--- linux-ein-5.4.0.orig/Documentation/ABI/stable/sysfs-driver-mlxreg-io
+++ linux-ein-5.4.0/Documentation/ABI/stable/sysfs-driver-mlxreg-io
@@ -29,13 +29,13 @@
 
 		The files are read only.
 
-What:		/sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
+What:		/sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version
 
 Date:		November 2018
 KernelVersion:	5.0
 Contact:	Vadim Pasternak <vadimpmellanox.com>
 Description:	These files show with which CPLD versions have been burned
-		on LED board.
+		on LED or Gearbox board.
 
 		The files are read only.
 
@@ -121,6 +121,15 @@
 
 		The files are read only.
 
+What:		/sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version
+Date:		November 2018
+KernelVersion:	5.0
+Contact:	Vadim Pasternak <vadimpmellanox.com>
+Description:	These files show with which CPLD versions have been burned
+		on LED board.
+
+		The files are read only.
+
 Date:		June 2019
 KernelVersion:	5.3
 Contact:	Vadim Pasternak <vadimpmellanox.com>
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/debugfs-aufs
+++ linux-ein-5.4.0/Documentation/ABI/testing/debugfs-aufs
@@ -0,0 +1,55 @@
+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>/xi0, xi1 ... xiN and xiN-N
+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.
+		Due to the file size limit, there may exist multiple
+		xino files per branch.  In this case, "-N" is added to
+		the filename and it corresponds to the index of the
+		internal xino array.  "-0" is omitted.
+		When the aufs mount option 'noxino' is specified, Those
+		entries won't exist.  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-ein-5.4.0.orig/Documentation/ABI/testing/debugfs-hisi-hpre
+++ linux-ein-5.4.0/Documentation/ABI/testing/debugfs-hisi-hpre
@@ -0,0 +1,57 @@
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/cluster[0-3]/regs
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Dump debug registers from the HPRE cluster.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/cluster[0-3]/cluster_ctrl
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Write the HPRE core selection in the cluster into this file,
+		and then we can read the debug information of the core.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/rdclr_en
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    HPRE cores debug registers read clear control. 1 means enable
+		register read clear, otherwise 0. Writing to this file has no
+		functional effect, only enable or disable counters clear after
+		reading of these registers.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/current_qm
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    One HPRE controller has one PF and multiple VFs, each function
+		has a QM. Select the QM which below qm refers to.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/regs
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Dump debug registers from the HPRE.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/qm/qm_regs
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Dump debug registers from the QM.
+		Available for PF and VF in host. VF in guest currently only
+		has one debug register.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/qm/current_q
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    One QM may contain multiple queues. Select specific queue to
+		show its debug registers in above qm_regs.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_hpre/<bdf>/qm/clear_enable
+Date:           Sep 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    QM debug registers(qm_regs) read clear control. 1 means enable
+		register read clear, otherwise 0.
+		Writing to this file has no functional effect, only enable or
+		disable counters clear after reading of these registers.
+		Only available for PF.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/debugfs-hisi-sec
+++ linux-ein-5.4.0/Documentation/ABI/testing/debugfs-hisi-sec
@@ -0,0 +1,43 @@
+What:           /sys/kernel/debug/hisi_sec/<bdf>/sec_dfx
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Dump the debug registers of SEC cores.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_sec/<bdf>/clear_enable
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Enabling/disabling of clear action after reading
+		the SEC debug registers.
+		0: disable, 1: enable.
+		Only available for PF, and take no other effect on SEC.
+
+What:           /sys/kernel/debug/hisi_sec/<bdf>/current_qm
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    One SEC controller has one PF and multiple VFs, each function
+		has a QM. This file can be used to select the QM which below
+		qm refers to.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_sec/<bdf>/qm/qm_regs
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Dump of QM related debug registers.
+		Available for PF and VF in host. VF in guest currently only
+		has one debug register.
+
+What:           /sys/kernel/debug/hisi_sec/<bdf>/qm/current_q
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    One QM of SEC may contain multiple queues. Select specific
+		queue to show its debug registers in above 'qm_regs'.
+		Only available for PF.
+
+What:           /sys/kernel/debug/hisi_sec/<bdf>/qm/clear_enable
+Date:           Oct 2019
+Contact:        linux-crypto@vger.kernel.org
+Description:    Enabling/disabling of clear action after reading
+		the SEC's QM debug registers.
+		0: disable, 1: enable.
+		Only available for PF, and take no other effect on SEC.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/evm
+++ linux-ein-5.4.0/Documentation/ABI/testing/evm
@@ -42,8 +42,30 @@
 		modification of EVM-protected metadata and
 		disable all further modification of policy
 
-		Note that once a key has been loaded, it will no longer be
-		possible to enable metadata modification.
+		Echoing a value is additive, the new value is added to the
+		existing initialization flags.
+
+		For example, after::
+
+		  echo 2 ><securityfs>/evm
+
+		another echo can be performed::
+
+		  echo 1 ><securityfs>/evm
+
+		and the resulting value will be 3.
+
+		Note that once an HMAC key has been loaded, it will no longer
+		be possible to enable metadata modification. Signaling that an
+		HMAC key has been loaded will clear the corresponding flag.
+		For example, if the current value is 6 (2 and 4 set)::
+
+		  echo 1 ><securityfs>/evm
+
+		will set the new value to 3 (4 cleared).
+
+		Loading an HMAC key is the only way to disable metadata
+		modification.
 
 		Until key loading has been signaled EVM can not create
 		or validate the 'security.evm' xattr, but returns
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/ima_policy
+++ linux-ein-5.4.0/Documentation/ABI/testing/ima_policy
@@ -25,6 +25,7 @@
 			lsm:	[[subj_user=] [subj_role=] [subj_type=]
 				 [obj_user=] [obj_role=] [obj_type=]]
 			option:	[[appraise_type=]] [template=] [permit_directio]
+				[appraise_flag=]
 		base: 	func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
 				[FIRMWARE_CHECK]
 				[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
@@ -38,6 +39,9 @@
 			fowner:= decimal value
 		lsm:  	are LSM specific
 		option:	appraise_type:= [imasig] [imasig|modsig]
+			appraise_flag:= [check_blacklist]
+			Currently, blacklist check is only for files signed with appended
+			signature.
 			template:= name of a defined IMA template type
 			(eg, ima-ng). Only valid when action is "measure".
 			pcr:= decimal value
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-ata
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-ata
@@ -107,13 +107,14 @@
 				described in ATA8 7.16 and 7.17. Only valid if
 				the device is not a PM.
 
-		pio_mode:	(RO) Transfer modes supported by the device when
-				in PIO mode. Mostly used by PATA device.
+		pio_mode:	(RO) PIO transfer mode used by the device.
+				Mostly used by PATA devices.
 
-		xfer_mode:	(RO) Current transfer mode
+		xfer_mode:	(RO) Current transfer mode. Mostly used by
+				PATA devices.
 
-		dma_mode:	(RO) Transfer modes supported by the device when
-				in DMA mode. Mostly used by PATA device.
+		dma_mode:	(RO) DMA transfer mode used by the device.
+				Mostly used by PATA devices.
 
 		class:		(RO) Device class. Can be "ata" for disk,
 				"atapi" for packet device, "pmp" for PM, or
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-aufs
+++ linux-ein-5.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-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-bus-iio
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-bus-iio
@@ -138,7 +138,7 @@
 		Raw capacitance measurement from channel Y. Units after
 		application of scale and offset are nanofarads.
 
-What:		/sys/.../iio:deviceX/in_capacitanceY-in_capacitanceZ_raw
+What:		/sys/.../iio:deviceX/in_capacitanceY-capacitanceZ_raw
 KernelVersion:	3.2
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -1566,7 +1566,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-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-bus-iio-vf610
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-bus-iio-vf610
@@ -1,4 +1,4 @@
-What:		/sys/bus/iio/devices/iio:deviceX/conversion_mode
+What:		/sys/bus/iio/devices/iio:deviceX/in_conversion_mode
 KernelVersion:	4.2
 Contact:	linux-iio@vger.kernel.org
 Description:
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-bus-mei
+++ linux-ein-5.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-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-bus-optee-devices
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-bus-optee-devices
@@ -0,0 +1,8 @@
+What:		/sys/bus/tee/devices/optee-ta-<uuid>/
+Date:           May 2020
+KernelVersion   5.8
+Contact:        op-tee@lists.trustedfirmware.org
+Description:
+		OP-TEE bus provides reference to registered drivers under this directory. The <uuid>
+		matches Trusted Application (TA) driver and corresponding TA in secure OS. Drivers
+		are free to create needed API under optee-ta-<uuid> directory.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-bus-pci
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-bus-pci
@@ -347,3 +347,16 @@
 		If the device has any Peer-to-Peer memory registered, this
 	        file contains a '1' if the memory has been published for
 		use outside the driver that owns the device.
+
+What:		/sys/bus/pci/devices/.../link/clkpm
+		/sys/bus/pci/devices/.../link/l0s_aspm
+		/sys/bus/pci/devices/.../link/l1_aspm
+		/sys/bus/pci/devices/.../link/l1_1_aspm
+		/sys/bus/pci/devices/.../link/l1_2_aspm
+		/sys/bus/pci/devices/.../link/l1_1_pcipm
+		/sys/bus/pci/devices/.../link/l1_2_pcipm
+Date:		October 2019
+Contact:	Heiner Kallweit <hkallweit1@gmail.com>
+Description:	If ASPM is supported for an endpoint, these files can be
+		used to disable or enable the individual power management
+		states. Write y/1/on to enable, n/0/off to disable.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-class-devfreq
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-class-devfreq
@@ -7,6 +7,13 @@
 		The name of devfreq object denoted as ... is same as the
 		name of device using devfreq.
 
+What:		/sys/class/devfreq/.../name
+Date:		November 2019
+Contact:	Chanwoo Choi <cw00.choi@samsung.com>
+Description:
+		The /sys/class/devfreq/.../name shows the name of device
+		of the corresponding devfreq object.
+
 What:		/sys/class/devfreq/.../governor
 Date:		September 2011
 Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-class-net-queues
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-class-net-queues
@@ -1,4 +1,4 @@
-What:		/sys/class/<iface>/queues/rx-<queue>/rps_cpus
+What:		/sys/class/net/<iface>/queues/rx-<queue>/rps_cpus
 Date:		March 2010
 KernelVersion:	2.6.35
 Contact:	netdev@vger.kernel.org
@@ -8,7 +8,7 @@
 		network device queue. Possible values depend on the number
 		of available CPU(s) in the system.
 
-What:		/sys/class/<iface>/queues/rx-<queue>/rps_flow_cnt
+What:		/sys/class/net/<iface>/queues/rx-<queue>/rps_flow_cnt
 Date:		April 2010
 KernelVersion:	2.6.35
 Contact:	netdev@vger.kernel.org
@@ -16,7 +16,7 @@
 		Number of Receive Packet Steering flows being currently
 		processed by this particular network device receive queue.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/tx_timeout
+What:		/sys/class/net/<iface>/queues/tx-<queue>/tx_timeout
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
@@ -24,7 +24,7 @@
 		Indicates the number of transmit timeout events seen by this
 		network interface transmit queue.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/tx_maxrate
+What:		/sys/class/net/<iface>/queues/tx-<queue>/tx_maxrate
 Date:		March 2015
 KernelVersion:	4.1
 Contact:	netdev@vger.kernel.org
@@ -32,7 +32,7 @@
 		A Mbps max-rate set for the queue, a value of zero means disabled,
 		default is disabled.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/xps_cpus
+What:		/sys/class/net/<iface>/queues/tx-<queue>/xps_cpus
 Date:		November 2010
 KernelVersion:	2.6.38
 Contact:	netdev@vger.kernel.org
@@ -42,7 +42,7 @@
 		network device transmit queue. Possible vaules depend on the
 		number of available CPU(s) in the system.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/xps_rxqs
+What:		/sys/class/net/<iface>/queues/tx-<queue>/xps_rxqs
 Date:		June 2018
 KernelVersion:	4.18.0
 Contact:	netdev@vger.kernel.org
@@ -53,7 +53,7 @@
 		number of available receive queue(s) in the network device.
 		Default is disabled.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time
+What:		/sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
@@ -62,7 +62,7 @@
 		of this particular network device transmit queue.
 		Default value is 1000.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/inflight
+What:		/sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/inflight
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
@@ -70,7 +70,7 @@
 		Indicates the number of bytes (objects) in flight on this
 		network device transmit queue.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit
+What:		/sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
@@ -79,7 +79,7 @@
 		on this network device transmit queue. This value is clamped
 		to be within the bounds defined by limit_max and limit_min.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max
+What:		/sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
@@ -88,7 +88,7 @@
 		queued on this network device transmit queue. See
 		include/linux/dynamic_queue_limits.h for the default value.
 
-What:		/sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min
+What:		/sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min
 Date:		November 2011
 KernelVersion:	3.3
 Contact:	netdev@vger.kernel.org
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -480,14 +480,17 @@
 		cpu_capacity: capacity of cpu#.
 
 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/spec_store_bypass
-		/sys/devices/system/cpu/vulnerabilities/l1tf
-		/sys/devices/system/cpu/vulnerabilities/mds
+		/sys/devices/system/cpu/vulnerabilities/srbds
 		/sys/devices/system/cpu/vulnerabilities/tsx_async_abort
-		/sys/devices/system/cpu/vulnerabilities/itlb_multihit
 Date:		January 2018
 Contact:	Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:	Information about CPU vulnerabilities
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-kernel-oops_count
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-kernel-oops_count
@@ -0,0 +1,6 @@
+What:		/sys/kernel/oops_count
+Date:		November 2022
+KernelVersion:	6.2.0
+Contact:	Linux Kernel Hardening List <linux-hardening@vger.kernel.org>
+Description:
+		Shows how many times the system has Oopsed since last boot.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-kernel-warn_count
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-kernel-warn_count
@@ -0,0 +1,6 @@
+What:		/sys/kernel/warn_count
+Date:		November 2022
+KernelVersion:	6.2.0
+Contact:	Linux Kernel Hardening List <linux-hardening@vger.kernel.org>
+Description:
+		Shows how many times the system has Warned since last boot.
--- linux-ein-5.4.0.orig/Documentation/ABI/testing/sysfs-secvar
+++ linux-ein-5.4.0/Documentation/ABI/testing/sysfs-secvar
@@ -0,0 +1,46 @@
+What:		/sys/firmware/secvar
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	This directory is created if the POWER firmware supports OS
+		secureboot, thereby secure variables. It exposes interface
+		for reading/writing the secure variables
+
+What:		/sys/firmware/secvar/vars
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	This directory lists all the secure variables that are supported
+		by the firmware.
+
+What:		/sys/firmware/secvar/format
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	A string indicating which backend is in use by the firmware.
+		This determines the format of the variable and the accepted
+		format of variable updates.
+
+What:		/sys/firmware/secvar/vars/<variable name>
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Each secure variable is represented as a directory named as
+		<variable_name>. The variable name is unique and is in ASCII
+		representation. The data and size can be determined by reading
+		their respective attribute files.
+
+What:		/sys/firmware/secvar/vars/<variable_name>/size
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	An integer representation of the size of the content of the
+		variable. In other words, it represents the size of the data.
+
+What:		/sys/firmware/secvar/vars/<variable_name>/data
+Date:		August 2019
+Contact:	Nayna Jain h<nayna@linux.ibm.com>
+Description:	A read-only file containing the value of the variable. The size
+		of the file represents the maximum size of the variable data.
+
+What:		/sys/firmware/secvar/vars/<variable_name>/update
+Date:		August 2019
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	A write-only file that is used to submit the new value for the
+		variable. The size of the file represents the maximum size of
+		the variable data that can be written.
--- linux-ein-5.4.0.orig/Documentation/DMA-attributes.txt
+++ linux-ein-5.4.0/Documentation/DMA-attributes.txt
@@ -5,24 +5,6 @@
 This document describes the semantics of the DMA attributes that are
 defined in linux/dma-mapping.h.
 
-DMA_ATTR_WRITE_BARRIER
-----------------------
-
-DMA_ATTR_WRITE_BARRIER is a (write) barrier attribute for DMA.  DMA
-to a memory region with the DMA_ATTR_WRITE_BARRIER attribute forces
-all pending DMA writes to complete, and thus provides a mechanism to
-strictly order DMA from a device across all intervening busses and
-bridges.  This barrier is not specific to a particular type of
-interconnect, it applies to the system as a whole, and so its
-implementation must account for the idiosyncrasies of the system all
-the way from the DMA device to memory.
-
-As an example of a situation where DMA_ATTR_WRITE_BARRIER would be
-useful, suppose that a device does a DMA write to indicate that data is
-ready and available in memory.  The DMA of the "completion indication"
-could race with data DMA.  Mapping the memory used for completion
-indications with DMA_ATTR_WRITE_BARRIER would prevent the race.
-
 DMA_ATTR_WEAK_ORDERING
 ----------------------
 
--- linux-ein-5.4.0.orig/Documentation/accounting/psi.rst
+++ linux-ein-5.4.0/Documentation/accounting/psi.rst
@@ -90,7 +90,8 @@
 for the same psi metric can be specified. However for each trigger a separate
 file descriptor is required to be able to poll it separately from others,
 therefore for each trigger a separate open() syscall should be made even
-when opening the same psi interface file.
+when opening the same psi interface file. Write operations to a file descriptor
+with an already existing psi trigger will fail with EBUSY.
 
 Monitors activate only when system enters stall state for the monitored
 psi metric and deactivates upon exit from the stall state. While system is
--- linux-ein-5.4.0.orig/Documentation/admin-guide/cgroup-v1/memory.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/cgroup-v1/memory.rst
@@ -82,6 +82,8 @@
  memory.swappiness		     set/show swappiness parameter of vmscan
 				     (See sysctl's vm.swappiness)
  memory.move_charge_at_immigrate     set/show controls of moving charges
+                                     This knob is deprecated and shouldn't be
+                                     used.
  memory.oom_control		     set/show oom controls.
  memory.numa_stat		     show the number of memory usage per numa
 				     node
@@ -745,8 +747,15 @@
        It is recommended to set the soft limit always below the hard limit,
        otherwise the hard limit will take precedence.
 
-8. Move charges at task migration
-=================================
+8. Move charges at task migration (DEPRECATED!)
+===============================================
+
+THIS IS DEPRECATED!
+
+It's expensive and unreliable! It's better practice to launch workload
+tasks directly from inside their target cgroup. Use dedicated workload
+cgroups to allow fine-grained policy adjustments without having to
+move physical pages between control domains.
 
 Users can move charges associated with a task along with task migration, that
 is, uncharge task's pages from the old cgroup and charge them to the new cgroup.
--- linux-ein-5.4.0.orig/Documentation/admin-guide/device-mapper/dm-integrity.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/device-mapper/dm-integrity.rst
@@ -177,6 +177,12 @@
 	The bitmap flush interval in milliseconds. The metadata buffers
 	are synchronized when this interval expires.
 
+legacy_recalculate
+	Allow recalculating of volumes with HMAC keys. This is disabled by
+	default for security reasons - an attacker could modify the volume,
+	set recalc_sector to zero, and the kernel would not detect the
+	modification.
+
 
 The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can
 be changed when reloading the target (load an inactive table and swap the
--- linux-ein-5.4.0.orig/Documentation/admin-guide/device-mapper/index.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/device-mapper/index.rst
@@ -8,6 +8,7 @@
     cache-policies
     cache
     delay
+    dm-clone
     dm-crypt
     dm-flakey
     dm-init
--- linux-ein-5.4.0.orig/Documentation/admin-guide/devices.txt
+++ linux-ein-5.4.0/Documentation/admin-guide/devices.txt
@@ -3002,10 +3002,10 @@
 		65 = /dev/infiniband/issm1     Second InfiniBand IsSM device
 		  ...
 		127 = /dev/infiniband/issm63    63rd InfiniBand IsSM device
-		128 = /dev/infiniband/uverbs0   First InfiniBand verbs device
-		129 = /dev/infiniband/uverbs1   Second InfiniBand verbs device
+		192 = /dev/infiniband/uverbs0   First InfiniBand verbs device
+		193 = /dev/infiniband/uverbs1   Second InfiniBand verbs device
 		  ...
-		159 = /dev/infiniband/uverbs31  31st InfiniBand verbs device
+		223 = /dev/infiniband/uverbs31  31st InfiniBand verbs device
 
  232 char	Biometric Devices
 		0 = /dev/biometric/sensor0/fingerprint	first fingerprint sensor on first device
--- linux-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/cross-thread-rsb.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/cross-thread-rsb.rst
@@ -0,0 +1,92 @@
+
+.. SPDX-License-Identifier: GPL-2.0
+
+Cross-Thread Return Address Predictions
+=======================================
+
+Certain AMD and Hygon processors are subject to a cross-thread return address
+predictions vulnerability. When running in SMT mode and one sibling thread
+transitions out of C0 state, the other sibling thread could use return target
+predictions from the sibling thread that transitioned out of C0.
+
+The Spectre v2 mitigations protect the Linux kernel, as it fills the return
+address prediction entries with safe targets when context switching to the idle
+thread. However, KVM does allow a VMM to prevent exiting guest mode when
+transitioning out of C0. This could result in a guest-controlled return target
+being consumed by the sibling thread.
+
+Affected processors
+-------------------
+
+The following CPUs are vulnerable:
+
+    - AMD Family 17h processors
+    - Hygon Family 18h processors
+
+Related CVEs
+------------
+
+The following CVE entry is related to this issue:
+
+   ==============  =======================================
+   CVE-2022-27672  Cross-Thread Return Address Predictions
+   ==============  =======================================
+
+Problem
+-------
+
+Affected SMT-capable processors support 1T and 2T modes of execution when SMT
+is enabled. In 2T mode, both threads in a core are executing code. For the
+processor core to enter 1T mode, it is required that one of the threads
+requests to transition out of the C0 state. This can be communicated with the
+HLT instruction or with an MWAIT instruction that requests non-C0.
+When the thread re-enters the C0 state, the processor transitions back
+to 2T mode, assuming the other thread is also still in C0 state.
+
+In affected processors, the return address predictor (RAP) is partitioned
+depending on the SMT mode. For instance, in 2T mode each thread uses a private
+16-entry RAP, but in 1T mode, the active thread uses a 32-entry RAP. Upon
+transition between 1T/2T mode, the RAP contents are not modified but the RAP
+pointers (which control the next return target to use for predictions) may
+change. This behavior may result in return targets from one SMT thread being
+used by RET predictions in the sibling thread following a 1T/2T switch. In
+particular, a RET instruction executed immediately after a transition to 1T may
+use a return target from the thread that just became idle. In theory, this
+could lead to information disclosure if the return targets used do not come
+from trustworthy code.
+
+Attack scenarios
+----------------
+
+An attack can be mounted on affected processors by performing a series of CALL
+instructions with targeted return locations and then transitioning out of C0
+state.
+
+Mitigation mechanism
+--------------------
+
+Before entering idle state, the kernel context switches to the idle thread. The
+context switch fills the RAP entries (referred to as the RSB in Linux) with safe
+targets by performing a sequence of CALL instructions.
+
+Prevent a guest VM from directly putting the processor into an idle state by
+intercepting HLT and MWAIT instructions.
+
+Both mitigations are required to fully address this issue.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+Use existing Spectre v2 mitigations that will fill the RSB on context switch.
+
+Mitigation control for KVM - module parameter
+---------------------------------------------
+
+By default, the KVM hypervisor mitigates this issue by intercepting guest
+attempts to transition out of C0. A VMM can use the KVM_CAP_X86_DISABLE_EXITS
+capability to override those interceptions, but since this is not common, the
+mitigation that covers this path is not enabled by default.
+
+The mitigation for the KVM_CAP_X86_DISABLE_EXITS capability can be turned on
+using the boolean module parameter mitigate_smt_rsb, e.g.:
+        kvm.mitigate_smt_rsb=1
--- linux-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/gather_data_sampling.rst
@@ -0,0 +1,109 @@
+.. 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 gather_data_sampling="force" or
+"clearcpuid=avx" on the kernel command-line.
+
+If used, these options will disable AVX use by turning off XSAVE YMM support.
+However, the processor will still enumerate AVX support.  Userspace that
+does not follow proper AVX enumeration to check both AVX *and* XSAVE YMM
+support will break.
+
+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. Specifying "gather_data_sampling=force" will
+use the microcode mitigation when available or disable AVX on affected systems
+where the microcode hasn't been updated to include the mitigation.
+
+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: AVX disabled,
+ no microcode                   Processor is vulnerable and microcode is missing
+                                mitigation. AVX disabled as 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-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/index.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/index.rst
@@ -14,3 +14,7 @@
    mds
    tsx_async_abort
    multihit.rst
+   special-register-buffer-data-sampling.rst
+   processor_mmio_stale_data.rst
+   cross-thread-rsb.rst
+   gather_data_sampling.rst
--- linux-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/mds.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/mds.rst
@@ -265,8 +265,11 @@
 
   ============  =============================================================
 
-Not specifying this option is equivalent to "mds=full".
-
+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
 --------------------------
--- linux-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
@@ -0,0 +1,260 @@
+=========================================
+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.
+     * - 'Unknown: No mitigations'
+       - The processor vulnerability status is unknown because it is
+	 out of Servicing period. Mitigation is not attempted.
+
+Definitions:
+------------
+
+Servicing period: The process of providing functional and security updates to
+Intel processors or platforms, utilizing the Intel Platform Update (IPU)
+process or other similar mechanisms.
+
+End of Servicing Updates (ESU): ESU is the date at which Intel will no
+longer provide Servicing, such as through IPU or other similar update
+processes. ESU dates will typically be aligned to end of quarter.
+
+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-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst
+++ linux-ein-5.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-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/spectre.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/spectre.rst
@@ -60,8 +60,8 @@
 Spectre variant 1 attacks take advantage of speculative execution of
 conditional branches, while Spectre variant 2 attacks use speculative
 execution of indirect branches to leak privileged memory.
-See :ref:`[1] <spec_ref1>` :ref:`[5] <spec_ref5>` :ref:`[7] <spec_ref7>`
-:ref:`[10] <spec_ref10>` :ref:`[11] <spec_ref11>`.
+See :ref:`[1] <spec_ref1>` :ref:`[5] <spec_ref5>` :ref:`[6] <spec_ref6>`
+:ref:`[7] <spec_ref7>` :ref:`[10] <spec_ref10>` :ref:`[11] <spec_ref11>`.
 
 Spectre variant 1 (Bounds Check Bypass)
 ---------------------------------------
@@ -131,6 +131,18 @@
 speculative execution's side effects left in level 1 cache to infer the
 victim's data.
 
+Yet another variant 2 attack vector is for the attacker to poison the
+Branch History Buffer (BHB) to speculatively steer an indirect branch
+to a specific Branch Target Buffer (BTB) entry, even if the entry isn't
+associated with the source address of the indirect branch. Specifically,
+the BHB might be shared across privilege levels even in the presence of
+Enhanced IBRS.
+
+Previously the only known real-world BHB attack vector was via unprivileged
+eBPF. Further research has found attacks that don't require unprivileged eBPF.
+For a full mitigation against BHB attacks it is recommended to set BHI_DIS_S or
+use the BHB clearing sequence.
+
 Attack scenarios
 ----------------
 
@@ -364,13 +376,15 @@
 
   - Kernel status:
 
-  ====================================  =================================
-  'Not affected'                        The processor is not vulnerable
-  'Vulnerable'                          Vulnerable, no mitigation
-  'Mitigation: Full generic retpoline'  Software-focused mitigation
-  'Mitigation: Full AMD retpoline'      AMD-specific software mitigation
-  'Mitigation: Enhanced IBRS'           Hardware-focused mitigation
-  ====================================  =================================
+  ========================================  =================================
+  'Not affected'                            The processor is not vulnerable
+  'Mitigation: None'                        Vulnerable, no mitigation
+  'Mitigation: Retpolines'                  Use Retpoline thunks
+  'Mitigation: LFENCE'                      Use LFENCE instructions
+  'Mitigation: Enhanced IBRS'               Hardware-focused mitigation
+  'Mitigation: Enhanced IBRS + Retpolines'  Hardware-focused + Retpolines
+  'Mitigation: Enhanced IBRS + LFENCE'      Hardware-focused + LFENCE
+  ========================================  =================================
 
   - Firmware status: Show if Indirect Branch Restricted Speculation (IBRS) is
     used to protect against Spectre variant 2 attacks when calling firmware (x86 only).
@@ -407,6 +421,31 @@
   'RSB filling'   Protection of RSB on context switch enabled
   =============   ===========================================
 
+  - EIBRS Post-barrier Return Stack Buffer (PBRSB) protection status:
+
+  ===========================  =======================================================
+  'PBRSB-eIBRS: SW sequence'   CPU is affected and protection of RSB on VMEXIT enabled
+  'PBRSB-eIBRS: Vulnerable'    CPU is vulnerable
+  'PBRSB-eIBRS: Not affected'  CPU is not affected by PBRSB
+  ===========================  =======================================================
+
+  - Branch History Injection (BHI) protection status:
+
+.. list-table::
+
+ * - BHI: Not affected
+   - System is not affected
+ * - BHI: Retpoline
+   - System is protected by retpoline
+ * - BHI: BHI_DIS_S
+   - System is protected by BHI_DIS_S
+ * - BHI: SW loop, KVM SW loop
+   - System is protected by software clearing sequence
+ * - BHI: Vulnerable
+   - System is vulnerable to BHI
+ * - BHI: Vulnerable, KVM: SW loop
+   - System is vulnerable; KVM is protected by software clearing sequence
+
 Full mitigation might require a microcode update from the CPU
 vendor. When the necessary microcode is not available, the kernel will
 report vulnerability.
@@ -456,8 +495,16 @@
    On Intel Skylake-era systems the mitigation covers most, but not all,
    cases. See :ref:`[3] <spec_ref3>` for more details.
 
-   On CPUs with hardware mitigation for Spectre variant 2 (e.g. Enhanced
-   IBRS on x86), retpoline is automatically disabled at run time.
+   On CPUs with hardware mitigation for Spectre variant 2 (e.g. IBRS
+   or enhanced IBRS on x86), retpoline is automatically disabled at run time.
+
+   Systems which support enhanced IBRS (eIBRS) enable IBRS protection once at
+   boot, by setting the IBRS bit, and they're automatically protected against
+   Spectre v2 variant attacks, including cross-thread branch target injections
+   on SMT systems (STIBP). In other words, eIBRS enables STIBP too.
+
+   Legacy IBRS systems clear the IBRS bit on exit to userspace and
+   therefore explicitly enable STIBP for that
 
    The retpoline mitigation is turned on by default on vulnerable
    CPUs. It can be forced on or off by the administrator
@@ -468,7 +515,7 @@
    before invoking any firmware code to prevent Spectre variant 2 exploits
    using the firmware.
 
-   Using kernel address space randomization (CONFIG_RANDOMIZE_SLAB=y
+   Using kernel address space randomization (CONFIG_RANDOMIZE_BASE=y
    and CONFIG_SLAB_FREELIST_RANDOM=y in the kernel configuration) makes
    attacks on the kernel generally more difficult.
 
@@ -481,9 +528,12 @@
    For Spectre variant 2 mitigation, individual user programs
    can be compiled with return trampolines for indirect branches.
    This protects them from consuming poisoned entries in the branch
-   target buffer left by malicious software.  Alternatively, the
-   programs can disable their indirect branch speculation via prctl()
-   (See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
+   target buffer left by malicious software.
+
+   On legacy IBRS systems, at return to userspace, implicit STIBP is disabled
+   because the kernel clears the IBRS bit. In this case, the userspace programs
+   can disable indirect branch speculation via prctl() (See
+   :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
    On x86, this will turn on STIBP to guard against attacks from the
    sibling thread when the user program is running, and use IBPB to
    flush the branch target buffer when switching to/from the program.
@@ -584,12 +634,13 @@
 
 		Specific mitigations can also be selected manually:
 
-		retpoline
-					replace indirect branches
-		retpoline,generic
-					google's original retpoline
-		retpoline,amd
-					AMD-specific minimal thunk
+                retpoline               auto pick between generic,lfence
+                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
 
 		Not specifying this option is equivalent to
 		spectre_v2=auto.
@@ -649,6 +700,24 @@
 		spectre_v2=off. Spectre variant 1 mitigations
 		cannot be disabled.
 
+	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.
+
+For spectre_v2_user see Documentation/admin-guide/kernel-parameters.txt
+
 Mitigation selection guide
 --------------------------
 
@@ -730,7 +799,7 @@
 
 .. _spec_ref6:
 
-[6] `Software techniques for managing speculation on AMD processors <https://developer.amd.com/wp-content/resources/90343-B_SoftwareTechniquesforManagingSpeculation_WP_7-18Update_FNL.pdf>`_.
+[6] `Software techniques for managing speculation on AMD processors <https://developer.amd.com/wp-content/resources/Managing-Speculation-on-AMD-Processors.pdf>`_.
 
 ARM white papers:
 
--- linux-ein-5.4.0.orig/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
@@ -174,7 +174,10 @@
                 CPU is not vulnerable to cross-thread TAA attacks.
   ============  =============================================================
 
-Not specifying this option is equivalent to "tsx_async_abort=full".
+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
--- linux-ein-5.4.0.orig/Documentation/admin-guide/iostats.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/iostats.rst
@@ -99,7 +99,7 @@
 
     Since 5.0 this field counts jiffies when at least one request was
     started or completed. If request runs more than 2 jiffies then some
-    I/O time will not be accounted unless there are other requests.
+    I/O time might be not accounted in case of concurrent requests.
 
 Field 11 -- weighted # of milliseconds spent doing I/Os
     This field is incremented at each I/O start, I/O completion, I/O
@@ -133,6 +133,9 @@
 summed to) and the result given to the user.  There is no convenient
 user interface for accessing the per-CPU counters themselves.
 
+Since 4.19 request times are measured with nanoseconds precision and
+truncated to milliseconds before showing in this interface.
+
 Disks vs Partitions
 -------------------
 
--- linux-ein-5.4.0.orig/Documentation/admin-guide/kdump/vmcoreinfo.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/kdump/vmcoreinfo.rst
@@ -393,6 +393,17 @@
 The kernel randomization offset. Used to compute the page offset. If
 KASLR is disabled, this value is zero.
 
+TCR_EL1.T1SZ
+------------
+
+Indicates the size offset of the memory region addressed by TTBR1_EL1.
+The region size is 2^(64-T1SZ) bytes.
+
+TTBR1_EL1 is the table base address register specified by ARMv8-A
+architecture which is used to lookup the page-tables for the Virtual
+addresses in the higher VA range (refer to ARMv8 ARM document for
+more details).
+
 arm
 ===
 
--- linux-ein-5.4.0.orig/Documentation/admin-guide/kernel-parameters.txt
+++ linux-ein-5.4.0/Documentation/admin-guide/kernel-parameters.txt
@@ -113,7 +113,7 @@
 			the GPE dispatcher.
 			This facility can be used to prevent such uncontrolled
 			GPE floodings.
-			Format: <int>
+			Format: <byte>
 
 	acpi_no_auto_serialize	[HW,ACPI]
 			Disable auto-serialization of AML methods
@@ -136,6 +136,10 @@
 			dynamic table installation which will install SSDT
 			tables to /sys/firmware/acpi/tables/dynamic.
 
+	acpi_no_watchdog	[HW,ACPI,WDT]
+			Ignore the ACPI-based watchdog interface (WDAT) and let
+			a native driver control the watchdog device instead.
+
 	acpi_rsdp=	[ACPI,EFI,KEXEC]
 			Pass the RSDP address to the kernel, mostly used
 			on machines running EFI runtime service to boot the
@@ -563,7 +567,13 @@
 			loops can be debugged more effectively on production
 			systems.
 
-	clearcpuid=BITNUM [X86]
+	clocksource.max_cswd_read_retries= [KNL]
+			Number of clocksource_watchdog() retries due to
+			external delays before the clock will be marked
+			unstable.  Defaults to three retries, that is,
+			four attempts to read the clock under test.
+
+	clearcpuid=BITNUM[,BITNUM...] [X86]
 			Disable CPUID feature X for the kernel. See
 			arch/x86/include/asm/cpufeatures.h for the valid bit
 			numbers. Note the Linux specific bits are not necessarily
@@ -680,6 +690,10 @@
 			0: default value, disable debugging
 			1: enable debugging at boot time
 
+	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
 
@@ -815,10 +829,6 @@
 
 	debugpat	[X86] Enable PAT debugging
 
-	decnet.addr=	[HW,NET]
-			Format: <area>[,<node>]
-			See also Documentation/networking/decnet.txt.
-
 	default_hugepagesz=
 			[same as hugepagesz=] The size of the default
 			HugeTLB page size. This is the size represented by
@@ -836,6 +846,18 @@
 			dump out devices still on the deferred probe list after
 			retrying.
 
+	dfltcc=		[HW,S390]
+			Format: { on | off | def_only | inf_only | always }
+			on:       s390 zlib hardware support for compression on
+			          level 1 and decompression (default)
+			off:      No s390 zlib hardware support
+			def_only: s390 zlib hardware support for deflate
+			          only (compression on level 1)
+			inf_only: s390 zlib hardware support for inflate
+			          only (decompression)
+			always:   Same as 'on' but ignores the selected compression
+			          level always using hardware support (used for debugging)
+
 	dhash_entries=	[KNL]
 			Set number of hash buckets for dentry cache.
 
@@ -1330,6 +1352,26 @@
 			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. On systems without the microcode mitigation
+			disabling AVX serves as a mitigation.
+
+			force:	Disable AVX to mitigate systems without
+				microcode mitigation. No effect if the microcode
+				mitigation is present. Known to cause crashes in
+				userspace with buggy AVX enumeration.
+
+			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.
@@ -1477,6 +1519,8 @@
 			architectures force reset to be always executed
 	i8042.unlock	[HW] Unlock (ignore) the keylock
 	i8042.kbdreset	[HW] Reset device connected to KBD port
+	i8042.probe_defer
+			[HW] Allow deferred probing upon i8042 probe errors
 
 	i810=		[HW,DRM]
 
@@ -1932,24 +1976,57 @@
 
 	ivrs_ioapic	[HW,X86_64]
 			Provide an override to the IOAPIC-ID<->DEVICE-ID
-			mapping provided in the IVRS ACPI table. For
-			example, to map IOAPIC-ID decimal 10 to
-			PCI device 00:14.0 write the parameter as:
+			mapping provided in the IVRS ACPI table.
+			By default, PCI segment is 0, and can be omitted.
+
+			For example, to map IOAPIC-ID decimal 10 to
+			PCI segment 0x1 and PCI device 00:14.0,
+			write the parameter as:
+				ivrs_ioapic=10@0001:00:14.0
+
+			Deprecated formats:
+			* To map IOAPIC-ID decimal 10 to PCI device 00:14.0
+			  write the parameter as:
 				ivrs_ioapic[10]=00:14.0
+			* To map IOAPIC-ID decimal 10 to PCI segment 0x1 and
+			  PCI device 00:14.0 write the parameter as:
+				ivrs_ioapic[10]=0001:00:14.0
 
 	ivrs_hpet	[HW,X86_64]
 			Provide an override to the HPET-ID<->DEVICE-ID
-			mapping provided in the IVRS ACPI table. For
-			example, to map HPET-ID decimal 0 to
-			PCI device 00:14.0 write the parameter as:
+			mapping provided in the IVRS ACPI table.
+			By default, PCI segment is 0, and can be omitted.
+
+			For example, to map HPET-ID decimal 10 to
+			PCI segment 0x1 and PCI device 00:14.0,
+			write the parameter as:
+				ivrs_hpet=10@0001:00:14.0
+
+			Deprecated formats:
+			* To map HPET-ID decimal 0 to PCI device 00:14.0
+			  write the parameter as:
 				ivrs_hpet[0]=00:14.0
+			* To map HPET-ID decimal 10 to PCI segment 0x1 and
+			  PCI device 00:14.0 write the parameter as:
+				ivrs_ioapic[10]=0001:00:14.0
 
 	ivrs_acpihid	[HW,X86_64]
 			Provide an override to the ACPI-HID:UID<->DEVICE-ID
-			mapping provided in the IVRS ACPI table. For
-			example, to map UART-HID:UID AMD0020:0 to
-			PCI device 00:14.5 write the parameter as:
+			mapping provided in the IVRS ACPI table.
+			By default, PCI segment is 0, and can be omitted.
+
+			For example, to map UART-HID:UID AMD0020:0 to
+			PCI segment 0x1 and PCI device ID 00:14.5,
+			write the parameter as:
+				ivrs_acpihid=AMD0020:0@0001:00:14.5
+
+			Deprecated formats:
+			* To map UART-HID:UID AMD0020:0 to PCI segment is 0,
+			  PCI device ID 00:14.5, write the parameter as:
 				ivrs_acpihid[00:14.5]=AMD0020:0
+			* To map UART-HID:UID AMD0020:0 to PCI segment 0x1 and
+			  PCI device ID 00:14.5, write the parameter as:
+				ivrs_acpihid[0001:00:14.5]=AMD0020:0
 
 	js=		[HW,JOY] Analog joystick
 			See Documentation/input/joydev/joystick.rst.
@@ -2102,8 +2179,12 @@
 			Default is 1 (enabled)
 
 	kvm-intel.emulate_invalid_guest_state=
-			[KVM,Intel] Enable emulation of invalid guest states
-			Default is 0 (disabled)
+			[KVM,Intel] Disable emulation of invalid guest state.
+			Ignored if kvm-intel.enable_unrestricted_guest=1, as
+			guest state is never invalid for unrestricted guests.
+			This param doesn't apply to nested guests (L2), as KVM
+			never emulates invalid L2 guest state.
+			Default is 1 (enabled)
 
 	kvm-intel.flexpriority=
 			[KVM,Intel] Disable FlexPriority feature (TPR shadow).
@@ -2473,6 +2554,12 @@
 				     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.
 
@@ -2645,18 +2732,27 @@
 				Disable all optional CPU mitigations.  This
 				improves system performance, but it may also
 				expose users to several CPU vulnerabilities.
-				Equivalent to: nopti [X86,PPC]
-					       kpti=0 [ARM64]
-					       nospectre_v1 [X86,PPC]
+				Equivalent to: if nokaslr then kpti=0 [ARM64]
+					       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]
+					       mmio_stale_data=off [X86]
 					       nobp=0 [S390]
+					       nopti [X86,PPC]
+					       nospectre_bhb [ARM64]
+					       nospectre_v1 [X86,PPC]
 					       nospectre_v2 [X86,PPC,S390,ARM64]
-					       spectre_v2_user=off [X86]
+					       retbleed=off [X86]
 					       spec_store_bypass_disable=off [X86,PPC]
+					       spectre_bhi=off [X86]
+					       spectre_v2_user=off [X86]
+					       srbds=off [X86,INTEL]
 					       ssbd=force-off [ARM64]
-					       l1tf=off [X86]
-					       mds=off [X86]
 					       tsx_async_abort=off [X86]
-					       kvm.nx_huge_pages=off [X86]
 
 				Exceptions:
 					       This does not have any effect on
@@ -2678,6 +2774,7 @@
 				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
@@ -2687,6 +2784,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.
@@ -2731,7 +2862,7 @@
 			<name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>]
 
 	mtdparts=	[MTD]
-			See drivers/mtd/cmdlinepart.c.
+			See drivers/mtd/parsers/cmdlinepart.c
 
 	multitce=off	[PPC]  This parameter disables the use of the pSeries
 			firmware feature for updating multiple TCE entries
@@ -2979,6 +3110,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]
@@ -3028,6 +3161,9 @@
 	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.
@@ -3402,6 +3538,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.
@@ -3555,6 +3697,8 @@
 				may put more devices in an IOMMU group.
 		force_floating	[S390] Force usage of floating interrupts.
 		nomio		[S390] Do not use MIO instructions.
+		norid		[S390] ignore the RID field and force use of
+				one PCI domain per PCI function
 
 	pcie_aspm=	[PCIE] Forcibly enable or disable PCIe Active State Power
 			Management.
@@ -3567,6 +3711,8 @@
 			even if the platform doesn't give the OS permission to
 			use them.  This may cause conflicts if the platform
 			also tries to use these services.
+		dpc-native	Use native PCIe service for DPC only.  May
+				cause conflicts if firmware uses AER or DPC.
 		compat	Disable native PCIe services (PME, AER, DPC, PCIe
 			hotplug).
 
@@ -3720,6 +3866,11 @@
 			before loading.
 			See Documentation/admin-guide/blockdev/ramdisk.rst.
 
+	prot_virt=	[S390] enable hosting protected virtual machines
+			isolated from the hypervisor (if hardware supports
+			that).
+			Format: <bool>
+
 	psi=		[KNL] Enable or disable pressure stall information
 			tracking.
 			Format: <bool>
@@ -3777,6 +3928,12 @@
 			fully seed the kernel's CRNG. Default is controlled
 			by CONFIG_RANDOM_TRUST_CPU.
 
+	random.trust_bootloader={on,off}
+			[KNL] Enable or disable trusting the use of a
+			seed passed by the bootloader (if available) to
+			fully seed the kernel's CRNG. Default is controlled
+			by CONFIG_RANDOM_TRUST_BOOTLOADER.
+
 	ras=option[,option,...]	[KNL] RAS-specific options
 
 		cec_disable	[X86]
@@ -4227,6 +4384,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.
@@ -4437,6 +4606,18 @@
 	sonypi.*=	[HW] Sony Programmable I/O Control Device driver
 			See Documentation/admin-guide/laptops/sonypi.rst
 
+	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
@@ -4464,8 +4645,13 @@
 			Specific mitigations can also be selected manually:
 
 			retpoline	  - replace indirect branches
-			retpoline,generic - google's original retpoline
-			retpoline,amd     - AMD-specific minimal thunk
+			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.
@@ -4569,6 +4755,26 @@
 	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
+
 	srcutree.counter_wrap_check [KNL]
 			Specifies how frequently to check for
 			grace-period sequence counter wrap for the
@@ -4931,6 +5137,11 @@
 				     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
@@ -4990,8 +5201,7 @@
 
 	usbcore.old_scheme_first=
 			[USB] Start with the old device initialization
-			scheme,  applies only to low and full-speed devices
-			 (default 0 = off).
+			scheme (default 0 = off).
 
 	usbcore.usbfs_memory_mb=
 			[USB] Memory limit (in MB) for buffers allocated by
@@ -5090,13 +5300,13 @@
 			Flags is a set of characters, each corresponding
 			to a common usb-storage quirk flag as follows:
 				a = SANE_SENSE (collect more than 18 bytes
-					of sense data);
+					of sense data, not on uas);
 				b = BAD_SENSE (don't collect more than 18
-					bytes of sense data);
+					bytes of sense data, not on uas);
 				c = FIX_CAPACITY (decrease the reported
 					device capacity by one sector);
 				d = NO_READ_DISC_INFO (don't use
-					READ_DISC_INFO command);
+					READ_DISC_INFO command, not on uas);
 				e = NO_READ_CAPACITY_16 (don't use
 					READ_CAPACITY_16 command);
 				f = NO_REPORT_OPCODES (don't use report opcodes
@@ -5110,18 +5320,20 @@
 					device);
 				j = NO_REPORT_LUNS (don't use report luns
 					command, uas only);
+				k = NO_SAME (do not use WRITE_SAME, uas only)
 				l = NOT_LOCKABLE (don't try to lock and
-					unlock ejectable media);
+					unlock ejectable media, not on uas);
 				m = MAX_SECTORS_64 (don't transfer more
-					than 64 sectors = 32 KB at a time);
+					than 64 sectors = 32 KB at a time,
+					not on uas);
 				n = INITIAL_READ10 (force a retry of the
-					initial READ(10) command);
+					initial READ(10) command, not on uas);
 				o = CAPACITY_OK (accept the capacity
-					reported by the device);
+					reported by the device, not on uas);
 				p = WRITE_CACHE (the device cache is ON
-					by default);
+					by default, not on uas);
 				r = IGNORE_RESIDUE (the device reports
-					bogus residue values);
+					bogus residue values, not on uas);
 				s = SINGLE_LUN (the device has only one
 					Logical Unit);
 				t = NO_ATA_1X (don't allow ATA(12) and ATA(16)
@@ -5130,7 +5342,8 @@
 				w = NO_WP_DETECT (don't test whether the
 					medium is write-protected).
 				y = ALWAYS_SYNC (issue a SYNCHRONIZE_CACHE
-					even if the device claims no cache)
+					even if the device claims no cache,
+					not on uas)
 			Example: quirks=0419:aaf5:rl,0421:0433:rc
 
 	user_debug=	[KNL,ARM]
@@ -5408,6 +5621,10 @@
 			This option is obsoleted by the "nopv" option, which
 			has equivalent effect for XEN platform.
 
+	xen_no_vector_callback
+			[KNL,X86,XEN] Disable the vector callback for Xen
+			event channel interrupts.
+
 	xen_scrub_pages=	[XEN]
 			Boolean option to control scrubbing pages before giving them back
 			to Xen, for use by other domains. Can be also changed at runtime
@@ -5426,6 +5643,21 @@
 			as generic guest with no PV drivers. Currently support
 			XEN HVM, KVM, HYPER_V and VMWARE guest.
 
+	xen.balloon_boot_timeout= [XEN]
+			The time (in seconds) to wait before giving up to boot
+			in case initial ballooning fails to free enough memory.
+			Applies only when running as HVM or PVH guest and
+			started with less memory configured than allowed at
+			max. Default is 180.
+
+	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-ein-5.4.0.orig/Documentation/admin-guide/pm/cpuidle.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/pm/cpuidle.rst
@@ -676,8 +676,8 @@
 by default this way, for example.
 
 The other kernel command line parameters controlling CPU idle time management
-described below are only relevant for the *x86* architecture and some of
-them affect Intel processors only.
+described below are only relevant for the *x86* architecture and references
+to ``intel_idle`` affect Intel processors only.
 
 The *x86* architecture support code recognizes three kernel command line
 options related to CPU idle time management: ``idle=poll``, ``idle=halt``,
@@ -699,10 +699,13 @@
 energy-efficiency.  Thus using it for performance reasons may not be a good idea
 at all.]
 
-The ``idle=nomwait`` option disables the ``intel_idle`` driver and causes
-``acpi_idle`` to be used (as long as all of the information needed by it is
-there in the system's ACPI tables), but it is not allowed to use the
-``MWAIT`` instruction of the CPUs to ask the hardware to enter idle states.
+The ``idle=nomwait`` option prevents the use of ``MWAIT`` instruction of
+the CPU to enter idle states. When this option is used, the ``acpi_idle``
+driver will use the ``HLT`` instruction instead of ``MWAIT``. On systems
+running Intel processors, this option disables the ``intel_idle`` driver
+and forces the use of the ``acpi_idle`` driver instead. Note that in either
+case, ``acpi_idle`` driver will function only if all the information needed
+by it is in the system's ACPI tables.
 
 In addition to the architecture-level kernel command line options affecting CPU
 idle time management, there are parameters affecting individual ``CPUIdle``
--- linux-ein-5.4.0.orig/Documentation/admin-guide/security-bugs.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/security-bugs.rst
@@ -56,31 +56,28 @@
 of the report are treated confidentially even after the embargo has been
 lifted, in perpetuity.
 
-Coordination
-------------
+Coordination with other groups
+------------------------------
 
-Fixes for sensitive bugs, such as those that might lead to privilege
-escalations, may need to be coordinated with the private
-<linux-distros@vs.openwall.org> mailing list so that distribution vendors
-are well prepared to issue a fixed kernel upon public disclosure of the
-upstream fix. Distros will need some time to test the proposed patch and
-will generally request at least a few days of embargo, and vendor update
-publication prefers to happen Tuesday through Thursday. When appropriate,
-the security team can assist with this coordination, or the reporter can
-include linux-distros from the start. In this case, remember to prefix
-the email Subject line with "[vs]" as described in the linux-distros wiki:
-<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>
+The kernel security team strongly recommends that reporters of potential
+security issues NEVER contact the "linux-distros" mailing list until
+AFTER discussing it with the kernel security team.  Do not Cc: both
+lists at once.  You may contact the linux-distros mailing list after a
+fix has been agreed on and you fully understand the requirements that
+doing so will impose on you and the kernel community.
+
+The different lists have different goals and the linux-distros rules do
+not contribute to actually fixing any potential security problems.
 
 CVE assignment
 --------------
 
-The security team does not normally assign CVEs, nor do we require them
-for reports or fixes, as this can needlessly complicate the process and
-may delay the bug handling. If a reporter wishes to have a CVE identifier
-assigned ahead of public disclosure, they will need to contact the private
-linux-distros list, described above. When such a CVE identifier is known
-before a patch is provided, it is desirable to mention it in the commit
-message if the reporter agrees.
+The security team does not assign CVEs, nor do we require them for
+reports or fixes, as this can needlessly complicate the process and may
+delay the bug handling.  If a reporter wishes to have a CVE identifier
+assigned, they should find one by themselves, for example by contacting
+MITRE directly.  However under no circumstances will a patch inclusion
+be delayed to wait for a CVE identifier to arrive.
 
 Non-disclosure agreements
 -------------------------
--- linux-ein-5.4.0.orig/Documentation/admin-guide/sysctl/kernel.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/sysctl/kernel.rst
@@ -48,6 +48,8 @@
 - hyperv_record_panic_msg
 - kexec_load_disabled
 - kptr_restrict
+- io_uring_disabled
+- io_uring_group
 - l2cr                        [ PPC only ]
 - modprobe                    ==> Documentation/debugging-modules.txt
 - modules_disabled
@@ -415,7 +417,6 @@
 
 kptr_restrict:
 ==============
-
 This toggle indicates whether restrictions are placed on
 exposing kernel addresses via /proc and other interfaces.
 
@@ -438,6 +439,35 @@
 %pK will be replaced with 0's regardless of privileges.
 
 
+io_uring_disabled:
+==================
+
+Prevents all processes from creating new io_uring instances. Enabling this
+shrinks the kernel's attack surface.
+
+= ======================================================================
+0 All processes can create io_uring instances as normal. This is the
+  default setting.
+1 io_uring creation is disabled (io_uring_setup() will fail with
+  -EPERM) for unprivileged processes not in the io_uring_group group.
+  Existing io_uring instances can still be used.  See the
+  documentation for io_uring_group for more information.
+2 io_uring creation is disabled for all processes. io_uring_setup()
+  always fails with -EPERM. Existing io_uring instances can still be
+  used.
+= ======================================================================
+
+
+io_uring_group:
+===============
+
+When io_uring_disabled is set to 1, a process must either be
+privileged (CAP_SYS_ADMIN) or be in the io_uring_group group in order
+to create an io_uring instance.  If io_uring_group is set to -1 (the
+default), only processes with the CAP_SYS_ADMIN capability may create
+io_uring instances.
+
+
 l2cr: (PPC only)
 ================
 
@@ -557,6 +587,15 @@
 scanned for a given scan.
 
 
+oops_limit
+==========
+
+Number of kernel oopses after which the kernel should panic when
+``panic_on_oops`` is not set. Setting this to 0 disables checking
+the count. Setting this to  1 has the same effect as setting
+``panic_on_oops=1``. The default value is 10000.
+
+
 osrelease, ostype & version:
 ============================
 
@@ -862,9 +901,40 @@
 a one-time setting until next reboot: once set, it cannot be changed by
 this sysctl interface anymore.
 
+pty
+===
 
-randomize_va_space:
-===================
+See Documentation/filesystems/devpts.rst.
+
+
+random
+======
+
+This is a directory, with the following entries:
+
+* ``boot_id``: a UUID generated the first time this is retrieved, and
+  unvarying after that;
+
+* ``uuid``: a UUID generated every time this is retrieved (this can
+  thus be used to generate UUIDs at will);
+
+* ``entropy_avail``: the pool's entropy count, in bits;
+
+* ``poolsize``: the entropy pool size, in bits;
+
+* ``urandom_min_reseed_secs``: obsolete (used to determine the minimum
+  number of seconds between urandom pool reseeding). This file is
+  writable for compatibility purposes, but writing to it has no effect
+  on any RNG behavior;
+
+* ``write_wakeup_threshold``: when the entropy count drops below this
+  (as a number of bits), processes waiting to write to ``/dev/random``
+  are woken up. This file is writable for compatibility purposes, but
+  writing to it has no effect on any RNG behavior.
+
+
+randomize_va_space
+==================
 
 This option can be used to select the type of process address
 space randomization that is used in the system, for architectures
@@ -1125,6 +1195,37 @@
 example.  If a system hangs up, try pressing the NMI switch.
 
 
+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
+= =============================================================
+
+
+warn_limit
+==========
+
+Number of kernel warnings after which the kernel should panic when
+``panic_on_warn`` is not set. Setting this to 0 disables checking
+the warning count. Setting this to 1 has the same effect as setting
+``panic_on_warn=1``. The default value is 0.
+
+
 watchdog:
 =========
 
--- linux-ein-5.4.0.orig/Documentation/admin-guide/sysctl/net.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/sysctl/net.rst
@@ -31,17 +31,18 @@
 
 Table : Subdirectories in /proc/sys/net
 
- ========= =================== = ========== ==================
+ ========= =================== = ========== ===================
  Directory Content               Directory  Content
- ========= =================== = ========== ==================
- core      General parameter     appletalk  Appletalk protocol
- unix      Unix domain sockets   netrom     NET/ROM
- 802       E802 protocol         ax25       AX25
- ethernet  Ethernet protocol     rose       X.25 PLP layer
+ ========= =================== = ========== ===================
+ 802       E802 protocol         mptcp      Multipath TCP
+ appletalk Appletalk protocol    netfilter  Network Filter
+ ax25      AX25                  netrom     NET/ROM
+ bridge    Bridging              rose       X.25 PLP layer
+ core      General parameter     tipc       TIPC
+ ethernet  Ethernet protocol     unix       Unix domain sockets
  ipv4      IP version 4          x25        X.25 protocol
- bridge    Bridging              decnet     DEC net
- ipv6      IP version 6          tipc       TIPC
- ========= =================== = ========== ==================
+ ipv6      IP version 6
+ ========= =================== = ========== ===================
 
 1. /proc/sys/net/core - Network core options
 ============================================
--- linux-ein-5.4.0.orig/Documentation/admin-guide/sysctl/vm.rst
+++ linux-ein-5.4.0/Documentation/admin-guide/sysctl/vm.rst
@@ -61,6 +61,7 @@
 - overcommit_memory
 - overcommit_ratio
 - page-cluster
+- page_lock_unfairness
 - panic_on_oom
 - percpu_pagelist_fraction
 - stat_interval
@@ -741,6 +742,14 @@
 that consecutive pages readahead would have brought in.
 
 
+page_lock_unfairness
+====================
+
+This value determines the number of times that the page lock can be
+stolen from under a waiter. After the lock is stolen the number of times
+specified in this file (default is 5), the "fair lock handoff" semantics
+will apply, and the waiter will only be awakened if the lock can be taken.
+
 panic_on_oom
 ============
 
--- linux-ein-5.4.0.orig/Documentation/arm/memory.rst
+++ linux-ein-5.4.0/Documentation/arm/memory.rst
@@ -45,9 +45,14 @@
 fffe0000	fffe7fff	ITCM mapping area for platforms with
 				ITCM mounted inside the CPU.
 
-ffc00000	ffefffff	Fixmap mapping region.  Addresses provided
+ffc80000	ffefffff	Fixmap mapping region.  Addresses provided
 				by fix_to_virt() will be located here.
 
+ffc00000	ffc7ffff	Guard region
+
+ff800000	ffbfffff	Permanent, fixed read-only mapping of the
+				firmware provided DT blob
+
 fee00000	feffffff	Mapping of PCI I/O space. This is a static
 				mapping within the vmalloc space.
 
--- linux-ein-5.4.0.orig/Documentation/arm64/silicon-errata.rst
+++ linux-ein-5.4.0/Documentation/arm64/silicon-errata.rst
@@ -70,8 +70,12 @@
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220        |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A57      | #1742098        | ARM64_ERRATUM_1742098       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A72      | #853709         | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A72      | #1655431        | ARM64_ERRATUM_1742098       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A73      | #858921         | ARM64_ERRATUM_858921        |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A55      | #1024718        | ARM64_ERRATUM_1024718       |
@@ -88,6 +92,8 @@
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1349291        | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Neoverse-N1     | #1542419        | ARM64_ERRATUM_1542419       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | MMU-500         | #841119,826419  | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
@@ -128,6 +134,9 @@
 +----------------+-----------------+-----------------+-----------------------------+
 | Hisilicon      | Hip08 SMMU PMCG | #162001800      | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| Hisilicon      | Hip08 SMMU PMCG | #162001900      | N/A                         |
+|                | Hip09 SMMU PMCG |                 |                             |
++----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
 | Qualcomm Tech. | Kryo/Falkor v1  | E1003           | QCOM_FALKOR_ERRATUM_1003    |
 +----------------+-----------------+-----------------+-----------------------------+
--- linux-ein-5.4.0.orig/Documentation/arm64/tagged-address-abi.rst
+++ linux-ein-5.4.0/Documentation/arm64/tagged-address-abi.rst
@@ -44,8 +44,25 @@
 how the user addresses are used by the kernel:
 
 1. User addresses not accessed by the kernel but used for address space
-   management (e.g. ``mmap()``, ``mprotect()``, ``madvise()``). The use
-   of valid tagged pointers in this context is always allowed.
+   management (e.g. ``mprotect()``, ``madvise()``). The use of valid
+   tagged pointers in this context is allowed with these exceptions:
+
+   - ``brk()``, ``mmap()`` and the ``new_address`` argument to
+     ``mremap()`` as these have the potential to alias with existing
+      user addresses.
+
+     NOTE: This behaviour changed in v5.6 and so some earlier kernels may
+     incorrectly accept valid tagged pointers for the ``brk()``,
+     ``mmap()`` and ``mremap()`` system calls.
+
+   - The ``range.start``, ``start`` and ``dst`` arguments to the
+     ``UFFDIO_*`` ``ioctl()``s used on a file descriptor obtained from
+     ``userfaultfd()``, as fault addresses subsequently obtained by reading
+     the file descriptor will be untagged, which may otherwise confuse
+     tag-unaware programs.
+
+     NOTE: This behaviour changed in v5.14 and so some earlier kernels may
+     incorrectly accept valid tagged pointers for this system call.
 
 2. User addresses accessed by the kernel (e.g. ``write()``). This ABI
    relaxation is disabled by default and the application thread needs to
--- linux-ein-5.4.0.orig/Documentation/asm-annotations.rst
+++ linux-ein-5.4.0/Documentation/asm-annotations.rst
@@ -0,0 +1,216 @@
+Assembler Annotations
+=====================
+
+Copyright (c) 2017-2019 Jiri Slaby
+
+This document describes the new macros for annotation of data and code in
+assembly. In particular, it contains information about ``SYM_FUNC_START``,
+``SYM_FUNC_END``, ``SYM_CODE_START``, and similar.
+
+Rationale
+---------
+Some code like entries, trampolines, or boot code needs to be written in
+assembly. The same as in C, such code is grouped into functions and
+accompanied with data. Standard assemblers do not force users into precisely
+marking these pieces as code, data, or even specifying their length.
+Nevertheless, assemblers provide developers with such annotations to aid
+debuggers throughout assembly. On top of that, developers also want to mark
+some functions as *global* in order to be visible outside of their translation
+units.
+
+Over time, the Linux kernel has adopted macros from various projects (like
+``binutils``) to facilitate such annotations. So for historic reasons,
+developers have been using ``ENTRY``, ``END``, ``ENDPROC``, and other
+annotations in assembly.  Due to the lack of their documentation, the macros
+are used in rather wrong contexts at some locations. Clearly, ``ENTRY`` was
+intended to denote the beginning of global symbols (be it data or code).
+``END`` used to mark the end of data or end of special functions with
+*non-standard* calling convention. In contrast, ``ENDPROC`` should annotate
+only ends of *standard* functions.
+
+When these macros are used correctly, they help assemblers generate a nice
+object with both sizes and types set correctly. For example, the result of
+``arch/x86/lib/putuser.S``::
+
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+    25: 0000000000000000    33 FUNC    GLOBAL DEFAULT    1 __put_user_1
+    29: 0000000000000030    37 FUNC    GLOBAL DEFAULT    1 __put_user_2
+    32: 0000000000000060    36 FUNC    GLOBAL DEFAULT    1 __put_user_4
+    35: 0000000000000090    37 FUNC    GLOBAL DEFAULT    1 __put_user_8
+
+This is not only important for debugging purposes. When there are properly
+annotated objects like this, tools can be run on them to generate more useful
+information. In particular, on properly annotated objects, ``objtool`` can be
+run to check and fix the object if needed. Currently, ``objtool`` can report
+missing frame pointer setup/destruction in functions. It can also
+automatically generate annotations for :doc:`ORC unwinder <x86/orc-unwinder>`
+for most code. Both of these are especially important to support reliable
+stack traces which are in turn necessary for :doc:`Kernel live patching
+<livepatch/livepatch>`.
+
+Caveat and Discussion
+---------------------
+As one might realize, there were only three macros previously. That is indeed
+insufficient to cover all the combinations of cases:
+
+* standard/non-standard function
+* code/data
+* global/local symbol
+
+There was a discussion_ and instead of extending the current ``ENTRY/END*``
+macros, it was decided that brand new macros should be introduced instead::
+
+    So how about using macro names that actually show the purpose, instead
+    of importing all the crappy, historic, essentially randomly chosen
+    debug symbol macro names from the binutils and older kernels?
+
+.. _discussion: https://lkml.kernel.org/r/20170217104757.28588-1-jslaby@suse.cz
+
+Macros Description
+------------------
+
+The new macros are prefixed with the ``SYM_`` prefix and can be divided into
+three main groups:
+
+1. ``SYM_FUNC_*`` -- to annotate C-like functions. This means functions with
+   standard C calling conventions, i.e. the stack contains a return address at
+   the predefined place and a return from the function can happen in a
+   standard way. When frame pointers are enabled, save/restore of frame
+   pointer shall happen at the start/end of a function, respectively, too.
+
+   Checking tools like ``objtool`` should ensure such marked functions conform
+   to these rules. The tools can also easily annotate these functions with
+   debugging information (like *ORC data*) automatically.
+
+2. ``SYM_CODE_*`` -- special functions called with special stack. Be it
+   interrupt handlers with special stack content, trampolines, or startup
+   functions.
+
+   Checking tools mostly ignore checking of these functions. But some debug
+   information still can be generated automatically. For correct debug data,
+   this code needs hints like ``UNWIND_HINT_REGS`` provided by developers.
+
+3. ``SYM_DATA*`` -- obviously data belonging to ``.data`` sections and not to
+   ``.text``. Data do not contain instructions, so they have to be treated
+   specially by the tools: they should not treat the bytes as instructions,
+   nor assign any debug information to them.
+
+Instruction Macros
+~~~~~~~~~~~~~~~~~~
+This section covers ``SYM_FUNC_*`` and ``SYM_CODE_*`` enumerated above.
+
+* ``SYM_FUNC_START`` and ``SYM_FUNC_START_LOCAL`` are supposed to be **the
+  most frequent markings**. They are used for functions with standard calling
+  conventions -- global and local. Like in C, they both align the functions to
+  architecture specific ``__ALIGN`` bytes. There are also ``_NOALIGN`` variants
+  for special cases where developers do not want this implicit alignment.
+
+  ``SYM_FUNC_START_WEAK`` and ``SYM_FUNC_START_WEAK_NOALIGN`` markings are
+  also offered as an assembler counterpart to the *weak* attribute known from
+  C.
+
+  All of these **shall** be coupled with ``SYM_FUNC_END``. First, it marks
+  the sequence of instructions as a function and computes its size to the
+  generated object file. Second, it also eases checking and processing such
+  object files as the tools can trivially find exact function boundaries.
+
+  So in most cases, developers should write something like in the following
+  example, having some asm instructions in between the macros, of course::
+
+    SYM_FUNC_START(function_hook)
+        ... asm insns ...
+    SYM_FUNC_END(function_hook)
+
+  In fact, this kind of annotation corresponds to the now deprecated ``ENTRY``
+  and ``ENDPROC`` macros.
+
+* ``SYM_FUNC_START_ALIAS`` and ``SYM_FUNC_START_LOCAL_ALIAS`` serve for those
+  who decided to have two or more names for one function. The typical use is::
+
+    SYM_FUNC_START_ALIAS(__memset)
+    SYM_FUNC_START(memset)
+        ... asm insns ...
+    SYM_FUNC_END(memset)
+    SYM_FUNC_END_ALIAS(__memset)
+
+  In this example, one can call ``__memset`` or ``memset`` with the same
+  result, except the debug information for the instructions is generated to
+  the object file only once -- for the non-``ALIAS`` case.
+
+* ``SYM_CODE_START`` and ``SYM_CODE_START_LOCAL`` should be used only in
+  special cases -- if you know what you are doing. This is used exclusively
+  for interrupt handlers and similar where the calling convention is not the C
+  one. ``_NOALIGN`` variants exist too. The use is the same as for the ``FUNC``
+  category above::
+
+    SYM_CODE_START_LOCAL(bad_put_user)
+        ... asm insns ...
+    SYM_CODE_END(bad_put_user)
+
+  Again, every ``SYM_CODE_START*`` **shall** be coupled by ``SYM_CODE_END``.
+
+  To some extent, this category corresponds to deprecated ``ENTRY`` and
+  ``END``. Except ``END`` had several other meanings too.
+
+* ``SYM_INNER_LABEL*`` is used to denote a label inside some
+  ``SYM_{CODE,FUNC}_START`` and ``SYM_{CODE,FUNC}_END``.  They are very similar
+  to C labels, except they can be made global. An example of use::
+
+    SYM_CODE_START(ftrace_caller)
+        /* save_mcount_regs fills in first two parameters */
+        ...
+
+    SYM_INNER_LABEL(ftrace_caller_op_ptr, SYM_L_GLOBAL)
+        /* Load the ftrace_ops into the 3rd parameter */
+        ...
+
+    SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
+        call ftrace_stub
+        ...
+        retq
+    SYM_CODE_END(ftrace_caller)
+
+Data Macros
+~~~~~~~~~~~
+Similar to instructions, there is a couple of macros to describe data in the
+assembly.
+
+* ``SYM_DATA_START`` and ``SYM_DATA_START_LOCAL`` mark the start of some data
+  and shall be used in conjunction with either ``SYM_DATA_END``, or
+  ``SYM_DATA_END_LABEL``. The latter adds also a label to the end, so that
+  people can use ``lstack`` and (local) ``lstack_end`` in the following
+  example::
+
+    SYM_DATA_START_LOCAL(lstack)
+        .skip 4096
+    SYM_DATA_END_LABEL(lstack, SYM_L_LOCAL, lstack_end)
+
+* ``SYM_DATA`` and ``SYM_DATA_LOCAL`` are variants for simple, mostly one-line
+  data::
+
+    SYM_DATA(HEAP,     .long rm_heap)
+    SYM_DATA(heap_end, .long rm_stack)
+
+  In the end, they expand to ``SYM_DATA_START`` with ``SYM_DATA_END``
+  internally.
+
+Support Macros
+~~~~~~~~~~~~~~
+All the above reduce themselves to some invocation of ``SYM_START``,
+``SYM_END``, or ``SYM_ENTRY`` at last. Normally, developers should avoid using
+these.
+
+Further, in the above examples, one could see ``SYM_L_LOCAL``. There are also
+``SYM_L_GLOBAL`` and ``SYM_L_WEAK``. All are intended to denote linkage of a
+symbol marked by them. They are used either in ``_LABEL`` variants of the
+earlier macros, or in ``SYM_START``.
+
+
+Overriding Macros
+~~~~~~~~~~~~~~~~~
+Architecture can also override any of the macros in their own
+``asm/linkage.h``, including macros specifying the type of a symbol
+(``SYM_T_FUNC``, ``SYM_T_OBJECT``, and ``SYM_T_NONE``).  As every macro
+described in this file is surrounded by ``#ifdef`` + ``#endif``, it is enough
+to define the macros differently in the aforementioned architecture-dependent
+header.
--- linux-ein-5.4.0.orig/Documentation/atomic_bitops.txt
+++ linux-ein-5.4.0/Documentation/atomic_bitops.txt
@@ -59,7 +59,7 @@
  - RMW operations that have a return value are fully ordered.
 
  - RMW operations that are conditional are unordered on FAILURE,
-   otherwise the above rules apply. In the case of test_and_{}_bit() operations,
+   otherwise the above rules apply. In the case of test_and_set_bit_lock(),
    if the bit in memory is unchanged by the operation then it is deemed to have
    failed.
 
--- linux-ein-5.4.0.orig/Documentation/cgroups/namespace.txt
+++ linux-ein-5.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-ein-5.4.0.orig/Documentation/conf.py
+++ linux-ein-5.4.0/Documentation/conf.py
@@ -98,7 +98,7 @@
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+language = 'en'
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
--- linux-ein-5.4.0.orig/Documentation/core-api/printk-formats.rst
+++ linux-ein-5.4.0/Documentation/core-api/printk-formats.rst
@@ -508,6 +508,12 @@
 Thanks
 ======
 
+Kernel messages:
+
+       %pj	123456
+
+       For generating the jhash of a string truncated to six digits
+
 If you add other %p extensions, please extend <lib/test_printf.c> with
 one or more test cases, if at all feasible.
 
--- linux-ein-5.4.0.orig/Documentation/core-api/xarray.rst
+++ linux-ein-5.4.0/Documentation/core-api/xarray.rst
@@ -461,13 +461,15 @@
 Each entry will only be returned once, no matter how many indices it
 occupies.
 
-Using xas_next() or xas_prev() with a multi-index xa_state
-is not supported.  Using either of these functions on a multi-index entry
-will reveal sibling entries; these should be skipped over by the caller.
+Using xas_next() or xas_prev() with a multi-index xa_state is not
+supported.  Using either of these functions on a multi-index entry will
+reveal sibling entries; these should be skipped over by the caller.
 
-Storing ``NULL`` into any index of a multi-index entry will set the entry
-at every index to ``NULL`` and dissolve the tie.  Splitting a multi-index
-entry into entries occupying smaller ranges is not yet supported.
+Storing ``NULL`` into any index of a multi-index entry will set the
+entry at every index to ``NULL`` and dissolve the tie.  A multi-index
+entry can be split into entries occupying smaller ranges by calling
+xas_split_alloc() without the xa_lock held, followed by taking the lock
+and calling xas_split().
 
 Functions and structures
 ========================
--- linux-ein-5.4.0.orig/Documentation/dev-tools/gdb-kernel-debugging.rst
+++ linux-ein-5.4.0/Documentation/dev-tools/gdb-kernel-debugging.rst
@@ -39,6 +39,10 @@
   this mode. In this case, you should build the kernel with
   CONFIG_RANDOMIZE_BASE disabled if the architecture supports KASLR.
 
+- Build the gdb scripts (required on kernels v5.1 and above)::
+
+    make scripts_gdb
+
 - Enable the gdb stub of QEMU/KVM, either
 
     - at VM startup time by appending "-s" to the QEMU command line
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/Makefile
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/Makefile
@@ -12,7 +12,6 @@
 	$(call if_changed,chk_binding)
 
 DT_TMP_SCHEMA := processed-schema.yaml
-extra-y += $(DT_TMP_SCHEMA)
 
 quiet_cmd_mk_schema = SCHEMA  $@
       cmd_mk_schema = $(DT_MK_SCHEMA) $(DT_MK_SCHEMA_FLAGS) -o $@ $(real-prereqs)
@@ -26,8 +25,12 @@
 
 DT_SCHEMA_FILES ?= $(addprefix $(src)/,$(DT_DOCS))
 
+ifeq ($(CHECK_DTBS),)
 extra-y += $(patsubst $(src)/%.yaml,%.example.dts, $(DT_SCHEMA_FILES))
 extra-y += $(patsubst $(src)/%.yaml,%.example.dt.yaml, $(DT_SCHEMA_FILES))
+endif
 
 $(obj)/$(DT_TMP_SCHEMA): $(DT_SCHEMA_FILES) FORCE
 	$(call if_changed,mk_schema)
+
+extra-y += $(DT_TMP_SCHEMA)
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/arm/fsl.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -240,6 +240,7 @@
           - enum:
               - boundary,imx8mq-nitrogen8m # i.MX8MQ NITROGEN Board
               - fsl,imx8mq-evk            # i.MX8MQ EVK Board
+              - google,imx8mq-phanbell    # Google Coral Edge TPU
               - purism,librem5-devkit     # Purism Librem5 devkit
               - solidrun,hummingboard-pulse # SolidRun Hummingboard Pulse
               - technexion,pico-pi-imx8m  # TechNexion PICO-PI-8M evk
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/arm/qcom.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -112,8 +112,8 @@
           - const: qcom,msm8974
 
       - items:
-          - const: qcom,msm8916-mtp/1
           - const: qcom,msm8916-mtp
+          - const: qcom,msm8916-mtp/1
           - const: qcom,msm8916
 
       - items:
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/arm/tegra.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/arm/tegra.yaml
@@ -49,7 +49,7 @@
           - const: toradex,apalis_t30
           - const: nvidia,tegra30
       - items:
-          - const: toradex,apalis_t30-eval-v1.1
+          - const: toradex,apalis_t30-v1.1-eval
           - const: toradex,apalis_t30-eval
           - const: toradex,apalis_t30-v1.1
           - const: toradex,apalis_t30
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/clock/imx8mp-clock.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/clock/imx8mp-clock.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/clock/imx8mp-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX8M Plus Clock Control Module Binding
+
+maintainers:
+  - Anson Huang <Anson.Huang@nxp.com>
+
+description:
+  NXP i.MX8M Plus clock control module is an integrated clock controller, which
+  generates and supplies to all modules.
+
+properties:
+  compatible:
+    const: fsl,imx8mp-ccm
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: 32k osc
+      - description: 24m osc
+      - description: ext1 clock input
+      - description: ext2 clock input
+      - description: ext3 clock input
+      - description: ext4 clock input
+
+  clock-names:
+    items:
+      - const: osc_32k
+      - const: osc_24m
+      - const: clk_ext1
+      - const: clk_ext2
+      - const: clk_ext3
+      - const: clk_ext4
+
+  '#clock-cells':
+    const: 1
+    description:
+      The clock consumer should specify the desired clock by having the clock
+      ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h
+      for the full list of i.MX8M Plus clock IDs.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+
+examples:
+  # Clock Control Module node:
+  - |
+    clk: clock-controller@30380000 {
+        compatible = "fsl,imx8mp-ccm";
+        reg = <0x30380000 0x10000>;
+        #clock-cells = <1>;
+        clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>,
+                 <&clk_ext2>, <&clk_ext3>, <&clk_ext4>;
+        clock-names = "osc_32k", "osc_24m", "clk_ext1",
+                      "clk_ext2", "clk_ext3", "clk_ext4";
+    };
+
+...
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt
@@ -46,7 +46,7 @@
 Example (R-Car H3):
 
 	usb2_clksel: clock-controller@e6590630 {
-		compatible = "renesas,r8a77950-rcar-usb2-clock-sel",
+		compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
 			     "renesas,rcar-gen3-usb2-clock-sel";
 		reg = <0 0xe6590630 0 0x02>;
 		clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>;
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
@@ -10,6 +10,9 @@
 maintainers:
   - Neil Armstrong <narmstrong@baylibre.com>
 
+allOf:
+  - $ref: /schemas/sound/name-prefix.yaml#
+
 description: |
   The Amlogic Meson Synopsys Designware Integration is composed of
   - A Synopsys DesignWare HDMI Controller IP
@@ -101,6 +104,8 @@
   "#sound-dai-cells":
     const: 0
 
+  sound-name-prefix: true
+
 required:
   - compatible
   - reg
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
@@ -78,6 +78,10 @@
   interrupts:
     maxItems: 1
 
+  amlogic,canvas:
+    description: should point to a canvas provider node
+    $ref: /schemas/types.yaml#/definitions/phandle
+
   power-domains:
     maxItems: 1
     description: phandle to the associated power domain
@@ -106,6 +110,7 @@
   - port@1
   - "#address-cells"
   - "#size-cells"
+  - amlogic,canvas
 
 examples:
   - |
@@ -116,6 +121,7 @@
         interrupts = <3>;
         #address-cells = <1>;
         #size-cells = <0>;
+        amlogic,canvas = <&canvas>;
 
         /* CVBS VDAC output port */
         port@0 {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -1,10 +1,10 @@
-Analog Device ADV7511(W)/13/33 HDMI Encoders
+Analog Device ADV7511(W)/13/33/35 HDMI Encoders
 -----------------------------------------
 
-The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
-compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
-the others support RGB interface.
+The ADV7511, ADV7511W, ADV7513, ADV7533 and ADV7535 are HDMI audio and video
+transmitters compatible with HDMI 1.4 and DVI 1.0. They support color space
+conversion, S/PDIF, CEC and HDCP. ADV7533 and ADV7535 support the DSI interface
+for input pixels, while the others support RGB interface.
 
 Required properties:
 
@@ -13,6 +13,7 @@
 		"adi,adv7511w"
 		"adi,adv7513"
 		"adi,adv7533"
+		"adi,adv7535"
 
 - reg: I2C slave addresses
   The ADV7511 internal registers are split into four pages exposed through
@@ -52,7 +53,7 @@
 - bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is
   needed only for ADV7511.
 
-The following properties are required for ADV7533:
+The following properties are required for ADV7533 and ADV7535:
 
 - adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
   be one of 1, 2, 3 or 4.
@@ -71,23 +72,31 @@
 - adi,embedded-sync: The input uses synchronization signals embedded in the
   data stream (similar to BT.656). Defaults to separate H/V synchronization
   signals.
-- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
-  generator. The chip will rely on the sync signals in the DSI data lanes,
-  rather than generate its own timings for HDMI output.
+- adi,disable-timing-generator: Only for ADV7533 and ADV7535. Disables the
+  internal timing generator. The chip will rely on the sync signals in the DSI
+  data lanes, rather than generate its own timings for HDMI output.
 - clocks: from common clock binding: reference to the CEC clock.
 - clock-names: from common clock binding: must be "cec".
 - reg-names : Names of maps with programmable addresses.
 	It can contain any map needing a non-default address.
 	Possible maps names are : "main", "edid", "cec", "packet"
+- adi,dsi-channel: Only for ADV7533 and ADV7535. DSI channel number to be used
+  when communicating with the DSI peripheral. It should be one of 0, 1, 2 or 3.
+- adi,addr-cec: Only for ADV7533 and ADV7535. The I2C DSI-CEC register map
+  address to be programmed into the MAIN register map.
+- adi,addr-edid: Only for ADV7533 and ADV7535. The I2C EDID register map
+  to be programmed into the MAIN register map.
+- adi,addr-pkt: Only for ADV7533 and ADV7535. The I2C PACKET register map
+  to be programmed into the MAIN register map.
 
 Required nodes:
 
 The ADV7511 has two video ports. Their connections are modelled using the OF
 graph bindings specified in Documentation/devicetree/bindings/graph.txt.
 
-- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
-  remote endpoint phandle should be a reference to a valid mipi_dsi_host device
-  node.
+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533 and
+  ADV7535, the remote endpoint phandle should be a reference to a valid
+  mipi_dsi_host device node.
 - Video port 1 for the HDMI output
 - Audio port 2 for the HDMI audio input
 
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/bridge/nxp,seiko-43wvfig.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/bridge/nxp,seiko-43wvfig.txt
@@ -0,0 +1,40 @@
+Legacy Freescale RA169Z20 adapter card for Seiko 43WVFIG panel, driver bindings
+
+This is an adapter card made for the 4.3", 800x480, LCD panel Seiko 43WVFIG.
+The LCD panel is a 24bit DPI bus, while the adapter card has two ports:
+18-bit and 24-bit data input. For the 18-bit data input, the adapter card
+is demuxing some of the data lines, in order to feed all of the 24 lines
+needed by the LCD.
+
+Required properties:
+- compatible: 	"nxp,seiko-43wvfig"
+- bus_mode:	must be one of <18> or <24>, depending on the input port
+		used (18-bit or 24-bit)
+- port:		input and output port nodes with endpoint definitions as
+		defined in Documentation/devicetree/bindings/graph.txt;
+		the input port should be connected to an lcd controller
+		while the output port should be connected to the Seiko
+		43wvfig LCD panel
+
+Example:
+	seiko_adapter: seiko-adapter {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nxp,seiko-43wvfig";
+		bus_mode = <18>;
+
+		port@0 {
+			reg = <0>;
+			adapter_in: endpoint {
+				remote-endpoint = <&lcdif_out>;
+			};
+		};
+		port@1 {
+			reg = <1>;
+			adapter_out: endpoint {
+				remote-endpoint = <&panel_in>;
+			};
+		};
+	};
+
+-
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/bridge/sec_dsim.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/bridge/sec_dsim.txt
@@ -0,0 +1,60 @@
+Samsung MIPI DSIM bridge bindings
+
+The MIPI DSIM host controller drives the video signals from
+display controller to video peripherals using DSI protocol.
+This is an un-managed DSI bridge. In order to use this bridge,
+an encoder or bridge must be implemented to manage the platform
+specific initializations.
+
+Required properties:
+- compatible: 		"fsl,imx8mm-mipi-dsim"
+- reg: 			the register range of the MIPI DSIM controller
+- interrupts: 		the interrupt number for this module
+- clock, clock-names: 	phandles to the MIPI-DSI clocks described in
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+	"cfg"		- DSIM access clock
+	"pll-ref"	- DSIM PHY PLL reference clock
+- assigned-clocks:	phandles to clocks that requires initial configuration
+- assigned-clock-rates:	rates of the clocks that requires initial configuration
+- pref-clk:		Assign DPHY PLL reference clock frequency. If not exists,
+			DSIM bridge driver will use the default lock frequency
+			which is 27MHz.
+- port: 		input and output port nodes with endpoint definitions as
+			defined in Documentation/devicetree/bindings/graph.txt;
+			the input port should be connected to an encoder or a
+			bridge that manages this MIPI DSIM host and the output
+			port should be connected to a panel or a bridge input
+			port
+
+Optional properties:
+-dsi-gpr:		a phandle which provides the MIPI DSIM control and gpr registers
+
+example:
+	mipi_dsi: mipi_dsi@32E10000 {
+		compatible = "fsl,imx8mm-mipi-dsim";
+		reg = <0x0 0x32e10000 0x0 0x400>;
+		clocks = <&clk IMX8MM_CLK_DSI_CORE_DIV>,
+			 <&clk IMX8MM_CLK_DSI_PHY_REF_DIV>;
+		clock-names = "cfg", "pll-ref";
+		assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE_SRC>,
+				  <&clk IMX8MM_CLK_DSI_PHY_REF_SRC>;
+		assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>,
+					 <&clk IMX8MM_VIDEO_PLL1_OUT>;
+		assigned-clock-rates = <266000000>, <594000000>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		dsi-gpr = <&dispmix_gpr>;
+		status = "disabled";
+
+		port@0 {
+			dsim_from_lcdif: endpoint {
+				remote-endpoint = <&lcdif_to_dsim>;
+			};
+		};
+
+		port@1 {
+			dsim_to_adv7535: endpoint {
+				remote-endpoint = <&adv7535_from_dsim>;
+			};
+		};
+
+	};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 NXP
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/imx/nxp,imx8mq-dcss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: iMX8MQ Display Controller Subsystem (DCSS)
+
+maintainers:
+  - Laurentiu Palcu <laurentiu.palcu@nxp.com>
+
+description:
+
+  The DCSS (display controller sub system) is used to source up to three
+  display buffers, compose them, and drive a display using HDMI 2.0a(with HDCP
+  2.2) or MIPI-DSI. The DCSS is intended to support up to 4kp60 displays. HDR10
+  image processing capabilities are included to provide a solution capable of
+  driving next generation high dynamic range displays.
+
+properties:
+  compatible:
+    const: nxp,imx8mq-dcss
+
+  reg:
+    items:
+      - description: DCSS base address and size, up to IRQ steer start
+      - description: DCSS BLKCTL base address and size
+
+  interrupts:
+    items:
+      - description: Context loader completion and error interrupt
+      - description: DTG interrupt used to signal context loader trigger time
+      - description: DTG interrupt for Vblank
+
+  interrupt-names:
+    items:
+      - const: ctxld
+      - const: ctxld_kick
+      - const: vblank
+
+  clocks:
+    items:
+      - description: Display APB clock for all peripheral PIO access interfaces
+      - description: Display AXI clock needed by DPR, Scaler, RTRAM_CTRL
+      - description: RTRAM clock
+      - description: Pixel clock, can be driven either by HDMI phy clock or MIPI
+      - description: DTRC clock, needed by video decompressor
+
+  clock-names:
+    items:
+      - const: apb
+      - const: axi
+      - const: rtrm
+      - const: pix
+      - const: dtrc
+
+  assigned-clocks:
+    items:
+      - description: Phandle and clock specifier of IMX8MQ_CLK_DISP_AXI_ROOT
+      - description: Phandle and clock specifier of IMX8MQ_CLK_DISP_RTRM
+      - description: Phandle and clock specifier of either IMX8MQ_VIDEO2_PLL1_REF_SEL or
+                     IMX8MQ_VIDEO_PLL1_REF_SEL
+
+  assigned-clock-parents:
+    items:
+      - description: Phandle and clock specifier of IMX8MQ_SYS1_PLL_800M
+      - description: Phandle and clock specifier of IMX8MQ_SYS1_PLL_800M
+      - description: Phandle and clock specifier of IMX8MQ_CLK_27M
+
+  assigned-clock-rates:
+    items:
+      - description: Must be 800 MHz
+      - description: Must be 400 MHz
+
+  port:
+    type: object
+    description:
+      A port node pointing to the input port of a HDMI/DP or MIPI display bridge.
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mq-clock.h>
+    dcss: display-controller@32e00000 {
+        compatible = "nxp,imx8mq-dcss";
+        reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>;
+        interrupts = <6>, <8>, <9>;
+        interrupt-names = "ctxld", "ctxld_kick", "vblank";
+        interrupt-parent = <&irqsteer>;
+        clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>, <&clk IMX8MQ_CLK_DISP_AXI_ROOT>,
+                 <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>, <&clk IMX8MQ_VIDEO2_PLL_OUT>,
+                 <&clk IMX8MQ_CLK_DISP_DTRC>;
+        clock-names = "apb", "axi", "rtrm", "pix", "dtrc";
+        assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>, <&clk IMX8MQ_CLK_DISP_RTRM>,
+                          <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>;
+        assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>, <&clk IMX8MQ_SYS1_PLL_800M>,
+                                 <&clk IMX8MQ_CLK_27M>;
+        assigned-clock-rates = <800000000>,
+                               <400000000>;
+        port {
+            dcss_out: endpoint {
+                remote-endpoint = <&hdmi_in>;
+            };
+        };
+    };
+
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt
@@ -16,6 +16,9 @@
   Documentation/devicetree/bindings/graph.txt. This port should be connected
   to the input port of an attached HDMI or LVDS encoder chip.
 
+Optional properties:
+- pinctrl-names: Contain "default" and "sleep".
+
 Example:
 
 dpi0: dpi@1401d000 {
@@ -26,6 +29,9 @@
 		 <&mmsys CLK_MM_DPI_ENGINE>,
 		 <&apmixedsys CLK_APMIXED_TVDPLL>;
 	clock-names = "pixel", "engine", "pll";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&dpi_pin_func>;
+	pinctrl-1 = <&dpi_pin_idle>;
 
 	port {
 		dpi0_out: endpoint {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
@@ -58,7 +58,7 @@
 then:
   properties:
     clocks:
-      maxItems: 2
+      minItems: 2
 
   required:
     - clock-names
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -51,8 +51,14 @@
 	22	SSI Dual FIFO	(needs firmware ver >= 2)
 	23	Shared ASRC
 	24	SAI
+	25	HDMI Audio
 
-The third cell specifies the transfer priority as below.
+The third cell specifies the transfer priority and software done
+as below.
+
+	Bit31: sw_done
+	Bit15~Bit8: selector
+	Bit7~Bit0: priority level
 
 	ID	transfer priority
 	-------------------------
@@ -60,6 +66,9 @@
 	1	Medium
 	2	Low
 
+For example: 0x80000000 means sw_done enabled for done0 sector and
+	High priority for PDM on i.mx8mm.
+
 Optional properties:
 
 - gpr : The phandle to the General Purpose Register (GPR) node.
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt
@@ -34,8 +34,8 @@
 Use specific request line passing from dma
 For example, MMC request line is 5
 
-	sdhci: sdhci@98e00000 {
-		compatible = "moxa,moxart-sdhci";
+	mmc: mmc@98e00000 {
+		compatible = "moxa,moxart-mmc";
 		reg = <0x98e00000 0x5C>;
 		interrupts = <5 0>;
 		clocks = <&clk_apb>;
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/gpio/gpio-altera.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/gpio/gpio-altera.txt
@@ -9,8 +9,9 @@
   - The second cell is reserved and is currently unused.
 - gpio-controller : Marks the device node as a GPIO controller.
 - interrupt-controller: Mark the device node as an interrupt controller
-- #interrupt-cells : Should be 1. The interrupt type is fixed in the hardware.
+- #interrupt-cells : Should be 2. The interrupt type is fixed in the hardware.
   - The first cell is the GPIO offset number within the GPIO controller.
+  - The second cell is the interrupt trigger type and level flags.
 - interrupts: Specify the interrupt.
 - altr,interrupt-type: Specifies the interrupt trigger type the GPIO
   hardware is synthesized. This field is required if the Altera GPIO controller
@@ -38,6 +39,6 @@
 	altr,interrupt-type = <IRQ_TYPE_EDGE_RISING>;
 	#gpio-cells = <2>;
 	gpio-controller;
-	#interrupt-cells = <1>;
+	#interrupt-cells = <2>;
 	interrupt-controller;
 };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
@@ -20,8 +20,9 @@
 - gpio-controller : Marks the device node as a GPIO controller
 - interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
 - interrupt-controller : Mark the GPIO controller as an interrupt-controller
-- ngpios : number of GPIO lines, see gpio.txt
-  (should be multiple of 8, up to 80 pins)
+- ngpios : number of *hardware* GPIO lines, see gpio.txt. This will expose
+  2 software GPIOs per hardware GPIO: one for hardware input, one for hardware
+  output. Up to 80 pins, must be a multiple of 8.
 - clocks : A phandle to the APB clock for SGPM clock division
 - bus-frequency : SGPM CLK frequency
 
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
@@ -85,7 +85,7 @@
       Must be the device tree identifier of the over-sampling
       mode pins. As the line is active high, it should be marked
       GPIO_ACTIVE_HIGH.
-    maxItems: 1
+    maxItems: 3
 
   adi,sw-mode:
     description:
@@ -128,9 +128,9 @@
                 adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
                 reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
                 adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
-                adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH
-                                                &gpio 23 GPIO_ACTIVE_HIGH
-                                                &gpio 26 GPIO_ACTIVE_HIGH>;
+                adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>,
+                                               <&gpio 23 GPIO_ACTIVE_HIGH>,
+                                               <&gpio 26 GPIO_ACTIVE_HIGH>;
                 standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
                 adi,sw-mode;
         };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
@@ -21,7 +21,7 @@
 
 Example:
 	mux: mux-controller {
-		compatible = "mux-gpio";
+		compatible = "gpio-mux";
 		#mux-control-cells = <0>;
 
 		mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/input/touchscreen/focaltech-ts.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/input/touchscreen/focaltech-ts.txt
@@ -0,0 +1,48 @@
+FocalTech touch controller
+
+The focaltech controller is connected to host processor via i2c.
+The controller generates interrupts when the user touches the panel.
+The host controller is expected to read the touch coordinates over
+i2c and pass the coordinates to the rest of the system.
+
+Required properties:
+ - compatible		: should be "focaltech,fts"
+ - reg			: i2c slave address of the device, should be <0x38>
+ - interrupt-parent	: parent of interrupt
+ - interrupts		: irq gpio, "0x02" stands for that the irq triggered by falling edge.
+ - focaltech,irq-gpio	: irq gpio, same as "interrupts" node.
+ - focaltech,reset-gpio	: reset gpio
+ - focaltech,num-max-touches	: maximum number of touches support
+ - focaltech,display-coords	: display resolution in pixels. A four tuple consisting of minX, minY, maxX and maxY.
+
+Optional properties:
+ - focaltech,have-key		: specify if virtual keys are supported
+ - focaltech,key-number		: number of keys
+ - focaltech,keys		: virtual key codes mapping to the coords
+ - focaltech,key-y-coord	: constant y coordinate of keys, depends on the y resolution
+ - focaltech,key-x-coords	: constant x coordinates of keys, depends on the x resolution
+ - focaltech,swap-xy		: swap x-y coordinates
+ - focaltech,panel-type		: set panel type, default is FT5416 panel
+ - focaltech,scaling-down-half	: scale down the x-y coordiantes to half
+
+
+Example:
+	i2c@f9927000 {
+		focaltech@38{
+			compatible = "focaltech,fts";
+			reg = <0x38>;
+			interrupt-parent = <&msm_gpio>;
+			interrupts = <13 0x02>;
+			focaltech,reset-gpio = <&msm_gpio 12 0x01>;
+			focaltech,irq-gpio = <&msm_gpio 13 0x02>;
+			focaltech,max-touch-number = <5>;
+			focaltech,display-coords =  <0 0 1080 1920>;
+
+			focaltech,have-key;
+			focaltech,key-number = <3>;
+			focaltech,keys = <139 102 158>;
+			focaltech,key-y-coord = <2000>;
+			focaltech,key-x-coords = <200 600 800>;
+			focaltech,swap-xy;
+		};
+	};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
@@ -55,7 +55,7 @@
 			corresponds to a range of host irqs.
 
 For more details on TISCI IRQ resource management refer:
-http://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
+https://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
 
 Example:
 --------
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.txt
@@ -87,7 +87,7 @@
 		ranges;
 
 		/* APU<->RPU0 IPI mailbox controller */
-		ipi_mailbox_rpu0: mailbox@ff90400 {
+		ipi_mailbox_rpu0: mailbox@ff990400 {
 			reg = <0xff990400 0x20>,
 			      <0xff990420 0x20>,
 			      <0xff990080 0x20>,
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mfd/ahc1ec0.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mfd/ahc1ec0.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/ahc1ec0.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Advantech Embedded Controller (AHC1EC0)
+
+maintainers:
+  - Campion Kang <campion.kang@advantech.com.tw>
+
+description: |
+  AHC1EC0 is one of the embedded controllers used by Advantech to provide several
+  functions such as watchdog, hwmon, brightness, etc. Advantech related applications
+  can control the whole system via these functions.
+
+properties:
+  compatible:
+    const: advantech,ahc1ec0
+
+  advantech,sub-dev-nb:
+    description:
+      The number of sub-devices specified in the platform.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maxItems: 1
+
+  advantech,sub-dev:
+    description:
+      A list of the sub-devices supported in the platform. Defines for the
+      appropriate values can found in dt-bindings/mfd/ahc1ec0-dt.h.
+    $ref: "/schemas/types.yaml#/definitions/uint32-array"
+    minItems: 1
+    maxItems: 6
+
+  advantech,hwmon-profile:
+    description:
+      The number of sub-devices specified in the platform. Defines for the
+      hwmon profiles can found in dt-bindings/mfd/ahc1ec0-dt.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maxItems: 1
+
+required:
+  - compatible
+  - advantech,sub-dev-nb
+  - advantech,sub-dev
+
+if:
+  properties:
+    advantech,sub-dev:
+      contains:
+        const: 0x3
+then:
+  required:
+    - advantech,hwmon-profile
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/mfd/ahc1ec0-dt.h>
+    ahc1ec0 {
+        compatible = "advantech,ahc1ec0";
+
+        advantech,sub-dev-nb = <2>;
+        advantech,sub-dev = <AHC1EC0_SUBDEV_HWMON
+                             AHC1EC0_SUBDEV_WDT>;
+
+        advantech,hwmon-profile = <AHC1EC0_HWMON_PRO_UNO2271G>;
+    };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
@@ -0,0 +1,197 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/gateworks-gsc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Gateworks System Controller
+
+description: |
+  The Gateworks System Controller (GSC) is a device present across various
+  Gateworks product families that provides a set of system related features
+  such as the following (refer to the board hardware user manuals to see what
+  features are present)
+   - Watchdog Timer
+   - GPIO
+   - Pushbutton controller
+   - Hardware monitor with ADC's for temperature and voltage rails and
+     fan controller
+
+maintainers:
+  - Tim Harvey <tharvey@gateworks.com>
+  - Robert Jones <rjones@gateworks.com>
+
+properties:
+  $nodename:
+    pattern: "gsc@[0-9a-f]{1,2}"
+  compatible:
+    const: gw,gsc
+
+  reg:
+    description: I2C device address
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  adc:
+    type: object
+    description: Optional hardware monitoring module
+
+    properties:
+      compatible:
+        const: gw,gsc-adc
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^channel@[0-9]+$":
+        type: object
+        description: |
+          Properties for a single ADC which can report cooked values
+          (i.e. temperature sensor based on thermister), raw values
+          (i.e. voltage rail with a pre-scaling resistor divider).
+
+        properties:
+          reg:
+            description: Register of the ADC
+            maxItems: 1
+
+          label:
+            description: Name of the ADC input
+
+          gw,mode:
+            description: |
+              conversion mode:
+                0 - temperature, in C*10
+                1 - pre-scaled 24-bit voltage value
+                2 - scaled voltage based on an optional resistor divider
+                    and optional offset
+                3 - pre-scaled 16-bit voltage value
+            $ref: /schemas/types.yaml#/definitions/uint32
+            enum: [0, 1, 2, 3]
+
+          gw,voltage-divider-ohms:
+            description: Values of resistors for divider on raw ADC input
+            maxItems: 2
+            items:
+             minimum: 1000
+             maximum: 1000000
+
+          gw,voltage-offset-microvolt:
+            description: |
+              A positive voltage offset to apply to a raw ADC
+              (i.e. to compensate for a diode drop).
+            minimum: 0
+            maximum: 1000000
+
+        required:
+          - gw,mode
+          - reg
+          - label
+
+    required:
+      - compatible
+      - "#address-cells"
+      - "#size-cells"
+
+patternProperties:
+  "^fan-controller@[0-9a-f]+$":
+    type: object
+    description: Optional fan controller
+
+    properties:
+      compatible:
+        const: gw,gsc-fan
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      reg:
+        description: The fan controller base address
+        maxItems: 1
+
+    required:
+      - compatible
+      - reg
+      - "#address-cells"
+      - "#size-cells"
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        gsc@20 {
+            compatible = "gw,gsc";
+            reg = <0x20>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <4 GPIO_ACTIVE_LOW>;
+            interrupt-controller;
+            #interrupt-cells = <1>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            adc {
+                compatible = "gw,gsc-adc";
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                channel@0 { /* A0: Board Temperature */
+                    reg = <0x00>;
+                    label = "temp";
+                    gw,mode = <0>;
+                };
+
+                channel@2 { /* A1: Input Voltage (raw ADC) */
+                    reg = <0x02>;
+                    label = "vdd_vin";
+                    gw,mode = <1>;
+                    gw,voltage-divider-ohms = <22100 1000>;
+                    gw,voltage-offset-microvolt = <800000>;
+                };
+
+                channel@b { /* A2: Battery voltage */
+                    reg = <0x0b>;
+                    label = "vdd_bat";
+                    gw,mode = <1>;
+                };
+            };
+
+            fan-controller@2c {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                compatible = "gw,gsc-fan";
+                reg = <0x2c>;
+            };
+        };
+    };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -49,6 +49,8 @@
 		     error caused by stop clock(fifo full)
 		     Valid range = [0:0x7]. if not present, default value is 0.
 		     applied to compatible "mediatek,mt2701-mmc".
+- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
+- reset-names: Should be "hrst".
 
 Examples:
 mmc0: mmc@11230000 {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
@@ -15,8 +15,15 @@
   - "nvidia,tegra210-sdhci": for Tegra210
   - "nvidia,tegra186-sdhci": for Tegra186
   - "nvidia,tegra194-sdhci": for Tegra194
-- clocks : Must contain one entry, for the module clock.
-  See ../clocks/clock-bindings.txt for details.
+- clocks: For Tegra210, Tegra186 and Tegra194 must contain two entries.
+	  One for the module clock and one for the timeout clock.
+	  For all other Tegra devices, must contain a single entry for
+	  the module clock. See ../clocks/clock-bindings.txt for details.
+- clock-names: For Tegra210, Tegra186 and Tegra194 must contain the
+	       strings 'sdhci' and 'tmclk' to represent the module and
+	       the timeout clocks, respectively.
+	       For all other Tegra devices must contain the string 'sdhci'
+	       to represent the module clock.
 - resets : Must contain an entry for each entry in reset-names.
   See ../reset/reset.txt for details.
 - reset-names : Must include the following entries:
@@ -99,7 +106,7 @@
 
 Example:
 sdhci@700b0000 {
-	compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
+	compatible = "nvidia,tegra124-sdhci";
 	reg = <0x0 0x700b0000 0x0 0x200>;
 	interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
 	clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
@@ -107,6 +114,25 @@
 	resets = <&tegra_car 14>;
 	reset-names = "sdhci";
 	pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
+	pinctrl-0 = <&sdmmc1_3v3>;
+	pinctrl-1 = <&sdmmc1_1v8>;
+	nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
+	nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>;
+	nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>;
+	nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
+	status = "disabled";
+};
+
+sdhci@700b0000 {
+	compatible = "nvidia,tegra210-sdhci";
+	reg = <0x0 0x700b0000 0x0 0x200>;
+	interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
+		 <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+	clock-names = "sdhci", "tmclk";
+	resets = <&tegra_car 14>;
+	reset-names = "sdhci";
+	pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
 	pinctrl-0 = <&sdmmc1_3v3>;
 	pinctrl-1 = <&sdmmc1_1v8>;
 	nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -122,7 +122,7 @@
 	so the device should have enough free bytes available its OOB/Spare
 	area to accommodate ECC for entire page. In general following expression
 	helps in determining if given device can accommodate ECC syndrome:
-	"2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE"
+	"2 + (PAGESIZE / 512) * ECC_BYTES" <= OOBSIZE"
 	where
 		OOBSIZE		number of bytes in OOB/spare area
 		PAGESIZE	number of bytes in main-area of device page
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/mtd/nand-controller.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/mtd/nand-controller.yaml
@@ -44,7 +44,7 @@
     properties:
       reg:
         description:
-          Contains the native Ready/Busy IDs.
+          Contains the chip-select IDs.
 
       nand-ecc-mode:
         allOf:
@@ -139,6 +139,6 @@
         nand-ecc-mode = "soft";
         nand-ecc-algo = "bch";
 
-        /* controller specific properties */
+        /* NAND chip specific properties */
       };
     };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/btusb.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/btusb.txt
@@ -38,7 +38,7 @@
 	compatible = "usb1286,204e";
 	reg = <1>;
 	interrupt-parent = <&gpio0>;
-	interrupt-name = "wakeup";
+	interrupt-names = "wakeup";
 	interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
     };
 };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
@@ -31,9 +31,9 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		spi-max-frequency = <10000000>;
-		bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>;
+		bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
 		interrupt-parent = <&gpio1>;
-		interrupts = <14 GPIO_ACTIVE_LOW>;
+		interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
 		device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
 		device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
 		reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -51,7 +51,7 @@
     description:
       Reference to an nvmem node for the MAC address
 
-  nvmem-cells-names:
+  nvmem-cell-names:
     const: mac-address
 
   phy-connection-type:
@@ -190,6 +190,11 @@
                 Indicates that full-duplex is used. When absent, half
                 duplex is assumed.
 
+            pause:
+              $ref: /schemas/types.yaml#definitions/flag
+              description:
+                Indicates that pause should be enabled.
+
             asym-pause:
               $ref: /schemas/types.yaml#definitions/flag
               description:
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/ethernet-phy.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/ethernet-phy.yaml
@@ -87,6 +87,14 @@
       compensate for the board being designed with the lanes
       swapped.
 
+  enet-phy-lane-no-swap:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      If set, indicates that PHY will disable swap of the
+      TX/RX lanes. This property allows the PHY to work correcly after
+      e.g. wrong bootstrap configuration caused by issues in PCB
+      layout design.
+
   eee-broken-100tx:
     $ref: /schemas/types.yaml#definitions/flag
     description:
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -22,6 +22,11 @@
 - fsl,err006687-workaround-present: If present indicates that the system has
   the hardware workaround for ERR006687 applied and does not need a software
   workaround.
+- fsl,stop-mode: register bits of stop mode control, the format is
+		 <&gpr req_gpr req_bit>.
+		 gpr is the phandle to general purpose register node.
+		 req_gpr is the gpr register offset for ENET stop request.
+		 req_bit is the gpr bit offset for ENET stop request.
  -interrupt-names:  names of the interrupts listed in interrupts property in
   the same order. The defaults if not specified are
   __Number of interrupts__   __Default__
@@ -80,6 +85,7 @@
 	phy-supply = <&reg_fec_supply>;
 	phy-handle = <&ethphy>;
 	mdio {
+	        clock-frequency = <5000000>;
 		ethphy: ethernet-phy@6 {
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <6>;
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/fsl-fman.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/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-ein-5.4.0.orig/Documentation/devicetree/bindings/net/mdio.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/mdio.yaml
@@ -39,6 +39,18 @@
       and must therefore be appropriately determined based on all PHY
       requirements (maximum value of all per-PHY RESET pulse widths).
 
+  clock-frequency:
+    description:
+      Desired MDIO bus clock frequency in Hz. Values greater than IEEE 802.3
+      defined 2.5MHz should only be used when all devices on the bus support
+      the given clock speed.
+
+  suppress-preamble:
+    description:
+      The 32 bit preamble should be suppressed. In order for this to
+      work, all devices on the bus must support suppressed preamble.
+    type: boolean
+
 patternProperties:
   "^ethernet-phy@[0-9a-f]+$":
     type: object
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt
@@ -25,7 +25,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-ein-5.4.0.orig/Documentation/devicetree/bindings/net/nfc/pn544.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/nfc/pn544.txt
@@ -25,7 +25,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-ein-5.4.0.orig/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -347,6 +347,7 @@
               - st,spear600-gmac
 
     then:
+      properties:
         snps,tso:
           $ref: /schemas/types.yaml#definitions/flag
           description:
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
@@ -81,6 +81,12 @@
 	Definition: Name of external front end module used. Some valid FEM names
 		    for example: "microsemi-lx5586", "sky85703-11"
 		    and "sky85803" etc.
+- qcom,snoc-host-cap-8bit-quirk:
+	Usage: Optional
+	Value type: <empty>
+	Definition: Quirk specifying that the firmware expects the 8bit version
+		    of the host capability QMI request
+
 
 Example (to supply PCI based wifi block details):
 
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
@@ -10,6 +10,8 @@
 	- "fsl,imx6qp-pcie"
 	- "fsl,imx7d-pcie"
 	- "fsl,imx8mq-pcie"
+	- "fsl,imx8qm-pcie"
+	- "fsl,imx8qxp-pcie"
 - reg: base address and length of the PCIe controller
 - interrupts: A list of interrupt outputs of the controller. Must contain an
   entry for each entry in the interrupt-names property.
@@ -38,6 +40,9 @@
   The regulator will be enabled when initializing the PCIe host and
   disabled either as part of the init process or when shutting down the
   host.
+- vph-supply: Should specify the regulator in charge of VPH one of the three
+  PCIe PHY powers. This regulator can be supplied by both 1.8v and 3.3v voltage
+  supplies.
 
 Additional required properties for imx6sx-pcie:
 - clock names: Must include the following additional entries:
@@ -60,6 +65,17 @@
 - clock-names: Must include the following additional entries:
 	- "pcie_aux"
 
+Additional required properties for imx8 pcie:
+- hsio-cfg: hsio configration mode when the pcie node is supported.
+  mode 1: pciea 2 lanes and one sata ahci port.
+  mode 2: pciea 1 lane, pcieb 1 lane and one sata ahci port.
+  mode 3: pciea 2 lanes, pcieb 1 lane.
+- local-addr: the local address used in hsio module.
+	Example:
+		hsio-cfg = <PCIEAX2PCIEBX1>;
+		hsio = <&hsio>;
+		local-addr = <0x80000000>;
+
 Example:
 
 	pcie@01000000 {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie.txt
@@ -118,7 +118,7 @@
 --------
 
 	pcie@14180000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8B>;
 		reg = <0x00 0x14180000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x38000000 0x0 0x00040000   /* configuration space (256K) */
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt
@@ -5,6 +5,9 @@
 - compatible: should be one of:
 	"fsl,imx8-ddr-pmu"
 	"fsl,imx8m-ddr-pmu"
+	"fsl,imx8mp-ddr-pmu"
+	"fsl,imx8dxl-ddr-pmu"
+	"fsl,imx8dxl-db-pmu"
 
 - reg: physical address and size
 
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic G12A USB3 + PCIE Combo PHY
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+
+properties:
+  compatible:
+    enum:
+      - amlogic,g12a-usb3-pcie-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: ref_clk
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: phy
+
+  "#phy-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - "#phy-cells"
+
+examples:
+  - |
+    phy@46000 {
+          compatible = "amlogic,g12a-usb3-pcie-phy";
+          reg = <0x46000 0x2000>;
+          clocks = <&ref_clk>;
+          clock-names = "ref_clk";
+          resets = <&phy_reset>;
+          reset-names = "phy";
+          #phy-cells = <1>;
+    };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt
@@ -1,7 +1,7 @@
 * Freescale i.MX8MQ USB3 PHY binding
 
 Required properties:
-- compatible:	Should be "fsl,imx8mq-usb-phy"
+- compatible:	Should be "fsl,imx8mq-usb-phy" or "fsl,imx8mp-usb-phy"
 - #phys-cells:	must be 0 (see phy-bindings.txt in this directory)
 - reg:		The base address and length of the registers
 - clocks:	phandles to the clocks for each clock listed in clock-names
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/pinctrl/fsl,imx8mp-pinctrl.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/pinctrl/fsl,imx8mp-pinctrl.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/fsl,imx8mp-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale IMX8MP IOMUX Controller
+
+maintainers:
+  - Anson Huang <Anson.Huang@nxp.com>
+
+description:
+  Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
+  for common binding part and usage.
+
+properties:
+  compatible:
+    const: fsl,imx8mp-iomuxc
+
+  reg:
+    maxItems: 1
+
+# Client device subnode's properties
+patternProperties:
+  'grp$':
+    type: object
+    description:
+      Pinctrl node's client devices use subnodes for desired pin configuration.
+      Client device subnodes use below standard properties.
+
+    properties:
+      fsl,pins:
+        description:
+          each entry consists of 6 integers and represents the mux and config
+          setting for one pin. The first 5 integers <mux_reg conf_reg input_reg
+          mux_val input_val> are specified using a PIN_FUNC_ID macro, which can
+          be found in <arch/arm64/boot/dts/freescale/imx8mp-pinfunc.h>. The last
+          integer CONFIG is the pad setting value like pull-up on this pin. Please
+          refer to i.MX8M Plus Reference Manual for detailed CONFIG settings.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-matrix
+          - items:
+              items:
+                - description: |
+                    "mux_reg" indicates the offset of mux register.
+                - description: |
+                    "conf_reg" indicates the offset of pad configuration register.
+                - description: |
+                    "input_reg" indicates the offset of select input register.
+                - description: |
+                    "mux_val" indicates the mux value to be applied.
+                - description: |
+                    "input_val" indicates the select input value to be applied.
+                - description: |
+                    "pad_setting" indicates the pad configuration value to be applied.
+
+    required:
+      - fsl,pins
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  # Pinmux controller node
+  - |
+    iomuxc: pinctrl@30330000 {
+        compatible = "fsl,imx8mp-iomuxc";
+        reg = <0x30330000 0x10000>;
+
+        pinctrl_uart2: uart2grp {
+            fsl,pins =
+                <0x228 0x488 0x5F0 0x0 0x6	0x49>,
+                <0x228 0x488 0x000 0x0 0x0	0x49>;
+        };
+    };
+
+...
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
@@ -43,19 +43,19 @@
 
 group pwm0
  - pin 11 (GPIO1-11)
- - functions pwm, gpio
+ - functions pwm, led, gpio
 
 group pwm1
  - pin 12
- - functions pwm, gpio
+ - functions pwm, led, gpio
 
 group pwm2
  - pin 13
- - functions pwm, gpio
+ - functions pwm, led, gpio
 
 group pwm3
  - pin 14
- - functions pwm, gpio
+ - functions pwm, led, gpio
 
 group pmic1
  - pin 7
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
@@ -0,0 +1,195 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/nxp,pca9450-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCA9450A/B/C Power Management Integrated Circuit regulators
+
+maintainers:
+  - Robin Gong <yibin.gong@nxp.com>
+
+description: |
+  Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
+  definition for each of these nodes is defined using the standard
+  binding for regulators at
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+  Datasheet is available at
+  https://www.nxp.com/docs/en/data-sheet/PCA9450DS.pdf
+
+#The valid names for PCA9450 regulator nodes are:
+#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6,
+#LDO1, LDO2, LDO3, LDO4, LDO5
+#Note: Buck3 removed on PCA9450B and connect with Buck1 on PCA9450C.
+
+properties:
+  compatible:
+    enum:
+      - nxp,pca9450a
+      - nxp,pca9450b
+      - nxp,pca9450c
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  regulators:
+    type: object
+    description: |
+      list of regulators provided by this controller
+
+    patternProperties:
+      "^LDO[1-5]$":
+        type: object
+        $ref: regulator.yaml#
+        description:
+          Properties for single LDO regulator.
+
+        properties:
+          regulator-name:
+            pattern: "^LDO[1-5]$"
+            description:
+              should be "LDO1", ..., "LDO5"
+
+        unevaluatedProperties: false
+
+      "^BUCK[1-6]$":
+        type: object
+        $ref: regulator.yaml#
+        description:
+          Properties for single BUCK regulator.
+
+        properties:
+          regulator-name:
+            pattern: "^BUCK[1-6]$"
+            description:
+              should be "BUCK1", ..., "BUCK6"
+
+          nxp,dvs-run-voltage:
+            $ref: "/schemas/types.yaml#/definitions/uint32"
+            minimum: 600000
+            maximum: 2187500
+            description:
+              PMIC default "RUN" state voltage in uV. Only Buck1~3 have such
+              dvs(dynamic voltage scaling) property.
+
+          nxp,dvs-standby-voltage:
+            $ref: "/schemas/types.yaml#/definitions/uint32"
+            minimum: 600000
+            maximum: 2187500
+            description:
+              PMIC default "STANDBY" state voltage in uV. Only Buck1~3 have such
+              dvs(dynamic voltage scaling) property.
+
+        unevaluatedProperties: false
+
+    additionalProperties: false
+
+  sd-vsel-gpios:
+    description: GPIO that is used to switch LDO5 between being configured by
+      LDO5CTRL_L or LDO5CTRL_H register. Use this if the SD_VSEL signal is
+      connected to a host GPIO.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        pmic: pmic@25 {
+            compatible = "nxp,pca9450b";
+            reg = <0x25>;
+            pinctrl-0 = <&pinctrl_pmic>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+            regulators {
+                buck1: BUCK1 {
+                    regulator-name = "BUCK1";
+                    regulator-min-microvolt = <600000>;
+                    regulator-max-microvolt = <2187500>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <3125>;
+                };
+                buck2: BUCK2 {
+                    regulator-name = "BUCK2";
+                    regulator-min-microvolt = <600000>;
+                    regulator-max-microvolt = <2187500>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <3125>;
+                    nxp,dvs-run-voltage = <950000>;
+                    nxp,dvs-standby-voltage = <850000>;
+                };
+                buck4: BUCK4 {
+                    regulator-name = "BUCK4";
+                    regulator-min-microvolt = <600000>;
+                    regulator-max-microvolt = <3400000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                buck5: BUCK5 {
+                    regulator-name = "BUCK5";
+                    regulator-min-microvolt = <600000>;
+                    regulator-max-microvolt = <3400000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                buck6: BUCK6 {
+                    regulator-name = "BUCK6";
+                    regulator-min-microvolt = <600000>;
+                    regulator-max-microvolt = <3400000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+
+                ldo1: LDO1 {
+                    regulator-name = "LDO1";
+                    regulator-min-microvolt = <1600000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                ldo2: LDO2 {
+                    regulator-name = "LDO2";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <1150000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                ldo3: LDO3 {
+                    regulator-name = "LDO3";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                ldo4: LDO4 {
+                    regulator-name = "LDO4";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+                ldo5: LDO5 {
+                    regulator-name = "LDO5";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                };
+            };
+        };
+    };
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
@@ -13,6 +13,14 @@
 
 
 Required properties of the main device node (the parent!):
+ - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
+   for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
+
+ [1] If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+     property is specified, then all the eight voltage values for the
+     's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
+
+Optional properties of the main device node (the parent!):
  - s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
    units for buck2 when changing voltage using gpio dvs. Refer to [1] below
    for additional information.
@@ -25,26 +33,13 @@
    units for buck4 when changing voltage using gpio dvs. Refer to [1] below
    for additional information.
 
- - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
-   for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
-
- [1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
-     property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
-     property should specify atleast one voltage level (which would be a
-     safe operating voltage).
-
-     If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
-     property is specified, then all the eight voltage values for the
-     's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
-
-Optional properties of the main device node (the parent!):
  - s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
  - s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
  - s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
 
 Additional properties required if either of the optional properties are used:
 
- - s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
+ - s5m8767,pmic-buck-default-dvs-idx: Default voltage setting selected from
    the possible 8 options selectable by the dvs gpios. The value of this
    property should be between 0 and 7. If not specified or if out of range, the
    default value of this property is set to 0.
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/reset/brcm,brcmstb-reset.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/reset/brcm,brcmstb-reset.txt
@@ -22,6 +22,6 @@
 	};
 
 	&ethernet_switch {
-		resets = <&reset>;
+		resets = <&reset 26>;
 		reset-names = "switch";
 	};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt
@@ -9,6 +9,8 @@
 	- For i.MX7 SoCs should be "fsl,imx7d-src", "syscon"
 	- For i.MX8MQ SoCs should be "fsl,imx8mq-src", "syscon"
 	- For i.MX8MM SoCs should be "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon"
+	- For i.MX8MN SoCs should be "fsl,imx8mn-src", "fsl,imx8mq-src", "syscon"
+	- For i.MX8MP SoCs should be "fsl,imx8mp-src", "syscon"
 - reg: should be register base and length as documented in the
   datasheet
 - interrupts: Should contain SRC interrupt
@@ -49,4 +51,6 @@
 For list of all valid reset indices see
 <dt-bindings/reset/imx7-reset.h> for i.MX7,
 <dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ and
-<dt-bindings/reset/imx8mq-reset.h> for i.MX8MM
+<dt-bindings/reset/imx8mq-reset.h> for i.MX8MM and
+<dt-bindings/reset/imx8mq-reset.h> for i.MX8MN and
+<dt-bindings/reset/imx8mp-reset.h> for i.MX8MP
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/reset/nxp,dispmix-clk-en.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/reset/nxp,dispmix-clk-en.txt
@@ -0,0 +1,58 @@
+NXP Display Mix clk-en Reset Controller
+=======================================
+
+This binding describes a reset controller device that is used to enable
+or disable the internal clocks for all the submodules(such as, LCDIF,
+MIPI DSI, MIPI CSI, ISI and etc) included by the Display Mix subsystem
+on IMX8MM and IMX8MN platforms. Like sft-rstn, only assert and deassert
+functions are required for submodule internal clocks enable or disable,
+that means the clk-en can be treated as a real reset controller.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "fsl,imx8mm-dispmix-clk-en" or
+			"fsl,imx8mn-dispmix-clk-en".
+- reg: should be register base and length as documented in the datasheet.
+- clocks: phandle and clock specifier to disp apb clock for register access.
+- clock-names: should be "disp-apb".
+- power-domains: phandle to dispmix power domain.
+- reset-cells: 1, see below.
+
+example:
+
+	dispmix_clk_en: dispmix-clk-en@32e28004 {
+		compatible = "fsl,imx8mn-dispmix-clk-en";
+		reg = <0x0 0x32e28004 0x0 0x4>;
+		clocks = <&clk IMX8MN_CLK_DISP_APB_ROOT>;
+		clock-names = "disp-apb";
+		power-domains = <&dispmix_pd>;
+		#reset-cells = <1>;
+	};
+
+Specifying clk-en control of devices
+====================================
+
+Device nodes in Display Mix should specify the reset channel required in
+their "resets" property, containing a phandle to the clk-en device node
+and an index to specify which channel to use, as described in
+Documentation/devicetree/bindings/reset/reset.txt.
+
+example:
+
+	lcdif_resets: lcdif-resets {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#reset-cells = <0>;
+
+		lcdif-clk-enable {
+			compatible = "lcdif,clk-enable";
+			resets = <&dispmix_clk_en IMX8MN_LCDIF_APB_CLK_EN>,
+				 <&dispmix_clk_en IMX8MN_LCDIF_PIXEL_CLK_EN>;
+		};
+	};
+
+Macro definitions for the supported reset channels can be found in:
+include/dt-bindings/reset/imx8mm-dispmix.h and
+include/dt-bindings/reset/imx8mn-dispmix.h.
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/reset/nxp,dispmix-mipi-rst.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/reset/nxp,dispmix-mipi-rst.txt
@@ -0,0 +1,57 @@
+NXP Display Mix mipi-rst Reset Controller
+=========================================
+
+This binding describes a reset controller device that is used to reset
+or de-reset the MIPI DPHY master direction(for MIPI DSI) and slave
+direction(for MIPI CSI) included by the Display Mix subsystem on IMX8MM
+and IMX8MN platforms. Like sft-rstn, only assert and deassert functions
+are required for PHY reset or de-reset.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "fsl,imx8mm-dispmix-mipi-rst" or
+			"fsl,imx8mn-dispmix-mipi-rst".
+- reg: should be register base and length as documented in the datasheet.
+- clocks: phandle and clock specifier to disp apb clock for register access.
+- clock-names: should be "disp-apb".
+- power-domains: phandle to dispmix power domain.
+- reset-cells: 1, see below.
+
+example:
+
+	dispmix_mipi_rst: dispmix-mipi-rst@32e28008 {
+		compatible = "fsl,imx8mn-dispmix-mipi-rst";
+		reg = <0x0 0x32e28008 0x0 0x4>;
+		clocks = <&clk IMX8MN_CLK_DISP_APB_ROOT>;
+		clock-names = "disp-apb";
+		active_low;
+		power-domains = <&dispmix_pd>;
+		#reset-cells = <1>;
+	};
+
+Specifying mipi-rst control of devices
+======================================
+
+Device nodes in Display Mix should specify the reset channel required in
+their "resets" property, containing a phandle to the mipi-rst device node
+and an index to specify which channel to use, as described in
+Documentation/devicetree/bindings/reset/reset.txt.
+
+example:
+
+	mipi_dsi_resets: mipi-dsi-resets {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#reset-cells = <0>;
+
+		dsi-mipi-reset {
+			compatible = "dsi,mipi-reset";
+			resets = <&dispmix_mipi_rst IMX8MN_MIPI_M_RESET>;
+                };
+	};
+
+Macro definitions for the supported reset channels can be found in:
+include/dt-bindings/reset/imx8mm-dispmix.h and
+include/dt-bindings/reset/imx8mn-dispmix.h.
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/reset/nxp,dispmix-sft-rstn.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/reset/nxp,dispmix-sft-rstn.txt
@@ -0,0 +1,58 @@
+NXP Display Mix sft-rstn Reset Controller
+=========================================
+
+This binding describes a reset controller device that is used to reset
+or de-reset all the submodules(such as, LCDIF, MIPI DSI, MIPI CSI, ISI
+and etc) included by the Display Mix subsystem on IMX8MM and IMX8MN
+platforms. Only assert and deassert functions are required for submodule
+reset or de-reset.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "fsl,imx8mm-dispmix-sft-rstn" or
+			"fsl,imx8mn-dispmix-sft-rstn".
+- reg: should be register base and length as documented in the datasheet.
+- clocks: phandle and clock specifier to disp apb clock for register access.
+- clock-names: should be "disp-apb".
+- power-domains: phandle to dispmix power domain.
+- reset-cells: 1, see below.
+
+example:
+
+	dispmix_sft_rstn: dispmix-sft-rstn@32e28000 {
+		compatible = "fsl,imx8mm-dispmix-sft-rstn";
+		reg = <0x0 0x32e28000 0x0 0x4>;
+		clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		clock-names = "disp-apb";
+		active_low;
+		power-domains = <&dispmix_pd>;
+		#reset-cells = <1>;
+	};
+
+Specifying sft-rstn control of devices
+======================================
+
+Device nodes in Display Mix should specify the reset channel required in
+their "resets" property, containing a phandle to the sft-rstn device node
+and an index to specify which channel to use, as described in
+Documentation/devicetree/bindings/reset/reset.txt.
+
+example:
+
+        lcdif_resets: lcdif-resets {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                #reset-cells = <0>;
+
+                lcdif-soft-resetn {
+                        compatible = "lcdif,soft-resetn";
+                        resets = <&dispmix_sft_rstn IMX8MN_LCDIF_APB_CLK_RESET>,
+                                 <&dispmix_sft_rstn IMX8MN_LCDIF_PIXEL_CLK_RESET>;
+                };
+        };
+
+Macro definitions for the supported reset channels can be found in:
+include/dt-bindings/reset/imx8mm-dispmix.h and
+include/dt-bindings/reset/imx8mn-dispmix.h.
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/rng/omap3_rom_rng.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/rng/omap3_rom_rng.txt
@@ -0,0 +1,27 @@
+OMAP ROM RNG driver binding
+
+Secure SoCs may provide RNG via secure ROM calls like Nokia N900 does. The
+implementation can depend on the SoC secure ROM used.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "nokia,n900-rom-rng"
+
+- clocks:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: reference to the the RNG interface clock
+
+- clock-names:
+	Usage: required
+	Value type: <stringlist>
+	Definition: must be "ick"
+
+Example:
+
+	rom_rng: rng {
+		compatible = "nokia,n900-rom-rng";
+		clocks = <&rng_ick>;
+		clock-names = "ick";
+	};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -128,7 +128,6 @@
   - compatible
   - reg
   - interrupts
-  - clocks
   - clock-output-names
 
 additionalProperties: false
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/soc/fsl/fsl,rpmsg.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/soc/fsl/fsl,rpmsg.txt
@@ -0,0 +1,77 @@
+i.MX RPMSG platform implementations
+
+Distributed framework is used in IMX RPMSG implementation, refer to the
+following requirements:
+  - The CAN functions contained in M core and RTOS should be ready and
+    complete functional in 50ms after AMP system is turned on.
+  - Partition reset. System wouldn't be stalled by the exceptions (e.x
+    the reset triggered by the system hang) occurred at the other side.
+    And the RPMSG mechanism should be recovered automactilly after the
+    partition reset is completed.
+In this scenario, the M core and RTOS would be kicked off by bootloader
+firstly, then A core and Linux would be loaded later. Both M core/RTOS
+and A core/Linux are running independly.
+One physical memory region used to store the vring is mandatory required
+to pre-reserved and well-knowned by both A core and M core
+
+Required properties:
+- compatible: "fsl,imx8qxp-rpmsg", "fsl,imx8mq-rpmsg", "fsl,imx8mm-rpmsg",
+  "fsl,imx8qm-rpmsg", "fsl,imx7ulp-rpmsg", "fsl,imx7d-rpmsg",
+  "fsl,imx6sx-rpmsg".
+- vdev-nums: The number of the remote virtual devices.
+- reg: The reserved phisical DDR memory used to store vring descriptors.
+
+Optional properties:
+- rpmsg_dma_reserved: The reserved per device dma pool, that used to
+  allocate the shared memory buffers from the per device.
+  And it is optional for some platforms, since the system dma pool
+  is used to allocate the shared memory buffers directly on them.
+- mub-partition: The partition ID of muB side, that's optional
+  and used on i.mx8qm/8qxp for partition reset. The default
+  value is 3 in driver without this property.
+
+=====================================================================
+Mailbox used by iMX RPMSG
+
+- mboxes: mailboxes used in the RPMSG transactions.
+- mbox-names: names of the mailboxes used in RPMSG.
+	- "tx":TX channel with 32bit transmit register and IRQ transmit
+	- "rx":RX channel with 32bit receive register and IRQ support
+	- "rxdb":RX doorbell channel.
+
+Example:
+Rpmsg node in board dts file.
+&rpmsg{
+	/*
+	 * 64K for one rpmsg instance:
+	 */
+	vdev-nums = <2>;
+	reg = <0x0 0x90000000 0x0 0x20000>;
+	status = "okay";
+};
+
+SOC level dts node definitions:
+rpmsg_reserved: rpmsg@0x90000000 {
+	no-map;
+	reg = <0 0x90000000 0 0x400000>;
+};
+rpmsg_dma_reserved:rpmsg_dma@0x90400000 {
+	compatible = "shared-dma-pool";
+	no-map;
+	reg = <0 0x90400000 0 0x1C00000>;
+};
+rpmsg: rpmsg{
+	compatible = "fsl,imx8qxp-rpmsg";
+	/* up to now, the following channels are used in imx rpmsg
+	 * - tx1/rx1: messages channel.
+	 * - general interrupt1: remote proc finish re-init rpmsg stack
+	 *   when A core is partition reset.
+	 */
+	mbox-names = "tx", "rx", "rxdb";
+	mboxes = <&lsio_mu5 0 1
+		  &lsio_mu5 1 1
+		  &lsio_mu5 3 1>;
+	mub-partition = <3>;
+	memory-region = <&rpmsg_dma_reserved>;
+	status = "disabled";
+};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -6,7 +6,11 @@
 
 Required properties:
 
-  - compatible		: Compatible list, must contain "fsl,imx35-spdif".
+  - compatible		: Compatible list, should contain one of the following
+			  compatibles:
+			  "fsl,imx35-spdif",
+			  "fsl,vf610-spdif",
+			  "fsl,imx6sx-spdif",
 
   - reg			: Offset and length of the register set for the device.
 
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
@@ -34,6 +34,8 @@
 
  "fsl,imx-audio-wm8960"
 
+ "fsl,imx-audio-mqs"
+
 Required properties:
 
   - compatible		: Contains one of entries in the compatible list.
@@ -44,6 +46,11 @@
 
   - audio-codec		: The phandle of an audio codec
 
+Optional properties:
+
+  - audio-asrc		: The phandle of ASRC. It can be absent if there's no
+			  need to add ASRC support via DPCM.
+
   - audio-routing	: A list of the connections between audio components.
 			  Each entry is a pair of strings, the first being the
 			  connection's sink, the second being the connection's
@@ -60,11 +67,6 @@
 			        coexisting in order to support the old bindings
 				of wm8962 and sgtl5000.
 
-Optional properties:
-
-  - audio-asrc		: The phandle of ASRC. It can be absent if there's no
-			  need to add ASRC support via DPCM.
-
 Optional unless SSI is selected as a CPU DAI:
 
   - mux-int-port	: The internal port of the i.MX audio muxer (AUDMUX)
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/imx-audio-cdnhdmi.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/sound/imx-audio-cdnhdmi.txt
@@ -0,0 +1,16 @@
+Freescale i.MX audio complex with Cadence HDMI
+
+Required properties:
+- compatible : "fsl,imx-audio-cdnhdmi", "fsl,imx8mq-evk-cdnhdmi"
+- model : The user-visible name of this sound complex
+- audio-cpu : The phandle of the i.MX SAI controller
+- protocol : 0 is hdmi,  1 is dp.
+
+Example:
+
+sound-hdmi {
+	compatible = "fsl,imx-audio-cdnhdmi";
+	model = "imx-audio-hdmi";
+	audio-cpu = <&sai4>;
+	protocol = <0>;
+};
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt
@@ -2,9 +2,11 @@
 
 Required properties:
 - compatible : "mediatek,mt8183_mt6358_ts3a227_max98357"
-- mediatek,headset-codec: the phandles of ts3a227 codecs
 - mediatek,platform: the phandle of MT8183 ASoC platform
 
+Optional properties:
+- mediatek,headset-codec: the phandles of ts3a227 codecs
+
 Example:
 
 	sound {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
@@ -109,7 +109,7 @@
 	reg  = <1 0>;
 	interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>;
 	interrupt-names = "intr2"
-	reset-gpios = <&msmgpio 64 0>;
+	reset-gpios = <&msmgpio 64 GPIO_ACTIVE_LOW>;
 	slim-ifc-dev  = <&wc9335_ifd>;
 	clock-names = "mclk", "native";
 	clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/sound/wm8994.txt
+++ linux-ein-5.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:
 
@@ -73,11 +79,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-ein-5.4.0.orig/Documentation/devicetree/bindings/spi/spi-mxic.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/spi/spi-mxic.txt
@@ -8,11 +8,13 @@
 - reg: should contain 2 entries, one for the registers and one for the direct
        mapping area
 - reg-names: should contain "regs" and "dirmap"
-- interrupts: interrupt line connected to the SPI controller
 - clock-names: should contain "ps_clk", "send_clk" and "send_dly_clk"
 - clocks: should contain 3 entries for the "ps_clk", "send_clk" and
 	  "send_dly_clk" clocks
 
+Optional properties:
+- interrupts: interrupt line connected to the SPI controller
+
 Example:
 
 	spi@43c30000 {
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
@@ -2,6 +2,11 @@
 
 Required properties:
   - compatible : Should be "nxp,lx2160a-fspi"
+			    "nxp,imx8qxp-fspi"
+			    "nxp,imx8mm-fspi"
+			    "nxp,imx8mp-fspi"
+			    "nxp,imx8dxl-fspi"
+
   - reg :        First contains the register location and length,
                  Second contains the memory mapping address and length
   - reg-names :  Should contain the resource reg names:
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/usb/dwc3.txt
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -75,6 +75,8 @@
 			from P0 to P1/P2/P3 without delay.
  - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
 			during HS transmit.
+ - snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in
+			park mode are disabled.
  - snps,dis_metastability_quirk: when set, disable metastability workaround.
 			CAUTION: use only if you are absolutely sure of it.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
--- linux-ein-5.4.0.orig/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ linux-ein-5.4.0/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -381,6 +381,8 @@
     description: Gumstix, Inc.
   "^gw,.*":
     description: Gateworks Corporation
+                 use "gateworks" vendor prefix
+    deprecated: true
   "^hannstar,.*":
     description: HannStar Display Corporation
   "^haoyu,.*":
--- linux-ein-5.4.0.orig/Documentation/devicetree/writing-schema.rst
+++ linux-ein-5.4.0/Documentation/devicetree/writing-schema.rst
@@ -130,11 +130,13 @@
 
     make dt_binding_check
 
-In order to perform validation of DT source files, use the `dtbs_check` target::
+In order to perform validation of DT source files, use the ``dtbs_check`` target::
 
     make dtbs_check
 
-This will first run the `dt_binding_check` which generates the processed schema.
+Note that ``dtbs_check`` will skip any binding schema files with errors. It is
+necessary to use ``dt_binding_check`` to get all the validation errors in the
+binding schema files.
 
 It is also possible to run checks with a single schema file by setting the
 ``DT_SCHEMA_FILES`` variable to a specific schema file.
--- linux-ein-5.4.0.orig/Documentation/driver-api/dmaengine/dmatest.rst
+++ linux-ein-5.4.0/Documentation/driver-api/dmaengine/dmatest.rst
@@ -143,13 +143,14 @@
 Allocating Channels
 -------------------
 
-Channels are required to be configured prior to starting the test run.
-Attempting to run the test without configuring the channels will fail.
+Channels do not need to be configured prior to starting a test run. Attempting
+to run the test without configuring the channels will result in testing any
+channels that are available.
 
 Example::
 
     % echo 1 > /sys/module/dmatest/parameters/run
-    dmatest: Could not start test, no channels configured
+    dmatest: No channels configured, continue with any
 
 Channels are registered using the "channel" parameter. Channels can be requested by their
 name, once requested, the channel is registered and a pending thread is added to the test list.
--- linux-ein-5.4.0.orig/Documentation/driver-api/firewire.rst
+++ linux-ein-5.4.0/Documentation/driver-api/firewire.rst
@@ -19,7 +19,7 @@
 Firewire char device data structures
 ====================================
 
-.. include:: /ABI/stable/firewire-cdev
+.. include:: ../ABI/stable/firewire-cdev
     :literal:
 
 .. kernel-doc:: include/uapi/linux/firewire-cdev.h
@@ -28,7 +28,7 @@
 Firewire device probing and sysfs interfaces
 ============================================
 
-.. include:: /ABI/stable/sysfs-bus-firewire
+.. include:: ../ABI/stable/sysfs-bus-firewire
     :literal:
 
 .. kernel-doc:: drivers/firewire/core-device.c
--- linux-ein-5.4.0.orig/Documentation/driver-api/libata.rst
+++ linux-ein-5.4.0/Documentation/driver-api/libata.rst
@@ -250,7 +250,7 @@
 
 ::
 
-    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);
 
 
--- linux-ein-5.4.0.orig/Documentation/driver-api/spi.rst
+++ linux-ein-5.4.0/Documentation/driver-api/spi.rst
@@ -25,8 +25,8 @@
 a pair of FIFOs connected to dual DMA engines on the other side of the
 SPI shift register (maximizing throughput). Such drivers bridge between
 whatever bus they sit on (often the platform bus) and SPI, and expose
-the SPI side of their device as a :c:type:`struct spi_master
-<spi_master>`. SPI devices are children of that master,
+the SPI side of their device as a :c:type:`struct spi_controller
+<spi_controller>`. SPI devices are children of that master,
 represented as a :c:type:`struct spi_device <spi_device>` and
 manufactured from :c:type:`struct spi_board_info
 <spi_board_info>` descriptors which are usually provided by
--- linux-ein-5.4.0.orig/Documentation/fault-injection/fault-injection.rst
+++ linux-ein-5.4.0/Documentation/fault-injection/fault-injection.rst
@@ -74,8 +74,8 @@
 
 - /sys/kernel/debug/fail*/times:
 
-	specifies how many times failures may happen at most.
-	A value of -1 means "no limit".
+	specifies how many times failures may happen at most. A value of -1
+	means "no limit".
 
 - /sys/kernel/debug/fail*/space:
 
@@ -163,11 +163,13 @@
 	- ERRNO: retval must be -1 to -MAX_ERRNO (-4096).
 	- ERR_NULL: retval must be 0 or -1 to -MAX_ERRNO (-4096).
 
-- /sys/kernel/debug/fail_function/<functiuon-name>/retval:
+- /sys/kernel/debug/fail_function/<function-name>/retval:
 
-	specifies the "error" return value to inject to the given
-	function for given function. This will be created when
-	user specifies new injection entry.
+	specifies the "error" return value to inject to the given function.
+	This will be created when the user specifies a new injection entry.
+	Note that this file only accepts unsigned values. So, if you want to
+	use a negative errno, you better use 'printf' instead of 'echo', e.g.:
+	$ printf %#x -12 > retval
 
 Boot option
 ^^^^^^^^^^^
@@ -331,7 +333,7 @@
     FAILTYPE=fail_function
     FAILFUNC=open_ctree
     echo $FAILFUNC > /sys/kernel/debug/$FAILTYPE/inject
-    echo -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval
+    printf %#x -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval
     echo N > /sys/kernel/debug/$FAILTYPE/task-filter
     echo 100 > /sys/kernel/debug/$FAILTYPE/probability
     echo 0 > /sys/kernel/debug/$FAILTYPE/interval
--- linux-ein-5.4.0.orig/Documentation/fb/fbcon.rst
+++ linux-ein-5.4.0/Documentation/fb/fbcon.rst
@@ -127,7 +127,7 @@
 	is typically located on the same video card.  Thus, the consoles that
 	are controlled by the VGA console will be garbled.
 
-4. fbcon=rotate:<n>
+5. fbcon=rotate:<n>
 
 	This option changes the orientation angle of the console display. The
 	value 'n' accepts the following:
@@ -152,21 +152,21 @@
 	Actually, the underlying fb driver is totally ignorant of console
 	rotation.
 
-5. fbcon=margin:<color>
+6. fbcon=margin:<color>
 
 	This option specifies the color of the margins. The margins are the
 	leftover area at the right and the bottom of the screen that are not
 	used by text. By default, this area will be black. The 'color' value
 	is an integer number that depends on the framebuffer driver being used.
 
-6. fbcon=nodefer
+7. fbcon=nodefer
 
 	If the kernel is compiled with deferred fbcon takeover support, normally
 	the framebuffer contents, left in place by the firmware/bootloader, will
 	be preserved until there actually is some text is output to the console.
 	This option causes fbcon to bind immediately to the fbdev device.
 
-7. fbcon=logo-pos:<location>
+8. fbcon=logo-pos:<location>
 
 	The only possible 'location' is 'center' (without quotes), and when
 	given, the bootup logo is moved from the default top-left corner
--- linux-ein-5.4.0.orig/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
+++ linux-ein-5.4.0/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
@@ -24,7 +24,7 @@
     |      parisc: |  ok  |
     |     powerpc: |  ok  |
     |       riscv: | TODO |
-    |        s390: | TODO |
+    |        s390: |  ok  |
     |          sh: | TODO |
     |       sparc: | TODO |
     |          um: | TODO |
--- linux-ein-5.4.0.orig/Documentation/filesystems/affs.txt
+++ linux-ein-5.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-ein-5.4.0.orig/Documentation/filesystems/aufs/README
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/README
@@ -0,0 +1,401 @@
+
+Aufs5 -- advanced multi layered unification filesystem version 5.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 became totally different from
+Unionfs while keeping the basic features.
+Later, Unionfs Version 2.x series began taking some of the same
+approaches to aufs1's.
+Unionfs was being developed by Professor Erez Zadok at Stony Brook
+University and his team.
+
+Aufs5 supports linux-v5.0 and later, If you want older kernel version
+support,
+- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git
+- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git
+- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git
+  or 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 aufs5.
+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 aufs5, aufs5-linux.git,
+aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in
+"aufs-util.git."
+While the aufs-util is always necessary, you need either of aufs5-linux
+or aufs5-standalone.
+
+The aufs5-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 aufs5 as an external kernel module.
+Several extra patches are not included in this tree. Only
+aufs5-standalone tree contains them. They are described in the later
+section "Configuration and Compilation."
+
+On the other hand, the aufs5-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 "aufs5.x" where "x"
+represents the linux kernel version, "linux-5.x". For instance,
+"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use
+"aufs5.x-rcN" branch.
+
+o aufs5-linux tree
+$ git clone --reference /your/linux/git/tree \
+	git://github.com/sfjro/aufs5-linux.git aufs5-linux.git
+- if you don't have linux GIT tree, then remove "--reference ..."
+$ cd aufs5-linux.git
+$ git checkout origin/aufs5.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 aufs5 git://github.com/sfjro/aufs5-linux.git
+$ git fetch aufs5
+$ git checkout -b my5.0 v5.0
+$ (add your local change...)
+$ git pull aufs5 aufs5.0
+- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch.
+- you may need to solve some conflicts between your_changes and
+  aufs5.0. in this case, git-rerere is recommended so that you can
+  solve the similar conflicts automatically when you upgrade to 5.1 or
+  later in the future.
+
+o aufs5-standalone tree
+$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git
+$ cd aufs5-standalone.git
+$ git checkout origin/aufs5.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/aufs5.0
+
+Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY.
+The minor version number, 'x' in '5.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-5.10" and the "aufs5.10" branch
+does not exist in aufs-util repository, then "aufs5.9", "aufs5.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 aufs5-linux tree,
+- enable CONFIG_AUFS_FS.
+- set other aufs configurations if necessary.
+
+For aufs5-standalone tree,
+There are several ways to build.
+
+1.
+- apply ./aufs5-kbuild.patch to your kernel source files.
+- apply ./aufs5-base.patch too.
+- apply ./aufs5-mmap.patch too.
+- apply ./aufs5-standalone.patch too, if you have a plan to set
+  CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-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.
+- 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 ./aufs5-base.patch to your kernel source files.
+- apply ./aufs5-mmap.patch too.
+- apply ./aufs5-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".
+- 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 aufs5-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 aufs5-standalone.git. They are all
+optional. When you meet some problems, they will help you.
+- aufs5-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".
+- proc_mounts.patch
+  When there are many mountpoints and many mount(2)/umount(2) are
+  running, then /proc/mounts may not show the all mountpoints.  This
+  patch makes /proc/mounts always show the full mountpoints list.
+  If you don't want to apply this patch and meet such problem, then you
+  need to increase the value of 'ProcMounts_Times' make-variable in
+  aufs-util.git as a second best solution.
+- 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 you don't know what LOCKDEP is, 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)
+- LSM (linux security module, if you are using)
+- 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).
+OmegaPhil made a donation (2016/1, 2018/4).
+Tomasz Szewczyk made a donation (2016/4).
+James Burry made a donation (2016/12).
+Carsten Rose made a donation (2018/9).
+Porteus Kiosk made a donation (2018/10).
+
+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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/01intro.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/01intro.txt
@@ -0,0 +1,171 @@
+
+# Copyright (C) 2005-2020 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] | /ey-yoo-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.
+4. abbrev. for "African Urban Fashion Show".
+
+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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/02struct.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/02struct.txt
@@ -0,0 +1,258 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/03atomic_open.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/03atomic_open.txt
@@ -0,0 +1,85 @@
+
+# Copyright (C) 2015-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/03lookup.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/03lookup.txt
@@ -0,0 +1,113 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/04branch.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/04branch.txt
@@ -0,0 +1,74 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/05wbr_policy.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/05wbr_policy.txt
@@ -0,0 +1,64 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/06dirren.dot
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/06dirren.dot
@@ -0,0 +1,31 @@
+
+// to view this graph, run dot(1) command in GRAPHVIZ.
+
+digraph G {
+node [shape=box];
+whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"];
+
+node [shape=oval];
+
+aufs_rename -> whinfo [label="store/remove"];
+
+node [shape=oval];
+inode_list [label="h_inum list in branch\ncache"];
+
+node [shape=box];
+whinode [label="h_inum list file"];
+
+node [shape=oval];
+brmgmt [label="br_add/del/mod/umount"];
+
+brmgmt -> inode_list [label="create/remove"];
+brmgmt -> whinode [label="load/store"];
+
+inode_list -> whinode [style=dashed,dir=both];
+
+aufs_rename -> inode_list [label="add/del"];
+
+aufs_lookup -> inode_list [label="search"];
+
+aufs_lookup -> whinfo [label="load/remove"];
+}
--- linux-ein-5.4.0.orig/Documentation/filesystems/aufs/design/06dirren.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/06dirren.txt
@@ -0,0 +1,102 @@
+
+# Copyright (C) 2017-2020 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/>.
+
+Special handling for renaming a directory (DIRREN)
+----------------------------------------------------------------------
+First, let's assume we have a simple usecase.
+
+- /u = /rw + /ro
+- /rw/dirA exists
+- /ro/dirA and /ro/dirA/file exist too
+- there is no dirB on both branches
+- a user issues rename("dirA", "dirB")
+
+Now, what should aufs behave against this rename(2)?
+There are a few possible cases.
+
+A. returns EROFS.
+   since dirA exists on a readonly branch which cannot be renamed.
+B. returns EXDEV.
+   it is possible to copy-up dirA (only the dir itself), but the child
+   entries ("file" in this case) should not be. it must be a bad
+   approach to copy-up recursively.
+C. returns a success.
+   even the branch /ro is readonly, aufs tries renaming it. Obviously it
+   is a violation of aufs' policy.
+D. construct an extra information which indicates that /ro/dirA should
+   be handled as the name of dirB.
+   overlayfs has a similar feature called REDIRECT.
+
+Until now, aufs implements the case B only which returns EXDEV, and
+expects the userspace application behaves like mv(1) which tries
+issueing rename(2) recursively.
+
+A new aufs feature called DIRREN is introduced which implements the case
+D. There are several "extra information" added.
+
+1. detailed info per renamed directory
+   path: /rw/dirB/$AUFS_WH_DR_INFO_PFX.<lower branch-id>
+2. the inode-number list of directories on a branch
+   path: /rw/dirB/$AUFS_WH_DR_BRHINO
+
+The filename of "detailed info per directory" represents the lower
+branch, and its format is
+- a type of the branch id
+  one of these.
+  + uuid (not implemented yet)
+  + fsid
+  + dev
+- the inode-number of the branch root dir
+
+And it contains these info in a single regular file.
+- magic number
+- branch's inode-number of the logically renamed dir
+- the name of the before-renamed dir
+
+The "detailed info per directory" file is created in aufs rename(2), and
+loaded in any lookup.
+The info is considered in lookup for the matching case only. Here
+"matching" means that the root of branch (in the info filename) is same
+to the current looking-up branch. After looking-up the before-renamed
+name, the inode-number is compared. And the matched dentry is used.
+
+The "inode-number list of directories" is a regular file which contains
+simply the inode-numbers on the branch. The file is created or updated
+in removing the branch, and loaded in adding the branch. Its lifetime is
+equal to the branch.
+The list is refered in lookup, and when the current target inode is
+found in the list, the aufs tries loading the "detailed info per
+directory" and get the changed and valid name of the dir.
+
+Theoretically these "extra informaiton" may be able to be put into XATTR
+in the dir inode. But aufs doesn't choose this way because
+1. XATTR may not be supported by the branch (or its configuration)
+2. XATTR may have its size limit.
+3. XATTR may be less easy to convert than a regular file, when the
+   format of the info is changed in the future.
+At the same time, I agree that the regular file approach is much slower
+than XATTR approach. So, in the future, aufs may take the XATTR or other
+better approach.
+
+This DIRREN feature is enabled by aufs configuration, and is activated
+by a new mount option.
+
+For the more complicated case, there is a work with UDBA option, which
+is to dected the direct access to the branches (by-passing aufs) and to
+maintain the cashes in aufs. Since a single cached aufs dentry may
+contains two names, before- and after-rename, the name comparision in
+UDBA handler may not work correctly. In this case, the behaviour will be
+equivalen to udba=reval case.
--- linux-ein-5.4.0.orig/Documentation/filesystems/aufs/design/06fhsm.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/06fhsm.txt
@@ -0,0 +1,120 @@
+
+# Copyright (C) 2011-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/06mmap.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/06mmap.txt
@@ -0,0 +1,72 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/06xattr.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/06xattr.txt
@@ -0,0 +1,96 @@
+
+# Copyright (C) 2014-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/07export.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/07export.txt
@@ -0,0 +1,58 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/08shwh.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/08shwh.txt
@@ -0,0 +1,52 @@
+
+# Copyright (C) 2005-2020 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-ein-5.4.0.orig/Documentation/filesystems/aufs/design/10dynop.txt
+++ linux-ein-5.4.0/Documentation/filesystems/aufs/design/10dynop.txt
@@ -0,0 +1,47 @@
+
+# Copyright (C) 2010-2020 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-ein-5.4.0.orig/Documentation/filesystems/directory-locking.rst
+++ linux-ein-5.4.0/Documentation/filesystems/directory-locking.rst
@@ -23,13 +23,15 @@
 locks victim and calls the method.  Locks are exclusive.
 
 4) rename() that is _not_ cross-directory.  Locking rules: caller locks
-the parent and finds source and target.  In case of exchange (with
-RENAME_EXCHANGE in flags argument) lock both.  In any case,
-if the target already exists, lock it.  If the source is a non-directory,
-lock it.  If we need to lock both, lock them in inode pointer order.
-Then call the method.  All locks are exclusive.
-NB: we might get away with locking the the source (and target in exchange
-case) shared.
+the parent and finds source and target.  Then we decide which of the
+source and target need to be locked.  Source needs to be locked if it's a
+non-directory; target - if it's a non-directory or about to be removed.
+Take the locks that need to be taken, in inode pointer order if need
+to take both (that can happen only when both source and target are
+non-directories - the source because it wouldn't be locked otherwise
+and the target because mixing directory and non-directory is allowed
+only with RENAME_EXCHANGE, and that won't be removing the target).
+After the locks had been taken, call the method.  All locks are exclusive.
 
 5) link creation.  Locking rules:
 
@@ -44,19 +46,22 @@
 rules:
 
 	* lock the filesystem
-	* lock parents in "ancestors first" order.
+	* lock parents in "ancestors first" order. If one is not ancestor of
+	  the other, lock the parent of source first.
 	* find source and target.
 	* if old parent is equal to or is a descendent of target
 	  fail with -ENOTEMPTY
 	* if new parent is equal to or is a descendent of source
 	  fail with -ELOOP
-	* If it's an exchange, lock both the source and the target.
-	* If the target exists, lock it.  If the source is a non-directory,
-	  lock it.  If we need to lock both, do so in inode pointer order.
+	* Lock both the source and the target provided they exist. If we
+	  need to lock two inodes of different type (dir vs non-dir), we lock
+	  the directory first. If we need to lock two inodes of the same type,
+	  lock them in inode pointer order.
+	* Lock subdirectories involved (source before target).
+	* Lock non-directories involved, in inode pointer order.
 	* call the method.
 
-All ->i_rwsem are taken exclusive.  Again, we might get away with locking
-the the source (and target in exchange case) shared.
+All ->i_rwsem are taken exclusive.
 
 The rules above obviously guarantee that all directories that are going to be
 read, modified or removed by method will be locked by caller.
@@ -66,8 +71,10 @@
 
 Proof:
 
-	First of all, at any moment we have a partial ordering of the
-	objects - A < B iff A is an ancestor of B.
+[XXX: will be updated once we are done massaging the lock_rename()]
+	First of all, at any moment we have a linear ordering of the
+	objects - A < B iff (A is an ancestor of B) or (B is not an ancestor
+        of A and ptr(A) < ptr(B)).
 
 	That ordering can change.  However, the following is true:
 
--- linux-ein-5.4.0.orig/Documentation/filesystems/ext4/attributes.rst
+++ linux-ein-5.4.0/Documentation/filesystems/ext4/attributes.rst
@@ -76,7 +76,7 @@
      - Checksum of the extended attribute block.
    * - 0x14
      - \_\_u32
-     - h\_reserved[2]
+     - h\_reserved[3]
      - Zero.
 
 The checksum is calculated against the FS UUID, the 64-bit block number
--- linux-ein-5.4.0.orig/Documentation/filesystems/locking.rst
+++ linux-ein-5.4.0/Documentation/filesystems/locking.rst
@@ -95,7 +95,7 @@
 mkdir:		exclusive
 unlink:		exclusive (both)
 rmdir:		exclusive (both)(see below)
-rename:		exclusive (all)	(see below)
+rename:		exclusive (both parents, some children)	(see below)
 readlink:	no
 get_link:	no
 setattr:	exclusive
@@ -113,6 +113,9 @@
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem
 	exclusive on victim.
 	cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
+	->unlink() and ->rename() have ->i_rwsem exclusive on all non-directories
+	involved.
+	->rename() has ->i_rwsem exclusive on any subdirectory that changes parent.
 
 See Documentation/filesystems/directory-locking.rst for more detailed discussion
 of the locking scheme for directory operations.
--- linux-ein-5.4.0.orig/Documentation/filesystems/porting.rst
+++ linux-ein-5.4.0/Documentation/filesystems/porting.rst
@@ -850,3 +850,29 @@
 d_alloc_pseudo() is internal-only; uses outside of alloc_file_pseudo() are
 very suspect (and won't work in modules).  Such uses are very likely to
 be misspelled d_alloc_anon().
+
+---
+
+**mandatory**
+
+[should've been added in 2016] stale comment in finish_open() nonwithstanding,
+failure exits in ->atomic_open() instances should *NOT* fput() the file,
+no matter what.  Everything is handled by the caller.
+
+---
+
+**mandatory**
+
+If ->rename() update of .. on cross-directory move needs an exclusion with
+directory modifications, do *not* lock the subdirectory in question in your
+->rename() - it's done by the caller now [that item should've been added in
+28eceeda130f "fs: Lock moved directories"].
+
+---
+
+**mandatory**
+
+On same-directory ->rename() the (tautological) update of .. is not protected
+by any locks; just don't do it if the old parent is the same as the new one.
+We really can't lock two subdirectories in same-directory rename - not without
+deadlocks.
--- linux-ein-5.4.0.orig/Documentation/filesystems/seq_file.txt
+++ linux-ein-5.4.0/Documentation/filesystems/seq_file.txt
@@ -192,6 +192,12 @@
 is a reasonable thing to do. The seq_file code will also avoid taking any
 other locks while the iterator is active.
 
+The iterater value returned by start() or next() is guaranteed to be
+passed to a subsequent next() or stop() call.  This allows resources
+such as locks that were taken to be reliably released.  There is *no*
+guarantee that the iterator will be passed to show(), though in practice
+it often will be.
+
 
 Formatted output
 
--- linux-ein-5.4.0.orig/Documentation/filesystems/sysfs.txt
+++ linux-ein-5.4.0/Documentation/filesystems/sysfs.txt
@@ -232,12 +232,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-ein-5.4.0.orig/Documentation/filesystems/vfs.rst
+++ linux-ein-5.4.0/Documentation/filesystems/vfs.rst
@@ -1173,7 +1173,7 @@
 	return
 	-ECHILD and it will be called again in ref-walk mode.
 
-``_weak_revalidate``
+``d_weak_revalidate``
 	called when the VFS needs to revalidate a "jumped" dentry.  This
 	is called when a path-walk ends at dentry that was not acquired
 	by doing a lookup in the parent directory.  This includes "/",
--- linux-ein-5.4.0.orig/Documentation/firmware-guide/acpi/apei/einj.rst
+++ linux-ein-5.4.0/Documentation/firmware-guide/acpi/apei/einj.rst
@@ -168,7 +168,7 @@
   0x00000008	Memory Correctable
   0x00000010	Memory Uncorrectable non-fatal
   # echo 0x12345000 > param1		# Set memory address for injection
-  # echo $((-1 << 12)) > param2		# Mask 0xfffffffffffff000 - anywhere in this page
+  # echo 0xfffffffffffff000 > param2		# Mask - anywhere in this page
   # echo 0x8 > error_type			# Choose correctable memory error
   # echo 1 > error_inject			# Inject now
 
--- linux-ein-5.4.0.orig/Documentation/firmware-guide/acpi/dsd/data-node-references.rst
+++ linux-ein-5.4.0/Documentation/firmware-guide/acpi/dsd/data-node-references.rst
@@ -5,7 +5,7 @@
 Referencing hierarchical data nodes
 ===================================
 
-:Copyright: |copy| 2018 Intel Corporation
+:Copyright: |copy| 2018, 2021 Intel Corporation
 :Author: Sakari Ailus <sakari.ailus@linux.intel.com>
 
 ACPI in general allows referring to device objects in the tree only.
@@ -52,12 +52,14 @@
 	    Name (NOD0, Package() {
 		ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
 		Package () {
+		    Package () { "reg", 0 },
 		    Package () { "random-property", 3 },
 		}
 	    })
 	    Name (NOD1, Package() {
 		ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
 		Package () {
+		    Package () { "reg", 1 },
 		    Package () { "anothernode", "ANOD" },
 		}
 	    })
@@ -74,7 +76,11 @@
 	    Name (_DSD, Package () {
 		ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
 		Package () {
-		    Package () { "reference", ^DEV0, "node@1", "anothernode" },
+		    Package () {
+			"reference", Package () {
+			    ^DEV0, "node@1", "anothernode"
+			}
+		    },
 		}
 	    })
 	}
--- linux-ein-5.4.0.orig/Documentation/hwmon/gsc-hwmon.rst
+++ linux-ein-5.4.0/Documentation/hwmon/gsc-hwmon.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver gsc-hwmon
+=======================
+
+Supported chips: Gateworks GSC
+Datasheet: http://trac.gateworks.com/wiki/gsc
+Author: Tim Harvey <tharvey@gateworks.com>
+
+Description:
+------------
+
+This driver supports hardware monitoring for the temperature sensor,
+various ADC's connected to the GSC, and optional FAN controller available
+on some boards.
+
+
+Voltage Monitoring
+------------------
+
+The voltage inputs are scaled either internally or by the driver depending
+on the GSC version and firmware. The values returned by the driver do not need
+further scaling. The voltage input labels provide the voltage rail name:
+
+inX_input                  Measured voltage (mV).
+inX_label                  Name of voltage rail.
+
+
+Temperature Monitoring
+----------------------
+
+Temperatures are measured with 12-bit or 10-bit resolution and are scaled
+either internally or by the driver depending on the GSC version and firmware.
+The values returned by the driver reflect millidegree Celcius:
+
+tempX_input                Measured temperature.
+tempX_label                Name of temperature input.
+
+
+PWM Output Control
+------------------
+
+The GSC features 1 PWM output that operates in automatic mode where the
+PWM value will be scalled depending on 6 temperature boundaries.
+The tempeature boundaries are read-write and in millidegree Celcius and the
+read-only PWM values range from 0 (off) to 255 (full speed).
+Fan speed will be set to minimum (off) when the temperature sensor reads
+less than pwm1_auto_point1_temp and maximum when the temperature sensor
+equals or exceeds pwm1_auto_point6_temp.
+
+pwm1_auto_point[1-6]_pwm       PWM value.
+pwm1_auto_point[1-6]_temp      Temperature boundary.
+
--- linux-ein-5.4.0.orig/Documentation/hwmon/index.rst
+++ linux-ein-5.4.0/Documentation/hwmon/index.rst
@@ -56,6 +56,7 @@
    ftsteutates
    g760a
    g762
+   gsc-hwmon
    gl518sm
    hih6130
    ibmaem
--- linux-ein-5.4.0.orig/Documentation/hwmon/lm90.rst
+++ linux-ein-5.4.0/Documentation/hwmon/lm90.rst
@@ -123,6 +123,18 @@
 
 	       http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
 
+  * Maxim MAX6654
+
+    Prefix: 'max6654'
+
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+
+			   0x4c, 0x4d and 0x4e
+
+    Datasheet: Publicly available at the Maxim website
+
+	       https://www.maximintegrated.com/en/products/sensors/MAX6654.html
+
   * Maxim MAX6657
 
     Prefix: 'max6657'
@@ -253,6 +265,16 @@
 
 	       http://www.ti.com/litv/pdf/sbos686
 
+  * Texas Instruments TMP461
+
+    Prefix: 'tmp461'
+
+    Addresses scanned: I2C 0x48 through 0x4F
+
+    Datasheet: Publicly available at TI website
+
+	       https://www.ti.com/lit/gpn/tmp461
+
 Author: Jean Delvare <jdelvare@suse.de>
 
 
@@ -301,6 +323,13 @@
   * Extended temperature range (breaks compatibility)
   * Lower resolution for remote temperature
 
+MAX6654:
+  * Better local resolution
+  * Selectable address
+  * Remote sensor type selection
+  * Extended temperature range
+  * Extended resolution only available when conversion rate <= 1 Hz
+
 MAX6657 and MAX6658:
   * Better local resolution
   * Remote sensor type selection
@@ -336,8 +365,8 @@
 
 All temperature values are given in degrees Celsius. Resolution
 is 1.0 degree for the local temperature, 0.125 degree for the remote
-temperature, except for the MAX6657, MAX6658 and MAX6659 which have a
-resolution of 0.125 degree for both temperatures.
+temperature, except for the MAX6654, MAX6657, MAX6658 and MAX6659 which have
+a resolution of 0.125 degree for both temperatures.
 
 Each sensor has its own high and low limits, plus a critical limit.
 Additionally, there is a relative hysteresis value common to both critical
--- linux-ein-5.4.0.orig/Documentation/hwmon/max31790.rst
+++ linux-ein-5.4.0/Documentation/hwmon/max31790.rst
@@ -38,6 +38,7 @@
 fan[1-12]_input    RO  fan tachometer speed in RPM
 fan[1-12]_fault    RO  fan experienced fault
 fan[1-6]_target    RW  desired fan speed in RPM
-pwm[1-6]_enable    RW  regulator mode, 0=disabled, 1=manual mode, 2=rpm mode
-pwm[1-6]           RW  fan target duty cycle (0-255)
+pwm[1-6]_enable    RW  regulator mode, 0=disabled (duty cycle=0%), 1=manual mode, 2=rpm mode
+pwm[1-6]           RW  read: current pwm duty cycle,
+                       write: target pwm duty cycle (0-255)
 ================== === =======================================================
--- linux-ein-5.4.0.orig/Documentation/index.rst
+++ linux-ein-5.4.0/Documentation/index.rst
@@ -135,6 +135,14 @@
    mic/index
    scheduler/index
 
+Architecture-agnostic documentation
+-----------------------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   asm-annotations
+
 Architecture-specific documentation
 -----------------------------------
 
--- linux-ein-5.4.0.orig/Documentation/input/joydev/joystick.rst
+++ linux-ein-5.4.0/Documentation/input/joydev/joystick.rst
@@ -517,6 +517,7 @@
 * AVB Mag Turbo Force
 * AVB Top Shot Pegasus
 * AVB Top Shot Force Feedback Racing Wheel
+* Boeder Force Feedback Wheel
 * Logitech WingMan Force
 * Logitech WingMan Force Wheel
 * Guillemot Race Leader Force Feedback
--- linux-ein-5.4.0.orig/Documentation/ioctl/ioctl-number.rst
+++ linux-ein-5.4.0/Documentation/ioctl/ioctl-number.rst
@@ -158,7 +158,8 @@
 'I'   00-0F  drivers/isdn/divert/isdn_divert.h                       conflict!
 'I'   40-4F  linux/mISDNif.h                                         conflict!
 'J'   00-1F  drivers/scsi/gdth_ioctl.h
-'K'   all    linux/kd.h
+'K'   all    linux/kd.h                                              conflict!
+'K'   00-01  linux/caam_keygen.h                                     conflict! caam driver
 'L'   00-1F  linux/loop.h                                            conflict!
 'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                      conflict!
 'L'   20-2F  linux/lightnvm.h
@@ -301,7 +302,6 @@
 0x89  00-06  arch/x86/include/asm/sockios.h
 0x89  0B-DF  linux/sockios.h
 0x89  E0-EF  linux/sockios.h                                         SIOCPROTOPRIVATE range
-0x89  E0-EF  linux/dn.h                                              PROTOPRIVATE range
 0x89  F0-FF  linux/sockios.h                                         SIOCDEVPRIVATE range
 0x8B  all    linux/wireless.h
 0x8C  00-3F                                                          WiNRADiO driver
--- linux-ein-5.4.0.orig/Documentation/kbuild/index.rst
+++ linux-ein-5.4.0/Documentation/kbuild/index.rst
@@ -19,6 +19,7 @@
 
     issues
     reproducible-builds
+    llvm
 
 .. only::  subproject and html
 
--- linux-ein-5.4.0.orig/Documentation/kbuild/kbuild.rst
+++ linux-ein-5.4.0/Documentation/kbuild/kbuild.rst
@@ -262,3 +262,8 @@
 These two variables allow to override the user@host string displayed during
 boot and in /proc/version. The default value is the output of the commands
 whoami and host, respectively.
+
+LLVM
+----
+If this variable is set to 1, Kbuild will use Clang and LLVM utilities instead
+of GCC and GNU binutils to build the kernel.
--- linux-ein-5.4.0.orig/Documentation/kbuild/llvm.rst
+++ linux-ein-5.4.0/Documentation/kbuild/llvm.rst
@@ -0,0 +1,87 @@
+==============================
+Building Linux with Clang/LLVM
+==============================
+
+This document covers how to build the Linux kernel with Clang and LLVM
+utilities.
+
+About
+-----
+
+The Linux kernel has always traditionally been compiled with GNU toolchains
+such as GCC and binutils. Ongoing work has allowed for `Clang
+<https://clang.llvm.org/>`_ and `LLVM <https://llvm.org/>`_ utilities to be
+used as viable substitutes. Distributions such as `Android
+<https://www.android.com/>`_, `ChromeOS
+<https://www.chromium.org/chromium-os>`_, and `OpenMandriva
+<https://www.openmandriva.org/>`_ use Clang built kernels.  `LLVM is a
+collection of toolchain components implemented in terms of C++ objects
+<https://www.aosabook.org/en/llvm.html>`_. Clang is a front-end to LLVM that
+supports C and the GNU C extensions required by the kernel, and is pronounced
+"klang," not "see-lang."
+
+Clang
+-----
+
+The compiler used can be swapped out via `CC=` command line argument to `make`.
+`CC=` should be set when selecting a config and during a build.
+
+	make CC=clang defconfig
+
+	make CC=clang
+
+Cross Compiling
+---------------
+
+A single Clang compiler binary will typically contain all supported backends,
+which can help simplify cross compiling.
+
+	ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CC=clang
+
+`CROSS_COMPILE` is not used to prefix the Clang compiler binary, instead
+`CROSS_COMPILE` is used to set a command line flag: `--target <triple>`. For
+example:
+
+	clang --target aarch64-linux-gnu foo.c
+
+LLVM Utilities
+--------------
+
+LLVM has substitutes for GNU binutils utilities. Kbuild supports `LLVM=1`
+to enable them.
+
+	make LLVM=1
+
+They can be enabled individually. The full list of the parameters:
+
+	make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \\
+	  OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump OBJSIZE=llvm-size \\
+	  READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar \\
+	  HOSTLD=ld.lld
+
+Currently, the integrated assembler is disabled by default. You can pass
+`LLVM_IAS=1` to enable it.
+
+Getting Help
+------------
+
+- `Website <https://clangbuiltlinux.github.io/>`_
+- `Mailing List <https://groups.google.com/forum/#!forum/clang-built-linux>`_: <clang-built-linux@googlegroups.com>
+- `Issue Tracker <https://github.com/ClangBuiltLinux/linux/issues>`_
+- IRC: #clangbuiltlinux on chat.freenode.net
+- `Telegram <https://t.me/ClangBuiltLinux>`_: @ClangBuiltLinux
+- `Wiki <https://github.com/ClangBuiltLinux/linux/wiki>`_
+- `Beginner Bugs <https://github.com/ClangBuiltLinux/linux/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`_
+
+Getting LLVM
+-------------
+
+- http://releases.llvm.org/download.html
+- https://github.com/llvm/llvm-project
+- https://llvm.org/docs/GettingStarted.html
+- https://llvm.org/docs/CMake.html
+- https://apt.llvm.org/
+- https://www.archlinux.org/packages/extra/x86_64/llvm/
+- https://github.com/ClangBuiltLinux/tc-build
+- https://github.com/ClangBuiltLinux/linux/wiki/Building-Clang-from-source
+- https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/
--- linux-ein-5.4.0.orig/Documentation/kbuild/makefiles.rst
+++ linux-ein-5.4.0/Documentation/kbuild/makefiles.rst
@@ -1115,23 +1115,6 @@
 	In this example, extra-y is used to list object files that
 	shall be built, but shall not be linked as part of built-in.a.
 
-    header-test-y
-
-	header-test-y specifies headers (`*.h`) in the current directory that
-	should be compile tested to ensure they are self-contained,
-	i.e. compilable as standalone units. If CONFIG_HEADER_TEST is enabled,
-	this builds them as part of extra-y.
-
-    header-test-pattern-y
-
-	This works as a weaker version of header-test-y, and accepts wildcard
-	patterns. The typical usage is::
-
-		header-test-pattern-y += *.h
-
-	This specifies all the files that matches to `*.h` in the current
-	directory, but the files in 'header-test-' are excluded.
-
 6.7 Commands useful for building a boot image
 ---------------------------------------------
 
--- linux-ein-5.4.0.orig/Documentation/kbuild/modules.rst
+++ linux-ein-5.4.0/Documentation/kbuild/modules.rst
@@ -470,9 +470,9 @@
 
 	The syntax of the Module.symvers file is::
 
-	<CRC>       <Symbol>          <Namespace>  <Module>                         <Export Type>
+	<CRC>       <Symbol>         <Module>                         <Export Type>     <Namespace>
 
-	0xe1cc2a05  usb_stor_suspend  USB_STORAGE  drivers/usb/storage/usb-storage  EXPORT_SYMBOL_GPL
+	0xe1cc2a05  usb_stor_suspend drivers/usb/storage/usb-storage  EXPORT_SYMBOL_GPL USB_STORAGE
 
 	The fields are separated by tabs and values may be empty (e.g.
 	if no namespace is defined for an exported symbol).
--- linux-ein-5.4.0.orig/Documentation/kmsg/IPVS
+++ linux-ein-5.4.0/Documentation/kmsg/IPVS
@@ -0,0 +1,81 @@
+/*? Text: "%s(): NULL arg\n" */
+/*? Text: "%s(): NULL scheduler_name\n" */
+/*? Text: "%s(): [%s] pe already existed in the system\n" */
+/*? Text: "%s(): [%s] pe already linked\n" */
+/*? Text: "%s(): [%s] pe is not in the list. failed\n" */
+/*? Text: "%s(): [%s] scheduler already existed in the system\n" */
+/*? Text: "%s(): [%s] scheduler already linked\n" */
+/*? Text: "%s(): [%s] scheduler is not in the list. failed\n" */
+/*? Text: "%s(): done error\n" */
+/*? Text: "%s(): init error\n" */
+/*? Text: "%s(): lower threshold is higher than upper threshold\n" */
+/*? Text: "%s(): no memory\n" */
+/*? Text: "%s(): request for already hashed, called from %pF\n" */
+/*? Text: "%s(): request for unhash flagged, called from %pF\n" */
+/*? Text: "%s(): server weight less than zero\n" */
+/*? Text: "%s: %s %pI4:%d - %s\n" */
+/*? Text: "%s: %s [%pI6]:%d - %s\n" */
+/*? Text: "%s: %s [%pI6c]:%d - %s\n" */
+/*? Text: "%s: FWM %u 0x%08X - %s\n" */
+/*? Text: "%s: enter\n" */
+/*? Text: "%s: loaded support on port[%d] = %d\n" */
+/*? Text: "BACKUP v0, Dropping buffer bogus conn options\n" */
+/*? Text: "BACKUP v0, bogus conn\n" */
+/*? Text: "BACKUP, Dropping buffer, Err: %d in decoding\n" */
+/*? Text: "BACKUP, Dropping buffer, Unknown version %d\n" */
+/*? Text: "BACKUP, Dropping buffer, msg > buffer\n" */
+/*? Text: "BACKUP, Dropping buffer, to small\n" */
+/*? Text: "BACKUP, Invalid PE parameters\n" */
+/*? Text: "BUG control DEL with n=0 : %s:%d to %s:%d\n" */
+/*? Text: "Connection hash table configured (size=%d, memory=%ldKbytes)\n" */
+/*? Text: "Error binding address of the mcast interface\n" */
+/*? Text: "Error binding to the multicast addr\n" */
+/*? Text: "Error connecting to the multicast addr\n" */
+/*? Text: "Error during creation of socket; terminating\n" */
+/*? Text: "Error joining to the multicast group\n" */
+/*? Text: "Error setting outbound mcast interface\n" */
+/*? Text: "Failed to stop Backup Daemon\n" */
+/*? Text: "Failed to stop Master Daemon\n" */
+/*? Text: "Registered protocols (%s)\n" */
+/*? Text: "SYNC, connection pe_data invalid\n" */
+/*? Text: "Schedule: port zero only supported in persistent services, check your ipvs configuration\n" */
+/*? Text: "Scheduler module ip_vs_%s not found\n" */
+/*? Text: "There is no net ptr to find in the skb in %s() line:%d\n" */
+/*? Text: "UDP no ns data\n" */
+/*? Text: "You probably need to specify IP address on multicast interface.\n" */
+/*? Text: "[%s] pe registered.\n" */
+/*? Text: "[%s] pe unregistered.\n" */
+/*? Text: "[%s] scheduler registered.\n" */
+/*? Text: "[%s] scheduler unregistered.\n" */
+/*? Text: "can't register hooks.\n" */
+/*? Text: "can't register netlink/ioctl.\n" */
+/*? Text: "can't setup connection table.\n" */
+/*? Text: "can't setup control.\n" */
+/*? Text: "cannot register Generic Netlink interface.\n" */
+/*? Text: "cannot register sockopt.\n" */
+/*? Text: "get_ctl: len %u < %u\n" */
+/*? Text: "ip_vs_send_async error %d\n" */
+/*? Text: "ip_vs_sync_buff_create failed.\n" */
+/*? Text: "ipvs loaded.\n" */
+/*? Text: "ipvs unloaded.\n" */
+/*? Text: "length: %u != %u\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "not enough space in Netlink message\n" */
+/*? Text: "persistence engine module ip_vs_pe_%s not found\n" */
+/*? Text: "receiving message error\n" */
+/*? Text: "request control ADD for already controlled: %s:%d to %s:%d\n" */
+/*? Text: "request control DEL for uncontrolled: %s:%d to %s:%d\n" */
+/*? Text: "set_ctl: invalid protocol: %d %pI4:%d %s\n" */
+/*? Text: "set_ctl: len %u != %u\n" */
+/*? Text: "shouldn't reach here, because the box is on the half connection in the tun/dr module.\n" */
+/*? Text: "stopping backup sync thread %d ...\n" */
+/*? Text: "stopping master sync thread %d ...\n" */
+/*? Text: "sync thread started: state = BACKUP, mcast_ifn = %s, syncid = %d\n" */
+/*? Text: "sync thread started: state = MASTER, mcast_ifn = %s, syncid = %d\n" */
+/*? Text: "unknown Generic Netlink command\n" */
+/*? Text: "sync thread started: state = MASTER, mcast_ifn = %s, syncid = %d, id = %d\n" */
+/*? Text: "sync thread started: state = BACKUP, mcast_ifn = %s, syncid = %d, id = %d\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "Unknown mcast interface: %s\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/aes_s390
+++ linux-ein-5.4.0/Documentation/kmsg/s390/aes_s390
@@ -0,0 +1,45 @@
+/*?
+ * Text: "Allocating XTS fallback algorithm %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: algorithm name
+ * Description:
+ * The aes_s390 module failed to allocate a software fallback for the AES
+ * modes that are not supported by the hardware. A possible reason for this
+ * problem is that the aes_generic module that provides the fallback
+ * algorithms is not available.
+ * User action:
+ * Ensure that the aes_generic module is available and loaded and reload
+ * the aes_s390 module.
+ */
+
+/*?
+ * Text: "Allocating AES fallback algorithm %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: algorithm name
+ * Description:
+ * The advanced encryption standard (AES) algorithm includes three modes with
+ * 128-bit, 192-bit, and 256-bit keys. Your hardware system only provides
+ * hardware acceleration for the 128-bit mode. The aes_s390 module failed to
+ * allocate a software fallback for the AES modes that are not supported by the
+ * hardware. A possible reason for this problem is that the aes_generic module
+ * that provides the fallback algorithms is not available.
+ * User action:
+ * Use the 128-bit mode only or ensure that the aes_generic module is available
+ * and loaded and reload the aes_s390 module.
+ */
+
+/*?
+ * Text: "AES hardware acceleration is only available for 128-bit keys\n"
+ * Severity: Informational
+ * Description:
+ * The advanced encryption standard (AES) algorithm includes three modes with
+ * 128-bit, 192-bit, and 256-bit keys. Your hardware system only provides
+ * hardware acceleration for the 128-bit key mode. The aes_s390 module
+ * will use the less performant software fallback algorithm for the 192-bit
+ * and 256-bit key modes.
+ * User action:
+ * None.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/af_iucv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/af_iucv
@@ -0,0 +1,23 @@
+/*?
+ * Text: "Application %s on z/VM guest %s exceeds message limit\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: application name
+ *   @2: z/VM user ID
+ * Description:
+ * Messages or packets destined for the application have accumulated and
+ * reached the maximum value. The default for the message limit is 65535.
+ * You can specify a different limit as the value for MSGLIMIT within
+ * the IUCV statement of the z/VM virtual machine on which the application
+ * runs.
+ * User action:
+ * Ensure that you do not send data faster than the application retrieves
+ * them. Ensure that the message limit on the z/VM guest virtual machine
+ * on which the application runs is high enough.
+ */
+
+/*? Text: "Attempt to release alive iucv socket %p\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/ap
+++ linux-ein-5.4.0/Documentation/kmsg/s390/ap
@@ -0,0 +1,49 @@
+/*?
+ * Text: "%d is not a valid cryptographic domain\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: AP  domain index
+ * Description:
+ * The cryptographic domain specified for the 'domain=' module or kernel
+ * parameter must be an integer in the range 0 to 15.
+ * User action:
+ * Reload the cryptographic device driver with a correct module parameter.
+ * If the device driver has been compiled into the kernel, correct the value
+ * in the kernel parameter line and reboot Linux.
+ */
+
+/*?
+ * Text: "The hardware system does not support AP instructions\n"
+ * Severity: Warning
+ * Description:
+ * The ap module addresses AP adapters through AP instructions. The hardware
+ * system on which the Linux instance runs does not support AP instructions.
+ * The ap module cannot detect any AP adapters.
+ * User action:
+ * Load the ap module only if your Linux instance runs on hardware that
+ * supports AP instructions. If the ap module has been compiled into the kernel,
+ * ignore this message.
+ */
+
+/*?
+ * Text: "Registering adapter interrupts for AP device %02x.%04x failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: AP device ID
+ *   @2: AP queue
+ * Description:
+ * The hardware system supports AP adapter interrupts but failed to enable
+ * an adapter for interrupts. Possible causes for this error are:
+ * i)   The AP adapter firmware does not support AP interrupts.
+ * ii)  An AP adapter firmware update to a firmware level that supports AP
+ *      adapter interrupts failed.
+ * iii) The AP adapter firmware has been successfully updated to a level that
+ *      supports AP interrupts but the new firmware has not been activated.
+ * User action:
+ * Ensure that the firmware on your AP adapters support AP interrupts and that
+ * any firmware updates have completed successfully. If necessary, deconfigure
+ * your cryptographic adapters and reconfigure them to ensure that any firmware
+ * updates become active, then reload the ap module. If the ap module has been
+ * compiled into the kernel, reboot Linux.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/appldata
+++ linux-ein-5.4.0/Documentation/kmsg/s390/appldata
@@ -0,0 +1,91 @@
+/*?
+ * Text: "Starting the data collection for %s failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: appldata module
+ *   @2: return code
+ * Description:
+ * The specified data collection module used the z/VM diagnose call
+ * DIAG 0xDC to start writing data. z/VM returned an error and the data
+ * collection could not start. If the return code is 5, your z/VM guest
+ * virtual machine is not authorized to write data records.
+ * User action:
+ * If the return code is 5, ensure that your z/VM guest virtual machine's
+ * entry in the z/VM directory includes the OPTION APPLMON statement.
+ * For other return codes see the section about DIAGNOSE Code X'DC'
+ * in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Stopping the data collection for %s failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: appldata module
+ *   @2: return code
+ * Description:
+ * The specified data collection module used the z/VM diagnose call DIAG 0xDC
+ * to stop writing data. z/VM returned an error and the data collection
+ * continues.
+ * User action:
+ * See the section about DIAGNOSE Code X'DC' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Starting a new OS data collection failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * After a CPU hotplug event, the record size for the running operating
+ * system data collection is no longer correct. The appldata_os module tried
+ * to start a new data collection with the correct record size but received
+ * an error from the z/VM diagnose call DIAG 0xDC. Any data collected with
+ * the current record size might be faulty.
+ * User action:
+ * Start a new data collection with the cappldata_os module. For information
+ * about starting data collections see "Device Drivers, Features, and
+ * Commands". For information about the return codes see the section about
+ * DIAGNOSE Code X'DC' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Stopping a faulty OS data collection failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * After a CPU hotplug event, the record size for the running operating
+ * system data collection is no longer correct. The appldata_os module tried
+ * to stop the faulty data collection but received an error from the z/VM
+ * diagnose call DIAG 0xDC. Any data collected with the current record size
+ * might be faulty.
+ * User action:
+ * Try to restart appldata_os monitoring. For information about stopping
+ * and starting data collections see "Device Drivers, Features, and
+ * Commands". For information about the return codes see the section about
+ * DIAGNOSE Code X'DC' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Maximum OS record size %i exceeds the maximum record size %i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: no of bytes
+ *   @2: no of bytes
+ * Description:
+ * The OS record size grows with the number of CPUs and is adjusted by the
+ * appldata_os module in response to CPU hotplug events. For more than 110
+ * CPUs the record size would exceed the maximum record size of 4024 bytes
+ * that is  supported by the z/VM hypervisor. To prevent the maximum supported
+ * record size from being exceeded while data collection is in progress,
+ * you cannot load the appldata_os module on Linux instances that are
+ * configured for a maximum of more than 110 CPUs.
+ * User action:
+ * If you do not want to collect operating system data, you can ignore this
+ * message. If you want to collect operating system data, reconfigure your
+ * Linux instance to support less than 110 CPUs.
+ */
+
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/bpf_jit
+++ linux-ein-5.4.0/Documentation/kmsg/s390/bpf_jit
@@ -0,0 +1,16 @@
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+
+/*?
+ * Text: "Unknown opcode %02x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: Instruction opcode
+ * Description:
+ * The BPF JIT compiler has found an unknown instruction in the BPF program
+ * and therefore stops the compilation. As a fallback, the interpreter is used.
+ * User action:
+ * Report this problem and the error message to your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/cio
+++ linux-ein-5.4.0/Documentation/kmsg/s390/cio
@@ -0,0 +1,247 @@
+/*?
+ * Text: "%s is not a valid device for the cio_ignore kernel parameter\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: device bus-ID
+ * Description:
+ * The device specification for the cio_ignore kernel parameter is
+ * syntactically incorrect or specifies an unknown device. This device is not
+ * excluded from being sensed and analyzed.
+ * User action:
+ * Correct your device specification in the kernel parameter line to have the
+ * device excluded when you next reboot Linux. You can write the correct
+ * device specification to /proc/cio_ignore to add the device to the list of
+ * devices to be excluded. This does not immediately make the device
+ * inaccessible but the device is ignored if it disappears and later reappears.
+ */
+
+/*?
+ * Text: "0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: from subchannel set ID
+ *   @2: from device number
+ *   @3: to subchannel set ID
+ *   @4: to device number
+ * Description:
+ * The device range specified for the cio_ignore kernel parameter is
+ * syntactically incorrect. No devices specified with this range are
+ * excluded from being sensed and analyzed.
+ * User action:
+ * Correct your range specification in the kernel parameter line to have the
+ * range of devices  excluded when you next reboot Linux. You can write the
+ * correct range specification to /proc/cio_ignore to add the range of devices
+ * to the list of devices to be excluded. This does not immediately make the
+ * devices in the range inaccessible but any of these devices are ignored if
+ * they disappear and later reappear.
+ */
+
+/*?
+ * Text: "Processing %s for channel path %x.%02x\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: configuration change
+ *   @2: channel subsystem ID
+ *   @3: CHPID
+ * Description:
+ * A configuration change is in progress for the given channel path.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "No CCW console was found\n"
+ * Severity: Warning
+ * Description:
+ * Linux did not find the expected CCW console and tries to use an alternative
+ * console. A possible reason why the console was not found is that the console
+ * has been specified in the cio_ignore list.
+ * User action:
+ * None, if an appropriate alternative console has been found, and you want
+ * to use this alternative console. If you want to use the CCW console, ensure
+ * that is not specified in the cio_ignore list, explicitly specify the console
+ * with the 'condev=' kernel parameter, and reboot Linux.
+ */
+
+/*?
+ * Text: "Channel measurement facility initialized using format %s (mode %s)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: format
+ *   @2: mode
+ * Description:
+ * The channel measurement facility has been initialized successfully.
+ * Format 'extended' should be used for z990 and later mainframe systems.
+ * Format 'basic' is intended for earlier mainframes. Mode 'autodetected' means
+ * that the format has been set automatically. Mode 'parameter' means that the
+ * format has been set according to the 'format=' kernel parameter.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The CSS device driver initialization failed with errno=%d\n"
+ * Severity: Alert
+ * Parameter:
+ *   @1: Return code
+ * Description:
+ * The channel subsystem bus could not be established.
+ * User action:
+ * See the errno man page to find out what caused the problem.
+ */
+ /*? Text: "%s: Got subchannel machine check but no sch_event handler provided.\n" */
+
+/*?
+ * Text: "%s: Setting the device online failed because it is boxed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: Device bus-ID
+ * Description:
+ * Initialization of a device did not complete because it did not respond in
+ * time or it was reserved by another operating system.
+ * User action:
+ * Make sure that the device is working correctly, then try again to set it
+ * online. For devices that support the reserve/release mechanism (for example
+ * DASDs), you can try to override the reservation of the other system by
+ * writing 'force' to the 'online' sysfs attribute of the affected device.
+ */
+
+/*?
+ * Text: "%s: Setting the device online failed because it is not operational\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: Device bus-ID
+ * Description:
+ * Initialization of a device did not complete because it is not present or
+ * not operational.
+ * User action:
+ * Make sure that the device is present and working correctly, then try again
+ * to set it online.
+ */
+
+/*?
+ * Text: "%s: The device stopped operating while being set offline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: Device bus-ID
+ * Description:
+ * While the device was set offline, it was not present or not operational.
+ * The device is now inactive, but setting it online again might fail.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The device entered boxed state while being set offline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: Device bus-ID
+ * Description:
+ * While the device was set offline, it did not respond in time or it was
+ * reserved by another operating system. The device is now inactive, but
+ * setting it online again might fail.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Logging for subchannel 0.%x.%04x failed with errno=%d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: subchannel set ID
+ *   @2: subchannel number
+ *   @3: errno
+ * Description:
+ * Capturing model-dependent logs and traces could not be triggered for the
+ * specified subchannel.
+ * User action:
+ * See the errno man page to find out what caused the problem.
+ */
+
+/*?
+ * Text: "Logging for subchannel 0.%x.%04x was triggered\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: subchannel set ID
+ *   @2: subchannel number
+ * Description:
+ * Model-dependent logs and traces may be captured for the specified
+ * subchannel.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: No interrupt was received within %lus (CS=%02x, DS=%02x, CHPID=%x.%02x)\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: device number
+ *   @2: timeout value
+ *   @3: channel status
+ *   @4: device status
+ *   @5: channel subsystem ID
+ *   @6: CHPID
+ * Description:
+ * Internal I/Os are used by the common I/O layer to ensure that devices are
+ * operational and accessible.
+ * The common I/O layer did not receive an interrupt for an internal I/O
+ * during the specified timeout period.
+ * As a result, the device might assume a state that makes the device
+ * unusable to Linux until the problem is resolved.
+ * User action:
+ * Make sure that the device is working correctly and try the action again.
+ */
+
+/*?
+ * Text: "Link stopped: RS=%02x RSID=%04x IC=%02x IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: reporting source
+ *   @2: reporting source ID
+ *   @3: incident code
+ *   @4: incident unit parameters
+ *   @5: incident unit node ID
+ *   @6: attached unit parameters
+ *   @7: attached unit node ID
+ *
+ * Description:
+ * A hardware error has occurred. A unit at one end of an interface
+ * link has detected a failure in the link or in one of the units attached to
+ * the link. As a result, data transfer across the link has stopped. In the
+ * message text, the node IDs of involved units are represented in the
+ * following format: TTTTTT/MDL,MMM.PPSSSSSSSSSSSS,XXXX where TTTTTT refers to
+ * the machine type, MDL the model number, MMM the manufacturer, PP the
+ * manufacturing plant, SSSSSSSSSSSS the unit sequence number and XXXX the
+ * machine type-dependent physical interface number. If no data is available
+ * for the unit parameters or node ID field, "n/a" is used instead.
+ *
+ * User action:
+ * Report the problem to your support organization.
+ */
+
+/*?
+ * Text: "Link degraded: RS=%02x RSID=%04x IC=%02x IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: reporting source
+ *   @2: reporting source ID
+ *   @3: incident code
+ *   @4: incident unit parameters
+ *   @5: incident unit node ID
+ *   @6: attached unit parameters
+ *   @7: attached unit node ID
+ * Description:
+ * A hardware error has occurred. A unit at one end of an interface
+ * link has detected a failure in the link or in one of the units attached to
+ * the link. As a result, data transfer across the link is degraded. In the
+ * message text, the node IDs of involved units are represented in the
+ * following format: TTTTTT/MDL,MMM.PPSSSSSSSSSSSS,XXXX where TTTTTT refers to
+ * the machine type, MDL the model number, MMM the manufacturer, PP the
+ * manufacturing plant, SSSSSSSSSSSS the unit sequence number and XXXX the
+ * machine type-dependent physical interface number. If no data is available
+ * for the unit parameters or node ID field, "n/a" is used instead.
+ *
+ * User action:
+ * Report the problem to your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/cpcmd
+++ linux-ein-5.4.0/Documentation/kmsg/s390/cpcmd
@@ -0,0 +1,16 @@
+/*?
+ * Text: "The cpcmd kernel function failed to allocate a response buffer\n"
+ * Severity: Warning
+ * Description:
+ * IPL code, console detection, and device drivers like vmcp or vmlogrdr use
+ * the cpcmd kernel function to send commands to the z/VM control program (CP).
+ * If a program that uses the cpcmd function does not allocate a contiguous
+ * response buffer below 2 GB guest real storage, cpcmd creates a bounce buffer
+ * to be used as the response buffer. Because of low memory or memory
+ * fragmentation, cpcmd could not create the bounce buffer.
+ * User action:
+ * Look for related page allocation failure messages and at the stack trace to
+ * find out which program or operation failed. Free some memory and retry the
+ * failed operation. Consider allocating more memory to your z/VM guest virtual
+ * machine.
+ */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/cpu
+++ linux-ein-5.4.0/Documentation/kmsg/s390/cpu
@@ -0,0 +1,46 @@
+/*?
+ * Text: "%d configured CPUs, %d standby CPUs\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: number of configured CPUs
+ *   @2: number of standby CPUs
+ * Description:
+ * The kernel detected the given number of configured and standby CPUs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The CPU configuration topology of the machine is:"
+ * Severity: Informational
+ * Description:
+ * The first six values of the topology information represent fields Mag6 to
+ * Mag1 of system-information block (SYSIB) 15.1.2. These fields specify the
+ * maximum numbers of topology-list entries (TLE) at successive topology nesting
+ * levels. The last value represents the MNest value of SYSIB 15.1.2 which
+ * specifies the maximum possible nesting that can be configured through
+ * dynamic changes. For details see the SYSIB 15.1.2 information in the
+ * "Principles of Operation."
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "CPU %i exceeds the maximum %i and is excluded from the dump\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: CPU number
+ *   @2: maximum CPU number
+ * Description:
+ * The Linux kernel is used as a system dumper but it runs on more CPUs than
+ * it has been compiled for with the CONFIG_NR_CPUS kernel configuration
+ * option. The system dump will be created but information on one or more
+ * CPUs will be missing.
+ * User action:
+ * Update the system dump kernel to a newer version that supports more
+ * CPUs or reduce the number of installed CPUs and reproduce the problem
+ * that should be analyzed. If you send the system dump that prompted this
+ * message to a support organization, be sure to communicate that the dump
+ * does not include all CPU information.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/cpum_cf
+++ linux-ein-5.4.0/Documentation/kmsg/s390/cpum_cf
@@ -0,0 +1,68 @@
+/*?
+ * Text: "Enabling the performance measuring unit failed with rc=%x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: error condition
+ * Description:
+ * The device driver failed to enable CPU counter sets with the
+ * load counter controls (lcctl) instruction.
+ * See the section about lcctl in "The Load-Program-Parameter and the CPU-Measurement
+ * Facilities", SA23-2260, for an explanation of the error conditions.
+ * User action:
+ * Stop the performance measurement programs and try again.
+ */
+
+/*?
+ * Text: "Disabling the performance measuring unit failed with rc=%x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: error condition
+ * Description:
+ * The device driver failed to disable CPU counter sets with the
+ * load counter controls (lcctl) instruction.
+ * See the section about lcctl in "The Load-Program-Parameter and the CPU-Measurement
+ * Facilities", SA23-2260, for an explanation of the error conditions.
+ * User action:
+ * Stop the performance measurement programs and try again.
+ */
+
+/*?
+ * Text: "Registering the cpum_cf PMU failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *  @1: error code
+ * Description:
+ * The device driver could not register the Performance Measurement Unit (PMU)
+ * for the CPU-measurement counter facility.
+ * A possible cause of this problem is memory constraints.
+ * User action:
+ * If the error code is -12 (ENOMEM), consider assigning more memory
+ * to your Linux instance.
+ */
+
+/*?
+ * Text: "CPU[%i] Counter data was lost\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: cpu number
+ * Description:
+ * CPU counter data was lost because of machine internal
+ * high-priority activities.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Registering for CPU-measurement alerts failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *  @1: error code
+ * Description:
+ * The device driver could not register to receive CPU-measurement alerts.
+ * Alerts make you aware of measurement errors.
+ * A possible cause of this problem is memory constraints.
+ * User action:
+ * If the error code is -12 (ENOMEM), consider assigning more memory
+ * to your Linux instance.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/cpum_sf
+++ linux-ein-5.4.0/Documentation/kmsg/s390/cpum_sf
@@ -0,0 +1,104 @@
+/*?
+ * Text: "The sampling buffer limits have changed to: min=%lu max=%lu (diag=x%lu)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: minimum size in sample-data-blocks
+ *   @2: maximum size in sample-data-blocks
+ *   @3: size factor for buffering diagnostic-sampling data entries
+ * Description:
+ * The minimum or maximum size limit for the sampling facility buffer was
+ * changed.  The change is effective immediately.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Switching off the sampling facility failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: error condition
+ * Description:
+ * The CPU-measurement sampling facility could not be switched off and continues
+ * to run.  For details, see LOAD SAMPLING CONTROLS in
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * If this problem persists, reboot your Linux instance.
+ */
+
+/*?
+ * Text: "Sample data was lost\n"
+ * Severity: Error
+ * Description:
+ * Sample data was lost because of machine-internal high-priority activities.
+ * The sampling facility is stopped.
+ * User action:
+ * End all performance measurement sessions.  Discard the measurement data,
+ * which are likely to be flawed.  Repeat your measurements.
+ * If the problem persists, contact your hardware administrator.
+ */
+
+/*?
+ * Text: "Sampling facility support for perf is not available: reason=%04x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: reason code
+ * Description:
+ * The device driver could not initialize the sampling facility support.
+ * Possible reason codes are:
+ * 0001: The device driver failed to query CPU-measurement sampling facility
+ *	 information.
+ *
+ * 0002: The device driver does not support the basic-sampling function that
+ *	 is available on the LPAR within which the Linux instance runs.
+ *
+ * 0003: The device driver could not register to receive CPU-measurement alerts.
+ *	 A possible cause of this problem is memory constraints.
+ *
+ * 0004: The device driver could not register the Performance Measurement Unit
+ *	 (PMU) for the CPU-measurement sampling facility.
+ *	 A possible cause of this problem is memory constraints.
+ * User action:
+ * Consider assigning more memory to your Linux instance.
+ */
+
+/*?
+ * Text: "Loading sampling controls failed: op=%i err=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: Type of operation
+ *   @2: Error condition
+ * Description:
+ * The sampling facility support could not load sampling controls to enable
+ * (operation type 1) or disable (operation type 2) the CPU-measurement sampling
+ * facility.  For details of the error condition, see LOAD SAMPLING CONTROLS in
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * If the problem persists, reboot your Linux instance.
+ */
+
+/*?
+ * Text: "A sampling buffer entry is incorrect (alert=0x%x)\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: Alert code
+ * Description:
+ * An incorrect sampling facility buffer entry was detected. The alert code
+ * indicates the root cause, for example, an incorrect entry address or an
+ * incorrect sample-data-block-table entry.
+ * User action:
+ * End active performance measurement sessions, for example, perf processes. If
+ * the problem persists, reboot your Linux instance.
+ */
+
+/*?
+ * Text: "Registering for s390dbf failed\n"
+ * Severity: Error
+ * Description:
+ * The device driver failed to register for the s390 debug feature.  You will
+ * not receive any debug information.  A possible cause of this problem is
+ * memory constraints.
+ * User action:
+ * Consider assigning more memory
+ * to your Linux instance.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/crc32-vx
+++ linux-ein-5.4.0/Documentation/kmsg/s390/crc32-vx
@@ -0,0 +1 @@
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/ctcm
+++ linux-ein-5.4.0/Documentation/kmsg/s390/ctcm
@@ -0,0 +1,202 @@
+/*?
+ * Text: "%s: An I/O-error occurred on the CTCM device\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ * Description:
+ * An I/O error was detected on one of the subchannels of the CTCM device.
+ * Depending on the error, the CTCM device driver might attempt an automatic
+ * recovery.
+ * User action:
+ * Check the status of the CTCM device, for example, with ifconfig. If the
+ * device is not operational, perform a manual recovery. See "Device Drivers,
+ * Features, and Commands" for details about how to recover a CTCM device.
+ */
+
+/*?
+ * Text: "%s: An adapter hardware operation timed out\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ * Description:
+ * The CTCM device uses an adapter to physically connect to its communication
+ * peer. An operation on this adapter timed out.
+ * User action:
+ * Check the status of the CTCM device, for example, with ifconfig. If the
+ * device is not operational, perform a manual recovery. See "Device Drivers,
+ * Features, and Commands" for details about how to recover a CTCM device.
+ */
+
+/*?
+ * Text: "%s: An error occurred on the adapter hardware\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ * Description:
+ * The CTCM device uses an adapter to physically connect to its communication
+ * peer. An operation on this adapter returned an error.
+ * User action:
+ * Check the status of the CTCM device, for example, with ifconfig. If the
+ * device is not operational, perform a manual recovery. See "Device Drivers,
+ * Features, and Commands" for details about how to recover a CTCM device.
+ */
+
+/*?
+ * Text: "%s: The communication peer has disconnected\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: channel ID
+ * Description:
+ * The remote device has disconnected. Possible reasons are that the remote
+ * interface has been closed or that the operating system instance with the
+ * communication peer has been rebooted or shut down.
+ * User action:
+ * Check the status of the peer device. Ensure that the peer operating system
+ * instance is running and that the peer interface is operational.
+ */
+
+/*?
+ * Text: "%s: The remote operating system is not available\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: channel ID
+ * Description:
+ * The operating system instance with the communication peer has disconnected.
+ * Possible reasons are that the operating system instance has been rebooted
+ * or shut down.
+ * User action:
+ * Ensure that the peer operating system instance is running and that the peer
+ * interface is operational.
+ */
+
+/*?
+ * Text: "%s: The adapter received a non-specific IRQ\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ * Description:
+ * The adapter hardware used by the CTCM device received an IRQ that cannot
+ * be mapped to a particular device. This is a hardware problem.
+ * User action:
+ * Check the status of the CTCM device, for example, with ifconfig. Check if
+ * the connection to the remote device still works. If the CTCM device is not
+ * operational, set it offline and back online. If this does not resolve the
+ * problem, perform a manual recovery. See "Device Drivers, Features, and
+ * Commands" for details about how to recover a CTCM device. If this problem
+ * persists, gather Linux debug data, collect the hardware logs, and report the
+ * problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: A check occurred on the subchannel\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ * Description:
+ * A check condition has been detected on the subchannel.
+ * User action:
+ * Check if the connection to the remote device still works. If the CTCM device
+ * is not operational, set it offline and back online. If this does not resolve
+ * the problem, perform a manual recovery. See "Device Drivers, Features, and
+ * Commands" for details about how to recover a CTCM device. If this problem
+ * persists, gather Linux debug data and report the problem to your support
+ * organization.
+ */
+
+/*?
+ * Text: "%s: The communication peer is busy\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: channel ID
+ * Description:
+ * A busy target device was reported. This might be a temporary problem.
+ * User action:
+ * If this problem persists or is reported frequently ensure that the target
+ * device is working properly.
+ */
+
+/*?
+ * Text: "%s: The specified target device is not valid\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: channel ID
+ * Description:
+ * A target device was called with a faulty device specification. This is an
+ * adapter hardware problem.
+ * User action:
+ * Gather Linux debug data, collect the hardware logs, and contact IBM support.
+ */
+
+/*?
+ * Text: "An I/O operation resulted in error %04x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: channel ID
+ *   @2: error information
+ * Description:
+ * A hardware operation ended with an error.
+ * User action:
+ * Check the status of the CTCM device, for example, with ifconfig. If the
+ * device is not operational, perform a manual recovery. See "Device Drivers,
+ * Features, and Commands" for details about how to recover a CTCM device.
+ * If this problem persists, gather Linux debug data, collect the hardware logs,
+ * and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Initialization failed with RX/TX init handshake error %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ *   @2: error information
+ * Description:
+ * A problem occurred during the initialization of the connection. If the
+ * connection can be established after an automatic recovery, a success message
+ * is issued.
+ * User action:
+ * If the problem is not resolved by the automatic recovery process, check the
+ * local and remote device. If this problem persists, gather Linux debug data
+ * and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The network backlog for %s is exceeded, package dropped\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ *   @2: calling function
+ * Description:
+ * There is more network traffic than can be handled by the device. The device
+ * is closed and some data has not been transmitted. The device might be
+ * recovered automatically.
+ * User action:
+ * Investigate and resolve the congestion. If necessary, set the device
+ * online to make it operational.
+ */
+
+/*?
+ * Text: "%s: The XID used in the MPC protocol is not valid, rc = %d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the CTCM device
+ *   @2: return code
+ * Description:
+ * The exchange identification (XID) used by the CTCM device driver when
+ * in MPC mode is not valid.
+ * User action:
+ * Note the error information provided with this message and contact your
+ * support organization.
+ */
+
+/*? Text: "CTCM driver unloaded\n" */
+/*? Text: "%s: %s Internal error: net_device is NULL, ch = 0x%p\n" */
+/*? Text: "%s / Initializing the ctcm device driver failed, ret = %d\n" */
+/*? Text: "%s: %s: Internal error: Can't determine channel for interrupt device %s\n" */
+/*? Text: "CTCM driver initialized\n" */
+/*? Text: "%s: setup OK : r/w = %s/%s, protocol : %d\n" */
+/*? Text: "%s: Connected with remote side\n" */
+/*? Text: "%s: Restarting device\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/dasd
+++ linux-ein-5.4.0/Documentation/kmsg/s390/dasd
@@ -0,0 +1,704 @@
+/* dasd_ioctl */
+
+/*?
+ * Text: "%s: The DASD has been put in the quiesce state\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * No I/O operation is possible on this device.
+ * User action:
+ * Resume the DASD to enable I/O operations.
+ */
+
+/*?
+ * Text: "%s: I/O operations have been resumed on the DASD\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD is no longer in state quiesce and I/O operations can be performed
+ * on the device.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The DASD cannot be formatted while it is enabled\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD you try to format is enabled. Enabled devices cannot be formatted.
+ * User action:
+ * Contact the owner of the formatting tool.
+ */
+
+/*?
+ * Text: "%s: The specified DASD is a partition and cannot be formatted\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD you try to format is a partition. Partitions cannot be formatted
+ * separately. You can only format a complete DASD including all its partitions.
+ * User action:
+ * Format the complete DASD.
+ * ATTENTION: Formatting irreversibly destroys all data on all partitions
+ * of the DASD.
+ */
+
+/*?
+ * Text: "%s: The specified DASD is a partition and cannot be checked\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD you try to check is a partition. Partitions cannot be checked
+ * separately. You can only check a complete DASD including all its partitions.
+ * User action:
+ * Check the complete DASD.
+ */
+
+/*?
+ * Text: "%s: Formatting unit %d failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: start track
+ *   @3: return code
+ * Description:
+ * The formatting process might have been interrupted by a signal, for example,
+ * CTRL+C. If the process was not interrupted intentionally, an I/O error
+ * might have occurred.
+ * User action:
+ * Retry to format the device. If the error persists, check the log file for
+ * related error messages. If you cannot resolve the error, note the return
+ * code and contact your support organization.
+ */
+
+
+/* dasd */
+
+/*?
+ * Text: "%s: Cancelling request %p failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to request
+ *   @3: return code of previous function
+ * Description:
+ * In response to a user action, the DASD device driver tried but failed to
+ * cancel a previously started I/O operation.
+ * User action:
+ * Try the action again.
+ */
+
+/*?
+ * Text: "%s: Flushing the DASD request queue failed for request %p\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to request
+ * Description:
+ * As part of the unloading process, the DASD device driver flushes the
+ * request queue. This failed because a previously started I/O operation
+ * could not be canceled.
+ * User action:
+ * Try again to unload the DASD device driver or to shut down Linux.
+ */
+
+/*?
+ * Text: "The DASD device driver could not be initialized\n"
+ * Severity: Informational
+ * Description:
+ * The initialization of the DASD device driver failed because of previous
+ * errors.
+ * User action:
+ * Check for related previous error messages.
+ */
+
+/*?
+ * Text: "%s: Accessing the DASD failed because it is in probeonly mode\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The dasd= module or kernel parameter specified the probeonly attribute for
+ * the DASD you are trying to access. The DASD device driver cannot access
+ * DASDs that are in probeonly mode.
+ * User action:
+ * Change the dasd= parameter as to omit probeonly for the DASD and reload
+ * the DASD device driver. If the DASD device driver has been compiled into
+ * the kernel, reboot Linux.
+ */
+
+/*?
+ * Text: "%s: cqr %p timed out (%lus), %i retries remaining\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: request
+ *   @3: timeout value
+ *   @4: number of retries left
+ * Description:
+ * A try of the error recovery procedure (ERP) for the channel queued request
+ * (cqr) timed out and failed to recover the error. ERP continues for the DASD.
+ * User action:
+ * Ignore this message if it occurs infrequently and if the recovery succeeds
+ * during one of the retries. If this error persists, check for related
+ * previous error messages and report the problem to your support organization.
+ *
+ * The timeout can be changed by writing a new value to the sysfs 'expires' attribute of the DASD. The value specifies the timeout in seconds.
+ */
+
+/*?
+ * Text: "%s: cqr %p timed out (%lus) but cannot be ended, retrying in 5 s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: request
+ *   @3: timeout value
+ * Description:
+ * A try of the error recovery procedure (ERP) for the channel queued request
+ * (cqr) timed out and failed to recover the error. The I/O request submitted
+ * during the try could not be canceled. The ERP waits for 5 seconds before
+ * trying again.
+ * User action:
+ * Ignore this message if it occurs infrequently and if the recovery succeeds
+ * during one of the retries. If this error persists, check for related
+ * previous error messages and report the problem to your support organization.
+ *
+ * The timeout can be changed by writing a new value to the sysfs 'expires' attribute of the DASD. The value specifies the timeout in seconds.
+ */
+
+/*?
+ * Text: "%s: The DASD cannot be set offline while it is in use\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD cannot be set offline because it is in use by an internal process.
+ * An action to free the DASD might not have completed yet.
+ * User action:
+ * Wait some time and set the DASD offline later.
+ */
+
+/*?
+ * Text: "%s: The DASD cannot be set offline with open count %i\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: count
+ * Description:
+ * The DASD is being used by one or more processes and cannot be set offline.
+ * User action:
+ * Ensure that the DASD is not in use anymore, for example, unmount all
+ * partitions. Then try again to set the DASD offline.
+ */
+
+/*?
+ * Text: "%s: Setting the DASD online failed with rc=%d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ * Description:
+ * The DASD could not be set online because of previous errors.
+ * User action:
+ * Look for previous error messages. If you cannot resolve the error, note
+ * the return code and contact your support organization.
+ */
+
+/*?
+ * Text: "%s Setting the DASD online with discipline %s failed with rc=%i\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: discipline
+ *   @3: return code
+ * Description:
+ * The DASD could not be set online because of previous errors.
+ * User action:
+ * Look for previous error messages. If you cannot resolve the error, note the
+ * return code and contact your support organization.
+ */
+
+/*?
+ * Text: "%s Setting the DASD online failed because of missing DIAG discipline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD was to be set online with discipline DIAG but this discipline of
+ * the DASD device driver is not available.
+ * User action:
+ * Ensure that the dasd_diag_mod module is loaded. If your Linux system does
+ * not include this module, you cannot set DASDs online with the DIAG
+ * discipline.
+ */
+
+/*?
+ * Text: "%s Setting the DASD online failed because of a missing discipline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD was to be set online with a DASD device driver discipline that
+ * is not available.
+ * User action:
+ * Ensure that all DASD modules are loaded correctly.
+ */
+
+---------------------------
+
+/*?
+ * Text: "The statistics feature has been switched off\n"
+ * Severity: Informational
+ * Description:
+ * The statistics feature of the DASD device driver has been switched off.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The statistics feature has been switched on\n"
+ * Severity: Informational
+ * Description:
+ * The statistics feature of the DASD device driver has been switched on.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The statistics have been reset\n"
+ * Severity: Informational
+ * Description:
+ * The DASD statistics data have been reset.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s is not a supported value for /proc/dasd/statistics\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: value
+ * Description:
+ * An incorrect value has been written to /proc/dasd/statistics.
+ * The supported values are: 'set on', 'set off', and 'reset'.
+ * User action:
+ * Write a supported value to /proc/dasd/statistics.
+ */
+
+/*?
+ * Text: "%s is not a valid device range\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: range
+ * Description:
+ * A device range specified with the dasd= parameter is not valid.
+ * User action:
+ * Examine the dasd= parameter and correct the device range.
+ */
+
+/*?
+ * Text: "The probeonly mode has been activated\n"
+ * Severity: Informational
+ * Description:
+ * The probeonly mode of the DASD device driver has been activated. In this
+ * mode the device driver rejects any 'open' syscalls with EPERM.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The IPL device is not a CCW device\n"
+ * Severity: Error
+ * Description:
+ * The value for the dasd= parameter contains the 'ipldev' keyword. During
+ * the boot process this keyword is replaced with the device from which the
+ * IPL was performed. The 'ipldev' keyword is not valid if the IPL device is
+ * not a CCW device.
+ * User action:
+ * Do not specify the 'ipldev' keyword when performing an IPL from a device
+ * other than a CCW device.
+ */
+
+/*?
+ * Text: "A closing parenthesis ')' is missing in the dasd= parameter\n"
+ * Severity: Warning
+ * Description:
+ * The specification for the dasd= kernel or module parameter has an opening
+ * parenthesis '(' * without a matching closing parenthesis ')'.
+ * User action:
+ * Correct the parameter value.
+ */
+
+/*?
+ * Text: "The autodetection mode has been activated\n"
+ * Severity: Informational
+ * Description:
+ * The autodetection mode of the DASD device driver has been activated. In
+ * this mode the DASD device driver sets all detected DASDs online.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%*s is not a supported device option\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: length of option code
+ *   @2: option code
+ * Description:
+ * The dasd= parameter includes an unknown option for a DASD or a device range.
+ * Options are specified in parenthesis and immediately follow a device or
+ * device range.
+ * User action:
+ * Check the dasd= syntax and remove any unsupported options from the dasd=
+ * parameter specification.
+ */
+
+/*?
+ * Text: "PAV support has be deactivated\n"
+ * Severity: Informational
+ * Description:
+ * The 'nopav' keyword has been specified with the dasd= kernel or module
+ * parameter. The Parallel Access Volume (PAV) support of the DASD device
+ * driver has been deactivated.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "'nopav' is not supported on z/VM\n"
+ * Severity: Informational
+ * Description:
+ * For Linux instances that run as guest operating systems of the z/VM
+ * hypervisor Parallel Access Volume (PAV) support is controlled by z/VM not
+ * by Linux.
+ * User action:
+ * Remove 'nopav' from the dasd= module or kernel parameter specification.
+ */
+
+/*?
+ * Text: "High Performance FICON support has been deactivated\n"
+ * Severity: Informational
+ * Description:
+ * The 'nofcx' keyword has been specified with the dasd= kernel or module
+ * parameter. The High Performance FICON (transport mode) support of the DASD
+ * device driver has been deactivated.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The dasd= parameter value %s has an invalid ending\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: parameter value
+ * Description:
+ * The specified value for the dasd= kernel or module parameter is not correct.
+ * User action:
+ * Check the module or the kernel parameter.
+ */
+
+/*?
+ * Text: "Registering the device driver with major number %d failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DASD major
+ * Description:
+ * Major number 94 is reserved for the DASD device driver. The DASD device
+ * driver failed to register with this major number. Another device driver
+ * might have used major number 94.
+ * User action:
+ * Determine which device driver uses major number 94 instead of the DASD
+ * device driver and unload this device driver. Then try again to load the
+ * DASD device driver.
+ */
+
+/*?
+  * Text: "%s: default ERP has run out of retries and failed\n"
+  * Severity: Error
+  * Parameter:
+  *   @1: bus ID of the DASD
+  * Description:
+  * The error recovery procedure (ERP) tried to recover an error but the number
+  * of retries for the I/O was exceeded before the error could be resolved.
+  * User action:
+  * Check for related previous error messages.
+  */
+
+/*?
+ * Text: "%s: Unable to terminate request %p on suspend\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to request
+ * Description:
+ * As part of the suspend process, the DASD device driver terminates requests
+ * on the request queue. This failed because a previously started I/O operation
+ * could not be canceled. The suspend process will be stopped.
+ * User action:
+ * Try again to suspend the system.
+ */
+
+/*?
+ * Text: "%s: ERP failed for the DASD\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An error recovery procedure (ERP) was performed for the DASD but failed.
+ * User action:
+ * Check the message log for previous related error messages.
+ */
+
+/*?
+ * Text: "%s: An error occurred in the DASD device driver, reason=%s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: reason code
+ * Description:
+ * This problem indicates a program error in the DASD device driver.
+ * User action:
+ * Note the reason code and contact your support organization.
+*/
+
+/*?
+ * Text: "%s: No operational channel path is left for the device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * All channel paths to the device have become non-operational. The DASD
+ * device driver suspends I/O operations and queues I/O requests for this
+ * device until at least one channel path becomes operational again.
+ * User action:
+ * Ensure that each channel path to the device has been set up correctly
+ * and that the related physical cable connections are in place.
+ */
+
+/*?
+ * Text: "%s: No verified channel paths remain for the device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * All verified channel paths to the device have become non-operational.
+ * Any other paths to the device have previously been identified as not usable.
+ * The DASD device driver suspends I/O operations and queues I/O requests
+ * for this device until at least one channel path becomes operational
+ * again.
+ * User action:
+ * Ensure that each channel path to the device has been set up correctly
+ * and that the related physical cable connections are in place.
+ * Set all paths to the device offline and online again to repeat the path
+ * verification. Alternatively, set the device offline and online again to
+ * verify all available paths for this device.
+ * If this problem persists, gather Linux debug data and report the problem
+ * to your support organization.
+ */
+
+/*?
+ * Text: "%s: A channel path to the device has become operational\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * At least one channel path of this device has become operational again.
+ * The DASD device driver resumes I/O operations to the device and processes
+ * the I/O requests that were queued while there was no operational channel path.
+ * User action:
+ * None.
+ */
+
+------------------------------------------------------------------------------------
+/* dasd_diag */
+
+/*?
+ * Text: "%s: A 64-bit DIAG call failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * 64-bit DIAG calls require a 64-bit z/VM version.
+ * User action:
+ * Use z/VM 5.2 or later or set the sysfs 'use_diag' attribute of the DASD to 0
+ * to switch off DIAG.
+ */
+
+/*?
+ * Text: "%s: Accessing the DASD failed because of an incorrect format (rc=%d)\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ * Description:
+ * The format of the DASD is not correct.
+ * User action:
+ * Check the device format. For details about the return code see the
+ * section about the INITIALIZE function for DIAGNOSE Code X'250'
+ * in "z/VM CP Programming Services". If you cannot resolve the error, note
+ * the return code and contact your support organization.
+ */
+
+/*?
+ * Text: "%s: New DASD with %ld byte/block, total size %ld KB%s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: bytes per block
+ *   @3: size
+ *   @4: access mode
+ * Description:
+ * A DASD with the indicated block size and total size has been set online.
+ * If the DASD is configured as read-only to the real or virtual hardware,
+ * the message includes an indication of this hardware access mode. The
+ * hardware access mode is independent from the 'readonly' attribute of
+ * the device in sysfs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: DIAG ERP failed with rc=%d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ * Description:
+ * An error in the DIAG processing could not be recovered by the error
+ * recovery procedure (ERP) of the DIAG discipline.
+ * User action:
+ * Note the return code, check for related I/O errors, and report this problem
+ * to your support organization.
+ */
+
+/*?
+ * Text: "%s: DIAG initialization failed with rc=%d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ * Description:
+ * Initializing the DASD with the DIAG discipline failed. Possible reasons for
+ * this problem are that the device has a device type other than FBA or ECKD,
+ * or has a block size other than one of the supported sizes:
+ * 512 byte, 1024 byte, 2048 byte, or 4096 byte.
+ * User action:
+ * Ensure that the device can be written to and has a supported device type
+ * and block size. For details about the return code see the section about
+ * the INITIALIZE function for DIAGNOSE Code X'250' in "z/VM CP Programming
+ * Services". If you cannot resolve the error, note the error code and contact
+ * your support organization.
+ */
+
+/*?
+ * Text: "%s: Device type %d is not supported in DIAG mode\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: device type
+ * Description:
+ * Only DASD of type FBA and ECKD are supported in DIAG mode.
+ * User action:
+ * Set the sysfs 'use_diag' attribute of the DASD to 0 and try again to access
+ * the DASD.
+ */
+
+/*?
+ * Text: "Discipline %s cannot be used without z/VM\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: discipline name
+ * Description:
+ * The discipline that is specified with the dasd= kernel or module parameter
+ * is only available for Linux instances that run as guest operating
+ * systems of the z/VM hypervisor.
+ * User action:
+ * Remove the unsupported discipline from the parameter string.
+ */
+
+/*?
+ * Text: "%s: The access mode of a DIAG device changed to read-only\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A device changed its access mode from writeable to
+ * read-only while in use.
+ * User action:
+ * Set the device offline, ensure that the device is configured correctly in
+ * z/VM, then set the device online again.
+ */
+
+------------------------------------------------------------------------------------
+/* dasd_erp */
+
+/*?
+ * Text: "%s: A timeout error occurred for cqr %p\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to request
+ * Description:
+ * A channel queued request (cqr) failed because it timed out.
+ * One possible reason for this error is that a request did not
+ * complete within the timeout interval specified for the DASD.
+ * The timeout interval is set as the value of the 'timeout' sysfs
+ * attribute of a DASD. A value of 0 disables the timeout function.
+ * The timeout function can be used; for example, by mirroring setups;
+ * to quickly process a request queue for a DASD that has become unavailable.
+ * User action:
+ * Check the message log for previous related error messages.  Verify
+ * that the storage server and the connection from host to storage
+ * server are operational.  If the 'timeout' sysfs attribute of the
+ * DASD has been set to a value other than 0, verify that this
+ * setting is intentional and change it if required.
+ */
+
+/*?
+ * Text: "%s: A transport error occurred for cqr %p\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to request
+ * Description:
+ * A channel queued request (cqr) failed because the connection to the
+ * device was lost and the 'failfast' flag is set for the request.
+ * This flag can result from, for example:
+ *
+ * - A software layer above the DASD device driver;
+ *   for example, in a host based mirroring setup.
+ *
+ * - Value 1 for the 'failfast' sysfs attribute of the DASD.
+ *   This setting applies to all requests on the DASD.
+ *
+ * User action:
+ * Ensure that each channel path to the device has been set up
+ * correctly and that the related physical cable connections are in
+ * place. If the 'failfast' attribute of the DASD is set to 1,
+ * verify that this setting is intentional and change it to 0 if required.
+ */
+
+/*?
+ * Text: "%s Setting the DASD online failed because the required module %s could not be loaded (rc=%d)\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: kernel module name
+ *   @3: return code
+ * Description:
+ * The DASD was to be set online with discipline DIAG but this discipline of
+ * the DASD device driver is not available and an attempt to load the
+ * corresponding kernel module failed with the specified return code.
+ *
+ * User action:
+ * Ensure that the kernel module with the specified name is correctly installed
+ * or set the sysfs 'use_diag' attribute of the DASD to 0 to switch off DIAG.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/dasd-eckd
+++ linux-ein-5.4.0/Documentation/kmsg/s390/dasd-eckd
@@ -0,0 +1,2154 @@
+/* dasd_eckd */
+
+/*?
+ * Text: "%s: ERP failed for the DASD\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An error recovery procedure (ERP) was performed for the DASD but failed.
+ * User action:
+ * Check the message log for previous related error messages.
+ */
+
+/*?
+ * Text: "%s: An error occurred in the DASD device driver, reason=%s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: reason code
+ * Description:
+ * This problem indicates a program error in the DASD device driver.
+ * User action:
+ * Note the reason code and contact your support organization.
+*/
+
+/*?
+ * Text: "%s: Allocating memory for private DASD data failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD device driver maintains data structures for each DASD it manages.
+ * There is not enough memory to allocate these data structures for one or
+ * more DASD.
+ * User action:
+ * Free some memory and try the operation again.
+ */
+
+/*?
+ * Text: "%s: DASD with %d KB/block, %d KB total size, %d KB/track, %s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: block size
+ *   @3: DASD size
+ *   @4: track size
+ *   @5: disc layout
+ * Description:
+ * A DASD with the shown characteristics has been set online.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: Start track number %u used in formatting is too big\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: track number
+ * Description:
+ * The DASD format I/O control was used incorrectly by a formatting tool.
+ * User action:
+ * Contact the owner of the formatting tool.
+ */
+
+/*?
+ * Text: "%s: Stop track number %u used in formatting is too big\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: track number
+ * Description:
+ * The DASD format I/O control was used incorrectly by a formatting tool.
+ * User action:
+ * Contact the owner of the formatting tool.
+ */
+
+/*?
+ * Text: "%s: The DASD is not formatted\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A DASD has been set online but it has not been formatted yet. You must
+ * format the DASD before you can use it.
+ * User action:
+ * Format the DASD, for example, with dasdfmt.
+ */
+
+/*?
+ * Text: "%s: 0x%x is not a known command\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: command
+ * Description:
+ * This problem is likely to be caused by a programming error.
+ * User action:
+ * Contact your support organization.
+ */
+
+/*?
+ * Text: "%s: Track 0 has no records following the VTOC\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * Linux has identified a volume table of contents (VTOC) on the DASD but
+ * cannot read any data records following the VTOC. A possible cause of this
+ * problem is that the DASD has been used with another System z operating
+ * system.
+ * User action:
+ * Format the DASD for usage with Linux, for example, with dasdfmt.
+ * ATTENTION: Formatting irreversibly destroys all data on the DASD.
+ */
+
+/*?
+ * Text: "%s: An I/O control call used incorrect flags 0x%x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: flags
+ * Description:
+ * The DASD format I/O control was used incorrectly.
+ * User action:
+ * Contact the owner of the formatting tool.
+ */
+
+/*?
+ * Text: "%s: New DASD %04X/%02X (CU %04X/%02X) with %d cylinders, %d heads, %d sectors%s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: device type
+ *   @3: device model
+ *   @4: control unit type
+ *   @5: control unit model
+ *   @6: number of cylinders
+ *   @7: tracks per cylinder
+ *   @8: sectors per track
+ *   @9: access mode
+ * Description:
+ * A DASD with the shown characteristics has been set online.
+ * If the DASD is configured as read-only to the real or virtual hardware,
+ * the message includes an indication of this hardware access mode. The
+ * hardware access mode is independent from the 'readonly' attribute of
+ * the device in sysfs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The disk layout of the DASD is not supported\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD device driver only supports the following disk layouts: CDL, LDL,
+ * FBA, CMS, and CMS RESERVED.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: Start track %u used in formatting exceeds end track\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: track number
+ * Description:
+ * The DASD format I/O control was used incorrectly by a formatting tool.
+ * User action:
+ * Contact the owner of the formatting tool.
+ */
+
+/*?
+ * Text: "%s: The DASD cache mode was set to %x (%i cylinder prestage)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: operation mode
+ *   @3: number of cylinders
+ * Description:
+ * The DASD cache mode has been changed. See the storage system documentation
+ * for information about the different cache operation modes.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The DASD cannot be formatted with block size %u\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: block size
+ * Description:
+ * The block size specified for a format instruction is not valid. The block
+ * size must be between 512 and 4096 byte and must be a power of 2.
+ * User action:
+ * Call the format command with a supported block size.
+ */
+
+/*?
+ * Text: "%s: The UID of the DASD has changed\n"
+ * Severity: Error
+ * Parameter:
+ * @1: bus ID of the DASD
+ * Description:
+ * The Unique Identifier (UID) of a DASD that is currently in use has changed.
+ * This indicates that the physical disk has been replaced.
+ * User action:
+ * None if the replacement was intentional.
+ * If the disk change is not expected, stop using the disk to prevent possible
+ * data loss.
+*/
+
+
+/* dasd_3990_erp */
+
+/*?
+ * Text: "%s: is offline or not installed - INTERVENTION REQUIRED!!\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD to be accessed is not in an accessible state. The I/O operation
+ * will wait until the device is operational again. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * Make the DASD accessible again. For details see the storage system
+ * documentation.
+ */
+
+/*?
+ * Text: "%s: The DASD cannot be reached on any path (lpum=%x/opm=%x)\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: last path used mask
+ *   @3: online path mask
+ * Description:
+ * After a path to the DASD failed, the error recovery procedure of the DASD
+ * device driver tried but failed to reconnect the DASD through an alternative
+ * path.
+ * User action:
+ * Ensure that the cabling between the storage server and the mainframe
+ * system is securely in place. Check the file systems on the DASD when it is
+ * accessible again.
+ */
+
+/*?
+ * Text: "%s: Unable to allocate DCTL-CQR\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an internal error.
+ * User action:
+ * Contact your support organization.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Invalid Parameter\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A data argument of a command is not valid. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - DPS Installation Check\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This operating system independent message is issued by the storage system
+ *  for one of the following reasons:
+ * - A 3380 Model D or E DASD does not have the Dynamic Path Selection (DPS)
+ * feature in the DASD A-unit.
+ * - The device type of an attached DASD is not supported by the firmware.
+ * - A type 3390 DASD is attached to a 3 MB channel.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 2 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Drive motor switch is off\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - CCW Count less than required\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The CCW count of a command is less than required. This is an operating
+ * system independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Channel requested ... %02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: reason code
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system. The possible reason codes indicate the following problems:
+ * 00 No Message.
+ * 01 The channel has requested unit check sense data.
+ * 02 The channel has requested retry and retry is exhausted.
+ * 03 A SA Check-2 error has occurred. This sense is presented with
+ *    Equipment Check.
+ * 04 The channel has requested retry and retry is not possible.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Status Not As Required: reason %02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: reason code
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system. There are several potential reasons for this message;
+ * byte 8 contains the reason code.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Device status 1 not valid\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Storage Path Restart\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An operation for an active channel program was queued in a Storage Control
+ * when a warm start was received by the path. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Reset Notification\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A system reset or its equivalent was received on an interface. The Unit
+ * Check that generates this sense is posted to the next channel initiated
+ * selection following the resetting event. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Invalid Command Sequence\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An incorrect sequence of commands has occurred. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Missing device address bit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Subsystem Processing Error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A firmware logic error has been detected. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Seek incomplete\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Invalid Command\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A command was issued that is not in the 2107/1750 command set.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Command Invalid on Secondary Address\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A command or order not allowed on a PPRC secondary device has been received
+ * by the secondary device. This is an operating system independent message
+ * that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Invalid Defective/Alternate Track Pointer\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A defective track has been accessed. The subsystem generates an invalid
+ * Defective/Alternate Track Pointer as a part of RAID Recovery.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Channel Returned with Incorrect retry CCW\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A command portion of the CCW returned after a command retry sequence does
+ * not match the command for which retry was signaled. This is an operating
+ * system independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Diagnostic of Special Command Violates File Mask\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A command is not allowed under the Access Authorization specified by the
+ * File Mask. This is an operating system independent message that is issued
+ * by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Head address does not compare\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Device did not respond to selection\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Device check-2 error or Set Sector is not complete\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Device Error Source\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The device has completed soft error logging. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Data Pinned for Device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * Modified data in cache or in persistent storage exists for the DASD. The
+ * data cannot be destaged to the device. This track is the first track pinned
+ * for this device. This is an operating system independent message that is
+ * issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel C\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Device Status 1 not as expected\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 0 - Device Fenced - device = %02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: sense data byte 4
+ * Description:
+ * The device shown in sense byte 4 has been fenced. This is an operating
+ * system independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Interruption cannot be reset\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Index missing\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - DASD Fast Write inhibited\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * DASD Fast Write is not allowed because of a nonvolatile storage battery
+ * check condition. This is an operating system independent message that is
+ * issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Invalid tag-in for an extended command sequence\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Key area error; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Count area error; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Track physical address did not compare\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 2 - 3990 check-2 error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Offset active cannot be reset\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - RCC 1 and RCC 2 sequences not successful\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in count address area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Data area error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel A\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in count address area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the key area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Caching status reset to default\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The storage director has assigned two new subsystem status devices and
+ * resets the status to its default value. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the data area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Device not ready\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in key area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - DASD controller failed to set or reset the long busy latch\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 1 - Cylinder address did not compare\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 3 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in data area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 2 - Support facility errors\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Key area error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - End operation with transfer count not zero\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 2 - Microcode detected error %02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: error code
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the count area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 3 - Allegiance terminated\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * Allegiance terminated because of a Reset Allegiance or an Unconditional
+ * Reserve command on another channel. This is an operating system independent
+ * message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Home address area error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Count area error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Invalid tag-in during selection sequence\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in data area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in home address area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Home address area error; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - Data area error; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in home address area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the home address area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the home address area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the count area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 4 - No sync byte in key area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Invalid DCC selection response or timeout\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the data area\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Operation Terminated\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The storage system ends an operation related to an active channel program
+ * when termination and redrive are required and logging is not desired.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel B\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 5 - Data Check in the key area; offset active\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Volume is suspended duplex\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The duplex pair volume has entered the suspended duplex state because of a
+ * failure. This is an operating system independent message that is issued by
+ * the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel D\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - RCC 1 sequence not successful\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel E\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - 3990 microcode time out when stopping selection\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel F\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - RCC initiated by a connection check alert\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel G\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - extra RCC required\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 6 - Overrun on channel H\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - Unexpected end operation response code\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Permanent path error (DASD controller not available)\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Missing end operation; device transfer incomplete\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Cache or nonvolatile storage equipment failure\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An equipment failure has occurred in the cache storage or nonvolatile
+ * storage of the storage system. This is an operating system independent
+ * message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - DPS cannot be filled\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - Error correction code hardware fault\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Missing end operation; device transfer complete\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - DASD controller not available on disconnected command chain\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - No interruption from device during a command chain\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - No response to selection after a poll interruption\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 9 - Track physical address did not compare while oriented\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 9 - Head address did not compare\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Invalid tag-in for an immediate command sequence\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 9 - Cylinder address did not compare\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - DPS checks after a system reset or selective reset\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Caching reinitiated\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * Caching has been automatically reinitiated following an error.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - End operation with transfer count zero\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 7 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 9 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - Short busy time-out during device selection\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Caching terminated\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The storage system was unable to initiate caching or had to suspend caching
+ * for a 3990 control unit. If this problem is caused by a failure condition,
+ * an additional message will provide more information about the failure.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * Check for additional messages that point out possible failures. For more
+ * information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Subsystem status cannot be determined\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The status of a DASD Fast Write or PPRC volume cannot be determined.
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Nonvolatile storage terminated\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The storage director has stopped using nonvolatile storage or cannot
+ * initiate nonvolatile storage. If this problem is caused by a failure, an
+ * additional message will provide more information about the failure. This is
+ * an operating system independent message that is issued by the storage system.
+ * User action:
+ * Check for additional messages that point out possible failures. For more
+ * information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT 8 - Reserved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: Write inhibited path encountered\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an informational message.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: FORMAT 9 - Device check-2 error\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This is an operating system independent message that is issued by the
+ * storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Track format incorrect\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A track format error occurred while data was being written to the DASD or
+ * while a duplex pair was being established. This is an operating system
+ * independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: FORMAT F - Cache fast write access not authorized\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A request for Cache Fast Write Data access cannot be satisfied because
+ * of missing access authorization for the storage system. This is an operating
+ * system independent message that is issued by the storage system.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: Data recovered during retry with PCI fetch mode active\n"
+ * Severity: Emerg
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * A data error has been recovered on the storages system but the Linux file
+ * system cannot be informed about the data mismatch. To prevent Linux from
+ * running with incorrect data, the DASD device driver will trigger a kernel
+ * panic.
+ * User action:
+ * Reset your real or virtual hardware and reboot Linux.
+ */
+
+/*?
+ * Text: "%s: The specified record was not found\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The record to be accessed does not exist. The DASD might be unformatted
+ * or defect.
+ * User action:
+ * Try to format the DASD or replace it.
+ * ATTENTION: Formatting irreversibly destroys all data on the DASD.
+ */
+
+/*?
+ * Text: "%s: ERP %p (%02x) refers to %p\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: pointer to ERP
+ *   @3: ERP status
+ *   @4: cqr
+ * Description:
+ * This message provides debug information for the enhanced error recovery
+ * procedure (ERP).
+ * User action:
+ * If you do not need this information, you can suppress this message by
+ * switching off ERP logging, for example, by writing '1' to the 'erplog'
+ * sysfs attribute of the DASD.
+ */
+
+/*?
+ * Text: "%s: ERP chain at END of ERP-ACTION\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This message provides debug information for the enhanced error recovery
+ * procedure (ERP).
+ * User action:
+ * If you do not need this information, you can suppress this message by
+ * switching off ERP logging, for example, by writing '1' to the 'erplog'
+ * sysfs attribute of the DASD.
+ */
+
+/*?
+ * Text: "%s: The cylinder data for accessing the DASD is inconsistent\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An error occurred in the storage system hardware.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: Accessing the DASD failed because of a hardware error\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An error occurred in the storage system hardware.
+ * User action:
+ * For more information see the documentation of your storage system.
+ */
+
+/*?
+ * Text: "%s: ERP chain at BEGINNING of ERP-ACTION\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This message provides debug information for the enhanced error recovery
+ * procedure (ERP).
+ * User action:
+ * If you do not need this information, you can suppress this message by
+ * switching off ERP logging, for example, by writing '1' to the 'erplog'
+ * sysfs attribute of the DASD.
+ */
+
+/*?
+ * Text: "%s: ERP %p has run out of retries and failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: ERP pointer
+ * Description:
+ * The error recovery procedure (ERP) tried to recover an error but the number
+ * of retries for the I/O was exceeded before the error could be resolved.
+ * User action:
+ * Check for related previous error messages.
+ */
+
+/*?
+ * Text: "%s: SIM - SRC: %02x%02x%02x%02x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: sense byte
+ *   @3: sense byte
+ *   @4: sense byte
+ *   @5: sense byte
+ * Description:
+ * This error message is a System Information Message (SIM) generated by the
+ * storage system. The System Reference Code (SRC) defines the error in detail.
+ * User action:
+ * Look up the SRC in the storage server documentation.
+ */
+
+/*?
+ * Text: "%s: log SIM - SRC: %02x%02x%02x%02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: sense byte
+ *   @3: sense byte
+ *   @4: sense byte
+ *   @5: sense byte
+ * Description:
+ * This System Information Message (SIM) is generated by the storage system.
+ * The System Reference Code (SRC) defines the error in detail.
+ * User action:
+ * Look up the SRC in the storage server documentation.
+ */
+
+/*?
+ * Text: "%s: Reading device feature codes failed with rc=%d\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ * Description:
+ * The device feature codes state which advanced features are supported by a
+ * device.
+ * Examples for advanced features are PAV or high performance FICON.
+ * Some early devices do not provide feature codes and no advanced features are
+ * available on these devices.
+ * User action:
+ * None, if the DASD does not provide feature codes. If the DASD provides
+ * feature codes, make sure that it is working correctly, then set it offline
+ * and back online.
+ */
+
+/*?
+ * Text: "%s: A channel path group could not be established\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * Initialization of a DASD did not complete because a channel path group
+ * could not be established.
+ * User action:
+ * Make sure that the DASD is working correctly, then try again to set it
+ * online. If initialization still fails, reboot.
+ */
+
+/*?
+ * Text: "%s: The DASD is not operating in multipath mode\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD channel path group could not be configured to use multipath mode.
+ * This might negatively affect I/O performance on this DASD.
+ * User action:
+ * Make sure that the DASD is working correctly, then try again to set it
+ * online. If initialization still fails, reboot.
+ */
+
+/*?
+ * Text: "%s: Detecting the DASD disk layout failed because of an I/O error\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The disk layout of the DASD could not be detected because of an unexpected
+ * I/O error. The DASD device driver treats the device like an unformatted DASD,
+ * and partitions on the device are not accessible.
+ * User action:
+ * If the DASD is formatted, make sure that the DASD is working correctly,
+ * then set it offline and back online. If the DASD is unformatted, format the
+ * DASD, for example, with dasdfmt.
+ * ATTENTION: Formatting irreversibly destroys all data on the DASD.
+ */
+
+/*?
+ * Text: "%s: An I/O request was rejected because writing is inhibited\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * An I/O request was returned with an error indication of 'command reject'
+ * and 'write inhibited'. The most likely reason for this error is a
+ * failed write request to a device that was attached as read-only in z/VM.
+ * User action:
+ * Set the device offline, ensure that the device is configured correctly in
+ * z/VM, then set the device online again.
+ */
+
+/*?
+ * Text: "%s: An Alias device was reassigned to a new base device with UID: %s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the alias
+ *   @2: UID of new base device
+ * Description:
+ * The alias device with the indicated bus ID has been reassigned. The UID of the new base device is shown in the message.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: Detecting the maximum supported data size for zHPF requests failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * High Performance FICON (zHPF) requests are limited to a hardware-dependent
+ * maximum data size. The DASD device driver failed to detect this size and zHPF
+ * is not available for this device.
+ * User action:
+ * Set the device offline and online again. If this problem persists, gather
+ * Linux debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Reading device feature codes failed (rc=%d) for new path %x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ *   @3: path mask
+ * Description:
+ * A new path has been made available to the a device.
+ * A command to read the device feature codes on this device returned an error.
+ * The new path will not be used for I/O.
+ * User action:
+ * Set the new path offline and online again to repeat the path verification.
+ * Alternatively, set the device offline and online again to
+ * verify all available paths for this device.
+ * If this problem persists, gather Linux debug data and report the problem
+ * to your support organization.
+ */
+
+/*?
+ * Text: "%s: Detecting the maximum data size for zHPF requests failed (rc=%d) for a new path %x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: return code
+ *   @3: path mask
+ * Description:
+ * High Performance FICON (zHPF) requests are limited to a hardware-dependent
+ * maximum data size. A command to detect this size for
+ * a new path returned an error. The new path will not be used for I/O.
+ * User action:
+ * Set the new path offline and online again to repeat the path verification.
+ * Alternatively, set the device offline and online again to
+ * verify all available paths for this device.
+ * If this problem persists, gather Linux debug data and report the problem
+ * to your support organization.
+ */
+
+/*?
+ * Text: "%s: The maximum data size for zHPF requests %u on a new path %x is below the active maximum %u\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: size in bytes
+ *   @3: path mask
+ *   @4: size in bytes
+ * Description:
+ * High Performance FICON (zHPF) requests are limited to a hardware-dependent
+ * maximum data size. The maximum of the new path is below
+ * the previously established common maximum for the
+ * existing paths for this device. This could cause requests on the new
+ * path to fail. The new path will not be used for I/O.
+ * User action:
+ * Set the device offline and online again to establish a new common maximum
+ * data size for the device.
+ */
+
+/*?
+ * Text: "%s: The device reservation was lost\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * This Linux instance has lost its reservation of the device to another
+ * operating system instance. Depending on the reservation policy for the
+ * device, I/O might be blocked until the other operating system instance
+ * surrenders the reservation or all I/O requests might fail until the
+ * device is reset.
+ * User action:
+ * None, if this situation is handled by system automation software.
+ * If this situation is not handled by automation, check the
+ * last_known_reservation_state attribute of the device in sysfs.
+ * If the value is 'lost', verify that the device is no longer reserved
+ * by another operating system instance, then set the device offline and
+ * online again. For any other value of the last_known_reservation_state
+ * no action is required. I/O will resume when the device reservation is
+ * surrendered by the other operating system instance.
+ */
+
+/*?
+ * Text: "%s: The storage server does not support raw-track access\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD cannot be accessed in raw-track access mode because the storage
+ * server does not have all required features for this access mode.
+ * In raw-track access mode, the DASD device driver accesses complete ECKD
+ * tracks.
+ * By default, the DASD device driver accesses only the data fields of ECKD
+ * devices and omits the count and key data fields.
+ * User action:
+ * Ensure that the raw_track_access sysfs attribute of the DASD has the value
+ * 0 to access the device in default ECKD mode.
+ */
+
+/*?
+ * Text: "%s: The newly added channel path %02X will not be used because it leads to a different device %s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: logical path mask
+ *   @3: UID
+ * Description:
+ * The newly added channel path has a different UID than the DASD device. This indicates
+ * an incorrect cabling. This path is not going to be used.
+ * User action:
+ * Check the cabling of the DASD device. Disconnect and reconnect the cable.
+ */
+
+/*?
+ * Text: "%s: Not all channel paths lead to the same device, path %02X leads to device %s instead of %s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: logical path mask
+ *   @3: UID
+ *   @4: UID
+ * Description:
+ * Some channel paths have a different UID than others. This indicates
+ * an incorrect cabling. The DASD device is not enabled.
+ * User action:
+ * Check cabling of the DASD device and retry to enable the device.
+ */
+
+/*?
+ * Text: "Service on the storage server caused path %x.%02x to go offline"
+ * Severity: Warning
+ * Parameter:
+ *   @1: channel subsystem ID
+ *   @2: CHPID
+ * Description:
+ * A channel path to the DASD has been set offline because of
+ * a service action on the storage server. The path will be set back
+ * online automatically when the service action is completed.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Path %x.%02x is back online after service on the storage server"
+ * Severity: Informational
+ * Parameter:
+ *   @1: channel subsystem ID
+ *   @2: CHPID
+ * Description:
+ * A path had been set offline temporarily because of a service
+ * action on the storage server.
+ * The service action has completed, and the channel path is available
+ * again.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: High Performance FICON disabled\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * High Performance FICON (HPF) has been disabled. Either the device
+ * lost HPF functionality, or none of the remaining channel paths are
+ * HPF capable.
+ * User action:
+ * Report the problem to your support organization.
+ * Ensure that the cabling between the storage server and the mainframe
+ * system is securely in place.
+ * Reset the device and channel paths by writing "all" or a logical path mask
+ * to the path_reset sysfs attribute of the device.
+ */
+
+/*?
+ * Text: "%s: Channel path %02X lost HPF functionality and is disabled\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: logical path mask
+ * Description:
+ * A channel path has lost High Performance FICON (HPF) functionality
+ * and was removed from regular operations.
+ * User action:
+ * Report the problem to your support organization.
+ * Ensure that the cabling between the storage server and the mainframe
+ * system is securely in place.
+ * Reset the device and channel paths by writing "all" or a logical path mask
+ * to the path_reset sysfs attribute of the device.
+ */
+
+/*?
+ * Text: "%s: Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: cssid
+ *   @3: chpid
+ *   @4: logical path mask
+ * Description:
+ * Due to numerous interface or channel control checks (IFCCs), a channel path
+ * was removed from regular operations to retain good I/O performance.
+ * User action:
+ * Ensure that the cabling between the storage server and the mainframe
+ * system is securely in place.
+ * Reset the device and channel paths by writing "all" or a logical path mask
+ * to the path_reset sysfs attribute of the device.
+ * If the problem persists, report it to your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/dasd-fba
+++ linux-ein-5.4.0/Documentation/kmsg/s390/dasd-fba
@@ -0,0 +1,36 @@
+
+/*?
+ * Text: "%s: New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB and %d B/blk%s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the DASD
+ *   @2: device type
+ *   @3: device model
+ *   @4: control unit type
+ *   @5: control unit model
+ *   @6: size
+ *   @7: bytes per block
+ *   @8: access mode
+ * Description:
+ * A DASD with the shown characteristics has been set online.
+ * If the DASD is configured as read-only to the real or virtual hardware,
+ * the message includes an indication of this hardware access mode. The
+ * hardware access mode is independent from the 'readonly' attribute of
+ * the device in sysfs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: Allocating memory for private DASD data failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the DASD
+ * Description:
+ * The DASD device driver maintains data structures for each DASD it manages.
+ * There is not enough memory to allocate these data structures for one or
+ * more DASD.
+ * User action:
+ * Free some memory and try the operation again.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/dcssblk
+++ linux-ein-5.4.0/Documentation/kmsg/s390/dcssblk
@@ -0,0 +1,206 @@
+/*?
+ * Text: "Adjacent DCSSs %s and %s are not contiguous\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: name 1
+ *   @2: name 2
+ * Description:
+ * You can only map a set of two or more DCSSs to a single DCSS device if the
+ * DCSSs in the set form a contiguous memory space. The DCSS device cannot be
+ * created because there is a memory gap between two adjacent DCSSs.
+ * User action:
+ * Ensure that you have specified all DCSSs that belong to the set. Check the
+ * definitions of the DCSSs on the z/VM hypervisor to verify that they form
+ * a contiguous memory space.
+ */
+
+/*?
+ * Text: "DCSS %s and DCSS %s have incompatible types\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: name 1
+ *   @2: name 2
+ * Description:
+ * You can only map a set of two or more DCSSs to a single DCSS device if
+ * either all DCSSs in the set have the same type or if the set contains DCSSs
+ * of the two types EW and EN but no other type. The DCSS device cannot be
+ * created because at least two of the specified DCSSs are not compatible.
+ * User action:
+ * Check the definitions of the DCSSs on the z/VM hypervisor to verify that
+ * their types are compatible.
+ */
+
+/*?
+ * Text: "DCSS %s is of type SC and cannot be loaded as exclusive-writable\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * You cannot load a DCSS device in exclusive-writable access mode if the DCSS
+ * devise maps to one or more DCSSs of type SC.
+ * User action:
+ * Load the DCSS in shared access mode.
+ */
+
+/*?
+ * Text: "DCSS device %s is removed after a failed access mode change\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * To change the access mode of a DCSS device, all DCSSs that map to the device
+ * were unloaded. Reloading the DCSSs for the new access mode failed and the
+ * device is removed.
+ * User action:
+ * Look for related messages to find out why the DCSSs could not be reloaded.
+ * If necessary, add the device again.
+ */
+
+/*?
+ * Text: "All DCSSs that map to device %s are saved\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * A save request has been submitted for the DCSS device. Changes to all DCSSs
+ * that map to the device are saved permanently.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Device %s is in use, its DCSSs will be saved when it becomes idle\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * A save request for the device has been deferred until the device becomes
+ * idle. Then changes to all DCSSs that the device maps to will be saved
+ * permanently.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "A pending save request for device %s has been canceled\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * A save request for the DCSSs that map to a DCSS device has been pending
+ * while the device was in use. This save request has been canceled. Changes to
+ * the DCSSs will not be saved permanently.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Loaded %s with total size %lu bytes and capacity %lu sectors\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: DCSS names
+ *   @2: total size in bytes
+ *   @3: total size in 512 byte sectors
+ * Description:
+ * The listed DCSSs have been verified as contiguous and successfully loaded.
+ * The displayed sizes are the sums of all DCSSs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Device %s cannot be removed because it is not a known device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * The DCSS device you are trying to remove is not known to the DCSS device
+ * driver.
+ * User action:
+ * List the entries under /sys/devices/dcssblk/ to see the names of the
+ * existing DCSS devices.
+ */
+
+/*?
+ * Text: "Device %s cannot be removed while it is in use\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * You are trying to remove a device that is in use.
+ * User action:
+ * Make sure that all users of the device close the device before you try to
+ * remove it.
+ */
+
+/*?
+ * Text: "Device %s has become idle and is being saved now\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * A save request for the DCSSs that map to a DCSS device has been pending
+ * while the device was in use. The device has become idle and all changes
+ * to the DCSSs are now saved permanently.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Writing to %s failed because it is a read-only device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * The DCSS device is in shared access mode and cannot be written to. Depending
+ * on the type of the DCSSs that the device maps to, you might be able to
+ * change the access mode to exclusive-writable.
+ * User action:
+ * If the DCSSs of the device are of type SC, do not attempt to write to the
+ * device. If the DCSSs of the device are of type ER or SR, change the access
+ * mode to exclusive-writable before writing to the device.
+ */
+
+/*?
+ * Text: "The address range of DCSS %s changed while the system was suspended\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * After resuming the system, the start address or end address of a DCSS does
+ * not match the address when the system was suspended. DCSSs must not be
+ * changed after the system was suspended.
+ * This error cannot be recovered. The system is stopped with a kernel panic.
+ * User action:
+ * Reboot Linux.
+ */
+
+/*?
+ * Text: "Suspending the system failed because DCSS device %s is writable\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * A system cannot be suspended if one or more DCSSs are accessed in exclusive-
+ * writable mode. DCSS segment types EW, SW, and EN are always writable and
+ * must be removed before a system is suspended.
+ * User action:
+ * Remove all DCSSs of segment types EW, SW, and EN by writing the DCSS name to
+ * the sysfs 'remove' attribute. Set the access mode for all DCSSs of segment
+ * types SR and ER to read-only by writing 1 to the sysfs 'shared' attribute of
+ * the DCSS. Then try again to suspend the system.
+ */
+
+/*?
+ * Text: "DCSS %s is of type SN or EN and cannot be saved\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * DCSSs of type SN or EN cannot be saved.
+ * User action:
+ * If the DCSS was set up with the intention to prevent the content from being saved,
+ * no action is necessary.
+ * To be able to save the content, you must define the DCSS with a type other than SN or EN.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/diag288_wdt
+++ linux-ein-5.4.0/Documentation/kmsg/s390/diag288_wdt
@@ -0,0 +1,66 @@
+/*?
+ * Text: "The watchdog cannot be activated\n"
+ * Severity: Error
+ * Description:
+ * Diagnose instruction 0x288 was called to activate the diag288 watchdog.
+ * The diagnose call returned an error that cannot be handled by the device driver.
+ * The watchdog stays inactive.
+ * User action:
+ * Contact your support organization.
+ */
+
+/*?
+ * Text: "The watchdog cannot be initialized\n"
+ * Severity: Error
+ * Description:
+ * Diagnose instruction 0x288 was called to initialize the diag288 watchdog.
+ * The diagnose call returned an error that cannot be handled by the device driver.
+ * The watchdog stays inactive.
+ * A possible reason for this error is that your real or virtual hardware does not support
+ * the diag288 watchdog.
+ * User action:
+ * Confirm that the diag288 watchdog is supported in your environment.
+ * Use a watchdog that is supported in your environment.
+ */
+
+/*?
+ * Text: "The watchdog cannot be deactivated\n"
+ * Severity: Error
+ * Description:
+ * Diagnose instruction 0x288 was called to deactivate the diag288 watchdog.
+ * The diagnose call returned an error that cannot be handled by the device driver.
+ * The watchdog stays active and a watchdog timeout will trigger the configured timeout action.
+ * The diag288 watchdog device driver might intentionally be configured to prevent deactivation.
+ * User action:
+ * You can configure the diag288 watchdog device driver such that it can be deactivated.
+ * If the diag288 device driver has been compiled as a separate module, diag288_wdt, reload the module
+ * without specifying the 'nowayout' module parameter.
+ * If the diag288 device driver has been compiled into your kernel,
+ * reboot Linux without specifying the 'diag288.nowayout' kernel parameter'.
+ */
+
+/*?
+ * Text: "The watchdog timer cannot be started or reset\n"
+ * Severity: Error
+ * Description:
+ * Diagnose instruction 0x288 was called to start the diag288 watchdog or to set timer back to zero.
+ * The diagnose call returned an error that cannot be handled by the device driver.
+ * The watchdog stays inactive or becomes inactive.
+ * User action:
+ * Contact your support organization.
+ */
+
+/*?
+ * Text: "Linux cannot be suspended while the watchdog is in use\n"
+ * Severity: Error
+ * Description:
+ * The watchdog must not time out while Linux is suspended.
+ * Therefore, the diag288 watchdog device driver prevents Linux from being suspended
+ * while the watchdog is in use.
+ * User action:
+ * i) Stop the watchdog application. ii) If the problem persists, close the watchdog
+ * device node by issuing 'echo V > /dev/watchdog'.
+ * iii) If the device driver still prevents Linux from being suspended,
+ * contact your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/extmem
+++ linux-ein-5.4.0/Documentation/kmsg/s390/extmem
@@ -0,0 +1,293 @@
+/*?
+ * Text: "Querying a DCSS type failed with rc=%ld\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * The DCSS kernel interface used z/VM diagnose call X'64' to query the
+ * type of a DCSS. z/VM failed to determine the type and returned an error.
+ * User action:
+ * Look for related messages to find out which DCSS is affected.
+ * For details about the return codes see the section about DIAGNOSE Code
+ * X'64' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Loading DCSS %s failed with rc=%ld\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DCSS name
+ *   @2: return code
+ * Description:
+ * The DCSS kernel interface used diagnose call X'64' to load a DCSS. z/VM
+ * failed to load the DCSS and returned an error.
+ * User action:
+ * For details about the return codes see the section about DIAGNOSE Code
+ * X'64' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "DCSS %s of range %p to %p and type %s loaded as exclusive-writable\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: DCSS name
+ *   @2: starting page address
+ *   @3: ending page address
+ *   @4: DCSS type
+ * Description:
+ * The DCSS was loaded successfully in exclusive-writable access mode.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "DCSS %s of range %p to %p and type %s loaded in shared access mode\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: DCSS name
+ *   @2: starting page address
+ *   @3: ending page address
+ *   @4: DCSS type
+ * Description:
+ * The DCSS was loaded successfully in shared access mode.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "DCSS %s is already in the requested access mode\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * A request to reload a DCSS with a new access mode has been rejected
+ * because the new access mode is the same as the current access mode.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "DCSS %s is in use and cannot be reloaded\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * Reloading a DCSS in a different access mode has failed because the DCSS is
+ * being used by one or more device drivers. The DCSS remains loaded with the
+ * current access mode.
+ * User action:
+ * Ensure that the DCSS is not used by any device driver then try again to
+ * load the DCSS with the new access mode.
+ */
+
+/*?
+ * Text: "DCSS %s overlaps with used memory resources and cannot be reloaded\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The DCSS has been unloaded and cannot be reloaded because it overlaps with
+ * another loaded DCSS or with the memory of the z/VM guest virtual machine
+ * (guest storage).
+ * User action:
+ * Ensure that no DCSS is loaded that has overlapping memory resources
+ * with the DCSS you want to reload. If the DCSS overlaps with guest storage,
+ * use the DEF STORE CONFIG z/VM CP command to create a sufficient storage gap
+ * for the DCSS. For details, see the section about the DCSS device driver in
+ * "Device Drivers, Features, and Commands".
+ */
+
+/*?
+ * Text: "Reloading DCSS %s failed with rc=%ld\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: DCSS name
+ *   @2: return code
+ * Description:
+ * The DCSS kernel interface used z/VM diagnose call X'64' to reload a DCSS
+ * in a different access mode. The DCSS was unloaded but z/VM failed to reload
+ * the DCSS.
+ * User action:
+ * For details about the return codes see the section about DIAGNOSE Code
+ * X'64' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "Unloading unknown DCSS %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The specified DCSS cannot be unloaded. The DCSS is known to the DCSS device
+ * driver but not to the DCSS kernel interface. This problem indicates a
+ * program error in extmem.c.
+ * User action:
+ * Report this problem to your support organization.
+ */
+
+/*?
+ * Text: "Saving unknown DCSS %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The specified DCSS cannot be saved. The DCSS is known to the DCSS device
+ * driver but not to the DCSS kernel interface. This problem indicates a
+ * program error in extmem.c.
+ * User action:
+ * Report this problem to your support organization.
+ */
+
+/*?
+ * Text: "Saving a DCSS failed with DEFSEG response code %i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: response-code
+ * Description:
+ * The DEFSEG z/VM CP command failed to permanently save changes to a DCSS.
+ * User action:
+ * Ensure that the z/VM guest virtual machine is authorized to issue
+ * the CP DEFSEG command (typically privilege class E).
+ * Look for related messages to find the cause of this error. See also message
+ * HCP<response-code>E in the DEFSEG section of the "z/VM CP Command and
+ * Utility Reference".
+ */
+
+/*?
+ * Text: "Saving a DCSS failed with SAVESEG response code %i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: response-code
+ * Description:
+ * The SAVESEG z/VM CP command failed to permanently save changes to a DCSS.
+ * User action:
+ * Ensure that the z/VM guest virtual machine is authorized to issue
+ * the CP SAVESEG command (typically privilege class E).
+ * Look for related messages to find the cause of this error. See also message
+ * HCP<response-code>E in the SAVESEG section of the "z/VM CP Command and
+ * Utility Reference".
+ */
+
+/*?
+ * Text: "DCSS %s cannot be loaded or queried\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * You cannot load or query the specified DCSS because it either is not defined
+ * in the z/VM hypervisor, or it is a class S DCSS, or it is above 2047 MB
+ * and the Linux system is a 31-bit system.
+ * User action:
+ * Use the CP command "QUERY NSS" to find out if the DCSS is a valid
+ * DCSS that can be loaded.
+ */
+
+/*?
+ * Text: "DCSS %s cannot be loaded or queried without z/VM\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * A DCSS is a z/VM resource. Your Linux instance is not running as a z/VM
+ * guest operating system and, therefore, cannot load DCSSs.
+ * User action:
+ * Load DCSSs only on Linux instances that run as z/VM guest operating systems.
+ */
+
+/*?
+ * Text: "Loading or querying DCSS %s resulted in a hardware error\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * Either the z/VM DIAGNOSE X'64' query or load call issued for the DCSS
+ * returned with an error.
+ * User action:
+ * Look for previous extmem message to find the return code from the
+ * DIAGNOSE X'64' query or load call. For details about the return codes see
+ * the section about DIAGNOSE Code X'64' in "z/VM CP Programming Services".
+ */
+
+/*?
+ * Text: "DCSS %s has multiple page ranges and cannot be loaded or queried\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * You can only load or query a DCSS with multiple page ranges if:
+ * - The DCSS has 6 or fewer page ranges
+ * - The page ranges form a contiguous address space
+ * - The page ranges are of type EW or EN
+ * User action:
+ * Check the definition of the DCSS to make sure that the conditions for
+ * DCSSs with multiple page ranges are met.
+ */
+
+/*?
+ * Text: "%s needs used memory resources and cannot be loaded or queried\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * You cannot load or query the DCSS because it overlaps with an already
+ * loaded DCSS or with the memory of the z/VM guest virtual machine
+ * (guest storage).
+ * User action:
+ * Ensure that no DCSS is loaded that has overlapping memory resources
+ * with the DCSS you want to load or query. If the DCSS overlaps with guest
+ * storage, use the DEF STORE CONFIG z/VM CP command to create a sufficient
+ * storage gap for the DCSS. For details, see the section about the DCSS
+ * device driver in "Device Drivers, Features, and Commands".
+ */
+
+/*?
+ * Text: "DCSS %s is already loaded in a different access mode\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The DCSS you are trying to load has already been loaded in a different
+ * access mode. You cannot simultaneously load the DCSS in different modes.
+ * User action:
+ * Reload the DCSS in a different mode or load it with the same mode in which
+ * it has already been loaded.
+ */
+
+/*?
+ * Text: "There is not enough memory to load or query DCSS %s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The available memory is not enough to load or query the DCSS.
+ * User action:
+ * Free some memory and repeat the failed operation.
+ */
+
+/*?
+ * Text: "DCSS %s overlaps with used storage and cannot be loaded\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * You cannot load the DCSS because it overlaps with an already loaded DCSS
+ * or with the memory of the z/VM guest virtual machine (guest storage).
+ * User action:
+ * Ensure that no DCSS is loaded that has overlapping memory resources
+ * with the DCSS you want to load. If the DCSS overlaps with guest storage,
+ * use the DEF STORE CONFIG z/VM CP command to create a sufficient storage gap
+ * for the DCSS. For details, see the section about the DCSS device driver in
+ * "Device Drivers, Features, and Commands".
+ */
+
+/*?
+ * Text: "DCSS %s exceeds the kernel mapping range (%lu) and cannot be loaded\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ *   @2: kernel mapping range in bytes
+ * Description:
+ * You cannot load the DCSS because it exceeds the kernel mapping range limit.
+ * User action:
+ * Ensure that the DCSS range is defined below the kernel mapping range.
+ */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/hmcdrv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/hmcdrv
@@ -0,0 +1,22 @@
+/*?
+ * Text: "Allocating the requested cache size of %zu bytes failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: size
+ * Description:
+ * You cannot use the 'hmcdrv' module.
+ * Either the cache size that was specified for the 'hmcdrv' module exceeded
+ * the maximum of 1048576 (1 megabyte), or not enough free memory was
+ * available.
+ * If the 'hmcdrv' module was compiled into the kernel, the cache size was
+ * specified with the 'hmcdrv.cachesize' kernel parameter.
+ * For a separate 'hmcdrv' module, the cache size was specified with the
+ * 'cachesize=' module parameter.
+ * User action:
+ * Specify a smaller cache size and try again to load the module.
+ * Do not exceed the maximum specification of 1048576 (1 megabyte).
+ * If necessary, free some memory and try again.
+ * If the module is compiled into the kernel, you must reboot Linux to change
+ * the cache size specification.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/hugetlb
+++ linux-ein-5.4.0/Documentation/kmsg/s390/hugetlb
@@ -0,0 +1,13 @@
+/*?
+ * Text: "hugepagesz= specifies an unsupported page size %s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: size
+ * Description:
+ * The hugepagesz= kernel parameter specifies a huge page size
+ * that is not supported.
+ * User action:
+ * Specify "1M" for 1 MB huge pages. These are supported as of z10.
+ * Specify "2G" for 2 GB huge pages. These are supported as of zEC12
+ * and zBC12 machines.
+ */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/hvc_iucv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/hvc_iucv
@@ -0,0 +1,123 @@
+/*?
+ * Text: "The z/VM IUCV HVC device driver cannot be used without z/VM\n"
+ * Severity: Notice
+ * Description:
+ * The z/VM IUCV hypervisor console (HVC) device driver requires the
+ * z/VM inter-user communication vehicle (IUCV).
+ * User action:
+ * Set "hvc_iucv=" to zero in the kernel parameter line and reboot Linux.
+ */
+
+/*?
+ * Text: "%lu is not a valid value for the hvc_iucv= kernel parameter\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: hvc_iucv_devices
+ * Description:
+ * The "hvc_iucv=" kernel parameter specifies the number of z/VM IUCV
+ * hypervisor console (HVC) terminal devices.
+ * The parameter value ranges from 0 to 8.
+ * If zero is specified, the z/VM IUCV HVC device driver is disabled
+ * and no IUCV-based terminal access is available.
+ * User action:
+ * Correct the "hvc_iucv=" setting in the kernel parameter line and
+ * reboot Linux.
+ */
+
+/*?
+ * Text: "Creating a new HVC terminal device failed with error code=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: errno
+ * Description:
+ * The device driver initialization failed to allocate a new
+ * HVC terminal device.
+ * A possible cause of this problem is memory constraints.
+ * User action:
+ * If the error code is -12 (ENOMEM), consider assigning more memory
+ * to your z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "Registering HVC terminal device as Linux console failed\n"
+ * Severity: Error
+ * Description:
+ * The device driver initialization failed to set up the first HVC terminal
+ * device for use as Linux console.
+ * User action:
+ * If the error code is -12 (ENOMEM), consider assigning more memory
+ * to your z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "Registering IUCV handlers failed with error code=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: errno
+ * Description:
+ * The device driver initialization failed to register with z/VM IUCV to
+ * handle IUCV connections, as well as sending and receiving of IUCV messages.
+ * User action:
+ * Check for related IUCV error messages and see the errno manual page
+ * to find out what caused the problem.
+ */
+
+/*?
+ * Text: "Allocating memory failed with reason code=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: reason
+ * Description:
+ * The z/VM IUCV hypervisor console (HVC) device driver initialization failed,
+ * because of a general memory allocation failure. The reason code indicates
+ * the memory operation that has failed:
+ * 	kmem_cache (reason code=1),
+ * 	mempool (reason code=2), or
+ * 	hvc_iucv_allow= (reason code=3)
+ * User action:
+ * Consider assigning more memory to your z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "hvc_iucv_allow= does not specify a valid z/VM user ID list\n"
+ * Severity: Error
+ * Description:
+ * The "hvc_iucv_allow=" kernel parameter specifies a comma-separated list
+ * of z/VM user IDs that are permitted to connect to the z/VM IUCV hypervisor
+ * device driver.
+ * The z/VM user IDs in the list must not exceed eight characters and must
+ * not contain spaces.
+ * User action:
+ * Correct the "hvc_iucv_allow=" setting in the kernel parameter line and reboot
+ * Linux.
+ */
+
+/*?
+ * Text: "hvc_iucv_allow= specifies too many z/VM user IDs\n"
+ * Severity: Error
+ * Description:
+ * The "hvc_iucv_allow=" kernel parameter specifies a comma-separated list
+ * of z/VM user IDs that are permitted to connect to the z/VM IUCV hypervisor
+ * device driver.
+ * The number of z/VM user IDs that are specified with the "hvc_iucv_allow="
+ * kernel parameter exceeds the maximum of 500.
+ * User action:
+ * Correct the "hvc_iucv_allow=" setting by reducing the z/VM user IDs in
+ * the list and reboot Linux.
+ */
+
+/*?
+ * Text: "A connection request from z/VM user ID %s was refused\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: ID
+ * Description:
+ * An IUCV connection request from another z/VM guest virtual machine has been
+ * refused. The request was from a z/VM guest virtual machine that is not
+ * listed by the "hvc_iucv_allow=" kernel parameter.
+ * User action:
+ * Check the "hvc_iucv_allow=" kernel parameter setting.
+ * Consider adding the z/VM user ID to the "hvc_iucv_allow=" list in the kernel
+ * parameter line and reboot Linux.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/hypfs
+++ linux-ein-5.4.0/Documentation/kmsg/s390/hypfs
@@ -0,0 +1,56 @@
+/*?
+ * Text: "The hardware system does not support hypfs\n"
+ * Severity: Error
+ * Description:
+ * hypfs requires DIAGNOSE Code X'204' but this diagnose code is not available
+ * on your hardware. You need more recent hardware to use hypfs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The hardware system does not provide all functions required by hypfs\n"
+ * Severity: Error
+ * Description:
+ * hypfs requires DIAGNOSE Code X'224' but this diagnode code is not available
+ * on your hardware. You need more recent hardware to use hypfs.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Updating the hypfs tree failed\n"
+ * Severity: Error
+ * Description:
+ * There was not enough memory available to update the hypfs tree.
+ * User action:
+ * Free some memory and try again to update the hypfs tree. Consider assigning
+ * more memory to your LPAR or z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "%s is not a valid mount option\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: mount option
+ * Description:
+ * hypfs has detected mount options that are not valid.
+ * User action:
+ * See "Device Drivers Features and Commands" for information about valid
+ * mount options for hypfs.
+ */
+
+/*?
+ * Text: "Initialization of hypfs failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: error code
+ * Description:
+ * Initialization of hypfs failed because of resource or hardware constraints.
+ * Possible reasons for this problem are insufficient free memory or missing
+ * hardware interfaces.
+ * User action:
+ * See errno.h for information about the error codes.
+ */
+
+/*? Text: "Hypervisor filesystem mounted\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/iucv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/iucv
@@ -0,0 +1,33 @@
+/*?
+ * Text: "Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: CPU number
+ *   @2: hexadecimal error value
+ *   @3: short error code explanation
+ * Description:
+ * Defining an interrupt buffer for external interrupts failed. Error
+ * value 0x03 indicates a problem with the z/VM directory entry of the
+ * z/VM guest virtual machine. This problem can also be caused by a
+ * program error.
+ * User action:
+ * If the error value is 0x03, examine the z/VM directory entry of your
+ * z/VM guest virtual machine. If the directory entry is correct or if the
+ * error value is not 0x03, report this problem to your support organization.
+ */
+
+/*?
+ * Text: "Suspending Linux did not completely close all IUCV connections\n"
+ * Severity: Warning
+ * Description:
+ * When resuming a suspended Linux instance, the IUCV base code found
+ * data structures from one or more IUCV connections that existed before the
+ * Linux instance was suspended. Modules that use IUCV connections must close
+ * these connections when a Linux instance is suspended. This problem
+ * indicates an error in a program that used an IUCV connection.
+ * User action:
+ * Report this problem to your support organization.
+ */
+
+/*? Text: "iucv_external_interrupt: out of memory\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/lcs
+++ linux-ein-5.4.0/Documentation/kmsg/s390/lcs
@@ -0,0 +1,169 @@
+/*?
+ * Text: "%s:  Allocating a socket buffer to interface %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: network interface
+ * Description:
+ * LAN channel station (LCS) devices require a socket buffer (SKB) structure
+ * for storing incoming data. The LCS device driver failed to allocate an SKB
+ * structure to the LCS device. A likely cause of this problem is memory
+ * constraints.
+ * User action:
+ * Free some memory and repeat the failed operation.
+ */
+
+/*?
+ * Text: "%s:  Shutting down the LCS device failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ * Description:
+ * A request to shut down a LAN channel station (LCS) device resulted in an
+ * error. The error is logged in the LCS trace at trace level 4.
+ * User action:
+ * Try again to shut down the device. If the error persists, see the LCS trace
+ * to find out what causes the error.
+ */
+
+/*?
+ * Text: "%s: Detecting a network adapter for LCS devices failed with rc=%d (0x%x)\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: lcs_detect return code in decimal notation
+ *   @3: lcs_detect return code in hexadecimal notation
+ * Description:
+ * The LCS device driver could not initialize a network adapter.
+ * User action:
+ * Ensure that the physical connection from the port to the network is
+ * in place. If the error persists, note the return code from the error
+ * message and contact IBM support.
+ */
+
+/*?
+ * Text: "%s: A recovery process has been started for the LCS device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ * Description:
+ * The LAN channel station (LCS) device is shut down and restarted. The recovery
+ * process might have been initiated by a user or started automatically as a
+ * response to a device problem.
+ * User action:
+ * Wait until a message indicates the completion of the recovery process.
+ */
+
+/*?
+ * Text: "%s: An I/O-error occurred on the LCS device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ * Description:
+ * The LAN channel station (LCS) device reported a problem that can be recovered
+ * by the LCS device driver. Repeated occurrences of this problem indicate a
+ * malfunctioning device.
+ * User action:
+ * If this problem occurs frequently, initiate a recovery process for the
+ * device, for example, by writing '1' to the 'recover' sysfs attribute of the
+ * device.
+ */
+
+/*?
+ * Text: "%s: A command timed out on the LCS device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ * Description:
+ * The LAN channel station (LCS) device reported a problem that can be recovered
+ * by the LCS device driver. Repeated occurrences of this problem indicate a
+ * malfunctioning device.
+ * User action:
+ * If this problem occurs frequently, initiate a recovery process for the
+ * device, for example, by writing '1' to the 'recover' sysfs attribute of the
+ * device.
+ */
+
+/*?
+ * Text: "%s: An error occurred on the LCS device, rc=%ld\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: return code
+ * Description:
+ * The LAN channel station (LCS) device reported a problem that can be recovered
+ * by the LCS device driver. Repeated occurrences of this problem indicate a
+ * malfunctioning device.
+ * User action:
+ * If this problem occurs frequently, initiate a recovery process for the
+ * device, for example, by writing '1' to the 'recover' sysfs attribute of the
+ * device.
+ */
+
+/*?
+ * Text: "%s: The LCS device stopped because of an error, dstat=0x%X, cstat=0x%X \n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: device status
+ *   @3: subchannel status
+ * Description:
+ * The LAN channel station (LCS) device reported an error. The LCS device driver
+ * might start a device recovery process.
+ * User action:
+ * If the device driver does not start a recovery process, initiate a recovery
+ * process, for example, by writing '1' to the 'recover' sysfs attribute of the
+ * device. If the problem persists, note the status information provided with
+ * the message and contact IBM support.
+ */
+
+/*?
+ * Text: "%s: Starting an LCS device resulted in an error, rc=%d!\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: ccw_device_start return code in decimal notation
+ * Description:
+ * The LAN channel station (LCS) device driver failed to initialize an LCS
+ * device. The device is not operational.
+ * User action:
+ * Initiate a recovery process, for example, by writing '1' to the 'recover'
+ * sysfs attribute of the device. If the problem persists, contact IBM support.
+ */
+
+/*?
+ * Text: "%s: Sending data from the LCS device to the LAN failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the LCS device
+ *   @2: ccw_device_resume return code in decimal notation
+ * Description:
+ * The LAN channel station (LCS) device driver could not send data to the LAN
+ * using the LCS device. This might be a temporary problem. Operations continue
+ * on the LCS device.
+ * User action:
+ * If this problem occurs frequently, initiate a recovery process, for example,
+ * by writing '1' to the 'recover' sysfs attribute of the device. If the
+ * problem persists, contact IBM support.
+ */
+
+/*? Text: "Query IPAssist failed. Assuming unsupported!\n" */
+/*? Text: "Stoplan for %s initiated by LGW\n" */
+/*? Text: "Not enough memory to add new multicast entry!\n" */
+/*? Text: "Not enough memory for debug facility.\n" */
+/*? Text: "Adding multicast address failed. Table possibly full!\n" */
+/*? Text: "Error in opening device!\n" */
+/*? Text: "LCS device %s %s IPv6 support\n" */
+/*? Text: "Device %s successfully recovered!\n" */
+/*? Text: "LCS device %s %s Multicast support\n" */
+/*? Text: " Initialization failed\n" */
+/*? Text: "Loading %s\n" */
+/*? Text: "Initialization failed\n" */
+/*? Text: "Terminating lcs module.\n" */
+/*? Text: "Device %s could not be recovered!\n" */
+/*? Text: "Initializing the lcs device driver failed\n" */
+/*? Text: "%s: The lcs device driver failed to recover the device\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/monreader
+++ linux-ein-5.4.0/Documentation/kmsg/s390/monreader
@@ -0,0 +1,128 @@
+/*?
+ * Text: "Reading monitor data failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * The z/VM *MONITOR record device driver failed to read monitor data
+ * because the IUCV REPLY function failed. The read function against
+ * the monitor record device returns EIO. All monitor data that has been read
+ * since the last read with 0 size is incorrect.
+ * User action:
+ * Disregard all monitor data that has been read since the last read with
+ * 0 size. If the device driver has been compiled as a separate module, unload
+ * and reload the monreader module. If the device driver has been compiled
+ * into the kernel, reboot Linux. For more information about possible causes
+ * of the error see the IUCV section in "z/VM CP Programming Services" and
+ * the *MONITOR section in "z/VM Performance".
+ */
+
+/*?
+ * Text: "z/VM *MONITOR system service disconnected with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: IPUSER SEVER return code
+ * Description:
+ * The z/VM *MONITOR record device driver receives monitor records through
+ * an IUCV connection to the z/VM *MONITOR system service. This connection
+ * has been severed and the read function of the z/VM *MONITOR device driver
+ * returns EIO. All data received since the last read with 0 size is incorrect.
+ * User action:
+ * Disregard all monitor data read since the last read with 0 size. Close and
+ * reopen the monitor record device. For information about the IPUSER SEVER
+ * return codes see "z/VM Performance".
+ */
+
+/*?
+ * Text: "The read queue for monitor data is full\n"
+ * Severity: Warning
+ * Description:
+ * The read function of the z/VM *MONITOR device driver returns EOVERFLOW
+ * because not enough monitor data has been read since the monitor device
+ * has been opened. Monitor data already read are valid and subsequent reads
+ * return valid data but some intermediate data might be missing.
+ * User action:
+ * Be aware that monitor data might be missing. Assure that you regularly
+ * read monitor data after opening the monitor record device.
+ */
+
+/*?
+ * Text: "Connecting to the z/VM *MONITOR system service failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: IUCV CONNECT return code
+ * Description:
+ * The z/VM *MONITOR record device driver receives monitor records through
+ * an IUCV connection to the z/VM *MONITOR system service. This connection
+ * could not be established when the monitor record device was opened. If
+ * the return code is 15, your z/VM guest virtual machine is not authorized
+ * to connect to the *MONITOR system service.
+ * User action:
+ * If the return code is 15, ensure that the IUCV *MONITOR statement is
+ * included in the z/VM directory entry for your z/VM guest virtual machine.
+ * For other IUCV CONNECT return codes see the IUCV section in "CP Programming
+ * Services" and the *MONITOR section in "z/VM  Performance".
+ */
+
+/*?
+ * Text: "Disconnecting the z/VM *MONITOR system service failed with rc=%i\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: IUCV SEVER return code
+ * Description:
+ * The z/VM *MONITOR record device driver receives monitor data through an
+ * IUCV connection to the z/VM *MONITOR system service. This connection
+ * could not be closed when the monitor record device was closed. You might
+ * not be able to resume monitoring.
+ * User action:
+ * No immediate action is necessary. If you cannot open the monitor record
+ * device in the future, reboot Linux. For information about the IUCV SEVER
+ * return codes see the IUCV section in "CP Programming Services" and the
+ * *MONITOR section in "z/VM  Performance".
+ */
+
+/*?
+ * Text: "The z/VM *MONITOR record device driver cannot be loaded without z/VM\n"
+ * Severity: Error
+ * Description:
+ * The z/VM *MONITOR record device driver uses z/VM system services to provide
+ * monitor data about z/VM guest operating systems to applications on Linux.
+ * On Linux instances that run in environments other than the z/VM hypervisor,
+ * the z/VM *MONITOR record device driver does not provide any useful
+ * function and the corresponding monreader module cannot be loaded.
+ * User action:
+ * Load the z/VM *MONITOR record device driver only on Linux instances that run
+ * as guest operating systems of the z/VM hypervisor. If the z/VM *MONITOR
+ * record device driver has been compiled into the kernel, ignore this message.
+ */
+
+/*?
+ * Text: "The z/VM *MONITOR record device driver failed to register with IUCV\n"
+ * Severity: Error
+ * Description:
+ * The z/VM *MONITOR record device driver receives monitor data through an IUCV
+ * connection and needs to register with the IUCV device driver. This
+ * registration failed and the z/VM *MONITOR record device driver was not
+ * loaded. A possible cause of this problem is insufficient memory.
+ * User action:
+ * Free some memory and try again to load the module. If the z/VM *MONITOR
+ * record device driver has been compiled into the kernel, you might have to
+ * configure more memory and reboot Linux. If you do not want to read monitor
+ * data, ignore this message.
+ */
+
+/*?
+ * Text: "The specified *MONITOR DCSS %s does not have the required type SC\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: DCSS name
+ * Description:
+ * The DCSS that was specified with the monreader.mondcss kernel parameter or
+ * with the mondcss module parameter cannot be a *MONITOR DCSS because it is
+ * not of type SC.
+ * User action:
+ * Confirm that you are using the name of the DCSS that has been configured as
+ * the *MONITOR DCSS on the z/VM hypervisor. If the default name, MONDCSS, is
+ * used, omit the monreader.mondcss or mondcss parameter.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/monwriter
+++ linux-ein-5.4.0/Documentation/kmsg/s390/monwriter
@@ -0,0 +1,17 @@
+/*?
+ * Text: "Writing monitor data failed with rc=%i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * The monitor stream application device driver used the z/VM diagnose call
+ * DIAG X'DC' to start writing monitor data. z/VM returned an error and the
+ * monitor data cannot be written. If the return code is 5, your z/VM guest
+ * virtual machine is not authorized to write monitor data.
+ * User action:
+ * If the return code is 5, ensure that your z/VM guest virtual machine's
+ * entry in the z/VM directory includes the OPTION APPLMON statement.
+ * For other return codes see the section about DIAGNOSE Code X'DC'
+ * in "z/VM CP Programming Services".
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/netiucv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/netiucv
@@ -0,0 +1,156 @@
+/*?
+ * Text: "%s: The peer interface of the IUCV device has closed the connection\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ * Description:
+ * The peer interface on the remote z/VM guest virtual machine has closed the
+ * connection. Do not expect further packets on this interface. Any packets
+ * you send to this interface will be dropped.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The IUCV device failed to connect to z/VM guest %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: z/VM user ID
+ * Description:
+ * The connection cannot be established because the z/VM guest virtual
+ * machine with the peer interface is not running.
+ * User action:
+ * Ensure that the z/VM guest virtual machine with the peer interface is
+ * running; then try again to establish the connection.
+ */
+
+/*?
+ * Text: "%s: The IUCV device failed to connect to the peer on z/VM guest %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: z/VM user ID
+ * Description:
+ * The connection cannot be established because the z/VM guest virtual machine
+ * with the peer interface is not configured for IUCV connections.
+ * User action:
+ * Configure the z/VM guest virtual machine with the peer interface for IUCV
+ * connections; then try again to establish the connection.
+ */
+
+/*?
+ * Text: "%s: Connecting the IUCV device would exceed the maximum number of IUCV connections\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ * Description:
+ * The connection cannot be established because the maximum number of IUCV
+ * connections has been reached on the local z/VM guest virtual machine.
+ * User action:
+ * Close some of the established IUCV connections on the local z/VM guest
+ * virtual machine; then try again to establish the connection.
+ */
+
+/*?
+ * Text: "%s: z/VM guest %s has too many IUCV connections to connect with the IUCV device\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: remote z/VM user ID
+ * Description:
+ * Connecting to the remote z/VM guest virtual machine failed because the
+ * maximum number of IUCV connections for the remote z/VM guest virtual
+ * machine has been reached.
+ * User action:
+ * Close some of the established IUCV connections on the remote z/VM guest
+ * virtual machine; then try again to establish the connection.
+ */
+
+/*?
+ * Text: "%s: The IUCV device cannot connect to a z/VM guest with no IUCV authorization\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ * Description:
+ * Because the remote z/VM guest virtual machine is not authorized for IUCV
+ * connections, the connection cannot be established.
+ * User action:
+ * Add the statements 'IUCV ALLOW' and 'IUCV ANY' to the z/VM directory
+ * entry of the remote z/VM guest virtual machine; then try again to
+ * establish the connection. See "z/VM CP Planning and Administration"
+ * for details about the IUCV statements.
+ */
+
+/*?
+ * Text: "%s: Connecting the IUCV device failed with error %d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: error code
+ * Description:
+ * The connection cannot be established because of an IUCV CONNECT error.
+ * User action:
+ * Report this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The IUCV device has been connected successfully to %s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: remote z/VM user ID
+ * Description:
+ * The connection has been established and the interface is ready to
+ * transmit communication packages.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The IUCV interface to %s has been established successfully\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: remote z/VM user ID
+ * Description:
+ * The IUCV interface to the remote z/VM guest virtual machine has been
+ * established and can be activated with "ifconfig up" or an equivalent
+ * command.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The IUCV device is connected to %s and cannot be removed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: remote z/VM user ID
+ * Description:
+ * Removing a connection failed because the interface is active with a peer
+ * interface on a remote z/VM guest virtual machine.
+ * User action:
+ * Deactivate the interface with "ifconfig down" or an equivalent command;
+ * then try again to remove the interface.
+ */
+
+/*?
+ * Text: "%s: The peer z/VM guest %s has closed the connection\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the IUCV device
+ *   @2: remote z/VM user ID
+ * Description:
+ * The peer interface is no longer available.
+ * User action:
+ * Either deactivate and remove the interface, or wait for the peer
+ * z/VM guest to re-establish the interface.
+ */
+
+/*? Text: "driver unloaded\n" */
+/*? Text: "driver initialized\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/numa
+++ linux-ein-5.4.0/Documentation/kmsg/s390/numa
@@ -0,0 +1,11 @@
+/*?
+ * Text: "NUMA mode: %s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: mode
+ * Description:
+ * Linux started with the specified NUMA mode.
+ * User action:
+ * None.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/numa_emu
+++ linux-ein-5.4.0/Documentation/kmsg/s390/numa_emu
@@ -0,0 +1,50 @@
+/*?
+ * Text: "Not enough memory for %d nodes, reducing node count\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: requested number of nodes
+ * Description:
+ * Using the requested memory stripe size for emulating the requested number of
+ * NUMA nodes requires more than the available memory. The number of nodes is
+ * specified with the emu_nodes= kernel parameter. The memory stripe size to
+ * be used for distributing the available memory among the nodes is specified
+ * with the emu_size= kernel parameter. Fewer nodes were created than the
+ * requested number; each node has one memory stripe of the requested size.
+ * User action:
+ * Specify fewer nodes, reduce the memory stripe size, or make more memory
+ * available to your Linux instance.
+ */
+
+/*?
+ * Text: "Creating %d nodes with memory stripe size %ld MB\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: number of nodes
+ *   @2: stripe size
+ * Description:
+ * NUMA emulation is activated with the reported number of NUMA nodes.
+ * The specified memory stripe size is used to distribute, in round-robin
+ * fashion, the available memory among the nodes.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Increasing memory stripe size from %ld MB to %ld MB\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: requested memory stripe size
+ *   @2: adjusted memory stripe size
+ * Description:
+ * NUMA  emulation  could  not  use  the  requested memory stripe size and
+ * therefore has increased it to the next possible value.
+ * The requested memory stripe size is a default value or it was specified
+ * with the emu_size= kernel parameter.
+ * The memory stripe size must be a multiple of the memory block size that
+ * can be read in hexadecimal notation from
+ * /sys/devices/system/memory/block_size_bytes.
+ * User action:
+ * To avoid this message in the future, specify a valid memory stripe size
+ * with the emu_size= kernel parameter.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/os_info
+++ linux-ein-5.4.0/Documentation/kmsg/s390/os_info
@@ -0,0 +1,36 @@
+/*?
+ * Text: "entry %i: %s (addr=0x%lx size=%lu)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: entry ID
+ *   @2: entry state
+ *   @3: entry address
+ *   @4: entry size
+ * Description:
+ * Linux is running in kdump mode and reports information defined by the
+ * previously running production kernel. Possible values for
+ * "entry state" are:
+ *
+ * - copied: The entry has been found, verified, and copied
+ *
+ * - not available: The entry has not been defined
+ *
+ * - checksum failed: The entry has been found, but it is not valid
+ * User action:
+ * If kdump fails, contact your service organization and include this message
+ * in the error report.
+ */
+
+/*?
+ * Text: "crashkernel: addr=0x%lx size=%lu\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: address
+ *   @2: size
+ * Description:
+ * Linux is running in kdump mode and reports the address and size of
+ * the memory area that was reserved for kdump by the previously running
+ * production kernel.
+ * User action:
+ * None.
+ */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/perf
+++ linux-ein-5.4.0/Documentation/kmsg/s390/perf
@@ -0,0 +1,90 @@
+/*?
+ * Text: "CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: cpu number
+ *   @2: first version number
+ *   @3: second version number
+ *   @4: counter set authorization
+ *   @5: counter set enable controls
+ *   @6: counter set activation controls
+ * Description:
+ * This message displays information about the CPU-measurement counter facility
+ * (CPUM_CF) on a particular CPU.  For details, see
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "CPU[%i] CPUM_SF: basic=%i diag=%i min=%lu max=%lu cpu_speed=%u\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: cpu number
+ *   @2: authorization status for the basic-sampling function
+ *   @3: authorization status for the diagnostic-sampling function
+ *   @4: minimum sampling interval
+ *   @5: maximum sampling interval
+ *   @6: cpu speed
+ * Description:
+ * This message displays generic information about the CPU-measurement sampling
+ * facility (CPUM_SF) on a particular CPU.  For details, see
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "CPU[%i] CPUM_SF: Basic-sampling: a=%i e=%i c=%i bsdes=%i tear=%016lx dear=%016lx\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: cpu number
+ *   @2: authorization control
+ *   @3: enable control
+ *   @4: activation control
+ *   @5: basic-sampling-data-entry size
+ *   @6: tear register contents
+ *   @7: dear register contents
+ * Description:
+ * This message displays information about the basic-sampling function of the
+ * CPU-measurement sampling facility (CPUM_SF) on a particular CPU.
+ * For details, see
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "CPU[%i] CPUM_SF: Diagnostic-sampling: a=%i e=%i c=%i dsdes=%i tear=%016lx dear=%016lx\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: cpu number
+ *   @2: authorization control
+ *   @3: enable control
+ *   @4: activation control
+ *   @5: diagnostic-sampling-data-entry size
+ *   @6: tear register contents
+ *   @7: dear register contents
+ * Description:
+ * This message displays information about the diagnostic-sampling function of the
+ * CPU-measurement sampling facility (CPUM_SF) on a particular CPU.
+ * For details, see
+ * "The Load-Program-Parameter and the CPU-Measurement Facilities", SA23-2260.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The sampling facility is already reserved by %p\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: address of perf sampling support owner
+ * Description:
+ * A process tried to reserve the sampling facility support, but it was already
+ * reserved by another process.
+ * User action:
+ * Check whether another process, for example, the perf program or OProfile is
+ * currently active.  Retry activating the sampling facility after the other
+ * process has ended.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/prng
+++ linux-ein-5.4.0/Documentation/kmsg/s390/prng
@@ -0,0 +1,103 @@
+/* prng */
+
+/*?
+ * Text: "prng runs in TDES mode with chunksize=%d and reseed_limit=%u\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: read chunk size in bytes
+ *   @2: reseed limit
+ * Description:
+ * The pseudo-random number device driver started in triple DES mode.
+ * For IBM mainframes earlier than IBM zEnterprise EC12 (zEC12),
+ * triple DES is the only available mode.
+ * As of zEC12, the preferred mode is SHA-512.
+ * User action:
+ * If triple DES is the expected mode, no action is required.
+ * Otherwise, verify that the prng started with the mode= module or
+ * prng.mode= kernel parameter set to a value other than 1.
+ * The value 1 forces triple DES mode. Also ensure that the mainframe
+ * runs with the latest firmware level.
+ */
+
+/*?
+ * Text: "The prng module stopped after running in triple DES mode\n"
+ * Severity: Informational
+ * Description:
+ * The pseudo-random number device driver was running in triple DES mode.
+ * The device driver module, prng, was unloaded, or it stopped
+ * because Linux shut down.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The prng module cannot start in SHA-512 mode\n"
+ * Severity: Error
+ * Description:
+ * The pseudo-random number device driver was loaded with the mode= module parameter
+ * or the prng.mode= kernel parameter set to 2. This setting forces SHA-512 mode,
+ * but the required support for MSA 5 is not available. This support requires an IBM
+ * zEnterprise EC12 (zEC12) or later mainframe.
+ * User action:
+ * If your mainframe is earlier than zEC12, set the mode= module or
+ * prng.mode= kernel parameter to 0 or 1 to run the
+ * pseudo-random number device driver in triple DES mode.
+ * Otherwise, ensure that MSA 5 support available.
+ */
+
+/*?
+ * Text: "prng runs in SHA-512 mode with chunksize=%d and reseed_limit=%u\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: read chunk size in bytes
+ *   @2: reseed limit
+ * Description:
+ * The pseudo-random number device driver started in SHA-512 mode.
+ * As of IBM zEnterprise EC12, this is the preferred mode.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The prng module stopped after running in SHA-512 mode\n"
+ * Severity: Informational
+ * Description:
+ * The pseudo-random number device driver was running in SHA-512 mode.
+ * The device driver module, prng, was unloaded, or stopped
+ * because Linux shut down.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The prng self test state test for the SHA-512 mode failed\n"
+ * Severity: Error
+ * Description:
+ * The pseudo-random number device driver is not operational because the self test failed.
+ * After processing a published National Institute of Standards and Technology (NIST) test vector for the
+ * Deterministic Random Bit Generator (DRBG) algorithm, the device driver
+ * was not in the expected working state. This failure might indicate
+ * that the cryptographic software or hardware is not working correctly.
+ * The processed NIST test vector was: Hash Drbg, Sha-512, Count #0.
+ * User action:
+ * Unload and reload the prng module, or
+ * if prng was compiled into the kernel, restart Linux.
+ * If the error persists, contact your support organization.
+ */
+
+/*?
+ * Text: "The prng self test data test for the SHA-512 mode failed\n"
+ * Severity: Error
+ * Description:
+ * The pseudo-random number device driver is not operational because the self test failed.
+ * After processing a published National Institute of Standards and Technology (NIST) test vector for the
+ * Deterministic Random Bit Generator (DRBG) algorithm, the device driver
+ * did not produce the expected pseudo-random data. This failure might indicate
+ * that the cryptographic software or hardware is not working correctly.
+ * The processed NIST test vector was: Hash Drbg, Sha-512, Count #0.
+ * User action:
+ * Unload and reload the prng module, or
+ * if prng was compiled into the kernel, restart Linux.
+ * If the error persists, contact your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/qeth
+++ linux-ein-5.4.0/Documentation/kmsg/s390/qeth
@@ -0,0 +1,929 @@
+/*?
+ * Text: "%s: The LAN is offline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A start LAN command was sent by the qeth device driver but the physical or
+ * virtual adapter has not started the LAN. The LAN might take a few seconds
+ * to become available.
+ * User action:
+ * Check the status of the qeth device, for example, with the lsqeth command.
+ * If the device does not become operational within a few seconds, initiate a
+ * recovery process, for example, by writing '1' to the 'recover' sysfs
+ * attribute of the device.
+ */
+
+/*?
+ * Text: "%s: A recovery process has been started for the device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A recovery process was started either by the qeth device driver or through
+ * a user command.
+ * User action:
+ * Wait until a message indicates the completion of the recovery process.
+ */
+
+/*?
+ * Text: "%s: The qeth device driver failed to recover an error on the device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth device driver performed an automatic recovery operation to recover
+ * an error on a qeth device. The recovery operation failed.
+ * User action:
+ * Try the following actions in the given order: i) Check the status of the
+ * qeth device, for example, with the lsqeth command. ii) Initiate a recovery
+ * process by writing '1' to the 'recover' sysfs attribute of the device.
+ * iii) Ungroup and regroup the subchannel triplet of the device. vi) Reboot
+ * Linux. v) If the problem persists, gather Linux debug data and report the
+ * problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Device recovery failed to restore all offload features\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth device driver performed a recovery operation on a qeth device. Part
+ * of the recovery is to restore the offload features that were enabled before
+ * the recovery. At least one of those offload features could not be restored.
+ * User action:
+ * Check which offload features are enabled on the device, for example with
+ * the "ethtool -k" command. Try to explicitly re-enable the missing offload
+ * features for the device, for example with the "ethtool -K" command.
+ */
+
+/*?
+ * Text: "%s: The link for interface %s on CHPID 0x%X failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ *   @3: CHPID
+ * Description:
+ * A network link failed. A possible reason for this error is that a physical
+ * network cable has been disconnected.
+ * User action:
+ * Ensure that the network cable on the adapter hardware is connected properly.
+ * If the connection is to a guest LAN, ensure that the device is still coupled
+ * to the guest LAN.
+ */
+
+/*?
+ * Text: "%s: The link for %s on CHPID 0x%X has been restored\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ *   @3: CHPID
+ * Description:
+ * A failed network link has been re-established. A device recovery is in
+ * progress.
+ * User action:
+ * Wait until a message indicates the completion of the recovery process.
+ */
+
+/*?
+ * Text: "%s: A hardware operation timed out on the device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A hardware operation timed out on the qeth device.
+ * User action:
+ * Check the status of the qeth device, for example, with the lsqeth command.
+ * If the device is not operational, initiate a recovery process, for example,
+ * by writing '1' to the 'recover' sysfs attribute of the device.
+ */
+
+/*?
+ * Text: "%s: The adapter hardware is of an unknown type\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth device driver does not recognize the adapter hardware. The cause
+ * of this problem could be a hardware error or a Linux level that does not
+ * support your adapter hardware.
+ * User action:
+ * i) Investigate if your adapter hardware is supported by your Linux level.
+ * Consider using hardware that is supported by your Linux level or upgrading
+ * to a Linux level that supports your hardware. ii) Install the latest
+ * firmware on your adapter hardware. iii) If the problem persists and is not
+ * caused by a version mismatch, contact IBM support.
+ */
+
+/*?
+ * Text: "%s: The adapter is used exclusively by another host\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth adapter is exclusively used by another host.
+ * User action:
+ * Use another qeth adapter or configure this one not exclusively to a
+ * particular host.
+ */
+
+/*?
+ * Text: "%s: QDIO reported an error, rc=%i\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: return code
+ * Description:
+ * The QDIO subsystem reported an error.
+ * User action:
+ * Check for related QDIO errors. Check the status of the qeth device, for
+ * example, with the lsqeth command. If the device is not operational, initiate
+ * a recovery process, for example, by writing '1' to the 'recover' sysfs
+ * attribute of the device.
+ */
+
+/*?
+ * Text: "%s: There is no kernel module to support discipline %d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: discipline
+ * Description:
+ * The qeth device driver or a user command requested a kernel module for a
+ * particular qeth discipline. Either the discipline is not supported by the
+ * qeth device driver or the requested module is not available to your Linux
+ * system.
+ * User action:
+ * Check if the requested discipline module has been compiled into the kernel
+ * or is present in /lib/modules/<version>/kernel/drivers/s390/net.
+ */
+
+/*?
+ * Text: "Initializing the qeth device driver failed\n"
+ * Severity: Error
+ * Parameter:
+ * Description:
+ * The base module of the qeth device driver could not be initialized.
+ * User action:
+ * See errno.h to determine the reason for the error.
+ * i) Reboot Linux. ii) If the problem persists, gather Linux debug data and
+ * report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Registering IP address %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: IP address
+ * Description:
+ * An IP address could not be registered with the network adapter.
+ * User action:
+ * Check if another operating system instance has already registered the
+ * IP address with the same network adapter or at the same logical IP subnet.
+ */
+
+/*?
+ * Text: "%s: Reading the adapter MAC address failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth device driver could not read the MAC address from the network
+ * adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting ARP processing support for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not start ARP support on the network adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting IP fragmentation support for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not start IP fragmentation support on the
+ * network adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting VLAN support for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not start VLAN support on the network adapter.
+ * User action:
+ * None if you do not require VLAN support. If you need VLAN support,
+ * ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting multicast support for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not start multicast support on the network
+ * adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Activating IPv6 support for %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not activate IPv6 support on the network
+ * adapter.
+ * User action:
+ * None if you do not require IPv6 communication. If you need IPv6 support,
+ * ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Enabling the passthrough mode for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not enable the passthrough mode on the
+ * network adapter. The passthrough mode is required for all network traffic
+ * other than IPv4. In particular, the passthrough mode is required for IPv6
+ * traffic.
+ * User action:
+ * None if all you want to support is IPv4 communication. If you want to support
+ * IPv6 or other network traffic apart from IPv4, ungroup and regroup the
+ * subchannel triplet of the device. If this does not resolve the problem,
+ * reboot Linux. If the problem persists, gather Linux debug data and report
+ * the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Enabling broadcast filtering for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not enable broadcast filtering on the network
+ * adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Setting up broadcast filtering for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not set up broadcast filtering on the network
+ * adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Setting up broadcast echo filtering for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not set up broadcast echo filtering on the
+ * network adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting HW checksumming for %s failed, using SW checksumming\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The network adapter supports hardware checksumming for IP packages
+ * but the qeth device driver could not start hardware checksumming on the
+ * adapter. The qeth device driver continues to use software checksumming for
+ * IP packages.
+ * User action:
+ * None if you do not require hardware checksumming for network
+ * traffic. If you want to enable hardware checksumming, ungroup and regroup
+ * the subchannel triplet of the device. If this does not resolve the problem,
+ * reboot Linux. If the problem persists, gather Linux debug data and report
+ * the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Enabling HW checksumming for %s failed, using SW checksumming\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The network adapter supports hardware checksumming for IP packages
+ * but the qeth device driver could not enable hardware checksumming on the
+ * adapter. The qeth device driver continues to use software checksumming for
+ * IP packages.
+ * User action:
+ * None if you do not require hardware checksumming for network
+ * traffic. If you want to enable hardware checksumming, ungroup and regroup
+ * the subchannel triplet of the device. If this does not resolve the problem,
+ * reboot Linux. If the problem persists, gather Linux debug data and report
+ * the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Starting outbound TCP segmentation offload for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The network adapter supports TCP segmentation offload, but the qeth device
+ * driver could not start this support on the adapter.
+ * User action:
+ * None if you do not require TCP segmentation offload. If you want to
+ * enable TCP segmentation offload, ungroup and regroup the subchannel triplet
+ * of the device. If this does not resolve the problem, reboot Linux. If the
+ * problem persists, gather Linux debug data and report the problem to your
+ * support organization.
+ */
+
+/*?
+ * Text: "%s: The network adapter failed to generate a unique ID\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * In IBM mainframe environments, network interfaces are not identified by
+ * a specific MAC address. Therefore, the network adapters provide the network
+ * interfaces with unique IDs to be used in their IPv6 link local addresses.
+ * Without such a unique ID, duplicate addresses might be assigned in other
+ * LPARs.
+ * User action:
+ * Install the latest firmware on the adapter hardware. Manually, configure
+ * an IPv6 link local address for this device.
+ */
+
+/*?
+ * Text: "There is no IPv6 support for the layer 3 discipline\n"
+ * Severity: Warning
+ * Description:
+ * If you want to use IPv6 with the layer 3 discipline, you need a Linux kernel
+ * with IPv6 support. Because your Linux kernel has not been compiled with
+ * IPv6 support, you cannot use IPv6 with the layer 3 discipline, even if your
+ * adapter supports IPv6.
+ * User action:
+ * Use a Linux kernel that has been complied to include IPv6 support if you
+ * want to use IPv6 with layer 3 qeth devices.
+ */
+
+/*?
+ * Text: "%s: The qeth device is not configured for the OSI layer required by z/VM\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A qeth device that connects to a virtual network on z/VM must be configured for the
+ * same Open Systems Interconnection (OSI) layer as the virtual network. An ETHERNET
+ * guest LAN or VSWITCH uses the data link layer (layer 2) while an IP guest LAN
+ * or VSWITCH uses the network layer (layer 3).
+ * User action:
+ * If you are connecting to an ETHERNET guest LAN or VSWITCH, set the layer2 sysfs
+ * attribute of the qeth device to 1. If you are connecting to an IP guest LAN or
+ * VSWITCH, set the layer2 sysfs attribute of the qeth device to 0.
+ */
+
+/*?
+ * Text: "%s: Starting source MAC-address support for %s failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The qeth device driver could not enable source MAC-address on the network
+ * adapter.
+ * User action:
+ * Ungroup and regroup the subchannel triplet of the device. If this does not
+ * resolve the problem, reboot Linux. If the problem persists, gather Linux
+ * debug data and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: MAC address %pM already exists\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: MAC-address
+ * Description:
+ * Setting the MAC address for the qeth device fails, because this
+ * MAC address is already defined on the OSA CHPID.
+ * User action:
+ * Use a different MAC address for this qeth device.
+ */
+
+/*?
+ * Text: "%s: MAC address %pM is not authorized\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: MAC-address
+ * Description:
+ * This qeth device is a virtual network interface card (NIC), to which z/VM
+ * has already assigned a MAC address. z/VM MAC address verification does
+ * not allow you to change this predefined address.
+ * User action:
+ * None; use the MAC address that has been assigned by z/VM.
+ */
+
+/*?
+ * Text: "%s: The HiperSockets network traffic analyzer is activated\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The sysfs 'sniffer' attribute of the HiperSockets device has the value '1'.
+ * The corresponding HiperSockets interface has been switched into promiscuous mode.
+ * As a result, the HiperSockets network traffic analyzer is started on the device.
+ * User action:
+ * None.
+ */
+
+ /*?
+  * Text: "%s: The HiperSockets network traffic analyzer is deactivated\n"
+  * Severity: Informational
+  * Parameter:
+  *   @1: bus ID of the qeth device
+  * Description:
+  * The sysfs 'sniffer' attribute of the HiperSockets device has the value '1'.
+  * Promiscuous mode has been switched off for the corresponding HiperSockets interface
+  * As a result, the HiperSockets network traffic analyzer is stopped on the device.
+  * User action:
+  * None.
+  */
+
+/*?
+ * Text: "%s: The device is not authorized to run as a HiperSockets network traffic analyzer\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The sysfs 'sniffer' attribute of the HiperSockets device has the value '1'.
+ * The corresponding HiperSockets interface is switched into promiscuous mode
+ * but the network traffic analyzer (NTA) rules configured at the Support Element (SE)
+ * do not allow tracing. Possible reasons are:
+ * - Tracing is not authorized for all HiperSockets LANs in the mainframe system
+ * - Tracing is not authorized for this HiperSockets LAN
+ * - LPAR is not authorized to enable an NTA
+ * User action:
+ * Configure appropriate HiperSockets NTA rules at the SE.
+ */
+
+/*?
+ * Text: "%s: A HiperSockets network traffic analyzer is already active in the HiperSockets LAN\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The sysfs 'sniffer' attribute of the HiperSockets device has the value '1'.
+ * The HiperSockets interface is switched into promiscuous mode but another
+ * HiperSockets device on the same HiperSockets LAN is already running as
+ * a network traffic analyzer.
+ * A HiperSockets LAN can only have one active network traffic analyzer.
+ * User action:
+ * Do not configure multiple HiperSockets devices in the same HiperSockets LAN as
+ * tracing devices.
+ */
+
+/*?
+ * Text: "%s: Enabling HW TX checksumming for %s failed, using SW TX checksumming\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ * Description:
+ * The network adapter supports hardware checksumming for outgoing IP packages
+ * but the qeth device driver could not enable hardware TX checksumming on the
+ * adapter. The qeth device driver continues to use software checksumming for
+ * outgoing IP packages.
+ * User action:
+ * None if you do not require hardware checksumming for outgoing network
+ * traffic. If you want to enable hardware checksumming, ungroup and regroup
+ * the subchannel triplet of the device. If this does not resolve the problem,
+ * reboot Linux. If the problem persists, gather Linux debug data and report
+ * the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: A connection could not be established because of an OLM limit\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * z/OS has activated Optimized Latency Mode (OLM) for a connection through an OSA Express3 adapter.
+ * This reduces the maximum number of concurrent connections per physical port for shared adapters.
+ * The new connection would exceed the maximum. Linux cannot establish further connections using
+ * this adapter.
+ * User action:
+ * If possible, deactivate an existing connection that uses this adapter and try again to establish
+ * the new connection. If you cannot free an existing connection, use a different adapter for the
+ * new connection.
+ */
+
+/*?
+ * Text: "%s: Setting the device online failed because of insufficient authorization\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The qeth device is configured with OSX CHPIDs. An OSX CHPID cannot be activated unless the LPAR is explicitly authorized to access it.
+ * For z/VM guest operating systems, the z/VM user ID must be explicitly authorized in addition to the LPAR.
+ * You grant these authorizations through the Service Element.
+ * User action:
+ * At the Service Element, authorize the LPAR and, if applicable, the z/VM user ID for using the OSX CHPIDs with which the qeth device has been configured.
+ * Then try again to set the device online.
+ */
+
+/*?
+ * Text: "%s: portname is deprecated and is ignored\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * An OSA-Express port name was required to identify a shared OSA port.
+ * All operating system instances that shared the port had to use the same port name.
+ * This requirement no longer applies, and the specified portname attribute is ignored.
+ * User action:
+ * For future upgrades, remove OSA port name specifications from your
+ * network configuration.
+ */
+
+/*? Text: "core functions removed\n" */
+/*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s.\n" */
+/*? Text: "%s: issue_next_read failed: no iob available!\n" */
+/*? Text: "%s: Priority Queueing not supported\n" */
+/*? Text: "%s: sense data available. cstat 0x%X dstat 0x%X\n" */
+/*? Text: "loading core functions\n" */
+/*? Text: "%s: MAC address %pM successfully registered on device %s\n" */
+/*? Text: "%s: Device successfully recovered!\n" */
+/*? Text: "register layer 2 discipline\n" */
+/*? Text: "unregister layer 2 discipline\n" */
+/*? Text: "%s: Hardware IP fragmentation not supported on %s\n" */
+/*? Text: "%s: IPv6 not supported on %s\n" */
+/*? Text: "%s: VLAN not supported on %s\n" */
+/*? Text: "%s: Inbound source MAC-address not supported on %s\n" */
+/*? Text: "%s: IPV6 enabled\n" */
+/*? Text: "%s: ARP processing not supported on %s!\n" */
+/*? Text: "%s: Hardware IP fragmentation enabled \n" */
+/*? Text: "%s: set adapter parameters not supported.\n" */
+/*? Text: "%s: VLAN enabled\n" */
+/*? Text: "register layer 3 discipline\n" */
+/*? Text: "%s: Outbound TSO enabled\n" */
+/*? Text: "%s: Broadcast not supported on %s\n" */
+/*? Text: "%s: Outbound TSO not supported on %s\n" */
+/*? Text: "%s: Inbound HW Checksumming not supported on %s,\ncontinuing using Inbound SW Checksumming\n" */
+/*? Text: "%s: Using no checksumming on %s.\n" */
+/*? Text: "%s: Broadcast enabled\n" */
+/*? Text: "%s: Multicast not supported on %s\n" */
+/*? Text: "%s: Using SW checksumming on %s.\n" */
+/*? Text: "%s: HW Checksumming (%sbound) enabled\n" */
+/*? Text: "unregister layer 3 discipline\n" */
+/*? Text: "%s: Multicast enabled\n" */
+/*? Text: "%s: QDIO data connection isolation is deactivated\n" */
+/*? Text: "%s: QDIO data connection isolation is activated\n" */
+/*? Text: "%s: Adapter does not support QDIO data connection isolation\n" */
+/*? Text: "%s: Adapter is dedicated. QDIO data connection isolation not supported\n" */
+/*? Text: "%s: TSO does not permit QDIO data connection isolation\n" */
+/*? Text: "%s: HW TX Checksumming enabled\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "qeth_l3: ignoring TR device\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+
+/*?
+ * Text: "%s: Turning off reflective relay mode at the adjacent switch failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The policy for the QDIO data connection isolation was
+ * changed successfully, and communications are now handled according to the
+ * new policy. The ISOLATION_FORWARD policy is no longer used, but the qeth
+ * device driver could not turn off the reflective relay mode on the adjacent
+ * switch port.
+ * User action:
+ * Check the adjacent switch for errors and correct the problem.
+ */
+
+/*?
+ * Text: "%s: The adjacent switch port does not support reflective relay mode\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The 'isolation' sysfs attribute of the qeth device could not be set to 'forward'.
+ * This setting selects the ISOLATION_FORWARD policy for the QDIO data connection
+ * isolation. The ISOLATION_FORWARD policy requires a network adapter in Virtual
+ * Ethernet Port Aggregator (VEPA) mode with an adjacent switch port in reflective
+ * relay mode.
+ * User action:
+ * Use a switch port that supports reflective relay mode if you want to use the
+ * ISOLATION_FORWARD policy for the qeth device.
+ */
+
+/*?
+ * Text: "%s: The reflective relay mode cannot be enabled at the adjacent switch port"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The 'isolation' sysfs attribute of the qeth device could not be set to 'forward'.
+ * This setting selects the ISOLATION_FORWARD policy for the QDIO data connection
+ * isolation. The ISOLATION_FORWARD policy requires a network adapter in Virtual
+ * Ethernet Port Aggregator (VEPA) mode with an adjacent switch port in reflective relay
+ * mode. The qeth device driver failed to enable the required reflective relay mode on
+ * the adjacent switch port although the switch port supports this mode.
+ * User action:
+ * Enable reflective relay mode on the switch for the adjacent port and try again.
+ */
+
+/*?
+ * Text: "%s: Interface %s is down because the adjacent port is no longer in reflective relay mode\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: interface name
+ * Description:
+ * The ISOLATION_FORWARD policy is active for the QDIO data connection isolation
+ * of the qeth device. This policy requires a network adapter in Virtual Ethernet
+ * Port Aggregator (VEPA) mode with an adjacent switch port in reflective relay mode.
+ * The reflective relay mode on the adjacent switch port was disabled. The qeth device
+ * was set offline and the interface was deactivated to prevent any unintended network traffic.
+ * User action:
+ * Enable the reflective relay mode again on the adjacent port or use the 'isolation'
+ * sysfs attribute of the qeth device to set a different policy for the QDIO data connection
+ * isolation. You can then resume operations by setting the qeth device back
+ * online and activating the interface.
+ */
+
+/*?
+ * Text: "%s: Failed to create completion queue\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The HiperSockets device could not be configured with a completion queue.
+ * A completion queue is required to operate AF_IUCV communication in an LPAR.
+ * User action:
+ * i) Investigate if you have the latest firmware level in place.
+ * ii) If the problem persists and is not caused by a version mismatch, contact IBM
+ * support.
+ */
+
+/*?
+ * Text: "%s: Completion Queueing supported\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The HiperSockets device supports completion queueing. This is required to
+ * set up AF_IUCV communication in an LPAR.
+ */
+
+/*?
+ * Text: "%s: Completion Queue support enabled"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The HiperSockets device is enabled for completion queueing. This is part of
+ * the process to set up AF_IUCV communication in an LPAR.
+ */
+
+/*?
+ * Text: "%s: Completion Queue support disabled"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The HiperSockets device is disabled for completion queueing. This device
+ * cannot or no longer be used to set up AF_IUCV communication in an LPAR.
+ */
+
+/*?
+ * Text: "%s: The device represents a Bridge Capable Port\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * You can configure this device as a Bridge Port.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The device is not configured as a Bridge Port\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The Bridge Port role cannot be withdrawn from a device
+ * that is not configured as a Bridge Port.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The LAN already has a primary Bridge Port\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A LAN can have multiple secondary Bridge Ports, but only
+ * one primary Bridge Port. Configuring the device as a
+ * primary Bridge Port failed because another port on the
+ * LAN has been configured as the primary Bridge Port.
+ * User action:
+ * Find out which operating system instance has configured the primary
+ * Bridge Port. Assure that the primary role for this port is withdrawn
+ * before trying again to configure your device as the primary Bridge
+ * Port. Alternatively, consider configuring your device as a secondary
+ * Bridge Port.
+ */
+
+/*?
+ * Text: "%s: The device is already a secondary Bridge Port\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A device cannot be configured as a primary or secondary
+ * Bridge Port if it is already configured as a secondary Bridge Port.
+ * User action:
+ * None, if you want the device to be a secondary Bridge Port.
+ * If you want to configure the device as the primary Bridge Port,
+ * withdraw the secondary role by writing 'none' to the 'bridgeport_role'
+ * sysfs attribute of the device. Then try again to configure the
+ * device as the primary Bridge Port.
+ */
+
+/*?
+ * Text: "%s: The LAN cannot have more secondary Bridge Ports\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A LAN can have up to five secondary Bridge Ports.
+ * You cannot configure a further device as a secondary
+ * Bridge Port unless the Bridge Ports role is withdrawn from one of
+ * the existing secondary Bridge Ports.
+ * User action:
+ * Assure that the Bridge Port role is withdrawn from one of the
+ * existing secondary Bridge Ports before trying again to configure your
+ * device as a secondary Bridge Port.
+ */
+
+/*?
+ * Text: "%s: The device is already a primary Bridge Port\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * A device cannot be configured as a primary or secondary
+ * Bridge Port if it is already configured as a primary Bridge Port.
+ * User action:
+ * None, if you want the device to be a primary Bridge Port.
+ * If you want to configure the device as a secondary Bridge Port,
+ * withdraw the primary role by writing 'none' to the 'bridgeport_role'
+ * sysfs attribute of the device. Then try again to configure the
+ * device as the secondary Bridge Port.
+ */
+
+/*?
+ * Text: "%s: The device is not authorized to be a Bridge Port\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * The device cannot be configured as a Bridge Port because
+ * the required authorizations in the hardware are not in place.
+ * User action:
+ * See your hardware documentation about how to authorize
+ * ports for becoming a Bridge Port.
+ */
+
+/*?
+ * Text: "%s: A Bridge Port is already configured by a different operating system\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * Linux instances cannot configure the target port as a Bridge Port.
+ * Another operating system already uses a Bridge Port on the HiperSockets
+ * or on the OSA adapter. For example, a z/VM instance might be using
+ * a port in a VSWITCH configuration. Multiple Bridge Ports on the same
+ * HiperSockets or OSA adapter must be configured by instances of the same
+ * operating system, for example, all Linux or all z/VM.
+ * User action:
+ * Reconsider your network topology. Configure Bridge Ports only for ports
+ * on adapters where any other Bridge Ports are configured by other Linux
+ * instances.
+ */
+
+/*?
+ * Text: "%s: Setting address notification failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * Enabling or disabling the address notification feature of a
+ * HiperSockets device failed. The device might not be configured as a
+ * Bridge Port.
+ * User action:
+ * None, unless you need address notifications for this device.
+ * If you need notifications, confirm that your device is attached to a
+ * HiperSockets LAN that supports Bridge Capable Ports and that your
+ * device is configured as a Bridge Port. If the 'bridgeport_role'
+ * sysfs attribute of the device contains, one of the values 'primary'
+ * or 'secondary' and you cannot set the address notification, contact
+ * your support organization.
+ */
+
+/*?
+ * Text: "%s: Address notification from the Bridge Port stopped %s (%s)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ *   @2: network interface name
+ *   @3: error reported by the hardware
+ * Description:
+ * A Bridge Port no longer provides address notifications.
+ * Possible reasons include traffic overflow and that the device is no
+ * longer configured as a Bridge Port. A udev event with
+ * BRIDGEDHOST=abort was emitted to alert applications that rely on the
+ * address notifications.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The qeth driver ran out of channel command buffers\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the qeth device
+ * Description:
+ * Command buffers can temporarily run out during periods of
+ * intense network configuration activities.
+ * The device driver recovers from this condition as outstanding
+ * commands are completed.
+ * User action:
+ * Wait for a short time. If the problem persists,
+ * initiate a recovery process by writing '1' to the 'recover'
+ * sysfs attribute of the device.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/s390dbf
+++ linux-ein-5.4.0/Documentation/kmsg/s390/s390dbf
@@ -0,0 +1,83 @@
+/*?
+ * Text: "Root becomes the owner of all s390dbf files in sysfs\n"
+ * Severity: Warning
+ * Description:
+ * The S/390 debug feature you are using only supports uid/gid = 0.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Registering debug feature %s failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: feature name
+ * Description:
+ * The initialization of an S/390 debug feature failed. A likely cause of this
+ * problem is memory constraints. The system keeps running, but the debug
+ * data for this feature will not be available in sysfs.
+ * User action:
+ * Consider assigning more memory to your LPAR or z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "Registering view %s/%s would exceed the maximum number of views %i\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: feature name
+ *   @2: view name
+ *   @3: maximum
+ * Description:
+ * The maximum number of allowed debug feature views has been reached. The
+ * view has not been registered. The system keeps running but the new view
+ * will not be available in sysfs. This is a program error.
+ * User action:
+ * Report this problem to your support partner.
+ */
+
+/*?
+ * Text: "%s is not a valid level for a debug feature\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: level
+ * Description:
+ * Setting a new level for a debug feature by using the 'level' sysfs attribute
+ * failed. Valid levels are the minus sign (-) and the integers in the
+ * range 0 to 6. The minus sign switches off the feature. The numbers switch
+ * the feature on, where higher numbers produce more debug output.
+ * User action:
+ * Write a valid value to the 'level' sysfs attribute.
+ */
+
+/*?
+ * Text: "Flushing debug data failed because %c is not a valid area\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: debug area number
+ * Description:
+ * Flushing a debug area by using the 'flush' sysfs attribute failed. Valid
+ * values are the minus sign (-) for flushing all areas, or the number of the
+ * respective area for flushing a single area.
+ * User action:
+ * Write a valid area number or the minus sign (-) to the 'flush' sysfs
+ * attribute.
+ */
+
+/*?
+ * Text: "Allocating memory for %i pages failed\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: number of pages
+ * Description:
+ * Setting the debug feature size by using the 'page' sysfs attribute failed.
+ * Linux did not have enough memory for expanding the debug feature to the
+ * requested size.
+ * User action:
+ * Use a smaller number of pages for the debug feature or allocate more
+ * memory to your LPAR or z/VM guest virtual machine.
+ */
+
+/*? Text: "%s: set new size (%i pages)\n" */
+/*? Text: "%s: switched off\n" */
+/*? Text: "%s: level %i is out of range (%i - %i)\n" */
+/*? Text: "Registering view %s/%s failed due to out of memory\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/sclp_cmd
+++ linux-ein-5.4.0/Documentation/kmsg/s390/sclp_cmd
@@ -0,0 +1,44 @@
+/*? Text: "sync request failed (cmd=0x%08x, status=0x%02x)\n" */
+/*? Text: "readcpuinfo failed (response=0x%04x)\n" */
+/*? Text: "configure cpu failed (cmd=0x%08x, response=0x%04x)\n" */
+/*? Text: "configure channel-path failed (cmd=0x%08x, response=0x%04x)\n" */
+/*? Text: "read channel-path info failed (response=0x%04x)\n" */
+/*? Text: "assign storage failed (cmd=0x%08x, response=0x%04x, rn=0x%04x)\n" */
+/*? Text: "configure PCI I/O adapter failed: cmd=0x%08x  response=0x%04x\n" */
+/*? Text: "request failed (status=0x%02x)\n" */
+/*? Text: "request failed with response code 0x%x\n" */
+
+/*?
+ * Text: "Memory hotplug state changed, suspend refused.\n"
+ * Severity: Error
+ * Description:
+ * Suspend is refused after a memory hotplug operation was performed.
+ * User action:
+ * The system needs to be restarted and no memory hotplug operation must be
+ * performed in order to allow suspend.
+ */
+
+/*?
+ * Text: "Standby memory at 0x%llx (%lluM of %lluM usable)\n"
+ * Severity: Informational
+ * Parameter:
+ * @1: start address of standby memory
+ * @2: usable memory in MB
+ * @3: total detected memory in MB
+ * Description:
+ * Standby memory was detected. It can be used for memory hotplug only
+ * if it is aligned to the Linux hotplug memory block size.
+ * If the aligned amount of memory matches the total amount,
+ * all detected standby memory can be used. Otherwise, some of the detected
+ * memory is unaligned and cannot be used.
+ * User action:
+ * None, if the usable and the total amount of detected standby memory match.
+ * If the amounts of memory do not match,
+ * check the memory setup of your guest virtual machine and ensure that
+ * the standby memory start and end
+ * address is aligned to the Linux hotplug memory block size.
+ * On Linux, issue "cat /sys/devices/system/memory/block_size_bytes"
+ * to find the hotplug memory block size value in hexadecimal notation.
+ * On z/VM, query your memory setup with "vmcp q v store".
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/sclp_config
+++ linux-ein-5.4.0/Documentation/kmsg/s390/sclp_config
@@ -0,0 +1,15 @@
+/*?
+ * Text: "CPU capability may have changed\n"
+ * Severity: Informational
+ * Description:
+ * The capability of the CPUs in the configuration may have been upgraded
+ * or downgraded. This message may also appear if the capability of the
+ * CPUs in the configuration did not change.
+ * For details see the STORE SYSTEM INFORMATION description in the
+ * "Principles of Operation."
+ * User action:
+ * The user can examine /proc/sysinfo for CPU capability values.
+ */
+/*? Text: "Open for Business request failed with response code 0x%04x\n" */
+/*? Text: "SCLP receiver did not register to receive Configuration Management Data Events.\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/sclp_cpi
+++ linux-ein-5.4.0/Documentation/kmsg/s390/sclp_cpi
@@ -0,0 +1,3 @@
+/*? Text: "request failed (status=0x%02x)\n" */
+/*? Text: "request failed with response code 0x%x\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/sclp_ocf
+++ linux-ein-5.4.0/Documentation/kmsg/s390/sclp_ocf
@@ -0,0 +1 @@
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/sclp_sdias
+++ linux-ein-5.4.0/Documentation/kmsg/s390/sclp_sdias
@@ -0,0 +1,4 @@
+/*? Text: "sclp_send failed for get_nr_blocks\n" */
+/*? Text: "SCLP error: %x\n" */
+/*? Text: "sclp_send failed: %x\n" */
+/*? Text: "Error from SCLP while copying hsa. Event status = %x\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/scm_block
+++ linux-ein-5.4.0/Documentation/kmsg/s390/scm_block
@@ -0,0 +1,51 @@
+/*?
+ * Text: "%lx: The capabilities of the SCM increment changed\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: start address of the SCM increment
+ * Description:
+ * A configuration change is in progress for the storage class memory (SCM)
+ * increment.
+ * User action:
+ * Verify that the capability of the SCM increment is as intended; for
+ * example, with lsscm.
+ */
+
+/*?
+ * Text: "An I/O operation to SCM failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * An error occurred during I/O to storage class memory (SCM). The operation
+ * was repeated, but the maximum number of retries was exceeded before the
+ * request could be fulfilled.
+ * User action:
+ * Contact your support organization.
+ */
+
+/*?
+ * Text: "%lx: Write access to the SCM increment is suspended\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: start address of the SCM increment
+ * Description:
+ * A concurrent firmware upgrade is in progress. For the duration of the
+ * upgrade, write access to the storage class memory (SCM) increment has been
+ * suspended.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%lx: Write access to the SCM increment is restored\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: start address of the SCM increment
+ * Description:
+ * Write access to the storage class memory (SCM) increment was restored
+ * after a temporary suspension during a concurrent firmware upgrade.
+ * User action:
+ * None.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/setup
+++ linux-ein-5.4.0/Documentation/kmsg/s390/setup
@@ -0,0 +1,165 @@
+/*?
+ * Text: "The initial RAM disk does not fit into the memory\n"
+ * Severity: Error
+ * Description:
+ * The load address and the size of the initial RAM disk specify a memory
+ * area that is not available.
+ * User action:
+ * Lower the load address of the initial RAM disk, reduce the size of the
+ * initial RAM disk, or increase the size of the system memory to make the
+ * initial RAM disk fit into the memory.
+ */
+
+/*?
+ * Text: "The maximum memory size is %luMB\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: size in MB
+ * Description:
+ * The system memory size cannot exceed the amount of memory that is
+ * provided by the real or virtual hardware. It can be further reduced
+ * through an upper memory address limit that is specified with the
+ * mem= kernel parameter.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Linux is running as a z/VM guest operating system in 31-bit mode\n"
+ * Severity: Informational
+ * Description:
+ * The 31-bit Linux kernel detected that it is running as a guest operating
+ * system of the z/VM hypervisor.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Linux is running natively in 31-bit mode\n"
+ * Severity: Informational
+ * Description:
+ * The 31-bit Linux kernel detected that it is running on an IBM mainframe,
+ * either as the sole operating system in an LPAR or as the sole operating
+ * system on the entire mainframe. The Linux kernel is not running as a
+ * guest operating system of the z/VM hypervisor.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The hardware system has IEEE compatible floating point units\n"
+ * Severity: Informational
+ * Description:
+ * The Linux kernel detected that it is running on a hardware system with
+ * CPUs that have IEEE compatible floating point units.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The hardware system has no IEEE compatible floating point units\n"
+ * Severity: Informational
+ * Description:
+ * The Linux kernel detected that it is running on a hardware system with
+ * CPUs that do not have IEEE compatible floating point units.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Linux is running as a z/VM guest operating system in 64-bit mode\n"
+ * Severity: Informational
+ * Description:
+ * The 64-bit Linux kernel detected that it is running as a guest operating
+ * system of the z/VM hypervisor.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Linux is running under KVM in 64-bit mode\n"
+ * Severity: Informational
+ * Description:
+ * The 64-bit Linux kernel detected that it is running as a guest operating
+ * system of the KVM hypervisor.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Linux is running natively in 64-bit mode\n"
+ * Severity: Informational
+ * Description:
+ * The 64-bit Linux kernel detected that it is running on an IBM mainframe,
+ * either as the sole operating system in an LPAR or as the sole operating
+ * system on the entire mainframe. The Linux kernel is not running as a
+ * guest operating system of the z/VM hypervisor.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "Defining the Linux kernel NSS failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * The Linux kernel could not define the named saved system (NSS) with
+ * the z/VM CP DEFSYS command. The return code represents the numeric
+ * portion of the CP DEFSYS error message.
+ * User action:
+ * For return code 1, the z/VM guest virtual machine is not authorized
+ * to define named saved systems.
+ * Ensure that the z/VM guest virtual machine is authorized to issue
+ * the CP DEFSYS command (typically privilege class E).
+ * For other return codes, see the help and message documentation for
+ * the CP DEFSYS command.
+ */
+
+/*?
+ * Text: "Saving the Linux kernel NSS failed with rc=%d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: return code
+ * Description:
+ * The Linux kernel could not save the named saved system (NSS) with
+ * the z/VM CP SAVESYS command. The return code represents the numeric
+ * portion of the CP SAVESYS error message.
+ * User action:
+ * For return code 1, the z/VM guest virtual machine is not authorized
+ * to save named saved systems.
+ * Ensure that the z/VM guest virtual machine is authorized to issue
+ * the CP SAVESYS command (typically privilege class E).
+ * For other return codes, see the help and message documentation for
+ * the CP SAVESYS command.
+ */
+
+/*?
+ * Text: "crashkernel reservation failed: %s\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: reason string
+ * Description:
+ * The memory reservation for the kdump "crashkernel" parameter was not
+ * successful. The Linux kernel was either not able to find a free memory
+ * area or an invalid area has been defined. The reason string describes the
+ * cause of the failure in more detail.
+ * User action:
+ * Increase the memory footprint of your virtual machine or adjust the values
+ * for the "crashkernel" kernel parameter. Then boot your Linux system again.
+ */
+
+/*?
+ * Text: "Reserving %lluMB of memory at %lluMB for crashkernel (System RAM: %luMB)\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: amount of reserved memory
+ *   @2: storage location of reserved memory
+ *   @3: amount of system RAM
+ * Description:
+ * The memory reservation for the kdump "crashkernel" parameter was successful
+ * and a kdump kernel can now be loaded with the kexec tool.
+ * User action:
+ * None.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/smsgiucv
+++ linux-ein-5.4.0/Documentation/kmsg/s390/smsgiucv
@@ -0,0 +1 @@
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/smsgiucv_app
+++ linux-ein-5.4.0/Documentation/kmsg/s390/smsgiucv_app
@@ -0,0 +1 @@
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/tape
+++ linux-ein-5.4.0/Documentation/kmsg/s390/tape
@@ -0,0 +1,63 @@
+/*?
+ * Text: "%s: A tape unit was detached while in use\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A tape unit has been detached from the I/O configuration while a tape
+ * was being accessed. This typically results in I/O error messages and
+ * potentially in damaged data on the tape.
+ * User action:
+ * Check the output of the application that accesses the tape device.
+ * If this problem occurred during a write-type operation, consider repeating
+ * the operation after bringing the tape device back online.
+ */
+
+/*?
+ * Text: "%s: A tape cartridge has been mounted\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A tape cartridge has been inserted into the tape unit. The tape in the
+ * tape unit is ready to be accessed.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The tape cartridge has been successfully unloaded\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape cartridge has been unloaded from the tape unit. Insert a tape
+ * cartridge before accessing the tape device.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "A cartridge is loaded in tape device %s, refusing to suspend\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A request to suspend a tape device currently loaded with a cartridge is
+ * rejected.
+ * User action:
+ * Unload the tape device. Then try to suspend the system again.
+ */
+
+/*?
+ * Text: "Tape device %s is busy, refusing to suspend\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A request to suspend a tape device being currently in use is rejected.
+ * User action:
+ * Terminate applications performing tape operations
+ * and then try to suspend the system again.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/tape_34xx
+++ linux-ein-5.4.0/Documentation/kmsg/s390/tape_34xx
@@ -0,0 +1,418 @@
+/*?
+ * Text: "%s: An unexpected condition %d occurred in tape error recovery\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: number
+ * Description:
+ * The control unit has reported an error condition that is not recognized by
+ * the error recovery process of the tape device driver.
+ * User action:
+ * Report this problem and the condition number from the message to your
+ * support organization.
+ */
+
+/*?
+ * Text: "%s: A data overrun occurred between the control unit and tape unit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A data overrun error has occurred on the connection between the control
+ * unit and the tape unit. If this problem occurred during a write-type
+ * operation, the integrity of the data on the tape might be compromised.
+ * User action:
+ * Use a faster connection. If this problem occurred during a write-type
+ * operation, consider repositioning the tape and repeating the operation.
+ */
+
+/*?
+ * Text: "%s: The block ID sequence on the tape is incorrect\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The control unit has detected an incorrect block ID sequence on the tape.
+ * This problem typically indicates that the data on the tape is damaged.
+ * User action:
+ * If this problem occurred during a write-type operation reposition the tape
+ * and repeat the operation.
+ */
+
+/*?
+ * Text: "%s: A read error occurred that cannot be recovered\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A read error has occurred that cannot be recovered. The current tape might
+ * be damaged.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: A write error on the tape cannot be recovered\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A write error has occurred that could not be recovered by the automatic
+ * error recovery process.
+ * User action:
+ * Use a different tape cartridge.
+ */
+
+/*?
+ * Text: "%s: Writing the ID-mark failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The ID-mark at the beginning of tape could not be written. The tape medium
+ * might be write-protected.
+ * User action:
+ * Try a different tape cartridge. Ensure that the write-protection on the
+ * cartridge is switched off.
+ */
+
+/*?
+ * Text: "%s: Reading the tape beyond the end of the recorded area failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A read-type operation failed because it extended beyond the end of the
+ * recorded area on the tape medium.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The tape contains an incorrect block ID sequence\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The control unit has detected an incorrect block ID sequence on the tape.
+ * This problem typically indicates that the data on the tape is damaged.
+ * User action:
+ * If this problem occurred during a write-type operation reposition the tape
+ * and repeat the operation.
+ */
+
+/*?
+ * Text: "%s: A path equipment check occurred for the tape device\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A path equipment check has occurred. This check indicates problems with the
+ * connection between the mainframe system and the tape control unit.
+ * User action:
+ * Ensure that the cable connections between the mainframe system and the
+ * control unit are securely in place and not damaged.
+ */
+
+/*?
+ * Text: "%s: The tape unit cannot process the tape format\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * Either the tape unit is not able to read the format ID mark, or the
+ * specified format is not supported by the tape unit.
+ * User action:
+ * If you do not need the data recorded on the current tape, use a different
+ * tape or write a new format ID mark at the beginning of the tape. Be aware
+ * that writing a new ID mark leads to a loss of all data that has been
+ * recorded on the tape. If you need the data on the current tape, use a tape
+ * unit that supports the tape format.
+ */
+
+/*?
+ * Text: "%s: The tape medium is write-protected\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A write-type operation failed because the tape medium is write-protected.
+ * User action:
+ * Eject the tape cartridge, switch off the write protection on the cartridge,
+ * insert the cartridge, and try the operation again.
+ */
+
+/*?
+ * Text: "%s: The tape does not have the required tape tension\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape does not have the required tape tension.
+ * User action:
+ * Rewind and reposition the tape, then repeat the operation.
+ */
+
+/*?
+ * Text: "%s: The tape unit failed to load the cartridge\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * An error has occurred while loading the tape cartridge.
+ * User action:
+ * Unload the cartridge and load it again.
+ */
+
+/*?
+ * Text: "%s: Automatic unloading of the tape cartridge failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit failed to unload the cartridge.
+ * User action:
+ * Unload the cartridge manually by using the eject button on the tape unit.
+ */
+
+/*?
+ * Text: "%s: An equipment check has occurred on the tape unit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * Possible reasons for the check condition are a unit adapter error, a buffer
+ * error on the lower interface, an unusable internal path, or an error that
+ * has occurred while loading the cartridge.
+ * User action:
+ * Examine the tape unit and the cartridge loader. Consult the tape unit
+ * documentation for details.
+ */
+
+/*?
+ * Text: "%s: The tape information states an incorrect length\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape is shorter than stated at the beginning of the tape data. A
+ * possible reason for this problem is that the tape might have been physically
+ * truncated. Data written to the tape might be incomplete or damaged.
+ * User action:
+ * If this problem occurred during a write-type operation, consider repeating
+ * the operation with a different tape cartridge.
+ */
+
+/*?
+ * Text: "%s: The tape unit is not ready\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit is online but not ready.
+ * User action:
+ * Turn the ready switch on the tape unit to the ready position and try the
+ * operation again.
+ */
+
+/*?
+ * Text: "%s: The tape medium has been rewound or unloaded manually\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit rewind button, unload button, or both have been used to
+ * rewind or unload the tape cartridge. A tape cartridge other than the
+ * intended cartridge might have been inserted or the tape medium might not
+ * be at the expected position.
+ * User action:
+ * Verify that the correct tape cartridge has been inserted and that the tape
+ * medium is at the required position before continuing to work with the tape.
+ */
+
+/*?
+ * Text: "%s: The tape subsystem is running in degraded mode\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape subsystem is not operating at its maximum performance.
+ * User action:
+ * Contact your service representative for the tape unit and report this
+ * problem.
+ */
+
+/*?
+ * Text: "%s: The tape unit is already assigned\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit is already assigned to another channel path.
+ * User action:
+ * Free the tape unit from the operating system instance to which it is
+ * currently assigned then try again.
+ */
+
+/*?
+ * Text: "%s: The tape unit is not online\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit is not online to the tape device driver.
+ * User action:
+ * Ensure that the tape unit is operational and that the cable connections
+ * between the control unit and the tape unit are securely in place and not
+ * damaged.
+ */
+
+/*?
+ * Text: "%s: The control unit has fenced access to the tape volume\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The control unit fences further access to the current tape volume. The data
+ * integrity on the tape volume might have been compromised.
+ * User action:
+ * Rewind and unload the tape cartridge.
+ */
+
+/*?
+ * Text: "%s: A parity error occurred on the tape bus\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * A data parity check error occurred on the bus. Data that was read or written
+ * while the error occurred is not valid.
+ * User action:
+ * Reposition the tape and repeat the read-type or write-type operation.
+ */
+
+/*?
+ * Text: "%s: I/O error recovery failed on the tape control unit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * An I/O error occurred that cannot be recovered by the automatic error
+ * recovery process of the tape control unit. The application that operates
+ * the tape unit will receive a return value of -EIO which indicates an
+ * I/O error. The data on the tape might be damaged.
+ * User action:
+ * If this problem occurred during a write-type operation, consider
+ * repositioning the tape and repeating the operation.
+ */
+
+/*?
+ * Text: "%s: The tape unit requires a firmware update\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit requires firmware patches from the tape control unit but the
+ * required patches are not available on the control unit.
+ * User action:
+ * Make the require patches available on the control unit then reposition the
+ * tape and retry the operation. For details about obtaining and installing
+ * firmware updates see the control unit documentation.
+ */
+
+/*?
+ * Text: "%s: The maximum block size for buffered mode is exceeded\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The block to be written is larger than allowed for the buffered mode.
+ * User action:
+ * Use a smaller block size.
+ */
+
+/*?
+ * Text: "%s: A channel interface error cannot be recovered\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * An error has occurred on the channel interface. This error cannot
+ * be recovered by the control unit error recovery process.
+ * User action:
+ * See the documentation of the control unit.
+ */
+
+/*?
+ * Text: "%s: A channel protocol error occurred\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * An error was detected in the channel protocol.
+ * User action:
+ * Reposition the tape and try the operation again.
+ */
+
+/*?
+ * Text: "%s: The tape unit does not support the compaction algorithm\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit cannot read the current tape. The data on the tape has been
+ * compressed with an algorithm that is not supported by the tape unit.
+ * User action:
+ * Use a tape unit that supports the compaction algorithm used for the
+ * current tape.
+ */
+
+/*?
+ * Text: "%s: The tape unit does not support tape format 3480-2 XF\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit does not support tapes recorded in the 3480-2 XF format.
+ * User action:
+ * If you do not need the data recorded on the current tape, rewind the tape
+ * and overwrite it with a supported format. If you need the data on the
+ * current tape, use a tape unit that supports the tape format.
+ */
+
+/*?
+ * Text: "%s: The tape unit does not support format 3480 XF\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit does not support tapes recorded in the 3480 XF format.
+ * User action:
+ * If you do not need the data recorded on the current tape, rewind the tape
+ * and overwrite it with a supported format. If you need the data on the
+ * current tape, use a tape unit that supports the tape format.
+ */
+
+/*?
+ * Text: "%s: The tape unit does not support the current tape length\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The length of the tape in the cartridge is incompatible with the tape unit.
+ * User action:
+ * Either use a different tape unit or use a tape with a supported length.
+ */
+
+/*?
+ * Text: "%s: The tape unit does not support the tape length\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The length of the tape in the cartridge is incompatible with the tape
+ * unit.
+ * User action:
+ * Either use a different tape unit or use a tape with a supported length.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/tape_3590
+++ linux-ein-5.4.0/Documentation/kmsg/s390/tape_3590
@@ -0,0 +1,183 @@
+/*?
+ * Text: "%s: The tape medium must be loaded into a different tape unit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape device has indicated an error condition that requires loading
+ * the tape cartridge into a different tape unit to recover.
+ * User action:
+ * Unload the cartridge and use a different tape unit to retry the operation.
+ */
+
+/*?
+ * Text: "%s: Tape media information: exception %s, service %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: exception
+ *   @3: service
+ * Description:
+ * This is an operating system independent tape medium information message
+ * that was issued by the tape unit. The information in the message is
+ * intended for the IBM customer engineer.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: Device subsystem information: exception %s, service %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: exception
+ *   @3: required service action
+ * Description:
+ * This is an operating system independent device subsystem information message
+ * that was issued by the tape unit. The information in the message is
+ * intended for the IBM customer engineer.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: I/O subsystem information: exception %s, service %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: exception
+ *   @3: required service action
+ * Description:
+ * This is an operating system independent I/O subsystem information message
+ * that was issued by the tape unit. The information in the message is
+ * intended for the IBM customer engineer.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: The tape unit has issued sense message %s\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: sense message code
+ * Description:
+ * The tape unit has issued an operating system independent sense message.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: The tape unit has issued an unknown sense message code 0x%x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: code
+ * Description:
+ * The tape device driver has received an unknown sense message from the
+ * tape unit.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: MIM SEV=%i, MC=%02x, ES=%x/%x, RC=%02x-%04x-%02x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: SEV
+ *   @3: message code
+ *   @4: exception
+ *   @5: required service action
+ *   @6: refcode
+ *   @7: mid
+ *   @8: fid
+ * Description:
+ * This is an operating system independent information message that was
+ * issued by the tape unit. The information in the message is intended for
+ * the IBM customer engineer.
+ * User action:
+ * See to the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: IOSIM SEV=%i, DEVTYPE=3590/%02x, MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: SEV
+ *   @3: model
+ *   @4: message code
+ *   @5: exception
+ *   @6: required service action
+ *   @7: refcode1
+ *   @8: refcode2
+ *   @9: refcode3
+ * Description:
+ * This is an operating system independent I/O subsystem information message
+ * that was issued by the tape unit. The information in the message is
+ * intended for the IBM customer engineer.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: DEVSIM SEV=%i, DEVTYPE=3590/%02x, MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: SEV
+ *   @3: model
+ *   @4: message code
+ *   @5: exception
+ *   @6: required service action
+ *   @7: refcode1
+ *   @8: refcode2
+ *   @9: refcode3
+ * Description:
+ * This is an operating system independent device subsystem information message
+ * issued by the tape unit. The information in the message is intended for
+ * the IBM customer engineer.
+ * User action:
+ * See the documentation for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: The tape unit has issued an unknown sense message code %x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ *   @2: code
+ * Description:
+ * The tape device has issued a sense message, that is unknown to the device
+ * driver.
+ * User action:
+ * Use the message code printed as hexadecimal value and see the documentation
+ * for the tape unit for further information.
+ */
+
+/*?
+ * Text: "%s: The tape unit failed to obtain the encryption key from EKM\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * The tape unit was unable to retrieve the encryption key required to decode
+ * the data on the tape from the enterprise key manager (EKM).
+ * User action:
+ * See the EKM and tape unit documentation for information about how to enable
+ * the tape unit to retrieve the encryption key.
+ */
+
+/*?
+ * Text: "%s: A different host has privileged access to the tape unit\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the tape device
+ * Description:
+ * You cannot access the tape unit because a different operating system
+ * instance has privileged access to the unit.
+ * User action:
+ * Unload the current cartridge to solve this problem.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/time
+++ linux-ein-5.4.0/Documentation/kmsg/s390/time
@@ -0,0 +1,36 @@
+/*?
+ * Text: "The ETR interface has adjusted the clock by %li microseconds\n"
+ * Severity: Notice
+ * Parameter:
+ *   @1: number of microseconds
+ * Description:
+ * The external time reference (ETR) interface has synchronized the system
+ * clock  with the external reference and set it to a new value. The time
+ * difference between the old and new clock value has been passed to the
+ * network time protocol (NTP) as a single shot adjustment.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "The real or virtual hardware system does not provide an ETR interface\n"
+ * Severity: Warning
+ * Description:
+ * The 'etr=' parameter has been passed on the kernel parameter line for
+ * a Linux instance that does not have access to the external time reference
+ * (ETR) facility.
+ * User action:
+ * To avoid this warning remove the 'etr=' kernel parameter.
+ */
+
+/*?
+ * Text: "The real or virtual hardware system does not provide an STP interface\n"
+ * Severity: Warning
+ * Description:
+ * The 'stp=' parameter has been passed on the kernel parameter line for
+ * a Linux instance that does not have access to the server time protocol
+ * (STP) facility.
+ * User action:
+ * To avoid this warning remove the 'stp=' kernel parameter.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/vmlogrdr
+++ linux-ein-5.4.0/Documentation/kmsg/s390/vmlogrdr
@@ -0,0 +1,19 @@
+/*? Text: "vmlogrdr: failed to start recording automatically\n" */
+/*? Text: "vmlogrdr: connection severed with reason %i\n" */
+/*? Text: "vmlogrdr: iucv connection to %s failed with rc %i \n" */
+/*? Text: "vmlogrdr: failed to stop recording automatically\n" */
+/*? Text: "not running under VM, driver not loaded.\n" */
+
+/*?
+ * Text: "vmlogrdr: device %s is busy. Refuse to suspend.\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name
+ * Description:
+ * Suspending vmlogrdr devices that are in uses is not supported.
+ * A request to suspend such a device is refused.
+ * User action:
+ * Close all applications that use any of the vmlogrdr devices
+ * and then try to suspend the system again.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/vmur
+++ linux-ein-5.4.0/Documentation/kmsg/s390/vmur
@@ -0,0 +1,48 @@
+/*?
+ * Text: "The %s cannot be loaded without z/VM\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: z/VM virtual unit record device driver
+ * Description:
+ * The z/VM virtual unit record device driver provides Linux with access to
+ * z/VM virtual unit record devices like punch card readers, card punches, and
+ * line printers. On Linux instances that run in environments other than the
+ * z/VM hypervisor, the device driver does not provide any useful function and
+ * the corresponding vmur module cannot be loaded.
+ * User action:
+ * Load the vmur module only on Linux instances that run as guest operating
+ * systems of the z/VM hypervisor. If the z/VM virtual unit record device
+ * has been compiled into the kernel, ignore this message.
+ */
+
+/*?
+ * Text: "Kernel function alloc_chrdev_region failed with error code %d\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: error code according to errno definitions
+ * Description:
+ * The z/VM virtual unit record device driver (vmur) needs to register a range
+ * of character device minor numbers from 0x0000 to 0xffff.
+ * This registration failed, probably because of memory constraints.
+ * User action:
+ * Free some memory and reload the vmur module. If the z/VM virtual unit
+ * record device driver has been compiled into the kernel reboot Linux.
+ * Consider assigning more memory to your LPAR or z/VM guest virtual machine.
+ */
+
+/*?
+ * Text: "Unit record device %s is busy, %s refusing to suspend.\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the unit record device
+ *   @1: z/VM virtual unit record device driver
+ * Description:
+ * Linux cannot be suspended while a unit record device is in use.
+ * User action:
+ * Stop all applications that work on z/VM spool file queues, for example, the
+ * vmur tool. Then try again to suspend Linux.
+ */
+
+/*? Text: "%s loaded.\n" */
+/*? Text: "%s unloaded.\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/xpram
+++ linux-ein-5.4.0/Documentation/kmsg/s390/xpram
@@ -0,0 +1,74 @@
+/*?
+ * Text: "%d is not a valid number of XPRAM devices\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: number of partitions
+ * Description:
+ * The number of XPRAM partitions specified for the 'devs' module parameter
+ * or with the 'xpram.parts' kernel parameter must be an integer in the
+ * range 1 to 32. The XPRAM device driver created a maximum of 32 partitions
+ * that are probably not configured as intended.
+ * User action:
+ * If the XPRAM device driver has been compiled as a separate module,
+ * unload the module and load it again with a correct value for the 'devs'
+ * module parameter. If the XPRAM device driver has been compiled
+ * into the kernel, correct the 'xpram.parts' parameter in the kernel
+ * command line and restart Linux.
+ */
+
+/*?
+ * Text: "Not enough expanded memory available\n"
+ * Severity: Error
+ * Description:
+ * The amount of expanded memory required to set up your XPRAM partitions
+ * depends on the 'sizes' parameter specified for the xpram module or on
+ * the specifications for the 'xpram.parts' parameter if the XPRAM device
+ * driver has been compiled into the kernel. Your
+ * current specification exceed the amount of available expanded memory.
+ * Your XPRAM partitions are probably not configured as intended.
+ * User action:
+ * If the XPRAM device driver has been compiled as a separate module,
+ * unload the xpram module and load it again with an appropriate value
+ * for the 'sizes' module parameter. If the XPRAM device driver has been
+ * compiled into the kernel, adjust the 'xpram.parts' parameter in the
+ * kernel command line and restart Linux. If you need more than the
+ * available expanded memory, increase the expanded memory allocation for
+ * your virtual hardware or LPAR.
+ */
+
+/*?
+ * Text: "No expanded memory available\n"
+ * Severity: Error
+ * Description:
+ * The XPRAM device driver has been loaded in a Linux instance that runs
+ * in an LPAR or virtual hardware without expanded memory.
+ * No XPRAM partitions are created.
+ * User action:
+ * Allocate expanded memory for your LPAR or virtual hardware or do not
+ * load the xpram module. You can ignore this message, if you do not want
+ * to create XPRAM partitions.
+ */
+
+/*?
+ * Text: "Resuming the system failed: %s\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: cause of the failure
+ * Description:
+ * A system cannot be resumed if the expanded memory setup changes
+ * after hibernation. Possible reasons for the failure are:
+ * - Expanded memory was removed after hibernation.
+ * - Size of the expanded memory changed after hibernation.
+ * The system is stopped with a kernel panic.
+ * User action:
+ * Reboot Linux.
+ */
+
+/*? Text: "  number of devices (partitions): %d \n" */
+/*? Text: "  size of partition %d: %u kB\n" */
+/*? Text: "  size of partition %d to be set automatically\n" */
+/*? Text: "  memory needed (for sized partitions): %lu kB\n" */
+/*? Text: "  partitions to be sized automatically: %d\n" */
+/*? Text: "  automatically determined partition size: %lu kB\n" */
+/*? Text: "  %u pages expanded memory found (%lu KB).\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/zcrypt
+++ linux-ein-5.4.0/Documentation/kmsg/s390/zcrypt
@@ -0,0 +1,22 @@
+/*?
+ * Text: "Cryptographic device %02x.%04x failed and was set offline\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: AP device ID
+ *   @2: AP queue
+ * Description:
+ * A cryptographic device failed to process a cryptographic request.
+ * The cryptographic device driver could not correct the error and
+ * set the device offline. The application that issued the
+ * request received an indication that the request has failed.
+ * User action:
+ * Use the lszcrypt command to confirm that the cryptographic
+ * hardware is still configured to your LPAR or z/VM guest virtual
+ * machine. If the device is available to your Linux instance the
+ * command output contains a line that begins with 'card<device index>',
+ * where <device index> is the two-digit decimal number in the message text.
+ * After ensuring that the device is available, use the chzcrypt command to
+ * set it online again.
+ * If the error persists, contact your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/zdump
+++ linux-ein-5.4.0/Documentation/kmsg/s390/zdump
@@ -0,0 +1,27 @@
+/*?
+ * Text: "The 32-bit dump tool cannot be used for a 64-bit system\n"
+ * Severity: Alert
+ * Description:
+ * The dump process ends without creating a system dump.
+ * User action:
+ * Use a 64-bit dump tool to obtain a system dump for 64-bit Linux instance.
+ */
+/*?
+ * Text: "The 64-bit dump tool cannot be used for a 32-bit system\n"
+ * Severity: Alert
+ * Description:
+ * The dump process ends without creating a system dump.
+ * User action:
+ * Use a 32-bit dump tool to obtain a system dump for 32-bit Linux instance.
+ */
+/*?
+ * Text: "The dump process started for a 64-bit operating system\n"
+ * Severity: Alert
+ * Description:
+ * The SCSI dump process started to create a dump for a 64-bit operating
+ * system instance.
+ * User action:
+ * None.
+ */
+/*? Text: "0x%x is an unknown architecture.\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/zfcp
+++ linux-ein-5.4.0/Documentation/kmsg/s390/zfcp
@@ -0,0 +1,709 @@
+/*?
+ * Text: "%s is not a valid SCSI device\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device specification
+ * Description:
+ * The specification for an initial SCSI device provided with the 'zfcp.device'
+ * kernel parameter or with the 'device' module parameter is syntactically
+ * incorrect. The specified SCSI device could not be attached to the Linux
+ * system.
+ * User action:
+ * Correct the value for the 'zfcp.device' or 'device' parameter and reboot
+ * Linux. See "Device Drivers, Features, and Commands" for information about
+ * the syntax.
+ */
+
+/*?
+ * Text: "The zfcp device driver could not register with the common I/O layer\n"
+ * Severity: Error
+ * Description:
+ * The device driver initialization failed. A possible cause of this problem is
+ * memory constraints.
+ * User action:
+ * Free some memory and try again to load the zfcp device driver. If the zfcp
+ * device driver has been compiled into the kernel, reboot Linux. Consider
+ * assigning more memory to your LPAR or z/VM guest virtual machine. If the
+ * problem persists, contact your support organization.
+ */
+
+/*?
+ * Text: "%s: Setting up data structures for the FCP adapter failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The zfcp device driver could not allocate data structures for an FCP adapter.
+ * A possible reason for this problem is memory constraints.
+ * User action:
+ * Set the FCP adapter offline or detach it from the Linux system, free some
+ * memory and set the FCP adapter online again or attach it again. If this
+ * problem persists, gather Linux debug data, collect the FCP adapter
+ * hardware logs, and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The FCP device is operational again\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * An FCP device has been unavailable because it had been detached from the
+ * Linux system or because the corresponding CHPID was offline. The FCP device
+ * is now available again and the zfcp device driver resumes all operations to
+ * the FCP device.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The CHPID for the FCP device is offline\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The CHPID for an FCP device has been set offline, either logically in Linux
+ * or on the hardware.
+ * User action:
+ * Find out which CHPID corresponds to the FCP device, for example, with the
+ * lscss command. Check if the CHPID has been set logically offline in sysfs.
+ * Write 'on' to the CHPID's status attribute to set it online. If the CHPID is
+ * online in sysfs, find out if it has been varied offline through a hardware
+ * management interface, for example the service element (SE).
+ */
+
+/*?
+ * Text: "%s: The FCP device has been detached\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * An FCP device is no longer available to Linux.
+ * User action:
+ * Ensure that the FCP adapter is operational and attached to the LPAR or z/VM
+ * virtual machine.
+ */
+
+/*?
+ * Text: "%s: The FCP device did not respond within the specified time\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The common I/O layer waited for a response from the FCP adapter but
+ * no response was received within the specified time limit. This might
+ * indicate a hardware problem.
+ * User action:
+ * Consult your hardware administrator. If this problem persists,
+ * gather Linux debug data, collect the FCP adapter hardware logs, and
+ * report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Registering the FCP device with the SCSI stack failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter could not be registered with the Linux SCSI
+ * stack. A possible reason for this problem is memory constraints.
+ * User action:
+ * Set the FCP adapter offline or detach it from the Linux system, free some
+ * memory and set the FCP adapter online again or attach it again. If this
+ * problem persists, gather Linux debug data, collect the FCP adapter
+ * hardware logs, and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: ERP cannot recover an error on the FCP device\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * An error occurred on an FCP device. The error recovery procedure (ERP)
+ * could not resolve the error. The FCP device driver cannot use the FCP device.
+ * User action:
+ * Check for previous error messages for the same FCP device to find the
+ * cause of the problem.
+ */
+
+/*?
+ * Text: "%s: Creating an ERP thread for the FCP device failed.\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The zfcp device driver could not set up error recovery procedure (ERP)
+ * processing for the FCP device. The FCP device is not available for use
+ * in Linux.
+ * User action:
+ * Free some memory and try again to load the zfcp device driver. If the zfcp
+ * device driver has been compiled into the kernel, reboot Linux. Consider
+ * assigning more memory to your LPAR or z/VM guest virtual machine. If the
+ * problem persists, contact your support organization.
+ */
+
+/*?
+ * Text: "%s: ERP failed for LUN 0x%016Lx on port 0x%016Lx\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: LUN
+ *   @3: WWPN
+ * Description:
+ * An error occurred on the SCSI device at the specified LUN. The error recovery
+ * procedure (ERP) could not resolve the error. The SCSI device is not
+ * available.
+ * User action:
+ * Verify that the LUN is correct. Check the fibre channel fabric for errors
+ * related to the specified WWPN and LUN, the storage server, and Linux.
+ */
+
+/*?
+ * Text: "%s: ERP failed for remote port 0x%016Lx\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: WWPN
+ * Description:
+ * An error occurred on a remote port. The error recovery procedure (ERP)
+ * could not resolve the error. The port is not available.
+ * User action:
+ * Verify that the WWPN is correct and check the fibre channel fabric for
+ * errors related to the WWPN.
+ */
+
+/*?
+ * Text: "%s: Registering port 0x%016Lx failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: WWPN
+ * Description:
+ * The Linux kernel could not allocate enough memory to register the
+ * remote port with the indicated WWPN with the SCSI stack. The remote
+ * port is not available.
+ * User action:
+ * Free some memory and trigger the rescan for ports.
+ */
+
+/*?
+ * Text: "%s: A QDIO problem occurred\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * QDIO reported a problem to the zfcp device driver. The zfcp device driver
+ * tries to recover this problem.
+ * User action:
+ * Check for related error messages. If this problem occurs frequently, gather
+ * Linux debug data and contact your support organization.
+ */
+
+/*?
+ * Text: "%s: Setting up the QDIO connection to the FCP adapter failed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The zfcp device driver failed to establish a QDIO connection with the FCP
+ * adapter.
+ * User action:
+ * Set the FCP adapter offline or detach it from the Linux system, free some
+ * memory and set the FCP adapter online again or attach it again. If this
+ * problem persists, gather Linux debug data, collect the FCP adapter
+ * hardware logs, and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter reported a problem that cannot be recovered\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter has a problem that cannot be recovered by the zfcp device
+ * driver. The zfcp device driver stopped using the FCP device.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: There is a wrap plug instead of a fibre channel cable\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter is not physically connected to the fibre channel fabric.
+ * User action:
+ * Remove the wrap plug from the FCP adapter and connect the adapter with the
+ * fibre channel fabric.
+ */
+
+/*?
+ * Text: "%s: FCP device not operational because of an unsupported FC class\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter hardware does not support the fibre channel service class
+ * requested by the zfcp device driver. This problem indicates a program error
+ * in the zfcp device driver.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: 0x%Lx is an ambiguous request identifier\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: request ID
+ * Description:
+ * The FCP adapter reported that it received the same request ID twice. This is
+ * an error. The zfcp device driver stopped using the FCP device.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: QTCB version 0x%x not supported by FCP adapter (0x%x to 0x%x)\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: requested version
+ *   @3: lowest supported version
+ *   @4: highest supported version
+ * Description:
+ * See message text.
+ * The queue transfer control block (QTCB) version requested by the zfcp device
+ * driver is not supported by the FCP adapter hardware.
+ * User action:
+ * If the requested version is higher than the highest version supported by the
+ * hardware, install more recent firmware on the FCP adapter. If the requested
+ * version is lower then the lowest version supported by the hardware, upgrade
+ * to a Linux level with a more recent zfcp device driver.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter could not log in to the fibre channel fabric\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The fibre channel switch rejected the login request from the FCP adapter.
+ * User action:
+ * Check the fibre channel fabric or switch logs for possible errors.
+ */
+
+/*?
+ * Text: "%s: The FCP device is suspended because of a firmware update\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP device is not available while a firmware update is in progress. This
+ * problem is temporary. The FCP device will resume operations when the
+ * firmware update is completed.
+ * User action:
+ * Wait 10 seconds and try the operation again.
+ */
+
+/*?
+ * Text: "%s: All NPIV ports on the FCP adapter have been assigned\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The number of N_Port ID Virtualization (NPIV) ports that can be assigned
+ * on an FCP adapter is limited. Once assigned, NPIV ports are not released
+ * automatically but have to be released explicitly through the support
+ * element (SE).
+ * User action:
+ * Identify NPIV ports that have been assigned but are no longer in use and
+ * release them from the SE.
+ */
+
+/*?
+ * Text: "%s: The link between the FCP adapter and the FC fabric is down\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter is not usable. Specific error information is not available.
+ * User action:
+ * Check the cabling and the fibre channel fabric configuration. If this
+ * problem persists, gather Linux debug data, collect the FCP adapter
+ * hardware logs, and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The QTCB type is not supported by the FCP adapter\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The queue transfer control block (QTCB) type requested by the zfcp device
+ * driver is not supported by the FCP adapter hardware.
+ * User action:
+ * Install the latest firmware on your FCP adapter hardware. If this does not
+ * resolve the problem, upgrade to a Linux level with a more recent zfcp device
+ * driver. If the problem persists, contact your support organization.
+ */
+
+/*?
+ * Text: "%s: The error threshold for checksum statistics has been exceeded\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter has reported a large number of bit errors. This might
+ * indicate a problem with the physical components of the fibre channel fabric.
+ * Details about the errors have been written to the HBA trace for the FCP
+ * adapter.
+ * User action:
+ * Check for problems in the fibre channel fabric and ensure that all cables
+ * are properly plugged.
+ */
+
+/*?
+ * Text: "%s: The local link has been restored\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * A problem with the connection between the FCP adapter and the adjacent node
+ * on the fibre channel fabric has been resolved. The FCP adapter is now
+ * available again.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: The mode table on the FCP adapter has been damaged\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * This is an FCP adapter hardware problem.
+ * User action:
+ * Report this problem with FCP hardware logs to IBM support.
+ */
+
+/*?
+ * Text: "%s: The adjacent fibre channel node does not support FCP\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The fibre channel switch or storage system that is connected to the FCP
+ * channel does not support the fibre channel protocol (FCP). The zfcp
+ * device driver stopped using the FCP device.
+ * User action:
+ * Check the adjacent fibre channel node.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter does not recognize the command 0x%x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: command
+ * Description:
+ * A command code that was sent from the zfcp device driver to the FCP adapter
+ * is not valid. The zfcp device driver stopped using the FCP device.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: There is no light signal from the local fibre channel cable\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * There is no signal on the fibre channel cable that connects the FCP adapter
+ * to the fibre channel fabric.
+ * User action:
+ * Ensure that the cable is in place and connected properly to the FCP adapter
+ * and to the adjacent fibre channel switch or storage system.
+ */
+
+/*?
+ * Text: "%s: The WWPN assignment file on the FCP adapter has been damaged\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * This is an FCP adapter hardware problem.
+ * User action:
+ * Report this problem with FCP hardware logs to IBM support.
+ */
+
+/*?
+ * Text: "%s: The FCP device detected a WWPN that is duplicate or not valid\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * This condition indicates an error in the FCP adapter hardware or in the z/VM
+ * hypervisor.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to IBM support.
+ */
+
+/*?
+ * Text: "%s: The fibre channel fabric does not support NPIV\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP adapter requires N_Port ID Virtualization (NPIV) from the adjacent
+ * fibre channel node. Either the FCP adapter is connected to a fibre channel
+ * switch that does not support NPIV or the FCP adapter tries to use NPIV in a
+ * point-to-point setup. The connection is not operational.
+ * User action:
+ * Verify that NPIV is correctly used for this connection. Check the FCP adapter
+ * configuration and the fibre channel switch configuration. If necessary,
+ * update the fibre channel switch firmware.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter cannot support more NPIV ports\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * N_Port ID Virtualization (NPIV) ports consume physical resources on the FCP
+ * adapter. The FCP adapter resources are exhausted. The connection is not
+ * operational.
+ * User action:
+ * Analyze the number of available NPIV ports and which operating system
+ * instances use them. If necessary, reconfigure your setup to move some
+ * NPIV ports to an FCP adapter with free resources.
+ */
+
+/*?
+ * Text: "%s: The adjacent switch cannot support more NPIV ports\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * N_Port ID Virtualization (NPIV) ports consume physical resources. The
+ * resources of the fibre channel switch that is connected to the FCP adapter
+ * are exhausted. The connection is not operational.
+ * User action:
+ * Analyze the number of available NPIV ports on the adjacent fibre channel
+ * switch and how they are used. If necessary, reconfigure your fibre channel
+ * fabric to accommodate the required NPIV ports.
+ */
+
+/*?
+ * Text: "%s: 0x%x is not a valid transfer protocol status\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: status information
+ * Description:
+ * The transfer protocol status information reported by the FCP adapter is not
+ * a valid status for the zfcp device driver. The zfcp device driver stopped
+ * using the FCP device.
+ * User action:
+ * Gather Linux debug data, collect the FCP adapter hardware logs, and report
+ * this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Unknown or unsupported arbitrated loop fibre channel topology detected\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The FCP device is connected to a fibre channel arbitrated loop or the FCP adapter
+ * reported an unknown fibre channel topology. The zfcp device driver supports
+ * point-to-point connections and switched fibre channel fabrics but not arbitrated
+ * loop topologies. The FCP device cannot be used.
+ * User action:
+ * Check the fibre channel setup and ensure that only supported topologies are
+ * connected to the FCP adapter.
+ */
+
+/*?
+ * Text: "%s: FCP adapter maximum QTCB size (%d bytes) is too small\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: maximum supported size
+ *   @3: requested QTCB size
+ * Description:
+ * The queue transfer control block (QTCB) size requested by the zfcp
+ * device driver is not supported by the FCP adapter hardware.
+ * User action:
+ * Update the firmware on your FCP adapter hardware to the latest
+ * available level and update the Linux kernel to the latest supported
+ * level. If the problem persists, contact your support organization.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter only supports newer control block versions\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The protocol supported by the FCP adapter is not compatible with the zfcp
+ * device driver.
+ * User action:
+ * Upgrade your Linux kernel to a level that includes a zfcp device driver
+ * with support for the control block version required by your FCP adapter.
+ */
+
+/*?
+ * Text: "%s: The FCP adapter only supports older control block versions\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ * Description:
+ * The protocol supported by the FCP adapter is not compatible with the zfcp
+ * device driver.
+ * User action:
+ * Install the latest firmware on your FCP adapter.
+ */
+
+/*?
+ * Text: "%s: Not enough FCP adapter resources to open remote port 0x%016Lx\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: WWPN
+ * Description:
+ * Each port that is opened consumes physical resources of the FCP adapter to
+ * which it is attached. These resources are exhausted and the specified port
+ * cannot be opened.
+ * User action:
+ * Reduce the total number of remote ports that are attached to the
+ * FCP adapter.
+ */
+
+/*?
+ * Text: "%s: LUN 0x%Lx on port 0x%Lx is already in use by CSS%d, MIF Image ID %x\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: LUN
+ *   @3: remote port WWPN
+ *   @4: channel subsystem ID
+ *   @5: MIF Image ID of the LPAR
+ * Description:
+ * The SCSI device at the indicated LUN is already in use by another system.
+ * Only one system at a time can use the SCSI device.
+ * User action:
+ * Ensure that the other system stops using the device before trying to use it.
+ */
+
+/*?
+ * Text: "%s: No handle is available for LUN 0x%016Lx on port 0x%016Lx\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: LUN
+ *   @3: WWPN
+ * Description:
+ * The FCP adapter can only open a limited number of SCSI devices. This limit
+ * has been reached and the SCSI device at the indicated LUN cannot be opened.
+ * User action:
+ * For FCP subchannels running in non-NPIV mode, check all SCSI
+ * devices opened through the FCP adapter and close some of them.  For
+ * FCP subchannels running in NPIV mode, verify the SAN zoning and
+ * host connections on the storage systems. Ensure that the zoning and
+ * host connections only allow access to the required LUNs. As a
+ * workaround, disable the automatic LUN scanning by setting the
+ * zfcp.allow_lun_scan kernel parameter or the allow_lun_scan module
+ * parameter to 0.
+ */
+
+/*?
+ * Text: "%s: Incorrect direction %d, LUN 0x%016Lx on port 0x%016Lx closed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: value in direction field
+ *   @3: LUN
+ *   @4: WWPN
+ * Description:
+ * The direction field in a SCSI request contains an incorrect value. The zfcp
+ * device driver closed down the SCSI device at the indicated LUN.
+ * User action:
+ * Gather Linux debug data and report this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Incorrect CDB length %d, LUN 0x%016Lx on port 0x%016Lx closed\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: value in length field
+ *   @3: LUN
+ *   @4: WWPN
+ * Description:
+ * The control-data-block (CDB) length field in a SCSI request is not valid or
+ * too large for the FCP adapter. The zfcp device driver closed down the SCSI
+ * device at the indicated LUN.
+ * User action:
+ * Gather Linux debug data and report this problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: Opening WKA port 0x%x failed\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: destination ID of the WKA port
+ * Description:
+ * The FCP adapter rejected a request to open the specified
+ * well-known address (WKA) port. No retry is possible.
+ * User action:
+ * Verify the setup and check if the maximum number of remote ports
+ * used through this adapter is below the maximum allowed. If the
+ * problem persists, gather Linux debug data, collect the FCP adapter
+ * hardware logs, and report the problem to your support organization.
+ */
+
+/*?
+ * Text: "%s: The name server reported %d words residual data\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: number of words in residual data
+ * Description:
+ * The fibre channel name server sent too much information about remote ports.
+ * The zfcp device driver did not receive sufficient information to attach all
+ * available remote ports in the SAN.
+ * User action:
+ * Verify that you are running the latest firmware level on the FCP
+ * adapter. Check your SAN setup and consider reducing the number of ports
+ * visible to the FCP adapter by using more restrictive zoning in the SAN.
+ */
+
+/*?
+ * Text: "%s: A port opened with WWPN 0x%016Lx returned data that identifies it as WWPN 0x%016Lx\n"
+ * Severity: Warning
+ * Parameter:
+ *   @1: bus ID of the zfcp device
+ *   @2: expected WWPN
+ *   @3: reported WWPN
+ * Description:
+ * A remote port was opened successfully, but it reported an
+ * unexpected WWPN in the returned port login (PLOGI) data. This
+ * condition might have been caused by a change applied to the SAN
+ * configuration while the port was being opened.
+ * User action:
+ * If this condition is only temporary and access to the remote port
+ * is possible, no action is required. If the condition persists,
+ * identify the storage system with the specified WWPN and contact the
+ * support organization of the storage system.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/s390/zpci
+++ linux-ein-5.4.0/Documentation/kmsg/s390/zpci
@@ -0,0 +1,42 @@
+/*?
+ * Text: "%s: Event 0x%x reconfigured PCI function 0x%x\n"
+ * Severity: Informational
+ * Parameter:
+ *   @1: device name of the function
+ *   @2: PCI event code
+ *   @3: function ID
+ * Description:
+ * The availability of a PCI function has changed.
+ * Possible reasons for the change include PCI configuration actions on the
+ * Hardware Management Console or hypervisor.
+ * For shared PCI functions, the function might also have been reserved or
+ * released by another system.
+ * If the device name of a function is shown as 'n/a', the device registration
+ * with the PCI device driver has not completed.
+ * The function ID identifies the function to the I/O configuration (IOCDS).
+ * The PCI event code can be useful diagnostic information for your support
+ * organization.
+ * User action:
+ * None.
+ */
+
+/*?
+ * Text: "%s: Event 0x%x reports an error for PCI function 0x%x\n"
+ * Severity: Error
+ * Parameter:
+ *   @1: device name of the function
+ *   @2: PCI event code
+ *   @3: function ID
+ * Description:
+ * A PCI function entered an error state from which it cannot recover
+ * automatically.
+ * User action:
+ * Trigger a recovery action by writing '1' to the 'recover' sysfs attribute
+ * of the PCI function.
+ * In sysfs, PCI functions are represented as /sys/bus/pci/devices/<name>,
+ * where <name> is the device name of the function.
+ * If the device name of a function is shown as 'n/a', the device
+ * registration with the PCI device driver has not completed.
+ * If the problem persists, contact your support organization.
+ */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
--- linux-ein-5.4.0.orig/Documentation/kmsg/sbp_target
+++ linux-ein-5.4.0/Documentation/kmsg/sbp_target
@@ -0,0 +1,49 @@
+/*? Text: "ABORT TASK SET not implemented\n" */
+/*? Text: "ABORT TASK not implemented\n" */
+/*? Text: "Cannot change the directory_id on an active target.\n" */
+/*? Text: "Cannot enable a target with no LUNs!\n" */
+/*? Text: "Could not update Config ROM\n" */
+/*? Text: "Ignoring ORB_POINTER write while active.\n" */
+/*? Text: "LOGICAL UNIT RESET not implemented\n" */
+/*? Text: "Node ACL not found for %s\n" */
+/*? Text: "Only one TPG per Unit is possible.\n" */
+/*? Text: "QUERY LOGINS not implemented\n" */
+/*? Text: "Reconnect timer expired for node: %016llx\n" */
+/*? Text: "SET PASSWORD not implemented\n" */
+/*? Text: "TARGET RESET not implemented\n" */
+/*? Text: "Unable to allocate struct sbp_nacl\n" */
+/*? Text: "Unable to allocate struct sbp_tpg\n" */
+/*? Text: "Unable to allocate struct sbp_tport\n" */
+/*? Text: "Waiting for reconnect from node: %016llx\n" */
+/*? Text: "cannot find login: %d\n" */
+/*? Text: "failed to allocate login descriptor\n" */
+/*? Text: "failed to allocate login response block\n" */
+/*? Text: "failed to allocate session descriptor\n" */
+/*? Text: "failed to init se_session\n" */
+/*? Text: "failed to map command block handler: %d\n" */
+/*? Text: "failed to read peer GUID: %d\n" */
+/*? Text: "ignoring management request while busy\n" */
+/*? Text: "ignoring request from foreign node (%x != %x)\n" */
+/*? Text: "ignoring request with wrong generation\n" */
+/*? Text: "initiator already logged-in\n" */
+/*? Text: "login to unknown LUN: %d\n" */
+/*? Text: "logout from different node ID\n" */
+/*? Text: "max number of logins reached\n" */
+/*? Text: "mgt_agent LOGIN to LUN %d from %016llx\n" */
+/*? Text: "mgt_agent LOGOUT from LUN %d session %d\n" */
+/*? Text: "mgt_agent RECONNECT from %016llx\n" */
+/*? Text: "mgt_agent RECONNECT login GUID doesn't match\n" */
+/*? Text: "mgt_agent RECONNECT unknown login ID\n" */
+/*? Text: "mgt_orb bad request\n" */
+/*? Text: "netif_stop_queue() cannot be called before register_netdev()\n" */
+/*? Text: "refusing exclusive login with other active logins\n" */
+/*? Text: "refusing login while another exclusive login present\n" */
+/*? Text: "sbp_run_transaction: page size ignored\n" */
+/*? Text: "sbp_send_sense: unknown sense format: 0x%x\n" */
+/*? Text: "target_fabric_configfs_init() failed\n" */
+/*? Text: "target_fabric_configfs_register() failed for SBP\n" */
+/*? Text: "unknown management function 0x%x\n" */
+/*? Text: "unlink LUN: failed to update unit directory\n" */
+/*? Text: "flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n" */
+/*? Text: "%s selects TX queue %d, but real number of TX queues is %d\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
\ No newline at end of file
--- linux-ein-5.4.0.orig/Documentation/kmsg/zram
+++ linux-ein-5.4.0/Documentation/kmsg/zram
@@ -0,0 +1,34 @@
+/*? Text: "Error allocating compressor buffer space\n" */
+/*? Text: "Error allocating memory for compressed page: %u, size=%zu\n" */
+/*? Text: "Error creating memory pool\n" */
+/*? Text: "num_devices not specified. Using default: 1\n" */
+/*? Text: "Error allocating compressor working memory!\n" */
+/*? Text: "Error allocating zram address table\n" */
+/*? Text: "Unable to get major number\n" */
+/*? Text: "Compression failed! err=%d\n" */
+/*? Text: "Decompression failed! err=%d, page=%u\n" */
+/*? Text: "There is little point creating a zram of greater than twice the size of memory since we expect a 2:1 compression ratio. Note that zram uses about 0.1%% of the size of the disk when not in use so a huge zram is wasteful.\n\tMemory Size: %zu kB\n\tSize you selected: %llu kB\nContinuing anyway ...\n" */
+/*? Text: "disk size not provided. You can use disksize_kb module param to specify size.\nUsing default: (%u%% of RAM).\n" */
+/*? Text: "Error creating sysfs group" */
+/*? Text: "Error allocating memory for incompressible page: %u\n" */
+/*? Text: "Creating %u devices ...\n" */
+/*? Text: "Initialization failed: err=%d\n" */
+/*? Text: "Error allocating disk queue for device %d\n" */
+/*? Text: "Error allocating disk structure for device %d\n" */
+/*? Text: "Invalid value for num_devices: %u\n" */
+/*? Text: "Error allocating temp memory!\n" */
+/*? Text: "Unable to allocate temp memory\n" */
+/*? Text: "Created %u device(s) ...\n" */
+/*? Text: "There is little point creating a zram of greater than twice the size of memory since we expect a 2:1 compression ratio. Note that zram uses about 0.1%% of the size of the disk when not in use so a huge zram is wasteful.\n\tMemory Size: %lu kB\n\tSize you selected: %llu kB\nContinuing anyway ...\n" */
+/*? Text: "Cannot change disksize for initialized device\n" */
+/*? Text: "Can't change algorithm for initialized device\n" */
+/*? Text: "Cannot initialise %s compressing backend\n" */
+/*? Text: "Cannot change max compression streams\n" */
+/*? Text: "Destroyed %u device(s)\n" */
+/*? Text: "Created %u device(s)\n" */
+/*? Text: "Unable to register zram-control class\n" */
+/*? Text: "Removed device: %s\n" */
+/*? Text: "Added device: %s\n" */
+/*? Text: "Error creating sysfs group for device %d\n" */
+/*? Text: "Error allocating memory for compressed page: %u, size=%u\n" */
+/*? Text: "%s: %d output lines suppressed due to ratelimiting\n" */
\ No newline at end of file
--- linux-ein-5.4.0.orig/Documentation/lzo.txt
+++ linux-ein-5.4.0/Documentation/lzo.txt
@@ -159,11 +159,15 @@
            distance = 16384 + (H << 14) + D
            state = S (copy S literals after this block)
            End of stream is reached if distance == 16384
+           In version 1 only, to prevent ambiguity with the RLE case when
+           ((distance & 0x803f) == 0x803f) && (261 <= length <= 264), the
+           compressor must not emit block copies where distance and length
+           meet these conditions.
 
         In version 1 only, this instruction is also used to encode a run of
-        zeros if distance = 0xbfff, i.e. H = 1 and the D bits are all 1.
+           zeros if distance = 0xbfff, i.e. H = 1 and the D bits are all 1.
            In this case, it is followed by a fourth byte, X.
-           run length = ((X << 3) | (0 0 0 0 0 L L L)) + 4.
+           run length = ((X << 3) | (0 0 0 0 0 L L L)) + 4
 
       0 0 1 L L L L L  (32..63)
            Copy of small block within 16kB distance (preferably less than 34B)
--- linux-ein-5.4.0.orig/Documentation/media/uapi/v4l/colorspaces-defs.rst
+++ linux-ein-5.4.0/Documentation/media/uapi/v4l/colorspaces-defs.rst
@@ -36,8 +36,7 @@
 :c:type:`v4l2_hsv_encoding` specifies which encoding is used.
 
 .. note:: The default R'G'B' quantization is full range for all
-   colorspaces except for BT.2020 which uses limited range R'G'B'
-   quantization.
+   colorspaces. HSV formats are always full range.
 
 .. tabularcolumns:: |p{6.7cm}|p{10.8cm}|
 
@@ -169,8 +168,8 @@
       - Details
     * - ``V4L2_QUANTIZATION_DEFAULT``
       - Use the default quantization encoding as defined by the
-	colorspace. This is always full range for R'G'B' (except for the
-	BT.2020 colorspace) and HSV. It is usually limited range for Y'CbCr.
+	colorspace. This is always full range for R'G'B' and HSV.
+	It is usually limited range for Y'CbCr.
     * - ``V4L2_QUANTIZATION_FULL_RANGE``
       - Use the full range quantization encoding. I.e. the range [0…1] is
 	mapped to [0…255] (with possible clipping to [1…254] to avoid the
@@ -180,4 +179,4 @@
     * - ``V4L2_QUANTIZATION_LIM_RANGE``
       - Use the limited range quantization encoding. I.e. the range [0…1]
 	is mapped to [16…235]. Cb and Cr are mapped from [-0.5…0.5] to
-	[16…240].
+	[16…240]. Limited Range cannot be used with HSV.
--- linux-ein-5.4.0.orig/Documentation/media/uapi/v4l/colorspaces-details.rst
+++ linux-ein-5.4.0/Documentation/media/uapi/v4l/colorspaces-details.rst
@@ -377,9 +377,8 @@
 The :ref:`itu2020` standard defines the colorspace used by Ultra-high
 definition television (UHDTV). The default transfer function is
 ``V4L2_XFER_FUNC_709``. The default Y'CbCr encoding is
-``V4L2_YCBCR_ENC_BT2020``. The default R'G'B' quantization is limited
-range (!), and so is the default Y'CbCr quantization. The chromaticities
-of the primary colors and the white reference are:
+``V4L2_YCBCR_ENC_BT2020``. The default Y'CbCr quantization is limited range.
+The chromaticities of the primary colors and the white reference are:
 
 
 
--- linux-ein-5.4.0.orig/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst
+++ linux-ein-5.4.0/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst
@@ -17,7 +17,8 @@
 ===========
 
 Similar to the packed RGB formats these formats store the Y, Cb and Cr
-component of each pixel in one 16 or 32 bit word.
+component of each pixel next to each other in memory. They occupy 16, 24 or 32
+bits per pixel.
 
 
 .. raw:: latex
@@ -154,9 +155,40 @@
       - Cb\ :sub:`5`
       - Cb\ :sub:`4`
       - Cb\ :sub:`3`
-
       -  :cspan:`15`
+      -
+    * .. _V4L2-PIX-FMT-YUV24:
+
+      - ``V4L2_PIX_FMT_YUV24``
+      - 'YUV3'
+
+      - Y'\ :sub:`7`
+      - Y'\ :sub:`6`
+      - Y'\ :sub:`5`
+      - Y'\ :sub:`4`
+      - Y'\ :sub:`3`
+      - Y'\ :sub:`2`
+      - Y'\ :sub:`1`
+      - Y'\ :sub:`0`
+
+      - Cb\ :sub:`7`
+      - Cb\ :sub:`6`
+      - Cb\ :sub:`5`
+      - Cb\ :sub:`4`
+      - Cb\ :sub:`3`
+      - Cb\ :sub:`2`
+      - Cb\ :sub:`1`
+      - Cb\ :sub:`0`
 
+      - Cr\ :sub:`7`
+      - Cr\ :sub:`6`
+      - Cr\ :sub:`5`
+      - Cr\ :sub:`4`
+      - Cr\ :sub:`3`
+      - Cr\ :sub:`2`
+      - Cr\ :sub:`1`
+      - Cr\ :sub:`0`
+      -
     * .. _V4L2-PIX-FMT-YUV32:
 
       - ``V4L2_PIX_FMT_YUV32``
--- linux-ein-5.4.0.orig/Documentation/media/uapi/v4l/subdev-formats.rst
+++ linux-ein-5.4.0/Documentation/media/uapi/v4l/subdev-formats.rst
@@ -7794,3 +7794,30 @@
       - 0x5001
       - Interleaved raw UYVY and JPEG image format with embedded meta-data
 	used by Samsung S3C73MX camera sensors.
+
+.. _v4l2-mbus-metadata-fmts:
+
+Metadata Formats
+^^^^^^^^^^^^^^^^
+
+This section lists all metadata formats.
+
+The following table lists the existing metadata formats.
+
+.. tabularcolumns:: |p{8.0cm}|p{1.4cm}|p{7.7cm}|
+
+.. flat-table:: Metadata formats
+    :header-rows:  1
+    :stub-columns: 0
+
+    * - Identifier
+      - Code
+      - Comments
+    * .. _MEDIA-BUS-FMT-METADATA-FIXED:
+
+      - MEDIA_BUS_FMT_METADATA_FIXED
+      - 0x7001
+      - This format should be used when the same driver handles
+	both sides of the link and the bus format is a fixed
+	metadata format that is not configurable from userspace.
+	Width and height will be set to 0 for this format.
--- linux-ein-5.4.0.orig/Documentation/networking/af_xdp.rst
+++ linux-ein-5.4.0/Documentation/networking/af_xdp.rst
@@ -40,13 +40,13 @@
 appropriate (malloc, mmap, huge pages, etc). This memory area is then
 registered with the kernel using the new setsockopt XDP_UMEM_REG. The
 UMEM also has two rings: the FILL ring and the COMPLETION ring. The
-fill ring is used by the application to send down addr for the kernel
+FILL ring is used by the application to send down addr for the kernel
 to fill in with RX packet data. References to these frames will then
 appear in the RX ring once each packet has been received. The
-completion ring, on the other hand, contains frame addr that the
+COMPLETION ring, on the other hand, contains frame addr that the
 kernel has transmitted completely and can now be used again by user
 space, for either TX or RX. Thus, the frame addrs appearing in the
-completion ring are addrs that were previously transmitted using the
+COMPLETION ring are addrs that were previously transmitted using the
 TX ring. In summary, the RX and FILL rings are used for the RX path
 and the TX and COMPLETION rings are used for the TX path.
 
@@ -91,11 +91,16 @@
 ========
 
 In order to use an AF_XDP socket, a number of associated objects need
-to be setup.
+to be setup. These objects and their options are explained in the
+following sections.
 
-Jonathan Corbet has also written an excellent article on LWN,
-"Accelerating networking with AF_XDP". It can be found at
-https://lwn.net/Articles/750845/.
+For an overview on how AF_XDP works, you can also take a look at the
+Linux Plumbers paper from 2018 on the subject:
+http://vger.kernel.org/lpc_net2018_talks/lpc18_paper_af_xdp_perf-v2.pdf. Do
+NOT consult the paper from 2017 on "AF_PACKET v4", the first attempt
+at AF_XDP. Nearly everything changed since then. Jonathan Corbet has
+also written an excellent article on LWN, "Accelerating networking
+with AF_XDP". It can be found at https://lwn.net/Articles/750845/.
 
 UMEM
 ----
@@ -113,22 +118,22 @@
 struct sockaddr_xdp member sxdp_flags, and passing the file descriptor
 of A to struct sockaddr_xdp member sxdp_shared_umem_fd.
 
-The UMEM has two single-producer/single-consumer rings, that are used
+The UMEM has two single-producer/single-consumer rings that are used
 to transfer ownership of UMEM frames between the kernel and the
 user-space application.
 
 Rings
 -----
 
-There are a four different kind of rings: Fill, Completion, RX and
+There are a four different kind of rings: FILL, COMPLETION, RX and
 TX. All rings are single-producer/single-consumer, so the user-space
 application need explicit synchronization of multiple
 processes/threads are reading/writing to them.
 
-The UMEM uses two rings: Fill and Completion. Each socket associated
+The UMEM uses two rings: FILL and COMPLETION. Each socket associated
 with the UMEM must have an RX queue, TX queue or both. Say, that there
 is a setup with four sockets (all doing TX and RX). Then there will be
-one Fill ring, one Completion ring, four TX rings and four RX rings.
+one FILL ring, one COMPLETION ring, four TX rings and four RX rings.
 
 The rings are head(producer)/tail(consumer) based rings. A producer
 writes the data ring at the index pointed out by struct xdp_ring
@@ -146,7 +151,7 @@
 UMEM Fill Ring
 ~~~~~~~~~~~~~~
 
-The Fill ring is used to transfer ownership of UMEM frames from
+The FILL ring is used to transfer ownership of UMEM frames from
 user-space to kernel-space. The UMEM addrs are passed in the ring. As
 an example, if the UMEM is 64k and each chunk is 4k, then the UMEM has
 16 chunks and can pass addrs between 0 and 64k.
@@ -164,8 +169,8 @@
 UMEM Completion Ring
 ~~~~~~~~~~~~~~~~~~~~
 
-The Completion Ring is used transfer ownership of UMEM frames from
-kernel-space to user-space. Just like the Fill ring, UMEM indicies are
+The COMPLETION Ring is used transfer ownership of UMEM frames from
+kernel-space to user-space. Just like the FILL ring, UMEM indices are
 used.
 
 Frames passed from the kernel to user-space are frames that has been
@@ -181,7 +186,7 @@
 is a struct xdp_desc descriptor. The descriptor contains UMEM offset
 (addr) and the length of the data (len).
 
-If no frames have been passed to kernel via the Fill ring, no
+If no frames have been passed to kernel via the FILL ring, no
 descriptors will (or can) appear on the RX ring.
 
 The user application consumes struct xdp_desc descriptors from this
@@ -199,8 +204,24 @@
 The user application produces struct xdp_desc descriptors to this
 ring.
 
+Libbpf
+======
+
+Libbpf is a helper library for eBPF and XDP that makes using these
+technologies a lot simpler. It also contains specific helper functions
+in tools/lib/bpf/xsk.h for facilitating the use of AF_XDP. It
+contains two types of functions: those that can be used to make the
+setup of AF_XDP socket easier and ones that can be used in the data
+plane to access the rings safely and quickly. To see an example on how
+to use this API, please take a look at the sample application in
+samples/bpf/xdpsock_usr.c which uses libbpf for both setup and data
+plane operations.
+
+We recommend that you use this library unless you have become a power
+user. It will make your program a lot simpler.
+
 XSKMAP / BPF_MAP_TYPE_XSKMAP
-----------------------------
+============================
 
 On XDP side there is a BPF map type BPF_MAP_TYPE_XSKMAP (XSKMAP) that
 is used in conjunction with bpf_redirect_map() to pass the ingress
@@ -216,21 +237,193 @@
 successfully pass data to the socket. Please refer to the sample
 application (samples/bpf/) in for an example.
 
+Configuration Flags and Socket Options
+======================================
+
+These are the various configuration flags that can be used to control
+and monitor the behavior of AF_XDP sockets.
+
+XDP_COPY and XDP_ZERO_COPY bind flags
+-------------------------------------
+
+When you bind to a socket, the kernel will first try to use zero-copy
+copy. If zero-copy is not supported, it will fall back on using copy
+mode, i.e. copying all packets out to user space. But if you would
+like to force a certain mode, you can use the following flags. If you
+pass the XDP_COPY flag to the bind call, the kernel will force the
+socket into copy mode. If it cannot use copy mode, the bind call will
+fail with an error. Conversely, the XDP_ZERO_COPY flag will force the
+socket into zero-copy mode or fail.
+
+XDP_SHARED_UMEM bind flag
+-------------------------
+
+This flag enables you to bind multiple sockets to the same UMEM, but
+only if they share the same queue id. In this mode, each socket has
+their own RX and TX rings, but the UMEM (tied to the fist socket
+created) only has a single FILL ring and a single COMPLETION
+ring. To use this mode, create the first socket and bind it in the normal
+way. Create a second socket and create an RX and a TX ring, or at
+least one of them, but no FILL or COMPLETION rings as the ones from
+the first socket will be used. In the bind call, set he
+XDP_SHARED_UMEM option and provide the initial socket's fd in the
+sxdp_shared_umem_fd field. You can attach an arbitrary number of extra
+sockets this way.
+
+What socket will then a packet arrive on? This is decided by the XDP
+program. Put all the sockets in the XSK_MAP and just indicate which
+index in the array you would like to send each packet to. A simple
+round-robin example of distributing packets is shown below:
+
+.. code-block:: c
+
+   #include <linux/bpf.h>
+   #include "bpf_helpers.h"
+
+   #define MAX_SOCKS 16
+
+   struct {
+        __uint(type, BPF_MAP_TYPE_XSKMAP);
+        __uint(max_entries, MAX_SOCKS);
+        __uint(key_size, sizeof(int));
+        __uint(value_size, sizeof(int));
+   } xsks_map SEC(".maps");
+
+   static unsigned int rr;
+
+   SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
+   {
+	rr = (rr + 1) & (MAX_SOCKS - 1);
+
+	return bpf_redirect_map(&xsks_map, rr, 0);
+   }
+
+Note, that since there is only a single set of FILL and COMPLETION
+rings, and they are single producer, single consumer rings, you need
+to make sure that multiple processes or threads do not use these rings
+concurrently. There are no synchronization primitives in the
+libbpf code that protects multiple users at this point in time.
+
+XDP_USE_NEED_WAKEUP bind flag
+-----------------------------
+
+This option adds support for a new flag called need_wakeup that is
+present in the FILL ring and the TX ring, the rings for which user
+space is a producer. When this option is set in the bind call, the
+need_wakeup flag will be set if the kernel needs to be explicitly
+woken up by a syscall to continue processing packets. If the flag is
+zero, no syscall is needed.
+
+If the flag is set on the FILL ring, the application needs to call
+poll() to be able to continue to receive packets on the RX ring. This
+can happen, for example, when the kernel has detected that there are no
+more buffers on the FILL ring and no buffers left on the RX HW ring of
+the NIC. In this case, interrupts are turned off as the NIC cannot
+receive any packets (as there are no buffers to put them in), and the
+need_wakeup flag is set so that user space can put buffers on the
+FILL ring and then call poll() so that the kernel driver can put these
+buffers on the HW ring and start to receive packets.
+
+If the flag is set for the TX ring, it means that the application
+needs to explicitly notify the kernel to send any packets put on the
+TX ring. This can be accomplished either by a poll() call, as in the
+RX path, or by calling sendto().
+
+An example of how to use this flag can be found in
+samples/bpf/xdpsock_user.c. An example with the use of libbpf helpers
+would look like this for the TX path:
+
+.. code-block:: c
+
+   if (xsk_ring_prod__needs_wakeup(&my_tx_ring))
+      sendto(xsk_socket__fd(xsk_handle), NULL, 0, MSG_DONTWAIT, NULL, 0);
+
+I.e., only use the syscall if the flag is set.
+
+We recommend that you always enable this mode as it usually leads to
+better performance especially if you run the application and the
+driver on the same core, but also if you use different cores for the
+application and the kernel driver, as it reduces the number of
+syscalls needed for the TX path.
+
+XDP_{RX|TX|UMEM_FILL|UMEM_COMPLETION}_RING setsockopts
+------------------------------------------------------
+
+These setsockopts sets the number of descriptors that the RX, TX,
+FILL, and COMPLETION rings respectively should have. It is mandatory
+to set the size of at least one of the RX and TX rings. If you set
+both, you will be able to both receive and send traffic from your
+application, but if you only want to do one of them, you can save
+resources by only setting up one of them. Both the FILL ring and the
+COMPLETION ring are mandatory if you have a UMEM tied to your socket,
+which is the normal case. But if the XDP_SHARED_UMEM flag is used, any
+socket after the first one does not have a UMEM and should in that
+case not have any FILL or COMPLETION rings created.
+
+XDP_UMEM_REG setsockopt
+-----------------------
+
+This setsockopt registers a UMEM to a socket. This is the area that
+contain all the buffers that packet can recide in. The call takes a
+pointer to the beginning of this area and the size of it. Moreover, it
+also has parameter called chunk_size that is the size that the UMEM is
+divided into. It can only be 2K or 4K at the moment. If you have an
+UMEM area that is 128K and a chunk size of 2K, this means that you
+will be able to hold a maximum of 128K / 2K = 64 packets in your UMEM
+area and that your largest packet size can be 2K.
+
+There is also an option to set the headroom of each single buffer in
+the UMEM. If you set this to N bytes, it means that the packet will
+start N bytes into the buffer leaving the first N bytes for the
+application to use. The final option is the flags field, but it will
+be dealt with in separate sections for each UMEM flag.
+
+SO_BINDTODEVICE setsockopt
+--------------------------
+
+This is a generic SOL_SOCKET option that can be used to tie AF_XDP
+socket to a particular network interface.  It is useful when a socket
+is created by a privileged process and passed to a non-privileged one.
+Once the option is set, kernel will refuse attempts to bind that socket
+to a different interface.  Updating the value requires CAP_NET_RAW.
+
+XDP_STATISTICS getsockopt
+-------------------------
+
+Gets drop statistics of a socket that can be useful for debug
+purposes. The supported statistics are shown below:
+
+.. code-block:: c
+
+   struct xdp_statistics {
+	  __u64 rx_dropped; /* Dropped for reasons other than invalid desc */
+	  __u64 rx_invalid_descs; /* Dropped due to invalid descriptor */
+	  __u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
+   };
+
+XDP_OPTIONS getsockopt
+----------------------
+
+Gets options from an XDP socket. The only one supported so far is
+XDP_OPTIONS_ZEROCOPY which tells you if zero-copy is on or not.
+
 Usage
 =====
 
-In order to use AF_XDP sockets there are two parts needed. The
+In order to use AF_XDP sockets two parts are needed. The
 user-space application and the XDP program. For a complete setup and
 usage example, please refer to the sample application. The user-space
 side is xdpsock_user.c and the XDP side is part of libbpf.
 
-The XDP code sample included in tools/lib/bpf/xsk.c is the following::
+The XDP code sample included in tools/lib/bpf/xsk.c is the following:
+
+.. code-block:: c
 
    SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
    {
        int index = ctx->rx_queue_index;
 
-       // A set entry here means that the correspnding queue_id
+       // A set entry here means that the corresponding queue_id
        // has an active AF_XDP socket bound to it.
        if (bpf_map_lookup_elem(&xsks_map, &index))
            return bpf_redirect_map(&xsks_map, index, 0);
@@ -238,7 +431,10 @@
        return XDP_PASS;
    }
 
-Naive ring dequeue and enqueue could look like this::
+A simple but not so performance ring dequeue and enqueue could look
+like this:
+
+.. code-block:: c
 
     // struct xdp_rxtx_ring {
     // 	__u32 *producer;
@@ -287,17 +483,16 @@
         return 0;
     }
 
-
-For a more optimized version, please refer to the sample application.
+But please use the libbpf functions as they are optimized and ready to
+use. Will make your life easier.
 
 Sample application
 ==================
 
 There is a xdpsock benchmarking/test application included that
-demonstrates how to use AF_XDP sockets with both private and shared
-UMEMs. Say that you would like your UDP traffic from port 4242 to end
-up in queue 16, that we will enable AF_XDP on. Here, we use ethtool
-for this::
+demonstrates how to use AF_XDP sockets with private UMEMs. Say that
+you would like your UDP traffic from port 4242 to end up in queue 16,
+that we will enable AF_XDP on. Here, we use ethtool for this::
 
       ethtool -N p3p2 rx-flow-hash udp4 fn
       ethtool -N p3p2 flow-type udp4 src-port 4242 dst-port 4242 \
@@ -311,13 +506,18 @@
 For XDP_SKB mode, use the switch "-S" instead of "-N" and all options
 can be displayed with "-h", as usual.
 
+This sample application uses libbpf to make the setup and usage of
+AF_XDP simpler. If you want to know how the raw uapi of AF_XDP is
+really used to make something more advanced, take a look at the libbpf
+code in tools/lib/bpf/xsk.[ch].
+
 FAQ
 =======
 
 Q: I am not seeing any traffic on the socket. What am I doing wrong?
 
 A: When a netdev of a physical NIC is initialized, Linux usually
-   allocates one Rx and Tx queue pair per core. So on a 8 core system,
+   allocates one RX and TX queue pair per core. So on a 8 core system,
    queue ids 0 to 7 will be allocated, one per core. In the AF_XDP
    bind call or the xsk_socket__create libbpf function call, you
    specify a specific queue id to bind to and it is only the traffic
@@ -343,9 +543,21 @@
      sudo ethtool -N <interface> flow-type udp4 src-port 4242 dst-port \
      4242 action 2
 
-   A number of other ways are possible all up to the capabilitites of
+   A number of other ways are possible all up to the capabilities of
    the NIC you have.
 
+Q: Can I use the XSKMAP to implement a switch betwen different umems
+   in copy mode?
+
+A: The short answer is no, that is not supported at the moment. The
+   XSKMAP can only be used to switch traffic coming in on queue id X
+   to sockets bound to the same queue id X. The XSKMAP can contain
+   sockets bound to different queue ids, for example X and Y, but only
+   traffic goming in from queue id Y can be directed to sockets bound
+   to the same queue id Y. In zero-copy mode, you should use the
+   switch, or other distribution mechanism, in your NIC to direct
+   traffic to the correct queue id and socket.
+
 Credits
 =======
 
--- linux-ein-5.4.0.orig/Documentation/networking/bonding.txt
+++ linux-ein-5.4.0/Documentation/networking/bonding.txt
@@ -191,11 +191,12 @@
 ad_actor_system
 
 	In an AD system, this specifies the mac-address for the actor in
-	protocol packet exchanges (LACPDUs). The value cannot be NULL or
-	multicast. It is preferred to have the local-admin bit set for this
-	mac but driver does not enforce it. If the value is not given then
-	system defaults to using the masters' mac address as actors' system
-	address.
+	protocol packet exchanges (LACPDUs). The value cannot be a multicast
+	address. If the all-zeroes MAC is specified, bonding will internally
+	use the MAC of the bond itself. It is preferred to have the
+	local-admin bit set for this mac but driver does not enforce it. If
+	the value is not given then system defaults to using the masters'
+	mac address as actors' system address.
 
 	This parameter has effect only in 802.3ad mode and is available through
 	SysFs interface.
--- linux-ein-5.4.0.orig/Documentation/networking/device_drivers/amazon/ena.txt
+++ linux-ein-5.4.0/Documentation/networking/device_drivers/amazon/ena.txt
@@ -248,7 +248,7 @@
   inputs for hash functions.
 - The driver configures RSS settings using the AQ SetFeature command
   (ENA_ADMIN_RSS_HASH_FUNCTION, ENA_ADMIN_RSS_HASH_INPUT and
-  ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG properties).
+  ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG properties).
 - If the NETIF_F_RXHASH flag is set, the 32-bit result of the hash
   function delivered in the Rx CQ descriptor is set in the received
   SKB.
--- linux-ein-5.4.0.orig/Documentation/networking/device_drivers/mellanox/mlx5.rst
+++ linux-ein-5.4.0/Documentation/networking/device_drivers/mellanox/mlx5.rst
@@ -154,6 +154,27 @@
       values:
          cmode runtime value smfs
 
+enable_roce: RoCE enablement state
+----------------------------------
+RoCE enablement state controls driver support for RoCE traffic.
+When RoCE is disabled, there is no gid table, only raw ethernet QPs are supported and traffic on the well known UDP RoCE port is handled as raw ethernet traffic.
+
+To change RoCE enablement state a user must change the driverinit cmode value and run devlink reload.
+
+User command examples:
+
+- Disable RoCE::
+
+    $ devlink dev param set pci/0000:06:00.0 name enable_roce value false cmode driverinit
+    $ devlink dev reload pci/0000:06:00.0
+
+- Read RoCE enablement state::
+
+    $ devlink dev param show pci/0000:06:00.0 name enable_roce
+      pci/0000:06:00.0:
+      name enable_roce type generic
+      values:
+         cmode driverinit value true
 
 Devlink health reporters
 ========================
--- linux-ein-5.4.0.orig/Documentation/networking/devlink-params-mlx5.txt
+++ linux-ein-5.4.0/Documentation/networking/devlink-params-mlx5.txt
@@ -0,0 +1,17 @@
+flow_steering_mode	[DEVICE, DRIVER-SPECIFIC]
+			Controls the flow steering mode of the driver.
+			Two modes are supported:
+			1. 'dmfs' - Device managed flow steering.
+			2. 'smfs  - Software/Driver managed flow steering.
+			In DMFS mode, the HW steering entities are created and
+			managed through the Firmware.
+			In SMFS mode, the HW steering entities are created and
+			managed though by the driver directly into Hardware
+			without firmware intervention.
+			Type: String
+			Configuration mode: runtime
+
+enable_roce		[DEVICE, GENERIC]
+			Enable handling of RoCE traffic in the device.
+			Defaultly enabled.
+			Configuration mode: driverinit
--- linux-ein-5.4.0.orig/Documentation/networking/devlink-params.txt
+++ linux-ein-5.4.0/Documentation/networking/devlink-params.txt
@@ -65,3 +65,7 @@
 			  Reset only if device firmware can be found in the
 			  filesystem.
 			Type: u8
+
+enable_roce		[DEVICE, GENERIC]
+			Enable handling of RoCE traffic in the device.
+			Type: Boolean
--- linux-ein-5.4.0.orig/Documentation/networking/ip-sysctl.txt
+++ linux-ein-5.4.0/Documentation/networking/ip-sysctl.txt
@@ -876,7 +876,7 @@
 cipso_cache_bucket_size - INTEGER
 	The CIPSO label cache consists of a fixed size hash table with each
 	hash bucket containing a number of cache entries.  This variable limits
-	the number of entries in each hash bucket; the larger the value the
+	the number of entries in each hash bucket; the larger the value is, the
 	more CIPSO label mappings that can be cached.  When the number of
 	entries in a given hash bucket reaches this limit adding new entries
 	causes the oldest entry in the bucket to be removed to make room.
@@ -953,7 +953,7 @@
 	which can be quite useful - but may break some applications.
 	Default: 0
 
-ip_dynaddr - BOOLEAN
+ip_dynaddr - INTEGER
 	If set non-zero, enables support for dynamic addresses.
 	If set to a non-zero value larger than 1, a kernel log
 	message will be printed when dynamic address rewriting
@@ -1000,12 +1000,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
@@ -2282,7 +2284,14 @@
 	Default: 4K
 
 sctp_wmem  - vector of 3 INTEGERs: min, default, max
-	Currently this tunable has no effect.
+	Only the first value ("min") is used, "default" and "max" are
+	ignored.
+
+	min: Minimum size of send buffer that can be used by SCTP sockets.
+	It is guaranteed to each SCTP socket (but not association) even
+	under moderate memory pressure.
+
+	Default: 4K
 
 addr_scope_policy - INTEGER
 	Control IPv4 address scoping - draft-stewart-tsvwg-sctp-ipv4-00
--- linux-ein-5.4.0.orig/Documentation/networking/ipvs-sysctl.txt
+++ linux-ein-5.4.0/Documentation/networking/ipvs-sysctl.txt
@@ -30,8 +30,7 @@
 
 	0: disable any special handling on port reuse. The new
 	connection will be delivered to the same real server that was
-	servicing the previous connection. This will effectively
-	disable expire_nodest_conn.
+	servicing the previous connection.
 
 	bit 1: enable rescheduling of new connections when it is safe.
 	That is, whenever expire_nodest_conn and for TCP sockets, when
--- linux-ein-5.4.0.orig/Documentation/networking/j1939.rst
+++ linux-ein-5.4.0/Documentation/networking/j1939.rst
@@ -339,7 +339,7 @@
 			.pgn = J1939_PGN_ADDRESS_CLAIMED,
 			.pgn_mask = J1939_PGN_PDU1_MAX,
 		}, {
-			.pgn = J1939_PGN_ADDRESS_REQUEST,
+			.pgn = J1939_PGN_REQUEST,
 			.pgn_mask = J1939_PGN_PDU1_MAX,
 		}, {
 			.pgn = J1939_PGN_ADDRESS_COMMANDED,
@@ -414,8 +414,8 @@
 		.can_family = AF_CAN,
 		.can_addr.j1939 = {
 			.name = J1939_NO_NAME;
-			.pgn = 0x30,
-			.addr = 0x12300,
+			.addr = 0x30,
+			.pgn = 0x12300,
 		},
 	};
 
--- linux-ein-5.4.0.orig/Documentation/networking/nf_flowtable.txt
+++ linux-ein-5.4.0/Documentation/networking/nf_flowtable.txt
@@ -76,7 +76,7 @@
 
         table inet x {
 		flowtable f {
-			hook ingress priority 0 devices = { eth0, eth1 };
+			hook ingress priority 0; devices = { eth0, eth1 };
 		}
                 chain y {
                         type filter hook forward priority 0; policy accept;
--- linux-ein-5.4.0.orig/Documentation/power/runtime_pm.rst
+++ linux-ein-5.4.0/Documentation/power/runtime_pm.rst
@@ -382,6 +382,12 @@
       nonzero, increment the counter and return 1; otherwise return 0 without
       changing the counter
 
+  `int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);`
+    - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
+      runtime PM status is RPM_ACTIVE, and either ign_usage_count is true
+      or the device's usage_count is non-zero, 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-ein-5.4.0.orig/Documentation/process/code-of-conduct-interpretation.rst
+++ linux-ein-5.4.0/Documentation/process/code-of-conduct-interpretation.rst
@@ -51,7 +51,7 @@
 uncertain how to handle situations that come up.  It will not be
 considered a violation report unless you want it to be.  If you are
 uncertain about approaching the TAB or any other maintainers, please
-reach out to our conflict mediator, Mishi Choudhary <mishi@linux.com>.
+reach out to our conflict mediator, Joanna Lee <jlee@linuxfoundation.org>.
 
 In the end, "be kind to each other" is really what the end goal is for
 everybody.  We know everyone is human and we all fail at times, but the
--- linux-ein-5.4.0.orig/Documentation/process/stable-kernel-rules.rst
+++ linux-ein-5.4.0/Documentation/process/stable-kernel-rules.rst
@@ -174,7 +174,16 @@
  - The finalized and tagged releases of all stable kernels can be found
    in separate branches per version at:
 
-	https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
+	https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
+
+ - The release candidate of all stable kernel versions can be found at:
+
+        https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/
+
+   .. warning::
+      The -stable-rc tree is a snapshot in time of the stable-queue tree and
+      will change frequently, hence will be rebased often. It should only be
+      used for testing purposes (e.g. to be consumed by CI systems).
 
 
 Review committee
--- linux-ein-5.4.0.orig/Documentation/process/submitting-patches.rst
+++ linux-ein-5.4.0/Documentation/process/submitting-patches.rst
@@ -133,7 +133,7 @@
 
 The maintainer will thank you if you write your patch description in a
 form which can be easily pulled into Linux's source code management
-system, ``git``, as a "commit log".  See :ref:`explicit_in_reply_to`.
+system, ``git``, as a "commit log".  See :ref:`the_canonical_patch_format`.
 
 Solve only one problem per patch.  If your description starts to get
 long, that's a sign that you probably need to split up your patch.
--- linux-ein-5.4.0.orig/Documentation/remoteproc.txt
+++ linux-ein-5.4.0/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
--- linux-ein-5.4.0.orig/Documentation/s390/index.rst
+++ linux-ein-5.4.0/Documentation/s390/index.rst
@@ -15,6 +15,7 @@
     vfio-ccw
     zfcpdump
     common_io
+    pci
 
     text_files
 
--- linux-ein-5.4.0.orig/Documentation/s390/pci.rst
+++ linux-ein-5.4.0/Documentation/s390/pci.rst
@@ -0,0 +1,126 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========
+S/390 PCI
+=========
+
+Authors:
+        - Pierre Morel
+
+Copyright, IBM Corp. 2020
+
+
+command line parameters and debugfs entries
+===========================================
+
+Command line parameters
+-----------------------
+
+* nomio
+
+  Do not use MIO instructions.
+
+* norid
+
+  Ignore the RID field and force use of one PCI domain per PCI function.
+
+debugfs entries
+---------------
+
+* /sys/kernel/debug/s390dbf/pci_*/ (S/390 debug feature)
+
+  Some views generated by the debug feature to hold various debug outputs.
+
+  - /sys/kernel/debug/s390dbf/pci_msg/sprintf
+    Messages from the processing of PCI events like machine check handling
+    and setting of global functionality like UID checking.
+
+  The level of logging can be changed to be more or less verbose by piping to
+  /sys/kernel/debug/s390dbf/pci_*/level a number between 0 and 6; see the
+  documentation on the S/390 debug feature (Documentation/s390/s390dbf.rst)
+  for details.
+
+Sysfs entries
+=============
+
+Specific entries, or entries specificities for zPCI functions.
+
+* /sys/bus/pci/slots/XXXXXXXX
+
+  The slot entries are setup using the FID (Function Identifier) of the
+  PCI function.
+
+  - /sys/bus/pci/slots/XXXXXXXX/power
+
+  A physical function currently supporting virtual function can not be
+  powered-off until all virtual-function have been removed with
+  echo 0 > /sys/bus/pci/devices/XXXX:XX:XX.X/sriov_numvf
+
+* /sys/bus/pci/devices/XXXX:XX:XX.X/
+
+  - function_id
+    zPCI function identifier unique for the complete Z System.
+    It define uniquely a function in the system.
+
+  - function_handle
+    Low level identifier used for a configured PCI function.
+    It may be useful for debuging.
+
+  - pchid
+    Model dependent location of the I/O adapter.
+
+  - pfgid
+    PCI Function Group ID, functions sharing identical functionality
+    are using a common identifier.
+    A PCI group defines interrupts, IOMMU, IOTLB and DMA specifics.
+
+  - vfn
+    The Virtual Function Number, from 1 to N for virtual functions.
+    0 for physical functions.
+
+  - pft
+    PCI function type specifies the type of the PCI function.
+
+  - port
+    The port correspond to the physical port the function is attached to.
+    It also gives an indication on the physical function a virtual function
+    is attached to.
+
+  - uid
+    The UID, Unique Identifier is defined when configuring a LPAR and is
+    unique inside an LPAR.
+
+  - pfip/segmentX
+    The segments are used to determine the isolation of a function.
+    They corresponds to the physical path to the function.
+    The more the segment are different the more the functions are isolated.
+
+Enumeration and hotplug
+=======================
+
+The PCI address is made of 4 parts: domain, bus, device and function,
+like in DDDD:BB:dd.f
+
+* When not using multi-functions (norid is set or firmware does not support
+  multi-functions)
+
+  - There is only one function per domain.
+
+  - the domain is set from the zPCI function's UID as defined during the
+    LPAR creation.
+
+  - Addresses look like DDDD:00:00.0
+
+* When using multi-functions (norid parameter is not set), there are some
+  change in the way zPCI functions are addressed:
+
+  - There is still only one bus per domain.
+
+  - There can be up to 256 functions per bus.
+
+  - The domain part of the address of all functions of all functions for
+    a multi-Function device is set from the zPCI function's UID as defined
+    in the LPAR creation for the function zero.
+
+  - New functions will only be ready to be used after the function zero
+    (the function with devfn 0) has been enumerated.
--- linux-ein-5.4.0.orig/Documentation/scsi/smartpqi.txt
+++ linux-ein-5.4.0/Documentation/scsi/smartpqi.txt
@@ -29,7 +29,7 @@
   smartpqi host attributes:
   -------------------------
   /sys/class/scsi_host/host*/rescan
-  /sys/class/scsi_host/host*/version
+  /sys/class/scsi_host/host*/driver_version
 
   The host rescan attribute is a write only attribute. Writing to this
   attribute will trigger the driver to scan for new, changed, or removed
--- linux-ein-5.4.0.orig/Documentation/sound/hd-audio/index.rst
+++ linux-ein-5.4.0/Documentation/sound/hd-audio/index.rst
@@ -8,3 +8,4 @@
    models
    controls
    dp-mst
+   realtek-pc-beep
--- linux-ein-5.4.0.orig/Documentation/sound/hd-audio/models.rst
+++ linux-ein-5.4.0/Documentation/sound/hd-audio/models.rst
@@ -216,8 +216,6 @@
     ALC298 fixups on Dell AIO machines
 alc275-dell-xps
     ALC275 fixups on Dell XPS models
-alc256-dell-xps13
-    ALC256 fixups on Dell XPS13
 lenovo-spk-noise
     Workaround for speaker noise on Lenovo machines
 lenovo-hotkey
@@ -263,6 +261,10 @@
 huawei-mbx-stereo
     Enable initialization verbs for Huawei MBX stereo speakers;
     might be risky, try this at your own risk
+alc298-samsung-headphone
+    Samsung laptops with ALC298
+alc256-samsung-headphone
+    Samsung laptops with ALC256
 
 ALC66x/67x/892
 ==============
@@ -700,7 +702,7 @@
 no-jd
     BIOS setup but without jack-detection
 intel
-    Intel DG45* mobos
+    Intel D*45* mobos
 dell-m6-amic
     Dell desktops/laptops with analog mics
 dell-m6-dmic
--- linux-ein-5.4.0.orig/Documentation/sound/hd-audio/realtek-pc-beep.rst
+++ linux-ein-5.4.0/Documentation/sound/hd-audio/realtek-pc-beep.rst
@@ -0,0 +1,129 @@
+===============================
+Realtek PC Beep Hidden Register
+===============================
+
+This file documents the "PC Beep Hidden Register", which is present in certain
+Realtek HDA codecs and controls a muxer and pair of passthrough mixers that can
+route audio between pins but aren't themselves exposed as HDA widgets. As far
+as I can tell, these hidden routes are designed to allow flexible PC Beep output
+for codecs that don't have mixer widgets in their output paths. Why it's easier
+to hide a mixer behind an undocumented vendor register than to just expose it
+as a widget, I have no idea.
+
+Register Description
+====================
+
+The register is accessed via processing coefficient 0x36 on NID 20h. Bits not
+identified below have no discernible effect on my machine, a Dell XPS 13 9350::
+
+  MSB                           LSB
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  | |h|S|L|         | B |R|       | Known bits
+  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+  |0|0|1|1|  0x7  |0|0x0|1|  0x7  | Reset value
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+1Ah input select (B): 2 bits
+  When zero, expose the PC Beep line (from the internal beep generator, when
+  enabled with the Set Beep Generation verb on NID 01h, or else from the
+  external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone
+  jack (or possibly Line In on some machines) input instead. If PC Beep is
+  selected, the 1Ah boost control has no effect.
+
+Amplify 1Ah loopback, left (L): 1 bit
+  Amplify the left channel of 1Ah before mixing it into outputs as specified
+  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
+
+Amplify 1Ah loopback, right (R): 1 bit
+  Amplify the right channel of 1Ah before mixing it into outputs as specified
+  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
+
+Loopback 1Ah to 21h [active low] (h): 1 bit
+  When zero, mix 1Ah (possibly with amplification, depending on L and R bits)
+  into 21h (headphone jack on my machine). Mixed signal respects the mute
+  setting on 21h.
+
+Loopback 1Ah to 14h (S): 1 bit
+  When one, mix 1Ah (possibly with amplification, depending on L and R bits)
+  into 14h (internal speaker on my machine). Mixed signal **ignores** the mute
+  setting on 14h and is present whenever 14h is configured as an output.
+
+Path diagrams
+=============
+
+1Ah input selection (DIV is the PC Beep divider set on NID 01h)::
+
+  <Beep generator>   <PCBEEP pin>    <Headphone jack>
+          |                |                |
+          +--DIV--+--!DIV--+       {1Ah boost control}
+                  |                         |
+                  +--(b == 0)--+--(b != 0)--+
+                               |
+               >1Ah (Beep/Headphone Mic/Line In)<
+
+Loopback of 1Ah to 21h/14h::
+
+               <1Ah (Beep/Headphone Mic/Line In)>
+                               |
+                        {amplify if L/R}
+                               |
+                  +-----!h-----+-----S-----+
+                  |                        |
+          {21h mute control}               |
+                  |                        |
+          >21h (Headphone)<     >14h (Internal Speaker)<
+
+Background
+==========
+
+All Realtek HDA codecs have a vendor-defined widget with node ID 20h which
+provides access to a bank of registers that control various codec functions.
+Registers are read and written via the standard HDA processing coefficient
+verbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is
+named "Realtek Vendor Registers" in public datasheets' verb listings and,
+apart from that, is entirely undocumented.
+
+This particular register, exposed at coefficient 0x36 and named in commits from
+Realtek, is of note: unlike most registers, which seem to control detailed
+amplifier parameters not in scope of the HDA specification, it controls audio
+routing which could just as easily have been defined using standard HDA mixer
+and selector widgets.
+
+Specifically, it selects between two sources for the input pin widget with Node
+ID (NID) 1Ah: the widget's signal can come either from an audio jack (on my
+laptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek
+commits indicate that it might be a Line In on some machines) or from the PC
+Beep line (which is itself multiplexed between the codec's internal beep
+generator and external PCBEEP pin, depending on if the beep generator is
+enabled via verbs on NID 01h). Additionally, it can mix (with optional
+amplification) that signal onto the 21h and/or 14h output pins.
+
+The register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is
+then amplified and mixed into both the headphones and the speakers. Not only
+does this violate the HDA specification, which says that "[a vendor defined
+beep input pin] connection may be maintained *only* while the Link reset
+(**RST#**) is asserted", it means that we cannot ignore the register if we care
+about the input that 1Ah would otherwise expose or if the PCBEEP trace is
+poorly shielded and picks up chassis noise (both of which are the case on my
+machine).
+
+Unfortunately, there are lots of ways to get this register configuration wrong.
+Linux, it seems, has gone through most of them. For one, the register resets
+after S3 suspend: judging by existing code, this isn't the case for all vendor
+registers, and it's led to some fixes that improve behavior on cold boot but
+don't last after suspend. Other fixes have successfully switched the 1Ah input
+away from PC Beep but have failed to disable both loopback paths. On my
+machine, this means that the headphone input is amplified and looped back to
+the headphone output, which uses the exact same pins! As you might expect, this
+causes terrible headphone noise, the character of which is controlled by the
+1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone
+noise by changing "Headphone Mic Boost" in ALSA, now you know why.)
+
+The information here has been obtained through black-box reverse engineering of
+the ALC256 codec's behavior and is not guaranteed to be correct. It likely
+also applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs
+seem to be close relatives of the ALC256. (They all share one initialization
+function.) Additionally, other codecs like the ALC225 and ALC285 also have this
+register, judging by existing fixups in ``patch_realtek.c``, but specific
+data (e.g. node IDs, bit positions, pin mappings) for those codecs may differ
+from what I've described here.
--- linux-ein-5.4.0.orig/Documentation/sound/soc/dapm.rst
+++ linux-ein-5.4.0/Documentation/sound/soc/dapm.rst
@@ -234,7 +234,7 @@
 a virtual widget - a widget with no control bits e.g.
 ::
 
-  SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
+  SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 This can be used to merge to signal paths together in software.
 
--- linux-ein-5.4.0.orig/Documentation/sphinx/load_config.py
+++ linux-ein-5.4.0/Documentation/sphinx/load_config.py
@@ -3,7 +3,7 @@
 
 import os
 import sys
-from sphinx.util.pycompat import execfile_
+from sphinx.util.osutil import fs_encoding
 
 # ------------------------------------------------------------------------------
 def loadConfig(namespace):
@@ -48,7 +48,9 @@
             sys.stdout.write("load additional sphinx-config: %s\n" % config_file)
             config = namespace.copy()
             config['__file__'] = config_file
-            execfile_(config_file, config)
+            with open(config_file, 'rb') as f:
+                code = compile(f.read(), fs_encoding, 'exec')
+                exec(code, config)
             del config['__file__']
             namespace.update(config)
         else:
--- linux-ein-5.4.0.orig/Documentation/sphinx/parse-headers.pl
+++ linux-ein-5.4.0/Documentation/sphinx/parse-headers.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 use strict;
 use Text::Tabs;
 use Getopt::Long;
--- linux-ein-5.4.0.orig/Documentation/target/tcm_mod_builder.py
+++ linux-ein-5.4.0/Documentation/target/tcm_mod_builder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # The TCM v4 multi-protocol fabric module generation script for drivers/target/$NEW_MOD
 #
 # Copyright (c) 2010 Rising Tide Systems
--- linux-ein-5.4.0.orig/Documentation/trace/histogram.rst
+++ linux-ein-5.4.0/Documentation/trace/histogram.rst
@@ -39,7 +39,7 @@
   will use the event's kernel stacktrace as the key.  The keywords
   'keys' or 'key' can be used to specify keys, and the keywords
   'values', 'vals', or 'val' can be used to specify values.  Compound
-  keys consisting of up to two fields can be specified by the 'keys'
+  keys consisting of up to three fields can be specified by the 'keys'
   keyword.  Hashing a compound key produces a unique entry in the
   table for each unique combination of component keys, and can be
   useful for providing more fine-grained summaries of event data.
@@ -191,7 +191,7 @@
                                 with the event, in nanoseconds.  May be
 			        modified by .usecs to have timestamps
 			        interpreted as microseconds.
-    cpu                    int  the cpu on which the event occurred.
+    common_cpu             int  the cpu on which the event occurred.
     ====================== ==== =======================================
 
 Extended error information
--- linux-ein-5.4.0.orig/Documentation/trace/postprocess/decode_msr.py
+++ linux-ein-5.4.0/Documentation/trace/postprocess/decode_msr.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # add symbolic names to read_msr / write_msr in trace
 # decode_msr msr-index.h < trace
 import sys
--- linux-ein-5.4.0.orig/Documentation/trace/postprocess/trace-pagealloc-postprocess.pl
+++ linux-ein-5.4.0/Documentation/trace/postprocess/trace-pagealloc-postprocess.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 # This is a POC (proof of concept or piece of crap, take your pick) for reading the
 # text representation of trace output related to page allocation. It makes an attempt
 # to extract some high-level information on what is going on. The accuracy of the parser
--- linux-ein-5.4.0.orig/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
+++ linux-ein-5.4.0/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 # This is a POC for reading the text representation of trace output related to
 # page reclaim. It makes an attempt to extract some high-level information on
 # what is going on. The accuracy of the parser may vary
--- linux-ein-5.4.0.orig/Documentation/userspace-api/seccomp_filter.rst
+++ linux-ein-5.4.0/Documentation/userspace-api/seccomp_filter.rst
@@ -250,14 +250,14 @@
 seccomp notification fd to receive a ``struct seccomp_notif``, which contains
 five members: the input length of the structure, a unique-per-filter ``id``,
 the ``pid`` of the task which triggered this request (which may be 0 if the
-task is in a pid ns not visible from the listener's pid namespace), a ``flags``
-member which for now only has ``SECCOMP_NOTIF_FLAG_SIGNALED``, representing
-whether or not the notification is a result of a non-fatal signal, and the
-``data`` passed to seccomp. Userspace can then make a decision based on this
-information about what to do, and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a
-response, indicating what should be returned to userspace. The ``id`` member of
-``struct seccomp_notif_resp`` should be the same ``id`` as in ``struct
-seccomp_notif``.
+task is in a pid ns not visible from the listener's pid namespace). The
+notification also contains the ``data`` passed to seccomp, and a filters flag.
+The structure should be zeroed out prior to calling the ioctl.
+
+Userspace can then make a decision based on this information about what to do,
+and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a response, indicating what should be
+returned to userspace. The ``id`` member of ``struct seccomp_notif_resp`` should
+be the same ``id`` as in ``struct seccomp_notif``.
 
 It is worth noting that ``struct seccomp_data`` contains the values of register
 arguments to the syscall, but does not contain pointers to memory. The task's
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/api.txt
+++ linux-ein-5.4.0/Documentation/virt/kvm/api.txt
@@ -172,6 +172,9 @@
 be retrieved using KVM_CAP_ARM_VM_IPA_SIZE of the KVM_CHECK_EXTENSION
 ioctl() at run-time.
 
+Creation of the VM will fail if the requested IPA size (whether it is
+implicit or explicit) is unsupported on the host.
+
 Please note that configuring the IPA size does not affect the capability
 exposed by the guest CPUs in ID_AA64MMFR0_EL1[PARange]. It only affects
 size of the address translated by the stage2 level (guest physical to
@@ -1132,6 +1135,9 @@
 the entire memory slot size.  Any object may back this memory, including
 anonymous memory, ordinary files, and hugetlbfs.
 
+On architectures that support a form of address tagging, userspace_addr must
+be an untagged address.
+
 It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
 be identical.  This allows large pages in the guest to be backed by large
 pages in the host.
@@ -1897,9 +1903,11 @@
 Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
 Errors:
-  ENOENT:   no such register
-  EINVAL:   invalid register ID, or no such register
-  EPERM:    (arm64) register access not allowed before vcpu finalization
+  ENOENT   no such register
+  EINVAL   invalid register ID, or no such register or used with VMs in
+           protected virtualization mode on s390
+  EPERM    (arm64) register access not allowed before vcpu finalization
+
 (These error codes are indicative only: do not rely on a specific error
 code being returned in a specific situation.)
 
@@ -2290,9 +2298,11 @@
 Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
 Errors include:
-  ENOENT:   no such register
-  EINVAL:   invalid register ID, or no such register
-  EPERM:    (arm64) register access not allowed before vcpu finalization
+  ENOENT   no such register
+  EINVAL   invalid register ID, or no such register or used with VMs in
+           protected virtualization mode on s390
+  EPERM    (arm64) register access not allowed before vcpu finalization
+
 (These error codes are indicative only: do not rely on a specific error
 code being returned in a specific situation.)
 
@@ -3058,51 +3068,116 @@
 
 4.89 KVM_S390_MEM_OP
 
-Capability: KVM_CAP_S390_MEM_OP
-Architectures: s390
-Type: vcpu ioctl
-Parameters: struct kvm_s390_mem_op (in)
-Returns: = 0 on success,
-         < 0 on generic error (e.g. -EFAULT or -ENOMEM),
-         > 0 if an exception occurred while walking the page tables
-
-Read or write data from/to the logical (virtual) memory of a VCPU.
+:Capability: KVM_CAP_S390_MEM_OP, KVM_CAP_S390_PROTECTED, KVM_CAP_S390_MEM_OP_EXTENSION
+:Architectures: s390
+:Type: vm ioctl, vcpu ioctl
+:Parameters: struct kvm_s390_mem_op (in)
+:Returns: = 0 on success,
+          < 0 on generic error (e.g. -EFAULT or -ENOMEM),
+          > 0 if an exception occurred while walking the page tables
+
+Read or write data from/to the VM's memory.
+The KVM_CAP_S390_MEM_OP_EXTENSION capability specifies what functionality is
+supported.
 
-Parameters are specified via the following structure:
+Parameters are specified via the following structure::
 
-struct kvm_s390_mem_op {
+  struct kvm_s390_mem_op {
 	__u64 gaddr;		/* the guest address */
 	__u64 flags;		/* flags */
 	__u32 size;		/* amount of bytes */
 	__u32 op;		/* type of operation */
 	__u64 buf;		/* buffer in userspace */
-	__u8 ar;		/* the access register number */
-	__u8 reserved[31];	/* should be set to 0 */
-};
-
-The type of operation is specified in the "op" field. It is either
-KVM_S390_MEMOP_LOGICAL_READ for reading from logical memory space or
-KVM_S390_MEMOP_LOGICAL_WRITE for writing to logical memory space. The
-KVM_S390_MEMOP_F_CHECK_ONLY flag can be set in the "flags" field to check
-whether the corresponding memory access would create an access exception
-(without touching the data in the memory at the destination). In case an
-access exception occurred while walking the MMU tables of the guest, the
-ioctl returns a positive error number to indicate the type of exception.
-This exception is also raised directly at the corresponding VCPU if the
-flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field.
+	union {
+		struct {
+			__u8 ar;	/* the access register number */
+			__u8 key;	/* access key, ignored if flag unset */
+		};
+		__u32 sida_offset; /* offset into the sida */
+		__u8 reserved[32]; /* ignored */
+	};
+  };
 
 The start address of the memory region has to be specified in the "gaddr"
 field, and the length of the region in the "size" field (which must not
 be 0). The maximum value for "size" can be obtained by checking the
 KVM_CAP_S390_MEM_OP capability. "buf" is the buffer supplied by the
 userspace application where the read data should be written to for
-KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written is
-stored for a KVM_S390_MEMOP_LOGICAL_WRITE. When KVM_S390_MEMOP_F_CHECK_ONLY
-is specified, "buf" is unused and can be NULL. "ar" designates the access
-register number to be used; the valid range is 0..15.
+a read access, or where the data that should be written is stored for
+a write access.  The "reserved" field is meant for future extensions.
+Reserved and unused values are ignored. Future extension that add members must
+introduce new flags.
+
+The type of operation is specified in the "op" field. Flags modifying
+their behavior can be set in the "flags" field. Undefined flag bits must
+be set to 0.
+
+Possible operations are:
+  * ``KVM_S390_MEMOP_LOGICAL_READ``
+  * ``KVM_S390_MEMOP_LOGICAL_WRITE``
+  * ``KVM_S390_MEMOP_ABSOLUTE_READ``
+  * ``KVM_S390_MEMOP_ABSOLUTE_WRITE``
+  * ``KVM_S390_MEMOP_SIDA_READ``
+  * ``KVM_S390_MEMOP_SIDA_WRITE``
+
+Logical read/write:
+
+Access logical memory, i.e. translate the given guest address to an absolute
+address given the state of the VCPU and use the absolute address as target of
+the access. "ar" designates the access register number to be used; the valid
+range is 0..15.
+Logical accesses are permitted for the VCPU ioctl only.
+Logical accesses are permitted for non-protected guests only.
+
+Supported flags:
+  * ``KVM_S390_MEMOP_F_CHECK_ONLY``
+  * ``KVM_S390_MEMOP_F_INJECT_EXCEPTION``
+  * ``KVM_S390_MEMOP_F_SKEY_PROTECTION``
+
+The KVM_S390_MEMOP_F_CHECK_ONLY flag can be set to check whether the
+corresponding memory access would cause an access exception; however,
+no actual access to the data in memory at the destination is performed.
+In this case, "buf" is unused and can be NULL.
+
+In case an access exception occurred during the access (or would occur
+in case of KVM_S390_MEMOP_F_CHECK_ONLY), the ioctl returns a positive
+error number indicating the type of exception. This exception is also
+raised directly at the corresponding VCPU if the flag
+KVM_S390_MEMOP_F_INJECT_EXCEPTION is set.
+
+If the KVM_S390_MEMOP_F_SKEY_PROTECTION flag is set, storage key
+protection is also in effect and may cause exceptions if accesses are
+prohibited given the access key designated by "key"; the valid range is 0..15.
+KVM_S390_MEMOP_F_SKEY_PROTECTION is available if KVM_CAP_S390_MEM_OP_EXTENSION
+is > 0.
+
+Absolute read/write:
+
+Access absolute memory. This operation is intended to be used with the
+KVM_S390_MEMOP_F_SKEY_PROTECTION flag, to allow accessing memory and performing
+the checks required for storage key protection as one operation (as opposed to
+user space getting the storage keys, performing the checks, and accessing
+memory thereafter, which could lead to a delay between check and access).
+Absolute accesses are permitted for the VM ioctl if KVM_CAP_S390_MEM_OP_EXTENSION
+is > 0.
+Currently absolute accesses are not permitted for VCPU ioctls.
+Absolute accesses are permitted for non-protected guests only.
+
+Supported flags:
+  * ``KVM_S390_MEMOP_F_CHECK_ONLY``
+  * ``KVM_S390_MEMOP_F_SKEY_PROTECTION``
+
+The semantics of the flags are as for logical accesses.
+
+SIDA read/write:
+
+Access the secure instruction data area which contains memory operands necessary
+for instruction emulation for protected guests.
+SIDA accesses are available if the KVM_CAP_S390_PROTECTED capability is available.
+SIDA accesses are permitted for the VCPU ioctl only.
+SIDA accesses are permitted for protected guests only.
 
-The "reserved" field is meant for future extensions. It is not used by
-KVM with the currently defined set of flags.
+No flags are supported.
 
 4.90 KVM_S390_GET_SKEYS
 
@@ -3609,6 +3684,18 @@
 Parameters: struct kvm_s390_cmma_log (in, out)
 Returns: 0 on success, a negative value on error
 
+Errors:
+
+  ======     =============================================================
+  ENOMEM     not enough memory can be allocated to complete the task
+  ENXIO      if CMMA is not enabled
+  EINVAL     if KVM_S390_CMMA_PEEK is not set but migration mode was not enabled
+  EINVAL     if KVM_S390_CMMA_PEEK is not set but dirty tracking has been
+             disabled (and thus migration mode was automatically disabled)
+  EFAULT     if the userspace address is invalid or if no page table is
+             present for the addresses (e.g. when using hugepages).
+  ======     =============================================================
+
 This ioctl is used to get the values of the CMMA bits on the s390
 architecture. It is meant to be used in two scenarios:
 - During live migration to save the CMMA values. Live migration needs
@@ -3685,12 +3772,6 @@
 
 values points to the userspace buffer where the result will be stored.
 
-This ioctl can fail with -ENOMEM if not enough memory can be allocated to
-complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
-KVM_S390_CMMA_PEEK is not set but migration mode was not enabled, with
--EFAULT if the userspace address is invalid or if no page table is
-present for the addresses (e.g. when using hugepages).
-
 4.108 KVM_S390_SET_CMMA_BITS
 
 Capability: KVM_CAP_S390_CMMA_MIGRATION
@@ -4127,6 +4208,90 @@
 #define KVM_PMU_EVENT_DENY 1
 
 
+4.122 KVM_S390_NORMAL_RESET
+
+Capability: KVM_CAP_S390_VCPU_RESETS
+Architectures: s390
+Type: vcpu ioctl
+Parameters: none
+Returns: 0
+
+This ioctl resets VCPU registers and control structures according to
+the cpu reset definition in the POP (Principles Of Operation).
+
+4.123 KVM_S390_INITIAL_RESET
+
+Capability: none
+Architectures: s390
+Type: vcpu ioctl
+Parameters: none
+Returns: 0
+
+This ioctl resets VCPU registers and control structures according to
+the initial cpu reset definition in the POP. However, the cpu is not
+put into ESA mode. This reset is a superset of the normal reset.
+
+4.124 KVM_S390_CLEAR_RESET
+
+Capability: KVM_CAP_S390_VCPU_RESETS
+Architectures: s390
+Type: vcpu ioctl
+Parameters: none
+Returns: 0
+
+This ioctl resets VCPU registers and control structures according to
+the clear cpu reset definition in the POP. However, the cpu is not put
+into ESA mode. This reset is a superset of the initial reset.
+
+
+4.125 KVM_S390_PV_COMMAND
+-------------------------
+
+:Capability: KVM_CAP_S390_PROTECTED
+:Architectures: s390
+:Type: vm ioctl
+:Parameters: struct kvm_pv_cmd
+:Returns: 0 on success, < 0 on error
+
+::
+
+  struct kvm_pv_cmd {
+	__u32 cmd;	/* Command to be executed */
+	__u16 rc;	/* Ultravisor return code */
+	__u16 rrc;	/* Ultravisor return reason code */
+	__u64 data;	/* Data or address */
+	__u32 flags;    /* flags for future extensions. Must be 0 for now */
+	__u32 reserved[3];
+  };
+
+cmd values:
+
+KVM_PV_ENABLE
+  Allocate memory and register the VM with the Ultravisor, thereby
+  donating memory to the Ultravisor that will become inaccessible to
+  KVM. All existing CPUs are converted to protected ones. After this
+  command has succeeded, any CPU added via hotplug will become
+  protected during its creation as well.
+
+KVM_PV_DISABLE
+
+  Deregister the VM from the Ultravisor and reclaim the memory that
+  had been donated to the Ultravisor, making it usable by the kernel
+  again.  All registered VCPUs are converted back to non-protected
+  ones.
+
+KVM_PV_VM_SET_SEC_PARMS
+  Pass the image header from VM memory to the Ultravisor in
+  preparation of image unpacking and verification.
+
+KVM_PV_VM_UNPACK
+  Unpack (protect and decrypt) a page of the encrypted boot image.
+
+KVM_PV_VM_VERIFY
+  Verify the integrity of the unpacked image. Only if this succeeds,
+  KVM is allowed to start protected VCPUs.
+
+
 5. The kvm_run structure
 ------------------------
 
@@ -4444,9 +4609,11 @@
 #define KVM_EXIT_HYPERV_SYNIC          1
 #define KVM_EXIT_HYPERV_HCALL          2
 			__u32 type;
+			__u32 pad1;
 			union {
 				struct {
 					__u32 msr;
+					__u32 pad2;
 					__u64 control;
 					__u64 evt_page;
 					__u64 msg_page;
@@ -5322,3 +5489,21 @@
 flush hypercalls by Hyper-V) so userspace should disable KVM identification
 in CPUID and only exposes Hyper-V identification. In this case, guest
 thinks it's running on Hyper-V and only use Hyper-V hypercalls.
+
+8.22 KVM_CAP_S390_VCPU_RESETS
+
+Architectures: s390
+
+This capability indicates that the KVM_S390_NORMAL_RESET and
+KVM_S390_CLEAR_RESET ioctls are available.
+
+8.23 KVM_CAP_S390_PROTECTED
+
+Architecture: s390
+
+
+This capability indicates that the Ultravisor has been initialized and
+KVM can therefore start protected VMs.
+This capability governs the KVM_S390_PV_COMMAND ioctl and the
+KVM_MP_STATE_LOAD MP_STATE. KVM_SET_MP_STATE can fail for protected
+guests when the state change is invalid.
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/devices/s390_flic.txt
+++ linux-ein-5.4.0/Documentation/virt/kvm/devices/s390_flic.txt
@@ -100,15 +100,9 @@
       mask or unmask the adapter, as specified in mask
 
     KVM_S390_IO_ADAPTER_MAP
-      perform a gmap translation for the guest address provided in addr,
-      pin a userspace page for the translated address and add it to the
-      list of mappings
-      Note: A new mapping will be created unconditionally; therefore,
-            the calling code should avoid making duplicate mappings.
-
+      This is now a no-op. The mapping is purely done by the irq route.
     KVM_S390_IO_ADAPTER_UNMAP
-      release a userspace page for the translated address specified in addr
-      from the list of mappings
+      This is now a no-op. The mapping is purely done by the irq route.
 
   KVM_DEV_FLIC_AISM
     modify the adapter-interruption-suppression mode for a given isc if the
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/devices/vm.txt
+++ linux-ein-5.4.0/Documentation/virt/kvm/devices/vm.txt
@@ -183,6 +183,7 @@
 Parameters: address of a buffer in user space to store the data (u8) to
 Returns:    -EFAULT if the given address is not accessible from kernel space
 	    -EINVAL if setting the TOD clock extension to != 0 is not supported
+        -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
 
 3.2. ATTRIBUTE: KVM_S390_VM_TOD_LOW
 
@@ -191,6 +192,8 @@
 
 Parameters: address of a buffer in user space to store the data (u64) to
 Returns:    -EFAULT if the given address is not accessible from kernel space
+        -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
+
 
 3.3. ATTRIBUTE: KVM_S390_VM_TOD_EXT
 Allows user space to set/get bits 0-63 of the TOD clock register as defined in
@@ -202,6 +205,7 @@
             (kvm_s390_vm_tod_clock) to
 Returns:    -EFAULT if the given address is not accessible from kernel space
 	    -EINVAL if setting the TOD clock extension to != 0 is not supported
+        -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
 
 4. GROUP: KVM_S390_VM_CRYPTO
 Architectures: s390
@@ -254,6 +258,10 @@
 Setting this attribute when migration mode is already active will have
 no effects.
 
+Dirty tracking must be enabled on all memslots, else -EINVAL is returned. When
+dirty tracking is disabled on any memslot, migration mode is automatically
+stopped.
+
 Parameters: none
 Returns:    -ENOMEM if there is not enough free memory to start migration mode
 	    -EINVAL if the state of the VM is invalid (e.g. no memory defined)
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/index.rst
+++ linux-ein-5.4.0/Documentation/virt/kvm/index.rst
@@ -9,4 +9,6 @@
 
    amd-memory-encryption
    cpuid
+   s390-pv
+   s390-pv-boot
    vcpu-requests
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/mmu.txt
+++ linux-ein-5.4.0/Documentation/virt/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
@@ -420,7 +420,7 @@
 number, it will ignore the cached MMIO information and handle the page
 fault through the slow path.
 
-Since only 19 bits are used to store generation-number on mmio spte, all
+Since only 18 bits are used to store generation-number on mmio spte, all
 pages are zapped when there is an overflow.
 
 Unfortunately, a single memory access might access kvm_memslots(kvm) multiple
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/s390-pv-boot.rst
+++ linux-ein-5.4.0/Documentation/virt/kvm/s390-pv-boot.rst
@@ -0,0 +1,84 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+s390 (IBM Z) Boot/IPL of Protected VMs
+======================================
+
+Summary
+-------
+The memory of Protected Virtual Machines (PVMs) is not accessible to
+I/O or the hypervisor. In those cases where the hypervisor needs to
+access the memory of a PVM, that memory must be made accessible.
+Memory made accessible to the hypervisor will be encrypted. See
+:doc:`s390-pv` for details."
+
+On IPL (boot) a small plaintext bootloader is started, which provides
+information about the encrypted components and necessary metadata to
+KVM to decrypt the protected virtual machine.
+
+Based on this data, KVM will make the protected virtual machine known
+to the Ultravisor (UV) and instruct it to secure the memory of the
+PVM, decrypt the components and verify the data and address list
+hashes, to ensure integrity. Afterwards KVM can run the PVM via the
+SIE instruction which the UV will intercept and execute on KVM's
+behalf.
+
+As the guest image is just like an opaque kernel image that does the
+switch into PV mode itself, the user can load encrypted guest
+executables and data via every available method (network, dasd, scsi,
+direct kernel, ...) without the need to change the boot process.
+
+
+Diag308
+-------
+This diagnose instruction is the basic mechanism to handle IPL and
+related operations for virtual machines. The VM can set and retrieve
+IPL information blocks, that specify the IPL method/devices and
+request VM memory and subsystem resets, as well as IPLs.
+
+For PVMs this concept has been extended with new subcodes:
+
+Subcode 8: Set an IPL Information Block of type 5 (information block
+for PVMs)
+Subcode 9: Store the saved block in guest memory
+Subcode 10: Move into Protected Virtualization mode
+
+The new PV load-device-specific-parameters field specifies all data
+that is necessary to move into PV mode.
+
+* PV Header origin
+* PV Header length
+* List of Components composed of
+   * AES-XTS Tweak prefix
+   * Origin
+   * Size
+
+The PV header contains the keys and hashes, which the UV will use to
+decrypt and verify the PV, as well as control flags and a start PSW.
+
+The components are for instance an encrypted kernel, kernel parameters
+and initrd. The components are decrypted by the UV.
+
+After the initial import of the encrypted data, all defined pages will
+contain the guest content. All non-specified pages will start out as
+zero pages on first access.
+
+
+When running in protected virtualization mode, some subcodes will result in
+exceptions or return error codes.
+
+Subcodes 4 and 7, which specify operations that do not clear the guest
+memory, will result in specification exceptions. This is because the
+UV will clear all memory when a secure VM is removed, and therefore
+non-clearing IPL subcodes are not allowed.
+
+Subcodes 8, 9, 10 will result in specification exceptions.
+Re-IPL into a protected mode is only possible via a detour into non
+protected mode.
+
+Keys
+----
+Every CEC will have a unique public key to enable tooling to build
+encrypted images.
+See  `s390-tools <https://github.com/ibm-s390-tools/s390-tools/>`_
+for the tooling.
--- linux-ein-5.4.0.orig/Documentation/virt/kvm/s390-pv.rst
+++ linux-ein-5.4.0/Documentation/virt/kvm/s390-pv.rst
@@ -0,0 +1,116 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================
+s390 (IBM Z) Ultravisor and Protected VMs
+=========================================
+
+Summary
+-------
+Protected virtual machines (PVM) are KVM VMs that do not allow KVM to
+access VM state like guest memory or guest registers. Instead, the
+PVMs are mostly managed by a new entity called Ultravisor (UV). The UV
+provides an API that can be used by PVMs and KVM to request management
+actions.
+
+Each guest starts in non-protected mode and then may make a request to
+transition into protected mode. On transition, KVM registers the guest
+and its VCPUs with the Ultravisor and prepares everything for running
+it.
+
+The Ultravisor will secure and decrypt the guest's boot memory
+(i.e. kernel/initrd). It will safeguard state changes like VCPU
+starts/stops and injected interrupts while the guest is running.
+
+As access to the guest's state, such as the SIE state description, is
+normally needed to be able to run a VM, some changes have been made in
+the behavior of the SIE instruction. A new format 4 state description
+has been introduced, where some fields have different meanings for a
+PVM. SIE exits are minimized as much as possible to improve speed and
+reduce exposed guest state.
+
+
+Interrupt injection
+-------------------
+Interrupt injection is safeguarded by the Ultravisor. As KVM doesn't
+have access to the VCPUs' lowcores, injection is handled via the
+format 4 state description.
+
+Machine check, external, IO and restart interruptions each can be
+injected on SIE entry via a bit in the interrupt injection control
+field (offset 0x54). If the guest cpu is not enabled for the interrupt
+at the time of injection, a validity interception is recognized. The
+format 4 state description contains fields in the interception data
+block where data associated with the interrupt can be transported.
+
+Program and Service Call exceptions have another layer of
+safeguarding; they can only be injected for instructions that have
+been intercepted into KVM. The exceptions need to be a valid outcome
+of an instruction emulation by KVM, e.g. we can never inject a
+addressing exception as they are reported by SIE since KVM has no
+access to the guest memory.
+
+
+Mask notification interceptions
+-------------------------------
+KVM cannot intercept lctl(g) and lpsw(e) anymore in order to be
+notified when a PVM enables a certain class of interrupt.  As a
+replacement, two new interception codes have been introduced: One
+indicating that the contents of CRs 0, 6, or 14 have been changed,
+indicating different interruption subclasses; and one indicating that
+PSW bit 13 has been changed, indicating that a machine check
+intervention was requested and those are now enabled.
+
+Instruction emulation
+---------------------
+With the format 4 state description for PVMs, the SIE instruction already
+interprets more instructions than it does with format 2. It is not able
+to interpret every instruction, but needs to hand some tasks to KVM;
+therefore, the SIE and the ultravisor safeguard emulation inputs and outputs.
+
+The control structures associated with SIE provide the Secure
+Instruction Data Area (SIDA), the Interception Parameters (IP) and the
+Secure Interception General Register Save Area.  Guest GRs and most of
+the instruction data, such as I/O data structures, are filtered.
+Instruction data is copied to and from the SIDA when needed.  Guest
+GRs are put into / retrieved from the Secure Interception General
+Register Save Area.
+
+Only GR values needed to emulate an instruction will be copied into this
+save area and the real register numbers will be hidden.
+
+The Interception Parameters state description field still contains the
+the bytes of the instruction text, but with pre-set register values
+instead of the actual ones. I.e. each instruction always uses the same
+instruction text, in order not to leak guest instruction text.
+This also implies that the register content that a guest had in r<n>
+may be in r<m> from the hypervisor's point of view.
+
+The Secure Instruction Data Area contains instruction storage
+data. Instruction data, i.e. data being referenced by an instruction
+like the SCCB for sclp, is moved via the SIDA. When an instruction is
+intercepted, the SIE will only allow data and program interrupts for
+this instruction to be moved to the guest via the two data areas
+discussed before. Other data is either ignored or results in validity
+interceptions.
+
+
+Instruction emulation interceptions
+-----------------------------------
+There are two types of SIE secure instruction intercepts: the normal
+and the notification type. Normal secure instruction intercepts will
+make the guest pending for instruction completion of the intercepted
+instruction type, i.e. on SIE entry it is attempted to complete
+emulation of the instruction with the data provided by KVM. That might
+be a program exception or instruction completion.
+
+The notification type intercepts inform KVM about guest environment
+changes due to guest instruction interpretation. Such an interception
+is recognized, for example, for the store prefix instruction to provide
+the new lowcore location. On SIE reentry, any KVM data in the data areas
+is ignored and execution continues as if the guest instruction had
+completed. For that reason KVM is not allowed to inject a program
+interrupt.
+
+Links
+-----
+`KVM Forum 2019 presentation <https://static.sched.com/hosted_files/kvmforum2019/3b/ibm_protected_vms_s390x.pdf>`_
--- linux-ein-5.4.0.orig/Documentation/vm/memory-model.rst
+++ linux-ein-5.4.0/Documentation/vm/memory-model.rst
@@ -52,8 +52,7 @@
 usable until the call to :c:func:`memblock_free_all` that hands all
 the memory to the page allocator.
 
-If an architecture enables `CONFIG_ARCH_HAS_HOLES_MEMORYMODEL` option,
-it may free parts of the `mem_map` array that do not cover the
+An architecture may free parts of the `mem_map` array that do not cover the
 actual physical pages. In such case, the architecture specific
 :c:func:`pfn_valid` implementation should take the holes in the
 `mem_map` into account.
--- linux-ein-5.4.0.orig/Documentation/vm/slub.rst
+++ linux-ein-5.4.0/Documentation/vm/slub.rst
@@ -160,7 +160,7 @@
 Here is a sample of slub debug output::
 
  ====================================================================
- BUG kmalloc-8: Redzone overwritten
+ BUG kmalloc-8: Right Redzone overwritten
  --------------------------------------------------------------------
 
  INFO: 0xc90f6d28-0xc90f6d2b. First byte 0x00 instead of 0xcc
@@ -168,10 +168,10 @@
  INFO: Object 0xc90f6d20 @offset=3360 fp=0xc90f6d58
  INFO: Allocated in get_modalias+0x61/0xf5 age=53 cpu=1 pid=554
 
- Bytes b4 0xc90f6d10:  00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
-   Object 0xc90f6d20:  31 30 31 39 2e 30 30 35                         1019.005
-  Redzone 0xc90f6d28:  00 cc cc cc                                     .
-  Padding 0xc90f6d50:  5a 5a 5a 5a 5a 5a 5a 5a                         ZZZZZZZZ
+ Bytes b4 (0xc90f6d10): 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
+ Object   (0xc90f6d20): 31 30 31 39 2e 30 30 35                         1019.005
+ Redzone  (0xc90f6d28): 00 cc cc cc                                     .
+ Padding  (0xc90f6d50): 5a 5a 5a 5a 5a 5a 5a 5a                         ZZZZZZZZ
 
    [<c010523d>] dump_trace+0x63/0x1eb
    [<c01053df>] show_trace_log_lvl+0x1a/0x2f
--- linux-ein-5.4.0.orig/Documentation/x86/topology.rst
+++ linux-ein-5.4.0/Documentation/x86/topology.rst
@@ -41,6 +41,8 @@
 Packages contain a number of cores plus shared resources, e.g. DRAM
 controller, shared caches etc.
 
+Modern systems may also use the term 'Die' for package.
+
 AMD nomenclature for package is 'Node'.
 
 Package-related topology information in the kernel:
@@ -53,11 +55,18 @@
 
     The number of dies in a package. This information is retrieved via CPUID.
 
+  - cpuinfo_x86.cpu_die_id:
+
+    The physical ID of the die. This information is retrieved via CPUID.
+
   - cpuinfo_x86.phys_proc_id:
 
     The physical ID of the package. This information is retrieved via CPUID
     and deduced from the APIC IDs of the cores in the package.
 
+    Modern systems use this value for the socket. There may be multiple
+    packages within a socket. This value may differ from cpu_die_id.
+
   - cpuinfo_x86.logical_proc_id:
 
     The logical ID of the package. As we do not trust BIOSes to enumerate the
--- linux-ein-5.4.0.orig/Documentation/xtensa/mmu.rst
+++ linux-ein-5.4.0/Documentation/xtensa/mmu.rst
@@ -82,7 +82,8 @@
   +------------------+
   | VMALLOC area     |  VMALLOC_START            0xc0000000  128MB - 64KB
   +------------------+  VMALLOC_END
-  | Cache aliasing   |  TLBTEMP_BASE_1           0xc7ff0000  DCACHE_WAY_SIZE
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_1           0xc8000000  DCACHE_WAY_SIZE
   | remap area 1     |
   +------------------+
   | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
@@ -124,7 +125,8 @@
   +------------------+
   | VMALLOC area     |  VMALLOC_START            0xa0000000  128MB - 64KB
   +------------------+  VMALLOC_END
-  | Cache aliasing   |  TLBTEMP_BASE_1           0xa7ff0000  DCACHE_WAY_SIZE
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_1           0xa8000000  DCACHE_WAY_SIZE
   | remap area 1     |
   +------------------+
   | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
@@ -167,7 +169,8 @@
   +------------------+
   | VMALLOC area     |  VMALLOC_START            0x90000000  128MB - 64KB
   +------------------+  VMALLOC_END
-  | Cache aliasing   |  TLBTEMP_BASE_1           0x97ff0000  DCACHE_WAY_SIZE
+  +------------------+
+  | Cache aliasing   |  TLBTEMP_BASE_1           0x98000000  DCACHE_WAY_SIZE
   | remap area 1     |
   +------------------+
   | Cache aliasing   |  TLBTEMP_BASE_2                       DCACHE_WAY_SIZE
--- linux-ein-5.4.0.orig/Kconfig
+++ linux-ein-5.4.0/Kconfig
@@ -21,6 +21,8 @@
 
 source "drivers/Kconfig"
 
+source "ubuntu/Kconfig"
+
 source "fs/Kconfig"
 
 source "security/Kconfig"
--- linux-ein-5.4.0.orig/MAINTAINERS
+++ linux-ein-5.4.0/MAINTAINERS
@@ -537,6 +537,17 @@
 F:	Documentation/scsi/advansys.txt
 F:	drivers/scsi/advansys.c
 
+ADVANTECH AHC1EC0 EMBEDDED CONTROLLER DRIVER
+M:	Campion Kang <campion.kang@advantech.com.tw>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/ahc1ec0.yaml
+F:	drivers/hwmon/ahc1ec0-hwmon.c
+F:	drivers/mfd/ahc1ec0.c
+F:	drivers/watchdog/ahc1ec0-wdt.c
+F:	include/dt-bindings/mfd/ahc1ec0-dt.h
+F:	include/linux/mfd/ahc1ec0.h
+
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:	Michael Hennerich <michael.hennerich@analog.com>
 W:	http://wiki.analog.com/ADXL345
@@ -1101,7 +1112,7 @@
 M:	William Breathitt Gray <vilhelm.gray@gmail.com>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
-F:	drivers/iio/adc/stx104.c
+F:	drivers/iio/addac/stx104.c
 
 APM DRIVER
 M:	Jiri Kosina <jikos@kernel.org>
@@ -2832,6 +2843,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:	aufs-users@lists.sourceforge.net (members only)
+L:	linux-unionfs@vger.kernel.org
+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>
 S:	Maintained
@@ -4028,6 +4052,7 @@
 C:	irc://chat.freenode.net/clangbuiltlinux
 S:	Supported
 K:	\b(?i:clang|llvm)\b
+F:	Documentation/kbuild/llvm.rst
 
 CLEANCACHE API
 M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
@@ -4616,13 +4641,6 @@
 F:	include/linux/tfrc.h
 F:	net/dccp/
 
-DECnet NETWORK LAYER
-W:	http://linux-decnet.sourceforge.net
-L:	linux-decnet-user@lists.sourceforge.net
-S:	Orphan
-F:	Documentation/networking/decnet.txt
-F:	net/decnet/
-
 DECSTATION PLATFORM SUPPORT
 M:	"Maciej W. Rozycki" <macro@linux-mips.org>
 L:	linux-mips@vger.kernel.org
@@ -6775,6 +6793,17 @@
 F:	tools/perf/bench/futex*
 F:	Documentation/*futex*
 
+GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
+M:	Tim Harvey <tharvey@gateworks.com>
+M:	Robert Jones <rjones@gateworks.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
+F:	drivers/mfd/gateworks-gsc.c
+F:	include/linux/mfd/gsc.h
+F:	Documentation/hwmon/gsc-hwmon.rst
+F:	drivers/hwmon/gsc-hwmon.c
+F:	include/linux/platform_data/gsc_hwmon.h
+
 GCC PLUGINS
 M:	Kees Cook <keescook@chromium.org>
 R:	Emese Revfy <re.emese@gmail.com>
@@ -6973,6 +7002,7 @@
 S:	Maintained
 F:	Documentation/firmware-guide/acpi/gpio-properties.rst
 F:	drivers/gpio/gpiolib-acpi.c
+F:	drivers/gpio/gpiolib-acpi.h
 
 GPIO IR Transmitter
 M:	Sean Young <sean@mess.org>
@@ -7364,6 +7394,25 @@
 F:	net/802/hippi.c
 F:	drivers/net/hippi/
 
+HISILICON SECURITY ENGINE V2 DRIVER (SEC2)
+M:	Zaibo Xu <xuzaibo@huawei.com>
+L:	linux-crypto@vger.kernel.org
+S:	Maintained
+F:	drivers/crypto/hisilicon/sec2/sec_crypto.c
+F:	drivers/crypto/hisilicon/sec2/sec_main.c
+F:	drivers/crypto/hisilicon/sec2/sec_crypto.h
+F:	drivers/crypto/hisilicon/sec2/sec.h
+F:	Documentation/ABI/testing/debugfs-hisi-sec
+
+HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
+M:	Zaibo Xu <xuzaibo@huawei.com>
+L:	linux-crypto@vger.kernel.org
+S:	Maintained
+F:	drivers/crypto/hisilicon/hpre/hpre_crypto.c
+F:	drivers/crypto/hisilicon/hpre/hpre_main.c
+F:	drivers/crypto/hisilicon/hpre/hpre.h
+F:	Documentation/ABI/testing/debugfs-hisi-hpre
+
 HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
 M:	Yisen Zhuang <yisen.zhuang@huawei.com>
 M:	Salil Mehta <salil.mehta@huawei.com>
@@ -7372,6 +7421,11 @@
 S:	Maintained
 F:	drivers/net/ethernet/hisilicon/hns3/
 
+HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
+M:	Zaibo Xu <xuzaibo@huawei.com>
+S:	Maintained
+F:	drivers/char/hw_random/hisi-trng-v2.c
+
 HISILICON LPC BUS DRIVER
 M:	john.garry@huawei.com
 W:	http://www.hisilicon.com
@@ -7410,6 +7464,12 @@
 F:	drivers/scsi/hisi_sas/
 F:	Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
 
+HISILICON V3XX SPI NOR FLASH Controller Driver
+M:	John Garry <john.garry@huawei.com>
+W:	http://www.hisilicon.com
+S:	Maintained
+F:	drivers/spi/spi-hisi-sfc-v3xx.c
+
 HISILICON QM AND ZIP Controller DRIVER
 M:	Zhou Wang <wangzhou1@hisilicon.com>
 L:	linux-crypto@vger.kernel.org
@@ -7417,7 +7477,6 @@
 F:	drivers/crypto/hisilicon/qm.c
 F:	drivers/crypto/hisilicon/qm.h
 F:	drivers/crypto/hisilicon/sgl.c
-F:	drivers/crypto/hisilicon/sgl.h
 F:	drivers/crypto/hisilicon/zip/
 F:	Documentation/ABI/testing/debugfs-hisi-zip
 
@@ -8200,7 +8259,7 @@
 M:	Rodrigo Vivi <rodrigo.vivi@intel.com>
 L:	intel-gfx@lists.freedesktop.org
 W:	https://01.org/linuxgraphics/
-B:	https://01.org/linuxgraphics/documentation/how-report-bugs
+B:	https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
 C:	irc://chat.freenode.net/intel-gfx
 Q:	http://patchwork.freedesktop.org/project/intel-gfx/
 T:	git git://anongit.freedesktop.org/drm-intel
@@ -8703,8 +8762,10 @@
 L:	netdev@vger.kernel.org
 W:	http://www.isdn4linux.de
 S:	Maintained
-F:	drivers/isdn/mISDN
-F:	drivers/isdn/hardware
+F:	drivers/isdn/mISDN/
+F:	drivers/isdn/hardware/
+F:	drivers/isdn/Kconfig
+F:	drivers/isdn/Makefile
 
 ISDN/CAPI SUBSYSTEM
 M:	Karsten Keil <isdn@linux-pingi.de>
@@ -8991,6 +9052,7 @@
 W:	http://www.ibm.com/developerworks/linux/linux390/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
 S:	Supported
+F:	Documentation/virt/kvm/s390*
 F:	arch/s390/include/uapi/asm/kvm*
 F:	arch/s390/include/asm/gmap.h
 F:	arch/s390/include/asm/kvm*
@@ -11662,6 +11724,14 @@
 F:	drivers/iio/gyro/fxas21002c_i2c.c
 F:	drivers/iio/gyro/fxas21002c_spi.c
 
+NXP i.MX 8MQ DCSS DRIVER
+M:	Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
+R:	Lucas Stach <l.stach@pengutronix.de>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
+F:	drivers/gpu/drm/imx/dcss/
+
 NXP SGTL5000 DRIVER
 M:	Fabio Estevam <festevam@gmail.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -12067,6 +12137,7 @@
 M:	Jens Wiklander <jens.wiklander@linaro.org>
 L:	tee-dev@lists.linaro.org
 S:	Maintained
+F:	Documentation/ABI/testing/sysfs-bus-optee-devices
 F:	drivers/tee/optee/
 
 OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
@@ -13636,6 +13707,7 @@
 
 RANDOM NUMBER DRIVER
 M:	"Theodore Ts'o" <tytso@mit.edu>
+M:	Jason A. Donenfeld <Jason@zx2c4.com>
 S:	Maintained
 F:	drivers/char/random.c
 
@@ -14131,6 +14203,7 @@
 S:	Supported
 F:	arch/s390/pci/
 F:	drivers/pci/hotplug/s390_pci_hpc.c
+F:	Documentation/s390/pci.rst
 
 S390 VFIO-CCW DRIVER
 M:	Cornelia Huck <cohuck@redhat.com>
@@ -14656,6 +14729,7 @@
 S:	Maintained
 F:	drivers/net/phy/phylink.c
 F:	drivers/net/phy/sfp*
+F:	include/linux/mdio/mdio-i2c.h
 F:	include/linux/phylink.h
 F:	include/linux/sfp.h
 K:	phylink
@@ -17859,7 +17933,8 @@
 F:	sound/xen/*
 
 XFS FILESYSTEM
-M:	Darrick J. Wong <darrick.wong@oracle.com>
+M:	Chandan Babu R <chandan.babu@oracle.com>
+M:	Darrick J. Wong <djwong@kernel.org>
 M:	linux-xfs@vger.kernel.org
 L:	linux-xfs@vger.kernel.org
 W:	http://xfs.org/
--- linux-ein-5.4.0.orig/Makefile
+++ linux-ein-5.4.0/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 5
 PATCHLEVEL = 4
-SUBLEVEL = 0
+SUBLEVEL = 271
 EXTRAVERSION =
 NAME = Kleptomaniac Octopus
 
@@ -89,9 +89,16 @@
 
 # If the user is running make -s (silent mode), suppress echoing of
 # commands
+# make-4.0 (and later) keep single letter options in the 1st word of MAKEFLAGS.
 
-ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),)
-  quiet=silent_
+ifeq ($(filter 3.%,$(MAKE_VERSION)),)
+silence:=$(findstring s,$(firstword -$(MAKEFLAGS)))
+else
+silence:=$(findstring s,$(filter-out --%,$(MAKEFLAGS)))
+endif
+
+ifeq ($(silence),s)
+quiet=silent_
 endif
 
 export quiet Q KBUILD_VERBOSE
@@ -206,6 +213,20 @@
   KBUILD_CHECKSRC = 0
 endif
 
+# Call message checker as part of the C compilation
+#
+# Use 'make D=1' to enable checking
+# Use 'make D=2' to create the message catalog
+
+ifdef D
+  ifeq ("$(origin D)", "command line")
+    KBUILD_KMSG_CHECK = $(D)
+  endif
+endif
+ifndef KBUILD_KMSG_CHECK
+  KBUILD_KMSG_CHECK = 0
+endif
+
 # Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the
 # directory of external module to build. Setting M= takes precedence.
 ifeq ("$(origin M)", "command line")
@@ -394,8 +415,13 @@
 HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null)
 HOST_LFS_LIBS := $(shell getconf LFS_LIBS 2>/dev/null)
 
-HOSTCC       = gcc
-HOSTCXX      = g++
+ifneq ($(LLVM),)
+HOSTCC	= clang
+HOSTCXX	= clang++
+else
+HOSTCC	= gcc
+HOSTCXX	= g++
+endif
 KBUILD_HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
 		-fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS) \
 		$(HOSTCFLAGS)
@@ -404,31 +430,49 @@
 KBUILD_HOSTLDLIBS   := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
 
 # Make variables (CC, etc...)
-AS		= $(CROSS_COMPILE)as
-LD		= $(CROSS_COMPILE)ld
-CC		= $(CROSS_COMPILE)gcc
 CPP		= $(CC) -E
+ifneq ($(LLVM),)
+CC		= clang
+LD		= ld.lld
+AR		= llvm-ar
+NM		= llvm-nm
+OBJCOPY		= llvm-objcopy
+OBJDUMP		= llvm-objdump
+READELF		= llvm-readelf
+OBJSIZE		= llvm-size
+STRIP		= llvm-strip
+else
+CC		= $(CROSS_COMPILE)gcc
+LD		= $(CROSS_COMPILE)ld
 AR		= $(CROSS_COMPILE)ar
 NM		= $(CROSS_COMPILE)nm
-STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
 OBJDUMP		= $(CROSS_COMPILE)objdump
+READELF		= $(CROSS_COMPILE)readelf
 OBJSIZE		= $(CROSS_COMPILE)size
+STRIP		= $(CROSS_COMPILE)strip
+endif
 PAHOLE		= pahole
 LEX		= flex
 YACC		= bison
 AWK		= awk
 INSTALLKERNEL  := installkernel
-DEPMOD		= /sbin/depmod
+DEPMOD		= depmod
 PERL		= perl
 PYTHON		= python
-PYTHON2		= python2
 PYTHON3		= python3
 CHECK		= sparse
 BASH		= bash
+KGZIP		= gzip
+KBZIP2		= bzip2
+KLZOP		= lzop
+LZMA		= lzma
+LZ4		= lz4c
+XZ		= xz
 
 CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
 		  -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
+KMSG_CHECK	= $(srctree)/scripts/kmsg-doc
 NOSTDINC_FLAGS :=
 CFLAGS_MODULE   =
 AFLAGS_MODULE   =
@@ -437,6 +481,13 @@
 AFLAGS_KERNEL	=
 LDFLAGS_vmlinux =
 
+# 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    := \
 		-I$(srctree)/arch/$(SRCARCH)/include/uapi \
@@ -448,17 +499,21 @@
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := \
+		$(UBUNTUINCLUDE) \
 		-I$(srctree)/arch/$(SRCARCH)/include \
 		-I$(objtree)/arch/$(SRCARCH)/include/generated \
 		$(if $(building_out_of_srctree),-I$(srctree)/include) \
 		-I$(objtree)/include \
 		$(USERINCLUDE)
 
+# UBUNTU: Include our third party driver stuff too
+LINUXINCLUDE   += -Iubuntu/include $(if $(KBUILD_SRC),-I$(srctree)/ubuntu/include)
+
 KBUILD_AFLAGS   := -D__ASSEMBLY__ -fno-PIE
 KBUILD_CFLAGS   := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE \
 		   -Werror=implicit-function-declaration -Werror=implicit-int \
-		   -Wno-format-security \
+		   -Werror=return-type -Wno-format-security \
 		   -std=gnu89
 KBUILD_CPPFLAGS := -D__KERNEL__
 KBUILD_AFLAGS_KERNEL :=
@@ -471,15 +526,17 @@
 GCC_PLUGINS_CFLAGS :=
 CLANG_FLAGS :=
 
-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
-export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE PAHOLE LEX YACC AWK INSTALLKERNEL
-export PERL PYTHON PYTHON2 PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
+export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
+export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF PAHOLE LEX YACC AWK INSTALLKERNEL
+export PERL PYTHON PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
+export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ
 export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
 
 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
 export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
 export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+export KBUILD_KMSG_CHECK KMSG_CHECK
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
 
@@ -528,13 +585,13 @@
 ifneq ($(CROSS_COMPILE),)
 CLANG_FLAGS	+= --target=$(notdir $(CROSS_COMPILE:%-=%))
 GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit))
-CLANG_FLAGS	+= --prefix=$(GCC_TOOLCHAIN_DIR)
+CLANG_FLAGS	+= --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
 GCC_TOOLCHAIN	:= $(realpath $(GCC_TOOLCHAIN_DIR)/..)
 endif
 ifneq ($(GCC_TOOLCHAIN),)
 CLANG_FLAGS	+= --gcc-toolchain=$(GCC_TOOLCHAIN)
 endif
-ifeq ($(shell $(AS) --version 2>&1 | head -n 1 | grep clang),)
+ifneq ($(LLVM_IAS),1)
 CLANG_FLAGS	+= -no-integrated-as
 endif
 CLANG_FLAGS	+= -Werror=unknown-warning-option
@@ -587,12 +644,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
@@ -616,9 +669,8 @@
 ifeq ($(KBUILD_EXTMOD),)
 # Objects we will link into vmlinux / subdirs we need to visit
 init-y		:= init/
-drivers-y	:= drivers/ sound/
+drivers-y	:= drivers/ sound/ ubuntu/
 drivers-$(CONFIG_SAMPLES) += samples/
-drivers-$(CONFIG_KERNEL_HEADER_TEST) += include/
 net-y		:= net/
 libs-y		:= lib/
 core-y		:= usr/
@@ -708,12 +760,9 @@
 KBUILD_CFLAGS += -Os
 endif
 
-ifdef CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED
-KBUILD_CFLAGS   += -Wno-maybe-uninitialized
-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)
 
 include scripts/Makefile.kcov
 include scripts/Makefile.gcc-plugins
@@ -750,17 +799,21 @@
 KBUILD_CFLAGS += -mno-global-merge
 else
 
-# These warnings generated too much noise in a regular build.
-# Use make W=1 to enable them (see scripts/Makefile.extrawarn)
-KBUILD_CFLAGS += -Wno-unused-but-set-variable
-
 # Warn about unmarked fall-throughs in switch statement.
 # Disabled for clang while comment to attribute conversion happens and
 # https://github.com/ClangBuiltLinux/linux/issues/636 is discussed.
 KBUILD_CFLAGS += $(call cc-option,-Wimplicit-fallthrough,)
 endif
 
+# 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)
+
 KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable)
+
+# These result in bogus false positives
+KBUILD_CFLAGS += $(call cc-disable-warning, dangling-pointer)
+
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS	+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -787,8 +840,13 @@
 else
 DEBUG_CFLAGS	+= -g
 endif
+ifeq ($(LLVM_IAS),1)
+KBUILD_AFLAGS	+= -g
+else
 KBUILD_AFLAGS	+= -Wa,-gdwarf-2
 endif
+endif
+
 ifdef CONFIG_DEBUG_INFO_DWARF4
 DEBUG_CFLAGS	+= -gdwarf-4
 endif
@@ -861,6 +919,17 @@
 # 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)
 
@@ -891,12 +960,6 @@
 # change __FILE__ to the relative path from the srctree
 KBUILD_CFLAGS	+= $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
 
-# ensure -fcf-protection is disabled when using retpoline as it is
-# incompatible with -mindirect-branch=thunk-extern
-ifdef CONFIG_RETPOLINE
-KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
-endif
-
 include scripts/Makefile.kasan
 include scripts/Makefile.extrawarn
 include scripts/Makefile.ubsan
@@ -909,12 +972,15 @@
 KBUILD_LDFLAGS_MODULE += --build-id
 LDFLAGS_vmlinux += --build-id
 
+KBUILD_LDFLAGS	+= -z noexecstack
+KBUILD_LDFLAGS	+= $(call ld-option,--no-warn-rwx-segments)
+
 ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
 LDFLAGS_vmlinux	+= $(call ld-option, -X,)
 endif
 
 ifeq ($(CONFIG_RELR),y)
-LDFLAGS_vmlinux	+= --pack-dyn-relocs=relr
+LDFLAGS_vmlinux	+= --pack-dyn-relocs=relr --use-android-relr-tags
 endif
 
 # make the checker run with the right architecture
@@ -978,10 +1044,10 @@
 mod_compress_cmd = true
 ifdef CONFIG_MODULE_COMPRESS
   ifdef CONFIG_MODULE_COMPRESS_GZIP
-    mod_compress_cmd = gzip -n -f
+    mod_compress_cmd = $(KGZIP) -n -f
   endif # CONFIG_MODULE_COMPRESS_GZIP
   ifdef CONFIG_MODULE_COMPRESS_XZ
-    mod_compress_cmd = xz -f
+    mod_compress_cmd = $(XZ) -f
   endif # CONFIG_MODULE_COMPRESS_XZ
 endif # CONFIG_MODULE_COMPRESS
 export mod_compress_cmd
@@ -999,7 +1065,7 @@
 
 ifdef CONFIG_STACK_VALIDATION
   has_libelf := $(call try-run,\
-		echo "int main() {}" | $(HOSTCC) -xc -o /dev/null $(HOST_LIBELF_LIBS) -,1,0)
+		echo "int main() {}" | $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -xc -o /dev/null $(HOST_LIBELF_LIBS) -,1,0)
   ifeq ($(has_libelf),1)
     objtool_target := tools/objtool FORCE
   else
@@ -1050,7 +1116,7 @@
 ifdef CONFIG_TRIM_UNUSED_KSYMS
 autoksyms_recursive: descend modules.order
 	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
-	  "$(MAKE) -f $(srctree)/Makefile vmlinux"
+	  "$(MAKE) -f $(srctree)/Makefile autoksyms_recursive"
 endif
 
 # For the kernel to actually contain only the needed exported symbols,
@@ -1152,11 +1218,19 @@
 endef
 
 define filechk_version.h
-	echo \#define LINUX_VERSION_CODE $(shell                         \
-	expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
-	echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'
+	if [ $(SUBLEVEL) -gt 255 ]; then                                 \
+		echo \#define LINUX_VERSION_CODE $(shell                 \
+		expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + 255); \
+	else                                                             \
+		echo \#define LINUX_VERSION_CODE $(shell                 \
+		expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL)); \
+	fi;                                                              \
+	echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) +  \
+	((c) > 255 ? 255 : (c)))'
 endef
 
+$(version_h): PATCHLEVEL := $(if $(PATCHLEVEL), $(PATCHLEVEL), 0)
+$(version_h): SUBLEVEL := $(if $(SUBLEVEL), $(SUBLEVEL), 0)
 $(version_h): FORCE
 	$(call filechk,version.h)
 	$(Q)rm -f $(old_version_h)
@@ -1195,20 +1269,17 @@
 	  $(error Headers not exportable for the $(SRCARCH) architecture))
 	$(Q)$(MAKE) $(hdr-inst)=include/uapi
 	$(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi
+	$(Q)$(MAKE) $(hdr-inst)=ubuntu/include dst=include oldheaders=
 
+# Deprecated. It is no-op now.
 PHONY += headers_check
-headers_check: headers
-	$(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1
-	$(Q)$(MAKE) $(hdr-inst)=arch/$(SRCARCH)/include/uapi HDRCHECK=1
+headers_check:
+	@:
 
 ifdef CONFIG_HEADERS_INSTALL
 prepare: headers
 endif
 
-ifdef CONFIG_HEADERS_CHECK
-all: headers_check
-endif
-
 PHONY += scripts_unifdef
 scripts_unifdef: scripts_basic
 	$(Q)$(MAKE) $(build)=scripts scripts/unifdef
@@ -1242,12 +1313,16 @@
 %.dtb: include/config/kernel.release scripts_dtc
 	$(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-PHONY += dtbs dtbs_install dt_binding_check
-dtbs dtbs_check: include/config/kernel.release scripts_dtc
+PHONY += dtbs dtbs_install dtbs_check
+dtbs: include/config/kernel.release scripts_dtc
 	$(Q)$(MAKE) $(build)=$(dtstree)
 
+ifneq ($(filter dtbs_check, $(MAKECMDGOALS)),)
+dtbs: dt_binding_check
+endif
+
 dtbs_check: export CHECK_DTBS=1
-dtbs_check: dt_binding_check
+dtbs_check: dtbs
 
 dtbs_install:
 	$(Q)$(MAKE) $(dtbinst)=$(dtstree)
@@ -1262,6 +1337,7 @@
 scripts_dtc: scripts_basic
 	$(Q)$(MAKE) $(build)=scripts/dtc
 
+PHONY += dt_binding_check
 dt_binding_check: scripts_dtc
 	$(Q)$(MAKE) $(build)=Documentation/devicetree/bindings
 
@@ -1274,6 +1350,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
@@ -1476,7 +1559,6 @@
 	@echo  '  versioncheck    - Sanity check on version.h usage'
 	@echo  '  includecheck    - Check for duplicate included header files'
 	@echo  '  export_report   - List the usages of all exported symbols'
-	@echo  '  headers_check   - Sanity check on exported headers'
 	@echo  '  headerdep       - Detect inclusion cycles in headers'
 	@echo  '  coccicheck      - Check with Coccinelle'
 	@echo  ''
@@ -1641,6 +1723,50 @@
 PHONY += prepare
 endif # KBUILD_EXTMOD
 
+# Single targets
+# ---------------------------------------------------------------------------
+# To build individual files in subdirectories, you can do like this:
+#
+#   make foo/bar/baz.s
+#
+# The supported suffixes for single-target are listed in 'single-targets'
+#
+# To build only under specific subdirectories, you can do like this:
+#
+#   make foo/bar/baz/
+
+ifdef single-build
+
+# .ko is special because modpost is needed
+single-ko := $(sort $(filter %.ko, $(MAKECMDGOALS)))
+single-no-ko := $(sort $(patsubst %.ko,%.mod, $(MAKECMDGOALS)))
+
+$(single-ko): single_modpost
+	@:
+$(single-no-ko): descend
+	@:
+
+ifeq ($(KBUILD_EXTMOD),)
+# For the single build of in-tree modules, use a temporary file to avoid
+# the situation of modules_install installing an invalid modules.order.
+MODORDER := .modules.tmp
+endif
+
+PHONY += single_modpost
+single_modpost: $(single-no-ko)
+	$(Q){ $(foreach m, $(single-ko), echo $(extmod-prefix)$m;) } > $(MODORDER)
+	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
+
+KBUILD_MODULES := 1
+
+export KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko))
+
+# trim unrelated directories
+build-dirs := $(foreach d, $(build-dirs), \
+			$(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d)))
+
+endif
+
 # Handle descending into subdirectories listed in $(build-dirs)
 # Preset locale variables to speed up the build process. Limit locale
 # tweaks to this spot to avoid wrong language settings when running
@@ -1649,7 +1775,9 @@
 PHONY += descend $(build-dirs)
 descend: $(build-dirs)
 $(build-dirs): prepare
-	$(Q)$(MAKE) $(build)=$@ single-build=$(single-build) need-builtin=1 need-modorder=1
+	$(Q)$(MAKE) $(build)=$@ \
+	single-build=$(if $(filter-out $@/, $(single-no-ko)),1) \
+	need-builtin=1 need-modorder=1
 
 clean-dirs := $(addprefix _clean_, $(clean-dirs))
 PHONY += $(clean-dirs) clean
@@ -1753,50 +1881,6 @@
 	$(Q)mkdir -p $(objtree)/tools
 	$(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ $*
 
-# Single targets
-# ---------------------------------------------------------------------------
-# To build individual files in subdirectories, you can do like this:
-#
-#   make foo/bar/baz.s
-#
-# The supported suffixes for single-target are listed in 'single-targets'
-#
-# To build only under specific subdirectories, you can do like this:
-#
-#   make foo/bar/baz/
-
-ifdef single-build
-
-single-all := $(filter $(single-targets), $(MAKECMDGOALS))
-
-# .ko is special because modpost is needed
-single-ko := $(sort $(filter %.ko, $(single-all)))
-single-no-ko := $(sort $(patsubst %.ko,%.mod, $(single-all)))
-
-$(single-ko): single_modpost
-	@:
-$(single-no-ko): descend
-	@:
-
-ifeq ($(KBUILD_EXTMOD),)
-# For the single build of in-tree modules, use a temporary file to avoid
-# the situation of modules_install installing an invalid modules.order.
-MODORDER := .modules.tmp
-endif
-
-PHONY += single_modpost
-single_modpost: $(single-no-ko)
-	$(Q){ $(foreach m, $(single-ko), echo $(extmod-prefix)$m;) } > $(MODORDER)
-	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
-
-KBUILD_MODULES := 1
-
-export KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko))
-
-single-build = $(if $(filter-out $@/, $(single-no-ko)),1)
-
-endif
-
 # FIXME Should go into a make.lib or something
 # ===========================================================================
 
--- linux-ein-5.4.0.orig/Ubuntu.md
+++ linux-ein-5.4.0/Ubuntu.md
@@ -0,0 +1,7 @@
+Name:    linux-imx
+Version: 5.4.0
+Series:  20.04 (focal)
+Description:
+    This is the source code for the Ubuntu linux kernel for the 20.04 series. This
+    source tree is used to produce the flavours: imx.
+    This kernel is configured to support specialized IMX devices.
--- linux-ein-5.4.0.orig/arch/Kconfig
+++ linux-ein-5.4.0/arch/Kconfig
@@ -131,6 +131,22 @@
 	    managed by the kernel and kept transparent to the probed
 	    application. )
 
+config HAVE_64BIT_ALIGNED_ACCESS
+	def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS
+	help
+	  Some architectures require 64 bit accesses to be 64 bit
+	  aligned, which also requires structs containing 64 bit values
+	  to be 64 bit aligned too. This includes some 32 bit
+	  architectures which can do 64 bit accesses, as well as 64 bit
+	  architectures without unaligned access.
+
+	  This symbol should be selected by an architecture if 64 bit
+	  accesses are required to be 64 bit aligned in this way even
+	  though it is not a 64 bit architecture.
+
+	  See Documentation/unaligned-memory-access.txt for more
+	  information on the topic of unaligned memory accesses.
+
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
 	bool
 	help
@@ -255,6 +271,9 @@
 	select ARCH_HAS_DMA_PREP_COHERENT
 	bool
 
+config ARCH_HAS_CPU_FINALIZE_INIT
+	bool
+
 # Select if arch init_task must go in the __init_task_data section
 config ARCH_TASK_STRUCT_ON_STACK
        bool
@@ -396,15 +415,22 @@
 config HAVE_RCU_TABLE_FREE
 	bool
 
-config HAVE_RCU_TABLE_NO_INVALIDATE
+config HAVE_MMU_GATHER_PAGE_SIZE
 	bool
 
-config HAVE_MMU_GATHER_PAGE_SIZE
+config MMU_GATHER_NO_RANGE
 	bool
 
 config HAVE_MMU_GATHER_NO_GATHER
 	bool
 
+config ARCH_WANT_IRQS_OFF_ACTIVATE_MM
+	bool
+	help
+	  Temporary select until all architectures can be converted to have
+	  irqs disabled over activate_mm. Architectures that do IPI based TLB
+	  shootdowns should enable this.
+
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
 	bool
 
@@ -892,27 +918,6 @@
 config ARCH_HAS_PHYS_TO_DMA
 	bool
 
-config ARCH_HAS_REFCOUNT
-	bool
-	help
-	  An architecture selects this when it has implemented refcount_t
-	  using open coded assembly primitives that provide an optimized
-	  refcount_t implementation, possibly at the expense of some full
-	  refcount state checks of CONFIG_REFCOUNT_FULL=y.
-
-	  The refcount overflow check behavior, however, must be retained.
-	  Catching overflows is the primary security concern for protecting
-	  against bugs in reference counts.
-
-config REFCOUNT_FULL
-	bool "Perform full reference count validation at the expense of speed"
-	help
-	  Enabling this switches the refcounting infrastructure from a fast
-	  unchecked atomic_t implementation to a fully state checked
-	  implementation, which can be (slightly) slower but provides protections
-	  against various use-after-free conditions that can be used in
-	  security flaw exploits.
-
 config HAVE_ARCH_COMPILER_H
 	bool
 	help
--- linux-ein-5.4.0.orig/arch/alpha/configs/defconfig
+++ linux-ein-5.4.0/arch/alpha/configs/defconfig
@@ -36,7 +36,6 @@
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
--- linux-ein-5.4.0.orig/arch/alpha/include/asm/io.h
+++ linux-ein-5.4.0/arch/alpha/include/asm/io.h
@@ -61,7 +61,7 @@
  * Change virtual addresses to physical addresses and vv.
  */
 #ifdef USE_48_BIT_KSEG
-static inline unsigned long virt_to_phys(void *address)
+static inline unsigned long virt_to_phys(volatile void *address)
 {
 	return (unsigned long)address - IDENT_ADDR;
 }
@@ -71,7 +71,7 @@
 	return (void *) (address + IDENT_ADDR);
 }
 #else
-static inline unsigned long virt_to_phys(void *address)
+static inline unsigned long virt_to_phys(volatile void *address)
 {
         unsigned long phys = (unsigned long)address;
 
@@ -107,7 +107,7 @@
 extern unsigned long __direct_map_base;
 extern unsigned long __direct_map_size;
 
-static inline unsigned long __deprecated virt_to_bus(void *address)
+static inline unsigned long __deprecated virt_to_bus(volatile void *address)
 {
 	unsigned long phys = virt_to_phys(address);
 	unsigned long bus = phys + __direct_map_base;
@@ -322,14 +322,18 @@
 #if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
 extern inline unsigned int ioread8(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
 	mb();
 	return ret;
 }
 
 extern inline unsigned int ioread16(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
 	mb();
 	return ret;
 }
@@ -370,7 +374,9 @@
 #if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
 extern inline unsigned int ioread32(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
 	mb();
 	return ret;
 }
@@ -415,14 +421,18 @@
 
 extern inline u8 readb(const volatile void __iomem *addr)
 {
-	u8 ret = __raw_readb(addr);
+	u8 ret;
+	mb();
+	ret = __raw_readb(addr);
 	mb();
 	return ret;
 }
 
 extern inline u16 readw(const volatile void __iomem *addr)
 {
-	u16 ret = __raw_readw(addr);
+	u16 ret;
+	mb();
+	ret = __raw_readw(addr);
 	mb();
 	return ret;
 }
@@ -463,14 +473,18 @@
 
 extern inline u32 readl(const volatile void __iomem *addr)
 {
-	u32 ret = __raw_readl(addr);
+	u32 ret;
+	mb();
+	ret = __raw_readl(addr);
 	mb();
 	return ret;
 }
 
 extern inline u64 readq(const volatile void __iomem *addr)
 {
-	u64 ret = __raw_readq(addr);
+	u64 ret;
+	mb();
+	ret = __raw_readq(addr);
 	mb();
 	return ret;
 }
@@ -488,10 +502,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
@@ -499,14 +513,44 @@
 #define outb_p		outb
 #define outw_p		outw
 #define outl_p		outl
-#define readb_relaxed(addr)	__raw_readb(addr)
-#define readw_relaxed(addr)	__raw_readw(addr)
-#define readl_relaxed(addr)	__raw_readl(addr)
-#define readq_relaxed(addr)	__raw_readq(addr)
-#define writeb_relaxed(b, addr)	__raw_writeb(b, addr)
-#define writew_relaxed(b, addr)	__raw_writew(b, addr)
-#define writel_relaxed(b, addr)	__raw_writel(b, addr)
-#define writeq_relaxed(b, addr)	__raw_writeq(b, addr)
+
+extern u8 readb_relaxed(const volatile void __iomem *addr);
+extern u16 readw_relaxed(const volatile void __iomem *addr);
+extern u32 readl_relaxed(const volatile void __iomem *addr);
+extern u64 readq_relaxed(const volatile void __iomem *addr);
+
+#if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
+extern inline u8 readb_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readb(addr);
+}
+
+extern inline u16 readw_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readw(addr);
+}
+#endif
+
+#if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
+extern inline u32 readl_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readl(addr);
+}
+
+extern inline u64 readq_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readq(addr);
+}
+#endif
+
+#define writeb_relaxed	writeb
+#define writew_relaxed	writew
+#define writel_relaxed	writel
+#define writeq_relaxed	writeq
 
 /*
  * String version of IO memory access ops:
--- linux-ein-5.4.0.orig/arch/alpha/include/asm/timex.h
+++ linux-ein-5.4.0/arch/alpha/include/asm/timex.h
@@ -28,5 +28,6 @@
 	__asm__ __volatile__ ("rpcc %0" : "=r"(ret));
 	return ret;
 }
+#define get_cycles get_cycles
 
 #endif
--- linux-ein-5.4.0.orig/arch/alpha/kernel/entry.S
+++ linux-ein-5.4.0/arch/alpha/kernel/entry.S
@@ -469,8 +469,10 @@
 #ifdef CONFIG_AUDITSYSCALL
 	lda     $6, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
 	and     $3, $6, $3
-#endif
 	bne     $3, strace
+#else
+	blbs    $3, strace		/* check for SYSCALL_TRACE in disguise */
+#endif
 	beq	$4, 1f
 	ldq	$27, 0($5)
 1:	jsr	$26, ($27), sys_ni_syscall
--- linux-ein-5.4.0.orig/arch/alpha/kernel/io.c
+++ linux-ein-5.4.0/arch/alpha/kernel/io.c
@@ -16,21 +16,27 @@
 unsigned int
 ioread8(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
 	mb();
 	return ret;
 }
 
 unsigned int ioread16(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
 	mb();
 	return ret;
 }
 
 unsigned int ioread32(void __iomem *addr)
 {
-	unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
+	unsigned int ret;
+	mb();
+	ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
 	mb();
 	return ret;
 }
@@ -148,28 +154,36 @@
 
 u8 readb(const volatile void __iomem *addr)
 {
-	u8 ret = __raw_readb(addr);
+	u8 ret;
+	mb();
+	ret = __raw_readb(addr);
 	mb();
 	return ret;
 }
 
 u16 readw(const volatile void __iomem *addr)
 {
-	u16 ret = __raw_readw(addr);
+	u16 ret;
+	mb();
+	ret = __raw_readw(addr);
 	mb();
 	return ret;
 }
 
 u32 readl(const volatile void __iomem *addr)
 {
-	u32 ret = __raw_readl(addr);
+	u32 ret;
+	mb();
+	ret = __raw_readl(addr);
 	mb();
 	return ret;
 }
 
 u64 readq(const volatile void __iomem *addr)
 {
-	u64 ret = __raw_readq(addr);
+	u64 ret;
+	mb();
+	ret = __raw_readq(addr);
 	mb();
 	return ret;
 }
@@ -207,6 +221,38 @@
 EXPORT_SYMBOL(writel);
 EXPORT_SYMBOL(writeq);
 
+/*
+ * The _relaxed functions must be ordered w.r.t. each other, but they don't
+ * have to be ordered w.r.t. other memory accesses.
+ */
+u8 readb_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readb(addr);
+}
+
+u16 readw_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readw(addr);
+}
+
+u32 readl_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readl(addr);
+}
+
+u64 readq_relaxed(const volatile void __iomem *addr)
+{
+	mb();
+	return __raw_readq(addr);
+}
+
+EXPORT_SYMBOL(readb_relaxed);
+EXPORT_SYMBOL(readw_relaxed);
+EXPORT_SYMBOL(readl_relaxed);
+EXPORT_SYMBOL(readq_relaxed);
 
 /*
  * Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
--- linux-ein-5.4.0.orig/arch/alpha/kernel/module.c
+++ linux-ein-5.4.0/arch/alpha/kernel/module.c
@@ -146,10 +146,8 @@
 	base = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr;
 	symtab = (Elf64_Sym *)sechdrs[symindex].sh_addr;
 
-	/* The small sections were sorted to the end of the segment.
-	   The following should definitely cover them.  */
-	gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
 	got = sechdrs[me->arch.gotsecindex].sh_addr;
+	gp = got + 0x8000;
 
 	for (i = 0; i < n; i++) {
 		unsigned long r_sym = ELF64_R_SYM (rela[i].r_info);
--- linux-ein-5.4.0.orig/arch/alpha/kernel/setup.c
+++ linux-ein-5.4.0/arch/alpha/kernel/setup.c
@@ -394,8 +394,7 @@
 extern void setup_memory(void *);
 #endif /* !CONFIG_DISCONTIGMEM */
 
-int __init
-page_is_ram(unsigned long pfn)
+int page_is_ram(unsigned long pfn)
 {
 	struct memclust_struct * cluster;
 	struct memdesc_struct * memdesc;
--- linux-ein-5.4.0.orig/arch/alpha/kernel/smp.c
+++ linux-ein-5.4.0/arch/alpha/kernel/smp.c
@@ -585,7 +585,7 @@
 smp_send_stop(void)
 {
 	cpumask_t to_whom;
-	cpumask_copy(&to_whom, cpu_possible_mask);
+	cpumask_copy(&to_whom, cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), &to_whom);
 #ifdef DEBUG_IPI_MSG
 	if (hard_smp_processor_id() != boot_cpu_id)
--- linux-ein-5.4.0.orig/arch/alpha/kernel/srmcons.c
+++ linux-ein-5.4.0/arch/alpha/kernel/srmcons.c
@@ -59,7 +59,7 @@
 	} while((result.bits.status & 1) && (++loops < 10));
 
 	if (count)
-		tty_schedule_flip(port);
+		tty_flip_buffer_push(port);
 
 	return count;
 }
--- linux-ein-5.4.0.orig/arch/alpha/kernel/traps.c
+++ linux-ein-5.4.0/arch/alpha/kernel/traps.c
@@ -192,7 +192,7 @@
 		local_irq_enable();
 		while (1);
 	}
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 #ifndef CONFIG_MATHEMU
@@ -235,7 +235,21 @@
 {
 	int signo, code;
 
-	if ((regs->ps & ~IPL_MAX) == 0) {
+	if (type == 3) { /* FEN fault */
+		/* Irritating users can call PAL_clrfen to disable the
+		   FPU for the process.  The kernel will then trap in
+		   do_switch_stack and undo_switch_stack when we try
+		   to save and restore the FP registers.
+
+		   Given that GCC by default generates code that uses the
+		   FP registers, PAL_clrfen is not useful except for DoS
+		   attacks.  So turn the bleeding FPU back on and be done
+		   with it.  */
+		current_thread_info()->pcb.flags |= 1;
+		__reload_thread(&current_thread_info()->pcb);
+		return;
+	}
+	if (!user_mode(regs)) {
 		if (type == 1) {
 			const unsigned int *data
 			  = (const unsigned int *) regs->pc;
@@ -368,20 +382,6 @@
 		}
 		break;
 
-	      case 3: /* FEN fault */
-		/* Irritating users can call PAL_clrfen to disable the
-		   FPU for the process.  The kernel will then trap in
-		   do_switch_stack and undo_switch_stack when we try
-		   to save and restore the FP registers.
-
-		   Given that GCC by default generates code that uses the
-		   FP registers, PAL_clrfen is not useful except for DoS
-		   attacks.  So turn the bleeding FPU back on and be done
-		   with it.  */
-		current_thread_info()->pcb.flags |= 1;
-		__reload_thread(&current_thread_info()->pcb);
-		return;
-
 	      case 5: /* illoc */
 	      default: /* unexpected instruction-fault type */
 		      ;
@@ -577,7 +577,7 @@
 
 	printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n",
 		pc, va, opcode, reg);
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 
 got_exception:
 	/* Ok, we caught the exception, but we don't want it.  Is there
@@ -632,7 +632,7 @@
 		local_irq_enable();
 		while (1);
 	}
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/alpha/mm/fault.c
+++ linux-ein-5.4.0/arch/alpha/mm/fault.c
@@ -206,7 +206,7 @@
 	printk(KERN_ALERT "Unable to handle kernel paging request at "
 	       "virtual address %016lx\n", address);
 	die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 
 	/* We ran out of memory, or some other thing happened to us that
 	   made us unable to handle the page fault gracefully.  */
--- linux-ein-5.4.0.orig/arch/arc/Kconfig
+++ linux-ein-5.4.0/arch/arc/Kconfig
@@ -29,6 +29,7 @@
 	select GENERIC_SMP_IDLE_THREAD
 	select HAVE_ARCH_KGDB
 	select HAVE_ARCH_TRACEHOOK
+	select HAVE_COPY_THREAD_TLS
 	select HAVE_DEBUG_STACKOVERFLOW
 	select HAVE_FUTEX_CMPXCHG if FUTEX
 	select HAVE_IOREMAP_PROT
--- linux-ein-5.4.0.orig/arch/arc/Makefile
+++ linux-ein-5.4.0/arch/arc/Makefile
@@ -90,16 +90,22 @@
 
 boot		:= arch/arc/boot
 
-#default target for make without any arguments.
-KBUILD_IMAGE	:= $(boot)/bootpImage
-
-all:	bootpImage
-bootpImage: vmlinux
-
-boot_targets += uImage uImage.bin uImage.gz
+boot_targets := uImage.bin uImage.gz uImage.lzma
 
+PHONY += $(boot_targets)
 $(boot_targets): vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
+uimage-default-y			:= uImage.bin
+uimage-default-$(CONFIG_KERNEL_GZIP)	:= uImage.gz
+uimage-default-$(CONFIG_KERNEL_LZMA)	:= uImage.lzma
+
+PHONY += uImage
+uImage: $(uimage-default-y)
+	@ln -sf $< $(boot)/uImage
+	@$(kecho) '  Image $(boot)/uImage is ready'
+
+CLEAN_FILES += $(boot)/uImage
+
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
--- linux-ein-5.4.0.orig/arch/arc/boot/Makefile
+++ linux-ein-5.4.0/arch/arc/boot/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-targets := vmlinux.bin vmlinux.bin.gz uImage
+targets := vmlinux.bin vmlinux.bin.gz
 
 # uImage build relies on mkimage being availble on your host for ARC target
 # You will need to build u-boot for ARC, rename mkimage to arc-elf32-mkimage
@@ -13,11 +13,6 @@
 UIMAGE_LOADADDR    = $(CONFIG_LINUX_LINK_BASE)
 UIMAGE_ENTRYADDR   = $(LINUX_START_TEXT)
 
-suffix-y := bin
-suffix-$(CONFIG_KERNEL_GZIP)	:= gz
-suffix-$(CONFIG_KERNEL_LZMA)	:= lzma
-
-targets += uImage
 targets += uImage.bin
 targets += uImage.gz
 targets += uImage.lzma
@@ -42,7 +37,3 @@
 
 $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma FORCE
 	$(call if_changed,uimage,lzma)
-
-$(obj)/uImage: $(obj)/uImage.$(suffix-y)
-	@ln -sf $(notdir $<) $@
-	@echo '  Image $@ is ready'
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/axc001.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/axc001.dtsi
@@ -85,7 +85,7 @@
 	 * avoid duplicating the MB dtsi file given that IRQ from
 	 * this intc to cpu intc are different for axs101 and axs103
 	 */
-	mb_intc: dw-apb-ictl@e0012000 {
+	mb_intc: interrupt-controller@e0012000 {
 		#interrupt-cells = <1>;
 		compatible = "snps,dw-apb-ictl";
 		reg = < 0x0 0xe0012000 0x0 0x200 >;
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/axc003.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/axc003.dtsi
@@ -129,7 +129,7 @@
 	 * avoid duplicating the MB dtsi file given that IRQ from
 	 * this intc to cpu intc are different for axs101 and axs103
 	 */
-	mb_intc: dw-apb-ictl@e0012000 {
+	mb_intc: interrupt-controller@e0012000 {
 		#interrupt-cells = <1>;
 		compatible = "snps,dw-apb-ictl";
 		reg = < 0x0 0xe0012000 0x0 0x200 >;
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/axc003_idu.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/axc003_idu.dtsi
@@ -135,7 +135,7 @@
 	 * avoid duplicating the MB dtsi file given that IRQ from
 	 * this intc to cpu intc are different for axs101 and axs103
 	 */
-	mb_intc: dw-apb-ictl@e0012000 {
+	mb_intc: interrupt-controller@e0012000 {
 		#interrupt-cells = <1>;
 		compatible = "snps,dw-apb-ictl";
 		reg = < 0x0 0xe0012000 0x0 0x200 >;
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/axs10x_mb.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/axs10x_mb.dtsi
@@ -77,6 +77,7 @@
 			interrupt-names = "macirq";
 			phy-mode = "rgmii";
 			snps,pbl = < 32 >;
+			snps,multicast-filter-bins = <256>;
 			clocks = <&apbclk>;
 			clock-names = "stmmaceth";
 			max-speed = <100>;
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/hsdk.dts
+++ linux-ein-5.4.0/arch/arc/boot/dts/hsdk.dts
@@ -88,6 +88,8 @@
 
 	arcpct: pct {
 		compatible = "snps,archs-pct";
+		interrupt-parent = <&cpu_intc>;
+		interrupts = <20>;
 	};
 
 	/* TIMER0 with interrupt for clockevent */
@@ -208,7 +210,7 @@
 			reg = <0x8000 0x2000>;
 			interrupts = <10>;
 			interrupt-names = "macirq";
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 			snps,pbl = <32>;
 			snps,multicast-filter-bins = <256>;
 			clocks = <&gmacclk>;
@@ -226,7 +228,7 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "snps,dwmac-mdio";
-				phy0: ethernet-phy@0 {
+				phy0: ethernet-phy@0 { /* Micrel KSZ9031 */
 					reg = <0>;
 				};
 			};
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/vdk_axc003.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/vdk_axc003.dtsi
@@ -46,7 +46,7 @@
 
 	};
 
-	mb_intc: dw-apb-ictl@e0012000 {
+	mb_intc: interrupt-controller@e0012000 {
 		#interrupt-cells = <1>;
 		compatible = "snps,dw-apb-ictl";
 		reg = < 0xe0012000 0x200 >;
--- linux-ein-5.4.0.orig/arch/arc/boot/dts/vdk_axc003_idu.dtsi
+++ linux-ein-5.4.0/arch/arc/boot/dts/vdk_axc003_idu.dtsi
@@ -54,7 +54,7 @@
 
 	};
 
-	mb_intc: dw-apb-ictl@e0012000 {
+	mb_intc: interrupt-controller@e0012000 {
 		#interrupt-cells = <1>;
 		compatible = "snps,dw-apb-ictl";
 		reg = < 0xe0012000 0x200 >;
--- linux-ein-5.4.0.orig/arch/arc/include/asm/elf.h
+++ linux-ein-5.4.0/arch/arc/include/asm/elf.h
@@ -19,7 +19,7 @@
 #define  R_ARC_32_PCREL		0x31
 
 /*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
--- linux-ein-5.4.0.orig/arch/arc/include/asm/io.h
+++ linux-ein-5.4.0/arch/arc/include/asm/io.h
@@ -32,7 +32,7 @@
 {
 }
 
-extern void iounmap(const void __iomem *addr);
+extern void iounmap(const volatile void __iomem *addr);
 
 #define ioremap_nocache(phy, sz)	ioremap(phy, sz)
 #define ioremap_wc(phy, sz)		ioremap(phy, sz)
--- linux-ein-5.4.0.orig/arch/arc/include/asm/linkage.h
+++ linux-ein-5.4.0/arch/arc/include/asm/linkage.h
@@ -8,6 +8,10 @@
 
 #include <asm/dwarf.h>
 
+#define ASM_NL		 `	/* use '`' to mark new line in macro */
+#define __ALIGN		.align 4
+#define __ALIGN_STR	__stringify(__ALIGN)
+
 #ifdef __ASSEMBLY__
 
 .macro ST2 e, o, off
@@ -28,8 +32,6 @@
 #endif
 .endm
 
-#define ASM_NL		 `	/* use '`' to mark new line in macro */
-
 /* annotation for data we want in DCCM - if enabled in .config */
 .macro ARCFP_DATA nm
 #ifdef CONFIG_ARC_HAS_DCCM
--- linux-ein-5.4.0.orig/arch/arc/include/asm/page.h
+++ linux-ein-5.4.0/arch/arc/include/asm/page.h
@@ -7,9 +7,22 @@
 
 #include <uapi/asm/page.h>
 
+#ifdef CONFIG_ARC_HAS_PAE40
+
+#define MAX_POSSIBLE_PHYSMEM_BITS	40
+#define PAGE_MASK_PHYS			(0xff00000000ull | PAGE_MASK)
+
+#else /* CONFIG_ARC_HAS_PAE40 */
+
+#define MAX_POSSIBLE_PHYSMEM_BITS	32
+#define PAGE_MASK_PHYS			PAGE_MASK
+
+#endif /* CONFIG_ARC_HAS_PAE40 */
+
 #ifndef __ASSEMBLY__
 
 #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;
--- linux-ein-5.4.0.orig/arch/arc/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/arc/include/asm/pgtable.h
@@ -108,8 +108,8 @@
 #define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE)
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL)
-
+#define _PAGE_CHG_MASK	(PAGE_MASK_PHYS | _PAGE_ACCESSED | _PAGE_DIRTY | \
+							   _PAGE_SPECIAL)
 /* More Abbrevaited helpers */
 #define PAGE_U_NONE     __pgprot(___DEF)
 #define PAGE_U_R        __pgprot(___DEF | _PAGE_READ)
@@ -133,11 +133,7 @@
 #define PTE_BITS_IN_PD0		(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_HW_SZ)
 #define PTE_BITS_RWX		(_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ)
 
-#ifdef CONFIG_ARC_HAS_PAE40
-#define PTE_BITS_NON_RWX_IN_PD1	(0xff00000000 | PAGE_MASK | _PAGE_CACHEABLE)
-#else
-#define PTE_BITS_NON_RWX_IN_PD1	(PAGE_MASK | _PAGE_CACHEABLE)
-#endif
+#define PTE_BITS_NON_RWX_IN_PD1	(PAGE_MASK_PHYS | _PAGE_CACHEABLE)
 
 /**************************************************************************
  * Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
--- linux-ein-5.4.0.orig/arch/arc/include/asm/syscalls.h
+++ linux-ein-5.4.0/arch/arc/include/asm/syscalls.h
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 
 int sys_clone_wrapper(int, int, int, int, int);
+int sys_clone3_wrapper(void *, size_t);
 int sys_cacheflush(uint32_t, uint32_t uint32_t);
 int sys_arc_settls(void *);
 int sys_arc_gettls(void);
--- linux-ein-5.4.0.orig/arch/arc/include/uapi/asm/page.h
+++ linux-ein-5.4.0/arch/arc/include/uapi/asm/page.h
@@ -33,5 +33,4 @@
 
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
-
 #endif /* _UAPI__ASM_ARC_PAGE_H */
--- linux-ein-5.4.0.orig/arch/arc/include/uapi/asm/sigcontext.h
+++ linux-ein-5.4.0/arch/arc/include/uapi/asm/sigcontext.h
@@ -18,6 +18,7 @@
  */
 struct sigcontext {
 	struct user_regs_struct regs;
+	struct user_regs_arcv2 v2abi;
 };
 
 #endif /* _ASM_ARC_SIGCONTEXT_H */
--- linux-ein-5.4.0.orig/arch/arc/include/uapi/asm/unistd.h
+++ linux-ein-5.4.0/arch/arc/include/uapi/asm/unistd.h
@@ -21,6 +21,7 @@
 #define __ARCH_WANT_SET_GET_RLIMIT
 #define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_CLONE3
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_TIME32_SYSCALLS
--- linux-ein-5.4.0.orig/arch/arc/kernel/entry.S
+++ linux-ein-5.4.0/arch/arc/kernel/entry.S
@@ -35,6 +35,18 @@
 	b .Lret_from_system_call
 END(sys_clone_wrapper)
 
+ENTRY(sys_clone3_wrapper)
+	SAVE_CALLEE_SAVED_USER
+	bl  @sys_clone3
+	DISCARD_CALLEE_SAVED_USER
+
+	GET_CURR_THR_INFO_FLAGS   r10
+	btst r10, TIF_SYSCALL_TRACE
+	bnz  tracesys_exit
+
+	b .Lret_from_system_call
+END(sys_clone3_wrapper)
+
 ENTRY(ret_from_fork)
 	; when the forked child comes here from the __switch_to function
 	; r0 has the last task pointer.
@@ -153,7 +165,6 @@
 tracesys:
 	; save EFA in case tracer wants the PC of traced task
 	; using ERET won't work since next-PC has already committed
-	lr  r12, [efa]
 	GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r11
 	st  r12, [r11, THREAD_FAULT_ADDR]	; thread.fault_address
 
@@ -166,7 +177,7 @@
 
 	; Do the Sys Call as we normally would.
 	; Validate the Sys Call number
-	cmp     r8,  NR_syscalls
+	cmp     r8,  NR_syscalls - 1
 	mov.hi  r0, -ENOSYS
 	bhi     tracesys_exit
 
@@ -188,6 +199,7 @@
 	st  r0, [sp, PT_r0]     ; sys call return value in pt_regs
 
 	;POST Sys Call Ptrace Hook
+	mov r0, sp		; pt_regs needed
 	bl  @syscall_trace_exit
 	b   ret_from_exception ; NOT ret_from_system_call at is saves r0 which
 	; we'd done before calling post hook above
@@ -196,15 +208,9 @@
 ; Breakpoint TRAP
 ; ---------------------------------------------
 trap_with_param:
-
-	; stop_pc info by gdb needs this info
-	lr  r0, [efa]
+	mov r0, r12	; EFA in case ptracer/gdb wants stop_pc
 	mov r1, sp
 
-	; Now that we have read EFA, it is safe to do "fake" rtie
-	;   and get out of CPU exception mode
-	FAKE_RET_FROM_EXCPN
-
 	; Save callee regs in case gdb wants to have a look
 	; SP will grow up by size of CALLEE Reg-File
 	; NOTE: clobbers r12
@@ -231,6 +237,10 @@
 
 	EXCEPTION_PROLOGUE
 
+	lr  r12, [efa]
+
+	FAKE_RET_FROM_EXCPN
+
 	;============ TRAP 1   :breakpoints
 	; Check ECR for trap with arg (PROLOGUE ensures r10 has ECR)
 	bmsk.f 0, r10, 7
@@ -238,9 +248,6 @@
 
 	;============ TRAP  (no param): syscall top level
 
-	; First return from Exception to pure K mode (Exception/IRQs renabled)
-	FAKE_RET_FROM_EXCPN
-
 	; If syscall tracing ongoing, invoke pre-post-hooks
 	GET_CURR_THR_INFO_FLAGS   r10
 	btst r10, TIF_SYSCALL_TRACE
@@ -249,7 +256,7 @@
 	;============ Normal syscall case
 
 	; syscall num shd not exceed the total system calls avail
-	cmp     r8,  NR_syscalls
+	cmp     r8,  NR_syscalls - 1
 	mov.hi  r0, -ENOSYS
 	bhi     .Lret_from_system_call
 
--- linux-ein-5.4.0.orig/arch/arc/kernel/perf_event.c
+++ linux-ein-5.4.0/arch/arc/kernel/perf_event.c
@@ -562,7 +562,7 @@
 {
 	struct arc_reg_pct_build pct_bcr;
 	struct arc_reg_cc_build cc_bcr;
-	int i, has_interrupts;
+	int i, has_interrupts, irq = -1;
 	int counter_size;	/* in bits */
 
 	union cc_name {
@@ -638,22 +638,25 @@
 	};
 
 	if (has_interrupts) {
-		int irq = platform_get_irq(pdev, 0);
-
-		if (irq < 0) {
-			pr_err("Cannot get IRQ number for the platform\n");
-			return -ENODEV;
+		irq = platform_get_irq(pdev, 0);
+		if (irq >= 0) {
+			int ret;
+
+			arc_pmu->irq = irq;
+
+			/* intc map function ensures irq_set_percpu_devid() called */
+			ret = request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
+						 this_cpu_ptr(&arc_pmu_cpu));
+
+			if (!ret)
+				on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
+			else
+				irq = -1;
 		}
 
-		arc_pmu->irq = irq;
-
-		/* intc map function ensures irq_set_percpu_devid() called */
-		request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
-				   this_cpu_ptr(&arc_pmu_cpu));
-
-		on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
+	}
 
-	} else
+	if (irq == -1)
 		arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
 
 	/*
--- linux-ein-5.4.0.orig/arch/arc/kernel/process.c
+++ linux-ein-5.4.0/arch/arc/kernel/process.c
@@ -171,9 +171,8 @@
  * |    user_r25    |
  * ------------------  <===== END of PAGE
  */
-int copy_thread(unsigned long clone_flags,
-		unsigned long usp, unsigned long kthread_arg,
-		struct task_struct *p)
+int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
+	unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
 {
 	struct pt_regs *c_regs;        /* child's pt_regs */
 	unsigned long *childksp;       /* to unwind out of __switch_to() */
@@ -231,7 +230,7 @@
 		 * set task's userland tls data ptr from 4th arg
 		 * clone C-lib call is difft from clone sys-call
 		 */
-		task_thread_info(p)->thr_ptr = regs->r3;
+		task_thread_info(p)->thr_ptr = tls;
 	} else {
 		/* Normal fork case: set parent's TLS ptr in child */
 		task_thread_info(p)->thr_ptr =
--- linux-ein-5.4.0.orig/arch/arc/kernel/setup.c
+++ linux-ein-5.4.0/arch/arc/kernel/setup.c
@@ -12,6 +12,7 @@
 #include <linux/clocksource.h>
 #include <linux/console.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <linux/cpu.h>
 #include <linux/of_fdt.h>
 #include <linux/of.h>
@@ -409,12 +410,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
 
--- linux-ein-5.4.0.orig/arch/arc/kernel/signal.c
+++ linux-ein-5.4.0/arch/arc/kernel/signal.c
@@ -61,6 +61,41 @@
 	unsigned int sigret_magic;
 };
 
+static int save_arcv2_regs(struct sigcontext __user *mctx, struct pt_regs *regs)
+{
+	int err = 0;
+#ifndef CONFIG_ISA_ARCOMPACT
+	struct user_regs_arcv2 v2abi;
+
+	v2abi.r30 = regs->r30;
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+	v2abi.r58 = regs->r58;
+	v2abi.r59 = regs->r59;
+#else
+	v2abi.r58 = v2abi.r59 = 0;
+#endif
+	err = __copy_to_user(&mctx->v2abi, (void const *)&v2abi, sizeof(v2abi));
+#endif
+	return err;
+}
+
+static int restore_arcv2_regs(struct sigcontext __user *mctx, struct pt_regs *regs)
+{
+	int err = 0;
+#ifndef CONFIG_ISA_ARCOMPACT
+	struct user_regs_arcv2 v2abi;
+
+	err = __copy_from_user(&v2abi, &mctx->v2abi, sizeof(v2abi));
+
+	regs->r30 = v2abi.r30;
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+	regs->r58 = v2abi.r58;
+	regs->r59 = v2abi.r59;
+#endif
+#endif
+	return err;
+}
+
 static int
 stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
 	       sigset_t *set)
@@ -94,9 +129,13 @@
 
 	err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), &uregs.scratch,
 			     sizeof(sf->uc.uc_mcontext.regs.scratch));
+
+	if (is_isa_arcv2())
+		err |= save_arcv2_regs(&(sf->uc.uc_mcontext), regs);
+
 	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
-	return err;
+	return err ? -EFAULT : 0;
 }
 
 static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
@@ -109,8 +148,12 @@
 	err |= __copy_from_user(&uregs.scratch,
 				&(sf->uc.uc_mcontext.regs.scratch),
 				sizeof(sf->uc.uc_mcontext.regs.scratch));
+
+	if (is_isa_arcv2())
+		err |= restore_arcv2_regs(&(sf->uc.uc_mcontext), regs);
+
 	if (err)
-		return err;
+		return -EFAULT;
 
 	set_current_blocked(&set);
 	regs->bta	= uregs.scratch.bta;
--- linux-ein-5.4.0.orig/arch/arc/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/arc/kernel/stacktrace.c
@@ -38,15 +38,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;
 
@@ -65,11 +65,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);
@@ -103,6 +107,8 @@
 		frame_info->regs.r63 = regs->ret;
 		frame_info->call_frame = 0;
 	}
+
+	return 0;
 }
 
 #endif
@@ -112,11 +118,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);
@@ -132,6 +139,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 */
--- linux-ein-5.4.0.orig/arch/arc/kernel/sys.c
+++ linux-ein-5.4.0/arch/arc/kernel/sys.c
@@ -7,6 +7,7 @@
 #include <asm/syscalls.h>
 
 #define sys_clone	sys_clone_wrapper
+#define sys_clone3	sys_clone3_wrapper
 
 #undef __SYSCALL
 #define __SYSCALL(nr, call) [nr] = (call),
--- linux-ein-5.4.0.orig/arch/arc/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/arc/kernel/vmlinux.lds.S
@@ -88,6 +88,8 @@
 		CPUIDLE_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
+		IRQENTRY_TEXT
+		SOFTIRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	}
--- linux-ein-5.4.0.orig/arch/arc/mm/cache.c
+++ linux-ein-5.4.0/arch/arc/mm/cache.c
@@ -1123,7 +1123,7 @@
 	clear_page(to);
 	clear_bit(PG_dc_clean, &page->flags);
 }
-
+EXPORT_SYMBOL(clear_user_page);
 
 /**********************************************************************
  * Explicit Cache flush request from user space via syscall
--- linux-ein-5.4.0.orig/arch/arc/mm/dma.c
+++ linux-ein-5.4.0/arch/arc/mm/dma.c
@@ -48,8 +48,8 @@
  * upper layer functions (in include/linux/dma-mapping.h)
  */
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
@@ -69,8 +69,8 @@
 	}
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
--- linux-ein-5.4.0.orig/arch/arc/mm/ioremap.c
+++ linux-ein-5.4.0/arch/arc/mm/ioremap.c
@@ -53,9 +53,10 @@
 void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
 			   unsigned long flags)
 {
+	unsigned int off;
 	unsigned long vaddr;
 	struct vm_struct *area;
-	phys_addr_t off, end;
+	phys_addr_t end;
 	pgprot_t prot = __pgprot(flags);
 
 	/* Don't allow wraparound, zero size */
@@ -72,7 +73,7 @@
 
 	/* Mappings have to be page-aligned */
 	off = paddr & ~PAGE_MASK;
-	paddr &= PAGE_MASK;
+	paddr &= PAGE_MASK_PHYS;
 	size = PAGE_ALIGN(end + 1) - paddr;
 
 	/*
@@ -92,7 +93,7 @@
 EXPORT_SYMBOL(ioremap_prot);
 
 
-void iounmap(const void __iomem *addr)
+void iounmap(const volatile void __iomem *addr)
 {
 	/* weird double cast to handle phys_addr_t > 32 bits */
 	if (arc_uncached_addr_space((phys_addr_t)(u32)addr))
--- linux-ein-5.4.0.orig/arch/arc/mm/tlb.c
+++ linux-ein-5.4.0/arch/arc/mm/tlb.c
@@ -597,7 +597,7 @@
 		      pte_t *ptep)
 {
 	unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
-	phys_addr_t paddr = pte_val(*ptep) & PAGE_MASK;
+	phys_addr_t paddr = pte_val(*ptep) & PAGE_MASK_PHYS;
 	struct page *page = pfn_to_page(pte_pfn(*ptep));
 
 	create_tlb(vma, vaddr, ptep);
--- linux-ein-5.4.0.orig/arch/arc/plat-eznps/Kconfig
+++ linux-ein-5.4.0/arch/arc/plat-eznps/Kconfig
@@ -6,8 +6,9 @@
 
 menuconfig ARC_PLAT_EZNPS
 	bool "\"EZchip\" ARC dev platform"
+	depends on ISA_ARCOMPACT
 	select CPU_BIG_ENDIAN
-	select CLKSRC_NPS
+	select CLKSRC_NPS if !PHYS_ADDR_T_64BIT
 	select EZNPS_GIC
 	select EZCHIP_NPS_MANAGEMENT_ENET if ETHERNET
 	help
--- linux-ein-5.4.0.orig/arch/arc/plat-eznps/include/plat/ctop.h
+++ linux-ein-5.4.0/arch/arc/plat-eznps/include/plat/ctop.h
@@ -33,7 +33,6 @@
 #define CTOP_AUX_DPC				(CTOP_AUX_BASE + 0x02C)
 #define CTOP_AUX_LPC				(CTOP_AUX_BASE + 0x030)
 #define CTOP_AUX_EFLAGS				(CTOP_AUX_BASE + 0x080)
-#define CTOP_AUX_IACK				(CTOP_AUX_BASE + 0x088)
 #define CTOP_AUX_GPA1				(CTOP_AUX_BASE + 0x08C)
 #define CTOP_AUX_UDMC				(CTOP_AUX_BASE + 0x300)
 
--- linux-ein-5.4.0.orig/arch/arc/plat-hsdk/Kconfig
+++ linux-ein-5.4.0/arch/arc/plat-hsdk/Kconfig
@@ -8,5 +8,6 @@
 	select ARC_HAS_ACCL_REGS
 	select ARC_IRQ_NO_AUTOSAVE
 	select CLK_HSDK
+	select RESET_CONTROLLER
 	select RESET_HSDK
 	select HAVE_PCI
--- linux-ein-5.4.0.orig/arch/arm/Kconfig
+++ linux-ein-5.4.0/arch/arm/Kconfig
@@ -5,6 +5,7 @@
 	select ARCH_32BIT_OFF_T
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_HAS_BINFMT_FLAT
+	select ARCH_HAS_CPU_FINALIZE_INIT if MMU
 	select ARCH_HAS_DEBUG_VIRTUAL if MMU
 	select ARCH_HAS_DEVMEM_IS_ALLOWED
 	select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
@@ -26,7 +27,7 @@
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAVE_CUSTOM_GPIO_H
 	select ARCH_HAS_GCOV_PROFILE_ALL
-	select ARCH_KEEP_MEMBLOCK if HAVE_ARCH_PFN_VALID || KEXEC
+	select ARCH_KEEP_MEMBLOCK
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_NO_SG_CHAIN if !ARM_HAS_SG_CHAIN
 	select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
@@ -73,8 +74,9 @@
 	select HAVE_ARM_SMCCC if CPU_V7
 	select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
 	select HAVE_CONTEXT_TRACKING
+	select HAVE_COPY_THREAD_TLS
 	select HAVE_C_RECORDMCOUNT
-	select HAVE_DEBUG_KMEMLEAK
+	select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
 	select HAVE_DMA_CONTIGUOUS if MMU
 	select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
 	select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
@@ -84,6 +86,7 @@
 	select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
 	select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL && !CC_IS_CLANG
 	select HAVE_FUNCTION_TRACER if !XIP_KERNEL && (CC_IS_GCC || CLANG_VERSION >= 100000)
+	select HAVE_FUTEX_CMPXCHG if FUTEX
 	select HAVE_GCC_PLUGINS
 	select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)
 	select HAVE_IDE if PCI || ISA || PCMCIA
@@ -117,7 +120,6 @@
 	select OLD_SIGSUSPEND3
 	select PCI_SYSCALL if PCI
 	select PERF_USE_VMALLOC
-	select REFCOUNT_FULL
 	select RTC_LIB
 	select SYS_SUPPORTS_APM_EMULATION
 	# Above selects are sorted alphabetically; please add new ones
@@ -506,8 +508,10 @@
 	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	select HAVE_S3C_RTC if RTC_CLASS
 	select NEED_MACH_IO_H
+	select S3C2410_WATCHDOG
 	select SAMSUNG_ATAGS
 	select USE_OF
+	select WATCHDOG
 	help
 	  Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443
 	  and S3C2450 SoCs based systems, such as the Simtec Electronics BAST
@@ -517,7 +521,6 @@
 config ARCH_OMAP1
 	bool "TI OMAP1"
 	depends on MMU
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARCH_OMAP
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
@@ -1514,9 +1517,6 @@
 	  UNPREDICTABLE (in fact it can be predicted that it won't work
 	  at all). If in doubt say N.
 
-config ARCH_HAS_HOLES_MEMORYMODEL
-	bool
-
 config ARCH_SPARSEMEM_ENABLE
 	bool
 
@@ -1524,7 +1524,7 @@
 	def_bool ARCH_SPARSEMEM_ENABLE
 
 config HAVE_ARCH_PFN_VALID
-	def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
+	def_bool y
 
 config HIGHMEM
 	bool "High Memory Support"
@@ -1838,7 +1838,6 @@
 choice
 	prompt "Kernel command line type" if CMDLINE != ""
 	default CMDLINE_FROM_BOOTLOADER
-	depends on ATAGS
 
 config CMDLINE_FROM_BOOTLOADER
 	bool "Use bootloader kernel arguments if available"
@@ -1906,7 +1905,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
--- linux-ein-5.4.0.orig/arch/arm/Makefile
+++ linux-ein-5.4.0/arch/arm/Makefile
@@ -66,15 +66,15 @@
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
-arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
-arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m
+arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 -march=armv7-a
+arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 -march=armv6
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
 # always available in ARMv7
 ifeq ($(CONFIG_CPU_32v6),y)
-arch-$(CONFIG_CPU_32v6K)	=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+arch-$(CONFIG_CPU_32v6K)	=-D__LINUX_ARM_ARCH__=6 -march=armv6k
 endif
-arch-$(CONFIG_CPU_32v5)		=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
+arch-$(CONFIG_CPU_32v5)		=-D__LINUX_ARM_ARCH__=5 -march=armv5te
 arch-$(CONFIG_CPU_32v4T)	=-D__LINUX_ARM_ARCH__=4 -march=armv4t
 arch-$(CONFIG_CPU_32v4)		=-D__LINUX_ARM_ARCH__=4 -march=armv4
 arch-$(CONFIG_CPU_32v3)		=-D__LINUX_ARM_ARCH__=3 -march=armv3m
@@ -88,7 +88,7 @@
 tune-$(CONFIG_CPU_ARM740T)	=-mtune=arm7tdmi
 tune-$(CONFIG_CPU_ARM9TDMI)	=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM940T)	=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM946E)	=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
+tune-$(CONFIG_CPU_ARM946E)	=-mtune=arm9e
 tune-$(CONFIG_CPU_ARM920T)	=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM922T)	=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM925T)	=-mtune=arm9tdmi
@@ -96,11 +96,11 @@
 tune-$(CONFIG_CPU_FA526)	=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_SA110)	=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)	=-mtune=strongarm1100
-tune-$(CONFIG_CPU_XSCALE)	=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_XSC3)		=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_FEROCEON)	=$(call cc-option,-mtune=marvell-f,-mtune=xscale)
-tune-$(CONFIG_CPU_V6)		=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
-tune-$(CONFIG_CPU_V6K)		=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_XSCALE)	=-mtune=xscale
+tune-$(CONFIG_CPU_XSC3)		=-mtune=xscale
+tune-$(CONFIG_CPU_FEROCEON)	=-mtune=xscale
+tune-$(CONFIG_CPU_V6)		=-mtune=arm1136j-s
+tune-$(CONFIG_CPU_V6K)		=-mtune=arm1136j-s
 
 # Evaluate tune cc-option calls now
 tune-y := $(tune-y)
@@ -307,13 +307,15 @@
 ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
 prepare: stack_protector_prepare
 stack_protector_prepare: prepare0
-	$(eval KBUILD_CFLAGS += \
+	$(eval SSP_PLUGIN_CFLAGS := \
 		-fplugin-arg-arm_ssp_per_task_plugin-tso=$(shell	\
 			awk '{if ($$2 == "THREAD_SZ_ORDER") print $$3;}'\
 				include/generated/asm-offsets.h)	\
 		-fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell	\
 			awk '{if ($$2 == "TI_STACK_CANARY") print $$3;}'\
 				include/generated/asm-offsets.h))
+	$(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS))
+	$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
 endif
 
 all:	$(notdir $(KBUILD_IMAGE))
--- linux-ein-5.4.0.orig/arch/arm/boot/bootp/init.S
+++ linux-ein-5.4.0/arch/arm/boot/bootp/init.S
@@ -13,7 +13,7 @@
  *  size immediately following the kernel, we could build this into
  *  a binary blob, and concatenate the zImage using the cat command.
  */
-		.section .start,#alloc,#execinstr
+		.section .start, "ax"
 		.type	_start, #function
 		.globl	_start
 
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/Makefile
+++ linux-ein-5.4.0/arch/arm/boot/compressed/Makefile
@@ -90,6 +90,8 @@
 	$(addprefix $(obj)/,$(libfdt_hdrs))
 
 ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
+CFLAGS_REMOVE_atags_to_fdt.o += -Wframe-larger-than=${CONFIG_FRAME_WARN}
+CFLAGS_atags_to_fdt.o += -Wframe-larger-than=1280
 OBJS	+= $(libfdt_objs) atags_to_fdt.o
 endif
 
@@ -101,7 +103,6 @@
 		$(libfdt) $(libfdt_hdrs) hyp-stub.S
 
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
-KBUILD_CFLAGS += $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
 
 ifeq ($(CONFIG_FUNCTION_TRACER),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
@@ -117,13 +118,14 @@
 CFLAGS_fdt_rw.o := $(nossp_flags)
 CFLAGS_fdt_wip.o := $(nossp_flags)
 
-ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin -I$(obj)
+ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \
+	     -I$(obj) $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
 asflags-y := -DZIMAGE
 
 # Supply kernel BSS size to the decompressor via a linker symbol.
-KBSS_SZ = $(shell echo $$(($$($(CROSS_COMPILE)nm $(obj)/../../../../vmlinux | \
-		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
-		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
+KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
+		sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \
+		       -e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) )
 LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
 # Supply ZRELADDR to the decompressor via a linker symbol.
 ifneq ($(CONFIG_AUTO_ZRELADDR),y)
@@ -165,7 +167,7 @@
 # The .data section is already discarded by the linker script so no need
 # to bother about it here.
 check_for_bad_syms = \
-bad_syms=$$($(CROSS_COMPILE)nm $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \
+bad_syms=$$($(NM) $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \
 [ -z "$$bad_syms" ] || \
   ( echo "following symbols must have non local/private scope:" >&2; \
     echo "$$bad_syms" >&2; false )
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/big-endian.S
+++ linux-ein-5.4.0/arch/arm/boot/compressed/big-endian.S
@@ -6,7 +6,7 @@
  *  Author: Nicolas Pitre
  */
 
-	.section ".start", #alloc, #execinstr
+	.section ".start", "ax"
 
 	mrc	p15, 0, r0, c1, c0, 0	@ read control reg
 	orr	r0, r0, #(1 << 7)	@ enable big endian mode
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/decompress.c
+++ linux-ein-5.4.0/arch/arm/boot/compressed/decompress.c
@@ -47,7 +47,10 @@
 #endif
 
 #ifdef CONFIG_KERNEL_XZ
+/* Prevent KASAN override of string helpers in decompressor */
+#undef memmove
 #define memmove memmove
+#undef memcpy
 #define memcpy memcpy
 #include "../../../../lib/decompress_unxz.c"
 #endif
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/efi-header.S
+++ linux-ein-5.4.0/arch/arm/boot/compressed/efi-header.S
@@ -9,16 +9,22 @@
 #include <linux/sizes.h>
 
 		.macro	__nop
-#ifdef CONFIG_EFI_STUB
-		@ This is almost but not quite a NOP, since it does clobber the
-		@ condition flags. But it is the best we can do for EFI, since
-		@ PE/COFF expects the magic string "MZ" at offset 0, while the
-		@ ARM/Linux boot protocol expects an executable instruction
-		@ there.
-		.inst	MZ_MAGIC | (0x1310 << 16)	@ tstne r0, #0x4d000
-#else
  AR_CLASS(	mov	r0, r0		)
   M_CLASS(	nop.w			)
+		.endm
+
+		.macro __initial_nops
+#ifdef CONFIG_EFI_STUB
+		@ This is a two-instruction NOP, which happens to bear the
+		@ PE/COFF signature "MZ" in the first two bytes, so the kernel
+		@ is accepted as an EFI binary. Booting via the UEFI stub
+		@ will not execute those instructions, but the ARM/Linux
+		@ boot protocol does, so we need some NOPs here.
+		.inst	MZ_MAGIC | (0xe225 << 16)	@ eor r5, r5, 0x4d000
+		eor	r5, r5, 0x4d000			@ undo previous insn
+#else
+		__nop
+		__nop
 #endif
 		.endm
 
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/head.S
+++ linux-ein-5.4.0/arch/arm/boot/compressed/head.S
@@ -140,7 +140,7 @@
 #endif
 		.endm
 
-		.section ".start", #alloc, #execinstr
+		.section ".start", "ax"
 /*
  * sort out different calling conventions
  */
@@ -165,7 +165,8 @@
 		 * were patching the initial instructions of the kernel, i.e
 		 * had started to exploit this "patch area".
 		 */
-		.rept	7
+		__initial_nops
+		.rept	5
 		__nop
 		.endr
 #ifndef CONFIG_THUMB2_KERNEL
@@ -1142,9 +1143,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
@@ -1273,7 +1274,7 @@
 __armv5tej_mmu_cache_flush:
 		tst	r4, #1
 		movne	pc, lr
-1:		mrc	p15, 0, r15, c7, c14, 3	@ test,clean,invalidate D cache
+1:		mrc	p15, 0, APSR_nzcv, c7, c14, 3	@ test,clean,invalidate D cache
 		bne	1b
 		mcr	p15, 0, r0, c7, c5, 0	@ flush I cache
 		mcr	p15, 0, r0, c7, c10, 4	@ drain WB
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/libfdt_env.h
+++ linux-ein-5.4.0/arch/arm/boot/compressed/libfdt_env.h
@@ -2,11 +2,13 @@
 #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 INT_MAX			((int)(~0U>>1))
+#define INT32_MAX	S32_MAX
+#define UINT32_MAX	U32_MAX
 
 typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/piggy.S
+++ linux-ein-5.4.0/arch/arm/boot/compressed/piggy.S
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-	.section .piggydata,#alloc
+	.section .piggydata, "a"
 	.globl	input_data
 input_data:
 	.incbin	"arch/arm/boot/compressed/piggy_data"
--- linux-ein-5.4.0.orig/arch/arm/boot/compressed/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/arm/boot/compressed/vmlinux.lds.S
@@ -43,7 +43,7 @@
   }
   .table : ALIGN(4) {
     _table_start = .;
-    LONG(ZIMAGE_MAGIC(2))
+    LONG(ZIMAGE_MAGIC(4))
     LONG(ZIMAGE_MAGIC(0x5a534c4b))
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
--- linux-ein-5.4.0.orig/arch/arm/boot/deflate_xip_data.sh
+++ linux-ein-5.4.0/arch/arm/boot/deflate_xip_data.sh
@@ -56,7 +56,7 @@
 # substitute the data section by a compressed version
 $DD if="$XIPIMAGE" count=$data_start iflag=count_bytes of="$XIPIMAGE.tmp"
 $DD if="$XIPIMAGE"  skip=$data_start iflag=skip_bytes |
-gzip -9 >> "$XIPIMAGE.tmp"
+$KGZIP -9 >> "$XIPIMAGE.tmp"
 
 # replace kernel binary
 mv -f "$XIPIMAGE.tmp" "$XIPIMAGE"
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/Makefile
+++ linux-ein-5.4.0/arch/arm/boot/dts/Makefile
@@ -559,10 +559,12 @@
 	imx6sx-sdb-reva.dtb \
 	imx6sx-sdb-sai.dtb \
 	imx6sx-sdb.dtb \
+	imx6sx-sdb-mqs.dtb \
 	imx6sx-softing-vining-2000.dtb \
 	imx6sx-udoo-neo-basic.dtb \
 	imx6sx-udoo-neo-extended.dtb \
-	imx6sx-udoo-neo-full.dtb
+	imx6sx-udoo-neo-full.dtb \
+	imx6sx-x6med35-pdk.dtb
 dtb-$(CONFIG_SOC_IMX6UL) += \
 	imx6ul-14x14-evk.dtb \
 	imx6ul-ccimx6ulsbcexpress.dtb \
@@ -586,8 +588,13 @@
 	imx6ull-phytec-segin-ff-rdk-nand.dtb \
 	imx6ull-phytec-segin-ff-rdk-emmc.dtb \
 	imx6ull-phytec-segin-lc-rdk-nand.dtb \
-	imx6ulz-14x14-evk.dtb
+	imx6ulz-14x14-evk.dtb \
+	vesta-500.dtb
 dtb-$(CONFIG_SOC_IMX7D) += \
+	amgis-fcl-v3.dtb \
+	amgis-fcl-v4.dtb \
+	amgis-fcl-v5.dtb \
+	amgis-fcl-v6.dtb \
 	imx7d-cl-som-imx7.dtb \
 	imx7d-colibri-emmc-eval-v3.dtb \
 	imx7d-colibri-eval-v3.dtb \
@@ -1303,3 +1310,12 @@
 	aspeed-bmc-opp-zaius.dtb \
 	aspeed-bmc-portwell-neptune.dtb \
 	aspeed-bmc-quanta-q71l.dtb
+
+targets += dtbs dtbs_install
+targets += $(dtb-y)
+
+subdir-y	:= overlays
+
+ifeq ($(CONFIG_OF_OVERLAY),y)
+	DTC_FLAGS ?= -@
+endif
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am335x-boneblack-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am335x-boneblack-common.dtsi
@@ -131,6 +131,11 @@
 };
 
 / {
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x20000000>; /* 512 MB */
+	};
+
 	clk_mcasp0_fixed: clk_mcasp0_fixed {
 		#clock-cells = <0>;
 		compatible = "fixed-clock";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am335x-cm-t335.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am335x-cm-t335.dts
@@ -516,7 +516,7 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&spi0_pins>;
-	ti,pindir-d0-out-d1-in = <1>;
+	ti,pindir-d0-out-d1-in;
 	/* WLS1271 WiFi */
 	wlcore: wlcore@1 {
 		compatible = "ti,wl1271";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am335x-pcm-953.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am335x-pcm-953.dtsi
@@ -12,22 +12,20 @@
 	compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx";
 
 	/* Power */
-	regulators {
-		vcc3v3: fixedregulator@1 {
-			compatible = "regulator-fixed";
-			regulator-name = "vcc3v3";
-			regulator-min-microvolt = <3300000>;
-			regulator-max-microvolt = <3300000>;
-			regulator-boot-on;
-		};
+	vcc3v3: fixedregulator1 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+	};
 
-		vcc1v8: fixedregulator@2 {
-			compatible = "regulator-fixed";
-			regulator-name = "vcc1v8";
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			regulator-boot-on;
-		};
+	vcc1v8: fixedregulator2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
 	};
 
 	/* User IO */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am335x-pocketbeagle.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am335x-pocketbeagle.dts
@@ -88,7 +88,6 @@
 			AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
 			AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
 			AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
-			AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT, MUX_MODE4)		/* (B12) mcasp0_aclkr.mmc0_sdwp */
 		>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am335x-sancloud-bbe.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am335x-sancloud-bbe.dts
@@ -108,7 +108,7 @@
 
 &cpsw_emac0 {
 	phy-handle = <&ethphy0>;
-	phy-mode = "rgmii-txid";
+	phy-mode = "rgmii-id";
 };
 
 &i2c0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am33xx-l4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am33xx-l4.dtsi
@@ -1337,8 +1337,7 @@
 				ti,dual-volt;
 				ti,needs-special-reset;
 				ti,needs-special-hs-handling;
-				dmas = <&edma_xbar 24 0 0
-					&edma_xbar 25 0 0>;
+				dmas = <&edma 24 0>, <&edma 25 0>;
 				dma-names = "tx", "rx";
 				interrupts = <64>;
 				reg = <0x0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am33xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am33xx.dtsi
@@ -40,6 +40,9 @@
 		ethernet1 = &cpsw_emac1;
 		spi0 = &spi0;
 		spi1 = &spi1;
+		mmc0 = &mmc1;
+		mmc1 = &mmc2;
+		mmc2 = &mmc3;
 	};
 
 	cpus {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am3517-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am3517-evm.dts
@@ -160,6 +160,8 @@
 
 	/* HS USB Host PHY on PORT 1 */
 	hsusb1_phy: hsusb1_phy {
+		pinctrl-names = "default";
+		pinctrl-0 = <&hsusb1_rst_pins>;
 		compatible = "usb-nop-xceiv";
 		reset-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>; /* gpio_57 */
 		#phy-cells = <0>;
@@ -167,7 +169,9 @@
 };
 
 &davinci_emac {
-	     status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&ethernet_pins>;
+	status = "okay";
 };
 
 &davinci_mdio {
@@ -192,6 +196,8 @@
 };
 
 &i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
 	clock-frequency = <400000>;
 	/* User DIP swithes [1:8] / User LEDS [1:2] */
 	tca6416: gpio@21 {
@@ -204,6 +210,8 @@
 };
 
 &i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins>;
 	clock-frequency = <400000>;
 };
 
@@ -222,6 +230,8 @@
 };
 
 &usbhshost {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hsusb1_pins>;
 	port1-mode = "ehci-phy";
 };
 
@@ -230,8 +240,35 @@
 };
 
 &omap3_pmx_core {
-	pinctrl-names = "default";
-	pinctrl-0 = <&hsusb1_rst_pins>;
+
+	ethernet_pins: pinmux_ethernet_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21fe, PIN_INPUT | MUX_MODE0) /* rmii_mdio_data */
+			OMAP3_CORE1_IOPAD(0x2200, MUX_MODE0) /* rmii_mdio_clk */
+			OMAP3_CORE1_IOPAD(0x2202, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_rxd0 */
+			OMAP3_CORE1_IOPAD(0x2204, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_rxd1 */
+			OMAP3_CORE1_IOPAD(0x2206, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_crs_dv */
+			OMAP3_CORE1_IOPAD(0x2208, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* rmii_rxer */
+			OMAP3_CORE1_IOPAD(0x220a, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* rmii_txd0 */
+			OMAP3_CORE1_IOPAD(0x220c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* rmii_txd1 */
+			OMAP3_CORE1_IOPAD(0x220e, PIN_OUTPUT_PULLDOWN |MUX_MODE0) /* rmii_txen */
+			OMAP3_CORE1_IOPAD(0x2210, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_50mhz_clk */
+		>;
+	};
+
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21be, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c2_scl */
+			OMAP3_CORE1_IOPAD(0x21c0, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c2_sda */
+		>;
+	};
+
+	i2c3_pins: pinmux_i2c3_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c3_scl */
+			OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c3_sda */
+		>;
+	};
 
 	leds_pins: pinmux_leds_pins {
 		pinctrl-single,pins = <
@@ -299,8 +336,6 @@
 };
 
 &omap3_pmx_core2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&hsusb1_pins>;
 
 	hsusb1_pins: pinmux_hsusb1_pins {
 		pinctrl-single,pins = <
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am3517-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am3517-som.dtsi
@@ -69,6 +69,8 @@
 };
 
 &i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <400000>;
 
 	s35390a: s35390a@30 {
@@ -179,6 +181,13 @@
 
 &omap3_pmx_core {
 
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c1_scl */
+			OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT_PULLUP | MUX_MODE0)  /* i2c1_sda */
+		>;
+	};
+
 	wl12xx_buffer_pins: pinmux_wl12xx_buffer_pins {
 		pinctrl-single,pins = <
 			OMAP3_CORE1_IOPAD(0x2156, PIN_OUTPUT | MUX_MODE4)  /* mmc1_dat7.gpio_129 */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am437x-gp-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -86,7 +86,7 @@
 		};
 
 	lcd0: display {
-		compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+		compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
 		label = "lcd";
 
 		backlight = <&lcd_bl>;
@@ -829,11 +829,14 @@
 	status = "okay";
 };
 
+&gpio5_target {
+	ti,no-reset-on-init;
+};
+
 &gpio5 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&display_mux_pins>;
 	status = "okay";
-	ti,no-reset-on-init;
 
 	p8 {
 		/*
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am437x-idk-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -526,11 +526,11 @@
 	 * Supply voltage supervisor on board will not allow opp50 so
 	 * disable it and set opp100 as suspend OPP.
 	 */
-	opp50@300000000 {
+	opp50-300000000 {
 		status = "disabled";
 	};
 
-	opp100@600000000 {
+	opp100-600000000 {
 		opp-suspend;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am437x-l4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am437x-l4.dtsi
@@ -1576,8 +1576,9 @@
 			reg-names = "rev";
 			ti,hwmods = "d_can0";
 			/* Domains (P, C): per_pwrdm, l4ls_clkdm */
-			clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN0_CLKCTRL 0>;
-			clock-names = "fck";
+			clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN0_CLKCTRL 0>,
+			<&dcan0_fck>;
+			clock-names = "fck", "osc";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x0 0xcc000 0x2000>;
@@ -1585,6 +1586,8 @@
 			dcan0: can@0 {
 				compatible = "ti,am4372-d_can", "ti,am3352-d_can";
 				reg = <0x0 0x2000>;
+				clocks = <&dcan0_fck>;
+				clock-names = "fck";
 				syscon-raminit = <&scm_conf 0x644 0>;
 				interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
@@ -1597,8 +1600,9 @@
 			reg-names = "rev";
 			ti,hwmods = "d_can1";
 			/* Domains (P, C): per_pwrdm, l4ls_clkdm */
-			clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN1_CLKCTRL 0>;
-			clock-names = "fck";
+			clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN1_CLKCTRL 0>,
+			<&dcan1_fck>;
+			clock-names = "fck", "osc";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x0 0xd0000 0x2000>;
@@ -1606,6 +1610,8 @@
 			dcan1: can@0 {
 				compatible = "ti,am4372-d_can", "ti,am3352-d_can";
 				reg = <0x0 0x2000>;
+				clocks = <&dcan1_fck>;
+				clock-names = "fck";
 				syscon-raminit = <&scm_conf 0x644 1>;
 				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
@@ -2071,7 +2077,7 @@
 			};
 		};
 
-		target-module@22000 {			/* 0x48322000, ap 116 64.0 */
+		gpio5_target: target-module@22000 {		/* 0x48322000, ap 116 64.0 */
 			compatible = "ti,sysc-omap2", "ti,sysc";
 			ti,hwmods = "gpio6";
 			reg = <0x22000 0x4>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am43x-epos-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -42,7 +42,7 @@
 	};
 
 	lcd0: display {
-		compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
+		compatible = "osddisplays,osd070t1718-19ts", "panel-dpi";
 		label = "lcd";
 
 		backlight = <&lcd_bl>;
@@ -589,7 +589,7 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins>;
-	clock-frequency = <400000>;
+	clock-frequency = <100000>;
 
 	tps65218: tps65218@24 {
 		reg = <0x24>;
@@ -848,6 +848,7 @@
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&spi0_pins_default>;
 	pinctrl-1 = <&spi0_pins_sleep>;
+	ti,pindir-d0-out-d1-in;
 };
 
 &spi1 {
@@ -855,6 +856,7 @@
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&spi1_pins_default>;
 	pinctrl-1 = <&spi1_pins_sleep>;
+	ti,pindir-d0-out-d1-in;
 };
 
 &usb2_phy1 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am43xx-clocks.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am43xx-clocks.dtsi
@@ -704,6 +704,60 @@
 		ti,bit-shift = <8>;
 		reg = <0x2a48>;
 	};
+
+	clkout1_osc_div_ck: clkout1-osc-div-ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&sys_clkin_ck>;
+		ti,bit-shift = <20>;
+		ti,max-div = <4>;
+		reg = <0x4100>;
+	};
+
+	clkout1_src2_mux_ck: clkout1-src2-mux-ck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&clk_rc32k_ck>, <&sysclk_div>, <&dpll_ddr_m2_ck>,
+			 <&dpll_per_m2_ck>, <&dpll_disp_m2_ck>,
+			 <&dpll_mpu_m2_ck>;
+		reg = <0x4100>;
+	};
+
+	clkout1_src2_pre_div_ck: clkout1-src2-pre-div-ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&clkout1_src2_mux_ck>;
+		ti,bit-shift = <4>;
+		ti,max-div = <8>;
+		reg = <0x4100>;
+	};
+
+	clkout1_src2_post_div_ck: clkout1-src2-post-div-ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&clkout1_src2_pre_div_ck>;
+		ti,bit-shift = <8>;
+		ti,max-div = <32>;
+		ti,index-power-of-two;
+		reg = <0x4100>;
+	};
+
+	clkout1_mux_ck: clkout1-mux-ck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&clkout1_osc_div_ck>, <&clk_rc32k_ck>,
+			 <&clkout1_src2_post_div_ck>, <&dpll_extdev_m2_ck>;
+		ti,bit-shift = <16>;
+		reg = <0x4100>;
+	};
+
+	clkout1_ck: clkout1-ck {
+		#clock-cells = <0>;
+		compatible = "ti,gate-clock";
+		clocks = <&clkout1_mux_ck>;
+		ti,bit-shift = <23>;
+		reg = <0x4100>;
+	};
 };
 
 &prcm {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am571x-idk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am571x-idk.dts
@@ -167,11 +167,7 @@
 
 &pcie1_rc {
 	status = "okay";
-	gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
-};
-
-&pcie1_ep {
-	gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
+	gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>;
 };
 
 &mmc1 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am572x-idk-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am572x-idk-common.dtsi
@@ -147,10 +147,6 @@
 	gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
 };
 
-&pcie1_ep {
-	gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
-};
-
 &mailbox5 {
 	status = "okay";
 	mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
@@ -29,6 +29,27 @@
 		reg = <0x0 0x80000000 0x0 0x80000000>;
 	};
 
+	main_12v0: fixedregulator-main_12v0 {
+		/* main supply */
+		compatible = "regulator-fixed";
+		regulator-name = "main_12v0";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	evm_5v0: fixedregulator-evm_5v0 {
+		/* Output of TPS54531D */
+		compatible = "regulator-fixed";
+		regulator-name = "evm_5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&main_12v0>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
 	vdd_3v3: fixedregulator-vdd_3v3 {
 		compatible = "regulator-fixed";
 		regulator-name = "vdd_3v3";
@@ -547,10 +568,6 @@
 	gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
 };
 
-&pcie1_ep {
-	gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
-};
-
 &mcasp3 {
 	#sound-dai-cells = <0>;
 	assigned-clocks = <&l4per2_clkctrl DRA7_L4PER2_MCASP3_CLKCTRL 24>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
@@ -527,7 +527,7 @@
 
 		interrupt-parent = <&gpio1>;
 		interrupts = <31 0>;
-		pendown-gpio = <&gpio1 31 0>;
+		pendown-gpio = <&gpio1 31 GPIO_ACTIVE_LOW>;
 
 
 		ti,x-min = /bits/ 16 <0x0>;
@@ -611,12 +611,11 @@
 	>;
 };
 
-&gpio3 {
-	status = "okay";
+&gpio3_target {
 	ti,no-reset-on-init;
 };
 
-&gpio2 {
+&gpio2_target {
 	status = "okay";
 	ti,no-reset-on-init;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/amgis-fcl-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/amgis-fcl-common.dtsi
@@ -0,0 +1,784 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
+
+/dts-v1/;
+
+#include "imx7d.dtsi"
+
+/ {
+	compatible = "fsl,imx7d-sdb", "fsl,imx7d";
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	m4_tcm: tcml@007f8000 {
+		compatible = "fsl, m4_tcml";
+		reg = <0x007f8000 0x8000>;
+	};
+
+	memory {
+		reg = <0x80200000 0x3fd00000>;
+		linux,usable-memory = <0x80200000 0x3fd00000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		m4_0: m4_app@80000000 {
+			reg = <0x80000000 0x00100000>;
+		};
+
+		rpmsg_mem: rpmsg_mem_reg@bfff0000 {
+			no-map;
+			reg = <0xbfff0000 0x00010000>;
+		};
+
+		a7_1: a7_1_app@90000000 {
+			no-map;
+			reg = <0x90000000 0x10000000>;
+		};
+
+		a7_1_2: a7_1_2_app@A0000000 {
+			reg = <0xA0000000 0x10000000>;
+		};
+	};
+
+	shared-ddr {
+		compatible = "generic-uio";
+		linux,uio-name = "ps-pl-ddr";
+		reg = <0x90000000 0x10000000>;
+	};
+
+	// enable for STM8 encoder on new board
+	stm8_en {
+		compatible = "gpio-leds";
+		led0 {
+			gpios = <&gpio7 6 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_otg1_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		status = "okay";
+	};
+
+	reg_vref_1v8: regulator-vref-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "vref-1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_vref_3v3: regulator-vref-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vref-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	wifi_en: regulator-wifi_en {
+		compatible = "regulator-fixed";
+		regulator-name = "wifi0en";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_wifi_en>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vwlan_fixed: wifi-enable {
+		gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+	};
+
+	panel {
+		compatible = "dlc,dlc0430dcp10rf-2";
+		backlight = <&backlight>;
+		//power-supply = <&reg_lcd_3v3>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
+
+	sdhci1_pwrseq: sdhci1_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+		post-power-on-delay-ms = <15>;
+		power-off-delay-us = <70>;
+
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 8 9 10 11 12 13 14 15 16 18 20 22 24 26 28 30 32 36 40 44 48 52 56 60 64 72 80 88 96 104 112 120 128 143 159 175 191 207 223 239 255 255 >;
+		default-brightness-level = <40>;
+		status = "okay";
+	};
+
+	pxp_v4l2_out {
+		compatible = "fsl,imx7d-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
+		status = "okay";
+	};
+
+    soc {
+		caam_sm: caam-sm@100000 {
+			compatible = "fsl,imx7d-caam-sm", "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
+
+		ocrams_ddr: sram@900000 {
+			compatible = "fsl,ddr-lpm-sram";
+			reg = <0x900000 0x1000>;
+			clocks = <&clks IMX7D_OCRAM_CLK>;
+		};
+
+		ocram: sram@901000 {
+			compatible = "mmio-sram";
+			reg = <0x901000 0xf000>;
+			clocks = <&clks IMX7D_OCRAM_CLK>;
+		};
+
+		ocram_optee {
+			compatible = "fsl,optee-lpm-sram";
+			reg = <0x180000 0x8000>;
+			overw_reg = <&ocrams_ddr 0x904000 0x1000>,
+					<&ocram 0x905000 0x1b000>,
+					<&ocrams 0x900000 0x4000>;
+			overw_clock = <&ocrams &clks IMX7D_OCRAM_CLK>;
+		};
+
+		ocrams_mf: sram-mf@00900000 {
+			compatible = "fsl,mega-fast-sram";
+			reg = <0x00900000 0x20000>;
+			clocks = <&clks IMX7D_OCRAM_CLK>;
+		};
+    };
+
+	sound {
+		compatible = "simple-audio-card";
+
+		simple-audio-card,name = "tas2110";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,bitclock-master = <&cpu_dai>;
+		simple-audio-card,frame-master = <&cpu_dai>;
+		simple-audio-card,widgets = "Speaker", "External Speaker";
+		simple-audio-card,routing = "External Speaker", "OUT";
+
+		cpu_dai: simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&tas2110>;
+		};
+	};
+
+	clko1: clock-clko1 {
+		compatible = "gpio-gate-clock";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_9281_clk>;
+		clocks = <&clks IMX7D_CLKO1_ROOT_DIV>;
+		#clock-cells = <0>;
+		enable-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_keys>;
+
+		wakeup {
+			label = "spi-miso-wake-up";
+			gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+			linux,code = <KEY_WAKEUP>;
+			wakeup-source;
+		};
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "disabled";
+};
+
+&adc2 {
+	vref-supply = <&reg_vref_1v8>;
+	status = "disabled";
+};
+
+&cpu0 {
+	/delete-property/cpu-idle-states;
+};
+
+&cpu1 {
+	/delete-property/cpu-idle-states;
+};
+
+/delete-node/&cpu_sleep_wait;
+/delete-node/&csi;
+/delete-node/&video_mux;
+
+&aips2 {
+	csi1: csi1@30710000 {
+		compatible = "fsl,imx7d-csi", "fsl,imx6s-csi";
+		csi-mux-mipi = <&gpr 0x14 4>;
+		fsl,mipi-mode;
+		reg = <0x30710000 0x10000>;
+		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_CLK_DUMMY>,
+			<&clks IMX7D_CSI_MCLK_ROOT_CLK>,
+			<&clks IMX7D_CLK_DUMMY>;
+		clock-names = "disp-axi", "csi_mclk", "disp_dcic";
+		status = "okay";
+
+		port {
+			csi_ep: endpoint {
+				remote-endpoint = <&csi_mipi_ep>;
+			};
+		};
+	};
+
+	mipi_csi: mipi-csi@30750000 {
+		compatible = "fsl,imx7d-mipi-csi";
+		reg = <0x30750000 0x10000>;
+		interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MIPI_CSI_ROOT_CLK>,
+				<&clks IMX7D_MIPI_DPHY_ROOT_CLK>;
+		clock-names = "mipi_clk", "phy_clk";
+		clock-frequency = <240000000>;
+		mipi-phy-supply = <&reg_1p0d>;
+		csis-phy-reset = <&src 0x28 2>;
+		bus-width = <4>;
+		status = "okay";
+		/delete-node/ port@0;
+		/delete-node/ port@1;
+
+		port {
+			mipi_sensor_ep: endpoint@1 {
+				remote-endpoint = <&ov9281_mipi_ep>;
+				data-lanes = <2>;
+				csis-hs-settle = <13>;
+				csis-clk-settle = <2>;
+				csis-wclk;
+			};
+
+			csi_mipi_ep: endpoint@2 {
+				remote-endpoint = <&csi_ep>;
+			};
+		};
+	};
+
+	system_counter_rd: system-counter-rd@306a0000 {
+		compatible = "fsl,imx7d-system-counter-rd";
+		reg = <0x306a0000 0x10000>;
+		status = "disabled";
+	};
+
+	system_counter_cmp: system-counter-cmp@306b0000 {
+		compatible = "fsl,imx7d-system-counter-cmp";
+		reg = <0x306b0000 0x10000>;
+		status = "disabled";
+	};
+
+	system_counter_ctrl: system-counter-ctrl@306c0000 {
+		compatible = "fsl,imx7d-system-counter-ctrl";
+		reg = <0x306c0000 0x10000>;
+		interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
+			<GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+};
+
+&aips3 {
+	mu: mu@30aa0000 {
+		compatible = "fsl,imx7d-mu", "fsl,imx6sx-mu";
+		reg = <0x30aa0000 0x10000>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		clock-names = "mu";
+        #mbox-cells = <2>;
+		status = "okay";
+	};
+
+	mu_lp: mu_lp@30aa0000 {
+		compatible = "fsl,imx7d-mu-lp", "fsl,imx6sx-mu-lp";
+		reg = <0x30aa0000 0x10000>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_MU_ROOT_CLK>;
+		clock-names = "mu";
+		status = "okay";
+	};
+
+	rpmsg: rpmsg{
+		compatible = "fsl,imx7d-rpmsg";
+		vdev-nums = <1>;
+		reg = <0xbfff0000 0x00010000>;
+		/* up to now, the following channels are used in imx rpmsg
+		 * - tx1/rx1: messages channel.
+		 * - general interrupt1: remote proc finish re-init rpmsg stack
+		 *   when A core is partition reset.
+		 */
+		mbox-names = "tx", "rx", "rxdb";
+		mboxes = <&mu 0 1
+			  &mu 1 1
+			  &mu 3 1>;
+		status = "okay";
+	};
+
+	sema4: sema4@30ac0000 {
+		compatible = "fsl,imx7d-sema4";
+		reg = <0x30ac0000 0x10000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX7D_SEMA4_HS_ROOT_CLK>;
+		clock-names = "sema4";
+		status = "okay";
+	};
+};
+
+&clks {
+	assigned-clocks = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+	assigned-clock-rates = <884736000>;
+};
+
+&gpc {
+	mipi-phy-supply = <&reg_1p0d>;
+	pcie-phy-supply = <&reg_1p0d>;
+	fsl,mf-mix-wakeup-irq = <0x54010000 0xc00 0x0 0x1040640>;
+};
+
+// &epxp {
+// 	status = "okay";
+// };
+
+&intc {
+	exclude-int = <7 17 54>;
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	atmel_mxt_ts@4a {
+		compatible = "atmel,maxtouch";
+		reg = <0x4a>;
+		pinctrl-names ="default";
+		pinctrl-0 = <&pinctrl_atmel_mxt_ts>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		reset-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ov9281_mipi: ov9281_mipi@60 {
+		status = "okay";
+		compatible = "ovti,ov9281_mipi";
+		reg = <0x60>;
+		clocks = <&clko1>;
+		clock-names = "csi_mclk";
+		csi_id = <0>;
+		pwn-gpios = <&gpio7 9 GPIO_ACTIVE_HIGH>;
+		mclk = <24000000>;
+		mclk_source = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ov9281>;
+		port {
+			ov9281_mipi_ep: endpoint {
+				remote-endpoint = <&mipi_sensor_ep>;
+			};
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	tas2110: tas2110@4c {
+		compatible = "ti,tas2110";
+		reg = <0x4c>;
+		#sound-dai-cells = <0>;
+		ti,imon-slot-no = <2>;
+	};
+};
+
+&i2c4 {
+	clock-frequency = <100000> ;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+
+	pn715: pn547@28 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_nfcgpio>;
+		compatible = "nxp,pn547";
+
+		reg = <0x28>;
+		clock-frequency = <100000>;
+
+		interrupt-gpios = <&gpio1 4 0>;
+		enable-gpios = <&gpio5 10 0>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	imx7d-sdb {
+		pinctrl_ov9281: ov9281grp {
+			fsl,pins = <
+				MX7D_PAD_ENET1_RGMII_TD3__GPIO7_IO9 	0x59
+			>;
+		};
+
+		pinctrl_nfcgpio: nfcgrp {
+			fsl,pins = <
+				MX7D_PAD_SD2_WP__GPIO5_IO10		0x59
+				MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4	0x59
+			>;
+		};
+
+		pinctrl_atmel_mxt_ts: atmelgrp-1 {
+            fsl,pins = <
+                MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6 0x59
+            >;
+		};
+
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				MX7D_PAD_I2C1_SDA__I2C1_SDA		0x4000007f
+				MX7D_PAD_I2C1_SCL__I2C1_SCL		0x4000007f
+			>;
+		};
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX7D_PAD_I2C2_SDA__I2C2_SDA		0x4000007f
+				MX7D_PAD_I2C2_SCL__I2C2_SCL		0x4000007f
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX7D_PAD_I2C3_SDA__I2C3_SDA		0x4000007f
+				MX7D_PAD_I2C3_SCL__I2C3_SCL		0x4000007f
+			>;
+		};
+
+		pinctrl_i2c4: i2c4grp {
+			fsl,pins = <
+				MX7D_PAD_I2C4_SDA__I2C4_SDA		0x4000007f
+				MX7D_PAD_I2C4_SCL__I2C4_SCL		0x4000007f
+			>;
+		};
+
+		pinctrl_sai1: sai1grp {
+			fsl,pins = <
+				MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC	0x1f
+				MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK  	0x1f
+				MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0	0x30
+			>;
+		};
+
+		pinctrl_sai2: sai2grp {
+			fsl,pins = <
+				MX7D_PAD_SAI2_TX_BCLK__SAI2_TX_BCLK     0x1f
+				MX7D_PAD_SAI2_TX_SYNC__SAI2_TX_SYNC     0x1f
+				MX7D_PAD_SAI2_TX_DATA__SAI2_TX_DATA0    0x30
+				MX7D_PAD_SAI2_RX_DATA__SAI2_RX_DATA0    0x1f
+			>;
+		};
+
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX	0x79
+				MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX	0x79
+			>;
+		};
+
+		pinctrl_uart3: uart3grp {
+            fsl,pins = <
+                MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX    0x79
+                MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX    0x79
+                MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS     0x79
+                MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS     0x79
+            >;
+		};
+
+		pinctrl_usdhc1: usdhc1grp {
+			fsl,pins = <
+				MX7D_PAD_SD1_CMD__SD1_CMD		0x59
+				MX7D_PAD_SD1_CLK__SD1_CLK		0x19
+				MX7D_PAD_SD1_DATA0__SD1_DATA0		0x59
+				MX7D_PAD_SD1_DATA1__SD1_DATA1		0x59
+				MX7D_PAD_SD1_DATA2__SD1_DATA2		0x59
+				MX7D_PAD_SD1_DATA3__SD1_DATA3		0x59
+
+			>;
+		};
+
+		pinctrl_usdhc1_100mhz: usdhc1grp_100mhz {
+			fsl,pins = <
+				MX7D_PAD_SD1_CMD__SD1_CMD		0x5a
+				MX7D_PAD_SD1_CLK__SD1_CLK		0x1a
+				MX7D_PAD_SD1_DATA0__SD1_DATA0		0x5a
+				MX7D_PAD_SD1_DATA1__SD1_DATA1		0x5a
+				MX7D_PAD_SD1_DATA2__SD1_DATA2		0x5a
+				MX7D_PAD_SD1_DATA3__SD1_DATA3		0x5a
+			>;
+		};
+
+		pinctrl_usdhc1_200mhz: usdhc1grp_200mhz {
+			fsl,pins = <
+				MX7D_PAD_SD1_CMD__SD1_CMD		0x5b
+				MX7D_PAD_SD1_CLK__SD1_CLK		0x1b
+				MX7D_PAD_SD1_DATA0__SD1_DATA0		0x5b
+				MX7D_PAD_SD1_DATA1__SD1_DATA1		0x5b
+				MX7D_PAD_SD1_DATA2__SD1_DATA2		0x5b
+				MX7D_PAD_SD1_DATA3__SD1_DATA3		0x5b
+			>;
+		};
+
+        pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				MX7D_PAD_SD3_CMD__SD3_CMD		0x59
+				MX7D_PAD_SD3_CLK__SD3_CLK		0x19
+				MX7D_PAD_SD3_DATA0__SD3_DATA0		0x59
+				MX7D_PAD_SD3_DATA1__SD3_DATA1		0x59
+				MX7D_PAD_SD3_DATA2__SD3_DATA2		0x59
+				MX7D_PAD_SD3_DATA3__SD3_DATA3		0x59
+				MX7D_PAD_SD3_DATA4__SD3_DATA4		0x59
+				MX7D_PAD_SD3_DATA5__SD3_DATA5		0x59
+				MX7D_PAD_SD3_DATA6__SD3_DATA6		0x59
+				MX7D_PAD_SD3_DATA7__SD3_DATA7		0x59
+				MX7D_PAD_SD3_STROBE__SD3_STROBE		0x19
+			>;
+		};
+
+		pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+			fsl,pins = <
+				MX7D_PAD_SD3_CMD__SD3_CMD		0x5a
+				MX7D_PAD_SD3_CLK__SD3_CLK		0x1a
+				MX7D_PAD_SD3_DATA0__SD3_DATA0		0x5a
+				MX7D_PAD_SD3_DATA1__SD3_DATA1		0x5a
+				MX7D_PAD_SD3_DATA2__SD3_DATA2		0x5a
+				MX7D_PAD_SD3_DATA3__SD3_DATA3		0x5a
+				MX7D_PAD_SD3_DATA4__SD3_DATA4		0x5a
+				MX7D_PAD_SD3_DATA5__SD3_DATA5		0x5a
+				MX7D_PAD_SD3_DATA6__SD3_DATA6		0x5a
+				MX7D_PAD_SD3_DATA7__SD3_DATA7		0x5a
+				MX7D_PAD_SD3_STROBE__SD3_STROBE		0x1a
+			>;
+		};
+
+		pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+			fsl,pins = <
+				MX7D_PAD_SD3_CMD__SD3_CMD		0x5b
+				MX7D_PAD_SD3_CLK__SD3_CLK		0x1b
+				MX7D_PAD_SD3_DATA0__SD3_DATA0		0x5b
+				MX7D_PAD_SD3_DATA1__SD3_DATA1		0x5b
+				MX7D_PAD_SD3_DATA2__SD3_DATA2		0x5b
+				MX7D_PAD_SD3_DATA3__SD3_DATA3		0x5b
+				MX7D_PAD_SD3_DATA4__SD3_DATA4		0x5b
+				MX7D_PAD_SD3_DATA5__SD3_DATA5		0x5b
+				MX7D_PAD_SD3_DATA6__SD3_DATA6		0x5b
+				MX7D_PAD_SD3_DATA7__SD3_DATA7		0x5b
+				MX7D_PAD_SD3_STROBE__SD3_STROBE		0x1b
+			>;
+		};
+
+		pinctrl_wifi: wifigrp {
+			fsl,pins = <
+				MX7D_PAD_GPIO1_IO13__GPIO1_IO13		0x59
+				MX7D_PAD_GPIO1_IO14__GPIO1_IO14		0x59
+			>;
+		};
+
+		pinctrl_wifi_en: wifigrp_en {
+			fsl,pins = <
+				MX7D_PAD_GPIO1_IO15__GPIO1_IO15		0x59
+			>;
+		};
+
+		pinctrl_gpio_keys: gpio_keysgrp {
+			fsl,pins = <
+				MX7D_PAD_ECSPI2_MISO__GPIO4_IO22	0x59
+			>;
+		};
+	};
+};
+
+&iomuxc_lpsr {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb_vbus_en &pinctrl_tp_resetn>;
+
+	imx7d-sdb {
+		pinctrl_9281_clk: 9281_clk_grp {
+            fsl,pins = <
+                MX7D_PAD_LPSR_GPIO1_IO02__CCM_CLKO1     0x03
+            >;
+		};
+
+		pinctrl_usb_vbus_en: usb_vbus_en-2 {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5	  0x14
+			>;
+		};
+
+		pinctrl_tp_resetn: tp_resetn {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7	  0x14
+			>;
+		};
+	};
+};
+
+&lcdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lcdif>;
+	//display = <&display0>;
+	status = "okay";
+
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
+		};
+	};
+};
+
+&pgc_pcie_phy {
+	power-supply = <&reg_1p0d>;
+};
+
+&reg_1p0d {
+	status = "okay";
+};
+
+&sai1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai1>;
+	assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>,
+			  <&clks IMX7D_SAI1_ROOT_CLK>;
+	assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+	assigned-clock-rates = <0>, <36864000>;
+	status = "okay";
+	fsl,sai-asynchronous;
+};
+
+/* TBD for bluetooth audio
+&sai2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai2 &pinctrl_sai2_mclk>;
+	assigned-clocks = <&clks IMX7D_SAI2_ROOT_SRC>,
+			  <&clks IMX7D_SAI2_ROOT_CLK>;
+	assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+	assigned-clock-rates = <0>, <36864000>;
+	status = "okay";
+};
+*/
+
+&sdma {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+	status = "okay";
+};
+
+&uart2 {
+	status = "disabled";
+};
+
+/*Bluetooth*/
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+	status = "okay";
+};
+
+&usbotg1 {
+	vbus-supply = <&reg_usb_otg1_vbus>;
+	srp-disable;
+	hnp-disable;
+	adp-disable;
+	status = "okay";
+};
+
+&usdhc1 {  // wifi
+	/*Disabling these pinctrl forces the SDIO interface to run at a slower speed*/
+	/*The faster speeds were struggling with a timing issue that still needs to be resolved*/
+	//pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wifi>;
+	//pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_wifi>;
+	//pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_wifi>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	non-removable;
+	fsl,tuning-step = <2>;
+	pm-ignore-notify;
+	vmmc-supply = <&reg_vref_3v3>;
+	vwlan-supply = <&vwlan_fixed>;
+	regulator = <&wifi_en>;
+	mmc-pwrseq = <&sdhci1_pwrseq>;
+	keep-power-in-suspend;
+	bus-width = <4>;
+	cap-power-off-card;
+	status = "okay";
+	mwifiex: wifi@2 {
+		compatible = "marvell,sd8997";
+		reg = <2>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+		status = "okay";
+	};
+
+	btmrvl: bluetooth@3 {
+		compatible = "marvell,sd8997-bt";
+		reg = <3>;
+	};
+};
+
+&usdhc3 {  // emmc
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
+	assigned-clock-rates = <400000000>;
+	bus-width = <8>;
+	auto-cmd23-broken;
+	non-removable;
+	status = "okay";
+};
+
+&wdog3{
+	status = "disabled";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/amgis-fcl-v3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/amgis-fcl-v3.dts
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
+
+/dts-v1/;
+
+#include "amgis-fcl-common.dtsi"
+
+/ {
+	model = "AMGIS-V3";
+};
+
+&backlight {
+	pwms = <&pwm4 0 7000 0>;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	imx7d-sdb {
+		pinctrl_lcdif: lcdifgrp {
+			fsl,pins = <
+				MX7D_PAD_LCD_DATA00__LCD_DATA0		0x79
+				MX7D_PAD_LCD_DATA01__LCD_DATA1		0x79
+				MX7D_PAD_LCD_DATA02__LCD_DATA2		0x79
+				MX7D_PAD_LCD_DATA03__LCD_DATA3		0x79
+				MX7D_PAD_LCD_DATA04__LCD_DATA4		0x79
+				MX7D_PAD_LCD_DATA05__LCD_DATA5		0x79
+				MX7D_PAD_LCD_DATA06__LCD_DATA6		0x79
+				MX7D_PAD_LCD_DATA07__LCD_DATA7		0x79
+				MX7D_PAD_LCD_DATA08__LCD_DATA8		0x79
+				MX7D_PAD_LCD_DATA09__LCD_DATA9		0x79
+				MX7D_PAD_LCD_DATA10__LCD_DATA10		0x79
+				MX7D_PAD_LCD_DATA11__LCD_DATA11		0x79
+				MX7D_PAD_LCD_DATA12__LCD_DATA12		0x79
+				MX7D_PAD_LCD_DATA13__LCD_DATA13		0x79
+				MX7D_PAD_LCD_DATA14__LCD_DATA14		0x79
+				MX7D_PAD_LCD_DATA15__LCD_DATA15		0x79
+				MX7D_PAD_LCD_DATA16__LCD_DATA16		0x79
+				MX7D_PAD_LCD_DATA17__LCD_DATA17		0x79
+				MX7D_PAD_LCD_DATA18__LCD_DATA18		0x79
+				MX7D_PAD_LCD_DATA19__LCD_DATA19		0x79
+				MX7D_PAD_LCD_DATA20__LCD_DATA20		0x79
+				MX7D_PAD_LCD_DATA21__LCD_DATA21		0x79
+				MX7D_PAD_LCD_DATA22__LCD_DATA22		0x79
+				MX7D_PAD_LCD_DATA23__LCD_DATA23		0x79
+				MX7D_PAD_LCD_CLK__LCD_CLK		0x79
+				MX7D_PAD_LCD_ENABLE__LCD_ENABLE		0x79
+				MX7D_PAD_LCD_VSYNC__LCD_VSYNC		0x79
+				MX7D_PAD_LCD_HSYNC__LCD_HSYNC		0x79
+				MX7D_PAD_LCD_RESET__LCD_RESET		0x79
+			>;
+		};
+	};
+};
+
+&iomuxc_lpsr {
+	imx7d-sdb {
+		pinctrl_pwm4: pwm4grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO00__PWM4_OUT	  0x30
+			>;
+		};
+	};
+};
+
+&pwm4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm4>;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/amgis-fcl-v4.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/amgis-fcl-v4.dts
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
+
+/dts-v1/;
+
+#include "amgis-fcl-common.dtsi"
+
+/ {
+	model = "AMGIS-V4";
+};
+
+&backlight {
+	pwms = <&pwm4 0 7000 0>;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	imx7d-sdb {
+		pinctrl_lcdif: lcdifgrp {
+			fsl,pins = <
+				MX7D_PAD_LCD_DATA00__LCD_DATA0		0x7C
+				MX7D_PAD_LCD_DATA01__LCD_DATA1		0x7C
+				MX7D_PAD_LCD_DATA02__LCD_DATA2		0x7C
+				MX7D_PAD_LCD_DATA03__LCD_DATA3		0x7C
+				MX7D_PAD_LCD_DATA04__LCD_DATA4		0x7C
+				MX7D_PAD_LCD_DATA05__LCD_DATA5		0x7C
+				MX7D_PAD_LCD_DATA06__LCD_DATA6		0x7C
+				MX7D_PAD_LCD_DATA07__LCD_DATA7		0x7C
+				MX7D_PAD_LCD_DATA08__LCD_DATA8		0x7C
+				MX7D_PAD_LCD_DATA09__LCD_DATA9		0x7C
+				MX7D_PAD_LCD_DATA10__LCD_DATA10		0x7C
+				MX7D_PAD_LCD_DATA11__LCD_DATA11		0x7C
+				MX7D_PAD_LCD_DATA12__LCD_DATA12		0x7C
+				MX7D_PAD_LCD_DATA13__LCD_DATA13		0x7C
+				MX7D_PAD_LCD_DATA14__LCD_DATA14		0x7C
+				MX7D_PAD_LCD_DATA15__LCD_DATA15		0x7C
+				MX7D_PAD_LCD_DATA16__LCD_DATA16		0x7C
+				MX7D_PAD_LCD_DATA17__LCD_DATA17		0x7C
+				MX7D_PAD_LCD_DATA18__LCD_DATA18		0x7C
+				MX7D_PAD_LCD_DATA19__LCD_DATA19		0x7C
+				MX7D_PAD_LCD_DATA20__LCD_DATA20		0x7C
+				MX7D_PAD_LCD_DATA21__LCD_DATA21		0x7C
+				MX7D_PAD_LCD_DATA22__LCD_DATA22		0x7C
+				MX7D_PAD_LCD_DATA23__LCD_DATA23		0x7C
+				MX7D_PAD_LCD_CLK__LCD_CLK			0x7F
+				MX7D_PAD_LCD_ENABLE__LCD_ENABLE		0x7C
+				MX7D_PAD_LCD_VSYNC__LCD_VSYNC		0x7C
+				MX7D_PAD_LCD_HSYNC__LCD_HSYNC		0x7C
+				MX7D_PAD_LCD_RESET__LCD_RESET		0x7C
+			>;
+		};
+	};
+};
+
+&iomuxc_lpsr {
+	imx7d-sdb {
+		pinctrl_pwm4: pwm4grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO00__PWM4_OUT	  0x30
+			>;
+		};
+	};
+};
+
+&pwm4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm4>;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/amgis-fcl-v5.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/amgis-fcl-v5.dts
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
+
+/dts-v1/;
+
+#include "amgis-fcl-common.dtsi"
+
+/ {
+	model = "AMGIS-V5";
+};
+
+&backlight {
+	pwms = <&pwm1 0 7000 0>;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	imx7d-sdb {
+		pinctrl_lcdif: lcdifgrp {
+			fsl,pins = <
+				MX7D_PAD_LCD_DATA00__LCD_DATA0		0x7C
+				MX7D_PAD_LCD_DATA01__LCD_DATA1		0x7C
+				MX7D_PAD_LCD_DATA02__LCD_DATA2		0x7C
+				MX7D_PAD_LCD_DATA03__LCD_DATA3		0x7C
+				MX7D_PAD_LCD_DATA04__LCD_DATA4		0x7C
+				MX7D_PAD_LCD_DATA05__LCD_DATA5		0x7C
+				MX7D_PAD_LCD_DATA06__LCD_DATA6		0x7C
+				MX7D_PAD_LCD_DATA07__LCD_DATA7		0x7C
+				MX7D_PAD_LCD_DATA08__LCD_DATA8		0x7C
+				MX7D_PAD_LCD_DATA09__LCD_DATA9		0x7C
+				MX7D_PAD_LCD_DATA10__LCD_DATA10		0x7C
+				MX7D_PAD_LCD_DATA11__LCD_DATA11		0x7C
+				MX7D_PAD_LCD_DATA12__LCD_DATA12		0x7C
+				MX7D_PAD_LCD_DATA13__LCD_DATA13		0x7C
+				MX7D_PAD_LCD_DATA14__LCD_DATA14		0x7C
+				MX7D_PAD_LCD_DATA15__LCD_DATA15		0x7C
+				MX7D_PAD_LCD_DATA16__LCD_DATA16		0x7C
+				MX7D_PAD_LCD_DATA17__LCD_DATA17		0x7C
+				MX7D_PAD_LCD_DATA18__LCD_DATA18		0x7C
+				MX7D_PAD_LCD_DATA19__LCD_DATA19		0x7C
+				MX7D_PAD_LCD_DATA20__LCD_DATA20		0x7C
+				MX7D_PAD_LCD_DATA21__LCD_DATA21		0x7C
+				MX7D_PAD_LCD_DATA22__LCD_DATA22		0x7C
+				MX7D_PAD_LCD_DATA23__LCD_DATA23		0x7C
+				MX7D_PAD_LCD_CLK__LCD_CLK			0x7F
+				MX7D_PAD_LCD_ENABLE__LCD_ENABLE		0x7C
+				MX7D_PAD_LCD_VSYNC__LCD_VSYNC		0x7C
+				MX7D_PAD_LCD_HSYNC__LCD_HSYNC		0x7C
+				MX7D_PAD_LCD_RESET__LCD_RESET		0x7C
+			>;
+		};
+	};
+};
+
+&iomuxc_lpsr {
+	imx7d-sdb {
+		pinctrl_wdog1: wdog1grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B		0x74
+			>;
+		};
+
+		pinctrl_pwm1: pwm1grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT		0x30
+			>;
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog1>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/amgis-fcl-v6.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/amgis-fcl-v6.dts
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+//
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
+
+/dts-v1/;
+
+#include "amgis-fcl-common.dtsi"
+
+/ {
+	model = "AMGIS-V6";
+};
+
+&backlight {
+	pwms = <&pwm1 0 7000 0>;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	imx7d-sdb {
+		pinctrl_lcdif: lcdifgrp {
+			fsl,pins = <
+				MX7D_PAD_LCD_DATA00__LCD_DATA0		0x7C
+				MX7D_PAD_LCD_DATA01__LCD_DATA1		0x7C
+				MX7D_PAD_LCD_DATA02__LCD_DATA2		0x7C
+				MX7D_PAD_LCD_DATA03__LCD_DATA3		0x7C
+				MX7D_PAD_LCD_DATA04__LCD_DATA4		0x7C
+				MX7D_PAD_LCD_DATA05__LCD_DATA5		0x7C
+				MX7D_PAD_LCD_DATA06__LCD_DATA6		0x7C
+				MX7D_PAD_LCD_DATA07__LCD_DATA7		0x7C
+				MX7D_PAD_LCD_DATA08__LCD_DATA8		0x7C
+				MX7D_PAD_LCD_DATA09__LCD_DATA9		0x7C
+				MX7D_PAD_LCD_DATA10__LCD_DATA10		0x7C
+				MX7D_PAD_LCD_DATA11__LCD_DATA11		0x7C
+				MX7D_PAD_LCD_DATA12__LCD_DATA12		0x7C
+				MX7D_PAD_LCD_DATA13__LCD_DATA13		0x7C
+				MX7D_PAD_LCD_DATA14__LCD_DATA14		0x7C
+				MX7D_PAD_LCD_DATA15__LCD_DATA15		0x7C
+				MX7D_PAD_LCD_DATA16__LCD_DATA16		0x7C
+				MX7D_PAD_LCD_DATA17__LCD_DATA17		0x7C
+				MX7D_PAD_LCD_DATA18__LCD_DATA18		0x7C
+				MX7D_PAD_LCD_DATA19__LCD_DATA19		0x7C
+				MX7D_PAD_LCD_DATA20__LCD_DATA20		0x7C
+				MX7D_PAD_LCD_DATA21__LCD_DATA21		0x7C
+				MX7D_PAD_LCD_DATA22__LCD_DATA22		0x7C
+				MX7D_PAD_LCD_DATA23__LCD_DATA23		0x7C
+				MX7D_PAD_LCD_CLK__LCD_CLK			0x7F
+				MX7D_PAD_LCD_ENABLE__LCD_ENABLE		0x7C
+				MX7D_PAD_LCD_VSYNC__LCD_VSYNC		0x7C
+				MX7D_PAD_LCD_HSYNC__LCD_HSYNC		0x7C
+				MX7D_PAD_LCD_RESET__LCD_RESET		0x7C
+			>;
+		};
+	};
+};
+
+&iomuxc_lpsr {
+	imx7d-sdb {
+		pinctrl_wdog1: wdog1grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B		0x74
+			>;
+		};
+
+		pinctrl_pwm1: pwm1grp {
+			fsl,pins = <
+				MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT		0x30
+			>;
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog1>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-370.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-370.dtsi
@@ -74,7 +74,7 @@
 
 			pcie2: pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x80000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-375.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-375.dtsi
@@ -584,7 +584,7 @@
 
 			pcie1: pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-380.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-380.dtsi
@@ -79,7 +79,7 @@
 			/* x1 port */
 			pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -98,7 +98,7 @@
 			/* x1 port */
 			pcie@3,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-385-turris-omnia.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-385-turris-omnia.dts
@@ -22,6 +22,12 @@
 		stdout-path = &uart0;
 	};
 
+	aliases {
+		ethernet0 = &eth0;
+		ethernet1 = &eth1;
+		ethernet2 = &eth2;
+	};
+
 	memory {
 		device_type = "memory";
 		reg = <0x00000000 0x40000000>; /* 1024 MB */
@@ -236,6 +242,7 @@
 		status = "okay";
 		compatible = "ethernet-phy-id0141.0DD1", "ethernet-phy-ieee802.3-c22";
 		reg = <1>;
+		marvell,reg-init = <3 18 0 0x4985>;
 
 		/* irq is connected to &pcawan pin 7 */
 	};
@@ -290,7 +297,17 @@
 				};
 			};
 
-			/* port 6 is connected to eth0 */
+			ports@6 {
+				reg = <6>;
+				label = "cpu";
+				ethernet = <&eth0>;
+				phy-mode = "rgmii-id";
+
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
 		};
 	};
 };
@@ -306,7 +323,7 @@
 		marvell,function = "spi0";
 	};
 
-	spi0cs1_pins: spi0cs1-pins {
+	spi0cs2_pins: spi0cs2-pins {
 		marvell,pins = "mpp26";
 		marvell,function = "spi0";
 	};
@@ -341,7 +358,7 @@
 		};
 	};
 
-	/* MISO, MOSI, SCLK and CS1 are routed to pin header CN11 */
+	/* MISO, MOSI, SCLK and CS2 are routed to pin header CN11 */
 };
 
 &uart0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-385.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-385.dtsi
@@ -84,7 +84,7 @@
 			/* x1 port */
 			pcie2: pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -103,7 +103,7 @@
 			/* x1 port */
 			pcie3: pcie@3,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -125,7 +125,7 @@
 			 */
 			pcie4: pcie@4,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+				assigned-addresses = <0x82002000 0 0x48000 0 0x2000>;
 				reg = <0x2000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-388-helios4.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-388-helios4.dts
@@ -70,6 +70,9 @@
 
 	system-leds {
 		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&helios_system_led_pins>;
+
 		status-led {
 			label = "helios4:green:status";
 			gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
@@ -86,6 +89,9 @@
 
 	io-leds {
 		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&helios_io_led_pins>;
+
 		sata1-led {
 			label = "helios4:green:ata1";
 			gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
@@ -121,11 +127,15 @@
 	fan1: j10-pwm {
 		compatible = "pwm-fan";
 		pwms = <&gpio1 9 40000>;	/* Target freq:25 kHz */
+		pinctrl-names = "default";
+		pinctrl-0 = <&helios_fan1_pins>;
 	};
 
 	fan2: j17-pwm {
 		compatible = "pwm-fan";
 		pwms = <&gpio1 23 40000>;	/* Target freq:25 kHz */
+		pinctrl-names = "default";
+		pinctrl-0 = <&helios_fan2_pins>;
 	};
 
 	usb2_phy: usb2-phy {
@@ -291,16 +301,22 @@
 						       "mpp39", "mpp40";
 					marvell,function = "sd0";
 				};
-				helios_led_pins: helios-led-pins {
-					marvell,pins = "mpp24", "mpp25",
-						       "mpp49", "mpp50",
+				helios_system_led_pins: helios-system-led-pins {
+					marvell,pins = "mpp24", "mpp25";
+					marvell,function = "gpio";
+				};
+				helios_io_led_pins: helios-io-led-pins {
+					marvell,pins = "mpp49", "mpp50",
 						       "mpp52", "mpp53",
 						       "mpp54";
 					marvell,function = "gpio";
 				};
-				helios_fan_pins: helios-fan-pins {
-					marvell,pins = "mpp41", "mpp43",
-						       "mpp48", "mpp55";
+				helios_fan1_pins: helios_fan1_pins {
+					marvell,pins = "mpp41", "mpp43";
+					marvell,function = "gpio";
+				};
+				helios_fan2_pins: helios_fan2_pins {
+					marvell,pins = "mpp48", "mpp55";
 					marvell,function = "gpio";
 				};
 				microsom_spi1_cs_pins: spi1-cs-pins {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-38x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-38x.dtsi
@@ -165,7 +165,7 @@
 			};
 
 			uart0: serial@12000 {
-				compatible = "marvell,armada-38x-uart";
+				compatible = "marvell,armada-38x-uart", "ns16550a";
 				reg = <0x12000 0x100>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
@@ -175,7 +175,7 @@
 			};
 
 			uart1: serial@12100 {
-				compatible = "marvell,armada-38x-uart";
+				compatible = "marvell,armada-38x-uart", "ns16550a";
 				reg = <0x12100 0x100>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
@@ -339,7 +339,8 @@
 
 			comphy: phy@18300 {
 				compatible = "marvell,armada-380-comphy";
-				reg = <0x18300 0x100>;
+				reg-names = "comphy", "conf";
+				reg = <0x18300 0x100>, <0x18460 4>;
 				#address-cells = <1>;
 				#size-cells = <0>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-39x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-39x.dtsi
@@ -457,7 +457,7 @@
 			/* x1 port */
 			pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x40000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -476,7 +476,7 @@
 			/* x1 port */
 			pcie@3,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001800 0 0x44000 0 0x2000>;
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -498,7 +498,7 @@
 			 */
 			pcie@4,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+				assigned-addresses = <0x82002000 0 0x48000 0 0x2000>;
 				reg = <0x2000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-xp-98dx3236.dtsi
@@ -266,11 +266,6 @@
 	reg = <0x11000 0x100>;
 };
 
-&i2c1 {
-	compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
-	reg = <0x11100 0x100>;
-};
-
 &mpic {
 	reg = <0x20a00 0x2d0>, <0x21070 0x58>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -97,7 +97,7 @@
 
 			pcie2: pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -115,7 +115,7 @@
 
 			pcie3: pcie@3,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+				assigned-addresses = <0x82001800 0 0x48000 0 0x2000>;
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -133,7 +133,7 @@
 
 			pcie4: pcie@4,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x4c000 0 0x2000>;
+				assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>;
 				reg = <0x2000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -151,7 +151,7 @@
 
 			pcie5: pcie@5,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
+				assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
 				reg = <0x2800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -112,7 +112,7 @@
 
 			pcie2: pcie@2,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x44000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x44000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -130,7 +130,7 @@
 
 			pcie3: pcie@3,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x48000 0 0x2000>;
+				assigned-addresses = <0x82001800 0 0x48000 0 0x2000>;
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -148,7 +148,7 @@
 
 			pcie4: pcie@4,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x4c000 0 0x2000>;
+				assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>;
 				reg = <0x2000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -166,7 +166,7 @@
 
 			pcie5: pcie@5,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
+				assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
 				reg = <0x2800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -184,7 +184,7 @@
 
 			pcie6: pcie@6,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x84000 0 0x2000>;
+				assigned-addresses = <0x82003000 0 0x84000 0 0x2000>;
 				reg = <0x3000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -202,7 +202,7 @@
 
 			pcie7: pcie@7,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x88000 0 0x2000>;
+				assigned-addresses = <0x82003800 0 0x88000 0 0x2000>;
 				reg = <0x3800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -220,7 +220,7 @@
 
 			pcie8: pcie@8,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x8c000 0 0x2000>;
+				assigned-addresses = <0x82004000 0 0x8c000 0 0x2000>;
 				reg = <0x4000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
@@ -238,7 +238,7 @@
 
 			pcie9: pcie@9,0 {
 				device_type = "pci";
-				assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
+				assigned-addresses = <0x82004800 0 0x42000 0 0x2000>;
 				reg = <0x4800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-ast2500-evb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-ast2500-evb.dts
@@ -5,7 +5,7 @@
 
 / {
 	model = "AST2500 EVB";
-	compatible = "aspeed,ast2500";
+	compatible = "aspeed,ast2500-evb", "aspeed,ast2500";
 
 	aliases {
 		serial4 = &uart5;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-ast2600-evb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-ast2600-evb.dts
@@ -7,7 +7,7 @@
 
 / {
 	model = "AST2600 EVB";
-	compatible = "aspeed,ast2600";
+	compatible = "aspeed,ast2600-evb-a1", "aspeed,ast2600";
 
 	aliases {
 		serial4 = &uart5;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
@@ -81,11 +81,6 @@
 	status = "okay";
 };
 
-&vuart {
-	// VUART Host Console
-	status = "okay";
-};
-
 &uart1 {
 	// Host Console
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
@@ -22,9 +22,9 @@
 		#size-cells = <1>;
 		ranges;
 
-		vga_memory: framebuffer@7f000000 {
+		vga_memory: framebuffer@9f000000 {
 			no-map;
-			reg = <0x7f000000 0x01000000>;
+			reg = <0x9f000000 0x01000000>; /* 16M */
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-g4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -371,6 +371,7 @@
 						compatible = "aspeed,ast2400-ibt-bmc";
 						reg = <0xc0 0x18>;
 						interrupts = <8>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 				};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-g5.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -464,6 +464,7 @@
 						compatible = "aspeed,ast2500-ibt-bmc";
 						reg = <0xc0 0x18>;
 						interrupts = <8>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 				};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
@@ -117,11 +117,6 @@
 		groups = "FWSPID";
 	};
 
-	pinctrl_fwqspid_default: fwqspid_default {
-		function = "FWQSPID";
-		groups = "FWQSPID";
-	};
-
 	pinctrl_fwspiwp_default: fwspiwp_default {
 		function = "FWSPIWP";
 		groups = "FWSPIWP";
@@ -208,12 +203,12 @@
 	};
 
 	pinctrl_hvi3c3_default: hvi3c3_default {
-		function = "HVI3C3";
+		function = "I3C3";
 		groups = "HVI3C3";
 	};
 
 	pinctrl_hvi3c4_default: hvi3c4_default {
-		function = "HVI3C4";
+		function = "I3C4";
 		groups = "HVI3C4";
 	};
 
@@ -653,12 +648,12 @@
 	};
 
 	pinctrl_qspi1_default: qspi1_default {
-		function = "QSPI1";
+		function = "SPI1";
 		groups = "QSPI1";
 	};
 
 	pinctrl_qspi2_default: qspi2_default {
-		function = "QSPI2";
+		function = "SPI2";
 		groups = "QSPI2";
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-sama5d27_som1.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-sama5d27_som1.dtsi
@@ -44,8 +44,8 @@
 				pinctrl-0 = <&pinctrl_macb0_default>;
 				phy-mode = "rmii";
 
-				ethernet-phy@0 {
-					reg = <0x0>;
+				ethernet-phy@7 {
+					reg = <0x7>;
 					interrupt-parent = <&pioA>;
 					interrupts = <PIN_PD31 IRQ_TYPE_LEVEL_LOW>;
 					pinctrl-names = "default";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts
@@ -69,7 +69,6 @@
 			isc: isc@f0008000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>;
-				status = "okay";
 			};
 
 			qspi1: spi@f0024000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
@@ -40,7 +40,7 @@
 
 	ahb {
 		usb0: gadget@300000 {
-			atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>;
+			atmel,vbus-gpio = <&pioA PIN_PB11 GPIO_ACTIVE_HIGH>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usba_vbus>;
 			status = "okay";
@@ -125,8 +125,6 @@
 			bus-width = <8>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_sdmmc0_default>;
-			non-removable;
-			mmc-ddr-1_8v;
 			status = "okay";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-sama5d3_xplained.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -242,6 +242,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>;
+					};
 				};
 			};
 		};
@@ -259,6 +264,8 @@
 					   &pioE 3 GPIO_ACTIVE_LOW
 					   &pioE 4 GPIO_ACTIVE_LOW
 					  >;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb_default>;
 			status = "okay";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -133,6 +133,11 @@
 						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>;
@@ -158,6 +163,8 @@
 					   &pioE 11 GPIO_ACTIVE_HIGH
 					   &pioE 14 GPIO_ACTIVE_HIGH
 					  >;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb_default>;
 			status = "okay";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91-tse850-3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91-tse850-3.dts
@@ -262,7 +262,7 @@
 &macb1 {
 	status = "okay";
 
-	phy-mode = "rgmii";
+	phy-mode = "rmii";
 
 	#address-cells = <1>;
 	#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9260.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9260.dtsi
@@ -187,7 +187,7 @@
 				usart0 {
 					pinctrl_usart0: usart0-0 {
 						atmel,pins =
-							<AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -221,7 +221,7 @@
 				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
-							<AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -239,7 +239,7 @@
 				usart2 {
 					pinctrl_usart2: usart2-0 {
 						atmel,pins =
-							<AT91_PIOB 8 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 8 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -257,7 +257,7 @@
 				usart3 {
 					pinctrl_usart3: usart3-0 {
 						atmel,pins =
-							<AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 11 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -275,7 +275,7 @@
 				uart0 {
 					pinctrl_uart0: uart0-0 {
 						atmel,pins =
-							<AT91_PIOA 31 AT91_PERIPH_B AT91_PINCTRL_NONE
+							<AT91_PIOA 31 AT91_PERIPH_B AT91_PINCTRL_PULL_UP
 							 AT91_PIOA 30 AT91_PERIPH_B AT91_PINCTRL_PULL_UP>;
 					};
 				};
@@ -283,7 +283,7 @@
 				uart1 {
 					pinctrl_uart1: uart1-0 {
 						atmel,pins =
-							<AT91_PIOB 12 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 12 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 13 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 				};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9261.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9261.dtsi
@@ -329,7 +329,7 @@
 				usart0 {
 					pinctrl_usart0: usart0-0 {
 						atmel,pins =
-							<AT91_PIOC 8 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOC 8 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOC 9 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -347,7 +347,7 @@
 				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
-							<AT91_PIOC 12 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOC 12 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOC 13 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -365,7 +365,7 @@
 				usart2 {
 					pinctrl_usart2: usart2-0 {
 						atmel,pins =
-							<AT91_PIOC 14 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOC 14 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOC 15 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9261ek.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9261ek.dts
@@ -156,7 +156,7 @@
 					compatible = "ti,ads7843";
 					interrupts-extended = <&pioC 2 IRQ_TYPE_EDGE_BOTH>;
 					spi-max-frequency = <3000000>;
-					pendown-gpio = <&pioC 2 GPIO_ACTIVE_HIGH>;
+					pendown-gpio = <&pioC 2 GPIO_ACTIVE_LOW>;
 
 					ti,x-min = /bits/ 16 <150>;
 					ti,x-max = /bits/ 16 <3830>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9263.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9263.dtsi
@@ -183,7 +183,7 @@
 				usart0 {
 					pinctrl_usart0: usart0-0 {
 						atmel,pins =
-							<AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOA 26 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOA 27 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -201,7 +201,7 @@
 				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
-							<AT91_PIOD 0 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOD 0 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOD 1 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -219,7 +219,7 @@
 				usart2 {
 					pinctrl_usart2: usart2-0 {
 						atmel,pins =
-							<AT91_PIOD 2 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOD 2 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOD 3 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -38,6 +38,13 @@
 
 				};
 
+				usb1 {
+					pinctrl_usb1_vbus_gpio: usb1_vbus_gpio {
+						atmel,pins =
+							<AT91_PIOC 5 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;	/* PC5 GPIO */
+					};
+				};
+
 				mmc0_slot1 {
 					pinctrl_board_mmc0_slot1: mmc0_slot1-board {
 						atmel,pins =
@@ -83,6 +90,8 @@
 			};
 
 			usb1: gadget@fffa4000 {
+				pinctrl-0 = <&pinctrl_usb1_vbus_gpio>;
+				pinctrl-names = "default";
 				atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>;
 				status = "okay";
 			};
@@ -217,6 +226,12 @@
 		wm8731: wm8731@1b {
 			compatible = "wm8731";
 			reg = <0x1b>;
+
+			/* PCK0 at 12MHz */
+			clocks = <&pmc PMC_TYPE_SYSTEM 8>;
+			clock-names = "mclk";
+			assigned-clocks = <&pmc PMC_TYPE_SYSTEM 8>;
+			assigned-clock-rates = <12000000>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9g45.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -556,7 +556,7 @@
 				usart0 {
 					pinctrl_usart0: usart0-0 {
 						atmel,pins =
-							<AT91_PIOB 19 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 19 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 18 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -574,7 +574,7 @@
 				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
-							<AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 4 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -592,7 +592,7 @@
 				usart2 {
 					pinctrl_usart2: usart2-0 {
 						atmel,pins =
-							<AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -610,7 +610,7 @@
 				usart3 {
 					pinctrl_usart3: usart3-0 {
 						atmel,pins =
-							<AT91_PIOB 8 AT91_PERIPH_A AT91_PINCTRL_NONE
+							<AT91_PIOB 8 AT91_PERIPH_A AT91_PINCTRL_PULL_UP
 							 AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/at91sam9rl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -278,23 +278,26 @@
 				atmel,adc-use-res = "highres";
 
 				trigger0 {
-					trigger-name = "timer-counter-0";
+					trigger-name = "external-rising";
 					trigger-value = <0x1>;
+					trigger-external;
 				};
+
 				trigger1 {
-					trigger-name = "timer-counter-1";
-					trigger-value = <0x3>;
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
 				};
 
 				trigger2 {
-					trigger-name = "timer-counter-2";
-					trigger-value = <0x5>;
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
 				};
 
 				trigger3 {
-					trigger-name = "external";
-					trigger-value = <0x13>;
-					trigger-external;
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
 				};
 			};
 
@@ -682,7 +685,7 @@
 				usart0 {
 					pinctrl_usart0: usart0-0 {
 						atmel,pins =
-							<AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOA 6 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOA 7 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -721,7 +724,7 @@
 				usart1 {
 					pinctrl_usart1: usart1-0 {
 						atmel,pins =
-							<AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOA 11 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOA 12 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -744,7 +747,7 @@
 				usart2 {
 					pinctrl_usart2: usart2-0 {
 						atmel,pins =
-							<AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
@@ -767,7 +770,7 @@
 				usart3 {
 					pinctrl_usart3: usart3-0 {
 						atmel,pins =
-							<AT91_PIOB 0 AT91_PERIPH_A AT91_PINCTRL_NONE>,
+							<AT91_PIOB 0 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>,
 							<AT91_PIOB 1 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>;
 					};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -174,8 +174,8 @@
 		mdio: mdio@18002000 {
 			compatible = "brcm,iproc-mdio";
 			reg = <0x18002000 0x8>;
-			#size-cells = <1>;
-			#address-cells = <0>;
+			#size-cells = <0>;
+			#address-cells = <1>;
 			status = "disabled";
 
 			gphy0: ethernet-phy@0 {
@@ -460,7 +460,7 @@
 			status = "disabled";
 		};
 
-		nand: nand@18046000 {
+		nand_controller: nand-controller@18046000 {
 			compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
 			reg = <0x18046000 0x600>, <0xf8105408 0x600>,
 			      <0x18046f00 0x20>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm-hr2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm-hr2.dtsi
@@ -75,7 +75,7 @@
 		timer@20200 {
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0x20200 0x100>;
-			interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
 			clocks = <&periph_clk>;
 		};
 
@@ -83,7 +83,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x20600 0x20>;
 			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_HIGH)>;
+						  IRQ_TYPE_EDGE_RISING)>;
 			clocks = <&periph_clk>;
 		};
 
@@ -91,7 +91,7 @@
 			compatible = "arm,cortex-a9-twd-wdt";
 			reg = <0x20620 0x20>;
 			interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_HIGH)>;
+						  IRQ_TYPE_EDGE_RISING)>;
 			clocks = <&periph_clk>;
 		};
 
@@ -179,7 +179,7 @@
 			status = "disabled";
 		};
 
-		nand: nand@26000 {
+		nand_controller: nand-controller@26000 {
 			compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
 			reg = <0x26000 0x600>,
 			      <0x11b408 0x600>,
@@ -217,7 +217,7 @@
 		};
 
 		qspi: spi@27200 {
-			compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+			compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
 			reg = <0x027200 0x184>,
 			      <0x027000 0x124>,
 			      <0x11c408 0x004>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm-nsp.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -77,7 +77,7 @@
 		interrupt-affinity = <&cpu0>, <&cpu1>;
 	};
 
-	mpcore@19000000 {
+	mpcore-bus@19000000 {
 		compatible = "simple-bus";
 		ranges = <0x00000000 0x19000000 0x00023000>;
 		#address-cells = <1>;
@@ -217,7 +217,7 @@
 			#dma-cells = <1>;
 		};
 
-		sdio: sdhci@21000 {
+		sdio: mmc@21000 {
 			compatible = "brcm,sdhci-iproc-cygnus";
 			reg = <0x21000 0x100>;
 			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
@@ -257,17 +257,17 @@
 			status = "disabled";
 		};
 
-		mailbox: mailbox@25000 {
+		mailbox: mailbox@25c00 {
 			compatible = "brcm,iproc-fa2-mbox";
-			reg = <0x25000 0x445>;
-			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x25c00 0x400>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
 			#mbox-cells = <1>;
 			brcm,rx-status-len = <32>;
 			brcm,use-bcm-hdr;
 			dma-coherent;
 		};
 
-		nand: nand@26000 {
+		nand_controller: nand-controller@26000 {
 			compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
 			reg = <0x026000 0x600>,
 			      <0x11b408 0x600>,
@@ -282,7 +282,7 @@
 		};
 
 		qspi: spi@27200 {
-			compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+			compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
 			reg = <0x027200 0x184>,
 			      <0x027000 0x124>,
 			      <0x11c408 0x004>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -53,18 +53,17 @@
 			  "GPIO18",
 			  "NC", /* GPIO19 */
 			  "NC", /* GPIO20 */
-			  "GPIO21",
+			  "CAM_GPIO0",
 			  "GPIO22",
 			  "GPIO23",
 			  "GPIO24",
 			  "GPIO25",
 			  "NC", /* GPIO26 */
-			  "CAM_GPIO0",
-			  /* Binary number representing build/revision */
-			  "CONFIG0",
-			  "CONFIG1",
-			  "CONFIG2",
-			  "CONFIG3",
+			  "GPIO27",
+			  "GPIO28",
+			  "GPIO29",
+			  "GPIO30",
+			  "GPIO31",
 			  "NC", /* GPIO32 */
 			  "NC", /* GPIO33 */
 			  "NC", /* GPIO34 */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
@@ -24,7 +24,7 @@
 
 	leds {
 		act {
-			gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+			gpios = <&gpio 47 GPIO_ACTIVE_LOW>;
 		};
 	};
 
@@ -74,16 +74,18 @@
 			  "GPIO27",
 			  "SDA0",
 			  "SCL0",
-			  "NC", /* GPIO30 */
-			  "NC", /* GPIO31 */
-			  "NC", /* GPIO32 */
-			  "NC", /* GPIO33 */
-			  "NC", /* GPIO34 */
-			  "NC", /* GPIO35 */
-			  "NC", /* GPIO36 */
-			  "NC", /* GPIO37 */
-			  "NC", /* GPIO38 */
-			  "NC", /* GPIO39 */
+			  /* Used by BT module */
+			  "CTS0",
+			  "RTS0",
+			  "TXD0",
+			  "RXD0",
+			  /* Used by Wifi */
+			  "SD1_CLK",
+			  "SD1_CMD",
+			  "SD1_DATA0",
+			  "SD1_DATA1",
+			  "SD1_DATA2",
+			  "SD1_DATA3",
 			  "CAM_GPIO1", /* GPIO40 */
 			  "WL_ON", /* GPIO41 */
 			  "NC", /* GPIO42 */
@@ -112,6 +114,7 @@
 &sdhci {
 	#address-cells = <1>;
 	#size-cells = <0>;
+	pinctrl-names = "default";
 	pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
 	bus-width = <4>;
 	mmc-pwrseq = <&wifi_pwrseq>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
@@ -43,7 +43,7 @@
 		#gpio-cells = <2>;
 		gpio-line-names = "BT_ON",
 				  "WL_ON",
-				  "STATUS_LED_R",
+				  "PWR_LED_R",
 				  "LAN_RUN",
 				  "",
 				  "CAM_GPIO0",
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm2837-rpi-cm3-io3.dts
@@ -63,8 +63,8 @@
 			  "GPIO43",
 			  "GPIO44",
 			  "GPIO45",
-			  "GPIO46",
-			  "GPIO47",
+			  "SMPS_SCL",
+			  "SMPS_SDA",
 			  /* Used by eMMC */
 			  "SD_CLK_R",
 			  "SD_CMD_R",
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm2837.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm2837.dtsi
@@ -38,12 +38,26 @@
 		#size-cells = <0>;
 		enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
 
+		/* Source for d/i-cache-line-size and d/i-cache-sets
+		 * https://developer.arm.com/documentation/ddi0500/e/level-1-memory-system
+		 * /about-the-l1-memory-system?lang=en
+		 *
+		 * Source for d/i-cache-size
+		 * https://magpi.raspberrypi.com/articles/raspberry-pi-3-specs-benchmarks
+		 */
 		cpu0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53";
 			reg = <0>;
 			enable-method = "spin-table";
 			cpu-release-addr = <0x0 0x000000d8>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set
+			next-level-cache = <&l2>;
 		};
 
 		cpu1: cpu@1 {
@@ -52,6 +66,13 @@
 			reg = <1>;
 			enable-method = "spin-table";
 			cpu-release-addr = <0x0 0x000000e0>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set
+			next-level-cache = <&l2>;
 		};
 
 		cpu2: cpu@2 {
@@ -60,6 +81,13 @@
 			reg = <2>;
 			enable-method = "spin-table";
 			cpu-release-addr = <0x0 0x000000e8>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set
+			next-level-cache = <&l2>;
 		};
 
 		cpu3: cpu@3 {
@@ -68,6 +96,27 @@
 			reg = <3>;
 			enable-method = "spin-table";
 			cpu-release-addr = <0x0 0x000000f0>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set
+			next-level-cache = <&l2>;
+		};
+
+		/* Source for cache-line-size + cache-sets
+		 * https://developer.arm.com/documentation/ddi0500
+		 * /e/level-2-memory-system/about-the-l2-memory-system?lang=en
+		 * Source for cache-size
+		 * https://datasheets.raspberrypi.com/cm/cm1-and-cm3-datasheet.pdf
+		 */
+		l2: l2-cache0 {
+			compatible = "cache";
+			cache-size = <0x80000>;
+			cache-line-size = <64>;
+			cache-sets = <512>; // 512KiB(size)/64(line-size)=8192ways/16-way set
+			cache-level = <2>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm283x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm283x.dtsi
@@ -40,7 +40,7 @@
 
 			trips {
 				cpu-crit {
-					temperature	= <80000>;
+					temperature	= <90000>;
 					hysteresis	= <0>;
 					type		= "critical";
 				};
@@ -183,6 +183,7 @@
 
 			interrupt-controller;
 			#interrupt-cells = <2>;
+			gpio-ranges = <&gpio 0 0 54>;
 
 			/* Defines pin muxing groups according to
 			 * BCM2835-ARM-Peripherals.pdf page 102.
@@ -488,6 +489,7 @@
 					     "dsi0_ddr2",
 					     "dsi0_ddr";
 
+			status = "disabled";
 		};
 
 		thermal: thermal@7e212000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm4708-linksys-ea6500-v2.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm4708-linksys-ea6500-v2.dts
@@ -19,7 +19,8 @@
 
 	memory@0 {
 		device_type = "memory";
-		reg = <0x00000000 0x08000000>;
+		reg = <0x00000000 0x08000000>,
+		      <0x88000000 0x08000000>;
 	};
 
 	gpio-keys {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
@@ -26,7 +26,6 @@
 		wlan {
 			label = "bcm53xx:blue:wlan";
 			gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
-			linux,default-trigger = "default-off";
 		};
 
 		system {
@@ -46,3 +45,16 @@
 		};
 	};
 };
+
+&gmac0 {
+	phy-mode = "rgmii";
+	phy-handle = <&bcm54210e>;
+
+	mdio {
+		/delete-node/ switch@1e;
+
+		bcm54210e: ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
@@ -26,7 +26,6 @@
 		5ghz {
 			label = "bcm53xx:blue:5ghz";
 			gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "default-off";
 		};
 
 		system {
@@ -42,7 +41,6 @@
 		2ghz {
 			label = "bcm53xx:blue:2ghz";
 			gpios = <&pcie0_chipcommon 3 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "default-off";
 		};
 	};
 
@@ -83,3 +81,16 @@
 		};
 	};
 };
+
+&gmac0 {
+	phy-mode = "rgmii";
+	phy-handle = <&bcm54210e>;
+
+	mdio {
+		/delete-node/ switch@1e;
+
+		bcm54210e: ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm5301x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm5301x.dtsi
@@ -242,6 +242,8 @@
 
 			gpio-controller;
 			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 		};
 
 		pcie0: pcie@12000 {
@@ -353,8 +355,8 @@
 	mdio: mdio@18003000 {
 		compatible = "brcm,iproc-mdio";
 		reg = <0x18003000 0x8>;
-		#size-cells = <1>;
-		#address-cells = <0>;
+		#size-cells = <0>;
+		#address-cells = <1>;
 	};
 
 	mdio-bus-mux@18003000 {
@@ -387,7 +389,7 @@
 	i2c0: i2c@18009000 {
 		compatible = "brcm,iproc-i2c";
 		reg = <0x18009000 0x50>;
-		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		clock-frequency = <100000>;
@@ -488,33 +490,32 @@
 	};
 
 	spi@18029200 {
-		compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+		compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
 		reg = <0x18029200 0x184>,
 		      <0x18029000 0x124>,
 		      <0x1811b408 0x004>,
 		      <0x180293a0 0x01c>;
 		reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg";
-		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "spi_lr_fullness_reached",
+			     <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "mspi_done",
+				  "mspi_halted",
+				  "spi_lr_fullness_reached",
 				  "spi_lr_session_aborted",
 				  "spi_lr_impatient",
 				  "spi_lr_session_done",
-				  "spi_lr_overhead",
-				  "mspi_done",
-				  "mspi_halted";
+				  "spi_lr_overread";
 		clocks = <&iprocmed>;
-		clock-names = "iprocmed";
 		num-cs = <2>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		spi_nor: spi-nor@0 {
+		spi_nor: flash@0 {
 			compatible = "jedec,spi-nor";
 			reg = <0>;
 			spi-max-frequency = <20000000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm53573.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm53573.dtsi
@@ -127,6 +127,9 @@
 
 		pcie0: pcie@2000 {
 			reg = <0x00002000 0x1000>;
+
+			#address-cells = <3>;
+			#size-cells = <2>;
 		};
 
 		usb2: usb2@4000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm63138.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm63138.dtsi
@@ -203,7 +203,7 @@
 			status = "disabled";
 		};
 
-		nand: nand@2000 {
+		nand_controller: nand-controller@2000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.0", "brcm,brcmnand";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
@@ -14,10 +14,10 @@
 	};
 };
 
-&nand {
+&nand_controller {
 	status = "okay";
 
-	nandcs@1 {
+	nand@1 {
 		compatible = "brcm,nandcs";
 		reg = <1>;
 		nand-ecc-step-size = <512>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm7445.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm7445.dtsi
@@ -148,7 +148,7 @@
 			reg-names = "aon-ctrl", "aon-sram";
 		};
 
-		nand: nand@3e2800 {
+		nand_controller: nand-controller@3e2800 {
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm911360_entphn.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -82,8 +82,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@1 {
+&nand_controller {
+	nand@1 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm947189acdbmr.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm947189acdbmr.dts
@@ -60,9 +60,9 @@
 	spi {
 		compatible = "spi-gpio";
 		num-chipselects = <1>;
-		gpio-sck = <&chipcommon 21 0>;
-		gpio-miso = <&chipcommon 22 0>;
-		gpio-mosi = <&chipcommon 23 0>;
+		sck-gpios = <&chipcommon 21 0>;
+		miso-gpios = <&chipcommon 22 0>;
+		mosi-gpios = <&chipcommon 23 0>;
 		cs-gpios = <&chipcommon 24 0>;
 		#address-cells = <1>;
 		#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958300k.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958300k.dts
@@ -60,8 +60,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@1 {
+&nand_controller {
+	nand@1 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958305k.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958305k.dts
@@ -68,8 +68,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@1 {
+&nand_controller {
+	nand@1 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958522er.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958522er.dts
@@ -70,8 +70,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958525er.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958525er.dts
@@ -70,8 +70,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958525xmc.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958525xmc.dts
@@ -86,8 +86,8 @@
 	};
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958622hr.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958622hr.dts
@@ -74,8 +74,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958623hr.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958623hr.dts
@@ -74,8 +74,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958625hr.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958625hr.dts
@@ -90,8 +90,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm958625k.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm958625k.dts
@@ -64,8 +64,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm963138dvt.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm963138dvt.dts
@@ -31,10 +31,10 @@
 	status = "okay";
 };
 
-&nand {
+&nand_controller {
 	status = "okay";
 
-	nandcs@0 {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-ecc-strength = <4>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/bcm988312hr.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/bcm988312hr.dts
@@ -74,8 +74,8 @@
 	status = "okay";
 };
 
-&nand {
-	nandcs@0 {
+&nand_controller {
+	nand@0 {
 		compatible = "brcm,nandcs";
 		reg = <0>;
 		nand-on-flash-bbt;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dm8148-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/dm8148-evm.dts
@@ -24,12 +24,12 @@
 
 &cpsw_emac0 {
 	phy-handle = <&ethphy0>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
 	phy-handle = <&ethphy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dm8148-t410.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/dm8148-t410.dts
@@ -33,12 +33,12 @@
 
 &cpsw_emac0 {
 	phy-handle = <&ethphy0>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
 	phy-handle = <&ethphy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dove.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/dove.dtsi
@@ -129,7 +129,7 @@
 			pcie1: pcie@2 {
 				device_type = "pci";
 				status = "disabled";
-				assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
+				assigned-addresses = <0x82001000 0 0x80000 0 0x2000>;
 				reg = <0x1000 0 0 0 0>;
 				clocks = <&gate_clk 5>;
 				marvell,pcie-port = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dra62x-j5eco-evm.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/dra62x-j5eco-evm.dts
@@ -24,12 +24,12 @@
 
 &cpsw_emac0 {
 	phy-handle = <&ethphy0>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
 	phy-handle = <&ethphy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dra7-l4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/dra7-l4.dtsi
@@ -1176,7 +1176,7 @@
 			};
 		};
 
-		target-module@34000 {			/* 0x48034000, ap 7 46.0 */
+		timer3_target: target-module@34000 {	/* 0x48034000, ap 7 46.0 */
 			compatible = "ti,sysc-omap4-timer", "ti,sysc";
 			ti,hwmods = "timer3";
 			reg = <0x34000 0x4>,
@@ -1204,7 +1204,7 @@
 			};
 		};
 
-		target-module@36000 {			/* 0x48036000, ap 9 4e.0 */
+		timer4_target: target-module@36000 {	/* 0x48036000, ap 9 4e.0 */
 			compatible = "ti,sysc-omap4-timer", "ti,sysc";
 			ti,hwmods = "timer4";
 			reg = <0x36000 0x4>,
@@ -1326,7 +1326,7 @@
 			};
 		};
 
-		target-module@55000 {			/* 0x48055000, ap 13 0e.0 */
+		gpio2_target: target-module@55000 {		/* 0x48055000, ap 13 0e.0 */
 			compatible = "ti,sysc-omap2", "ti,sysc";
 			reg = <0x55000 0x4>,
 			      <0x55010 0x4>,
@@ -1359,7 +1359,7 @@
 			};
 		};
 
-		target-module@57000 {			/* 0x48057000, ap 15 06.0 */
+		gpio3_target: target-module@57000 {		/* 0x48057000, ap 15 06.0 */
 			compatible = "ti,sysc-omap2", "ti,sysc";
 			reg = <0x57000 0x4>,
 			      <0x57010 0x4>,
@@ -3059,7 +3059,7 @@
 
 				davinci_mdio: mdio@1000 {
 					compatible = "ti,cpsw-mdio","ti,davinci_mdio";
-					clocks = <&gmac_clkctrl DRA7_GMAC_GMAC_CLKCTRL 0>;
+					clocks = <&gmac_main_clk>;
 					clock-names = "fck";
 					#address-cells = <1>;
 					#size-cells = <0>;
@@ -3413,6 +3413,7 @@
 				clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER13_CLKCTRL 24>;
 				clock-names = "fck";
 				interrupts = <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>;
+				ti,timer-pwm;
 			};
 		};
 
@@ -3441,6 +3442,7 @@
 				clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER14_CLKCTRL 24>;
 				clock-names = "fck";
 				interrupts = <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>;
+				ti,timer-pwm;
 			};
 		};
 
@@ -3469,6 +3471,7 @@
 				clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER15_CLKCTRL 24>;
 				clock-names = "fck";
 				interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
+				ti,timer-pwm;
 			};
 		};
 
@@ -3497,6 +3500,7 @@
 				clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER16_CLKCTRL 24>;
 				clock-names = "fck";
 				interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>;
+				ti,timer-pwm;
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dra7.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/dra7.dtsi
@@ -46,6 +46,7 @@
 
 	timer {
 		compatible = "arm,armv7-timer";
+		status = "disabled";	/* See ARM architected timer wrap erratum i940 */
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
@@ -148,6 +149,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0x0 0x0 0xc0000000>;
+		dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>;
 		ti,hwmods = "l3_main_1", "l3_main_2";
 		reg = <0x0 0x44000000 0x0 0x1000000>,
 		      <0x0 0x45000000 0x0 0x1000>;
@@ -171,6 +173,7 @@
 			#address-cells = <1>;
 			ranges = <0x51000000 0x51000000 0x3000
 				  0x0	     0x20000000 0x10000000>;
+			dma-ranges;
 			/**
 			 * To enable PCI endpoint mode, disable the pcie1_rc
 			 * node and enable pcie1_ep mode.
@@ -228,6 +231,7 @@
 			#address-cells = <1>;
 			ranges = <0x51800000 0x51800000 0x3000
 				  0x0	     0x30000000 0x10000000>;
+			dma-ranges;
 			status = "disabled";
 			pcie2_rc: pcie@51800000 {
 				reg = <0x51800000 0x2000>, <0x51802000 0x14c>, <0x1000 0x2000>;
@@ -763,3 +767,22 @@
 
 #include "dra7-l4.dtsi"
 #include "dra7xx-clocks.dtsi"
+
+/* Local timers, see ARM architected timer wrap erratum i940 */
+&timer3_target {
+	ti,no-reset-on-init;
+	ti,no-idle;
+	timer@0 {
+		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>;
+		assigned-clock-parents = <&timer_sys_clk_div>;
+	};
+};
+
+&timer4_target {
+	ti,no-reset-on-init;
+	ti,no-idle;
+	timer@0 {
+		assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>;
+		assigned-clock-parents = <&timer_sys_clk_div>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dra76x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/dra76x.dtsi
@@ -32,8 +32,8 @@
 				interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "int0", "int1";
-				clocks = <&mcan_clk>, <&l3_iclk_div>;
-				clock-names = "cclk", "hclk";
+				clocks = <&l3_iclk_div>, <&mcan_clk>;
+				clock-names = "hclk", "cclk";
 				bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>;
 			};
 		};
@@ -86,3 +86,8 @@
 &usb4_tm {
 	status = "disabled";
 };
+
+&mmc3 {
+	/* dra76x is not affected by i887 */
+	max-frequency = <96000000>;
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/dra7xx-clocks.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/dra7xx-clocks.dtsi
@@ -796,16 +796,6 @@
 		clock-div = <1>;
 	};
 
-	ipu1_gfclk_mux: ipu1_gfclk_mux@520 {
-		#clock-cells = <0>;
-		compatible = "ti,mux-clock";
-		clocks = <&dpll_abe_m2x2_ck>, <&dpll_core_h22x2_ck>;
-		ti,bit-shift = <24>;
-		reg = <0x0520>;
-		assigned-clocks = <&ipu1_gfclk_mux>;
-		assigned-clock-parents = <&dpll_core_h22x2_ck>;
-	};
-
 	dummy_ck: dummy_ck {
 		#clock-cells = <0>;
 		compatible = "fixed-clock";
@@ -1564,6 +1554,8 @@
 			compatible = "ti,clkctrl";
 			reg = <0x20 0x4>;
 			#clock-cells = <2>;
+			assigned-clocks = <&ipu1_clkctrl DRA7_IPU1_MMU_IPU1_CLKCTRL 24>;
+			assigned-clock-parents = <&dpll_core_h22x2_ck>;
 		};
 
 		ipu_clkctrl: ipu-clkctrl@50 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos3250-artik5.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos3250-artik5.dtsi
@@ -75,7 +75,7 @@
 	s2mps14_pmic@66 {
 		compatible = "samsung,s2mps14-pmic";
 		interrupt-parent = <&gpx3>;
-		interrupts = <5 IRQ_TYPE_NONE>;
+		interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&s2mps14_irq>;
 		reg = <0x66>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos3250-monk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos3250-monk.dts
@@ -195,7 +195,7 @@
 	s2mps14_pmic@66 {
 		compatible = "samsung,s2mps14-pmic";
 		interrupt-parent = <&gpx0>;
-		interrupts = <7 IRQ_TYPE_NONE>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
 		reg = <0x66>;
 		wakeup-source;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos3250-rinato.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -239,7 +239,7 @@
 	i80-if-timings {
 		cs-setup = <0>;
 		wr-setup = <0>;
-		wr-act = <1>;
+		wr-active = <1>;
 		wr-hold = <0>;
 	};
 };
@@ -260,7 +260,7 @@
 	s2mps14_pmic@66 {
 		compatible = "samsung,s2mps14-pmic";
 		interrupt-parent = <&gpx0>;
-		interrupts = <7 IRQ_TYPE_NONE>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
 		reg = <0x66>;
 		wakeup-source;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi
@@ -10,7 +10,7 @@
 / {
 thermal-zones {
 	cpu_thermal: cpu-thermal {
-		thermal-sensors = <&tmu 0>;
+		thermal-sensors = <&tmu>;
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
 		trips {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4.dtsi
@@ -605,7 +605,7 @@
 			status = "disabled";
 
 			hdmi_i2c_phy: hdmiphy@38 {
-				compatible = "exynos4210-hdmiphy";
+				compatible = "samsung,exynos4210-hdmiphy";
 				reg = <0x38>;
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -115,7 +115,7 @@
 		gpio-sck = <&gpy3 1 GPIO_ACTIVE_HIGH>;
 		gpio-mosi = <&gpy3 3 GPIO_ACTIVE_HIGH>;
 		num-chipselects = <1>;
-		cs-gpios = <&gpy4 3 GPIO_ACTIVE_HIGH>;
+		cs-gpios = <&gpy4 3 GPIO_ACTIVE_LOW>;
 
 		lcd@0 {
 			compatible = "samsung,ld9040";
@@ -124,8 +124,6 @@
 			vci-supply = <&ldo17_reg>;
 			reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
 			spi-max-frequency = <1200000>;
-			spi-cpol;
-			spi-cpha;
 			power-on-delay = <10>;
 			reset-delay = <10>;
 			panel-width-mm = <90>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
@@ -68,7 +68,7 @@
 
 	i2c_cm36651: i2c-gpio-2 {
 		compatible = "i2c-gpio";
-		gpios = <&gpf0 0 GPIO_ACTIVE_LOW>, <&gpf0 1 GPIO_ACTIVE_LOW>;
+		gpios = <&gpf0 0 GPIO_ACTIVE_HIGH>, <&gpf0 1 GPIO_ACTIVE_HIGH>;
 		i2c-gpio,delay-us = <2>;
 		#address-cells = <1>;
 		#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4412-itop-elite.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4412-itop-elite.dts
@@ -179,7 +179,7 @@
 		compatible = "wlf,wm8960";
 		reg = <0x1a>;
 		clocks = <&pmu_system_controller 0>;
-		clock-names = "MCLK1";
+		clock-names = "mclk";
 		wlf,shared-lrclk;
 		#sound-dai-cells = <0>;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4412-midas.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4412-midas.dtsi
@@ -139,7 +139,7 @@
 		max77693@66 {
 			compatible = "maxim,max77693";
 			interrupt-parent = <&gpx1>;
-			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&max77693_irq>;
 			reg = <0x66>;
@@ -187,7 +187,7 @@
 		max77693-fuel-gauge@36 {
 			compatible = "maxim,max17047";
 			interrupt-parent = <&gpx2>;
-			interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+			interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&max77693_fuel_irq>;
 			reg = <0x36>;
@@ -534,7 +534,7 @@
 		clocks = <&camera 1>;
 		clock-names = "extclk";
 		samsung,camclk-out = <1>;
-		gpios = <&gpm1 6 GPIO_ACTIVE_HIGH>;
+		gpios = <&gpm1 6 GPIO_ACTIVE_LOW>;
 
 		port {
 			is_s5k6a3_ep: endpoint {
@@ -588,7 +588,7 @@
 	max77686: max77686_pmic@9 {
 		compatible = "maxim,max77686";
 		interrupt-parent = <&gpx0>;
-		interrupts = <7 IRQ_TYPE_NONE>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-0 = <&max77686_irq>;
 		pinctrl-names = "default";
 		reg = <0x09>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -274,7 +274,7 @@
 	max77686: pmic@9 {
 		compatible = "maxim,max77686";
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_NONE>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&max77686_irq>;
 		reg = <0x09>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos4412-origen.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos4412-origen.dts
@@ -86,7 +86,7 @@
 };
 
 &ehci {
-	samsung,vbus-gpio = <&gpx3 5 1>;
+	samsung,vbus-gpio = <&gpx3 5 GPIO_ACTIVE_HIGH>;
 	status = "okay";
 	phys = <&exynos_usbphy 2>, <&exynos_usbphy 3>;
 	phy-names = "hsic0", "hsic1";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5250-pinctrl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5250-pinctrl.dtsi
@@ -260,7 +260,7 @@
 	};
 
 	uart3_data: uart3-data {
-		samsung,pins = "gpa1-4", "gpa1-4";
+		samsung,pins = "gpa1-4", "gpa1-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
 		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -117,6 +117,9 @@
 	status = "okay";
 	ddc = <&i2c_2>;
 	hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+	vdd-supply = <&ldo8_reg>;
+	vdd_osc-supply = <&ldo10_reg>;
+	vdd_pll-supply = <&ldo8_reg>;
 };
 
 &i2c_0 {
@@ -125,7 +128,7 @@
 	samsung,i2c-max-bus-freq = <20000>;
 
 	eeprom@50 {
-		compatible = "samsung,s524ad0xd1";
+		compatible = "samsung,s524ad0xd1", "atmel,24c128";
 		reg = <0x50>;
 	};
 
@@ -133,7 +136,7 @@
 		compatible = "maxim,max77686";
 		reg = <0x09>;
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_NONE>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&max77686_irq>;
 		wakeup-source;
@@ -284,7 +287,7 @@
 	samsung,i2c-max-bus-freq = <20000>;
 
 	eeprom@51 {
-		compatible = "samsung,s524ad0xd1";
+		compatible = "samsung,s524ad0xd1", "atmel,24c128";
 		reg = <0x51>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5250-snow-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5250-snow-common.dtsi
@@ -292,7 +292,7 @@
 	max77686: max77686@9 {
 		compatible = "maxim,max77686";
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_NONE>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&max77686_irq>;
 		wakeup-source;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5250-spring.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5250-spring.dts
@@ -108,7 +108,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-ein-5.4.0.orig/arch/arm/boot/dts/exynos5410-odroidxu.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5410-odroidxu.dts
@@ -116,7 +116,6 @@
 };
 
 &cpu0_thermal {
-	thermal-sensors = <&tmu_cpu0 0>;
 	polling-delay-passive = <0>;
 	polling-delay = <0>;
 
@@ -327,6 +326,8 @@
 				regulator-name = "vddq_lcd";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
+				/* Supplies also GPK and GPJ */
+				regulator-always-on;
 			};
 
 			ldo8_reg: LDO8 {
@@ -637,11 +638,11 @@
 };
 
 &usbdrd_dwc3_0 {
-	dr_mode = "host";
+	dr_mode = "peripheral";
 };
 
 &usbdrd_dwc3_1 {
-	dr_mode = "peripheral";
+	dr_mode = "host";
 };
 
 &usbdrd3_0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5410-pinctrl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5410-pinctrl.dtsi
@@ -560,6 +560,34 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
+
+	usb3_1_oc: usb3-1-oc {
+		samsung,pins = "gpk2-4", "gpk2-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
+	};
+
+	usb3_1_vbusctrl: usb3-1-vbusctrl {
+		samsung,pins = "gpk2-6", "gpk2-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
+	};
+
+	usb3_0_oc: usb3-0-oc {
+		samsung,pins = "gpk3-0", "gpk3-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
+	};
+
+	usb3_0_vbusctrl: usb3-0-vbusctrl {
+		samsung,pins = "gpk3-2", "gpk3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
+	};
 };
 
 &pinctrl_2 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5410.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5410.dtsi
@@ -398,6 +398,8 @@
 &usbdrd3_0 {
 	clocks = <&clock CLK_USBD300>;
 	clock-names = "usbdrd30";
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb3_0_oc>, <&usb3_0_vbusctrl>;
 };
 
 &usbdrd_phy0 {
@@ -409,6 +411,8 @@
 &usbdrd3_1 {
 	clocks = <&clock CLK_USBD301>;
 	clock-names = "usbdrd30";
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb3_1_oc>, <&usb3_1_vbusctrl>;
 };
 
 &usbdrd_dwc3_1 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -349,7 +349,7 @@
 		reg = <0x66>;
 
 		interrupt-parent = <&gpx3>;
-		interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&s2mps11_irq>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -132,6 +132,9 @@
 	hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&hdmi_hpd_irq>;
+	vdd-supply = <&ldo6_reg>;
+	vdd_osc-supply = <&ldo7_reg>;
+	vdd_pll-supply = <&ldo6_reg>;
 };
 
 &hsi2c_4 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5420.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5420.dtsi
@@ -539,7 +539,7 @@
 		};
 
 		mipi_phy: mipi-video-phy {
-			compatible = "samsung,s5pv210-mipi-video-phy";
+			compatible = "samsung,exynos5420-mipi-video-phy";
 			syscon = <&pmu_system_controller>;
 			#phy-cells = <1>;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5422-odroid-core.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5422-odroid-core.dtsi
@@ -141,7 +141,7 @@
 		samsung,s2mps11-acokb-ground;
 
 		interrupt-parent = <&gpx0>;
-		interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+		interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&s2mps11_irq>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5422-odroidhc1.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5422-odroidhc1.dts
@@ -22,7 +22,7 @@
 			label = "blue:heartbeat";
 			pwms = <&pwm 2 2000000 0>;
 			pwm-names = "pwm2";
-			max_brightness = <255>;
+			max-brightness = <255>;
 			linux,default-trigger = "heartbeat";
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos5422-odroidxu4.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos5422-odroidxu4.dts
@@ -24,7 +24,7 @@
 			label = "blue:heartbeat";
 			pwms = <&pwm 2 2000000 0>;
 			pwm-names = "pwm2";
-			max_brightness = <255>;
+			max-brightness = <255>;
 			linux,default-trigger = "heartbeat";
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi
@@ -22,7 +22,7 @@
 			 * Green LED is much brighter than the others
 			 * so limit its max brightness
 			 */
-			max_brightness = <127>;
+			max-brightness = <127>;
 			linux,default-trigger = "mmc0";
 		};
 
@@ -30,7 +30,7 @@
 			label = "blue:heartbeat";
 			pwms = <&pwm 2 2000000 0>;
 			pwm-names = "pwm2";
-			max_brightness = <255>;
+			max-brightness = <255>;
 			linux,default-trigger = "heartbeat";
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini-dlink-dns-313.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini-dlink-dns-313.dts
@@ -140,7 +140,7 @@
 		};
 	};
 
-	mdio0: ethernet-phy {
+	mdio0: mdio {
 		compatible = "virtual,mdio-gpio";
 		/* Uses MDC and MDIO */
 		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini-nas4220b.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini-nas4220b.dts
@@ -62,7 +62,7 @@
 		};
 	};
 
-	mdio0: ethernet-phy {
+	mdio0: mdio {
 		compatible = "virtual,mdio-gpio";
 		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */
 			<&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */
@@ -84,7 +84,7 @@
 			partitions {
 				compatible = "redboot-fis";
 				/* Eraseblock at 0xfe0000 */
-				fis-index-block = <0x1fc>;
+				fis-index-block = <0x7f>;
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini-rut1xx.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini-rut1xx.dts
@@ -56,7 +56,7 @@
 		};
 	};
 
-	mdio0: ethernet-phy {
+	mdio0: mdio {
 		compatible = "virtual,mdio-gpio";
 		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */
 			<&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */
@@ -114,18 +114,6 @@
 		};
 
 		ethernet@60000000 {
-			status = "okay";
-
-			ethernet-port@0 {
-				phy-mode = "rgmii";
-				phy-handle = <&phy0>;
-			};
-			ethernet-port@1 {
-				/* Not used in this platform */
-			};
-		};
-
-		ethernet@60000000 {
 			status = "okay";
 
 			ethernet-port@0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini-wbd111.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini-wbd111.dts
@@ -68,7 +68,7 @@
 		};
 	};
 
-	mdio0: ethernet-phy {
+	mdio0: mdio {
 		compatible = "virtual,mdio-gpio";
 		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */
 			<&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini-wbd222.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini-wbd222.dts
@@ -67,7 +67,7 @@
 		};
 	};
 
-	mdio0: ethernet-phy {
+	mdio0: mdio {
 		compatible = "virtual,mdio-gpio";
 		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */
 			<&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/gemini.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/gemini.dtsi
@@ -286,6 +286,7 @@
 			clock-names = "PCLK", "PCICLK";
 			pinctrl-names = "default";
 			pinctrl-0 = <&pci_default_pins>;
+			device_type = "pci";
 			#address-cells = <3>;
 			#size-cells = <2>;
 			#interrupt-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx1-ads.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx1-ads.dts
@@ -65,7 +65,7 @@
 	pinctrl-0 = <&pinctrl_weim>;
 	status = "okay";
 
-	nor: nor@0,0 {
+	nor: flash@0,0 {
 		compatible = "cfi-flash";
 		reg = <0 0x00000000 0x02000000>;
 		bank-width = <4>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx1-apf9328.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx1-apf9328.dts
@@ -45,7 +45,7 @@
 	pinctrl-0 = <&pinctrl_weim>;
 	status = "okay";
 
-	nor: nor@0,0 {
+	nor: flash@0,0 {
 		compatible = "cfi-flash";
 		reg = <0 0x00000000 0x02000000>;
 		bank-width = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx1.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx1.dtsi
@@ -125,7 +125,7 @@
 			};
 
 			pwm: pwm@208000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx1-pwm";
 				reg = <0x00208000 0x1000>;
 				interrupts = <34>;
@@ -268,9 +268,12 @@
 			status = "disabled";
 		};
 
-		esram: esram@300000 {
+		esram: sram@300000 {
 			compatible = "mmio-sram";
 			reg = <0x00300000 0x20000>;
+			ranges = <0 0x00300000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx23-evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx23-evk.dts
@@ -53,7 +53,7 @@
 
 	apb@80000000 {
 		apbh@80000000 {
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&gpmi_pins_a &gpmi_pins_fixup>;
 				status = "okay";
@@ -79,7 +79,6 @@
 						MX23_PAD_LCD_RESET__GPIO_1_18
 						MX23_PAD_PWM3__GPIO_1_29
 						MX23_PAD_PWM4__GPIO_1_30
-						MX23_PAD_SSP1_DETECT__SSP1_DETECT
 					>;
 					fsl,drive-strength = <MXS_DRIVE_4mA>;
 					fsl,voltage = <MXS_VOLTAGE_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx23-sansa.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx23-sansa.dts
@@ -175,10 +175,8 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "i2c-gpio";
-		gpios = <
-			&gpio1 24 0		/* SDA */
-			&gpio1 22 0		/* SCL */
-		>;
+		sda-gpios = <&gpio1 24 0>;
+		scl-gpios = <&gpio1 22 0>;
 		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
 	};
 
@@ -186,10 +184,8 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "i2c-gpio";
-		gpios = <
-			&gpio0 31 0		/* SDA */
-			&gpio0 30 0		/* SCL */
-		>;
+		sda-gpios = <&gpio0 31 0>;
+		scl-gpios = <&gpio0 30 0>;
 		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
 
 		touch: touch@20 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx23.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx23.dtsi
@@ -59,7 +59,7 @@
 				reg = <0x80000000 0x2000>;
 			};
 
-			dma_apbh: dma-apbh@80004000 {
+			dma_apbh: dma-controller@80004000 {
 				compatible = "fsl,imx23-dma-apbh";
 				reg = <0x80004000 0x2000>;
 				interrupts = <0 14 20 0
@@ -76,7 +76,7 @@
 				status = "disabled";
 			};
 
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				compatible = "fsl,imx23-gpmi-nand";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -406,7 +406,7 @@
 				status = "disabled";
 			};
 
-			dma_apbx: dma-apbx@80024000 {
+			dma_apbx: dma-controller@80024000 {
 				compatible = "fsl,imx23-dma-apbx";
 				reg = <0x80024000 0x2000>;
 				interrupts = <7 5 9 26
@@ -422,7 +422,7 @@
 				clocks = <&clks 16>;
 			};
 
-			dcp@80028000 {
+			dcp: crypto@80028000 {
 				compatible = "fsl,imx23-dcp";
 				reg = <0x80028000 0x2000>;
 				interrupts = <53 54>;
@@ -434,7 +434,7 @@
 				status = "disabled";
 			};
 
-			ocotp@8002c000 {
+			efuse@8002c000 {
 				compatible = "fsl,imx23-ocotp", "fsl,ocotp";
 				#address-cells = <1>;
 				#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi
@@ -27,7 +27,7 @@
 	pinctrl-0 = <&pinctrl_i2c1>;
 	status = "okay";
 
-	pcf8563@51 {
+	rtc@51 {
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts
@@ -16,7 +16,7 @@
 		bus-width = <18>;
 		display-timings {
 			native-mode = <&qvga_timings>;
-			qvga_timings: 320x240 {
+			qvga_timings: timing0 {
 				clock-frequency = <6500000>;
 				hactive = <320>;
 				vactive = <240>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts
@@ -16,7 +16,7 @@
 		bus-width = <18>;
 		display-timings {
 			native-mode = <&dvi_svga_timings>;
-			dvi_svga_timings: 800x600 {
+			dvi_svga_timings: timing0 {
 				clock-frequency = <40000000>;
 				hactive = <800>;
 				vactive = <600>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts
@@ -16,7 +16,7 @@
 		bus-width = <18>;
 		display-timings {
 			native-mode = <&dvi_vga_timings>;
-			dvi_vga_timings: 640x480 {
+			dvi_vga_timings: timing0 {
 				clock-frequency = <31250000>;
 				hactive = <640>;
 				vactive = <480>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25-pdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25-pdk.dts
@@ -78,7 +78,7 @@
 		bus-width = <18>;
 		display-timings {
 			native-mode = <&wvga_timings>;
-			wvga_timings: 640x480 {
+			wvga_timings: timing0 {
 				hactive = <640>;
 				vactive = <480>;
 				hback-porch = <45>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx25.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx25.dtsi
@@ -75,7 +75,7 @@
 		interrupt-parent = <&asic>;
 		ranges;
 
-		aips@43f00000 { /* AIPS1 */
+		bus@43f00000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -332,7 +332,7 @@
 			};
 		};
 
-		aips@53f00000 { /* AIPS2 */
+		bus@53f00000 { /* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -411,7 +411,7 @@
 
 			pwm2: pwm@53fa0000 {
 				compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				reg = <0x53fa0000 0x4000>;
 				clocks = <&clks 106>, <&clks 52>;
 				clock-names = "ipg", "per";
@@ -430,7 +430,7 @@
 
 			pwm3: pwm@53fa8000 {
 				compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				reg = <0x53fa8000 0x4000>;
 				clocks = <&clks 107>, <&clks 52>;
 				clock-names = "ipg", "per";
@@ -453,7 +453,7 @@
 				interrupts = <22>;
 			};
 
-			esdhc1: esdhc@53fb4000 {
+			esdhc1: mmc@53fb4000 {
 				compatible = "fsl,imx25-esdhc";
 				reg = <0x53fb4000 0x4000>;
 				interrupts = <9>;
@@ -462,7 +462,7 @@
 				status = "disabled";
 			};
 
-			esdhc2: esdhc@53fb8000 {
+			esdhc2: mmc@53fb8000 {
 				compatible = "fsl,imx25-esdhc";
 				reg = <0x53fb8000 0x4000>;
 				interrupts = <8>;
@@ -488,7 +488,7 @@
 
 			pwm4: pwm@53fc8000 {
 				compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				reg = <0x53fc8000 0x4000>;
 				clocks = <&clks 108>, <&clks 52>;
 				clock-names = "ipg", "per";
@@ -535,14 +535,14 @@
 
 			pwm1: pwm@53fe0000 {
 				compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				reg = <0x53fe0000 0x4000>;
 				clocks = <&clks 105>, <&clks 52>;
 				clock-names = "ipg", "per";
 				interrupts = <26>;
 			};
 
-			iim: iim@53ff0000 {
+			iim: efuse@53ff0000 {
 				compatible = "fsl,imx25-iim", "fsl,imx27-iim";
 				reg = <0x53ff0000 0x4000>;
 				interrupts = <19>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27-apf27dev.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-apf27dev.dts
@@ -16,7 +16,7 @@
 		fsl,pcr = <0xfae80083>;	/* non-standard but required */
 		display-timings {
 			native-mode = <&timing0>;
-			timing0: 800x480 {
+			timing0: timing0 {
 				clock-frequency = <33000033>;
 				hactive = <800>;
 				vactive = <480>;
@@ -47,7 +47,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_gpio_leds>;
 
-		user {
+		led-user {
 			label = "Heartbeat";
 			gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "heartbeat";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi
@@ -33,7 +33,7 @@
 	pinctrl-0 = <&pinctrl_i2c1>;
 	status = "okay";
 
-	pcf8563@51 {
+	rtc@51 {
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 	};
@@ -90,7 +90,7 @@
 &weim {
 	status = "okay";
 
-	nor: nor@0,0 {
+	nor: flash@0,0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
 		compatible = "cfi-flash";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts
@@ -16,7 +16,7 @@
 
 		display-timings {
 			native-mode = <&timing0>;
-			timing0: 320x240 {
+			timing0: timing0 {
 				clock-frequency = <6500000>;
 				hactive = <320>;
 				vactive = <240>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts
@@ -19,7 +19,7 @@
 		fsl,pcr = <0xf0c88080>;	/* non-standard but required */
 		display-timings {
 			native-mode = <&timing0>;
-			timing0: 640x480 {
+			timing0: timing0 {
 				hactive = <640>;
 				vactive = <480>;
 				hback-porch = <112>;
@@ -75,8 +75,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-ein-5.4.0.orig/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts
@@ -19,7 +19,7 @@
 
 		display-timings {
 			native-mode = <&timing0>;
-			timing0: 240x320 {
+			timing0: timing0 {
 				clock-frequency = <5500000>;
 				hactive = <240>;
 				vactive = <320>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
@@ -322,7 +322,7 @@
 &weim {
 	status = "okay";
 
-	nor: nor@0,0 {
+	nor: flash@0,0 {
 		compatible = "cfi-flash";
 		reg = <0 0x00000000 0x02000000>;
 		bank-width = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx27.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx27.dtsi
@@ -134,7 +134,7 @@
 			};
 
 			pwm: pwm@10006000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx27-pwm";
 				reg = <0x10006000 0x1000>;
 				interrupts = <23>;
@@ -265,7 +265,7 @@
 				status = "disabled";
 			};
 
-			sdhci1: sdhci@10013000 {
+			sdhci1: mmc@10013000 {
 				compatible = "fsl,imx27-mmc", "fsl,imx21-mmc";
 				reg = <0x10013000 0x1000>;
 				interrupts = <11>;
@@ -277,7 +277,7 @@
 				status = "disabled";
 			};
 
-			sdhci2: sdhci@10014000 {
+			sdhci2: mmc@10014000 {
 				compatible = "fsl,imx27-mmc", "fsl,imx21-mmc";
 				reg = <0x10014000 0x1000>;
 				interrupts = <10>;
@@ -431,7 +431,7 @@
 				status = "disabled";
 			};
 
-			sdhci3: sdhci@1001e000 {
+			sdhci3: mmc@1001e000 {
 				compatible = "fsl,imx27-mmc", "fsl,imx21-mmc";
 				reg = <0x1001e000 0x1000>;
 				interrupts = <9>;
@@ -525,7 +525,7 @@
 				reg = <0x10024600 0x200>;
 			};
 
-			sahara2: sahara@10025000 {
+			sahara2: crypto@10025000 {
 				compatible = "fsl,imx27-sahara";
 				reg = <0x10025000 0x1000>;
 				interrupts = <59>;
@@ -540,7 +540,7 @@
 				#clock-cells = <1>;
 			};
 
-			iim: iim@10028000 {
+			iim: efuse@10028000 {
 				compatible = "fsl,imx27-iim";
 				reg = <0x10028000 0x1000>;
 				interrupts = <62>;
@@ -588,6 +588,9 @@
 		iram: iram@ffff4c00 {
 			compatible = "mmio-sram";
 			reg = <0xffff4c00 0xb400>;
+			ranges = <0 0xffff4c00 0xb400>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx28-apf28.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx28-apf28.dts
@@ -17,7 +17,7 @@
 
 	apb@80000000 {
 		apbh@80000000 {
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg>;
 				status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx28-apx4devkit.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx28-apx4devkit.dts
@@ -13,7 +13,7 @@
 
 	apb@80000000 {
 		apbh@80000000 {
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg>;
 				status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx28-evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx28-evk.dts
@@ -97,7 +97,7 @@
 
 	apb@80000000 {
 		apbh@80000000 {
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg
 					     &gpmi_pins_evk>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx28-m28cu3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx28-m28cu3.dts
@@ -17,7 +17,7 @@
 
 	apb@80000000 {
 		apbh@80000000 {
-			gpmi-nand@8000c000 {
+			nand-controller@8000c000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				pinctrl-names = "default";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx28.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx28.dtsi
@@ -78,7 +78,7 @@
 				status = "disabled";
 			};
 
-			dma_apbh: dma-apbh@80004000 {
+			dma_apbh: dma-controller@80004000 {
 				compatible = "fsl,imx28-dma-apbh";
 				reg = <0x80004000 0x2000>;
 				interrupts = <82 83 84 85
@@ -100,7 +100,7 @@
 				status = "disabled";
 			};
 
-			gpmi: gpmi-nand@8000c000 {
+			gpmi: nand-controller@8000c000 {
 				compatible = "fsl,imx28-gpmi-nand";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -982,7 +982,7 @@
 				status = "disabled";
 			};
 
-			dma_apbx: dma-apbx@80024000 {
+			dma_apbx: dma-controller@80024000 {
 				compatible = "fsl,imx28-dma-apbx";
 				reg = <0x80024000 0x2000>;
 				interrupts = <78 79 66 0
@@ -998,7 +998,7 @@
 				clocks = <&clks 26>;
 			};
 
-			dcp: dcp@80028000 {
+			dcp: crypto@80028000 {
 				compatible = "fsl,imx28-dcp", "fsl,imx23-dcp";
 				reg = <0x80028000 0x2000>;
 				interrupts = <52 53 54>;
@@ -1011,7 +1011,7 @@
 				status = "disabled";
 			};
 
-			ocotp: ocotp@8002c000 {
+			ocotp: efuse@8002c000 {
 				compatible = "fsl,imx28-ocotp", "fsl,ocotp";
 				#address-cells = <1>;
 				#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx31.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx31.dtsi
@@ -63,7 +63,7 @@
 			ranges = <0 0x1fffc000 0x4000>;
 		};
 
-		aips@43f00000 { /* AIPS1 */
+		bus@43f00000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -173,7 +173,7 @@
 			reg = <0x50000000 0x100000>;
 			ranges;
 
-			sdhci1: sdhci@50004000 {
+			sdhci1: mmc@50004000 {
 				compatible = "fsl,imx31-mmc";
 				reg = <0x50004000 0x4000>;
 				interrupts = <9>;
@@ -184,7 +184,7 @@
 				status = "disabled";
 			};
 
-			sdhci2: sdhci@50008000 {
+			sdhci2: mmc@50008000 {
 				compatible = "fsl,imx31-mmc";
 				reg = <0x50008000 0x4000>;
 				interrupts = <8>;
@@ -217,7 +217,7 @@
 				status = "disabled";
 			};
 
-			iim: iim@5001c000 {
+			iim: efuse@5001c000 {
 				compatible = "fsl,imx31-iim", "fsl,imx27-iim";
 				reg = <0x5001c000 0x1000>;
 				interrupts = <19>;
@@ -225,7 +225,7 @@
 			};
 		};
 
-		aips@53f00000 { /* AIPS2 */
+		bus@53f00000 { /* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -327,7 +327,7 @@
 				interrupts = <26>;
 				clocks = <&clks 10>, <&clks 42>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx35.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx35.dtsi
@@ -59,14 +59,14 @@
 		interrupt-parent = <&avic>;
 		ranges;
 
-		L2: l2-cache@30000000 {
+		L2: cache-controller@30000000 {
 			compatible = "arm,l210-cache";
 			reg = <0x30000000 0x1000>;
 			cache-unified;
 			cache-level = <2>;
 		};
 
-		aips1: aips@43f00000 {
+		aips1: bus@43f00000 {
 			compatible = "fsl,aips", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -199,7 +199,7 @@
 			};
 		};
 
-		aips2: aips@53f00000 {
+		aips2: bus@53f00000 {
 			compatible = "fsl,aips", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -231,7 +231,7 @@
 				#interrupt-cells = <2>;
 			};
 
-			esdhc1: esdhc@53fb4000 {
+			esdhc1: mmc@53fb4000 {
 				compatible = "fsl,imx35-esdhc";
 				reg = <0x53fb4000 0x4000>;
 				interrupts = <7>;
@@ -240,7 +240,7 @@
 				status = "disabled";
 			};
 
-			esdhc2: esdhc@53fb8000 {
+			esdhc2: mmc@53fb8000 {
 				compatible = "fsl,imx35-esdhc";
 				reg = <0x53fb8000 0x4000>;
 				interrupts = <8>;
@@ -249,7 +249,7 @@
 				status = "disabled";
 			};
 
-			esdhc3: esdhc@53fbc000 {
+			esdhc3: mmc@53fbc000 {
 				compatible = "fsl,imx35-esdhc";
 				reg = <0x53fbc000 0x4000>;
 				interrupts = <9>;
@@ -320,7 +320,7 @@
 				status = "disabled";
 			};
 
-			iim@53ff0000 {
+			efuse@53ff0000 {
 				compatible = "fsl,imx35-iim";
 				reg = <0x53ff0000 0x4000>;
 				interrupts = <19>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx50-evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx50-evk.dts
@@ -59,7 +59,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-ein-5.4.0.orig/arch/arm/boot/dts/imx50.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx50.dtsi
@@ -101,7 +101,7 @@
 		interrupt-parent = <&tzic>;
 		ranges;
 
-		aips@50000000 { /* AIPS1 */
+		bus@50000000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -115,7 +115,7 @@
 				reg = <0x50000000 0x40000>;
 				ranges;
 
-				esdhc1: esdhc@50004000 {
+				esdhc1: mmc@50004000 {
 					compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc";
 					reg = <0x50004000 0x4000>;
 					interrupts = <1>;
@@ -127,7 +127,7 @@
 					status = "disabled";
 				};
 
-				esdhc2: esdhc@50008000 {
+				esdhc2: mmc@50008000 {
 					compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc";
 					reg = <0x50008000 0x4000>;
 					interrupts = <2>;
@@ -176,7 +176,7 @@
 					status = "disabled";
 				};
 
-				esdhc3: esdhc@50020000 {
+				esdhc3: mmc@50020000 {
 					compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc";
 					reg = <0x50020000 0x4000>;
 					interrupts = <3>;
@@ -188,7 +188,7 @@
 					status = "disabled";
 				};
 
-				esdhc4: esdhc@50024000 {
+				esdhc4: mmc@50024000 {
 					compatible = "fsl,imx50-esdhc", "fsl,imx53-esdhc";
 					reg = <0x50024000 0x4000>;
 					interrupts = <4>;
@@ -294,7 +294,7 @@
 			};
 
 			pwm1: pwm@53fb4000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx50-pwm", "fsl,imx27-pwm";
 				reg = <0x53fb4000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
@@ -304,7 +304,7 @@
 			};
 
 			pwm2: pwm@53fb8000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx50-pwm", "fsl,imx27-pwm";
 				reg = <0x53fb8000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>,
@@ -389,7 +389,7 @@
 			};
 		};
 
-		aips@60000000 {	/* AIPS2 */
+		bus@60000000 {	/* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx51-ts4800.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx51-ts4800.dts
@@ -113,6 +113,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm_backlight>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx51.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx51.dtsi
@@ -158,7 +158,7 @@
 			};
 		};
 
-		aips@70000000 { /* AIPS1 */
+		bus@70000000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -172,7 +172,7 @@
 				reg = <0x70000000 0x40000>;
 				ranges;
 
-				esdhc1: esdhc@70004000 {
+				esdhc1: mmc@70004000 {
 					compatible = "fsl,imx51-esdhc";
 					reg = <0x70004000 0x4000>;
 					interrupts = <1>;
@@ -183,7 +183,7 @@
 					status = "disabled";
 				};
 
-				esdhc2: esdhc@70008000 {
+				esdhc2: mmc@70008000 {
 					compatible = "fsl,imx51-esdhc";
 					reg = <0x70008000 0x4000>;
 					interrupts = <2>;
@@ -232,7 +232,7 @@
 					status = "disabled";
 				};
 
-				esdhc3: esdhc@70020000 {
+				esdhc3: mmc@70020000 {
 					compatible = "fsl,imx51-esdhc";
 					reg = <0x70020000 0x4000>;
 					interrupts = <3>;
@@ -244,7 +244,7 @@
 					status = "disabled";
 				};
 
-				esdhc4: esdhc@70024000 {
+				esdhc4: mmc@70024000 {
 					compatible = "fsl,imx51-esdhc";
 					reg = <0x70024000 0x4000>;
 					interrupts = <4>;
@@ -387,7 +387,7 @@
 			};
 
 			pwm1: pwm@73fb4000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx51-pwm", "fsl,imx27-pwm";
 				reg = <0x73fb4000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
@@ -397,7 +397,7 @@
 			};
 
 			pwm2: pwm@73fb8000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx51-pwm", "fsl,imx27-pwm";
 				reg = <0x73fb8000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>,
@@ -440,7 +440,7 @@
 			};
 		};
 
-		aips@80000000 {	/* AIPS2 */
+		bus@80000000 {	/* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -452,7 +452,7 @@
 				reg = <0x83f00000 0x60>;
 			};
 
-			iim: iim@83f98000 {
+			iim: efuse@83f98000 {
 				compatible = "fsl,imx51-iim", "fsl,imx27-iim";
 				reg = <0x83f98000 0x4000>;
 				interrupts = <69>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-kp.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-kp.dtsi
@@ -162,6 +162,14 @@
 	>;
 };
 
+&pwm1 {
+	#pwm-cells = <2>;
+};
+
+&pwm2 {
+	#pwm-cells = <2>;
+};
+
 &uart1 {
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-m53evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-m53evk.dts
@@ -321,6 +321,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-m53menlo.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-m53menlo.dts
@@ -53,14 +53,40 @@
 		};
 	};
 
+	lvds-decoder {
+		compatible = "ti,ds90cf364a", "lvds-decoder";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				lvds_decoder_in: endpoint {
+					remote-endpoint = <&lvds0_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+
+				lvds_decoder_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
+
 	panel {
 		compatible = "edt,etm0700g0dh6";
 		pinctrl-0 = <&pinctrl_display_gpio>;
+		pinctrl-names = "default";
 		enable-gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>;
 
 		port {
 			panel_in: endpoint {
-				remote-endpoint = <&lvds0_out>;
+				remote-endpoint = <&lvds_decoder_out>;
 			};
 		};
 	};
@@ -76,8 +102,7 @@
 		regulator-name = "vbus";
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
-		gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
+		gpio = <&gpio1 2 0>;
 	};
 };
 
@@ -388,13 +413,13 @@
 
 		pinctrl_power_button: powerbutgrp {
 			fsl,pins = <
-				MX53_PAD_SD2_DATA2__GPIO1_13		0x1e4
+				MX53_PAD_SD2_DATA0__GPIO1_15		0x1e4
 			>;
 		};
 
 		pinctrl_power_out: poweroutgrp {
 			fsl,pins = <
-				MX53_PAD_SD2_DATA0__GPIO1_15		0x1e4
+				MX53_PAD_SD2_DATA2__GPIO1_13		0x1e4
 			>;
 		};
 
@@ -450,7 +475,7 @@
 			reg = <2>;
 
 			lvds0_out: endpoint {
-				remote-endpoint = <&panel_in>;
+				remote-endpoint = <&lvds_decoder_in>;
 			};
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-ppd.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-ppd.dts
@@ -70,6 +70,12 @@
 		clock-frequency = <11289600>;
 	};
 
+	achc_24M: achc-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+	};
+
 	sgtlsound: sound {
 		compatible = "fsl,imx53-cpuvo-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
@@ -287,16 +293,13 @@
 		    &gpio4 12 GPIO_ACTIVE_LOW>;
 	status = "okay";
 
-	spidev0: spi@0 {
-		compatible = "ge,achc";
-		reg = <0>;
-		spi-max-frequency = <1000000>;
-	};
-
-	spidev1: spi@1 {
-		compatible = "ge,achc";
-		reg = <1>;
-		spi-max-frequency = <1000000>;
+	spidev0: spi@1 {
+		compatible = "ge,achc", "nxp,kinetis-k20";
+		reg = <1>, <0>;
+		vdd-supply = <&reg_3v3>;
+		vdda-supply = <&reg_3v3>;
+		clocks = <&achc_24M>;
+		reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
 	};
 
 	gpioxra0: gpio@2 {
@@ -458,7 +461,7 @@
 	scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
 	status = "okay";
 
-	i2c-switch@70 {
+	i2c-mux@70 {
 		compatible = "nxp,pca9547";
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -598,12 +601,14 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
 &pwm2 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-tqma53.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-tqma53.dtsi
@@ -209,6 +209,14 @@
 	};
 };
 
+&pwm1 {
+	#pwm-cells = <2>;
+};
+
+&pwm2 {
+	#pwm-cells = <2>;
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53-tx53.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53-tx53.dtsi
@@ -542,7 +542,6 @@
 &pwm2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
-	#pwm-cells = <3>;
 };
 
 &sdma {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx53.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx53.dtsi
@@ -222,7 +222,7 @@
 			clock-names = "core_clk", "mem_iface_clk";
 		};
 
-		aips@50000000 { /* AIPS1 */
+		bus@50000000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -236,7 +236,7 @@
 				reg = <0x50000000 0x40000>;
 				ranges;
 
-				esdhc1: esdhc@50004000 {
+				esdhc1: mmc@50004000 {
 					compatible = "fsl,imx53-esdhc";
 					reg = <0x50004000 0x4000>;
 					interrupts = <1>;
@@ -248,7 +248,7 @@
 					status = "disabled";
 				};
 
-				esdhc2: esdhc@50008000 {
+				esdhc2: mmc@50008000 {
 					compatible = "fsl,imx53-esdhc";
 					reg = <0x50008000 0x4000>;
 					interrupts = <2>;
@@ -301,7 +301,7 @@
 					status = "disabled";
 				};
 
-				esdhc3: esdhc@50020000 {
+				esdhc3: mmc@50020000 {
 					compatible = "fsl,imx53-esdhc";
 					reg = <0x50020000 0x4000>;
 					interrupts = <3>;
@@ -313,7 +313,7 @@
 					status = "disabled";
 				};
 
-				esdhc4: esdhc@50024000 {
+				esdhc4: mmc@50024000 {
 					compatible = "fsl,imx53-esdhc";
 					reg = <0x50024000 0x4000>;
 					interrupts = <4>;
@@ -525,7 +525,7 @@
 			};
 
 			pwm1: pwm@53fb4000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
 				reg = <0x53fb4000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
@@ -535,7 +535,7 @@
 			};
 
 			pwm2: pwm@53fb8000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
 				reg = <0x53fb8000 0x4000>;
 				clocks = <&clks IMX5_CLK_PWM2_IPG_GATE>,
@@ -654,7 +654,7 @@
 			};
 		};
 
-		aips@60000000 {	/* AIPS2 */
+		bus@60000000 {	/* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -666,7 +666,7 @@
 				reg = <0x63f00000 0x60>;
 			};
 
-			iim: iim@63f98000 {
+			iim: efuse@63f98000 {
 				compatible = "fsl,imx53-iim", "fsl,imx27-iim";
 				reg = <0x63f98000 0x4000>;
 				interrupts = <69>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-aristainetos_4.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-aristainetos_4.dts
@@ -79,5 +79,6 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-aristainetos_7.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-aristainetos_7.dts
@@ -69,5 +69,6 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-icore-mipi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-icore-mipi.dts
@@ -8,7 +8,7 @@
 /dts-v1/;
 
 #include "imx6dl.dtsi"
-#include "imx6qdl-icore.dtsi"
+#include "imx6qdl-icore-1.5.dtsi"
 
 / {
 	model = "Engicam i.CoreM6 DualLite/Solo MIPI Starter Kit";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-mamoj.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-mamoj.dts
@@ -303,6 +303,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi
@@ -99,9 +99,13 @@
 	phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
 	phy-reset-duration = <20>;
 	phy-supply = <&sw2_reg>;
-	phy-handle = <&ethphy0>;
 	status = "okay";
 
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+
 	mdio {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -520,7 +524,6 @@
 };
 
 &pwm1 {
-	#pwm-cells = <3>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "disabled";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl-yapp4-ursa.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl-yapp4-ursa.dts
@@ -38,7 +38,7 @@
 };
 
 &switch_ports {
-	/delete-node/ port@2;
+	/delete-node/ port@3;
 };
 
 &touchscreen {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6dl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6dl.dtsi
@@ -44,6 +44,8 @@
 			arm-supply = <&reg_arm>;
 			pu-supply = <&reg_pu>;
 			soc-supply = <&reg_soc>;
+			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cell-names = "speed_grade";
 		};
 
 		cpu@1 {
@@ -81,11 +83,14 @@
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x20000>;
+			ranges = <0 0x00900000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6QDL_CLK_OCRAM>;
 		};
 
-		aips1: aips-bus@2000000 {
-			iomuxc: iomuxc@20e0000 {
+		aips1: bus@2000000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6dl-iomuxc";
 			};
 
@@ -100,7 +105,7 @@
 			};
 		};
 
-		aips2: aips-bus@2100000 {
+		aips2: bus@2100000 {
 			i2c4: i2c@21f8000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-b450v3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-b450v3.dts
@@ -65,13 +65,6 @@
 	};
 };
 
-&clks {
-	assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
-			  <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
-	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
-				 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
-};
-
 &ldb {
 	status = "okay";
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-b650v3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-b650v3.dts
@@ -65,13 +65,6 @@
 	};
 };
 
-&clks {
-	assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
-			  <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
-	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
-				 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
-};
-
 &ldb {
 	status = "okay";
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-b850v3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-b850v3.dts
@@ -53,17 +53,6 @@
 	};
 };
 
-&clks {
-	assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
-			  <&clks IMX6QDL_CLK_LDB_DI1_SEL>,
-			  <&clks IMX6QDL_CLK_IPU1_DI0_PRE_SEL>,
-			  <&clks IMX6QDL_CLK_IPU2_DI0_PRE_SEL>;
-	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>,
-				 <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>,
-				 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>,
-				 <&clks IMX6QDL_CLK_PLL2_PFD2_396M>;
-};
-
 &ldb {
 	fsl,dual-channel;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-ba16.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-ba16.dtsi
@@ -334,6 +334,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-bx50v3.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-bx50v3.dtsi
@@ -377,3 +377,18 @@
 		#interrupt-cells = <1>;
 	};
 };
+
+&clks {
+	assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+			  <&clks IMX6QDL_CLK_LDB_DI1_SEL>,
+			  <&clks IMX6QDL_CLK_IPU1_DI0_PRE_SEL>,
+			  <&clks IMX6QDL_CLK_IPU1_DI1_PRE_SEL>,
+			  <&clks IMX6QDL_CLK_IPU2_DI0_PRE_SEL>,
+			  <&clks IMX6QDL_CLK_IPU2_DI1_PRE_SEL>;
+	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>,
+				 <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>,
+				 <&clks IMX6QDL_CLK_PLL2_PFD0_352M>,
+				 <&clks IMX6QDL_CLK_PLL2_PFD0_352M>,
+				 <&clks IMX6QDL_CLK_PLL2_PFD0_352M>,
+				 <&clks IMX6QDL_CLK_PLL2_PFD0_352M>;
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-dhcom-pdk2.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-dhcom-pdk2.dts
@@ -55,7 +55,7 @@
 		#sound-dai-cells = <0>;
 		clocks = <&clk_ext_audio_codec>;
 		VDDA-supply = <&reg_3p3v>;
-		VDDIO-supply = <&reg_3p3v>;
+		VDDIO-supply = <&sw2_reg>;
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-dhcom-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-dhcom-som.dtsi
@@ -98,30 +98,40 @@
 			reg = <0>;
 			max-speed = <100>;
 			reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
-			reset-delay-us = <1000>;
-			reset-post-delay-us = <1000>;
+			reset-assert-us = <1000>;
+			reset-deassert-us = <1000>;
+			smsc,disable-energy-detect; /* Make plugin detection reliable */
 		};
 	};
 };
 
 &i2c1 {
 	clock-frequency = <100000>;
-	pinctrl-names = "default";
+	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+	scl-gpios = <&gpio3 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio3 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	status = "okay";
 };
 
 &i2c2 {
 	clock-frequency = <100000>;
-	pinctrl-names = "default";
+	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	status = "okay";
 };
 
 &i2c3 {
 	clock-frequency = <100000>;
-	pinctrl-names = "default";
+	pinctrl-names = "default", "gpio";
 	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+	scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 	status = "okay";
 
 	ltc3676: pmic@3c {
@@ -206,7 +216,7 @@
 	};
 
 	rtc@56 {
-		compatible = "rv3029c2";
+		compatible = "microcrystal,rv3029";
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_rtc_hw300>;
 		reg = <0x56>;
@@ -287,6 +297,13 @@
 		>;
 	};
 
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D21__GPIO3_IO21		0x4001b8b1
+			MX6QDL_PAD_EIM_D28__GPIO3_IO28		0x4001b8b1
+		>;
+	};
+
 	pinctrl_i2c2: i2c2-grp {
 		fsl,pins = <
 			MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
@@ -294,6 +311,13 @@
 		>;
 	};
 
+	pinctrl_i2c2_gpio: i2c2-gpio-grp {
+		fsl,pins = <
+			MX6QDL_PAD_KEY_COL3__GPIO4_IO12		0x4001b8b1
+			MX6QDL_PAD_KEY_ROW3__GPIO4_IO13		0x4001b8b1
+		>;
+	};
+
 	pinctrl_i2c3: i2c3-grp {
 		fsl,pins = <
 			MX6QDL_PAD_GPIO_3__I2C3_SCL		0x4001b8b1
@@ -301,6 +325,13 @@
 		>;
 	};
 
+	pinctrl_i2c3_gpio: i2c3-gpio-grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_3__GPIO1_IO03		0x4001b8b1
+			MX6QDL_PAD_GPIO_6__GPIO1_IO06		0x4001b8b1
+		>;
+	};
+
 	pinctrl_pmic_hw300: pmic-hw300-grp {
 		fsl,pins = <
 			MX6QDL_PAD_EIM_A25__GPIO5_IO02		0x1B0B0
@@ -408,6 +439,18 @@
 	vin-supply = <&sw1_reg>;
 };
 
+&reg_pu {
+	vin-supply = <&sw1_reg>;
+};
+
+&reg_vdd1p1 {
+	vin-supply = <&sw2_reg>;
+};
+
+&reg_vdd2p5 {
+	vin-supply = <&sw2_reg>;
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-display5.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-display5.dtsi
@@ -399,7 +399,6 @@
 };
 
 &pwm2 {
-	#pwm-cells = <3>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-kp.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-kp.dtsi
@@ -378,12 +378,14 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
 &pwm2 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-mccmon6.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-mccmon6.dts
@@ -237,7 +237,6 @@
 };
 
 &pwm2 {
-	#pwm-cells = <3>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-novena.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-novena.dts
@@ -455,6 +455,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-pistachio.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-pistachio.dts
@@ -570,6 +570,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q-var-dt6customboard.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q-var-dt6customboard.dts
@@ -203,6 +203,7 @@
 };
 
 &pwm2 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6q.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6q.dtsi
@@ -49,6 +49,8 @@
 			arm-supply = <&reg_arm>;
 			pu-supply = <&reg_pu>;
 			soc-supply = <&reg_soc>;
+			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cell-names = "speed_grade";
 		};
 
 		cpu1: cpu@1 {
@@ -158,10 +160,13 @@
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x40000>;
+			ranges = <0 0x00900000 0x40000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6QDL_CLK_OCRAM>;
 		};
 
-		aips-bus@2000000 { /* AIPS1 */
+		bus@2000000 { /* AIPS1 */
 			spba-bus@2000000 {
 				ecspi5: spi@2018000 {
 					#address-cells = <1>;
@@ -178,7 +183,7 @@
 				};
 			};
 
-			iomuxc: iomuxc@20e0000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6q-iomuxc";
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-apalis.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-apalis.dtsi
@@ -314,6 +314,8 @@
 	codec: sgtl5000@a {
 		compatible = "fsl,sgtl5000";
 		reg = <0x0a>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_sgtl5000>;
 		clocks = <&clks IMX6QDL_CLK_CKO>;
 		VDDA-supply = <&reg_module_3v3_audio>;
 		VDDIO-supply = <&reg_module_3v3>;
@@ -399,6 +401,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "disabled";
@@ -543,8 +546,6 @@
 			MX6QDL_PAD_DISP0_DAT21__AUD4_TXD	0x130b0
 			MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS	0x130b0
 			MX6QDL_PAD_DISP0_DAT23__AUD4_RXD	0x130b0
-			/* SGTL5000 sys_mclk */
-			MX6QDL_PAD_GPIO_5__CCM_CLKO1		0x130b0
 		>;
 	};
 
@@ -810,6 +811,12 @@
 		>;
 	};
 
+	pinctrl_sgtl5000: sgtl5000grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_5__CCM_CLKO1	0x130b0
+		>;
+	};
+
 	pinctrl_spdif: spdifgrp {
 		fsl,pins = <
 			MX6QDL_PAD_GPIO_16__SPDIF_IN  0x1b0b0
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
@@ -233,6 +233,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
@@ -336,6 +336,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-colibri.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-colibri.dtsi
@@ -336,6 +336,7 @@
 
 /* Colibri PWM<A> */
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "disabled";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -233,6 +233,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-emcon-avari.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-emcon-avari.dtsi
@@ -126,7 +126,7 @@
 		compatible = "nxp,pca8574";
 		reg = <0x3a>;
 		gpio-controller;
-		#gpio-cells = <1>;
+		#gpio-cells = <2>;
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-emcon.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-emcon.dtsi
@@ -737,14 +737,17 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -273,7 +273,7 @@
 
 			/* VDD_AUD_1P8: Audio codec */
 			reg_aud_1p8v: ldo3 {
-				regulator-name = "vdd1p8";
+				regulator-name = "vdd1p8a";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-boot-on;
@@ -360,6 +360,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -351,6 +351,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -414,6 +414,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default", "state_dio";
 	pinctrl-0 = <&pinctrl_pwm4_backlight>;
 	pinctrl-1 = <&pinctrl_pwm4_dio>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -105,19 +105,16 @@
 	sound-digital {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "tda1997x-audio";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,bitclock-master = <&sound_codec>;
+		simple-audio-card,frame-master = <&sound_codec>;
 
-		simple-audio-card,dai-link@0 {
-			format = "i2s";
-
-			cpu {
-				sound-dai = <&ssi2>;
-			};
+		sound_cpu: simple-audio-card,cpu {
+			sound-dai = <&ssi1>;
+		};
 
-			codec {
-				bitclock-master;
-				frame-master;
-				sound-dai = <&hdmi_receiver>;
-			};
+		sound_codec: simple-audio-card,codec {
+			sound-dai = <&hdmi_receiver>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw560x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw560x.dtsi
@@ -452,6 +452,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
@@ -464,7 +465,6 @@
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
-	uart-has-rtscts;
 	rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw5903.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw5903.dtsi
@@ -365,6 +365,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-gw5904.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-gw5904.dtsi
@@ -382,6 +382,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-icore.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-icore.dtsi
@@ -232,6 +232,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
@@ -384,7 +385,7 @@
 
 	pinctrl_usbotg: usbotggrp {
 		fsl,pins = <
-			MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+			MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
 		>;
 	};
 
@@ -396,6 +397,7 @@
 			MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17070
 			MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17070
 			MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17070
+			MX6QDL_PAD_GPIO_1__GPIO1_IO01  0x1b0b0
 		>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-kontron-samx6i.dtsi
@@ -51,16 +51,6 @@
 		vin-supply = <&reg_3p3v_s5>;
 	};
 
-	reg_3p3v_s0: regulator-3p3v-s0 {
-		compatible = "regulator-fixed";
-		regulator-name = "V_3V3_S0";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-		regulator-boot-on;
-		vin-supply = <&reg_3p3v_s5>;
-	};
-
 	reg_3p3v_s5: regulator-3p3v-s5 {
 		compatible = "regulator-fixed";
 		regulator-name = "V_3V3_S5";
@@ -167,7 +157,7 @@
 		i2c-gpio,delay-us = <2>; /* ~100 kHz */
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disabld";
+		status = "disabled";
 	};
 
 	i2c_cam: i2c-gpio-cam {
@@ -179,7 +169,7 @@
 		i2c-gpio,delay-us = <2>; /* ~100 kHz */
 		#address-cells = <1>;
 		#size-cells = <0>;
-		status = "disabld";
+		status = "disabled";
 	};
 };
 
@@ -551,7 +541,7 @@
 
 	pinctrl_i2c3: i2c3grp {
 		fsl,pins = <
-			MX6QDL_PAD_GPIO_3__I2C3_SCL		0x4001b8b1
+			MX6QDL_PAD_GPIO_5__I2C3_SCL		0x4001b8b1
 			MX6QDL_PAD_GPIO_16__I2C3_SDA		0x4001b8b1
 		>;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
@@ -497,6 +497,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -509,6 +510,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -736,12 +736,14 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
 &pwm2 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
@@ -754,6 +756,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
@@ -639,6 +639,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -651,6 +652,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -596,6 +596,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -608,6 +609,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi
@@ -218,6 +218,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -315,8 +315,8 @@
 			fsl,pins = <
 				MX6QDL_PAD_EIM_D24__UART3_TX_DATA	0x1b0b1
 				MX6QDL_PAD_EIM_D25__UART3_RX_DATA	0x1b0b1
-				MX6QDL_PAD_EIM_D30__UART3_RTS_B		0x1b0b1
-				MX6QDL_PAD_EIM_D31__UART3_CTS_B		0x1b0b1
+				MX6QDL_PAD_EIM_D31__UART3_RTS_B		0x1b0b1
+				MX6QDL_PAD_EIM_D30__UART3_CTS_B		0x1b0b1
 			>;
 		};
 
@@ -403,6 +403,7 @@
 &uart3 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart3>;
+	uart-has-rtscts;
 	status = "disabled";
 };
 
@@ -432,6 +433,7 @@
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
 	wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+	vmmc-supply = <&vdd_sd1_reg>;
 	status = "disabled";
 };
 
@@ -441,5 +443,6 @@
 		     &pinctrl_usdhc3_cdwp>;
 	cd-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
 	wp-gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
+	vmmc-supply = <&vdd_sd0_reg>;
 	status = "disabled";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
@@ -107,14 +107,14 @@
 		regulators {
 			vdd_arm: buck1 {
 				regulator-name = "vdd_arm";
-				regulator-min-microvolt = <730000>;
+				regulator-min-microvolt = <925000>;
 				regulator-max-microvolt = <1380000>;
 				regulator-always-on;
 			};
 
 			vdd_soc: buck2 {
 				regulator-name = "vdd_soc";
-				regulator-min-microvolt = <730000>;
+				regulator-min-microvolt = <1150000>;
 				regulator-max-microvolt = <1380000>;
 				regulator-always-on;
 			};
@@ -183,7 +183,6 @@
 	pinctrl-0 = <&pinctrl_usdhc4>;
 	bus-width = <8>;
 	non-removable;
-	vmmc-supply = <&vdd_emmc_1p8>;
 	status = "disabled";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -800,6 +800,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -687,18 +687,21 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -728,6 +728,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -749,10 +750,6 @@
 	vin-supply = <&vgen5_reg>;
 };
 
-&reg_vdd3p0 {
-	vin-supply = <&sw2_reg>;
-};
-
 &reg_vdd2p5 {
 	vin-supply = <&vgen5_reg>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
@@ -140,6 +140,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-sr-som-ti.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-sr-som-ti.dtsi
@@ -153,6 +153,7 @@
 	bus-width = <4>;
 	keep-power-in-suspend;
 	mmc-pwrseq = <&pwrseq_ti_wifi>;
+	cap-power-off-card;
 	non-removable;
 	vmmc-supply = <&vcc_3v3>;
 	/* vqmmc-supply = <&nvcc_sd1>; - MMC layer doesn't like it! */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-sr-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-sr-som.dtsi
@@ -54,7 +54,13 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_microsom_enet_ar8035>;
 	phy-mode = "rgmii-id";
-	phy-reset-duration = <2>;
+
+	/*
+	 * The PHY seems to require a long-enough reset duration to avoid
+	 * some rare issues where the PHY gets stuck in an inconsistent and
+	 * non-functional state at boot-up. 10ms proved to be fine .
+	 */
+	phy-reset-duration = <10>;
 	phy-reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-ts7970.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-ts7970.dtsi
@@ -226,7 +226,7 @@
 		reg = <0x28>;
 		#gpio-cells = <2>;
 		gpio-controller;
-		ngpio = <32>;
+		ngpios = <62>;
 	};
 
 	sgtl5000: codec@a {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-tx6.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-tx6.dtsi
@@ -738,14 +738,12 @@
 &pwm1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
-	#pwm-cells = <3>;
 	status = "disabled";
 };
 
 &pwm2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
-	#pwm-cells = <3>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -5,6 +5,8 @@
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
 	aliases {
 		backlight = &backlight;
@@ -98,7 +100,7 @@
 &fec {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
@@ -218,6 +220,7 @@
 				MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
 				MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
 				MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
+				MX6QDL_PAD_SD3_DAT5__GPIO7_IO00		0x1b0b0
 			>;
 		};
 
@@ -290,7 +293,7 @@
 &usdhc3 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc3>;
-	non-removable;
+	cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi
@@ -166,7 +166,6 @@
 				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b030
 				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b030
 				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b030
-				MX6QDL_PAD_GPIO_6__ENET_IRQ		0x000b1
 			>;
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
@@ -627,7 +627,7 @@
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	bus-width = <4>;
 	cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
-	wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+	disable-wp;
 	vmmc-supply = <&reg_3p3v_sd>;
 	vqmmc-supply = <&reg_3p3v>;
 	no-1-8-v;
@@ -640,7 +640,7 @@
 	pinctrl-0 = <&pinctrl_usdhc3>;
 	bus-width = <4>;
 	cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
-	wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+	disable-wp;
 	vmmc-supply = <&reg_3p3v_sd>;
 	vqmmc-supply = <&reg_3p3v>;
 	no-1-8-v;
@@ -774,6 +774,7 @@
 &usbh1 {
 	vbus-supply = <&reg_5p0v_main>;
 	disable-over-current;
+	maximum-speed = "full-speed";
 	status = "okay";
 };
 
@@ -1055,7 +1056,6 @@
 			MX6QDL_PAD_SD2_DAT1__SD2_DATA1		0x17059
 			MX6QDL_PAD_SD2_DAT2__SD2_DATA2		0x17059
 			MX6QDL_PAD_SD2_DAT3__SD2_DATA3		0x17059
-			MX6QDL_PAD_NANDF_D3__GPIO2_IO03		0x40010040
 			MX6QDL_PAD_NANDF_D2__GPIO2_IO02		0x40010040
 		>;
 	};
@@ -1068,7 +1068,6 @@
 			MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
 			MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
 			MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
-			MX6QDL_PAD_NANDF_D1__GPIO2_IO01		0x40010040
 			MX6QDL_PAD_NANDF_D0__GPIO2_IO00		0x40010040
 
 		>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qdl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qdl.dtsi
@@ -45,6 +45,10 @@
 		spi1 = &ecspi2;
 		spi2 = &ecspi3;
 		spi3 = &ecspi4;
+		usb0 = &usbotg;
+		usb1 = &usbh1;
+		usb2 = &usbh2;
+		usb3 = &usbh3;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
 	};
@@ -69,16 +73,6 @@
 		};
 	};
 
-	tempmon: tempmon {
-		compatible = "fsl,imx6q-tempmon";
-		interrupt-parent = <&gpc>;
-		interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>;
-		fsl,tempmon = <&anatop>;
-		fsl,tempmon-data = <&ocotp>;
-		clocks = <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
-		#thermal-sensor-cells = <0>;
-	};
-
 	ldb: ldb {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -156,7 +150,7 @@
 		interrupt-parent = <&gpc>;
 		ranges;
 
-		dma_apbh: dma-apbh@110000 {
+		dma_apbh: dma-controller@110000 {
 			compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh";
 			reg = <0x00110000 0x2000>;
 			interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>,
@@ -169,7 +163,7 @@
 			clocks = <&clks IMX6QDL_CLK_APBH_DMA>;
 		};
 
-		gpmi: gpmi-nand@112000 {
+		gpmi: nand-controller@112000 {
 			compatible = "fsl,imx6q-gpmi-nand";
 			reg = <0x00112000 0x2000>, <0x00114000 0x2000>;
 			reg-names = "gpmi-nand", "bch";
@@ -255,7 +249,7 @@
 			interrupt-parent = <&intc>;
 		};
 
-		L2: l2-cache@a02000 {
+		L2: cache-controller@a02000 {
 			compatible = "arm,pl310-cache";
 			reg = <0x00a02000 0x1000>;
 			interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
@@ -294,7 +288,7 @@
 			status = "disabled";
 		};
 
-		aips-bus@2000000 { /* AIPS1 */
+		bus@2000000 { /* AIPS1 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -509,7 +503,7 @@
 			};
 
 			pwm1: pwm@2080000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm";
 				reg = <0x02080000 0x4000>;
 				interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>;
@@ -520,7 +514,7 @@
 			};
 
 			pwm2: pwm@2084000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm";
 				reg = <0x02084000 0x4000>;
 				interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>;
@@ -531,7 +525,7 @@
 			};
 
 			pwm3: pwm@2088000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm";
 				reg = <0x02088000 0x4000>;
 				interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>;
@@ -542,7 +536,7 @@
 			};
 
 			pwm4: pwm@208c000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm";
 				reg = <0x0208c000 0x4000>;
 				interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
@@ -559,7 +553,7 @@
 				clocks = <&clks IMX6QDL_CLK_CAN1_IPG>,
 					 <&clks IMX6QDL_CLK_CAN1_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x34 28 0x10 17>;
+				fsl,stop-mode = <&gpr 0x34 28>;
 				status = "disabled";
 			};
 
@@ -570,11 +564,11 @@
 				clocks = <&clks IMX6QDL_CLK_CAN2_IPG>,
 					 <&clks IMX6QDL_CLK_CAN2_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x34 29 0x10 18>;
+				fsl,stop-mode = <&gpr 0x34 29>;
 				status = "disabled";
 			};
 
-			gpt: gpt@2098000 {
+			gpt: timer@2098000 {
 				compatible = "fsl,imx6q-gpt", "fsl,imx31-gpt";
 				reg = <0x02098000 0x4000>;
 				interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>;
@@ -661,7 +655,7 @@
 				#interrupt-cells = <2>;
 			};
 
-			kpp: kpp@20b8000 {
+			kpp: keypad@20b8000 {
 				compatible = "fsl,imx6q-kpp", "fsl,imx21-kpp";
 				reg = <0x020b8000 0x4000>;
 				interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>;
@@ -669,14 +663,14 @@
 				status = "disabled";
 			};
 
-			wdog1: wdog@20bc000 {
+			wdog1: watchdog@20bc000 {
 				compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
 				reg = <0x020bc000 0x4000>;
 				interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6QDL_CLK_IPG>;
 			};
 
-			wdog2: wdog@20c0000 {
+			wdog2: watchdog@20c0000 {
 				compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
 				reg = <0x020c0000 0x4000>;
 				interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>;
@@ -684,7 +678,7 @@
 				status = "disabled";
 			};
 
-			clks: ccm@20c4000 {
+			clks: clock-controller@20c4000 {
 				compatible = "fsl,imx6q-ccm";
 				reg = <0x020c4000 0x4000>;
 				interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>,
@@ -766,7 +760,7 @@
 					regulator-name = "vddpu";
 					regulator-min-microvolt = <725000>;
 					regulator-max-microvolt = <1450000>;
-					regulator-enable-ramp-delay = <150>;
+					regulator-enable-ramp-delay = <380>;
 					anatop-reg-offset = <0x140>;
 					anatop-vol-bit-shift = <9>;
 					anatop-vol-bit-width = <5>;
@@ -794,6 +788,17 @@
 					anatop-min-voltage = <725000>;
 					anatop-max-voltage = <1450000>;
 				};
+
+				tempmon: tempmon {
+					compatible = "fsl,imx6q-tempmon";
+					interrupt-parent = <&gpc>;
+					interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+					#thermal-sensor-cells = <0>;
+				};
 			};
 
 			usbphy1: usbphy@20c9000 {
@@ -857,7 +862,7 @@
 				interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			src: src@20d8000 {
+			src: reset-controller@20d8000 {
 				compatible = "fsl,imx6q-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -870,8 +875,7 @@
 				reg = <0x020dc000 0x4000>;
 				interrupt-controller;
 				#interrupt-cells = <3>;
-				interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>,
-					     <0 90 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-parent = <&intc>;
 				clocks = <&clks IMX6QDL_CLK_IPG>;
 				clock-names = "ipg";
@@ -908,7 +912,7 @@
 				};
 			};
 
-			iomuxc: iomuxc@20e0000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6dl-iomuxc", "fsl,imx6q-iomuxc";
 				reg = <0x20e0000 0x4000>;
 			};
@@ -935,14 +939,14 @@
 			};
 		};
 
-		aips-bus@2100000 { /* AIPS2 */
+		bus@2100000 { /* AIPS2 */
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			reg = <0x02100000 0x100000>;
 			ranges;
 
-			crypto: caam@2100000 {
+			crypto: crypto@2100000 {
 				compatible = "fsl,sec-v4.0";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -954,13 +958,13 @@
 					 <&clks IMX6QDL_CLK_EIM_SLOW>;
 				clock-names = "mem", "aclk", "ipg", "emi_slow";
 
-				sec_jr0: jr0@1000 {
+				sec_jr0: jr@1000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x1000 0x1000>;
 					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr1: jr1@2000 {
+				sec_jr1: jr@2000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x2000 0x1000>;
 					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
@@ -1039,13 +1043,13 @@
 				compatible = "fsl,imx6q-fec";
 				reg = <0x02188000 0x4000>;
 				interrupt-names = "int0", "pps";
-				interrupts-extended =
-					<&intc 0 118 IRQ_TYPE_LEVEL_HIGH>,
-					<&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>,
+					     <0 119 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6QDL_CLK_ENET>,
 					 <&clks IMX6QDL_CLK_ENET>,
 					 <&clks IMX6QDL_CLK_ENET_REF>;
 				clock-names = "ipg", "ahb", "ptp";
+				fsl,stop-mode = <&gpr 0x34 27>;
 				status = "disabled";
 			};
 
@@ -1056,7 +1060,7 @@
 					     <0 126 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			usdhc1: usdhc@2190000 {
+			usdhc1: mmc@2190000 {
 				compatible = "fsl,imx6q-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>;
@@ -1068,7 +1072,7 @@
 				status = "disabled";
 			};
 
-			usdhc2: usdhc@2194000 {
+			usdhc2: mmc@2194000 {
 				compatible = "fsl,imx6q-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
@@ -1080,7 +1084,7 @@
 				status = "disabled";
 			};
 
-			usdhc3: usdhc@2198000 {
+			usdhc3: mmc@2198000 {
 				compatible = "fsl,imx6q-usdhc";
 				reg = <0x02198000 0x4000>;
 				interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
@@ -1092,7 +1096,7 @@
 				status = "disabled";
 			};
 
-			usdhc4: usdhc@219c000 {
+			usdhc4: mmc@219c000 {
 				compatible = "fsl,imx6q-usdhc";
 				reg = <0x0219c000 0x4000>;
 				interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
@@ -1161,10 +1165,24 @@
 				status = "disabled";
 			};
 
-			ocotp: ocotp@21bc000 {
+			ocotp: efuse@21bc000 {
 				compatible = "fsl,imx6q-ocotp", "syscon";
 				reg = <0x021bc000 0x4000>;
 				clocks = <&clks IMX6QDL_CLK_IIM>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				cpu_speed_grade: speed-grade@10 {
+					reg = <0x10 4>;
+				};
+
+				tempmon_calib: calib@38 {
+					reg = <0x38 4>;
+				};
+
+				tempmon_temp_grade: temp-grade@20 {
+					reg = <0x20 4>;
+				};
 			};
 
 			tzasc@21d0000 { /* TZASC1 */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6qp.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6qp.dtsi
@@ -9,16 +9,22 @@
 		ocram2: sram@940000 {
 			compatible = "mmio-sram";
 			reg = <0x00940000 0x20000>;
+			ranges = <0 0x00940000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6QDL_CLK_OCRAM>;
 		};
 
 		ocram3: sram@960000 {
 			compatible = "mmio-sram";
 			reg = <0x00960000 0x20000>;
+			ranges = <0 0x00960000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6QDL_CLK_OCRAM>;
 		};
 
-		aips-bus@2100000 {
+		bus@2100000 {
 			pre1: pre@21c8000 {
 				compatible = "fsl,imx6qp-pre";
 				reg = <0x021c8000 0x1000>;
@@ -77,7 +83,6 @@
 };
 
 &fec {
-	/delete-property/interrupts-extended;
 	interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>,
 		     <0 119 IRQ_TYPE_LEVEL_HIGH>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sl-evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sl-evk.dts
@@ -575,6 +575,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -584,10 +585,6 @@
 	vin-supply = <&sw2_reg>;
 };
 
-&reg_vdd3p0 {
-	vin-supply = <&sw2_reg>;
-};
-
 &reg_vdd2p5 {
 	vin-supply = <&sw2_reg>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sl.dtsi
@@ -39,6 +39,9 @@
 		spi1 = &ecspi2;
 		spi2 = &ecspi3;
 		spi3 = &ecspi4;
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
+		usb2 = &usbh;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
 	};
@@ -74,6 +77,8 @@
 			arm-supply = <&reg_arm>;
 			pu-supply = <&reg_pu>;
 			soc-supply = <&reg_soc>;
+			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cell-names = "speed_grade";
 		};
 	};
 
@@ -91,15 +96,6 @@
 		};
 	};
 
-	tempmon: tempmon {
-		compatible = "fsl,imx6q-tempmon";
-		interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-parent = <&gpc>;
-		fsl,tempmon = <&anatop>;
-		fsl,tempmon-data = <&ocotp>;
-		clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>;
-	};
-
 	pmu {
 		compatible = "arm,cortex-a9-pmu";
 		interrupt-parent = <&gpc>;
@@ -121,6 +117,9 @@
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x20000>;
+			ranges = <0 0x00900000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6SL_CLK_OCRAM>;
 		};
 
@@ -133,7 +132,7 @@
 			interrupt-parent = <&intc>;
 		};
 
-		L2: l2-cache@a02000 {
+		L2: cache-controller@a02000 {
 			compatible = "arm,pl310-cache";
 			reg = <0x00a02000 0x1000>;
 			interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
@@ -143,7 +142,7 @@
 			arm,data-latency = <4 2 3>;
 		};
 
-		aips1: aips-bus@2000000 {
+		aips1: bus@2000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -341,7 +340,7 @@
 			};
 
 			pwm1: pwm@2080000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
 				reg = <0x02080000 0x4000>;
 				interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>;
@@ -351,7 +350,7 @@
 			};
 
 			pwm2: pwm@2084000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
 				reg = <0x02084000 0x4000>;
 				interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>;
@@ -361,7 +360,7 @@
 			};
 
 			pwm3: pwm@2088000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
 				reg = <0x02088000 0x4000>;
 				interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>;
@@ -371,7 +370,7 @@
 			};
 
 			pwm4: pwm@208c000 {
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm";
 				reg = <0x0208c000 0x4000>;
 				interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
@@ -380,7 +379,7 @@
 				clock-names = "ipg", "per";
 			};
 
-			gpt: gpt@2098000 {
+			gpt: timer@2098000 {
 				compatible = "fsl,imx6sl-gpt";
 				reg = <0x02098000 0x4000>;
 				interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>;
@@ -491,7 +490,7 @@
 					      <&iomuxc 21 161 1>;
 			};
 
-			kpp: kpp@20b8000 {
+			kpp: keypad@20b8000 {
 				compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp";
 				reg = <0x020b8000 0x4000>;
 				interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>;
@@ -499,14 +498,14 @@
 				status = "disabled";
 			};
 
-			wdog1: wdog@20bc000 {
+			wdog1: watchdog@20bc000 {
 				compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
 				reg = <0x020bc000 0x4000>;
 				interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SL_CLK_IPG>;
 			};
 
-			wdog2: wdog@20c0000 {
+			wdog2: watchdog@20c0000 {
 				compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt";
 				reg = <0x020c0000 0x4000>;
 				interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>;
@@ -514,7 +513,7 @@
 				status = "disabled";
 			};
 
-			clks: ccm@20c4000 {
+			clks: clock-controller@20c4000 {
 				compatible = "fsl,imx6sl-ccm";
 				reg = <0x020c4000 0x4000>;
 				interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>,
@@ -525,7 +524,7 @@
 			anatop: anatop@20c8000 {
 				compatible = "fsl,imx6sl-anatop",
 					     "fsl,imx6q-anatop",
-					     "syscon", "simple-bus";
+					     "syscon", "simple-mfd";
 				reg = <0x020c8000 0x1000>;
 				interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>,
 					     <0 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -625,6 +624,16 @@
 					anatop-min-voltage = <725000>;
 					anatop-max-voltage = <1450000>;
 				};
+
+				tempmon: tempmon {
+					compatible = "fsl,imx6q-tempmon";
+					interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>;
+					interrupt-parent = <&gpc>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>;
+				};
 			};
 
 			usbphy1: usbphy@20c9000 {
@@ -675,7 +684,7 @@
 				interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			src: src@20d8000 {
+			src: reset-controller@20d8000 {
 				compatible = "fsl,imx6sl-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -728,7 +737,7 @@
 				reg = <0x020e0000 0x38>;
 			};
 
-			iomuxc: iomuxc@20e0000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6sl-iomuxc";
 				reg = <0x020e0000 0x4000>;
 			};
@@ -777,7 +786,7 @@
 				power-domains = <&pd_disp>;
 			};
 
-			dcp: dcp@20fc000 {
+			dcp: crypto@20fc000 {
 				compatible = "fsl,imx6sl-dcp", "fsl,imx28-dcp";
 				reg = <0x020fc000 0x4000>;
 				interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>,
@@ -786,7 +795,7 @@
 			};
 		};
 
-		aips2: aips-bus@2100000 {
+		aips2: bus@2100000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -851,7 +860,7 @@
 				status = "disabled";
 			};
 
-			usdhc1: usdhc@2190000 {
+			usdhc1: mmc@2190000 {
 				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>;
@@ -863,7 +872,7 @@
 				status = "disabled";
 			};
 
-			usdhc2: usdhc@2194000 {
+			usdhc2: mmc@2194000 {
 				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
@@ -875,7 +884,7 @@
 				status = "disabled";
 			};
 
-			usdhc3: usdhc@2198000 {
+			usdhc3: mmc@2198000 {
 				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
 				reg = <0x02198000 0x4000>;
 				interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
@@ -887,7 +896,7 @@
 				status = "disabled";
 			};
 
-			usdhc4: usdhc@219c000 {
+			usdhc4: mmc@219c000 {
 				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
 				reg = <0x0219c000 0x4000>;
 				interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
@@ -936,8 +945,10 @@
 			};
 
 			rngb: rngb@21b4000 {
+				compatible = "fsl,imx6sl-rngb", "fsl,imx25-rngb";
 				reg = <0x021b4000 0x4000>;
 				interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6SL_CLK_DUMMY>;
 			};
 
 			weim: weim@21b8000 {
@@ -949,10 +960,24 @@
 				status = "disabled";
 			};
 
-			ocotp: ocotp@21bc000 {
+			ocotp: efuse@21bc000 {
 				compatible = "fsl,imx6sl-ocotp", "syscon";
 				reg = <0x021bc000 0x4000>;
 				clocks = <&clks IMX6SL_CLK_OCOTP>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				cpu_speed_grade: speed-grade@10 {
+					reg = <0x10 4>;
+				};
+
+				tempmon_calib: calib@38 {
+					reg = <0x38 4>;
+				};
+
+				tempmon_temp_grade: temp-grade@20 {
+					reg = <0x20 4>;
+				};
 			};
 
 			audmux: audmux@21d8000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sll-evk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sll-evk.dts
@@ -260,15 +260,12 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
-&reg_3p0 {
-	vin-supply = <&sw2_reg>;
-};
-
 &snvs_poweroff {
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sll.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sll.dtsi
@@ -36,6 +36,8 @@
 		spi1 = &ecspi2;
 		spi3 = &ecspi3;
 		spi4 = &ecspi4;
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
 	};
@@ -49,20 +51,18 @@
 			device_type = "cpu";
 			reg = <0>;
 			next-level-cache = <&L2>;
-			operating-points = <
+			operating-points =
 				/* kHz    uV */
-				996000  1275000
-				792000  1175000
-				396000  1075000
-				198000	975000
-			>;
-			fsl,soc-operating-points = <
+				<996000  1275000>,
+				<792000  1175000>,
+				<396000  1075000>,
+				<198000	  975000>;
+			fsl,soc-operating-points =
 				/* ARM kHz      SOC-PU uV */
-				996000          1175000
-				792000          1175000
-				396000          1175000
-				198000		1175000
-			>;
+				<996000         1175000>,
+				<792000         1175000>,
+				<396000         1175000>,
+				<198000		1175000>;
 			clock-latency = <61036>; /* two CLK32 periods */
 			#cooling-cells = <2>;
 			clocks = <&clks IMX6SLL_CLK_ARM>,
@@ -72,6 +72,8 @@
 				 <&clks IMX6SLL_CLK_PLL1_SYS>;
 			clock-names = "arm", "pll2_pfd2_396m", "step",
 				      "pll1_sw", "pll1_sys";
+			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cell-names = "speed_grade";
 		};
 	};
 
@@ -103,16 +105,6 @@
 		clock-output-names = "ipp_di1";
 	};
 
-	tempmon: temperature-sensor {
-		compatible = "fsl,imx6sll-tempmon", "fsl,imx6sx-tempmon";
-		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-parent = <&gpc>;
-		fsl,tempmon = <&anatop>;
-		nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
-		nvmem-cell-names = "calib", "temp_grade";
-		clocks = <&clks IMX6SLL_CLK_PLL3_USB_OTG>;
-	};
-
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -123,6 +115,9 @@
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x20000>;
+			ranges = <0 0x00900000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 		};
 
 		intc: interrupt-controller@a01000 {
@@ -134,7 +129,7 @@
 			interrupt-parent = <&intc>;
 		};
 
-		L2: l2-cache@a02000 {
+		L2: cache-controller@a02000 {
 			compatible = "arm,pl310-cache";
 			reg = <0x00a02000 0x1000>;
 			interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
@@ -144,7 +139,7 @@
 			arm,data-latency = <4 2 3>;
 		};
 
-		aips1: aips-bus@2000000 {
+		aips1: bus@2000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -269,7 +264,7 @@
 					status = "disabled";
 				};
 
-				ssi1: ssi-controller@2028000 {
+				ssi1: ssi@2028000 {
 					compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
 					reg = <0x02028000 0x4000>;
 					interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
@@ -282,7 +277,7 @@
 					status = "disabled";
 				};
 
-				ssi2: ssi-controller@202c000 {
+				ssi2: ssi@202c000 {
 					compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
 					reg = <0x0202c000 0x4000>;
 					interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
@@ -295,7 +290,7 @@
 					status = "disabled";
 				};
 
-				ssi3: ssi-controller@2030000 {
+				ssi3: ssi@2030000 {
 					compatible = "fsl,imx6sl-ssi", "fsl,imx51-ssi";
 					reg = <0x02030000 0x4000>;
 					interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
@@ -329,7 +324,7 @@
 				clocks = <&clks IMX6SLL_CLK_PWM1>,
 					 <&clks IMX6SLL_CLK_PWM1>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm2: pwm@2084000 {
@@ -339,7 +334,7 @@
 				clocks = <&clks IMX6SLL_CLK_PWM2>,
 					 <&clks IMX6SLL_CLK_PWM2>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm3: pwm@2088000 {
@@ -349,7 +344,7 @@
 				clocks = <&clks IMX6SLL_CLK_PWM3>,
 					 <&clks IMX6SLL_CLK_PWM3>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm4: pwm@208c000 {
@@ -359,7 +354,7 @@
 				clocks = <&clks IMX6SLL_CLK_PWM4>,
 					 <&clks IMX6SLL_CLK_PWM4>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			gpt1: timer@2098000 {
@@ -507,7 +502,7 @@
 			anatop: anatop@20c8000 {
 				compatible = "fsl,imx6sll-anatop",
 					     "fsl,imx6q-anatop",
-					     "syscon", "simple-bus";
+					     "syscon", "simple-mfd";
 				reg = <0x020c8000 0x4000>;
 				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -529,6 +524,16 @@
 					anatop-max-voltage = <3400000>;
 					anatop-enable-bit = <0>;
 				};
+
+				tempmon: temperature-sensor {
+					compatible = "fsl,imx6sll-tempmon", "fsl,imx6sx-tempmon";
+					interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+					interrupt-parent = <&gpc>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX6SLL_CLK_PLL3_USB_OTG>;
+				};
 			};
 
 			usbphy1: usb-phy@20c9000 {
@@ -547,7 +552,7 @@
 				reg = <0x020ca000 0x1000>;
 				interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SLL_CLK_USBPHY2>;
-				phy-reg_3p0-supply = <&reg_3p0>;
+				phy-3p0-supply = <&reg_3p0>;
 				fsl,anatop = <&anatop>;
 			};
 
@@ -643,7 +648,7 @@
 				status = "disabled";
 			};
 
-			dcp: dcp@20fc000 {
+			dcp: crypto@20fc000 {
 				compatible = "fsl,imx28-dcp";
 				reg = <0x020fc000 0x4000>;
 				interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
@@ -654,7 +659,7 @@
 			};
 		};
 
-		aips2: aips-bus@2100000 {
+		aips2: bus@2100000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -775,13 +780,17 @@
 				clocks = <&clks IMX6SLL_CLK_MMDC_P0_IPG>;
 			};
 
-			ocotp: ocotp-ctrl@21bc000 {
+			ocotp: efuse@21bc000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				compatible = "fsl,imx6sll-ocotp", "syscon";
 				reg = <0x021bc000 0x4000>;
 				clocks = <&clks IMX6SLL_CLK_OCOTP>;
 
+				cpu_speed_grade: speed-grade@10 {
+					reg = <0x10 4>;
+				};
+
 				tempmon_calib: calib@38 {
 					reg = <0x38 4>;
 				};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts
@@ -229,6 +229,7 @@
 };
 
 &pwm4 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
 	status = "okay";
@@ -484,31 +485,31 @@
 
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
-			MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1
-			MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX		0x1b0b1
 		>;
 	};
 
 	pinctrl_uart2: uart2grp {
 		fsl,pins = <
-			MX6SX_PAD_GPIO1_IO06__UART2_TX		0x1b0b1
-			MX6SX_PAD_GPIO1_IO07__UART2_RX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX		0x1b0b1
 		>;
 	};
 
 	pinctrl_uart3: uart3grp {
 		fsl,pins = <
-			MX6SX_PAD_QSPI1B_SS0_B__UART3_TX	0x1b0b1
-			MX6SX_PAD_QSPI1B_SCLK__UART3_RX		0x1b0b1
+			MX6SX_PAD_QSPI1B_SS0_B__UART3_DCE_TX		0x1b0b1
+			MX6SX_PAD_QSPI1B_SCLK__UART3_DCE_RX		0x1b0b1
 		>;
 	};
 
 	pinctrl_uart5: uart5grp {
 		fsl,pins = <
-			MX6SX_PAD_KEY_COL3__UART5_TX		0x1b0b1
-			MX6SX_PAD_KEY_ROW3__UART5_RX		0x1b0b1
-			MX6SX_PAD_SD3_DATA6__UART3_RTS_B	0x1b0b1
-			MX6SX_PAD_SD3_DATA7__UART3_CTS_B	0x1b0b1
+			MX6SX_PAD_KEY_COL3__UART5_DCE_TX		0x1b0b1
+			MX6SX_PAD_KEY_ROW3__UART5_DCE_RX		0x1b0b1
+			MX6SX_PAD_SD3_DATA6__UART3_DCE_RTS		0x1b0b1
+			MX6SX_PAD_SD3_DATA7__UART3_DCE_CTS		0x1b0b1
 		>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-pinfunc.h
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-pinfunc.h
@@ -42,8 +42,8 @@
 #define MX6SX_PAD_GPIO1_IO03__GPIO1_IO_3                          0x0020 0x0368 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO03__CCM_PLL3_BYP                        0x0020 0x0368 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO03__PHY_TCK                             0x0020 0x0368 0x0000 0x7 0x0
-#define MX6SX_PAD_GPIO1_IO04__UART1_RX                            0x0024 0x036C 0x0830 0x0 0x0
-#define MX6SX_PAD_GPIO1_IO04__UART1_TX                            0x0024 0x036C 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX                        0x0024 0x036C 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO04__UART1_DTE_RX                        0x0024 0x036C 0x0830 0x0 0x0
 #define MX6SX_PAD_GPIO1_IO04__USDHC2_RESET_B                      0x0024 0x036C 0x0000 0x1 0x0
 #define MX6SX_PAD_GPIO1_IO04__ENET1_MDC                           0x0024 0x036C 0x0000 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO04__OSC32K_32K_OUT                      0x0024 0x036C 0x0000 0x3 0x0
@@ -51,8 +51,8 @@
 #define MX6SX_PAD_GPIO1_IO04__GPIO1_IO_4                          0x0024 0x036C 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO04__CCM_PLL2_BYP                        0x0024 0x036C 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO04__PHY_TMS                             0x0024 0x036C 0x0000 0x7 0x0
-#define MX6SX_PAD_GPIO1_IO05__UART1_RX                            0x0028 0x0370 0x0830 0x0 0x1
-#define MX6SX_PAD_GPIO1_IO05__UART1_TX                            0x0028 0x0370 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX                        0x0028 0x0370 0x0830 0x0 0x1
+#define MX6SX_PAD_GPIO1_IO05__UART1_DTE_TX                        0x0028 0x0370 0x0000 0x0 0x0
 #define MX6SX_PAD_GPIO1_IO05__USDHC2_VSELECT                      0x0028 0x0370 0x0000 0x1 0x0
 #define MX6SX_PAD_GPIO1_IO05__ENET1_MDIO                          0x0028 0x0370 0x0764 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO05__ASRC_ASRC_EXT_CLK                   0x0028 0x0370 0x0000 0x3 0x0
@@ -60,21 +60,23 @@
 #define MX6SX_PAD_GPIO1_IO05__GPIO1_IO_5                          0x0028 0x0370 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO05__SRC_TESTER_ACK                      0x0028 0x0370 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO05__PHY_TDO                             0x0028 0x0370 0x0000 0x7 0x0
-#define MX6SX_PAD_GPIO1_IO06__UART2_RX                            0x002C 0x0374 0x0838 0x0 0x0
-#define MX6SX_PAD_GPIO1_IO06__UART2_TX                            0x002C 0x0374 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX                        0x002C 0x0374 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO06__UART2_DTE_RX                        0x002C 0x0374 0x0838 0x0 0x0
 #define MX6SX_PAD_GPIO1_IO06__USDHC2_CD_B                         0x002C 0x0374 0x086C 0x1 0x1
 #define MX6SX_PAD_GPIO1_IO06__ENET2_MDC                           0x002C 0x0374 0x0000 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO06__CSI1_MCLK                           0x002C 0x0374 0x0000 0x3 0x0
-#define MX6SX_PAD_GPIO1_IO06__UART1_RTS_B                         0x002C 0x0374 0x082C 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO06__UART1_DCE_RTS                       0x002C 0x0374 0x082C 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO06__UART1_DTE_CTS                       0x002C 0x0374 0x0000 0x4 0x0
 #define MX6SX_PAD_GPIO1_IO06__GPIO1_IO_6                          0x002C 0x0374 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO06__SRC_ANY_PU_RESET                    0x002C 0x0374 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO06__OCOTP_CTRL_WRAPPER_FUSE_LATCHED     0x002C 0x0374 0x0000 0x7 0x0
-#define MX6SX_PAD_GPIO1_IO07__UART2_RX                            0x0030 0x0378 0x0838 0x0 0x1
-#define MX6SX_PAD_GPIO1_IO07__UART2_TX                            0x0030 0x0378 0x0000 0x0 0x0
+#define MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX                        0x0030 0x0378 0x0838 0x0 0x1
+#define MX6SX_PAD_GPIO1_IO07__UART2_DTE_TX                        0x0030 0x0378 0x0000 0x0 0x0
 #define MX6SX_PAD_GPIO1_IO07__USDHC2_WP                           0x0030 0x0378 0x0870 0x1 0x1
 #define MX6SX_PAD_GPIO1_IO07__ENET2_MDIO                          0x0030 0x0378 0x0770 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO07__AUDMUX_MCLK                         0x0030 0x0378 0x0000 0x3 0x0
-#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B                         0x0030 0x0378 0x0000 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO07__UART1_DCE_CTS                       0x0030 0x0378 0x0000 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO07__UART1_DTE_RTS                       0x0030 0x0378 0x082C 0x4 0x1
 #define MX6SX_PAD_GPIO1_IO07__GPIO1_IO_7                          0x0030 0x0378 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO07__SRC_EARLY_RESET                     0x0030 0x0378 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO07__DCIC2_OUT                           0x0030 0x0378 0x0000 0x7 0x0
@@ -83,7 +85,8 @@
 #define MX6SX_PAD_GPIO1_IO08__WDOG1_WDOG_B                        0x0034 0x037C 0x0000 0x1 0x0
 #define MX6SX_PAD_GPIO1_IO08__SDMA_EXT_EVENT_0                    0x0034 0x037C 0x081C 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO08__CCM_PMIC_RDY                        0x0034 0x037C 0x069C 0x3 0x1
-#define MX6SX_PAD_GPIO1_IO08__UART2_RTS_B                         0x0034 0x037C 0x0834 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO08__UART2_DCE_RTS                       0x0034 0x037C 0x0834 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO08__UART2_DTE_CTS                       0x0034 0x037C 0x0000 0x4 0x0
 #define MX6SX_PAD_GPIO1_IO08__GPIO1_IO_8                          0x0034 0x037C 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO08__SRC_SYSTEM_RESET                    0x0034 0x037C 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO08__DCIC1_OUT                           0x0034 0x037C 0x0000 0x7 0x0
@@ -92,7 +95,8 @@
 #define MX6SX_PAD_GPIO1_IO09__WDOG2_WDOG_B                        0x0038 0x0380 0x0000 0x1 0x0
 #define MX6SX_PAD_GPIO1_IO09__SDMA_EXT_EVENT_1                    0x0038 0x0380 0x0820 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO09__CCM_OUT0                            0x0038 0x0380 0x0000 0x3 0x0
-#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B                         0x0038 0x0380 0x0000 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO09__UART2_DCE_CTS                       0x0038 0x0380 0x0000 0x4 0x0
+#define MX6SX_PAD_GPIO1_IO09__UART2_DTE_RTS                       0x0038 0x0380 0x0834 0x4 0x1
 #define MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9                          0x0038 0x0380 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO09__SRC_INT_BOOT                        0x0038 0x0380 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO09__OBSERVE_MUX_OUT_4                   0x0038 0x0380 0x0000 0x7 0x0
@@ -177,8 +181,8 @@
 #define MX6SX_PAD_CSI_DATA04__ESAI_TX1                            0x005C 0x03A4 0x0794 0x1 0x1
 #define MX6SX_PAD_CSI_DATA04__SPDIF_OUT                           0x005C 0x03A4 0x0000 0x2 0x0
 #define MX6SX_PAD_CSI_DATA04__KPP_COL_6                           0x005C 0x03A4 0x07CC 0x3 0x0
-#define MX6SX_PAD_CSI_DATA04__UART6_RX                            0x005C 0x03A4 0x0858 0x4 0x0
-#define MX6SX_PAD_CSI_DATA04__UART6_TX                            0x005C 0x03A4 0x0000 0x4 0x0
+#define MX6SX_PAD_CSI_DATA04__UART6_DCE_RX                        0x005C 0x03A4 0x0858 0x4 0x0
+#define MX6SX_PAD_CSI_DATA04__UART6_DTE_TX                        0x005C 0x03A4 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_DATA04__GPIO1_IO_18                         0x005C 0x03A4 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_DATA04__WEIM_DATA_19                        0x005C 0x03A4 0x0000 0x6 0x0
 #define MX6SX_PAD_CSI_DATA04__PWM5_OUT                            0x005C 0x03A4 0x0000 0x7 0x0
@@ -188,8 +192,8 @@
 #define MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1                        0x0060 0x03A8 0x07A0 0x1 0x1
 #define MX6SX_PAD_CSI_DATA05__SPDIF_IN                            0x0060 0x03A8 0x0824 0x2 0x1
 #define MX6SX_PAD_CSI_DATA05__KPP_ROW_6                           0x0060 0x03A8 0x07D8 0x3 0x0
-#define MX6SX_PAD_CSI_DATA05__UART6_RX                            0x0060 0x03A8 0x0858 0x4 0x1
-#define MX6SX_PAD_CSI_DATA05__UART6_TX                            0x0060 0x03A8 0x0000 0x4 0x0
+#define MX6SX_PAD_CSI_DATA05__UART6_DCE_TX                        0x0060 0x03A8 0x0000 0x4 0x0
+#define MX6SX_PAD_CSI_DATA05__UART6_DTE_RX                        0x0060 0x03A8 0x0858 0x4 0x1
 #define MX6SX_PAD_CSI_DATA05__GPIO1_IO_19                         0x0060 0x03A8 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_DATA05__WEIM_DATA_18                        0x0060 0x03A8 0x0000 0x6 0x0
 #define MX6SX_PAD_CSI_DATA05__PWM6_OUT                            0x0060 0x03A8 0x0000 0x7 0x0
@@ -199,7 +203,8 @@
 #define MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3                        0x0064 0x03AC 0x0798 0x1 0x1
 #define MX6SX_PAD_CSI_DATA06__I2C4_SCL                            0x0064 0x03AC 0x07C0 0x2 0x2
 #define MX6SX_PAD_CSI_DATA06__KPP_COL_7                           0x0064 0x03AC 0x07D0 0x3 0x0
-#define MX6SX_PAD_CSI_DATA06__UART6_RTS_B                         0x0064 0x03AC 0x0854 0x4 0x0
+#define MX6SX_PAD_CSI_DATA06__UART6_DCE_RTS                       0x0064 0x03AC 0x0854 0x4 0x0
+#define MX6SX_PAD_CSI_DATA06__UART6_DTE_CTS                       0x0064 0x03AC 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_DATA06__GPIO1_IO_20                         0x0064 0x03AC 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_DATA06__WEIM_DATA_17                        0x0064 0x03AC 0x0000 0x6 0x0
 #define MX6SX_PAD_CSI_DATA06__DCIC2_OUT                           0x0064 0x03AC 0x0000 0x7 0x0
@@ -209,7 +214,8 @@
 #define MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2                        0x0068 0x03B0 0x079C 0x1 0x1
 #define MX6SX_PAD_CSI_DATA07__I2C4_SDA                            0x0068 0x03B0 0x07C4 0x2 0x2
 #define MX6SX_PAD_CSI_DATA07__KPP_ROW_7                           0x0068 0x03B0 0x07DC 0x3 0x0
-#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B                         0x0068 0x03B0 0x0000 0x4 0x0
+#define MX6SX_PAD_CSI_DATA07__UART6_DCE_CTS                       0x0068 0x03B0 0x0000 0x4 0x0
+#define MX6SX_PAD_CSI_DATA07__UART6_DTE_RTS                       0x0068 0x03B0 0x0854 0x4 0x1
 #define MX6SX_PAD_CSI_DATA07__GPIO1_IO_21                         0x0068 0x03B0 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_DATA07__WEIM_DATA_16                        0x0068 0x03B0 0x0000 0x6 0x0
 #define MX6SX_PAD_CSI_DATA07__DCIC1_OUT                           0x0068 0x03B0 0x0000 0x7 0x0
@@ -218,7 +224,8 @@
 #define MX6SX_PAD_CSI_HSYNC__CSI1_HSYNC                           0x006C 0x03B4 0x0700 0x0 0x0
 #define MX6SX_PAD_CSI_HSYNC__ESAI_TX0                             0x006C 0x03B4 0x0790 0x1 0x1
 #define MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD                      0x006C 0x03B4 0x0678 0x2 0x1
-#define MX6SX_PAD_CSI_HSYNC__UART4_RTS_B                          0x006C 0x03B4 0x0844 0x3 0x2
+#define MX6SX_PAD_CSI_HSYNC__UART4_DCE_RTS                        0x006C 0x03B4 0x0844 0x3 0x2
+#define MX6SX_PAD_CSI_HSYNC__UART4_DTE_CTS                        0x006C 0x03B4 0x0000 0x3 0x0
 #define MX6SX_PAD_CSI_HSYNC__MQS_LEFT                             0x006C 0x03B4 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_HSYNC__GPIO1_IO_22                          0x006C 0x03B4 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_HSYNC__WEIM_DATA_25                         0x006C 0x03B4 0x0000 0x6 0x0
@@ -228,8 +235,8 @@
 #define MX6SX_PAD_CSI_MCLK__CSI1_MCLK                             0x0070 0x03B8 0x0000 0x0 0x0
 #define MX6SX_PAD_CSI_MCLK__ESAI_TX_HF_CLK                        0x0070 0x03B8 0x0784 0x1 0x1
 #define MX6SX_PAD_CSI_MCLK__OSC32K_32K_OUT                        0x0070 0x03B8 0x0000 0x2 0x0
-#define MX6SX_PAD_CSI_MCLK__UART4_RX                              0x0070 0x03B8 0x0848 0x3 0x2
-#define MX6SX_PAD_CSI_MCLK__UART4_TX                              0x0070 0x03B8 0x0000 0x3 0x0
+#define MX6SX_PAD_CSI_MCLK__UART4_DCE_RX                          0x0070 0x03B8 0x0848 0x3 0x2
+#define MX6SX_PAD_CSI_MCLK__UART4_DTE_TX                          0x0070 0x03B8 0x0000 0x3 0x0
 #define MX6SX_PAD_CSI_MCLK__ANATOP_32K_OUT                        0x0070 0x03B8 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_MCLK__GPIO1_IO_23                           0x0070 0x03B8 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_MCLK__WEIM_DATA_26                          0x0070 0x03B8 0x0000 0x6 0x0
@@ -239,8 +246,8 @@
 #define MX6SX_PAD_CSI_PIXCLK__CSI1_PIXCLK                         0x0074 0x03BC 0x0704 0x0 0x0
 #define MX6SX_PAD_CSI_PIXCLK__ESAI_RX_HF_CLK                      0x0074 0x03BC 0x0780 0x1 0x1
 #define MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK                         0x0074 0x03BC 0x0000 0x2 0x0
-#define MX6SX_PAD_CSI_PIXCLK__UART4_RX                            0x0074 0x03BC 0x0848 0x3 0x3
-#define MX6SX_PAD_CSI_PIXCLK__UART4_TX                            0x0074 0x03BC 0x0000 0x3 0x0
+#define MX6SX_PAD_CSI_PIXCLK__UART4_DCE_TX                        0x0074 0x03BC 0x0000 0x3 0x0
+#define MX6SX_PAD_CSI_PIXCLK__UART4_DTE_RX                        0x0074 0x03BC 0x0848 0x3 0x3
 #define MX6SX_PAD_CSI_PIXCLK__ANATOP_24M_OUT                      0x0074 0x03BC 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_PIXCLK__GPIO1_IO_24                         0x0074 0x03BC 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_PIXCLK__WEIM_DATA_27                        0x0074 0x03BC 0x0000 0x6 0x0
@@ -250,7 +257,8 @@
 #define MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC                           0x0078 0x03C0 0x0708 0x0 0x0
 #define MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0                         0x0078 0x03C0 0x07A4 0x1 0x1
 #define MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD                      0x0078 0x03C0 0x0674 0x2 0x1
-#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B                          0x0078 0x03C0 0x0000 0x3 0x0
+#define MX6SX_PAD_CSI_VSYNC__UART4_DCE_CTS                        0x0078 0x03C0 0x0000 0x3 0x0
+#define MX6SX_PAD_CSI_VSYNC__UART4_DTE_RTS                        0x0078 0x03C0 0x0844 0x3 0x3
 #define MX6SX_PAD_CSI_VSYNC__MQS_RIGHT                            0x0078 0x03C0 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_VSYNC__GPIO1_IO_25                          0x0078 0x03C0 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_VSYNC__WEIM_DATA_24                         0x0078 0x03C0 0x0000 0x6 0x0
@@ -330,8 +338,8 @@
 #define MX6SX_PAD_ENET2_COL__ENET2_COL                            0x0094 0x03DC 0x0000 0x0 0x0
 #define MX6SX_PAD_ENET2_COL__ENET1_MDC                            0x0094 0x03DC 0x0000 0x1 0x0
 #define MX6SX_PAD_ENET2_COL__AUDMUX_AUD4_RXC                      0x0094 0x03DC 0x064C 0x2 0x1
-#define MX6SX_PAD_ENET2_COL__UART1_RX                             0x0094 0x03DC 0x0830 0x3 0x2
-#define MX6SX_PAD_ENET2_COL__UART1_TX                             0x0094 0x03DC 0x0000 0x3 0x0
+#define MX6SX_PAD_ENET2_COL__UART1_DCE_RX                         0x0094 0x03DC 0x0830 0x3 0x2
+#define MX6SX_PAD_ENET2_COL__UART1_DTE_TX                         0x0094 0x03DC 0x0000 0x3 0x0
 #define MX6SX_PAD_ENET2_COL__SPDIF_IN                             0x0094 0x03DC 0x0824 0x4 0x3
 #define MX6SX_PAD_ENET2_COL__GPIO2_IO_6                           0x0094 0x03DC 0x0000 0x5 0x0
 #define MX6SX_PAD_ENET2_COL__ANATOP_OTG1_ID                       0x0094 0x03DC 0x0624 0x6 0x1
@@ -341,8 +349,8 @@
 #define MX6SX_PAD_ENET2_CRS__ENET2_CRS                            0x0098 0x03E0 0x0000 0x0 0x0
 #define MX6SX_PAD_ENET2_CRS__ENET1_MDIO                           0x0098 0x03E0 0x0764 0x1 0x2
 #define MX6SX_PAD_ENET2_CRS__AUDMUX_AUD4_RXFS                     0x0098 0x03E0 0x0650 0x2 0x1
-#define MX6SX_PAD_ENET2_CRS__UART1_RX                             0x0098 0x03E0 0x0830 0x3 0x3
-#define MX6SX_PAD_ENET2_CRS__UART1_TX                             0x0098 0x03E0 0x0000 0x3 0x0
+#define MX6SX_PAD_ENET2_CRS__UART1_DCE_TX                         0x0098 0x03E0 0x0000 0x3 0x0
+#define MX6SX_PAD_ENET2_CRS__UART1_DTE_RX                         0x0098 0x03E0 0x0830 0x3 0x3
 #define MX6SX_PAD_ENET2_CRS__MLB_SIG                              0x0098 0x03E0 0x07F0 0x4 0x1
 #define MX6SX_PAD_ENET2_CRS__GPIO2_IO_7                           0x0098 0x03E0 0x0000 0x5 0x0
 #define MX6SX_PAD_ENET2_CRS__ANATOP_OTG2_ID                       0x0098 0x03E0 0x0628 0x6 0x1
@@ -352,7 +360,8 @@
 #define MX6SX_PAD_ENET2_RX_CLK__ENET2_RX_CLK                      0x009C 0x03E4 0x0774 0x0 0x0
 #define MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M                 0x009C 0x03E4 0x0000 0x1 0x0
 #define MX6SX_PAD_ENET2_RX_CLK__I2C3_SCL                          0x009C 0x03E4 0x07B8 0x2 0x1
-#define MX6SX_PAD_ENET2_RX_CLK__UART1_RTS_B                       0x009C 0x03E4 0x082C 0x3 0x2
+#define MX6SX_PAD_ENET2_RX_CLK__UART1_DCE_RTS                     0x009C 0x03E4 0x082C 0x3 0x2
+#define MX6SX_PAD_ENET2_RX_CLK__UART1_DTE_CTS                     0x009C 0x03E4 0x0000 0x3 0x0
 #define MX6SX_PAD_ENET2_RX_CLK__MLB_DATA                          0x009C 0x03E4 0x07EC 0x4 0x1
 #define MX6SX_PAD_ENET2_RX_CLK__GPIO2_IO_8                        0x009C 0x03E4 0x0000 0x5 0x0
 #define MX6SX_PAD_ENET2_RX_CLK__USB_OTG2_OC                       0x009C 0x03E4 0x085C 0x6 0x1
@@ -362,7 +371,8 @@
 #define MX6SX_PAD_ENET2_TX_CLK__ENET2_TX_CLK                      0x00A0 0x03E8 0x0000 0x0 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2                    0x00A0 0x03E8 0x076C 0x1 0x1
 #define MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA                          0x00A0 0x03E8 0x07BC 0x2 0x1
-#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B                       0x00A0 0x03E8 0x0000 0x3 0x0
+#define MX6SX_PAD_ENET2_TX_CLK__UART1_DCE_CTS                     0x00A0 0x03E8 0x0000 0x3 0x0
+#define MX6SX_PAD_ENET2_TX_CLK__UART1_DTE_RTS                     0x00A0 0x03E8 0x082C 0x3 0x3
 #define MX6SX_PAD_ENET2_TX_CLK__MLB_CLK                           0x00A0 0x03E8 0x07E8 0x4 0x1
 #define MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9                        0x00A0 0x03E8 0x0000 0x5 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__USB_OTG2_PWR                      0x00A0 0x03E8 0x0000 0x6 0x0
@@ -371,7 +381,8 @@
 #define MX6SX_PAD_ENET2_TX_CLK__PCIE_CTRL_DEBUG_24                0x00A0 0x03E8 0x0000 0x9 0x0
 #define MX6SX_PAD_KEY_COL0__KPP_COL_0                             0x00A4 0x03EC 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_COL0__USDHC3_CD_B                           0x00A4 0x03EC 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_COL0__UART6_RTS_B                           0x00A4 0x03EC 0x0854 0x2 0x2
+#define MX6SX_PAD_KEY_COL0__UART6_DCE_RTS                         0x00A4 0x03EC 0x0854 0x2 0x2
+#define MX6SX_PAD_KEY_COL0__UART6_DTE_CTS                         0x00A4 0x03EC 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_COL0__ECSPI1_SCLK                           0x00A4 0x03EC 0x0710 0x3 0x0
 #define MX6SX_PAD_KEY_COL0__AUDMUX_AUD5_TXC                       0x00A4 0x03EC 0x066C 0x4 0x0
 #define MX6SX_PAD_KEY_COL0__GPIO2_IO_10                           0x00A4 0x03EC 0x0000 0x5 0x0
@@ -380,8 +391,8 @@
 #define MX6SX_PAD_KEY_COL0__VADC_DATA_0                           0x00A4 0x03EC 0x0000 0x8 0x0
 #define MX6SX_PAD_KEY_COL1__KPP_COL_1                             0x00A8 0x03F0 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_COL1__USDHC3_RESET_B                        0x00A8 0x03F0 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_COL1__UART6_RX                              0x00A8 0x03F0 0x0858 0x2 0x2
-#define MX6SX_PAD_KEY_COL1__UART6_TX                              0x00A8 0x03F0 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_COL1__UART6_DCE_TX                          0x00A8 0x03F0 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_COL1__UART6_DTE_RX                          0x00A8 0x03F0 0x0858 0x2 0x2
 #define MX6SX_PAD_KEY_COL1__ECSPI1_MISO                           0x00A8 0x03F0 0x0714 0x3 0x0
 #define MX6SX_PAD_KEY_COL1__AUDMUX_AUD5_TXFS                      0x00A8 0x03F0 0x0670 0x4 0x0
 #define MX6SX_PAD_KEY_COL1__GPIO2_IO_11                           0x00A8 0x03F0 0x0000 0x5 0x0
@@ -389,7 +400,8 @@
 #define MX6SX_PAD_KEY_COL1__SAI2_TX_SYNC                          0x00A8 0x03F0 0x0818 0x7 0x0
 #define MX6SX_PAD_KEY_COL2__KPP_COL_2                             0x00AC 0x03F4 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_COL2__USDHC4_CD_B                           0x00AC 0x03F4 0x0874 0x1 0x1
-#define MX6SX_PAD_KEY_COL2__UART5_RTS_B                           0x00AC 0x03F4 0x084C 0x2 0x2
+#define MX6SX_PAD_KEY_COL2__UART5_DCE_RTS                         0x00AC 0x03F4 0x084C 0x2 0x2
+#define MX6SX_PAD_KEY_COL2__UART5_DTE_CTS                         0x00AC 0x03F4 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_COL2__CAN1_TX                               0x00AC 0x03F4 0x0000 0x3 0x0
 #define MX6SX_PAD_KEY_COL2__CANFD_TX1                             0x00AC 0x03F4 0x0000 0x4 0x0
 #define MX6SX_PAD_KEY_COL2__GPIO2_IO_12                           0x00AC 0x03F4 0x0000 0x5 0x0
@@ -397,8 +409,8 @@
 #define MX6SX_PAD_KEY_COL2__ECSPI1_RDY                            0x00AC 0x03F4 0x0000 0x7 0x0
 #define MX6SX_PAD_KEY_COL3__KPP_COL_3                             0x00B0 0x03F8 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_COL3__USDHC4_LCTL                           0x00B0 0x03F8 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_COL3__UART5_RX                              0x00B0 0x03F8 0x0850 0x2 0x2
-#define MX6SX_PAD_KEY_COL3__UART5_TX                              0x00B0 0x03F8 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_COL3__UART5_DCE_TX                          0x00B0 0x03F8 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_COL3__UART5_DTE_RX                          0x00B0 0x03F8 0x0850 0x2 0x2
 #define MX6SX_PAD_KEY_COL3__CAN2_TX                               0x00B0 0x03F8 0x0000 0x3 0x0
 #define MX6SX_PAD_KEY_COL3__CANFD_TX2                             0x00B0 0x03F8 0x0000 0x4 0x0
 #define MX6SX_PAD_KEY_COL3__GPIO2_IO_13                           0x00B0 0x03F8 0x0000 0x5 0x0
@@ -414,7 +426,8 @@
 #define MX6SX_PAD_KEY_COL4__SAI2_RX_BCLK                          0x00B4 0x03FC 0x0808 0x7 0x0
 #define MX6SX_PAD_KEY_ROW0__KPP_ROW_0                             0x00B8 0x0400 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW0__USDHC3_WP                             0x00B8 0x0400 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B                           0x00B8 0x0400 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW0__UART6_DCE_CTS                         0x00B8 0x0400 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW0__UART6_DTE_RTS                         0x00B8 0x0400 0x0854 0x2 0x3
 #define MX6SX_PAD_KEY_ROW0__ECSPI1_MOSI                           0x00B8 0x0400 0x0718 0x3 0x0
 #define MX6SX_PAD_KEY_ROW0__AUDMUX_AUD5_TXD                       0x00B8 0x0400 0x0660 0x4 0x0
 #define MX6SX_PAD_KEY_ROW0__GPIO2_IO_15                           0x00B8 0x0400 0x0000 0x5 0x0
@@ -423,8 +436,8 @@
 #define MX6SX_PAD_KEY_ROW0__GPU_IDLE                              0x00B8 0x0400 0x0000 0x8 0x0
 #define MX6SX_PAD_KEY_ROW1__KPP_ROW_1                             0x00BC 0x0404 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW1__USDHC4_VSELECT                        0x00BC 0x0404 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_ROW1__UART6_RX                              0x00BC 0x0404 0x0858 0x2 0x3
-#define MX6SX_PAD_KEY_ROW1__UART6_TX                              0x00BC 0x0404 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW1__UART6_DCE_RX                          0x00BC 0x0404 0x0858 0x2 0x3
+#define MX6SX_PAD_KEY_ROW1__UART6_DTE_TX                          0x00BC 0x0404 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_ROW1__ECSPI1_SS0                            0x00BC 0x0404 0x071C 0x3 0x0
 #define MX6SX_PAD_KEY_ROW1__AUDMUX_AUD5_RXD                       0x00BC 0x0404 0x065C 0x4 0x0
 #define MX6SX_PAD_KEY_ROW1__GPIO2_IO_16                           0x00BC 0x0404 0x0000 0x5 0x0
@@ -433,7 +446,8 @@
 #define MX6SX_PAD_KEY_ROW1__M4_NMI                                0x00BC 0x0404 0x0000 0x8 0x0
 #define MX6SX_PAD_KEY_ROW2__KPP_ROW_2                             0x00C0 0x0408 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW2__USDHC4_WP                             0x00C0 0x0408 0x0878 0x1 0x1
-#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B                           0x00C0 0x0408 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS                         0x00C0 0x0408 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW2__UART5_DTE_RTS                         0x00C0 0x0408 0x084C 0x2 0x3
 #define MX6SX_PAD_KEY_ROW2__CAN1_RX                               0x00C0 0x0408 0x068C 0x3 0x1
 #define MX6SX_PAD_KEY_ROW2__CANFD_RX1                             0x00C0 0x0408 0x0694 0x4 0x1
 #define MX6SX_PAD_KEY_ROW2__GPIO2_IO_17                           0x00C0 0x0408 0x0000 0x5 0x0
@@ -441,8 +455,8 @@
 #define MX6SX_PAD_KEY_ROW2__ECSPI1_SS3                            0x00C0 0x0408 0x0000 0x7 0x0
 #define MX6SX_PAD_KEY_ROW3__KPP_ROW_3                             0x00C4 0x040C 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW3__USDHC3_LCTL                           0x00C4 0x040C 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_ROW3__UART5_RX                              0x00C4 0x040C 0x0850 0x2 0x3
-#define MX6SX_PAD_KEY_ROW3__UART5_TX                              0x00C4 0x040C 0x0000 0x2 0x0
+#define MX6SX_PAD_KEY_ROW3__UART5_DCE_RX                          0x00C4 0x040C 0x0850 0x2 0x3
+#define MX6SX_PAD_KEY_ROW3__UART5_DTE_TX                          0x00C4 0x040C 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_ROW3__CAN2_RX                               0x00C4 0x040C 0x0690 0x3 0x1
 #define MX6SX_PAD_KEY_ROW3__CANFD_RX2                             0x00C4 0x040C 0x0698 0x4 0x1
 #define MX6SX_PAD_KEY_ROW3__GPIO2_IO_18                           0x00C4 0x040C 0x0000 0x5 0x0
@@ -815,7 +829,8 @@
 #define MX6SX_PAD_NAND_DATA04__RAWNAND_DATA04                     0x0160 0x04A8 0x0000 0x0 0x0
 #define MX6SX_PAD_NAND_DATA04__USDHC2_DATA4                       0x0160 0x04A8 0x0000 0x1 0x0
 #define MX6SX_PAD_NAND_DATA04__QSPI2_B_SS1_B                      0x0160 0x04A8 0x0000 0x2 0x0
-#define MX6SX_PAD_NAND_DATA04__UART3_RTS_B                        0x0160 0x04A8 0x083C 0x3 0x0
+#define MX6SX_PAD_NAND_DATA04__UART3_DCE_RTS                      0x0160 0x04A8 0x083C 0x3 0x0
+#define MX6SX_PAD_NAND_DATA04__UART3_DTE_CTS                      0x0160 0x04A8 0x0000 0x3 0x0
 #define MX6SX_PAD_NAND_DATA04__AUDMUX_AUD4_RXFS                   0x0160 0x04A8 0x0650 0x4 0x0
 #define MX6SX_PAD_NAND_DATA04__GPIO4_IO_8                         0x0160 0x04A8 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA04__WEIM_AD_4                          0x0160 0x04A8 0x0000 0x6 0x0
@@ -825,7 +840,8 @@
 #define MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05                     0x0164 0x04AC 0x0000 0x0 0x0
 #define MX6SX_PAD_NAND_DATA05__USDHC2_DATA5                       0x0164 0x04AC 0x0000 0x1 0x0
 #define MX6SX_PAD_NAND_DATA05__QSPI2_B_DQS                        0x0164 0x04AC 0x0000 0x2 0x0
-#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B                        0x0164 0x04AC 0x0000 0x3 0x0
+#define MX6SX_PAD_NAND_DATA05__UART3_DCE_CTS                      0x0164 0x04AC 0x0000 0x3 0x0
+#define MX6SX_PAD_NAND_DATA05__UART3_DTE_RTS                      0x0164 0x04AC 0x083C 0x3 0x1
 #define MX6SX_PAD_NAND_DATA05__AUDMUX_AUD4_RXC                    0x0164 0x04AC 0x064C 0x4 0x0
 #define MX6SX_PAD_NAND_DATA05__GPIO4_IO_9                         0x0164 0x04AC 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA05__WEIM_AD_5                          0x0164 0x04AC 0x0000 0x6 0x0
@@ -835,8 +851,8 @@
 #define MX6SX_PAD_NAND_DATA06__RAWNAND_DATA06                     0x0168 0x04B0 0x0000 0x0 0x0
 #define MX6SX_PAD_NAND_DATA06__USDHC2_DATA6                       0x0168 0x04B0 0x0000 0x1 0x0
 #define MX6SX_PAD_NAND_DATA06__QSPI2_A_SS1_B                      0x0168 0x04B0 0x0000 0x2 0x0
-#define MX6SX_PAD_NAND_DATA06__UART3_RX                           0x0168 0x04B0 0x0840 0x3 0x0
-#define MX6SX_PAD_NAND_DATA06__UART3_TX                           0x0168 0x04B0 0x0000 0x3 0x0
+#define MX6SX_PAD_NAND_DATA06__UART3_DCE_RX                       0x0168 0x04B0 0x0840 0x3 0x0
+#define MX6SX_PAD_NAND_DATA06__UART3_DTE_TX                       0x0168 0x04B0 0x0000 0x3 0x0
 #define MX6SX_PAD_NAND_DATA06__PWM3_OUT                           0x0168 0x04B0 0x0000 0x4 0x0
 #define MX6SX_PAD_NAND_DATA06__GPIO4_IO_10                        0x0168 0x04B0 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA06__WEIM_AD_6                          0x0168 0x04B0 0x0000 0x6 0x0
@@ -846,8 +862,8 @@
 #define MX6SX_PAD_NAND_DATA07__RAWNAND_DATA07                     0x016C 0x04B4 0x0000 0x0 0x0
 #define MX6SX_PAD_NAND_DATA07__USDHC2_DATA7                       0x016C 0x04B4 0x0000 0x1 0x0
 #define MX6SX_PAD_NAND_DATA07__QSPI2_A_DQS                        0x016C 0x04B4 0x0000 0x2 0x0
-#define MX6SX_PAD_NAND_DATA07__UART3_RX                           0x016C 0x04B4 0x0840 0x3 0x1
-#define MX6SX_PAD_NAND_DATA07__UART3_TX                           0x016C 0x04B4 0x0000 0x3 0x0
+#define MX6SX_PAD_NAND_DATA07__UART3_DCE_TX                       0x016C 0x04B4 0x0000 0x3 0x0
+#define MX6SX_PAD_NAND_DATA07__UART3_DTE_RX                       0x016C 0x04B4 0x0840 0x3 0x1
 #define MX6SX_PAD_NAND_DATA07__PWM4_OUT                           0x016C 0x04B4 0x0000 0x4 0x0
 #define MX6SX_PAD_NAND_DATA07__GPIO4_IO_11                        0x016C 0x04B4 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA07__WEIM_AD_7                          0x016C 0x04B4 0x0000 0x6 0x0
@@ -967,7 +983,8 @@
 #define MX6SX_PAD_QSPI1A_SS1_B__SIM_M_HADDR_12                    0x019C 0x04E4 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1A_SS1_B__SDMA_DEBUG_PC_3                   0x019C 0x04E4 0x0000 0x9 0x0
 #define MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0                    0x01A0 0x04E8 0x0000 0x0 0x0
-#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B                       0x01A0 0x04E8 0x0000 0x1 0x0
+#define MX6SX_PAD_QSPI1B_DATA0__UART3_DCE_CTS                     0x01A0 0x04E8 0x0000 0x1 0x0
+#define MX6SX_PAD_QSPI1B_DATA0__UART3_DTE_RTS                     0x01A0 0x04E8 0x083C 0x1 0x4
 #define MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI                       0x01A0 0x04E8 0x0738 0x2 0x1
 #define MX6SX_PAD_QSPI1B_DATA0__ESAI_RX_FS                        0x01A0 0x04E8 0x0778 0x3 0x2
 #define MX6SX_PAD_QSPI1B_DATA0__CSI1_DATA_22                      0x01A0 0x04E8 0x06F4 0x4 0x1
@@ -975,7 +992,8 @@
 #define MX6SX_PAD_QSPI1B_DATA0__WEIM_DATA_14                      0x01A0 0x04E8 0x0000 0x6 0x0
 #define MX6SX_PAD_QSPI1B_DATA0__SIM_M_HADDR_9                     0x01A0 0x04E8 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1B_DATA1__QSPI1_B_DATA_1                    0x01A4 0x04EC 0x0000 0x0 0x0
-#define MX6SX_PAD_QSPI1B_DATA1__UART3_RTS_B                       0x01A4 0x04EC 0x083C 0x1 0x5
+#define MX6SX_PAD_QSPI1B_DATA1__UART3_DCE_RTS                     0x01A4 0x04EC 0x083C 0x1 0x5
+#define MX6SX_PAD_QSPI1B_DATA1__UART3_DTE_CTS                     0x01A4 0x04EC 0x0000 0x1 0x0
 #define MX6SX_PAD_QSPI1B_DATA1__ECSPI3_MISO                       0x01A4 0x04EC 0x0734 0x2 0x1
 #define MX6SX_PAD_QSPI1B_DATA1__ESAI_RX_CLK                       0x01A4 0x04EC 0x0788 0x3 0x2
 #define MX6SX_PAD_QSPI1B_DATA1__CSI1_DATA_21                      0x01A4 0x04EC 0x06F0 0x4 0x1
@@ -1007,8 +1025,8 @@
 #define MX6SX_PAD_QSPI1B_DQS__WEIM_DATA_15                        0x01B0 0x04F8 0x0000 0x6 0x0
 #define MX6SX_PAD_QSPI1B_DQS__SIM_M_HADDR_15                      0x01B0 0x04F8 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__QSPI1_B_SCLK                       0x01B4 0x04FC 0x0000 0x0 0x0
-#define MX6SX_PAD_QSPI1B_SCLK__UART3_RX                           0x01B4 0x04FC 0x0840 0x1 0x4
-#define MX6SX_PAD_QSPI1B_SCLK__UART3_TX                           0x01B4 0x04FC 0x0000 0x0 0x0
+#define MX6SX_PAD_QSPI1B_SCLK__UART3_DCE_RX                       0x01B4 0x04FC 0x0840 0x1 0x4
+#define MX6SX_PAD_QSPI1B_SCLK__UART3_DTE_TX                       0x01B4 0x04FC 0x0000 0x1 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__ECSPI3_SCLK                        0x01B4 0x04FC 0x0730 0x2 0x1
 #define MX6SX_PAD_QSPI1B_SCLK__ESAI_RX_HF_CLK                     0x01B4 0x04FC 0x0780 0x3 0x2
 #define MX6SX_PAD_QSPI1B_SCLK__CSI1_DATA_16                       0x01B4 0x04FC 0x06DC 0x4 0x1
@@ -1016,8 +1034,8 @@
 #define MX6SX_PAD_QSPI1B_SCLK__WEIM_DATA_8                        0x01B4 0x04FC 0x0000 0x6 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__SIM_M_HADDR_11                     0x01B4 0x04FC 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1B_SS0_B__QSPI1_B_SS0_B                     0x01B8 0x0500 0x0000 0x0 0x0
-#define MX6SX_PAD_QSPI1B_SS0_B__UART3_RX                          0x01B8 0x0500 0x0840 0x1 0x5
-#define MX6SX_PAD_QSPI1B_SS0_B__UART3_TX                          0x01B8 0x0500 0x0000 0x1 0x0
+#define MX6SX_PAD_QSPI1B_SS0_B__UART3_DCE_TX                      0x01B8 0x0500 0x0000 0x1 0x0
+#define MX6SX_PAD_QSPI1B_SS0_B__UART3_DTE_RX                      0x01B8 0x0500 0x0840 0x1 0x5
 #define MX6SX_PAD_QSPI1B_SS0_B__ECSPI3_SS0                        0x01B8 0x0500 0x073C 0x2 0x1
 #define MX6SX_PAD_QSPI1B_SS0_B__ESAI_TX_HF_CLK                    0x01B8 0x0500 0x0784 0x3 0x3
 #define MX6SX_PAD_QSPI1B_SS0_B__CSI1_DATA_17                      0x01B8 0x0500 0x06E0 0x4 0x1
@@ -1224,8 +1242,8 @@
 #define MX6SX_PAD_SD1_DATA0__AUDMUX_AUD5_RXD                      0x0228 0x0570 0x065C 0x1 0x1
 #define MX6SX_PAD_SD1_DATA0__CAAM_WRAPPER_RNG_OSC_OBS             0x0228 0x0570 0x0000 0x2 0x0
 #define MX6SX_PAD_SD1_DATA0__GPT_CAPTURE1                         0x0228 0x0570 0x0000 0x3 0x0
-#define MX6SX_PAD_SD1_DATA0__UART2_RX                             0x0228 0x0570 0x0838 0x4 0x2
-#define MX6SX_PAD_SD1_DATA0__UART2_TX                             0x0228 0x0570 0x0000 0x4 0x0
+#define MX6SX_PAD_SD1_DATA0__UART2_DCE_RX                         0x0228 0x0570 0x0838 0x4 0x2
+#define MX6SX_PAD_SD1_DATA0__UART2_DTE_TX                         0x0228 0x0570 0x0000 0x4 0x0
 #define MX6SX_PAD_SD1_DATA0__GPIO6_IO_2                           0x0228 0x0570 0x0000 0x5 0x0
 #define MX6SX_PAD_SD1_DATA0__ENET1_1588_EVENT1_IN                 0x0228 0x0570 0x0000 0x6 0x0
 #define MX6SX_PAD_SD1_DATA0__CCM_OUT2                             0x0228 0x0570 0x0000 0x7 0x0
@@ -1235,8 +1253,8 @@
 #define MX6SX_PAD_SD1_DATA1__AUDMUX_AUD5_TXC                      0x022C 0x0574 0x066C 0x1 0x1
 #define MX6SX_PAD_SD1_DATA1__PWM4_OUT                             0x022C 0x0574 0x0000 0x2 0x0
 #define MX6SX_PAD_SD1_DATA1__GPT_CAPTURE2                         0x022C 0x0574 0x0000 0x3 0x0
-#define MX6SX_PAD_SD1_DATA1__UART2_RX                             0x022C 0x0574 0x0838 0x4 0x3
-#define MX6SX_PAD_SD1_DATA1__UART2_TX                             0x022C 0x0574 0x0000 0x4 0x0
+#define MX6SX_PAD_SD1_DATA1__UART2_DCE_TX                         0x022C 0x0574 0x0000 0x4 0x0
+#define MX6SX_PAD_SD1_DATA1__UART2_DTE_RX                         0x022C 0x0574 0x0838 0x4 0x3
 #define MX6SX_PAD_SD1_DATA1__GPIO6_IO_3                           0x022C 0x0574 0x0000 0x5 0x0
 #define MX6SX_PAD_SD1_DATA1__ENET1_1588_EVENT1_OUT                0x022C 0x0574 0x0000 0x6 0x0
 #define MX6SX_PAD_SD1_DATA1__CCM_CLKO2                            0x022C 0x0574 0x0000 0x7 0x0
@@ -1246,7 +1264,8 @@
 #define MX6SX_PAD_SD1_DATA2__AUDMUX_AUD5_TXFS                     0x0230 0x0578 0x0670 0x1 0x1
 #define MX6SX_PAD_SD1_DATA2__PWM3_OUT                             0x0230 0x0578 0x0000 0x2 0x0
 #define MX6SX_PAD_SD1_DATA2__GPT_COMPARE2                         0x0230 0x0578 0x0000 0x3 0x0
-#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B                          0x0230 0x0578 0x0000 0x4 0x0
+#define MX6SX_PAD_SD1_DATA2__UART2_DCE_CTS                        0x0230 0x0578 0x0000 0x4 0x0
+#define MX6SX_PAD_SD1_DATA2__UART2_DTE_RTS                        0x0230 0x0578 0x0834 0x4 0x2
 #define MX6SX_PAD_SD1_DATA2__GPIO6_IO_4                           0x0230 0x0578 0x0000 0x5 0x0
 #define MX6SX_PAD_SD1_DATA2__ECSPI4_RDY                           0x0230 0x0578 0x0000 0x6 0x0
 #define MX6SX_PAD_SD1_DATA2__CCM_OUT0                             0x0230 0x0578 0x0000 0x7 0x0
@@ -1255,7 +1274,8 @@
 #define MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_TXD                      0x0234 0x057C 0x0660 0x1 0x1
 #define MX6SX_PAD_SD1_DATA3__AUDMUX_AUD5_RXD                      0x0234 0x057C 0x065C 0x2 0x2
 #define MX6SX_PAD_SD1_DATA3__GPT_COMPARE3                         0x0234 0x057C 0x0000 0x3 0x0
-#define MX6SX_PAD_SD1_DATA3__UART2_RTS_B                          0x0234 0x057C 0x0834 0x4 0x3
+#define MX6SX_PAD_SD1_DATA3__UART2_DCE_RTS                        0x0234 0x057C 0x0834 0x4 0x3
+#define MX6SX_PAD_SD1_DATA3__UART2_DTE_CTS                        0x0234 0x057C 0x0000 0x4 0x0
 #define MX6SX_PAD_SD1_DATA3__GPIO6_IO_5                           0x0234 0x057C 0x0000 0x5 0x0
 #define MX6SX_PAD_SD1_DATA3__ECSPI4_SS1                           0x0234 0x057C 0x0000 0x6 0x0
 #define MX6SX_PAD_SD1_DATA3__CCM_PMIC_RDY                         0x0234 0x057C 0x069C 0x7 0x2
@@ -1287,8 +1307,8 @@
 #define MX6SX_PAD_SD2_DATA0__I2C4_SDA                             0x0240 0x0588 0x07C4 0x4 0x3
 #define MX6SX_PAD_SD2_DATA0__GPIO6_IO_8                           0x0240 0x0588 0x0000 0x5 0x0
 #define MX6SX_PAD_SD2_DATA0__ECSPI4_SS3                           0x0240 0x0588 0x0000 0x6 0x0
-#define MX6SX_PAD_SD2_DATA0__UART4_RX                             0x0240 0x0588 0x0848 0x7 0x4
-#define MX6SX_PAD_SD2_DATA0__UART4_TX                             0x0240 0x0588 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA0__UART4_DCE_RX                         0x0240 0x0588 0x0848 0x7 0x4
+#define MX6SX_PAD_SD2_DATA0__UART4_DTE_TX                         0x0240 0x0588 0x0000 0x7 0x0
 #define MX6SX_PAD_SD2_DATA0__VADC_CLAMP_CURRENT_0                 0x0240 0x0588 0x0000 0x8 0x0
 #define MX6SX_PAD_SD2_DATA0__MMDC_DEBUG_50                        0x0240 0x0588 0x0000 0x9 0x0
 #define MX6SX_PAD_SD2_DATA1__USDHC2_DATA1                         0x0244 0x058C 0x0000 0x0 0x0
@@ -1298,8 +1318,8 @@
 #define MX6SX_PAD_SD2_DATA1__I2C4_SCL                             0x0244 0x058C 0x07C0 0x4 0x3
 #define MX6SX_PAD_SD2_DATA1__GPIO6_IO_9                           0x0244 0x058C 0x0000 0x5 0x0
 #define MX6SX_PAD_SD2_DATA1__ECSPI4_SS2                           0x0244 0x058C 0x0000 0x6 0x0
-#define MX6SX_PAD_SD2_DATA1__UART4_RX                             0x0244 0x058C 0x0848 0x7 0x5
-#define MX6SX_PAD_SD2_DATA1__UART4_TX                             0x0244 0x058C 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA1__UART4_DCE_TX                         0x0244 0x058C 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA1__UART4_DTE_RX                         0x0244 0x058C 0x0848 0x7 0x5
 #define MX6SX_PAD_SD2_DATA1__VADC_CLAMP_CURRENT_1                 0x0244 0x058C 0x0000 0x8 0x0
 #define MX6SX_PAD_SD2_DATA1__MMDC_DEBUG_49                        0x0244 0x058C 0x0000 0x9 0x0
 #define MX6SX_PAD_SD2_DATA2__USDHC2_DATA2                         0x0248 0x0590 0x0000 0x0 0x0
@@ -1309,8 +1329,8 @@
 #define MX6SX_PAD_SD2_DATA2__SDMA_EXT_EVENT_0                     0x0248 0x0590 0x081C 0x4 0x2
 #define MX6SX_PAD_SD2_DATA2__GPIO6_IO_10                          0x0248 0x0590 0x0000 0x5 0x0
 #define MX6SX_PAD_SD2_DATA2__SPDIF_OUT                            0x0248 0x0590 0x0000 0x6 0x0
-#define MX6SX_PAD_SD2_DATA2__UART6_RX                             0x0248 0x0590 0x0858 0x7 0x4
-#define MX6SX_PAD_SD2_DATA2__UART6_TX                             0x0248 0x0590 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA2__UART6_DCE_RX                         0x0248 0x0590 0x0858 0x7 0x4
+#define MX6SX_PAD_SD2_DATA2__UART6_DTE_TX                         0x0248 0x0590 0x0000 0x7 0x0
 #define MX6SX_PAD_SD2_DATA2__VADC_CLAMP_CURRENT_2                 0x0248 0x0590 0x0000 0x8 0x0
 #define MX6SX_PAD_SD2_DATA2__MMDC_DEBUG_32                        0x0248 0x0590 0x0000 0x9 0x0
 #define MX6SX_PAD_SD2_DATA3__USDHC2_DATA3                         0x024C 0x0594 0x0000 0x0 0x0
@@ -1320,12 +1340,13 @@
 #define MX6SX_PAD_SD2_DATA3__MLB_DATA                             0x024C 0x0594 0x07EC 0x4 0x2
 #define MX6SX_PAD_SD2_DATA3__GPIO6_IO_11                          0x024C 0x0594 0x0000 0x5 0x0
 #define MX6SX_PAD_SD2_DATA3__SPDIF_IN                             0x024C 0x0594 0x0824 0x6 0x4
-#define MX6SX_PAD_SD2_DATA3__UART6_RX                             0x024C 0x0594 0x0858 0x7 0x5
-#define MX6SX_PAD_SD2_DATA3__UART6_TX                             0x024C 0x0594 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA3__UART6_DCE_TX                         0x024C 0x0594 0x0000 0x7 0x0
+#define MX6SX_PAD_SD2_DATA3__UART6_DTE_RX                         0x024C 0x0594 0x0858 0x7 0x5
 #define MX6SX_PAD_SD2_DATA3__VADC_CLAMP_CURRENT_3                 0x024C 0x0594 0x0000 0x8 0x0
 #define MX6SX_PAD_SD2_DATA3__MMDC_DEBUG_31                        0x024C 0x0594 0x0000 0x9 0x0
 #define MX6SX_PAD_SD3_CLK__USDHC3_CLK                             0x0250 0x0598 0x0000 0x0 0x0
-#define MX6SX_PAD_SD3_CLK__UART4_CTS_B                            0x0250 0x0598 0x0000 0x1 0x0
+#define MX6SX_PAD_SD3_CLK__UART4_DCE_CTS                          0x0250 0x0598 0x0000 0x1 0x0
+#define MX6SX_PAD_SD3_CLK__UART4_DTE_RTS                          0x0250 0x0598 0x0844 0x1 0x0
 #define MX6SX_PAD_SD3_CLK__ECSPI4_SCLK                            0x0250 0x0598 0x0740 0x2 0x0
 #define MX6SX_PAD_SD3_CLK__AUDMUX_AUD6_RXFS                       0x0250 0x0598 0x0680 0x3 0x0
 #define MX6SX_PAD_SD3_CLK__LCDIF2_VSYNC                           0x0250 0x0598 0x0000 0x4 0x0
@@ -1334,8 +1355,8 @@
 #define MX6SX_PAD_SD3_CLK__TPSMP_HDATA_29                         0x0250 0x0598 0x0000 0x7 0x0
 #define MX6SX_PAD_SD3_CLK__SDMA_DEBUG_EVENT_CHANNEL_5             0x0250 0x0598 0x0000 0x9 0x0
 #define MX6SX_PAD_SD3_CMD__USDHC3_CMD                             0x0254 0x059C 0x0000 0x0 0x0
-#define MX6SX_PAD_SD3_CMD__UART4_RX                               0x0254 0x059C 0x0848 0x1 0x0
-#define MX6SX_PAD_SD3_CMD__UART4_TX                               0x0254 0x059C 0x0000 0x1 0x0
+#define MX6SX_PAD_SD3_CMD__UART4_DCE_TX                           0x0254 0x059C 0x0000 0x1 0x0
+#define MX6SX_PAD_SD3_CMD__UART4_DTE_RX                           0x0254 0x059C 0x0848 0x1 0x0
 #define MX6SX_PAD_SD3_CMD__ECSPI4_MOSI                            0x0254 0x059C 0x0748 0x2 0x0
 #define MX6SX_PAD_SD3_CMD__AUDMUX_AUD6_RXC                        0x0254 0x059C 0x067C 0x3 0x0
 #define MX6SX_PAD_SD3_CMD__LCDIF2_HSYNC                           0x0254 0x059C 0x07E4 0x4 0x1
@@ -1364,7 +1385,8 @@
 #define MX6SX_PAD_SD3_DATA1__GPU_DEBUG_1                          0x025C 0x05A4 0x0000 0x8 0x0
 #define MX6SX_PAD_SD3_DATA1__SDMA_DEBUG_EVT_CHN_LINES_1           0x025C 0x05A4 0x0000 0x9 0x0
 #define MX6SX_PAD_SD3_DATA2__USDHC3_DATA2                         0x0260 0x05A8 0x0000 0x0 0x0
-#define MX6SX_PAD_SD3_DATA2__UART4_RTS_B                          0x0260 0x05A8 0x0844 0x1 0x1
+#define MX6SX_PAD_SD3_DATA2__UART4_DCE_RTS                        0x0260 0x05A8 0x0844 0x1 0x1
+#define MX6SX_PAD_SD3_DATA2__UART4_DTE_CTS                        0x0260 0x05A8 0x0000 0x1 0x0
 #define MX6SX_PAD_SD3_DATA2__ECSPI4_SS0                           0x0260 0x05A8 0x074C 0x2 0x0
 #define MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS                     0x0260 0x05A8 0x0688 0x3 0x0
 #define MX6SX_PAD_SD3_DATA2__LCDIF2_CLK                           0x0260 0x05A8 0x0000 0x4 0x0
@@ -1374,8 +1396,8 @@
 #define MX6SX_PAD_SD3_DATA2__GPU_DEBUG_2                          0x0260 0x05A8 0x0000 0x8 0x0
 #define MX6SX_PAD_SD3_DATA2__SDMA_DEBUG_EVENT_CHANNEL_2           0x0260 0x05A8 0x0000 0x9 0x0
 #define MX6SX_PAD_SD3_DATA3__USDHC3_DATA3                         0x0264 0x05AC 0x0000 0x0 0x0
-#define MX6SX_PAD_SD3_DATA3__UART4_RX                             0x0264 0x05AC 0x0848 0x1 0x1
-#define MX6SX_PAD_SD3_DATA3__UART4_TX                             0x0264 0x05AC 0x0000 0x1 0x0
+#define MX6SX_PAD_SD3_DATA3__UART4_DCE_RX                         0x0264 0x05AC 0x0848 0x1 0x1
+#define MX6SX_PAD_SD3_DATA3__UART4_DTE_TX                         0x0264 0x05AC 0x0000 0x1 0x0
 #define MX6SX_PAD_SD3_DATA3__ECSPI4_MISO                          0x0264 0x05AC 0x0744 0x2 0x0
 #define MX6SX_PAD_SD3_DATA3__AUDMUX_AUD6_TXD                      0x0264 0x05AC 0x0678 0x3 0x0
 #define MX6SX_PAD_SD3_DATA3__LCDIF2_ENABLE                        0x0264 0x05AC 0x0000 0x4 0x0
@@ -1387,8 +1409,8 @@
 #define MX6SX_PAD_SD3_DATA4__USDHC3_DATA4                         0x0268 0x05B0 0x0000 0x0 0x0
 #define MX6SX_PAD_SD3_DATA4__CAN2_RX                              0x0268 0x05B0 0x0690 0x1 0x0
 #define MX6SX_PAD_SD3_DATA4__CANFD_RX2                            0x0268 0x05B0 0x0698 0x2 0x0
-#define MX6SX_PAD_SD3_DATA4__UART3_RX                             0x0268 0x05B0 0x0840 0x3 0x2
-#define MX6SX_PAD_SD3_DATA4__UART3_TX                             0x0268 0x05B0 0x0000 0x3 0x0
+#define MX6SX_PAD_SD3_DATA4__UART3_DCE_RX                         0x0268 0x05B0 0x0840 0x3 0x2
+#define MX6SX_PAD_SD3_DATA4__UART3_DTE_TX                         0x0268 0x05B0 0x0000 0x3 0x0
 #define MX6SX_PAD_SD3_DATA4__LCDIF2_DATA_3                        0x0268 0x05B0 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA4__GPIO7_IO_6                           0x0268 0x05B0 0x0000 0x5 0x0
 #define MX6SX_PAD_SD3_DATA4__ENET2_1588_EVENT0_IN                 0x0268 0x05B0 0x0000 0x6 0x0
@@ -1398,8 +1420,8 @@
 #define MX6SX_PAD_SD3_DATA5__USDHC3_DATA5                         0x026C 0x05B4 0x0000 0x0 0x0
 #define MX6SX_PAD_SD3_DATA5__CAN1_TX                              0x026C 0x05B4 0x0000 0x1 0x0
 #define MX6SX_PAD_SD3_DATA5__CANFD_TX1                            0x026C 0x05B4 0x0000 0x2 0x0
-#define MX6SX_PAD_SD3_DATA5__UART3_RX                             0x026C 0x05B4 0x0840 0x3 0x3
-#define MX6SX_PAD_SD3_DATA5__UART3_TX                             0x026C 0x05B4 0x0000 0x3 0x0
+#define MX6SX_PAD_SD3_DATA5__UART3_DCE_TX                         0x026C 0x05B4 0x0000 0x3 0x0
+#define MX6SX_PAD_SD3_DATA5__UART3_DTE_RX                         0x026C 0x05B4 0x0840 0x3 0x3
 #define MX6SX_PAD_SD3_DATA5__LCDIF2_DATA_2                        0x026C 0x05B4 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA5__GPIO7_IO_7                           0x026C 0x05B4 0x0000 0x5 0x0
 #define MX6SX_PAD_SD3_DATA5__ENET2_1588_EVENT0_OUT                0x026C 0x05B4 0x0000 0x6 0x0
@@ -1409,7 +1431,8 @@
 #define MX6SX_PAD_SD3_DATA6__USDHC3_DATA6                         0x0270 0x05B8 0x0000 0x0 0x0
 #define MX6SX_PAD_SD3_DATA6__CAN2_TX                              0x0270 0x05B8 0x0000 0x1 0x0
 #define MX6SX_PAD_SD3_DATA6__CANFD_TX2                            0x0270 0x05B8 0x0000 0x2 0x0
-#define MX6SX_PAD_SD3_DATA6__UART3_RTS_B                          0x0270 0x05B8 0x083C 0x3 0x2
+#define MX6SX_PAD_SD3_DATA6__UART3_DCE_RTS                        0x0270 0x05B8 0x083C 0x3 0x2
+#define MX6SX_PAD_SD3_DATA6__UART3_DTE_CTS                        0x0270 0x05B8 0x0000 0x3 0x0
 #define MX6SX_PAD_SD3_DATA6__LCDIF2_DATA_4                        0x0270 0x05B8 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA6__GPIO7_IO_8                           0x0270 0x05B8 0x0000 0x5 0x0
 #define MX6SX_PAD_SD3_DATA6__ENET1_1588_EVENT0_OUT                0x0270 0x05B8 0x0000 0x6 0x0
@@ -1419,7 +1442,8 @@
 #define MX6SX_PAD_SD3_DATA7__USDHC3_DATA7                         0x0274 0x05BC 0x0000 0x0 0x0
 #define MX6SX_PAD_SD3_DATA7__CAN1_RX                              0x0274 0x05BC 0x068C 0x1 0x0
 #define MX6SX_PAD_SD3_DATA7__CANFD_RX1                            0x0274 0x05BC 0x0694 0x2 0x0
-#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B                          0x0274 0x05BC 0x0000 0x3 0x0
+#define MX6SX_PAD_SD3_DATA7__UART3_DCE_CTS                        0x0274 0x05BC 0x0000 0x3 0x0
+#define MX6SX_PAD_SD3_DATA7__UART3_DTE_RTS                        0x0274 0x05BC 0x083C 0x3 0x3
 #define MX6SX_PAD_SD3_DATA7__LCDIF2_DATA_5                        0x0274 0x05BC 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA7__GPIO7_IO_9                           0x0274 0x05BC 0x0000 0x5 0x0
 #define MX6SX_PAD_SD3_DATA7__ENET1_1588_EVENT0_IN                 0x0274 0x05BC 0x0000 0x6 0x0
@@ -1488,8 +1512,8 @@
 #define MX6SX_PAD_SD4_DATA3__SDMA_DEBUG_MATCHED_DMBUS             0x028C 0x05D4 0x0000 0x9 0x0
 #define MX6SX_PAD_SD4_DATA4__USDHC4_DATA4                         0x0290 0x05D8 0x0000 0x0 0x0
 #define MX6SX_PAD_SD4_DATA4__RAWNAND_DATA09                       0x0290 0x05D8 0x0000 0x1 0x0
-#define MX6SX_PAD_SD4_DATA4__UART5_RX                             0x0290 0x05D8 0x0850 0x2 0x0
-#define MX6SX_PAD_SD4_DATA4__UART5_TX                             0x0290 0x05D8 0x0000 0x2 0x0
+#define MX6SX_PAD_SD4_DATA4__UART5_DCE_RX                         0x0290 0x05D8 0x0850 0x2 0x0
+#define MX6SX_PAD_SD4_DATA4__UART5_DTE_TX                         0x0290 0x05D8 0x0000 0x2 0x0
 #define MX6SX_PAD_SD4_DATA4__ECSPI3_SCLK                          0x0290 0x05D8 0x0730 0x3 0x0
 #define MX6SX_PAD_SD4_DATA4__LCDIF2_DATA_8                        0x0290 0x05D8 0x0000 0x4 0x0
 #define MX6SX_PAD_SD4_DATA4__GPIO6_IO_18                          0x0290 0x05D8 0x0000 0x5 0x0
@@ -1499,8 +1523,8 @@
 #define MX6SX_PAD_SD4_DATA4__SDMA_DEBUG_RTBUFFER_WRITE            0x0290 0x05D8 0x0000 0x9 0x0
 #define MX6SX_PAD_SD4_DATA5__USDHC4_DATA5                         0x0294 0x05DC 0x0000 0x0 0x0
 #define MX6SX_PAD_SD4_DATA5__RAWNAND_CE2_B                        0x0294 0x05DC 0x0000 0x1 0x0
-#define MX6SX_PAD_SD4_DATA5__UART5_RX                             0x0294 0x05DC 0x0850 0x2 0x1
-#define MX6SX_PAD_SD4_DATA5__UART5_TX                             0x0294 0x05DC 0x0000 0x2 0x0
+#define MX6SX_PAD_SD4_DATA5__UART5_DCE_TX                         0x0294 0x05DC 0x0000 0x2 0x0
+#define MX6SX_PAD_SD4_DATA5__UART5_DTE_RX                         0x0294 0x05DC 0x0850 0x2 0x1
 #define MX6SX_PAD_SD4_DATA5__ECSPI3_MOSI                          0x0294 0x05DC 0x0738 0x3 0x0
 #define MX6SX_PAD_SD4_DATA5__LCDIF2_DATA_7                        0x0294 0x05DC 0x0000 0x4 0x0
 #define MX6SX_PAD_SD4_DATA5__GPIO6_IO_19                          0x0294 0x05DC 0x0000 0x5 0x0
@@ -1510,7 +1534,8 @@
 #define MX6SX_PAD_SD4_DATA5__SDMA_DEBUG_EVENT_CHANNEL_0           0x0294 0x05DC 0x0000 0x9 0x0
 #define MX6SX_PAD_SD4_DATA6__USDHC4_DATA6                         0x0298 0x05E0 0x0000 0x0 0x0
 #define MX6SX_PAD_SD4_DATA6__RAWNAND_CE3_B                        0x0298 0x05E0 0x0000 0x1 0x0
-#define MX6SX_PAD_SD4_DATA6__UART5_RTS_B                          0x0298 0x05E0 0x084C 0x2 0x0
+#define MX6SX_PAD_SD4_DATA6__UART5_DCE_RTS                        0x0298 0x05E0 0x084C 0x2 0x0
+#define MX6SX_PAD_SD4_DATA6__UART5_DTE_CTS                        0x0298 0x05E0 0x0000 0x2 0x0
 #define MX6SX_PAD_SD4_DATA6__ECSPI3_MISO                          0x0298 0x05E0 0x0734 0x3 0x0
 #define MX6SX_PAD_SD4_DATA6__LCDIF2_DATA_6                        0x0298 0x05E0 0x0000 0x4 0x0
 #define MX6SX_PAD_SD4_DATA6__GPIO6_IO_20                          0x0298 0x05E0 0x0000 0x5 0x0
@@ -1520,7 +1545,8 @@
 #define MX6SX_PAD_SD4_DATA6__SDMA_DEBUG_EVENT_CHANNEL_1           0x0298 0x05E0 0x0000 0x9 0x0
 #define MX6SX_PAD_SD4_DATA7__USDHC4_DATA7                         0x029C 0x05E4 0x0000 0x0 0x0
 #define MX6SX_PAD_SD4_DATA7__RAWNAND_DATA08                       0x029C 0x05E4 0x0000 0x1 0x0
-#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B                          0x029C 0x05E4 0x0000 0x2 0x0
+#define MX6SX_PAD_SD4_DATA7__UART5_DCE_CTS                        0x029C 0x05E4 0x0000 0x2 0x0
+#define MX6SX_PAD_SD4_DATA7__UART5_DTE_RTS                        0x029C 0x05E4 0x084C 0x2 0x1
 #define MX6SX_PAD_SD4_DATA7__ECSPI3_SS0                           0x029C 0x05E4 0x073C 0x3 0x0
 #define MX6SX_PAD_SD4_DATA7__LCDIF2_DATA_15                       0x029C 0x05E4 0x0000 0x4 0x0
 #define MX6SX_PAD_SD4_DATA7__GPIO6_IO_21                          0x029C 0x05E4 0x0000 0x5 0x0
@@ -1551,4 +1577,92 @@
 #define MX6SX_PAD_USB_H_STROBE__WDOG3_WDOG_RST_B_DEB              0x02A8 0x05F0 0x0000 0x4 0x0
 #define MX6SX_PAD_USB_H_STROBE__GPIO7_IO_11                       0x02A8 0x05F0 0x0000 0x5 0x0
 
+/* these are not supposed to be used any more and remove them after some time */
+#define MX6SX_PAD_GPIO1_IO04__UART1_RX		MX6SX_PAD_GPIO1_IO04__UART1_DTE_RX
+#define MX6SX_PAD_GPIO1_IO04__UART1_TX		MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX
+#define MX6SX_PAD_GPIO1_IO05__UART1_RX		MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX
+#define MX6SX_PAD_GPIO1_IO05__UART1_TX		MX6SX_PAD_GPIO1_IO05__UART1_DTE_TX
+#define MX6SX_PAD_GPIO1_IO06__UART2_RX		MX6SX_PAD_GPIO1_IO06__UART2_DTE_RX
+#define MX6SX_PAD_GPIO1_IO06__UART2_TX		MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX
+#define MX6SX_PAD_GPIO1_IO06__UART1_RTS_B	MX6SX_PAD_GPIO1_IO06__UART1_DCE_RTS
+#define MX6SX_PAD_GPIO1_IO07__UART2_RX		MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX
+#define MX6SX_PAD_GPIO1_IO07__UART2_TX		MX6SX_PAD_GPIO1_IO07__UART2_DTE_TX
+#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B	MX6SX_PAD_GPIO1_IO07__UART1_DCE_CTS
+#define MX6SX_PAD_GPIO1_IO08__UART2_RTS_B	MX6SX_PAD_GPIO1_IO08__UART2_DCE_RTS
+#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B	MX6SX_PAD_GPIO1_IO09__UART2_DCE_CTS
+#define MX6SX_PAD_CSI_DATA04__UART6_RX		MX6SX_PAD_CSI_DATA04__UART6_DCE_RX
+#define MX6SX_PAD_CSI_DATA04__UART6_TX		MX6SX_PAD_CSI_DATA04__UART6_DTE_TX
+#define MX6SX_PAD_CSI_DATA05__UART6_RX		MX6SX_PAD_CSI_DATA05__UART6_DTE_RX
+#define MX6SX_PAD_CSI_DATA05__UART6_TX		MX6SX_PAD_CSI_DATA05__UART6_DCE_TX
+#define MX6SX_PAD_CSI_DATA06__UART6_RTS_B	MX6SX_PAD_CSI_DATA06__UART6_DCE_RTS
+#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B	MX6SX_PAD_CSI_DATA07__UART6_DCE_CTS
+#define MX6SX_PAD_CSI_HSYNC__UART4_RTS_B	MX6SX_PAD_CSI_HSYNC__UART4_DCE_RTS
+#define MX6SX_PAD_CSI_MCLK__UART4_RX		MX6SX_PAD_CSI_MCLK__UART4_DCE_RX
+#define MX6SX_PAD_CSI_MCLK__UART4_TX		MX6SX_PAD_CSI_MCLK__UART4_DTE_TX
+#define MX6SX_PAD_CSI_PIXCLK__UART4_RX		MX6SX_PAD_CSI_PIXCLK__UART4_DTE_RX
+#define MX6SX_PAD_CSI_PIXCLK__UART4_TX		MX6SX_PAD_CSI_PIXCLK__UART4_DCE_TX
+#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B	MX6SX_PAD_CSI_VSYNC__UART4_DCE_CTS
+#define MX6SX_PAD_ENET2_COL__UART1_RX		MX6SX_PAD_ENET2_COL__UART1_DCE_RX
+#define MX6SX_PAD_ENET2_COL__UART1_TX		MX6SX_PAD_ENET2_COL__UART1_DTE_TX
+#define MX6SX_PAD_ENET2_CRS__UART1_RX		MX6SX_PAD_ENET2_CRS__UART1_DTE_RX
+#define MX6SX_PAD_ENET2_CRS__UART1_TX		MX6SX_PAD_ENET2_CRS__UART1_DCE_TX
+#define MX6SX_PAD_ENET2_RX_CLK__UART1_RTS_B	MX6SX_PAD_ENET2_RX_CLK__UART1_DCE_RTS
+#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B	MX6SX_PAD_ENET2_TX_CLK__UART1_DCE_CTS
+#define MX6SX_PAD_KEY_COL0__UART6_RTS_B		MX6SX_PAD_KEY_COL0__UART6_DCE_RTS
+#define MX6SX_PAD_KEY_COL1__UART6_RX		MX6SX_PAD_KEY_COL1__UART6_DTE_RX
+#define MX6SX_PAD_KEY_COL1__UART6_TX		MX6SX_PAD_KEY_COL1__UART6_DCE_TX
+#define MX6SX_PAD_KEY_COL2__UART5_RTS_B		MX6SX_PAD_KEY_COL2__UART5_DCE_RTS
+#define MX6SX_PAD_KEY_COL3__UART5_RX		MX6SX_PAD_KEY_COL3__UART5_DTE_RX
+#define MX6SX_PAD_KEY_COL3__UART5_TX		MX6SX_PAD_KEY_COL3__UART5_DCE_TX
+#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B		MX6SX_PAD_KEY_ROW0__UART6_DCE_CTS
+#define MX6SX_PAD_KEY_ROW1__UART6_RX		MX6SX_PAD_KEY_ROW1__UART6_DCE_RX
+#define MX6SX_PAD_KEY_ROW1__UART6_TX		MX6SX_PAD_KEY_ROW1__UART6_DTE_TX
+#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B		MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS
+#define MX6SX_PAD_KEY_ROW3__UART5_RX		MX6SX_PAD_KEY_ROW3__UART5_DCE_RX
+#define MX6SX_PAD_KEY_ROW3__UART5_TX		MX6SX_PAD_KEY_ROW3__UART5_DTE_TX
+#define MX6SX_PAD_NAND_DATA04__UART3_RTS_B	MX6SX_PAD_NAND_DATA04__UART3_DCE_RTS
+#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B	MX6SX_PAD_NAND_DATA05__UART3_DCE_CTS
+#define MX6SX_PAD_NAND_DATA06__UART3_RX		MX6SX_PAD_NAND_DATA06__UART3_DCE_RX
+#define MX6SX_PAD_NAND_DATA06__UART3_TX		MX6SX_PAD_NAND_DATA06__UART3_DTE_TX
+#define MX6SX_PAD_NAND_DATA07__UART3_RX		MX6SX_PAD_NAND_DATA07__UART3_DTE_RX
+#define MX6SX_PAD_NAND_DATA07__UART3_TX		MX6SX_PAD_NAND_DATA07__UART3_DCE_TX
+#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B	MX6SX_PAD_QSPI1B_DATA0__UART3_DCE_CTS
+#define MX6SX_PAD_QSPI1B_DATA1__UART3_RTS_B	MX6SX_PAD_QSPI1B_DATA1__UART3_DCE_RTS
+#define MX6SX_PAD_QSPI1B_SCLK__UART3_RX		MX6SX_PAD_QSPI1B_SCLK__UART3_DCE_RX
+#define MX6SX_PAD_QSPI1B_SCLK__UART3_TX		MX6SX_PAD_QSPI1B_SCLK__UART3_DTE_TX
+#define MX6SX_PAD_QSPI1B_SS0_B__UART3_RX	MX6SX_PAD_QSPI1B_SS0_B__UART3_DTE_RX
+#define MX6SX_PAD_QSPI1B_SS0_B__UART3_TX	MX6SX_PAD_QSPI1B_SS0_B__UART3_DCE_TX
+#define MX6SX_PAD_SD1_DATA0__UART2_RX		MX6SX_PAD_SD1_DATA0__UART2_DCE_RX
+#define MX6SX_PAD_SD1_DATA0__UART2_TX		MX6SX_PAD_SD1_DATA0__UART2_DTE_TX
+#define MX6SX_PAD_SD1_DATA1__UART2_RX		MX6SX_PAD_SD1_DATA1__UART2_DTE_RX
+#define MX6SX_PAD_SD1_DATA1__UART2_TX		MX6SX_PAD_SD1_DATA1__UART2_DCE_TX
+#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B	MX6SX_PAD_SD1_DATA2__UART2_DCE_CTS
+#define MX6SX_PAD_SD1_DATA3__UART2_RTS_B	MX6SX_PAD_SD1_DATA3__UART2_DCE_RTS
+#define MX6SX_PAD_SD2_DATA0__UART4_RX		MX6SX_PAD_SD2_DATA0__UART4_DCE_RX
+#define MX6SX_PAD_SD2_DATA0__UART4_TX		MX6SX_PAD_SD2_DATA0__UART4_DTE_TX
+#define MX6SX_PAD_SD2_DATA1__UART4_RX		MX6SX_PAD_SD2_DATA1__UART4_DTE_RX
+#define MX6SX_PAD_SD2_DATA1__UART4_TX		MX6SX_PAD_SD2_DATA1__UART4_DCE_TX
+#define MX6SX_PAD_SD2_DATA2__UART6_RX		MX6SX_PAD_SD2_DATA2__UART6_DCE_RX
+#define MX6SX_PAD_SD2_DATA2__UART6_TX		MX6SX_PAD_SD2_DATA2__UART6_DTE_TX
+#define MX6SX_PAD_SD2_DATA3__UART6_RX		MX6SX_PAD_SD2_DATA3__UART6_DTE_RX
+#define MX6SX_PAD_SD2_DATA3__UART6_TX		MX6SX_PAD_SD2_DATA3__UART6_DCE_TX
+#define MX6SX_PAD_SD3_CLK__UART4_CTS_B		MX6SX_PAD_SD3_CLK__UART4_DCE_CTS
+#define MX6SX_PAD_SD3_CMD__UART4_RX		MX6SX_PAD_SD3_CMD__UART4_DTE_RX
+#define MX6SX_PAD_SD3_CMD__UART4_TX		MX6SX_PAD_SD3_CMD__UART4_DCE_TX
+#define MX6SX_PAD_SD3_DATA2__UART4_RTS_B	MX6SX_PAD_SD3_DATA2__UART4_DCE_RTS
+#define MX6SX_PAD_SD3_DATA3__UART4_RX		MX6SX_PAD_SD3_DATA3__UART4_DCE_RX
+#define MX6SX_PAD_SD3_DATA3__UART4_TX		MX6SX_PAD_SD3_DATA3__UART4_DTE_TX
+#define MX6SX_PAD_SD3_DATA4__UART3_RX		MX6SX_PAD_SD3_DATA4__UART3_DCE_RX
+#define MX6SX_PAD_SD3_DATA4__UART3_TX		MX6SX_PAD_SD3_DATA4__UART3_DTE_TX
+#define MX6SX_PAD_SD3_DATA5__UART3_RX		MX6SX_PAD_SD3_DATA5__UART3_DTE_RX
+#define MX6SX_PAD_SD3_DATA5__UART3_TX		MX6SX_PAD_SD3_DATA5__UART3_DCE_TX
+#define MX6SX_PAD_SD3_DATA6__UART3_RTS_B	MX6SX_PAD_SD3_DATA6__UART3_DCE_RTS
+#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B	MX6SX_PAD_SD3_DATA7__UART3_DCE_CTS
+#define MX6SX_PAD_SD4_DATA4__UART5_RX		MX6SX_PAD_SD4_DATA4__UART5_DCE_RX
+#define MX6SX_PAD_SD4_DATA4__UART5_TX		MX6SX_PAD_SD4_DATA4__UART5_DTE_TX
+#define MX6SX_PAD_SD4_DATA5__UART5_RX		MX6SX_PAD_SD4_DATA5__UART5_DTE_RX
+#define MX6SX_PAD_SD4_DATA5__UART5_TX		MX6SX_PAD_SD4_DATA5__UART5_DCE_TX
+#define MX6SX_PAD_SD4_DATA6__UART5_RTS_B	MX6SX_PAD_SD4_DATA6__UART5_DCE_RTS
+#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B	MX6SX_PAD_SD4_DATA7__UART5_DCE_CTS
+
 #endif /* __DTS_IMX6SX_PINFUNC_H */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-sabreauto.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-sabreauto.dts
@@ -66,12 +66,68 @@
 		enable-active-high;
 		vin-supply = <&reg_can_en>;
 	};
+
+	reg_cs42888: cs42888_supply {
+		compatible = "regulator-fixed";
+		regulator-name = "cs42888_supply";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	sound-cs42888 {
+		compatible = "fsl,imx6-sabreauto-cs42888",
+			     "fsl,imx-audio-cs42888";
+		model = "imx-cs42888";
+		audio-cpu = <&esai>;
+		audio-asrc = <&asrc>;
+		audio-codec = <&cs42888>;
+		audio-routing =
+			"Line Out Jack", "AOUT1L",
+			"Line Out Jack", "AOUT1R",
+			"Line Out Jack", "AOUT2L",
+			"Line Out Jack", "AOUT2R",
+			"Line Out Jack", "AOUT3L",
+			"Line Out Jack", "AOUT3R",
+			"Line Out Jack", "AOUT4L",
+			"Line Out Jack", "AOUT4R",
+			"AIN1L", "Line In Jack",
+			"AIN1R", "Line In Jack",
+			"AIN2L", "Line In Jack",
+			"AIN2R", "Line In Jack";
+	};
+
+	sound-spdif {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-spdif";
+		spdif-controller = <&spdif>;
+		spdif-in;
+	};
 };
 
 &anaclk2 {
 	clock-frequency = <24576000>;
 };
 
+&clks {
+	assigned-clocks = <&clks IMX6SX_PLL4_BYPASS_SRC>,
+			  <&clks IMX6SX_PLL4_BYPASS>,
+			  <&clks IMX6SX_CLK_PLL4_POST_DIV>;
+	assigned-clock-parents = <&clks IMX6SX_CLK_LVDS2_IN>,
+				 <&clks IMX6SX_PLL4_BYPASS_SRC>;
+	assigned-clock-rates = <0>, <0>, <24576000>;
+};
+
+&esai {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_esai>;
+	assigned-clocks = <&clks IMX6SX_CLK_ESAI_SEL>,
+			<&clks IMX6SX_CLK_ESAI_EXTAL>;
+	assigned-clock-parents = <&clks IMX6SX_CLK_PLL4_AUDIO_DIV>;
+	assigned-clock-rates = <0>, <24576000>;
+	status = "okay";
+};
+
 &fec1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet1>;
@@ -99,7 +155,7 @@
 &fec2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet2>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy0>;
 	fsl,magic-packet;
 	status = "okay";
@@ -193,6 +249,21 @@
 		>;
 	};
 
+	pinctrl_esai: esaigrp {
+		fsl,pins = <
+			MX6SX_PAD_CSI_DATA00__ESAI_TX_CLK   0x1b030
+			MX6SX_PAD_CSI_DATA01__ESAI_TX_FS    0x1b030
+			MX6SX_PAD_CSI_HSYNC__ESAI_TX0       0x1b030
+			MX6SX_PAD_CSI_DATA04__ESAI_TX1      0x1b030
+			MX6SX_PAD_CSI_DATA06__ESAI_TX2_RX3  0x1b030
+			MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2  0x1b030
+			MX6SX_PAD_CSI_DATA02__ESAI_RX_CLK   0x1b030
+			MX6SX_PAD_CSI_DATA03__ESAI_RX_FS    0x1b030
+			MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0   0x1b030
+			MX6SX_PAD_CSI_DATA05__ESAI_TX4_RX1  0x1b030
+		>;
+	};
+
 	pinctrl_flexcan1: flexcan1grp {
 		fsl,pins = <
 			MX6SX_PAD_QSPI1B_DQS__CAN1_TX   0x1b020
@@ -227,10 +298,16 @@
 		>;
 	};
 
+	pinctrl_spdif: spdifgrp {
+		fsl,pins = <
+			MX6SX_PAD_ENET2_COL__SPDIF_IN           0x1b0b0
+		>;
+	};
+
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
-			MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1
-			MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX		0x1b0b1
 		>;
 	};
 
@@ -313,6 +390,17 @@
 	pinctrl-0 = <&pinctrl_i2c2>;
 	status = "okay";
 
+	cs42888: cs42888@48 {
+		compatible = "cirrus,cs42888";
+		reg = <0x48>;
+		clocks = <&anaclk2 0>;
+		clock-names = "mclk";
+		VA-supply = <&reg_cs42888>;
+		VD-supply = <&reg_cs42888>;
+		VLS-supply = <&reg_cs42888>;
+		VLC-supply = <&reg_cs42888>;
+	};
+
 	touchscreen@4 {
 		compatible = "eeti,egalax_ts";
 		reg = <0x04>;
@@ -454,6 +542,14 @@
 	};
 };
 
+&spdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spdif>;
+	assigned-clocks = <&clks IMX6SX_CLK_SPDIF_PODF>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
 &wdog1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_wdog>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-sdb-mqs.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-sdb-mqs.dts
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+
+#include "imx6sx-sdb.dts"
+/ {
+
+	sound {
+		status = "disabled";
+	};
+
+	sound-mqs {
+		compatible = "fsl,imx6sx-sdb-mqs",
+			     "fsl,imx-audio-mqs";
+		model = "mqs-audio";
+		audio-cpu = <&sai1>;
+		audio-asrc = <&asrc>;
+		audio-codec = <&mqs>;
+	};
+};
+
+&usdhc2 {
+	/* pin conflict with mqs*/
+	status = "disabled";
+};
+
+&mqs {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_mqs>;
+	clocks = <&clks IMX6SX_CLK_SAI1>;
+	clock-names = "mclk";
+	status = "okay";
+};
+
+&sai1 {
+	pinctrl-0 = <>;
+	status = "okay";
+};
+
+&ssi2 {
+	status = "disabled";
+};
+
+&sdma {
+	gpr = <&gpr>;
+	/* SDMA event remap for SAI1 */
+	fsl,sdma-event-remap = <0 15 1>, <0 16 1>;
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-sdb-reva.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-sdb-reva.dts
@@ -159,10 +159,6 @@
 	vin-supply = <&vgen6_reg>;
 };
 
-&reg_vdd3p0 {
-	vin-supply = <&sw2_reg>;
-};
-
 &reg_vdd2p5 {
 	vin-supply = <&vgen6_reg>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-sdb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-sdb.dts
@@ -141,10 +141,6 @@
 	vin-supply = <&vgen6_reg>;
 };
 
-&reg_vdd3p0 {
-	vin-supply = <&sw2_reg>;
-};
-
 &reg_vdd2p5 {
 	vin-supply = <&vgen6_reg>;
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-sdb.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-sdb.dtsi
@@ -153,6 +153,8 @@
 
 	sound {
 		compatible = "fsl,imx6sx-sdb-wm8962", "fsl,imx-audio-wm8962";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_hp>;
 		model = "wm8962-audio";
 		ssi-controller = <&ssi2>;
 		audio-codec = <&codec>;
@@ -165,6 +167,7 @@
 			"IN3R", "AMIC";
 		mux-int-port = <2>;
 		mux-ext-port = <6>;
+		hp-det-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>;
 	};
 
 	panel {
@@ -179,6 +182,15 @@
 			};
 		};
 	};
+
+	sound-spdif {
+		compatible = "fsl,imx-audio-spdif",
+			   "fsl,imx6sx-sdb-spdif";
+		model = "imx-spdif";
+		spdif-controller = <&spdif>;
+		spdif-out;
+	};
+
 };
 
 &audmux {
@@ -213,7 +225,7 @@
 &fec2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet2>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ethphy2>;
 	status = "okay";
 };
@@ -281,6 +293,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
@@ -296,6 +309,14 @@
 	status = "disabled";
 };
 
+&spdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spdif>;
+	assigned-clocks = <&clks IMX6SX_CLK_SPDIF_PODF>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
 &ssi2 {
 	status = "okay";
 };
@@ -450,6 +471,12 @@
 			>;
 		};
 
+		pinctrl_hp: hpgrp {
+			fsl,pins = <
+				MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x17059
+			>;
+		};
+
 		pinctrl_i2c1: i2c1grp {
 			fsl,pins = <
 				MX6SX_PAD_GPIO1_IO01__I2C1_SDA		0x4001b8b1
@@ -505,6 +532,13 @@
 			>;
 		};
 
+		pinctrl_mqs: mqsgrp {
+			fsl,pins = <
+				MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x120b0
+				MX6SX_PAD_SD2_CMD__MQS_LEFT  0x120b0
+			>;
+		};
+
 		pinctrl_pcie: pciegrp {
 			fsl,pins = <
 				MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x10b0
@@ -562,19 +596,25 @@
 			>;
 		};
 
+		pinctrl_spdif: spdifgrp {
+			fsl,pins = <
+				MX6SX_PAD_SD4_DATA4__SPDIF_OUT          0x1b0b0
+			>;
+		};
+
 		pinctrl_uart1: uart1grp {
 			fsl,pins = <
-				MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1
-				MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1
+				MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX	0x1b0b1
+				MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX	0x1b0b1
 			>;
 		};
 
 		pinctrl_uart5: uart5grp {
 			fsl,pins = <
-				MX6SX_PAD_KEY_ROW3__UART5_RX		0x1b0b1
-				MX6SX_PAD_KEY_COL3__UART5_TX		0x1b0b1
-				MX6SX_PAD_KEY_ROW2__UART5_CTS_B		0x1b0b1
-				MX6SX_PAD_KEY_COL2__UART5_RTS_B		0x1b0b1
+				MX6SX_PAD_KEY_ROW3__UART5_DCE_RX	0x1b0b1
+				MX6SX_PAD_KEY_COL3__UART5_DCE_TX	0x1b0b1
+				MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS	0x1b0b1
+				MX6SX_PAD_KEY_COL2__UART5_DCE_RTS	0x1b0b1
 			>;
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts
@@ -352,6 +352,12 @@
 		>;
 	};
 
+	pinctrl_pcie: pciegrp {
+		fsl,pins = <
+			MX6SX_PAD_NAND_DATA02__GPIO4_IO_6	0x10b0
+		>;
+	};
+
 	pinctrl_pwm1: pwm1grp-1 {
 		fsl,pins = <
 			/* blue LED */
@@ -384,15 +390,15 @@
 
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
-			MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1
-			MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX	0x1b0b1
+			MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX	0x1b0b1
 		>;
 	};
 
 	pinctrl_uart2: uart2grp {
 		fsl,pins = <
-			MX6SX_PAD_GPIO1_IO06__UART2_TX		0x1b0b1
-			MX6SX_PAD_GPIO1_IO07__UART2_RX		0x1b0b1
+			MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX	0x1b0b1
+			MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX	0x1b0b1
 		>;
 	};
 
@@ -490,19 +496,30 @@
 	};
 };
 
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>;
+	reset-gpio-active-high;
+	status = "okay";
+};
+
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
 };
 
 &pwm2 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm2>;
 	status = "okay";
 };
 
 &pwm6 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm6>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
@@ -235,28 +235,28 @@
 
 	pinctrl_uart1: uart1grp {
 		fsl,pins =
-			<MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1>,
-			<MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1>;
+			<MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX	0x1b0b1>,
+			<MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX	0x1b0b1>;
 	};
 
 	pinctrl_uart2: uart2grp {
 		fsl,pins =
-			<MX6SX_PAD_GPIO1_IO06__UART2_TX		0x1b0b1>,
-			<MX6SX_PAD_GPIO1_IO07__UART2_RX		0x1b0b1>;
+			<MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX	0x1b0b1>,
+			<MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX	0x1b0b1>;
 	};
 
 	pinctrl_uart3: uart3grp {
 		fsl,pins =
-			<MX6SX_PAD_SD3_DATA4__UART3_RX          0x13059>,
-			<MX6SX_PAD_SD3_DATA5__UART3_TX          0x13059>,
-			<MX6SX_PAD_SD3_DATA6__UART3_RTS_B       0x13059>,
-			<MX6SX_PAD_SD3_DATA7__UART3_CTS_B       0x13059>;
+			<MX6SX_PAD_SD3_DATA4__UART3_DCE_RX	0x13059>,
+			<MX6SX_PAD_SD3_DATA5__UART3_DCE_TX	0x13059>,
+			<MX6SX_PAD_SD3_DATA6__UART3_DCE_RTS	0x13059>,
+			<MX6SX_PAD_SD3_DATA7__UART3_DCE_CTS	0x13059>;
 	};
 
 	pinctrl_uart5: uart5grp {
 		fsl,pins =
-			<MX6SX_PAD_SD4_DATA4__UART5_RX		0x1b0b1>,
-			<MX6SX_PAD_SD4_DATA5__UART5_TX		0x1b0b1>;
+			<MX6SX_PAD_SD4_DATA4__UART5_DCE_RX	0x1b0b1>,
+			<MX6SX_PAD_SD4_DATA5__UART5_DCE_TX	0x1b0b1>;
 	};
 
 	pinctrl_uart6: uart6grp {
@@ -265,10 +265,10 @@
 			<MX6SX_PAD_CSI_DATA01__UART6_DSR_B	0x1b0b1>,
 			<MX6SX_PAD_CSI_DATA02__UART6_DTR_B	0x1b0b1>,
 			<MX6SX_PAD_CSI_DATA03__UART6_DCD_B	0x1b0b1>,
-			<MX6SX_PAD_CSI_DATA04__UART6_RX		0x1b0b1>,
-			<MX6SX_PAD_CSI_DATA05__UART6_TX		0x1b0b1>,
-			<MX6SX_PAD_CSI_DATA06__UART6_RTS_B	0x1b0b1>,
-			<MX6SX_PAD_CSI_DATA07__UART6_CTS_B	0x1b0b1>;
+			<MX6SX_PAD_CSI_DATA04__UART6_DCE_RX	0x1b0b1>,
+			<MX6SX_PAD_CSI_DATA05__UART6_DCE_TX	0x1b0b1>,
+			<MX6SX_PAD_CSI_DATA06__UART6_DCE_RTS	0x1b0b1>,
+			<MX6SX_PAD_CSI_DATA07__UART6_DCE_CTS	0x1b0b1>;
 	};
 
 	pinctrl_otg1_reg: otg1grp {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-x6med35-pdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-x6med35-pdk.dts
@@ -0,0 +1,944 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 Shrirang Bagul <shrirang.bagul@canonical.com>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/sound/fsl-imx-audmux.h>
+#include "imx6sx-x6med35-som.dtsi"
+
+/ {
+	model = "Honeywell i.MX6SX X6Med35 PDK";
+	compatible = "Honeywell,x6med35-pdk", "fsl,imx6sx";
+
+	aliases {
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		watchdog0 = &rtc;
+		watchdog1 = &wdog1;
+	};
+
+	beeper {
+		compatible = "pwm-beeper";
+		pwms = <&pwm4 0 1000000 0>;
+	};
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpiokeys>;
+
+		s1 {
+			label = "s1";
+			gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_ESC>;
+			wakeup-source;
+		};
+
+		s2 {
+			label = "s2";
+			gpios = <&gpio4 12 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_SPACE>;
+			wakeup-source;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		dl1 {
+			label = "yellow:dl1";
+			gpios = <&led_expander 0 GPIO_ACTIVE_LOW>;
+		};
+
+		dl2 {
+			label = "blue:dl2";
+			gpios = <&led_expander 1 GPIO_ACTIVE_LOW>;
+		};
+
+		dl3 {
+			label = "green:dl3";
+			gpios = <&led_expander 2 GPIO_ACTIVE_LOW>;
+		};
+
+		dl4 {
+			label = "green:dl4";
+			gpios = <&led_expander 3 GPIO_ACTIVE_LOW>;
+		};
+
+		dl5 {
+			label = "green:dl5";
+			gpios = <&led_expander 4 GPIO_ACTIVE_LOW>;
+		};
+
+		dl6 {
+			label = "green:dl6";
+			gpios = <&led_expander 5 GPIO_ACTIVE_LOW>;
+		};
+
+		dl7 {
+			label = "green:dl7";
+			gpios = <&led_expander 6 GPIO_ACTIVE_LOW>;
+		};
+
+		dl8 {
+			label = "green:dl8";
+			gpios = <&led_expander 7 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-0 = <&pinctrl_usb_vbus>;
+		pinctrl-names = "default";
+		regulator-name = "vbus_usb_pwr_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_cam_1v8: regulator-cam-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "cam_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&gpio_exp_20 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_cam_2v8: regulator-cam-2v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "cam_2v8";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&gpio_exp_20 15 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_wifi: regulator-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "wifi_power";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		startup-delay-us = <10000>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_bt_power: regulator-bt-power {
+		compatible = "regulator-fixed";
+		regulator-name = "bt_power";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		startup-delay-us = <10000>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_v_3v3: regulator-v-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_3v3";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_v_5v0: regulator-v-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_5v0";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "x6med35-audio";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,bitclock-master = <&sound_codec>;
+		simple-audio-card,frame-master = <&sound_codec>;
+		simple-audio-card,widgets =
+						"Microphone", "AMIC",
+						"Speaker", "Ext Spk";
+		simple-audio-card,routing =
+						"Ext Spk", "LSPK",
+						"Ext Spk", "RSPK",
+					    "RMICP", "AMIC",
+					    "RMICN", "AMIC",
+					    "AMIC", "Mic Bias";
+
+		sound_cpu: simple-audio-card,cpu {
+			sound-dai = <&ssi2>;
+		};
+
+		sound_codec: simple-audio-card,codec {
+			sound-dai = <&codec>;
+			clocks = <&clks IMX6SX_CLK_AUDIO>;
+		};
+	};
+};
+
+&adc1 {
+	vref-supply = <&reg_v_3v3>;
+	status = "okay";
+};
+
+&adc2 {
+	vref-supply = <&reg_v_3v3>;
+	status = "okay";
+};
+
+&anatop {
+	status = "disabled";
+};
+
+&audmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_audmux>;
+	status = "okay";
+
+	ssi2 {
+		fsl,audmux-port = <1>;
+		fsl,port-config = <
+			(IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TFSEL(2) |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR |
+			IMX_AUDMUX_V2_PTCR_TCSEL(2))
+			IMX_AUDMUX_V2_PDCR_RXDSEL(2)
+		>;
+	};
+
+	aud3 {
+		fsl,audmux-port = <2>;
+		fsl,port-config = <
+			IMX_AUDMUX_V2_PTCR_SYN
+			IMX_AUDMUX_V2_PDCR_RXDSEL(1)
+		>;
+	};
+};
+
+&csi1 {
+	compatible = "fsl,imx6s-csi";
+	status = "okay";
+
+	/delete-property/clock-names;
+	clock-names = "disp-axi", "csi_mclk", "disp_dcic";
+	power-domains = <&pd_disp>;
+
+	port {
+		csi1_ep: endpoint {
+			remote-endpoint = <&ov5640_ep>;
+		};
+	};
+};
+
+/* Common module P1 */
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	num-cs = <1>;
+	cs-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+
+	spidev@0 {
+		compatible = "rohm,dh2228fv";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+		dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
+		dma-names = "rx", "tx";
+	};
+};
+
+/* Common module P2 */
+&ecspi3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi3>;
+	status = "okay";
+
+	num-cs = <1>;
+	cs-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
+
+	spidev@0 {
+		compatible = "rohm,dh2228fv";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+		dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
+		dma-names = "rx", "tx";
+	};
+};
+
+/* LTE module */
+&ecspi5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi5>;
+	status = "okay";
+
+	num-cs = <1>;
+	cs-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+
+	spidev@0 {
+		compatible = "rohm,dh2228fv";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+		dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
+		dma-names = "rx", "tx";
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	phy-reset-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+	phy-reset-duration = <20>;
+	nvmem-cells = <&eth_mac1>;
+	nvmem-cell-names = "mac-address";
+	nvmem_macaddr_swap;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			micrel,led-mode = <0>;
+		};
+	};
+};
+
+&fec2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet2>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy1>;
+	phy-reset-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
+	phy-reset-duration = <20>;
+	nvmem-cells = <&eth_mac2>;
+	nvmem-cell-names = "mac-address";
+	nvmem_macaddr_swap;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy1: ethernet-phy@2 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <2>;
+			micrel,led-mode = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	rtc: rtc@68 {
+		compatible = "st,m41t82";
+		reg = <0x68>;
+	};
+
+	codec: nau8822@1a {
+		compatible = "nuvoton,nau8822";
+		reg = <0x1a>;
+		clocks = <&clks IMX6SX_CLK_AUDIO>;
+		#sound-dai-cells = <0>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	clock-frequency = <1000000>;
+	status = "okay";
+
+	eeeprom: eeeprom@52 {
+		compatible = "microchip,24lc32ac", "atmel,24c32";
+		reg = <0x52>;
+		page-size = <32>;
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	gpio_exp_20: gpio@20 {
+		compatible = "ti,tca6416";
+		reg = <0x20>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+		gpio-line-names =
+			"port1_3v3_pwr_ctl", "port2_3v3_pwr_ctl",
+			"common_port1_nrst", "common_port2_nrst",
+			"board_id_1", "board_id_2", "board_id_3",
+			"board_id_4", "lte_igt", "lte_radio_usb_ctrl",
+			"lte_pwr_en", "lte_emergency_off", "lte_uart_dtr",
+			"lte_vdd5v_en",	"cam_1v8_en", "cam_2v8_en";
+	};
+
+	led_expander: led-controller@21 {
+		compatible = "ti,tca6408";
+		reg = <0x21>;
+		vcc-supply = <&reg_vdd_3v3>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	ov5640: camera@3c {
+		compatible = "ovti,ov5640";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ov5640>;
+		reg = <0x3c>;
+		clocks = <&clks IMX6SX_CLK_CSI>;
+		clock-names = "csi_mclk";
+		DOVDD-supply = <&reg_cam_1v8>; /* 1.8v */
+		AVDD-supply = <&reg_cam_2v8>;  /* 2.8v */
+		DVDD-supply = <&reg_cam_1v8>;  /* 1.8v */
+		pwn-gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>;
+		rst-gpios = <&gpio3 17 GPIO_ACTIVE_LOW>;
+		csi_id = <0>;
+		mclk = <24000000>;
+		mclk_source = <0>;
+		rotation = <180>;
+
+		port {
+			/* Parallel bus endpoint */
+			ov5640_ep: endpoint {
+				remote-endpoint = <&csi1_ep>;
+				bus-width = <8>;
+				data-shift = <2>; /* lines 9:2 are used */
+				hsync-active = <0>;
+				vsync-active = <0>;
+				pclk-sample = <1>;
+			};
+		};
+	};
+};
+
+&ocotp {
+	eth_mac1: mac-address@88 {
+		reg = <0x88 6>;
+	};
+
+	eth_mac2: mac-address@8c {
+		reg = <0x8c 6>;
+	};
+};
+
+&pwm4 {
+	#pwm-cells = <2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm4>;
+	status = "okay";
+};
+
+&pxp {
+	status = "okay";
+};
+
+&qspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi2>;
+	status = "disabled";
+
+	flash0: w25q128@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "winbond,w25q128", "jedec,spi-nor";
+		spi-max-frequency = <15625000>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+		reg = <0>;
+	};
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&ssi2 {
+	status = "okay";
+};
+
+&usbotg1 {
+	vbus-supply = <&reg_usb_otg1_vbus>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb_otg1_id>;
+	srp-disable;
+	hnp-disable;
+	adp-disable;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbotg2 {
+	pinctrl-names = "default";
+	srp-disable;
+	hnp-disable;
+	adp-disable;
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbphy1 {
+	fsl,tx-d-cal = <106>;
+};
+
+&usbphy2 {
+	fsl,tx-d-cal = <106>;
+};
+
+/* Cortex-A9 Debug UART */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+/* UART For BT */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+/* UART For WWAN/Modem */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+/* UART For RS-485#P11*/
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	rts-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+	linux,rs485-enabled-at-boot-time;
+	rs485-rx-during-tx;
+	status = "okay";
+};
+
+/* UART For RS-485#P12*/
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>;
+	rts-gpios = <&gpio2 17 GPIO_ACTIVE_LOW>;
+	linux,rs485-enabled-at-boot-time;
+	rs485-rx-during-tx;
+	status = "okay";
+};
+
+/* UART For TTL-232#P15/P19*/
+&uart6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart6>;
+	status = "okay";
+};
+
+/* Wifi SDIO */
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	vmmc-supply = <&reg_wifi>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	status = "okay";
+
+	wifi@1 {
+		compatible = "brcm,bcm4329-fmac";
+		reg = <1>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	imx6x-x6med35-som {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_hog1 &pinctrl_board_id>;
+
+		pinctrl_hog1: hoggrp-1 {
+			fsl,pins = <
+				MX6SX_PAD_USB_H_DATA__GPIO7_IO_10	0x83030
+			>;
+		};
+
+		pinctrl_board_id: hoggrp-2 {
+			fsl,pins = <
+				MX6SX_PAD_LCD1_DATA00__GPIO3_IO_1	0x110b0
+				MX6SX_PAD_LCD1_DATA01__GPIO3_IO_2	0x110b0
+				MX6SX_PAD_LCD1_DATA02__GPIO3_IO_3	0x110b0
+				MX6SX_PAD_LCD1_DATA23__GPIO3_IO_24	0x110b0
+			>;
+		};
+
+		pinctrl_audmux: audmuxgrp {
+			fsl,pins = <
+				MX6SX_PAD_LCD1_ENABLE__AUDMUX_AUD3_TXC	0x130b0
+				MX6SX_PAD_LCD1_VSYNC__AUDMUX_AUD3_TXFS	0x130b0
+				MX6SX_PAD_LCD1_HSYNC__AUDMUX_AUD3_TXD	0x12098
+				MX6SX_PAD_LCD1_RESET__AUDMUX_AUD3_RXD	0x130b0
+				MX6SX_PAD_ENET1_MDIO__AUDMUX_MCLK	0x13098
+			>;
+		};
+
+		pinctrl_ecspi1: ecspi1grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1A_DATA0__ECSPI1_MOSI		0x1b091
+				MX6SX_PAD_QSPI1A_DATA1__ECSPI1_MISO		0x1b091
+				MX6SX_PAD_QSPI1A_SCLK__ECSPI1_SCLK		0x1b099
+				MX6SX_PAD_QSPI1A_SS0_B__GPIO4_IO_22		0x0b0b9
+			>;
+		};
+
+		pinctrl_ecspi3: ecspi3grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI		0x1b091
+				MX6SX_PAD_QSPI1B_DATA1__ECSPI3_MISO		0x1b091
+				MX6SX_PAD_QSPI1B_SCLK__ECSPI3_SCLK		0x1b099
+				MX6SX_PAD_QSPI1B_SS0_B__GPIO4_IO_30		0x0b0b9
+			>;
+		};
+
+		pinctrl_ecspi5: ecspi5grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1A_DQS__ECSPI5_MOSI		0x1b091
+				MX6SX_PAD_QSPI1A_SS1_B__ECSPI5_MISO		0x1b091
+				MX6SX_PAD_QSPI1B_SS1_B__ECSPI5_SCLK		0x1b099
+				MX6SX_PAD_QSPI1B_DQS__GPIO4_IO_28		0x0b0b9
+			>;
+		};
+
+		pinctrl_enet1: enet1grp {
+			fsl,pins = <
+				MX6SX_PAD_ENET2_CRS__ENET1_MDIO		0xa0b1
+				MX6SX_PAD_ENET2_COL__ENET1_MDC		0xa0b1
+
+				MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0	0xa0b1
+				MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1	0xa0b1
+				MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2	0xa0b1
+				MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3	0xa0b1
+				MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN	0xa0b1
+				MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC	0xa0b9
+
+				MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0	0x3081
+				MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1	0x3081
+				MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2	0x3081
+				MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3	0x3081
+				MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK	0x3081
+				MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN	0x3081
+
+				/* phy reset */
+				MX6SX_PAD_ENET1_RX_CLK__GPIO2_IO_4		0x10b0
+			>;
+		};
+
+		pinctrl_rmii_enet1: rmiienet1grp {
+			fsl,pins = <
+				MX6SX_PAD_ENET2_CRS__ENET1_MDIO		0xa089
+				MX6SX_PAD_ENET2_COL__ENET1_MDC		0xa089
+
+				MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0   0xb099
+				MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1   0xb099
+				MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN	0xb099
+				MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4000b099
+
+				MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0   0xb099
+				MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1   0xb099
+				MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN   	0xb099
+				MX6SX_PAD_RGMII1_RXC__ENET1_RX_ER 	0xb099
+
+				/* phy reset */
+				MX6SX_PAD_ENET1_RX_CLK__GPIO2_IO_4 	0xb099
+			>;
+		};
+
+		pinctrl_enet2: enet2grp {
+			fsl,pins = <
+				MX6SX_PAD_ENET1_CRS__ENET2_MDIO		0xa0b1
+				MX6SX_PAD_ENET1_COL__ENET2_MDC		0xa0b1
+
+				MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0	0xa0b1
+				MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1	0xa0b1
+				MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2	0xa0b1
+				MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3	0xa0b1
+				MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN	0xa0b1
+				MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC	0xa0b9
+
+				MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0	0x3081
+				MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1	0x3081
+				MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2	0x3081
+				MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3	0x3081
+				MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK	0x3081
+				MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN	0x3081
+
+				/* phy reset */
+				MX6SX_PAD_ENET1_MDC__GPIO2_IO_2		0x10b0
+			>;
+		};
+
+		pinctrl_rmii_enet2: rmiienet2grp {
+			fsl,pins = <
+				MX6SX_PAD_ENET1_CRS__ENET2_MDIO		0xa089
+				MX6SX_PAD_ENET1_COL__ENET2_MDC		0xa089
+
+				MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0	0xb099
+				MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1	0xb099
+				MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN	0xb099
+				MX6SX_PAD_RGMII2_RXC__ENET2_RX_ER	0xb099
+
+				MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0	0xb099
+				MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1	0xb099
+				MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN	0xb099
+				MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4000b099
+
+				/* phy reset */
+				MX6SX_PAD_ENET1_MDC__GPIO2_IO_2		0xb099
+			>;
+		};
+
+		pinctrl_flexcan1: flexcan1grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1B_DQS__CAN1_TX		0x1b020
+				MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX		0x1b020
+			>;
+		};
+
+		pinctrl_flexcan2: flexcan2grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX		0x1b020
+				MX6SX_PAD_QSPI1A_DQS__CAN2_TX		0x1b020
+			>;
+		};
+
+		pinctrl_gpiokeys: gpiokeysgrp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO11__GPIO1_IO_11		0xf000
+				MX6SX_PAD_NAND_RE_B__GPIO4_IO_12		0xf000
+			>;
+		};
+
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO01__I2C1_SDA		0x4001b8b1
+				MX6SX_PAD_GPIO1_IO00__I2C1_SCL		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6SX_PAD_KEY_ROW4__I2C3_SDA		0x4001b8b1
+				MX6SX_PAD_KEY_COL4__I2C3_SCL		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c4: i2c4grp {
+			fsl,pins = <
+				MX6SX_PAD_SD3_DATA1__I2C4_SDA		0x4001b8b1
+				MX6SX_PAD_SD3_DATA0__I2C4_SCL		0x4001b8b1
+			>;
+		};
+
+		pinctrl_mqs: mqsgrp {
+			fsl,pins = <
+				MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x120b0
+				MX6SX_PAD_SD2_CMD__MQS_LEFT  0x120b0
+			>;
+		};
+
+		pinctrl_ov5640: ov5640grp {
+			fsl,pins = <
+				MX6SX_PAD_LCD1_DATA07__CSI1_MCLK		0x110b0
+				MX6SX_PAD_LCD1_DATA06__CSI1_PIXCLK		0x110b0
+				MX6SX_PAD_LCD1_DATA04__CSI1_VSYNC		0x110b0
+				MX6SX_PAD_LCD1_DATA05__CSI1_HSYNC		0x110b0
+				MX6SX_PAD_LCD1_DATA15__CSI1_DATA_2		0x110b0
+				MX6SX_PAD_LCD1_DATA14__CSI1_DATA_3		0x110b0
+				MX6SX_PAD_LCD1_DATA13__CSI1_DATA_4		0x110b0
+				MX6SX_PAD_LCD1_DATA12__CSI1_DATA_5		0x110b0
+				MX6SX_PAD_LCD1_DATA11__CSI1_DATA_6		0x110b0
+				MX6SX_PAD_LCD1_DATA10__CSI1_DATA_7		0x110b0
+				MX6SX_PAD_LCD1_DATA09__CSI1_DATA_8		0x110b0
+				MX6SX_PAD_LCD1_DATA08__CSI1_DATA_9		0x110b0
+
+				MX6SX_PAD_LCD1_DATA16__GPIO3_IO_17		0x80000000
+				MX6SX_PAD_LCD1_DATA17__GPIO3_IO_18		0x80000000
+			>;
+		};
+
+		pinctrl_pwm4: pwm4grp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO13__PWM4_OUT 0x110b0
+			>;
+		};
+
+		pinctrl_qspi2: qspi2grp {
+			fsl,pins = <
+				MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0     0x70f1
+				MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1  0x70f1
+				MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2    0x70f1
+				MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3    0x70f1
+				MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK        0x70f1
+				MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B       0x70f1
+			>;
+		};
+
+		pinctrl_vcc_sd3: vccsd3grp {
+			fsl,pins = <
+				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059
+			>;
+		};
+
+		pinctrl_sai1: sai1grp {
+			fsl,pins = <
+				MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK	0x130b0
+				MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC	0x130b0
+				MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0	0x120b0
+				MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0	0x130b0
+				MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK	0x130b0
+			>;
+		};
+
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX	0x1b0b1
+				MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart2: uart2grp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO06__UART2_DCE_TX	0x1b0b1
+				MX6SX_PAD_GPIO1_IO07__UART2_DCE_RX	0x1b0b1
+				MX6SX_PAD_GPIO1_IO08__UART2_RTS_B	0x1b0b1
+				MX6SX_PAD_GPIO1_IO09__UART2_CTS_B	0x1b0b1
+				/* bt_reg GPIO */
+				MX6SX_PAD_GPIO1_IO02__GPIO1_IO_2	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart3: uart3grp {
+			fsl,pins = <
+				MX6SX_PAD_SD3_DATA4__UART3_RX	0x1b0b1
+				MX6SX_PAD_SD3_DATA5__UART3_TX	0x1b0b1
+				MX6SX_PAD_SD3_DATA6__UART3_RTS_B	0x1b0b1
+				MX6SX_PAD_SD3_DATA7__UART3_CTS_B	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart4: uart4grp {
+			fsl,pins = <
+				MX6SX_PAD_SD3_CMD__UART4_DCE_TX	0x1b0b1
+				MX6SX_PAD_SD3_DATA3__UART4_DCE_RX	0x1b0b1
+				MX6SX_PAD_SD3_CLK__UART4_DCE_CTS	0x1b0b1
+				MX6SX_PAD_SD3_DATA2__UART4_DCE_RTS	0x1b0b1
+				/* RS485_CM_PORT_UART_SEL#2 */
+				MX6SX_PAD_NAND_WE_B__GPIO4_IO_14	0x0b0b9
+			>;
+		};
+
+		pinctrl_uart5: uart5grp {
+			fsl,pins = <
+				MX6SX_PAD_KEY_ROW3__UART5_DCE_RX	0x1b0b1
+				MX6SX_PAD_KEY_COL3__UART5_DCE_TX	0x1b0b1
+				MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS	0x1b0b1
+				MX6SX_PAD_KEY_COL2__UART5_DCE_RTS	0x1b0b1
+				/* RS485_CM_PORT_UART_SEL#1 */
+				MX6SX_PAD_NAND_DATA05__GPIO4_IO_9	0x0b0b9
+			>;
+		};
+
+		pinctrl_uart6: uart6grp {
+			fsl,pins = <
+				MX6SX_PAD_KEY_COL1__UART6_DCE_TX	0x1b0b1
+				MX6SX_PAD_KEY_ROW1__UART6_DCE_RX	0x1b0b1
+				/* RS232_UART_SEL */
+				MX6SX_PAD_KEY_ROW0__GPIO2_IO_15		0x0b0b9
+			>;
+		};
+
+		pinctrl_usb_cc: usbccgrp {
+			fsl,pins = <
+				MX6SX_PAD_LCD1_DATA22__GPIO3_IO_23	0x10b0
+			>;
+		};
+
+		pinctrl_usb_vbus: usbvbusgrp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1A_DATA2__GPIO4_IO_18	0x10b0
+			>;
+		};
+
+		pinctrl_usb_otg1_id: usbotg1idgrp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID	0x17059
+				MX6SX_PAD_QSPI1A_DATA3__USB_OTG1_OC		0x17059
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				MX6SX_PAD_SD2_CMD__USDHC2_CMD		0x17059
+				MX6SX_PAD_SD2_CLK__USDHC2_CLK		0x10059
+				MX6SX_PAD_SD2_DATA0__USDHC2_DATA0	0x17059
+				MX6SX_PAD_SD2_DATA1__USDHC2_DATA1	0x17059
+				MX6SX_PAD_SD2_DATA2__USDHC2_DATA2	0x17059
+				MX6SX_PAD_SD2_DATA3__USDHC2_DATA3	0x17059
+				/* wifi power GPIO */
+				MX6SX_PAD_KEY_COL0__GPIO2_IO_10		0x17059
+			>;
+		};
+
+		pinctrl_wdog: wdoggrp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO03__WDOG2_WDOG_B 0x30b0
+			>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx-x6med35-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx-x6med35-som.dtsi
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 Shrirang Bagul <shrirang.bagul@canonical.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "imx6sx.dtsi"
+
+/ {
+	memory@80000000 {
+		device_type = "memory";
+		linux,usable-memory = <0x80000000 0x1ff00000>;
+	};
+
+	ocram_optee {
+		compatible = "fsl,optee-lpm-sram";
+		reg = <0x008f8000 0x4000>;
+		overw_reg = <&ocram 0x00904000 0x1000>,
+					<&ocram 0x00905000 0x1b000>,
+					<&ocram_s 0x00900000 0x4000>;
+		overw_clock = <&ocram_s &clks IMX6SX_CLK_OCRAM>;
+	};
+
+	pxp_v4l2_out {
+		compatible = "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
+		status = "okay";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x8000000>;
+			linux,cma-default;
+		};
+
+		m4_reserved {
+			reg = <0x9ff00000 0xf0000>;
+			no-map;
+		};
+
+		rpmsg_reserved {
+			reg = <0x9ff00000 0x10000>;
+			no-map;
+		};
+	};
+
+	reg_vdd_3v3: regulator-vdd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "vdd_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_vdd_1v8: regulator-vdd-1v8 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "vdd_1v8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	reg_vdd_1v38: regulator-vdd-1v38 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "vdd_1v38";
+		regulator-min-microvolt = <1380000>;
+		regulator-max-microvolt = <1380000>;
+	};
+
+	rpmsg: rpmsg {
+		compatible = "fsl,imx6sx-rpmsg";
+		vdev-nums = <1>;
+		reg = <0xbff00000 0x10000>;
+		status = "okay";
+	};
+};
+
+&aips2 {
+	qspi_m4: qspi-m4 {
+		compatible = "fsl,imx6sx-qspi-m4-restore";
+		reg = <0x021e4000 0x4000>;
+		status = "disabled";
+	};
+};
+
+&aips3 {
+	sema4: sema4@02290000 { /* sema4 */
+		compatible = "fsl,imx6sx-sema4";
+		reg = <0x02290000 0x4000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+		status = "okay";
+	};
+
+	mu: mailbox@02294000 { /* mu */
+		compatible = "fsl,imx6sx-mu";
+		reg = <0x02294000 0x4000>;
+		interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+		status = "okay";
+	};
+};
+
+&gpc {
+	fsl,ldo-bypass = <1>;
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ext_crypto: extcrypto@60 {
+		compatible = "atmel,atecc508a";
+		reg = <0x60>;
+	};
+};
+
+&ocram {
+	reg = <0x00901000 0xf000>;
+};
+
+&reg_vdd1p1 {
+	vin-supply = <&reg_vdd_3v3>;
+};
+
+&reg_vdd2p5 {
+	vin-supply = <&reg_vdd_3v3>;
+};
+
+&reg_arm {
+	vin-supply = <&reg_vdd_1v38>;
+	regulator-allow-bypass;
+};
+
+&reg_soc {
+	vin-supply = <&reg_vdd_1v38>;
+	regulator-allow-bypass;
+};
+
+&usdhc4 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	pinctrl-1 = <&pinctrl_usdhc4_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc4_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	no-1-8-v;
+	vmmc-supply = <&reg_vdd_3v3>;
+	keep-power-in-suspend;
+	status = "okay";
+};
+
+&iomuxc {
+	imx6x-x6med35-som {
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6SX_PAD_QSPI1B_DATA2__I2C2_SDA		0x4001b8b1
+				MX6SX_PAD_QSPI1B_DATA3__I2C2_SCL		0x4001b8b1
+			>;
+		};
+
+		pinctrl_usdhc4: usdhc4grp {
+			fsl,pins = <
+				MX6SX_PAD_SD4_CMD__USDHC4_CMD		0x17059
+				MX6SX_PAD_SD4_CLK__USDHC4_CLK		0x10059
+				MX6SX_PAD_SD4_DATA0__USDHC4_DATA0	0x17059
+				MX6SX_PAD_SD4_DATA1__USDHC4_DATA1	0x17059
+				MX6SX_PAD_SD4_DATA2__USDHC4_DATA2	0x17059
+				MX6SX_PAD_SD4_DATA3__USDHC4_DATA3	0x17059
+				MX6SX_PAD_SD4_DATA4__USDHC4_DATA4	0x17059
+				MX6SX_PAD_SD4_DATA5__USDHC4_DATA5	0x17059
+				MX6SX_PAD_SD4_DATA6__USDHC4_DATA6	0x17059
+				MX6SX_PAD_SD4_DATA7__USDHC4_DATA7	0x17059
+			>;
+		};
+
+		pinctrl_usdhc4_100mhz: usdhc4grp-100mhz {
+			fsl,pins = <
+				MX6SX_PAD_SD4_CMD__USDHC4_CMD		0x170b9
+				MX6SX_PAD_SD4_CLK__USDHC4_CLK		0x100b9
+				MX6SX_PAD_SD4_DATA0__USDHC4_DATA0	0x170b9
+				MX6SX_PAD_SD4_DATA1__USDHC4_DATA1	0x170b9
+				MX6SX_PAD_SD4_DATA2__USDHC4_DATA2	0x170b9
+				MX6SX_PAD_SD4_DATA3__USDHC4_DATA3	0x170b9
+				MX6SX_PAD_SD4_DATA4__USDHC4_DATA4	0x170b9
+				MX6SX_PAD_SD4_DATA5__USDHC4_DATA5	0x170b9
+				MX6SX_PAD_SD4_DATA6__USDHC4_DATA6	0x170b9
+				MX6SX_PAD_SD4_DATA7__USDHC4_DATA7	0x170b9
+			>;
+		};
+
+		pinctrl_usdhc4_200mhz: usdhc4grp-200mhz {
+			fsl,pins = <
+				MX6SX_PAD_SD4_CMD__USDHC4_CMD		0x170f9
+				MX6SX_PAD_SD4_CLK__USDHC4_CLK		0x100f9
+				MX6SX_PAD_SD4_DATA0__USDHC4_DATA0	0x170f9
+				MX6SX_PAD_SD4_DATA1__USDHC4_DATA1	0x170f9
+				MX6SX_PAD_SD4_DATA2__USDHC4_DATA2	0x170f9
+				MX6SX_PAD_SD4_DATA3__USDHC4_DATA3	0x170f9
+				MX6SX_PAD_SD4_DATA4__USDHC4_DATA4	0x170f9
+				MX6SX_PAD_SD4_DATA5__USDHC4_DATA5	0x170f9
+				MX6SX_PAD_SD4_DATA6__USDHC4_DATA6	0x170f9
+				MX6SX_PAD_SD4_DATA7__USDHC4_DATA7	0x170f9
+			>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6sx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6sx.dtsi
@@ -49,6 +49,9 @@
 		spi2 = &ecspi3;
 		spi3 = &ecspi4;
 		spi4 = &ecspi5;
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
+		usb2 = &usbh;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
 	};
@@ -87,6 +90,8 @@
 				      "pll1_sw", "pll1_sys";
 			arm-supply = <&reg_arm>;
 			soc-supply = <&reg_soc>;
+			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cell-names = "speed_grade";
 		};
 	};
 
@@ -132,14 +137,10 @@
 		clock-output-names = "anaclk2";
 	};
 
-	tempmon: tempmon {
-		compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon";
-		interrupt-parent = <&gpc>;
-		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
-		fsl,tempmon = <&anatop>;
-		nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
-		nvmem-cell-names = "calib", "temp_grade";
-		clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
+	mqs: mqs {
+		compatible = "fsl,imx6sx-mqs";
+		gpr = <&gpr>;
+		status = "disabled";
 	};
 
 	pmu {
@@ -163,12 +164,18 @@
 		ocram_s: sram@8f8000 {
 			compatible = "mmio-sram";
 			reg = <0x008f8000 0x4000>;
+			ranges = <0 0x008f8000 0x4000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6SX_CLK_OCRAM_S>;
 		};
 
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x20000>;
+			ranges = <0 0x00900000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			clocks = <&clks IMX6SX_CLK_OCRAM>;
 		};
 
@@ -181,7 +188,7 @@
 			interrupt-parent = <&intc>;
 		};
 
-		L2: l2-cache@a02000 {
+		L2: cache-controller@a02000 {
 			compatible = "arm,pl310-cache";
 			reg = <0x00a02000 0x1000>;
 			interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
@@ -202,7 +209,7 @@
 			power-domains = <&pd_pu>;
 		};
 
-		dma_apbh: dma-apbh@1804000 {
+		dma_apbh: dma-controller@1804000 {
 			compatible = "fsl,imx6sx-dma-apbh", "fsl,imx28-dma-apbh";
 			reg = <0x01804000 0x2000>;
 			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
@@ -215,7 +222,7 @@
 			clocks = <&clks IMX6SX_CLK_APBH_DMA>;
 		};
 
-		gpmi: gpmi-nand@1806000{
+		gpmi: nand-controller@1806000{
 			compatible = "fsl,imx6sx-gpmi-nand";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -235,7 +242,7 @@
 			status = "disabled";
 		};
 
-		aips1: aips-bus@2000000 {
+		aips1: bus@2000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -333,6 +340,7 @@
 				};
 
 				esai: esai@2024000 {
+					compatible = "fsl,imx6sx-esai", "fsl,imx35-esai";
 					reg = <0x02024000 0x4000>;
 					interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
 					clocks = <&clks IMX6SX_CLK_ESAI_IPG>,
@@ -342,6 +350,9 @@
 						 <&clks IMX6SX_CLK_SPBA>;
 					clock-names = "core", "mem", "extal",
 						      "fsys", "spba";
+					dmas = <&sdma 23 21 0>,
+					       <&sdma 24 21 0>;
+					dma-names = "rx", "tx";
 					status = "disabled";
 				};
 
@@ -388,18 +399,28 @@
 				};
 
 				asrc: asrc@2034000 {
+					compatible = "fsl,imx6sx-asrc", "fsl,imx53-asrc";
 					reg = <0x02034000 0x4000>;
 					interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
-					clocks = <&clks IMX6SX_CLK_ASRC_MEM>,
-						 <&clks IMX6SX_CLK_ASRC_IPG>,
-						 <&clks IMX6SX_CLK_SPDIF>,
-						 <&clks IMX6SX_CLK_SPBA>;
-					clock-names = "mem", "ipg", "asrck", "spba";
-					dmas = <&sdma 17 20 1>, <&sdma 18 20 1>,
-					       <&sdma 19 20 1>, <&sdma 20 20 1>,
-					       <&sdma 21 20 1>, <&sdma 22 20 1>;
+					clocks = <&clks IMX6SX_CLK_ASRC_IPG>,
+						<&clks IMX6SX_CLK_ASRC_MEM>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks IMX6SX_CLK_SPDIF>, <&clks 0>, <&clks 0>,
+						<&clks IMX6SX_CLK_SPBA>;
+					clock-names = "mem", "ipg", "asrck_0",
+						"asrck_1", "asrck_2", "asrck_3", "asrck_4",
+						"asrck_5", "asrck_6", "asrck_7", "asrck_8",
+						"asrck_9", "asrck_a", "asrck_b", "asrck_c",
+						"asrck_d", "asrck_e", "asrck_f", "spba";
+					dmas = <&sdma 17 23 1>, <&sdma 18 23 1>,
+					       <&sdma 19 23 1>, <&sdma 20 23 1>,
+					       <&sdma 21 23 1>, <&sdma 22 23 1>;
 					dma-names = "rxa", "rxb", "rxc",
 						    "txa", "txb", "txc";
+					fsl,asrc-rate  = <48000>;
+					fsl,asrc-width = <16>;
 					status = "okay";
 				};
 			};
@@ -411,7 +432,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM1>,
 					 <&clks IMX6SX_CLK_PWM1>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm2: pwm@2084000 {
@@ -421,7 +442,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM2>,
 					 <&clks IMX6SX_CLK_PWM2>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm3: pwm@2088000 {
@@ -431,7 +452,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM3>,
 					 <&clks IMX6SX_CLK_PWM3>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm4: pwm@208c000 {
@@ -441,7 +462,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM4>,
 					 <&clks IMX6SX_CLK_PWM4>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			flexcan1: can@2090000 {
@@ -451,7 +472,7 @@
 				clocks = <&clks IMX6SX_CLK_CAN1_IPG>,
 					 <&clks IMX6SX_CLK_CAN1_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 1 0x10 17>;
+				fsl,stop-mode = <&gpr 0x10 1>;
 				status = "disabled";
 			};
 
@@ -462,11 +483,11 @@
 				clocks = <&clks IMX6SX_CLK_CAN2_IPG>,
 					 <&clks IMX6SX_CLK_CAN2_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 2 0x10 18>;
+				fsl,stop-mode = <&gpr 0x10 2>;
 				status = "disabled";
 			};
 
-			gpt: gpt@2098000 {
+			gpt: timer@2098000 {
 				compatible = "fsl,imx6sx-gpt", "fsl,imx6dl-gpt";
 				reg = <0x02098000 0x4000>;
 				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
@@ -559,7 +580,7 @@
 				gpio-ranges = <&iomuxc 0 148 10>, <&iomuxc 10 169 2>;
 			};
 
-			kpp: kpp@20b8000 {
+			kpp: keypad@20b8000 {
 				compatible = "fsl,imx6sx-kpp", "fsl,imx21-kpp";
 				reg = <0x020b8000 0x4000>;
 				interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
@@ -567,14 +588,14 @@
 				status = "disabled";
 			};
 
-			wdog1: wdog@20bc000 {
+			wdog1: watchdog@20bc000 {
 				compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt";
 				reg = <0x020bc000 0x4000>;
 				interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SX_CLK_IPG>;
 			};
 
-			wdog2: wdog@20c0000 {
+			wdog2: watchdog@20c0000 {
 				compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt";
 				reg = <0x020c0000 0x4000>;
 				interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
@@ -582,7 +603,7 @@
 				status = "disabled";
 			};
 
-			clks: ccm@20c4000 {
+			clks: clock-controller@20c4000 {
 				compatible = "fsl,imx6sx-ccm";
 				reg = <0x020c4000 0x4000>;
 				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
@@ -594,7 +615,7 @@
 
 			anatop: anatop@20c8000 {
 				compatible = "fsl,imx6sx-anatop", "fsl,imx6q-anatop",
-					     "syscon", "simple-bus";
+					     "syscon", "simple-mfd";
 				reg = <0x020c8000 0x1000>;
 				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -694,6 +715,16 @@
 					anatop-min-voltage = <725000>;
 					anatop-max-voltage = <1450000>;
 				};
+
+				tempmon: tempmon {
+					compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon";
+					interrupt-parent = <&gpc>;
+					interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
+				};
 			};
 
 			usbphy1: usbphy@20c9000 {
@@ -752,7 +783,7 @@
 				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			src: src@20d8000 {
+			src: reset-controller@20d8000 {
 				compatible = "fsl,imx6sx-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -806,7 +837,7 @@
 				};
 			};
 
-			iomuxc: iomuxc@20e0000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6sx-iomuxc";
 				reg = <0x020e0000 0x4000>;
 			};
@@ -830,14 +861,14 @@
 			};
 		};
 
-		aips2: aips-bus@2100000 {
+		aips2: bus@2100000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			reg = <0x02100000 0x100000>;
 			ranges;
 
-			crypto: caam@2100000 {
+			crypto: crypto@2100000 {
 				compatible = "fsl,sec-v4.0";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -850,13 +881,13 @@
 					 <&clks IMX6SX_CLK_EIM_SLOW>;
 				clock-names = "mem", "aclk", "ipg", "emi_slow";
 
-				sec_jr0: jr0@1000 {
+				sec_jr0: jr@1000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x1000 0x1000>;
 					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr1: jr1@2000 {
+				sec_jr1: jr@2000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x2000 0x1000>;
 					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
@@ -928,6 +959,7 @@
 					      "enet_clk_ref", "enet_out";
 				fsl,num-tx-queues = <3>;
 				fsl,num-rx-queues = <3>;
+				fsl,stop-mode = <&gpr 0x10 3>;
 				status = "disabled";
 			};
 
@@ -940,7 +972,7 @@
 				status = "disabled";
 			};
 
-			usdhc1: usdhc@2190000 {
+			usdhc1: mmc@2190000 {
 				compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
@@ -949,10 +981,12 @@
 					 <&clks IMX6SX_CLK_USDHC1>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
 				status = "disabled";
 			};
 
-			usdhc2: usdhc@2194000 {
+			usdhc2: mmc@2194000 {
 				compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
@@ -961,10 +995,12 @@
 					 <&clks IMX6SX_CLK_USDHC2>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
 				status = "disabled";
 			};
 
-			usdhc3: usdhc@2198000 {
+			usdhc3: mmc@2198000 {
 				compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x02198000 0x4000>;
 				interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
@@ -973,10 +1009,12 @@
 					 <&clks IMX6SX_CLK_USDHC3>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
 				status = "disabled";
 			};
 
-			usdhc4: usdhc@219c000 {
+			usdhc4: mmc@219c000 {
 				compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x0219c000 0x4000>;
 				interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
@@ -1037,6 +1075,7 @@
 					 <&clks IMX6SX_CLK_ENET_PTP>;
 				clock-names = "ipg", "ahb", "ptp",
 					      "enet_clk_ref", "enet_out";
+				fsl,stop-mode = <&gpr 0x10 4>;
 				status = "disabled";
 			};
 
@@ -1051,13 +1090,17 @@
 				status = "disabled";
 			};
 
-			ocotp: ocotp@21bc000 {
+			ocotp: efuse@21bc000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				compatible = "fsl,imx6sx-ocotp", "syscon";
 				reg = <0x021bc000 0x4000>;
 				clocks = <&clks IMX6SX_CLK_OCOTP>;
 
+				cpu_speed_grade: speed-grade@10 {
+					reg = <0x10 4>;
+				};
+
 				tempmon_calib: calib@38 {
 					reg = <0x38 4>;
 				};
@@ -1188,7 +1231,7 @@
 			};
 		};
 
-		aips3: aips-bus@2200000 {
+		aips3: bus@2200000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -1289,7 +1332,7 @@
 				status = "disabled";
 			};
 
-			wdog3: wdog@2288000 {
+			wdog3: watchdog@2288000 {
 				compatible = "fsl,imx6sx-wdt", "fsl,imx21-wdt";
 				reg = <0x02288000 0x4000>;
 				interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
@@ -1329,7 +1372,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM5>,
 					 <&clks IMX6SX_CLK_PWM5>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm6: pwm@22a8000 {
@@ -1339,7 +1382,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM6>,
 					 <&clks IMX6SX_CLK_PWM6>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm7: pwm@22ac000 {
@@ -1349,7 +1392,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM7>,
 					 <&clks IMX6SX_CLK_PWM7>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 
 			pwm8: pwm@22b0000 {
@@ -1359,7 +1402,7 @@
 				clocks = <&clks IMX6SX_CLK_PWM8>,
 					 <&clks IMX6SX_CLK_PWM8>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
@@ -202,6 +202,7 @@
 };
 
 &pwm1 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm1>;
 	status = "okay";
@@ -215,7 +216,7 @@
 	flash0: n25q256a@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "micron,n25q256a";
+		compatible = "micron,n25q256a", "jedec,spi-nor";
 		spi-max-frequency = <29000000>;
 		spi-rx-bus-width = <4>;
 		spi-tx-bus-width = <4>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -168,6 +168,7 @@
 };
 
 &pwm5 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm5>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-geam.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-geam.dts
@@ -195,6 +195,7 @@
 };
 
 &pwm8 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm8>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-isiot.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-isiot.dtsi
@@ -187,6 +187,7 @@
 };
 
 &pwm8 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm8>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-kontron-n6310-s-43.dts
@@ -41,6 +41,7 @@
 };
 
 &pwm7 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm7>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-kontron-n6310-s.dts
@@ -157,10 +157,6 @@
 	status = "okay";
 };
 
-&snvs_poweroff {
-	status = "okay";
-};
-
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-pico.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-pico.dtsi
@@ -184,6 +184,7 @@
 };
 
 &pwm3 {
+	#pwm-cells = <2>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm3>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul-tx6ul.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul-tx6ul.dtsi
@@ -549,7 +549,6 @@
 &pwm5 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm5>;
-	#pwm-cells = <3>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ul.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ul.dtsi
@@ -47,6 +47,8 @@
 		spi1 = &ecspi2;
 		spi2 = &ecspi3;
 		spi3 = &ecspi4;
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
 	};
@@ -62,20 +64,18 @@
 			clock-frequency = <696000000>;
 			clock-latency = <61036>; /* two CLK32 periods */
 			#cooling-cells = <2>;
-			operating-points = <
+			operating-points =
 				/* kHz	uV */
-				696000	1275000
-				528000	1175000
-				396000	1025000
-				198000	950000
-			>;
-			fsl,soc-operating-points = <
+				<696000	1275000>,
+				<528000	1175000>,
+				<396000	1025000>,
+				<198000	950000>;
+			fsl,soc-operating-points =
 				/* KHz	uV */
-				696000	1275000
-				528000	1175000
-				396000	1175000
-				198000	1175000
-			>;
+				<696000	1275000>,
+				<528000	1175000>,
+				<396000	1175000>,
+				<198000	1175000>;
 			clocks = <&clks IMX6UL_CLK_ARM>,
 				 <&clks IMX6UL_CLK_PLL2_BUS>,
 				 <&clks IMX6UL_CLK_PLL2_PFD2>,
@@ -131,16 +131,6 @@
 		clock-output-names = "ipp_di1";
 	};
 
-	tempmon: tempmon {
-		compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon";
-		interrupt-parent = <&gpc>;
-		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
-		fsl,tempmon = <&anatop>;
-		nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
-		nvmem-cell-names = "calib", "temp_grade";
-		clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>;
-	};
-
 	pmu {
 		compatible = "arm,cortex-a7-pmu";
 		interrupt-parent = <&gpc>;
@@ -157,6 +147,9 @@
 		ocram: sram@900000 {
 			compatible = "mmio-sram";
 			reg = <0x00900000 0x20000>;
+			ranges = <0 0x00900000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
 		};
 
 		intc: interrupt-controller@a01000 {
@@ -171,7 +164,7 @@
 			      <0x00a06000 0x2000>;
 		};
 
-		dma_apbh: dma-apbh@1804000 {
+		dma_apbh: dma-controller@1804000 {
 			compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh";
 			reg = <0x01804000 0x2000>;
 			interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>,
@@ -184,7 +177,7 @@
 			clocks = <&clks IMX6UL_CLK_APBHDMA>;
 		};
 
-		gpmi: gpmi-nand@1806000 {
+		gpmi: nand-controller@1806000 {
 			compatible = "fsl,imx6q-gpmi-nand";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -204,7 +197,7 @@
 			status = "disabled";
 		};
 
-		aips1: aips-bus@2000000 {
+		aips1: bus@2000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -351,6 +344,31 @@
 					dma-names = "rx", "tx";
 					status = "disabled";
 				};
+
+				asrc: asrc@2034000 {
+					compatible = "fsl,imx6ul-asrc", "fsl,imx53-asrc";
+					reg = <0x2034000 0x4000>;
+					interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clks IMX6UL_CLK_ASRC_IPG>,
+						<&clks IMX6UL_CLK_ASRC_MEM>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+						<&clks IMX6UL_CLK_SPDIF>, <&clks 0>, <&clks 0>,
+						<&clks IMX6UL_CLK_SPBA>;
+					clock-names = "mem", "ipg", "asrck_0",
+						"asrck_1", "asrck_2", "asrck_3", "asrck_4",
+						"asrck_5", "asrck_6", "asrck_7", "asrck_8",
+						"asrck_9", "asrck_a", "asrck_b", "asrck_c",
+						"asrck_d", "asrck_e", "asrck_f", "spba";
+					dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
+						<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
+					dma-names = "rxa", "rxb", "rxc",
+						    "txa", "txb", "txc";
+					fsl,asrc-rate  = <48000>;
+					fsl,asrc-width = <16>;
+					status = "okay";
+				};
 			};
 
 			tsc: tsc@2040000 {
@@ -371,7 +389,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM1>,
 					 <&clks IMX6UL_CLK_PWM1>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -382,7 +400,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM2>,
 					 <&clks IMX6UL_CLK_PWM2>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -393,7 +411,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM3>,
 					 <&clks IMX6UL_CLK_PWM3>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -404,7 +422,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM4>,
 					 <&clks IMX6UL_CLK_PWM4>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -415,7 +433,7 @@
 				clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
 					 <&clks IMX6UL_CLK_CAN1_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 1 0x10 17>;
+				fsl,stop-mode = <&gpr 0x10 1>;
 				status = "disabled";
 			};
 
@@ -426,11 +444,11 @@
 				clocks = <&clks IMX6UL_CLK_CAN2_IPG>,
 					 <&clks IMX6UL_CLK_CAN2_SERIAL>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 2 0x10 18>;
+				fsl,stop-mode = <&gpr 0x10 2>;
 				status = "disabled";
 			};
 
-			gpt1: gpt@2098000 {
+			gpt1: timer@2098000 {
 				compatible = "fsl,imx6ul-gpt", "fsl,imx6sx-gpt";
 				reg = <0x02098000 0x4000>;
 				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
@@ -520,10 +538,11 @@
 					      "enet_clk_ref", "enet_out";
 				fsl,num-tx-queues = <1>;
 				fsl,num-rx-queues = <1>;
+				fsl,stop-mode = <&gpr 0x10 4>;
 				status = "disabled";
 			};
 
-			kpp: kpp@20b8000 {
+			kpp: keypad@20b8000 {
 				compatible = "fsl,imx6ul-kpp", "fsl,imx6q-kpp", "fsl,imx21-kpp";
 				reg = <0x020b8000 0x4000>;
 				interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
@@ -531,14 +550,14 @@
 				status = "disabled";
 			};
 
-			wdog1: wdog@20bc000 {
+			wdog1: watchdog@20bc000 {
 				compatible = "fsl,imx6ul-wdt", "fsl,imx21-wdt";
 				reg = <0x020bc000 0x4000>;
 				interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6UL_CLK_WDOG1>;
 			};
 
-			wdog2: wdog@20c0000 {
+			wdog2: watchdog@20c0000 {
 				compatible = "fsl,imx6ul-wdt", "fsl,imx21-wdt";
 				reg = <0x020c0000 0x4000>;
 				interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
@@ -546,7 +565,7 @@
 				status = "disabled";
 			};
 
-			clks: ccm@20c4000 {
+			clks: clock-controller@20c4000 {
 				compatible = "fsl,imx6ul-ccm";
 				reg = <0x020c4000 0x4000>;
 				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
@@ -558,7 +577,7 @@
 
 			anatop: anatop@20c8000 {
 				compatible = "fsl,imx6ul-anatop", "fsl,imx6q-anatop",
-					     "syscon", "simple-bus";
+					     "syscon", "simple-mfd";
 				reg = <0x020c8000 0x1000>;
 				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -611,6 +630,16 @@
 					anatop-min-voltage = <725000>;
 					anatop-max-voltage = <1450000>;
 				};
+
+				tempmon: tempmon {
+					compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon";
+					interrupt-parent = <&gpc>;
+					interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>;
+				};
 			};
 
 			usbphy1: usbphy@20c9000 {
@@ -676,7 +705,7 @@
 				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			src: src@20d8000 {
+			src: reset-controller@20d8000 {
 				compatible = "fsl,imx6ul-src", "fsl,imx51-src";
 				reg = <0x020d8000 0x4000>;
 				interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -693,7 +722,7 @@
 				interrupt-parent = <&intc>;
 			};
 
-			iomuxc: iomuxc@20e0000 {
+			iomuxc: pinctrl@20e0000 {
 				compatible = "fsl,imx6ul-iomuxc";
 				reg = <0x020e0000 0x4000>;
 			};
@@ -704,7 +733,7 @@
 				reg = <0x020e4000 0x4000>;
 			};
 
-			gpt2: gpt@20e8000 {
+			gpt2: timer@20e8000 {
 				compatible = "fsl,imx6ul-gpt", "fsl,imx6sx-gpt";
 				reg = <0x020e8000 0x4000>;
 				interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
@@ -732,7 +761,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM5>,
 					 <&clks IMX6UL_CLK_PWM5>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -743,7 +772,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM6>,
 					 <&clks IMX6UL_CLK_PWM6>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -754,7 +783,7 @@
 				clocks = <&clks IMX6UL_CLK_PWM7>,
 					 <&clks IMX6UL_CLK_PWM7>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 
@@ -765,19 +794,19 @@
 				clocks = <&clks IMX6UL_CLK_PWM8>,
 					 <&clks IMX6UL_CLK_PWM8>;
 				clock-names = "ipg", "per";
-				#pwm-cells = <2>;
+				#pwm-cells = <3>;
 				status = "disabled";
 			};
 		};
 
-		aips2: aips-bus@2100000 {
+		aips2: bus@2100000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			reg = <0x02100000 0x100000>;
 			ranges;
 
-			crypto: caam@2140000 {
+			crypto: crypto@2140000 {
 				compatible = "fsl,imx6ul-caam", "fsl,sec-v4.0";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -788,19 +817,19 @@
 					 <&clks IMX6UL_CLK_CAAM_MEM>;
 				clock-names = "ipg", "aclk", "mem";
 
-				sec_jr0: jr0@1000 {
+				sec_jr0: jr@1000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x1000 0x1000>;
 					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr1: jr1@2000 {
+				sec_jr1: jr@2000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x2000 0x1000>;
 					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr2: jr2@3000 {
+				sec_jr2: jr@3000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x3000 0x1000>;
 					interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
@@ -855,10 +884,11 @@
 					      "enet_clk_ref", "enet_out";
 				fsl,num-tx-queues = <1>;
 				fsl,num-rx-queues = <1>;
+				fsl,stop-mode = <&gpr 0x10 3>;
 				status = "disabled";
 			};
 
-			usdhc1: usdhc@2190000 {
+			usdhc1: mmc@2190000 {
 				compatible = "fsl,imx6ul-usdhc", "fsl,imx6sx-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
@@ -872,7 +902,7 @@
 				status = "disabled";
 			};
 
-			usdhc2: usdhc@2194000 {
+			usdhc2: mmc@2194000 {
 				compatible = "fsl,imx6ul-usdhc", "fsl,imx6sx-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
@@ -945,7 +975,7 @@
 				status = "disabled";
 			};
 
-			ocotp: ocotp-ctrl@21bc000 {
+			ocotp: efuse@21bc000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				compatible = "fsl,imx6ul-ocotp", "syscon";
@@ -966,7 +996,7 @@
 			};
 
 			csi: csi@21c4000 {
-				compatible = "fsl,imx6ul-csi", "fsl,imx7-csi";
+				compatible = "fsl,imx6ul-csi";
 				reg = <0x021c4000 0x4000>;
 				interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6UL_CLK_CSI>;
@@ -975,7 +1005,7 @@
 			};
 
 			lcdif: lcdif@21c8000 {
-				compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
+				compatible = "fsl,imx6ul-lcdif", "fsl,imx6sx-lcdif";
 				reg = <0x021c8000 0x4000>;
 				interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
@@ -996,7 +1026,7 @@
 			qspi: spi@21e0000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
-				compatible = "fsl,imx6ul-qspi", "fsl,imx6sx-qspi";
+				compatible = "fsl,imx6ul-qspi";
 				reg = <0x021e0000 0x4000>, <0x60000000 0x10000000>;
 				reg-names = "QuadSPI", "QuadSPI-memory";
 				interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
@@ -1006,7 +1036,7 @@
 				status = "disabled";
 			};
 
-			wdog3: wdog@21e4000 {
+			wdog3: watchdog@21e4000 {
 				compatible = "fsl,imx6ul-wdt", "fsl,imx21-wdt";
 				reg = <0x021e4000 0x4000>;
 				interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
@@ -43,6 +43,7 @@
 	assigned-clock-rates = <0>, <198000000>;
 	cap-power-off-card;
 	keep-power-in-suspend;
+	max-frequency = <25000000>;
 	mmc-pwrseq = <&wifi_pwrseq>;
 	no-1-8-v;
 	non-removable;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ull-colibri.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ull-colibri.dtsi
@@ -37,7 +37,7 @@
 
 	reg_sd1_vmmc: regulator-sd1-vmmc {
 		compatible = "regulator-gpio";
-		gpio = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+		gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_snvs_reg_sd>;
 		regulator-always-on;
@@ -132,25 +132,21 @@
 &pwm4 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm4>;
-	#pwm-cells = <3>;
 };
 
 &pwm5 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm5>;
-	#pwm-cells = <3>;
 };
 
 &pwm6 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm6>;
-	#pwm-cells = <3>;
 };
 
 &pwm7 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm7>;
-	#pwm-cells = <3>;
 };
 
 &sdma {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ull-pinfunc.h
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ull-pinfunc.h
@@ -82,6 +82,6 @@
 #define MX6ULL_PAD_CSI_DATA04__ESAI_TX_FS                         0x01F4 0x0480 0x0000 0x9 0x0
 #define MX6ULL_PAD_CSI_DATA05__ESAI_TX_CLK                        0x01F8 0x0484 0x0000 0x9 0x0
 #define MX6ULL_PAD_CSI_DATA06__ESAI_TX5_RX0                       0x01FC 0x0488 0x0000 0x9 0x0
-#define MX6ULL_PAD_CSI_DATA07__ESAI_T0                            0x0200 0x048C 0x0000 0x9 0x0
+#define MX6ULL_PAD_CSI_DATA07__ESAI_TX0                           0x0200 0x048C 0x0000 0x9 0x0
 
 #endif /* __DTS_IMX6ULL_PINFUNC_H */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx6ull.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx6ull.dtsi
@@ -51,7 +51,7 @@
 
 / {
 	soc {
-		aips3: aips-bus@2200000 {
+		aips3: bus@2200000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7-colibri.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -77,7 +77,7 @@
 
 		dailink_master: simple-audio-card,codec {
 			sound-dai = <&codec>;
-			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		};
 	};
 };
@@ -152,7 +152,7 @@
 		compatible = "fsl,sgtl5000";
 		#sound-dai-cells = <0>;
 		reg = <0x0a>;
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_sai1_mclk>;
 		VDDA-supply = <&reg_module_3v3_avdd>;
@@ -337,7 +337,6 @@
 	assigned-clock-rates = <400000000>;
 	bus-width = <8>;
 	fsl,tuning-step = <2>;
-	max-frequency = <100000000>;
 	vmmc-supply = <&reg_module_3v3>;
 	vqmmc-supply = <&reg_DCDC3>;
 	non-removable;
@@ -347,7 +346,7 @@
 &iomuxc {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4
-		     &pinctrl_gpio7>;
+		     &pinctrl_gpio7 &pinctrl_usbc_det>;
 
 	pinctrl_gpio1: gpio1-grp {
 		fsl,pins = <
@@ -452,7 +451,6 @@
 
 	pinctrl_enet1: enet1grp {
 		fsl,pins = <
-			MX7D_PAD_ENET1_CRS__GPIO7_IO14			0x14
 			MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL	0x73
 			MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0	0x73
 			MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1	0x73
@@ -650,6 +648,12 @@
 		>;
 	};
 
+	pinctrl_usbc_det: gpio-usbc-det {
+		fsl,pins = <
+			MX7D_PAD_ENET1_CRS__GPIO7_IO14	0x14
+		>;
+	};
+
 	pinctrl_usbh_reg: gpio-usbh-vbus {
 		fsl,pins = <
 			MX7D_PAD_UART3_CTS_B__GPIO4_IO7	0x14 /* SODIMM 129 USBH PEN */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7-mba7.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7-mba7.dtsi
@@ -250,7 +250,7 @@
 	tlv320aic32x4: audio-codec@18 {
 		compatible = "ti,tlv320aic32x4";
 		reg = <0x18>;
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		clock-names = "mclk";
 		ldoin-supply = <&reg_audio_3v3>;
 		iov-supply = <&reg_audio_3v3>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-meerkat96.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-meerkat96.dts
@@ -193,7 +193,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	keep-power-in-suspend;
-	tuning-step = <2>;
+	fsl,tuning-step = <2>;
 	vmmc-supply = <&reg_3p3v>;
 	no-1-8-v;
 	broken-cd;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-nitrogen7.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-nitrogen7.dts
@@ -284,7 +284,7 @@
 	codec: wm8960@1a {
 		compatible = "wlf,wm8960";
 		reg = <0x1a>;
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		clock-names = "mclk";
 		wlf,shared-lrclk;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-pico-hobbit.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-pico-hobbit.dts
@@ -31,7 +31,7 @@
 
 		dailink_master: simple-audio-card,codec {
 			sound-dai = <&sgtl5000>;
-			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		};
 	};
 };
@@ -41,7 +41,7 @@
 		#sound-dai-cells = <0>;
 		reg = <0x0a>;
 		compatible = "fsl,sgtl5000";
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_vref_1v8>;
 	};
@@ -64,7 +64,7 @@
 		interrupt-parent = <&gpio2>;
 		interrupts = <7 0>;
 		spi-max-frequency = <1000000>;
-		pendown-gpio = <&gpio2 7 0>;
+		pendown-gpio = <&gpio2 7 GPIO_ACTIVE_LOW>;
 		vcc-supply = <&reg_3p3v>;
 		ti,x-min = /bits/ 16 <0>;
 		ti,x-max = /bits/ 16 <4095>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-pico-pi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-pico-pi.dts
@@ -31,7 +31,7 @@
 
 		dailink_master: simple-audio-card,codec {
 			sound-dai = <&sgtl5000>;
-			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		};
 	};
 };
@@ -41,7 +41,7 @@
 		#sound-dai-cells = <0>;
 		reg = <0x0a>;
 		compatible = "fsl,sgtl5000";
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_vref_1v8>;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-pico.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-pico.dtsi
@@ -307,7 +307,7 @@
 	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
 	cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
 	bus-width = <4>;
-	tuning-step = <2>;
+	fsl,tuning-step = <2>;
 	vmmc-supply = <&reg_3p3v>;
 	wakeup-source;
 	no-1-8-v;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d-sdb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d-sdb.dts
@@ -19,6 +19,11 @@
 		reg = <0x80000000 0x80000000>;
 	};
 
+	m4_tcm: tcml@007f8000 {
+		compatible = "fsl, m4_tcml";
+		reg = <0x007f8000 0x8000>;
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		pinctrl-names = "default";
@@ -176,13 +181,8 @@
 		pinctrl-0 = <&pinctrl_tsc2046_pendown>;
 		interrupt-parent = <&gpio2>;
 		interrupts = <29 0>;
-		pendown-gpio = <&gpio2 29 GPIO_ACTIVE_HIGH>;
-		ti,x-min = /bits/ 16 <0>;
-		ti,x-max = /bits/ 16 <0>;
-		ti,y-min = /bits/ 16 <0>;
-		ti,y-max = /bits/ 16 <0>;
-		ti,pressure-max = /bits/ 16 <0>;
-		ti,x-plate-ohms = /bits/ 16 <400>;
+		pendown-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>;
+		touchscreen-max-pressure = <255>;
 		wakeup-source;
 	};
 };
@@ -356,7 +356,7 @@
 	codec: wm8960@1a {
 		compatible = "wlf,wm8960";
 		reg = <0x1a>;
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		clock-names = "mclk";
 		wlf,shared-lrclk;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7d.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7d.dtsi
@@ -7,12 +7,18 @@
 #include <dt-bindings/reset/imx7-reset.h>
 
 / {
+	aliases {
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
+		usb2 = &usbh;
+	};
+
 	cpus {
 		cpu0: cpu@0 {
 			clock-frequency = <996000000>;
 			operating-points-v2 = <&cpu0_opp_table>;
 			#cooling-cells = <2>;
-			nvmem-cells = <&cpu_speed_grade>;
+			nvmem-cells = <&fuse_grade>;
 			nvmem-cell-names = "speed_grade";
 		};
 
@@ -28,6 +34,7 @@
 
 	timer {
 		compatible = "arm,armv7-timer";
+		arm,cpu-registers-not-fw-configured;
 		interrupt-parent = <&intc>;
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
@@ -69,6 +76,13 @@
 	};
 
 	soc {
+		ocrams: sram@00180000 {
+			compatible = "fsl,lpm-sram";
+			reg = <0x00180000 0x8000>;
+			clocks = <&clks IMX7D_OCRAM_S_CLK>;
+			status = "disabled";
+		};
+
 		etm@3007d000 {
 			compatible = "arm,coresight-etm3x", "arm,primecell";
 			reg = <0x3007d000 0x1000>;
@@ -149,6 +163,7 @@
 			"enet_clk_ref", "enet_out";
 		fsl,num-tx-queues = <3>;
 		fsl,num-rx-queues = <3>;
+		fsl,stop-mode = <&gpr 0x10 4>;
 		status = "disabled";
 	};
 
@@ -198,9 +213,6 @@
 };
 
 &ca_funnel_in_ports {
-	#address-cells = <1>;
-	#size-cells = <0>;
-
 	port@1 {
 		reg = <1>;
 		ca_funnel_in_port1: endpoint {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7s-colibri.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7s-colibri.dtsi
@@ -49,3 +49,7 @@
 		reg = <0x80000000 0x10000000>;
 	};
 };
+
+&gpmi {
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7s-warp.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7s-warp.dts
@@ -75,7 +75,7 @@
 
 		dailink_master: simple-audio-card,codec {
 			sound-dai = <&codec>;
-			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		};
 	};
 };
@@ -232,7 +232,7 @@
 		#sound-dai-cells = <0>;
 		reg = <0x0a>;
 		compatible = "fsl,sgtl5000";
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_sai1_mclk>;
 		VDDA-supply = <&vgen4_reg>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7s.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7s.dtsi
@@ -47,6 +47,8 @@
 		spi1 = &ecspi2;
 		spi2 = &ecspi3;
 		spi3 = &ecspi4;
+		usb0 = &usbotg1;
+		usb1 = &usbh;
 	};
 
 	cpus {
@@ -147,17 +149,6 @@
 		};
 	};
 
-	tempmon: tempmon {
-		compatible = "fsl,imx7d-tempmon";
-		interrupt-parent = <&gpc>;
-		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
-		fsl,tempmon = <&anatop>;
-		nvmem-cells = <&tempmon_calib>,
-			<&tempmon_temp_grade>;
-		nvmem-cell-names = "calib", "temp_grade";
-		clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>;
-	};
-
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupt-parent = <&intc>;
@@ -181,7 +172,11 @@
 			clock-names = "apb_pclk";
 
 			ca_funnel_in_ports: in-ports {
-				port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
 					ca_funnel_in_port0: endpoint {
 						remote-endpoint = <&etm0_out_port>;
 					};
@@ -316,7 +311,7 @@
 			      <0x31006000 0x2000>;
 		};
 
-		aips1: aips-bus@30000000 {
+		aips1: bus@30000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -407,14 +402,14 @@
 				gpio-ranges = <&iomuxc 0 139 16>;
 			};
 
-			wdog1: wdog@30280000 {
+			wdog1: watchdog@30280000 {
 				compatible = "fsl,imx7d-wdt", "fsl,imx21-wdt";
 				reg = <0x30280000 0x10000>;
 				interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_WDOG1_ROOT_CLK>;
 			};
 
-			wdog2: wdog@30290000 {
+			wdog2: watchdog@30290000 {
 				compatible = "fsl,imx7d-wdt", "fsl,imx21-wdt";
 				reg = <0x30290000 0x10000>;
 				interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
@@ -422,7 +417,7 @@
 				status = "disabled";
 			};
 
-			wdog3: wdog@302a0000 {
+			wdog3: watchdog@302a0000 {
 				compatible = "fsl,imx7d-wdt", "fsl,imx21-wdt";
 				reg = <0x302a0000 0x10000>;
 				interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
@@ -430,7 +425,7 @@
 				status = "disabled";
 			};
 
-			wdog4: wdog@302b0000 {
+			wdog4: watchdog@302b0000 {
 				compatible = "fsl,imx7d-wdt", "fsl,imx21-wdt";
 				reg = <0x302b0000 0x10000>;
 				interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
@@ -444,8 +439,8 @@
 				fsl,input-sel = <&iomuxc>;
 			};
 
-			gpt1: gpt@302d0000 {
-				compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+			gpt1: timer@302d0000 {
+				compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt";
 				reg = <0x302d0000 0x10000>;
 				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_GPT1_ROOT_CLK>,
@@ -453,8 +448,8 @@
 				clock-names = "ipg", "per";
 			};
 
-			gpt2: gpt@302e0000 {
-				compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+			gpt2: timer@302e0000 {
+				compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt";
 				reg = <0x302e0000 0x10000>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_GPT2_ROOT_CLK>,
@@ -463,8 +458,8 @@
 				status = "disabled";
 			};
 
-			gpt3: gpt@302f0000 {
-				compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+			gpt3: timer@302f0000 {
+				compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt";
 				reg = <0x302f0000 0x10000>;
 				interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_GPT3_ROOT_CLK>,
@@ -473,8 +468,8 @@
 				status = "disabled";
 			};
 
-			gpt4: gpt@30300000 {
-				compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+			gpt4: timer@30300000 {
+				compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt";
 				reg = <0x30300000 0x10000>;
 				interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_GPT4_ROOT_CLK>,
@@ -483,7 +478,7 @@
 				status = "disabled";
 			};
 
-			kpp: kpp@30320000 {
+			kpp: keypad@30320000 {
 				compatible = "fsl,imx7d-kpp", "fsl,imx21-kpp";
 				reg = <0x30320000 0x10000>;
 				interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
@@ -491,7 +486,7 @@
 				status = "disabled";
 			};
 
-			iomuxc: iomuxc@30330000 {
+			iomuxc: pinctrl@30330000 {
 				compatible = "fsl,imx7d-iomuxc";
 				reg = <0x30330000 0x10000>;
 			};
@@ -504,7 +499,7 @@
 
 				mux: mux-controller {
 					compatible = "mmio-mux";
-					#mux-control-cells = <0>;
+					#mux-control-cells = <1>;
 					mux-reg-masks = <0x14 0x00000010>;
 				};
 
@@ -537,7 +532,7 @@
 				};
 			};
 
-			ocotp: ocotp-ctrl@30350000 {
+			ocotp: efuse@30350000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				compatible = "fsl,imx7d-ocotp", "syscon";
@@ -548,18 +543,14 @@
 					reg = <0x3c 0x4>;
 				};
 
-				tempmon_temp_grade: temp-grade@10 {
-					reg = <0x10 0x4>;
-				};
-
-				cpu_speed_grade: speed-grade@10 {
+				fuse_grade: fuse-grade@10 {
 					reg = <0x10 0x4>;
 				};
 			};
 
 			anatop: anatop@30360000 {
 				compatible = "fsl,imx7d-anatop", "fsl,imx6q-anatop",
-					"syscon", "simple-bus";
+					"syscon", "simple-mfd";
 				reg = <0x30360000 0x10000>;
 				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
 					<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
@@ -591,6 +582,16 @@
 					anatop-max-voltage = <1300000>;
 					anatop-enable-bit = <0>;
 				};
+
+				tempmon: tempmon {
+					compatible = "fsl,imx7d-tempmon";
+					interrupt-parent = <&gpc>;
+					interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+					fsl,tempmon = <&anatop>;
+					nvmem-cells = <&tempmon_calib>,	<&fuse_grade>;
+					nvmem-cell-names = "calib", "temp_grade";
+					clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>;
+				};
 			};
 
 			snvs: snvs@30370000 {
@@ -617,7 +618,7 @@
 				};
 			};
 
-			clks: ccm@30380000 {
+			clks: clock-controller@30380000 {
 				compatible = "fsl,imx7d-ccm";
 				reg = <0x30380000 0x10000>;
 				interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
@@ -627,8 +628,8 @@
 				clock-names = "ckil", "osc";
 			};
 
-			src: src@30390000 {
-				compatible = "fsl,imx7d-src", "syscon";
+			src: reset-controller@30390000 {
+				compatible = "fsl,imx7d-src", "fsl,imx51-src", "syscon";
 				reg = <0x30390000 0x10000>;
 				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 				#reset-cells = <1>;
@@ -662,7 +663,7 @@
 			};
 		};
 
-		aips2: aips-bus@30400000 {
+		aips2: bus@30400000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -763,7 +764,7 @@
 			};
 
 			lcdif: lcdif@30730000 {
-				compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif";
+				compatible = "fsl,imx7d-lcdif", "fsl,imx6sx-lcdif";
 				reg = <0x30730000 0x10000>;
 				interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>,
@@ -802,7 +803,7 @@
 			};
 		};
 
-		aips3: aips-bus@30800000 {
+		aips3: bus@30800000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -931,7 +932,7 @@
 				};
 			};
 
-			crypto: caam@30900000 {
+			crypto: crypto@30900000 {
 				compatible = "fsl,sec-v4.0";
 				#address-cells = <1>;
 				#size-cells = <1>;
@@ -942,19 +943,19 @@
 					 <&clks IMX7D_AHB_CHANNEL_ROOT_CLK>;
 				clock-names = "ipg", "aclk";
 
-				sec_jr0: jr0@1000 {
+				sec_jr0: jr@1000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x1000 0x1000>;
 					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr1: jr1@2000 {
+				sec_jr1: jr@2000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x2000 0x1000>;
 					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 				};
 
-				sec_jr2: jr1@3000 {
+				sec_jr2: jr@3000 {
 					compatible = "fsl,sec-v4.0-job-ring";
 					reg = <0x3000 0x1000>;
 					interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
@@ -968,7 +969,7 @@
 				clocks = <&clks IMX7D_CLK_DUMMY>,
 					<&clks IMX7D_CAN1_ROOT_CLK>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 1 0x10 17>;
+				fsl,stop-mode = <&gpr 0x10 1>;
 				status = "disabled";
 			};
 
@@ -979,7 +980,7 @@
 				clocks = <&clks IMX7D_CLK_DUMMY>,
 					<&clks IMX7D_CAN2_ROOT_CLK>;
 				clock-names = "ipg", "per";
-				fsl,stop-mode = <&gpr 0x10 2 0x10 18>;
+				fsl,stop-mode = <&gpr 0x10 2>;
 				status = "disabled";
 			};
 
@@ -1122,7 +1123,7 @@
 				reg = <0x30b30200 0x200>;
 			};
 
-			usdhc1: usdhc@30b40000 {
+			usdhc1: mmc@30b40000 {
 				compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x30b40000 0x10000>;
 				interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
@@ -1131,10 +1132,12 @@
 					<&clks IMX7D_USDHC1_ROOT_CLK>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-step = <2>;
+				fsl,tuning-start-tap = <20>;
 				status = "disabled";
 			};
 
-			usdhc2: usdhc@30b50000 {
+			usdhc2: mmc@30b50000 {
 				compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x30b50000 0x10000>;
 				interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
@@ -1143,10 +1146,12 @@
 					<&clks IMX7D_USDHC2_ROOT_CLK>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-step = <2>;
+				fsl,tuning-start-tap = <20>;
 				status = "disabled";
 			};
 
-			usdhc3: usdhc@30b60000 {
+			usdhc3: mmc@30b60000 {
 				compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
 				reg = <0x30b60000 0x10000>;
 				interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
@@ -1155,6 +1160,8 @@
 					<&clks IMX7D_USDHC3_ROOT_CLK>;
 				clock-names = "ipg", "ahb", "per";
 				bus-width = <4>;
+				fsl,tuning-step = <2>;
+				fsl,tuning-start-tap = <20>;
 				status = "disabled";
 			};
 
@@ -1186,27 +1193,27 @@
 					"enet_clk_ref", "enet_out";
 				fsl,num-tx-queues = <3>;
 				fsl,num-rx-queues = <3>;
+				fsl,stop-mode = <&gpr 0x10 3>;
 				status = "disabled";
 			};
 		};
 
-		dma_apbh: dma-apbh@33000000 {
+		dma_apbh: dma-controller@33000000 {
 			compatible = "fsl,imx7d-dma-apbh", "fsl,imx28-dma-apbh";
 			reg = <0x33000000 0x2000>;
 			interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3";
 			#dma-cells = <1>;
 			dma-channels = <4>;
 			clocks = <&clks IMX7D_NAND_USDHC_BUS_RAWNAND_CLK>;
 		};
 
-		gpmi: gpmi-nand@33002000{
+		gpmi: nand-controller@33002000{
 			compatible = "fsl,imx7d-gpmi-nand";
 			#address-cells = <1>;
-			#size-cells = <1>;
+			#size-cells = <0>;
 			reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
 			reg-names = "gpmi-nand", "bch";
 			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/imx7ulp.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/imx7ulp.dtsi
@@ -37,10 +37,10 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		cpu0: cpu@0 {
+		cpu0: cpu@f00 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
-			reg = <0>;
+			reg = <0xf00>;
 		};
 	};
 
@@ -139,13 +139,13 @@
 				 <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>;
 			clock-names = "aclk", "ipg";
 
-			sec_jr0: jr0@1000 {
+			sec_jr0: jr@1000 {
 				compatible = "fsl,sec-v4.0-job-ring";
 				reg = <0x1000 0x1000>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			sec_jr1: jr1@2000 {
+			sec_jr1: jr@2000 {
 				compatible = "fsl,sec-v4.0-job-ring";
 				reg = <0x2000 0x1000>;
 				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
@@ -397,7 +397,7 @@
 			clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
 				 <&pcc3 IMX7ULP_CLK_PCTLC>;
 			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc1 0 0 32>;
+			gpio-ranges = <&iomuxc1 0 0 20>;
 		};
 
 		gpio_ptd: gpio@40af0000 {
@@ -411,7 +411,7 @@
 			clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
 				 <&pcc3 IMX7ULP_CLK_PCTLD>;
 			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc1 0 32 32>;
+			gpio-ranges = <&iomuxc1 0 32 12>;
 		};
 
 		gpio_pte: gpio@40b00000 {
@@ -425,7 +425,7 @@
 			clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
 				 <&pcc3 IMX7ULP_CLK_PCTLE>;
 			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc1 0 64 32>;
+			gpio-ranges = <&iomuxc1 0 64 16>;
 		};
 
 		gpio_ptf: gpio@40b10000 {
@@ -439,7 +439,7 @@
 			clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
 				 <&pcc3 IMX7ULP_CLK_PCTLF>;
 			clock-names = "gpio", "port";
-			gpio-ranges = <&iomuxc1 0 96 32>;
+			gpio-ranges = <&iomuxc1 0 96 20>;
 		};
 	};
 
@@ -455,7 +455,7 @@
 			reg = <0x410a3000 0x1000>;
 		};
 
-		ocotp: ocotp-ctrl@410a6000 {
+		ocotp: efuse@410a6000 {
 			compatible = "fsl,imx7ulp-ocotp", "syscon";
 			reg = <0x410a6000 0x4000>;
 			clocks = <&scg1 IMX7ULP_CLK_DUMMY>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/integratorap.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/integratorap.dts
@@ -155,6 +155,7 @@
 
 	pci: pciv3@62000000 {
 		compatible = "arm,integrator-ap-pci", "v3,v360epc-pci";
+		device_type = "pci";
 		#interrupt-cells = <1>;
 		#size-cells = <2>;
 		#address-cells = <3>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/kirkwood-lsxl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/kirkwood-lsxl.dtsi
@@ -10,6 +10,11 @@
 
 	ocp@f1000000 {
 		pinctrl: pin-controller@10000 {
+			/* Non-default UART pins */
+			pmx_uart0: pmx-uart0 {
+				marvell,pins = "mpp4", "mpp5";
+			};
+
 			pmx_power_hdd: pmx-power-hdd {
 				marvell,pins = "mpp10";
 				marvell,function = "gpo";
@@ -213,22 +218,11 @@
 &mdio {
 	status = "okay";
 
-	ethphy0: ethernet-phy@0 {
-		reg = <0>;
-	};
-
 	ethphy1: ethernet-phy@8 {
 		reg = <8>;
 	};
 };
 
-&eth0 {
-	status = "okay";
-	ethernet0-port@0 {
-		phy-handle = <&ethphy0>;
-	};
-};
-
 &eth1 {
 	status = "okay";
 	ethernet1-port@0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-som-lv-35xx-devkit.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-som-lv-35xx-devkit.dts
@@ -11,3 +11,18 @@
 	model = "LogicPD Zoom OMAP35xx SOM-LV Development Kit";
 	compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3";
 };
+
+&omap3_pmx_core2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hsusb2_2_pins>;
+	hsusb2_2_pins: pinmux_hsusb2_2_pins {
+		pinctrl-single,pins = <
+			OMAP3430_CORE2_IOPAD(0x25f0, PIN_OUTPUT | MUX_MODE3)            /* etk_d10.hsusb2_clk */
+			OMAP3430_CORE2_IOPAD(0x25f2, PIN_OUTPUT | MUX_MODE3)            /* etk_d11.hsusb2_stp */
+			OMAP3430_CORE2_IOPAD(0x25f4, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d12.hsusb2_dir */
+			OMAP3430_CORE2_IOPAD(0x25f6, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d13.hsusb2_nxt */
+			OMAP3430_CORE2_IOPAD(0x25f8, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d14.hsusb2_data0 */
+			OMAP3430_CORE2_IOPAD(0x25fa, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d15.hsusb2_data1 */
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts
@@ -11,3 +11,18 @@
 	model = "LogicPD Zoom DM3730 SOM-LV Development Kit";
 	compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3630", "ti,omap3";
 };
+
+&omap3_pmx_core2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hsusb2_2_pins>;
+	hsusb2_2_pins: pinmux_hsusb2_2_pins {
+		pinctrl-single,pins = <
+			OMAP3630_CORE2_IOPAD(0x25f0, PIN_OUTPUT | MUX_MODE3)            /* etk_d10.hsusb2_clk */
+			OMAP3630_CORE2_IOPAD(0x25f2, PIN_OUTPUT | MUX_MODE3)            /* etk_d11.hsusb2_stp */
+			OMAP3630_CORE2_IOPAD(0x25f4, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d12.hsusb2_dir */
+			OMAP3630_CORE2_IOPAD(0x25f6, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d13.hsusb2_nxt */
+			OMAP3630_CORE2_IOPAD(0x25f8, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d14.hsusb2_data0 */
+			OMAP3630_CORE2_IOPAD(0x25fa, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d15.hsusb2_data1 */
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi
@@ -51,6 +51,8 @@
 
 &mcbsp2 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcbsp2_pins>;
 };
 
 &charger {
@@ -102,35 +104,18 @@
 		regulator-max-microvolt = <3300000>;
 	};
 
-	lcd0: display@0 {
-		compatible = "panel-dpi";
-		label = "28";
-		status = "okay";
-		/* default-on; */
+	lcd0: display {
+		/* This isn't the exact LCD, but the timings meet spec */
+		compatible = "logicpd,type28";
 		pinctrl-names = "default";
 		pinctrl-0 = <&lcd_enable_pin>;
-		enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;	/* gpio155, lcd INI */
+		backlight = <&bl>;
+		enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
 		port {
 			lcd_in: endpoint {
 				remote-endpoint = <&dpi_out>;
 			};
 		};
-
-		panel-timing {
-			clock-frequency = <9000000>;
-			hactive = <480>;
-			vactive = <272>;
-			hfront-porch = <3>;
-			hback-porch = <2>;
-			hsync-len = <42>;
-			vback-porch = <3>;
-			vfront-porch = <2>;
-			vsync-len = <11>;
-			hsync-active = <1>;
-			vsync-active = <1>;
-			de-active = <1>;
-			pixelclk-active = <0>;
-		};
 	};
 
 	bl: backlight {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-som-lv.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-som-lv.dtsi
@@ -265,21 +265,6 @@
 	};
 };
 
-&omap3_pmx_core2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&hsusb2_2_pins>;
-	hsusb2_2_pins: pinmux_hsusb2_2_pins {
-		pinctrl-single,pins = <
-			OMAP3630_CORE2_IOPAD(0x25f0, PIN_OUTPUT | MUX_MODE3)            /* etk_d10.hsusb2_clk */
-			OMAP3630_CORE2_IOPAD(0x25f2, PIN_OUTPUT | MUX_MODE3)            /* etk_d11.hsusb2_stp */
-			OMAP3630_CORE2_IOPAD(0x25f4, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d12.hsusb2_dir */
-			OMAP3630_CORE2_IOPAD(0x25f6, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d13.hsusb2_nxt */
-			OMAP3630_CORE2_IOPAD(0x25f8, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d14.hsusb2_data0 */
-			OMAP3630_CORE2_IOPAD(0x25fa, PIN_INPUT_PULLDOWN | MUX_MODE3)    /* etk_d15.hsusb2_data1 */
-		>;
-	};
-};
-
 &uart2 {
 	interrupts-extended = <&intc 73 &omap3_pmx_core OMAP3_UART2_RX>;
 	pinctrl-names = "default";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit-28.dts
@@ -11,22 +11,6 @@
 #include "logicpd-torpedo-37xx-devkit.dts"
 
 &lcd0 {
-
-	label = "28";
-
-	panel-timing {
-		clock-frequency = <9000000>;
-		hactive = <480>;
-		vactive = <272>;
-		hfront-porch = <3>;
-		hback-porch = <2>;
-		hsync-len = <42>;
-		vback-porch = <3>;
-		vfront-porch = <2>;
-		vsync-len = <11>;
-		hsync-active = <1>;
-		vsync-active = <1>;
-		de-active = <1>;
-		pixelclk-active = <0>;
-	};
+	/* To make it work, set CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=4 */
+	compatible = "logicpd,type28";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
@@ -80,6 +80,8 @@
 };
 
 &mcbsp2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcbsp2_pins>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/lpc32xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/lpc32xx.dtsi
@@ -329,9 +329,6 @@
 
 					clocks = <&xtal_32k>, <&xtal>;
 					clock-names = "xtal_32k", "xtal";
-
-					assigned-clocks = <&clk LPC32XX_CLK_HCLK_PLL>;
-					assigned-clock-rates = <208000000>;
 				};
 			};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/ls1021a-tsn.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/ls1021a-tsn.dts
@@ -247,7 +247,7 @@
 
 	flash@0 {
 		/* Rev. A uses 64MB flash, Rev. B & C use 32MB flash */
-		compatible = "jedec,spi-nor", "s25fl256s1", "s25fl512s";
+		compatible = "jedec,spi-nor";
 		spi-max-frequency = <20000000>;
 		#address-cells = <1>;
 		#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/ls1021a.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/ls1021a.dtsi
@@ -181,7 +181,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x0 0x1550000 0x0 0x10000>,
-			      <0x0 0x40000000 0x0 0x40000000>;
+			      <0x0 0x40000000 0x0 0x20000000>;
 			reg-names = "QuadSPI", "QuadSPI-memory";
 			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
 			clock-names = "qspi_en", "qspi";
@@ -311,39 +311,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-
-				thermal-sensors = <&tmu 0>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-					cpu_crit: cpu-crit {
-						temperature = <95000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>,
-							<&cpu1 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		dspi0: spi@2100000 {
 			compatible = "fsl,ls1021a-v1.0-dspi";
 			#address-cells = <1>;
@@ -728,7 +695,7 @@
 		};
 
 		mdio0: mdio@2d24000 {
-			compatible = "fsl,etsec2-mdio";
+			compatible = "gianfar";
 			device_type = "mdio";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -737,7 +704,7 @@
 		};
 
 		mdio1: mdio@2d64000 {
-			compatible = "fsl,etsec2-mdio";
+			compatible = "gianfar";
 			device_type = "mdio";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -753,7 +720,7 @@
 			fsl,tmr-prsc    = <2>;
 			fsl,tmr-add     = <0xaaaaaaab>;
 			fsl,tmr-fiper1  = <999999995>;
-			fsl,tmr-fiper2  = <99990>;
+			fsl,tmr-fiper2  = <999999995>;
 			fsl,max-adj     = <499999999>;
 			fsl,extts-fifo;
 		};
@@ -984,4 +951,37 @@
 		};
 
 	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+
+			thermal-sensors = <&tmu 0>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit: cpu-crit {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>,
+						<&cpu1 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson.dtsi
@@ -49,14 +49,14 @@
 			};
 
 			uart_A: serial@84c0 {
-				compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+				compatible = "amlogic,meson6-uart";
 				reg = <0x84c0 0x18>;
 				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
 
 			uart_B: serial@84dc {
-				compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+				compatible = "amlogic,meson6-uart";
 				reg = <0x84dc 0x18>;
 				interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
@@ -94,7 +94,7 @@
 			};
 
 			uart_C: serial@8700 {
-				compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+				compatible = "amlogic,meson6-uart";
 				reg = <0x8700 0x18>;
 				interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
@@ -196,7 +196,7 @@
 			};
 
 			uart_AO: serial@4c0 {
-				compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart", "amlogic,meson-uart";
+				compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart";
 				reg = <0x4c0 0x18>;
 				interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8.dtsi
@@ -129,8 +129,8 @@
 	gpu_opp_table: gpu-opp-table {
 		compatible = "operating-points-v2";
 
-		opp-182150000 {
-			opp-hz = /bits/ 64 <182150000>;
+		opp-182142857 {
+			opp-hz = /bits/ 64 <182142857>;
 			opp-microvolt = <1150000>;
 		};
 		opp-318750000 {
@@ -230,8 +230,6 @@
 				     <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
@@ -243,8 +241,13 @@
 					  "pp2", "ppmmu2", "pp4", "ppmmu4",
 					  "pp5", "ppmmu5", "pp6", "ppmmu6";
 			resets = <&reset RESET_MALI>;
+
 			clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
 			clock-names = "bus", "core";
+
+			assigned-clocks = <&clkc CLKID_MALI>;
+			assigned-clock-rates = <318750000>;
+
 			operating-points-v2 = <&gpu_opp_table>;
 		};
 	};
@@ -253,7 +256,7 @@
 &aobus {
 	pmu: pmu@e0 {
 		compatible = "amlogic,meson8-pmu", "syscon";
-		reg = <0xe0 0x8>;
+		reg = <0xe0 0x18>;
 	};
 
 	pinctrl_aobus: pinctrl@84 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8b-ec100.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8b-ec100.dts
@@ -148,7 +148,7 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
-		vin-supply = <&vcc_5v>;
+		pwm-supply = <&vcc_5v>;
 
 		pwms = <&pwm_cd 0 1148 0>;
 		pwm-dutycycle-range = <100 0>;
@@ -232,7 +232,7 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
-		vin-supply = <&vcc_5v>;
+		pwm-supply = <&vcc_5v>;
 
 		pwms = <&pwm_cd 1 1148 0>;
 		pwm-dutycycle-range = <100 0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8b-mxq.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8b-mxq.dts
@@ -39,6 +39,8 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
+		pwm-supply = <&vcc_5v>;
+
 		pwms = <&pwm_cd 0 1148 0>;
 		pwm-dutycycle-range = <100 0>;
 
@@ -84,7 +86,7 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
-		vin-supply = <&vcc_5v>;
+		pwm-supply = <&vcc_5v>;
 
 		pwms = <&pwm_cd 1 1148 0>;
 		pwm-dutycycle-range = <100 0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8b-odroidc1.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8b-odroidc1.dts
@@ -130,7 +130,7 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
-		vin-supply = <&p5v0>;
+		pwm-supply = <&p5v0>;
 
 		pwms = <&pwm_cd 0 12218 0>;
 		pwm-dutycycle-range = <91 0>;
@@ -162,7 +162,7 @@
 		regulator-min-microvolt = <860000>;
 		regulator-max-microvolt = <1140000>;
 
-		vin-supply = <&p5v0>;
+		pwm-supply = <&p5v0>;
 
 		pwms = <&pwm_cd 1 12218 0>;
 		pwm-dutycycle-range = <91 0>;
@@ -219,7 +219,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
 
 			interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8b.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8b.dtsi
@@ -125,8 +125,8 @@
 			opp-hz = /bits/ 64 <255000000>;
 			opp-microvolt = <1100000>;
 		};
-		opp-364300000 {
-			opp-hz = /bits/ 64 <364300000>;
+		opp-364285714 {
+			opp-hz = /bits/ 64 <364285714>;
 			opp-microvolt = <1100000>;
 		};
 		opp-425000000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/meson8m2-mxiii-plus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/meson8m2-mxiii-plus.dts
@@ -83,7 +83,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -13,8 +13,10 @@
 		#interrupt-cells = <2>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		spi-max-frequency = <3000000>;
+		spi-max-frequency = <9600000>;
 		spi-cs-high;
+		spi-cpol;
+		spi-cpha;
 
 		cpcap_adc: adc {
 			compatible = "motorola,mapphone-cpcap-adc";
@@ -160,12 +162,12 @@
 		regulator-enable-ramp-delay = <1000>;
 	};
 
-	/* Used by DSS */
+	/* Used by DSS and is the "zerov_regulator" trigger for SoC off mode */
 	vcsi: VCSI {
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 		regulator-enable-ramp-delay = <1000>;
-		regulator-boot-on;
+		regulator-always-on;
 	};
 
 	vdac: VDAC {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/moxart-uc7112lx.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/moxart-uc7112lx.dts
@@ -79,7 +79,7 @@
 	clocks = <&ref12>;
 };
 
-&sdhci {
+&mmc {
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/moxart.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/moxart.dtsi
@@ -93,8 +93,8 @@
 			clock-names = "PCLK";
 		};
 
-		sdhci: sdhci@98e00000 {
-			compatible = "moxa,moxart-sdhci";
+		mmc: mmc@98e00000 {
+			compatible = "moxa,moxart-mmc";
 			reg = <0x98e00000 0x5C>;
 			interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&clk_apb>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
@@ -192,6 +192,7 @@
 					fixed-link {
 						speed = <1000>;
 						full-duplex;
+						pause;
 					};
 				};
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/mt7623n-rfb-emmc.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/mt7623n-rfb-emmc.dts
@@ -138,6 +138,7 @@
 	mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		phy-mode = "rgmii";
 		phy-handle = <&phy5>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
@@ -29,7 +29,7 @@
 		compatible = "smsc,lan9221","smsc,lan9115";
 		bank-width = <2>;
 
-		gpmc,mux-add-data;
+		gpmc,mux-add-data = <0>;
 		gpmc,cs-on-ns = <0>;
 		gpmc,cs-rd-off-ns = <42>;
 		gpmc,cs-wr-off-ns = <36>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -227,7 +227,7 @@
 
 		interrupt-parent = <&gpio2>;
 		interrupts = <25 0>;		/* gpio_57 */
-		pendown-gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio2 25 GPIO_ACTIVE_LOW>;
 
 		ti,x-min = /bits/ 16 <0x0>;
 		ti,x-max = /bits/ 16 <0x0fff>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
@@ -54,7 +54,7 @@
 
 		interrupt-parent = <&gpio1>;
 		interrupts = <27 0>;		/* gpio_27 */
-		pendown-gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio1 27 GPIO_ACTIVE_LOW>;
 
 		ti,x-min = /bits/ 16 <0x0>;
 		ti,x-max = /bits/ 16 <0x0fff>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-gta04.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -31,6 +31,8 @@
 	aliases {
 		display0 = &lcd;
 		display1 = &tv0;
+		/delete-property/ mmc2;
+		/delete-property/ mmc3;
 	};
 
 	ldo_3v3: fixedregulator {
@@ -515,7 +517,7 @@
 		compatible = "bosch,bma180";
 		reg = <0x41>;
 		pinctrl-names = "default";
-		pintcrl-0 = <&bma180_pins>;
+		pinctrl-0 = <&bma180_pins>;
 		interrupt-parent = <&gpio4>;
 		interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; /* GPIO_115 */
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-gta04a5one.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-gta04a5one.dts
@@ -5,9 +5,11 @@
 
 #include "omap3-gta04a5.dts"
 
-&omap3_pmx_core {
+/ {
 	model = "Goldelico GTA04A5/Letux 2804 with OneNAND";
+};
 
+&omap3_pmx_core {
 	gpmc_pins: pinmux_gpmc_pins {
 		pinctrl-single,pins = <
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -311,7 +311,7 @@
 		interrupt-parent = <&gpio1>;
 		interrupts = <8 0>;   /* boot6 / gpio_8 */
 		spi-max-frequency = <1000000>;
-		pendown-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
 		vcc-supply = <&reg_vcc3>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&tsc2048_pins>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-n900.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-n900.dts
@@ -105,6 +105,14 @@
 			linux,code = <SW_FRONT_PROXIMITY>;
 			linux,can-disable;
 		};
+
+		machine_cover {
+			label = "Machine Cover";
+			gpios = <&gpio6 0 GPIO_ACTIVE_LOW>; /* 160 */
+			linux,input-type = <EV_SW>;
+			linux,code = <SW_MACHINE_COVER>;
+			linux,can-disable;
+		};
 	};
 
 	isp1707: isp1707 {
@@ -155,6 +163,12 @@
 		pwms = <&pwm9 0 26316 0>; /* 38000 Hz */
 	};
 
+	rom_rng: rng {
+		compatible = "nokia,n900-rom-rng";
+		clocks = <&rng_ick>;
+		clock-names = "ick";
+	};
+
 	/* controlled (enabled/disabled) directly by bcm2048 and wl1251 */
 	vctcxo: vctcxo {
 		compatible = "fixed-clock";
@@ -808,10 +822,6 @@
 	pinctrl-0 = <&mmc1_pins>;
 	vmmc-supply = <&vmmc1>;
 	bus-width = <4>;
-	/* For debugging, it is often good idea to remove this GPIO.
-	   It means you can remove back cover (to reboot by removing
-	   battery) and still use the MMC card. */
-	cd-gpios = <&gpio6 0 GPIO_ACTIVE_LOW>; /* 160 */
 };
 
 /* most boards use vaux3, only some old versions use vmmc2 instead */
@@ -843,34 +853,46 @@
 		compatible = "ti,omap2-onenand";
 		reg = <0 0 0x20000>;	/* CS0, offset 0, IO size 128K */
 
+		/*
+		 * These timings are based on CONFIG_OMAP_GPMC_DEBUG=y reported
+		 * bootloader set values when booted with v5.1
+		 * (OneNAND Manufacturer: Samsung):
+		 *
+		 *   cs0 GPMC_CS_CONFIG1: 0xfb001202
+		 *   cs0 GPMC_CS_CONFIG2: 0x00111100
+		 *   cs0 GPMC_CS_CONFIG3: 0x00020200
+		 *   cs0 GPMC_CS_CONFIG4: 0x11001102
+		 *   cs0 GPMC_CS_CONFIG5: 0x03101616
+		 *   cs0 GPMC_CS_CONFIG6: 0x90060000
+		 */
 		gpmc,sync-read;
 		gpmc,sync-write;
 		gpmc,burst-length = <16>;
 		gpmc,burst-read;
 		gpmc,burst-wrap;
 		gpmc,burst-write;
-		gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */
-		gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */
+		gpmc,device-width = <2>;
+		gpmc,mux-add-data = <2>;
 		gpmc,cs-on-ns = <0>;
-		gpmc,cs-rd-off-ns = <87>;
-		gpmc,cs-wr-off-ns = <87>;
+		gpmc,cs-rd-off-ns = <102>;
+		gpmc,cs-wr-off-ns = <102>;
 		gpmc,adv-on-ns = <0>;
-		gpmc,adv-rd-off-ns = <10>;
-		gpmc,adv-wr-off-ns = <10>;
-		gpmc,oe-on-ns = <15>;
-		gpmc,oe-off-ns = <87>;
+		gpmc,adv-rd-off-ns = <12>;
+		gpmc,adv-wr-off-ns = <12>;
+		gpmc,oe-on-ns = <12>;
+		gpmc,oe-off-ns = <102>;
 		gpmc,we-on-ns = <0>;
-		gpmc,we-off-ns = <87>;
-		gpmc,rd-cycle-ns = <112>;
-		gpmc,wr-cycle-ns = <112>;
-		gpmc,access-ns = <81>;
-		gpmc,page-burst-access-ns = <15>;
+		gpmc,we-off-ns = <102>;
+		gpmc,rd-cycle-ns = <132>;
+		gpmc,wr-cycle-ns = <132>;
+		gpmc,access-ns = <96>;
+		gpmc,page-burst-access-ns = <18>;
 		gpmc,bus-turnaround-ns = <0>;
 		gpmc,cycle2cycle-delay-ns = <0>;
 		gpmc,wait-monitoring-ns = <0>;
-		gpmc,clk-activation-ns = <5>;
-		gpmc,wr-data-mux-bus-ns = <30>;
-		gpmc,wr-access-ns = <81>;
+		gpmc,clk-activation-ns = <6>;
+		gpmc,wr-data-mux-bus-ns = <36>;
+		gpmc,wr-access-ns = <96>;
 		gpmc,sync-clk-ps = <15000>;
 
 		/*
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
@@ -149,7 +149,7 @@
 
 		interrupt-parent = <&gpio4>;
 		interrupts = <18 0>;			/* gpio_114 */
-		pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
 
 		ti,x-min = /bits/ 16 <0x0>;
 		ti,x-max = /bits/ 16 <0x0fff>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
@@ -160,7 +160,7 @@
 
 		interrupt-parent = <&gpio4>;
 		interrupts = <18 0>;			/* gpio_114 */
-		pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
 
 		ti,x-min = /bits/ 16 <0x0>;
 		ti,x-max = /bits/ 16 <0x0fff>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
@@ -22,7 +22,7 @@
 		compatible = "smsc,lan9221","smsc,lan9115";
 		bank-width = <2>;
 
-		gpmc,mux-add-data;
+		gpmc,mux-add-data = <0>;
 		gpmc,cs-on-ns = <0>;
 		gpmc,cs-rd-off-ns = <42>;
 		gpmc,cs-wr-off-ns = <36>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-pandora-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-pandora-common.dtsi
@@ -226,6 +226,17 @@
 		gpio = <&gpio6 4 GPIO_ACTIVE_HIGH>;	/* GPIO_164 */
 	};
 
+	/* wl1251 wifi+bt module */
+	wlan_en: fixed-regulator-wg7210_en {
+		compatible = "regulator-fixed";
+		regulator-name = "vwlan";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		startup-delay-us = <50000>;
+		enable-active-high;
+		gpio = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+	};
+
 	/* wg7210 (wifi+bt module) 32k clock buffer */
 	wg7210_32k: fixed-regulator-wg7210_32k {
 		compatible = "regulator-fixed";
@@ -522,9 +533,30 @@
 	/*wp-gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>;*/	/* GPIO_127 */
 };
 
-/* mmc3 is probed using pdata-quirks to pass wl1251 card data */
 &mmc3 {
-	status = "disabled";
+	vmmc-supply = <&wlan_en>;
+
+	bus-width = <4>;
+	non-removable;
+	ti,non-removable;
+	cap-power-off-card;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc3_pins>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	wlan: wifi@1 {
+		compatible = "ti,wl1251";
+
+		reg = <1>;
+
+		interrupt-parent = <&gpio1>;
+		interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;	/* GPIO_21 */
+
+		ti,wl1251-has-eeprom;
+	};
 };
 
 /* bluetooth*/
@@ -619,7 +651,7 @@
 		pinctrl-0 = <&penirq_pins>;
 		interrupt-parent = <&gpio3>;
 		interrupts = <30 IRQ_TYPE_NONE>;	/* GPIO_94 */
-		pendown-gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio3 30 GPIO_ACTIVE_LOW>;
 		vcc-supply = <&vaux4>;
 
 		ti,x-min = /bits/ 16 <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3-tao3530.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3-tao3530.dtsi
@@ -222,7 +222,7 @@
 	pinctrl-0 = <&mmc1_pins>;
 	vmmc-supply = <&vmmc1>;
 	vqmmc-supply = <&vsim>;
-	cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_HIGH>;
+	cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>;
 	bus-width = <8>;
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3.dtsi
@@ -23,6 +23,9 @@
 		i2c0 = &i2c1;
 		i2c1 = &i2c2;
 		i2c2 = &i2c3;
+		mmc0 = &mmc1;
+		mmc1 = &mmc2;
+		mmc2 = &mmc3;
 		serial0 = &uart1;
 		serial1 = &uart2;
 		serial2 = &uart3;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap3430-sdp.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap3430-sdp.dts
@@ -101,7 +101,7 @@
 
 	nand@1,0 {
 		compatible = "ti,omap2-nand";
-		reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
+		reg = <1 0 4>; /* CS1, offset 0, IO size 4 */
 		interrupt-parent = <&gpmc>;
 		interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
 			     <1 IRQ_TYPE_NONE>;	/* termcount */
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap4-droid4-xt894.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap4-droid4-xt894.dts
@@ -656,12 +656,12 @@
 /* Configure pwm clock source for timers 8 & 9 */
 &timer8 {
 	assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>;
-	assigned-clock-parents = <&sys_clkin_ck>;
+	assigned-clock-parents = <&sys_32k_ck>;
 };
 
 &timer9 {
 	assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>;
-	assigned-clock-parents = <&sys_clkin_ck>;
+	assigned-clock-parents = <&sys_32k_ck>;
 };
 
 /*
@@ -678,6 +678,7 @@
 &uart3 {
 	interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
 			       &omap4_pmx_core 0x17c>;
+	overrun-throttle-ms = <500>;
 };
 
 &uart4 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -139,7 +139,7 @@
 	ethernet@gpmc {
 		reg = <5 0 0xff>;
 		interrupt-parent = <&gpio2>;
-		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;	/* gpio_44 */
+		interrupts = <12 IRQ_TYPE_LEVEL_LOW>;		/* gpio_44 */
 
 		phy-mode = "mii";
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap4-panda-es.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap4-panda-es.dts
@@ -46,7 +46,7 @@
 
 	button_pins: pinmux_button_pins {
 		pinctrl-single,pins = <
-			OMAP4_IOPAD(0x11b, PIN_INPUT_PULLUP | MUX_MODE3) /* gpio_113 */
+			OMAP4_IOPAD(0x0fc, PIN_INPUT_PULLUP | MUX_MODE3) /* gpio_113 */
 		>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap4.dtsi
@@ -22,6 +22,11 @@
 		i2c1 = &i2c2;
 		i2c2 = &i2c3;
 		i2c3 = &i2c4;
+		mmc0 = &mmc1;
+		mmc1 = &mmc2;
+		mmc2 = &mmc3;
+		mmc3 = &mmc4;
+		mmc4 = &mmc5;
 		serial0 = &uart1;
 		serial1 = &uart2;
 		serial2 = &uart3;
@@ -328,10 +333,10 @@
 			status = "disabled";
 		};
 
-		target-module@56000000 {
+		sgx_module: target-module@56000000 {
 			compatible = "ti,sysc-omap4", "ti,sysc";
-			reg = <0x5601fc00 0x4>,
-			      <0x5601fc10 0x4>;
+			reg = <0x5600fe00 0x4>,
+			      <0x5600fe10 0x4>;
 			reg-names = "rev", "sysc";
 			ti,sysc-midle = <SYSC_IDLE_FORCE>,
 					<SYSC_IDLE_NO>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap443x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap443x.dtsi
@@ -33,10 +33,12 @@
 	};
 
 	ocp {
+		/* 4430 has only gpio_86 tshut and no talert interrupt */
 		bandgap: bandgap@4a002260 {
 			reg = <0x4a002260 0x4
 			       0x4a00232C 0x4>;
 			compatible = "ti,omap4430-bandgap";
+			gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
 
 			#thermal-sensor-cells = <0>;
 		};
@@ -74,3 +76,13 @@
 };
 
 /include/ "omap443x-clocks.dtsi"
+
+/*
+ * Use dpll_per for sgx at 153.6MHz like droid4 stock v3.0.8 Android kernel
+ */
+&sgx_module {
+	assigned-clocks = <&l3_gfx_clkctrl OMAP4_GPU_CLKCTRL 24>,
+			  <&dpll_per_m7x2_ck>;
+	assigned-clock-rates = <0>, <153600000>;
+	assigned-clock-parents = <&dpll_per_m7x2_ck>;
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap44xx-clocks.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap44xx-clocks.dtsi
@@ -770,14 +770,6 @@
 		ti,max-div = <2>;
 	};
 
-	sha2md5_fck: sha2md5_fck@15c8 {
-		#clock-cells = <0>;
-		compatible = "ti,gate-clock";
-		clocks = <&l3_div_ck>;
-		ti,bit-shift = <1>;
-		reg = <0x15c8>;
-	};
-
 	usb_phy_cm_clk32k: usb_phy_cm_clk32k@640 {
 		#clock-cells = <0>;
 		compatible = "ti,gate-clock";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap5-board-common.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap5-board-common.dtsi
@@ -30,14 +30,6 @@
 		regulator-max-microvolt = <5000000>;
 	};
 
-	vdds_1v8_main: fixedregulator-vdds_1v8_main {
-		compatible = "regulator-fixed";
-		regulator-name = "vdds_1v8_main";
-		vin-supply = <&smps7_reg>;
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-	};
-
 	vmmcsd_fixed: fixedregulator-mmcsd {
 		compatible = "regulator-fixed";
 		regulator-name = "vmmcsd_fixed";
@@ -487,6 +479,7 @@
 					regulator-boot-on;
 				};
 
+				vdds_1v8_main:
 				smps7_reg: smps7 {
 					/* VDDS_1v8_OMAP over VDDS_1v8_MAIN */
 					regulator-name = "smps7";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap5-cm-t54.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap5-cm-t54.dts
@@ -354,7 +354,7 @@
 
 		interrupt-parent = <&gpio1>;
 		interrupts = <15 0>;			/* gpio1_wk15 */
-		pendown-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+		pendown-gpio = <&gpio1 15 GPIO_ACTIVE_LOW>;
 
 
 		ti,x-min = /bits/ 16 <0x0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/omap5.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/omap5.dtsi
@@ -25,6 +25,11 @@
 		i2c2 = &i2c3;
 		i2c3 = &i2c4;
 		i2c4 = &i2c5;
+		mmc0 = &mmc1;
+		mmc1 = &mmc2;
+		mmc2 = &mmc3;
+		mmc3 = &mmc4;
+		mmc4 = &mmc5;
 		serial0 = &uart1;
 		serial1 = &uart2;
 		serial2 = &uart3;
@@ -143,6 +148,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0 0 0 0xc0000000>;
+		dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>;
 		ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3";
 		reg = <0 0x44000000 0 0x2000>,
 		      <0 0x44800000 0 0x3000>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00001-0001.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00001-0001.dts
@@ -0,0 +1,26 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00001";
+	version = "0001";
+
+	fragment@0 {
+		target = <&default_adccard>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc1>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-0002.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-0002.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "0002";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-0003.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-0003.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "0003";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-0004.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-0004.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "0004";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-0005.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-0005.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "0005";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-0006.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-0006.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "0006";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00110-000A.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00110-000A.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00110";
+	version = "000A";
+
+	fragment@0 {
+		target = <&verizon_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vz_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00121-0001.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00121-0001.dts
@@ -0,0 +1,28 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00121";
+	version = "0001";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00121-0003.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00121-0003.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00121";
+	version = "0003";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00121-0004.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00121-0004.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00121";
+	version = "0004";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00121-000A.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00121-000A.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00121";
+	version = "000A";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00125-0001.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00125-0001.dts
@@ -0,0 +1,55 @@
+/dts-v1/;
+/plugin/;
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00125";
+	version = "0001";
+
+	fragment@0 {
+		target = <&tau_board>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_tau80>;
+		};
+	};
+
+	fragment@1 {
+		target = <&uart4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart5>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&uart8>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc1>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00125-0002.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00125-0002.dts
@@ -0,0 +1,55 @@
+/dts-v1/;
+/plugin/;
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00125";
+	version = "0002";
+
+	fragment@0 {
+		target = <&tau_board>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_tau80>;
+		};
+	};
+
+	fragment@1 {
+		target = <&uart4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart5>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&uart8>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc1>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00125-000A.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00125-000A.dts
@@ -0,0 +1,55 @@
+/dts-v1/;
+/plugin/;
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00125";
+	version = "000A";
+
+	fragment@0 {
+		target = <&tau_board>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_tau80>;
+		};
+	};
+
+	fragment@1 {
+		target = <&uart4>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart5>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&uart8>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc1>;
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00134-0001.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00134-0001.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+/plugin/;
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00134";
+	version = "0001";
+
+	fragment@0 {
+		target = <&multiplexer_board>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_multiplexer>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00157-0001.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00157-0001.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00157";
+	version = "0001";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/310-00157-000A.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/310-00157-000A.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "rigado,vesta";
+
+	/* identification */
+	part-number = "310-00157";
+	version = "000A";
+
+	fragment@0 {
+		target = <&gemalto_cellmdm>;
+		__overlay__ {
+			status = "okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_gm_cellmdm>;
+		};
+	};
+
+	fragment@1 {
+		target = <&adc1>;
+		__overlay__ {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_adc2>;
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&uart7>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/overlays/Makefile
+++ linux-ein-5.4.0/arch/arm/boot/dts/overlays/Makefile
@@ -0,0 +1,29 @@
+ifeq ($(CONFIG_OF),y)
+
+# Overlays for Vesta IoT Gateways
+
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00001-0001.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-0002.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-0003.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-0004.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-0005.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-0006.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00110-000A.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00121-0001.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00121-0003.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00121-0004.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00121-000A.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00125-0001.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00125-0002.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00125-000A.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00134-0001.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00157-0001.dtbo
+dtbo-$(CONFIG_OF_OVERLAY) += 310-00157-000A.dtbo
+
+targets += dtbs dtbs_install
+targets += $(dtbo-y)
+
+endif
+
+always		:= $(dtbo-y)
+clean-files	:= *.dtbo
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/owl-s500.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/owl-s500.dtsi
@@ -84,21 +84,21 @@
 		global_timer: timer@b0020200 {
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0xb0020200 0x100>;
-			interrupts = <GIC_PPI 0 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
+			interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
 			status = "disabled";
 		};
 
 		twd_timer: timer@b0020600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xb0020600 0x20>;
-			interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
 			status = "disabled";
 		};
 
 		twd_wdt: wdt@b0020620 {
 			compatible = "arm,cortex-a9-twd-wdt";
 			reg = <0xb0020620 0xe0>;
-			interrupts = <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
+			interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
 			status = "disabled";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/ox810se.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/ox810se.dtsi
@@ -323,8 +323,8 @@
 					interrupt-controller;
 					reg = <0 0x200>;
 					#interrupt-cells = <1>;
-					valid-mask = <0xFFFFFFFF>;
-					clear-mask = <0>;
+					valid-mask = <0xffffffff>;
+					clear-mask = <0xffffffff>;
 				};
 
 				timer0: timer@200 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/ox820.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/ox820.dtsi
@@ -240,8 +240,8 @@
 					reg = <0 0x200>;
 					interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 					#interrupt-cells = <1>;
-					valid-mask = <0xFFFFFFFF>;
-					clear-mask = <0>;
+					valid-mask = <0xffffffff>;
+					clear-mask = <0xffffffff>;
 				};
 
 				timer0: timer@200 {
@@ -287,7 +287,7 @@
 				clocks = <&armclk>;
 			};
 
-			gic: gic@1000 {
+			gic: interrupt-controller@1000 {
 				compatible = "arm,arm11mp-gic";
 				interrupt-controller;
 				#interrupt-cells = <3>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/picoxcell-pc3x2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/picoxcell-pc3x2.dtsi
@@ -45,18 +45,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>;
 		};
 
@@ -234,6 +237,7 @@
 		axi2pico@c0000000 {
 			compatible = "picochip,axi2pico-pc3x2";
 			reg = <0xc0000000 0x10000>;
+			interrupt-parent = <&vic0>;
 			interrupts = <13 14 15 16 17 18 19 20 21>;
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -198,7 +198,7 @@
 			clock-frequency = <19200000>;
 		};
 
-		pxo_board {
+		pxo_board: pxo_board {
 			compatible = "fixed-clock";
 			#clock-cells = <0>;
 			clock-frequency = <27000000>;
@@ -759,7 +759,7 @@
 
 				xoadc: xoadc@197 {
 					compatible = "qcom,pm8921-adc";
-					reg = <197>;
+					reg = <0x197>;
 					interrupts-extended = <&pmicintc 78 IRQ_TYPE_EDGE_RISING>;
 					#address-cells = <2>;
 					#size-cells = <0>;
@@ -1147,7 +1147,7 @@
 		};
 
 		gpu: adreno-3xx@4300000 {
-			compatible = "qcom,adreno-3xx";
+			compatible = "qcom,adreno-320.2", "qcom,adreno";
 			reg = <0x04300000 0x20000>;
 			reg-names = "kgsl_3d0_reg_memory";
 			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
@@ -1162,7 +1162,6 @@
 			    <&mmcc GFX3D_AHB_CLK>,
 			    <&mmcc GFX3D_AXI_CLK>,
 			    <&mmcc MMSS_IMEM_AHB_CLK>;
-			qcom,chipid = <0x03020002>;
 
 			iommus = <&gfx3d 0
 				  &gfx3d 1
@@ -1261,9 +1260,9 @@
 				<&mmcc DSI1_BYTE_CLK>,
 				<&mmcc DSI_PIXEL_CLK>,
 				<&mmcc DSI1_ESC_CLK>;
-			clock-names = "iface_clk", "bus_clk", "core_mmss_clk",
-					"src_clk", "byte_clk", "pixel_clk",
-					"core_clk";
+			clock-names = "iface", "bus", "core_mmss",
+					"src", "byte", "pixel",
+					"core";
 
 			assigned-clocks = <&mmcc DSI1_BYTE_SRC>,
 					<&mmcc DSI1_ESC_SRC>,
@@ -1305,7 +1304,7 @@
 			reg-names = "dsi_pll", "dsi_phy", "dsi_phy_regulator";
 			clock-names = "iface_clk", "ref";
 			clocks = <&mmcc DSI_M_AHB_CLK>,
-				 <&cxo_board>;
+				 <&pxo_board>;
 		};
 
 
@@ -1571,7 +1570,7 @@
 		};
 
 		etb@1a01000 {
-			compatible = "coresight-etb10", "arm,primecell";
+			compatible = "arm,coresight-etb10", "arm,primecell";
 			reg = <0x1a01000 0x1000>;
 
 			clocks = <&rpmcc RPM_QDSS_CLK>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -141,7 +141,8 @@
 	clocks {
 		sleep_clk: sleep_clk {
 			compatible = "fixed-clock";
-			clock-frequency = <32768>;
+			clock-frequency = <32000>;
+			clock-output-names = "gcc_sleep_clk_src";
 			#clock-cells = <0>;
 		};
 
@@ -392,8 +393,8 @@
 			#address-cells = <3>;
 			#size-cells = <2>;
 
-			ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000>,
-				 <0x82000000 0 0x40300000 0x40300000 0 0x00d00000>;
+			ranges = <0x81000000 0x0 0x00000000 0x40200000 0x0 0x00100000>,
+				 <0x82000000 0x0 0x40300000 0x40300000 0x0 0x00d00000>;
 
 			interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "msi";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -451,8 +451,8 @@
 			#address-cells = <3>;
 			#size-cells = <2>;
 
-			ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000   /* downstream I/O */
-				  0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */
+			ranges = <0x81000000 0x0 0x00000000 0x0fe00000 0x0 0x00010000   /* I/O */
+				  0x82000000 0x0 0x08000000 0x08000000 0x0 0x07e00000>; /* MEM */
 
 			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "msi";
@@ -502,8 +502,8 @@
 			#address-cells = <3>;
 			#size-cells = <2>;
 
-			ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000   /* downstream I/O */
-				  0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */
+			ranges = <0x81000000 0x0 0x00000000 0x31e00000 0x0 0x00010000   /* I/O */
+				  0x82000000 0x0 0x2e000000 0x2e000000 0x0 0x03e00000>; /* MEM */
 
 			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "msi";
@@ -553,8 +553,8 @@
 			#address-cells = <3>;
 			#size-cells = <2>;
 
-			ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000   /* downstream I/O */
-				  0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */
+			ranges = <0x81000000 0x0 0x00000000 0x35e00000 0x0 0x00010000   /* I/O */
+				  0x82000000 0x0 0x32000000 0x32000000 0x0 0x03e00000>; /* MEM */
 
 			interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "msi";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-mdm9615.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-mdm9615.dtsi
@@ -82,14 +82,12 @@
 		};
 	};
 
-	regulators {
-		vsdcc_fixed: vsdcc-regulator {
-			compatible = "regulator-fixed";
-			regulator-name = "SDCC Power";
-			regulator-min-microvolt = <2700000>;
-			regulator-max-microvolt = <2700000>;
-			regulator-always-on;
-		};
+	vsdcc_fixed: vsdcc-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "SDCC Power";
+		regulator-min-microvolt = <2700000>;
+		regulator-max-microvolt = <2700000>;
+		regulator-always-on;
 	};
 
 	soc: soc {
@@ -323,6 +321,7 @@
 
 				pmicgpio: gpio@150 {
 					compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio";
+					reg = <0x150>;
 					interrupt-controller;
 					#interrupt-cells = <2>;
 					gpio-controller;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-msm8960.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-msm8960.dtsi
@@ -145,7 +145,9 @@
 			reg		= <0x108000 0x1000>;
 			qcom,ipc	= <&l2cc 0x8 2>;
 
-			interrupts	= <0 19 0>, <0 21 0>, <0 22 0>;
+			interrupts	= <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
+					  <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+					  <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names	= "ack", "err", "wakeup";
 
 			regulators {
@@ -191,7 +193,7 @@
 				compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
 				reg = <0x16440000 0x1000>,
 				      <0x16400000 0x1000>;
-				interrupts = <0 154 0x0>;
+				interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>;
 				clock-names = "core", "iface";
 				status = "disabled";
@@ -317,7 +319,7 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 				reg = <0x16080000 0x1000>;
-				interrupts = <0 147 0>;
+				interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
 				spi-max-frequency = <24000000>;
 				cs-gpios = <&msmgpio 8 0>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -1213,8 +1213,8 @@
 				#phy-cells = <0>;
 				qcom,dsi-phy-index = <0>;
 
-				clocks = <&mmcc MDSS_AHB_CLK>;
-				clock-names = "iface";
+				clocks = <&mmcc MDSS_AHB_CLK>, <&xo_board>;
+				clock-names = "iface", "ref";
 			};
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/qcom-pm8841.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/qcom-pm8841.dtsi
@@ -25,6 +25,7 @@
 			compatible = "qcom,spmi-temp-alarm";
 			reg = <0x2400>;
 			interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>;
+			#thermal-sensor-cells = <0>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a73a4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a73a4.dtsi
@@ -131,7 +131,14 @@
 	cmt1: timer@e6130000 {
 		compatible = "renesas,r8a73a4-cmt1", "renesas,rcar-gen2-cmt1";
 		reg = <0 0xe6130000 0 0x1004>;
-		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A73A4_CLK_CMT1>;
 		clock-names = "fck";
 		power-domains = <&pd_c5>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7740.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7740.dtsi
@@ -479,7 +479,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-ein-5.4.0.orig/arch/arm/boot/dts/r8a7743.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7743.dtsi
@@ -338,7 +338,7 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -348,7 +348,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -357,7 +357,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -367,7 +367,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -376,7 +376,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -386,7 +386,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7743",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7744.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7744.dtsi
@@ -338,7 +338,7 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -348,7 +348,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -357,7 +357,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -367,7 +367,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -376,7 +376,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -386,7 +386,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7744",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7745.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7745.dtsi
@@ -302,7 +302,7 @@
 			resets = <&cpg 407>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -312,7 +312,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -321,7 +321,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -331,7 +331,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -340,7 +340,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -350,7 +350,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7745",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7779-marzen.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7779-marzen.dts
@@ -146,7 +146,7 @@
 	status = "okay";
 
 	clocks = <&mstp1_clks R8A7779_CLK_DU>, <&x3_clk>;
-	clock-names = "du", "dclkin.0";
+	clock-names = "du.0", "dclkin.0";
 
 	ports {
 		port@0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7779.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7779.dtsi
@@ -68,6 +68,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>;
@@ -455,6 +463,7 @@
 		reg = <0xfff80000 0x40000>;
 		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp1_clks R8A7779_CLK_DU>;
+		clock-names = "du.0";
 		power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
 		status = "disabled";
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7790.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7790.dtsi
@@ -427,7 +427,7 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -437,7 +437,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -446,7 +446,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -456,7 +456,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -465,7 +465,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -475,7 +475,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_rt: mmu@ffc80000 {
+		ipmmu_rt: iommu@ffc80000 {
 			compatible = "renesas,ipmmu-r8a7790",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xffc80000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7791.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7791.dtsi
@@ -350,7 +350,7 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -360,7 +360,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -369,7 +369,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -379,7 +379,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -388,7 +388,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -398,7 +398,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_rt: mmu@ffc80000 {
+		ipmmu_rt: iommu@ffc80000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xffc80000 0 0x1000>;
@@ -407,7 +407,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7791",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7793-gose.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7793-gose.dts
@@ -339,7 +339,7 @@
 			reg = <0x20>;
 			remote = <&vin1>;
 
-			port {
+			ports {
 				#address-cells = <1>;
 				#size-cells = <0>;
 
@@ -399,7 +399,7 @@
 			interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 			default-input = <0>;
 
-			port {
+			ports {
 				#address-cells = <1>;
 				#size-cells = <0>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7793.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7793.dtsi
@@ -336,7 +336,7 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -346,7 +346,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -355,7 +355,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -365,7 +365,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -374,7 +374,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -384,7 +384,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_rt: mmu@ffc80000 {
+		ipmmu_rt: iommu@ffc80000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xffc80000 0 0x1000>;
@@ -393,7 +393,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7793",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/r8a7794.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/r8a7794.dtsi
@@ -290,7 +290,7 @@
 			resets = <&cpg 407>;
 		};
 
-		ipmmu_sy0: mmu@e6280000 {
+		ipmmu_sy0: iommu@e6280000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6280000 0 0x1000>;
@@ -300,7 +300,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_sy1: mmu@e6290000 {
+		ipmmu_sy1: iommu@e6290000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6290000 0 0x1000>;
@@ -309,7 +309,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_ds: mmu@e6740000 {
+		ipmmu_ds: iommu@e6740000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe6740000 0 0x1000>;
@@ -319,7 +319,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mp: mmu@ec680000 {
+		ipmmu_mp: iommu@ec680000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xec680000 0 0x1000>;
@@ -328,7 +328,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_mx: mmu@fe951000 {
+		ipmmu_mx: iommu@fe951000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xfe951000 0 0x1000>;
@@ -338,7 +338,7 @@
 			status = "disabled";
 		};
 
-		ipmmu_gp: mmu@e62a0000 {
+		ipmmu_gp: iommu@e62a0000 {
 			compatible = "renesas,ipmmu-r8a7794",
 				     "renesas,ipmmu-vmsa";
 			reg = <0 0xe62a0000 0 0x1000>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3036-evb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3036-evb.dts
@@ -31,7 +31,7 @@
 &i2c1 {
 	status = "okay";
 
-	hym8563: hym8563@51 {
+	hym8563: rtc@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
 		#clock-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3036-kylin.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3036-kylin.dts
@@ -390,7 +390,7 @@
 		};
 	};
 
-	sleep {
+	suspend {
 		global_pwroff: global-pwroff {
 			rockchip,pins = <2 RK_PA7 1 &pcfg_pull_none>;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3036.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3036.dtsi
@@ -128,7 +128,7 @@
 		assigned-clocks = <&cru SCLK_GPU>;
 		assigned-clock-rates = <100000000>;
 		clocks = <&cru SCLK_GPU>, <&cru SCLK_GPU>;
-		clock-names = "core", "bus";
+		clock-names = "bus", "core";
 		resets = <&cru SRST_GPU>;
 		status = "disabled";
 	};
@@ -337,12 +337,20 @@
 		pinctrl-0 = <&hdmi_ctl>;
 		status = "disabled";
 
-		hdmi_in: port {
+		ports {
 			#address-cells = <1>;
 			#size-cells = <0>;
-			hdmi_in_vop: endpoint@0 {
+
+			hdmi_in: port@0 {
 				reg = <0>;
-				remote-endpoint = <&vop_out_hdmi>;
+
+				hdmi_in_vop: endpoint {
+					remote-endpoint = <&vop_out_hdmi>;
+				};
+			};
+
+			hdmi_out: port@1 {
+				reg = <1>;
 			};
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3066a.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3066a.dtsi
@@ -761,7 +761,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		pd_vio@RK3066_PD_VIO {
+		power-domain@RK3066_PD_VIO {
 			reg = <RK3066_PD_VIO>;
 			clocks = <&cru ACLK_LCDC0>,
 				 <&cru ACLK_LCDC1>,
@@ -788,7 +788,7 @@
 				 <&qos_rga>;
 		};
 
-		pd_video@RK3066_PD_VIDEO {
+		power-domain@RK3066_PD_VIDEO {
 			reg = <RK3066_PD_VIDEO>;
 			clocks = <&cru ACLK_VDPU>,
 				 <&cru ACLK_VEPU>,
@@ -797,7 +797,7 @@
 			pm_qos = <&qos_vpu>;
 		};
 
-		pd_gpu@RK3066_PD_GPU {
+		power-domain@RK3066_PD_GPU {
 			reg = <RK3066_PD_GPU>;
 			clocks = <&cru ACLK_GPU>;
 			pm_qos = <&qos_gpu>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3188-bqedison2qc.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3188-bqedison2qc.dts
@@ -58,20 +58,25 @@
 
 	lvds-encoder {
 		compatible = "ti,sn75lvds83", "lvds-encoder";
-		#address-cells = <1>;
-		#size-cells = <0>;
 
-		port@0 {
-			reg = <0>;
-			lvds_in_vop0: endpoint {
-				remote-endpoint = <&vop0_out_lvds>;
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				lvds_in_vop0: endpoint {
+					remote-endpoint = <&vop0_out_lvds>;
+				};
 			};
-		};
 
-		port@1 {
-			reg = <1>;
-			lvds_out_panel: endpoint {
-				remote-endpoint = <&panel_in_lvds>;
+			port@1 {
+				reg = <1>;
+
+				lvds_out_panel: endpoint {
+					remote-endpoint = <&panel_in_lvds>;
+				};
 			};
 		};
 	};
@@ -465,10 +470,13 @@
 	non-removable;
 	pinctrl-names = "default";
 	pinctrl-0 = <&sd1_clk>, <&sd1_cmd>, <&sd1_bus4>;
-	vmmcq-supply = <&vccio_wl>;
+	vqmmc-supply = <&vccio_wl>;
+	#address-cells = <1>;
+	#size-cells = <0>;
 	status = "okay";
 
 	brcmf: wifi@1 {
+		reg = <1>;
 		compatible = "brcm,bcm4329-fmac";
 		interrupt-parent = <&gpio3>;
 		interrupts = <RK_PD2 GPIO_ACTIVE_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3188-radxarock.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3188-radxarock.dts
@@ -67,7 +67,7 @@
 		#sound-dai-cells = <0>;
 	};
 
-	ir_recv: gpio-ir-receiver {
+	ir_recv: ir-receiver {
 		compatible = "gpio-ir-receiver";
 		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
 		pinctrl-names = "default";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3188.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3188.dtsi
@@ -150,16 +150,16 @@
 		compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer";
 		reg = <0x2000e000 0x20>;
 		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cru SCLK_TIMER3>, <&cru PCLK_TIMER3>;
-		clock-names = "timer", "pclk";
+		clocks = <&cru PCLK_TIMER3>, <&cru SCLK_TIMER3>;
+		clock-names = "pclk", "timer";
 	};
 
 	timer6: timer@200380a0 {
 		compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer";
 		reg = <0x200380a0 0x20>;
 		interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cru SCLK_TIMER6>, <&cru PCLK_TIMER0>;
-		clock-names = "timer", "pclk";
+		clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER6>;
+		clock-names = "pclk", "timer";
 	};
 
 	i2s0: i2s@1011a000 {
@@ -404,7 +404,7 @@
 				rockchip,pins = <2 RK_PD3 1 &pcfg_pull_none>;
 			};
 
-			lcdc1_rgb24: ldcd1-rgb24 {
+			lcdc1_rgb24: lcdc1-rgb24 {
 				rockchip,pins = <2 RK_PA0 1 &pcfg_pull_none>,
 						<2 RK_PA1 1 &pcfg_pull_none>,
 						<2 RK_PA2 1 &pcfg_pull_none>,
@@ -632,7 +632,6 @@
 
 &global_timer {
 	interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_EDGE_RISING)>;
-	status = "disabled";
 };
 
 &local_timer {
@@ -701,7 +700,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		pd_vio@RK3188_PD_VIO {
+		power-domain@RK3188_PD_VIO {
 			reg = <RK3188_PD_VIO>;
 			clocks = <&cru ACLK_LCDC0>,
 				 <&cru ACLK_LCDC1>,
@@ -723,7 +722,7 @@
 				 <&qos_rga>;
 		};
 
-		pd_video@RK3188_PD_VIDEO {
+		power-domain@RK3188_PD_VIDEO {
 			reg = <RK3188_PD_VIDEO>;
 			clocks = <&cru ACLK_VDPU>,
 				 <&cru ACLK_VEPU>,
@@ -732,7 +731,7 @@
 			pm_qos = <&qos_vpu>;
 		};
 
-		pd_gpu@RK3188_PD_GPU {
+		power-domain@RK3188_PD_GPU {
 			reg = <RK3188_PD_GPU>;
 			clocks = <&cru ACLK_GPU>;
 			pm_qos = <&qos_gpu>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3228-evb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3228-evb.dts
@@ -46,7 +46,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		phy: phy@0 {
+		phy: ethernet-phy@0 {
 			compatible = "ethernet-phy-id1234.d400", "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
 			clocks = <&cru SCLK_MAC_PHY>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3229-xms6.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3229-xms6.dts
@@ -150,7 +150,7 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		phy: phy@0 {
+		phy: ethernet-phy@0 {
 			compatible = "ethernet-phy-id1234.d400",
 			             "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk322x.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk322x.dtsi
@@ -561,7 +561,7 @@
 				  "pp1",
 				  "ppmmu1";
 		clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
-		clock-names = "core", "bus";
+		clock-names = "bus", "core";
 		resets = <&cru SRST_GPU_A>;
 		status = "disabled";
 	};
@@ -570,10 +570,9 @@
 		compatible = "rockchip,iommu";
 		reg = <0x20020800 0x100>;
 		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "vpu_mmu";
 		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
 		clock-names = "aclk", "iface";
-		iommu-cells = <0>;
+		#iommu-cells = <0>;
 		status = "disabled";
 	};
 
@@ -581,10 +580,9 @@
 		compatible = "rockchip,iommu";
 		reg = <0x20030480 0x40>, <0x200304c0 0x40>;
 		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "vdec_mmu";
 		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>;
 		clock-names = "aclk", "iface";
-		iommu-cells = <0>;
+		#iommu-cells = <0>;
 		status = "disabled";
 	};
 
@@ -614,7 +612,6 @@
 		compatible = "rockchip,iommu";
 		reg = <0x20053f00 0x100>;
 		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "vop_mmu";
 		clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
 		clock-names = "aclk", "iface";
 		#iommu-cells = <0>;
@@ -625,10 +622,9 @@
 		compatible = "rockchip,iommu";
 		reg = <0x20070800 0x100>;
 		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "iep_mmu";
 		clocks = <&cru ACLK_IEP>, <&cru HCLK_IEP>;
 		clock-names = "aclk", "iface";
-		iommu-cells = <0>;
+		#iommu-cells = <0>;
 		status = "disabled";
 	};
 
@@ -639,8 +635,8 @@
 		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
 		assigned-clocks = <&cru SCLK_HDMI_PHY>;
 		assigned-clock-parents = <&hdmi_phy>;
-		clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>;
-		clock-names = "isfr", "iahb", "cec";
+		clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
+		clock-names = "iahb", "isfr", "cec";
 		pinctrl-names = "default";
 		pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
 		resets = <&cru SRST_HDMI_P>;
@@ -1033,7 +1029,7 @@
 			};
 		};
 
-		spi-0 {
+		spi0 {
 			spi0_clk: spi0-clk {
 				rockchip,pins = <0 RK_PB1 2 &pcfg_pull_up>;
 			};
@@ -1051,7 +1047,7 @@
 			};
 		};
 
-		spi-1 {
+		spi1 {
 			spi1_clk: spi1-clk {
 				rockchip,pins = <0 RK_PC7 2 &pcfg_pull_up>;
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -53,7 +53,7 @@
 		vin-supply = <&vcc_sys>;
 	};
 
-	hym8563@51 {
+	rtc@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-firefly.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -233,7 +233,7 @@
 		vin-supply = <&vcc_sys>;
 	};
 
-	hym8563: hym8563@51 {
+	hym8563: rtc@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
 		#clock-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-miqi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-miqi.dts
@@ -145,7 +145,7 @@
 		vin-supply = <&vcc_sys>;
 	};
 
-	hym8563: hym8563@51 {
+	hym8563: rtc@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
 		#clock-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-rock2-som.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-rock2-som.dtsi
@@ -218,7 +218,7 @@
 	flash0-supply = <&vcc_flash>;
 	flash1-supply = <&vccio_pmu>;
 	gpio30-supply = <&vccio_pmu>;
-	gpio1830 = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
 	lcdc-supply = <&vcc_io>;
 	sdcard-supply = <&vccio_sd>;
 	wifi-supply = <&vcc_18>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-rock2-square.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-rock2-square.dts
@@ -165,7 +165,7 @@
 };
 
 &i2c0 {
-	hym8563: hym8563@51 {
+	hym8563: rtc@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
 		#clock-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288-vyasa.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -357,10 +357,10 @@
 	audio-supply = <&vcc_18>;
 	bb-supply = <&vcc_io>;
 	dvp-supply = <&vcc_io>;
-	flash0-suuply = <&vcc_18>;
+	flash0-supply = <&vcc_18>;
 	flash1-supply = <&vcc_lan>;
 	gpio30-supply = <&vcc_io>;
-	gpio1830 = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
 	lcdc-supply = <&vcc_io>;
 	sdcard-supply = <&vccio_sd>;
 	wifi-supply = <&vcc_18>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3288.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3288.dtsi
@@ -238,8 +238,8 @@
 		compatible = "rockchip,rk3288-timer";
 		reg = <0x0 0xff810000 0x0 0x20>;
 		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&xin24m>, <&cru PCLK_TIMER>;
-		clock-names = "timer", "pclk";
+		clocks = <&cru PCLK_TIMER>, <&xin24m>;
+		clock-names = "pclk", "timer";
 	};
 
 	display-subsystem {
@@ -771,7 +771,7 @@
 			 *	*_HDMI		HDMI
 			 *	*_MIPI_*	MIPI
 			 */
-			pd_vio@RK3288_PD_VIO {
+			power-domain@RK3288_PD_VIO {
 				reg = <RK3288_PD_VIO>;
 				clocks = <&cru ACLK_IEP>,
 					 <&cru ACLK_ISP>,
@@ -813,7 +813,7 @@
 			 * Note: The following 3 are HEVC(H.265) clocks,
 			 * and on the ACLK_HEVC_NIU (NOC).
 			 */
-			pd_hevc@RK3288_PD_HEVC {
+			power-domain@RK3288_PD_HEVC {
 				reg = <RK3288_PD_HEVC>;
 				clocks = <&cru ACLK_HEVC>,
 					 <&cru SCLK_HEVC_CABAC>,
@@ -827,7 +827,7 @@
 			 * (video endecoder & decoder) clocks that on the
 			 * ACLK_VCODEC_NIU and HCLK_VCODEC_NIU (NOC).
 			 */
-			pd_video@RK3288_PD_VIDEO {
+			power-domain@RK3288_PD_VIDEO {
 				reg = <RK3288_PD_VIDEO>;
 				clocks = <&cru ACLK_VCODEC>,
 					 <&cru HCLK_VCODEC>;
@@ -838,7 +838,7 @@
 			 * Note: ACLK_GPU is the GPU clock,
 			 * and on the ACLK_GPU_NIU (NOC).
 			 */
-			pd_gpu@RK3288_PD_GPU {
+			power-domain@RK3288_PD_GPU {
 				reg = <RK3288_PD_GPU>;
 				clocks = <&cru ACLK_GPU>;
 				pm_qos = <&qos_gpu_r>,
@@ -942,7 +942,7 @@
 		status = "disabled";
 	};
 
-	spdif: sound@ff88b0000 {
+	spdif: sound@ff8b0000 {
 		compatible = "rockchip,rk3288-spdif", "rockchip,rk3066-spdif";
 		reg = <0x0 0xff8b0000 0x0 0x10000>;
 		#sound-dai-cells = <0>;
@@ -975,7 +975,7 @@
 		status = "disabled";
 	};
 
-	crypto: cypto-controller@ff8a0000 {
+	crypto: crypto@ff8a0000 {
 		compatible = "rockchip,rk3288-crypto";
 		reg = <0x0 0xff8a0000 0x0 0x4000>;
 		interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
@@ -1188,6 +1188,7 @@
 		clock-names = "dp", "pclk";
 		phys = <&edp_phy>;
 		phy-names = "dp";
+		power-domains = <&power RK3288_PD_VIO>;
 		resets = <&cru SRST_EDP>;
 		reset-names = "dp";
 		rockchip,grf = <&grf>;
@@ -1575,7 +1576,7 @@
 			drive-strength = <12>;
 		};
 
-		sleep {
+		suspend {
 			global_pwroff: global-pwroff {
 				rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>;
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/rk3xxx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/rk3xxx.dtsi
@@ -84,7 +84,7 @@
 		compatible = "arm,mali-400";
 		reg = <0x10090000 0x10000>;
 		clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
-		clock-names = "core", "bus";
+		clock-names = "bus", "core";
 		assigned-clocks = <&cru ACLK_GPU>;
 		assigned-clock-rates = <100000000>;
 		resets = <&cru SRST_GPU>;
@@ -108,6 +108,13 @@
 		reg = <0x1013c200 0x20>;
 		interrupts = <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
 		clocks = <&cru CORE_PERI>;
+		status = "disabled";
+		/* The clock source and the sched_clock provided by the arm_global_timer
+		 * on Rockchip rk3066a/rk3188 are quite unstable because their rates
+		 * depend on the CPU frequency.
+		 * Keep the arm_global_timer disabled in order to have the
+		 * DW_APB_TIMER (rk3066a) or ROCKCHIP_TIMER (rk3188) selected by default.
+		 */
 	};
 
 	local_timer: local-timer@1013c600 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s3c6410-mini6410.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/s3c6410-mini6410.dts
@@ -28,29 +28,21 @@
 		bootargs = "console=ttySAC0,115200n8 earlyprintk rootwait root=/dev/mmcblk0p1";
 	};
 
-	clocks {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		fin_pll: oscillator@0 {
-			compatible = "fixed-clock";
-			reg = <0>;
-			clock-frequency = <12000000>;
-			clock-output-names = "fin_pll";
-			#clock-cells = <0>;
-		};
+	fin_pll: oscillator-0 {
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+		clock-output-names = "fin_pll";
+		#clock-cells = <0>;
+	};
 
-		xusbxti: oscillator@1 {
-			compatible = "fixed-clock";
-			reg = <1>;
-			clock-output-names = "xusbxti";
-			clock-frequency = <48000000>;
-			#clock-cells = <0>;
-		};
+	xusbxti: oscillator-1 {
+		compatible = "fixed-clock";
+		clock-output-names = "xusbxti";
+		clock-frequency = <48000000>;
+		#clock-cells = <0>;
 	};
 
-	srom-cs1@18000000 {
+	srom-cs1-bus@18000000 {
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -59,7 +51,7 @@
 
 		ethernet@18000000 {
 			compatible = "davicom,dm9000";
-			reg = <0x18000000 0x2 0x18000004 0x2>;
+			reg = <0x18000000 0x2>, <0x18000004 0x2>;
 			interrupt-parent = <&gpn>;
 			interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
 			davicom,no-eeprom;
@@ -165,6 +157,10 @@
 	};
 };
 
+&clocks {
+	clocks = <&fin_pll>;
+};
+
 &sdhci0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
@@ -197,12 +193,12 @@
 };
 
 &pinctrl0 {
-	gpio_leds: gpio-leds {
+	gpio_leds: gpio-leds-pins {
 		samsung,pins = "gpk-4", "gpk-5", "gpk-6", "gpk-7";
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	gpio_keys: gpio-keys {
+	gpio_keys: gpio-keys-pins {
 		samsung,pins = "gpn-0", "gpn-1", "gpn-2", "gpn-3",
 				"gpn-4", "gpn-5", "gpl-11", "gpl-12";
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s3c6410-smdk6410.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/s3c6410-smdk6410.dts
@@ -69,6 +69,10 @@
 	};
 };
 
+&clocks {
+	clocks = <&fin_pll>;
+};
+
 &sdhci0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
@@ -16,111 +16,111 @@
 	 * Pin banks
 	 */
 
-	gpa: gpa {
+	gpa: gpa-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpb: gpb {
+	gpb: gpb-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpc: gpc {
+	gpc: gpc-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpd: gpd {
+	gpd: gpd-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpe: gpe {
+	gpe: gpe-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 	};
 
-	gpf: gpf {
+	gpf: gpf-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpg: gpg {
+	gpg: gpg-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gph: gph {
+	gph: gph-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpi: gpi {
+	gpi: gpi-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 	};
 
-	gpj: gpj {
+	gpj: gpj-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 	};
 
-	gpk: gpk {
+	gpk: gpk-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 	};
 
-	gpl: gpl {
+	gpl: gpl-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpm: gpm {
+	gpm: gpm-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpn: gpn {
+	gpn: gpn-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpo: gpo {
+	gpo: gpo-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpp: gpp {
+	gpp: gpp-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
 
-	gpq: gpq {
+	gpq: gpq-gpio-bank {
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
@@ -131,225 +131,225 @@
 	 * Pin groups
 	 */
 
-	uart0_data: uart0-data {
+	uart0_data: uart0-data-pins {
 		samsung,pins = "gpa-0", "gpa-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	uart0_fctl: uart0-fctl {
+	uart0_fctl: uart0-fctl-pins {
 		samsung,pins = "gpa-2", "gpa-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	uart1_data: uart1-data {
+	uart1_data: uart1-data-pins {
 		samsung,pins = "gpa-4", "gpa-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	uart1_fctl: uart1-fctl {
+	uart1_fctl: uart1-fctl-pins {
 		samsung,pins = "gpa-6", "gpa-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	uart2_data: uart2-data {
+	uart2_data: uart2-data-pins {
 		samsung,pins = "gpb-0", "gpb-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	uart3_data: uart3-data {
+	uart3_data: uart3-data-pins {
 		samsung,pins = "gpb-2", "gpb-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	ext_dma_0: ext-dma-0 {
+	ext_dma_0: ext-dma-0-pins {
 		samsung,pins = "gpb-0", "gpb-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	ext_dma_1: ext-dma-1 {
+	ext_dma_1: ext-dma-1-pins {
 		samsung,pins = "gpb-2", "gpb-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	irda_data_0: irda-data-0 {
+	irda_data_0: irda-data-0-pins {
 		samsung,pins = "gpb-0", "gpb-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	irda_data_1: irda-data-1 {
+	irda_data_1: irda-data-1-pins {
 		samsung,pins = "gpb-2", "gpb-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	irda_sdbw: irda-sdbw {
+	irda_sdbw: irda-sdbw-pins {
 		samsung,pins = "gpb-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2c0_bus: i2c0-bus {
+	i2c0_bus: i2c0-bus-pins {
 		samsung,pins = "gpb-5", "gpb-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	i2c1_bus: i2c1-bus {
+	i2c1_bus: i2c1-bus-pins {
 		/* S3C6410-only */
 		samsung,pins = "gpb-2", "gpb-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_6>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	spi0_bus: spi0-bus {
+	spi0_bus: spi0-bus-pins {
 		samsung,pins = "gpc-0", "gpc-1", "gpc-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	spi0_cs: spi0-cs {
+	spi0_cs: spi0-cs-pins {
 		samsung,pins = "gpc-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	spi1_bus: spi1-bus {
+	spi1_bus: spi1-bus-pins {
 		samsung,pins = "gpc-4", "gpc-5", "gpc-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	spi1_cs: spi1-cs {
+	spi1_cs: spi1-cs-pins {
 		samsung,pins = "gpc-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd0_cmd: sd0-cmd {
+	sd0_cmd: sd0-cmd-pins {
 		samsung,pins = "gpg-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd0_clk: sd0-clk {
+	sd0_clk: sd0-clk-pins {
 		samsung,pins = "gpg-0";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd0_bus1: sd0-bus1 {
+	sd0_bus1: sd0-bus1-pins {
 		samsung,pins = "gpg-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd0_bus4: sd0-bus4 {
+	sd0_bus4: sd0-bus4-pins {
 		samsung,pins = "gpg-2", "gpg-3", "gpg-4", "gpg-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd0_cd: sd0-cd {
+	sd0_cd: sd0-cd-pins {
 		samsung,pins = "gpg-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	sd1_cmd: sd1-cmd {
+	sd1_cmd: sd1-cmd-pins {
 		samsung,pins = "gph-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd1_clk: sd1-clk {
+	sd1_clk: sd1-clk-pins {
 		samsung,pins = "gph-0";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd1_bus1: sd1-bus1 {
+	sd1_bus1: sd1-bus1-pins {
 		samsung,pins = "gph-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd1_bus4: sd1-bus4 {
+	sd1_bus4: sd1-bus4-pins {
 		samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd1_bus8: sd1-bus8 {
+	sd1_bus8: sd1-bus8-pins {
 		samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5",
 				"gph-6", "gph-7", "gph-8", "gph-9";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd1_cd: sd1-cd {
+	sd1_cd: sd1-cd-pins {
 		samsung,pins = "gpg-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
 	};
 
-	sd2_cmd: sd2-cmd {
+	sd2_cmd: sd2-cmd-pins {
 		samsung,pins = "gpc-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd2_clk: sd2-clk {
+	sd2_clk: sd2-clk-pins {
 		samsung,pins = "gpc-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd2_bus1: sd2-bus1 {
+	sd2_bus1: sd2-bus1-pins {
 		samsung,pins = "gph-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	sd2_bus4: sd2-bus4 {
+	sd2_bus4: sd2-bus4-pins {
 		samsung,pins = "gph-6", "gph-7", "gph-8", "gph-9";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s0_bus: i2s0-bus {
+	i2s0_bus: i2s0-bus-pins {
 		samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s0_cdclk: i2s0-cdclk {
+	i2s0_cdclk: i2s0-cdclk-pins {
 		samsung,pins = "gpd-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s1_bus: i2s1-bus {
+	i2s1_bus: i2s1-bus-pins {
 		samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s1_cdclk: i2s1-cdclk {
+	i2s1_cdclk: i2s1-cdclk-pins {
 		samsung,pins = "gpe-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s2_bus: i2s2-bus {
+	i2s2_bus: i2s2-bus-pins {
 		/* S3C6410-only */
 		samsung,pins = "gpc-4", "gpc-5", "gpc-6", "gph-6",
 				"gph-8", "gph-9";
@@ -357,50 +357,50 @@
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	i2s2_cdclk: i2s2-cdclk {
+	i2s2_cdclk: i2s2-cdclk-pins {
 		/* S3C6410-only */
 		samsung,pins = "gph-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pcm0_bus: pcm0-bus {
+	pcm0_bus: pcm0-bus-pins {
 		samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pcm0_extclk: pcm0-extclk {
+	pcm0_extclk: pcm0-extclk-pins {
 		samsung,pins = "gpd-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pcm1_bus: pcm1-bus {
+	pcm1_bus: pcm1-bus-pins {
 		samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pcm1_extclk: pcm1-extclk {
+	pcm1_extclk: pcm1-extclk-pins {
 		samsung,pins = "gpe-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	ac97_bus_0: ac97-bus-0 {
+	ac97_bus_0: ac97-bus-0-pins {
 		samsung,pins = "gpd-0", "gpd-1", "gpd-2", "gpd-3", "gpd-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	ac97_bus_1: ac97-bus-1 {
+	ac97_bus_1: ac97-bus-1-pins {
 		samsung,pins = "gpe-0", "gpe-1", "gpe-2", "gpe-3", "gpe-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	cam_port: cam-port {
+	cam_port: cam-port-pins {
 		samsung,pins = "gpf-0", "gpf-1", "gpf-2", "gpf-4",
 				"gpf-5", "gpf-6", "gpf-7", "gpf-8",
 				"gpf-9", "gpf-10", "gpf-11", "gpf-12";
@@ -408,242 +408,242 @@
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	cam_rst: cam-rst {
+	cam_rst: cam-rst-pins {
 		samsung,pins = "gpf-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	cam_field: cam-field {
+	cam_field: cam-field-pins {
 		/* S3C6410-only */
 		samsung,pins = "gpb-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pwm_extclk: pwm-extclk {
+	pwm_extclk: pwm-extclk-pins {
 		samsung,pins = "gpf-13";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pwm0_out: pwm0-out {
+	pwm0_out: pwm0-out-pins {
 		samsung,pins = "gpf-14";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	pwm1_out: pwm1-out {
+	pwm1_out: pwm1-out-pins {
 		samsung,pins = "gpf-15";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	clkout0: clkout-0 {
+	clkout0: clkout-0-pins {
 		samsung,pins = "gpf-14";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col0_0: keypad-col0-0 {
+	keypad_col0_0: keypad-col0-0-pins {
 		samsung,pins = "gph-0";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col1_0: keypad-col1-0 {
+	keypad_col1_0: keypad-col1-0-pins {
 		samsung,pins = "gph-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col2_0: keypad-col2-0 {
+	keypad_col2_0: keypad-col2-0-pins {
 		samsung,pins = "gph-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col3_0: keypad-col3-0 {
+	keypad_col3_0: keypad-col3-0-pins {
 		samsung,pins = "gph-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col4_0: keypad-col4-0 {
+	keypad_col4_0: keypad-col4-0-pins {
 		samsung,pins = "gph-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col5_0: keypad-col5-0 {
+	keypad_col5_0: keypad-col5-0-pins {
 		samsung,pins = "gph-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col6_0: keypad-col6-0 {
+	keypad_col6_0: keypad-col6-0-pins {
 		samsung,pins = "gph-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col7_0: keypad-col7-0 {
+	keypad_col7_0: keypad-col7-0-pins {
 		samsung,pins = "gph-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col0_1: keypad-col0-1 {
+	keypad_col0_1: keypad-col0-1-pins {
 		samsung,pins = "gpl-0";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col1_1: keypad-col1-1 {
+	keypad_col1_1: keypad-col1-1-pins {
 		samsung,pins = "gpl-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col2_1: keypad-col2-1 {
+	keypad_col2_1: keypad-col2-1-pins {
 		samsung,pins = "gpl-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col3_1: keypad-col3-1 {
+	keypad_col3_1: keypad-col3-1-pins {
 		samsung,pins = "gpl-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col4_1: keypad-col4-1 {
+	keypad_col4_1: keypad-col4-1-pins {
 		samsung,pins = "gpl-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col5_1: keypad-col5-1 {
+	keypad_col5_1: keypad-col5-1-pins {
 		samsung,pins = "gpl-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col6_1: keypad-col6-1 {
+	keypad_col6_1: keypad-col6-1-pins {
 		samsung,pins = "gpl-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_col7_1: keypad-col7-1 {
+	keypad_col7_1: keypad-col7-1-pins {
 		samsung,pins = "gpl-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row0_0: keypad-row0-0 {
+	keypad_row0_0: keypad-row0-0-pins {
 		samsung,pins = "gpk-8";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row1_0: keypad-row1-0 {
+	keypad_row1_0: keypad-row1-0-pins {
 		samsung,pins = "gpk-9";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row2_0: keypad-row2-0 {
+	keypad_row2_0: keypad-row2-0-pins {
 		samsung,pins = "gpk-10";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row3_0: keypad-row3-0 {
+	keypad_row3_0: keypad-row3-0-pins {
 		samsung,pins = "gpk-11";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row4_0: keypad-row4-0 {
+	keypad_row4_0: keypad-row4-0-pins {
 		samsung,pins = "gpk-12";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row5_0: keypad-row5-0 {
+	keypad_row5_0: keypad-row5-0-pins {
 		samsung,pins = "gpk-13";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row6_0: keypad-row6-0 {
+	keypad_row6_0: keypad-row6-0-pins {
 		samsung,pins = "gpk-14";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row7_0: keypad-row7-0 {
+	keypad_row7_0: keypad-row7-0-pins {
 		samsung,pins = "gpk-15";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row0_1: keypad-row0-1 {
+	keypad_row0_1: keypad-row0-1-pins {
 		samsung,pins = "gpn-0";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row1_1: keypad-row1-1 {
+	keypad_row1_1: keypad-row1-1-pins {
 		samsung,pins = "gpn-1";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row2_1: keypad-row2-1 {
+	keypad_row2_1: keypad-row2-1-pins {
 		samsung,pins = "gpn-2";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row3_1: keypad-row3-1 {
+	keypad_row3_1: keypad-row3-1-pins {
 		samsung,pins = "gpn-3";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row4_1: keypad-row4-1 {
+	keypad_row4_1: keypad-row4-1-pins {
 		samsung,pins = "gpn-4";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row5_1: keypad-row5-1 {
+	keypad_row5_1: keypad-row5-1-pins {
 		samsung,pins = "gpn-5";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row6_1: keypad-row6-1 {
+	keypad_row6_1: keypad-row6-1-pins {
 		samsung,pins = "gpn-6";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	keypad_row7_1: keypad-row7-1 {
+	keypad_row7_1: keypad-row7-1-pins {
 		samsung,pins = "gpn-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	lcd_ctrl: lcd-ctrl {
+	lcd_ctrl: lcd-ctrl-pins {
 		samsung,pins = "gpj-8", "gpj-9", "gpj-10", "gpj-11";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	lcd_data16: lcd-data-width16 {
+	lcd_data16: lcd-data-width16-pins {
 		samsung,pins = "gpi-3", "gpi-4", "gpi-5", "gpi-6",
 				"gpi-7", "gpi-10", "gpi-11", "gpi-12",
 				"gpi-13", "gpi-14", "gpi-15", "gpj-3",
@@ -652,7 +652,7 @@
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	lcd_data18: lcd-data-width18 {
+	lcd_data18: lcd-data-width18-pins {
 		samsung,pins = "gpi-2", "gpi-3", "gpi-4", "gpi-5",
 				"gpi-6", "gpi-7", "gpi-10", "gpi-11",
 				"gpi-12", "gpi-13", "gpi-14", "gpi-15",
@@ -662,7 +662,7 @@
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	lcd_data24: lcd-data-width24 {
+	lcd_data24: lcd-data-width24-pins {
 		samsung,pins = "gpi-0", "gpi-1", "gpi-2", "gpi-3",
 				"gpi-4", "gpi-5", "gpi-6", "gpi-7",
 				"gpi-8", "gpi-9", "gpi-10", "gpi-11",
@@ -673,7 +673,7 @@
 		samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
 	};
 
-	hsi_bus: hsi-bus {
+	hsi_bus: hsi-bus-pins {
 		samsung,pins = "gpk-0", "gpk-1", "gpk-2", "gpk-3",
 				"gpk-4", "gpk-5", "gpk-6", "gpk-7";
 		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s5pv210-aries.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/s5pv210-aries.dtsi
@@ -454,6 +454,7 @@
 	pinctrl-names = "default";
 	cap-sd-highspeed;
 	cap-mmc-highspeed;
+	keep-power-in-suspend;
 
 	mmc-pwrseq = <&wifi_pwrseq>;
 	non-removable;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s5pv210-smdkv210.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/s5pv210-smdkv210.dts
@@ -15,6 +15,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/input/input.h>
 #include "s5pv210.dtsi"
 
@@ -31,11 +32,18 @@
 		reg = <0x20000000 0x40000000>;
 	};
 
-	ethernet@18000000 {
+	pmic_ap_clk: clock-0 {
+		/* Workaround for missing PMIC and its clock */
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+	};
+
+	ethernet@a8000000 {
 		compatible = "davicom,dm9000";
-		reg = <0xA8000000 0x2 0xA8000002 0x2>;
+		reg = <0xa8000000 0x2>, <0xa8000002 0x2>;
 		interrupt-parent = <&gph1>;
-		interrupts = <1 4>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
 		local-mac-address = [00 00 de ad be ef];
 		davicom,no-eeprom;
 	};
@@ -47,6 +55,14 @@
 		default-brightness-level = <6>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pwm3_out>;
+		power-supply = <&dc5v_reg>;
+	};
+
+	dc5v_reg: regulator-0 {
+		compatible = "regulator-fixed";
+		regulator-name = "DC5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
 	};
 };
 
@@ -147,6 +163,8 @@
 
 &rtc {
 	status = "okay";
+	clocks = <&clocks CLK_RTC>, <&pmic_ap_clk>;
+	clock-names = "rtc", "rtc_src";
 };
 
 &sdhci0 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/s5pv210.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/s5pv210.dtsi
@@ -52,34 +52,26 @@
 		};
 	};
 
+	xxti: oscillator-0 {
+		compatible = "fixed-clock";
+		clock-frequency = <0>;
+		clock-output-names = "xxti";
+		#clock-cells = <0>;
+	};
+
+	xusbxti: oscillator-1 {
+		compatible = "fixed-clock";
+		clock-frequency = <0>;
+		clock-output-names = "xusbxti";
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
 
-		external-clocks {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			xxti: oscillator@0 {
-				compatible = "fixed-clock";
-				reg = <0>;
-				clock-frequency = <0>;
-				clock-output-names = "xxti";
-				#clock-cells = <0>;
-			};
-
-			xusbxti: oscillator@1 {
-				compatible = "fixed-clock";
-				reg = <1>;
-				clock-frequency = <0>;
-				clock-output-names = "xusbxti";
-				#clock-cells = <0>;
-			};
-		};
-
 		onenand: onenand@b0600000 {
 			compatible = "samsung,s5pv210-onenand";
 			reg = <0xb0600000 0x2000>,
@@ -100,19 +92,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 {
@@ -128,35 +117,28 @@
 			};
 		};
 
-		amba {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "simple-bus";
-			ranges;
-
-			pdma0: dma@e0900000 {
-				compatible = "arm,pl330", "arm,primecell";
-				reg = <0xe0900000 0x1000>;
-				interrupt-parent = <&vic0>;
-				interrupts = <19>;
-				clocks = <&clocks CLK_PDMA0>;
-				clock-names = "apb_pclk";
-				#dma-cells = <1>;
-				#dma-channels = <8>;
-				#dma-requests = <32>;
-			};
+		pdma0: dma@e0900000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0xe0900000 0x1000>;
+			interrupt-parent = <&vic0>;
+			interrupts = <19>;
+			clocks = <&clocks CLK_PDMA0>;
+			clock-names = "apb_pclk";
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
+		};
 
-			pdma1: dma@e0a00000 {
-				compatible = "arm,pl330", "arm,primecell";
-				reg = <0xe0a00000 0x1000>;
-				interrupt-parent = <&vic0>;
-				interrupts = <20>;
-				clocks = <&clocks CLK_PDMA1>;
-				clock-names = "apb_pclk";
-				#dma-cells = <1>;
-				#dma-channels = <8>;
-				#dma-requests = <32>;
-			};
+		pdma1: dma@e0a00000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0xe0a00000 0x1000>;
+			interrupt-parent = <&vic0>;
+			interrupts = <20>;
+			clocks = <&clocks CLK_PDMA1>;
+			clock-names = "apb_pclk";
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
 		};
 
 		spi0: spi@e1300000 {
@@ -229,43 +211,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 {
@@ -596,7 +571,7 @@
 				interrupts = <29>;
 				clocks = <&clocks CLK_CSIS>,
 						<&clocks SCLK_CSIS>;
-				clock-names = "clk_csis",
+				clock-names = "csis",
 						"sclk_csis";
 				bus-width = <4>;
 				status = "disabled";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sama5d2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d2.dtsi
@@ -526,7 +526,7 @@
 				pmecc: ecc-engine@f8014070 {
 					compatible = "atmel,sama5d2-pmecc";
 					reg = <0xf8014070 0x490>,
-					      <0xf8014500 0x100>;
+					      <0xf8014500 0x200>;
 				};
 			};
 
@@ -648,6 +648,7 @@
 				clocks = <&pmc PMC_TYPE_PERIPHERAL 51>;
 				#address-cells = <1>;
 				#size-cells = <1>;
+				no-memory-wc;
 				ranges = <0 0xf8044000 0x1420>;
 			};
 
@@ -716,7 +717,7 @@
 
 			can0: can@f8054000 {
 				compatible = "bosch,m_can";
-				reg = <0xf8054000 0x4000>, <0x210000 0x4000>;
+				reg = <0xf8054000 0x4000>, <0x210000 0x1c00>;
 				reg-names = "m_can", "message_ram";
 				interrupts = <56 IRQ_TYPE_LEVEL_HIGH 7>,
 					     <64 IRQ_TYPE_LEVEL_HIGH 7>;
@@ -932,13 +933,13 @@
 				clocks = <&pmc PMC_TYPE_PERIPHERAL 55>, <&pmc PMC_TYPE_GCK 55>;
 				clock-names = "pclk", "gclk";
 				assigned-clocks = <&pmc PMC_TYPE_CORE PMC_I2S1_MUX>;
-				assigned-parrents = <&pmc PMC_TYPE_GCK 55>;
+				assigned-clock-parents = <&pmc PMC_TYPE_GCK 55>;
 				status = "disabled";
 			};
 
 			can1: can@fc050000 {
 				compatible = "bosch,m_can";
-				reg = <0xfc050000 0x4000>, <0x210000 0x4000>;
+				reg = <0xfc050000 0x4000>, <0x210000 0x3800>;
 				reg-names = "m_can", "message_ram";
 				interrupts = <57 IRQ_TYPE_LEVEL_HIGH 7>,
 					     <65 IRQ_TYPE_LEVEL_HIGH 7>;
@@ -948,7 +949,7 @@
 				assigned-clocks = <&pmc PMC_TYPE_GCK 57>;
 				assigned-clock-parents = <&pmc PMC_TYPE_CORE PMC_UTMI>;
 				assigned-clock-rates = <40000000>;
-				bosch,mram-cfg = <0x1100 0 0 64 0 0 32 32>;
+				bosch,mram-cfg = <0x1c00 0 0 64 0 0 32 32>;
 				status = "disabled";
 			};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sama5d3.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d3.dtsi
@@ -1188,49 +1188,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 {
@@ -1246,19 +1246,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 {
@@ -1269,7 +1269,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 {
@@ -1300,13 +1300,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-ein-5.4.0.orig/arch/arm/boot/dts/sama5d3_can.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d3_can.dtsi
@@ -36,13 +36,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-ein-5.4.0.orig/arch/arm/boot/dts/sama5d3_tcb1.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d3_tcb1.dtsi
@@ -22,6 +22,7 @@
 					tcb1_clk: tcb1_clk {
 						#clock-cells = <0>;
 						reg = <27>;
+						atmel,clk-output-range = <0 166000000>;
 					};
 				};
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sama5d3_uart.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d3_uart.dtsi
@@ -41,13 +41,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-ein-5.4.0.orig/arch/arm/boot/dts/sama5d4.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sama5d4.dtsi
@@ -914,7 +914,7 @@
 					0xffffffff 0x3ffcfe7c 0x1c010101	/* pioA */
 					0x7fffffff 0xfffccc3a 0x3f00cc3a	/* pioB */
 					0xffffffff 0x3ff83fff 0xff00ffff	/* pioC */
-					0x0003ff00 0x8002a800 0x00000000	/* pioD */
+					0xb003ff00 0x8002a800 0x00000000	/* pioD */
 					0xffffffff 0x7fffffff 0x76fff1bf	/* pioE */
 					>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga.dtsi
@@ -710,7 +710,7 @@
 			};
 		};
 
-		L2: l2-cache@fffef000 {
+		L2: cache-controller@fffef000 {
 			compatible = "arm,pl310-cache";
 			reg = <0xfffef000 0x1000>;
 			interrupts = <0 38 0x04>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -636,7 +636,7 @@
 			reg = <0xffcfb100 0x80>;
 		};
 
-		L2: l2-cache@fffff000 {
+		L2: cache-controller@fffff000 {
 			compatible = "arm,pl310-cache";
 			reg = <0xfffff000 0x1000>;
 			interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
@@ -819,7 +819,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";
 			resets = <&rst L4SYSTIMER1_RESET>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
@@ -12,7 +12,7 @@
 	flash0: n25q00@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q00aa";
+		compatible = "micron,mt25qu02g", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <100000000>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_arria5_socdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_arria5_socdk.dts
@@ -119,7 +119,7 @@
 	flash: flash@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q256a";
+		compatible = "micron,n25q256a", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <100000000>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -124,7 +124,7 @@
 	flash0: n25q00@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q00";
+		compatible = "micron,mt25qu02g", "jedec,spi-nor";
 		reg = <0>;	/* chip select */
 		spi-max-frequency = <100000000>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
@@ -169,7 +169,7 @@
 	flash: flash@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q00";
+		compatible = "micron,mt25qu02g", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <100000000>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
@@ -80,7 +80,7 @@
 	flash: flash@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q256a";
+		compatible = "micron,n25q256a", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <100000000>;
 		m25p,fast-read;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
@@ -116,7 +116,7 @@
 	flash0: n25q512a@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q512a";
+		compatible = "micron,n25q512a", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <100000000>;
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
@@ -224,7 +224,7 @@
 	n25q128@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q128";
+		compatible = "micron,n25q128", "jedec,spi-nor";
 		reg = <0>;		/* chip select */
 		spi-max-frequency = <100000000>;
 		m25p,fast-read;
@@ -241,7 +241,7 @@
 	n25q00@1 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "n25q00";
+		compatible = "micron,mt25qu02g", "jedec,spi-nor";
 		reg = <1>;		/* chip select */
 		spi-max-frequency = <100000000>;
 		m25p,fast-read;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/spear1340.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/spear1340.dtsi
@@ -136,9 +136,9 @@
 				reg = <0xb4100000 0x1000>;
 				interrupts = <0 105 0x4>;
 				status = "disabled";
-				dmas = <&dwdma0 12 0 1>,
-					<&dwdma0 13 1 0>;
-				dma-names = "tx", "rx";
+				dmas = <&dwdma0 13 0 1>,
+					<&dwdma0 12 1 0>;
+				dma-names = "rx", "tx";
 			};
 
 			thermal@e07008c4 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/spear13xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/spear13xx.dtsi
@@ -284,9 +284,9 @@
 				#size-cells = <0>;
 				interrupts = <0 31 0x4>;
 				status = "disabled";
-				dmas = <&dwdma0 4 0 0>,
-					<&dwdma0 5 0 0>;
-				dma-names = "tx", "rx";
+				dmas = <&dwdma0 5 0 0>,
+					<&dwdma0 4 0 0>;
+				dma-names = "rx", "tx";
 			};
 
 			rtc@e0580000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/spear320-hmi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/spear320-hmi.dts
@@ -242,7 +242,7 @@
 					irq-trigger = <0x1>;
 
 					stmpegpio: stmpe-gpio {
-						compatible = "stmpe,gpio";
+						compatible = "st,stmpe-gpio";
 						reg = <0>;
 						gpio-controller;
 						#gpio-cells = <2>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/spear3xx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/spear3xx.dtsi
@@ -47,7 +47,7 @@
 		};
 
 		gmac: eth@e0800000 {
-			compatible = "st,spear600-gmac";
+			compatible = "snps,dwmac-3.40a";
 			reg = <0xe0800000 0x8000>;
 			interrupts = <23 22>;
 			interrupt-names = "macirq", "eth_wake_irq";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/spear600.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/spear600.dtsi
@@ -47,7 +47,7 @@
 			compatible = "arm,pl110", "arm,primecell";
 			reg = <0xfc200000 0x1000>;
 			interrupt-parent = <&vic1>;
-			interrupts = <12>;
+			interrupts = <13>;
 			status = "disabled";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -755,14 +755,14 @@
 			status = "disabled";
 		};
 
-		vica: intc@10140000 {
+		vica: interrupt-controller@10140000 {
 			compatible = "arm,versatile-vic";
 			interrupt-controller;
 			#interrupt-cells = <1>;
 			reg = <0x10140000 0x20>;
 		};
 
-		vicb: intc@10140020 {
+		vicb: interrupt-controller@10140020 {
 			compatible = "arm,versatile-vic";
 			interrupt-controller;
 			#interrupt-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -46,7 +46,7 @@
 			/* DAC */
 			format = "i2s";
 			mclk-fs = <256>;
-			frame-inversion = <1>;
+			frame-inversion;
 			cpu {
 				sound-dai = <&sti_uni_player2>;
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32429i-eval.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32429i-eval.dts
@@ -112,17 +112,15 @@
 		};
 	};
 
-	gpio_keys {
+	gpio-keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		autorepeat;
-		button@0 {
+		button-0 {
 			label = "Wake up";
 			linux,code = <KEY_WAKEUP>;
 			gpios = <&gpioa 0 0>;
 		};
-		button@1 {
+		button-1 {
 			label = "Tamper";
 			linux,code = <KEY_RESTART>;
 			gpios = <&gpioc 13 0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32746g-eval.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32746g-eval.dts
@@ -81,12 +81,10 @@
 		};
 	};
 
-	gpio_keys {
+	gpio-keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		autorepeat;
-		button@0 {
+		button-0 {
 			label = "Wake up";
 			linux,code = <KEY_WAKEUP>;
 			gpios = <&gpioc 13 0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f429-disco.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f429-disco.dts
@@ -79,12 +79,10 @@
 		};
 	};
 
-	gpio_keys {
+	gpio-keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		autorepeat;
-		button@0 {
+		button-0 {
 			label = "User";
 			linux,code = <KEY_HOME>;
 			gpios = <&gpioa 0 0>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f429.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f429.dtsi
@@ -283,8 +283,6 @@
 		};
 
 		timers13: timers@40001c00 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40001C00 0x400>;
 			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM13)>;
@@ -299,8 +297,6 @@
 		};
 
 		timers14: timers@40002000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40002000 0x400>;
 			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM14)>;
@@ -623,8 +619,6 @@
 		};
 
 		timers10: timers@40014400 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40014400 0x400>;
 			clocks = <&rcc 0 STM32F4_APB2_CLOCK(TIM10)>;
@@ -639,8 +633,6 @@
 		};
 
 		timers11: timers@40014800 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40014800 0x400>;
 			clocks = <&rcc 0 STM32F4_APB2_CLOCK(TIM11)>;
@@ -696,7 +688,7 @@
 			status = "disabled";
 		};
 
-		rcc: rcc@40023810 {
+		rcc: rcc@40023800 {
 			#reset-cells = <1>;
 			#clock-cells = <2>;
 			compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f469-disco.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f469-disco.dts
@@ -76,6 +76,13 @@
 		regulator-max-microvolt = <3300000>;
 	};
 
+	vdd_dsi: vdd-dsi {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_dsi";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
 	soc {
 		dma-ranges = <0xc0000000 0x0 0x10000000>;
 	};
@@ -97,12 +104,10 @@
 		};
 	};
 
-	gpio_keys {
+	gpio-keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		autorepeat;
-		button@0 {
+		button-0 {
 			label = "User";
 			linux,code = <KEY_WAKEUP>;
 			gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>;
@@ -155,6 +160,7 @@
 		compatible = "orisetech,otm8009a";
 		reg = <0>; /* dsi virtual channel (0..3) */
 		reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>;
+		power-supply = <&vdd_dsi>;
 		status = "okay";
 
 		port {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f7-pinctrl.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f7-pinctrl.dtsi
@@ -284,6 +284,88 @@
 					slew-rate = <2>;
 				};
 			};
+
+			can1_pins_a: can1-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('A', 12, AF9)>; /* CAN1_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('A', 11, AF9)>; /* CAN1_RX */
+					bias-pull-up;
+				};
+			};
+
+			can1_pins_b: can1-1 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 9, AF9)>; /* CAN1_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 8, AF9)>; /* CAN1_RX */
+					bias-pull-up;
+				};
+			};
+
+			can1_pins_c: can1-2 {
+				pins1 {
+					pinmux = <STM32_PINMUX('D', 1, AF9)>; /* CAN1_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('D', 0, AF9)>; /* CAN1_RX */
+					bias-pull-up;
+
+				};
+			};
+
+			can1_pins_d: can1-3 {
+				pins1 {
+					pinmux = <STM32_PINMUX('H', 13, AF9)>; /* CAN1_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('H', 14, AF9)>; /* CAN1_RX */
+					bias-pull-up;
+
+				};
+			};
+
+			can2_pins_a: can2-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 6, AF9)>; /* CAN2_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 5, AF9)>; /* CAN2_RX */
+					bias-pull-up;
+				};
+			};
+
+			can2_pins_b: can2-1 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 13, AF9)>; /* CAN2_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 12, AF9)>; /* CAN2_RX */
+					bias-pull-up;
+				};
+			};
+
+			can3_pins_a: can3-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('A', 15, AF11)>; /* CAN3_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('A', 8, AF11)>; /* CAN3_RX */
+					bias-pull-up;
+				};
+			};
+
+			can3_pins_b: can3-1 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 4, AF11)>;  /* CAN3_TX */
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 3, AF11)>; /* CAN3_RX */
+					bias-pull-up;
+				};
+			};
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f746.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f746.dtsi
@@ -265,8 +265,6 @@
 		};
 
 		timers13: timers@40001c00 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40001C00 0x400>;
 			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM13)>;
@@ -281,8 +279,6 @@
 		};
 
 		timers14: timers@40002000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40002000 0x400>;
 			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM14)>;
@@ -366,9 +362,9 @@
 			status = "disabled";
 		};
 
-		i2c3: i2c@40005C00 {
+		i2c3: i2c@40005c00 {
 			compatible = "st,stm32f7-i2c";
-			reg = <0x40005C00 0x400>;
+			reg = <0x40005c00 0x400>;
 			interrupts = <72>,
 				     <73>;
 			resets = <&rcc STM32F7_APB1_RESET(I2C3)>;
@@ -533,8 +529,6 @@
 		};
 
 		timers10: timers@40014400 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40014400 0x400>;
 			clocks = <&rcc 0 STM32F7_APB2_CLOCK(TIM10)>;
@@ -549,8 +543,6 @@
 		};
 
 		timers11: timers@40014800 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-timers";
 			reg = <0x40014800 0x400>;
 			clocks = <&rcc 0 STM32F7_APB2_CLOCK(TIM11)>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32f769-disco.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32f769-disco.dts
@@ -75,12 +75,10 @@
 		};
 	};
 
-	gpio_keys {
+	gpio-keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		autorepeat;
-		button@0 {
+		button-0 {
 			label = "User";
 			linux,code = <KEY_HOME>;
 			gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32h743.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32h743.dtsi
@@ -438,8 +438,6 @@
 		};
 
 		lptimer4: timer@58002c00 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-lptimer";
 			reg = <0x58002c00 0x400>;
 			clocks = <&rcc LPTIM4_CK>;
@@ -454,8 +452,6 @@
 		};
 
 		lptimer5: timer@58003000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
 			compatible = "st,stm32-lptimer";
 			reg = <0x58003000 0x400>;
 			clocks = <&rcc LPTIM5_CK>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32mp157a-avenger96.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32mp157a-avenger96.dts
@@ -91,6 +91,9 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "snps,dwmac-mdio";
+		reset-gpios = <&gpioz 2 GPIO_ACTIVE_LOW>;
+		reset-delay-us = <1000>;
+
 		phy0: ethernet-phy@7 {
 			reg = <7>;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/stm32mp157c.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -515,7 +515,7 @@
 			compatible = "st,stm32-cec";
 			reg = <0x40016000 0x400>;
 			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&rcc CEC_K>, <&clk_lse>;
+			clocks = <&rcc CEC_K>, <&rcc CEC>;
 			clock-names = "cec", "hdmi-cec";
 			status = "disabled";
 		};
@@ -773,7 +773,7 @@
 				#sound-dai-cells = <0>;
 
 				compatible = "st,stm32-sai-sub-a";
-				reg = <0x4 0x1c>;
+				reg = <0x4 0x20>;
 				clocks = <&rcc SAI1_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 87 0x400 0x01>;
@@ -783,7 +783,7 @@
 			sai1b: audio-controller@4400a024 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-b";
-				reg = <0x24 0x1c>;
+				reg = <0x24 0x20>;
 				clocks = <&rcc SAI1_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 88 0x400 0x01>;
@@ -804,7 +804,7 @@
 			sai2a: audio-controller@4400b004 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-a";
-				reg = <0x4 0x1c>;
+				reg = <0x4 0x20>;
 				clocks = <&rcc SAI2_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 89 0x400 0x01>;
@@ -814,7 +814,7 @@
 			sai2b: audio-controller@4400b024 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-b";
-				reg = <0x24 0x1c>;
+				reg = <0x24 0x20>;
 				clocks = <&rcc SAI2_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 90 0x400 0x01>;
@@ -835,7 +835,7 @@
 			sai3a: audio-controller@4400c004 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-a";
-				reg = <0x04 0x1c>;
+				reg = <0x04 0x20>;
 				clocks = <&rcc SAI3_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 113 0x400 0x01>;
@@ -845,7 +845,7 @@
 			sai3b: audio-controller@4400c024 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-b";
-				reg = <0x24 0x1c>;
+				reg = <0x24 0x20>;
 				clocks = <&rcc SAI3_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 114 0x400 0x01>;
@@ -1191,7 +1191,7 @@
 			sai4a: audio-controller@50027004 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-a";
-				reg = <0x04 0x1c>;
+				reg = <0x04 0x20>;
 				clocks = <&rcc SAI4_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 99 0x400 0x01>;
@@ -1201,7 +1201,7 @@
 			sai4b: audio-controller@50027024 {
 				#sound-dai-cells = <0>;
 				compatible = "st,stm32-sai-sub-b";
-				reg = <0x24 0x1c>;
+				reg = <0x24 0x20>;
 				clocks = <&rcc SAI4_K>;
 				clock-names = "sai_ck";
 				dmas = <&dmamux1 100 0x400 0x01>;
@@ -1311,12 +1311,6 @@
 			status = "disabled";
 		};
 
-		stmmac_axi_config_0: stmmac-axi-config {
-			snps,wr_osr_lmt = <0x7>;
-			snps,rd_osr_lmt = <0x7>;
-			snps,blen = <0 0 0 0 16 8 4>;
-		};
-
 		ethernet0: ethernet@5800a000 {
 			compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
 			reg = <0x5800a000 0x2000>;
@@ -1339,6 +1333,12 @@
 			snps,axi-config = <&stmmac_axi_config_0>;
 			snps,tso;
 			status = "disabled";
+
+			stmmac_axi_config_0: stmmac-axi-config {
+				snps,wr_osr_lmt = <0x7>;
+				snps,rd_osr_lmt = <0x7>;
+				snps,blen = <0 0 0 0 16 8 4>;
+			};
 		};
 
 		usbh_ohci: usbh-ohci@5800c000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun4i-a10.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -143,7 +143,7 @@
 			trips {
 				cpu_alert0: cpu-alert0 {
 					/* milliCelsius */
-					temperature = <850000>;
+					temperature = <85000>;
 					hysteresis = <2000>;
 					type = "passive";
 				};
@@ -198,7 +198,7 @@
 		default-pool {
 			compatible = "shared-dma-pool";
 			size = <0x6000000>;
-			alloc-ranges = <0x4a000000 0x6000000>;
+			alloc-ranges = <0x40000000 0x10000000>;
 			reusable;
 			linux,cma-default;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun5i.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun5i.dtsi
@@ -117,7 +117,7 @@
 		default-pool {
 			compatible = "shared-dma-pool";
 			size = <0x6000000>;
-			alloc-ranges = <0x4a000000 0x6000000>;
+			alloc-ranges = <0x40000000 0x10000000>;
 			reusable;
 			linux,cma-default;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -154,7 +154,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts
@@ -130,7 +130,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_gmac_3v3>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -132,7 +132,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_gmac_3v3>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-bananapro.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -110,7 +110,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_gmac_3v3>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -151,7 +151,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -112,7 +112,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Adam Sampson <ats@offog.org>
+ * Copyright 2015-2020 Adam Sampson <ats@offog.org>
  *
  * 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
@@ -115,7 +115,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun7i-a20.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -180,7 +180,7 @@
 		default-pool {
 			compatible = "shared-dma-pool";
 			size = <0x6000000>;
-			alloc-ranges = <0x4a000000 0x6000000>;
+			alloc-ranges = <0x40000000 0x10000000>;
 			reusable;
 			linux,cma-default;
 		};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -131,7 +131,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_sw>;
 	phy-handle = <&rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	allwinner,rx-delay-ps = <700>;
 	allwinner,tx-delay-ps = <700>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
@@ -101,7 +101,7 @@
 		initial-mode = <1>; /* initialize in HUB mode */
 		disabled-ports = <1>;
 		intn-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
-		reset-gpios = <&pio 4 16 GPIO_ACTIVE_HIGH>; /* PE16 */
+		reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */
 		connect-gpios = <&pio 4 17 GPIO_ACTIVE_HIGH>; /* PE17 */
 		refclk-frequency = <19200000>;
 	};
@@ -183,7 +183,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_dldo4>;
 	phy-handle = <&rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
@@ -358,8 +358,8 @@
 };
 
 &reg_dldo3 {
-	regulator-min-microvolt = <2800000>;
-	regulator-max-microvolt = <2800000>;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
 	regulator-name = "vdd-csi";
 };
 
@@ -482,7 +482,8 @@
 };
 
 &usbphy {
-	usb0_id_det-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+	usb0_id_det-gpios = <&pio 7 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH11 */
+	usb0_vbus_power-supply = <&usb_power_supply>;
 	usb0_vbus-supply = <&reg_drivevbus>;
 	usb1_vbus-supply = <&reg_vmain>;
 	usb2_vbus-supply = <&reg_vmain>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -313,7 +313,7 @@
 
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-a83t-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_PLL_DE>;
 			clock-names = "bus",
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -31,7 +31,7 @@
 
 		pwr_led {
 			label = "bananapi-m2-zero:red:pwr";
-			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_LOW>; /* PL10 */
 			default-state = "on";
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
@@ -169,7 +169,7 @@
 	flash@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+		compatible = "mxicy,mx25l1606e", "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <40000000>;
 	};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
@@ -53,11 +53,6 @@
 	};
 };
 
-&emac {
-	/* LEDs changed to active high on the plus */
-	/delete-property/ allwinner,leds-active-low;
-};
-
 &mmc1 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
@@ -67,7 +67,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-h3.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -80,7 +80,7 @@
 			#cooling-cells = <2>;
 		};
 
-		cpu@1 {
+		cpu1: cpu@1 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <1>;
@@ -90,7 +90,7 @@
 			#cooling-cells = <2>;
 		};
 
-		cpu@2 {
+		cpu2: cpu@2 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <2>;
@@ -100,7 +100,7 @@
 			#cooling-cells = <2>;
 		};
 
-		cpu@3 {
+		cpu3: cpu@3 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <3>;
@@ -111,6 +111,15 @@
 		};
 	};
 
+	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>,
+			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -129,7 +129,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_dc1sw>;
 	status = "okay";
 };
@@ -223,16 +223,16 @@
 };
 
 &reg_dc1sw {
-	regulator-min-microvolt = <3000000>;
-	regulator-max-microvolt = <3000000>;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
 	regulator-name = "vcc-gmac-phy";
 };
 
 &reg_dcdc1 {
 	regulator-always-on;
-	regulator-min-microvolt = <3000000>;
-	regulator-max-microvolt = <3000000>;
-	regulator-name = "vcc-3v0";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-3v3";
 };
 
 &reg_dcdc2 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-r40.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -118,7 +118,7 @@
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-r40-de2-clk",
 				     "allwinner,sun8i-h3-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
@@ -266,6 +266,16 @@
 			#phy-cells = <1>;
 		};
 
+		ahci: sata@1c18000 {
+			compatible = "allwinner,sun8i-r40-ahci";
+			reg = <0x01c18000 0x1000>;
+			interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SATA>, <&ccu CLK_SATA>;
+			resets = <&ccu RST_BUS_SATA>;
+			reset-names = "ahci";
+			status = "disabled";
+		};
+
 		ehci1: usb@1c19000 {
 			compatible = "allwinner,sun8i-r40-ehci", "generic-ehci";
 			reg = <0x01c19000 0x100>;
@@ -557,17 +567,6 @@
 			#size-cells = <0>;
 		};
 
-		ahci: sata@1c18000 {
-			compatible = "allwinner,sun8i-r40-ahci";
-			reg = <0x01c18000 0x1000>;
-			interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&ccu CLK_BUS_SATA>, <&ccu CLK_SATA>;
-			resets = <&ccu RST_BUS_SATA>;
-			reset-names = "ahci";
-			status = "disabled";
-
-		};
-
 		gmac: ethernet@1c50000 {
 			compatible = "allwinner,sun8i-r40-gmac";
 			syscon = <&ccu>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -105,7 +105,7 @@
 
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-v3s-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
@@ -423,7 +423,7 @@
 		gic: interrupt-controller@1c81000 {
 			compatible = "arm,gic-400";
 			reg = <0x01c81000 0x1000>,
-			      <0x01c82000 0x1000>,
+			      <0x01c82000 0x2000>,
 			      <0x01c84000 0x2000>,
 			      <0x01c86000 0x2000>;
 			interrupt-controller;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
@@ -120,7 +120,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_dc1sw>;
 	status = "okay";
 };
@@ -198,16 +198,16 @@
 };
 
 &reg_dc1sw {
-	regulator-min-microvolt = <3000000>;
-	regulator-max-microvolt = <3000000>;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
 	regulator-name = "vcc-gmac-phy";
 };
 
 &reg_dcdc1 {
 	regulator-always-on;
-	regulator-min-microvolt = <3000000>;
-	regulator-max-microvolt = <3000000>;
-	regulator-name = "vcc-3v0";
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-3v3";
 };
 
 &reg_dcdc2 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -129,7 +129,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_cldo1>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -124,7 +124,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac_rgmii_pins>;
 	phy-handle = <&phy1>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-supply = <&reg_cldo1>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/suniv-f1c100s.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/suniv-f1c100s.dtsi
@@ -104,8 +104,10 @@
 
 		wdt: watchdog@1c20ca0 {
 			compatible = "allwinner,suniv-f1c100s-wdt",
-				     "allwinner,sun4i-a10-wdt";
+				     "allwinner,sun6i-a31-wdt";
 			reg = <0x01c20ca0 0x20>;
+			interrupts = <16>;
+			clocks = <&osc32k>;
 		};
 
 		uart0: serial@1c25000 {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sunxi-bananapi-m2-plus-v1.2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sunxi-bananapi-m2-plus-v1.2.dtsi
@@ -16,15 +16,27 @@
 		regulator-type = "voltage";
 		regulator-boot-on;
 		regulator-always-on;
-		regulator-min-microvolt = <1100000>;
-		regulator-max-microvolt = <1300000>;
+		regulator-min-microvolt = <1108475>;
+		regulator-max-microvolt = <1308475>;
 		regulator-ramp-delay = <50>; /* 4ms */
 		gpios = <&r_pio 0 1 GPIO_ACTIVE_HIGH>; /* PL1 */
 		gpios-states = <0x1>;
-		states = <1100000 0>, <1300000 1>;
+		states = <1108475 0>, <1308475 1>;
 	};
 };
 
 &cpu0 {
 	cpu-supply = <&reg_vdd_cpux>;
 };
+
+&cpu1 {
+	cpu-supply = <&reg_vdd_cpux>;
+};
+
+&cpu2 {
+	cpu-supply = <&reg_vdd_cpux>;
+};
+
+&cpu3 {
+	cpu-supply = <&reg_vdd_cpux>;
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
@@ -126,7 +126,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -113,7 +113,7 @@
 
 		display_clocks: clock@1000000 {
 			/* compatible is in per SoC .dtsi file */
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/tegra20-tamonten.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/tegra20-tamonten.dtsi
@@ -183,10 +183,11 @@
 			};
 			conf_ata {
 				nvidia,pins = "ata", "atb", "atc", "atd", "ate",
-					"cdev1", "cdev2", "dap1", "dtb", "gma",
-					"gmb", "gmc", "gmd", "gme", "gpu7",
-					"gpv", "i2cp", "pta", "rm", "slxa",
-					"slxk", "spia", "spib", "uac";
+					"cdev1", "cdev2", "dap1", "dtb", "dtf",
+					"gma", "gmb", "gmc", "gmd", "gme", "gpu7",
+					"gpv", "i2cp", "irrx", "irtx", "pta",
+					"rm", "slxa", "slxk", "spia", "spib",
+					"uac";
 				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
 				nvidia,tristate = <TEGRA_PIN_DISABLE>;
 			};
@@ -202,7 +203,7 @@
 			};
 			conf_crtp {
 				nvidia,pins = "crtp", "dap2", "dap3", "dap4",
-					"dtc", "dte", "dtf", "gpu", "sdio1",
+					"dtc", "dte", "gpu", "sdio1",
 					"slxc", "slxd", "spdi", "spdo", "spig",
 					"uda";
 				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
@@ -211,7 +212,7 @@
 			conf_ddc {
 				nvidia,pins = "ddc", "dta", "dtd", "kbca",
 					"kbcb", "kbcc", "kbcd", "kbce", "kbcf",
-					"sdc";
+					"sdc", "uad", "uca";
 				nvidia,pull = <TEGRA_PIN_PULL_UP>;
 				nvidia,tristate = <TEGRA_PIN_DISABLE>;
 			};
@@ -221,10 +222,9 @@
 					"lvp0", "owc", "sdb";
 				nvidia,tristate = <TEGRA_PIN_ENABLE>;
 			};
-			conf_irrx {
-				nvidia,pins = "irrx", "irtx", "sdd", "spic",
-					"spie", "spih", "uaa", "uab", "uad",
-					"uca", "ucb";
+			conf_sdd {
+				nvidia,pins = "sdd", "spic", "spie", "spih",
+					"uaa", "uab", "ucb";
 				nvidia,pull = <TEGRA_PIN_PULL_UP>;
 				nvidia,tristate = <TEGRA_PIN_ENABLE>;
 			};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/uniphier-pxs2.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/uniphier-pxs2.dtsi
@@ -571,7 +571,7 @@
 			clocks = <&sys_clk 6>;
 			reset-names = "ether";
 			resets = <&sys_rst 6>;
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 			local-mac-address = [00 00 00 00 00 00];
 			socionext,syscon-phy-mode = <&soc_glue 0>;
 
@@ -585,8 +585,8 @@
 			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
 			status = "disabled";
 			reg = <0x65a00000 0xcd00>;
-			interrupt-names = "host", "peripheral";
-			interrupts = <0 134 4>, <0 135 4>;
+			interrupt-names = "dwc_usb3";
+			interrupts = <0 134 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb2>;
 			clock-names = "ref", "bus_early", "suspend";
@@ -681,8 +681,8 @@
 			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
 			status = "disabled";
 			reg = <0x65c00000 0xcd00>;
-			interrupt-names = "host", "peripheral";
-			interrupts = <0 137 4>, <0 138 4>;
+			interrupt-names = "dwc_usb3";
+			interrupts = <0 137 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb1>, <&pinctrl_usb3>;
 			clock-names = "ref", "bus_early", "suspend";
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/versatile-ab.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/versatile-ab.dts
@@ -195,16 +195,15 @@
 		#size-cells = <1>;
 		ranges;
 
-		vic: intc@10140000 {
+		vic: interrupt-controller@10140000 {
 			compatible = "arm,versatile-vic";
 			interrupt-controller;
 			#interrupt-cells = <1>;
 			reg = <0x10140000 0x1000>;
-			clear-mask = <0xffffffff>;
 			valid-mask = <0xffffffff>;
 		};
 
-		sic: intc@10003000 {
+		sic: interrupt-controller@10003000 {
 			compatible = "arm,versatile-sic";
 			interrupt-controller;
 			#interrupt-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/versatile-pb.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/versatile-pb.dts
@@ -7,7 +7,7 @@
 
 	amba {
 		/* The Versatile PB is using more SIC IRQ lines than the AB */
-		sic: intc@10003000 {
+		sic: interrupt-controller@10003000 {
 			clear-mask = <0xffffffff>;
 			/*
 			 * Valid interrupt lines mask according to
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vesta-500.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/vesta-500.dts
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (C) 2018 Shrirang Bagul <shrirang.bagul@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.
+ */
+
+/dts-v1/;
+
+#include "vesta-500.dtsi"
+
+/ {
+	model = "Rigado Cascade 500 Board";
+	compatible = "fsl,vesta-500", "fsl,imx6ull";
+	version = "1.0.0";
+
+	aliases {
+		wifi0 = &athwifi;
+	};
+};
+
+&usdhc1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_wifi>;
+
+	no-1-8-v;
+	non-removable;
+	cap-sdio-irq;
+	cap-sd-highspeed;
+	enable-sdio-wakeup;
+	keep-power-in-suspend;
+	wakeup-source;
+	bus-width = <4>;
+	status = "okay";
+
+	athwifi:wifi@0 {
+		compatible = "qcom,ath10k";
+		local-mac-address = [ 00 00 00 00 00 00 ];
+	};
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+
+	no-1-8-v;
+	non-removable;
+	cap-mmc-highspeed;
+	keep-power-in-suspend;
+	bus-width = <8>;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vesta-500.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/vesta-500.dtsi
@@ -0,0 +1,706 @@
+/*
+ *  Copyright (C) 2018 Shrirang Bagul <shrirang.bagul@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 <dt-bindings/input/input.h>
+#include "imx6ull.dtsi"
+
+/ {
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	ocram_optee {
+		compatible = "fsl,optee-lpm-sram";
+		reg = <0x00918000 0x8000>;
+		overw_reg = <&ocram 0x00900000 0x18000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x200000>;
+			linux,cma-default;
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_can_3v3: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "can-3v3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+		};
+
+		reg_vref_3v3: regulator@1 {
+			  compatible = "regulator-fixed";
+			  reg = <0>;
+			  regulator-name = "vref-3v3";
+			  regulator-min-microvolt = <3300000>;
+			  regulator-max-microvolt = <3300000>;
+	  	};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_user_btn &pinctrl_rst_btn>;
+
+		user_btn {
+			label = "User_Button";
+			gpios = <&gpio5 10 GPIO_ACTIVE_HIGH>;
+			linux,code = <KEY_SPACE>;
+		};
+
+		rst_btn {
+			label = "Reset_Button";
+			gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;
+			linux,code = <KEY_BACKSPACE>;
+		};
+	};
+
+	gpio-restart {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_wdog>;
+
+		compatible = "gpio-restart";
+		gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;
+		priority = <200>;
+	};
+
+	pwmleds {
+		compatible = "pwm-leds";
+
+		pwm-green {
+			active-low;
+			linux,default-trigger = "default-on";
+			label = "vesta:pwm-green";
+			max-brightness = <248>;
+			pwms = <&pwm2 0 50000 0>;
+		};
+
+		pwm-red {
+			active-low;
+			linux,default-trigger = "default-on";
+			label = "vesta:pwm-red";
+			max-brightness = <248>;
+			pwms = <&pwm6 0 50000 0>;
+		};
+	};
+
+	/* All expansion cards should be listed here, as disabled  */
+
+	default_adccard: default_adccard {
+		compatible = "rigado,vesta-exp-card";
+		status = "disabled";
+	};
+
+	verizon_cellmdm: verizon_cellmdm {
+		compatible = "rigado,vesta-exp-card";
+		status = "disabled";
+	};
+
+	gemalto_cellmdm: gemalto_cellmdm {
+		compatible = "rigado,vesta-exp-card";
+		status = "disabled";
+	};
+
+	tau_board: tau_board {
+		compatible = "rigado,vesta-exp-card";
+		status = "disabled";
+	};
+
+	multiplexer_board: multiplexer_board {
+		compatible = "rigado,vesta-exp-card";
+		status = "disabled";
+	};
+};
+
+&cpu0 {
+	arm-supply = <&reg_arm>;
+	soc-supply = <&reg_soc>;
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet1>;
+
+	phy-mode = "rmii";
+	phy-handle = <&ethphy0>;
+
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+		};
+
+		ethphy1: ethernet-phy@2 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <2>;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+
+	clock-frequency = <100000>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+
+	clock_frequency = <100000>;
+	status = "okay";
+
+	exp_eeprom@50 {
+		compatible = "atmel,24c32";
+		reg = <0x50>;
+		pagesize = <32>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		exp0_data: exp_data@0 {
+			reg = <0 0x4A>;
+		};
+	};
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+
+	clock-frequency = <100000>;
+	status = "okay";
+};
+
+&adc1 {
+	vref-supply = <&reg_vref_3v3>;
+	status = "disabled";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	pinctrl_hog_1: hog1grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO06__GPIO1_IO06	0x00001020 /* PMIC_INT_N */
+			MX6UL_PAD_CSI_DATA02__GPIO4_IO23	0x00001020 /* BT_GPIO */
+			MX6UL_PAD_CSI_DATA03__GPIO4_IO24	0x00001020 /* BT_RST_N */
+			MX6UL_PAD_CSI_DATA04__GPIO4_IO25	0x00001020 /* ENET1 RST N */
+			MX6UL_PAD_CSI_DATA06__GPIO4_IO27	0x00001020 /* BT_INT_N */
+			MX6UL_PAD_CSI_DATA07__GPIO4_IO28	0x00001020 /* ENET1_INT_N */
+			MX6UL_PAD_NAND_ALE__USDHC2_RESET_B	0x000010A0 /* SD2_RST_N */
+			MX6UL_PAD_LCD_DATA00__GPIO3_IO05	0x00001020 /* BLE_RST_N */
+			MX6UL_PAD_LCD_DATA08__GPIO3_IO13	0x00001020 /* SWDIO */
+			MX6UL_PAD_LCD_DATA09__GPIO3_IO14	0x00001020 /* SWCLK */
+		>;
+	};
+
+	pinctrl_adc1: adc1grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 		0x00001020
+		  >;
+	};
+
+	pinctrl_adc2: adc2grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 		0x00001020
+			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01		0x00001020
+		  >;
+	};
+
+	pinctrl_wifi: wifigrp {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_TX_CLK__GPIO2_IO14 0x00001020
+		>;
+	};
+
+	pinctrl_enet1: enet1grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO07__ENET1_MDC		0x00002008
+			MX6UL_PAD_ENET2_RX_DATA0__ENET1_MDIO	0x00002008
+
+			MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN	0x00001088
+			MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER	0x00001088
+			MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00	0x00001088
+			MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01	0x00001088
+			MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN	0x00001088
+			MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00	0x00001088
+			MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01	0x00001088
+			MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x40001008
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_PIXCLK__I2C1_SCL 0x40001820
+			MX6UL_PAD_GPIO1_IO03__I2C1_SDA 0x40001820
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_HSYNC__I2C2_SCL 0x40001820
+			MX6UL_PAD_CSI_VSYNC__I2C2_SDA 0x40001820
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA02__I2C4_SDA	0x40001820
+			MX6UL_PAD_LCD_DATA03__I2C4_SCL	0x40001820
+		>;
+	};
+
+	pinctrl_pwm2: pwm2grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA01__PWM2_OUT	0x00009030
+		>;
+	};
+
+	pinctrl_pwm6: pwm6grp {
+		fsl,pins = <
+			MX6UL_PAD_JTAG_TDI__PWM6_OUT   0x00007030
+		>;
+	};
+
+	pinctrl_qspi: qspigrp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK      0x00001020
+			MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x00009020
+			MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01   0x00001020
+			MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02   0x00001020
+			MX6UL_PAD_NAND_CLE__QSPI_A_DATA03     0x00001020
+			MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B      0x00001020
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX	0x00001020
+			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX	0x00001020
+			MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS	0x00001020
+			MX6UL_PAD_UART1_CTS_B__UART1_DCE_CTS	0x00001020
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX	0x00001020
+			MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX	0x00001020
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX	0x00001020
+			MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX	0x00001020
+			MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS	0x00001020
+			MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS	0x00001020
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX	0x00001020
+			MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX	0x00001020
+		>;
+	};
+
+	pinctrl_uart4_flowctrl: uart4grp_flowctrl {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX	0x00001020
+			MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX	0x00001020
+			MX6UL_PAD_LCD_HSYNC__UART4_DCE_CTS	0x00001020
+			MX6UL_PAD_LCD_VSYNC__UART4_DCE_RTS	0x00001020
+
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO04__UART5_DCE_TX	0x00001020
+			MX6UL_PAD_GPIO1_IO05__UART5_DCE_RX	0x00001020
+		>;
+	};
+
+	pinctrl_uart5_flowctrl: uart5grp_flowctrl {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO04__UART5_DCE_TX	0x00001020
+			MX6UL_PAD_GPIO1_IO05__UART5_DCE_RX	0x00001020
+			MX6UL_PAD_GPIO1_IO09__UART5_DCE_CTS 0x00001020
+			MX6UL_PAD_GPIO1_IO08__UART5_DCE_RTS	0x00001020
+		>;
+	};
+
+	pinctrl_uart6: uart6grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_RX_DATA1__UART6_DCE_RX	0x00001020
+			MX6UL_PAD_CSI_MCLK__UART6_DCE_TX	0x00001020
+		>;
+	};
+
+	pinctrl_uart7: uart7grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_TX_DATA0__UART7_DCE_RX	0x00001008
+			MX6UL_PAD_ENET2_RX_EN__UART7_DCE_TX	0x00001008
+		>;
+	};
+
+	pinctrl_uart7_flowctrl: uart7grp_flowctrl {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_TX_DATA0__UART7_DCE_RX	0x00001008
+			MX6UL_PAD_ENET2_RX_EN__UART7_DCE_TX	0x00001008
+			MX6UL_PAD_LCD_DATA06__UART7_DCE_CTS 	0x00001008
+			MX6UL_PAD_LCD_DATA07__UART7_DCE_RTS 	0x00001008
+		>;
+	};
+
+	pinctrl_uart8: uart8grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX	0x00001020
+			MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX	0x00001020
+		>;
+	};
+
+	pinctrl_uart8_flowctrl: uart8grp_flowctrl {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX	0x1b0b1
+			MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX	0x1b0b1
+			MX6UL_PAD_LCD_DATA04__UART8_DCE_CTS	0x1b0b1
+			MX6UL_PAD_LCD_DATA05__UART8_DCE_RTS	0x1b0b1
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x000090A0
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x00001008
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x000090A0
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x000090A0
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x000090A0
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x000090A0
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x000010A0
+			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x000090A0
+			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x000090A0
+			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x000010A0
+			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x000010A0
+			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x000010A0
+			MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x000010A0
+			MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x000010A0
+			MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x000010A0
+			MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x000010A0
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15	0x000010B0
+		>;
+	};
+
+	pinctrl_vz_cellmdm: vzcellmdmgrp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02	0x00001020 /* Ring */
+			MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28	0x00001020 /* DCD */
+			MX6UL_PAD_CSI_DATA00__GPIO4_IO21	0x00001020 /* CELL_WAKEUP */
+			MX6UL_PAD_CSI_DATA01__GPIO4_IO22	0x00001020	/* VBUS_CTRL */
+			MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30	0x00001020	/* CELL_PWRKEY */
+			MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31	0x00001020 /* CELL_STATUS N */
+			MX6UL_PAD_GPIO1_IO08__GPIO1_IO08	0x00001020 /* CELL_PWR_SHDN */
+			MX6UL_PAD_UART2_RTS_B__GPIO1_IO23	0x00001020	/* CELL_DISABLE */
+			MX6UL_PAD_UART2_CTS_B__GPIO1_IO22	0x00001020 /* CELL_RST */
+		>;
+	};
+
+	pinctrl_gm_cellmdm: gmcellmdmgrp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02	0x00001020 /* Ring */
+			MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28	0x00001020 /* DCD */
+			MX6UL_PAD_GPIO1_IO08__GPIO1_IO08	0x00001020 /* CELL_PWR_SHDN */
+			MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09 0x00001020 /* DSR */
+			MX6UL_PAD_CSI_DATA01__GPIO4_IO22	0x00001020	/* VBUS_CTRL */
+			MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30	0x00001020	/* CELL_IGT */
+			MX6UL_PAD_UART2_RTS_B__GPIO1_IO23	0x00001020	/* CELL_EOFF */
+			MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31	0x00001020	/* CELL_STATUS */
+			MX6UL_PAD_UART2_CTS_B__GPIO1_IO22	0x00001020 /* CELL_SHDN */
+		>;
+	};
+
+	pinctrl_user_btn: user-btn {
+		fsl,pins = <
+			MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10	0x00013020 /* user button */
+		>;
+	};
+
+	pinctrl_rst_btn: rst-btn {
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA05__GPIO4_IO26	0x00001020 /* RST BTN */
+		>;
+	};
+
+	pinctrl_tau80: tau80grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA12__GPIO3_IO17	0x00001020 /* BLE1_INT_IN */
+			MX6UL_PAD_LCD_DATA13__GPIO3_IO18	0x00001020 /* BLE2_INT_IN */
+			MX6UL_PAD_LCD_DATA14__GPIO3_IO19	0x00001020 /* BLE3_INT_IN */
+			MX6UL_PAD_LCD_DATA15__GPIO3_IO20	0x00001020 /* BLE4_INT_IN */
+
+			MX6UL_PAD_CSI_DATA00__GPIO4_IO21	0x00001020 /* BLE1_RST_N */
+			MX6UL_PAD_CSI_DATA01__GPIO4_IO22	0x00001020 /* BLE2_RST_N */
+			MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30	0x00001020 /* BLE3_RST_N */
+			MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31	0x00001020 /* BLE4_RST_N */
+
+			MX6UL_PAD_UART2_RTS_B__GPIO1_IO23	0x00001020 /* SWD_CLK1 */
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02	0x00001020 /* SWD_CLK2 */
+			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01	0x00001020 /* SWD_CLK3 */
+
+			MX6UL_PAD_UART2_CTS_B__GPIO1_IO22	0x00001020 /* SWD_IO */
+		>;
+	};
+
+	pinctrl_multiplexer: multiplexergrp {
+		 fsl,pins = <
+			 MX6UL_PAD_LCD_CLK__GPIO3_IO00           0x00001020 /* EXP_PWR_DIS2 */
+			 MX6UL_PAD_LCD_ENABLE__GPIO3_IO01        0x00001020 /* EXP_PWR_DIS1 */
+			 MX6UL_PAD_LCD_HSYNC__GPIO3_IO02         0x00001020 /* HUB_RST_N4 */
+			 MX6UL_PAD_LCD_VSYNC__GPIO3_IO03         0x00001020 /* EXP_INT1_N4 */
+			 MX6UL_PAD_LCD_RESET__GPIO3_IO04         0x00001020 /* EXP_INT2_N4 */
+			 MX6UL_PAD_LCD_DATA16__GPIO3_IO21        0x00001020 /* EXP_INT4_N4 */
+			 MX6UL_PAD_LCD_DATA17__GPIO3_IO22        0x00001020 /* EXP_INT3_N4 */
+			 MX6UL_PAD_LCD_DATA18__GPIO3_IO23        0x00001020 /* EXP_RST_N4 */
+			 MX6UL_PAD_LCD_DATA19__GPIO3_IO24        0x00001020 /* EXP_PWR_DIS4 */
+			 MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28     0x00001020 /* EXP_INT4_N1 */
+			 MX6UL_PAD_UART4_RX_DATA__GPIO1_IO29     0x00001020 /* EXP_INT2_N1 */
+			 MX6UL_PAD_GPIO1_IO04__GPIO1_IO04        0x00001020 /* EXP_INT1_N1 */
+			 MX6UL_PAD_GPIO1_IO05__GPIO1_IO05        0x00001020 /* HUB_RST_N1 */
+			 MX6UL_PAD_CSI_MCLK__GPIO4_IO17          0x00001020 /* EXP_RST_N1 */
+			 MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09    0x00001020 /* EXP_RST_N2 */
+			 MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10       0x00001020 /* USB_RST_N */
+			 MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11    0x00001020 /* EXP_INT1_N3 */
+			 MX6UL_PAD_ENET2_TX_DATA1__GPIO2_IO12    0x00001020 /* EXP_INT2_N3 */
+			 MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13       0x00001020 /* EXP_INT3_N3 */
+			 MX6UL_PAD_CSI_DATA00__GPIO4_IO21        0x00001020 /* EXP_PWR_DIS3 */
+			 MX6UL_PAD_CSI_DATA01__GPIO4_IO22        0x00001020 /* EXP_INT4_N3 */
+			 MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30     0x00001020 /* EXP_RST_N3 */
+			 MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31     0x00001020 /* HUB_RST_N2 */
+			 MX6UL_PAD_LCD_DATA04__GPIO3_IO09        0x00001020 /* EXP_INT3_N1 */
+			 MX6UL_PAD_LCD_DATA05__GPIO3_IO10        0x00001020 /* HUB_RST_N3 */
+			 MX6UL_PAD_LCD_DATA06__GPIO3_IO11        0x00001020 /* MAG_DRDY */
+			 MX6UL_PAD_LCD_DATA07__GPIO3_IO12        0x00001020 /* ACCEL_INT */
+			 MX6UL_PAD_LCD_DATA10__GPIO3_IO15        0x00001020 /* MAG_INT */
+			 MX6UL_PAD_LCD_DATA11__GPIO3_IO16        0x00001020 /* EXT_BUTTON */
+			 MX6UL_PAD_LCD_DATA12__GPIO3_IO17        0x00001020 /* EXP_INT3_N2 */
+			 MX6UL_PAD_LCD_DATA13__GPIO3_IO18        0x00001020 /* EXP_INT4_N2 */
+			 MX6UL_PAD_LCD_DATA14__GPIO3_IO19        0x00001020 /* EXP_INT2_N2 */
+			 MX6UL_PAD_LCD_DATA15__GPIO3_IO20        0x00001020 /* EXP_INT1_N2 */
+			 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x00001020 /* SWD_SEL_C */
+			 MX6UL_PAD_GPIO1_IO08__GPIO1_IO08        0x00001020 /* SWD_SEL_D */
+			 MX6UL_PAD_GPIO1_IO01__GPIO1_IO01        0x00001020 /* SWD_SEL_B */
+			 MX6UL_PAD_GPIO1_IO02__GPIO1_IO02        0x00001020 /* SWD_SEL_A */
+			 MX6UL_PAD_UART2_RTS_B__GPIO1_IO23       0x00001020 /* SWD_CLK1 */
+			 MX6UL_PAD_UART2_CTS_B__GPIO1_IO22       0x00001020 /* SWD_IO */
+		 >;
+	 };
+
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK	0x00001020
+			MX6UL_PAD_LCD_DATA21__ECSPI1_SS0	0x00001020
+			MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI	0x00001020
+			MX6UL_PAD_LCD_DATA23__ECSPI1_MISO	0x00001020
+		>;
+	};
+};
+
+&ocotp {
+	compatible = "fsl,imx6ull-ocotp", "syscon";
+
+	status = "okay";
+};
+
+&pwm2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm2>;
+
+	status = "okay";
+};
+
+&pwm6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm6>;
+
+	status = "okay";
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+
+	status = "disabled";
+};
+
+&tempmon {
+	fsl,tempmon-data = <&ocotp>;
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+
+	dmas = <&sdma 25 4 0>, <&sdma 26 4 0>;
+	dma-names = "rx", "tx";
+
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	fsl,uart-has-rtscts;
+
+	dmas = <&sdma 29 4 0>, <&sdma 30 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4_flowctrl>;
+	fsl,uart-has-rtscts;
+
+	dmas = <&sdma 31 4 0>, <&sdma 32 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "disabled";
+};
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5_flowctrl>;
+	fsl,uart-has-rtscts;
+
+	dmas = <&sdma 33 4 0>, <&sdma 34 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "disabled";
+};
+
+&uart6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart6>;
+
+	dmas = <&sdma 0 4 0>, <&sdma 47 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "disabled";
+};
+
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart7_flowctrl>;
+	fsl,uart-has-rtscts;
+
+	dmas = <&sdma 43 4 0>, <&sdma 44 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "disabled";
+};
+
+&uart8 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart8_flowctrl>;
+	fsl,uart-has-rtscts;
+
+	dmas = <&sdma 45 4 0>, <&sdma 46 4 0>;
+	dma-names = "rx", "tx";
+
+	status = "disabled";
+};
+
+&usbotg1 {
+	dr_mode = "host";
+	disable-over-current;
+
+	status = "okay";
+};
+
+&usbotg2 {
+	dr_mode = "host";
+	disable-over-current;
+
+	status = "okay";
+};
+
+&wdog1 {
+	status = "okay";
+};
+
+/* Vesta expansion card DT overlay manager - based on beaglebone cape manager */
+
+/ {
+
+	vesta_overlaymgr {
+		compatible = "rigado,vesta-overlaymgr";
+		status = "okay";
+
+		nvmem-cells = <&exp0_data>;
+		nvmem-cell-names = "slot0";
+
+		#slots = <1>;
+
+		/* map board revisions to compatible definitions */
+		baseboardmaps {
+			baseboard_vesta: board@0 {
+				board-name ="vesta";
+				compatible-name = "rigado,vesta";
+			};
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -31,7 +31,7 @@
 			#interrupt-cells = <1>;
 			ranges;
 
-			nor_flash: flash@0,00000000 {
+			nor_flash: flash@0 {
 				compatible = "arm,vexpress-flash", "cfi-flash";
 				reg = <0 0x00000000 0x04000000>,
 				      <4 0x00000000 0x04000000>;
@@ -41,13 +41,13 @@
 				};
 			};
 
-			psram@1,00000000 {
+			psram@100000000 {
 				compatible = "arm,vexpress-psram", "mtd-ram";
 				reg = <1 0x00000000 0x02000000>;
 				bank-width = <4>;
 			};
 
-			ethernet@2,02000000 {
+			ethernet@202000000 {
 				compatible = "smsc,lan9118", "smsc,lan9115";
 				reg = <2 0x02000000 0x10000>;
 				interrupts = <15>;
@@ -59,14 +59,14 @@
 				vddvario-supply = <&v2m_fixed_3v3>;
 			};
 
-			usb@2,03000000 {
+			usb@203000000 {
 				compatible = "nxp,usb-isp1761";
 				reg = <2 0x03000000 0x20000>;
 				interrupts = <16>;
 				port1-otg;
 			};
 
-			iofpga@3,00000000 {
+			iofpga@300000000 {
 				compatible = "simple-bus";
 				#address-cells = <1>;
 				#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
+++ linux-ein-5.4.0/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -132,6 +132,7 @@
 		reg = <0x2c0f0000 0x1000>;
 		interrupts = <0 84 4>;
 		cache-level = <2>;
+		cache-unified;
 	};
 
 	pmu {
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vf500.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/vf500.dtsi
@@ -23,7 +23,7 @@
 	};
 
 	soc {
-		aips-bus@40000000 {
+		bus@40000000 {
 
 			intc: interrupt-controller@40003000 {
 				compatible = "arm,cortex-a9-gic";
@@ -43,7 +43,7 @@
 			};
 		};
 
-		aips-bus@40080000 {
+		bus@40080000 {
 			pmu@40089000 {
 				compatible = "arm,cortex-a5-pmu";
 				interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm/boot/dts/vfxxx.dtsi
+++ linux-ein-5.4.0/arch/arm/boot/dts/vfxxx.dtsi
@@ -59,7 +59,7 @@
 		interrupt-parent = <&mscm_ir>;
 		ranges;
 
-		aips0: aips-bus@40000000 {
+		aips0: bus@40000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -471,7 +471,7 @@
 			};
 		};
 
-		aips1: aips-bus@40080000 {
+		aips1: bus@40080000 {
 			compatible = "fsl,aips-bus", "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -495,7 +495,7 @@
 			};
 
 			ocotp: ocotp@400a5000 {
-				compatible = "fsl,vf610-ocotp";
+				compatible = "fsl,vf610-ocotp", "syscon";
 				reg = <0x400a5000 0x1000>;
 				clocks = <&clks VF610_CLK_OCOTP>;
 			};
--- linux-ein-5.4.0.orig/arch/arm/configs/aspeed_g5_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/aspeed_g5_defconfig
@@ -139,6 +139,7 @@
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_ASPEED_VUART=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_ASPEED_KCS_IPMI_BMC=y
 CONFIG_ASPEED_BT_IPMI_BMC=y
--- linux-ein-5.4.0.orig/arch/arm/configs/exynos_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/exynos_defconfig
@@ -38,6 +38,7 @@
 CONFIG_CRYPTO_SHA512_ARM=m
 CONFIG_CRYPTO_AES_ARM_BS=m
 CONFIG_CRYPTO_CHACHA20_NEON=m
+CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
@@ -92,6 +93,7 @@
 CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_ATA=y
@@ -290,6 +292,7 @@
 CONFIG_COMMON_CLK_MAX77686=y
 CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_EXYNOS_IOMMU=y
+CONFIG_PM_DEVFREQ=y
 CONFIG_DEVFREQ_GOV_PERFORMANCE=y
 CONFIG_DEVFREQ_GOV_POWERSAVE=y
 CONFIG_DEVFREQ_GOV_USERSPACE=y
@@ -348,9 +351,13 @@
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_INFO=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_SOFTLOCKUP_DETECTOR=y
 # CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_PROVE_LOCKING=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_USER=y
--- linux-ein-5.4.0.orig/arch/arm/configs/imx_v6_v7_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/imx_v6_v7_defconfig
@@ -460,6 +460,7 @@
 CONFIG_FONT_8x16=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_PROVE_LOCKING=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
--- linux-ein-5.4.0.orig/arch/arm/configs/omap2plus_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/omap2plus_defconfig
@@ -552,5 +552,6 @@
 CONFIG_DEBUG_INFO_SPLIT=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
--- linux-ein-5.4.0.orig/arch/arm/configs/rpc_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/rpc_defconfig
@@ -32,7 +32,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/arm/configs/s3c2410_defconfig
+++ linux-ein-5.4.0/arch/arm/configs/s3c2410_defconfig
@@ -202,7 +202,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_CHR_DEV_SCH=m
 CONFIG_SCSI_CONSTANTS=y
--- linux-ein-5.4.0.orig/arch/arm/crypto/Kconfig
+++ linux-ein-5.4.0/arch/arm/crypto/Kconfig
@@ -30,7 +30,7 @@
 
 config CRYPTO_SHA1_ARM_CE
 	tristate "SHA1 digest algorithm (ARM v8 Crypto Extensions)"
-	depends on KERNEL_MODE_NEON
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
 	select CRYPTO_SHA1_ARM
 	select CRYPTO_HASH
 	help
@@ -39,7 +39,7 @@
 
 config CRYPTO_SHA2_ARM_CE
 	tristate "SHA-224/256 digest algorithm (ARM v8 Crypto Extensions)"
-	depends on KERNEL_MODE_NEON
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
 	select CRYPTO_SHA256_ARM
 	select CRYPTO_HASH
 	help
@@ -96,7 +96,7 @@
 
 config CRYPTO_AES_ARM_CE
 	tristate "Accelerated AES using ARMv8 Crypto Extensions"
-	depends on KERNEL_MODE_NEON
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
 	select CRYPTO_BLKCIPHER
 	select CRYPTO_LIB_AES
 	select CRYPTO_SIMD
@@ -106,7 +106,7 @@
 
 config CRYPTO_GHASH_ARM_CE
 	tristate "PMULL-accelerated GHASH using NEON/ARMv8 Crypto Extensions"
-	depends on KERNEL_MODE_NEON
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
 	select CRYPTO_HASH
 	select CRYPTO_CRYPTD
 	select CRYPTO_GF128MUL
@@ -118,12 +118,14 @@
 
 config CRYPTO_CRCT10DIF_ARM_CE
 	tristate "CRCT10DIF digest algorithm using PMULL instructions"
-	depends on KERNEL_MODE_NEON && CRC_T10DIF
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
+	depends on CRC_T10DIF
 	select CRYPTO_HASH
 
 config CRYPTO_CRC32_ARM_CE
 	tristate "CRC32(C) digest algorithm using CRC and/or PMULL instructions"
-	depends on KERNEL_MODE_NEON && CRC32
+	depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
+	depends on CRC32
 	select CRYPTO_HASH
 
 config CRYPTO_CHACHA20_NEON
--- linux-ein-5.4.0.orig/arch/arm/crypto/Makefile
+++ linux-ein-5.4.0/arch/arm/crypto/Makefile
@@ -12,32 +12,12 @@
 obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o
 obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
 
-ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
-ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
-ce-obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o
-ce-obj-$(CONFIG_CRYPTO_GHASH_ARM_CE) += ghash-arm-ce.o
-ce-obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM_CE) += crct10dif-arm-ce.o
-crc-obj-$(CONFIG_CRYPTO_CRC32_ARM_CE) += crc32-arm-ce.o
-
-ifneq ($(crc-obj-y)$(crc-obj-m),)
-ifeq ($(call as-instr,.arch armv8-a\n.arch_extension crc,y,n),y)
-ce-obj-y += $(crc-obj-y)
-ce-obj-m += $(crc-obj-m)
-else
-$(warning These CRC Extensions modules need binutils 2.23 or higher)
-$(warning $(crc-obj-y) $(crc-obj-m))
-endif
-endif
-
-ifneq ($(ce-obj-y)$(ce-obj-m),)
-ifeq ($(call as-instr,.fpu crypto-neon-fp-armv8,y,n),y)
-obj-y += $(ce-obj-y)
-obj-m += $(ce-obj-m)
-else
-$(warning These ARMv8 Crypto Extensions modules need binutils 2.23 or higher)
-$(warning $(ce-obj-y) $(ce-obj-m))
-endif
-endif
+obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
+obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
+obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o
+obj-$(CONFIG_CRYPTO_GHASH_ARM_CE) += ghash-arm-ce.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM_CE) += crct10dif-arm-ce.o
+obj-$(CONFIG_CRYPTO_CRC32_ARM_CE) += crc32-arm-ce.o
 
 aes-arm-y	:= aes-cipher-core.o aes-cipher-glue.o
 aes-arm-bs-y	:= aes-neonbs-core.o aes-neonbs-glue.o
--- linux-ein-5.4.0.orig/arch/arm/crypto/aes-ce-core.S
+++ linux-ein-5.4.0/arch/arm/crypto/aes-ce-core.S
@@ -386,20 +386,32 @@
 .Lctrloop4x:
 	subs		r4, r4, #4
 	bmi		.Lctr1x
-	add		r6, r6, #1
+
+	/*
+	 * NOTE: the sequence below has been carefully tweaked to avoid
+	 * a silicon erratum that exists in Cortex-A57 (#1742098) and
+	 * Cortex-A72 (#1655431) cores, where AESE/AESMC instruction pairs
+	 * may produce an incorrect result if they take their input from a
+	 * register of which a single 32-bit lane has been updated the last
+	 * time it was modified. To work around this, the lanes of registers
+	 * q0-q3 below are not manipulated individually, and the different
+	 * counter values are prepared by successive manipulations of q7.
+	 */
+	add		ip, r6, #1
 	vmov		q0, q7
+	rev		ip, ip
+	add		lr, r6, #2
+	vmov		s31, ip			@ set lane 3 of q1 via q7
+	add		ip, r6, #3
+	rev		lr, lr
 	vmov		q1, q7
-	rev		ip, r6
-	add		r6, r6, #1
+	vmov		s31, lr			@ set lane 3 of q2 via q7
+	rev		ip, ip
 	vmov		q2, q7
-	vmov		s7, ip
-	rev		ip, r6
-	add		r6, r6, #1
+	vmov		s31, ip			@ set lane 3 of q3 via q7
+	add		r6, r6, #4
 	vmov		q3, q7
-	vmov		s11, ip
-	rev		ip, r6
-	add		r6, r6, #1
-	vmov		s15, ip
+
 	vld1.8		{q4-q5}, [r1]!
 	vld1.8		{q6}, [r1]!
 	vld1.8		{q15}, [r1]!
--- linux-ein-5.4.0.orig/arch/arm/crypto/crct10dif-ce-core.S
+++ linux-ein-5.4.0/arch/arm/crypto/crct10dif-ce-core.S
@@ -72,7 +72,7 @@
 #endif
 
 	.text
-	.arch		armv7-a
+	.arch		armv8-a
 	.fpu		crypto-neon-fp-armv8
 
 	init_crc	.req	r0
--- linux-ein-5.4.0.orig/arch/arm/crypto/ghash-ce-core.S
+++ linux-ein-5.4.0/arch/arm/crypto/ghash-ce-core.S
@@ -8,6 +8,9 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
+	.arch		armv8-a
+	.fpu		crypto-neon-fp-armv8
+
 	SHASH		.req	q0
 	T1		.req	q1
 	XL		.req	q2
@@ -88,7 +91,6 @@
 	T3_H		.req	d17
 
 	.text
-	.fpu		crypto-neon-fp-armv8
 
 	.macro		__pmull_p64, rd, rn, rm, b1, b2, b3, b4
 	vmull.p64	\rd, \rn, \rm
--- linux-ein-5.4.0.orig/arch/arm/crypto/nhpoly1305-neon-glue.c
+++ linux-ein-5.4.0/arch/arm/crypto/nhpoly1305-neon-glue.c
@@ -30,7 +30,7 @@
 		return crypto_nhpoly1305_update(desc, src, srclen);
 
 	do {
-		unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE);
+		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
 
 		kernel_neon_begin();
 		crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon);
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha1-ce-core.S
+++ linux-ein-5.4.0/arch/arm/crypto/sha1-ce-core.S
@@ -10,6 +10,7 @@
 #include <asm/assembler.h>
 
 	.text
+	.arch		armv8-a
 	.fpu		crypto-neon-fp-armv8
 
 	k0		.req	q0
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha2-ce-core.S
+++ linux-ein-5.4.0/arch/arm/crypto/sha2-ce-core.S
@@ -10,6 +10,7 @@
 #include <asm/assembler.h>
 
 	.text
+	.arch		armv8-a
 	.fpu		crypto-neon-fp-armv8
 
 	k0		.req	q7
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha256-armv4.pl
+++ linux-ein-5.4.0/arch/arm/crypto/sha256-armv4.pl
@@ -175,7 +175,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -471,7 +470,8 @@
 	stmdb	sp!,{r4-r12,lr}
 
 	sub	$H,sp,#16*4+16
-	adrl	$Ktbl,K256
+	adr	$Ktbl,.Lsha256_block_data_order
+	sub	$Ktbl,$Ktbl,#.Lsha256_block_data_order-K256
 	bic	$H,$H,#15		@ align for 128-bit stores
 	mov	$t2,sp
 	mov	sp,$H			@ alloca
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha256-core.S_shipped
+++ linux-ein-5.4.0/arch/arm/crypto/sha256-core.S_shipped
@@ -56,7 +56,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -1885,7 +1884,8 @@
 	stmdb	sp!,{r4-r12,lr}
 
 	sub	r11,sp,#16*4+16
-	adrl	r14,K256
+	adr	r14,.Lsha256_block_data_order
+	sub	r14,r14,#.Lsha256_block_data_order-K256
 	bic	r11,r11,#15		@ align for 128-bit stores
 	mov	r12,sp
 	mov	sp,r11			@ alloca
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha512-armv4.pl
+++ linux-ein-5.4.0/arch/arm/crypto/sha512-armv4.pl
@@ -212,7 +212,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -602,7 +601,8 @@
 	dmb				@ errata #451034 on early Cortex A8
 	add	$len,$inp,$len,lsl#7	@ len to point at the end of inp
 	VFP_ABI_PUSH
-	adrl	$Ktbl,K512
+	adr	$Ktbl,.Lsha512_block_data_order
+	sub	$Ktbl,$Ktbl,.Lsha512_block_data_order-K512
 	vldmia	$ctx,{$A-$H}		@ load context
 .Loop_neon:
 ___
--- linux-ein-5.4.0.orig/arch/arm/crypto/sha512-core.S_shipped
+++ linux-ein-5.4.0/arch/arm/crypto/sha512-core.S_shipped
@@ -79,7 +79,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -543,7 +542,8 @@
 	dmb				@ errata #451034 on early Cortex A8
 	add	r2,r1,r2,lsl#7	@ len to point at the end of inp
 	VFP_ABI_PUSH
-	adrl	r3,K512
+	adr	r3,.Lsha512_block_data_order
+	sub	r3,r3,.Lsha512_block_data_order-K512
 	vldmia	r0,{d16-d23}		@ load context
 .Loop_neon:
 	vshr.u64	d24,d20,#14	@ 0
--- linux-ein-5.4.0.orig/arch/arm/include/asm/assembler.h
+++ linux-ein-5.4.0/arch/arm/include/asm/assembler.h
@@ -18,11 +18,11 @@
 #endif
 
 #include <asm/ptrace.h>
-#include <asm/domain.h>
 #include <asm/opcodes-virt.h>
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
+#include <asm/uaccess-asm.h>
 
 #define IOMEM(x)	(x)
 
@@ -107,6 +107,16 @@
 	.endm
 #endif
 
+#if __LINUX_ARM_ARCH__ < 7
+	.macro	dsb, args
+	mcr	p15, 0, r0, c7, c10, 4
+	.endm
+
+	.macro	isb, args
+	mcr	p15, 0, r0, c7, c5, 4
+	.endm
+#endif
+
 	.macro asm_trace_hardirqs_off, save=1
 #if defined(CONFIG_TRACE_IRQFLAGS)
 	.if \save
@@ -269,10 +279,9 @@
 	.endif							;\
 	.popsection
 #define ALT_UP_B(label)					\
-	.equ	up_b_offset, label - 9998b			;\
 	.pushsection ".alt.smp.init", "a"			;\
 	.long	9998b						;\
-	W(b)	. + up_b_offset					;\
+	W(b)	. + (label - 9998b)					;\
 	.popsection
 #else
 #define ALT_SMP(instr...)
@@ -446,79 +455,6 @@
 	.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
-	sbcscc	\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) {
-	subshs	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
-	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
-	csdb
-#endif
-	.endm
-
-	.macro	uaccess_disable, tmp, isb=1
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-	/*
-	 * Whenever we re-enter userspace, the domains should always be
-	 * set appropriately.
-	 */
-	mov	\tmp, #DACR_UACCESS_DISABLE
-	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
-	.if	\isb
-	instr_sync
-	.endif
-#endif
-	.endm
-
-	.macro	uaccess_enable, tmp, isb=1
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-	/*
-	 * Whenever we re-enter userspace, the domains should always be
-	 * set appropriately.
-	 */
-	mov	\tmp, #DACR_UACCESS_ENABLE
-	mcr	p15, 0, \tmp, c3, c0, 0
-	.if	\isb
-	instr_sync
-	.endif
-#endif
-	.endm
-
-	.macro	uaccess_save, tmp
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-	mrc	p15, 0, \tmp, c3, c0, 0
-	str	\tmp, [sp, #SVC_DACR]
-#endif
-	.endm
-
-	.macro	uaccess_restore
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-	ldr	r0, [sp, #SVC_DACR]
-	mcr	p15, 0, r0, c3, c0, 0
-#endif
-	.endm
-
 	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
 	.macro	ret\c, reg
 #if __LINUX_ARM_ARCH__ < 6
--- linux-ein-5.4.0.orig/arch/arm/include/asm/bugs.h
+++ linux-ein-5.4.0/arch/arm/include/asm/bugs.h
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- *  arch/arm/include/asm/bugs.h
- *
  *  Copyright (C) 1995-2003 Russell King
  */
 #ifndef __ASM_BUGS_H
@@ -10,10 +8,8 @@
 extern void check_writebuffer_bugs(void);
 
 #ifdef CONFIG_MMU
-extern void check_bugs(void);
 extern void check_other_bugs(void);
 #else
-#define check_bugs() do { } while (0)
 #define check_other_bugs() do { } while (0)
 #endif
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/clocksource.h
+++ linux-ein-5.4.0/arch/arm/include/asm/clocksource.h
@@ -1,8 +1,17 @@
 #ifndef _ASM_CLOCKSOURCE_H
 #define _ASM_CLOCKSOURCE_H
 
+enum vdso_arch_clockmode {
+	/* vdso clocksource not usable */
+	VDSO_CLOCKMODE_NONE,
+	/* vdso clocksource usable */
+	VDSO_CLOCKMODE_ARCHTIMER,
+	VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT = VDSO_CLOCKMODE_ARCHTIMER,
+};
+
 struct arch_clocksource_data {
-	bool vdso_direct;	/* Usable for direct VDSO access? */
+	/* Usable for direct VDSO access? */
+	enum vdso_arch_clockmode clock_mode;
 };
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/exception.h
+++ linux-ein-5.4.0/arch/arm/include/asm/exception.h
@@ -10,10 +10,6 @@
 
 #include <linux/interrupt.h>
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #define __exception_irq_entry	__irq_entry
-#else
-#define __exception_irq_entry
-#endif
 
 #endif /* __ASM_ARM_EXCEPTION_H */
--- linux-ein-5.4.0.orig/arch/arm/include/asm/fixmap.h
+++ linux-ein-5.4.0/arch/arm/include/asm/fixmap.h
@@ -2,7 +2,7 @@
 #ifndef _ASM_FIXMAP_H
 #define _ASM_FIXMAP_H
 
-#define FIXADDR_START		0xffc00000UL
+#define FIXADDR_START		0xffc80000UL
 #define FIXADDR_END		0xfff00000UL
 #define FIXADDR_TOP		(FIXADDR_END - PAGE_SIZE)
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/ftrace.h
+++ linux-ein-5.4.0/arch/arm/include/asm/ftrace.h
@@ -16,6 +16,9 @@
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 struct dyn_arch_ftrace {
+#ifdef CONFIG_ARM_MODULE_PLTS
+	struct module *mod;
+#endif
 };
 
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
--- linux-ein-5.4.0.orig/arch/arm/include/asm/futex.h
+++ linux-ein-5.4.0/arch/arm/include/asm/futex.h
@@ -164,8 +164,13 @@
 	preempt_enable();
 #endif
 
-	if (!ret)
-		*oval = oldval;
+	/*
+	 * 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-ein-5.4.0.orig/arch/arm/include/asm/insn.h
+++ linux-ein-5.4.0/arch/arm/include/asm/insn.h
@@ -13,18 +13,18 @@
 }
 
 unsigned long
-__arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool warn);
 
 static inline unsigned long
 arm_gen_branch(unsigned long pc, unsigned long addr)
 {
-	return __arm_gen_branch(pc, addr, false);
+	return __arm_gen_branch(pc, addr, false, true);
 }
 
 static inline unsigned long
-arm_gen_branch_link(unsigned long pc, unsigned long addr)
+arm_gen_branch_link(unsigned long pc, unsigned long addr, bool warn)
 {
-	return __arm_gen_branch(pc, addr, true);
+	return __arm_gen_branch(pc, addr, true, warn);
 }
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/io.h
+++ linux-ein-5.4.0/arch/arm/include/asm/io.h
@@ -138,6 +138,7 @@
 	void *);
 extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
 extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
+void __arm_iomem_set_ro(void __iomem *ptr, size_t size);
 extern void __iounmap(volatile void __iomem *addr);
 
 extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
@@ -457,6 +458,9 @@
 extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
 extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
 extern int devmem_is_allowed(unsigned long pfn);
+extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
+					unsigned long flags);
+#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
 #endif
 
 /*
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kexec-internal.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kexec-internal.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ARM_KEXEC_INTERNAL_H
+#define _ARM_KEXEC_INTERNAL_H
+
+struct kexec_relocate_data {
+	unsigned long kexec_start_address;
+	unsigned long kexec_indirection_page;
+	unsigned long kexec_mach_type;
+	unsigned long kexec_r2;
+};
+
+#endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kprobes.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kprobes.h
@@ -44,20 +44,20 @@
 			     unsigned long val, void *data);
 
 /* optinsn template addresses */
-extern __visible kprobe_opcode_t optprobe_template_entry;
-extern __visible kprobe_opcode_t optprobe_template_val;
-extern __visible kprobe_opcode_t optprobe_template_call;
-extern __visible kprobe_opcode_t optprobe_template_end;
-extern __visible kprobe_opcode_t optprobe_template_sub_sp;
-extern __visible kprobe_opcode_t optprobe_template_add_sp;
-extern __visible kprobe_opcode_t optprobe_template_restore_begin;
-extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn;
-extern __visible kprobe_opcode_t optprobe_template_restore_end;
+extern __visible kprobe_opcode_t optprobe_template_entry[];
+extern __visible kprobe_opcode_t optprobe_template_val[];
+extern __visible kprobe_opcode_t optprobe_template_call[];
+extern __visible kprobe_opcode_t optprobe_template_end[];
+extern __visible kprobe_opcode_t optprobe_template_sub_sp[];
+extern __visible kprobe_opcode_t optprobe_template_add_sp[];
+extern __visible kprobe_opcode_t optprobe_template_restore_begin[];
+extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn[];
+extern __visible kprobe_opcode_t optprobe_template_restore_end[];
 
 #define MAX_OPTIMIZED_LENGTH	4
 #define MAX_OPTINSN_SIZE				\
-	((unsigned long)&optprobe_template_end -	\
-	 (unsigned long)&optprobe_template_entry)
+	((unsigned long)optprobe_template_end -	\
+	 (unsigned long)optprobe_template_entry)
 #define RELATIVEJUMP_SIZE	4
 
 struct arch_optimized_insn {
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kvm_asm.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kvm_asm.h
@@ -56,7 +56,7 @@
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
-extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
+extern void __kvm_flush_cpu_context(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kvm_emulate.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kvm_emulate.h
@@ -14,13 +14,25 @@
 #include <asm/cputype.h>
 
 /* arm64 compatibility macros */
+#define PSR_AA32_MODE_FIQ	FIQ_MODE
+#define PSR_AA32_MODE_SVC	SVC_MODE
 #define PSR_AA32_MODE_ABT	ABT_MODE
 #define PSR_AA32_MODE_UND	UND_MODE
 #define PSR_AA32_T_BIT		PSR_T_BIT
+#define PSR_AA32_F_BIT		PSR_F_BIT
 #define PSR_AA32_I_BIT		PSR_I_BIT
 #define PSR_AA32_A_BIT		PSR_A_BIT
 #define PSR_AA32_E_BIT		PSR_E_BIT
 #define PSR_AA32_IT_MASK	PSR_IT_MASK
+#define PSR_AA32_GE_MASK	0x000f0000
+#define PSR_AA32_DIT_BIT	0x00200000
+#define PSR_AA32_PAN_BIT	0x00400000
+#define PSR_AA32_SSBS_BIT	0x00800000
+#define PSR_AA32_Q_BIT		PSR_Q_BIT
+#define PSR_AA32_V_BIT		PSR_V_BIT
+#define PSR_AA32_C_BIT		PSR_C_BIT
+#define PSR_AA32_Z_BIT		PSR_Z_BIT
+#define PSR_AA32_N_BIT		PSR_N_BIT
 
 unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
 
@@ -41,6 +53,11 @@
 	*__vcpu_spsr(vcpu) = v;
 }
 
+static inline unsigned long host_spsr_to_spsr32(unsigned long spsr)
+{
+	return spsr;
+}
+
 static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
 					 u8 reg_num)
 {
@@ -177,12 +194,17 @@
 	return kvm_vcpu_get_hsr(vcpu) & HSR_SSE;
 }
 
+static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
+{
+	return false;
+}
+
 static inline int kvm_vcpu_dabt_get_rd(struct kvm_vcpu *vcpu)
 {
 	return (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT;
 }
 
-static inline bool kvm_vcpu_dabt_iss1tw(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_S1PTW;
 }
@@ -214,16 +236,21 @@
 	return kvm_vcpu_get_hsr(vcpu) & HSR_IL;
 }
 
-static inline u8 kvm_vcpu_trap_get_class(struct kvm_vcpu *vcpu)
+static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) >> HSR_EC_SHIFT;
 }
 
-static inline bool kvm_vcpu_trap_is_iabt(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_trap_get_class(vcpu) == HSR_EC_IABT;
 }
 
+static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
+{
+	return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
+}
+
 static inline u8 kvm_vcpu_trap_get_fault(struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & HSR_FSC;
@@ -341,6 +368,7 @@
 	}
 }
 
-static inline void vcpu_ptrauth_setup_lazy(struct kvm_vcpu *vcpu) {}
+static inline bool vcpu_has_ptrauth(struct kvm_vcpu *vcpu) { return false; }
+static inline void vcpu_ptrauth_disable(struct kvm_vcpu *vcpu) { }
 
 #endif /* __ARM_KVM_EMULATE_H__ */
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kvm_host.h
@@ -266,7 +266,7 @@
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva_range(struct kvm *kvm,
-			unsigned long start, unsigned long end);
+			unsigned long start, unsigned long end, unsigned flags);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
@@ -335,6 +335,7 @@
 static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 
 static inline void kvm_arm_init_debug(void) {}
+static inline void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {}
@@ -421,4 +422,6 @@
 	return true;
 }
 
+#define kvm_arm_vcpu_loaded(vcpu)	(false)
+
 #endif /* __ARM_KVM_HOST_H__ */
--- linux-ein-5.4.0.orig/arch/arm/include/asm/kvm_mmio.h
+++ linux-ein-5.4.0/arch/arm/include/asm/kvm_mmio.h
@@ -14,6 +14,8 @@
 struct kvm_decode {
 	unsigned long rt;
 	bool sign_extend;
+	/* Not used on 32-bit arm */
+	bool sixty_four;
 };
 
 void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
--- linux-ein-5.4.0.orig/arch/arm/include/asm/mach/map.h
+++ linux-ein-5.4.0/arch/arm/include/asm/mach/map.h
@@ -27,6 +27,7 @@
 	MT_HIGH_VECTORS,
 	MT_MEMORY_RWX,
 	MT_MEMORY_RW,
+	MT_MEMORY_RO,
 	MT_ROM,
 	MT_MEMORY_RWX_NONCACHED,
 	MT_MEMORY_RW_DTCM,
--- linux-ein-5.4.0.orig/arch/arm/include/asm/memory.h
+++ linux-ein-5.4.0/arch/arm/include/asm/memory.h
@@ -67,6 +67,10 @@
  */
 #define XIP_VIRT_ADDR(physaddr)  (MODULES_VADDR + ((physaddr) & 0x000fffff))
 
+#define FDT_FIXED_BASE		UL(0xff800000)
+#define FDT_FIXED_SIZE		(2 * SECTION_SIZE)
+#define FDT_VIRT_BASE(physbase)	((void *)(FDT_FIXED_BASE | (physbase) % SECTION_SIZE))
+
 #if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
 /*
  * Allow 16MB-aligned ioremap pages
@@ -107,6 +111,7 @@
 #define MODULES_VADDR		PAGE_OFFSET
 
 #define XIP_VIRT_ADDR(physaddr)  (physaddr)
+#define FDT_VIRT_BASE(physbase)  ((void *)(physbase))
 
 #endif /* !CONFIG_MMU */
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/module.h
+++ linux-ein-5.4.0/arch/arm/include/asm/module.h
@@ -19,8 +19,18 @@
 };
 #endif
 
+#define PLT_ENT_STRIDE		L1_CACHE_BYTES
+#define PLT_ENT_COUNT		(PLT_ENT_STRIDE / sizeof(u32))
+#define PLT_ENT_SIZE		(sizeof(struct plt_entries) / PLT_ENT_COUNT)
+
+struct plt_entries {
+	u32	ldr[PLT_ENT_COUNT];
+	u32	lit[PLT_ENT_COUNT];
+};
+
 struct mod_plt_sec {
 	struct elf32_shdr	*plt;
+	struct plt_entries	*plt_ent;
 	int			plt_count;
 };
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/percpu.h
+++ linux-ein-5.4.0/arch/arm/include/asm/percpu.h
@@ -5,6 +5,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-ein-5.4.0.orig/arch/arm/include/asm/perf_event.h
+++ linux-ein-5.4.0/arch/arm/include/asm/perf_event.h
@@ -17,7 +17,7 @@
 
 #define perf_arch_fetch_caller_regs(regs, __ip) { \
 	(regs)->ARM_pc = (__ip); \
-	(regs)->ARM_fp = (unsigned long) __builtin_frame_address(0); \
+	frame_pointer((regs)) = (unsigned long) __builtin_frame_address(0); \
 	(regs)->ARM_sp = current_stack_pointer; \
 	(regs)->ARM_cpsr = SVC_MODE; \
 }
--- linux-ein-5.4.0.orig/arch/arm/include/asm/pgtable-2level.h
+++ linux-ein-5.4.0/arch/arm/include/asm/pgtable-2level.h
@@ -75,6 +75,8 @@
 #define PTE_HWTABLE_OFF		(PTE_HWTABLE_PTRS * sizeof(pte_t))
 #define PTE_HWTABLE_SIZE	(PTRS_PER_PTE * sizeof(u32))
 
+#define MAX_POSSIBLE_PHYSMEM_BITS	32
+
 /*
  * PMD_SHIFT determines the size of the area a second-level page table can map
  * PGDIR_SHIFT determines what a third-level page table entry can map
--- linux-ein-5.4.0.orig/arch/arm/include/asm/pgtable-3level.h
+++ linux-ein-5.4.0/arch/arm/include/asm/pgtable-3level.h
@@ -25,6 +25,8 @@
 #define PTE_HWTABLE_OFF		(0)
 #define PTE_HWTABLE_SIZE	(PTRS_PER_PTE * sizeof(u64))
 
+#define MAX_POSSIBLE_PHYSMEM_BITS 40
+
 /*
  * PGDIR_SHIFT determines the size a top-level page table entry can map.
  */
--- linux-ein-5.4.0.orig/arch/arm/include/asm/pgtable-nommu.h
+++ linux-ein-5.4.0/arch/arm/include/asm/pgtable-nommu.h
@@ -52,12 +52,6 @@
 typedef pte_t *pte_addr_t;
 
 /*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-#define ZERO_PAGE(vaddr)	(virt_to_page(0))
-
-/*
  * Mark the prot value as uncacheable and unbufferable.
  */
 #define pgprot_noncached(prot)	(prot)
--- linux-ein-5.4.0.orig/arch/arm/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/arm/include/asm/pgtable.h
@@ -10,6 +10,15 @@
 #include <linux/const.h>
 #include <asm/proc-fns.h>
 
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern struct page *empty_zero_page;
+#define ZERO_PAGE(vaddr)	(empty_zero_page)
+#endif
+
 #ifndef CONFIG_MMU
 
 #include <asm-generic/4level-fixup.h>
@@ -166,13 +175,6 @@
 #define __S111  __PAGE_SHARED_EXEC
 
 #ifndef __ASSEMBLY__
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern struct page *empty_zero_page;
-#define ZERO_PAGE(vaddr)	(empty_zero_page)
-
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
--- linux-ein-5.4.0.orig/arch/arm/include/asm/prom.h
+++ linux-ein-5.4.0/arch/arm/include/asm/prom.h
@@ -9,12 +9,12 @@
 
 #ifdef CONFIG_OF
 
-extern const struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
+extern const struct machine_desc *setup_machine_fdt(void *dt_virt);
 extern void __init arm_dt_init_cpu_maps(void);
 
 #else /* CONFIG_OF */
 
-static inline const struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
+static inline const struct machine_desc *setup_machine_fdt(void *dt_virt)
 {
 	return NULL;
 }
--- linux-ein-5.4.0.orig/arch/arm/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/arm/include/asm/ptrace.h
@@ -164,5 +164,31 @@
 		((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1;	\
 })
 
+
+/*
+ * Update ITSTATE after normal execution of an IT block instruction.
+ *
+ * The 8 IT state bits are split into two parts in CPSR:
+ *	ITSTATE<1:0> are in CPSR<26:25>
+ *	ITSTATE<7:2> are in CPSR<15:10>
+ */
+static inline unsigned long it_advance(unsigned long cpsr)
+{
+	if ((cpsr & 0x06000400) == 0) {
+		/* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
+		cpsr &= ~PSR_IT_MASK;
+	} else {
+		/* We need to shift left ITSTATE<4:0> */
+		const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
+		unsigned long it = cpsr & mask;
+		it <<= 1;
+		it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
+		it &= mask;
+		cpsr &= ~mask;
+		cpsr |= it;
+	}
+	return cpsr;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/spectre.h
+++ linux-ein-5.4.0/arch/arm/include/asm/spectre.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_SPECTRE_H
+#define __ASM_SPECTRE_H
+
+enum {
+	SPECTRE_UNAFFECTED,
+	SPECTRE_MITIGATED,
+	SPECTRE_VULNERABLE,
+};
+
+enum {
+	__SPECTRE_V2_METHOD_BPIALL,
+	__SPECTRE_V2_METHOD_ICIALLU,
+	__SPECTRE_V2_METHOD_SMC,
+	__SPECTRE_V2_METHOD_HVC,
+	__SPECTRE_V2_METHOD_LOOP8,
+};
+
+enum {
+	SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL),
+	SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
+	SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
+	SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
+	SPECTRE_V2_METHOD_LOOP8 = BIT(__SPECTRE_V2_METHOD_LOOP8),
+};
+
+#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
+void spectre_v2_update_state(unsigned int state, unsigned int methods);
+#else
+static inline void spectre_v2_update_state(unsigned int state,
+					   unsigned int methods)
+{}
+#endif
+
+int spectre_bhb_update_vectors(unsigned int method);
+
+#endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/timex.h
+++ linux-ein-5.4.0/arch/arm/include/asm/timex.h
@@ -11,5 +11,6 @@
 
 typedef unsigned long cycles_t;
 #define get_cycles()	({ cycles_t c; read_current_timer(&c) ? 0 : c; })
+#define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm/include/asm/uaccess-asm.h
+++ linux-ein-5.4.0/arch/arm/include/asm/uaccess-asm.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_UACCESS_ASM_H__
+#define __ASM_UACCESS_ASM_H__
+
+#include <asm/asm-offsets.h>
+#include <asm/domain.h>
+#include <asm/memory.h>
+#include <asm/thread_info.h>
+
+	.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
+	sbcscc	\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) {
+	subshs	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
+	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
+	csdb
+#endif
+	.endm
+
+	.macro	uaccess_disable, tmp, isb=1
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+	/*
+	 * Whenever we re-enter userspace, the domains should always be
+	 * set appropriately.
+	 */
+	mov	\tmp, #DACR_UACCESS_DISABLE
+	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
+	.if	\isb
+	instr_sync
+	.endif
+#endif
+	.endm
+
+	.macro	uaccess_enable, tmp, isb=1
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+	/*
+	 * Whenever we re-enter userspace, the domains should always be
+	 * set appropriately.
+	 */
+	mov	\tmp, #DACR_UACCESS_ENABLE
+	mcr	p15, 0, \tmp, c3, c0, 0
+	.if	\isb
+	instr_sync
+	.endif
+#endif
+	.endm
+
+#if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS)
+#define DACR(x...)	x
+#else
+#define DACR(x...)
+#endif
+
+	/*
+	 * Save the address limit on entry to a privileged exception.
+	 *
+	 * If we are using the DACR for kernel access by the user accessors
+	 * (CONFIG_CPU_USE_DOMAINS=y), always reset the DACR kernel domain
+	 * back to client mode, whether or not \disable is set.
+	 *
+	 * If we are using SW PAN, set the DACR user domain to no access
+	 * if \disable is set.
+	 */
+	.macro	uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
+	ldr	\tmp1, [\tsk, #TI_ADDR_LIMIT]
+	mov	\tmp2, #TASK_SIZE
+	str	\tmp2, [\tsk, #TI_ADDR_LIMIT]
+ DACR(	mrc	p15, 0, \tmp0, c3, c0, 0)
+ DACR(	str	\tmp0, [sp, #SVC_DACR])
+	str	\tmp1, [sp, #SVC_ADDR_LIMIT]
+	.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
+	/* kernel=client, user=no access */
+	mov	\tmp2, #DACR_UACCESS_DISABLE
+	mcr	p15, 0, \tmp2, c3, c0, 0
+	instr_sync
+	.elseif IS_ENABLED(CONFIG_CPU_USE_DOMAINS)
+	/* kernel=client */
+	bic	\tmp2, \tmp0, #domain_mask(DOMAIN_KERNEL)
+	orr	\tmp2, \tmp2, #domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT)
+	mcr	p15, 0, \tmp2, c3, c0, 0
+	instr_sync
+	.endif
+	.endm
+
+	/* Restore the user access state previously saved by uaccess_entry */
+	.macro	uaccess_exit, tsk, tmp0, tmp1
+	ldr	\tmp1, [sp, #SVC_ADDR_LIMIT]
+ DACR(	ldr	\tmp0, [sp, #SVC_DACR])
+	str	\tmp1, [\tsk, #TI_ADDR_LIMIT]
+ DACR(	mcr	p15, 0, \tmp0, c3, c0, 0)
+	.endm
+
+#undef DACR
+
+#endif /* __ASM_UACCESS_ASM_H__ */
--- linux-ein-5.4.0.orig/arch/arm/include/asm/vfpmacros.h
+++ linux-ein-5.4.0/arch/arm/include/asm/vfpmacros.h
@@ -19,23 +19,25 @@
 
 	@ read all the working registers back into the VFP
 	.macro	VFPFLDMIA, base, tmp
+	.fpu	vfpv2
 #if __LINUX_ARM_ARCH__ < 6
-	LDC	p11, cr0, [\base],#33*4		    @ FLDMIAX \base!, {d0-d15}
+	fldmiax	\base!, {d0-d15}
 #else
-	LDC	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d0-d15}
+	vldmia	\base!, {d0-d15}
 #endif
 #ifdef CONFIG_VFPv3
+	.fpu	vfpv3
 #if __LINUX_ARM_ARCH__ <= 6
 	ldr	\tmp, =elf_hwcap		    @ may not have MVFR regs
 	ldr	\tmp, [\tmp, #0]
 	tst	\tmp, #HWCAP_VFPD32
-	ldclne	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d16-d31}
+	vldmiane \base!, {d16-d31}
 	addeq	\base, \base, #32*4		    @ step over unused register space
 #else
 	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
 	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
 	cmp	\tmp, #2			    @ 32 x 64bit registers?
-	ldcleq	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d16-d31}
+	vldmiaeq \base!, {d16-d31}
 	addne	\base, \base, #32*4		    @ step over unused register space
 #endif
 #endif
@@ -44,22 +46,23 @@
 	@ write all the working registers out of the VFP
 	.macro	VFPFSTMIA, base, tmp
 #if __LINUX_ARM_ARCH__ < 6
-	STC	p11, cr0, [\base],#33*4		    @ FSTMIAX \base!, {d0-d15}
+	fstmiax	\base!, {d0-d15}
 #else
-	STC	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d0-d15}
+	vstmia	\base!, {d0-d15}
 #endif
 #ifdef CONFIG_VFPv3
+	.fpu	vfpv3
 #if __LINUX_ARM_ARCH__ <= 6
 	ldr	\tmp, =elf_hwcap		    @ may not have MVFR regs
 	ldr	\tmp, [\tmp, #0]
 	tst	\tmp, #HWCAP_VFPD32
-	stclne	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d16-d31}
+	vstmiane \base!, {d16-d31}
 	addeq	\base, \base, #32*4		    @ step over unused register space
 #else
 	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
 	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
 	cmp	\tmp, #2			    @ 32 x 64bit registers?
-	stcleq	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d16-d31}
+	vstmiaeq \base!, {d16-d31}
 	addne	\base, \base, #32*4		    @ step over unused register space
 #endif
 #endif
--- linux-ein-5.4.0.orig/arch/arm/kernel/Makefile
+++ linux-ein-5.4.0/arch/arm/kernel/Makefile
@@ -17,10 +17,14 @@
 # Object file lists.
 
 obj-y		:= elf.o entry-common.o irq.o opcodes.o \
-		   process.o ptrace.o reboot.o return_address.o \
+		   process.o ptrace.o reboot.o \
 		   setup.o signal.o sigreturn_codes.o \
 		   stacktrace.o sys_arm.o time.o traps.o
 
+ifneq ($(CONFIG_ARM_UNWIND),y)
+obj-$(CONFIG_FRAME_POINTER)	+= return_address.o
+endif
+
 obj-$(CONFIG_ATAGS)		+= atags_parse.o
 obj-$(CONFIG_ATAGS_PROC)	+= atags_proc.o
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
@@ -102,4 +106,6 @@
 
 obj-$(CONFIG_HAVE_ARM_SMCCC)	+= smccc-call.o
 
+obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o
+
 extra-y := $(head-y) vmlinux.lds
--- linux-ein-5.4.0.orig/arch/arm/kernel/asm-offsets.c
+++ linux-ein-5.4.0/arch/arm/kernel/asm-offsets.c
@@ -15,6 +15,7 @@
 #include <linux/kvm_host.h>
 #endif
 #include <asm/cacheflush.h>
+#include <asm/kexec-internal.h>
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
 #include <asm/mach/arch.h>
@@ -26,6 +27,7 @@
 #include <asm/vdso_datapage.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <linux/kbuild.h>
+#include <linux/arm-smccc.h>
 #include "signal.h"
 
 /*
@@ -159,6 +161,8 @@
   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_QUIRK_ID_OFFS,	offsetof(struct arm_smccc_quirk, id));
+  DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS,	offsetof(struct arm_smccc_quirk, state));
   BLANK();
   DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
   DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
@@ -190,5 +194,9 @@
   DEFINE(MPU_RGN_PRBAR,	offsetof(struct mpu_rgn, prbar));
   DEFINE(MPU_RGN_PRLAR,	offsetof(struct mpu_rgn, prlar));
 #endif
+  DEFINE(KEXEC_START_ADDR,	offsetof(struct kexec_relocate_data, kexec_start_address));
+  DEFINE(KEXEC_INDIR_PAGE,	offsetof(struct kexec_relocate_data, kexec_indirection_page));
+  DEFINE(KEXEC_MACH_TYPE,	offsetof(struct kexec_relocate_data, kexec_mach_type));
+  DEFINE(KEXEC_R2,		offsetof(struct kexec_relocate_data, kexec_r2));
   return 0; 
 }
--- linux-ein-5.4.0.orig/arch/arm/kernel/atags.h
+++ linux-ein-5.4.0/arch/arm/kernel/atags.h
@@ -2,11 +2,11 @@
 void convert_to_tag_list(struct tag *tags);
 
 #ifdef CONFIG_ATAGS
-const struct machine_desc *setup_machine_tags(phys_addr_t __atags_pointer,
+const struct machine_desc *setup_machine_tags(void *__atags_vaddr,
 	unsigned int machine_nr);
 #else
 static inline const struct machine_desc * __init __noreturn
-setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
+setup_machine_tags(void *__atags_vaddr, unsigned int machine_nr)
 {
 	early_print("no ATAGS support: can't continue\n");
 	while (true);
--- linux-ein-5.4.0.orig/arch/arm/kernel/atags_parse.c
+++ linux-ein-5.4.0/arch/arm/kernel/atags_parse.c
@@ -176,7 +176,7 @@
 }
 
 const struct machine_desc * __init
-setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
+setup_machine_tags(void *atags_vaddr, unsigned int machine_nr)
 {
 	struct tag *tags = (struct tag *)&default_tags;
 	const struct machine_desc *mdesc = NULL, *p;
@@ -197,8 +197,8 @@
 	if (!mdesc)
 		return NULL;
 
-	if (__atags_pointer)
-		tags = phys_to_virt(__atags_pointer);
+	if (atags_vaddr)
+		tags = atags_vaddr;
 	else if (mdesc->atag_offset)
 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/bugs.c
+++ linux-ein-5.4.0/arch/arm/kernel/bugs.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/init.h>
+#include <linux/cpu.h>
 #include <asm/bugs.h>
 #include <asm/proc-fns.h>
 
@@ -11,7 +12,7 @@
 #endif
 }
 
-void __init check_bugs(void)
+void __init arch_cpu_finalize_init(void)
 {
 	check_writebuffer_bugs();
 	check_other_bugs();
--- linux-ein-5.4.0.orig/arch/arm/kernel/devtree.c
+++ linux-ein-5.4.0/arch/arm/kernel/devtree.c
@@ -203,12 +203,12 @@
 
 /**
  * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
- * @dt_phys: physical address of dt blob
+ * @dt_virt: virtual address of dt blob
  *
  * If a dtb was passed to the kernel in r2, then use it to choose the
  * correct machine_desc and to setup the system.
  */
-const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
+const struct machine_desc * __init setup_machine_fdt(void *dt_virt)
 {
 	const struct machine_desc *mdesc, *mdesc_best = NULL;
 
@@ -221,7 +221,7 @@
 	mdesc_best = &__mach_desc_GENERIC_DT;
 #endif
 
-	if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))
+	if (!dt_virt || !early_init_dt_verify(dt_virt))
 		return NULL;
 
 	mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
--- linux-ein-5.4.0.orig/arch/arm/kernel/entry-armv.S
+++ linux-ein-5.4.0/arch/arm/kernel/entry-armv.S
@@ -27,6 +27,7 @@
 #include <asm/unistd.h>
 #include <asm/tls.h>
 #include <asm/system_info.h>
+#include <asm/uaccess-asm.h>
 
 #include "entry-header.S"
 #include <asm/entry-macro-multi.S>
@@ -179,15 +180,7 @@
 	stmia	r7, {r2 - r6}
 
 	get_thread_info tsk
-	ldr	r0, [tsk, #TI_ADDR_LIMIT]
-	mov	r1, #TASK_SIZE
-	str	r1, [tsk, #TI_ADDR_LIMIT]
-	str	r0, [sp, #SVC_ADDR_LIMIT]
-
-	uaccess_save r0
-	.if \uaccess
-	uaccess_disable r0
-	.endif
+	uaccess_entry tsk, r0, r1, r2, \uaccess
 
 	.if \trace
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -259,31 +252,10 @@
 #else
 	svc_entry
 #endif
-	@
-	@ call emulation code, which returns using r9 if it has emulated
-	@ the instruction, or the more conventional lr if we are to treat
-	@ this as a real undefined instruction
-	@
-	@  r0 - instruction
-	@
-#ifndef CONFIG_THUMB2_KERNEL
-	ldr	r0, [r4, #-4]
-#else
-	mov	r1, #2
-	ldrh	r0, [r4, #-2]			@ Thumb instruction at LR - 2
-	cmp	r0, #0xe800			@ 32-bit instruction if xx >= 0
-	blo	__und_svc_fault
-	ldrh	r9, [r4]			@ bottom 16 bits
-	add	r4, r4, #2
-	str	r4, [sp, #S_PC]
-	orr	r0, r9, r0, lsl #16
-#endif
-	badr	r9, __und_svc_finish
-	mov	r2, r4
-	bl	call_fpe
 
 	mov	r1, #4				@ PC correction to apply
-__und_svc_fault:
+ THUMB(	tst	r5, #PSR_T_BIT		)	@ exception taken in Thumb mode?
+ THUMB(	movne	r1, #2			)	@ if so, fix up PC correction
 	mov	r0, sp				@ struct pt_regs *regs
 	bl	__und_fault
 
@@ -624,11 +596,9 @@
 	tstne	r0, #0x04000000			@ bit 26 set on both ARM and Thumb-2
 	reteq	lr
 	and	r8, r0, #0x00000f00		@ mask out CP number
- THUMB(	lsr	r8, r8, #8		)
 	mov	r7, #1
-	add	r6, r10, #TI_USED_CP
- ARM(	strb	r7, [r6, r8, lsr #8]	)	@ set appropriate used_cp[]
- THUMB(	strb	r7, [r6, r8]		)	@ set appropriate used_cp[]
+	add	r6, r10, r8, lsr #8		@ add used_cp[] array offset first
+	strb	r7, [r6, #TI_USED_CP]		@ set appropriate used_cp[]
 #ifdef CONFIG_IWMMXT
 	@ Test if we need to give access to iWMMXt coprocessors
 	ldr	r5, [r10, #TI_FLAGS]
@@ -637,7 +607,7 @@
 	bcs	iwmmxt_task_enable
 #endif
  ARM(	add	pc, pc, r8, lsr #6	)
- THUMB(	lsl	r8, r8, #2		)
+ THUMB(	lsr	r8, r8, #6		)
  THUMB(	add	pc, r8			)
 	nop
 
@@ -1035,12 +1005,11 @@
 	sub	lr, lr, #\correction
 	.endif
 
-	@
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-	@ (parent CPSR)
-	@
+	@ Save r0, lr_<exception> (parent PC)
 	stmia	sp, {r0, lr}		@ save r0, lr
-	mrs	lr, spsr
+
+	@ Save spsr_<exception> (parent CPSR)
+2:	mrs	lr, spsr
 	str	lr, [sp, #8]		@ save spsr
 
 	@
@@ -1061,6 +1030,44 @@
 	movs	pc, lr			@ branch to handler in SVC mode
 ENDPROC(vector_\name)
 
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+	.subsection 1
+	.align 5
+vector_bhb_loop8_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@ Save r0, lr_<exception> (parent PC)
+	stmia	sp, {r0, lr}
+
+	@ bhb workaround
+	mov	r0, #8
+3:	W(b)	. + 4
+	subs	r0, r0, #1
+	bne	3b
+	dsb
+	isb
+	b	2b
+ENDPROC(vector_bhb_loop8_\name)
+
+vector_bhb_bpiall_\name:
+	.if \correction
+	sub	lr, lr, #\correction
+	.endif
+
+	@ Save r0, lr_<exception> (parent PC)
+	stmia	sp, {r0, lr}
+
+	@ bhb workaround
+	mcr	p15, 0, r0, c7, c5, 6	@ BPIALL
+	@ isb not needed due to "movs pc, lr" in the vector stub
+	@ which gives a "context synchronisation".
+	b	2b
+ENDPROC(vector_bhb_bpiall_\name)
+	.previous
+#endif
+
 	.align	2
 	@ handler addresses follow this label
 1:
@@ -1069,6 +1076,10 @@
 	.section .stubs, "ax", %progbits
 	@ This must be the first word
 	.word	vector_swi
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+	.word	vector_bhb_loop8_swi
+	.word	vector_bhb_bpiall_swi
+#endif
 
 vector_rst:
  ARM(	swi	SYS_ERROR0	)
@@ -1183,8 +1194,10 @@
  * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
  * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
- * systems.
+ * systems. This must be the last vector stub, so lets place it in its own
+ * subsection.
  */
+	.subsection 2
 	vector_stub	fiq, FIQ_MODE, 4
 
 	.long	__fiq_usr			@  0  (USR_26 / USR_32)
@@ -1217,6 +1230,30 @@
 	W(b)	vector_irq
 	W(b)	vector_fiq
 
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+	.section .vectors.bhb.loop8, "ax", %progbits
+.L__vectors_bhb_loop8_start:
+	W(b)	vector_rst
+	W(b)	vector_bhb_loop8_und
+	W(ldr)	pc, .L__vectors_bhb_loop8_start + 0x1004
+	W(b)	vector_bhb_loop8_pabt
+	W(b)	vector_bhb_loop8_dabt
+	W(b)	vector_addrexcptn
+	W(b)	vector_bhb_loop8_irq
+	W(b)	vector_bhb_loop8_fiq
+
+	.section .vectors.bhb.bpiall, "ax", %progbits
+.L__vectors_bhb_bpiall_start:
+	W(b)	vector_rst
+	W(b)	vector_bhb_bpiall_und
+	W(ldr)	pc, .L__vectors_bhb_bpiall_start + 0x1008
+	W(b)	vector_bhb_bpiall_pabt
+	W(b)	vector_bhb_bpiall_dabt
+	W(b)	vector_addrexcptn
+	W(b)	vector_bhb_bpiall_irq
+	W(b)	vector_bhb_bpiall_fiq
+#endif
+
 	.data
 	.align	2
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/entry-common.S
+++ linux-ein-5.4.0/arch/arm/kernel/entry-common.S
@@ -163,12 +163,36 @@
  */
 
 	.align	5
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+ENTRY(vector_bhb_loop8_swi)
+	sub	sp, sp, #PT_REGS_SIZE
+	stmia	sp, {r0 - r12}
+	mov	r8, #8
+1:	b	2f
+2:	subs	r8, r8, #1
+	bne	1b
+	dsb
+	isb
+	b	3f
+ENDPROC(vector_bhb_loop8_swi)
+
+	.align	5
+ENTRY(vector_bhb_bpiall_swi)
+	sub	sp, sp, #PT_REGS_SIZE
+	stmia	sp, {r0 - r12}
+	mcr	p15, 0, r8, c7, c5, 6	@ BPIALL
+	isb
+	b	3f
+ENDPROC(vector_bhb_bpiall_swi)
+#endif
+	.align	5
 ENTRY(vector_swi)
 #ifdef CONFIG_CPU_V7M
 	v7m_exception_entry
 #else
 	sub	sp, sp, #PT_REGS_SIZE
 	stmia	sp, {r0 - r12}			@ Calling r0 - r12
+3:
  ARM(	add	r8, sp, #S_PC		)
  ARM(	stmdb	r8, {sp, lr}^		)	@ Calling sp, lr
  THUMB(	mov	r8, sp			)
--- linux-ein-5.4.0.orig/arch/arm/kernel/entry-header.S
+++ linux-ein-5.4.0/arch/arm/kernel/entry-header.S
@@ -6,6 +6,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/errno.h>
 #include <asm/thread_info.h>
+#include <asm/uaccess-asm.h>
 #include <asm/v7m.h>
 
 @ Bad Abort numbers
@@ -217,9 +218,7 @@
 	blne	trace_hardirqs_off
 #endif
 	.endif
-	ldr	r1, [sp, #SVC_ADDR_LIMIT]
-	uaccess_restore
-	str	r1, [tsk, #TI_ADDR_LIMIT]
+	uaccess_exit tsk, r0, r1
 
 #ifndef CONFIG_THUMB2_KERNEL
 	@ ARM mode SVC restore
@@ -263,9 +262,7 @@
 	@ on the stack remains correct).
 	@
 	.macro  svc_exit_via_fiq
-	ldr	r1, [sp, #SVC_ADDR_LIMIT]
-	uaccess_restore
-	str	r1, [tsk, #TI_ADDR_LIMIT]
+	uaccess_exit tsk, r0, r1
 #ifndef CONFIG_THUMB2_KERNEL
 	@ ARM mode restore
 	mov	r0, sp
--- linux-ein-5.4.0.orig/arch/arm/kernel/ftrace.c
+++ linux-ein-5.4.0/arch/arm/kernel/ftrace.c
@@ -71,9 +71,10 @@
 	return 0;
 }
 
-static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr,
+					 bool warn)
 {
-	return arm_gen_branch_link(pc, addr);
+	return arm_gen_branch_link(pc, addr, warn);
 }
 
 static int ftrace_modify_code(unsigned long pc, unsigned long old,
@@ -112,14 +113,14 @@
 	int ret;
 
 	pc = (unsigned long)&ftrace_call;
-	new = ftrace_call_replace(pc, (unsigned long)func);
+	new = ftrace_call_replace(pc, (unsigned long)func, true);
 
 	ret = ftrace_modify_code(pc, 0, new, false);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 	if (!ret) {
 		pc = (unsigned long)&ftrace_regs_call;
-		new = ftrace_call_replace(pc, (unsigned long)func);
+		new = ftrace_call_replace(pc, (unsigned long)func, true);
 
 		ret = ftrace_modify_code(pc, 0, new, false);
 	}
@@ -132,10 +133,22 @@
 {
 	unsigned long new, old;
 	unsigned long ip = rec->ip;
+	unsigned long aaddr = adjust_address(rec, addr);
+	struct module *mod = NULL;
+
+#ifdef CONFIG_ARM_MODULE_PLTS
+	mod = rec->arch.mod;
+#endif
 
 	old = ftrace_nop_replace(rec);
 
-	new = ftrace_call_replace(ip, adjust_address(rec, addr));
+	new = ftrace_call_replace(ip, aaddr, !mod);
+#ifdef CONFIG_ARM_MODULE_PLTS
+	if (!new && mod) {
+		aaddr = get_module_plt(mod, ip, aaddr);
+		new = ftrace_call_replace(ip, aaddr, true);
+	}
+#endif
 
 	return ftrace_modify_code(rec->ip, old, new, true);
 }
@@ -148,9 +161,9 @@
 	unsigned long new, old;
 	unsigned long ip = rec->ip;
 
-	old = ftrace_call_replace(ip, adjust_address(rec, old_addr));
+	old = ftrace_call_replace(ip, adjust_address(rec, old_addr), true);
 
-	new = ftrace_call_replace(ip, adjust_address(rec, addr));
+	new = ftrace_call_replace(ip, adjust_address(rec, addr), true);
 
 	return ftrace_modify_code(rec->ip, old, new, true);
 }
@@ -160,12 +173,29 @@
 int ftrace_make_nop(struct module *mod,
 		    struct dyn_ftrace *rec, unsigned long addr)
 {
+	unsigned long aaddr = adjust_address(rec, addr);
 	unsigned long ip = rec->ip;
 	unsigned long old;
 	unsigned long new;
 	int ret;
 
-	old = ftrace_call_replace(ip, adjust_address(rec, addr));
+#ifdef CONFIG_ARM_MODULE_PLTS
+	/* mod is only supplied during module loading */
+	if (!mod)
+		mod = rec->arch.mod;
+	else
+		rec->arch.mod = mod;
+#endif
+
+	old = ftrace_call_replace(ip, aaddr,
+				  !IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || !mod);
+#ifdef CONFIG_ARM_MODULE_PLTS
+	if (!old && mod) {
+		aaddr = get_module_plt(mod, ip, aaddr);
+		old = ftrace_call_replace(ip, aaddr, true);
+	}
+#endif
+
 	new = ftrace_nop_replace(rec);
 	ret = ftrace_modify_code(ip, old, new, true);
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/head.S
+++ linux-ein-5.4.0/arch/arm/kernel/head.S
@@ -274,11 +274,10 @@
 	 * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
 	 */
 	mov	r0, r2, lsr #SECTION_SHIFT
-	movs	r0, r0, lsl #SECTION_SHIFT
-	subne	r3, r0, r8
-	addne	r3, r3, #PAGE_OFFSET
-	addne	r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
-	orrne	r6, r7, r0
+	cmp	r2, #0
+	ldrne	r3, =FDT_FIXED_BASE >> (SECTION_SHIFT - PMD_ORDER)
+	addne	r3, r3, r4
+	orrne	r6, r7, r0, lsl #SECTION_SHIFT
 	strne	r6, [r3], #1 << PMD_ORDER
 	addne	r6, r6, #1 << SECTION_SHIFT
 	strne	r6, [r3]
@@ -672,11 +671,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
@@ -685,7 +680,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-ein-5.4.0.orig/arch/arm/kernel/hw_breakpoint.c
+++ linux-ein-5.4.0/arch/arm/kernel/hw_breakpoint.c
@@ -623,7 +623,7 @@
 	hw->address &= ~alignment_mask;
 	hw->ctrl.len <<= offset;
 
-	if (is_default_overflow_handler(bp)) {
+	if (uses_default_overflow_handler(bp)) {
 		/*
 		 * Mismatch breakpoints are required for single-stepping
 		 * breakpoints.
@@ -680,26 +680,68 @@
 	arch_install_hw_breakpoint(bp);
 }
 
+/*
+ * Arm32 hardware does not always report a watchpoint hit address that matches
+ * one of the watchpoints set. It can also report an address "near" the
+ * watchpoint if a single instruction access both watched and unwatched
+ * addresses. There is no straight-forward way, short of disassembling the
+ * offending instruction, to map that address back to the watchpoint. This
+ * function computes the distance of the memory access from the watchpoint as a
+ * heuristic for the likelyhood that a given access triggered the watchpoint.
+ *
+ * See this same function in the arm64 platform code, which has the same
+ * problem.
+ *
+ * The function returns the distance of the address from the bytes watched by
+ * the watchpoint. In case of an exact match, it returns 0.
+ */
+static u32 get_distance_from_watchpoint(unsigned long addr, u32 val,
+					struct arch_hw_breakpoint_ctrl *ctrl)
+{
+	u32 wp_low, wp_high;
+	u32 lens, lene;
+
+	lens = __ffs(ctrl->len);
+	lene = __fls(ctrl->len);
+
+	wp_low = val + lens;
+	wp_high = val + lene;
+	if (addr < wp_low)
+		return wp_low - addr;
+	else if (addr > wp_high)
+		return addr - wp_high;
+	else
+		return 0;
+}
+
+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)
 {
-	int i, access;
-	u32 val, ctrl_reg, alignment_mask;
+	int i, access, closest_match = 0;
+	u32 min_dist = -1, dist;
+	u32 val, ctrl_reg;
 	struct perf_event *wp, **slots;
 	struct arch_hw_breakpoint *info;
 	struct arch_hw_breakpoint_ctrl ctrl;
 
 	slots = this_cpu_ptr(wp_on_reg);
 
+	/*
+	 * Find all watchpoints that match the reported address. If no exact
+	 * match is found. Attribute the hit to the closest watchpoint.
+	 */
+	rcu_read_lock();
 	for (i = 0; i < core_num_wrps; ++i) {
-		rcu_read_lock();
-
 		wp = slots[i];
-
 		if (wp == NULL)
-			goto unlock;
+			continue;
 
-		info = counter_arch_bp(wp);
 		/*
 		 * The DFAR is an unknown value on debug architectures prior
 		 * to 7.1. Since we only allow a single watchpoint on these
@@ -708,50 +750,69 @@
 		 */
 		if (debug_arch < ARM_DEBUG_ARCH_V7_1) {
 			BUG_ON(i > 0);
+			info = counter_arch_bp(wp);
 			info->trigger = wp->attr.bp_addr;
 		} else {
-			if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
-				alignment_mask = 0x7;
-			else
-				alignment_mask = 0x3;
-
-			/* Check if the watchpoint value matches. */
-			val = read_wb_reg(ARM_BASE_WVR + i);
-			if (val != (addr & ~alignment_mask))
-				goto unlock;
-
-			/* Possible match, check the byte address select. */
-			ctrl_reg = read_wb_reg(ARM_BASE_WCR + i);
-			decode_ctrl_reg(ctrl_reg, &ctrl);
-			if (!((1 << (addr & alignment_mask)) & ctrl.len))
-				goto unlock;
-
 			/* Check that the access type matches. */
 			if (debug_exception_updates_fsr()) {
 				access = (fsr & ARM_FSR_ACCESS_MASK) ?
 					  HW_BREAKPOINT_W : HW_BREAKPOINT_R;
 				if (!(access & hw_breakpoint_type(wp)))
-					goto unlock;
+					continue;
+			}
+
+			val = read_wb_reg(ARM_BASE_WVR + i);
+			ctrl_reg = read_wb_reg(ARM_BASE_WCR + i);
+			decode_ctrl_reg(ctrl_reg, &ctrl);
+			dist = get_distance_from_watchpoint(addr, val, &ctrl);
+			if (dist < min_dist) {
+				min_dist = dist;
+				closest_match = i;
 			}
+			/* Is this an exact match? */
+			if (dist != 0)
+				continue;
 
 			/* We have a winner. */
+			info = counter_arch_bp(wp);
 			info->trigger = addr;
 		}
 
 		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 (is_default_overflow_handler(wp))
-			enable_single_step(wp, instruction_pointer(regs));
+		if (!uses_default_overflow_handler(wp))
+			continue;
+step:
+		enable_single_step(wp, instruction_pointer(regs));
+	}
 
-unlock:
-		rcu_read_unlock();
+	if (min_dist > 0 && min_dist != -1) {
+		/* No exact match found. */
+		wp = slots[closest_match];
+		info = counter_arch_bp(wp);
+		info->trigger = addr;
+		pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
+		perf_bp_event(wp, regs);
+		if (uses_default_overflow_handler(wp))
+			enable_single_step(wp, instruction_pointer(regs));
 	}
+
+	rcu_read_unlock();
 }
 
 static void watchpoint_single_step_handler(unsigned long pc)
@@ -822,7 +883,7 @@
 			info->trigger = addr;
 			pr_debug("breakpoint fired: address = 0x%x\n", addr);
 			perf_bp_event(bp, regs);
-			if (!bp->overflow_handler)
+			if (uses_default_overflow_handler(bp))
 				enable_single_step(bp, addr);
 			goto unlock;
 		}
--- linux-ein-5.4.0.orig/arch/arm/kernel/hyp-stub.S
+++ linux-ein-5.4.0/arch/arm/kernel/hyp-stub.S
@@ -146,10 +146,9 @@
 #if !defined(ZIMAGE) && defined(CONFIG_ARM_ARCH_TIMER)
 	@ make CNTP_* and CNTPCT accessible from PL1
 	mrc	p15, 0, r7, c0, c1, 1	@ ID_PFR1
-	lsr	r7, #16
-	and	r7, #0xf
-	cmp	r7, #1
-	bne	1f
+	ubfx	r7, r7, #16, #4
+	teq	r7, #0
+	beq	1f
 	mrc	p15, 4, r7, c14, c1, 0	@ CNTHCTL
 	orr	r7, r7, #3		@ PL1PCEN | PL1PCTEN
 	mcr	p15, 4, r7, c14, c1, 0	@ CNTHCTL
--- linux-ein-5.4.0.orig/arch/arm/kernel/insn.c
+++ linux-ein-5.4.0/arch/arm/kernel/insn.c
@@ -3,8 +3,9 @@
 #include <linux/kernel.h>
 #include <asm/opcodes.h>
 
-static unsigned long
-__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link)
+static unsigned long __arm_gen_branch_thumb2(unsigned long pc,
+					     unsigned long addr, bool link,
+					     bool warn)
 {
 	unsigned long s, j1, j2, i1, i2, imm10, imm11;
 	unsigned long first, second;
@@ -12,7 +13,7 @@
 
 	offset = (long)addr - (long)(pc + 4);
 	if (offset < -16777216 || offset > 16777214) {
-		WARN_ON_ONCE(1);
+		WARN_ON_ONCE(warn);
 		return 0;
 	}
 
@@ -33,8 +34,8 @@
 	return __opcode_thumb32_compose(first, second);
 }
 
-static unsigned long
-__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link)
+static unsigned long __arm_gen_branch_arm(unsigned long pc, unsigned long addr,
+					  bool link, bool warn)
 {
 	unsigned long opcode = 0xea000000;
 	long offset;
@@ -44,7 +45,7 @@
 
 	offset = (long)addr - (long)(pc + 8);
 	if (unlikely(offset < -33554432 || offset > 33554428)) {
-		WARN_ON_ONCE(1);
+		WARN_ON_ONCE(warn);
 		return 0;
 	}
 
@@ -54,10 +55,10 @@
 }
 
 unsigned long
-__arm_gen_branch(unsigned long pc, unsigned long addr, bool link)
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool warn)
 {
 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL))
-		return __arm_gen_branch_thumb2(pc, addr, link);
+		return __arm_gen_branch_thumb2(pc, addr, link, warn);
 	else
-		return __arm_gen_branch_arm(pc, addr, link);
+		return __arm_gen_branch_arm(pc, addr, link, warn);
 }
--- linux-ein-5.4.0.orig/arch/arm/kernel/iwmmxt.S
+++ linux-ein-5.4.0/arch/arm/kernel/iwmmxt.S
@@ -16,6 +16,7 @@
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
+#include "iwmmxt.h"
 
 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
 #define PJ4(code...)		code
@@ -113,33 +114,33 @@
 
 concan_dump:
 
-	wstrw	wCSSF, [r1, #MMX_WCSSF]
-	wstrw	wCASF, [r1, #MMX_WCASF]
-	wstrw	wCGR0, [r1, #MMX_WCGR0]
-	wstrw	wCGR1, [r1, #MMX_WCGR1]
-	wstrw	wCGR2, [r1, #MMX_WCGR2]
-	wstrw	wCGR3, [r1, #MMX_WCGR3]
+	wstrw	wCSSF, r1, MMX_WCSSF
+	wstrw	wCASF, r1, MMX_WCASF
+	wstrw	wCGR0, r1, MMX_WCGR0
+	wstrw	wCGR1, r1, MMX_WCGR1
+	wstrw	wCGR2, r1, MMX_WCGR2
+	wstrw	wCGR3, r1, MMX_WCGR3
 
 1:	@ MUP? wRn
 	tst	r2, #0x2
 	beq	2f
 
-	wstrd	wR0,  [r1, #MMX_WR0]
-	wstrd	wR1,  [r1, #MMX_WR1]
-	wstrd	wR2,  [r1, #MMX_WR2]
-	wstrd	wR3,  [r1, #MMX_WR3]
-	wstrd	wR4,  [r1, #MMX_WR4]
-	wstrd	wR5,  [r1, #MMX_WR5]
-	wstrd	wR6,  [r1, #MMX_WR6]
-	wstrd	wR7,  [r1, #MMX_WR7]
-	wstrd	wR8,  [r1, #MMX_WR8]
-	wstrd	wR9,  [r1, #MMX_WR9]
-	wstrd	wR10, [r1, #MMX_WR10]
-	wstrd	wR11, [r1, #MMX_WR11]
-	wstrd	wR12, [r1, #MMX_WR12]
-	wstrd	wR13, [r1, #MMX_WR13]
-	wstrd	wR14, [r1, #MMX_WR14]
-	wstrd	wR15, [r1, #MMX_WR15]
+	wstrd	wR0,  r1, MMX_WR0
+	wstrd	wR1,  r1, MMX_WR1
+	wstrd	wR2,  r1, MMX_WR2
+	wstrd	wR3,  r1, MMX_WR3
+	wstrd	wR4,  r1, MMX_WR4
+	wstrd	wR5,  r1, MMX_WR5
+	wstrd	wR6,  r1, MMX_WR6
+	wstrd	wR7,  r1, MMX_WR7
+	wstrd	wR8,  r1, MMX_WR8
+	wstrd	wR9,  r1, MMX_WR9
+	wstrd	wR10, r1, MMX_WR10
+	wstrd	wR11, r1, MMX_WR11
+	wstrd	wR12, r1, MMX_WR12
+	wstrd	wR13, r1, MMX_WR13
+	wstrd	wR14, r1, MMX_WR14
+	wstrd	wR15, r1, MMX_WR15
 
 2:	teq	r0, #0				@ anything to load?
 	reteq	lr				@ if not, return
@@ -147,30 +148,30 @@
 concan_load:
 
 	@ Load wRn
-	wldrd	wR0,  [r0, #MMX_WR0]
-	wldrd	wR1,  [r0, #MMX_WR1]
-	wldrd	wR2,  [r0, #MMX_WR2]
-	wldrd	wR3,  [r0, #MMX_WR3]
-	wldrd	wR4,  [r0, #MMX_WR4]
-	wldrd	wR5,  [r0, #MMX_WR5]
-	wldrd	wR6,  [r0, #MMX_WR6]
-	wldrd	wR7,  [r0, #MMX_WR7]
-	wldrd	wR8,  [r0, #MMX_WR8]
-	wldrd	wR9,  [r0, #MMX_WR9]
-	wldrd	wR10, [r0, #MMX_WR10]
-	wldrd	wR11, [r0, #MMX_WR11]
-	wldrd	wR12, [r0, #MMX_WR12]
-	wldrd	wR13, [r0, #MMX_WR13]
-	wldrd	wR14, [r0, #MMX_WR14]
-	wldrd	wR15, [r0, #MMX_WR15]
+	wldrd	wR0,  r0, MMX_WR0
+	wldrd	wR1,  r0, MMX_WR1
+	wldrd	wR2,  r0, MMX_WR2
+	wldrd	wR3,  r0, MMX_WR3
+	wldrd	wR4,  r0, MMX_WR4
+	wldrd	wR5,  r0, MMX_WR5
+	wldrd	wR6,  r0, MMX_WR6
+	wldrd	wR7,  r0, MMX_WR7
+	wldrd	wR8,  r0, MMX_WR8
+	wldrd	wR9,  r0, MMX_WR9
+	wldrd	wR10, r0, MMX_WR10
+	wldrd	wR11, r0, MMX_WR11
+	wldrd	wR12, r0, MMX_WR12
+	wldrd	wR13, r0, MMX_WR13
+	wldrd	wR14, r0, MMX_WR14
+	wldrd	wR15, r0, MMX_WR15
 
 	@ Load wCx
-	wldrw	wCSSF, [r0, #MMX_WCSSF]
-	wldrw	wCASF, [r0, #MMX_WCASF]
-	wldrw	wCGR0, [r0, #MMX_WCGR0]
-	wldrw	wCGR1, [r0, #MMX_WCGR1]
-	wldrw	wCGR2, [r0, #MMX_WCGR2]
-	wldrw	wCGR3, [r0, #MMX_WCGR3]
+	wldrw	wCSSF, r0, MMX_WCSSF
+	wldrw	wCASF, r0, MMX_WCASF
+	wldrw	wCGR0, r0, MMX_WCGR0
+	wldrw	wCGR1, r0, MMX_WCGR1
+	wldrw	wCGR2, r0, MMX_WCGR2
+	wldrw	wCGR3, r0, MMX_WCGR3
 
 	@ clear CUP/MUP (only if r1 != 0)
 	teq	r1, #0
--- linux-ein-5.4.0.orig/arch/arm/kernel/iwmmxt.h
+++ linux-ein-5.4.0/arch/arm/kernel/iwmmxt.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __IWMMXT_H__
+#define __IWMMXT_H__
+
+.irp b, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+.set .LwR\b, \b
+.set .Lr\b, \b
+.endr
+
+.set .LwCSSF, 0x2
+.set .LwCASF, 0x3
+.set .LwCGR0, 0x8
+.set .LwCGR1, 0x9
+.set .LwCGR2, 0xa
+.set .LwCGR3, 0xb
+
+.macro wldrd, reg:req, base:req, offset:req
+.inst 0xedd00100 | (.L\reg << 12) | (.L\base << 16) | (\offset >> 2)
+.endm
+
+.macro wldrw, reg:req, base:req, offset:req
+.inst 0xfd900100 | (.L\reg << 12) | (.L\base << 16) | (\offset >> 2)
+.endm
+
+.macro wstrd, reg:req, base:req, offset:req
+.inst 0xedc00100 | (.L\reg << 12) | (.L\base << 16) | (\offset >> 2)
+.endm
+
+.macro wstrw, reg:req, base:req, offset:req
+.inst 0xfd800100 | (.L\reg << 12) | (.L\base << 16) | (\offset >> 2)
+.endm
+
+#ifdef __clang__
+
+#define wCon c1
+
+.macro tmrc, dest:req, control:req
+mrc p1, 0, \dest, \control, c0, 0
+.endm
+
+.macro tmcr, control:req, src:req
+mcr p1, 0, \src, \control, c0, 0
+.endm
+#endif
+
+#endif
--- linux-ein-5.4.0.orig/arch/arm/kernel/kgdb.c
+++ linux-ein-5.4.0/arch/arm/kernel/kgdb.c
@@ -154,22 +154,38 @@
 	return 0;
 }
 
-static struct undef_hook kgdb_brkpt_hook = {
+static struct undef_hook kgdb_brkpt_arm_hook = {
 	.instr_mask		= 0xffffffff,
 	.instr_val		= KGDB_BREAKINST,
-	.cpsr_mask		= MODE_MASK,
+	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
 	.cpsr_val		= SVC_MODE,
 	.fn			= kgdb_brk_fn
 };
 
-static struct undef_hook kgdb_compiled_brkpt_hook = {
+static struct undef_hook kgdb_brkpt_thumb_hook = {
+	.instr_mask		= 0xffff,
+	.instr_val		= KGDB_BREAKINST & 0xffff,
+	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
+	.cpsr_val		= PSR_T_BIT | SVC_MODE,
+	.fn			= kgdb_brk_fn
+};
+
+static struct undef_hook kgdb_compiled_brkpt_arm_hook = {
 	.instr_mask		= 0xffffffff,
 	.instr_val		= KGDB_COMPILED_BREAK,
-	.cpsr_mask		= MODE_MASK,
+	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
 	.cpsr_val		= SVC_MODE,
 	.fn			= kgdb_compiled_brk_fn
 };
 
+static struct undef_hook kgdb_compiled_brkpt_thumb_hook = {
+	.instr_mask		= 0xffff,
+	.instr_val		= KGDB_COMPILED_BREAK & 0xffff,
+	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
+	.cpsr_val		= PSR_T_BIT | SVC_MODE,
+	.fn			= kgdb_compiled_brk_fn
+};
+
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
 {
 	struct pt_regs *regs = args->regs;
@@ -210,8 +226,10 @@
 	if (ret != 0)
 		return ret;
 
-	register_undef_hook(&kgdb_brkpt_hook);
-	register_undef_hook(&kgdb_compiled_brkpt_hook);
+	register_undef_hook(&kgdb_brkpt_arm_hook);
+	register_undef_hook(&kgdb_brkpt_thumb_hook);
+	register_undef_hook(&kgdb_compiled_brkpt_arm_hook);
+	register_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
 
 	return 0;
 }
@@ -224,8 +242,10 @@
  */
 void kgdb_arch_exit(void)
 {
-	unregister_undef_hook(&kgdb_brkpt_hook);
-	unregister_undef_hook(&kgdb_compiled_brkpt_hook);
+	unregister_undef_hook(&kgdb_brkpt_arm_hook);
+	unregister_undef_hook(&kgdb_brkpt_thumb_hook);
+	unregister_undef_hook(&kgdb_compiled_brkpt_arm_hook);
+	unregister_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
 	unregister_die_notifier(&kgdb_notifier);
 }
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/machine_kexec.c
+++ linux-ein-5.4.0/arch/arm/kernel/machine_kexec.c
@@ -15,6 +15,7 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
+#include <asm/kexec-internal.h>
 #include <asm/fncpy.h>
 #include <asm/mach-types.h>
 #include <asm/smp_plat.h>
@@ -24,11 +25,6 @@
 extern void relocate_new_kernel(void);
 extern const unsigned int relocate_new_kernel_size;
 
-extern unsigned long kexec_start_address;
-extern unsigned long kexec_indirection_page;
-extern unsigned long kexec_mach_type;
-extern unsigned long kexec_boot_atags;
-
 static atomic_t waiting_for_crash_ipi;
 
 /*
@@ -161,6 +157,7 @@
 void machine_kexec(struct kimage *image)
 {
 	unsigned long page_list, reboot_entry_phys;
+	struct kexec_relocate_data *data;
 	void (*reboot_entry)(void);
 	void *reboot_code_buffer;
 
@@ -176,18 +173,17 @@
 
 	reboot_code_buffer = page_address(image->control_code_page);
 
-	/* Prepare parameters for reboot_code_buffer*/
-	set_kernel_text_rw();
-	kexec_start_address = image->start;
-	kexec_indirection_page = page_list;
-	kexec_mach_type = machine_arch_type;
-	kexec_boot_atags = image->arch.kernel_r2;
-
 	/* copy our kernel relocation code to the control code page */
 	reboot_entry = fncpy(reboot_code_buffer,
 			     &relocate_new_kernel,
 			     relocate_new_kernel_size);
 
+	data = reboot_code_buffer + relocate_new_kernel_size;
+	data->kexec_start_address = image->start;
+	data->kexec_indirection_page = page_list;
+	data->kexec_mach_type = machine_arch_type;
+	data->kexec_r2 = image->arch.kernel_r2;
+
 	/* get the identity mapping physical address for the reboot code */
 	reboot_entry_phys = virt_to_idmap(reboot_entry);
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/module-plts.c
+++ linux-ein-5.4.0/arch/arm/kernel/module-plts.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/elf.h>
+#include <linux/ftrace.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sort.h>
@@ -11,10 +12,6 @@
 #include <asm/cache.h>
 #include <asm/opcodes.h>
 
-#define PLT_ENT_STRIDE		L1_CACHE_BYTES
-#define PLT_ENT_COUNT		(PLT_ENT_STRIDE / sizeof(u32))
-#define PLT_ENT_SIZE		(sizeof(struct plt_entries) / PLT_ENT_COUNT)
-
 #ifdef CONFIG_THUMB2_KERNEL
 #define PLT_ENT_LDR		__opcode_to_mem_thumb32(0xf8dff000 | \
 							(PLT_ENT_STRIDE - 4))
@@ -23,9 +20,11 @@
 						    (PLT_ENT_STRIDE - 8))
 #endif
 
-struct plt_entries {
-	u32	ldr[PLT_ENT_COUNT];
-	u32	lit[PLT_ENT_COUNT];
+static const u32 fixed_plts[] = {
+#ifdef CONFIG_DYNAMIC_FTRACE
+	FTRACE_ADDR,
+	MCOUNT_ADDR,
+#endif
 };
 
 static bool in_init(const struct module *mod, unsigned long loc)
@@ -33,14 +32,40 @@
 	return loc - (u32)mod->init_layout.base < mod->init_layout.size;
 }
 
+static void prealloc_fixed(struct mod_plt_sec *pltsec, struct plt_entries *plt)
+{
+	int i;
+
+	if (!ARRAY_SIZE(fixed_plts) || pltsec->plt_count)
+		return;
+	pltsec->plt_count = ARRAY_SIZE(fixed_plts);
+
+	for (i = 0; i < ARRAY_SIZE(plt->ldr); ++i)
+		plt->ldr[i] = PLT_ENT_LDR;
+
+	BUILD_BUG_ON(sizeof(fixed_plts) > sizeof(plt->lit));
+	memcpy(plt->lit, fixed_plts, sizeof(fixed_plts));
+}
+
 u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
 {
 	struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
 							  &mod->arch.init;
+	struct plt_entries *plt;
+	int idx;
+
+	/* cache the address, ELF header is available only during module load */
+	if (!pltsec->plt_ent)
+		pltsec->plt_ent = (struct plt_entries *)pltsec->plt->sh_addr;
+	plt = pltsec->plt_ent;
 
-	struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
-	int idx = 0;
+	prealloc_fixed(pltsec, plt);
+
+	for (idx = 0; idx < ARRAY_SIZE(fixed_plts); ++idx)
+		if (plt->lit[idx] == val)
+			return (u32)&plt->ldr[idx];
 
+	idx = 0;
 	/*
 	 * Look for an existing entry pointing to 'val'. Given that the
 	 * relocations are sorted, this will be the last entry we allocated.
@@ -188,8 +213,8 @@
 int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
 			      char *secstrings, struct module *mod)
 {
-	unsigned long core_plts = 0;
-	unsigned long init_plts = 0;
+	unsigned long core_plts = ARRAY_SIZE(fixed_plts);
+	unsigned long init_plts = ARRAY_SIZE(fixed_plts);
 	Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
 	Elf32_Sym *syms = NULL;
 
@@ -244,6 +269,7 @@
 	mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
 					       sizeof(struct plt_entries));
 	mod->arch.core.plt_count = 0;
+	mod->arch.core.plt_ent = NULL;
 
 	mod->arch.init.plt->sh_type = SHT_NOBITS;
 	mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
@@ -251,6 +277,7 @@
 	mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
 					       sizeof(struct plt_entries));
 	mod->arch.init.plt_count = 0;
+	mod->arch.init.plt_ent = NULL;
 
 	pr_debug("%s: plt=%x, init.plt=%x\n", __func__,
 		 mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size);
--- linux-ein-5.4.0.orig/arch/arm/kernel/perf_callchain.c
+++ linux-ein-5.4.0/arch/arm/kernel/perf_callchain.c
@@ -62,9 +62,10 @@
 void
 perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct frame_tail __user *tail;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -98,9 +99,10 @@
 void
 perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct stackframe fr;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -111,18 +113,21 @@
 
 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();
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
+	if (guest_cbs && guest_cbs->is_in_guest())
+		return guest_cbs->get_guest_ip();
 
 	return instruction_pointer(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	int misc = 0;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-		if (perf_guest_cbs->is_user_mode())
+	if (guest_cbs && guest_cbs->is_in_guest()) {
+		if (guest_cbs->is_user_mode())
 			misc |= PERF_RECORD_MISC_GUEST_USER;
 		else
 			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
--- linux-ein-5.4.0.orig/arch/arm/kernel/perf_event_v7.c
+++ linux-ein-5.4.0/arch/arm/kernel/perf_event_v7.c
@@ -773,10 +773,10 @@
 		pr_err("CPU%u writing wrong counter %d\n",
 			smp_processor_id(), idx);
 	} else if (idx == ARMV7_IDX_CYCLE_COUNTER) {
-		asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
+		asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" ((u32)value));
 	} else {
 		armv7_pmnc_select_counter(idx);
-		asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
+		asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" ((u32)value));
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/process.c
+++ linux-ein-5.4.0/arch/arm/kernel/process.c
@@ -224,8 +224,8 @@
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 int
-copy_thread(unsigned long clone_flags, unsigned long stack_start,
-	    unsigned long stk_sz, struct task_struct *p)
+copy_thread_tls(unsigned long clone_flags, unsigned long stack_start,
+	    unsigned long stk_sz, struct task_struct *p, unsigned long tls)
 {
 	struct thread_info *thread = task_thread_info(p);
 	struct pt_regs *childregs = task_pt_regs(p);
@@ -259,7 +259,7 @@
 	clear_ptrace_hw_breakpoint(p);
 
 	if (clone_flags & CLONE_SETTLS)
-		thread->tp_value[0] = childregs->ARM_r3;
+		thread->tp_value[0] = tls;
 	thread->tp_value[1] = get_tpuser();
 
 	thread_notify(THREAD_NOTIFY_COPY, thread);
--- linux-ein-5.4.0.orig/arch/arm/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/arm/kernel/ptrace.c
@@ -219,8 +219,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,
--- linux-ein-5.4.0.orig/arch/arm/kernel/relocate_kernel.S
+++ linux-ein-5.4.0/arch/arm/kernel/relocate_kernel.S
@@ -5,14 +5,16 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/asm-offsets.h>
 #include <asm/kexec.h>
 
 	.align	3	/* not needed for this code, but keeps fncpy() happy */
 
 ENTRY(relocate_new_kernel)
 
-	ldr	r0,kexec_indirection_page
-	ldr	r1,kexec_start_address
+	adr	r7, relocate_new_kernel_end
+	ldr	r0, [r7, #KEXEC_INDIR_PAGE]
+	ldr	r1, [r7, #KEXEC_START_ADDR]
 
 	/*
 	 * If there is no indirection page (we are doing crashdumps)
@@ -57,34 +59,16 @@
 
 2:
 	/* Jump to relocated kernel */
-	mov lr,r1
-	mov r0,#0
-	ldr r1,kexec_mach_type
-	ldr r2,kexec_boot_atags
- ARM(	ret lr	)
- THUMB(	bx lr		)
-
-	.align
-
-	.globl kexec_start_address
-kexec_start_address:
-	.long	0x0
-
-	.globl kexec_indirection_page
-kexec_indirection_page:
-	.long	0x0
-
-	.globl kexec_mach_type
-kexec_mach_type:
-	.long	0x0
-
-	/* phy addr of the atags for the new kernel */
-	.globl kexec_boot_atags
-kexec_boot_atags:
-	.long	0x0
+	mov	lr, r1
+	mov	r0, #0
+	ldr	r1, [r7, #KEXEC_MACH_TYPE]
+	ldr	r2, [r7, #KEXEC_R2]
+ ARM(	ret	lr	)
+ THUMB(	bx	lr	)
 
 ENDPROC(relocate_new_kernel)
 
+	.align	3
 relocate_new_kernel_end:
 
 	.globl relocate_new_kernel_size
--- linux-ein-5.4.0.orig/arch/arm/kernel/return_address.c
+++ linux-ein-5.4.0/arch/arm/kernel/return_address.c
@@ -7,8 +7,6 @@
  */
 #include <linux/export.h>
 #include <linux/ftrace.h>
-
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
 #include <linux/sched.h>
 
 #include <asm/stacktrace.h>
@@ -53,6 +51,4 @@
 		return NULL;
 }
 
-#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
-
 EXPORT_SYMBOL_GPL(return_address);
--- linux-ein-5.4.0.orig/arch/arm/kernel/setup.c
+++ linux-ein-5.4.0/arch/arm/kernel/setup.c
@@ -18,6 +18,7 @@
 #include <linux/of_platform.h>
 #include <linux/init.h>
 #include <linux/kexec.h>
+#include <linux/libfdt.h>
 #include <linux/of_fdt.h>
 #include <linux/cpu.h>
 #include <linux/interrupt.h>
@@ -543,9 +544,11 @@
 	 * In Thumb-2, msr with an immediate value is not allowed.
 	 */
 #ifdef CONFIG_THUMB2_KERNEL
-#define PLC	"r"
+#define PLC_l	"l"
+#define PLC_r	"r"
 #else
-#define PLC	"I"
+#define PLC_l	"I"
+#define PLC_r	"I"
 #endif
 
 	/*
@@ -567,15 +570,15 @@
 	"msr	cpsr_c, %9"
 	    :
 	    : "r" (stk),
-	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+	      PLC_r (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
 	      "I" (offsetof(struct stack, irq[0])),
-	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+	      PLC_r (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
 	      "I" (offsetof(struct stack, abt[0])),
-	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+	      PLC_r (PSR_F_BIT | PSR_I_BIT | UND_MODE),
 	      "I" (offsetof(struct stack, und[0])),
-	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+	      PLC_r (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
 	      "I" (offsetof(struct stack, fiq[0])),
-	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+	      PLC_l (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
 #endif
 }
@@ -1075,19 +1078,27 @@
 
 void __init setup_arch(char **cmdline_p)
 {
-	const struct machine_desc *mdesc;
+	const struct machine_desc *mdesc = NULL;
+	void *atags_vaddr = NULL;
+
+	if (__atags_pointer)
+		atags_vaddr = FDT_VIRT_BASE(__atags_pointer);
 
 	setup_processor();
-	mdesc = setup_machine_fdt(__atags_pointer);
+	if (atags_vaddr) {
+		mdesc = setup_machine_fdt(atags_vaddr);
+		if (mdesc)
+			memblock_reserve(__atags_pointer,
+					 fdt_totalsize(atags_vaddr));
+	}
 	if (!mdesc)
-		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
+		mdesc = setup_machine_tags(atags_vaddr, __machine_arch_type);
 	if (!mdesc) {
 		early_print("\nError: invalid dtb and unrecognized/unsupported machine ID\n");
 		early_print("  r1=0x%08x, r2=0x%08x\n", __machine_arch_type,
 			    __atags_pointer);
 		if (__atags_pointer)
-			early_print("  r2[]=%*ph\n", 16,
-				    phys_to_virt(__atags_pointer));
+			early_print("  r2[]=%*ph\n", 16, atags_vaddr);
 		dump_machine_table();
 	}
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/signal.c
+++ linux-ein-5.4.0/arch/arm/kernel/signal.c
@@ -694,18 +694,20 @@
 
 	addr = page_address(page);
 
+	/* Poison the entire page */
+	memset32(addr, __opcode_to_mem_arm(0xe7fddef1),
+		 PAGE_SIZE / sizeof(u32));
+
 	/* Give the signal return code some randomness */
 	offset = 0x200 + (get_random_int() & 0x7fc);
 	signal_return_offset = offset;
 
-	/*
-	 * Copy signal return handlers into the vector page, and
-	 * set sigreturn to be a pointer to these.
-	 */
+	/* Copy signal return handlers into the page */
 	memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
 
-	ptr = (unsigned long)addr + offset;
-	flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+	/* Flush out all instructions in this page */
+	ptr = (unsigned long)addr;
+	flush_icache_range(ptr, ptr + PAGE_SIZE);
 
 	return page;
 }
--- linux-ein-5.4.0.orig/arch/arm/kernel/smccc-call.S
+++ linux-ein-5.4.0/arch/arm/kernel/smccc-call.S
@@ -3,7 +3,9 @@
  * Copyright (c) 2015, Linaro Limited
  */
 #include <linux/linkage.h>
+#include <linux/arm-smccc.h>
 
+#include <asm/asm-offsets.h>
 #include <asm/opcodes-sec.h>
 #include <asm/opcodes-virt.h>
 #include <asm/unwind.h>
@@ -27,7 +29,14 @@
 UNWIND(	.save	{r4-r7})
 	ldm	r12, {r4-r7}
 	\instr
-	pop	{r4-r7}
+	ldr	r4, [sp, #36]
+	cmp	r4, #0
+	beq	1f			// No quirk structure
+	ldr     r5, [r4, #ARM_SMCCC_QUIRK_ID_OFFS]
+	cmp     r5, #ARM_SMCCC_QUIRK_QCOM_A6
+	bne	1f			// No quirk present
+	str	r6, [r4, #ARM_SMCCC_QUIRK_STATE_OFFS]
+1:	pop	{r4-r7}
 	ldr	r12, [sp, #(4 * 4)]
 	stm	r12, {r0-r3}
 	bx	lr
--- linux-ein-5.4.0.orig/arch/arm/kernel/smp.c
+++ linux-ein-5.4.0/arch/arm/kernel/smp.c
@@ -240,6 +240,10 @@
 	if (ret)
 		return ret;
 
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
+	remove_cpu_topology(cpu);
+#endif
+
 	/*
 	 * Take this CPU offline.  Once we clear this, we can't return,
 	 * and we must not schedule until we're ready to give up the cpu.
--- linux-ein-5.4.0.orig/arch/arm/kernel/spectre.c
+++ linux-ein-5.4.0/arch/arm/kernel/spectre.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/bpf.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+
+#include <asm/spectre.h>
+
+static bool _unprivileged_ebpf_enabled(void)
+{
+#ifdef CONFIG_BPF_SYSCALL
+	return !sysctl_unprivileged_bpf_disabled;
+#else
+	return false;
+#endif
+}
+
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+static unsigned int spectre_v2_state;
+static unsigned int spectre_v2_methods;
+
+void spectre_v2_update_state(unsigned int state, unsigned int method)
+{
+	if (state > spectre_v2_state)
+		spectre_v2_state = state;
+	spectre_v2_methods |= method;
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	const char *method;
+
+	if (spectre_v2_state == SPECTRE_UNAFFECTED)
+		return sprintf(buf, "%s\n", "Not affected");
+
+	if (spectre_v2_state != SPECTRE_MITIGATED)
+		return sprintf(buf, "%s\n", "Vulnerable");
+
+	if (_unprivileged_ebpf_enabled())
+		return sprintf(buf, "Vulnerable: Unprivileged eBPF enabled\n");
+
+	switch (spectre_v2_methods) {
+	case SPECTRE_V2_METHOD_BPIALL:
+		method = "Branch predictor hardening";
+		break;
+
+	case SPECTRE_V2_METHOD_ICIALLU:
+		method = "I-cache invalidation";
+		break;
+
+	case SPECTRE_V2_METHOD_SMC:
+	case SPECTRE_V2_METHOD_HVC:
+		method = "Firmware call";
+		break;
+
+	case SPECTRE_V2_METHOD_LOOP8:
+		method = "History overwrite";
+		break;
+
+	default:
+		method = "Multiple mitigations";
+		break;
+	}
+
+	return sprintf(buf, "Mitigation: %s\n", method);
+}
--- linux-ein-5.4.0.orig/arch/arm/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/arm/kernel/stacktrace.c
@@ -22,6 +22,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.
  */
@@ -34,14 +47,24 @@
 	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 = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
+	frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
+#else
 	/* check current frame pointer is within bounds */
 	if (fp < low + 12 || fp > high - 4)
 		return -EINVAL;
 
 	/* restore the registers from the stack frame */
-	frame->fp = *(unsigned long *)(fp - 12);
-	frame->sp = *(unsigned long *)(fp - 8);
-	frame->pc = *(unsigned long *)(fp - 4);
+	frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
+	frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
+	frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
+#endif
 
 	return 0;
 }
@@ -92,6 +115,8 @@
 		return 0;
 
 	regs = (struct pt_regs *)frame->sp;
+	if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
+		return 0;
 
 	trace->entries[trace->nr_entries++] = regs->ARM_pc;
 
--- linux-ein-5.4.0.orig/arch/arm/kernel/suspend.c
+++ linux-ein-5.4.0/arch/arm/kernel/suspend.c
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/mm_types.h>
@@ -27,12 +28,22 @@
 		return -EINVAL;
 
 	/*
+	 * Function graph tracer state gets incosistent when the kernel
+	 * calls functions that never return (aka suspend finishers) hence
+	 * disable graph tracing during their execution.
+	 */
+	pause_graph_tracing();
+
+	/*
 	 * Provide a temporary page table with an identity mapping for
 	 * the MMU-enable code, required for resuming.  On successful
 	 * resume (indicated by a zero return code), we need to switch
 	 * back to the correct page tables.
 	 */
 	ret = __cpu_suspend(arg, fn, __mpidr);
+
+	unpause_graph_tracing();
+
 	if (ret == 0) {
 		cpu_switch_mm(mm->pgd, mm);
 		local_flush_bp_all();
@@ -46,7 +57,13 @@
 int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
 {
 	u32 __mpidr = cpu_logical_map(smp_processor_id());
-	return __cpu_suspend(arg, fn, __mpidr);
+	int ret;
+
+	pause_graph_tracing();
+	ret = __cpu_suspend(arg, fn, __mpidr);
+	unpause_graph_tracing();
+
+	return ret;
 }
 #define	idmap_pgd	NULL
 #endif
--- linux-ein-5.4.0.orig/arch/arm/kernel/topology.c
+++ linux-ein-5.4.0/arch/arm/kernel/topology.c
@@ -196,9 +196,8 @@
 	struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
 	unsigned int mpidr;
 
-	/* If the cpu topology has been already set, just return */
-	if (cpuid_topo->core_id != -1)
-		return;
+	if (cpuid_topo->package_id != -1)
+		goto topology_populated;
 
 	mpidr = read_cpuid_mpidr();
 
@@ -231,14 +230,15 @@
 		cpuid_topo->package_id = -1;
 	}
 
-	update_siblings_masks(cpuid);
-
 	update_cpu_capacity(cpuid);
 
 	pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
 		cpuid, cpu_topology[cpuid].thread_id,
 		cpu_topology[cpuid].core_id,
 		cpu_topology[cpuid].package_id, mpidr);
+
+topology_populated:
+	update_siblings_masks(cpuid);
 }
 
 static inline int cpu_corepower_flags(void)
--- linux-ein-5.4.0.orig/arch/arm/kernel/traps.c
+++ linux-ein-5.4.0/arch/arm/kernel/traps.c
@@ -30,6 +30,7 @@
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/exception.h>
+#include <asm/spectre.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
 #include <asm/ptrace.h>
@@ -64,14 +65,16 @@
 
 void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
 {
+	unsigned long end = frame + 4 + sizeof(struct pt_regs);
+
 #ifdef CONFIG_KALLSYMS
 	printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
 #else
 	printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
 #endif
 
-	if (in_entry_text(from))
-		dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
+	if (in_entry_text(from) && end <= ALIGN(frame, THREAD_SIZE))
+		dump_mem("", "Exception stack", frame + 4, end);
 }
 
 void dump_backtrace_stm(u32 *stack, u32 instruction)
@@ -338,7 +341,7 @@
 	if (panic_on_oops)
 		panic("Fatal exception");
 	if (signr)
-		do_exit(signr);
+		make_task_dead(signr);
 }
 
 /*
@@ -797,10 +800,59 @@
 }
 #endif
 
+#ifndef CONFIG_CPU_V7M
+static void copy_from_lma(void *vma, void *lma_start, void *lma_end)
+{
+	memcpy(vma, lma_start, lma_end - lma_start);
+}
+
+static void flush_vectors(void *vma, size_t offset, size_t size)
+{
+	unsigned long start = (unsigned long)vma + offset;
+	unsigned long end = start + size;
+
+	flush_icache_range(start, end);
+}
+
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+int spectre_bhb_update_vectors(unsigned int method)
+{
+	extern char __vectors_bhb_bpiall_start[], __vectors_bhb_bpiall_end[];
+	extern char __vectors_bhb_loop8_start[], __vectors_bhb_loop8_end[];
+	void *vec_start, *vec_end;
+
+	if (system_state > SYSTEM_SCHEDULING) {
+		pr_err("CPU%u: Spectre BHB workaround too late - system vulnerable\n",
+		       smp_processor_id());
+		return SPECTRE_VULNERABLE;
+	}
+
+	switch (method) {
+	case SPECTRE_V2_METHOD_LOOP8:
+		vec_start = __vectors_bhb_loop8_start;
+		vec_end = __vectors_bhb_loop8_end;
+		break;
+
+	case SPECTRE_V2_METHOD_BPIALL:
+		vec_start = __vectors_bhb_bpiall_start;
+		vec_end = __vectors_bhb_bpiall_end;
+		break;
+
+	default:
+		pr_err("CPU%u: unknown Spectre BHB state %d\n",
+		       smp_processor_id(), method);
+		return SPECTRE_VULNERABLE;
+	}
+
+	copy_from_lma(vectors_page, vec_start, vec_end);
+	flush_vectors(vectors_page, 0, vec_end - vec_start);
+
+	return SPECTRE_MITIGATED;
+}
+#endif
+
 void __init early_trap_init(void *vectors_base)
 {
-#ifndef CONFIG_CPU_V7M
-	unsigned long vectors = (unsigned long)vectors_base;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
 	unsigned i;
@@ -821,17 +873,20 @@
 	 * into the vector page, mapped at 0xffff0000, and ensure these
 	 * are visible to the instruction stream.
 	 */
-	memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-	memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
+	copy_from_lma(vectors_base, __vectors_start, __vectors_end);
+	copy_from_lma(vectors_base + 0x1000, __stubs_start, __stubs_end);
 
 	kuser_init(vectors_base);
 
-	flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
+	flush_vectors(vectors_base, 0, PAGE_SIZE * 2);
+}
 #else /* ifndef CONFIG_CPU_V7M */
+void __init early_trap_init(void *vectors_base)
+{
 	/*
 	 * on V7-M there is no need to copy the vector table to a dedicated
 	 * memory area. The address is configurable and so a table in the kernel
 	 * image can be used.
 	 */
-#endif
 }
+#endif
--- linux-ein-5.4.0.orig/arch/arm/kernel/unwind.c
+++ linux-ein-5.4.0/arch/arm/kernel/unwind.c
@@ -300,6 +300,29 @@
 	return URC_OK;
 }
 
+static unsigned long unwind_decode_uleb128(struct unwind_ctrl_block *ctrl)
+{
+	unsigned long bytes = 0;
+	unsigned long insn;
+	unsigned long result = 0;
+
+	/*
+	 * unwind_get_byte() will advance `ctrl` one instruction at a time, so
+	 * loop until we get an instruction byte where bit 7 is not set.
+	 *
+	 * Note: This decodes a maximum of 4 bytes to output 28 bits data where
+	 * max is 0xfffffff: that will cover a vsp increment of 1073742336, hence
+	 * it is sufficient for unwinding the stack.
+	 */
+	do {
+		insn = unwind_get_byte(ctrl);
+		result |= (insn & 0x7f) << (bytes * 7);
+		bytes++;
+	} while (!!(insn & 0x80) && (bytes != sizeof(result)));
+
+	return result;
+}
+
 /*
  * Execute the current unwind instruction.
  */
@@ -353,7 +376,7 @@
 		if (ret)
 			goto error;
 	} else if (insn == 0xb2) {
-		unsigned long uleb128 = unwind_get_byte(ctrl);
+		unsigned long uleb128 = unwind_decode_uleb128(ctrl);
 
 		ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
 	} else {
--- linux-ein-5.4.0.orig/arch/arm/kernel/vdso.c
+++ linux-ein-5.4.0/arch/arm/kernel/vdso.c
@@ -93,6 +93,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"))
@@ -279,7 +281,7 @@
 	if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
 		return false;
 
-	if (!tk->tkr_mono.clock->archdata.vdso_direct)
+	if (tk->tkr_mono.clock->archdata.clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
 		return false;
 
 	return true;
--- linux-ein-5.4.0.orig/arch/arm/kernel/vmlinux-xip.lds.S
+++ linux-ein-5.4.0/arch/arm/kernel/vmlinux-xip.lds.S
@@ -180,7 +180,7 @@
 ASSERT((_end - __bss_start) >= 12288, ".bss too small for CONFIG_XIP_DEFLATED_DATA")
 #endif
 
-#ifdef CONFIG_ARM_MPU
+#if defined(CONFIG_ARM_MPU) && !defined(CONFIG_COMPILE_TEST)
 /*
  * Due to PMSAv7 restriction on base address and size we have to
  * enforce minimal alignment restrictions. It was seen that weaker
--- linux-ein-5.4.0.orig/arch/arm/kernel/vmlinux.lds.h
+++ linux-ein-5.4.0/arch/arm/kernel/vmlinux.lds.h
@@ -25,6 +25,19 @@
 #define ARM_MMU_DISCARD(x)	x
 #endif
 
+/*
+ * ld.lld does not support NOCROSSREFS:
+ * https://github.com/ClangBuiltLinux/linux/issues/1609
+ */
+#ifdef CONFIG_LD_IS_LLD
+#define NOCROSSREFS
+#endif
+
+/* Set start/end symbol names to the LMA for the section */
+#define ARM_LMA(sym, section)						\
+	sym##_start = LOADADDR(section);				\
+	sym##_end = LOADADDR(section) + SIZEOF(section)
+
 #define PROC_INFO							\
 		. = ALIGN(4);						\
 		__proc_info_begin = .;					\
@@ -100,19 +113,31 @@
  * only thing that matters is their relative offsets
  */
 #define ARM_VECTORS							\
-	__vectors_start = .;						\
-	.vectors 0xffff0000 : AT(__vectors_start) {			\
-		*(.vectors)						\
+	__vectors_lma = .;						\
+	OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) {		\
+		.vectors {						\
+			*(.vectors)					\
+		}							\
+		.vectors.bhb.loop8 {					\
+			*(.vectors.bhb.loop8)				\
+		}							\
+		.vectors.bhb.bpiall {					\
+			*(.vectors.bhb.bpiall)				\
+		}							\
 	}								\
-	. = __vectors_start + SIZEOF(.vectors);				\
-	__vectors_end = .;						\
+	ARM_LMA(__vectors, .vectors);					\
+	ARM_LMA(__vectors_bhb_loop8, .vectors.bhb.loop8);		\
+	ARM_LMA(__vectors_bhb_bpiall, .vectors.bhb.bpiall);		\
+	. = __vectors_lma + SIZEOF(.vectors) +				\
+		SIZEOF(.vectors.bhb.loop8) +				\
+		SIZEOF(.vectors.bhb.bpiall);				\
 									\
-	__stubs_start = .;						\
-	.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) {		\
+	__stubs_lma = .;						\
+	.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) {		\
 		*(.stubs)						\
 	}								\
-	. = __stubs_start + SIZEOF(.stubs);				\
-	__stubs_end = .;						\
+	ARM_LMA(__stubs, .stubs);					\
+	. = __stubs_lma + SIZEOF(.stubs);				\
 									\
 	PROVIDE(vector_fiq_offset = vector_fiq - ADDR(.vectors));
 
--- linux-ein-5.4.0.orig/arch/arm/kvm/hyp/tlb.c
+++ linux-ein-5.4.0/arch/arm/kvm/hyp/tlb.c
@@ -45,7 +45,7 @@
 	__kvm_tlb_flush_vmid(kvm);
 }
 
-void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
+void __hyp_text __kvm_flush_cpu_context(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
 
@@ -54,6 +54,7 @@
 	isb();
 
 	write_sysreg(0, TLBIALL);
+	write_sysreg(0, ICIALLU);
 	dsb(nsh);
 	isb();
 
--- linux-ein-5.4.0.orig/arch/arm/lib/copy_from_user.S
+++ linux-ein-5.4.0/arch/arm/lib/copy_from_user.S
@@ -118,7 +118,7 @@
 
 ENDPROC(arm_copy_from_user)
 
-	.pushsection .fixup,"ax"
+	.pushsection .text.fixup,"ax"
 	.align 0
 	copy_abort_preamble
 	ldmfd	sp!, {r1, r2, r3}
--- linux-ein-5.4.0.orig/arch/arm/lib/findbit.S
+++ linux-ein-5.4.0/arch/arm/lib/findbit.S
@@ -40,8 +40,8 @@
  * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset)
  */
 ENTRY(_find_next_zero_bit_le)
-		teq	r1, #0
-		beq	3b
+		cmp	r2, r1
+		bhs	3b
 		ands	ip, r2, #7
 		beq	1b			@ If new byte, goto old routine
  ARM(		ldrb	r3, [r0, r2, lsr #3]	)
@@ -81,8 +81,8 @@
  * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset)
  */
 ENTRY(_find_next_bit_le)
-		teq	r1, #0
-		beq	3b
+		cmp	r2, r1
+		bhs	3b
 		ands	ip, r2, #7
 		beq	1b			@ If new byte, goto old routine
  ARM(		ldrb	r3, [r0, r2, lsr #3]	)
@@ -115,8 +115,8 @@
 ENDPROC(_find_first_zero_bit_be)
 
 ENTRY(_find_next_zero_bit_be)
-		teq	r1, #0
-		beq	3b
+		cmp	r2, r1
+		bhs	3b
 		ands	ip, r2, #7
 		beq	1b			@ If new byte, goto old routine
 		eor	r3, r2, #0x18		@ big endian byte ordering
@@ -149,8 +149,8 @@
 ENDPROC(_find_first_bit_be)
 
 ENTRY(_find_next_bit_be)
-		teq	r1, #0
-		beq	3b
+		cmp	r2, r1
+		bhs	3b
 		ands	ip, r2, #7
 		beq	1b			@ If new byte, goto old routine
 		eor	r3, r2, #0x18		@ big endian byte ordering
--- linux-ein-5.4.0.orig/arch/arm/lib/memset.S
+++ linux-ein-5.4.0/arch/arm/lib/memset.S
@@ -16,6 +16,7 @@
 ENTRY(mmioset)
 ENTRY(memset)
 UNWIND( .fnstart         )
+	and	r1, r1, #255		@ cast to unsigned char
 	ands	r3, r0, #3		@ 1 unaligned?
 	mov	ip, r0			@ preserve r0 as return value
 	bne	6f			@ 1
--- linux-ein-5.4.0.orig/arch/arm/lib/xor-neon.c
+++ linux-ein-5.4.0/arch/arm/lib/xor-neon.c
@@ -26,8 +26,9 @@
  * While older versions of GCC do not generate incorrect code, they fail to
  * recognize the parallel nature of these functions, and emit plain ARM code,
  * which is known to be slower than the optimized ARM code in asm-arm/xor.h.
+ *
+ * #warning This code requires at least version 4.6 of GCC
  */
-#warning This code requires at least version 4.6 of GCC
 #endif
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
--- linux-ein-5.4.0.orig/arch/arm/mach-at91/pm.c
+++ linux-ein-5.4.0/arch/arm/mach-at91/pm.c
@@ -103,7 +103,7 @@
 
 static const struct of_device_id sama5d2_ws_ids[] = {
 	{ .compatible = "atmel,sama5d2-gem",		.data = &ws_info[0] },
-	{ .compatible = "atmel,at91rm9200-rtc",		.data = &ws_info[1] },
+	{ .compatible = "atmel,sama5d2-rtc",		.data = &ws_info[1] },
 	{ .compatible = "atmel,sama5d3-udc",		.data = &ws_info[2] },
 	{ .compatible = "atmel,at91rm9200-ohci",	.data = &ws_info[2] },
 	{ .compatible = "usb-ohci",			.data = &ws_info[2] },
@@ -114,12 +114,12 @@
 };
 
 static const struct of_device_id sam9x60_ws_ids[] = {
-	{ .compatible = "atmel,at91sam9x5-rtc",		.data = &ws_info[1] },
+	{ .compatible = "microchip,sam9x60-rtc",	.data = &ws_info[1] },
 	{ .compatible = "atmel,at91rm9200-ohci",	.data = &ws_info[2] },
 	{ .compatible = "usb-ohci",			.data = &ws_info[2] },
 	{ .compatible = "atmel,at91sam9g45-ehci",	.data = &ws_info[2] },
 	{ .compatible = "usb-ehci",			.data = &ws_info[2] },
-	{ .compatible = "atmel,at91sam9260-rtt",	.data = &ws_info[4] },
+	{ .compatible = "microchip,sam9x60-rtt",	.data = &ws_info[4] },
 	{ .compatible = "cdns,sam9x60-macb",		.data = &ws_info[5] },
 	{ /* sentinel */ }
 };
@@ -592,13 +592,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);
@@ -606,12 +606,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 bool __init at91_is_pm_mode_active(int pm_mode)
@@ -691,6 +696,12 @@
 		soc_pm.data.suspend_mode = AT91_PM_ULP0;
 }
 
+static const struct of_device_id atmel_shdwc_ids[] = {
+	{ .compatible = "atmel,sama5d2-shdwc" },
+	{ .compatible = "microchip,sam9x60-shdwc" },
+	{ /* sentinel. */ }
+};
+
 static void __init at91_pm_modes_init(void)
 {
 	struct device_node *np;
@@ -700,7 +711,7 @@
 	    !at91_is_pm_mode_active(AT91_PM_ULP1))
 		return;
 
-	np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-shdwc");
+	np = of_find_matching_node(NULL, atmel_shdwc_ids);
 	if (!np) {
 		pr_warn("%s: failed to find shdwc!\n", __func__);
 		goto ulp1_default;
@@ -751,6 +762,7 @@
 	{ .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] },
 	{ .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] },
 	{ .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
+	{ .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[1] },
 	{ /* sentinel */ },
 };
 
@@ -765,6 +777,7 @@
 
 	pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id);
 	soc_pm.data.pmc = of_iomap(pmc_np, 0);
+	of_node_put(pmc_np);
 	if (!soc_pm.data.pmc) {
 		pr_err("AT91: PM not supported, PMC not found\n");
 		return;
--- linux-ein-5.4.0.orig/arch/arm/mach-at91/pm_suspend.S
+++ linux-ein-5.4.0/arch/arm/mach-at91/pm_suspend.S
@@ -268,6 +268,10 @@
 	orr	tmp1, tmp1, #AT91_PMC_KEY
 	str	tmp1, [pmc, #AT91_CKGR_MOR]
 
+	/* Quirk for SAM9X60's PMC */
+	nop
+	nop
+
 	wait_mckrdy
 
 	/* Enable the crystal oscillator */
--- linux-ein-5.4.0.orig/arch/arm/mach-axxia/platsmp.c
+++ linux-ein-5.4.0/arch/arm/mach-axxia/platsmp.c
@@ -39,6 +39,7 @@
 		return -ENOENT;
 
 	syscon = of_iomap(syscon_np, 0);
+	of_node_put(syscon_np);
 	if (!syscon)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-bcm/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-bcm/Kconfig
@@ -214,7 +214,6 @@
 	select HAVE_ARM_ARCH_TIMER
 	select BRCMSTB_L2_IRQ
 	select BCM7120_L2_IRQ
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ZONE_DMA if ARM_LPAE
 	select SOC_BRCMSTB
 	select SOC_BUS
--- linux-ein-5.4.0.orig/arch/arm/mach-bcm/bcm_kona_smc.c
+++ linux-ein-5.4.0/arch/arm/mach-bcm/bcm_kona_smc.c
@@ -54,6 +54,7 @@
 		return -ENODEV;
 
 	prop_val = of_get_address(node, 0, &prop_size, NULL);
+	of_node_put(node);
 	if (!prop_val)
 		return -EINVAL;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-cns3xxx/core.c
+++ linux-ein-5.4.0/arch/arm/mach-cns3xxx/core.c
@@ -376,6 +376,7 @@
 		/* De-Asscer SATA Reset */
 		cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA));
 	}
+	of_node_put(dn);
 
 	dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-sdhci");
 	if (of_device_is_available(dn)) {
@@ -389,6 +390,7 @@
 		cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
 		cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
 	}
+	of_node_put(dn);
 
 	pm_power_off = cns3xxx_power_off;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-davinci/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-davinci/Kconfig
@@ -3,12 +3,13 @@
 menuconfig ARCH_DAVINCI
 	bool "TI DaVinci"
 	depends on ARCH_MULTI_V5
+	select CPU_ARM926T
 	select DAVINCI_TIMER
 	select ZONE_DMA
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select PM_GENERIC_DOMAINS if PM
 	select PM_GENERIC_DOMAINS_OF if PM && OF
 	select REGMAP_MMIO
+	select RESET_CONTROLLER
 	select HAVE_IDE
 	select PINCTRL_SINGLE
 
--- linux-ein-5.4.0.orig/arch/arm/mach-davinci/board-da850-evm.c
+++ linux-ein-5.4.0/arch/arm/mach-davinci/board-da850-evm.c
@@ -1101,11 +1101,13 @@
 	int ret;
 	u32 val;
 	struct davinci_soc_info *soc_info = &davinci_soc_info;
-	u8 rmii_en = soc_info->emac_pdata->rmii_en;
+	u8 rmii_en;
 
 	if (!machine_is_davinci_da850_evm())
 		return 0;
 
+	rmii_en = soc_info->emac_pdata->rmii_en;
+
 	cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
 
 	val = __raw_readl(cfg_chip3_base);
--- linux-ein-5.4.0.orig/arch/arm/mach-ep93xx/core.c
+++ linux-ein-5.4.0/arch/arm/mach-ep93xx/core.c
@@ -337,6 +337,7 @@
 				GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
 		GPIO_LOOKUP_IDX("G", 0, NULL, 1,
 				GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+		{ }
 	},
 };
 
--- linux-ein-5.4.0.orig/arch/arm/mach-ep93xx/timer-ep93xx.c
+++ linux-ein-5.4.0/arch/arm/mach-ep93xx/timer-ep93xx.c
@@ -9,6 +9,7 @@
 #include <linux/io.h>
 #include <asm/mach/time.h>
 #include "soc.h"
+#include "platform.h"
 
 /*************************************************************************
  * Timer handling for EP93xx
@@ -60,7 +61,7 @@
 	return ret;
 }
 
-u64 ep93xx_clocksource_read(struct clocksource *c)
+static u64 ep93xx_clocksource_read(struct clocksource *c)
 {
 	u64 ret;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-exynos/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-exynos/Kconfig
@@ -8,7 +8,6 @@
 menuconfig ARCH_EXYNOS
 	bool "Samsung EXYNOS"
 	depends on ARCH_MULTI_V7
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARM_AMBA
 	select ARM_GIC
--- linux-ein-5.4.0.orig/arch/arm/mach-exynos/exynos.c
+++ linux-ein-5.4.0/arch/arm/mach-exynos/exynos.c
@@ -46,6 +46,7 @@
 		sysram_base_addr = of_iomap(node, 0);
 		sysram_base_phys = of_translate_address(node,
 					   of_get_address(node, 0, NULL, NULL));
+		of_node_put(node);
 		break;
 	}
 
@@ -53,6 +54,7 @@
 		if (!of_device_is_available(node))
 			continue;
 		sysram_ns_base_addr = of_iomap(node, 0);
+		of_node_put(node);
 		break;
 	}
 }
@@ -134,6 +136,7 @@
 	np = of_find_matching_node(NULL, exynos_dt_pmu_match);
 	if (np)
 		pmu_base_addr = of_iomap(np, 0);
+	of_node_put(np);
 }
 
 static void __init exynos_init_irq(void)
--- linux-ein-5.4.0.orig/arch/arm/mach-exynos/mcpm-exynos.c
+++ linux-ein-5.4.0/arch/arm/mach-exynos/mcpm-exynos.c
@@ -26,6 +26,7 @@
 #define EXYNOS5420_USE_L2_COMMON_UP_STATE	BIT(30)
 
 static void __iomem *ns_sram_base_addr __ro_after_init;
+static bool secure_firmware __ro_after_init;
 
 /*
  * The common v7_exit_coherency_flush API could not be used because of the
@@ -58,15 +59,16 @@
 static int exynos_cpu_powerup(unsigned int cpu, unsigned int cluster)
 {
 	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+	bool state;
 
 	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
 	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
 		cluster >= EXYNOS5420_NR_CLUSTERS)
 		return -EINVAL;
 
-	if (!exynos_cpu_power_state(cpunr)) {
-		exynos_cpu_power_up(cpunr);
-
+	state = exynos_cpu_power_state(cpunr);
+	exynos_cpu_power_up(cpunr);
+	if (!state && secure_firmware) {
 		/*
 		 * This assumes the cluster number of the big cores(Cortex A15)
 		 * is 0 and the Little cores(Cortex A7) is 1.
@@ -258,6 +260,8 @@
 		return -ENOMEM;
 	}
 
+	secure_firmware = exynos_secure_firmware_available();
+
 	/*
 	 * To increase the stability of KFC reset we need to program
 	 * the PMU SPARE3 register
--- linux-ein-5.4.0.orig/arch/arm/mach-footbridge/cats-pci.c
+++ linux-ein-5.4.0/arch/arm/mach-footbridge/cats-pci.c
@@ -15,14 +15,14 @@
 #include <asm/mach-types.h>
 
 /* cats host-specific stuff */
-static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
+static int irqmap_cats[] = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
 
 static u8 cats_no_swizzle(struct pci_dev *dev, u8 *pin)
 {
 	return 0;
 }
 
-static int __init cats_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int cats_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	if (dev->irq >= 255)
 		return -1;	/* not a valid interrupt. */
--- linux-ein-5.4.0.orig/arch/arm/mach-footbridge/dc21285.c
+++ linux-ein-5.4.0/arch/arm/mach-footbridge/dc21285.c
@@ -66,15 +66,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;
 		}
@@ -100,17 +100,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-ein-5.4.0.orig/arch/arm/mach-footbridge/ebsa285-pci.c
+++ linux-ein-5.4.0/arch/arm/mach-footbridge/ebsa285-pci.c
@@ -14,9 +14,9 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
-static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI };
+static int irqmap_ebsa285[] = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI };
 
-static int __init ebsa285_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int ebsa285_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
 	    dev->device == PCI_DEVICE_ID_CONTAQ_82C693)
--- linux-ein-5.4.0.orig/arch/arm/mach-footbridge/netwinder-pci.c
+++ linux-ein-5.4.0/arch/arm/mach-footbridge/netwinder-pci.c
@@ -18,7 +18,7 @@
  * We now use the slot ID instead of the device identifiers to select
  * which interrupt is routed where.
  */
-static int __init netwinder_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int netwinder_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	switch (slot) {
 	case 0:  /* host bridge */
--- linux-ein-5.4.0.orig/arch/arm/mach-footbridge/personal-pci.c
+++ linux-ein-5.4.0/arch/arm/mach-footbridge/personal-pci.c
@@ -14,13 +14,12 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
-static int irqmap_personal_server[] __initdata = {
+static int irqmap_personal_server[] = {
 	IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0,
 	IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI
 };
 
-static int __init personal_server_map_irq(const struct pci_dev *dev, u8 slot,
-	u8 pin)
+static int personal_server_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 	unsigned char line;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-highbank/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-highbank/Kconfig
@@ -2,7 +2,6 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000/2000 (Highbank/Midway)"
 	depends on ARCH_MULTI_V7
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARM_AMBA
 	select ARM_ERRATA_764369 if SMP
--- linux-ein-5.4.0.orig/arch/arm/mach-hisi/platsmp.c
+++ linux-ein-5.4.0/arch/arm/mach-hisi/platsmp.c
@@ -67,14 +67,17 @@
 		}
 		ctrl_base = of_iomap(np, 0);
 		if (!ctrl_base) {
+			of_node_put(np);
 			pr_err("failed to map address\n");
 			return;
 		}
 		if (of_property_read_u32(np, "smp-offset", &offset) < 0) {
+			of_node_put(np);
 			pr_err("failed to find smp-offset property\n");
 			return;
 		}
 		ctrl_base += offset;
+		of_node_put(np);
 	}
 }
 
@@ -160,6 +163,7 @@
 	if (WARN_ON(!node))
 		return -1;
 	ctrl_base = of_iomap(node, 0);
+	of_node_put(node);
 
 	/* set the secondary core boot from DDR */
 	remap_reg_value = readl_relaxed(ctrl_base + REG_SC_CTRL);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-imx/Kconfig
@@ -40,9 +40,29 @@
 	bool
 	select PM_GENERIC_DOMAINS if PM
 
+config HAVE_IMX_GPCV2
+	bool
+	select PM_GENERIC_DOMAINS if PM
+
 config HAVE_IMX_MMDC
 	bool
 
+config HAVE_IMX_AMP
+	bool
+
+config HAVE_IMX_DDRC
+       bool
+       select HAVE_IMX_BUSFREQ
+
+config HAVE_IMX_BUSFREQ
+       bool
+
+config HAVE_IMX_MU
+	bool
+
+config HAVE_IMX_RPMSG
+	bool
+
 config HAVE_IMX_SRC
 	def_bool y if SMP
 	select ARCH_HAS_RESET_CONTROLLER
@@ -471,8 +491,6 @@
 config SOC_IMX6
 	bool
 	select ARM_CPU_SUSPEND if (PM || CPU_IDLE)
-	select ARM_ERRATA_754322
-	select ARM_ERRATA_775420
 	select ARM_GIC
 	select HAVE_IMX_ANATOP
 	select HAVE_IMX_GPC
@@ -484,6 +502,8 @@
 config SOC_IMX6Q
 	bool "i.MX6 Quad/DualLite support"
 	select ARM_ERRATA_764369 if SMP
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_775420
 	select HAVE_ARM_SCU if SMP
 	select HAVE_ARM_TWD
 	select PINCTRL_IMX6Q
@@ -494,6 +514,8 @@
 
 config SOC_IMX6SL
 	bool "i.MX6 SoloLite support"
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_775420
 	select PINCTRL_IMX6SL
 	select SOC_IMX6
 
@@ -502,6 +524,8 @@
 
 config SOC_IMX6SLL
 	bool "i.MX6 SoloLiteLite support"
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_775420
 	select PINCTRL_IMX6SLL
 	select SOC_IMX6
 
@@ -510,7 +534,10 @@
 
 config SOC_IMX6SX
 	bool "i.MX6 SoloX support"
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_775420
 	select PINCTRL_IMX6SX
+	select HAVE_IMX_AMP
 	select SOC_IMX6
 
 	help
@@ -520,6 +547,7 @@
 	bool "i.MX6 UltraLite support"
 	select PINCTRL_IMX6UL
 	select SOC_IMX6
+	select ARM_ERRATA_814220
 
 	help
 	  This enables support for Freescale i.MX6 UltraLite processor.
@@ -534,10 +562,10 @@
 
 endif
 
-comment "Cortex-A/Cortex-M asymmetric multiprocessing platforms"
-
 if ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M
 
+comment "Cortex-A/Cortex-M asymmetric multiprocessing platforms"
+
 config SOC_IMX7D_CA7
 	bool
 	select ARM_GIC
@@ -546,6 +574,11 @@
 	select HAVE_IMX_MMDC
 	select HAVE_IMX_SRC
 	select IMX_GPCV2
+	select HAVE_IMX_DDRC
+	select HAVE_IMX_MU
+	select HAVE_IMX_RPMSG
+	select HAVE_IMX_GPCV2
+	select KEYBOARD_SNVS_PWRKEY
 
 config SOC_IMX7D_CM4
 	bool
@@ -556,6 +589,7 @@
 	select PINCTRL_IMX7D
 	select SOC_IMX7D_CA7 if ARCH_MULTI_V7
 	select SOC_IMX7D_CM4 if ARM_SINGLE_ARMV7M
+	select ARM_ERRATA_814220 if ARCH_MULTI_V7
 	help
 		This enables support for Freescale i.MX7 Dual processor.
 
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/Makefile
+++ linux-ein-5.4.0/arch/arm/mach-imx/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-y := cpu.o system.o irq-common.o
+obj-y := cpu.o system.o irq-common.o common.o
 
 obj-$(CONFIG_SOC_IMX21) += mm-imx21.o
 
@@ -30,6 +30,8 @@
 obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o
 obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6sx.o
 obj-$(CONFIG_SOC_IMX7ULP) += cpuidle-imx7ulp.o
+AFLAGS_imx7d_low_power_idle.o :=-Wa,-march=armv7-a
+obj-$(CONFIG_SOC_IMX7D_CA7) += cpuidle-imx7d.o imx7d_low_power_idle.o
 endif
 
 ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
@@ -70,8 +72,11 @@
 
 obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
+obj-$(CONFIG_HAVE_IMX_GPCV2) += gpcv2.o
 obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
 obj-$(CONFIG_HAVE_IMX_SRC) += src.o
+obj-$(CONFIG_HAVE_IMX_DDRC) += ddrc.o
+obj-$(CONFIG_HAVE_IMX_MU) += mu.o
 ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
 AFLAGS_headsmp.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
@@ -82,15 +87,26 @@
 obj-$(CONFIG_SOC_IMX6SLL) += mach-imx6sl.o
 obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
 obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o
-obj-$(CONFIG_SOC_IMX7D_CA7) += mach-imx7d.o
+obj-$(CONFIG_SOC_IMX7D_CA7) += mach-imx7d.o pm-imx7.o ddr3_freq_imx7d.o smp_wfe.o \
+			   lpddr3_freq_imx.o suspend-imx7.o
 obj-$(CONFIG_SOC_IMX7D_CM4) += mach-imx7d-cm4.o
 obj-$(CONFIG_SOC_IMX7ULP) += mach-imx7ulp.o pm-imx7ulp.o
 
+obj-y += busfreq-imx.o busfreq_ddr3.o
+AFLAGS_smp_wfe.o :=-Wa,-march=armv7-a
+AFLAGS_ddr3_freq_imx7d.o :=-Wa,-march=armv7-a
+AFLAGS_lpddr3_freq_imx.o :=-Wa,-march=armv7-a
+
 ifeq ($(CONFIG_SUSPEND),y)
 AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
+AFLAGS_suspend-imx7.o :=-Wa,-march=armv7-a
 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_IMX1) += mach-imx1.o
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/anatop.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/anatop.c
@@ -4,6 +4,7 @@
  * Copyright 2017-2018 NXP.
  */
 
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -16,11 +17,17 @@
 #define REG_SET		0x4
 #define REG_CLR		0x8
 
+#define ANADIG_ARM_PLL		0x60
+#define ANADIG_DDR_PLL		0x70
+#define ANADIG_SYS_PLL		0xb0
+#define ANADIG_ENET_PLL		0xe0
+#define ANADIG_AUDIO_PLL	0xf0
+#define ANADIG_VIDEO_PLL	0x130
+
 #define ANADIG_REG_2P5		0x130
 #define ANADIG_REG_CORE		0x140
 #define ANADIG_ANA_MISC0	0x150
-#define ANADIG_USB1_CHRG_DETECT	0x1b0
-#define ANADIG_USB2_CHRG_DETECT	0x210
+#define ANADIG_ANA_MISC2	0x170
 #define ANADIG_DIGPROG		0x260
 #define ANADIG_DIGPROG_IMX6SL	0x280
 #define ANADIG_DIGPROG_IMX7D	0x800
@@ -30,11 +37,21 @@
 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG	0x40000
 #define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN	0x8
 #define BM_ANADIG_REG_CORE_FET_ODRIVE		0x20000000
+#define BM_ANADIG_REG_CORE_REG1			(0x1f << 9)
+#define BM_ANADIG_REG_CORE_REG2			(0x1f << 18)
+#define BP_ANADIG_REG_CORE_REG2			(18)
 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	0x1000
+#define BM_ANADIG_ANA_MISC0_V2_STOP_MODE_CONFIG	0x800
+#define BM_ANADIG_ANA_MISC0_V3_STOP_MODE_CONFIG	0xc00
+#define BM_ANADIG_ANA_MISC2_REG1_STEP_TIME	(0x3 << 26)
+#define BP_ANADIG_ANA_MISC2_REG1_STEP_TIME	(26)
 /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
 #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS	0x2000
-#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x80000
-#define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x100000
+/* Since i.MX6SX, DISCON_HIGH_SNVS is changed to bit 12 */
+#define BM_ANADIG_ANA_MISC0_V2_DISCON_HIGH_SNVS	0x1000
+
+#define LDO_RAMP_UP_UNIT_IN_CYCLES      64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */
 
 static struct regmap *anatop;
 
@@ -71,6 +88,17 @@
 
 void imx_anatop_pre_suspend(void)
 {
+	if (cpu_is_imx7d()) {
+		/* PLL and PFDs overwrite set */
+		regmap_write(anatop, ANADIG_ARM_PLL + REG_SET, 1 << 20);
+		regmap_write(anatop, ANADIG_DDR_PLL + REG_SET, 1 << 19);
+		regmap_write(anatop, ANADIG_SYS_PLL + REG_SET, 0x1ff << 17);
+		regmap_write(anatop, ANADIG_ENET_PLL + REG_SET, 1 << 13);
+		regmap_write(anatop, ANADIG_AUDIO_PLL + REG_SET, 1 << 24);
+		regmap_write(anatop, ANADIG_VIDEO_PLL + REG_SET, 1 << 24);
+		return;
+	}
+
 	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
 		imx_anatop_enable_2p5_pulldown(true);
 	else
@@ -84,6 +112,17 @@
 
 void imx_anatop_post_resume(void)
 {
+	if (cpu_is_imx7d()) {
+		/* PLL and PFDs overwrite clear */
+		regmap_write(anatop, ANADIG_ARM_PLL + REG_CLR, 1 << 20);
+		regmap_write(anatop, ANADIG_DDR_PLL + REG_CLR, 1 << 19);
+		regmap_write(anatop, ANADIG_SYS_PLL + REG_CLR, 0x1ff << 17);
+		regmap_write(anatop, ANADIG_ENET_PLL + REG_CLR, 1 << 13);
+		regmap_write(anatop, ANADIG_AUDIO_PLL + REG_CLR, 1 << 24);
+		regmap_write(anatop, ANADIG_VIDEO_PLL + REG_CLR, 1 << 24);
+		return;
+	}
+
 	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
 		imx_anatop_enable_2p5_pulldown(false);
 	else
@@ -93,27 +132,17 @@
 
 	if (cpu_is_imx6sl())
 		imx_anatop_disconnect_high_snvs(false);
-
-}
-
-static void imx_anatop_usb_chrg_detect_disable(void)
-{
-	regmap_write(anatop, ANADIG_USB1_CHRG_DETECT,
-		BM_ANADIG_USB_CHRG_DETECT_EN_B
-		| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
-	regmap_write(anatop, ANADIG_USB2_CHRG_DETECT,
-		BM_ANADIG_USB_CHRG_DETECT_EN_B |
-		BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
 }
 
 void __init imx_init_revision_from_anatop(void)
 {
-	struct device_node *np;
+	struct device_node *np, *src_np;
 	void __iomem *anatop_base;
+	void __iomem *src_base;
 	unsigned int revision;
-	u32 digprog;
+	u32 digprog, sbmr2 = 0;
 	u16 offset = ANADIG_DIGPROG;
-	u8 major_part, minor_part;
+	u16 major_part, minor_part;
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
 	anatop_base = of_iomap(np, 0);
@@ -149,9 +178,10 @@
 			void __iomem *src_base;
 			u32 sbmr2;
 
-			np = of_find_compatible_node(NULL, NULL,
+			src_np = of_find_compatible_node(NULL, NULL,
 						     "fsl,imx6ul-src");
-			src_base = of_iomap(np, 0);
+			src_base = of_iomap(src_np, 0);
+			of_node_put(src_np);
 			WARN_ON(!src_base);
 			sbmr2 = readl_relaxed(src_base + SRC_SBMR2);
 			iounmap(src_base);
@@ -163,6 +193,7 @@
 			}
 		}
 	}
+	of_node_put(np);
 
 	mxc_set_cpu_type(digprog >> 16 & 0xff);
 	imx_set_soc_revision(revision);
@@ -171,10 +202,6 @@
 void __init imx_anatop_init(void)
 {
 	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
-	if (IS_ERR(anatop)) {
+	if (IS_ERR(anatop))
 		pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__);
-		return;
-	}
-
-	imx_anatop_usb_chrg_detect_disable();
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/busfreq-imx.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/busfreq-imx.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
+ * Copyright 2018 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/tlb.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/reboot.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include "hardware.h"
+#include "common.h"
+
+#define LPAPM_CLK		24000000
+#define LOW_AUDIO_CLK		50000000
+#define HIGH_AUDIO_CLK		100000000
+
+#define LOW_POWER_RUN_VOLTAGE	950000
+
+#define MMDC_MDMISC_DDR_TYPE_DDR3	0
+#define MMDC_MDMISC_DDR_TYPE_LPDDR2	1
+
+unsigned int ddr_med_rate;
+unsigned int ddr_normal_rate;
+unsigned long ddr_freq_change_total_size;
+unsigned long ddr_freq_change_iram_base;
+unsigned long ddr_freq_change_iram_phys;
+
+static int ddr_type;
+static int low_bus_freq_mode;
+static int audio_bus_freq_mode;
+static int ultra_low_bus_freq_mode;
+static int high_bus_freq_mode;
+static int med_bus_freq_mode;
+static int bus_freq_scaling_initialized;
+static bool cancel_reduce_bus_freq;
+static struct device *busfreq_dev;
+static int busfreq_suspended;
+static int bus_freq_scaling_is_active;
+static int high_bus_count, med_bus_count, audio_bus_count, low_bus_count;
+static unsigned int ddr_low_rate;
+static int cur_bus_freq_mode;
+
+extern unsigned long iram_tlb_phys_addr;
+extern int unsigned long iram_tlb_base_addr;
+
+/*
+ * Bus frequency management by Linux
+ */
+extern int init_mmdc_lpddr2_settings(struct platform_device *dev);
+extern int init_mmdc_lpddr2_settings_mx6q(struct platform_device *dev);
+extern int init_mmdc_ddr3_settings_imx6_up(struct platform_device *dev);
+extern int init_mmdc_ddr3_settings_imx6_smp(struct platform_device *dev);
+extern int init_ddrc_ddr_settings(struct platform_device *dev);
+extern int update_ddr_freq_imx_smp(int ddr_rate);
+extern int update_ddr_freq_imx6_up(int ddr_rate);
+extern int update_lpddr2_freq(int ddr_rate);
+extern int update_lpddr2_freq_smp(int ddr_rate);
+
+
+/**
+ * @brief  Functions to init and update the busfreq function of
+ *         device and memory type
+ */
+static struct busfreq_func {
+	int (*init)(struct platform_device *dev);
+	int (*update)(int ddr_rate);
+} busfreq_func = {NULL, NULL};
+
+DEFINE_MUTEX(bus_freq_mutex);
+
+static struct clk *osc_clk;
+static struct clk *ahb_clk;
+static struct clk *axi_sel_clk;
+static struct clk *dram_root;
+static struct clk *dram_alt_sel;
+static struct clk *dram_alt_root;
+static struct clk *pfd0_392m;
+static struct clk *pfd2_270m;
+static struct clk *pfd1_332m;
+static struct clk *pll_dram;
+static struct clk *ahb_sel_clk;
+static struct clk *axi_clk;
+
+static struct delayed_work low_bus_freq_handler;
+static struct delayed_work bus_freq_daemon;
+
+static RAW_NOTIFIER_HEAD(busfreq_notifier_chain);
+
+static bool busfreq_notified_low = false;
+
+static int busfreq_notify(enum busfreq_event event)
+{
+	int ret;
+
+	if (event == LOW_BUSFREQ_ENTER) {
+		WARN_ON(busfreq_notified_low);
+		busfreq_notified_low = true;
+	} else if (event == LOW_BUSFREQ_EXIT) {
+		WARN_ON(!busfreq_notified_low);
+		busfreq_notified_low = false;
+	}
+	ret = raw_notifier_call_chain(&busfreq_notifier_chain, event, NULL);
+
+	return notifier_to_errno(ret);
+}
+
+int register_busfreq_notifier(struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&busfreq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(register_busfreq_notifier);
+
+int unregister_busfreq_notifier(struct notifier_block *nb)
+{
+	return raw_notifier_chain_unregister(&busfreq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(unregister_busfreq_notifier);
+
+static void enter_lpm_imx7d(void)
+{
+	/*
+	 * The AHB clock parent switch and divider change
+	 * needs to keep previous/current parent enabled
+	 * per design requirement, but when we switch the
+	 * clock parent, previous AHB clock parent may be
+	 * disabled by common clock framework, so here we
+	 * have to make sure AHB's previous parent pfd2_270m
+	 * is enabled during AHB set rate.
+	 */
+	clk_prepare_enable(pfd2_270m);
+	if (audio_bus_count) {
+		clk_prepare_enable(pfd0_392m);
+		busfreq_func.update(HIGH_AUDIO_CLK);
+
+		clk_set_parent(dram_alt_sel, pfd0_392m);
+		clk_set_parent(dram_root, dram_alt_root);
+		if (high_bus_freq_mode) {
+			clk_set_parent(axi_sel_clk, osc_clk);
+			clk_set_parent(ahb_sel_clk, osc_clk);
+			clk_set_rate(ahb_clk, LPAPM_CLK);
+		}
+		clk_disable_unprepare(pfd0_392m);
+		audio_bus_freq_mode = 1;
+		low_bus_freq_mode = 0;
+		cur_bus_freq_mode = BUS_FREQ_AUDIO;
+	} else {
+		busfreq_func.update(LPAPM_CLK);
+
+		clk_set_parent(dram_alt_sel, osc_clk);
+		clk_set_parent(dram_root, dram_alt_root);
+		if (high_bus_freq_mode) {
+			clk_set_parent(axi_sel_clk, osc_clk);
+			clk_set_parent(ahb_sel_clk, osc_clk);
+			clk_set_rate(ahb_clk, LPAPM_CLK);
+		}
+		low_bus_freq_mode = 1;
+		audio_bus_freq_mode = 0;
+		cur_bus_freq_mode = BUS_FREQ_LOW;
+	}
+	clk_disable_unprepare(pfd2_270m);
+}
+
+static void exit_lpm_imx7d(void)
+{
+	clk_set_parent(axi_sel_clk, pfd1_332m);
+	clk_set_rate(ahb_clk, LPAPM_CLK / 2);
+	clk_set_parent(ahb_sel_clk, pfd2_270m);
+
+	busfreq_func.update(ddr_normal_rate);
+
+	clk_set_parent(dram_root, pll_dram);
+}
+
+static void reduce_bus_freq(void)
+{
+	if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode))
+		busfreq_notify(LOW_BUSFREQ_EXIT);
+	else if (!audio_bus_count)
+		busfreq_notify(LOW_BUSFREQ_ENTER);
+
+	if (cpu_is_imx7d())
+		enter_lpm_imx7d();
+
+	med_bus_freq_mode = 0;
+	high_bus_freq_mode = 0;
+
+	if (audio_bus_freq_mode)
+		dev_dbg(busfreq_dev,
+			"Bus freq set to audio mode. Count: high %d, med %d, audio %d\n",
+			high_bus_count, med_bus_count, audio_bus_count);
+	if (low_bus_freq_mode)
+		dev_dbg(busfreq_dev,
+			"Bus freq set to low mode. Count: high %d, med %d, audio %d\n",
+			high_bus_count, med_bus_count, audio_bus_count);
+}
+
+static inline void cancel_low_bus_freq_handler(void)
+{
+	cancel_delayed_work(&low_bus_freq_handler);
+	cancel_reduce_bus_freq = true;
+}
+
+static void reduce_bus_freq_handler(struct work_struct *work)
+{
+	mutex_lock(&bus_freq_mutex);
+
+	if (!cancel_reduce_bus_freq) {
+		reduce_bus_freq();
+		cancel_low_bus_freq_handler();
+	}
+
+	mutex_unlock(&bus_freq_mutex);
+}
+
+/*
+ * Set the DDR, AHB to 24MHz.
+ * This mode will be activated only when none of the modules that
+ * need a higher DDR or AHB frequency are active.
+ */
+static int set_low_bus_freq(void)
+{
+	if (busfreq_suspended)
+		return 0;
+
+	if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+		return 0;
+
+	cancel_reduce_bus_freq = false;
+
+	/*
+	 * Check to see if we need to got from
+	 * low bus freq mode to audio bus freq mode.
+	 * If so, the change needs to be done immediately.
+	 */
+	if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode))
+		reduce_bus_freq();
+	else
+		/*
+		 * Don't lower the frequency immediately. Instead
+		 * scheduled a delayed work and drop the freq if
+		 * the conditions still remain the same.
+		 */
+		schedule_delayed_work(&low_bus_freq_handler,
+					usecs_to_jiffies(3000000));
+	return 0;
+}
+
+/*
+ * Set the DDR to either 528MHz or 400MHz for iMX6qd
+ * or 400MHz for iMX6dl.
+ */
+static int set_high_bus_freq(int high_bus_freq)
+{
+	if (bus_freq_scaling_initialized && bus_freq_scaling_is_active)
+		cancel_low_bus_freq_handler();
+
+	if (busfreq_suspended)
+		return 0;
+
+	if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+		return 0;
+
+	if (high_bus_freq_mode)
+		return 0;
+
+	/* medium bus freq is only supported for MX6DQ */
+	if (med_bus_freq_mode && !high_bus_freq)
+		return 0;
+
+	if (low_bus_freq_mode || ultra_low_bus_freq_mode)
+		busfreq_notify(LOW_BUSFREQ_EXIT);
+
+	if (cpu_is_imx7d())
+		exit_lpm_imx7d();
+
+	high_bus_freq_mode = 1;
+	med_bus_freq_mode = 0;
+	low_bus_freq_mode = 0;
+	audio_bus_freq_mode = 0;
+	cur_bus_freq_mode = BUS_FREQ_HIGH;
+
+	if (high_bus_freq_mode)
+		dev_dbg(busfreq_dev,
+			"Bus freq set to high mode. Count: high %d, med %d, audio %d\n",
+			high_bus_count, med_bus_count, audio_bus_count);
+	if (med_bus_freq_mode)
+		dev_dbg(busfreq_dev,
+			"Bus freq set to med mode. Count: high %d, med %d, audio %d\n",
+			high_bus_count, med_bus_count, audio_bus_count);
+
+	return 0;
+}
+
+void request_bus_freq(enum bus_freq_mode mode)
+{
+	mutex_lock(&bus_freq_mutex);
+
+	if (mode == BUS_FREQ_ULTRA_LOW) {
+		dev_dbg(busfreq_dev, "This mode cannot be requested!\n");
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	if (mode == BUS_FREQ_HIGH)
+		high_bus_count++;
+	else if (mode == BUS_FREQ_MED)
+		med_bus_count++;
+	else if (mode == BUS_FREQ_AUDIO)
+		audio_bus_count++;
+	else if (mode == BUS_FREQ_LOW)
+		low_bus_count++;
+
+	if (busfreq_suspended || !bus_freq_scaling_initialized ||
+		!bus_freq_scaling_is_active) {
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	cancel_low_bus_freq_handler();
+
+	if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) {
+		set_high_bus_freq(1);
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	if ((mode == BUS_FREQ_MED) && (!high_bus_freq_mode) &&
+		(!med_bus_freq_mode)) {
+		set_high_bus_freq(0);
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+	if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) &&
+		(!med_bus_freq_mode) && (!audio_bus_freq_mode)) {
+		set_low_bus_freq();
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+	mutex_unlock(&bus_freq_mutex);
+}
+EXPORT_SYMBOL(request_bus_freq);
+
+void release_bus_freq(enum bus_freq_mode mode)
+{
+	mutex_lock(&bus_freq_mutex);
+
+	if (mode == BUS_FREQ_ULTRA_LOW) {
+		dev_dbg(busfreq_dev,
+			"This mode cannot be released!\n");
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	if (mode == BUS_FREQ_HIGH) {
+		if (high_bus_count == 0) {
+			dev_err(busfreq_dev, "high bus count mismatch!\n");
+			dump_stack();
+			mutex_unlock(&bus_freq_mutex);
+			return;
+		}
+		high_bus_count--;
+	} else if (mode == BUS_FREQ_MED) {
+		if (med_bus_count == 0) {
+			dev_err(busfreq_dev, "med bus count mismatch!\n");
+			dump_stack();
+			mutex_unlock(&bus_freq_mutex);
+			return;
+		}
+		med_bus_count--;
+	} else if (mode == BUS_FREQ_AUDIO) {
+		if (audio_bus_count == 0) {
+			dev_err(busfreq_dev, "audio bus count mismatch!\n");
+			dump_stack();
+			mutex_unlock(&bus_freq_mutex);
+			return;
+		}
+		audio_bus_count--;
+	} else if (mode == BUS_FREQ_LOW) {
+		if (low_bus_count == 0) {
+			dev_err(busfreq_dev, "low bus count mismatch!\n");
+			dump_stack();
+			mutex_unlock(&bus_freq_mutex);
+			return;
+		}
+		low_bus_count--;
+	}
+
+	if (busfreq_suspended || !bus_freq_scaling_initialized ||
+		!bus_freq_scaling_is_active) {
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	if ((!audio_bus_freq_mode) && (high_bus_count == 0) &&
+		(med_bus_count == 0) && (audio_bus_count != 0)) {
+		set_low_bus_freq();
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+	if ((!low_bus_freq_mode) && (high_bus_count == 0) &&
+		(med_bus_count == 0) && (audio_bus_count == 0) &&
+		(low_bus_count != 0)) {
+		set_low_bus_freq();
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+	if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) &&
+		(med_bus_count == 0) && (audio_bus_count == 0) &&
+		(low_bus_count == 0)) {
+		set_low_bus_freq();
+		mutex_unlock(&bus_freq_mutex);
+		return;
+	}
+
+	mutex_unlock(&bus_freq_mutex);
+}
+EXPORT_SYMBOL(release_bus_freq);
+
+int get_bus_freq_mode(void)
+{
+	return cur_bus_freq_mode;
+}
+EXPORT_SYMBOL(get_bus_freq_mode);
+
+static struct map_desc ddr_iram_io_desc __initdata = {
+	/* .virtual and .pfn are run-time assigned */
+	.length		= SZ_1M,
+	.type		= MT_MEMORY_RWX_NONCACHED,
+};
+
+static int __init imx_dt_find_ddr_sram(unsigned long node,
+		const char *uname, int depth, void *data)
+{
+	unsigned long ddr_iram_addr;
+	const __be32 *prop;
+
+	if (of_flat_dt_is_compatible(node, "fsl,ddr-lpm-sram")) {
+		unsigned int len;
+
+		prop = of_get_flat_dt_prop(node, "reg", &len);
+		if (prop == NULL || len != (sizeof(unsigned long) * 2))
+			return -EINVAL;
+		ddr_iram_addr = be32_to_cpu(prop[0]);
+		ddr_freq_change_total_size = be32_to_cpu(prop[1]);
+		ddr_freq_change_iram_phys = ddr_iram_addr;
+
+		/* Make sure ddr_freq_change_iram_phys is 8 byte aligned. */
+		if ((uintptr_t)(ddr_freq_change_iram_phys) & (FNCPY_ALIGN - 1))
+			ddr_freq_change_iram_phys += FNCPY_ALIGN -
+				((uintptr_t)ddr_freq_change_iram_phys %
+				(FNCPY_ALIGN));
+	}
+	return 0;
+}
+
+void __init imx_busfreq_map_io(void)
+{
+	/*
+	 * Get the address of IRAM to be used by the ddr frequency
+	 * change code from the device tree.
+	 */
+	WARN_ON(of_scan_flat_dt(imx_dt_find_ddr_sram, NULL));
+	if (ddr_freq_change_iram_phys) {
+		ddr_freq_change_iram_base = IMX_IO_P2V(
+			ddr_freq_change_iram_phys);
+		if ((iram_tlb_phys_addr & 0xFFF00000) !=
+			(ddr_freq_change_iram_phys & 0xFFF00000)) {
+			/* We need to create a 1M page table entry. */
+			ddr_iram_io_desc.virtual = IMX_IO_P2V(
+				ddr_freq_change_iram_phys & 0xFFF00000);
+			ddr_iram_io_desc.pfn = __phys_to_pfn(
+				ddr_freq_change_iram_phys & 0xFFF00000);
+			iotable_init(&ddr_iram_io_desc, 1);
+		}
+		memset((void *)ddr_freq_change_iram_base, 0,
+			ddr_freq_change_total_size);
+	}
+}
+
+static void bus_freq_daemon_handler(struct work_struct *work)
+{
+	mutex_lock(&bus_freq_mutex);
+	if ((!low_bus_freq_mode) && (!ultra_low_bus_freq_mode)
+		&& (high_bus_count == 0) &&
+		(med_bus_count == 0) && (audio_bus_count == 0))
+		set_low_bus_freq();
+	mutex_unlock(&bus_freq_mutex);
+}
+
+static ssize_t bus_freq_scaling_enable_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	if (bus_freq_scaling_is_active)
+		return sprintf(buf, "Bus frequency scaling is enabled\n");
+	else
+		return sprintf(buf, "Bus frequency scaling is disabled\n");
+}
+
+static ssize_t bus_freq_scaling_enable_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	if (strncmp(buf, "1", 1) == 0) {
+		bus_freq_scaling_is_active = 1;
+		set_high_bus_freq(1);
+		/*
+		 * We set bus freq to highest at the beginning,
+		 * so we use this daemon thread to make sure system
+		 * can enter low bus mode if
+		 * there is no high bus request pending
+		 */
+		schedule_delayed_work(&bus_freq_daemon,
+			usecs_to_jiffies(5000000));
+	} else if (strncmp(buf, "0", 1) == 0) {
+		if (bus_freq_scaling_is_active)
+			set_high_bus_freq(1);
+		bus_freq_scaling_is_active = 0;
+	}
+	return size;
+}
+
+static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event,
+	void *dummy)
+{
+	mutex_lock(&bus_freq_mutex);
+
+	if (event == PM_SUSPEND_PREPARE) {
+		if (cpu_is_imx7d() && imx_src_is_m4_enabled())
+			imx_mu_lpm_ready(false);
+		high_bus_count++;
+		set_high_bus_freq(1);
+		busfreq_suspended = 1;
+	} else if (event == PM_POST_SUSPEND) {
+		busfreq_suspended = 0;
+		high_bus_count--;
+		if (cpu_is_imx7d() && imx_src_is_m4_enabled())
+			imx_mu_lpm_ready(true);
+		schedule_delayed_work(&bus_freq_daemon,
+			usecs_to_jiffies(5000000));
+	}
+
+	mutex_unlock(&bus_freq_mutex);
+
+	return NOTIFY_OK;
+}
+
+static int busfreq_reboot_notifier_event(struct notifier_block *this,
+						 unsigned long event, void *ptr)
+{
+	/* System is rebooting. Set the system into high_bus_freq_mode. */
+	request_bus_freq(BUS_FREQ_HIGH);
+
+	return 0;
+}
+
+static struct notifier_block imx_bus_freq_pm_notifier = {
+	.notifier_call = bus_freq_pm_notify,
+};
+
+static struct notifier_block imx_busfreq_reboot_notifier = {
+	.notifier_call = busfreq_reboot_notifier_event,
+};
+
+
+static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
+			bus_freq_scaling_enable_store);
+
+/*!
+ * This is the probe routine for the bus frequency driver.
+ *
+ * @param   pdev   The platform device structure
+ *
+ * @return         The function returns 0 on success
+ *
+ */
+
+static int busfreq_probe(struct platform_device *pdev)
+{
+	u32 err;
+
+	busfreq_dev = &pdev->dev;
+
+	/* Return if no IRAM space is allocated for ddr freq change code. */
+	if (!ddr_freq_change_iram_base)
+		return -ENOMEM;
+
+	if (cpu_is_imx7d()) {
+		osc_clk = devm_clk_get(&pdev->dev, "osc");
+		axi_sel_clk = devm_clk_get(&pdev->dev, "axi_sel");
+		ahb_sel_clk = devm_clk_get(&pdev->dev, "ahb_sel");
+		pfd0_392m = devm_clk_get(&pdev->dev, "pfd0_392m");
+		dram_root = devm_clk_get(&pdev->dev, "dram_root");
+		dram_alt_sel = devm_clk_get(&pdev->dev, "dram_alt_sel");
+		pll_dram = devm_clk_get(&pdev->dev, "pll_dram");
+		dram_alt_root = devm_clk_get(&pdev->dev, "dram_alt_root");
+		pfd1_332m = devm_clk_get(&pdev->dev, "pfd1_332m");
+		pfd2_270m = devm_clk_get(&pdev->dev, "pfd2_270m");
+		ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+		axi_clk = devm_clk_get(&pdev->dev, "axi");
+		if (IS_ERR(osc_clk) || IS_ERR(axi_sel_clk) || IS_ERR(ahb_clk)
+			|| IS_ERR(pfd0_392m) || IS_ERR(dram_root)
+			|| IS_ERR(dram_alt_sel) || IS_ERR(pll_dram)
+			|| IS_ERR(dram_alt_root) || IS_ERR(pfd1_332m)
+			|| IS_ERR(ahb_clk) || IS_ERR(axi_clk)
+			|| IS_ERR(pfd2_270m)) {
+			dev_err(busfreq_dev,
+				"%s: failed to get busfreq clk\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
+	if (err) {
+		dev_err(busfreq_dev,
+		       "Unable to register sysdev entry for BUSFREQ");
+		return err;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "fsl,max_ddr_freq",
+			&ddr_normal_rate)) {
+		dev_err(busfreq_dev, "max_ddr_freq entry missing\n");
+		return -EINVAL;
+	}
+
+	high_bus_freq_mode = 1;
+	med_bus_freq_mode = 0;
+	low_bus_freq_mode = 0;
+	audio_bus_freq_mode = 0;
+	ultra_low_bus_freq_mode = 0;
+	cur_bus_freq_mode = BUS_FREQ_HIGH;
+
+	bus_freq_scaling_is_active = 1;
+	bus_freq_scaling_initialized = 1;
+
+	ddr_low_rate = LPAPM_CLK;
+
+	INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler);
+	INIT_DELAYED_WORK(&bus_freq_daemon, bus_freq_daemon_handler);
+	register_pm_notifier(&imx_bus_freq_pm_notifier);
+	register_reboot_notifier(&imx_busfreq_reboot_notifier);
+
+	/* enter low bus mode if no high speed device enabled */
+	schedule_delayed_work(&bus_freq_daemon,
+		msecs_to_jiffies(20000));
+
+	/*
+	 * Need to make sure to an entry for the ddr freq change code
+	 * address in the IRAM page table.
+	 * This is only required if the DDR freq code and suspend/idle
+	 * code are in different OCRAM spaces.
+	 */
+	if ((iram_tlb_phys_addr & 0xFFF00000) !=
+		(ddr_freq_change_iram_phys & 0xFFF00000)) {
+		unsigned long i;
+
+		/*
+		 * Make sure the ddr_iram virtual address has a mapping
+		 * in the IRAM page table.
+		 */
+		i = ((IMX_IO_P2V(ddr_freq_change_iram_phys) >> 20) << 2) / 4;
+		*((unsigned long *)iram_tlb_base_addr + i) =
+			(ddr_freq_change_iram_phys  & 0xFFF00000) |
+			TT_ATTRIB_NON_CACHEABLE_1M;
+	}
+
+	if (cpu_is_imx7d()) {
+		ddr_type = imx_ddrc_get_ddr_type();
+		/* reduce ddr3 normal rate to 400M due to CKE issue on TO1.1 */
+		if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_1 &&
+			ddr_type == IMX_DDR_TYPE_DDR3) {
+			ddr_normal_rate = 400000000;
+			pr_info("ddr3 normal rate changed to 400MHz for TO1.1.\n");
+		}
+		busfreq_func.init   = &init_ddrc_ddr_settings;
+		busfreq_func.update = &update_ddr_freq_imx_smp;
+	}
+
+	if (busfreq_func.init)
+		err = busfreq_func.init(pdev);
+	else
+		err = -EINVAL;
+
+	if (!err) {
+		if (cpu_is_imx7d() && imx_src_is_m4_enabled()) {
+			high_bus_count++;
+			imx_mu_lpm_ready(true);
+		}
+	}
+
+	if (err) {
+		dev_err(busfreq_dev, "Busfreq init of ddr controller failed\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id imx_busfreq_ids[] = {
+	{ .compatible = "fsl,imx_busfreq", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver busfreq_driver = {
+	.driver = {
+		.name = "imx_busfreq",
+		.owner  = THIS_MODULE,
+		.of_match_table = imx_busfreq_ids,
+		},
+	.probe = busfreq_probe,
+};
+
+/*!
+ * Initialise the busfreq_driver.
+ *
+ * @return  The function always returns 0.
+ */
+
+static int __init busfreq_init(void)
+{
+#ifndef CONFIG_MX6_VPU_352M
+	if (platform_driver_register(&busfreq_driver) != 0)
+		return -ENODEV;
+
+	pr_info("Bus freq driver module loaded\n");
+#endif
+	return 0;
+}
+
+static void __exit busfreq_cleanup(void)
+{
+	sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
+
+	/* Unregister the device structure */
+	platform_driver_unregister(&busfreq_driver);
+	bus_freq_scaling_initialized = 0;
+}
+
+module_init(busfreq_init);
+module_exit(busfreq_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("BusFreq driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/busfreq_ddr3.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/busfreq_ddr3.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file busfreq_ddr3.c
+ *
+ * @brief iMX6 DDR3 frequency change specific file.
+ *
+ * @ingroup PM
+ */
+#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/tlb.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#include "hardware.h"
+#include "common.h"
+
+#define SMP_WFE_CODE_SIZE	0x400
+
+#define MIN_DLL_ON_FREQ		333000000
+#define MAX_DLL_OFF_FREQ	125000000
+#define MMDC0_MPMUR0		0x8b8
+#define MMDC0_MPMUR0_OFFSET	16
+#define MMDC0_MPMUR0_MASK	0x3ff
+
+/*
+ * This structure is for passing necessary data for low level ocram
+ * busfreq code(arch/arm/mach-imx/ddr3_freq_imx6.S), if this struct
+ * definition is changed, the offset definition in
+ * arch/arm/mach-imx/ddr3_freq_imx6.S must be also changed accordingly,
+ * otherwise, the busfreq change function will be broken!
+ *
+ * This structure will be placed in front of the asm code on ocram.
+ */
+struct imx6_busfreq_info {
+	u32 freq;
+	void *ddr_settings;
+	u32 dll_off;
+	void *iomux_offsets;
+	u32 mu_delay_val;
+} __aligned(8);
+
+/* DDR settings */
+static unsigned long (*iram_iomux_settings)[2];
+
+static void __iomem *gic_dist_base;
+
+static int curr_ddr_rate;
+
+void (*imx7d_change_ddr_freq)(u32 freq) = NULL;
+extern void imx7d_ddr3_freq_change(u32 freq);
+extern void imx_lpddr3_freq_change(u32 freq);
+
+extern unsigned int ddr_normal_rate;
+extern int low_bus_freq_mode;
+extern int audio_bus_freq_mode;
+
+extern unsigned long save_ttbr1(void);
+extern void restore_ttbr1(unsigned long ttbr1);
+extern unsigned long ddr_freq_change_iram_base;
+
+extern unsigned long ddr_freq_change_total_size;
+extern unsigned long iram_tlb_phys_addr;
+
+#ifdef CONFIG_SMP
+volatile u32 *wait_for_ddr_freq_update;
+static unsigned int online_cpus;
+static u32 *irqs_used;
+
+void (*wfe_change_ddr_freq)(u32 cpuid, u32 *ddr_freq_change_done);
+void (*imx7_wfe_change_ddr_freq)(u32 cpuid, u32 ocram_base);
+extern void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done);
+extern void imx7_smp_wfe(u32 cpuid, u32 ocram_base);
+extern unsigned long wfe_smp_freq_change_start asm("wfe_smp_freq_change_start");
+extern unsigned long wfe_smp_freq_change_end asm("wfe_smp_freq_change_end");
+extern void __iomem *imx_scu_base;
+#endif
+
+int can_change_ddr_freq(void)
+{
+	return 1;
+}
+
+#ifdef CONFIG_SMP
+/*
+ * each active core apart from the one changing
+ * the DDR frequency will execute this function.
+ * the rest of the cores have to remain in WFE
+ * state until the frequency is changed.
+ */
+static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id)
+{
+	u32 me;
+
+	me = smp_processor_id();
+#ifdef CONFIG_LOCAL_TIMERS
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+		&me);
+#endif
+	if (cpu_is_imx7d())
+		imx7_wfe_change_ddr_freq(0x8 * me,
+			(u32)ddr_freq_change_iram_base);
+	else
+		wfe_change_ddr_freq(0xff << (me * 8),
+			(u32 *)&iram_iomux_settings[0][1]);
+#ifdef CONFIG_LOCAL_TIMERS
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+		&me);
+#endif
+
+	return IRQ_HANDLED;
+}
+#endif
+
+/* change the DDR frequency. */
+int update_ddr_freq_imx_smp(int ddr_rate)
+{
+	int me = 0;
+	unsigned long ttbr1;
+#ifdef CONFIG_SMP
+	unsigned int reg = 0;
+	int cpu = 0;
+#endif
+
+	if (!can_change_ddr_freq())
+		return -1;
+
+	if (ddr_rate == curr_ddr_rate)
+		return 0;
+
+	printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate);
+
+	/* ensure that all Cores are in WFE. */
+	local_irq_disable();
+
+#ifdef CONFIG_SMP
+	me = smp_processor_id();
+
+	/* Make sure all the online cores are active */
+	while (1) {
+		bool not_exited_busfreq = false;
+		u32 reg = 0;
+
+		for_each_online_cpu(cpu) {
+			if (cpu_is_imx7d())
+				reg = *(wait_for_ddr_freq_update + 1);
+
+			if (reg & (0x02 << (cpu * 8)))
+				not_exited_busfreq = true;
+		}
+		if (!not_exited_busfreq)
+			break;
+	}
+
+	wmb();
+	*wait_for_ddr_freq_update = 1;
+	dsb();
+	if (cpu_is_imx7d())
+		online_cpus = *(wait_for_ddr_freq_update + 1);
+	for_each_online_cpu(cpu) {
+		*((char *)(&online_cpus) + (u8)cpu) = 0x02;
+		if (cpu != me) {
+			/* set the interrupt to be pending in the GIC. */
+			reg = 1 << (irqs_used[cpu] % 32);
+			writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET
+				+ (irqs_used[cpu] / 32) * 4);
+		}
+	}
+	/* Wait for the other active CPUs to idle */
+	while (1) {
+		u32 reg = 0;
+
+		if (cpu_is_imx7d())
+			reg = *(wait_for_ddr_freq_update + 1);
+		reg |= (0x02 << (me * 8));
+		if (reg == online_cpus)
+			break;
+	}
+#endif
+
+	/* Ensure iram_tlb_phys_addr is flushed to DDR. */
+	__cpuc_flush_dcache_area(&iram_tlb_phys_addr,
+		sizeof(iram_tlb_phys_addr));
+
+	ttbr1 = save_ttbr1();
+	/* Now we can change the DDR frequency. */
+	if (cpu_is_imx7d())
+		imx7d_change_ddr_freq(ddr_rate);
+	restore_ttbr1(ttbr1);
+	curr_ddr_rate = ddr_rate;
+
+#ifdef CONFIG_SMP
+	wmb();
+	/* DDR frequency change is done . */
+	*wait_for_ddr_freq_update = 0;
+	dsb();
+
+	/* wake up all the cores. */
+	sev();
+#endif
+
+	local_irq_enable();
+
+	printk(KERN_DEBUG "Bus freq set to %d done! cpu=%d\n", ddr_rate, me);
+
+	return 0;
+}
+
+int init_ddrc_ddr_settings(struct platform_device *busfreq_pdev)
+{
+	int ddr_type = imx_ddrc_get_ddr_type();
+#ifdef CONFIG_SMP
+	struct device_node *node;
+	u32 cpu;
+	struct device *dev = &busfreq_pdev->dev;
+	int err;
+	struct irq_data *d;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,cortex-a7-gic");
+	if (!node) {
+		printk(KERN_ERR "failed to find imx7d-a7-gic device tree data!\n");
+		return -EINVAL;
+	}
+	gic_dist_base = of_iomap(node, 0);
+	WARN(!gic_dist_base, "unable to map gic dist registers\n");
+
+	irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(),
+					GFP_KERNEL);
+	for_each_online_cpu(cpu) {
+		int irq;
+		/*
+		 * set up a reserved interrupt to get all
+		 * the active cores into a WFE state
+		 * before changing the DDR frequency.
+		 */
+		irq = platform_get_irq(busfreq_pdev, cpu);
+		err = request_irq(irq, wait_in_wfe_irq,
+			IRQF_PERCPU, "ddrc", NULL);
+		if (err) {
+			dev_err(dev,
+				"Busfreq:request_irq failed %d, err = %d\n",
+				irq, err);
+			return err;
+		}
+		err = irq_set_affinity(irq, cpumask_of(cpu));
+		if (err) {
+			dev_err(dev,
+				"Busfreq: Cannot set irq affinity irq=%d\n",
+				irq);
+			return err;
+		}
+		d = irq_get_irq_data(irq);
+		irqs_used[cpu] = d->hwirq + 32;
+	}
+
+	/* Store the variable used to communicate between cores */
+	wait_for_ddr_freq_update = (u32 *)ddr_freq_change_iram_base;
+	imx7_wfe_change_ddr_freq = (void *)fncpy(
+		(void *)ddr_freq_change_iram_base + 0x8,
+		&imx7_smp_wfe, SMP_WFE_CODE_SIZE - 0x8);
+#endif
+	if (ddr_type == IMX_DDR_TYPE_DDR3)
+		imx7d_change_ddr_freq = (void *)fncpy(
+			(void *)ddr_freq_change_iram_base + SMP_WFE_CODE_SIZE,
+			&imx7d_ddr3_freq_change,
+			MX7_BUSFREQ_OCRAM_SIZE - SMP_WFE_CODE_SIZE);
+	else if (ddr_type == IMX_DDR_TYPE_LPDDR3
+		|| ddr_type == IMX_DDR_TYPE_LPDDR2)
+		imx7d_change_ddr_freq = (void *)fncpy(
+			(void *)ddr_freq_change_iram_base +
+			SMP_WFE_CODE_SIZE,
+			&imx_lpddr3_freq_change,
+			MX7_BUSFREQ_OCRAM_SIZE - SMP_WFE_CODE_SIZE);
+
+	curr_ddr_rate = ddr_normal_rate;
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/busfreq_lpddr2.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/busfreq_lpddr2.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file busfreq_lpddr2.c
+ *
+ * @brief iMX6 LPDDR2 frequency change specific file.
+ *
+ * @ingroup PM
+ */
+#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/tlb.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+
+#include "common.h"
+#include "hardware.h"
+
+static struct device *busfreq_dev;
+static int curr_ddr_rate;
+static DEFINE_SPINLOCK(freq_lock);
+
+void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode) = NULL;
+
+extern unsigned int ddr_normal_rate;
+extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode);
+extern void imx6_up_lpddr2_freq_change(u32 freq, int bus_freq_mode);
+extern void imx6sll_lpddr2_freq_change(u32 freq, int bus_freq_mode);
+extern unsigned long save_ttbr1(void);
+extern void restore_ttbr1(unsigned long ttbr1);
+extern void mx6q_lpddr2_freq_change(u32 freq, void *ddr_settings);
+extern unsigned long ddr_freq_change_iram_base;
+extern unsigned long imx6_lpddr2_freq_change_start asm("imx6_lpddr2_freq_change_start");
+extern unsigned long imx6_lpddr2_freq_change_end asm("imx6_lpddr2_freq_change_end");
+extern unsigned long mx6q_lpddr2_freq_change_start asm("mx6q_lpddr2_freq_change_start");
+extern unsigned long mx6q_lpddr2_freq_change_end asm("mx6q_lpddr2_freq_change_end");
+extern unsigned long iram_tlb_phys_addr;
+
+struct mmdc_settings_info {
+	u32 size;
+	void *settings;
+	int freq;
+} __aligned(8);
+static struct mmdc_settings_info *mmdc_settings_info;
+void (*mx6_change_lpddr2_freq_smp)(u32 ddr_freq, struct mmdc_settings_info
+		*mmdc_settings_info) = NULL;
+
+static int mmdc_settings_size;
+static unsigned long (*mmdc_settings)[2];
+static unsigned long (*iram_mmdc_settings)[2];
+static unsigned long *iram_settings_size;
+static unsigned long *iram_ddr_freq_chage;
+unsigned long mmdc_timing_settings[][2] = {
+	{0x0C, 0x0},	/* mmdc_mdcfg0 */
+	{0x10, 0x0},	/* mmdc_mdcfg1 */
+	{0x14, 0x0},	/* mmdc_mdcfg2 */
+	{0x18, 0x0},	/* mmdc_mdmisc */
+	{0x38, 0x0},	/* mmdc_mdcfg3lp */
+};
+
+#ifdef CONFIG_SMP
+volatile u32 *wait_for_lpddr2_freq_update;
+static unsigned int online_cpus;
+static u32 *irqs_used;
+void (*wfe_change_lpddr2_freq)(u32 cpuid, u32 *ddr_freq_change_done);
+extern void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done);
+extern unsigned long wfe_smp_freq_change_start asm("wfe_smp_freq_change_start");
+extern unsigned long wfe_smp_freq_change_end asm("wfe_smp_freq_change_end");
+extern void __iomem *imx_scu_base;
+static void __iomem *gic_dist_base;
+#endif
+
+#ifdef CONFIG_SMP
+static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id)
+{
+	u32 me;
+
+	me = smp_processor_id();
+#ifdef CONFIG_LOCAL_TIMERS
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &me);
+#endif
+	wfe_change_lpddr2_freq(0xff << (me * 8),
+			(u32 *)ddr_freq_change_iram_base);
+#ifdef CONFIG_LOCAL_TIMERS
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &me);
+#endif
+	return IRQ_HANDLED;
+}
+#endif
+
+/* change the DDR frequency. */
+int update_lpddr2_freq(int ddr_rate)
+{
+	unsigned long ttbr1, flags;
+	int mode = get_bus_freq_mode();
+
+	if (ddr_rate == curr_ddr_rate)
+		return 0;
+
+	printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate);
+
+	spin_lock_irqsave(&freq_lock, flags);
+	/*
+	 * Flush the TLB, to ensure no TLB maintenance occurs
+	 * when DDR is in self-refresh.
+	 */
+	ttbr1 = save_ttbr1();
+
+	/* Now change DDR frequency. */
+	if (cpu_is_imx6sl())
+		mx6_change_lpddr2_freq(ddr_rate,
+			(mode == BUS_FREQ_LOW || mode == BUS_FREQ_ULTRA_LOW) ? 1 : 0);
+	else
+		mx6_change_lpddr2_freq(ddr_rate,
+			(mode == BUS_FREQ_LOW || mode == BUS_FREQ_AUDIO) ? 1 : 0);
+
+	restore_ttbr1(ttbr1);
+
+	curr_ddr_rate = ddr_rate;
+	spin_unlock_irqrestore(&freq_lock, flags);
+
+	printk(KERN_DEBUG "\nBus freq set to %d done...\n", ddr_rate);
+
+	return 0;
+}
+
+int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev)
+{
+	unsigned long ddr_code_size;
+	busfreq_dev = &busfreq_pdev->dev;
+
+	ddr_code_size = SZ_4K;
+
+	if (cpu_is_imx6sl())
+		mx6_change_lpddr2_freq = (void *)fncpy(
+			(void *)ddr_freq_change_iram_base,
+			&mx6_lpddr2_freq_change, ddr_code_size);
+	if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull())
+		mx6_change_lpddr2_freq = (void *)fncpy(
+			(void *)ddr_freq_change_iram_base,
+			&imx6_up_lpddr2_freq_change, ddr_code_size);
+	if (cpu_is_imx6sll())
+		mx6_change_lpddr2_freq = (void *)fncpy(
+			(void *)ddr_freq_change_iram_base,
+			&imx6sll_lpddr2_freq_change, ddr_code_size);
+
+	curr_ddr_rate = ddr_normal_rate;
+
+	return 0;
+}
+
+int update_lpddr2_freq_smp(int ddr_rate)
+{
+	unsigned long ttbr1;
+	int i, me = 0;
+#ifdef CONFIG_SMP
+	int cpu = 0;
+	u32 reg = 0;
+#endif
+
+	if (ddr_rate == curr_ddr_rate)
+		return 0;
+
+	printk(KERN_DEBUG "Bus freq set to %d start...\n", ddr_rate);
+
+	for (i=0; i < mmdc_settings_size; i++) {
+		iram_mmdc_settings[i][0] = mmdc_settings[i][0];
+		iram_mmdc_settings[i][1] = mmdc_settings[i][1];
+	}
+
+	mmdc_settings_info->size = mmdc_settings_size;
+	mmdc_settings_info->settings = iram_mmdc_settings;
+	mmdc_settings_info->freq = curr_ddr_rate;
+
+	/* ensure that all Cores are in WFE. */
+	local_irq_disable();
+
+#ifdef CONFIG_SMP
+	me = smp_processor_id();
+
+	/* Make sure all the online cores are active */
+	while (1) {
+		bool not_exited_busfreq = false;
+		for_each_online_cpu(cpu) {
+			reg = __raw_readl(imx_scu_base + 0x08);
+			if (reg & (0x02 << (cpu * 8)))
+				not_exited_busfreq = true;
+		}
+		if (!not_exited_busfreq)
+			break;
+	}
+
+	wmb();
+	*wait_for_lpddr2_freq_update = 1;
+	dsb();
+	online_cpus = readl_relaxed(imx_scu_base + 0x08);
+	for_each_online_cpu(cpu) {
+		*((char *)(&online_cpus) + (u8)cpu) = 0x02;
+		if (cpu != me) {
+			reg = 1 << (irqs_used[cpu] % 32);
+			writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET
+					+ (irqs_used[cpu] / 32) * 4);
+		}
+	}
+
+	/* Wait for the other active CPUs to idle */
+	while (1) {
+		reg = 0;
+		reg = readl_relaxed(imx_scu_base + 0x08);
+		reg |= (0x02 << (me * 8));
+		if (reg == online_cpus)
+			break;
+	}
+#endif
+
+	/* Ensure iram_tlb_phys_addr is flushed to DDR. */
+	__cpuc_flush_dcache_area(&iram_tlb_phys_addr,
+			sizeof(iram_tlb_phys_addr));
+	outer_clean_range(__pa(&iram_tlb_phys_addr),
+			__pa(&iram_tlb_phys_addr + 1));
+	/*
+	 * Flush the TLB, to ensure no TLB maintenance occurs
+	 * when DDR is in self-refresh.
+	 */
+	ttbr1 = save_ttbr1();
+
+	curr_ddr_rate = ddr_rate;
+
+	/* Now change DDR frequency. */
+	mx6_change_lpddr2_freq_smp(ddr_rate, mmdc_settings_info);
+
+	restore_ttbr1(ttbr1);
+
+#ifdef CONFIG_SMP
+	wmb();
+	/* DDR frequency change is done . */
+	*wait_for_lpddr2_freq_update = 0;
+	dsb();
+	/* wake up all the cores. */
+	sev();
+#endif
+
+	local_irq_enable();
+
+	printk(KERN_DEBUG "Bus freq set to %d done! cpu=%d\n", ddr_rate, me);
+
+	return 0;
+}
+
+int init_mmdc_lpddr2_settings_mx6q(struct platform_device *busfreq_pdev)
+{
+	struct device *dev = &busfreq_pdev->dev;
+	unsigned long ddr_code_size = 0;
+	unsigned long wfe_code_size = 0;
+	struct device_node *node;
+	void __iomem *mmdc_base;
+	int i;
+#ifdef CONFIG_SMP
+	struct irq_data *d;
+	u32 cpu;
+	int err;
+#endif
+
+	node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc");
+	if (!node) {
+		printk(KERN_ERR "failed to find mmdc device tree data!\n");
+		return -EINVAL;
+	}
+
+	mmdc_base = of_iomap(node, 0);
+	if (!mmdc_base) {
+		dev_err(dev, "unable to map mmdc registers\n");
+		return -EINVAL;
+	}
+
+	mmdc_settings_size = ARRAY_SIZE(mmdc_timing_settings);
+	mmdc_settings = kmalloc((mmdc_settings_size * 8), GFP_KERNEL);
+	memcpy(mmdc_settings, mmdc_timing_settings,
+			sizeof(mmdc_timing_settings));
+
+#ifdef CONFIG_SMP
+	node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic");
+	if (!node) {
+		printk(KERN_ERR "failed to find imx6q-a9-gic device tree data!\n");
+		return -EINVAL;
+	}
+
+	gic_dist_base = of_iomap(node, 0);
+	WARN(!gic_dist_base, "unable to map gic dist registers\n");
+
+	irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(),
+			GFP_KERNEL);
+
+	for_each_online_cpu(cpu) {
+		int irq = platform_get_irq(busfreq_pdev, cpu);
+		err = request_irq(irq, wait_in_wfe_irq, IRQF_PERCPU,
+				"mmdc_1", NULL);
+		if (err) {
+			dev_err(dev,
+				"Busfreq:request_irq failed %d, err = %d\n",
+				irq, err);
+			return err;
+		}
+		err = irq_set_affinity(irq, cpumask_of(cpu));
+		if (err) {
+			dev_err(dev,
+				"Busfreq: Cannot set irq affinity irq=%d,\n",
+				irq);
+			return err;
+		}
+		d = irq_get_irq_data(irq);
+		irqs_used[cpu] = d->hwirq + 32;
+	}
+
+	/* Stoange_iram_basee the variable used to communicate between cores in
+	 * a non-cacheable IRAM area */
+	wait_for_lpddr2_freq_update = (u32 *)ddr_freq_change_iram_base;
+	wfe_code_size = (&wfe_smp_freq_change_end - &wfe_smp_freq_change_start) *4;
+
+	wfe_change_lpddr2_freq = (void *)fncpy((void *)ddr_freq_change_iram_base + 0x8,
+			&wfe_smp_freq_change, wfe_code_size);
+#endif
+	iram_settings_size = (void *)ddr_freq_change_iram_base + wfe_code_size + 0x8;
+	iram_mmdc_settings = (void *)iram_settings_size + sizeof(*mmdc_settings_info);
+	iram_ddr_freq_chage = (void *)iram_mmdc_settings + (mmdc_settings_size * 8) + 0x8;
+	mmdc_settings_info = (struct mmdc_settings_info *)iram_settings_size;
+
+	ddr_code_size = (&mx6q_lpddr2_freq_change_end -&mx6q_lpddr2_freq_change_start) *4;
+
+	mx6_change_lpddr2_freq_smp = (void *)fncpy(iram_ddr_freq_chage,
+			&mx6q_lpddr2_freq_change, ddr_code_size);
+
+	/* save initial mmdc boot timing settings */
+	for (i=0; i < mmdc_settings_size; i++)
+		mmdc_settings[i][1] = readl_relaxed(mmdc_base +
+				mmdc_settings[i][0]);
+
+	curr_ddr_rate = ddr_normal_rate;
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/common.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/common.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_net.h>
+#include <linux/slab.h>
+
+#include "hardware.h"
+
+unsigned long iram_tlb_base_addr;
+unsigned long iram_tlb_phys_addr;
+
+unsigned long save_ttbr1(void)
+{
+	unsigned long lttbr1;
+	asm volatile(
+		".align 4\n"
+		"mrc p15, 0, %0, c2, c0, 1\n"
+		: "=r" (lttbr1)
+	);
+	return lttbr1;
+}
+
+void restore_ttbr1(unsigned long ttbr1)
+{
+	asm volatile(
+		".align 4\n"
+		"mcr p15, 0, %0, c2, c0, 1\n"
+		: : "r" (ttbr1)
+	);
+}
+
+#define OCOTP_MAC_OFF	(cpu_is_imx7d() ? 0x640 : 0x620)
+#define OCOTP_MACn(n)	(OCOTP_MAC_OFF + (n) * 0x10)
+void __init imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat)
+{
+	struct device_node *ocotp_np, *enet_np, *from = NULL;
+	void __iomem *base;
+	struct property *newmac;
+	u32 macaddr_low;
+	u32 macaddr_high = 0;
+	u32 macaddr1_high = 0;
+	u8 *macaddr;
+	int i, id;
+
+	for (i = 0; i < 2; i++) {
+		enet_np = of_find_compatible_node(from, NULL, enet_compat);
+		if (!enet_np)
+			return;
+
+		from = enet_np;
+
+		if (of_get_mac_address(enet_np))
+			goto put_enet_node;
+
+		id = of_alias_get_id(enet_np, "ethernet");
+		if (id < 0)
+			id = i;
+
+		ocotp_np = of_find_compatible_node(NULL, NULL, ocotp_compat);
+		if (!ocotp_np) {
+			pr_warn("failed to find ocotp node\n");
+			goto put_enet_node;
+		}
+
+		base = of_iomap(ocotp_np, 0);
+		if (!base) {
+			pr_warn("failed to map ocotp\n");
+			goto put_ocotp_node;
+		}
+
+		macaddr_low = readl_relaxed(base + OCOTP_MACn(1));
+		if (id)
+			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
+		else
+			macaddr_high = readl_relaxed(base + OCOTP_MACn(0));
+
+		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
+		if (!newmac)
+			goto put_ocotp_node;
+
+		newmac->value = newmac + 1;
+		newmac->length = 6;
+		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
+		if (!newmac->name) {
+			kfree(newmac);
+			goto put_ocotp_node;
+		}
+
+		macaddr = newmac->value;
+		if (id) {
+			macaddr[5] = (macaddr_low >> 16) & 0xff;
+			macaddr[4] = (macaddr_low >> 24) & 0xff;
+			macaddr[3] = macaddr1_high & 0xff;
+			macaddr[2] = (macaddr1_high >> 8) & 0xff;
+			macaddr[1] = (macaddr1_high >> 16) & 0xff;
+			macaddr[0] = (macaddr1_high >> 24) & 0xff;
+		} else {
+			macaddr[5] = macaddr_high & 0xff;
+			macaddr[4] = (macaddr_high >> 8) & 0xff;
+			macaddr[3] = (macaddr_high >> 16) & 0xff;
+			macaddr[2] = (macaddr_high >> 24) & 0xff;
+			macaddr[1] = macaddr_low & 0xff;
+			macaddr[0] = (macaddr_low >> 8) & 0xff;
+		}
+
+		of_update_property(enet_np, newmac);
+
+put_ocotp_node:
+	of_node_put(ocotp_np);
+put_enet_node:
+	of_node_put(enet_np);
+	}
+}
+
+#ifndef CONFIG_HAVE_IMX_GPC
+int imx_gpc_mf_request_on(unsigned int irq, unsigned int on) { return 0; }
+EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on);
+#endif
+
+#if !defined(CONFIG_SOC_IMX6SL)
+u32 imx6_lpddr2_freq_change_start, imx6_lpddr2_freq_change_end;
+void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode) {}
+#endif
+
+#if !defined(CONFIG_SOC_IMX6SLL)
+void imx6sll_lpddr2_freq_change(u32 freq, int bus_freq_mode) {}
+#endif
+
+#if !defined(CONFIG_SOC_IMX6SX) && !defined(CONFIG_SOC_IMX6UL)
+u32 imx6_up_ddr3_freq_change_start, imx6_up_ddr3_freq_change_end;
+struct imx6_busfreq_info {
+} __aligned(8);
+void imx6_up_ddr3_freq_change(struct imx6_busfreq_info *busfreq_info) {}
+void imx6_up_lpddr2_freq_change(u32 freq, int bus_freq_mode) {}
+#endif
+
+#if !defined(CONFIG_SOC_IMX6ULL)
+u32 mx6ull_lpm_wfi_start, mx6ull_lpm_wfi_end;
+void imx6ull_low_power_idle(void) {}
+#endif
+
+#if !defined(CONFIG_SOC_IMX6Q)
+u32 mx6_ddr3_freq_change_start, mx6_ddr3_freq_change_end;
+u32 mx6q_lpddr2_freq_change_start, mx6q_lpddr2_freq_change_end;
+u32 wfe_smp_freq_change_start, wfe_smp_freq_change_end;
+void mx6_ddr3_freq_change(u32 freq, void *ddr_settings,
+	bool dll_mode, void *iomux_offsets) {}
+void mx6q_lpddr2_freq_change(u32 freq, void *ddr_settings) {}
+void wfe_smp_freq_change(u32 cpuid, u32 *ddr_freq_change_done) {}
+#endif
+
+#if !defined(CONFIG_SOC_IMX7D)
+void imx7_smp_wfe(u32 cpuid, u32 ocram_base) {}
+void imx7d_ddr3_freq_change(u32 freq) {}
+#endif
+
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/common.h
+++ linux-ein-5.4.0/arch/arm/mach-imx/common.h
@@ -8,6 +8,7 @@
 #define __ASM_ARCH_MXC_COMMON_H__
 
 #include <linux/reboot.h>
+#include <soc/imx/src.h>
 
 struct irq_data;
 struct platform_device;
@@ -49,16 +50,25 @@
 int mxc_device_init(void);
 void imx_set_soc_revision(unsigned int rev);
 void imx_init_revision_from_anatop(void);
-struct device *imx_soc_device_init(void);
 void imx6_enable_rbc(bool enable);
 void imx_gpc_check_dt(void);
 void imx_gpc_set_arm_power_in_lpm(bool power_off);
 void imx_gpc_set_l2_mem_power_in_lpm(bool power_off);
 void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw);
 void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw);
+void imx_gpcv2_pre_suspend(bool arm_power_off);
+void imx_gpcv2_post_resume(void);
+unsigned int imx_gpcv2_is_mf_mix_off(void);
+void imx_gpcv2_enable_wakeup_for_m4(void);
+void imx_gpcv2_disable_wakeup_for_m4(void);
 void imx25_pm_init(void);
 void imx27_pm_init(void);
 void imx5_pmu_init(void);
+#ifdef CONFIG_HAVE_IMX_MU
+int imx_mu_lpm_ready(bool ready);
+#else
+static inline int imx_mu_lpm_ready(bool ready) { return 0; }
+#endif
 
 enum mxc_cpu_pwr_mode {
 	WAIT_CLOCKED,		/* wfi only */
@@ -89,6 +99,32 @@
 static inline void imx_scu_map_io(void) {}
 static inline void imx_smp_prepare(void) {}
 #endif
+void imx_mu_enable_m4_irqs_in_gic(bool enable);
+#ifdef CONFIG_HAVE_IMX_GPC
+void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable);
+unsigned int imx_gpc_is_m4_sleeping(void);
+#else
+static inline void imx_gpc_add_m4_wake_up_irq(u32 irq, bool enable) {}
+static inline unsigned int imx_gpc_is_m4_sleeping(void) { return 0; }
+#endif
+#ifdef CONFIG_HAVE_IMX_GPCV2
+int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on);
+void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn);
+void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable);
+#else
+static inline int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on) { return 0; }
+static inline void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) {}
+static inline void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable) {}
+#endif
+void imx_gpc_hold_m4_in_sleep(void);
+void imx_gpc_release_m4_in_sleep(void);
+void __init imx_gpcv2_check_dt(void);
+void imx_gpcv2_set_lpm_mode(enum mxc_cpu_pwr_mode mode);
+void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn);
+void imx_gpcv2_enable_rbc(bool enable);
+bool imx_mu_is_m4_in_low_freq(void);
+bool imx_mu_is_m4_in_stop(void);
+void imx_mu_set_m4_run_mode(void);
 void imx_src_init(void);
 void imx_gpc_pre_suspend(bool arm_power_off);
 void imx_gpc_post_resume(void);
@@ -96,28 +132,47 @@
 void imx_gpc_restore_all(void);
 void imx_gpc_hwirq_mask(unsigned int hwirq);
 void imx_gpc_hwirq_unmask(unsigned int hwirq);
+unsigned int imx_gpc_is_mf_mix_off(void);
 void imx_anatop_init(void);
 void imx_anatop_pre_suspend(void);
 void imx_anatop_post_resume(void);
 int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
 void imx6_set_int_mem_clk_lpm(bool enable);
-void imx6sl_set_wait_clk(bool enter);
+void imx7d_low_power_idle(void);
+#ifdef CONFIG_HAVE_IMX_MMDC
 int imx_mmdc_get_ddr_type(void);
+int imx_mmdc_get_lpddr2_2ch_mode(void);
+#else
+static inline int imx_mmdc_get_ddr_type(void) { return 0; }
+static inline int imx_mmdc_get_lpddr2_2ch_mode(void) { return 0; }
+#endif
 int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode);
+void imx_busfreq_map_io(void);
+void imx7_pm_map_io(void);
 
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
 
 #ifdef CONFIG_SUSPEND
 void v7_cpu_resume(void);
+void ca7_cpu_resume(void);
 void imx53_suspend(void __iomem *ocram_vbase);
 extern const u32 imx53_suspend_sz;
 void imx6_suspend(void __iomem *ocram_vbase);
+void imx7_suspend(void __iomem *ocram_vbase);
 #else
 static inline void v7_cpu_resume(void) {}
+static inline void ca7_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) {}
+static inline void imx7_suspend(void __iomem *ocram_vbase) {}
+#endif
+
+#ifdef CONFIG_HAVE_IMX_DDRC
+int imx_ddrc_get_ddr_type(void);
+#else
+static inline int imx_ddrc_get_ddr_type(void) { return 0; }
 #endif
 
 void imx6_pm_ccm_init(const char *ccm_compat);
@@ -126,6 +181,7 @@
 void imx6sl_pm_init(void);
 void imx6sx_pm_init(void);
 void imx6ul_pm_init(void);
+void imx7d_pm_init(void);
 void imx7ulp_pm_init(void);
 
 #ifdef CONFIG_PM
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu-imx25.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu-imx25.c
@@ -23,6 +23,7 @@
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx25-iim");
 	iim_base = of_iomap(np, 0);
+	of_node_put(np);
 	BUG_ON(!iim_base);
 	rev = readl(iim_base + MXC_IIMSREV);
 	iounmap(iim_base);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu-imx27.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu-imx27.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/of_address.h>
 #include <linux/module.h>
 
 #include "hardware.h"
@@ -17,16 +18,24 @@
 static int mx27_cpu_partnumber;
 
 #define SYS_CHIP_ID             0x00    /* The offset of CHIP ID register */
+#define SYSCTRL_OFFSET		0x800	/* Offset from CCM base address */
 
 static int mx27_read_cpu_rev(void)
 {
+	void __iomem *ccm_base;
+	struct device_node *np;
 	u32 val;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx27-ccm");
+	ccm_base = of_iomap(np, 0);
+	of_node_put(np);
+	BUG_ON(!ccm_base);
 	/*
 	 * now we have access to the IO registers. As we need
 	 * the silicon revision very early we read it here to
 	 * avoid any further hooks
 	*/
-	val = imx_readl(MX27_IO_ADDRESS(MX27_SYSCTRL_BASE_ADDR + SYS_CHIP_ID));
+	val = imx_readl(ccm_base + SYSCTRL_OFFSET + SYS_CHIP_ID);
 
 	mx27_cpu_partnumber = (int)((val >> 12) & 0xFFFF);
 
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu-imx31.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu-imx31.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/io.h>
 
 #include "common.h"
@@ -32,10 +33,17 @@
 
 static int mx31_read_cpu_rev(void)
 {
+	void __iomem *iim_base;
+	struct device_node *np;
 	u32 i, srev;
 
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx31-iim");
+	iim_base = of_iomap(np, 0);
+	of_node_put(np);
+	BUG_ON(!iim_base);
+
 	/* read SREV register from IIM module */
-	srev = imx_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV));
+	srev = imx_readl(iim_base + MXC_IIMSREV);
 	srev &= 0xff;
 
 	for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu-imx35.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu-imx35.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
  */
 #include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/io.h>
 
 #include "hardware.h"
@@ -14,9 +15,16 @@
 
 static int mx35_read_cpu_rev(void)
 {
+	void __iomem *iim_base;
+	struct device_node *np;
 	u32 rev;
 
-	rev = imx_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV));
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx35-iim");
+	iim_base = of_iomap(np, 0);
+	of_node_put(np);
+	BUG_ON(!iim_base);
+
+	rev = imx_readl(iim_base + MXC_IIMSREV);
 	switch (rev) {
 	case 0x00:
 		return IMX_CHIP_REVISION_1_0;
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu-imx5.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu-imx5.c
@@ -28,6 +28,7 @@
 
 	np = of_find_compatible_node(NULL, NULL, compat);
 	iim_base = of_iomap(np, 0);
+	of_node_put(np);
 	WARN_ON(!iim_base);
 
 	srev = readl(iim_base + IIM_SREV) & 0xff;
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpu.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpu.c
@@ -4,8 +4,6 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/slab.h>
-#include <linux/sys_soc.h>
 
 #include "hardware.h"
 #include "common.h"
@@ -72,102 +70,3 @@
 		imx_set_aips(aips_base_addr);
 	}
 }
-
-struct device * __init imx_soc_device_init(void)
-{
-	struct soc_device_attribute *soc_dev_attr;
-	struct soc_device *soc_dev;
-	struct device_node *root;
-	const char *soc_id;
-	int ret;
-
-	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
-	if (!soc_dev_attr)
-		return NULL;
-
-	soc_dev_attr->family = "Freescale i.MX";
-
-	root = of_find_node_by_path("/");
-	ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
-	of_node_put(root);
-	if (ret)
-		goto free_soc;
-
-	switch (__mxc_cpu_type) {
-	case MXC_CPU_MX1:
-		soc_id = "i.MX1";
-		break;
-	case MXC_CPU_MX21:
-		soc_id = "i.MX21";
-		break;
-	case MXC_CPU_MX25:
-		soc_id = "i.MX25";
-		break;
-	case MXC_CPU_MX27:
-		soc_id = "i.MX27";
-		break;
-	case MXC_CPU_MX31:
-		soc_id = "i.MX31";
-		break;
-	case MXC_CPU_MX35:
-		soc_id = "i.MX35";
-		break;
-	case MXC_CPU_MX51:
-		soc_id = "i.MX51";
-		break;
-	case MXC_CPU_MX53:
-		soc_id = "i.MX53";
-		break;
-	case MXC_CPU_IMX6SL:
-		soc_id = "i.MX6SL";
-		break;
-	case MXC_CPU_IMX6DL:
-		soc_id = "i.MX6DL";
-		break;
-	case MXC_CPU_IMX6SX:
-		soc_id = "i.MX6SX";
-		break;
-	case MXC_CPU_IMX6Q:
-		soc_id = "i.MX6Q";
-		break;
-	case MXC_CPU_IMX6UL:
-		soc_id = "i.MX6UL";
-		break;
-	case MXC_CPU_IMX6ULL:
-		soc_id = "i.MX6ULL";
-		break;
-	case MXC_CPU_IMX6ULZ:
-		soc_id = "i.MX6ULZ";
-		break;
-	case MXC_CPU_IMX6SLL:
-		soc_id = "i.MX6SLL";
-		break;
-	case MXC_CPU_IMX7D:
-		soc_id = "i.MX7D";
-		break;
-	case MXC_CPU_IMX7ULP:
-		soc_id = "i.MX7ULP";
-		break;
-	default:
-		soc_id = "Unknown";
-	}
-	soc_dev_attr->soc_id = soc_id;
-
-	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
-					   (imx_soc_revision >> 4) & 0xf,
-					   imx_soc_revision & 0xf);
-	if (!soc_dev_attr->revision)
-		goto free_soc;
-
-	soc_dev = soc_device_register(soc_dev_attr);
-	if (IS_ERR(soc_dev))
-		goto free_rev;
-
-	return soc_device_to_device(soc_dev);
-
-free_rev:
-	kfree(soc_dev_attr->revision);
-free_soc:
-	kfree(soc_dev_attr);
-	return NULL;
-}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpuidle-imx6q.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -62,13 +62,13 @@
  */
 void imx6q_cpuidle_fec_irqs_used(void)
 {
-	imx6q_cpuidle_driver.states[1].disabled = true;
+	cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, true);
 }
 EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_used);
 
 void imx6q_cpuidle_fec_irqs_unused(void)
 {
-	imx6q_cpuidle_driver.states[1].disabled = false;
+	cpuidle_driver_state_disabled(&imx6q_cpuidle_driver, 1, false);
 }
 EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_unused);
 
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  */
 
+#include <linux/clk/imx.h>
 #include <linux/cpuidle.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpuidle-imx6sx.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -41,7 +41,6 @@
 		break;
 	case 2:
 		imx6_enable_rbc(true);
-		imx_gpc_set_arm_power_in_lpm(true);
 		imx_set_cpu_jump(0, v7_cpu_resume);
 		/* Need to notify there is a cpu pm operation. */
 		cpu_pm_enter();
@@ -51,7 +50,6 @@
 
 		cpu_cluster_pm_exit();
 		cpu_pm_exit();
-		imx_gpc_set_arm_power_in_lpm(false);
 		imx6_enable_rbc(false);
 		break;
 	default:
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpuidle-imx7d.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpuidle-imx7d.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2015 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+#include <linux/delay.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/psci.h>
+#include <asm/cp15.h>
+#include <asm/cpuidle.h>
+#include <asm/fncpy.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/tlb.h>
+
+#include <uapi/linux/psci.h>
+
+#include "common.h"
+#include "cpuidle.h"
+#include "hardware.h"
+
+#define XTALOSC24M_OSC_CONFIG0	0x10
+#define XTALOSC24M_OSC_CONFIG1	0x20
+#define XTALOSC24M_OSC_CONFIG2	0x30
+#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT	24
+#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK		0xf
+#define XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT		16
+#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK		0xf
+#define XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT		12
+#define XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT	4
+#define XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT		1
+#define XTALOSC24M_OSC_CONFIG0_START_SHIFT		0
+#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT	20
+#define XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT	0
+#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK	0xfff
+#define XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT	0
+
+#define XTALOSC_CTRL_24M				0x0
+#define XTALOSC_CTRL_24M_RC_OSC_EN_SHIFT		13
+#define REG_SET						0x4
+
+static void __iomem *wfi_iram_base;
+static void __iomem *wfi_iram_base_phys;
+extern unsigned long iram_tlb_phys_addr;
+
+struct imx7_pm_base {
+	phys_addr_t pbase;
+	void __iomem *vbase;
+};
+
+struct imx7_cpuidle_pm_info {
+	phys_addr_t vbase; /* The virtual address of pm_info. */
+	phys_addr_t pbase; /* The physical address of pm_info. */
+	phys_addr_t resume_addr; /* The physical resume address for asm code */
+	u32 pm_info_size;
+	u32 ttbr;
+	u32 num_online_cpus;
+	u32 num_lpi_cpus;
+	atomic_t val;
+	atomic_t flag0;
+	atomic_t flag1;
+	struct imx7_pm_base ddrc_base;
+	struct imx7_pm_base ccm_base;
+	struct imx7_pm_base anatop_base;
+	struct imx7_pm_base src_base;
+	struct imx7_pm_base iomuxc_gpr_base;
+	struct imx7_pm_base gpc_base;
+	struct imx7_pm_base gic_dist_base;
+} __aligned(8);
+
+static atomic_t master_lpi = ATOMIC_INIT(0);
+static atomic_t master_wait = ATOMIC_INIT(0);
+
+static void (*imx7d_wfi_in_iram_fn)(void __iomem *iram_vbase);
+static struct imx7_cpuidle_pm_info *cpuidle_pm_info;
+
+#define MX7D_POWERDWN_IDLE_PARAM	\
+	((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+	 (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+	 (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
+
+#define MX7D_STANDBY_IDLE_PARAM	\
+	((1 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+	 (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+	 (PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
+
+/* Mapped for the kernel, unlike cpuidle_pm_info->gic_dist_base.vbase */
+static void __iomem *imx7d_cpuidle_gic_base;
+
+static void imx_pen_lock(int cpu)
+{
+	if (cpu == 0) {
+		atomic_set(&cpuidle_pm_info->flag0, 1);
+		dsb();
+		atomic_set(&cpuidle_pm_info->val, cpu);
+		do {
+			dsb();
+		} while (atomic_read(&cpuidle_pm_info->flag1) == 1
+			&& atomic_read(&cpuidle_pm_info->val) == cpu)
+			;
+	} else {
+		atomic_set(&cpuidle_pm_info->flag1, 1);
+		dsb();
+		atomic_set(&cpuidle_pm_info->val, cpu);
+		do {
+			dsb();
+		} while (atomic_read(&cpuidle_pm_info->flag0) == 1
+			&& atomic_read(&cpuidle_pm_info->val) == cpu)
+			;
+	}
+}
+
+static void imx_pen_unlock(int cpu)
+{
+	dsb();
+	if (cpu == 0)
+		atomic_set(&cpuidle_pm_info->flag0, 0);
+	else
+		atomic_set(&cpuidle_pm_info->flag1, 0);
+}
+
+static int imx7d_idle_finish(unsigned long val)
+{
+	if (psci_ops.cpu_suspend)
+		psci_ops.cpu_suspend(MX7D_POWERDWN_IDLE_PARAM, __pa(cpu_resume));
+	else
+		imx7d_wfi_in_iram_fn(wfi_iram_base);
+
+	return 0;
+}
+
+static bool imx7d_gic_sgis_pending(void)
+{
+	void __iomem *sgip_base = imx7d_cpuidle_gic_base + 0x1f20;
+
+	return (readl_relaxed(sgip_base + 0x0) |
+		readl_relaxed(sgip_base + 0x4) |
+		readl_relaxed(sgip_base + 0x8) |
+		readl_relaxed(sgip_base + 0xc));
+}
+
+static DEFINE_SPINLOCK(psci_lock);
+static int imx7d_enter_low_power_idle(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	int mode = get_bus_freq_mode();
+
+
+	if ((index == 1) || ((mode != BUS_FREQ_LOW) && index == 2)) {
+		index = 1;
+		if (atomic_inc_return(&master_wait) == num_online_cpus())
+			imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED);
+
+		cpu_do_idle();
+
+		atomic_dec(&master_wait);
+		imx_gpcv2_set_lpm_mode(WAIT_CLOCKED);
+	} else {
+		if (psci_ops.cpu_suspend) {
+			cpu_pm_enter();
+			spin_lock(&psci_lock);
+			if (atomic_inc_return(&master_lpi) == num_online_cpus()) {
+				if (imx7d_gic_sgis_pending()) {
+					atomic_dec(&master_lpi);
+					index = -1;
+					goto psci_skip_lpi_flow;
+				}
+
+				imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED);
+				imx_gpcv2_set_cpu_power_gate_in_idle(true);
+
+				cpu_cluster_pm_enter();
+			}
+			spin_unlock(&psci_lock);
+
+			cpu_suspend(0, imx7d_idle_finish);
+
+			spin_lock(&psci_lock);
+			if (atomic_read(&master_lpi) == num_online_cpus()) {
+				cpu_cluster_pm_exit();
+				imx_gpcv2_set_cpu_power_gate_in_idle(false);
+				imx_gpcv2_set_lpm_mode(WAIT_CLOCKED);
+			}
+
+			atomic_dec(&master_lpi);
+psci_skip_lpi_flow:
+			spin_unlock(&psci_lock);
+			cpu_pm_exit();
+		} else {
+			imx_pen_lock(dev->cpu);
+			cpuidle_pm_info->num_online_cpus = num_online_cpus();
+			++cpuidle_pm_info->num_lpi_cpus;
+			cpu_pm_enter();
+			if (cpuidle_pm_info->num_lpi_cpus ==
+					cpuidle_pm_info->num_online_cpus) {
+				/*
+				 * GPC will not wake on SGIs so check for them
+				 * manually here. At this point we know the other cpu
+				 * is in wfi or waiting for the lock and can't send
+				 * any additional IPIs.
+				 */
+				if (imx7d_gic_sgis_pending()) {
+					index = -1;
+					goto skip_lpi_flow;
+				}
+				imx_gpcv2_set_lpm_mode(WAIT_UNCLOCKED);
+				imx_gpcv2_set_cpu_power_gate_in_idle(true);
+				cpu_cluster_pm_enter();
+			} else {
+				imx_set_cpu_jump(dev->cpu, ca7_cpu_resume);
+			}
+
+			cpu_suspend(0, imx7d_idle_finish);
+
+			if (cpuidle_pm_info->num_lpi_cpus ==
+					cpuidle_pm_info->num_online_cpus) {
+				cpu_cluster_pm_exit();
+				imx_gpcv2_set_cpu_power_gate_in_idle(false);
+				imx_gpcv2_set_lpm_mode(WAIT_CLOCKED);
+			}
+
+skip_lpi_flow:
+			cpu_pm_exit();
+			--cpuidle_pm_info->num_lpi_cpus;
+			imx_pen_unlock(dev->cpu);
+		}
+	}
+
+	return index;
+}
+
+static struct cpuidle_driver imx7d_cpuidle_driver = {
+	.name = "imx7d_cpuidle",
+	.owner = THIS_MODULE,
+	.states = {
+		/* WFI */
+		ARM_CPUIDLE_WFI_STATE,
+		/* WAIT MODE */
+		{
+			.exit_latency = 50,
+			.target_residency = 75,
+			.flags = CPUIDLE_FLAG_TIMER_STOP,
+			.enter = imx7d_enter_low_power_idle,
+			.name = "WAIT",
+			.desc = "Clock off",
+		},
+		/* LOW POWER IDLE */
+		{
+			.exit_latency = 10000,
+			.target_residency = 20000,
+			.flags = CPUIDLE_FLAG_TIMER_STOP,
+			.enter = imx7d_enter_low_power_idle,
+			.name = "LOW-POWER-IDLE",
+			.desc = "ARM power off",
+		},
+	},
+	.state_count = 3,
+	.safe_state_index = 0,
+};
+
+int imx7d_enable_rcosc(void)
+{
+	void __iomem *anatop_base =
+		(void __iomem *)IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR);
+	u32 val;
+
+	imx_gpcv2_set_lpm_mode(WAIT_CLOCKED);
+	/* set RC-OSC freq and turn it on */
+	writel_relaxed(0x1 << XTALOSC_CTRL_24M_RC_OSC_EN_SHIFT,
+		anatop_base + XTALOSC_CTRL_24M + REG_SET);
+	/*
+	 * config RC-OSC freq
+	 * tune_enable = 1;tune_start = 1;hyst_plus = 0;hyst_minus = 0;
+	 * osc_prog = 0xa7;
+	 */
+	writel_relaxed(
+		0x4 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR_SHIFT |
+		0xa7 << XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_SHIFT |
+		0x1 << XTALOSC24M_OSC_CONFIG0_ENABLE_SHIFT |
+		0x1 << XTALOSC24M_OSC_CONFIG0_START_SHIFT,
+		anatop_base + XTALOSC24M_OSC_CONFIG0);
+	/* set count_trg = 0x2dc */
+	writel_relaxed(
+		0x40 << XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR_SHIFT |
+		0x2dc << XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG_SHIFT,
+		anatop_base + XTALOSC24M_OSC_CONFIG1);
+	/* wait at least 4ms according to hardware design */
+	mdelay(6);
+	/*
+	 * now add some hysteresis, hyst_plus=3, hyst_minus=3
+	 * (the minimum hysteresis that looks good is 2)
+	 */
+	val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG0);
+	val &= ~((XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK <<
+		XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) |
+		(XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK <<
+		XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT));
+	val |= (0x3 << XTALOSC24M_OSC_CONFIG0_HYST_MINUS_SHIFT) |
+		(0x3 << XTALOSC24M_OSC_CONFIG0_HYST_PLUS_SHIFT);
+	writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG0);
+	/* set the count_1m_trg = 0x2d7 */
+	val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG2);
+	val &= ~(XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK <<
+		XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT);
+	val |= 0x2d7 << XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_SHIFT;
+	writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG2);
+	/*
+	 * hardware design require to write XTALOSC24M_OSC_CONFIG0 or
+	 * XTALOSC24M_OSC_CONFIG1 to
+	 * make XTALOSC24M_OSC_CONFIG2 write work
+	 */
+	val = readl_relaxed(anatop_base + XTALOSC24M_OSC_CONFIG1);
+	writel_relaxed(val, anatop_base + XTALOSC24M_OSC_CONFIG1);
+
+	return 0;
+}
+
+int __init imx7d_cpuidle_init(void)
+{
+	wfi_iram_base_phys = (void *)(iram_tlb_phys_addr +
+		MX7_CPUIDLE_OCRAM_ADDR_OFFSET);
+
+	/* Make sure wfi_iram_base is 8 byte aligned. */
+	if ((uintptr_t)(wfi_iram_base_phys) & (FNCPY_ALIGN - 1))
+		wfi_iram_base_phys += FNCPY_ALIGN -
+		((uintptr_t)wfi_iram_base_phys % (FNCPY_ALIGN));
+
+	wfi_iram_base = (void *)IMX_IO_P2V((unsigned long) wfi_iram_base_phys);
+
+	cpuidle_pm_info = wfi_iram_base;
+	cpuidle_pm_info->vbase = (phys_addr_t) wfi_iram_base;
+	cpuidle_pm_info->pbase = (phys_addr_t) wfi_iram_base_phys;
+	cpuidle_pm_info->pm_info_size = sizeof(*cpuidle_pm_info);
+	cpuidle_pm_info->resume_addr = virt_to_phys(ca7_cpu_resume);
+	cpuidle_pm_info->num_online_cpus = num_online_cpus();
+
+	cpuidle_pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR;
+	cpuidle_pm_info->ddrc_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_DDRC_BASE_ADDR);
+
+	cpuidle_pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR;
+	cpuidle_pm_info->ccm_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_CCM_BASE_ADDR);
+
+	cpuidle_pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR;
+	cpuidle_pm_info->anatop_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR);
+
+	cpuidle_pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR;
+	cpuidle_pm_info->src_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_SRC_BASE_ADDR);
+
+	cpuidle_pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR;
+	cpuidle_pm_info->iomuxc_gpr_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR);
+
+	cpuidle_pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR;
+	cpuidle_pm_info->gpc_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_GPC_BASE_ADDR);
+
+	cpuidle_pm_info->gic_dist_base.pbase = MX7D_GIC_BASE_ADDR;
+	cpuidle_pm_info->gic_dist_base.vbase =
+		(void __iomem *)IMX_IO_P2V(MX7D_GIC_BASE_ADDR);
+
+	imx7d_cpuidle_gic_base = ioremap(MX7D_GIC_BASE_ADDR, MX7D_GIC_SIZE);
+
+	imx7d_enable_rcosc();
+
+	/* code size should include cpuidle_pm_info size */
+	if (!psci_ops.cpu_suspend) {
+		imx7d_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base +
+			sizeof(*cpuidle_pm_info),
+			&imx7d_low_power_idle,
+			MX7_CPUIDLE_OCRAM_SIZE - sizeof(*cpuidle_pm_info));
+	}
+
+	return cpuidle_register(&imx7d_cpuidle_driver, NULL);
+}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/cpuidle.h
+++ linux-ein-5.4.0/arch/arm/mach-imx/cpuidle.h
@@ -9,6 +9,8 @@
 extern int imx6q_cpuidle_init(void);
 extern int imx6sl_cpuidle_init(void);
 extern int imx6sx_cpuidle_init(void);
+extern int imx7d_cpuidle_init(void);
+extern int imx7d_enable_rcosc(void);
 extern int imx7ulp_cpuidle_init(void);
 #else
 static inline int imx5_cpuidle_init(void)
@@ -27,6 +29,14 @@
 {
 	return 0;
 }
+static inline int imx7d_cpuidle_init(void)
+{
+	return 0;
+}
+static inline int imx7d_enable_rcosc(void)
+{
+	return 0;
+}
 static inline int imx7ulp_cpuidle_init(void)
 {
 	return 0;
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/ddr3_freq_imx7d.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/ddr3_freq_imx7d.S
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include "hardware.h"
+
+#define DDRC_MSTR		0x0
+#define DDRC_STAT		0x4
+#define DDRC_MRCTRL0		0x10
+#define DDRC_MRCTRL1		0x14
+#define DDRC_MRSTAT		0x18
+#define DDRC_PWRCTL		0x30
+#define DDRC_RFSHCTL3		0x60
+#define DDRC_RFSHTMG		0x64
+#define DDRC_DBG1		0x304
+#define DDRC_SWCTL		0x320
+#define DDRC_SWSTAT		0x324
+#define DDRC_PSTAT		0x3fc
+#define DDRC_PCTRL_0		0x490
+#define DDRC_ZQCTL0		0x180
+#define DDRC_DFIMISC		0x1b0
+#define DDRC_DBGCAM		0x308
+#define DDRPHY_LP_CON0		0x18
+#define IOMUXC_GPR8		0x20
+#define DDRPHY_MDLL_CON0	0xb0
+#define DDRPHY_MDLL_CON1	0xb4
+#define DDRPHY_OFFSETD_CON0	0x50
+#define DDRPHY_OFFSETR_CON0	0x20
+#define DDRPHY_OFFSETR_CON1	0x24
+#define DDRPHY_OFFSETR_CON2	0x28
+#define DDRPHY_OFFSETW_CON0	0x30
+#define DDRPHY_OFFSETW_CON1	0x34
+#define DDRPHY_OFFSETW_CON2	0x38
+#define DDRPHY_CA_WLDSKEW_CON0	0x6c
+#define DDRPHY_CA_DSKEW_CON0	0x7c
+#define DDRPHY_CA_DSKEW_CON1	0x80
+#define DDRPHY_CA_DSKEW_CON2	0x84
+
+#define ANADIG_DIGPROG		0x800
+
+	.align 3
+
+	.macro	switch_to_below_100m
+
+	ldr	r7, =0x2
+	str	r7, [r4, #DDRC_DBG1]
+
+	ldr	r6, =0x36000000
+1:
+	ldr	r7, [r4, #DDRC_DBGCAM]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	1b
+
+	ldr	r6, =0x1
+2:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	2b
+
+	ldr	r7, =0x10f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800010f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+3:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	3b
+
+	ldr	r7, =0x20f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x8
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800020f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+4:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	4b
+
+	ldr	r7, =0x10f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800010f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r7, =0x20
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x23
+5:
+	ldr	r7, [r4, #DDRC_STAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	5b
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_SWCTL]
+
+	ldr	r7, =0x03048001
+	str	r7, [r4, #DDRC_MSTR]
+
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_SWCTL]
+
+	ldr	r6, =0x1
+6:
+	ldr	r7, [r4, #DDRC_SWSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	6b
+
+	ldr	r7, =0x10010100
+	str	r7, [r5, #0x4]
+
+	ldr	r6, =24000000
+	cmp	r0, r6
+	beq	25f
+
+	ldr	r7, =0x000B000D
+	str	r7,[r4, #DDRC_RFSHTMG]
+	b	7f
+
+25:
+	ldr	r7, =0x00030004
+	str	r7,[r4, #DDRC_RFSHTMG]
+
+	/* dram alt sel set to OSC */
+	ldr	r7, =0x10000000
+	ldr	r8, =0xa080
+	str	r7, [r2, r8]
+	/* dram root set to from dram alt, div by 1 */
+	ldr	r7, =0x11000000
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+	b	8f
+7:
+	/* dram alt sel set to pfd0_392m */
+	ldr	r7, =0x15000000
+	ldr	r8, =0xa080
+	str	r7, [r2, r8]
+	/* dram root set to from dram alt, div by 4 */
+	ldr	r7, =0x11000003
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+8:
+	ldr	r7, =0x202ffd0
+	str	r7, [r5, #DDRPHY_MDLL_CON0]
+
+	ldr	r7, =0x1000007f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r7, =0x7f7f7f7f
+	str	r7, [r5, #DDRPHY_OFFSETR_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETR_CON1]
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETR_CON2]
+
+	ldr	r7, =0x7f7f7f7f
+	str	r7, [r5, #DDRPHY_OFFSETW_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETW_CON1]
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETW_CON2]
+
+	ldr	r7, [r9, #ANADIG_DIGPROG]
+	and	r7, r7, #0x11
+	cmp	r7, #0x11
+	bne	20f
+
+	ldr	r7, =0x0
+	str	r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
+	ldr	r7, =0x60606060
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x00006060
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+	b	21f
+20:
+	ldr	r7, =0x0
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+21:
+	ldr	r7, =0x1100007f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+	ldr	r7, =0x1000007f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x1
+9:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	9b
+
+	ldr	r7, =0xf0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x820
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800000f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+10:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	10b
+
+	ldr	r7, =0x800020
+	str	r7, [r4, #DDRC_ZQCTL0]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_DBG1]
+
+	/* enable auto self-refresh */
+	ldr	r7, [r4, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	.endm
+
+	.macro	switch_to_533m
+
+	ldr	r7, =0x2
+	str	r7, [r4, #DDRC_DBG1]
+
+	ldr	r7, =0x78
+	str	r7, [r3, #IOMUXC_GPR8]
+	orr	r7, r7, #0x100
+	str	r7, [r3, #IOMUXC_GPR8]
+
+	ldr	r6, =0x30000000
+11:
+	ldr	r7, [r4, #DDRC_DBGCAM]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	11b
+
+	ldr	r6, =0x1
+12:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	12b
+
+	ldr	r7, =0x10f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800010f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r7, =0x20
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x23
+13:
+	ldr	r7, [r4, #DDRC_STAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	13b
+
+	ldr	r7, =0x03040001
+	str	r7, [r4, #DDRC_MSTR]
+
+	ldr	r7, =0x40800020
+	str	r7, [r4, #DDRC_ZQCTL0]
+
+
+	ldr	r7, =0x10210100
+	str	r7, [r5, #0x4]
+
+	ldr	r7, =0x00040046
+	str	r7, [r4, #DDRC_RFSHTMG]
+
+	/* dram root set to from dram main, div by 2 */
+	ldr	r7, =0x10000001
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+
+	ldr	r7, =0x1010007e
+	str	r7, [r5, #DDRPHY_MDLL_CON0]
+
+	ldr	r7, =0x10000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_OFFSETR_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETR_CON1]
+	ldr	r7, =0x8
+	str	r7, [r5, #DDRPHY_OFFSETR_CON2]
+
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_OFFSETW_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETW_CON1]
+	ldr	r7, =0x8
+	str	r7, [r5, #DDRPHY_OFFSETW_CON2]
+
+	ldr	r7, [r9, #ANADIG_DIGPROG]
+	and	r7, r7, #0x11
+	cmp	r7, #0x11
+	bne	22f
+
+	ldr	r7, =0x40404040
+	str	r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
+	ldr	r7, =0x18181818
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x40401818
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+	b	23f
+22:
+	ldr	r7, =0x0
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+23:
+	ldr	r7, =0x11000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+	ldr	r7, =0x10000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r6, =0x4
+14:
+	ldr	r7, [r5, #DDRPHY_MDLL_CON1]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	14b
+
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_RFSHCTL3]
+	ldr	r7, =0x3
+	str	r7, [r4, #DDRC_RFSHCTL3]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x1
+15:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	15b
+
+	ldr	r7, =0x10f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800010f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+16:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	16b
+
+	ldr	r7, =0xf0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x930
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800000f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_RFSHCTL3]
+	ldr	r7, =0x2
+	str	r7, [r4, #DDRC_RFSHCTL3]
+
+	ldr	r6, =0x1
+17:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	17b
+
+	ldr	r7, =0xf0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x930
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800000f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+18:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	18b
+
+	ldr	r7, =0x20f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x408
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800020f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r6, =0x1
+19:
+	ldr	r7, [r4, #DDRC_MRSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	19b
+
+	ldr	r7, =0x10f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+	ldr	r7, =0x4
+	str	r7, [r4, #DDRC_MRCTRL1]
+	ldr	r7, =0x800010f0
+	str	r7, [r4, #DDRC_MRCTRL0]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_DBG1]
+
+	/* enable auto self-refresh */
+	ldr	r7, [r4, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	.endm
+
+ENTRY(imx7d_ddr3_freq_change)
+	push	{r2 - r9}
+
+	/*
+	 * To ensure no page table walks occur in DDR, we
+	 * have a another page table stored in IRAM that only
+	 * contains entries pointing to IRAM, AIPS1 and AIPS2.
+	 * We need to set the TTBR1 to the new IRAM TLB.
+	 * Do the following steps:
+	 * 1. Flush the Branch Target Address Cache (BTAC)
+	 * 2. Set TTBR1 to point to IRAM page table.
+	 * 3. Disable page table walks in TTBR0 (PD0 = 1)
+	 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
+	 *     and 2-4G is translated by TTBR1.
+	 */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	ldr	r6, =iram_tlb_phys_addr
+	ldr	r7, [r6]
+
+	/* Disable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	bic	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	dsb
+	isb
+	/* Store the IRAM table in TTBR1 */
+	mcr	p15, 0, r7, c2, c0, 1
+
+	/* Read TTBCR and set PD0=1, N = 1 */
+	mrc	p15, 0, r6, c2, c0, 2
+	orr	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	dsb
+	isb
+
+	ldr	r2, =IMX_IO_P2V(MX7D_CCM_BASE_ADDR)
+	ldr	r3, =IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR)
+	ldr	r4, =IMX_IO_P2V(MX7D_DDRC_BASE_ADDR)
+	ldr	r5, =IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR)
+	ldr	r9, =IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR)
+
+	ldr	r6, =100000000
+	cmp	r0, r6
+	bgt	set_to_533m
+
+set_to_below_100m:
+	switch_to_below_100m
+	b	done
+
+set_to_533m:
+	switch_to_533m
+	b	done
+
+done:
+	/* Enable L1 data cache. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x4
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Restore the TTBCR */
+	dsb
+	isb
+
+	/* Read TTBCR and set PD0=0, N = 0 */
+	mrc	p15, 0, r6, c2, c0, 2
+	bic	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	dsb
+	isb
+
+	/* Enable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	dsb
+	isb
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	/* Restore registers */
+	pop	{r2 - r9}
+	mov	pc, lr
+	.ltorg
+ENDPROC(imx7d_ddr3_freq_change)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/ddrc.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/ddrc.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include "hardware.h"
+
+#define DDRC_MSTR		0x0
+#define	BM_DDRC_MSTR_DDR3	0x1
+#define	BM_DDRC_MSTR_LPDDR2	0x4
+#define	BM_DDRC_MSTR_LPDDR3	0x8
+
+static int ddr_type;
+
+static int imx_ddrc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	void __iomem *ddrc_base, *reg;
+	u32 val;
+
+	ddrc_base = of_iomap(np, 0);
+	WARN_ON(!ddrc_base);
+
+	reg = ddrc_base + DDRC_MSTR;
+	/* Get ddr type */
+	val = readl_relaxed(reg);
+	val &= (BM_DDRC_MSTR_DDR3 | BM_DDRC_MSTR_LPDDR2
+		| BM_DDRC_MSTR_LPDDR3);
+
+	switch (val) {
+	case BM_DDRC_MSTR_DDR3:
+		pr_info("DDR type is DDR3!\n");
+		ddr_type = IMX_DDR_TYPE_DDR3;
+		break;
+	case BM_DDRC_MSTR_LPDDR2:
+		pr_info("DDR type is LPDDR2!\n");
+		ddr_type = IMX_DDR_TYPE_LPDDR2;
+		break;
+	case BM_DDRC_MSTR_LPDDR3:
+		pr_info("DDR type is LPDDR3!\n");
+		ddr_type = IMX_DDR_TYPE_LPDDR3;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int imx_ddrc_get_ddr_type(void)
+{
+	return ddr_type;
+}
+
+static struct of_device_id imx_ddrc_dt_ids[] = {
+	{ .compatible = "fsl,imx7-ddrc", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver imx_ddrc_driver = {
+	.driver		= {
+		.name	= "imx-ddrc",
+		.owner	= THIS_MODULE,
+		.of_match_table = imx_ddrc_dt_ids,
+	},
+	.probe		= imx_ddrc_probe,
+};
+
+static int __init imx_ddrc_init(void)
+{
+	return platform_driver_register(&imx_ddrc_driver);
+}
+postcore_initcall(imx_ddrc_init);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/devices/platform-gpio-mxc.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/devices/platform-gpio-mxc.c
@@ -24,7 +24,8 @@
 			.flags = IORESOURCE_IRQ,
 		},
 	};
+	unsigned int nres;
 
-	return platform_device_register_resndata(&mxc_aips_bus,
-			name, id, res, ARRAY_SIZE(res), NULL, 0);
+	nres = irq_high ? ARRAY_SIZE(res) : ARRAY_SIZE(res) - 1;
+	return platform_device_register_resndata(&mxc_aips_bus, name, id, res, nres, NULL, 0);
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/gpc.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/gpc.c
@@ -10,26 +10,157 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/irqchip/arm-gic.h>
+
 #include "common.h"
 #include "hardware.h"
 
-#define GPC_CNTR		0x0
+#define GPC_CNTR		0x000
+#define GPC_CNTR_L2_PGE		22
+
 #define GPC_IMR1		0x008
+#define GPC_PGC_MF_PDN		0x220
 #define GPC_PGC_CPU_PDN		0x2a0
 #define GPC_PGC_CPU_PUPSCR	0x2a4
 #define GPC_PGC_CPU_PDNSCR	0x2a8
 #define GPC_PGC_SW2ISO_SHIFT	0x8
 #define GPC_PGC_SW_SHIFT	0x0
-
-#define GPC_CNTR_L2_PGE_SHIFT	22
+#define GPC_M4_LPSR		0x2c
+#define GPC_M4_LPSR_M4_SLEEPING_SHIFT	4
+#define GPC_M4_LPSR_M4_SLEEPING_MASK	0x1
+#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK	0x1
+#define GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT	0
+#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK	0x1
+#define GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT	1
+
+#define GPC_PGC_CPU_SW_SHIFT		0
+#define GPC_PGC_CPU_SW_MASK		0x3f
+#define GPC_PGC_CPU_SW2ISO_SHIFT	8
+#define GPC_PGC_CPU_SW2ISO_MASK		0x3f
 
 #define IMR_NUM			4
 #define GPC_MAX_IRQS		(IMR_NUM * 32)
 
+/* for irq #74 and #75 */
+#define GPC_USB_VBUS_WAKEUP_IRQ_MASK		0xc00
+
+/* for irq #150 and #151 */
+#define GPC_ENET_WAKEUP_IRQ_MASK        0xC00000
+
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
+static u32 gpc_mf_irqs[IMR_NUM];
+static u32 gpc_mf_request_on[IMR_NUM];
+static DEFINE_SPINLOCK(gpc_lock);
+
+void imx_gpc_add_m4_wake_up_irq(u32 hwirq, bool enable)
+{
+	unsigned int idx = hwirq / 32;
+	unsigned long flags;
+	u32 mask;
+
+	/* Sanity check for SPI irq */
+	if (hwirq < 32)
+		return;
+
+	mask = 1 << hwirq % 32;
+	spin_lock_irqsave(&gpc_lock, flags);
+	gpc_wake_irqs[idx] = enable ? gpc_wake_irqs[idx] | mask :
+		gpc_wake_irqs[idx] & ~mask;
+	spin_unlock_irqrestore(&gpc_lock, flags);
+}
+
+void imx_gpc_hold_m4_in_sleep(void)
+{
+	int val;
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+	/* wait M4 in wfi before asserting hold request */
+	while (!imx_gpc_is_m4_sleeping())
+		if (time_after(jiffies, timeout))
+			pr_err("M4 is NOT in expected sleep!\n");
+
+	val = readl_relaxed(gpc_base + GPC_M4_LPSR);
+	val &= ~(GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK <<
+		GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT);
+	writel_relaxed(val, gpc_base + GPC_M4_LPSR);
+
+	timeout = jiffies + msecs_to_jiffies(500);
+	while (readl_relaxed(gpc_base + GPC_M4_LPSR)
+		& (GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_MASK <<
+		GPC_M4_LPSR_M4_SLEEP_HOLD_ACK_SHIFT))
+		if (time_after(jiffies, timeout))
+			pr_err("Wait M4 hold ack timeout!\n");
+}
+
+void imx_gpc_release_m4_in_sleep(void)
+{
+	int val;
+
+	val = readl_relaxed(gpc_base + GPC_M4_LPSR);
+	val |= GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_MASK <<
+		GPC_M4_LPSR_M4_SLEEP_HOLD_REQ_SHIFT;
+	writel_relaxed(val, gpc_base + GPC_M4_LPSR);
+}
+
+unsigned int imx_gpc_is_m4_sleeping(void)
+{
+	if (readl_relaxed(gpc_base + GPC_M4_LPSR) &
+		(GPC_M4_LPSR_M4_SLEEPING_MASK <<
+		GPC_M4_LPSR_M4_SLEEPING_SHIFT))
+		return 1;
+
+	return 0;
+}
+
+bool imx_gpc_usb_wakeup_enabled(void)
+{
+	if (!(cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()
+		|| cpu_is_imx6sll()))
+		return false;
+
+	/*
+	 * for SoC later than i.MX6SX, USB vbus wakeup
+	 * only needs weak 2P5 on, stop_mode_config is
+	 * NOT needed, so we check if is USB vbus wakeup
+	 * is enabled(assume irq #74 and #75) to decide
+	 * if to keep weak 2P5 on.
+	 */
+	if (gpc_wake_irqs[1] & GPC_USB_VBUS_WAKEUP_IRQ_MASK)
+		return true;
+
+	return false;
+}
+
+bool imx_gpc_enet_wakeup_enabled(void)
+{
+	if (!cpu_is_imx6q())
+		return false;
+
+	if (gpc_wake_irqs[3] & GPC_ENET_WAKEUP_IRQ_MASK)
+		return true;
+
+	return false;
+}
+
+unsigned int imx_gpc_is_mf_mix_off(void)
+{
+	return readl_relaxed(gpc_base + GPC_PGC_MF_PDN);
+}
+
+static void imx_gpc_mf_mix_off(void)
+{
+	int i;
+
+	for (i = 0; i < IMR_NUM; i++)
+		if (((gpc_wake_irqs[i] | gpc_mf_request_on[i]) &
+						gpc_mf_irqs[i]) != 0)
+			return;
+
+	pr_info("Turn off M/F mix!\n");
+	/* turn off mega/fast mix */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_MF_PDN);
+}
 
 void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
 {
@@ -53,9 +184,9 @@
 	u32 val;
 
 	val = readl_relaxed(gpc_base + GPC_CNTR);
-	val &= ~(1 << GPC_CNTR_L2_PGE_SHIFT);
+	val &= ~(1 << GPC_CNTR_L2_PGE);
 	if (power_off)
-		val |= 1 << GPC_CNTR_L2_PGE_SHIFT;
+		val |= 1 << GPC_CNTR_L2_PGE;
 	writel_relaxed(val, gpc_base + GPC_CNTR);
 }
 
@@ -89,11 +220,14 @@
 static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	unsigned int idx = d->hwirq / 32;
+	unsigned long flags;
 	u32 mask;
 
 	mask = 1 << d->hwirq % 32;
+	spin_lock_irqsave(&gpc_lock, flags);
 	gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
 				  gpc_wake_irqs[idx] & ~mask;
+	spin_unlock_irqrestore(&gpc_lock, flags);
 
 	/*
 	 * Do *not* call into the parent, as the GIC doesn't have any
@@ -111,7 +245,6 @@
 		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
 		writel_relaxed(~0, reg_imr1 + i * 4);
 	}
-
 }
 
 void imx_gpc_restore_all(void)
@@ -225,11 +358,75 @@
 	.free		= irq_domain_free_irqs_common,
 };
 
+int imx_gpc_mf_power_on(unsigned int irq, unsigned int on)
+{
+	struct irq_desc *d = irq_to_desc(irq);
+	unsigned int idx = d->irq_data.hwirq / 32;
+	unsigned long flags;
+	u32 mask;
+
+	mask = 1 << (d->irq_data.hwirq % 32);
+	spin_lock_irqsave(&gpc_lock, flags);
+	gpc_mf_request_on[idx] = on ? gpc_mf_request_on[idx] | mask :
+				  gpc_mf_request_on[idx] & ~mask;
+	spin_unlock_irqrestore(&gpc_lock, flags);
+
+	return 0;
+}
+
+int imx_gpc_mf_request_on(unsigned int irq, unsigned int on)
+{
+	if (cpu_is_imx7d())
+		return imx_gpcv2_mf_power_on(irq, on);
+	else
+		return 0;
+}
+EXPORT_SYMBOL_GPL(imx_gpc_mf_request_on);
+
+void imx_gpc_switch_pupscr_clk(bool flag)
+{
+	static u32 pupscr_sw2iso, pupscr_sw;
+	u32 ratio, pupscr = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR);
+
+	if (flag) {
+		/* save the init clock setting IPG/2048 for IPG@66Mhz */
+		pupscr_sw2iso = (pupscr >> GPC_PGC_CPU_SW2ISO_SHIFT) &
+				    GPC_PGC_CPU_SW2ISO_MASK;
+		pupscr_sw = (pupscr >> GPC_PGC_CPU_SW_SHIFT) &
+				GPC_PGC_CPU_SW_MASK;
+		/*
+		 * i.MX6UL TO1.0 ARM power up uses IPG/2048 as clock source,
+		 * from TO1.1, PGC_CPU_PUPSCR bit [5] is re-defined to switch
+		 * clock to IPG/32, enable this bit to speed up the ARM power
+		 * up process in low power idle case(IPG@1.5Mhz). So the sw and
+		 * sw2iso need to be adjusted as below:
+		 * sw_new(sw2iso_new) = (2048 * 1.5 / 66 * 32) * sw(sw2iso)
+		 */
+		ratio = 3072 / (66 * 32);
+		pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT |
+			  GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+		pupscr |= (ratio * pupscr_sw + 1) << GPC_PGC_CPU_SW_SHIFT |
+			  1 << 5 | (ratio * pupscr_sw2iso + 1) <<
+			  GPC_PGC_CPU_SW2ISO_SHIFT;
+		writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR);
+	} else {
+		/* restore back after exit from low power idle */
+		pupscr &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT |
+			  GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+		pupscr |= pupscr_sw << GPC_PGC_CPU_SW_SHIFT |
+			  pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT;
+		writel_relaxed(pupscr, gpc_base + GPC_PGC_CPU_PUPSCR);
+	}
+}
+
 static int __init imx_gpc_init(struct device_node *node,
 			       struct device_node *parent)
 {
 	struct irq_domain *parent_domain, *domain;
 	int i;
+	u32 val;
+	u32 cpu_pupscr_sw2iso, cpu_pupscr_sw;
+	u32 cpu_pdnscr_iso2sw, cpu_pdnscr_iso;
 
 	if (!parent) {
 		pr_err("%pOF: no parent, giving up\n", node);
@@ -264,6 +461,41 @@
 	 */
 	of_node_clear_flag(node, OF_POPULATED);
 
+	/*
+	 * If there are CPU isolation timing settings in dts,
+	 * update them according to dts, otherwise, keep them
+	 * with default value in registers.
+	 */
+	cpu_pupscr_sw2iso = cpu_pupscr_sw =
+		cpu_pdnscr_iso2sw = cpu_pdnscr_iso = 0;
+
+	/* Read CPU isolation setting for GPC */
+	of_property_read_u32(node, "fsl,cpu_pupscr_sw2iso", &cpu_pupscr_sw2iso);
+	of_property_read_u32(node, "fsl,cpu_pupscr_sw", &cpu_pupscr_sw);
+	of_property_read_u32(node, "fsl,cpu_pdnscr_iso2sw", &cpu_pdnscr_iso2sw);
+	of_property_read_u32(node, "fsl,cpu_pdnscr_iso", &cpu_pdnscr_iso);
+
+	/* Return if no property found in dtb */
+	if ((cpu_pupscr_sw2iso | cpu_pupscr_sw
+		| cpu_pdnscr_iso2sw | cpu_pdnscr_iso) == 0)
+		return 0;
+
+	/* Update CPU PUPSCR timing if it is defined in dts */
+	val = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR);
+	val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+	val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT);
+	val |= cpu_pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT;
+	val |= cpu_pupscr_sw << GPC_PGC_CPU_SW_SHIFT;
+	writel_relaxed(val, gpc_base + GPC_PGC_CPU_PUPSCR);
+
+	/* Update CPU PDNSCR timing if it is defined in dts */
+	val = readl_relaxed(gpc_base + GPC_PGC_CPU_PDNSCR);
+	val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT);
+	val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT);
+	val |= cpu_pdnscr_iso2sw << GPC_PGC_CPU_SW2ISO_SHIFT;
+	val |= cpu_pdnscr_iso << GPC_PGC_CPU_SW_SHIFT;
+	writel_relaxed(val, gpc_base + GPC_PGC_CPU_PDNSCR);
+
 	return 0;
 }
 IRQCHIP_DECLARE(imx_gpc, "fsl,imx6q-gpc", imx_gpc_init);
@@ -282,4 +514,5 @@
 		/* map GPC, so that at least CPUidle and WARs keep working */
 		gpc_base = of_iomap(np, 0);
 	}
+	of_node_put(np);
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/gpcv2.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/gpcv2.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
+
+#include "common.h"
+#include "hardware.h"
+
+#define IMR_NUM			4
+#define GPC_MAX_IRQS		(IMR_NUM * 32)
+#define GPC_LPCR_A7_BSC		0x0
+#define GPC_LPCR_A7_AD		0x4
+#define GPC_LPCR_M4		0x8
+#define GPC_SLPCR		0x14
+#define GPC_MLPCR		0x20
+#define GPC_PGC_ACK_SEL_A7	0x24
+#define GPC_MISC		0x2c
+#define GPC_IMR1_CORE0		0x30
+#define GPC_IMR1_CORE1		0x40
+#define GPC_IMR1_M4		0x50
+#define GPC_SLOT0_CFG		0xb0
+#define GPC_PGC_CPU_MAPPING	0xec
+#define GPC_CPU_PGC_SW_PUP_REQ	0xf0
+#define GPC_PU_PGC_SW_PUP_REQ	0xf8
+#define GPC_CPU_PGC_SW_PDN_REQ	0xfc
+#define GPC_PU_PGC_SW_PDN_REQ	0x104
+#define GPC_GTOR		0x124
+#define GPC_PGC_C0		0x800
+#define GPC_PGC_C0_PUPSCR	0x804
+#define GPC_PGC_SCU_TIMING	0x890
+#define GPC_PGC_C1		0x840
+#define GPC_PGC_C1_PUPSCR	0x844
+#define GPC_PGC_SCU		0x880
+#define GPC_PGC_FM		0xa00
+
+#define BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP	0x70000000
+#define BM_LPCR_A7_BSC_CPU_CLK_ON_LPM		0x4000
+#define BM_LPCR_A7_BSC_LPM1			0xc
+#define BM_LPCR_A7_BSC_LPM0			0x3
+#define BP_LPCR_A7_BSC_LPM1			2
+#define BP_LPCR_A7_BSC_LPM0			0
+#define BM_LPCR_M4_MASK_DSM_TRIGGER		0x80000000
+#define BM_SLPCR_EN_DSM				0x80000000
+#define BM_SLPCR_RBC_EN				0x40000000
+#define BM_SLPCR_REG_BYPASS_COUNT		0x3f000000
+#define BM_SLPCR_VSTBY				0x4
+#define BM_SLPCR_SBYOS				0x2
+#define BM_SLPCR_BYPASS_PMIC_READY		0x1
+#define BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE	0x10000
+#define BM_LPCR_A7_AD_L2PGE			0x10000
+#define BM_LPCR_A7_AD_EN_C1_PUP			0x800
+#define BM_LPCR_A7_AD_EN_C1_IRQ_PUP		0x400
+#define BM_LPCR_A7_AD_EN_C0_PUP			0x200
+#define BM_LPCR_A7_AD_EN_C0_IRQ_PUP		0x100
+#define BM_LPCR_A7_AD_EN_PLAT_PDN		0x10
+#define BM_LPCR_A7_AD_EN_C1_PDN			0x8
+#define BM_LPCR_A7_AD_EN_C1_WFI_PDN		0x4
+#define BM_LPCR_A7_AD_EN_C0_PDN			0x2
+#define BM_LPCR_A7_AD_EN_C0_WFI_PDN		0x1
+
+#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7	0x2
+#define BM_GPC_PGC_PCG				0x1
+#define BM_GPC_PGC_CORE_PUPSCR			0x7fff80
+
+#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK	0x80000000
+#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK	0x8000
+#define BM_GPC_MLPCR_MEMLP_CTL_DIS		0x1
+
+#define BP_LPCR_A7_BSC_IRQ_SRC			28
+
+#define MAX_SLOT_NUMBER				10
+#define A7_LPM_WAIT				0x5
+#define A7_LPM_STOP				0xa
+
+enum imx_gpc_slot {
+	CORE0_A7,
+	CORE1_A7,
+	SCU_A7,
+	FAST_MEGA_MIX,
+	MIPI_PHY,
+	PCIE_PHY,
+	USB_OTG1_PHY,
+	USB_OTG2_PHY,
+	USB_HSIC_PHY,
+	CORE0_M4,
+};
+
+static void __iomem *gpc_base;
+static u32 gpcv2_wake_irqs[IMR_NUM];
+static u32 gpcv2_saved_imrs[IMR_NUM];
+static u32 gpcv2_saved_imrs_m4[IMR_NUM];
+static u32 gpcv2_mf_irqs[IMR_NUM];
+static u32 gpcv2_mf_request_on[IMR_NUM];
+static DEFINE_SPINLOCK(gpcv2_lock);
+
+void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable)
+{
+	unsigned int idx = hwirq / 32;
+	unsigned long flags;
+	u32 mask;
+
+	/* Sanity check for SPI irq */
+	if (hwirq < 32)
+		return;
+
+	mask = 1 << hwirq % 32;
+	spin_lock_irqsave(&gpcv2_lock, flags);
+	gpcv2_wake_irqs[idx] = enable ? gpcv2_wake_irqs[idx] | mask :
+		gpcv2_wake_irqs[idx] & ~mask;
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
+
+static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	unsigned int idx = d->hwirq / 32;
+	unsigned long flags;
+	u32 mask;
+
+	BUG_ON(idx >= IMR_NUM);
+
+	mask = 1 << d->hwirq % 32;
+	spin_lock_irqsave(&gpcv2_lock, flags);
+	gpcv2_wake_irqs[idx] = on ? gpcv2_wake_irqs[idx] | mask :
+				  gpcv2_wake_irqs[idx] & ~mask;
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+
+	return 0;
+}
+
+void imx_gpcv2_mask_all(void)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0;
+	int i;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
+		writel_relaxed(~0, reg_imr1 + i * 4);
+	}
+}
+
+void imx_gpcv2_restore_all(void)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0;
+	int i;
+
+	for (i = 0; i < IMR_NUM; i++)
+		writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4);
+}
+
+void imx_gpcv2_hwirq_unmask(unsigned int hwirq)
+{
+	void __iomem *reg;
+	u32 val;
+
+	reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4;
+	val = readl_relaxed(reg);
+	val &= ~(1 << hwirq % 32);
+	writel_relaxed(val, reg);
+}
+
+void imx_gpcv2_hwirq_mask(unsigned int hwirq)
+{
+	void __iomem *reg;
+	u32 val;
+
+	reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4;
+	val = readl_relaxed(reg);
+	val |= 1 << (hwirq % 32);
+	writel_relaxed(val, reg);
+}
+
+static void imx_gpcv2_irq_unmask(struct irq_data *d)
+{
+	imx_gpcv2_hwirq_unmask(d->hwirq);
+	irq_chip_unmask_parent(d);
+}
+
+static void imx_gpcv2_irq_mask(struct irq_data *d)
+{
+	imx_gpcv2_hwirq_mask(d->hwirq);
+	irq_chip_mask_parent(d);
+}
+
+void imx_gpcv2_set_slot_ack(u32 index, enum imx_gpc_slot m_core,
+				bool mode, bool ack)
+{
+	u32 val;
+
+	if (index >= MAX_SLOT_NUMBER)
+		pr_err("Invalid slot index!\n");
+	/* set slot */
+	writel_relaxed(readl_relaxed(gpc_base + GPC_SLOT0_CFG + index * 4) |
+		((mode + 1) << (m_core * 2)),
+		gpc_base + GPC_SLOT0_CFG + index * 4);
+
+	if (ack) {
+		/* set ack */
+		val = readl_relaxed(gpc_base + GPC_PGC_ACK_SEL_A7);
+		/* clear dummy ack */
+		val &= ~(1 << (15 + (mode ? 16 : 0)));
+		val |= 1 << (m_core + (mode ? 16 : 0));
+		writel_relaxed(val, gpc_base + GPC_PGC_ACK_SEL_A7);
+	}
+}
+
+void imx_gpcv2_set_lpm_mode(enum mxc_cpu_pwr_mode mode)
+{
+	unsigned long flags;
+	u32 val1, val2;
+
+	spin_lock_irqsave(&gpcv2_lock, flags);
+
+	val1 = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC);
+	val2 = readl_relaxed(gpc_base + GPC_SLPCR);
+
+	/* all cores' LPM settings must be same */
+	val1 &= ~(BM_LPCR_A7_BSC_LPM0 | BM_LPCR_A7_BSC_LPM1);
+
+	val1 |= BM_LPCR_A7_BSC_CPU_CLK_ON_LPM;
+
+	val2 &= ~(BM_SLPCR_EN_DSM | BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN |
+		BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY);
+	/*
+	 * GPC: When improper low-power sequence is used,
+	 * the SoC enters low power mode before the ARM core executes WFI.
+	 *
+	 * Software workaround:
+	 * 1) Software should trigger IRQ #32 (IOMUX) to be always pending
+	 *    by setting IOMUX_GPR1_IRQ.
+	 * 2) Software should then unmask IRQ #32 in GPC before setting GPC
+	 *    Low-Power mode.
+	 * 3) Software should mask IRQ #32 right after GPC Low-Power mode
+	 *    is set.
+	 */
+	switch (mode) {
+	case WAIT_CLOCKED:
+		imx_gpcv2_hwirq_unmask(0);
+		break;
+	case WAIT_UNCLOCKED:
+		val1 |= A7_LPM_WAIT << BP_LPCR_A7_BSC_LPM0;
+		val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM;
+		imx_gpcv2_hwirq_mask(0);
+		break;
+	case STOP_POWER_ON:
+		val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0;
+		val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM;
+		val2 |= BM_SLPCR_EN_DSM;
+		val2 |= BM_SLPCR_RBC_EN;
+		val2 |= BM_SLPCR_BYPASS_PMIC_READY;
+		imx_gpcv2_hwirq_mask(0);
+		break;
+	case STOP_POWER_OFF:
+		val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0;
+		val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM;
+		val2 |= BM_SLPCR_EN_DSM;
+		val2 |= BM_SLPCR_RBC_EN;
+		val2 |= BM_SLPCR_SBYOS;
+		val2 |= BM_SLPCR_VSTBY;
+		val2 |= BM_SLPCR_BYPASS_PMIC_READY;
+		imx_gpcv2_hwirq_mask(0);
+		break;
+	default:
+		return;
+	}
+	writel_relaxed(val1, gpc_base + GPC_LPCR_A7_BSC);
+	writel_relaxed(val2, gpc_base + GPC_SLPCR);
+
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
+
+void imx_gpcv2_set_plat_power_gate_by_lpm(bool pdn)
+{
+	u32 val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD);
+
+	val &= ~(BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE);
+	if (pdn)
+		val |= BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE;
+
+	writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD);
+}
+
+void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
+{
+	u32 val = readl_relaxed(gpc_base + offset) & (~BM_GPC_PGC_PCG);
+
+	if (enable)
+		val |= BM_GPC_PGC_PCG;
+
+	writel_relaxed(val, gpc_base + offset);
+}
+
+void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn)
+{
+	u32 val = readl_relaxed(gpc_base + (pdn ?
+		GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ));
+
+	imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
+	val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
+	writel_relaxed(val, gpc_base + (pdn ?
+		GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ));
+
+	while ((readl_relaxed(gpc_base + (pdn ?
+		GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) &
+		BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
+		;
+	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
+}
+
+void imx_gpcv2_set_cpu_power_gate_by_wfi(u32 cpu, bool pdn)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&gpcv2_lock, flags);
+	val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD);
+
+	if (cpu == 0) {
+		if (pdn) {
+			imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0);
+			val |= BM_LPCR_A7_AD_EN_C0_WFI_PDN |
+				BM_LPCR_A7_AD_EN_C0_IRQ_PUP;
+		} else {
+			imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0);
+			val &= ~(BM_LPCR_A7_AD_EN_C0_WFI_PDN |
+				BM_LPCR_A7_AD_EN_C0_IRQ_PUP);
+		}
+	}
+	if (cpu == 1) {
+		if (pdn) {
+			imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
+			val |= BM_LPCR_A7_AD_EN_C1_WFI_PDN |
+				BM_LPCR_A7_AD_EN_C1_IRQ_PUP;
+		} else {
+			imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
+			val &= ~(BM_LPCR_A7_AD_EN_C1_WFI_PDN |
+				BM_LPCR_A7_AD_EN_C1_IRQ_PUP);
+		}
+	}
+	writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD);
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
+
+void imx_gpcv2_set_cpu_power_gate_by_lpm(u32 cpu, bool pdn)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&gpcv2_lock, flags);
+
+	val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD);
+	if (cpu == 0) {
+		if (pdn)
+			val |= BM_LPCR_A7_AD_EN_C0_PDN |
+				BM_LPCR_A7_AD_EN_C0_PUP;
+		else
+			val &= ~(BM_LPCR_A7_AD_EN_C0_PDN |
+				BM_LPCR_A7_AD_EN_C0_PUP);
+	}
+	if (cpu == 1) {
+		if (pdn)
+			val |= BM_LPCR_A7_AD_EN_C1_PDN |
+				BM_LPCR_A7_AD_EN_C1_PUP;
+		else
+			val &= ~(BM_LPCR_A7_AD_EN_C1_PDN |
+				BM_LPCR_A7_AD_EN_C1_PUP);
+	}
+
+	writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD);
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
+
+void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn)
+{
+	unsigned long flags;
+	u32 cpu;
+
+	for_each_possible_cpu(cpu)
+		imx_gpcv2_set_cpu_power_gate_by_lpm(cpu, pdn);
+
+	spin_lock_irqsave(&gpcv2_lock, flags);
+
+	imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C0);
+	if (num_online_cpus() > 1)
+		imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C1);
+	imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_SCU);
+	imx_gpcv2_set_plat_power_gate_by_lpm(pdn);
+
+	if (pdn) {
+		imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false);
+		if (num_online_cpus() > 1)
+			imx_gpcv2_set_slot_ack(2, CORE1_A7, false, false);
+		imx_gpcv2_set_slot_ack(3, SCU_A7, false, true);
+		imx_gpcv2_set_slot_ack(6, SCU_A7, true, false);
+		if (num_online_cpus() > 1)
+			imx_gpcv2_set_slot_ack(6, CORE1_A7, true, false);
+		imx_gpcv2_set_slot_ack(6, CORE0_A7, true, true);
+	} else {
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 0 * 0x4);
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 2 * 0x4);
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 3 * 0x4);
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 6 * 0x4);
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 7 * 0x4);
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 8 * 0x4);
+		writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK |
+			BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK,
+			gpc_base + GPC_PGC_ACK_SEL_A7);
+		imx_gpcv2_enable_rbc(false);
+	}
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
+
+void imx_gpcv2_set_mix_phy_gate_by_lpm(u32 pdn_index, u32 pup_index)
+{
+	/* set power down slot */
+	writel_relaxed(1 << (FAST_MEGA_MIX * 2),
+		gpc_base + GPC_SLOT0_CFG + pdn_index * 4);
+
+	/* set power up slot */
+	writel_relaxed(1 << (FAST_MEGA_MIX * 2 + 1),
+		gpc_base + GPC_SLOT0_CFG + pup_index * 4);
+}
+
+unsigned int imx_gpcv2_is_mf_mix_off(void)
+{
+	return readl_relaxed(gpc_base + GPC_PGC_FM);
+}
+
+static void imx_gpcv2_mf_mix_off(void)
+{
+	int i;
+
+	for (i = 0; i < IMR_NUM; i++)
+		if (((gpcv2_wake_irqs[i] | gpcv2_mf_request_on[i]) &
+						gpcv2_mf_irqs[i]) != 0)
+			return;
+
+	pr_info("Turn off Mega/Fast mix in DSM\n");
+	imx_gpcv2_set_slot_ack(1, FAST_MEGA_MIX, false, false);
+	imx_gpcv2_set_slot_ack(5, FAST_MEGA_MIX, true, false);
+	imx_gpcv2_set_m_core_pgc(true, GPC_PGC_FM);
+}
+
+int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+	unsigned long hwirq = desc->irq_data.hwirq;
+	unsigned int idx = hwirq / 32;
+	unsigned long flags;
+	u32 mask = 1 << (hwirq % 32);
+
+	BUG_ON(idx >= IMR_NUM);
+
+	spin_lock_irqsave(&gpcv2_lock, flags);
+	gpcv2_mf_request_on[idx] = on ? gpcv2_mf_request_on[idx] | mask :
+				  gpcv2_mf_request_on[idx] & ~mask;
+	spin_unlock_irqrestore(&gpcv2_lock, flags);
+
+	return 0;
+}
+
+void imx_gpcv2_enable_rbc(bool enable)
+{
+	u32 val;
+
+	/*
+	 * need to mask all interrupts in GPC before
+	 * operating RBC configurations
+	 */
+	imx_gpcv2_mask_all();
+
+	/* configure RBC enable bit */
+	val = readl_relaxed(gpc_base + GPC_SLPCR);
+	val &= ~BM_SLPCR_RBC_EN;
+	val |= enable ? BM_SLPCR_RBC_EN : 0;
+	writel_relaxed(val, gpc_base + GPC_SLPCR);
+
+	/* configure RBC count */
+	val = readl_relaxed(gpc_base + GPC_SLPCR);
+	val &= ~BM_SLPCR_REG_BYPASS_COUNT;
+	val |= enable ? BM_SLPCR_REG_BYPASS_COUNT : 0;
+	writel(val, gpc_base + GPC_SLPCR);
+
+	/*
+	 * need to delay at least 2 cycles of CKIL(32K)
+	 * due to hardware design requirement, which is
+	 * ~61us, here we use 65us for safe
+	 */
+	udelay(65);
+
+	/* restore GPC interrupt mask settings */
+	imx_gpcv2_restore_all();
+}
+
+
+void imx_gpcv2_pre_suspend(bool arm_power_off)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0;
+	int i;
+
+	if (arm_power_off) {
+		imx_gpcv2_set_lpm_mode(STOP_POWER_OFF);
+		/* enable core0 power down/up with low power mode */
+		imx_gpcv2_set_cpu_power_gate_by_lpm(0, true);
+		/* enable plat power down with low power mode */
+		imx_gpcv2_set_plat_power_gate_by_lpm(true);
+
+		/*
+		 * To avoid confuse, we use slot 0~4 for power down,
+		 * slot 5~9 for power up.
+		 *
+		 * Power down slot sequence:
+		 * Slot0 -> CORE0
+		 * Slot1 -> Mega/Fast MIX
+		 * Slot2 -> SCU
+		 *
+		 * Power up slot sequence:
+		 * Slot5 -> Mega/Fast MIX
+		 * Slot6 -> SCU
+		 * Slot7 -> CORE0
+		 */
+		imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false);
+		imx_gpcv2_set_slot_ack(2, SCU_A7, false, true);
+
+		if ((!imx_src_is_m4_enabled()) ||
+			(imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()))
+				imx_gpcv2_mf_mix_off();;
+
+		imx_gpcv2_set_slot_ack(6, SCU_A7, true, false);
+		imx_gpcv2_set_slot_ack(6, CORE0_A7, true, true);
+
+		/* enable core0, scu */
+		imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0);
+		imx_gpcv2_set_m_core_pgc(true, GPC_PGC_SCU);
+	} else {
+		imx_gpcv2_set_lpm_mode(STOP_POWER_ON);
+	}
+
+	for (i = 0; i < IMR_NUM; i++) {
+		gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
+		writel_relaxed(~gpcv2_wake_irqs[i], reg_imr1 + i * 4);
+	}
+}
+
+void imx_gpcv2_enable_wakeup_for_m4(void)
+{
+	void __iomem *reg_imr2 = gpc_base + GPC_IMR1_M4;
+	u32 i;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		gpcv2_saved_imrs_m4[i] = readl_relaxed(reg_imr2 + i * 4);
+		writel_relaxed(~gpcv2_wake_irqs[i], reg_imr2 + i * 4);
+	}
+}
+
+void imx_gpcv2_disable_wakeup_for_m4(void)
+{
+	void __iomem *reg_imr2 = gpc_base + GPC_IMR1_M4;
+	u32 i;
+
+	for (i = 0; i < IMR_NUM; i++)
+		writel_relaxed(gpcv2_saved_imrs_m4[i], reg_imr2 + i * 4);
+}
+
+void imx_gpcv2_post_resume(void)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0;
+	int i, val;
+
+	/* only external IRQs to wake up LPM and core 0/1 */
+	val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC);
+	val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP;
+	writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC);
+	/* mask m4 dsm trigger if M4 NOT enabled */
+	if (!imx_src_is_m4_enabled())
+		writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) |
+			BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4);
+	/* set mega/fast mix in A7 domain */
+	val = readl_relaxed(gpc_base + GPC_PGC_CPU_MAPPING);
+	val |= 0x1;
+	writel_relaxed(val, gpc_base + GPC_PGC_CPU_MAPPING);
+	/* set SCU timing */
+	writel_relaxed((0x59 << 10) | 0x5B | (0x2 << 20),
+		gpc_base + GPC_PGC_SCU_TIMING);
+
+	/* set C0/C1 power up timming per design requirement */
+	val = readl_relaxed(gpc_base + GPC_PGC_C0_PUPSCR);
+	val &= ~BM_GPC_PGC_CORE_PUPSCR;
+	val |= (0x1A << 7);
+	writel_relaxed(val, gpc_base + GPC_PGC_C0_PUPSCR);
+
+	val = readl_relaxed(gpc_base + GPC_PGC_C1_PUPSCR);
+	val &= ~BM_GPC_PGC_CORE_PUPSCR;
+	val |= (0x1A << 7);
+	writel_relaxed(val, gpc_base + GPC_PGC_C1_PUPSCR);
+
+	val = readl_relaxed(gpc_base + GPC_SLPCR);
+	val &= ~(BM_SLPCR_EN_DSM);
+	if (!imx_src_is_m4_enabled())
+		val &= ~(BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN |
+			BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY);
+	val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE;
+	writel_relaxed(val, gpc_base + GPC_SLPCR);
+
+	if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
+		/* disable memory low power mode */
+		val = readl_relaxed(gpc_base + GPC_MLPCR);
+		val |= BM_GPC_MLPCR_MEMLP_CTL_DIS;
+		writel_relaxed(val, gpc_base + GPC_MLPCR);
+	}
+
+	for (i = 0; i < IMR_NUM; i++)
+		writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4);
+
+	imx_gpcv2_set_lpm_mode(WAIT_CLOCKED);
+	imx_gpcv2_set_cpu_power_gate_by_lpm(0, false);
+	imx_gpcv2_set_plat_power_gate_by_lpm(false);
+
+	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0);
+	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_SCU);
+	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_FM);
+	for (i = 0; i < MAX_SLOT_NUMBER; i++){
+		if (i == 1 || i == 5) /* skip slts m4 uses */
+			continue;
+		writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + i * 0x4);
+	}
+	writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK |
+		BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK,
+		gpc_base + GPC_PGC_ACK_SEL_A7);
+
+	/* disable RBC */
+	imx_gpcv2_enable_rbc(false);
+}
+
+static struct irq_chip imx_gpcv2_chip = {
+	.name			= "GPCV2",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_mask		= imx_gpcv2_irq_mask,
+	.irq_unmask		= imx_gpcv2_irq_unmask,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_wake		= imx_gpcv2_irq_set_wake,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+#endif
+};
+
+static int imx_gpcv2_domain_xlate(struct irq_domain *domain,
+				struct device_node *controller,
+				const u32 *intspec,
+				unsigned int intsize,
+				unsigned long *out_hwirq,
+				unsigned int *out_type)
+{
+	if (irq_domain_get_of_node(domain) != controller)
+		return -EINVAL;	/* Shouldn't happen, really... */
+	if (intsize != 3)
+		return -EINVAL;	/* Not GIC compliant */
+	if (intspec[0] != 0)
+		return -EINVAL;	/* No PPI should point to this domain */
+
+	*out_hwirq = intspec[1];
+	*out_type = intspec[2];
+	return 0;
+}
+
+static int imx_gpcv2_domain_alloc(struct irq_domain *domain,
+				  unsigned int irq,
+				  unsigned int nr_irqs, void *data)
+{
+	struct irq_fwspec *fwspec = data;
+	struct irq_fwspec parent_fwspec;
+	irq_hw_number_t hwirq;
+	int i;
+
+	if (fwspec->param_count != 3)
+		return -EINVAL;	/* Not GIC compliant */
+	if (fwspec->param[0] != 0)
+		return -EINVAL;	/* No PPI should point to this domain */
+
+	hwirq = fwspec->param[1];
+	if (hwirq >= GPC_MAX_IRQS)
+		return -EINVAL;	/* Can't deal with this */
+
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+					      &imx_gpcv2_chip, NULL);
+
+	parent_fwspec.fwnode = domain->parent->fwnode;
+	parent_fwspec.param_count = 3;
+	parent_fwspec.param[0] = 0;
+	parent_fwspec.param[1] = hwirq;
+	parent_fwspec.param[2] = fwspec->param[2];
+
+	return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs,
+					    &parent_fwspec);
+}
+
+static struct irq_domain_ops imx_gpcv2_domain_ops = {
+	.xlate	= imx_gpcv2_domain_xlate,
+	.alloc	= imx_gpcv2_domain_alloc,
+	.free	= irq_domain_free_irqs_common,
+};
+
+static int __init imx_gpcv2_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	struct irq_domain *parent_domain, *domain;
+	int i, val;
+
+	if (!parent) {
+		pr_err("%s: no parent, giving up\n", node->full_name);
+		return -ENODEV;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("%s: unable to obtain parent domain\n", node->full_name);
+		return -ENXIO;
+	}
+
+	gpc_base = of_iomap(node, 0);
+	if (WARN_ON(!gpc_base))
+		return -ENOMEM;
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
+					  node, &imx_gpcv2_domain_ops,
+					  NULL);
+	if (!domain) {
+		iounmap(gpc_base);
+		return -ENOMEM;
+	}
+
+	/* Initially mask all interrupts */
+	for (i = 0; i < IMR_NUM; i++) {
+		writel_relaxed(~0, gpc_base + GPC_IMR1_CORE0 + i * 4);
+		writel_relaxed(~0, gpc_base + GPC_IMR1_CORE1 + i * 4);
+	}
+	/*
+	 * Due to hardware design requirement, need to make sure GPR
+	 * interrupt(#32) is unmasked during RUN mode to avoid entering
+	 * DSM by mistake.
+	 */
+	writel_relaxed(~0x1, gpc_base + GPC_IMR1_CORE0);
+
+	/* Read supported wakeup source in M/F domain */
+	if (cpu_is_imx7d()) {
+		of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0,
+			&gpcv2_mf_irqs[0]);
+		of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1,
+			&gpcv2_mf_irqs[1]);
+		of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2,
+			&gpcv2_mf_irqs[2]);
+		of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3,
+			&gpcv2_mf_irqs[3]);
+		if (!(gpcv2_mf_irqs[0] | gpcv2_mf_irqs[1] |
+			gpcv2_mf_irqs[2] | gpcv2_mf_irqs[3]))
+			pr_info("No wakeup source in Mega/Fast domain found!\n");
+	}
+
+	/* only external IRQs to wake up LPM and core 0/1 */
+	val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC);
+	val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP;
+	writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC);
+	/* mask m4 dsm trigger if M4 NOT enabled */
+	if (!imx_src_is_m4_enabled())
+		writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) |
+			BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4);
+	/* set mega/fast mix in A7 domain */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_MAPPING);
+	/* set SCU timing */
+	writel_relaxed((0x59 << 10) | 0x5B | (0x2 << 20),
+		gpc_base + GPC_PGC_SCU_TIMING);
+
+	/* set C0/C1 power up timming per design requirement */
+	val = readl_relaxed(gpc_base + GPC_PGC_C0_PUPSCR);
+	val &= ~BM_GPC_PGC_CORE_PUPSCR;
+	val |= (0x1A << 7);
+	writel_relaxed(val, gpc_base + GPC_PGC_C0_PUPSCR);
+
+	val = readl_relaxed(gpc_base + GPC_PGC_C1_PUPSCR);
+	val &= ~BM_GPC_PGC_CORE_PUPSCR;
+	val |= (0x1A << 7);
+	writel_relaxed(val, gpc_base + GPC_PGC_C1_PUPSCR);
+
+	writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK |
+		BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK,
+		gpc_base + GPC_PGC_ACK_SEL_A7);
+
+	val = readl_relaxed(gpc_base + GPC_SLPCR);
+	val &= ~(BM_SLPCR_EN_DSM);
+	if (!imx_src_is_m4_enabled())
+		val &= ~(BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN |
+			BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY);
+	val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE;
+	writel_relaxed(val, gpc_base + GPC_SLPCR);
+
+	if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
+		/* disable memory low power mode */
+		val = readl_relaxed(gpc_base + GPC_MLPCR);
+		val |= BM_GPC_MLPCR_MEMLP_CTL_DIS;
+		writel_relaxed(val, gpc_base + GPC_MLPCR);
+	}
+
+	/* disable RBC */
+	imx_gpcv2_enable_rbc(false);
+
+	/*
+	 * Clear the OF_POPULATED flag set in of_irq_init so that
+	 * later the GPC power domain driver will not be skipped.
+	 */
+	of_node_clear_flag(node, OF_POPULATED);
+
+	return 0;
+}
+
+/*
+ * We cannot use the IRQCHIP_DECLARE macro that lives in
+ * drivers/irqchip, so we're forced to roll our own. Not very nice.
+ */
+OF_DECLARE_2(irqchip, imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_init);
+
+void __init imx_gpcv2_check_dt(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc");
+	if (WARN_ON(!np))
+		return;
+
+	if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
+		pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+
+		/* map GPC, so that at least CPUidle and WARs keep working */
+		gpc_base = of_iomap(np, 0);
+	}
+}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/hardware.h
+++ linux-ein-5.4.0/arch/arm/mach-imx/hardware.h
@@ -81,13 +81,16 @@
  *	CCM	0x020c4000+0x004000	->	0xf42c4000+0x004000
  *	ANATOP	0x020c8000+0x004000	->	0xf42c8000+0x004000
  *	UART4	0x021f0000+0x004000	->	0xf42f0000+0x004000
+ * mx7d:
+ *     CCM     0x30380000+0x010000     ->      0xf5380000+0x010000
+ *     ANATOP  0x30360000+0x010000     ->      0xf5360000+0x010000
+ *     UART1   0x30860000+0x010000     ->      0xf5860000+0x010000
  */
 #define IMX_IO_P2V(x)	(						\
-			(((x) & 0x80000000) >> 7) |			\
 			(0xf4000000 +					\
-			(((x) & 0x50000000) >> 6) +			\
-			(((x) & 0x0b000000) >> 4) +			\
-			(((x) & 0x000fffff))))
+			(((x) & 0x50000000) >> 4) +			\
+			(((x) & 0x0a000000) >> 4) +			\
+			(((x) & 0x00ffffff))))
 
 #define IMX_IO_ADDRESS(x)	IOMEM(IMX_IO_P2V(x))
 
@@ -99,6 +102,7 @@
 #include "mx2x.h"
 #include "mx21.h"
 #include "mx27.h"
+#include "mx7.h"
 
 #define imx_map_entry(soc, name, _type)	{				\
 	.virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR),	\
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/headsmp.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/headsmp.S
@@ -21,6 +21,17 @@
 
 ENTRY(v7_secondary_startup)
 ARM_BE8(setend be)			@ go BE8 if entered LE
+	mrc	p15, 0, r0, c0, c0, 0
+	ldr	r1, =0xf00
+	orr	r1, r1, #0xff
+	mov	r0, r0, lsr #4
+	and	r0, r0, r1
+	/* 0xc07 is cortex A7's ID */
+	ldr	r1, =0xc00
+	orr	r1, r1, #0x7
+	cmp	r0, r1
+	beq	secondary_startup
+
 	set_diag_reg
 	b	secondary_startup
 ENDPROC(v7_secondary_startup)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/hotplug.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/hotplug.c
@@ -6,32 +6,12 @@
 
 #include <linux/errno.h>
 #include <linux/jiffies.h>
+#include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/proc-fns.h>
 
 #include "common.h"
 
-static inline void cpu_enter_lowpower(void)
-{
-	unsigned int v;
-
-	asm volatile(
-		"mcr	p15, 0, %1, c7, c5, 0\n"
-	"	mcr	p15, 0, %1, c7, c10, 4\n"
-	/*
-	 * Turn off coherency
-	 */
-	"	mrc	p15, 0, %0, c1, c0, 1\n"
-	"	bic	%0, %0, %3\n"
-	"	mcr	p15, 0, %0, c1, c0, 1\n"
-	"	mrc	p15, 0, %0, c1, c0, 0\n"
-	"	bic	%0, %0, %2\n"
-	"	mcr	p15, 0, %0, c1, c0, 0\n"
-	  : "=&r" (v)
-	  : "r" (0), "Ir" (CR_C), "Ir" (0x40)
-	  : "cc");
-}
-
 /*
  * platform-specific code to shutdown a CPU
  *
@@ -39,7 +19,7 @@
  */
 void imx_cpu_die(unsigned int cpu)
 {
-	cpu_enter_lowpower();
+	v7_exit_coherency_flush(louis);
 	/*
 	 * We use the cpu jumping argument register to sync with
 	 * imx_cpu_kill() which is running on cpu0 and waiting for
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/imx7d_low_power_idle.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/imx7d_low_power_idle.S
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+
+#define PM_INFO_VBASE_OFFSET			0x0
+#define PM_INFO_PBASE_OFFSET			0x4
+#define PM_INFO_RESUME_ADDR_OFFSET		0x8
+#define PM_INFO_PM_INFO_SIZE_OFFSET		0xc
+#define PM_INFO_PM_INFO_TTBR_OFFSET		0x10
+#define PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET	0x14
+#define PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET	0x18
+#define PM_INFO_VAL_OFFSET			0x1c
+#define PM_INFO_FLAG0_OFFSET			0x20
+#define PM_INFO_FLAG1_OFFSET			0x24
+#define PM_INFO_MX7D_DDRC_P_OFFSET		0x28
+#define PM_INFO_MX7D_DDRC_V_OFFSET		0x2c
+#define PM_INFO_MX7D_CCM_P_OFFSET		0x30
+#define PM_INFO_MX7D_CCM_V_OFFSET		0x34
+#define PM_INFO_MX7D_ANATOP_P_OFFSET		0x38
+#define PM_INFO_MX7D_ANATOP_V_OFFSET		0x3c
+#define PM_INFO_MX7D_SRC_P_OFFSET		0x40
+#define PM_INFO_MX7D_SRC_V_OFFSET		0x44
+#define PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET	0x48
+#define PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET	0x4c
+#define PM_INFO_MX7D_GPC_P_OFFSET		0x50
+#define PM_INFO_MX7D_GPC_V_OFFSET		0x54
+#define PM_INFO_MX7D_GIC_DIST_P_OFFSET		0x58
+#define PM_INFO_MX7D_GIC_DIST_V_OFFSET		0x5c
+
+#define MX7D_SRC_GPR1	0x74
+#define MX7D_SRC_GPR2	0x78
+#define MX7D_SRC_GPR3	0x7c
+#define MX7D_SRC_GPR4	0x80
+#define MX7D_GPC_IMR1	0x30
+#define MX7D_GPC_IMR2	0x34
+#define MX7D_GPC_IMR3	0x38
+#define MX7D_GPC_IMR4	0x3c
+#define DDRC_STAT	0x4
+#define DDRC_PWRCTL	0x30
+#define DDRC_DBG1	0x304
+#define DDRC_DBGCAM	0x308
+#define DDRC_PSTAT	0x3fc
+#define DDRC_PCTRL_0	0x490
+
+/*
+ * imx_pen_lock
+ *
+ * The reference link of Peterson's algorithm:
+ * http://en.wikipedia.org/wiki/Peterson's_algorithm
+ *
+ * val1 = r1 = !turn (inverted from Peterson's algorithm)
+ * on cpu 0:
+ * r2 = flag[0] (in flag0)
+ * r3 = flag[1] (in flag1)
+ * on cpu1:
+ * r2 = flag[1] (in flag1)
+ * r3 = flag[0] (in flag0)
+ *
+ */
+	.macro	imx_pen_lock
+
+	mov	r8, r0
+	mrc	p15, 0, r5, c0, c0, 5
+	and	r5, r5, #3
+	add	r6, r8, #PM_INFO_VAL_OFFSET
+	cmp	r5, #0
+	addeq	r7, r8, #PM_INFO_FLAG0_OFFSET
+	addeq	r8, r8, #PM_INFO_FLAG1_OFFSET
+	addne	r7, r8, #PM_INFO_FLAG1_OFFSET
+	addne	r8, r8, #PM_INFO_FLAG0_OFFSET
+
+	mov	r9, #1
+	str	r9, [r7]
+	dsb
+	str	r5, [r6]
+1:
+	dsb
+	ldr	r9, [r8]
+	cmp	r9, #1
+	ldreq	r9, [r6]
+	cmpeq	r9, r5
+	beq	1b
+
+	.endm
+
+	.macro	imx_pen_unlock
+
+	dsb
+	mrc	p15, 0, r6, c0, c0, 5
+	and	r6, r6, #3
+	cmp	r6, #0
+	addeq	r7, r0, #PM_INFO_FLAG0_OFFSET
+	addne	r7, r0, #PM_INFO_FLAG1_OFFSET
+	mov	r9, #0
+	str	r9, [r7]
+
+	.endm
+
+	.macro  disable_l1_dcache
+
+	push	{r0 - r12, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r12, lr}
+
+	/* disable d-cache */
+	mrc	p15, 0, r7, c1, c0, 0
+	bic	r7, r7, #(1 << 2)
+	mcr	p15, 0, r7, c1, c0, 0
+	dsb
+	isb
+
+	push	{r0 - r12, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r12, lr}
+
+#ifdef CONFIG_SMP
+	clrex
+
+	/* Turn off SMP bit. */
+	mrc	p15, 0, r8, c1, c0, 1
+	bic	r8, r8, #0x40
+	mcr	p15, 0, r8, c1, c0, 1
+
+	isb
+	dsb
+#endif
+
+	.endm
+
+	.macro	tlb_set_to_ocram
+
+	/* save ttbr */
+	mrc	p15, 0, r7, c2, c0, 1
+	str	r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
+
+	/*
+	 * To ensure no page table walks occur in DDR, we
+	 * have a another page table stored in IRAM that only
+	 * contains entries pointing to IRAM, AIPS1 and AIPS2.
+	 * We need to set the TTBR1 to the new IRAM TLB.
+	 * Do the following steps:
+	 * 1. Flush the Branch Target Address Cache (BTAC)
+	 * 2. Set TTBR1 to point to IRAM page table.
+	 * 3. Disable page table walks in TTBR0 (PD0 = 1)
+	 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
+	 *     and 2-4G is translated by TTBR1.
+	 */
+
+	/* Disable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	bic	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the BTAC. */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	ldr	r6, =iram_tlb_phys_addr
+	ldr	r7, [r6]
+
+	dsb
+	isb
+
+	/* Store the IRAM table in TTBR1 */
+	mcr	p15, 0, r7, c2, c0, 1
+
+	/* Read TTBCR and set PD0=1, N = 1 */
+	mrc	p15, 0, r6, c2, c0, 2
+	orr	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	.endm
+
+	.macro	tlb_back_to_ddr
+
+	/* Read TTBCR and set PD0=0, N = 0 */
+	mrc	p15, 0, r6, c2, c0, 2
+	bic	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	/* Enable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	/* restore ttbr */
+	ldr	r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
+	mcr	p15, 0, r7, c2, c0, 1
+
+	.endm
+
+	/* r10 must be DDRC base address */
+	.macro ddrc_enter_self_refresh
+
+	ldr	r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET]
+
+	/* disable port */
+	ldr	r7, =0x0
+	str	r7, [r10, #DDRC_PCTRL_0]
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r10, #DDRC_PWRCTL]
+
+	/* wait rw port_busy clear */
+	ldr	r6, =(0x1 << 16)
+	orr	r6, r6, #0x1
+2:
+	ldr	r7, [r10, #DDRC_PSTAT]
+	ands	r7, r7, r6
+	bne	2b
+
+	ldr	r7, =0x1
+	str	r7, [r10, #DDRC_DBG1]
+
+	ldr	r6, =0x36000000
+11:
+	ldr	r7, [r10, #DDRC_DBGCAM]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	11b
+
+	/* enter self-refresh bit 5 */
+	ldr	r7, =(0x1 << 5)
+	str	r7, [r10, #DDRC_PWRCTL]
+
+	/* wait until self-refresh mode entered */
+3:
+	ldr	r7, [r10, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	bne	3b
+4:
+	ldr	r7, [r10, #DDRC_STAT]
+	ands	r7, r7, #0x20
+	beq	4b
+
+	/* disable dram clk */
+	ldr	r7, [r10, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 3)
+	str	r7, [r10, #DDRC_PWRCTL]
+
+	/*
+	 * TO1.1 adds feature of DDR pads power down,
+	 * although TO1.0 has no such function, but it is
+	 * NOT harmful to program GPR registers for TO1.0,
+	 * it can avoid the logic of version check in idle
+	 * thread.
+	 */
+	ldr	r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET]
+	ldr	r7, =0xf0000
+	str	r7, [r10]
+
+	/* delay 20us, measured by gpio */
+	ldr	r7, =20
+12:
+	subs	r7, r7, #0x1
+	bne	12b
+
+	.endm
+
+	/* r10 must be DDRC base address */
+	.macro ddrc_exit_self_refresh
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET]
+
+	ldr	r7, =0x0
+	str	r7, [r10]
+
+	ldr	r7, =20
+13:
+	subs	r7, r7, #0x1
+	bne	13b
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_DDRC_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET]
+
+	ldr	r7, =0x0
+	str	r7, [r10, #DDRC_DBG1]
+
+	ldr	r6, =0x30000000
+14:
+	ldr	r7, [r10, #DDRC_DBGCAM]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	14b
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r10, #DDRC_PWRCTL]
+
+	/* wait until self-refresh mode exited */
+5:
+	ldr	r7, [r10, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	beq	5b
+
+	/* enable auto self-refresh */
+	ldr	r7, [r10, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r10, #DDRC_PWRCTL]
+
+	ldr	r7, =0x1
+	str	r7, [r10, #DDRC_PCTRL_0]
+
+	.endm
+
+	.macro	pll_do_wait_lock
+6:
+	ldr	r7, [r10, r8]
+	ands	r7, #0x80000000
+	beq	6b
+
+	.endm
+
+	.macro ccm_enter_idle
+
+	ldr	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* ungate pfd1 332m for lower axi */
+	ldr	r7, =0x8000
+	str	r7, [r10, #0xc8]
+
+	ldr	r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET]
+
+	/* switch ARM CLK to OSC */
+	ldr	r8, =0x8000
+	ldr	r7, [r10, r8]
+	bic	r7, r7, #0x7000000
+	str	r7, [r10, r8]
+
+	/* lower AXI clk from 24MHz to 3MHz */
+	ldr	r8, =0x8800
+	ldr	r7, [r10, r8]
+	orr	r7, r7, #0x7
+	str	r7, [r10, r8]
+
+	/* lower AHB clk from 24MHz to 3MHz */
+	ldr	r8, =0x9000
+	ldr	r7, [r10, r8]
+	orr	r7, r7, #0x7
+	str	r7, [r10, r8]
+
+	/* gate dram clk */
+	ldr	r8, =0x9880
+	ldr	r7, [r10, r8]
+	bic	r7, r7, #0x10000000
+	str	r7, [r10, r8]
+
+	ldr	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* gate pfd1 332m */
+	ldr	r7, =0x8000
+	str	r7, [r10, #0xc4]
+
+	/* gate system pll pfd div 1 */
+	ldr	r7, =0x10
+	str	r7, [r10, #0xb4]
+	/* power down ARM, 480 and DRAM PLL */
+	ldr	r7, =0x1000
+	str	r7, [r10, #0x64]
+	str	r7, [r10, #0xb4]
+	ldr	r7, =0x100000
+	str	r7, [r10, #0x74]
+
+	.endm
+
+	.macro ccm_exit_idle
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* power up ARM, 480 and DRAM PLL */
+	ldr	r7, =0x1000
+	str	r7, [r10, #0x68]
+	ldr	r8, =0x60
+	pll_do_wait_lock
+
+	ldr	r7, =0x1000
+	str	r7, [r10, #0xb8]
+	ldr	r8, =0xb0
+	pll_do_wait_lock
+
+	ldr	r7, =0x100000
+	str	r7, [r10, #0x78]
+	ldr	r8, =0x70
+	pll_do_wait_lock
+
+	/* ungate pfd1 332m for lower axi */
+	ldr	r7, =0x8000
+	str	r7, [r10, #0xc8]
+
+	/* ungate system pll pfd div 1 */
+	ldr	r7, =0x10
+	str	r7, [r10, #0xb8]
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_CCM_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET]
+
+	/* switch ARM CLK to PLL */
+	ldr	r8, =0x8000
+	ldr	r7, [r10, r8]
+	orr	r7, r7, #0x1000000
+	str	r7, [r10, r8]
+
+	/* restore AXI clk from 3MHz to 24MHz */
+	ldr	r8, =0x8800
+	ldr	r7, [r10, r8]
+	bic	r7, r7, #0x7
+	str	r7, [r10, r8]
+
+	/* restore AHB clk from 3MHz to 24MHz */
+	ldr	r8, =0x9000
+	ldr	r7, [r10, r8]
+	bic	r7, r7, #0x7
+	str	r7, [r10, r8]
+
+	/* ungate dram clk */
+	ldr	r8, =0x9880
+	ldr	r7, [r10, r8]
+	orr	r7, r7, #0x10000000
+	str	r7, [r10, r8]
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* gate pfd1 332m for lower axi */
+	ldr	r7, =0x8000
+	str	r7, [r10, #0xc4]
+
+	.endm
+
+	.macro anatop_enter_idle
+
+	ldr	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* XTAL to RC-OSC switch */
+	ldr	r7, [r10]
+	orr	r7, r7, #0x1000
+	str	r7, [r10]
+	/* power down XTAL */
+	ldr	r7, [r10]
+	orr	r7, r7, #0x1
+	str	r7, [r10]
+
+	/* enable weak 1P0A */
+	ldr	r7, [r10, #0x200]
+	orr	r7, r7, #0x40000
+	str	r7, [r10, #0x200]
+
+	/* disable LDO 1P0A */
+	ldr	r7, [r10, #0x200]
+	bic	r7, r7, #0x1
+	str	r7, [r10, #0x200]
+
+	/* disable LDO 1P0D */
+	ldr	r7, [r10, #0x210]
+	bic	r7, r7, #0x1
+	str	r7, [r10, #0x210]
+
+	/* disable LDO 1P2 */
+	ldr	r7, [r10, #0x220]
+	bic	r7, r7, #0x1
+	str	r7, [r10, #0x220]
+
+	/* switch to low power bandgap */
+	ldr	r7, [r10, #0x270]
+	orr	r7, r7, #0x400
+	str	r7, [r10, #0x270]
+	/* power down normal bandgap */
+	orr	r7, r7, #0x1
+	str	r7, [r10, #0x270]
+
+	.endm
+
+	.macro anatop_exit_idle
+
+	cmp	r5, #0x1
+	ldreq	r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
+
+	/* power on normal bandgap */
+	ldr	r7, [r10, #0x270]
+	bic	r7, r7, #0x1
+	str	r7, [r10, #0x270]
+	/* switch to normal bandgap */
+	bic	r7, r7, #0x400
+	str	r7, [r10, #0x270]
+
+	/* enable LDO 1P2 */
+	ldr	r7, [r10, #0x220]
+	orr	r7, r7, #0x1
+	str	r7, [r10, #0x220]
+7:
+	ldr	r7, [r10, #0x220]
+	ands	r7, #0x20000
+	beq	7b
+
+	/* enable LDO 1P0D */
+	ldr	r7, [r10, #0x210]
+	orr	r7, r7, #0x1
+	str	r7, [r10, #0x210]
+8:
+	ldr	r7, [r10, #0x210]
+	ands	r7, #0x20000
+	beq	8b
+
+	/* enable LDO 1P0A */
+	ldr	r7, [r10, #0x200]
+	orr	r7, r7, #0x1
+	str	r7, [r10, #0x200]
+9:
+	ldr	r7, [r10, #0x200]
+	ands	r7, #0x20000
+	beq	9b
+	/* disable weak 1P0A */
+	ldr	r7, [r10, #0x200]
+	bic	r7, r7, #0x40000
+	str	r7, [r10, #0x200]
+
+	/* power up XTAL and wait */
+	ldr	r7, [r10]
+	bic	r7, r7, #0x1
+	str	r7, [r10]
+10:
+	ldr	r7, [r10]
+	ands	r7, r7, #0x4
+	beq	10b
+	/* RC-OSC to XTAL switch */
+	ldr	r7, [r10]
+	bic	r7, r7, #0x1000
+	str	r7, [r10]
+
+	.endm
+
+.extern iram_tlb_phys_addr
+
+	.align 3
+ENTRY(imx7d_low_power_idle)
+	push	{r0 - r12}
+
+	/* get necessary info from pm_info */
+	ldr	r1, [r0, #PM_INFO_PBASE_OFFSET]
+	ldr	r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
+
+	/*
+	 * counting the resume address in iram
+	 * to set it in SRC register.
+	 */
+	ldr	r5, =imx7d_low_power_idle
+	ldr     r6, =wakeup
+	sub	r6, r6, r5
+	add     r8, r1, r2
+	add	r3, r8, r6
+
+	/* r11 is cpu id */
+	mrc	p15, 0, r11, c0, c0, 5
+	and	r11, r11, #3
+	cmp	r11, #0x0
+	ldreq	r6, =MX7D_SRC_GPR1
+	ldreq	r7, =MX7D_SRC_GPR2
+	ldrne	r6, =MX7D_SRC_GPR3
+	ldrne	r7, =MX7D_SRC_GPR4
+	/* store physical resume addr and pm_info address. */
+	ldr	r10, [r0, #PM_INFO_MX7D_SRC_V_OFFSET]
+	str	r3, [r10, r6]
+	str	r1, [r10, r7]
+
+	disable_l1_dcache
+
+	tlb_set_to_ocram
+
+	/* check last to sleep */
+	ldr	r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
+	ldr	r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
+	cmp	r6, r7
+	bne	lpi_enter_done
+
+	ddrc_enter_self_refresh
+	ccm_enter_idle
+	anatop_enter_idle
+
+	ldr	r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET]
+	ldr	r7, =0x0
+	ldr	r8, =0x1000
+	str	r7, [r10, r8]
+
+	ldr	r10, [r0, #PM_INFO_MX7D_GPC_V_OFFSET]
+	ldr	r4, [r10, #MX7D_GPC_IMR1]
+	ldr	r5, [r10, #MX7D_GPC_IMR2]
+	ldr	r6, [r10, #MX7D_GPC_IMR3]
+	ldr	r7, [r10, #MX7D_GPC_IMR4]
+
+	ldr	r8, =0xffffffff
+	str	r8, [r10, #MX7D_GPC_IMR1]
+	str	r8, [r10, #MX7D_GPC_IMR2]
+	str	r8, [r10, #MX7D_GPC_IMR3]
+	str	r8, [r10, #MX7D_GPC_IMR4]
+
+	/*
+	 * enable the RBC bypass counter here
+	 * to hold off the interrupts. RBC counter
+	 * = 8 (240us). With this setting, the latency
+	 * from wakeup interrupt to ARM power up
+	 * is ~250uS.
+	 */
+	ldr	r8, [r10, #0x14]
+	bic	r8, r8, #(0x3f << 24)
+	orr	r8, r8, #(0x8 << 24)
+	str	r8, [r10, #0x14]
+
+	/* enable the counter. */
+	ldr	r8, [r10, #0x14]
+	orr	r8, r8, #(0x1 << 30)
+	str	r8, [r10, #0x14]
+
+	/* unmask all the GPC interrupts. */
+	str	r4, [r10, #MX7D_GPC_IMR1]
+	str	r5, [r10, #MX7D_GPC_IMR2]
+	str	r6, [r10, #MX7D_GPC_IMR3]
+	str	r7, [r10, #MX7D_GPC_IMR4]
+
+	/*
+	 * now delay for a short while (30usec)
+	 * ARM is at 24MHz at this point
+	 * so a short loop should be enough.
+	 * this delay is required to ensure that
+	 * the RBC counter can start counting in
+	 * case an interrupt is already pending
+	 * or in case an interrupt arrives just
+	 * as ARM is about to assert DSM_request.
+	 */
+	ldr	r4, =5
+rbc_loop:
+	subs	r4, r4, #0x1
+	bne	rbc_loop
+
+lpi_enter_done:
+
+	imx_pen_unlock
+
+	wfi
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	imx_pen_lock
+
+	/* check first to wake */
+	ldr	r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
+	ldr	r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
+	cmp	r6, r7
+	bne	skip_lpi_flow
+
+	ldr	r5, =0x0
+	anatop_exit_idle
+	ccm_exit_idle
+	ddrc_exit_self_refresh
+
+	ldr	r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET]
+	ldr	r7, =0x1
+	ldr	r8, =0x1000
+	str	r7, [r10, r8]
+
+skip_lpi_flow:
+	tlb_back_to_ddr
+
+#ifdef CONFIG_SMP
+	/* Turn on SMP bit. */
+	mrc	p15, 0, r7, c1, c0, 1
+	orr	r7, r7, #0x40
+	mcr	p15, 0, r7, c1, c0, 1
+
+	isb
+#endif
+
+	/* enable d-cache */
+	mrc	p15, 0, r7, c1, c0, 0
+	orr	r7, r7, #(1 << 2)
+	mcr	p15, 0, r7, c1, c0, 0
+	dsb
+	isb
+
+	/* Restore registers */
+	pop	{r0 - r12}
+	mov	pc, lr
+
+wakeup:
+
+	/* invalidate L1 I-cache first */
+	mov	r1, #0x0
+	mcr	p15, 0, r1, c7, c5, 0
+	mcr	p15, 0, r1, c7, c5, 0
+	mcr	p15, 0, r1, c7, c5, 6
+	/* enable the Icache and branch prediction */
+	mov	r1, #0x1800
+	mcr	p15, 0, r1, c1, c0, 0
+	isb
+
+	imx_pen_lock
+
+	/* check first to wake */
+	ldr	r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
+	ldr	r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
+	cmp	r6, r7
+	bne	wakeup_skip_lpi_flow
+
+	ldr	r5, =0x1
+	anatop_exit_idle
+	ccm_exit_idle
+	ddrc_exit_self_refresh
+
+wakeup_skip_lpi_flow:
+	/* get physical resume address from pm_info. */
+	ldr	lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
+
+	/* Restore registers */
+	mov	pc, lr
+	.ltorg
+ENDPROC(imx7d_low_power_idle)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/lpddr3_freq_imx.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/lpddr3_freq_imx.S
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include "hardware.h"
+
+#define DDRC_MSTR		0x0
+#define DDRC_STAT		0x4
+#define DDRC_PWRCTL		0x30
+#define DDRC_RFSHTMG		0x64
+#define DDRC_DBG1		0x304
+#define DDRC_PSTAT		0x3fc
+#define DDRC_PCTRL_0		0x490
+#define DDRC_DFIMISC		0x1b0
+#define DDRC_DBGCAM		0x308
+#define DDRC_SWCTL		0x320
+#define DDRC_SWSTAT		0x324
+#define DDRPHY_LP_CON0		0x18
+#define IOMUXC_GPR8		0x20
+#define DDRPHY_PHY_CON1		0x4
+#define DDRPHY_MDLL_CON0	0xb0
+#define DDRPHY_MDLL_CON1	0xb4
+#define DDRPHY_OFFSETD_CON0	0x50
+#define DDRPHY_OFFSETR_CON0	0x20
+#define DDRPHY_OFFSETR_CON1	0x24
+#define DDRPHY_OFFSETR_CON2	0x28
+#define DDRPHY_OFFSETW_CON0	0x30
+#define DDRPHY_OFFSETW_CON1	0x34
+#define DDRPHY_OFFSETW_CON2	0x38
+#define DDRPHY_RFSHTMG		0x64
+#define DDRPHY_CA_WLDSKEW_CON0	0x6c
+#define DDRPHY_CA_DSKEW_CON0	0x7c
+#define DDRPHY_CA_DSKEW_CON1	0x80
+#define DDRPHY_CA_DSKEW_CON2	0x84
+
+#define ANADIG_DIGPROG		0x800
+
+	.align 3
+
+	.macro	ddrc_prepare
+
+	/* disable port */
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_PCTRL_0]
+
+	/* wait port busy done */
+	ldr	r6, =0x10001
+1:
+	ldr	r7, [r4, #DDRC_PSTAT]
+	and	r7, r7, r6
+	cmp	r7, #0
+	bne	1b
+
+	ldr	r7, =0x20
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x23
+2:
+	ldr	r7, [r4, #DDRC_STAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	2b
+
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_DBG1]
+
+	ldr	r6, =0x30000000
+3:
+	ldr	r7, [r4, #DDRC_DBGCAM]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	3b
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_SWCTL]
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_DFIMISC]
+
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_SWCTL]
+
+	ldr	r6, =0x1
+4:
+	ldr	r7, [r4, #DDRC_SWSTAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	4b
+
+	.endm
+
+	.macro	ddrc_done
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	ldr	r6, =0x3
+5:
+	ldr	r7, [r4, #DDRC_STAT]
+	and	r7, r7, r6
+	cmp	r7, r6
+	beq	5b
+
+	ldr	r7, =0x0
+	str	r7, [r4, #DDRC_DBG1]
+
+	ldr	r7, =0x1
+	str	r7, [r4, #DDRC_PCTRL_0]
+
+	/* enable auto self-refresh */
+	ldr	r7, [r4, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r4, #DDRC_PWRCTL]
+
+	.endm
+
+	.macro	switch_to_below_100m
+
+	/* LPDDR2 and LPDDR3 has different setting */
+	ldr	r8, [r4, #DDRC_MSTR]
+	ands	r8, r8, #0x4
+	bne	9f
+
+	/* LPDDR3 */
+	ldr	r7, =0x00000100
+	str	r7, [r5, #DDRPHY_PHY_CON1]
+	b	10f
+9:
+	/* LPDDR2 */
+	ldr	r7, =0x10010100
+	str	r7, [r5, #DDRPHY_PHY_CON1]
+10:
+	ldr	r6, =24000000
+	cmp	r0, r6
+	beq	16f
+
+	ldr	r7, =0x0005000B
+	str	r7, [r4, #DDRC_RFSHTMG]
+	b	6f
+16:
+	ldr	r7, =0x00010003
+	str	r7, [r4, #DDRC_RFSHTMG]
+
+	/* dram alt sel set to OSC */
+	ldr	r7, =0x10000000
+	ldr	r8, =0xa080
+	str	r7, [r2, r8]
+	/* dram root set to from dram alt, div by 1 */
+	ldr	r7, =0x11000000
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+	b	7f
+
+6:
+	/* dram alt sel set to pfd0_392m */
+	ldr	r7, =0x15000000
+	ldr	r8, =0xa080
+	str	r7, [r2, r8]
+	/* dram root set to from dram alt, div by 4 */
+	ldr	r7, =0x11000003
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+7:
+	ldr	r7, =0x202ffd0
+	str	r7, [r5, #DDRPHY_MDLL_CON0]
+
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r7, =0x7f7f7f7f
+	str	r7, [r5, #DDRPHY_OFFSETR_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETR_CON1]
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETR_CON2]
+
+	ldr	r7, =0x7f7f7f7f
+	str	r7, [r5, #DDRPHY_OFFSETW_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETW_CON1]
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETW_CON2]
+
+	ldr	r7, [r9, #ANADIG_DIGPROG]
+	and	r7, r7, #0x11
+	cmp	r7, #0x11
+	bne	11f
+
+	ldr	r7, =0x0
+	str	r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
+	ldr	r7, =0x60606060
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x00006060
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+	b	12f
+11:
+	ldr	r7, =0x0
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+12:
+	ldr	r7, =0x100007f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+	ldr	r7, =0x7f
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	.endm
+
+	.macro	switch_to_533m
+
+	ldr	r7, =0x10210100
+	str	r7, [r5, #DDRPHY_PHY_CON1]
+
+	ldr	r7, =0x00200038
+	str	r7, [r4, #DDRC_RFSHTMG]
+
+	/* dram root set to from dram main, div by 2 */
+	ldr	r7, =0x10000001
+	ldr	r8, =0x9880
+	str	r7, [r2, r8]
+
+	ldr	r7, =0x1010007e
+	str	r7, [r5, #DDRPHY_MDLL_CON0]
+
+	ldr	r7, =0x10000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_OFFSETR_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETR_CON1]
+	ldr	r7, =0x8
+	str	r7, [r5, #DDRPHY_OFFSETR_CON2]
+
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_OFFSETW_CON0]
+	str	r7, [r5, #DDRPHY_OFFSETW_CON1]
+	ldr	r7, =0x8
+	str	r7, [r5, #DDRPHY_OFFSETW_CON2]
+
+	/* LPDDR2 and LPDDR3 has different setting */
+	ldr	r8, [r4, #DDRC_MSTR]
+	ands	r8, r8, #0x4
+	beq	15f
+
+	ldr	r7, [r9, #ANADIG_DIGPROG]
+	and	r7, r7, #0x11
+	cmp	r7, #0x11
+	bne	14f
+
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x0a0a0808
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+	ldr	r7, =0x0a0a0a0a
+	str	r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
+	b	14f
+15:
+	ldr	r7, [r9, #ANADIG_DIGPROG]
+	and	r7, r7, #0x11
+	cmp	r7, #0x11
+	bne	13f
+
+	ldr	r7, =0x1c1c1c1c
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x30301c1c
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+	ldr	r7, =0x30303030
+	str	r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
+	b	14f
+13:
+	ldr	r7, =0x08080808
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON0]
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON1]
+	ldr	r7, =0x0808
+	str	r7, [r5, #DDRPHY_CA_DSKEW_CON2]
+14:
+	ldr	r7, =0x11000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+	ldr	r7, =0x10000008
+	str	r7, [r5, #DDRPHY_OFFSETD_CON0]
+
+	ldr	r6, =0x4
+8:
+	ldr	r7, [r5, #DDRPHY_MDLL_CON1]
+	and	r7, r7, r6
+	cmp	r7, r6
+	bne	8b
+
+	.endm
+
+ENTRY(imx_lpddr3_freq_change)
+	push	{r2 - r9}
+
+	/*
+	 * To ensure no page table walks occur in DDR, we
+	 * have a another page table stored in IRAM that only
+	 * contains entries pointing to IRAM, AIPS1 and AIPS2.
+	 * We need to set the TTBR1 to the new IRAM TLB.
+	 * Do the following steps:
+	 * 1. Flush the Branch Target Address Cache (BTAC)
+	 * 2. Set TTBR1 to point to IRAM page table.
+	 * 3. Disable page table walks in TTBR0 (PD0 = 1)
+	 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
+	 *     and 2-4G is translated by TTBR1.
+	 */
+
+	ldr	r6, =iram_tlb_phys_addr
+	ldr	r7, [r6]
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	/* Disable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	bic	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	dsb
+	isb
+	/* Store the IRAM table in TTBR1 */
+	mcr	p15, 0, r7, c2, c0, 1
+
+	/* Read TTBCR and set PD0=1, N = 1 */
+	mrc	p15, 0, r6, c2, c0, 2
+	orr	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	/* Disable L1 data cache. */
+	mrc	p15, 0, r6, c1, c0, 0
+	bic	r6, r6, #0x4
+	mcr	p15, 0, r6, c1, c0, 0
+
+	dsb
+	isb
+
+	ldr	r2, =IMX_IO_P2V(MX7D_CCM_BASE_ADDR)
+	ldr	r3, =IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR)
+	ldr	r4, =IMX_IO_P2V(MX7D_DDRC_BASE_ADDR)
+	ldr	r5, =IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR)
+	ldr	r9, =IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR)
+
+	ddrc_prepare
+
+	ldr	r6, =100000000
+	cmp	r0, r6
+	bgt	set_to_533m
+
+set_to_below_100m:
+	switch_to_below_100m
+	b	done
+
+set_to_533m:
+	switch_to_533m
+	b	done
+
+done:
+	ddrc_done
+
+	/* Enable L1 data cache. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x4
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Restore the TTBCR */
+	dsb
+	isb
+
+	/* Read TTBCR and set PD0=0, N = 0 */
+	mrc	p15, 0, r6, c2, c0, 2
+	bic	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	dsb
+	isb
+
+	/* Enable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	/* Restore registers */
+	pop	{r2 - r9}
+	mov	pc, lr
+ENDPROC(imx_lpddr3_freq_change)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx6q.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx6q.c
@@ -5,29 +5,16 @@
  */
 
 #include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/cpu.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/irqchip.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/of_platform.h>
-#include <linux/pm_opp.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
-#include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/micrel_phy.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <asm/system_misc.h>
 
 #include "common.h"
 #include "cpuidle.h"
@@ -258,21 +245,20 @@
 
 static void __init imx6q_init_machine(void)
 {
-	struct device *parent;
-
-	if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)
-		imx_print_silicon_rev("i.MX6QP", IMX_CHIP_REVISION_1_0);
+	if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0)
+		/*
+		 * SoCs that identify as i.MX6Q >= rev 2.0 are really i.MX6QP.
+		 * Quirk: i.MX6QP revision = i.MX6Q revision - (1, 0),
+		 * e.g. i.MX6QP rev 1.1 identifies as i.MX6Q rev 2.1.
+		 */
+		imx_print_silicon_rev("i.MX6QP", imx_get_soc_revision() - 0x10);
 	else
 		imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
 				imx_get_soc_revision());
 
-	parent = imx_soc_device_init();
-	if (parent == NULL)
-		pr_warn("failed to initialize soc device\n");
-
 	imx6q_enet_phy_init();
 
-	of_platform_default_populate(NULL, NULL, parent);
+	of_platform_default_populate(NULL, NULL, NULL);
 
 	imx_anatop_init();
 	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx6sl.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx6sl.c
@@ -4,7 +4,6 @@
  */
 
 #include <linux/irqchip.h>
-#include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -46,13 +45,7 @@
 
 static void __init imx6sl_init_machine(void)
 {
-	struct device *parent;
-
-	parent = imx_soc_device_init();
-	if (parent == NULL)
-		pr_warn("failed to initialize soc device\n");
-
-	of_platform_default_populate(NULL, NULL, parent);
+	of_platform_default_populate(NULL, NULL, NULL);
 
 	if (cpu_is_imx6sl())
 		imx6sl_fec_init();
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx6sx.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx6sx.c
@@ -63,13 +63,7 @@
 
 static void __init imx6sx_init_machine(void)
 {
-	struct device *parent;
-
-	parent = imx_soc_device_init();
-	if (parent == NULL)
-		pr_warn("failed to initialize soc device\n");
-
-	of_platform_default_populate(NULL, NULL, parent);
+	of_platform_default_populate(NULL, NULL, NULL);
 
 	imx6sx_enet_init();
 	imx_anatop_init();
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx6ul.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx6ul.c
@@ -14,6 +14,7 @@
 
 #include "common.h"
 #include "cpuidle.h"
+#include "hardware.h"
 
 static void __init imx6ul_enet_clk_init(void)
 {
@@ -25,7 +26,6 @@
 				   IMX6UL_GPR1_ENET_CLK_OUTPUT);
 	else
 		pr_err("failed to find fsl,imx6ul-iomux-gpr regmap\n");
-
 }
 
 static int ksz8081_phy_fixup(struct phy_device *dev)
@@ -56,13 +56,10 @@
 
 static void __init imx6ul_init_machine(void)
 {
-	struct device *parent;
-
-	parent = imx_soc_device_init();
-	if (parent == NULL)
-		pr_warn("failed to initialize soc device\n");
+	imx_print_silicon_rev(cpu_is_imx6ull() ? "i.MX6ULL" : "i.MX6UL",
+		imx_get_soc_revision());
 
-	of_platform_default_populate(NULL, NULL, parent);
+	of_platform_default_populate(NULL, NULL, NULL);
 	imx6ul_enet_init();
 	imx_anatop_init();
 	imx6ul_pm_init();
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx7d.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx7d.c
@@ -13,6 +13,13 @@
 #include <asm/mach/map.h>
 
 #include "common.h"
+#include "cpuidle.h"
+
+static struct property device_disabled = {
+	.name = "status",
+	.length = sizeof("disabled"),
+	.value = "disabled",
+};
 
 static int ar8031_phy_fixup(struct phy_device *dev)
 {
@@ -76,29 +83,48 @@
 	imx7d_enet_clk_sel();
 }
 
-static void __init imx7d_init_machine(void)
+static inline void imx7d_disable_arm_arch_timer(void)
 {
-	struct device *parent;
+	struct device_node *node;
 
-	parent = imx_soc_device_init();
-	if (parent == NULL)
-		pr_warn("failed to initialize soc device\n");
+	node = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
+	if (node) {
+		pr_info("disable arm arch timer for nosmp!\n");
+		of_add_property(node, &device_disabled);
+	}
+}
 
+static void __init imx7d_init_machine(void)
+{
 	imx_anatop_init();
+	of_platform_default_populate(NULL, NULL, NULL);
+	imx7d_pm_init();
 	imx7d_enet_init();
 }
 
 static void __init imx7d_init_late(void)
 {
+	imx7d_cpuidle_init();
 	if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
 		platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
 }
 
 static void __init imx7d_init_irq(void)
 {
+	imx_gpcv2_check_dt();
 	imx_init_revision_from_anatop();
 	imx_src_init();
 	irqchip_init();
+#ifndef CONFIG_SMP
+	imx7d_disable_arm_arch_timer();
+#endif
+}
+
+static void __init imx7d_map_io(void)
+{
+	debug_ll_io_init();
+	imx7_pm_map_io();
+	imx_busfreq_map_io();
 }
 
 static const char *const imx7d_dt_compat[] __initconst = {
@@ -108,6 +134,8 @@
 };
 
 DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
+	.map_io         = imx7d_map_io,
+	.smp            = smp_ops(imx_smp_ops),
 	.init_irq	= imx7d_init_irq,
 	.init_machine	= imx7d_init_machine,
 	.init_late      = imx7d_init_late,
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-imx7ulp.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-imx7ulp.c
@@ -37,6 +37,7 @@
 	 * bit[31:28] of JTAG_ID register defines revision as below from B0:
 	 * 0001        B0
 	 * 0010        B1
+	 * 0011        B2
 	 */
 	switch (revision >> 28) {
 	case 1:
@@ -45,6 +46,9 @@
 	case 2:
 		imx_set_soc_revision(IMX_CHIP_REVISION_2_1);
 		break;
+	case 3:
+		imx_set_soc_revision(IMX_CHIP_REVISION_2_2);
+		break;
 	default:
 		imx_set_soc_revision(IMX_CHIP_REVISION_1_0);
 		break;
@@ -57,7 +61,7 @@
 
 	mxc_set_cpu_type(MXC_CPU_IMX7ULP);
 	imx7ulp_set_revision();
-	of_platform_default_populate(NULL, NULL, imx_soc_device_init());
+	of_platform_default_populate(NULL, NULL, NULL);
 }
 
 static const char *const imx7ulp_dt_compat[] __initconst = {
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mach-vf610.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mach-vf610.c
@@ -3,11 +3,57 @@
  * Copyright 2012-2013 Freescale Semiconductor, Inc.
  */
 
+#include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/io.h>
+
 #include <linux/irqchip.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/cache-l2x0.h>
 
+#include "common.h"
+#include "hardware.h"
+
+#define MSCM_CPxCOUNT		0x00c
+#define MSCM_CPxCFG1		0x014
+
+static void __init vf610_detect_cpu(void)
+{
+	struct device_node *np;
+	u32 cpxcount, cpxcfg1;
+	unsigned int cpu_type;
+	void __iomem *mscm;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,vf610-mscm-cpucfg");
+	if (WARN_ON(!np))
+		return;
+
+	mscm = of_iomap(np, 0);
+	of_node_put(np);
+
+	if (WARN_ON(!mscm))
+		return;
+
+	cpxcount = readl_relaxed(mscm + MSCM_CPxCOUNT);
+	cpxcfg1  = readl_relaxed(mscm + MSCM_CPxCFG1);
+
+	iounmap(mscm);
+
+	cpu_type = cpxcount ? MXC_CPU_VF600 : MXC_CPU_VF500;
+
+	if (cpxcfg1)
+		cpu_type |= MXC_CPU_VFx10;
+
+	mxc_set_cpu_type(cpu_type);
+}
+
+static void __init vf610_init_machine(void)
+{
+	vf610_detect_cpu();
+
+	of_platform_default_populate(NULL, NULL, NULL);
+}
+
 static const char * const vf610_dt_compat[] __initconst = {
 	"fsl,vf500",
 	"fsl,vf510",
@@ -20,5 +66,6 @@
 DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF5xx/VF6xx (Device Tree)")
 	.l2c_aux_val	= 0,
 	.l2c_aux_mask	= ~0,
+	.init_machine   = vf610_init_machine,
 	.dt_compat	= vf610_dt_compat,
 MACHINE_END
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mmdc.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mmdc.c
@@ -59,6 +59,7 @@
 #define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu)
 
 static int ddr_type;
+static int lpddr2_2ch_mode;
 
 struct fsl_mmdc_devtype_data {
 	unsigned int flags;
@@ -99,10 +100,12 @@
 	cpumask_t cpu;
 	struct hrtimer hrtimer;
 	unsigned int active_events;
+	int id;
 	struct device *dev;
 	struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
 	struct hlist_node node;
 	struct fsl_mmdc_devtype_data *devtype_data;
+	struct clk *mmdc_ipg_clk;
 };
 
 /*
@@ -432,8 +435,6 @@
 static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc,
 		void __iomem *mmdc_base, struct device *dev)
 {
-	int mmdc_num;
-
 	*pmu_mmdc = (struct mmdc_pmu) {
 		.pmu = (struct pmu) {
 			.task_ctx_nr    = perf_invalid_context,
@@ -451,26 +452,29 @@
 		.active_events = 0,
 	};
 
-	mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
+	pmu_mmdc->id = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
 
-	return mmdc_num;
+	return pmu_mmdc->id;
 }
 
 static int imx_mmdc_remove(struct platform_device *pdev)
 {
 	struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);
 
+	ida_simple_remove(&mmdc_ida, pmu_mmdc->id);
 	cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
 	perf_pmu_unregister(&pmu_mmdc->pmu);
+	iounmap(pmu_mmdc->mmdc_base);
+	clk_disable_unprepare(pmu_mmdc->mmdc_ipg_clk);
 	kfree(pmu_mmdc);
 	return 0;
 }
 
-static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_base)
+static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_base,
+			      struct clk *mmdc_ipg_clk)
 {
 	struct mmdc_pmu *pmu_mmdc;
 	char *name;
-	int mmdc_num;
 	int ret;
 	const struct of_device_id *of_id =
 		of_match_device(imx_mmdc_dt_ids, &pdev->dev);
@@ -493,13 +497,18 @@
 		cpuhp_mmdc_state = ret;
 	}
 
-	mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
-	if (mmdc_num == 0)
-		name = "mmdc";
-	else
-		name = devm_kasprintf(&pdev->dev,
-				GFP_KERNEL, "mmdc%d", mmdc_num);
+	ret = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
+	if (ret < 0)
+		goto  pmu_free;
+
+	name = devm_kasprintf(&pdev->dev,
+				GFP_KERNEL, "mmdc%d", ret);
+	if (!name) {
+		ret = -ENOMEM;
+		goto pmu_release_id;
+	}
 
+	pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk;
 	pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data;
 
 	hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
@@ -522,6 +531,8 @@
 	pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret);
 	cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
 	hrtimer_cancel(&pmu_mmdc->hrtimer);
+pmu_release_id:
+	ida_simple_remove(&mmdc_ida, pmu_mmdc->id);
 pmu_free:
 	kfree(pmu_mmdc);
 	return ret;
@@ -529,7 +540,7 @@
 
 #else
 #define imx_mmdc_remove NULL
-#define imx_mmdc_perf_init(pdev, mmdc_base) 0
+#define imx_mmdc_perf_init(pdev, mmdc_base, mmdc_ipg_clk) 0
 #endif
 
 static int imx_mmdc_probe(struct platform_device *pdev)
@@ -567,7 +578,13 @@
 	val &= ~(1 << BP_MMDC_MAPSR_PSD);
 	writel_relaxed(val, reg);
 
-	return imx_mmdc_perf_init(pdev, mmdc_base);
+	err = imx_mmdc_perf_init(pdev, mmdc_base, mmdc_ipg_clk);
+	if (err) {
+		iounmap(mmdc_base);
+		clk_disable_unprepare(mmdc_ipg_clk);
+	}
+
+	return err;
 }
 
 int imx_mmdc_get_ddr_type(void)
@@ -575,6 +592,11 @@
 	return ddr_type;
 }
 
+int imx_mmdc_get_lpddr2_2ch_mode(void)
+{
+	return lpddr2_2ch_mode;
+}
+
 static struct platform_driver imx_mmdc_driver = {
 	.driver		= {
 		.name	= "imx-mmdc",
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mu.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/mu.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include "common.h"
+#include "hardware.h"
+
+#define MU_ATR0_OFFSET	0x0
+#define MU_ARR0_OFFSET	0x10
+#define MU_ARR1_OFFSET	0x14
+#define MU_ASR		0x20
+#define MU_ACR		0x24
+#define MX7ULP_MU_TR0	0x20
+#define MX7ULP_MU_RR0	0x40
+#define MX7ULP_MU_RR1	0x44
+#define MX7ULP_MU_SR	0x60
+#define MX7ULP_MU_CR	0x64
+
+#define MU_LPM_HANDSHAKE_INDEX		0
+#define MU_RPMSG_HANDSHAKE_INDEX	1
+#define MU_LPM_BUS_HIGH_READY_FOR_M4	0xFFFF6666
+#define MU_LPM_M4_FREQ_CHANGE_READY	0xFFFF7777
+#define MU_LPM_M4_REQUEST_HIGH_BUS	0x2222CCCC
+#define MU_LPM_M4_RELEASE_HIGH_BUS	0x2222BBBB
+#define MU_LPM_M4_WAKEUP_SRC_VAL	0x55555000
+#define MU_LPM_M4_WAKEUP_SRC_MASK	0xFFFFF000
+#define MU_LPM_M4_WAKEUP_IRQ_MASK	0xFF0
+#define MU_LPM_M4_WAKEUP_IRQ_SHIFT	0x4
+#define MU_LPM_M4_WAKEUP_ENABLE_MASK	0xF
+#define MU_LPM_M4_WAKEUP_ENABLE_SHIFT	0x0
+
+#define MU_LPM_M4_RUN_MODE	        0x5A5A0001
+#define MU_LPM_M4_WAIT_MODE	        0x5A5A0002
+#define MU_LPM_M4_STOP_MODE	        0x5A5A0003
+
+#define MAX_NUM 10     /*  enlarge it if overflow happen */
+
+static void __iomem *mu_base;
+static u32 m4_message[MAX_NUM];
+static u32 in_idx, out_idx;
+static struct delayed_work mu_work;
+static u32 m4_wake_irqs[4];
+static bool m4_freq_low;
+struct irq_domain *domain;
+static bool m4_in_stop;
+static struct clk *clk;
+static DEFINE_SPINLOCK(mu_lock);
+
+void imx_mu_set_m4_run_mode(void)
+{
+	m4_in_stop = false;
+}
+
+bool imx_mu_is_m4_in_stop(void)
+{
+	return m4_in_stop;
+}
+
+bool imx_mu_is_m4_in_low_freq(void)
+{
+	return m4_freq_low;
+}
+
+void imx_mu_enable_m4_irqs_in_gic(bool enable)
+{
+	int i, j;
+
+	for (i = 0; i < 4; i++) {
+		if (m4_wake_irqs[i] == 0)
+			continue;
+		for (j = 0; j < 32; j++) {
+			if (m4_wake_irqs[i] & (1 << j)) {
+				if (enable)
+					enable_irq(irq_find_mapping(
+						domain, i * 32 + j));
+				else
+					disable_irq(irq_find_mapping(
+						domain, i * 32 + j));
+			}
+		}
+	}
+}
+
+static irqreturn_t mcc_m4_dummy_isr(int irq, void *param)
+{
+	return IRQ_HANDLED;
+}
+
+static int imx_mu_send_message(unsigned int index, unsigned int data)
+{
+	u32 val, ep;
+	int i, te_flag = 0;
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+	/* wait for transfer buffer empty, and no event pending */
+	do {
+		if (cpu_is_imx7ulp())
+			val = readl_relaxed(mu_base + MX7ULP_MU_SR);
+		else
+			val = readl_relaxed(mu_base + MU_ASR);
+		ep = val & BIT(4);
+		if (time_after(jiffies, timeout)) {
+			pr_err("Waiting MU transmit buffer empty timeout!\n");
+			return -EIO;
+		}
+	} while (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4)));
+
+	if (cpu_is_imx7ulp())
+		writel_relaxed(data, mu_base + index * 0x4 + MX7ULP_MU_TR0);
+	else
+		writel_relaxed(data, mu_base + index * 0x4 + MU_ATR0_OFFSET);
+
+	/*
+	 * make a double check that TEn is not empty after write
+	 */
+	if (cpu_is_imx7ulp())
+		val = readl_relaxed(mu_base + MX7ULP_MU_SR);
+	else
+		val = readl_relaxed(mu_base + MU_ASR);
+	ep = val & BIT(4);
+	if (((val & (1 << (20 + (3 - index)))) == 0) || (ep == BIT(4)))
+		return 0;
+	else
+		te_flag = 1;
+
+	/*
+	 * Make sure that TEn flag is changed, after the ATRn is filled up.
+	 */
+	for (i = 0; i < 100; i++) {
+		if (cpu_is_imx7ulp())
+			val = readl_relaxed(mu_base + MX7ULP_MU_SR);
+		else
+			val = readl_relaxed(mu_base + MU_ASR);
+		ep = val & BIT(4);
+		if (((val & (1 << (20 + 3 - index))) == 0) || (ep == BIT(4))) {
+			/*
+			 * BUG here. TEn flag is changes, after the
+			 * ATRn is filled with MSG for a while.
+			 */
+			te_flag = 0;
+			break;
+		} else if (time_after(jiffies, timeout)) {
+			/* Can't see TEn 1->0, maybe already handled! */
+			te_flag = 1;
+			break;
+		}
+	}
+	if (te_flag == 0)
+		pr_info("BUG: TEn is not changed immediately"
+				"when ATRn is filled up.\n");
+
+	return 0;
+}
+
+static void mu_work_handler(struct work_struct *work)
+{
+	int ret;
+	u32 irq, enable, idx, mask, virq;
+	struct of_phandle_args args;
+	u32 message;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mu_lock, flags);
+	message = m4_message[out_idx % MAX_NUM];
+	spin_unlock_irqrestore(&mu_lock, flags);
+
+	pr_debug("receive M4 message 0x%x\n", message);
+
+	switch (message) {
+	case MU_LPM_M4_RUN_MODE:
+	case MU_LPM_M4_WAIT_MODE:
+		m4_in_stop = false;
+		break;
+	case MU_LPM_M4_STOP_MODE:
+		m4_in_stop = true;
+		break;
+	case MU_LPM_M4_REQUEST_HIGH_BUS:
+		request_bus_freq(BUS_FREQ_HIGH);
+		imx_mu_send_message(MU_LPM_HANDSHAKE_INDEX,
+			MU_LPM_BUS_HIGH_READY_FOR_M4);
+		m4_freq_low = false;
+		break;
+	case MU_LPM_M4_RELEASE_HIGH_BUS:
+		release_bus_freq(BUS_FREQ_HIGH);
+		m4_freq_low = true;
+		break;
+	default:
+		if ((message & MU_LPM_M4_WAKEUP_SRC_MASK) ==
+			MU_LPM_M4_WAKEUP_SRC_VAL) {
+			irq = (message & MU_LPM_M4_WAKEUP_IRQ_MASK) >>
+				MU_LPM_M4_WAKEUP_IRQ_SHIFT;
+
+			enable = (message & MU_LPM_M4_WAKEUP_ENABLE_MASK) >>
+				MU_LPM_M4_WAKEUP_ENABLE_SHIFT;
+
+			/* to hwirq start from 0 */
+			irq -= 32;
+
+			idx = irq / 32;
+			mask = 1 << irq % 32;
+
+			args.np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-gpc");
+			args.args_count = 3;
+			args.args[0] = 0;
+			args.args[1] = irq;
+			args.args[2] = IRQ_TYPE_LEVEL_HIGH;
+
+			virq = irq_create_of_mapping(&args);
+
+			if (enable && can_request_irq(virq, 0)) {
+				ret = request_irq(virq, mcc_m4_dummy_isr,
+					IRQF_NO_SUSPEND, "imx-m4-dummy", NULL);
+				if (ret) {
+					pr_err("%s: register interrupt %d failed, rc %d\n",
+						__func__, virq, ret);
+					break;
+				}
+				disable_irq(virq);
+				m4_wake_irqs[idx] = m4_wake_irqs[idx] | mask;
+			}
+			imx_gpc_add_m4_wake_up_irq(irq, enable);
+		}
+		break;
+	}
+
+	spin_lock_irqsave(&mu_lock, flags);
+	m4_message[out_idx % MAX_NUM] = 0;
+	out_idx++;
+	spin_unlock_irqrestore(&mu_lock, flags);
+
+	/* enable RIE3 interrupt */
+	if (cpu_is_imx7ulp())
+		writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) | BIT(27),
+			mu_base + MX7ULP_MU_CR);
+	else
+		writel_relaxed(readl_relaxed(mu_base + MU_ACR) | BIT(27),
+			mu_base + MU_ACR);
+}
+
+int imx_mu_lpm_ready(bool ready)
+{
+	u32 val;
+
+	if (cpu_is_imx7ulp()) {
+		val = readl_relaxed(mu_base + MX7ULP_MU_CR);
+		if (ready)
+			writel_relaxed(val | BIT(0), mu_base + MX7ULP_MU_CR);
+		else
+			writel_relaxed(val & ~BIT(0), mu_base + MX7ULP_MU_CR);
+	} else {
+		val = readl_relaxed(mu_base + MU_ACR);
+		if (ready)
+			writel_relaxed(val | BIT(0), mu_base + MU_ACR);
+		else
+			writel_relaxed(val & ~BIT(0), mu_base + MU_ACR);
+	}
+	return 0;
+}
+
+static irqreturn_t imx_mu_isr(int irq, void *param)
+{
+	u32 irqs;
+	unsigned long flags;
+
+	if (cpu_is_imx7ulp())
+		irqs = readl_relaxed(mu_base + MX7ULP_MU_SR);
+	else
+		irqs = readl_relaxed(mu_base + MU_ASR);
+
+	if (irqs & (1 << 27)) {
+		spin_lock_irqsave(&mu_lock, flags);
+		/* get message from receive buffer */
+		if (cpu_is_imx7ulp())
+			m4_message[in_idx % MAX_NUM] = readl_relaxed(mu_base +
+						MX7ULP_MU_RR0);
+		else
+			m4_message[in_idx % MAX_NUM] = readl_relaxed(mu_base +
+						MU_ARR0_OFFSET);
+		/* disable RIE3 interrupt */
+		if (cpu_is_imx7ulp())
+			writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR)
+					& (~BIT(27)), mu_base + MX7ULP_MU_CR);
+		else
+			writel_relaxed(readl_relaxed(mu_base + MU_ACR)
+					& (~BIT(27)), mu_base + MU_ACR);
+		in_idx++;
+		if (in_idx == out_idx) {
+			spin_unlock_irqrestore(&mu_lock, flags);
+			pr_err("MU overflow!\n");
+			return IRQ_HANDLED;
+		}
+		spin_unlock_irqrestore(&mu_lock, flags);
+
+		schedule_delayed_work(&mu_work, 0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int imx_mu_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 irq;
+	struct device_node *np;
+	struct device *dev = &pdev->dev;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu-lp");
+	mu_base = of_iomap(np, 0);
+	WARN_ON(!mu_base);
+
+	ret = of_device_is_compatible(np, "fsl,imx7ulp-mu-lp");
+	if (ret)
+		irq = platform_get_irq(pdev, 1);
+	else
+		irq = platform_get_irq(pdev, 0);
+	ret = request_irq(irq, imx_mu_isr,
+			  IRQF_NO_SUSPEND | IRQF_SHARED, "imx-mu-lp", dev);
+	if (ret) {
+		pr_err("%s: register interrupt %d failed, rc %d\n",
+			__func__, irq, ret);
+		return ret;
+	}
+
+	ret = of_device_is_compatible(np, "fsl,imx7d-mu-lp");
+	if (ret) {
+		clk = devm_clk_get(&pdev->dev, "mu");
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev,
+				"mu clock source missing or invalid\n");
+			return PTR_ERR(clk);
+		} else {
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"unable to enable mu clock\n");
+				return ret;
+			}
+		}
+
+		/* MU always as a wakeup source for low power mode */
+		imx_gpcv2_add_m4_wake_up_irq(irq_to_desc(irq)->irq_data.hwirq,
+			true);
+	} else {
+		/* MU always as a wakeup source for low power mode */
+		imx_gpc_add_m4_wake_up_irq(irq_to_desc(irq)->irq_data.hwirq, true);
+	}
+
+	INIT_DELAYED_WORK(&mu_work, mu_work_handler);
+	/* bit0 of MX7ULP_MU_CR used to let m4 to know MU is ready now */
+	if (cpu_is_imx7ulp())
+		writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) |
+			BIT(0) | BIT(26) | BIT(27), mu_base + MX7ULP_MU_CR);
+	else
+		writel_relaxed(readl_relaxed(mu_base + MU_ACR) |
+			BIT(26) | BIT(27), mu_base + MU_ACR);
+
+	pr_info("MU is ready for cross core communication!\n");
+
+	return 0;
+}
+
+static const struct of_device_id imx_mu_ids[] = {
+	{ .compatible = "fsl,imx7d-mu-lp" },
+	{ .compatible = "fsl,imx7ulp-mu-lp" },
+	{ }
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int mu_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int mu_resume(struct device *dev)
+{
+	if (!cpu_is_imx7ulp())
+		return 0;
+
+	writel_relaxed(readl_relaxed(mu_base + MX7ULP_MU_CR) |
+			BIT(0) | BIT(26) | BIT(27), mu_base + MX7ULP_MU_CR);
+
+	return 0;
+}
+#endif
+static const struct dev_pm_ops mu_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(mu_suspend, mu_resume)
+};
+
+static struct platform_driver imx_mu_driver = {
+	.driver = {
+		.name   = "imx-mu-lp",
+		.owner  = THIS_MODULE,
+		.pm = &mu_pm_ops,
+		.of_match_table = imx_mu_ids,
+	},
+	.probe = imx_mu_probe,
+};
+
+static int __init imx_mu_init(void)
+{
+	return platform_driver_register(&imx_mu_driver);
+}
+subsys_initcall(imx_mu_init);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mx7.h
+++ linux-ein-5.4.0/arch/arm/mach-imx/mx7.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ *  * This program is free software; you can redistribute it and/or modify
+ *   * it under the terms of the GNU General Public License version 2 as
+ *    * published by the Free Software Foundation.
+ *     */
+
+#ifndef __ASM_ARCH_MX7_IOMAP_H__
+#define __ASM_ARCH_MX7_IOMAP_H__
+
+#define MX7D_IO_P2V(x)                  IMX_IO_P2V(x)
+#define MX7D_IO_ADDRESS(x)              IOMEM(MX7D_IO_P2V(x))
+
+#define MX7D_LPSR_BASE_ADDR             0x30270000
+#define MX7D_LPSR_SIZE                  0x10000
+#define MX7D_CCM_BASE_ADDR              0x30380000
+#define MX7D_CCM_SIZE                   0x10000
+#define MX7D_IOMUXC_BASE_ADDR           0x30330000
+#define MX7D_IOMUXC_SIZE                0x10000
+#define MX7D_IOMUXC_GPR_BASE_ADDR       0x30340000
+#define MX7D_IOMUXC_GPR_SIZE            0x10000
+#define MX7D_ANATOP_BASE_ADDR           0x30360000
+#define MX7D_ANATOP_SIZE                0x10000
+#define MX7D_SNVS_BASE_ADDR		0x30370000
+#define MX7D_SNVS_SIZE			0x10000
+#define MX7D_GPC_BASE_ADDR              0x303a0000
+#define MX7D_GPC_SIZE                   0x10000
+#define MX7D_SRC_BASE_ADDR              0x30390000
+#define MX7D_SRC_SIZE                   0x10000
+#define MX7D_DDRC_BASE_ADDR             0x307a0000
+#define MX7D_DDRC_SIZE                  0x10000
+#define MX7D_DDRC_PHY_BASE_ADDR         0x30790000
+#define MX7D_DDRC_PHY_SIZE              0x10000
+#define MX7D_AIPS1_BASE_ADDR            0x30000000
+#define MX7D_AIPS1_SIZE                 0x400000
+#define MX7D_AIPS2_BASE_ADDR            0x30400000
+#define MX7D_AIPS2_SIZE                 0x400000
+#define MX7D_AIPS3_BASE_ADDR            0x30900000
+#define MX7D_AIPS3_SIZE                 0x300000
+#define MX7D_GIC_BASE_ADDR              0x31000000
+#define MX7D_GIC_SIZE                   0x100000
+
+#define TT_ATTRIB_NON_CACHEABLE_1M     0x802
+#define MX7_IRAM_TLB_SIZE              0x4000
+#define MX7_SUSPEND_OCRAM_SIZE         0x1000
+#define MX7_CPUIDLE_OCRAM_ADDR_OFFSET  0x1000
+#define MX7_CPUIDLE_OCRAM_SIZE         0x1000
+#define MX7_BUSFREQ_OCRAM_ADDR_OFFSET  0x2000
+#define MX7_BUSFREQ_OCRAM_SIZE         0x1000
+
+#endif
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/mxc.h
+++ linux-ein-5.4.0/arch/arm/mach-imx/mxc.h
@@ -8,6 +8,7 @@
 #define __ASM_ARCH_MXC_H__
 
 #include <linux/types.h>
+#include <soc/imx/cpu.h>
 
 #ifndef __ASM_ARCH_MXC_HARDWARE_H__
 #error "Do not include directly."
@@ -33,10 +34,15 @@
 #define MXC_CPU_IMX7D		0x72
 #define MXC_CPU_IMX7ULP		0xff
 
+#define IMX_DDR_TYPE_DDR3		0
 #define IMX_DDR_TYPE_LPDDR2		1
+#define IMX_DDR_TYPE_LPDDR3		2
+#define IMX_MMDC_DDR_TYPE_LPDDR3	3
+
+#define IMX_LPDDR2_1CH_MODE            0
+#define IMX_LPDDR2_2CH_MODE            1
 
 #ifndef __ASSEMBLY__
-extern unsigned int __mxc_cpu_type;
 
 #ifdef CONFIG_SOC_IMX6SL
 static inline bool cpu_is_imx6sl(void)
@@ -90,6 +96,11 @@
 	return __mxc_cpu_type == MXC_CPU_IMX7D;
 }
 
+static inline bool cpu_is_imx7ulp(void)
+{
+	return __mxc_cpu_type == MXC_CPU_IMX7ULP;
+}
+
 struct cpu_op {
 	u32 cpu_rate;
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/platsmp.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/platsmp.c
@@ -47,15 +47,39 @@
 	return 0;
 }
 
+#define MXC_ARCH_CA7           0xc07
+static unsigned long __mxc_arch_type;
+
+static inline bool arm_is_ca7(void)
+{
+       return __mxc_arch_type == MXC_ARCH_CA7;
+}
 /*
  * Initialise the CPU possible map early - this describes the CPUs
  * which may be present or become present in the system.
  */
 static void __init imx_smp_init_cpus(void)
 {
+	unsigned long arch_type;
 	int i, ncores;
 
-	ncores = scu_get_core_count(scu_base);
+	asm volatile(
+		".align 4\n"
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		: "=r" (arch_type)
+	);
+	/* MIDR[15:4] defines ARCH type */
+	__mxc_arch_type = (arch_type >> 4) & 0xfff;
+
+	if (arm_is_ca7()) {
+		unsigned long val;
+
+		/* CA7 core number, [25:24] of CP15 L2CTLR */
+		asm volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (val));
+		ncores = ((val >> 24) & 0x3) + 1;
+	} else {
+		ncores = scu_get_core_count(scu_base);
+	}
 
 	for (i = ncores; i < NR_CPUS; i++)
 		set_cpu_possible(i, false);
@@ -63,11 +87,15 @@
 
 void imx_smp_prepare(void)
 {
+	if (arm_is_ca7())
+		return;
 	scu_enable(scu_base);
 }
 
 static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
 {
+	if (arm_is_ca7())
+		return;
 	imx_smp_prepare();
 
 	/*
@@ -109,6 +137,7 @@
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
 	dcfg_base = of_iomap(np, 0);
+	of_node_put(np);
 	BUG_ON(!dcfg_base);
 
 	paddr = __pa_symbol(secondary_startup);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/pm-imx5.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/pm-imx5.c
@@ -295,14 +295,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);
@@ -312,6 +312,8 @@
 	if (virt_out)
 		*virt_out = virt;
 
+put_device:
+	put_device(&pdev->dev);
 put_node:
 	of_node_put(node);
 
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/pm-imx6.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/pm-imx6.c
@@ -4,11 +4,13 @@
  * Copyright 2011 Linaro Ltd.
  */
 
+#include <linux/clk/imx.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/genalloc.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/of.h>
@@ -493,14 +495,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, MX6Q_SUSPEND_OCRAM_SIZE);
 	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);
@@ -523,7 +525,7 @@
 	ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat);
 	if (ret) {
 		pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret);
-		goto put_node;
+		goto put_device;
 	}
 
 	ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat);
@@ -570,7 +572,9 @@
 		&imx6_suspend,
 		MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));
 
-	goto put_node;
+	__arm_iomem_set_ro(suspend_ocram_base, MX6Q_SUSPEND_OCRAM_SIZE);
+
+	goto put_device;
 
 pl310_cache_map_failed:
 	iounmap(pm_info->gpc_base.vbase);
@@ -580,6 +584,8 @@
 	iounmap(pm_info->src_base.vbase);
 src_map_failed:
 	iounmap(pm_info->mmdc_base.vbase);
+put_device:
+	put_device(&pdev->dev);
 put_node:
 	of_node_put(node);
 
@@ -616,6 +622,7 @@
 
 static void imx6_pm_stby_poweroff(void)
 {
+	gic_cpu_if_down(0);
 	imx6_set_lpm(STOP_POWER_OFF);
 	imx6q_suspend_finish(0);
 
@@ -655,6 +662,8 @@
 
 	if (of_property_read_bool(np, "fsl,pmic-stby-poweroff"))
 		imx6_pm_stby_poweroff_probe();
+
+	of_node_put(np);
 }
 
 void __init imx6q_pm_init(void)
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/pm-imx7.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/pm-imx7.c
@@ -0,0 +1,1216 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/psci.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/genalloc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/tlb.h>
+
+#include <uapi/linux/psci.h>
+
+#include "common.h"
+#include "hardware.h"
+#include "cpuidle.h"
+
+#define MX7_SUSPEND_OCRAM_SIZE		0x1000
+#define MX7_MAX_DDRC_NUM		32
+#define MX7_MAX_DDRC_PHY_NUM		16
+
+#define MX7_SUSPEND_IRAM_ADDR_OFFSET	0
+#define READ_DATA_FROM_HARDWARE		0
+
+#define UART_UCR1	0x80
+#define UART_UCR2	0x84
+#define UART_UCR3	0x88
+#define UART_UCR4	0x8c
+#define UART_UFCR	0x90
+#define UART_UESC	0x9c
+#define UART_UTIM	0xa0
+#define UART_UBIR	0xa4
+#define UART_UBMR	0xa8
+#define UART_UBRC	0xac
+#define UART_UTS	0xb4
+
+#define MAX_IOMUXC_GPR			23
+#define MAX_UART_IO			4
+#define MAX_CCM_LPCG			167
+#define MAX_GPT				3
+#define MAX_GPIO_ROW			7
+#define MAX_GPIO_COL			8
+
+#define UART_RX_IO	0x128
+#define UART_RX_PAD	0x398
+#define UART_TX_IO	0x12c
+#define UART_TX_PAD	0x39c
+
+#define GPT_CR		0x0
+#define GPT_PR		0x4
+#define GPT_IR		0xc
+
+#define CCM_LPCG_START		0x4040
+#define CCM_LPCG_STEP		0x10
+#define CCM_EIM_LPCG		0x4160
+#define CCM_PXP_LPCG		0x44c0
+#define CCM_PCIE_LPCG		0x4600
+
+#define BM_CCM_ROOT_POST_PODF	0x3f
+#define BM_CCM_ROOT_PRE_PODF	0x70000
+#define BM_CCM_ROOT_MUX		0x7000000
+#define BM_CCM_ROOT_ENABLE	0x10000000
+
+#define BM_SYS_COUNTER_CNTCR_FCR1 0x200
+#define BM_SYS_COUNTER_CNTCR_FCR0 0x100
+
+#define PFD_A_OFFSET		0xc0
+#define PFD_B_OFFSET		0xd0
+
+#define PLL_ARM_OFFSET		0x60
+#define PLL_DDR_OFFSET		0x70
+#define PLL_DDR_SS_OFFSET	0x80
+#define PLL_DDR_NUM_OFFSET	0x90
+#define PLL_DDR_DENOM_OFFSET	0xa0
+#define PLL_480_OFFSET		0xb0
+#define PLL_ENET_OFFSET		0xe0
+#define PLL_AUDIO_OFFSET	0xf0
+#define PLL_AUDIO_SS_OFFSET	0x100
+#define PLL_AUDIO_NUM_OFFSET	0x110
+#define PLL_AUDIO_DENOM_OFFSET	0x120
+#define PLL_VIDEO_OFFSET	0x130
+#define PLL_VIDEO_SS_OFFSET	0x140
+#define PLL_VIDEO_NUM_OFFSET	0x150
+#define PLL_VIDEO_DENOM_OFFSET	0x160
+
+#define REG_SET			0x4
+#define REG_CLR			0x8
+
+#define GPIO_DR			0x0
+#define GPIO_GDIR		0x4
+#define GPIO_ICR1		0xc
+#define GPIO_ICR2		0x10
+#define GPIO_IMR		0x14
+#define GPIO_EDGE		0x1c
+
+#define M4RCR			0x0C
+#define M4_SP_OFF		0x00
+#define M4_PC_OFF		0x04
+#define M4_RCR_HALT		0xAB
+#define M4_RCR_GO		0xAA
+#define M4_OCRAMS_RESERVED_SIZE	0xc
+
+extern unsigned long iram_tlb_base_addr;
+extern unsigned long iram_tlb_phys_addr;
+
+static unsigned int *ocram_saved_in_ddr;
+static void __iomem *ocram_base;
+static unsigned int ocram_size;
+static unsigned int *lpm_ocram_saved_in_ddr;
+static void __iomem *lpm_ocram_base;
+
+static unsigned int *lpm_m4tcm_saved_in_ddr;
+static void __iomem *lpm_m4tcm_base;
+static void __iomem *m4_bootrom_base;
+
+static unsigned int lpm_ocram_size;
+static void __iomem *ccm_base;
+static void __iomem *lpsr_base;
+static void __iomem *console_base;
+static void __iomem *suspend_ocram_base;
+static void __iomem *iomuxc_base;
+static void __iomem *gpt1_base;
+static void __iomem *system_counter_ctrl_base;
+static void __iomem *system_counter_cmp_base;
+static void __iomem *gpio1_base;
+static void (*imx7_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
+struct imx7_cpu_pm_info *pm_info;
+static bool lpsr_enabled;
+static u32 iomuxc_gpr[MAX_IOMUXC_GPR];
+static u32 uart1_io[MAX_UART_IO];
+static u32 ccm_lpcg[MAX_CCM_LPCG];
+static u32 ccm_root[][2] = {
+	{0x8000, 0}, {0x8080, 0}, {0x8100, 0}, {0x8800, 0},
+	{0x8880, 0}, {0x8900, 0}, {0x8980, 0}, {0x9000, 0},
+	{0x9800, 0}, {0x9880, 0}, {0xa000, 0}, {0xa080, 0},
+	{0xa100, 0}, {0xa180, 0}, {0xa200, 0}, {0xa280, 0},
+	{0xa300, 0}, {0xa380, 0}, {0xa400, 0}, {0xa480, 0},
+	{0xa500, 0}, {0xa580, 0}, {0xa600, 0}, {0xa680, 0},
+	{0xa700, 0}, {0xa780, 0}, {0xa800, 0}, {0xa880, 0},
+	{0xa900, 0}, {0xa980, 0}, {0xaa00, 0}, {0xaa80, 0},
+	{0xab00, 0}, {0xab80, 0}, {0xac00, 0}, {0xac80, 0},
+	{0xad00, 0}, {0xad80, 0}, {0xae00, 0}, {0xae80, 0},
+	{0xaf00, 0}, {0xaf80, 0}, {0xb000, 0}, {0xb080, 0},
+	{0xb100, 0}, {0xb180, 0}, {0xb200, 0}, {0xb280, 0},
+	{0xb300, 0}, {0xb380, 0}, {0xb400, 0}, {0xb480, 0},
+	{0xb500, 0}, {0xb580, 0}, {0xb600, 0}, {0xb680, 0},
+	{0xb700, 0}, {0xb780, 0}, {0xb800, 0}, {0xb880, 0},
+	{0xb900, 0}, {0xb980, 0}, {0xba00, 0}, {0xba80, 0},
+	{0xbb00, 0}, {0xbb80, 0}, {0xbc00, 0}, {0xbc80, 0},
+	{0xbd00, 0}, {0xbd80, 0}, {0xbe00, 0},
+};
+static u32 pfd_a, pfd_b;
+static u32 pll[15];
+static u32 gpt1_regs[MAX_GPT];
+static u32 sys_ctrl_reg, sys_cmp_reg;
+static u32 gpio_reg[MAX_GPIO_ROW][MAX_GPIO_COL];
+/*
+ * suspend ocram space layout:
+ * ======================== high address ======================
+ *                              .
+ *                              .
+ *                              .
+ *                              ^
+ *                              ^
+ *                              ^
+ *                      imx7_suspend code
+ *              PM_INFO structure(imx7_cpu_pm_info)
+ * ======================== low address =======================
+ */
+
+struct imx7_pm_base {
+	phys_addr_t pbase;
+	void __iomem *vbase;
+};
+
+struct imx7_pm_socdata {
+	u32 ddr_type;
+	const char *ddrc_compat;
+	const char *src_compat;
+	const char *iomuxc_compat;
+	const char *gpc_compat;
+	const u32 ddrc_num;
+	const u32 (*ddrc_offset)[2];
+	const u32 ddrc_phy_num;
+	const u32 (*ddrc_phy_offset)[2];
+};
+
+static const u32 imx7d_ddrc_lpddr3_setting[][2] __initconst = {
+	{ 0x0, READ_DATA_FROM_HARDWARE },
+	{ 0x1a0, READ_DATA_FROM_HARDWARE },
+	{ 0x1a4, READ_DATA_FROM_HARDWARE },
+	{ 0x1a8, READ_DATA_FROM_HARDWARE },
+	{ 0x64, READ_DATA_FROM_HARDWARE },
+	{ 0xd0, READ_DATA_FROM_HARDWARE },
+	{ 0xdc, READ_DATA_FROM_HARDWARE },
+	{ 0xe0, READ_DATA_FROM_HARDWARE },
+	{ 0xe4, READ_DATA_FROM_HARDWARE },
+	{ 0xf4, READ_DATA_FROM_HARDWARE },
+	{ 0x100, READ_DATA_FROM_HARDWARE },
+	{ 0x104, READ_DATA_FROM_HARDWARE },
+	{ 0x108, READ_DATA_FROM_HARDWARE },
+	{ 0x10c, READ_DATA_FROM_HARDWARE },
+	{ 0x110, READ_DATA_FROM_HARDWARE },
+	{ 0x114, READ_DATA_FROM_HARDWARE },
+	{ 0x118, READ_DATA_FROM_HARDWARE },
+	{ 0x120, READ_DATA_FROM_HARDWARE },
+	{ 0x11c, READ_DATA_FROM_HARDWARE },
+	{ 0x180, READ_DATA_FROM_HARDWARE },
+	{ 0x184, READ_DATA_FROM_HARDWARE },
+	{ 0x190, READ_DATA_FROM_HARDWARE },
+	{ 0x194, READ_DATA_FROM_HARDWARE },
+	{ 0x200, READ_DATA_FROM_HARDWARE },
+	{ 0x204, READ_DATA_FROM_HARDWARE },
+	{ 0x210, READ_DATA_FROM_HARDWARE },
+	{ 0x214, READ_DATA_FROM_HARDWARE },
+	{ 0x218, READ_DATA_FROM_HARDWARE },
+	{ 0x240, READ_DATA_FROM_HARDWARE },
+	{ 0x244, READ_DATA_FROM_HARDWARE },
+};
+
+static const u32 imx7d_ddrc_phy_lpddr3_setting[][2] __initconst = {
+	{ 0x0, READ_DATA_FROM_HARDWARE },
+	{ 0x4, READ_DATA_FROM_HARDWARE },
+	{ 0x8, READ_DATA_FROM_HARDWARE },
+	{ 0x10, READ_DATA_FROM_HARDWARE },
+	{ 0xb0, READ_DATA_FROM_HARDWARE },
+	{ 0x1c, READ_DATA_FROM_HARDWARE },
+	{ 0x9c, READ_DATA_FROM_HARDWARE },
+	{ 0x7c, READ_DATA_FROM_HARDWARE },
+	{ 0x80, READ_DATA_FROM_HARDWARE },
+	{ 0x84, READ_DATA_FROM_HARDWARE },
+	{ 0x88, READ_DATA_FROM_HARDWARE },
+	{ 0x6c, READ_DATA_FROM_HARDWARE },
+	{ 0x20, READ_DATA_FROM_HARDWARE },
+	{ 0x30, READ_DATA_FROM_HARDWARE },
+	{ 0x50, 0x01000008 },
+	{ 0x50, 0x00000008 },
+	{ 0xc0, 0x0e487304 },
+	{ 0xc0, 0x0e4c7304 },
+	{ 0xc0, 0x0e4c7306 },
+	{ 0xc0, 0x0e487304 },
+};
+
+static const u32 imx7d_ddrc_ddr3_setting[][2] __initconst = {
+	{ 0x0, READ_DATA_FROM_HARDWARE },
+	{ 0x1a0, READ_DATA_FROM_HARDWARE },
+	{ 0x1a4, READ_DATA_FROM_HARDWARE },
+	{ 0x1a8, READ_DATA_FROM_HARDWARE },
+	{ 0x64, READ_DATA_FROM_HARDWARE },
+	{ 0x490, READ_DATA_FROM_HARDWARE },
+	{ 0xd0, READ_DATA_FROM_HARDWARE },
+	{ 0xd4, READ_DATA_FROM_HARDWARE },
+	{ 0xdc, READ_DATA_FROM_HARDWARE },
+	{ 0xe0, READ_DATA_FROM_HARDWARE },
+	{ 0xe4, READ_DATA_FROM_HARDWARE },
+	{ 0xf4, READ_DATA_FROM_HARDWARE },
+	{ 0x100, READ_DATA_FROM_HARDWARE },
+	{ 0x104, READ_DATA_FROM_HARDWARE },
+	{ 0x108, READ_DATA_FROM_HARDWARE },
+	{ 0x10c, READ_DATA_FROM_HARDWARE },
+	{ 0x110, READ_DATA_FROM_HARDWARE },
+	{ 0x114, READ_DATA_FROM_HARDWARE },
+	{ 0x120, READ_DATA_FROM_HARDWARE },
+	{ 0x180, READ_DATA_FROM_HARDWARE },
+	{ 0x190, READ_DATA_FROM_HARDWARE },
+	{ 0x194, READ_DATA_FROM_HARDWARE },
+	{ 0x200, READ_DATA_FROM_HARDWARE },
+	{ 0x204, READ_DATA_FROM_HARDWARE },
+	{ 0x210, READ_DATA_FROM_HARDWARE },
+	{ 0x214, READ_DATA_FROM_HARDWARE },
+	{ 0x218, READ_DATA_FROM_HARDWARE },
+	{ 0x240, READ_DATA_FROM_HARDWARE },
+	{ 0x244, READ_DATA_FROM_HARDWARE },
+};
+
+static const u32 imx7d_ddrc_phy_ddr3_setting[][2] __initconst = {
+	{ 0x0, READ_DATA_FROM_HARDWARE },
+	{ 0x4, READ_DATA_FROM_HARDWARE },
+	{ 0x10, READ_DATA_FROM_HARDWARE },
+	{ 0xb0, READ_DATA_FROM_HARDWARE },
+	{ 0x9c, READ_DATA_FROM_HARDWARE },
+	{ 0x7c, READ_DATA_FROM_HARDWARE },
+	{ 0x80, READ_DATA_FROM_HARDWARE },
+	{ 0x84, READ_DATA_FROM_HARDWARE },
+	{ 0x88, READ_DATA_FROM_HARDWARE },
+	{ 0x6c, READ_DATA_FROM_HARDWARE },
+	{ 0x20, READ_DATA_FROM_HARDWARE },
+	{ 0x30, READ_DATA_FROM_HARDWARE },
+	{ 0x50, 0x01000010 },
+	{ 0x50, 0x00000010 },
+	{ 0xc0, 0x0e407304 },
+	{ 0xc0, 0x0e447304 },
+	{ 0xc0, 0x0e447306 },
+	{ 0xc0, 0x0e407304 },
+};
+
+static const struct imx7_pm_socdata imx7d_pm_data_lpddr3 __initconst = {
+	.ddrc_compat = "fsl,imx7d-ddrc",
+	.src_compat = "fsl,imx7d-src",
+	.iomuxc_compat = "fsl,imx7d-iomuxc",
+	.gpc_compat = "fsl,imx7d-gpc",
+	.ddrc_num = ARRAY_SIZE(imx7d_ddrc_lpddr3_setting),
+	.ddrc_offset = imx7d_ddrc_lpddr3_setting,
+	.ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_lpddr3_setting),
+	.ddrc_phy_offset = imx7d_ddrc_phy_lpddr3_setting,
+};
+
+static const struct imx7_pm_socdata imx7d_pm_data_ddr3 __initconst = {
+	.ddrc_compat = "fsl,imx7d-ddrc",
+	.src_compat = "fsl,imx7d-src",
+	.iomuxc_compat = "fsl,imx7d-iomuxc",
+	.gpc_compat = "fsl,imx7d-gpc",
+	.ddrc_num = ARRAY_SIZE(imx7d_ddrc_ddr3_setting),
+	.ddrc_offset = imx7d_ddrc_ddr3_setting,
+	.ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_ddr3_setting),
+	.ddrc_phy_offset = imx7d_ddrc_phy_ddr3_setting,
+};
+
+/*
+ * This structure is for passing necessary data for low level ocram
+ * suspend code(arch/arm/mach-imx/suspend-imx7.S), if this struct
+ * definition is changed, the offset definition in
+ * arch/arm/mach-imx/suspend-imx7.S must be also changed accordingly,
+ * otherwise, the suspend to ocram function will be broken!
+ */
+struct imx7_cpu_pm_info {
+	u32 m4_reserve0;
+	u32 m4_reserve1;
+	u32 m4_reserve2;
+	phys_addr_t pbase; /* The physical address of pm_info. */
+	phys_addr_t resume_addr; /* The physical resume address for asm code */
+	u32 ddr_type;
+	u32 pm_info_size; /* Size of pm_info. */
+	struct imx7_pm_base ddrc_base;
+	struct imx7_pm_base ddrc_phy_base;
+	struct imx7_pm_base src_base;
+	struct imx7_pm_base iomuxc_gpr_base;
+	struct imx7_pm_base ccm_base;
+	struct imx7_pm_base gpc_base;
+	struct imx7_pm_base snvs_base;
+	struct imx7_pm_base anatop_base;
+	struct imx7_pm_base lpsr_base;
+	struct imx7_pm_base gic_base;
+	u32 ttbr1; /* Store TTBR1 */
+	u32 ddrc_num; /* Number of DDRC which need saved/restored. */
+	u32 ddrc_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */
+	u32 ddrc_phy_num; /* Number of DDRC which need saved/restored. */
+	u32 ddrc_phy_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */
+} __aligned(8);
+
+static struct map_desc imx7_pm_io_desc[] __initdata = {
+	imx_map_entry(MX7D, AIPS1, MT_DEVICE),
+	imx_map_entry(MX7D, AIPS2, MT_DEVICE),
+	imx_map_entry(MX7D, AIPS3, MT_DEVICE),
+};
+
+static void imx7_gpio_save(void)
+{
+	u32 i;
+
+	for (i = 0; i < 7; i++) {
+		gpio_reg[i][0] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_DR);
+		gpio_reg[i][1] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_GDIR);
+		gpio_reg[i][3] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_ICR1);
+		gpio_reg[i][4] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_ICR2);
+		gpio_reg[i][5] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_IMR);
+		gpio_reg[i][7] = readl_relaxed(gpio1_base +
+			(i << 16) + GPIO_EDGE);
+	}
+}
+
+static void imx7_gpio_restore(void)
+{
+	u32 i, val;
+
+	for (i = 0; i < 7; i++) {
+		writel_relaxed(gpio_reg[i][1], gpio1_base +
+			(i << 16) + GPIO_GDIR);
+		writel_relaxed(gpio_reg[i][3], gpio1_base +
+			(i << 16) + GPIO_ICR1);
+		writel_relaxed(gpio_reg[i][4], gpio1_base +
+			(i << 16) + GPIO_ICR2);
+		writel_relaxed(gpio_reg[i][5], gpio1_base +
+			(i << 16) + GPIO_IMR);
+		writel_relaxed(gpio_reg[i][7], gpio1_base +
+			(i << 16) + GPIO_EDGE);
+		/* only restore output gpio value */
+		val = readl_relaxed(gpio1_base + (i << 16) + GPIO_DR) |
+		     (gpio_reg[i][0] & gpio_reg[i][1]);
+		writel_relaxed(val, gpio1_base + (i << 16) + GPIO_DR);
+	}
+}
+
+static void imx7_ccm_save(void)
+{
+	u32 i;
+
+	for (i = 0; i < MAX_CCM_LPCG; i++)
+		ccm_lpcg[i] = readl_relaxed(pm_info->ccm_base.vbase +
+			i * CCM_LPCG_STEP + CCM_LPCG_START);
+	pfd_a = readl_relaxed(pm_info->anatop_base.vbase + PFD_A_OFFSET);
+	pfd_b = readl_relaxed(pm_info->anatop_base.vbase + PFD_B_OFFSET);
+
+	pll[0] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_ARM_OFFSET);
+	pll[1] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_DDR_OFFSET);
+	pll[2] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_DDR_SS_OFFSET);
+	pll[3] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_DDR_NUM_OFFSET);
+	pll[4] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_DDR_DENOM_OFFSET);
+	pll[5] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_480_OFFSET);
+	pll[6] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_ENET_OFFSET);
+	pll[7] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_AUDIO_OFFSET);
+	pll[8] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_AUDIO_SS_OFFSET);
+	pll[9] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_AUDIO_NUM_OFFSET);
+	pll[10] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_AUDIO_DENOM_OFFSET);
+	pll[11] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_VIDEO_OFFSET);
+	pll[12] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_VIDEO_SS_OFFSET);
+	pll[13] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_VIDEO_NUM_OFFSET);
+	pll[14] = readl_relaxed(pm_info->anatop_base.vbase +
+		PLL_VIDEO_DENOM_OFFSET);
+
+	/* enable all PLLs/PFDs for saving CCM root */
+	writel_relaxed(0x1c000070, pm_info->anatop_base.vbase +
+		PLL_480_OFFSET + 0x8);
+	writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
+		PFD_A_OFFSET + 0x8);
+	writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
+		PFD_B_OFFSET + 0x8);
+	writel_relaxed(0x1fc0, pm_info->anatop_base.vbase +
+		PLL_ENET_OFFSET + 0x4);
+	writel_relaxed(0x12000, pm_info->anatop_base.vbase +
+		PLL_AUDIO_OFFSET);
+	writel_relaxed(0x12000, pm_info->anatop_base.vbase +
+		PLL_VIDEO_OFFSET);
+
+	for (i = 0; i < sizeof(ccm_root) / 8; i++)
+		ccm_root[i][1] = readl_relaxed(
+			pm_info->ccm_base.vbase + ccm_root[i][0]);
+}
+
+static void imx7_ccm_restore(void)
+{
+	u32 i, val;
+
+	/* enable all PLLs/PFDs for restoring CCM root */
+	writel_relaxed(0x1c000070, pm_info->anatop_base.vbase +
+		PLL_480_OFFSET + REG_CLR);
+	writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
+		PFD_A_OFFSET + REG_CLR);
+	writel_relaxed(0x80808080, pm_info->anatop_base.vbase +
+		PFD_B_OFFSET + REG_CLR);
+	writel_relaxed(0x1fc0, pm_info->anatop_base.vbase +
+		PLL_ENET_OFFSET + REG_SET);
+	writel_relaxed(0x12000, pm_info->anatop_base.vbase +
+		PLL_AUDIO_OFFSET);
+	writel_relaxed(0x12000, pm_info->anatop_base.vbase +
+		PLL_VIDEO_OFFSET);
+
+	for (i = 0; i < sizeof(ccm_root) / 8; i++) {
+		val = readl_relaxed(pm_info->ccm_base.vbase + ccm_root[i][0]);
+		/* restore post podf */
+		val &= ~BM_CCM_ROOT_POST_PODF;
+		val |= ccm_root[i][1] & BM_CCM_ROOT_POST_PODF;
+		writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
+		/* resotre pre podf */
+		val &= ~BM_CCM_ROOT_PRE_PODF;
+		val |= ccm_root[i][1] & BM_CCM_ROOT_PRE_PODF;
+		writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
+		/* restore mux */
+		val &= ~BM_CCM_ROOT_MUX;
+		val |= ccm_root[i][1] & BM_CCM_ROOT_MUX;
+		writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
+		/* restore enable */
+		val &= ~BM_CCM_ROOT_ENABLE;
+		val |= ccm_root[i][1] & BM_CCM_ROOT_ENABLE;
+		writel_relaxed(val, pm_info->ccm_base.vbase + ccm_root[i][0]);
+	}
+
+	/* restore PLLs */
+	writel_relaxed(pll[0], pm_info->anatop_base.vbase +
+		PLL_ARM_OFFSET);
+	writel_relaxed(pll[1], pm_info->anatop_base.vbase +
+		PLL_DDR_OFFSET);
+	writel_relaxed(pll[2], pm_info->anatop_base.vbase +
+		PLL_DDR_SS_OFFSET);
+	writel_relaxed(pll[3], pm_info->anatop_base.vbase +
+		PLL_DDR_NUM_OFFSET);
+	writel_relaxed(pll[4], pm_info->anatop_base.vbase +
+		PLL_DDR_DENOM_OFFSET);
+	writel_relaxed(pll[5], pm_info->anatop_base.vbase +
+		PLL_480_OFFSET);
+	writel_relaxed(pll[6], pm_info->anatop_base.vbase +
+		PLL_ENET_OFFSET);
+	writel_relaxed(pll[7], pm_info->anatop_base.vbase +
+		PLL_AUDIO_OFFSET);
+	writel_relaxed(pll[8], pm_info->anatop_base.vbase +
+		PLL_AUDIO_SS_OFFSET);
+	writel_relaxed(pll[9], pm_info->anatop_base.vbase +
+		PLL_AUDIO_NUM_OFFSET);
+	writel_relaxed(pll[10], pm_info->anatop_base.vbase +
+		PLL_AUDIO_DENOM_OFFSET);
+	writel_relaxed(pll[11], pm_info->anatop_base.vbase +
+		PLL_VIDEO_OFFSET);
+	writel_relaxed(pll[12], pm_info->anatop_base.vbase +
+		PLL_VIDEO_SS_OFFSET);
+	writel_relaxed(pll[13], pm_info->anatop_base.vbase +
+		PLL_VIDEO_NUM_OFFSET);
+	writel_relaxed(pll[14], pm_info->anatop_base.vbase +
+		PLL_VIDEO_DENOM_OFFSET);
+
+	for (i = 0; i < MAX_CCM_LPCG; i++)
+		writel_relaxed(ccm_lpcg[i], pm_info->ccm_base.vbase +
+			i * CCM_LPCG_STEP + CCM_LPCG_START);
+	/* restore PFDs */
+	writel_relaxed(pfd_a & 0x80808080,
+		pm_info->anatop_base.vbase + PFD_A_OFFSET + REG_SET);
+	writel_relaxed(pfd_a, pm_info->anatop_base.vbase + PFD_A_OFFSET);
+
+	writel_relaxed(pfd_b & 0x80808080,
+		pm_info->anatop_base.vbase + PFD_B_OFFSET + REG_SET);
+	writel_relaxed(pfd_b, pm_info->anatop_base.vbase + PFD_B_OFFSET);
+}
+
+static void imx7_sys_counter_save(void)
+{
+	sys_ctrl_reg = readl_relaxed(system_counter_ctrl_base);
+	sys_cmp_reg = readl_relaxed(system_counter_cmp_base);
+}
+
+static void imx7_sys_counter_restore(void)
+{
+	writel_relaxed(sys_ctrl_reg, system_counter_ctrl_base);
+	writel_relaxed(sys_cmp_reg, system_counter_cmp_base);
+}
+
+static void imx7_gpt_save(void)
+{
+	gpt1_regs[0] = readl_relaxed(gpt1_base + GPT_CR);
+	gpt1_regs[1] = readl_relaxed(gpt1_base + GPT_PR);
+	gpt1_regs[2] = readl_relaxed(gpt1_base + GPT_IR);
+}
+
+static void imx7_gpt_restore(void)
+{
+	writel_relaxed(gpt1_regs[0], gpt1_base + GPT_CR);
+	writel_relaxed(gpt1_regs[1], gpt1_base + GPT_PR);
+	writel_relaxed(gpt1_regs[2], gpt1_base + GPT_IR);
+}
+
+static void imx7_iomuxc_gpr_save(void)
+{
+	u32 i;
+
+	for (i = 0; i < MAX_IOMUXC_GPR; i++)
+		iomuxc_gpr[i] = readl_relaxed(
+			pm_info->iomuxc_gpr_base.vbase + i * 4);
+}
+
+static void imx7_iomuxc_gpr_restore(void)
+{
+	u32 i;
+
+	for (i = 0; i < MAX_IOMUXC_GPR; i++)
+		writel_relaxed(iomuxc_gpr[i],
+			pm_info->iomuxc_gpr_base.vbase + i * 4);
+}
+
+static void imx7_console_save(unsigned int *regs)
+{
+	if (!console_base)
+		return;
+
+	regs[0] = readl_relaxed(console_base + UART_UCR1);
+	regs[1] = readl_relaxed(console_base + UART_UCR2);
+	regs[2] = readl_relaxed(console_base + UART_UCR3);
+	regs[3] = readl_relaxed(console_base + UART_UCR4);
+	regs[4] = readl_relaxed(console_base + UART_UFCR);
+	regs[5] = readl_relaxed(console_base + UART_UESC);
+	regs[6] = readl_relaxed(console_base + UART_UTIM);
+	regs[7] = readl_relaxed(console_base + UART_UBIR);
+	regs[8] = readl_relaxed(console_base + UART_UBMR);
+	regs[9] = readl_relaxed(console_base + UART_UTS);
+}
+
+static void imx7_console_io_save(void)
+{
+	/* save uart1 io, driver resume is too late */
+	uart1_io[0] = readl_relaxed(iomuxc_base + UART_RX_IO);
+	uart1_io[1] = readl_relaxed(iomuxc_base + UART_RX_PAD);
+	uart1_io[2] = readl_relaxed(iomuxc_base + UART_TX_IO);
+	uart1_io[3] = readl_relaxed(iomuxc_base + UART_TX_PAD);
+}
+
+static void imx7_console_restore(unsigned int *regs)
+{
+	if (!console_base)
+		return;
+
+	writel_relaxed(regs[4], console_base + UART_UFCR);
+	writel_relaxed(regs[5], console_base + UART_UESC);
+	writel_relaxed(regs[6], console_base + UART_UTIM);
+	writel_relaxed(regs[7], console_base + UART_UBIR);
+	writel_relaxed(regs[8], console_base + UART_UBMR);
+	writel_relaxed(regs[9], console_base + UART_UTS);
+	writel_relaxed(regs[0], console_base + UART_UCR1);
+	writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2);
+	writel_relaxed(regs[2], console_base + UART_UCR3);
+	writel_relaxed(regs[3], console_base + UART_UCR4);
+}
+
+static void imx7_console_io_restore(void)
+{
+	/* restore uart1 io */
+	writel_relaxed(uart1_io[0], iomuxc_base + UART_RX_IO);
+	writel_relaxed(uart1_io[1], iomuxc_base + UART_RX_PAD);
+	writel_relaxed(uart1_io[2], iomuxc_base + UART_TX_IO);
+	writel_relaxed(uart1_io[3], iomuxc_base + UART_TX_PAD);
+}
+
+#define MX7D_SUSPEND_POWERDWN_PARAM	\
+	((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+	 (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+	 (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
+
+#define MX7D_SUSPEND_STANDBY_PARAM	\
+	((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+	 (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+	 (PSCI_POWER_STATE_TYPE_STANDBY << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
+
+static int imx7_suspend_finish(unsigned long val)
+{
+	u32 state;
+
+	if (val == 0)
+		state = MX7D_SUSPEND_POWERDWN_PARAM;
+	else
+		state = MX7D_SUSPEND_STANDBY_PARAM;
+
+	if (psci_ops.cpu_suspend) {
+		return psci_ops.cpu_suspend(state, __pa(cpu_resume));
+	}
+
+	if (!imx7_suspend_in_ocram_fn) {
+		cpu_do_idle();
+	} else {
+		/*
+		 * call low level suspend function in ocram,
+		 * as we need to float DDR IO.
+		 */
+		local_flush_tlb_all();
+		imx7_suspend_in_ocram_fn(suspend_ocram_base);
+	}
+
+	return 0;
+}
+
+static void imx7_pm_set_lpsr_resume_addr(unsigned long addr)
+{
+	writel_relaxed(addr, pm_info->lpsr_base.vbase);
+}
+
+static int imx7_pm_is_resume_from_lpsr(void)
+{
+	return readl_relaxed(lpsr_base);
+}
+
+static int imx7_pm_enter(suspend_state_t state)
+{
+	unsigned int console_saved_reg[10] = {0};
+	u32 val;
+
+	if (!iram_tlb_base_addr) {
+		pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \
+			 code. Please ensure device tree has an entry for \
+			 fsl,lpm-sram.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * arm_arch_timer driver requires system counter to be
+	 * a clock source with CLOCK_SOURCE_SUSPEND_NONSTOP flag
+	 * set, which means hardware system counter needs to keep
+	 * running during suspend, as the base clock for system
+	 * counter is 24MHz which will be disabled in STOP mode,
+	 * so we need to switch system counter's clock to alternate
+	 * (lower) clock, it is based on 32K, from block guide, there
+	 * is no special flow needs to be followed, system counter
+	 * hardware will handle the clock transition.
+	 */
+	val = readl_relaxed(system_counter_ctrl_base);
+	val &= ~BM_SYS_COUNTER_CNTCR_FCR0;
+	val |= BM_SYS_COUNTER_CNTCR_FCR1;
+	writel_relaxed(val, system_counter_ctrl_base);
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		imx_anatop_pre_suspend();
+		imx_gpcv2_pre_suspend(false);
+
+		/* Zzz ... */
+		if (psci_ops.cpu_suspend)
+			cpu_suspend(1, imx7_suspend_finish);
+		else
+			imx7_suspend_in_ocram_fn(suspend_ocram_base);
+
+		imx_anatop_post_resume();
+		imx_gpcv2_post_resume();
+		break;
+	case PM_SUSPEND_MEM:
+		imx_anatop_pre_suspend();
+		imx_gpcv2_pre_suspend(true);
+		if (imx_gpcv2_is_mf_mix_off()) {
+			/*
+			 * per design requirement, EXSC for PCIe/EIM/PXP
+			 * will need clock to recover RDC setting on
+			 * resume, so enable PCIe/EIM LPCG for RDC
+			 * recovery when M/F mix off
+			 */
+			writel_relaxed(0x3, pm_info->ccm_base.vbase +
+				CCM_EIM_LPCG);
+			writel_relaxed(0x3, pm_info->ccm_base.vbase +
+				CCM_PXP_LPCG);
+			writel_relaxed(0x3, pm_info->ccm_base.vbase +
+				CCM_PCIE_LPCG);
+			/* stop m4 if mix will also be shutdown */
+			if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) {
+				writel(M4_RCR_HALT,
+					pm_info->src_base.vbase + M4RCR);
+				imx_gpcv2_enable_wakeup_for_m4();
+			}
+			imx7_console_save(console_saved_reg);
+			memcpy(ocram_saved_in_ddr, ocram_base, ocram_size);
+			if (lpsr_enabled) {
+				imx7_pm_set_lpsr_resume_addr(pm_info->resume_addr);
+				imx7_console_io_save();
+				memcpy(lpm_ocram_saved_in_ddr, lpm_ocram_base,
+					lpm_ocram_size);
+				imx7_iomuxc_gpr_save();
+				imx7_ccm_save();
+				imx7_gpt_save();
+				imx7_sys_counter_save();
+				imx7_gpio_save();
+			}
+		}
+
+		/* Zzz ... */
+		cpu_suspend(0, imx7_suspend_finish);
+
+		if (imx7_pm_is_resume_from_lpsr()) {
+			imx7_console_io_restore();
+			memcpy(lpm_ocram_base, lpm_ocram_saved_in_ddr,
+				lpm_ocram_size);
+			imx7_iomuxc_gpr_restore();
+			imx7_ccm_restore();
+			imx7_gpt_restore();
+			imx7_sys_counter_restore();
+			imx7_gpio_restore();
+			imx7d_enable_rcosc();
+		}
+		if (imx_gpcv2_is_mf_mix_off() ||
+			imx7_pm_is_resume_from_lpsr()) {
+			writel_relaxed(0x0, pm_info->ccm_base.vbase +
+				CCM_EIM_LPCG);
+			writel_relaxed(0x0, pm_info->ccm_base.vbase +
+				CCM_PXP_LPCG);
+			writel_relaxed(0x0, pm_info->ccm_base.vbase +
+				CCM_PCIE_LPCG);
+			memcpy(ocram_base, ocram_saved_in_ddr, ocram_size);
+			imx7_console_restore(console_saved_reg);
+			if (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop()) {
+				imx_gpcv2_disable_wakeup_for_m4();
+				/* restore M4 image */
+				memcpy(lpm_m4tcm_base,
+				    lpm_m4tcm_saved_in_ddr, SZ_32K);
+				/* kick m4 to enable */
+				writel(M4_RCR_GO,
+					pm_info->src_base.vbase + M4RCR);
+				/* offset high bus count for m4 image */
+				request_bus_freq(BUS_FREQ_HIGH);
+				/* restore M4 to run mode */
+				imx_mu_set_m4_run_mode();
+				/* gpc wakeup */
+			}
+		}
+		/* clear LPSR resume address */
+		imx7_pm_set_lpsr_resume_addr(0);
+		imx_anatop_post_resume();
+		imx_gpcv2_post_resume();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* restore system counter's clock to base clock */
+	val = readl_relaxed(system_counter_ctrl_base);
+	val &= ~BM_SYS_COUNTER_CNTCR_FCR1;
+	val |= BM_SYS_COUNTER_CNTCR_FCR0;
+	writel_relaxed(val, system_counter_ctrl_base);
+
+	return 0;
+}
+
+static int imx7_pm_valid(suspend_state_t state)
+{
+	return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
+}
+
+static const struct platform_suspend_ops imx7_pm_ops = {
+	.enter = imx7_pm_enter,
+	.valid = imx7_pm_valid,
+};
+
+void __init imx7_pm_set_ccm_base(void __iomem *base)
+{
+	ccm_base = base;
+}
+
+static struct map_desc iram_tlb_io_desc __initdata = {
+	/* .virtual and .pfn are run-time assigned */
+	.length     = SZ_1M,
+	.type       = MT_MEMORY_RWX_NONCACHED,
+};
+
+static int __init imx7_dt_find_lpsram(unsigned long node, const char *uname,
+				      int depth, void *data)
+{
+	unsigned long lpram_addr;
+	const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL);
+
+	if (of_flat_dt_is_compatible(node, "fsl,lpm-sram")) {
+		if (!prop)
+			return -EINVAL;
+
+		lpram_addr = be32_to_cpup(prop);
+
+		/* We need to create a 1M page table entry. */
+		iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000);
+		iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000);
+		iram_tlb_phys_addr = lpram_addr;
+		iram_tlb_base_addr = IMX_IO_P2V(lpram_addr);
+		iotable_init(&iram_tlb_io_desc, 1);
+	}
+
+	return 0;
+}
+
+void __init imx7_pm_map_io(void)
+{
+	unsigned long i, j;
+
+	iotable_init(imx7_pm_io_desc, ARRAY_SIZE(imx7_pm_io_desc));
+	/*
+	 * Get the address of IRAM or OCRAM to be used by the low
+	 * power code from the device tree.
+	 */
+	WARN_ON(of_scan_flat_dt(imx7_dt_find_lpsram, NULL));
+
+	/* Return if no IRAM space is allocated for suspend/resume code. */
+	if (!iram_tlb_base_addr) {
+		pr_warn("No valid ocram available for suspend/resume!\n");
+		return;
+	}
+
+	/* TODO: Handle M4 in TEE? */
+	/* Set all entries to 0 except first 3 words reserved for M4. */
+	memset((void *)(iram_tlb_base_addr + M4_OCRAMS_RESERVED_SIZE),
+		0, MX7_IRAM_TLB_SIZE - M4_OCRAMS_RESERVED_SIZE);
+
+	/*
+	 * Make sure the IRAM virtual address has a mapping in the IRAM
+	 * page table.
+	 *
+	 * Only use the top 12 bits [31-20] when storing the physical
+	 * address in the page table as only these bits are required
+	 * for 1M mapping.
+	 */
+	j = ((iram_tlb_base_addr >> 20) << 2) / 4;
+	*((unsigned long *)iram_tlb_base_addr + j) =
+		(iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
+
+	/*
+	 * Make sure the AIPS1 virtual address has a mapping in the
+	 * IRAM page table.
+	 */
+	for (i = 0; i < 4; i++) {
+		j = ((IMX_IO_P2V(MX7D_AIPS1_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
+		*((unsigned long *)iram_tlb_base_addr + j) =
+			((MX7D_AIPS1_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
+			TT_ATTRIB_NON_CACHEABLE_1M;
+	}
+
+	/*
+	 * Make sure the AIPS2 virtual address has a mapping in the
+	 * IRAM page table.
+	 */
+	for (i = 0; i < 4; i++) {
+		j = ((IMX_IO_P2V(MX7D_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
+		*((unsigned long *)iram_tlb_base_addr + j) =
+			((MX7D_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
+			TT_ATTRIB_NON_CACHEABLE_1M;
+	}
+
+	/*
+	 * Make sure the AIPS3 virtual address has a mapping
+	 * in the IRAM page table.
+	 */
+	for (i = 0; i < 4; i++) {
+		j = ((IMX_IO_P2V(MX7D_AIPS3_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
+		*((unsigned long *)iram_tlb_base_addr + j) =
+			((MX7D_AIPS3_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
+			TT_ATTRIB_NON_CACHEABLE_1M;
+	}
+
+	/*
+	 * Make sure the GIC virtual address has a mapping in the
+	 * IRAM page table.
+	 */
+	j = ((IMX_IO_P2V(MX7D_GIC_BASE_ADDR) >> 20) << 2) / 4;
+	*((unsigned long *)iram_tlb_base_addr + j) =
+		(MX7D_GIC_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
+}
+
+static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata)
+{
+	const u32 (*ddrc_offset_array)[2];
+	const u32 (*ddrc_phy_offset_array)[2];
+	unsigned long iram_paddr;
+	int i;
+
+	suspend_set_ops(&imx7_pm_ops);
+
+	if (!socdata) {
+		pr_warn("%s: invalid argument!\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB,
+	 * The lower 8K is not used, so use the lower 8K for IRAM code and
+	 * pm_info.
+	 *
+	 */
+	iram_paddr = iram_tlb_phys_addr + MX7_SUSPEND_IRAM_ADDR_OFFSET;
+
+	/* Make sure iram_paddr is 8 byte aligned. */
+	if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1))
+		iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN);
+
+	/* Get the virtual address of the suspend code. */
+	suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr);
+
+	if (psci_ops.cpu_suspend) {
+		pm_info = kmalloc(sizeof(*pm_info), GFP_KERNEL);
+		if (!pm_info)
+			return -ENOMEM;
+	} else {
+		pm_info = suspend_ocram_base;
+	}
+	/* pbase points to iram_paddr. */
+	pm_info->pbase = iram_paddr;
+	pm_info->resume_addr = virt_to_phys(ca7_cpu_resume);
+	pm_info->pm_info_size = sizeof(*pm_info);
+
+	/*
+	 * ccm physical address is not used by asm code currently,
+	 * so get ccm virtual address directly, as we already have
+	 * it from ccm driver.
+	 */
+	pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR;
+	pm_info->ccm_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_CCM_BASE_ADDR);
+
+	pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR;
+	pm_info->ddrc_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_DDRC_BASE_ADDR);
+
+	pm_info->ddrc_phy_base.pbase = MX7D_DDRC_PHY_BASE_ADDR;
+	pm_info->ddrc_phy_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR);
+
+	pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR;
+	pm_info->src_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_SRC_BASE_ADDR);
+
+	pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR;
+	pm_info->iomuxc_gpr_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR);
+
+	pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR;
+	pm_info->gpc_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_GPC_BASE_ADDR);
+
+	pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR;
+	pm_info->anatop_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR);
+
+	pm_info->snvs_base.pbase = MX7D_SNVS_BASE_ADDR;
+	pm_info->snvs_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_SNVS_BASE_ADDR);
+
+	pm_info->lpsr_base.pbase = MX7D_LPSR_BASE_ADDR;
+	lpsr_base = pm_info->lpsr_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_LPSR_BASE_ADDR);
+
+	pm_info->gic_base.pbase = MX7D_GIC_BASE_ADDR;
+	pm_info->gic_base.vbase = (void __iomem *)
+				IMX_IO_P2V(MX7D_GIC_BASE_ADDR);
+
+	pm_info->ddrc_num = socdata->ddrc_num;
+	ddrc_offset_array = socdata->ddrc_offset;
+	pm_info->ddrc_phy_num = socdata->ddrc_phy_num;
+	ddrc_phy_offset_array = socdata->ddrc_phy_offset;
+
+	/* initialize DDRC settings */
+	for (i = 0; i < pm_info->ddrc_num; i++) {
+		pm_info->ddrc_val[i][0] = ddrc_offset_array[i][0];
+		if (ddrc_offset_array[i][1] == READ_DATA_FROM_HARDWARE)
+			pm_info->ddrc_val[i][1] =
+				readl_relaxed(pm_info->ddrc_base.vbase +
+				ddrc_offset_array[i][0]);
+		else
+			pm_info->ddrc_val[i][1] = ddrc_offset_array[i][1];
+
+		if (pm_info->ddrc_val[i][0] == 0xd0)
+			pm_info->ddrc_val[i][1] |= 0xc0000000;
+	}
+
+	/* initialize DDRC PHY settings */
+	for (i = 0; i < pm_info->ddrc_phy_num; i++) {
+		pm_info->ddrc_phy_val[i][0] =
+			ddrc_phy_offset_array[i][0];
+		if (ddrc_phy_offset_array[i][1] == READ_DATA_FROM_HARDWARE)
+			pm_info->ddrc_phy_val[i][1] =
+				readl_relaxed(pm_info->ddrc_phy_base.vbase +
+				ddrc_phy_offset_array[i][0]);
+		else
+			pm_info->ddrc_phy_val[i][1] =
+				ddrc_phy_offset_array[i][1];
+	}
+
+	if (psci_ops.cpu_suspend)
+		return 0;
+
+	imx7_suspend_in_ocram_fn = fncpy(
+		suspend_ocram_base + sizeof(*pm_info),
+		&imx7_suspend,
+		MX7_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));
+
+	return 0;
+}
+
+static void __init imx7_pm_common_init(const struct imx7_pm_socdata
+					*socdata)
+{
+	int ret;
+	struct regmap *gpr;
+
+	if (IS_ENABLED(CONFIG_SUSPEND)) {
+		ret = imx7_suspend_init(socdata);
+		if (ret)
+			pr_warn("%s: No DDR LPM support with suspend %d!\n",
+				__func__, ret);
+	}
+
+	/*
+	 * Force IOMUXC irq pending, so that the interrupt to GPC can be
+	 * used to deassert dsm_request signal when the signal gets
+	 * asserted unexpectedly.
+	 */
+	gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr");
+	if (!IS_ERR(gpr))
+		regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_IRQ_MASK,
+			IMX7D_GPR1_IRQ_MASK);
+}
+
+void __init imx7d_pm_init(void)
+{
+	struct device_node *np;
+	struct resource res;
+	if (imx_src_is_m4_enabled()) {
+		/* map the 32K of M4 TCM */
+		np = of_find_node_by_path(
+			"/tcml@007f8000");
+		if (np)
+			lpm_m4tcm_base = of_iomap(np, 0);
+		WARN_ON(!lpm_m4tcm_base);
+
+		/* map the m4 bootrom from dtb */
+		np = of_find_node_by_path(
+			"/soc/sram@00180000");
+		if (np)
+			m4_bootrom_base = of_iomap(np, 0);
+		WARN_ON(!m4_bootrom_base);
+
+		lpm_m4tcm_saved_in_ddr = kzalloc(SZ_32K, GFP_KERNEL);
+		WARN_ON(!lpm_m4tcm_saved_in_ddr);
+
+		/* save M4 Image to DDR */
+		memcpy(lpm_m4tcm_saved_in_ddr, lpm_m4tcm_base, SZ_32K);
+	}
+	np = of_find_compatible_node(NULL, NULL, "fsl,lpm-sram");
+	if (of_get_property(np, "fsl,enable-lpsr", NULL))
+		lpsr_enabled = true;
+
+	if (psci_ops.cpu_suspend)
+		lpsr_enabled = false;
+
+	if (lpsr_enabled) {
+		pr_info("LPSR mode enabled, DSM will go into LPSR mode!\n");
+		lpm_ocram_base = of_iomap(np, 0);
+		WARN_ON(!lpm_ocram_base);
+		WARN_ON(of_address_to_resource(np, 0, &res));
+		lpm_ocram_size = resource_size(&res);
+		lpm_ocram_saved_in_ddr = kzalloc(lpm_ocram_size, GFP_KERNEL);
+		WARN_ON(!lpm_ocram_saved_in_ddr);
+
+		np = of_find_node_by_path(
+			"/soc/bus@30000000/iomuxc@30330000");
+		if (np)
+			iomuxc_base = of_iomap(np, 0);
+		WARN_ON(!iomuxc_base);
+
+		np = of_find_node_by_path(
+			"/soc/bus@30000000/gpt@302d0000");
+		if (np)
+			gpt1_base = of_iomap(np, 0);
+		WARN_ON(!gpt1_base);
+
+		np = of_find_node_by_path(
+			"/soc/bus@30400000/system-counter-cmp@306b0000");
+		if (np)
+			system_counter_cmp_base = of_iomap(np, 0);
+		WARN_ON(!system_counter_cmp_base);
+
+		np = of_find_node_by_path(
+			"/soc/bus@30000000/gpio@30200000");
+		if (np)
+			gpio1_base = of_iomap(np, 0);
+		WARN_ON(!gpio1_base);
+	}
+
+	np = of_find_node_by_path(
+		"/soc/bus@30400000/system-counter-ctrl@306c0000");
+	if (np)
+		system_counter_ctrl_base = of_iomap(np, 0);
+	WARN_ON(!system_counter_ctrl_base);
+
+	if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR3
+		|| imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
+		imx7_pm_common_init(&imx7d_pm_data_lpddr3);
+	else if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_DDR3)
+		imx7_pm_common_init(&imx7d_pm_data_ddr3);
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram");
+	ocram_base = of_iomap(np, 0);
+	WARN_ON(!ocram_base);
+	WARN_ON(of_address_to_resource(np, 0, &res));
+	ocram_size = resource_size(&res);
+	ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL);
+	WARN_ON(!ocram_saved_in_ddr);
+
+	np = of_find_node_by_path(
+		"/soc/bus@30800000/serial@30860000");
+	if (np)
+		console_base = of_iomap(np, 0);
+
+	/* clear LPSR resume address first */
+	imx7_pm_set_lpsr_resume_addr(0);
+}
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/pm-imx7ulp.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/pm-imx7ulp.c
@@ -62,6 +62,7 @@
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
 	smc1_base = of_iomap(np, 0);
+	of_node_put(np);
 	WARN_ON(!smc1_base);
 
 	imx7ulp_set_lpm(ULP_PM_RUN);
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/resume-imx6.S
+++ linux-ein-5.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-ein-5.4.0.orig/arch/arm/mach-imx/smp_wfe.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/smp_wfe.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/smp_scu.h>
+#include "hardware.h"
+
+	.macro	disable_l1_dcache
+
+	/*
+	 * Flush all data from the L1 data cache before disabling
+	 * SCTLR.C bit.
+	 */
+	push	{r0 - r10, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r10, lr}
+
+	/* disable d-cache */
+	mrc	p15, 0, r7, c1, c0, 0
+	bic	r7, r7, #(1 << 2)
+	mcr	p15, 0, r7, c1, c0, 0
+	dsb
+	isb
+
+	push	{r0 - r10, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r10, lr}
+
+	.endm
+
+#ifdef CONFIG_SMP
+	.align 3
+
+ENTRY(imx7_smp_wfe)
+	push	{r4 - r11, lr}
+
+	dsb
+	isb
+
+	disable_l1_dcache
+
+	isb
+
+	/* Turn off SMP bit. */
+	mrc	p15, 0, r8, c1, c0, 1
+	bic	r8, r8, #0x40
+	mcr	p15, 0, r8, c1, c0, 1
+
+	isb
+	/* Set flag of entering WFE. */
+	mov	r7, #0xff
+	lsl	r7, r7, r0
+	mov	r6, #SCU_PM_DORMANT
+	lsl	r6, r6, r0
+	ldr	r8, [r1, #0x4]
+	bic	r8, r8, r7
+	orr	r6, r6, r8
+	str	r6, [r1, #0x4]
+
+go_back_wfe:
+	wfe
+
+	/* Offset 0x0 stores busfeq done flag */
+	ldr	r6, [r1]
+	cmp	r6, #1
+	beq	go_back_wfe
+
+	/* Turn ON SMP bit. */
+	mrc	p15, 0, r8, c1, c0, 1
+	orr	r8, r8, #0x40
+	mcr	p15, 0, r8, c1, c0, 1
+
+	isb
+	/* Enable L1 data cache. */
+	mrc	p15, 0, r8, c1, c0, 0
+	orr	r8, r8, #0x4
+	mcr	p15, 0, r8, c1, c0, 0
+	isb
+
+	/* Set flag of exiting WFE. */
+	mov	r7, #0xff
+	lsl	r7, r7, r0
+	mov	r6, #SCU_PM_NORMAL
+	lsl	r6, r6, r0
+	ldr	r8, [r1, #0x4]
+	bic	r8, r8, r7
+	orr	r6, r6, r8
+	str	r6, [r1, #0x4]
+
+	/* Pop all saved registers. */
+	pop	{r4 - r11, lr}
+	mov	pc, lr
+	.ltorg
+ENDPROC(imx7_smp_wfe)
+#endif
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/src.c
+++ linux-ein-5.4.0/arch/arm/mach-imx/src.c
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 #include <asm/smp_plat.h>
 #include "common.h"
+#include "hardware.h"
 
 #define SRC_SCR				0x000
 #define SRC_GPR1			0x020
@@ -23,9 +24,18 @@
 #define BP_SRC_SCR_SW_IPU2_RST		12
 #define BP_SRC_SCR_CORE1_RST		14
 #define BP_SRC_SCR_CORE1_ENABLE		22
+/* below is for i.MX7D */
+#define SRC_GPR1_V2			0x074
+#define SRC_A7RCR0			0x004
+#define SRC_A7RCR1			0x008
+#define SRC_M4RCR			0x00C
+
+#define BP_SRC_A7RCR0_A7_CORE_RESET0   0
+#define BP_SRC_A7RCR1_A7_CORE1_ENABLE  1
 
 static void __iomem *src_base;
-static DEFINE_SPINLOCK(scr_lock);
+static DEFINE_SPINLOCK(src_lock);
+static bool m4_is_enabled;
 
 static const int sw_reset_bits[5] = {
 	BP_SRC_SCR_SW_GPU_RST,
@@ -35,6 +45,11 @@
 	BP_SRC_SCR_SW_IPU2_RST
 };
 
+bool imx_src_is_m4_enabled(void)
+{
+	return m4_is_enabled;
+}
+
 static int imx_src_reset_module(struct reset_controller_dev *rcdev,
 		unsigned long sw_reset_idx)
 {
@@ -43,19 +58,16 @@
 	int bit;
 	u32 val;
 
-	if (!src_base)
-		return -ENODEV;
-
 	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
 		return -EINVAL;
 
 	bit = 1 << sw_reset_bits[sw_reset_idx];
 
-	spin_lock_irqsave(&scr_lock, flags);
+	spin_lock_irqsave(&src_lock, flags);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val |= bit;
 	writel_relaxed(val, src_base + SRC_SCR);
-	spin_unlock_irqrestore(&scr_lock, flags);
+	spin_unlock_irqrestore(&src_lock, flags);
 
 	timeout = jiffies + msecs_to_jiffies(1000);
 	while (readl(src_base + SRC_SCR) & bit) {
@@ -81,32 +93,59 @@
 	u32 mask, val;
 
 	cpu = cpu_logical_map(cpu);
-	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
-	spin_lock(&scr_lock);
-	val = readl_relaxed(src_base + SRC_SCR);
-	val = enable ? val | mask : val & ~mask;
-	val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1);
-	writel_relaxed(val, src_base + SRC_SCR);
-	spin_unlock(&scr_lock);
+	spin_lock(&src_lock);
+	if (cpu_is_imx7d()) {
+		/* enable core */
+		if (enable)
+			imx_gpcv2_set_core1_pdn_pup_by_software(false);
+
+		mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
+		val = readl_relaxed(src_base + SRC_A7RCR1);
+		val = enable ? val | mask : val & ~mask;
+		writel_relaxed(val, src_base + SRC_A7RCR1);
+	} else {
+		mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
+		val = readl_relaxed(src_base + SRC_SCR);
+		val = enable ? val | mask : val & ~mask;
+		val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1);
+		writel_relaxed(val, src_base + SRC_SCR);
+	}
+		spin_unlock(&src_lock);
 }
 
 void imx_set_cpu_jump(int cpu, void *jump_addr)
 {
+	spin_lock(&src_lock);
 	cpu = cpu_logical_map(cpu);
-	writel_relaxed(__pa_symbol(jump_addr),
-		       src_base + SRC_GPR1 + cpu * 8);
+	if (cpu_is_imx7d())
+		writel_relaxed(__pa_symbol(jump_addr),
+			src_base + SRC_GPR1_V2 + cpu * 8);
+	else
+		writel_relaxed(__pa_symbol(jump_addr),
+			src_base + SRC_GPR1 + cpu * 8);
+	spin_unlock(&src_lock);
 }
 
 u32 imx_get_cpu_arg(int cpu)
 {
 	cpu = cpu_logical_map(cpu);
-	return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
+	if (cpu_is_imx7d())
+		return readl_relaxed(src_base + SRC_GPR1_V2
+			+ cpu * 8 + 4);
+	else
+		return readl_relaxed(src_base + SRC_GPR1
+			+ cpu * 8 + 4);
 }
 
 void imx_set_cpu_arg(int cpu, u32 arg)
 {
 	cpu = cpu_logical_map(cpu);
-	writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
+	if (cpu_is_imx7d())
+		writel_relaxed(arg, src_base + SRC_GPR1_V2
+			+ cpu * 8 + 4);
+	else
+		writel_relaxed(arg, src_base + SRC_GPR1
+			+ cpu * 8 + 4);
 }
 
 void __init imx_src_init(void)
@@ -120,6 +159,15 @@
 	src_base = of_iomap(np, 0);
 	WARN_ON(!src_base);
 
+	if (cpu_is_imx7d()) {
+		val = readl_relaxed(src_base + SRC_M4RCR);
+		if (((val & BIT(3)) == BIT(3)) && !(val & BIT(0)))
+			m4_is_enabled = true;
+		else
+			m4_is_enabled = false;
+		return;
+	}
+
 	imx_reset_controller.of_node = np;
 	if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
 		reset_controller_register(&imx_reset_controller);
@@ -128,9 +176,9 @@
 	 * force warm reset sources to generate cold reset
 	 * for a more reliable restart
 	 */
-	spin_lock(&scr_lock);
+	spin_lock(&src_lock);
 	val = readl_relaxed(src_base + SRC_SCR);
 	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
 	writel_relaxed(val, src_base + SRC_SCR);
-	spin_unlock(&scr_lock);
+	spin_unlock(&src_lock);
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/suspend-imx53.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/suspend-imx53.S
@@ -28,11 +28,11 @@
  *                              ^
  *                              ^
  *                      imx53_suspend code
- *              PM_INFO structure(imx53_suspend_info)
+ *              PM_INFO structure(imx5_cpu_suspend_info)
  * ======================== low address =======================
  */
 
-/* Offsets of members of struct imx53_suspend_info */
+/* Offsets of members of struct imx5_cpu_suspend_info */
 #define SUSPEND_INFO_MX53_M4IF_V_OFFSET		0x0
 #define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET	0x4
 #define SUSPEND_INFO_MX53_IO_COUNT_OFFSET	0x8
--- linux-ein-5.4.0.orig/arch/arm/mach-imx/suspend-imx6.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/suspend-imx6.S
@@ -67,6 +67,7 @@
 #define MX6Q_CCM_CCR	0x0
 
 	.align 3
+	.arm
 
 	.macro  sync_l2_cache
 
@@ -327,17 +328,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-ein-5.4.0.orig/arch/arm/mach-imx/suspend-imx7.S
+++ linux-ein-5.4.0/arch/arm/mach-imx/suspend-imx7.S
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include "hardware.h"
+
+/*
+ * ==================== low level suspend ====================
+ *
+ * Better to follow below rules to use ARM registers:
+ * r0: pm_info structure address;
+ * r1 ~ r4: for saving pm_info members;
+ * r5 ~ r10: free registers;
+ * r11: io base address.
+ *
+ * suspend ocram space layout:
+ * ======================== high address ======================
+ *                              .
+ *                              .
+ *                              .
+ *                              ^
+ *                              ^
+ *                              ^
+ *                      imx7_suspend code
+ *              PM_INFO structure(imx7_cpu_pm_info)
+ * ======================== low address =======================
+ */
+
+/*
+ * Below offsets are based on struct imx7_cpu_pm_info
+ * which defined in arch/arm/mach-imx/pm-imx7.c, this
+ * structure contains necessary pm info for low level
+ * suspend related code.
+ */
+#define PM_INFO_M4_RESERVE0_OFFSET		0x0
+#define PM_INFO_M4_RESERVE1_OFFSET		0x4
+#define PM_INFO_M4_RESERVE2_OFFSET		0x8
+#define PM_INFO_PBASE_OFFSET			0xc
+#define PM_INFO_RESUME_ADDR_OFFSET		0x10
+#define PM_INFO_DDR_TYPE_OFFSET			0x14
+#define PM_INFO_PM_INFO_SIZE_OFFSET		0x18
+#define PM_INFO_MX7_DDRC_P_OFFSET		0x1c
+#define PM_INFO_MX7_DDRC_V_OFFSET		0x20
+#define PM_INFO_MX7_DDRC_PHY_P_OFFSET		0x24
+#define PM_INFO_MX7_DDRC_PHY_V_OFFSET		0x28
+#define PM_INFO_MX7_SRC_P_OFFSET		0x2c
+#define PM_INFO_MX7_SRC_V_OFFSET		0x30
+#define PM_INFO_MX7_IOMUXC_GPR_P_OFFSET		0x34
+#define PM_INFO_MX7_IOMUXC_GPR_V_OFFSET		0x38
+#define PM_INFO_MX7_CCM_P_OFFSET		0x3c
+#define PM_INFO_MX7_CCM_V_OFFSET		0x40
+#define PM_INFO_MX7_GPC_P_OFFSET		0x44
+#define PM_INFO_MX7_GPC_V_OFFSET		0x48
+#define PM_INFO_MX7_SNVS_P_OFFSET		0x4c
+#define PM_INFO_MX7_SNVS_V_OFFSET		0x50
+#define PM_INFO_MX7_ANATOP_P_OFFSET		0x54
+#define PM_INFO_MX7_ANATOP_V_OFFSET		0x58
+#define PM_INFO_MX7_LPSR_P_OFFSET		0x5c
+#define PM_INFO_MX7_LPSR_V_OFFSET		0x60
+#define PM_INFO_MX7_GIC_DIST_P_OFFSET		0x64
+#define PM_INFO_MX7_GIC_DIST_V_OFFSET		0x68
+#define PM_INFO_MX7_TTBR1_V_OFFSET		0x6c
+#define PM_INFO_DDRC_REG_NUM_OFFSET		0x70
+#define PM_INFO_DDRC_REG_OFFSET			0x74
+#define PM_INFO_DDRC_VALUE_OFFSET		0x78
+#define PM_INFO_DDRC_PHY_REG_NUM_OFFSET		0x174
+#define PM_INFO_DDRC_PHY_REG_OFFSET		0x178
+#define PM_INFO_DDRC_PHY_VALUE_OFFSET		0x17c
+
+#define MX7_SRC_GPR1	0x74
+#define MX7_SRC_GPR2	0x78
+#define GPC_PGC_C0	0x800
+#define GPC_PGC_FM	0xa00
+#define ANADIG_SNVS_MISC_CTRL	0x380
+#define ANADIG_SNVS_MISC_CTRL_SET 0x384
+#define ANADIG_SNVS_MISC_CTRL_CLR 0x388
+#define ANADIG_DIGPROG	0x800
+#define DDRC_STAT	0x4
+#define DDRC_PWRCTL	0x30
+#define DDRC_PSTAT	0x3fc
+#define DDRC_PCTRL_0	0x490
+#define DDRC_DFIMISC	0x1b0
+#define DDRC_SWCTL	0x320
+#define DDRC_SWSTAT	0x324
+#define DDRPHY_LP_CON0	0x18
+
+#define CCM_SNVS_LPCG	0x250
+#define MX7D_GPC_IMR1	0x30
+#define MX7D_GPC_IMR2	0x34
+#define MX7D_GPC_IMR3	0x38
+#define MX7D_GPC_IMR4	0x3c
+
+	.align 3
+
+	.macro	disable_l1_dcache
+
+	/*
+	 * Flush all data from the L1 data cache before disabling
+	 * SCTLR.C bit.
+	 */
+	push	{r0 - r10, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r10, lr}
+
+	/* disable d-cache */
+	mrc	p15, 0, r7, c1, c0, 0
+	bic	r7, r7, #(1 << 2)
+	mcr	p15, 0, r7, c1, c0, 0
+	dsb
+	isb
+
+	push	{r0 - r10, lr}
+	ldr	r7, =v7_flush_dcache_all
+	mov	lr, pc
+	mov	pc, r7
+	pop	{r0 - r10, lr}
+
+	.endm
+
+	.macro store_ttbr1
+
+	/* Store TTBR1 to pm_info->ttbr1 */
+	mrc	p15, 0, r7, c2, c0, 1
+	str	r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET]
+
+	/* Disable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	bic	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the BTAC. */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	ldr	r6, =iram_tlb_phys_addr
+	ldr	r6, [r6]
+	dsb
+	isb
+
+	/* Store the IRAM table in TTBR1 */
+	mcr	p15, 0, r6, c2, c0, 1
+	/* Read TTBCR and set PD0=1, N = 1 */
+	mrc	p15, 0, r6, c2, c0, 2
+	orr	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	.endm
+
+	.macro restore_ttbr1
+
+	/* Enable L1 data cache. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x4
+	mcr	p15, 0, r6, c1, c0, 0
+
+	dsb
+	isb
+
+	/* Restore TTBCR */
+	/* Read TTBCR and set PD0=0, N = 0 */
+	mrc	p15, 0, r6, c2, c0, 2
+	bic	r6, r6, #0x11
+	mcr	p15, 0, r6, c2, c0, 2
+	dsb
+	isb
+
+	/* flush the TLB */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c8, c3, 0
+
+	/* Enable Branch Prediction, Z bit in SCTLR. */
+	mrc	p15, 0, r6, c1, c0, 0
+	orr	r6, r6, #0x800
+	mcr	p15, 0, r6, c1, c0, 0
+
+	/* Flush the Branch Target Address Cache (BTAC) */
+	ldr	r6, =0x0
+	mcr	p15, 0, r6, c7, c1, 6
+
+	/* Restore TTBR1, get the origin ttbr1 from pm info */
+	ldr	r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET]
+	mcr	p15, 0, r7, c2, c0, 1
+
+	.endm
+
+	.macro ddrc_enter_self_refresh
+
+	ldr	r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET]
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	/* wait rw port_busy clear */
+	ldr	r6, =(0x1 << 16)
+	orr	r6, r6, #0x1
+1:
+	ldr	r7, [r11, #DDRC_PSTAT]
+	ands	r7, r7, r6
+	bne	1b
+
+	/* enter self-refresh bit 5 */
+	ldr	r7, =(0x1 << 5)
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	/* wait until self-refresh mode entered */
+2:
+	ldr	r7, [r11, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	bne	2b
+3:
+	ldr	r7, [r11, #DDRC_STAT]
+	ands	r7, r7, #0x20
+	beq	3b
+
+	/* disable dram clk */
+	ldr	r7, [r11, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 3)
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	.endm
+
+	.macro ddrc_exit_self_refresh
+
+	cmp	r5, #0x0
+	ldreq	r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET]
+	ldrne	r11, [r0, #PM_INFO_MX7_DDRC_P_OFFSET]
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	/* wait until self-refresh mode entered */
+4:
+	ldr	r7, [r11, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	beq	4b
+
+	/* enable auto self-refresh */
+	ldr	r7, [r11, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	.endm
+
+	.macro wait_delay
+5:
+	subs	r6, r6, #0x1
+	bne	5b
+
+	.endm
+
+	.macro ddr_enter_retention
+
+	ldr	r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET]
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r11, #DDRC_PCTRL_0]
+
+	/* wait rw port_busy clear */
+	ldr	r6, =(0x1 << 16)
+	orr	r6, r6, #0x1
+6:
+	ldr	r7, [r11, #DDRC_PSTAT]
+	ands	r7, r7, r6
+	bne	6b
+
+	ldr	r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET]
+	/* enter self-refresh bit 5 */
+	ldr	r7, =(0x1 << 5)
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	/* wait until self-refresh mode entered */
+7:
+	ldr	r7, [r11, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	bne	7b
+8:
+	ldr	r7, [r11, #DDRC_STAT]
+	ands	r7, r7, #0x20
+	beq	8b
+
+	/* disable dram clk */
+	ldr	r7, =(0x1 << 5)
+	orr	r7, r7, #(1 << 3)
+	str	r7, [r11, #DDRC_PWRCTL]
+
+	ldr	r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET]
+	ldr	r7, [r11, #ANADIG_DIGPROG]
+	and	r7, r7, #0xff
+	cmp	r7, #0x11
+	bne	10f
+
+	/* TO 1.1 */
+	ldr	r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_V_OFFSET]
+	ldr	r7, =0x38000000
+	str	r7, [r11]
+
+	/* LPSR mode need to use TO1.0 flow as IOMUX lost power */
+	ldr	r10, [r0, #PM_INFO_MX7_LPSR_V_OFFSET]
+	ldr	r7, [r10]
+	cmp	r7, #0x0
+	beq	11f
+10:
+	/* reset ddr_phy  */
+	ldr	r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET]
+	ldr	r7, =0x0
+	str	r7, [r11, #ANADIG_SNVS_MISC_CTRL]
+
+	/* delay 7 us */
+	ldr	r6, =6000
+	wait_delay
+
+	ldr	r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET]
+	ldr	r6, =0x1000
+	ldr	r7, [r11, r6]
+	orr	r7, r7, #0x1
+	str	r7, [r11, r6]
+11:
+	/* turn off ddr power */
+	ldr	r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET]
+	ldr	r7, =(0x1 << 29)
+	str	r7, [r11, #ANADIG_SNVS_MISC_CTRL_SET]
+
+	ldr	r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET]
+	ldr	r6, =0x1000
+	ldr	r7, [r11, r6]
+	orr	r7, r7, #0x1
+	str	r7, [r11, r6]
+
+	.endm
+
+	.macro ddr_exit_retention
+
+	cmp	r5, #0x0
+	ldreq	r1, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET]
+	ldrne	r1, [r0, #PM_INFO_MX7_ANATOP_P_OFFSET]
+	ldreq	r2, [r0, #PM_INFO_MX7_SRC_V_OFFSET]
+	ldrne	r2, [r0, #PM_INFO_MX7_SRC_P_OFFSET]
+	ldreq	r3, [r0, #PM_INFO_MX7_DDRC_V_OFFSET]
+	ldrne	r3, [r0, #PM_INFO_MX7_DDRC_P_OFFSET]
+	ldreq	r4, [r0, #PM_INFO_MX7_DDRC_PHY_V_OFFSET]
+	ldrne	r4, [r0, #PM_INFO_MX7_DDRC_PHY_P_OFFSET]
+	ldreq	r10, [r0, #PM_INFO_MX7_CCM_V_OFFSET]
+	ldrne	r10, [r0, #PM_INFO_MX7_CCM_P_OFFSET]
+	ldreq	r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_V_OFFSET]
+	ldrne	r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_P_OFFSET]
+
+	/* turn on ddr power */
+	ldr	r7, =(0x1 << 29)
+	str	r7, [r1, #ANADIG_SNVS_MISC_CTRL_CLR]
+
+	ldr	r6, =50
+	wait_delay
+
+	/* clear ddr_phy reset */
+	ldr	r6, =0x1000
+	ldr	r7, [r2, r6]
+	orr	r7, r7, #0x3
+	str	r7, [r2, r6]
+	ldr	r7, [r2, r6]
+	bic	r7, r7, #0x1
+	str	r7, [r2, r6]
+13:
+	ldr	r6, [r0, #PM_INFO_DDRC_REG_NUM_OFFSET]
+	ldr	r7, =PM_INFO_DDRC_REG_OFFSET
+	add	r7, r7, r0
+14:
+	ldr	r8, [r7], #0x4
+	ldr	r9, [r7], #0x4
+	str	r9, [r3, r8]
+	subs	r6, r6, #0x1
+	bne	14b
+	ldr	r7, =0x20
+	str	r7, [r3, #DDRC_PWRCTL]
+	ldr	r7, =0x0
+	str	r7, [r3, #DDRC_DFIMISC]
+
+	/* do PHY, clear ddr_phy reset */
+	ldr	r6, =0x1000
+	ldr	r7, [r2, r6]
+	bic	r7, r7, #0x2
+	str	r7, [r2, r6]
+
+	ldr	r7, [r1, #ANADIG_DIGPROG]
+	and	r7, r7, #0xff
+	cmp	r7, #0x11
+	bne	12f
+
+	/*
+	 * TKT262940:
+	 * System hang when press RST for DDR PAD is
+	 * in retention mode, fixed on TO1.1
+	 */
+	ldr	r7, [r11]
+	bic	r7, r7, #(1 << 27)
+	str	r7, [r11]
+	ldr	r7, [r11]
+	bic	r7, r7, #(1 << 29)
+	str	r7, [r11]
+12:
+	ldr	r7, =(0x1 << 30)
+	str	r7, [r1, #ANADIG_SNVS_MISC_CTRL_SET]
+
+	/* need to delay ~5mS */
+	ldr	r6, =0x100000
+	wait_delay
+
+	ldr	r6, [r0, #PM_INFO_DDRC_PHY_REG_NUM_OFFSET]
+	ldr	r7, =PM_INFO_DDRC_PHY_REG_OFFSET
+	add	r7, r7, r0
+
+15:
+	ldr	r8, [r7], #0x4
+	ldr	r9, [r7], #0x4
+	str	r9, [r4, r8]
+	subs	r6, r6, #0x1
+	bne	15b
+
+	ldr	r7, =0x0
+	add	r9, r10, #0x4000
+	str	r7, [r9, #0x130]
+
+	ldr	r7, =0x170
+	orr	r7, r7, #0x8
+	str	r7, [r11, #0x20]
+
+	ldr	r7, =0x2
+	add	r9, r10, #0x4000
+	str	r7, [r9, #0x130]
+
+	ldr	r7, =0xf
+	str	r7, [r4, #DDRPHY_LP_CON0]
+
+	/* wait until self-refresh mode entered */
+16:
+	ldr	r7, [r3, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x3
+	bne	16b
+	ldr	r7, =0x0
+	str	r7, [r3, #DDRC_SWCTL]
+	ldr	r7, =0x1
+	str	r7, [r3, #DDRC_DFIMISC]
+	ldr	r7, =0x1
+	str	r7, [r3, #DDRC_SWCTL]
+17:
+	ldr	r7, [r3, #DDRC_SWSTAT]
+	and	r7, r7, #0x1
+	cmp	r7, #0x1
+	bne	17b
+18:
+	ldr	r7, [r3, #DDRC_STAT]
+	and	r7, r7, #0x20
+	cmp	r7, #0x20
+	bne	18b
+
+	/* let DDR out of self-refresh */
+	ldr	r7, =0x0
+	str	r7, [r3, #DDRC_PWRCTL]
+19:
+	ldr	r7, [r3, #DDRC_STAT]
+	and	r7, r7, #0x30
+	cmp	r7, #0x0
+	bne	19b
+
+20:
+	ldr	r7, [r3, #DDRC_STAT]
+	and	r7, r7, #0x3
+	cmp	r7, #0x1
+	bne	20b
+
+	/* enable port */
+	ldr	r7, =0x1
+	str	r7, [r3, #DDRC_PCTRL_0]
+
+	/* enable auto self-refresh */
+	ldr	r7, [r3, #DDRC_PWRCTL]
+	orr	r7, r7, #(1 << 0)
+	str	r7, [r3, #DDRC_PWRCTL]
+
+	.endm
+
+ENTRY(imx7_suspend)
+	push	{r4-r12}
+
+	/* make sure SNVS clk is enabled */
+	ldr	r11, [r0, #PM_INFO_MX7_CCM_V_OFFSET]
+	add	r11, r11, #0x4000
+	ldr	r7, =0x3
+	str	r7, [r11, #CCM_SNVS_LPCG]
+
+	/* check whether it is a standby mode */
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r7, [r11, #GPC_PGC_C0]
+	cmp	r7, #0
+	beq	ddr_only_self_refresh
+
+	/*
+	 * The value of r0 is mapped the same in origin table and IRAM table,
+	 * thus no need to care r0 here.
+	 */
+	ldr	r1, [r0, #PM_INFO_PBASE_OFFSET]
+	ldr	r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
+	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
+	ldr	r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
+
+	/*
+	 * counting the resume address in iram
+	 * to set it in SRC register.
+	 */
+	ldr	r6, =imx7_suspend
+	ldr	r7, =resume
+	sub	r7, r7, r6
+	add	r8, r1, r4
+	add	r9, r8, r7
+
+	ldr	r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET]
+	/* store physical resume addr and pm_info address. */
+	str	r9, [r11, #MX7_SRC_GPR1]
+	str	r1, [r11, #MX7_SRC_GPR2]
+
+	disable_l1_dcache
+
+	store_ttbr1
+
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r7, [r11, #GPC_PGC_FM]
+	cmp	r7, #0
+	beq	ddr_only_self_refresh
+
+	ddr_enter_retention
+	/* enter LPSR mode if resume addr is valid */
+	ldr	r11, [r0, #PM_INFO_MX7_LPSR_V_OFFSET]
+	ldr	r7, [r11]
+	cmp	r7, #0x0
+	beq	ddr_retention_enter_out
+
+	/* disable STOP mode before entering LPSR */
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r7, [r11]
+	bic	r7, #0xf
+	str	r7, [r11]
+
+	/* shut down vddsoc to enter lpsr mode */
+	ldr	r11, [r0, #PM_INFO_MX7_SNVS_V_OFFSET]
+	ldr	r7, [r11, #0x38]
+	orr	r7, r7, #0x60
+	str	r7, [r11, #0x38]
+wait_shutdown:
+	wfi
+	nop
+	nop
+	nop
+	nop
+	b	wait_shutdown
+
+ddr_only_self_refresh:
+	ddrc_enter_self_refresh
+	b	wfi
+ddr_retention_enter_out:
+
+	ldr	r11, [r0, #PM_INFO_MX7_GIC_DIST_V_OFFSET]
+	ldr	r7, =0x0
+	ldr	r8, =0x1000
+	str	r7, [r11, r8]
+
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r4, [r11, #MX7D_GPC_IMR1]
+	ldr	r5, [r11, #MX7D_GPC_IMR2]
+	ldr	r6, [r11, #MX7D_GPC_IMR3]
+	ldr	r7, [r11, #MX7D_GPC_IMR4]
+
+	ldr	r8, =0xffffffff
+	str	r8, [r11, #MX7D_GPC_IMR1]
+	str	r8, [r11, #MX7D_GPC_IMR2]
+	str	r8, [r11, #MX7D_GPC_IMR3]
+	str	r8, [r11, #MX7D_GPC_IMR4]
+
+	/*
+	 * enable the RBC bypass counter here
+	 * to hold off the interrupts. RBC counter
+	 * = 8 (240us). With this setting, the latency
+	 * from wakeup interrupt to ARM power up
+	 * is ~250uS.
+	 */
+	ldr	r8, [r11, #0x14]
+	bic	r8, r8, #(0x3f << 24)
+	orr	r8, r8, #(0x8 << 24)
+	str	r8, [r11, #0x14]
+
+	/* enable the counter. */
+	ldr	r8, [r11, #0x14]
+	orr	r8, r8, #(0x1 << 30)
+	str	r8, [r11, #0x14]
+
+	/* unmask all the GPC interrupts. */
+	str	r4, [r11, #MX7D_GPC_IMR1]
+	str	r5, [r11, #MX7D_GPC_IMR2]
+	str	r6, [r11, #MX7D_GPC_IMR3]
+	str	r7, [r11, #MX7D_GPC_IMR4]
+
+	/*
+	 * now delay for a short while (3usec)
+	 * ARM is at 1GHz at this point
+	 * so a short loop should be enough.
+	 * this delay is required to ensure that
+	 * the RBC counter can start counting in
+	 * case an interrupt is already pending
+	 * or in case an interrupt arrives just
+	 * as ARM is about to assert DSM_request.
+	 */
+	ldr	r7, =2000
+rbc_loop:
+	subs	r7, r7, #0x1
+	bne	rbc_loop
+wfi:
+	/* Zzz, enter stop mode */
+	wfi
+	nop
+	nop
+	nop
+	nop
+
+	mov	r5, #0x0
+
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r7, [r11, #GPC_PGC_FM]
+	cmp	r7, #0
+	beq	wfi_ddr_self_refresh_out
+
+	ddr_exit_retention
+	b	wfi_ddr_retention_out
+wfi_ddr_self_refresh_out:
+	ddrc_exit_self_refresh
+wfi_ddr_retention_out:
+
+	/* check whether it is a standby mode */
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET]
+	ldr	r7, [r11, #GPC_PGC_C0]
+	cmp	r7, #0
+	beq	standby_out
+
+	ldr	r11, [r0, #PM_INFO_MX7_GIC_DIST_V_OFFSET]
+	ldr	r7, =0x1
+	ldr	r8, =0x1000
+	str	r7, [r11, r8]
+
+	restore_ttbr1
+standby_out:
+	pop	{r4-r12}
+	/* return to suspend finish */
+	mov	pc, lr
+
+resume:
+	/* invalidate L1 I-cache first */
+	mov     r6, #0x0
+	mcr     p15, 0, r6, c7, c5, 0
+	mcr     p15, 0, r6, c7, c5, 6
+	/* enable the Icache and branch prediction */
+	mov     r6, #0x1800
+	mcr     p15, 0, r6, c1, c0, 0
+	isb
+
+	/* get physical resume address from pm_info. */
+	ldr	lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
+	/* clear core0's entry and parameter */
+	ldr	r11, [r0, #PM_INFO_MX7_SRC_P_OFFSET]
+	mov	r7, #0x0
+	str	r7, [r11, #MX7_SRC_GPR1]
+	str	r7, [r11, #MX7_SRC_GPR2]
+
+	mov	r5, #0x1
+
+	ldr	r11, [r0, #PM_INFO_MX7_GPC_P_OFFSET]
+	ldr	r7, [r11, #GPC_PGC_FM]
+	cmp	r7, #0
+	beq	dsm_ddr_self_refresh_out
+
+	ddr_exit_retention
+	b	dsm_ddr_retention_out
+dsm_ddr_self_refresh_out:
+	ddrc_exit_self_refresh
+dsm_ddr_retention_out:
+
+	mov	pc, lr
+ENDPROC(imx7_suspend)
+
+ENTRY(ca7_cpu_resume)
+	bl	v7_invalidate_l1
+	b	cpu_resume
+ENDPROC(ca7_cpu_resume)
--- linux-ein-5.4.0.orig/arch/arm/mach-integrator/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-integrator/Kconfig
@@ -4,6 +4,8 @@
 	depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6
 	select ARM_AMBA
 	select COMMON_CLK_VERSATILE
+	select CMA
+	select DMA_CMA
 	select HAVE_TCM
 	select ICST
 	select MFD_SYSCON
@@ -35,14 +37,13 @@
 	select ARM_VIC
 	select GPIO_PL061
 	select GPIOLIB
+	select REGULATOR
+	select REGULATOR_FIXED_VOLTAGE
 	help
 	  The IM-PD1 is an add-on logic module for the Integrator which
 	  allows ARM(R) Ltd PrimeCells to be developed and evaluated.
 	  The IM-PD1 can be found on the Integrator/PP2 platform.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called impd1.
-
 config INTEGRATOR_CM7TDMI
 	bool "Integrator/CM7TDMI core module"
 	depends on ARCH_INTEGRATOR_AP
--- linux-ein-5.4.0.orig/arch/arm/mach-iop32x/include/mach/entry-macro.S
+++ linux-ein-5.4.0/arch/arm/mach-iop32x/include/mach/entry-macro.S
@@ -20,7 +20,7 @@
 	mrc     p6, 0, \irqstat, c8, c0, 0	@ Read IINTSRC
 	cmp     \irqstat, #0
 	clzne   \irqnr, \irqstat
-	rsbne   \irqnr, \irqnr, #31
+	rsbne   \irqnr, \irqnr, #32
 	.endm
 
 	.macro arch_ret_to_user, tmp1, tmp2
--- linux-ein-5.4.0.orig/arch/arm/mach-iop32x/include/mach/irqs.h
+++ linux-ein-5.4.0/arch/arm/mach-iop32x/include/mach/irqs.h
@@ -9,6 +9,6 @@
 #ifndef __IRQS_H
 #define __IRQS_H
 
-#define NR_IRQS			32
+#define NR_IRQS			33
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm/mach-iop32x/irq.c
+++ linux-ein-5.4.0/arch/arm/mach-iop32x/irq.c
@@ -32,14 +32,14 @@
 static void
 iop32x_irq_mask(struct irq_data *d)
 {
-	iop32x_mask &= ~(1 << d->irq);
+	iop32x_mask &= ~(1 << (d->irq - 1));
 	intctl_write(iop32x_mask);
 }
 
 static void
 iop32x_irq_unmask(struct irq_data *d)
 {
-	iop32x_mask |= 1 << d->irq;
+	iop32x_mask |= 1 << (d->irq - 1);
 	intctl_write(iop32x_mask);
 }
 
@@ -65,7 +65,7 @@
 	    machine_is_em7210())
 		*IOP3XX_PCIIRSR = 0x0f;
 
-	for (i = 0; i < NR_IRQS; i++) {
+	for (i = 1; i < NR_IRQS; i++) {
 		irq_set_chip_and_handler(i, &ext_chip, handle_level_irq);
 		irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE);
 	}
--- linux-ein-5.4.0.orig/arch/arm/mach-iop32x/irqs.h
+++ linux-ein-5.4.0/arch/arm/mach-iop32x/irqs.h
@@ -7,36 +7,40 @@
 #ifndef __IOP32X_IRQS_H
 #define __IOP32X_IRQS_H
 
+/* Interrupts in Linux start at 1, hardware starts at 0 */
+
+#define IOP_IRQ(x) ((x) + 1)
+
 /*
  * IOP80321 chipset interrupts
  */
-#define IRQ_IOP32X_DMA0_EOT	0
-#define IRQ_IOP32X_DMA0_EOC	1
-#define IRQ_IOP32X_DMA1_EOT	2
-#define IRQ_IOP32X_DMA1_EOC	3
-#define IRQ_IOP32X_AA_EOT	6
-#define IRQ_IOP32X_AA_EOC	7
-#define IRQ_IOP32X_CORE_PMON	8
-#define IRQ_IOP32X_TIMER0	9
-#define IRQ_IOP32X_TIMER1	10
-#define IRQ_IOP32X_I2C_0	11
-#define IRQ_IOP32X_I2C_1	12
-#define IRQ_IOP32X_MESSAGING	13
-#define IRQ_IOP32X_ATU_BIST	14
-#define IRQ_IOP32X_PERFMON	15
-#define IRQ_IOP32X_CORE_PMU	16
-#define IRQ_IOP32X_BIU_ERR	17
-#define IRQ_IOP32X_ATU_ERR	18
-#define IRQ_IOP32X_MCU_ERR	19
-#define IRQ_IOP32X_DMA0_ERR	20
-#define IRQ_IOP32X_DMA1_ERR	21
-#define IRQ_IOP32X_AA_ERR	23
-#define IRQ_IOP32X_MSG_ERR	24
-#define IRQ_IOP32X_SSP		25
-#define IRQ_IOP32X_XINT0	27
-#define IRQ_IOP32X_XINT1	28
-#define IRQ_IOP32X_XINT2	29
-#define IRQ_IOP32X_XINT3	30
-#define IRQ_IOP32X_HPI		31
+#define IRQ_IOP32X_DMA0_EOT	IOP_IRQ(0)
+#define IRQ_IOP32X_DMA0_EOC	IOP_IRQ(1)
+#define IRQ_IOP32X_DMA1_EOT	IOP_IRQ(2)
+#define IRQ_IOP32X_DMA1_EOC	IOP_IRQ(3)
+#define IRQ_IOP32X_AA_EOT	IOP_IRQ(6)
+#define IRQ_IOP32X_AA_EOC	IOP_IRQ(7)
+#define IRQ_IOP32X_CORE_PMON	IOP_IRQ(8)
+#define IRQ_IOP32X_TIMER0	IOP_IRQ(9)
+#define IRQ_IOP32X_TIMER1	IOP_IRQ(10)
+#define IRQ_IOP32X_I2C_0	IOP_IRQ(11)
+#define IRQ_IOP32X_I2C_1	IOP_IRQ(12)
+#define IRQ_IOP32X_MESSAGING	IOP_IRQ(13)
+#define IRQ_IOP32X_ATU_BIST	IOP_IRQ(14)
+#define IRQ_IOP32X_PERFMON	IOP_IRQ(15)
+#define IRQ_IOP32X_CORE_PMU	IOP_IRQ(16)
+#define IRQ_IOP32X_BIU_ERR	IOP_IRQ(17)
+#define IRQ_IOP32X_ATU_ERR	IOP_IRQ(18)
+#define IRQ_IOP32X_MCU_ERR	IOP_IRQ(19)
+#define IRQ_IOP32X_DMA0_ERR	IOP_IRQ(20)
+#define IRQ_IOP32X_DMA1_ERR	IOP_IRQ(21)
+#define IRQ_IOP32X_AA_ERR	IOP_IRQ(23)
+#define IRQ_IOP32X_MSG_ERR	IOP_IRQ(24)
+#define IRQ_IOP32X_SSP		IOP_IRQ(25)
+#define IRQ_IOP32X_XINT0	IOP_IRQ(27)
+#define IRQ_IOP32X_XINT1	IOP_IRQ(28)
+#define IRQ_IOP32X_XINT2	IOP_IRQ(29)
+#define IRQ_IOP32X_XINT3	IOP_IRQ(30)
+#define IRQ_IOP32X_HPI		IOP_IRQ(31)
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm/mach-ixp4xx/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-ixp4xx/Kconfig
@@ -13,7 +13,6 @@
 	select I2C
 	select I2C_IOP3XX
 	select PCI
-	select TIMER_OF
 	select USE_OF
 	help
 	  Say 'Y' here to support Device Tree-based IXP4xx platforms.
--- linux-ein-5.4.0.orig/arch/arm/mach-keystone/keystone.c
+++ linux-ein-5.4.0/arch/arm/mach-keystone/keystone.c
@@ -62,7 +62,7 @@
 static long long __init keystone_pv_fixup(void)
 {
 	long long offset;
-	phys_addr_t mem_start, mem_end;
+	u64 mem_start, mem_end;
 
 	mem_start = memblock_start_of_DRAM();
 	mem_end = memblock_end_of_DRAM();
@@ -75,7 +75,7 @@
 	if (mem_start < KEYSTONE_HIGH_PHYS_START ||
 	    mem_end   > KEYSTONE_HIGH_PHYS_END) {
 		pr_crit("Invalid address space for memory (%08llx-%08llx)\n",
-		        (u64)mem_start, (u64)mem_end);
+		        mem_start, mem_end);
 		return 0;
 	}
 
--- linux-ein-5.4.0.orig/arch/arm/mach-mediatek/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-mediatek/Kconfig
@@ -30,6 +30,7 @@
 config MACH_MT7629
 	bool "MediaTek MT7629 SoCs support"
 	default ARCH_MEDIATEK
+	select HAVE_ARM_ARCH_TIMER
 
 config MACH_MT8127
 	bool "MediaTek MT8127 SoCs support"
--- linux-ein-5.4.0.orig/arch/arm/mach-meson/platsmp.c
+++ linux-ein-5.4.0/arch/arm/mach-meson/platsmp.c
@@ -71,6 +71,7 @@
 	}
 
 	sram_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!sram_base) {
 		pr_err("Couldn't map SRAM registers\n");
 		return;
@@ -91,6 +92,7 @@
 	}
 
 	scu_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!scu_base) {
 		pr_err("Couldn't map SCU registers\n");
 		return;
--- linux-ein-5.4.0.orig/arch/arm/mach-mmp/sram.c
+++ linux-ein-5.4.0/arch/arm/mach-mmp/sram.c
@@ -72,6 +72,8 @@
 	if (!info)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, info);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
 		dev_err(&pdev->dev, "no memory resource defined\n");
@@ -107,8 +109,6 @@
 	list_add(&info->node, &sram_bank_list);
 	mutex_unlock(&sram_lock);
 
-	platform_set_drvdata(pdev, info);
-
 	dev_info(&pdev->dev, "initialized\n");
 	return 0;
 
@@ -127,17 +127,19 @@
 	struct sram_bank_info *info;
 
 	info = platform_get_drvdata(pdev);
-	if (info == NULL)
-		return -ENODEV;
 
-	mutex_lock(&sram_lock);
-	list_del(&info->node);
-	mutex_unlock(&sram_lock);
+	if (info->sram_size) {
+		mutex_lock(&sram_lock);
+		list_del(&info->node);
+		mutex_unlock(&sram_lock);
+
+		gen_pool_destroy(info->gpool);
+		iounmap(info->sram_virt);
+		kfree(info->pool_name);
+	}
 
-	gen_pool_destroy(info->gpool);
-	iounmap(info->sram_virt);
-	kfree(info->pool_name);
 	kfree(info);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/arm/mach-mmp/time.c
+++ linux-ein-5.4.0/arch/arm/mach-mmp/time.c
@@ -44,18 +44,21 @@
 static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
 
 /*
- * FIXME: the timer needs some delay to stablize the counter capture
+ * Read the timer through the CVWR register. Delay is required after requesting
+ * a read. The CR register cannot be directly read due to metastability issues
+ * documented in the PXA168 software manual.
  */
 static inline uint32_t timer_read(void)
 {
-	int delay = 100;
+	uint32_t val;
+	int delay = 3;
 
 	__raw_writel(1, mmp_timer_base + TMR_CVWR(1));
 
 	while (delay--)
-		cpu_relax();
+		val = __raw_readl(mmp_timer_base + TMR_CVWR(1));
 
-	return __raw_readl(mmp_timer_base + TMR_CVWR(1));
+	return val;
 }
 
 static u64 notrace mmp_read_sched_clock(void)
--- linux-ein-5.4.0.orig/arch/arm/mach-mxs/mach-mxs.c
+++ linux-ein-5.4.0/arch/arm/mach-mxs/mach-mxs.c
@@ -387,8 +387,10 @@
 
 	root = of_find_node_by_path("/");
 	ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
-	if (ret)
+	if (ret) {
+		kfree(soc_dev_attr);
 		return;
+	}
 
 	soc_dev_attr->family = "Freescale MXS Family";
 	soc_dev_attr->soc_id = mxs_get_soc_id();
--- linux-ein-5.4.0.orig/arch/arm/mach-npcm/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-npcm/Kconfig
@@ -11,7 +11,7 @@
 	depends on ARCH_MULTI_V7
 	select PINCTRL_NPCM7XX
 	select NPCM7XX_TIMER
-	select ARCH_REQUIRE_GPIOLIB
+	select GPIOLIB
 	select CACHE_L2X0
 	select ARM_GIC
 	select HAVE_ARM_TWD if SMP
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ linux-ein-5.4.0/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -15,6 +15,7 @@
 #include <linux/platform_data/gpio-omap.h>
 
 #include <asm/assembler.h>
+#include <asm/irq.h>
 
 #include "ams-delta-fiq.h"
 #include "board-ams-delta.h"
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/clock.c
+++ linux-ein-5.4.0/arch/arm/mach-omap1/clock.c
@@ -41,7 +41,7 @@
 unsigned long omap1_uart_recalc(struct clk *clk)
 {
 	unsigned int val = __raw_readl(clk->enable_reg);
-	return val & clk->enable_bit ? 48000000 : 12000000;
+	return val & 1 << clk->enable_bit ? 48000000 : 12000000;
 }
 
 unsigned long omap1_sossi_recalc(struct clk *clk)
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/pm.c
+++ linux-ein-5.4.0/arch/arm/mach-omap1/pm.c
@@ -596,11 +596,6 @@
 	return IRQ_HANDLED;
 }
 
-static struct irqaction omap_wakeup_irq = {
-	.name		= "peripheral wakeup",
-	.handler	= omap_wakeup_interrupt
-};
-
 
 
 static const struct platform_suspend_ops omap_pm_ops = {
@@ -613,6 +608,7 @@
 static int __init omap_pm_init(void)
 {
 	int error = 0;
+	int irq;
 
 	if (!cpu_class_is_omap1())
 		return -ENODEV;
@@ -656,9 +652,12 @@
 	arm_pm_idle = omap1_pm_idle;
 
 	if (cpu_is_omap7xx())
-		setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
+		irq = INT_7XX_WAKE_UP_REQ;
 	else if (cpu_is_omap16xx())
-		setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+		irq = INT_1610_WAKE_UP_REQ;
+	if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup",
+			NULL))
+		pr_err("Failed to request irq %d (peripheral wakeup)\n", irq);
 
 	/* Program new power ramp-up time
 	 * (0 for most boards since we don't lower voltage when in deep sleep)
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/time.c
+++ linux-ein-5.4.0/arch/arm/mach-omap1/time.c
@@ -155,15 +155,11 @@
 	return IRQ_HANDLED;
 }
 
-static struct irqaction omap_mpu_timer1_irq = {
-	.name		= "mpu_timer1",
-	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= omap_mpu_timer1_interrupt,
-};
-
 static __init void omap_init_mpu_timer(unsigned long rate)
 {
-	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+	if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
+			IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
+		pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
 	omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
 
 	clockevent_mpu_timer1.cpumask = cpumask_of(0);
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/timer.c
+++ linux-ein-5.4.0/arch/arm/mach-omap1/timer.c
@@ -165,7 +165,7 @@
 	kfree(pdata);
 
 err_free_pdev:
-	platform_device_unregister(pdev);
+	platform_device_put(pdev);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-omap1/timer32k.c
+++ linux-ein-5.4.0/arch/arm/mach-omap1/timer32k.c
@@ -148,15 +148,11 @@
 	return IRQ_HANDLED;
 }
 
-static struct irqaction omap_32k_timer_irq = {
-	.name		= "32KHz timer",
-	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= omap_32k_timer_interrupt,
-};
-
 static __init void omap_init_32k_timer(void)
 {
-	setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+	if (request_irq(INT_OS_TIMER, omap_32k_timer_interrupt,
+			IRQF_TIMER | IRQF_IRQPOLL, "32KHz timer", NULL))
+		pr_err("Failed to request irq %d(32KHz timer)\n", INT_OS_TIMER);
 
 	clockevent_32k_timer.cpumask = cpumask_of(0);
 	clockevents_config_and_register(&clockevent_32k_timer,
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-omap2/Kconfig
@@ -94,7 +94,7 @@
 config ARCH_OMAP2PLUS
 	bool
 	select ARCH_HAS_BANDGAP
-	select ARCH_HAS_HOLES_MEMORYMODEL
+	select ARCH_HAS_RESET_CONTROLLER
 	select ARCH_OMAP
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/board-generic.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/board-generic.c
@@ -327,7 +327,7 @@
 	.init_late	= dra7xx_init_late,
 	.init_irq	= omap_gic_of_init,
 	.init_machine	= omap_generic_init,
-	.init_time	= omap5_realtime_timer_init,
+	.init_time	= omap3_gptimer_timer_init,
 	.dt_compat	= dra74x_boards_compat,
 	.restart	= omap44xx_restart,
 MACHINE_END
@@ -350,7 +350,7 @@
 	.init_late	= dra7xx_init_late,
 	.init_irq	= omap_gic_of_init,
 	.init_machine	= omap_generic_init,
-	.init_time	= omap5_realtime_timer_init,
+	.init_time	= omap3_gptimer_timer_init,
 	.dt_compat	= dra72x_boards_compat,
 	.restart	= omap44xx_restart,
 MACHINE_END
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/board-n8x0.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/board-n8x0.c
@@ -322,6 +322,7 @@
 
 static void n8x0_mmc_callback(void *data, u8 card_mask)
 {
+#ifdef CONFIG_MMC_OMAP
 	int bit, *openp, index;
 
 	if (board_is_n800()) {
@@ -339,7 +340,6 @@
 	else
 		*openp = 0;
 
-#ifdef CONFIG_MMC_OMAP
 	omap_mmc_notify_cover_event(mmc_device, index, *openp);
 #else
 	pr_warn("MMC: notify cover event not available\n");
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/cpuidle34xx.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/cpuidle34xx.c
@@ -109,6 +109,7 @@
 			    int index)
 {
 	struct omap3_idle_statedata *cx = &omap3_idle_data[index];
+	int error;
 
 	if (omap_irq_pending() || need_resched())
 		goto return_sleep_time;
@@ -125,8 +126,11 @@
 	 * Call idle CPU PM enter notifier chain so that
 	 * VFP context is saved.
 	 */
-	if (cx->mpu_state == PWRDM_POWER_OFF)
-		cpu_pm_enter();
+	if (cx->mpu_state == PWRDM_POWER_OFF) {
+		error = cpu_pm_enter();
+		if (error)
+			goto out_clkdm_set;
+	}
 
 	/* Execute ARM wfi */
 	omap_sram_idle();
@@ -139,6 +143,7 @@
 	    pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
 		cpu_pm_exit();
 
+out_clkdm_set:
 	/* Re-allow idle for C1 */
 	if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
 		clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/cpuidle44xx.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/cpuidle44xx.c
@@ -122,6 +122,7 @@
 {
 	struct idle_statedata *cx = state_ptr + index;
 	u32 mpuss_can_lose_context = 0;
+	int error;
 
 	/*
 	 * CPU0 has to wait and stay ON until CPU1 is OFF state.
@@ -150,27 +151,37 @@
 				 (cx->mpu_logic_state == PWRDM_POWER_OFF);
 
 	/* Enter broadcast mode for periodic timers */
-	tick_broadcast_enable();
+	RCU_NONIDLE(tick_broadcast_enable());
 
 	/* Enter broadcast mode for one-shot timers */
-	tick_broadcast_enter();
+	RCU_NONIDLE(tick_broadcast_enter());
 
 	/*
 	 * Call idle CPU PM enter notifier chain so that
 	 * VFP and per CPU interrupt context is saved.
 	 */
-	cpu_pm_enter();
+	error = cpu_pm_enter();
+	if (error)
+		goto cpu_pm_out;
 
 	if (dev->cpu == 0) {
 		pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
-		omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+		RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state));
 
 		/*
 		 * Call idle CPU cluster PM enter notifier chain
 		 * to save GIC and wakeupgen context.
 		 */
-		if (mpuss_can_lose_context)
-			cpu_cluster_pm_enter();
+		if (mpuss_can_lose_context) {
+			error = cpu_cluster_pm_enter();
+			if (error) {
+				index = 0;
+				cx = state_ptr + index;
+				pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
+				RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state));
+				mpuss_can_lose_context = 0;
+			}
+		}
 	}
 
 	omap4_enter_lowpower(dev->cpu, cx->cpu_state);
@@ -183,9 +194,9 @@
 		    mpuss_can_lose_context)
 			gic_dist_disable();
 
-		clkdm_deny_idle(cpu_clkdm[1]);
-		omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON);
-		clkdm_allow_idle(cpu_clkdm[1]);
+		RCU_NONIDLE(clkdm_deny_idle(cpu_clkdm[1]));
+		RCU_NONIDLE(omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON));
+		RCU_NONIDLE(clkdm_allow_idle(cpu_clkdm[1]));
 
 		if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) &&
 		    mpuss_can_lose_context) {
@@ -198,19 +209,20 @@
 	}
 
 	/*
-	 * Call idle CPU PM exit notifier chain to restore
-	 * VFP and per CPU IRQ context.
-	 */
-	cpu_pm_exit();
-
-	/*
 	 * Call idle CPU cluster PM exit notifier chain
 	 * to restore GIC and wakeupgen context.
 	 */
 	if (dev->cpu == 0 && mpuss_can_lose_context)
 		cpu_cluster_pm_exit();
 
-	tick_broadcast_exit();
+	/*
+	 * Call idle CPU PM exit notifier chain to restore
+	 * VFP and per CPU IRQ context.
+	 */
+	cpu_pm_exit();
+
+cpu_pm_out:
+	RCU_NONIDLE(tick_broadcast_exit());
 
 fail:
 	cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/display.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/display.c
@@ -211,6 +211,7 @@
 	node = of_find_node_by_name(NULL, "omap4_padconf_global");
 	if (node)
 		omap4_dsi_mux_syscon = syscon_node_to_regmap(node);
+	of_node_put(node);
 
 	return 0;
 }
@@ -259,10 +260,13 @@
 
 	if (!pdev) {
 		pr_err("Unable to find DSS platform device\n");
+		of_node_put(node);
 		return -ENODEV;
 	}
 
 	r = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	put_device(&pdev->dev);
+	of_node_put(node);
 	if (r) {
 		pr_err("Unable to populate DSS submodule devices\n");
 		return r;
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/id.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/id.c
@@ -797,10 +797,15 @@
 
 	soc_dev_attr->machine  = soc_name;
 	soc_dev_attr->family   = omap_get_family();
+	if (!soc_dev_attr->family) {
+		kfree(soc_dev_attr);
+		return;
+	}
 	soc_dev_attr->revision = soc_rev;
 
 	soc_dev = soc_device_register(soc_dev_attr);
 	if (IS_ERR(soc_dev)) {
+		kfree(soc_dev_attr->family);
 		kfree(soc_dev_attr);
 		return;
 	}
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/omap-iommu.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/omap-iommu.c
@@ -11,14 +11,43 @@
 
 #include "omap_hwmod.h"
 #include "omap_device.h"
+#include "clockdomain.h"
 #include "powerdomain.h"
 
+static void omap_iommu_dra7_emu_swsup_config(struct platform_device *pdev,
+					     bool enable)
+{
+	static struct clockdomain *emu_clkdm;
+	static DEFINE_SPINLOCK(emu_lock);
+	static atomic_t count;
+	struct device_node *np = pdev->dev.of_node;
+
+	if (!of_device_is_compatible(np, "ti,dra7-dsp-iommu"))
+		return;
+
+	if (!emu_clkdm) {
+		emu_clkdm = clkdm_lookup("emu_clkdm");
+		if (WARN_ON_ONCE(!emu_clkdm))
+			return;
+	}
+
+	spin_lock(&emu_lock);
+
+	if (enable && (atomic_inc_return(&count) == 1))
+		clkdm_deny_idle(emu_clkdm);
+	else if (!enable && (atomic_dec_return(&count) == 0))
+		clkdm_allow_idle(emu_clkdm);
+
+	spin_unlock(&emu_lock);
+}
+
 int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
 				    u8 *pwrst)
 {
 	struct powerdomain *pwrdm;
 	struct omap_device *od;
 	u8 next_pwrst;
+	int ret = 0;
 
 	od = to_omap_device(pdev);
 	if (!od)
@@ -31,13 +60,21 @@
 	if (!pwrdm)
 		return -EINVAL;
 
-	if (request)
+	if (request) {
 		*pwrst = pwrdm_read_next_pwrst(pwrdm);
+		omap_iommu_dra7_emu_swsup_config(pdev, true);
+	}
 
 	if (*pwrst > PWRDM_POWER_RET)
-		return 0;
+		goto out;
 
 	next_pwrst = request ? PWRDM_POWER_ON : *pwrst;
 
-	return pwrdm_set_next_pwrst(pwrdm, next_pwrst);
+	ret = pwrdm_set_next_pwrst(pwrdm, next_pwrst);
+
+out:
+	if (!request)
+		omap_iommu_dra7_emu_swsup_config(pdev, false);
+
+	return ret;
 }
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/omap4-common.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/omap4-common.c
@@ -314,10 +314,12 @@
 
 	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic");
 	gic_dist_base_addr = of_iomap(np, 0);
+	of_node_put(np);
 	WARN_ON(!gic_dist_base_addr);
 
 	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-twd-timer");
 	twd_base = of_iomap(np, 0);
+	of_node_put(np);
 	WARN_ON(!twd_base);
 
 skip_errata_init:
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/omap_device.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/omap_device.c
@@ -234,10 +234,12 @@
 		break;
 	case BUS_NOTIFY_BIND_DRIVER:
 		od = to_omap_device(pdev);
-		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) &&
-		    pm_runtime_status_suspended(dev)) {
+		if (od) {
 			od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
-			pm_runtime_set_active(dev);
+			if (od->_state == OMAP_DEVICE_STATE_ENABLED &&
+			    pm_runtime_status_suspended(dev)) {
+				pm_runtime_set_active(dev);
+			}
 		}
 		break;
 	case BUS_NOTIFY_ADD_DEVICE:
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/omap_hwmod.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/omap_hwmod.c
@@ -782,8 +782,10 @@
 
 	for_each_matching_node(np, ti_clkctrl_match_table) {
 		ret = _setup_clkctrl_provider(np);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			break;
+		}
 	}
 
 	return ret;
@@ -3535,7 +3537,7 @@
 };
 
 static const struct omap_hwmod_reset omap_reset_quirks[] = {
-	{ .match = "dss", .len = 3, .reset = omap_dss_reset, },
+	{ .match = "dss_core", .len = 8, .reset = omap_dss_reset, },
 	{ .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
 	{ .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
 	{ .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
@@ -3656,6 +3658,8 @@
 		oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
 	if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
 		oh->flags |= HWMOD_SWSUP_MSTANDBY;
+	if (data->cfg->quirks & SYSC_QUIRK_CLKDM_NOAUTO)
+		oh->flags |= HWMOD_CLKDM_NOAUTO;
 
 	error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
 					rev_offs, sysc_offs, syss_offs,
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/pdata-quirks.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/pdata-quirks.c
@@ -7,7 +7,6 @@
 #include <linux/clk.h>
 #include <linux/davinci_emac.h>
 #include <linux/gpio.h>
-#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
@@ -45,6 +44,17 @@
 static struct of_dev_auxdata omap_auxdata_lookup[];
 static struct twl4030_gpio_platform_data twl_gpio_auxdata;
 
+#if IS_ENABLED(CONFIG_OMAP_IOMMU)
+int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
+				    u8 *pwrst);
+#else
+static inline int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev,
+						  bool request, u8 *pwrst)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_MACH_NOKIA_N8X0
 static void __init omap2420_n8x0_legacy_init(void)
 {
@@ -269,14 +279,6 @@
 	am35xx_emac_reset();
 }
 
-static struct platform_device omap3_rom_rng_device = {
-	.name		= "omap3-rom-rng",
-	.id		= -1,
-	.dev	= {
-		.platform_data	= rx51_secure_rng_call,
-	},
-};
-
 static void __init nokia_n900_legacy_init(void)
 {
 	hsmmc2_internal_input_clk();
@@ -292,9 +294,6 @@
 			pr_warn("RX-51: Not enabling ARM errata 430973 workaround\n");
 			pr_warn("Thumb binaries may crash randomly without this workaround\n");
 		}
-
-		pr_info("RX-51: Registering OMAP3 HWRNG device\n");
-		platform_device_register(&omap3_rom_rng_device);
 	}
 }
 
@@ -311,131 +310,18 @@
 }
 
 /* omap3pandora legacy devices */
-#define PANDORA_WIFI_IRQ_GPIO		21
-#define PANDORA_WIFI_NRESET_GPIO	23
 
 static struct platform_device pandora_backlight = {
 	.name	= "pandora-backlight",
 	.id	= -1,
 };
 
-static struct regulator_consumer_supply pandora_vmmc3_supply[] = {
-	REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2"),
-};
-
-static struct regulator_init_data pandora_vmmc3 = {
-	.constraints = {
-		.valid_ops_mask		= REGULATOR_CHANGE_STATUS,
-	},
-	.num_consumer_supplies	= ARRAY_SIZE(pandora_vmmc3_supply),
-	.consumer_supplies	= pandora_vmmc3_supply,
-};
-
-static struct fixed_voltage_config pandora_vwlan = {
-	.supply_name		= "vwlan",
-	.microvolts		= 1800000, /* 1.8V */
-	.startup_delay		= 50000, /* 50ms */
-	.init_data		= &pandora_vmmc3,
-};
-
-static struct platform_device pandora_vwlan_device = {
-	.name		= "reg-fixed-voltage",
-	.id		= 1,
-	.dev = {
-		.platform_data = &pandora_vwlan,
-	},
-};
-
-static struct gpiod_lookup_table pandora_vwlan_gpiod_table = {
-	.dev_id = "reg-fixed-voltage.1",
-	.table = {
-		/*
-		 * As this is a low GPIO number it should be at the first
-		 * GPIO bank.
-		 */
-		GPIO_LOOKUP("gpio-0-31", PANDORA_WIFI_NRESET_GPIO,
-			    NULL, GPIO_ACTIVE_HIGH),
-		{ },
-	},
-};
-
-static void pandora_wl1251_init_card(struct mmc_card *card)
-{
-	/*
-	 * We have TI wl1251 attached to MMC3. Pass this information to
-	 * SDIO core because it can't be probed by normal methods.
-	 */
-	if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) {
-		card->quirks |= MMC_QUIRK_NONSTD_SDIO;
-		card->cccr.wide_bus = 1;
-		card->cis.vendor = 0x104c;
-		card->cis.device = 0x9066;
-		card->cis.blksize = 512;
-		card->cis.max_dtr = 24000000;
-		card->ocr = 0x80;
-	}
-}
-
-static struct omap2_hsmmc_info pandora_mmc3[] = {
-	{
-		.mmc		= 3,
-		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
-		.init_card	= pandora_wl1251_init_card,
-	},
-	{}	/* Terminator */
-};
-
-static void __init pandora_wl1251_init(void)
-{
-	struct wl1251_platform_data pandora_wl1251_pdata;
-	int ret;
-
-	memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
-
-	pandora_wl1251_pdata.power_gpio = -1;
-
-	ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
-	if (ret < 0)
-		goto fail;
-
-	pandora_wl1251_pdata.irq = gpio_to_irq(PANDORA_WIFI_IRQ_GPIO);
-	if (pandora_wl1251_pdata.irq < 0)
-		goto fail_irq;
-
-	pandora_wl1251_pdata.use_eeprom = true;
-	ret = wl1251_set_platform_data(&pandora_wl1251_pdata);
-	if (ret < 0)
-		goto fail_irq;
-
-	return;
-
-fail_irq:
-	gpio_free(PANDORA_WIFI_IRQ_GPIO);
-fail:
-	pr_err("wl1251 board initialisation failed\n");
-}
-
 static void __init omap3_pandora_legacy_init(void)
 {
 	platform_device_register(&pandora_backlight);
-	gpiod_add_lookup_table(&pandora_vwlan_gpiod_table);
-	platform_device_register(&pandora_vwlan_device);
-	omap_hsmmc_init(pandora_mmc3);
-	omap_hsmmc_late_init(pandora_mmc3);
-	pandora_wl1251_init();
 }
 #endif /* CONFIG_ARCH_OMAP3 */
 
-#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
-static struct iommu_platform_data omap4_iommu_pdata = {
-	.reset_name = "mmu_cache",
-	.assert_reset = omap_device_assert_hardreset,
-	.deassert_reset = omap_device_deassert_hardreset,
-	.device_enable = omap_device_enable,
-	.device_idle = omap_device_idle,
-};
-#endif
-
 #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
 static struct wkup_m3_platform_data wkup_m3_data = {
 	.reset_name = "wkup_m3",
@@ -451,6 +337,10 @@
 #endif
 
 #ifdef CONFIG_SOC_DRA7XX
+static struct iommu_platform_data dra7_ipu1_dsp_iommu_pdata = {
+	.set_pwrdm_constraint = omap_iommu_set_pwrdm_constraint,
+};
+
 static struct omap_hsmmc_platform_data dra7_hsmmc_data_mmc1;
 static struct omap_hsmmc_platform_data dra7_hsmmc_data_mmc2;
 static struct omap_hsmmc_platform_data dra7_hsmmc_data_mmc3;
@@ -472,10 +362,14 @@
 
 static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk)
 {
+	struct clk_hw *hw = __clk_get_hw(clk);
 	struct clockdomain *clkdm = NULL;
 	struct clk_hw_omap *hwclk;
 
-	hwclk = to_clk_hw_omap(__clk_get_hw(clk));
+	hwclk = to_clk_hw_omap(hw);
+	if (!omap2_clk_is_hw_omap(hw))
+		return NULL;
+
 	if (hwclk && hwclk->clkdm_name)
 		clkdm = clkdm_lookup(hwclk->clkdm_name);
 
@@ -638,6 +532,7 @@
 	OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
 	OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
 		       &am35xx_emac_pdata),
+	OF_DEV_AUXDATA("nokia,n900-rom-rng", 0, NULL, rx51_secure_rng_call),
 	/* McBSP modules with sidetone core */
 #if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
 	OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
@@ -653,10 +548,6 @@
 		       &wkup_m3_data),
 #endif
 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
-	OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu",
-		       &omap4_iommu_pdata),
-	OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu",
-		       &omap4_iommu_pdata),
 	OF_DEV_AUXDATA("ti,omap4-smartreflex-iva", 0x4a0db000,
 		       "4a0db000.smartreflex", &omap_sr_pdata[OMAP_SR_IVA]),
 	OF_DEV_AUXDATA("ti,omap4-smartreflex-core", 0x4a0dd000,
@@ -671,6 +562,12 @@
 		       &dra7_hsmmc_data_mmc2),
 	OF_DEV_AUXDATA("ti,dra7-hsmmc", 0x480ad000, "480ad000.mmc",
 		       &dra7_hsmmc_data_mmc3),
+	OF_DEV_AUXDATA("ti,dra7-dsp-iommu", 0x40d01000, "40d01000.mmu",
+		       &dra7_ipu1_dsp_iommu_pdata),
+	OF_DEV_AUXDATA("ti,dra7-dsp-iommu", 0x41501000, "41501000.mmu",
+		       &dra7_ipu1_dsp_iommu_pdata),
+	OF_DEV_AUXDATA("ti,dra7-iommu", 0x58882000, "58882000.mmu",
+		       &dra7_ipu1_dsp_iommu_pdata),
 #endif
 	/* Common auxdata */
 	OF_DEV_AUXDATA("ti,sysc", 0, NULL, &ti_sysc_pdata),
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/pm34xx.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/pm34xx.c
@@ -194,6 +194,7 @@
 	int per_next_state = PWRDM_POWER_ON;
 	int core_next_state = PWRDM_POWER_ON;
 	u32 sdrc_pwr = 0;
+	int error;
 
 	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
 	switch (mpu_next_state) {
@@ -222,8 +223,11 @@
 	pwrdm_pre_transition(NULL);
 
 	/* PER */
-	if (per_next_state == PWRDM_POWER_OFF)
-		cpu_cluster_pm_enter();
+	if (per_next_state == PWRDM_POWER_OFF) {
+		error = cpu_cluster_pm_enter();
+		if (error)
+			return;
+	}
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/powerdomain.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/powerdomain.c
@@ -174,7 +174,7 @@
 		break;
 	case PWRDM_STATE_PREV:
 		prev = pwrdm_read_prev_pwrst(pwrdm);
-		if (pwrdm->state != prev)
+		if (prev >= 0 && pwrdm->state != prev)
 			pwrdm->state_counter[prev]++;
 		if (prev == PWRDM_POWER_RET)
 			_update_logic_membank_counters(pwrdm);
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/prm3xxx.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/prm3xxx.c
@@ -708,6 +708,7 @@
 	}
 
 	irq_num = of_irq_get(np, 0);
+	of_node_put(np);
 	if (irq_num == -EPROBE_DEFER)
 		return irq_num;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/sleep34xx.S
+++ linux-ein-5.4.0/arch/arm/mach-omap2/sleep34xx.S
@@ -72,7 +72,7 @@
 	stmfd	sp!, {lr}	@ save registers on stack
 	/* Setup so that we will disable and enable l2 */
 	mov	r1, #0x1
-	adrl	r3, l2dis_3630_offset	@ may be too distant for plain adr
+	adr	r3, l2dis_3630_offset
 	ldr	r2, [r3]		@ value for offset
 	str	r1, [r2, r3]		@ write to l2dis_3630
 	ldmfd	sp!, {pc}	@ restore regs and return
--- linux-ein-5.4.0.orig/arch/arm/mach-omap2/timer.c
+++ linux-ein-5.4.0/arch/arm/mach-omap2/timer.c
@@ -42,6 +42,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_data/dmtimer-omap.h>
 #include <linux/sched_clock.h>
+#include <linux/cpu.h>
 
 #include <asm/mach/time.h>
 
@@ -63,15 +64,28 @@
 
 /* Clockevent code */
 
-static struct omap_dm_timer clkev;
-static struct clock_event_device clockevent_gpt;
-
 /* Clockevent hwmod for am335x and am437x suspend */
 static struct omap_hwmod *clockevent_gpt_hwmod;
 
 /* Clockesource hwmod for am437x suspend */
 static struct omap_hwmod *clocksource_gpt_hwmod;
 
+struct dmtimer_clockevent {
+	struct clock_event_device dev;
+	struct omap_dm_timer timer;
+};
+
+static struct dmtimer_clockevent clockevent;
+
+static struct omap_dm_timer *to_dmtimer(struct clock_event_device *clockevent)
+{
+	struct dmtimer_clockevent *clkevt =
+		container_of(clockevent, struct dmtimer_clockevent, dev);
+	struct omap_dm_timer *timer = &clkevt->timer;
+
+	return timer;
+}
+
 #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
 static unsigned long arch_timer_freq;
 
@@ -83,24 +97,21 @@
 
 static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = &clockevent_gpt;
-
-	__omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
+	struct dmtimer_clockevent *clkevt = dev_id;
+	struct clock_event_device *evt = &clkevt->dev;
+	struct omap_dm_timer *timer = &clkevt->timer;
 
+	__omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW);
 	evt->event_handler(evt);
 	return IRQ_HANDLED;
 }
 
-static struct irqaction omap2_gp_timer_irq = {
-	.name		= "gp_timer",
-	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= omap2_gp_timer_interrupt,
-};
-
 static int omap2_gp_timer_set_next_event(unsigned long cycles,
 					 struct clock_event_device *evt)
 {
-	__omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
+	struct omap_dm_timer *timer = to_dmtimer(evt);
+
+	__omap_dm_timer_load_start(timer, OMAP_TIMER_CTRL_ST,
 				   0xffffffff - cycles, OMAP_TIMER_POSTED);
 
 	return 0;
@@ -108,22 +119,26 @@
 
 static int omap2_gp_timer_shutdown(struct clock_event_device *evt)
 {
-	__omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
+	struct omap_dm_timer *timer = to_dmtimer(evt);
+
+	__omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate);
+
 	return 0;
 }
 
 static int omap2_gp_timer_set_periodic(struct clock_event_device *evt)
 {
+	struct omap_dm_timer *timer = to_dmtimer(evt);
 	u32 period;
 
-	__omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
+	__omap_dm_timer_stop(timer, OMAP_TIMER_POSTED, timer->rate);
 
-	period = clkev.rate / HZ;
+	period = timer->rate / HZ;
 	period -= 1;
 	/* Looks like we need to first set the load value separately */
-	__omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, 0xffffffff - period,
+	__omap_dm_timer_write(timer, OMAP_TIMER_LOAD_REG, 0xffffffff - period,
 			      OMAP_TIMER_POSTED);
-	__omap_dm_timer_load_start(&clkev,
+	__omap_dm_timer_load_start(timer,
 				   OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
 				   0xffffffff - period, OMAP_TIMER_POSTED);
 	return 0;
@@ -137,26 +152,17 @@
 	omap_hwmod_idle(clockevent_gpt_hwmod);
 }
 
-static void omap_clkevt_unidle(struct clock_event_device *unused)
+static void omap_clkevt_unidle(struct clock_event_device *evt)
 {
+	struct omap_dm_timer *timer = to_dmtimer(evt);
+
 	if (!clockevent_gpt_hwmod)
 		return;
 
 	omap_hwmod_enable(clockevent_gpt_hwmod);
-	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+	__omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
 }
 
-static struct clock_event_device clockevent_gpt = {
-	.features		= CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_ONESHOT,
-	.rating			= 300,
-	.set_next_event		= omap2_gp_timer_set_next_event,
-	.set_state_shutdown	= omap2_gp_timer_shutdown,
-	.set_state_periodic	= omap2_gp_timer_set_periodic,
-	.set_state_oneshot	= omap2_gp_timer_shutdown,
-	.tick_resume		= omap2_gp_timer_shutdown,
-};
-
 static const struct of_device_id omap_timer_match[] __initconst = {
 	{ .compatible = "ti,omap2420-timer", },
 	{ .compatible = "ti,omap3430-timer", },
@@ -362,47 +368,104 @@
 }
 #endif
 
-static void __init omap2_gp_clockevent_init(int gptimer_id,
-						const char *fck_source,
-						const char *property)
+static void __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
+					      int gptimer_id,
+					      const char *fck_source,
+					      unsigned int features,
+					      const struct cpumask *cpumask,
+					      const char *property,
+					      int rating, const char *name)
 {
+	struct omap_dm_timer *timer = &clkevt->timer;
 	int res;
 
-	clkev.id = gptimer_id;
-	clkev.errata = omap_dm_timer_get_errata();
+	timer->id = gptimer_id;
+	timer->errata = omap_dm_timer_get_errata();
+	clkevt->dev.features = features;
+	clkevt->dev.rating = rating;
+	clkevt->dev.set_next_event = omap2_gp_timer_set_next_event;
+	clkevt->dev.set_state_shutdown = omap2_gp_timer_shutdown;
+	clkevt->dev.set_state_periodic = omap2_gp_timer_set_periodic;
+	clkevt->dev.set_state_oneshot = omap2_gp_timer_shutdown;
+	clkevt->dev.tick_resume = omap2_gp_timer_shutdown;
 
 	/*
 	 * For clock-event timers we never read the timer counter and
 	 * so we are not impacted by errata i103 and i767. Therefore,
 	 * we can safely ignore this errata for clock-event timers.
 	 */
-	__omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
+	__omap_dm_timer_override_errata(timer, OMAP_TIMER_ERRATA_I103_I767);
 
-	res = omap_dm_timer_init_one(&clkev, fck_source, property,
-				     &clockevent_gpt.name, OMAP_TIMER_POSTED);
+	res = omap_dm_timer_init_one(timer, fck_source, property,
+				     &clkevt->dev.name, OMAP_TIMER_POSTED);
 	BUG_ON(res);
 
-	omap2_gp_timer_irq.dev_id = &clkev;
-	setup_irq(clkev.irq, &omap2_gp_timer_irq);
+	clkevt->dev.cpumask = cpumask;
+	clkevt->dev.irq = omap_dm_timer_get_irq(timer);
 
-	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+	if (request_irq(clkevt->dev.irq, omap2_gp_timer_interrupt,
+			IRQF_TIMER | IRQF_IRQPOLL, name, clkevt))
+		pr_err("Failed to request irq %d (gp_timer)\n", clkevt->dev.irq);
 
-	clockevent_gpt.cpumask = cpu_possible_mask;
-	clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
-	clockevents_config_and_register(&clockevent_gpt, clkev.rate,
-					3, /* Timer internal resynch latency */
-					0xffffffff);
+	__omap_dm_timer_int_enable(timer, OMAP_TIMER_INT_OVERFLOW);
 
 	if (soc_is_am33xx() || soc_is_am43xx()) {
-		clockevent_gpt.suspend = omap_clkevt_idle;
-		clockevent_gpt.resume = omap_clkevt_unidle;
+		clkevt->dev.suspend = omap_clkevt_idle;
+		clkevt->dev.resume = omap_clkevt_unidle;
 
 		clockevent_gpt_hwmod =
-			omap_hwmod_lookup(clockevent_gpt.name);
+			omap_hwmod_lookup(clkevt->dev.name);
 	}
 
-	pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
-		clkev.rate);
+	pr_info("OMAP clockevent source: %s at %lu Hz\n", clkevt->dev.name,
+		timer->rate);
+}
+
+static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
+
+static int omap_gptimer_starting_cpu(unsigned int cpu)
+{
+	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
+	struct clock_event_device *dev = &clkevt->dev;
+	struct omap_dm_timer *timer = &clkevt->timer;
+
+	clockevents_config_and_register(dev, timer->rate, 3, ULONG_MAX);
+	irq_force_affinity(dev->irq, cpumask_of(cpu));
+
+	return 0;
+}
+
+static int __init dmtimer_percpu_quirk_init(void)
+{
+	struct dmtimer_clockevent *clkevt;
+	struct clock_event_device *dev;
+	struct device_node *arm_timer;
+	struct omap_dm_timer *timer;
+	int cpu = 0;
+
+	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
+	if (of_device_is_available(arm_timer)) {
+		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
+		return 0;
+	}
+
+	for_each_possible_cpu(cpu) {
+		clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
+		dev = &clkevt->dev;
+		timer = &clkevt->timer;
+
+		dmtimer_clkevt_init_common(clkevt, 0, "timer_sys_ck",
+					   CLOCK_EVT_FEAT_ONESHOT,
+					   cpumask_of(cpu),
+					   "assigned-clock-parents",
+					   500, "percpu timer");
+	}
+
+	cpuhp_setup_state(CPUHP_AP_OMAP_DM_TIMER_STARTING,
+			  "clockevents/omap/gptimer:starting",
+			  omap_gptimer_starting_cpu, NULL);
+
+	return 0;
 }
 
 /* Clocksource code */
@@ -542,7 +605,15 @@
 {
 	omap_clk_init();
 	omap_dmtimer_init();
-	omap2_gp_clockevent_init(clkev_nr, clkev_src, clkev_prop);
+	dmtimer_clkevt_init_common(&clockevent, clkev_nr, clkev_src,
+				   CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+				   cpu_possible_mask, clkev_prop, 300, "clockevent");
+	clockevents_config_and_register(&clockevent.dev, clockevent.timer.rate,
+					3, /* Timer internal resynch latency */
+					0xffffffff);
+
+	if (soc_is_dra7xx())
+		dmtimer_percpu_quirk_init();
 
 	/* Enable the use of clocksource="gp_timer" kernel parameter */
 	if (use_gptimer_clksrc || gptimer)
@@ -571,7 +642,7 @@
 #endif /* CONFIG_ARCH_OMAP3 */
 
 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \
-	defined(CONFIG_SOC_AM43XX)
+	defined(CONFIG_SOC_AM43XX) || defined(CONFIG_SOC_DRA7XX)
 void __init omap3_gptimer_timer_init(void)
 {
 	__omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
@@ -629,6 +700,7 @@
 	}
 
 	rate = clk_get_rate(sys_clk);
+	clk_put(sys_clk);
 
 	if (soc_is_dra7xx()) {
 		/*
--- linux-ein-5.4.0.orig/arch/arm/mach-orion5x/board-dt.c
+++ linux-ein-5.4.0/arch/arm/mach-orion5x/board-dt.c
@@ -63,6 +63,9 @@
 	if (of_machine_is_compatible("maxtor,shared-storage-2"))
 		mss2_init();
 
+	if (of_machine_is_compatible("lacie,d2-network"))
+		d2net_init();
+
 	of_platform_default_populate(NULL, orion5x_auxdata_lookup, NULL);
 }
 
--- linux-ein-5.4.0.orig/arch/arm/mach-orion5x/common.h
+++ linux-ein-5.4.0/arch/arm/mach-orion5x/common.h
@@ -75,6 +75,12 @@
 static inline void mss2_init(void) {}
 #endif
 
+#ifdef CONFIG_MACH_D2NET_DT
+void d2net_init(void);
+#else
+static inline void d2net_init(void) {}
+#endif
+
 /*****************************************************************************
  * Helpers to access Orion registers
  ****************************************************************************/
--- linux-ein-5.4.0.orig/arch/arm/mach-pxa/cm-x300.c
+++ linux-ein-5.4.0/arch/arm/mach-pxa/cm-x300.c
@@ -355,13 +355,13 @@
 static struct gpiod_lookup_table cm_x300_spi_gpiod_table = {
 	.dev_id         = "spi_gpio",
 	.table          = {
-		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL,
+		GPIO_LOOKUP("pca9555.1", GPIO_LCD_SCL - GPIO_LCD_BASE,
 			    "sck", GPIO_ACTIVE_HIGH),
-		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN,
+		GPIO_LOOKUP("pca9555.1", GPIO_LCD_DIN - GPIO_LCD_BASE,
 			    "mosi", GPIO_ACTIVE_HIGH),
-		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT,
+		GPIO_LOOKUP("pca9555.1", GPIO_LCD_DOUT - GPIO_LCD_BASE,
 			    "miso", GPIO_ACTIVE_HIGH),
-		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS,
+		GPIO_LOOKUP("pca9555.1", GPIO_LCD_CS - GPIO_LCD_BASE,
 			    "cs", GPIO_ACTIVE_HIGH),
 		{ },
 	},
--- linux-ein-5.4.0.orig/arch/arm/mach-pxa/magician.c
+++ linux-ein-5.4.0/arch/arm/mach-pxa/magician.c
@@ -675,7 +675,7 @@
 static struct gpiod_lookup_table bq24022_gpiod_table = {
 	.dev_id = "gpio-regulator",
 	.table = {
-		GPIO_LOOKUP("gpio-pxa", EGPIO_MAGICIAN_BQ24022_ISET2,
+		GPIO_LOOKUP("htc-egpio-0", EGPIO_MAGICIAN_BQ24022_ISET2 - MAGICIAN_EGPIO_BASE,
 			    NULL, GPIO_ACTIVE_HIGH),
 		GPIO_LOOKUP("gpio-pxa", GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
 			    "enable", GPIO_ACTIVE_LOW),
--- linux-ein-5.4.0.orig/arch/arm/mach-pxa/sharpsl_pm.c
+++ linux-ein-5.4.0/arch/arm/mach-pxa/sharpsl_pm.c
@@ -220,8 +220,6 @@
 {
 	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
 }
-EXPORT_SYMBOL(sharpsl_battery_kick);
-
 
 static void sharpsl_battery_thread(struct work_struct *private_)
 {
--- linux-ein-5.4.0.orig/arch/arm/mach-pxa/spitz.c
+++ linux-ein-5.4.0/arch/arm/mach-pxa/spitz.c
@@ -9,7 +9,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>	/* symbol_get ; symbol_put */
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/gpio_keys.h>
@@ -514,17 +513,6 @@
 	.gpio_cs		= SPITZ_GPIO_ADS7846_CS,
 };
 
-static void spitz_bl_kick_battery(void)
-{
-	void (*kick_batt)(void);
-
-	kick_batt = symbol_get(sharpsl_battery_kick);
-	if (kick_batt) {
-		kick_batt();
-		symbol_put(sharpsl_battery_kick);
-	}
-}
-
 static struct corgi_lcd_platform_data spitz_lcdcon_info = {
 	.init_mode		= CORGI_LCD_MODE_VGA,
 	.max_intensity		= 0x2f,
@@ -532,7 +520,7 @@
 	.limit_mask		= 0x0b,
 	.gpio_backlight_cont	= SPITZ_GPIO_BACKLIGHT_CONT,
 	.gpio_backlight_on	= SPITZ_GPIO_BACKLIGHT_ON,
-	.kick_battery		= spitz_bl_kick_battery,
+	.kick_battery		= sharpsl_battery_kick,
 };
 
 static struct pxa2xx_spi_chip spitz_lcdcon_chip = {
--- linux-ein-5.4.0.orig/arch/arm/mach-pxa/tosa.c
+++ linux-ein-5.4.0/arch/arm/mach-pxa/tosa.c
@@ -295,9 +295,9 @@
 	.table = {
 		GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_nSD_DETECT,
 			    "cd", GPIO_ACTIVE_LOW),
-		GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_SD_WP,
+		GPIO_LOOKUP("sharp-scoop.0", TOSA_GPIO_SD_WP - TOSA_SCOOP_GPIO_BASE,
 			    "wp", GPIO_ACTIVE_LOW),
-		GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_PWR_ON,
+		GPIO_LOOKUP("sharp-scoop.0", TOSA_GPIO_PWR_ON - TOSA_SCOOP_GPIO_BASE,
 			    "power", GPIO_ACTIVE_HIGH),
 		{ },
 	},
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -143,7 +143,7 @@
 	.dev_id = "s3c2410-sdi",
 	.table = {
 		/* Card detect S3C2410_GPG(10) */
-		GPIO_LOOKUP("GPG", 10, "cd", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOG", 10, "cd", GPIO_ACTIVE_LOW),
 		{ },
 	},
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-h1940.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -468,9 +468,9 @@
 	.dev_id = "s3c2410-sdi",
 	.table = {
 		/* Card detect S3C2410_GPF(5) */
-		GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOF", 5, "cd", GPIO_ACTIVE_LOW),
 		/* Write protect S3C2410_GPH(8) */
-		GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_LOW),
 		{ },
 	},
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-jive.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-jive.c
@@ -237,11 +237,11 @@
 	unsigned long set;
 
 	if (options == NULL || options[0] == '\0')
-		return 0;
+		return 1;
 
 	if (kstrtoul(options, 10, &set)) {
 		printk(KERN_ERR "failed to parse mtdset=%s\n", options);
-		return 0;
+		return 1;
 	}
 
 	switch (set) {
@@ -256,7 +256,7 @@
 		       "using default.", set);
 	}
 
-	return 0;
+	return 1;
 }
 
 /* parse the mtdset= option given to the kernel command line */
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -244,9 +244,9 @@
 	.dev_id = "s3c2410-sdi",
 	.table = {
 		/* Card detect S3C2410_GPG(8) */
-		GPIO_LOOKUP("GPG", 8, "cd", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOG", 8, "cd", GPIO_ACTIVE_LOW),
 		/* Write protect S3C2410_GPH(8) */
-		GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_HIGH),
 		{ },
 	},
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-n30.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-n30.c
@@ -359,9 +359,9 @@
 	.dev_id = "s3c2410-sdi",
 	.table = {
 		/* Card detect S3C2410_GPF(1) */
-		GPIO_LOOKUP("GPF", 1, "cd", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOF", 1, "cd", GPIO_ACTIVE_LOW),
 		/* Write protect S3C2410_GPG(10) */
-		GPIO_LOOKUP("GPG", 10, "wp", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOG", 10, "wp", GPIO_ACTIVE_LOW),
 		{ },
 	},
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ linux-ein-5.4.0/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -567,9 +567,9 @@
 	.dev_id = "s3c2410-sdi",
 	.table = {
 		/* Card detect S3C2410_GPF(5) */
-		GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOF", 5, "cd", GPIO_ACTIVE_LOW),
 		/* Write protect S3C2410_GPH(8) */
-		GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_LOW),
 		{ },
 	},
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-s5pv210/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-s5pv210/Kconfig
@@ -8,7 +8,6 @@
 config ARCH_S5PV210
 	bool "Samsung S5PV210/S5PC110"
 	depends on ARCH_MULTI_V7
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARM_VIC
 	select CLKSRC_SAMSUNG_PWM
 	select COMMON_CLK_SAMSUNG
--- linux-ein-5.4.0.orig/arch/arm/mach-sa1100/assabet.c
+++ linux-ein-5.4.0/arch/arm/mach-sa1100/assabet.c
@@ -653,7 +653,7 @@
  */
 static void __init get_assabet_scr(void)
 {
-	unsigned long uninitialized_var(scr), i;
+	unsigned long scr, i;
 
 	GPDR |= 0x3fc;			/* Configure GPIO 9:2 as outputs */
 	GPSR = 0x3fc;			/* Write 0xFF to GPIO 9:2 */
--- linux-ein-5.4.0.orig/arch/arm/mach-sa1100/jornada720_ssp.c
+++ linux-ein-5.4.0/arch/arm/mach-sa1100/jornada720_ssp.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
  *  arch/arm/mac-sa1100/jornada720_ssp.c
  *
  *  Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
@@ -26,6 +26,7 @@
 
 /**
  * jornada_ssp_reverse - reverses input byte
+ * @byte: input byte to reverse
  *
  * we need to reverse all data we receive from the mcu due to its physical location
  * returns : 01110111 -> 11101110
@@ -46,6 +47,7 @@
 
 /**
  * jornada_ssp_byte - waits for ready ssp bus and sends byte
+ * @byte: input byte to transmit
  *
  * waits for fifo buffer to clear and then transmits, if it doesn't then we will
  * timeout after <timeout> rounds. Needs mcu running before its called.
@@ -77,6 +79,7 @@
 
 /**
  * jornada_ssp_inout - decide if input is command or trading byte
+ * @byte: input byte to send (may be %TXDUMMY)
  *
  * returns : (jornada_ssp_byte(byte)) on success
  *         : %-ETIMEDOUT on timeout failure
--- linux-ein-5.4.0.orig/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
+++ linux-ein-5.4.0/arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
@@ -125,6 +125,7 @@
 
 	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
 		list_del(&pos->list);
+		of_node_put(pos->np);
 		kfree(pos);
 	}
 
@@ -154,8 +155,10 @@
 		return -ENODEV;
 
 	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
-		if (!of_device_is_available(np))
+		if (!of_device_is_available(np)) {
+			of_node_put(np);
 			break;
+		}
 
 		ret = of_property_read_u32(np, "reg", &addr);
 		if (ret)	/* Skip invalid entry and continue */
@@ -164,6 +167,7 @@
 		quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
 		if (!quirk) {
 			ret = -ENOMEM;
+			of_node_put(np);
 			goto err_mem;
 		}
 
@@ -171,11 +175,12 @@
 		memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
 
 		quirk->id = id;
-		quirk->np = np;
+		quirk->np = of_node_get(np);
 		quirk->i2c_msg.addr = addr;
 
 		ret = of_irq_parse_one(np, 0, argsa);
 		if (ret) {	/* Skip invalid entry and continue */
+			of_node_put(np);
 			kfree(quirk);
 			continue;
 		}
@@ -222,6 +227,7 @@
 err_mem:
 	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
 		list_del(&pos->list);
+		of_node_put(pos->np);
 		kfree(pos);
 	}
 
--- linux-ein-5.4.0.orig/arch/arm/mach-socfpga/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-socfpga/Kconfig
@@ -2,6 +2,7 @@
 menuconfig ARCH_SOCFPGA
 	bool "Altera SOCFPGA family"
 	depends on ARCH_MULTI_V7
+	select ARCH_HAS_RESET_CONTROLLER
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARM_AMBA
 	select ARM_GIC
@@ -19,6 +20,7 @@
 	select PL310_ERRATA_727915
 	select PL310_ERRATA_753970 if PL310
 	select PL310_ERRATA_769419
+	select RESET_CONTROLLER
 
 if ARCH_SOCFPGA
 config SOCFPGA_SUSPEND
--- linux-ein-5.4.0.orig/arch/arm/mach-socfpga/core.h
+++ linux-ein-5.4.0/arch/arm/mach-socfpga/core.h
@@ -33,7 +33,7 @@
 u32 socfpga_sdram_self_refresh(u32 sdr_base);
 extern unsigned int socfpga_sdram_self_refresh_sz;
 
-extern char secondary_trampoline, secondary_trampoline_end;
+extern char secondary_trampoline[], secondary_trampoline_end[];
 
 extern unsigned long socfpga_cpu1start_addr;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-socfpga/platsmp.c
+++ linux-ein-5.4.0/arch/arm/mach-socfpga/platsmp.c
@@ -20,14 +20,14 @@
 
 static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-	int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
+	int trampoline_size = secondary_trampoline_end - secondary_trampoline;
 
 	if (socfpga_cpu1start_addr) {
 		/* This will put CPU #1 into reset. */
 		writel(RSTMGR_MPUMODRST_CPU1,
 		       rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
 
-		memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
+		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
 
 		writel(__pa_symbol(secondary_startup),
 		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
@@ -45,12 +45,12 @@
 
 static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-	int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
+	int trampoline_size = secondary_trampoline_end - secondary_trampoline;
 
 	if (socfpga_cpu1start_addr) {
 		writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr +
 		       SOCFPGA_A10_RSTMGR_MODMPURST);
-		memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
+		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
 
 		writel(__pa_symbol(secondary_startup),
 		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff));
--- linux-ein-5.4.0.orig/arch/arm/mach-socfpga/pm.c
+++ linux-ein-5.4.0/arch/arm/mach-socfpga/pm.c
@@ -49,14 +49,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);
@@ -67,7 +67,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 */
@@ -81,6 +81,8 @@
 	if (!socfpga_sdram_self_refresh_in_ocram)
 		ret = -EFAULT;
 
+put_device:
+	put_device(&pdev->dev);
 put_node:
 	of_node_put(np);
 
--- linux-ein-5.4.0.orig/arch/arm/mach-sunxi/mc_smp.c
+++ linux-ein-5.4.0/arch/arm/mach-sunxi/mc_smp.c
@@ -804,16 +804,16 @@
 	for (i = 0; i < ARRAY_SIZE(sunxi_mc_smp_data); i++) {
 		ret = of_property_match_string(node, "enable-method",
 					       sunxi_mc_smp_data[i].enable_method);
-		if (!ret)
+		if (ret >= 0)
 			break;
 	}
 
-	is_a83t = sunxi_mc_smp_data[i].is_a83t;
-
 	of_node_put(node);
-	if (ret)
+	if (ret < 0)
 		return -ENODEV;
 
+	is_a83t = sunxi_mc_smp_data[i].is_a83t;
+
 	if (!sunxi_mc_smp_cpu_table_init())
 		return -EINVAL;
 
--- linux-ein-5.4.0.orig/arch/arm/mach-sunxi/sunxi.c
+++ linux-ein-5.4.0/arch/arm/mach-sunxi/sunxi.c
@@ -66,6 +66,7 @@
 	"allwinner,sun8i-h2-plus",
 	"allwinner,sun8i-h3",
 	"allwinner,sun8i-r40",
+	"allwinner,sun8i-v3",
 	"allwinner,sun8i-v3s",
 	NULL,
 };
--- linux-ein-5.4.0.orig/arch/arm/mach-tango/Kconfig
+++ linux-ein-5.4.0/arch/arm/mach-tango/Kconfig
@@ -3,7 +3,6 @@
 	bool "Sigma Designs Tango4 (SMP87xx)"
 	depends on ARCH_MULTI_V7
 	# Cortex-A9 MPCore r3p0, PL310 r3p2
-	select ARCH_HAS_HOLES_MEMORYMODEL
 	select ARM_ERRATA_754322
 	select ARM_ERRATA_764369 if SMP
 	select ARM_ERRATA_775420
--- linux-ein-5.4.0.orig/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ linux-ein-5.4.0/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -203,7 +203,7 @@
 {
 	pr_info_once(
 		"Disabling cpuidle LP2 state, since PCIe IRQs are in use\n");
-	tegra_idle_driver.states[1].disabled = true;
+	cpuidle_driver_state_disabled(&tegra_idle_driver, 1, true);
 }
 
 int __init tegra20_cpuidle_init(void)
--- linux-ein-5.4.0.orig/arch/arm/mach-tegra/reset-handler.S
+++ linux-ein-5.4.0/arch/arm/mach-tegra/reset-handler.S
@@ -44,16 +44,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-ein-5.4.0.orig/arch/arm/mach-tegra/sleep-tegra30.S
+++ linux-ein-5.4.0/arch/arm/mach-tegra/sleep-tegra30.S
@@ -370,6 +370,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
@@ -630,7 +638,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-ein-5.4.0.orig/arch/arm/mach-tegra/tegra.c
+++ linux-ein-5.4.0/arch/arm/mach-tegra/tegra.c
@@ -106,8 +106,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-ein-5.4.0.orig/arch/arm/mach-vexpress/dcscb.c
+++ linux-ein-5.4.0/arch/arm/mach-vexpress/dcscb.c
@@ -143,6 +143,7 @@
 	if (!node)
 		return -ENODEV;
 	dcscb_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!dcscb_base)
 		return -EADDRNOTAVAIL;
 	cfg = readl_relaxed(dcscb_base + DCS_CFG_R);
--- linux-ein-5.4.0.orig/arch/arm/mach-vexpress/spc.c
+++ linux-ein-5.4.0/arch/arm/mach-vexpress/spc.c
@@ -551,8 +551,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 */
@@ -578,8 +579,17 @@
 			continue;
 		}
 
+		cluster = topology_physical_package_id(cpu_dev->id);
+		if (cluster < 0 || 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-ein-5.4.0.orig/arch/arm/mach-zynq/common.c
+++ linux-ein-5.4.0/arch/arm/mach-zynq/common.c
@@ -77,6 +77,7 @@
 	}
 
 	zynq_devcfg_base = of_iomap(np, 0);
+	of_node_put(np);
 	if (!zynq_devcfg_base) {
 		pr_err("%s: Unable to map I/O memory\n", __func__);
 		return -1;
--- linux-ein-5.4.0.orig/arch/arm/mach-zynq/slcr.c
+++ linux-ein-5.4.0/arch/arm/mach-zynq/slcr.c
@@ -213,6 +213,7 @@
 	zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
 	if (IS_ERR(zynq_slcr_regmap)) {
 		pr_err("%s: failed to find zynq-slcr\n", __func__);
+		of_node_put(np);
 		return -ENODEV;
 	}
 
--- linux-ein-5.4.0.orig/arch/arm/mm/Kconfig
+++ linux-ein-5.4.0/arch/arm/mm/Kconfig
@@ -743,6 +743,7 @@
 config CPU_BIG_ENDIAN
 	bool "Build big-endian kernel"
 	depends on ARCH_SUPPORTS_BIG_ENDIAN
+	depends on !LD_IS_LLD
 	help
 	  Say Y if you plan on running a kernel in big-endian mode.
 	  Note that your board must be properly built and your board
@@ -752,7 +753,7 @@
 config CPU_ENDIAN_BE8
 	bool
 	depends on CPU_BIG_ENDIAN
-	default CPU_V6 || CPU_V6K || CPU_V7
+	default CPU_V6 || CPU_V6K || CPU_V7 || CPU_V7M
 	help
 	  Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors.
 
@@ -832,6 +833,7 @@
 
 config CPU_SPECTRE
 	bool
+	select GENERIC_CPU_VULNERABILITIES
 
 config HARDEN_BRANCH_PREDICTOR
 	bool "Harden the branch predictor against aliasing attacks" if EXPERT
@@ -852,6 +854,16 @@
 
 	   If unsure, say Y.
 
+config HARDEN_BRANCH_HISTORY
+	bool "Harden Spectre style attacks against branch history" if EXPERT
+	depends on CPU_SPECTRE
+	default y
+	help
+	  Speculation attacks against some high-performance processors can
+	  make use of branch history to influence future speculation. When
+	  taking an exception, a sequence of branches overwrites the branch
+	  history, or branch history is invalidated.
+
 config TLS_REG_EMUL
 	bool
 	select NEED_KUSER_HELPERS
--- linux-ein-5.4.0.orig/arch/arm/mm/alignment.c
+++ linux-ein-5.4.0/arch/arm/mm/alignment.c
@@ -799,7 +799,7 @@
 static int
 do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
-	union offset_union uninitialized_var(offset);
+	union offset_union offset;
 	unsigned long instrptr;
 	int (*handler)(unsigned long addr, u32 instr, struct pt_regs *regs);
 	unsigned int type;
@@ -935,6 +935,9 @@
 	if (type == TYPE_LDST)
 		do_alignment_finish_ldst(addr, instr, regs, offset);
 
+	if (thumb_mode(regs))
+		regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+
 	return 0;
 
  bad_or_fault:
--- linux-ein-5.4.0.orig/arch/arm/mm/cache-l2x0.c
+++ linux-ein-5.4.0/arch/arm/mm/cache-l2x0.c
@@ -867,6 +867,11 @@
 		l2x0_saved_regs.aux_ctrl = aux;
 
 		data->enable(l2x0_base, data->num_lock);
+	} else {
+		pr_info("%s cache controller enabled try to unlock\n",
+			data->type);
+
+		data->unlock(l2x0_base, data->num_lock);
 	}
 
 	outer_cache = fns;
@@ -1249,20 +1254,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-ein-5.4.0.orig/arch/arm/mm/dma-mapping-nommu.c
+++ linux-ein-5.4.0/arch/arm/mm/dma-mapping-nommu.c
@@ -35,7 +35,7 @@
 				 unsigned long attrs)
 
 {
-	void *ret = dma_alloc_from_global_coherent(size, dma_handle);
+	void *ret = dma_alloc_from_global_coherent(dev, size, dma_handle);
 
 	/*
 	 * dma_alloc_from_global_coherent() may fail because:
--- linux-ein-5.4.0.orig/arch/arm/mm/dma-mapping.c
+++ linux-ein-5.4.0/arch/arm/mm/dma-mapping.c
@@ -221,7 +221,7 @@
 
 static int __dma_supported(struct device *dev, u64 mask, bool warn)
 {
-	unsigned long max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);
+	unsigned long max_dma_pfn = min(max_pfn - 1, arm_dma_pfn_limit);
 
 	/*
 	 * Translate the device's DMA mask to a PFN limit.  This
@@ -2332,15 +2332,15 @@
 }
 
 #ifdef CONFIG_SWIOTLB
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_page_cpu_to_dev(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
 			      size, dir);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_page_dev_to_cpu(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
 			      size, dir);
--- linux-ein-5.4.0.orig/arch/arm/mm/fault.c
+++ linux-ein-5.4.0/arch/arm/mm/fault.c
@@ -124,7 +124,7 @@
 	show_pte(KERN_ALERT, mm, addr);
 	die("Oops", regs, fsr);
 	bust_spinlocks(0);
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/arm/mm/init.c
+++ linux-ein-5.4.0/arch/arm/mm/init.c
@@ -176,11 +176,22 @@
 int pfn_valid(unsigned long pfn)
 {
 	phys_addr_t addr = __pfn_to_phys(pfn);
+	unsigned long pageblock_size = PAGE_SIZE * pageblock_nr_pages;
 
 	if (__phys_to_pfn(addr) != pfn)
 		return 0;
 
-	return memblock_is_map_memory(__pfn_to_phys(pfn));
+	/*
+	 * If address less than pageblock_size bytes away from a present
+	 * memory chunk there still will be a memory map entry for it
+	 * because we round freed memory map to the pageblock boundaries.
+	 */
+	if (memblock_overlaps_region(&memblock.memory,
+				     ALIGN_DOWN(addr, pageblock_size),
+				     pageblock_size))
+		return 1;
+
+	return 0;
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
@@ -274,7 +285,6 @@
 	if (mdesc->reserve)
 		mdesc->reserve();
 
-	early_init_fdt_reserve_self();
 	early_init_fdt_scan_reserved_mem();
 
 	/* reserve memory for DMA contiguous allocations */
@@ -323,7 +333,7 @@
 		*p++ = 0xe7fddef0;
 }
 
-static inline void
+static inline void __init
 free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
 	struct page *start_pg, *end_pg;
@@ -372,14 +382,14 @@
 		 */
 		start = min(start,
 				 ALIGN(prev_end, PAGES_PER_SECTION));
-#else
+#endif
 		/*
-		 * Align down here since the VM subsystem insists that the
-		 * memmap entries are valid from the bank start aligned to
-		 * MAX_ORDER_NR_PAGES.
+		 * Align down here since many operations in VM subsystem
+		 * presume that there are no holes in the memory map inside
+		 * a pageblock
 		 */
-		start = round_down(start, MAX_ORDER_NR_PAGES);
-#endif
+		start = round_down(start, pageblock_nr_pages);
+
 		/*
 		 * If we had a previous bank, and there is a space
 		 * between the current bank and the previous, free it.
@@ -388,18 +398,20 @@
 			free_memmap(prev_end, start);
 
 		/*
-		 * Align up here since the VM subsystem insists that the
-		 * memmap entries are valid from the bank end aligned to
-		 * MAX_ORDER_NR_PAGES.
+		 * Align up here since many operations in VM subsystem
+		 * presume that there are no holes in the memory map inside
+		 * a pageblock
 		 */
 		prev_end = ALIGN(memblock_region_memory_end_pfn(reg),
-				 MAX_ORDER_NR_PAGES);
+				 pageblock_nr_pages);
 	}
 
 #ifdef CONFIG_SPARSEMEM
-	if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
+	if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) {
+		prev_end = ALIGN(prev_end, pageblock_nr_pages);
 		free_memmap(prev_end,
 			    ALIGN(prev_end, PAGES_PER_SECTION));
+	}
 #endif
 }
 
@@ -470,7 +482,11 @@
 void __init mem_init(void)
 {
 #ifdef CONFIG_ARM_LPAE
-	swiotlb_init(1);
+	if (swiotlb_force == SWIOTLB_FORCE ||
+	    max_pfn > arm_dma_pfn_limit)
+		swiotlb_init(1);
+	else
+		swiotlb_force = SWIOTLB_NO_FORCE;
 #endif
 
 	set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
--- linux-ein-5.4.0.orig/arch/arm/mm/ioremap.c
+++ linux-ein-5.4.0/arch/arm/mm/ioremap.c
@@ -27,6 +27,7 @@
 #include <linux/vmalloc.h>
 #include <linux/io.h>
 #include <linux/sizes.h>
+#include <linux/memblock.h>
 
 #include <asm/cp15.h>
 #include <asm/cputype.h>
@@ -35,6 +36,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/set_memory.h>
 #include <asm/system_info.h>
 
 #include <asm/mach/map.h>
@@ -301,7 +303,8 @@
 	 * Don't allow RAM to be mapped with mismatched attributes - this
 	 * causes problems with ARMv6+
 	 */
-	if (WARN_ON(pfn_valid(pfn) && mtype != MT_MEMORY_RW))
+	if (WARN_ON(memblock_is_map_memory(PFN_PHYS(pfn)) &&
+		    mtype != MT_MEMORY_RW))
 		return NULL;
 
 	area = get_vm_area_caller(size, VM_IOREMAP, caller);
@@ -420,6 +423,11 @@
 			__builtin_return_address(0));
 }
 
+void __arm_iomem_set_ro(void __iomem *ptr, size_t size)
+{
+	set_memory_ro((unsigned long)ptr, PAGE_ALIGN(size) / PAGE_SIZE);
+}
+
 void *arch_memremap_wb(phys_addr_t phys_addr, size_t size)
 {
 	return (__force void *)arch_ioremap_caller(phys_addr, size,
@@ -498,3 +506,11 @@
 {
 	early_ioremap_setup();
 }
+
+bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
+				 unsigned long flags)
+{
+	unsigned long pfn = PHYS_PFN(offset);
+
+	return memblock_is_map_memory(pfn);
+}
--- linux-ein-5.4.0.orig/arch/arm/mm/mmu.c
+++ linux-ein-5.4.0/arch/arm/mm/mmu.c
@@ -39,6 +39,8 @@
 #include "mm.h"
 #include "tcm.h"
 
+extern unsigned long __atags_pointer;
+
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
@@ -227,12 +229,14 @@
 static int __init early_cachepolicy(char *p)
 {
 	pr_warn("cachepolicy kernel parameter not supported without cp15\n");
+	return 0;
 }
 early_param("cachepolicy", early_cachepolicy);
 
 static int __init noalign_setup(char *__unused)
 {
 	pr_warn("noalign kernel parameter not supported without cp15\n");
+	return 1;
 }
 __setup("noalign", noalign_setup);
 
@@ -312,6 +316,17 @@
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
 	},
+	[MT_MEMORY_RO] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+			     L_PTE_XN | L_PTE_RDONLY,
+		.prot_l1   = PMD_TYPE_TABLE,
+#ifdef CONFIG_ARM_LPAE
+		.prot_sect = PMD_TYPE_SECT | L_PMD_SECT_RDONLY | PMD_SECT_AP2,
+#else
+		.prot_sect = PMD_TYPE_SECT,
+#endif
+		.domain    = DOMAIN_KERNEL,
+	},
 	[MT_ROM] = {
 		.prot_sect = PMD_TYPE_SECT,
 		.domain    = DOMAIN_KERNEL,
@@ -413,9 +428,9 @@
 		     FIXADDR_END);
 	BUG_ON(idx >= __end_of_fixed_addresses);
 
-	/* we only support device mappings until pgprot_kernel has been set */
+	/* We support only device mappings before pgprot_kernel is set. */
 	if (WARN_ON(pgprot_val(prot) != pgprot_val(FIXMAP_PAGE_IO) &&
-		    pgprot_val(pgprot_kernel) == 0))
+		    pgprot_val(prot) && pgprot_val(pgprot_kernel) == 0))
 		return;
 
 	if (pgprot_val(prot))
@@ -511,6 +526,7 @@
 
 			/* Also setup NX memory mapping */
 			mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_XN;
+			mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_XN;
 		}
 		if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
 			/*
@@ -593,6 +609,7 @@
 		mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+		mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 #endif
 
 		/*
@@ -613,6 +630,8 @@
 			mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED;
 			mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S;
 			mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED;
+			mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY_RO].prot_pte |= L_PTE_SHARED;
 			mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED;
 			mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S;
 			mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED;
@@ -676,6 +695,8 @@
 	mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
 	mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
 	mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
+	mem_types[MT_MEMORY_RO].prot_sect |= ecc_mask | cp->pmd;
+	mem_types[MT_MEMORY_RO].prot_pte |= kern_pgprot;
 	mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
 	mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
 	mem_types[MT_ROM].prot_sect |= cp->pmd;
@@ -962,7 +983,7 @@
 		return;
 	}
 
-	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+	if (md->type == MT_DEVICE &&
 	    md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
 	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
 		pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
@@ -1352,6 +1373,15 @@
 	for (addr = VMALLOC_START; addr < (FIXADDR_TOP & PMD_MASK); addr += PMD_SIZE)
 		pmd_clear(pmd_off_k(addr));
 
+	if (__atags_pointer) {
+		/* create a read-only mapping of the device tree */
+		map.pfn = __phys_to_pfn(__atags_pointer & SECTION_MASK);
+		map.virtual = FDT_FIXED_BASE;
+		map.length = FDT_FIXED_SIZE;
+		map.type = MT_MEMORY_RO;
+		create_mapping(&map);
+	}
+
 	/*
 	 * Map the kernel if it is XIP.
 	 * It is always first in the modulearea.
@@ -1512,8 +1542,7 @@
 }
 
 #ifdef CONFIG_ARM_PV_FIXUP
-extern unsigned long __atags_pointer;
-typedef void pgtables_remap(long long offset, unsigned long pgd, void *bdata);
+typedef void pgtables_remap(long long offset, unsigned long pgd);
 pgtables_remap lpae_pgtables_remap_asm;
 
 /*
@@ -1526,7 +1555,6 @@
 	unsigned long pa_pgd;
 	unsigned int cr, ttbcr;
 	long long offset;
-	void *boot_data;
 
 	if (!mdesc->pv_fixup)
 		return;
@@ -1543,7 +1571,6 @@
 	 */
 	lpae_pgtables_remap = (pgtables_remap *)(unsigned long)__pa(lpae_pgtables_remap_asm);
 	pa_pgd = __pa(swapper_pg_dir);
-	boot_data = __va(__atags_pointer);
 	barrier();
 
 	pr_info("Switching physical address space to 0x%08llx\n",
@@ -1579,7 +1606,7 @@
 	 * needs to be assembly.  It's fairly simple, as we're using the
 	 * temporary tables setup by the initial assembly code.
 	 */
-	lpae_pgtables_remap(offset, pa_pgd, boot_data);
+	lpae_pgtables_remap(offset, pa_pgd);
 
 	/* Re-enable the caches and cacheable TLB walks */
 	asm volatile("mcr p15, 0, %0, c2, c0, 2" : : "r" (ttbcr));
--- linux-ein-5.4.0.orig/arch/arm/mm/nommu.c
+++ linux-ein-5.4.0/arch/arm/mm/nommu.c
@@ -26,6 +26,13 @@
 
 unsigned long vectors_base;
 
+/*
+ * empty_zero_page is a special page that is used for
+ * zero-initialized data and COW.
+ */
+struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
+
 #ifdef CONFIG_ARM_MPU
 struct mpu_rgn_info mpu_rgn_info;
 #endif
@@ -148,9 +155,21 @@
  */
 void __init paging_init(const struct machine_desc *mdesc)
 {
+	void *zero_page;
+
 	early_trap_init((void *)vectors_base);
 	mpu_setup();
+
+	/* allocate the zero page. */
+	zero_page = (void *)memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+	if (!zero_page)
+		panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
+		      __func__, PAGE_SIZE, PAGE_SIZE);
+
 	bootmem_init();
+
+	empty_zero_page = virt_to_page(zero_page);
+	flush_dcache_page(empty_zero_page);
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm1020.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm1020.S
@@ -491,7 +491,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm1020_proc_info,#object
 __arm1020_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm1020e.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm1020e.S
@@ -449,7 +449,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm1020e_proc_info,#object
 __arm1020e_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm1022.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm1022.S
@@ -443,7 +443,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm1022_proc_info,#object
 __arm1022_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm1026.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm1026.S
@@ -138,7 +138,7 @@
 	mov	ip, #0
 __flush_whole_cache:
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-1:	mrc	p15, 0, r15, c7, c14, 3		@ test, clean, invalidate
+1:	mrc	p15, 0, APSR_nzcv, c7, c14, 3		@ test, clean, invalidate
 	bne	1b
 #endif
 	tst	r2, #VM_EXEC
@@ -363,7 +363,7 @@
 #ifdef CONFIG_MMU
 	mov	r1, #0
 #ifndef CONFIG_CPU_DCACHE_DISABLE
-1:	mrc	p15, 0, r15, c7, c14, 3		@ test, clean, invalidate
+1:	mrc	p15, 0, APSR_nzcv, c7, c14, 3		@ test, clean, invalidate
 	bne	1b
 #endif
 #ifndef CONFIG_CPU_ICACHE_DISABLE
@@ -437,7 +437,7 @@
 	string	cpu_arm1026_name, "ARM1026EJ-S"
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm1026_proc_info,#object
 __arm1026_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm720.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm720.S
@@ -172,7 +172,7 @@
  * See <asm/procinfo.h> for a definition of this structure.
  */
 	
-		.section ".proc.info.init", #alloc
+		.section ".proc.info.init", "a"
 
 .macro arm720_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cpu_flush:req
 		.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm740.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm740.S
@@ -128,7 +128,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 	.type	__arm740_proc_info,#object
 __arm740_proc_info:
 	.long	0x41807400
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm7tdmi.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm7tdmi.S
@@ -72,7 +72,7 @@
 
 		.align
 
-		.section ".proc.info.init", #alloc
+		.section ".proc.info.init", "a"
 
 .macro arm7tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \
 	extra_hwcaps=0
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm920.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm920.S
@@ -434,7 +434,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm920_proc_info,#object
 __arm920_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm922.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm922.S
@@ -412,7 +412,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm922_proc_info,#object
 __arm922_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm925.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm925.S
@@ -477,7 +477,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro arm925_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
 	.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm926.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm926.S
@@ -131,7 +131,7 @@
 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
 	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
 #else
-1:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
+1:	mrc	p15, 0, APSR_nzcv, c7, c14, 3 	@ test,clean,invalidate
 	bne	1b
 #endif
 	tst	r2, #VM_EXEC
@@ -358,7 +358,7 @@
 	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
 #else
 @ && 'Clean & Invalidate whole DCache'
-1:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
+1:	mrc	p15, 0, APSR_nzcv, c7, c14, 3 	@ test,clean,invalidate
 	bne	1b
 #endif
 	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
@@ -460,7 +460,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm926_proc_info,#object
 __arm926_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm940.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm940.S
@@ -340,7 +340,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__arm940_proc_info,#object
 __arm940_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm946.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm946.S
@@ -395,7 +395,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 	.type	__arm946_proc_info,#object
 __arm946_proc_info:
 	.long	0x41009460
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-arm9tdmi.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-arm9tdmi.S
@@ -66,7 +66,7 @@
 
 		.align
 
-		.section ".proc.info.init", #alloc
+		.section ".proc.info.init", "a"
 
 .macro arm9tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
 		.type	__\name\()_proc_info, #object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-fa526.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-fa526.S
@@ -185,7 +185,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__fa526_proc_info,#object
 __fa526_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-feroceon.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-feroceon.S
@@ -571,7 +571,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req
 	.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-macros.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-macros.S
@@ -5,6 +5,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]
 	.if (TSK_ACTIVE_MM > IMM12_MASK)
@@ -341,6 +342,7 @@
 
 .macro define_tlb_functions name:req, flags_up:req, flags_smp
 	.type	\name\()_tlb_fns, #object
+	.align 2
 ENTRY(\name\()_tlb_fns)
 	.long	\name\()_flush_user_tlb_range
 	.long	\name\()_flush_kern_tlb_range
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-mohawk.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-mohawk.S
@@ -416,7 +416,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__88sv331x_proc_info,#object
 __88sv331x_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-sa110.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-sa110.S
@@ -196,7 +196,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	.type	__sa110_proc_info,#object
 __sa110_proc_info:
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-sa1100.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-sa1100.S
@@ -239,7 +239,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro sa1100_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
 	.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-v6.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-v6.S
@@ -261,7 +261,7 @@
 	string	cpu_elf_name, "v6"
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	/*
 	 * Match any ARMv6 processor core.
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-v7-bugs.c
+++ linux-ein-5.4.0/arch/arm/mm/proc-v7-bugs.c
@@ -7,8 +7,35 @@
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/proc-fns.h>
+#include <asm/spectre.h>
 #include <asm/system_misc.h>
 
+#ifdef CONFIG_ARM_PSCI
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+			     ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+
+	switch ((int)res.a0) {
+	case SMCCC_RET_SUCCESS:
+		return SPECTRE_MITIGATED;
+
+	case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+		return SPECTRE_UNAFFECTED;
+
+	default:
+		return SPECTRE_VULNERABLE;
+	}
+}
+#else
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
+{
+	return SPECTRE_VULNERABLE;
+}
+#endif
+
 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
 DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
 
@@ -37,13 +64,60 @@
 	arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
 }
 
-static void cpu_v7_spectre_init(void)
+static unsigned int spectre_v2_install_workaround(unsigned int method)
 {
 	const char *spectre_v2_method = NULL;
 	int cpu = smp_processor_id();
 
 	if (per_cpu(harden_branch_predictor_fn, cpu))
-		return;
+		return SPECTRE_MITIGATED;
+
+	switch (method) {
+	case SPECTRE_V2_METHOD_BPIALL:
+		per_cpu(harden_branch_predictor_fn, cpu) =
+			harden_branch_predictor_bpiall;
+		spectre_v2_method = "BPIALL";
+		break;
+
+	case SPECTRE_V2_METHOD_ICIALLU:
+		per_cpu(harden_branch_predictor_fn, cpu) =
+			harden_branch_predictor_iciallu;
+		spectre_v2_method = "ICIALLU";
+		break;
+
+	case SPECTRE_V2_METHOD_HVC:
+		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 SPECTRE_V2_METHOD_SMC:
+		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;
+	}
+
+	if (spectre_v2_method)
+		pr_info("CPU%u: Spectre v2: using %s workaround\n",
+			smp_processor_id(), spectre_v2_method);
+
+	return SPECTRE_MITIGATED;
+}
+#else
+static unsigned int spectre_v2_install_workaround(unsigned int method)
+{
+	pr_info_once("Spectre V2: workarounds disabled by configuration\n");
+
+	return SPECTRE_VULNERABLE;
+}
+#endif
+
+static void cpu_v7_spectre_v2_init(void)
+{
+	unsigned int state, method = 0;
 
 	switch (read_cpuid_part()) {
 	case ARM_CPU_PART_CORTEX_A8:
@@ -52,29 +126,37 @@
 	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";
+		state = SPECTRE_MITIGATED;
+		method = 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";
+		state = SPECTRE_MITIGATED;
+		method = SPECTRE_V2_METHOD_ICIALLU;
+		break;
+
+	case ARM_CPU_PART_BRAHMA_B53:
+		/* Requires no workaround */
+		state = SPECTRE_UNAFFECTED;
 		break;
 
-#ifdef CONFIG_ARM_PSCI
 	default:
 		/* Other ARM CPUs require no workaround */
-		if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
+		if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) {
+			state = SPECTRE_UNAFFECTED;
 			break;
+		}
 		/* fallthrough */
-		/* Cortex A57/A72 require firmware workaround */
+	/* Cortex A57/A72 require firmware workaround */
 	case ARM_CPU_PART_CORTEX_A57:
 	case ARM_CPU_PART_CORTEX_A72: {
 		struct arm_smccc_res res;
 
+		state = spectre_v2_get_cpu_fw_mitigation_state();
+		if (state != SPECTRE_MITIGATED)
+			break;
+
 		if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
 			break;
 
@@ -84,10 +166,7 @@
 					  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";
+			method = SPECTRE_V2_METHOD_HVC;
 			break;
 
 		case PSCI_CONDUIT_SMC:
@@ -95,29 +174,97 @@
 					  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";
+			method = SPECTRE_V2_METHOD_SMC;
 			break;
 
 		default:
+			state = SPECTRE_VULNERABLE;
 			break;
 		}
 	}
-#endif
 	}
 
-	if (spectre_v2_method)
-		pr_info("CPU%u: Spectre v2: using %s workaround\n",
-			smp_processor_id(), spectre_v2_method);
+	if (state == SPECTRE_MITIGATED)
+		state = spectre_v2_install_workaround(method);
+
+	spectre_v2_update_state(state, method);
+}
+
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+static int spectre_bhb_method;
+
+static const char *spectre_bhb_method_name(int method)
+{
+	switch (method) {
+	case SPECTRE_V2_METHOD_LOOP8:
+		return "loop";
+
+	case SPECTRE_V2_METHOD_BPIALL:
+		return "BPIALL";
+
+	default:
+		return "unknown";
+	}
+}
+
+static int spectre_bhb_install_workaround(int method)
+{
+	if (spectre_bhb_method != method) {
+		if (spectre_bhb_method) {
+			pr_err("CPU%u: Spectre BHB: method disagreement, system vulnerable\n",
+			       smp_processor_id());
+
+			return SPECTRE_VULNERABLE;
+		}
+
+		if (spectre_bhb_update_vectors(method) == SPECTRE_VULNERABLE)
+			return SPECTRE_VULNERABLE;
+
+		spectre_bhb_method = method;
+
+		pr_info("CPU%u: Spectre BHB: enabling %s workaround for all CPUs\n",
+			smp_processor_id(), spectre_bhb_method_name(method));
+	}
+
+	return SPECTRE_MITIGATED;
 }
 #else
-static void cpu_v7_spectre_init(void)
+static int spectre_bhb_install_workaround(int method)
 {
+	return SPECTRE_VULNERABLE;
 }
 #endif
 
+static void cpu_v7_spectre_bhb_init(void)
+{
+	unsigned int state, method = 0;
+
+	switch (read_cpuid_part()) {
+	case ARM_CPU_PART_CORTEX_A15:
+	case ARM_CPU_PART_BRAHMA_B15:
+	case ARM_CPU_PART_CORTEX_A57:
+	case ARM_CPU_PART_CORTEX_A72:
+		state = SPECTRE_MITIGATED;
+		method = SPECTRE_V2_METHOD_LOOP8;
+		break;
+
+	case ARM_CPU_PART_CORTEX_A73:
+	case ARM_CPU_PART_CORTEX_A75:
+		state = SPECTRE_MITIGATED;
+		method = SPECTRE_V2_METHOD_BPIALL;
+		break;
+
+	default:
+		state = SPECTRE_UNAFFECTED;
+		break;
+	}
+
+	if (state == SPECTRE_MITIGATED)
+		state = spectre_bhb_install_workaround(method);
+
+	spectre_v2_update_state(state, method);
+}
+
 static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
 						  u32 mask, const char *msg)
 {
@@ -146,16 +293,18 @@
 void cpu_v7_ca8_ibe(void)
 {
 	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
-		cpu_v7_spectre_init();
+		cpu_v7_spectre_v2_init();
 }
 
 void cpu_v7_ca15_ibe(void)
 {
 	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
-		cpu_v7_spectre_init();
+		cpu_v7_spectre_v2_init();
+	cpu_v7_spectre_bhb_init();
 }
 
 void cpu_v7_bugs_init(void)
 {
-	cpu_v7_spectre_init();
+	cpu_v7_spectre_v2_init();
+	cpu_v7_spectre_bhb_init();
 }
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-v7.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-v7.S
@@ -644,7 +644,7 @@
 	string	cpu_elf_name, "v7"
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 	/*
 	 * Standard v7 proc info content
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-v7m.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-v7m.S
@@ -93,7 +93,7 @@
 	ret	lr
 ENDPROC(cpu_cm7_proc_fin)
 
-	.section ".init.text", #alloc, #execinstr
+	.section ".init.text", "ax"
 
 __v7m_cm7_setup:
 	mov	r8, #(V7M_SCB_CCR_DC | V7M_SCB_CCR_IC| V7M_SCB_CCR_BP)
@@ -177,7 +177,7 @@
 	string cpu_elf_name "v7m"
 	string cpu_v7m_name "ARMv7-M"
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro __v7m_proc name, initfunc, cache_fns = nop_cache_fns, hwcaps = 0,  proc_fns = v7m_processor_functions
 	.long	0			/* proc_info_list.__cpu_mm_mmu_flags */
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-xsc3.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-xsc3.S
@@ -496,7 +496,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro xsc3_proc_info name:req, cpu_val:req, cpu_mask:req
 	.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/proc-xscale.S
+++ linux-ein-5.4.0/arch/arm/mm/proc-xscale.S
@@ -610,7 +610,7 @@
 
 	.align
 
-	.section ".proc.info.init", #alloc
+	.section ".proc.info.init", "a"
 
 .macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
 	.type	__\name\()_proc_info,#object
--- linux-ein-5.4.0.orig/arch/arm/mm/pv-fixup-asm.S
+++ linux-ein-5.4.0/arch/arm/mm/pv-fixup-asm.S
@@ -39,8 +39,8 @@
 
 	/* Update level 2 entries for the boot data */
 	add	r7, r2, #0x1000
-	add	r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER
-	bic	r7, r7, #(1 << L2_ORDER) - 1
+	movw	r3, #FDT_FIXED_BASE >> (SECTION_SHIFT - L2_ORDER)
+	add	r7, r7, r3
 	ldrd	r4, r5, [r7]
 	adds	r4, r4, r0
 	adc	r5, r5, r1
--- linux-ein-5.4.0.orig/arch/arm/net/bpf_jit_32.c
+++ linux-ein-5.4.0/arch/arm/net/bpf_jit_32.c
@@ -36,6 +36,10 @@
  *                        +-----+
  *                        |RSVD | JIT scratchpad
  * current ARM_SP =>      +-----+ <= (BPF_FP - STACK_SIZE + SCRATCH_SIZE)
+ *                        | ... | caller-saved registers
+ *                        +-----+
+ *                        | ... | arguments passed on stack
+ * ARM_SP during call =>  +-----|
  *                        |     |
  *                        | ... | Function call stack
  *                        |     |
@@ -63,6 +67,12 @@
  *
  * When popping registers off the stack at the end of a BPF function, we
  * reference them via the current ARM_FP register.
+ *
+ * Some eBPF operations are implemented via a call to a helper function.
+ * Such calls are "invisible" in the eBPF code, so it is up to the calling
+ * program to preserve any caller-saved ARM registers during the call. The
+ * JIT emits code to push and pop those registers onto the stack, immediately
+ * above the callee stack frame.
  */
 #define CALLEE_MASK	(1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \
 			 1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R9 | \
@@ -70,6 +80,8 @@
 #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
 #define CALLEE_POP_MASK  (CALLEE_MASK | 1 << ARM_PC)
 
+#define CALLER_MASK	(1 << ARM_R0 | 1 << ARM_R1 | 1 << ARM_R2 | 1 << ARM_R3)
+
 enum {
 	/* Stack layout - these are offsets from (top of stack - 4) */
 	BPF_R2_HI,
@@ -464,6 +476,7 @@
 
 static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
 {
+	const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1);
 	const s8 *tmp = bpf2a32[TMP_REG_1];
 
 #if __LINUX_ARM_ARCH__ == 7
@@ -495,11 +508,17 @@
 		emit(ARM_MOV_R(ARM_R0, rm), ctx);
 	}
 
+	/* Push caller-saved registers on stack */
+	emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx);
+
 	/* Call appropriate function */
 	emit_mov_i(ARM_IP, op == BPF_DIV ?
 		   (u32)jit_udiv32 : (u32)jit_mod32, ctx);
 	emit_blx_r(ARM_IP, ctx);
 
+	/* Restore caller-saved registers from stack */
+	emit(ARM_POP(CALLER_MASK & ~exclude_mask), ctx);
+
 	/* Save return value */
 	if (rd != ARM_R0)
 		emit(ARM_MOV_R(rd, ARM_R0), ctx);
@@ -929,7 +948,11 @@
 	rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
 	/* Do LSR operation */
-	if (val < 32) {
+	if (val == 0) {
+		/* An immediate value of 0 encodes a shift amount of 32
+		 * for LSR. To shift by 0, don't do anything.
+		 */
+	} else if (val < 32) {
 		emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx);
 		emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx);
 		emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_LSR, val), ctx);
@@ -955,7 +978,11 @@
 	rd = arm_bpf_get_reg64(dst, tmp, ctx);
 
 	/* Do ARSH operation */
-	if (val < 32) {
+	if (val == 0) {
+		/* An immediate value of 0 encodes a shift amount of 32
+		 * for ASR. To shift by 0, don't do anything.
+		 */
+	} else if (val < 32) {
 		emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx);
 		emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx);
 		emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, val), ctx);
@@ -992,21 +1019,35 @@
 	arm_bpf_put_reg32(dst_hi, rd[0], ctx);
 }
 
+static bool is_ldst_imm(s16 off, const u8 size)
+{
+	s16 off_max = 0;
+
+	switch (size) {
+	case BPF_B:
+	case BPF_W:
+		off_max = 0xfff;
+		break;
+	case BPF_H:
+		off_max = 0xff;
+		break;
+	case BPF_DW:
+		/* Need to make sure off+4 does not overflow. */
+		off_max = 0xfff - 4;
+		break;
+	}
+	return -off_max <= off && off <= off_max;
+}
+
 /* *(size *)(dst + off) = src */
 static inline void emit_str_r(const s8 dst, const s8 src[],
-			      s32 off, struct jit_ctx *ctx, const u8 sz){
+			      s16 off, struct jit_ctx *ctx, const u8 sz){
 	const s8 *tmp = bpf2a32[TMP_REG_1];
-	s32 off_max;
 	s8 rd;
 
 	rd = arm_bpf_get_reg32(dst, tmp[1], ctx);
 
-	if (sz == BPF_H)
-		off_max = 0xff;
-	else
-		off_max = 0xfff;
-
-	if (off < 0 || off > off_max) {
+	if (!is_ldst_imm(off, sz)) {
 		emit_a32_mov_i(tmp[0], off, ctx);
 		emit(ARM_ADD_R(tmp[0], tmp[0], rd), ctx);
 		rd = tmp[0];
@@ -1035,18 +1076,12 @@
 
 /* dst = *(size*)(src + off) */
 static inline void emit_ldx_r(const s8 dst[], const s8 src,
-			      s32 off, struct jit_ctx *ctx, const u8 sz){
+			      s16 off, struct jit_ctx *ctx, const u8 sz){
 	const s8 *tmp = bpf2a32[TMP_REG_1];
 	const s8 *rd = is_stacked(dst_lo) ? tmp : dst;
 	s8 rm = src;
-	s32 off_max;
-
-	if (sz == BPF_H)
-		off_max = 0xff;
-	else
-		off_max = 0xfff;
 
-	if (off < 0 || off > off_max) {
+	if (!is_ldst_imm(off, sz)) {
 		emit_a32_mov_i(tmp[0], off, ctx);
 		emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);
 		rm = tmp[0];
@@ -1586,6 +1621,9 @@
 		rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
 		emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
 		break;
+	/* speculation barrier */
+	case BPF_ST | BPF_NOSPEC:
+		break;
 	/* ST: *(size *)(dst + off) = imm */
 	case BPF_ST | BPF_MEM | BPF_W:
 	case BPF_ST | BPF_MEM | BPF_H:
--- linux-ein-5.4.0.orig/arch/arm/nwfpe/Makefile
+++ linux-ein-5.4.0/arch/arm/nwfpe/Makefile
@@ -11,3 +11,9 @@
 				   entry.o
 
 nwfpe-$(CONFIG_FPE_NWFPE_XP)	+= extended_cpdo.o
+
+# Try really hard to avoid generating calls to __aeabi_uldivmod() from
+# float64_rem() due to loop elision.
+ifdef CONFIG_CC_IS_CLANG
+CFLAGS_softfloat.o	+= -mllvm -replexitval=never
+endif
--- linux-ein-5.4.0.orig/arch/arm/plat-samsung/Kconfig
+++ linux-ein-5.4.0/arch/arm/plat-samsung/Kconfig
@@ -241,6 +241,7 @@
 	depends on PM && DEBUG_KERNEL
 	depends on PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
 	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.rst>
--- linux-ein-5.4.0.orig/arch/arm/probes/decode.h
+++ linux-ein-5.4.0/arch/arm/probes/decode.h
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <asm/probes.h>
+#include <asm/ptrace.h>
 #include <asm/kprobes.h>
 
 void __init arm_probes_decode_init(void);
@@ -35,31 +36,6 @@
 #endif
 
 
-/*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- *	ITSTATE<1:0> are in CPSR<26:25>
- *	ITSTATE<7:2> are in CPSR<15:10>
- */
-static inline unsigned long it_advance(unsigned long cpsr)
-	{
-	if ((cpsr & 0x06000400) == 0) {
-		/* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
-		cpsr &= ~PSR_IT_MASK;
-	} else {
-		/* We need to shift left ITSTATE<4:0> */
-		const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
-		unsigned long it = cpsr & mask;
-		it <<= 1;
-		it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
-		it &= mask;
-		cpsr &= ~mask;
-		cpsr |= it;
-	}
-	return cpsr;
-}
-
 static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
 {
 	long cpsr = regs->ARM_cpsr;
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/checkers-common.c
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/checkers-common.c
@@ -40,7 +40,7 @@
  * Different from other insn uses imm8, the real addressing offset of
  * STRD in T32 encoding should be imm8 * 4. See ARMARM description.
  */
-enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
+static enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
 		struct arch_probes_insn *asi,
 		const struct decode_header *h)
 {
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/core.c
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/core.c
@@ -231,7 +231,7 @@
  * kprobe, and that level is reserved for user kprobe handlers, so we can't
  * risk encountering a new kprobe in an interrupt handler.
  */
-void __kprobes kprobe_handler(struct pt_regs *regs)
+static void __kprobes kprobe_handler(struct pt_regs *regs)
 {
 	struct kprobe *p, *cur;
 	struct kprobe_ctlblk *kcb;
@@ -534,7 +534,7 @@
 
 #endif /* !CONFIG_THUMB2_KERNEL */
 
-int __init arch_init_kprobes()
+int __init arch_init_kprobes(void)
 {
 	arm_probes_decode_init();
 #ifdef CONFIG_THUMB2_KERNEL
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/opt-arm.c
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/opt-arm.c
@@ -85,21 +85,21 @@
 			"optprobe_template_end:\n");
 
 #define TMPL_VAL_IDX \
-	((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_val - (unsigned long *)optprobe_template_entry)
 #define TMPL_CALL_IDX \
-	((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_call - (unsigned long *)optprobe_template_entry)
 #define TMPL_END_IDX \
-	((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_end - (unsigned long *)optprobe_template_entry)
 #define TMPL_ADD_SP \
-	((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_add_sp - (unsigned long *)optprobe_template_entry)
 #define TMPL_SUB_SP \
-	((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_sub_sp - (unsigned long *)optprobe_template_entry)
 #define TMPL_RESTORE_BEGIN \
-	((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_restore_begin - (unsigned long *)optprobe_template_entry)
 #define TMPL_RESTORE_ORIGN_INSN \
-	((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_restore_orig_insn - (unsigned long *)optprobe_template_entry)
 #define TMPL_RESTORE_END \
-	((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry)
+	((unsigned long *)optprobe_template_restore_end - (unsigned long *)optprobe_template_entry)
 
 /*
  * ARM can always optimize an instruction when using ARM ISA, except
@@ -145,8 +145,6 @@
 	}
 }
 
-extern void kprobe_handler(struct pt_regs *regs);
-
 static void
 optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
 {
@@ -234,7 +232,7 @@
 	}
 
 	/* Copy arch-dep-instance from template. */
-	memcpy(code, (unsigned long *)&optprobe_template_entry,
+	memcpy(code, (unsigned long *)optprobe_template_entry,
 			TMPL_END_IDX * sizeof(kprobe_opcode_t));
 
 	/* Adjust buffer according to instruction. */
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/test-core.c
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/test-core.c
@@ -720,7 +720,7 @@
 	[REG_TYPE_NOSPPCX]	= COVERAGE_ANY_REG | COVERAGE_SP,
 };
 
-unsigned coverage_start_registers(const struct decode_header *h)
+static unsigned coverage_start_registers(const struct decode_header *h)
 {
 	unsigned regs = 0;
 	int i;
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/test-core.h
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/test-core.h
@@ -453,3 +453,7 @@
 #else
 void kprobe_arm_test_cases(void);
 #endif
+
+void __kprobes_test_case_start(void);
+void __kprobes_test_case_end_16(void);
+void __kprobes_test_case_end_32(void);
--- linux-ein-5.4.0.orig/arch/arm/probes/kprobes/test-thumb.c
+++ linux-ein-5.4.0/arch/arm/probes/kprobes/test-thumb.c
@@ -441,21 +441,21 @@
 		"3:	mvn	r0, r0	\n\t"
 		"2:	nop		\n\t")
 
-	TEST_RX("tbh	[pc, r",7, (9f-(1f+4))>>1,"]",
+	TEST_RX("tbh	[pc, r",7, (9f-(1f+4))>>1,", lsl #1]",
 		"9:			\n\t"
 		".short	(2f-1b-4)>>1	\n\t"
 		".short	(3f-1b-4)>>1	\n\t"
 		"3:	mvn	r0, r0	\n\t"
 		"2:	nop		\n\t")
 
-	TEST_RX("tbh	[pc, r",12, ((9f-(1f+4))>>1)+1,"]",
+	TEST_RX("tbh	[pc, r",12, ((9f-(1f+4))>>1)+1,", lsl #1]",
 		"9:			\n\t"
 		".short	(2f-1b-4)>>1	\n\t"
 		".short	(3f-1b-4)>>1	\n\t"
 		"3:	mvn	r0, r0	\n\t"
 		"2:	nop		\n\t")
 
-	TEST_RRX("tbh	[r",1,9f, ", r",14,1,"]",
+	TEST_RRX("tbh	[r",1,9f, ", r",14,1,", lsl #1]",
 		"9:			\n\t"
 		".short	(2f-1b-4)>>1	\n\t"
 		".short	(3f-1b-4)>>1	\n\t"
@@ -468,10 +468,10 @@
 
 	TEST_UNSUPPORTED("strexb	r0, r1, [r2]")
 	TEST_UNSUPPORTED("strexh	r0, r1, [r2]")
-	TEST_UNSUPPORTED("strexd	r0, r1, [r2]")
+	TEST_UNSUPPORTED("strexd	r0, r1, r2, [r2]")
 	TEST_UNSUPPORTED("ldrexb	r0, [r1]")
 	TEST_UNSUPPORTED("ldrexh	r0, [r1]")
-	TEST_UNSUPPORTED("ldrexd	r0, [r1]")
+	TEST_UNSUPPORTED("ldrexd	r0, r1, [r1]")
 
 	TEST_GROUP("Data-processing (shifted register) and (modified immediate)")
 
--- linux-ein-5.4.0.orig/arch/arm/probes/uprobes/core.c
+++ linux-ein-5.4.0/arch/arm/probes/uprobes/core.c
@@ -204,7 +204,7 @@
 static struct undef_hook uprobes_arm_break_hook = {
 	.instr_mask	= 0x0fffffff,
 	.instr_val	= (UPROBE_SWBP_ARM_INSN & 0x0fffffff),
-	.cpsr_mask	= MODE_MASK,
+	.cpsr_mask	= (PSR_T_BIT | MODE_MASK),
 	.cpsr_val	= USR_MODE,
 	.fn		= uprobe_trap_handler,
 };
@@ -212,7 +212,7 @@
 static struct undef_hook uprobes_arm_ss_hook = {
 	.instr_mask	= 0x0fffffff,
 	.instr_val	= (UPROBE_SS_ARM_INSN & 0x0fffffff),
-	.cpsr_mask	= MODE_MASK,
+	.cpsr_mask	= (PSR_T_BIT | MODE_MASK),
 	.cpsr_val	= USR_MODE,
 	.fn		= uprobe_trap_handler,
 };
--- linux-ein-5.4.0.orig/arch/arm/vfp/Makefile
+++ linux-ein-5.4.0/arch/arm/vfp/Makefile
@@ -8,6 +8,4 @@
 # ccflags-y := -DDEBUG
 # asflags-y := -DDEBUG
 
-KBUILD_AFLAGS	:=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp -mfloat-abi=soft)
-
 obj-y		+= vfpmodule.o entry.o vfphw.o vfpsingle.o vfpdouble.o
--- linux-ein-5.4.0.orig/arch/arm/vfp/entry.S
+++ linux-ein-5.4.0/arch/arm/vfp/entry.S
@@ -37,20 +37,3 @@
 	.align	2
 .LCvfp:
 	.word	vfp_vector
-
-@ This code is called if the VFP does not exist. It needs to flag the
-@ failure to the VFP initialisation code.
-
-	__INIT
-ENTRY(vfp_testing_entry)
-	dec_preempt_count_ti r10, r4
-	ldr	r0, VFP_arch_address
-	str	r0, [r0]		@ set to non-zero value
-	ret	r9			@ we have handled the fault
-ENDPROC(vfp_testing_entry)
-
-	.align	2
-VFP_arch_address:
-	.word	VFP_arch
-
-	__FINIT
--- linux-ein-5.4.0.orig/arch/arm/vfp/vfphw.S
+++ linux-ein-5.4.0/arch/arm/vfp/vfphw.S
@@ -78,11 +78,6 @@
 ENTRY(vfp_support_entry)
 	DBGSTR3	"instr %08x pc %08x state %p", r0, r2, r10
 
-	ldr	r3, [sp, #S_PSR]	@ Neither lazy restore nor FP exceptions
-	and	r3, r3, #MODE_MASK	@ are supported in kernel mode
-	teq	r3, #USR_MODE
-	bne	vfp_kmode_exception	@ Returns through lr
-
 	VFPFMRX	r1, FPEXC		@ Is the VFP enabled?
 	DBGSTR1	"fpexc %08x", r1
 	tst	r1, #FPEXC_EN
@@ -258,11 +253,14 @@
 
 ENTRY(vfp_get_float)
 	tbl_branch r0, r3, #3
+	.fpu	vfpv2
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	mrc	p10, 0, r0, c\dr, c0, 0	@ fmrs	r0, s0
+1:	vmov	r0, s\dr
 	ret	lr
 	.org	1b + 8
-1:	mrc	p10, 0, r0, c\dr, c0, 4	@ fmrs	r0, s1
+	.endr
+	.irp	dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+1:	vmov	r0, s\dr
 	ret	lr
 	.org	1b + 8
 	.endr
@@ -270,11 +268,14 @@
 
 ENTRY(vfp_put_float)
 	tbl_branch r1, r3, #3
+	.fpu	vfpv2
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	mcr	p10, 0, r0, c\dr, c0, 0	@ fmsr	r0, s0
+1:	vmov	s\dr, r0
 	ret	lr
 	.org	1b + 8
-1:	mcr	p10, 0, r0, c\dr, c0, 4	@ fmsr	r0, s1
+	.endr
+	.irp	dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+1:	vmov	s\dr, r0
 	ret	lr
 	.org	1b + 8
 	.endr
@@ -282,15 +283,17 @@
 
 ENTRY(vfp_get_double)
 	tbl_branch r0, r3, #3
+	.fpu	vfpv2
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	fmrrd	r0, r1, d\dr
+1:	vmov	r0, r1, d\dr
 	ret	lr
 	.org	1b + 8
 	.endr
 #ifdef CONFIG_VFPv3
 	@ d16 - d31 registers
-	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	mrrc	p11, 3, r0, r1, c\dr	@ fmrrd	r0, r1, d\dr
+	.fpu	vfpv3
+	.irp	dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+1:	vmov	r0, r1, d\dr
 	ret	lr
 	.org	1b + 8
 	.endr
@@ -304,15 +307,17 @@
 
 ENTRY(vfp_put_double)
 	tbl_branch r2, r3, #3
+	.fpu	vfpv2
 	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	fmdrr	d\dr, r0, r1
+1:	vmov	d\dr, r0, r1
 	ret	lr
 	.org	1b + 8
 	.endr
 #ifdef CONFIG_VFPv3
+	.fpu	vfpv3
 	@ d16 - d31 registers
-	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1:	mcrr	p11, 3, r0, r1, c\dr	@ fmdrr	r0, r1, d\dr
+	.irp	dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+1:	vmov	d\dr, r0, r1
 	ret	lr
 	.org	1b + 8
 	.endr
--- linux-ein-5.4.0.orig/arch/arm/vfp/vfpmodule.c
+++ linux-ein-5.4.0/arch/arm/vfp/vfpmodule.c
@@ -23,6 +23,7 @@
 #include <asm/cputype.h>
 #include <asm/system_info.h>
 #include <asm/thread_notify.h>
+#include <asm/traps.h>
 #include <asm/vfp.h>
 
 #include "vfpinstr.h"
@@ -31,7 +32,6 @@
 /*
  * Our undef handlers (in entry.S)
  */
-asmlinkage void vfp_testing_entry(void);
 asmlinkage void vfp_support_entry(void);
 asmlinkage void vfp_null_entry(void);
 
@@ -42,7 +42,7 @@
  * Used in startup: set to non-zero if VFP checks fail
  * After startup, holds VFP architecture
  */
-unsigned int VFP_arch;
+static unsigned int __initdata VFP_arch;
 
 /*
  * The pointer to the vfpstate structure of the thread which currently
@@ -436,7 +436,7 @@
  * present on all CPUs within a SMP complex. Needs to be called prior to
  * vfp_init().
  */
-void vfp_disable(void)
+void __init vfp_disable(void)
 {
 	if (VFP_arch) {
 		pr_debug("%s: should be called prior to vfp_init\n", __func__);
@@ -642,7 +642,9 @@
 	return 0;
 }
 
-void vfp_kmode_exception(void)
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
 {
 	/*
 	 * If we reach this point, a floating point exception has been raised
@@ -660,9 +662,51 @@
 		pr_crit("BUG: unsupported FP instruction in kernel mode\n");
 	else
 		pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n");
+	pr_crit("FPEXC == 0x%08x\n", fmrx(FPEXC));
+	return 1;
 }
 
-#ifdef CONFIG_KERNEL_MODE_NEON
+static struct undef_hook vfp_kmode_exception_hook[] = {{
+	.instr_mask	= 0xfe000000,
+	.instr_val	= 0xf2000000,
+	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
+	.cpsr_val	= SVC_MODE,
+	.fn		= vfp_kmode_exception,
+}, {
+	.instr_mask	= 0xff100000,
+	.instr_val	= 0xf4000000,
+	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
+	.cpsr_val	= SVC_MODE,
+	.fn		= vfp_kmode_exception,
+}, {
+	.instr_mask	= 0xef000000,
+	.instr_val	= 0xef000000,
+	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
+	.cpsr_val	= SVC_MODE | PSR_T_BIT,
+	.fn		= vfp_kmode_exception,
+}, {
+	.instr_mask	= 0xff100000,
+	.instr_val	= 0xf9000000,
+	.cpsr_mask	= MODE_MASK | PSR_T_BIT,
+	.cpsr_val	= SVC_MODE | PSR_T_BIT,
+	.fn		= vfp_kmode_exception,
+}, {
+	.instr_mask	= 0x0c000e00,
+	.instr_val	= 0x0c000a00,
+	.cpsr_mask	= MODE_MASK,
+	.cpsr_val	= SVC_MODE,
+	.fn		= vfp_kmode_exception,
+}};
+
+static int __init vfp_kmode_exception_hook_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)
+		register_undef_hook(&vfp_kmode_exception_hook[i]);
+	return 0;
+}
+subsys_initcall(vfp_kmode_exception_hook_init);
 
 /*
  * Kernel-side NEON support functions
@@ -708,6 +752,21 @@
 
 #endif /* CONFIG_KERNEL_MODE_NEON */
 
+static int __init vfp_detect(struct pt_regs *regs, unsigned int instr)
+{
+	VFP_arch = UINT_MAX;	/* mark as not present */
+	regs->ARM_pc += 4;
+	return 0;
+}
+
+static struct undef_hook vfp_detect_hook __initdata = {
+	.instr_mask	= 0x0c000e00,
+	.instr_val	= 0x0c000a00,
+	.cpsr_mask	= MODE_MASK,
+	.cpsr_val	= SVC_MODE,
+	.fn		= vfp_detect,
+};
+
 /*
  * VFP support code initialisation.
  */
@@ -728,10 +787,11 @@
 	 * The handler is already setup to just log calls, so
 	 * we just need to read the VFPSID register.
 	 */
-	vfp_vector = vfp_testing_entry;
+	register_undef_hook(&vfp_detect_hook);
 	barrier();
 	vfpsid = fmrx(FPSID);
 	barrier();
+	unregister_undef_hook(&vfp_detect_hook);
 	vfp_vector = vfp_null_entry;
 
 	pr_info("VFP support v0.3: ");
--- linux-ein-5.4.0.orig/arch/arm/xen/enlighten.c
+++ linux-ein-5.4.0/arch/arm/xen/enlighten.c
@@ -354,7 +354,8 @@
 	 * for secondary CPUs as they are brought up.
 	 * For uniformity we use VCPUOP_register_vcpu_info even on cpu0.
 	 */
-	xen_vcpu_info = alloc_percpu(struct vcpu_info);
+	xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info),
+				       1 << fls(sizeof(struct vcpu_info) - 1));
 	if (xen_vcpu_info == NULL)
 		return -ENOMEM;
 
@@ -370,8 +371,6 @@
 		return -ENOMEM;
 	}
 	gnttab_init();
-	if (!xen_initial_domain())
-		xenbus_probe(NULL);
 
 	/*
 	 * Making sure board specific code will not set up ops for
--- linux-ein-5.4.0.orig/arch/arm/xen/mm.c
+++ linux-ein-5.4.0/arch/arm/xen/mm.c
@@ -70,20 +70,20 @@
  * pfn_valid returns true the pages is local and we can use the native
  * dma-direct functions, otherwise we call the Xen specific version.
  */
-void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle,
-		phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+void xen_dma_sync_for_cpu(dma_addr_t handle, phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	if (pfn_valid(PFN_DOWN(handle)))
-		arch_sync_dma_for_cpu(dev, paddr, size, dir);
+		arch_sync_dma_for_cpu(paddr, size, dir);
 	else if (dir != DMA_TO_DEVICE)
 		dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
 }
 
-void xen_dma_sync_for_device(struct device *dev, dma_addr_t handle,
-		phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+void xen_dma_sync_for_device(dma_addr_t handle, phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	if (pfn_valid(PFN_DOWN(handle)))
-		arch_sync_dma_for_device(dev, paddr, size, dir);
+		arch_sync_dma_for_device(paddr, size, dir);
 	else if (dir == DMA_FROM_DEVICE)
 		dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
 	else
--- linux-ein-5.4.0.orig/arch/arm/xen/p2m.c
+++ linux-ein-5.4.0/arch/arm/xen/p2m.c
@@ -62,11 +62,12 @@
 
 unsigned long __pfn_to_mfn(unsigned long pfn)
 {
-	struct rb_node *n = phys_to_mach.rb_node;
+	struct rb_node *n;
 	struct xen_p2m_entry *entry;
 	unsigned long irqflags;
 
 	read_lock_irqsave(&p2m_lock, irqflags);
+	n = phys_to_mach.rb_node;
 	while (n) {
 		entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
 		if (entry->pfn <= pfn &&
@@ -93,10 +94,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;
@@ -124,10 +154,11 @@
 	int rc;
 	unsigned long irqflags;
 	struct xen_p2m_entry *p2m_entry;
-	struct rb_node *n = phys_to_mach.rb_node;
+	struct rb_node *n;
 
 	if (mfn == INVALID_P2M_ENTRY) {
 		write_lock_irqsave(&p2m_lock, irqflags);
+		n = phys_to_mach.rb_node;
 		while (n) {
 			p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
 			if (p2m_entry->pfn <= pfn &&
--- linux-ein-5.4.0.orig/arch/arm64/Kconfig
+++ linux-ein-5.4.0/arch/arm64/Kconfig
@@ -139,6 +139,7 @@
 	select HAVE_CMPXCHG_DOUBLE
 	select HAVE_CMPXCHG_LOCAL
 	select HAVE_CONTEXT_TRACKING
+	select HAVE_COPY_THREAD_TLS
 	select HAVE_DEBUG_BUGVERBOSE
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_DMA_CONTIGUOUS
@@ -180,7 +181,6 @@
 	select PCI_SYSCALL if PCI
 	select POWER_RESET
 	select POWER_SUPPLY
-	select REFCOUNT_FULL
 	select SPARSE_IRQ
 	select SWIOTLB
 	select SYSCTL_EXCEPTION_TRACE
@@ -488,7 +488,7 @@
 	help
 	  This option adds a workaround for ARM Cortex-A55 Erratum 1024718.
 
-	  Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+	  Affected Cortex-A55 cores (all revisions) could cause incorrect
 	  update of the hardware dirty bit when the DBM/AP bits are updated
 	  without a break-before-make. The workaround is to disable the usage
 	  of hardware DBM locally on the affected cores. CPUs not affected by
@@ -558,6 +558,38 @@
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_1542419
+	bool "Neoverse-N1: workaround mis-ordering of instruction fetches"
+	default y
+	help
+	  This option adds a workaround for ARM Neoverse-N1 erratum
+	  1542419.
+
+	  Affected Neoverse-N1 cores could execute a stale instruction when
+	  modified by another CPU. The workaround depends on a firmware
+	  counterpart.
+
+	  Workaround the issue by hiding the DIC feature from EL0. This
+	  forces user-space to perform cache maintenance.
+
+	  If unsure, say Y.
+
+config ARM64_ERRATUM_1742098
+	bool "Cortex-A57/A72: 1742098: ELR recorded incorrectly on interrupt taken between cryptographic instructions in a sequence"
+	depends on COMPAT
+	default y
+	help
+	  This option removes the AES hwcap for aarch32 user-space to
+	  workaround erratum 1742098 on Cortex-A57 and Cortex-A72.
+
+	  Affected parts may corrupt the AES state if an interrupt is
+	  taken between a pair of AES instructions. These instructions
+	  are only present if the cryptography extensions are present.
+	  All software should have a fallback implementation for CPUs
+	  that don't implement the cryptography extensions.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
@@ -1048,6 +1080,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
@@ -1122,6 +1155,15 @@
 
 	  If unsure, say Y.
 
+config MITIGATE_SPECTRE_BRANCH_HISTORY
+	bool "Mitigate Spectre style attacks against branch history" if EXPERT
+	default y
+	help
+	  Speculation attacks against some high-performance processors can
+	  make use of branch history to influence future speculation.
+	  When taking an exception from user-space, a sequence of branches
+	  or a firmware call overwrites the branch history.
+
 config RODATA_FULL_DEFAULT_ENABLED
 	bool "Apply r/o permissions of VM areas also to their linear aliases"
 	default y
--- linux-ein-5.4.0.orig/arch/arm64/Kconfig.platforms
+++ linux-ein-5.4.0/arch/arm64/Kconfig.platforms
@@ -54,6 +54,7 @@
 config ARCH_BERLIN
 	bool "Marvell Berlin SoC Family"
 	select DW_APB_ICTL
+	select DW_APB_TIMER_OF
 	select GPIOLIB
 	select PINCTRL
 	help
@@ -224,6 +225,7 @@
 
 config ARCH_SYNQUACER
 	bool "Socionext SynQuacer SoC Family"
+	select IRQ_FASTEOI_HIERARCHY_HANDLERS
 
 config ARCH_TEGRA
 	bool "NVIDIA Tegra SoC Family"
--- linux-ein-5.4.0.orig/arch/arm64/Makefile
+++ linux-ein-5.4.0/arch/arm64/Makefile
@@ -18,7 +18,7 @@
 # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour
 # for relative relocs, since this leads to better Image compression
 # with the relocation offsets always being zero.
-LDFLAGS_vmlinux		+= -shared -Bsymbolic -z notext -z norelro \
+LDFLAGS_vmlinux		+= -shared -Bsymbolic -z notext \
 			$(call ld-option, --no-apply-dynamic-relocs)
 endif
 
@@ -72,23 +72,31 @@
 					include/generated/asm-offsets.h))
 endif
 
+# Ensure that if the compiler supports branch protection we default it
+# off.
+KBUILD_CFLAGS += $(call cc-option,-mbranch-protection=none)
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS	+= -mbig-endian
 CHECKFLAGS	+= -D__AARCH64EB__
 AS		+= -EB
 # Prefer the baremetal ELF build target, but not all toolchains include
 # it so fall back to the standard linux version if needed.
-KBUILD_LDFLAGS	+= -EB $(call ld-option, -maarch64elfb, -maarch64linuxb)
+KBUILD_LDFLAGS	+= -EB $(call ld-option, -maarch64elfb, -maarch64linuxb -z norelro)
 UTS_MACHINE	:= aarch64_be
 else
 KBUILD_CPPFLAGS	+= -mlittle-endian
 CHECKFLAGS	+= -D__AARCH64EL__
 AS		+= -EL
 # Same as above, prefer ELF but fall back to linux target if needed.
-KBUILD_LDFLAGS	+= -EL $(call ld-option, -maarch64elf, -maarch64linux)
+KBUILD_LDFLAGS	+= -EL $(call ld-option, -maarch64elf, -maarch64linux -z norelro)
 UTS_MACHINE	:= aarch64
 endif
 
+ifeq ($(CONFIG_LD_IS_LLD), y)
+KBUILD_LDFLAGS	+= -z norelro
+endif
+
 CHECKFLAGS	+= -D__aarch64__
 
 ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
@@ -142,6 +150,8 @@
 PHONY += vdso_install
 vdso_install:
 	$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
+	$(if $(CONFIG_COMPAT_VDSO), \
+		$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
--- linux-ein-5.4.0.orig/arch/arm64/boot/Makefile
+++ linux-ein-5.4.0/arch/arm64/boot/Makefile
@@ -16,7 +16,7 @@
 
 OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 
-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-ein-5.4.0.orig/arch/arm64/boot/dts/Makefile
+++ linux-ein-5.4.0/arch/arm64/boot/dts/Makefile
@@ -17,6 +17,7 @@
 subdir-y += lg
 subdir-y += marvell
 subdir-y += mediatek
+subdir-y += msc
 subdir-y += nvidia
 subdir-y += qcom
 subdir-y += realtek
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/actions/s700.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/actions/s700.dtsi
@@ -231,7 +231,7 @@
 
 		pinctrl: pinctrl@e01b0000 {
 			compatible = "actions,s700-pinctrl";
-			reg = <0x0 0xe01b0000 0x0 0x1000>;
+			reg = <0x0 0xe01b0000 0x0 0x100>;
 			clocks = <&cmu CLK_GPIO>;
 			gpio-controller;
 			gpio-ranges = <&pinctrl 0 0 136>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
@@ -127,7 +127,7 @@
 &emac {
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmii_pins>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ext_rgmii_phy>;
 	phy-supply = <&reg_dc1sw>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino-emmc.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino-emmc.dts
@@ -15,7 +15,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	vqmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_eldo1>;
 	bus-width = <8>;
 	non-removable;
 	cap-mmc-hw-reset;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
@@ -140,7 +140,7 @@
 &mmc1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc1_pins>;
-	vmmc-supply = <&reg_aldo2>;
+	vmmc-supply = <&reg_dcdc1>;
 	vqmmc-supply = <&reg_dldo4>;
 	mmc-pwrseq = <&wifi_pwrseq>;
 	bus-width = <4>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
@@ -78,7 +78,7 @@
 	leds {
 		compatible = "gpio-leds";
 
-		status {
+		led-0 {
 			label = "orangepi:green:status";
 			gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
 		};
@@ -129,7 +129,7 @@
 &emac {
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmii_pins>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ext_rgmii_phy>;
 	phy-supply = <&reg_gmac_3v3>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts
@@ -11,3 +11,7 @@
 	compatible = "pine64,pine64-lts", "allwinner,sun50i-r18",
 		     "allwinner,sun50i-a64";
 };
+
+&mmc0 {
+	broken-cd;		/* card detect is broken on *some* boards */
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts
@@ -52,7 +52,7 @@
 &emac {
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmii_pins>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-txid";
 	phy-handle = <&ext_rgmii_phy>;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
@@ -103,8 +103,6 @@
 };
 
 &ehci0 {
-	phys = <&usbphy 0>;
-	phy-names = "usb";
 	status = "okay";
 };
 
@@ -142,6 +140,7 @@
 	pinctrl-0 = <&mmc2_pins>, <&mmc2_ds_pin>;
 	vmmc-supply = <&reg_dcdc1>;
 	vqmmc-supply = <&reg_eldo1>;
+	max-frequency = <200000000>;
 	bus-width = <8>;
 	non-removable;
 	cap-mmc-hw-reset;
@@ -150,8 +149,6 @@
 };
 
 &ohci0 {
-	phys = <&usbphy 0>;
-	phy-names = "usb";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
@@ -55,10 +55,9 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	non-removable;
 	disable-wp;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 push-pull switch */
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -142,6 +142,15 @@
 		clock-output-names = "ext-osc32k";
 	};
 
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
 	psci {
 		compatible = "arm,psci-0.2";
 		method = "smc";
@@ -218,7 +227,7 @@
 
 			display_clocks: clock@0 {
 				compatible = "allwinner,sun50i-a64-de2-clk";
-				reg = <0x0 0x100000>;
+				reg = <0x0 0x10000>;
 				clocks = <&ccu CLK_BUS_DE>,
 					 <&ccu CLK_DE>;
 				clock-names = "bus",
@@ -467,7 +476,7 @@
 			resets = <&ccu RST_BUS_MMC2>;
 			reset-names = "ahb";
 			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-			max-frequency = <200000000>;
+			max-frequency = <150000000>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -521,6 +530,8 @@
 				 <&ccu CLK_USB_OHCI0>;
 			resets = <&ccu RST_BUS_OHCI0>,
 				 <&ccu RST_BUS_EHCI0>;
+			phys = <&usbphy 0>;
+			phy-names = "usb";
 			status = "disabled";
 		};
 
@@ -531,6 +542,8 @@
 			clocks = <&ccu CLK_BUS_OHCI0>,
 				 <&ccu CLK_USB_OHCI0>;
 			resets = <&ccu RST_BUS_OHCI0>;
+			phys = <&usbphy 0>;
+			phy-names = "usb";
 			status = "disabled";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
@@ -114,7 +114,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
@@ -157,7 +157,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
@@ -164,7 +164,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
@@ -72,7 +72,7 @@
 	pinctrl-0 = <&emac_rgmii_pins>;
 	phy-supply = <&reg_gmac_3v3>;
 	phy-handle = <&ext_rgmii_phy>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -54,21 +54,21 @@
 			enable-method = "psci";
 		};
 
-		cpu@1 {
+		cpu1: cpu@1 {
 			compatible = "arm,cortex-a53";
 			device_type = "cpu";
 			reg = <1>;
 			enable-method = "psci";
 		};
 
-		cpu@2 {
+		cpu2: cpu@2 {
 			compatible = "arm,cortex-a53";
 			device_type = "cpu";
 			reg = <2>;
 			enable-method = "psci";
 		};
 
-		cpu@3 {
+		cpu3: cpu@3 {
 			compatible = "arm,cortex-a53";
 			device_type = "cpu";
 			reg = <3>;
@@ -76,6 +76,15 @@
 		};
 	};
 
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
 	psci {
 		compatible = "arm,psci-0.2";
 		method = "smc";
@@ -146,8 +155,7 @@
 				     <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+				     <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "gp",
 					  "gpmmu",
 					  "pp",
@@ -158,8 +166,7 @@
 					  "pp2",
 					  "ppmmu2",
 					  "pp3",
-					  "ppmmu3",
-					  "pmu";
+					  "ppmmu3";
 			clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
 			clock-names = "bus", "core";
 			resets = <&ccu RST_BUS_GPU>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
@@ -83,7 +83,7 @@
 &emac {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ext_rgmii_pins>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ext_rgmii_phy>;
 	phy-supply = <&reg_aldo2>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -66,7 +66,7 @@
 &emac {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ext_rgmii_pins>;
-	phy-mode = "rgmii";
+	phy-mode = "rgmii-id";
 	phy-handle = <&ext_rgmii_phy>;
 	phy-supply = <&reg_aldo2>;
 	allwinner,rx-delay-ps = <200>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -70,6 +70,15 @@
 		clock-output-names = "ext_osc32k";
 	};
 
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
 	psci {
 		compatible = "arm,psci-0.2";
 		method = "smc";
@@ -323,6 +332,7 @@
 			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&mmc0_pins>;
+			max-frequency = <150000000>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -339,6 +349,7 @@
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&mmc1_pins>;
+			max-frequency = <150000000>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -355,6 +366,7 @@
 			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&mmc2_pins>;
+			max-frequency = <150000000>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -524,6 +536,8 @@
 				 <&ccu CLK_USB_OHCI0>;
 			resets = <&ccu RST_BUS_OHCI0>,
 				 <&ccu RST_BUS_EHCI0>;
+			phys = <&usb2phy 0>;
+			phy-names = "usb";
 			status = "disabled";
 		};
 
@@ -534,6 +548,8 @@
 			clocks = <&ccu CLK_BUS_OHCI0>,
 				 <&ccu CLK_USB_OHCI0>;
 			resets = <&ccu RST_BUS_OHCI0>;
+			phys = <&usb2phy 0>;
+			phy-names = "usb";
 			status = "disabled";
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -61,10 +61,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>,
@@ -77,7 +77,7 @@
 		method = "smc";
 	};
 
-	intc: intc@fffc1000 {
+	intc: interrupt-controller@fffc1000 {
 		compatible = "arm,gic-400", "arm,cortex-a15-gic";
 		#interrupt-cells = <3>;
 		interrupt-controller;
@@ -302,7 +302,7 @@
 			status = "disabled";
 		};
 
-		nand: nand@ffb90000 {
+		nand: nand-controller@ffb90000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "altr,socfpga-denali-nand";
@@ -445,7 +445,7 @@
 			clock-names = "timer";
 		};
 
-		uart0: serial0@ffc02000 {
+		uart0: serial@ffc02000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0xffc02000 0x100>;
 			interrupts = <0 108 4>;
@@ -456,7 +456,7 @@
 			status = "disabled";
 		};
 
-		uart1: serial1@ffc02100 {
+		uart1: serial@ffc02100 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0xffc02100 0x100>;
 			interrupts = <0 109 4>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
@@ -129,7 +129,7 @@
 	status = "okay";
 	clock-frequency = <100000>;
 	i2c-sda-falling-time-ns = <890>;  /* hcnt */
-	i2c-sdl-falling-time-ns = <890>;  /* lcnt */
+	i2c-scl-falling-time-ns = <890>;  /* lcnt */
 
 	adc@14 {
 		compatible = "lltc,ltc2497";
@@ -155,6 +155,7 @@
 };
 
 &qspi {
+	status = "okay";
 	flash@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
@@ -150,7 +150,7 @@
 		scpi_clocks: clocks {
 			compatible = "arm,scpi-clocks";
 
-			scpi_dvfs: clock-controller {
+			scpi_dvfs: clocks-0 {
 				compatible = "arm,scpi-dvfs-clocks";
 				#clock-cells = <1>;
 				clock-indices = <0>;
@@ -159,7 +159,7 @@
 		};
 
 		scpi_sensors: sensors {
-			compatible = "amlogic,meson-gxbb-scpi-sensors";
+			compatible = "amlogic,meson-gxbb-scpi-sensors", "arm,scpi-sensors";
 			#thermal-sensor-cells = <1>;
 		};
 	};
@@ -1162,7 +1162,7 @@
 
 			toddr_a: audio-controller@100 {
 				compatible = "amlogic,axg-toddr";
-				reg = <0x0 0x100 0x0 0x1c>;
+				reg = <0x0 0x100 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "TODDR_A";
 				interrupts = <GIC_SPI 84 IRQ_TYPE_EDGE_RISING>;
@@ -1173,7 +1173,7 @@
 
 			toddr_b: audio-controller@140 {
 				compatible = "amlogic,axg-toddr";
-				reg = <0x0 0x140 0x0 0x1c>;
+				reg = <0x0 0x140 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "TODDR_B";
 				interrupts = <GIC_SPI 85 IRQ_TYPE_EDGE_RISING>;
@@ -1184,7 +1184,7 @@
 
 			toddr_c: audio-controller@180 {
 				compatible = "amlogic,axg-toddr";
-				reg = <0x0 0x180 0x0 0x1c>;
+				reg = <0x0 0x180 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "TODDR_C";
 				interrupts = <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>;
@@ -1195,7 +1195,7 @@
 
 			frddr_a: audio-controller@1c0 {
 				compatible = "amlogic,axg-frddr";
-				reg = <0x0 0x1c0 0x0 0x1c>;
+				reg = <0x0 0x1c0 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "FRDDR_A";
 				interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>;
@@ -1206,7 +1206,7 @@
 
 			frddr_b: audio-controller@200 {
 				compatible = "amlogic,axg-frddr";
-				reg = <0x0 0x200 0x0 0x1c>;
+				reg = <0x0 0x200 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "FRDDR_B";
 				interrupts = <GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
@@ -1217,7 +1217,7 @@
 
 			frddr_c: audio-controller@240 {
 				compatible = "amlogic,axg-frddr";
-				reg = <0x0 0x240 0x0 0x1c>;
+				reg = <0x0 0x240 0x0 0x2c>;
 				#sound-dai-cells = <0>;
 				sound-name-prefix = "FRDDR_C";
 				interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
@@ -1705,7 +1705,7 @@
 			sd_emmc_b: sd@5000 {
 				compatible = "amlogic,meson-axg-mmc";
 				reg = <0x0 0x5000 0x0 0x800>;
-				interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
+				interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 				clocks = <&clkc CLKID_SD_EMMC_B>,
 					<&clkc CLKID_SD_EMMC_B_CLK0>,
@@ -1717,7 +1717,7 @@
 			sd_emmc_c: mmc@7000 {
 				compatible = "amlogic,meson-axg-mmc";
 				reg = <0x0 0x7000 0x0 0x800>;
-				interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
+				interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 				clocks = <&clkc CLKID_SD_EMMC_C>,
 					<&clkc CLKID_SD_EMMC_C_CLK0>,
@@ -1728,18 +1728,18 @@
 		};
 
 		sram: sram@fffc0000 {
-			compatible = "amlogic,meson-axg-sram", "mmio-sram";
+			compatible = "mmio-sram";
 			reg = <0x0 0xfffc0000 0x0 0x20000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0 0x0 0xfffc0000 0x20000>;
 
-			cpu_scp_lpri: scp-shmem@13000 {
+			cpu_scp_lpri: scp-sram@13000 {
 				compatible = "amlogic,meson-axg-scp-shmem";
 				reg = <0x13000 0x400>;
 			};
 
-			cpu_scp_hpri: scp-shmem@13400 {
+			cpu_scp_hpri: scp-sram@13400 {
 				compatible = "amlogic,meson-axg-scp-shmem";
 				reg = <0x13400 0x400>;
 			};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
@@ -76,6 +76,12 @@
 			no-map;
 		};
 
+		/* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+		secmon_reserved_bl32: secmon@5300000 {
+			reg = <0x0 0x05300000 0x0 0x2000000>;
+			no-map;
+		};
+
 		linux,cma {
 			compatible = "shared-dma-pool";
 			reusable;
@@ -167,6 +173,8 @@
 				hwrng: rng@218 {
 					compatible = "amlogic,meson-rng";
 					reg = <0x0 0x218 0x0 0x4>;
+					clocks = <&clkc CLKID_RNG0>;
+					clock-names = "core";
 				};
 			};
 
@@ -1368,10 +1376,9 @@
 
 			dmc: bus@38000 {
 				compatible = "simple-bus";
-				reg = <0x0 0x38000 0x0 0x400>;
 				#address-cells = <2>;
 				#size-cells = <2>;
-				ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>;
+				ranges = <0x0 0x0 0x0 0x38000 0x0 0x2000>;
 
 				canvas: video-lut@48 {
 					compatible = "amlogic,canvas";
@@ -1509,7 +1516,7 @@
 				toddr_a: audio-controller@100 {
 					compatible = "amlogic,g12a-toddr",
 						     "amlogic,axg-toddr";
-					reg = <0x0 0x100 0x0 0x1c>;
+					reg = <0x0 0x100 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "TODDR_A";
 					interrupts = <GIC_SPI 148 IRQ_TYPE_EDGE_RISING>;
@@ -1521,7 +1528,7 @@
 				toddr_b: audio-controller@140 {
 					compatible = "amlogic,g12a-toddr",
 						     "amlogic,axg-toddr";
-					reg = <0x0 0x140 0x0 0x1c>;
+					reg = <0x0 0x140 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "TODDR_B";
 					interrupts = <GIC_SPI 149 IRQ_TYPE_EDGE_RISING>;
@@ -1533,7 +1540,7 @@
 				toddr_c: audio-controller@180 {
 					compatible = "amlogic,g12a-toddr",
 						     "amlogic,axg-toddr";
-					reg = <0x0 0x180 0x0 0x1c>;
+					reg = <0x0 0x180 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "TODDR_C";
 					interrupts = <GIC_SPI 150 IRQ_TYPE_EDGE_RISING>;
@@ -1545,7 +1552,7 @@
 				frddr_a: audio-controller@1c0 {
 					compatible = "amlogic,g12a-frddr",
 						     "amlogic,axg-frddr";
-					reg = <0x0 0x1c0 0x0 0x1c>;
+					reg = <0x0 0x1c0 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "FRDDR_A";
 					interrupts = <GIC_SPI 152 IRQ_TYPE_EDGE_RISING>;
@@ -1557,7 +1564,7 @@
 				frddr_b: audio-controller@200 {
 					compatible = "amlogic,g12a-frddr",
 						     "amlogic,axg-frddr";
-					reg = <0x0 0x200 0x0 0x1c>;
+					reg = <0x0 0x200 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "FRDDR_B";
 					interrupts = <GIC_SPI 153 IRQ_TYPE_EDGE_RISING>;
@@ -1569,7 +1576,7 @@
 				frddr_c: audio-controller@240 {
 					compatible = "amlogic,g12a-frddr",
 						     "amlogic,axg-frddr";
-					reg = <0x0 0x240 0x0 0x1c>;
+					reg = <0x0 0x240 0x0 0x2c>;
 					#sound-dai-cells = <0>;
 					sound-name-prefix = "FRDDR_C";
 					interrupts = <GIC_SPI 154 IRQ_TYPE_EDGE_RISING>;
@@ -1775,7 +1782,7 @@
 					#address-cells = <1>;
 					#size-cells = <0>;
 
-					internal_ephy: ethernet_phy@8 {
+					internal_ephy: ethernet-phy@8 {
 						compatible = "ethernet-phy-id0180.3301",
 							     "ethernet-phy-ieee802.3-c22";
 						interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
@@ -2309,7 +2316,7 @@
 		sd_emmc_a: sd@ffe03000 {
 			compatible = "amlogic,meson-axg-mmc";
 			reg = <0x0 0xffe03000 0x0 0x800>;
-			interrupts = <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 			clocks = <&clkc CLKID_SD_EMMC_A>,
 				 <&clkc CLKID_SD_EMMC_A_CLK0>,
@@ -2321,7 +2328,7 @@
 		sd_emmc_b: sd@ffe05000 {
 			compatible = "amlogic,meson-axg-mmc";
 			reg = <0x0 0xffe05000 0x0 0x800>;
-			interrupts = <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 			clocks = <&clkc CLKID_SD_EMMC_B>,
 				 <&clkc CLKID_SD_EMMC_B_CLK0>,
@@ -2333,7 +2340,7 @@
 		sd_emmc_c: mmc@ffe07000 {
 			compatible = "amlogic,meson-axg-mmc";
 			reg = <0x0 0xffe07000 0x0 0x800>;
-			interrupts = <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>;
+			interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 			clocks = <&clkc CLKID_SD_EMMC_C>,
 				 <&clkc CLKID_SD_EMMC_C_CLK0>,
@@ -2365,7 +2372,7 @@
 				reg = <0x0 0xff400000 0x0 0x40000>;
 				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
-				clock-names = "ddr";
+				clock-names = "otg";
 				phys = <&usb2_phy1>;
 				phy-names = "usb2-phy";
 				dr_mode = "peripheral";
@@ -2380,7 +2387,8 @@
 				interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 				dr_mode = "host";
 				snps,dis_u2_susphy_quirk;
-				snps,quirk-frame-length-adjustment;
+				snps,quirk-frame-length-adjustment = <0x20>;
+				snps,parkmode-disable-ss-quirk;
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
@@ -139,7 +139,7 @@
 		regulator-min-microvolt = <721000>;
 		regulator-max-microvolt = <1022000>;
 
-		vin-supply = <&dc_in>;
+		pwm-supply = <&dc_in>;
 
 		pwms = <&pwm_AO_cd 1 1250 0>;
 		pwm-dutycycle-range = <100 0>;
@@ -157,14 +157,6 @@
 		regulator-always-on;
 	};
 
-	reserved-memory {
-		/* TEE Reserved Memory */
-		bl32_reserved: bl32@5000000 {
-			reg = <0x0 0x05300000 0x0 0x2000000>;
-			no-map;
-		};
-	};
-
 	sdio_pwrseq: sdio-pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
@@ -139,7 +139,7 @@
 		regulator-min-microvolt = <721000>;
 		regulator-max-microvolt = <1022000>;
 
-		vin-supply = <&main_12v>;
+		pwm-supply = <&main_12v>;
 
 		pwms = <&pwm_AO_cd 1 1250 0>;
 		pwm-dutycycle-range = <100 0>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
@@ -139,7 +139,7 @@
 		regulator-min-microvolt = <721000>;
 		regulator-max-microvolt = <1022000>;
 
-		vin-supply = <&dc_in>;
+		pwm-supply = <&dc_in>;
 
 		pwms = <&pwm_AO_cd 1 1250 0>;
 		pwm-dutycycle-range = <100 0>;
@@ -340,7 +340,7 @@
 		eee-broken-1000t;
 
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
 
 		interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
@@ -54,26 +54,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <666666666>;
-			opp-microvolt = <731000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <731000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi
@@ -11,26 +11,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <667000000>;
-			opp-microvolt = <731000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <761000>;
@@ -71,26 +51,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <667000000>;
-			opp-microvolt = <731000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <731000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
@@ -152,6 +152,10 @@
 	clock-latency = <50000>;
 };
 
+&frddr_a {
+	status = "okay";
+};
+
 &frddr_b {
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi
@@ -11,26 +11,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <731000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <667000000>;
-			opp-microvolt = <731000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <731000>;
@@ -71,26 +51,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <751000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <751000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <751000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <667000000>;
-			opp-microvolt = <751000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <771000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -41,6 +41,12 @@
 			no-map;
 		};
 
+		/* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+		secmon_reserved_bl32: secmon@5300000 {
+			reg = <0x0 0x05300000 0x0 0x2000000>;
+			no-map;
+		};
+
 		linux,cma {
 			compatible = "shared-dma-pool";
 			reusable;
@@ -166,7 +172,7 @@
 			reg = <0x14 0x10>;
 		};
 
-		eth_mac: eth_mac@34 {
+		eth_mac: eth-mac@34 {
 			reg = <0x34 0x10>;
 		};
 
@@ -183,7 +189,7 @@
 		scpi_clocks: clocks {
 			compatible = "arm,scpi-clocks";
 
-			scpi_dvfs: scpi_clocks@0 {
+			scpi_dvfs: clocks-0 {
 				compatible = "arm,scpi-dvfs-clocks";
 				#clock-cells = <1>;
 				clock-indices = <0>;
@@ -345,20 +351,20 @@
 		};
 
 		sram: sram@c8000000 {
-			compatible = "amlogic,meson-gx-sram", "amlogic,meson-gxbb-sram", "mmio-sram";
+			compatible = "mmio-sram";
 			reg = <0x0 0xc8000000 0x0 0x14000>;
 
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0 0x0 0xc8000000 0x14000>;
 
-			cpu_scp_lpri: scp-shmem@0 {
-				compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem";
+			cpu_scp_lpri: scp-sram@0 {
+				compatible = "amlogic,meson-gxbb-scp-shmem";
 				reg = <0x13000 0x400>;
 			};
 
-			cpu_scp_hpri: scp-shmem@200 {
-				compatible = "amlogic,meson-gx-scp-shmem", "amlogic,meson-gxbb-scp-shmem";
+			cpu_scp_hpri: scp-sram@200 {
+				compatible = "amlogic,meson-gxbb-scp-shmem";
 				reg = <0x13400 0x400>;
 			};
 		};
@@ -458,7 +464,7 @@
 			#size-cells = <2>;
 			ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>;
 
-			hwrng: rng {
+			hwrng: rng@0 {
 				compatible = "amlogic,meson-rng";
 				reg = <0x0 0x0 0x0 0x4>;
 			};
@@ -522,21 +528,21 @@
 			sd_emmc_a: mmc@70000 {
 				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
 				reg = <0x0 0x70000 0x0 0x800>;
-				interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
+				interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 
 			sd_emmc_b: mmc@72000 {
 				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
 				reg = <0x0 0x72000 0x0 0x800>;
-				interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
+				interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 
 			sd_emmc_c: mmc@74000 {
 				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
 				reg = <0x0 0x74000 0x0 0x800>;
-				interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
+				interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
 				status = "disabled";
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
@@ -165,7 +165,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 			interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -138,7 +138,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 			interrupt-parent = <&gpio_intc>;
@@ -296,7 +296,7 @@
 };
 
 &usb0_phy {
-	status = "okay";
+	status = "disabled";
 	phy-supply = <&usb_otg_pwr>;
 };
 
@@ -306,7 +306,7 @@
 };
 
 &usb0 {
-	status = "okay";
+	status = "disabled";
 };
 
 &usb1 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
@@ -126,7 +126,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 			interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
@@ -6,6 +6,7 @@
  */
 
 #include "meson-gxbb.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	aliases {
@@ -64,6 +65,7 @@
 		regulator-name = "VDDIO_AO18";
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
 	};
 
 	vcc_3v3: regulator-vcc_3v3 {
@@ -147,7 +149,7 @@
 			reg = <0>;
 
 			reset-assert-us = <10000>;
-			reset-deassert-us = <30000>;
+			reset-deassert-us = <80000>;
 			reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 		};
 	};
@@ -157,6 +159,7 @@
 	status = "okay";
 	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
 	pinctrl-names = "default";
+	hdmi-supply = <&vddio_ao18>;
 };
 
 &hdmi_tx_tmds_port {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts
@@ -9,7 +9,7 @@
 
 #include <dt-bindings/input/input.h>
 
-#include "meson-gxl-s905x.dtsi"
+#include "meson-gxl-s805x.dtsi"
 
 / {
 	compatible = "libretech,aml-s805x-ac", "amlogic,s805x",
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-p241.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-p241.dts
@@ -9,7 +9,7 @@
 
 #include <dt-bindings/input/input.h>
 
-#include "meson-gxl-s905x.dtsi"
+#include "meson-gxl-s805x.dtsi"
 
 / {
 	compatible = "amlogic,p241", "amlogic,s805x", "amlogic,meson-gxl";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s805x.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s805x.dtsi
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 BayLibre SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include "meson-gxl-s905x.dtsi"
+
+/ {
+	compatible = "amlogic,s805x", "amlogic,meson-gxl";
+};
+
+/* The S805X Package doesn't seem to handle the 744MHz OPP correctly */
+&mali {
+	assigned-clocks = <&clkc CLKID_MALI_0_SEL>,
+			  <&clkc CLKID_MALI_0>,
+			  <&clkc CLKID_MALI>; /* Glitch free mux */
+	assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>,
+				 <0>, /* Do Nothing */
+				 <&clkc CLKID_MALI_0>;
+	assigned-clock-rates = <0>, /* Do Nothing */
+			       <666666666>,
+			       <0>; /* Do Nothing */
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -82,7 +82,7 @@
 
 		/* External PHY reset is shared with internal PHY Led signal */
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 		interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-phicomm-n1.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-phicomm-n1.dts
@@ -18,7 +18,7 @@
 	leds {
 		compatible = "gpio-leds";
 
-		status {
+		led {
 			label = "n1:white:status";
 			gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
@@ -33,11 +33,9 @@
 
 	gpio-keys-polled {
 		compatible = "gpio-keys-polled";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		poll-interval = <100>;
 
-		button@0 {
+		power-button {
 			label = "power";
 			linux,code = <KEY_POWER>;
 			gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
@@ -192,6 +190,9 @@
 	bluetooth {
 		compatible = "brcm,bcm43438-bt";
 		shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+		max-speed = <2000000>;
+		clocks = <&wifi32k>;
+		clock-names = "lpo";
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -288,6 +288,11 @@
 	};
 };
 
+&hwrng {
+	clocks = <&clkc CLKID_RNG0>;
+	clock-names = "core";
+};
+
 &i2c_A {
 	clocks = <&clkc CLKID_I2C>;
 };
@@ -695,7 +700,7 @@
 		};
 	};
 
-	eth-phy-mux {
+	eth-phy-mux@55c {
 		compatible = "mdio-mux-mmioreg", "mdio-mux";
 		#address-cells = <1>;
 		#size-cells = <0>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
@@ -251,7 +251,7 @@
 		reg = <0>;
 
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 		interrupt-parent = <&gpio_intc>;
@@ -327,7 +327,7 @@
 	#size-cells = <0>;
 
 	bus-width = <4>;
-	max-frequency = <50000000>;
+	max-frequency = <60000000>;
 
 	non-removable;
 	disable-wp;
@@ -395,7 +395,7 @@
 		#size-cells = <1>;
 		compatible = "winbond,w25q16", "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <3000000>;
+		spi-max-frequency = <104000000>;
 	};
 };
 
@@ -409,6 +409,9 @@
 	bluetooth {
 		compatible = "brcm,bcm43438-bt";
 		shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+		max-speed = <2000000>;
+		clocks = <&wifi32k>;
+		clock-names = "lpo";
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
@@ -112,7 +112,7 @@
 		max-speed = <1000>;
 
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts
@@ -64,7 +64,7 @@
 
 		/* External PHY reset is shared with internal PHY Led signal */
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 
 		interrupt-parent = <&gpio_intc>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
@@ -114,7 +114,7 @@
 		max-speed = <1000>;
 
 		reset-assert-us = <10000>;
-		reset-deassert-us = <30000>;
+		reset-deassert-us = <80000>;
 		reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
@@ -43,13 +43,13 @@
 
 		white {
 			label = "vim3:white:sys";
-			gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "heartbeat";
 		};
 
 		red {
 			label = "vim3:red";
-			gpios = <&gpio_expander 5 GPIO_ACTIVE_LOW>;
+			gpios = <&gpio_expander 5 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
@@ -164,14 +164,6 @@
 		regulator-always-on;
 	};
 
-	reserved-memory {
-		/* TEE Reserved Memory */
-		bl32_reserved: bl32@5000000 {
-			reg = <0x0 0x05300000 0x0 0x2000000>;
-			no-map;
-		};
-	};
-
 	sdio_pwrseq: sdio-pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
@@ -361,6 +353,9 @@
 
 	bluetooth {
 		compatible = "brcm,bcm43438-bt";
+		interrupt-parent = <&gpio_intc>;
+		interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "host-wakeup";
 		shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
 		max-speed = <2000000>;
 		clocks = <&wifi32k>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
@@ -55,26 +55,6 @@
 		compatible = "operating-points-v2";
 		opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <730000>;
-		};
-
-		opp-250000000 {
-			opp-hz = /bits/ 64 <250000000>;
-			opp-microvolt = <730000>;
-		};
-
-		opp-500000000 {
-			opp-hz = /bits/ 64 <500000000>;
-			opp-microvolt = <730000>;
-		};
-
-		opp-667000000 {
-			opp-hz = /bits/ 64 <666666666>;
-			opp-microvolt = <750000>;
-		};
-
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
 			opp-microvolt = <770000>;
@@ -90,7 +70,7 @@
 			opp-microvolt = <790000>;
 		};
 
-		opp-1512000000 {
+		opp-1500000000 {
 			opp-hz = /bits/ 64 <1500000000>;
 			opp-microvolt = <800000>;
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/foundation-v8-gicv2.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/foundation-v8-gicv2.dtsi
@@ -8,7 +8,7 @@
 	gic: interrupt-controller@2c001000 {
 		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
 		#interrupt-cells = <3>;
-		#address-cells = <2>;
+		#address-cells = <1>;
 		interrupt-controller;
 		reg = <0x0 0x2c001000 0 0x1000>,
 		      <0x0 0x2c002000 0 0x2000>,
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/foundation-v8-gicv3.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/foundation-v8-gicv3.dtsi
@@ -8,9 +8,9 @@
 	gic: interrupt-controller@2f000000 {
 		compatible = "arm,gic-v3";
 		#interrupt-cells = <3>;
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x0 0x2f000000 0x100000>;
 		interrupt-controller;
 		reg =	<0x0 0x2f000000 0x0 0x10000>,
 			<0x0 0x2f100000 0x0 0x200000>,
@@ -22,7 +22,7 @@
 		its: its@2f020000 {
 			compatible = "arm,gic-v3-its";
 			msi-controller;
-			reg = <0x0 0x2f020000 0x0 0x20000>;
+			reg = <0x20000 0x20000>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/foundation-v8.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/foundation-v8.dtsi
@@ -107,51 +107,51 @@
 
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 63>;
-		interrupt-map = <0 0  0 &gic 0 0 GIC_SPI  0 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  1 &gic 0 0 GIC_SPI  1 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  2 &gic 0 0 GIC_SPI  2 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  3 &gic 0 0 GIC_SPI  3 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  4 &gic 0 0 GIC_SPI  4 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  5 &gic 0 0 GIC_SPI  5 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  6 &gic 0 0 GIC_SPI  6 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  7 &gic 0 0 GIC_SPI  7 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  8 &gic 0 0 GIC_SPI  8 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  9 &gic 0 0 GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 10 &gic 0 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 11 &gic 0 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 12 &gic 0 0 GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 13 &gic 0 0 GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 14 &gic 0 0 GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 15 &gic 0 0 GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 16 &gic 0 0 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 17 &gic 0 0 GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 18 &gic 0 0 GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 19 &gic 0 0 GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 20 &gic 0 0 GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 21 &gic 0 0 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 22 &gic 0 0 GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 23 &gic 0 0 GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 24 &gic 0 0 GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 25 &gic 0 0 GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 26 &gic 0 0 GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 27 &gic 0 0 GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 28 &gic 0 0 GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 29 &gic 0 0 GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 30 &gic 0 0 GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 31 &gic 0 0 GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 32 &gic 0 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 33 &gic 0 0 GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 34 &gic 0 0 GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 35 &gic 0 0 GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 36 &gic 0 0 GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 37 &gic 0 0 GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 38 &gic 0 0 GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 39 &gic 0 0 GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 40 &gic 0 0 GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 41 &gic 0 0 GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 42 &gic 0 0 GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0  0 &gic 0 GIC_SPI  0 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  1 &gic 0 GIC_SPI  1 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  2 &gic 0 GIC_SPI  2 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  3 &gic 0 GIC_SPI  3 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  4 &gic 0 GIC_SPI  4 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  5 &gic 0 GIC_SPI  5 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  6 &gic 0 GIC_SPI  6 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  7 &gic 0 GIC_SPI  7 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  8 &gic 0 GIC_SPI  8 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  9 &gic 0 GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 10 &gic 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 11 &gic 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 12 &gic 0 GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 13 &gic 0 GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 14 &gic 0 GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 15 &gic 0 GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 16 &gic 0 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 17 &gic 0 GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 18 &gic 0 GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 19 &gic 0 GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 20 &gic 0 GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 21 &gic 0 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 22 &gic 0 GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 23 &gic 0 GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 24 &gic 0 GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 25 &gic 0 GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 26 &gic 0 GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 27 &gic 0 GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 28 &gic 0 GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 29 &gic 0 GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 30 &gic 0 GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 31 &gic 0 GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 32 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 33 &gic 0 GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 34 &gic 0 GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 35 &gic 0 GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 36 &gic 0 GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 37 &gic 0 GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 38 &gic 0 GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 39 &gic 0 GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 40 &gic 0 GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 41 &gic 0 GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 42 &gic 0 GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
 
-		ethernet@2,02000000 {
+		ethernet@202000000 {
 			compatible = "smsc,lan91c111";
 			reg = <2 0x02000000 0x10000>;
 			interrupts = <15>;
@@ -178,7 +178,7 @@
 			clock-output-names = "v2m:refclk32khz";
 		};
 
-		iofpga@3,00000000 {
+		iofpga@300000000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
 			#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/fvp-base-revc.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/fvp-base-revc.dts
@@ -161,10 +161,10 @@
 		bus-range = <0x0 0x1>;
 		reg = <0x0 0x40000000 0x0 0x10000000>;
 		ranges = <0x2000000 0x0 0x50000000 0x0 0x50000000 0x0 0x10000000>;
-		interrupt-map = <0 0 0 1 &gic GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 2 &gic GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 3 &gic GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 4 &gic GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 2 &gic 0 0 GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 3 &gic 0 0 GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 4 &gic 0 0 GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-map-mask = <0x0 0x0 0x0 0x7>;
 		msi-map = <0x0 &its 0x0 0x10000>;
 		iommu-map = <0x0 &smmu 0x0 0x10000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/juno-base.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/juno-base.dtsi
@@ -6,7 +6,6 @@
 	/*
 	 *  Devices shared by all Juno boards
 	 */
-	dma-ranges = <0 0 0 0 0x100 0>;
 
 	memtimer: timer@2a810000 {
 		compatible = "arm,armv7-timer-mem";
@@ -63,35 +62,35 @@
 		      <0x0 0x2c02f000 0 0x2000>,
 		      <0x0 0x2c04f000 0 0x2000>,
 		      <0x0 0x2c06f000 0 0x2000>;
-		#address-cells = <2>;
+		#address-cells = <1>;
 		#interrupt-cells = <3>;
-		#size-cells = <2>;
+		#size-cells = <1>;
 		interrupt-controller;
 		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
-		ranges = <0 0 0 0x2c1c0000 0 0x40000>;
+		ranges = <0 0 0x2c1c0000 0x40000>;
 
 		v2m_0: v2m@0 {
 			compatible = "arm,gic-v2m-frame";
 			msi-controller;
-			reg = <0 0 0 0x10000>;
+			reg = <0 0x10000>;
 		};
 
 		v2m@10000 {
 			compatible = "arm,gic-v2m-frame";
 			msi-controller;
-			reg = <0 0x10000 0 0x10000>;
+			reg = <0x10000 0x10000>;
 		};
 
 		v2m@20000 {
 			compatible = "arm,gic-v2m-frame";
 			msi-controller;
-			reg = <0 0x20000 0 0x10000>;
+			reg = <0x20000 0x10000>;
 		};
 
 		v2m@30000 {
 			compatible = "arm,gic-v2m-frame";
 			msi-controller;
-			reg = <0 0x30000 0 0x10000>;
+			reg = <0x30000 0x10000>;
 		};
 	};
 
@@ -520,10 +519,10 @@
 			 <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>;
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 0 7>;
-		interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 2 &gic 0 0 GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 3 &gic 0 0 GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 0 4 &gic 0 0 GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 0 1 &gic 0 GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 2 &gic 0 GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 3 &gic 0 GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 4 &gic 0 GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
 		msi-parent = <&v2m_0>;
 		status = "disabled";
 		iommu-map-mask = <0x0>;	/* RC has no means to output PCI RID */
@@ -538,13 +537,13 @@
 		clocks {
 			compatible = "arm,scpi-clocks";
 
-			scpi_dvfs: scpi-dvfs {
+			scpi_dvfs: clocks-0 {
 				compatible = "arm,scpi-dvfs-clocks";
 				#clock-cells = <1>;
 				clock-indices = <0>, <1>, <2>;
 				clock-output-names = "atlclk", "aplclk","gpuclk";
 			};
-			scpi_clk: scpi-clk {
+			scpi_clk: clocks-1 {
 				compatible = "arm,scpi-variable-clocks";
 				#clock-cells = <1>;
 				clock-indices = <3>;
@@ -552,7 +551,7 @@
 			};
 		};
 
-		scpi_devpd: scpi-power-domains {
+		scpi_devpd: power-controller {
 			compatible = "arm,scpi-power-domains";
 			num-domains = <2>;
 			#power-domain-cells = <1>;
@@ -787,19 +786,19 @@
 
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 15>;
-		interrupt-map = <0 0  0 &gic 0 0 GIC_SPI  68 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  1 &gic 0 0 GIC_SPI  69 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  2 &gic 0 0 GIC_SPI  70 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  3 &gic 0 0 GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  4 &gic 0 0 GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  5 &gic 0 0 GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  6 &gic 0 0 GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  7 &gic 0 0 GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  8 &gic 0 0 GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0  9 &gic 0 0 GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 10 &gic 0 0 GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 11 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
-				<0 0 12 &gic 0 0 GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0  0 &gic 0 GIC_SPI  68 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  1 &gic 0 GIC_SPI  69 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  2 &gic 0 GIC_SPI  70 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  3 &gic 0 GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  4 &gic 0 GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  5 &gic 0 GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  6 &gic 0 GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  7 &gic 0 GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  8 &gic 0 GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0  9 &gic 0 GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 10 &gic 0 GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 11 &gic 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 12 &gic 0 GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
 	site2: tlx@60000000 {
@@ -809,6 +808,6 @@
 		ranges = <0 0 0x60000000 0x10000000>;
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0>;
-		interrupt-map = <0 0 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map = <0 0 &gic 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/juno-clocks.dtsi
+++ linux-ein-5.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-ein-5.4.0.orig/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
@@ -103,7 +103,7 @@
 				};
 			};
 
-			flash@0,00000000 {
+			flash@0 {
 				/* 2 * 32MiB NOR Flash memory mounted on CS0 */
 				compatible = "arm,vexpress-flash", "cfi-flash";
 				reg = <0 0x00000000 0x04000000>;
@@ -120,7 +120,7 @@
 				};
 			};
 
-			ethernet@2,00000000 {
+			ethernet@200000000 {
 				compatible = "smsc,lan9118", "smsc,lan9115";
 				reg = <2 0x00000000 0x10000>;
 				interrupts = <3>;
@@ -133,7 +133,7 @@
 				vddvario-supply = <&mb_fixed_3v3>;
 			};
 
-			iofpga@3,00000000 {
+			iofpga@300000000 {
 				compatible = "simple-bus";
 				#address-cells = <1>;
 				#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/rtsm_ve-motherboard-rs2.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/rtsm_ve-motherboard-rs2.dtsi
@@ -9,7 +9,7 @@
 		motherboard {
 			arm,v2m-memory-map = "rs2";
 
-			iofpga@3,00000000 {
+			iofpga@300000000 {
 				virtio-p9@140000 {
 					compatible = "virtio,mmio";
 					reg = <0x140000 0x200>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
@@ -17,14 +17,14 @@
 			#interrupt-cells = <1>;
 			ranges;
 
-			flash@0,00000000 {
+			flash@0 {
 				compatible = "arm,vexpress-flash", "cfi-flash";
 				reg = <0 0x00000000 0x04000000>,
 				      <4 0x00000000 0x04000000>;
 				bank-width = <4>;
 			};
 
-			ethernet@2,02000000 {
+			ethernet@202000000 {
 				compatible = "smsc,lan91c111";
 				reg = <2 0x02000000 0x10000>;
 				interrupts = <15>;
@@ -51,7 +51,7 @@
 				clock-output-names = "v2m:refclk32khz";
 			};
 
-			iofpga@3,00000000 {
+			iofpga@300000000 {
 				compatible = "simple-bus";
 				#address-cells = <1>;
 				#size-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts
@@ -111,8 +111,8 @@
 		compatible = "silabs,si3226x";
 		reg = <0>;
 		spi-max-frequency = <5000000>;
-		spi-cpha = <1>;
-		spi-cpol = <1>;
+		spi-cpha;
+		spi-cpol;
 		pl022,hierarchy = <0>;
 		pl022,interface = <0>;
 		pl022,slave-tx-disable = <0>;
@@ -135,8 +135,8 @@
 		at25,byte-len = <0x8000>;
 		at25,addr-mode = <2>;
 		at25,page-size = <64>;
-		spi-cpha = <1>;
-		spi-cpol = <1>;
+		spi-cpha;
+		spi-cpol;
 		pl022,hierarchy = <0>;
 		pl022,interface = <0>;
 		pl022,slave-tx-disable = <0>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
@@ -687,7 +687,7 @@
 			};
 		};
 
-		sata: ahci@663f2000 {
+		sata: sata@663f2000 {
 			compatible = "brcm,iproc-ahci", "generic-ahci";
 			reg = <0x663f2000 0x1000>;
 			dma-coherent;
@@ -745,7 +745,7 @@
 		};
 
 		qspi: spi@66470200 {
-			compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
+			compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi";
 			reg = <0x66470200 0x184>,
 				<0x66470000 0x124>,
 				<0x67017408 0x004>,
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi
@@ -4,21 +4,26 @@
  */
 	usb {
 		compatible = "simple-bus";
-		dma-ranges;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0x0 0x0 0x68500000 0x00400000>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges = <0x0 0x0 0x0 0x68500000 0x0 0x00400000>;
+
+		/*
+		 * Internally, USB bus to the interconnect can only address up
+		 * to 40-bit
+		 */
+		dma-ranges = <0 0 0 0 0x100 0x0>;
 
 		usbphy0: usb-phy@0 {
 			compatible = "brcm,sr-usb-combo-phy";
-			reg = <0x00000000 0x100>;
+			reg = <0x0 0x00000000 0x0 0x100>;
 			#phy-cells = <1>;
 			status = "disabled";
 		};
 
 		xhci0: usb@1000 {
 			compatible = "generic-xhci";
-			reg = <0x00001000 0x1000>;
+			reg = <0x0 0x00001000 0x0 0x1000>;
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
 			phys = <&usbphy0 1>, <&usbphy0 0>;
 			phy-names = "phy0", "phy1";
@@ -28,7 +33,7 @@
 
 		bdc0: usb@2000 {
 			compatible = "brcm,bdc-v0.16";
-			reg = <0x00002000 0x1000>;
+			reg = <0x0 0x00002000 0x0 0x1000>;
 			interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>;
 			phys = <&usbphy0 0>, <&usbphy0 1>;
 			phy-names = "phy0", "phy1";
@@ -38,21 +43,21 @@
 
 		usbphy1: usb-phy@10000 {
 			compatible = "brcm,sr-usb-combo-phy";
-			reg = <0x00010000 0x100>;
+			reg = <0x0 0x00010000 0x0 0x100>;
 			#phy-cells = <1>;
 			status = "disabled";
 		};
 
 		usbphy2: usb-phy@20000 {
 			compatible = "brcm,sr-usb-hs-phy";
-			reg = <0x00020000 0x100>;
+			reg = <0x0 0x00020000 0x0 0x100>;
 			#phy-cells = <0>;
 			status = "disabled";
 		};
 
 		xhci1: usb@11000 {
 			compatible = "generic-xhci";
-			reg = <0x00011000 0x1000>;
+			reg = <0x0 0x00011000 0x0 0x1000>;
 			interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
 			phys = <&usbphy1 1>, <&usbphy2>, <&usbphy1 0>;
 			phy-names = "phy0", "phy1", "phy2";
@@ -62,7 +67,7 @@
 
 		bdc1: usb@21000 {
 			compatible = "brcm,bdc-v0.16";
-			reg = <0x00021000 0x1000>;
+			reg = <0x0 0x00021000 0x0 0x1000>;
 			interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
 			phys = <&usbphy2>;
 			phy-names = "phy0";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
@@ -389,7 +389,7 @@
 	s2mps13-pmic@66 {
 		compatible = "samsung,s2mps13-pmic";
 		interrupt-parent = <&gpa0>;
-		interrupts = <7 IRQ_TYPE_NONE>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
 		reg = <0x66>;
 		samsung,s2mps11-wrstbi-ground;
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/exynos/exynos5433.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/exynos/exynos5433.dtsi
@@ -18,8 +18,8 @@
 
 / {
 	compatible = "samsung,exynos5433";
-	#address-cells = <1>;
-	#size-cells = <1>;
+	#address-cells = <2>;
+	#size-cells = <2>;
 
 	interrupt-parent = <&gic>;
 
@@ -311,7 +311,7 @@
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		ranges;
+		ranges = <0x0 0x0 0x0 0x18000000>;
 
 		chipid@10000000 {
 			compatible = "samsung,exynos4210-chipid";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
@@ -90,7 +90,7 @@
 	s2mps15_pmic@66 {
 		compatible = "samsung,s2mps15-pmic";
 		reg = <0x66>;
-		interrupts = <2 IRQ_TYPE_NONE>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-parent = <&gpa0>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pmic_irq>;
@@ -157,6 +157,7 @@
 				regulator-min-microvolt = <700000>;
 				regulator-max-microvolt = <1150000>;
 				regulator-enable-ramp-delay = <125>;
+				regulator-always-on;
 			};
 
 			ldo8_reg: LDO8 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/exynos/exynos7.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/exynos/exynos7.dtsi
@@ -12,8 +12,8 @@
 / {
 	compatible = "samsung,exynos7";
 	interrupt-parent = <&gic>;
-	#address-cells = <1>;
-	#size-cells = <1>;
+	#address-cells = <2>;
+	#size-cells = <2>;
 
 	aliases {
 		pinctrl0 = &pinctrl_alive;
@@ -90,15 +90,17 @@
 	};
 
 	psci {
-		compatible = "arm,psci-0.2";
+		compatible = "arm,psci";
 		method = "smc";
+		cpu_off = <0x84000002>;
+		cpu_on = <0xC4000003>;
 	};
 
 	soc: soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		ranges;
+		ranges = <0 0 0 0x18000000>;
 
 		chipid@10000000 {
 			compatible = "samsung,exynos4210-chipid";
@@ -111,7 +113,7 @@
 			#address-cells = <0>;
 			interrupt-controller;
 			reg =	<0x11001000 0x1000>,
-				<0x11002000 0x1000>,
+				<0x11002000 0x2000>,
 				<0x11004000 0x2000>,
 				<0x11006000 0x2000>;
 		};
@@ -494,13 +496,6 @@
 		pmu_system_controller: system-controller@105c0000 {
 			compatible = "samsung,exynos7-pmu", "syscon";
 			reg = <0x105c0000 0x5000>;
-
-			reboot: syscon-reboot {
-				compatible = "syscon-reboot";
-				regmap = <&pmu_system_controller>;
-				offset = <0x0400>;
-				mask = <0x1>;
-			};
 		};
 
 		rtc: rtc@10590000 {
@@ -650,3 +645,4 @@
 };
 
 #include "exynos7-pinctrl.dtsi"
+#include "arm/exynos-syscon-restart.dtsi"
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/Makefile
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/Makefile
@@ -22,12 +22,21 @@
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-ddr4-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7902.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-x8high35-pdk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-x8high35-bms.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-nitrogen.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-pe100a.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-phanbell.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-pico-pi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
@@ -177,6 +177,7 @@
 			ranges = <0x0 0x00 0x1700000 0x100000>;
 			reg = <0x00 0x1700000 0x0 0x100000>;
 			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+			dma-coherent;
 
 			sec_jr0: jr@10000 {
 				compatible = "fsl,sec-v5.4-job-ring",
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
@@ -161,11 +161,6 @@
 				vcc-supply = <&sb_3v3>;
 			};
 
-			rtc@51 {
-				compatible = "nxp,pcf2129";
-				reg = <0x51>;
-			};
-
 			eeprom@56 {
 				compatible = "atmel,24c512";
 				reg = <0x56>;
@@ -209,6 +204,15 @@
 
 };
 
+&i2c1 {
+	status = "okay";
+
+	rtc@51 {
+		compatible = "nxp,pcf2129";
+		reg = <0x51>;
+	};
+};
+
 &enetc_port1 {
 	phy-handle = <&qds_phy1>;
 	phy-connection-type = "rgmii-id";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
@@ -65,7 +65,7 @@
 		};
 	};
 
-	sysclk: clock-sysclk {
+	sysclk: sysclk {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <100000000>;
@@ -102,8 +102,8 @@
 
 	reboot {
 		compatible ="syscon-reboot";
-		regmap = <&dcfg>;
-		offset = <0xb0>;
+		regmap = <&rst>;
+		offset = <0>;
 		mask = <0x02>;
 	};
 
@@ -151,14 +151,20 @@
 		ddr: memory-controller@1080000 {
 			compatible = "fsl,qoriq-memory-controller";
 			reg = <0x0 0x1080000 0x0 0x1000>;
-			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-			big-endian;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			little-endian;
 		};
 
 		dcfg: syscon@1e00000 {
 			compatible = "fsl,ls1028a-dcfg", "syscon";
 			reg = <0x0 0x1e00000 0x0 0x10000>;
-			big-endian;
+			little-endian;
+		};
+
+		rst: syscon@1e60000 {
+			compatible = "syscon";
+			reg = <0x0 0x1e60000 0x0 0x10000>;
+			little-endian;
 		};
 
 		scfg: syscon@1fc0000 {
@@ -281,6 +287,24 @@
 			status = "disabled";
 		};
 
+		can0: can@2180000 {
+			compatible = "fsl,ls1028ar1-flexcan", "fsl,lx2160ar1-flexcan";
+			reg = <0x0 0x2180000 0x0 0x10000>;
+			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&sysclk>, <&clockgen 4 1>;
+			clock-names = "ipg", "per";
+			status = "disabled";
+		};
+
+		can1: can@2190000 {
+			compatible = "fsl,ls1028ar1-flexcan", "fsl,lx2160ar1-flexcan";
+			reg = <0x0 0x2190000 0x0 0x10000>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&sysclk>, <&clockgen 4 1>;
+			clock-names = "ipg", "per";
+			status = "disabled";
+		};
+
 		duart0: serial@21c0500 {
 			compatible = "fsl,ns16550", "ns16550a";
 			reg = <0x00 0x21c0500 0x0 0x100>;
@@ -490,14 +514,14 @@
 			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc000000 0x0 0x1000>;
 			clocks = <&clockgen 4 15>, <&clockgen 4 15>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster1_core1_watchdog: watchdog@c010000 {
 			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc010000 0x0 0x1000>;
 			clocks = <&clockgen 4 15>, <&clockgen 4 15>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		sai1: audio-controller@f100000 {
@@ -567,7 +591,7 @@
 					       0x00010004 0x0000003d
 					       0x00010005 0x00000045
 					       0x00010006 0x0000004d
-					       0x00010007 0x00000045
+					       0x00010007 0x00000055
 					       0x00010008 0x0000005e
 					       0x00010009 0x00000066
 					       0x0001000a 0x0000006e
@@ -667,7 +691,7 @@
 			ethernet@0,4 {
 				compatible = "fsl,enetc-ptp";
 				reg = <0x000400 0 0 0 0>;
-				clocks = <&clockgen 4 0>;
+				clocks = <&clockgen 2 3>;
 				little-endian;
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi
@@ -20,6 +20,8 @@
 };
 
 &fman0 {
+	fsl,erratum-a050385;
+
 	/* these aliases provide the FMan ports mapping */
 	enet0: ethernet@e0000 {
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
@@ -119,12 +119,12 @@
 
 	ethernet@e4000 {
 		phy-handle = <&rgmii_phy1>;
-		phy-connection-type = "rgmii-txid";
+		phy-connection-type = "rgmii-id";
 	};
 
 	ethernet@e6000 {
 		phy-handle = <&rgmii_phy2>;
-		phy-connection-type = "rgmii-txid";
+		phy-connection-type = "rgmii-id";
 	};
 
 	ethernet@e8000 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -241,6 +241,7 @@
 			ranges = <0x0 0x00 0x1700000 0x100000>;
 			reg = <0x00 0x1700000 0x0 0x100000>;
 			interrupts = <0 75 0x4>;
+			dma-coherent;
 
 			sec_jr0: jr@10000 {
 				compatible = "fsl,sec-v5.4-job-ring",
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts
@@ -83,15 +83,9 @@
 			};
 
 			eeprom@52 {
-				compatible = "atmel,24c512";
+				compatible = "onnn,cat24c04", "atmel,24c04";
 				reg = <0x52>;
 			};
-
-			eeprom@53 {
-				compatible = "atmel,24c512";
-				reg = <0x53>;
-			};
-
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
@@ -58,14 +58,9 @@
 	};
 
 	eeprom@52 {
-		compatible = "atmel,24c512";
+		compatible = "onnn,cat24c05", "atmel,24c04";
 		reg = <0x52>;
 	};
-
-	eeprom@53 {
-		compatible = "atmel,24c512";
-		reg = <0x53>;
-	};
 };
 
 &i2c3 {
@@ -127,12 +122,12 @@
 &fman0 {
 	ethernet@e4000 {
 		phy-handle = <&rgmii_phy1>;
-		phy-connection-type = "rgmii";
+		phy-connection-type = "rgmii-id";
 	};
 
 	ethernet@e6000 {
 		phy-handle = <&rgmii_phy2>;
-		phy-connection-type = "rgmii";
+		phy-connection-type = "rgmii-id";
 	};
 
 	ethernet@e8000 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -244,6 +244,7 @@
 			ranges = <0x0 0x00 0x1700000 0x100000>;
 			reg = <0x00 0x1700000 0x0 0x100000>;
 			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+			dma-coherent;
 
 			sec_jr0: jr@10000 {
 				compatible = "fsl,sec-v5.4-job-ring",
@@ -304,7 +305,7 @@
 
 		dcfg: dcfg@1ee0000 {
 			compatible = "fsl,ls1046a-dcfg", "syscon";
-			reg = <0x0 0x1ee0000 0x0 0x10000>;
+			reg = <0x0 0x1ee0000 0x0 0x1000>;
 			big-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -637,59 +637,59 @@
 		};
 
 		cluster1_core0_watchdog: wdt@c000000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc000000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster1_core1_watchdog: wdt@c010000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc010000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster1_core2_watchdog: wdt@c020000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc020000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster1_core3_watchdog: wdt@c030000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc030000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core0_watchdog: wdt@c100000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc100000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core1_watchdog: wdt@c110000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc110000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core2_watchdog: wdt@c120000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc120000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core3_watchdog: wdt@c130000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc130000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		fsl_mc: fsl-mc@80c000000 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
@@ -227,59 +227,59 @@
 		};
 
 		cluster1_core0_watchdog: wdt@c000000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc000000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster1_core1_watchdog: wdt@c010000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc010000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core0_watchdog: wdt@c100000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc100000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster2_core1_watchdog: wdt@c110000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc110000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster3_core0_watchdog: wdt@c200000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc200000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster3_core1_watchdog: wdt@c210000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc210000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster4_core0_watchdog: wdt@c300000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc300000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		cluster4_core1_watchdog: wdt@c310000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xc310000 0x0 0x1000>;
 			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
-			clock-names = "apb_pclk", "wdog_clk";
+			clock-names = "wdog_clk", "apb_pclk";
 		};
 
 		crypto: crypto@8000000 {
@@ -501,7 +501,6 @@
 			clocks = <&clockgen 4 3>;
 			clock-names = "dspi";
 			spi-num-chipselects = <5>;
-			bus-num = <0>;
 		};
 
 		esdhc: esdhc@2140000 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm-ddr4-evk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm-ddr4-evk.dts
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8mm-evk.dtsi"
+
+/ {
+	model = "FSL i.MX8MM DDR4 EVK with CYW43455 WIFI/BT board";
+	compatible = "fsl,imx8mm-ddr4-evk", "fsl,imx8mm";
+
+	leds {
+		pinctrl-0 = <&pinctrl_gpio_led_2>;
+
+		status {
+			gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&gpmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpmi_nand>;
+	nand-on-flash-bbt;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_gpmi_nand: gpmi-nand {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_ALE_RAWNAND_ALE		0x00000096
+			MX8MM_IOMUXC_NAND_CE0_B_RAWNAND_CE0_B		0x00000096
+			MX8MM_IOMUXC_NAND_CE1_B_RAWNAND_CE1_B		0x00000096
+			MX8MM_IOMUXC_NAND_CLE_RAWNAND_CLE		0x00000096
+			MX8MM_IOMUXC_NAND_DATA00_RAWNAND_DATA00		0x00000096
+			MX8MM_IOMUXC_NAND_DATA01_RAWNAND_DATA01		0x00000096
+			MX8MM_IOMUXC_NAND_DATA02_RAWNAND_DATA02		0x00000096
+			MX8MM_IOMUXC_NAND_DATA03_RAWNAND_DATA03		0x00000096
+			MX8MM_IOMUXC_NAND_DATA04_RAWNAND_DATA04		0x00000096
+			MX8MM_IOMUXC_NAND_DATA05_RAWNAND_DATA05		0x00000096
+			MX8MM_IOMUXC_NAND_DATA06_RAWNAND_DATA06		0x00000096
+			MX8MM_IOMUXC_NAND_DATA07_RAWNAND_DATA07		0x00000096
+			MX8MM_IOMUXC_NAND_RE_B_RAWNAND_RE_B		0x00000096
+			MX8MM_IOMUXC_NAND_READY_B_RAWNAND_READY_B	0x00000056
+			MX8MM_IOMUXC_NAND_WE_B_RAWNAND_WE_B		0x00000096
+			MX8MM_IOMUXC_NAND_WP_B_RAWNAND_WP_B		0x00000096
+		>;
+	};
+
+	pinctrl_gpio_led_2: gpioled2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_CE3_B_GPIO3_IO4	0x19
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
@@ -1,145 +1,61 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright 2019 NXP
+ * Copyright 2019-2020 NXP
  */
 
 /dts-v1/;
 
 #include <dt-bindings/usb/pd.h>
-#include "imx8mm.dtsi"
+#include "imx8mm-evk.dtsi"
 
 / {
 	model = "FSL i.MX8MM EVK board";
 	compatible = "fsl,imx8mm-evk", "fsl,imx8mm";
 
-	chosen {
-		stdout-path = &uart2;
-	};
-
-	leds {
-		compatible = "gpio-leds";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_gpio_led>;
-
-		status {
-			label = "status";
-			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
-			default-state = "on";
-		};
-	};
-
-	reg_usdhc2_vmmc: regulator-usdhc2 {
-		compatible = "regulator-fixed";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
-		regulator-name = "VSD_3V3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
+	aliases {
+		spi0 = &flexspi;
 	};
+};
 
-	wm8524: audio-codec {
-		#sound-dai-cells = <0>;
-		compatible = "wlf,wm8524";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_gpio_wlf>;
-		wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
-	};
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
 
-	sound-wm8524 {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "wm8524-audio";
-		simple-audio-card,format = "i2s";
-		simple-audio-card,frame-master = <&cpudai>;
-		simple-audio-card,bitclock-master = <&cpudai>;
-		simple-audio-card,widgets =
-			"Line", "Left Line Out Jack",
-			"Line", "Right Line Out Jack";
-		simple-audio-card,routing =
-			"Left Line Out Jack", "LINEVOUTL",
-			"Right Line Out Jack", "LINEVOUTR";
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
 
-		cpudai: simple-audio-card,cpu {
-			sound-dai = <&sai3>;
+		opp-25M {
+			opp-hz = /bits/ 64 <25000000>;
 		};
 
-		simple-audio-card,codec {
-			sound-dai = <&wm8524>;
-			clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
+		opp-100M {
+			opp-hz = /bits/ 64 <100000000>;
 		};
-	};
-};
-
-&A53_0 {
-	cpu-supply = <&buck2_reg>;
-};
-
-&fec1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_fec1>;
-	phy-mode = "rgmii-id";
-	phy-handle = <&ethphy0>;
-	fsl,magic-packet;
-	status = "okay";
 
-	mdio {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethphy0: ethernet-phy@0 {
-			compatible = "ethernet-phy-ieee802.3-c22";
-			reg = <0>;
+		opp-750M {
+			opp-hz = /bits/ 64 <750000000>;
 		};
 	};
 };
 
-&sai3 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sai3>;
-	assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
-	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
-	assigned-clock-rates = <24576000>;
-	status = "okay";
-};
-
-&snvs_pwrkey {
-	status = "okay";
-};
-
-&uart2 { /* console */
+&flexspi {
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart2>;
+	pinctrl-0 = <&pinctrl_flexspi>;
 	status = "okay";
-};
 
-&usbotg1 {
-	dr_mode = "otg";
-	hnp-disable;
-	srp-disable;
-	adp-disable;
-	usb-role-switch;
-	status = "okay";
-
-	port {
-		usb1_drd_sw: endpoint {
-			remote-endpoint = <&typec1_dr_sw>;
-		};
+	flash@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <80000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
 	};
 };
 
-&usdhc2 {
-	pinctrl-names = "default", "state_100mhz", "state_200mhz";
-	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-	cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
-	bus-width = <4>;
-	vmmc-supply = <&reg_usdhc2_vmmc>;
-	status = "okay";
-};
-
 &usdhc3 {
+	assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc3>;
 	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
@@ -149,339 +65,64 @@
 	status = "okay";
 };
 
-&wdog1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_wdog>;
-	fsl,ext-reset-output;
-	status = "okay";
-};
-
-&i2c1 {
-	clock-frequency = <400000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c1>;
-	status = "okay";
-
-	pmic@4b {
-		compatible = "rohm,bd71847";
-		reg = <0x4b>;
-		pinctrl-0 = <&pinctrl_pmic>;
-		interrupt-parent = <&gpio1>;
-		interrupts = <3 GPIO_ACTIVE_LOW>;
-		rohm,reset-snvs-powered;
-
-		regulators {
-			buck1_reg: BUCK1 {
-				regulator-name = "BUCK1";
-				regulator-min-microvolt = <700000>;
-				regulator-max-microvolt = <1300000>;
-				regulator-boot-on;
-				regulator-always-on;
-				regulator-ramp-delay = <1250>;
-			};
-
-			buck2_reg: BUCK2 {
-				regulator-name = "BUCK2";
-				regulator-min-microvolt = <700000>;
-				regulator-max-microvolt = <1300000>;
-				regulator-boot-on;
-				regulator-always-on;
-				regulator-ramp-delay = <1250>;
-				rohm,dvs-run-voltage = <1000000>;
-				rohm,dvs-idle-voltage = <900000>;
-			};
-
-			buck3_reg: BUCK3 {
-				// BUCK5 in datasheet
-				regulator-name = "BUCK3";
-				regulator-min-microvolt = <700000>;
-				regulator-max-microvolt = <1350000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			buck4_reg: BUCK4 {
-				// BUCK6 in datasheet
-				regulator-name = "BUCK4";
-				regulator-min-microvolt = <3000000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			buck5_reg: BUCK5 {
-				// BUCK7 in datasheet
-				regulator-name = "BUCK5";
-				regulator-min-microvolt = <1605000>;
-				regulator-max-microvolt = <1995000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			buck6_reg: BUCK6 {
-				// BUCK8 in datasheet
-				regulator-name = "BUCK6";
-				regulator-min-microvolt = <800000>;
-				regulator-max-microvolt = <1400000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			ldo1_reg: LDO1 {
-				regulator-name = "LDO1";
-				regulator-min-microvolt = <3000000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			ldo2_reg: LDO2 {
-				regulator-name = "LDO2";
-				regulator-min-microvolt = <900000>;
-				regulator-max-microvolt = <900000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			ldo3_reg: LDO3 {
-				regulator-name = "LDO3";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			ldo4_reg: LDO4 {
-				regulator-name = "LDO4";
-				regulator-min-microvolt = <900000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			ldo6_reg: LDO6 {
-				regulator-name = "LDO6";
-				regulator-min-microvolt = <900000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-		};
-	};
-};
-
-&i2c2 {
-	clock-frequency = <400000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c2>;
-	status = "okay";
-
-	ptn5110: tcpc@50 {
-		compatible = "nxp,ptn5110";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_typec1>;
-		reg = <0x50>;
-		interrupt-parent = <&gpio2>;
-		interrupts = <11 8>;
-		status = "okay";
-
-		port {
-			typec1_dr_sw: endpoint {
-				remote-endpoint = <&usb1_drd_sw>;
-			};
-		};
-
-		typec1_con: connector {
-			compatible = "usb-c-connector";
-			label = "USB-C";
-			power-role = "dual";
-			data-role = "dual";
-			try-power-role = "sink";
-			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
-			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
-				     PDO_VAR(5000, 20000, 3000)>;
-			op-sink-microwatt = <15000000>;
-			self-powered;
-		};
-	};
-};
-
 &iomuxc {
-	pinctrl-names = "default";
-
-	pinctrl_fec1: fec1grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
-			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
-			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
-			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
-			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
-			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
-			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
-			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
-			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
-			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
-			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
-			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
-			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
-			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
-			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
-		>;
-	};
-
-	pinctrl_gpio_led: gpioledgrp {
-		fsl,pins = <
-			MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16	0x19
-		>;
-	};
-
-	pinctrl_gpio_wlf: gpiowlfgrp {
-		fsl,pins = <
-			MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21	0xd6
-		>;
-	};
-
-	pinctrl_i2c1: i2c1grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
-			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
-		>;
-	};
-
-	pinctrl_i2c2: i2c2grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL			0x400001c3
-			MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA			0x400001c3
-		>;
-	};
-
-	pinctrl_pmic: pmicirq {
-		fsl,pins = <
-			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x41
-		>;
-	};
-
-	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
-		fsl,pins = <
-			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
-		>;
-	};
-
-	pinctrl_sai3: sai3grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
-			MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
-			MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
-			MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
-		>;
-	};
-
-	pinctrl_typec1: typec1grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x159
-		>;
-	};
-
-	pinctrl_uart2: uart2grp {
-		fsl,pins = <
-			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
-			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
-		>;
-	};
-
-	pinctrl_usdhc2_gpio: usdhc2grpgpio {
-		fsl,pins = <
-			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x1c4
-		>;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
+	pinctrl_flexspi: flexspigrp {
 		fsl,pins = <
-			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
-			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
-			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
-			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
-			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
-			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
-			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
-		>;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
-		fsl,pins = <
-			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
-			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
-			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
-			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
-			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
-			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
-			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
-		>;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
-		fsl,pins = <
-			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
-			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
-			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
-			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
-			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
-			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
-			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+			MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK               0x1c2
+			MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B            0x82
+			MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0           0x82
+			MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1           0x82
+			MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2           0x82
+			MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3           0x82
 		>;
 	};
 
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
-			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x190
-			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
-			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
-			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
-			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
-			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
-			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
-			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
-			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
-			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
-			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x190
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x190
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d0
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d0
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d0
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d0
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d0
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d0
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d0
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d0
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d0
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d0
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x190
 		>;
 	};
 
-	pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
-		fsl,pins = <
-			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x194
-			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
-			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
-			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
-			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
-			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
-			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
-			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
-			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
-			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
-			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x194
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x194
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d4
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d4
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d4
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d4
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d4
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d4
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d4
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d4
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d4
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x194
 		>;
 	};
 
-	pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
-		fsl,pins = <
-			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK		0x196
-			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
-			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
-			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
-			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
-			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
-			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
-			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
-			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
-			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
-			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 		0x196
-		>;
-	};
-
-	pinctrl_wdog: wdoggrp {
-		fsl,pins = <
-			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x196
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d6
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d6
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d6
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d6
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d6
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d6
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d6
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d6
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d6
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x196
 		>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020 NXP
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx8mm.dtsi"
+
+/ {
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+
+		status {
+			label = "status";
+			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ir>;
+		linux,autosuspend-period = <125>;
+	};
+
+	wm8524: audio-codec {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8524";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_wlf>;
+		wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
+	};
+
+	sound-wm8524 {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "wm8524-audio";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&cpudai>;
+		simple-audio-card,bitclock-master = <&cpudai>;
+		simple-audio-card,widgets =
+			"Line", "Left Line Out Jack",
+			"Line", "Right Line Out Jack";
+		simple-audio-card,routing =
+			"Left Line Out Jack", "LINEVOUTL",
+			"Right Line Out Jack", "LINEVOUTR";
+
+		cpudai: simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+			dai-tdm-slot-num = <2>;
+			dai-tdm-slot-width = <32>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&wm8524>;
+			clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
+		};
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2_reg>;
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic@4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-0 = <&pinctrl_pmic>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 GPIO_ACTIVE_LOW>;
+		rohm,reset-snvs-powered;
+
+		#clock-cells = <0>;
+		clocks = <&osc_32k 0>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			buck3_reg: BUCK3 {
+				// BUCK5 in datasheet
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck4_reg: BUCK4 {
+				// BUCK6 in datasheet
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				// BUCK7 in datasheet
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				// BUCK8 in datasheet
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ptn5110: tcpc@50 {
+		compatible = "nxp,ptn5110";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_typec1>;
+		reg = <0x50>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <11 8>;
+		status = "okay";
+
+		port {
+			typec1_dr_sw: endpoint {
+				remote-endpoint = <&usb1_drd_sw>;
+			};
+		};
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			power-role = "dual";
+			data-role = "dual";
+			try-power-role = "sink";
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			op-sink-microwatt = <15000000>;
+			self-powered;
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	pca6416: gpio@20 {
+		compatible = "ti,tca6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart2 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	usb-role-switch;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MM_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+	bus-width = <4>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
+			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22		0x19
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_ir: irgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13              0x4f
+		>;
+	};
+
+	pinctrl_gpio_wlf: gpiowlfgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C4_SDA_GPIO5_IO21	0xd6
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
+			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL			0x400001c3
+			MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA			0x400001c3
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL			0x400001c3
+			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA			0x400001c3
+		>;
+	};
+
+	pinctrl_pmic: pmicirqgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x41
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
+			MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
+			MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
+			MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
+		>;
+	};
+
+	pinctrl_typec1: typec1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11	0x159
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2grpgpiogrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x1c4
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h
@@ -124,7 +124,7 @@
 #define MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD                                     0x0A4 0x30C 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SD1_CMD_GPIO2_IO1                                      0x0A4 0x30C 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0                                 0x0A8 0x310 0x000 0x0 0x0
-#define MX8MM_IOMUXC_SD1_DATA0_GPIO2_IO2                                    0x0A8 0x31  0x000 0x5 0x0
+#define MX8MM_IOMUXC_SD1_DATA0_GPIO2_IO2                                    0x0A8 0x310 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1                                 0x0AC 0x314 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SD1_DATA1_GPIO2_IO3                                    0x0AC 0x314 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2                                 0x0B0 0x318 0x000 0x0 0x0
@@ -430,18 +430,26 @@
 #define MX8MM_IOMUXC_SAI1_MCLK_SIM_M_HRESP                                  0x1AC 0x414 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI2_RXFS_SAI2_RX_SYNC                                 0x1B0 0x418 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI2_RXFS_SAI5_TX_SYNC                                 0x1B0 0x418 0x4EC 0x1 0x2
+#define MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX                                 0x1B0 0x418 0x000 0x4 0x0
+#define MX8MM_IOMUXC_SAI2_RXFS_UART1_DTE_RX                                 0x1B0 0x418 0x4F4 0x4 0x2
 #define MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21                                   0x1B0 0x418 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI2_RXFS_SIM_M_HSIZE0                                 0x1B0 0x418 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI2_RXC_SAI2_RX_BCLK                                  0x1B4 0x41C 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI2_RXC_SAI5_TX_BCLK                                  0x1B4 0x41C 0x4E8 0x1 0x2
+#define MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX                                  0x1B4 0x41C 0x4F4 0x4 0x3
+#define MX8MM_IOMUXC_SAI2_RXC_UART1_DTE_TX                                  0x1B4 0x41C 0x000 0x4 0x0
 #define MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22                                    0x1B4 0x41C 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI2_RXC_SIM_M_HSIZE1                                  0x1B4 0x41C 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0                                0x1B8 0x420 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI2_RXD0_SAI5_TX_DATA0                                0x1B8 0x420 0x000 0x1 0x0
+#define MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B                              0x1B8 0x420 0x4F0 0x4 0x2
+#define MX8MM_IOMUXC_SAI2_RXD0_UART1_DTE_CTS_B                              0x1B8 0x420 0x000 0x4 0x0
 #define MX8MM_IOMUXC_SAI2_RXD0_GPIO4_IO23                                   0x1B8 0x420 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI2_RXD0_SIM_M_HSIZE2                                 0x1B8 0x420 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC                                 0x1BC 0x424 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI2_TXFS_SAI5_TX_DATA1                                0x1BC 0x424 0x000 0x1 0x0
+#define MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B                              0x1BC 0x424 0x000 0x4 0x0
+#define MX8MM_IOMUXC_SAI2_TXFS_UART1_DTE_RTS_B                              0x1BC 0x424 0x4F0 0x4 0x3
 #define MX8MM_IOMUXC_SAI2_TXFS_GPIO4_IO24                                   0x1BC 0x424 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI2_TXFS_SIM_M_HWRITE                                 0x1BC 0x424 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI2_TXC_SAI2_TX_BCLK                                  0x1C0 0x428 0x000 0x0 0x0
@@ -464,21 +472,29 @@
 #define MX8MM_IOMUXC_SAI3_RXC_SAI3_RX_BCLK                                  0x1D0 0x438 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI3_RXC_GPT1_CLK                                      0x1D0 0x438 0x000 0x1 0x0
 #define MX8MM_IOMUXC_SAI3_RXC_SAI5_RX_BCLK                                  0x1D0 0x438 0x4D0 0x2 0x2
+#define MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B                               0x1D0 0x438 0x000 0x4 0x0
+#define MX8MM_IOMUXC_SAI3_RXC_UART2_DTE_RTS_B                               0x1D0 0x438 0x4F8 0x4 0x2
 #define MX8MM_IOMUXC_SAI3_RXC_GPIO4_IO29                                    0x1D0 0x438 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI3_RXC_TPSMP_HTRANS1                                 0x1D0 0x438 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0                                 0x1D4 0x43C 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI3_RXD_GPT1_COMPARE1                                 0x1D4 0x43C 0x000 0x1 0x0
 #define MX8MM_IOMUXC_SAI3_RXD_SAI5_RX_DATA0                                 0x1D4 0x43C 0x4D4 0x2 0x2
+#define MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B                               0x1D4 0x43C 0x4F8 0x4 0x3
+#define MX8MM_IOMUXC_SAI3_RXD_UART2_DTE_CTS_B                               0x1D4 0x43C 0x000 0x4 0x0
 #define MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30                                    0x1D4 0x43C 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI3_RXD_TPSMP_HDATA0                                  0x1D4 0x43C 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC                                 0x1D8 0x440 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI3_TXFS_GPT1_CAPTURE2                                0x1D8 0x440 0x000 0x1 0x0
 #define MX8MM_IOMUXC_SAI3_TXFS_SAI5_RX_DATA1                                0x1D8 0x440 0x4D8 0x2 0x2
+#define MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX                                 0x1D8 0x440 0x4Fc 0x4 0x2
+#define MX8MM_IOMUXC_SAI3_TXFS_UART2_DTE_TX                                 0x1D8 0x440 0x000 0x4 0x0
 #define MX8MM_IOMUXC_SAI3_TXFS_GPIO4_IO31                                   0x1D8 0x440 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI3_TXFS_TPSMP_HDATA1                                 0x1D8 0x440 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK                                  0x1DC 0x444 0x000 0x0 0x0
 #define MX8MM_IOMUXC_SAI3_TXC_GPT1_COMPARE2                                 0x1DC 0x444 0x000 0x1 0x0
 #define MX8MM_IOMUXC_SAI3_TXC_SAI5_RX_DATA2                                 0x1DC 0x444 0x4DC 0x2 0x2
+#define MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX                                  0x1DC 0x444 0x000 0x4 0x0
+#define MX8MM_IOMUXC_SAI3_TXC_UART2_DTE_RX                                  0x1DC 0x444 0x4Fc 0x4 0x3
 #define MX8MM_IOMUXC_SAI3_TXC_GPIO5_IO0                                     0x1DC 0x444 0x000 0x5 0x0
 #define MX8MM_IOMUXC_SAI3_TXC_TPSMP_HDATA2                                  0x1DC 0x444 0x000 0x7 0x0
 #define MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0                                 0x1E0 0x448 0x000 0x0 0x0
@@ -585,7 +601,7 @@
 #define MX8MM_IOMUXC_UART1_RXD_GPIO5_IO22                                   0x234 0x49C 0x000 0x5 0x0
 #define MX8MM_IOMUXC_UART1_RXD_TPSMP_HDATA24                                0x234 0x49C 0x000 0x7 0x0
 #define MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX                                 0x238 0x4A0 0x000 0x0 0x0
-#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX                                 0x238 0x4A0 0x4F4 0x0 0x0
+#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX                                 0x238 0x4A0 0x4F4 0x0 0x1
 #define MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI                                  0x238 0x4A0 0x000 0x1 0x0
 #define MX8MM_IOMUXC_UART1_TXD_GPIO5_IO23                                   0x238 0x4A0 0x000 0x5 0x0
 #define MX8MM_IOMUXC_UART1_TXD_TPSMP_HDATA25                                0x238 0x4A0 0x000 0x7 0x0
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
@@ -0,0 +1,1140 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2021 Gateworks Corporation
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/power/imx8mm-power.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
+
+#include "imx8mm.dtsi"
+
+/ {
+	model = "Gateworks Venice GW7902 i.MX8MM board";
+	compatible = "gw,imx8mm-gw7902", "fsl,imx8mm";
+
+	aliases {
+		ethernet1 = &eth1;
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		usb0 = &usbotg1;
+		usb1 = &usbotg2;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 32MiB */
+		optee_core@be000000 {
+			reg = <0x00 0xbe000000 0x00 0x2000000>;
+		};
+
+		/* 4K */
+		optee_shm@bfc00000 {
+			reg = <0x00 0xbfc00000 0x00 0x400000>;
+		};
+	};
+
+	can20m: can20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+		clock-output-names = "can20m";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		user-pb {
+			label = "user_pb";
+			gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_0>;
+		};
+
+		user-pb1x {
+			label = "user_pb1x";
+			linux,code = <BTN_1>;
+			interrupt-parent = <&gsc>;
+			interrupts = <0>;
+		};
+
+		key-erased {
+			label = "key_erased";
+			linux,code = <BTN_2>;
+			interrupt-parent = <&gsc>;
+			interrupts = <1>;
+		};
+
+		eeprom-wp {
+			label = "eeprom_wp";
+			linux,code = <BTN_3>;
+			interrupt-parent = <&gsc>;
+			interrupts = <2>;
+		};
+
+		tamper {
+			label = "tamper";
+			linux,code = <BTN_4>;
+			interrupt-parent = <&gsc>;
+			interrupts = <5>;
+		};
+
+		switch-hold {
+			label = "switch_hold";
+			linux,code = <BTN_5>;
+			interrupt-parent = <&gsc>;
+			interrupts = <7>;
+		};
+	};
+
+	led-controller {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel1";
+			gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel2";
+			gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-2 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel3";
+			gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-3 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel4";
+			gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-4 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel5";
+			gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
+	power-domains {
+		compatible = "simple-bus";
+		/* HSIO SS */
+		hsiomix_pd: hsiomix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <0>;
+			domain-name = "hsiomix";
+			clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
+		};
+
+		pcie_pd: pcie-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <1>;
+			domain-name = "pcie";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		usb_otg1_pd: usbotg1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <2>;
+			domain-name = "usb_otg1";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		usb_otg2_pd: usbotg2-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <3>;
+			domain-name = "usb_otg2";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		/* GPU SS */
+		gpumix_pd: gpumix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <4>;
+			domain-name = "gpumix";
+			clocks = <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+				 <&clk IMX8MM_CLK_GPU_AHB>,
+				 <&clk IMX8MM_CLK_GPU2D_ROOT>,
+				 <&clk IMX8MM_CLK_GPU3D_ROOT>;
+		};
+
+		/* VPU SS */
+		vpumix_pd: vpumix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <5>;
+			domain-name = "vpumix";
+			clocks = <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+		};
+
+		vpu_g1_pd: vpug1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <6>;
+			domain-name = "vpu_g1";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_G1_ROOT>;
+		};
+
+		vpu_g2_pd: vpug2-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <7>;
+			domain-name = "vpu_g2";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_G2_ROOT>;
+		};
+
+		vpu_h1_pd: vpuh1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <8>;
+			domain-name = "vpu_h1";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_H1_ROOT>;
+		};
+
+		/* DISP SS */
+		dispmix_pd: dispmix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <9>;
+			domain-name = "dispmix";
+			clocks = <&clk IMX8MM_CLK_DISP_ROOT>,
+				 <&clk IMX8MM_CLK_DISP_AXI_ROOT>,
+				 <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		};
+
+		mipi_pd: mipi-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <10>;
+			domain-name = "mipi";
+			parent-domains = <&dispmix_pd>;
+		};
+	};
+
+	soc@0 {
+		pcie0: pcie@33800000 {
+			compatible = "fsl,imx8mm-pcie", "snps,dw-pcie";
+			reg = <0x33800000 0x400000>,
+				<0x1ff00000 0x80000>;
+			reg-names = "dbi", "config";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			bus-range = <0x00 0xff>;
+			ranges =  <0x81000000 0 0x00000000 0x1ff80000 0 0x00010000 /* downstream I/O 64KB */
+					0x82000000 0 0x18000000 0x18000000 0 0x07f00000>; /* non-prefetchable memory */
+			num-lanes = <1>;
+			num-viewport = <4>;
+			interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &gic GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 3 &gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 4 &gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+			fsl,max-link-speed = <2>;
+			power-domains = <&pcie_pd>;
+			resets = <&src IMX8MQ_RESET_PCIEPHY>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_CLK_REQ>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
+			reset-names = "pciephy", "apps", "clkreq", "turnoff";
+			fsl,imx7d-pcie-phy = <&pcie_phy>;
+			status = "disabled";
+		};
+	};
+
+	pcie0_refclk: pcie0-refclk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+	};
+
+	pps {
+		compatible = "pps-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pps>;
+		gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "3P3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usb1_vbus: regulator-usb1 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usb1>;
+		compatible = "regulator-fixed";
+		regulator-name = "usb_usb1_vbus";
+		gpio = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_wifi: regulator-wifi {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_wl>;
+		compatible = "regulator-fixed";
+		regulator-name = "wifi";
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&aips4 {
+	pcie_phy: pcie-phy@32f00000 {
+		  compatible = "fsl,imx7d-pcie-phy";
+		  reg = <0x32f00000 0x10000>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25M {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100M {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		opp-750M {
+			opp-hz = /bits/ 64 <750000000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1>;
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can@0 {
+		compatible = "microchip,mcp2515";
+		reg = <0>;
+		clocks = <&can20m>;
+		oscillator-frequency = <20000000>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		spi-max-frequency = <10000000>;
+	};
+};
+
+/* off-board header */
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	local-mac-address = [00 00 00 00 00 00];
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	gsc: gsc@20 {
+		compatible = "gw,gsc";
+		reg = <0x20>;
+		pinctrl-0 = <&pinctrl_gsc>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+
+		adc {
+			compatible = "gw,gsc-adc";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel@6 {
+				gw,mode = <0>;
+				reg = <0x06>;
+				label = "temp";
+			};
+
+			channel@8 {
+				gw,mode = <1>;
+				reg = <0x08>;
+				label = "vdd_bat";
+			};
+
+			channel@82 {
+				gw,mode = <2>;
+				reg = <0x82>;
+				label = "vin";
+				gw,voltage-divider-ohms = <22100 1000>;
+				gw,voltage-offset-microvolt = <700000>;
+			};
+
+			channel@84 {
+				gw,mode = <2>;
+				reg = <0x84>;
+				label = "vin_4p0";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@86 {
+				gw,mode = <2>;
+				reg = <0x86>;
+				label = "vdd_3p3";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@88 {
+				gw,mode = <2>;
+				reg = <0x88>;
+				label = "vdd_0p9";
+			};
+
+			channel@8c {
+				gw,mode = <2>;
+				reg = <0x8c>;
+				label = "vdd_soc";
+			};
+
+			channel@8e {
+				gw,mode = <2>;
+				reg = <0x8e>;
+				label = "vdd_arm";
+			};
+
+			channel@90 {
+				gw,mode = <2>;
+				reg = <0x90>;
+				label = "vdd_1p8";
+			};
+
+			channel@92 {
+				gw,mode = <2>;
+				reg = <0x92>;
+				label = "vdd_dram";
+			};
+
+			channel@98 {
+				gw,mode = <2>;
+				reg = <0x98>;
+				label = "vdd_1p0";
+			};
+
+			channel@9a {
+				gw,mode = <2>;
+				reg = <0x9a>;
+				label = "vdd_2p5";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@a2 {
+				gw,mode = <2>;
+				reg = <0xa2>;
+				label = "vdd_gsc";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+		};
+	};
+
+	gpio: gpio@23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gsc>;
+		interrupts = <4>;
+	};
+
+	pmic@4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+		#clock-cells = <0>;
+		clocks = <&osc_32k 0>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			/* vdd_soc: 0.805-0.900V (typ=0.8V) */
+			BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			/* vdd_arm: 0.805-1.0V (typ=0.9V) */
+			buck2: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			/* vdd_0p9: 0.805-1.0V (typ=0.9V) */
+			BUCK3 {
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_3p3 */
+			BUCK4 {
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_1p8 */
+			BUCK5 {
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_dram */
+			BUCK6 {
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* nvcc_snvs_1p8 */
+			LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <1900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_snvs_0p8 */
+			LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdda_1p8 */
+			LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+
+	eeprom@50 {
+		compatible = "atmel,24c02";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+
+	eeprom@51 {
+		compatible = "atmel,24c02";
+		reg = <0x51>;
+		pagesize = <16>;
+	};
+
+	eeprom@52 {
+		compatible = "atmel,24c02";
+		reg = <0x52>;
+		pagesize = <16>;
+	};
+
+	eeprom@53 {
+		compatible = "atmel,24c02";
+		reg = <0x53>;
+		pagesize = <16>;
+	};
+
+	rtc: rtc@68 {
+		compatible = "dallas,ds1672";
+		reg = <0x68>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	accelerometer@19 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_accel>;
+		compatible = "st,lis2de12";
+		reg = <0x19>;
+		st,drdy-int-pin = <1>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "INT1";
+	};
+
+	secure-element@60 {
+		compatible = "nxp,se050";
+		reg = <0x60>;
+	};
+};
+
+/* off-board header */
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+/* off-board header */
+&i2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie0>;
+	reset-gpio = <&gpio4 5 GPIO_ACTIVE_LOW>;
+	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>,
+		 <&clk IMX8MM_CLK_PCIE1_AUX>,
+		 <&clk IMX8MM_CLK_PCIE1_PHY>,
+		 <&pcie0_refclk>;
+	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+	ext_osc = <1>;
+	status = "okay";
+
+	pcie@0,0 {
+		reg = <0x0000 0 0 0 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		eth1: pcie@1,0 {
+			reg = <0x0000 0 0 0 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			local-mac-address = [00 00 00 00 00 00];
+		};
+	};
+};
+
+/* off-board header */
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
+/* RS232/RS485/RS422 selectable */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>;
+	rts-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
+	cts-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+/* RS232 console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+/* bluetooth HCI */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
+	rts-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+	cts-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		shutdown-gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/* LTE Cat M1/NB1/EGPRS modem or GPS (loading option) */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	rts-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+	cts-gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
+	dtr-gpios = <&gpio4 3 GPIO_ACTIVE_LOW>;
+	dsr-gpios = <&gpio4 4 GPIO_ACTIVE_LOW>;
+	dcd-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "host";
+	vbus-supply = <&reg_usb1_vbus>;
+	power-domains = <&usb_otg1_pd>;
+	disable-over-current;
+	status = "okay";
+};
+
+&usbotg2 {
+	dr_mode = "host";
+	power-domains = <&usb_otg2_pd>;
+	disable-over-current;
+	status = "okay";
+};
+
+/* SDIO WiFi */
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	bus-width = <4>;
+	non-removable;
+	vmmc-supply = <&reg_wifi>;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_CE0_B_GPIO3_IO1	0x40000159 /* M2_GDIS# */
+			MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13	0x40000041 /* M2_RST# */
+			MX8MM_IOMUXC_NAND_DATA01_GPIO3_IO7	0x40000119 /* M2_OFF# */
+			MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x40000159 /* M2_WDIS# */
+			MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14	0x40000041 /* AMP GPIO1 */
+			MX8MM_IOMUXC_SAI1_TXD0_GPIO4_IO12	0x40000041 /* AMP GPIO2 */
+			MX8MM_IOMUXC_SAI1_TXC_GPIO4_IO11	0x40000041 /* AMP GPIO3 */
+			MX8MM_IOMUXC_SAI1_MCLK_GPIO4_IO20	0x40000041 /* AMP_GPIO4 */
+			MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x40000041 /* APP GPIO1 */
+			MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27	0x40000041 /* APP GPIO2 */
+			MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8	0x40000041 /* UART2_EN# */
+			MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28	0x40000041 /* MIPI_GPIO1 */
+			MX8MM_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5	0x40000041 /* MIPI_GPIO2 */
+			MX8MM_IOMUXC_SPDIF_RX_GPIO5_IO4		0x40000041 /* MIPI_GPIO3/PWM2 */
+			MX8MM_IOMUXC_SPDIF_TX_GPIO5_IO3		0x40000041 /* MIPI_GPIO4/PWM3 */
+		>;
+	};
+
+	pinctrl_accel: accelgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12	0x159
+		>;
+	};
+
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
+			MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10		0x19 /* RST# */
+			MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x19 /* IRQ# */
+			MX8MM_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN	0x141
+			MX8MM_IOMUXC_GPIO1_IO09_ENET1_1588_EVENT0_OUT	0x141
+		>;
+	};
+
+	pinctrl_gsc: gscgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6	0x40
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL		0x400001c3
+			MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_gpio_leds: gpioledgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21	0x19
+			MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23	0x19
+			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22	0x19
+			MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20	0x19
+			MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25	0x19
+		>;
+	};
+
+	pinctrl_pcie0: pciegrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5	0x41 /* PERST# */
+
+		>;
+	};
+
+	pinctrl_pmic: pmicgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_DATA02_GPIO3_IO8	0x41
+		>;
+	};
+
+	pinctrl_pps: ppsgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI5_RXD3_GPIO3_IO24	0x141 /* PPS */
+		>;
+	};
+
+	pinctrl_reg_wl: regwlgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41 /* WLAN_WLON */
+		>;
+	};
+
+	pinctrl_reg_usb1: regusb1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7	0x41
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK	0xd6
+			MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0	0xd6
+			MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK	0xd6
+			MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0	0xd6
+			MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC	0xd6
+		>;
+	};
+
+	pinctrl_spi1: spi1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK	0x82
+			MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI	0x82
+			MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO	0x82
+			MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9	0x40
+			MX8MM_IOMUXC_SD1_DATA1_GPIO2_IO3	0x140 /* CAN_IRQ# */
+		>;
+	};
+
+	pinctrl_spi2: spi2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK	0x82
+			MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI	0x82
+			MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO	0x82
+			MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13	0x40 /* SS0 */
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+			MX8MM_IOMUXC_SAI1_TXFS_GPIO4_IO10	0x140 /* RTS */
+			MX8MM_IOMUXC_SAI2_TXFS_GPIO4_IO24	0x140 /* CTS */
+		>;
+	};
+
+	pinctrl_uart1_gpio: uart1gpiogrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SAI2_TXD0_GPIO4_IO26	0x40000110 /* HALF */
+			MX8MM_IOMUXC_SAI2_TXC_GPIO4_IO25	0x40000110 /* TERM */
+			MX8MM_IOMUXC_SAI2_RXD0_GPIO4_IO23	0x40000110 /* RS485 */
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_uart3_gpio: uart3_gpiogrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12	0x41 /* BT_EN# */
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX	0x140
+			MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX	0x140
+			MX8MM_IOMUXC_SD1_CLK_GPIO2_IO0		0x140 /* CTS */
+			MX8MM_IOMUXC_SD1_CMD_GPIO2_IO1		0x140 /* RTS */
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX	0x140
+			MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX	0x140
+			MX8MM_IOMUXC_SAI1_RXC_GPIO4_IO1		0x140 /* CTS */
+			MX8MM_IOMUXC_SAI1_RXD0_GPIO4_IO2	0x140 /* RTS */
+			MX8MM_IOMUXC_SAI1_RXD1_GPIO4_IO3	0x140 /* DTR */
+			MX8MM_IOMUXC_SAI1_RXD2_GPIO4_IO4	0x140 /* DSR */
+			MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6	0x140 /* DCD */
+			MX8MM_IOMUXC_SAI1_RXD5_GPIO4_IO7	0x140 /* RI */
+			MX8MM_IOMUXC_SAI1_RXFS_GPIO4_IO0	0x140 /* GNSS_PPS */
+			MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6	0x141 /* GNSS_GASP */
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK	0x190
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d0
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d0
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d0
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d0
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d0
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d0
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d0
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d0
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d0
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK	0x194
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d4
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d4
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d4
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d4
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d4
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d4
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d4
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d4
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d4
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK	0x196
+			MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d6
+			MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d6
+			MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d6
+			MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d6
+			MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d6
+			MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d6
+			MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d6
+			MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d6
+			MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d6
+			MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
+		>;
+	};
+};
+
+&cpu_alert0 {
+	temperature = <95000>;
+	hysteresis = <2000>;
+	type = "passive";
+};
+
+&cpu_crit0 {
+	temperature = <105000>;
+	hysteresis = <2000>;
+	type = "critical";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -7,22 +7,31 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/imx8mm-power.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
 #include <dt-bindings/thermal/thermal.h>
 
 #include "imx8mm-pinfunc.h"
 
 / {
-	compatible = "fsl,imx8mm";
 	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
 
 	aliases {
 		ethernet0 = &fec1;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
 		i2c0 = &i2c1;
 		i2c1 = &i2c2;
 		i2c2 = &i2c3;
 		i2c3 = &i2c4;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
 		serial0 = &uart1;
 		serial1 = &uart2;
 		serial2 = &uart3;
@@ -30,14 +39,6 @@
 		spi0 = &ecspi1;
 		spi1 = &ecspi2;
 		spi2 = &ecspi3;
-		mmc0 = &usdhc1;
-		mmc1 = &usdhc2;
-		mmc2 = &usdhc3;
-		gpio0 = &gpio1;
-		gpio1 = &gpio2;
-		gpio2 = &gpio3;
-		gpio3 = &gpio4;
-		gpio4 = &gpio5;
 	};
 
 	cpus {
@@ -64,11 +65,18 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MM_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			nvmem-cells = <&cpu_speed_grade>;
 			nvmem-cell-names = "speed_grade";
 			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_1: cpu@1 {
@@ -78,9 +86,16 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MM_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_2: cpu@2 {
@@ -90,9 +105,16 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MM_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_3: cpu@3 {
@@ -102,13 +124,24 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MM_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_L2: l2-cache0 {
 			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <0x80000>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
 		};
 	};
 
@@ -126,7 +159,7 @@
 
 		opp-1600000000 {
 			opp-hz = /bits/ 64 <1600000000>;
-			opp-microvolt = <900000>;
+			opp-microvolt = <950000>;
 			opp-supported-hw = <0xc>, <0x7>;
 			clock-latency-ns = <150000>;
 			opp-suspend;
@@ -141,11 +174,6 @@
 		};
 	};
 
-	memory@40000000 {
-		device_type = "memory";
-		reg = <0x0 0x40000000 0 0x80000000>;
-	};
-
 	osc_32k: clock-osc-32k {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -196,20 +224,52 @@
 	pmu {
 		compatible = "arm,armv8-pmuv3";
 		interrupts = <GIC_PPI 7
-			     (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+			     (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>;
 	};
 
 	timer {
 		compatible = "arm,armv8-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Secure */
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Non-Secure */
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Virtual */
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>; /* Hypervisor */
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Secure */
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Non-Secure */
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, /* Virtual */
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; /* Hypervisor */
 		clock-frequency = <8000000>;
 		arm,no-tick-in-suspend;
 	};
 
+	thermal-zones {
+		cpu-thermal {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tmu>;
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit0: trip1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	usbphynop1: usbphynop1 {
 		compatible = "usb-nop-xceiv";
 		clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
@@ -227,18 +287,27 @@
 	};
 
 	soc@0 {
-		compatible = "simple-bus";
+		compatible = "fsl,imx8mm-soc", "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0x0 0x0 0x3e000000>;
+		nvmem-cells = <&imx8mm_uid>;
+		nvmem-cell-names = "soc_unique_id";
+
+		caam_sm: caam-sm@100000 {
+			compatible = "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
 
 		aips1: bus@30000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30000000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x30000000 0x30000000 0x400000>;
 
 			sai1: sai@30010000 {
+				#sound-dai-cells = <0>;
 				compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
 				reg = <0x30010000 0x10000>;
 				interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
@@ -252,6 +321,7 @@
 			};
 
 			sai2: sai@30020000 {
+				#sound-dai-cells = <0>;
 				compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
 				reg = <0x30020000 0x10000>;
 				interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
@@ -279,6 +349,7 @@
 			};
 
 			sai5: sai@30050000 {
+				#sound-dai-cells = <0>;
 				compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
 				reg = <0x30050000 0x10000>;
 				interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
@@ -292,6 +363,7 @@
 			};
 
 			sai6: sai@30060000 {
+				#sound-dai-cells = <0>;
 				compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
 				reg = <0x30060000 0x10000>;
 				interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
@@ -304,6 +376,49 @@
 				status = "disabled";
 			};
 
+			micfil: audio-controller@30080000 {
+				compatible = "fsl,imx8mm-micfil";
+				reg = <0x30080000 0x10000>;
+				interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MM_CLK_PDM_IPG>,
+					 <&clk IMX8MM_CLK_PDM_ROOT>,
+					 <&clk IMX8MM_AUDIO_PLL1_OUT>,
+					 <&clk IMX8MM_AUDIO_PLL2_OUT>,
+					 <&clk IMX8MM_CLK_EXT3>;
+				clock-names = "ipg_clk", "ipg_clk_app",
+					      "pll8k", "pll11k", "clkext3";
+				dmas = <&sdma2 24 25 0x80000000>;
+				dma-names = "rx";
+				status = "disabled";
+			};
+
+			spdif1: spdif@30090000 {
+				compatible = "fsl,imx35-spdif";
+				reg = <0x30090000 0x10000>;
+				interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, /* core */
+					 <&clk IMX8MM_CLK_24M>, /* rxtx0 */
+					 <&clk IMX8MM_CLK_SPDIF1>, /* rxtx1 */
+					 <&clk IMX8MM_CLK_DUMMY>, /* rxtx2 */
+					 <&clk IMX8MM_CLK_DUMMY>, /* rxtx3 */
+					 <&clk IMX8MM_CLK_DUMMY>, /* rxtx4 */
+					 <&clk IMX8MM_CLK_AUDIO_AHB>, /* rxtx5 */
+					 <&clk IMX8MM_CLK_DUMMY>, /* rxtx6 */
+					 <&clk IMX8MM_CLK_DUMMY>, /* rxtx7 */
+					 <&clk IMX8MM_CLK_DUMMY>; /* spba */
+				clock-names = "core", "rxtx0",
+					      "rxtx1", "rxtx2",
+					      "rxtx3", "rxtx4",
+					      "rxtx5", "rxtx6",
+					      "rxtx7", "spba";
+				dmas = <&sdma2 28 18 0>, <&sdma2 29 18 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			gpio1: gpio@30200000 {
 				compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
 				reg = <0x30200000 0x10000>;
@@ -369,6 +484,13 @@
 				gpio-ranges = <&iomuxc 0 119 30>;
 			};
 
+			tmu: tmu@30260000 {
+				compatible = "fsl,imx8mm-tmu";
+				reg = <0x30260000 0x10000>;
+				clocks = <&clk IMX8MM_CLK_TMU_ROOT>;
+				#thermal-sensor-cells = <0>;
+			};
+
 			wdog1: watchdog@30280000 {
 				compatible = "fsl,imx8mm-wdt", "fsl,imx21-wdt";
 				reg = <0x30280000 0x10000>;
@@ -421,25 +543,33 @@
 			};
 
 			gpr: iomuxc-gpr@30340000 {
-				compatible = "fsl,imx8mm-iomuxc-gpr", "syscon";
+				compatible = "fsl,imx8mm-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", "syscon";
 				reg = <0x30340000 0x10000>;
 			};
 
-			ocotp: ocotp-ctrl@30350000 {
-				compatible = "fsl,imx8mm-ocotp", "fsl,imx7d-ocotp", "syscon";
+			ocotp: efuse@30350000 {
+				compatible = "fsl,imx8mm-ocotp", "syscon";
 				reg = <0x30350000 0x10000>;
 				clocks = <&clk IMX8MM_CLK_OCOTP_ROOT>;
 				/* For nvmem subnodes */
 				#address-cells = <1>;
 				#size-cells = <1>;
 
+				imx8mm_uid: unique-id@410 {
+					reg = <0x4 0x8>;
+				};
+
 				cpu_speed_grade: speed-grade@10 {
 					reg = <0x10 4>;
 				};
+
+				fec_mac_address: mac-address@90 {
+					reg = <0x90 6>;
+				};
 			};
 
 			anatop: anatop@30360000 {
-				compatible = "fsl,imx8mm-anatop", "syscon", "simple-bus";
+				compatible = "fsl,imx8mm-anatop", "syscon";
 				reg = <0x30360000 0x10000>;
 			};
 
@@ -461,6 +591,8 @@
 					compatible = "fsl,sec-v4.0-pwrkey";
 					regmap = <&snvs>;
 					interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MM_CLK_SNVS_ROOT>;
+					clock-names = "snvs-pwrkey";
 					linux,keycode = <KEY_POWER>;
 					wakeup-source;
 					status = "disabled";
@@ -475,18 +607,26 @@
 					 <&clk_ext3>, <&clk_ext4>;
 				clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
 					      "clk_ext3", "clk_ext4";
-				assigned-clocks = <&clk IMX8MM_CLK_NOC>,
+				assigned-clocks = <&clk IMX8MM_CLK_A53_SRC>,
+						<&clk IMX8MM_CLK_A53_CORE>,
+						<&clk IMX8MM_CLK_NOC>,
 						<&clk IMX8MM_CLK_AUDIO_AHB>,
 						<&clk IMX8MM_CLK_IPG_AUDIO_ROOT>,
 						<&clk IMX8MM_SYS_PLL3>,
-						<&clk IMX8MM_VIDEO_PLL1>;
-				assigned-clock-parents = <&clk IMX8MM_SYS_PLL3_OUT>,
+						<&clk IMX8MM_VIDEO_PLL1>,
+						<&clk IMX8MM_AUDIO_PLL1>,
+						<&clk IMX8MM_AUDIO_PLL2>;
+				assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>,
+							 <&clk IMX8MM_ARM_PLL_OUT>,
+							 <&clk IMX8MM_SYS_PLL3_OUT>,
 							 <&clk IMX8MM_SYS_PLL1_800M>;
-				assigned-clock-rates = <0>,
+				assigned-clock-rates = <0>, <0>, <0>,
 							<400000000>,
 							<400000000>,
 							<750000000>,
-							<594000000>;
+							<594000000>,
+							<393216000>,
+							<361267200>;
 			};
 
 			src: reset-controller@30390000 {
@@ -495,10 +635,116 @@
 				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 				#reset-cells = <1>;
 			};
+
+			gpc: gpc@303a0000 {
+				compatible = "fsl,imx8mm-gpc";
+				reg = <0x303a0000 0x10000>;
+				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-parent = <&gic>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+
+				pgc {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					pgc_hsiomix: power-domain@0 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_HSIOMIX>;
+						clocks = <&clk IMX8MM_CLK_USB_BUS>;
+						assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>;
+						assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
+					};
+
+					pgc_pcie: power-domain@1 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_PCIE>;
+						power-domains = <&pgc_hsiomix>;
+						clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>;
+					};
+
+					pgc_otg1: power-domain@2 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_OTG1>;
+						power-domains = <&pgc_hsiomix>;
+					};
+
+					pgc_otg2: power-domain@3 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_OTG2>;
+						power-domains = <&pgc_hsiomix>;
+					};
+
+					pgc_gpumix: power-domain@4 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_GPUMIX>;
+						clocks = <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+							 <&clk IMX8MM_CLK_GPU_AHB>;
+						assigned-clocks = <&clk IMX8MM_CLK_GPU_AXI>,
+								  <&clk IMX8MM_CLK_GPU_AHB>;
+						assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>,
+									 <&clk IMX8MM_SYS_PLL1_800M>;
+						assigned-clock-rates = <800000000>, <400000000>;
+					};
+
+					pgc_gpu: power-domain@5 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_GPU>;
+						clocks = <&clk IMX8MM_CLK_GPU_AHB>,
+							 <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+							 <&clk IMX8MM_CLK_GPU2D_ROOT>,
+							 <&clk IMX8MM_CLK_GPU3D_ROOT>;
+						resets = <&src IMX8MQ_RESET_GPU_RESET>;
+						power-domains = <&pgc_gpumix>;
+					};
+
+					pgc_vpumix: power-domain@6 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_VPUMIX>;
+						clocks = <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+						assigned-clocks = <&clk IMX8MM_CLK_VPU_BUS>;
+						assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>;
+						resets = <&src IMX8MQ_RESET_VPU_RESET>;
+					};
+
+					pgc_vpu_g1: power-domain@7 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_VPUG1>;
+					};
+
+					pgc_vpu_g2: power-domain@8 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_VPUG2>;
+					};
+
+					pgc_vpu_h1: power-domain@9 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_VPUH1>;
+					};
+
+					pgc_dispmix: power-domain@10 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_DISPMIX>;
+						clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>,
+							 <&clk IMX8MM_CLK_DISP_AXI_ROOT>;
+						assigned-clocks = <&clk IMX8MM_CLK_DISP_AXI>,
+								  <&clk IMX8MM_CLK_DISP_APB>;
+						assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_1000M>,
+									 <&clk IMX8MM_SYS_PLL1_800M>;
+						assigned-clock-rates = <500000000>, <200000000>;
+					};
+
+					pgc_mipi: power-domain@11 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MM_POWER_DOMAIN_MIPI>;
+					};
+				};
+			};
 		};
 
 		aips2: bus@30400000 {
 			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30400000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x30400000 0x30400000 0x400000>;
@@ -558,9 +804,11 @@
 
 		aips3: bus@30800000 {
 			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30800000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			ranges = <0x30800000 0x30800000 0x400000>;
+			ranges = <0x30800000 0x30800000 0x400000>,
+				 <0x8000000 0x8000000 0x10000000>;
 
 			ecspi1: spi@30820000 {
 				compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi";
@@ -638,6 +886,36 @@
 				status = "disabled";
 			};
 
+			crypto: crypto@30900000 {
+				compatible = "fsl,sec-v4.0";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x30900000 0x40000>;
+				ranges = <0 0x30900000 0x40000>;
+				interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MM_CLK_AHB>,
+					 <&clk IMX8MM_CLK_IPG_ROOT>;
+				clock-names = "aclk", "ipg";
+
+				sec_jr0: jr@1000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x1000 0x1000>;
+					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr1: jr@2000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x2000 0x1000>;
+					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr2: jr@3000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x3000 0x1000>;
+					interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+				};
+			};
+
 			i2c1: i2c@30a20000 {
 				compatible = "fsl,imx8mm-i2c", "fsl,imx21-i2c";
 				#address-cells = <1>;
@@ -690,6 +968,14 @@
 				status = "disabled";
 			};
 
+			mu: mailbox@30aa0000 {
+				compatible = "fsl,imx8mm-mu", "fsl,imx6sx-mu";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MM_CLK_MU_ROOT>;
+				#mbox-cells = <2>;
+			};
+
 			usdhc1: mmc@30b40000 {
 				compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
 				reg = <0x30b40000 0x10000>;
@@ -698,8 +984,6 @@
 					 <&clk IMX8MM_CLK_NAND_USDHC_BUS>,
 					 <&clk IMX8MM_CLK_USDHC1_ROOT>;
 				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX8MM_CLK_USDHC1>;
-				assigned-clock-rates = <400000000>;
 				fsl,tuning-start-tap = <20>;
 				fsl,tuning-step= <2>;
 				bus-width = <4>;
@@ -728,20 +1012,31 @@
 					 <&clk IMX8MM_CLK_NAND_USDHC_BUS>,
 					 <&clk IMX8MM_CLK_USDHC3_ROOT>;
 				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>;
-				assigned-clock-rates = <400000000>;
 				fsl,tuning-start-tap = <20>;
 				fsl,tuning-step= <2>;
 				bus-width = <4>;
 				status = "disabled";
 			};
 
+			flexspi: spi@30bb0000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "nxp,imx8mm-fspi";
+				reg = <0x30bb0000 0x10000>, <0x8000000 0x10000000>;
+				reg-names = "fspi_base", "fspi_mmap";
+				interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MM_CLK_QSPI_ROOT>,
+					 <&clk IMX8MM_CLK_QSPI_ROOT>;
+				clock-names = "fspi", "fspi_en";
+				status = "disabled";
+			};
+
 			sdma1: dma-controller@30bd0000 {
 				compatible = "fsl,imx8mm-sdma", "fsl,imx8mq-sdma";
 				reg = <0x30bd0000 0x10000>;
 				interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MM_CLK_SDMA1_ROOT>,
-					 <&clk IMX8MM_CLK_SDMA1_ROOT>;
+					 <&clk IMX8MM_CLK_AHB>;
 				clock-names = "ipg", "ahb";
 				#dma-cells = <3>;
 				fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
@@ -752,7 +1047,8 @@
 				reg = <0x30be0000 0x10000>;
 				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MM_CLK_ENET1_ROOT>,
 					 <&clk IMX8MM_CLK_ENET1_ROOT>,
 					 <&clk IMX8MM_CLK_ENET_TIMER>,
@@ -763,13 +1059,18 @@
 				assigned-clocks = <&clk IMX8MM_CLK_ENET_AXI>,
 						  <&clk IMX8MM_CLK_ENET_TIMER>,
 						  <&clk IMX8MM_CLK_ENET_REF>,
-						  <&clk IMX8MM_CLK_ENET_TIMER>;
+						  <&clk IMX8MM_CLK_ENET_PHY_REF>;
 				assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>,
 							 <&clk IMX8MM_SYS_PLL2_100M>,
-							 <&clk IMX8MM_SYS_PLL2_125M>;
-				assigned-clock-rates = <0>, <0>, <125000000>, <100000000>;
+							 <&clk IMX8MM_SYS_PLL2_125M>,
+							 <&clk IMX8MM_SYS_PLL2_50M>;
+				assigned-clock-rates = <0>, <100000000>, <125000000>, <0>;
 				fsl,num-tx-queues = <3>;
 				fsl,num-rx-queues = <3>;
+				nvmem-cells = <&fec_mac_address>;
+				nvmem-cell-names = "mac-address";
+				nvmem_macaddr_swap;
+				fsl,stop-mode = <&gpr 0x10 3>;
 				status = "disabled";
 			};
 
@@ -777,6 +1078,7 @@
 
 		aips4: bus@32c00000 {
 			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x32c00000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x32c00000 0x32c00000 0x400000>;
@@ -819,6 +1121,19 @@
 				reg = <0x32e50200 0x200>;
 			};
 
+			pcie_phy: pcie-phy@32f00000 {
+				compatible = "fsl,imx8mm-pcie-phy";
+				reg = <0x32f00000 0x10000>;
+				clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
+				clock-names = "ref";
+				assigned-clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
+				assigned-clock-rates = <100000000>;
+				assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_100M>;
+				resets = <&src IMX8MQ_RESET_PCIEPHY>;
+				reset-names = "pciephy";
+				#phy-cells = <0>;
+				status = "disabled";
+			};
 		};
 
 		dma_apbh: dma-controller@33000000 {
@@ -834,10 +1149,10 @@
 			clocks = <&clk IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK>;
 		};
 
-		gpmi: nand-controller@33002000{
+		gpmi: nand-controller@33002000 {
 			compatible = "fsl,imx8mm-gpmi-nand", "fsl,imx7d-gpmi-nand";
 			#address-cells = <1>;
-			#size-cells = <1>;
+			#size-cells = <0>;
 			reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
 			reg-names = "gpmi-nand", "bch";
 			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
@@ -850,6 +1165,68 @@
 			status = "disabled";
 		};
 
+		pcie0: pcie@33800000 {
+			compatible = "fsl,imx8mm-pcie";
+			reg = <0x33800000 0x400000>, <0x1ff00000 0x80000>;
+			reg-names = "dbi", "config";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			bus-range = <0x00 0xff>;
+			ranges =  <0x81000000 0 0x00000000 0x1ff80000 0 0x00010000 /* downstream I/O 64KB */
+				   0x82000000 0 0x18000000 0x18000000 0 0x07f00000>; /* non-prefetchable memory */
+			num-lanes = <1>;
+			num-viewport = <4>;
+			interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &gic GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 3 &gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+					<0 0 0 4 &gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+			fsl,max-link-speed = <2>;
+			linux,pci-domain = <0>;
+			power-domains = <&pgc_pcie>;
+			resets = <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
+			reset-names = "apps", "turnoff";
+			phys = <&pcie_phy>;
+			phy-names = "pcie-phy";
+			status = "disabled";
+		};
+
+		gpu_3d: gpu@38000000 {
+			compatible = "vivante,gc";
+			reg = <0x38000000 0x8000>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX8MM_CLK_GPU_AHB>,
+				 <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+				 <&clk IMX8MM_CLK_GPU3D_ROOT>,
+				 <&clk IMX8MM_CLK_GPU3D_ROOT>;
+			clock-names = "reg", "bus", "core", "shader";
+			assigned-clocks = <&clk IMX8MM_CLK_GPU3D_CORE>,
+					  <&clk IMX8MM_GPU_PLL_OUT>;
+			assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>;
+			assigned-clock-rates = <0>, <1000000000>;
+			power-domains = <&pgc_gpu>;
+		};
+
+		gpu_2d: gpu@38008000 {
+			compatible = "vivante,gc";
+			reg = <0x38008000 0x8000>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX8MM_CLK_GPU_AHB>,
+				 <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+				 <&clk IMX8MM_CLK_GPU2D_ROOT>;
+			clock-names = "reg", "bus", "core";
+			assigned-clocks = <&clk IMX8MM_CLK_GPU2D_CORE>,
+					  <&clk IMX8MM_GPU_PLL_OUT>;
+			assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>;
+			assigned-clock-rates = <0>, <1000000000>;
+			power-domains = <&pgc_gpu>;
+		};
+
 		gic: interrupt-controller@38800000 {
 			compatible = "arm,gic-v3";
 			reg = <0x38800000 0x10000>, /* GIC Dist */
@@ -859,10 +1236,19 @@
 			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		ddrc: memory-controller@3d400000 {
+			compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
+			reg = <0x3d400000 0x400000>;
+			clock-names = "core", "pll", "alt", "apb";
+			clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
+				 <&clk IMX8MM_DRAM_PLL>,
+				 <&clk IMX8MM_CLK_DRAM_ALT>,
+				 <&clk IMX8MM_CLK_DRAM_APB>;
+		};
+
 		ddr-pmu@3d800000 {
 			compatible = "fsl,imx8mm-ddr-pmu", "fsl,imx8m-ddr-pmu";
 			reg = <0x3d800000 0x400000>;
-			interrupt-parent = <&gic>;
 			interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mn-ddr4-evk.dts
@@ -6,216 +6,54 @@
 /dts-v1/;
 
 #include "imx8mn.dtsi"
+#include "imx8mn-evk.dtsi"
 
 / {
 	model = "NXP i.MX8MNano DDR4 EVK board";
 	compatible = "fsl,imx8mn-ddr4-evk", "fsl,imx8mn";
-
-	chosen {
-		stdout-path = &uart2;
-	};
-
-	reg_usdhc2_vmmc: regulator-usdhc2 {
-		compatible = "regulator-fixed";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
-		regulator-name = "VSD_3V3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
 };
 
 &A53_0 {
 	cpu-supply = <&buck2_reg>;
 };
 
-&iomuxc {
-	pinctrl-names = "default";
-
-	pinctrl_fec1: fec1grp {
-		fsl,pins = <
-			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC		0x3
-			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO	0x3
-			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3	0x1f
-			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2	0x1f
-			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1	0x1f
-			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0	0x1f
-			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3	0x91
-			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2	0x91
-			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1	0x91
-			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0	0x91
-			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC	0x1f
-			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC	0x91
-			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
-			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
-			MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22	0x19
-		>;
-	};
-
-	pinctrl_i2c1: i2c1grp {
-		fsl,pins = <
-			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c3
-			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c3
-		>;
-	};
-
-	pinctrl_pmic: pmicirq {
-		fsl,pins = <
-			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3	0x41
-		>;
-	};
-
-	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
-		fsl,pins = <
-			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
-		>;
-	};
-
-	pinctrl_uart2: uart2grp {
-		fsl,pins = <
-			MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
-			MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
-		>;
-	};
-
-	pinctrl_usdhc2_gpio: usdhc2grpgpio {
-		fsl,pins = <
-			MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x1c4
-		>;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-		fsl,pins = <
-			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
-			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
-			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
-			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
-			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
-			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
-			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
-		>;
-	};
-
-	pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
-		fsl,pins = <
-			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
-			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
-			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
-			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
-			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
-			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
-			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
-		>;
-	};
-
-	pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
-		fsl,pins = <
-			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
-			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
-			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
-			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
-			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
-			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
-			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
-		>;
-	};
-
-	pinctrl_usdhc3: usdhc3grp {
-		fsl,pins = <
-			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000190
-			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
-			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
-			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
-			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
-			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
-			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
-			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
-			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
-			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
-			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
-		>;
-	};
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
 
-	pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
-		fsl,pins = <
-			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000194
-			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
-			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
-			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
-			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
-			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
-			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
-			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
-			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
-			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
-			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
-		>;
-	};
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
 
-	pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
-		fsl,pins = <
-			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000196
-			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
-			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
-			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
-			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
-			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
-			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
-			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
-			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
-			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
-			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
-		>;
-	};
+		opp-25M {
+			opp-hz = /bits/ 64 <25000000>;
+		};
 
-	pinctrl_wdog: wdoggrp {
-		fsl,pins = <
-			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0xc6
-		>;
-	};
-};
+		opp-100M {
+			opp-hz = /bits/ 64 <100000000>;
+		};
 
-&fec1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_fec1>;
-	phy-mode = "rgmii-id";
-	phy-handle = <&ethphy0>;
-	fsl,magic-packet;
-	status = "okay";
-
-	mdio {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethphy0: ethernet-phy@0 {
-			compatible = "ethernet-phy-ieee802.3-c22";
-			reg = <0>;
-			at803x,led-act-blind-workaround;
-			at803x,eee-disabled;
-			at803x,vddio-1p8v;
+		opp-600M {
+			opp-hz = /bits/ 64 <600000000>;
 		};
 	};
 };
 
 &i2c1 {
-	clock-frequency = <400000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c1>;
-	status = "okay";
-
 	pmic@4b {
 		compatible = "rohm,bd71847";
 		reg = <0x4b>;
+		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_pmic>;
 		interrupt-parent = <&gpio1>;
 		interrupts = <3 GPIO_ACTIVE_LOW>;
 		rohm,reset-snvs-powered;
 
+		#clock-cells = <0>;
+		clocks = <&osc_32k 0>;
+		clock-output-names = "clk-32k-out";
+
 		regulators {
 			buck1_reg: BUCK1 {
-				regulator-name = "BUCK1";
+				regulator-name = "buck1";
 				regulator-min-microvolt = <700000>;
 				regulator-max-microvolt = <1300000>;
 				regulator-boot-on;
@@ -224,7 +62,7 @@
 			};
 
 			buck2_reg: BUCK2 {
-				regulator-name = "BUCK2";
+				regulator-name = "buck2";
 				regulator-min-microvolt = <700000>;
 				regulator-max-microvolt = <1300000>;
 				regulator-boot-on;
@@ -234,14 +72,14 @@
 
 			buck3_reg: BUCK3 {
 				// BUCK5 in datasheet
-				regulator-name = "BUCK3";
+				regulator-name = "buck3";
 				regulator-min-microvolt = <700000>;
 				regulator-max-microvolt = <1350000>;
 			};
 
 			buck4_reg: BUCK4 {
 				// BUCK6 in datasheet
-				regulator-name = "BUCK4";
+				regulator-name = "buck4";
 				regulator-min-microvolt = <3000000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
@@ -250,7 +88,7 @@
 
 			buck5_reg: BUCK5 {
 				// BUCK7 in datasheet
-				regulator-name = "BUCK5";
+				regulator-name = "buck5";
 				regulator-min-microvolt = <1605000>;
 				regulator-max-microvolt = <1995000>;
 				regulator-boot-on;
@@ -259,7 +97,7 @@
 
 			buck6_reg: BUCK6 {
 				// BUCK8 in datasheet
-				regulator-name = "BUCK6";
+				regulator-name = "buck6";
 				regulator-min-microvolt = <800000>;
 				regulator-max-microvolt = <1400000>;
 				regulator-boot-on;
@@ -267,23 +105,23 @@
 			};
 
 			ldo1_reg: LDO1 {
-				regulator-name = "LDO1";
-				regulator-min-microvolt = <3000000>;
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
 			ldo2_reg: LDO2 {
-				regulator-name = "LDO2";
-				regulator-min-microvolt = <900000>;
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
 				regulator-max-microvolt = <900000>;
 				regulator-boot-on;
 				regulator-always-on;
 			};
 
 			ldo3_reg: LDO3 {
-				regulator-name = "LDO3";
+				regulator-name = "ldo3";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-boot-on;
@@ -291,7 +129,7 @@
 			};
 
 			ldo4_reg: LDO4 {
-				regulator-name = "LDO4";
+				regulator-name = "ldo4";
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-boot-on;
@@ -299,7 +137,7 @@
 			};
 
 			ldo6_reg: LDO6 {
-				regulator-name = "LDO6";
+				regulator-name = "ldo6";
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-boot-on;
@@ -309,40 +147,10 @@
 	};
 };
 
-&snvs_pwrkey {
-	status = "okay";
-};
-
-&uart2 { /* console */
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart2>;
-	status = "okay";
-};
-
-&usdhc2 {
-	pinctrl-names = "default", "state_100mhz", "state_200mhz";
-	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
-	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
-	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
-	cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
-	bus-width = <4>;
-	vmmc-supply = <&reg_usdhc2_vmmc>;
-	status = "okay";
-};
-
-&usdhc3 {
-	pinctrl-names = "default", "state_100mhz", "state_200mhz";
-	pinctrl-0 = <&pinctrl_usdhc3>;
-	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
-	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-	bus-width = <8>;
-	non-removable;
-	status = "okay";
-};
-
-&wdog1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_wdog>;
-	fsl,ext-reset-output;
-	status = "okay";
+&iomuxc {
+	pinctrl_pmic: pmicirqgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3	0x41
+		>;
+	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <dt-bindings/usb/pd.h>
+#include "imx8mn.dtsi"
+
+/ {
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+
+		status {
+			label = "yellow:status";
+			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ir>;
+		linux,autosuspend-period = <125>;
+	};
+
+	wm8524: audio-codec {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8524";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_wlf>;
+		wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
+		clocks = <&clk IMX8MN_CLK_SAI3_ROOT>;
+		clock-names = "mclk";
+	};
+
+	sound-wm8524 {
+		compatible = "fsl,imx-audio-wm8524";
+		model = "wm8524-audio";
+		audio-cpu = <&sai3>;
+		audio-codec = <&wm8524>;
+		audio-asrc = <&easrc>;
+		audio-routing =
+			"Line Out Jack", "LINEVOUTL",
+			"Line Out Jack", "LINEVOUTR";
+	};
+
+	sound-spdif {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-spdif";
+		spdif-controller = <&spdif1>;
+		spdif-out;
+		spdif-in;
+	};
+};
+
+&easrc {
+	fsl,asrc-rate  = <48000>;
+	status = "okay";
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ptn5110: tcpc@50 {
+		compatible = "nxp,ptn5110";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_typec1>;
+		reg = <0x50>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		status = "okay";
+
+		port {
+			typec1_dr_sw: endpoint {
+				remote-endpoint = <&usb1_drd_sw>;
+			};
+		};
+
+		typec1_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			power-role = "dual";
+			data-role = "dual";
+			try-power-role = "sink";
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_VAR(5000, 20000, 3000)>;
+			op-sink-microwatt = <15000000>;
+			self-powered;
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	pca6416: gpio@20 {
+		compatible = "ti,tca6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MN_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&spdif1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spdif1>;
+	assigned-clocks = <&clk IMX8MN_CLK_SPDIF1>;
+	assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
+&uart2 { /* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	usb-role-switch;
+	samsung,picophy-pre-emp-curr-control = <3>;
+	samsung,picophy-dc-vol-level-adjust = <7>;
+	status = "okay";
+
+	port {
+		usb1_drd_sw: endpoint {
+			remote-endpoint = <&typec1_dr_sw>;
+		};
+	};
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MN_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+	bus-width = <4>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC		0x3
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO	0x3
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3	0x1f
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2	0x1f
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1	0x1f
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0	0x1f
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3	0x91
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2	0x91
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1	0x91
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0	0x91
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC	0x1f
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC	0x91
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MN_IOMUXC_SAI2_RXC_GPIO4_IO22	0x19
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_READY_B_GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_gpio_wlf: gpiowlfgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C4_SDA_GPIO5_IO21	0xd6
+		>;
+	};
+
+	pinctrl_ir: irgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13              0x4f
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
+			MX8MN_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
+			MX8MN_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
+			MX8MN_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
+		>;
+	};
+
+	pinctrl_spdif1: spdif1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SPDIF_TX_SPDIF1_OUT	0xd6
+			MX8MN_IOMUXC_SPDIF_RX_SPDIF1_IN		0xd6
+		>;
+	};
+
+	pinctrl_typec1: typec1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_STROBE_GPIO2_IO11	0x159
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2grpgpio {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x1c4
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x194
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d4
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d4
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d4
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d4
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d4
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x196
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d6
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d6
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d6
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d6
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d6
+			MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000190
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000194
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d4
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d4
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d4
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK		0x40000196
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD		0x1d6
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4		0x1d6
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7		0x1d6
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0xc6
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
@@ -0,0 +1,944 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2021 Gateworks Corporation
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
+#include "imx8mn.dtsi"
+
+/ {
+	model = "Gateworks Venice GW7902 i.MX8MN board";
+	compatible = "gw,imx8mn-gw7902", "fsl,imx8mn";
+
+	aliases {
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		usb0 = &usbotg1;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 32MiB */
+		optee_core@56000000 {
+			reg = <0x00 0x56000000 0x00 0x2000000>;
+		};
+
+		/* 4K */
+		optee_shm@57c00000 {
+			reg = <0x00 0x57c00000 0x00 0x400000>;
+		};
+	};
+
+	can20m: can20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+		clock-output-names = "can20m";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		user-pb {
+			label = "user_pb";
+			gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_0>;
+		};
+
+		user-pb1x {
+			label = "user_pb1x";
+			linux,code = <BTN_1>;
+			interrupt-parent = <&gsc>;
+			interrupts = <0>;
+		};
+
+		key-erased {
+			label = "key_erased";
+			linux,code = <BTN_2>;
+			interrupt-parent = <&gsc>;
+			interrupts = <1>;
+		};
+
+		eeprom-wp {
+			label = "eeprom_wp";
+			linux,code = <BTN_3>;
+			interrupt-parent = <&gsc>;
+			interrupts = <2>;
+		};
+
+		tamper {
+			label = "tamper";
+			linux,code = <BTN_4>;
+			interrupt-parent = <&gsc>;
+			interrupts = <5>;
+		};
+
+		switch-hold {
+			label = "switch_hold";
+			linux,code = <BTN_5>;
+			interrupt-parent = <&gsc>;
+			interrupts = <7>;
+		};
+	};
+
+	led-controller {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel1";
+			gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel2";
+			gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-2 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel3";
+			gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-3 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel4";
+			gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led-4 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			label = "panel5";
+			gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+
+	pps {
+		compatible = "pps-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pps>;
+		gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "3P3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usb1_vbus: regulator-usb1 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usb1>;
+		compatible = "regulator-fixed";
+		regulator-name = "usb_usb1_vbus";
+		gpio = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_wifi: regulator-wifi {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_wl>;
+		compatible = "regulator-fixed";
+		regulator-name = "wifi";
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2>;
+};
+
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25M {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100M {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		opp-750M {
+			opp-hz = /bits/ 64 <750000000>;
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi1>;
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	can@0 {
+		compatible = "microchip,mcp2515";
+		reg = <0>;
+		clocks = <&can20m>;
+		oscillator-frequency = <20000000>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		spi-max-frequency = <10000000>;
+	};
+};
+
+/* off-board header */
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	local-mac-address = [00 00 00 00 00 00];
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+		};
+	};
+};
+
+&gpc {
+	status = "disabled";
+};
+
+&gpu {
+	status = "disabled";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	gsc: gsc@20 {
+		compatible = "gw,gsc";
+		reg = <0x20>;
+		pinctrl-0 = <&pinctrl_gsc>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+
+		adc {
+			compatible = "gw,gsc-adc";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel@6 {
+				gw,mode = <0>;
+				reg = <0x06>;
+				label = "temp";
+			};
+
+			channel@8 {
+				gw,mode = <1>;
+				reg = <0x08>;
+				label = "vdd_bat";
+			};
+
+			channel@82 {
+				gw,mode = <2>;
+				reg = <0x82>;
+				label = "vin";
+				gw,voltage-divider-ohms = <22100 1000>;
+				gw,voltage-offset-microvolt = <700000>;
+			};
+
+			channel@84 {
+				gw,mode = <2>;
+				reg = <0x84>;
+				label = "vin_4p0";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@86 {
+				gw,mode = <2>;
+				reg = <0x86>;
+				label = "vdd_3p3";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@88 {
+				gw,mode = <2>;
+				reg = <0x88>;
+				label = "vdd_0p9";
+			};
+
+			channel@8c {
+				gw,mode = <2>;
+				reg = <0x8c>;
+				label = "vdd_soc";
+			};
+
+			channel@8e {
+				gw,mode = <2>;
+				reg = <0x8e>;
+				label = "vdd_arm";
+			};
+
+			channel@90 {
+				gw,mode = <2>;
+				reg = <0x90>;
+				label = "vdd_1p8";
+			};
+
+			channel@92 {
+				gw,mode = <2>;
+				reg = <0x92>;
+				label = "vdd_dram";
+			};
+
+			channel@98 {
+				gw,mode = <2>;
+				reg = <0x98>;
+				label = "vdd_1p0";
+			};
+
+			channel@9a {
+				gw,mode = <2>;
+				reg = <0x9a>;
+				label = "vdd_2p5";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@a2 {
+				gw,mode = <2>;
+				reg = <0xa2>;
+				label = "vdd_gsc";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+		};
+	};
+
+	gpio: gpio@23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gsc>;
+		interrupts = <4>;
+	};
+
+	pmic@4b {
+		compatible = "rohm,bd71847";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+		#clock-cells = <0>;
+		clocks = <&osc_32k 0>;
+		clock-output-names = "clk-32k-out";
+
+		regulators {
+			/* vdd_soc: 0.805-0.900V (typ=0.8V) */
+			BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			/* vdd_arm: 0.805-1.0V (typ=0.9V) */
+			buck2: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			/* vdd_0p9: 0.805-1.0V (typ=0.9V) */
+			BUCK3 {
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_3p3 */
+			BUCK4 {
+				regulator-name = "buck4";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_1p8 */
+			BUCK5 {
+				regulator-name = "buck5";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_dram */
+			BUCK6 {
+				regulator-name = "buck6";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* nvcc_snvs_1p8 */
+			LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <1900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdd_snvs_0p8 */
+			LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			/* vdda_1p8 */
+			LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+
+	eeprom@50 {
+		compatible = "atmel,24c02";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+
+	eeprom@51 {
+		compatible = "atmel,24c02";
+		reg = <0x51>;
+		pagesize = <16>;
+	};
+
+	eeprom@52 {
+		compatible = "atmel,24c02";
+		reg = <0x52>;
+		pagesize = <16>;
+	};
+
+	eeprom@53 {
+		compatible = "atmel,24c02";
+		reg = <0x53>;
+		pagesize = <16>;
+	};
+
+	rtc: rtc@68 {
+		compatible = "dallas,ds1672";
+		reg = <0x68>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	accelerometer@19 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_accel>;
+		compatible = "st,lis2de12";
+		reg = <0x19>;
+		st,drdy-int-pin = <1>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "INT1";
+	};
+
+	secure-element@60 {
+		compatible = "nxp,se050";
+		reg = <0x60>;
+	};
+};
+
+/* off-board header */
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+/* off-board header */
+&i2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+};
+
+&mu {
+	status = "disabled";
+};
+
+/* off-board header */
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MN_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
+/* RS232/RS485/RS422 selectable */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>;
+	status = "okay";
+};
+
+/* RS232 console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+/* bluetooth HCI */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
+	rts-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+	cts-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	bluetooth {
+		compatible = "brcm,bcm4330-bt";
+		shutdown-gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/* LTE Cat M1/NB1/EGPRS modem or GPS (loading option) */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "host";
+	vbus-supply = <&reg_usb1_vbus>;
+	disable-over-current;
+	status = "okay";
+
+	/delete-property/power-domains;
+	/delete-property/assigned-clocks;
+	/delete-property/assigned-clock-parents;
+	assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>,
+		<&clk IMX8MN_CLK_USB_CORE_REF>;
+	assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>,
+		<&clk IMX8MN_SYS_PLL1_100M>;
+};
+
+/* SDIO WiFi */
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	bus-width = <4>;
+	non-removable;
+	vmmc-supply = <&reg_wifi>;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_CE0_B_GPIO3_IO1	0x40000159 /* M2_GDIS# */
+			MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13	0x40000041 /* M2_RST# */
+			MX8MN_IOMUXC_NAND_DATA01_GPIO3_IO7	0x40000119 /* M2_OFF# */
+			MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15	0x40000159 /* M2_WDIS# */
+			MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21	0x40000041 /* APP GPIO1 */
+			MX8MN_IOMUXC_SAI2_MCLK_GPIO4_IO27	0x40000041 /* APP GPIO2 */
+			MX8MN_IOMUXC_SD1_DATA6_GPIO2_IO8	0x40000041 /* UART2_EN# */
+			MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28	0x40000041 /* MIPI_GPIO1 */
+			MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5	0x40000041 /* MIPI_GPIO2 */
+			MX8MN_IOMUXC_SPDIF_RX_GPIO5_IO4		0x40000041 /* MIPI_GPIO3/PWM2 */
+			MX8MN_IOMUXC_SPDIF_TX_GPIO5_IO3		0x40000041 /* MIPI_GPIO4/PWM3 */
+		>;
+	};
+
+	pinctrl_accel: accelgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12	0x159
+		>;
+	};
+
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MN_IOMUXC_ENET_MDIO_ENET1_MDIO		0x3
+			MX8MN_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MN_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MN_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MN_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MN_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MN_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MN_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MN_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MN_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MN_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MN_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MN_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10		0x19 /* RST# */
+			MX8MN_IOMUXC_GPIO1_IO11_GPIO1_IO11		0x19 /* IRQ# */
+			MX8MN_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN	0x141
+			MX8MN_IOMUXC_GPIO1_IO09_ENET1_1588_EVENT0_OUT	0x141
+		>;
+	};
+
+	pinctrl_gsc: gscgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6	0x40
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C1_SCL_I2C1_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C1_SDA_I2C1_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C3_SCL_I2C3_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C3_SDA_I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL		0x400001c3
+			MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_gpio_leds: gpioledgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI5_RXD0_GPIO3_IO21	0x19
+			MX8MN_IOMUXC_SAI5_RXD2_GPIO3_IO23	0x19
+			MX8MN_IOMUXC_SAI5_RXD1_GPIO3_IO22	0x19
+			MX8MN_IOMUXC_SAI5_RXC_GPIO3_IO20	0x19
+			MX8MN_IOMUXC_SAI5_MCLK_GPIO3_IO25	0x19
+		>;
+	};
+
+	pinctrl_pmic: pmicgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_DATA02_GPIO3_IO8	0x41
+		>;
+	};
+
+	pinctrl_pps: ppsgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI5_RXD3_GPIO3_IO24	0x141 /* PPS */
+		>;
+	};
+
+	pinctrl_reg_wl: regwlgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41 /* WLAN_WLON */
+		>;
+	};
+
+	pinctrl_reg_usb1: regusb1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD1_DATA5_GPIO2_IO7	0x41
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI3_MCLK_SAI3_MCLK	0xd6
+			MX8MN_IOMUXC_SAI3_RXD_SAI3_RX_DATA0	0xd6
+			MX8MN_IOMUXC_SAI3_TXC_SAI3_TX_BCLK	0xd6
+			MX8MN_IOMUXC_SAI3_TXD_SAI3_TX_DATA0	0xd6
+			MX8MN_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC	0xd6
+		>;
+	};
+
+	pinctrl_spi1: spi1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK	0x82
+			MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI	0x82
+			MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO	0x82
+			MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9	0x40
+			MX8MN_IOMUXC_SD1_DATA1_GPIO2_IO3	0x140 /* CAN_IRQ# */
+		>;
+	};
+
+	pinctrl_spi2: spi2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK	0x82
+			MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI	0x82
+			MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO	0x82
+			MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13	0x40 /* SS0 */
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX	0x140
+			MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_uart1_gpio: uart1gpiogrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SAI2_TXD0_GPIO4_IO26	0x40000110 /* HALF */
+			MX8MN_IOMUXC_SAI2_TXC_GPIO4_IO25	0x40000110 /* TERM */
+			MX8MN_IOMUXC_SAI2_RXD0_GPIO4_IO23	0x40000110 /* RS485 */
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART2_RXD_UART2_DCE_RX	0x140
+			MX8MN_IOMUXC_UART2_TXD_UART2_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_uart3_gpio: uart3_gpiogrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CD_B_GPIO2_IO12	0x41 /* BT_EN# */
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART3_RXD_UART3_DCE_RX	0x140
+			MX8MN_IOMUXC_UART3_TXD_UART3_DCE_TX	0x140
+			MX8MN_IOMUXC_SD1_CLK_GPIO2_IO0		0x140 /* CTS */
+			MX8MN_IOMUXC_SD1_CMD_GPIO2_IO1		0x140 /* RTS */
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_UART4_RXD_UART4_DCE_RX	0x140
+			MX8MN_IOMUXC_UART4_TXD_UART4_DCE_TX	0x140
+			MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6	0x141 /* GNSS_GASP */
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_SD2_CLK_USDHC2_CLK		0x190
+			MX8MN_IOMUXC_SD2_CMD_USDHC2_CMD		0x1d0
+			MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0	0x1d0
+			MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1	0x1d0
+			MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2	0x1d0
+			MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK	0x190
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d0
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d0
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d0
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d0
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d0
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d0
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d0
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d0
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d0
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK	0x194
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d4
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d4
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d4
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d4
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d4
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d4
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d4
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d4
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d4
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK	0x196
+			MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD	0x1d6
+			MX8MN_IOMUXC_NAND_DATA04_USDHC3_DATA0	0x1d6
+			MX8MN_IOMUXC_NAND_DATA05_USDHC3_DATA1	0x1d6
+			MX8MN_IOMUXC_NAND_DATA06_USDHC3_DATA2	0x1d6
+			MX8MN_IOMUXC_NAND_DATA07_USDHC3_DATA3	0x1d6
+			MX8MN_IOMUXC_NAND_RE_B_USDHC3_DATA4	0x1d6
+			MX8MN_IOMUXC_NAND_CE2_B_USDHC3_DATA5	0x1d6
+			MX8MN_IOMUXC_NAND_CE3_B_USDHC3_DATA6	0x1d6
+			MX8MN_IOMUXC_NAND_CLE_USDHC3_DATA7	0x1d6
+			MX8MN_IOMUXC_NAND_CE1_B_USDHC3_STROBE	0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MN_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
+		>;
+	};
+};
+
+&cpu_alert0 {
+	temperature = <95000>;
+	hysteresis = <2000>;
+	type = "passive";
+};
+
+&cpu_crit0 {
+	temperature = <105000>;
+	hysteresis = <2000>;
+	type = "critical";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -4,14 +4,16 @@
  */
 
 #include <dt-bindings/clock/imx8mn-clock.h>
+#include <dt-bindings/power/imx8mn-power.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
 
 #include "imx8mn-pinfunc.h"
 
 / {
-	compatible = "fsl,imx8mn";
 	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
@@ -43,6 +45,19 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
+		idle-states {
+			entry-method = "psci";
+
+			cpu_pd_wait: cpu-pd-wait {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x0010033>;
+				local-timer-stop;
+				entry-latency-us = <1000>;
+				exit-latency-us = <700>;
+				min-residency-us = <2700>;
+			};
+		};
+
 		A53_0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53";
@@ -50,10 +65,18 @@
 			clock-latency = <61036>;
 			clocks = <&clk IMX8MN_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			nvmem-cells = <&cpu_speed_grade>;
 			nvmem-cell-names = "speed_grade";
+			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_1: cpu@1 {
@@ -63,8 +86,16 @@
 			clock-latency = <61036>;
 			clocks = <&clk IMX8MN_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
+			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_2: cpu@2 {
@@ -74,8 +105,16 @@
 			clock-latency = <61036>;
 			clocks = <&clk IMX8MN_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
+			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_3: cpu@3 {
@@ -85,12 +124,24 @@
 			clock-latency = <61036>;
 			clocks = <&clk IMX8MN_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
+			cpu-idle-states = <&cpu_pd_wait>;
+			#cooling-cells = <2>;
 		};
 
 		A53_L2: l2-cache0 {
 			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <0x80000>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
 		};
 	};
 
@@ -123,11 +174,6 @@
 		};
 	};
 
-	memory@40000000 {
-		device_type = "memory";
-		reg = <0x0 0x40000000 0 0x80000000>;
-	};
-
 	osc_32k: clock-osc-32k {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -170,26 +216,73 @@
 		clock-output-names = "clk_ext4";
 	};
 
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_PPI 7
+			     (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>;
+	};
+
 	psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
 	};
 
+	thermal-zones {
+		cpu-thermal {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tmu>;
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit0: trip1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
 		clock-frequency = <8000000>;
 		arm,no-tick-in-suspend;
 	};
 
 	soc@0 {
-		compatible = "simple-bus";
+		compatible = "fsl,imx8mn-soc", "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0x0 0x0 0x3e000000>;
+		dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>;
+		nvmem-cells = <&imx8mn_uid>;
+		nvmem-cell-names = "soc_unique_id";
+
+		caam_sm: caam-sm@00100000 {
+			compatible = "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
 
 		aips1: bus@30000000 {
 			compatible = "fsl,aips-bus", "simple-bus";
@@ -198,6 +291,149 @@
 			#size-cells = <1>;
 			ranges;
 
+			spba: spba-bus@30000000 {
+				compatible = "fsl,spba-bus", "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x30000000 0x100000>;
+				ranges;
+
+				sai2: sai@30020000 {
+					compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+					reg = <0x30020000 0x10000>;
+					interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SAI2_IPG>,
+						<&clk IMX8MN_CLK_DUMMY>,
+						<&clk IMX8MN_CLK_SAI2_ROOT>,
+						<&clk IMX8MN_CLK_DUMMY>, <&clk IMX8MN_CLK_DUMMY>;
+					clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+					dmas = <&sdma2 2 2 0>, <&sdma2 3 2 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
+
+				sai3: sai@30030000 {
+					compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+					reg = <0x30030000 0x10000>;
+					interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SAI3_IPG>,
+						 <&clk IMX8MN_CLK_DUMMY>,
+						 <&clk IMX8MN_CLK_SAI3_ROOT>,
+						 <&clk IMX8MN_CLK_DUMMY>, <&clk IMX8MN_CLK_DUMMY>;
+					clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+					dmas = <&sdma2 4 2 0>, <&sdma2 5 2 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
+
+				sai5: sai@30050000 {
+					compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+					reg = <0x30050000 0x10000>;
+					interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SAI5_IPG>,
+						 <&clk IMX8MN_CLK_DUMMY>,
+						 <&clk IMX8MN_CLK_SAI5_ROOT>,
+						 <&clk IMX8MN_CLK_DUMMY>, <&clk IMX8MN_CLK_DUMMY>;
+					clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+					dmas = <&sdma2 8 2 0>, <&sdma2 9 2 0>;
+					dma-names = "rx", "tx";
+					fsl,shared-interrupt;
+					fsl,dataline = <0 0xf 0xf>;
+					status = "disabled";
+				};
+
+				sai6: sai@30060000 {
+					compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+					reg = <0x30060000  0x10000>;
+					interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SAI6_IPG>,
+						 <&clk IMX8MN_CLK_DUMMY>,
+						 <&clk IMX8MN_CLK_SAI6_ROOT>,
+						 <&clk IMX8MN_CLK_DUMMY>, <&clk IMX8MN_CLK_DUMMY>;
+					clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+					dmas = <&sdma2 10 2 0>, <&sdma2 11 2 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
+
+				micfil: audio-controller@30080000 {
+					compatible = "fsl,imx8mm-micfil";
+					reg = <0x30080000 0x10000>;
+					interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+						     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+						     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+						     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_PDM_IPG>,
+						 <&clk IMX8MN_CLK_PDM_ROOT>,
+						 <&clk IMX8MN_AUDIO_PLL1_OUT>,
+						 <&clk IMX8MN_AUDIO_PLL2_OUT>,
+						 <&clk IMX8MN_CLK_EXT3>;
+					clock-names = "ipg_clk", "ipg_clk_app",
+						      "pll8k", "pll11k", "clkext3";
+					dmas = <&sdma2 24 25 0x80000000>;
+					dma-names = "rx";
+					status = "disabled";
+				};
+
+				spdif1: spdif@30090000 {
+					compatible = "fsl,imx35-spdif";
+					reg = <0x30090000 0x10000>;
+					interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_AUDIO_AHB>, /* core */
+						 <&clk IMX8MN_CLK_24M>, /* rxtx0 */
+						 <&clk IMX8MN_CLK_SPDIF1>, /* rxtx1 */
+						 <&clk IMX8MN_CLK_DUMMY>, /* rxtx2 */
+						 <&clk IMX8MN_CLK_DUMMY>, /* rxtx3 */
+						 <&clk IMX8MN_CLK_DUMMY>, /* rxtx4 */
+						 <&clk IMX8MN_CLK_AUDIO_AHB>, /* rxtx5 */
+						 <&clk IMX8MN_CLK_DUMMY>, /* rxtx6 */
+						 <&clk IMX8MN_CLK_DUMMY>, /* rxtx7 */
+						 <&clk IMX8MN_CLK_DUMMY>; /* spba */
+					clock-names = "core", "rxtx0",
+						      "rxtx1", "rxtx2",
+						      "rxtx3", "rxtx4",
+						      "rxtx5", "rxtx6",
+						      "rxtx7", "spba";
+					dmas = <&sdma2 28 18 0>, <&sdma2 29 18 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
+
+				sai7: sai@300b0000 {
+					compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai";
+					reg = <0x300b0000 0x10000>;
+					interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SAI7_IPG>,
+						 <&clk IMX8MN_CLK_DUMMY>,
+						 <&clk IMX8MN_CLK_SAI7_ROOT>,
+						 <&clk IMX8MN_CLK_DUMMY>, <&clk IMX8MN_CLK_DUMMY>;
+					clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+					dmas = <&sdma2 12 2 0>, <&sdma2 13 2 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
+
+				easrc: easrc@300c0000 {
+					compatible = "fsl,imx8mn-easrc";
+					reg = <0x300c0000 0x10000>;
+					interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_ASRC_ROOT>;
+					clock-names = "mem";
+					dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>,
+					       <&sdma2 18 23 0> , <&sdma2 19 23 0>,
+					       <&sdma2 20 23 0> , <&sdma2 21 23 0>,
+					       <&sdma2 22 23 0> , <&sdma2 23 23 0>;
+					dma-names = "ctx0_rx", "ctx0_tx",
+						    "ctx1_rx", "ctx1_tx",
+						    "ctx2_rx", "ctx2_tx",
+						    "ctx3_rx", "ctx3_tx";
+					firmware-name = "imx/easrc/easrc-imx8mn.bin";
+					fsl,asrc-rate  = <8000>;
+					fsl,asrc-format = <2>;
+					status = "disabled";
+				};
+			};
+
 			gpio1: gpio@30200000 {
 				compatible = "fsl,imx8mn-gpio", "fsl,imx35-gpio";
 				reg = <0x30200000 0x10000>;
@@ -263,6 +499,13 @@
 				gpio-ranges = <&iomuxc 0 119 30>;
 			};
 
+			tmu: tmu@30260000 {
+				compatible = "fsl,imx8mn-tmu", "fsl,imx8mm-tmu";
+				reg = <0x30260000 0x10000>;
+				clocks = <&clk IMX8MN_CLK_TMU_ROOT>;
+				#thermal-sensor-cells = <0>;
+			};
+
 			wdog1: watchdog@30280000 {
 				compatible = "fsl,imx8mn-wdt", "fsl,imx21-wdt";
 				reg = <0x30280000 0x10000>;
@@ -319,21 +562,29 @@
 				reg = <0x30340000 0x10000>;
 			};
 
-			ocotp: ocotp-ctrl@30350000 {
-				compatible = "fsl,imx8mn-ocotp", "fsl,imx7d-ocotp", "syscon";
+			ocotp: efuse@30350000 {
+				compatible = "fsl,imx8mn-ocotp", "fsl,imx8mm-ocotp", "syscon";
 				reg = <0x30350000 0x10000>;
 				clocks = <&clk IMX8MN_CLK_OCOTP_ROOT>;
 				#address-cells = <1>;
 				#size-cells = <1>;
 
+				imx8mn_uid: unique-id@410 {
+					reg = <0x4 0x8>;
+				};
+
 				cpu_speed_grade: speed-grade@10 {
 					reg = <0x10 4>;
 				};
+
+				fec_mac_address: mac-address@90 {
+					reg = <0x90 6>;
+				};
 			};
 
 			anatop: anatop@30360000 {
 				compatible = "fsl,imx8mn-anatop", "fsl,imx8mm-anatop",
-					     "syscon", "simple-bus";
+					     "syscon";
 				reg = <0x30360000 0x10000>;
 			};
 
@@ -347,6 +598,7 @@
 					offset = <0x34>;
 					interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
 						     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SNVS_ROOT>;
 					clock-names = "snvs-rtc";
 				};
 
@@ -354,6 +606,8 @@
 					compatible = "fsl,sec-v4.0-pwrkey";
 					regmap = <&snvs>;
 					interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MN_CLK_SNVS_ROOT>;
+					clock-names = "snvs-pwrkey";
 					linux,keycode = <KEY_POWER>;
 					wakeup-source;
 					status = "disabled";
@@ -368,14 +622,66 @@
 					 <&clk_ext3>, <&clk_ext4>;
 				clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
 					      "clk_ext3", "clk_ext4";
+				assigned-clocks = <&clk IMX8MN_CLK_A53_SRC>,
+						<&clk IMX8MN_CLK_A53_CORE>,
+						<&clk IMX8MN_CLK_NOC>,
+						<&clk IMX8MN_CLK_AUDIO_AHB>,
+						<&clk IMX8MN_CLK_IPG_AUDIO_ROOT>,
+						<&clk IMX8MN_SYS_PLL3>,
+						<&clk IMX8MN_AUDIO_PLL1>,
+						<&clk IMX8MN_AUDIO_PLL2>;
+				assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_800M>,
+							 <&clk IMX8MN_ARM_PLL_OUT>,
+							 <&clk IMX8MN_SYS_PLL3_OUT>,
+							 <&clk IMX8MN_SYS_PLL1_800M>;
+				assigned-clock-rates = <0>, <0>, <0>,
+							<400000000>,
+							<400000000>,
+							<600000000>,
+							<393216000>,
+							<361267200>;
 			};
 
 			src: reset-controller@30390000 {
-				compatible = "fsl,imx8mn-src", "syscon";
+				compatible = "fsl,imx8mn-src", "fsl,imx8mq-src", "syscon";
 				reg = <0x30390000 0x10000>;
 				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 				#reset-cells = <1>;
 			};
+
+			gpc: gpc@303a0000 {
+				compatible = "fsl,imx8mn-gpc";
+				reg = <0x303a0000 0x10000>;
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+
+				pgc {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					pgc_hsiomix: power-domain@0 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MN_POWER_DOMAIN_HSIOMIX>;
+						clocks = <&clk IMX8MN_CLK_USB_BUS>;
+					};
+
+					pgc_otg1: power-domain@1 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MN_POWER_DOMAIN_OTG1>;
+						power-domains = <&pgc_hsiomix>;
+					};
+
+					pgc_gpumix: power-domain@2 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MN_POWER_DOMAIN_GPUMIX>;
+						clocks = <&clk IMX8MN_CLK_GPU_CORE_ROOT>,
+							 <&clk IMX8MN_CLK_GPU_SHADER_DIV>,
+							 <&clk IMX8MN_CLK_GPU_BUS_ROOT>,
+							 <&clk IMX8MN_CLK_GPU_AHB>;
+						resets = <&src IMX8MQ_RESET_GPU_RESET>;
+					};
+				};
+			};
 		};
 
 		aips2: bus@30400000 {
@@ -428,6 +734,14 @@
 				#pwm-cells = <2>;
 				status = "disabled";
 			};
+
+			system_counter: timer@306a0000 {
+				compatible = "nxp,sysctr-timer";
+				reg = <0x306a0000 0x20000>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&osc_24m>;
+				clock-names = "per";
+			};
 		};
 
 		aips3: bus@30800000 {
@@ -513,6 +827,36 @@
 				status = "disabled";
 			};
 
+			crypto: crypto@30900000 {
+				compatible = "fsl,sec-v4.0";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x30900000 0x40000>;
+				ranges = <0 0x30900000 0x40000>;
+				interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MN_CLK_AHB>,
+					 <&clk IMX8MN_CLK_IPG_ROOT>;
+				clock-names = "aclk", "ipg";
+
+				sec_jr0: jr@1000 {
+					 compatible = "fsl,sec-v4.0-job-ring";
+					 reg = <0x1000 0x1000>;
+					 interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr1: jr@2000 {
+					 compatible = "fsl,sec-v4.0-job-ring";
+					 reg = <0x2000 0x1000>;
+					 interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr2: jr@3000 {
+					 compatible = "fsl,sec-v4.0-job-ring";
+					 reg = <0x3000 0x1000>;
+					 interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+				};
+			};
+
 			i2c1: i2c@30a20000 {
 				compatible = "fsl,imx8mn-i2c", "fsl,imx21-i2c";
 				#address-cells = <1>;
@@ -565,6 +909,14 @@
 				status = "disabled";
 			};
 
+			mu: mailbox@30aa0000 {
+				compatible = "fsl,imx8mn-mu", "fsl,imx6sx-mu";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MN_CLK_MU_ROOT>;
+				#mbox-cells = <2>;
+			};
+
 			usdhc1: mmc@30b40000 {
 				compatible = "fsl,imx8mn-usdhc", "fsl,imx7d-usdhc";
 				reg = <0x30b40000 0x10000>;
@@ -573,8 +925,6 @@
 					 <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
 					 <&clk IMX8MN_CLK_USDHC1_ROOT>;
 				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX8MN_CLK_USDHC1>;
-				assigned-clock-rates = <400000000>;
 				fsl,tuning-start-tap = <20>;
 				fsl,tuning-step= <2>;
 				bus-width = <4>;
@@ -603,20 +953,31 @@
 					 <&clk IMX8MN_CLK_NAND_USDHC_BUS>,
 					 <&clk IMX8MN_CLK_USDHC3_ROOT>;
 				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX8MN_CLK_USDHC3_ROOT>;
-				assigned-clock-rates = <400000000>;
 				fsl,tuning-start-tap = <20>;
 				fsl,tuning-step= <2>;
 				bus-width = <4>;
 				status = "disabled";
 			};
 
+			flexspi: spi@30bb0000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "nxp,imx8mm-fspi";
+				reg = <0x30bb0000 0x10000>, <0x8000000 0x10000000>;
+				reg-names = "fspi_base", "fspi_mmap";
+				interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MN_CLK_QSPI_ROOT>,
+					 <&clk IMX8MN_CLK_QSPI_ROOT>;
+				clock-names = "fspi", "fspi_en";
+				status = "disabled";
+			};
+
 			sdma1: dma-controller@30bd0000 {
 				compatible = "fsl,imx8mn-sdma", "fsl,imx8mq-sdma";
 				reg = <0x30bd0000 0x10000>;
 				interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MN_CLK_SDMA1_ROOT>,
-					 <&clk IMX8MN_CLK_SDMA1_ROOT>;
+					 <&clk IMX8MN_CLK_AHB>;
 				clock-names = "ipg", "ahb";
 				#dma-cells = <3>;
 				fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
@@ -627,7 +988,8 @@
 				reg = <0x30be0000 0x10000>;
 				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MN_CLK_ENET1_ROOT>,
 					 <&clk IMX8MN_CLK_ENET1_ROOT>,
 					 <&clk IMX8MN_CLK_ENET_TIMER>,
@@ -638,13 +1000,18 @@
 				assigned-clocks = <&clk IMX8MN_CLK_ENET_AXI>,
 						  <&clk IMX8MN_CLK_ENET_TIMER>,
 						  <&clk IMX8MN_CLK_ENET_REF>,
-						  <&clk IMX8MN_CLK_ENET_TIMER>;
+						  <&clk IMX8MN_CLK_ENET_PHY_REF>;
 				assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_266M>,
 							 <&clk IMX8MN_SYS_PLL2_100M>,
-							 <&clk IMX8MN_SYS_PLL2_125M>;
-				assigned-clock-rates = <0>, <0>, <125000000>, <100000000>;
+							 <&clk IMX8MN_SYS_PLL2_125M>,
+							 <&clk IMX8MN_SYS_PLL2_50M>;
+				assigned-clock-rates = <0>, <100000000>, <125000000>, <0>;
 				fsl,num-tx-queues = <3>;
 				fsl,num-rx-queues = <3>;
+				nvmem-cells = <&fec_mac_address>;
+				nvmem-cell-names = "mac-address";
+				nvmem_macaddr_swap;
+				fsl,stop-mode = <&gpr 0x10 3>;
 				status = "disabled";
 			};
 
@@ -663,12 +1030,11 @@
 				interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>;
 				clock-names = "usb1_ctrl_root_clk";
-				assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>,
-						  <&clk IMX8MN_CLK_USB_CORE_REF>;
-				assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>,
-							 <&clk IMX8MN_SYS_PLL1_100M>;
+				assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>;
+				assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>;
 				fsl,usbphy = <&usbphynop1>;
 				fsl,usbmisc = <&usbmisc1 0>;
+				power-domains = <&pgc_otg1>;
 				status = "disabled";
 			};
 
@@ -677,28 +1043,6 @@
 				#index-cells = <1>;
 				reg = <0x32e40200 0x200>;
 			};
-
-			usbotg2: usb@32e50000 {
-				compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb";
-				reg = <0x32e50000 0x200>;
-				interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>;
-				clock-names = "usb1_ctrl_root_clk";
-				assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>,
-						  <&clk IMX8MN_CLK_USB_CORE_REF>;
-				assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>,
-							 <&clk IMX8MN_SYS_PLL1_100M>;
-				fsl,usbphy = <&usbphynop2>;
-				fsl,usbmisc = <&usbmisc2 0>;
-				status = "disabled";
-			};
-
-			usbmisc2: usbmisc@32e50200 {
-				compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc";
-				#index-cells = <1>;
-				reg = <0x32e50200 0x200>;
-			};
-
 		};
 
 		dma_apbh: dma-controller@33000000 {
@@ -717,7 +1061,7 @@
 		gpmi: nand-controller@33002000 {
 			compatible = "fsl,imx8mn-gpmi-nand", "fsl,imx7d-gpmi-nand";
 			#address-cells = <1>;
-			#size-cells = <1>;
+			#size-cells = <0>;
 			reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
 			reg-names = "gpmi-nand", "bch";
 			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
@@ -730,6 +1074,31 @@
 			status = "disabled";
 		};
 
+		gpu: gpu@38000000 {
+			compatible = "vivante,gc";
+			reg = <0x38000000 0x8000>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX8MN_CLK_GPU_AHB>,
+				<&clk IMX8MN_CLK_GPU_BUS_ROOT>,
+				<&clk IMX8MN_CLK_GPU_CORE_ROOT>,
+				<&clk IMX8MN_CLK_GPU_SHADER_DIV>;
+			clock-names = "reg", "bus", "core", "shader";
+			assigned-clocks = <&clk IMX8MN_CLK_GPU_CORE_SRC>,
+					  <&clk IMX8MN_CLK_GPU_SHADER_SRC>,
+					  <&clk IMX8MN_CLK_GPU_AXI>,
+					  <&clk IMX8MN_CLK_GPU_AHB>,
+					  <&clk IMX8MN_GPU_PLL>,
+					  <&clk IMX8MN_CLK_GPU_CORE_DIV>,
+					  <&clk IMX8MN_CLK_GPU_SHADER_DIV>;
+			assigned-clock-parents = <&clk IMX8MN_GPU_PLL_OUT>,
+						  <&clk IMX8MN_GPU_PLL_OUT>,
+						  <&clk IMX8MN_SYS_PLL1_800M>,
+						  <&clk IMX8MN_SYS_PLL1_800M>;
+			assigned-clock-rates = <0>, <0>, <800000000>, <400000000>, <1200000000>,
+				<400000000>, <400000000>;
+			power-domains = <&pgc_gpumix>;
+		};
+
 		gic: interrupt-controller@38800000 {
 			compatible = "arm,gic-v3";
 			reg = <0x38800000 0x10000>,
@@ -738,17 +1107,25 @@
 			interrupt-controller;
 			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
 		};
-	};
 
-	usbphynop1: usbphynop1 {
-		compatible = "usb-nop-xceiv";
-		clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;
-		assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;
-		assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_100M>;
-		clock-names = "main_clk";
+		ddrc: memory-controller@3d400000 {
+			compatible = "fsl,imx8mn-ddrc", "fsl,imx8m-ddrc";
+			reg = <0x3d400000 0x400000>;
+			clock-names = "core", "pll", "alt", "apb";
+			clocks = <&clk IMX8MN_CLK_DRAM_CORE>,
+				 <&clk IMX8MN_DRAM_PLL>,
+				 <&clk IMX8MN_CLK_DRAM_ALT>,
+				 <&clk IMX8MN_CLK_DRAM_APB>;
+		};
+
+		ddr-pmu@3d800000 {
+			compatible = "fsl,imx8mn-ddr-pmu", "fsl,imx8m-ddr-pmu";
+			reg = <0x3d800000 0x400000>;
+			interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+		};
 	};
 
-	usbphynop2: usbphynop2 {
+	usbphynop1: usbphynop1 {
 		compatible = "usb-nop-xceiv";
 		clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;
 		assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8mp.dtsi"
+
+/ {
+	model = "NXP i.MX8MPlus EVK board";
+	compatible = "fsl,imx8mp-evk", "fsl,imx8mp";
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+
+		status {
+			label = "yellow:status";
+			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0xc0000000>,
+		      <0x1 0x00000000 0 0xc0000000>;
+	};
+
+	reg_can1_stby: regulator-can1-stby {
+		compatible = "regulator-fixed";
+		regulator-name = "can1-stby";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_flexcan1_reg>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_can2_stby: regulator-can2-stby {
+		compatible = "regulator-fixed";
+		regulator-name = "can2-stby";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_flexcan2_reg>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio4 27 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	xceiver-supply = <&reg_can1_stby>;
+	status = "okay";
+};
+
+&flexcan2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan2>;
+	xceiver-supply = <&reg_can2_stby>;
+	status = "disabled";/* can2 pin conflict with pdm */
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy1>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy1: ethernet-phy@1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			eee-broken-1000t;
+			reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	pca6416: gpio@20 {
+		compatible = "ti,tca6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart2 {
+	/* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb1_vbus>;
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC3>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC		0x3
+			MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO		0x3
+			MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0		0x91
+			MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1		0x91
+			MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2		0x91
+			MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3		0x91
+			MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC		0x91
+			MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL	0x91
+			MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0		0x1f
+			MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1		0x1f
+			MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2		0x1f
+			MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3		0x1f
+			MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL	0x1f
+			MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC		0x1f
+			MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02		0x19
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_RX__CAN1_RX          0x154
+			MX8MP_IOMUXC_SPDIF_TX__CAN1_TX          0x154
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX         0x154
+			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX         0x154
+		>;
+	};
+
+	pinctrl_flexcan1_reg: flexcan1reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05  0x154   /* CAN1_STBY */
+		>;
+	};
+
+	pinctrl_flexcan2_reg: flexcan2reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27      0x154   /* CAN2_STBY */
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19	0x41
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX	0x49
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX	0x49
+		>;
+	};
+
+	pinctrl_usb1_vbus: usb1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR	0x19
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT	0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12	0x1c4
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x190
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d0
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d0
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d0
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d0
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d0
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d0
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d0
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d0
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d0
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x194
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d4
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d4
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d4
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d4
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d4
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d4
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d4
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d4
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d4
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x196
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d6
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d6
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d6
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d6
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d6
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d6
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d6
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d6
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d6
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B	0x166
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp-pinfunc.h
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp-pinfunc.h
@@ -0,0 +1,799 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#ifndef __DTS_IMX8MP_PINFUNC_H
+#define __DTS_IMX8MP_PINFUNC_H
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+#define MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00                          0x014 0x274 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO00__CCM_ENET_PHY_REF_CLK_ROOT           0x014 0x274 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO00__ISP_FL_TRIG_0                       0x014 0x274 0x5D4 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO00__CCM_EXT_CLK1                        0x014 0x274 0x000 0x6 0x0
+#define MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01                          0x018 0x278 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO01__PWM1_OUT                            0x018 0x278 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO01__ISP_SHUTTER_TRIG_0                  0x018 0x278 0x5DC 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO01__CCM_EXT_CLK2                        0x018 0x278 0x000 0x6 0x0
+#define MX8MP_IOMUXC_GPIO1_IO02__GPIO1_IO02                          0x01C 0x27C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B                        0x01C 0x27C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO02__ISP_FLASH_TRIG_0                    0x01C 0x27C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_ANY                      0x01C 0x27C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO02__SJC_DE_B                            0x01C 0x27C 0x000 0x7 0x0
+#define MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03                          0x020 0x280 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO03__USDHC1_VSELECT                      0x020 0x280 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO03__ISP_PRELIGHT_TRIG_0                 0x020 0x280 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO03__SDMA1_EXT_EVENT00                   0x020 0x280 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04                          0x024 0x284 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT                      0x024 0x284 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO04__ISP_SHUTTER_OPEN_0                  0x024 0x284 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO04__SDMA1_EXT_EVENT01                   0x024 0x284 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05                          0x028 0x288 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO05__M7_NMI                              0x028 0x288 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO05__ISP_FL_TRIG_1                       0x028 0x288 0x5D8 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO05__CCM_PMIC_READY                      0x028 0x288 0x554 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06                          0x02C 0x28C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO06__ENET_QOS_MDC                        0x02C 0x28C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO06__ISP_SHUTTER_TRIG_1                  0x02C 0x28C 0x5E0 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO06__USDHC1_CD_B                         0x02C 0x28C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO06__CCM_EXT_CLK3                        0x02C 0x28C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07                          0x030 0x290 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO07__ENET_QOS_MDIO                       0x030 0x290 0x590 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO07__ISP_FLASH_TRIG_1                    0x030 0x290 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO07__USDHC1_WP                           0x030 0x290 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO07__CCM_EXT_CLK4                        0x030 0x290 0x000 0x6 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08                          0x034 0x294 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__ENET_QOS_1588_EVENT0_IN             0x034 0x294 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__PWM1_OUT                            0x034 0x294 0x000 0x2 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__ISP_PRELIGHT_TRIG_1                 0x034 0x294 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__ENET_QOS_1588_EVENT0_AUX_IN         0x034 0x294 0x000 0x4 0x0
+#define MX8MP_IOMUXC_GPIO1_IO08__USDHC2_RESET_B                      0x034 0x294 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09                          0x038 0x298 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__ENET_QOS_1588_EVENT0_OUT            0x038 0x298 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__PWM2_OUT                            0x038 0x298 0x000 0x2 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__ISP_SHUTTER_OPEN_1                  0x038 0x298 0x000 0x3 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__USDHC3_RESET_B                      0x038 0x298 0x000 0x4 0x0
+#define MX8MP_IOMUXC_GPIO1_IO09__SDMA2_EXT_EVENT00                   0x038 0x298 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10                          0x03C 0x29C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO10__USB1_OTG_ID                         0x03C 0x29C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO10__PWM3_OUT                            0x03C 0x29C 0x000 0x2 0x0
+#define MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11                          0x040 0x2A0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO11__USB2_OTG_ID                         0x040 0x2A0 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO11__PWM2_OUT                            0x040 0x2A0 0x000 0x2 0x0
+#define MX8MP_IOMUXC_GPIO1_IO11__USDHC3_VSELECT                      0x040 0x2A0 0x000 0x4 0x0
+#define MX8MP_IOMUXC_GPIO1_IO11__CCM_PMIC_READY                      0x040 0x2A0 0x554 0x5 0x1
+#define MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12                          0x044 0x2A4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO12__USB1_OTG_PWR                        0x044 0x2A4 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO12__SDMA2_EXT_EVENT01                   0x044 0x2A4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13                          0x048 0x2A8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO13__USB1_OTG_OC                         0x048 0x2A8 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO13__PWM2_OUT                            0x048 0x2A8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14                          0x04C 0x2AC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR                        0x04C 0x2AC 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO14__USDHC3_CD_B                         0x04C 0x2AC 0x608 0x4 0x0
+#define MX8MP_IOMUXC_GPIO1_IO14__PWM3_OUT                            0x04C 0x2AC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO14__CCM_CLKO1                           0x04C 0x2AC 0x000 0x6 0x0
+#define MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15                          0x050 0x2B0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_GPIO1_IO15__USB2_OTG_OC                         0x050 0x2B0 0x000 0x1 0x0
+#define MX8MP_IOMUXC_GPIO1_IO15__USDHC3_WP                           0x050 0x2B0 0x634 0x4 0x0
+#define MX8MP_IOMUXC_GPIO1_IO15__PWM4_OUT                            0x050 0x2B0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_GPIO1_IO15__CCM_CLKO2                           0x050 0x2B0 0x000 0x6 0x0
+#define MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                          0x054 0x2B4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_MDC__AUDIOMIX_SAI6_TX_DATA00               0x054 0x2B4 0x000 0x2 0x0
+#define MX8MP_IOMUXC_ENET_MDC__GPIO1_IO16                            0x054 0x2B4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_MDC__USDHC3_STROBE                         0x054 0x2B4 0x630 0x6 0x0
+#define MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                        0x058 0x2B8 0x590 0x0 0x1
+#define MX8MP_IOMUXC_ENET_MDIO__AUDIOMIX_SAI6_TX_SYNC                0x058 0x2B8 0x528 0x2 0x0
+#define MX8MP_IOMUXC_ENET_MDIO__AUDIOMIX_PDM_BIT_STREAM03            0x058 0x2B8 0x4CC 0x3 0x0
+#define MX8MP_IOMUXC_ENET_MDIO__GPIO1_IO17                           0x058 0x2B8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_MDIO__USDHC3_DATA5                         0x058 0x2B8 0x624 0x6 0x0
+#define MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                    0x05C 0x2BC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TD3__AUDIOMIX_SAI6_TX_BCLK                 0x05C 0x2BC 0x524 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TD3__AUDIOMIX_PDM_BIT_STREAM02             0x05C 0x2BC 0x4C8 0x3 0x0
+#define MX8MP_IOMUXC_ENET_TD3__GPIO1_IO18                            0x05C 0x2BC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TD3__USDHC3_DATA6                          0x05C 0x2BC 0x628 0x6 0x0
+#define MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                    0x060 0x2C0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TD2__CCM_ENET_QOS_CLOCK_GENERATE_REF_CLK   0x060 0x2C0 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ENET_TD2__AUDIOMIX_SAI6_RX_DATA00               0x060 0x2C0 0x51C 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TD2__AUDIOMIX_PDM_BIT_STREAM01             0x060 0x2C0 0x4C4 0x3 0x0
+#define MX8MP_IOMUXC_ENET_TD2__GPIO1_IO19                            0x060 0x2C0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TD2__USDHC3_DATA7                          0x060 0x2C0 0x62C 0x6 0x0
+#define MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                    0x064 0x2C4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TD1__AUDIOMIX_SAI6_RX_SYNC                 0x064 0x2C4 0x520 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TD1__AUDIOMIX_PDM_BIT_STREAM00             0x064 0x2C4 0x4C0 0x3 0x0
+#define MX8MP_IOMUXC_ENET_TD1__GPIO1_IO20                            0x064 0x2C4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TD1__USDHC3_CD_B                           0x064 0x2C4 0x608 0x6 0x1
+#define MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                    0x068 0x2C8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TD0__AUDIOMIX_SAI6_RX_BCLK                 0x068 0x2C8 0x518 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TD0__AUDIOMIX_PDM_CLK                      0x068 0x2C8 0x000 0x3 0x0
+#define MX8MP_IOMUXC_ENET_TD0__GPIO1_IO21                            0x068 0x2C8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TD0__USDHC3_WP                             0x068 0x2C8 0x634 0x6 0x1
+#define MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL              0x06C 0x2CC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TX_CTL__AUDIOMIX_SAI6_MCLK                 0x06C 0x2CC 0x514 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TX_CTL__AUDIOMIX_SPDIF1_OUT                0x06C 0x2CC 0x000 0x3 0x0
+#define MX8MP_IOMUXC_ENET_TX_CTL__GPIO1_IO22                         0x06C 0x2CC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TX_CTL__USDHC3_DATA0                       0x06C 0x2CC 0x610 0x6 0x0
+#define MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK    0x070 0x2D0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_TXC__ENET_QOS_TX_ER                        0x070 0x2D0 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ENET_TXC__AUDIOMIX_SAI7_TX_DATA00               0x070 0x2D0 0x000 0x2 0x0
+#define MX8MP_IOMUXC_ENET_TXC__GPIO1_IO23                            0x070 0x2D0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_TXC__USDHC3_DATA1                          0x070 0x2D0 0x614 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL              0x074 0x2D4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RX_CTL__AUDIOMIX_SAI7_TX_SYNC              0x074 0x2D4 0x540 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RX_CTL__AUDIOMIX_PDM_BIT_STREAM03          0x074 0x2D4 0x4CC 0x3 0x1
+#define MX8MP_IOMUXC_ENET_RX_CTL__GPIO1_IO24                         0x074 0x2D4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RX_CTL__USDHC3_DATA2                       0x074 0x2D4 0x618 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK    0x078 0x2D8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RXC__ENET_QOS_RX_ER                        0x078 0x2D8 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ENET_RXC__AUDIOMIX_SAI7_TX_BCLK                 0x078 0x2D8 0x53C 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RXC__AUDIOMIX_PDM_BIT_STREAM02             0x078 0x2D8 0x4C8 0x3 0x1
+#define MX8MP_IOMUXC_ENET_RXC__GPIO1_IO25                            0x078 0x2D8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RXC__USDHC3_DATA3                          0x078 0x2D8 0x61C 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                    0x07C 0x2DC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RD0__AUDIOMIX_SAI7_RX_DATA00               0x07C 0x2DC 0x534 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RD0__AUDIOMIX_PDM_BIT_STREAM01             0x07C 0x2DC 0x4C4 0x3 0x1
+#define MX8MP_IOMUXC_ENET_RD0__GPIO1_IO26                            0x07C 0x2DC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RD0__USDHC3_DATA4                          0x07C 0x2DC 0x620 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                    0x080 0x2E0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RD1__AUDIOMIX_SAI7_RX_SYNC                 0x080 0x2E0 0x538 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RD1__AUDIOMIX_PDM_BIT_STREAM00             0x080 0x2E0 0x4C0 0x3 0x1
+#define MX8MP_IOMUXC_ENET_RD1__GPIO1_IO27                            0x080 0x2E0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RD1__USDHC3_RESET_B                        0x080 0x2E0 0x000 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                    0x084 0x2E4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RD2__AUDIOMIX_SAI7_RX_BCLK                 0x084 0x2E4 0x530 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RD2__AUDIOMIX_PDM_CLK                      0x084 0x2E4 0x000 0x3 0x0
+#define MX8MP_IOMUXC_ENET_RD2__GPIO1_IO28                            0x084 0x2E4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RD2__USDHC3_CLK                            0x084 0x2E4 0x604 0x6 0x0
+#define MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                    0x088 0x2E8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_ENET_RD3__AUDIOMIX_SAI7_MCLK                    0x088 0x2E8 0x52C 0x2 0x0
+#define MX8MP_IOMUXC_ENET_RD3__AUDIOMIX_SPDIF1_IN                    0x088 0x2E8 0x544 0x3 0x0
+#define MX8MP_IOMUXC_ENET_RD3__GPIO1_IO29                            0x088 0x2E8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ENET_RD3__USDHC3_CMD                            0x088 0x2E8 0x60C 0x6 0x0
+#define MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                             0x08C 0x2EC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_CLK__ENET1_MDC                              0x08C 0x2EC 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SD1_CLK__I2C5_SCL                               0x08C 0x2EC 0x5C4 0x3 0x0
+#define MX8MP_IOMUXC_SD1_CLK__UART1_DCE_TX                           0x08C 0x2EC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_CLK__UART1_DTE_RX                           0x08C 0x2EC 0x5E8 0x4 0x0
+#define MX8MP_IOMUXC_SD1_CLK__GPIO2_IO00                             0x08C 0x2EC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                             0x090 0x2F0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_CMD__ENET1_MDIO                             0x090 0x2F0 0x57C 0x1 0x0
+#define MX8MP_IOMUXC_SD1_CMD__I2C5_SDA                               0x090 0x2F0 0x5C8 0x3 0x0
+#define MX8MP_IOMUXC_SD1_CMD__UART1_DCE_RX                           0x090 0x2F0 0x5E8 0x4 0x1
+#define MX8MP_IOMUXC_SD1_CMD__UART1_DTE_TX                           0x090 0x2F0 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_CMD__GPIO2_IO01                             0x090 0x2F0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0                         0x094 0x2F4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__ENET1_RGMII_TD1                      0x094 0x2F4 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__I2C6_SCL                             0x094 0x2F4 0x5CC 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__UART1_DCE_RTS                        0x094 0x2F4 0x5E4 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__UART1_DTE_CTS                        0x094 0x2F4 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA0__GPIO2_IO02                           0x094 0x2F4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1                         0x098 0x2F8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA1__ENET1_RGMII_TD0                      0x098 0x2F8 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA1__I2C6_SDA                             0x098 0x2F8 0x5D0 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA1__UART1_DCE_CTS                        0x098 0x2F8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA1__UART1_DTE_RTS                        0x098 0x2F8 0x5E4 0x4 0x1
+#define MX8MP_IOMUXC_SD1_DATA1__GPIO2_IO03                           0x098 0x2F8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2                         0x09C 0x2FC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__ENET1_RGMII_RD0                      0x09C 0x2FC 0x580 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__I2C4_SCL                             0x09C 0x2FC 0x5BC 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__UART2_DCE_TX                         0x09C 0x2FC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__UART2_DTE_RX                         0x09C 0x2FC 0x5F0 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA2__GPIO2_IO04                           0x09C 0x2FC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3                         0x0A0 0x300 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA3__ENET1_RGMII_RD1                      0x0A0 0x300 0x584 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA3__I2C4_SDA                             0x0A0 0x300 0x5C0 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA3__UART2_DCE_RX                         0x0A0 0x300 0x5F0 0x4 0x1
+#define MX8MP_IOMUXC_SD1_DATA3__UART2_DTE_TX                         0x0A0 0x300 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA3__GPIO2_IO05                           0x0A0 0x300 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4                         0x0A4 0x304 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__ENET1_RGMII_TX_CTL                   0x0A4 0x304 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__I2C1_SCL                             0x0A4 0x304 0x5A4 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__UART2_DCE_RTS                        0x0A4 0x304 0x5EC 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__UART2_DTE_CTS                        0x0A4 0x304 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06                           0x0A4 0x304 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5                         0x0A8 0x308 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA5__ENET1_TX_ER                          0x0A8 0x308 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA5__I2C1_SDA                             0x0A8 0x308 0x5A8 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA5__UART2_DCE_CTS                        0x0A8 0x308 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA5__UART2_DTE_RTS                        0x0A8 0x308 0x5EC 0x4 0x1
+#define MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07                           0x0A8 0x308 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6                         0x0AC 0x30C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__ENET1_RGMII_RX_CTL                   0x0AC 0x30C 0x588 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__I2C2_SCL                             0x0AC 0x30C 0x5AC 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__UART3_DCE_TX                         0x0AC 0x30C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__UART3_DTE_RX                         0x0AC 0x30C 0x5F8 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08                           0x0AC 0x30C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7                         0x0B0 0x310 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_DATA7__ENET1_RX_ER                          0x0B0 0x310 0x58C 0x1 0x0
+#define MX8MP_IOMUXC_SD1_DATA7__I2C2_SDA                             0x0B0 0x310 0x5B0 0x3 0x0
+#define MX8MP_IOMUXC_SD1_DATA7__UART3_DCE_RX                         0x0B0 0x310 0x5F8 0x4 0x1
+#define MX8MP_IOMUXC_SD1_DATA7__UART3_DTE_TX                         0x0B0 0x310 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09                           0x0B0 0x310 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__USDHC1_RESET_B                     0x0B4 0x314 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__ENET1_TX_CLK                       0x0B4 0x314 0x578 0x1 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__I2C3_SCL                           0x0B4 0x314 0x5B4 0x3 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__UART3_DCE_RTS                      0x0B4 0x314 0x5F4 0x4 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__UART3_DTE_CTS                      0x0B4 0x314 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10                         0x0B4 0x314 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE                       0x0B8 0x318 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD1_STROBE__I2C3_SDA                            0x0B8 0x318 0x5B8 0x3 0x0
+#define MX8MP_IOMUXC_SD1_STROBE__UART3_DCE_CTS                       0x0B8 0x318 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD1_STROBE__UART3_DTE_RTS                       0x0B8 0x318 0x5F4 0x4 0x1
+#define MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11                          0x0B8 0x318 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_CD_B__USDHC2_CD_B                           0x0BC 0x31C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12                            0x0BC 0x31C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                             0x0C0 0x320 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_CLK__ECSPI2_SCLK                            0x0C0 0x320 0x568 0x2 0x0
+#define MX8MP_IOMUXC_SD2_CLK__UART4_DCE_RX                           0x0C0 0x320 0x600 0x3 0x0
+#define MX8MP_IOMUXC_SD2_CLK__UART4_DTE_TX                           0x0C0 0x320 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SD2_CLK__GPIO2_IO13                             0x0C0 0x320 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                             0x0C4 0x324 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_CMD__ECSPI2_MOSI                            0x0C4 0x324 0x570 0x2 0x0
+#define MX8MP_IOMUXC_SD2_CMD__UART4_DCE_TX                           0x0C4 0x324 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SD2_CMD__UART4_DTE_RX                           0x0C4 0x324 0x600 0x3 0x1
+#define MX8MP_IOMUXC_SD2_CMD__AUDIOMIX_PDM_CLK                       0x0C4 0x324 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14                             0x0C4 0x324 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0                         0x0C8 0x328 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_DATA0__I2C4_SDA                             0x0C8 0x328 0x5C0 0x2 0x1
+#define MX8MP_IOMUXC_SD2_DATA0__UART2_DCE_RX                         0x0C8 0x328 0x5F0 0x3 0x2
+#define MX8MP_IOMUXC_SD2_DATA0__UART2_DTE_TX                         0x0C8 0x328 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SD2_DATA0__AUDIOMIX_PDM_BIT_STREAM00            0x0C8 0x328 0x4C0 0x4 0x2
+#define MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15                           0x0C8 0x328 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1                         0x0CC 0x32C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_DATA1__I2C4_SCL                             0x0CC 0x32C 0x5BC 0x2 0x1
+#define MX8MP_IOMUXC_SD2_DATA1__UART2_DCE_TX                         0x0CC 0x32C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SD2_DATA1__UART2_DTE_RX                         0x0CC 0x32C 0x5F0 0x3 0x3
+#define MX8MP_IOMUXC_SD2_DATA1__AUDIOMIX_PDM_BIT_STREAM01            0x0CC 0x32C 0x4C4 0x4 0x2
+#define MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16                           0x0CC 0x32C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2                         0x0D0 0x330 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_DATA2__ECSPI2_SS0                           0x0D0 0x330 0x574 0x2 0x0
+#define MX8MP_IOMUXC_SD2_DATA2__AUDIOMIX_SPDIF1_OUT                  0x0D0 0x330 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SD2_DATA2__AUDIOMIX_PDM_BIT_STREAM02            0x0D0 0x330 0x4C8 0x4 0x2
+#define MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17                           0x0D0 0x330 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3                         0x0D4 0x334 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_DATA3__ECSPI2_MISO                          0x0D4 0x334 0x56C 0x2 0x0
+#define MX8MP_IOMUXC_SD2_DATA3__AUDIOMIX_SPDIF1_IN                   0x0D4 0x334 0x544 0x3 0x1
+#define MX8MP_IOMUXC_SD2_DATA3__AUDIOMIX_PDM_BIT_STREAM03            0x0D4 0x334 0x4CC 0x4 0x2
+#define MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18                           0x0D4 0x334 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_DATA3__SRC_EARLY_RESET                      0x0D4 0x334 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SD2_RESET_B__USDHC2_RESET_B                     0x0D8 0x338 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19                         0x0D8 0x338 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_RESET_B__SRC_SYSTEM_RESET                   0x0D8 0x338 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SD2_WP__USDHC2_WP                               0x0DC 0x33C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SD2_WP__GPIO2_IO20                              0x0DC 0x33C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SD2_WP__CORESIGHT_EVENTI                        0x0DC 0x33C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_ALE__NAND_ALE                              0x0E0 0x340 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK                        0x0E0 0x340 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_ALE__AUDIOMIX_SAI3_TX_BCLK                 0x0E0 0x340 0x4E8 0x2 0x0
+#define MX8MP_IOMUXC_NAND_ALE__ISP_FL_TRIG_0                         0x0E0 0x340 0x5D4 0x3 0x1
+#define MX8MP_IOMUXC_NAND_ALE__UART3_DCE_RX                          0x0E0 0x340 0x5F8 0x4 0x2
+#define MX8MP_IOMUXC_NAND_ALE__UART3_DTE_TX                          0x0E0 0x340 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00                            0x0E0 0x340 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_ALE__CORESIGHT_TRACE_CLK                   0x0E0 0x340 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__NAND_CE0_B                          0x0E4 0x344 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B                     0x0E4 0x344 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__AUDIOMIX_SAI3_TX_DATA00             0x0E4 0x344 0x000 0x2 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__ISP_SHUTTER_TRIG_0                  0x0E4 0x344 0x5DC 0x3 0x1
+#define MX8MP_IOMUXC_NAND_CE0_B__UART3_DCE_TX                        0x0E4 0x344 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__UART3_DTE_RX                        0x0E4 0x344 0x5F8 0x4 0x3
+#define MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01                          0x0E4 0x344 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_CE0_B__CORESIGHT_TRACE_CTL                 0x0E4 0x344 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_CE1_B__NAND_CE1_B                          0x0E8 0x348 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_CE1_B__FLEXSPI_A_SS1_B                     0x0E8 0x348 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE                       0x0E8 0x348 0x630 0x2 0x1
+#define MX8MP_IOMUXC_NAND_CE1_B__I2C4_SCL                            0x0E8 0x348 0x5BC 0x4 0x2
+#define MX8MP_IOMUXC_NAND_CE1_B__GPIO3_IO02                          0x0E8 0x348 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_CE1_B__CORESIGHT_TRACE00                   0x0E8 0x348 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_CE2_B__NAND_CE2_B                          0x0EC 0x34C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_CE2_B__FLEXSPI_B_SS0_B                     0x0EC 0x34C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5                        0x0EC 0x34C 0x624 0x2 0x1
+#define MX8MP_IOMUXC_NAND_CE2_B__I2C4_SDA                            0x0EC 0x34C 0x5C0 0x4 0x2
+#define MX8MP_IOMUXC_NAND_CE2_B__GPIO3_IO03                          0x0EC 0x34C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_CE2_B__CORESIGHT_TRACE01                   0x0EC 0x34C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_CE3_B__NAND_CE3_B                          0x0F0 0x350 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_CE3_B__FLEXSPI_B_SS1_B                     0x0F0 0x350 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6                        0x0F0 0x350 0x628 0x2 0x1
+#define MX8MP_IOMUXC_NAND_CE3_B__I2C3_SDA                            0x0F0 0x350 0x5B8 0x4 0x1
+#define MX8MP_IOMUXC_NAND_CE3_B__GPIO3_IO04                          0x0F0 0x350 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_CE3_B__CORESIGHT_TRACE02                   0x0F0 0x350 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_CLE__NAND_CLE                              0x0F4 0x354 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_CLE__FLEXSPI_B_SCLK                        0x0F4 0x354 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7                          0x0F4 0x354 0x62C 0x2 0x1
+#define MX8MP_IOMUXC_NAND_CLE__UART4_DCE_RX                          0x0F4 0x354 0x600 0x4 0x2
+#define MX8MP_IOMUXC_NAND_CLE__UART4_DTE_TX                          0x0F4 0x354 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_CLE__GPIO3_IO05                            0x0F4 0x354 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_CLE__CORESIGHT_TRACE03                     0x0F4 0x354 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__NAND_DATA00                        0x0F8 0x358 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00                   0x0F8 0x358 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__AUDIOMIX_SAI3_RX_DATA00            0x0F8 0x358 0x4E4 0x2 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__ISP_FLASH_TRIG_0                   0x0F8 0x358 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__UART4_DCE_RX                       0x0F8 0x358 0x600 0x4 0x3
+#define MX8MP_IOMUXC_NAND_DATA00__UART4_DTE_TX                       0x0F8 0x358 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06                         0x0F8 0x358 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA00__CORESIGHT_TRACE04                  0x0F8 0x358 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__NAND_DATA01                        0x0FC 0x35C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01                   0x0FC 0x35C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__AUDIOMIX_SAI3_TX_SYNC              0x0FC 0x35C 0x4EC 0x2 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__ISP_PRELIGHT_TRIG_0                0x0FC 0x35C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__UART4_DCE_TX                       0x0FC 0x35C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__UART4_DTE_RX                       0x0FC 0x35C 0x600 0x4 0x4
+#define MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                         0x0FC 0x35C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA01__CORESIGHT_TRACE05                  0x0FC 0x35C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__NAND_DATA02                        0x100 0x360 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02                   0x100 0x360 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__USDHC3_CD_B                        0x100 0x360 0x608 0x2 0x2
+#define MX8MP_IOMUXC_NAND_DATA02__UART4_DCE_CTS                      0x100 0x360 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__UART4_DTE_RTS                      0x100 0x360 0x5FC 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__I2C4_SDA                           0x100 0x360 0x5C0 0x4 0x3
+#define MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08                         0x100 0x360 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA02__CORESIGHT_TRACE06                  0x100 0x360 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA03__NAND_DATA03                        0x104 0x364 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03                   0x104 0x364 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA03__USDHC3_WP                          0x104 0x364 0x634 0x2 0x2
+#define MX8MP_IOMUXC_NAND_DATA03__UART4_DCE_RTS                      0x104 0x364 0x5FC 0x3 0x1
+#define MX8MP_IOMUXC_NAND_DATA03__UART4_DTE_CTS                      0x104 0x364 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA03__ISP_FL_TRIG_1                      0x104 0x364 0x5D8 0x4 0x1
+#define MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09                         0x104 0x364 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA03__CORESIGHT_TRACE07                  0x104 0x364 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA04__NAND_DATA04                        0x108 0x368 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA04__FLEXSPI_B_DATA00                   0x108 0x368 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0                       0x108 0x368 0x610 0x2 0x1
+#define MX8MP_IOMUXC_NAND_DATA04__FLEXSPI_A_DATA04                   0x108 0x368 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA04__ISP_SHUTTER_TRIG_1                 0x108 0x368 0x5E0 0x4 0x1
+#define MX8MP_IOMUXC_NAND_DATA04__GPIO3_IO10                         0x108 0x368 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA04__CORESIGHT_TRACE08                  0x108 0x368 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__NAND_DATA05                        0x10C 0x36C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__FLEXSPI_B_DATA01                   0x10C 0x36C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1                       0x10C 0x36C 0x614 0x2 0x1
+#define MX8MP_IOMUXC_NAND_DATA05__FLEXSPI_A_DATA05                   0x10C 0x36C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__ISP_FLASH_TRIG_1                   0x10C 0x36C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__GPIO3_IO11                         0x10C 0x36C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA05__CORESIGHT_TRACE09                  0x10C 0x36C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__NAND_DATA06                        0x110 0x370 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__FLEXSPI_B_DATA02                   0x110 0x370 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2                       0x110 0x370 0x618 0x2 0x1
+#define MX8MP_IOMUXC_NAND_DATA06__FLEXSPI_A_DATA06                   0x110 0x370 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__ISP_PRELIGHT_TRIG_1                0x110 0x370 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__GPIO3_IO12                         0x110 0x370 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA06__CORESIGHT_TRACE10                  0x110 0x370 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__NAND_DATA07                        0x114 0x374 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__FLEXSPI_B_DATA03                   0x114 0x374 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3                       0x114 0x374 0x61C 0x2 0x1
+#define MX8MP_IOMUXC_NAND_DATA07__FLEXSPI_A_DATA07                   0x114 0x374 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__ISP_SHUTTER_OPEN_1                 0x114 0x374 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__GPIO3_IO13                         0x114 0x374 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DATA07__CORESIGHT_TRACE11                  0x114 0x374 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_DQS__NAND_DQS                              0x118 0x378 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_DQS__FLEXSPI_A_DQS                         0x118 0x378 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_DQS__AUDIOMIX_SAI3_MCLK                    0x118 0x378 0x4E0 0x2 0x0
+#define MX8MP_IOMUXC_NAND_DQS__ISP_SHUTTER_OPEN_0                    0x118 0x378 0x000 0x3 0x0
+#define MX8MP_IOMUXC_NAND_DQS__I2C3_SCL                              0x118 0x378 0x5B4 0x4 0x1
+#define MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14                            0x118 0x378 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_DQS__CORESIGHT_TRACE12                     0x118 0x378 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_RE_B__NAND_RE_B                            0x11C 0x37C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_RE_B__FLEXSPI_B_DQS                        0x11C 0x37C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4                         0x11C 0x37C 0x620 0x2 0x1
+#define MX8MP_IOMUXC_NAND_RE_B__UART4_DCE_TX                         0x11C 0x37C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_NAND_RE_B__UART4_DTE_RX                         0x11C 0x37C 0x600 0x4 0x5
+#define MX8MP_IOMUXC_NAND_RE_B__GPIO3_IO15                           0x11C 0x37C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_RE_B__CORESIGHT_TRACE13                    0x11C 0x37C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_READY_B__NAND_READY_B                      0x120 0x380 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B                    0x120 0x380 0x000 0x2 0x0
+#define MX8MP_IOMUXC_NAND_READY_B__I2C3_SCL                          0x120 0x380 0x5B4 0x4 0x2
+#define MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16                        0x120 0x380 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_READY_B__CORESIGHT_TRACE14                 0x120 0x380 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_WE_B__NAND_WE_B                            0x124 0x384 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK                           0x124 0x384 0x604 0x2 0x1
+#define MX8MP_IOMUXC_NAND_WE_B__I2C3_SDA                             0x124 0x384 0x5B8 0x4 0x2
+#define MX8MP_IOMUXC_NAND_WE_B__GPIO3_IO17                           0x124 0x384 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_WE_B__CORESIGHT_TRACE15                    0x124 0x384 0x000 0x6 0x0
+#define MX8MP_IOMUXC_NAND_WP_B__NAND_WP_B                            0x128 0x388 0x000 0x0 0x0
+#define MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD                           0x128 0x388 0x60C 0x2 0x1
+#define MX8MP_IOMUXC_NAND_WP_B__I2C4_SCL                             0x128 0x388 0x5BC 0x4 0x3
+#define MX8MP_IOMUXC_NAND_WP_B__GPIO3_IO18                           0x128 0x388 0x000 0x5 0x0
+#define MX8MP_IOMUXC_NAND_WP_B__CORESIGHT_EVENTO                     0x128 0x388 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SAI5_RXFS__AUDIOMIX_SAI5_RX_SYNC                0x12C 0x38C 0x508 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXFS__AUDIOMIX_SAI1_TX_DATA00              0x12C 0x38C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXFS__PWM4_OUT                             0x12C 0x38C 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI5_RXFS__I2C6_SCL                             0x12C 0x38C 0x5CC 0x3 0x1
+#define MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19                           0x12C 0x38C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXC__AUDIOMIX_SAI5_RX_BCLK                 0x130 0x390 0x4F4 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXC__AUDIOMIX_SAI1_TX_DATA01               0x130 0x390 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXC__PWM3_OUT                              0x130 0x390 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA                              0x130 0x390 0x5D0 0x3 0x1
+#define MX8MP_IOMUXC_SAI5_RXC__AUDIOMIX_PDM_CLK                      0x130 0x390 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20                            0x130 0x390 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXD0__AUDIOMIX_SAI5_RX_DATA00              0x134 0x394 0x4F8 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXD0__AUDIOMIX_SAI1_TX_DATA02              0x134 0x394 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXD0__PWM2_OUT                             0x134 0x394 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI5_RXD0__I2C5_SCL                             0x134 0x394 0x5C4 0x3 0x1
+#define MX8MP_IOMUXC_SAI5_RXD0__AUDIOMIX_PDM_BIT_STREAM00            0x134 0x394 0x4C0 0x4 0x3
+#define MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21                           0x134 0x394 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI5_RX_DATA01              0x138 0x398 0x4FC 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI1_TX_DATA03              0x138 0x398 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI1_TX_SYNC                0x138 0x398 0x4D8 0x2 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI5_TX_SYNC                0x138 0x398 0x510 0x3 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_PDM_BIT_STREAM01            0x138 0x398 0x4C4 0x4 0x3
+#define MX8MP_IOMUXC_SAI5_RXD1__GPIO3_IO22                           0x138 0x398 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXD1__CAN1_TX                              0x138 0x398 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI5_RX_DATA02              0x13C 0x39C 0x500 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI1_TX_DATA04              0x13C 0x39C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI1_TX_SYNC                0x13C 0x39C 0x4D8 0x2 0x1
+#define MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI5_TX_BCLK                0x13C 0x39C 0x50C 0x3 0x0
+#define MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_PDM_BIT_STREAM02            0x13C 0x39C 0x4C8 0x4 0x3
+#define MX8MP_IOMUXC_SAI5_RXD2__GPIO3_IO23                           0x13C 0x39C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXD2__CAN1_RX                              0x13C 0x39C 0x54C 0x6 0x0
+#define MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI5_RX_DATA03              0x140 0x3A0 0x504 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI1_TX_DATA05              0x140 0x3A0 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI1_TX_SYNC                0x140 0x3A0 0x4D8 0x2 0x2
+#define MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI5_TX_DATA00              0x140 0x3A0 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_PDM_BIT_STREAM03            0x140 0x3A0 0x4CC 0x4 0x3
+#define MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24                           0x140 0x3A0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX                              0x140 0x3A0 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SAI5_MCLK__AUDIOMIX_SAI5_MCLK                   0x144 0x3A4 0x4F0 0x0 0x0
+#define MX8MP_IOMUXC_SAI5_MCLK__AUDIOMIX_SAI1_TX_BCLK                0x144 0x3A4 0x4D4 0x1 0x0
+#define MX8MP_IOMUXC_SAI5_MCLK__PWM1_OUT                             0x144 0x3A4 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI5_MCLK__I2C5_SDA                             0x144 0x3A4 0x5C8 0x3 0x1
+#define MX8MP_IOMUXC_SAI5_MCLK__GPIO3_IO25                           0x144 0x3A4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX                              0x144 0x3A4 0x550 0x6 0x0
+#define MX8MP_IOMUXC_SAI1_RXFS__AUDIOMIX_SAI1_RX_SYNC                0x148 0x3A8 0x4D0 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN                 0x148 0x3A8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00                           0x148 0x3A8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXC__AUDIOMIX_SAI1_RX_BCLK                 0x14C 0x3AC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXC__AUDIOMIX_PDM_CLK                      0x14C 0x3AC 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT                 0x14C 0x3AC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01                            0x14C 0x3AC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD0__AUDIOMIX_SAI1_RX_DATA00              0x150 0x3B0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD0__AUDIOMIX_SAI1_TX_DATA01              0x150 0x3B0 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI1_RXD0__AUDIOMIX_PDM_BIT_STREAM00            0x150 0x3B0 0x4C0 0x3 0x4
+#define MX8MP_IOMUXC_SAI1_RXD0__ENET1_1588_EVENT1_IN                 0x150 0x3B0 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02                           0x150 0x3B0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD1__AUDIOMIX_SAI1_RX_DATA01              0x154 0x3B4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD1__AUDIOMIX_PDM_BIT_STREAM01            0x154 0x3B4 0x4C4 0x3 0x4
+#define MX8MP_IOMUXC_SAI1_RXD1__ENET1_1588_EVENT1_OUT                0x154 0x3B4 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03                           0x154 0x3B4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD2__AUDIOMIX_SAI1_RX_DATA02              0x158 0x3B8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD2__AUDIOMIX_PDM_BIT_STREAM02            0x158 0x3B8 0x4C8 0x3 0x4
+#define MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC                            0x158 0x3B8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXD2__GPIO4_IO04                           0x158 0x3B8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD3__AUDIOMIX_SAI1_RX_DATA03              0x15C 0x3BC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD3__AUDIOMIX_PDM_BIT_STREAM03            0x15C 0x3BC 0x4CC 0x3 0x4
+#define MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO                           0x15C 0x3BC 0x57C 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_RXD3__GPIO4_IO05                           0x15C 0x3BC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD4__AUDIOMIX_SAI1_RX_DATA04              0x160 0x3C0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD4__AUDIOMIX_SAI6_TX_BCLK                0x160 0x3C0 0x524 0x1 0x1
+#define MX8MP_IOMUXC_SAI1_RXD4__AUDIOMIX_SAI6_RX_BCLK                0x160 0x3C0 0x518 0x2 0x1
+#define MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0                      0x160 0x3C0 0x580 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_RXD4__GPIO4_IO06                           0x160 0x3C0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD5__AUDIOMIX_SAI1_RX_DATA05              0x164 0x3C4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD5__AUDIOMIX_SAI6_TX_DATA00              0x164 0x3C4 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI1_RXD5__AUDIOMIX_SAI6_RX_DATA00              0x164 0x3C4 0x51C 0x2 0x1
+#define MX8MP_IOMUXC_SAI1_RXD5__AUDIOMIX_SAI1_RX_SYNC                0x164 0x3C4 0x4D0 0x3 0x1
+#define MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1                      0x164 0x3C4 0x584 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_RXD5__GPIO4_IO07                           0x164 0x3C4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD6__AUDIOMIX_SAI1_RX_DATA06              0x168 0x3C8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD6__AUDIOMIX_SAI6_TX_SYNC                0x168 0x3C8 0x528 0x1 0x1
+#define MX8MP_IOMUXC_SAI1_RXD6__AUDIOMIX_SAI6_RX_SYNC                0x168 0x3C8 0x520 0x2 0x1
+#define MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2                      0x168 0x3C8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXD6__GPIO4_IO08                           0x168 0x3C8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_RXD7__AUDIOMIX_SAI1_RX_DATA07              0x16C 0x3CC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_RXD7__AUDIOMIX_SAI6_MCLK                   0x16C 0x3CC 0x514 0x1 0x1
+#define MX8MP_IOMUXC_SAI1_RXD7__AUDIOMIX_SAI1_TX_SYNC                0x16C 0x3CC 0x4D8 0x2 0x3
+#define MX8MP_IOMUXC_SAI1_RXD7__AUDIOMIX_SAI1_TX_DATA04              0x16C 0x3CC 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3                      0x16C 0x3CC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_RXD7__GPIO4_IO09                           0x16C 0x3CC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXFS__AUDIOMIX_SAI1_TX_SYNC                0x170 0x3D0 0x4D8 0x0 0x4
+#define MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL                   0x170 0x3D0 0x588 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_TXFS__GPIO4_IO10                           0x170 0x3D0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXC__AUDIOMIX_SAI1_TX_BCLK                 0x174 0x3D4 0x4D4 0x0 0x1
+#define MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC                       0x174 0x3D4 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXC__GPIO4_IO11                            0x174 0x3D4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD0__AUDIOMIX_SAI1_TX_DATA00              0x178 0x3D8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0                      0x178 0x3D8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD0__GPIO4_IO12                           0x178 0x3D8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD1__AUDIOMIX_SAI1_TX_DATA01              0x17C 0x3DC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1                      0x17C 0x3DC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD1__GPIO4_IO13                           0x17C 0x3DC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD2__AUDIOMIX_SAI1_TX_DATA02              0x180 0x3E0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2                      0x180 0x3E0 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD2__GPIO4_IO14                           0x180 0x3E0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD3__AUDIOMIX_SAI1_TX_DATA03              0x184 0x3E4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3                      0x184 0x3E4 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD3__GPIO4_IO15                           0x184 0x3E4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD4__AUDIOMIX_SAI1_TX_DATA04              0x188 0x3E8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD4__AUDIOMIX_SAI6_RX_BCLK                0x188 0x3E8 0x518 0x1 0x2
+#define MX8MP_IOMUXC_SAI1_TXD4__AUDIOMIX_SAI6_TX_BCLK                0x188 0x3E8 0x524 0x2 0x2
+#define MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL                   0x188 0x3E8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD4__GPIO4_IO16                           0x188 0x3E8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD5__AUDIOMIX_SAI1_TX_DATA05              0x18C 0x3EC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD5__AUDIOMIX_SAI6_RX_DATA00              0x18C 0x3EC 0x51C 0x1 0x2
+#define MX8MP_IOMUXC_SAI1_TXD5__AUDIOMIX_SAI6_TX_DATA00              0x18C 0x3EC 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC                      0x18C 0x3EC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD5__GPIO4_IO17                           0x18C 0x3EC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD6__AUDIOMIX_SAI1_TX_DATA06              0x190 0x3F0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD6__AUDIOMIX_SAI6_RX_SYNC                0x190 0x3F0 0x520 0x1 0x2
+#define MX8MP_IOMUXC_SAI1_TXD6__AUDIOMIX_SAI6_TX_SYNC                0x190 0x3F0 0x528 0x2 0x2
+#define MX8MP_IOMUXC_SAI1_TXD6__ENET1_RX_ER                          0x190 0x3F0 0x58C 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18                           0x190 0x3F0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_TXD7__AUDIOMIX_SAI1_TX_DATA07              0x194 0x3F4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_TXD7__AUDIOMIX_SAI6_MCLK                   0x194 0x3F4 0x514 0x1 0x2
+#define MX8MP_IOMUXC_SAI1_TXD7__AUDIOMIX_PDM_CLK                     0x194 0x3F4 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI1_TXD7__ENET1_TX_ER                          0x194 0x3F4 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19                           0x194 0x3F4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI1_MCLK__AUDIOMIX_SAI1_MCLK                   0x198 0x3F8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI1_MCLK__AUDIOMIX_SAI1_TX_BCLK                0x198 0x3F8 0x4D4 0x2 0x2
+#define MX8MP_IOMUXC_SAI1_MCLK__ENET1_TX_CLK                         0x198 0x3F8 0x578 0x4 0x1
+#define MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20                           0x198 0x3F8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__AUDIOMIX_SAI2_RX_SYNC                0x19C 0x3FC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__AUDIOMIX_SAI5_TX_SYNC                0x19C 0x3FC 0x510 0x1 0x2
+#define MX8MP_IOMUXC_SAI2_RXFS__AUDIOMIX_SAI5_TX_DATA01              0x19C 0x3FC 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__AUDIOMIX_SAI2_RX_DATA01              0x19C 0x3FC 0x4DC 0x3 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__UART1_DCE_TX                         0x19C 0x3FC 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__UART1_DTE_RX                         0x19C 0x3FC 0x5E8 0x4 0x2
+#define MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21                           0x19C 0x3FC 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_RXFS__AUDIOMIX_PDM_BIT_STREAM02            0x19C 0x3FC 0x4C8 0x6 0x5
+#define MX8MP_IOMUXC_SAI2_RXC__AUDIOMIX_SAI2_RX_BCLK                 0x1A0 0x400 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_RXC__AUDIOMIX_SAI5_TX_BCLK                 0x1A0 0x400 0x50C 0x1 0x2
+#define MX8MP_IOMUXC_SAI2_RXC__CAN1_TX                               0x1A0 0x400 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI2_RXC__UART1_DCE_RX                          0x1A0 0x400 0x5E8 0x4 0x3
+#define MX8MP_IOMUXC_SAI2_RXC__UART1_DTE_TX                          0x1A0 0x400 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                            0x1A0 0x400 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_RXC__AUDIOMIX_PDM_BIT_STREAM01             0x1A0 0x400 0x4C4 0x6 0x5
+#define MX8MP_IOMUXC_SAI2_RXD0__AUDIOMIX_SAI2_RX_DATA00              0x1A4 0x404 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__AUDIOMIX_SAI5_TX_DATA00              0x1A4 0x404 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__ENET_QOS_1588_EVENT2_OUT             0x1A4 0x404 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__AUDIOMIX_SAI2_TX_DATA01              0x1A4 0x404 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__UART1_DCE_RTS                        0x1A4 0x404 0x5E4 0x4 0x2
+#define MX8MP_IOMUXC_SAI2_RXD0__UART1_DTE_CTS                        0x1A4 0x404 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__GPIO4_IO23                           0x1A4 0x404 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_RXD0__AUDIOMIX_PDM_BIT_STREAM03            0x1A4 0x404 0x4CC 0x6 0x5
+#define MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI2_TX_SYNC                0x1A8 0x408 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI5_TX_DATA01              0x1A8 0x408 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__ENET_QOS_1588_EVENT3_OUT             0x1A8 0x408 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI2_TX_DATA01              0x1A8 0x408 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__UART1_DCE_CTS                        0x1A8 0x408 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__UART1_DTE_RTS                        0x1A8 0x408 0x5E4 0x4 0x3
+#define MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24                           0x1A8 0x408 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_PDM_BIT_STREAM02            0x1A8 0x408 0x4C8 0x6 0x6
+#define MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_SAI2_TX_BCLK                 0x1AC 0x40C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_SAI5_TX_DATA02               0x1AC 0x40C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI2_TXC__CAN1_RX                               0x1AC 0x40C 0x54C 0x3 0x1
+#define MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25                            0x1AC 0x40C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_PDM_BIT_STREAM01             0x1AC 0x40C 0x4C4 0x6 0x6
+#define MX8MP_IOMUXC_SAI2_TXD0__AUDIOMIX_SAI2_TX_DATA00              0x1B0 0x410 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_TXD0__AUDIOMIX_SAI5_TX_DATA03              0x1B0 0x410 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI2_TXD0__ENET_QOS_1588_EVENT2_IN              0x1B0 0x410 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI2_TXD0__CAN2_TX                              0x1B0 0x410 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI2_TXD0__ENET_QOS_1588_EVENT2_AUX_IN          0x1B0 0x410 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_TXD0__GPIO4_IO26                           0x1B0 0x410 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_MCLK__AUDIOMIX_SAI2_MCLK                   0x1B4 0x414 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI2_MCLK__AUDIOMIX_SAI5_MCLK                   0x1B4 0x414 0x4F0 0x1 0x2
+#define MX8MP_IOMUXC_SAI2_MCLK__ENET_QOS_1588_EVENT3_IN              0x1B4 0x414 0x000 0x2 0x0
+#define MX8MP_IOMUXC_SAI2_MCLK__CAN2_RX                              0x1B4 0x414 0x550 0x3 0x1
+#define MX8MP_IOMUXC_SAI2_MCLK__ENET_QOS_1588_EVENT3_AUX_IN          0x1B4 0x414 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27                           0x1B4 0x414 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI2_MCLK__AUDIOMIX_SAI3_MCLK                   0x1B4 0x414 0x4E0 0x6 0x1
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_SYNC                0x1B8 0x418 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI2_RX_DATA01              0x1B8 0x418 0x4DC 0x1 0x1
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI5_RX_SYNC                0x1B8 0x418 0x508 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_DATA01              0x1B8 0x418 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SPDIF1_IN                   0x1B8 0x418 0x544 0x4 0x2
+#define MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28                           0x1B8 0x418 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00            0x1B8 0x418 0x4C0 0x6 0x5
+#define MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI3_RX_BCLK                 0x1BC 0x41C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI2_RX_DATA02               0x1BC 0x41C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_SAI5_RX_BCLK                 0x1BC 0x41C 0x4F4 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_RXC__GPT1_CLK                              0x1BC 0x41C 0x59C 0x3 0x0
+#define MX8MP_IOMUXC_SAI3_RXC__UART2_DCE_CTS                         0x1BC 0x41C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_RXC__UART2_DTE_RTS                         0x1BC 0x41C 0x5EC 0x4 0x2
+#define MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29                            0x1BC 0x41C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_RXC__AUDIOMIX_PDM_CLK                      0x1BC 0x41C 0x000 0x6 0x0
+#define MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00               0x1C0 0x420 0x4E4 0x0 0x1
+#define MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI2_RX_DATA03               0x1C0 0x420 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI5_RX_DATA00               0x1C0 0x420 0x4F8 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_RXD__UART2_DCE_RTS                         0x1C0 0x420 0x5EC 0x4 0x3
+#define MX8MP_IOMUXC_SAI3_RXD__UART2_DTE_CTS                         0x1C0 0x420 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30                            0x1C0 0x420 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_PDM_BIT_STREAM01             0x1C0 0x420 0x4C4 0x6 0x7
+#define MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC                0x1C4 0x424 0x4EC 0x0 0x1
+#define MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI2_TX_DATA01              0x1C4 0x424 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI5_RX_DATA01              0x1C4 0x424 0x4FC 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_DATA01              0x1C4 0x424 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SAI3_TXFS__UART2_DCE_RX                         0x1C4 0x424 0x5F0 0x4 0x4
+#define MX8MP_IOMUXC_SAI3_TXFS__UART2_DTE_TX                         0x1C4 0x424 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31                           0x1C4 0x424 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_PDM_BIT_STREAM03            0x1C4 0x424 0x4CC 0x6 0x6
+#define MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK                 0x1C8 0x428 0x4E8 0x0 0x1
+#define MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI2_TX_DATA02               0x1C8 0x428 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI5_RX_DATA02               0x1C8 0x428 0x500 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_TXC__GPT1_CAPTURE1                         0x1C8 0x428 0x594 0x3 0x0
+#define MX8MP_IOMUXC_SAI3_TXC__UART2_DCE_TX                          0x1C8 0x428 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_TXC__UART2_DTE_RX                          0x1C8 0x428 0x5F0 0x4 0x5
+#define MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00                            0x1C8 0x428 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_PDM_BIT_STREAM02             0x1C8 0x428 0x4C8 0x6 0x7
+#define MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00               0x1CC 0x42C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI2_TX_DATA03               0x1CC 0x42C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI5_RX_DATA03               0x1CC 0x42C 0x504 0x2 0x2
+#define MX8MP_IOMUXC_SAI3_TXD__GPT1_CAPTURE2                         0x1CC 0x42C 0x598 0x3 0x0
+#define MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SPDIF1_EXT_CLK               0x1CC 0x42C 0x548 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01                            0x1CC 0x42C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK                   0x1D0 0x430 0x4E0 0x0 0x2
+#define MX8MP_IOMUXC_SAI3_MCLK__PWM4_OUT                             0x1D0 0x430 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI5_MCLK                   0x1D0 0x430 0x4F0 0x2 0x3
+#define MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SPDIF1_OUT                  0x1D0 0x430 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02                           0x1D0 0x430 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SPDIF1_IN                   0x1D0 0x430 0x544 0x6 0x3
+#define MX8MP_IOMUXC_SPDIF_TX__AUDIOMIX_SPDIF1_OUT                   0x1D4 0x434 0x000 0x0 0x0
+#define MX8MP_IOMUXC_SPDIF_TX__PWM3_OUT                              0x1D4 0x434 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL                              0x1D4 0x434 0x5C4 0x2 0x2
+#define MX8MP_IOMUXC_SPDIF_TX__GPT1_COMPARE1                         0x1D4 0x434 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SPDIF_TX__CAN1_TX                               0x1D4 0x434 0x000 0x4 0x0
+#define MX8MP_IOMUXC_SPDIF_TX__GPIO5_IO03                            0x1D4 0x434 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SPDIF_RX__AUDIOMIX_SPDIF1_IN                    0x1D8 0x438 0x544 0x0 0x4
+#define MX8MP_IOMUXC_SPDIF_RX__PWM2_OUT                              0x1D8 0x438 0x000 0x1 0x0
+#define MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA                              0x1D8 0x438 0x5C8 0x2 0x2
+#define MX8MP_IOMUXC_SPDIF_RX__GPT1_COMPARE2                         0x1D8 0x438 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SPDIF_RX__CAN1_RX                               0x1D8 0x438 0x54C 0x4 0x2
+#define MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04                            0x1D8 0x438 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SPDIF_EXT_CLK__GPT1_COMPARE3                    0x1DC 0x43C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05                       0x1DC 0x43C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_SPDIF_EXT_CLK__AUDIOMIX_SPDIF1_EXT_CLK          0x1DC 0x43C 0x548 0x0 0x1
+#define MX8MP_IOMUXC_SPDIF_EXT_CLK__PWM1_OUT                         0x1DC 0x43C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK                        0x1E0 0x440 0x558 0x0 0x0
+#define MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX                       0x1E0 0x440 0x5F8 0x1 0x4
+#define MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DTE_TX                       0x1E0 0x440 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI1_SCLK__I2C1_SCL                           0x1E0 0x440 0x5A4 0x2 0x1
+#define MX8MP_IOMUXC_ECSPI1_SCLK__AUDIOMIX_SAI7_RX_SYNC              0x1E0 0x440 0x538 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI1_SCLK__GPIO5_IO06                         0x1E0 0x440 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI                        0x1E4 0x444 0x560 0x0 0x0
+#define MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX                       0x1E4 0x444 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DTE_RX                       0x1E4 0x444 0x5F8 0x1 0x5
+#define MX8MP_IOMUXC_ECSPI1_MOSI__I2C1_SDA                           0x1E4 0x444 0x5A8 0x2 0x1
+#define MX8MP_IOMUXC_ECSPI1_MOSI__AUDIOMIX_SAI7_RX_BCLK              0x1E4 0x444 0x530 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI1_MOSI__GPIO5_IO07                         0x1E4 0x444 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO                        0x1E8 0x448 0x55C 0x0 0x0
+#define MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS                      0x1E8 0x448 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI1_MISO__UART3_DTE_RTS                      0x1E8 0x448 0x5F4 0x1 0x2
+#define MX8MP_IOMUXC_ECSPI1_MISO__I2C2_SCL                           0x1E8 0x448 0x5AC 0x2 0x1
+#define MX8MP_IOMUXC_ECSPI1_MISO__AUDIOMIX_SAI7_RX_DATA00            0x1E8 0x448 0x534 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08                         0x1E8 0x448 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI1_SS0__ECSPI1_SS0                          0x1EC 0x44C 0x564 0x0 0x0
+#define MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS                       0x1EC 0x44C 0x5F4 0x1 0x3
+#define MX8MP_IOMUXC_ECSPI1_SS0__UART3_DTE_CTS                       0x1EC 0x44C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI1_SS0__I2C2_SDA                            0x1EC 0x44C 0x5B0 0x2 0x1
+#define MX8MP_IOMUXC_ECSPI1_SS0__AUDIOMIX_SAI7_TX_SYNC               0x1EC 0x44C 0x540 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09                          0x1EC 0x44C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK                        0x1F0 0x450 0x568 0x0 0x1
+#define MX8MP_IOMUXC_ECSPI2_SCLK__UART4_DCE_RX                       0x1F0 0x450 0x600 0x1 0x6
+#define MX8MP_IOMUXC_ECSPI2_SCLK__UART4_DTE_TX                       0x1F0 0x450 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI2_SCLK__I2C3_SCL                           0x1F0 0x450 0x5B4 0x2 0x3
+#define MX8MP_IOMUXC_ECSPI2_SCLK__AUDIOMIX_SAI7_TX_BCLK              0x1F0 0x450 0x53C 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI2_SCLK__GPIO5_IO10                         0x1F0 0x450 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI                        0x1F4 0x454 0x570 0x0 0x1
+#define MX8MP_IOMUXC_ECSPI2_MOSI__UART4_DCE_TX                       0x1F4 0x454 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI2_MOSI__UART4_DTE_RX                       0x1F4 0x454 0x600 0x1 0x7
+#define MX8MP_IOMUXC_ECSPI2_MOSI__I2C3_SDA                           0x1F4 0x454 0x5B8 0x2 0x3
+#define MX8MP_IOMUXC_ECSPI2_MOSI__AUDIOMIX_SAI7_TX_DATA00            0x1F4 0x454 0x000 0x3 0x0
+#define MX8MP_IOMUXC_ECSPI2_MOSI__GPIO5_IO11                         0x1F4 0x454 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI2_MISO__GPIO5_IO12                         0x1F8 0x458 0x000 0x5 0x0
+#define MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO                        0x1F8 0x458 0x56C 0x0 0x1
+#define MX8MP_IOMUXC_ECSPI2_MISO__UART4_DCE_CTS                      0x1F8 0x458 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI2_MISO__UART4_DTE_RTS                      0x1F8 0x458 0x5FC 0x1 0x2
+#define MX8MP_IOMUXC_ECSPI2_MISO__I2C4_SCL                           0x1F8 0x458 0x5BC 0x2 0x4
+#define MX8MP_IOMUXC_ECSPI2_MISO__AUDIOMIX_SAI7_MCLK                 0x1F8 0x458 0x52C 0x3 0x1
+#define MX8MP_IOMUXC_ECSPI2_MISO__CCM_CLKO1                          0x1F8 0x458 0x000 0x4 0x0
+#define MX8MP_IOMUXC_ECSPI2_SS0__ECSPI2_SS0                          0x1FC 0x45C 0x574 0x0 0x1
+#define MX8MP_IOMUXC_ECSPI2_SS0__UART4_DCE_RTS                       0x1FC 0x45C 0x5FC 0x1 0x3
+#define MX8MP_IOMUXC_ECSPI2_SS0__UART4_DTE_CTS                       0x1FC 0x45C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_ECSPI2_SS0__I2C4_SDA                            0x1FC 0x45C 0x5C0 0x2 0x4
+#define MX8MP_IOMUXC_ECSPI2_SS0__CCM_CLKO2                           0x1FC 0x45C 0x000 0x4 0x0
+#define MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13                          0x1FC 0x45C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL                              0x200 0x460 0x5A4 0x0 0x2
+#define MX8MP_IOMUXC_I2C1_SCL__ENET_QOS_MDC                          0x200 0x460 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C1_SCL__ECSPI1_SCLK                           0x200 0x460 0x558 0x3 0x1
+#define MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14                            0x200 0x460 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA                              0x204 0x464 0x5A8 0x0 0x2
+#define MX8MP_IOMUXC_I2C1_SDA__ENET_QOS_MDIO                         0x204 0x464 0x590 0x1 0x2
+#define MX8MP_IOMUXC_I2C1_SDA__ECSPI1_MOSI                           0x204 0x464 0x560 0x3 0x1
+#define MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15                            0x204 0x464 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL                              0x208 0x468 0x5AC 0x0 0x2
+#define MX8MP_IOMUXC_I2C2_SCL__ENET_QOS_1588_EVENT1_IN               0x208 0x468 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C2_SCL__USDHC3_CD_B                           0x208 0x468 0x608 0x2 0x3
+#define MX8MP_IOMUXC_I2C2_SCL__ECSPI1_MISO                           0x208 0x468 0x55C 0x3 0x1
+#define MX8MP_IOMUXC_I2C2_SCL__ENET_QOS_1588_EVENT1_AUX_IN           0x208 0x468 0x000 0x4 0x0
+#define MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16                            0x208 0x468 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA                              0x20C 0x46C 0x5B0 0x0 0x2
+#define MX8MP_IOMUXC_I2C2_SDA__ENET_QOS_1588_EVENT1_OUT              0x20C 0x46C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C2_SDA__USDHC3_WP                             0x20C 0x46C 0x634 0x2 0x3
+#define MX8MP_IOMUXC_I2C2_SDA__ECSPI1_SS0                            0x20C 0x46C 0x564 0x3 0x1
+#define MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17                            0x20C 0x46C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                              0x210 0x470 0x5B4 0x0 0x4
+#define MX8MP_IOMUXC_I2C3_SCL__PWM4_OUT                              0x210 0x470 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C3_SCL__GPT2_CLK                              0x210 0x470 0x000 0x2 0x0
+#define MX8MP_IOMUXC_I2C3_SCL__ECSPI2_SCLK                           0x210 0x470 0x568 0x3 0x2
+#define MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18                            0x210 0x470 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                              0x214 0x474 0x5B8 0x0 0x4
+#define MX8MP_IOMUXC_I2C3_SDA__PWM3_OUT                              0x214 0x474 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C3_SDA__GPT3_CLK                              0x214 0x474 0x000 0x2 0x0
+#define MX8MP_IOMUXC_I2C3_SDA__ECSPI2_MOSI                           0x214 0x474 0x570 0x3 0x2
+#define MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19                            0x214 0x474 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL                              0x218 0x478 0x5BC 0x0 0x5
+#define MX8MP_IOMUXC_I2C4_SCL__PWM2_OUT                              0x218 0x478 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C4_SCL__PCIE_CLKREQ_B                         0x218 0x478 0x5A0 0x2 0x0
+#define MX8MP_IOMUXC_I2C4_SCL__ECSPI2_MISO                           0x218 0x478 0x56C 0x3 0x2
+#define MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20                            0x218 0x478 0x000 0x5 0x0
+#define MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA                              0x21C 0x47C 0x5C0 0x0 0x5
+#define MX8MP_IOMUXC_I2C4_SDA__PWM1_OUT                              0x21C 0x47C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_I2C4_SDA__ECSPI2_SS0                            0x21C 0x47C 0x574 0x3 0x2
+#define MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21                            0x21C 0x47C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX                         0x220 0x480 0x5E8 0x0 0x4
+#define MX8MP_IOMUXC_UART1_RXD__UART1_DTE_TX                         0x220 0x480 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART1_RXD__ECSPI3_SCLK                          0x220 0x480 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART1_RXD__GPIO5_IO22                           0x220 0x480 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX                         0x224 0x484 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART1_TXD__UART1_DTE_RX                         0x224 0x484 0x5E8 0x0 0x5
+#define MX8MP_IOMUXC_UART1_TXD__ECSPI3_MOSI                          0x224 0x484 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART1_TXD__GPIO5_IO23                           0x224 0x484 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX                         0x228 0x488 0x5F0 0x0 0x6
+#define MX8MP_IOMUXC_UART2_RXD__UART2_DTE_TX                         0x228 0x488 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART2_RXD__ECSPI3_MISO                          0x228 0x488 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART2_RXD__GPT1_COMPARE3                        0x228 0x488 0x000 0x3 0x0
+#define MX8MP_IOMUXC_UART2_RXD__GPIO5_IO24                           0x228 0x488 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX                         0x22C 0x48C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART2_TXD__UART2_DTE_RX                         0x22C 0x48C 0x5F0 0x0 0x7
+#define MX8MP_IOMUXC_UART2_TXD__ECSPI3_SS0                           0x22C 0x48C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART2_TXD__GPT1_COMPARE2                        0x22C 0x48C 0x000 0x3 0x0
+#define MX8MP_IOMUXC_UART2_TXD__GPIO5_IO25                           0x22C 0x48C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX                         0x230 0x490 0x5F8 0x0 0x6
+#define MX8MP_IOMUXC_UART3_RXD__UART3_DTE_TX                         0x230 0x490 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART3_RXD__UART1_DCE_CTS                        0x230 0x490 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART3_RXD__UART1_DTE_RTS                        0x230 0x490 0x5E4 0x1 0x4
+#define MX8MP_IOMUXC_UART3_RXD__USDHC3_RESET_B                       0x230 0x490 0x000 0x2 0x0
+#define MX8MP_IOMUXC_UART3_RXD__GPT1_CAPTURE2                        0x230 0x490 0x598 0x3 0x1
+#define MX8MP_IOMUXC_UART3_RXD__CAN2_TX                              0x230 0x490 0x000 0x4 0x0
+#define MX8MP_IOMUXC_UART3_RXD__GPIO5_IO26                           0x230 0x490 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX                         0x234 0x494 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART3_TXD__UART3_DTE_RX                         0x234 0x494 0x5F8 0x0 0x7
+#define MX8MP_IOMUXC_UART3_TXD__UART1_DCE_RTS                        0x234 0x494 0x5E4 0x1 0x5
+#define MX8MP_IOMUXC_UART3_TXD__UART1_DTE_CTS                        0x234 0x494 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART3_TXD__USDHC3_VSELECT                       0x234 0x494 0x000 0x2 0x0
+#define MX8MP_IOMUXC_UART3_TXD__GPT1_CLK                             0x234 0x494 0x59C 0x3 0x1
+#define MX8MP_IOMUXC_UART3_TXD__CAN2_RX                              0x234 0x494 0x550 0x4 0x2
+#define MX8MP_IOMUXC_UART3_TXD__GPIO5_IO27                           0x234 0x494 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX                         0x238 0x498 0x600 0x0 0x8
+#define MX8MP_IOMUXC_UART4_RXD__UART4_DTE_TX                         0x238 0x498 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART4_RXD__UART2_DCE_CTS                        0x238 0x498 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART4_RXD__UART2_DTE_RTS                        0x238 0x498 0x5EC 0x1 0x4
+#define MX8MP_IOMUXC_UART4_RXD__PCIE_CLKREQ_B                        0x238 0x498 0x5A0 0x2 0x1
+#define MX8MP_IOMUXC_UART4_RXD__GPT1_COMPARE1                        0x238 0x498 0x000 0x3 0x0
+#define MX8MP_IOMUXC_UART4_RXD__I2C6_SCL                             0x238 0x498 0x5CC 0x4 0x2
+#define MX8MP_IOMUXC_UART4_RXD__GPIO5_IO28                           0x238 0x498 0x000 0x5 0x0
+#define MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX                         0x23C 0x49C 0x000 0x0 0x0
+#define MX8MP_IOMUXC_UART4_TXD__UART4_DTE_RX                         0x23C 0x49C 0x600 0x0 0x9
+#define MX8MP_IOMUXC_UART4_TXD__UART2_DCE_RTS                        0x23C 0x49C 0x5EC 0x1 0x5
+#define MX8MP_IOMUXC_UART4_TXD__UART2_DTE_CTS                        0x23C 0x49C 0x000 0x1 0x0
+#define MX8MP_IOMUXC_UART4_TXD__GPT1_CAPTURE1                        0x23C 0x49C 0x594 0x3 0x1
+#define MX8MP_IOMUXC_UART4_TXD__I2C6_SDA                             0x23C 0x49C 0x5D0 0x4 0x2
+#define MX8MP_IOMUXC_UART4_TXD__GPIO5_IO29                           0x23C 0x49C 0x000 0x5 0x0
+#define MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL                  0x240 0x4A0 0x000 0x0 0x0
+#define MX8MP_IOMUXC_HDMI_DDC_SCL__I2C5_SCL                          0x240 0x4A0 0x5C4 0x3 0x3
+#define MX8MP_IOMUXC_HDMI_DDC_SCL__CAN1_TX                           0x240 0x4A0 0x000 0x4 0x0
+#define MX8MP_IOMUXC_HDMI_DDC_SCL__GPIO3_IO26                        0x240 0x4A0 0x000 0x5 0x0
+#define MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA                  0x244 0x4A4 0x000 0x0 0x0
+#define MX8MP_IOMUXC_HDMI_DDC_SDA__I2C5_SDA                          0x244 0x4A4 0x5C8 0x3 0x3
+#define MX8MP_IOMUXC_HDMI_DDC_SDA__CAN1_RX                           0x244 0x4A4 0x54C 0x4 0x3
+#define MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27                        0x244 0x4A4 0x000 0x5 0x0
+#define MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC                      0x248 0x4A8 0x000 0x0 0x0
+#define MX8MP_IOMUXC_HDMI_CEC__I2C6_SCL                              0x248 0x4A8 0x5CC 0x3 0x3
+#define MX8MP_IOMUXC_HDMI_CEC__CAN2_TX                               0x248 0x4A8 0x000 0x4 0x0
+#define MX8MP_IOMUXC_HDMI_CEC__GPIO3_IO28                            0x248 0x4A8 0x000 0x5 0x0
+#define MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD                      0x24C 0x4AC 0x000 0x0 0x0
+#define MX8MP_IOMUXC_HDMI_HPD__AUDIOMIX_HDMI_HPD_O                   0x24C 0x4AC 0x000 0x1 0x0
+#define MX8MP_IOMUXC_HDMI_HPD__I2C6_SDA                              0x24C 0x4AC 0x5D0 0x3 0x3
+#define MX8MP_IOMUXC_HDMI_HPD__CAN2_RX                               0x24C 0x4AC 0x550 0x4 0x3
+#define MX8MP_IOMUXC_HDMI_HPD__GPIO3_IO29                            0x24C 0x4AC 0x000 0x5 0x0
+
+#endif /* __DTS_IMX8MP_PINFUNC_H */
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp-x8high35-bms.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp-x8high35-bms.dts
@@ -0,0 +1,919 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 Shrirang Bagul <shrirang.bagul@canonical.com>
+ */
+
+/dts-v1/;
+
+#include "dt-bindings/leds/leds-pca955x.h"
+#include "dt-bindings/usb/pd.h"
+#include "imx8mp-x8high35-som.dtsi"
+
+/ {
+	model = "Honeywell i.MX8MP X8High35 BMS";
+	compatible = "Honeywell,x8high35-bms", "fsl,imx8mp";
+
+	aliases {
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+		watchdog0 = &rtc;
+		watchdog1 = &wdog1;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0x8000000>;
+			alloc-ranges = <0x0 0x40000000 0x0 0xc0000000>;
+			linux,cma-default;
+		};
+
+		rpmsg_reserved: rpmsg@55800000 {
+			no-map;
+			reg = <0x0 0x55800000 0x0 0x800000>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		/delete-property/pinctrl-0;
+		/delete-property/pinctrl-names;
+		status = "disabled";
+	};
+
+	clk20m: oscillator-0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency  = <24000000>;
+		clock-output-names = "clk20m";
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpiokeys>;
+
+		s1 {
+			label = "s1";
+			gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_ESC>;
+			wakeup-source;
+		};
+	};
+
+	reg_can1_stby: regulator-can1-stby {
+		compatible = "regulator-fixed";
+		regulator-name = "can1-stby";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_flexcan1_reg>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+		enable-active-high;
+	};
+
+	reg_bt_power: regulator-bt-power {
+		compatible = "regulator-fixed";
+		regulator-name = "bt_power";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_bt_reg>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+
+	reg_wifi_power: regulator-wifi-power {
+		compatible = "regulator-fixed";
+		regulator-name = "wifi_power";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_wifi_reg>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		startup-delay-us = <10000>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_v_1v8: regulator-v-1v8 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ldo5>;
+		compatible = "regulator-gpio";
+		regulator-name = "v_1v8";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+		states = <1800000 0x1>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	reg_v_3v3: regulator-v-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_3v3";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_v_5v0: regulator-v-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_5v0";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-always-on;
+	};
+
+	wdoggpio: watchdog {
+		compatible = "linux,wdt-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_wdoggpio>;
+		gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+		hw_algo = "toggle";
+		hw_margin_ms = <60000>;
+		always-running;
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_uart_exp1_int>;
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+	num-cs = <1>;
+	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* UART Port A <--> RS-485 UART */
+	/* UART Port B <--> FFT UART */
+	uart_exp1@0 {
+		compatible = "nxp,sc16is752";
+		reg = <0>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+		clock-frequency = <24000000>;
+		spi-max-frequency = <2000000>;
+
+        gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names =
+			"MMI_PWR_EN", "MMI_PWR_OK",	"RS422_MODE", "GPIO3",
+			"GPIO4", "GPIO5", "GPIO6", "GPIO7";
+    };
+};
+
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_uart_exp2_int>;
+	cs-gpios =	<&gpio5 13 GPIO_ACTIVE_LOW>;
+	num-cs = <1>;
+	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* UART Port A <--> Wifi BT UART */
+	/* UART Port B <--> BLE5 ZigBee UART */
+	uart_exp2@0 {
+		compatible = "nxp,sc16is752";
+		reg = <0>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+		clock-frequency = <24000000>;
+		spi-max-frequency = <2000000>;
+
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-line-names =
+			"BLE5_ZIGBEE_RESET_B", "BLE5_ZIGBEE_INT_B",
+			"GPIO2", "GPIO3", "GPIO4",
+			"GPIO5", "GPIO6", "GPIO7";
+    };
+};
+
+&eqos {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_eqos>;
+	phy-mode = "rgmii-id";
+	phy-reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+	phy-handle = <&ethphy0>;
+	nvmem-cells = <&eth_mac2>;
+	nvmem-cell-names = "mac-address";
+	nvmem_macaddr_swap;
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@3 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <3>;
+			eee-broken-1000t;
+			eee-broken-100tx;
+			eee-broken-10gt;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec>;
+	phy-mode = "rgmii-id";
+	fsl,magic-packet;
+	status = "okay";
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&flexcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	xceiver-supply = <&reg_can1_stby>;
+	status = "okay";
+};
+
+&flexspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexspi>;
+	status = "okay";
+
+	flash@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible ="mb85rq4ml", "jedec,spi-nor";
+		spi-max-frequency = <40000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+
+		/* a 512K partition */
+		partition@0 {
+			label = "fram";
+			reg = <0x0 0x80000>;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	switch: switch@5f {
+		compatible = "microchip,ksz9897";
+		reg = <0x5f>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port@1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port@3 {
+				reg = <3>;
+				label = "lan4";
+			};
+
+			port@4 {
+				reg = <4>;
+				label = "lan5";
+			};
+
+			port@5 {
+				reg = <5>;
+				label = "t1l";
+			};
+
+			port@6 {
+				reg = <6>;
+				label = "cpu";
+				ethernet = <&fec>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	led_driver_0: pca9552@60 {
+		compatible = "nxp,pca9552";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x60>;
+
+		led@0 {
+			label = "green:tx1";
+			reg = <0>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@1 {
+			label = "red:tx1";
+			reg = <1>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@2 {
+			label = "green:rx1";
+			reg = <2>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@3 {
+			label = "red:rx1";
+			reg = <3>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@4 {
+			label = "green:tx2";
+			reg = <4>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@5 {
+			label = "red:tx2";
+			reg = <5>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@6 {
+			label = "green:rx2";
+			reg = <6>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@7 {
+			label = "red:rx2";
+			reg = <7>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@8 {
+			label = "green:tx3";
+			reg = <8>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@9 {
+			label = "red:tx3";
+			reg = <9>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@10 {
+			label = "green:rx3";
+			reg = <10>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@11 {
+			label = "red:rx3";
+			reg = <11>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@12 {
+			label = "green:tx4";
+			reg = <12>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@13 {
+			label = "red:tx4";
+			reg = <13>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@14 {
+			label = "green:rx4";
+			reg = <14>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@15 {
+			label = "red:rx4";
+			reg = <15>;
+			type = <PCA955X_TYPE_LED>;
+		};
+	};
+
+	led_driver_1: pca9552@61 {
+		compatible = "nxp,pca9552";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x61>;
+
+		led@0 {
+			label = "green:tx5";
+			reg = <0>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@1 {
+			label = "red:tx5";
+			reg = <1>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@2 {
+			label = "green:rx5";
+			reg = <2>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@3 {
+			label = "red:rx5";
+			reg = <3>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@4 {
+			label = "green:status";
+			reg = <4>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@5 {
+			label = "red:status";
+			reg = <5>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@6 {
+			label = "green:wifi";
+			reg = <6>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@7 {
+			label = "red:wifi";
+			reg = <7>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@8 {
+			label = "green:bluetooth";
+			reg = <8>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@9 {
+			label = "red:bluetooth";
+			reg = <9>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@10 {
+			label = "green:alarm_b";
+			reg = <10>;
+			type = <PCA955X_TYPE_LED>;
+		};
+
+		led@11 {
+			label = "red:alarm_b";
+			reg = <11>;
+			type = <PCA955X_TYPE_LED>;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c6>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	rtc: rtc@68 {
+		compatible = "st,m41t83";
+		reg = <0x68>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "rtc-wake";
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_beeper_pwm: beeperpwmgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO10__PWM3_OUT	0x6
+		>;
+	};
+
+	pinctrl_bt_reg: btreggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__GPIO3_IO25	0x19
+		>;
+	};
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			/* LED_SHUTDOWN_B */
+			MX8MP_IOMUXC_SD1_DATA6__GPIO2_IO08	0x19
+			/* LED_ALARM_B */
+			MX8MP_IOMUXC_SD1_DATA7__GPIO2_IO09	0x19
+		>;
+	};
+
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC	0x3
+			MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO	0x3
+			MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0	0x91
+			MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1	0x91
+			MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2	0x91
+			MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3	0x91
+			MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x91
+			MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL	0x91
+			MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0		0x1f
+			MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1		0x1f
+			MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2		0x1f
+			MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3		0x1f
+			MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL	0x1f
+			MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x1f
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22		0x19
+		>;
+	};
+
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK	0x82
+			MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO	0x82
+			MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI	0x82
+			MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09	0x82
+		>;
+	};
+
+	pinctrl_ecspi2: ecspi2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK	0x82
+			MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO	0x82
+			MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI	0x82
+			MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13	0x82
+		>;
+	};
+
+	pinctrl_uart_exp1_int: uartexp1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00	0x19
+		>;
+	};
+
+	pinctrl_uart_exp2_int: uartexp2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x19
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC		0x3
+			MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO		0x3
+			MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0		0x91
+			MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1		0x91
+			MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2		0x91
+			MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3		0x91
+			MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC		0x91
+			MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL	0x91
+			MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0		0x1f
+			MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1		0x1f
+			MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2		0x1f
+			MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3		0x1f
+			MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL	0x1f
+			MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC		0x1f
+			MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02		0x19
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_RXD1__CAN1_TX		0x154
+			MX8MP_IOMUXC_SAI5_RXD2__CAN1_RX		0x154
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX         0x154
+			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX         0x154
+		>;
+	};
+
+	pinctrl_flexcan1_reg: flexcan1reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08		0x154   /* CAN1_STBY */
+		>;
+	};
+
+	pinctrl_flexcan2_reg: flexcan2reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27      0x154   /* CAN2_STBY */
+		>;
+	};
+
+	pinctrl_flexspi: flexspigrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK		0x1c2
+			MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B	0x82
+			MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00	0x82
+			MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01	0x82
+			MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02	0x82
+			MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03	0x82
+		>;
+	};
+
+	pinctrl_gpiokeys: gpiokeysgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19	0x19
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA2__I2C4_SCL	0x400001c3
+			MX8MP_IOMUXC_SD1_DATA3__I2C4_SDA 	0x400001c3
+		>;
+	};
+
+	pinctrl_i2c6: i2c6grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA0__I2C6_SCL		0x400001c3
+			MX8MP_IOMUXC_SD1_DATA1__I2C6_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_ldo5: ldo5grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04	0x19
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__UART1_DTE_RX 0x49
+			MX8MP_IOMUXC_SD1_CMD__UART1_DTE_TX 0x49
+			MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05	0x19
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_TXC__UART2_DTE_RX		0x49
+			MX8MP_IOMUXC_SAI3_TXFS__UART2_DTE_TX	0x49
+			MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04		0x19
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX	0x49
+			MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX	0x49
+			MX8MP_IOMUXC_SPDIF_TX__GPIO5_IO03		0x19
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX	0x49
+			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX	0x49
+			MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02		0x19
+		>;
+	};
+
+	pinctrl_uart_exp2_int: uartexp2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x19
+		>;
+	};
+
+	pinctrl_usb1_vbus: usb1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10	0x19
+		>;
+	};
+
+	pinctrl_usb2_vbus: usb2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14	0x19
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d4
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d6
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B	0x166
+		>;
+	};
+
+	pinctrl_wdoggpio:wdoggpiogrp{
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00	0x19
+		>;
+	};
+
+	pinctrl_wifi_reg: wifireggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24	0x19
+		>;
+	};
+
+};
+
+&ocotp {
+	eth_mac2: mac-address@94 {
+		reg = <0x94 6>;
+	};
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart1 {
+	/* RS-485 TouchFlakes */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	fsl,dte-mode;
+	linux,rs485-enabled-at-boot-time;
+	rts-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&uart2 {
+	/* RS-485 MSTP Port1 */
+	/* AND */
+	/* ARM53 debug console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	linux,rs485-enabled-at-boot-time;
+	status = "okay";
+
+	fsl,dte-mode;
+	rts-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+};
+
+&uart3 {
+	/* RS-485 MSTP Port2 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	linux,rs485-enabled-at-boot-time;
+	status = "okay";
+
+	rts-gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>;
+};
+
+&uart4 {
+	/* RS-485 MSTP Port3 */
+	/* AND */
+	/* ARM M7 debug console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	linux,rs485-enabled-at-boot-time;
+	status = "okay";
+
+	rts-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+&usb3_0 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "peripheral";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "peripheral";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	status = "okay";
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+	vmmc-supply = <&reg_wifi_power>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	status = "okay";
+
+	wifi@1 {
+		compatible = "brcm,bcm4329-fmac";
+		reg = <1>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp-x8high35-pdk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp-x8high35-pdk.dts
@@ -0,0 +1,872 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 Shrirang Bagul <shrirang.bagul@canonical.com>
+ */
+
+/dts-v1/;
+
+#include "dt-bindings/usb/pd.h"
+#include "imx8mp-x8high35-som.dtsi"
+
+/ {
+	model = "Honeywell i.MX8MP X8High35 PDK";
+	compatible = "Honeywell,x8high35-pdk", "fsl,imx8mp";
+
+	aliases {
+		rtc0 = &rtc;
+		rtc1 = &snvs_rtc;
+	};
+
+	beeper {
+		compatible = "pwm-beeper";
+		pwms = <&pwm3 0 5000000 0>;
+	};
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+
+	leds {
+		compatible = "gpio-leds";
+
+		dl14 {
+			label = "trouble";
+			gpios = <&led_expander 0 GPIO_ACTIVE_LOW>;
+		};
+
+		dl15 {
+			label = "bt-status";
+			gpios = <&led_expander 1 GPIO_ACTIVE_LOW>;
+		};
+
+		dl16 {
+			label = "panel-conn";
+			gpios = <&led_expander 2 GPIO_ACTIVE_LOW>;
+		};
+
+		dl17 {
+			label = "cloud-conn";
+			gpios = <&led_expander 3 GPIO_ACTIVE_LOW>;
+		};
+
+		dl18 {
+			label = "wifi-conn";
+			gpios = <&led_expander 4 GPIO_ACTIVE_LOW>;
+		};
+
+		dl19 {
+			label = "bte-conn";
+			gpios = <&led_expander 5 GPIO_ACTIVE_LOW>;
+		};
+
+		dl20 {
+			label = "add-on";
+			gpios = <&led_expander 6 GPIO_ACTIVE_LOW>;
+		};
+
+		dl21 {
+			label = "module-conn";
+			gpios = <&led_expander 7 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	bus@30c00000 { /* AIPS5 */
+		compatible = "simple-bus";
+		reg = <0x30c00000 0x400000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		spba-bus@30c00000 {
+			compatible = "fsl,spba-bus", "simple-bus";
+			reg = <0x30c00000 0x100000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			sai3: sai@30c30000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x308c0000 0x10000>;
+				interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_AUDIOMIX_SAI3_IPG>,
+				     <&clk IMX8MP_CLK_DUMMY>, <&clk IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>,
+				     <&clk IMX8MP_CLK_DUMMY>, <&clk IMX8MP_CLK_DUMMY>;
+				clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma1 12 24 0>, <&sdma1 13 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+		};
+	};
+
+	reg_usb1_host_vbus: regulator-usb1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb1_vbus>;
+		regulator-name = "usb1_host_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		status = "disabled";
+	};
+
+	reg_usb2_host_vbus: regulator-usb2-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2_vbus>;
+		regulator-name = "usb1_host_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		status = "disabled";
+	};
+
+	reg_wifi_power: regulator-wifi-power {
+		compatible = "regulator-fixed";
+		regulator-name = "wifi_power";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+		startup-delay-us = <10000>;
+		off-on-delay-us = <12000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_v_1v8: regulator-v-1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_1v8";
+		regulator-max-microvolt = <1800000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_v_3v3: regulator-v-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_3v3";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_v_5v0: regulator-v-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v_5v0";
+		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <5000000>;
+		regulator-always-on;
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1
+		&pinctrl_uart_exp1_int &pinctrl_uart_exp2_int>;
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>,
+		<&gpio1 1 GPIO_ACTIVE_LOW>;
+	num-cs = <2>;
+	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	uart_exp1@0 {
+		compatible = "nxp,sc16is752";
+		reg = <0x0>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+		clock-frequency = <14745600>;
+		spi-max-frequency = <2000000>;
+    };
+
+	uart_exp2@1 {
+		compatible = "nxp,sc16is752";
+		reg = <0x1>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+		clock-frequency = <14745600>;
+		spi-max-frequency = <2000000>;
+    };
+};
+
+&eqos {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_eqos>;
+	phy-mode = "rgmii-id";
+	phy-reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+	phy-handle = <&ethphy1>;
+	nvmem-cells = <&eth_mac2>;
+	nvmem-cell-names = "mac-address";
+	nvmem_macaddr_swap;
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy1: ethernet-phy@2 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <2>;
+			eee-broken-1000t;
+			eee-broken-100tx;
+			eee-broken-10gt;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec>;
+	phy-mode = "rgmii-id";
+	phy-reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+	phy-handle = <&ethphy0>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <1>;
+			eee-broken-1000t;
+			eee-broken-100tx;
+			eee-broken-10gt;
+			micrel,led-mode = <1>;
+		};
+	};
+};
+
+&i2c2 {
+	rtc: rtc@6f {
+		compatible = "microchip,mcp7940x";
+		reg = <0x6f>;
+	};
+
+	codec: sgtl5000@a {
+		#sound-dai-cells = <0>;
+		compatible = "fsl,sgtl5000";
+		reg = <0xa>;
+		VDDA-supply = <&reg_v_3v3>;
+		VDDIO-supply = <&reg_v_1v8>;
+		clocks = <&clk IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
+	};
+
+	/* ToDo: CSI1/2 , DSI */
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	sensor@48 {
+		compatible = "ti,tmp75";
+		reg = <0x48>;
+	};
+
+	typec_1: ptn5150@3d {
+		compatible = "nxp,ptn5150";
+		reg = <0x3d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb1_vbus>;
+		vbus-gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+	typec_2: ptn5150@1d {
+		compatible = "nxp,ptn5150";
+		reg = <0x1d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2_vbus>;
+		vbus-gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+	/* ToDo: Pi, LVDS0/1 */
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	clock-frequency = <100000>;
+	status = "okay";
+
+	sensor@48 {
+		compatible = "ti,tmp75";
+		reg = <0x48>;
+	};
+
+	gpio_exp_74: gpio@74 {
+		compatible = "ti,tca9539";
+		reg = <0x74>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <22 IRQ_TYPE_EDGE_FALLING>;
+		vcc-supply = <&reg_v_3v3>;
+
+		port1_3v3_pwr_ctl {
+			gpio-hog;
+			gpios = <0 GPIO_ACTIVE_HIGH>;
+			line-name = "PORT1_3V3_PWR_CTL";
+		};
+
+		nint_port1 {
+			gpio-hog;
+			gpios = <1 GPIO_ACTIVE_LOW>;
+			line-name = "nINT_PORT1";
+		};
+
+		port1_nrst {
+			gpio-hog;
+			gpios = <2 GPIO_ACTIVE_LOW>;
+			line-name = "PORT1_nRST";
+		};
+
+		/* ToDo: GPIO/SPI_CTS_PORT1 (P03) */
+
+		board_id_1 {
+			gpio-hog;
+			gpios = <4 0>;
+			input;
+			line-name = "BOARD_ID_1";
+		};
+
+		board_id_2 {
+			gpio-hog;
+			gpios = <5 0>;
+			input;
+			line-name = "BOARD_ID_2";
+		};
+
+		board_id_3 {
+			gpio-hog;
+			gpios = <6 0>;
+			input;
+			line-name = "BOARD_ID_3";
+		};
+
+		board_id_4 {
+			gpio-hog;
+			gpios = <7 0>;
+			input;
+			line-name = "BOARD_ID_4";
+		};
+
+		lte_igt {
+			gpio-hog;
+			gpios = <8 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_IGT";
+		};
+
+		lte_radio_usb_ctrl {
+			gpio-hog;
+			gpios = <9 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_RADIO_USB_CTR";
+		};
+
+		lte_power_en {
+			gpio-hog;
+			gpios = <10 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_POWER_EN";
+		};
+
+		lte_emergency_off {
+			gpio-hog;
+			gpios = <11 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_EMERGENCY_OFF";
+		};
+
+		lte_uart_dtr {
+			gpio-hog;
+			gpios = <12 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_UART_DTR";
+		};
+
+		lte_vdd5v_en {
+			gpio-hog;
+			gpios = <13 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_VDD5V_EN";
+		};
+
+		/* ToDo: GPIO/SPI_CTS_PORT1 (P03) */
+
+		lte_ring_wakeup {
+			gpio-hog;
+			gpios = <15 GPIO_ACTIVE_HIGH>;
+			output-low;
+			line-name = "LTE_RING_WAKEUP";
+		};
+	};
+
+	gpio_exp_75: gpio@75 {
+		compatible = "ti,tca9539";
+		reg = <0x75>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		interrupt-parent = <&gpio3>;
+		interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
+		vcc-supply = <&reg_v_3v3>;
+	};
+
+	led_expander: led-controller@21 {
+		compatible = "ti,tca6408";
+		reg = <0x21>;
+		vcc-supply = <&reg_v_3v3>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_beeper_pwm: beeperpwmgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO10__PWM3_OUT	0x6
+		>;
+	};
+
+	pinctrl_bt: btgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__GPIO3_IO25	0x19
+		>;
+	};
+
+	/* ToDo: set correct value for IO12 input */
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12	0x41
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC	0x3
+			MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO	0x3
+			MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0	0x91
+			MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1	0x91
+			MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2	0x91
+			MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3	0x91
+			MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x91
+			MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL	0x91
+			MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0		0x1f
+			MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1		0x1f
+			MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2		0x1f
+			MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3		0x1f
+			MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL	0x1f
+			MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x1f
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22		0x19
+		>;
+	};
+
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK	0x82
+			MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO	0x82
+			MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI	0x82
+			MX8MP_IOMUXC_ECSPI1_SS0__ECSPI1_SS0	0x82
+			MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01	0x82
+		>;
+	};
+
+	pinctrl_uart_exp1_int: uartexp1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00	0x19
+		>;
+	};
+
+	pinctrl_uart_exp2_int: uartexp2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x19
+		>;
+	};
+
+	pinctrl_fec: fecgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC		0x3
+			MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO		0x3
+			MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0		0x91
+			MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1		0x91
+			MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2		0x91
+			MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3		0x91
+			MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC		0x91
+			MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL	0x91
+			MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0		0x1f
+			MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1		0x1f
+			MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2		0x1f
+			MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3		0x1f
+			MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL	0x1f
+			MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC		0x1f
+			MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02		0x19
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_RX__CAN1_RX          0x154
+			MX8MP_IOMUXC_SPDIF_TX__CAN1_TX          0x154
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX         0x154
+			MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX         0x154
+		>;
+	};
+
+	pinctrl_flexcan1_reg: flexcan1reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05  0x154   /* CAN1_STBY */
+		>;
+	};
+
+	pinctrl_flexcan2_reg: flexcan2reggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27      0x154   /* CAN2_STBY */
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00	0xd6
+			MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC	0xd6
+			MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK	0xd6
+			MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00	0xd6
+
+			/* Confirm: This pin has multiple connections */
+			/*                |--- U87 --> GPIO_RAS PI_13 */
+			/*   SAI3_MCLK ---|                           */
+			/*                |--- U54 --> SYS_MCLK       */
+			/*
+			MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK	0xd6
+			*/
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19	0x41
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX	0x140
+			MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX	0x140
+			MX8MP_IOMUXC_UART3_RXD__UART1_DCE_CTS	0x140
+			MX8MP_IOMUXC_UART3_TXD__UART1_DCE_RTS	0x140
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX	0x49
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX	0x49
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA6__UART3_DCE_TX	0x49
+			MX8MP_IOMUXC_SD1_DATA7__UART3_DCE_RX	0x49
+		>;
+	};
+
+	pinctrl_uart4: uart4grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX	0x49
+			MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX	0x49
+		>;
+	};
+
+	pinctrl_uart_exp2_int: uartexp2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19	0x19
+		>;
+	};
+
+	pinctrl_usb1_vbus: usb1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11	0x19
+		>;
+	};
+
+	pinctrl_usb2_vbus: usb2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14	0x19
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK	0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD	0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0	0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1	0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2	0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3	0x1d0
+			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24	0x19
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK	0x194
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD	0x1d4
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0	0x1d4
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1	0x1d4
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2	0x1d4
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3	0x1d4
+			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24	0x19
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK	0x196
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD	0x1d6
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0	0x1d6
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1	0x1d6
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2	0x1d6
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3	0x1d6
+			MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24	0x19
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT	0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12	0x1c4
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B	0x166
+		>;
+	};
+};
+
+&ocotp {
+	eth_mac2: mac-address@94 {
+		reg = <0x94 6>;
+	};
+};
+
+&pwm3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_beeper_pwm>;
+	status = "okay";
+};
+
+&sai3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&snvs_pwrkey {
+	status = "okay";
+};
+
+&uart1 {
+	/* BT UART */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1 &pinctrl_bt>;
+	status = "okay";
+	fsl,uart-has-rtscts;
+};
+
+&uart2 {
+	/* ARM53 debug console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&uart3 {
+	/* RS-232 port */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+&uart4 {
+	/* ARM M7 debug console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+&usb3_0 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "otg";
+	status = "okay";
+
+	extcon = <&typec_1>;
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb3_1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	vmmc-supply = <&reg_wifi_power>;
+	bus-width = <4>;
+	non-removable;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	status = "okay";
+
+	wifi@1 {
+		compatible = "brcm,bcm4329-fmac";
+		reg = <1>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp-x8high35-som.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp-x8high35-som.dtsi
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 Shrirang Bagul <shrirang.bagul@canonical.com>
+ */
+
+#include "imx8mp.dtsi"
+
+/ {
+	reg_vdd_3v3: regulator-vdd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "vdd_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_som_led>;
+
+		som_led: status {
+			label = "green:status";
+			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	a53_opp_table: opp-table {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <850000>;
+			opp-supported-hw = <0x8a0>, <0x7>;
+			clock-latency-ns = <150000>;
+			opp-suspend;
+		};
+
+		opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <950000>;
+			opp-supported-hw = <0xa0>, <0x7>;
+			clock-latency-ns = <150000>;
+			opp-suspend;
+		};
+
+		opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1000000>;
+			opp-supported-hw = <0x20>, <0x3>;
+			clock-latency-ns = <150000>;
+			opp-suspend;
+		};
+	};
+
+	cpus {
+		idle-states {
+			entry-method = "psci";
+
+			cpu_pd_wait: cpu-pd-wait {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x0010033>;
+				local-timer-stop;
+				entry-latency-us = <1000>;
+				exit-latency-us = <700>;
+				min-residency-us = <2700>;
+			};
+		};
+	};
+
+};
+
+&A53_0 {
+	operating-points-v2 = <&a53_opp_table>;
+	cpu-idle-states = <&cpu_pd_wait>;
+	nvmem-cells = <&cpu_speed_grade>;
+	nvmem-cell-names = "speed_grade";
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+	operating-points-v2 = <&a53_opp_table>;
+	cpu-idle-states = <&cpu_pd_wait>;
+	nvmem-cells = <&cpu_speed_grade>;
+	nvmem-cell-names = "speed_grade";
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+	operating-points-v2 = <&a53_opp_table>;
+	cpu-idle-states = <&cpu_pd_wait>;
+	nvmem-cells = <&cpu_speed_grade>;
+	nvmem-cell-names = "speed_grade";
+	cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+	operating-points-v2 = <&a53_opp_table>;
+	cpu-idle-states = <&cpu_pd_wait>;
+	nvmem-cells = <&cpu_speed_grade>;
+	nvmem-cell-names = "speed_grade";
+	cpu-supply = <&buck2_reg>;
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic: pca9450@25 {
+		compatible = "nxp,pca9450c";
+		reg = <0x25>;
+
+		pinctrl-0 = <&pinctrl_pmic>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+		regulators {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			buck1_reg: regulator@0 {
+				reg = <0>;
+				regulator-compatible = "BUCK1";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <2187500>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck2_reg: regulator@1 {
+				reg = <1>;
+				regulator-compatible = "BUCK2";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <2187500>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+				nxp,dvs-run-voltage = <950000>;
+				nxp,dvs-standby-voltage = <850000>;
+			};
+
+			buck4_reg: regulator@3 {
+				reg = <3>;
+				regulator-compatible = "BUCK4";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5_reg: regulator@4 {
+				reg = <4>;
+				regulator-compatible = "BUCK5";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6_reg: regulator@5 {
+				reg = <5>;
+				regulator-compatible = "BUCK6";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1_reg: regulator@6 {
+				reg = <6>;
+				regulator-compatible = "LDO1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2_reg: regulator@7 {
+				reg = <7>;
+				regulator-compatible = "LDO2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3_reg: regulator@8 {
+				reg = <8>;
+				regulator-compatible = "LDO3";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4_reg: regulator@9 {
+				reg = <9>;
+				regulator-compatible = "LDO4";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo5_reg: regulator@10 {
+				reg = <10>;
+				regulator-compatible = "LDO5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ext_crypto: extcrypto@60 {
+		compatible = "atmel,atecc508a";
+		reg = <0x60>;
+	};
+};
+
+&iomuxc {
+	pinctrl_som_led: somledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x19
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL		0x400001c3
+			MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA		0x400001c3
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x190
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d0
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d0
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d0
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d0
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d0
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d0
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d0
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d0
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d0
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x194
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d4
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d4
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d4
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d4
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d4
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d4
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d4
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d4
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d4
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x196
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d6
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d6
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d6
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d6
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d6
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d6
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d6
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d6
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d6
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x196
+		>;
+	};
+
+	pinctrl_pmic: pmicirq {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03	0x41
+		>;
+	};
+};
+
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC3>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mp.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mp.dtsi
@@ -0,0 +1,1006 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <dt-bindings/clock/imx8mp-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
+
+#include "imx8mp-pinfunc.h"
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		ethernet0 = &fec;
+		ethernet1 = &eqos;
+		gpio0 = &gpio1;
+		gpio1 = &gpio2;
+		gpio2 = &gpio3;
+		gpio3 = &gpio4;
+		gpio4 = &gpio5;
+		i2c0 = &i2c1;
+		i2c1 = &i2c2;
+		i2c2 = &i2c3;
+		i2c3 = &i2c4;
+		i2c4 = &i2c5;
+		i2c5 = &i2c6;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
+		mmc2 = &usdhc3;
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		serial3 = &uart4;
+		spi0 = &flexspi;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		A53_0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			clock-latency = <61036>;
+			clocks = <&clk IMX8MP_CLK_ARM>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&A53_L2>;
+			#cooling-cells = <2>;
+		};
+
+		A53_1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			clock-latency = <61036>;
+			clocks = <&clk IMX8MP_CLK_ARM>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&A53_L2>;
+			#cooling-cells = <2>;
+		};
+
+		A53_2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x2>;
+			clock-latency = <61036>;
+			clocks = <&clk IMX8MP_CLK_ARM>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&A53_L2>;
+			#cooling-cells = <2>;
+		};
+
+		A53_3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+			clock-latency = <61036>;
+			clocks = <&clk IMX8MP_CLK_ARM>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&A53_L2>;
+			#cooling-cells = <2>;
+		};
+
+		A53_L2: l2-cache0 {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <0x80000>;
+			cache-line-size = <64>;
+			cache-sets = <512>;
+		};
+	};
+
+	osc_32k: clock-osc-32k {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		clock-output-names = "osc_32k";
+	};
+
+	osc_24m: clock-osc-24m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "osc_24m";
+	};
+
+	clk_ext1: clock-ext1 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133000000>;
+		clock-output-names = "clk_ext1";
+	};
+
+	clk_ext2: clock-ext2 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133000000>;
+		clock-output-names = "clk_ext2";
+	};
+
+	clk_ext3: clock-ext3 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <133000000>;
+		clock-output-names = "clk_ext3";
+	};
+
+	clk_ext4: clock-ext4 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency= <133000000>;
+		clock-output-names = "clk_ext4";
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		dsp_reserved: dsp@92400000 {
+			reg = <0 0x92400000 0 0x2000000>;
+			no-map;
+		};
+	};
+
+	pmu {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts = <GIC_PPI 7
+			     (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	thermal-zones {
+		cpu-thermal {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tmu 0>;
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit0: trip1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+
+		soc-thermal {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tmu 1>;
+			trips {
+				soc_alert0: trip0 {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				soc_crit0: trip1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&soc_alert0>;
+					cooling-device =
+						<&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+		clock-frequency = <8000000>;
+		arm,no-tick-in-suspend;
+	};
+
+	soc@0 {
+		compatible = "fsl,imx8mp-soc", "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x0 0x0 0x3e000000>;
+		dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>;
+		nvmem-cells = <&imx8mp_uid>;
+		nvmem-cell-names = "soc_unique_id";
+
+		caam_sm: caam-sm@100000 {
+			compatible = "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
+
+		aips1: bus@30000000 {
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30000000 0x400000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpio1: gpio@30200000 {
+				compatible = "fsl,imx8mp-gpio", "fsl,imx35-gpio";
+				reg = <0x30200000 0x10000>;
+				interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPIO1_ROOT>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&iomuxc 0 5 30>;
+			};
+
+			gpio2: gpio@30210000 {
+				compatible = "fsl,imx8mp-gpio", "fsl,imx35-gpio";
+				reg = <0x30210000 0x10000>;
+				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPIO2_ROOT>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&iomuxc 0 35 21>;
+			};
+
+			gpio3: gpio@30220000 {
+				compatible = "fsl,imx8mp-gpio", "fsl,imx35-gpio";
+				reg = <0x30220000 0x10000>;
+				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPIO3_ROOT>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&iomuxc 0 56 26>, <&iomuxc 26 144 4>;
+			};
+
+			gpio4: gpio@30230000 {
+				compatible = "fsl,imx8mp-gpio", "fsl,imx35-gpio";
+				reg = <0x30230000 0x10000>;
+				interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPIO4_ROOT>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&iomuxc 0 82 32>;
+			};
+
+			gpio5: gpio@30240000 {
+				compatible = "fsl,imx8mp-gpio", "fsl,imx35-gpio";
+				reg = <0x30240000 0x10000>;
+				interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPIO5_ROOT>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&iomuxc 0 114 30>;
+			};
+
+			tmu: tmu@30260000 {
+				compatible = "fsl,imx8mp-tmu";
+				reg = <0x30260000 0x10000>;
+				clocks = <&clk IMX8MP_CLK_TSENSOR_ROOT>;
+				#thermal-sensor-cells = <1>;
+			};
+
+			wdog1: watchdog@30280000 {
+				compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt";
+				reg = <0x30280000 0x10000>;
+				interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_WDOG1_ROOT>;
+				status = "disabled";
+			};
+
+			wdog2: watchdog@30290000 {
+				compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt";
+				reg = <0x30290000 0x10000>;
+				interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_WDOG2_ROOT>;
+				status = "disabled";
+			};
+
+			wdog3: watchdog@302a0000 {
+				compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt";
+				reg = <0x302a0000 0x10000>;
+				interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_WDOG3_ROOT>;
+				status = "disabled";
+			};
+
+			iomuxc: pinctrl@30330000 {
+				compatible = "fsl,imx8mp-iomuxc";
+				reg = <0x30330000 0x10000>;
+			};
+
+			gpr: iomuxc-gpr@30340000 {
+				compatible = "fsl,imx8mp-iomuxc-gpr", "syscon";
+				reg = <0x30340000 0x10000>;
+			};
+
+			ocotp: efuse@30350000 {
+				compatible = "fsl,imx8mp-ocotp", "fsl,imx8mm-ocotp", "syscon";
+				reg = <0x30350000 0x10000>;
+				clocks = <&clk IMX8MP_CLK_OCOTP_ROOT>;
+				/* For nvmem subnodes */
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				imx8mp_uid: unique-id@420 {
+					reg = <0x8 0x8>;
+				};
+
+				cpu_speed_grade: speed-grade@10 {
+					reg = <0x10 4>;
+				};
+
+				eth_mac1: mac-address@90 {
+					reg = <0x90 6>;
+				};
+			};
+
+			anatop: anatop@30360000 {
+				compatible = "fsl,imx8mp-anatop", "fsl,imx8mm-anatop",
+					     "syscon";
+				reg = <0x30360000 0x10000>;
+			};
+
+			snvs: snvs@30370000 {
+				compatible = "fsl,sec-v4.0-mon","syscon", "simple-mfd";
+				reg = <0x30370000 0x10000>;
+
+				snvs_rtc: snvs-rtc-lp {
+					compatible = "fsl,sec-v4.0-mon-rtc-lp";
+					regmap =<&snvs>;
+					offset = <0x34>;
+					interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+						     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_SNVS_ROOT>;
+					clock-names = "snvs-rtc";
+				};
+
+				snvs_pwrkey: snvs-powerkey {
+					compatible = "fsl,sec-v4.0-pwrkey";
+					regmap = <&snvs>;
+					interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_SNVS_ROOT>;
+					clock-names = "snvs-pwrkey";
+					linux,keycode = <KEY_POWER>;
+					wakeup-source;
+					status = "disabled";
+				};
+			};
+
+			clk: clock-controller@30380000 {
+				compatible = "fsl,imx8mp-ccm";
+				reg = <0x30380000 0x10000>;
+				#clock-cells = <1>;
+				clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
+					 <&clk_ext3>, <&clk_ext4>;
+				clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
+					      "clk_ext3", "clk_ext4";
+				assigned-clocks = <&clk IMX8MP_CLK_A53_SRC>,
+						  <&clk IMX8MP_CLK_A53_CORE>,
+						  <&clk IMX8MP_CLK_NOC>,
+						  <&clk IMX8MP_CLK_NOC_IO>,
+						  <&clk IMX8MP_CLK_GIC>,
+						  <&clk IMX8MP_CLK_AUDIO_AHB>,
+						  <&clk IMX8MP_CLK_AUDIO_AXI_SRC>,
+						  <&clk IMX8MP_AUDIO_PLL1>,
+						  <&clk IMX8MP_AUDIO_PLL2>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>,
+							 <&clk IMX8MP_ARM_PLL_OUT>,
+							 <&clk IMX8MP_SYS_PLL2_1000M>,
+							 <&clk IMX8MP_SYS_PLL1_800M>,
+							 <&clk IMX8MP_SYS_PLL2_500M>,
+							 <&clk IMX8MP_SYS_PLL1_800M>,
+							 <&clk IMX8MP_SYS_PLL1_800M>;
+				assigned-clock-rates = <0>, <0>,
+						       <1000000000>,
+						       <800000000>,
+						       <500000000>,
+						       <400000000>,
+						       <800000000>,
+						       <393216000>,
+						       <361267200>;
+			};
+
+			src: reset-controller@30390000 {
+				compatible = "fsl,imx8mp-src", "syscon";
+				reg = <0x30390000 0x10000>;
+				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+				#reset-cells = <1>;
+			};
+		};
+
+		aips2: bus@30400000 {
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30400000 0x400000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			pwm1: pwm@30660000 {
+				compatible = "fsl,imx8mp-pwm", "fsl,imx27-pwm";
+				reg = <0x30660000 0x10000>;
+				interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_PWM1_ROOT>,
+					 <&clk IMX8MP_CLK_PWM1_ROOT>;
+				clock-names = "ipg", "per";
+				#pwm-cells = <2>;
+				status = "disabled";
+			};
+
+			pwm2: pwm@30670000 {
+				compatible = "fsl,imx8mp-pwm", "fsl,imx27-pwm";
+				reg = <0x30670000 0x10000>;
+				interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_PWM2_ROOT>,
+					 <&clk IMX8MP_CLK_PWM2_ROOT>;
+				clock-names = "ipg", "per";
+				#pwm-cells = <2>;
+				status = "disabled";
+			};
+
+			pwm3: pwm@30680000 {
+				compatible = "fsl,imx8mp-pwm", "fsl,imx27-pwm";
+				reg = <0x30680000 0x10000>;
+				interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_PWM3_ROOT>,
+					 <&clk IMX8MP_CLK_PWM3_ROOT>;
+				clock-names = "ipg", "per";
+				#pwm-cells = <2>;
+				status = "disabled";
+			};
+
+			pwm4: pwm@30690000 {
+				compatible = "fsl,imx8mp-pwm", "fsl,imx27-pwm";
+				reg = <0x30690000 0x10000>;
+				interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_PWM4_ROOT>,
+					 <&clk IMX8MP_CLK_PWM4_ROOT>;
+				clock-names = "ipg", "per";
+				#pwm-cells = <2>;
+				status = "disabled";
+			};
+
+			system_counter: timer@306a0000 {
+				compatible = "nxp,sysctr-timer";
+				reg = <0x306a0000 0x20000>;
+				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&osc_24m>;
+				clock-names = "per";
+			};
+		};
+
+		aips3: bus@30800000 {
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30800000 0x400000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			ecspi1: spi@30820000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+				reg = <0x30820000 0x10000>;
+				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_ECSPI1_ROOT>,
+					 <&clk IMX8MP_CLK_ECSPI1_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			ecspi2: spi@30830000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+				reg = <0x30830000 0x10000>;
+				interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_ECSPI2_ROOT>,
+					 <&clk IMX8MP_CLK_ECSPI2_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			ecspi3: spi@30840000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
+				reg = <0x30840000 0x10000>;
+				interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_ECSPI3_ROOT>,
+					 <&clk IMX8MP_CLK_ECSPI3_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			uart1: serial@30860000 {
+				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+				reg = <0x30860000 0x10000>;
+				interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_UART1_ROOT>,
+					 <&clk IMX8MP_CLK_UART1_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			uart3: serial@30880000 {
+				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+				reg = <0x30880000 0x10000>;
+				interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_UART3_ROOT>,
+					 <&clk IMX8MP_CLK_UART3_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			uart2: serial@30890000 {
+				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+				reg = <0x30890000 0x10000>;
+				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_UART2_ROOT>,
+					 <&clk IMX8MP_CLK_UART2_ROOT>;
+				clock-names = "ipg", "per";
+				status = "disabled";
+			};
+
+			flexcan1: can@308c0000 {
+				compatible = "fsl,imx8mp-flexcan";
+				reg = <0x308c0000 0x10000>;
+				interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
+					 <&clk IMX8MP_CLK_CAN1_ROOT>;
+				clock-names = "ipg", "per";
+				assigned-clocks = <&clk IMX8MP_CLK_CAN1>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
+				assigned-clock-rates = <40000000>;
+				fsl,clk-source = /bits/ 8 <0>;
+				fsl,stop-mode = <&gpr 0x10 4>;
+				status = "disabled";
+			};
+
+			flexcan2: can@308d0000 {
+				compatible = "fsl,imx8mp-flexcan";
+				reg = <0x308d0000 0x10000>;
+				interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
+					 <&clk IMX8MP_CLK_CAN2_ROOT>;
+				clock-names = "ipg", "per";
+				assigned-clocks = <&clk IMX8MP_CLK_CAN2>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
+				assigned-clock-rates = <40000000>;
+				fsl,clk-source = /bits/ 8 <0>;
+				fsl,stop-mode = <&gpr 0x10 5>;
+				status = "disabled";
+			};
+
+			crypto: crypto@30900000 {
+				compatible = "fsl,sec-v4.0";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x30900000 0x40000>;
+				ranges = <0 0x30900000 0x40000>;
+				interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_AHB>,
+					 <&clk IMX8MP_CLK_IPG_ROOT>;
+				clock-names = "aclk", "ipg";
+
+				sec_jr0: jr@1000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x1000 0x1000>;
+					interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr1: jr@2000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x2000 0x1000>;
+					interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				sec_jr2: jr@3000 {
+					compatible = "fsl,sec-v4.0-job-ring";
+					reg = <0x3000 0x1000>;
+					interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+				};
+			};
+
+			i2c1: i2c@30a20000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30a20000 0x10000>;
+				interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C1_ROOT>;
+				status = "disabled";
+			};
+
+			i2c2: i2c@30a30000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30a30000 0x10000>;
+				interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C2_ROOT>;
+				status = "disabled";
+			};
+
+			i2c3: i2c@30a40000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30a40000 0x10000>;
+				interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C3_ROOT>;
+				status = "disabled";
+			};
+
+			i2c4: i2c@30a50000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30a50000 0x10000>;
+				interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C4_ROOT>;
+				status = "disabled";
+			};
+
+			uart4: serial@30a60000 {
+				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+				reg = <0x30a60000 0x10000>;
+				interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_UART4_ROOT>,
+					 <&clk IMX8MP_CLK_UART4_ROOT>;
+				clock-names = "ipg", "per";
+				dmas = <&sdma1 28 4 0>, <&sdma1 29 4 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			mu: mailbox@30aa0000 {
+				compatible = "fsl,imx8mp-mu", "fsl,imx6sx-mu";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_MU_ROOT>;
+				#mbox-cells = <2>;
+			};
+
+			mu2: mailbox@30e60000 {
+				compatible = "fsl,imx8mp-mu", "fsl,imx6sx-mu";
+				reg = <0x30e60000 0x10000>;
+				interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+				#mbox-cells = <2>;
+				status = "disabled";
+			};
+
+			i2c5: i2c@30ad0000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30ad0000 0x10000>;
+				interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C5_ROOT>;
+				status = "disabled";
+			};
+
+			i2c6: i2c@30ae0000 {
+				compatible = "fsl,imx8mp-i2c", "fsl,imx21-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x30ae0000 0x10000>;
+				interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_I2C6_ROOT>;
+				status = "disabled";
+			};
+
+			usdhc1: mmc@30b40000 {
+				compatible = "fsl,imx8mp-usdhc", "fsl,imx7d-usdhc";
+				reg = <0x30b40000 0x10000>;
+				interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_DUMMY>,
+					 <&clk IMX8MP_CLK_NAND_USDHC_BUS>,
+					 <&clk IMX8MP_CLK_USDHC1_ROOT>;
+				clock-names = "ipg", "ahb", "per";
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
+				bus-width = <4>;
+				status = "disabled";
+			};
+
+			usdhc2: mmc@30b50000 {
+				compatible = "fsl,imx8mp-usdhc", "fsl,imx7d-usdhc";
+				reg = <0x30b50000 0x10000>;
+				interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_DUMMY>,
+					 <&clk IMX8MP_CLK_NAND_USDHC_BUS>,
+					 <&clk IMX8MP_CLK_USDHC2_ROOT>;
+				clock-names = "ipg", "ahb", "per";
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
+				bus-width = <4>;
+				status = "disabled";
+			};
+
+			usdhc3: mmc@30b60000 {
+				compatible = "fsl,imx8mp-usdhc", "fsl,imx7d-usdhc";
+				reg = <0x30b60000 0x10000>;
+				interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_DUMMY>,
+					 <&clk IMX8MP_CLK_NAND_USDHC_BUS>,
+					 <&clk IMX8MP_CLK_USDHC3_ROOT>;
+				clock-names = "ipg", "ahb", "per";
+				fsl,tuning-start-tap = <20>;
+				fsl,tuning-step= <2>;
+				bus-width = <4>;
+				status = "disabled";
+			};
+
+			flexspi: spi@30bb0000 {
+				compatible = "nxp,imx8mp-fspi";
+				reg = <0x30bb0000 0x10000>, <0x8000000 0x10000000>;
+				reg-names = "fspi_base", "fspi_mmap";
+				interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_QSPI_ROOT>,
+					 <&clk IMX8MP_CLK_QSPI_ROOT>;
+				clock-names = "fspi", "fspi_en";
+				assigned-clock-rates = <80000000>;
+				assigned-clocks = <&clk IMX8MP_CLK_QSPI>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			sdma1: dma-controller@30bd0000 {
+				compatible = "fsl,imx8mp-sdma", "fsl,imx8mq-sdma";
+				reg = <0x30bd0000 0x10000>;
+				interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_SDMA1_ROOT>,
+					 <&clk IMX8MP_CLK_AHB>;
+				clock-names = "ipg", "ahb";
+				#dma-cells = <3>;
+				fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+			};
+
+			fec: ethernet@30be0000 {
+				compatible = "fsl,imx8mp-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
+				reg = <0x30be0000 0x10000>;
+				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_ENET1_ROOT>,
+					 <&clk IMX8MP_CLK_SIM_ENET_ROOT>,
+					 <&clk IMX8MP_CLK_ENET_TIMER>,
+					 <&clk IMX8MP_CLK_ENET_REF>,
+					 <&clk IMX8MP_CLK_ENET_PHY_REF>;
+				clock-names = "ipg", "ahb", "ptp",
+					      "enet_clk_ref", "enet_out";
+				assigned-clocks = <&clk IMX8MP_CLK_ENET_AXI>,
+						  <&clk IMX8MP_CLK_ENET_TIMER>,
+						  <&clk IMX8MP_CLK_ENET_REF>,
+						  <&clk IMX8MP_CLK_ENET_PHY_REF>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>,
+							 <&clk IMX8MP_SYS_PLL2_100M>,
+							 <&clk IMX8MP_SYS_PLL2_125M>,
+							 <&clk IMX8MP_SYS_PLL2_50M>;
+				assigned-clock-rates = <0>, <100000000>, <125000000>, <0>;
+				fsl,num-tx-queues = <3>;
+				fsl,num-rx-queues = <3>;
+				nvmem-cells = <&eth_mac1>;
+				nvmem-cell-names = "mac-address";
+				fsl,stop-mode = <&gpr 0x10 3>;
+				nvmem_macaddr_swap;
+				status = "disabled";
+			};
+
+			eqos: ethernet@30bf0000 {
+				compatible = "nxp,imx8mp-dwmac-eqos", "snps,dwmac-5.10a";
+				reg = <0x30bf0000 0x10000>;
+				interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "eth_wake_irq", "macirq";
+				clocks = <&clk IMX8MP_CLK_ENET_QOS_ROOT>,
+					 <&clk IMX8MP_CLK_QOS_ENET_ROOT>,
+					 <&clk IMX8MP_CLK_ENET_QOS_TIMER>,
+					 <&clk IMX8MP_CLK_ENET_QOS>;
+				clock-names = "stmmaceth", "pclk", "ptp_ref", "tx";
+				assigned-clocks = <&clk IMX8MP_CLK_ENET_AXI>,
+						  <&clk IMX8MP_CLK_ENET_QOS_TIMER>,
+						  <&clk IMX8MP_CLK_ENET_QOS>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>,
+							 <&clk IMX8MP_SYS_PLL2_100M>,
+							 <&clk IMX8MP_SYS_PLL2_125M>;
+				assigned-clock-rates = <0>, <100000000>, <125000000>;
+				intf_mode = <&gpr 0x4>;
+				status = "disabled";
+			};
+		};
+
+		gic: interrupt-controller@38800000 {
+			compatible = "arm,gic-v3";
+			reg = <0x38800000 0x10000>,
+			      <0x38880000 0xc0000>;
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-parent = <&gic>;
+		};
+
+		ddr-pmu@3d800000 {
+			compatible = "fsl,imx8mp-ddr-pmu", "fsl,imx8m-ddr-pmu";
+			reg = <0x3d800000 0x400000>;
+			interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		usb3_phy0: usb-phy@381f0040 {
+			compatible = "fsl,imx8mp-usb-phy";
+			reg = <0x381f0040 0x40>;
+			clocks = <&clk IMX8MP_CLK_USB_PHY_ROOT>;
+			clock-names = "phy";
+			assigned-clocks = <&clk IMX8MP_CLK_USB_PHY_REF>;
+			assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
+
+		usb3_0: usb@32f10100 {
+			compatible = "fsl,imx8mp-dwc3";
+			reg = <0x32f10100 0x8>;
+			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
+				 <&clk IMX8MP_CLK_USB_ROOT>;
+			clock-names = "hsio", "suspend";
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			dma-ranges = <0x40000000 0x40000000 0xc0000000>;
+			ranges;
+			status = "disabled";
+
+			usb_dwc3_0: usb@38100000 {
+				compatible = "snps,dwc3";
+				reg = <0x38100000 0x10000>;
+				clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+					 <&clk IMX8MP_CLK_USB_CORE_REF>,
+					 <&clk IMX8MP_CLK_USB_ROOT>;
+				clock-names = "bus_early", "ref", "suspend";
+				assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>;
+				assigned-clock-rates = <500000000>;
+				interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+				phys = <&usb3_phy0>, <&usb3_phy0>;
+				phy-names = "usb2-phy", "usb3-phy";
+				snps,dis-u2-freeclk-exists-quirk;
+			};
+
+		};
+
+		usb3_phy1: usb-phy@382f0040 {
+			compatible = "fsl,imx8mp-usb-phy";
+			reg = <0x382f0040 0x40>;
+			clocks = <&clk IMX8MP_CLK_USB_PHY_ROOT>;
+			clock-names = "phy";
+			assigned-clocks = <&clk IMX8MP_CLK_USB_PHY_REF>;
+			assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
+			#phy-cells = <0>;
+		};
+
+		usb3_1: usb@32f10108 {
+			compatible = "fsl,imx8mp-dwc3";
+			reg = <0x32f10108 0x8>;
+			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
+				 <&clk IMX8MP_CLK_USB_ROOT>;
+			clock-names = "hsio", "suspend";
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			dma-ranges = <0x40000000 0x40000000 0xc0000000>;
+			ranges;
+			status = "disabled";
+
+			usb_dwc3_1: usb@38200000 {
+				compatible = "snps,dwc3";
+				reg = <0x38200000 0x10000>;
+				clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+					 <&clk IMX8MP_CLK_USB_CORE_REF>,
+					 <&clk IMX8MP_CLK_USB_ROOT>;
+				clock-names = "bus_early", "ref", "suspend";
+				assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>;
+				assigned-clock-rates = <500000000>;
+				interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+				phys = <&usb3_phy1>, <&usb3_phy1>;
+				phy-names = "usb2-phy", "usb3-phy";
+				snps,dis-u2-freeclk-exists-quirk;
+			};
+		};
+
+		dsp: dsp@3b6e8000 {
+			compatible = "fsl,imx8mp-dsp";
+			reg = <0x3b6e8000 0x88000>;
+			mbox-names = "txdb0", "txdb1",
+				"rxdb0", "rxdb1";
+			mboxes = <&mu2 2 0>, <&mu2 2 1>,
+				<&mu2 3 0>, <&mu2 3 1>;
+			memory-region = <&dsp_reserved>;
+			status = "disabled";
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-evk-hdmi.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-evk-hdmi.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include "imx8mq-evk.dts"
+
+&irqsteer {
+	status = "okay";
+};
+
+&dcss {
+	status = "okay";
+	disp-dev = "hdmi_disp";
+
+	port@0 {
+		dcss_out: endpoint {
+			remote-endpoint = <&hdmi_in>;
+		};
+	};
+};
+
+&hdmi {
+	compatible = "cdn,imx8mq-hdmi";
+	lane-mapping = <0xe4>;
+	status = "okay";
+	port@1 {
+		hdmi_in: endpoint {
+			remote-endpoint = <&dcss_out>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-evk.dts
@@ -48,6 +48,16 @@
 		gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
 		states = <1000000 0x0
 			  900000 0x1>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ir>;
+		linux,autosuspend-period = <125>;
 	};
 
 	wm8524: audio-codec {
@@ -78,6 +88,21 @@
 			clocks = <&clk IMX8MQ_CLK_SAI2_ROOT>;
 		};
 	};
+
+	sound-spdif {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-spdif";
+		spdif-controller = <&spdif1>;
+		spdif-out;
+		spdif-in;
+	};
+
+	sound-hdmi-arc {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-hdmi-arc";
+		spdif-controller = <&spdif2>;
+		spdif-in;
+	};
 };
 
 &A53_0 {
@@ -96,6 +121,33 @@
 	cpu-supply = <&buck2_reg>;
 };
 
+&ddrc {
+	operating-points-v2 = <&ddrc_opp_table>;
+
+	ddrc_opp_table: opp-table {
+		compatible = "operating-points-v2";
+
+		opp-25M {
+			opp-hz = /bits/ 64 <25000000>;
+		};
+
+		opp-100M {
+			opp-hz = /bits/ 64 <100000000>;
+		};
+
+		/*
+		 * On imx8mq B0 PLL can't be bypassed so low bus is 166M
+		 */
+		opp-166M {
+			opp-hz = /bits/ 64 <166935483>;
+		};
+
+		opp-800M {
+			opp-hz = /bits/ 64 <800000000>;
+		};
+	};
+};
+
 &fec1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_fec1>;
@@ -111,24 +163,17 @@
 		ethphy0: ethernet-phy@0 {
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
+			reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
 		};
 	};
 };
 
-&sai2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sai2>;
-	assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1_BYPASS>, <&clk IMX8MQ_CLK_SAI2>;
-	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL1_OUT>;
-	assigned-clock-rates = <0>, <24576000>;
-	status = "okay";
-};
-
 &gpio5 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_wifi_reset>;
 
-	wl-reg-on {
+	wl-reg-on-hog {
 		gpio-hog;
 		gpios = <29 GPIO_ACTIVE_HIGH>;
 		output-high;
@@ -235,6 +280,7 @@
 		 <&clk IMX8MQ_CLK_PCIE1_PHY>,
 		 <&pcie0_refclk>;
 	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+	vph-supply = <&vgen5_reg>;
 	status = "okay";
 };
 
@@ -242,10 +288,49 @@
 	power-supply = <&sw1a_reg>;
 };
 
+&qspi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi>;
+	status = "okay";
+
+	n25q256a: flash@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "micron,n25q256a", "jedec,spi-nor";
+		spi-max-frequency = <29000000>;
+	};
+};
+
+&sai2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai2>;
+	assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1_BYPASS>, <&clk IMX8MQ_CLK_SAI2>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <0>, <24576000>;
+	status = "okay";
+};
+
 &snvs_pwrkey {
 	status = "okay";
 };
 
+&spdif1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spdif1>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SPDIF1>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
+&spdif2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_SPDIF2>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "okay";
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
@@ -261,21 +346,9 @@
 	status = "okay";
 };
 
-&qspi0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_qspi>;
-	status = "okay";
-
-	n25q256a: flash@0 {
-		reg = <0>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		compatible = "micron,n25q256a", "jedec,spi-nor";
-		spi-max-frequency = <29000000>;
-	};
-};
-
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
@@ -289,6 +362,8 @@
 };
 
 &usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
@@ -340,6 +415,12 @@
 		>;
 	};
 
+	pinctrl_ir: irgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12		0x4f
+		>;
+	};
+
 	pinctrl_pcie0: pcie0grp {
 		fsl,pins = <
 			MX8MQ_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B		0x76
@@ -359,7 +440,7 @@
 		>;
 	};
 
-	pinctrl_reg_usdhc2: regusdhc2grpgpio {
+	pinctrl_reg_usdhc2: regusdhc2gpiogrp {
 		fsl,pins = <
 			MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x41
 		>;
@@ -375,6 +456,13 @@
 		>;
 	};
 
+	pinctrl_spdif1: spdif1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SPDIF_TX_SPDIF1_OUT	0xd6
+			MX8MQ_IOMUXC_SPDIF_RX_SPDIF1_IN		0xd6
+		>;
+	};
+
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
 			MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX		0x49
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-hummingboard-pulse.dts
@@ -110,6 +110,8 @@
 };
 
 &usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
@@ -421,7 +421,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_imu>;
 		interrupt-parent = <&gpio3>;
-		interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
 		vdd-supply = <&reg_3v3_p>;
 		vddio-supply = <&reg_3v3_p>;
 	};
@@ -743,6 +743,7 @@
 };
 
 &usb3_phy0 {
+	vbus-supply = <&reg_5v_p>;
 	status = "okay";
 };
 
@@ -780,6 +781,8 @@
 };
 
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
@@ -790,6 +793,8 @@
 };
 
 &usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts
@@ -191,6 +191,8 @@
 };
 
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	bus-width = <8>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-pe100a.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-pe100a.dts
@@ -0,0 +1,1264 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2017 NXP
+ * Copyright (C) 2017-2018 Pengutronix, Lucas Stach <kernel@pengutronix.de>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/usb/pd.h>
+#include "imx8mq.dtsi"
+
+/ {
+	model = "ASUS PE100A";
+	compatible = "fsl,imx8mq-evk", "fsl,imx8mq";
+
+	aliases {
+		rtc0 = &snvs_rtc;
+		rtc1 = &rtc_isl1208;
+		rtc2 = &rtc_bq32k;
+	};
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x40000000 0 0xc0000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		rpmsg_reserved: rpmsg@0xb8000000 {
+			no-map;
+			reg = <0 0xb8000000 0 0x400000>;
+		};
+	};
+
+	pmic_osc: clock-pmic {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		clock-output-names = "pmic_osc";
+	};
+
+	can_osc: clock-can-20m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+		clock-output-names = "can_osc";
+	};
+
+	modem_reset: modem-reset {
+		compatible = "gpio-reset";
+		reset-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
+		reset-delay-us = <2000>;
+		reset-post-delay-ms = <40>;
+		#reset-cells = <0>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		wakeup {
+			label = "wakeup gpio";
+			gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+			linux,code = <KEY_WAKEUP>;
+			gpio-key,wakeup;
+		};
+	};
+
+	ir_recv: ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ir_recv>;
+		status = "disabled";
+	};
+
+	resmem: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* global autoconfigured region for contiguous allocations */
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x3c000000>;
+			alloc-ranges = <0 0x40000000 0 0x40000000>;
+			linux,cma-default;
+		};
+	};
+
+	pcie0_refclk: pcie0-refclk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+	};
+
+	pcie1_refclk: pcie0-refclk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+	};
+
+	vgen5_reg: vgen5 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie_vph_dummy";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_usdhc2_vmmc: regulator-vsd-3v3 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2>;
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		off-on-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	bt_sco_codec: bt_sco_codec {
+		#sound-dai-cells = <1>;
+		compatible = "linux,bt-sco";
+	};
+
+	wm8524: audio-codec {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8524";
+		wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+		status = "disabled";
+	};
+
+	sound-bt-sco {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "bt-sco-audio";
+		simple-audio-card,format = "dsp_a";
+		simple-audio-card,bitclock-inversion;
+		simple-audio-card,frame-master = <&btcpu>;
+		simple-audio-card,bitclock-master = <&btcpu>;
+
+		btcpu: simple-audio-card,cpu {
+			sound-dai = <&sai3>;
+			dai-tdm-slot-num = <2>;
+			dai-tdm-slot-width = <16>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&bt_sco_codec 1>;
+		};
+	};
+
+	sound-wm8524 {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "wm8524-audio";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,frame-master = <&cpudai>;
+		simple-audio-card,bitclock-master = <&cpudai>;
+		simple-audio-card,widgets =
+			"Line", "Left Line Out Jack",
+			"Line", "Right Line Out Jack";
+		simple-audio-card,routing =
+			"Left Line Out Jack", "LINEVOUTL",
+			"Right Line Out Jack", "LINEVOUTR";
+
+		cpudai: simple-audio-card,cpu {
+			sound-dai = <&sai2>;
+			dai-tdm-slot-num = <2>;
+			dai-tdm-slot-width = <32>;
+		};
+
+		link_codec: simple-audio-card,codec {
+			sound-dai = <&wm8524>;
+			clocks = <&clk IMX8MQ_CLK_SAI2_ROOT>;
+		};
+	};
+
+	sound-hdmi {
+		compatible = "fsl,imx-audio-cdnhdmi";
+		model = "imx-audio-hdmi";
+		audio-cpu = <&sai4>;
+		protocol = <1>;
+	};
+
+	sound-spdif {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-spdif";
+		spdif-controller = <&spdif1>;
+		spdif-out;
+		spdif-in;
+		status = "disabled";
+	};
+
+	sound-hdmi-arc {
+		compatible = "fsl,imx-audio-spdif";
+		model = "imx-hdmi-arc";
+		spdif-controller = <&spdif2>;
+		spdif-in;
+		status = "disabled";
+	};
+
+	sound-ak4458 {
+		compatible = "fsl,imx-audio-ak4458-mq";
+		model = "ak4458-audio";
+		audio-cpu = <&sai1>;
+		audio-codec = <&ak4458_1>, <&ak4458_2>;
+		ak4458,pdn-gpio = <&gpio3 18 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+
+	sound-ak5558 {
+		compatible = "fsl,imx-audio-ak5558-mq";
+		model = "ak5558-audio";
+		audio-cpu = <&sai5>;
+		audio-codec = <&ak5558>;
+		status = "disabled";
+	};
+
+	sound-ak4497 {
+		compatible = "fsl,imx-audio-ak4497-mq";
+		model = "ak4497-audio";
+		audio-cpu = <&sai1>;
+		audio-codec = <&ak4497>;
+		status = "disabled";
+	};
+
+	platform-reset {
+		compatible = "asus,pe100a-reset";
+		reset-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2>;
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	customize-phy-led;
+	fsl,magic-packet;
+	wakeup-enable = "1";
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			at803x,eee-disabled;
+		};
+	};
+};
+
+&sai2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai2>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SAI2>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "disabled";
+};
+
+&sai1 {
+	pinctrl-names = "default", "pcm_b2m", "dsd";
+	pinctrl-0 = <&pinctrl_sai1_pcm>;
+	pinctrl-1 = <&pinctrl_sai1_pcm_b2m>;
+	pinctrl-2 = <&pinctrl_sai1_dsd>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SAI1>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <49152000>;
+	clocks = <&clk IMX8MQ_CLK_SAI1_IPG>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_SAI1_ROOT>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_AUDIO_PLL1_OUT>,
+		<&clk IMX8MQ_AUDIO_PLL2_OUT>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
+	fsl,sai-multi-lane;
+	fsl,dataline,dsd = <0 0xff 0xff 2 0xff 0x11>;
+	dmas = <&sdma2 8 25 0>, <&sdma2 9 25 0>;
+	status = "disabled";
+};
+
+&sai3 {
+	#sound-dai-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai3>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SAI3>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "disabled";
+};
+
+&sai4 {
+	assigned-clocks = <&clk IMX8MQ_CLK_SAI4>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	clocks = <&clk IMX8MQ_CLK_SAI4_IPG>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_SAI4_ROOT>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_AUDIO_PLL1_OUT>,
+		<&clk IMX8MQ_AUDIO_PLL2_OUT>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
+	status = "okay";
+};
+
+&sai5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai5>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SAI5>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <49152000>;
+	clocks = <&clk IMX8MQ_CLK_SAI5_IPG>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_SAI5_ROOT>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_AUDIO_PLL1_OUT>,
+		<&clk IMX8MQ_AUDIO_PLL2_OUT>;
+	clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
+	fsl,sai-asynchronous;
+	status = "disabled";
+};
+
+&spdif1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spdif1>;
+	assigned-clocks = <&clk IMX8MQ_CLK_SPDIF1>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	clocks = <&clk IMX8MQ_CLK_IPG_ROOT>, <&clk IMX8MQ_CLK_25M>,
+		<&clk IMX8MQ_CLK_SPDIF1>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_IPG_ROOT>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>,
+		<&clk IMX8MQ_AUDIO_PLL1_OUT>, <&clk IMX8MQ_AUDIO_PLL2_OUT>;
+	clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3", "rxtx4",
+		      "rxtx5", "rxtx6", "rxtx7", "spba", "pll8k", "pll11k";
+	status = "disabled";
+};
+
+&spdif2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_SPDIF2>;
+	assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+	assigned-clock-rates = <24576000>;
+	status = "disabled";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	ov5640_mipi2: ov5640_mipi2@3c {
+		compatible = "ovti,ov5640_mipi";
+		reg = <0x3c>;
+		status = "disabled";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_csi2_pwn>, <&pinctrl_csi_rst>;
+		clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		clock-names = "csi_mclk";
+		assigned-clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_200M>;
+		assigned-clock-rates = <20000000>;
+		csi_id = <1>;
+		pwn-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+		mclk = <20000000>;
+		mclk_source = <0>;
+		port {
+			ov5640_mipi2_ep: endpoint {
+			};
+		};
+	};
+
+	pmic: bd71837@4b {
+		compatible = "rohm,bd71837";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		#clock-cells = <0>;
+		clocks = <&pmic_osc>;
+		clock-output-names = "pmic_clk";
+		interrupt-parent = <&gpio1>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		rohm,reset-snvs-powered;
+
+		regulators {
+			buck1: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+			};
+
+			buck2: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck3: BUCK3 {
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck4: BUCK4 {
+				regulator-name = "buck4";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck5: BUCK5 {
+				regulator-name = "buck5";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6: BUCK6 {
+				regulator-name = "buck6";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck7: BUCK7 {
+				regulator-name = "buck7";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck8: BUCK8 {
+				regulator-name = "buck8";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo5: LDO5 {
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo6: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo7: LDO7 {
+				regulator-name = "ldo7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+
+	rtc_bq32k: rtc@68 {
+		compatible = "ti,bq32000";
+		reg = <0x68>;
+		status = "okay";
+	};
+
+	rtc_isl1208: rtc@6f {
+		compatible = "isil,isl1208";
+		reg = <0x6f>;
+		status = "okay";
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	synaptics_dsx_ts: synaptics_dsx_ts@20 {
+		compatible = "synaptics_dsx";
+		reg = <0x20>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2c1_dsi_ts_int>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		synaptics,diagonal-rotation;
+		status = "disabled";
+	};
+
+	ak4458_1: ak4458@10 {
+		compatible = "asahi-kasei,ak4458";
+		reg = <0x10>;
+	};
+
+	ak4458_2: ak4458@12 {
+		compatible = "asahi-kasei,ak4458";
+		reg = <0x12>;
+	};
+
+	ak5558: ak5558@13 {
+		compatible = "asahi-kasei,ak5558";
+		reg = <0x13>;
+		ak5558,pdn-gpio = <&gpio3 17 GPIO_ACTIVE_HIGH>;
+	};
+
+	ak4497: ak4497@11 {
+		compatible = "asahi-kasei,ak4497";
+		reg = <0x11>;
+		ak4497,pdn-gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+	};
+
+	adv_bridge: adv7535@3d {
+		compatible = "adi,adv7535";
+		reg = <0x3d>;
+		adi,addr-cec = <0x3b>;
+		adi,dsi-lanes = <4>;
+		pinctrl-0 = <&pinctrl_i2c1_dsi_ts_int>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+
+		status = "disabled";
+	};
+
+	eeprom: eeprom@50 {
+		compatible = "atmel,24c08";
+		reg = <0x50>;
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	ov5640_mipi: ov5640_mipi@3c {
+		compatible = "ovti,ov5640_mipi";
+		reg = <0x3c>;
+		status = "disable";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_csi1_pwn>;
+		clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		clock-names = "csi_mclk";
+		assigned-clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_200M>;
+		assigned-clock-rates = <20000000>;
+		csi_id = <0>;
+		pwn-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+		mclk = <20000000>;
+		mclk_source = <0>;
+		port {
+			ov5640_mipi1_ep: endpoint {
+			};
+		};
+	};
+
+	it5201: tcpc@67 {
+		compatible = "ite,it5201";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_typec>;
+		reg = <0x67>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		port {
+			typec_dr_sw: endpoint {
+				remote-endpoint = <&usb3_drd_sw>;
+			};
+		};
+	};
+};
+
+&i2c4 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie0>;
+	clocks = <&clk IMX8MQ_CLK_PCIE1_ROOT>,
+		 <&clk IMX8MQ_CLK_PCIE1_AUX>,
+		 <&clk IMX8MQ_CLK_PCIE1_PHY>,
+		 <&pcie0_refclk>;
+	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+	/delete-property/ assigned-clocks;
+	/delete-property/ assigned-clock-parents;
+	/delete-property/ assigned-clock-rates;
+	hard-wired = <1>;
+	vph-supply = <&vgen5_reg>;
+	status = "okay";
+};
+
+&pcie1 {
+	clocks = <&clk IMX8MQ_CLK_PCIE2_ROOT>,
+		 <&clk IMX8MQ_CLK_PCIE2_AUX>,
+		 <&clk IMX8MQ_CLK_PCIE2_PHY>,
+		 <&pcie1_refclk>;
+	clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+	/delete-property/ assigned-clocks;
+	/delete-property/ assigned-clock-parents;
+	/delete-property/ assigned-clock-rates;
+	vph-supply = <&vgen5_reg>;
+	status = "okay";
+};
+
+//&pgc_gpu {
+//	power-supply = <&buck3>;
+//};
+
+//&pgc_vpu {
+//	power-supply = <&buck4>;
+//};
+
+&snvs_pwrkey {
+	clock-names = "snvs";
+	status = "okay";
+};
+
+&qspi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi>;
+	status = "okay";
+
+	flash0: n25q256a@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <29000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+		spi-nor,ddr-quad-read-dummy = <6>;
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	assigned-clocks = <&clk IMX8MQ_CLK_UART1>;
+	assigned-clock-parents = <&clk IMX8MQ_CLK_25M>;
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	assigned-clocks = <&clk IMX8MQ_CLK_UART2>;
+	assigned-clock-parents = <&clk IMX8MQ_CLK_25M>;
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+&uart3 { /* BT */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	assigned-clocks = <&clk IMX8MQ_CLK_UART3>;
+	assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>;
+	fsl,uart-has-rtscts;
+	resets = <&modem_reset>;
+	status = "disabled";
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "otg";
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	extcon = <&it5201>;
+	snps,dis-u1-entry-quirk;
+	snps,dis-u2-entry-quirk;
+	status = "okay";
+
+	port {
+		usb3_drd_sw: endpoint {
+			remote-endpoint = <&typec_dr_sw>;
+		};
+	};
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	vqmmc-supply = <&buck7>;
+	bus-width = <8>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_NAND_READY_B_GPIO3_IO16		0x19
+			MX8MQ_IOMUXC_NAND_WE_B_GPIO3_IO17		0x19
+			MX8MQ_IOMUXC_NAND_WP_B_GPIO3_IO18		0x19
+			MX8MQ_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K	0x16
+			MX8MQ_IOMUXC_GPIO1_IO08_GPIO1_IO8		0x19 /* S_PLTRST */
+		>;
+	};
+
+	pinctrl_ir_recv: ir-recv {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12		0x4f
+		>;
+	};
+
+	pinctrl_csi1_pwn: csi1_pwn_grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x19
+		>;
+	};
+	pinctrl_csi2_pwn: csi2_pwn_grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO05_GPIO1_IO5		0x19
+		>;
+	};
+
+	pinctrl_csi_rst: csi_rst_grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO06_GPIO1_IO6		0x19
+			MX8MQ_IOMUXC_GPIO1_IO15_CCMSRCGPCMIX_CLKO2	0x59
+		>;
+	};
+
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK		0x82
+			MX8MQ_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI		0x82
+			MX8MQ_IOMUXC_ECSPI1_MISO_ECSPI1_MISO		0x82
+			MX8MQ_IOMUXC_GPIO1_IO05_GPIO1_IO5		0x19
+		>;
+	};
+
+	pinctrl_ecspi1_cs: ecspi1_cs_grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x19
+		>;
+	};
+
+	pinctrl_ecspi2: ecspi2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK		0x82
+			MX8MQ_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI		0x82
+			MX8MQ_IOMUXC_ECSPI2_MISO_ECSPI2_MISO		0x82
+			MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3		0x19
+		>;
+	};
+
+	pinctrl_ecspi2_cs: ecspi2_cs_grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ECSPI2_SS0_GPIO5_IO13		0x19
+		>;
+	};
+
+	pinctrl_can_standby: can_standby {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI1_MCLK_GPIO4_IO20		0x19
+		>;
+	};
+
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC			0x7
+			MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO		0x7
+			MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x5
+			MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x5
+			MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x5
+			MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x5
+			MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x7
+			MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x7
+			MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x7
+			MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x7
+			MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x5
+			MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x7
+			MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x7
+			MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x5
+			MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9		0x19
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL			0x4000007f
+			MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA			0x4000007f
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_I2C3_SCL_I2C3_SCL			0x4000007f
+			MX8MQ_IOMUXC_I2C3_SDA_I2C3_SDA			0x4000007f
+		>;
+	};
+
+	pinctrl_i2c1_dsi_ts_int: dsi_ts_int {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ECSPI1_MOSI_GPIO5_IO7		0x19
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_I2C2_SCL_I2C2_SCL			0x40000067
+			MX8MQ_IOMUXC_I2C2_SDA_I2C2_SDA			0x40000067
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_I2C4_SCL_I2C4_SCL			0x40000067
+			MX8MQ_IOMUXC_I2C4_SDA_I2C4_SDA			0x40000067
+		>;
+	};
+
+	pinctrl_pcie0: pcie0grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12		0x16 /* S_WAKE */
+		>;
+	};
+
+	pinctrl_pmic: pmicirq {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO07_GPIO1_IO7		0x41
+		>;
+	};
+
+	pinctrl_qspi: qspigrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B	0x82
+			MX8MQ_IOMUXC_NAND_DATA00_QSPI_A_DATA0	0x82
+			MX8MQ_IOMUXC_NAND_DATA01_QSPI_A_DATA1	0x82
+			MX8MQ_IOMUXC_NAND_DATA02_QSPI_A_DATA2	0x82
+			MX8MQ_IOMUXC_NAND_DATA03_QSPI_A_DATA3	0x82
+
+		>;
+	};
+
+	pinctrl_reg_usdhc2: regusdhc2grpgpio {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x41
+		>;
+	};
+
+	pinctrl_sai2: sai2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC     0xd6
+			MX8MQ_IOMUXC_SAI2_TXC_SAI2_TX_BCLK      0xd6
+			MX8MQ_IOMUXC_SAI2_MCLK_SAI2_MCLK        0xd6
+			MX8MQ_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0    0xd6
+		>;
+	};
+
+	pinctrl_sai3: sai3grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
+			MX8MQ_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
+			MX8MQ_IOMUXC_SAI3_TXD_SAI3_TX_DATA0	0xd6
+			MX8MQ_IOMUXC_SAI3_RXD_SAI3_RX_DATA0	0xd6
+		>;
+	};
+
+	pinctrl_sai1_pcm: sai1grp_pcm {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI1_MCLK_SAI1_MCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC		0xd6
+			MX8MQ_IOMUXC_SAI1_RXD7_SAI1_TX_SYNC		0xd6
+			MX8MQ_IOMUXC_SAI1_TXC_SAI1_TX_BCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD2_SAI1_TX_DATA2		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD3_SAI1_TX_DATA3		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD4_SAI1_TX_DATA4		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD5_SAI1_TX_DATA5		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD6_SAI1_TX_DATA6		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD7_SAI1_TX_DATA7		0xd6
+		>;
+	};
+
+	pinctrl_sai1_pcm_b2m: sai1grp_pcm_b2m {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI1_MCLK_SAI1_TX_BCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC		0xd6
+			MX8MQ_IOMUXC_SAI1_RXD7_SAI1_TX_SYNC		0xd6
+			MX8MQ_IOMUXC_SAI1_TXC_SAI1_TX_BCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD2_SAI1_TX_DATA2		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD3_SAI1_TX_DATA3		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD4_SAI1_TX_DATA4		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD5_SAI1_TX_DATA5		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD6_SAI1_TX_DATA6		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD7_SAI1_TX_DATA7		0xd6
+		>;
+	};
+
+	pinctrl_sai1_dsd: sai1grp_dsd {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI1_MCLK_SAI1_MCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC		0xd6
+			MX8MQ_IOMUXC_SAI1_RXD7_SAI1_TX_DATA4		0xd6
+			MX8MQ_IOMUXC_SAI1_TXC_SAI1_TX_BCLK		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD2_SAI1_TX_DATA2		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD3_SAI1_TX_DATA3		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD4_SAI1_TX_DATA4		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD5_SAI1_TX_DATA5		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD6_SAI1_TX_DATA6		0xd6
+			MX8MQ_IOMUXC_SAI1_TXD7_SAI1_TX_DATA7		0xd6
+		>;
+	};
+
+	pinctrl_sai5: sai5grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SAI5_MCLK_SAI5_MCLK	0xd6
+			MX8MQ_IOMUXC_SAI5_RXC_SAI5_RX_BCLK	0xd6
+			MX8MQ_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC	0xd6
+			MX8MQ_IOMUXC_SAI5_RXD0_SAI5_RX_DATA0	0xd6
+			MX8MQ_IOMUXC_SAI5_RXD1_SAI5_RX_DATA1	0xd6
+			MX8MQ_IOMUXC_SAI5_RXD2_SAI5_RX_DATA2	0xd6
+			MX8MQ_IOMUXC_SAI5_RXD3_SAI5_RX_DATA3	0xd6
+		>;
+	};
+
+	pinctrl_spdif1: spdif1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SPDIF_TX_SPDIF1_OUT	0xd6
+			MX8MQ_IOMUXC_SPDIF_RX_SPDIF1_IN		0xd6
+		>;
+	};
+
+	pinctrl_typec: typecgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_NAND_ALE_GPIO3_IO0		0x19
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX		0x49
+			MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX		0x49
+			MX8MQ_IOMUXC_UART3_RXD_UART1_DCE_CTS_B		0x49
+			MX8MQ_IOMUXC_UART3_TXD_UART1_DCE_RTS_B		0x49
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX		0x49
+			MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX		0x49
+			MX8MQ_IOMUXC_UART4_RXD_UART2_DCE_CTS_B		0x49
+			MX8MQ_IOMUXC_UART4_TXD_UART2_DCE_RTS_B		0x49
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_UART3_TXD_UART3_DCE_TX		0x49
+			MX8MQ_IOMUXC_UART3_RXD_UART3_DCE_RX		0x49
+			MX8MQ_IOMUXC_ECSPI1_MISO_UART3_DCE_CTS_B	0x49
+			MX8MQ_IOMUXC_ECSPI1_SS0_UART3_DCE_RTS_B		0x49
+			MX8MQ_IOMUXC_NAND_CLE_GPIO3_IO5			0x19
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x83
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xc3
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xc3
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xc3
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xc3
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xc3
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xc3
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xc3
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xc3
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xc3
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x83
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x8d
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xcd
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xcd
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xcd
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xcd
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xcd
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xcd
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xcd
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xcd
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xcd
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x8d
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x9f
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xdf
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xdf
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xdf
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xdf
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xdf
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xdf
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xdf
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xdf
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xdf
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x9f
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x83
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc3
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc3
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc3
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc3
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc3
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x85
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc5
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc5
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc5
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc5
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc5
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x87
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc7
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc7
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc7
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc7
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc7
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_wdog: wdog1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B		0xc6
+		>;
+	};
+};
+
+&vpu {
+	status = "okay";
+};
+
+&irqsteer {
+	status = "okay";
+};
+
+&dcss {
+	status = "okay";
+
+	port@0 {
+		dcss_out: endpoint {
+			  remote-endpoint = <&hdmi_in>;
+		};
+	};
+};
+
+&hdmi {
+	compatible = "cdn,imx8mq-hdmi";
+	lane-mapping = <0xe4>;
+	init-cec-pa-from-edid;
+	status = "okay";
+	port@1 {
+		hdmi_in: endpoint {
+			remote-endpoint = <&dcss_out>;
+		};
+	};
+};
+
+&ecspi1 {
+	fsl,spi-num-chipselects = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>;
+	cs-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	tpi@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "tcg,tpm_tis-spi";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+		status = "okay";
+	};
+};
+
+&ecspi2 {
+	fsl,spi-num-chipselects = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2>,<&pinctrl_ecspi2_cs>,<&pinctrl_can_standby>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	can0: mcp2515@0 {
+		compatible = "microchip,mcp2515";
+		standby-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
+		reg = <0>;
+		spi-max-frequency = <5000000>;
+		clocks = <&can_osc>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 0x2>;
+		status = "okay";
+	};
+};
+
+&cpu_thermal {
+	trips {
+		cpu-alert {
+			temperature = <95000>;
+		};
+		cpu-crit {
+			temperature = <105000>;
+		};
+	};
+};
+
+&gpu_thermal {
+	trips {
+		gpu-crit {
+			temperature = <105000>;
+		};
+	};
+};
+
+&vpu_thermal {
+	trips {
+		vpu-crit {
+			temperature = <105000>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2017-2019 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8mq.dtsi"
+
+/ {
+	model = "Google i.MX8MQ Phanbell";
+	compatible = "google,imx8mq-phanbell", "fsl,imx8mq";
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x40000000 0 0x40000000>;
+	};
+
+	pmic_osc: clock-pmic {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		clock-output-names = "pmic_osc";
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	fan: gpio-fan {
+		compatible = "gpio-fan";
+		gpio-fan,speed-map = <0 0 8600 1>;
+		gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>;
+		#cooling-cells = <2>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_fan>;
+		status = "okay";
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2>;
+};
+
+&cpu_thermal {
+	trips {
+		cpu_alert0: trip0 {
+			temperature = <75000>;
+			hysteresis = <2000>;
+			type = "passive";
+		};
+
+		cpu_alert1: trip1 {
+			temperature = <80000>;
+			hysteresis = <2000>;
+			type = "passive";
+		};
+
+		cpu_crit0: trip3 {
+			temperature = <90000>;
+			hysteresis = <2000>;
+			type = "critical";
+		};
+
+		fan_toggle0: trip4 {
+			temperature = <65000>;
+			hysteresis = <10000>;
+			type = "active";
+		};
+	};
+
+	cooling-maps {
+		map0 {
+			trip = <&cpu_alert0>;
+			cooling-device =
+			<&A53_0 0 1>; /* Exclude highest OPP */
+		};
+
+		map1 {
+			trip = <&cpu_alert1>;
+			cooling-device =
+			<&A53_0 0 2>; /* Exclude two highest OPPs */
+		};
+
+		map4 {
+			trip = <&fan_toggle0>;
+			cooling-device = <&fan 0 1>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic: pmic@4b {
+		compatible = "rohm,bd71837";
+		reg = <0x4b>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		#clock-cells = <0>;
+		clocks = <&pmic_osc>;
+		clock-output-names = "pmic_clk";
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 GPIO_ACTIVE_LOW>;
+
+		regulators {
+			buck1: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <1250>;
+				rohm,dvs-run-voltage = <900000>;
+				rohm,dvs-idle-voltage = <900000>;
+				rohm,dvs-suspend-voltage = <800000>;
+			};
+
+			buck2: BUCK2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-boot-on;
+				regulator-always-on;
+				rohm,dvs-run-voltage = <1000000>;
+				rohm,dvs-idle-voltage = <900000>;
+			};
+
+			buck3: BUCK3 {
+				regulator-name = "buck3";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				rohm,dvs-run-voltage = <900000>;
+			};
+
+			buck4: BUCK4 {
+				regulator-name = "buck4";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-always-on;
+				rohm,dvs-run-voltage = <900000>;
+			};
+
+			buck5: BUCK5 {
+				regulator-name = "buck5";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck6: BUCK6 {
+				regulator-name = "buck6";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck7: BUCK7 {
+				regulator-name = "buck7";
+				regulator-min-microvolt = <1605000>;
+				regulator-max-microvolt = <1995000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			buck8: BUCK8 {
+				regulator-name = "buck8";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo1: LDO1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo2: LDO2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo3: LDO3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo4: LDO4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo5: LDO5 {
+				regulator-name = "ldo5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo6: LDO6 {
+				regulator-name = "ldo6";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			ldo7: LDO7 {
+				regulator-name = "ldo7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <10000>;
+			reset-deassert-us = <50000>;
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	bus-width = <4>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	status = "okay";
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_fec1: fec1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC			0x3
+			MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO		0x23
+			MX8MQ_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+			MX8MQ_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+			MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+			MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+			MX8MQ_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+			MX8MQ_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+			MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+			MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+			MX8MQ_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+			MX8MQ_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+			MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+			MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+			MX8MQ_IOMUXC_GPIO1_IO09_GPIO1_IO9		0x19
+		>;
+	};
+
+	pinctrl_gpio_fan: gpiofangrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_NAND_CLE_GPIO3_IO5			0x16
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL			0x4000007f
+			MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA			0x4000007f
+		>;
+	};
+
+	pinctrl_pmic: pmicirqgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3	0x41
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX		0x49
+			MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX		0x49
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x83
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xc3
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xc3
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xc3
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xc3
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xc3
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xc3
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xc3
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xc3
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xc3
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x83
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x85
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xc5
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xc5
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xc5
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xc5
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xc5
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xc5
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xc5
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xc5
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xc5
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x85
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK			0x87
+			MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD			0xc7
+			MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0		0xc7
+			MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1		0xc7
+			MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2		0xc7
+			MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3		0xc7
+			MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4		0xc7
+			MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5		0xc7
+			MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6		0xc7
+			MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7		0xc7
+			MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE		0x87
+			MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CD_B_GPIO2_IO12	0x41
+			MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19	0x41
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x83
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc3
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc3
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc3
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc3
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc3
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x85
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc5
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc5
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc5
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc5
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc5
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK			0x87
+			MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD			0xc7
+			MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0		0xc7
+			MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1		0xc7
+			MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2		0xc7
+			MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3		0xc7
+			MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT		0xc1
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6
+		>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts
@@ -207,6 +207,8 @@
 };
 
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
@@ -217,6 +219,8 @@
 };
 
 &usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h
@@ -130,7 +130,7 @@
 #define MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                                     0x0A4 0x30C 0x000 0x0 0x0
 #define MX8MQ_IOMUXC_SD1_CMD_GPIO2_IO1                                      0x0A4 0x30C 0x000 0x5 0x0
 #define MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0                                 0x0A8 0x310 0x000 0x0 0x0
-#define MX8MQ_IOMUXC_SD1_DATA0_GPIO2_IO2                                    0x0A8 0x31  0x000 0x5 0x0
+#define MX8MQ_IOMUXC_SD1_DATA0_GPIO2_IO2                                    0x0A8 0x310 0x000 0x5 0x0
 #define MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1                                 0x0AC 0x314 0x000 0x0 0x0
 #define MX8MQ_IOMUXC_SD1_DATA1_GPIO2_IO3                                    0x0AC 0x314 0x000 0x5 0x0
 #define MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2                                 0x0B0 0x318 0x000 0x0 0x0
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-sr-som.dtsi
@@ -170,6 +170,8 @@
 };
 
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi
@@ -45,8 +45,8 @@
 	reg_12p0_main: regulator-12p0-main {
 		compatible = "regulator-fixed";
 		regulator-name = "12V_MAIN";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
 		regulator-always-on;
 	};
 
@@ -486,6 +486,8 @@
 };
 
 &usdhc1 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
+	assigned-clock-rates = <400000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1>;
 	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
@@ -499,6 +501,8 @@
 };
 
 &usdhc2 {
+	assigned-clocks = <&clk IMX8MQ_CLK_USDHC2>;
+	assigned-clock-rates = <200000000>;
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -20,6 +20,7 @@
 	#size-cells = <2>;
 
 	aliases {
+		ethernet0 = &fec1;
 		gpio0 = &gpio1;
 		gpio1 = &gpio2;
 		gpio2 = &gpio3;
@@ -29,6 +30,8 @@
 		i2c1 = &i2c2;
 		i2c2 = &i2c3;
 		i2c3 = &i2c4;
+		mmc0 = &usdhc1;
+		mmc1 = &usdhc2;
 		serial0 = &uart1;
 		serial1 = &uart2;
 		serial2 = &uart3;
@@ -98,6 +101,12 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MQ_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			#cooling-cells = <2>;
@@ -112,6 +121,12 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MQ_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			#cooling-cells = <2>;
@@ -124,6 +139,12 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MQ_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			#cooling-cells = <2>;
@@ -136,6 +157,12 @@
 			clock-latency = <61036>; /* two CLK32 periods */
 			clocks = <&clk IMX8MQ_CLK_ARM>;
 			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
 			next-level-cache = <&A53_L2>;
 			operating-points-v2 = <&a53_opp_table>;
 			#cooling-cells = <2>;
@@ -143,6 +170,10 @@
 
 		A53_L2: l2-cache0 {
 			compatible = "cache";
+			cache-level = <2>;
+			cache-size = <0x100000>;
+			cache-line-size = <64>;
+			cache-sets = <1024>;
 		};
 	};
 
@@ -198,7 +229,7 @@
 	};
 
 	thermal-zones {
-		cpu-thermal {
+		cpu_thermal: cpu-thermal {
 			polling-delay-passive = <250>;
 			polling-delay = <2000>;
 			thermal-sensors = <&tmu 0>;
@@ -229,7 +260,7 @@
 			};
 		};
 
-		gpu-thermal {
+		gpu_thermal: gpu-thermal {
 			polling-delay-passive = <250>;
 			polling-delay = <2000>;
 			thermal-sensors = <&tmu 1>;
@@ -243,7 +274,7 @@
 			};
 		};
 
-		vpu-thermal {
+		vpu_thermal: vpu-thermal {
 			polling-delay-passive = <250>;
 			polling-delay = <2000>;
 			thermal-sensors = <&tmu 2>;
@@ -269,18 +300,82 @@
 	};
 
 	soc@0 {
-		compatible = "simple-bus";
+		compatible = "fsl,imx8mq-soc", "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0x0 0x0 0x3e000000>;
 		dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>;
+		nvmem-cells = <&imx8mq_uid>;
+		nvmem-cell-names = "soc_unique_id";
+
+		caam_sm: caam-sm@100000 {
+			compatible = "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
 
 		bus@30000000 { /* AIPS1 */
-			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30000000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x30000000 0x30000000 0x400000>;
 
+			sai1: sai@30010000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x30010000 0x10000>;
+				interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_SAI1_IPG>,
+				         <&clk IMX8MQ_CLK_SAI1_ROOT>,
+				         <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+				clock-names = "bus", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma2 8 24 0>, <&sdma1 9 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			sai6: sai@30030000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x30030000 0x10000>;
+				interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_SAI6_IPG>,
+				         <&clk IMX8MQ_CLK_SAI6_ROOT>,
+				         <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+				clock-names = "bus", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma2 4 24 0>, <&sdma2 5 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			sai5: sai@30040000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x30040000 0x10000>;
+				interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_SAI5_IPG>,
+				         <&clk IMX8MQ_CLK_SAI5_ROOT>,
+				         <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+				clock-names = "bus", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma2 2 24 0>, <&sdma2 3 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			sai4: sai@30050000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x30050000 0x10000>;
+				interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_SAI4_IPG>,
+				         <&clk IMX8MQ_CLK_SAI4_ROOT>,
+				         <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+				clock-names = "bus", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma2 0 24 0>, <&sdma2 1 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			gpio1: gpio@30200000 {
 				compatible = "fsl,imx8mq-gpio", "fsl,imx35-gpio";
 				reg = <0x30200000 0x10000>;
@@ -349,7 +444,7 @@
 			tmu: tmu@30260000 {
 				compatible = "fsl,imx8mq-tmu";
 				reg = <0x30260000 0x10000>;
-				interrupt = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MQ_CLK_TMU_ROOT>;
 				little-endian;
 				fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>;
@@ -434,7 +529,30 @@
 				fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
 			};
 
-			iomuxc: iomuxc@30330000 {
+			lcdif: lcd-controller@30320000 {
+				compatible = "fsl,imx8mq-lcdif", "fsl,imx28-lcdif";
+				reg = <0x30320000 0x10000>;
+				interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_LCDIF_PIXEL>;
+				clock-names = "pix";
+				assigned-clocks = <&clk IMX8MQ_VIDEO_PLL1_REF_SEL>,
+						  <&clk IMX8MQ_VIDEO_PLL1_BYPASS>,
+						  <&clk IMX8MQ_CLK_LCDIF_PIXEL>,
+						  <&clk IMX8MQ_VIDEO_PLL1>;
+				assigned-clock-parents = <&clk IMX8MQ_CLK_25M>,
+						  <&clk IMX8MQ_VIDEO_PLL1>,
+						  <&clk IMX8MQ_VIDEO_PLL1_OUT>;
+				assigned-clock-rates = <0>, <0>, <0>, <594000000>;
+				status = "disabled";
+
+				port@0 {
+					lcdif_mipi_dsi: endpoint {
+						remote-endpoint = <&mipi_dsi_lcdif_in>;
+					};
+				};
+			};
+
+			iomuxc: pinctrl@30330000 {
 				compatible = "fsl,imx8mq-iomuxc";
 				reg = <0x30330000 0x10000>;
 			};
@@ -451,16 +569,24 @@
 				};
 			};
 
-			ocotp: ocotp-ctrl@30350000 {
+			ocotp: efuse@30350000 {
 				compatible = "fsl,imx8mq-ocotp", "syscon";
 				reg = <0x30350000 0x10000>;
 				clocks = <&clk IMX8MQ_CLK_OCOTP_ROOT>;
 				#address-cells = <1>;
 				#size-cells = <1>;
 
+				imx8mq_uid: soc-uid@410 {
+					reg = <0x4 0x8>;
+				};
+
 				cpu_speed_grade: speed-grade@10 {
 					reg = <0x10 4>;
 				};
+
+				fec_mac_address: mac-address@90 {
+					reg = <0x90 6>;
+				};
 			};
 
 			anatop: syscon@30360000 {
@@ -487,6 +613,8 @@
 					compatible = "fsl,sec-v4.0-pwrkey";
 					regmap = <&snvs>;
 					interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MQ_CLK_SNVS_ROOT>;
+					clock-names = "snvs-pwrkey";
 					linux,keycode = <KEY_POWER>;
 					wakeup-source;
 					status = "disabled";
@@ -505,17 +633,40 @@
 				clock-names = "ckil", "osc_25m", "osc_27m",
 				              "clk_ext1", "clk_ext2",
 				              "clk_ext3", "clk_ext4";
+				assigned-clocks = <&clk IMX8MQ_CLK_A53_SRC>,
+						  <&clk IMX8MQ_CLK_A53_CORE>,
+						  <&clk IMX8MQ_CLK_NOC>,
+						  <&clk IMX8MQ_CLK_AUDIO_AHB>,
+						  <&clk IMX8MQ_AUDIO_PLL1_BYPASS>,
+						  <&clk IMX8MQ_AUDIO_PLL2_BYPASS>,
+						  <&clk IMX8MQ_AUDIO_PLL1>,
+						  <&clk IMX8MQ_AUDIO_PLL2>;
+				assigned-clock-rates = <0>, <0>,
+						       <800000000>,
+						       <0>,
+						       <0>,
+						       <0>,
+						       <786432000>,
+						       <722534400>;
+				assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>,
+							 <&clk IMX8MQ_ARM_PLL_OUT>,
+							 <0>,
+							 <&clk IMX8MQ_SYS2_PLL_500M>,
+							 <&clk IMX8MQ_AUDIO_PLL1>,
+							 <&clk IMX8MQ_AUDIO_PLL2>;
 			};
 
 			src: reset-controller@30390000 {
 				compatible = "fsl,imx8mq-src", "syscon";
 				reg = <0x30390000 0x10000>;
+				interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 				#reset-cells = <1>;
 			};
 
 			gpc: gpc@303a0000 {
 				compatible = "fsl,imx8mq-gpc";
 				reg = <0x303a0000 0x10000>;
+				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-parent = <&gic>;
 				interrupt-controller;
 				#interrupt-cells = <3>;
@@ -577,6 +728,7 @@
 					pgc_vpu: power-domain@6 {
 						#power-domain-cells = <0>;
 						reg = <IMX8M_POWER_DOMAIN_VPU>;
+						clocks = <&clk IMX8MQ_CLK_VPU_DEC_ROOT>;
 					};
 
 					pgc_disp: power-domain@7 {
@@ -603,7 +755,8 @@
 		};
 
 		bus@30400000 { /* AIPS2 */
-			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30400000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x30400000 0x30400000 0x400000>;
@@ -662,12 +815,37 @@
 		};
 
 		bus@30800000 { /* AIPS3 */
-			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x30800000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x30800000 0x30800000 0x400000>,
 				 <0x08000000 0x08000000 0x10000000>;
 
+			spdif1: spdif@30810000 {
+				compatible = "fsl,imx35-spdif";
+				reg = <0x30810000 0x10000>;
+				interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_IPG_ROOT>, /* core */
+					<&clk IMX8MQ_CLK_25M>, /* rxtx0 */
+					<&clk IMX8MQ_CLK_SPDIF1>, /* rxtx1 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx2 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx3 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx4 */
+					<&clk IMX8MQ_CLK_IPG_ROOT>, /* rxtx5 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx6 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx7 */
+					<&clk IMX8MQ_CLK_DUMMY>; /* spba */
+				clock-names = "core", "rxtx0",
+					      "rxtx1", "rxtx2",
+					      "rxtx3", "rxtx4",
+					      "rxtx5", "rxtx6",
+					      "rxtx7", "spba";
+				dmas = <&sdma1 8 18 0>, <&sdma1 9 18 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			ecspi1: spi@30820000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -737,6 +915,30 @@
 				status = "disabled";
 			};
 
+			spdif2: spdif@308a0000 {
+				compatible = "fsl,imx35-spdif";
+				reg = <0x308a0000 0x10000>;
+				interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_IPG_ROOT>, /* core */
+					<&clk IMX8MQ_CLK_25M>, /* rxtx0 */
+					<&clk IMX8MQ_CLK_SPDIF2>, /* rxtx1 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx2 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx3 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx4 */
+					<&clk IMX8MQ_CLK_IPG_ROOT>, /* rxtx5 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx6 */
+					<&clk IMX8MQ_CLK_DUMMY>, /* rxtx7 */
+					<&clk IMX8MQ_CLK_DUMMY>; /* spba */
+				clock-names = "core", "rxtx0",
+					      "rxtx1", "rxtx2",
+					      "rxtx3", "rxtx4",
+					      "rxtx5", "rxtx6",
+					      "rxtx7", "spba";
+				dmas = <&sdma1 16 18 0>, <&sdma1 17 18 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			sai2: sai@308b0000 {
 				#sound-dai-cells = <0>;
 				compatible = "fsl,imx8mq-sai";
@@ -751,6 +953,20 @@
 				status = "disabled";
 			};
 
+			sai3: sai@308c0000 {
+				#sound-dai-cells = <0>;
+				compatible = "fsl,imx8mq-sai";
+				reg = <0x308c0000 0x10000>;
+				interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_SAI3_IPG>,
+				         <&clk IMX8MQ_CLK_SAI3_ROOT>,
+				         <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+				clock-names = "bus", "mclk1", "mclk2", "mclk3";
+				dmas = <&sdma1 12 24 0>, <&sdma1 13 24 0>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			crypto: crypto@30900000 {
 				compatible = "fsl,sec-v4.0";
 				#address-cells = <1>;
@@ -781,14 +997,62 @@
 				};
 			};
 
+			mipi_dsi: mipi-dsi@30a00000 {
+				compatible = "fsl,imx8mq-nwl-dsi";
+				reg = <0x30a00000 0x300>;
+				clocks = <&clk IMX8MQ_CLK_DSI_CORE>,
+					 <&clk IMX8MQ_CLK_DSI_AHB>,
+					 <&clk IMX8MQ_CLK_DSI_IPG_DIV>,
+					 <&clk IMX8MQ_CLK_DSI_PHY_REF>,
+					 <&clk IMX8MQ_CLK_LCDIF_PIXEL>;
+				clock-names = "core", "rx_esc", "tx_esc", "phy_ref", "lcdif";
+				assigned-clocks = <&clk IMX8MQ_CLK_DSI_AHB>,
+						  <&clk IMX8MQ_CLK_DSI_CORE>,
+						  <&clk IMX8MQ_CLK_DSI_IPG_DIV>;
+				assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>,
+							 <&clk IMX8MQ_SYS1_PLL_266M>;
+				assigned-clock-rates = <80000000>, <266000000>, <20000000>;
+				interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+				mux-controls = <&mux 0>;
+				power-domains = <&pgc_mipi>;
+				phys = <&dphy>;
+				phy-names = "dphy";
+				resets = <&src IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N>,
+					 <&src IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N>,
+					 <&src IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N>,
+					 <&src IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N>;
+				reset-names = "byte", "dpi", "esc", "pclk";
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+						#address-cells = <1>;
+						#size-cells = <0>;
+						mipi_dsi_lcdif_in: endpoint@0 {
+							reg = <0>;
+							remote-endpoint = <&lcdif_mipi_dsi>;
+						};
+					};
+				};
+			};
+
 			dphy: dphy@30a00300 {
 				compatible = "fsl,imx8mq-mipi-dphy";
 				reg = <0x30a00300 0x100>;
 				clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
 				clock-names = "phy_ref";
-				assigned-clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
-				assigned-clock-parents = <&clk IMX8MQ_VIDEO_PLL1_OUT>;
-				assigned-clock-rates = <24000000>;
+				assigned-clocks = <&clk IMX8MQ_VIDEO_PLL1_REF_SEL>,
+						  <&clk IMX8MQ_VIDEO_PLL1_BYPASS>,
+						  <&clk IMX8MQ_CLK_DSI_PHY_REF>,
+						  <&clk IMX8MQ_VIDEO_PLL1>;
+				assigned-clock-parents = <&clk IMX8MQ_CLK_25M>,
+						  <&clk IMX8MQ_VIDEO_PLL1>,
+						  <&clk IMX8MQ_VIDEO_PLL1_OUT>;
+				assigned-clock-rates = <0>, <0>, <24000000>, <594000000>;
 				#phy-cells = <0>;
 				power-domains = <&pgc_mipi>;
 				status = "disabled";
@@ -845,6 +1109,14 @@
 				status = "disabled";
 			};
 
+			mu: mailbox@30aa0000 {
+				compatible = "fsl,imx8mq-mu", "fsl,imx6sx-mu";
+				reg = <0x30aa0000 0x10000>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MQ_CLK_MU_ROOT>;
+				#mbox-cells = <2>;
+			};
+
 			usdhc1: mmc@30b40000 {
 				compatible = "fsl,imx8mq-usdhc",
 				             "fsl,imx7d-usdhc";
@@ -854,8 +1126,6 @@
 				         <&clk IMX8MQ_CLK_NAND_USDHC_BUS>,
 				         <&clk IMX8MQ_CLK_USDHC1_ROOT>;
 				clock-names = "ipg", "ahb", "per";
-				assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>;
-				assigned-clock-rates = <400000000>;
 				fsl,tuning-start-tap = <20>;
 				fsl,tuning-step = <2>;
 				bus-width = <4>;
@@ -907,7 +1177,8 @@
 				reg = <0x30be0000 0x10000>;
 				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 				             <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
-				             <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+					     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clk IMX8MQ_CLK_ENET1_ROOT>,
 				         <&clk IMX8MQ_CLK_ENET1_ROOT>,
 				         <&clk IMX8MQ_CLK_ENET_TIMER>,
@@ -915,18 +1186,40 @@
 				         <&clk IMX8MQ_CLK_ENET_PHY_REF>;
 				clock-names = "ipg", "ahb", "ptp",
 				              "enet_clk_ref", "enet_out";
+				assigned-clocks = <&clk IMX8MQ_CLK_ENET_AXI>,
+						  <&clk IMX8MQ_CLK_ENET_TIMER>,
+						  <&clk IMX8MQ_CLK_ENET_REF>,
+						  <&clk IMX8MQ_CLK_ENET_PHY_REF>;
+				assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_266M>,
+							 <&clk IMX8MQ_SYS2_PLL_100M>,
+							 <&clk IMX8MQ_SYS2_PLL_125M>,
+							 <&clk IMX8MQ_SYS2_PLL_50M>;
+				assigned-clock-rates = <0>, <100000000>, <125000000>, <0>;
 				fsl,num-tx-queues = <3>;
 				fsl,num-rx-queues = <3>;
+				nvmem-cells = <&fec_mac_address>;
+				nvmem-cell-names = "mac-address";
+				nvmem_macaddr_swap;
+				fsl,stop-mode = <&iomuxc_gpr 0x10 3>;
 				status = "disabled";
 			};
 		};
 
 		bus@32c00000 { /* AIPS4 */
-			compatible = "fsl,imx8mq-aips-bus", "simple-bus";
+			compatible = "fsl,aips-bus", "simple-bus";
+			reg = <0x32c00000 0x400000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges = <0x32c00000 0x32c00000 0x400000>;
 
+			hdmi: hdmi@32c00000 {
+				reg = <0x32c00000 0x100000>,
+					<0x32e40000 0x40000>;
+				interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+							 <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "plug_in", "plug_out";
+			};
+
 			irqsteer: interrupt-controller@32e2d000 {
 				compatible = "fsl,imx8m-irqsteer", "fsl,imx-irqsteer";
 				reg = <0x32e2d000 0x1000>;
@@ -938,6 +1231,35 @@
 				interrupt-controller;
 				#interrupt-cells = <1>;
 			};
+
+			dcss: dcss@0x32e00000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "nxp,imx8mq-dcss";
+				reg = <0x32e00000 0x2D000>, <0x32e2f000 0x1000>;
+				interrupts = <6>, <8>, <9>, <16>, <17>;
+				interrupt-names = "ctx_ld", "ctxld_kick", "vblank",
+								  "dtrc_ch1", "dtrc_ch2";
+				interrupt-parent = <&irqsteer>;
+				clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>,
+					 <&clk IMX8MQ_CLK_DISP_AXI_ROOT>,
+					 <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>,
+					 <&clk IMX8MQ_VIDEO2_PLL_OUT>,
+					 <&clk IMX8MQ_CLK_DISP_DTRC>,
+					 <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>,
+					 <&clk IMX8MQ_CLK_PHY_27MHZ>;
+				clock-names = "apb", "axi", "rtrm", "pix", "dtrc", "pll_src",
+						      "pll_phy_ref";
+				assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>,
+						  <&clk IMX8MQ_CLK_DISP_RTRM>,
+						  <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>;
+				assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>,
+							 <&clk IMX8MQ_SYS1_PLL_800M>,
+							 <&clk IMX8MQ_CLK_27M>;
+				assigned-clock-rates = <800000000>,
+							   <400000000>;
+				status = "disabled";
+			};
 		};
 
 		gpu: gpu@38000000 {
@@ -1028,6 +1350,32 @@
 			status = "disabled";
 		};
 
+		vpu: video-codec@38300000 {
+			compatible = "nxp,imx8mq-vpu";
+			reg = <0x38300000 0x10000>,
+			      <0x38310000 0x10000>,
+			      <0x38320000 0x10000>;
+			reg-names = "g1", "g2", "ctrl";
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "g1", "g2";
+			clocks = <&clk IMX8MQ_CLK_VPU_G1_ROOT>,
+				 <&clk IMX8MQ_CLK_VPU_G2_ROOT>,
+				 <&clk IMX8MQ_CLK_VPU_DEC_ROOT>;
+			clock-names = "g1", "g2", "bus";
+			assigned-clocks = <&clk IMX8MQ_CLK_VPU_G1>,
+					  <&clk IMX8MQ_CLK_VPU_G2>,
+					  <&clk IMX8MQ_CLK_VPU_BUS>,
+					  <&clk IMX8MQ_VPU_PLL_BYPASS>;
+			assigned-clock-parents = <&clk IMX8MQ_VPU_PLL_OUT>,
+						 <&clk IMX8MQ_VPU_PLL_OUT>,
+						 <&clk IMX8MQ_SYS1_PLL_800M>,
+						 <&clk IMX8MQ_VPU_PLL>;
+			assigned-clock-rates = <600000000>, <600000000>,
+					       <800000000>, <0>;
+			power-domains = <&pgc_vpu>;
+		};
+
 		pcie0: pcie@33800000 {
 			compatible = "fsl,imx8mq-pcie";
 			reg = <0x33800000 0x400000>,
@@ -1050,11 +1398,20 @@
 			                <0 0 0 3 &gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
 			                <0 0 0 4 &gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
 			fsl,max-link-speed = <2>;
+			linux,pci-domain = <0>;
 			power-domains = <&pgc_pcie>;
 			resets = <&src IMX8MQ_RESET_PCIEPHY>,
 			         <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
 			         <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
 			reset-names = "pciephy", "apps", "turnoff";
+			assigned-clocks = <&clk IMX8MQ_CLK_PCIE1_CTRL>,
+			                  <&clk IMX8MQ_CLK_PCIE1_PHY>,
+			                  <&clk IMX8MQ_CLK_PCIE1_AUX>;
+			assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_250M>,
+			                         <&clk IMX8MQ_SYS2_PLL_100M>,
+			                         <&clk IMX8MQ_SYS1_PLL_80M>;
+			assigned-clock-rates = <250000000>, <100000000>,
+			                       <10000000>;
 			status = "disabled";
 		};
 
@@ -1079,11 +1436,20 @@
 					<0 0 0 3 &gic GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
 					<0 0 0 4 &gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
 			fsl,max-link-speed = <2>;
+			linux,pci-domain = <1>;
 			power-domains = <&pgc_pcie>;
 			resets = <&src IMX8MQ_RESET_PCIEPHY2>,
 			         <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_EN>,
 			         <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF>;
 			reset-names = "pciephy", "apps", "turnoff";
+			assigned-clocks = <&clk IMX8MQ_CLK_PCIE2_CTRL>,
+			                  <&clk IMX8MQ_CLK_PCIE2_PHY>,
+			                  <&clk IMX8MQ_CLK_PCIE2_AUX>;
+			assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_250M>,
+			                         <&clk IMX8MQ_SYS2_PLL_100M>,
+			                         <&clk IMX8MQ_SYS1_PLL_80M>;
+			assigned-clock-rates = <250000000>, <100000000>,
+			                       <10000000>;
 			status = "disabled";
 		};
 
@@ -1100,6 +1466,16 @@
 			interrupt-parent = <&gic>;
 		};
 
+		ddrc: memory-controller@3d400000 {
+			compatible = "fsl,imx8mq-ddrc", "fsl,imx8m-ddrc";
+			reg = <0x3d400000 0x400000>;
+			clock-names = "core", "pll", "alt", "apb";
+			clocks = <&clk IMX8MQ_CLK_DRAM_CORE>,
+				 <&clk IMX8MQ_DRAM_PLL_OUT>,
+				 <&clk IMX8MQ_CLK_DRAM_ALT>,
+				 <&clk IMX8MQ_CLK_DRAM_APB>;
+		};
+
 		ddr-pmu@3d800000 {
 			compatible = "fsl,imx8mq-ddr-pmu", "fsl,imx8m-ddr-pmu";
 			reg = <0x3d800000 0x400000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
@@ -52,11 +52,6 @@
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
 		};
-
-		ethphy1: ethernet-phy@1 {
-			compatible = "ethernet-phy-ieee802.3-c22";
-			reg = <1>;
-		};
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/pinctrl/pads-imx8qxp.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -182,6 +183,11 @@
 			compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
 			timeout-sec = <60>;
 		};
+
+		tsens: thermal-sensor {
+			compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
+			#thermal-sensor-cells = <1>;
+		};
 	};
 
 	timer {
@@ -597,4 +603,37 @@
 			#clock-cells = <1>;
 		};
 	};
+
+	thermal_zones: thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <2000>;
+			thermal-sensors = <&tsens IMX_SC_R_SYSTEM>;
+
+			trips {
+				cpu_alert0: trip0 {
+					temperature = <107000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit0: trip1 {
+					temperature = <127000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&A35_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A35_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A35_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&A35_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
@@ -530,6 +530,17 @@
 		status = "ok";
 		compatible = "adi,adv7533";
 		reg = <0x39>;
+		adi,dsi-lanes = <4>;
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+			};
+			port@1 {
+				reg = <1>;
+			};
+		};
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
@@ -1086,7 +1086,7 @@
 		};
 
 		watchdog0: watchdog@e8a06000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xe8a06000 0x0 0x1000>;
 			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&crg_ctrl HI3660_OSC32K>;
@@ -1094,7 +1094,7 @@
 		};
 
 		watchdog1: watchdog@e8a07000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xe8a07000 0x0 0x1000>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&crg_ctrl HI3660_OSC32K>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -516,7 +516,7 @@
 		reg = <0x39>;
 		interrupt-parent = <&gpio1>;
 		interrupts = <1 2>;
-		pd-gpio = <&gpio0 4 0>;
+		pd-gpios = <&gpio0 4 0>;
 		adi,dsi-lanes = <4>;
 		#sound-dai-cells = <0>;
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -839,7 +839,7 @@
 		};
 
 		watchdog0: watchdog@f8005000 {
-			compatible = "arm,sp805-wdt", "arm,primecell";
+			compatible = "arm,sp805", "arm,primecell";
 			reg = <0x0 0xf8005000 0x0 0x1000>;
 			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ao_ctrl HI6220_WDT0_PCLK>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
@@ -47,10 +47,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>,
@@ -82,7 +82,7 @@
 		ranges = <0 0 0 0xffffffff>;
 
 		gmac0: ethernet@ff800000 {
-			compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+			compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
 			reg = <0xff800000 0x2000>;
 			interrupts = <0 90 4>;
 			interrupt-names = "macirq";
@@ -97,7 +97,7 @@
 		};
 
 		gmac1: ethernet@ff802000 {
-			compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+			compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
 			reg = <0xff802000 0x2000>;
 			interrupts = <0 91 4>;
 			interrupt-names = "macirq";
@@ -112,7 +112,7 @@
 		};
 
 		gmac2: ethernet@ff804000 {
-			compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+			compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
 			reg = <0xff804000 0x2000>;
 			interrupts = <0 92 4>;
 			interrupt-names = "macirq";
@@ -369,7 +369,7 @@
 		};
 
 		usb0: usb@ffb00000 {
-			compatible = "snps,dwc2";
+			compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
 			reg = <0xffb00000 0x40000>;
 			interrupts = <0 93 4>;
 			phys = <&usbphy0>;
@@ -381,7 +381,7 @@
 		};
 
 		usb1: usb@ffb40000 {
-			compatible = "snps,dwc2";
+			compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
 			reg = <0xffb40000 0x40000>;
 			interrupts = <0 94 4>;
 			phys = <&usbphy0>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -128,6 +128,9 @@
 
 /* CON15(V2.0)/CON17(V1.4) : PCIe / CON15(V2.0)/CON12(V1.4) :mini-PCIe */
 &pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
+	reset-gpios = <&gpiosb 3 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -19,6 +19,16 @@
 	model = "Globalscale Marvell ESPRESSOBin Board";
 	compatible = "globalscale,espressobin", "marvell,armada3720", "marvell,armada3710";
 
+	aliases {
+		ethernet0 = &eth0;
+		/* for dsa slave device */
+		ethernet1 = &switch0port1;
+		ethernet2 = &switch0port2;
+		ethernet3 = &switch0port3;
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
@@ -49,6 +59,7 @@
 	phys = <&comphy1 0>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
+	reset-gpios = <&gpiosb 3 GPIO_ACTIVE_LOW>;
 };
 
 /* J6 */
@@ -141,7 +152,7 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			port@0 {
+			switch0port0: port@0 {
 				reg = <0>;
 				label = "cpu";
 				ethernet = <&eth0>;
@@ -152,19 +163,19 @@
 				};
 			};
 
-			port@1 {
+			switch0port1: port@1 {
 				reg = <1>;
 				label = "wan";
 				phy-handle = <&switch0phy0>;
 			};
 
-			port@2 {
+			switch0port2: port@2 {
 				reg = <2>;
 				label = "lan0";
 				phy-handle = <&switch0phy1>;
 			};
 
-			port@3 {
+			switch0port3: port@3 {
 				reg = <3>;
 				label = "lan1";
 				phy-handle = <&switch0phy2>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
@@ -18,6 +18,7 @@
 
 	aliases {
 		spi0 = &spi0;
+		ethernet0 = &eth0;
 		ethernet1 = &eth1;
 	};
 
@@ -95,7 +96,7 @@
 	};
 
 	sfp: sfp {
-		compatible = "sff,sfp+";
+		compatible = "sff,sfp";
 		i2c-bus = <&i2c0>;
 		los-gpio = <&moxtet_sfp 0 GPIO_ACTIVE_HIGH>;
 		tx-fault-gpio = <&moxtet_sfp 1 GPIO_ACTIVE_HIGH>;
@@ -106,24 +107,30 @@
 		/* enabled by U-Boot if SFP module is present */
 		status = "disabled";
 	};
+
+	firmware {
+		armada-3700-rwtm {
+			compatible = "marvell,armada-3700-rwtm-firmware", "cznic,turris-mox-rwtm";
+		};
+	};
 };
 
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <100000>;
+	/delete-property/ mrvl,i2c-fast-mode;
 	status = "okay";
 
+	/* MCP7940MT-I/MNY RTC */
 	rtc@6f {
 		compatible = "microchip,mcp7940x";
 		reg = <0x6f>;
+		interrupt-parent = <&gpiosb>;
+		interrupts = <5 IRQ_TYPE_EDGE_FALLING>; /* GPIO2_5 */
 	};
 };
 
-&pcie_reset_pins {
-	function = "gpio";
-};
-
 &pcie0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie_reset_pins &pcie_clkreq_pins>;
@@ -131,6 +138,28 @@
 	max-link-speed = <2>;
 	reset-gpios = <&gpiosb 3 GPIO_ACTIVE_LOW>;
 	phys = <&comphy1 0>;
+	/*
+	 * U-Boot port for Turris Mox has a bug which always expects that "ranges" DT property
+	 * contains exactly 2 ranges with 3 (child) address cells, 2 (parent) address cells and
+	 * 2 size cells and also expects that the second range starts at 16 MB offset. Also it
+	 * expects that first range uses same address for PCI (child) and CPU (parent) cells (so
+	 * no remapping) and that this address is the lowest from all specified ranges. If these
+	 * conditions are not met then U-Boot crashes during loading kernel DTB file. PCIe address
+	 * space is 128 MB long, so the best split between MEM and IO is to use fixed 16 MB window
+	 * for IO and the rest 112 MB (64+32+16) for MEM, despite that maximal IO size is just 64 kB.
+	 * This bug is not present in U-Boot ports for other Armada 3700 devices and is fixed in
+	 * U-Boot version 2021.07. See relevant U-Boot commits (the last one contains fix):
+	 * https://source.denx.de/u-boot/u-boot/-/commit/cb2ddb291ee6fcbddd6d8f4ff49089dfe580f5d7
+	 * https://source.denx.de/u-boot/u-boot/-/commit/c64ac3b3185aeb3846297ad7391fc6df8ecd73bf
+	 * https://source.denx.de/u-boot/u-boot/-/commit/4a82fca8e330157081fc132a591ebd99ba02ee33
+	 * Bug related to requirement of same child and parent addresses for first range is fixed
+	 * in U-Boot version 2022.04 by following commit:
+	 * https://source.denx.de/u-boot/u-boot/-/commit/1fd54253bca7d43d046bba4853fe5fafd034bc17
+	 */
+	#address-cells = <3>;
+	#size-cells = <2>;
+	ranges = <0x81000000 0 0xe8000000   0 0xe8000000   0 0x01000000   /* Port 0 IO */
+		  0x82000000 0 0xe9000000   0 0xe9000000   0 0x07000000>; /* Port 0 MEM */
 
 	/* enabled by U-Boot if PCIe module is present */
 	status = "disabled";
@@ -144,7 +173,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmii_pins>;
 	phy-mode = "rgmii-id";
-	phy = <&phy1>;
+	phy-handle = <&phy1>;
 	status = "okay";
 };
 
@@ -171,6 +200,8 @@
 	marvell,pad-type = "sd";
 	vqmmc-supply = <&vsdio_reg>;
 	mmc-pwrseq = <&sdhci1_pwrseq>;
+	/* forbid SDR104 for FCC purposes */
+	sdhci-caps-mask = <0x2 0x0>;
 	status = "okay";
 };
 
@@ -200,7 +231,7 @@
 			};
 
 			partition@20000 {
-				label = "u-boot";
+				label = "a53-firmware";
 				reg = <0x20000 0x160000>;
 			};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
@@ -143,6 +143,7 @@
 	phy-mode = "sgmii";
 	status = "okay";
 	managed = "in-band-status";
+	phys = <&comphy1 0>;
 	sfp = <&sfp_eth0>;
 };
 
@@ -150,11 +151,14 @@
 	phy-mode = "sgmii";
 	status = "okay";
 	managed = "in-band-status";
+	phys = <&comphy0 1>;
 	sfp = <&sfp_eth1>;
 };
 
 &usb3 {
 	status = "okay";
+	phys = <&usb2_utmi_otg_phy>;
+	phy-names = "usb2-utmi-otg-phy";
 };
 
 &uart0 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -134,7 +134,7 @@
 
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
-				reg = <0x12000 0x200>;
+				reg = <0x12000 0x18>;
 				clocks = <&xtalclk>;
 				interrupts =
 				<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
@@ -156,7 +156,8 @@
 			};
 
 			nb_periph_clk: nb-periph-clk@13000 {
-				compatible = "marvell,armada-3700-periph-clock-nb";
+				compatible = "marvell,armada-3700-periph-clock-nb",
+					     "syscon";
 				reg = <0x13000 0x100>;
 				clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
 				<&tbg 3>, <&xtalclk>;
@@ -317,7 +318,7 @@
 
 				pcie_reset_pins: pcie-reset-pins {
 					groups = "pcie1";
-					function = "pcie";
+					function = "gpio";
 				};
 
 				pcie_clkreq_pins: pcie-clkreq-pins {
@@ -486,8 +487,15 @@
 			#interrupt-cells = <1>;
 			msi-parent = <&pcie0>;
 			msi-controller;
-			ranges = <0x82000000 0 0xe8000000   0 0xe8000000 0 0x1000000 /* Port 0 MEM */
-				  0x81000000 0 0xe9000000   0 0xe9000000 0 0x10000>; /* Port 0 IO*/
+			/*
+			 * The 128 MiB address range [0xe8000000-0xf0000000] is
+			 * dedicated for PCIe and can be assigned to 8 windows
+			 * with size a power of two. Use one 64 KiB window for
+			 * IO at the end and the remaining seven windows
+			 * (totaling 127 MiB) for MEM.
+			 */
+			ranges = <0x82000000 0 0xe8000000   0 0xe8000000   0 0x07f00000   /* Port 0 MEM */
+				  0x81000000 0 0x00000000   0 0xefff0000   0 0x00010000>; /* Port 0 IO */
 			interrupt-map-mask = <0 0 0 7>;
 			interrupt-map = <0 0 0 1 &pcie_intc 0>,
 					<0 0 0 2 &pcie_intc 1>,
@@ -499,4 +507,12 @@
 			};
 		};
 	};
+
+	firmware {
+		armada-3700-rwtm {
+			compatible = "marvell,armada-3700-rwtm-firmware";
+			mboxes = <&rwtm 0>;
+			status = "okay";
+		};
+	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts
@@ -367,6 +367,7 @@
 		pinctrl-0 = <&cp0_copper_eth_phy_reset>;
 		reset-gpios = <&cp0_gpio2 11 GPIO_ACTIVE_LOW>;
 		reset-assert-us = <10000>;
+		reset-deassert-us = <10000>;
 	};
 
 	switch0: switch0@4 {
@@ -408,6 +409,8 @@
 				reg = <5>;
 				label = "cpu";
 				ethernet = <&cp1_eth2>;
+				phy-mode = "2500base-x";
+				managed = "in-band-status";
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
@@ -71,6 +71,7 @@
 		tx-fault-gpio  = <&cp1_gpio1 26 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&cp1_sfpp0_pins>;
+		maximum-power-milliwatt = <2000>;
 	};
 
 	sfp_eth1: sfp-eth1 {
@@ -83,6 +84,7 @@
 		tx-fault-gpio = <&cp0_gpio2 30 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&cp1_sfpp1_pins &cp0_sfpp1_pins>;
+		maximum-power-milliwatt = <2000>;
 	};
 
 	sfp_eth3: sfp-eth3 {
@@ -95,6 +97,7 @@
 		tx-fault-gpio = <&cp0_gpio2 19 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&cp0_sfp_1g_pins &cp1_sfp_1g_pins>;
+		maximum-power-milliwatt = <2000>;
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
@@ -21,6 +21,7 @@
 			reg = <0x000>;
 			enable-method = "psci";
 			#cooling-cells = <2>;
+			clocks = <&cpu_clk 0>;
 		};
 		cpu1: cpu@1 {
 			device_type = "cpu";
@@ -28,6 +29,7 @@
 			reg = <0x001>;
 			enable-method = "psci";
 			#cooling-cells = <2>;
+			clocks = <&cpu_clk 0>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -438,10 +438,10 @@
 
 		CP110_LABEL(nand_controller): nand@720000 {
 			/*
-			* Due to the limitation of the pins available
-			* this controller is only usable on the CPM
-			* for A7K and on the CPS for A8K.
-			*/
+			 * Due to the limitation of the pins available
+			 * this controller is only usable on the CPM
+			 * for A7K and on the CPS for A8K.
+			 */
 			compatible = "marvell,armada-8k-nand-controller",
 				"marvell,armada370-nand-controller";
 			reg = <0x720000 0x54>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
@@ -26,14 +26,14 @@
 		stdout-path = "serial0:921600n8";
 	};
 
-	cpus_fixed_vproc0: fixedregulator@0 {
+	cpus_fixed_vproc0: regulator-vproc-buck0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vproc_buck0";
 		regulator-min-microvolt = <1000000>;
 		regulator-max-microvolt = <1000000>;
 	};
 
-	cpus_fixed_vproc1: fixedregulator@1 {
+	cpus_fixed_vproc1: regulator-vproc-buck1 {
 		compatible = "regulator-fixed";
 		regulator-name = "vproc_buck1";
 		regulator-min-microvolt = <1000000>;
@@ -50,7 +50,7 @@
 		id-gpio = <&pio 14 GPIO_ACTIVE_HIGH>;
 	};
 
-	usb_p0_vbus: regulator@2 {
+	usb_p0_vbus: regulator-usb-p0-vbus {
 		compatible = "regulator-fixed";
 		regulator-name = "p0_vbus";
 		regulator-min-microvolt = <5000000>;
@@ -59,7 +59,7 @@
 		enable-active-high;
 	};
 
-	usb_p1_vbus: regulator@3 {
+	usb_p1_vbus: regulator-usb-p1-vbus {
 		compatible = "regulator-fixed";
 		regulator-name = "p1_vbus";
 		regulator-min-microvolt = <5000000>;
@@ -68,7 +68,7 @@
 		enable-active-high;
 	};
 
-	usb_p2_vbus: regulator@4 {
+	usb_p2_vbus: regulator-usb-p2-vbus {
 		compatible = "regulator-fixed";
 		regulator-name = "p2_vbus";
 		regulator-min-microvolt = <5000000>;
@@ -77,7 +77,7 @@
 		enable-active-high;
 	};
 
-	usb_p3_vbus: regulator@5 {
+	usb_p3_vbus: regulator-usb-p3-vbus {
 		compatible = "regulator-fixed";
 		regulator-name = "p3_vbus";
 		regulator-min-microvolt = <5000000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
@@ -160,70 +160,70 @@
 		#clock-cells = <0>;
 	};
 
-	clk26m: oscillator@0 {
+	clk26m: oscillator-26m {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <26000000>;
 		clock-output-names = "clk26m";
 	};
 
-	clk32k: oscillator@1 {
+	clk32k: oscillator-32k {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <32768>;
 		clock-output-names = "clk32k";
 	};
 
-	clkfpc: oscillator@2 {
+	clkfpc: oscillator-50m {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <50000000>;
 		clock-output-names = "clkfpc";
 	};
 
-	clkaud_ext_i_0: oscillator@3 {
+	clkaud_ext_i_0: oscillator-aud0 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <6500000>;
 		clock-output-names = "clkaud_ext_i_0";
 	};
 
-	clkaud_ext_i_1: oscillator@4 {
+	clkaud_ext_i_1: oscillator-aud1 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <196608000>;
 		clock-output-names = "clkaud_ext_i_1";
 	};
 
-	clkaud_ext_i_2: oscillator@5 {
+	clkaud_ext_i_2: oscillator-aud2 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <180633600>;
 		clock-output-names = "clkaud_ext_i_2";
 	};
 
-	clki2si0_mck_i: oscillator@6 {
+	clki2si0_mck_i: oscillator-i2s0 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <30000000>;
 		clock-output-names = "clki2si0_mck_i";
 	};
 
-	clki2si1_mck_i: oscillator@7 {
+	clki2si1_mck_i: oscillator-i2s1 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <30000000>;
 		clock-output-names = "clki2si1_mck_i";
 	};
 
-	clki2si2_mck_i: oscillator@8 {
+	clki2si2_mck_i: oscillator-i2s2 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <30000000>;
 		clock-output-names = "clki2si2_mck_i";
 	};
 
-	clktdmin_mclk_i: oscillator@9 {
+	clktdmin_mclk_i: oscillator-mclk {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <30000000>;
@@ -266,7 +266,7 @@
 		reg = <0 0x10005000 0 0x1000>;
 	};
 
-	pio: pinctrl@10005000 {
+	pio: pinctrl@1000b000 {
 		compatible = "mediatek,mt2712-pinctrl";
 		reg = <0 0x1000b000 0 0x1000>;
 		mediatek,pctl-regmap = <&syscfg_pctl_a>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt6797.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt6797.dtsi
@@ -102,7 +102,7 @@
 		};
 	};
 
-	clk26m: oscillator@0 {
+	clk26m: oscillator-26m {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <26000000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
@@ -49,7 +49,7 @@
 		wps {
 			label = "wps";
 			linux,code = <KEY_WPS_BUTTON>;
-			gpios = <&pio 102 GPIO_ACTIVE_HIGH>;
+			gpios = <&pio 102 GPIO_ACTIVE_LOW>;
 		};
 	};
 
@@ -69,7 +69,7 @@
 		};
 	};
 
-	memory {
+	memory@40000000 {
 		reg = <0 0x40000000 0 0x40000000>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
@@ -55,7 +55,7 @@
 		};
 	};
 
-	memory {
+	memory@40000000 {
 		reg = <0 0x40000000 0 0x20000000>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -428,6 +428,7 @@
 	pwm: pwm@11006000 {
 		compatible = "mediatek,mt7622-pwm";
 		reg = <0 0x11006000 0 0x1000>;
+		#pwm-cells = <2>;
 		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&topckgen CLK_TOP_PWM_SEL>,
 			 <&pericfg CLK_PERI_PWM_PD>,
@@ -686,6 +687,8 @@
 		clocks = <&pericfg CLK_PERI_MSDC30_0_PD>,
 			 <&topckgen CLK_TOP_MSDC50_0_SEL>;
 		clock-names = "source", "hclk";
+		resets = <&pericfg MT7622_PERI_MSDC0_SW_RST>;
+		reset-names = "hrst";
 		status = "disabled";
 	};
 
@@ -696,6 +699,8 @@
 		clocks = <&pericfg CLK_PERI_MSDC30_1_PD>,
 			 <&topckgen CLK_TOP_AXI_SEL>;
 		clock-names = "source", "hclk";
+		resets = <&pericfg MT7622_PERI_MSDC1_SW_RST>;
+		reset-names = "hrst";
 		status = "disabled";
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -43,7 +43,7 @@
 		id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>;
 	};
 
-	usb_p1_vbus: regulator@0 {
+	usb_p1_vbus: regulator-usb-p1 {
 		compatible = "regulator-fixed";
 		regulator-name = "usb_vbus";
 		regulator-min-microvolt = <5000000>;
@@ -52,7 +52,7 @@
 		enable-active-high;
 	};
 
-	usb_p0_vbus: regulator@1 {
+	usb_p0_vbus: regulator-usb-p0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vbus";
 		regulator-min-microvolt = <5000000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -238,21 +238,21 @@
 		cpu_on	      = <0x84000003>;
 	};
 
-	clk26m: oscillator@0 {
+	clk26m: oscillator0 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <26000000>;
 		clock-output-names = "clk26m";
 	};
 
-	clk32k: oscillator@1 {
+	clk32k: oscillator1 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <32000>;
 		clock-output-names = "clk32k";
 	};
 
-	cpum_ck: oscillator@2 {
+	cpum_ck: oscillator2 {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <0>;
@@ -268,19 +268,19 @@
 			sustainable-power = <1500>; /* milliwatts */
 
 			trips {
-				threshold: trip-point@0 {
+				threshold: trip-point0 {
 					temperature = <68000>;
 					hysteresis = <2000>;
 					type = "passive";
 				};
 
-				target: trip-point@1 {
+				target: trip-point1 {
 					temperature = <85000>;
 					hysteresis = <2000>;
 					type = "passive";
 				};
 
-				cpu_crit: cpu_crit@0 {
+				cpu_crit: cpu_crit0 {
 					temperature = <115000>;
 					hysteresis = <2000>;
 					type = "critical";
@@ -288,13 +288,13 @@
 			};
 
 			cooling-maps {
-				map@0 {
+				map0 {
 					trip = <&target>;
 					cooling-device = <&cpu0 0 0>,
 							 <&cpu1 0 0>;
 					contribution = <3072>;
 				};
-				map@1 {
+				map1 {
 					trip = <&target>;
 					cooling-device = <&cpu2 0 0>,
 							 <&cpu3 0 0>;
@@ -308,7 +308,7 @@
 		#address-cells = <2>;
 		#size-cells = <2>;
 		ranges;
-		vpu_dma_reserved: vpu_dma_mem_region {
+		vpu_dma_reserved: vpu_dma_mem_region@b7000000 {
 			compatible = "shared-dma-pool";
 			reg = <0 0xb7000000 0 0x500000>;
 			alignment = <0x1000>;
@@ -360,7 +360,7 @@
 			reg = <0 0x10005000 0 0x1000>;
 		};
 
-		pio: pinctrl@10005000 {
+		pio: pinctrl@1000b000 {
 			compatible = "mediatek,mt8173-pinctrl";
 			reg = <0 0x1000b000 0 0x1000>;
 			mediatek,pctl-regmap = <&syscfg_pctl_a>;
@@ -567,7 +567,7 @@
 			status = "disabled";
 		};
 
-		gic: interrupt-controller@10220000 {
+		gic: interrupt-controller@10221000 {
 			compatible = "arm,gic-400";
 			#interrupt-cells = <3>;
 			interrupt-parent = <&gic>;
@@ -1137,7 +1137,7 @@
 				 <&mmsys CLK_MM_DSI1_DIGITAL>,
 				 <&mipi_tx1>;
 			clock-names = "engine", "digital", "hs";
-			phy = <&mipi_tx1>;
+			phys = <&mipi_tx1>;
 			phy-names = "dphy";
 			status = "disabled";
 		};
@@ -1397,8 +1397,8 @@
 				      "venc_lt_sel";
 			assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>,
 					  <&topckgen CLK_TOP_VENC_LT_SEL>;
-			assigned-clock-parents = <&topckgen CLK_TOP_VENCPLL_D2>,
-						 <&topckgen CLK_TOP_UNIVPLL1_D2>;
+			assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL>,
+						 <&topckgen CLK_TOP_VCODECPLL_370P5>;
 		};
 
 		vencltsys: clock-controller@19000000 {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/msc/Makefile
+++ linux-ein-5.4.0/arch/arm64/boot/dts/msc/Makefile
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2020 AVNET Integrated, <avnet-integrated.eu>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation version 2.
+#
+# This program is distributed "as is" WITHOUT ANY WARRANTY of any
+# kind, whether express or implied; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+subdir-y += imx8mlc_mini
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/msc/imx8mlc_mini/Makefile
+++ linux-ein-5.4.0/arch/arm64/boot/dts/msc/imx8mlc_mini/Makefile
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2020 AVNET Integrated, <avnet-integrated.eu>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation version 2.
+#
+# This program is distributed "as is" WITHOUT ANY WARRANTY of any
+# kind, whether express or implied; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+
+dtb-$(CONFIG_ARCH_MXC) += \
+	msc-sm2s-imx8mm-04N0201I-module.dtb \
+	kdp-sm2s-imx8mm-04N0830E-module.dtb
+
+always		:= $(dtb-y)
+subdir-y	:= $(dts-dirs)
+clean-files	:= *.dtb
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/msc/imx8mlc_mini/kdp-sm2s-imx8mm-04N0830E-module.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/msc/imx8mlc_mini/kdp-sm2s-imx8mm-04N0830E-module.dts
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 AVNET Integrated, MSC Technologies GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msc-sm2s-imx8mlc-mini-module.dtsi"
+/ {
+	memory@40000000 {
+		/* 1GiB LPDDR4 */
+		reg = <0x0 0x40000000 0 0x40000000>;
+	};
+
+	firmware {
+		optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+	};
+
+	panel {
+		compatible = "msc,avdtt101wxcn";
+		status = "okay";
+	};
+};
+
+&resmem {
+	/* 32MiB */
+	optee_core@be000000 {
+	reg = <0x00 0xbe000000 0x00 0x1c00000>;
+	};
+
+	/* 4K */
+	optee_shm@bfc00000 {
+	reg = <0x00 0xbfc00000 0x00 0x400000>;
+	};
+};
+
+&sec_jr2 {
+    status = "disabled";
+    secure-status = "okay";
+};
+
+&fec1 {
+	status = "disabled";
+};
+
+&usbotg2 {
+	disable-over-current;
+};
+
+&mipi_dsi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+	panel@0 {
+		reg = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_lcd0_panel>;
+		compatible = "msc,avdtt101wxcn";
+		backlight = <&lcd0_backlight>;
+		enable-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+		status = "okay";
+	};
+};
+
+
+&lcdif {
+	status = "okay";
+};
+
+
+&pwm1 {
+	status = "okay";
+};
+
+
+&lcd0_backlight {
+	status = "okay";
+};
+
+
+&gpu {
+	status = "okay";
+};
+
+
+&vpu_g1 {
+	status = "okay";
+};
+
+
+&vpu_g2 {
+	status = "okay";
+};
+
+
+&vpu_h1 {
+	status = "okay";
+};
+
+&mu {
+	status = "okay";
+};
+
+&usdhc2 {
+	non-removable;
+	status = "okay";
+};
+
+/* Delete unused device tree nodes */
+/delete-node/ &user_gpios;
+/delete-node/ &tmp103;
+
+&gpio1 {
+	wifi-enable {
+		gpio-hog;
+		gpios = <9 GPIO_ACTIVE_HIGH>;
+		output-high; /* enable by default */
+		line-name = "wifi-enable";
+	};
+	cell-modem-reset {
+		gpio-hog;
+		gpios = <7 GPIO_ACTIVE_HIGH>;
+		output-low; /* enable by default */
+		line-name = "cell-modem-reset";
+	};
+};
+
+/* Swap i2c-1 and i2c-2 */
+/ {
+	aliases {
+		i2c2 = &i2c2;
+		i2c1 = &i2c3;
+	};
+};
+
+/* ser 2 */
+&pinctrl_uart2 {
+	fsl,pins = <
+		/* SER2_RX */
+		MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX		0x49
+		/* SER2_TX */
+		MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX		0x49
+		/* SER2_RTS, !DCE-DTE-connection! */
+		MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B		0x156
+		/* SER2_CTS, !DCE-DTE-connection!*/
+		MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B		0x156
+	>;
+};
+
+&uart2{
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	uart-has-rtscts;
+	status = "okay";
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/msc/imx8mlc_mini/msc-sm2s-imx8mlc-mini-module.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/msc/imx8mlc_mini/msc-sm2s-imx8mlc-mini-module.dtsi
@@ -0,0 +1,1439 @@
+/*
+ * Copyright (C) 2020 AVNET Integrated, MSC Technologies GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "../../freescale/imx8mm.dtsi"
+#include <dt-bindings/reset/imx8mm-dispmix.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
+/delete-node/ &gpu_3d;
+/delete-node/ &gpu_2d;
+
+&aips1 {
+	irq_sec_vio: caam_secvio {
+		compatible = "fsl,imx6q-caam-secvio";
+		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+		jtag-tamper = "disabled";
+		watchdog-tamper = "enabled";
+		internal-boot-tamper = "enabled";
+		external-pin-tamper = "disabled";
+	};
+
+	caam_snvs: caam-snvs@30370000 {
+		compatible = "fsl,imx6q-caam-snvs";
+		reg = <0x30370000 0x10000>;
+		clocks = <&clk IMX8MM_CLK_SNVS_ROOT>;
+		clock-names = "ipg";
+	};
+};
+
+&aips4 {
+	lcdif: lcdif@32e00000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,imx8mm-lcdif";
+		reg = <0x32e00000 0x10000>;
+		clocks = <&clk IMX8MM_CLK_LCDIF_PIXEL>,
+			 <&clk IMX8MM_CLK_DISP_AXI_ROOT>,
+			 <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		clock-names = "pix", "disp-axi", "disp-apb";
+		assigned-clocks = <&clk IMX8MM_CLK_LCDIF_PIXEL>,
+				  <&clk IMX8MM_CLK_DISP_AXI>,
+				  <&clk IMX8MM_CLK_DISP_APB>;
+		assigned-clock-parents = <&clk IMX8MM_VIDEO_PLL1_OUT>,
+					 <&clk IMX8MM_SYS_PLL2_1000M>,
+					 <&clk IMX8MM_SYS_PLL1_800M>;
+		assigned-clock-rate = <594000000>, <500000000>, <200000000>;
+		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+		lcdif-gpr = <&dispmix_gpr>;
+		resets = <&lcdif_resets>;
+		power-domains = <&dispmix_pd>;
+		status = "disabled";
+
+		lcdif_disp0: port@0 {
+			reg = <0>;
+
+			lcdif_to_dsim: endpoint {
+				remote-endpoint = <&dsim_from_lcdif>;
+			};
+		};
+	};
+
+	mipi_dsi: mipi_dsi@32e10000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,imx8mm-mipi-dsim";
+		reg = <0x32e10000 0x400>;
+		clocks = <&clk IMX8MM_CLK_DSI_CORE>,
+			 <&clk IMX8MM_CLK_DSI_PHY_REF>;
+		clock-names = "cfg", "pll-ref";
+		assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE>,
+				  <&clk IMX8MM_CLK_DSI_PHY_REF>;
+		assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>,
+					 <&clk IMX8MM_CLK_24M>;
+		assigned-clock-rates = <266000000>, <12000000>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		dsi-gpr = <&dispmix_gpr>;
+		resets = <&mipi_dsi_resets>;
+		power-domains = <&mipi_pd>;
+		status = "disabled";
+
+		port@0 {
+			dsim_from_lcdif: endpoint {
+				remote-endpoint = <&lcdif_to_dsim>;
+			};
+		};
+	};
+
+	csi1_bridge: csi1_bridge@32e20000 {
+		compatible = "fsl,imx8mm-csi", "fsl,imx8mq-csi", "fsl,imx6s-csi";
+		reg = <0x32e20000 0x1000>;
+		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clk IMX8MM_CLK_DISP_AXI_ROOT>,
+			<&clk IMX8MM_CLK_CSI1_ROOT>,
+			<&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		clock-names = "disp-axi", "csi_mclk", "disp_dcic";
+		power-domains = <&dispmix_pd>;
+		status = "disabled";
+	};
+
+	mipi_csi_1: mipi_csi@32e30000 {
+		compatible = "fsl,imx8mm-mipi-csi";
+		reg = <0x32e30000 0x1000>;
+		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <333000000>;
+		clocks = <&clk IMX8MM_CLK_CSI1_CORE>,
+			<&clk IMX8MM_CLK_CSI1_PHY_REF>,
+			<&clk IMX8MM_CLK_DISP_AXI_ROOT>,
+			<&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		clock-names = "mipi_clk", "phy_clk", "disp_axi", "disp_apb";
+		bus-width = <4>;
+		power-domains = <&mipi_pd>;
+		status = "disabled";
+	};
+
+	dispmix_gpr: display-gpr@32e28000 {
+		compatible = "fsl, imx8mm-iomuxc-gpr", "syscon";
+		reg = <0x32e28000 0x100>;
+	};
+
+	display-subsystem {
+		compatible = "fsl,imx-display-subsystem";
+		ports = <&lcdif_disp0>;
+	};
+
+	pcie_phy: pcie-phy@32f00000 {
+		compatible = "fsl,imx7d-pcie-phy";
+		reg = <0x32f00000 0x10000>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&vcc_arm>;
+};
+
+&A53_1 {
+	cpu-supply = <&vcc_arm>;
+};
+
+&A53_2 {
+	cpu-supply = <&vcc_arm>;
+};
+
+&A53_3 {
+	cpu-supply = <&vcc_arm>;
+};
+
+&iomuxc {
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>, <&pinctrl_smarc_gpio>;
+
+	sm2s-imx8mm {
+
+		pinctrl_smarc_gpio: smarcgrp-gpio {
+			fsl,pins = <
+				/* GPIO 0, linux-gpio-id=0  */
+				MX8MM_IOMUXC_GPIO1_IO00_GPIO1_IO0			0x40000019
+				/* GPIO 1, linux-gpio-id=1  */
+				MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1			0x40000019
+				/* GPIO 2, linux-gpio-id=3  */
+				MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3			0x40000019
+				/* GPIO 3, linux-gpio-id=5, no SION because of M4_NMI */
+				MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5			0x19
+				/* GPIO 4, linux-gpio-id=6 */
+				MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6			0x40000019
+				/* GPIO 5, linux-gpio-id=130 */
+				MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2			0x40000019
+				/* GPIO 6, linux-gpio-id=129 */
+				MX8MM_IOMUXC_SAI3_TXD_GPIO5_IO1				0x40000019
+				/* GPIO 7, linux-gpio-id=118 */
+				MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22			0x40000019
+				/* GPIO 8, linux-gpio-id=89 */
+				MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25			0x40000019
+				/* GPIO 9, linux-gpio-id=124 */
+				MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28			0x40000019
+				/* GPIO 10, linux-gpio-id=9 */
+				MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9			0x40000019
+				/* GPIO 11, linux-gpio-id=7 */
+				MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7			0x40000019
+			>;
+		};
+
+		pinctrl_hog: hoggrp {
+			fsl,pins = <
+				/* CHARGER_PRSNT */
+				MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7			0x19
+				/* CHARGING, linux-gpio-id=84 */
+				MX8MM_IOMUXC_SD1_DATA3_GPIO2_IO5			0x19
+				/* CHARGER_PRSNT linux-gpio-id=38 */
+				MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6			0x19
+				/* PERI_RST, linux-gpio-id=123 */
+				MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27			0x19
+				/* SLEEP, linux-gpio-id=117 */
+				MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21			0x40000019
+				/* BOOT_SEL0, linux-gpio-id=34 */
+				MX8MM_IOMUXC_SD1_DATA0_GPIO2_IO2			0x40000019
+				/* BOOT_SEL1, linux-gpio-id=35 */
+				MX8MM_IOMUXC_SD1_DATA1_GPIO2_IO3			0x40000019
+				/* BOOT_SEL2, linux-gpio-id=36 */
+				MX8MM_IOMUXC_SD1_DATA2_GPIO2_IO4			0x40000019
+			>;
+		};
+
+		pinctrl_fec1: fec1grp {
+			fsl,pins = <
+				/* GBE_MDIO_CLK */
+				MX8MM_IOMUXC_ENET_MDC_ENET1_MDC				0x3
+				/* GBE_MDIO_DATA */
+				MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO			0x3
+				/* RGMII_TXEN */
+				MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL	0x1f
+				/* RGMII_TCLK */
+				MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC		0x1f
+				/* RGMII_TXD0 */
+				MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0		0x1f
+				/* RGMII_TXD1 */
+				MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1		0x1f
+				/* RGMII_TXD2 */
+				MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2		0x1f
+				/* RGMII_TXD3 */
+				MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3		0x1f
+				/* RGMII_RCNT */
+				MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL	0x91
+				/* RGMII_RCLK */
+				MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC		0x91
+				/* RGMII_RXD0 */
+				MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0		0x91
+				/* RGMII_RXD1 */
+				MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1		0x91
+				/* RGMII_RXD2 */
+				MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2		0x91
+				/* RGMII_RXD3 */
+				MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3		0x91
+				/* GBE_INT */
+				MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20			0x40000019
+				/* GBE0_GPIO_0 */
+				MX8MM_IOMUXC_GPIO1_IO08_ENET1_1588_EVENT0_IN	0x19
+			>;
+		};
+
+		/* I2C_DEV */
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				/* I2C_DEV_SCL */
+				MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL			0x400001c3
+				/* I2C_DEV_SDA */
+				MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA			0x400001c3
+			>;
+
+		};
+
+		/* I2C_PM */
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				/* I2C_PM_SCL */
+				MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL			0x400001c3
+				/* I2C_PM_SDA */
+				MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA			0x400001c3
+			>;
+		};
+
+		/* I2C_GP */
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				/* I2C_GP_SCL */
+				MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL			0x400001c3
+				/* I2C_GP_SDA */
+				MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA			0x400001c3
+			>;
+		};
+
+		/* I2C_LCD */
+		pinctrl_i2c4: i2c4grp {
+			fsl,pins = <
+				/* I2C_LCD_SCL */
+				MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL			0x400001c3
+				/* I2C_LCD_SDA */
+				MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA			0x400001c3
+			>;
+		};
+
+		/* I2C_CAM */
+		pinctrl_i2c_cam: i2ccamgrp {
+			fsl,pins = <
+				/* I2C_CAM_SCL, linux-gpio-id=152 */
+				MX8MM_IOMUXC_UART2_RXD_GPIO5_IO24		0x40000116
+				/* I2C_CAM_SDA, linux-gpio-id=153 */
+				MX8MM_IOMUXC_UART2_TXD_GPIO5_IO25		0x40000116
+			>;
+		};
+
+		/* ser 0 */
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				/* SER0_RX */
+				MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX		0x49
+				/* SER0_TX */
+				MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX		0x49
+				/* SER0_RTS, linux-gpio-id=120 */
+				MX8MM_IOMUXC_SAI2_TXFS_GPIO4_IO24		0x116
+				/* SER0_CTS, linux-gpio-id=119 */
+				MX8MM_IOMUXC_SAI2_RXD0_GPIO4_IO23		0x116
+			>;
+		};
+
+		/* ser 2 */
+		pinctrl_uart2: uart2grp {
+			fsl,pins = <
+				/* SER2_RX */
+				MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX		0x49
+				/* SER2_TX */
+				MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX		0x49
+				/* SER2_RTS, linux-gpio-id=126 */
+				MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30		0x116
+				/* SER2_CTS, linux-gpio-id=125 */
+				MX8MM_IOMUXC_SAI3_RXC_GPIO4_IO29		0x116
+			>;
+		};
+
+		/* ser 1 */
+		pinctrl_uart3: uart3grp {
+			fsl,pins = <
+				/* SER1_RX */
+				MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX		0x49
+				/* SER1_TX */
+				MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX		0x49
+			>;
+		};
+
+		/* ser 3 */
+		pinctrl_uart4: uart4grp {
+			fsl,pins = <
+				/* SER3_RX */
+				MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX		0x49
+				/* SER3_TX */
+				MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX		0x49
+			>;
+		};
+
+		pinctrl_usdhc2_gpio: usdhc2grp-gpio {
+			fsl,pins = <
+				/* SD2_RESET_B, linux-gpio-id=51 */
+				MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19		0x41
+				/* SD2_CD_B, SDIO_CD, linux-gpio-id=44 */
+				MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12		0x41
+				/* SD2_WP, SDIO_WP, linux-gpio-id=52 */
+				MX8MM_IOMUXC_SD2_WP_GPIO2_IO20			0x41
+				/* SDIO_PWR_EN, linux-gpio-id=78 */
+				MX8MM_IOMUXC_NAND_DQS_GPIO3_IO14		0x41
+				/* USDHC2_VSELECT */
+				MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT	0x1d0
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				/* SD2_CLK, SDIO_CK */
+				MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK			0x190
+				/* SD2_CMD, SDIO_CMD */
+				MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD			0x1d0
+				/* SD2_DATA0, SDIO_DATA0 */
+				MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d0
+				/* SD2_DATA1, SDIO_DATA1 */
+				MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d0
+				/* SD2_DATA2, SDIO_DATA2 */
+				MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d0
+				/* SD2_DATA3, SDIO_DATA3 */
+				MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d0
+			>;
+		};
+
+		pinctrl_usdhc2_100mhz: usdhc2grp-100mhz {
+			fsl,pins = <
+				/* SD2_CLK, SDIO_CK */
+				MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK			0x194
+				/* SD2_CMD, SDIO_CMD */
+				MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD			0x1d4
+				/* SD2_DATA0, SDIO_DATA0 */
+				MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d4
+				/* SD2_DATA1, SDIO_DATA1 */
+				MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d4
+				/* SD2_DATA2, SDIO_DATA2 */
+				MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d4
+				/* SD2_DATA3, SDIO_DATA3 */
+				MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d4
+			>;
+		};
+
+		pinctrl_usdhc2_200mhz: usdhc2grp-200mhz {
+			fsl,pins = <
+				/* SD2_CLK, SDIO_CK */
+				MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK			0x196
+				/* SD2_CMD, SDIO_CMD */
+				MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD			0x1d6
+				/* SD2_DATA0, SDIO_DATA0 */
+				MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0		0x1d6
+				/* SD2_DATA1, SDIO_DATA1 */
+				MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1		0x1d6
+				/* SD2_DATA2, SDIO_DATA2 */
+				MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2		0x1d6
+				/* SD2_DATA3, SDIO_DATA3 */
+				MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3		0x1d6
+			>;
+		};
+
+		pinctrl_usdhc3_reset: usdhc3grp-reset {
+			fsl,pins = <
+				/* SD3_RESET_B, EMMC_RST */
+				MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16	0x116
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				/* SD3_CLK, EMMC_CK */
+				MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK			0x40000190
+				/* SD3_CMD, EMMC_CMD */
+				MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD			0x1d0
+				/* SD3_DATA0, EMMC_DATA0 */
+				MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d0
+				/* SD3_DATA1, EMMC_DATA1 */
+				MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d0
+				/* SD3_DATA2, EMMC_DATA2 */
+				MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d0
+				/* SD3_DATA3, EMMC_DATA3 */
+				MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d0
+				/* SD3_DATA4, EMMC_DATA4 */
+				MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4			0x1d0
+				/* SD3_DATA5, EMMC_DATA5 */
+				MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d0
+				/* SD3_DATA6, EMMC_DATA6 */
+				MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d0
+				/* SD3_DATA7, EMMC_DATA7 */
+				MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7			0x1d0
+				/* SD3_STROBE, EMMC_STRB */
+				MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x190
+			>;
+		};
+
+		pinctrl_usdhc3_100mhz: usdhc3grp-100mhz {
+			fsl,pins = <
+				/* SD3_CLK, EMMC_CK */
+				MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK			0x40000194
+				/* SD3_CMD, EMMC_CMD */
+				MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD			0x1d4
+				/* SD3_DATA0, EMMC_DATA0 */
+				MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d4
+				/* SD3_DATA1, EMMC_DATA1 */
+				MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d4
+				/* SD3_DATA2, EMMC_DATA2 */
+				MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d4
+				/* SD3_DATA3, EMMC_DATA3 */
+				MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d4
+				/* SD3_DATA4, EMMC_DATA4 */
+				MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4			0x1d4
+				/* SD3_DATA5, EMMC_DATA5 */
+				MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d4
+				/* SD3_DATA6, EMMC_DATA6 */
+				MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d4
+				/* SD3_DATA7, EMMC_DATA7 */
+				MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7			0x1d4
+				/* SD3_STROBE, EMMC_STRB */
+				MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x194
+			>;
+		};
+
+		pinctrl_usdhc3_200mhz: usdhc3grp-200mhz {
+			fsl,pins = <
+				/* SD3_CLK, EMMC_CK */
+				MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK			0x40000196
+				/* SD3_CMD, EMMC_CMD */
+				MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD			0x1d6
+				/* SD3_DATA0, EMMC_DATA0 */
+				MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0		0x1d6
+				/* SD3_DATA1, EMMC_DATA1 */
+				MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1		0x1d6
+				/* SD3_DATA2, EMMC_DATA2 */
+				MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2		0x1d6
+				/* SD3_DATA3, EMMC_DATA3 */
+				MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3		0x1d6
+				/* SD3_DATA4, EMMC_DATA4 */
+				MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4			0x1d6
+				/* SD3_DATA5, EMMC_DATA5 */
+				MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5		0x1d6
+				/* SD3_DATA6, EMMC_DATA6 */
+				MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6		0x1d6
+				/* SD3_DATA7, EMMC_DATA7 */
+				MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7			0x1d6
+				/* SD3_STROBE, EMMC_STRB */
+				MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE		0x196
+			>;
+		};
+
+		pinctrl_flexspi: flexspi0grp {
+			fsl,pins = <
+				/* QSPI_CK */
+				MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK		0x1c6
+				/* QSPI_CS0# */
+				MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B	0x86
+				/* QSPI_DATA0 */
+				MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0	0x86
+				/* QSPI_DATA1 */
+				MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1	0x86
+				/* QSPI_DATA2 */
+				MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2	0x86
+				/* QSPI_DATA3 */
+				MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3	0x86
+			>;
+		};
+
+		pinctrl_ecspi1: ecspi1grp {
+			fsl,pins = <
+				/* SPI0_CK */
+				MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK	0x82
+				/* SPI0_MOSI */
+				MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI	0x82
+				/* SPI0_MISO */
+				MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO	0x82
+			>;
+		};
+
+		pinctrl_ecspi1_cs: ecspi1grp-cs {
+			fsl,pins = <
+				/* SPI0_CS0, linux-gpio-id=137 */
+				MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9		0x19
+				/* SPI0_CS1, linux-gpio-id=121 */
+				MX8MM_IOMUXC_SAI2_TXC_GPIO4_IO25		0x19
+			>;
+		};
+
+		pinctrl_ecspi2: ecspi2grp {
+			fsl,pins = <
+				/* SPI1_CK */
+				MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK	0x82
+				/* SPI1_MOSI */
+				MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI	0x82
+				/* SPI1_MISO */
+				MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO	0x82
+			>;
+		};
+
+		pinctrl_ecspi2_cs: ecspi2grp-cs {
+			fsl,pins = <
+				/* SPI1_CS0, linux-gpio-id=141 */
+				MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13		0x19
+				/* SPI1_CS1, linux-gpio-id=122 */
+				MX8MM_IOMUXC_SAI2_TXD0_GPIO4_IO26		0x19
+			>;
+		};
+
+		pinctrl_sai1: sai1grp {
+			fsl,pins = <
+				/* I2S2_LRCK */
+				MX8MM_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC		0xd6
+				/* I2S2_SDIN */
+				MX8MM_IOMUXC_SAI1_RXD0_SAI1_RX_DATA0	0xd6
+				/* I2S2_CK */
+				MX8MM_IOMUXC_SAI1_TXC_SAI1_TX_BCLK		0xd6
+				/* I2S2_SDOUT */
+				MX8MM_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0	0xd6
+			>;
+		};
+
+		pinctrl_sai5: sai5grp {
+			fsl,pins = <
+				/* I2S0_LRCK */
+				MX8MM_IOMUXC_SAI5_RXD1_SAI5_TX_SYNC		0xd6
+				/* I2S0_SDIN */
+				MX8MM_IOMUXC_SAI5_RXD0_SAI5_RX_DATA0	0xd6
+				/* I2S0_CK */
+				MX8MM_IOMUXC_SAI5_RXD2_SAI5_TX_BCLK		0xd6
+				/* I2S0_SDOUT */
+				MX8MM_IOMUXC_SAI5_RXD3_SAI5_TX_DATA0	0xd6
+			>;
+		};
+
+		pinctrl_pwm1: pwm1grp {
+			fsl,pins = <
+				/* LCD0_BKLT_PWM */
+				MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT		0x19
+			>;
+		};
+
+		pinctrl_rtc1: rtc1grp {
+			fsl,pins = <
+				/* RTC_INT, linux-gpio-id=83 */
+				MX8MM_IOMUXC_SAI5_RXFS_GPIO3_IO19		0x40000019
+			>;
+		};
+
+		pinctrl_wdog1: wdog1grp {
+			fsl,pins = <
+				/* WDOG1, WDT_TIME_OUT */
+				MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B	0xc6
+			>;
+		};
+
+		pinctrl_can: cangrp {
+			fsl,pins = <
+				/* CAN_RESET, linux-gpio-id=104 */
+				MX8MM_IOMUXC_SAI1_RXD6_GPIO4_IO8		0x19
+				/* CAN_INT, linux-gpio-id=102 */
+				MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6		0x40000019
+			>;
+		};
+
+		pinctrl_pcie: pciegrp {
+			fsl,pins = <
+				/* PCIE_A_RST, linux-gpio-id=69 */
+				MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10			0x19
+				/* PCIE_WAKE, linux-gpio-id=79 */
+				MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11		0x40000019
+			>;
+		};
+
+		pinctrl_lcd0_backlight: lcd0grp-backlight {
+			fsl,pins = <
+				/* LCD0_BKLT_EN, linux-gpio-id=132 */
+				MX8MM_IOMUXC_SPDIF_RX_GPIO5_IO4				0x19
+			>;
+		};
+
+		pinctrl_lcd0_panel: lcd0grp-panel {
+			fsl,pins = <
+				/* LCD0_VDD_EN, linux-gpio-id=131 */
+				MX8MM_IOMUXC_SPDIF_TX_GPIO5_IO3				0x19
+			>;
+		};
+
+		/* usb otg 0 */
+		pinctrl_usbotg1: usbotg1grp {
+			fsl,pins = <
+				/* USB0_OTG_EN */
+				MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12	0x19
+				/* USB0_OTG_OC */
+				MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC		0x40000019
+			>;
+		};
+
+		/* usb 1 */
+		pinctrl_usbotg2: usbotg2grp {
+			fsl,pins = <
+				/* USB1_PWR_EN */
+				MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14		0x19
+				/* USB1_OC */
+				MX8MM_IOMUXC_GPIO1_IO15_USB2_OTG_OC		0x40000019
+			>;
+		};
+
+		pinctrl_usbotg1_extcon: usbotg1extcongrp {
+			fsl,pins = <
+				/* USB0_OTG_ID */
+				MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10		0x40000019
+			>;
+		};
+	};
+};
+
+/ {
+	model = "MSC SM2S-IMX8MM";
+	compatible = "msc,sm2s-imx8mm", "fsl,imx8mm";
+
+	chosen {
+		bootargs = "console=ttymxc0,115200 earlycon=ec_imx6q,0x30860000,115200";
+		stdout-path = &uart1;
+	};
+
+	soc@0 {
+		caam_sm: caam-sm@100000 {
+			compatible = "fsl,imx6q-caam-sm";
+			reg = <0x100000 0x8000>;
+		};
+
+		pcie0_ep: pcie_ep@33800000 {
+			compatible = "fsl,imx8mm-pcie-ep";
+			reg = <0x33800000 0x000400000>,
+		    	  <0x18000000 0x08000000>;
+			reg-names = "regs", "addr_space";
+			num-lanes = <1>;
+			interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>; /* eDMA */
+			interrupt-names = "dma";
+			fsl,max-link-speed = <2>;
+			power-domains = <&pcie_pd>;
+			resets = <&src IMX8MQ_RESET_PCIEPHY>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_CLK_REQ>,
+				 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
+			reset-names = "pciephy", "apps", "clkreq", "turnoff";
+			fsl,imx7d-pcie-phy = <&pcie_phy>;
+			num-ib-windows = <4>;
+			num-ob-windows = <4>;
+			status = "disabled";
+		};
+	};
+
+	dispmix-reset {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		dispmix_sft_rstn: dispmix-sft-rstn@32e28000 {
+			compatible = "fsl,imx8mm-dispmix-sft-rstn";
+			reg = <0x0 0x32e28000 0x0 0x4>;
+			clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+			clock-names = "disp_apb_root_clk";
+			active_low;
+			power-domains = <&dispmix_pd>;
+			#reset-cells = <1>;
+		};
+
+		dispmix_clk_en: dispmix-clk-en@32e28004 {
+			compatible = "fsl,imx8mm-dispmix-clk-en";
+			reg = <0x0 0x32e28004 0x0 0x4>;
+			clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+			clock-names = "disp_apb_root_clk";
+			power-domains = <&dispmix_pd>;
+			#reset-cells = <1>;
+		};
+
+		dispmix_mipi_rst: dispmix-mipi-rst@32e28008 {
+			compatible = "fsl,imx8mm-dispmix-mipi-rst";
+			reg = <0x0 0x32e28008 0x0 0x4>;
+			clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+			clock-names = "disp_apb_root_clk";
+			active_low;
+			power-domains = <&dispmix_pd>;
+			#reset-cells = <1>;
+		};
+	};
+
+	gpu: gpu@38000000 {
+		compatible ="fsl,imx8mm-gpu", "fsl,imx6q-gpu";
+		reg = <0x0 0x38000000 0x0 0x8000>, <0x0 0x38008000 0x0 0x8000>,
+			<0x0 0x40000000 0x0 0x80000000>, <0x0 0x0 0x0 0x8000000>;
+		reg-names = "iobase_3d", "iobase_2d",
+			"phys_baseaddr", "contiguous_mem";
+		interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+			<GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "irq_3d", "irq_2d";
+		clocks = <&clk IMX8MM_CLK_GPU3D_ROOT>,
+			<&clk IMX8MM_CLK_DUMMY>,
+			<&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+			<&clk IMX8MM_CLK_GPU_AHB>,
+			<&clk IMX8MM_CLK_GPU2D_ROOT>,
+			<&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+			<&clk IMX8MM_CLK_GPU_AHB>;
+		clock-names = "gpu3d_clk", "gpu3d_shader_clk",
+			  "gpu3d_axi_clk", "gpu3d_ahb_clk",
+			  "gpu2d_clk", "gpu2d_axi_clk",
+			  "gpu2d_ahb_clk";
+		assigned-clocks = <&clk IMX8MM_CLK_GPU3D_SRC>,
+				<&clk IMX8MM_CLK_GPU2D_SRC>,
+				<&clk IMX8MM_CLK_GPU_AXI>,
+				<&clk IMX8MM_CLK_GPU_AHB>,
+				<&clk IMX8MM_GPU_PLL_OUT>;
+		assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>,
+				<&clk IMX8MM_GPU_PLL_OUT>,
+				<&clk IMX8MM_SYS_PLL1_800M>,
+				<&clk IMX8MM_SYS_PLL1_800M>;
+		assigned-clock-rates = <0>, <0>, <0>,<400000000>,<1000000000>;
+
+		power-domains = <&gpumix_pd>;
+
+		status = "disabled";
+	};
+
+	lcdif_resets: lcdif-resets {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#reset-cells = <0>;
+
+		lcdif-clk-enable {
+			compatible = "lcdif,clk-enable";
+			resets = <&dispmix_clk_en IMX8MM_LCDIF_APB_CLK_EN>,
+				 <&dispmix_clk_en IMX8MM_LCDIF_PIXEL_CLK_EN>;
+		};
+	};
+
+	mipi_dsi_resets: mipi-dsi-resets {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#reset-cells = <0>;
+
+		dsi-soft-resetn {
+			compatible = "dsi,soft-resetn";
+			resets = <&dispmix_sft_rstn IMX8MM_MIPI_DSI_I_PRESET>;
+		};
+
+		dsi-clk-enable {
+			compatible = "dsi,clk-enable";
+			resets = <&dispmix_clk_en IMX8MM_MIPI_DSI_CLKREF_EN>,
+				 <&dispmix_clk_en IMX8MM_MIPI_DSI_PCLK_EN>;
+		};
+
+		dsi-mipi-reset {
+			compatible = "dsi,mipi-reset";
+			resets = <&dispmix_mipi_rst IMX8MM_MIPI_M_RESET>;
+		};
+	};
+
+	reg_otg1_vbus: reg-otg1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "OTG1_VBUS";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		always-on;
+		u-boot,off-on-delay-us = <100000>;
+	};
+
+	aliases {
+		i2c5 = &i2c_cam;
+	};
+
+	i2c_cam: i2c_cam {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2c_cam>;
+		compatible = "i2c-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		sda-gpios = <&gpio5 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		scl-gpios = <&gpio5 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		status = "okay";
+	};
+
+	lcd0_backlight: lcd0_backlight {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_lcd0_backlight>;
+		compatible = "pwm-backlight";
+		pwms = <&pwm1 0 1000000>;
+		brightness-levels = <
+			  0   1   2   3   4   5   6   7   8   9
+			 10  11  12  13  14  15  16  17  18  19
+			 20  21  22  23  24  25  26  27  28  29
+			 30  31  32  33  34  35  36  37  38  39
+			 40  41  42  43  44  45  46  47  48  49
+			 50  51  52  53  54  55  56  57  58  59
+			 60  61  62  63  64  65  66  67  68  69
+			 70  71  72  73  74  75  76  77  78  79
+			 80  81  82  83  84  85  86  87  88  89
+			 90  91  92  93  94  95  96  97  98  99
+			100 101 102 103 104 105 106 107 108 109
+			110 111 112 113 114 115 116 117 118 119
+			120 121 122 123 124 125 126 127 128 129
+			130 131 132 133 134 135 136 137 138 139
+			140 141 142 143 144 145 146 147 148 149
+			150 151 152 153 154 155 156 157 158 159
+			160 161 162 163 164 165 166 167 168 169
+			170 171 172 173 174 175 176 177 178 179
+			180 181 182 183 184 185 186 187 188 189
+			190 191 192 193 194 195 196 197 198 199
+			200 201 202 203 204 205 206 207 208 209
+			210 211 212 213 214 215 216 217 218 219
+			220 221 222 223 224 225 226 227 228 229
+			230 231 232 233 234 235 236 237 238 239
+			240 241 242 243 244 245 246 247 248 249
+			250 251 252 253 254 255
+		>;
+		default-brightness-level = <255>;
+		enable-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+
+	resmem: reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* global autoconfigured region for contiguous allocations */
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x14000000>;
+			linux,cma-default;
+		};
+	};
+
+	power-domains {
+		compatible = "simple-bus";
+		/* HSIO SS */
+		hsiomix_pd: hsiomix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <0>;
+			domain-name = "hsiomix";
+			clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
+		};
+
+		pcie_pd: pcie-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <1>;
+			domain-name = "pcie";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		usb_otg1_pd: usbotg1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <2>;
+			domain-name = "usb_otg1";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		usb_otg2_pd: usbotg2-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <3>;
+			domain-name = "usb_otg2";
+			parent-domains = <&hsiomix_pd>;
+		};
+
+		/* GPU SS */
+		gpumix_pd: gpumix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <4>;
+			domain-name = "gpumix";
+			clocks = <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
+				 <&clk IMX8MM_CLK_GPU_AHB>,
+				 <&clk IMX8MM_CLK_GPU2D_ROOT>,
+				 <&clk IMX8MM_CLK_GPU3D_ROOT>;
+		};
+
+		/* VPU SS */
+		vpumix_pd: vpumix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <5>;
+			domain-name = "vpumix";
+			clocks = <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+		};
+
+		vpu_g1_pd: vpug1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <6>;
+			domain-name = "vpu_g1";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_G1_ROOT>;
+		};
+
+		vpu_g2_pd: vpug2-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <7>;
+			domain-name = "vpu_g2";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_G2_ROOT>;
+		};
+
+		vpu_h1_pd: vpuh1-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <8>;
+			domain-name = "vpu_h1";
+			parent-domains = <&vpumix_pd>;
+			clocks = <&clk IMX8MM_CLK_VPU_H1_ROOT>;
+		};
+
+		/* DISP SS */
+		dispmix_pd: dispmix-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <9>;
+			domain-name = "dispmix";
+			clocks = <&clk IMX8MM_CLK_DISP_ROOT>,
+				 <&clk IMX8MM_CLK_DISP_AXI_ROOT>,
+				 <&clk IMX8MM_CLK_DISP_APB_ROOT>;
+		};
+
+		mipi_pd: mipi-pd {
+			compatible = "fsl,imx8m-pm-domain";
+			#power-domain-cells = <0>;
+			domain-index = <10>;
+			domain-name = "mipi";
+			parent-domains = <&dispmix_pd>;
+		};
+	};
+
+	user_gpios: user_gpios {
+                compatible = "msc,user-gpios";
+                /* The first entry is the GPIO controller.
+                   The number of next entries must match of #gpio-cells.
+                   The first number is the offset within the controller.
+                   If necessary, the second number is a flag
+                   see linux.git/Documentation/devicetree/bindings/gpio/ */
+                GPIO0-gpios  = <&gpio1 0 0>;
+                GPIO1-gpios  = <&gpio1 1 0>;
+                GPIO2-gpios  = <&gpio1 3 0>;
+                GPIO3-gpios  = <&gpio1 5 0>;
+                GPIO4-gpios  = <&gpio1 6 0>;
+                GPIO5-gpios  = <&gpio5 2 0>;
+                GPIO6-gpios  = <&gpio5 1 0>;
+                GPIO7-gpios  = <&gpio4 22 0>;
+                GPIO8-gpios  = <&gpio3 25 0>;
+                GPIO9-gpios  = <&gpio4 28 0>;
+				GPIO10-gpios = <&gpio1 9 0>;
+                GPIO11-gpios = <&gpio1 7 0>;
+	};
+
+	vpu_h1: vpu_h1@38320000 {
+		compatible = "nxp,imx8mm-hantro-h1";
+		reg = <0x0 0x38320000 0x0 0x10000>;
+		reg-names = "regs_hantro_h1";
+		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "irq_hantro_h1";
+		clocks = <&clk IMX8MM_CLK_VPU_H1_ROOT>, <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+		clock-names = "clk_hantro_h1", "clk_hantro_h1_bus";
+		assigned-clocks = <&clk IMX8MM_CLK_VPU_H1>,<&clk IMX8MM_CLK_VPU_BUS>;
+		assigned-clock-parents = <&clk IMX8MM_VPU_PLL_OUT>, <&clk IMX8MM_SYS_PLL1_800M>;
+		assigned-clock-rates = <600000000>, <800000000>;
+		power-domains = <&vpu_h1_pd>;
+		status = "disabled";
+	};
+
+	vpu_g1: vpu_g1@38300000 {
+		compatible = "nxp,imx8mm-hantro";
+		reg = <0x0 0x38300000 0x0 0x100000>;
+		reg-names = "regs_hantro";
+		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "irq_hantro";
+		clocks = <&clk IMX8MM_CLK_VPU_G1_ROOT>, <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+		clock-names = "clk_hantro", "clk_hantro_bus";
+		assigned-clocks = <&clk IMX8MM_CLK_VPU_G1>, <&clk IMX8MM_CLK_VPU_BUS>;
+		assigned-clock-parents = <&clk IMX8MM_VPU_PLL_OUT>, <&clk IMX8MM_SYS_PLL1_800M>;
+		assigned-clock-rates = <600000000>, <800000000>;
+		power-domains = <&vpu_g1_pd>;
+		status = "disabled";
+	};
+
+	vpu_g2: vpu_g2@38310000 {
+		compatible = "nxp,imx8mm-hantro";
+		reg = <0x0 0x38310000 0x0 0x100000>;
+		reg-names = "regs_hantro";
+		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "irq_hantro";
+		clocks = <&clk IMX8MM_CLK_VPU_G2_ROOT>, <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
+		clock-names = "clk_hantro", "clk_hantro_bus";
+		assigned-clocks = <&clk IMX8MM_CLK_VPU_G2>, <&clk IMX8MM_CLK_VPU_BUS>;
+		assigned-clock-parents = <&clk IMX8MM_VPU_PLL_OUT>, <&clk IMX8MM_SYS_PLL1_800M>;
+		assigned-clock-rates = <600000000>, <800000000>;
+		power-domains = <&vpu_g2_pd>;
+		status = "disabled";
+	};
+
+	extcon_usbotg1: extcon_usbotg1 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usbotg1_extcon>;
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&fec1 {
+	compatible = "fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_fec1>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy1>;
+	stop-mode = <&gpr 0x10 3>;
+	fsl,wakeup_irq = <2>;
+	fsl,magic-packet;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy1: ethernet-phy@1 {
+			reg = <1>;
+			compatible = "ethernet-phy-id2000.a231";
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
+			ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			ti,led-gpio-polarity-active-low;
+			ti,led-2-polarity-active-low;
+			ti,led-1-polarity-active-low;
+			ti,led-0-polarity-active-low;
+		};
+	};
+};
+
+/* I2C_DEV */
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic1: pmic@31 {
+		compatible = "ricoh,rn5t567";
+		reg = <0x31>;
+		pmic-id = <0>;
+		system-restart-controller;
+		sleep-sequence = /bits/ 8 <
+				0x16	0x2b
+				0x17	0x49
+				0x1b	0x2b
+				0x1c	0x67
+				0x1f	0x0b
+				0x32	0x03
+				0x30	0x03
+			>;
+
+		regulators {
+			DCDC1 {
+				regulator-name = "VCC_SOC";
+				regulator-always-on;
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+			};
+			vcc_arm: DCDC2 {
+				regulator-name = "VCC_ARM";
+				regulator-always-on;
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <950000>;
+			};
+			DCDC3 {
+				regulator-name = "VCC_DRAM_1V2";
+				regulator-always-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			DCDC4 {
+				regulator-name = "VCC_1V8_PMIC";
+				regulator-always-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			LDO1 {
+				regulator-name = "VCC_2V5";
+				regulator-always-on;
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+			};
+			LDO2 {
+				regulator-name = "VCC_3V3";
+				regulator-always-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			LDO3 {
+				regulator-name = "VCC_3V3_2";
+				regulator-always-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			LDO4 {
+				regulator-name = "VCC_LDO4_1V8";
+				regulator-always-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			LDO5 {
+				regulator-name = "VCC_1V0";
+				regulator-always-on;
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+			};
+			LDORTC1 {
+				regulator-name = "VCC_SNVS_1V8";
+				regulator-always-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			LDORTC2 {
+				regulator-name = "VCC_PM1_SNVS_3V3";
+				regulator-always-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+		};
+	};
+
+	rtc: rtc@32 {
+		compatible = "ricoh,r2221tl";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_rtc1>;
+		reg = <0x32>;
+	};
+
+	tmp103: tmp103@71 {
+		compatible = "ti,tmp103";
+		reg = <0x71>;
+	};
+
+	dsi_lvds_bridge: sn65dsi84@2d {
+		compatible = "ti,sn65dsi83";
+		reg = <0x2d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_lcd0_panel>;
+		enable-gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+
+};
+
+/* I2C_PM */
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+};
+
+/* I2C_GP */
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	module_eeprom@50 {
+		compatible = "atmel,24c64";
+		reg = <0x50>;
+	};
+};
+
+/* I2C_LCD */
+&i2c4 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+};
+
+/* ser 0 */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+/* ser 2 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+/* ser 1 */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+#if 0
+/* ser 3 */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+};
+#endif
+
+&flexspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexspi>;
+	status = "okay";
+
+	flash0: w25q32@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <29000000>;
+		spi-nor,ddr-quad-read-dummy = <6>;
+	};
+};
+
+&ecspi1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	fsl,spi-num-chipselects = <2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>;
+	cs-gpios =
+			<&gpio5 9 GPIO_ACTIVE_LOW>,
+			<&gpio4 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&ecspi2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	fsl,spi-num-chipselects = <2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>;
+	cs-gpios =
+			<&gpio5 13 GPIO_ACTIVE_LOW>,
+			<&gpio4 26 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&usdhc2 {
+#if 0
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+#else
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+#endif
+	bus-width = <4>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	wp-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	no-1-8-v; /* to avoid problems with some uhs sd cards */
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	sdhci-extra-quirks2 = <0x40000040>;
+	status = "okay";
+};
+
+&usbotg1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg1>;
+	vbus-supply = <&reg_otg1_vbus>;
+	dr_mode = "otg";
+	extcon = <0>, <&extcon_usbotg1>;
+	hnp-disable;
+	srp-disable;
+	adp-disable;
+	disable-over-current;
+	power-domains = <&usb_otg1_pd>;
+	status = "okay";
+};
+
+&usbotg2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg2>;
+	dr_mode = "host";
+	power-domains = <&usb_otg2_pd>;
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "disabled";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog1>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	linux,pci-domain = <0>;
+	power-domains = <&pcie_pd>;
+	reset-gpio = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	resets = <&src IMX8MQ_RESET_PCIEPHY>,
+		 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
+		 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_CLK_REQ>,
+		 <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
+	reset-names = "pciephy", "apps", "clkreq", "turnoff";
+	ext_osc = <0>;
+	status = "okay";
+};
+
+&mipi_dsi {
+	status = "disabled";
+};
+
+&sai1 {
+    fsl,dataline = <0 0xff 0xff>;
+};
+
+&sai5 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&pinctrl_sai5>;
+    fsl,dataline = <0 0xf 0xf>;
+    status = "disabled";
+};
+
+&mipi_csi_1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "disabled";
+	port {
+		mipi1_sensor_ep: endpoint@1 {
+		};
+
+		csi1_mipi_ep: endpoint@2 {
+			remote-endpoint = <&csi1_ep>;
+		};
+	};
+};
+
+&csi1_bridge {
+	fsl,mipi-mode;
+	status = "disabled";
+	port {
+		csi1_ep: endpoint {
+			remote-endpoint = <&csi1_mipi_ep>;
+		};
+	};
+};
+
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/msc/imx8mlc_mini/msc-sm2s-imx8mm-04N0201I-module.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/msc/imx8mlc_mini/msc-sm2s-imx8mm-04N0201I-module.dts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 AVNET Integrated, MSC Technologies GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msc-sm2s-imx8mlc-mini-module.dtsi"
+/*#include "../imx8mm/msc-sm2s-imx8mm-module.dtsi"*/
+/ {
+	memory@40000000 {
+		/* 1GiB LPDDR4 */
+		reg = <0x0 0x40000000 0 0x40000000>;
+	};
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -1082,13 +1082,13 @@
 
 		cpu@0 {
 			device_type = "cpu";
-			compatible = "nvidia,denver";
+			compatible = "nvidia,tegra132-denver";
 			reg = <0>;
 		};
 
 		cpu@1 {
 			device_type = "cpu";
-			compatible = "nvidia,denver";
+			compatible = "nvidia,tegra132-denver";
 			reg = <1>;
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -10,18 +10,6 @@
 	model = "NVIDIA Jetson TX2 Developer Kit";
 	compatible = "nvidia,p2771-0000", "nvidia,tegra186";
 
-	aconnect {
-		status = "okay";
-
-		dma-controller@2930000 {
-			status = "okay";
-		};
-
-		interrupt-controller@2a40000 {
-			status = "okay";
-		};
-	};
-
 	i2c@3160000 {
 		power-monitor@42 {
 			compatible = "ti,ina3221";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -309,8 +309,9 @@
 		compatible = "nvidia,tegra186-sdhci";
 		reg = <0x0 0x03400000 0x0 0x10000>;
 		interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&bpmp TEGRA186_CLK_SDMMC1>;
-		clock-names = "sdhci";
+		clocks = <&bpmp TEGRA186_CLK_SDMMC1>,
+			 <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&bpmp TEGRA186_RESET_SDMMC1>;
 		reset-names = "sdhci";
 		iommus = <&smmu TEGRA186_SID_SDMMC1>;
@@ -335,8 +336,9 @@
 		compatible = "nvidia,tegra186-sdhci";
 		reg = <0x0 0x03420000 0x0 0x10000>;
 		interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&bpmp TEGRA186_CLK_SDMMC2>;
-		clock-names = "sdhci";
+		clocks = <&bpmp TEGRA186_CLK_SDMMC2>,
+			 <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&bpmp TEGRA186_RESET_SDMMC2>;
 		reset-names = "sdhci";
 		iommus = <&smmu TEGRA186_SID_SDMMC2>;
@@ -356,8 +358,9 @@
 		compatible = "nvidia,tegra186-sdhci";
 		reg = <0x0 0x03440000 0x0 0x10000>;
 		interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&bpmp TEGRA186_CLK_SDMMC3>;
-		clock-names = "sdhci";
+		clocks = <&bpmp TEGRA186_CLK_SDMMC3>,
+			 <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&bpmp TEGRA186_RESET_SDMMC3>;
 		reset-names = "sdhci";
 		iommus = <&smmu TEGRA186_SID_SDMMC3>;
@@ -379,8 +382,9 @@
 		compatible = "nvidia,tegra186-sdhci";
 		reg = <0x0 0x03460000 0x0 0x10000>;
 		interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&bpmp TEGRA186_CLK_SDMMC4>;
-		clock-names = "sdhci";
+		clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
+			 <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+		clock-names = "sdhci", "tmclk";
 		assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
 				  <&bpmp TEGRA186_CLK_PLLC4_VCO>;
 		assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>;
@@ -705,7 +709,7 @@
 
 	ccplex@e000000 {
 		compatible = "nvidia,tegra186-ccplex-cluster";
-		reg = <0x0 0x0e000000 0x0 0x3fffff>;
+		reg = <0x0 0x0e000000 0x0 0x400000>;
 
 		nvidia,bpmp = <&bpmp>;
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
@@ -32,7 +32,7 @@
 
 			phy-reset-gpios = <&gpio TEGRA194_MAIN_GPIO(G, 5) GPIO_ACTIVE_LOW>;
 			phy-handle = <&phy>;
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 
 			mdio {
 				#address-cells = <1>;
@@ -309,9 +309,8 @@
 			regulator-name = "VDD_12V";
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-			gpio = <&gpio TEGRA194_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>;
+			gpio = <&gpio TEGRA194_MAIN_GPIO(A, 1) GPIO_ACTIVE_HIGH>;
 			regulator-boot-on;
-			enable-active-low;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -144,7 +144,7 @@
 					nvidia,schmitt = <TEGRA_PIN_DISABLE>;
 					nvidia,lpdr = <TEGRA_PIN_ENABLE>;
 					nvidia,enable-input = <TEGRA_PIN_DISABLE>;
-					nvidia,io-high-voltage = <TEGRA_PIN_ENABLE>;
+					nvidia,io-hv = <TEGRA_PIN_ENABLE>;
 					nvidia,tristate = <TEGRA_PIN_DISABLE>;
 					nvidia,pull = <TEGRA_PIN_PULL_NONE>;
 				};
@@ -156,7 +156,7 @@
 					nvidia,schmitt = <TEGRA_PIN_DISABLE>;
 					nvidia,lpdr = <TEGRA_PIN_ENABLE>;
 					nvidia,enable-input = <TEGRA_PIN_ENABLE>;
-					nvidia,io-high-voltage = <TEGRA_PIN_ENABLE>;
+					nvidia,io-hv = <TEGRA_PIN_ENABLE>;
 					nvidia,tristate = <TEGRA_PIN_DISABLE>;
 					nvidia,pull = <TEGRA_PIN_PULL_NONE>;
 				};
@@ -403,8 +403,9 @@
 			compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
 			reg = <0x03400000 0x10000>;
 			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&bpmp TEGRA194_CLK_SDMMC1>;
-			clock-names = "sdhci";
+			clocks = <&bpmp TEGRA194_CLK_SDMMC1>,
+				 <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+			clock-names = "sdhci", "tmclk";
 			resets = <&bpmp TEGRA194_RESET_SDMMC1>;
 			reset-names = "sdhci";
 			nvidia,pad-autocal-pull-up-offset-3v3-timeout =
@@ -425,8 +426,9 @@
 			compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
 			reg = <0x03440000 0x10000>;
 			interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&bpmp TEGRA194_CLK_SDMMC3>;
-			clock-names = "sdhci";
+			clocks = <&bpmp TEGRA194_CLK_SDMMC3>,
+				 <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+			clock-names = "sdhci", "tmclk";
 			resets = <&bpmp TEGRA194_RESET_SDMMC3>;
 			reset-names = "sdhci";
 			nvidia,pad-autocal-pull-up-offset-1v8 = <0x00>;
@@ -448,8 +450,9 @@
 			compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
 			reg = <0x03460000 0x10000>;
 			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&bpmp TEGRA194_CLK_SDMMC4>;
-			clock-names = "sdhci";
+			clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
+				 <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+			clock-names = "sdhci", "tmclk";
 			assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
 					  <&bpmp TEGRA194_CLK_PLLC4>;
 			assigned-clock-parents =
@@ -689,7 +692,7 @@
 
 		hsp_aon: hsp@c150000 {
 			compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp";
-			reg = <0x0c150000 0xa0000>;
+			reg = <0x0c150000 0x90000>;
 			interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
 			             <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
 			             <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
@@ -1151,7 +1154,7 @@
 	};
 
 	pcie@14100000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
 		reg = <0x00 0x14100000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x30000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1192,12 +1195,12 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x30100000 0x0  0x30100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x12 0x00000000 0x12 0x00000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+			  0xc3000000 0x12 0x00000000 0x12 0x00000000 0x0 0x30000000   /* prefetchable memory (768MB) */
 			  0x82000000 0x0  0x40000000 0x12 0x30000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
 	};
 
 	pcie@14120000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
 		reg = <0x00 0x14120000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x32000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1238,12 +1241,12 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x32100000 0x0  0x32100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x12 0x40000000 0x12 0x40000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+			  0xc3000000 0x12 0x40000000 0x12 0x40000000 0x0 0x30000000   /* prefetchable memory (768MB) */
 			  0x82000000 0x0  0x40000000 0x12 0x70000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
 	};
 
 	pcie@14140000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX1A>;
 		reg = <0x00 0x14140000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x34000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1284,12 +1287,12 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x34100000 0x0  0x34100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x12 0x80000000 0x12 0x80000000 0x0 0x30000000   /* prefetchable memory (768MB) */
+			  0xc3000000 0x12 0x80000000 0x12 0x80000000 0x0 0x30000000   /* prefetchable memory (768MB) */
 			  0x82000000 0x0  0x40000000 0x12 0xb0000000 0x0 0x10000000>; /* non-prefetchable memory (256MB) */
 	};
 
 	pcie@14160000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX4A>;
 		reg = <0x00 0x14160000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x36000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1330,12 +1333,12 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x36100000 0x0  0x36100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x14 0x00000000 0x14 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+			  0xc3000000 0x14 0x00000000 0x14 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
 			  0x82000000 0x0  0x40000000 0x17 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
 	};
 
 	pcie@14180000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8B>;
 		reg = <0x00 0x14180000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x38000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1376,12 +1379,12 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x38100000 0x0  0x38100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x18 0x00000000 0x18 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+			  0xc3000000 0x18 0x00000000 0x18 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
 			  0x82000000 0x0  0x40000000 0x1b 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
 	};
 
 	pcie@141a0000 {
-		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
+		compatible = "nvidia,tegra194-pcie";
 		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8A>;
 		reg = <0x00 0x141a0000 0x0 0x00020000   /* appl registers (128K)      */
 		       0x00 0x3a000000 0x0 0x00040000   /* configuration space (256K) */
@@ -1426,10 +1429,109 @@
 
 		bus-range = <0x0 0xff>;
 		ranges = <0x81000000 0x0  0x3a100000 0x0  0x3a100000 0x0 0x00100000   /* downstream I/O (1MB) */
-			  0xc2000000 0x1c 0x00000000 0x1c 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
+			  0xc3000000 0x1c 0x00000000 0x1c 0x00000000 0x3 0x40000000   /* prefetchable memory (13GB) */
 			  0x82000000 0x0  0x40000000 0x1f 0x40000000 0x0 0xc0000000>; /* non-prefetchable memory (3GB) */
 	};
 
+	pcie_ep@14160000 {
+		compatible = "nvidia,tegra194-pcie-ep";
+		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX4A>;
+		reg = <0x00 0x14160000 0x0 0x00020000   /* appl registers (128K)      */
+		       0x00 0x36040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+		       0x00 0x36080000 0x0 0x00040000   /* DBI reg space (256K)       */
+		       0x14 0x00000000 0x4 0x00000000>; /* Address Space (16G)        */
+		reg-names = "appl", "atu_dma", "dbi", "addr_space";
+
+		status = "disabled";
+
+		num-lanes = <4>;
+		num-ib-windows = <2>;
+		num-ob-windows = <8>;
+
+		clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_4>;
+		clock-names = "core";
+
+		resets = <&bpmp TEGRA194_RESET_PEX0_CORE_4_APB>,
+			 <&bpmp TEGRA194_RESET_PEX0_CORE_4>;
+		reset-names = "apb", "core";
+
+		interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;	/* controller interrupt */
+		interrupt-names = "intr";
+
+		nvidia,bpmp = <&bpmp 4>;
+
+		nvidia,aspm-cmrt-us = <60>;
+		nvidia,aspm-pwr-on-t-us = <20>;
+		nvidia,aspm-l0s-entrance-latency-us = <3>;
+	};
+
+	pcie_ep@14180000 {
+		compatible = "nvidia,tegra194-pcie-ep";
+		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8B>;
+		reg = <0x00 0x14180000 0x0 0x00020000   /* appl registers (128K)      */
+		       0x00 0x38040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+		       0x00 0x38080000 0x0 0x00040000   /* DBI reg space (256K)       */
+		       0x18 0x00000000 0x4 0x00000000>; /* Address Space (16G)        */
+		reg-names = "appl", "atu_dma", "dbi", "addr_space";
+
+		status = "disabled";
+
+		num-lanes = <8>;
+		num-ib-windows = <2>;
+		num-ob-windows = <8>;
+
+		clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_0>;
+		clock-names = "core";
+
+		resets = <&bpmp TEGRA194_RESET_PEX0_CORE_0_APB>,
+			 <&bpmp TEGRA194_RESET_PEX0_CORE_0>;
+		reset-names = "apb", "core";
+
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;	/* controller interrupt */
+		interrupt-names = "intr";
+
+		nvidia,bpmp = <&bpmp 0>;
+
+		nvidia,aspm-cmrt-us = <60>;
+		nvidia,aspm-pwr-on-t-us = <20>;
+		nvidia,aspm-l0s-entrance-latency-us = <3>;
+	};
+
+	pcie_ep@141a0000 {
+		compatible = "nvidia,tegra194-pcie-ep";
+		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8A>;
+		reg = <0x00 0x141a0000 0x0 0x00020000   /* appl registers (128K)      */
+		       0x00 0x3a040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
+		       0x00 0x3a080000 0x0 0x00040000   /* DBI reg space (256K)       */
+		       0x1c 0x00000000 0x4 0x00000000>; /* Address Space (16G)        */
+		reg-names = "appl", "atu_dma", "dbi", "addr_space";
+
+		status = "disabled";
+
+		num-lanes = <8>;
+		num-ib-windows = <2>;
+		num-ob-windows = <8>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&clkreq_c5_bi_dir_state>;
+
+		clocks = <&bpmp TEGRA194_CLK_PEX1_CORE_5>;
+		clock-names = "core";
+
+		resets = <&bpmp TEGRA194_RESET_PEX1_CORE_5_APB>,
+			 <&bpmp TEGRA194_RESET_PEX1_CORE_5>;
+		reset-names = "apb", "core";
+
+		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;	/* controller interrupt */
+		interrupt-names = "intr";
+
+		nvidia,bpmp = <&bpmp 5>;
+
+		nvidia,aspm-cmrt-us = <60>;
+		nvidia,aspm-pwr-on-t-us = <20>;
+		nvidia,aspm-l0s-entrance-latency-us = <3>;
+	};
+
 	sysram@40000000 {
 		compatible = "nvidia,tegra194-sysram", "mmio-sram";
 		reg = <0x0 0x40000000 0x0 0x50000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
@@ -1612,7 +1612,7 @@
 			regulator-name = "VDD_HDMI_5V0";
 			regulator-min-microvolt = <5000000>;
 			regulator-max-microvolt = <5000000>;
-			gpio = <&exp1 12 GPIO_ACTIVE_LOW>;
+			gpio = <&exp1 12 GPIO_ACTIVE_HIGH>;
 			enable-active-high;
 			vin-supply = <&vdd_5v0_sys>;
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -917,6 +917,7 @@
 			 <&tegra_car 128>, /* hda2hdmi */
 			 <&tegra_car 111>; /* hda2codec_2x */
 		reset-names = "hda", "hda2hdmi", "hda2codec_2x";
+		power-domains = <&pd_sor>;
 		status = "disabled";
 	};
 
@@ -1116,8 +1117,9 @@
 		compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0000 0x0 0x200>;
 		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
-		clock-names = "sdhci";
+		clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
+			 <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&tegra_car 14>;
 		reset-names = "sdhci";
 		pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
@@ -1144,8 +1146,9 @@
 		compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0200 0x0 0x200>;
 		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&tegra_car TEGRA210_CLK_SDMMC2>;
-		clock-names = "sdhci";
+		clocks = <&tegra_car TEGRA210_CLK_SDMMC2>,
+			 <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&tegra_car 9>;
 		reset-names = "sdhci";
 		pinctrl-names = "sdmmc-1v8-drv";
@@ -1161,8 +1164,9 @@
 		compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0400 0x0 0x200>;
 		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&tegra_car TEGRA210_CLK_SDMMC3>;
-		clock-names = "sdhci";
+		clocks = <&tegra_car TEGRA210_CLK_SDMMC3>,
+			 <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&tegra_car 69>;
 		reset-names = "sdhci";
 		pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
@@ -1184,8 +1188,9 @@
 		compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0600 0x0 0x200>;
 		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&tegra_car TEGRA210_CLK_SDMMC4>;
-		clock-names = "sdhci";
+		clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
+			 <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+		clock-names = "sdhci", "tmclk";
 		resets = <&tegra_car 15>;
 		reset-names = "sdhci";
 		pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
@@ -623,6 +623,8 @@
 				l21 {
 					regulator-min-microvolt = <2950000>;
 					regulator-max-microvolt = <2950000>;
+					regulator-allow-set-load;
+					regulator-system-load = <200000>;
 				};
 				l22 {
 					regulator-min-microvolt = <3300000>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
@@ -20,7 +20,7 @@
 		stdout-path = "serial0";
 	};
 
-	memory {
+	memory@40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0x0 0x20000000>;
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/ipq8074.dtsi
@@ -253,7 +253,7 @@
 			status = "disabled";
 		};
 
-		qpic_nand: nand@79b0000 {
+		qpic_nand: nand-controller@79b0000 {
 			compatible = "qcom,ipq8074-nand";
 			reg = <0x79b0000 0x10000>;
 			#address-cells = <1>;
@@ -482,7 +482,7 @@
 	clocks {
 		sleep_clk: sleep_clk {
 			compatible = "fixed-clock";
-			clock-frequency = <32000>;
+			clock-frequency = <32768>;
 			#clock-cells = <0>;
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
@@ -508,7 +508,7 @@
 				pins = "gpio63", "gpio64", "gpio65", "gpio66",
 				       "gpio67", "gpio68";
 				drive-strength = <8>;
-				bias-pull-none;
+				bias-disable;
 			};
 		};
 		cdc_pdm_lines_sus: pdm_lines_off {
@@ -521,7 +521,7 @@
 				pins = "gpio63", "gpio64", "gpio65", "gpio66",
 				       "gpio67", "gpio68";
 				drive-strength = <2>;
-				bias-disable;
+				bias-pull-down;
 			};
 		};
 	};
@@ -537,7 +537,7 @@
 				pins = "gpio113", "gpio114", "gpio115",
 				       "gpio116";
 				drive-strength = <8>;
-				bias-pull-none;
+				bias-disable;
 			};
 		};
 
@@ -565,7 +565,7 @@
 			pinconf {
 				pins = "gpio110";
 				drive-strength = <8>;
-				bias-pull-none;
+				bias-disable;
 			};
 		};
 
@@ -591,7 +591,7 @@
 			pinconf {
 				pins = "gpio116";
 				drive-strength = <8>;
-				bias-pull-none;
+				bias-disable;
 			};
 		};
 		ext_mclk_tlmm_lines_sus: mclk_lines_off {
@@ -619,7 +619,7 @@
 				pins = "gpio112", "gpio117", "gpio118",
 					"gpio119";
 				drive-strength = <8>;
-				bias-pull-none;
+				bias-disable;
 			};
 		};
 		ext_sec_tlmm_lines_sus: tlmm_lines_off {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -16,8 +16,8 @@
 	#size-cells = <2>;
 
 	aliases {
-		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
-		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+		mmc0 = &sdhc_1; /* SDC1 eMMC slot */
+		mmc1 = &sdhc_2; /* SDC2 SD card slot */
 	};
 
 	chosen { };
@@ -53,7 +53,7 @@
 			no-map;
 		};
 
-		reserved@8668000 {
+		reserved@86680000 {
 			reg = <0x0 0x86680000 0x0 0x80000>;
 			no-map;
 		};
@@ -66,7 +66,7 @@
 			qcom,client-id = <1>;
 		};
 
-		rfsa@867e00000 {
+		rfsa@867e0000 {
 			reg = <0x0 0x867e0000 0x0 0x20000>;
 			no-map;
 		};
@@ -175,14 +175,14 @@
 	};
 
 	thermal-zones {
-		cpu0_1-thermal {
+		cpu0-1-thermal {
 			polling-delay-passive = <250>;
 			polling-delay = <1000>;
 
 			thermal-sensors = <&tsens 4>;
 
 			trips {
-				cpu0_1_alert0: trip-point@0 {
+				cpu0_1_alert0: trip-point0 {
 					temperature = <75000>;
 					hysteresis = <2000>;
 					type = "passive";
@@ -205,14 +205,14 @@
 			};
 		};
 
-		cpu2_3-thermal {
+		cpu2-3-thermal {
 			polling-delay-passive = <250>;
 			polling-delay = <1000>;
 
 			thermal-sensors = <&tsens 3>;
 
 			trips {
-				cpu2_3_alert0: trip-point@0 {
+				cpu2_3_alert0: trip-point0 {
 					temperature = <75000>;
 					hysteresis = <2000>;
 					type = "passive";
@@ -242,7 +242,7 @@
 			thermal-sensors = <&tsens 2>;
 
 			trips {
-				gpu_alert0: trip-point@0 {
+				gpu_alert0: trip-point0 {
 					temperature = <75000>;
 					hysteresis = <2000>;
 					type = "passive";
@@ -262,7 +262,7 @@
 			thermal-sensors = <&tsens 1>;
 
 			trips {
-				cam_alert0: trip-point@0 {
+				cam_alert0: trip-point0 {
 					temperature = <75000>;
 					hysteresis = <2000>;
 					type = "hot";
@@ -277,7 +277,7 @@
 			thermal-sensors = <&tsens 0>;
 
 			trips {
-				modem_alert0: trip-point@0 {
+				modem_alert0: trip-point0 {
 					temperature = <85000>;
 					hysteresis = <2000>;
 					type = "hot";
@@ -934,7 +934,7 @@
 				reg-names = "mdp_phys";
 
 				interrupt-parent = <&mdss>;
-				interrupts = <0 0>;
+				interrupts = <0>;
 
 				clocks = <&gcc GCC_MDSS_AHB_CLK>,
 					 <&gcc GCC_MDSS_AXI_CLK>,
@@ -966,7 +966,7 @@
 				reg-names = "dsi_ctrl";
 
 				interrupt-parent = <&mdss>;
-				interrupts = <4 0>;
+				interrupts = <4>;
 
 				assigned-clocks = <&gcc BYTE0_CLK_SRC>,
 						  <&gcc PCLK0_CLK_SRC>;
@@ -1097,8 +1097,8 @@
 			vddmx-supply = <&pm8916_l3>;
 			vddpx-supply = <&pm8916_l7>;
 
-			qcom,state = <&wcnss_smp2p_out 0>;
-			qcom,state-names = "stop";
+			qcom,smem-states = <&wcnss_smp2p_out 0>;
+			qcom,smem-state-names = "stop";
 
 			pinctrl-names = "default";
 			pinctrl-0 = <&wcnss_pin_a>;
@@ -1451,7 +1451,7 @@
 			};
 		};
 
-		camss: camss@1b00000 {
+		camss: camss@1b0ac00 {
 			compatible = "qcom,msm8916-camss";
 			reg = <0x1b0ac00 0x200>,
 				<0x1b00030 0x4>,
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts
@@ -30,3 +30,7 @@
 		};
 	};
 };
+
+&msmgpio {
+	gpio-reserved-ranges = <85 4>;
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -433,6 +433,19 @@
 		};
 	};
 
+	etm {
+		compatible = "qcom,coresight-remote-etm";
+
+		out-ports {
+			port {
+				modem_etm_out_funnel_in2: endpoint {
+					remote-endpoint =
+					  <&funnel_in2_in_modem_etm>;
+				};
+			};
+		};
+	};
+
 	psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
@@ -736,6 +749,14 @@
 			clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
 
+			in-ports {
+				port {
+					funnel_in2_in_modem_etm: endpoint {
+						remote-endpoint =
+						  <&modem_etm_out_funnel_in2>;
+					};
+				};
+			};
 
 			out-ports {
 				port {
@@ -1598,6 +1619,8 @@
 				interrupts = <0 138 IRQ_TYPE_LEVEL_HIGH>;
 				phys = <&hsusb_phy2>;
 				phy-names = "usb2-phy";
+				snps,dis_u2_susphy_quirk;
+				snps,dis_enblslpm_quirk;
 			};
 		};
 
@@ -1628,6 +1651,8 @@
 				interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>;
 				phys = <&hsusb_phy1>, <&ssusb_phy_0>;
 				phy-names = "usb2-phy", "usb3-phy";
+				snps,dis_u2_susphy_quirk;
+				snps,dis_enblslpm_quirk;
 			};
 		};
 
@@ -1677,16 +1702,16 @@
 				"csi_clk_mux",
 				"vfe0",
 				"vfe1";
-			interrupts = <GIC_SPI 78 0>,
-				<GIC_SPI 79 0>,
-				<GIC_SPI 80 0>,
-				<GIC_SPI 296 0>,
-				<GIC_SPI 297 0>,
-				<GIC_SPI 298 0>,
-				<GIC_SPI 299 0>,
-				<GIC_SPI 309 0>,
-				<GIC_SPI 314 0>,
-				<GIC_SPI 315 0>;
+			interrupts = <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 79 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 80 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 309 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 315 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "csiphy0",
 				"csiphy1",
 				"csiphy2",
@@ -2094,9 +2119,6 @@
 			nvmem-cells = <&gpu_speed_bin>;
 			nvmem-cell-names = "speed_bin";
 
-			qcom,gpu-quirk-two-pass-use-wfi;
-			qcom,gpu-quirk-fault-detect-mask;
-
 			operating-points-v2 = <&gpu_opp_table>;
 
 			gpu_opp_table: opp-table {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
@@ -23,6 +23,43 @@
 	};
 };
 
+/*
+ * The laptop FW does not appear to support the retention state as it is
+ * not advertised as enabled in ACPI, and enabling it in DT can cause boot
+ * hangs.
+ */
+&CPU0 {
+	cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU1 {
+	cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU2 {
+	cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU3 {
+	cpu-idle-states = <&LITTLE_CPU_SLEEP_1>;
+};
+
+&CPU4 {
+	cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU5 {
+	cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU6 {
+	cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
+&CPU7 {
+	cpu-idle-states = <&BIG_CPU_SLEEP_1>;
+};
+
 &qusb2phy {
 	status = "okay";
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
@@ -27,6 +27,66 @@
 	status = "okay";
 };
 
+&etf {
+	status = "okay";
+};
+
+&etm1 {
+	status = "okay";
+};
+
+&etm2 {
+	status = "okay";
+};
+
+&etm3 {
+	status = "okay";
+};
+
+&etm4 {
+	status = "okay";
+};
+
+&etm5 {
+	status = "okay";
+};
+
+&etm6 {
+	status = "okay";
+};
+
+&etm7 {
+	status = "okay";
+};
+
+&etm8 {
+	status = "okay";
+};
+
+&etr {
+	status = "okay";
+};
+
+&funnel1 {
+	status = "okay";
+};
+
+&funnel2 {
+	status = "okay";
+};
+
+&funnel3 {
+	status = "okay";
+};
+
+&funnel4 {
+	status = "okay";
+};
+
+&funnel5 {
+	status = "okay";
+};
+
 &pm8005_lsid1 {
 	pm8005-regulators {
 		compatible = "qcom,pm8005-regulators";
@@ -51,6 +111,10 @@
 	vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
 };
 
+&replicator1 {
+	status = "okay";
+};
+
 &rpm_requests {
 	pm8998-regulators {
 		compatible = "qcom,rpm-pm8998-regulators";
@@ -249,6 +313,10 @@
 	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
 };
 
+&stm {
+	status = "okay";
+};
+
 &ufshc {
 	vcc-supply = <&vreg_l20a_2p95>;
 	vccq-supply = <&vreg_l26a_1p2>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/msm8998.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/msm8998.dtsi
@@ -246,38 +246,42 @@
 			LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
 				compatible = "arm,idle-state";
 				idle-state-name = "little-retention";
+				/* CPU Retention (C2D), L2 Active */
 				arm,psci-suspend-param = <0x00000002>;
 				entry-latency-us = <81>;
 				exit-latency-us = <86>;
-				min-residency-us = <200>;
+				min-residency-us = <504>;
 			};
 
 			LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 {
 				compatible = "arm,idle-state";
 				idle-state-name = "little-power-collapse";
+				/* CPU + L2 Power Collapse (C3, D4) */
 				arm,psci-suspend-param = <0x40000003>;
-				entry-latency-us = <273>;
-				exit-latency-us = <612>;
-				min-residency-us = <1000>;
+				entry-latency-us = <814>;
+				exit-latency-us = <4562>;
+				min-residency-us = <9183>;
 				local-timer-stop;
 			};
 
 			BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
 				compatible = "arm,idle-state";
 				idle-state-name = "big-retention";
+				/* CPU Retention (C2D), L2 Active */
 				arm,psci-suspend-param = <0x00000002>;
 				entry-latency-us = <79>;
 				exit-latency-us = <82>;
-				min-residency-us = <200>;
+				min-residency-us = <1302>;
 			};
 
 			BIG_CPU_SLEEP_1: cpu-sleep-1-1 {
 				compatible = "arm,idle-state";
 				idle-state-name = "big-power-collapse";
+				/* CPU + L2 Power Collapse (C3, D4) */
 				arm,psci-suspend-param = <0x40000003>;
-				entry-latency-us = <336>;
-				exit-latency-us = <525>;
-				min-residency-us = <1000>;
+				entry-latency-us = <724>;
+				exit-latency-us = <2027>;
+				min-residency-us = <9419>;
 				local-timer-stop;
 			};
 		};
@@ -985,7 +989,7 @@
 
 		tcsr_mutex_regs: syscon@1f40000 {
 			compatible = "syscon";
-			reg = <0x01f40000 0x20000>;
+			reg = <0x01f40000 0x40000>;
 		};
 
 		tlmm: pinctrl@3400000 {
@@ -998,11 +1002,12 @@
 			#interrupt-cells = <0x2>;
 		};
 
-		stm@6002000 {
+		stm: stm@6002000 {
 			compatible = "arm,coresight-stm", "arm,primecell";
 			reg = <0x06002000 0x1000>,
 			      <0x16280000 0x180000>;
 			reg-names = "stm-base", "stm-data-base";
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1016,9 +1021,10 @@
 			};
 		};
 
-		funnel@6041000 {
+		funnel1: funnel@6041000 {
 			compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
 			reg = <0x06041000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1045,9 +1051,10 @@
 			};
 		};
 
-		funnel@6042000 {
+		funnel2: funnel@6042000 {
 			compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
 			reg = <0x06042000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1075,9 +1082,10 @@
 			};
 		};
 
-		funnel@6045000 {
+		funnel3: funnel@6045000 {
 			compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
 			reg = <0x06045000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1113,9 +1121,10 @@
 			};
 		};
 
-		replicator@6046000 {
+		replicator1: replicator@6046000 {
 			compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
 			reg = <0x06046000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1137,9 +1146,10 @@
 			};
 		};
 
-		etf@6047000 {
+		etf: etf@6047000 {
 			compatible = "arm,coresight-tmc", "arm,primecell";
 			reg = <0x06047000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1163,9 +1173,10 @@
 			};
 		};
 
-		etr@6048000 {
+		etr: etr@6048000 {
 			compatible = "arm,coresight-tmc", "arm,primecell";
 			reg = <0x06048000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1181,9 +1192,10 @@
 			};
 		};
 
-		etm@7840000 {
+		etm1: etm@7840000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07840000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1200,9 +1212,10 @@
 			};
 		};
 
-		etm@7940000 {
+		etm2: etm@7940000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07940000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1219,9 +1232,10 @@
 			};
 		};
 
-		etm@7a40000 {
+		etm3: etm@7a40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07a40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1238,9 +1252,10 @@
 			};
 		};
 
-		etm@7b40000 {
+		etm4: etm@7b40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07b40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1257,9 +1272,10 @@
 			};
 		};
 
-		funnel@7b60000 { /* APSS Funnel */
+		funnel4: funnel@7b60000 { /* APSS Funnel */
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07b60000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1343,9 +1359,10 @@
 			};
 		};
 
-		funnel@7b70000 {
+		funnel5: funnel@7b70000 {
 			compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
 			reg = <0x07b70000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
@@ -1369,66 +1386,78 @@
 			};
 		};
 
-		etm@7c40000 {
+		etm5: etm@7c40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07c40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
 
 			cpu = <&CPU4>;
 
-			port{
-				etm4_out: endpoint {
-					remote-endpoint = <&apss_funnel_in4>;
+			out-ports {
+				port{
+					etm4_out: endpoint {
+						remote-endpoint = <&apss_funnel_in4>;
+					};
 				};
 			};
 		};
 
-		etm@7d40000 {
+		etm6: etm@7d40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07d40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
 
 			cpu = <&CPU5>;
 
-			port{
-				etm5_out: endpoint {
-					remote-endpoint = <&apss_funnel_in5>;
+			out-ports {
+				port{
+					etm5_out: endpoint {
+						remote-endpoint = <&apss_funnel_in5>;
+					};
 				};
 			};
 		};
 
-		etm@7e40000 {
+		etm7: etm@7e40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07e40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
 
 			cpu = <&CPU6>;
 
-			port{
-				etm6_out: endpoint {
-					remote-endpoint = <&apss_funnel_in6>;
+			out-ports {
+				port{
+					etm6_out: endpoint {
+						remote-endpoint = <&apss_funnel_in6>;
+					};
 				};
 			};
 		};
 
-		etm@7f40000 {
+		etm8: etm@7f40000 {
 			compatible = "arm,coresight-etm4x", "arm,primecell";
 			reg = <0x07f40000 0x1000>;
+			status = "disabled";
 
 			clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
 			clock-names = "apb_pclk", "atclk";
 
 			cpu = <&CPU7>;
 
-			port{
-				etm7_out: endpoint {
-					remote-endpoint = <&apss_funnel_in7>;
+			out-ports {
+				port{
+					etm7_out: endpoint {
+						remote-endpoint = <&apss_funnel_in7>;
+					};
 				};
 			};
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/pm8150.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/pm8150.dtsi
@@ -17,7 +17,7 @@
 		#size-cells = <0>;
 
 		pon: power-on@800 {
-			compatible = "qcom,pm8916-pon";
+			compatible = "qcom,pm8998-pon";
 			reg = <0x0800>;
 			pwrkey {
 				compatible = "qcom,pm8941-pwrkey";
@@ -73,18 +73,8 @@
 			reg = <0xc000>;
 			gpio-controller;
 			#gpio-cells = <2>;
-			interrupts = <0x0 0xc0 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc1 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc2 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc3 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc4 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc5 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc6 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc7 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc8 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xc9 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xca 0x0 IRQ_TYPE_NONE>,
-				     <0x0 0xcb 0x0 IRQ_TYPE_NONE>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/pm8150b.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/pm8150b.dtsi
@@ -62,18 +62,8 @@
 			reg = <0xc000>;
 			gpio-controller;
 			#gpio-cells = <2>;
-			interrupts = <0x2 0xc0 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc1 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc2 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc3 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc4 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc5 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc6 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc7 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc8 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xc9 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xca 0x0 IRQ_TYPE_NONE>,
-				     <0x2 0xcb 0x0 IRQ_TYPE_NONE>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/pm8150l.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/pm8150l.dtsi
@@ -56,18 +56,8 @@
 			reg = <0xc000>;
 			gpio-controller;
 			#gpio-cells = <2>;
-			interrupts = <0x4 0xc0 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc1 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc2 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc3 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc4 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc5 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc6 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc7 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc8 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xc9 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xca 0x0 IRQ_TYPE_NONE>,
-				     <0x4 0xcb 0x0 IRQ_TYPE_NONE>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 		};
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -113,7 +113,7 @@
 
 		wcd_codec: codec@f000 {
 			compatible = "qcom,pm8916-wcd-analog-codec";
-			reg = <0xf000 0x200>;
+			reg = <0xf000>;
 			reg-names = "pmic-codec-core";
 			clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
 			clock-names = "mclk";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
@@ -73,6 +73,7 @@
 		regulator-always-on;
 		regulator-boot-on;
 		regulator-name = "vdd_apc";
+		regulator-initial-mode = <1>;
 		regulator-min-microvolt = <1048000>;
 		regulator-max-microvolt = <1384000>;
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/qcs404.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/qcs404.dtsi
@@ -533,7 +533,7 @@
 
 			clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
 			resets = <&gcc GCC_PCIEPHY_0_PHY_BCR>,
-				 <&gcc 21>;
+				 <&gcc GCC_PCIE_0_PIPE_ARES>;
 			reset-names = "phy", "pipe";
 
 			clock-output-names = "pcie_0_pipe_clk";
@@ -991,12 +991,12 @@
 				 <&gcc GCC_PCIE_0_SLV_AXI_CLK>;
 			clock-names = "iface", "aux", "master_bus", "slave_bus";
 
-			resets = <&gcc 18>,
-				 <&gcc 17>,
-				 <&gcc 15>,
-				 <&gcc 19>,
+			resets = <&gcc GCC_PCIE_0_AXI_MASTER_ARES>,
+				 <&gcc GCC_PCIE_0_AXI_SLAVE_ARES>,
+				 <&gcc GCC_PCIE_0_AXI_MASTER_STICKY_ARES>,
+				 <&gcc GCC_PCIE_0_CORE_STICKY_ARES>,
 				 <&gcc GCC_PCIE_0_BCR>,
-				 <&gcc 16>;
+				 <&gcc GCC_PCIE_0_AHB_ARES>;
 			reset-names = "axi_m",
 				      "axi_s",
 				      "axi_m_sticky",
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
@@ -165,6 +165,8 @@
 /delete-node/ &venus_mem;
 /delete-node/ &cdsp_mem;
 /delete-node/ &cdsp_pas;
+/delete-node/ &zap_shader;
+/delete-node/ &gpu_mem;
 
 /* Increase the size from 120 MB to 128 MB */
 &mpss_region {
@@ -1308,7 +1310,7 @@
 		config {
 			pins = "gpio126";
 			function = "gpio";
-			bias-no-pull;
+			bias-disable;
 			drive-strength = <2>;
 			output-low;
 		};
@@ -1318,7 +1320,7 @@
 		config {
 			pins = "gpio126";
 			function = "gpio";
-			bias-no-pull;
+			bias-disable;
 			drive-strength = <2>;
 			output-high;
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -53,8 +53,8 @@
 		user4 {
 			label = "green:user4";
 			gpios = <&pm8998_gpio 13 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "panic-indicator";
 			default-state = "off";
+			panic-indicator;
 		};
 
 		wlan {
@@ -337,7 +337,9 @@
 &gcc {
 	protected-clocks = <GCC_QSPI_CORE_CLK>,
 			   <GCC_QSPI_CORE_CLK_SRC>,
-			   <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+			   <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+			   <GCC_LPASS_Q6_AXI_CLK>,
+			   <GCC_LPASS_SWAY_CLK>;
 };
 
 &pm8998_gpio {
@@ -517,6 +519,8 @@
 	vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
 	vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
 	vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+
+	qcom,snoc-host-cap-8bit-quirk;
 };
 
 /* PINCTRL - additions to nodes defined in sdm845.dtsi */
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
@@ -468,6 +468,8 @@
 	vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
 	vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
 	vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+
+	qcom,snoc-host-cap-8bit-quirk;
 };
 
 /* PINCTRL - additions to nodes defined in sdm845.dtsi */
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -715,6 +715,7 @@
 			#clock-cells = <1>;
 			#reset-cells = <1>;
 			#power-domain-cells = <1>;
+			power-domains = <&rpmhpd SDM845_CX>;
 		};
 
 		qfprom@784000 {
@@ -2502,8 +2503,8 @@
 
 			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 488 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 489 IRQ_TYPE_LEVEL_HIGH>;
+				     <GIC_SPI 488 IRQ_TYPE_EDGE_BOTH>,
+				     <GIC_SPI 489 IRQ_TYPE_EDGE_BOTH>;
 			interrupt-names = "hs_phy_irq", "ss_phy_irq",
 					  "dm_hs_phy_irq", "dp_hs_phy_irq";
 
@@ -2546,8 +2547,8 @@
 
 			interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 487 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 490 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 491 IRQ_TYPE_LEVEL_HIGH>;
+				     <GIC_SPI 490 IRQ_TYPE_EDGE_BOTH>,
+				     <GIC_SPI 491 IRQ_TYPE_EDGE_BOTH>;
 			interrupt-names = "hs_phy_irq", "ss_phy_irq",
 					  "dm_hs_phy_irq", "dp_hs_phy_irq";
 
@@ -2824,7 +2825,7 @@
 
 			qcom,gmu = <&gmu>;
 
-			zap-shader {
+			zap_shader: zap-shader {
 				memory-region = <&gpu_mem>;
 			};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
@@ -232,7 +232,9 @@
 &gcc {
 	protected-clocks = <GCC_QSPI_CORE_CLK>,
 			   <GCC_QSPI_CORE_CLK_SRC>,
-			   <GCC_QSPI_CNOC_PERIPH_AHB_CLK>;
+			   <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+			   <GCC_LPASS_Q6_AXI_CLK>,
+			   <GCC_LPASS_SWAY_CLK>;
 };
 
 &i2c1 {
@@ -243,24 +245,23 @@
 &i2c3 {
 	status = "okay";
 	clock-frequency = <400000>;
+	/* Overwrite pinctrl-0 from sdm845.dtsi */
+	pinctrl-0 = <&qup_i2c3_default &i2c3_hid_active>;
 
-	hid@15 {
+	tsel: hid@15 {
 		compatible = "hid-over-i2c";
 		reg = <0x15>;
 		hid-descr-addr = <0x1>;
 
-		interrupts-extended = <&tlmm 37 IRQ_TYPE_EDGE_RISING>;
+		interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
-	hid@2c {
+	tsc2: hid@2c {
 		compatible = "hid-over-i2c";
 		reg = <0x2c>;
 		hid-descr-addr = <0x20>;
 
-		interrupts-extended = <&tlmm 37 IRQ_TYPE_EDGE_RISING>;
-
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c2_hid_active>;
+		interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>;
 	};
 };
 
@@ -268,15 +269,15 @@
 	status = "okay";
 	clock-frequency = <400000>;
 
-	hid@10 {
+	tsc1: hid@10 {
 		compatible = "hid-over-i2c";
 		reg = <0x10>;
 		hid-descr-addr = <0x1>;
 
-		interrupts-extended = <&tlmm 125 IRQ_TYPE_EDGE_FALLING>;
+		interrupts-extended = <&tlmm 125 IRQ_TYPE_LEVEL_LOW>;
 
 		pinctrl-names = "default";
-		pinctrl-0 = <&i2c6_hid_active>;
+		pinctrl-0 = <&i2c5_hid_active>;
 	};
 };
 
@@ -284,7 +285,7 @@
 	status = "okay";
 	clock-frequency = <400000>;
 
-	hid@5c {
+	ecsh: hid@5c {
 		compatible = "hid-over-i2c";
 		reg = <0x5c>;
 		hid-descr-addr = <0x1>;
@@ -292,13 +293,15 @@
 		interrupts-extended = <&tlmm 92 IRQ_TYPE_LEVEL_LOW>;
 
 		pinctrl-names = "default";
-		pinctrl-0 = <&i2c12_hid_active>;
+		pinctrl-0 = <&i2c11_hid_active>;
 	};
 };
 
 &qup_i2c12_default {
-	drive-strength = <2>;
-	bias-disable;
+	pinmux {
+		drive-strength = <2>;
+		bias-disable;
+	};
 };
 
 &qup_uart6_default {
@@ -335,7 +338,7 @@
 &tlmm {
 	gpio-reserved-ranges = <0 4>, <81 4>;
 
-	i2c2_hid_active: i2c2-hid-active {
+	i2c3_hid_active: i2c2-hid-active {
 		pins = <37>;
 		function = "gpio";
 
@@ -344,7 +347,7 @@
 		drive-strength = <2>;
 	};
 
-	i2c6_hid_active: i2c6-hid-active {
+	i2c5_hid_active: i2c5-hid-active {
 		pins = <125>;
 		function = "gpio";
 
@@ -353,7 +356,7 @@
 		drive-strength = <2>;
 	};
 
-	i2c12_hid_active: i2c12-hid-active {
+	i2c11_hid_active: i2c11-hid-active {
 		pins = <92>;
 		function = "gpio";
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/qcom/sm8150.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/qcom/sm8150.dtsi
@@ -336,7 +336,7 @@
 			      <0x0 0x03D00000 0x0 0x300000>;
 			reg-names = "west", "east", "north", "south";
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
-			gpio-ranges = <&tlmm 0 0 175>;
+			gpio-ranges = <&tlmm 0 0 176>;
 			gpio-controller;
 			#gpio-cells = <2>;
 			interrupt-controller;
@@ -459,9 +459,9 @@
 			qcom,tcs-offset = <0xd00>;
 			qcom,drv-id = <2>;
 			qcom,tcs-config = <ACTIVE_TCS  2>,
-					  <SLEEP_TCS   1>,
-					  <WAKE_TCS    1>,
-					  <CONTROL_TCS 0>;
+					  <SLEEP_TCS   3>,
+					  <WAKE_TCS    3>,
+					  <CONTROL_TCS 1>;
 
 			rpmhcc: clock-controller {
 				compatible = "qcom,sm8150-rpmh-clk";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/cat875.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/cat875.dtsi
@@ -22,7 +22,6 @@
 	status = "okay";
 
 	phy0: ethernet-phy@0 {
-		rxc-skew-ps = <1500>;
 		reg = <0>;
 		interrupt-parent = <&gpio2>;
 		interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/hihope-common.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/hihope-common.dtsi
@@ -86,7 +86,7 @@
 
 		label = "rcar-sound";
 
-		dais = <&rsnd_port0>;
+		dais = <&rsnd_port>;
 	};
 
 	vbus0_usb2: regulator-vbus0-usb2 {
@@ -191,7 +191,7 @@
 		port@2 {
 			reg = <2>;
 			dw_hdmi0_snd_in: endpoint {
-				remote-endpoint = <&rsnd_endpoint0>;
+				remote-endpoint = <&rsnd_endpoint>;
 			};
 		};
 	};
@@ -327,17 +327,15 @@
 	/* Single DAI */
 	#sound-dai-cells = <0>;
 
-	ports {
-		rsnd_port0: port@0 {
-			rsnd_endpoint0: endpoint {
-				remote-endpoint = <&dw_hdmi0_snd_in>;
-
-				dai-format = "i2s";
-				bitclock-master = <&rsnd_endpoint0>;
-				frame-master = <&rsnd_endpoint0>;
+	rsnd_port: port {
+		rsnd_endpoint: endpoint {
+			remote-endpoint = <&dw_hdmi0_snd_in>;
+
+			dai-format = "i2s";
+			bitclock-master = <&rsnd_endpoint>;
+			frame-master = <&rsnd_endpoint>;
 
-				playback = <&ssi2>;
-			};
+			playback = <&ssi2>;
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi
@@ -23,7 +23,6 @@
 	status = "okay";
 
 	phy0: ethernet-phy@0 {
-		rxc-skew-ps = <1500>;
 		reg = <0>;
 		interrupt-parent = <&gpio2>;
 		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
@@ -1726,17 +1726,6 @@
 				      "ssi.1", "ssi.0";
 			status = "disabled";
 
-			ports {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				port@0 {
-					reg = <0>;
-				};
-				port@1 {
-					reg = <1>;
-				};
-			};
-
 			rcar_sound,ctu {
 				ctu00: ctu-0 { };
 				ctu01: ctu-1 { };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a774c0.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a774c0.dtsi
@@ -49,17 +49,14 @@
 		opp-shared;
 		opp-800000000 {
 			opp-hz = /bits/ 64 <800000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 		};
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 		};
 		opp-1200000000 {
 			opp-hz = /bits/ 64 <1200000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 			opp-suspend;
 		};
@@ -1212,9 +1209,8 @@
 			reg = <0 0xe6ea0000 0 0x0064>;
 			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 210>;
-			dmas = <&dmac1 0x43>, <&dmac1 0x42>,
-			       <&dmac2 0x43>, <&dmac2 0x42>;
-			dma-names = "tx", "rx", "tx", "rx";
+			dmas = <&dmac0 0x43>, <&dmac0 0x42>;
+			dma-names = "tx", "rx";
 			power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
 			resets = <&cpg 210>;
 			#address-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts
@@ -59,7 +59,7 @@
 	memory@48000000 {
 		device_type = "memory";
 		/* first 128MB is reserved for secure area. */
-		reg = <0x0 0x48000000 0x0 0x38000000>;
+		reg = <0x0 0x48000000 0x0 0x78000000>;
 	};
 
 	osc5_clk: osc5-clock {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77970.dtsi
@@ -652,7 +652,7 @@
 		};
 
 		pwm3: pwm@e6e33000 {
-			compatible = "renesas,pwm-r8a7790", "renesas,pwm-rcar";
+			compatible = "renesas,pwm-r8a77970", "renesas,pwm-rcar";
 			reg = <0 0xe6e33000 0 8>;
 			#pwm-cells = <2>;
 			clocks = <&cpg CPG_MOD 523>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77980.dtsi
@@ -990,8 +990,8 @@
 
 					reg = <1>;
 
-					vin4csi41: endpoint@2 {
-						reg = <2>;
+					vin4csi41: endpoint@3 {
+						reg = <3>;
 						remote-endpoint = <&csi41vin4>;
 					};
 				};
@@ -1018,8 +1018,8 @@
 
 					reg = <1>;
 
-					vin5csi41: endpoint@2 {
-						reg = <2>;
+					vin5csi41: endpoint@3 {
+						reg = <3>;
 						remote-endpoint = <&csi41vin5>;
 					};
 				};
@@ -1046,8 +1046,8 @@
 
 					reg = <1>;
 
-					vin6csi41: endpoint@2 {
-						reg = <2>;
+					vin6csi41: endpoint@3 {
+						reg = <3>;
 						remote-endpoint = <&csi41vin6>;
 					};
 				};
@@ -1074,8 +1074,8 @@
 
 					reg = <1>;
 
-					vin7csi41: endpoint@2 {
-						reg = <2>;
+					vin7csi41: endpoint@3 {
+						reg = <3>;
 						remote-endpoint = <&csi41vin7>;
 					};
 				};
@@ -1318,6 +1318,7 @@
 		ipmmu_vip0: mmu@e7b00000 {
 			compatible = "renesas,ipmmu-r8a77980";
 			reg = <0 0xe7b00000 0 0x1000>;
+			renesas,ipmmu-main = <&ipmmu_mm 4>;
 			power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
 			#iommu-cells = <1>;
 		};
@@ -1325,6 +1326,7 @@
 		ipmmu_vip1: mmu@e7960000 {
 			compatible = "renesas,ipmmu-r8a77980";
 			reg = <0 0xe7960000 0 0x1000>;
+			renesas,ipmmu-main = <&ipmmu_mm 11>;
 			power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
 			#iommu-cells = <1>;
 		};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts
@@ -636,7 +636,6 @@
 	/* audio_clkout0/1/2/3 */
 	#clock-cells = <1>;
 	clock-frequency = <12288000 11289600>;
-	clkout-lr-synchronous;
 
 	status = "okay";
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77990.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77990.dtsi
@@ -60,17 +60,14 @@
 		opp-shared;
 		opp-800000000 {
 			opp-hz = /bits/ 64 <800000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 		};
 		opp-1000000000 {
 			opp-hz = /bits/ 64 <1000000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 		};
 		opp-1200000000 {
 			opp-hz = /bits/ 64 <1200000000>;
-			opp-microvolt = <820000>;
 			clock-latency-ns = <300000>;
 			opp-suspend;
 		};
@@ -1168,9 +1165,8 @@
 			reg = <0 0xe6ea0000 0 0x0064>;
 			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 210>;
-			dmas = <&dmac1 0x43>, <&dmac1 0x42>,
-			       <&dmac2 0x43>, <&dmac2 0x42>;
-			dma-names = "tx", "rx", "tx", "rx";
+			dmas = <&dmac0 0x43>, <&dmac0 0x42>;
+			dma-names = "tx", "rx";
 			power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
 			resets = <&cpg 210>;
 			#address-cells = <1>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/r8a77995-draak.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/r8a77995-draak.dts
@@ -277,10 +277,6 @@
 		interrupt-parent = <&gpio1>;
 		interrupts = <28 IRQ_TYPE_LEVEL_LOW>;
 
-		/* Depends on LVDS */
-		max-clock = <135000000>;
-		min-vrefresh = <50>;
-
 		adi,input-depth = <8>;
 		adi,input-colorspace = "rgb";
 		adi,input-clock = "1x";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi
@@ -269,7 +269,7 @@
 	};
 
 	scif1_pins: scif1 {
-		groups = "scif1_data_b", "scif1_ctrl";
+		groups = "scif1_data_b";
 		function = "scif1";
 	};
 
@@ -329,7 +329,6 @@
 &scif1 {
 	pinctrl-0 = <&scif1_pins>;
 	pinctrl-names = "default";
-	uart-has-rtscts;
 
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/renesas/ulcb.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/renesas/ulcb.dtsi
@@ -470,6 +470,7 @@
 	mmc-hs200-1_8v;
 	mmc-hs400-1_8v;
 	non-removable;
+	full-pwr-cycle-in-suspend;
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/px30.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/px30.dtsi
@@ -213,20 +213,20 @@
 			#size-cells = <0>;
 
 			/* These power domains are grouped by VD_LOGIC */
-			pd_usb@PX30_PD_USB {
+			power-domain@PX30_PD_USB {
 				reg = <PX30_PD_USB>;
 				clocks = <&cru HCLK_HOST>,
 					 <&cru HCLK_OTG>,
 					 <&cru SCLK_OTG_ADP>;
 				pm_qos = <&qos_usb_host>, <&qos_usb_otg>;
 			};
-			pd_sdcard@PX30_PD_SDCARD {
+			power-domain@PX30_PD_SDCARD {
 				reg = <PX30_PD_SDCARD>;
 				clocks = <&cru HCLK_SDMMC>,
 					 <&cru SCLK_SDMMC>;
 				pm_qos = <&qos_sdmmc>;
 			};
-			pd_gmac@PX30_PD_GMAC {
+			power-domain@PX30_PD_GMAC {
 				reg = <PX30_PD_GMAC>;
 				clocks = <&cru ACLK_GMAC>,
 					 <&cru PCLK_GMAC>,
@@ -234,7 +234,7 @@
 					 <&cru SCLK_GMAC_RX_TX>;
 				pm_qos = <&qos_gmac>;
 			};
-			pd_mmc_nand@PX30_PD_MMC_NAND {
+			power-domain@PX30_PD_MMC_NAND {
 				reg = <PX30_PD_MMC_NAND>;
 				clocks =  <&cru HCLK_NANDC>,
 					  <&cru HCLK_EMMC>,
@@ -247,14 +247,14 @@
 				pm_qos = <&qos_emmc>, <&qos_nand>,
 					 <&qos_sdio>, <&qos_sfc>;
 			};
-			pd_vpu@PX30_PD_VPU {
+			power-domain@PX30_PD_VPU {
 				reg = <PX30_PD_VPU>;
 				clocks = <&cru ACLK_VPU>,
 					 <&cru HCLK_VPU>,
 					 <&cru SCLK_CORE_VPU>;
 				pm_qos = <&qos_vpu>, <&qos_vpu_r128>;
 			};
-			pd_vo@PX30_PD_VO {
+			power-domain@PX30_PD_VO {
 				reg = <PX30_PD_VO>;
 				clocks = <&cru ACLK_RGA>,
 					 <&cru ACLK_VOPB>,
@@ -270,7 +270,7 @@
 				pm_qos = <&qos_rga_rd>, <&qos_rga_wr>,
 					 <&qos_vop_m0>, <&qos_vop_m1>;
 			};
-			pd_vi@PX30_PD_VI {
+			power-domain@PX30_PD_VI {
 				reg = <PX30_PD_VI>;
 				clocks = <&cru ACLK_CIF>,
 					 <&cru ACLK_ISP>,
@@ -281,7 +281,7 @@
 					 <&qos_isp_wr>, <&qos_isp_m1>,
 					 <&qos_vip>;
 			};
-			pd_gpu@PX30_PD_GPU {
+			power-domain@PX30_PD_GPU {
 				reg = <PX30_PD_GPU>;
 				clocks = <&cru SCLK_GPU>;
 				pm_qos = <&qos_gpu>;
@@ -768,7 +768,7 @@
 		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
 			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		max-frequency = <150000000>;
 		pinctrl-names = "default";
@@ -783,7 +783,7 @@
 		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
 			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		max-frequency = <150000000>;
 		pinctrl-names = "default";
@@ -798,7 +798,7 @@
 		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
 			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		max-frequency = <150000000>;
 		power-domains = <&power PX30_PD_MMC_NAND>;
@@ -860,7 +860,7 @@
 	vopl_mmu: iommu@ff470f00 {
 		compatible = "rockchip,iommu";
 		reg = <0x0 0xff470f00 0x0 0x100>;
-		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "vopl_mmu";
 		clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
 		clock-names = "aclk", "hclk";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3328-evb.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3328-evb.dts
@@ -86,13 +86,13 @@
 	assigned-clock-rate = <50000000>;
 	assigned-clocks = <&cru SCLK_MAC2PHY>;
 	assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>;
-
+	status = "okay";
 };
 
 &i2c1 {
 	status = "okay";
 
-	rk805: rk805@18 {
+	rk805: pmic@18 {
 		compatible = "rockchip,rk805";
 		reg = <0x18>;
 		interrupt-parent = <&gpio2>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
@@ -90,7 +90,6 @@
 			linux,default-trigger = "heartbeat";
 			gpios = <&rk805 1 GPIO_ACTIVE_LOW>;
 			default-state = "on";
-			mode = <0x23>;
 		};
 
 		user {
@@ -98,7 +97,6 @@
 			linux,default-trigger = "mmc1";
 			gpios = <&rk805 0 GPIO_ACTIVE_LOW>;
 			default-state = "off";
-			mode = <0x05>;
 		};
 	};
 };
@@ -333,6 +331,7 @@
 };
 
 &usb20_otg {
+	dr_mode = "host";
 	status = "okay";
 };
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
@@ -169,7 +169,7 @@
 &i2c1 {
 	status = "okay";
 
-	rk805: rk805@18 {
+	rk805: pmic@18 {
 		compatible = "rockchip,rk805";
 		reg = <0x18>;
 		interrupt-parent = <&gpio2>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -270,13 +270,13 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 
-			pd_hevc@RK3328_PD_HEVC {
+			power-domain@RK3328_PD_HEVC {
 				reg = <RK3328_PD_HEVC>;
 			};
-			pd_video@RK3328_PD_VIDEO {
+			power-domain@RK3328_PD_VIDEO {
 				reg = <RK3328_PD_VIDEO>;
 			};
-			pd_vpu@RK3328_PD_VPU {
+			power-domain@RK3328_PD_VPU {
 				reg = <RK3328_PD_VPU>;
 				clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
 			};
@@ -555,7 +555,7 @@
 
 	gpu: gpu@ff300000 {
 		compatible = "rockchip,rk3328-mali", "arm,mali-450";
-		reg = <0x0 0xff300000 0x0 0x40000>;
+		reg = <0x0 0xff300000 0x0 0x30000>;
 		interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
 			     <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
@@ -1190,8 +1190,8 @@
 
 		uart0 {
 			uart0_xfer: uart0-xfer {
-				rockchip,pins = <1 RK_PB1 1 &pcfg_pull_up>,
-						<1 RK_PB0 1 &pcfg_pull_none>;
+				rockchip,pins = <1 RK_PB1 1 &pcfg_pull_none>,
+						<1 RK_PB0 1 &pcfg_pull_up>;
 			};
 
 			uart0_cts: uart0-cts {
@@ -1209,8 +1209,8 @@
 
 		uart1 {
 			uart1_xfer: uart1-xfer {
-				rockchip,pins = <3 RK_PA4 4 &pcfg_pull_up>,
-						<3 RK_PA6 4 &pcfg_pull_none>;
+				rockchip,pins = <3 RK_PA4 4 &pcfg_pull_none>,
+						<3 RK_PA6 4 &pcfg_pull_up>;
 			};
 
 			uart1_cts: uart1-cts {
@@ -1228,15 +1228,15 @@
 
 		uart2-0 {
 			uart2m0_xfer: uart2m0-xfer {
-				rockchip,pins = <1 RK_PA0 2 &pcfg_pull_up>,
-						<1 RK_PA1 2 &pcfg_pull_none>;
+				rockchip,pins = <1 RK_PA0 2 &pcfg_pull_none>,
+						<1 RK_PA1 2 &pcfg_pull_up>;
 			};
 		};
 
 		uart2-1 {
 			uart2m1_xfer: uart2m1-xfer {
-				rockchip,pins = <2 RK_PA0 1 &pcfg_pull_up>,
-						<2 RK_PA1 1 &pcfg_pull_none>;
+				rockchip,pins = <2 RK_PA0 1 &pcfg_pull_none>,
+						<2 RK_PA1 1 &pcfg_pull_up>;
 			};
 		};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
@@ -156,7 +156,7 @@
 	pinctrl-0 = <&rgmii_pins>;
 	snps,reset-active-low;
 	snps,reset-delays-us = <0 10000 50000>;
-	snps,reset-gpio = <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>;
+	snps,reset-gpio = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
 	tx_delay = <0x10>;
 	rx_delay = <0x10>;
 	status = "okay";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
@@ -666,12 +666,15 @@
 	sd-uhs-sdr104;
 
 	/* Power supply */
-	vqmmc-supply = &vcc1v8_s3;	/* IO line */
-	vmmc-supply = &vcc_sdio;	/* card's power */
+	vqmmc-supply = <&vcc1v8_s3>;	/* IO line */
+	vmmc-supply = <&vcc_sdio>;	/* card's power */
 
+	#address-cells = <1>;
+	#size-cells = <0>;
 	status = "okay";
 
 	brcmf: wifi@1 {
+		reg = <1>;
 		compatible = "brcm,bcm4329-fmac";
 		interrupt-parent = <&gpio0>;
 		interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
@@ -77,3 +77,8 @@
 		};
 	};
 };
+
+&wlan_host_wake_l {
+	/* Kevin has an external pull up, but Bob does not. */
+	rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
+};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
@@ -237,6 +237,14 @@
 &edp {
 	status = "okay";
 
+	/*
+	 * eDP PHY/clk don't sync reliably at anything other than 24 MHz. Only
+	 * set this here, because rk3399-gru.dtsi ensures we can generate this
+	 * off GPLL=600MHz, whereas some other RK3399 boards may not.
+	 */
+	assigned-clocks = <&cru PCLK_EDP>;
+	assigned-clock-rates = <24000000>;
+
 	ports {
 		edp_out: port@1 {
 			reg = <1>;
@@ -397,6 +405,7 @@
 	};
 
 	wlan_host_wake_l: wlan-host-wake-l {
+		/* Kevin has an external pull up, but Bob does not */
 		rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -281,7 +281,7 @@
 
 	sound: sound {
 		compatible = "rockchip,rk3399-gru-sound";
-		rockchip,cpu = <&i2s0 &i2s2>;
+		rockchip,cpu = <&i2s0 &spdif>;
 	};
 };
 
@@ -432,10 +432,6 @@
 	status = "okay";
 };
 
-&i2s2 {
-	status = "okay";
-};
-
 &io_domains {
 	status = "okay";
 
@@ -532,6 +528,17 @@
 	vqmmc-supply = <&ppvar_sd_card_io>;
 };
 
+&spdif {
+	status = "okay";
+
+	/*
+	 * SPDIF is routed internally to DP; we either don't use these pins, or
+	 * mux them to something else.
+	 */
+	/delete-property/ pinctrl-0;
+	/delete-property/ pinctrl-names;
+};
+
 &spi1 {
 	status = "okay";
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
@@ -654,9 +654,12 @@
 	sd-uhs-sdr104;
 	vqmmc-supply = <&vcc1v8_s3>;
 	vmmc-supply = <&vccio_sd>;
+	#address-cells = <1>;
+	#size-cells = <0>;
 	status = "okay";
 
 	brcmf: wifi@1 {
+		reg = <1>;
 		compatible = "brcm,bcm4329-fmac";
 		interrupt-parent = <&gpio0>;
 		interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
@@ -682,7 +685,6 @@
 &sdhci {
 	bus-width = <8>;
 	mmc-hs400-1_8v;
-	mmc-hs400-enhanced-strobe;
 	non-removable;
 	status = "okay";
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
@@ -49,7 +49,7 @@
 		regulator-boot-on;
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
-		vim-supply = <&vcc3v3_sys>;
+		vin-supply = <&vcc3v3_sys>;
 	};
 
 	vcc3v3_sys: vcc3v3-sys {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
@@ -94,33 +94,6 @@
 	};
 };
 
-&gpu_thermal {
-	trips {
-		gpu_warm: gpu_warm {
-			temperature = <55000>;
-			hysteresis = <2000>;
-			type = "active";
-		};
-
-		gpu_hot: gpu_hot {
-			temperature = <65000>;
-			hysteresis = <2000>;
-			type = "active";
-		};
-	};
-	cooling-maps {
-		map1 {
-			trip = <&gpu_warm>;
-			cooling-device = <&fan THERMAL_NO_LIMIT 1>;
-		};
-
-		map2 {
-			trip = <&gpu_hot>;
-			cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
-		};
-	};
-};
-
 &pinctrl {
 	ir {
 		ir_rx: ir-rx {
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
@@ -648,9 +648,12 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
 	sd-uhs-sdr104;
+	#address-cells = <1>;
+	#size-cells = <0>;
 	status = "okay";
 
 	brcmf: wifi@1 {
+		reg = <1>;
 		compatible = "brcm,bcm4329-fmac";
 		interrupt-parent = <&gpio0>;
 		interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
@@ -203,7 +203,7 @@
 	cap-sd-highspeed;
 	cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
 	disable-wp;
-	max-frequency = <150000000>;
+	max-frequency = <40000000>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
 	vmmc-supply = <&vcc3v3_baseboard>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
@@ -101,8 +101,7 @@
 
 	vcc5v0_host: vcc5v0-host-regulator {
 		compatible = "regulator-fixed";
-		gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>;
-		enable-active-low;
+		gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_LOW>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&vcc5v0_host_en>;
 		regulator-name = "vcc5v0_host";
@@ -157,7 +156,7 @@
 	phy-mode = "rgmii";
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmii_pins>;
-	snps,reset-gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>;
+	snps,reset-gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
 	snps,reset-active-low;
 	snps,reset-delays-us = <0 10000 50000>;
 	tx_delay = <0x10>;
@@ -467,6 +466,12 @@
 };
 
 &sdhci {
+	/*
+	 * Signal integrity isn't great at 200MHz but 100MHz has proven stable
+	 * enough.
+	 */
+	max-frequency = <100000000>;
+
 	bus-width = <8>;
 	mmc-hs400-1_8v;
 	mmc-hs400-enhanced-strobe;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
@@ -441,7 +441,6 @@
 &i2s1 {
 	rockchip,playback-channels = <2>;
 	rockchip,capture-channels = <2>;
-	status = "okay";
 };
 
 &i2s2 {
@@ -452,7 +451,7 @@
 	status = "okay";
 
 	bt656-supply = <&vcc_3v0>;
-	audio-supply = <&vcc_3v0>;
+	audio-supply = <&vcc1v8_codec>;
 	sdmmc-supply = <&vcc_sdio>;
 	gpio1830-supply = <&vcc_3v0>;
 };
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -29,6 +29,9 @@
 		i2c6 = &i2c6;
 		i2c7 = &i2c7;
 		i2c8 = &i2c8;
+		mmc0 = &sdio0;
+		mmc1 = &sdmmc;
+		mmc2 = &sdhci;
 		serial0 = &uart0;
 		serial1 = &uart1;
 		serial2 = &uart2;
@@ -229,6 +232,7 @@
 		reg = <0x0 0xf8000000 0x0 0x2000000>,
 		      <0x0 0xfd000000 0x0 0x1000000>;
 		reg-names = "axi-base", "apb-base";
+		device_type = "pci";
 		#address-cells = <3>;
 		#size-cells = <2>;
 		#interrupt-cells = <1>;
@@ -247,7 +251,6 @@
 				<0 0 0 2 &pcie0_intc 1>,
 				<0 0 0 3 &pcie0_intc 2>,
 				<0 0 0 4 &pcie0_intc 3>;
-		linux,pci-domain = <0>;
 		max-link-speed = <1>;
 		msi-map = <0x0 &its 0x0 0x1000>;
 		phys = <&pcie_phy 0>, <&pcie_phy 1>,
@@ -410,7 +413,7 @@
 		reset-names = "usb3-otg";
 		status = "disabled";
 
-		usbdrd_dwc3_0: dwc3 {
+		usbdrd_dwc3_0: usb@fe800000 {
 			compatible = "snps,dwc3";
 			reg = <0x0 0xfe800000 0x0 0x100000>;
 			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
@@ -446,7 +449,7 @@
 		reset-names = "usb3-otg";
 		status = "disabled";
 
-		usbdrd_dwc3_1: dwc3 {
+		usbdrd_dwc3_1: usb@fe900000 {
 			compatible = "snps,dwc3";
 			reg = <0x0 0xfe900000 0x0 0x100000>;
 			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
@@ -1444,6 +1447,7 @@
 			reg = <0xf780 0x24>;
 			clocks = <&sdhci>;
 			clock-names = "emmcclk";
+			drive-impedance-ohm = <50>;
 			#phy-cells = <0>;
 			status = "disabled";
 		};
@@ -1454,7 +1458,6 @@
 			clock-names = "refclk";
 			#phy-cells = <1>;
 			resets = <&cru SRST_PCIEPHY>;
-			drive-impedance-ohm = <50>;
 			reset-names = "phy";
 			status = "disabled";
 		};
@@ -1743,10 +1746,10 @@
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru PCLK_HDMI_CTRL>,
 			 <&cru SCLK_HDMI_SFR>,
-			 <&cru PLL_VPLL>,
+			 <&cru SCLK_HDMI_CEC>,
 			 <&cru PCLK_VIO_GRF>,
-			 <&cru SCLK_HDMI_CEC>;
-		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+			 <&cru PLL_VPLL>;
+		clock-names = "iahb", "isfr", "cec", "grf", "vpll";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
@@ -1881,10 +1884,10 @@
 	gpu: gpu@ff9a0000 {
 		compatible = "rockchip,rk3399-mali", "arm,mali-t860";
 		reg = <0x0 0xff9a0000 0x0 0x10000>;
-		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH 0>,
-			     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH 0>,
-			     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH 0>;
-		interrupt-names = "gpu", "job", "mmu";
+		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH 0>,
+			     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = "job", "mmu", "gpu";
 		clocks = <&cru ACLK_GPU>;
 		power-domains = <&power RK3399_PD_GPU>;
 		status = "disabled";
@@ -2314,7 +2317,7 @@
 			};
 		};
 
-		sleep {
+		suspend {
 			ap_pwroff: ap-pwroff {
 				rockchip,pins = <1 RK_PA5 1 &pcfg_pull_none>;
 			};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
@@ -718,7 +718,7 @@
 			clocks = <&sys_clk 6>;
 			reset-names = "ether";
 			resets = <&sys_rst 6>;
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 			local-mac-address = [00 00 00 00 00 00];
 			socionext,syscon-phy-mode = <&soc_glue 0>;
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
@@ -509,7 +509,7 @@
 			clocks = <&sys_clk 6>;
 			reset-names = "ether";
 			resets = <&sys_rst 6>;
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 			local-mac-address = [00 00 00 00 00 00];
 			socionext,syscon-phy-mode = <&soc_glue 0>;
 
@@ -530,7 +530,7 @@
 			clocks = <&sys_clk 7>;
 			reset-names = "ether";
 			resets = <&sys_rst 7>;
-			phy-mode = "rgmii";
+			phy-mode = "rgmii-id";
 			local-mac-address = [00 00 00 00 00 00];
 			socionext,syscon-phy-mode = <&soc_glue 1>;
 
@@ -544,8 +544,8 @@
 			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
 			status = "disabled";
 			reg = <0x65a00000 0xcd00>;
-			interrupt-names = "host", "peripheral";
-			interrupts = <0 134 4>, <0 135 4>;
+			interrupt-names = "dwc_usb3";
+			interrupts = <0 134 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb2>;
 			clock-names = "ref", "bus_early", "suspend";
@@ -646,8 +646,8 @@
 			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
 			status = "disabled";
 			reg = <0x65c00000 0xcd00>;
-			interrupt-names = "host", "peripheral";
-			interrupts = <0 137 4>, <0 138 4>;
+			interrupt-names = "dwc_usb3";
+			interrupts = <0 137 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_usb1>, <&pinctrl_usb3>;
 			clock-names = "ref", "bus_early", "suspend";
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/ti/k3-am65-main.dtsi
@@ -307,6 +307,7 @@
 		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
 		dma-coherent;
 		power-domains = <&k3_pds 151 TI_SCI_PD_EXCLUSIVE>;
+		clocks = <&k3_clks 151 2>, <&k3_clks 151 7>;
 		assigned-clocks = <&k3_clks 151 2>, <&k3_clks 151 7>;
 		assigned-clock-parents = <&k3_clks 151 4>,	/* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
 					 <&k3_clks 151 9>;	/* set PIPE3_TXB_CLK to CLK_12M_RC/256 (for HS only) */
@@ -346,6 +347,7 @@
 		interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
 		dma-coherent;
 		power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
+		clocks = <&k3_clks 152 2>;
 		assigned-clocks = <&k3_clks 152 2>;
 		assigned-clock-parents = <&k3_clks 152 4>;	/* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
@@ -43,6 +43,7 @@
 	smmu0: smmu@36600000 {
 		compatible = "arm,smmu-v3";
 		reg = <0x0 0x36600000 0x0 0x100000>;
+		power-domains = <&k3_pds 229 TI_SCI_PD_EXCLUSIVE>;
 		interrupt-parent = <&gic500>;
 		interrupts = <GIC_SPI 772 IRQ_TYPE_EDGE_RISING>,
 			     <GIC_SPI 768 IRQ_TYPE_EDGE_RISING>;
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/ti/k3-j721e.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/ti/k3-j721e.dtsi
@@ -60,7 +60,7 @@
 			i-cache-sets = <256>;
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
-			d-cache-sets = <128>;
+			d-cache-sets = <256>;
 			next-level-cache = <&L2_0>;
 		};
 
@@ -74,7 +74,7 @@
 			i-cache-sets = <256>;
 			d-cache-size = <0x8000>;
 			d-cache-line-size = <64>;
-			d-cache-sets = <128>;
+			d-cache-sets = <256>;
 			next-level-cache = <&L2_0>;
 		};
 	};
@@ -84,7 +84,7 @@
 		cache-level = <2>;
 		cache-size = <0x100000>;
 		cache-line-size = <64>;
-		cache-sets = <2048>;
+		cache-sets = <1024>;
 		next-level-cache = <&msmc_l3>;
 	};
 
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
+++ linux-ein-5.4.0/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
@@ -131,7 +131,7 @@
 		reg = <0>;
 
 		partition@0 {
-			label = "data";
+			label = "spi0-data";
 			reg = <0x0 0x100000>;
 		};
 	};
@@ -149,7 +149,7 @@
 		reg = <0>;
 
 		partition@0 {
-			label = "data";
+			label = "spi1-data";
 			reg = <0x0 0x84000>;
 		};
 	};
--- linux-ein-5.4.0.orig/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ linux-ein-5.4.0/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -419,7 +419,7 @@
 		};
 
 		i2c0: i2c@ff020000 {
-			compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 17 4>;
@@ -429,7 +429,7 @@
 		};
 
 		i2c1: i2c@ff030000 {
-			compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 18 4>;
@@ -582,7 +582,7 @@
 		};
 
 		uart0: serial@ff000000 {
-			compatible = "cdns,uart-r1p12", "xlnx,xuartps";
+			compatible = "xlnx,zynqmp-uart", "cdns,uart-r1p12";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 21 4>;
@@ -591,7 +591,7 @@
 		};
 
 		uart1: serial@ff010000 {
-			compatible = "cdns,uart-r1p12", "xlnx,xuartps";
+			compatible = "xlnx,zynqmp-uart", "cdns,uart-r1p12";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 22 4>;
--- linux-ein-5.4.0.orig/arch/arm64/configs/defconfig
+++ linux-ein-5.4.0/arch/arm64/configs/defconfig
@@ -486,6 +486,7 @@
 CONFIG_REGULATOR_HI655X=y
 CONFIG_REGULATOR_MAX77620=y
 CONFIG_REGULATOR_MAX8973=y
+CONFIG_REGULATOR_PCA9450=y
 CONFIG_REGULATOR_PFUZE100=y
 CONFIG_REGULATOR_PWM=y
 CONFIG_REGULATOR_QCOM_RPMH=y
--- linux-ein-5.4.0.orig/arch/arm64/configs/imx_v8_pe100a_defconfig
+++ linux-ein-5.4.0/arch/arm64/configs/imx_v8_pe100a_defconfig
@@ -0,0 +1,938 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_NUMA_BALANCING=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_ARCH_LAYERSCAPE=y
+CONFIG_ARCH_MXC=y
+CONFIG_ARCH_S32=y
+CONFIG_SOC_S32V234=y
+CONFIG_ARM64_VA_BITS_48=y
+CONFIG_SCHED_MC=y
+CONFIG_NUMA=y
+CONFIG_SECCOMP=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_XEN=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_COMPAT=y
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_TEST_SUSPEND=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_ARM_PSCI_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_ACPI_CPPC_CPUFREQ=m
+CONFIG_ARM_SCPI_CPUFREQ=y
+CONFIG_ARM_IMX_CPUFREQ_DT=y
+CONFIG_QORIQ_CPUFREQ=y
+CONFIG_ARM_SCPI_PROTOCOL=y
+CONFIG_EFI_CAPSULE_LOADER=y
+CONFIG_IMX_DSP=y
+CONFIG_IMX_SCU=y
+CONFIG_IMX_SCU_PD=y
+CONFIG_IMX_SECO_MU=y
+CONFIG_ACPI=y
+CONFIG_ACPI_APEI=y
+CONFIG_ACPI_APEI_GHES=y
+CONFIG_ACPI_APEI_PCIEAER=y
+CONFIG_ACPI_APEI_MEMORY_FAILURE=y
+CONFIG_ACPI_APEI_EINJ=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_SHA512_ARM64_CE=m
+CONFIG_CRYPTO_SHA3_ARM64=m
+CONFIG_CRYPTO_SM3_ARM64_CE=m
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_CHACHA20_NEON=m
+CONFIG_CRYPTO_AES_ARM64_BS=m
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_KSM=y
+CONFIG_MEMORY_FAILURE=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IPV6_SIT=m
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_LLC2=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_CBS=y
+CONFIG_NET_SCH_TAPRIO=y
+CONFIG_NET_SCH_MQPRIO=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_TSN=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_BPF_JIT=y
+CONFIG_NET_PKTGEN=y
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_FLEXCAN=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+# CONFIG_BT_HS is not set
+# CONFIG_BT_LE is not set
+CONFIG_BT_LEDS=y
+# CONFIG_BT_DEBUGFS is not set
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIVHCI=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
+CONFIG_MAC80211_LEDS=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_IOV=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCI_XGENE=y
+CONFIG_PCIE_ALTERA=y
+CONFIG_PCIE_ALTERA_MSI=y
+CONFIG_PCI_HOST_THUNDER_PEM=y
+CONFIG_PCI_HOST_THUNDER_ECAM=y
+CONFIG_PCI_IMX6_HOST=y
+CONFIG_PCI_IMX6_EP=y
+CONFIG_PCI_LAYERSCAPE=y
+CONFIG_PCI_HISI=y
+CONFIG_PCIE_KIRIN=y
+CONFIG_PCIE_LAYERSCAPE_GEN4=y
+CONFIG_PCI_ENDPOINT=y
+CONFIG_PCI_ENDPOINT_CONFIGFS=y
+CONFIG_PCI_EPF_TEST=y
+CONFIG_IMX_MIC_EPF=m
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_BRCMSTB_GISB_ARB=y
+CONFIG_SIMPLE_PM_BUS=y
+CONFIG_VEXPRESS_CONFIG=y
+CONFIG_FSL_MC_BUS=y
+CONFIG_FSL_MC_UAPI_SUPPORT=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_SST25L=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_NAND_DENALI_DT=y
+CONFIG_MTD_NAND_GPMI_NAND=y
+CONFIG_MTD_NAND_FSL_IFC=y
+CONFIG_MTD_SPI_NOR=y
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_XEN_BLKDEV_BACKEND=m
+CONFIG_VIRTIO_BLK=y
+CONFIG_BLK_DEV_NVME=y
+CONFIG_SENSORS_FXOS8700=y
+CONFIG_SENSORS_FXAS2100X=y
+CONFIG_SRAM=y
+CONFIG_PCI_ENDPOINT_TEST=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=m
+CONFIG_SCIF_BUS=m
+CONFIG_VOP_BUS=m
+CONFIG_IMX_MIC_HOST=m
+CONFIG_IMX_MIC_CARD=m
+CONFIG_SCIF=m
+CONFIG_MIC_COSM=m
+CONFIG_VOP=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_HISI_SAS=y
+CONFIG_SCSI_HISI_SAS_PCI=y
+CONFIG_SCSI_MPT3SAS=m
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_AHCI_IMX=y
+CONFIG_AHCI_CEVA=y
+CONFIG_AHCI_XGENE=y
+CONFIG_AHCI_QORIQ=y
+CONFIG_SATA_SIL24=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_PATA_OF_PLATFORM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_NETDEVICES=y
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_TUN=y
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=y
+CONFIG_AMD_XGBE=y
+CONFIG_ATL1C=m
+CONFIG_BNX2X=m
+CONFIG_MACB=y
+CONFIG_THUNDER_NIC_PF=y
+CONFIG_FEC=y
+CONFIG_FSL_SDK_DPAA_ETH=y
+CONFIG_FSL_DPAA2_ETH=y
+CONFIG_FSL_ENETC=y
+CONFIG_FSL_ENETC_VF=y
+CONFIG_HIX5HD2_GMAC=y
+CONFIG_HNS_DSAF=y
+CONFIG_HNS_ENET=y
+CONFIG_HNS3=y
+CONFIG_HNS3_HCLGE=y
+CONFIG_HNS3_ENET=y
+CONFIG_E1000=y
+CONFIG_E1000E=y
+CONFIG_IGB=y
+CONFIG_IGBVF=y
+CONFIG_MVMDIO=y
+CONFIG_SKY2=y
+CONFIG_MLX4_EN=m
+CONFIG_MLX5_CORE=m
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MSCC_OCELOT_SWITCH=y
+CONFIG_QCOM_EMAC=m
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_STMMAC_ETH=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPPOE=y
+CONFIG_AQUANTIA_PHY=y
+CONFIG_AT803X_PHY=y
+CONFIG_INPHI_PHY=y
+CONFIG_MARVELL_PHY=m
+CONFIG_MARVELL_10G_PHY=m
+CONFIG_MICREL_PHY=y
+CONFIG_MICROSEMI_PHY=y
+CONFIG_NXP_TJA11XX_PHY=y
+CONFIG_REALTEK_PHY=y
+CONFIG_ROCKCHIP_PHY=y
+CONFIG_VITESSE_PHY=y
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_CDC_MBIM=y
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_QMI_WWAN=y
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_PCIE=y
+CONFIG_HOSTAP=y
+CONFIG_MXMWIFIEX=m
+CONFIG_WL18XX=m
+CONFIG_WLCORE_SDIO=m
+CONFIG_XEN_NETDEV_BACKEND=m
+CONFIG_IVSHMEM_NET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_ADC=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_SNVS_PWRKEY=y
+CONFIG_KEYBOARD_IMX_SC_PWRKEY=y
+CONFIG_KEYBOARD_CROS_EC=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MPL3115=y
+CONFIG_INPUT_ISL29023=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_XILINX_PS_UART=y
+CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
+CONFIG_SERIAL_FSL_LPUART=y
+CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_SERIAL_FSL_LINFLEXUART=y
+CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_TCG_TPM=y
+CONFIG_TCG_TIS_I2C_INFINEON=y
+CONFIG_TCG_TIS_SPI=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_IMX=y
+CONFIG_I2C_IMX_LPI2C=y
+CONFIG_I2C_RK3X=y
+CONFIG_I2C_RPBUS=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_XEN_I2C_BACKEND=y
+CONFIG_I2C_SLAVE=y
+CONFIG_SPI=y
+CONFIG_SPI_FSL_LPSPI=y
+CONFIG_SPI_FSL_QUADSPI=y
+CONFIG_SPI_NXP_FLEXSPI=y
+CONFIG_SPI_IMX=y
+CONFIG_SPI_FSL_DSPI=y
+CONFIG_SPI_PL022=y
+CONFIG_SPI_ROCKCHIP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPI_SLAVE=y
+CONFIG_SPI_SLAVE_TIME=y
+CONFIG_SPI_SLAVE_SYSTEM_CONTROL=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINCTRL_MAX77620=y
+CONFIG_PINCTRL_IMX8MM=y
+CONFIG_PINCTRL_IMX8MN=y
+CONFIG_PINCTRL_IMX8MP=y
+CONFIG_PINCTRL_IMX8MQ=y
+CONFIG_PINCTRL_IMX8QM=y
+CONFIG_PINCTRL_IMX8QXP=y
+CONFIG_PINCTRL_IMX8DXL=y
+CONFIG_PINCTRL_S32V234=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_MB86S7X=y
+CONFIG_GPIO_MPC8XXX=y
+CONFIG_GPIO_PL061=y
+CONFIG_GPIO_XGENE=y
+CONFIG_GPIO_MAX732X=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_MAX77620=y
+CONFIG_POWER_AVS=y
+CONFIG_POWER_RESET_BRCMSTB=y
+CONFIG_POWER_RESET_VEXPRESS=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_RESET_ASUS_PE100A=y
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_BATTERY_SBS=m
+CONFIG_BATTERY_BQ27XXX=y
+CONFIG_SENSORS_ARM_SCPI=y
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_PWM_FAN=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_INA3221=m
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=100
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_CPU_THERMAL=y
+CONFIG_THERMAL_EMULATION=y
+CONFIG_IMX_SC_THERMAL=y
+CONFIG_DEVICE_THERMAL=y
+CONFIG_IMX8MM_THERMAL=y
+CONFIG_QORIQ_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_ARM_SBSA_WATCHDOG=y
+CONFIG_DW_WATCHDOG=y
+CONFIG_IMX2_WDT=y
+CONFIG_IMX_SC_WDT=y
+CONFIG_XEN_WDT=y
+CONFIG_MFD_BD9571MWV=y
+CONFIG_MFD_AXP20X_I2C=y
+CONFIG_MFD_IMX_AUDIOMIX=y
+CONFIG_MFD_HI6421_PMIC=y
+CONFIG_MFD_MAX77620=y
+CONFIG_MFD_RK808=y
+CONFIG_MFD_SEC_CORE=y
+CONFIG_MFD_ROHM_BD718XX=y
+CONFIG_MFD_PCA9450=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_BD718XX=y
+CONFIG_REGULATOR_BD9571MWV=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_HI6421V530=y
+CONFIG_REGULATOR_MAX77620=y
+CONFIG_REGULATOR_MAX8973=y
+CONFIG_REGULATOR_PCA9450=y
+CONFIG_REGULATOR_PFUZE100=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_REGULATOR_QCOM_SPMI=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_REGULATOR_S2MPS11=y
+CONFIG_REGULATOR_VCTRL=m
+CONFIG_RC_CORE=m
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_IR_IMON_DECODER=m
+CONFIG_IR_RCMM_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_IR_GPIO_CIR=m
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_DVB_NET is not set
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_MX8_CAPTURE=y
+CONFIG_VIDEO_MXC_CAPTURE=y
+CONFIG_VIDEO_MXC_CSI_CAMERA=y
+CONFIG_MXC_MIPI_CSI=y
+CONFIG_MXC_CAMERA_OV5640_MIPI_V2=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_OV5640=y
+CONFIG_IMX_DPU_CORE=y
+CONFIG_IMX_LCDIF_CORE=y
+CONFIG_IMX_LCDIFV3_CORE=y
+CONFIG_DRM=y
+CONFIG_DRM_I2C_NXP_TDA998X=m
+CONFIG_DRM_MALI_DISPLAY=m
+CONFIG_DRM_NOUVEAU=m
+CONFIG_DRM_RCAR_LVDS=m
+CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_PANEL_RAYDIUM_RM67191=y
+CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
+CONFIG_DRM_PANEL_WKS_101WX001=y
+CONFIG_DRM_FSL_IMX_LVDS_BRIDGE=y
+CONFIG_DRM_NXP_SEIKO_43WVFIG=y
+CONFIG_DRM_SII902X=m
+CONFIG_DRM_I2C_ADV7511=y
+CONFIG_DRM_NWL_MIPI_DSI=y
+CONFIG_DRM_CDNS_HDMI_CEC=y
+CONFIG_DRM_DW_HDMI_I2S_AUDIO=m
+CONFIG_DRM_DW_HDMI_GP_AUDIO=y
+CONFIG_DRM_DW_HDMI_CEC=y
+CONFIG_DRM_ITE_IT6263=y
+CONFIG_DRM_IMX=y
+CONFIG_DRM_IMX_LCDIF_MUX_DISPLAY=y
+CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
+CONFIG_DRM_IMX_TVE=y
+CONFIG_DRM_IMX_LDB=y
+CONFIG_DRM_IMX8QM_LDB=y
+CONFIG_DRM_IMX8QXP_LDB=y
+CONFIG_DRM_IMX8MP_LDB=y
+CONFIG_DRM_IMX_HDMI=y
+CONFIG_DRM_IMX_SEC_DSIM=y
+CONFIG_DRM_IMX_DCSS=y
+CONFIG_DRM_IMX_CDNS_MHDP=y
+CONFIG_DRM_ETNAVIV=m
+CONFIG_DRM_HISI_HIBMC=m
+CONFIG_DRM_HISI_KIRIN=m
+CONFIG_DRM_MXSFB=y
+CONFIG_DRM_PL111=m
+CONFIG_DRM_LIMA=m
+CONFIG_DRM_PANFROST=m
+CONFIG_FB_ARMCLCD=y
+CONFIG_FB_EFI=y
+CONFIG_BACKLIGHT_GENERIC=m
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_LP855X=m
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_FSL_EASRC=y
+CONFIG_SND_IMX_SOC=y
+CONFIG_SND_SOC_IMX_AK4458=y
+CONFIG_SND_SOC_IMX_AK5558=y
+CONFIG_SND_SOC_IMX_AK4497=y
+CONFIG_SND_SOC_IMX_WM8960=y
+CONFIG_SND_SOC_IMX_WM8524=y
+CONFIG_SND_SOC_IMX_CS42888=y
+CONFIG_SND_SOC_IMX_MICFIL=y
+CONFIG_SND_SOC_IMX_RPMSG=y
+CONFIG_SND_SOC_IMX_MQS=y
+CONFIG_SND_SOC_IMX_SPDIF=y
+CONFIG_SND_SOC_IMX_AUDMIX=y
+CONFIG_SND_SOC_IMX_PDM_MIC=y
+CONFIG_SND_SOC_IMX_DSP=y
+CONFIG_SND_SOC_IMX_CDNHDMI=y
+CONFIG_SND_SOC_IMX_XCVR=y
+CONFIG_SND_SOC_IMX_PCM512X=y
+CONFIG_SND_SOC_SOF_TOPLEVEL=y
+CONFIG_SND_SOC_SOF_OF=m
+CONFIG_SND_SOC_SOF_IMX_TOPLEVEL=y
+CONFIG_SND_SOC_SOF_IMX8_SUPPORT=m
+CONFIG_SND_SOC_SOF_IMX8M_SUPPORT=m
+CONFIG_SND_SOC_AK4613=m
+CONFIG_SND_SOC_BT_SCO=y
+CONFIG_SND_SOC_DMIC=m
+CONFIG_SND_SOC_ES7134=m
+CONFIG_SND_SOC_ES7241=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_PCM3168A_I2C=m
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_TAS571X=m
+CONFIG_SND_SIMPLE_CARD=y
+CONFIG_SND_AUDIO_GRAPH_CARD=y
+CONFIG_I2C_HID=m
+CONFIG_HID_ASUS=y
+CONFIG_UHID=y
+CONFIG_USB=y
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_WHITELIST=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_HCD_TEST_MODE=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UAS=y
+CONFIG_USB_CDNS3=y
+CONFIG_USB_CDNS3_GADGET=y
+CONFIG_USB_CDNS3_HOST=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=y
+CONFIG_USB_SERIAL_CP210X=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_KEYSPAN=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_SERIAL_OTI6858=y
+CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_SIERRAWIRELESS=y
+CONFIG_USB_SERIAL_OPTION=y
+CONFIG_USB_TEST=m
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_HSIC_USB3503=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MXS_PHY=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_SNP_UDC_PLAT=y
+CONFIG_USB_BDC_UDC=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_TYPEC=y
+CONFIG_TYPEC_TCPM=y
+CONFIG_TYPEC_TCPCI=y
+CONFIG_TYPEC_SWITCH_GPIO=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ACPI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ARASAN=y
+CONFIG_MMC_SDHCI_OF_ESDHC=y
+CONFIG_MMC_SDHCI_CADENCE=y
+CONFIG_MMC_SDHCI_ESDHC_IMX=y
+CONFIG_MMC_SDHCI_F_SDH30=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_EXYNOS=y
+CONFIG_MMC_DW_HI3798CV200=y
+CONFIG_MMC_DW_K3=y
+CONFIG_MMC_SDHCI_XENON=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PWM=y
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_EDAC=y
+CONFIG_EDAC_GHES=y
+CONFIG_EDAC_SYNOPSYS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_ISL1208=y
+CONFIG_RTC_DRV_PCF85363=y
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_S5M=y
+CONFIG_RTC_DRV_DS3232=y
+CONFIG_RTC_DRV_PCF2127=y
+CONFIG_RTC_DRV_EFI=y
+CONFIG_RTC_DRV_CROS_EC=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_RTC_DRV_SNVS=y
+CONFIG_RTC_DRV_IMX_SC=y
+CONFIG_DMADEVICES=y
+CONFIG_BCM_SBA_RAID=m
+CONFIG_FSL_EDMA=y
+CONFIG_FSL_EDMA_V3=y
+CONFIG_IMX_SDMA=y
+CONFIG_MV_XOR_V2=y
+CONFIG_MXS_DMA=y
+CONFIG_PL330_DMA=y
+CONFIG_QCOM_HIDMA_MGMT=y
+CONFIG_QCOM_HIDMA=y
+CONFIG_DMATEST=y
+CONFIG_UIO=y
+CONFIG_UIO_PCI_GENERIC=y
+CONFIG_UIO_IVSHMEM=y
+CONFIG_VFIO=y
+CONFIG_VFIO_PCI=y
+CONFIG_VFIO_FSL_MC=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_XEN_GNTDEV=y
+CONFIG_XEN_GRANT_DEV_ALLOC=y
+CONFIG_STAGING=y
+CONFIG_STAGING_MEDIA=y
+CONFIG_VIDEO_IMX_CAPTURE=y
+CONFIG_IMX8_MEDIA_DEVICE=m
+CONFIG_ION=y
+CONFIG_ION_SYSTEM_HEAP=y
+CONFIG_ION_CMA_HEAP=y
+CONFIG_FSL_DPAA2=y
+CONFIG_FSL_DPAA2_ETHSW=y
+CONFIG_FSL_DPAA2_MAC=y
+CONFIG_FSL_SDK_DPA=y
+CONFIG_FSL_PPFE=y
+CONFIG_FSL_PPFE_UTIL_DISABLED=y
+CONFIG_MFD_CROS_EC=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_SPI=y
+CONFIG_COMMON_CLK_VERSATILE=y
+CONFIG_CLK_SP810=y
+CONFIG_CLK_VEXPRESS_OSC=y
+CONFIG_COMMON_CLK_RK808=y
+CONFIG_COMMON_CLK_SCPI=y
+CONFIG_COMMON_CLK_CS2000_CP=y
+CONFIG_COMMON_CLK_S2MPS11=y
+CONFIG_COMMON_CLK_XGENE=y
+CONFIG_COMMON_CLK_PWM=y
+CONFIG_CLK_IMX8MM=y
+CONFIG_CLK_IMX8MN=y
+CONFIG_CLK_IMX8MP=y
+CONFIG_CLK_IMX8MQ=y
+CONFIG_CLK_IMX8QXP=y
+CONFIG_HWSPINLOCK=y
+CONFIG_ARM_MHU=y
+CONFIG_IMX_MBOX=y
+CONFIG_PLATFORM_MHU=y
+CONFIG_ARM_SMMU=y
+CONFIG_ARM_SMMU_V3=y
+CONFIG_REMOTEPROC=y
+CONFIG_IMX_REMOTEPROC=y
+CONFIG_RPMSG_QCOM_GLINK_RPM=y
+CONFIG_SOC_BRCMSTB=y
+CONFIG_FSL_MC_DPIO=y
+CONFIG_FSL_QIXIS=y
+CONFIG_IMX_SCU_SOC=y
+CONFIG_SECVIO_SC=y
+CONFIG_SOC_TI=y
+CONFIG_EXTCON_IT5201=y
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_EXTCON_USBC_CROS_EC=y
+CONFIG_IIO=y
+CONFIG_IMX8QXP_ADC=y
+CONFIG_IIO_CROS_EC_SENSORS_CORE=m
+CONFIG_IIO_CROS_EC_SENSORS=m
+CONFIG_IIO_CROS_EC_LIGHT_PROX=m
+CONFIG_IIO_CROS_EC_BARO=m
+CONFIG_PWM=y
+CONFIG_PWM_CROS_EC=m
+CONFIG_PWM_IMX27=y
+CONFIG_PHY_XGENE=y
+CONFIG_PHY_MIXEL_LVDS=y
+CONFIG_PHY_MIXEL_LVDS_COMBO=y
+CONFIG_PHY_FSL_IMX8MP_LVDS=y
+CONFIG_PHY_MIXEL_MIPI_DPHY=y
+CONFIG_PHY_SAMSUNG_HDMI_PHY=y
+CONFIG_PHY_QCOM_USB_HS=y
+CONFIG_PHY_SAMSUNG_USB2=y
+CONFIG_FSL_IMX8_DDR_PMU=y
+CONFIG_HISI_PMU=y
+CONFIG_NVMEM_IMX_OCOTP=y
+CONFIG_NVMEM_IMX_OCOTP_SCU=y
+CONFIG_FPGA=y
+CONFIG_FPGA_BRIDGE=m
+CONFIG_ALTERA_FREEZE_BRIDGE=m
+CONFIG_FPGA_REGION=m
+CONFIG_OF_FPGA_REGION=m
+CONFIG_TEE=y
+CONFIG_OPTEE=y
+CONFIG_MUX_MMIO=y
+CONFIG_MXC_SIM=y
+CONFIG_MXC_EMVSIM=y
+CONFIG_MXC_MLB150=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_OVERLAY_FS=m
+CONFIG_UDF_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_HUGETLBFS=y
+CONFIG_EFIVAR_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_UBIFS_FS=y
+CONFIG_SQUASHFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_9P_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_SECURITY=y
+CONFIG_CRYPTO_USER=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_TLS=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_STREEBOG=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=m
+CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=y
+CONFIG_INDIRECT_PIO=y
+CONFIG_CMA_SIZE_MBYTES=320
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
+CONFIG_MEMTEST=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SOURCE_ETM4X=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_NETFILTER_XT_MATCH_IPVS=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_VS=y
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_RR=y
+CONFIG_VXLAN=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_ALGO=y
+CONFIG_INET_ESP=y
+CONFIG_DUMMY=y
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_NAT_TFTP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
--- linux-ein-5.4.0.orig/arch/arm64/crypto/Kconfig
+++ linux-ein-5.4.0/arch/arm64/crypto/Kconfig
@@ -59,6 +59,7 @@
 	select CRYPTO_HASH
 	select CRYPTO_GF128MUL
 	select CRYPTO_LIB_AES
+	select CRYPTO_AEAD
 
 config CRYPTO_CRCT10DIF_ARM64_CE
 	tristate "CRCT10DIF digest algorithm using PMULL instructions"
--- linux-ein-5.4.0.orig/arch/arm64/crypto/aes-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/aes-glue.c
@@ -55,7 +55,7 @@
 #define aes_mac_update		neon_aes_mac_update
 MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON");
 #endif
-#if defined(USE_V8_CRYPTO_EXTENSIONS) || !defined(CONFIG_CRYPTO_AES_ARM64_BS)
+#if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS)
 MODULE_ALIAS_CRYPTO("ecb(aes)");
 MODULE_ALIAS_CRYPTO("cbc(aes)");
 MODULE_ALIAS_CRYPTO("ctr(aes)");
@@ -668,7 +668,7 @@
 }
 
 static struct skcipher_alg aes_algs[] = { {
-#if defined(USE_V8_CRYPTO_EXTENSIONS) || !defined(CONFIG_CRYPTO_AES_ARM64_BS)
+#if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS)
 	.base = {
 		.cra_name		= "__ecb(aes)",
 		.cra_driver_name	= "__ecb-aes-" MODE,
@@ -1028,7 +1028,6 @@
 	struct simd_skcipher_alg *simd;
 	const char *basename;
 	const char *algname;
-	const char *drvname;
 	int err;
 	int i;
 
@@ -1045,9 +1044,8 @@
 			continue;
 
 		algname = aes_algs[i].base.cra_name + 2;
-		drvname = aes_algs[i].base.cra_driver_name + 2;
 		basename = aes_algs[i].base.cra_driver_name;
-		simd = simd_skcipher_create_compat(algname, drvname, basename);
+		simd = simd_skcipher_create(algname, basename);
 		err = PTR_ERR(simd);
 		if (IS_ERR(simd))
 			goto unregister_simds;
--- linux-ein-5.4.0.orig/arch/arm64/crypto/aes-neonbs-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/aes-neonbs-glue.c
@@ -384,7 +384,7 @@
 			goto xts_tail;
 
 		kernel_neon_end();
-		skcipher_walk_done(&walk, nbytes);
+		err = skcipher_walk_done(&walk, nbytes);
 	}
 
 	if (err || likely(!tail))
--- linux-ein-5.4.0.orig/arch/arm64/crypto/ghash-ce-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/ghash-ce-glue.c
@@ -261,7 +261,7 @@
 static struct shash_alg ghash_alg[] = {{
 	.base.cra_name		= "ghash",
 	.base.cra_driver_name	= "ghash-neon",
-	.base.cra_priority	= 100,
+	.base.cra_priority	= 150,
 	.base.cra_blocksize	= GHASH_BLOCK_SIZE,
 	.base.cra_ctxsize	= sizeof(struct ghash_key),
 	.base.cra_module	= THIS_MODULE,
--- linux-ein-5.4.0.orig/arch/arm64/crypto/nhpoly1305-neon-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/nhpoly1305-neon-glue.c
@@ -30,7 +30,7 @@
 		return crypto_nhpoly1305_update(desc, src, srclen);
 
 	do {
-		unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE);
+		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
 
 		kernel_neon_begin();
 		crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon);
--- linux-ein-5.4.0.orig/arch/arm64/crypto/sha1-ce-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/sha1-ce-glue.c
@@ -19,6 +19,7 @@
 MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("sha1");
 
 struct sha1_ce_state {
 	struct sha1_state	sst;
--- linux-ein-5.4.0.orig/arch/arm64/crypto/sha2-ce-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/sha2-ce-glue.c
@@ -19,6 +19,8 @@
 MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("sha224");
+MODULE_ALIAS_CRYPTO("sha256");
 
 struct sha256_ce_state {
 	struct sha256_state	sst;
--- linux-ein-5.4.0.orig/arch/arm64/crypto/sha3-ce-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/sha3-ce-glue.c
@@ -23,6 +23,10 @@
 MODULE_DESCRIPTION("SHA3 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("sha3-224");
+MODULE_ALIAS_CRYPTO("sha3-256");
+MODULE_ALIAS_CRYPTO("sha3-384");
+MODULE_ALIAS_CRYPTO("sha3-512");
 
 asmlinkage void sha3_ce_transform(u64 *st, const u8 *data, int blocks,
 				  int md_len);
--- linux-ein-5.4.0.orig/arch/arm64/crypto/sha512-ce-glue.c
+++ linux-ein-5.4.0/arch/arm64/crypto/sha512-ce-glue.c
@@ -23,6 +23,8 @@
 MODULE_DESCRIPTION("SHA-384/SHA-512 secure hash using ARMv8 Crypto Extensions");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("sha384");
+MODULE_ALIAS_CRYPTO("sha512");
 
 asmlinkage void sha512_ce_transform(struct sha512_state *sst, u8 const *src,
 				    int blocks);
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/acpi.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/acpi.h
@@ -12,6 +12,7 @@
 #include <linux/efi.h>
 #include <linux/memblock.h>
 #include <linux/psci.h>
+#include <linux/stddef.h>
 
 #include <asm/cputype.h>
 #include <asm/io.h>
@@ -31,14 +32,14 @@
  * is therefore used to delimit the MADT GICC structure minimum length
  * appropriately.
  */
-#define ACPI_MADT_GICC_MIN_LENGTH   ACPI_OFFSET(  \
+#define ACPI_MADT_GICC_MIN_LENGTH   offsetof(  \
 	struct acpi_madt_generic_interrupt, efficiency_class)
 
 #define BAD_MADT_GICC_ENTRY(entry, end)					\
 	(!(entry) || (entry)->header.length < ACPI_MADT_GICC_MIN_LENGTH || \
 	(unsigned long)(entry) + (entry)->header.length > (end))
 
-#define ACPI_MADT_GICC_SPE  (ACPI_OFFSET(struct acpi_madt_generic_interrupt, \
+#define ACPI_MADT_GICC_SPE  (offsetof(struct acpi_madt_generic_interrupt, \
 	spe_interrupt) + sizeof(u16))
 
 /* Basic configuration for ACPI */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/alternative.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/alternative.h
@@ -35,13 +35,16 @@
 static inline void apply_alternatives_module(void *start, size_t length) { }
 #endif
 
-#define ALTINSTR_ENTRY(feature,cb)					      \
+#define ALTINSTR_ENTRY(feature)					              \
 	" .word 661b - .\n"				/* label           */ \
-	" .if " __stringify(cb) " == 0\n"				      \
 	" .word 663f - .\n"				/* new instruction */ \
-	" .else\n"							      \
+	" .hword " __stringify(feature) "\n"		/* feature bit     */ \
+	" .byte 662b-661b\n"				/* source len      */ \
+	" .byte 664f-663f\n"				/* replacement len */
+
+#define ALTINSTR_ENTRY_CB(feature, cb)					      \
+	" .word 661b - .\n"				/* label           */ \
 	" .word " __stringify(cb) "- .\n"		/* callback */	      \
-	" .endif\n"							      \
 	" .hword " __stringify(feature) "\n"		/* feature bit     */ \
 	" .byte 662b-661b\n"				/* source len      */ \
 	" .byte 664f-663f\n"				/* replacement len */
@@ -62,33 +65,40 @@
  *
  * Alternatives with callbacks do not generate replacement instructions.
  */
-#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb)	\
+#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled)	\
 	".if "__stringify(cfg_enabled)" == 1\n"				\
 	"661:\n\t"							\
 	oldinstr "\n"							\
 	"662:\n"							\
 	".pushsection .altinstructions,\"a\"\n"				\
-	ALTINSTR_ENTRY(feature,cb)					\
+	ALTINSTR_ENTRY(feature)						\
 	".popsection\n"							\
-	" .if " __stringify(cb) " == 0\n"				\
-	".pushsection .altinstr_replacement, \"a\"\n"			\
+	".subsection 1\n"						\
 	"663:\n\t"							\
 	newinstr "\n"							\
 	"664:\n\t"							\
-	".popsection\n\t"						\
 	".org	. - (664b-663b) + (662b-661b)\n\t"			\
-	".org	. - (662b-661b) + (664b-663b)\n"			\
-	".else\n\t"							\
+	".org	. - (662b-661b) + (664b-663b)\n\t"			\
+	".previous\n"							\
+	".endif\n"
+
+#define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb)	\
+	".if "__stringify(cfg_enabled)" == 1\n"				\
+	"661:\n\t"							\
+	oldinstr "\n"							\
+	"662:\n"							\
+	".pushsection .altinstructions,\"a\"\n"				\
+	ALTINSTR_ENTRY_CB(feature, cb)					\
+	".popsection\n"							\
 	"663:\n\t"							\
 	"664:\n\t"							\
-	".endif\n"							\
 	".endif\n"
 
 #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...)	\
-	__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0)
+	__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
 
 #define ALTERNATIVE_CB(oldinstr, cb) \
-	__ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb)
+	__ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb)
 #else
 
 #include <asm/assembler.h>
@@ -107,11 +117,11 @@
 662:	.pushsection .altinstructions, "a"
 	altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
 	.popsection
-	.pushsection .altinstr_replacement, "ax"
+	.subsection 1
 663:	\insn2
-664:	.popsection
-	.org	. - (664b-663b) + (662b-661b)
+664:	.org	. - (664b-663b) + (662b-661b)
 	.org	. - (662b-661b) + (664b-663b)
+	.previous
 	.endif
 .endm
 
@@ -150,7 +160,7 @@
 	.pushsection .altinstructions, "a"
 	altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f
 	.popsection
-	.pushsection .altinstr_replacement, "ax"
+	.subsection 1
 	.align 2	/* So GAS knows label 661 is suitably aligned */
 661:
 .endm
@@ -169,9 +179,9 @@
 .macro alternative_else
 662:
 	.if .Lasm_alt_mode==0
-	.pushsection .altinstr_replacement, "ax"
+	.subsection 1
 	.else
-	.popsection
+	.previous
 	.endif
 663:
 .endm
@@ -181,11 +191,11 @@
  */
 .macro alternative_endif
 664:
-	.if .Lasm_alt_mode==0
-	.popsection
-	.endif
 	.org	. - (664b-663b) + (662b-661b)
 	.org	. - (662b-661b) + (664b-663b)
+	.if .Lasm_alt_mode==0
+	.previous
+	.endif
 .endm
 
 /*
@@ -211,7 +221,7 @@
 
 .macro user_alt, label, oldinstr, newinstr, cond
 9999:	alternative_insn "\oldinstr", "\newinstr", \cond
-	_ASM_EXTABLE 9999b, \label
+	_asm_extable 9999b, \label
 .endm
 
 /*
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/arch_gicv3.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/arch_gicv3.h
@@ -109,7 +109,7 @@
 	return read_sysreg_s(SYS_ICC_PMR_EL1);
 }
 
-static inline void gic_write_pmr(u32 val)
+static __always_inline void gic_write_pmr(u32 val)
 {
 	write_sysreg_s(val, SYS_ICC_PMR_EL1);
 }
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/arch_timer.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/arch_timer.h
@@ -58,6 +58,7 @@
 	u64 (*read_cntvct_el0)(void);
 	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
 	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
+	bool disable_compat_vdso;
 };
 
 DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
@@ -164,25 +165,6 @@
 	isb();
 }
 
-/*
- * Ensure that reads of the counter are treated the same as memory reads
- * for the purposes of ordering by subsequent memory barriers.
- *
- * This insanity brought to you by speculative system register reads,
- * out-of-order memory accesses, sequence locks and Thomas Gleixner.
- *
- * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
- */
-#define arch_counter_enforce_ordering(val) do {				\
-	u64 tmp, _val = (val);						\
-									\
-	asm volatile(							\
-	"	eor	%0, %1, %1\n"					\
-	"	add	%0, sp, %0\n"					\
-	"	ldr	xzr, [%0]"					\
-	: "=r" (tmp) : "r" (_val));					\
-} while (0)
-
 static __always_inline u64 __arch_counter_get_cntpct_stable(void)
 {
 	u64 cnt;
@@ -223,8 +205,6 @@
 	return cnt;
 }
 
-#undef arch_counter_enforce_ordering
-
 static inline int arch_timer_arch_init(void)
 {
 	return 0;
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/asm-uaccess.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/asm-uaccess.h
@@ -15,10 +15,10 @@
 	.macro	__uaccess_ttbr0_disable, tmp1
 	mrs	\tmp1, ttbr1_el1			// swapper_pg_dir
 	bic	\tmp1, \tmp1, #TTBR_ASID_MASK
-	sub	\tmp1, \tmp1, #RESERVED_TTBR0_SIZE	// reserved_ttbr0 just before swapper_pg_dir
+	sub	\tmp1, \tmp1, #PAGE_SIZE		// reserved_pg_dir just before swapper_pg_dir
 	msr	ttbr0_el1, \tmp1			// set reserved TTBR0_EL1
 	isb
-	add	\tmp1, \tmp1, #RESERVED_TTBR0_SIZE
+	add	\tmp1, \tmp1, #PAGE_SIZE
 	msr	ttbr1_el1, \tmp1		// set reserved ASID
 	isb
 	.endm
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/assembler.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/assembler.h
@@ -111,6 +111,13 @@
 	.endm
 
 /*
+ * Clear Branch History instruction
+ */
+	.macro clearbhb
+	hint	#22
+	.endm
+
+/*
  * Speculation barrier
  */
 	.macro	sb
@@ -462,6 +469,7 @@
 	.endm
 
 /*
+ * Deprecated! Use SYM_FUNC_{START,START_WEAK,END}_PI instead.
  * Annotate a function as position independent, i.e., safe to be called before
  * the kernel virtual mapping is activated.
  */
@@ -756,4 +764,30 @@
 .Lyield_out_\@ :
 	.endm
 
+	.macro __mitigate_spectre_bhb_loop      tmp
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+alternative_cb  spectre_bhb_patch_loop_iter
+	mov	\tmp, #32		// Patched to correct the immediate
+alternative_cb_end
+.Lspectre_bhb_loop\@:
+	b	. + 4
+	subs	\tmp, \tmp, #1
+	b.ne	.Lspectre_bhb_loop\@
+	sb
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+	.endm
+
+	/* Save/restores x0-x3 to the stack */
+	.macro __mitigate_spectre_bhb_fw
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+	stp	x0, x1, [sp, #-16]!
+	stp	x2, x3, [sp, #-16]!
+	mov	w0, #ARM_SMCCC_ARCH_WORKAROUND_3
+alternative_cb	arm64_update_smccc_conduit
+	nop					// Patched to SMC/HVC #0
+alternative_cb_end
+	ldp	x2, x3, [sp], #16
+	ldp	x0, x1, [sp], #16
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+	.endm
 #endif	/* __ASM_ASSEMBLER_H */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/atomic.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/atomic.h
@@ -17,7 +17,7 @@
 #include <asm/lse.h>
 
 #define ATOMIC_OP(op)							\
-static inline void arch_##op(int i, atomic_t *v)			\
+static __always_inline void arch_##op(int i, atomic_t *v)		\
 {									\
 	__lse_ll_sc_body(op, i, v);					\
 }
@@ -32,7 +32,7 @@
 #undef ATOMIC_OP
 
 #define ATOMIC_FETCH_OP(name, op)					\
-static inline int arch_##op##name(int i, atomic_t *v)			\
+static __always_inline int arch_##op##name(int i, atomic_t *v)		\
 {									\
 	return __lse_ll_sc_body(op##name, i, v);			\
 }
@@ -56,7 +56,7 @@
 #undef ATOMIC_FETCH_OPS
 
 #define ATOMIC64_OP(op)							\
-static inline void arch_##op(long i, atomic64_t *v)			\
+static __always_inline void arch_##op(long i, atomic64_t *v)		\
 {									\
 	__lse_ll_sc_body(op, i, v);					\
 }
@@ -71,7 +71,7 @@
 #undef ATOMIC64_OP
 
 #define ATOMIC64_FETCH_OP(name, op)					\
-static inline long arch_##op##name(long i, atomic64_t *v)		\
+static __always_inline long arch_##op##name(long i, atomic64_t *v)	\
 {									\
 	return __lse_ll_sc_body(op##name, i, v);			\
 }
@@ -94,7 +94,7 @@
 #undef ATOMIC64_FETCH_OP
 #undef ATOMIC64_FETCH_OPS
 
-static inline long arch_atomic64_dec_if_positive(atomic64_t *v)
+static __always_inline long arch_atomic64_dec_if_positive(atomic64_t *v)
 {
 	return __lse_ll_sc_body(atomic64_dec_if_positive, v);
 }
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/atomic_ll_sc.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/atomic_ll_sc.h
@@ -12,19 +12,6 @@
 
 #include <linux/stringify.h>
 
-#if IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS) && IS_ENABLED(CONFIG_AS_LSE)
-#define __LL_SC_FALLBACK(asm_ops)					\
-"	b	3f\n"							\
-"	.subsection	1\n"						\
-"3:\n"									\
-asm_ops "\n"								\
-"	b	4f\n"							\
-"	.previous\n"							\
-"4:\n"
-#else
-#define __LL_SC_FALLBACK(asm_ops) asm_ops
-#endif
-
 #ifndef CONFIG_CC_HAS_K_CONSTRAINT
 #define K
 #endif
@@ -43,12 +30,11 @@
 	int result;							\
 									\
 	asm volatile("// atomic_" #op "\n"				\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %2\n"					\
-"1:	ldxr	%w0, %2\n"						\
-"	" #asm_op "	%w0, %w0, %w3\n"				\
-"	stxr	%w1, %w0, %2\n"						\
-"	cbnz	%w1, 1b\n")						\
+	"	prfm	pstl1strm, %2\n"				\
+	"1:	ldxr	%w0, %2\n"					\
+	"	" #asm_op "	%w0, %w0, %w3\n"			\
+	"	stxr	%w1, %w0, %2\n"					\
+	"	cbnz	%w1, 1b\n"					\
 	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)		\
 	: __stringify(constraint) "r" (i));				\
 }
@@ -61,13 +47,12 @@
 	int result;							\
 									\
 	asm volatile("// atomic_" #op "_return" #name "\n"		\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %2\n"					\
-"1:	ld" #acq "xr	%w0, %2\n"					\
-"	" #asm_op "	%w0, %w0, %w3\n"				\
-"	st" #rel "xr	%w1, %w0, %2\n"					\
-"	cbnz	%w1, 1b\n"						\
-"	" #mb )								\
+	"	prfm	pstl1strm, %2\n"				\
+	"1:	ld" #acq "xr	%w0, %2\n"				\
+	"	" #asm_op "	%w0, %w0, %w3\n"			\
+	"	st" #rel "xr	%w1, %w0, %2\n"				\
+	"	cbnz	%w1, 1b\n"					\
+	"	" #mb							\
 	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)		\
 	: __stringify(constraint) "r" (i)				\
 	: cl);								\
@@ -83,13 +68,12 @@
 	int val, result;						\
 									\
 	asm volatile("// atomic_fetch_" #op #name "\n"			\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %3\n"					\
-"1:	ld" #acq "xr	%w0, %3\n"					\
-"	" #asm_op "	%w1, %w0, %w4\n"				\
-"	st" #rel "xr	%w2, %w1, %3\n"					\
-"	cbnz	%w2, 1b\n"						\
-"	" #mb )								\
+	"	prfm	pstl1strm, %3\n"				\
+	"1:	ld" #acq "xr	%w0, %3\n"				\
+	"	" #asm_op "	%w1, %w0, %w4\n"			\
+	"	st" #rel "xr	%w2, %w1, %3\n"				\
+	"	cbnz	%w2, 1b\n"					\
+	"	" #mb							\
 	: "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter)	\
 	: __stringify(constraint) "r" (i)				\
 	: cl);								\
@@ -142,12 +126,11 @@
 	unsigned long tmp;						\
 									\
 	asm volatile("// atomic64_" #op "\n"				\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %2\n"					\
-"1:	ldxr	%0, %2\n"						\
-"	" #asm_op "	%0, %0, %3\n"					\
-"	stxr	%w1, %0, %2\n"						\
-"	cbnz	%w1, 1b")						\
+	"	prfm	pstl1strm, %2\n"				\
+	"1:	ldxr	%0, %2\n"					\
+	"	" #asm_op "	%0, %0, %3\n"				\
+	"	stxr	%w1, %0, %2\n"					\
+	"	cbnz	%w1, 1b"					\
 	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)		\
 	: __stringify(constraint) "r" (i));				\
 }
@@ -160,13 +143,12 @@
 	unsigned long tmp;						\
 									\
 	asm volatile("// atomic64_" #op "_return" #name "\n"		\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %2\n"					\
-"1:	ld" #acq "xr	%0, %2\n"					\
-"	" #asm_op "	%0, %0, %3\n"					\
-"	st" #rel "xr	%w1, %0, %2\n"					\
-"	cbnz	%w1, 1b\n"						\
-"	" #mb )								\
+	"	prfm	pstl1strm, %2\n"				\
+	"1:	ld" #acq "xr	%0, %2\n"				\
+	"	" #asm_op "	%0, %0, %3\n"				\
+	"	st" #rel "xr	%w1, %0, %2\n"				\
+	"	cbnz	%w1, 1b\n"					\
+	"	" #mb							\
 	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)		\
 	: __stringify(constraint) "r" (i)				\
 	: cl);								\
@@ -176,19 +158,18 @@
 
 #define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint)\
 static inline long							\
-__ll_sc_atomic64_fetch_##op##name(s64 i, atomic64_t *v)		\
+__ll_sc_atomic64_fetch_##op##name(s64 i, atomic64_t *v)			\
 {									\
 	s64 result, val;						\
 	unsigned long tmp;						\
 									\
 	asm volatile("// atomic64_fetch_" #op #name "\n"		\
-	__LL_SC_FALLBACK(						\
-"	prfm	pstl1strm, %3\n"					\
-"1:	ld" #acq "xr	%0, %3\n"					\
-"	" #asm_op "	%1, %0, %4\n"					\
-"	st" #rel "xr	%w2, %1, %3\n"					\
-"	cbnz	%w2, 1b\n"						\
-"	" #mb )								\
+	"	prfm	pstl1strm, %3\n"				\
+	"1:	ld" #acq "xr	%0, %3\n"				\
+	"	" #asm_op "	%1, %0, %4\n"				\
+	"	st" #rel "xr	%w2, %1, %3\n"				\
+	"	cbnz	%w2, 1b\n"					\
+	"	" #mb							\
 	: "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter)	\
 	: __stringify(constraint) "r" (i)				\
 	: cl);								\
@@ -240,15 +221,14 @@
 	unsigned long tmp;
 
 	asm volatile("// atomic64_dec_if_positive\n"
-	__LL_SC_FALLBACK(
-"	prfm	pstl1strm, %2\n"
-"1:	ldxr	%0, %2\n"
-"	subs	%0, %0, #1\n"
-"	b.lt	2f\n"
-"	stlxr	%w1, %0, %2\n"
-"	cbnz	%w1, 1b\n"
-"	dmb	ish\n"
-"2:")
+	"	prfm	pstl1strm, %2\n"
+	"1:	ldxr	%0, %2\n"
+	"	subs	%0, %0, #1\n"
+	"	b.lt	2f\n"
+	"	stlxr	%w1, %0, %2\n"
+	"	cbnz	%w1, 1b\n"
+	"	dmb	ish\n"
+	"2:"
 	: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
 	:
 	: "cc", "memory");
@@ -274,7 +254,6 @@
 		old = (u##sz)old;					\
 									\
 	asm volatile(							\
-	__LL_SC_FALLBACK(						\
 	"	prfm	pstl1strm, %[v]\n"				\
 	"1:	ld" #acq "xr" #sfx "\t%" #w "[oldval], %[v]\n"		\
 	"	eor	%" #w "[tmp], %" #w "[oldval], %" #w "[old]\n"	\
@@ -282,7 +261,7 @@
 	"	st" #rel "xr" #sfx "\t%w[tmp], %" #w "[new], %[v]\n"	\
 	"	cbnz	%w[tmp], 1b\n"					\
 	"	" #mb "\n"						\
-	"2:")								\
+	"2:"								\
 	: [tmp] "=&r" (tmp), [oldval] "=&r" (oldval),			\
 	  [v] "+Q" (*(u##sz *)ptr)					\
 	: [old] __stringify(constraint) "r" (old), [new] "r" (new)	\
@@ -326,7 +305,6 @@
 	unsigned long tmp, ret;						\
 									\
 	asm volatile("// __cmpxchg_double" #name "\n"			\
-	__LL_SC_FALLBACK(						\
 	"	prfm	pstl1strm, %2\n"				\
 	"1:	ldxp	%0, %1, %2\n"					\
 	"	eor	%0, %0, %3\n"					\
@@ -336,8 +314,8 @@
 	"	st" #rel "xp	%w0, %5, %6, %2\n"			\
 	"	cbnz	%w0, 1b\n"					\
 	"	" #mb "\n"						\
-	"2:")								\
-	: "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr)	\
+	"2:"								\
+	: "=&r" (tmp), "=&r" (ret), "+Q" (*(__uint128_t *)ptr)		\
 	: "r" (old1), "r" (old2), "r" (new1), "r" (new2)		\
 	: cl);								\
 									\
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/atomic_lse.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/atomic_lse.h
@@ -11,10 +11,11 @@
 #define __ASM_ATOMIC_LSE_H
 
 #define ATOMIC_OP(op, asm_op)						\
-static inline void __lse_atomic_##op(int i, atomic_t *v)			\
+static inline void __lse_atomic_##op(int i, atomic_t *v)		\
 {									\
 	asm volatile(							\
-"	" #asm_op "	%w[i], %[v]\n"					\
+	__LSE_PREAMBLE							\
+	"	" #asm_op "	%w[i], %[v]\n"				\
 	: [i] "+r" (i), [v] "+Q" (v->counter)				\
 	: "r" (v));							\
 }
@@ -30,7 +31,8 @@
 static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v)	\
 {									\
 	asm volatile(							\
-"	" #asm_op #mb "	%w[i], %w[i], %[v]"				\
+	__LSE_PREAMBLE							\
+	"	" #asm_op #mb "	%w[i], %w[i], %[v]"			\
 	: [i] "+r" (i), [v] "+Q" (v->counter)				\
 	: "r" (v)							\
 	: cl);								\
@@ -58,6 +60,7 @@
 	u32 tmp;							\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	ldadd" #mb "	%w[i], %w[tmp], %[v]\n"			\
 	"	add	%w[i], %w[i], %w[tmp]"				\
 	: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)	\
@@ -77,6 +80,7 @@
 static inline void __lse_atomic_and(int i, atomic_t *v)
 {
 	asm volatile(
+	__LSE_PREAMBLE
 	"	mvn	%w[i], %w[i]\n"
 	"	stclr	%w[i], %[v]"
 	: [i] "+&r" (i), [v] "+Q" (v->counter)
@@ -87,6 +91,7 @@
 static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v)	\
 {									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	mvn	%w[i], %w[i]\n"					\
 	"	ldclr" #mb "	%w[i], %w[i], %[v]"			\
 	: [i] "+&r" (i), [v] "+Q" (v->counter)				\
@@ -106,6 +111,7 @@
 static inline void __lse_atomic_sub(int i, atomic_t *v)
 {
 	asm volatile(
+	__LSE_PREAMBLE
 	"	neg	%w[i], %w[i]\n"
 	"	stadd	%w[i], %[v]"
 	: [i] "+&r" (i), [v] "+Q" (v->counter)
@@ -118,12 +124,13 @@
 	u32 tmp;							\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	neg	%w[i], %w[i]\n"					\
 	"	ldadd" #mb "	%w[i], %w[tmp], %[v]\n"			\
 	"	add	%w[i], %w[i], %w[tmp]"				\
 	: [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)	\
 	: "r" (v)							\
-	: cl);							\
+	: cl);								\
 									\
 	return i;							\
 }
@@ -139,6 +146,7 @@
 static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v)	\
 {									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	neg	%w[i], %w[i]\n"					\
 	"	ldadd" #mb "	%w[i], %w[i], %[v]"			\
 	: [i] "+&r" (i), [v] "+Q" (v->counter)				\
@@ -159,7 +167,8 @@
 static inline void __lse_atomic64_##op(s64 i, atomic64_t *v)		\
 {									\
 	asm volatile(							\
-"	" #asm_op "	%[i], %[v]\n"					\
+	__LSE_PREAMBLE							\
+	"	" #asm_op "	%[i], %[v]\n"				\
 	: [i] "+r" (i), [v] "+Q" (v->counter)				\
 	: "r" (v));							\
 }
@@ -175,7 +184,8 @@
 static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\
 {									\
 	asm volatile(							\
-"	" #asm_op #mb "	%[i], %[i], %[v]"				\
+	__LSE_PREAMBLE							\
+	"	" #asm_op #mb "	%[i], %[i], %[v]"			\
 	: [i] "+r" (i), [v] "+Q" (v->counter)				\
 	: "r" (v)							\
 	: cl);								\
@@ -203,6 +213,7 @@
 	unsigned long tmp;						\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	ldadd" #mb "	%[i], %x[tmp], %[v]\n"			\
 	"	add	%[i], %[i], %x[tmp]"				\
 	: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)	\
@@ -222,6 +233,7 @@
 static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
 {
 	asm volatile(
+	__LSE_PREAMBLE
 	"	mvn	%[i], %[i]\n"
 	"	stclr	%[i], %[v]"
 	: [i] "+&r" (i), [v] "+Q" (v->counter)
@@ -232,6 +244,7 @@
 static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v)	\
 {									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	mvn	%[i], %[i]\n"					\
 	"	ldclr" #mb "	%[i], %[i], %[v]"			\
 	: [i] "+&r" (i), [v] "+Q" (v->counter)				\
@@ -251,6 +264,7 @@
 static inline void __lse_atomic64_sub(s64 i, atomic64_t *v)
 {
 	asm volatile(
+	__LSE_PREAMBLE
 	"	neg	%[i], %[i]\n"
 	"	stadd	%[i], %[v]"
 	: [i] "+&r" (i), [v] "+Q" (v->counter)
@@ -258,11 +272,12 @@
 }
 
 #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...)				\
-static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v)	\
+static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v)\
 {									\
 	unsigned long tmp;						\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	neg	%[i], %[i]\n"					\
 	"	ldadd" #mb "	%[i], %x[tmp], %[v]\n"			\
 	"	add	%[i], %[i], %x[tmp]"				\
@@ -284,6 +299,7 @@
 static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v)	\
 {									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	neg	%[i], %[i]\n"					\
 	"	ldadd" #mb "	%[i], %[i], %[v]"			\
 	: [i] "+&r" (i), [v] "+Q" (v->counter)				\
@@ -305,6 +321,7 @@
 	unsigned long tmp;
 
 	asm volatile(
+	__LSE_PREAMBLE
 	"1:	ldr	%x[tmp], %[v]\n"
 	"	subs	%[ret], %x[tmp], #1\n"
 	"	b.lt	2f\n"
@@ -332,6 +349,7 @@
 	unsigned long tmp;						\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	mov	%" #w "[tmp], %" #w "[old]\n"			\
 	"	cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n"	\
 	"	mov	%" #w "[ret], %" #w "[tmp]"			\
@@ -379,12 +397,13 @@
 	register unsigned long x4 asm ("x4") = (unsigned long)ptr;	\
 									\
 	asm volatile(							\
+	__LSE_PREAMBLE							\
 	"	casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
 	"	eor	%[old1], %[old1], %[oldval1]\n"			\
 	"	eor	%[old2], %[old2], %[oldval2]\n"			\
 	"	orr	%[old1], %[old1], %[old2]"			\
 	: [old1] "+&r" (x0), [old2] "+&r" (x1),				\
-	  [v] "+Q" (*(unsigned long *)ptr)				\
+	  [v] "+Q" (*(__uint128_t *)ptr)				\
 	: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),		\
 	  [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)		\
 	: cl);								\
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/barrier.h
@@ -57,6 +57,25 @@
 	return mask;
 }
 
+/*
+ * Ensure that reads of the counter are treated the same as memory reads
+ * for the purposes of ordering by subsequent memory barriers.
+ *
+ * This insanity brought to you by speculative system register reads,
+ * out-of-order memory accesses, sequence locks and Thomas Gleixner.
+ *
+ * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
+ */
+#define arch_counter_enforce_ordering(val) do {				\
+	u64 tmp, _val = (val);						\
+									\
+	asm volatile(							\
+	"	eor	%0, %1, %1\n"					\
+	"	add	%0, sp, %0\n"					\
+	"	ldr	xzr, [%0]"					\
+	: "=r" (tmp) : "r" (_val));					\
+} while (0)
+
 #define __smp_mb()	dmb(ish)
 #define __smp_rmb()	dmb(ishld)
 #define __smp_wmb()	dmb(ishst)
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/brk-imm.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/brk-imm.h
@@ -10,6 +10,7 @@
  * #imm16 values used for BRK instruction generation
  * 0x004: for installing kprobes
  * 0x005: for installing uprobes
+ * 0x006: for kprobe software single-step
  * Allowed values for kgdb are 0x400 - 0x7ff
  * 0x100: for triggering a fault on purpose (reserved)
  * 0x400: for dynamic BRK instruction
@@ -19,6 +20,7 @@
  */
 #define KPROBES_BRK_IMM			0x004
 #define UPROBES_BRK_IMM			0x005
+#define KPROBES_BRK_SS_IMM		0x006
 #define FAULT_BRK_IMM			0x100
 #define KGDB_DYN_DBG_BRK_IMM		0x400
 #define KGDB_COMPILED_DBG_BRK_IMM	0x401
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cache.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cache.h
@@ -11,6 +11,7 @@
 #define CTR_L1IP_MASK		3
 #define CTR_DMINLINE_SHIFT	16
 #define CTR_IMINLINE_SHIFT	0
+#define CTR_IMINLINE_MASK	0xf
 #define CTR_ERG_SHIFT		20
 #define CTR_CWG_SHIFT		24
 #define CTR_CWG_MASK		15
@@ -18,7 +19,7 @@
 #define CTR_DIC_SHIFT		29
 
 #define CTR_CACHE_MINLINE_MASK	\
-	(0xf << CTR_DMINLINE_SHIFT | 0xf << CTR_IMINLINE_SHIFT)
+	(0xf << CTR_DMINLINE_SHIFT | CTR_IMINLINE_MASK << CTR_IMINLINE_SHIFT)
 
 #define CTR_L1IP(ctr)		(((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cacheflush.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cacheflush.h
@@ -79,7 +79,7 @@
 	 * IPI all online CPUs so that they undergo a context synchronization
 	 * event and are forced to refetch the new instructions.
 	 */
-#ifdef CONFIG_KGDB
+
 	/*
 	 * KGDB performs cache maintenance with interrupts disabled, so we
 	 * will deadlock trying to IPI the secondary CPUs. In theory, we can
@@ -89,9 +89,9 @@
 	 * the patching operation, so we don't need extra IPIs here anyway.
 	 * In which case, add a KGDB-specific bodge and return early.
 	 */
-	if (kgdb_connected && irqs_disabled())
+	if (in_dbg_master())
 		return;
-#endif
+
 	kick_all_cpus_sync();
 }
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/checksum.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/checksum.h
@@ -19,16 +19,17 @@
 {
 	__uint128_t tmp;
 	u64 sum;
+	int n = ihl; /* we want it signed */
 
 	tmp = *(const __uint128_t *)iph;
 	iph += 16;
-	ihl -= 4;
+	n -= 4;
 	tmp += ((tmp >> 64) | (tmp << 64));
 	sum = tmp >> 64;
 	do {
 		sum += *(const u32 *)iph;
 		iph += 4;
-	} while (--ihl);
+	} while (--n > 0);
 
 	sum += ((sum >> 32) | (sum << 32));
 	return csum_fold((__force u32)(sum >> 32));
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/clocksource.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/clocksource.h
@@ -2,8 +2,11 @@
 #ifndef _ASM_CLOCKSOURCE_H
 #define _ASM_CLOCKSOURCE_H
 
+#include <asm/vdso/clocksource.h>
+
 struct arch_clocksource_data {
-	bool vdso_direct;	/* Usable for direct VDSO access? */
+	/* Usable for direct VDSO access? */
+	enum vdso_arch_clockmode clock_mode;
 };
 
 #endif
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/compat.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/compat.h
@@ -4,6 +4,9 @@
  */
 #ifndef __ASM_COMPAT_H
 #define __ASM_COMPAT_H
+
+#include <asm-generic/compat.h>
+
 #ifdef CONFIG_COMPAT
 
 /*
@@ -13,8 +16,6 @@
 #include <linux/sched.h>
 #include <linux/sched/task_stack.h>
 
-#include <asm-generic/compat.h>
-
 #define COMPAT_USER_HZ		100
 #ifdef __AARCH64EB__
 #define COMPAT_UTS_MACHINE	"armv8b\0\0"
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cpu.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cpu.h
@@ -25,6 +25,7 @@
 	u64		reg_id_aa64dfr1;
 	u64		reg_id_aa64isar0;
 	u64		reg_id_aa64isar1;
+	u64		reg_id_aa64isar2;
 	u64		reg_id_aa64mmfr0;
 	u64		reg_id_aa64mmfr1;
 	u64		reg_id_aa64mmfr2;
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cpucaps.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cpucaps.h
@@ -54,7 +54,10 @@
 #define ARM64_WORKAROUND_1463225		44
 #define ARM64_WORKAROUND_CAVIUM_TX2_219_TVM	45
 #define ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM	46
+#define ARM64_WORKAROUND_1542419		47
+#define ARM64_SPECTRE_BHB			48
+#define ARM64_WORKAROUND_1742098		49
 
-#define ARM64_NCAPS				47
+#define ARM64_NCAPS				50
 
 #endif /* __ASM_CPUCAPS_H */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cpufeature.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cpufeature.h
@@ -262,6 +262,8 @@
 /*
  * CPU feature detected at boot time based on feature of one or more CPUs.
  * All possible conflicts for a late CPU are ignored.
+ * NOTE: this means that a late CPU with the feature will *not* cause the
+ * capability to be advertised by cpus_have_*cap()!
  */
 #define ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE		\
 	(ARM64_CPUCAP_SCOPE_LOCAL_CPU		|	\
@@ -447,6 +449,29 @@
 	return cpuid_feature_extract_unsigned_field_width(features, field, 4);
 }
 
+/*
+ * Fields that identify the version of the Performance Monitors Extension do
+ * not follow the standard ID scheme. See ARM DDI 0487E.a page D13-2825,
+ * "Alternative ID scheme used for the Performance Monitors Extension version".
+ */
+static inline u64 __attribute_const__
+cpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
+{
+	u64 val = cpuid_feature_extract_unsigned_field(features, field);
+	u64 mask = GENMASK_ULL(field + 3, field);
+
+	/* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
+	if (val == 0xf)
+		val = 0;
+
+	if (val > cap) {
+		features &= ~mask;
+		features |= (cap << field) & mask;
+	}
+
+	return features;
+}
+
 static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
 {
 	return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
@@ -506,6 +531,34 @@
 	return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
 }
 
+static inline bool supports_csv2p3(int scope)
+{
+	u64 pfr0;
+	u8 csv2_val;
+
+	if (scope == SCOPE_LOCAL_CPU)
+		pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
+	else
+		pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+	csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
+							ID_AA64PFR0_CSV2_SHIFT);
+	return csv2_val == 3;
+}
+
+static inline bool supports_clearbhb(int scope)
+{
+	u64 isar2;
+
+	if (scope == SCOPE_LOCAL_CPU)
+		isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
+	else
+		isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
+
+	return cpuid_feature_extract_unsigned_field(isar2,
+						    ID_AA64ISAR2_CLEARBHB_SHIFT);
+}
+
 static inline bool system_supports_32bit_el0(void)
 {
 	return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
@@ -601,7 +654,7 @@
 		 cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH_IMP_DEF));
 }
 
-static inline bool system_uses_irq_prio_masking(void)
+static __always_inline bool system_uses_irq_prio_masking(void)
 {
 	return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
 	       cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
@@ -637,6 +690,18 @@
 
 void arm64_set_ssbd_mitigation(bool state);
 
+/* Watch out, ordering is important here. */
+enum mitigation_state {
+	SPECTRE_UNAFFECTED,
+	SPECTRE_MITIGATED,
+	SPECTRE_VULNERABLE,
+};
+
+enum mitigation_state arm64_get_spectre_bhb_state(void);
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
+u8 spectre_bhb_loop_affected(int scope);
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
+
 extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 
 static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/cputype.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/cputype.h
@@ -41,7 +41,7 @@
 	(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
 
 #define MIDR_CPU_MODEL(imp, partnum) \
-	(((imp)			<< MIDR_IMPLEMENTOR_SHIFT) | \
+	((_AT(u32, imp)		<< MIDR_IMPLEMENTOR_SHIFT) | \
 	(0xf			<< MIDR_ARCHITECTURE_SHIFT) | \
 	((partnum)		<< MIDR_PARTNUM_SHIFT))
 
@@ -59,6 +59,7 @@
 #define ARM_CPU_IMP_NVIDIA		0x4E
 #define ARM_CPU_IMP_FUJITSU		0x46
 #define ARM_CPU_IMP_HISI		0x48
+#define ARM_CPU_IMP_AMPERE		0xC0
 
 #define ARM_CPU_PART_AEM_V8		0xD0F
 #define ARM_CPU_PART_FOUNDATION		0xD00
@@ -71,6 +72,14 @@
 #define ARM_CPU_PART_CORTEX_A55		0xD05
 #define ARM_CPU_PART_CORTEX_A76		0xD0B
 #define ARM_CPU_PART_NEOVERSE_N1	0xD0C
+#define ARM_CPU_PART_CORTEX_A77		0xD0D
+#define ARM_CPU_PART_NEOVERSE_V1	0xD40
+#define ARM_CPU_PART_CORTEX_A78		0xD41
+#define ARM_CPU_PART_CORTEX_X1		0xD44
+#define ARM_CPU_PART_CORTEX_A710	0xD47
+#define ARM_CPU_PART_CORTEX_X2		0xD48
+#define ARM_CPU_PART_NEOVERSE_N2	0xD49
+#define ARM_CPU_PART_CORTEX_A78C	0xD4B
 
 #define APM_CPU_PART_POTENZA		0x000
 
@@ -93,6 +102,8 @@
 
 #define HISI_CPU_PART_TSV110		0xD01
 
+#define AMPERE_CPU_PART_AMPERE1		0xAC3
+
 #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_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
@@ -102,6 +113,14 @@
 #define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
 #define MIDR_CORTEX_A76	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
 #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
+#define MIDR_CORTEX_A77	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_NEOVERSE_V1	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
+#define MIDR_CORTEX_A78	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
+#define MIDR_CORTEX_X1	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
+#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
+#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
+#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
+#define MIDR_CORTEX_A78C	MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 #define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
@@ -115,6 +134,7 @@
 #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
 #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
 #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
+#define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1)
 
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
 #define MIDR_FUJITSU_ERRATUM_010001		MIDR_FUJITSU_A64FX
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/daifflags.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/daifflags.h
@@ -36,7 +36,7 @@
 	trace_hardirqs_off();
 }
 
-static inline unsigned long local_daif_save(void)
+static inline unsigned long local_daif_save_flags(void)
 {
 	unsigned long flags;
 
@@ -48,6 +48,15 @@
 			flags |= PSR_I_BIT;
 	}
 
+	return flags;
+}
+
+static inline unsigned long local_daif_save(void)
+{
+	unsigned long flags;
+
+	flags = local_daif_save_flags();
+
 	local_daif_mask();
 
 	return flags;
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/debug-monitors.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/debug-monitors.h
@@ -53,6 +53,7 @@
 
 /* kprobes BRK opcodes with ESR encoding  */
 #define BRK64_OPCODE_KPROBES	(AARCH64_BREAK_MON | (KPROBES_BRK_IMM << 5))
+#define BRK64_OPCODE_KPROBES_SS	(AARCH64_BREAK_MON | (KPROBES_BRK_SS_IMM << 5))
 /* uprobes BRK opcodes with ESR encoding  */
 #define BRK64_OPCODE_UPROBES	(AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5))
 
@@ -109,10 +110,13 @@
 
 void user_rewind_single_step(struct task_struct *task);
 void user_fastforward_single_step(struct task_struct *task);
+void user_regs_reset_single_step(struct user_pt_regs *regs,
+				 struct task_struct *task);
 
 void kernel_enable_single_step(struct pt_regs *regs);
 void kernel_disable_single_step(void);
 int kernel_active_single_step(void);
+void kernel_rewind_single_step(struct pt_regs *regs);
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 int reinstall_suspended_bps(struct pt_regs *regs);
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/fixmap.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/fixmap.h
@@ -63,9 +63,11 @@
 #endif /* CONFIG_ACPI_APEI_GHES */
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+	FIX_ENTRY_TRAMP_TEXT3,
+	FIX_ENTRY_TRAMP_TEXT2,
+	FIX_ENTRY_TRAMP_TEXT1,
 	FIX_ENTRY_TRAMP_DATA,
-	FIX_ENTRY_TRAMP_TEXT,
-#define TRAMP_VALIAS		(__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
+#define TRAMP_VALIAS		(__fix_to_virt(FIX_ENTRY_TRAMP_TEXT1))
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 	__end_of_permanent_fixed_addresses,
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/io.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/io.h
@@ -204,4 +204,8 @@
 
 extern int devmem_is_allowed(unsigned long pfn);
 
+extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
+					unsigned long flags);
+#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
+
 #endif	/* __ASM_IO_H */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kernel-pgtable.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kernel-pgtable.h
@@ -65,8 +65,8 @@
 #define EARLY_KASLR	(0)
 #endif
 
-#define EARLY_ENTRIES(vstart, vend, shift) (((vend) >> (shift)) \
-					- ((vstart) >> (shift)) + 1 + EARLY_KASLR)
+#define EARLY_ENTRIES(vstart, vend, shift) \
+	((((vend) - 1) >> (shift)) - ((vstart) >> (shift)) + 1 + EARLY_KASLR)
 
 #define EARLY_PGDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT))
 
@@ -89,12 +89,6 @@
 #define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR + TEXT_OFFSET, _end))
 #define IDMAP_DIR_SIZE		(IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
 
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-#define RESERVED_TTBR0_SIZE	(PAGE_SIZE)
-#else
-#define RESERVED_TTBR0_SIZE	(0)
-#endif
-
 /* Initial memory map size */
 #if ARM64_SWAPPER_USES_SECTION_MAPS
 #define SWAPPER_BLOCK_SHIFT	SECTION_SHIFT
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kprobes.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kprobes.h
@@ -16,7 +16,7 @@
 #include <linux/percpu.h>
 
 #define __ARCH_WANT_KPROBES_INSN_SLOT
-#define MAX_INSN_SIZE			1
+#define MAX_INSN_SIZE			2
 
 #define flush_insn_slot(p)		do { } while (0)
 #define kretprobe_blacklist_size	0
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_arm.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_arm.h
@@ -72,11 +72,12 @@
  * IMO:		Override CPSR.I and enable signaling with VI
  * FMO:		Override CPSR.F and enable signaling with VF
  * SWIO:	Turn set/way invalidates into set/way clean+invalidate
+ * PTW:		Take a stage2 fault if a stage1 walk steps in device memory
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
-			 HCR_FMO | HCR_IMO)
+			 HCR_FMO | HCR_IMO | HCR_PTW )
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
 #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
@@ -275,6 +276,7 @@
 #define CPTR_EL2_DEFAULT	CPTR_EL2_RES1
 
 /* Hyp Debug Configuration Register bits */
+#define MDCR_EL2_TTRF		(1 << 19)
 #define MDCR_EL2_TPMS		(1 << 14)
 #define MDCR_EL2_E2PB_MASK	(UL(0x3))
 #define MDCR_EL2_E2PB_SHIFT	(UL(12))
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_asm.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_asm.h
@@ -60,7 +60,7 @@
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
-extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
+extern void __kvm_flush_cpu_context(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
@@ -88,6 +88,34 @@
 		*__hyp_this_cpu_ptr(sym);				\
 	 })
 
+#define __KVM_EXTABLE(from, to)						\
+	"	.pushsection	__kvm_ex_table, \"a\"\n"		\
+	"	.align		3\n"					\
+	"	.long		(" #from " - .), (" #to " - .)\n"	\
+	"	.popsection\n"
+
+
+#define __kvm_at(at_op, addr)						\
+( { 									\
+	int __kvm_at_err = 0;						\
+	u64 spsr, elr;							\
+	asm volatile(							\
+	"	mrs	%1, spsr_el2\n"					\
+	"	mrs	%2, elr_el2\n"					\
+	"1:	at	"at_op", %3\n"					\
+	"	isb\n"							\
+	"	b	9f\n"						\
+	"2:	msr	spsr_el2, %1\n"					\
+	"	msr	elr_el2, %2\n"					\
+	"	mov	%w0, %4\n"					\
+	"9:\n"								\
+	__KVM_EXTABLE(1b, 2b)						\
+	: "+r" (__kvm_at_err), "=&r" (spsr), "=&r" (elr)		\
+	: "r" (addr), "i" (-EFAULT));					\
+	__kvm_at_err;							\
+} )
+
+
 #else /* __ASSEMBLY__ */
 
 .macro hyp_adr_this_cpu reg, sym, tmp
@@ -113,6 +141,21 @@
 	kern_hyp_va	\vcpu
 .endm
 
+/*
+ * KVM extable for unexpected exceptions.
+ * In the same format _asm_extable, but output to a different section so that
+ * it can be mapped to EL2. The KVM version is not sorted. The caller must
+ * ensure:
+ * x18 has the hypervisor value to allow any Shadow-Call-Stack instrumented
+ * code to write to it, and that SPSR_EL2 and ELR_EL2 are restored by the fixup.
+ */
+.macro	_kvm_extable, from, to
+	.pushsection	__kvm_ex_table, "a"
+	.align		3
+	.long		(\from - .), (\to - .)
+	.popsection
+.endm
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_emulate.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_emulate.h
@@ -97,12 +97,6 @@
 	vcpu->arch.hcr_el2 &= ~(HCR_API | HCR_APK);
 }
 
-static inline void vcpu_ptrauth_setup_lazy(struct kvm_vcpu *vcpu)
-{
-	if (vcpu_has_ptrauth(vcpu))
-		vcpu_ptrauth_disable(vcpu);
-}
-
 static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.vsesr_el2;
@@ -204,6 +198,38 @@
 		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
 }
 
+/*
+ * The layout of SPSR for an AArch32 state is different when observed from an
+ * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
+ * view given an AArch64 view.
+ *
+ * In ARM DDI 0487E.a see:
+ *
+ * - The AArch64 view (SPSR_EL2) in section C5.2.18, page C5-426
+ * - The AArch32 view (SPSR_abt) in section G8.2.126, page G8-6256
+ * - The AArch32 view (SPSR_und) in section G8.2.132, page G8-6280
+ *
+ * Which show the following differences:
+ *
+ * | Bit | AA64 | AA32 | Notes                       |
+ * +-----+------+------+-----------------------------|
+ * | 24  | DIT  | J    | J is RES0 in ARMv8          |
+ * | 21  | SS   | DIT  | SS doesn't exist in AArch32 |
+ *
+ * ... and all other bits are (currently) common.
+ */
+static inline unsigned long host_spsr_to_spsr32(unsigned long spsr)
+{
+	const unsigned long overlap = BIT(24) | BIT(21);
+	unsigned long dit = !!(spsr & PSR_AA32_DIT_BIT);
+
+	spsr &= ~overlap;
+
+	spsr |= dit << 21;
+
+	return spsr;
+}
+
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
 {
 	u32 mode;
@@ -263,12 +289,17 @@
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE);
 }
 
+static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
+{
+	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SF);
+}
+
 static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
 {
 	return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
@@ -276,7 +307,7 @@
 static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
-		kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
+		kvm_vcpu_abt_iss1tw(vcpu); /* AF/DBM update */
 }
 
 static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
@@ -305,6 +336,11 @@
 	return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
+static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
+{
+	return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
+}
+
 static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC;
@@ -342,6 +378,27 @@
 
 static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
 {
+	if (kvm_vcpu_abt_iss1tw(vcpu)) {
+		/*
+		 * Only a permission fault on a S1PTW should be
+		 * considered as a write. Otherwise, page tables baked
+		 * in a read-only memslot will result in an exception
+		 * being delivered in the guest.
+		 *
+		 * The drawback is that we end-up faulting twice if the
+		 * guest is using any of HW AF/DB: a translation fault
+		 * to map the page containing the PT (read only at
+		 * first), then a permission fault to allow the flags
+		 * to be set.
+		 */
+		switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
+		case ESR_ELx_FSC_PERM:
+			return true;
+		default:
+			return false;
+		}
+	}
+
 	if (kvm_vcpu_trap_is_iabt(vcpu))
 		return false;
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_host.h
@@ -182,6 +182,7 @@
 #define c2_TTBR1	(TTBR1_EL1 * 2)	/* Translation Table Base Register 1 */
 #define c2_TTBR1_high	(c2_TTBR1 + 1)	/* TTBR1 top 32 bits */
 #define c2_TTBCR	(TCR_EL1 * 2)	/* Translation Table Base Control R. */
+#define c2_TTBCR2	(c2_TTBCR + 1)	/* Translation Table Base Control R. 2 */
 #define c3_DACR		(DACR32_EL2 * 2)/* Domain Access Control Register */
 #define c5_DFSR		(ESR_EL1 * 2)	/* Data Fault Status Register */
 #define c5_IFSR		(IFSR32_EL2 * 2)/* Instruction Fault Status Register */
@@ -209,6 +210,7 @@
 #define cp14_DBGWCR0	(DBGWCR0_EL1 * 2)
 #define cp14_DBGWVR0	(DBGWVR0_EL1 * 2)
 #define cp14_DBGDCCINT	(MDCCINT_EL1 * 2)
+#define cp14_DBGVCR	(DBGVCR32_EL2 * 2)
 
 #define NR_COPRO_REGS	(NR_SYS_REGS * 2)
 
@@ -392,8 +394,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])
 
 struct kvm_vm_stat {
 	ulong remote_tlb_flush;
@@ -425,7 +429,7 @@
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva_range(struct kvm *kvm,
-			unsigned long start, unsigned long end);
+			unsigned long start, unsigned long end, unsigned flags);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
@@ -548,6 +552,7 @@
 static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 
 void kvm_arm_init_debug(void);
+void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
@@ -677,4 +682,6 @@
 #define kvm_arm_vcpu_sve_finalized(vcpu) \
 	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
 
+#define kvm_arm_vcpu_loaded(vcpu)	((vcpu)->arch.sysregs_loaded_on_cpu)
+
 #endif /* __ARM64_KVM_HOST_H__ */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_hyp.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_hyp.h
@@ -71,6 +71,9 @@
 
 void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
 void __debug_switch_to_host(struct kvm_vcpu *vcpu);
+void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu);
+void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu);
+
 
 void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_mmio.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_mmio.h
@@ -10,13 +10,11 @@
 #include <linux/kvm_host.h>
 #include <asm/kvm_arm.h>
 
-/*
- * This is annoying. The mmio code requires this, even if we don't
- * need any decoding. To be fixed.
- */
 struct kvm_decode {
 	unsigned long rt;
 	bool sign_extend;
+	/* Witdth of the register accessed by the faulting instruction is 64-bits */
+	bool sixty_four;
 };
 
 void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/kvm_mmu.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/kvm_mmu.h
@@ -478,7 +478,9 @@
 	void *vect = kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
 	int slot = -1;
 
-	if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) && data->fn) {
+	if ((cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) ||
+	     cpus_have_const_cap(ARM64_SPECTRE_BHB)) &&
+	    data && data->template_start) {
 		vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs_start));
 		slot = data->hyp_vectors_slot;
 	}
@@ -507,7 +509,8 @@
 	 * !HBP +  HEL2 -> allocate one vector slot and use exec mapping
 	 *  HBP +  HEL2 -> use hardened vertors and use exec mapping
 	 */
-	if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) {
+	if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) ||
+	    cpus_have_const_cap(ARM64_SPECTRE_BHB)) {
 		__kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs_start);
 		__kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
 	}
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/linkage.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/linkage.h
@@ -4,4 +4,20 @@
 #define __ALIGN		.align 2
 #define __ALIGN_STR	".align 2"
 
+/*
+ * Annotate a function as position independent, i.e., safe to be called before
+ * the kernel virtual mapping is activated.
+ */
+#define SYM_FUNC_START_PI(x)			\
+		SYM_FUNC_START_ALIAS(__pi_##x);	\
+		SYM_FUNC_START(x)
+
+#define SYM_FUNC_START_WEAK_PI(x)		\
+		SYM_FUNC_START_ALIAS(__pi_##x);	\
+		SYM_FUNC_START_WEAK(x)
+
+#define SYM_FUNC_END_PI(x)			\
+		SYM_FUNC_END(x);		\
+		SYM_FUNC_END_ALIAS(__pi_##x)
+
 #endif
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/lse.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/lse.h
@@ -6,6 +6,8 @@
 
 #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
 
+#define __LSE_PREAMBLE	".arch_extension lse\n"
+
 #include <linux/compiler_types.h>
 #include <linux/export.h>
 #include <linux/jump_label.h>
@@ -14,8 +16,6 @@
 #include <asm/atomic_lse.h>
 #include <asm/cpucaps.h>
 
-__asm__(".arch_extension	lse");
-
 extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
 extern struct static_key_false arm64_const_caps_ready;
 
@@ -34,7 +34,7 @@
 
 /* In-line patching at runtime */
 #define ARM64_LSE_ATOMIC_INSN(llsc, lse)				\
-	ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS)
+	ALTERNATIVE(llsc, __LSE_PREAMBLE lse, ARM64_HAS_LSE_ATOMICS)
 
 #else	/* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/memory.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/memory.h
@@ -178,7 +178,6 @@
 #include <linux/bitops.h>
 #include <linux/mmdebug.h>
 
-extern s64			physvirt_offset;
 extern s64			memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
 #define PHYS_OFFSET		({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
@@ -219,7 +218,7 @@
 	((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55))
 
 #define untagged_addr(addr)	({					\
-	u64 __addr = (__force u64)addr;					\
+	u64 __addr = (__force u64)(addr);					\
 	__addr &= __untagged_addr(__addr);				\
 	(__force __typeof__(addr))__addr;				\
 })
@@ -248,13 +247,13 @@
 
 
 /*
- * The linear kernel range starts at the bottom of the virtual address
- * space. Testing the top bit for the start of the region is a
- * sufficient check and avoids having to worry about the tag.
+ * Check whether an arbitrary address is within the linear map, which
+ * lives in the [PAGE_OFFSET, PAGE_END) interval at the bottom of the
+ * kernel's TTBR1 address range.
  */
-#define __is_lm_address(addr)	(!(((u64)addr) & BIT(vabits_actual - 1)))
+#define __is_lm_address(addr)	(((u64)(addr) ^ PAGE_OFFSET) < (PAGE_END - PAGE_OFFSET))
 
-#define __lm_to_phys(addr)	(((addr) + physvirt_offset))
+#define __lm_to_phys(addr)	(((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
 #define __kimg_to_phys(addr)	((addr) - kimage_voffset)
 
 #define __virt_to_phys_nodebug(x) ({					\
@@ -272,7 +271,7 @@
 #define __phys_addr_symbol(x)	__pa_symbol_nodebug(x)
 #endif /* CONFIG_DEBUG_VIRTUAL */
 
-#define __phys_to_virt(x)	((unsigned long)((x) - physvirt_offset))
+#define __phys_to_virt(x)	((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
 #define __phys_to_kimg(x)	((unsigned long)((x) + kimage_voffset))
 
 /*
@@ -316,6 +315,11 @@
 #define ARCH_PFN_OFFSET		((unsigned long)PHYS_PFN_OFFSET)
 
 #if !defined(CONFIG_SPARSEMEM_VMEMMAP) || defined(CONFIG_DEBUG_VIRTUAL)
+#define page_to_virt(x)	({						\
+	__typeof__(x) __page = x;					\
+	void *__addr = __va(page_to_phys(__page));			\
+	(void *)__tag_set((const void *)__addr, page_kasan_tag(__page));\
+})
 #define virt_to_page(x)		pfn_to_page(virt_to_pfn(x))
 #else
 #define page_to_virt(x)	({						\
@@ -333,7 +337,7 @@
 #endif /* !CONFIG_SPARSEMEM_VMEMMAP || CONFIG_DEBUG_VIRTUAL */
 
 #define virt_addr_valid(addr)	({					\
-	__typeof__(addr) __addr = addr;					\
+	__typeof__(addr) __addr = __tag_reset(addr);			\
 	__is_lm_address(__addr) && pfn_valid(virt_to_pfn(__addr));	\
 })
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/mmu.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/mmu.h
@@ -29,7 +29,7 @@
  */
 #define ASID(mm)	((mm)->context.id.counter & 0xffff)
 
-static inline bool arm64_kernel_unmapped_at_el0(void)
+static __always_inline bool arm64_kernel_unmapped_at_el0(void)
 {
 	return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) &&
 	       cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
@@ -82,6 +82,12 @@
 struct bp_hardening_data {
 	int			hyp_vectors_slot;
 	bp_hardening_cb_t	fn;
+
+	/*
+	 * template_start is only used by the BHB mitigation to identify the
+	 * hyp_vectors_slot sequence.
+	 */
+	const char *template_start;
 };
 
 #if (defined(CONFIG_HARDEN_BRANCH_PREDICTOR) ||	\
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/mmu_context.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/mmu_context.h
@@ -36,11 +36,11 @@
 }
 
 /*
- * Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0.
+ * Set TTBR0 to reserved_pg_dir. No translations will be possible via TTBR0.
  */
 static inline void cpu_set_reserved_ttbr0(void)
 {
-	unsigned long ttbr = phys_to_ttbr(__pa_symbol(empty_zero_page));
+	unsigned long ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
 
 	write_sysreg(ttbr, ttbr0_el1);
 	isb();
@@ -63,10 +63,7 @@
 
 static inline bool __cpu_uses_extended_idmap(void)
 {
-	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52))
-		return false;
-
-	return unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS));
+	return unlikely(idmap_t0sz != TCR_T0SZ(vabits_actual));
 }
 
 /*
@@ -187,9 +184,9 @@
 		return;
 
 	if (mm == &init_mm)
-		ttbr = __pa_symbol(empty_zero_page);
+		ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
 	else
-		ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
+		ttbr = phys_to_ttbr(virt_to_phys(mm->pgd)) | ASID(mm) << 48;
 
 	WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr);
 }
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/numa.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/numa.h
@@ -25,6 +25,9 @@
 /* Returns a pointer to the cpumask of CPUs on Node 'node'. */
 static inline const struct cpumask *cpumask_of_node(int node)
 {
+	if (node == NUMA_NO_NODE)
+		return cpu_all_mask;
+
 	return node_to_cpumask_map[node];
 }
 #endif
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/pgtable-hwdef.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/pgtable-hwdef.h
@@ -215,6 +215,7 @@
 #define TCR_TxSZ(x)		(TCR_T0SZ(x) | TCR_T1SZ(x))
 #define TCR_TxSZ_WIDTH		6
 #define TCR_T0SZ_MASK		(((UL(1) << TCR_TxSZ_WIDTH) - 1) << TCR_T0SZ_OFFSET)
+#define TCR_T1SZ_MASK		(((UL(1) << TCR_TxSZ_WIDTH) - 1) << TCR_T1SZ_OFFSET)
 
 #define TCR_EPD0_SHIFT		7
 #define TCR_EPD0_MASK		(UL(1) << TCR_EPD0_SHIFT)
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/pgtable-prot.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/pgtable-prot.h
@@ -54,7 +54,7 @@
 #define PAGE_HYP		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
 #define PAGE_HYP_EXEC		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
 #define PAGE_HYP_RO		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
-#define PAGE_HYP_DEVICE		__pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
+#define PAGE_HYP_DEVICE		__pgprot(_PROT_DEFAULT | PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_HYP | PTE_HYP_XN)
 
 #define PAGE_S2_MEMATTR(attr)						\
 	({								\
@@ -85,13 +85,12 @@
 #define PAGE_SHARED_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
 #define PAGE_READONLY		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_READONLY_EXEC	__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN)
-#define PAGE_EXECONLY		__pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN)
 
 #define __P000  PAGE_NONE
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_READONLY
 #define __P011  PAGE_READONLY
-#define __P100  PAGE_EXECONLY
+#define __P100  PAGE_READONLY_EXEC
 #define __P101  PAGE_READONLY_EXEC
 #define __P110  PAGE_READONLY_EXEC
 #define __P111  PAGE_READONLY_EXEC
@@ -100,7 +99,7 @@
 #define __S001  PAGE_READONLY
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_EXECONLY
+#define __S100  PAGE_READONLY_EXEC
 #define __S101  PAGE_READONLY_EXEC
 #define __S110  PAGE_SHARED_EXEC
 #define __S111  PAGE_SHARED_EXEC
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/pgtable.h
@@ -23,6 +23,8 @@
 #define VMALLOC_START		(MODULES_END)
 #define VMALLOC_END		(- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
+#define vmemmap			((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
+
 #define FIRST_USER_ADDRESS	0UL
 
 #ifndef __ASSEMBLY__
@@ -33,8 +35,6 @@
 #include <linux/mm_types.h>
 #include <linux/sched.h>
 
-extern struct page *vmemmap;
-
 extern void __pte_error(const char *file, int line, unsigned long val);
 extern void __pmd_error(const char *file, int line, unsigned long val);
 extern void __pud_error(const char *file, int line, unsigned long val);
@@ -54,9 +54,15 @@
  * page table entry, taking care of 52-bit addresses.
  */
 #ifdef CONFIG_ARM64_PA_BITS_52
-#define __pte_to_phys(pte)	\
-	((pte_val(pte) & PTE_ADDR_LOW) | ((pte_val(pte) & PTE_ADDR_HIGH) << 36))
-#define __phys_to_pte_val(phys)	(((phys) | ((phys) >> 36)) & PTE_ADDR_MASK)
+static inline phys_addr_t __pte_to_phys(pte_t pte)
+{
+	return (pte_val(pte) & PTE_ADDR_LOW) |
+		((pte_val(pte) & PTE_ADDR_HIGH) << 36);
+}
+static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
+{
+	return (phys | (phys >> 36)) & PTE_ADDR_MASK;
+}
 #else
 #define __pte_to_phys(pte)	(pte_val(pte) & PTE_ADDR_MASK)
 #define __phys_to_pte_val(phys)	(phys)
@@ -96,14 +102,8 @@
 #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
 
 #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
-/*
- * Execute-only user mappings do not have the PTE_USER bit set. All valid
- * kernel mappings have the PTE_UXN bit set.
- */
 #define pte_valid_not_user(pte) \
-	((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
-#define pte_valid_young(pte) \
-	((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
+	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 #define pte_valid_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 
@@ -111,14 +111,17 @@
  * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
  * so that we don't erroneously return false for pages that have been
  * remapped as PROT_NONE but are yet to be flushed from the TLB.
+ * Note that we can't make any assumptions based on the state of the access
+ * flag, since ptep_clear_flush_young() elides a DSB when invalidating the
+ * TLB.
  */
 #define pte_accessible(mm, pte)	\
-	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
+	(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
 
 /*
  * p??_access_permitted() is true for valid user mappings (subject to the
- * write permission check) other than user execute-only which do not have the
- * PTE_USER bit set. PROT_NONE mappings do not have the PTE_VALID bit set.
+ * write permission check). PROT_NONE mappings do not have the PTE_VALID bit
+ * set.
  */
 #define pte_access_permitted(pte, write) \
 	(pte_valid_user(pte) && (!(write) || pte_write(pte)))
@@ -139,13 +142,6 @@
 	return pte;
 }
 
-static inline pte_t pte_wrprotect(pte_t pte)
-{
-	pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
-	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
-	return pte;
-}
-
 static inline pte_t pte_mkwrite(pte_t pte)
 {
 	pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
@@ -171,6 +167,20 @@
 	return pte;
 }
 
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+	/*
+	 * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
+	 * clear), set the PTE_DIRTY bit.
+	 */
+	if (pte_hw_dirty(pte))
+		pte = pte_mkdirty(pte);
+
+	pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
+	pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
+	return pte;
+}
+
 static inline pte_t pte_mkold(pte_t pte)
 {
 	return clear_pte_bit(pte, __pgprot(PTE_AF));
@@ -460,7 +470,9 @@
 extern pgd_t init_pg_end[];
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
+extern pgd_t idmap_pg_end[];
 extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
+extern pgd_t reserved_pg_dir[PTRS_PER_PGD];
 
 extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
 
@@ -667,6 +679,12 @@
 	if (pte_hw_dirty(pte))
 		pte = pte_mkdirty(pte);
 	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
+	/*
+	 * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware
+	 * dirtiness again.
+	 */
+	if (pte_sw_dirty(pte))
+		pte = pte_mkdirty(pte);
 	return pte;
 }
 
@@ -785,12 +803,6 @@
 	pte = READ_ONCE(*ptep);
 	do {
 		old_pte = pte;
-		/*
-		 * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
-		 * clear), set the PTE_DIRTY bit.
-		 */
-		if (pte_hw_dirty(pte))
-			pte = pte_mkdirty(pte);
 		pte = pte_wrprotect(pte);
 		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
 					       pte_val(old_pte), pte_val(pte));
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/pointer_auth.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/pointer_auth.h
@@ -3,7 +3,6 @@
 #define __ASM_POINTER_AUTH_H
 
 #include <linux/bitops.h>
-#include <linux/random.h>
 
 #include <asm/cpufeature.h>
 #include <asm/memory.h>
@@ -30,6 +29,13 @@
 	struct ptrauth_key apga;
 };
 
+/*
+ * Only include random.h once ptrauth_keys_* structures are defined
+ * to avoid yet another circular include hell (random.h * ends up
+ * including asm/smp.h, which requires ptrauth_keys_kernel).
+ */
+#include <linux/random.h>
+
 static inline void ptrauth_keys_init(struct ptrauth_keys *keys)
 {
 	if (system_supports_address_auth()) {
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/processor.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/processor.h
@@ -184,8 +184,9 @@
 
 static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
 {
+	s32 previous_syscall = regs->syscallno;
 	memset(regs, 0, sizeof(*regs));
-	forget_syscall(regs);
+	regs->syscallno = previous_syscall;
 	regs->pc = pc;
 
 	if (system_uses_irq_prio_masking())
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/ptrace.h
@@ -62,6 +62,7 @@
 #define PSR_AA32_I_BIT		0x00000080
 #define PSR_AA32_A_BIT		0x00000100
 #define PSR_AA32_E_BIT		0x00000200
+#define PSR_AA32_PAN_BIT	0x00400000
 #define PSR_AA32_SSBS_BIT	0x00800000
 #define PSR_AA32_DIT_BIT	0x01000000
 #define PSR_AA32_Q_BIT		0x08000000
@@ -298,7 +299,17 @@
 
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
-	return regs->regs[0];
+	unsigned long val = regs->regs[0];
+
+	/*
+	 * Audit currently uses regs_return_value() instead of
+	 * syscall_get_return_value(). Apply the same sign-extension here until
+	 * audit is updated to use syscall_get_return_value().
+	 */
+	if (compat_user_mode(regs))
+		val = sign_extend64(val, 31);
+
+	return val;
 }
 
 static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/sections.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/sections.h
@@ -15,8 +15,14 @@
 extern char __idmap_text_start[], __idmap_text_end[];
 extern char __initdata_begin[], __initdata_end[];
 extern char __inittext_begin[], __inittext_end[];
+extern char __exittext_begin[], __exittext_end[];
 extern char __irqentry_text_start[], __irqentry_text_end[];
 extern char __mmuoff_data_start[], __mmuoff_data_end[];
 extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
 
+static inline size_t entry_tramp_text_size(void)
+{
+	return __entry_tramp_text_end - __entry_tramp_text_start;
+}
+
 #endif /* __ASM_SECTIONS_H */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/smp.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/smp.h
@@ -46,7 +46,12 @@
  * Logical CPU mapping.
  */
 extern u64 __cpu_logical_map[NR_CPUS];
-#define cpu_logical_map(cpu)    __cpu_logical_map[cpu]
+extern u64 cpu_logical_map(int cpu);
+
+static inline void set_cpu_logical_map(int cpu, u64 hwid)
+{
+	__cpu_logical_map[cpu] = hwid;
+}
 
 struct seq_file;
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/syscall.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/syscall.h
@@ -29,25 +29,36 @@
 	regs->regs[0] = regs->orig_x0;
 }
 
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	unsigned long val = regs->regs[0];
+
+	if (is_compat_thread(task_thread_info(task)))
+		val = sign_extend64(val, 31);
+
+	return val;
+}
 
 static inline long syscall_get_error(struct task_struct *task,
 				     struct pt_regs *regs)
 {
-	unsigned long error = regs->regs[0];
-	return IS_ERR_VALUE(error) ? error : 0;
-}
+	unsigned long error = syscall_get_return_value(task, regs);
 
-static inline long syscall_get_return_value(struct task_struct *task,
-					    struct pt_regs *regs)
-{
-	return regs->regs[0];
+	return IS_ERR_VALUE(error) ? error : 0;
 }
 
 static inline void syscall_set_return_value(struct task_struct *task,
 					    struct pt_regs *regs,
 					    int error, long val)
 {
-	regs->regs[0] = (long) error ? error : val;
+	if (error)
+		val = error;
+
+	if (is_compat_thread(task_thread_info(task)))
+		val = lower_32_bits(val);
+
+	regs->regs[0] = val;
 }
 
 #define SYSCALL_MAX_ARGS 6
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/syscall_wrapper.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/syscall_wrapper.h
@@ -8,7 +8,7 @@
 #ifndef __ASM_SYSCALL_WRAPPER_H
 #define __ASM_SYSCALL_WRAPPER_H
 
-struct pt_regs;
+#include <asm/ptrace.h>
 
 #define SC_ARM64_REGS_TO_ARGS(x, ...)				\
 	__MAP(x,__SC_ARGS					\
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/sysreg.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/sysreg.h
@@ -49,7 +49,9 @@
 #ifndef CONFIG_BROKEN_GAS_INST
 
 #ifdef __ASSEMBLY__
-#define __emit_inst(x)			.inst (x)
+// The space separator is omitted so that __emit_inst(x) can be parsed as
+// either an assembler directive or an assembler macro argument.
+#define __emit_inst(x)			.inst(x)
 #else
 #define __emit_inst(x)			".inst " __stringify((x)) "\n\t"
 #endif
@@ -100,8 +102,14 @@
 #define SB_BARRIER_INSN			__SYS_BARRIER_INSN(0, 7, 31)
 
 #define SYS_DC_ISW			sys_insn(1, 0, 7, 6, 2)
+#define SYS_DC_IGSW			sys_insn(1, 0, 7, 6, 4)
+#define SYS_DC_IGDSW			sys_insn(1, 0, 7, 6, 6)
 #define SYS_DC_CSW			sys_insn(1, 0, 7, 10, 2)
+#define SYS_DC_CGSW			sys_insn(1, 0, 7, 10, 4)
+#define SYS_DC_CGDSW			sys_insn(1, 0, 7, 10, 6)
 #define SYS_DC_CISW			sys_insn(1, 0, 7, 14, 2)
+#define SYS_DC_CIGSW			sys_insn(1, 0, 7, 14, 4)
+#define SYS_DC_CIGDSW			sys_insn(1, 0, 7, 14, 6)
 
 #define SYS_OSDTRRX_EL1			sys_reg(2, 0, 0, 0, 2)
 #define SYS_MDCCINT_EL1			sys_reg(2, 0, 0, 2, 0)
@@ -163,6 +171,7 @@
 
 #define SYS_ID_AA64ISAR0_EL1		sys_reg(3, 0, 0, 6, 0)
 #define SYS_ID_AA64ISAR1_EL1		sys_reg(3, 0, 0, 6, 1)
+#define SYS_ID_AA64ISAR2_EL1		sys_reg(3, 0, 0, 6, 2)
 
 #define SYS_ID_AA64MMFR0_EL1		sys_reg(3, 0, 0, 7, 0)
 #define SYS_ID_AA64MMFR1_EL1		sys_reg(3, 0, 0, 7, 1)
@@ -573,6 +582,21 @@
 #define ID_AA64ISAR1_GPI_NI		0x0
 #define ID_AA64ISAR1_GPI_IMP_DEF	0x1
 
+/* id_aa64isar2 */
+#define ID_AA64ISAR2_CLEARBHB_SHIFT	28
+#define ID_AA64ISAR2_RPRES_SHIFT	4
+#define ID_AA64ISAR2_WFXT_SHIFT		0
+
+#define ID_AA64ISAR2_RPRES_8BIT		0x0
+#define ID_AA64ISAR2_RPRES_12BIT	0x1
+/*
+ * Value 0x1 has been removed from the architecture, and is
+ * reserved, but has not yet been removed from the ARM ARM
+ * as of ARM DDI 0487G.b.
+ */
+#define ID_AA64ISAR2_WFXT_NI		0x0
+#define ID_AA64ISAR2_WFXT_SUPPORTED	0x2
+
 /* id_aa64pfr0 */
 #define ID_AA64PFR0_CSV3_SHIFT		60
 #define ID_AA64PFR0_CSV2_SHIFT		56
@@ -644,6 +668,7 @@
 #endif
 
 /* id_aa64mmfr1 */
+#define ID_AA64MMFR1_ECBHB_SHIFT	60
 #define ID_AA64MMFR1_PAN_SHIFT		20
 #define ID_AA64MMFR1_LOR_SHIFT		16
 #define ID_AA64MMFR1_HPD_SHIFT		12
@@ -672,6 +697,12 @@
 #define ID_AA64DFR0_TRACEVER_SHIFT	4
 #define ID_AA64DFR0_DEBUGVER_SHIFT	0
 
+#define ID_AA64DFR0_PMUVER_8_1		0x4
+
+#define ID_DFR0_PERFMON_SHIFT		24
+
+#define ID_DFR0_PERFMON_8_1		0x4
+
 #define ID_ISAR5_RDM_SHIFT		24
 #define ID_ISAR5_CRC32_SHIFT		16
 #define ID_ISAR5_SHA2_SHIFT		12
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/thread_info.h
@@ -91,6 +91,7 @@
 #define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
 #define _TIF_FSCHECK		(1 << TIF_FSCHECK)
+#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_32BIT		(1 << TIF_32BIT)
 #define _TIF_SVE		(1 << TIF_SVE)
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/uaccess.h
@@ -62,8 +62,13 @@
 {
 	unsigned long ret, limit = current_thread_info()->addr_limit;
 
+	/*
+	 * Asynchronous I/O running in a kernel thread does not have the
+	 * TIF_TAGGED_ADDR flag of the process owning the mm, so always untag
+	 * the user address before checking.
+	 */
 	if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) &&
-	    test_thread_flag(TIF_TAGGED_ADDR))
+	    (current->flags & PF_KTHREAD || test_thread_flag(TIF_TAGGED_ADDR)))
 		addr = untagged_addr(addr);
 
 	__chk_user_ptr(addr);
@@ -107,8 +112,8 @@
 	local_irq_save(flags);
 	ttbr = read_sysreg(ttbr1_el1);
 	ttbr &= ~TTBR_ASID_MASK;
-	/* reserved_ttbr0 placed before swapper_pg_dir */
-	write_sysreg(ttbr - RESERVED_TTBR0_SIZE, ttbr0_el1);
+	/* reserved_pg_dir placed before swapper_pg_dir */
+	write_sysreg(ttbr - PAGE_SIZE, ttbr0_el1);
 	isb();
 	/* Set reserved ASID */
 	write_sysreg(ttbr, ttbr1_el1);
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/unistd.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/unistd.h
@@ -25,8 +25,8 @@
 #define __NR_compat_gettimeofday	78
 #define __NR_compat_sigreturn		119
 #define __NR_compat_rt_sigreturn	173
-#define __NR_compat_clock_getres	247
 #define __NR_compat_clock_gettime	263
+#define __NR_compat_clock_getres	264
 #define __NR_compat_clock_gettime64	403
 #define __NR_compat_clock_getres_time64	406
 
@@ -42,7 +42,6 @@
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
-#define __ARCH_WANT_SYS_CLONE3
 
 #ifndef __COMPAT_SYSCALL_NR
 #include <uapi/asm/unistd.h>
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/vdso/clocksource.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/vdso/clocksource.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_VDSOCLOCKSOURCE_H
+#define __ASM_VDSOCLOCKSOURCE_H
+
+enum vdso_arch_clockmode {
+	/* vdso clocksource not usable */
+	VDSO_CLOCKMODE_NONE,
+	/* vdso clocksource for both 32 and 64bit tasks */
+	VDSO_CLOCKMODE_ARCHTIMER,
+	/* vdso clocksource for 64bit tasks only */
+	VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT,
+};
+
+#endif
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/vdso/compat_gettimeofday.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/vdso/compat_gettimeofday.h
@@ -10,6 +10,7 @@
 #include <asm/unistd.h>
 #include <uapi/linux/time.h>
 
+#include <asm/vdso/clocksource.h>
 #include <asm/vdso/compat_barrier.h>
 
 #define __VDSO_USE_SYSCALL		ULLONG_MAX
@@ -117,10 +118,10 @@
 	u64 res;
 
 	/*
-	 * clock_mode == 0 implies that vDSO are enabled otherwise
+	 * clock_mode == ARCHTIMER implies that vDSO are enabled otherwise
 	 * fallback on syscall.
 	 */
-	if (clock_mode)
+	if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
 		return __VDSO_USE_SYSCALL;
 
 	/*
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/vdso/gettimeofday.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/vdso/gettimeofday.h
@@ -10,6 +10,8 @@
 #include <asm/unistd.h>
 #include <uapi/linux/time.h>
 
+#include <asm/vdso/clocksource.h>
+
 #define __VDSO_USE_SYSCALL		ULLONG_MAX
 
 #define VDSO_HAS_CLOCK_GETRES		1
@@ -71,10 +73,10 @@
 	u64 res;
 
 	/*
-	 * clock_mode == 0 implies that vDSO are enabled otherwise
+	 * clock_mode != NONE implies that vDSO are enabled otherwise
 	 * fallback on syscall.
 	 */
-	if (clock_mode)
+	if (clock_mode == VDSO_CLOCKMODE_NONE)
 		return __VDSO_USE_SYSCALL;
 
 	/*
@@ -83,11 +85,7 @@
 	 */
 	isb();
 	asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory");
-	/*
-	 * This isb() is required to prevent that the seq lock is
-	 * speculated.#
-	 */
-	isb();
+	arch_counter_enforce_ordering(res);
 
 	return res;
 }
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/vdso/vsyscall.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/vdso/vsyscall.h
@@ -24,9 +24,7 @@
 static __always_inline
 int __arm64_get_clock_mode(struct timekeeper *tk)
 {
-	u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct;
-
-	return use_syscall;
+	return tk->tkr_mono.clock->archdata.clock_mode;
 }
 #define __arch_get_clock_mode __arm64_get_clock_mode
 
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/vectors.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/vectors.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 ARM Ltd.
+ */
+#ifndef __ASM_VECTORS_H
+#define __ASM_VECTORS_H
+
+#include <linux/bug.h>
+#include <linux/percpu.h>
+
+#include <asm/fixmap.h>
+
+extern char vectors[];
+extern char tramp_vectors[];
+extern char __bp_harden_el1_vectors[];
+
+/*
+ * Note: the order of this enum corresponds to two arrays in entry.S:
+ * tramp_vecs and __bp_harden_el1_vectors. By default the canonical
+ * 'full fat' vectors are used directly.
+ */
+enum arm64_bp_harden_el1_vectors {
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+	/*
+	 * Perform the BHB loop mitigation, before branching to the canonical
+	 * vectors.
+	 */
+	EL1_VECTOR_BHB_LOOP,
+
+	/*
+	 * Make the SMC call for firmware mitigation, before branching to the
+	 * canonical vectors.
+	 */
+	EL1_VECTOR_BHB_FW,
+
+	/*
+	 * Use the ClearBHB instruction, before branching to the canonical
+	 * vectors.
+	 */
+	EL1_VECTOR_BHB_CLEAR_INSN,
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+
+	/*
+	 * Remap the kernel before branching to the canonical vectors.
+	 */
+	EL1_VECTOR_KPTI,
+};
+
+#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+#define EL1_VECTOR_BHB_LOOP		-1
+#define EL1_VECTOR_BHB_FW		-1
+#define EL1_VECTOR_BHB_CLEAR_INSN	-1
+#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+
+/* The vectors to use on return from EL0. e.g. to remap the kernel */
+DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
+
+#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
+#define TRAMP_VALIAS	0ul
+#endif
+
+static inline const char *
+arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot)
+{
+	if (arm64_kernel_unmapped_at_el0())
+		return (char *)(TRAMP_VALIAS + SZ_2K * slot);
+
+	WARN_ON_ONCE(slot == EL1_VECTOR_KPTI);
+
+	return __bp_harden_el1_vectors + SZ_2K * slot;
+}
+
+#endif /* __ASM_VECTORS_H */
--- linux-ein-5.4.0.orig/arch/arm64/include/asm/word-at-a-time.h
+++ linux-ein-5.4.0/arch/arm64/include/asm/word-at-a-time.h
@@ -53,7 +53,7 @@
  */
 static inline unsigned long load_unaligned_zeropad(const void *addr)
 {
-	unsigned long ret, offset;
+	unsigned long ret, tmp;
 
 	/* Load word from unaligned pointer addr */
 	asm(
@@ -61,9 +61,9 @@
 	"2:\n"
 	"	.pushsection .fixup,\"ax\"\n"
 	"	.align 2\n"
-	"3:	and	%1, %2, #0x7\n"
-	"	bic	%2, %2, #0x7\n"
-	"	ldr	%0, [%2]\n"
+	"3:	bic	%1, %2, #0x7\n"
+	"	ldr	%0, [%1]\n"
+	"	and	%1, %2, #0x7\n"
 	"	lsl	%1, %1, #0x3\n"
 #ifndef __AARCH64EB__
 	"	lsr	%0, %0, %1\n"
@@ -73,7 +73,7 @@
 	"	b	2b\n"
 	"	.popsection\n"
 	_ASM_EXTABLE(1b, 3b)
-	: "=&r" (ret), "=&r" (offset)
+	: "=&r" (ret), "=&r" (tmp)
 	: "r" (addr), "Q" (*(unsigned long *)addr));
 
 	return ret;
--- linux-ein-5.4.0.orig/arch/arm64/include/uapi/asm/kvm.h
+++ linux-ein-5.4.0/arch/arm64/include/uapi/asm/kvm.h
@@ -240,6 +240,11 @@
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED	3
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED     	(1U << 4)
 
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3	KVM_REG_ARM_FW_REG(3)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL		0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL		1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED	2
+
 /* SVE registers */
 #define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
 
--- linux-ein-5.4.0.orig/arch/arm64/include/uapi/asm/ptrace.h
+++ linux-ein-5.4.0/arch/arm64/include/uapi/asm/ptrace.h
@@ -49,6 +49,7 @@
 #define PSR_SSBS_BIT	0x00001000
 #define PSR_PAN_BIT	0x00400000
 #define PSR_UAO_BIT	0x00800000
+#define PSR_DIT_BIT	0x01000000
 #define PSR_V_BIT	0x10000000
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
--- linux-ein-5.4.0.orig/arch/arm64/include/uapi/asm/unistd.h
+++ linux-ein-5.4.0/arch/arm64/include/uapi/asm/unistd.h
@@ -19,5 +19,6 @@
 #define __ARCH_WANT_NEW_STAT
 #define __ARCH_WANT_SET_GET_RLIMIT
 #define __ARCH_WANT_TIME32_SYSCALLS
+#define __ARCH_WANT_SYS_CLONE3
 
 #include <asm-generic/unistd.h>
--- linux-ein-5.4.0.orig/arch/arm64/kernel/acpi.c
+++ linux-ein-5.4.0/arch/arm64/kernel/acpi.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/irq_work.h>
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/smp.h>
@@ -269,12 +270,19 @@
 int apei_claim_sea(struct pt_regs *regs)
 {
 	int err = -ENOENT;
+	bool return_to_irqs_enabled;
 	unsigned long current_flags;
 
 	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
 		return err;
 
-	current_flags = arch_local_save_flags();
+	current_flags = local_daif_save_flags();
+
+	/* current_flags isn't useful here as daif doesn't tell us about pNMI */
+	return_to_irqs_enabled = !irqs_disabled_flags(arch_local_save_flags());
+
+	if (regs)
+		return_to_irqs_enabled = interrupts_enabled(regs);
 
 	/*
 	 * SEA can interrupt SError, mask it and describe this as an NMI so
@@ -284,6 +292,23 @@
 	nmi_enter();
 	err = ghes_notify_sea();
 	nmi_exit();
+
+	/*
+	 * APEI NMI-like notifications are deferred to irq_work. Unless
+	 * we interrupted irqs-masked code, we can do that now.
+	 */
+	if (!err) {
+		if (return_to_irqs_enabled) {
+			local_daif_restore(DAIF_PROCCTX_NOIRQ);
+			__irq_enter();
+			irq_work_run();
+			__irq_exit();
+		} else {
+			pr_warn_ratelimited("APEI work queued but not completed");
+			err = -EINPROGRESS;
+		}
+	}
+
 	local_daif_restore(current_flags);
 
 	return err;
--- linux-ein-5.4.0.orig/arch/arm64/kernel/alternative.c
+++ linux-ein-5.4.0/arch/arm64/kernel/alternative.c
@@ -41,27 +41,15 @@
 /*
  * Check if the target PC is within an alternative block.
  */
-static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
+static __always_inline bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
 {
-	unsigned long replptr;
-
-	if (kernel_text_address(pc))
-		return true;
-
-	replptr = (unsigned long)ALT_REPL_PTR(alt);
-	if (pc >= replptr && pc <= (replptr + alt->alt_len))
-		return false;
-
-	/*
-	 * Branching into *another* alternate sequence is doomed, and
-	 * we're not even trying to fix it up.
-	 */
-	BUG();
+	unsigned long replptr = (unsigned long)ALT_REPL_PTR(alt);
+	return !(pc >= replptr && pc <= (replptr + alt->alt_len));
 }
 
 #define align_down(x, a)	((unsigned long)(x) & ~(((unsigned long)(a)) - 1))
 
-static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnptr)
+static __always_inline u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnptr)
 {
 	u32 insn;
 
@@ -106,7 +94,7 @@
 	return insn;
 }
 
-static void patch_alternative(struct alt_instr *alt,
+static noinstr void patch_alternative(struct alt_instr *alt,
 			      __le32 *origptr, __le32 *updptr, int nr_inst)
 {
 	__le32 *replptr;
--- linux-ein-5.4.0.orig/arch/arm64/kernel/armv8_deprecated.c
+++ linux-ein-5.4.0/arch/arm64/kernel/armv8_deprecated.c
@@ -59,6 +59,7 @@
 static LIST_HEAD(insn_emulation);
 static int nr_insn_emulated __initdata;
 static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
+static DEFINE_MUTEX(insn_emulation_mutex);
 
 static void register_emulation_hooks(struct insn_emulation_ops *ops)
 {
@@ -207,10 +208,12 @@
 				  loff_t *ppos)
 {
 	int ret = 0;
-	struct insn_emulation *insn = (struct insn_emulation *) table->data;
-	enum insn_emulation_mode prev_mode = insn->current_mode;
+	struct insn_emulation *insn;
+	enum insn_emulation_mode prev_mode;
 
-	table->data = &insn->current_mode;
+	mutex_lock(&insn_emulation_mutex);
+	insn = container_of(table->data, struct insn_emulation, current_mode);
+	prev_mode = insn->current_mode;
 	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 
 	if (ret || !write || prev_mode == insn->current_mode)
@@ -223,7 +226,7 @@
 		update_insn_emulation_mode(insn, INSN_UNDEF);
 	}
 ret:
-	table->data = insn;
+	mutex_unlock(&insn_emulation_mutex);
 	return ret;
 }
 
@@ -247,7 +250,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;
@@ -601,7 +604,7 @@
 	},
 	{
 		/* Thumb mode */
-		.instr_mask	= 0x0000fff7,
+		.instr_mask	= 0xfffffff7,
 		.instr_val	= 0x0000b650,
 		.pstate_mask	= (PSR_AA32_T_BIT | PSR_AA32_MODE_MASK),
 		.pstate_val	= (PSR_AA32_T_BIT | PSR_AA32_MODE_USR),
--- linux-ein-5.4.0.orig/arch/arm64/kernel/cacheinfo.c
+++ linux-ein-5.4.0/arch/arm64/kernel/cacheinfo.c
@@ -43,9 +43,10 @@
 	this_leaf->type = type;
 }
 
-static int __init_cache_level(unsigned int cpu)
+int init_cache_level(unsigned int cpu)
 {
-	unsigned int ctype, level, leaves, fw_level;
+	unsigned int ctype, level, leaves;
+	int fw_level;
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
 	for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
@@ -63,6 +64,9 @@
 	else
 		fw_level = acpi_find_last_cache_level(cpu);
 
+	if (fw_level < 0)
+		return fw_level;
+
 	if (level < fw_level) {
 		/*
 		 * some external caches not specified in CLIDR_EL1
@@ -78,7 +82,7 @@
 	return 0;
 }
 
-static int __populate_cache_leaves(unsigned int cpu)
+int populate_cache_leaves(unsigned int cpu)
 {
 	unsigned int level, idx;
 	enum cache_type type;
@@ -97,6 +101,3 @@
 	}
 	return 0;
 }
-
-DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
-DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/cpu_errata.c
+++ linux-ein-5.4.0/arch/arm64/kernel/cpu_errata.c
@@ -13,6 +13,7 @@
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
 #include <asm/smp_plat.h>
+#include <asm/vectors.h>
 
 static bool __maybe_unused
 is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
@@ -88,13 +89,21 @@
 }
 
 static void
-cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused)
+cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
 {
 	u64 mask = arm64_ftr_reg_ctrel0.strict_mask;
+	bool enable_uct_trap = false;
 
 	/* Trap CTR_EL0 access on this CPU, only if it has a mismatch */
 	if ((read_cpuid_cachetype() & mask) !=
 	    (arm64_ftr_reg_ctrel0.sys_val & mask))
+		enable_uct_trap = true;
+
+	/* ... or if the system is affected by an erratum */
+	if (cap->capability == ARM64_WORKAROUND_1542419)
+		enable_uct_trap = true;
+
+	if (enable_uct_trap)
 		sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
 }
 
@@ -108,6 +117,16 @@
 #ifdef CONFIG_KVM_INDIRECT_VECTORS
 extern char __smccc_workaround_1_smc_start[];
 extern char __smccc_workaround_1_smc_end[];
+extern char __smccc_workaround_3_smc_start[];
+extern char __smccc_workaround_3_smc_end[];
+extern char __spectre_bhb_loop_k8_start[];
+extern char __spectre_bhb_loop_k8_end[];
+extern char __spectre_bhb_loop_k24_start[];
+extern char __spectre_bhb_loop_k24_end[];
+extern char __spectre_bhb_loop_k32_start[];
+extern char __spectre_bhb_loop_k32_end[];
+extern char __spectre_bhb_clearbhb_start[];
+extern char __spectre_bhb_clearbhb_end[];
 
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
 				const char *hyp_vecs_end)
@@ -121,11 +140,11 @@
 	__flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
 }
 
+static DEFINE_RAW_SPINLOCK(bp_lock);
 static void install_bp_hardening_cb(bp_hardening_cb_t fn,
 				    const char *hyp_vecs_start,
 				    const char *hyp_vecs_end)
 {
-	static DEFINE_RAW_SPINLOCK(bp_lock);
 	int cpu, slot = -1;
 
 	/*
@@ -151,8 +170,12 @@
 		__copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
 	}
 
-	__this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
-	__this_cpu_write(bp_hardening_data.fn, fn);
+	if (fn != __this_cpu_read(bp_hardening_data.fn)) {
+		__this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
+		__this_cpu_write(bp_hardening_data.fn, fn);
+		__this_cpu_write(bp_hardening_data.template_start,
+				 hyp_vecs_start);
+	}
 	raw_spin_unlock(&bp_lock);
 }
 #else
@@ -484,6 +507,12 @@
 	return required;
 }
 
+static void cpu_enable_ssbd_mitigation(const struct arm64_cpu_capabilities *cap)
+{
+	if (ssbd_state != ARM64_SSBD_FORCE_DISABLE)
+		cap->matches(cap, SCOPE_LOCAL_CPU);
+}
+
 /* known invulnerable cores */
 static const struct midr_range arm64_ssb_cpus[] = {
 	MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
@@ -575,6 +604,7 @@
 	MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
 	MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
 	MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
+	MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
 	{ /* sentinel */ }
 };
 
@@ -626,6 +656,12 @@
 	return (need_wa > 0);
 }
 
+static void
+cpu_enable_branch_predictor_hardening(const struct arm64_cpu_capabilities *cap)
+{
+	cap->matches(cap, SCOPE_LOCAL_CPU);
+}
+
 static const __maybe_unused struct midr_range tx2_family_cpus[] = {
 	MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
 	MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
@@ -650,6 +686,18 @@
 	return false;
 }
 
+static bool __maybe_unused
+has_neoverse_n1_erratum_1542419(const struct arm64_cpu_capabilities *entry,
+				int scope)
+{
+	u32 midr = read_cpuid_id();
+	bool has_dic = read_cpuid_cachetype() & BIT(CTR_DIC_SHIFT);
+	const struct midr_range range = MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1);
+
+	WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+	return is_midr_in_range(midr, &range) && has_dic;
+}
+
 #ifdef CONFIG_HARDEN_EL2_VECTORS
 
 static const struct midr_range arm64_harden_el2_vectors[] = {
@@ -772,6 +820,14 @@
 };
 #endif
 
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+static struct midr_range broken_aarch32_aes[] = {
+	MIDR_RANGE(MIDR_CORTEX_A57, 0, 1, 0xf, 0xf),
+	MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+	{},
+};
+#endif
+
 const struct arm64_cpu_capabilities arm64_errata[] = {
 #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
 	{
@@ -873,9 +929,11 @@
 	},
 #endif
 	{
+		.desc = "Branch predictor hardening",
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
 		.matches = check_branch_predictor,
+		.cpu_enable = cpu_enable_branch_predictor_hardening,
 	},
 #ifdef CONFIG_HARDEN_EL2_VECTORS
 	{
@@ -889,13 +947,27 @@
 		.capability = ARM64_SSBD,
 		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
 		.matches = has_ssbd_mitigation,
+		.cpu_enable = cpu_enable_ssbd_mitigation,
 		.midr_range_list = arm64_ssb_cpus,
 	},
+	{
+		.desc = "Spectre-BHB",
+		.capability = ARM64_SPECTRE_BHB,
+		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+		.matches = is_spectre_bhb_affected,
+		.cpu_enable = spectre_bhb_enable_mitigation,
+	},
 #ifdef CONFIG_ARM64_ERRATUM_1418040
 	{
 		.desc = "ARM erratum 1418040",
 		.capability = ARM64_WORKAROUND_1418040,
 		ERRATA_MIDR_RANGE_LIST(erratum_1418040_list),
+		/*
+		 * We need to allow affected CPUs to come in late, but
+		 * also need the non-affected CPUs to be able to come
+		 * in at any point in time. Wonderful.
+		 */
+		.type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_1165522
@@ -927,6 +999,24 @@
 		ERRATA_MIDR_RANGE_LIST(tx2_family_cpus),
 	},
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_1542419
+	{
+		/* we depend on the firmware portion for correctness */
+		.desc = "ARM erratum 1542419 (kernel portion)",
+		.capability = ARM64_WORKAROUND_1542419,
+		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+		.matches = has_neoverse_n1_erratum_1542419,
+		.cpu_enable = cpu_enable_trap_ctr_access,
+	},
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+	{
+		.desc = "ARM erratum 1742098",
+		.capability = ARM64_WORKAROUND_1742098,
+		CAP_MIDR_RANGE_LIST(broken_aarch32_aes),
+		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+	},
+#endif
 	{
 	}
 };
@@ -937,15 +1027,41 @@
 	return sprintf(buf, "Mitigation: __user pointer sanitization\n");
 }
 
+static const char *get_bhb_affected_string(enum mitigation_state bhb_state)
+{
+	switch (bhb_state) {
+	case SPECTRE_UNAFFECTED:
+		return "";
+	default:
+	case SPECTRE_VULNERABLE:
+		return ", but not BHB";
+	case SPECTRE_MITIGATED:
+		return ", BHB";
+	}
+}
+
 ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
+	enum mitigation_state bhb_state = arm64_get_spectre_bhb_state();
+	const char *bhb_str = get_bhb_affected_string(bhb_state);
+	const char *v2_str = "Branch predictor hardening";
+
 	switch (get_spectre_v2_workaround_state()) {
 	case ARM64_BP_HARDEN_NOT_REQUIRED:
-		return sprintf(buf, "Not affected\n");
-        case ARM64_BP_HARDEN_WA_NEEDED:
-		return sprintf(buf, "Mitigation: Branch predictor hardening\n");
-        case ARM64_BP_HARDEN_UNKNOWN:
+		if (bhb_state == SPECTRE_UNAFFECTED)
+			return sprintf(buf, "Not affected\n");
+
+		/*
+		 * Platforms affected by Spectre-BHB can't report
+		 * "Not affected" for Spectre-v2.
+		 */
+		v2_str = "CSV2";
+		fallthrough;
+	case ARM64_BP_HARDEN_WA_NEEDED:
+		return sprintf(buf, "Mitigation: %s%s\n", v2_str, bhb_str);
+	case ARM64_BP_HARDEN_UNKNOWN:
+		fallthrough;
 	default:
 		return sprintf(buf, "Vulnerable\n");
 	}
@@ -967,3 +1083,348 @@
 
 	return sprintf(buf, "Vulnerable\n");
 }
+
+/*
+ * We try to ensure that the mitigation state can never change as the result of
+ * onlining a late CPU.
+ */
+static void update_mitigation_state(enum mitigation_state *oldp,
+				    enum mitigation_state new)
+{
+	enum mitigation_state state;
+
+	do {
+		state = READ_ONCE(*oldp);
+		if (new <= state)
+			break;
+	} while (cmpxchg_relaxed(oldp, state, new) != state);
+}
+
+/*
+ * Spectre BHB.
+ *
+ * A CPU is either:
+ * - Mitigated by a branchy loop a CPU specific number of times, and listed
+ *   in our "loop mitigated list".
+ * - Mitigated in software by the firmware Spectre v2 call.
+ * - Has the ClearBHB instruction to perform the mitigation.
+ * - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
+ *   software mitigation in the vectors is needed.
+ * - Has CSV2.3, so is unaffected.
+ */
+static enum mitigation_state spectre_bhb_state;
+
+enum mitigation_state arm64_get_spectre_bhb_state(void)
+{
+	return spectre_bhb_state;
+}
+
+/*
+ * This must be called with SCOPE_LOCAL_CPU for each type of CPU, before any
+ * SCOPE_SYSTEM call will give the right answer.
+ */
+u8 spectre_bhb_loop_affected(int scope)
+{
+	u8 k = 0;
+	static u8 max_bhb_k;
+
+	if (scope == SCOPE_LOCAL_CPU) {
+		static const struct midr_range spectre_bhb_k32_list[] = {
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
+			MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+			MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
+			{},
+		};
+		static const struct midr_range spectre_bhb_k24_list[] = {
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
+			MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
+			{},
+		};
+		static const struct midr_range spectre_bhb_k11_list[] = {
+			MIDR_ALL_VERSIONS(MIDR_AMPERE1),
+			{},
+		};
+		static const struct midr_range spectre_bhb_k8_list[] = {
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+			MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+			{},
+		};
+
+		if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list))
+			k = 32;
+		else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list))
+			k = 24;
+		else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k11_list))
+			k = 11;
+		else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list))
+			k =  8;
+
+		max_bhb_k = max(max_bhb_k, k);
+	} else {
+		k = max_bhb_k;
+	}
+
+	return k;
+}
+
+static enum mitigation_state spectre_bhb_get_cpu_fw_mitigation_state(void)
+{
+	int ret;
+	struct arm_smccc_res res;
+
+	if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
+		return SPECTRE_VULNERABLE;
+
+	switch (psci_ops.conduit) {
+	case PSCI_CONDUIT_HVC:
+		arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+				  ARM_SMCCC_ARCH_WORKAROUND_3, &res);
+		break;
+
+	case PSCI_CONDUIT_SMC:
+		arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+				  ARM_SMCCC_ARCH_WORKAROUND_3, &res);
+		break;
+
+	default:
+		return SPECTRE_VULNERABLE;
+	}
+
+	ret = res.a0;
+	switch (ret) {
+	case SMCCC_RET_SUCCESS:
+		return SPECTRE_MITIGATED;
+	case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+		return SPECTRE_UNAFFECTED;
+	default:
+		fallthrough;
+	case SMCCC_RET_NOT_SUPPORTED:
+		return SPECTRE_VULNERABLE;
+	}
+}
+
+static bool is_spectre_bhb_fw_affected(int scope)
+{
+	static bool system_affected;
+	enum mitigation_state fw_state;
+	bool has_smccc = (psci_ops.smccc_version >= SMCCC_VERSION_1_1);
+	static const struct midr_range spectre_bhb_firmware_mitigated_list[] = {
+		MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+		MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+		{},
+	};
+	bool cpu_in_list = is_midr_in_range_list(read_cpuid_id(),
+					 spectre_bhb_firmware_mitigated_list);
+
+	if (scope != SCOPE_LOCAL_CPU)
+		return system_affected;
+
+	fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+	if (cpu_in_list || (has_smccc && fw_state == SPECTRE_MITIGATED)) {
+		system_affected = true;
+		return true;
+	}
+
+	return false;
+}
+
+static bool supports_ecbhb(int scope)
+{
+	u64 mmfr1;
+
+	if (scope == SCOPE_LOCAL_CPU)
+		mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
+	else
+		mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+
+	return cpuid_feature_extract_unsigned_field(mmfr1,
+						    ID_AA64MMFR1_ECBHB_SHIFT);
+}
+
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
+			     int scope)
+{
+	WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+
+	if (supports_csv2p3(scope))
+		return false;
+
+	if (supports_clearbhb(scope))
+		return true;
+
+	if (spectre_bhb_loop_affected(scope))
+		return true;
+
+	if (is_spectre_bhb_fw_affected(scope))
+		return true;
+
+	return false;
+}
+
+static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
+{
+	const char *v = arm64_get_bp_hardening_vector(slot);
+
+	if (slot < 0)
+		return;
+
+	__this_cpu_write(this_cpu_vector, v);
+
+	/*
+	 * When KPTI is in use, the vectors are switched when exiting to
+	 * user-space.
+	 */
+	if (arm64_kernel_unmapped_at_el0())
+		return;
+
+	write_sysreg(v, vbar_el1);
+	isb();
+}
+
+#ifdef CONFIG_KVM_INDIRECT_VECTORS
+static const char *kvm_bhb_get_vecs_end(const char *start)
+{
+	if (start == __smccc_workaround_3_smc_start)
+		return __smccc_workaround_3_smc_end;
+	else if (start == __spectre_bhb_loop_k8_start)
+		return __spectre_bhb_loop_k8_end;
+	else if (start == __spectre_bhb_loop_k24_start)
+		return __spectre_bhb_loop_k24_end;
+	else if (start == __spectre_bhb_loop_k32_start)
+		return __spectre_bhb_loop_k32_end;
+	else if (start == __spectre_bhb_clearbhb_start)
+		return __spectre_bhb_clearbhb_end;
+
+	return NULL;
+}
+
+static void kvm_setup_bhb_slot(const char *hyp_vecs_start)
+{
+	int cpu, slot = -1;
+	const char *hyp_vecs_end;
+
+	if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
+		return;
+
+	hyp_vecs_end = kvm_bhb_get_vecs_end(hyp_vecs_start);
+	if (WARN_ON_ONCE(!hyp_vecs_start || !hyp_vecs_end))
+		return;
+
+	raw_spin_lock(&bp_lock);
+	for_each_possible_cpu(cpu) {
+		if (per_cpu(bp_hardening_data.template_start, cpu) == hyp_vecs_start) {
+			slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
+			break;
+		}
+	}
+
+	if (slot == -1) {
+		slot = atomic_inc_return(&arm64_el2_vector_last_slot);
+		BUG_ON(slot >= BP_HARDEN_EL2_SLOTS);
+		__copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
+	}
+
+	if (hyp_vecs_start != __this_cpu_read(bp_hardening_data.template_start)) {
+		__this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
+		__this_cpu_write(bp_hardening_data.template_start,
+				 hyp_vecs_start);
+	}
+	raw_spin_unlock(&bp_lock);
+}
+#else
+#define __smccc_workaround_3_smc_start NULL
+#define __spectre_bhb_loop_k8_start NULL
+#define __spectre_bhb_loop_k24_start NULL
+#define __spectre_bhb_loop_k32_start NULL
+#define __spectre_bhb_clearbhb_start NULL
+
+static void kvm_setup_bhb_slot(const char *hyp_vecs_start) { }
+#endif
+
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
+{
+	enum mitigation_state fw_state, state = SPECTRE_VULNERABLE;
+
+	if (!is_spectre_bhb_affected(entry, SCOPE_LOCAL_CPU))
+		return;
+
+	if (get_spectre_v2_workaround_state() == ARM64_BP_HARDEN_UNKNOWN) {
+		/* No point mitigating Spectre-BHB alone. */
+	} else if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY)) {
+		pr_info_once("spectre-bhb mitigation disabled by compile time option\n");
+	} else if (cpu_mitigations_off()) {
+		pr_info_once("spectre-bhb mitigation disabled by command line option\n");
+	} else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
+		state = SPECTRE_MITIGATED;
+	} else if (supports_clearbhb(SCOPE_LOCAL_CPU)) {
+		kvm_setup_bhb_slot(__spectre_bhb_clearbhb_start);
+		this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN);
+
+		state = SPECTRE_MITIGATED;
+	} else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
+		switch (spectre_bhb_loop_affected(SCOPE_SYSTEM)) {
+		case 8:
+			/*
+			 * A57/A72-r0 will already have selected the
+			 * spectre-indirect vector, which is sufficient
+			 * for BHB too.
+			 */
+			if (!__this_cpu_read(bp_hardening_data.fn))
+				kvm_setup_bhb_slot(__spectre_bhb_loop_k8_start);
+			break;
+		case 24:
+			kvm_setup_bhb_slot(__spectre_bhb_loop_k24_start);
+			break;
+		case 32:
+			kvm_setup_bhb_slot(__spectre_bhb_loop_k32_start);
+			break;
+		default:
+			WARN_ON_ONCE(1);
+		}
+		this_cpu_set_vectors(EL1_VECTOR_BHB_LOOP);
+
+		state = SPECTRE_MITIGATED;
+	} else if (is_spectre_bhb_fw_affected(SCOPE_LOCAL_CPU)) {
+		fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+		if (fw_state == SPECTRE_MITIGATED) {
+			kvm_setup_bhb_slot(__smccc_workaround_3_smc_start);
+			this_cpu_set_vectors(EL1_VECTOR_BHB_FW);
+
+			/*
+			 * With WA3 in the vectors, the WA1 calls can be
+			 * removed.
+			 */
+			__this_cpu_write(bp_hardening_data.fn, NULL);
+
+			state = SPECTRE_MITIGATED;
+		}
+	}
+
+	update_mitigation_state(&spectre_bhb_state, state);
+}
+
+/* Patched to correct the immediate */
+void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt,
+				   __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+	u8 rd;
+	u32 insn;
+	u16 loop_count = spectre_bhb_loop_affected(SCOPE_SYSTEM);
+
+	BUG_ON(nr_inst != 1); /* MOV -> MOV */
+
+	if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY))
+		return;
+
+	insn = le32_to_cpu(*origptr);
+	rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
+	insn = aarch64_insn_gen_movewide(rd, loop_count, 0,
+					 AARCH64_INSN_VARIANT_64BIT,
+					 AARCH64_INSN_MOVEWIDE_ZERO);
+	*updptr++ = cpu_to_le32(insn);
+}
--- linux-ein-5.4.0.orig/arch/arm64/kernel/cpufeature.c
+++ linux-ein-5.4.0/arch/arm64/kernel/cpufeature.c
@@ -10,19 +10,23 @@
 #include <linux/bsearch.h>
 #include <linux/cpumask.h>
 #include <linux/crash_dump.h>
+#include <linux/percpu.h>
 #include <linux/sort.h>
 #include <linux/stop_machine.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/cpu.h>
+
 #include <asm/cpu.h>
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/fpsimd.h>
+#include <asm/hwcap.h>
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
+#include <asm/vectors.h>
 #include <asm/virt.h>
 
 /* Kernel representation of AT_HWCAP and AT_HWCAP2 */
@@ -32,9 +36,7 @@
 #define COMPAT_ELF_HWCAP_DEFAULT	\
 				(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
 				 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
-				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
-				 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
-				 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\
+				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_IDIV|\
 				 COMPAT_HWCAP_LPAE)
 unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
 unsigned int compat_elf_hwcap2 __read_mostly;
@@ -47,6 +49,8 @@
 /* Need also bit for ARM64_CB_PATCH */
 DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
 
+DEFINE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector) = vectors;
+
 /*
  * Flag to indicate if we have computed the system wide
  * capabilities based on the boot time active CPUs. This
@@ -152,6 +156,11 @@
 	ARM64_FTR_END,
 };
 
+static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
+	ARM64_FTR_END,
+};
+
 static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
@@ -162,11 +171,10 @@
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_GIC_SHIFT, 4, 0),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
-	/* Linux doesn't care about the EL3 */
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL3_SHIFT, 4, 0),
-	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL2_SHIFT, 4, 0),
-	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
-	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL2_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
 	ARM64_FTR_END,
 };
 
@@ -280,7 +288,6 @@
 	 * of support.
 	 */
 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
-	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
 	ARM64_FTR_END,
 };
@@ -322,7 +329,7 @@
 };
 
 static const struct arm64_ftr_bits ftr_id_dfr0[] = {
-	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
+	/* [31:28] TraceFilt */
 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf),	/* PerfMon */
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
@@ -414,6 +421,7 @@
 	/* Op1 = 0, CRn = 0, CRm = 6 */
 	ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0),
 	ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1),
+	ARM64_FTR_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2),
 
 	/* Op1 = 0, CRn = 0, CRm = 7 */
 	ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0),
@@ -585,6 +593,7 @@
 	init_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1);
 	init_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0);
 	init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1);
+	init_cpu_ftr_reg(SYS_ID_AA64ISAR2_EL1, info->reg_id_aa64isar2);
 	init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0);
 	init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1);
 	init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
@@ -708,6 +717,8 @@
 				      info->reg_id_aa64isar0, boot->reg_id_aa64isar0);
 	taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu,
 				      info->reg_id_aa64isar1, boot->reg_id_aa64isar1);
+	taint |= check_update_ftr_reg(SYS_ID_AA64ISAR2_EL1, cpu,
+				      info->reg_id_aa64isar2, boot->reg_id_aa64isar2);
 
 	/*
 	 * Differing PARange support is fine as long as all peripherals and
@@ -721,9 +732,6 @@
 	taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu,
 				      info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2);
 
-	/*
-	 * EL3 is not our concern.
-	 */
 	taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu,
 				      info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0);
 	taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu,
@@ -845,6 +853,7 @@
 	read_sysreg_case(SYS_ID_AA64MMFR2_EL1);
 	read_sysreg_case(SYS_ID_AA64ISAR0_EL1);
 	read_sysreg_case(SYS_ID_AA64ISAR1_EL1);
+	read_sysreg_case(SYS_ID_AA64ISAR2_EL1);
 
 	read_sysreg_case(SYS_CNTFRQ_EL0);
 	read_sysreg_case(SYS_CTR_EL0);
@@ -1045,6 +1054,12 @@
 	static bool kpti_applied = false;
 	int cpu = smp_processor_id();
 
+	if (__this_cpu_read(this_cpu_vector) == vectors) {
+		const char *v = arm64_get_bp_hardening_vector(EL1_VECTOR_KPTI);
+
+		__this_cpu_write(this_cpu_vector, v);
+	}
+
 	/*
 	 * We don't need to rewrite the page-tables if either we've done
 	 * it already or we have KASLR enabled and therefore have not
@@ -1098,7 +1113,7 @@
 	/* List of CPUs which have broken DBM support. */
 	static const struct midr_range cpus[] = {
 #ifdef CONFIG_ARM64_ERRATUM_1024718
-		MIDR_RANGE(MIDR_CORTEX_A55, 0, 0, 1, 0),  // A55 r0p0 -r1p0
+		MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
 #endif
 		{},
 	};
@@ -1266,6 +1281,14 @@
 }
 #endif
 
+static void elf_hwcap_fixup(void)
+{
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+	if (cpus_have_const_cap(ARM64_WORKAROUND_1742098))
+		compat_elf_hwcap2 &= ~COMPAT_HWCAP2_AES;
+#endif /* ARM64_ERRATUM_1742098 */
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
 	{
 		.desc = "GIC system register CPU interface",
@@ -1367,7 +1390,7 @@
 	{
 		/* FP/SIMD is not implemented */
 		.capability = ARM64_HAS_NO_FPSIMD,
-		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE,
 		.min_field_value = 0,
 		.matches = has_no_fpsimd,
 	},
@@ -1595,6 +1618,12 @@
 		.match_list = list,						\
 	}
 
+#define HWCAP_CAP_MATCH(match, cap_type, cap)					\
+	{									\
+		__HWCAP_CAP(#cap, cap_type, cap)				\
+		.matches = match,						\
+	}
+
 #ifdef CONFIG_ARM64_PTR_AUTH
 static const struct arm64_cpu_capabilities ptr_auth_hwcap_addr_matches[] = {
 	{
@@ -1668,8 +1697,35 @@
 	{},
 };
 
+#ifdef CONFIG_COMPAT
+static bool compat_has_neon(const struct arm64_cpu_capabilities *cap, int scope)
+{
+	/*
+	 * Check that all of MVFR1_EL1.{SIMDSP, SIMDInt, SIMDLS} are available,
+	 * in line with that of arm32 as in vfp_init(). We make sure that the
+	 * check is future proof, by making sure value is non-zero.
+	 */
+	u32 mvfr1;
+
+	WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible());
+	if (scope == SCOPE_SYSTEM)
+		mvfr1 = read_sanitised_ftr_reg(SYS_MVFR1_EL1);
+	else
+		mvfr1 = read_sysreg_s(SYS_MVFR1_EL1);
+
+	return cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDSP_SHIFT) &&
+		cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDINT_SHIFT) &&
+		cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDLS_SHIFT);
+}
+#endif
+
 static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = {
 #ifdef CONFIG_COMPAT
+	HWCAP_CAP_MATCH(compat_has_neon, CAP_COMPAT_HWCAP, COMPAT_HWCAP_NEON),
+	HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_SIMDFMAC_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv4),
+	/* Arm v8 mandates MVFR0.FPDP == {0, 2}. So, piggy back on this for the presence of VFP support */
+	HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFP),
+	HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv3),
 	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),
@@ -2056,8 +2112,10 @@
 	mark_const_caps_ready();
 	setup_elf_hwcaps(arm64_elf_hwcaps);
 
-	if (system_supports_32bit_el0())
+	if (system_supports_32bit_el0()) {
 		setup_elf_hwcaps(compat_elf_hwcaps);
+		elf_hwcap_fixup();
+	}
 
 	if (system_uses_ttbr0_pan())
 		pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
--- linux-ein-5.4.0.orig/arch/arm64/kernel/cpuidle.c
+++ linux-ein-5.4.0/arch/arm64/kernel/cpuidle.c
@@ -53,6 +53,9 @@
 	struct acpi_lpi_state *lpi;
 	struct acpi_processor *pr = per_cpu(processors, cpu);
 
+	if (unlikely(!pr || !pr->flags.has_lpi))
+		return -EINVAL;
+
 	/*
 	 * If the PSCI cpu_suspend function hook has not been initialized
 	 * idle states must not be enabled, so bail out
@@ -60,9 +63,6 @@
 	if (!psci_ops.cpu_suspend)
 		return -EOPNOTSUPP;
 
-	if (unlikely(!pr || !pr->flags.has_lpi))
-		return -EINVAL;
-
 	count = pr->power.count - 1;
 	if (count <= 0)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/arch/arm64/kernel/cpuinfo.c
+++ linux-ein-5.4.0/arch/arm64/kernel/cpuinfo.c
@@ -344,6 +344,7 @@
 	info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
 	info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
 	info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
+	info->reg_id_aa64isar2 = read_cpuid(ID_AA64ISAR2_EL1);
 	info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
 	info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
 	info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/crash_core.c
+++ linux-ein-5.4.0/arch/arm64/kernel/crash_core.c
@@ -6,6 +6,14 @@
 
 #include <linux/crash_core.h>
 #include <asm/memory.h>
+#include <asm/pgtable-hwdef.h>
+
+static inline u64 get_tcr_el1_t1sz(void);
+
+static inline u64 get_tcr_el1_t1sz(void)
+{
+	return (read_sysreg(tcr_el1) & TCR_T1SZ_MASK) >> TCR_T1SZ_OFFSET;
+}
 
 void arch_crash_save_vmcoreinfo(void)
 {
@@ -15,5 +23,7 @@
 						kimage_voffset);
 	vmcoreinfo_append_str("NUMBER(PHYS_OFFSET)=0x%llx\n",
 						PHYS_OFFSET);
+	vmcoreinfo_append_str("NUMBER(TCR_EL1_T1SZ)=0x%llx\n",
+						get_tcr_el1_t1sz());
 	vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/crash_dump.c
+++ linux-ein-5.4.0/arch/arm64/kernel/crash_dump.c
@@ -64,5 +64,7 @@
 ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
 {
 	memcpy(buf, phys_to_virt((phys_addr_t)*ppos), count);
+	*ppos += count;
+
 	return count;
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/debug-monitors.c
+++ linux-ein-5.4.0/arch/arm64/kernel/debug-monitors.c
@@ -141,17 +141,20 @@
 /*
  * Single step API and exception handling.
  */
-static void set_regs_spsr_ss(struct pt_regs *regs)
+static void set_user_regs_spsr_ss(struct user_pt_regs *regs)
 {
 	regs->pstate |= DBG_SPSR_SS;
 }
-NOKPROBE_SYMBOL(set_regs_spsr_ss);
+NOKPROBE_SYMBOL(set_user_regs_spsr_ss);
 
-static void clear_regs_spsr_ss(struct pt_regs *regs)
+static void clear_user_regs_spsr_ss(struct user_pt_regs *regs)
 {
 	regs->pstate &= ~DBG_SPSR_SS;
 }
-NOKPROBE_SYMBOL(clear_regs_spsr_ss);
+NOKPROBE_SYMBOL(clear_user_regs_spsr_ss);
+
+#define set_regs_spsr_ss(r)	set_user_regs_spsr_ss(&(r)->user_regs)
+#define clear_regs_spsr_ss(r)	clear_user_regs_spsr_ss(&(r)->user_regs)
 
 static DEFINE_SPINLOCK(debug_hook_lock);
 static LIST_HEAD(user_step_hook);
@@ -393,17 +396,26 @@
 	 * 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));
 }
 NOKPROBE_SYMBOL(user_rewind_single_step);
 
 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));
 }
 
+void user_regs_reset_single_step(struct user_pt_regs *regs,
+				 struct task_struct *task)
+{
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
+		set_user_regs_spsr_ss(regs);
+	else
+		clear_user_regs_spsr_ss(regs);
+}
+
 /* Kernel API */
 void kernel_enable_single_step(struct pt_regs *regs)
 {
@@ -429,6 +441,11 @@
 }
 NOKPROBE_SYMBOL(kernel_active_single_step);
 
+void kernel_rewind_single_step(struct pt_regs *regs)
+{
+	set_regs_spsr_ss(regs);
+}
+
 /* ptrace API */
 void user_enable_single_step(struct task_struct *task)
 {
--- linux-ein-5.4.0.orig/arch/arm64/kernel/efi.c
+++ linux-ein-5.4.0/arch/arm64/kernel/efi.c
@@ -12,6 +12,14 @@
 
 #include <asm/efi.h>
 
+static bool region_is_misaligned(const efi_memory_desc_t *md)
+{
+	if (PAGE_SIZE == EFI_PAGE_SIZE)
+		return false;
+	return !PAGE_ALIGNED(md->phys_addr) ||
+	       !PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT);
+}
+
 /*
  * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
  * executable, everything else can be mapped with the XN bits
@@ -25,14 +33,22 @@
 	if (type == EFI_MEMORY_MAPPED_IO)
 		return PROT_DEVICE_nGnRE;
 
-	if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr),
-		      "UEFI Runtime regions are not aligned to 64 KB -- buggy firmware?"))
+	if (region_is_misaligned(md)) {
+		static bool __initdata code_is_misaligned;
+
 		/*
-		 * If the region is not aligned to the page size of the OS, we
-		 * can not use strict permissions, since that would also affect
-		 * the mapping attributes of the adjacent regions.
+		 * Regions that are not aligned to the OS page size cannot be
+		 * mapped with strict permissions, as those might interfere
+		 * with the permissions that are needed by the adjacent
+		 * region's mapping. However, if we haven't encountered any
+		 * misaligned runtime code regions so far, we can safely use
+		 * non-executable permissions for non-code regions.
 		 */
-		return pgprot_val(PAGE_KERNEL_EXEC);
+		code_is_misaligned |= (type == EFI_RUNTIME_SERVICES_CODE);
+
+		return code_is_misaligned ? pgprot_val(PAGE_KERNEL_EXEC)
+					  : pgprot_val(PAGE_KERNEL);
+	}
 
 	/* R-- */
 	if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
@@ -62,19 +78,16 @@
 	bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE ||
 				   md->type == EFI_RUNTIME_SERVICES_DATA);
 
-	if (!PAGE_ALIGNED(md->phys_addr) ||
-	    !PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT)) {
-		/*
-		 * If the end address of this region is not aligned to page
-		 * size, the mapping is rounded up, and may end up sharing a
-		 * page frame with the next UEFI memory region. If we create
-		 * a block entry now, we may need to split it again when mapping
-		 * the next region, and support for that is going to be removed
-		 * from the MMU routines. So avoid block mappings altogether in
-		 * that case.
-		 */
+	/*
+	 * If this region is not aligned to the page size used by the OS, the
+	 * mapping will be rounded outwards, and may end up sharing a page
+	 * frame with an adjacent runtime memory region. Given that the page
+	 * table descriptor covering the shared page will be rewritten when the
+	 * adjacent region gets mapped, we must avoid block mappings here so we
+	 * don't have to worry about splitting them when that happens.
+	 */
+	if (region_is_misaligned(md))
 		page_mappings_only = true;
-	}
 
 	create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
 			   md->num_pages << EFI_PAGE_SHIFT,
@@ -101,6 +114,9 @@
 	BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
 	       md->type != EFI_RUNTIME_SERVICES_DATA);
 
+	if (region_is_misaligned(md))
+		return 0;
+
 	/*
 	 * Calling apply_to_page_range() is only safe on regions that are
 	 * guaranteed to be mapped down to pages. Since we are only called
--- linux-ein-5.4.0.orig/arch/arm64/kernel/entry.S
+++ linux-ein-5.4.0/arch/arm64/kernel/entry.S
@@ -59,18 +59,21 @@
 
 	.macro kernel_ventry, el, label, regsize = 64
 	.align 7
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-alternative_if ARM64_UNMAP_KERNEL_AT_EL0
+.Lventry_start\@:
 	.if	\el == 0
+	/*
+	 * This must be the first instruction of the EL0 vector entries. It is
+	 * skipped by the trampoline vectors, to trigger the cleanup.
+	 */
+	b	.Lskip_tramp_vectors_cleanup\@
 	.if	\regsize == 64
 	mrs	x30, tpidrro_el0
 	msr	tpidrro_el0, xzr
 	.else
 	mov	x30, xzr
 	.endif
+.Lskip_tramp_vectors_cleanup\@:
 	.endif
-alternative_else_nop_endif
-#endif
 
 	sub	sp, sp, #S_FRAME_SIZE
 #ifdef CONFIG_VMAP_STACK
@@ -116,11 +119,15 @@
 	mrs	x0, tpidrro_el0
 #endif
 	b	el\()\el\()_\label
+.org .Lventry_start\@ + 128	// Did we overflow the ventry slot?
 	.endm
 
-	.macro tramp_alias, dst, sym
+	.macro tramp_alias, dst, sym, tmp
 	mov_q	\dst, TRAMP_VALIAS
-	add	\dst, \dst, #(\sym - .entry.tramp.text)
+	adr_l	\tmp, \sym
+	add	\dst, \dst, \tmp
+	adr_l	\tmp, .entry.tramp.text
+	sub	\dst, \dst, \tmp
 	.endm
 
 	// This macro corrupts x0-x3. It is the caller's duty
@@ -361,21 +368,25 @@
 	ldp	x24, x25, [sp, #16 * 12]
 	ldp	x26, x27, [sp, #16 * 13]
 	ldp	x28, x29, [sp, #16 * 14]
-	ldr	lr, [sp, #S_LR]
-	add	sp, sp, #S_FRAME_SIZE		// restore sp
 
 	.if	\el == 0
-alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
+alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
+	ldr	lr, [sp, #S_LR]
+	add	sp, sp, #S_FRAME_SIZE		// restore sp
+	eret
+alternative_else_nop_endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 	bne	5f
-	msr	far_el1, x30
-	tramp_alias	x30, tramp_exit_native
+	msr	far_el1, x29
+	tramp_alias	x30, tramp_exit_native, x29
 	br	x30
 5:
-	tramp_alias	x30, tramp_exit_compat
+	tramp_alias	x30, tramp_exit_compat, x29
 	br	x30
 #endif
 	.else
+	ldr	lr, [sp, #S_LR]
+	add	sp, sp, #S_FRAME_SIZE		// restore sp
 	eret
 	.endif
 	sb
@@ -1012,15 +1023,10 @@
 
 	.popsection				// .entry.text
 
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-/*
- * Exception vectors trampoline.
- */
-	.pushsection ".entry.tramp.text", "ax"
-
+	// Move from tramp_pg_dir to swapper_pg_dir
 	.macro tramp_map_kernel, tmp
 	mrs	\tmp, ttbr1_el1
-	add	\tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
+	add	\tmp, \tmp, #(2 * PAGE_SIZE)
 	bic	\tmp, \tmp, #USER_ASID_FLAG
 	msr	ttbr1_el1, \tmp
 #ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
@@ -1037,9 +1043,10 @@
 #endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
 	.endm
 
+	// Move from swapper_pg_dir to tramp_pg_dir
 	.macro tramp_unmap_kernel, tmp
 	mrs	\tmp, ttbr1_el1
-	sub	\tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
+	sub	\tmp, \tmp, #(2 * PAGE_SIZE)
 	orr	\tmp, \tmp, #USER_ASID_FLAG
 	msr	ttbr1_el1, \tmp
 	/*
@@ -1049,12 +1056,47 @@
 	 */
 	.endm
 
-	.macro tramp_ventry, regsize = 64
+	.macro tramp_data_page	dst
+	adr_l	\dst, .entry.tramp.text
+	sub	\dst, \dst, PAGE_SIZE
+	.endm
+
+	.macro tramp_data_read_var	dst, var
+#ifdef CONFIG_RANDOMIZE_BASE
+	tramp_data_page		\dst
+	add	\dst, \dst, #:lo12:__entry_tramp_data_\var
+	ldr	\dst, [\dst]
+#else
+	ldr	\dst, =\var
+#endif
+	.endm
+
+#define BHB_MITIGATION_NONE	0
+#define BHB_MITIGATION_LOOP	1
+#define BHB_MITIGATION_FW	2
+#define BHB_MITIGATION_INSN	3
+
+	.macro tramp_ventry, vector_start, regsize, kpti, bhb
 	.align	7
 1:
 	.if	\regsize == 64
 	msr	tpidrro_el0, x30	// Restored in kernel_ventry
 	.endif
+
+	.if	\bhb == BHB_MITIGATION_LOOP
+	/*
+	 * This sequence must appear before the first indirect branch. i.e. the
+	 * ret out of tramp_ventry. It appears here because x30 is free.
+	 */
+	__mitigate_spectre_bhb_loop	x30
+	.endif // \bhb == BHB_MITIGATION_LOOP
+
+	.if	\bhb == BHB_MITIGATION_INSN
+	clearbhb
+	isb
+	.endif // \bhb == BHB_MITIGATION_INSN
+
+	.if	\kpti == 1
 	/*
 	 * Defend against branch aliasing attacks by pushing a dummy
 	 * entry onto the return stack and using a RET instruction to
@@ -1064,46 +1106,79 @@
 	b	.
 2:
 	tramp_map_kernel	x30
-#ifdef CONFIG_RANDOMIZE_BASE
-	adr	x30, tramp_vectors + PAGE_SIZE
 alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
-	ldr	x30, [x30]
-#else
-	ldr	x30, =vectors
-#endif
+	tramp_data_read_var	x30, vectors
 alternative_if_not ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM
-	prfm	plil1strm, [x30, #(1b - tramp_vectors)]
+	prfm	plil1strm, [x30, #(1b - \vector_start)]
 alternative_else_nop_endif
+
 	msr	vbar_el1, x30
-	add	x30, x30, #(1b - tramp_vectors)
 	isb
+	.else
+	ldr	x30, =vectors
+	.endif // \kpti == 1
+
+	.if	\bhb == BHB_MITIGATION_FW
+	/*
+	 * The firmware sequence must appear before the first indirect branch.
+	 * i.e. the ret out of tramp_ventry. But it also needs the stack to be
+	 * mapped to save/restore the registers the SMC clobbers.
+	 */
+	__mitigate_spectre_bhb_fw
+	.endif // \bhb == BHB_MITIGATION_FW
+
+	add	x30, x30, #(1b - \vector_start + 4)
 	ret
+.org 1b + 128	// Did we overflow the ventry slot?
 	.endm
 
 	.macro tramp_exit, regsize = 64
-	adr	x30, tramp_vectors
+	tramp_data_read_var	x30, this_cpu_vector
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
+	mrs	x29, tpidr_el1
+alternative_else
+	mrs	x29, tpidr_el2
+alternative_endif
+	ldr	x30, [x30, x29]
+
 	msr	vbar_el1, x30
-	tramp_unmap_kernel	x30
+	ldr	lr, [sp, #S_LR]
+	tramp_unmap_kernel	x29
 	.if	\regsize == 64
-	mrs	x30, far_el1
+	mrs	x29, far_el1
 	.endif
+	add	sp, sp, #S_FRAME_SIZE		// restore sp
 	eret
 	sb
 	.endm
 
-	.align	11
-ENTRY(tramp_vectors)
+	.macro	generate_tramp_vector,	kpti, bhb
+.Lvector_start\@:
 	.space	0x400
 
-	tramp_ventry
-	tramp_ventry
-	tramp_ventry
-	tramp_ventry
-
-	tramp_ventry	32
-	tramp_ventry	32
-	tramp_ventry	32
-	tramp_ventry	32
+	.rept	4
+	tramp_ventry	.Lvector_start\@, 64, \kpti, \bhb
+	.endr
+	.rept	4
+	tramp_ventry	.Lvector_start\@, 32, \kpti, \bhb
+	.endr
+	.endm
+
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+/*
+ * Exception vectors trampoline.
+ * The order must match __bp_harden_el1_vectors and the
+ * arm64_bp_harden_el1_vectors enum.
+ */
+	.pushsection ".entry.tramp.text", "ax"
+	.align	11
+ENTRY(tramp_vectors)
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+	generate_tramp_vector	kpti=1, bhb=BHB_MITIGATION_LOOP
+	generate_tramp_vector	kpti=1, bhb=BHB_MITIGATION_FW
+	generate_tramp_vector	kpti=1, bhb=BHB_MITIGATION_INSN
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+	generate_tramp_vector	kpti=1, bhb=BHB_MITIGATION_NONE
 END(tramp_vectors)
 
 ENTRY(tramp_exit_native)
@@ -1121,12 +1196,56 @@
 	.align PAGE_SHIFT
 	.globl	__entry_tramp_data_start
 __entry_tramp_data_start:
+__entry_tramp_data_vectors:
 	.quad	vectors
+#ifdef CONFIG_ARM_SDE_INTERFACE
+__entry_tramp_data___sdei_asm_handler:
+	.quad	__sdei_asm_handler
+#endif /* CONFIG_ARM_SDE_INTERFACE */
+__entry_tramp_data_this_cpu_vector:
+	.quad	this_cpu_vector
 	.popsection				// .rodata
 #endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
 /*
+ * Exception vectors for spectre mitigations on entry from EL1 when
+ * kpti is not in use.
+ */
+	.macro generate_el1_vector, bhb
+.Lvector_start\@:
+	kernel_ventry	1, sync_invalid			// Synchronous EL1t
+	kernel_ventry	1, irq_invalid			// IRQ EL1t
+	kernel_ventry	1, fiq_invalid			// FIQ EL1t
+	kernel_ventry	1, error_invalid		// Error EL1t
+
+	kernel_ventry	1, sync				// Synchronous EL1h
+	kernel_ventry	1, irq				// IRQ EL1h
+	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+	kernel_ventry	1, error			// Error EL1h
+
+	.rept	4
+	tramp_ventry	.Lvector_start\@, 64, 0, \bhb
+	.endr
+	.rept 4
+	tramp_ventry	.Lvector_start\@, 32, 0, \bhb
+	.endr
+	.endm
+
+/* The order must match tramp_vecs and the arm64_bp_harden_el1_vectors enum. */
+	.pushsection ".entry.text", "ax"
+	.align	11
+SYM_CODE_START(__bp_harden_el1_vectors)
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+	generate_el1_vector	bhb=BHB_MITIGATION_LOOP
+	generate_el1_vector	bhb=BHB_MITIGATION_FW
+	generate_el1_vector	bhb=BHB_MITIGATION_INSN
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+SYM_CODE_END(__bp_harden_el1_vectors)
+	.popsection
+
+
+/*
  * Register switch for AArch64. The callee-saved registers need to be saved
  * and restored. On entry:
  *   x0 = previous task_struct (must be preserved across the switch)
@@ -1212,13 +1331,7 @@
 	 */
 1:	str	x4, [x1, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
 
-#ifdef CONFIG_RANDOMIZE_BASE
-	adr	x4, tramp_vectors + PAGE_SIZE
-	add	x4, x4, #:lo12:__sdei_asm_trampoline_next_handler
-	ldr	x4, [x4]
-#else
-	ldr	x4, =__sdei_asm_handler
-#endif
+	tramp_data_read_var     x4, __sdei_asm_handler
 	br	x4
 ENDPROC(__sdei_asm_entry_trampoline)
 NOKPROBE(__sdei_asm_entry_trampoline)
@@ -1241,12 +1354,6 @@
 NOKPROBE(__sdei_asm_exit_trampoline)
 	.ltorg
 .popsection		// .entry.tramp.text
-#ifdef CONFIG_RANDOMIZE_BASE
-.pushsection ".rodata", "a"
-__sdei_asm_trampoline_next_handler:
-	.quad	__sdei_asm_handler
-.popsection		// .rodata
-#endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
 /*
@@ -1342,7 +1449,7 @@
 alternative_else_nop_endif
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-	tramp_alias	dst=x5, sym=__sdei_asm_exit_trampoline
+	tramp_alias	dst=x5, sym=__sdei_asm_exit_trampoline, tmp=x3
 	br	x5
 #endif
 ENDPROC(__sdei_asm_handler)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/fpsimd.c
+++ linux-ein-5.4.0/arch/arm64/kernel/fpsimd.c
@@ -269,6 +269,7 @@
  */
 static void task_fpsimd_load(void)
 {
+	WARN_ON(!system_supports_fpsimd());
 	WARN_ON(!have_cpu_fpsimd_context());
 
 	if (system_supports_sve() && test_thread_flag(TIF_SVE))
@@ -289,6 +290,7 @@
 		this_cpu_ptr(&fpsimd_last_state);
 	/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
 
+	WARN_ON(!system_supports_fpsimd());
 	WARN_ON(!have_cpu_fpsimd_context());
 
 	if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
@@ -336,7 +338,7 @@
 	return sve_vl_from_vq(__bit_to_vq(bit));
 }
 
-#ifdef CONFIG_SYSCTL
+#if defined(CONFIG_ARM64_SVE) && defined(CONFIG_SYSCTL)
 
 static int sve_proc_do_default_vl(struct ctl_table *table, int write,
 				  void __user *buffer, size_t *lenp,
@@ -382,9 +384,9 @@
 	return 0;
 }
 
-#else /* ! CONFIG_SYSCTL */
+#else /* ! (CONFIG_ARM64_SVE && CONFIG_SYSCTL) */
 static int __init sve_sysctl_init(void) { return 0; }
-#endif /* ! CONFIG_SYSCTL */
+#endif /* ! (CONFIG_ARM64_SVE && CONFIG_SYSCTL) */
 
 #define ZREG(sve_state, vq, n) ((char *)(sve_state) +		\
 	(SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET))
@@ -496,7 +498,7 @@
 void sve_alloc(struct task_struct *task)
 {
 	if (task->thread.sve_state) {
-		memset(task->thread.sve_state, 0, sve_state_size(current));
+		memset(task->thread.sve_state, 0, sve_state_size(task));
 		return;
 	}
 
@@ -1092,6 +1094,7 @@
 	struct fpsimd_last_state_struct *last =
 		this_cpu_ptr(&fpsimd_last_state);
 
+	WARN_ON(!system_supports_fpsimd());
 	last->st = &current->thread.uw.fpsimd_state;
 	last->sve_state = current->thread.sve_state;
 	last->sve_vl = current->thread.sve_vl;
@@ -1114,6 +1117,7 @@
 	struct fpsimd_last_state_struct *last =
 		this_cpu_ptr(&fpsimd_last_state);
 
+	WARN_ON(!system_supports_fpsimd());
 	WARN_ON(!in_softirq() && !irqs_disabled());
 
 	last->st = st;
@@ -1128,8 +1132,19 @@
  */
 void fpsimd_restore_current_state(void)
 {
-	if (!system_supports_fpsimd())
+	/*
+	 * For the tasks that were created before we detected the absence of
+	 * FP/SIMD, the TIF_FOREIGN_FPSTATE could be set via fpsimd_thread_switch(),
+	 * e.g, init. This could be then inherited by the children processes.
+	 * If we later detect that the system doesn't support FP/SIMD,
+	 * we must clear the flag for  all the tasks to indicate that the
+	 * FPSTATE is clean (as we can't have one) to avoid looping for ever in
+	 * do_notify_resume().
+	 */
+	if (!system_supports_fpsimd()) {
+		clear_thread_flag(TIF_FOREIGN_FPSTATE);
 		return;
+	}
 
 	get_cpu_fpsimd_context();
 
@@ -1148,7 +1163,7 @@
  */
 void fpsimd_update_current_state(struct user_fpsimd_state const *state)
 {
-	if (!system_supports_fpsimd())
+	if (WARN_ON(!system_supports_fpsimd()))
 		return;
 
 	get_cpu_fpsimd_context();
@@ -1179,7 +1194,13 @@
 void fpsimd_flush_task_state(struct task_struct *t)
 {
 	t->thread.fpsimd_cpu = NR_CPUS;
-
+	/*
+	 * If we don't support fpsimd, bail out after we have
+	 * reset the fpsimd_cpu for this task and clear the
+	 * FPSTATE.
+	 */
+	if (!system_supports_fpsimd())
+		return;
 	barrier();
 	set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE);
 
@@ -1193,6 +1214,7 @@
  */
 static void fpsimd_flush_cpu_state(void)
 {
+	WARN_ON(!system_supports_fpsimd());
 	__this_cpu_write(fpsimd_last_state.st, NULL);
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
 }
@@ -1203,6 +1225,8 @@
  */
 void fpsimd_save_and_flush_cpu_state(void)
 {
+	if (!system_supports_fpsimd())
+		return;
 	WARN_ON(preemptible());
 	__get_cpu_fpsimd_context();
 	fpsimd_save();
--- linux-ein-5.4.0.orig/arch/arm64/kernel/ftrace.c
+++ linux-ein-5.4.0/arch/arm64/kernel/ftrace.c
@@ -69,14 +69,26 @@
 {
 	unsigned long pc = rec->ip;
 	u32 old, new;
-	long offset = (long)pc - (long)addr;
+	long offset = (long)addr - (long)pc;
 
 	if (offset < -SZ_128M || offset >= SZ_128M) {
 #ifdef CONFIG_ARM64_MODULE_PLTS
-		struct plt_entry trampoline, *dst;
 		struct module *mod;
 
 		/*
+		 * There is only one ftrace trampoline per module. For now,
+		 * this is not a problem since on arm64, all dynamic ftrace
+		 * invocations are routed via ftrace_caller(). This will need
+		 * to be revisited if support for multiple ftrace entry points
+		 * is added in the future, but for now, the pr_err() below
+		 * deals with a theoretical issue only.
+		 */
+		if (addr != FTRACE_ADDR) {
+			pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
+			return -EINVAL;
+		}
+
+		/*
 		 * On kernels that support module PLTs, the offset between the
 		 * branch instruction and its target may legally exceed the
 		 * range of an ordinary relative 'bl' opcode. In this case, we
@@ -93,46 +105,7 @@
 		if (WARN_ON(!mod))
 			return -EINVAL;
 
-		/*
-		 * There is only one ftrace trampoline per module. For now,
-		 * this is not a problem since on arm64, all dynamic ftrace
-		 * invocations are routed via ftrace_caller(). This will need
-		 * to be revisited if support for multiple ftrace entry points
-		 * is added in the future, but for now, the pr_err() below
-		 * deals with a theoretical issue only.
-		 *
-		 * Note that PLTs are place relative, and plt_entries_equal()
-		 * checks whether they point to the same target. Here, we need
-		 * to check if the actual opcodes are in fact identical,
-		 * regardless of the offset in memory so use memcmp() instead.
-		 */
-		dst = mod->arch.ftrace_trampoline;
-		trampoline = get_plt_entry(addr, dst);
-		if (memcmp(dst, &trampoline, sizeof(trampoline))) {
-			if (plt_entry_is_initialized(dst)) {
-				pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
-				return -EINVAL;
-			}
-
-			/* point the trampoline to our ftrace entry point */
-			module_disable_ro(mod);
-			*dst = trampoline;
-			module_enable_ro(mod, true);
-
-			/*
-			 * Ensure updated trampoline is visible to instruction
-			 * fetch before we patch in the branch. Although the
-			 * architecture doesn't require an IPI in this case,
-			 * Neoverse-N1 erratum #1542419 does require one
-			 * if the TLB maintenance in module_enable_ro() is
-			 * skipped due to rodata_enabled. It doesn't seem worth
-			 * it to make it conditional given that this is
-			 * certainly not a fast-path.
-			 */
-			flush_icache_range((unsigned long)&dst[0],
-					   (unsigned long)&dst[1]);
-		}
-		addr = (unsigned long)dst;
+		addr = (unsigned long)mod->arch.ftrace_trampoline;
 #else /* CONFIG_ARM64_MODULE_PLTS */
 		return -EINVAL;
 #endif /* CONFIG_ARM64_MODULE_PLTS */
@@ -153,7 +126,7 @@
 	unsigned long pc = rec->ip;
 	bool validate = true;
 	u32 old = 0, new;
-	long offset = (long)pc - (long)addr;
+	long offset = (long)addr - (long)pc;
 
 	if (offset < -SZ_128M || offset >= SZ_128M) {
 #ifdef CONFIG_ARM64_MODULE_PLTS
--- linux-ein-5.4.0.orig/arch/arm64/kernel/head.S
+++ linux-ein-5.4.0/arch/arm64/kernel/head.S
@@ -194,7 +194,7 @@
  * to be composed of multiple pages. (This effectively scales the end index).
  *
  *	vstart:	virtual address of start of range
- *	vend:	virtual address of end of range
+ *	vend:	virtual address of end of range - we map [vstart, vend]
  *	shift:	shift used to transform virtual address into index
  *	ptrs:	number of entries in page table
  *	istart:	index in table corresponding to vstart
@@ -231,17 +231,18 @@
  *
  *	tbl:	location of page table
  *	rtbl:	address to be used for first level page table entry (typically tbl + PAGE_SIZE)
- *	vstart:	start address to map
- *	vend:	end address to map - we map [vstart, vend]
+ *	vstart:	virtual address of start of range
+ *	vend:	virtual address of end of range - we map [vstart, vend - 1]
  *	flags:	flags to use to map last level entries
  *	phys:	physical address corresponding to vstart - physical memory is contiguous
  *	pgds:	the number of pgd entries
  *
  * Temporaries:	istart, iend, tmp, count, sv - these need to be different registers
- * Preserves:	vstart, vend, flags
- * Corrupts:	tbl, rtbl, istart, iend, tmp, count, sv
+ * Preserves:	vstart, flags
+ * Corrupts:	tbl, rtbl, vend, istart, iend, tmp, count, sv
  */
 	.macro map_memory, tbl, rtbl, vstart, vend, flags, phys, pgds, istart, iend, tmp, count, sv
+	sub \vend, \vend, #1
 	add \rtbl, \tbl, #PAGE_SIZE
 	mov \sv, \rtbl
 	mov \count, #0
@@ -337,7 +338,7 @@
 	 */
 	adrp	x5, __idmap_text_end
 	clz	x5, x5
-	cmp	x5, TCR_T0SZ(VA_BITS)	// default T0SZ small enough?
+	cmp	x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small enough?
 	b.ge	1f			// .. then skip VA range extension
 
 	adr_l	x6, idmap_t0sz
@@ -393,13 +394,19 @@
 
 	/*
 	 * Since the page tables have been populated with non-cacheable
-	 * accesses (MMU disabled), invalidate the idmap and swapper page
-	 * tables again to remove any speculatively loaded cache lines.
+	 * accesses (MMU disabled), invalidate those tables again to
+	 * remove any speculatively loaded cache lines.
 	 */
+	dmb	sy
+
 	adrp	x0, idmap_pg_dir
+	adrp	x1, idmap_pg_end
+	sub	x1, x1, x0
+	bl	__inval_dcache_area
+
+	adrp	x0, init_pg_dir
 	adrp	x1, init_pg_end
 	sub	x1, x1, x0
-	dmb	sy
 	bl	__inval_dcache_area
 
 	ret	x28
@@ -964,6 +971,7 @@
 
 	tlbi	vmalle1				// Remove any stale TLB entries
 	dsb	nsh
+	isb
 
 	msr	sctlr_el1, x19			// re-enable the MMU
 	isb
--- linux-ein-5.4.0.orig/arch/arm64/kernel/hw_breakpoint.c
+++ linux-ein-5.4.0/arch/arm64/kernel/hw_breakpoint.c
@@ -654,7 +654,7 @@
 		perf_bp_event(bp, regs);
 
 		/* Do we need to handle the stepping? */
-		if (is_default_overflow_handler(bp))
+		if (uses_default_overflow_handler(bp))
 			step = 1;
 unlock:
 		rcu_read_unlock();
@@ -730,6 +730,27 @@
 		return 0;
 }
 
+static int watchpoint_report(struct perf_event *wp, unsigned long addr,
+			     struct pt_regs *regs)
+{
+	int step = uses_default_overflow_handler(wp);
+	struct arch_hw_breakpoint *info = counter_arch_bp(wp);
+
+	info->trigger = addr;
+
+	/*
+	 * 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 (!user_mode(regs) && info->ctrl.privilege == AARCH64_BREAKPOINT_EL0)
+		step = 1;
+	else
+		perf_bp_event(wp, regs);
+
+	return step;
+}
+
 static int watchpoint_handler(unsigned long addr, unsigned int esr,
 			      struct pt_regs *regs)
 {
@@ -739,7 +760,6 @@
 	u64 val;
 	struct perf_event *wp, **slots;
 	struct debug_info *debug_info;
-	struct arch_hw_breakpoint *info;
 	struct arch_hw_breakpoint_ctrl ctrl;
 
 	slots = this_cpu_ptr(wp_on_reg);
@@ -777,25 +797,13 @@
 		if (dist != 0)
 			continue;
 
-		info = counter_arch_bp(wp);
-		info->trigger = addr;
-		perf_bp_event(wp, regs);
-
-		/* Do we need to handle the stepping? */
-		if (is_default_overflow_handler(wp))
-			step = 1;
+		step = watchpoint_report(wp, addr, regs);
 	}
-	if (min_dist > 0 && min_dist != -1) {
-		/* No exact match found. */
-		wp = slots[closest_match];
-		info = counter_arch_bp(wp);
-		info->trigger = addr;
-		perf_bp_event(wp, regs);
 
-		/* Do we need to handle the stepping? */
-		if (is_default_overflow_handler(wp))
-			step = 1;
-	}
+	/* No exact match found? */
+	if (min_dist > 0 && min_dist != -1)
+		step = watchpoint_report(slots[closest_match], addr, regs);
+
 	rcu_read_unlock();
 
 	if (!step)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/insn.c
+++ linux-ein-5.4.0/arch/arm64/kernel/insn.c
@@ -21,6 +21,7 @@
 #include <asm/fixmap.h>
 #include <asm/insn.h>
 #include <asm/kprobes.h>
+#include <asm/sections.h>
 
 #define AARCH64_INSN_SF_BIT	BIT(31)
 #define AARCH64_INSN_N_BIT	BIT(22)
@@ -78,16 +79,29 @@
 
 static DEFINE_RAW_SPINLOCK(patch_lock);
 
+static bool is_exit_text(unsigned long addr)
+{
+	/* discarded with init text/data */
+	return system_state < SYSTEM_RUNNING &&
+		addr >= (unsigned long)__exittext_begin &&
+		addr < (unsigned long)__exittext_end;
+}
+
+static bool is_image_text(unsigned long addr)
+{
+	return core_kernel_text(addr) || is_exit_text(addr);
+}
+
 static void __kprobes *patch_map(void *addr, int fixmap)
 {
 	unsigned long uintaddr = (uintptr_t) addr;
-	bool module = !core_kernel_text(uintaddr);
+	bool image = is_image_text(uintaddr);
 	struct page *page;
 
-	if (module && IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
-		page = vmalloc_to_page(addr);
-	else if (!module)
+	if (image)
 		page = phys_to_page(__pa_symbol(addr));
+	else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+		page = vmalloc_to_page(addr);
 	else
 		return addr;
 
@@ -193,8 +207,8 @@
 	int i, ret = 0;
 	struct aarch64_insn_patch *pp = arg;
 
-	/* The first CPU becomes master */
-	if (atomic_inc_return(&pp->cpu_count) == 1) {
+	/* The last CPU becomes master */
+	if (atomic_inc_return(&pp->cpu_count) == num_online_cpus()) {
 		for (i = 0; ret == 0 && i < pp->insn_cnt; i++)
 			ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i],
 							     pp->new_insns[i]);
@@ -1508,16 +1522,10 @@
 				    u32 insn)
 {
 	unsigned int immr, imms, n, ones, ror, esz, tmp;
-	u64 mask = ~0UL;
-
-	/* Can't encode full zeroes or full ones */
-	if (!imm || !~imm)
-		return AARCH64_BREAK_FAULT;
+	u64 mask;
 
 	switch (variant) {
 	case AARCH64_INSN_VARIANT_32BIT:
-		if (upper_32_bits(imm))
-			return AARCH64_BREAK_FAULT;
 		esz = 32;
 		break;
 	case AARCH64_INSN_VARIANT_64BIT:
@@ -1529,6 +1537,12 @@
 		return AARCH64_BREAK_FAULT;
 	}
 
+	mask = GENMASK(esz - 1, 0);
+
+	/* Can't encode full zeroes, full ones, or value wider than the mask */
+	if (!imm || imm == mask || imm & ~mask)
+		return AARCH64_BREAK_FAULT;
+
 	/*
 	 * Inverse of Replicate(). Try to spot a repeating pattern
 	 * with a pow2 stride.
--- linux-ein-5.4.0.orig/arch/arm64/kernel/kgdb.c
+++ linux-ein-5.4.0/arch/arm64/kernel/kgdb.c
@@ -223,6 +223,8 @@
 		 */
 		if (!kernel_active_single_step())
 			kernel_enable_single_step(linux_regs);
+		else
+			kernel_rewind_single_step(linux_regs);
 		err = 0;
 		break;
 	default:
@@ -252,7 +254,7 @@
 	if (!kgdb_single_step)
 		return DBG_HOOK_ERROR;
 
-	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+	kgdb_handle_exception(0, SIGTRAP, 0, regs);
 	return DBG_HOOK_HANDLED;
 }
 NOKPROBE_SYMBOL(kgdb_step_brk_fn);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/machine_kexec.c
+++ linux-ein-5.4.0/arch/arm64/kernel/machine_kexec.c
@@ -189,6 +189,7 @@
 	 * the offline CPUs. Therefore, we must use the __* variant here.
 	 */
 	__flush_icache_range((uintptr_t)reboot_code_buffer,
+			     (uintptr_t)reboot_code_buffer +
 			     arm64_relocate_new_kernel_size);
 
 	/* Flush the kimage list and its buffers. */
--- linux-ein-5.4.0.orig/arch/arm64/kernel/machine_kexec_file.c
+++ linux-ein-5.4.0/arch/arm64/kernel/machine_kexec_file.c
@@ -150,8 +150,10 @@
 
 		/* duplicate a device tree blob */
 		ret = fdt_open_into(initial_boot_params, buf, buf_size);
-		if (ret)
+		if (ret) {
+			vfree(buf);
 			return -EINVAL;
+		}
 
 		ret = setup_dtb(image, initrd_load_addr, initrd_len,
 				cmdline, buf);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/module-plts.c
+++ linux-ein-5.4.0/arch/arm64/kernel/module-plts.c
@@ -270,8 +270,7 @@
 			mod->arch.core.plt_shndx = i;
 		else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt"))
 			mod->arch.init.plt_shndx = i;
-		else if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
-			 !strcmp(secstrings + sechdrs[i].sh_name,
+		else if (!strcmp(secstrings + sechdrs[i].sh_name,
 				 ".text.ftrace_trampoline"))
 			tramp = sechdrs + i;
 		else if (sechdrs[i].sh_type == SHT_SYMTAB)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/module.c
+++ linux-ein-5.4.0/arch/arm64/kernel/module.c
@@ -9,6 +9,7 @@
 
 #include <linux/bitops.h>
 #include <linux/elf.h>
+#include <linux/ftrace.h>
 #include <linux/gfp.h>
 #include <linux/kasan.h>
 #include <linux/kernel.h>
@@ -470,22 +471,48 @@
 	return -ENOEXEC;
 }
 
-int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
+static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
+				    const Elf_Shdr *sechdrs,
+				    const char *name)
 {
 	const Elf_Shdr *s, *se;
 	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
 	for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
-		if (strcmp(".altinstructions", secstrs + s->sh_name) == 0)
-			apply_alternatives_module((void *)s->sh_addr, s->sh_size);
-#ifdef CONFIG_ARM64_MODULE_PLTS
-		if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
-		    !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name))
-			me->arch.ftrace_trampoline = (void *)s->sh_addr;
-#endif
+		if (strcmp(name, secstrs + s->sh_name) == 0)
+			return s;
 	}
 
+	return NULL;
+}
+
+static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
+				  const Elf_Shdr *sechdrs,
+				  struct module *mod)
+{
+#if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE)
+	const Elf_Shdr *s;
+	struct plt_entry *plt;
+
+	s = find_section(hdr, sechdrs, ".text.ftrace_trampoline");
+	if (!s)
+		return -ENOEXEC;
+
+	plt = (void *)s->sh_addr;
+	*plt = get_plt_entry(FTRACE_ADDR, plt);
+	mod->arch.ftrace_trampoline = plt;
+#endif
 	return 0;
 }
+
+int module_finalize(const Elf_Ehdr *hdr,
+		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+	const Elf_Shdr *s;
+	s = find_section(hdr, sechdrs, ".altinstructions");
+	if (s)
+		apply_alternatives_module((void *)s->sh_addr, s->sh_size);
+
+	return module_init_ftrace_plt(hdr, sechdrs, me);
+}
--- linux-ein-5.4.0.orig/arch/arm64/kernel/module.lds
+++ linux-ein-5.4.0/arch/arm64/kernel/module.lds
@@ -1,5 +1,5 @@
 SECTIONS {
-	.plt (NOLOAD) : { BYTE(0) }
-	.init.plt (NOLOAD) : { BYTE(0) }
-	.text.ftrace_trampoline (NOLOAD) : { BYTE(0) }
+	.plt 0 : { BYTE(0) }
+	.init.plt 0 : { BYTE(0) }
+	.text.ftrace_trampoline 0 : { BYTE(0) }
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/perf_callchain.c
+++ linux-ein-5.4.0/arch/arm64/kernel/perf_callchain.c
@@ -102,7 +102,9 @@
 void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
 			 struct pt_regs *regs)
 {
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -147,9 +149,10 @@
 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 			   struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct stackframe frame;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -160,18 +163,21 @@
 
 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();
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
+	if (guest_cbs && guest_cbs->is_in_guest())
+		return guest_cbs->get_guest_ip();
 
 	return instruction_pointer(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	int misc = 0;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-		if (perf_guest_cbs->is_user_mode())
+	if (guest_cbs && guest_cbs->is_in_guest()) {
+		if (guest_cbs->is_user_mode())
 			misc |= PERF_RECORD_MISC_GUEST_USER;
 		else
 			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
--- linux-ein-5.4.0.orig/arch/arm64/kernel/perf_event.c
+++ linux-ein-5.4.0/arch/arm64/kernel/perf_event.c
@@ -155,7 +155,7 @@
 
 	pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
 
-	return sprintf(page, "event=0x%03llx\n", pmu_attr->id);
+	return sprintf(page, "event=0x%04llx\n", pmu_attr->id);
 }
 
 #define ARMV8_EVENT_ATTR(name, config) \
@@ -303,10 +303,13 @@
 	    test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap))
 		return attr->mode;
 
-	pmu_attr->id -= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
-	if (pmu_attr->id < ARMV8_PMUV3_MAX_COMMON_EVENTS &&
-	    test_bit(pmu_attr->id, cpu_pmu->pmceid_ext_bitmap))
-		return attr->mode;
+	if (pmu_attr->id >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) {
+		u64 id = pmu_attr->id - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE;
+
+		if (id < ARMV8_PMUV3_MAX_COMMON_EVENTS &&
+		    test_bit(id, cpu_pmu->pmceid_ext_bitmap))
+			return attr->mode;
+	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/perf_regs.c
+++ linux-ein-5.4.0/arch/arm64/kernel/perf_regs.c
@@ -15,15 +15,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-ein-5.4.0.orig/arch/arm64/kernel/probes/kprobes.c
+++ linux-ein-5.4.0/arch/arm64/kernel/probes/kprobes.c
@@ -36,25 +36,16 @@
 static void __kprobes
 post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
 
-static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
-{
-	void *addrs[1];
-	u32 insns[1];
-
-	addrs[0] = addr;
-	insns[0] = opcode;
-
-	return aarch64_insn_patch_text(addrs, insns, 1);
-}
-
 static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
 {
+	kprobe_opcode_t *addr = p->ainsn.api.insn;
+	void *addrs[] = {addr, addr + 1};
+	u32 insns[] = {p->opcode, BRK64_OPCODE_KPROBES_SS};
+
 	/* prepare insn slot */
-	patch_text(p->ainsn.api.insn, p->opcode);
+	aarch64_insn_patch_text(addrs, insns, 2);
 
-	flush_icache_range((uintptr_t) (p->ainsn.api.insn),
-			   (uintptr_t) (p->ainsn.api.insn) +
-			   MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+	flush_icache_range((uintptr_t)addr, (uintptr_t)(addr + MAX_INSN_SIZE));
 
 	/*
 	 * Needs restoring of return address after stepping xol.
@@ -134,13 +125,18 @@
 /* arm kprobe: install breakpoint in text */
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-	patch_text(p->addr, BRK64_OPCODE_KPROBES);
+	void *addr = p->addr;
+	u32 insn = BRK64_OPCODE_KPROBES;
+
+	aarch64_insn_patch_text(&addr, &insn, 1);
 }
 
 /* disarm kprobe: remove breakpoint from text */
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-	patch_text(p->addr, p->opcode);
+	void *addr = p->addr;
+
+	aarch64_insn_patch_text(&addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
@@ -169,20 +165,15 @@
 }
 
 /*
- * Interrupts need to be disabled before single-step mode is set, and not
- * reenabled until after single-step mode ends.
- * Without disabling interrupt on local CPU, there is a chance of
- * interrupt occurrence in the period of exception return and  start of
- * out-of-line single-step, that result in wrongly single stepping
- * into the interrupt handler.
+ * Mask all of DAIF while executing the instruction out-of-line, to keep things
+ * simple and avoid nesting exceptions. Interrupts do have to be disabled since
+ * the kprobe state is per-CPU and doesn't get migrated.
  */
 static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
 						struct pt_regs *regs)
 {
 	kcb->saved_irqflag = regs->pstate & DAIF_MASK;
-	regs->pstate |= PSR_I_BIT;
-	/* Unmask PSTATE.D for enabling software step exceptions. */
-	regs->pstate &= ~PSR_D_BIT;
+	regs->pstate |= DAIF_MASK;
 }
 
 static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
@@ -225,10 +216,7 @@
 		slot = (unsigned long)p->ainsn.api.insn;
 
 		set_ss_context(kcb, slot);	/* mark pending ss */
-
-		/* IRQs and single stepping do not mix well. */
 		kprobes_save_local_irqflag(kcb, regs);
-		kernel_enable_single_step(regs);
 		instruction_pointer_set(regs, slot);
 	} else {
 		/* insn simulation */
@@ -279,12 +267,8 @@
 	}
 	/* call post handler */
 	kcb->kprobe_status = KPROBE_HIT_SSDONE;
-	if (cur->post_handler)	{
-		/* post_handler can hit breakpoint and single step
-		 * again, so we enable D-flag for recursive exception.
-		 */
+	if (cur->post_handler)
 		cur->post_handler(cur, regs, 0);
-	}
 
 	reset_current_kprobe();
 }
@@ -308,8 +292,6 @@
 		if (!instruction_pointer(regs))
 			BUG();
 
-		kernel_disable_single_step();
-
 		if (kcb->kprobe_status == KPROBE_REENTER)
 			restore_previous_kprobe(kcb);
 		else
@@ -371,10 +353,6 @@
 			 * pre-handler and it returned non-zero, it will
 			 * modify the execution path and no need to single
 			 * stepping. Let's just reset current kprobe and exit.
-			 *
-			 * pre_handler can hit a breakpoint and can step thru
-			 * before return, keep PSTATE D-flag enabled until
-			 * pre_handler return back.
 			 */
 			if (!p->pre_handler || !p->pre_handler(p, regs)) {
 				setup_singlestep(p, regs, kcb, 0);
@@ -405,7 +383,7 @@
 }
 
 static int __kprobes
-kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
+kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned int esr)
 {
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 	int retval;
@@ -415,16 +393,15 @@
 
 	if (retval == DBG_HOOK_HANDLED) {
 		kprobes_restore_local_irqflag(kcb, regs);
-		kernel_disable_single_step();
-
 		post_kprobe_handler(kcb, regs);
 	}
 
 	return retval;
 }
 
-static struct step_hook kprobes_step_hook = {
-	.fn = kprobe_single_step_handler,
+static struct break_hook kprobes_break_ss_hook = {
+	.imm = KPROBES_BRK_SS_IMM,
+	.fn = kprobe_breakpoint_ss_handler,
 };
 
 static int __kprobes
@@ -568,7 +545,7 @@
 int __init arch_init_kprobes(void)
 {
 	register_kernel_break_hook(&kprobes_break_hook);
-	register_kernel_step_hook(&kprobes_step_hook);
+	register_kernel_break_hook(&kprobes_break_ss_hook);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/probes/uprobes.c
+++ linux-ein-5.4.0/arch/arm64/kernel/probes/uprobes.c
@@ -38,7 +38,7 @@
 
 	/* TODO: Currently we do not support AARCH32 instruction probing */
 	if (mm->context.flags & MMCF_AARCH32)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	else if (!IS_ALIGNED(addr, AARCH64_INSN_SIZE))
 		return -EINVAL;
 
--- linux-ein-5.4.0.orig/arch/arm64/kernel/process.c
+++ linux-ein-5.4.0/arch/arm64/kernel/process.c
@@ -56,7 +56,7 @@
 
 #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
 #include <linux/stackprotector.h>
-unsigned long __stack_chk_guard __read_mostly;
+unsigned long __stack_chk_guard __ro_after_init;
 EXPORT_SYMBOL(__stack_chk_guard);
 #endif
 
@@ -360,8 +360,8 @@
 
 asmlinkage void ret_from_fork(void) asm("ret_from_fork");
 
-int copy_thread(unsigned long clone_flags, unsigned long stack_start,
-		unsigned long stk_sz, struct task_struct *p)
+int copy_thread_tls(unsigned long clone_flags, unsigned long stack_start,
+		unsigned long stk_sz, struct task_struct *p, unsigned long tls)
 {
 	struct pt_regs *childregs = task_pt_regs(p);
 
@@ -394,11 +394,11 @@
 		}
 
 		/*
-		 * If a TLS pointer was passed to clone (4th argument), use it
-		 * for the new thread.
+		 * If a TLS pointer was passed to clone, use it for the new
+		 * thread.
 		 */
 		if (clone_flags & CLONE_SETTLS)
-			p->thread.uw.tp_value = childregs->regs[3];
+			p->thread.uw.tp_value = tls;
 	} else {
 		memset(childregs, 0, sizeof(struct pt_regs));
 		childregs->pstate = PSR_MODE_EL1h;
@@ -466,6 +466,13 @@
 	if (unlikely(next->flags & PF_KTHREAD))
 		return;
 
+	/*
+	 * If all CPUs implement the SSBS extension, then we just need to
+	 * context-switch the PSTATE field.
+	 */
+	if (cpu_have_feature(cpu_feature(SSBS)))
+		return;
+
 	/* If the mitigation is enabled, then we leave SSBS clear. */
 	if ((arm64_get_ssbd_state() == ARM64_SSBD_FORCE_ENABLE) ||
 	    test_tsk_thread_flag(next, TIF_SSBD))
@@ -492,6 +499,30 @@
 }
 
 /*
+ * ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
+ * Ensure access is disabled when switching to a 32bit task, ensure
+ * access is enabled when switching to a 64bit task.
+ */
+static void erratum_1418040_thread_switch(struct task_struct *next)
+{
+	if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) ||
+	    !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
+		return;
+
+	if (is_compat_thread(task_thread_info(next)))
+		sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
+	else
+		sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN);
+}
+
+static void erratum_1418040_new_exec(void)
+{
+	preempt_disable();
+	erratum_1418040_thread_switch(current);
+	preempt_enable();
+}
+
+/*
  * Thread switching.
  */
 __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
@@ -507,6 +538,7 @@
 	uao_thread_switch(next);
 	ptrauth_thread_switch(next);
 	ssbs_thread_switch(next);
+	erratum_1418040_thread_switch(next);
 
 	/*
 	 * Complete any pending TLB or cache maintenance on this CPU in case
@@ -565,6 +597,7 @@
 	current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
 
 	ptrauth_thread_init_user(current);
+	erratum_1418040_new_exec();
 }
 
 #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
--- linux-ein-5.4.0.orig/arch/arm64/kernel/psci.c
+++ linux-ein-5.4.0/arch/arm64/kernel/psci.c
@@ -66,7 +66,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.
@@ -74,14 +73,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;
@@ -91,16 +89,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-ein-5.4.0.orig/arch/arm64/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/arm64/kernel/ptrace.c
@@ -615,6 +615,13 @@
 	return 0;
 }
 
+static int fpr_active(struct task_struct *target, const struct user_regset *regset)
+{
+	if (!system_supports_fpsimd())
+		return -ENODEV;
+	return regset->n;
+}
+
 /*
  * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
  */
@@ -637,6 +644,9 @@
 		   unsigned int pos, unsigned int count,
 		   void *kbuf, void __user *ubuf)
 {
+	if (!system_supports_fpsimd())
+		return -EINVAL;
+
 	if (target == current)
 		fpsimd_preserve_current_state();
 
@@ -676,6 +686,9 @@
 {
 	int ret;
 
+	if (!system_supports_fpsimd())
+		return -EINVAL;
+
 	ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0);
 	if (ret)
 		return ret;
@@ -1134,6 +1147,7 @@
 		 */
 		.size = sizeof(u32),
 		.align = sizeof(u32),
+		.active = fpr_active,
 		.get = fpr_get,
 		.set = fpr_set
 	},
@@ -1348,6 +1362,9 @@
 	compat_ulong_t fpscr;
 	int ret, vregs_end_pos;
 
+	if (!system_supports_fpsimd())
+		return -EINVAL;
+
 	uregs = &target->thread.uw.fpsimd_state;
 
 	if (target == current)
@@ -1381,6 +1398,9 @@
 	compat_ulong_t fpscr;
 	int ret, vregs_end_pos;
 
+	if (!system_supports_fpsimd())
+		return -EINVAL;
+
 	uregs = &target->thread.uw.fpsimd_state;
 
 	vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
@@ -1438,6 +1458,7 @@
 		.n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
 		.size = sizeof(compat_ulong_t),
 		.align = sizeof(compat_ulong_t),
+		.active = fpr_active,
 		.get = compat_vfp_get,
 		.set = compat_vfp_set
 	},
@@ -1798,20 +1819,32 @@
 	saved_reg = regs->regs[regno];
 	regs->regs[regno] = dir;
 
-	if (dir == PTRACE_SYSCALL_EXIT)
+	if (dir == PTRACE_SYSCALL_ENTER) {
+		if (tracehook_report_syscall_entry(regs))
+			forget_syscall(regs);
+		regs->regs[regno] = saved_reg;
+	} else if (!test_thread_flag(TIF_SINGLESTEP)) {
 		tracehook_report_syscall_exit(regs, 0);
-	else if (tracehook_report_syscall_entry(regs))
-		forget_syscall(regs);
+		regs->regs[regno] = saved_reg;
+	} else {
+		regs->regs[regno] = saved_reg;
 
-	regs->regs[regno] = saved_reg;
+		/*
+		 * Signal a pseudo-step exception since we are stepping but
+		 * tracer modifications to the registers may have rewound the
+		 * state machine.
+		 */
+		tracehook_report_syscall_exit(regs, 1);
+	}
 }
 
 int syscall_trace_enter(struct pt_regs *regs)
 {
-	if (test_thread_flag(TIF_SYSCALL_TRACE) ||
-		test_thread_flag(TIF_SYSCALL_EMU)) {
+	unsigned long flags = READ_ONCE(current_thread_info()->flags);
+
+	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
 		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
-		if (!in_syscall(regs) || test_thread_flag(TIF_SYSCALL_EMU))
+		if (flags & _TIF_SYSCALL_EMU)
 			return -1;
 	}
 
@@ -1830,12 +1863,14 @@
 
 void syscall_trace_exit(struct pt_regs *regs)
 {
+	unsigned long flags = READ_ONCE(current_thread_info()->flags);
+
 	audit_syscall_exit(regs);
 
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
-		trace_sys_exit(regs, regs_return_value(regs));
+	if (flags & _TIF_SYSCALL_TRACEPOINT)
+		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
+	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
 		tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
 
 	rseq_syscall(regs);
@@ -1913,8 +1948,8 @@
  */
 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;
+	/* https://lore.kernel.org/lkml/20191118131525.GA4180@willie-the-truck */
+	user_regs_reset_single_step(regs, task);
 
 	if (is_compat_thread(task_thread_info(task)))
 		return valid_compat_regs(regs);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/setup.c
+++ linux-ein-5.4.0/arch/arm64/kernel/setup.c
@@ -85,7 +85,7 @@
 void __init smp_setup_processor_id(void)
 {
 	u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
-	cpu_logical_map(0) = mpidr;
+	set_cpu_logical_map(0, mpidr);
 
 	/*
 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
@@ -276,6 +276,12 @@
 
 u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
 
+u64 cpu_logical_map(int cpu)
+{
+	return __cpu_logical_map[cpu];
+}
+EXPORT_SYMBOL_GPL(cpu_logical_map);
+
 void __init setup_arch(char **cmdline_p)
 {
 	init_mm.start_code = (unsigned long) _text;
@@ -350,7 +356,7 @@
 	 * faults in case uaccess_enable() is inadvertently called by the init
 	 * thread.
 	 */
-	init_task.thread_info.ttbr0 = __pa_symbol(empty_zero_page);
+	init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
 #endif
 
 #ifdef CONFIG_VT
--- linux-ein-5.4.0.orig/arch/arm64/kernel/signal.c
+++ linux-ein-5.4.0/arch/arm64/kernel/signal.c
@@ -29,6 +29,7 @@
 #include <asm/unistd.h>
 #include <asm/fpsimd.h>
 #include <asm/ptrace.h>
+#include <asm/syscall.h>
 #include <asm/signal32.h>
 #include <asm/traps.h>
 #include <asm/vdso.h>
@@ -782,7 +783,6 @@
  */
 static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
-	struct task_struct *tsk = current;
 	sigset_t *oldset = sigmask_to_save();
 	int usig = ksig->sig;
 	int ret;
@@ -806,14 +806,8 @@
 	 */
 	ret |= !valid_user_regs(&regs->user_regs, current);
 
-	/*
-	 * Fast forward the stepping logic so we step into the signal
-	 * handler.
-	 */
-	if (!ret)
-		user_fastforward_single_step(tsk);
-
-	signal_setup_done(ret, ksig, 0);
+	/* Step into the signal handler if we are stepping */
+	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
@@ -875,7 +869,7 @@
 		     retval == -ERESTART_RESTARTBLOCK ||
 		     (retval == -ERESTARTSYS &&
 		      !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
-			regs->regs[0] = -EINTR;
+			syscall_set_return_value(current, regs, -EINTR, 0);
 			regs->pc = continue_addr;
 		}
 
--- linux-ein-5.4.0.orig/arch/arm64/kernel/smp.c
+++ linux-ein-5.4.0/arch/arm64/kernel/smp.c
@@ -215,6 +215,7 @@
 	if (system_uses_irq_prio_masking())
 		init_gic_priority_masking();
 
+	rcu_cpu_starting(cpu);
 	preempt_disable();
 	trace_hardirqs_off();
 
@@ -387,6 +388,7 @@
 
 	/* Mark this CPU absent */
 	set_cpu_present(cpu, 0);
+	rcu_report_dead(cpu);
 
 #ifdef CONFIG_HOTPLUG_CPU
 	update_cpu_boot_status(CPU_KILL_ME);
@@ -549,7 +551,7 @@
 		return;
 
 	/* map the logical cpu id to cpu MPIDR */
-	cpu_logical_map(cpu_count) = hwid;
+	set_cpu_logical_map(cpu_count, hwid);
 
 	cpu_madt_gicc[cpu_count] = *processor;
 
@@ -663,7 +665,7 @@
 			goto next;
 
 		pr_debug("cpu logical map 0x%llx\n", hwid);
-		cpu_logical_map(cpu_count) = hwid;
+		set_cpu_logical_map(cpu_count, hwid);
 
 		early_map_cpu_to_node(cpu_count, of_node_to_nid(dn));
 next:
@@ -704,7 +706,7 @@
 	for (i = 1; i < nr_cpu_ids; i++) {
 		if (cpu_logical_map(i) != INVALID_HWID) {
 			if (smp_cpu_setup(i))
-				cpu_logical_map(i) = INVALID_HWID;
+				set_cpu_logical_map(i, INVALID_HWID);
 		}
 	}
 }
@@ -955,11 +957,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);
@@ -972,10 +985,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 %*pbl\n",
 			   cpumask_pr_args(cpu_online_mask));
 
@@ -998,7 +1011,11 @@
 
 	cpus_stopped = 1;
 
-	if (num_online_cpus() == 1) {
+	/*
+	 * If this cpu is the only one alive at this point in time, online or
+	 * not, there are no stop messages to be sent around, so just back out.
+	 */
+	if (num_other_online_cpus() == 0) {
 		sdei_mask_local_cpu();
 		return;
 	}
@@ -1006,7 +1023,7 @@
 	cpumask_copy(&mask, cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), &mask);
 
-	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+	atomic_set(&waiting_for_crash_ipi, num_other_online_cpus());
 
 	pr_crit("SMP: stopping secondary CPUs\n");
 	smp_cross_call(&mask, IPI_CPU_CRASH_STOP);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/sys_compat.c
+++ linux-ein-5.4.0/arch/arm64/kernel/sys_compat.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/compat.h>
+#include <linux/cpufeature.h>
 #include <linux/personality.h>
 #include <linux/sched.h>
 #include <linux/sched/signal.h>
@@ -17,6 +18,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/system_misc.h>
+#include <asm/tlbflush.h>
 #include <asm/unistd.h>
 
 static long
@@ -30,6 +32,15 @@
 		if (fatal_signal_pending(current))
 			return 0;
 
+		if (cpus_have_const_cap(ARM64_WORKAROUND_1542419)) {
+			/*
+			 * The workaround requires an inner-shareable tlbi.
+			 * We pick the reserved-ASID to minimise the impact.
+			 */
+			__tlbi(aside1is, __TLBI_VADDR(0, 0));
+			dsb(ish);
+		}
+
 		ret = __flush_cache_user_range(start, start + chunk);
 		if (ret)
 			return ret;
@@ -104,6 +115,6 @@
 		(compat_thumb_mode(regs) ? 2 : 4);
 
 	arm64_notify_die("Oops - bad compat syscall(2)", regs,
-			 SIGILL, ILL_ILLTRP, addr, scno);
+			 SIGILL, ILL_ILLTRP, addr, 0);
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/arm64/kernel/syscall.c
+++ linux-ein-5.4.0/arch/arm64/kernel/syscall.c
@@ -50,7 +50,7 @@
 		ret = do_ni_syscall(regs, scno);
 	}
 
-	regs->regs[0] = ret;
+	syscall_set_return_value(current, regs, 0, ret);
 }
 
 static inline bool has_syscall_work(unsigned long flags)
@@ -99,13 +99,13 @@
 	regs->syscallno = scno;
 
 	cortex_a76_erratum_1463225_svc_handler();
+	user_exit_irqoff();
 	local_daif_restore(DAIF_PROCCTX);
-	user_exit();
 
 	if (has_syscall_work(flags)) {
 		/* set default errno for user-issued syscall(-1) */
 		if (scno == NO_SYSCALL)
-			regs->regs[0] = -ENOSYS;
+			syscall_set_return_value(current, regs, -ENOSYS, 0);
 		scno = syscall_trace_enter(regs);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
@@ -121,7 +121,7 @@
 	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
 		local_daif_mask();
 		flags = current_thread_info()->flags;
-		if (!has_syscall_work(flags)) {
+		if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP)) {
 			/*
 			 * We're off to userspace, where interrupts are
 			 * always enabled after we restore the flags from
--- linux-ein-5.4.0.orig/arch/arm64/kernel/topology.c
+++ linux-ein-5.4.0/arch/arm64/kernel/topology.c
@@ -21,44 +21,6 @@
 #include <asm/cputype.h>
 #include <asm/topology.h>
 
-void store_cpu_topology(unsigned int cpuid)
-{
-	struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
-	u64 mpidr;
-
-	if (cpuid_topo->package_id != -1)
-		goto topology_populated;
-
-	mpidr = read_cpuid_mpidr();
-
-	/* Uniprocessor systems can rely on default topology values */
-	if (mpidr & MPIDR_UP_BITMASK)
-		return;
-
-	/* Create cpu topology mapping based on MPIDR. */
-	if (mpidr & MPIDR_MT_BITMASK) {
-		/* Multiprocessor system : Multi-threads per core */
-		cpuid_topo->thread_id  = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-		cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-		cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
-					 MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
-	} else {
-		/* Multiprocessor system : Single-thread per core */
-		cpuid_topo->thread_id  = -1;
-		cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-		cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
-					 MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
-					 MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
-	}
-
-	pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
-		 cpuid, cpuid_topo->package_id, cpuid_topo->core_id,
-		 cpuid_topo->thread_id, mpidr);
-
-topology_populated:
-	update_siblings_masks(cpuid);
-}
-
 #ifdef CONFIG_ACPI
 static bool __init acpi_cpu_is_threaded(int cpu)
 {
--- linux-ein-5.4.0.orig/arch/arm64/kernel/traps.c
+++ linux-ein-5.4.0/arch/arm64/kernel/traps.c
@@ -202,7 +202,7 @@
 	raw_spin_unlock_irqrestore(&die_lock, flags);
 
 	if (ret != NOTIFY_STOP)
-		do_exit(SIGSEGV);
+		make_task_dead(SIGSEGV);
 }
 
 static void arm64_show_signal(int signo, const char *str)
@@ -470,6 +470,15 @@
 	int rt = ESR_ELx_SYS64_ISS_RT(esr);
 	unsigned long val = arm64_ftr_reg_user_value(&arm64_ftr_reg_ctrel0);
 
+	if (cpus_have_const_cap(ARM64_WORKAROUND_1542419)) {
+		/* Hide DIC so that we can trap the unnecessary maintenance...*/
+		val &= ~BIT(CTR_DIC_SHIFT);
+
+		/* ... and fake IminLine to reduce the number of traps. */
+		val &= ~CTR_IMINLINE_MASK;
+		val |= (PAGE_SHIFT - 2) & CTR_IMINLINE_MASK;
+	}
+
 	pt_regs_write_reg(regs, rt, val);
 
 	arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
--- linux-ein-5.4.0.orig/arch/arm64/kernel/vdso.c
+++ linux-ein-5.4.0/arch/arm64/kernel/vdso.c
@@ -260,18 +260,7 @@
 	if (ret)
 		return ret;
 
-	ret = aarch32_alloc_kuser_vdso_page();
-	if (ret) {
-		unsigned long c_vvar =
-			(unsigned long)page_to_virt(aarch32_vdso_pages[C_VVAR]);
-		unsigned long c_vdso =
-			(unsigned long)page_to_virt(aarch32_vdso_pages[C_VDSO]);
-
-		free_page(c_vvar);
-		free_page(c_vdso);
-	}
-
-	return ret;
+	return aarch32_alloc_kuser_vdso_page();
 }
 #else
 static int __aarch32_alloc_vdso_pages(void)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/vdso/Makefile
+++ linux-ein-5.4.0/arch/arm64/kernel/vdso/Makefile
@@ -32,7 +32,7 @@
 OBJECT_FILES_NON_STANDARD	:= y
 KCOV_INSTRUMENT			:= n
 
-CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny
+CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -fasynchronous-unwind-tables
 
 ifneq ($(c-gettimeofday-y),)
   CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
--- linux-ein-5.4.0.orig/arch/arm64/kernel/vdso/vdso.lds.S
+++ linux-ein-5.4.0/arch/arm64/kernel/vdso/vdso.lds.S
@@ -28,6 +28,13 @@
 	.gnu.version_d	: { *(.gnu.version_d) }
 	.gnu.version_r	: { *(.gnu.version_r) }
 
+	/*
+	 * Discard .note.gnu.property sections which are unused and have
+	 * different alignment requirement from vDSO note sections.
+	 */
+	/DISCARD/	: {
+		*(.note.GNU-stack .note.gnu.property)
+	}
 	.note		: { *(.note.*) }		:text	:note
 
 	. = ALIGN(16);
@@ -48,7 +55,6 @@
 	PROVIDE(end = .);
 
 	/DISCARD/	: {
-		*(.note.GNU-stack)
 		*(.data .data.* .gnu.linkonce.d.* .sdata*)
 		*(.bss .sbss .dynbss .dynsbss)
 	}
--- linux-ein-5.4.0.orig/arch/arm64/kernel/vdso32/Makefile
+++ linux-ein-5.4.0/arch/arm64/kernel/vdso32/Makefile
@@ -32,7 +32,8 @@
 # As a result we set our own flags here.
 
 # KBUILD_CPPFLAGS and NOSTDINC_FLAGS from top-level Makefile
-VDSO_CPPFLAGS := -D__KERNEL__ -nostdinc -isystem $(shell $(CC_COMPAT) -print-file-name=include)
+VDSO_CPPFLAGS := -D__KERNEL__ -nostdinc
+VDSO_CPPFLAGS += -isystem $(shell $(CC_COMPAT) -print-file-name=include 2>/dev/null)
 VDSO_CPPFLAGS += $(LINUXINCLUDE)
 
 # Common C and assembly flags
@@ -190,7 +191,7 @@
       cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
 
 # Install commands for the unstripped file
-quiet_cmd_vdso_install = INSTALL $@
+quiet_cmd_vdso_install = INSTALL32 $@
       cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
 
 vdso.so: $(obj)/vdso.so.dbg
--- linux-ein-5.4.0.orig/arch/arm64/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/arm64/kernel/vmlinux.lds.S
@@ -24,6 +24,13 @@
 
 jiffies = jiffies_64;
 
+
+#define HYPERVISOR_EXTABLE					\
+	. = ALIGN(SZ_8);					\
+	__start___kvm_ex_table = .;				\
+	*(__kvm_ex_table)					\
+	__stop___kvm_ex_table = .;
+
 #define HYPERVISOR_TEXT					\
 	/*						\
 	 * Align to 4 KB so that			\
@@ -39,6 +46,7 @@
 	__hyp_idmap_text_end = .;			\
 	__hyp_text_start = .;				\
 	*(.hyp.text)					\
+	HYPERVISOR_EXTABLE				\
 	__hyp_text_end = .;
 
 #define IDMAP_TEXT					\
@@ -142,28 +150,30 @@
 	. = ALIGN(PAGE_SIZE);
 	idmap_pg_dir = .;
 	. += IDMAP_DIR_SIZE;
+	idmap_pg_end = .;
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 	tramp_pg_dir = .;
 	. += PAGE_SIZE;
 #endif
 
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-	reserved_ttbr0 = .;
-	. += RESERVED_TTBR0_SIZE;
-#endif
+	reserved_pg_dir = .;
+	. += PAGE_SIZE;
+
 	swapper_pg_dir = .;
 	. += PAGE_SIZE;
-	swapper_pg_end = .;
 
 	. = ALIGN(SEGMENT_ALIGN);
 	__init_begin = .;
 	__inittext_begin = .;
 
 	INIT_TEXT_SECTION(8)
+
+	__exittext_begin = .;
 	.exit.text : {
 		ARM_EXIT_KEEP(EXIT_TEXT)
 	}
+	__exittext_end = .;
 
 	. = ALIGN(4);
 	.altinstructions : {
@@ -171,9 +181,6 @@
 		*(.altinstructions)
 		__alt_instructions_end = .;
 	}
-	.altinstr_replacement : {
-		*(.altinstr_replacement)
-	}
 
 	. = ALIGN(PAGE_SIZE);
 	__inittext_end = .;
@@ -269,7 +276,7 @@
 	<= SZ_4K, "Hibernate exit text too big or misaligned")
 #endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE,
+ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
 	"Entry trampoline text too big")
 #endif
 /*
--- linux-ein-5.4.0.orig/arch/arm64/kvm/debug.c
+++ linux-ein-5.4.0/arch/arm64/kvm/debug.c
@@ -69,6 +69,64 @@
 }
 
 /**
+ * kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
+ *
+ * @vcpu:	the vcpu pointer
+ *
+ * This ensures we will trap access to:
+ *  - Performance monitors (MDCR_EL2_TPM/MDCR_EL2_TPMCR)
+ *  - Debug ROM Address (MDCR_EL2_TDRA)
+ *  - OS related registers (MDCR_EL2_TDOSA)
+ *  - Statistical profiler (MDCR_EL2_TPMS/MDCR_EL2_E2PB)
+ *  - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
+ */
+static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * This also clears MDCR_EL2_E2PB_MASK to disable guest access
+	 * to the profiling buffer.
+	 */
+	vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
+	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
+				MDCR_EL2_TPMS |
+				MDCR_EL2_TTRF |
+				MDCR_EL2_TPMCR |
+				MDCR_EL2_TDRA |
+				MDCR_EL2_TDOSA);
+
+	/* Is the VM being debugged by userspace? */
+	if (vcpu->guest_debug)
+		/* Route all software debug exceptions to EL2 */
+		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
+
+	/*
+	 * Trap debug register access when one of the following is true:
+	 *  - Userspace is using the hardware to debug the guest
+	 *  (KVM_GUESTDBG_USE_HW is set).
+	 *  - The guest is not using debug (KVM_ARM64_DEBUG_DIRTY is clear).
+	 */
+	if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) ||
+	    !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY))
+		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
+
+	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
+}
+
+/**
+ * kvm_arm_vcpu_init_debug - setup vcpu debug traps
+ *
+ * @vcpu:	the vcpu pointer
+ *
+ * Set vcpu initial mdcr_el2 value.
+ */
+void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
+{
+	preempt_disable();
+	kvm_arm_setup_mdcr_el2(vcpu);
+	preempt_enable();
+}
+
+/**
  * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state
  */
 
@@ -83,12 +141,7 @@
  * @vcpu:	the vcpu pointer
  *
  * This is called before each entry into the hypervisor to setup any
- * debug related registers. Currently this just ensures we will trap
- * access to:
- *  - Performance monitors (MDCR_EL2_TPM/MDCR_EL2_TPMCR)
- *  - Debug ROM Address (MDCR_EL2_TDRA)
- *  - OS related registers (MDCR_EL2_TDOSA)
- *  - Statistical profiler (MDCR_EL2_TPMS/MDCR_EL2_E2PB)
+ * debug related registers.
  *
  * Additionally, KVM only traps guest accesses to the debug registers if
  * the guest is not actively using them (see the KVM_ARM64_DEBUG_DIRTY
@@ -100,27 +153,14 @@
 
 void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 {
-	bool trap_debug = !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY);
-	unsigned long mdscr;
+	unsigned long mdscr, orig_mdcr_el2 = vcpu->arch.mdcr_el2;
 
 	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
 
-	/*
-	 * This also clears MDCR_EL2_E2PB_MASK to disable guest access
-	 * to the profiling buffer.
-	 */
-	vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
-	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
-				MDCR_EL2_TPMS |
-				MDCR_EL2_TPMCR |
-				MDCR_EL2_TDRA |
-				MDCR_EL2_TDOSA);
+	kvm_arm_setup_mdcr_el2(vcpu);
 
 	/* Is Guest debugging in effect? */
 	if (vcpu->guest_debug) {
-		/* Route all software debug exceptions to EL2 */
-		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
-
 		/* Save guest debug state */
 		save_guest_debug_regs(vcpu);
 
@@ -174,7 +214,6 @@
 
 			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
 			vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
-			trap_debug = true;
 
 			trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
 						&vcpu->arch.debug_ptr->dbg_bcr[0],
@@ -189,15 +228,14 @@
 	BUG_ON(!vcpu->guest_debug &&
 		vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state);
 
-	/* Trap debug register access */
-	if (trap_debug)
-		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
-
 	/* If KDE or MDE are set, perform a full save/restore cycle. */
 	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
 		vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
 
-	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
+	/* Write mdcr_el2 changes since vcpu_load on VHE systems */
+	if (has_vhe() && orig_mdcr_el2 != vcpu->arch.mdcr_el2)
+		write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+
 	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_read_sys_reg(vcpu, MDSCR_EL1));
 }
 
--- linux-ein-5.4.0.orig/arch/arm64/kvm/guest.c
+++ linux-ein-5.4.0/arch/arm64/kvm/guest.c
@@ -202,6 +202,13 @@
 	}
 
 	memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id));
+
+	if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) {
+		int i;
+
+		for (i = 0; i < 16; i++)
+			*vcpu_reg32(vcpu, i) = (u32)*vcpu_reg32(vcpu, i);
+	}
 out:
 	return err;
 }
--- linux-ein-5.4.0.orig/arch/arm64/kvm/handle_exit.c
+++ linux-ein-5.4.0/arch/arm64/kvm/handle_exit.c
@@ -162,31 +162,16 @@
 	return 1;
 }
 
-#define __ptrauth_save_key(regs, key)						\
-({										\
-	regs[key ## KEYLO_EL1] = read_sysreg_s(SYS_ ## key ## KEYLO_EL1);	\
-	regs[key ## KEYHI_EL1] = read_sysreg_s(SYS_ ## key ## KEYHI_EL1);	\
-})
-
 /*
  * Handle the guest trying to use a ptrauth instruction, or trying to access a
  * ptrauth register.
  */
 void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu)
 {
-	struct kvm_cpu_context *ctxt;
-
-	if (vcpu_has_ptrauth(vcpu)) {
+	if (vcpu_has_ptrauth(vcpu))
 		vcpu_ptrauth_enable(vcpu);
-		ctxt = vcpu->arch.host_cpu_context;
-		__ptrauth_save_key(ctxt->sys_regs, APIA);
-		__ptrauth_save_key(ctxt->sys_regs, APIB);
-		__ptrauth_save_key(ctxt->sys_regs, APDA);
-		__ptrauth_save_key(ctxt->sys_regs, APDB);
-		__ptrauth_save_key(ctxt->sys_regs, APGA);
-	} else {
+	else
 		kvm_inject_undefined(vcpu);
-	}
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp-init.S
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp-init.S
@@ -136,11 +136,15 @@
 
 1:	cmp	x0, #HVC_RESET_VECTORS
 	b.ne	1f
-reset:
+
 	/*
-	 * Reset kvm back to the hyp stub. Do not clobber x0-x4 in
-	 * case we coming via HVC_SOFT_RESTART.
+	 * Set the HVC_RESET_VECTORS return code before entering the common
+	 * path so that we do not clobber x0-x2 in case we are coming via
+	 * HVC_SOFT_RESTART.
 	 */
+	mov	x0, xzr
+reset:
+	/* Reset kvm back to the hyp stub. */
 	mrs	x5, sctlr_el2
 	ldr	x6, =SCTLR_ELx_FLAGS
 	bic	x5, x5, x6		// Clear SCTL_M and etc
@@ -151,7 +155,6 @@
 	/* Install stub vectors */
 	adr_l	x5, __hyp_stub_vectors
 	msr	vbar_el2, x5
-	mov	x0, xzr
 	eret
 
 1:	/* Bad stub call */
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp/debug-sr.c
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp/debug-sr.c
@@ -168,6 +168,21 @@
 	write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
 }
 
+void __hyp_text __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Non-VHE: Disable and flush SPE data generation
+	 * VHE: The vcpu can run, but it can't hide.
+	 */
+	__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
+
+}
+
+void __hyp_text __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
+{
+	__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
+}
+
 void __hyp_text __debug_switch_to_guest(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *host_ctxt;
@@ -175,13 +190,6 @@
 	struct kvm_guest_debug_arch *host_dbg;
 	struct kvm_guest_debug_arch *guest_dbg;
 
-	/*
-	 * Non-VHE: Disable and flush SPE data generation
-	 * VHE: The vcpu can run, but it can't hide.
-	 */
-	if (!has_vhe())
-		__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
-
 	if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY))
 		return;
 
@@ -201,8 +209,6 @@
 	struct kvm_guest_debug_arch *host_dbg;
 	struct kvm_guest_debug_arch *guest_dbg;
 
-	if (!has_vhe())
-		__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
 
 	if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY))
 		return;
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp/entry.S
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp/entry.S
@@ -173,20 +173,23 @@
 	// This is our single instruction exception window. A pending
 	// SError is guaranteed to occur at the earliest when we unmask
 	// it, and at the latest just after the ISB.
-	.global	abort_guest_exit_start
 abort_guest_exit_start:
 
 	isb
 
-	.global	abort_guest_exit_end
 abort_guest_exit_end:
 
 	msr	daifset, #4	// Mask aborts
+	ret
 
-	// If the exception took place, restore the EL1 exception
-	// context so that we can report some information.
-	// Merge the exception code with the SError pending bit.
-	tbz	x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
+	_kvm_extable	abort_guest_exit_start, 9997f
+	_kvm_extable	abort_guest_exit_end, 9997f
+9997:
+	msr	daifset, #4	// Mask aborts
+	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
+
+	// restore the EL1 exception context so that we can report some
+	// information. Merge the exception code with the SError pending bit.
 	msr	elr_el2, x2
 	msr	esr_el2, x3
 	msr	spsr_el2, x4
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp/hyp-entry.S
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,30 @@
 #include <asm/kvm_mmu.h>
 #include <asm/mmu.h>
 
+.macro save_caller_saved_regs_vect
+	/* x0 and x1 were saved in the vector entry */
+	stp	x2, x3,   [sp, #-16]!
+	stp	x4, x5,   [sp, #-16]!
+	stp	x6, x7,   [sp, #-16]!
+	stp	x8, x9,   [sp, #-16]!
+	stp	x10, x11, [sp, #-16]!
+	stp	x12, x13, [sp, #-16]!
+	stp	x14, x15, [sp, #-16]!
+	stp	x16, x17, [sp, #-16]!
+.endm
+
+.macro restore_caller_saved_regs_vect
+	ldp	x16, x17, [sp], #16
+	ldp	x14, x15, [sp], #16
+	ldp	x12, x13, [sp], #16
+	ldp	x10, x11, [sp], #16
+	ldp	x8, x9,   [sp], #16
+	ldp	x6, x7,   [sp], #16
+	ldp	x4, x5,   [sp], #16
+	ldp	x2, x3,   [sp], #16
+	ldp	x0, x1,   [sp], #16
+.endm
+
 	.text
 	.pushsection	.hyp.text, "ax"
 
@@ -89,6 +113,10 @@
 	/* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
 	eor	w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
 			  ARM_SMCCC_ARCH_WORKAROUND_2)
+	cbz	w1, wa_epilogue
+
+	eor	w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_2 ^ \
+			  ARM_SMCCC_ARCH_WORKAROUND_3)
 	cbnz	w1, el1_trap
 
 #ifdef CONFIG_ARM64_SSBD
@@ -142,13 +170,19 @@
 	b	__guest_exit
 
 el2_sync:
-	/* Check for illegal exception return, otherwise panic */
+	/* Check for illegal exception return */
 	mrs	x0, spsr_el2
+	tbnz	x0, #20, 1f
 
-	/* if this was something else, then panic! */
-	tst	x0, #PSR_IL_BIT
-	b.eq	__hyp_panic
+	save_caller_saved_regs_vect
+	stp     x29, x30, [sp, #-16]!
+	bl	kvm_unexpected_el2_exception
+	ldp     x29, x30, [sp], #16
+	restore_caller_saved_regs_vect
+
+	eret
 
+1:
 	/* Let's attempt a recovery from the illegal exception return */
 	get_vcpu_ptr	x1, x0
 	mov	x0, #ARM_EXCEPTION_IL
@@ -156,27 +190,14 @@
 
 
 el2_error:
-	ldp	x0, x1, [sp], #16
+	save_caller_saved_regs_vect
+	stp     x29, x30, [sp, #-16]!
+
+	bl	kvm_unexpected_el2_exception
+
+	ldp     x29, x30, [sp], #16
+	restore_caller_saved_regs_vect
 
-	/*
-	 * Only two possibilities:
-	 * 1) Either we come from the exit path, having just unmasked
-	 *    PSTATE.A: change the return code to an EL2 fault, and
-	 *    carry on, as we're already in a sane state to handle it.
-	 * 2) Or we come from anywhere else, and that's a bug: we panic.
-	 *
-	 * For (1), x0 contains the original return code and x1 doesn't
-	 * contain anything meaningful at that stage. We can reuse them
-	 * as temp registers.
-	 * For (2), who cares?
-	 */
-	mrs	x0, elr_el2
-	adr	x1, abort_guest_exit_start
-	cmp	x0, x1
-	adr	x1, abort_guest_exit_end
-	ccmp	x0, x1, #4, ne
-	b.ne	__hyp_panic
-	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
 	eret
 	sb
 
@@ -330,4 +351,64 @@
 	ldp	x0, x1, [sp, #(8 * 2)]
 	add	sp, sp, #(8 * 4)
 ENTRY(__smccc_workaround_1_smc_end)
+
+ENTRY(__smccc_workaround_3_smc_start)
+	esb
+	sub	sp, sp, #(8 * 4)
+	stp	x2, x3, [sp, #(8 * 0)]
+	stp	x0, x1, [sp, #(8 * 2)]
+	mov	w0, #ARM_SMCCC_ARCH_WORKAROUND_3
+	smc	#0
+	ldp	x2, x3, [sp, #(8 * 0)]
+	ldp	x0, x1, [sp, #(8 * 2)]
+	add	sp, sp, #(8 * 4)
+ENTRY(__smccc_workaround_3_smc_end)
+
+ENTRY(__spectre_bhb_loop_k8_start)
+	esb
+	sub	sp, sp, #(8 * 2)
+	stp	x0, x1, [sp, #(8 * 0)]
+	mov	x0, #8
+2:	b	. + 4
+	subs	x0, x0, #1
+	b.ne	2b
+	dsb	nsh
+	isb
+	ldp	x0, x1, [sp, #(8 * 0)]
+	add	sp, sp, #(8 * 2)
+ENTRY(__spectre_bhb_loop_k8_end)
+
+ENTRY(__spectre_bhb_loop_k24_start)
+	esb
+	sub	sp, sp, #(8 * 2)
+	stp	x0, x1, [sp, #(8 * 0)]
+	mov	x0, #8
+2:	b	. + 4
+	subs	x0, x0, #1
+	b.ne	2b
+	dsb	nsh
+	isb
+	ldp	x0, x1, [sp, #(8 * 0)]
+	add	sp, sp, #(8 * 2)
+ENTRY(__spectre_bhb_loop_k24_end)
+
+ENTRY(__spectre_bhb_loop_k32_start)
+	esb
+	sub	sp, sp, #(8 * 2)
+	stp	x0, x1, [sp, #(8 * 0)]
+	mov     x0, #8
+2:	b	. + 4
+	subs	x0, x0, #1
+	b.ne	2b
+	dsb	nsh
+	isb
+	ldp	x0, x1, [sp, #(8 * 0)]
+	add	sp, sp, #(8 * 2)
+ENTRY(__spectre_bhb_loop_k32_end)
+
+ENTRY(__spectre_bhb_clearbhb_start)
+	esb
+	clearbhb
+	isb
+ENTRY(__spectre_bhb_clearbhb_end)
 #endif
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp/switch.c
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp/switch.c
@@ -14,6 +14,7 @@
 
 #include <asm/arch_gicv3.h>
 #include <asm/cpufeature.h>
+#include <asm/extable.h>
 #include <asm/kprobes.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
@@ -24,11 +25,23 @@
 #include <asm/debug-monitors.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/vectors.h>
+
+extern struct exception_table_entry __start___kvm_ex_table;
+extern struct exception_table_entry __stop___kvm_ex_table;
 
 /* Check whether the FP regs were dirtied while in the host-side run loop: */
 static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu)
 {
-	if (vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE)
+	/*
+	 * When the system doesn't support FP/SIMD, we cannot rely on
+	 * the _TIF_FOREIGN_FPSTATE flag. However, we always inject an
+	 * abort on the very first access to FP and thus we should never
+	 * see KVM_ARM64_FP_ENABLED. For added safety, make sure we always
+	 * trap the accesses.
+	 */
+	if (!system_supports_fpsimd() ||
+	    vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE)
 		vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED |
 				      KVM_ARM64_FP_HOST);
 
@@ -140,7 +153,7 @@
 
 static void deactivate_traps_vhe(void)
 {
-	extern char vectors[];	/* kernel exception vectors */
+	const char *host_vectors = vectors;
 	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
 
 	/*
@@ -151,7 +164,10 @@
 	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_1165522));
 
 	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
-	write_sysreg(vectors, vbar_el1);
+
+	if (!arm64_kernel_unmapped_at_el0())
+		host_vectors = __this_cpu_read(this_cpu_vector);
+	write_sysreg(host_vectors, vbar_el1);
 }
 NOKPROBE_SYMBOL(deactivate_traps_vhe);
 
@@ -249,10 +265,10 @@
 	 * saved the guest context yet, and we may return early...
 	 */
 	par = read_sysreg(par_el1);
-	asm volatile("at s1e1r, %0" : : "r" (far));
-	isb();
-
-	tmp = read_sysreg(par_el1);
+	if (!__kvm_at("s1e1r", far))
+		tmp = read_sysreg(par_el1);
+	else
+		tmp = SYS_PAR_EL1_F; /* back to the guest */
 	write_sysreg(par, par_el1);
 
 	if (unlikely(tmp & SYS_PAR_EL1_F))
@@ -484,7 +500,7 @@
 			kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
 			kvm_vcpu_dabt_isvalid(vcpu) &&
 			!kvm_vcpu_dabt_isextabt(vcpu) &&
-			!kvm_vcpu_dabt_iss1tw(vcpu);
+			!kvm_vcpu_abt_iss1tw(vcpu);
 
 		if (valid) {
 			int ret = __vgic_v2_perform_cpuif_access(vcpu);
@@ -670,6 +686,15 @@
 
 	__sysreg_save_state_nvhe(host_ctxt);
 
+	/*
+	 * We must flush and disable the SPE buffer for nVHE, as
+	 * the translation regime(EL1&0) is going to be loaded with
+	 * that of the guest. And we must do this before we change the
+	 * translation regime to EL2 (via MDCR_EL2_EPB == 0) and
+	 * before we load guest Stage1.
+	 */
+	__debug_save_host_buffers_nvhe(vcpu);
+
 	__activate_vm(kern_hyp_va(vcpu->kvm));
 	__activate_traps(vcpu);
 
@@ -708,11 +733,13 @@
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED)
 		__fpsimd_save_fpexc32(vcpu);
 
+	__debug_switch_to_host(vcpu);
+
 	/*
 	 * This must come after restoring the host sysregs, since a non-VHE
 	 * system may enable SPE here and make use of the TTBRs.
 	 */
-	__debug_switch_to_host(vcpu);
+	__debug_restore_host_buffers_nvhe(vcpu);
 
 	if (pmu_switch_needed)
 		__pmu_switch_to_host(host_ctxt);
@@ -746,7 +773,7 @@
 	 * making sure it is a kernel address and not a PC-relative
 	 * reference.
 	 */
-	asm volatile("ldr %0, =__hyp_panic_string" : "=r" (str_va));
+	asm volatile("ldr %0, =%1" : "=r" (str_va) : "S" (__hyp_panic_string));
 
 	__hyp_do_panic(str_va,
 		       spsr, elr,
@@ -783,3 +810,30 @@
 
 	unreachable();
 }
+
+asmlinkage void __hyp_text kvm_unexpected_el2_exception(void)
+{
+	unsigned long addr, fixup;
+	struct kvm_cpu_context *host_ctxt;
+	struct exception_table_entry *entry, *end;
+	unsigned long elr_el2 = read_sysreg(elr_el2);
+
+	entry = hyp_symbol_addr(__start___kvm_ex_table);
+	end = hyp_symbol_addr(__stop___kvm_ex_table);
+	host_ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt;
+
+	while (entry < end) {
+		addr = (unsigned long)&entry->insn + entry->insn;
+		fixup = (unsigned long)&entry->fixup + entry->fixup;
+
+		if (addr != elr_el2) {
+			entry++;
+			continue;
+		}
+
+		write_sysreg(fixup, elr_el2);
+		return;
+	}
+
+	hyp_panic(host_ctxt);
+}
--- linux-ein-5.4.0.orig/arch/arm64/kvm/hyp/tlb.c
+++ linux-ein-5.4.0/arch/arm64/kvm/hyp/tlb.c
@@ -182,7 +182,7 @@
 	__tlb_switch_to_host(kvm, &cxt);
 }
 
-void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
+void __hyp_text __kvm_flush_cpu_context(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
 	struct tlb_inv_context cxt;
@@ -191,6 +191,7 @@
 	__tlb_switch_to_guest(kvm, &cxt);
 
 	__tlbi(vmalle1);
+	asm volatile("ic iallu");
 	dsb(nsh);
 	isb();
 
--- linux-ein-5.4.0.orig/arch/arm64/kvm/inject_fault.c
+++ linux-ein-5.4.0/arch/arm64/kvm/inject_fault.c
@@ -14,9 +14,6 @@
 #include <asm/kvm_emulate.h>
 #include <asm/esr.h>
 
-#define PSTATE_FAULT_BITS_64 	(PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
-				 PSR_I_BIT | PSR_D_BIT)
-
 #define CURRENT_EL_SP_EL0_VECTOR	0x0
 #define CURRENT_EL_SP_ELx_VECTOR	0x200
 #define LOWER_EL_AArch64_VECTOR		0x400
@@ -50,6 +47,69 @@
 	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
 }
 
+/*
+ * When an exception is taken, most PSTATE fields are left unchanged in the
+ * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all
+ * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx
+ * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0.
+ *
+ * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429.
+ * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426.
+ *
+ * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from
+ * MSB to LSB.
+ */
+static unsigned long get_except64_pstate(struct kvm_vcpu *vcpu)
+{
+	unsigned long sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
+	unsigned long old, new;
+
+	old = *vcpu_cpsr(vcpu);
+	new = 0;
+
+	new |= (old & PSR_N_BIT);
+	new |= (old & PSR_Z_BIT);
+	new |= (old & PSR_C_BIT);
+	new |= (old & PSR_V_BIT);
+
+	// TODO: TCO (if/when ARMv8.5-MemTag is exposed to guests)
+
+	new |= (old & PSR_DIT_BIT);
+
+	// PSTATE.UAO is set to zero upon any exception to AArch64
+	// See ARM DDI 0487E.a, page D5-2579.
+
+	// PSTATE.PAN is unchanged unless SCTLR_ELx.SPAN == 0b0
+	// SCTLR_ELx.SPAN is RES1 when ARMv8.1-PAN is not implemented
+	// See ARM DDI 0487E.a, page D5-2578.
+	new |= (old & PSR_PAN_BIT);
+	if (!(sctlr & SCTLR_EL1_SPAN))
+		new |= PSR_PAN_BIT;
+
+	// PSTATE.SS is set to zero upon any exception to AArch64
+	// See ARM DDI 0487E.a, page D2-2452.
+
+	// PSTATE.IL is set to zero upon any exception to AArch64
+	// See ARM DDI 0487E.a, page D1-2306.
+
+	// PSTATE.SSBS is set to SCTLR_ELx.DSSBS upon any exception to AArch64
+	// See ARM DDI 0487E.a, page D13-3258
+	if (sctlr & SCTLR_ELx_DSSBS)
+		new |= PSR_SSBS_BIT;
+
+	// PSTATE.BTYPE is set to zero upon any exception to AArch64
+	// See ARM DDI 0487E.a, pages D1-2293 to D1-2294.
+
+	new |= PSR_D_BIT;
+	new |= PSR_A_BIT;
+	new |= PSR_I_BIT;
+	new |= PSR_F_BIT;
+
+	new |= PSR_MODE_EL1h;
+
+	return new;
+}
+
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
 {
 	unsigned long cpsr = *vcpu_cpsr(vcpu);
@@ -59,7 +119,7 @@
 	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
-	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+	*vcpu_cpsr(vcpu) = get_except64_pstate(vcpu);
 	vcpu_write_spsr(vcpu, cpsr);
 
 	vcpu_write_sys_reg(vcpu, addr, FAR_EL1);
@@ -94,7 +154,7 @@
 	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
-	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+	*vcpu_cpsr(vcpu) = get_except64_pstate(vcpu);
 	vcpu_write_spsr(vcpu, cpsr);
 
 	/*
--- linux-ein-5.4.0.orig/arch/arm64/kvm/reset.c
+++ linux-ein-5.4.0/arch/arm64/kvm/reset.c
@@ -258,7 +258,7 @@
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
 	const struct kvm_regs *cpu_reset;
-	int ret = -EINVAL;
+	int ret;
 	bool loaded;
 
 	/* Reset PMU outside of the non-preemptible section */
@@ -281,15 +281,19 @@
 
 	if (test_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, vcpu->arch.features) ||
 	    test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, vcpu->arch.features)) {
-		if (kvm_vcpu_enable_ptrauth(vcpu))
+		if (kvm_vcpu_enable_ptrauth(vcpu)) {
+			ret = -EINVAL;
 			goto out;
+		}
 	}
 
 	switch (vcpu->arch.target) {
 	default:
 		if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
-			if (!cpu_has_32bit_el1())
+			if (!cpu_has_32bit_el1()) {
+				ret = -EINVAL;
 				goto out;
+			}
 			cpu_reset = &default_regs_reset32;
 		} else {
 			cpu_reset = &default_regs_reset;
@@ -374,10 +378,10 @@
 		pr_info("kvm: Limiting the IPA size due to kernel %s Address limit\n",
 			(va_max < pa_max) ? "Virtual" : "Physical");
 
-	WARN(ipa_max < KVM_PHYS_SHIFT,
-	     "KVM IPA limit (%d bit) is smaller than default size\n", ipa_max);
 	kvm_ipa_limit = ipa_max;
-	kvm_info("IPA Size Limit: %dbits\n", kvm_ipa_limit);
+	kvm_info("IPA Size Limit: %d bits%s\n", kvm_ipa_limit,
+		 ((kvm_ipa_limit < KVM_PHYS_SHIFT) ?
+		  " (Reduced IPA size, limited VM/VMM compatibility)" : ""));
 }
 
 /*
@@ -404,6 +408,11 @@
 			return -EINVAL;
 	} else {
 		phys_shift = KVM_PHYS_SHIFT;
+		if (phys_shift > kvm_ipa_limit) {
+			pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+				     current->comm);
+			return -EINVAL;
+		}
 	}
 
 	parange = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1) & 7;
--- linux-ein-5.4.0.orig/arch/arm64/kvm/sys_regs.c
+++ linux-ein-5.4.0/arch/arm64/kvm/sys_regs.c
@@ -432,14 +432,14 @@
 		     struct sys_reg_params *p,
 		     const struct sys_reg_desc *rd)
 {
-	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm];
 
 	if (p->is_write)
 		reg_to_dbg(vcpu, p, dbg_reg);
 	else
 		dbg_to_reg(vcpu, p, dbg_reg);
 
-	trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
+	trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
 
 	return true;
 }
@@ -447,7 +447,7 @@
 static int set_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm];
 
 	if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -457,7 +457,7 @@
 static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm];
 
 	if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -467,21 +467,21 @@
 static void reset_bvr(struct kvm_vcpu *vcpu,
 		      const struct sys_reg_desc *rd)
 {
-	vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
+	vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm] = rd->val;
 }
 
 static bool trap_bcr(struct kvm_vcpu *vcpu,
 		     struct sys_reg_params *p,
 		     const struct sys_reg_desc *rd)
 {
-	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm];
 
 	if (p->is_write)
 		reg_to_dbg(vcpu, p, dbg_reg);
 	else
 		dbg_to_reg(vcpu, p, dbg_reg);
 
-	trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
+	trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
 
 	return true;
 }
@@ -489,7 +489,7 @@
 static int set_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm];
 
 	if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -500,7 +500,7 @@
 static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm];
 
 	if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -510,22 +510,22 @@
 static void reset_bcr(struct kvm_vcpu *vcpu,
 		      const struct sys_reg_desc *rd)
 {
-	vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
+	vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm] = rd->val;
 }
 
 static bool trap_wvr(struct kvm_vcpu *vcpu,
 		     struct sys_reg_params *p,
 		     const struct sys_reg_desc *rd)
 {
-	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm];
 
 	if (p->is_write)
 		reg_to_dbg(vcpu, p, dbg_reg);
 	else
 		dbg_to_reg(vcpu, p, dbg_reg);
 
-	trace_trap_reg(__func__, rd->reg, p->is_write,
-		vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]);
+	trace_trap_reg(__func__, rd->CRm, p->is_write,
+		vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]);
 
 	return true;
 }
@@ -533,7 +533,7 @@
 static int set_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm];
 
 	if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -543,7 +543,7 @@
 static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm];
 
 	if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -553,21 +553,21 @@
 static void reset_wvr(struct kvm_vcpu *vcpu,
 		      const struct sys_reg_desc *rd)
 {
-	vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
+	vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm] = rd->val;
 }
 
 static bool trap_wcr(struct kvm_vcpu *vcpu,
 		     struct sys_reg_params *p,
 		     const struct sys_reg_desc *rd)
 {
-	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm];
 
 	if (p->is_write)
 		reg_to_dbg(vcpu, p, dbg_reg);
 	else
 		dbg_to_reg(vcpu, p, dbg_reg);
 
-	trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
+	trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg);
 
 	return true;
 }
@@ -575,7 +575,7 @@
 static int set_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm];
 
 	if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -585,7 +585,7 @@
 static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+	__u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm];
 
 	if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
 		return -EFAULT;
@@ -595,7 +595,7 @@
 static void reset_wcr(struct kvm_vcpu *vcpu,
 		      const struct sys_reg_desc *rd)
 {
-	vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val;
+	vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm] = rd->val;
 }
 
 static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -625,6 +625,10 @@
 {
 	u64 pmcr, val;
 
+	/* No PMU available, PMCR_EL0 may UNDEF... */
+	if (!kvm_arm_support_pmu_v3())
+		return;
+
 	pmcr = read_sysreg(pmcr_el0);
 	/*
 	 * Writable bits of PMCR_EL0 (ARMV8_PMU_PMCR_MASK) are reset to UNKNOWN
@@ -1085,6 +1089,16 @@
 			 (0xfUL << ID_AA64ISAR1_API_SHIFT) |
 			 (0xfUL << ID_AA64ISAR1_GPA_SHIFT) |
 			 (0xfUL << ID_AA64ISAR1_GPI_SHIFT));
+	} else if (id == SYS_ID_AA64DFR0_EL1) {
+		/* Limit guests to PMUv3 for ARMv8.1 */
+		val = cpuid_feature_cap_perfmon_field(val,
+						ID_AA64DFR0_PMUVER_SHIFT,
+						ID_AA64DFR0_PMUVER_8_1);
+	} else if (id == SYS_ID_DFR0_EL1) {
+		/* Limit guests to PMUv3 for ARMv8.1 */
+		val = cpuid_feature_cap_perfmon_field(val,
+						ID_DFR0_PERFMON_SHIFT,
+						ID_DFR0_PERFMON_8_1);
 	}
 
 	return val;
@@ -1132,16 +1146,6 @@
 	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
 }
 
-/* Visibility overrides for SVE-specific ID registers */
-static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
-				      const struct sys_reg_desc *rd)
-{
-	if (vcpu_has_sve(vcpu))
-		return 0;
-
-	return REG_HIDDEN_USER;
-}
-
 /* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
 static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
 {
@@ -1168,9 +1172,6 @@
 {
 	u64 val;
 
-	if (WARN_ON(!vcpu_has_sve(vcpu)))
-		return -ENOENT;
-
 	val = guest_id_aa64zfr0_el1(vcpu);
 	return reg_to_user(uaddr, &val, reg->id);
 }
@@ -1183,9 +1184,6 @@
 	int err;
 	u64 val;
 
-	if (WARN_ON(!vcpu_has_sve(vcpu)))
-		return -ENOENT;
-
 	err = reg_from_user(&val, uaddr, id);
 	if (err)
 		return err;
@@ -1280,10 +1278,16 @@
 static bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			  const struct sys_reg_desc *r)
 {
+	int reg = r->reg;
+
+	/* See the 32bit mapping in kvm_host.h */
+	if (p->is_aarch32)
+		reg = r->reg / 2;
+
 	if (p->is_write)
-		vcpu_write_sys_reg(vcpu, p->regval, r->reg);
+		vcpu_write_sys_reg(vcpu, p->regval, reg);
 	else
-		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
+		p->regval = vcpu_read_sys_reg(vcpu, reg);
 	return true;
 }
 
@@ -1442,7 +1446,7 @@
 	ID_SANITISED(ID_AA64PFR1_EL1),
 	ID_UNALLOCATED(4,2),
 	ID_UNALLOCATED(4,3),
-	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
+	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, },
 	ID_UNALLOCATED(4,5),
 	ID_UNALLOCATED(4,6),
 	ID_UNALLOCATED(4,7),
@@ -1460,7 +1464,7 @@
 	/* CRm=6 */
 	ID_SANITISED(ID_AA64ISAR0_EL1),
 	ID_SANITISED(ID_AA64ISAR1_EL1),
-	ID_UNALLOCATED(6,2),
+	ID_SANITISED(ID_AA64ISAR2_EL1),
 	ID_UNALLOCATED(6,3),
 	ID_UNALLOCATED(6,4),
 	ID_UNALLOCATED(6,5),
@@ -1740,9 +1744,9 @@
 	{ Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi },
 	DBG_BCR_BVR_WCR_WVR(1),
 	/* DBGDCCINT */
-	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32 },
+	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32, NULL, cp14_DBGDCCINT },
 	/* DBGDSCRext */
-	{ Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32 },
+	{ Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32, NULL, cp14_DBGDSCRext },
 	DBG_BCR_BVR_WCR_WVR(2),
 	/* DBGDTR[RT]Xint */
 	{ Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi },
@@ -1757,7 +1761,7 @@
 	{ Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi },
 	DBG_BCR_BVR_WCR_WVR(6),
 	/* DBGVCR */
-	{ Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32 },
+	{ Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32, NULL, cp14_DBGVCR },
 	DBG_BCR_BVR_WCR_WVR(7),
 	DBG_BCR_BVR_WCR_WVR(8),
 	DBG_BCR_BVR_WCR_WVR(9),
@@ -1847,6 +1851,7 @@
 	{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
 	{ Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
 	{ Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
+	{ Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, c2_TTBCR2 },
 	{ Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR },
 	{ Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR },
 	{ Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR },
@@ -2360,8 +2365,11 @@
 	if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG)
 		return NULL;
 
+	if (!index_to_params(id, &params))
+		return NULL;
+
 	table = get_target_table(vcpu->arch.target, true, &num);
-	r = find_reg_by_id(id, &params, table, num);
+	r = find_reg(&params, table, num);
 	if (!r)
 		r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
 
--- linux-ein-5.4.0.orig/arch/arm64/lib/clear_page.S
+++ linux-ein-5.4.0/arch/arm64/lib/clear_page.S
@@ -14,7 +14,7 @@
  * Parameters:
  *	x0 - dest
  */
-ENTRY(clear_page)
+SYM_FUNC_START(clear_page)
 	mrs	x1, dczid_el0
 	and	w1, w1, #0xf
 	mov	x2, #4
@@ -25,5 +25,5 @@
 	tst	x0, #(PAGE_SIZE - 1)
 	b.ne	1b
 	ret
-ENDPROC(clear_page)
+SYM_FUNC_END(clear_page)
 EXPORT_SYMBOL(clear_page)
--- linux-ein-5.4.0.orig/arch/arm64/lib/clear_user.S
+++ linux-ein-5.4.0/arch/arm64/lib/clear_user.S
@@ -19,7 +19,7 @@
  *
  * Alignment fixed up by hardware.
  */
-ENTRY(__arch_clear_user)
+SYM_FUNC_START(__arch_clear_user)
 	mov	x2, x1			// save the size for fixup return
 	subs	x1, x1, #8
 	b.mi	2f
@@ -40,7 +40,7 @@
 uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
 5:	mov	x0, #0
 	ret
-ENDPROC(__arch_clear_user)
+SYM_FUNC_END(__arch_clear_user)
 EXPORT_SYMBOL(__arch_clear_user)
 
 	.section .fixup,"ax"
--- linux-ein-5.4.0.orig/arch/arm64/lib/copy_from_user.S
+++ linux-ein-5.4.0/arch/arm64/lib/copy_from_user.S
@@ -53,12 +53,12 @@
 	.endm
 
 end	.req	x5
-ENTRY(__arch_copy_from_user)
+SYM_FUNC_START(__arch_copy_from_user)
 	add	end, x0, x2
 #include "copy_template.S"
 	mov	x0, #0				// Nothing to copy
 	ret
-ENDPROC(__arch_copy_from_user)
+SYM_FUNC_END(__arch_copy_from_user)
 EXPORT_SYMBOL(__arch_copy_from_user)
 
 	.section .fixup,"ax"
--- linux-ein-5.4.0.orig/arch/arm64/lib/copy_in_user.S
+++ linux-ein-5.4.0/arch/arm64/lib/copy_in_user.S
@@ -55,12 +55,12 @@
 
 end	.req	x5
 
-ENTRY(__arch_copy_in_user)
+SYM_FUNC_START(__arch_copy_in_user)
 	add	end, x0, x2
 #include "copy_template.S"
 	mov	x0, #0
 	ret
-ENDPROC(__arch_copy_in_user)
+SYM_FUNC_END(__arch_copy_in_user)
 EXPORT_SYMBOL(__arch_copy_in_user)
 
 	.section .fixup,"ax"
--- linux-ein-5.4.0.orig/arch/arm64/lib/copy_page.S
+++ linux-ein-5.4.0/arch/arm64/lib/copy_page.S
@@ -17,7 +17,7 @@
  *	x0 - dest
  *	x1 - src
  */
-ENTRY(copy_page)
+SYM_FUNC_START(copy_page)
 alternative_if ARM64_HAS_NO_HW_PREFETCH
 	// Prefetch three cache lines ahead.
 	prfm	pldl1strm, [x1, #128]
@@ -75,5 +75,5 @@
 	stnp	x16, x17, [x0, #112]
 
 	ret
-ENDPROC(copy_page)
+SYM_FUNC_END(copy_page)
 EXPORT_SYMBOL(copy_page)
--- linux-ein-5.4.0.orig/arch/arm64/lib/copy_to_user.S
+++ linux-ein-5.4.0/arch/arm64/lib/copy_to_user.S
@@ -52,12 +52,12 @@
 	.endm
 
 end	.req	x5
-ENTRY(__arch_copy_to_user)
+SYM_FUNC_START(__arch_copy_to_user)
 	add	end, x0, x2
 #include "copy_template.S"
 	mov	x0, #0
 	ret
-ENDPROC(__arch_copy_to_user)
+SYM_FUNC_END(__arch_copy_to_user)
 EXPORT_SYMBOL(__arch_copy_to_user)
 
 	.section .fixup,"ax"
--- linux-ein-5.4.0.orig/arch/arm64/lib/crc32.S
+++ linux-ein-5.4.0/arch/arm64/lib/crc32.S
@@ -85,17 +85,17 @@
 	.endm
 
 	.align		5
-ENTRY(crc32_le)
+SYM_FUNC_START(crc32_le)
 alternative_if_not ARM64_HAS_CRC32
 	b		crc32_le_base
 alternative_else_nop_endif
 	__crc32
-ENDPROC(crc32_le)
+SYM_FUNC_END(crc32_le)
 
 	.align		5
-ENTRY(__crc32c_le)
+SYM_FUNC_START(__crc32c_le)
 alternative_if_not ARM64_HAS_CRC32
 	b		__crc32c_le_base
 alternative_else_nop_endif
 	__crc32		c
-ENDPROC(__crc32c_le)
+SYM_FUNC_END(__crc32c_le)
--- linux-ein-5.4.0.orig/arch/arm64/lib/memchr.S
+++ linux-ein-5.4.0/arch/arm64/lib/memchr.S
@@ -19,7 +19,7 @@
  * Returns:
  *	x0 - address of first occurrence of 'c' or 0
  */
-WEAK(memchr)
+SYM_FUNC_START_WEAK_PI(memchr)
 	and	w1, w1, #0xff
 1:	subs	x2, x2, #1
 	b.mi	2f
@@ -30,5 +30,5 @@
 	ret
 2:	mov	x0, #0
 	ret
-ENDPIPROC(memchr)
+SYM_FUNC_END_PI(memchr)
 EXPORT_SYMBOL_NOKASAN(memchr)
--- linux-ein-5.4.0.orig/arch/arm64/lib/memcmp.S
+++ linux-ein-5.4.0/arch/arm64/lib/memcmp.S
@@ -46,7 +46,7 @@
 limit_wd	.req	x12
 mask		.req	x13
 
-WEAK(memcmp)
+SYM_FUNC_START_WEAK_PI(memcmp)
 	cbz	limit, .Lret0
 	eor	tmp1, src1, src2
 	tst	tmp1, #7
@@ -243,5 +243,5 @@
 .Lret0:
 	mov	result, #0
 	ret
-ENDPIPROC(memcmp)
+SYM_FUNC_END_PI(memcmp)
 EXPORT_SYMBOL_NOKASAN(memcmp)
--- linux-ein-5.4.0.orig/arch/arm64/lib/memcpy.S
+++ linux-ein-5.4.0/arch/arm64/lib/memcpy.S
@@ -56,12 +56,11 @@
 	stp \ptr, \regB, [\regC], \val
 	.endm
 
-	.weak memcpy
-ENTRY(__memcpy)
-ENTRY(memcpy)
+SYM_FUNC_START_ALIAS(__memcpy)
+SYM_FUNC_START_WEAK_PI(memcpy)
 #include "copy_template.S"
 	ret
-ENDPIPROC(memcpy)
+SYM_FUNC_END_PI(memcpy)
 EXPORT_SYMBOL(memcpy)
-ENDPROC(__memcpy)
+SYM_FUNC_END_ALIAS(__memcpy)
 EXPORT_SYMBOL(__memcpy)
--- linux-ein-5.4.0.orig/arch/arm64/lib/memmove.S
+++ linux-ein-5.4.0/arch/arm64/lib/memmove.S
@@ -45,9 +45,8 @@
 D_l	.req	x13
 D_h	.req	x14
 
-	.weak memmove
-ENTRY(__memmove)
-ENTRY(memmove)
+SYM_FUNC_START_ALIAS(__memmove)
+SYM_FUNC_START_WEAK_PI(memmove)
 	cmp	dstin, src
 	b.lo	__memcpy
 	add	tmp1, src, count
@@ -184,7 +183,7 @@
 	tst	count, #0x3f
 	b.ne	.Ltail63
 	ret
-ENDPIPROC(memmove)
+SYM_FUNC_END_PI(memmove)
 EXPORT_SYMBOL(memmove)
-ENDPROC(__memmove)
+SYM_FUNC_END_ALIAS(__memmove)
 EXPORT_SYMBOL(__memmove)
--- linux-ein-5.4.0.orig/arch/arm64/lib/memset.S
+++ linux-ein-5.4.0/arch/arm64/lib/memset.S
@@ -42,9 +42,8 @@
 tmp3w		.req	w9
 tmp3		.req	x9
 
-	.weak memset
-ENTRY(__memset)
-ENTRY(memset)
+SYM_FUNC_START_ALIAS(__memset)
+SYM_FUNC_START_WEAK_PI(memset)
 	mov	dst, dstin	/* Preserve return value.  */
 	and	A_lw, val, #255
 	orr	A_lw, A_lw, A_lw, lsl #8
@@ -203,7 +202,7 @@
 	ands	count, count, zva_bits_x
 	b.ne	.Ltail_maybe_long
 	ret
-ENDPIPROC(memset)
+SYM_FUNC_END_PI(memset)
 EXPORT_SYMBOL(memset)
-ENDPROC(__memset)
+SYM_FUNC_END_ALIAS(__memset)
 EXPORT_SYMBOL(__memset)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strchr.S
+++ linux-ein-5.4.0/arch/arm64/lib/strchr.S
@@ -18,7 +18,7 @@
  * Returns:
  *	x0 - address of first occurrence of 'c' or 0
  */
-WEAK(strchr)
+SYM_FUNC_START_WEAK(strchr)
 	and	w1, w1, #0xff
 1:	ldrb	w2, [x0], #1
 	cmp	w2, w1
@@ -28,5 +28,5 @@
 	cmp	w2, w1
 	csel	x0, x0, xzr, eq
 	ret
-ENDPROC(strchr)
+SYM_FUNC_END(strchr)
 EXPORT_SYMBOL_NOKASAN(strchr)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strcmp.S
+++ linux-ein-5.4.0/arch/arm64/lib/strcmp.S
@@ -48,7 +48,7 @@
 zeroones	.req	x10
 pos		.req	x11
 
-WEAK(strcmp)
+SYM_FUNC_START_WEAK_PI(strcmp)
 	eor	tmp1, src1, src2
 	mov	zeroones, #REP8_01
 	tst	tmp1, #7
@@ -219,5 +219,5 @@
 	lsr	data1, data1, #56
 	sub	result, data1, data2, lsr #56
 	ret
-ENDPIPROC(strcmp)
+SYM_FUNC_END_PI(strcmp)
 EXPORT_SYMBOL_NOKASAN(strcmp)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strlen.S
+++ linux-ein-5.4.0/arch/arm64/lib/strlen.S
@@ -44,7 +44,7 @@
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
-WEAK(strlen)
+SYM_FUNC_START_WEAK_PI(strlen)
 	mov	zeroones, #REP8_01
 	bic	src, srcin, #15
 	ands	tmp1, srcin, #15
@@ -111,5 +111,5 @@
 	csinv	data1, data1, xzr, le
 	csel	data2, data2, data2a, le
 	b	.Lrealigned
-ENDPIPROC(strlen)
+SYM_FUNC_END_PI(strlen)
 EXPORT_SYMBOL_NOKASAN(strlen)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strncmp.S
+++ linux-ein-5.4.0/arch/arm64/lib/strncmp.S
@@ -52,7 +52,7 @@
 mask		.req	x14
 endloop		.req	x15
 
-WEAK(strncmp)
+SYM_FUNC_START_WEAK_PI(strncmp)
 	cbz	limit, .Lret0
 	eor	tmp1, src1, src2
 	mov	zeroones, #REP8_01
@@ -295,5 +295,5 @@
 .Lret0:
 	mov	result, #0
 	ret
-ENDPIPROC(strncmp)
+SYM_FUNC_END_PI(strncmp)
 EXPORT_SYMBOL_NOKASAN(strncmp)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strnlen.S
+++ linux-ein-5.4.0/arch/arm64/lib/strnlen.S
@@ -47,7 +47,7 @@
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
-WEAK(strnlen)
+SYM_FUNC_START_WEAK_PI(strnlen)
 	cbz	limit, .Lhit_limit
 	mov	zeroones, #REP8_01
 	bic	src, srcin, #15
@@ -156,5 +156,5 @@
 .Lhit_limit:
 	mov	len, limit
 	ret
-ENDPIPROC(strnlen)
+SYM_FUNC_END_PI(strnlen)
 EXPORT_SYMBOL_NOKASAN(strnlen)
--- linux-ein-5.4.0.orig/arch/arm64/lib/strrchr.S
+++ linux-ein-5.4.0/arch/arm64/lib/strrchr.S
@@ -18,7 +18,7 @@
  * Returns:
  *	x0 - address of last occurrence of 'c' or 0
  */
-WEAK(strrchr)
+SYM_FUNC_START_WEAK_PI(strrchr)
 	mov	x3, #0
 	and	w1, w1, #0xff
 1:	ldrb	w2, [x0], #1
@@ -29,5 +29,5 @@
 	b	1b
 2:	mov	x0, x3
 	ret
-ENDPIPROC(strrchr)
+SYM_FUNC_END_PI(strrchr)
 EXPORT_SYMBOL_NOKASAN(strrchr)
--- linux-ein-5.4.0.orig/arch/arm64/lib/tishift.S
+++ linux-ein-5.4.0/arch/arm64/lib/tishift.S
@@ -7,7 +7,7 @@
 
 #include <asm/assembler.h>
 
-ENTRY(__ashlti3)
+SYM_FUNC_START(__ashlti3)
 	cbz	x2, 1f
 	mov	x3, #64
 	sub	x3, x3, x2
@@ -26,10 +26,10 @@
 	lsl	x1, x0, x1
 	mov	x0, x2
 	ret
-ENDPROC(__ashlti3)
+SYM_FUNC_END(__ashlti3)
 EXPORT_SYMBOL(__ashlti3)
 
-ENTRY(__ashrti3)
+SYM_FUNC_START(__ashrti3)
 	cbz	x2, 1f
 	mov	x3, #64
 	sub	x3, x3, x2
@@ -48,10 +48,10 @@
 	asr	x0, x1, x0
 	mov	x1, x2
 	ret
-ENDPROC(__ashrti3)
+SYM_FUNC_END(__ashrti3)
 EXPORT_SYMBOL(__ashrti3)
 
-ENTRY(__lshrti3)
+SYM_FUNC_START(__lshrti3)
 	cbz	x2, 1f
 	mov	x3, #64
 	sub	x3, x3, x2
@@ -70,5 +70,5 @@
 	lsr	x0, x1, x0
 	mov	x1, x2
 	ret
-ENDPROC(__lshrti3)
+SYM_FUNC_END(__lshrti3)
 EXPORT_SYMBOL(__lshrti3)
--- linux-ein-5.4.0.orig/arch/arm64/mm/cache.S
+++ linux-ein-5.4.0/arch/arm64/mm/cache.S
@@ -228,8 +228,6 @@
  *	- dir	- DMA direction
  */
 ENTRY(__dma_map_area)
-	cmp	w2, #DMA_FROM_DEVICE
-	b.eq	__dma_inv_area
 	b	__dma_clean_area
 ENDPIPROC(__dma_map_area)
 
--- linux-ein-5.4.0.orig/arch/arm64/mm/dma-mapping.c
+++ linux-ein-5.4.0/arch/arm64/mm/dma-mapping.c
@@ -13,14 +13,14 @@
 
 #include <asm/cacheflush.h>
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_map_area(phys_to_virt(paddr), size, dir);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_unmap_area(phys_to_virt(paddr), size, dir);
 }
--- linux-ein-5.4.0.orig/arch/arm64/mm/fault.c
+++ linux-ein-5.4.0/arch/arm64/mm/fault.c
@@ -296,7 +296,7 @@
 	show_pte(addr);
 	die("Oops", regs, esr);
 	bust_spinlocks(0);
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 }
 
 static void __do_kernel_fault(unsigned long addr, unsigned int esr,
@@ -403,8 +403,8 @@
 	}
 }
 
-#define VM_FAULT_BADMAP		0x010000
-#define VM_FAULT_BADACCESS	0x020000
+#define VM_FAULT_BADMAP		((__force vm_fault_t)0x010000)
+#define VM_FAULT_BADACCESS	((__force vm_fault_t)0x020000)
 
 static vm_fault_t __do_page_fault(struct mm_struct *mm, unsigned long addr,
 			   unsigned int mm_flags, unsigned long vm_flags)
@@ -454,7 +454,7 @@
 	const struct fault_info *inf;
 	struct mm_struct *mm = current->mm;
 	vm_fault_t fault, major = 0;
-	unsigned long vm_flags = VM_READ | VM_WRITE;
+	unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
 	unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
 	if (kprobe_page_fault(regs, esr))
@@ -654,11 +654,13 @@
 
 	inf = esr_to_fault_info(esr);
 
-	/*
-	 * Return value ignored as we rely on signal merging.
-	 * Future patches will make this more robust.
-	 */
-	apei_claim_sea(regs);
+	if (user_mode(regs) && apei_claim_sea(regs) == 0) {
+		/*
+		 * APEI claimed this as a firmware-first notification.
+		 * Some processing deferred to task_work before ret_to_user().
+		 */
+		return 0;
+	}
 
 	if (esr & ESR_ELx_FnV)
 		siaddr = NULL;
--- linux-ein-5.4.0.orig/arch/arm64/mm/hugetlbpage.c
+++ linux-ein-5.4.0/arch/arm64/mm/hugetlbpage.c
@@ -230,6 +230,8 @@
 		ptep = (pte_t *)pudp;
 	} else if (sz == (CONT_PTE_SIZE)) {
 		pmdp = pmd_alloc(mm, pudp, addr);
+		if (!pmdp)
+			return NULL;
 
 		WARN_ON(addr & (sz - 1));
 		/*
--- linux-ein-5.4.0.orig/arch/arm64/mm/init.c
+++ linux-ein-5.4.0/arch/arm64/mm/init.c
@@ -50,12 +50,6 @@
 s64 memstart_addr __ro_after_init = -1;
 EXPORT_SYMBOL(memstart_addr);
 
-s64 physvirt_offset __ro_after_init;
-EXPORT_SYMBOL(physvirt_offset);
-
-struct page *vmemmap __ro_after_init;
-EXPORT_SYMBOL(vmemmap);
-
 phys_addr_t arm64_dma_phys_limit __ro_after_init;
 
 #ifdef CONFIG_KEXEC_CORE
@@ -251,6 +245,18 @@
 
 	if (!valid_section(__nr_to_section(pfn_to_section_nr(pfn))))
 		return 0;
+
+	/*
+	 * ZONE_DEVICE memory does not have the memblock entries.
+	 * memblock_is_map_memory() check for ZONE_DEVICE based
+	 * addresses will always fail. Even the normal hotplugged
+	 * memory will never have MEMBLOCK_NOMAP flag set in their
+	 * memblock entries. Skip memblock search for all non early
+	 * memory sections covering all of hotplug memory including
+	 * both normal and ZONE_DEVICE based.
+	 */
+	if (!early_section(__pfn_to_section(pfn)))
+		return pfn_section_valid(__pfn_to_section(pfn), pfn);
 #endif
 	return memblock_is_map_memory(addr);
 }
@@ -321,20 +327,6 @@
 	memstart_addr = round_down(memblock_start_of_DRAM(),
 				   ARM64_MEMSTART_ALIGN);
 
-	physvirt_offset = PHYS_OFFSET - PAGE_OFFSET;
-
-	vmemmap = ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT));
-
-	/*
-	 * If we are running with a 52-bit kernel VA config on a system that
-	 * does not support it, we have to offset our vmemmap and physvirt_offset
-	 * s.t. we avoid the 52-bit portion of the direct linear map
-	 */
-	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) {
-		vmemmap += (_PAGE_OFFSET(48) - _PAGE_OFFSET(52)) >> PAGE_SHIFT;
-		physvirt_offset = PHYS_OFFSET - _PAGE_OFFSET(48);
-	}
-
 	/*
 	 * Remove the memory that we will not be able to cover with the
 	 * linear mapping. Take care not to clip the kernel which may be
@@ -350,6 +342,16 @@
 	}
 
 	/*
+	 * If we are running with a 52-bit kernel VA config on a system that
+	 * does not support it, we have to place the available physical
+	 * memory in the 48-bit addressable part of the linear region, i.e.,
+	 * we have to move it upward. Since memstart_addr represents the
+	 * physical address of PAGE_OFFSET, we have to *subtract* from it.
+	 */
+	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52))
+		memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52);
+
+	/*
 	 * Apply the memory limit if it was set. Since the kernel may be loaded
 	 * high up in memory, add back the kernel region that must be accessible
 	 * via the linear mapping.
--- linux-ein-5.4.0.orig/arch/arm64/mm/ioremap.c
+++ linux-ein-5.4.0/arch/arm64/mm/ioremap.c
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
@@ -100,3 +101,11 @@
 {
 	early_ioremap_setup();
 }
+
+bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
+				 unsigned long flags)
+{
+	unsigned long pfn = PHYS_PFN(offset);
+
+	return memblock_is_map_memory(pfn);
+}
--- linux-ein-5.4.0.orig/arch/arm64/mm/mmu.c
+++ linux-ein-5.4.0/arch/arm64/mm/mmu.c
@@ -38,7 +38,7 @@
 #define NO_BLOCK_MAPPINGS	BIT(0)
 #define NO_CONT_MAPPINGS	BIT(1)
 
-u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
+u64 idmap_t0sz = TCR_T0SZ(VA_BITS_MIN);
 u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
 
 u64 __section(".mmuoff.data.write") vabits_actual;
@@ -399,7 +399,7 @@
 static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
 				  phys_addr_t size, pgprot_t prot)
 {
-	if ((virt >= PAGE_END) && (virt < VMALLOC_START)) {
+	if (virt < PAGE_OFFSET) {
 		pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
 			&phys, virt);
 		return;
@@ -426,7 +426,7 @@
 static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
 				phys_addr_t size, pgprot_t prot)
 {
-	if ((virt >= PAGE_END) && (virt < VMALLOC_START)) {
+	if (virt < PAGE_OFFSET) {
 		pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
 			&phys, virt);
 		return;
@@ -583,6 +583,8 @@
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 static int __init map_entry_trampoline(void)
 {
+	int i;
+
 	pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
 	phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
 
@@ -591,11 +593,15 @@
 
 	/* Map only the text into the trampoline page table */
 	memset(tramp_pg_dir, 0, PGD_SIZE);
-	__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
-			     prot, __pgd_pgtable_alloc, 0);
+	__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
+			     entry_tramp_text_size(), prot,
+			     __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
 
 	/* Map both the text and data into the kernel page table */
-	__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
+	for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
+		__set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
+			     pa_start + i * PAGE_SIZE, prot);
+
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
 		extern char __entry_tramp_data_start[];
 
@@ -1069,7 +1075,6 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct zone *zone;
 
 	/*
 	 * FIXME: Cleanup page tables (also in arch_add_memory() in case
@@ -1078,7 +1083,6 @@
 	 * unplug. ARCH_ENABLE_MEMORY_HOTREMOVE must not be
 	 * unlocked yet.
 	 */
-	zone = page_zone(pfn_to_page(start_pfn));
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 }
 #endif
--- linux-ein-5.4.0.orig/arch/arm64/mm/numa.c
+++ linux-ein-5.4.0/arch/arm64/mm/numa.c
@@ -46,7 +46,11 @@
  */
 const struct cpumask *cpumask_of_node(int node)
 {
-	if (WARN_ON(node >= nr_node_ids))
+
+	if (node == NUMA_NO_NODE)
+		return cpu_all_mask;
+
+	if (WARN_ON(node < 0 || node >= nr_node_ids))
 		return cpu_none_mask;
 
 	if (WARN_ON(node_to_cpumask_map[node] == NULL))
--- linux-ein-5.4.0.orig/arch/arm64/mm/physaddr.c
+++ linux-ein-5.4.0/arch/arm64/mm/physaddr.c
@@ -9,7 +9,7 @@
 
 phys_addr_t __virt_to_phys(unsigned long x)
 {
-	WARN(!__is_lm_address(x),
+	WARN(!__is_lm_address(__tag_reset(x)),
 	     "virt_to_phys used for non-linear address: %pK (%pS)\n",
 	      (void *)x,
 	      (void *)x);
--- linux-ein-5.4.0.orig/arch/arm64/mm/proc.S
+++ linux-ein-5.4.0/arch/arm64/mm/proc.S
@@ -166,7 +166,7 @@
 	.pushsection ".idmap.text", "awx"
 
 .macro	__idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
-	adrp	\tmp1, empty_zero_page
+	adrp	\tmp1, reserved_pg_dir
 	phys_to_ttbr \tmp2, \tmp1
 	offset_ttbr1 \tmp2, \tmp1
 	msr	ttbr1_el1, \tmp2
--- linux-ein-5.4.0.orig/arch/arm64/net/bpf_jit_comp.c
+++ linux-ein-5.4.0/arch/arm64/net/bpf_jit_comp.c
@@ -141,14 +141,17 @@
 	}
 }
 
-static inline int bpf2a64_offset(int bpf_to, int bpf_from,
+static inline int bpf2a64_offset(int bpf_insn, int off,
 				 const struct jit_ctx *ctx)
 {
-	int to = ctx->offset[bpf_to];
-	/* -1 to account for the Branch instruction */
-	int from = ctx->offset[bpf_from] - 1;
-
-	return to - from;
+	/* BPF JMP offset is relative to the next instruction */
+	bpf_insn++;
+	/*
+	 * Whereas arm64 branch instructions encode the offset
+	 * from the branch itself, so we must subtract 1 from the
+	 * instruction offset.
+	 */
+	return ctx->offset[bpf_insn + off] - (ctx->offset[bpf_insn] - 1);
 }
 
 static void jit_fill_hole(void *area, unsigned int size)
@@ -532,7 +535,7 @@
 
 	/* JUMP off */
 	case BPF_JMP | BPF_JA:
-		jmp_offset = bpf2a64_offset(i + off, i, ctx);
+		jmp_offset = bpf2a64_offset(i, off, ctx);
 		check_imm26(jmp_offset);
 		emit(A64_B(jmp_offset), ctx);
 		break;
@@ -559,7 +562,7 @@
 	case BPF_JMP32 | BPF_JSLE | BPF_X:
 		emit(A64_CMP(is64, dst, src), ctx);
 emit_cond_jmp:
-		jmp_offset = bpf2a64_offset(i + off, i, ctx);
+		jmp_offset = bpf2a64_offset(i, off, ctx);
 		check_imm19(jmp_offset);
 		switch (BPF_OP(code)) {
 		case BPF_JEQ:
@@ -698,6 +701,19 @@
 		}
 		break;
 
+	/* speculation barrier */
+	case BPF_ST | BPF_NOSPEC:
+		/*
+		 * Nothing required here.
+		 *
+		 * In case of arm64, we rely on the firmware mitigation of
+		 * Speculative Store Bypass as controlled via the ssbd kernel
+		 * parameter. Whenever the mitigation is enabled, it works
+		 * for all of the kernel code with no need to provide any
+		 * additional instructions.
+		 */
+		break;
+
 	/* ST: *(size *)(dst + off) = imm */
 	case BPF_ST | BPF_MEM | BPF_W:
 	case BPF_ST | BPF_MEM | BPF_H:
@@ -780,10 +796,21 @@
 	const struct bpf_prog *prog = ctx->prog;
 	int i;
 
+	/*
+	 * - offset[0] offset of the end of prologue,
+	 *   start of the 1st instruction.
+	 * - offset[1] - offset of the end of 1st instruction,
+	 *   start of the 2nd instruction
+	 * [....]
+	 * - offset[3] - offset of the end of 3rd instruction,
+	 *   start of 4th instruction
+	 */
 	for (i = 0; i < prog->len; i++) {
 		const struct bpf_insn *insn = &prog->insnsi[i];
 		int ret;
 
+		if (ctx->image == NULL)
+			ctx->offset[i] = ctx->idx;
 		ret = build_insn(insn, ctx, extra_pass);
 		if (ret > 0) {
 			i++;
@@ -791,11 +818,16 @@
 				ctx->offset[i] = ctx->idx;
 			continue;
 		}
-		if (ctx->image == NULL)
-			ctx->offset[i] = ctx->idx;
 		if (ret)
 			return ret;
 	}
+	/*
+	 * offset is allocated with prog->len + 1 so fill in
+	 * the last element with the offset after the last
+	 * instruction (end of program)
+	 */
+	if (ctx->image == NULL)
+		ctx->offset[i] = ctx->idx;
 
 	return 0;
 }
@@ -871,21 +903,24 @@
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.prog = prog;
 
-	ctx.offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
+	ctx.offset = kcalloc(prog->len + 1, sizeof(int), GFP_KERNEL);
 	if (ctx.offset == NULL) {
 		prog = orig_prog;
 		goto out_off;
 	}
 
-	/* 1. Initial fake pass to compute ctx->idx. */
-
-	/* Fake pass to fill in ctx->offset. */
-	if (build_body(&ctx, extra_pass)) {
+	/*
+	 * 1. Initial fake pass to compute ctx->idx and ctx->offset.
+	 *
+	 * BPF line info needs ctx->offset[i] to be the offset of
+	 * instruction[i] in jited image, so build prologue first.
+	 */
+	if (build_prologue(&ctx, was_classic)) {
 		prog = orig_prog;
 		goto out_off;
 	}
 
-	if (build_prologue(&ctx, was_classic)) {
+	if (build_body(&ctx, extra_pass)) {
 		prog = orig_prog;
 		goto out_off;
 	}
@@ -938,6 +973,7 @@
 			bpf_jit_binary_free(header);
 			prog->bpf_func = NULL;
 			prog->jited = 0;
+			prog->jited_len = 0;
 			goto out_off;
 		}
 		bpf_jit_binary_lock_ro(header);
@@ -951,7 +987,12 @@
 	prog->jited_len = image_size;
 
 	if (!prog->is_func || extra_pass) {
-		bpf_prog_fill_jited_linfo(prog, ctx.offset);
+		int i;
+
+		/* offset[prog->len] is the size of program */
+		for (i = 0; i <= prog->len; i++)
+			ctx.offset[i] *= AARCH64_INSN_SIZE;
+		bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
 out_off:
 		kfree(ctx.offset);
 		kfree(jit_data);
@@ -964,6 +1005,11 @@
 	return prog;
 }
 
+u64 bpf_jit_alloc_exec_limit(void)
+{
+	return BPF_JIT_REGION_SIZE;
+}
+
 void *bpf_jit_alloc_exec(unsigned long size)
 {
 	return __vmalloc_node_range(size, PAGE_SIZE, BPF_JIT_REGION_START,
--- linux-ein-5.4.0.orig/arch/c6x/mm/dma-coherent.c
+++ linux-ein-5.4.0/arch/c6x/mm/dma-coherent.c
@@ -140,7 +140,7 @@
 		      sizeof(long));
 }
 
-static void c6x_dma_sync(struct device *dev, phys_addr_t paddr, size_t size,
+static void c6x_dma_sync(phys_addr_t paddr, size_t size,
 		enum dma_data_direction dir)
 {
 	BUG_ON(!valid_dma_direction(dir));
@@ -160,14 +160,14 @@
 	}
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	return c6x_dma_sync(dev, paddr, size, dir);
+	return c6x_dma_sync(paddr, size, dir);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	return c6x_dma_sync(dev, paddr, size, dir);
+	return c6x_dma_sync(paddr, size, dir);
 }
--- linux-ein-5.4.0.orig/arch/csky/Kconfig
+++ linux-ein-5.4.0/arch/csky/Kconfig
@@ -36,6 +36,7 @@
 	select GX6605S_TIMER if CPU_CK610
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_COPY_THREAD_TLS
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
@@ -74,7 +75,7 @@
 config CPU_HAS_LDSTEX
 	bool
 	help
-	  For SMP, CPU needs "ldex&stex" instrcutions to atomic operations.
+	  For SMP, CPU needs "ldex&stex" instructions for atomic operations.
 
 config CPU_NEED_TLBSYNC
 	bool
@@ -219,7 +220,7 @@
 	int "Maximum zone order"
 	default "11"
 
-config RAM_BASE
+config DRAM_BASE
 	hex "DRAM start addr (the same with memory-section in dts)"
 	default 0x0
 
--- linux-ein-5.4.0.orig/arch/csky/abiv1/alignment.c
+++ linux-ein-5.4.0/arch/csky/abiv1/alignment.c
@@ -294,7 +294,7 @@
 				__func__, opcode, rz, rx, imm, addr);
 		show_regs(regs);
 		bust_spinlocks(0);
-		do_exit(SIGKILL);
+		make_task_dead(SIGKILL);
 	}
 
 	force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
--- linux-ein-5.4.0.orig/arch/csky/abiv1/inc/abi/entry.h
+++ linux-ein-5.4.0/arch/csky/abiv1/inc/abi/entry.h
@@ -16,14 +16,16 @@
 #define LSAVE_A4	40
 #define LSAVE_A5	44
 
+#define usp ss1
+
 .macro USPTOKSP
-	mtcr	sp, ss1
+	mtcr	sp, usp
 	mfcr	sp, ss0
 .endm
 
 .macro KSPTOUSP
 	mtcr	sp, ss0
-	mfcr	sp, ss1
+	mfcr	sp, usp
 .endm
 
 .macro	SAVE_ALL epc_inc
@@ -45,7 +47,13 @@
 	add	lr, r13
 	stw     lr, (sp, 8)
 
+	mov	lr, sp
+	addi	lr, 32
+	addi	lr, 32
+	addi	lr, 16
+	bt	2f
 	mfcr	lr, ss1
+2:
 	stw     lr, (sp, 16)
 
 	stw     a0, (sp, 20)
@@ -79,9 +87,10 @@
 	ldw     a0, (sp, 12)
 	mtcr    a0, epsr
 	btsti   a0, 31
+	bt      1f
 	ldw     a0, (sp, 16)
 	mtcr	a0, ss1
-
+1:
 	ldw     a0, (sp, 24)
 	ldw     a1, (sp, 28)
 	ldw     a2, (sp, 32)
@@ -102,9 +111,9 @@
 	addi	sp, 32
 	addi	sp, 8
 
-	bt      1f
+	bt      2f
 	KSPTOUSP
-1:
+2:
 	rte
 .endm
 
@@ -158,15 +167,12 @@
 	 *   BA     Reserved  C   D   V
 	 */
 	cprcr	r6, cpcr30
-	lsri	r6, 28
-	lsli	r6, 28
+	lsri	r6, 29
+	lsli	r6, 29
 	addi	r6, 0xe
 	cpwcr	r6, cpcr30
 
-	lsri	r6, 28
-	addi	r6, 2
-	lsli	r6, 28
-	addi	r6, 0xe
+	movi	r6, 0
 	cpwcr	r6, cpcr31
 .endm
 
--- linux-ein-5.4.0.orig/arch/csky/abiv2/fpu.c
+++ linux-ein-5.4.0/arch/csky/abiv2/fpu.c
@@ -10,11 +10,6 @@
 #define MTCR_DIST	0xC0006420
 #define MFCR_DIST	0xC0006020
 
-void __init init_fpu(void)
-{
-	mtcr("cr<1, 2>", 0);
-}
-
 /*
  * fpu_libc_helper() is to help libc to excute:
  *  - mfcr %a, cr<1, 2>
--- linux-ein-5.4.0.orig/arch/csky/abiv2/inc/abi/entry.h
+++ linux-ein-5.4.0/arch/csky/abiv2/inc/abi/entry.h
@@ -13,6 +13,8 @@
 #define LSAVE_A1	28
 #define LSAVE_A2	32
 #define LSAVE_A3	36
+#define LSAVE_A4	40
+#define LSAVE_A5	44
 
 #define KSPTOUSP
 #define USPTOKSP
@@ -31,7 +33,13 @@
 
 	mfcr	lr, epsr
 	stw	lr, (sp, 12)
+	btsti   lr, 31
+	bf      1f
+	addi    lr, sp, 152
+	br	2f
+1:
 	mfcr	lr, usp
+2:
 	stw	lr, (sp, 16)
 
 	stw     a0, (sp, 20)
@@ -64,8 +72,10 @@
 	mtcr	a0, epc
 	ldw	a0, (sp, 12)
 	mtcr	a0, epsr
+	btsti   a0, 31
 	ldw	a0, (sp, 16)
 	mtcr	a0, usp
+	mtcr	a0, ss0
 
 #ifdef CONFIG_CPU_HAS_HILO
 	ldw	a0, (sp, 140)
@@ -86,6 +96,9 @@
 	addi    sp, 40
 	ldm     r16-r30, (sp)
 	addi    sp, 72
+	bf	1f
+	mfcr	sp, ss0
+1:
 	rte
 .endm
 
@@ -214,16 +227,13 @@
 	 */
 	mfcr	r6, cr<30, 15> /* Get MSA0 */
 2:
-	lsri	r6, 28
-	lsli	r6, 28
+	lsri	r6, 29
+	lsli	r6, 29
 	addi	r6, 0x1ce
 	mtcr	r6, cr<30, 15> /* Set MSA0 */
 
-	lsri	r6, 28
-	addi	r6, 2
-	lsli	r6, 28
-	addi	r6, 0x1ce
-	mtcr	r6, cr<31, 15> /* Set MSA1 */
+	movi    r6, 0
+	mtcr	r6, cr<31, 15> /* Clr MSA1 */
 
 	/* enable MMU */
 	mfcr    r6, cr18
--- linux-ein-5.4.0.orig/arch/csky/abiv2/inc/abi/fpu.h
+++ linux-ein-5.4.0/arch/csky/abiv2/inc/abi/fpu.h
@@ -9,7 +9,8 @@
 
 int fpu_libc_helper(struct pt_regs *regs);
 void fpu_fpe(struct pt_regs *regs);
-void __init init_fpu(void);
+
+static inline void init_fpu(void) { mtcr("cr<1, 2>", 0); }
 
 void save_to_user_fp(struct user_fp *user_fp);
 void restore_from_user_fp(struct user_fp *user_fp);
--- linux-ein-5.4.0.orig/arch/csky/include/asm/page.h
+++ linux-ein-5.4.0/arch/csky/include/asm/page.h
@@ -28,7 +28,7 @@
 #define SSEG_SIZE	0x20000000
 #define LOWMEM_LIMIT	(SSEG_SIZE * 2)
 
-#define PHYS_OFFSET_OFFSET (CONFIG_RAM_BASE & (SSEG_SIZE - 1))
+#define PHYS_OFFSET_OFFSET (CONFIG_DRAM_BASE & (SSEG_SIZE - 1))
 
 #ifndef __ASSEMBLY__
 
--- linux-ein-5.4.0.orig/arch/csky/include/asm/processor.h
+++ linux-ein-5.4.0/arch/csky/include/asm/processor.h
@@ -43,6 +43,7 @@
 struct thread_struct {
 	unsigned long  ksp;       /* kernel stack pointer */
 	unsigned long  sr;        /* saved status register */
+	unsigned long  trap_no;   /* saved status register */
 
 	/* FPU regs */
 	struct user_fp __aligned(16) user_fp;
--- linux-ein-5.4.0.orig/arch/csky/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/csky/include/asm/uaccess.h
@@ -254,7 +254,7 @@
 
 extern int __get_user_bad(void);
 
-#define __copy_user(to, from, n)			\
+#define ___copy_to_user(to, from, n)			\
 do {							\
 	int w0, w1, w2, w3;				\
 	asm volatile(					\
@@ -289,31 +289,34 @@
 	"       subi    %0, 4           \n"		\
 	"       br      3b              \n"		\
 	"5:     cmpnei  %0, 0           \n"  /* 1B */   \
-	"       bf      8f              \n"		\
+	"       bf      13f             \n"		\
 	"       ldb     %3, (%2, 0)     \n"		\
 	"6:     stb     %3, (%1, 0)     \n"		\
 	"       addi    %2,  1          \n"		\
 	"       addi    %1,  1          \n"		\
 	"       subi    %0,  1          \n"		\
 	"       br      5b              \n"		\
-	"7:     br      8f              \n"		\
+	"7:     subi	%0,  4          \n"		\
+	"8:     subi	%0,  4          \n"		\
+	"12:    subi	%0,  4          \n"		\
+	"       br      13f             \n"		\
 	".section __ex_table, \"a\"     \n"		\
 	".align   2                     \n"		\
-	".long    2b, 7b                \n"		\
-	".long    9b, 7b                \n"		\
-	".long   10b, 7b                \n"		\
+	".long    2b, 13f               \n"		\
+	".long    4b, 13f               \n"		\
+	".long    6b, 13f               \n"		\
+	".long    9b, 12b               \n"		\
+	".long   10b, 8b                \n"		\
 	".long   11b, 7b                \n"		\
-	".long    4b, 7b                \n"		\
-	".long    6b, 7b                \n"		\
 	".previous                      \n"		\
-	"8:                             \n"		\
+	"13:                            \n"		\
 	: "=r"(n), "=r"(to), "=r"(from), "=r"(w0),	\
 	  "=r"(w1), "=r"(w2), "=r"(w3)			\
 	: "0"(n), "1"(to), "2"(from)			\
 	: "memory");					\
 } while (0)
 
-#define __copy_user_zeroing(to, from, n)		\
+#define ___copy_from_user(to, from, n)			\
 do {							\
 	int tmp;					\
 	int nsave;					\
@@ -356,22 +359,22 @@
 	"       addi    %1,  1          \n"		\
 	"       subi    %0,  1          \n"		\
 	"       br      5b              \n"		\
-	"8:     mov     %3, %0          \n"		\
-	"       movi    %4, 0           \n"		\
-	"9:     stb     %4, (%1, 0)     \n"		\
-	"       addi    %1, 1           \n"		\
-	"       subi    %3, 1           \n"		\
-	"       cmpnei  %3, 0           \n"		\
-	"       bt      9b              \n"		\
-	"       br      7f              \n"		\
+	"8:     stw     %3, (%1, 0)     \n"		\
+	"       subi    %0, 4           \n"		\
+	"       bf      7f              \n"		\
+	"9:     subi    %0, 8           \n"		\
+	"       bf      7f              \n"		\
+	"13:    stw     %3, (%1, 8)     \n"		\
+	"       subi    %0, 12          \n"		\
+	"       bf      7f              \n"		\
 	".section __ex_table, \"a\"     \n"		\
 	".align   2                     \n"		\
-	".long    2b, 8b                \n"		\
+	".long    2b, 7f                \n"		\
+	".long    4b, 7f                \n"		\
+	".long    6b, 7f                \n"		\
 	".long   10b, 8b                \n"		\
-	".long   11b, 8b                \n"		\
-	".long   12b, 8b                \n"		\
-	".long    4b, 8b                \n"		\
-	".long    6b, 8b                \n"		\
+	".long   11b, 9b                \n"		\
+	".long   12b,13b                \n"		\
 	".previous                      \n"		\
 	"7:                             \n"		\
 	: "=r"(n), "=r"(to), "=r"(from), "=r"(nsave),	\
--- linux-ein-5.4.0.orig/arch/csky/include/uapi/asm/unistd.h
+++ linux-ein-5.4.0/arch/csky/include/uapi/asm/unistd.h
@@ -1,7 +1,10 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
 
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_NEW_STAT
 #define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_CLONE3
 #define __ARCH_WANT_SET_GET_RLIMIT
 #define __ARCH_WANT_TIME32_SYSCALLS
 #include <asm-generic/unistd.h>
--- linux-ein-5.4.0.orig/arch/csky/kernel/atomic.S
+++ linux-ein-5.4.0/arch/csky/kernel/atomic.S
@@ -17,10 +17,12 @@
 	mfcr	a3, epc
 	addi	a3, TRAP0_SIZE
 
-	subi    sp, 8
+	subi    sp, 16
 	stw     a3, (sp, 0)
 	mfcr    a3, epsr
 	stw     a3, (sp, 4)
+	mfcr	a3, usp
+	stw     a3, (sp, 8)
 
 	psrset	ee
 #ifdef CONFIG_CPU_HAS_LDSTEX
@@ -47,7 +49,9 @@
 	mtcr	a3, epc
 	ldw     a3, (sp, 4)
 	mtcr	a3, epsr
-	addi	sp, 8
+	ldw     a3, (sp, 8)
+	mtcr	a3, usp
+	addi	sp, 16
 	KSPTOUSP
 	rte
 END(csky_cmpxchg)
--- linux-ein-5.4.0.orig/arch/csky/kernel/entry.S
+++ linux-ein-5.4.0/arch/csky/kernel/entry.S
@@ -170,8 +170,10 @@
 	ldw	a3, (sp, LSAVE_A3)
 #if defined(__CSKYABIV2__)
 	subi	sp, 8
-	stw	r5, (sp, 0x4)
-	stw	r4, (sp, 0x0)
+	ldw	r9, (sp, LSAVE_A4)
+	stw	r9, (sp, 0x0)
+	ldw	r9, (sp, LSAVE_A5)
+	stw	r9, (sp, 0x4)
 #else
 	ldw	r6, (sp, LSAVE_A4)
 	ldw	r7, (sp, LSAVE_A5)
@@ -318,8 +320,6 @@
 
 	mfcr	a2, psr			/* Save PSR value */
 	stw	a2, (a3, THREAD_SR)	/* Save PSR in task struct */
-	bclri	a2, 6			/* Disable interrupts */
-	mtcr	a2, psr
 
 	SAVE_SWITCH_STACK
 
--- linux-ein-5.4.0.orig/arch/csky/kernel/head.S
+++ linux-ein-5.4.0/arch/csky/kernel/head.S
@@ -21,6 +21,11 @@
 ENTRY(_start_smp_secondary)
 	SETUP_MMU
 
+	/* copy msa1 from CPU0 */
+	lrw     r6, secondary_msa1
+	ld.w	r6, (r6, 0)
+	mtcr	r6, cr<31, 15>
+
 	/* set stack point */
 	lrw     r6, secondary_stack
 	ld.w	r6, (r6, 0)
--- linux-ein-5.4.0.orig/arch/csky/kernel/perf_callchain.c
+++ linux-ein-5.4.0/arch/csky/kernel/perf_callchain.c
@@ -12,12 +12,17 @@
 
 static int unwind_frame_kernel(struct stackframe *frame)
 {
-	if (kstack_end((void *)frame->fp))
+	unsigned long low = (unsigned long)task_stack_page(current);
+	unsigned long high = low + THREAD_SIZE;
+
+	if (unlikely(frame->fp < low || frame->fp > high))
 		return -EPERM;
-	if (frame->fp & 0x3 || frame->fp < TASK_SIZE)
+
+	if (kstack_end((void *)frame->fp) || frame->fp & 0x3)
 		return -EPERM;
 
 	*frame = *(struct stackframe *)frame->fp;
+
 	if (__kernel_text_address(frame->lr)) {
 		int graph = 0;
 
@@ -81,10 +86,11 @@
 void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
 			 struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	unsigned long fp = 0;
 
 	/* C-SKY does not support virtualization. */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+	if (guest_cbs && guest_cbs->is_in_guest())
 		return;
 
 	fp = regs->regs[4];
@@ -105,10 +111,11 @@
 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 			   struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct stackframe fr;
 
 	/* C-SKY does not support virtualization. */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		pr_warn("C-SKY does not support perf in guest mode!");
 		return;
 	}
--- linux-ein-5.4.0.orig/arch/csky/kernel/process.c
+++ linux-ein-5.4.0/arch/csky/kernel/process.c
@@ -34,10 +34,11 @@
 	return sw->r15;
 }
 
-int copy_thread(unsigned long clone_flags,
+int copy_thread_tls(unsigned long clone_flags,
 		unsigned long usp,
 		unsigned long kthread_arg,
-		struct task_struct *p)
+		struct task_struct *p,
+		unsigned long tls)
 {
 	struct switch_stack *childstack;
 	struct pt_regs *childregs = task_pt_regs(p);
@@ -64,7 +65,7 @@
 			childregs->usp = usp;
 		if (clone_flags & CLONE_SETTLS)
 			task_thread_info(p)->tp_value = childregs->tls
-						      = childregs->regs[0];
+						      = tls;
 
 		childregs->a0 = 0;
 		childstack->r15 = (unsigned long) ret_from_fork;
--- linux-ein-5.4.0.orig/arch/csky/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/csky/kernel/ptrace.c
@@ -96,7 +96,8 @@
 	if (ret)
 		return ret;
 
-	regs.sr = task_pt_regs(target)->sr;
+	/* BIT(0) of regs.sr is Condition Code/Carry bit */
+	regs.sr = (regs.sr & BIT(0)) | (task_pt_regs(target)->sr & ~BIT(0));
 #ifdef CONFIG_CPU_HAS_HILO
 	regs.dcsr = task_pt_regs(target)->dcsr;
 #endif
--- linux-ein-5.4.0.orig/arch/csky/kernel/setup.c
+++ linux-ein-5.4.0/arch/csky/kernel/setup.c
@@ -24,26 +24,9 @@
 };
 #endif
 
-phys_addr_t __init_memblock memblock_end_of_REG0(void)
-{
-	return (memblock.memory.regions[0].base +
-		memblock.memory.regions[0].size);
-}
-
-phys_addr_t __init_memblock memblock_start_of_REG1(void)
-{
-	return memblock.memory.regions[1].base;
-}
-
-size_t __init_memblock memblock_size_of_REG1(void)
-{
-	return memblock.memory.regions[1].size;
-}
-
 static void __init csky_memblock_init(void)
 {
 	unsigned long zone_size[MAX_NR_ZONES];
-	unsigned long zhole_size[MAX_NR_ZONES];
 	signed long size;
 
 	memblock_reserve(__pa(_stext), _end - _stext);
@@ -57,54 +40,36 @@
 	memblock_dump_all();
 
 	memset(zone_size, 0, sizeof(zone_size));
-	memset(zhole_size, 0, sizeof(zhole_size));
 
 	min_low_pfn = PFN_UP(memblock_start_of_DRAM());
-	max_pfn	    = PFN_DOWN(memblock_end_of_DRAM());
-
-	max_low_pfn = PFN_UP(memblock_end_of_REG0());
-	if (max_low_pfn == 0)
-		max_low_pfn = max_pfn;
+	max_low_pfn = max_pfn = PFN_DOWN(memblock_end_of_DRAM());
 
 	size = max_pfn - min_low_pfn;
 
-	if (memblock.memory.cnt > 1) {
-		zone_size[ZONE_NORMAL]  =
-			PFN_DOWN(memblock_start_of_REG1()) - min_low_pfn;
-		zhole_size[ZONE_NORMAL] =
-			PFN_DOWN(memblock_start_of_REG1()) - max_low_pfn;
+	if (size <= PFN_DOWN(SSEG_SIZE - PHYS_OFFSET_OFFSET))
+		zone_size[ZONE_NORMAL] = size;
+	else if (size < PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET)) {
+		zone_size[ZONE_NORMAL] =
+				PFN_DOWN(SSEG_SIZE - PHYS_OFFSET_OFFSET);
+		max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL];
 	} else {
-		if (size <= PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET))
-			zone_size[ZONE_NORMAL] = max_pfn - min_low_pfn;
-		else {
-			zone_size[ZONE_NORMAL] =
+		zone_size[ZONE_NORMAL] =
 				PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET);
-			max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL];
-		}
+		max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL];
+		write_mmu_msa1(read_mmu_msa0() + SSEG_SIZE);
 	}
 
 #ifdef CONFIG_HIGHMEM
-	size = 0;
-	if (memblock.memory.cnt > 1) {
-		size = PFN_DOWN(memblock_size_of_REG1());
-		highstart_pfn = PFN_DOWN(memblock_start_of_REG1());
-	} else {
-		size = max_pfn - min_low_pfn -
-			PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET);
-		highstart_pfn =  min_low_pfn +
-			PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET);
-	}
-
-	if (size > 0)
-		zone_size[ZONE_HIGHMEM] = size;
+	zone_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
 
-	highend_pfn = max_pfn;
+	highstart_pfn = max_low_pfn;
+	highend_pfn   = max_pfn;
 #endif
 	memblock_set_current_limit(PFN_PHYS(max_low_pfn));
 
 	dma_contiguous_reserve(0);
 
-	free_area_init_node(0, zone_size, min_low_pfn, zhole_size);
+	free_area_init_node(0, zone_size, min_low_pfn, NULL);
 }
 
 void __init setup_arch(char **cmdline_p)
--- linux-ein-5.4.0.orig/arch/csky/kernel/signal.c
+++ linux-ein-5.4.0/arch/csky/kernel/signal.c
@@ -52,10 +52,14 @@
 	struct sigcontext __user *sc)
 {
 	int err = 0;
+	unsigned long sr = regs->sr;
 
 	/* sc_pt_regs is structured the same as the start of pt_regs */
 	err |= __copy_from_user(regs, &sc->sc_pt_regs, sizeof(struct pt_regs));
 
+	/* BIT(0) of regs->sr is Condition Code/Carry bit */
+	regs->sr = (sr & ~1) | (regs->sr & 1);
+
 	/* Restore the floating-point state. */
 	err |= restore_fpu_state(sc);
 
--- linux-ein-5.4.0.orig/arch/csky/kernel/smp.c
+++ linux-ein-5.4.0/arch/csky/kernel/smp.c
@@ -22,6 +22,9 @@
 #include <asm/sections.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
+#ifdef CONFIG_CPU_HAS_FPU
+#include <abi/fpu.h>
+#endif
 
 struct ipi_data_struct {
 	unsigned long bits ____cacheline_aligned;
@@ -120,7 +123,7 @@
 	int rc;
 
 	if (ipi_irq == 0)
-		panic("%s IRQ mapping failed\n", __func__);
+		return;
 
 	rc = request_percpu_irq(ipi_irq, handle_ipi, "IPI Interrupt",
 				&ipi_dummy_dev);
@@ -156,6 +159,8 @@
 volatile unsigned int secondary_ccr;
 volatile unsigned int secondary_stack;
 
+unsigned long secondary_msa1;
+
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
 	unsigned long mask = 1 << cpu;
@@ -164,6 +169,7 @@
 		(unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8;
 	secondary_hint = mfcr("cr31");
 	secondary_ccr  = mfcr("cr18");
+	secondary_msa1 = read_mmu_msa1();
 
 	/*
 	 * Because other CPUs are in reset status, we must flush data
--- linux-ein-5.4.0.orig/arch/csky/kernel/traps.c
+++ linux-ein-5.4.0/arch/csky/kernel/traps.c
@@ -85,7 +85,7 @@
 	pr_err("%s: %08x\n", str, nr);
 	show_regs(regs);
 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 void buserr(struct pt_regs *regs)
@@ -115,8 +115,9 @@
 	int sig;
 	unsigned long vector;
 	siginfo_t info;
+	struct task_struct *tsk = current;
 
-	vector = (mfcr("psr") >> 16) & 0xff;
+	vector = (regs->sr >> 16) & 0xff;
 
 	switch (vector) {
 	case VEC_ZERODIV:
@@ -129,6 +130,7 @@
 		sig = SIGTRAP;
 		break;
 	case VEC_ILLEGAL:
+		tsk->thread.trap_no = vector;
 		die_if_kernel("Kernel mode ILLEGAL", regs, vector);
 #ifndef CONFIG_CPU_NO_USER_BKPT
 		if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT)
@@ -146,16 +148,20 @@
 		sig = SIGTRAP;
 		break;
 	case VEC_ACCESS:
+		tsk->thread.trap_no = vector;
 		return buserr(regs);
 #ifdef CONFIG_CPU_NEED_SOFTALIGN
 	case VEC_ALIGN:
+		tsk->thread.trap_no = vector;
 		return csky_alignment(regs);
 #endif
 #ifdef CONFIG_CPU_HAS_FPU
 	case VEC_FPE:
+		tsk->thread.trap_no = vector;
 		die_if_kernel("Kernel mode FPE", regs, vector);
 		return fpu_fpe(regs);
 	case VEC_PRIV:
+		tsk->thread.trap_no = vector;
 		die_if_kernel("Kernel mode PRIV", regs, vector);
 		if (fpu_libc_helper(regs))
 			return;
@@ -164,5 +170,8 @@
 		sig = SIGSEGV;
 		break;
 	}
+
+	tsk->thread.trap_no = vector;
+
 	send_sig(sig, current, 0);
 }
--- linux-ein-5.4.0.orig/arch/csky/lib/usercopy.c
+++ linux-ein-5.4.0/arch/csky/lib/usercopy.c
@@ -7,10 +7,7 @@
 unsigned long raw_copy_from_user(void *to, const void *from,
 			unsigned long n)
 {
-	if (access_ok(from, n))
-		__copy_user_zeroing(to, from, n);
-	else
-		memset(to, 0, n);
+	___copy_from_user(to, from, n);
 	return n;
 }
 EXPORT_SYMBOL(raw_copy_from_user);
@@ -18,8 +15,7 @@
 unsigned long raw_copy_to_user(void *to, const void *from,
 			unsigned long n)
 {
-	if (access_ok(to, n))
-		__copy_user(to, from, n);
+	___copy_to_user(to, from, n);
 	return n;
 }
 EXPORT_SYMBOL(raw_copy_to_user);
--- linux-ein-5.4.0.orig/arch/csky/mm/Makefile
+++ linux-ein-5.4.0/arch/csky/mm/Makefile
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 ifeq ($(CONFIG_CPU_HAS_CACHEV2),y)
 obj-y +=			cachev2.o
+CFLAGS_REMOVE_cachev2.o = $(CC_FLAGS_FTRACE)
 else
 obj-y +=			cachev1.o
+CFLAGS_REMOVE_cachev1.o = $(CC_FLAGS_FTRACE)
 endif
 
 obj-y +=			dma-mapping.o
--- linux-ein-5.4.0.orig/arch/csky/mm/dma-mapping.c
+++ linux-ein-5.4.0/arch/csky/mm/dma-mapping.c
@@ -58,8 +58,8 @@
 	cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-			      size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
@@ -74,8 +74,8 @@
 	}
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-			   size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
--- linux-ein-5.4.0.orig/arch/csky/mm/fault.c
+++ linux-ein-5.4.0/arch/csky/mm/fault.c
@@ -179,11 +179,14 @@
 bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
 	if (user_mode(regs)) {
+		tsk->thread.trap_no = (regs->sr >> 16) & 0xff;
 		force_sig_fault(SIGSEGV, si_code, (void __user *)address);
 		return;
 	}
 
 no_context:
+	tsk->thread.trap_no = (regs->sr >> 16) & 0xff;
+
 	/* Are we prepared to handle this kernel fault? */
 	if (fixup_exception(regs))
 		return;
@@ -198,6 +201,8 @@
 	die_if_kernel("Oops", regs, write);
 
 out_of_memory:
+	tsk->thread.trap_no = (regs->sr >> 16) & 0xff;
+
 	/*
 	 * We ran out of memory, call the OOM killer, and return the userspace
 	 * (which will retry the fault, or kill us if we got oom-killed).
@@ -206,6 +211,8 @@
 	return;
 
 do_sigbus:
+	tsk->thread.trap_no = (regs->sr >> 16) & 0xff;
+
 	up_read(&mm->mmap_sem);
 
 	/* Kernel mode? Handle exceptions or die */
--- linux-ein-5.4.0.orig/arch/csky/mm/init.c
+++ linux-ein-5.4.0/arch/csky/mm/init.c
@@ -31,6 +31,7 @@
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
 pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss;
+EXPORT_SYMBOL(invalid_pte_table);
 unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
 						__page_aligned_bss;
 EXPORT_SYMBOL(empty_zero_page);
--- linux-ein-5.4.0.orig/arch/h8300/kernel/asm-offsets.c
+++ linux-ein-5.4.0/arch/h8300/kernel/asm-offsets.c
@@ -63,6 +63,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-ein-5.4.0.orig/arch/h8300/kernel/traps.c
+++ linux-ein-5.4.0/arch/h8300/kernel/traps.c
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/task.h>
 #include <linux/mm_types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -110,7 +111,7 @@
 	dump(fp);
 
 	spin_unlock_irq(&die_lock);
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 static int kstack_depth_to_print = 24;
--- linux-ein-5.4.0.orig/arch/h8300/mm/fault.c
+++ linux-ein-5.4.0/arch/h8300/mm/fault.c
@@ -52,7 +52,7 @@
 	printk(" at virtual address %08lx\n", address);
 	if (!user_mode(regs))
 		die("Oops", regs, error_code);
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 
 	return 1;
 }
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/atomic.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/atomic.h
@@ -91,7 +91,7 @@
 		"1:	%0 = memw_locked(%1);\n"			\
 		"	%0 = "#op "(%0,%2);\n"				\
 		"	memw_locked(%1,P3)=%0;\n"			\
-		"	if !P3 jump 1b;\n"				\
+		"	if (!P3) jump 1b;\n"				\
 		: "=&r" (output)					\
 		: "r" (&v->counter), "r" (i)				\
 		: "memory", "p3"					\
@@ -107,7 +107,7 @@
 		"1:	%0 = memw_locked(%1);\n"			\
 		"	%0 = "#op "(%0,%2);\n"				\
 		"	memw_locked(%1,P3)=%0;\n"			\
-		"	if !P3 jump 1b;\n"				\
+		"	if (!P3) jump 1b;\n"				\
 		: "=&r" (output)					\
 		: "r" (&v->counter), "r" (i)				\
 		: "memory", "p3"					\
@@ -124,7 +124,7 @@
 		"1:	%0 = memw_locked(%2);\n"			\
 		"	%1 = "#op "(%0,%3);\n"				\
 		"	memw_locked(%2,P3)=%1;\n"			\
-		"	if !P3 jump 1b;\n"				\
+		"	if (!P3) jump 1b;\n"				\
 		: "=&r" (output), "=&r" (val)				\
 		: "r" (&v->counter), "r" (i)				\
 		: "memory", "p3"					\
@@ -173,7 +173,7 @@
 		"	}"
 		"	memw_locked(%2, p3) = %1;"
 		"	{"
-		"		if !p3 jump 1b;"
+		"		if (!p3) jump 1b;"
 		"	}"
 		"2:"
 		: "=&r" (__oldval), "=&r" (tmp)
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/bitops.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/bitops.h
@@ -38,7 +38,7 @@
 	"1:	R12 = memw_locked(R10);\n"
 	"	{ P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n"
 	"	memw_locked(R10,P1) = R12;\n"
-	"	{if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n"
+	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
 	: "=&r" (oldval)
 	: "r" (addr), "r" (nr)
 	: "r10", "r11", "r12", "p0", "p1", "memory"
@@ -62,7 +62,7 @@
 	"1:	R12 = memw_locked(R10);\n"
 	"	{ P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n"
 	"	memw_locked(R10,P1) = R12;\n"
-	"	{if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n"
+	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
 	: "=&r" (oldval)
 	: "r" (addr), "r" (nr)
 	: "r10", "r11", "r12", "p0", "p1", "memory"
@@ -88,7 +88,7 @@
 	"1:	R12 = memw_locked(R10);\n"
 	"	{ P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n"
 	"	memw_locked(R10,P1) = R12;\n"
-	"	{if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n"
+	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
 	: "=&r" (oldval)
 	: "r" (addr), "r" (nr)
 	: "r10", "r11", "r12", "p0", "p1", "memory"
@@ -223,7 +223,7 @@
 	int r;
 
 	asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n"
-		"{ if P0 %0 = #0; if !P0 %0 = add(%0,#1);}\n"
+		"{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n"
 		: "=&r" (r)
 		: "r" (x)
 		: "p0");
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/cmpxchg.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/cmpxchg.h
@@ -30,7 +30,7 @@
 	__asm__ __volatile__ (
 	"1:	%0 = memw_locked(%1);\n"    /*  load into retval */
 	"	memw_locked(%1,P0) = %2;\n" /*  store into memory */
-	"	if !P0 jump 1b;\n"
+	"	if (!P0) jump 1b;\n"
 	: "=&r" (retval)
 	: "r" (ptr), "r" (x)
 	: "memory", "p0"
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/futex.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/futex.h
@@ -16,7 +16,7 @@
 	    /* For example: %1 = %4 */ \
 	    insn \
 	"2: memw_locked(%3,p2) = %1;\n" \
-	"   if !p2 jump 1b;\n" \
+	"   if (!p2) jump 1b;\n" \
 	"   %1 = #0;\n" \
 	"3:\n" \
 	".section .fixup,\"ax\"\n" \
@@ -84,10 +84,10 @@
 	"1: %1 = memw_locked(%3)\n"
 	"   {\n"
 	"      p2 = cmp.eq(%1,%4)\n"
-	"      if !p2.new jump:NT 3f\n"
+	"      if (!p2.new) jump:NT 3f\n"
 	"   }\n"
 	"2: memw_locked(%3,p2) = %5\n"
-	"   if !p2 jump 1b\n"
+	"   if (!p2) jump 1b\n"
 	"3:\n"
 	".section .fixup,\"ax\"\n"
 	"4: %0 = #%6\n"
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/io.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/io.h
@@ -171,16 +171,10 @@
 #define writew_relaxed __raw_writew
 #define writel_relaxed __raw_writel
 
-/*
- * Need an mtype somewhere in here, for cache type deals?
- * This is probably too long for an inline.
- */
-void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size);
+void __iomem *ioremap(unsigned long phys_addr, unsigned long size);
+#define ioremap_nocache ioremap
+#define ioremap_uc(X, Y) ioremap((X), (Y))
 
-static inline void __iomem *ioremap(unsigned long phys_addr, unsigned long size)
-{
-	return ioremap_nocache(phys_addr, size);
-}
 
 static inline void iounmap(volatile void __iomem *addr)
 {
--- linux-ein-5.4.0.orig/arch/hexagon/include/asm/spinlock.h
+++ linux-ein-5.4.0/arch/hexagon/include/asm/spinlock.h
@@ -30,9 +30,9 @@
 	__asm__ __volatile__(
 		"1:	R6 = memw_locked(%0);\n"
 		"	{ P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n"
-		"	{ if !P3 jump 1b; }\n"
+		"	{ if (!P3) jump 1b; }\n"
 		"	memw_locked(%0,P3) = R6;\n"
-		"	{ if !P3 jump 1b; }\n"
+		"	{ if (!P3) jump 1b; }\n"
 		:
 		: "r" (&lock->lock)
 		: "memory", "r6", "p3"
@@ -46,7 +46,7 @@
 		"1:	R6 = memw_locked(%0);\n"
 		"	R6 = add(R6,#-1);\n"
 		"	memw_locked(%0,P3) = R6\n"
-		"	if !P3 jump 1b;\n"
+		"	if (!P3) jump 1b;\n"
 		:
 		: "r" (&lock->lock)
 		: "memory", "r6", "p3"
@@ -61,7 +61,7 @@
 	__asm__ __volatile__(
 		"	R6 = memw_locked(%1);\n"
 		"	{ %0 = #0; P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n"
-		"	{ if !P3 jump 1f; }\n"
+		"	{ if (!P3) jump 1f; }\n"
 		"	memw_locked(%1,P3) = R6;\n"
 		"	{ %0 = P3 }\n"
 		"1:\n"
@@ -78,9 +78,9 @@
 	__asm__ __volatile__(
 		"1:	R6 = memw_locked(%0)\n"
 		"	{ P3 = cmp.eq(R6,#0);  R6 = #-1;}\n"
-		"	{ if !P3 jump 1b; }\n"
+		"	{ if (!P3) jump 1b; }\n"
 		"	memw_locked(%0,P3) = R6;\n"
-		"	{ if !P3 jump 1b; }\n"
+		"	{ if (!P3) jump 1b; }\n"
 		:
 		: "r" (&lock->lock)
 		: "memory", "r6", "p3"
@@ -94,7 +94,7 @@
 	__asm__ __volatile__(
 		"	R6 = memw_locked(%1)\n"
 		"	{ %0 = #0; P3 = cmp.eq(R6,#0);  R6 = #-1;}\n"
-		"	{ if !P3 jump 1f; }\n"
+		"	{ if (!P3) jump 1f; }\n"
 		"	memw_locked(%1,P3) = R6;\n"
 		"	%0 = P3;\n"
 		"1:\n"
@@ -117,9 +117,9 @@
 	__asm__ __volatile__(
 		"1:	R6 = memw_locked(%0);\n"
 		"	P3 = cmp.eq(R6,#0);\n"
-		"	{ if !P3 jump 1b; R6 = #1; }\n"
+		"	{ if (!P3) jump 1b; R6 = #1; }\n"
 		"	memw_locked(%0,P3) = R6;\n"
-		"	{ if !P3 jump 1b; }\n"
+		"	{ if (!P3) jump 1b; }\n"
 		:
 		: "r" (&lock->lock)
 		: "memory", "r6", "p3"
@@ -139,7 +139,7 @@
 	__asm__ __volatile__(
 		"	R6 = memw_locked(%1);\n"
 		"	P3 = cmp.eq(R6,#0);\n"
-		"	{ if !P3 jump 1f; R6 = #1; %0 = #0; }\n"
+		"	{ if (!P3) jump 1f; R6 = #1; %0 = #0; }\n"
 		"	memw_locked(%1,P3) = R6;\n"
 		"	%0 = P3;\n"
 		"1:\n"
--- linux-ein-5.4.0.orig/arch/hexagon/kernel/dma.c
+++ linux-ein-5.4.0/arch/hexagon/kernel/dma.c
@@ -55,8 +55,8 @@
 	gen_pool_free(coherent_pool, (unsigned long) vaddr, size);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	void *addr = phys_to_virt(paddr);
 
--- linux-ein-5.4.0.orig/arch/hexagon/kernel/hexagon_ksyms.c
+++ linux-ein-5.4.0/arch/hexagon/kernel/hexagon_ksyms.c
@@ -20,7 +20,7 @@
 EXPORT_SYMBOL(__vmsetie);
 EXPORT_SYMBOL(__vmyield);
 EXPORT_SYMBOL(empty_zero_page);
-EXPORT_SYMBOL(ioremap_nocache);
+EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
 
--- linux-ein-5.4.0.orig/arch/hexagon/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/hexagon/kernel/stacktrace.c
@@ -11,8 +11,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;
@@ -30,7 +28,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-ein-5.4.0.orig/arch/hexagon/kernel/traps.c
+++ linux-ein-5.4.0/arch/hexagon/kernel/traps.c
@@ -221,7 +221,7 @@
 		panic("Fatal exception");
 
 	oops_exit();
-	do_exit(err);
+	make_task_dead(err);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/hexagon/kernel/vm_entry.S
+++ linux-ein-5.4.0/arch/hexagon/kernel/vm_entry.S
@@ -369,7 +369,7 @@
 		R26.L = #LO(do_work_pending);
 		R0 = #VM_INT_DISABLE;
 	}
-	if P0 jump check_work_pending
+	if (P0) jump check_work_pending
 	{
 		R0 = R25;
 		callr R24
--- linux-ein-5.4.0.orig/arch/hexagon/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/hexagon/kernel/vmlinux.lds.S
@@ -60,13 +60,8 @@
 
 	_end = .;
 
-	/DISCARD/ : {
-		EXIT_TEXT
-		EXIT_DATA
-		EXIT_CALL
-	}
-
 	STABS_DEBUG
 	DWARF_DEBUG
 
+	DISCARDS
 }
--- linux-ein-5.4.0.orig/arch/hexagon/lib/io.c
+++ linux-ein-5.4.0/arch/hexagon/lib/io.c
@@ -27,6 +27,7 @@
 		*dst++ = *src;
 
 }
+EXPORT_SYMBOL(__raw_readsw);
 
 /*
  * __raw_writesw - read words a short at a time
@@ -47,6 +48,7 @@
 
 
 }
+EXPORT_SYMBOL(__raw_writesw);
 
 /*  Pretty sure len is pre-adjusted for the length of the access already */
 void __raw_readsl(const void __iomem *addr, void *data, int len)
@@ -62,6 +64,7 @@
 
 
 }
+EXPORT_SYMBOL(__raw_readsl);
 
 void __raw_writesl(void __iomem *addr, const void *data, int len)
 {
@@ -76,3 +79,4 @@
 
 
 }
+EXPORT_SYMBOL(__raw_writesl);
--- linux-ein-5.4.0.orig/arch/hexagon/mm/ioremap.c
+++ linux-ein-5.4.0/arch/hexagon/mm/ioremap.c
@@ -9,7 +9,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 
-void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size)
+void __iomem *ioremap(unsigned long phys_addr, unsigned long size)
 {
 	unsigned long last_addr, addr;
 	unsigned long offset = phys_addr & ~PAGE_MASK;
--- linux-ein-5.4.0.orig/arch/ia64/Kconfig
+++ linux-ein-5.4.0/arch/ia64/Kconfig
@@ -8,6 +8,7 @@
 
 config IA64
 	bool
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
 	select ACPI
@@ -360,7 +361,7 @@
 	depends on PROC_KCORE
 
 config IA64_MCA_RECOVERY
-	tristate "MCA recovery from errors other than TLB."
+	bool "MCA recovery from errors other than TLB."
 
 config PERFMON
 	bool "Performance monitor support"
--- linux-ein-5.4.0.orig/arch/ia64/Kconfig.debug
+++ linux-ein-5.4.0/arch/ia64/Kconfig.debug
@@ -39,7 +39,7 @@
 
 config IA64_DEBUG_CMPXCHG
 	bool "Turn on compare-and-exchange bug checking (slow!)"
-	depends on DEBUG_KERNEL
+	depends on DEBUG_KERNEL && PRINTK
 	help
 	  Selecting this option turns on bug checking for the IA-64
 	  compare-and-exchange instructions.  This is slow!  Itaniums
--- linux-ein-5.4.0.orig/arch/ia64/Makefile
+++ linux-ein-5.4.0/arch/ia64/Makefile
@@ -40,7 +40,7 @@
 endif
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = cat $(real-prereqs) | gzip -n -f -9 > $@
+cmd_gzip = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
 
 quiet_cmd_objcopy = OBJCOPY $@
 cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
--- linux-ein-5.4.0.orig/arch/ia64/configs/zx1_defconfig
+++ linux-ein-5.4.0/arch/ia64/configs/zx1_defconfig
@@ -35,7 +35,6 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_CHR_DEV_OSST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/ia64/include/asm/module.h
+++ linux-ein-5.4.0/arch/ia64/include/asm/module.h
@@ -14,16 +14,20 @@
 struct elf64_shdr;			/* forward declration */
 
 struct mod_arch_specific {
+	/* Used only at module load time. */
 	struct elf64_shdr *core_plt;	/* core PLT section */
 	struct elf64_shdr *init_plt;	/* init PLT section */
 	struct elf64_shdr *got;		/* global offset table */
 	struct elf64_shdr *opd;		/* official procedure descriptors */
 	struct elf64_shdr *unwind;	/* unwind-table section */
 	unsigned long gp;		/* global-pointer for module */
+	unsigned int next_got_entry;	/* index of next available got entry */
 
+	/* Used at module run and cleanup time. */
 	void *core_unw_table;		/* core unwind-table cookie returned by unwinder */
 	void *init_unw_table;		/* init unwind-table cookie returned by unwinder */
-	unsigned int next_got_entry;	/* index of next available got entry */
+	void *opd_addr;			/* symbolize uses .opd to get to actual function */
+	unsigned long opd_size;
 };
 
 #define MODULE_PROC_FAMILY	"ia64"
--- linux-ein-5.4.0.orig/arch/ia64/include/asm/processor.h
+++ linux-ein-5.4.0/arch/ia64/include/asm/processor.h
@@ -552,7 +552,7 @@
 {
 	unsigned int reg = vector / 64;
 	unsigned int bit = vector % 64;
-	u64 irr;
+	unsigned long irr;
 
 	switch (reg) {
 	case 0: irr = ia64_getreg(_IA64_REG_CR_IRR0); break;
--- linux-ein-5.4.0.orig/arch/ia64/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/ia64/include/asm/ptrace.h
@@ -54,8 +54,7 @@
 
 static inline unsigned long user_stack_pointer(struct pt_regs *regs)
 {
-	/* FIXME: should this be bspstore + nr_dirty regs? */
-	return regs->ar_bspstore;
+	return regs->r12;
 }
 
 static inline int is_syscall_success(struct pt_regs *regs)
@@ -79,11 +78,6 @@
 	unsigned long __ip = instruction_pointer(regs);			\
 	(__ip & ~3UL) + ((__ip & 3UL) << 2);				\
 })
-/*
- * Why not default?  Because user_stack_pointer() on ia64 gives register
- * stack backing store instead...
- */
-#define current_user_stack_pointer() (current_pt_regs()->r12)
 
   /* given a pointer to a task_struct, return the user's pt_regs */
 # define task_pt_regs(t)		(((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1)
--- linux-ein-5.4.0.orig/arch/ia64/include/asm/syscall.h
+++ linux-ein-5.4.0/arch/ia64/include/asm/syscall.h
@@ -32,7 +32,7 @@
 static inline long syscall_get_error(struct task_struct *task,
 				     struct pt_regs *regs)
 {
-	return regs->r10 == -1 ? regs->r8:0;
+	return regs->r10 == -1 ? -regs->r8:0;
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
--- linux-ein-5.4.0.orig/arch/ia64/include/asm/timex.h
+++ linux-ein-5.4.0/arch/ia64/include/asm/timex.h
@@ -39,6 +39,7 @@
 	ret = ia64_getreg(_IA64_REG_AR_ITC);
 	return ret;
 }
+#define get_cycles get_cycles
 
 extern void ia64_cpu_local_tick (void);
 extern unsigned long long ia64_native_sched_clock (void);
--- linux-ein-5.4.0.orig/arch/ia64/kernel/Makefile
+++ linux-ein-5.4.0/arch/ia64/kernel/Makefile
@@ -41,7 +41,7 @@
 endif
 obj-$(CONFIG_INTEL_IOMMU)	+= pci-dma.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
--- linux-ein-5.4.0.orig/arch/ia64/kernel/acpi.c
+++ linux-ein-5.4.0/arch/ia64/kernel/acpi.c
@@ -448,7 +448,8 @@
 	if (srat_num_cpus == 0) {
 		node_set_online(0);
 		node_cpuid[0].phys_id = hard_smp_processor_id();
-		return;
+		slit_distance(0, 0) = LOCAL_DISTANCE;
+		goto out;
 	}
 
 	/*
@@ -491,7 +492,7 @@
 			for (j = 0; j < MAX_NUMNODES; j++)
 				slit_distance(i, j) = i == j ?
 					LOCAL_DISTANCE : REMOTE_DISTANCE;
-		return;
+		goto out;
 	}
 
 	memset(numa_slit, -1, sizeof(numa_slit));
@@ -516,6 +517,8 @@
 		printk("\n");
 	}
 #endif
+out:
+	node_possible_map = node_online_map;
 }
 #endif				/* CONFIG_ACPI_NUMA */
 
--- linux-ein-5.4.0.orig/arch/ia64/kernel/err_inject.c
+++ linux-ein-5.4.0/arch/ia64/kernel/err_inject.c
@@ -59,7 +59,7 @@
 		char *buf)						\
 {									\
 	u32 cpu=dev->id;						\
-	return sprintf(buf, "%lx\n", name[cpu]);			\
+	return sprintf(buf, "%llx\n", name[cpu]);			\
 }
 
 #define store(name)							\
@@ -86,9 +86,9 @@
 
 #ifdef ERR_INJ_DEBUG
 	printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
-	printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
-	printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
-	printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
+	printk(KERN_DEBUG "err_type_info=%llx,\n", err_type_info[cpu]);
+	printk(KERN_DEBUG "err_struct_info=%llx,\n", err_struct_info[cpu]);
+	printk(KERN_DEBUG "err_data_buffer=%llx, %llx, %llx.\n",
 			  err_data_buffer[cpu].data1,
 			  err_data_buffer[cpu].data2,
 			  err_data_buffer[cpu].data3);
@@ -117,8 +117,8 @@
 
 #ifdef ERR_INJ_DEBUG
 	printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
-	printk(KERN_DEBUG "capabilities=%lx,\n", capabilities[cpu]);
-	printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
+	printk(KERN_DEBUG "capabilities=%llx,\n", capabilities[cpu]);
+	printk(KERN_DEBUG "resources=%llx\n", resources[cpu]);
 #endif
 	return size;
 }
@@ -131,7 +131,7 @@
 			char *buf)
 {
 	unsigned int cpu=dev->id;
-	return sprintf(buf, "%lx\n", phys_addr[cpu]);
+	return sprintf(buf, "%llx\n", phys_addr[cpu]);
 }
 
 static ssize_t
@@ -145,7 +145,7 @@
 	ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL);
 	if (ret<=0) {
 #ifdef ERR_INJ_DEBUG
-		printk("Virtual address %lx is not existing.\n",virt_addr);
+		printk("Virtual address %llx is not existing.\n", virt_addr);
 #endif
 		return -EINVAL;
 	}
@@ -163,7 +163,7 @@
 {
 	unsigned int cpu=dev->id;
 
-	return sprintf(buf, "%lx, %lx, %lx\n",
+	return sprintf(buf, "%llx, %llx, %llx\n",
 			err_data_buffer[cpu].data1,
 			err_data_buffer[cpu].data2,
 			err_data_buffer[cpu].data3);
@@ -178,13 +178,13 @@
 	int ret;
 
 #ifdef ERR_INJ_DEBUG
-	printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
+	printk("write err_data_buffer=[%llx,%llx,%llx] on cpu%d\n",
 		 err_data_buffer[cpu].data1,
 		 err_data_buffer[cpu].data2,
 		 err_data_buffer[cpu].data3,
 		 cpu);
 #endif
-	ret=sscanf(buf, "%lx, %lx, %lx",
+	ret = sscanf(buf, "%llx, %llx, %llx",
 			&err_data_buffer[cpu].data1,
 			&err_data_buffer[cpu].data2,
 			&err_data_buffer[cpu].data3);
--- linux-ein-5.4.0.orig/arch/ia64/kernel/kprobes.c
+++ linux-ein-5.4.0/arch/ia64/kernel/kprobes.c
@@ -411,7 +411,7 @@
 	struct hlist_node *tmp;
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long trampoline_address =
-		((struct fnptr *)kretprobe_trampoline)->ip;
+		(unsigned long)dereference_function_descriptor(kretprobe_trampoline);
 
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
@@ -487,7 +487,7 @@
 	ri->ret_addr = (kprobe_opcode_t *)regs->b0;
 
 	/* Replace the return addr with trampoline addr */
-	regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
+	regs->b0 = (unsigned long)dereference_function_descriptor(kretprobe_trampoline);
 }
 
 /* Check the instruction in the slot is break */
@@ -991,14 +991,14 @@
 int __init arch_init_kprobes(void)
 {
 	trampoline_p.addr =
-		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
+		dereference_function_descriptor(kretprobe_trampoline);
 	return register_kprobe(&trampoline_p);
 }
 
 int __kprobes arch_trampoline_kprobe(struct kprobe *p)
 {
 	if (p->addr ==
-		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip)
+		dereference_function_descriptor(kretprobe_trampoline))
 		return 1;
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/ia64/kernel/mca.c
+++ linux-ein-5.4.0/arch/ia64/kernel/mca.c
@@ -1851,7 +1851,7 @@
 			data = mca_bootmem();
 			first_time = 0;
 		} else
-			data = (void *)__get_free_pages(GFP_KERNEL,
+			data = (void *)__get_free_pages(GFP_ATOMIC,
 							get_order(sz));
 		if (!data)
 			panic("Could not allocate MCA memory for cpu %d\n",
--- linux-ein-5.4.0.orig/arch/ia64/kernel/mca_drv.c
+++ linux-ein-5.4.0/arch/ia64/kernel/mca_drv.c
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/sched/task.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kallsyms.h>
@@ -176,7 +177,7 @@
 	spin_unlock(&mca_bh_lock);
 
 	/* This process is about to be killed itself */
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 }
 
 /**
@@ -343,7 +344,7 @@
 
 	/* - 2 - */
 	sect_min_size = sal_log_sect_min_sizes[0];
-	for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++)
+	for (i = 1; i < ARRAY_SIZE(sal_log_sect_min_sizes); i++)
 		if (sect_min_size > sal_log_sect_min_sizes[i])
 			sect_min_size = sal_log_sect_min_sizes[i];
 
--- linux-ein-5.4.0.orig/arch/ia64/kernel/module.c
+++ linux-ein-5.4.0/arch/ia64/kernel/module.c
@@ -905,9 +905,31 @@
 int
 module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
 {
+	struct mod_arch_specific *mas = &mod->arch;
+
 	DEBUGP("%s: init: entry=%p\n", __func__, mod->init);
-	if (mod->arch.unwind)
+	if (mas->unwind)
 		register_unwind_table(mod);
+
+	/*
+	 * ".opd" was already relocated to the final destination. Store
+	 * it's address for use in symbolizer.
+	 */
+	mas->opd_addr = (void *)mas->opd->sh_addr;
+	mas->opd_size = mas->opd->sh_size;
+
+	/*
+	 * Module relocation was already done at this point. Section
+	 * headers are about to be deleted. Wipe out load-time context.
+	 */
+	mas->core_plt = NULL;
+	mas->init_plt = NULL;
+	mas->got = NULL;
+	mas->opd = NULL;
+	mas->unwind = NULL;
+	mas->gp = 0;
+	mas->next_got_entry = 0;
+
 	return 0;
 }
 
@@ -926,10 +948,9 @@
 
 void *dereference_module_function_descriptor(struct module *mod, void *ptr)
 {
-	Elf64_Shdr *opd = mod->arch.opd;
+	struct mod_arch_specific *mas = &mod->arch;
 
-	if (ptr < (void *)opd->sh_addr ||
-			ptr >= (void *)(opd->sh_addr + opd->sh_size))
+	if (ptr < mas->opd_addr || ptr >= mas->opd_addr + mas->opd_size)
 		return ptr;
 
 	return dereference_function_descriptor(ptr);
--- linux-ein-5.4.0.orig/arch/ia64/kernel/process.c
+++ linux-ein-5.4.0/arch/ia64/kernel/process.c
@@ -444,7 +444,7 @@
 do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
 {
 	unsigned long mask, sp, nat_bits = 0, ar_rnat, urbs_end, cfm;
-	unsigned long uninitialized_var(ip);	/* GCC be quiet */
+	unsigned long ip;
 	elf_greg_t *dst = arg;
 	struct pt_regs *pt;
 	char nat;
--- linux-ein-5.4.0.orig/arch/ia64/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/ia64/kernel/ptrace.c
@@ -2147,27 +2147,39 @@
 {
 	struct syscall_get_set_args *args = data;
 	struct pt_regs *pt = args->regs;
-	unsigned long *krbs, cfm, ndirty;
+	unsigned long *krbs, cfm, ndirty, nlocals, nouts;
 	int i, count;
 
 	if (unw_unwind_to_user(info) < 0)
 		return;
 
+	/*
+	 * We get here via a few paths:
+	 * - break instruction: cfm is shared with caller.
+	 *   syscall args are in out= regs, locals are non-empty.
+	 * - epsinstruction: cfm is set by br.call
+	 *   locals don't exist.
+	 *
+	 * For both cases argguments are reachable in cfm.sof - cfm.sol.
+	 * CFM: [ ... | sor: 17..14 | sol : 13..7 | sof : 6..0 ]
+	 */
 	cfm = pt->cr_ifs;
+	nlocals = (cfm >> 7) & 0x7f; /* aka sol */
+	nouts = (cfm & 0x7f) - nlocals; /* aka sof - sol */
 	krbs = (unsigned long *)info->task + IA64_RBS_OFFSET/8;
 	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
 
 	count = 0;
 	if (in_syscall(pt))
-		count = min_t(int, args->n, cfm & 0x7f);
+		count = min_t(int, args->n, nouts);
 
+	/* Iterate over outs. */
 	for (i = 0; i < count; i++) {
+		int j = ndirty + nlocals + i + args->i;
 		if (args->rw)
-			*ia64_rse_skip_regs(krbs, ndirty + i + args->i) =
-				args->args[i];
+			*ia64_rse_skip_regs(krbs, j) = args->args[i];
 		else
-			args->args[i] = *ia64_rse_skip_regs(krbs,
-				ndirty + i + args->i);
+			args->args[i] = *ia64_rse_skip_regs(krbs, j);
 	}
 
 	if (!args->rw) {
--- linux-ein-5.4.0.orig/arch/ia64/kernel/salinfo.c
+++ linux-ein-5.4.0/arch/ia64/kernel/salinfo.c
@@ -581,7 +581,7 @@
  * 'data' contains an integer that corresponds to the feature we're
  * testing
  */
-static int proc_salinfo_show(struct seq_file *m, void *v)
+static int __maybe_unused proc_salinfo_show(struct seq_file *m, void *v)
 {
 	unsigned long data = (unsigned long)v;
 	seq_puts(m, (sal_platform_features & data) ? "1\n" : "0\n");
--- linux-ein-5.4.0.orig/arch/ia64/kernel/setup.c
+++ linux-ein-5.4.0/arch/ia64/kernel/setup.c
@@ -1073,8 +1073,7 @@
 	}
 }
 
-void __init
-check_bugs (void)
+void __init arch_cpu_finalize_init(void)
 {
 	ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles,
 			       (unsigned long) __end___mckinley_e9_bundles);
--- linux-ein-5.4.0.orig/arch/ia64/kernel/topology.c
+++ linux-ein-5.4.0/arch/ia64/kernel/topology.c
@@ -3,9 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * This file contains NUMA specific variables and functions which can
- * be split away from DISCONTIGMEM and are used on NUMA machines with
- * contiguous memory.
+ * This file contains NUMA specific variables and functions which are used on
+ * NUMA machines with contiguous memory.
  * 		2002/08/07 Erich Focht <efocht@ess.nec.de>
  * Populate cpu entries in sysfs for non-numa systems as well
  *  	Intel Corporation - Ashok Raj
--- linux-ein-5.4.0.orig/arch/ia64/kernel/traps.c
+++ linux-ein-5.4.0/arch/ia64/kernel/traps.c
@@ -85,7 +85,7 @@
 	if (panic_on_oops)
 		panic("Fatal exception");
 
-  	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/ia64/mm/contig.c
+++ linux-ein-5.4.0/arch/ia64/mm/contig.c
@@ -81,7 +81,7 @@
 	return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
 }
 
-static inline void
+static inline __init void
 alloc_per_cpu_data(void)
 {
 	size_t size = PERCPU_PAGE_SIZE * num_possible_cpus();
--- linux-ein-5.4.0.orig/arch/ia64/mm/discontig.c
+++ linux-ein-5.4.0/arch/ia64/mm/discontig.c
@@ -95,7 +95,7 @@
  * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
  * called yet.  Note that node 0 will also count all non-existent cpus.
  */
-static int __meminit early_nr_cpus_node(int node)
+static int early_nr_cpus_node(int node)
 {
 	int cpu, n = 0;
 
@@ -110,7 +110,7 @@
  * compute_pernodesize - compute size of pernode data
  * @node: the node id.
  */
-static unsigned long __meminit compute_pernodesize(int node)
+static unsigned long compute_pernodesize(int node)
 {
 	unsigned long pernodesize = 0, cpus;
 
@@ -180,7 +180,7 @@
 void __init setup_per_cpu_areas(void)
 {
 	struct pcpu_alloc_info *ai;
-	struct pcpu_group_info *uninitialized_var(gi);
+	struct pcpu_group_info *gi;
 	unsigned int *cpu_map;
 	void *base;
 	unsigned long base_offset;
@@ -367,7 +367,7 @@
 	}
 }
 
-static void __meminit scatter_node_data(void)
+static void scatter_node_data(void)
 {
 	pg_data_t **dst;
 	int node;
--- linux-ein-5.4.0.orig/arch/ia64/mm/fault.c
+++ linux-ein-5.4.0/arch/ia64/mm/fault.c
@@ -272,7 +272,7 @@
 		regs = NULL;
 	bust_spinlocks(0);
 	if (regs)
-		do_exit(SIGKILL);
+		make_task_dead(SIGKILL);
 	return;
 
   out_of_memory:
--- linux-ein-5.4.0.orig/arch/ia64/mm/init.c
+++ linux-ein-5.4.0/arch/ia64/mm/init.c
@@ -73,8 +73,8 @@
  * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
  * flush them when they get mapped into an executable vm-area.
  */
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	unsigned long pfn = PHYS_PFN(paddr);
 
@@ -518,7 +518,7 @@
 	if (map_start < map_end)
 		memmap_init_zone((unsigned long)(map_end - map_start),
 				 args->nid, args->zone, page_to_pfn(map_start),
-				 MEMMAP_EARLY, NULL);
+				 MEMINIT_EARLY, NULL);
 	return 0;
 }
 
@@ -527,8 +527,8 @@
 	     unsigned long start_pfn)
 {
 	if (!vmem_map) {
-		memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY,
-				NULL);
+		memmap_init_zone(size, nid, zone, start_pfn,
+				 MEMINIT_EARLY, NULL);
 	} else {
 		struct page *start;
 		struct memmap_init_callback_data args;
@@ -689,9 +689,7 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct zone *zone;
 
-	zone = page_zone(pfn_to_page(start_pfn));
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 }
 #endif
--- linux-ein-5.4.0.orig/arch/ia64/mm/numa.c
+++ linux-ein-5.4.0/arch/ia64/mm/numa.c
@@ -3,9 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * This file contains NUMA specific variables and functions which can
- * be split away from DISCONTIGMEM and are used on NUMA machines with
- * contiguous memory.
+ * This file contains NUMA specific variables and functions which are used on
+ * NUMA machines with contiguous memory.
  * 
  *                         2002/08/07 Erich Focht <efocht@ess.nec.de>
  */
--- linux-ein-5.4.0.orig/arch/ia64/mm/tlb.c
+++ linux-ein-5.4.0/arch/ia64/mm/tlb.c
@@ -369,7 +369,7 @@
 
 void ia64_tlb_init(void)
 {
-	ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */
+	ia64_ptce_info_t ptce_info;
 	u64 tr_pgbits;
 	long status;
 	pal_vm_info_1_u_t vm_info_1;
--- linux-ein-5.4.0.orig/arch/ia64/scripts/unwcheck.py
+++ linux-ein-5.4.0/arch/ia64/scripts/unwcheck.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # SPDX-License-Identifier: GPL-2.0
 #
 # Usage: unwcheck.py FILE
--- linux-ein-5.4.0.orig/arch/m68k/68000/entry.S
+++ linux-ein-5.4.0/arch/m68k/68000/entry.S
@@ -47,6 +47,8 @@
 	jbsr	syscall_trace_enter
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
+	addql	#1,%d0
+	jeq	ret_from_exception
 	movel	%sp@(PT_OFF_ORIG_D0),%d1
 	movel	#-ENOSYS,%d0
 	cmpl	#NR_syscalls,%d1
--- linux-ein-5.4.0.orig/arch/m68k/Kconfig
+++ linux-ein-5.4.0/arch/m68k/Kconfig
@@ -4,6 +4,7 @@
 	default y
 	select ARCH_32BIT_OFF_T
 	select ARCH_HAS_BINFMT_FLAT
+	select ARCH_HAS_CPU_FINALIZE_INIT if MMU
 	select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
 	select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
--- linux-ein-5.4.0.orig/arch/m68k/Kconfig.bus
+++ linux-ein-5.4.0/arch/m68k/Kconfig.bus
@@ -63,7 +63,7 @@
 
 endif
 
-if !MMU
+if COLDFIRE
 
 config ISA_DMA_API
         def_bool !M5272
--- linux-ein-5.4.0.orig/arch/m68k/Kconfig.cpu
+++ linux-ein-5.4.0/arch/m68k/Kconfig.cpu
@@ -309,7 +309,7 @@
 
 config M68KFPU_EMU
 	bool "Math emulation support"
-	depends on MMU
+	depends on M68KCLASSIC && FPU
 	help
 	  At some point in the future, this will cause floating-point math
 	  instructions to be emulated by the kernel on machines that lack a
--- linux-ein-5.4.0.orig/arch/m68k/Kconfig.devices
+++ linux-ein-5.4.0/arch/m68k/Kconfig.devices
@@ -19,6 +19,7 @@
 # We have a dedicated heartbeat LED. :-)
 config PROC_HARDWARE
 	bool "/proc/hardware support"
+	depends on PROC_FS
 	help
 	  Say Y here to support the /proc/hardware file, which gives you
 	  access to information about the machine you're running on,
--- linux-ein-5.4.0.orig/arch/m68k/Kconfig.machine
+++ linux-ein-5.4.0/arch/m68k/Kconfig.machine
@@ -23,6 +23,9 @@
 	  this kernel on an Atari, say Y here and browse the material
 	  available in <file:Documentation/m68k>; otherwise say N.
 
+config ATARI_KBD_CORE
+	bool
+
 config MAC
 	bool "Macintosh support"
 	depends on MMU
@@ -187,6 +190,7 @@
 config MEMORY_RESERVE
 	int "Memory reservation (MiB)"
 	depends on (UCSIMM || UCDIMM)
+	default 0
 	help
 	  Reserve certain memory regions on 68x328 based boards.
 
@@ -316,6 +320,7 @@
 
 config UBOOT
 	bool "Support for U-Boot command line parameters"
+	depends on COLDFIRE
 	help
 	  If you say Y here kernel will try to collect command
 	  line parameters from the initial u-boot stack.
--- linux-ein-5.4.0.orig/arch/m68k/Makefile
+++ linux-ein-5.4.0/arch/m68k/Makefile
@@ -135,10 +135,10 @@
 ifndef CONFIG_KGDB
 	cp vmlinux vmlinux.tmp
 	$(STRIP) vmlinux.tmp
-	gzip -9c vmlinux.tmp >vmlinux.gz
+	$(KGZIP) -9c vmlinux.tmp >vmlinux.gz
 	rm vmlinux.tmp
 else
-	gzip -9c vmlinux >vmlinux.gz
+	$(KGZIP) -9c vmlinux >vmlinux.gz
 endif
 
 bzImage: vmlinux.bz2
@@ -148,10 +148,10 @@
 ifndef CONFIG_KGDB
 	cp vmlinux vmlinux.tmp
 	$(STRIP) vmlinux.tmp
-	bzip2 -1c vmlinux.tmp >vmlinux.bz2
+	$(KBZIP2) -1c vmlinux.tmp >vmlinux.bz2
 	rm vmlinux.tmp
 else
-	bzip2 -1c vmlinux >vmlinux.bz2
+	$(KBZIP2) -1c vmlinux >vmlinux.bz2
 endif
 
 archclean:
--- linux-ein-5.4.0.orig/arch/m68k/coldfire/entry.S
+++ linux-ein-5.4.0/arch/m68k/coldfire/entry.S
@@ -92,6 +92,8 @@
 	jbsr	syscall_trace_enter
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
+	addql	#1,%d0
+	jeq	ret_from_exception
 	movel	%d3,%a0
 	jbsr	%a0@
 	movel	%d0,%sp@(PT_OFF_D0)		/* save the return value */
--- linux-ein-5.4.0.orig/arch/m68k/coldfire/pci.c
+++ linux-ein-5.4.0/arch/m68k/coldfire/pci.c
@@ -216,8 +216,10 @@
 
 	/* Keep a virtual mapping to IO/config space active */
 	iospace = (unsigned long) ioremap(PCI_IO_PA, PCI_IO_SIZE);
-	if (iospace == 0)
+	if (iospace == 0) {
+		pci_free_host_bridge(bridge);
 		return -ENODEV;
+	}
 	pr_info("Coldfire: PCI IO/config window mapped to 0x%x\n",
 		(u32) iospace);
 
--- linux-ein-5.4.0.orig/arch/m68k/configs/amiga_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/amiga_defconfig
@@ -334,7 +334,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/apollo_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/apollo_defconfig
@@ -319,7 +319,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/atari_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/atari_defconfig
@@ -334,7 +334,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/bvme6000_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/bvme6000_defconfig
@@ -316,7 +316,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/hp300_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/hp300_defconfig
@@ -318,7 +318,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/mac_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/mac_defconfig
@@ -325,7 +325,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/multi_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/multi_defconfig
@@ -358,7 +358,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/mvme147_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/mvme147_defconfig
@@ -315,7 +315,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/mvme16x_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/mvme16x_defconfig
@@ -316,7 +316,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/q40_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/q40_defconfig
@@ -324,7 +324,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/sun3_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/sun3_defconfig
@@ -313,7 +313,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/configs/sun3x_defconfig
+++ linux-ein-5.4.0/arch/m68k/configs/sun3x_defconfig
@@ -313,7 +313,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
--- linux-ein-5.4.0.orig/arch/m68k/emu/nfeth.c
+++ linux-ein-5.4.0/arch/m68k/emu/nfeth.c
@@ -254,8 +254,8 @@
 
 	for (i = 0; i < MAX_UNIT; i++) {
 		if (nfeth_dev[i]) {
-			unregister_netdev(nfeth_dev[0]);
-			free_netdev(nfeth_dev[0]);
+			unregister_netdev(nfeth_dev[i]);
+			free_netdev(nfeth_dev[i]);
 		}
 	}
 	free_irq(nfEtherIRQ, nfeth_interrupt);
--- linux-ein-5.4.0.orig/arch/m68k/fpsp040/skeleton.S
+++ linux-ein-5.4.0/arch/m68k/fpsp040/skeleton.S
@@ -499,12 +499,12 @@
 	dbf	%d0,morein
 	rts
 
-	.section .fixup,#alloc,#execinstr
+	.section .fixup,"ax"
 	.even
 1:
 	jbra	fpsp040_die
 
-	.section __ex_table,#alloc
+	.section __ex_table,"a"
 	.align	4
 
 	.long	in_ea,1b
--- linux-ein-5.4.0.orig/arch/m68k/ifpsp060/os.S
+++ linux-ein-5.4.0/arch/m68k/ifpsp060/os.S
@@ -379,11 +379,11 @@
 
 
 | Execption handling for movs access to illegal memory
-	.section .fixup,#alloc,#execinstr
+	.section .fixup,"ax"
 	.even
 1:	moveq		#-1,%d1
 	rts
-.section __ex_table,#alloc
+.section __ex_table,"a"
 	.align 4
 	.long	dmrbuae,1b
 	.long	dmrwuae,1b
--- linux-ein-5.4.0.orig/arch/m68k/include/asm/m53xxacr.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/m53xxacr.h
@@ -89,9 +89,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-ein-5.4.0.orig/arch/m68k/include/asm/mac_via.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/mac_via.h
@@ -257,6 +257,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-ein-5.4.0.orig/arch/m68k/include/asm/mvme147hw.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/mvme147hw.h
@@ -66,6 +66,9 @@
 #define PCC_INT_ENAB		0x08
 
 #define PCC_TIMER_INT_CLR	0x80
+
+#define PCC_TIMER_TIC_EN	0x01
+#define PCC_TIMER_COC_EN	0x02
 #define PCC_TIMER_CLR_OVF	0x04
 
 #define PCC_LEVEL_ABORT		0x07
--- linux-ein-5.4.0.orig/arch/m68k/include/asm/pgtable_no.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/pgtable_no.h
@@ -42,7 +42,8 @@
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-#define ZERO_PAGE(vaddr)	(virt_to_page(0))
+extern void *empty_zero_page;
+#define ZERO_PAGE(vaddr)	(virt_to_page(empty_zero_page))
 
 /*
  * All 32bit addresses are effectively valid for vmalloc...
--- linux-ein-5.4.0.orig/arch/m68k/include/asm/raw_io.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/raw_io.h
@@ -17,21 +17,21 @@
  * two accesses to memory, which may be undesirable for some devices.
  */
 #define in_8(addr) \
-    ({ u8 __v = (*(__force volatile u8 *) (addr)); __v; })
+    ({ u8 __v = (*(__force volatile u8 *) (unsigned long)(addr)); __v; })
 #define in_be16(addr) \
-    ({ u16 __v = (*(__force volatile u16 *) (addr)); __v; })
+    ({ u16 __v = (*(__force volatile u16 *) (unsigned long)(addr)); __v; })
 #define in_be32(addr) \
-    ({ u32 __v = (*(__force volatile u32 *) (addr)); __v; })
+    ({ u32 __v = (*(__force volatile u32 *) (unsigned long)(addr)); __v; })
 #define in_le16(addr) \
-    ({ u16 __v = le16_to_cpu(*(__force volatile __le16 *) (addr)); __v; })
+    ({ u16 __v = le16_to_cpu(*(__force volatile __le16 *) (unsigned long)(addr)); __v; })
 #define in_le32(addr) \
-    ({ u32 __v = le32_to_cpu(*(__force volatile __le32 *) (addr)); __v; })
+    ({ u32 __v = le32_to_cpu(*(__force volatile __le32 *) (unsigned long)(addr)); __v; })
 
-#define out_8(addr,b) (void)((*(__force volatile u8 *) (addr)) = (b))
-#define out_be16(addr,w) (void)((*(__force volatile u16 *) (addr)) = (w))
-#define out_be32(addr,l) (void)((*(__force volatile u32 *) (addr)) = (l))
-#define out_le16(addr,w) (void)((*(__force volatile __le16 *) (addr)) = cpu_to_le16(w))
-#define out_le32(addr,l) (void)((*(__force volatile __le32 *) (addr)) = cpu_to_le32(l))
+#define out_8(addr,b) (void)((*(__force volatile u8 *) (unsigned long)(addr)) = (b))
+#define out_be16(addr,w) (void)((*(__force volatile u16 *) (unsigned long)(addr)) = (w))
+#define out_be32(addr,l) (void)((*(__force volatile u32 *) (unsigned long)(addr)) = (l))
+#define out_le16(addr,w) (void)((*(__force volatile __le16 *) (unsigned long)(addr)) = cpu_to_le16(w))
+#define out_le32(addr,l) (void)((*(__force volatile __le32 *) (unsigned long)(addr)) = cpu_to_le32(l))
 
 #define raw_inb in_8
 #define raw_inw in_be16
--- linux-ein-5.4.0.orig/arch/m68k/include/asm/timex.h
+++ linux-ein-5.4.0/arch/m68k/include/asm/timex.h
@@ -35,7 +35,7 @@
 {
 	if (mach_random_get_entropy)
 		return mach_random_get_entropy();
-	return 0;
+	return random_get_entropy_fallback();
 }
 #define random_get_entropy	random_get_entropy
 
--- linux-ein-5.4.0.orig/arch/m68k/kernel/dma.c
+++ linux-ein-5.4.0/arch/m68k/kernel/dma.c
@@ -61,8 +61,8 @@
 
 #endif /* CONFIG_MMU && !CONFIG_COLDFIRE */
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t handle,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t handle, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_BIDIRECTIONAL:
--- linux-ein-5.4.0.orig/arch/m68k/kernel/entry.S
+++ linux-ein-5.4.0/arch/m68k/kernel/entry.S
@@ -160,9 +160,12 @@
 	jbsr	syscall_trace
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
+	addql	#1,%d0			| optimization for cmpil #-1,%d0
+	jeq	ret_from_syscall
 	movel	%sp@(PT_OFF_ORIG_D0),%d0
 	cmpl	#NR_syscalls,%d0
 	jcs	syscall
+	jra	ret_from_syscall
 badsys:
 	movel	#-ENOSYS,%sp@(PT_OFF_D0)
 	jra	ret_from_syscall
--- linux-ein-5.4.0.orig/arch/m68k/kernel/relocate_kernel.S
+++ linux-ein-5.4.0/arch/m68k/kernel/relocate_kernel.S
@@ -26,7 +26,7 @@
 	lea %pc@(.Lcopy),%a4
 2:	addl #0x00000000,%a4		/* virt_to_phys() */
 
-	.section ".m68k_fixup","aw"
+	.section .m68k_fixup,"aw"
 	.long M68K_FIXUP_MEMOFFSET, 2b+2
 	.previous
 
@@ -49,7 +49,7 @@
 	lea %pc@(.Lcont040),%a4
 5:	addl #0x00000000,%a4		/* virt_to_phys() */
 
-	.section ".m68k_fixup","aw"
+	.section .m68k_fixup,"aw"
 	.long M68K_FIXUP_MEMOFFSET, 5b+2
 	.previous
 
--- linux-ein-5.4.0.orig/arch/m68k/kernel/setup_mm.c
+++ linux-ein-5.4.0/arch/m68k/kernel/setup_mm.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/cpu.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
@@ -527,7 +528,7 @@
 module_init(proc_hardware_init);
 #endif
 
-void check_bugs(void)
+void __init arch_cpu_finalize_init(void)
 {
 #if defined(CONFIG_FPU) && !defined(CONFIG_M68KFPU_EMU)
 	if (m68k_fputype == 0) {
--- linux-ein-5.4.0.orig/arch/m68k/kernel/setup_no.c
+++ linux-ein-5.4.0/arch/m68k/kernel/setup_no.c
@@ -139,7 +139,8 @@
 	pr_debug("MEMORY -> ROMFS=0x%p-0x%06lx MEM=0x%06lx-0x%06lx\n ",
 		 __bss_stop, memory_start, memory_start, memory_end);
 
-	memblock_add(memory_start, memory_end - memory_start);
+	memblock_add(_rambase, memory_end - _rambase);
+	memblock_reserve(_rambase, memory_start - _rambase);
 
 	/* Keep a copy of command line */
 	*cmdline_p = &command_line[0];
--- linux-ein-5.4.0.orig/arch/m68k/kernel/signal.c
+++ linux-ein-5.4.0/arch/m68k/kernel/signal.c
@@ -448,7 +448,7 @@
 
 	if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
 		fpu_version = sc->sc_fpstate[0];
-		if (CPU_IS_020_OR_030 &&
+		if (CPU_IS_020_OR_030 && !regs->stkadj &&
 		    regs->vector >= (VEC_FPBRUC * 4) &&
 		    regs->vector <= (VEC_FPNAN * 4)) {
 			/* Clear pending exception in 68882 idle frame */
@@ -511,7 +511,7 @@
 		if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
 			context_size = fpstate[1];
 		fpu_version = fpstate[0];
-		if (CPU_IS_020_OR_030 &&
+		if (CPU_IS_020_OR_030 && !regs->stkadj &&
 		    regs->vector >= (VEC_FPBRUC * 4) &&
 		    regs->vector <= (VEC_FPNAN * 4)) {
 			/* Clear pending exception in 68882 idle frame */
@@ -829,18 +829,24 @@
 	return 0;
 }
 
+static inline struct pt_regs *rte_regs(struct pt_regs *regs)
+{
+	return (void *)regs + regs->stkadj;
+}
+
 static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 			     unsigned long mask)
 {
+	struct pt_regs *tregs = rte_regs(regs);
 	sc->sc_mask = mask;
 	sc->sc_usp = rdusp();
 	sc->sc_d0 = regs->d0;
 	sc->sc_d1 = regs->d1;
 	sc->sc_a0 = regs->a0;
 	sc->sc_a1 = regs->a1;
-	sc->sc_sr = regs->sr;
-	sc->sc_pc = regs->pc;
-	sc->sc_formatvec = regs->format << 12 | regs->vector;
+	sc->sc_sr = tregs->sr;
+	sc->sc_pc = tregs->pc;
+	sc->sc_formatvec = tregs->format << 12 | tregs->vector;
 	save_a5_state(sc, regs);
 	save_fpu_state(sc, regs);
 }
@@ -848,6 +854,7 @@
 static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
 {
 	struct switch_stack *sw = (struct switch_stack *)regs - 1;
+	struct pt_regs *tregs = rte_regs(regs);
 	greg_t __user *gregs = uc->uc_mcontext.gregs;
 	int err = 0;
 
@@ -868,43 +875,50 @@
 	err |= __put_user(sw->a5, &gregs[13]);
 	err |= __put_user(sw->a6, &gregs[14]);
 	err |= __put_user(rdusp(), &gregs[15]);
-	err |= __put_user(regs->pc, &gregs[16]);
-	err |= __put_user(regs->sr, &gregs[17]);
-	err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+	err |= __put_user(tregs->pc, &gregs[16]);
+	err |= __put_user(tregs->sr, &gregs[17]);
+	err |= __put_user((tregs->format << 12) | tregs->vector, &uc->uc_formatvec);
 	err |= rt_save_fpu_state(uc, regs);
 	return err;
 }
 
 static inline void __user *
-get_sigframe(struct ksignal *ksig, size_t frame_size)
+get_sigframe(struct ksignal *ksig, struct pt_regs *tregs, size_t frame_size)
 {
 	unsigned long usp = sigsp(rdusp(), ksig);
+	unsigned long gap = 0;
+
+	if (CPU_IS_020_OR_030 && tregs->format == 0xb) {
+		/* USP is unreliable so use worst-case value */
+		gap = 256;
+	}
 
-	return (void __user *)((usp - frame_size) & -8UL);
+	return (void __user *)((usp - gap - frame_size) & -8UL);
 }
 
 static int setup_frame(struct ksignal *ksig, sigset_t *set,
 			struct pt_regs *regs)
 {
 	struct sigframe __user *frame;
-	int fsize = frame_extra_sizes(regs->format);
+	struct pt_regs *tregs = rte_regs(regs);
+	int fsize = frame_extra_sizes(tregs->format);
 	struct sigcontext context;
 	int err = 0, sig = ksig->sig;
 
 	if (fsize < 0) {
 		pr_debug("setup_frame: Unknown frame format %#x\n",
-			 regs->format);
+			 tregs->format);
 		return -EFAULT;
 	}
 
-	frame = get_sigframe(ksig, sizeof(*frame) + fsize);
+	frame = get_sigframe(ksig, tregs, sizeof(*frame) + fsize);
 
 	if (fsize)
 		err |= copy_to_user (frame + 1, regs + 1, fsize);
 
 	err |= __put_user(sig, &frame->sig);
 
-	err |= __put_user(regs->vector, &frame->code);
+	err |= __put_user(tregs->vector, &frame->code);
 	err |= __put_user(&frame->sc, &frame->psc);
 
 	if (_NSIG_WORDS > 1)
@@ -930,33 +944,27 @@
 	push_cache ((unsigned long) &frame->retcode);
 
 	/*
-	 * Set up registers for signal handler.  All the state we are about
-	 * to destroy is successfully copied to sigframe.
-	 */
-	wrusp ((unsigned long) frame);
-	regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
-	adjustformat(regs);
-
-	/*
 	 * This is subtle; if we build more than one sigframe, all but the
 	 * first one will see frame format 0 and have fsize == 0, so we won't
 	 * screw stkadj.
 	 */
-	if (fsize)
+	if (fsize) {
 		regs->stkadj = fsize;
-
-	/* Prepare to skip over the extra stuff in the exception frame.  */
-	if (regs->stkadj) {
-		struct pt_regs *tregs =
-			(struct pt_regs *)((ulong)regs + regs->stkadj);
+		tregs = rte_regs(regs);
 		pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
-		/* This must be copied with decreasing addresses to
-                   handle overlaps.  */
 		tregs->vector = 0;
 		tregs->format = 0;
-		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
+
+	/*
+	 * Set up registers for signal handler.  All the state we are about
+	 * to destroy is successfully copied to sigframe.
+	 */
+	wrusp ((unsigned long) frame);
+	tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
+	adjustformat(regs);
+
 	return 0;
 }
 
@@ -964,7 +972,8 @@
 			   struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
-	int fsize = frame_extra_sizes(regs->format);
+	struct pt_regs *tregs = rte_regs(regs);
+	int fsize = frame_extra_sizes(tregs->format);
 	int err = 0, sig = ksig->sig;
 
 	if (fsize < 0) {
@@ -973,7 +982,7 @@
 		return -EFAULT;
 	}
 
-	frame = get_sigframe(ksig, sizeof(*frame));
+	frame = get_sigframe(ksig, tregs, sizeof(*frame));
 
 	if (fsize)
 		err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
@@ -1014,33 +1023,26 @@
 	push_cache ((unsigned long) &frame->retcode);
 
 	/*
-	 * Set up registers for signal handler.  All the state we are about
-	 * to destroy is successfully copied to sigframe.
-	 */
-	wrusp ((unsigned long) frame);
-	regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
-	adjustformat(regs);
-
-	/*
 	 * This is subtle; if we build more than one sigframe, all but the
 	 * first one will see frame format 0 and have fsize == 0, so we won't
 	 * screw stkadj.
 	 */
-	if (fsize)
+	if (fsize) {
 		regs->stkadj = fsize;
-
-	/* Prepare to skip over the extra stuff in the exception frame.  */
-	if (regs->stkadj) {
-		struct pt_regs *tregs =
-			(struct pt_regs *)((ulong)regs + regs->stkadj);
+		tregs = rte_regs(regs);
 		pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
-		/* This must be copied with decreasing addresses to
-                   handle overlaps.  */
 		tregs->vector = 0;
 		tregs->format = 0;
-		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
+
+	/*
+	 * Set up registers for signal handler.  All the state we are about
+	 * to destroy is successfully copied to sigframe.
+	 */
+	wrusp ((unsigned long) frame);
+	tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
+	adjustformat(regs);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/m68k/kernel/traps.c
+++ linux-ein-5.4.0/arch/m68k/kernel/traps.c
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/ptrace.h>
 #include <linux/kallsyms.h>
+#include <linux/extable.h>
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
@@ -550,7 +551,8 @@
 			errorcode |= 2;
 
 		if (mmusr & (MMU_I | MMU_WP)) {
-			if (ssw & 4) {
+			/* We might have an exception table for this PC */
+			if (ssw & 4 && !search_exception_tables(fp->ptregs.pc)) {
 				pr_err("Data %s fault at %#010lx in %s (pc=%#lx)\n",
 				       ssw & RW ? "read" : "write",
 				       fp->un.fmtb.daddr,
@@ -1139,7 +1141,7 @@
 	pr_crit("%s: %08x\n", str, nr);
 	show_registers(fp);
 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 asmlinkage void set_esp0(unsigned long ssp)
--- linux-ein-5.4.0.orig/arch/m68k/mac/config.c
+++ linux-ein-5.4.0/arch/m68k/mac/config.c
@@ -59,7 +59,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);
@@ -130,21 +129,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)
@@ -175,9 +159,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-ein-5.4.0.orig/arch/m68k/mac/iop.c
+++ linux-ein-5.4.0/arch/m68k/mac/iop.c
@@ -183,7 +183,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)
@@ -191,14 +191,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)
@@ -244,7 +239,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;
@@ -256,7 +250,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 @@
 	msg->status = IOP_MSGSTATUS_UNUSED;
 	msg = msg->next;
 	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);
 }
 
 /*
@@ -490,16 +485,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-ein-5.4.0.orig/arch/m68k/mac/via.c
+++ linux-ein-5.4.0/arch/m68k/mac/via.c
@@ -294,10 +294,14 @@
  * 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);
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/m68k/mm/fault.c
+++ linux-ein-5.4.0/arch/m68k/mm/fault.c
@@ -48,7 +48,7 @@
 			pr_alert("Unable to handle kernel access");
 		pr_cont(" at virtual address %p\n", addr);
 		die_if_kernel("Oops", regs, 0 /*error_code*/);
-		do_exit(SIGKILL);
+		make_task_dead(SIGKILL);
 	}
 
 	return 1;
--- linux-ein-5.4.0.orig/arch/m68k/mm/mcfmmu.c
+++ linux-ein-5.4.0/arch/m68k/mm/mcfmmu.c
@@ -164,7 +164,7 @@
 	m68k_memory[0].addr = _rambase;
 	m68k_memory[0].size = _ramend - _rambase;
 
-	memblock_add(m68k_memory[0].addr, m68k_memory[0].size);
+	memblock_add_node(m68k_memory[0].addr, m68k_memory[0].size, 0);
 
 	/* compute total pages in system */
 	num_pages = PFN_DOWN(_ramend - _rambase);
--- linux-ein-5.4.0.orig/arch/m68k/mvme147/config.c
+++ linux-ein-5.4.0/arch/m68k/mvme147/config.c
@@ -117,8 +117,10 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
-	m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF;
+	m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN |
+			     PCC_TIMER_TIC_EN;
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR |
+				 PCC_LEVEL_TIMER1;
 	clk_total += PCC_TIMER_CYCLES;
 	timer_routine(0, NULL);
 	local_irq_restore(flags);
@@ -136,10 +138,10 @@
 	/* Init the clock with a value */
 	/* The clock counter increments until 0xFFFF then reloads */
 	m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
-	m147_pcc->t1_cntrl = 0x0;	/* clear timer */
-	m147_pcc->t1_cntrl = 0x3;	/* start timer */
-	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  /* clear pending ints */
-	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+	m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN |
+			     PCC_TIMER_TIC_EN;
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR |
+				 PCC_LEVEL_TIMER1;
 
 	clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ);
 }
--- linux-ein-5.4.0.orig/arch/m68k/mvme16x/config.c
+++ linux-ein-5.4.0/arch/m68k/mvme16x/config.c
@@ -368,6 +368,7 @@
 #define PCCTOVR1_COC_EN      0x02
 #define PCCTOVR1_OVR_CLR     0x04
 
+#define PCCTIC1_INT_LEVEL    6
 #define PCCTIC1_INT_CLR      0x08
 #define PCCTIC1_INT_EN       0x10
 
@@ -377,8 +378,8 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	out_8(PCCTIC1, in_8(PCCTIC1) | PCCTIC1_INT_CLR);
-	out_8(PCCTOVR1, PCCTOVR1_OVR_CLR);
+	out_8(PCCTOVR1, PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN);
+	out_8(PCCTIC1, PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL);
 	clk_total += PCC_TIMER_CYCLES;
 	timer_routine(0, NULL);
 	local_irq_restore(flags);
@@ -392,14 +393,15 @@
     int irq;
 
     /* Using PCCchip2 or MC2 chip tick timer 1 */
-    out_be32(PCCTCNT1, 0);
-    out_be32(PCCTCMP1, PCC_TIMER_CYCLES);
-    out_8(PCCTOVR1, in_8(PCCTOVR1) | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN);
-    out_8(PCCTIC1, PCCTIC1_INT_EN | 6);
     if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, IRQF_TIMER, "timer",
                     timer_routine))
 	panic ("Couldn't register timer int");
 
+    out_be32(PCCTCNT1, 0);
+    out_be32(PCCTCMP1, PCC_TIMER_CYCLES);
+    out_8(PCCTOVR1, PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN);
+    out_8(PCCTIC1, PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL);
+
     clocksource_register_hz(&mvme16x_clk, PCC_TIMER_CLOCK_FREQ);
 
     if (brdno == 0x0162 || brdno == 0x172)
--- linux-ein-5.4.0.orig/arch/m68k/q40/config.c
+++ linux-ein-5.4.0/arch/m68k/q40/config.c
@@ -264,6 +264,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-ein-5.4.0.orig/arch/microblaze/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/microblaze/include/asm/uaccess.h
@@ -171,27 +171,27 @@
 
 #define __get_user(x, ptr)						\
 ({									\
-	unsigned long __gu_val = 0;					\
 	long __gu_err;							\
 	switch (sizeof(*(ptr))) {					\
 	case 1:								\
-		__get_user_asm("lbu", (ptr), __gu_val, __gu_err);	\
+		__get_user_asm("lbu", (ptr), x, __gu_err);		\
 		break;							\
 	case 2:								\
-		__get_user_asm("lhu", (ptr), __gu_val, __gu_err);	\
+		__get_user_asm("lhu", (ptr), x, __gu_err);		\
 		break;							\
 	case 4:								\
-		__get_user_asm("lw", (ptr), __gu_val, __gu_err);	\
+		__get_user_asm("lw", (ptr), x, __gu_err);		\
 		break;							\
-	case 8:								\
-		__gu_err = __copy_from_user(&__gu_val, ptr, 8);		\
-		if (__gu_err)						\
-			__gu_err = -EFAULT;				\
+	case 8: {							\
+		__u64 __x = 0;						\
+		__gu_err = raw_copy_from_user(&__x, ptr, 8) ?		\
+							-EFAULT : 0;	\
+		(x) = (typeof(x))(typeof((x) - (x)))__x;		\
 		break;							\
+	}								\
 	default:							\
 		/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
 	}								\
-	x = (__force __typeof__(*(ptr))) __gu_val;			\
 	__gu_err;							\
 })
 
--- linux-ein-5.4.0.orig/arch/microblaze/kernel/cpu/cache.c
+++ linux-ein-5.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-ein-5.4.0.orig/arch/microblaze/kernel/dma.c
+++ linux-ein-5.4.0/arch/microblaze/kernel/dma.c
@@ -15,7 +15,7 @@
 #include <linux/bug.h>
 #include <asm/cacheflush.h>
 
-static void __dma_sync(struct device *dev, phys_addr_t paddr, size_t size,
+static void __dma_sync(phys_addr_t paddr, size_t size,
 		enum dma_data_direction direction)
 {
 	switch (direction) {
@@ -31,14 +31,14 @@
 	}
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	__dma_sync(dev, paddr, size, dir);
+	__dma_sync(paddr, size, dir);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	__dma_sync(dev, paddr, size, dir);
+	__dma_sync(paddr, size, dir);
 }
--- linux-ein-5.4.0.orig/arch/microblaze/kernel/exceptions.c
+++ linux-ein-5.4.0/arch/microblaze/kernel/exceptions.c
@@ -44,10 +44,10 @@
 	pr_warn("Oops: %s, sig: %ld\n", str, err);
 	show_regs(fp);
 	spin_unlock_irq(&die_lock);
-	/* do_exit() should take care of panic'ing from an interrupt
+	/* make_task_dead() should take care of panic'ing from an interrupt
 	 * context so we don't handle it here
 	 */
-	do_exit(err);
+	make_task_dead(err);
 }
 
 /* for user application debugging */
--- linux-ein-5.4.0.orig/arch/mips/Kconfig
+++ linux-ein-5.4.0/arch/mips/Kconfig
@@ -5,6 +5,7 @@
 	select ARCH_32BIT_OFF_T if !64BIT
 	select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT
 	select ARCH_CLOCKSOURCE_DATA
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAS_UBSAN_SANITIZE_ALL
 	select ARCH_SUPPORTS_UPROBES
@@ -46,7 +47,8 @@
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES
 	select HAVE_ASM_MODVERSIONS
-	select HAVE_EBPF_JIT if (!CPU_MICROMIPS)
+	select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
+	select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2
 	select HAVE_CONTEXT_TRACKING
 	select HAVE_COPY_THREAD_TLS
 	select HAVE_C_RECORDMCOUNT
@@ -293,6 +295,9 @@
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select SYS_HAS_EARLY_PRINTK
+	select SYS_HAS_CPU_BMIPS32_3300
+	select SYS_HAS_CPU_BMIPS4350
+	select SYS_HAS_CPU_BMIPS4380
 	select SWAP_IO_SPACE
 	select GPIOLIB
 	select HAVE_CLK
@@ -862,6 +867,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
@@ -1391,6 +1397,7 @@
 	select WEAK_REORDERING_BEYOND_LLSC
 	select MIPS_PGD_C0_CONTEXT
 	select MIPS_L1_CACHE_SHIFT_6
+	select MIPS_FP_SUPPORT
 	select GPIOLIB
 	select SWIOTLB
 	help
@@ -3053,7 +3060,7 @@
 config PGTABLE_LEVELS
 	int
 	default 4 if PAGE_SIZE_4KB && MIPS_VA_BITS_48
-	default 3 if 64BIT && !PAGE_SIZE_64KB
+	default 3 if 64BIT && (!PAGE_SIZE_64KB || MIPS_VA_BITS_48)
 	default 2
 
 config MIPS_AUTO_PFN_OFFSET
--- linux-ein-5.4.0.orig/arch/mips/Makefile
+++ linux-ein-5.4.0/arch/mips/Makefile
@@ -285,12 +285,23 @@
   endif
 endif
 
+# When linking a 32-bit executable the LLVM linker cannot cope with a
+# 32-bit load address that has been sign-extended to 64 bits.  Simply
+# remove the upper 32 bits then, as it is safe to do so with other
+# linkers.
+ifdef CONFIG_64BIT
+	load-ld			= $(load-y)
+else
+	load-ld			= $(subst 0xffffffff,0x,$(load-y))
+endif
+
 KBUILD_AFLAGS	+= $(cflags-y)
 KBUILD_CFLAGS	+= $(cflags-y)
-KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y)
+KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) -DLINKER_LOAD_ADDRESS=$(load-ld)
 KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
 
 bootvars-y	= VMLINUX_LOAD_ADDRESS=$(load-y) \
+		  LINKER_LOAD_ADDRESS=$(load-ld) \
 		  VMLINUX_ENTRY_ADDRESS=$(entry-y) \
 		  PLATFORM="$(platform-y)" \
 		  ITS_INPUTS="$(its-y)"
@@ -309,7 +320,7 @@
 
 ifdef CONFIG_MIPS
 CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
-	egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \
+	egrep -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \
 	sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g')
 endif
 
--- linux-ein-5.4.0.orig/arch/mips/Makefile.postlink
+++ linux-ein-5.4.0/arch/mips/Makefile.postlink
@@ -12,7 +12,7 @@
 include scripts/Kbuild.include
 
 CMD_RELOCS = arch/mips/boot/tools/relocs
-quiet_cmd_relocs = RELOCS $@
+quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(CMD_RELOCS) $@
 
 # `@true` prevents complaint when there is nothing to be done
--- linux-ein-5.4.0.orig/arch/mips/alchemy/board-xxs1500.c
+++ linux-ein-5.4.0/arch/mips/alchemy/board-xxs1500.c
@@ -18,6 +18,7 @@
 #include <asm/reboot.h>
 #include <asm/setup.h>
 #include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/gpio-au1000.h>
 #include <prom.h>
 
 const char *get_system_type(void)
--- linux-ein-5.4.0.orig/arch/mips/alchemy/common/clock.c
+++ linux-ein-5.4.0/arch/mips/alchemy/common/clock.c
@@ -152,6 +152,7 @@
 {
 	struct clk_init_data id;
 	struct clk_hw *h;
+	struct clk *clk;
 
 	h = kzalloc(sizeof(*h), GFP_KERNEL);
 	if (!h)
@@ -164,7 +165,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-ein-5.4.0.orig/arch/mips/alchemy/devboards/db1000.c
+++ linux-ein-5.4.0/arch/mips/alchemy/devboards/db1000.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
@@ -165,14 +164,10 @@
 
 /******************************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
 {
-	void (*mmc_cd)(struct mmc_host *, unsigned long);
-	/* link against CONFIG_MMC=m */
-	mmc_cd = symbol_get(mmc_detect_change);
-	mmc_cd(ptr, msecs_to_jiffies(500));
-	symbol_put(mmc_detect_change);
-
+	mmc_detect_change(ptr, msecs_to_jiffies(500));
 	return IRQ_HANDLED;
 }
 
@@ -375,6 +370,7 @@
 	.num_resources	= ARRAY_SIZE(au1100_mmc1_res),
 	.resource	= au1100_mmc1_res,
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /******************************************************************************/
 
@@ -438,8 +434,10 @@
 
 static struct platform_device *db1100_devs[] = {
 	&au1100_lcd_device,
+#ifdef CONFIG_MMC_AU1X
 	&db1100_mmc0_dev,
 	&db1100_mmc1_dev,
+#endif
 };
 
 int __init db1000_dev_setup(void)
--- linux-ein-5.4.0.orig/arch/mips/alchemy/devboards/db1200.c
+++ linux-ein-5.4.0/arch/mips/alchemy/devboards/db1200.c
@@ -10,7 +10,6 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/leds.h>
@@ -327,6 +326,7 @@
 
 /**********************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 /* SD carddetects:  they're supposed to be edge-triggered, but ack
  * doesn't seem to work (CPLD Rev 2).  Instead, the screaming one
  * is disabled and its counterpart enabled.  The 200ms timeout is
@@ -340,14 +340,7 @@
 
 static irqreturn_t db1200_mmc_cdfn(int irq, void *ptr)
 {
-	void (*mmc_cd)(struct mmc_host *, unsigned long);
-
-	/* link against CONFIG_MMC=m */
-	mmc_cd = symbol_get(mmc_detect_change);
-	if (mmc_cd) {
-		mmc_cd(ptr, msecs_to_jiffies(200));
-		symbol_put(mmc_detect_change);
-	}
+	mmc_detect_change(ptr, msecs_to_jiffies(200));
 
 	msleep(100);	/* debounce */
 	if (irq == DB1200_SD0_INSERT_INT)
@@ -431,14 +424,7 @@
 
 static irqreturn_t pb1200_mmc1_cdfn(int irq, void *ptr)
 {
-	void (*mmc_cd)(struct mmc_host *, unsigned long);
-
-	/* link against CONFIG_MMC=m */
-	mmc_cd = symbol_get(mmc_detect_change);
-	if (mmc_cd) {
-		mmc_cd(ptr, msecs_to_jiffies(200));
-		symbol_put(mmc_detect_change);
-	}
+	mmc_detect_change(ptr, msecs_to_jiffies(200));
 
 	msleep(100);	/* debounce */
 	if (irq == PB1200_SD1_INSERT_INT)
@@ -599,6 +585,7 @@
 	.num_resources	= ARRAY_SIZE(au1200_mmc1_res),
 	.resource	= au1200_mmc1_res,
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /**********************************************************************/
 
@@ -766,7 +753,9 @@
 static struct platform_device *db1200_devs[] __initdata = {
 	NULL,		/* PSC0, selected by S6.8 */
 	&db1200_ide_dev,
+#ifdef CONFIG_MMC_AU1X
 	&db1200_mmc0_dev,
+#endif
 	&au1200_lcd_dev,
 	&db1200_eth_dev,
 	&db1200_nand_dev,
@@ -777,7 +766,9 @@
 };
 
 static struct platform_device *pb1200_devs[] __initdata = {
+#ifdef CONFIG_MMC_AU1X
 	&pb1200_mmc1_dev,
+#endif
 };
 
 /* Some peripheral base addresses differ on the PB1200 */
@@ -856,7 +847,7 @@
 	i2c_register_board_info(0, db1200_i2c_devs,
 				ARRAY_SIZE(db1200_i2c_devs));
 	spi_register_board_info(db1200_spi_devs,
-				ARRAY_SIZE(db1200_i2c_devs));
+				ARRAY_SIZE(db1200_spi_devs));
 
 	/* SWITCHES:	S6.8 I2C/SPI selector  (OFF=I2C	 ON=SPI)
 	 *		S6.7 AC97/I2S selector (OFF=AC97 ON=I2S)
--- linux-ein-5.4.0.orig/arch/mips/alchemy/devboards/db1300.c
+++ linux-ein-5.4.0/arch/mips/alchemy/devboards/db1300.c
@@ -17,7 +17,6 @@
 #include <linux/interrupt.h>
 #include <linux/ata_platform.h>
 #include <linux/mmc/host.h>
-#include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/platnand.h>
 #include <linux/platform_device.h>
@@ -451,6 +450,7 @@
 
 /**********************************************************************/
 
+#ifdef CONFIG_MMC_AU1X
 static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
 {
 	disable_irq_nosync(irq);
@@ -459,14 +459,7 @@
 
 static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr)
 {
-	void (*mmc_cd)(struct mmc_host *, unsigned long);
-
-	/* link against CONFIG_MMC=m.  We can only be called once MMC core has
-	 * initialized the controller, so symbol_get() should always succeed.
-	 */
-	mmc_cd = symbol_get(mmc_detect_change);
-	mmc_cd(ptr, msecs_to_jiffies(200));
-	symbol_put(mmc_detect_change);
+	mmc_detect_change(ptr, msecs_to_jiffies(200));
 
 	msleep(100);	/* debounce */
 	if (irq == DB1300_SD1_INSERT_INT)
@@ -640,6 +633,7 @@
 	.resource	= au1300_sd0_res,
 	.num_resources	= ARRAY_SIZE(au1300_sd0_res),
 };
+#endif /* CONFIG_MMC_AU1X */
 
 /**********************************************************************/
 
@@ -777,8 +771,10 @@
 	&db1300_5waysw_dev,
 	&db1300_nand_dev,
 	&db1300_ide_dev,
+#ifdef CONFIG_MMC_AU1X
 	&db1300_sd0_dev,
 	&db1300_sd1_dev,
+#endif
 	&db1300_lcd_dev,
 	&db1300_ac97_dev,
 	&db1300_i2s_dev,
--- linux-ein-5.4.0.orig/arch/mips/alchemy/devboards/db1550.c
+++ linux-ein-5.4.0/arch/mips/alchemy/devboards/db1550.c
@@ -588,7 +588,7 @@
 	i2c_register_board_info(0, db1550_i2c_devs,
 				ARRAY_SIZE(db1550_i2c_devs));
 	spi_register_board_info(db1550_spi_devs,
-				ARRAY_SIZE(db1550_i2c_devs));
+				ARRAY_SIZE(db1550_spi_devs));
 
 	c = clk_get(NULL, "psc0_intclk");
 	if (!IS_ERR(c)) {
--- linux-ein-5.4.0.orig/arch/mips/bcm47xx/Kconfig
+++ linux-ein-5.4.0/arch/mips/bcm47xx/Kconfig
@@ -27,6 +27,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-ein-5.4.0.orig/arch/mips/bcm47xx/prom.c
+++ linux-ein-5.4.0/arch/mips/bcm47xx/prom.c
@@ -85,7 +85,7 @@
 			pr_debug("Assume 128MB RAM\n");
 			break;
 		}
-		if (!memcmp(prom_init, prom_init + mem, 32))
+		if (!memcmp((void *)prom_init, (void *)prom_init + mem, 32))
 			break;
 	}
 	lowmem = mem;
@@ -162,7 +162,7 @@
 
 	off = EXTVBASE + __pa(off);
 	for (extmem = 128 << 20; extmem < 512 << 20; extmem <<= 1) {
-		if (!memcmp(prom_init, (void *)(off + extmem), 16))
+		if (!memcmp((void *)prom_init, (void *)(off + extmem), 16))
 			break;
 	}
 	extmem -= lowmem;
--- linux-ein-5.4.0.orig/arch/mips/bcm63xx/clk.c
+++ linux-ein-5.4.0/arch/mips/bcm63xx/clk.c
@@ -361,6 +361,8 @@
  */
 int clk_enable(struct clk *clk)
 {
+	if (!clk)
+		return 0;
 	mutex_lock(&clocks_mutex);
 	clk_enable_unlocked(clk);
 	mutex_unlock(&clocks_mutex);
@@ -381,6 +383,18 @@
 
 EXPORT_SYMBOL(clk_disable);
 
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return NULL;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
 unsigned long clk_get_rate(struct clk *clk)
 {
 	if (!clk)
--- linux-ein-5.4.0.orig/arch/mips/bmips/dma.c
+++ linux-ein-5.4.0/arch/mips/bmips/dma.c
@@ -64,7 +64,9 @@
 	return dma_addr;
 }
 
-void arch_sync_dma_for_cpu_all(struct device *dev)
+bool bmips_rac_flush_disable;
+
+void arch_sync_dma_for_cpu_all(void)
 {
 	void __iomem *cbr = BMIPS_GET_CBR();
 	u32 cfg;
@@ -74,6 +76,9 @@
 	    boot_cpu_type() != CPU_BMIPS4380)
 		return;
 
+	if (unlikely(bmips_rac_flush_disable))
+		return;
+
 	/* Flush stale data out of the readahead cache */
 	cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
 	__raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
--- linux-ein-5.4.0.orig/arch/mips/bmips/setup.c
+++ linux-ein-5.4.0/arch/mips/bmips/setup.c
@@ -34,6 +34,8 @@
 #define REG_BCM6328_OTP		((void __iomem *)CKSEG1ADDR(0x1000062c))
 #define BCM6328_TP1_DISABLED	BIT(9)
 
+extern bool bmips_rac_flush_disable;
+
 static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
 
 struct bmips_quirk {
@@ -103,6 +105,12 @@
 	 * disable SMP for now
 	 */
 	bmips_smp_enabled = 0;
+
+	/*
+	 * RAC flush causes kernel panics on BCM6358 when booting from TP1
+	 * because the bootloader is not initializing it properly.
+	 */
+	bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31));
 }
 
 static void bcm6368_quirks(void)
@@ -167,7 +175,7 @@
 		dtb = phys_to_virt(fw_arg2);
 	else if (fw_passed_dtb) /* UHI interface or appended dtb */
 		dtb = (void *)fw_passed_dtb;
-	else if (__dtb_start != __dtb_end)
+	else if (&__dtb_start != &__dtb_end)
 		dtb = (void *)__dtb_start;
 	else
 		panic("no dtb found");
--- linux-ein-5.4.0.orig/arch/mips/boot/Makefile
+++ linux-ein-5.4.0/arch/mips/boot/Makefile
@@ -123,7 +123,7 @@
 targets += vmlinux.its
 targets += vmlinux.gz.its
 targets += vmlinux.bz2.its
-targets += vmlinux.lzmo.its
+targets += vmlinux.lzma.its
 targets += vmlinux.lzo.its
 
 quiet_cmd_cpp_its_S = ITS     $@
--- linux-ein-5.4.0.orig/arch/mips/boot/compressed/Makefile
+++ linux-ein-5.4.0/arch/mips/boot/compressed/Makefile
@@ -29,8 +29,11 @@
 	-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
 	-DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS)
 
+# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
+KCOV_INSTRUMENT		:= n
+
 # decompressor objects (linked with vmlinuz)
-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/bswapsi.o
 
 ifdef CONFIG_DEBUG_ZBOOT
 vmlinuzobjs-$(CONFIG_DEBUG_ZBOOT)		   += $(obj)/dbg.o
@@ -44,7 +47,7 @@
 $(obj)/uart-ath79.c: $(srctree)/arch/mips/ath79/early_printk.c
 	$(call cmd,shipped)
 
-vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o $(obj)/bswapsi.o
+vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o
 
 extra-y += ashldi3.c
 $(obj)/ashldi3.c: $(obj)/%.c: $(srctree)/lib/%.c FORCE
@@ -87,7 +90,7 @@
 VMLINUZ_LOAD_ADDRESS := $(zload-y)
 else
 VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
-		$(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
+		$(obj)/vmlinux.bin $(LINKER_LOAD_ADDRESS))
 endif
 UIMAGE_LOADADDR = $(VMLINUZ_LOAD_ADDRESS)
 
--- linux-ein-5.4.0.orig/arch/mips/boot/compressed/decompress.c
+++ linux-ein-5.4.0/arch/mips/boot/compressed/decompress.c
@@ -7,12 +7,15 @@
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  */
 
+#define DISABLE_BRANCH_PROFILING
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/libfdt.h>
 
 #include <asm/addrspace.h>
+#include <asm/unaligned.h>
 
 /*
  * These two variables specify the free mem region
@@ -113,7 +116,7 @@
 		dtb_size = fdt_totalsize((void *)&__appended_dtb);
 
 		/* last four bytes is always image size in little endian */
-		image_size = le32_to_cpup((void *)&__image_end - 4);
+		image_size = get_unaligned_le32((void *)&__image_end - 4);
 
 		/* copy dtb to where the booted kernel will expect it */
 		memcpy((void *)VMLINUX_LOAD_ADDRESS_ULL + image_size,
--- linux-ein-5.4.0.orig/arch/mips/boot/compressed/string.c
+++ linux-ein-5.4.0/arch/mips/boot/compressed/string.c
@@ -5,6 +5,7 @@
  * Very small subset of simple string routines
  */
 
+#include <linux/compiler_attributes.h>
 #include <linux/types.h>
 
 void *memcpy(void *dest, const void *src, size_t n)
@@ -27,3 +28,19 @@
 		ss[i] = c;
 	return s;
 }
+
+void * __weak memmove(void *dest, const void *src, size_t n)
+{
+	unsigned int i;
+	const char *s = src;
+	char *d = dest;
+
+	if ((uintptr_t)dest < (uintptr_t)src) {
+		for (i = 0; i < n; i++)
+			d[i] = s[i];
+	} else {
+		for (i = n; i > 0; i--)
+			d[i - 1] = s[i - 1];
+	}
+	return dest;
+}
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/brcm/bcm3368.dtsi
+++ linux-ein-5.4.0/arch/mips/boot/dts/brcm/bcm3368.dtsi
@@ -59,7 +59,7 @@
 
 		periph_cntl: syscon@fff8c008 {
 			compatible = "syscon";
-			reg = <0xfff8c000 0x4>;
+			reg = <0xfff8c008 0x4>;
 			native-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/brcm/bcm63268.dtsi
+++ linux-ein-5.4.0/arch/mips/boot/dts/brcm/bcm63268.dtsi
@@ -59,7 +59,7 @@
 
 		periph_cntl: syscon@10000008 {
 			compatible = "syscon";
-			reg = <0x10000000 0xc>;
+			reg = <0x10000008 0x4>;
 			native-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/brcm/bcm6358.dtsi
+++ linux-ein-5.4.0/arch/mips/boot/dts/brcm/bcm6358.dtsi
@@ -59,7 +59,7 @@
 
 		periph_cntl: syscon@fffe0008 {
 			compatible = "syscon";
-			reg = <0xfffe0000 0x4>;
+			reg = <0xfffe0008 0x4>;
 			native-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/brcm/bcm6362.dtsi
+++ linux-ein-5.4.0/arch/mips/boot/dts/brcm/bcm6362.dtsi
@@ -59,7 +59,7 @@
 
 		periph_cntl: syscon@10000008 {
 			compatible = "syscon";
-			reg = <0x10000000 0xc>;
+			reg = <0x10000008 0x4>;
 			native-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/brcm/bcm6368.dtsi
+++ linux-ein-5.4.0/arch/mips/boot/dts/brcm/bcm6368.dtsi
@@ -59,7 +59,7 @@
 
 		periph_cntl: syscon@100000008 {
 			compatible = "syscon";
-			reg = <0x10000000 0xc>;
+			reg = <0x10000008 0x4>;
 			native-endian;
 		};
 
--- linux-ein-5.4.0.orig/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ linux-ein-5.4.0/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -69,7 +69,7 @@
 			"Speaker", "OUTL",
 			"Speaker", "OUTR",
 			"INL", "LOUT",
-			"INL", "ROUT";
+			"INR", "ROUT";
 
 		simple-audio-card,aux-devs = <&amp>;
 
--- linux-ein-5.4.0.orig/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
+++ linux-ein-5.4.0/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
@@ -211,7 +211,7 @@
 {
 	cvmx_helper_link_info_t result;
 
-	WARN(!octeon_is_simulation(),
+	WARN_ONCE(!octeon_is_simulation(),
 	     "Using deprecated link status - please update your DT");
 
 	/* Unless we fix it later, all links are defaulted to down */
--- linux-ein-5.4.0.orig/arch/mips/cavium-octeon/executive/cvmx-helper.c
+++ linux-ein-5.4.0/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -1100,7 +1100,7 @@
 		if (index == 0)
 			result = __cvmx_helper_rgmii_link_get(ipd_port);
 		else {
-			WARN(1, "Using deprecated link status - please update your DT");
+			WARN_ONCE(1, "Using deprecated link status - please update your DT");
 			result.s.full_duplex = 1;
 			result.s.link_up = 1;
 			result.s.speed = 1000;
--- linux-ein-5.4.0.orig/arch/mips/cavium-octeon/octeon-irq.c
+++ linux-ein-5.4.0/arch/mips/cavium-octeon/octeon-irq.c
@@ -127,6 +127,16 @@
 static int octeon_irq_force_ciu_mapping(struct irq_domain *domain,
 					int irq, int line, int bit)
 {
+	struct device_node *of_node;
+	int ret;
+
+	of_node = irq_domain_get_of_node(domain);
+	if (!of_node)
+		return -EINVAL;
+	ret = irq_alloc_desc_at(irq, of_node_to_nid(of_node));
+	if (ret < 0)
+		return ret;
+
 	return irq_domain_associate(domain, irq, line << 6 | bit);
 }
 
@@ -2199,6 +2209,9 @@
 	}
 
 	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+	if (!cd)
+		return -ENOMEM;
+
 	cd->host_data = host_data;
 	cd->bit = hw;
 
--- linux-ein-5.4.0.orig/arch/mips/cavium-octeon/octeon-platform.c
+++ linux-ein-5.4.0/arch/mips/cavium-octeon/octeon-platform.c
@@ -86,11 +86,12 @@
 					 "refclk-frequency", &clock_rate);
 		if (i) {
 			dev_err(dev, "No UCTL \"refclk-frequency\"\n");
+			of_node_put(uctl_node);
 			goto exit;
 		}
 		i = of_property_read_string(uctl_node,
 					    "refclk-type", &clock_type);
-
+		of_node_put(uctl_node);
 		if (!i && strcmp("crystal", clock_type) == 0)
 			is_crystal_clock = true;
 	}
@@ -328,6 +329,7 @@
 
 	pd->dev.platform_data = &octeon_ehci_pdata;
 	octeon_ehci_hw_start(&pd->dev);
+	put_device(&pd->dev);
 
 	return ret;
 }
@@ -391,6 +393,7 @@
 
 	pd->dev.platform_data = &octeon_ohci_pdata;
 	octeon_ohci_hw_start(&pd->dev);
+	put_device(&pd->dev);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/arch/mips/cavium-octeon/octeon-usb.c
+++ linux-ein-5.4.0/arch/mips/cavium-octeon/octeon-usb.c
@@ -518,6 +518,7 @@
 
 			res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 			if (res == NULL) {
+				put_device(&pdev->dev);
 				dev_err(&pdev->dev, "No memory resources\n");
 				return -ENXIO;
 			}
@@ -529,8 +530,10 @@
 			 * know the difference.
 			 */
 			base = devm_ioremap_resource(&pdev->dev, res);
-			if (IS_ERR(base))
+			if (IS_ERR(base)) {
+				put_device(&pdev->dev);
 				return PTR_ERR(base);
+			}
 
 			mutex_lock(&dwc3_octeon_clocks_mutex);
 			dwc3_octeon_clocks_start(&pdev->dev, (u64)base);
@@ -541,6 +544,7 @@
 			devm_iounmap(&pdev->dev, base);
 			devm_release_mem_region(&pdev->dev, res->start,
 						resource_size(res));
+			put_device(&pdev->dev);
 		}
 	} while (node != NULL);
 
--- linux-ein-5.4.0.orig/arch/mips/configs/bigsur_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/bigsur_defconfig
@@ -112,7 +112,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_CHR_DEV_SCH=m
 CONFIG_ATA=y
--- linux-ein-5.4.0.orig/arch/mips/configs/decstation_64_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/decstation_64_defconfig
@@ -53,8 +53,6 @@
 CONFIG_NETWORK_SECMARK=y
 CONFIG_IP_SCTP=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
-CONFIG_DECNET_ROUTER=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 # CONFIG_FW_LOADER is not set
--- linux-ein-5.4.0.orig/arch/mips/configs/decstation_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/decstation_defconfig
@@ -49,8 +49,6 @@
 CONFIG_NETWORK_SECMARK=y
 CONFIG_IP_SCTP=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
-CONFIG_DECNET_ROUTER=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 # CONFIG_FW_LOADER is not set
--- linux-ein-5.4.0.orig/arch/mips/configs/decstation_r4k_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/decstation_r4k_defconfig
@@ -48,8 +48,6 @@
 CONFIG_NETWORK_SECMARK=y
 CONFIG_IP_SCTP=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
-CONFIG_DECNET_ROUTER=y
 # CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 # CONFIG_FW_LOADER is not set
--- linux-ein-5.4.0.orig/arch/mips/configs/fuloong2e_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/fuloong2e_defconfig
@@ -99,7 +99,6 @@
 CONFIG_ATA_OVER_ETH=m
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOWLEVEL is not set
--- linux-ein-5.4.0.orig/arch/mips/configs/gpr_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/gpr_defconfig
@@ -69,7 +69,6 @@
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -99,7 +98,6 @@
 CONFIG_ATM_BR2684=m
 CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
 CONFIG_LLC2=m
 CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
--- linux-ein-5.4.0.orig/arch/mips/configs/ip27_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/ip27_defconfig
@@ -99,7 +99,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_CHR_DEV_SCH=m
 CONFIG_SCSI_CONSTANTS=y
--- linux-ein-5.4.0.orig/arch/mips/configs/ip32_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/ip32_defconfig
@@ -50,7 +50,6 @@
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/mips/configs/jazz_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/jazz_defconfig
@@ -106,7 +106,6 @@
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -127,7 +126,6 @@
 CONFIG_BRIDGE_EBT_SNAT=m
 CONFIG_BRIDGE_EBT_LOG=m
 CONFIG_BRIDGE=m
-CONFIG_DECNET=m
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
@@ -191,7 +189,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/mips/configs/loongson3_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/loongson3_defconfig
@@ -231,7 +231,7 @@
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_DRM=y
-CONFIG_DRM_RADEON=y
+CONFIG_DRM_RADEON=m
 CONFIG_FB_RADEON=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=m
--- linux-ein-5.4.0.orig/arch/mips/configs/malta_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/malta_defconfig
@@ -239,7 +239,6 @@
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/mips/configs/malta_kvm_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/malta_kvm_defconfig
@@ -247,7 +247,6 @@
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/mips/configs/malta_kvm_guest_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/malta_kvm_guest_defconfig
@@ -245,7 +245,6 @@
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/mips/configs/maltaup_xpa_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/maltaup_xpa_defconfig
@@ -245,7 +245,6 @@
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
--- linux-ein-5.4.0.orig/arch/mips/configs/mtx1_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/mtx1_defconfig
@@ -117,7 +117,6 @@
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -147,7 +146,6 @@
 CONFIG_ATM_BR2684=m
 CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
 CONFIG_LLC2=m
 CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
--- linux-ein-5.4.0.orig/arch/mips/configs/nlm_xlp_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/nlm_xlp_defconfig
@@ -200,7 +200,6 @@
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_SECURITY=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -234,7 +233,6 @@
 CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
 CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_DECNET=m
 CONFIG_LLC2=m
 CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
--- linux-ein-5.4.0.orig/arch/mips/configs/nlm_xlr_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/nlm_xlr_defconfig
@@ -198,7 +198,6 @@
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_SECURITY=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -232,7 +231,6 @@
 CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
 CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_DECNET=m
 CONFIG_LLC2=m
 CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
--- linux-ein-5.4.0.orig/arch/mips/configs/rm200_defconfig
+++ linux-ein-5.4.0/arch/mips/configs/rm200_defconfig
@@ -116,7 +116,6 @@
 CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
-CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -137,7 +136,6 @@
 CONFIG_BRIDGE_EBT_SNAT=m
 CONFIG_BRIDGE_EBT_LOG=m
 CONFIG_BRIDGE=m
-CONFIG_DECNET=m
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
@@ -203,7 +201,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/mips/dec/int-handler.S
+++ linux-ein-5.4.0/arch/mips/dec/int-handler.S
@@ -131,7 +131,7 @@
 		 */
 		mfc0	t0,CP0_CAUSE		# get pending interrupts
 		mfc0	t1,CP0_STATUS
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)
 		lw	t2,cpu_fpu_mask
 #endif
 		andi	t0,ST0_IM		# CAUSE.CE may be non-zero!
@@ -139,7 +139,7 @@
 
 		beqz	t0,spurious
 
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)
 		 and	t2,t0
 		bnez	t2,fpu			# handle FPU immediately
 #endif
@@ -280,7 +280,7 @@
 		j	dec_irq_dispatch
 		 nop
 
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)
 fpu:
 		lw	t0,fpu_kstat_irq
 		nop
--- linux-ein-5.4.0.orig/arch/mips/dec/prom/Makefile
+++ linux-ein-5.4.0/arch/mips/dec/prom/Makefile
@@ -6,4 +6,4 @@
 
 lib-y			+= init.o memory.o cmdline.o identify.o console.o
 
-lib-$(CONFIG_32BIT)	+= locore.o
+lib-$(CONFIG_CPU_R3000)	+= locore.o
--- linux-ein-5.4.0.orig/arch/mips/dec/setup.c
+++ linux-ein-5.4.0/arch/mips/dec/setup.c
@@ -6,7 +6,7 @@
  * for more details.
  *
  * Copyright (C) 1998 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2005  Maciej W. Rozycki
+ * Copyright (C) 2000, 2001, 2002, 2003, 2005, 2020  Maciej W. Rozycki
  */
 #include <linux/console.h>
 #include <linux/export.h>
@@ -15,6 +15,7 @@
 #include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/irqnr.h>
+#include <linux/memblock.h>
 #include <linux/param.h>
 #include <linux/percpu-defs.h>
 #include <linux/sched.h>
@@ -22,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/pm.h>
 
+#include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
@@ -29,7 +31,9 @@
 #include <asm/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
+#include <asm/page.h>
 #include <asm/reboot.h>
+#include <asm/sections.h>
 #include <asm/time.h>
 #include <asm/traps.h>
 #include <asm/wbflush.h>
@@ -166,6 +170,9 @@
 
 	ioport_resource.start = ~0UL;
 	ioport_resource.end = 0UL;
+
+	/* Stay away from the firmware working memory area for now. */
+	memblock_reserve(PHYS_OFFSET, __pa_symbol(&_text) - PHYS_OFFSET);
 }
 
 /*
@@ -759,7 +766,8 @@
 		dec_interrupt[DEC_IRQ_HALT] = -1;
 
 	/* Register board interrupts: FPU and cascade. */
-	if (dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) {
+	if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) &&
+	    dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) {
 		struct irq_desc *desc_fpu;
 		int irq_fpu;
 
--- linux-ein-5.4.0.orig/arch/mips/fw/lib/cmdline.c
+++ linux-ein-5.4.0/arch/mips/fw/lib/cmdline.c
@@ -51,7 +51,7 @@
 {
 	char *result = NULL;
 
-	if (_fw_envp != NULL) {
+	if (_fw_envp != NULL && fw_envp(0) != NULL) {
 		/*
 		 * Return a pointer to the given environment variable.
 		 * YAMON uses "name", "value" pairs, while U-Boot uses
--- linux-ein-5.4.0.orig/arch/mips/generic/board-boston.its.S
+++ linux-ein-5.4.0/arch/mips/generic/board-boston.its.S
@@ -1,22 +1,22 @@
 / {
 	images {
-		fdt@boston {
+		fdt-boston {
 			description = "img,boston Device Tree";
 			data = /incbin/("boot/dts/img/boston.dtb");
 			type = "flat_dt";
 			arch = "mips";
 			compression = "none";
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 	};
 
 	configurations {
-		conf@boston {
+		conf-boston {
 			description = "Boston Linux kernel";
-			kernel = "kernel@0";
-			fdt = "fdt@boston";
+			kernel = "kernel";
+			fdt = "fdt-boston";
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/mips/generic/board-ni169445.its.S
+++ linux-ein-5.4.0/arch/mips/generic/board-ni169445.its.S
@@ -1,22 +1,22 @@
 / {
 	images {
-		fdt@ni169445 {
+		fdt-ni169445 {
 			description = "NI 169445 device tree";
 			data = /incbin/("boot/dts/ni/169445.dtb");
 			type = "flat_dt";
 			arch = "mips";
 			compression = "none";
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 	};
 
 	configurations {
-		conf@ni169445 {
+		conf-ni169445 {
 			description = "NI 169445 Linux Kernel";
-			kernel = "kernel@0";
-			fdt = "fdt@ni169445";
+			kernel = "kernel";
+			fdt = "fdt-ni169445";
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/mips/generic/board-ocelot.its.S
+++ linux-ein-5.4.0/arch/mips/generic/board-ocelot.its.S
@@ -1,40 +1,40 @@
 /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
 / {
 	images {
-		fdt@ocelot_pcb123 {
+		fdt-ocelot_pcb123 {
 			description = "MSCC Ocelot PCB123 Device Tree";
 			data = /incbin/("boot/dts/mscc/ocelot_pcb123.dtb");
 			type = "flat_dt";
 			arch = "mips";
 			compression = "none";
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 
-		fdt@ocelot_pcb120 {
+		fdt-ocelot_pcb120 {
 			description = "MSCC Ocelot PCB120 Device Tree";
 			data = /incbin/("boot/dts/mscc/ocelot_pcb120.dtb");
 			type = "flat_dt";
 			arch = "mips";
 			compression = "none";
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 	};
 
 	configurations {
-		conf@ocelot_pcb123 {
+		conf-ocelot_pcb123 {
 			description = "Ocelot Linux kernel";
-			kernel = "kernel@0";
-			fdt = "fdt@ocelot_pcb123";
+			kernel = "kernel";
+			fdt = "fdt-ocelot_pcb123";
 		};
 
-		conf@ocelot_pcb120 {
+		conf-ocelot_pcb120 {
 			description = "Ocelot Linux kernel";
-			kernel = "kernel@0";
-			fdt = "fdt@ocelot_pcb120";
+			kernel = "kernel";
+			fdt = "fdt-ocelot_pcb120";
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/mips/generic/board-xilfpga.its.S
+++ linux-ein-5.4.0/arch/mips/generic/board-xilfpga.its.S
@@ -1,22 +1,22 @@
 / {
 	images {
-		fdt@xilfpga {
+		fdt-xilfpga {
 			description = "MIPSfpga (xilfpga) Device Tree";
 			data = /incbin/("boot/dts/xilfpga/nexys4ddr.dtb");
 			type = "flat_dt";
 			arch = "mips";
 			compression = "none";
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 	};
 
 	configurations {
-		conf@xilfpga {
+		conf-xilfpga {
 			description = "MIPSfpga Linux kernel";
-			kernel = "kernel@0";
-			fdt = "fdt@xilfpga";
+			kernel = "kernel";
+			fdt = "fdt-xilfpga";
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/mips/generic/vmlinux.its.S
+++ linux-ein-5.4.0/arch/mips/generic/vmlinux.its.S
@@ -6,7 +6,7 @@
 	#address-cells = <ADDR_CELLS>;
 
 	images {
-		kernel@0 {
+		kernel {
 			description = KERNEL_NAME;
 			data = /incbin/(VMLINUX_BINARY);
 			type = "kernel";
@@ -15,18 +15,18 @@
 			compression = VMLINUX_COMPRESSION;
 			load = /bits/ ADDR_BITS <VMLINUX_LOAD_ADDRESS>;
 			entry = /bits/ ADDR_BITS <VMLINUX_ENTRY_ADDRESS>;
-			hash@0 {
+			hash {
 				algo = "sha1";
 			};
 		};
 	};
 
 	configurations {
-		default = "conf@default";
+		default = "conf-default";
 
-		conf@default {
+		conf-default {
 			description = "Generic Linux kernel";
-			kernel = "kernel@0";
+			kernel = "kernel";
 		};
 	};
 };
--- linux-ein-5.4.0.orig/arch/mips/generic/yamon-dt.c
+++ linux-ein-5.4.0/arch/mips/generic/yamon-dt.c
@@ -75,7 +75,7 @@
 __init int yamon_dt_append_memory(void *fdt,
 				  const struct yamon_mem_region *regions)
 {
-	unsigned long phys_memsize, memsize;
+	unsigned long phys_memsize = 0, memsize;
 	__be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
 	unsigned int mem_entries;
 	int i, err, mem_off;
--- linux-ein-5.4.0.orig/arch/mips/include/asm/asm.h
+++ linux-ein-5.4.0/arch/mips/include/asm/asm.h
@@ -20,10 +20,27 @@
 #include <asm/sgidefs.h>
 #include <asm/asm-eva.h>
 
+#ifndef __VDSO__
+/*
+ * Emit CFI data in .debug_frame sections, not .eh_frame sections.
+ * We don't do DWARF unwinding at runtime, so only the offline DWARF
+ * information is useful to anyone. Note we should change this if we
+ * ever decide to enable DWARF unwinding at runtime.
+ */
+#define CFI_SECTIONS	.cfi_sections .debug_frame
+#else
+ /*
+  * For the vDSO, emit both runtime unwind information and debug
+  * symbols for the .dbg file.
+  */
+#define CFI_SECTIONS
+#endif
+
 /*
  * LEAF - declare leaf routine
  */
 #define LEAF(symbol)					\
+		CFI_SECTIONS;				\
 		.globl	symbol;				\
 		.align	2;				\
 		.type	symbol, @function;		\
@@ -36,6 +53,7 @@
  * NESTED - declare nested routine entry point
  */
 #define NESTED(symbol, framesize, rpc)			\
+		CFI_SECTIONS;				\
 		.globl	symbol;				\
 		.align	2;				\
 		.type	symbol, @function;		\
--- linux-ein-5.4.0.orig/arch/mips/include/asm/bugs.h
+++ linux-ein-5.4.0/arch/mips/include/asm/bugs.h
@@ -1,17 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
  * Copyright (C) 2007  Maciej W. Rozycki
- *
- * Needs:
- *	void check_bugs(void);
  */
 #ifndef _ASM_BUGS_H
 #define _ASM_BUGS_H
 
 #include <linux/bug.h>
-#include <linux/delay.h>
 #include <linux/smp.h>
 
 #include <asm/cpu.h>
@@ -31,17 +25,6 @@
 #endif
 }
 
-static inline void check_bugs(void)
-{
-	unsigned int cpu = smp_processor_id();
-
-	cpu_data[cpu].udelay_val = loops_per_jiffy;
-	check_bugs32();
-#ifdef CONFIG_64BIT
-	check_bugs64();
-#endif
-}
-
 static inline int r4k_daddiu_bug(void)
 {
 #ifdef CONFIG_64BIT
--- linux-ein-5.4.0.orig/arch/mips/include/asm/checksum.h
+++ linux-ein-5.4.0/arch/mips/include/asm/checksum.h
@@ -276,7 +276,8 @@
 	"	.set	pop"
 	: "=&r" (sum), "=&r" (tmp)
 	: "r" (saddr), "r" (daddr),
-	  "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
+	  "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)
+	: "memory");
 
 	return csum_fold(sum);
 }
--- linux-ein-5.4.0.orig/arch/mips/include/asm/cmpxchg.h
+++ linux-ein-5.4.0/arch/mips/include/asm/cmpxchg.h
@@ -239,6 +239,7 @@
 	"	.set	" MIPS_ISA_ARCH_LEVEL "		\n"
 	/* Load 64 bits from ptr */
 	"1:	lld	%L0, %3		# __cmpxchg64	\n"
+	"	.set	pop				\n"
 	/*
 	 * Split the 64 bit value we loaded into the 2 registers that hold the
 	 * ret variable.
@@ -266,6 +267,8 @@
 	"	or	%L1, %L1, $at			\n"
 	"	.set	at				\n"
 #  endif
+	"	.set	push				\n"
+	"	.set	" MIPS_ISA_ARCH_LEVEL "		\n"
 	/* Attempt to store new at ptr */
 	"	scd	%L1, %2				\n"
 	/* If we failed, loop! */
--- linux-ein-5.4.0.orig/arch/mips/include/asm/cpu-features.h
+++ linux-ein-5.4.0/arch/mips/include/asm/cpu-features.h
@@ -124,7 +124,24 @@
 #define cpu_has_tx39_cache	__opt(MIPS_CPU_TX39_CACHE)
 #endif
 #ifndef cpu_has_octeon_cache
-#define cpu_has_octeon_cache	0
+#define cpu_has_octeon_cache						\
+({									\
+	int __res;							\
+									\
+	switch (boot_cpu_type()) {					\
+	case CPU_CAVIUM_OCTEON:						\
+	case CPU_CAVIUM_OCTEON_PLUS:					\
+	case CPU_CAVIUM_OCTEON2:					\
+	case CPU_CAVIUM_OCTEON3:					\
+		__res = 1;						\
+		break;							\
+									\
+	default:							\
+		__res = 0;						\
+	}								\
+									\
+	__res;								\
+})
 #endif
 /* Don't override `cpu_has_fpu' to 1 or the "nofpu" option won't work.  */
 #ifndef cpu_has_fpu
@@ -288,10 +305,12 @@
 # define cpu_has_mips32r6	__isa_ge_or_flag(6, MIPS_CPU_ISA_M32R6)
 #endif
 #ifndef cpu_has_mips64r1
-# define cpu_has_mips64r1	__isa_range_or_flag(1, 6, MIPS_CPU_ISA_M64R1)
+# define cpu_has_mips64r1	(cpu_has_64bits && \
+				 __isa_range_or_flag(1, 6, MIPS_CPU_ISA_M64R1))
 #endif
 #ifndef cpu_has_mips64r2
-# define cpu_has_mips64r2	__isa_range_or_flag(2, 6, MIPS_CPU_ISA_M64R2)
+# define cpu_has_mips64r2	(cpu_has_64bits && \
+				 __isa_range_or_flag(2, 6, MIPS_CPU_ISA_M64R2))
 #endif
 #ifndef cpu_has_mips64r6
 # define cpu_has_mips64r6	__isa_ge_and_flag(6, MIPS_CPU_ISA_M64R6)
@@ -339,7 +358,7 @@
 ({									\
 	int __res;							\
 									\
-	switch (current_cpu_type()) {					\
+	switch (boot_cpu_type()) {					\
 	case CPU_M14KC:							\
 	case CPU_74K:							\
 	case CPU_1074K:							\
--- linux-ein-5.4.0.orig/arch/mips/include/asm/cpu-type.h
+++ linux-ein-5.4.0/arch/mips/include/asm/cpu-type.h
@@ -47,6 +47,7 @@
 	case CPU_34K:
 	case CPU_1004K:
 	case CPU_74K:
+	case CPU_1074K:
 	case CPU_M14KC:
 	case CPU_M14KEC:
 	case CPU_INTERAPTIV:
--- linux-ein-5.4.0.orig/arch/mips/include/asm/dec/prom.h
+++ linux-ein-5.4.0/arch/mips/include/asm/dec/prom.h
@@ -43,16 +43,11 @@
  */
 #define REX_PROM_MAGIC		0x30464354
 
-#ifdef CONFIG_64BIT
-
-#define prom_is_rex(magic)	1	/* KN04 and KN05 are REX PROMs.  */
-
-#else /* !CONFIG_64BIT */
-
-#define prom_is_rex(magic)	((magic) == REX_PROM_MAGIC)
-
-#endif /* !CONFIG_64BIT */
-
+/* KN04 and KN05 are REX PROMs, so only do the check for R3k systems.  */
+static inline bool prom_is_rex(u32 magic)
+{
+	return !IS_ENABLED(CONFIG_CPU_R3000) || magic == REX_PROM_MAGIC;
+}
 
 /*
  * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's and
@@ -75,7 +70,7 @@
  */
 typedef struct {
 	int pagesize;
-	unsigned char bitmap[0];
+	unsigned char bitmap[];
 } memmap;
 
 
--- linux-ein-5.4.0.orig/arch/mips/include/asm/div64.h
+++ linux-ein-5.4.0/arch/mips/include/asm/div64.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2004  Maciej W. Rozycki
+ * Copyright (C) 2000, 2004, 2021  Maciej W. Rozycki
  * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,25 +9,18 @@
 #ifndef __ASM_DIV64_H
 #define __ASM_DIV64_H
 
-#include <asm-generic/div64.h>
-
-#if BITS_PER_LONG == 64
+#include <asm/bitsperlong.h>
 
-#include <linux/types.h>
+#if BITS_PER_LONG == 32
 
 /*
  * No traps on overflows for any of these...
  */
 
-#define __div64_32(n, base)						\
-({									\
+#define do_div64_32(res, high, low, base) ({				\
 	unsigned long __cf, __tmp, __tmp2, __i;				\
 	unsigned long __quot32, __mod32;				\
-	unsigned long __high, __low;					\
-	unsigned long long __n;						\
 									\
-	__high = *__n >> 32;						\
-	__low = __n;							\
 	__asm__(							\
 	"	.set	push					\n"	\
 	"	.set	noat					\n"	\
@@ -51,18 +44,48 @@
 	"	subu	%0, %0, %z6				\n"	\
 	"	addiu	%2, %2, 1				\n"	\
 	"3:							\n"	\
-	"	bnez	%4, 0b\n\t"					\
-	"	 srl	%5, %1, 0x1f\n\t"				\
+	"	bnez	%4, 0b					\n"	\
+	"	 srl	%5, %1, 0x1f				\n"	\
 	"	.set	pop"						\
 	: "=&r" (__mod32), "=&r" (__tmp),				\
 	  "=&r" (__quot32), "=&r" (__cf),				\
 	  "=&r" (__i), "=&r" (__tmp2)					\
-	: "Jr" (base), "0" (__high), "1" (__low));			\
+	: "Jr" (base), "0" (high), "1" (low));				\
 									\
-	(__n) = __quot32;						\
+	(res) = __quot32;						\
 	__mod32;							\
 })
 
-#endif /* BITS_PER_LONG == 64 */
+#define __div64_32(n, base) ({						\
+	unsigned long __upper, __low, __high, __radix;			\
+	unsigned long long __quot;					\
+	unsigned long long __div;					\
+	unsigned long __mod;						\
+									\
+	__div = (*n);							\
+	__radix = (base);						\
+									\
+	__high = __div >> 32;						\
+	__low = __div;							\
+									\
+	if (__high < __radix) {						\
+		__upper = __high;					\
+		__high = 0;						\
+	} else {							\
+		__upper = __high % __radix;				\
+		__high /= __radix;					\
+	}								\
+									\
+	__mod = do_div64_32(__low, __upper, __low, __radix);		\
+									\
+	__quot = __high;						\
+	__quot = __quot << 32 | __low;					\
+	(*n) = __quot;							\
+	__mod;								\
+})
+
+#endif /* BITS_PER_LONG == 32 */
+
+#include <asm-generic/div64.h>
 
 #endif /* __ASM_DIV64_H */
--- linux-ein-5.4.0.orig/arch/mips/include/asm/fw/fw.h
+++ linux-ein-5.4.0/arch/mips/include/asm/fw/fw.h
@@ -26,6 +26,6 @@
 extern void fw_meminit(void);
 extern char *fw_getenv(char *name);
 extern unsigned long fw_getenvl(char *name);
-extern void fw_init_early_console(char port);
+extern void fw_init_early_console(void);
 
 #endif /* __ASM_FW_H_ */
--- linux-ein-5.4.0.orig/arch/mips/include/asm/highmem.h
+++ linux-ein-5.4.0/arch/mips/include/asm/highmem.h
@@ -36,7 +36,7 @@
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#if defined(CONFIG_PHYS_ADDR_T_64BIT) || defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
 #define LAST_PKMAP 512
 #else
 #define LAST_PKMAP 1024
--- linux-ein-5.4.0.orig/arch/mips/include/asm/hugetlb.h
+++ linux-ein-5.4.0/arch/mips/include/asm/hugetlb.h
@@ -53,7 +53,13 @@
 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
 					 unsigned long addr, pte_t *ptep)
 {
-	flush_tlb_page(vma, addr & huge_page_mask(hstate_vma(vma)));
+	/*
+	 * clear the huge pte entry firstly, so that the other smp threads will
+	 * not get old pte entry after finishing flush_tlb_page and before
+	 * setting new huge pte entry
+	 */
+	huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+	flush_tlb_page(vma, addr);
 }
 
 #define __HAVE_ARCH_HUGE_PTE_NONE
--- linux-ein-5.4.0.orig/arch/mips/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/mips/include/asm/kvm_host.h
@@ -274,8 +274,12 @@
 #define MIPS3_PG_SHIFT		6
 #define MIPS3_PG_FRAME		0x3fffffc0
 
+#if defined(CONFIG_64BIT)
+#define VPN2_MASK		GENMASK(cpu_vmbits - 1, 13)
+#else
 #define VPN2_MASK		0xffffe000
-#define KVM_ENTRYHI_ASID	MIPS_ENTRYHI_ASID
+#endif
+#define KVM_ENTRYHI_ASID	cpu_asid_mask(&boot_cpu_data)
 #define TLB_IS_GLOBAL(x)	((x).tlb_lo[0] & (x).tlb_lo[1] & ENTRYLO_G)
 #define TLB_VPN2(x)		((x).tlb_hi & VPN2_MASK)
 #define TLB_ASID(x)		((x).tlb_hi & KVM_ENTRYHI_ASID)
@@ -935,7 +939,7 @@
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva_range(struct kvm *kvm,
-			unsigned long start, unsigned long end);
+			unsigned long start, unsigned long end, unsigned flags);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
--- linux-ein-5.4.0.orig/arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
+++ linux-ein-5.4.0/arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
@@ -28,7 +28,6 @@
 #define cpu_has_6k_cache		0
 #define cpu_has_8k_cache		0
 #define cpu_has_tx39_cache		0
-#define cpu_has_fpu			1
 #define cpu_has_nofpuex			0
 #define cpu_has_32fpr			1
 #define cpu_has_counter			1
--- linux-ein-5.4.0.orig/arch/mips/include/asm/mach-rc32434/pci.h
+++ linux-ein-5.4.0/arch/mips/include/asm/mach-rc32434/pci.h
@@ -377,7 +377,7 @@
 				 PCI_CFG04_STAT_SSE | \
 				 PCI_CFG04_STAT_PE)
 
-#define KORINA_CNFG1		((KORINA_STAT<<16)|KORINA_CMD)
+#define KORINA_CNFG1		(KORINA_STAT | KORINA_CMD)
 
 #define KORINA_REVID		0
 #define KORINA_CLASS_CODE	0
--- linux-ein-5.4.0.orig/arch/mips/include/asm/mips-cm.h
+++ linux-ein-5.4.0/arch/mips/include/asm/mips-cm.h
@@ -11,6 +11,7 @@
 #ifndef __MIPS_ASM_MIPS_CM_H__
 #define __MIPS_ASM_MIPS_CM_H__
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/errno.h>
 
@@ -153,8 +154,8 @@
 #define CM_GCR_REV_MINOR			GENMASK(7, 0)
 
 #define CM_ENCODE_REV(major, minor) \
-		(((major) << __ffs(CM_GCR_REV_MAJOR)) | \
-		 ((minor) << __ffs(CM_GCR_REV_MINOR)))
+		(FIELD_PREP(CM_GCR_REV_MAJOR, major) | \
+		 FIELD_PREP(CM_GCR_REV_MINOR, minor))
 
 #define CM_REV_CM2				CM_ENCODE_REV(6, 0)
 #define CM_REV_CM2_5				CM_ENCODE_REV(7, 0)
@@ -362,10 +363,10 @@
 static inline unsigned int mips_cm_max_vp_width(void)
 {
 	extern int smp_num_siblings;
-	uint32_t cfg;
 
 	if (mips_cm_revision() >= CM_REV_CM3)
-		return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW;
+		return FIELD_GET(CM_GCR_SYS_CONFIG2_MAXVPW,
+				 read_gcr_sys_config2());
 
 	if (mips_cm_present()) {
 		/*
@@ -373,8 +374,7 @@
 		 * number of VP(E)s, and if that ever changes then this will
 		 * need revisiting.
 		 */
-		cfg = read_gcr_cl_config() & CM_GCR_Cx_CONFIG_PVPE;
-		return (cfg >> __ffs(CM_GCR_Cx_CONFIG_PVPE)) + 1;
+		return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, read_gcr_cl_config()) + 1;
 	}
 
 	if (IS_ENABLED(CONFIG_SMP))
--- linux-ein-5.4.0.orig/arch/mips/include/asm/mipsregs.h
+++ linux-ein-5.4.0/arch/mips/include/asm/mipsregs.h
@@ -750,7 +750,7 @@
 
 /* MAAR bit definitions */
 #define MIPS_MAAR_VH		(_U64CAST_(1) << 63)
-#define MIPS_MAAR_ADDR		((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12)
+#define MIPS_MAAR_ADDR		GENMASK_ULL(55, 12)
 #define MIPS_MAAR_ADDR_SHIFT	12
 #define MIPS_MAAR_S		(_ULCAST_(1) << 1)
 #define MIPS_MAAR_VL		(_ULCAST_(1) << 0)
@@ -2007,7 +2007,7 @@
 ({ int __res;								\
 	__asm__ __volatile__(						\
 		".set\tpush\n\t"					\
-		".set\tmips32r2\n\t"					\
+		".set\tmips32r5\n\t"					\
 		_ASM_SET_VIRT						\
 		"mfgc0\t%0, " #source ", %1\n\t"			\
 		".set\tpop"						\
@@ -2020,7 +2020,7 @@
 ({ unsigned long long __res;						\
 	__asm__ __volatile__(						\
 		".set\tpush\n\t"					\
-		".set\tmips64r2\n\t"					\
+		".set\tmips64r5\n\t"					\
 		_ASM_SET_VIRT						\
 		"dmfgc0\t%0, " #source ", %1\n\t"			\
 		".set\tpop"						\
@@ -2033,7 +2033,7 @@
 do {									\
 	__asm__ __volatile__(						\
 		".set\tpush\n\t"					\
-		".set\tmips32r2\n\t"					\
+		".set\tmips32r5\n\t"					\
 		_ASM_SET_VIRT						\
 		"mtgc0\t%z0, " #register ", %1\n\t"			\
 		".set\tpop"						\
@@ -2045,7 +2045,7 @@
 do {									\
 	__asm__ __volatile__(						\
 		".set\tpush\n\t"					\
-		".set\tmips64r2\n\t"					\
+		".set\tmips64r5\n\t"					\
 		_ASM_SET_VIRT						\
 		"dmtgc0\t%z0, " #register ", %1\n\t"			\
 		".set\tpop"						\
--- linux-ein-5.4.0.orig/arch/mips/include/asm/mmzone.h
+++ linux-ein-5.4.0/arch/mips/include/asm/mmzone.h
@@ -20,10 +20,4 @@
 #define nid_to_addrbase(nid) 0
 #endif
 
-#ifdef CONFIG_DISCONTIGMEM
-
-#define pfn_to_nid(pfn)		pa_to_nid((pfn) << PAGE_SHIFT)
-
-#endif /* CONFIG_DISCONTIGMEM */
-
 #endif /* _ASM_MMZONE_H_ */
--- linux-ein-5.4.0.orig/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+++ linux-ein-5.4.0/arch/mips/include/asm/octeon/cvmx-bootinfo.h
@@ -315,7 +315,7 @@
 
 /* Functions to return string based on type */
 #define ENUM_BRD_TYPE_CASE(x) \
-	case x: return(#x + 16);	/* Skip CVMX_BOARD_TYPE_ */
+	case x: return (&#x[16]);	/* Skip CVMX_BOARD_TYPE_ */
 static inline const char *cvmx_board_type_to_string(enum
 						    cvmx_board_types_enum type)
 {
@@ -404,7 +404,7 @@
 }
 
 #define ENUM_CHIP_TYPE_CASE(x) \
-	case x: return(#x + 15);	/* Skip CVMX_CHIP_TYPE */
+	case x: return (&#x[15]);	/* Skip CVMX_CHIP_TYPE */
 static inline const char *cvmx_chip_type_to_string(enum
 						   cvmx_chip_types_enum type)
 {
--- linux-ein-5.4.0.orig/arch/mips/include/asm/pgtable-32.h
+++ linux-ein-5.4.0/arch/mips/include/asm/pgtable-32.h
@@ -155,6 +155,7 @@
 
 #if defined(CONFIG_XPA)
 
+#define MAX_POSSIBLE_PHYSMEM_BITS 40
 #define pte_pfn(x)		(((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT))
 static inline pte_t
 pfn_pte(unsigned long pfn, pgprot_t prot)
@@ -170,6 +171,7 @@
 
 #elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
 
+#define MAX_POSSIBLE_PHYSMEM_BITS 36
 #define pte_pfn(x)		((unsigned long)((x).pte_high >> 6))
 
 static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
@@ -184,6 +186,7 @@
 
 #else
 
+#define MAX_POSSIBLE_PHYSMEM_BITS 32
 #ifdef CONFIG_CPU_VR41XX
 #define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
 #define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
--- linux-ein-5.4.0.orig/arch/mips/include/asm/pgtable-64.h
+++ linux-ein-5.4.0/arch/mips/include/asm/pgtable-64.h
@@ -18,10 +18,12 @@
 #include <asm/fixmap.h>
 
 #define __ARCH_USE_5LEVEL_HACK
-#if defined(CONFIG_PAGE_SIZE_64KB) && !defined(CONFIG_MIPS_VA_BITS_48)
+#if CONFIG_PGTABLE_LEVELS == 2
 #include <asm-generic/pgtable-nopmd.h>
-#elif !(defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS_VA_BITS_48))
+#elif CONFIG_PGTABLE_LEVELS == 3
 #include <asm-generic/pgtable-nopud.h>
+#else
+#include <asm-generic/5level-fixup.h>
 #endif
 
 /*
@@ -216,6 +218,9 @@
 	return pgd_val(pgd);
 }
 
+#define pgd_phys(pgd)		virt_to_phys((void *)pgd_val(pgd))
+#define pgd_page(pgd)		(pfn_to_page(pgd_phys(pgd) >> PAGE_SHIFT))
+
 static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
 {
 	return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(address);
--- linux-ein-5.4.0.orig/arch/mips/include/asm/setup.h
+++ linux-ein-5.4.0/arch/mips/include/asm/setup.h
@@ -16,7 +16,7 @@
 	unsigned int reg_shift, unsigned int timeout) {}
 #endif
 
-extern void set_handler(unsigned long offset, void *addr, unsigned long len);
+void set_handler(unsigned long offset, const void *addr, unsigned long len);
 extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
 
 typedef void (*vi_handler_t)(void);
--- linux-ein-5.4.0.orig/arch/mips/include/asm/string.h
+++ linux-ein-5.4.0/arch/mips/include/asm/string.h
@@ -10,127 +10,6 @@
 #ifndef _ASM_STRING_H
 #define _ASM_STRING_H
 
-
-/*
- * Most of the inline functions are rather naive implementations so I just
- * didn't bother updating them for 64-bit ...
- */
-#ifdef CONFIG_32BIT
-
-#ifndef IN_STRING_C
-
-#define __HAVE_ARCH_STRCPY
-static __inline__ char *strcpy(char *__dest, __const__ char *__src)
-{
-  char *__xdest = __dest;
-
-  __asm__ __volatile__(
-	".set\tnoreorder\n\t"
-	".set\tnoat\n"
-	"1:\tlbu\t$1,(%1)\n\t"
-	"addiu\t%1,1\n\t"
-	"sb\t$1,(%0)\n\t"
-	"bnez\t$1,1b\n\t"
-	"addiu\t%0,1\n\t"
-	".set\tat\n\t"
-	".set\treorder"
-	: "=r" (__dest), "=r" (__src)
-	: "0" (__dest), "1" (__src)
-	: "memory");
-
-  return __xdest;
-}
-
-#define __HAVE_ARCH_STRNCPY
-static __inline__ char *strncpy(char *__dest, __const__ char *__src, size_t __n)
-{
-  char *__xdest = __dest;
-
-  if (__n == 0)
-    return __xdest;
-
-  __asm__ __volatile__(
-	".set\tnoreorder\n\t"
-	".set\tnoat\n"
-	"1:\tlbu\t$1,(%1)\n\t"
-	"subu\t%2,1\n\t"
-	"sb\t$1,(%0)\n\t"
-	"beqz\t$1,2f\n\t"
-	"addiu\t%0,1\n\t"
-	"bnez\t%2,1b\n\t"
-	"addiu\t%1,1\n"
-	"2:\n\t"
-	".set\tat\n\t"
-	".set\treorder"
-	: "=r" (__dest), "=r" (__src), "=r" (__n)
-	: "0" (__dest), "1" (__src), "2" (__n)
-	: "memory");
-
-  return __xdest;
-}
-
-#define __HAVE_ARCH_STRCMP
-static __inline__ int strcmp(__const__ char *__cs, __const__ char *__ct)
-{
-  int __res;
-
-  __asm__ __volatile__(
-	".set\tnoreorder\n\t"
-	".set\tnoat\n\t"
-	"lbu\t%2,(%0)\n"
-	"1:\tlbu\t$1,(%1)\n\t"
-	"addiu\t%0,1\n\t"
-	"bne\t$1,%2,2f\n\t"
-	"addiu\t%1,1\n\t"
-	"bnez\t%2,1b\n\t"
-	"lbu\t%2,(%0)\n\t"
-#if defined(CONFIG_CPU_R3000)
-	"nop\n\t"
-#endif
-	"move\t%2,$1\n"
-	"2:\tsubu\t%2,$1\n"
-	"3:\t.set\tat\n\t"
-	".set\treorder"
-	: "=r" (__cs), "=r" (__ct), "=r" (__res)
-	: "0" (__cs), "1" (__ct));
-
-  return __res;
-}
-
-#endif /* !defined(IN_STRING_C) */
-
-#define __HAVE_ARCH_STRNCMP
-static __inline__ int
-strncmp(__const__ char *__cs, __const__ char *__ct, size_t __count)
-{
-	int __res;
-
-	__asm__ __volatile__(
-	".set\tnoreorder\n\t"
-	".set\tnoat\n"
-	"1:\tlbu\t%3,(%0)\n\t"
-	"beqz\t%2,2f\n\t"
-	"lbu\t$1,(%1)\n\t"
-	"subu\t%2,1\n\t"
-	"bne\t$1,%3,3f\n\t"
-	"addiu\t%0,1\n\t"
-	"bnez\t%3,1b\n\t"
-	"addiu\t%1,1\n"
-	"2:\n\t"
-#if defined(CONFIG_CPU_R3000)
-	"nop\n\t"
-#endif
-	"move\t%3,$1\n"
-	"3:\tsubu\t%3,$1\n\t"
-	".set\tat\n\t"
-	".set\treorder"
-	: "=r" (__cs), "=r" (__ct), "=r" (__count), "=r" (__res)
-	: "0" (__cs), "1" (__ct), "2" (__count));
-
-	return __res;
-}
-#endif /* CONFIG_32BIT */
-
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *__s, int __c, size_t __count);
 
--- linux-ein-5.4.0.orig/arch/mips/include/asm/syscall.h
+++ linux-ein-5.4.0/arch/mips/include/asm/syscall.h
@@ -38,7 +38,7 @@
 static inline long syscall_get_nr(struct task_struct *task,
 				  struct pt_regs *regs)
 {
-	return current_thread_info()->syscall;
+	return task_thread_info(task)->syscall;
 }
 
 static inline void mips_syscall_update_nr(struct task_struct *task,
--- linux-ein-5.4.0.orig/arch/mips/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/mips/include/asm/thread_info.h
@@ -49,8 +49,26 @@
 	.addr_limit	= KERNEL_DS,		\
 }
 
-/* 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-ein-5.4.0.orig/arch/mips/include/asm/timex.h
+++ linux-ein-5.4.0/arch/mips/include/asm/timex.h
@@ -40,9 +40,9 @@
 typedef unsigned int cycles_t;
 
 /*
- * On R4000/R4400 before version 5.0 an erratum exists such that if the
- * cycle counter is read in the exact moment that it is matching the
- * compare register, no interrupt will be generated.
+ * On R4000/R4400 an erratum exists such that if the cycle counter is
+ * read in the exact moment that it is matching the compare register,
+ * no interrupt will be generated.
  *
  * There is a suggested workaround and also the erratum can't strike if
  * the compare interrupt isn't being used as the clock source device.
@@ -63,7 +63,7 @@
 	if (!__builtin_constant_p(cpu_has_counter))
 		asm volatile("" : "=m" (cpu_data[0].options));
 	if (likely(cpu_has_counter &&
-		   prid >= (PRID_IMP_R4000 | PRID_REV_ENCODE_44(5, 0))))
+		   prid > (PRID_IMP_R4000 | PRID_REV_ENCODE_44(15, 15))))
 		return 1;
 	else
 		return 0;
@@ -76,25 +76,24 @@
 	else
 		return 0;	/* no usable counter */
 }
+#define get_cycles get_cycles
 
 /*
  * Like get_cycles - but where c0_count is not available we desperately
  * use c0_random in an attempt to get at least a little bit of entropy.
- *
- * R6000 and R6000A neither have a count register nor a random register.
- * That leaves no entropy source in the CPU itself.
  */
 static inline unsigned long random_get_entropy(void)
 {
-	unsigned int prid = read_c0_prid();
-	unsigned int imp = prid & PRID_IMP_MASK;
+	unsigned int c0_random;
 
-	if (can_use_mips_counter(prid))
+	if (can_use_mips_counter(read_c0_prid()))
 		return read_c0_count();
-	else if (likely(imp != PRID_IMP_R6000 && imp != PRID_IMP_R6000A))
-		return read_c0_random();
+
+	if (cpu_has_3kex)
+		c0_random = (read_c0_random() >> 8) & 0x3f;
 	else
-		return 0;	/* no usable register */
+		c0_random = read_c0_random() & 0x3f;
+	return (random_get_entropy_fallback() << 6) | (0x3f - c0_random);
 }
 #define random_get_entropy random_get_entropy
 
--- linux-ein-5.4.0.orig/arch/mips/include/asm/vdso/gettimeofday.h
+++ linux-ein-5.4.0/arch/mips/include/asm/vdso/gettimeofday.h
@@ -26,7 +26,11 @@
 
 #define __VDSO_USE_SYSCALL		ULLONG_MAX
 
-#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+#if MIPS_ISA_REV < 6
+#define VDSO_SYSCALL_CLOBBERS "hi", "lo",
+#else
+#define VDSO_SYSCALL_CLOBBERS
+#endif
 
 static __always_inline long gettimeofday_fallback(
 				struct __kernel_old_timeval *_tv,
@@ -43,22 +47,13 @@
 	: "=r" (ret), "=r" (error)
 	: "r" (tv), "r" (tz), "r" (nr)
 	: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
-	  "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+	  "$14", "$15", "$24", "$25",
+	  VDSO_SYSCALL_CLOBBERS
+	  "memory");
 
 	return error ? -ret : ret;
 }
 
-#else
-
-static __always_inline long gettimeofday_fallback(
-				struct __kernel_old_timeval *_tv,
-				struct timezone *_tz)
-{
-	return -1;
-}
-
-#endif
-
 static __always_inline long clock_gettime_fallback(
 					clockid_t _clkid,
 					struct __kernel_timespec *_ts)
@@ -78,7 +73,9 @@
 	: "=r" (ret), "=r" (error)
 	: "r" (clkid), "r" (ts), "r" (nr)
 	: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
-	  "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+	  "$14", "$15", "$24", "$25",
+	  VDSO_SYSCALL_CLOBBERS
+	  "memory");
 
 	return error ? -ret : ret;
 }
@@ -102,7 +99,9 @@
 	: "=r" (ret), "=r" (error)
 	: "r" (clkid), "r" (ts), "r" (nr)
 	: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
-	  "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+	  "$14", "$15", "$24", "$25",
+	  VDSO_SYSCALL_CLOBBERS
+	  "memory");
 
 	return error ? -ret : ret;
 }
@@ -126,7 +125,9 @@
 	: "=r" (ret), "=r" (error)
 	: "r" (clkid), "r" (ts), "r" (nr)
 	: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
-	  "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+	  "$14", "$15", "$24", "$25",
+	  VDSO_SYSCALL_CLOBBERS
+	  "memory");
 
 	return error ? -ret : ret;
 }
@@ -146,7 +147,9 @@
 	: "=r" (ret), "=r" (error)
 	: "r" (clkid), "r" (ts), "r" (nr)
 	: "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
-	  "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+	  "$14", "$15", "$24", "$25",
+	  VDSO_SYSCALL_CLOBBERS
+	  "memory");
 
 	return error ? -ret : ret;
 }
--- linux-ein-5.4.0.orig/arch/mips/include/asm/vdso/vdso.h
+++ linux-ein-5.4.0/arch/mips/include/asm/vdso/vdso.h
@@ -67,7 +67,7 @@
 
 static inline void __iomem *get_gic(const struct vdso_data *data)
 {
-	return (void __iomem *)data - PAGE_SIZE;
+	return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE;
 }
 
 #endif /* CONFIG_CLKSRC_MIPS_GIC */
--- linux-ein-5.4.0.orig/arch/mips/include/asm/vpe.h
+++ linux-ein-5.4.0/arch/mips/include/asm/vpe.h
@@ -104,7 +104,6 @@
 	struct list_head tc_list;       /* Thread contexts */
 };
 
-extern unsigned long physical_memsize;
 extern struct vpe_control vpecontrol;
 extern const struct file_operations vpe_fops;
 
--- linux-ein-5.4.0.orig/arch/mips/jazz/jazzdma.c
+++ linux-ein-5.4.0/arch/mips/jazz/jazzdma.c
@@ -592,7 +592,7 @@
 	phys_addr_t phys = page_to_phys(page) + offset;
 
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		arch_sync_dma_for_device(dev, phys, size, dir);
+		arch_sync_dma_for_device(phys, size, dir);
 	return vdma_alloc(phys, size);
 }
 
@@ -600,7 +600,7 @@
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-		arch_sync_dma_for_cpu(dev, vdma_log2phys(dma_addr), size, dir);
+		arch_sync_dma_for_cpu(vdma_log2phys(dma_addr), size, dir);
 	vdma_free(dma_addr);
 }
 
@@ -612,7 +612,7 @@
 
 	for_each_sg(sglist, sg, nents, i) {
 		if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-			arch_sync_dma_for_device(dev, sg_phys(sg), sg->length,
+			arch_sync_dma_for_device(sg_phys(sg), sg->length,
 				dir);
 		sg->dma_address = vdma_alloc(sg_phys(sg), sg->length);
 		if (sg->dma_address == DMA_MAPPING_ERROR)
@@ -631,8 +631,7 @@
 
 	for_each_sg(sglist, sg, nents, i) {
 		if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-			arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length,
-				dir);
+			arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
 		vdma_free(sg->dma_address);
 	}
 }
@@ -640,13 +639,13 @@
 static void jazz_dma_sync_single_for_device(struct device *dev,
 		dma_addr_t addr, size_t size, enum dma_data_direction dir)
 {
-	arch_sync_dma_for_device(dev, vdma_log2phys(addr), size, dir);
+	arch_sync_dma_for_device(vdma_log2phys(addr), size, dir);
 }
 
 static void jazz_dma_sync_single_for_cpu(struct device *dev,
 		dma_addr_t addr, size_t size, enum dma_data_direction dir)
 {
-	arch_sync_dma_for_cpu(dev, vdma_log2phys(addr), size, dir);
+	arch_sync_dma_for_cpu(vdma_log2phys(addr), size, dir);
 }
 
 static void jazz_dma_sync_sg_for_device(struct device *dev,
@@ -656,7 +655,7 @@
 	int i;
 
 	for_each_sg(sgl, sg, nents, i)
-		arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir);
+		arch_sync_dma_for_device(sg_phys(sg), sg->length, dir);
 }
 
 static void jazz_dma_sync_sg_for_cpu(struct device *dev,
@@ -666,7 +665,7 @@
 	int i;
 
 	for_each_sg(sgl, sg, nents, i)
-		arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
+		arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
 }
 
 const struct dma_map_ops jazz_dma_ops = {
--- linux-ein-5.4.0.orig/arch/mips/jz4740/setup.c
+++ linux-ein-5.4.0/arch/mips/jz4740/setup.c
@@ -61,7 +61,7 @@
 
 	jz4740_reset_init();
 
-	if (__dtb_start != __dtb_end)
+	if (&__dtb_start != &__dtb_end)
 		dtb = __dtb_start;
 	else
 		dtb = (void *)fw_passed_dtb;
--- linux-ein-5.4.0.orig/arch/mips/kernel/cacheinfo.c
+++ linux-ein-5.4.0/arch/mips/kernel/cacheinfo.c
@@ -17,7 +17,7 @@
 	leaf++;							\
 } while (0)
 
-static int __init_cache_level(unsigned int cpu)
+int init_cache_level(unsigned int cpu)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
@@ -50,21 +50,46 @@
 	return 0;
 }
 
-static int __populate_cache_leaves(unsigned int cpu)
+static void fill_cpumask_siblings(int cpu, cpumask_t *cpu_map)
+{
+	int cpu1;
+
+	for_each_possible_cpu(cpu1)
+		if (cpus_are_siblings(cpu, cpu1))
+			cpumask_set_cpu(cpu1, cpu_map);
+}
+
+static void fill_cpumask_cluster(int cpu, cpumask_t *cpu_map)
+{
+	int cpu1;
+	int cluster = cpu_cluster(&cpu_data[cpu]);
+
+	for_each_possible_cpu(cpu1)
+		if (cpu_cluster(&cpu_data[cpu1]) == cluster)
+			cpumask_set_cpu(cpu1, cpu_map);
+}
+
+int populate_cache_leaves(unsigned int cpu)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
 
 	if (c->icache.waysize) {
+		/* L1 caches are per core */
+		fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map);
 		populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA);
+		fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map);
 		populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST);
 	} else {
 		populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED);
 	}
 
-	if (c->scache.waysize)
+	if (c->scache.waysize) {
+		/* L2 cache is per cluster */
+		fill_cpumask_cluster(cpu, &this_leaf->shared_cpu_map);
 		populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED);
+	}
 
 	if (c->tcache.waysize)
 		populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED);
@@ -73,6 +98,3 @@
 
 	return 0;
 }
-
-DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
-DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
--- linux-ein-5.4.0.orig/arch/mips/kernel/elf.c
+++ linux-ein-5.4.0/arch/mips/kernel/elf.c
@@ -11,6 +11,7 @@
 
 #include <asm/cpu-features.h>
 #include <asm/cpu-info.h>
+#include <asm/fpu.h>
 
 #ifdef CONFIG_MIPS_FP_SUPPORT
 
@@ -309,6 +310,11 @@
 	struct cpuinfo_mips *c = &boot_cpu_data;
 	struct task_struct *t = current;
 
+	/* Do this early so t->thread.fpu.fcr31 won't be clobbered in case
+	 * we are preempted before the lose_fpu(0) in start_thread.
+	 */
+	lose_fpu(0);
+
 	t->thread.fpu.fcr31 = c->fpu_csr31;
 	switch (state->nan_2008) {
 	case 0:
--- linux-ein-5.4.0.orig/arch/mips/kernel/genex.S
+++ linux-ein-5.4.0/arch/mips/kernel/genex.S
@@ -474,20 +474,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-ein-5.4.0.orig/arch/mips/kernel/jump_label.c
+++ linux-ein-5.4.0/arch/mips/kernel/jump_label.c
@@ -56,7 +56,7 @@
 			 * The branch offset must fit in the instruction's 26
 			 * bit field.
 			 */
-			WARN_ON((offset >= BIT(25)) ||
+			WARN_ON((offset >= (long)BIT(25)) ||
 				(offset < -(long)BIT(25)));
 
 			insn.j_format.opcode = bc6_op;
--- linux-ein-5.4.0.orig/arch/mips/kernel/mips-cm.c
+++ linux-ein-5.4.0/arch/mips/kernel/mips-cm.c
@@ -119,9 +119,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"
 };
 
@@ -179,8 +179,7 @@
 	phys_addr_t addr;
 
 	/* L2-only sync was introduced with CM major revision 6 */
-	major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR) >>
-		__ffs(CM_GCR_REV_MAJOR);
+	major_rev = FIELD_GET(CM_GCR_REV_MAJOR, read_gcr_rev());
 	if (major_rev < 6)
 		return;
 
@@ -263,13 +262,13 @@
 	preempt_disable();
 
 	if (cm_rev >= CM_REV_CM3) {
-		val = core << __ffs(CM3_GCR_Cx_OTHER_CORE);
-		val |= vp << __ffs(CM3_GCR_Cx_OTHER_VP);
+		val = FIELD_PREP(CM3_GCR_Cx_OTHER_CORE, core) |
+		      FIELD_PREP(CM3_GCR_Cx_OTHER_VP, vp);
 
 		if (cm_rev >= CM_REV_CM3_5) {
 			val |= CM_GCR_Cx_OTHER_CLUSTER_EN;
-			val |= cluster << __ffs(CM_GCR_Cx_OTHER_CLUSTER);
-			val |= block << __ffs(CM_GCR_Cx_OTHER_BLOCK);
+			val |= FIELD_PREP(CM_GCR_Cx_OTHER_CLUSTER, cluster);
+			val |= FIELD_PREP(CM_GCR_Cx_OTHER_BLOCK, block);
 		} else {
 			WARN_ON(cluster != 0);
 			WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL);
@@ -299,7 +298,7 @@
 		spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
 				  per_cpu(cm_core_lock_flags, curr_core));
 
-		val = core << __ffs(CM_GCR_Cx_OTHER_CORENUM);
+		val = FIELD_PREP(CM_GCR_Cx_OTHER_CORENUM, core);
 	}
 
 	write_gcr_cl_other(val);
@@ -343,8 +342,8 @@
 	cm_other = read_gcr_error_mult();
 
 	if (revision < CM_REV_CM3) { /* CM2 */
-		cause = cm_error >> __ffs(CM_GCR_ERROR_CAUSE_ERRTYPE);
-		ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND);
+		cause = FIELD_GET(CM_GCR_ERROR_CAUSE_ERRTYPE, cm_error);
+		ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other);
 
 		if (!cause)
 			return;
@@ -386,8 +385,8 @@
 		ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits;
 		ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit;
 
-		cause = cm_error >> __ffs64(CM3_GCR_ERROR_CAUSE_ERRTYPE);
-		ocause = cm_other >> __ffs(CM_GCR_ERROR_MULT_ERR2ND);
+		cause = FIELD_GET(CM3_GCR_ERROR_CAUSE_ERRTYPE, cm_error);
+		ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other);
 
 		if (!cause)
 			return;
--- linux-ein-5.4.0.orig/arch/mips/kernel/mips-cpc.c
+++ linux-ein-5.4.0/arch/mips/kernel/mips-cpc.c
@@ -27,6 +27,7 @@
 	cpc_node = of_find_compatible_node(of_root, NULL, "mti,mips-cpc");
 	if (cpc_node) {
 		err = of_address_to_resource(cpc_node, 0, &res);
+		of_node_put(cpc_node);
 		if (!err)
 			return res.start;
 	}
--- linux-ein-5.4.0.orig/arch/mips/kernel/proc.c
+++ linux-ein-5.4.0/arch/mips/kernel/proc.c
@@ -168,7 +168,7 @@
 {
 	unsigned long i = *pos;
 
-	return i < NR_CPUS ? (void *) (i + 1) : NULL;
+	return i < nr_cpu_ids ? (void *) (i + 1) : NULL;
 }
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
--- linux-ein-5.4.0.orig/arch/mips/kernel/r2300_fpu.S
+++ linux-ein-5.4.0/arch/mips/kernel/r2300_fpu.S
@@ -29,8 +29,8 @@
 #define EX2(a,b)						\
 9:	a,##b;							\
 	.section __ex_table,"a";				\
-	PTR	9b,bad_stack;					\
-	PTR	9b+4,bad_stack;					\
+	PTR	9b,fault;					\
+	PTR	9b+4,fault;					\
 	.previous
 
 	.set	mips1
--- linux-ein-5.4.0.orig/arch/mips/kernel/relocate.c
+++ linux-ein-5.4.0/arch/mips/kernel/relocate.c
@@ -187,8 +187,14 @@
 static inline __init unsigned long rotate_xor(unsigned long hash,
 					      const void *area, size_t size)
 {
-	size_t i;
-	unsigned long *ptr = (unsigned long *)area;
+	const typeof(hash) *ptr = PTR_ALIGN(area, sizeof(hash));
+	size_t diff, i;
+
+	diff = (void *)ptr - area;
+	if (unlikely(size < diff + sizeof(hash)))
+		return hash;
+
+	size = ALIGN_DOWN(size - diff, sizeof(hash));
 
 	for (i = 0; i < size / sizeof(hash); i++) {
 		/* Rotate by odd number of bits and XOR. */
--- linux-ein-5.4.0.orig/arch/mips/kernel/setup.c
+++ linux-ein-5.4.0/arch/mips/kernel/setup.c
@@ -11,6 +11,8 @@
  * Copyright (C) 2000, 2001, 2002, 2007	 Maciej W. Rozycki
  */
 #include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/export.h>
 #include <linux/screen_info.h>
@@ -190,10 +192,6 @@
 		pr_err("initrd start must be page aligned\n");
 		goto disable;
 	}
-	if (initrd_start < PAGE_OFFSET) {
-		pr_err("initrd start < PAGE_OFFSET\n");
-		goto disable;
-	}
 
 	/*
 	 * Sanitize initrd addresses. For example firmware
@@ -206,6 +204,11 @@
 	initrd_end = (unsigned long)__va(end);
 	initrd_start = (unsigned long)__va(__pa(initrd_start));
 
+	if (initrd_start < PAGE_OFFSET) {
+		pr_err("initrd start < PAGE_OFFSET\n");
+		goto disable;
+	}
+
 	ROOT_DEV = Root_RAM0;
 	return PFN_UP(end);
 disable:
@@ -359,11 +362,11 @@
 		panic("Incorrect memory mapping !!!");
 
 	if (max_pfn > PFN_DOWN(HIGHMEM_START)) {
+		max_low_pfn = PFN_DOWN(HIGHMEM_START);
 #ifdef CONFIG_HIGHMEM
-		highstart_pfn = PFN_DOWN(HIGHMEM_START);
+		highstart_pfn = max_low_pfn;
 		highend_pfn = max_pfn;
 #else
-		max_low_pfn = PFN_DOWN(HIGHMEM_START);
 		max_pfn = max_low_pfn;
 #endif
 	}
@@ -494,7 +497,7 @@
 	if (ret != 0 || crash_size <= 0)
 		return;
 
-	if (!memblock_find_in_range(crash_base, crash_base + crash_size, crash_size, 0)) {
+	if (!memblock_find_in_range(crash_base, crash_base + crash_size, crash_size, 1)) {
 		pr_warn("Invalid memory region reserved for crash kernel\n");
 		return;
 	}
@@ -529,8 +532,8 @@
 
 static void __init check_kernel_sections_mem(void)
 {
-	phys_addr_t start = PFN_PHYS(PFN_DOWN(__pa_symbol(&_text)));
-	phys_addr_t size = PFN_PHYS(PFN_UP(__pa_symbol(&_end))) - start;
+	phys_addr_t start = __pa_symbol(&_text);
+	phys_addr_t size = __pa_symbol(&_end) - start;
 
 	if (!memblock_is_region_memory(start, size)) {
 		pr_info("Kernel sections are not in the memory maps\n");
@@ -653,7 +656,17 @@
 				 crashk_res.end - crashk_res.start + 1);
 #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();
 
 	dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
@@ -801,3 +814,14 @@
 }
 early_param("nocoherentio", setnocoherentio);
 #endif
+
+void __init arch_cpu_finalize_init(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	cpu_data[cpu].udelay_val = loops_per_jiffy;
+	check_bugs32();
+
+	if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64))
+		check_bugs64();
+}
--- linux-ein-5.4.0.orig/arch/mips/kernel/smp-bmips.c
+++ linux-ein-5.4.0/arch/mips/kernel/smp-bmips.c
@@ -241,6 +241,8 @@
  */
 static void bmips_init_secondary(void)
 {
+	bmips_cpu_setup();
+
 	switch (current_cpu_type()) {
 	case CPU_BMIPS4350:
 	case CPU_BMIPS4380:
--- linux-ein-5.4.0.orig/arch/mips/kernel/smp-cps.c
+++ linux-ein-5.4.0/arch/mips/kernel/smp-cps.c
@@ -423,9 +423,11 @@
 			wmb();
 		}
 	} else {
-		pr_debug("Gating power to core %d\n", core);
-		/* Power down the core */
-		cps_pm_enter_state(CPS_PM_POWER_GATED);
+		if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) {
+			pr_debug("Gating power to core %d\n", core);
+			/* Power down the core */
+			cps_pm_enter_state(CPS_PM_POWER_GATED);
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/mips/kernel/smp.c
+++ linux-ein-5.4.0/arch/mips/kernel/smp.c
@@ -361,6 +361,9 @@
 	cpu = smp_processor_id();
 	cpu_data[cpu].udelay_val = loops_per_jiffy;
 
+	set_cpu_sibling_map(cpu);
+	set_cpu_core_map(cpu);
+
 	cpumask_set_cpu(cpu, &cpu_coherent_mask);
 	notify_cpu_starting(cpu);
 
@@ -372,9 +375,6 @@
 	/* The CPU is running and counters synchronised, now mark it online */
 	set_cpu_online(cpu, true);
 
-	set_cpu_sibling_map(cpu);
-	set_cpu_core_map(cpu);
-
 	calculate_cpu_foreign_map();
 
 	/*
--- linux-ein-5.4.0.orig/arch/mips/kernel/syscall.c
+++ linux-ein-5.4.0/arch/mips/kernel/syscall.c
@@ -239,12 +239,3 @@
 {
 	return -ENOSYS;
 }
-
-/*
- * If we ever come here the user sp is bad.  Zap the process right away.
- * Due to the bad stack signaling wouldn't work.
- */
-asmlinkage void bad_stack(void)
-{
-	do_exit(SIGSEGV);
-}
--- linux-ein-5.4.0.orig/arch/mips/kernel/syscalls/Makefile
+++ linux-ein-5.4.0/arch/mips/kernel/syscalls/Makefile
@@ -18,7 +18,7 @@
 		   '$(syshdr_pfx_$(basetarget))'		\
 		   '$(syshdr_offset_$(basetarget))'
 
-quiet_cmd_sysnr = SYSNR  $@
+quiet_cmd_sysnr = SYSNR   $@
       cmd_sysnr = $(CONFIG_SHELL) '$(sysnr)' '$<' '$@'		\
 		  '$(sysnr_abis_$(basetarget))'			\
 		  '$(sysnr_pfx_$(basetarget))'			\
--- linux-ein-5.4.0.orig/arch/mips/kernel/time.c
+++ linux-ein-5.4.0/arch/mips/kernel/time.c
@@ -18,12 +18,82 @@
 #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)
+{
+	struct cpufreq_freqs *freq = data;
+	struct cpumask *cpus = freq->policy->cpus;
+	unsigned long lpj;
+	int cpu;
+
+	/*
+	 * 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;
+		}
+	}
+
+	/*
+	 * 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);
+
+		for_each_cpu(cpu, cpus) {
+			lpj = cpufreq_scale(per_cpu(pcp_lpj_ref, cpu),
+					    per_cpu(pcp_lpj_ref_freq, cpu),
+					    freq->new);
+			cpu_data[cpu].udelay_val = (unsigned int)lpj;
+		}
+	}
+
+	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
  */
@@ -71,15 +141,10 @@
 	case CPU_R4400MC:
 		/*
 		 * The published errata for the R4400 up to 3.0 say the CPU
-		 * has the mfc0 from count bug.
+		 * has the mfc0 from count bug.  This seems the last version
+		 * produced.
 		 */
-		if ((current_cpu_data.processor_id & 0xff) <= 0x30)
-			return 1;
-
-		/*
-		 * we assume newer revisions are ok
-		 */
-		return 0;
+		return 1;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/mips/kernel/topology.c
+++ linux-ein-5.4.0/arch/mips/kernel/topology.c
@@ -20,7 +20,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-ein-5.4.0.orig/arch/mips/kernel/traps.c
+++ linux-ein-5.4.0/arch/mips/kernel/traps.c
@@ -415,7 +415,7 @@
 	if (regs && kexec_should_crash(current))
 		crash_kexec(regs);
 
-	do_exit(sig);
+	make_task_dead(sig);
 }
 
 extern struct exception_table_entry __start___dbe_table[];
@@ -1240,6 +1240,18 @@
 		err = own_fpu_inatomic(1);
 		if (msa && !err) {
 			enable_msa();
+			/*
+			 * with MSA enabled, userspace can see MSACSR
+			 * and MSA regs, but the values in them are from
+			 * other task before current task, restore them
+			 * from saved fp/msa context
+			 */
+			write_msa_csr(current->thread.fpu.msacsr);
+			/*
+			 * own_fpu_inatomic(1) just restore low 64bit,
+			 * fix the high 64bit
+			 */
+			init_msa_upper();
 			set_thread_flag(TIF_USEDMSA);
 			set_thread_flag(TIF_MSA_CTX_LIVE);
 		}
@@ -2008,19 +2020,19 @@
 		 * If no shadow set is selected then use the default handler
 		 * that does normal register saving and standard interrupt exit
 		 */
-		extern char except_vec_vi, except_vec_vi_lui;
-		extern char except_vec_vi_ori, except_vec_vi_end;
-		extern char rollback_except_vec_vi;
-		char *vec_start = using_rollback_handler() ?
-			&rollback_except_vec_vi : &except_vec_vi;
+		extern const u8 except_vec_vi[], except_vec_vi_lui[];
+		extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
+		extern const u8 rollback_except_vec_vi[];
+		const u8 *vec_start = using_rollback_handler() ?
+				      rollback_except_vec_vi : except_vec_vi;
 #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
-		const int lui_offset = &except_vec_vi_lui - vec_start + 2;
-		const int ori_offset = &except_vec_vi_ori - vec_start + 2;
+		const int lui_offset = except_vec_vi_lui - vec_start + 2;
+		const int ori_offset = except_vec_vi_ori - vec_start + 2;
 #else
-		const int lui_offset = &except_vec_vi_lui - vec_start;
-		const int ori_offset = &except_vec_vi_ori - vec_start;
+		const int lui_offset = except_vec_vi_lui - vec_start;
+		const int ori_offset = except_vec_vi_ori - vec_start;
 #endif
-		const int handler_len = &except_vec_vi_end - vec_start;
+		const int handler_len = except_vec_vi_end - vec_start;
 
 		if (handler_len > VECTORSPACING) {
 			/*
@@ -2126,6 +2138,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();
 }
 
 unsigned int hwrena;
@@ -2227,7 +2240,7 @@
 }
 
 /* Install CPU exception handler */
-void set_handler(unsigned long offset, void *addr, unsigned long size)
+void set_handler(unsigned long offset, const void *addr, unsigned long size)
 {
 #ifdef CONFIG_CPU_MICROMIPS
 	memcpy((void *)(ebase + offset), ((unsigned char *)addr - 1), size);
--- linux-ein-5.4.0.orig/arch/mips/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/mips/kernel/vmlinux.lds.S
@@ -10,6 +10,8 @@
  */
 #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
 
+#define RUNTIME_DISCARD_EXIT
+
 #include <asm-generic/vmlinux.lds.h>
 
 #undef mips
@@ -50,7 +52,7 @@
 	/* . = 0xa800000000300000; */
 	. = 0xffffffff80300000;
 #endif
-	. = VMLINUX_LOAD_ADDRESS;
+	. = LINKER_LOAD_ADDRESS;
 	/* read-only */
 	_text = .;	/* Text and read-only data */
 	.text : {
@@ -93,6 +95,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
@@ -225,6 +228,5 @@
 		*(.options)
 		*(.pdr)
 		*(.reginfo)
-		*(.eh_frame)
 	}
 }
--- linux-ein-5.4.0.orig/arch/mips/kernel/vpe-cmp.c
+++ linux-ein-5.4.0/arch/mips/kernel/vpe-cmp.c
@@ -75,7 +75,6 @@
 
 static void vpe_device_release(struct device *cd)
 {
-	kfree(cd);
 }
 
 static struct class vpe_class = {
@@ -157,6 +156,7 @@
 	device_del(&vpe_device);
 
 out_class:
+	put_device(&vpe_device);
 	class_unregister(&vpe_class);
 
 out_chrdev:
@@ -169,7 +169,7 @@
 {
 	struct vpe *v, *n;
 
-	device_del(&vpe_device);
+	device_unregister(&vpe_device);
 	class_unregister(&vpe_class);
 	unregister_chrdev(major, VPE_MODULE_NAME);
 
--- linux-ein-5.4.0.orig/arch/mips/kernel/vpe-mt.c
+++ linux-ein-5.4.0/arch/mips/kernel/vpe-mt.c
@@ -92,12 +92,11 @@
 	write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
 
 	/*
-	 * The sde-kit passes 'memsize' to __start in $a3, so set something
-	 * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
-	 * DFLT_HEAP_SIZE when you compile your program
+	 * We don't pass the memsize here, so VPE programs need to be
+	 * compiled with DFLT_STACK_SIZE and DFLT_HEAP_SIZE defined.
 	 */
+	mttgpr(7, 0);
 	mttgpr(6, v->ntcs);
-	mttgpr(7, physical_memsize);
 
 	/* set up VPE1 */
 	/*
@@ -313,7 +312,6 @@
 
 static void vpe_device_release(struct device *cd)
 {
-	kfree(cd);
 }
 
 static struct class vpe_class = {
@@ -497,6 +495,7 @@
 	device_del(&vpe_device);
 
 out_class:
+	put_device(&vpe_device);
 	class_unregister(&vpe_class);
 
 out_chrdev:
@@ -509,7 +508,7 @@
 {
 	struct vpe *v, *n;
 
-	device_del(&vpe_device);
+	device_unregister(&vpe_device);
 	class_unregister(&vpe_class);
 	unregister_chrdev(major, VPE_MODULE_NAME);
 
--- linux-ein-5.4.0.orig/arch/mips/kernel/vpe.c
+++ linux-ein-5.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);
 }
 
--- linux-ein-5.4.0.orig/arch/mips/kvm/mips.c
+++ linux-ein-5.4.0/arch/mips/kvm/mips.c
@@ -131,6 +131,8 @@
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	switch (type) {
+	case KVM_VM_MIPS_AUTO:
+		break;
 #ifdef CONFIG_KVM_MIPS_VZ
 	case KVM_VM_MIPS_VZ:
 #else
--- linux-ein-5.4.0.orig/arch/mips/kvm/mmu.c
+++ linux-ein-5.4.0/arch/mips/kvm/mmu.c
@@ -512,7 +512,8 @@
 	return 1;
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+			unsigned flags)
 {
 	handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, NULL);
 
@@ -692,7 +693,7 @@
 	gfn_t gfn = gpa >> PAGE_SHIFT;
 	int srcu_idx, err;
 	kvm_pfn_t pfn;
-	pte_t *ptep, entry, old_pte;
+	pte_t *ptep, entry;
 	bool writeable;
 	unsigned long prot_bits;
 	unsigned long mmu_seq;
@@ -765,7 +766,6 @@
 	entry = pfn_pte(pfn, __pgprot(prot_bits));
 
 	/* Write the PTE */
-	old_pte = *ptep;
 	set_pte(ptep, entry);
 
 	err = 0;
--- linux-ein-5.4.0.orig/arch/mips/lantiq/clk.c
+++ linux-ein-5.4.0/arch/mips/lantiq/clk.c
@@ -50,6 +50,7 @@
 {
 	return &cpu_clk_generic[2];
 }
+EXPORT_SYMBOL_GPL(clk_get_io);
 
 struct clk *clk_get_ppe(void)
 {
@@ -158,6 +159,18 @@
 }
 EXPORT_SYMBOL(clk_deactivate);
 
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return NULL;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
 static inline u32 get_counter_resolution(void)
 {
 	u32 res;
--- linux-ein-5.4.0.orig/arch/mips/lantiq/falcon/sysctrl.c
+++ linux-ein-5.4.0/arch/mips/lantiq/falcon/sysctrl.c
@@ -167,6 +167,8 @@
 {
 	struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
+	if (!clk)
+		return;
 	clk->cl.dev_id = dev;
 	clk->cl.con_id = NULL;
 	clk->cl.clk = clk;
--- linux-ein-5.4.0.orig/arch/mips/lantiq/irq.c
+++ linux-ein-5.4.0/arch/mips/lantiq/irq.c
@@ -302,7 +302,7 @@
 	generic_handle_irq(irq_linear_revmap(ltq_domain, hwirq));
 
 	/* 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-ein-5.4.0.orig/arch/mips/lantiq/prom.c
+++ linux-ein-5.4.0/arch/mips/lantiq/prom.c
@@ -23,12 +23,6 @@
 EXPORT_SYMBOL_GPL(ebu_lock);
 
 /*
- * This is needed by the VPE loader code, just set it to 0 and assume
- * that the firmware hardcodes this value to something useful.
- */
-unsigned long physical_memsize = 0L;
-
-/*
  * this struct is filled by the soc specific detection code and holds
  * information about the specific soc type, revision and name
  */
@@ -79,7 +73,7 @@
 
 	if (fw_passed_dtb) /* UHI interface */
 		dtb = (void *)fw_passed_dtb;
-	else if (__dtb_start != __dtb_end)
+	else if (&__dtb_start != &__dtb_end)
 		dtb = (void *)__dtb_start;
 	else
 		panic("no dtb found");
--- linux-ein-5.4.0.orig/arch/mips/lantiq/xway/dma.c
+++ linux-ein-5.4.0/arch/mips/lantiq/xway/dma.c
@@ -11,6 +11,7 @@
 #include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 
 #include <lantiq_soc.h>
@@ -29,6 +30,7 @@
 #define LTQ_DMA_PCTRL		0x44
 #define LTQ_DMA_IRNEN		0xf4
 
+#define DMA_ID_CHNR		GENMASK(26, 20)	/* channel number */
 #define DMA_DESCPT		BIT(3)		/* descriptor complete irq */
 #define DMA_TX			BIT(8)		/* TX channel direction */
 #define DMA_CHAN_ON		BIT(0)		/* channel on / off bit */
@@ -39,7 +41,6 @@
 #define DMA_POLL		BIT(31)		/* turn on channel polling */
 #define DMA_CLK_DIV4		BIT(6)		/* polling clock divider */
 #define DMA_2W_BURST		BIT(1)		/* 2 word burst length */
-#define DMA_MAX_CHANNEL		20		/* the soc has 20 channels */
 #define DMA_ETOP_ENDIANNESS	(0xf << 8) /* endianness swap etop channels */
 #define DMA_WEIGHT	(BIT(17) | BIT(16))	/* default channel wheight */
 
@@ -205,7 +206,7 @@
 {
 	struct clk *clk;
 	struct resource *res;
-	unsigned id;
+	unsigned int id, nchannels;
 	int i;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -221,21 +222,24 @@
 	clk_enable(clk);
 	ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
 
+	usleep_range(1, 10);
+
 	/* disable all interrupts */
 	ltq_dma_w32(0, LTQ_DMA_IRNEN);
 
 	/* reset/configure each channel */
-	for (i = 0; i < DMA_MAX_CHANNEL; i++) {
+	id = ltq_dma_r32(LTQ_DMA_ID);
+	nchannels = ((id & DMA_ID_CHNR) >> 20);
+	for (i = 0; i < nchannels; i++) {
 		ltq_dma_w32(i, LTQ_DMA_CS);
 		ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
 		ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
 		ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
 	}
 
-	id = ltq_dma_r32(LTQ_DMA_ID);
 	dev_info(&pdev->dev,
 		"Init done - hw rev: %X, ports: %d, channels: %d\n",
-		id & 0x1f, (id >> 16) & 0xf, id >> 20);
+		id & 0x1f, (id >> 16) & 0xf, nchannels);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/mips/lantiq/xway/gptu.c
+++ linux-ein-5.4.0/arch/mips/lantiq/xway/gptu.c
@@ -122,6 +122,8 @@
 {
 	struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
+	if (!clk)
+		return;
 	clk->cl.dev_id = dev_name(dev);
 	clk->cl.con_id = con;
 	clk->cl.clk = clk;
--- linux-ein-5.4.0.orig/arch/mips/lantiq/xway/sysctrl.c
+++ linux-ein-5.4.0/arch/mips/lantiq/xway/sysctrl.c
@@ -311,6 +311,8 @@
 {
 	struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
+	if (!clk)
+		return;
 	clk->cl.dev_id = dev;
 	clk->cl.con_id = con;
 	clk->cl.clk = clk;
@@ -334,6 +336,8 @@
 {
 	struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
+	if (!clk)
+		return;
 	clk->cl.dev_id = dev;
 	clk->cl.con_id = con;
 	clk->cl.clk = clk;
@@ -352,24 +356,28 @@
 	struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
 	/* main pci clock */
-	clk->cl.dev_id = "17000000.pci";
-	clk->cl.con_id = NULL;
-	clk->cl.clk = clk;
-	clk->rate = CLOCK_33M;
-	clk->rates = valid_pci_rates;
-	clk->enable = pci_enable;
-	clk->disable = pmu_disable;
-	clk->module = 0;
-	clk->bits = PMU_PCI;
-	clkdev_add(&clk->cl);
+	if (clk) {
+		clk->cl.dev_id = "17000000.pci";
+		clk->cl.con_id = NULL;
+		clk->cl.clk = clk;
+		clk->rate = CLOCK_33M;
+		clk->rates = valid_pci_rates;
+		clk->enable = pci_enable;
+		clk->disable = pmu_disable;
+		clk->module = 0;
+		clk->bits = PMU_PCI;
+		clkdev_add(&clk->cl);
+	}
 
 	/* use internal/external bus clock */
-	clk_ext->cl.dev_id = "17000000.pci";
-	clk_ext->cl.con_id = "external";
-	clk_ext->cl.clk = clk_ext;
-	clk_ext->enable = pci_ext_enable;
-	clk_ext->disable = pci_ext_disable;
-	clkdev_add(&clk_ext->cl);
+	if (clk_ext) {
+		clk_ext->cl.dev_id = "17000000.pci";
+		clk_ext->cl.con_id = "external";
+		clk_ext->cl.clk = clk_ext;
+		clk_ext->enable = pci_ext_enable;
+		clk_ext->disable = pci_ext_disable;
+		clkdev_add(&clk_ext->cl);
+	}
 }
 
 /* xway socs can generate clocks on gpio pins */
@@ -389,9 +397,15 @@
 		char *name;
 
 		name = kzalloc(sizeof("clkout0"), GFP_KERNEL);
+		if (!name)
+			continue;
 		sprintf(name, "clkout%d", i);
 
 		clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
+		if (!clk) {
+			kfree(name);
+			continue;
+		}
 		clk->cl.dev_id = "1f103000.cgu";
 		clk->cl.con_id = name;
 		clk->cl.clk = clk;
@@ -514,8 +528,8 @@
 		clkdev_add_pmu("1e10b308.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("1e108000.gswip", "gphy0", 0, 0, PMU_GPHY);
-		clkdev_add_pmu("1e108000.gswip", "gphy1", 0, 0, PMU_GPHY);
+		clkdev_add_pmu("1e108000.switch", "gphy0", 0, 0, PMU_GPHY);
+		clkdev_add_pmu("1e108000.switch", "gphy1", 0, 0, PMU_GPHY);
 		clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
 		clkdev_add_pmu("1e116000.mei", "afe", 1, 2, PMU_ANALOG_DSL_AFE);
 		clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
@@ -538,8 +552,8 @@
 				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("1e108000.gswip", "gphy0", 0, 0, PMU_GPHY);
-		clkdev_add_pmu("1e108000.gswip", "gphy1", 0, 0, PMU_GPHY);
+		clkdev_add_pmu("1e108000.switch", "gphy0", 0, 0, PMU_GPHY);
+		clkdev_add_pmu("1e108000.switch", "gphy1", 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-ein-5.4.0.orig/arch/mips/lasat/picvue_proc.c
+++ linux-ein-5.4.0/arch/mips/lasat/picvue_proc.c
@@ -39,7 +39,7 @@
 		pvc_write_string(pvc_lines[i], 0, i);
 }
 
-static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0);
+static DECLARE_TASKLET_OLD(pvc_display_tasklet, &pvc_display);
 
 static int pvc_line_proc_show(struct seq_file *m, void *v)
 {
--- linux-ein-5.4.0.orig/arch/mips/lib/dump_tlb.c
+++ linux-ein-5.4.0/arch/mips/lib/dump_tlb.c
@@ -80,7 +80,7 @@
 	unsigned int pagemask, guestctl1 = 0, c0, c1, i;
 	unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
 	int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
-	unsigned long uninitialized_var(s_mmid);
+	unsigned long s_mmid;
 #ifdef CONFIG_32BIT
 	bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
 	int pwidth = xpa ? 11 : 8;
--- linux-ein-5.4.0.orig/arch/mips/lib/mips-atomic.c
+++ linux-ein-5.4.0/arch/mips/lib/mips-atomic.c
@@ -37,7 +37,7 @@
  */
 notrace void arch_local_irq_disable(void)
 {
-	preempt_disable();
+	preempt_disable_notrace();
 
 	__asm__ __volatile__(
 	"	.set	push						\n"
@@ -53,7 +53,7 @@
 	: /* no inputs */
 	: "memory");
 
-	preempt_enable();
+	preempt_enable_notrace();
 }
 EXPORT_SYMBOL(arch_local_irq_disable);
 
@@ -61,7 +61,7 @@
 {
 	unsigned long flags;
 
-	preempt_disable();
+	preempt_disable_notrace();
 
 	__asm__ __volatile__(
 	"	.set	push						\n"
@@ -78,7 +78,7 @@
 	: /* no inputs */
 	: "memory");
 
-	preempt_enable();
+	preempt_enable_notrace();
 
 	return flags;
 }
@@ -88,7 +88,7 @@
 {
 	unsigned long __tmp1;
 
-	preempt_disable();
+	preempt_disable_notrace();
 
 	__asm__ __volatile__(
 	"	.set	push						\n"
@@ -106,7 +106,7 @@
 	: "0" (flags)
 	: "memory");
 
-	preempt_enable();
+	preempt_enable_notrace();
 }
 EXPORT_SYMBOL(arch_local_irq_restore);
 
--- linux-ein-5.4.0.orig/arch/mips/lib/uncached.c
+++ linux-ein-5.4.0/arch/mips/lib/uncached.c
@@ -37,10 +37,12 @@
  */
 unsigned long run_uncached(void *func)
 {
-	register long sp __asm__("$sp");
 	register long ret __asm__("$2");
 	long lfunc = (long)func, ufunc;
 	long usp;
+	long sp;
+
+	__asm__("move %0, $sp" : "=r" (sp));
 
 	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
 		usp = CKSEG1ADDR(sp);
--- linux-ein-5.4.0.orig/arch/mips/loongson32/common/platform.c
+++ linux-ein-5.4.0/arch/mips/loongson32/common/platform.c
@@ -98,7 +98,7 @@
 	if (plat_dat->bus_id) {
 		__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
 			     GMAC1_USE_UART0, LS1X_MUX_CTRL0);
-		switch (plat_dat->interface) {
+		switch (plat_dat->phy_interface) {
 		case PHY_INTERFACE_MODE_RGMII:
 			val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
 			break;
@@ -107,12 +107,12 @@
 			break;
 		default:
 			pr_err("unsupported mii mode %d\n",
-			       plat_dat->interface);
+			       plat_dat->phy_interface);
 			return -ENOTSUPP;
 		}
 		val &= ~GMAC1_SHUT;
 	} else {
-		switch (plat_dat->interface) {
+		switch (plat_dat->phy_interface) {
 		case PHY_INTERFACE_MODE_RGMII:
 			val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
 			break;
@@ -121,7 +121,7 @@
 			break;
 		default:
 			pr_err("unsupported mii mode %d\n",
-			       plat_dat->interface);
+			       plat_dat->phy_interface);
 			return -ENOTSUPP;
 		}
 		val &= ~GMAC0_SHUT;
@@ -131,7 +131,7 @@
 	plat_dat = dev_get_platdata(&pdev->dev);
 
 	val &= ~PHY_INTF_SELI;
-	if (plat_dat->interface == PHY_INTERFACE_MODE_RMII)
+	if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII)
 		val |= 0x4 << PHY_INTF_SELI_SHIFT;
 	__raw_writel(val, LS1X_MUX_CTRL1);
 
@@ -146,9 +146,9 @@
 	.bus_id			= 0,
 	.phy_addr		= -1,
 #if defined(CONFIG_LOONGSON1_LS1B)
-	.interface		= PHY_INTERFACE_MODE_MII,
+	.phy_interface		= PHY_INTERFACE_MODE_MII,
 #elif defined(CONFIG_LOONGSON1_LS1C)
-	.interface		= PHY_INTERFACE_MODE_RMII,
+	.phy_interface		= PHY_INTERFACE_MODE_RMII,
 #endif
 	.mdio_bus_data		= &ls1x_mdio_bus_data,
 	.dma_cfg		= &ls1x_eth_dma_cfg,
@@ -186,7 +186,7 @@
 static struct plat_stmmacenet_data ls1x_eth1_pdata = {
 	.bus_id			= 1,
 	.phy_addr		= -1,
-	.interface		= PHY_INTERFACE_MODE_MII,
+	.phy_interface		= PHY_INTERFACE_MODE_MII,
 	.mdio_bus_data		= &ls1x_mdio_bus_data,
 	.dma_cfg		= &ls1x_eth_dma_cfg,
 	.has_gmac		= 1,
--- linux-ein-5.4.0.orig/arch/mips/loongson32/ls1c/board.c
+++ linux-ein-5.4.0/arch/mips/loongson32/ls1c/board.c
@@ -15,7 +15,6 @@
 static int __init ls1c_platform_init(void)
 {
 	ls1x_serial_set_uartclk(&ls1x_uart_pdev);
-	ls1x_rtc_set_extclk(&ls1x_rtc_pdev);
 
 	return platform_add_devices(ls1c_platform_devices,
 				   ARRAY_SIZE(ls1c_platform_devices));
--- linux-ein-5.4.0.orig/arch/mips/loongson64/loongson-3/numa.c
+++ linux-ein-5.4.0/arch/mips/loongson64/loongson-3/numa.c
@@ -200,6 +200,9 @@
 		if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT))
 			memblock_reserve((node_addrspace_offset | 0xfe000000),
 					 32 << 20);
+
+		/* Reserve pfn range 0~node[0]->node_start_pfn */
+		memblock_reserve(0, PAGE_SIZE * start_pfn);
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/mips/loongson64/loongson-3/platform.c
+++ linux-ein-5.4.0/arch/mips/loongson64/loongson-3/platform.c
@@ -27,6 +27,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-ein-5.4.0.orig/arch/mips/mm/c-r4k.c
+++ linux-ein-5.4.0/arch/mips/mm/c-r4k.c
@@ -1560,7 +1560,7 @@
 	return 1;
 }
 
-static void __init loongson2_sc_init(void)
+static void loongson2_sc_init(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 
@@ -1576,7 +1576,7 @@
 	c->options |= MIPS_CPU_INCLUSIVE_CACHES;
 }
 
-static void __init loongson3_sc_init(void)
+static void loongson3_sc_init(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 	unsigned int config2, lsize;
@@ -1676,7 +1676,11 @@
 				printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
 				       scache_size >> 10,
 				       way_string[c->scache.ways], c->scache.linesz);
+
+				if (current_cpu_type() == CPU_BMIPS5000)
+					c->options |= MIPS_CPU_INCLUSIVE_CACHES;
 			}
+
 #else
 			if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
 				panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
--- linux-ein-5.4.0.orig/arch/mips/mm/dma-noncoherent.c
+++ linux-ein-5.4.0/arch/mips/mm/dma-noncoherent.c
@@ -27,7 +27,7 @@
  * R10000 and R12000 are used in such systems, the SGI IP28 Indigo² rsp.
  * SGI IP32 aka O2.
  */
-static inline bool cpu_needs_post_dma_flush(struct device *dev)
+static inline bool cpu_needs_post_dma_flush(void)
 {
 	switch (boot_cpu_type()) {
 	case CPU_R10000:
@@ -118,17 +118,17 @@
 	} while (left);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	dma_sync_phys(paddr, size, dir);
 }
 
 #ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	if (cpu_needs_post_dma_flush(dev))
+	if (cpu_needs_post_dma_flush())
 		dma_sync_phys(paddr, size, dir);
 }
 #endif
--- linux-ein-5.4.0.orig/arch/mips/mm/init.c
+++ linux-ein-5.4.0/arch/mips/mm/init.c
@@ -84,7 +84,7 @@
 static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
 {
 	enum fixed_addresses idx;
-	unsigned int uninitialized_var(old_mmid);
+	unsigned int old_mmid;
 	unsigned long vaddr, flags, entrylo;
 	unsigned long old_ctx;
 	pte_t pte;
@@ -416,7 +416,12 @@
 		       (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
 		max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
 	}
+
+	max_mapnr = highend_pfn ? highend_pfn : max_low_pfn;
+#else
+	max_mapnr = max_low_pfn;
 #endif
+	high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
 
 	free_area_init_nodes(max_zone_pfns);
 }
@@ -452,16 +457,6 @@
 	 */
 	BUILD_BUG_ON(IS_ENABLED(CONFIG_32BIT) && (_PFN_SHIFT > PAGE_SHIFT));
 
-#ifdef CONFIG_HIGHMEM
-#ifdef CONFIG_DISCONTIGMEM
-#error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet"
-#endif
-	max_mapnr = highend_pfn ? highend_pfn : max_low_pfn;
-#else
-	max_mapnr = max_low_pfn;
-#endif
-	high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-
 	maar_init();
 	memblock_free_all();
 	setup_zero_pages();	/* Setup zeroed pages.  */
--- linux-ein-5.4.0.orig/arch/mips/mm/sc-mips.c
+++ linux-ein-5.4.0/arch/mips/mm/sc-mips.c
@@ -147,7 +147,7 @@
 	return 1;
 }
 
-static int __init mips_sc_probe_cm3(void)
+static int mips_sc_probe_cm3(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 	unsigned long cfg = read_gcr_l2_config();
@@ -181,7 +181,7 @@
 	return 0;
 }
 
-static inline int __init mips_sc_probe(void)
+static inline int mips_sc_probe(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
 	unsigned int config1, config2;
--- linux-ein-5.4.0.orig/arch/mips/mm/tlb-r4k.c
+++ linux-ein-5.4.0/arch/mips/mm/tlb-r4k.c
@@ -120,7 +120,7 @@
 		if (size <= (current_cpu_data.tlbsizeftlbsets ?
 			     current_cpu_data.tlbsize / 8 :
 			     current_cpu_data.tlbsize / 2)) {
-			unsigned long old_entryhi, uninitialized_var(old_mmid);
+			unsigned long old_entryhi, old_mmid;
 			int newpid = cpu_asid(cpu, mm);
 
 			old_entryhi = read_c0_entryhi();
@@ -214,7 +214,7 @@
 	int cpu = smp_processor_id();
 
 	if (cpu_context(cpu, vma->vm_mm) != 0) {
-		unsigned long uninitialized_var(old_mmid);
+		unsigned long old_mmid;
 		unsigned long flags, old_entryhi;
 		int idx;
 
@@ -381,7 +381,7 @@
 #ifdef CONFIG_XPA
 	panic("Broken for XPA kernels");
 #else
-	unsigned int uninitialized_var(old_mmid);
+	unsigned int old_mmid;
 	unsigned long flags;
 	unsigned long wired;
 	unsigned long old_pagemask;
@@ -437,6 +437,7 @@
 	}
 	return mask == PM_HUGE_MASK;
 }
+EXPORT_SYMBOL(has_transparent_hugepage);
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
 
--- linux-ein-5.4.0.orig/arch/mips/mm/tlbex.c
+++ linux-ein-5.4.0/arch/mips/mm/tlbex.c
@@ -629,7 +629,7 @@
 		return;
 	}
 
-	if (cpu_has_rixi && !!_PAGE_NO_EXEC) {
+	if (cpu_has_rixi && _PAGE_NO_EXEC != 0) {
 		if (fill_includes_sw_bits) {
 			UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
 		} else {
@@ -1480,6 +1480,7 @@
 
 static void setup_pw(void)
 {
+	unsigned int pwctl;
 	unsigned long pgd_i, pgd_w;
 #ifndef __PAGETABLE_PMD_FOLDED
 	unsigned long pmd_i, pmd_w;
@@ -1506,6 +1507,7 @@
 
 	pte_i = ilog2(_PAGE_GLOBAL);
 	pte_w = 0;
+	pwctl = 1 << 30; /* Set PWDirExt */
 
 #ifndef __PAGETABLE_PMD_FOLDED
 	write_c0_pwfield(pgd_i << 24 | pmd_i << 12 | pt_i << 6 | pte_i);
@@ -1516,8 +1518,9 @@
 #endif
 
 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
-	write_c0_pwctl(1 << 6 | psn);
+	pwctl |= (1 << 6 | psn);
 #endif
+	write_c0_pwctl(pwctl);
 	write_c0_kpgd((long)swapper_pg_dir);
 	kscratch_used_mask |= (1 << 7); /* KScratch6 is used for KPGD */
 }
@@ -2565,7 +2568,7 @@
 	unsigned long entry;
 	unsigned pabits, fillbits;
 
-	if (!cpu_has_rixi || !_PAGE_NO_EXEC) {
+	if (!cpu_has_rixi || _PAGE_NO_EXEC == 0) {
 		/*
 		 * We'll only be making use of the fact that we can rotate bits
 		 * into the fill if the CPU supports RIXI, so don't bother
--- linux-ein-5.4.0.orig/arch/mips/mti-malta/malta-dtshim.c
+++ linux-ein-5.4.0/arch/mips/mti-malta/malta-dtshim.c
@@ -22,7 +22,7 @@
 #define  ROCIT_CONFIG_GEN1_MEMMAP_SHIFT	8
 #define  ROCIT_CONFIG_GEN1_MEMMAP_MASK	(0xf << 8)
 
-static unsigned char fdt_buf[16 << 10] __initdata;
+static unsigned char fdt_buf[16 << 10] __initdata __aligned(8);
 
 /* determined physical memory size, not overridden by command line args	 */
 extern unsigned long physical_memsize;
--- linux-ein-5.4.0.orig/arch/mips/mti-malta/malta-platform.c
+++ linux-ein-5.4.0/arch/mips/mti-malta/malta-platform.c
@@ -47,7 +47,8 @@
 		.mapbase	= 0x1f000900,	/* The CBUS UART */
 		.irq		= MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2,
 		.uartclk	= 3686400,	/* Twice the usual clk! */
-		.iotype		= UPIO_MEM32,
+		.iotype		= IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
+				  UPIO_MEM32BE : UPIO_MEM32,
 		.flags		= CBUS_UART_FLAGS,
 		.regshift	= 3,
 	},
--- linux-ein-5.4.0.orig/arch/mips/net/Makefile
+++ linux-ein-5.4.0/arch/mips/net/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 # MIPS networking code
 
+obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o
 obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o
--- linux-ein-5.4.0.orig/arch/mips/net/bpf_jit.c
+++ linux-ein-5.4.0/arch/mips/net/bpf_jit.c
@@ -0,0 +1,1299 @@
+/*
+ * Just-In-Time compiler for BPF filters on MIPS
+ *
+ * Copyright (c) 2014 Imagination Technologies Ltd.
+ * Author: Markos Chandras <markos.chandras@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/filter.h>
+#include <linux/if_vlan.h>
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/asm.h>
+#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+#include <asm/cpu-features.h>
+#include <asm/uasm.h>
+
+#include "bpf_jit.h"
+
+/* ABI
+ * r_skb_hl	SKB header length
+ * r_data	SKB data pointer
+ * r_off	Offset
+ * r_A		BPF register A
+ * r_X		BPF register X
+ * r_skb	*skb
+ * r_M		*scratch memory
+ * r_skb_len	SKB length
+ *
+ * On entry (*bpf_func)(*skb, *filter)
+ * a0 = MIPS_R_A0 = skb;
+ * a1 = MIPS_R_A1 = filter;
+ *
+ * Stack
+ * ...
+ * M[15]
+ * M[14]
+ * M[13]
+ * ...
+ * M[0] <-- r_M
+ * saved reg k-1
+ * saved reg k-2
+ * ...
+ * saved reg 0 <-- r_sp
+ * <no argument area>
+ *
+ *                     Packet layout
+ *
+ * <--------------------- len ------------------------>
+ * <--skb-len(r_skb_hl)-->< ----- skb->data_len ------>
+ * ----------------------------------------------------
+ * |                  skb->data                       |
+ * ----------------------------------------------------
+ */
+
+#define ptr typeof(unsigned long)
+
+#define SCRATCH_OFF(k)		(4 * (k))
+
+/* JIT flags */
+#define SEEN_CALL		(1 << BPF_MEMWORDS)
+#define SEEN_SREG_SFT		(BPF_MEMWORDS + 1)
+#define SEEN_SREG_BASE		(1 << SEEN_SREG_SFT)
+#define SEEN_SREG(x)		(SEEN_SREG_BASE << (x))
+#define SEEN_OFF		SEEN_SREG(2)
+#define SEEN_A			SEEN_SREG(3)
+#define SEEN_X			SEEN_SREG(4)
+#define SEEN_SKB		SEEN_SREG(5)
+#define SEEN_MEM		SEEN_SREG(6)
+/* SEEN_SK_DATA also implies skb_hl an skb_len */
+#define SEEN_SKB_DATA		(SEEN_SREG(7) | SEEN_SREG(1) | SEEN_SREG(0))
+
+/* Arguments used by JIT */
+#define ARGS_USED_BY_JIT	2 /* only applicable to 64-bit */
+
+#define SBIT(x)			(1 << (x)) /* Signed version of BIT() */
+
+/**
+ * struct jit_ctx - JIT context
+ * @skf:		The sk_filter
+ * @prologue_bytes:	Number of bytes for prologue
+ * @idx:		Instruction index
+ * @flags:		JIT flags
+ * @offsets:		Instruction offsets
+ * @target:		Memory location for the compiled filter
+ */
+struct jit_ctx {
+	const struct bpf_prog *skf;
+	unsigned int prologue_bytes;
+	u32 idx;
+	u32 flags;
+	u32 *offsets;
+	u32 *target;
+};
+
+
+static inline int optimize_div(u32 *k)
+{
+	/* power of 2 divides can be implemented with right shift */
+	if (!(*k & (*k-1))) {
+		*k = ilog2(*k);
+		return 1;
+	}
+
+	return 0;
+}
+
+static inline void emit_jit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx);
+
+/* Simply emit the instruction if the JIT memory space has been allocated */
+#define emit_instr(ctx, func, ...)			\
+do {							\
+	if ((ctx)->target != NULL) {			\
+		u32 *p = &(ctx)->target[ctx->idx];	\
+		uasm_i_##func(&p, ##__VA_ARGS__);	\
+	}						\
+	(ctx)->idx++;					\
+} while (0)
+
+/*
+ * Similar to emit_instr but it must be used when we need to emit
+ * 32-bit or 64-bit instructions
+ */
+#define emit_long_instr(ctx, func, ...)			\
+do {							\
+	if ((ctx)->target != NULL) {			\
+		u32 *p = &(ctx)->target[ctx->idx];	\
+		UASM_i_##func(&p, ##__VA_ARGS__);	\
+	}						\
+	(ctx)->idx++;					\
+} while (0)
+
+/* Determine if immediate is within the 16-bit signed range */
+static inline bool is_range16(s32 imm)
+{
+	return !(imm >= SBIT(15) || imm < -SBIT(15));
+}
+
+static inline void emit_addu(unsigned int dst, unsigned int src1,
+			     unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, addu, dst, src1, src2);
+}
+
+static inline void emit_nop(struct jit_ctx *ctx)
+{
+	emit_instr(ctx, nop);
+}
+
+/* Load a u32 immediate to a register */
+static inline void emit_load_imm(unsigned int dst, u32 imm, struct jit_ctx *ctx)
+{
+	if (ctx->target != NULL) {
+		/* addiu can only handle s16 */
+		if (!is_range16(imm)) {
+			u32 *p = &ctx->target[ctx->idx];
+			uasm_i_lui(&p, r_tmp_imm, (s32)imm >> 16);
+			p = &ctx->target[ctx->idx + 1];
+			uasm_i_ori(&p, dst, r_tmp_imm, imm & 0xffff);
+		} else {
+			u32 *p = &ctx->target[ctx->idx];
+			uasm_i_addiu(&p, dst, r_zero, imm);
+		}
+	}
+	ctx->idx++;
+
+	if (!is_range16(imm))
+		ctx->idx++;
+}
+
+static inline void emit_or(unsigned int dst, unsigned int src1,
+			   unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, or, dst, src1, src2);
+}
+
+static inline void emit_ori(unsigned int dst, unsigned src, u32 imm,
+			    struct jit_ctx *ctx)
+{
+	if (imm >= BIT(16)) {
+		emit_load_imm(r_tmp, imm, ctx);
+		emit_or(dst, src, r_tmp, ctx);
+	} else {
+		emit_instr(ctx, ori, dst, src, imm);
+	}
+}
+
+static inline void emit_daddiu(unsigned int dst, unsigned int src,
+			       int imm, struct jit_ctx *ctx)
+{
+	/*
+	 * Only used for stack, so the imm is relatively small
+	 * and it fits in 15-bits
+	 */
+	emit_instr(ctx, daddiu, dst, src, imm);
+}
+
+static inline void emit_addiu(unsigned int dst, unsigned int src,
+			      u32 imm, struct jit_ctx *ctx)
+{
+	if (!is_range16(imm)) {
+		emit_load_imm(r_tmp, imm, ctx);
+		emit_addu(dst, r_tmp, src, ctx);
+	} else {
+		emit_instr(ctx, addiu, dst, src, imm);
+	}
+}
+
+static inline void emit_and(unsigned int dst, unsigned int src1,
+			    unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, and, dst, src1, src2);
+}
+
+static inline void emit_andi(unsigned int dst, unsigned int src,
+			     u32 imm, struct jit_ctx *ctx)
+{
+	/* If imm does not fit in u16 then load it to register */
+	if (imm >= BIT(16)) {
+		emit_load_imm(r_tmp, imm, ctx);
+		emit_and(dst, src, r_tmp, ctx);
+	} else {
+		emit_instr(ctx, andi, dst, src, imm);
+	}
+}
+
+static inline void emit_xor(unsigned int dst, unsigned int src1,
+			    unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, xor, dst, src1, src2);
+}
+
+static inline void emit_xori(ptr dst, ptr src, u32 imm, struct jit_ctx *ctx)
+{
+	/* If imm does not fit in u16 then load it to register */
+	if (imm >= BIT(16)) {
+		emit_load_imm(r_tmp, imm, ctx);
+		emit_xor(dst, src, r_tmp, ctx);
+	} else {
+		emit_instr(ctx, xori, dst, src, imm);
+	}
+}
+
+static inline void emit_stack_offset(int offset, struct jit_ctx *ctx)
+{
+	emit_long_instr(ctx, ADDIU, r_sp, r_sp, offset);
+}
+
+static inline void emit_subu(unsigned int dst, unsigned int src1,
+			     unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, subu, dst, src1, src2);
+}
+
+static inline void emit_neg(unsigned int reg, struct jit_ctx *ctx)
+{
+	emit_subu(reg, r_zero, reg, ctx);
+}
+
+static inline void emit_sllv(unsigned int dst, unsigned int src,
+			     unsigned int sa, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, sllv, dst, src, sa);
+}
+
+static inline void emit_sll(unsigned int dst, unsigned int src,
+			    unsigned int sa, struct jit_ctx *ctx)
+{
+	/* sa is 5-bits long */
+	if (sa >= BIT(5))
+		/* Shifting >= 32 results in zero */
+		emit_jit_reg_move(dst, r_zero, ctx);
+	else
+		emit_instr(ctx, sll, dst, src, sa);
+}
+
+static inline void emit_srlv(unsigned int dst, unsigned int src,
+			     unsigned int sa, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, srlv, dst, src, sa);
+}
+
+static inline void emit_srl(unsigned int dst, unsigned int src,
+			    unsigned int sa, struct jit_ctx *ctx)
+{
+	/* sa is 5-bits long */
+	if (sa >= BIT(5))
+		/* Shifting >= 32 results in zero */
+		emit_jit_reg_move(dst, r_zero, ctx);
+	else
+		emit_instr(ctx, srl, dst, src, sa);
+}
+
+static inline void emit_slt(unsigned int dst, unsigned int src1,
+			    unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, slt, dst, src1, src2);
+}
+
+static inline void emit_sltu(unsigned int dst, unsigned int src1,
+			     unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, sltu, dst, src1, src2);
+}
+
+static inline void emit_sltiu(unsigned dst, unsigned int src,
+			      unsigned int imm, struct jit_ctx *ctx)
+{
+	/* 16 bit immediate */
+	if (!is_range16((s32)imm)) {
+		emit_load_imm(r_tmp, imm, ctx);
+		emit_sltu(dst, src, r_tmp, ctx);
+	} else {
+		emit_instr(ctx, sltiu, dst, src, imm);
+	}
+
+}
+
+/* Store register on the stack */
+static inline void emit_store_stack_reg(ptr reg, ptr base,
+					unsigned int offset,
+					struct jit_ctx *ctx)
+{
+	emit_long_instr(ctx, SW, reg, offset, base);
+}
+
+static inline void emit_store(ptr reg, ptr base, unsigned int offset,
+			      struct jit_ctx *ctx)
+{
+	emit_instr(ctx, sw, reg, offset, base);
+}
+
+static inline void emit_load_stack_reg(ptr reg, ptr base,
+				       unsigned int offset,
+				       struct jit_ctx *ctx)
+{
+	emit_long_instr(ctx, LW, reg, offset, base);
+}
+
+static inline void emit_load(unsigned int reg, unsigned int base,
+			     unsigned int offset, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, lw, reg, offset, base);
+}
+
+static inline void emit_load_byte(unsigned int reg, unsigned int base,
+				  unsigned int offset, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, lb, reg, offset, base);
+}
+
+static inline void emit_half_load(unsigned int reg, unsigned int base,
+				  unsigned int offset, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, lh, reg, offset, base);
+}
+
+static inline void emit_half_load_unsigned(unsigned int reg, unsigned int base,
+					   unsigned int offset, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, lhu, reg, offset, base);
+}
+
+static inline void emit_mul(unsigned int dst, unsigned int src1,
+			    unsigned int src2, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, mul, dst, src1, src2);
+}
+
+static inline void emit_div(unsigned int dst, unsigned int src,
+			    struct jit_ctx *ctx)
+{
+	if (ctx->target != NULL) {
+		u32 *p = &ctx->target[ctx->idx];
+		uasm_i_divu(&p, dst, src);
+		p = &ctx->target[ctx->idx + 1];
+		uasm_i_mflo(&p, dst);
+	}
+	ctx->idx += 2; /* 2 insts */
+}
+
+static inline void emit_mod(unsigned int dst, unsigned int src,
+			    struct jit_ctx *ctx)
+{
+	if (ctx->target != NULL) {
+		u32 *p = &ctx->target[ctx->idx];
+		uasm_i_divu(&p, dst, src);
+		p = &ctx->target[ctx->idx + 1];
+		uasm_i_mfhi(&p, dst);
+	}
+	ctx->idx += 2; /* 2 insts */
+}
+
+static inline void emit_dsll(unsigned int dst, unsigned int src,
+			     unsigned int sa, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, dsll, dst, src, sa);
+}
+
+static inline void emit_dsrl32(unsigned int dst, unsigned int src,
+			       unsigned int sa, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, dsrl32, dst, src, sa);
+}
+
+static inline void emit_wsbh(unsigned int dst, unsigned int src,
+			     struct jit_ctx *ctx)
+{
+	emit_instr(ctx, wsbh, dst, src);
+}
+
+/* load pointer to register */
+static inline void emit_load_ptr(unsigned int dst, unsigned int src,
+				     int imm, struct jit_ctx *ctx)
+{
+	/* src contains the base addr of the 32/64-pointer */
+	emit_long_instr(ctx, LW, dst, imm, src);
+}
+
+/* load a function pointer to register */
+static inline void emit_load_func(unsigned int reg, ptr imm,
+				  struct jit_ctx *ctx)
+{
+	if (IS_ENABLED(CONFIG_64BIT)) {
+		/* At this point imm is always 64-bit */
+		emit_load_imm(r_tmp, (u64)imm >> 32, ctx);
+		emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */
+		emit_ori(r_tmp, r_tmp_imm, (imm >> 16) & 0xffff, ctx);
+		emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */
+		emit_ori(reg, r_tmp_imm, imm & 0xffff, ctx);
+	} else {
+		emit_load_imm(reg, imm, ctx);
+	}
+}
+
+/* Move to real MIPS register */
+static inline void emit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx)
+{
+	emit_long_instr(ctx, ADDU, dst, src, r_zero);
+}
+
+/* Move to JIT (32-bit) register */
+static inline void emit_jit_reg_move(ptr dst, ptr src, struct jit_ctx *ctx)
+{
+	emit_addu(dst, src, r_zero, ctx);
+}
+
+/* Compute the immediate value for PC-relative branches. */
+static inline u32 b_imm(unsigned int tgt, struct jit_ctx *ctx)
+{
+	if (ctx->target == NULL)
+		return 0;
+
+	/*
+	 * We want a pc-relative branch. We only do forward branches
+	 * so tgt is always after pc. tgt is the instruction offset
+	 * we want to jump to.
+
+	 * Branch on MIPS:
+	 * I: target_offset <- sign_extend(offset)
+	 * I+1: PC += target_offset (delay slot)
+	 *
+	 * ctx->idx currently points to the branch instruction
+	 * but the offset is added to the delay slot so we need
+	 * to subtract 4.
+	 */
+	return ctx->offsets[tgt] -
+		(ctx->idx * 4 - ctx->prologue_bytes) - 4;
+}
+
+static inline void emit_bcond(int cond, unsigned int reg1, unsigned int reg2,
+			     unsigned int imm, struct jit_ctx *ctx)
+{
+	if (ctx->target != NULL) {
+		u32 *p = &ctx->target[ctx->idx];
+
+		switch (cond) {
+		case MIPS_COND_EQ:
+			uasm_i_beq(&p, reg1, reg2, imm);
+			break;
+		case MIPS_COND_NE:
+			uasm_i_bne(&p, reg1, reg2, imm);
+			break;
+		case MIPS_COND_ALL:
+			uasm_i_b(&p, imm);
+			break;
+		default:
+			pr_warn("%s: Unhandled branch conditional: %d\n",
+				__func__, cond);
+		}
+	}
+	ctx->idx++;
+}
+
+static inline void emit_b(unsigned int imm, struct jit_ctx *ctx)
+{
+	emit_bcond(MIPS_COND_ALL, r_zero, r_zero, imm, ctx);
+}
+
+static inline void emit_jalr(unsigned int link, unsigned int reg,
+			     struct jit_ctx *ctx)
+{
+	emit_instr(ctx, jalr, link, reg);
+}
+
+static inline void emit_jr(unsigned int reg, struct jit_ctx *ctx)
+{
+	emit_instr(ctx, jr, reg);
+}
+
+static inline u16 align_sp(unsigned int num)
+{
+	/* Double word alignment for 32-bit, quadword for 64-bit */
+	unsigned int align = IS_ENABLED(CONFIG_64BIT) ? 16 : 8;
+	num = (num + (align - 1)) & -align;
+	return num;
+}
+
+static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
+{
+	int i = 0, real_off = 0;
+	u32 sflags, tmp_flags;
+
+	/* Adjust the stack pointer */
+	if (offset)
+		emit_stack_offset(-align_sp(offset), ctx);
+
+	tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
+	/* sflags is essentially a bitmap */
+	while (tmp_flags) {
+		if ((sflags >> i) & 0x1) {
+			emit_store_stack_reg(MIPS_R_S0 + i, r_sp, real_off,
+					     ctx);
+			real_off += SZREG;
+		}
+		i++;
+		tmp_flags >>= 1;
+	}
+
+	/* save return address */
+	if (ctx->flags & SEEN_CALL) {
+		emit_store_stack_reg(r_ra, r_sp, real_off, ctx);
+		real_off += SZREG;
+	}
+
+	/* Setup r_M leaving the alignment gap if necessary */
+	if (ctx->flags & SEEN_MEM) {
+		if (real_off % (SZREG * 2))
+			real_off += SZREG;
+		emit_long_instr(ctx, ADDIU, r_M, r_sp, real_off);
+	}
+}
+
+static void restore_bpf_jit_regs(struct jit_ctx *ctx,
+				 unsigned int offset)
+{
+	int i, real_off = 0;
+	u32 sflags, tmp_flags;
+
+	tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
+	/* sflags is a bitmap */
+	i = 0;
+	while (tmp_flags) {
+		if ((sflags >> i) & 0x1) {
+			emit_load_stack_reg(MIPS_R_S0 + i, r_sp, real_off,
+					    ctx);
+			real_off += SZREG;
+		}
+		i++;
+		tmp_flags >>= 1;
+	}
+
+	/* restore return address */
+	if (ctx->flags & SEEN_CALL)
+		emit_load_stack_reg(r_ra, r_sp, real_off, ctx);
+
+	/* Restore the sp and discard the scrach memory */
+	if (offset)
+		emit_stack_offset(align_sp(offset), ctx);
+}
+
+static unsigned int get_stack_depth(struct jit_ctx *ctx)
+{
+	int sp_off = 0;
+
+
+	/* How may s* regs do we need to preserved? */
+	sp_off += hweight32(ctx->flags >> SEEN_SREG_SFT) * SZREG;
+
+	if (ctx->flags & SEEN_MEM)
+		sp_off += 4 * BPF_MEMWORDS; /* BPF_MEMWORDS are 32-bit */
+
+	if (ctx->flags & SEEN_CALL)
+		sp_off += SZREG; /* Space for our ra register */
+
+	return sp_off;
+}
+
+static void build_prologue(struct jit_ctx *ctx)
+{
+	int sp_off;
+
+	/* Calculate the total offset for the stack pointer */
+	sp_off = get_stack_depth(ctx);
+	save_bpf_jit_regs(ctx, sp_off);
+
+	if (ctx->flags & SEEN_SKB)
+		emit_reg_move(r_skb, MIPS_R_A0, ctx);
+
+	if (ctx->flags & SEEN_SKB_DATA) {
+		/* Load packet length */
+		emit_load(r_skb_len, r_skb, offsetof(struct sk_buff, len),
+			  ctx);
+		emit_load(r_tmp, r_skb, offsetof(struct sk_buff, data_len),
+			  ctx);
+		/* Load the data pointer */
+		emit_load_ptr(r_skb_data, r_skb,
+			      offsetof(struct sk_buff, data), ctx);
+		/* Load the header length */
+		emit_subu(r_skb_hl, r_skb_len, r_tmp, ctx);
+	}
+
+	if (ctx->flags & SEEN_X)
+		emit_jit_reg_move(r_X, r_zero, ctx);
+
+	/*
+	 * 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);
+}
+
+static void build_epilogue(struct jit_ctx *ctx)
+{
+	unsigned int sp_off;
+
+	/* Calculate the total offset for the stack pointer */
+
+	sp_off = get_stack_depth(ctx);
+	restore_bpf_jit_regs(ctx, sp_off);
+
+	/* Return */
+	emit_jr(r_ra, ctx);
+	emit_nop(ctx);
+}
+
+#define CHOOSE_LOAD_FUNC(K, func) \
+	((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative : func) : \
+	 func##_positive)
+
+static bool is_bad_offset(int b_off)
+{
+	return b_off > 0x1ffff || b_off < -0x20000;
+}
+
+static int build_body(struct jit_ctx *ctx)
+{
+	const struct bpf_prog *prog = ctx->skf;
+	const struct sock_filter *inst;
+	unsigned int i, off, condt;
+	u32 k, b_off __maybe_unused;
+	u8 (*sk_load_func)(unsigned long *skb, int offset);
+
+	for (i = 0; i < prog->len; i++) {
+		u16 code;
+
+		inst = &(prog->insns[i]);
+		pr_debug("%s: code->0x%02x, jt->0x%x, jf->0x%x, k->0x%x\n",
+			 __func__, inst->code, inst->jt, inst->jf, inst->k);
+		k = inst->k;
+		code = bpf_anc_helper(inst);
+
+		if (ctx->target == NULL)
+			ctx->offsets[i] = ctx->idx * 4;
+
+		switch (code) {
+		case BPF_LD | BPF_IMM:
+			/* A <- k ==> li r_A, k */
+			ctx->flags |= SEEN_A;
+			emit_load_imm(r_A, k, ctx);
+			break;
+		case BPF_LD | BPF_W | BPF_LEN:
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+			/* A <- len ==> lw r_A, offset(skb) */
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			off = offsetof(struct sk_buff, len);
+			emit_load(r_A, r_skb, off, ctx);
+			break;
+		case BPF_LD | BPF_MEM:
+			/* A <- M[k] ==> lw r_A, offset(M) */
+			ctx->flags |= SEEN_MEM | SEEN_A;
+			emit_load(r_A, r_M, SCRATCH_OFF(k), ctx);
+			break;
+		case BPF_LD | BPF_W | BPF_ABS:
+			/* A <- P[k:4] */
+			sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_word);
+			goto load;
+		case BPF_LD | BPF_H | BPF_ABS:
+			/* A <- P[k:2] */
+			sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_half);
+			goto load;
+		case BPF_LD | BPF_B | BPF_ABS:
+			/* A <- P[k:1] */
+			sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_byte);
+load:
+			emit_load_imm(r_off, k, ctx);
+load_common:
+			ctx->flags |= SEEN_CALL | SEEN_OFF |
+				SEEN_SKB | SEEN_A | SEEN_SKB_DATA;
+
+			emit_load_func(r_s0, (ptr)sk_load_func, ctx);
+			emit_reg_move(MIPS_R_A0, r_skb, ctx);
+			emit_jalr(MIPS_R_RA, r_s0, ctx);
+			/* Load second argument to delay slot */
+			emit_reg_move(MIPS_R_A1, r_off, ctx);
+			/* Check the error value */
+			emit_bcond(MIPS_COND_EQ, r_ret, 0, b_imm(i + 1, ctx),
+				   ctx);
+			/* Load return register on DS for failures */
+			emit_reg_move(r_ret, r_zero, ctx);
+			/* Return with error */
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_b(b_off, ctx);
+			emit_nop(ctx);
+			break;
+		case BPF_LD | BPF_W | BPF_IND:
+			/* A <- P[X + k:4] */
+			sk_load_func = sk_load_word;
+			goto load_ind;
+		case BPF_LD | BPF_H | BPF_IND:
+			/* A <- P[X + k:2] */
+			sk_load_func = sk_load_half;
+			goto load_ind;
+		case BPF_LD | BPF_B | BPF_IND:
+			/* A <- P[X + k:1] */
+			sk_load_func = sk_load_byte;
+load_ind:
+			ctx->flags |= SEEN_OFF | SEEN_X;
+			emit_addiu(r_off, r_X, k, ctx);
+			goto load_common;
+		case BPF_LDX | BPF_IMM:
+			/* X <- k */
+			ctx->flags |= SEEN_X;
+			emit_load_imm(r_X, k, ctx);
+			break;
+		case BPF_LDX | BPF_MEM:
+			/* X <- M[k] */
+			ctx->flags |= SEEN_X | SEEN_MEM;
+			emit_load(r_X, r_M, SCRATCH_OFF(k), ctx);
+			break;
+		case BPF_LDX | BPF_W | BPF_LEN:
+			/* X <- len */
+			ctx->flags |= SEEN_X | SEEN_SKB;
+			off = offsetof(struct sk_buff, len);
+			emit_load(r_X, r_skb, off, ctx);
+			break;
+		case BPF_LDX | BPF_B | BPF_MSH:
+			/* X <- 4 * (P[k:1] & 0xf) */
+			ctx->flags |= SEEN_X | SEEN_CALL | SEEN_SKB;
+			/* Load offset to a1 */
+			emit_load_func(r_s0, (ptr)sk_load_byte, ctx);
+			/*
+			 * This may emit two instructions so it may not fit
+			 * in the delay slot. So use a0 in the delay slot.
+			 */
+			emit_load_imm(MIPS_R_A1, k, ctx);
+			emit_jalr(MIPS_R_RA, r_s0, ctx);
+			emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */
+			/* Check the error value */
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_NE, r_ret, 0, b_off, ctx);
+			emit_reg_move(r_ret, r_zero, ctx);
+			/* We are good */
+			/* X <- P[1:K] & 0xf */
+			emit_andi(r_X, r_A, 0xf, ctx);
+			/* X << 2 */
+			emit_b(b_imm(i + 1, ctx), ctx);
+			emit_sll(r_X, r_X, 2, ctx); /* delay slot */
+			break;
+		case BPF_ST:
+			/* M[k] <- A */
+			ctx->flags |= SEEN_MEM | SEEN_A;
+			emit_store(r_A, r_M, SCRATCH_OFF(k), ctx);
+			break;
+		case BPF_STX:
+			/* M[k] <- X */
+			ctx->flags |= SEEN_MEM | SEEN_X;
+			emit_store(r_X, r_M, SCRATCH_OFF(k), ctx);
+			break;
+		case BPF_ALU | BPF_ADD | BPF_K:
+			/* A += K */
+			ctx->flags |= SEEN_A;
+			emit_addiu(r_A, r_A, k, ctx);
+			break;
+		case BPF_ALU | BPF_ADD | BPF_X:
+			/* A += X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_addu(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_SUB | BPF_K:
+			/* A -= K */
+			ctx->flags |= SEEN_A;
+			emit_addiu(r_A, r_A, -k, ctx);
+			break;
+		case BPF_ALU | BPF_SUB | BPF_X:
+			/* A -= X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_subu(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_MUL | BPF_K:
+			/* A *= K */
+			/* Load K to scratch register before MUL */
+			ctx->flags |= SEEN_A;
+			emit_load_imm(r_s0, k, ctx);
+			emit_mul(r_A, r_A, r_s0, ctx);
+			break;
+		case BPF_ALU | BPF_MUL | BPF_X:
+			/* A *= X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_mul(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_DIV | BPF_K:
+			/* A /= k */
+			if (k == 1)
+				break;
+			if (optimize_div(&k)) {
+				ctx->flags |= SEEN_A;
+				emit_srl(r_A, r_A, k, ctx);
+				break;
+			}
+			ctx->flags |= SEEN_A;
+			emit_load_imm(r_s0, k, ctx);
+			emit_div(r_A, r_s0, ctx);
+			break;
+		case BPF_ALU | BPF_MOD | BPF_K:
+			/* A %= k */
+			if (k == 1) {
+				ctx->flags |= SEEN_A;
+				emit_jit_reg_move(r_A, r_zero, ctx);
+			} else {
+				ctx->flags |= SEEN_A;
+				emit_load_imm(r_s0, k, ctx);
+				emit_mod(r_A, r_s0, ctx);
+			}
+			break;
+		case BPF_ALU | BPF_DIV | BPF_X:
+			/* A /= X */
+			ctx->flags |= SEEN_X | SEEN_A;
+			/* Check if r_X is zero */
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
+			emit_load_imm(r_ret, 0, ctx); /* delay slot */
+			emit_div(r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_MOD | BPF_X:
+			/* A %= X */
+			ctx->flags |= SEEN_X | SEEN_A;
+			/* Check if r_X is zero */
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
+			emit_load_imm(r_ret, 0, ctx); /* delay slot */
+			emit_mod(r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_OR | BPF_K:
+			/* A |= K */
+			ctx->flags |= SEEN_A;
+			emit_ori(r_A, r_A, k, ctx);
+			break;
+		case BPF_ALU | BPF_OR | BPF_X:
+			/* A |= X */
+			ctx->flags |= SEEN_A;
+			emit_ori(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_XOR | BPF_K:
+			/* A ^= k */
+			ctx->flags |= SEEN_A;
+			emit_xori(r_A, r_A, k, ctx);
+			break;
+		case BPF_ANC | SKF_AD_ALU_XOR_X:
+		case BPF_ALU | BPF_XOR | BPF_X:
+			/* A ^= X */
+			ctx->flags |= SEEN_A;
+			emit_xor(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_AND | BPF_K:
+			/* A &= K */
+			ctx->flags |= SEEN_A;
+			emit_andi(r_A, r_A, k, ctx);
+			break;
+		case BPF_ALU | BPF_AND | BPF_X:
+			/* A &= X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_and(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_LSH | BPF_K:
+			/* A <<= K */
+			ctx->flags |= SEEN_A;
+			emit_sll(r_A, r_A, k, ctx);
+			break;
+		case BPF_ALU | BPF_LSH | BPF_X:
+			/* A <<= X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_sllv(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_RSH | BPF_K:
+			/* A >>= K */
+			ctx->flags |= SEEN_A;
+			emit_srl(r_A, r_A, k, ctx);
+			break;
+		case BPF_ALU | BPF_RSH | BPF_X:
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_srlv(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_ALU | BPF_NEG:
+			/* A = -A */
+			ctx->flags |= SEEN_A;
+			emit_neg(r_A, ctx);
+			break;
+		case BPF_JMP | BPF_JA:
+			/* pc += K */
+			b_off = b_imm(i + k + 1, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_b(b_off, ctx);
+			emit_nop(ctx);
+			break;
+		case BPF_JMP | BPF_JEQ | BPF_K:
+			/* pc += ( A == K ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_EQ | MIPS_COND_K;
+			goto jmp_cmp;
+		case BPF_JMP | BPF_JEQ | BPF_X:
+			ctx->flags |= SEEN_X;
+			/* pc += ( A == X ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_EQ | MIPS_COND_X;
+			goto jmp_cmp;
+		case BPF_JMP | BPF_JGE | BPF_K:
+			/* pc += ( A >= K ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_GE | MIPS_COND_K;
+			goto jmp_cmp;
+		case BPF_JMP | BPF_JGE | BPF_X:
+			ctx->flags |= SEEN_X;
+			/* pc += ( A >= X ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_GE | MIPS_COND_X;
+			goto jmp_cmp;
+		case BPF_JMP | BPF_JGT | BPF_K:
+			/* pc += ( A > K ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_GT | MIPS_COND_K;
+			goto jmp_cmp;
+		case BPF_JMP | BPF_JGT | BPF_X:
+			ctx->flags |= SEEN_X;
+			/* pc += ( A > X ) ? pc->jt : pc->jf */
+			condt = MIPS_COND_GT | MIPS_COND_X;
+jmp_cmp:
+			/* Greater or Equal */
+			if ((condt & MIPS_COND_GE) ||
+			    (condt & MIPS_COND_GT)) {
+				if (condt & MIPS_COND_K) { /* K */
+					ctx->flags |= SEEN_A;
+					emit_sltiu(r_s0, r_A, k, ctx);
+				} else { /* X */
+					ctx->flags |= SEEN_A |
+						SEEN_X;
+					emit_sltu(r_s0, r_A, r_X, ctx);
+				}
+				/* A < (K|X) ? r_scrach = 1 */
+				b_off = b_imm(i + inst->jf + 1, ctx);
+				emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off,
+					   ctx);
+				emit_nop(ctx);
+				/* A > (K|X) ? scratch = 0 */
+				if (condt & MIPS_COND_GT) {
+					/* Checking for equality */
+					ctx->flags |= SEEN_A | SEEN_X;
+					if (condt & MIPS_COND_K)
+						emit_load_imm(r_s0, k, ctx);
+					else
+						emit_jit_reg_move(r_s0, r_X,
+								  ctx);
+					b_off = b_imm(i + inst->jf + 1, ctx);
+					emit_bcond(MIPS_COND_EQ, r_A, r_s0,
+						   b_off, ctx);
+					emit_nop(ctx);
+					/* Finally, A > K|X */
+					b_off = b_imm(i + inst->jt + 1, ctx);
+					emit_b(b_off, ctx);
+					emit_nop(ctx);
+				} else {
+					/* A >= (K|X) so jump */
+					b_off = b_imm(i + inst->jt + 1, ctx);
+					emit_b(b_off, ctx);
+					emit_nop(ctx);
+				}
+			} else {
+				/* A == K|X */
+				if (condt & MIPS_COND_K) { /* K */
+					ctx->flags |= SEEN_A;
+					emit_load_imm(r_s0, k, ctx);
+					/* jump true */
+					b_off = b_imm(i + inst->jt + 1, ctx);
+					emit_bcond(MIPS_COND_EQ, r_A, r_s0,
+						   b_off, ctx);
+					emit_nop(ctx);
+					/* jump false */
+					b_off = b_imm(i + inst->jf + 1,
+						      ctx);
+					emit_bcond(MIPS_COND_NE, r_A, r_s0,
+						   b_off, ctx);
+					emit_nop(ctx);
+				} else { /* X */
+					/* jump true */
+					ctx->flags |= SEEN_A | SEEN_X;
+					b_off = b_imm(i + inst->jt + 1,
+						      ctx);
+					emit_bcond(MIPS_COND_EQ, r_A, r_X,
+						   b_off, ctx);
+					emit_nop(ctx);
+					/* jump false */
+					b_off = b_imm(i + inst->jf + 1, ctx);
+					emit_bcond(MIPS_COND_NE, r_A, r_X,
+						   b_off, ctx);
+					emit_nop(ctx);
+				}
+			}
+			break;
+		case BPF_JMP | BPF_JSET | BPF_K:
+			ctx->flags |= SEEN_A;
+			/* pc += (A & K) ? pc -> jt : pc -> jf */
+			emit_load_imm(r_s1, k, ctx);
+			emit_and(r_s0, r_A, r_s1, ctx);
+			/* jump true */
+			b_off = b_imm(i + inst->jt + 1, ctx);
+			emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx);
+			emit_nop(ctx);
+			/* jump false */
+			b_off = b_imm(i + inst->jf + 1, ctx);
+			emit_b(b_off, ctx);
+			emit_nop(ctx);
+			break;
+		case BPF_JMP | BPF_JSET | BPF_X:
+			ctx->flags |= SEEN_X | SEEN_A;
+			/* pc += (A & X) ? pc -> jt : pc -> jf */
+			emit_and(r_s0, r_A, r_X, ctx);
+			/* jump true */
+			b_off = b_imm(i + inst->jt + 1, ctx);
+			emit_bcond(MIPS_COND_NE, r_s0, r_zero, b_off, ctx);
+			emit_nop(ctx);
+			/* jump false */
+			b_off = b_imm(i + inst->jf + 1, ctx);
+			emit_b(b_off, ctx);
+			emit_nop(ctx);
+			break;
+		case BPF_RET | BPF_A:
+			ctx->flags |= SEEN_A;
+			if (i != prog->len - 1) {
+				/*
+				 * If this is not the last instruction
+				 * then jump to the epilogue
+				 */
+				b_off = b_imm(prog->len, ctx);
+				if (is_bad_offset(b_off))
+					return -E2BIG;
+				emit_b(b_off, ctx);
+			}
+			emit_reg_move(r_ret, r_A, ctx); /* delay slot */
+			break;
+		case BPF_RET | BPF_K:
+			/*
+			 * It can emit two instructions so it does not fit on
+			 * the delay slot.
+			 */
+			emit_load_imm(r_ret, k, ctx);
+			if (i != prog->len - 1) {
+				/*
+				 * If this is not the last instruction
+				 * then jump to the epilogue
+				 */
+				b_off = b_imm(prog->len, ctx);
+				if (is_bad_offset(b_off))
+					return -E2BIG;
+				emit_b(b_off, ctx);
+				emit_nop(ctx);
+			}
+			break;
+		case BPF_MISC | BPF_TAX:
+			/* X = A */
+			ctx->flags |= SEEN_X | SEEN_A;
+			emit_jit_reg_move(r_X, r_A, ctx);
+			break;
+		case BPF_MISC | BPF_TXA:
+			/* A = X */
+			ctx->flags |= SEEN_A | SEEN_X;
+			emit_jit_reg_move(r_A, r_X, ctx);
+			break;
+		/* AUX */
+		case BPF_ANC | SKF_AD_PROTOCOL:
+			/* A = ntohs(skb->protocol */
+			ctx->flags |= SEEN_SKB | SEEN_OFF | SEEN_A;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  protocol) != 2);
+			off = offsetof(struct sk_buff, protocol);
+			emit_half_load(r_A, r_skb, off, ctx);
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+			/* This needs little endian fixup */
+			if (cpu_has_wsbh) {
+				/* R2 and later have the wsbh instruction */
+				emit_wsbh(r_A, r_A, ctx);
+			} else {
+				/* Get first byte */
+				emit_andi(r_tmp_imm, r_A, 0xff, ctx);
+				/* Shift it */
+				emit_sll(r_tmp, r_tmp_imm, 8, ctx);
+				/* Get second byte */
+				emit_srl(r_tmp_imm, r_A, 8, ctx);
+				emit_andi(r_tmp_imm, r_tmp_imm, 0xff, ctx);
+				/* Put everyting together in r_A */
+				emit_or(r_A, r_tmp, r_tmp_imm, ctx);
+			}
+#endif
+			break;
+		case BPF_ANC | SKF_AD_CPU:
+			ctx->flags |= SEEN_A | SEEN_OFF;
+			/* A = current_thread_info()->cpu */
+			BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info,
+						  cpu) != 4);
+			off = offsetof(struct thread_info, cpu);
+			/* $28/gp points to the thread_info struct */
+			emit_load(r_A, 28, off, ctx);
+			break;
+		case BPF_ANC | SKF_AD_IFINDEX:
+			/* A = skb->dev->ifindex */
+		case BPF_ANC | SKF_AD_HATYPE:
+			/* A = skb->dev->type */
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			off = offsetof(struct sk_buff, dev);
+			/* Load *dev pointer */
+			emit_load_ptr(r_s0, r_skb, off, ctx);
+			/* error (0) in the delay slot */
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_s0, r_zero, b_off, ctx);
+			emit_reg_move(r_ret, r_zero, ctx);
+			if (code == (BPF_ANC | SKF_AD_IFINDEX)) {
+				BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+				off = offsetof(struct net_device, ifindex);
+				emit_load(r_A, r_s0, off, ctx);
+			} else { /* (code == (BPF_ANC | SKF_AD_HATYPE) */
+				BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
+				off = offsetof(struct net_device, type);
+				emit_half_load_unsigned(r_A, r_s0, off, ctx);
+			}
+			break;
+		case BPF_ANC | SKF_AD_MARK:
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+			off = offsetof(struct sk_buff, mark);
+			emit_load(r_A, r_skb, off, ctx);
+			break;
+		case BPF_ANC | SKF_AD_RXHASH:
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+			off = offsetof(struct sk_buff, hash);
+			emit_load(r_A, r_skb, off, ctx);
+			break;
+		case BPF_ANC | SKF_AD_VLAN_TAG:
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  vlan_tci) != 2);
+			off = offsetof(struct sk_buff, vlan_tci);
+			emit_half_load_unsigned(r_A, r_skb, off, ctx);
+			break;
+		case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			emit_load_byte(r_A, r_skb, PKT_VLAN_PRESENT_OFFSET(), ctx);
+			if (PKT_VLAN_PRESENT_BIT)
+				emit_srl(r_A, r_A, PKT_VLAN_PRESENT_BIT, ctx);
+			if (PKT_VLAN_PRESENT_BIT < 7)
+				emit_andi(r_A, r_A, 1, ctx);
+			break;
+		case BPF_ANC | SKF_AD_PKTTYPE:
+			ctx->flags |= SEEN_SKB;
+
+			emit_load_byte(r_tmp, r_skb, PKT_TYPE_OFFSET(), ctx);
+			/* Keep only the last 3 bits */
+			emit_andi(r_A, r_tmp, PKT_TYPE_MAX, ctx);
+#ifdef __BIG_ENDIAN_BITFIELD
+			/* Get the actual packet type to the lower 3 bits */
+			emit_srl(r_A, r_A, 5, ctx);
+#endif
+			break;
+		case BPF_ANC | SKF_AD_QUEUE:
+			ctx->flags |= SEEN_SKB | SEEN_A;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  queue_mapping) != 2);
+			BUILD_BUG_ON(offsetof(struct sk_buff,
+					      queue_mapping) > 0xff);
+			off = offsetof(struct sk_buff, queue_mapping);
+			emit_half_load_unsigned(r_A, r_skb, off, ctx);
+			break;
+		default:
+			pr_debug("%s: Unhandled opcode: 0x%02x\n", __FILE__,
+				 inst->code);
+			return -1;
+		}
+	}
+
+	/* compute offsets only during the first pass */
+	if (ctx->target == NULL)
+		ctx->offsets[i] = ctx->idx * 4;
+
+	return 0;
+}
+
+void bpf_jit_compile(struct bpf_prog *fp)
+{
+	struct jit_ctx ctx;
+	unsigned int alloc_size, tmp_idx;
+
+	if (!bpf_jit_enable)
+		return;
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	ctx.offsets = kcalloc(fp->len + 1, sizeof(*ctx.offsets), GFP_KERNEL);
+	if (ctx.offsets == NULL)
+		return;
+
+	ctx.skf = fp;
+
+	if (build_body(&ctx))
+		goto out;
+
+	tmp_idx = ctx.idx;
+	build_prologue(&ctx);
+	ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
+	/* just to complete the ctx.idx count */
+	build_epilogue(&ctx);
+
+	alloc_size = 4 * ctx.idx;
+	ctx.target = module_alloc(alloc_size);
+	if (ctx.target == NULL)
+		goto out;
+
+	/* Clean it */
+	memset(ctx.target, 0, alloc_size);
+
+	ctx.idx = 0;
+
+	/* Generate the actual JIT code */
+	build_prologue(&ctx);
+	if (build_body(&ctx)) {
+		module_memfree(ctx.target);
+		goto out;
+	}
+	build_epilogue(&ctx);
+
+	/* Update the icache */
+	flush_icache_range((ptr)ctx.target, (ptr)(ctx.target + ctx.idx));
+
+	if (bpf_jit_enable > 1)
+		/* Dump JIT code */
+		bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
+
+	fp->bpf_func = (void *)ctx.target;
+	fp->jited = 1;
+
+out:
+	kfree(ctx.offsets);
+}
+
+void bpf_jit_free(struct bpf_prog *fp)
+{
+	if (fp->jited)
+		module_memfree(fp->bpf_func);
+
+	bpf_prog_unlock_free(fp);
+}
--- linux-ein-5.4.0.orig/arch/mips/net/bpf_jit_asm.S
+++ linux-ein-5.4.0/arch/mips/net/bpf_jit_asm.S
@@ -0,0 +1,285 @@
+/*
+ * bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF
+ * compiler.
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ * Author: Markos Chandras <markos.chandras@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <asm/asm.h>
+#include <asm/isa-rev.h>
+#include <asm/regdef.h>
+#include "bpf_jit.h"
+
+/* ABI
+ *
+ * r_skb_hl	skb header length
+ * r_skb_data	skb data
+ * r_off(a1)	offset register
+ * r_A		BPF register A
+ * r_X		PF register X
+ * r_skb(a0)	*skb
+ * r_M		*scratch memory
+ * r_skb_le	skb length
+ * r_s0		Scratch register 0
+ * r_s1		Scratch register 1
+ *
+ * On entry:
+ * a0: *skb
+ * a1: offset (imm or imm + X)
+ *
+ * All non-BPF-ABI registers are free for use. On return, we only
+ * care about r_ret. The BPF-ABI registers are assumed to remain
+ * unmodified during the entire filter operation.
+ */
+
+#define skb	a0
+#define offset	a1
+#define SKF_LL_OFF  (-0x200000) /* Can't include linux/filter.h in assembly */
+
+	/* We know better :) so prevent assembler reordering etc */
+	.set 	noreorder
+
+#define is_offset_negative(TYPE)				\
+	/* If offset is negative we have more work to do */	\
+	slti	t0, offset, 0;					\
+	bgtz	t0, bpf_slow_path_##TYPE##_neg;			\
+	/* Be careful what follows in DS. */
+
+#define is_offset_in_header(SIZE, TYPE)				\
+	/* Reading from header? */				\
+	addiu	$r_s0, $r_skb_hl, -SIZE;			\
+	slt	t0, $r_s0, offset;				\
+	bgtz	t0, bpf_slow_path_##TYPE;			\
+
+LEAF(sk_load_word)
+	is_offset_negative(word)
+FEXPORT(sk_load_word_positive)
+	is_offset_in_header(4, word)
+	/* Offset within header boundaries */
+	PTR_ADDU t1, $r_skb_data, offset
+	.set	reorder
+	lw	$r_A, 0(t1)
+	.set	noreorder
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# if MIPS_ISA_REV >= 2
+	wsbh	t0, $r_A
+	rotr	$r_A, t0, 16
+# else
+	sll	t0, $r_A, 24
+	srl	t1, $r_A, 24
+	srl	t2, $r_A, 8
+	or	t0, t0, t1
+	andi	t2, t2, 0xff00
+	andi	t1, $r_A, 0xff00
+	or	t0, t0, t2
+	sll	t1, t1, 8
+	or	$r_A, t0, t1
+# endif
+#endif
+	jr	$r_ra
+	 move	$r_ret, zero
+	END(sk_load_word)
+
+LEAF(sk_load_half)
+	is_offset_negative(half)
+FEXPORT(sk_load_half_positive)
+	is_offset_in_header(2, half)
+	/* Offset within header boundaries */
+	PTR_ADDU t1, $r_skb_data, offset
+	lhu	$r_A, 0(t1)
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# if MIPS_ISA_REV >= 2
+	wsbh	$r_A, $r_A
+# else
+	sll	t0, $r_A, 8
+	srl	t1, $r_A, 8
+	andi	t0, t0, 0xff00
+	or	$r_A, t0, t1
+# endif
+#endif
+	jr	$r_ra
+	 move	$r_ret, zero
+	END(sk_load_half)
+
+LEAF(sk_load_byte)
+	is_offset_negative(byte)
+FEXPORT(sk_load_byte_positive)
+	is_offset_in_header(1, byte)
+	/* Offset within header boundaries */
+	PTR_ADDU t1, $r_skb_data, offset
+	lbu	$r_A, 0(t1)
+	jr	$r_ra
+	 move	$r_ret, zero
+	END(sk_load_byte)
+
+/*
+ * call skb_copy_bits:
+ * (prototype in linux/skbuff.h)
+ *
+ * int skb_copy_bits(sk_buff *skb, int offset, void *to, int len)
+ *
+ * o32 mandates we leave 4 spaces for argument registers in case
+ * the callee needs to use them. Even though we don't care about
+ * the argument registers ourselves, we need to allocate that space
+ * to remain ABI compliant since the callee may want to use that space.
+ * We also allocate 2 more spaces for $r_ra and our return register (*to).
+ *
+ * n64 is a bit different. The *caller* will allocate the space to preserve
+ * the arguments. So in 64-bit kernels, we allocate the 4-arg space for no
+ * good reason but it does not matter that much really.
+ *
+ * (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;		\
+	sltu		$r_s0, offset, $r_s1;			\
+	beqz		$r_s0, fault;				\
+	/* Load 4th argument in DS */				\
+	 LONG_ADDIU	a3, zero, SIZE;				\
+	PTR_ADDIU	$r_sp, $r_sp, -(6 * SZREG);		\
+	PTR_LA		t0, skb_copy_bits;			\
+	PTR_S		$r_ra, (5 * SZREG)($r_sp);		\
+	/* Assign low slot to a2 */				\
+	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);		\
+	/*							\
+	 * skb_copy_bits returns 0 on success and -EFAULT	\
+	 * on error. Our data live in a2. Do not bother with	\
+	 * our data if an error has been returned.		\
+	 */							\
+	/* Restore our frame */					\
+	PTR_L		$r_ra, (5 * SZREG)($r_sp);		\
+	INT_L		$r_s0, (4 * SZREG)($r_sp);		\
+	bltz		v0, fault;				\
+	 PTR_ADDIU	$r_sp, $r_sp, 6 * SZREG;		\
+	move		$r_ret, zero;				\
+
+NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp)
+	bpf_slow_path_common(4)
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# if MIPS_ISA_REV >= 2
+	wsbh	t0, $r_s0
+	jr	$r_ra
+	 rotr	$r_A, t0, 16
+# else
+	sll	t0, $r_s0, 24
+	srl	t1, $r_s0, 24
+	srl	t2, $r_s0, 8
+	or	t0, t0, t1
+	andi	t2, t2, 0xff00
+	andi	t1, $r_s0, 0xff00
+	or	t0, t0, t2
+	sll	t1, t1, 8
+	jr	$r_ra
+	 or	$r_A, t0, t1
+# endif
+#else
+	jr	$r_ra
+	 move	$r_A, $r_s0
+#endif
+
+	END(bpf_slow_path_word)
+
+NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp)
+	bpf_slow_path_common(2)
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# if MIPS_ISA_REV >= 2
+	jr	$r_ra
+	 wsbh	$r_A, $r_s0
+# else
+	sll	t0, $r_s0, 8
+	andi	t1, $r_s0, 0xff00
+	andi	t0, t0, 0xff00
+	srl	t1, t1, 8
+	jr	$r_ra
+	 or	$r_A, t0, t1
+# endif
+#else
+	jr	$r_ra
+	 move	$r_A, $r_s0
+#endif
+
+	END(bpf_slow_path_half)
+
+NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp)
+	bpf_slow_path_common(1)
+	jr	$r_ra
+	 move	$r_A, $r_s0
+
+	END(bpf_slow_path_byte)
+
+/*
+ * Negative entry points
+ */
+	.macro bpf_is_end_of_data
+	li	t0, SKF_LL_OFF
+	/* Reading link layer data? */
+	slt	t1, offset, t0
+	bgtz	t1, fault
+	/* Be careful what follows in DS. */
+	.endm
+/*
+ * call skb_copy_bits:
+ * (prototype in linux/filter.h)
+ *
+ * void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb,
+ *                                            int k, unsigned int size)
+ *
+ * see above (bpf_slow_path_common) for ABI restrictions
+ */
+#define bpf_negative_common(SIZE)					\
+	PTR_ADDIU	$r_sp, $r_sp, -(6 * SZREG);			\
+	PTR_LA		t0, bpf_internal_load_pointer_neg_helper;	\
+	PTR_S		$r_ra, (5 * SZREG)($r_sp);			\
+	jalr		t0;						\
+	 li		a2, SIZE;					\
+	PTR_L		$r_ra, (5 * SZREG)($r_sp);			\
+	/* Check return pointer */					\
+	beqz		v0, fault;					\
+	 PTR_ADDIU	$r_sp, $r_sp, 6 * SZREG;			\
+	/* Preserve our pointer */					\
+	move		$r_s0, v0;					\
+	/* Set return value */						\
+	move		$r_ret, zero;					\
+
+bpf_slow_path_word_neg:
+	bpf_is_end_of_data
+NESTED(sk_load_word_negative, (6 * SZREG), $r_sp)
+	bpf_negative_common(4)
+	jr	$r_ra
+	 lw	$r_A, 0($r_s0)
+	END(sk_load_word_negative)
+
+bpf_slow_path_half_neg:
+	bpf_is_end_of_data
+NESTED(sk_load_half_negative, (6 * SZREG), $r_sp)
+	bpf_negative_common(2)
+	jr	$r_ra
+	 lhu	$r_A, 0($r_s0)
+	END(sk_load_half_negative)
+
+bpf_slow_path_byte_neg:
+	bpf_is_end_of_data
+NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp)
+	bpf_negative_common(1)
+	jr	$r_ra
+	 lbu	$r_A, 0($r_s0)
+	END(sk_load_byte_negative)
+
+fault:
+	jr	$r_ra
+	 addiu $r_ret, zero, 1
--- linux-ein-5.4.0.orig/arch/mips/net/ebpf_jit.c
+++ linux-ein-5.4.0/arch/mips/net/ebpf_jit.c
@@ -604,6 +604,7 @@
 static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx)
 {
 	int off, b_off;
+	int tcc_reg;
 
 	ctx->flags |= EBPF_SEEN_TC;
 	/*
@@ -616,14 +617,14 @@
 	b_off = b_imm(this_idx + 1, ctx);
 	emit_instr(ctx, bne, MIPS_R_AT, MIPS_R_ZERO, b_off);
 	/*
-	 * if (--TCC < 0)
+	 * if (TCC-- < 0)
 	 *     goto out;
 	 */
 	/* Delay slot */
-	emit_instr(ctx, daddiu, MIPS_R_T5,
-		   (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4, -1);
+	tcc_reg = (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4;
+	emit_instr(ctx, daddiu, MIPS_R_T5, tcc_reg, -1);
 	b_off = b_imm(this_idx + 1, ctx);
-	emit_instr(ctx, bltz, MIPS_R_T5, b_off);
+	emit_instr(ctx, bltz, tcc_reg, b_off);
 	/*
 	 * prog = array->ptrs[index];
 	 * if (prog == NULL)
@@ -1354,6 +1355,9 @@
 		}
 		break;
 
+	case BPF_ST | BPF_NOSPEC: /* speculation barrier */
+		break;
+
 	case BPF_ST | BPF_B | BPF_MEM:
 	case BPF_ST | BPF_H | BPF_MEM:
 	case BPF_ST | BPF_W | BPF_MEM:
@@ -1803,7 +1807,7 @@
 	unsigned int image_size;
 	u8 *image_ptr;
 
-	if (!prog->jit_requested || MIPS_ISA_REV < 2)
+	if (!prog->jit_requested)
 		return prog;
 
 	tmp = bpf_jit_blind_constants(prog);
--- linux-ein-5.4.0.orig/arch/mips/pci/pci-legacy.c
+++ linux-ein-5.4.0/arch/mips/pci/pci-legacy.c
@@ -166,8 +166,13 @@
 			res = hose->mem_resource;
 			break;
 		}
-		if (res != NULL)
-			of_pci_range_to_resource(&range, node, res);
+		if (res != NULL) {
+			res->name = node->full_name;
+			res->flags = range.flags;
+			res->start = range.cpu_addr;
+			res->end = range.cpu_addr + range.size - 1;
+			res->parent = res->child = res->sibling = NULL;
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/mips/pci/pci-mt7620.c
+++ linux-ein-5.4.0/arch/mips/pci/pci-mt7620.c
@@ -30,6 +30,7 @@
 #define RALINK_GPIOMODE			0x60
 
 #define PPLL_CFG1			0x9c
+#define PPLL_LD				BIT(23)
 
 #define PPLL_DRV			0xa0
 #define PDRV_SW_SET			BIT(31)
@@ -239,8 +240,8 @@
 	rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
 	mdelay(100);
 
-	if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
-		dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
+	if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
+		dev_err(&pdev->dev, "pcie PLL not locked, aborting init\n");
 		reset_control_assert(rstpcie0);
 		rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
 		return -1;
--- linux-ein-5.4.0.orig/arch/mips/pci/pci-rt2880.c
+++ linux-ein-5.4.0/arch/mips/pci/pci-rt2880.c
@@ -180,7 +180,6 @@
 
 int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
-	u16 cmd;
 	int irq = -1;
 
 	if (dev->bus->number != 0)
@@ -188,8 +187,6 @@
 
 	switch (PCI_SLOT(dev->devfn)) {
 	case 0x00:
-		rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000);
-		(void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0);
 		break;
 	case 0x11:
 		irq = RT288X_CPU_IRQ_PCI;
@@ -201,16 +198,6 @@
 		break;
 	}
 
-	pci_write_config_byte((struct pci_dev *) dev,
-		PCI_CACHE_LINE_SIZE, 0x14);
-	pci_write_config_byte((struct pci_dev *) dev, PCI_LATENCY_TIMER, 0xFF);
-	pci_read_config_word((struct pci_dev *) dev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK |
-		PCI_COMMAND_SERR | PCI_COMMAND_WAIT | PCI_COMMAND_PARITY;
-	pci_write_config_word((struct pci_dev *) dev, PCI_COMMAND, cmd);
-	pci_write_config_byte((struct pci_dev *) dev, PCI_INTERRUPT_LINE,
-			      dev->irq);
 	return irq;
 }
 
@@ -251,6 +238,30 @@
 
 int pcibios_plat_dev_init(struct pci_dev *dev)
 {
+	static bool slot0_init;
+
+	/*
+	 * Nobody seems to initialize slot 0, but this platform requires it, so
+	 * do it once when some other slot is being enabled. The PCI subsystem
+	 * should configure other slots properly, so no need to do anything
+	 * special for those.
+	 */
+	if (!slot0_init && dev->bus->number == 0) {
+		u16 cmd;
+		u32 bar0;
+
+		slot0_init = true;
+
+		pci_bus_write_config_dword(dev->bus, 0, PCI_BASE_ADDRESS_0,
+					   0x08000000);
+		pci_bus_read_config_dword(dev->bus, 0, PCI_BASE_ADDRESS_0,
+					  &bar0);
+
+		pci_bus_read_config_word(dev->bus, 0, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+		pci_bus_write_config_word(dev->bus, 0, PCI_COMMAND, cmd);
+	}
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/mips/pci/pci-xtalk-bridge.c
+++ linux-ein-5.4.0/arch/mips/pci/pci-xtalk-bridge.c
@@ -279,16 +279,15 @@
 	struct bridge_irq_chip_data *data = d->chip_data;
 	int bit = d->parent_data->hwirq;
 	int pin = d->hwirq;
-	nasid_t nasid;
 	int ret, cpu;
 
 	ret = irq_chip_set_affinity_parent(d, mask, force);
 	if (ret >= 0) {
 		cpu = cpumask_first_and(mask, cpu_online_mask);
-		nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+		data->nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
 		bridge_write(data->bc, b_int_addr[pin].addr,
 			     (((data->bc->intr_addr >> 30) & 0x30000) |
-			      bit | (nasid << 8)));
+			      bit | (data->nasid << 8)));
 		bridge_read(data->bc, b_wid_tflush);
 	}
 	return ret;
@@ -445,9 +444,10 @@
 		return -ENOMEM;
 	domain = irq_domain_create_hierarchy(parent, 0, 8, fn,
 					     &bridge_domain_ops, NULL);
-	irq_domain_free_fwnode(fn);
-	if (!domain)
+	if (!domain) {
+		irq_domain_free_fwnode(fn);
 		return -ENOMEM;
+	}
 
 	pci_set_flags(PCI_PROBE_ONLY);
 
@@ -539,6 +539,7 @@
 	pci_free_resource_list(&host->windows);
 err_remove_domain:
 	irq_domain_remove(domain);
+	irq_domain_free_fwnode(fn);
 	return err;
 }
 
@@ -546,8 +547,10 @@
 {
 	struct pci_bus *bus = platform_get_drvdata(pdev);
 	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+	struct fwnode_handle *fn = bc->domain->fwnode;
 
 	irq_domain_remove(bc->domain);
+	irq_domain_free_fwnode(fn);
 	pci_lock_rescan_remove();
 	pci_stop_root_bus(bus);
 	pci_remove_root_bus(bus);
--- linux-ein-5.4.0.orig/arch/mips/pic32/pic32mzda/early_console.c
+++ linux-ein-5.4.0/arch/mips/pic32/pic32mzda/early_console.c
@@ -27,7 +27,7 @@
 #define U_BRG(x)	(UART_BASE(x) + 0x40)
 
 static void __iomem *uart_base;
-static char console_port = -1;
+static int console_port = -1;
 
 static int __init configure_uart_pins(int port)
 {
@@ -47,7 +47,7 @@
 	return 0;
 }
 
-static void __init configure_uart(char port, int baud)
+static void __init configure_uart(int port, int baud)
 {
 	u32 pbclk;
 
@@ -60,7 +60,7 @@
 		     uart_base + PIC32_SET(U_STA(port)));
 }
 
-static void __init setup_early_console(char port, int baud)
+static void __init setup_early_console(int port, int baud)
 {
 	if (configure_uart_pins(port))
 		return;
@@ -130,16 +130,15 @@
 	return baud;
 }
 
-void __init fw_init_early_console(char port)
+void __init fw_init_early_console(void)
 {
 	char *arch_cmdline = pic32_getcmdline();
-	int baud = -1;
+	int baud, port;
 
 	uart_base = ioremap_nocache(PIC32_BASE_UART, 0xc00);
 
 	baud = get_baud_from_cmdline(arch_cmdline);
-	if (port == -1)
-		port = get_port_from_cmdline(arch_cmdline);
+	port = get_port_from_cmdline(arch_cmdline);
 
 	if (port == -1)
 		port = EARLY_CONSOLE_PORT;
--- linux-ein-5.4.0.orig/arch/mips/pic32/pic32mzda/init.c
+++ linux-ein-5.4.0/arch/mips/pic32/pic32mzda/init.c
@@ -28,7 +28,7 @@
 	if (fw_passed_dtb && !fw_arg2 && !fw_arg3)
 		return (ulong)fw_passed_dtb;
 
-	if (__dtb_start < __dtb_end)
+	if (&__dtb_start < &__dtb_end)
 		ftaddr = (ulong)__dtb_start;
 
 	return ftaddr;
@@ -60,7 +60,7 @@
 		strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
 
 #ifdef CONFIG_EARLY_PRINTK
-	fw_init_early_console(-1);
+	fw_init_early_console();
 #endif
 	pic32_config_init();
 }
--- linux-ein-5.4.0.orig/arch/mips/ralink/Kconfig
+++ linux-ein-5.4.0/arch/mips/ralink/Kconfig
@@ -51,6 +51,7 @@
 		select MIPS_GIC
 		select COMMON_CLK
 		select CLKSRC_MIPS_GIC
+		select HAVE_PCI if PCI_MT7621
 endchoice
 
 choice
--- linux-ein-5.4.0.orig/arch/mips/ralink/ill_acc.c
+++ linux-ein-5.4.0/arch/mips/ralink/ill_acc.c
@@ -61,6 +61,7 @@
 	pdev = of_find_device_by_node(np);
 	if (!pdev) {
 		pr_err("%pOFn: failed to lookup pdev\n", np);
+		of_node_put(np);
 		return -EINVAL;
 	}
 
--- linux-ein-5.4.0.orig/arch/mips/ralink/of.c
+++ linux-ein-5.4.0/arch/mips/ralink/of.c
@@ -8,6 +8,7 @@
 
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/sizes.h>
 #include <linux/of_fdt.h>
@@ -25,6 +26,7 @@
 
 __iomem void *rt_sysc_membase;
 __iomem void *rt_memc_membase;
+EXPORT_SYMBOL_GPL(rt_sysc_membase);
 
 __iomem void *plat_of_remap_node(const char *node)
 {
@@ -75,7 +77,7 @@
 	 */
 	if (fw_passed_dtb)
 		dtb = (void *)fw_passed_dtb;
-	else if (__dtb_start != __dtb_end)
+	else if (&__dtb_start != &__dtb_end)
 		dtb = (void *)__dtb_start;
 
 	__dt_setup_arch(dtb);
--- linux-ein-5.4.0.orig/arch/mips/rb532/devices.c
+++ linux-ein-5.4.0/arch/mips/rb532/devices.c
@@ -310,11 +310,9 @@
 static int __init setup_kmac(char *s)
 {
 	printk(KERN_INFO "korina mac = %s\n", s);
-	if (!mac_pton(s, korina_dev0_data.mac)) {
+	if (!mac_pton(s, korina_dev0_data.mac))
 		printk(KERN_ERR "Invalid mac\n");
-		return -EINVAL;
-	}
-	return 0;
+	return 1;
 }
 
 __setup("kmac=", setup_kmac);
--- linux-ein-5.4.0.orig/arch/mips/sgi-ip27/ip27-irq.c
+++ linux-ein-5.4.0/arch/mips/sgi-ip27/ip27-irq.c
@@ -73,6 +73,9 @@
 	int cpu;
 
 	cpu = cpumask_first_and(mask, cpu_online_mask);
+	if (cpu >= nr_cpu_ids)
+		cpu = cpumask_any(cpu_online_mask);
+
 	nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
 	hd->cpu = cpu;
 	if (!cputoslice(cpu)) {
@@ -139,6 +142,7 @@
 	/* use CPU connected to nearest hub */
 	hub = hub_data(NASID_TO_COMPACT_NODEID(info->nasid));
 	setup_hub_mask(hd, &hub->h_cpus);
+	info->nasid = cpu_to_node(hd->cpu);
 
 	/* Make sure it's not already pending when we connect it. */
 	REMOTE_HUB_CLR_INTR(info->nasid, swlevel);
--- linux-ein-5.4.0.orig/arch/mips/sni/a20r.c
+++ linux-ein-5.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-ein-5.4.0.orig/arch/mips/sni/time.c
+++ linux-ein-5.4.0/arch/mips/sni/time.c
@@ -18,14 +18,14 @@
 {
 	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34;
 	wmb();
-	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV;
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV & 0xff;
 	wmb();
 	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8;
 	wmb();
 
 	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4;
 	wmb();
-	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV;
+	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV & 0xff;
 	wmb();
 	*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8;
 	wmb();
--- linux-ein-5.4.0.orig/arch/mips/tools/elf-entry.c
+++ linux-ein-5.4.0/arch/mips/tools/elf-entry.c
@@ -51,11 +51,14 @@
 	nread = fread(&hdr, 1, sizeof(hdr), file);
 	if (nread != sizeof(hdr)) {
 		perror("Unable to read input file");
+		fclose(file);
 		return EXIT_FAILURE;
 	}
 
-	if (memcmp(hdr.ehdr32.e_ident, ELFMAG, SELFMAG))
+	if (memcmp(hdr.ehdr32.e_ident, ELFMAG, SELFMAG)) {
+		fclose(file);
 		die("Input is not an ELF\n");
+	}
 
 	switch (hdr.ehdr32.e_ident[EI_CLASS]) {
 	case ELFCLASS32:
@@ -67,6 +70,7 @@
 			entry = be32toh(hdr.ehdr32.e_entry);
 			break;
 		default:
+			fclose(file);
 			die("Invalid ELF encoding\n");
 		}
 
@@ -83,14 +87,17 @@
 			entry = be64toh(hdr.ehdr64.e_entry);
 			break;
 		default:
+			fclose(file);
 			die("Invalid ELF encoding\n");
 		}
 		break;
 
 	default:
+		fclose(file);
 		die("Invalid ELF class\n");
 	}
 
 	printf("0x%016" PRIx64 "\n", entry);
+	fclose(file);
 	return EXIT_SUCCESS;
 }
--- linux-ein-5.4.0.orig/arch/mips/vdso/Makefile
+++ linux-ein-5.4.0/arch/mips/vdso/Makefile
@@ -16,12 +16,9 @@
 	$(filter -march=%,$(KBUILD_CFLAGS)) \
 	$(filter -m%-float,$(KBUILD_CFLAGS)) \
 	$(filter -mno-loongson-%,$(KBUILD_CFLAGS)) \
+	$(CLANG_FLAGS) \
 	-D__VDSO__
 
-ifdef CONFIG_CC_IS_CLANG
-ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS))
-endif
-
 #
 # The -fno-jump-tables flag only prevents the compiler from generating
 # jump tables but does not prevent the compiler from emitting absolute
--- linux-ein-5.4.0.orig/arch/mips/vdso/genvdso.c
+++ linux-ein-5.4.0/arch/mips/vdso/genvdso.c
@@ -122,6 +122,7 @@
 	if (fstat(fd, &stat) != 0) {
 		fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
 			path, strerror(errno));
+		close(fd);
 		return NULL;
 	}
 
@@ -130,6 +131,7 @@
 	if (addr == MAP_FAILED) {
 		fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
 			path, strerror(errno));
+		close(fd);
 		return NULL;
 	}
 
@@ -139,6 +141,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;
 	}
 
@@ -150,6 +153,7 @@
 	default:
 		fprintf(stderr, "%s: '%s' has invalid ELF class\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	}
 
@@ -161,6 +165,7 @@
 	default:
 		fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
 			program_name, path);
+		close(fd);
 		return NULL;
 	}
 
@@ -168,15 +173,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;
 }
 
@@ -280,10 +288,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-ein-5.4.0.orig/arch/mips/vdso/vgettimeofday.c
+++ linux-ein-5.4.0/arch/mips/vdso/vgettimeofday.c
@@ -17,12 +17,22 @@
 	return __cvdso_clock_gettime32(clock, ts);
 }
 
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+/*
+ * This is behind the ifdef so that we don't provide the symbol when there's no
+ * possibility of there being a usable clocksource, because there's nothing we
+ * can do without it. When libc fails the symbol lookup it should fall back on
+ * the standard syscall path.
+ */
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
 			struct timezone *tz)
 {
 	return __cvdso_gettimeofday(tv, tz);
 }
 
+#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
+
 int __vdso_clock_getres(clockid_t clock_id,
 			struct old_timespec32 *res)
 {
@@ -43,12 +53,22 @@
 	return __cvdso_clock_gettime(clock, ts);
 }
 
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+/*
+ * This is behind the ifdef so that we don't provide the symbol when there's no
+ * possibility of there being a usable clocksource, because there's nothing we
+ * can do without it. When libc fails the symbol lookup it should fall back on
+ * the standard syscall path.
+ */
 int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
 			struct timezone *tz)
 {
 	return __cvdso_gettimeofday(tv, tz);
 }
 
+#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
+
 int __vdso_clock_getres(clockid_t clock_id,
 			struct __kernel_timespec *res)
 {
--- linux-ein-5.4.0.orig/arch/mips/vr41xx/common/icu.c
+++ linux-ein-5.4.0/arch/mips/vr41xx/common/icu.c
@@ -640,8 +640,6 @@
 
 	printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2);
 
-	atomic_inc(&irq_err_count);
-
 	return -1;
 }
 
--- linux-ein-5.4.0.orig/arch/nds32/include/asm/cacheflush.h
+++ linux-ein-5.4.0/arch/nds32/include/asm/cacheflush.h
@@ -9,7 +9,11 @@
 #define PG_dcache_dirty PG_arch_1
 
 void flush_icache_range(unsigned long start, unsigned long end);
+#define flush_icache_range flush_icache_range
+
 void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+#define flush_icache_page flush_icache_page
+
 #ifdef CONFIG_CPU_CACHE_ALIASING
 void flush_cache_mm(struct mm_struct *mm);
 void flush_cache_dup_mm(struct mm_struct *mm);
@@ -40,12 +44,11 @@
 #define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&(mapping)->i_pages)
 
 #else
-#include <asm-generic/cacheflush.h>
-#undef flush_icache_range
-#undef flush_icache_page
-#undef flush_icache_user_range
 void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
 	                     unsigned long addr, int len);
+#define flush_icache_user_range flush_icache_user_range
+
+#include <asm-generic/cacheflush.h>
 #endif
 
 #endif /* __NDS32_CACHEFLUSH_H__ */
--- linux-ein-5.4.0.orig/arch/nds32/include/asm/memory.h
+++ linux-ein-5.4.0/arch/nds32/include/asm/memory.h
@@ -76,18 +76,12 @@
  *  virt_to_page(k)	convert a _valid_ virtual address to struct page *
  *  virt_addr_valid(k)	indicates whether a virtual address is valid
  */
-#ifndef CONFIG_DISCONTIGMEM
-
 #define ARCH_PFN_OFFSET		PHYS_PFN_OFFSET
 #define pfn_valid(pfn)		((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
 
 #define virt_to_page(kaddr)	(pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
 #define virt_addr_valid(kaddr)	((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory)
 
-#else /* CONFIG_DISCONTIGMEM */
-#error CONFIG_DISCONTIGMEM is not supported yet.
-#endif /* !CONFIG_DISCONTIGMEM */
-
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 
 #endif
--- linux-ein-5.4.0.orig/arch/nds32/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/nds32/include/asm/uaccess.h
@@ -71,9 +71,7 @@
  * versions are void (ie, don't return a value as such).
  */
 
-#define get_user	__get_user					\
-
-#define __get_user(x, ptr)						\
+#define get_user(x, ptr)						\
 ({									\
 	long __gu_err = 0;						\
 	__get_user_check((x), (ptr), __gu_err);				\
@@ -86,6 +84,14 @@
 	(void)0;							\
 })
 
+#define __get_user(x, ptr)						\
+({									\
+	long __gu_err = 0;						\
+	const __typeof__(*(ptr)) __user *__p = (ptr);			\
+	__get_user_err((x), __p, (__gu_err));				\
+	__gu_err;							\
+})
+
 #define __get_user_check(x, ptr, err)					\
 ({									\
 	const __typeof__(*(ptr)) __user *__p = (ptr);			\
@@ -166,12 +172,18 @@
 		: "r"(addr), "i"(-EFAULT)				\
 		: "cc")
 
-#define put_user	__put_user					\
+#define put_user(x, ptr)						\
+({									\
+	long __pu_err = 0;						\
+	__put_user_check((x), (ptr), __pu_err);				\
+	__pu_err;							\
+})
 
 #define __put_user(x, ptr)						\
 ({									\
 	long __pu_err = 0;						\
-	__put_user_err((x), (ptr), __pu_err);				\
+	__typeof__(*(ptr)) __user *__p = (ptr);				\
+	__put_user_err((x), __p, __pu_err);				\
 	__pu_err;							\
 })
 
--- linux-ein-5.4.0.orig/arch/nds32/kernel/dma.c
+++ linux-ein-5.4.0/arch/nds32/kernel/dma.c
@@ -46,8 +46,8 @@
 	} while (left);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_FROM_DEVICE:
@@ -61,8 +61,8 @@
 	}
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_TO_DEVICE:
--- linux-ein-5.4.0.orig/arch/nds32/kernel/fpu.c
+++ linux-ein-5.4.0/arch/nds32/kernel/fpu.c
@@ -223,7 +223,7 @@
 		}
 	} else if (fpcsr & FPCSR_mskRIT) {
 		if (!user_mode(regs))
-			do_exit(SIGILL);
+			make_task_dead(SIGILL);
 		si_signo = SIGILL;
 	}
 
--- linux-ein-5.4.0.orig/arch/nds32/kernel/perf_event_cpu.c
+++ linux-ein-5.4.0/arch/nds32/kernel/perf_event_cpu.c
@@ -1363,6 +1363,7 @@
 perf_callchain_user(struct perf_callchain_entry_ctx *entry,
 		    struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	unsigned long fp = 0;
 	unsigned long gp = 0;
 	unsigned long lp = 0;
@@ -1371,7 +1372,7 @@
 
 	leaf_fp = 0;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -1479,9 +1480,10 @@
 perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 		      struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct stackframe fr;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* We don't support guest os callchain now */
 		return;
 	}
@@ -1493,20 +1495,23 @@
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
 	/* However, NDS32 does not support virtualization */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
-		return perf_guest_cbs->get_guest_ip();
+	if (guest_cbs && guest_cbs->is_in_guest())
+		return guest_cbs->get_guest_ip();
 
 	return instruction_pointer(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	int misc = 0;
 
 	/* However, NDS32 does not support virtualization */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-		if (perf_guest_cbs->is_user_mode())
+	if (guest_cbs && guest_cbs->is_in_guest()) {
+		if (guest_cbs->is_user_mode())
 			misc |= PERF_RECORD_MISC_GUEST_USER;
 		else
 			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
--- linux-ein-5.4.0.orig/arch/nds32/kernel/traps.c
+++ linux-ein-5.4.0/arch/nds32/kernel/traps.c
@@ -184,7 +184,7 @@
 
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 EXPORT_SYMBOL(die);
@@ -288,7 +288,7 @@
 	pr_emerg("unhandled_interruption\n");
 	show_regs(regs);
 	if (!user_mode(regs))
-		do_exit(SIGKILL);
+		make_task_dead(SIGKILL);
 	force_sig(SIGKILL);
 }
 
@@ -299,7 +299,7 @@
 		 addr, type);
 	show_regs(regs);
 	if (!user_mode(regs))
-		do_exit(SIGKILL);
+		make_task_dead(SIGKILL);
 	force_sig(SIGKILL);
 }
 
@@ -326,7 +326,7 @@
 	pr_emerg("Reserved Instruction\n");
 	show_regs(regs);
 	if (!user_mode(regs))
-		do_exit(SIGILL);
+		make_task_dead(SIGILL);
 	force_sig(SIGILL);
 }
 
--- linux-ein-5.4.0.orig/arch/nds32/mm/cacheflush.c
+++ linux-ein-5.4.0/arch/nds32/mm/cacheflush.c
@@ -239,7 +239,7 @@
 {
 	struct address_space *mapping;
 
-	mapping = page_mapping(page);
+	mapping = page_mapping_file(page);
 	if (mapping && !mapping_mapped(mapping))
 		set_bit(PG_dcache_dirty, &page->flags);
 	else {
--- linux-ein-5.4.0.orig/arch/nds32/mm/mmap.c
+++ linux-ein-5.4.0/arch/nds32/mm/mmap.c
@@ -59,7 +59,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-ein-5.4.0.orig/arch/nios2/boot/Makefile
+++ linux-ein-5.4.0/arch/nios2/boot/Makefile
@@ -20,7 +20,7 @@
 $(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,gzip)
 
-$(obj)/vmImage: $(obj)/vmlinux.gz
+$(obj)/vmImage: $(obj)/vmlinux.gz FORCE
 	$(call if_changed,uimage)
 	@$(kecho) 'Kernel: $@ is ready'
 
--- linux-ein-5.4.0.orig/arch/nios2/boot/dts/10m50_devboard.dts
+++ linux-ein-5.4.0/arch/nios2/boot/dts/10m50_devboard.dts
@@ -97,7 +97,7 @@
 			rx-fifo-depth = <8192>;
 			tx-fifo-depth = <8192>;
 			address-bits = <48>;
-			max-frame-size = <1518>;
+			max-frame-size = <1500>;
 			local-mac-address = [00 00 00 00 00 00];
 			altr,has-supplementary-unicast;
 			altr,enable-sup-addr = <1>;
--- linux-ein-5.4.0.orig/arch/nios2/boot/dts/3c120_devboard.dts
+++ linux-ein-5.4.0/arch/nios2/boot/dts/3c120_devboard.dts
@@ -106,7 +106,7 @@
 				interrupt-names = "rx_irq", "tx_irq";
 				rx-fifo-depth = <8192>;
 				tx-fifo-depth = <8192>;
-				max-frame-size = <1518>;
+				max-frame-size = <1500>;
 				local-mac-address = [ 00 00 00 00 00 00 ];
 				phy-mode = "rgmii-id";
 				phy-handle = <&phy0>;
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/entry.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/entry.h
@@ -50,7 +50,8 @@
 	stw	r13, PT_R13(sp)
 	stw	r14, PT_R14(sp)
 	stw	r15, PT_R15(sp)
-	stw	r2, PT_ORIG_R2(sp)
+	movi	r24, -1
+	stw	r24, PT_ORIG_R2(sp)
 	stw	r7, PT_ORIG_R7(sp)
 
 	stw	ra, PT_RA(sp)
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/irqflags.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/irqflags.h
@@ -9,7 +9,7 @@
 
 static inline unsigned long arch_local_save_flags(void)
 {
-	return RDCTL(CTL_STATUS);
+	return RDCTL(CTL_FSTATUS);
 }
 
 /*
@@ -18,7 +18,7 @@
  */
 static inline void arch_local_irq_restore(unsigned long flags)
 {
-	WRCTL(CTL_STATUS, flags);
+	WRCTL(CTL_FSTATUS, flags);
 }
 
 static inline void arch_local_irq_disable(void)
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/ptrace.h
@@ -74,6 +74,8 @@
 	((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\
 		- 1)
 
+#define force_successful_syscall_return() (current_pt_regs()->orig_r2 = -1)
+
 int do_syscall_trace_enter(void);
 void do_syscall_trace_exit(void);
 #endif /* __ASSEMBLY__ */
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/registers.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/registers.h
@@ -11,7 +11,7 @@
 #endif
 
 /* control register numbers */
-#define CTL_STATUS	0
+#define CTL_FSTATUS	0
 #define CTL_ESTATUS	1
 #define CTL_BSTATUS	2
 #define CTL_IENABLE	3
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/timex.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/timex.h
@@ -8,5 +8,8 @@
 typedef unsigned long cycles_t;
 
 extern cycles_t get_cycles(void);
+#define get_cycles get_cycles
+
+#define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
 
 #endif
--- linux-ein-5.4.0.orig/arch/nios2/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/nios2/include/asm/uaccess.h
@@ -89,6 +89,7 @@
 /* Optimized macros */
 #define __get_user_asm(val, insn, addr, err)				\
 {									\
+	unsigned long __gu_val;						\
 	__asm__ __volatile__(						\
 	"       movi    %0, %3\n"					\
 	"1:   " insn " %1, 0(%2)\n"					\
@@ -97,14 +98,20 @@
 	"       .section __ex_table,\"a\"\n"				\
 	"       .word 1b, 2b\n"						\
 	"       .previous"						\
-	: "=&r" (err), "=r" (val)					\
+	: "=&r" (err), "=r" (__gu_val)					\
 	: "r" (addr), "i" (-EFAULT));					\
+	val = (__force __typeof__(*(addr)))__gu_val;			\
 }
 
-#define __get_user_unknown(val, size, ptr, err) do {			\
+extern void __get_user_unknown(void);
+
+#define __get_user_8(val, ptr, err) do {				\
+	u64 __val = 0;							\
 	err = 0;							\
-	if (__copy_from_user(&(val), ptr, size)) {			\
+	if (raw_copy_from_user(&(__val), ptr, sizeof(val))) {		\
 		err = -EFAULT;						\
+	} else {							\
+		val = (typeof(val))(typeof((val) - (val)))__val;	\
 	}								\
 	} while (0)
 
@@ -120,8 +127,11 @@
 	case 4:								\
 		__get_user_asm(val, "ldw", ptr, err);			\
 		break;							\
+	case 8:								\
+		__get_user_8(val, ptr, err);				\
+		break;							\
 	default:							\
-		__get_user_unknown(val, size, ptr, err);		\
+		__get_user_unknown();					\
 		break;							\
 	}								\
 } while (0)
@@ -130,9 +140,7 @@
 	({								\
 	long __gu_err = -EFAULT;					\
 	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);		\
-	unsigned long __gu_val = 0;					\
-	__get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
-	(x) = (__force __typeof__(x))__gu_val;				\
+	__get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err);	\
 	__gu_err;							\
 	})
 
@@ -140,11 +148,9 @@
 ({									\
 	long __gu_err = -EFAULT;					\
 	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);		\
-	unsigned long __gu_val = 0;					\
 	if (access_ok( __gu_ptr, sizeof(*__gu_ptr)))	\
-		__get_user_common(__gu_val, sizeof(*__gu_ptr),		\
+		__get_user_common(x, sizeof(*__gu_ptr),			\
 			__gu_ptr, __gu_err);				\
-	(x) = (__force __typeof__(x))__gu_val;				\
 	__gu_err;							\
 })
 
--- linux-ein-5.4.0.orig/arch/nios2/kernel/entry.S
+++ linux-ein-5.4.0/arch/nios2/kernel/entry.S
@@ -185,6 +185,7 @@
 	ldw	r5, PT_R5(sp)
 
 local_restart:
+	stw	r2, PT_ORIG_R2(sp)
 	/* Check that the requested system call is within limits */
 	movui	r1, __NR_syscalls
 	bgeu	r2, r1, ret_invsyscall
@@ -192,7 +193,6 @@
 	movhi	r11, %hiadj(sys_call_table)
 	add	r1, r1, r11
 	ldw	r1, %lo(sys_call_table)(r1)
-	beq	r1, r0, ret_invsyscall
 
 	/* Check if we are being traced */
 	GET_THREAD_INFO r11
@@ -213,6 +213,9 @@
 translate_rc_and_ret:
 	movi	r1, 0
 	bge	r2, zero, 3f
+	ldw	r1, PT_ORIG_R2(sp)
+	addi	r1, r1, 1
+	beq	r1, zero, 3f
 	sub	r2, zero, r2
 	movi	r1, 1
 3:
@@ -255,9 +258,9 @@
 	ldw	r6, PT_R6(sp)
 	ldw	r7, PT_R7(sp)
 
-	/* Fetch the syscall function, we don't need to check the boundaries
-	 * since this is already done.
-	 */
+	/* Fetch the syscall function. */
+	movui	r1, __NR_syscalls
+	bgeu	r2, r1, traced_invsyscall
 	slli	r1, r2, 2
 	movhi	r11,%hiadj(sys_call_table)
 	add	r1, r1, r11
@@ -276,6 +279,9 @@
 translate_rc_and_ret2:
 	movi	r1, 0
 	bge	r2, zero, 4f
+	ldw	r1, PT_ORIG_R2(sp)
+	addi	r1, r1, 1
+	beq	r1, zero, 4f
 	sub	r2, zero, r2
 	movi	r1, 1
 4:
@@ -287,6 +293,11 @@
 	RESTORE_SWITCH_STACK
 	br	ret_from_exception
 
+	/* If the syscall number was invalid return ENOSYS */
+traced_invsyscall:
+	movi	r2, -ENOSYS
+	br	translate_rc_and_ret2
+
 Luser_return:
 	GET_THREAD_INFO	r11			/* get thread_info pointer */
 	ldw	r10, TI_FLAGS(r11)		/* get thread_info->flags */
@@ -336,9 +347,6 @@
 	/* skip if no interrupt is pending */
 	beq	r12, r0, ret_from_interrupt
 
-	movi	r24, -1
-	stw	r24, PT_ORIG_R2(sp)
-
 	/*
 	 * Process an external hardware interrupt.
 	 */
--- linux-ein-5.4.0.orig/arch/nios2/kernel/signal.c
+++ linux-ein-5.4.0/arch/nios2/kernel/signal.c
@@ -240,7 +240,7 @@
 	/*
 	 * If we were from a system call, check for system call restarting...
 	 */
-	if (regs->orig_r2 >= 0) {
+	if (regs->orig_r2 >= 0 && regs->r1) {
 		continue_addr = regs->ea;
 		restart_addr = continue_addr - 4;
 		retval = regs->r2;
@@ -261,6 +261,7 @@
 			regs->ea = restart_addr;
 			break;
 		}
+		regs->orig_r2 = -1;
 	}
 
 	if (get_signal(&ksig)) {
--- linux-ein-5.4.0.orig/arch/nios2/kernel/syscall_table.c
+++ linux-ein-5.4.0/arch/nios2/kernel/syscall_table.c
@@ -13,5 +13,6 @@
 #define __SYSCALL(nr, call) [nr] = (call),
 
 void *sys_call_table[__NR_syscalls] = {
+	[0 ... __NR_syscalls-1] = sys_ni_syscall,
 #include <asm/unistd.h>
 };
--- linux-ein-5.4.0.orig/arch/nios2/kernel/traps.c
+++ linux-ein-5.4.0/arch/nios2/kernel/traps.c
@@ -37,10 +37,10 @@
 	show_regs(regs);
 	spin_unlock_irq(&die_lock);
 	/*
-	 * do_exit() should take care of panic'ing from an interrupt
+	 * make_task_dead() should take care of panic'ing from an interrupt
 	 * context so we don't handle it here
 	 */
-	do_exit(err);
+	make_task_dead(err);
 }
 
 void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr)
--- linux-ein-5.4.0.orig/arch/nios2/mm/dma-mapping.c
+++ linux-ein-5.4.0/arch/nios2/mm/dma-mapping.c
@@ -18,8 +18,8 @@
 #include <linux/cache.h>
 #include <asm/cacheflush.h>
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	void *vaddr = phys_to_virt(paddr);
 
@@ -42,8 +42,8 @@
 	}
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	void *vaddr = phys_to_virt(paddr);
 
--- linux-ein-5.4.0.orig/arch/nios2/platform/Kconfig.platform
+++ linux-ein-5.4.0/arch/nios2/platform/Kconfig.platform
@@ -37,6 +37,7 @@
 
 config NIOS2_DTB_SOURCE_BOOL
 	bool "Compile and link device tree into kernel image"
+	depends on !COMPILE_TEST
 	help
 	  This allows you to specify a dts (device tree source) file
 	  which will be compiled and linked into the kernel image.
--- linux-ein-5.4.0.orig/arch/openrisc/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/openrisc/include/asm/barrier.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+#define mb() asm volatile ("l.msync" ::: "memory")
+
+#include <asm-generic/barrier.h>
+
+#endif /* __ASM_BARRIER_H */
--- linux-ein-5.4.0.orig/arch/openrisc/include/asm/timex.h
+++ linux-ein-5.4.0/arch/openrisc/include/asm/timex.h
@@ -23,6 +23,7 @@
 {
 	return mfspr(SPR_TTCR);
 }
+#define get_cycles get_cycles
 
 /* This isn't really used any more */
 #define CLOCK_TICK_RATE 1000
--- linux-ein-5.4.0.orig/arch/openrisc/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/openrisc/include/asm/uaccess.h
@@ -164,19 +164,19 @@
 
 #define __get_user_nocheck(x, ptr, size)			\
 ({								\
-	long __gu_err, __gu_val;				\
-	__get_user_size(__gu_val, (ptr), (size), __gu_err);	\
-	(x) = (__force __typeof__(*(ptr)))__gu_val;		\
+	long __gu_err;						\
+	__get_user_size((x), (ptr), (size), __gu_err);		\
 	__gu_err;						\
 })
 
 #define __get_user_check(x, ptr, size)					\
 ({									\
-	long __gu_err = -EFAULT, __gu_val = 0;				\
-	const __typeof__(*(ptr)) * __gu_addr = (ptr);			\
-	if (access_ok(__gu_addr, size))			\
-		__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
-	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
+	long __gu_err = -EFAULT;					\
+	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
+	if (access_ok(__gu_addr, size))					\
+		__get_user_size((x), __gu_addr, (size), __gu_err);	\
+	else								\
+		(x) = (__typeof__(*(ptr))) 0;				\
 	__gu_err;							\
 })
 
@@ -190,11 +190,13 @@
 	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); break;			\
-	default: (x) = __get_user_bad();				\
+	default: (x) = (__typeof__(*(ptr)))__get_user_bad();		\
 	}								\
 } while (0)
 
 #define __get_user_asm(x, addr, err, op)		\
+{							\
+	unsigned long __gu_tmp;				\
 	__asm__ __volatile__(				\
 		"1:	"op" %1,0(%2)\n"		\
 		"2:\n"					\
@@ -208,10 +210,14 @@
 		"	.align 2\n"			\
 		"	.long 1b,3b\n"			\
 		".previous"				\
-		: "=r"(err), "=r"(x)			\
-		: "r"(addr), "i"(-EFAULT), "0"(err))
+		: "=r"(err), "=r"(__gu_tmp)		\
+		: "r"(addr), "i"(-EFAULT), "0"(err));	\
+	(x) = (__typeof__(*(addr)))__gu_tmp;		\
+}
 
 #define __get_user_asm2(x, addr, err)			\
+{							\
+	unsigned long long __gu_tmp;			\
 	__asm__ __volatile__(				\
 		"1:	l.lwz %1,0(%2)\n"		\
 		"2:	l.lwz %H1,4(%2)\n"		\
@@ -228,8 +234,11 @@
 		"	.long 1b,4b\n"			\
 		"	.long 2b,4b\n"			\
 		".previous"				\
-		: "=r"(err), "=&r"(x)			\
-		: "r"(addr), "i"(-EFAULT), "0"(err))
+		: "=r"(err), "=&r"(__gu_tmp)		\
+		: "r"(addr), "i"(-EFAULT), "0"(err));	\
+	(x) = (__typeof__(*(addr)))(			\
+		(__typeof__((x)-(x)))__gu_tmp);		\
+}
 
 /* more complex routines */
 
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/dma.c
+++ linux-ein-5.4.0/arch/openrisc/kernel/dma.c
@@ -125,7 +125,7 @@
 	free_pages_exact(vaddr, size);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t addr, size_t size,
+void arch_sync_dma_for_device(phys_addr_t addr, size_t size,
 		enum dma_data_direction dir)
 {
 	unsigned long cl;
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/entry.S
+++ linux-ein-5.4.0/arch/openrisc/kernel/entry.S
@@ -173,7 +173,6 @@
 	l.sw    PT_GPR28(r1),r28					;\
 	l.sw    PT_GPR29(r1),r29					;\
 	/* r30 already save */					;\
-/*        l.sw    PT_GPR30(r1),r30*/					;\
 	l.sw    PT_GPR31(r1),r31					;\
 	TRACE_IRQS_OFF_ENTRY						;\
 	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
@@ -211,9 +210,8 @@
 	l.sw    PT_GPR27(r1),r27					;\
 	l.sw    PT_GPR28(r1),r28					;\
 	l.sw    PT_GPR29(r1),r29					;\
-	/* r31 already saved */					;\
-	l.sw    PT_GPR30(r1),r30					;\
-/*        l.sw    PT_GPR31(r1),r31	*/				;\
+	/* r30 already saved */						;\
+	l.sw    PT_GPR31(r1),r31					;\
 	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
 	l.addi	r30,r0,-1					;\
 	l.sw	PT_ORIG_GPR11(r1),r30				;\
@@ -547,6 +545,7 @@
 	l.bnf	1f			// ext irq enabled, all ok.
 	l.nop
 
+#ifdef CONFIG_PRINTK
 	l.addi  r1,r1,-0x8
 	l.movhi r3,hi(42f)
 	l.ori	r3,r3,lo(42f)
@@ -560,6 +559,7 @@
 		.string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r"
 		.align 4
 	.previous
+#endif
 
 	l.ori	r4,r4,SPR_SR_IEE	// fix the bug
 //	l.sw	PT_SR(r1),r4
@@ -1166,13 +1166,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.jal	_sys_rt_sigreturn
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/head.S
+++ linux-ein-5.4.0/arch/openrisc/kernel/head.S
@@ -521,6 +521,15 @@
 	l.ori	r3,r0,0x1
 	l.mtspr	r0,r3,SPR_SR
 
+	/*
+	 * Start the TTCR as early as possible, so that the RNG can make use of
+	 * measurements of boot time from the earliest opportunity. Especially
+	 * important is that the TTCR does not return zero by the time we reach
+	 * rand_initialize().
+	 */
+	l.movhi r3,hi(SPR_TTMR_CR)
+	l.mtspr r0,r3,SPR_TTMR
+
 	CLEAR_GPR(r1)
 	CLEAR_GPR(r2)
 	CLEAR_GPR(r3)
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/setup.c
+++ linux-ein-5.4.0/arch/openrisc/kernel/setup.c
@@ -274,6 +274,8 @@
 	pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
 		loops_per_jiffy / (500000 / HZ),
 		(loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
+
+	of_node_put(cpu);
 }
 
 void __init setup_arch(char **cmdline_p)
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/openrisc/kernel/stacktrace.c
@@ -13,6 +13,7 @@
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/task_stack.h>
 #include <linux/stacktrace.h>
 
 #include <asm/processor.h>
@@ -68,12 +69,25 @@
 {
 	unsigned long *sp = NULL;
 
+	if (!try_get_task_stack(tsk))
+		return;
+
 	if (tsk == current)
 		sp = (unsigned long *) &sp;
-	else
-		sp = (unsigned long *) KSTK_ESP(tsk);
+	else {
+		unsigned long ksp;
+
+		/* Locate stack from kernel context */
+		ksp = task_thread_info(tsk)->ksp;
+		ksp += STACK_FRAME_OVERHEAD;	/* redzone */
+		ksp += sizeof(struct pt_regs);
+
+		sp = (unsigned long *) ksp;
+	}
 
 	unwind_stack(trace, sp, save_stack_address_nosched);
+
+	put_task_stack(tsk);
 }
 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
 
--- linux-ein-5.4.0.orig/arch/openrisc/kernel/traps.c
+++ linux-ein-5.4.0/arch/openrisc/kernel/traps.c
@@ -218,7 +218,7 @@
 	__asm__ __volatile__("l.nop   1");
 	do {} while (1);
 #endif
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 /* This is normally the 'Oops' routine */
--- linux-ein-5.4.0.orig/arch/openrisc/mm/cache.c
+++ linux-ein-5.4.0/arch/openrisc/mm/cache.c
@@ -16,7 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static void cache_loop(struct page *page, const unsigned int reg)
+static __always_inline void cache_loop(struct page *page, const unsigned int reg)
 {
 	unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT;
 	unsigned long line = paddr & ~(L1_CACHE_BYTES - 1);
--- linux-ein-5.4.0.orig/arch/parisc/Kconfig
+++ linux-ein-5.4.0/arch/parisc/Kconfig
@@ -11,6 +11,7 @@
 	select ARCH_WANT_FRAME_POINTERS
 	select ARCH_HAS_ELF_RANDOMIZE
 	select ARCH_HAS_STRICT_KERNEL_RWX
+	select ARCH_HAS_STRICT_MODULE_RWX
 	select ARCH_HAS_UBSAN_SANITIZE_ALL
 	select ARCH_NO_SG_CHAIN
 	select ARCH_SUPPORTS_MEMORY_FAILURE
@@ -62,6 +63,7 @@
 	select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
 	select HAVE_KPROBES_ON_FTRACE
 	select HAVE_DYNAMIC_FTRACE_WITH_REGS
+	select HAVE_COPY_THREAD_TLS
 
 	help
 	  The PA-RISC microprocessor is designed by Hewlett-Packard and used
--- linux-ein-5.4.0.orig/arch/parisc/Makefile
+++ linux-ein-5.4.0/arch/parisc/Makefile
@@ -17,7 +17,12 @@
 # Mike Shaver, Helge Deller and Martin K. Petersen
 #
 
+ifdef CONFIG_PARISC_SELF_EXTRACT
+boot := arch/parisc/boot
+KBUILD_IMAGE := $(boot)/bzImage
+else
 KBUILD_IMAGE := vmlinuz
+endif
 
 NM		= sh $(srctree)/arch/parisc/nm
 CHECKFLAGS	+= -D__hppa__=1
@@ -60,7 +65,6 @@
 		 -DFTRACE_PATCHABLE_FUNCTION_SIZE=$(NOP_COUNT)
 
 CC_FLAGS_FTRACE := -fpatchable-function-entry=$(NOP_COUNT),$(shell echo $$(($(NOP_COUNT)-1)))
-KBUILD_LDS_MODULE += $(srctree)/arch/parisc/kernel/module.lds
 endif
 
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
@@ -156,7 +160,7 @@
 	$(OBJCOPY) $(boot)/bzImage $@
 else
 vmlinuz: vmlinux
-	@gzip -cf -9 $< > $@
+	@$(KGZIP) -cf -9 $< > $@
 endif
 
 install:
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/atomic.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/atomic.h
@@ -212,6 +212,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-ein-5.4.0.orig/arch/parisc/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/barrier.h
@@ -26,6 +26,67 @@
 #define __smp_rmb()	mb()
 #define __smp_wmb()	mb()
 
+#define __smp_store_release(p, v)					\
+do {									\
+	typeof(p) __p = (p);						\
+        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("stb,ma %0,0(%1)"				\
+				: : "r"(*(__u8 *)__u.__c), "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 2:								\
+		asm volatile("sth,ma %0,0(%1)"				\
+				: : "r"(*(__u16 *)__u.__c), "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 4:								\
+		asm volatile("stw,ma %0,0(%1)"				\
+				: : "r"(*(__u32 *)__u.__c), "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 8:								\
+		if (IS_ENABLED(CONFIG_64BIT))				\
+			asm volatile("std,ma %0,0(%1)"			\
+				: : "r"(*(__u64 *)__u.__c), "r"(__p)	\
+				: "memory");				\
+		break;							\
+	}								\
+} while (0)
+
+#define __smp_load_acquire(p)						\
+({									\
+	union { typeof(*p) __val; char __c[1]; } __u;			\
+	typeof(p) __p = (p);						\
+	compiletime_assert_atomic_type(*p);				\
+	switch (sizeof(*p)) {						\
+	case 1:								\
+		asm volatile("ldb,ma 0(%1),%0"				\
+				: "=r"(*(__u8 *)__u.__c) : "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 2:								\
+		asm volatile("ldh,ma 0(%1),%0"				\
+				: "=r"(*(__u16 *)__u.__c) : "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 4:								\
+		asm volatile("ldw,ma 0(%1),%0"				\
+				: "=r"(*(__u32 *)__u.__c) : "r"(__p)	\
+				: "memory");				\
+		break;							\
+	case 8:								\
+		if (IS_ENABLED(CONFIG_64BIT))				\
+			asm volatile("ldd,ma 0(%1),%0"			\
+				: "=r"(*(__u64 *)__u.__c) : "r"(__p)	\
+				: "memory");				\
+		break;							\
+	}								\
+	__u.__val;							\
+})
 #include <asm-generic/barrier.h>
 
 #endif /* !__ASSEMBLY__ */
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/cacheflush.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/cacheflush.h
@@ -57,6 +57,11 @@
 
 #define flush_dcache_mmap_lock(mapping)		xa_lock_irq(&mapping->i_pages)
 #define flush_dcache_mmap_unlock(mapping)	xa_unlock_irq(&mapping->i_pages)
+#define flush_dcache_mmap_lock_irqsave(mapping, flags)		\
+		xa_lock_irqsave(&mapping->i_pages, flags)
+#define flush_dcache_mmap_unlock_irqrestore(mapping, flags)	\
+		xa_unlock_irqrestore(&mapping->i_pages, flags)
+
 
 #define flush_icache_page(vma,page)	do { 		\
 	flush_kernel_dcache_page(page);			\
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/cmpxchg.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/cmpxchg.h
@@ -44,8 +44,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);
@@ -54,6 +60,7 @@
 extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old,
 				   unsigned int new_);
 extern u64 __cmpxchg_u64(volatile u64 *ptr, u64 old, u64 new_);
+extern u8 __cmpxchg_u8(volatile u8 *ptr, u8 old, u8 new_);
 
 /* don't worry...optimizer will get rid of most of this */
 static inline unsigned long
@@ -65,6 +72,7 @@
 #endif
 	case 4: return __cmpxchg_u32((unsigned int *)ptr,
 				     (unsigned int)old, (unsigned int)new_);
+	case 1: return __cmpxchg_u8((u8 *)ptr, old & 0xff, new_ & 0xff);
 	}
 	__cmpxchg_called_with_bad_pointer();
 	return old;
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/hardware.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/hardware.h
@@ -10,12 +10,12 @@
 #define SVERSION_ANY_ID		PA_SVERSION_ANY_ID
 
 struct hp_hardware {
-	unsigned short	hw_type:5;	/* HPHW_xxx */
-	unsigned short	hversion;
-	unsigned long	sversion:28;
-	unsigned short	opt;
-	const char	name[80];	/* The hardware description */
-};
+	unsigned int	hw_type:8;	/* HPHW_xxx */
+	unsigned int	hversion:12;
+	unsigned int	sversion:12;
+	unsigned char	opt;
+	unsigned char	name[59];	/* The hardware description */
+} __packed;
 
 struct parisc_device;
 
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/kexec.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/kexec.h
@@ -2,8 +2,6 @@
 #ifndef _ASM_PARISC_KEXEC_H
 #define _ASM_PARISC_KEXEC_H
 
-#ifdef CONFIG_KEXEC
-
 /* Maximum physical address we can use pages from */
 #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
 /* Maximum address we can reach in physical address mode */
@@ -32,6 +30,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#endif /* CONFIG_KEXEC */
-
 #endif /* _ASM_PARISC_KEXEC_H */
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/ldcw.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/ldcw.h
@@ -2,14 +2,28 @@
 #ifndef __PARISC_LDCW_H
 #define __PARISC_LDCW_H
 
-#ifndef CONFIG_PA20
 /* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
    and GCC only guarantees 8-byte alignment for stack locals, we can't
    be assured of 16-byte alignment for atomic lock data even if we
    specify "__attribute ((aligned(16)))" in the type declaration.  So,
    we use a struct containing an array of four ints for the atomic lock
    type and dynamically select the 16-byte aligned int from the array
-   for the semaphore.  */
+   for the semaphore. */
+
+/* From: "Jim Hull" <jim.hull of hp.com>
+   I've attached a summary of the change, but basically, for PA 2.0, as
+   long as the ",CO" (coherent operation) completer is implemented, then the
+   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
+   they only require "natural" alignment (4-byte for ldcw, 8-byte for
+   ldcd).
+
+   Although the cache control hint is accepted by all PA 2.0 processors,
+   it is only implemented on PA8800/PA8900 CPUs. Prior PA8X00 CPUs still
+   require 16-byte alignment. If the address is unaligned, the operation
+   of the instruction is undefined. The ldcw instruction does not generate
+   unaligned data reference traps so misaligned accesses are not detected.
+   This hid the problem for years. So, restore the 16-byte alignment dropped
+   by Kyle McMartin in "Remove __ldcw_align for PA-RISC 2.0 processors". */
 
 #define __PA_LDCW_ALIGNMENT	16
 #define __PA_LDCW_ALIGN_ORDER	4
@@ -19,22 +33,12 @@
 		& ~(__PA_LDCW_ALIGNMENT - 1);			\
 	(volatile unsigned int *) __ret;			\
 })
-#define __LDCW	"ldcw"
 
-#else /*CONFIG_PA20*/
-/* From: "Jim Hull" <jim.hull of hp.com>
-   I've attached a summary of the change, but basically, for PA 2.0, as
-   long as the ",CO" (coherent operation) completer is specified, then the
-   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
-   they only require "natural" alignment (4-byte for ldcw, 8-byte for
-   ldcd). */
-
-#define __PA_LDCW_ALIGNMENT	4
-#define __PA_LDCW_ALIGN_ORDER	2
-#define __ldcw_align(a) (&(a)->slock)
+#ifdef CONFIG_PA20
 #define __LDCW	"ldcw,co"
-
-#endif /*!CONFIG_PA20*/
+#else
+#define __LDCW	"ldcw"
+#endif
 
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
    We don't explicitly expose that "*a" may be written as reload
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/led.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/led.h
@@ -11,8 +11,8 @@
 #define	LED1		0x02
 #define	LED0		0x01		/* bottom (or furthest left) LED */
 
-#define	LED_LAN_TX	LED0		/* for LAN transmit activity */
-#define	LED_LAN_RCV	LED1		/* for LAN receive activity */
+#define	LED_LAN_RCV	LED0		/* for LAN receive activity */
+#define	LED_LAN_TX	LED1		/* for LAN transmit activity */
 #define	LED_DISK_IO	LED2		/* for disk activity */
 #define	LED_HEARTBEAT	LED3		/* heartbeat */
 
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/page.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/page.h
@@ -181,7 +181,7 @@
 #include <asm-generic/getorder.h>
 #include <asm/pdc.h>
 
-#define PAGE0   ((struct zeropage *)__PAGE_OFFSET)
+#define PAGE0   ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
 
 /* DEFINITION OF THE ZERO-PAGE (PAG0) */
 /* based on work by Jason Eckhardt (jason@equator.com) */
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/processor.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/processor.h
@@ -97,7 +97,6 @@
 	unsigned long cpu_loc;      /* CPU location from PAT firmware */
 	unsigned int state;
 	struct parisc_device *dev;
-	unsigned long loops_per_jiffy;
 };
 
 extern struct system_cpuinfo_parisc boot_cpu_data;
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/ropes.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/ropes.h
@@ -86,6 +86,9 @@
 	struct ioc		ioc[MAX_IOC];
 };
 
+/* list of SBA's in system, see drivers/parisc/sba_iommu.c */
+extern struct sba_device *sba_list;
+
 #define ASTRO_RUNWAY_PORT	0x582
 #define IKE_MERCED_PORT		0x803
 #define REO_MERCED_PORT		0x804
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/spinlock.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/spinlock.h
@@ -37,12 +37,8 @@
 	volatile unsigned int *a;
 
 	a = __ldcw_align(x);
-#ifdef CONFIG_SMP
-	(void) __ldcw(a);
-#else
-	mb();
-#endif
-	*a = 1;
+	/* Release with ordered store. */
+	__asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory");
 }
 
 static inline int arch_spin_trylock(arch_spinlock_t *x)
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/spinlock_types.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/spinlock_types.h
@@ -3,13 +3,8 @@
 #define __ASM_SPINLOCK_TYPES_H
 
 typedef struct {
-#ifdef CONFIG_PA20
-	volatile unsigned int slock;
-# define __ARCH_SPIN_LOCK_UNLOCKED { 1 }
-#else
 	volatile unsigned int lock[4];
 # define __ARCH_SPIN_LOCK_UNLOCKED	{ { 1, 1, 1, 1 } }
-#endif
 } arch_spinlock_t;
 
 typedef struct {
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/string.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/string.h
@@ -8,19 +8,4 @@
 #define __HAVE_ARCH_MEMCPY
 void * memcpy(void * dest,const void *src,size_t count);
 
-#define __HAVE_ARCH_STRLEN
-extern size_t strlen(const char *s);
-
-#define __HAVE_ARCH_STRCPY
-extern char *strcpy(char *dest, const char *src);
-
-#define __HAVE_ARCH_STRNCPY
-extern char *strncpy(char *dest, const char *src, size_t count);
-
-#define __HAVE_ARCH_STRCAT
-extern char *strcat(char *dest, const char *src);
-
-#define __HAVE_ARCH_MEMSET
-extern void *memset(void *, int, size_t);
-
 #endif
--- linux-ein-5.4.0.orig/arch/parisc/include/asm/timex.h
+++ linux-ein-5.4.0/arch/parisc/include/asm/timex.h
@@ -12,9 +12,10 @@
 
 typedef unsigned long cycles_t;
 
-static inline cycles_t get_cycles (void)
+static inline cycles_t get_cycles(void)
 {
 	return mfctl(16);
 }
+#define get_cycles get_cycles
 
 #endif
--- linux-ein-5.4.0.orig/arch/parisc/include/uapi/asm/mman.h
+++ linux-ein-5.4.0/arch/parisc/include/uapi/asm/mman.h
@@ -48,28 +48,27 @@
 #define MADV_DONTFORK	10		/* don't inherit across fork */
 #define MADV_DOFORK	11		/* do inherit across fork */
 
-#define MADV_COLD	20		/* deactivate these pages */
-#define MADV_PAGEOUT	21		/* reclaim these pages */
-
-#define MADV_MERGEABLE   65		/* KSM may merge identical pages */
-#define MADV_UNMERGEABLE 66		/* KSM may not merge identical pages */
+#define MADV_MERGEABLE   12		/* KSM may merge identical pages */
+#define MADV_UNMERGEABLE 13		/* KSM may not merge identical pages */
 
-#define MADV_HUGEPAGE	67		/* Worth backing with hugepages */
-#define MADV_NOHUGEPAGE	68		/* Not worth backing with hugepages */
+#define MADV_HUGEPAGE	14		/* Worth backing with hugepages */
+#define MADV_NOHUGEPAGE 15		/* Not worth backing with hugepages */
 
-#define MADV_DONTDUMP   69		/* Explicity exclude from the core dump,
+#define MADV_DONTDUMP   16		/* Explicity exclude from the core dump,
 					   overrides the coredump filter bits */
-#define MADV_DODUMP	70		/* Clear the MADV_NODUMP flag */
+#define MADV_DODUMP	17		/* Clear the MADV_NODUMP flag */
 
-#define MADV_WIPEONFORK 71		/* Zero memory on fork, child only */
-#define MADV_KEEPONFORK 72		/* Undo MADV_WIPEONFORK */
+#define MADV_WIPEONFORK 18		/* Zero memory on fork, child only */
+#define MADV_KEEPONFORK 19		/* Undo MADV_WIPEONFORK */
+
+#define MADV_COLD	20		/* deactivate these pages */
+#define MADV_PAGEOUT	21		/* reclaim these pages */
 
 #define MADV_HWPOISON     100		/* poison a page for testing */
 #define MADV_SOFT_OFFLINE 101		/* soft offline page for testing */
 
 /* compatibility flags */
 #define MAP_FILE	0
-#define MAP_VARIABLE	0
 
 #define PKEY_DISABLE_ACCESS	0x1
 #define PKEY_DISABLE_WRITE	0x2
--- linux-ein-5.4.0.orig/arch/parisc/include/uapi/asm/pdc.h
+++ linux-ein-5.4.0/arch/parisc/include/uapi/asm/pdc.h
@@ -465,6 +465,7 @@
 	unsigned long arch_rev;
 	unsigned long pot_key;
 	unsigned long curr_key;
+	unsigned long width;	/* default of PSW_W bit (1=enabled) */
 };
 
 struct pdc_cache_cf {		/* for PDC_CACHE  (I/D-caches) */
--- linux-ein-5.4.0.orig/arch/parisc/install.sh
+++ linux-ein-5.4.0/arch/parisc/install.sh
@@ -39,6 +39,7 @@
 if [ -n "${INSTALLKERNEL}" ]; then
   if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
   if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
+  if [ -x /usr/sbin/${INSTALLKERNEL} ]; then exec /usr/sbin/${INSTALLKERNEL} "$@"; fi
 fi
 
 # Default install
--- linux-ein-5.4.0.orig/arch/parisc/kernel/Makefile
+++ linux-ein-5.4.0/arch/parisc/kernel/Makefile
@@ -37,5 +37,5 @@
 obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_KPROBES)			+= kprobes.o
-obj-$(CONFIG_KEXEC)			+= kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_CORE)		+= kexec.o relocate_kernel.o
 obj-$(CONFIG_KEXEC_FILE)		+= kexec_file.o
--- linux-ein-5.4.0.orig/arch/parisc/kernel/cache.c
+++ linux-ein-5.4.0/arch/parisc/kernel/cache.c
@@ -328,6 +328,7 @@
 	struct vm_area_struct *mpnt;
 	unsigned long offset;
 	unsigned long addr, old_addr = 0;
+	unsigned long flags;
 	pgoff_t pgoff;
 
 	if (mapping && !mapping_mapped(mapping)) {
@@ -347,7 +348,7 @@
 	 * declared as MAP_PRIVATE or MAP_SHARED), so we only need
 	 * to flush one address here for them all to become coherent */
 
-	flush_dcache_mmap_lock(mapping);
+	flush_dcache_mmap_lock_irqsave(mapping, flags);
 	vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) {
 		offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
 		addr = mpnt->vm_start + offset;
@@ -370,7 +371,7 @@
 			old_addr = addr;
 		}
 	}
-	flush_dcache_mmap_unlock(mapping);
+	flush_dcache_mmap_unlock_irqrestore(mapping, flags);
 }
 EXPORT_SYMBOL(flush_dcache_page);
 
--- linux-ein-5.4.0.orig/arch/parisc/kernel/drivers.c
+++ linux-ein-5.4.0/arch/parisc/kernel/drivers.c
@@ -520,7 +520,6 @@
 	dev->id.hversion_rev = iodc_data[1] & 0x0f;
 	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
 			(iodc_data[5] << 8) | iodc_data[6];
-	dev->hpa.name = parisc_pathname(dev);
 	dev->hpa.start = hpa;
 	/* This is awkward.  The STI spec says that gfx devices may occupy
 	 * 32MB or 64MB.  Unfortunately, we don't know how to tell whether
@@ -534,10 +533,10 @@
 		dev->hpa.end = hpa + 0xfff;
 	}
 	dev->hpa.flags = IORESOURCE_MEM;
-	name = parisc_hardware_description(&dev->id);
-	if (name) {
-		strlcpy(dev->name, name, sizeof(dev->name));
-	}
+	dev->hpa.name = dev->name;
+	name = parisc_hardware_description(&dev->id) ? : "unknown";
+	snprintf(dev->name, sizeof(dev->name), "%s [%s]",
+		name, parisc_pathname(dev));
 
 	/* Silently fail things like mouse ports which are subsumed within
 	 * the keyboard controller
@@ -810,7 +809,7 @@
 static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
                             struct device *parent);
 
-static void walk_lower_bus(struct parisc_device *dev)
+static void __init walk_lower_bus(struct parisc_device *dev)
 {
 	unsigned long io_io_low, io_io_high;
 
@@ -883,15 +882,13 @@
 			&root);
 }
 
-static void print_parisc_device(struct parisc_device *dev)
+static __init void print_parisc_device(struct parisc_device *dev)
 {
-	char hw_path[64];
-	static int count;
+	static int count __initdata;
 
-	print_pa_hwpath(dev, hw_path);
-	pr_info("%d. %s at 0x%px [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }",
-		++count, dev->name, (void*) dev->hpa.start, hw_path, dev->id.hw_type,
-		dev->id.hversion_rev, dev->id.hversion, dev->id.sversion);
+	pr_info("%d. %s at %pap { type:%d, hv:%#x, sv:%#x, rev:%#x }",
+		++count, dev->name, &(dev->hpa.start), dev->id.hw_type,
+		dev->id.hversion, dev->id.sversion, dev->id.hversion_rev);
 
 	if (dev->num_addrs) {
 		int k;
@@ -927,9 +924,9 @@
 	pr_info("#define PARISC_MODEL \"%s\"\n\n",
 			boot_cpu_data.pdc.sys_model_name);
 
+	#define p ((unsigned long *)&boot_cpu_data.pdc.model)
 	pr_info("#define PARISC_PDC_MODEL 0x%lx, 0x%lx, 0x%lx, "
 		"0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n\n",
-	#define p ((unsigned long *)&boot_cpu_data.pdc.model)
 		p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
 	#undef p
 
@@ -1080,7 +1077,7 @@
 
 
 
-static int print_one_device(struct device * dev, void * data)
+static __init int print_one_device(struct device * dev, void * data)
 {
 	struct parisc_device * pdev = to_parisc_device(dev);
 
--- linux-ein-5.4.0.orig/arch/parisc/kernel/entry.S
+++ linux-ein-5.4.0/arch/parisc/kernel/entry.S
@@ -454,7 +454,6 @@
 	nop
 	LDREG		0(\ptp),\pte
 	bb,<,n		\pte,_PAGE_PRESENT_BIT,3f
-	LDCW		0(\tmp),\tmp1
 	b		\fault
 	stw		\spc,0(\tmp)
 99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
@@ -464,23 +463,26 @@
 3:
 	.endm
 
-	/* Release pa_tlb_lock lock without reloading lock address. */
-	.macro		tlb_unlock0	spc,tmp,tmp1
+	/* Release pa_tlb_lock lock without reloading lock address.
+	   Note that the values in the register spc are limited to
+	   NR_SPACE_IDS (262144). Thus, the stw instruction always
+	   stores a nonzero value even when register spc is 64 bits.
+	   We use an ordered store to ensure all prior accesses are
+	   performed prior to releasing the lock. */
+	.macro		tlb_unlock0	spc,tmp
 #ifdef CONFIG_SMP
 98:	or,COND(=)	%r0,\spc,%r0
-	LDCW		0(\tmp),\tmp1
-	or,COND(=)	%r0,\spc,%r0
-	stw		\spc,0(\tmp)
+	stw,ma		\spc,0(\tmp)
 99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
 	.endm
 
 	/* Release pa_tlb_lock lock. */
-	.macro		tlb_unlock1	spc,tmp,tmp1
+	.macro		tlb_unlock1	spc,tmp
 #ifdef CONFIG_SMP
 98:	load_pa_tlb_lock \tmp
 99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
-	tlb_unlock0	\spc,\tmp,\tmp1
+	tlb_unlock0	\spc,\tmp
 #endif
 	.endm
 
@@ -509,13 +511,13 @@
 	 * to a CPU TLB 4k PFN (4k => 12 bits to shift) */
 	#define PAGE_ADD_SHIFT		(PAGE_SHIFT-12)
 	#define PAGE_ADD_HUGE_SHIFT	(REAL_HPAGE_SHIFT-12)
+	#define PFN_START_BIT	(63-ASM_PFN_PTE_SHIFT+(63-58)-PAGE_ADD_SHIFT)
 
 	/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
 	.macro		convert_for_tlb_insert20 pte,tmp
 #ifdef CONFIG_HUGETLB_PAGE
 	copy		\pte,\tmp
-	extrd,u		\tmp,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
-				64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
+	extrd,u		\tmp,PFN_START_BIT,PFN_START_BIT+1,\pte
 
 	depdi		_PAGE_SIZE_ENCODING_DEFAULT,63,\
 				(63-58)+PAGE_ADD_SHIFT,\pte
@@ -523,8 +525,7 @@
 	depdi		_HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\
 				(63-58)+PAGE_ADD_HUGE_SHIFT,\pte
 #else /* Huge pages disabled */
-	extrd,u		\pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
-				64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
+	extrd,u		\pte,PFN_START_BIT,PFN_START_BIT+1,\pte
 	depdi		_PAGE_SIZE_ENCODING_DEFAULT,63,\
 				(63-58)+PAGE_ADD_SHIFT,\pte
 #endif
@@ -1163,7 +1164,7 @@
 	
 	idtlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1189,7 +1190,7 @@
 
 	idtlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1223,7 +1224,7 @@
 
 	mtsp		t1, %sr1	/* Restore sr1 */
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1256,7 +1257,7 @@
 
 	mtsp		t1, %sr1	/* Restore sr1 */
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1285,7 +1286,7 @@
 
 	idtlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1313,7 +1314,7 @@
 	
 	idtlbt		pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1420,7 +1421,7 @@
 	
 	iitlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1444,7 +1445,7 @@
 
 	iitlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1478,7 +1479,7 @@
 
 	mtsp		t1, %sr1	/* Restore sr1 */
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1502,7 +1503,7 @@
 
 	mtsp		t1, %sr1	/* Restore sr1 */
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1532,7 +1533,7 @@
 
 	iitlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1552,7 +1553,7 @@
 
 	iitlbt          pte,prot
 
-	tlb_unlock1	spc,t0,t1
+	tlb_unlock1	spc,t0
 	rfir
 	nop
 
@@ -1582,7 +1583,7 @@
 		
 	idtlbt          pte,prot
 
-	tlb_unlock0	spc,t0,t1
+	tlb_unlock0	spc,t0
 	rfir
 	nop
 #else
@@ -1608,7 +1609,7 @@
 
 	mtsp            t1, %sr1     /* Restore sr1 */
 
-	tlb_unlock0	spc,t0,t1
+	tlb_unlock0	spc,t0
 	rfir
 	nop
 
@@ -1628,7 +1629,7 @@
 	
 	idtlbt		pte,prot
 
-	tlb_unlock0	spc,t0,t1
+	tlb_unlock0	spc,t0
 	rfir
 	nop
 #endif
@@ -1839,8 +1840,8 @@
 	LDREG	TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
 
 	/* Are we being ptraced? */
-	ldw	TASK_FLAGS(%r1),%r19
-	ldi	_TIF_SYSCALL_TRACE_MASK,%r2
+	LDREG	TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
+	ldi	_TIF_SINGLESTEP|_TIF_BLOCKSTEP,%r2
 	and,COND(=)	%r19,%r2,%r0
 	b,n	syscall_restore_rfi
 
--- linux-ein-5.4.0.orig/arch/parisc/kernel/firmware.c
+++ linux-ein-5.4.0/arch/parisc/kernel/firmware.c
@@ -122,10 +122,10 @@
 #ifdef CONFIG_64BIT
 	if(unlikely(parisc_narrow_firmware)) {
 		if((address & 0xff000000) == 0xf0000000)
-			return 0xf0f0f0f000000000UL | (u32)address;
+			return (0xfffffff0UL << 32) | (u32)address;
 
 		if((address & 0xf0000000) == 0xf0000000)
-			return 0xffffffff00000000UL | (u32)address;
+			return (0xffffffffUL << 32) | (u32)address;
 	}
 #endif
 	return address;
@@ -1229,7 +1229,7 @@
  */
 int pdc_iodc_print(const unsigned char *str, unsigned count)
 {
-	unsigned int i;
+	unsigned int i, found = 0;
 	unsigned long flags;
 
 	for (i = 0; i < count;) {
@@ -1238,6 +1238,7 @@
 			iodc_dbuf[i+0] = '\r';
 			iodc_dbuf[i+1] = '\n';
 			i += 2;
+			found = 1;
 			goto print;
 		default:
 			iodc_dbuf[i] = str[i];
@@ -1254,7 +1255,7 @@
                     __pa(iodc_retbuf), 0, __pa(iodc_dbuf), i, 0);
         spin_unlock_irqrestore(&pdc_lock, flags);
 
-	return i;
+	return i - found;
 }
 
 #if !defined(BOOTLOADER)
--- linux-ein-5.4.0.orig/arch/parisc/kernel/head.S
+++ linux-ein-5.4.0/arch/parisc/kernel/head.S
@@ -22,7 +22,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
-	.level	PA_ASM_LEVEL
+	.level	1.1
 
 	__INITDATA
 ENTRY(boot_args)
@@ -69,6 +69,46 @@
 	stw,ma          %arg2,4(%r1)
 	stw,ma          %arg3,4(%r1)
 
+#if defined(CONFIG_PA20)
+	/* check for 64-bit capable CPU as required by current kernel */
+	ldi		32,%r10
+	mtctl		%r10,%cr11
+	.level 2.0
+	mfctl,w		%cr11,%r10
+	.level 1.1
+	comib,<>,n	0,%r10,$cpu_ok
+
+	load32		PA(msg1),%arg0
+	ldi		msg1_end-msg1,%arg1
+$iodc_panic:
+	copy		%arg0, %r10
+	copy		%arg1, %r11
+	load32		PA(init_stack),%sp
+#define MEM_CONS 0x3A0
+	ldw		MEM_CONS+32(%r0),%arg0	// HPA
+	ldi		ENTRY_IO_COUT,%arg1
+	ldw		MEM_CONS+36(%r0),%arg2	// SPA
+	ldw		MEM_CONS+8(%r0),%arg3	// layers
+	load32		PA(__bss_start),%r1
+	stw		%r1,-52(%sp)		// arg4
+	stw		%r0,-56(%sp)		// arg5
+	stw		%r10,-60(%sp)		// arg6 = ptr to text
+	stw		%r11,-64(%sp)		// arg7 = len
+	stw		%r0,-68(%sp)		// arg8
+	load32		PA(.iodc_panic_ret), %rp
+	ldw		MEM_CONS+40(%r0),%r1	// ENTRY_IODC
+	bv,n		(%r1)
+.iodc_panic_ret:
+	b .				/* wait endless with ... */
+	or		%r10,%r10,%r10	/* qemu idle sleep */
+msg1:	.ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n"
+msg1_end:
+
+$cpu_ok:
+#endif
+
+	.level	PA_ASM_LEVEL
+
 	/* Initialize startup VM. Just map first 16/32 MB of memory */
 	load32		PA(swapper_pg_dir),%r4
 	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
--- linux-ein-5.4.0.orig/arch/parisc/kernel/irq.c
+++ linux-ein-5.4.0/arch/parisc/kernel/irq.c
@@ -376,7 +376,11 @@
 /*
  * IRQ STACK - used for irq handler
  */
+#ifdef CONFIG_64BIT
+#define IRQ_STACK_SIZE      (4096 << 4) /* 64k irq stack size */
+#else
 #define IRQ_STACK_SIZE      (4096 << 3) /* 32k irq stack size */
+#endif
 
 union irq_stack_union {
 	unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
@@ -384,7 +388,7 @@
 	volatile unsigned int lock[1];
 };
 
-DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
+static DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
 		.slock = { 1,1,1,1 },
 	};
 #endif
--- linux-ein-5.4.0.orig/arch/parisc/kernel/module.c
+++ linux-ein-5.4.0/arch/parisc/kernel/module.c
@@ -43,6 +43,7 @@
 #include <linux/elf.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/ftrace.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/bug.h>
@@ -862,7 +863,7 @@
 	const char *strtab = NULL;
 	const Elf_Shdr *s;
 	char *secstrings;
-	int err, symindex = -1;
+	int symindex = -1;
 	Elf_Sym *newptr, *oldptr;
 	Elf_Shdr *symhdr = NULL;
 #ifdef DEBUG
@@ -946,11 +947,13 @@
 			/* patch .altinstructions */
 			apply_alternatives(aseg, aseg + s->sh_size, me->name);
 
+#ifdef CONFIG_DYNAMIC_FTRACE
 		/* For 32 bit kernels we're compiling modules with
 		 * -ffunction-sections so we must relocate the addresses in the
-		 *__mcount_loc section.
+		 *  ftrace callsite section.
 		 */
-		if (symindex != -1 && !strcmp(secname, "__mcount_loc")) {
+		if (symindex != -1 && !strcmp(secname, FTRACE_CALLSITE_SECTION)) {
+			int err;
 			if (s->sh_type == SHT_REL)
 				err = apply_relocate((Elf_Shdr *)sechdrs,
 							strtab, symindex,
@@ -962,6 +965,7 @@
 			if (err)
 				return err;
 		}
+#endif
 	}
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/parisc/kernel/parisc_ksyms.c
+++ linux-ein-5.4.0/arch/parisc/kernel/parisc_ksyms.c
@@ -17,10 +17,6 @@
 
 #include <linux/string.h>
 EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strcat);
 
 #include <linux/atomic.h>
 EXPORT_SYMBOL(__xchg8);
--- linux-ein-5.4.0.orig/arch/parisc/kernel/patch.c
+++ linux-ein-5.4.0/arch/parisc/kernel/patch.c
@@ -40,10 +40,7 @@
 
 	*need_unmap = 1;
 	set_fixmap(fixmap, page_to_phys(page));
-	if (flags)
-		raw_spin_lock_irqsave(&patch_lock, *flags);
-	else
-		__acquire(&patch_lock);
+	raw_spin_lock_irqsave(&patch_lock, *flags);
 
 	return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK));
 }
@@ -52,10 +49,7 @@
 {
 	clear_fixmap(fixmap);
 
-	if (flags)
-		raw_spin_unlock_irqrestore(&patch_lock, *flags);
-	else
-		__release(&patch_lock);
+	raw_spin_unlock_irqrestore(&patch_lock, *flags);
 }
 
 void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
@@ -67,8 +61,9 @@
 	int mapped;
 
 	/* Make sure we don't have any aliases in cache */
-	flush_kernel_vmap_range(addr, len);
-	flush_icache_range(start, end);
+	flush_kernel_dcache_range_asm(start, end);
+	flush_kernel_icache_range_asm(start, end);
+	flush_tlb_kernel_range(start, end);
 
 	p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags, &mapped);
 
@@ -81,8 +76,10 @@
 			 * We're crossing a page boundary, so
 			 * need to remap
 			 */
-			flush_kernel_vmap_range((void *)fixmap,
-						(p-fixmap) * sizeof(*p));
+			flush_kernel_dcache_range_asm((unsigned long)fixmap,
+						      (unsigned long)p);
+			flush_tlb_kernel_range((unsigned long)fixmap,
+					       (unsigned long)p);
 			if (mapped)
 				patch_unmap(FIX_TEXT_POKE0, &flags);
 			p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags,
@@ -90,10 +87,10 @@
 		}
 	}
 
-	flush_kernel_vmap_range((void *)fixmap, (p-fixmap) * sizeof(*p));
+	flush_kernel_dcache_range_asm((unsigned long)fixmap, (unsigned long)p);
+	flush_tlb_kernel_range((unsigned long)fixmap, (unsigned long)p);
 	if (mapped)
 		patch_unmap(FIX_TEXT_POKE0, &flags);
-	flush_icache_range(start, end);
 }
 
 void __kprobes __patch_text(void *addr, u32 insn)
--- linux-ein-5.4.0.orig/arch/parisc/kernel/pci-dma.c
+++ linux-ein-5.4.0/arch/parisc/kernel/pci-dma.c
@@ -439,16 +439,32 @@
 	free_pages((unsigned long)__va(dma_handle), order);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
+	/*
+	 * fdc: The data cache line is written back to memory, if and only if
+	 * it is dirty, and then invalidated from the data cache.
+	 */
 	flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
-	flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
+	unsigned long addr = (unsigned long) phys_to_virt(paddr);
+
+	switch (dir) {
+	case DMA_TO_DEVICE:
+	case DMA_BIDIRECTIONAL:
+		flush_kernel_dcache_range(addr, size);
+		return;
+	case DMA_FROM_DEVICE:
+		purge_kernel_dcache_range_asm(addr, addr + size);
+		return;
+	default:
+		BUG();
+	}
 }
 
 void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
--- linux-ein-5.4.0.orig/arch/parisc/kernel/process.c
+++ linux-ein-5.4.0/arch/parisc/kernel/process.c
@@ -124,13 +124,18 @@
 	/* It seems we have no way to power the system off via
 	 * software. The user has to press the button himself. */
 
-	printk(KERN_EMERG "System shut down completed.\n"
-	       "Please power this system off now.");
+	printk("Power off or press RETURN to reboot.\n");
 
 	/* prevent soft lockup/stalled CPU messages for endless loop. */
 	rcu_sysrq_start();
 	lockup_detector_soft_poweroff();
-	for (;;);
+	while (1) {
+		/* reboot if user presses RETURN key */
+		if (pdc_iodc_getc() == 13) {
+			printk("Rebooting...\n");
+			machine_restart(NULL);
+		}
+	}
 }
 
 void (*pm_power_off)(void);
@@ -208,8 +213,8 @@
  * Copy architecture-specific thread state
  */
 int
-copy_thread(unsigned long clone_flags, unsigned long usp,
-	    unsigned long kthread_arg, struct task_struct *p)
+copy_thread_tls(unsigned long clone_flags, unsigned long usp,
+	    unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
 {
 	struct pt_regs *cregs = &(p->thread.regs);
 	void *stack = task_stack_page(p);
@@ -254,9 +259,9 @@
 		cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
 		cregs->kpc = (unsigned long) &child_return;
 
-		/* Setup thread TLS area from the 4th parameter in clone */
+		/* Setup thread TLS area */
 		if (clone_flags & CLONE_SETTLS)
-			cregs->cr27 = cregs->gr[23];
+			cregs->cr27 = tls;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/parisc/kernel/processor.c
+++ linux-ein-5.4.0/arch/parisc/kernel/processor.c
@@ -163,7 +163,6 @@
 	if (cpuid)
 		memset(p, 0, sizeof(struct cpuinfo_parisc));
 
-	p->loops_per_jiffy = loops_per_jiffy;
 	p->dev = dev;		/* Save IODC data in case we need it */
 	p->hpa = dev->hpa.start;	/* save CPU hpa */
 	p->cpuid = cpuid;	/* save CPU id */
@@ -373,10 +372,18 @@
 show_cpuinfo (struct seq_file *m, void *v)
 {
 	unsigned long cpu;
+	char cpu_name[60], *p;
+
+	/* strip PA path from CPU name to not confuse lscpu */
+	strlcpy(cpu_name, per_cpu(cpu_data, 0).dev->name, sizeof(cpu_name));
+	p = strrchr(cpu_name, '[');
+	if (p)
+		*(--p) = 0;
 
 	for_each_online_cpu(cpu) {
-		const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
 #ifdef CONFIG_SMP
+		const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
+
 		if (0 == cpuinfo->hpa)
 			continue;
 #endif
@@ -419,11 +426,9 @@
 		}
 		seq_printf(m, " (0x%02lx)\n", boot_cpu_data.pdc.capabilities);
 
-		seq_printf(m, "model\t\t: %s\n"
-				"model name\t: %s\n",
+		seq_printf(m, "model\t\t: %s - %s\n",
 				 boot_cpu_data.pdc.sys_model_name,
-				 cpuinfo->dev ?
-				 cpuinfo->dev->name : "Unknown");
+				 cpu_name);
 
 		seq_printf(m, "hversion\t: 0x%08x\n"
 			        "sversion\t: 0x%08x\n",
@@ -434,8 +439,8 @@
 		show_cache_info(m);
 
 		seq_printf(m, "bogomips\t: %lu.%02lu\n",
-			     cpuinfo->loops_per_jiffy / (500000 / HZ),
-			     (cpuinfo->loops_per_jiffy / (5000 / HZ)) % 100);
+			     loops_per_jiffy / (500000 / HZ),
+			     loops_per_jiffy / (5000 / HZ) % 100);
 
 		seq_printf(m, "software id\t: %ld\n\n",
 				boot_cpu_data.pdc.model.sw_id);
--- linux-ein-5.4.0.orig/arch/parisc/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/parisc/kernel/ptrace.c
@@ -128,6 +128,12 @@
 	unsigned long tmp;
 	long ret = -EIO;
 
+	unsigned long user_regs_struct_size = sizeof(struct user_regs_struct);
+#ifdef CONFIG_64BIT
+	if (is_compat_task())
+		user_regs_struct_size /= 2;
+#endif
+
 	switch (request) {
 
 	/* Read the word at location addr in the USER area.  For ptraced
@@ -183,14 +189,14 @@
 		return copy_regset_to_user(child,
 					   task_user_regset_view(current),
 					   REGSET_GENERAL,
-					   0, sizeof(struct user_regs_struct),
+					   0, user_regs_struct_size,
 					   datap);
 
 	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
 		return copy_regset_from_user(child,
 					     task_user_regset_view(current),
 					     REGSET_GENERAL,
-					     0, sizeof(struct user_regs_struct),
+					     0, user_regs_struct_size,
 					     datap);
 
 	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
@@ -304,6 +310,11 @@
 			}
 		}
 		break;
+	case PTRACE_GETREGS:
+	case PTRACE_SETREGS:
+	case PTRACE_GETFPREGS:
+	case PTRACE_SETFPREGS:
+		return arch_ptrace(child, request, addr, data);
 
 	default:
 		ret = compat_ptrace_request(child, request, addr, data);
--- linux-ein-5.4.0.orig/arch/parisc/kernel/real2.S
+++ linux-ein-5.4.0/arch/parisc/kernel/real2.S
@@ -248,9 +248,6 @@
 	/* save fn */
 	copy	%arg2, %r31
 
-	/* set up the new ap */
-	ldo	64(%arg1), %r29
-
 	/* load up the arg registers from the saved arg area */
 	/* 32-bit calling convention passes first 4 args in registers */
 	ldd	0*REG_SZ(%arg1), %arg0		/* note overwriting arg0 */
@@ -262,7 +259,9 @@
 	ldd	7*REG_SZ(%arg1), %r19
 	ldd	1*REG_SZ(%arg1), %arg1		/* do this one last! */
 
+	/* set up real-mode stack and real-mode ap */
 	tophys_r1 %sp
+	ldo	-16(%sp), %r29			/* Reference param save area */
 
 	b,l	rfi_virt2real,%r2
 	nop
--- linux-ein-5.4.0.orig/arch/parisc/kernel/signal.c
+++ linux-ein-5.4.0/arch/parisc/kernel/signal.c
@@ -238,6 +238,12 @@
 #endif
 	
 	usp = (regs->gr[30] & ~(0x01UL));
+#ifdef CONFIG_64BIT
+	if (is_compat_task()) {
+		/* The gcc alloca implementation leaves garbage in the upper 32 bits of sp */
+		usp = (compat_uint_t)usp;
+	}
+#endif
 	/*FIXME: frame_size parameter is unused, remove it. */
 	frame = get_sigframe(&ksig->ka, usp, sizeof(*frame));
 
--- linux-ein-5.4.0.orig/arch/parisc/kernel/smp.c
+++ linux-ein-5.4.0/arch/parisc/kernel/smp.c
@@ -29,6 +29,7 @@
 #include <linux/bitops.h>
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
+#include <linux/kgdb.h>
 
 #include <linux/atomic.h>
 #include <asm/current.h>
@@ -71,7 +72,10 @@
 	IPI_CALL_FUNC,
 	IPI_CPU_START,
 	IPI_CPU_STOP,
-	IPI_CPU_TEST
+	IPI_CPU_TEST,
+#ifdef CONFIG_KGDB
+	IPI_ENTER_KGDB,
+#endif
 };
 
 
@@ -169,7 +173,12 @@
 			case IPI_CPU_TEST:
 				smp_debug(100, KERN_DEBUG "CPU%d is alive!\n", this_cpu);
 				break;
-
+#ifdef CONFIG_KGDB
+			case IPI_ENTER_KGDB:
+				smp_debug(100, KERN_DEBUG "CPU%d ENTER_KGDB\n", this_cpu);
+				kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+				break;
+#endif
 			default:
 				printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
 					this_cpu, which);
@@ -225,6 +234,12 @@
 	}
 }
 
+#ifdef CONFIG_KGDB
+void kgdb_roundup_cpus(void)
+{
+	send_IPI_allbutself(IPI_ENTER_KGDB);
+}
+#endif
 
 inline void 
 smp_send_stop(void)	{ send_IPI_allbutself(IPI_CPU_STOP); }
--- linux-ein-5.4.0.orig/arch/parisc/kernel/sys_parisc.c
+++ linux-ein-5.4.0/arch/parisc/kernel/sys_parisc.c
@@ -373,3 +373,30 @@
 
 	return err;
 }
+
+/*
+ * madvise() wrapper
+ *
+ * Up to kernel v6.1 parisc has different values than all other
+ * platforms for the MADV_xxx flags listed below.
+ * To keep binary compatibility with existing userspace programs
+ * translate the former values to the new values.
+ *
+ * XXX: Remove this wrapper in year 2025 (or later)
+ */
+
+asmlinkage notrace long parisc_madvise(unsigned long start, size_t len_in, int behavior)
+{
+	switch (behavior) {
+	case 65: behavior = MADV_MERGEABLE;	break;
+	case 66: behavior = MADV_UNMERGEABLE;	break;
+	case 67: behavior = MADV_HUGEPAGE;	break;
+	case 68: behavior = MADV_NOHUGEPAGE;	break;
+	case 69: behavior = MADV_DONTDUMP;	break;
+	case 70: behavior = MADV_DODUMP;	break;
+	case 71: behavior = MADV_WIPEONFORK;	break;
+	case 72: behavior = MADV_KEEPONFORK;	break;
+	}
+
+	return sys_madvise(start, len_in, behavior);
+}
--- linux-ein-5.4.0.orig/arch/parisc/kernel/syscall.S
+++ linux-ein-5.4.0/arch/parisc/kernel/syscall.S
@@ -478,7 +478,7 @@
 	extrd,u	%r1,PSW_W_BIT,1,%r1
 	/* sp must be aligned on 4, so deposit the W bit setting into
 	 * the bottom of sp temporarily */
-	or,ev	%r1,%r30,%r30
+	or,od	%r1,%r30,%r30
 
 	/* Clip LWS number to a 32-bit value for 32-bit processes */
 	depdi	0, 31, 32, %r20
@@ -640,11 +640,7 @@
 	sub,<>	%r28, %r25, %r0
 2:	stw	%r24, 0(%r26)
 	/* Free lock */
-#ifdef CONFIG_SMP
-98:	LDCW	0(%sr2,%r20), %r1			/* Barrier */
-99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
-#endif
-	stw	%r20, 0(%sr2,%r20)
+	stw,ma	%r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
 	/* Clear thread register indicator */
 	stw	%r0, 4(%sr2,%r20)
@@ -658,11 +654,7 @@
 3:		
 	/* Error occurred on load or store */
 	/* Free lock */
-#ifdef CONFIG_SMP
-98:	LDCW	0(%sr2,%r20), %r1			/* Barrier */
-99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
-#endif
-	stw	%r20, 0(%sr2,%r20)
+	stw,ma	%r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
 	stw	%r0, 4(%sr2,%r20)
 #endif
@@ -863,11 +855,7 @@
 
 cas2_end:
 	/* Free lock */
-#ifdef CONFIG_SMP
-98:	LDCW	0(%sr2,%r20), %r1			/* Barrier */
-99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
-#endif
-	stw	%r20, 0(%sr2,%r20)
+	stw,ma	%r20, 0(%sr2,%r20)
 	/* Enable interrupts */
 	ssm	PSW_SM_I, %r0
 	/* Return to userspace, set no error */
@@ -877,11 +865,7 @@
 22:
 	/* Error occurred on load or store */
 	/* Free lock */
-#ifdef CONFIG_SMP
-98:	LDCW	0(%sr2,%r20), %r1			/* Barrier */
-99:	ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
-#endif
-	stw	%r20, 0(%sr2,%r20)
+	stw,ma	%r20, 0(%sr2,%r20)
 	ssm	PSW_SM_I, %r0
 	ldo	1(%r0),%r28
 	b	lws_exit
--- linux-ein-5.4.0.orig/arch/parisc/kernel/syscalls/syscall.tbl
+++ linux-ein-5.4.0/arch/parisc/kernel/syscalls/syscall.tbl
@@ -131,7 +131,7 @@
 116	common	sysinfo			sys_sysinfo			compat_sys_sysinfo
 117	common	shutdown		sys_shutdown
 118	common	fsync			sys_fsync
-119	common	madvise			sys_madvise
+119	common	madvise			parisc_madvise
 120	common	clone			sys_clone_wrapper
 121	common	setdomainname		sys_setdomainname
 122	common	sendfile		sys_sendfile			compat_sys_sendfile
@@ -413,7 +413,7 @@
 412	32	utimensat_time64		sys_utimensat			sys_utimensat
 413	32	pselect6_time64			sys_pselect6			compat_sys_pselect6_time64
 414	32	ppoll_time64			sys_ppoll			compat_sys_ppoll_time64
-416	32	io_pgetevents_time64		sys_io_pgetevents		sys_io_pgetevents
+416	32	io_pgetevents_time64		sys_io_pgetevents		compat_sys_io_pgetevents_time64
 417	32	recvmmsg_time64			sys_recvmmsg			compat_sys_recvmmsg_time64
 418	32	mq_timedsend_time64		sys_mq_timedsend		sys_mq_timedsend
 419	32	mq_timedreceive_time64		sys_mq_timedreceive		sys_mq_timedreceive
--- linux-ein-5.4.0.orig/arch/parisc/kernel/time.c
+++ linux-ein-5.4.0/arch/parisc/kernel/time.c
@@ -245,27 +245,13 @@
 static int __init init_cr16_clocksource(void)
 {
 	/*
-	 * The cr16 interval timers are not syncronized across CPUs on
-	 * different sockets, so mark them unstable and lower rating on
-	 * multi-socket SMP systems.
+	 * The cr16 interval timers are not syncronized across CPUs, even if
+	 * they share the same socket.
 	 */
 	if (num_online_cpus() > 1 && !running_on_qemu) {
-		int cpu;
-		unsigned long cpu0_loc;
-		cpu0_loc = per_cpu(cpu_data, 0).cpu_loc;
-
-		for_each_online_cpu(cpu) {
-			if (cpu == 0)
-				continue;
-			if ((cpu0_loc != 0) &&
-			    (cpu0_loc == per_cpu(cpu_data, cpu).cpu_loc))
-				continue;
-
-			clocksource_cr16.name = "cr16_unstable";
-			clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
-			clocksource_cr16.rating = 0;
-			break;
-		}
+		clocksource_cr16.name = "cr16_unstable";
+		clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
+		clocksource_cr16.rating = 0;
 	}
 
 	/* XXX: We may want to mark sched_clock stable here if cr16 clocks are
--- linux-ein-5.4.0.orig/arch/parisc/kernel/traps.c
+++ linux-ein-5.4.0/arch/parisc/kernel/traps.c
@@ -268,7 +268,7 @@
 		panic("Fatal exception");
 
 	oops_exit();
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 /* gdb uses break 4,8 */
@@ -305,8 +305,8 @@
 #endif
 
 #ifdef CONFIG_KGDB
-	if (unlikely(iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
-		iir == PARISC_KGDB_BREAK_INSN)) {
+	if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
+		iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) {
 		kgdb_handle_exception(9, SIGTRAP, 0, regs);
 		return;
 	}
@@ -783,7 +783,7 @@
 	     * unless pagefault_disable() was called before.
 	     */
 
-	    if (fault_space == 0 && !faulthandler_disabled())
+	    if (faulthandler_disabled() || fault_space == 0)
 	    {
 		/* Clean up and return if in exception table. */
 		if (fixup_exception(regs))
--- linux-ein-5.4.0.orig/arch/parisc/kernel/unaligned.c
+++ linux-ein-5.4.0/arch/parisc/kernel/unaligned.c
@@ -107,7 +107,7 @@
 #define R1(i) (((i)>>21)&0x1f)
 #define R2(i) (((i)>>16)&0x1f)
 #define R3(i) ((i)&0x1f)
-#define FR3(i) ((((i)<<1)&0x1f)|(((i)>>6)&1))
+#define FR3(i) ((((i)&0x1f)<<1)|(((i)>>6)&1))
 #define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
 #define IM5_2(i) IM((i)>>16,5)
 #define IM5_3(i) IM((i),5)
@@ -340,7 +340,7 @@
 	: "r" (val), "r" (regs->ior), "r" (regs->isr)
 	: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 
-	return 0;
+	return ret;
 }
 static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 {
@@ -397,7 +397,7 @@
 	__asm__ __volatile__ (
 "	mtsp	%4, %%sr1\n"
 "	zdep	%2, 29, 2, %%r19\n"
-"	dep	%%r0, 31, 2, %2\n"
+"	dep	%%r0, 31, 2, %3\n"
 "	mtsar	%%r19\n"
 "	zvdepi	-2, 32, %%r19\n"
 "1:	ldw	0(%%sr1,%3),%%r20\n"
@@ -409,7 +409,7 @@
 "	andcm	%%r21, %%r19, %%r21\n"
 "	or	%1, %%r20, %1\n"
 "	or	%2, %%r21, %2\n"
-"3:	stw	%1,0(%%sr1,%1)\n"
+"3:	stw	%1,0(%%sr1,%3)\n"
 "4:	stw	%%r1,4(%%sr1,%3)\n"
 "5:	stw	%2,8(%%sr1,%3)\n"
 "	copy	%%r0, %0\n"
@@ -596,7 +596,6 @@
 		ret = ERR_NOTHANDLED;	/* "undefined", but lets kill them. */
 		break;
 	}
-#ifdef CONFIG_PA20
 	switch (regs->iir & OPCODE2_MASK)
 	{
 	case OPCODE_FLDD_L:
@@ -607,22 +606,23 @@
 		flop=1;
 		ret = emulate_std(regs, R2(regs->iir),1);
 		break;
+#ifdef CONFIG_PA20
 	case OPCODE_LDD_L:
 		ret = emulate_ldd(regs, R2(regs->iir),0);
 		break;
 	case OPCODE_STD_L:
 		ret = emulate_std(regs, R2(regs->iir),0);
 		break;
-	}
 #endif
+	}
 	switch (regs->iir & OPCODE3_MASK)
 	{
 	case OPCODE_FLDW_L:
 		flop=1;
-		ret = emulate_ldw(regs, R2(regs->iir),0);
+		ret = emulate_ldw(regs, R2(regs->iir), 1);
 		break;
 	case OPCODE_LDW_M:
-		ret = emulate_ldw(regs, R2(regs->iir),1);
+		ret = emulate_ldw(regs, R2(regs->iir), 0);
 		break;
 
 	case OPCODE_FSTW_L:
--- linux-ein-5.4.0.orig/arch/parisc/kernel/unwind.c
+++ linux-ein-5.4.0/arch/parisc/kernel/unwind.c
@@ -21,6 +21,8 @@
 #include <asm/ptrace.h>
 
 #include <asm/unwind.h>
+#include <asm/switch_to.h>
+#include <asm/sections.h>
 
 /* #define DEBUG 1 */
 #ifdef DEBUG
@@ -203,6 +205,11 @@
 	return 0;
 }
 
+static bool pc_is_kernel_fn(unsigned long pc, void *fn)
+{
+	return (unsigned long)dereference_kernel_function_descriptor(fn) == pc;
+}
+
 static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
 {
 	/*
@@ -221,7 +228,7 @@
 	extern void * const _call_on_stack;
 #endif /* CONFIG_IRQSTACKS */
 
-	if (pc == (unsigned long) &handle_interruption) {
+	if (pc_is_kernel_fn(pc, handle_interruption)) {
 		struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
 		dbg("Unwinding through handle_interruption()\n");
 		info->prev_sp = regs->gr[30];
@@ -229,13 +236,13 @@
 		return 1;
 	}
 
-	if (pc == (unsigned long) &ret_from_kernel_thread ||
-	    pc == (unsigned long) &syscall_exit) {
+	if (pc_is_kernel_fn(pc, ret_from_kernel_thread) ||
+	    pc_is_kernel_fn(pc, syscall_exit)) {
 		info->prev_sp = info->prev_ip = 0;
 		return 1;
 	}
 
-	if (pc == (unsigned long) &intr_return) {
+	if (pc_is_kernel_fn(pc, intr_return)) {
 		struct pt_regs *regs;
 
 		dbg("Found intr_return()\n");
@@ -246,20 +253,20 @@
 		return 1;
 	}
 
-	if (pc == (unsigned long) &_switch_to_ret) {
+	if (pc_is_kernel_fn(pc, _switch_to) ||
+	    pc_is_kernel_fn(pc, _switch_to_ret)) {
 		info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
 		info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
 		return 1;
 	}
 
 #ifdef CONFIG_IRQSTACKS
-	if (pc == (unsigned long) &_call_on_stack) {
+	if (pc_is_kernel_fn(pc, _call_on_stack)) {
 		info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
 		info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
 		return 1;
 	}
 #endif
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/parisc/lib/Makefile
+++ linux-ein-5.4.0/arch/parisc/lib/Makefile
@@ -3,7 +3,7 @@
 # Makefile for parisc-specific library files
 #
 
-lib-y	:= lusercopy.o bitops.o checksum.o io.o memcpy.o \
-	   ucmpdi2.o delay.o string.o
+lib-y	:= lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \
+	   ucmpdi2.o delay.o
 
 obj-y	:= iomap.o
--- linux-ein-5.4.0.orig/arch/parisc/lib/bitops.c
+++ linux-ein-5.4.0/arch/parisc/lib/bitops.c
@@ -79,3 +79,15 @@
 	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return (unsigned long)prev;
 }
+
+u8 __cmpxchg_u8(volatile u8 *ptr, u8 old, u8 new)
+{
+	unsigned long flags;
+	u8 prev;
+
+	_atomic_spin_lock_irqsave(ptr, flags);
+	if ((prev = *ptr) == old)
+		*ptr = new;
+	_atomic_spin_unlock_irqrestore(ptr, flags);
+	return prev;
+}
--- linux-ein-5.4.0.orig/arch/parisc/lib/memset.c
+++ linux-ein-5.4.0/arch/parisc/lib/memset.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <linux/types.h>
+#include <asm/string.h>
+
+#define OPSIZ (BITS_PER_LONG/8)
+typedef unsigned long op_t;
+
+void *
+memset (void *dstpp, int sc, size_t len)
+{
+  unsigned int c = sc;
+  long int dstp = (long int) dstpp;
+
+  if (len >= 8)
+    {
+      size_t xlen;
+      op_t cccc;
+
+      cccc = (unsigned char) c;
+      cccc |= cccc << 8;
+      cccc |= cccc << 16;
+      if (OPSIZ > 4)
+	/* Do the shift in two steps to avoid warning if long has 32 bits.  */
+	cccc |= (cccc << 16) << 16;
+
+      /* There are at least some bytes to set.
+	 No need to test for LEN == 0 in this alignment loop.  */
+      while (dstp % OPSIZ != 0)
+	{
+	  ((unsigned char *) dstp)[0] = c;
+	  dstp += 1;
+	  len -= 1;
+	}
+
+      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
+      xlen = len / (OPSIZ * 8);
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  ((op_t *) dstp)[1] = cccc;
+	  ((op_t *) dstp)[2] = cccc;
+	  ((op_t *) dstp)[3] = cccc;
+	  ((op_t *) dstp)[4] = cccc;
+	  ((op_t *) dstp)[5] = cccc;
+	  ((op_t *) dstp)[6] = cccc;
+	  ((op_t *) dstp)[7] = cccc;
+	  dstp += 8 * OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ * 8;
+
+      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
+      xlen = len / OPSIZ;
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  dstp += OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ;
+    }
+
+  /* Write the last few bytes.  */
+  while (len > 0)
+    {
+      ((unsigned char *) dstp)[0] = c;
+      dstp += 1;
+      len -= 1;
+    }
+
+  return dstpp;
+}
--- linux-ein-5.4.0.orig/arch/parisc/math-emu/fpudispatch.c
+++ linux-ein-5.4.0/arch/parisc/math-emu/fpudispatch.c
@@ -310,12 +310,15 @@
 					r1 &= ~3;
 					fpregs[t+3] = fpregs[r1+3];
 					fpregs[t+2] = fpregs[r1+2];
+					fallthrough;
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					fpregs[t] = fpregs[r1];
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 3: /* FABS */
 				switch (fmt) {
 				    case 2: /* illegal */
@@ -325,13 +328,16 @@
 					r1 &= ~3;
 					fpregs[t+3] = fpregs[r1+3];
 					fpregs[t+2] = fpregs[r1+2];
+					fallthrough;
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					/* copy and clear sign bit */
 					fpregs[t] = fpregs[r1] & 0x7fffffff;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 6: /* FNEG */
 				switch (fmt) {
 				    case 2: /* illegal */
@@ -341,13 +347,16 @@
 					r1 &= ~3;
 					fpregs[t+3] = fpregs[r1+3];
 					fpregs[t+2] = fpregs[r1+2];
+					fallthrough;
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					/* copy and invert sign bit */
 					fpregs[t] = fpregs[r1] ^ 0x80000000;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 7: /* FNEGABS */
 				switch (fmt) {
 				    case 2: /* illegal */
@@ -357,13 +366,16 @@
 					r1 &= ~3;
 					fpregs[t+3] = fpregs[r1+3];
 					fpregs[t+2] = fpregs[r1+2];
+					fallthrough;
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					/* copy and set sign bit */
 					fpregs[t] = fpregs[r1] | 0x80000000;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 4: /* FSQRT */
 				switch (fmt) {
 				    case 0:
@@ -376,6 +388,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 5: /* FRND */
 				switch (fmt) {
 				    case 0:
@@ -389,7 +402,7 @@
 					return(MAJOR_0C_EXCP);
 				}
 		} /* end of switch (subop) */
-
+		BUG();
 	case 1: /* class 1 */
 		df = extru(ir,fpdfpos,2); /* get dest format */
 		if ((df & 2) || (fmt & 2)) {
@@ -419,6 +432,7 @@
 				    case 3: /* dbl/dbl */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 1: /* FCNVXF */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -434,6 +448,7 @@
 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 2: /* FCNVFX */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -449,6 +464,7 @@
 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 3: /* FCNVFXT */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -464,6 +480,7 @@
 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 5: /* FCNVUF (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -479,6 +496,7 @@
 					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 6: /* FCNVFU (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -494,6 +512,7 @@
 					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 7: /* FCNVFUT (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -509,10 +528,11 @@
 					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 4: /* undefined */
 				return(MAJOR_0C_EXCP);
 		} /* end of switch subop */
-
+		BUG();
 	case 2: /* class 2 */
 		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
 		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);
@@ -590,6 +610,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 1: /* FTEST */
 				switch (fmt) {
 				    case 0:
@@ -609,8 +630,10 @@
 				    case 3:
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 		    } /* end of switch subop */
 		} /* end of else for PA1.0 & PA1.1 */
+		BUG();
 	case 3: /* class 3 */
 		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);
 		if (r2 == 0)
@@ -633,6 +656,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 1: /* FSUB */
 				switch (fmt) {
 				    case 0:
@@ -645,6 +669,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 2: /* FMPY */
 				switch (fmt) {
 				    case 0:
@@ -657,6 +682,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 3: /* FDIV */
 				switch (fmt) {
 				    case 0:
@@ -669,6 +695,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 			case 4: /* FREM */
 				switch (fmt) {
 				    case 0:
@@ -681,6 +708,7 @@
 				    case 3: /* quad not implemented */
 					return(MAJOR_0C_EXCP);
 				}
+				BUG();
 		} /* end of class 3 switch */
 	} /* end of switch(class) */
 
@@ -736,10 +764,12 @@
 					return(MAJOR_0E_EXCP);
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					fpregs[t] = fpregs[r1];
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 3: /* FABS */
 				switch (fmt) {
 				    case 2:
@@ -747,10 +777,12 @@
 					return(MAJOR_0E_EXCP);
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					fpregs[t] = fpregs[r1] & 0x7fffffff;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 6: /* FNEG */
 				switch (fmt) {
 				    case 2:
@@ -758,10 +790,12 @@
 					return(MAJOR_0E_EXCP);
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					fpregs[t] = fpregs[r1] ^ 0x80000000;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 7: /* FNEGABS */
 				switch (fmt) {
 				    case 2:
@@ -769,10 +803,12 @@
 					return(MAJOR_0E_EXCP);
 				    case 1: /* double */
 					fpregs[t+1] = fpregs[r1+1];
+					fallthrough;
 				    case 0: /* single */
 					fpregs[t] = fpregs[r1] | 0x80000000;
 					return(NOEXCEPTION);
 				}
+				BUG();
 			case 4: /* FSQRT */
 				switch (fmt) {
 				    case 0:
@@ -785,6 +821,7 @@
 				    case 3:
 					return(MAJOR_0E_EXCP);
 				}
+				BUG();
 			case 5: /* FRMD */
 				switch (fmt) {
 				    case 0:
@@ -798,7 +835,7 @@
 					return(MAJOR_0E_EXCP);
 				}
 		} /* end of switch (subop */
-	
+		BUG();
 	case 1: /* class 1 */
 		df = extru(ir,fpdfpos,2); /* get dest format */
 		/*
@@ -826,6 +863,7 @@
 				    case 3: /* dbl/dbl */
 					return(MAJOR_0E_EXCP);
 				}
+				BUG();
 			case 1: /* FCNVXF */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -841,6 +879,7 @@
 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 2: /* FCNVFX */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -856,6 +895,7 @@
 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 3: /* FCNVFXT */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -871,6 +911,7 @@
 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 5: /* FCNVUF (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -886,6 +927,7 @@
 					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 6: /* FCNVFU (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -901,6 +943,7 @@
 					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 7: /* FCNVFUT (PA2.0 only) */
 				switch(fmt) {
 				    case 0: /* sgl/sgl */
@@ -916,9 +959,11 @@
 					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
 						&fpregs[t],status));
 				}
+				BUG();
 			case 4: /* undefined */
 				return(MAJOR_0C_EXCP);
 		} /* end of switch subop */
+		BUG();
 	case 2: /* class 2 */
 		/*
 		 * Be careful out there.
@@ -994,6 +1039,7 @@
 				}
 		    } /* end of switch subop */
 		} /* end of else for PA1.0 & PA1.1 */
+		BUG();
 	case 3: /* class 3 */
 		/*
 		 * Be careful out there.
@@ -1026,6 +1072,7 @@
 					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
 						&fpregs[t],status));
 				}
+				BUG();
 			case 1: /* FSUB */
 				switch (fmt) {
 				    case 0:
@@ -1035,6 +1082,7 @@
 					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
 						&fpregs[t],status));
 				}
+				BUG();
 			case 2: /* FMPY or XMPYU */
 				/*
 				 * check for integer multiply (x bit set)
@@ -1071,6 +1119,7 @@
 					       &fpregs[r2],&fpregs[t],status));
 				    }
 				}
+				BUG();
 			case 3: /* FDIV */
 				switch (fmt) {
 				    case 0:
@@ -1080,6 +1129,7 @@
 					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
 						&fpregs[t],status));
 				}
+				BUG();
 			case 4: /* FREM */
 				switch (fmt) {
 				    case 0:
--- linux-ein-5.4.0.orig/arch/parisc/mm/fixmap.c
+++ linux-ein-5.4.0/arch/parisc/mm/fixmap.c
@@ -18,12 +18,9 @@
 	pte_t *pte;
 
 	if (pmd_none(*pmd))
-		pmd = pmd_alloc(NULL, pgd, vaddr);
-
-	pte = pte_offset_kernel(pmd, vaddr);
-	if (pte_none(*pte))
 		pte = pte_alloc_kernel(pmd, vaddr);
 
+	pte = pte_offset_kernel(pmd, vaddr);
 	set_pte_at(&init_mm, vaddr, pte, __mk_pte(phys, PAGE_KERNEL_RWX));
 	flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE);
 }
--- linux-ein-5.4.0.orig/arch/parisc/mm/init.c
+++ linux-ein-5.4.0/arch/parisc/mm/init.c
@@ -347,9 +347,9 @@
 
 static bool kernel_set_to_readonly;
 
-static void __init map_pages(unsigned long start_vaddr,
-			     unsigned long start_paddr, unsigned long size,
-			     pgprot_t pgprot, int force)
+static void __ref map_pages(unsigned long start_vaddr,
+			    unsigned long start_paddr, unsigned long size,
+			    pgprot_t pgprot, int force)
 {
 	pgd_t *pg_dir;
 	pmd_t *pmd;
@@ -485,7 +485,7 @@
 	flush_tlb_all();
 }
 
-void __ref free_initmem(void)
+void free_initmem(void)
 {
 	unsigned long init_begin = (unsigned long)__init_begin;
 	unsigned long init_end = (unsigned long)__init_end;
@@ -499,7 +499,6 @@
 	/* The init text pages are marked R-X.  We have to
 	 * flush the icache and mark them RW-
 	 *
-	 * This is tricky, because map_pages is in the init section.
 	 * Do a dummy remap of the data section first (the data
 	 * section is already PAGE_KERNEL) to pull in the TLB entries
 	 * for map_kernel */
@@ -588,7 +587,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);
 	memblock_free_all();
 
 #ifdef CONFIG_PA11
@@ -892,9 +891,9 @@
 {
 	int do_recycle;
 
-	__inc_irq_stat(irq_tlb_count);
 	do_recycle = 0;
 	spin_lock(&sid_lock);
+	__inc_irq_stat(irq_tlb_count);
 	if (dirty_space_ids > RECYCLE_THRESHOLD) {
 	    BUG_ON(recycle_inuse);  /* FIXME: Use a semaphore/wait queue here */
 	    get_dirty_sids(&recycle_ndirty,recycle_dirty_array);
@@ -913,8 +912,8 @@
 #else
 void flush_tlb_all(void)
 {
-	__inc_irq_stat(irq_tlb_count);
 	spin_lock(&sid_lock);
+	__inc_irq_stat(irq_tlb_count);
 	flush_tlb_all_local(NULL);
 	recycle_sids();
 	spin_unlock(&sid_lock);
--- linux-ein-5.4.0.orig/arch/powerpc/Kconfig
+++ linux-ein-5.4.0/arch/powerpc/Kconfig
@@ -133,7 +133,7 @@
 	select ARCH_HAS_PTE_SPECIAL
 	select ARCH_HAS_MEMBARRIER_CALLBACKS
 	select ARCH_HAS_SCALED_CPUTIME		if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
-	select ARCH_HAS_STRICT_KERNEL_RWX	if ((PPC_BOOK3S_64 || PPC32) && !RELOCATABLE && !HIBERNATION)
+	select ARCH_HAS_STRICT_KERNEL_RWX	if (PPC32 && !HIBERNATION)
 	select ARCH_HAS_TICK_BROADCAST		if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_HAS_UACCESS_FLUSHCACHE
 	select ARCH_HAS_UACCESS_MCSAFE		if PPC64
@@ -147,6 +147,7 @@
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF		if PPC64
 	select ARCH_WANT_IPC_PARSE_VERSION
+	select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
 	select ARCH_WEAK_RELEASE_ACQUIRE
 	select BINFMT_ELF
 	select BUILDTIME_EXTABLE_SORT
@@ -171,7 +172,7 @@
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_HUGE_VMAP		if PPC_BOOK3S_64 && PPC_RADIX_MMU
 	select HAVE_ARCH_JUMP_LABEL
-	select HAVE_ARCH_KASAN			if PPC32
+	select HAVE_ARCH_KASAN			if PPC32 && PPC_PAGE_SHIFT <= 14
 	select HAVE_ARCH_KGDB
 	select HAVE_ARCH_MMAP_RND_BITS
 	select HAVE_ARCH_MMAP_RND_COMPAT_BITS	if COMPAT
@@ -213,7 +214,7 @@
 	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_MOD_ARCH_SPECIFIC
 	select HAVE_NMI				if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
-	select HAVE_HARDLOCKUP_DETECTOR_ARCH	if (PPC64 && PPC_BOOK3S)
+	select HAVE_HARDLOCKUP_DETECTOR_ARCH	if PPC64 && PPC_BOOK3S && SMP
 	select HAVE_OPROFILE
 	select HAVE_OPTPROBES			if PPC64
 	select HAVE_PERF_EVENTS
@@ -221,8 +222,7 @@
 	select HAVE_HARDLOCKUP_DETECTOR_PERF	if PERF_EVENTS && HAVE_PERF_EVENTS_NMI && !HAVE_HARDLOCKUP_DETECTOR_ARCH
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
-	select HAVE_RCU_TABLE_FREE		if SMP
-	select HAVE_RCU_TABLE_NO_INVALIDATE	if HAVE_RCU_TABLE_FREE
+	select HAVE_RCU_TABLE_FREE
 	select HAVE_MMU_GATHER_PAGE_SIZE
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RELIABLE_STACKTRACE		if PPC_BOOK3S_64 && CPU_LITTLE_ENDIAN
@@ -237,6 +237,7 @@
 	select NEED_DMA_MAP_STATE		if PPC64 || NOT_COHERENT_CACHE
 	select NEED_SG_DMA_LENGTH
 	select OF
+	select OF_DMA_DEFAULT_COHERENT		if !NOT_COHERENT_CACHE
 	select OF_EARLY_FLATTREE
 	select OLD_SIGACTION			if PPC32
 	select OLD_SIGSUSPEND
@@ -722,7 +723,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.
 
@@ -747,6 +748,7 @@
 	range 13 15
 	default "15" if PPC_256K_PAGES
 	default "14" if PPC64
+	default "14" if KASAN
 	default "13"
 	help
 	  Used to define the stack size. The default is almost always what you
@@ -934,6 +936,28 @@
 
 	  If unsure, say y.
 
+config PPC_SECURE_BOOT
+	prompt "Enable secure boot support"
+	bool
+	depends on PPC_POWERNV
+	depends on IMA_ARCH_POLICY
+	help
+	  Systems with firmware secure boot enabled need to define security
+	  policies to extend secure boot to the OS. This config allows a user
+	  to enable OS secure boot on systems that have firmware support for
+	  it. If in doubt say N.
+
+config PPC_SECVAR_SYSFS
+	bool "Enable sysfs interface for POWER secure variables"
+	default y
+	depends on PPC_SECURE_BOOT
+	depends on SYSFS
+	help
+	  POWER secure variables are managed and controlled by firmware.
+	  These variables are exposed to userspace via sysfs to enable
+	  read/write operations on these variables. Say Y if you have
+	  secure boot enabled and want to expose variables to userspace.
+
 endmenu
 
 config ISA_DMA_API
@@ -1022,6 +1046,19 @@
 	  Include support for RapidIO controller on Freescale embedded
 	  processors (MPC8548, MPC8641, etc).
 
+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 NONSTATIC_KERNEL
--- linux-ein-5.4.0.orig/arch/powerpc/Kconfig.debug
+++ linux-ein-5.4.0/arch/powerpc/Kconfig.debug
@@ -234,7 +234,7 @@
 
 config PPC_EARLY_DEBUG_CPM
 	bool "Early serial debugging for Freescale CPM-based serial ports"
-	depends on SERIAL_CPM
+	depends on SERIAL_CPM=y
 	help
 	  Select this to enable early debugging for Freescale chips
 	  using a CPM-based serial port.  This assumes that the bootwrapper
@@ -352,6 +352,7 @@
 config FAIL_IOMMU
 	bool "Fault-injection capability for IOMMU"
 	depends on FAULT_INJECTION
+	depends on PCI || IBMVIO
 	help
 	  Provide fault-injection capability for IOMMU. Each device can
 	  be selectively enabled via the fail_iommu property.
@@ -371,7 +372,7 @@
 
 config PPC_DEBUG_WX
 	bool "Warn on W+X mappings at boot"
-	depends on PPC_PTDUMP
+	depends on PPC_PTDUMP && STRICT_KERNEL_RWX
 	help
 	  Generate a warning if any W+X mappings are found at boot.
 
--- linux-ein-5.4.0.orig/arch/powerpc/Makefile
+++ linux-ein-5.4.0/arch/powerpc/Makefile
@@ -17,23 +17,6 @@
 # Set default 32 bits cross compilers for vdso and boot wrapper
 CROSS32_COMPILE ?=
 
-ifeq ($(HAS_BIARCH),y)
-ifeq ($(CROSS32_COMPILE),)
-ifdef CONFIG_PPC32
-# These options will be overridden by any -mcpu option that the CPU
-# or platform code sets later on the command line, but they are needed
-# to set a sane 32-bit cpu target for the 64-bit cross compiler which
-# may default to the wrong ISA.
-KBUILD_CFLAGS		+= -mcpu=powerpc
-KBUILD_AFLAGS		+= -mcpu=powerpc
-endif
-endif
-endif
-
-ifdef CONFIG_PPC_BOOK3S_32
-KBUILD_CFLAGS		+= -mcpu=powerpc
-endif
-
 # If we're on a ppc/ppc64/ppc64le machine use that defconfig, otherwise just use
 # ppc64_defconfig because we have nothing better to go on.
 uname := $(shell uname -m)
@@ -91,11 +74,13 @@
 endif
 
 ifdef CONFIG_PPC64
+ifndef CONFIG_CC_IS_CLANG
 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
+endif
 
 ifndef CONFIG_CC_IS_CLANG
   cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -mno-strict-align
@@ -108,7 +93,7 @@
 
 ifeq ($(HAS_BIARCH),y)
 KBUILD_CFLAGS	+= -m$(BITS)
-KBUILD_AFLAGS	+= -m$(BITS) -Wl,-a$(BITS)
+KBUILD_AFLAGS	+= -m$(BITS)
 KBUILD_LDFLAGS	+= -m elf$(BITS)$(LDEMULATION)
 endif
 
@@ -141,6 +126,7 @@
 endif
 
 CFLAGS-$(CONFIG_PPC64)	:= $(call cc-option,-mtraceback=no)
+ifndef CONFIG_CC_IS_CLANG
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc))
 AFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv2)
@@ -149,6 +135,7 @@
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mcall-aixdesc)
 AFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mabi=elfv1)
 endif
+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)
 
@@ -168,9 +155,9 @@
 CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power9,-mtune=power8)
 else
 CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,$(call cc-option,-mtune=power5))
-CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mcpu=power5,-mcpu=power4)
+CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=power4
 endif
-else
+else ifdef CONFIG_PPC_BOOK3E_64
 CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64
 endif
 
@@ -188,6 +175,7 @@
 endif
 
 CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU))
+AFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU))
 
 # Altivec option not allowed with e500mc64 in GCC.
 ifdef CONFIG_ALTIVEC
@@ -198,14 +186,6 @@
 CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
 CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
 
-ifdef CONFIG_PPC32
-ifdef CONFIG_PPC_E500MC
-CFLAGS-y += $(call cc-option,-mcpu=e500mc,-mcpu=powerpc)
-else
-CFLAGS-$(CONFIG_E500) += $(call cc-option,-mcpu=8540 -msoft-float,-mcpu=powerpc)
-endif
-endif
-
 asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1)
 
 KBUILD_CPPFLAGS	+= -I $(srctree)/arch/$(ARCH) $(asinstr)
@@ -246,7 +226,6 @@
 
 cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
 cpu-as-$(CONFIG_ALTIVEC)	+= $(call as-option,-Wa$(comma)-maltivec)
-cpu-as-$(CONFIG_E200)		+= -Wa,-me200
 cpu-as-$(CONFIG_E500)		+= -Wa,-me500
 
 # When using '-many -mpower4' gas will first try and find a matching power4
@@ -281,7 +260,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)
@@ -446,3 +425,11 @@
 		echo -n '*** Please use a different binutils version.' ; \
 		false ; \
 	fi
+	@if test "x${CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT}" = "xy" -a \
+		"x${CONFIG_LD_IS_BFD}" = "xy" -a \
+		"${CONFIG_LD_VERSION}" = "23700" ; then \
+		echo -n '*** binutils 2.37 drops unused section symbols, which recordmcount ' ; \
+		echo 'is unable to handle.' ; \
+		echo '*** Please use a different binutils version.' ; \
+		false ; \
+	fi
--- linux-ein-5.4.0.orig/arch/powerpc/Makefile.postlink
+++ linux-ein-5.4.0/arch/powerpc/Makefile.postlink
@@ -17,11 +17,11 @@
 quiet_cmd_relocs_check = CHKREL  $@
 ifdef CONFIG_PPC_BOOK3S_64
       cmd_relocs_check =						\
-	$(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$@" ; \
+	$(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@" ; \
 	$(BASH) $(srctree)/arch/powerpc/tools/unrel_branch_check.sh "$(OBJDUMP)" "$@"
 else
       cmd_relocs_check =						\
-	$(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$@"
+	$(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@"
 endif
 
 # `@true` prevents complaint when there is nothing to be done
--- linux-ein-5.4.0.orig/arch/powerpc/boot/4xx.c
+++ linux-ein-5.4.0/arch/powerpc/boot/4xx.c
@@ -228,7 +228,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-ein-5.4.0.orig/arch/powerpc/boot/Makefile
+++ linux-ein-5.4.0/arch/powerpc/boot/Makefile
@@ -30,6 +30,7 @@
 
 BOOTCFLAGS    := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		 -fno-strict-aliasing -O2 -msoft-float -mno-altivec -mno-vsx \
+		 $(call cc-option,-mno-spe) $(call cc-option,-mspe=no) \
 		 -pipe -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \
 		 $(LINUXINCLUDE)
 
@@ -119,7 +120,7 @@
 		elf_util.c $(zlib-y) devtree.c stdlib.c \
 		oflib.c ofconsole.c cuboot.c
 
-src-wlib-$(CONFIG_PPC_MPC52XX) += mpc52xx-psc.c
+src-wlib-$(CONFIG_PPC_MPC52xx) += mpc52xx-psc.c
 src-wlib-$(CONFIG_PPC64_BOOT_WRAPPER) += opal-calls.S opal.c
 ifndef CONFIG_PPC64_BOOT_WRAPPER
 src-wlib-y += crtsavres.S
--- linux-ein-5.4.0.orig/arch/powerpc/boot/crt0.S
+++ linux-ein-5.4.0/arch/powerpc/boot/crt0.S
@@ -44,9 +44,6 @@
 p_pstack:	.long	_platform_stack_top
 #endif
 
-	.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
--- linux-ein-5.4.0.orig/arch/powerpc/boot/devtree.c
+++ linux-ein-5.4.0/arch/powerpc/boot/devtree.c
@@ -13,6 +13,7 @@
 #include "string.h"
 #include "stdio.h"
 #include "ops.h"
+#include "of.h"
 
 void dt_fixup_memory(u64 start, u64 size)
 {
@@ -23,21 +24,25 @@
 	root = finddevice("/");
 	if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
 		naddr = 2;
+	else
+		naddr = be32_to_cpu(naddr);
 	if (naddr < 1 || naddr > 2)
 		fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
 
 	if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
 		nsize = 1;
+	else
+		nsize = be32_to_cpu(nsize);
 	if (nsize < 1 || nsize > 2)
 		fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
 
 	i = 0;
 	if (naddr == 2)
-		memreg[i++] = start >> 32;
-	memreg[i++] = start & 0xffffffff;
+		memreg[i++] = cpu_to_be32(start >> 32);
+	memreg[i++] = cpu_to_be32(start & 0xffffffff);
 	if (nsize == 2)
-		memreg[i++] = size >> 32;
-	memreg[i++] = size & 0xffffffff;
+		memreg[i++] = cpu_to_be32(size >> 32);
+	memreg[i++] = cpu_to_be32(size & 0xffffffff);
 
 	memory = finddevice("/memory");
 	if (! memory) {
@@ -45,9 +50,9 @@
 		setprop_str(memory, "device_type", "memory");
 	}
 
-	printf("Memory <- <0x%x", memreg[0]);
+	printf("Memory <- <0x%x", be32_to_cpu(memreg[0]));
 	for (i = 1; i < (naddr + nsize); i++)
-		printf(" 0x%x", memreg[i]);
+		printf(" 0x%x", be32_to_cpu(memreg[i]));
 	printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
 
 	setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
@@ -65,10 +70,10 @@
 		printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
 
 	while ((devp = find_node_by_devtype(devp, "cpu"))) {
-		setprop_val(devp, "clock-frequency", cpu);
-		setprop_val(devp, "timebase-frequency", tb);
+		setprop_val(devp, "clock-frequency", cpu_to_be32(cpu));
+		setprop_val(devp, "timebase-frequency", cpu_to_be32(tb));
 		if (bus > 0)
-			setprop_val(devp, "bus-frequency", bus);
+			setprop_val(devp, "bus-frequency", cpu_to_be32(bus));
 	}
 
 	timebase_period_ns = 1000000000 / tb;
@@ -80,7 +85,7 @@
 
 	if (devp) {
 		printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
-		setprop_val(devp, "clock-frequency", freq);
+		setprop_val(devp, "clock-frequency", cpu_to_be32(freq));
 	}
 }
 
@@ -133,8 +138,12 @@
 {
 	if (getprop(node, "#address-cells", naddr, 4) != 4)
 		*naddr = 2;
+	else
+		*naddr = be32_to_cpu(*naddr);
 	if (getprop(node, "#size-cells", nsize, 4) != 4)
 		*nsize = 1;
+	else
+		*nsize = be32_to_cpu(*nsize);
 }
 
 static void copy_val(u32 *dest, u32 *src, int naddr)
@@ -163,9 +172,9 @@
 	int i, carry = 0;
 
 	for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
-		u64 tmp = (u64)reg[i] + add[i] + carry;
+		u64 tmp = (u64)be32_to_cpu(reg[i]) + be32_to_cpu(add[i]) + carry;
 		carry = tmp >> 32;
-		reg[i] = (u32)tmp;
+		reg[i] = cpu_to_be32((u32)tmp);
 	}
 
 	return !carry;
@@ -180,18 +189,18 @@
 	u32 end;
 
 	for (i = 0; i < MAX_ADDR_CELLS; i++) {
-		if (reg[i] < range[i])
+		if (be32_to_cpu(reg[i]) < be32_to_cpu(range[i]))
 			return 0;
-		if (reg[i] > range[i])
+		if (be32_to_cpu(reg[i]) > be32_to_cpu(range[i]))
 			break;
 	}
 
 	for (i = 0; i < MAX_ADDR_CELLS; i++) {
-		end = range[i] + rangesize[i];
+		end = be32_to_cpu(range[i]) + be32_to_cpu(rangesize[i]);
 
-		if (reg[i] < end)
+		if (be32_to_cpu(reg[i]) < end)
 			break;
-		if (reg[i] > end)
+		if (be32_to_cpu(reg[i]) > end)
 			return 0;
 	}
 
@@ -240,7 +249,6 @@
 		return 0;
 
 	dt_get_reg_format(parent, &naddr, &nsize);
-
 	if (nsize > 2)
 		return 0;
 
@@ -252,10 +260,10 @@
 
 	copy_val(last_addr, prop_buf + offset, naddr);
 
-	ret_size = prop_buf[offset + naddr];
+	ret_size = be32_to_cpu(prop_buf[offset + naddr]);
 	if (nsize == 2) {
 		ret_size <<= 32;
-		ret_size |= prop_buf[offset + naddr + 1];
+		ret_size |= be32_to_cpu(prop_buf[offset + naddr + 1]);
 	}
 
 	for (;;) {
@@ -278,7 +286,6 @@
 
 		offset = find_range(last_addr, prop_buf, prev_naddr,
 		                    naddr, prev_nsize, buflen / 4);
-
 		if (offset < 0)
 			return 0;
 
@@ -296,8 +303,7 @@
 	if (naddr > 2)
 		return 0;
 
-	ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
-
+	ret_addr = ((u64)be32_to_cpu(last_addr[2]) << 32) | be32_to_cpu(last_addr[3]);
 	if (sizeof(void *) == 4 &&
 	    (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
 	     ret_addr + ret_size > 0x100000000ULL))
@@ -350,11 +356,14 @@
 int dt_get_virtual_reg(void *node, void **addr, int nres)
 {
 	unsigned long xaddr;
-	int n;
+	int n, i;
 
 	n = getprop(node, "virtual-reg", addr, nres * 4);
-	if (n > 0)
+	if (n > 0) {
+		for (i = 0; i < n/4; i ++)
+			((u32 *)addr)[i] = be32_to_cpu(((u32 *)addr)[i]);
 		return n / 4;
+	}
 
 	for (n = 0; n < nres; n++) {
 		if (!dt_xlate_reg(node, n, &xaddr, NULL))
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/charon.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/charon.dts
@@ -35,7 +35,7 @@
 		};
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x00000000 0x08000000>;	// 128MB
 	};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/digsy_mtc.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/digsy_mtc.dts
@@ -16,7 +16,7 @@
 	model = "intercontrol,digsy-mtc";
 	compatible = "intercontrol,digsy-mtc";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x02000000>;	// 32MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/e500v1_power_isa.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/e500v1_power_isa.dtsi
@@ -0,0 +1,51 @@
+/*
+ * e500v1 Power ISA Device Tree Source (include)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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.
+ */
+
+/ {
+	cpus {
+		power-isa-version = "2.03";
+		power-isa-b;		// Base
+		power-isa-e;		// Embedded
+		power-isa-atb;		// Alternate Time Base
+		power-isa-cs;		// Cache Specification
+		power-isa-e.le;		// Embedded.Little-Endian
+		power-isa-e.pm;		// Embedded.Performance Monitor
+		power-isa-ecl;		// Embedded Cache Locking
+		power-isa-mmc;		// Memory Coherence
+		power-isa-sp;		// Signal Processing Engine
+		power-isa-sp.fs;	// SPE.Embedded Float Scalar Single
+		power-isa-sp.fv;	// SPE.Embedded Float Vector
+		mmu-type = "power-embedded";
+	};
+};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/mpc8540ads.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/mpc8540ads.dts
@@ -7,7 +7,7 @@
 
 /dts-v1/;
 
-/include/ "e500v2_power_isa.dtsi"
+/include/ "e500v1_power_isa.dtsi"
 
 / {
 	model = "MPC8540ADS";
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/mpc8541cds.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/mpc8541cds.dts
@@ -7,7 +7,7 @@
 
 /dts-v1/;
 
-/include/ "e500v2_power_isa.dtsi"
+/include/ "e500v1_power_isa.dtsi"
 
 / {
 	model = "MPC8541CDS";
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/mpc8555cds.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/mpc8555cds.dts
@@ -7,7 +7,7 @@
 
 /dts-v1/;
 
-/include/ "e500v2_power_isa.dtsi"
+/include/ "e500v1_power_isa.dtsi"
 
 / {
 	model = "MPC8555CDS";
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/mpc8560ads.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/mpc8560ads.dts
@@ -7,7 +7,7 @@
 
 /dts-v1/;
 
-/include/ "e500v2_power_isa.dtsi"
+/include/ "e500v1_power_isa.dtsi"
 
 / {
 	model = "MPC8560ADS";
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -122,7 +122,15 @@
 	};
 
 /include/ "pq3-i2c-0.dtsi"
+	i2c@3000 {
+		fsl,i2c-erratum-a004447;
+	};
+
 /include/ "pq3-i2c-1.dtsi"
+	i2c@3100 {
+		fsl,i2c-erratum-a004447;
+	};
+
 /include/ "pq3-duart-0.dtsi"
 /include/ "pq3-espi-0.dtsi"
 	spi0: spi@7000 {
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -371,7 +371,23 @@
 	};
 
 /include/ "qoriq-i2c-0.dtsi"
+	i2c@118000 {
+		fsl,i2c-erratum-a004447;
+	};
+
+	i2c@118100 {
+		fsl,i2c-erratum-a004447;
+	};
+
 /include/ "qoriq-i2c-1.dtsi"
+	i2c@119000 {
+		fsl,i2c-erratum-a004447;
+	};
+
+	i2c@119100 {
+		fsl,i2c-erratum-a004447;
+	};
+
 /include/ "qoriq-duart-0.dtsi"
 /include/ "qoriq-duart-1.dtsi"
 /include/ "qoriq-gpio-0.dtsi"
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi
@@ -63,6 +63,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy0: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi
@@ -60,6 +60,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xf1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy6: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi
@@ -63,6 +63,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy1: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi
@@ -60,6 +60,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xf3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy7: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
+/*
+ * QorIQ FMan v3 10g port #2 device tree stub [ controller @ offset 0x400000 ]
+ *
+ * Copyright 2022 Sean Anderson <sean.anderson@seco.com>
+ * Copyright 2012 - 2015 Freescale Semiconductor Inc.
+ */
+
+fman@400000 {
+	fman0_rx_0x08: port@88000 {
+		cell-index = <0x8>;
+		compatible = "fsl,fman-v3-port-rx";
+		reg = <0x88000 0x1000>;
+		fsl,fman-10g-port;
+	};
+
+	fman0_tx_0x28: port@a8000 {
+		cell-index = <0x28>;
+		compatible = "fsl,fman-v3-port-tx";
+		reg = <0xa8000 0x1000>;
+		fsl,fman-10g-port;
+	};
+
+	ethernet@e0000 {
+		cell-index = <0>;
+		compatible = "fsl,fman-memac";
+		reg = <0xe0000 0x1000>;
+		fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>;
+		ptp-timer = <&ptp_timer0>;
+		pcsphy-handle = <&pcsphy0>;
+	};
+
+	mdio@e1000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
+		reg = <0xe1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
+
+		pcsphy0: ethernet-phy@0 {
+			reg = <0x0>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
+/*
+ * QorIQ FMan v3 10g port #3 device tree stub [ controller @ offset 0x400000 ]
+ *
+ * Copyright 2022 Sean Anderson <sean.anderson@seco.com>
+ * Copyright 2012 - 2015 Freescale Semiconductor Inc.
+ */
+
+fman@400000 {
+	fman0_rx_0x09: port@89000 {
+		cell-index = <0x9>;
+		compatible = "fsl,fman-v3-port-rx";
+		reg = <0x89000 0x1000>;
+		fsl,fman-10g-port;
+	};
+
+	fman0_tx_0x29: port@a9000 {
+		cell-index = <0x29>;
+		compatible = "fsl,fman-v3-port-tx";
+		reg = <0xa9000 0x1000>;
+		fsl,fman-10g-port;
+	};
+
+	ethernet@e2000 {
+		cell-index = <1>;
+		compatible = "fsl,fman-memac";
+		reg = <0xe2000 0x1000>;
+		fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>;
+		ptp-timer = <&ptp_timer0>;
+		pcsphy-handle = <&pcsphy1>;
+	};
+
+	mdio@e3000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
+		reg = <0xe3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
+
+		pcsphy1: ethernet-phy@0 {
+			reg = <0x0>;
+		};
+	};
+};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy0: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy1: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe5000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy2: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe7000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy3: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe9000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy4: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xeb000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy5: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi
@@ -60,6 +60,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xf1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy14: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi
@@ -60,6 +60,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xf3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy15: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe1000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy8: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe3000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy9: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe5000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy10: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe7000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy11: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xe9000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy12: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi
@@ -59,6 +59,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xeb000 0x1000>;
+		fsl,erratum-a011043; /* must ignore read errors */
 
 		pcsphy13: ethernet-phy@0 {
 			reg = <0x0>;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi
@@ -79,6 +79,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfc000 0x1000>;
+		fsl,erratum-a009885;
 	};
 
 	xmdio0: mdio@fd000 {
@@ -86,6 +87,7 @@
 		#size-cells = <0>;
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfd000 0x1000>;
+		fsl,erratum-a009885;
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/t1023rdb.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/t1023rdb.dts
@@ -154,7 +154,7 @@
 
 			fm1mac3: ethernet@e4000 {
 				phy-handle = <&sgmii_aqr_phy3>;
-				phy-connection-type = "sgmii-2500";
+				phy-connection-type = "2500base-x";
 				sleep = <&rcpm 0x20000000>;
 			};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi
@@ -139,12 +139,12 @@
 		fman@400000 {
 			ethernet@e6000 {
 				phy-handle = <&phy_rgmii_0>;
-				phy-connection-type = "rgmii";
+				phy-connection-type = "rgmii-id";
 			};
 
 			ethernet@e8000 {
 				phy-handle = <&phy_rgmii_1>;
-				phy-connection-type = "rgmii";
+				phy-connection-type = "rgmii-id";
 			};
 
 			mdio0: mdio@fc000 {
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
@@ -609,8 +609,8 @@
 /include/ "qoriq-bman1.dtsi"
 
 /include/ "qoriq-fman3-0.dtsi"
-/include/ "qoriq-fman3-0-1g-0.dtsi"
-/include/ "qoriq-fman3-0-1g-1.dtsi"
+/include/ "qoriq-fman3-0-10g-2.dtsi"
+/include/ "qoriq-fman3-0-10g-3.dtsi"
 /include/ "qoriq-fman3-0-1g-2.dtsi"
 /include/ "qoriq-fman3-0-1g-3.dtsi"
 /include/ "qoriq-fman3-0-1g-4.dtsi"
@@ -659,3 +659,19 @@
 		interrupts = <16 2 1 9>;
 	};
 };
+
+&fman0_rx_0x08 {
+	/delete-property/ fsl,fman-10g-port;
+};
+
+&fman0_tx_0x28 {
+	/delete-property/ fsl,fman-10g-port;
+};
+
+&fman0_rx_0x09 {
+	/delete-property/ fsl,fman-10g-port;
+};
+
+&fman0_tx_0x29 {
+	/delete-property/ fsl,fman-10g-port;
+};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/lite5200.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/lite5200.dts
@@ -32,7 +32,7 @@
 		};
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x00000000 0x04000000>;	// 64MB
 	};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/lite5200b.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/lite5200b.dts
@@ -31,7 +31,7 @@
 		led4 { gpios = <&gpio_simple 2 1>; };
 	};
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x10000000>;	// 256MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/media5200.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/media5200.dts
@@ -32,7 +32,7 @@
 		};
 	};
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x08000000>;	// 128MB RAM
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/mpc5200b.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/mpc5200b.dtsi
@@ -33,7 +33,7 @@
 		};
 	};
 
-	memory: memory {
+	memory: memory@0 {
 		device_type = "memory";
 		reg = <0x00000000 0x04000000>;	// 64MB
 	};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/o2d.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/o2d.dts
@@ -12,7 +12,7 @@
 	model = "ifm,o2d";
 	compatible = "ifm,o2d";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x08000000>;  // 128MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/o2d.dtsi
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/o2d.dtsi
@@ -19,7 +19,7 @@
 	model = "ifm,o2d";
 	compatible = "ifm,o2d";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x04000000>;	// 64MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/o2dnt2.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/o2dnt2.dts
@@ -12,7 +12,7 @@
 	model = "ifm,o2dnt2";
 	compatible = "ifm,o2d";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x08000000>;  // 128MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/o3dnt.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/o3dnt.dts
@@ -12,7 +12,7 @@
 	model = "ifm,o3dnt";
 	compatible = "ifm,o2d";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x04000000>;  // 64MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/pcm032.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/pcm032.dts
@@ -22,7 +22,7 @@
 	model = "phytec,pcm032";
 	compatible = "phytec,pcm032";
 
-	memory {
+	memory@0 {
 		reg = <0x00000000 0x08000000>;	// 128MB
 	};
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/dts/tqm5200.dts
+++ linux-ein-5.4.0/arch/powerpc/boot/dts/tqm5200.dts
@@ -32,7 +32,7 @@
 		};
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x00000000 0x04000000>;	// 64MB
 	};
--- linux-ein-5.4.0.orig/arch/powerpc/boot/libfdt_env.h
+++ linux-ein-5.4.0/arch/powerpc/boot/libfdt_env.h
@@ -6,6 +6,8 @@
 #include <string.h>
 
 #define INT_MAX			((int)(~0U>>1))
+#define UINT32_MAX		((u32)~0U)
+#define INT32_MAX		((s32)(UINT32_MAX >> 1))
 
 #include "of.h"
 
--- linux-ein-5.4.0.orig/arch/powerpc/boot/ns16550.c
+++ linux-ein-5.4.0/arch/powerpc/boot/ns16550.c
@@ -15,6 +15,7 @@
 #include "stdio.h"
 #include "io.h"
 #include "ops.h"
+#include "of.h"
 
 #define UART_DLL	0	/* Out: Divisor Latch Low */
 #define UART_DLM	1	/* Out: Divisor Latch High */
@@ -58,16 +59,20 @@
 	int n;
 	u32 reg_offset;
 
-	if (dt_get_virtual_reg(devp, (void **)&reg_base, 1) < 1)
+	if (dt_get_virtual_reg(devp, (void **)&reg_base, 1) < 1) {
+		printf("virt reg parse fail...\r\n");
 		return -1;
+	}
 
 	n = getprop(devp, "reg-offset", &reg_offset, sizeof(reg_offset));
 	if (n == sizeof(reg_offset))
-		reg_base += reg_offset;
+		reg_base += be32_to_cpu(reg_offset);
 
 	n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
 	if (n != sizeof(reg_shift))
 		reg_shift = 0;
+	else
+		reg_shift = be32_to_cpu(reg_shift);
 
 	scdp->open = ns16550_open;
 	scdp->putc = ns16550_putc;
--- linux-ein-5.4.0.orig/arch/powerpc/boot/serial.c
+++ linux-ein-5.4.0/arch/powerpc/boot/serial.c
@@ -128,7 +128,7 @@
 	         dt_is_compatible(devp, "fsl,cpm2-smc-uart"))
 		rc = cpm_console_init(devp, &serial_cd);
 #endif
-#ifdef CONFIG_PPC_MPC52XX
+#ifdef CONFIG_PPC_MPC52xx
 	else if (dt_is_compatible(devp, "fsl,mpc5200-psc-uart"))
 		rc = mpc5200_psc_console_init(devp, &serial_cd);
 #endif
--- linux-ein-5.4.0.orig/arch/powerpc/configs/85xx-hw.config
+++ linux-ein-5.4.0/arch/powerpc/configs/85xx-hw.config
@@ -2,7 +2,6 @@
 CONFIG_AT803X_PHY=y
 CONFIG_ATA=y
 CONFIG_BLK_DEV_SD=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BROADCOM_PHY=y
 CONFIG_C293_PCIE=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/amigaone_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/amigaone_defconfig
@@ -47,7 +47,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SYM53C8XX_2=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/chrp32_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/chrp32_defconfig
@@ -45,7 +45,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SYM53C8XX_2=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/g5_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/g5_defconfig
@@ -62,7 +62,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SPI_ATTRS=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/maple_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/maple_defconfig
@@ -41,7 +41,6 @@
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_IPR=y
 CONFIG_ATA=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/mpc885_ads_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/mpc885_ads_defconfig
@@ -39,6 +39,7 @@
 # CONFIG_MTD_CFI_I2 is not set
 CONFIG_MTD_CFI_I4=y
 CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_OF=y
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/pasemi_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/pasemi_defconfig
@@ -60,7 +60,6 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_CHR_DEV_OSST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_CHR_DEV_SCH=y
 CONFIG_SCSI_CONSTANTS=y
@@ -110,7 +109,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-ein-5.4.0.orig/arch/powerpc/configs/pmac32_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/pmac32_defconfig
@@ -119,7 +119,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/powernv_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/powernv_defconfig
@@ -111,7 +111,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/ppc64_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/ppc64_defconfig
@@ -110,7 +110,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/ppc64e_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/ppc64e_defconfig
@@ -60,7 +60,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/ppc6xx_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/ppc6xx_defconfig
@@ -253,8 +253,6 @@
 CONFIG_ATM_BR2684=m
 CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
-CONFIG_DECNET=m
-CONFIG_DECNET_ROUTER=y
 CONFIG_IPX=m
 CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
@@ -372,7 +370,6 @@
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_CHR_DEV_SCH=m
 CONFIG_SCSI_ENCLOSURE=m
@@ -778,7 +775,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-ein-5.4.0.orig/arch/powerpc/configs/pseries_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/pseries_defconfig
@@ -97,7 +97,6 @@
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_FC_ATTRS=y
--- linux-ein-5.4.0.orig/arch/powerpc/configs/skiroot_defconfig
+++ linux-ein-5.4.0/arch/powerpc/configs/skiroot_defconfig
@@ -83,7 +83,6 @@
 # CONFIG_OCXL is not set
 CONFIG_BLK_DEV_SD=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/archrandom.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/archrandom.h
@@ -6,44 +6,35 @@
 
 #include <asm/machdep.h>
 
-static inline int arch_get_random_long(unsigned long *v)
+static inline bool arch_get_random_long(unsigned long *v)
 {
-	return 0;
+	return false;
 }
 
-static inline int arch_get_random_int(unsigned int *v)
+static inline bool arch_get_random_int(unsigned int *v)
 {
-	return 0;
+	return false;
 }
 
-static inline int arch_get_random_seed_long(unsigned long *v)
+static inline bool arch_get_random_seed_long(unsigned long *v)
 {
 	if (ppc_md.get_random_seed)
 		return ppc_md.get_random_seed(v);
 
-	return 0;
+	return false;
 }
-static inline int arch_get_random_seed_int(unsigned int *v)
+
+static inline bool arch_get_random_seed_int(unsigned int *v)
 {
 	unsigned long val;
-	int rc;
+	bool rc;
 
-	rc = arch_get_random_long(&val);
+	rc = arch_get_random_seed_long(&val);
 	if (rc)
 		*v = val;
 
 	return rc;
 }
-
-static inline int arch_has_random(void)
-{
-	return 0;
-}
-
-static inline int arch_has_random_seed(void)
-{
-	return !!ppc_md.get_random_seed;
-}
 #endif /* CONFIG_ARCH_RANDOM */
 
 #ifdef CONFIG_PPC_POWERNV
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/asm-prototypes.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/asm-prototypes.h
@@ -152,9 +152,12 @@
 /* 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 s32 patch__memset_nocache, patch__memcpy_nocache;
 
 extern long flush_count_cache;
+extern long kvm_flush_link_stack;
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/barrier.h
@@ -44,6 +44,8 @@
 #    define SMPWMB      eieio
 #endif
 
+/* clang defines this macro for a builtin, which will not work with runtime patching */
+#undef __lwsync
 #define __lwsync()	__asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
 #define dma_rmb()	__lwsync()
 #define dma_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/bitops.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/bitops.h
@@ -217,15 +217,34 @@
  */
 static __inline__ int fls(unsigned int x)
 {
-	return 32 - __builtin_clz(x);
+	int lz;
+
+	if (__builtin_constant_p(x))
+		return x ? 32 - __builtin_clz(x) : 0;
+	asm("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	return 32 - lz;
 }
 
 #include <asm-generic/bitops/builtin-__fls.h>
 
+/*
+ * 64-bit can do this using one cntlzd (count leading zeroes doubleword)
+ * instruction; for 32-bit we use the generic version, which does two
+ * 32-bit fls calls.
+ */
+#ifdef CONFIG_PPC64
 static __inline__ int fls64(__u64 x)
 {
-	return 64 - __builtin_clzll(x);
+	int lz;
+
+	if (__builtin_constant_p(x))
+		return x ? 64 - __builtin_clzll(x) : 0;
+	asm("cntlzd %0,%1" : "=r" (lz) : "r" (x));
+	return 64 - lz;
 }
+#else
+#include <asm-generic/bitops/fls64.h>
+#endif
 
 #ifdef CONFIG_PPC64
 unsigned int __arch_hweight8(unsigned int w);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/32/kup.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/32/kup.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_POWERPC_BOOK3S_32_KUP_H
 #define _ASM_POWERPC_BOOK3S_32_KUP_H
 
+#include <asm/bug.h>
 #include <asm/book3s/32/mmu-hash.h>
 
 #ifdef __ASSEMBLY__
@@ -75,7 +76,7 @@
 
 .macro kuap_check	current, gpr
 #ifdef CONFIG_PPC_KUAP_DEBUG
-	lwz	\gpr2, KUAP(thread)
+	lwz	\gpr, THREAD + KUAP(\current)
 999:	twnei	\gpr, 0
 	EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
 #endif
@@ -102,11 +103,13 @@
 	isync();	/* Context sync required after mtsrin() */
 }
 
-static inline void allow_user_access(void __user *to, const void __user *from, u32 size)
+static __always_inline void allow_user_access(void __user *to, const void __user *from,
+					      u32 size, unsigned long dir)
 {
 	u32 addr, end;
 
-	if (__builtin_constant_p(to) && to == NULL)
+	BUILD_BUG_ON(!__builtin_constant_p(dir));
+	if (!(dir & KUAP_WRITE))
 		return;
 
 	addr = (__force u32)to;
@@ -119,11 +122,16 @@
 	kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end);	/* Clear Ks */
 }
 
-static inline void prevent_user_access(void __user *to, const void __user *from, u32 size)
+static __always_inline void prevent_user_access(void __user *to, const void __user *from,
+						u32 size, unsigned long dir)
 {
 	u32 addr = (__force u32)to;
 	u32 end = min(addr + size, TASK_SIZE);
 
+	BUILD_BUG_ON(!__builtin_constant_p(dir));
+	if (!(dir & KUAP_WRITE))
+		return;
+
 	if (!addr || addr >= TASK_SIZE || !size)
 		return;
 
@@ -131,12 +139,17 @@
 	kuap_update_sr(mfsrin(addr) | SR_KS, addr, end);	/* set Ks */
 }
 
-static inline bool bad_kuap_fault(struct pt_regs *regs, bool is_write)
+static inline bool
+bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
 {
+	unsigned long begin = regs->kuap & 0xf0000000;
+	unsigned long end = regs->kuap << 28;
+
 	if (!is_write)
 		return false;
 
-	return WARN(!regs->kuap, "Bug: write fault blocked by segment registers !");
+	return WARN(address < begin || address >= end,
+		    "Bug: write fault blocked by segment registers !");
 }
 
 #endif /* CONFIG_PPC_KUAP */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/32/pgalloc.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/32/pgalloc.h
@@ -49,7 +49,6 @@
 
 #define get_hugepd_cache_index(x)  (x)
 
-#ifdef CONFIG_SMP
 static inline void pgtable_free_tlb(struct mmu_gather *tlb,
 				    void *table, int shift)
 {
@@ -66,13 +65,6 @@
 
 	pgtable_free(table, shift);
 }
-#else
-static inline void pgtable_free_tlb(struct mmu_gather *tlb,
-				    void *table, int shift)
-{
-	pgtable_free(table, shift);
-}
-#endif
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
 				  unsigned long address)
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -37,8 +37,10 @@
  */
 #ifdef CONFIG_PTE_64BIT
 #define PTE_RPN_MASK	(~((1ULL << PTE_RPN_SHIFT) - 1))
+#define MAX_POSSIBLE_PHYSMEM_BITS 36
 #else
 #define PTE_RPN_MASK	(~((1UL << PTE_RPN_SHIFT) - 1))
+#define MAX_POSSIBLE_PHYSMEM_BITS 32
 #endif
 
 /*
@@ -555,9 +557,9 @@
 	if (pte_val(*ptep) & _PAGE_HASHPTE)
 		flush_hash_entry(mm, ptep, addr);
 	__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-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/hash-4k.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/hash-4k.h
@@ -13,20 +13,19 @@
  */
 #define MAX_EA_BITS_PER_CONTEXT		46
 
-#define REGION_SHIFT		(MAX_EA_BITS_PER_CONTEXT - 2)
 
 /*
- * Our page table limit us to 64TB. Hence for the kernel mapping,
- * each MAP area is limited to 16 TB.
- * The four map areas are:  linear mapping, vmap, IO and vmemmap
+ * Our page table limit us to 64TB. For 64TB physical memory, we only need 64GB
+ * of vmemmap space. To better support sparse memory layout, we use 61TB
+ * linear map range, 1TB of vmalloc, 1TB of I/O and 1TB of vmememmap.
  */
+#define REGION_SHIFT		(40)
 #define H_KERN_MAP_SIZE		(ASM_CONST(1) << REGION_SHIFT)
 
 /*
- * Define the address range of the kernel non-linear virtual area
- * 16TB
+ * Define the address range of the kernel non-linear virtual area (61TB)
  */
-#define H_KERN_VIRT_START	ASM_CONST(0xc000100000000000)
+#define H_KERN_VIRT_START	ASM_CONST(0xc0003d0000000000)
 
 #ifndef __ASSEMBLY__
 #define H_PTE_TABLE_SIZE	(sizeof(pte_t) << H_PTE_INDEX_SIZE)
@@ -156,6 +155,12 @@
 extern int hash__has_transparent_hugepage(void);
 #endif
 
+static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd)
+{
+	BUG();
+	return pmd;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/hash-64k.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/hash-64k.h
@@ -246,7 +246,7 @@
  */
 static inline int hash__pmd_trans_huge(pmd_t pmd)
 {
-	return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE)) ==
+	return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP)) ==
 		  (_PAGE_PTE | H_PAGE_THP_HUGE));
 }
 
@@ -272,6 +272,12 @@
 				       unsigned long addr, pmd_t *pmdp);
 extern int hash__has_transparent_hugepage(void);
 #endif /*  CONFIG_TRANSPARENT_HUGEPAGE */
+
+static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd)
+{
+	return __pmd(pmd_val(pmd) | (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP));
+}
+
 #endif	/* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/kup-radix.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/kup-radix.h
@@ -11,13 +11,12 @@
 
 #ifdef __ASSEMBLY__
 
-.macro kuap_restore_amr	gpr
 #ifdef CONFIG_PPC_KUAP
+.macro kuap_restore_amr	gpr
 	BEGIN_MMU_FTR_SECTION_NESTED(67)
 	ld	\gpr, STACK_REGS_KUAP(r1)
 	mtspr	SPRN_AMR, \gpr
 	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
-#endif
 .endm
 
 .macro kuap_check_amr gpr1, gpr2
@@ -31,6 +30,7 @@
 	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
 #endif
 .endm
+#endif
 
 .macro kuap_save_amr_and_lock gpr1, gpr2, use_cr, msr_pr_cr
 #ifdef CONFIG_PPC_KUAP
@@ -54,6 +54,10 @@
 
 #else /* !__ASSEMBLY__ */
 
+#include <linux/jump_label.h>
+
+DECLARE_STATIC_KEY_FALSE(uaccess_flush_key);
+
 #ifdef CONFIG_PPC_KUAP
 
 #include <asm/reg.h>
@@ -77,32 +81,39 @@
 	isync();
 }
 
-static inline void allow_user_access(void __user *to, const void __user *from,
-				     unsigned long size)
+static inline bool
+bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+{
+	return WARN(mmu_has_feature(MMU_FTR_RADIX_KUAP) &&
+		    (regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
+		    "Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
+}
+#else /* CONFIG_PPC_KUAP */
+static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr) { }
+static inline void set_kuap(unsigned long value) { }
+#endif /* !CONFIG_PPC_KUAP */
+
+static __always_inline void allow_user_access(void __user *to, const void __user *from,
+					      unsigned long size, unsigned long dir)
 {
 	// This is written so we can resolve to a single case at build time
-	if (__builtin_constant_p(to) && to == NULL)
+	BUILD_BUG_ON(!__builtin_constant_p(dir));
+	if (dir == KUAP_READ)
 		set_kuap(AMR_KUAP_BLOCK_WRITE);
-	else if (__builtin_constant_p(from) && from == NULL)
+	else if (dir == KUAP_WRITE)
 		set_kuap(AMR_KUAP_BLOCK_READ);
 	else
 		set_kuap(0);
 }
 
 static inline void prevent_user_access(void __user *to, const void __user *from,
-				       unsigned long size)
+				       unsigned long size, unsigned long dir)
 {
 	set_kuap(AMR_KUAP_BLOCKED);
+	if (static_branch_unlikely(&uaccess_flush_key))
+		do_uaccess_flush();
 }
 
-static inline bool bad_kuap_fault(struct pt_regs *regs, bool is_write)
-{
-	return WARN(mmu_has_feature(MMU_FTR_RADIX_KUAP) &&
-		    (regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
-		    "Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
-}
-#endif /* CONFIG_PPC_KUAP */
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -600,8 +600,11 @@
  *
  */
 #define MAX_USER_CONTEXT	((ASM_CONST(1) << CONTEXT_BITS) - 2)
+
+// The + 2 accounts for INVALID_REGION and 1 more to avoid overlap with kernel
 #define MIN_USER_CONTEXT	(MAX_KERNEL_CTX_CNT + MAX_VMALLOC_CTX_CNT + \
-				 MAX_IO_CTX_CNT + MAX_VMEMMAP_CTX_CNT)
+				 MAX_IO_CTX_CNT + MAX_VMEMMAP_CTX_CNT + 2)
+
 /*
  * For platforms that support on 65bit VA we limit the context bits
  */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/mmu.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -225,14 +225,14 @@
 
 extern void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base,
 					 phys_addr_t first_memblock_size);
-extern void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
-					 phys_addr_t first_memblock_size);
 static inline void setup_initial_memory_limit(phys_addr_t first_memblock_base,
 					      phys_addr_t first_memblock_size)
 {
-	if (early_radix_enabled())
-		return radix__setup_initial_memory_limit(first_memblock_base,
-						   first_memblock_size);
+	/*
+	 * Hash has more strict restrictions. At this point we don't
+	 * know which translations we will pick. Hence go with hash
+	 * restrictions.
+	 */
 	return hash__setup_initial_memory_limit(first_memblock_base,
 					   first_memblock_size);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/pgalloc.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/pgalloc.h
@@ -19,9 +19,7 @@
 extern pmd_t *pmd_fragment_alloc(struct mm_struct *, unsigned long);
 extern void pmd_fragment_free(unsigned long *);
 extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift);
-#ifdef CONFIG_SMP
 extern void __tlb_remove_table(void *_table);
-#endif
 void pte_frag_destroy(void *pte_frag);
 
 static inline pgd_t *radix__pgd_alloc(struct mm_struct *mm)
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -998,10 +998,25 @@
 #define pud_page_vaddr(pud)	__va(pud_val(pud) & ~PUD_MASKED_BITS)
 #define pgd_page_vaddr(pgd)	__va(pgd_val(pgd) & ~PGD_MASKED_BITS)
 
-#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
-#define pud_index(address) (((address) >> (PUD_SHIFT)) & (PTRS_PER_PUD - 1))
-#define pmd_index(address) (((address) >> (PMD_SHIFT)) & (PTRS_PER_PMD - 1))
-#define pte_index(address) (((address) >> (PAGE_SHIFT)) & (PTRS_PER_PTE - 1))
+static inline unsigned long pgd_index(unsigned long address)
+{
+	return (address >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1);
+}
+
+static inline unsigned long pud_index(unsigned long address)
+{
+	return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
+}
+
+static inline unsigned long pmd_index(unsigned long address)
+{
+	return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+}
+
+static inline unsigned long pte_index(unsigned long address)
+{
+	return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+}
 
 /*
  * Find an entry in a page-table-directory.  We combine the address region
@@ -1303,7 +1318,9 @@
 
 static inline pmd_t pmd_mkdevmap(pmd_t pmd)
 {
-	return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP));
+	if (radix_enabled())
+		return radix__pmd_mkdevmap(pmd);
+	return hash__pmd_mkdevmap(pmd);
 }
 
 static inline int pmd_devmap(pmd_t pmd)
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/book3s/64/radix.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/book3s/64/radix.h
@@ -206,8 +206,10 @@
 	 * from ptesync, it should probably go into update_mmu_cache, rather
 	 * than set_pte_at (which is used to set ptes unrelated to faults).
 	 *
-	 * Spurious faults to vmalloc region are not tolerated, so there is
-	 * a ptesync in flush_cache_vmap.
+	 * Spurious faults from the kernel memory are not tolerated, so there
+	 * is a ptesync in flush_cache_vmap, and __map_kernel_page() follows
+	 * the pte update sequence from ISA Book III 6.10 Translation Table
+	 * Update Synchronization Requirements.
 	 */
 }
 
@@ -263,6 +265,11 @@
 }
 #endif
 
+static inline pmd_t radix__pmd_mkdevmap(pmd_t pmd)
+{
+	return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP));
+}
+
 extern int __meminit radix__vmemmap_create_mapping(unsigned long start,
 					     unsigned long page_size,
 					     unsigned long phys);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/bpf_perf_event.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/bpf_perf_event.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_BPF_PERF_EVENT_H
+#define _ASM_POWERPC_BPF_PERF_EVENT_H
+
+#include <asm/ptrace.h>
+
+typedef struct user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _ASM_POWERPC_BPF_PERF_EVENT_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/cache.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cache.h
@@ -55,42 +55,48 @@
 
 extern struct ppc64_caches ppc64_caches;
 
-static inline u32 l1_cache_shift(void)
+static inline u32 l1_dcache_shift(void)
 {
 	return ppc64_caches.l1d.log_block_size;
 }
 
-static inline u32 l1_cache_bytes(void)
+static inline u32 l1_dcache_bytes(void)
 {
 	return ppc64_caches.l1d.block_size;
 }
+
+static inline u32 l1_icache_shift(void)
+{
+	return ppc64_caches.l1i.log_block_size;
+}
+
+static inline u32 l1_icache_bytes(void)
+{
+	return ppc64_caches.l1i.block_size;
+}
 #else
-static inline u32 l1_cache_shift(void)
+static inline u32 l1_dcache_shift(void)
 {
 	return L1_CACHE_SHIFT;
 }
 
-static inline u32 l1_cache_bytes(void)
+static inline u32 l1_dcache_bytes(void)
 {
 	return L1_CACHE_BYTES;
 }
-#endif
-#endif /* ! __ASSEMBLY__ */
 
-#if defined(__ASSEMBLY__)
-/*
- * For a snooping icache, we still need a dummy icbi to purge all the
- * prefetched instructions from the ifetch buffers. We also need a sync
- * before the icbi to order the the actual stores to memory that might
- * have modified instructions with the icbi.
- */
-#define PURGE_PREFETCHED_INS	\
-	sync;			\
-	icbi	0,r3;		\
-	sync;			\
-	isync
+static inline u32 l1_icache_shift(void)
+{
+	return L1_CACHE_SHIFT;
+}
+
+static inline u32 l1_icache_bytes(void)
+{
+	return L1_CACHE_BYTES;
+}
+
+#endif
 
-#else
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifdef CONFIG_PPC_BOOK3S_32
@@ -124,6 +130,17 @@
 {
 	__asm__ __volatile__ ("dcbst 0, %0" : : "r"(addr) : "memory");
 }
+
+static inline void icbi(void *addr)
+{
+	asm volatile ("icbi 0, %0" : : "r"(addr) : "memory");
+}
+
+static inline void iccci(void *addr)
+{
+	asm volatile ("iccci 0, %0" : : "r"(addr) : "memory");
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_CACHE_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/cacheflush.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cacheflush.h
@@ -42,29 +42,25 @@
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
-extern void flush_icache_range(unsigned long, unsigned long);
+void flush_icache_range(unsigned long start, unsigned long stop);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
 				    struct page *page, unsigned long addr,
 				    int len);
-extern void __flush_dcache_icache(void *page_va);
 extern void flush_dcache_icache_page(struct page *page);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE)
-extern void __flush_dcache_icache_phys(unsigned long physaddr);
-#else
-static inline void __flush_dcache_icache_phys(unsigned long physaddr)
-{
-	BUG();
-}
-#endif
+void __flush_dcache_icache(void *page);
 
-/*
- * Write any modified data cache blocks out to memory and invalidate them.
- * Does not invalidate the corresponding instruction cache blocks.
+/**
+ * flush_dcache_range(): Write any modified data cache blocks out to memory and
+ * invalidate them. Does not invalidate the corresponding instruction cache
+ * blocks.
+ *
+ * @start: the start address
+ * @stop: the stop address (exclusive)
  */
 static inline void flush_dcache_range(unsigned long start, unsigned long stop)
 {
-	unsigned long shift = l1_cache_shift();
-	unsigned long bytes = l1_cache_bytes();
+	unsigned long shift = l1_dcache_shift();
+	unsigned long bytes = l1_dcache_bytes();
 	void *addr = (void *)(start & ~(bytes - 1));
 	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
 	unsigned long i;
@@ -89,8 +85,8 @@
  */
 static inline void clean_dcache_range(unsigned long start, unsigned long stop)
 {
-	unsigned long shift = l1_cache_shift();
-	unsigned long bytes = l1_cache_bytes();
+	unsigned long shift = l1_dcache_shift();
+	unsigned long bytes = l1_dcache_bytes();
 	void *addr = (void *)(start & ~(bytes - 1));
 	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
 	unsigned long i;
@@ -108,8 +104,8 @@
 static inline void invalidate_dcache_range(unsigned long start,
 					   unsigned long stop)
 {
-	unsigned long shift = l1_cache_shift();
-	unsigned long bytes = l1_cache_bytes();
+	unsigned long shift = l1_dcache_shift();
+	unsigned long bytes = l1_dcache_bytes();
 	void *addr = (void *)(start & ~(bytes - 1));
 	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
 	unsigned long i;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/code-patching.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/code-patching.h
@@ -22,6 +22,7 @@
 #define BRANCH_ABSOLUTE	0x2
 
 bool is_offset_in_branch_range(long offset);
+bool is_offset_in_cond_branch_range(long offset);
 unsigned int create_branch(const unsigned int *addr,
 			   unsigned long target, int flags);
 unsigned int create_cond_branch(const unsigned int *addr,
@@ -72,7 +73,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-ein-5.4.0.orig/arch/powerpc/include/asm/cpm1.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cpm1.h
@@ -68,6 +68,7 @@
 #define PROFF_SPI	((uint)0x0180)
 #define PROFF_SCC3	((uint)0x0200)
 #define PROFF_SMC1	((uint)0x0280)
+#define PROFF_DSP1	((uint)0x02c0)
 #define PROFF_SCC4	((uint)0x0300)
 #define PROFF_SMC2	((uint)0x0380)
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/cpu_has_feature.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cpu_has_feature.h
@@ -7,7 +7,7 @@
 #include <linux/bug.h>
 #include <asm/cputable.h>
 
-static inline bool early_cpu_has_feature(unsigned long feature)
+static __always_inline bool early_cpu_has_feature(unsigned long feature)
 {
 	return !!((CPU_FTRS_ALWAYS & feature) ||
 		  (CPU_FTRS_POSSIBLE & cur_cpu_spec->cpu_features & feature));
@@ -46,7 +46,7 @@
 	return static_branch_likely(&cpu_feature_keys[i]);
 }
 #else
-static inline bool cpu_has_feature(unsigned long feature)
+static __always_inline bool cpu_has_feature(unsigned long feature)
 {
 	return early_cpu_has_feature(feature);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/cputable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cputable.h
@@ -367,7 +367,7 @@
 	    CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_82XX	(CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_G2_LE	(CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | \
-	    CPU_FTR_MAYBE_CAN_NAP)
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_E300	(CPU_FTR_MAYBE_CAN_DOZE | \
 	    CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_COMMON  | CPU_FTR_NOEXECUTE)
@@ -407,7 +407,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_PPC970	(CPU_FTR_LWSYNC | \
@@ -507,8 +506,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_PPC_8xx
 	    CPU_FTRS_8XX |
@@ -585,8 +582,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_PPC_8xx
 	    CPU_FTRS_8XX &
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/cputhreads.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/cputhreads.h
@@ -3,6 +3,7 @@
 #define _ASM_POWERPC_CPUTHREADS_H
 
 #ifndef __ASSEMBLY__
+#include <asm/cpu_has_feature.h>
 #include <linux/cpumask.h>
 #include <asm/cpu_has_feature.h>
 
@@ -99,6 +100,36 @@
 	return cpu | (threads_per_core - 1);
 }
 
+/*
+ * tlb_thread_siblings are siblings which share a TLB. This is not
+ * architected, is not something a hypervisor could emulate and a future
+ * CPU may change behaviour even in compat mode, so this should only be
+ * used on PowerNV, and only with care.
+ */
+static inline int cpu_first_tlb_thread_sibling(int cpu)
+{
+	if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+		return cpu & ~0x6;	/* Big Core */
+	else
+		return cpu_first_thread_sibling(cpu);
+}
+
+static inline int cpu_last_tlb_thread_sibling(int cpu)
+{
+	if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+		return cpu | 0x6;	/* Big Core */
+	else
+		return cpu_last_thread_sibling(cpu);
+}
+
+static inline int cpu_tlb_thread_sibling_step(void)
+{
+	if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+		return 2;		/* Big Core */
+	else
+		return 1;
+}
+
 static inline u32 get_tensr(void)
 {
 #ifdef	CONFIG_BOOKE
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/dcr-native.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/dcr-native.h
@@ -53,8 +53,8 @@
 #define mfdcr(rn)						\
 	({unsigned int rval;					\
 	if (__builtin_constant_p(rn) && rn < 1024)		\
-		asm volatile("mfdcr %0," __stringify(rn)	\
-		              : "=r" (rval));			\
+		asm volatile("mfdcr %0, %1" : "=r" (rval)	\
+			      : "n" (rn));			\
 	else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))	\
 		rval = mfdcrx(rn);				\
 	else							\
@@ -64,8 +64,8 @@
 #define mtdcr(rn, v)						\
 do {								\
 	if (__builtin_constant_p(rn) && rn < 1024)		\
-		asm volatile("mtdcr " __stringify(rn) ",%0"	\
-			      : : "r" (v)); 			\
+		asm volatile("mtdcr %0, %1"			\
+			      : : "n" (rn), "r" (v));		\
 	else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))	\
 		mtdcrx(rn, v);					\
 	else							\
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/drmem.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/drmem.h
@@ -8,31 +8,44 @@
 #ifndef _ASM_POWERPC_LMB_H
 #define _ASM_POWERPC_LMB_H
 
+#include <linux/sched.h>
+
 struct drmem_lmb {
 	u64     base_addr;
 	u32     drc_index;
 	u32     aa_index;
 	u32     flags;
-#ifdef CONFIG_MEMORY_HOTPLUG
-	int	nid;
-#endif
 };
 
 struct drmem_lmb_info {
 	struct drmem_lmb        *lmbs;
 	int                     n_lmbs;
-	u32                     lmb_size;
+	u64                     lmb_size;
 };
 
 extern struct drmem_lmb_info *drmem_info;
 
+static inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb,
+					       const struct drmem_lmb *start)
+{
+	/*
+	 * DLPAR code paths can take several milliseconds per element
+	 * when interacting with firmware. Ensure that we don't
+	 * unfairly monopolize the CPU.
+	 */
+	if (((++lmb - start) % 16) == 0)
+		cond_resched();
+
+	return lmb;
+}
+
 #define for_each_drmem_lmb_in_range(lmb, start, end)		\
-	for ((lmb) = (start); (lmb) <= (end); (lmb)++)
+	for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start))
 
 #define for_each_drmem_lmb(lmb)					\
 	for_each_drmem_lmb_in_range((lmb),			\
 		&drmem_info->lmbs[0],				\
-		&drmem_info->lmbs[drmem_info->n_lmbs - 1])
+		&drmem_info->lmbs[drmem_info->n_lmbs])
 
 /*
  * The of_drconf_cell_v1 struct defines the layout of the LMB data
@@ -66,7 +79,7 @@
 #define DRCONF_MEM_AI_INVALID	0x00000040
 #define DRCONF_MEM_RESERVED	0x00000080
 
-static inline u32 drmem_lmb_size(void)
+static inline u64 drmem_lmb_size(void)
 {
 	return drmem_info->lmb_size;
 }
@@ -103,22 +116,4 @@
 	lmb->aa_index = 0xffffffff;
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static inline void lmb_set_nid(struct drmem_lmb *lmb)
-{
-	lmb->nid = memory_add_physaddr_to_nid(lmb->base_addr);
-}
-static inline void lmb_clear_nid(struct drmem_lmb *lmb)
-{
-	lmb->nid = -1;
-}
-#else
-static inline void lmb_set_nid(struct drmem_lmb *lmb)
-{
-}
-static inline void lmb_clear_nid(struct drmem_lmb *lmb)
-{
-}
-#endif
-
 #endif /* _ASM_POWERPC_LMB_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/exception-64s.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/exception-64s.h
@@ -61,11 +61,18 @@
 	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
+	STF_ENTRY_BARRIER_SLOT;						\
+	ENTRY_FLUSH_SLOT
 
 /*
  * Macros for annotating the expected destination of (h)rfid
@@ -127,6 +134,9 @@
 	hrfid;								\
 	b	hrfi_flush_fallback
 
+#else /* __ASSEMBLY__ */
+/* Prototype for function defined in exceptions-64s.S */
+void do_uaccess_flush(void);
 #endif /* __ASSEMBLY__ */
 
 #endif	/* _ASM_POWERPC_EXCEPTION_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/fadump-internal.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/fadump-internal.h
@@ -64,12 +64,14 @@
 };
 
 /* fadump memory ranges info */
+#define RNG_NAME_SZ			16
 struct fadump_mrange_info {
-	char				name[16];
+	char				name[RNG_NAME_SZ];
 	struct fadump_memory_range	*mem_ranges;
 	u32				mem_ranges_sz;
 	u32				mem_range_cnt;
 	u32				max_mem_ranges;
+	bool				is_static;
 };
 
 /* Platform specific callback functions */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/feature-fixups.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/feature-fixups.h
@@ -205,6 +205,22 @@
 	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";		\
@@ -237,8 +253,11 @@
 #include <linux/types.h>
 
 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;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/fixmap.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/fixmap.h
@@ -77,7 +77,12 @@
 static inline void __set_fixmap(enum fixed_addresses idx,
 				phys_addr_t phys, pgprot_t flags)
 {
-	map_kernel_page(fix_to_virt(idx), phys, flags);
+	if (__builtin_constant_p(idx))
+		BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
+	else if (WARN_ON(idx >= __end_of_fixed_addresses))
+		return;
+
+	map_kernel_page(__fix_to_virt(idx), phys, flags);
 }
 
 #endif /* !__ASSEMBLY__ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/ftrace.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/ftrace.h
@@ -96,7 +96,7 @@
 #endif /* PPC64_ELF_ABI_v1 */
 #endif /* CONFIG_FTRACE_SYSCALLS */
 
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC64) && defined(CONFIG_FUNCTION_TRACER)
 #include <asm/paca.h>
 
 static inline void this_cpu_disable_ftrace(void)
@@ -108,9 +108,12 @@
 {
 	get_paca()->ftrace_enabled = 1;
 }
+
+void ftrace_free_init_tramp(void);
 #else /* CONFIG_PPC64 */
 static inline void this_cpu_disable_ftrace(void) { }
 static inline void this_cpu_enable_ftrace(void) { }
+static inline void ftrace_free_init_tramp(void) { }
 #endif /* CONFIG_PPC64 */
 #endif /* !__ASSEMBLY__ */
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/futex.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/futex.h
@@ -35,7 +35,7 @@
 {
 	int oldval = 0, ret;
 
-	allow_write_to_user(uaddr, sizeof(*uaddr));
+	allow_read_write_user(uaddr, uaddr, sizeof(*uaddr));
 	pagefault_disable();
 
 	switch (op) {
@@ -62,7 +62,7 @@
 
 	*oval = oldval;
 
-	prevent_write_to_user(uaddr, sizeof(*uaddr));
+	prevent_read_write_user(uaddr, uaddr, sizeof(*uaddr));
 	return ret;
 }
 
@@ -76,7 +76,8 @@
 	if (!access_ok(uaddr, sizeof(u32)))
 		return -EFAULT;
 
-	allow_write_to_user(uaddr, sizeof(*uaddr));
+	allow_read_write_user(uaddr, uaddr, sizeof(*uaddr));
+
         __asm__ __volatile__ (
         PPC_ATOMIC_ENTRY_BARRIER
 "1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
@@ -97,7 +98,8 @@
         : "cc", "memory");
 
 	*uval = prev;
-	prevent_write_to_user(uaddr, sizeof(*uaddr));
+	prevent_read_write_user(uaddr, uaddr, sizeof(*uaddr));
+
         return ret;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/imc-pmu.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/imc-pmu.h
@@ -132,7 +132,7 @@
  * are inited.
  */
 struct imc_pmu_ref {
-	struct mutex lock;
+	spinlock_t lock;
 	unsigned int id;
 	int refc;
 };
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/io.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/io.h
@@ -345,25 +345,37 @@
  */
 static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr)
 {
-	__asm__ __volatile__("stbcix %0,0,%1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      stbcix %0,0,%1;  \
+			      .machine pop;"
 		: : "r" (val), "r" (paddr) : "memory");
 }
 
 static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr)
 {
-	__asm__ __volatile__("sthcix %0,0,%1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      sthcix %0,0,%1;  \
+			      .machine pop;"
 		: : "r" (val), "r" (paddr) : "memory");
 }
 
 static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr)
 {
-	__asm__ __volatile__("stwcix %0,0,%1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      stwcix %0,0,%1;  \
+			      .machine pop;"
 		: : "r" (val), "r" (paddr) : "memory");
 }
 
 static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
 {
-	__asm__ __volatile__("stdcix %0,0,%1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      stdcix %0,0,%1;  \
+			      .machine pop;"
 		: : "r" (val), "r" (paddr) : "memory");
 }
 
@@ -375,7 +387,10 @@
 static inline u8 __raw_rm_readb(volatile void __iomem *paddr)
 {
 	u8 ret;
-	__asm__ __volatile__("lbzcix %0,0, %1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      lbzcix %0,0, %1; \
+			      .machine pop;"
 			     : "=r" (ret) : "r" (paddr) : "memory");
 	return ret;
 }
@@ -383,7 +398,10 @@
 static inline u16 __raw_rm_readw(volatile void __iomem *paddr)
 {
 	u16 ret;
-	__asm__ __volatile__("lhzcix %0,0, %1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      lhzcix %0,0, %1; \
+			      .machine pop;"
 			     : "=r" (ret) : "r" (paddr) : "memory");
 	return ret;
 }
@@ -391,7 +409,10 @@
 static inline u32 __raw_rm_readl(volatile void __iomem *paddr)
 {
 	u32 ret;
-	__asm__ __volatile__("lwzcix %0,0, %1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      lwzcix %0,0, %1; \
+			      .machine pop;"
 			     : "=r" (ret) : "r" (paddr) : "memory");
 	return ret;
 }
@@ -399,7 +420,10 @@
 static inline u64 __raw_rm_readq(volatile void __iomem *paddr)
 {
 	u64 ret;
-	__asm__ __volatile__("ldcix %0,0, %1"
+	__asm__ __volatile__(".machine push;   \
+			      .machine power6; \
+			      ldcix %0,0, %1;  \
+			      .machine pop;"
 			     : "=r" (ret) : "r" (paddr) : "memory");
 	return ret;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/kasan.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/kasan.h
@@ -23,9 +23,7 @@
 
 #define KASAN_SHADOW_OFFSET	ASM_CONST(CONFIG_KASAN_SHADOW_OFFSET)
 
-#define KASAN_SHADOW_END	0UL
-
-#define KASAN_SHADOW_SIZE	(KASAN_SHADOW_END - KASAN_SHADOW_START)
+#define KASAN_SHADOW_END	(-(-KASAN_SHADOW_START >> KASAN_SHADOW_SCALE_SHIFT))
 
 #ifdef CONFIG_KASAN
 void kasan_early_init(void);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/kup.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/kup.h
@@ -2,7 +2,11 @@
 #ifndef _ASM_POWERPC_KUP_H_
 #define _ASM_POWERPC_KUP_H_
 
-#ifdef CONFIG_PPC64
+#define KUAP_READ	1
+#define KUAP_WRITE	2
+#define KUAP_READ_WRITE	(KUAP_READ | KUAP_WRITE)
+
+#ifdef CONFIG_PPC_BOOK3S_64
 #include <asm/book3s/64/kup-radix.h>
 #endif
 #ifdef CONFIG_PPC_8xx
@@ -20,9 +24,15 @@
 .macro kuap_restore	sp, current, gpr1, gpr2, gpr3
 .endm
 
+.macro kuap_restore_amr gpr
+.endm
+
 .macro kuap_check	current, gpr
 .endm
 
+.macro kuap_check_amr	gpr1, gpr2
+.endm
+
 #endif
 
 #else /* !__ASSEMBLY__ */
@@ -41,33 +51,60 @@
 void setup_kuap(bool disabled);
 #else
 static inline void setup_kuap(bool disabled) { }
+
+static inline bool
+bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+{
+	return false;
+}
+
+static inline void kuap_check_amr(void) { }
+
+/*
+ * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush
+ * the L1D cache after user accesses. Only include the empty stubs for other
+ * platforms.
+ */
+#ifndef CONFIG_PPC_BOOK3S_64
 static inline void allow_user_access(void __user *to, const void __user *from,
-				     unsigned long size) { }
+				     unsigned long size, unsigned long dir) { }
 static inline void prevent_user_access(void __user *to, const void __user *from,
-				       unsigned long size) { }
-static inline bool bad_kuap_fault(struct pt_regs *regs, bool is_write) { return false; }
+				       unsigned long size, unsigned long dir) { }
+#endif /* CONFIG_PPC_BOOK3S_64 */
 #endif /* CONFIG_PPC_KUAP */
 
 static inline void allow_read_from_user(const void __user *from, unsigned long size)
 {
-	allow_user_access(NULL, from, size);
+	allow_user_access(NULL, from, size, KUAP_READ);
 }
 
 static inline void allow_write_to_user(void __user *to, unsigned long size)
 {
-	allow_user_access(to, NULL, size);
+	allow_user_access(to, NULL, size, KUAP_WRITE);
+}
+
+static inline void allow_read_write_user(void __user *to, const void __user *from,
+					 unsigned long size)
+{
+	allow_user_access(to, from, size, KUAP_READ_WRITE);
 }
 
 static inline void prevent_read_from_user(const void __user *from, unsigned long size)
 {
-	prevent_user_access(NULL, from, size);
+	prevent_user_access(NULL, from, size, KUAP_READ);
 }
 
 static inline void prevent_write_to_user(void __user *to, unsigned long size)
 {
-	prevent_user_access(to, NULL, size);
+	prevent_user_access(to, NULL, size, KUAP_WRITE);
+}
+
+static inline void prevent_read_write_user(void __user *to, const void __user *from,
+					   unsigned long size)
+{
+	prevent_user_access(to, from, size, KUAP_READ_WRITE);
 }
 
 #endif /* !__ASSEMBLY__ */
 
-#endif /* _ASM_POWERPC_KUP_H_ */
+#endif /* _ASM_POWERPC_KUAP_H_ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/kvm_asm.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/kvm_asm.h
@@ -150,4 +150,7 @@
 
 #define KVM_INST_FETCH_FAILED	-1
 
+/* Extract PO and XOP opcode fields */
+#define PO_XOP_OPCODE_MASK 0xfc0007fe
+
 #endif /* __POWERPC_KVM_ASM_H__ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/kvm_host.h
@@ -58,7 +58,8 @@
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 
 extern int kvm_unmap_hva_range(struct kvm *kvm,
-			       unsigned long start, unsigned long end);
+			       unsigned long start, unsigned long end,
+			       unsigned flags);
 extern int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 extern int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/machdep.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/machdep.h
@@ -59,6 +59,9 @@
 	int		(*pcibios_root_bridge_prepare)(struct pci_host_bridge
 				*bridge);
 
+	/* finds all the pci_controllers present at boot */
+	void 		(*discover_phbs)(void);
+
 	/* To setup PHBs when using automatic OF platform driver for PCI */
 	int		(*pci_setup_phb)(struct pci_controller *host);
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/mmu.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/mmu.h
@@ -375,5 +375,9 @@
 #include <asm/nohash/mmu.h>
 #endif
 
+#if defined(CONFIG_FA_DUMP) || defined(CONFIG_PRESERVE_FA_DUMP)
+#define __HAVE_ARCH_RESERVED_KERNEL_PAGES
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/mmu_context.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/mmu_context.h
@@ -216,7 +216,7 @@
  */
 static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
-	switch_mm(prev, next, current);
+	switch_mm_irqs_off(prev, next, current);
 }
 
 /* We don't currently use enter_lazy_tlb() for anything */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/mmzone.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/mmzone.h
@@ -42,9 +42,6 @@
 #else
 #define memory_hotplug_max() memblock_end_of_DRAM()
 #endif /* CONFIG_NEED_MULTIPLE_NODES */
-#ifdef CONFIG_FA_DUMP
-#define __HAVE_ARCH_RESERVED_KERNEL_PAGES
-#endif
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_MMZONE_H_ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -34,18 +34,19 @@
 #include <asm/reg.h>
 
 static inline void allow_user_access(void __user *to, const void __user *from,
-				     unsigned long size)
+				     unsigned long size, unsigned long dir)
 {
 	mtspr(SPRN_MD_AP, MD_APG_INIT);
 }
 
 static inline void prevent_user_access(void __user *to, const void __user *from,
-				       unsigned long size)
+				       unsigned long size, unsigned long dir)
 {
 	mtspr(SPRN_MD_AP, MD_APG_KUAP);
 }
 
-static inline bool bad_kuap_fault(struct pt_regs *regs, bool is_write)
+static inline bool
+bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
 {
 	return WARN(!((regs->kuap ^ MD_APG_KUAP) & 0xf0000000),
 		    "Bug: fault blocked by AP register !");
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -148,8 +148,10 @@
  */
 #if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
 #define PTE_RPN_MASK	(~((1ULL << PTE_RPN_SHIFT) - 1))
+#define MAX_POSSIBLE_PHYSMEM_BITS 36
 #else
 #define PTE_RPN_MASK	(~((1UL << PTE_RPN_SHIFT) - 1))
+#define MAX_POSSIBLE_PHYSMEM_BITS 32
 #endif
 
 /*
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -91,6 +91,13 @@
 
 #define pte_wrprotect pte_wrprotect
 
+static inline int pte_read(pte_t pte)
+{
+	return (pte_val(pte) & _PAGE_RO) != _PAGE_NA;
+}
+
+#define pte_read pte_read
+
 static inline int pte_write(pte_t pte)
 {
 	return !(pte_val(pte) & _PAGE_RO);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -244,7 +244,7 @@
 {
 	unsigned long old;
 
-	if (pte_young(*ptep))
+	if (!pte_young(*ptep))
 		return 0;
 	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
 	return (old & _PAGE_ACCESSED) != 0;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/pgalloc.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/pgalloc.h
@@ -46,7 +46,6 @@
 
 #define get_hugepd_cache_index(x)	(x)
 
-#ifdef CONFIG_SMP
 static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
 {
 	unsigned long pgf = (unsigned long)table;
@@ -64,13 +63,6 @@
 	pgtable_free(table, shift);
 }
 
-#else
-static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
-{
-	pgtable_free(table, shift);
-}
-#endif
-
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
 				  unsigned long address)
 {
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/nohash/pgtable.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/nohash/pgtable.h
@@ -45,7 +45,9 @@
 	return pte_val(pte) & _PAGE_RW;
 }
 #endif
+#ifndef pte_read
 static inline int pte_read(pte_t pte)		{ return 1; }
+#endif
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
@@ -199,9 +201,9 @@
 	 */
 	if (IS_ENABLED(CONFIG_PPC32) && IS_ENABLED(CONFIG_PTE_64BIT) && !percpu) {
 		__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");
 		return;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/opal-api.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/opal-api.h
@@ -211,7 +211,10 @@
 #define OPAL_MPIPL_UPDATE			173
 #define OPAL_MPIPL_REGISTER_TAG			174
 #define OPAL_MPIPL_QUERY_TAG			175
-#define OPAL_LAST				175
+#define OPAL_SECVAR_GET				176
+#define OPAL_SECVAR_GET_NEXT			177
+#define OPAL_SECVAR_ENQUEUE_UPDATE		178
+#define OPAL_LAST				178
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/opal.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/opal.h
@@ -298,6 +298,13 @@
 int opal_sensor_group_enable(u32 group_hndl, int token, bool enable);
 int opal_nx_coproc_init(uint32_t chip_id, uint32_t ct);
 
+int opal_secvar_get(const char *key, uint64_t key_len, u8 *data,
+		    uint64_t *data_size);
+int opal_secvar_get_next(const char *key, uint64_t *key_len,
+			 uint64_t key_buf_size);
+int opal_secvar_enqueue_update(const char *key, uint64_t key_len, u8 *data,
+			       uint64_t data_size);
+
 s64 opal_mpipl_update(enum opal_mpipl_ops op, u64 src, u64 dest, u64 size);
 s64 opal_mpipl_register_tag(enum opal_mpipl_tags tag, u64 addr);
 s64 opal_mpipl_query_tag(enum opal_mpipl_tags tag, u64 *addr);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/page.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/page.h
@@ -132,7 +132,11 @@
 #define virt_to_page(kaddr)	pfn_to_page(virt_to_pfn(kaddr))
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
-#define virt_addr_valid(kaddr)	pfn_valid(virt_to_pfn(kaddr))
+#define virt_addr_valid(vaddr)	({					\
+	unsigned long _addr = (unsigned long)vaddr;			\
+	_addr >= PAGE_OFFSET && _addr < (unsigned long)high_memory &&	\
+	pfn_valid(virt_to_pfn(_addr));					\
+})
 
 /*
  * On Book-E parts we need __va to parse the device tree and we can't
@@ -212,6 +216,9 @@
 #define __pa(x) ((unsigned long)(x) - VIRT_PHYS_OFFSET)
 #else
 #ifdef CONFIG_PPC64
+
+#define VIRTUAL_WARN_ON(x)	WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && (x))
+
 /*
  * gcc miscompiles (unsigned long)(&static_var) - PAGE_OFFSET
  * with -mcmodel=medium, so we use & and | instead of - and + on 64-bit.
@@ -219,13 +226,13 @@
  */
 #define __va(x)								\
 ({									\
-	VIRTUAL_BUG_ON((unsigned long)(x) >= PAGE_OFFSET);		\
+	VIRTUAL_WARN_ON((unsigned long)(x) >= PAGE_OFFSET);		\
 	(void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET);	\
 })
 
 #define __pa(x)								\
 ({									\
-	VIRTUAL_BUG_ON((unsigned long)(x) < PAGE_OFFSET);		\
+	VIRTUAL_WARN_ON((unsigned long)(x) < PAGE_OFFSET);		\
 	(unsigned long)(x) & 0x0fffffffffffffffUL;			\
 })
 
@@ -295,8 +302,13 @@
 /*
  * Some number of bits at the level of the page table that points to
  * a hugepte are used to encode the size.  This masks those bits.
+ * On 8xx, HW assistance requires 4k alignment for the hugepte.
  */
+#ifdef CONFIG_PPC_8xx
+#define HUGEPD_SHIFT_MASK     0xfff
+#else
 #define HUGEPD_SHIFT_MASK     0x3f
+#endif
 
 #ifndef __ASSEMBLY__
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/percpu.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/percpu.h
@@ -10,8 +10,6 @@
 
 #ifdef CONFIG_SMP
 
-#include <asm/paca.h>
-
 #define __my_cpu_offset local_paca->data_offset
 
 #endif /* CONFIG_SMP */
@@ -19,4 +17,6 @@
 
 #include <asm-generic/percpu.h>
 
+#include <asm/paca.h>
+
 #endif /* _ASM_POWERPC_PERCPU_H_ */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/perf_event.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/perf_event.h
@@ -12,6 +12,8 @@
 
 #ifdef CONFIG_PPC_PERF_CTRS
 #include <asm/perf_event_server.h>
+#else
+static inline bool is_sier_available(void) { return false; }
 #endif
 
 #ifdef CONFIG_FSL_EMB_PERF_EVENT
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/pmc.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/pmc.h
@@ -34,6 +34,13 @@
 #endif
 }
 
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+static inline int ppc_get_pmu_inuse(void)
+{
+	return get_paca()->pmcregs_in_use;
+}
+#endif
+
 extern void power4_enable_pmcs(void);
 
 #else /* CONFIG_PPC64 */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/pnv-pci.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/pnv-pci.h
@@ -15,6 +15,7 @@
 #define PCI_SLOT_ID_PREFIX	(1UL << 63)
 #define PCI_SLOT_ID(phb_id, bdfn)	\
 	(PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb_id))
+#define PCI_PHB_SLOT_ID(phb_id)		(phb_id)
 
 extern int pnv_pci_get_slot_id(struct device_node *np, uint64_t *id);
 extern int pnv_pci_get_device_tree(uint32_t phandle, void *buf, uint64_t len);
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/ppc-opcode.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/ppc-opcode.h
@@ -204,6 +204,7 @@
 #define PPC_INST_ICBT			0x7c00002c
 #define PPC_INST_ICSWX			0x7c00032d
 #define PPC_INST_ICSWEPX		0x7c00076d
+#define PPC_INST_DSSALL			0x7e00066c
 #define PPC_INST_ISEL			0x7c00001e
 #define PPC_INST_ISEL_MASK		0xfc00003e
 #define PPC_INST_LDARX			0x7c0000a8
@@ -439,6 +440,7 @@
 					__PPC_RA(a) | __PPC_RB(b))
 #define	PPC_DCBZL(a, b)		stringify_in_c(.long PPC_INST_DCBZL | \
 					__PPC_RA(a) | __PPC_RB(b))
+#define PPC_DSSALL		stringify_in_c(.long PPC_INST_DSSALL)
 #define PPC_LQARX(t, a, b, eh)	stringify_in_c(.long PPC_INST_LQARX | \
 					___PPC_RT(t) | ___PPC_RA(a) | \
 					___PPC_RB(b) | __PPC_EH(eh))
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/processor.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/processor.h
@@ -291,7 +291,6 @@
 #else
 #define INIT_THREAD  { \
 	.ksp = INIT_SP, \
-	.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
 	.addr_limit = KERNEL_DS, \
 	.fpexc_mode = 0, \
 	.fscr = FSCR_TAR | FSCR_EBB \
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/ps3.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/ps3.h
@@ -71,6 +71,7 @@
  * @bus_addr: The 'translated' bus address of the region.
  * @len: The length in bytes of the region.
  * @offset: The offset from the start of memory of the region.
+ * @dma_mask: Device dma_mask.
  * @ioid: The IOID of the device who owns this region
  * @chunk_list: Opaque variable used by the ioc page manager.
  * @region_ops: struct ps3_dma_region_ops - dma region operations
@@ -85,6 +86,7 @@
 	enum ps3_dma_region_type region_type;
 	unsigned long len;
 	unsigned long offset;
+	u64 dma_mask;
 
 	/* driver variables  (set by ps3_dma_region_create) */
 	unsigned long bus_addr;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/ptrace.h
@@ -62,6 +62,9 @@
 };
 #endif
 
+
+#define STACK_FRAME_WITH_PT_REGS (STACK_FRAME_OVERHEAD + sizeof(struct pt_regs))
+
 #ifdef __powerpc64__
 
 /*
@@ -203,7 +206,7 @@
 #endif /* __powerpc64__ */
 
 #define arch_has_single_step()	(1)
-#ifndef CONFIG_BOOK3S_601
+#ifndef CONFIG_PPC_BOOK3S_601
 #define arch_has_block_step()	(true)
 #else
 #define arch_has_block_step()	(false)
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/reg.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/reg.h
@@ -796,7 +796,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)
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/rtas.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/rtas.h
@@ -368,8 +368,6 @@
 extern void rtas_progress(char *s, unsigned short hex);
 extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data);
 extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data);
-extern int rtas_online_cpus_mask(cpumask_var_t cpus);
-extern int rtas_offline_cpus_mask(cpumask_var_t cpus);
 extern int rtas_ibm_suspend_me(u64 handle);
 
 struct rtc_time;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/sections.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/sections.h
@@ -5,8 +5,22 @@
 
 #include <linux/elf.h>
 #include <linux/uaccess.h>
+
+#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
+
 #include <asm-generic/sections.h>
 
+extern bool init_mem_is_free;
+
+static inline int arch_is_kernel_initmem_freed(unsigned long addr)
+{
+	if (!init_mem_is_free)
+		return 0;
+
+	return addr >= (unsigned long)__init_begin &&
+		addr < (unsigned long)__init_end;
+}
+
 extern char __head_end[];
 
 #ifdef __powerpc64__
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/secure_boot.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/secure_boot.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Secure boot definitions
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain
+ */
+#ifndef _ASM_POWER_SECURE_BOOT_H
+#define _ASM_POWER_SECURE_BOOT_H
+
+#ifdef CONFIG_PPC_SECURE_BOOT
+
+bool is_ppc_secureboot_enabled(void);
+bool is_ppc_trustedboot_enabled(void);
+
+#else
+
+static inline bool is_ppc_secureboot_enabled(void)
+{
+	return false;
+}
+
+static inline bool is_ppc_trustedboot_enabled(void)
+{
+	return false;
+}
+
+#endif
+#endif
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/security_features.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/security_features.h
@@ -9,7 +9,7 @@
 #define _ASM_POWERPC_SECURITY_FEATURES_H
 
 
-extern unsigned long powerpc_security_features;
+extern u64 powerpc_security_features;
 extern bool rfi_flush;
 
 /* These are bit flags */
@@ -24,21 +24,26 @@
 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)
+static inline void security_ftr_set(u64 feature)
 {
 	powerpc_security_features |= feature;
 }
 
-static inline void security_ftr_clear(unsigned long feature)
+static inline void security_ftr_clear(u64 feature)
 {
 	powerpc_security_features &= ~feature;
 }
 
-static inline bool security_ftr_enabled(unsigned long feature)
+static inline bool security_ftr_enabled(u64 feature)
 {
 	return !!(powerpc_security_features & feature);
 }
 
+#ifdef CONFIG_PPC_BOOK3S_64
+enum stf_barrier_type stf_barrier_type_get(void);
+#else
+static inline enum stf_barrier_type stf_barrier_type_get(void) { return STF_BARRIER_NONE; }
+#endif
 
 // Features indicating support for Spectre/Meltdown mitigations
 
@@ -81,12 +86,22 @@
 // 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-ein-5.4.0.orig/arch/powerpc/include/asm/secvar.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/secvar.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain
+ *
+ * PowerPC secure variable operations.
+ */
+#ifndef SECVAR_OPS_H
+#define SECVAR_OPS_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+extern const struct secvar_operations *secvar_ops;
+
+struct secvar_operations {
+	int (*get)(const char *key, uint64_t key_len, u8 *data,
+		   uint64_t *data_size);
+	int (*get_next)(const char *key, uint64_t *key_len,
+			uint64_t keybufsize);
+	int (*set)(const char *key, uint64_t key_len, u8 *data,
+		   uint64_t data_size);
+};
+
+#ifdef CONFIG_PPC_SECURE_BOOT
+
+extern void set_secvar_ops(const struct secvar_operations *ops);
+
+#else
+
+static inline void set_secvar_ops(const struct secvar_operations *ops) { }
+
+#endif
+
+#endif
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/setjmp.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/setjmp.h
@@ -7,7 +7,9 @@
 
 #define JMP_BUF_LEN    23
 
-extern long setjmp(long *) __attribute__((returns_twice));
-extern void longjmp(long *, long) __attribute__((noreturn));
+typedef long jmp_buf[JMP_BUF_LEN];
+
+extern int setjmp(jmp_buf env) __attribute__((returns_twice));
+extern void longjmp(jmp_buf env, int val) __attribute__((noreturn));
 
 #endif /* _ASM_POWERPC_SETJMP_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/setup.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/setup.h
@@ -52,12 +52,16 @@
 };
 
 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;
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/spinlock.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/spinlock.h
@@ -15,6 +15,7 @@
  *
  * (the type definitions are in asm/spinlock_types.h)
  */
+#include <linux/jump_label.h>
 #include <linux/irqflags.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
@@ -36,10 +37,12 @@
 #endif
 
 #ifdef CONFIG_PPC_PSERIES
+DECLARE_STATIC_KEY_FALSE(shared_processor);
+
 #define vcpu_is_preempted vcpu_is_preempted
 static inline bool vcpu_is_preempted(int cpu)
 {
-	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+	if (!static_branch_unlikely(&shared_processor))
 		return false;
 	return !!(be32_to_cpu(lppaca_of(cpu).yield_count) & 1);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/timex.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/timex.h
@@ -17,11 +17,12 @@
 
 static inline cycles_t get_cycles(void)
 {
-	if (IS_ENABLED(CONFIG_BOOK3S_601))
+	if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
 		return 0;
 
 	return mftb();
 }
+#define get_cycles get_cycles
 
 #endif	/* __KERNEL__ */
 #endif	/* _ASM_POWERPC_TIMEX_H */
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/tlb.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/tlb.h
@@ -26,6 +26,17 @@
 
 #define tlb_flush tlb_flush
 extern void tlb_flush(struct mmu_gather *tlb);
+/*
+ * book3s:
+ * Hash does not use the linux page-tables, so we can avoid
+ * the TLB invalidate for page-table freeing, Radix otoh does use the
+ * page-tables and needs the TLBI.
+ *
+ * nohash:
+ * We still do TLB invalidate in the __pte_free_tlb routine before we
+ * add the page table pages to mmu gather table batch.
+ */
+#define tlb_needs_table_invalidate()	radix_enabled()
 
 /* Get the generic bits... */
 #include <asm-generic/tlb.h>
@@ -56,19 +67,6 @@
 		return false;
 	return cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm));
 }
-static inline void mm_reset_thread_local(struct mm_struct *mm)
-{
-	WARN_ON(atomic_read(&mm->context.copros) > 0);
-	/*
-	 * It's possible for mm_access to take a reference on mm_users to
-	 * access the remote mm from another thread, but it's not allowed
-	 * to set mm_cpumask, so mm_users may be > 1 here.
-	 */
-	WARN_ON(current->mm != mm);
-	atomic_set(&mm->context.active_cpus, 1);
-	cpumask_clear(mm_cpumask(mm));
-	cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-}
 #else /* CONFIG_PPC_BOOK3S_64 */
 static inline int mm_is_thread_local(struct mm_struct *mm)
 {
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/uaccess.h
@@ -191,8 +191,11 @@
  */
 #define __get_user_atomic_128_aligned(kaddr, uaddr, err)		\
 	__asm__ __volatile__(				\
+		".machine push\n"			\
+		".machine altivec\n"			\
 		"1:	lvx  0,0,%1	# get user\n"	\
 		" 	stvx 0,0,%2	# put kernel\n"	\
+		".machine pop\n"			\
 		"2:\n"					\
 		".section .fixup,\"ax\"\n"		\
 		"3:	li %0,%3\n"			\
@@ -313,9 +316,9 @@
 	unsigned long ret;
 
 	barrier_nospec();
-	allow_user_access(to, from, n);
+	allow_read_write_user(to, from, n);
 	ret = __copy_tofrom_user(to, from, n);
-	prevent_user_access(to, from, n);
+	prevent_read_write_user(to, from, n);
 	return ret;
 }
 #endif /* __powerpc64__ */
@@ -401,7 +404,7 @@
 	return n;
 }
 
-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)
 {
@@ -409,12 +412,17 @@
 	might_fault();
 	if (likely(access_ok(addr, size))) {
 		allow_write_to_user(addr, size);
-		ret = __clear_user(addr, size);
+		ret = __arch_clear_user(addr, size);
 		prevent_write_to_user(addr, 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 strnlen_user(const char __user *str, long n);
 
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/vdso_datapage.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/vdso_datapage.h
@@ -82,6 +82,7 @@
 	__s32 wtom_clock_nsec;			/* Wall to monotonic clock nsec */
 	__s64 wtom_clock_sec;			/* Wall to monotonic clock sec */
 	struct timespec stamp_xtime;		/* xtime as at tb_orig_stamp */
+	__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 */
 };
@@ -103,6 +104,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-ein-5.4.0.orig/arch/powerpc/include/asm/word-at-a-time.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/word-at-a-time.h
@@ -34,7 +34,7 @@
 	return leading_zero_bits >> 3;
 }
 
-static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
 {
 	unsigned long rhs = val | c->low_bits;
 	*data = rhs;
--- linux-ein-5.4.0.orig/arch/powerpc/include/asm/xive-regs.h
+++ linux-ein-5.4.0/arch/powerpc/include/asm/xive-regs.h
@@ -39,6 +39,7 @@
 
 #define XIVE_ESB_VAL_P		0x2
 #define XIVE_ESB_VAL_Q		0x1
+#define XIVE_ESB_INVALID	0xFF
 
 /*
  * Thread Management (aka "TM") registers
--- linux-ein-5.4.0.orig/arch/powerpc/include/uapi/asm/errno.h
+++ linux-ein-5.4.0/arch/powerpc/include/uapi/asm/errno.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_POWERPC_ERRNO_H
 #define _ASM_POWERPC_ERRNO_H
 
+#undef	EDEADLOCK
 #include <asm-generic/errno.h>
 
 #undef	EDEADLOCK
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/Makefile
+++ linux-ein-5.4.0/arch/powerpc/kernel/Makefile
@@ -5,9 +5,6 @@
 
 CFLAGS_ptrace.o		+= -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
-# Disable clang warning for using setjmp without setjmp.h header
-CFLAGS_crash.o		+= $(call cc-disable-warning, builtin-requires-header)
-
 ifdef CONFIG_PPC64
 CFLAGS_prom_init.o	+= $(NO_MINIMAL_TOC)
 endif
@@ -16,12 +13,14 @@
 CFLAGS_btext.o		+= -fPIC
 endif
 
+CFLAGS_early_32.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 
 CFLAGS_prom_init.o += $(call cc-option, -fno-stack-protector)
+CFLAGS_prom_init.o += -DDISABLE_BRANCH_PROFILING
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace early boot code
@@ -39,7 +38,6 @@
 ifdef CONFIG_KASAN
 CFLAGS_early_32.o += -DDISABLE_BRANCH_PROFILING
 CFLAGS_cputable.o += -DDISABLE_BRANCH_PROFILING
-CFLAGS_prom_init.o += -DDISABLE_BRANCH_PROFILING
 CFLAGS_btext.o += -DDISABLE_BRANCH_PROFILING
 endif
 
@@ -161,6 +159,9 @@
 obj-y				+= ucall.o
 endif
 
+obj-$(CONFIG_PPC_SECURE_BOOT)	+= secure_boot.o ima_arch.o secvar-ops.o
+obj-$(CONFIG_PPC_SECVAR_SYSFS)	+= secvar-sysfs.o
+
 # Disable GCOV, KCOV & sanitizers in odd or sensitive code
 GCOV_PROFILE_prom_init.o := n
 KCOV_INSTRUMENT_prom_init.o := n
@@ -184,6 +185,9 @@
 KCOV_INSTRUMENT_setup_64.o := n
 KCOV_INSTRUMENT_paca.o := n
 
+CFLAGS_setup_64.o		+= -fno-stack-protector
+CFLAGS_paca.o			+= -fno-stack-protector
+
 extra-$(CONFIG_PPC_FPU)		+= fpu.o
 extra-$(CONFIG_ALTIVEC)		+= vector.o
 extra-$(CONFIG_PPC64)		+= entry_64.o
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/asm-offsets.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/asm-offsets.c
@@ -285,7 +285,7 @@
 
 	/* Interrupt register frame */
 	DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE);
-	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_WITH_PT_REGS);
 	STACK_PT_REGS_OFFSET(GPR0, gpr[0]);
 	STACK_PT_REGS_OFFSET(GPR1, gpr[1]);
 	STACK_PT_REGS_OFFSET(GPR2, gpr[2]);
@@ -387,6 +387,7 @@
 	OFFSET(WTOM_CLOCK_NSEC, vdso_data, wtom_clock_nsec);
 	OFFSET(STAMP_XTIME, vdso_data, stamp_xtime);
 	OFFSET(STAMP_SEC_FRAC, vdso_data, stamp_sec_fraction);
+	OFFSET(CLOCK_HRTIMER_RES, vdso_data, hrtimer_res);
 	OFFSET(CFG_ICACHE_BLOCKSZ, vdso_data, icache_block_size);
 	OFFSET(CFG_DCACHE_BLOCKSZ, vdso_data, dcache_block_size);
 	OFFSET(CFG_ICACHE_LOGBLOCKSZ, vdso_data, icache_log_block_size);
@@ -417,7 +418,6 @@
 	DEFINE(CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE);
 	DEFINE(CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_COARSE);
 	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));
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/btext.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/btext.c
@@ -250,8 +250,10 @@
 			rc = btext_initialize(np);
 			printk("result: %d\n", rc);
 		}
-		if (rc == 0)
+		if (rc == 0) {
+			of_node_put(np);
 			break;
+		}
 	}
 	return rc;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/cpu_setup_power.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/cpu_setup_power.S
@@ -184,7 +184,7 @@
 
 __init_FSCR:
 	mfspr	r3,SPRN_FSCR
-	ori	r3,r3,FSCR_TAR|FSCR_DSCR|FSCR_EBB
+	ori	r3,r3,FSCR_TAR|FSCR_EBB
 	mtspr	SPRN_FSCR,r3
 	blr
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/cputable.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/cputable.c
@@ -2193,11 +2193,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-ein-5.4.0.orig/arch/powerpc/kernel/dma-iommu.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/dma-iommu.c
@@ -160,7 +160,8 @@
 			return bypass_mask;
 	}
 
-	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-ein-5.4.0.orig/arch/powerpc/kernel/dt_cpu_ftrs.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/dt_cpu_ftrs.c
@@ -139,7 +139,6 @@
 	/* Initialize the base environment -- clear FSCR/HFSCR.  */
 	hv_mode = !!(mfmsr() & MSR_HV);
 	if (hv_mode) {
-		/* CPU_FTR_HVMODE is used early in PACA setup */
 		cur_cpu_spec->cpu_features |= CPU_FTR_HVMODE;
 		mtspr(SPRN_HFSCR, 0);
 	}
@@ -347,6 +346,14 @@
 {
 	u64 lpcr;
 
+	/*
+	 * Linux relies on FSCR[DSCR] being clear, so that we can take the
+	 * facility unavailable interrupt and track the task's usage of DSCR.
+	 * See facility_unavailable_exception().
+	 * Clear the bit here so that feat_enable() doesn't set it.
+	 */
+	f->fscr_bit_nr = -1;
+
 	feat_enable(f);
 
 	lpcr = mfspr(SPRN_LPCR);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/eeh.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/eeh.c
@@ -368,14 +368,11 @@
 	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);
-	}
+	if (!hugepage_shift)
+		hugepage_shift = PAGE_SHIFT;
 
+	pa <<= PAGE_SHIFT;
+	pa |= token & ((1ul << hugepage_shift) - 1);
 	return pa;
 }
 
@@ -503,7 +500,7 @@
 	rc = 1;
 	if (pe->state & EEH_PE_ISOLATED) {
 		pe->check_count++;
-		if (pe->check_count % EEH_MAX_FAILS == 0) {
+		if (pe->check_count == EEH_MAX_FAILS) {
 			dn = pci_device_to_OF_node(dev);
 			if (dn)
 				location = of_get_property(dn, "ibm,loc-code",
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/eeh_cache.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/eeh_cache.c
@@ -272,8 +272,9 @@
 {
 	struct pci_io_addr_range *piar;
 	struct rb_node *n;
+	unsigned long flags;
 
-	spin_lock(&pci_io_addr_cache_root.piar_lock);
+	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
 	for (n = rb_first(&pci_io_addr_cache_root.rb_root); n; n = rb_next(n)) {
 		piar = rb_entry(n, struct pci_io_addr_range, rb_node);
 
@@ -281,7 +282,7 @@
 		       (piar->flags & IORESOURCE_IO) ? "i/o" : "mem",
 		       &piar->addr_lo, &piar->addr_hi, pci_name(piar->pcidev));
 	}
-	spin_unlock(&pci_io_addr_cache_root.piar_lock);
+	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/eeh_driver.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/eeh_driver.c
@@ -541,12 +541,6 @@
 
 		pci_iov_remove_virtfn(edev->physfn, pdn->vf_index);
 		edev->pdev = NULL;
-
-		/*
-		 * We have to set the VF PE number to invalid one, which is
-		 * required to plug the VF successfully.
-		 */
-		pdn->pe_number = IODA_INVALID_PE;
 #endif
 		if (rmv_data)
 			list_add(&edev->rmv_entry, &rmv_data->removed_vf_list);
@@ -897,12 +891,12 @@
 
 	/* Log the event */
 	if (pe->type & EEH_PE_PHB) {
-		pr_err("EEH: PHB#%x failure detected, location: %s\n",
+		pr_err("EEH: Recovering PHB#%x, location: %s\n",
 			pe->phb->global_number, eeh_pe_loc_get(pe));
 	} else {
 		struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb);
 
-		pr_err("EEH: Frozen PHB#%x-PE#%x detected\n",
+		pr_err("EEH: Recovering PHB#%x-PE#%x\n",
 		       pe->phb->global_number, pe->addr);
 		pr_err("EEH: PE location: %s, PHB location: %s\n",
 		       eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe));
@@ -1078,45 +1072,46 @@
 		}
 
 		pr_info("EEH: Recovery successful.\n");
-	} else  {
-		/*
-		 * About 90% of all real-life EEH failures in the field
-		 * are due to poorly seated PCI cards. Only 10% or so are
-		 * due to actual, failed cards.
-		 */
-		pr_err("EEH: Unable to recover from failure from PHB#%x-PE#%x.\n"
-		       "Please try reseating or replacing it\n",
-			pe->phb->global_number, pe->addr);
-
-		eeh_slot_error_detail(pe, EEH_LOG_PERM);
+		goto out;
+	}
 
-		/* Notify all devices that they're about to go down. */
-		eeh_set_channel_state(pe, pci_channel_io_perm_failure);
-		eeh_set_irq_state(pe, false);
-		eeh_pe_report("error_detected(permanent failure)", pe,
-			      eeh_report_failure, NULL);
+	/*
+	 * About 90% of all real-life EEH failures in the field
+	 * are due to poorly seated PCI cards. Only 10% or so are
+	 * due to actual, failed cards.
+	 */
+	pr_err("EEH: Unable to recover from failure from PHB#%x-PE#%x.\n"
+		"Please try reseating or replacing it\n",
+		pe->phb->global_number, pe->addr);
+
+	eeh_slot_error_detail(pe, EEH_LOG_PERM);
+
+	/* Notify all devices that they're about to go down. */
+	eeh_set_irq_state(pe, false);
+	eeh_pe_report("error_detected(permanent failure)", pe,
+		      eeh_report_failure, NULL);
+	eeh_set_channel_state(pe, pci_channel_io_perm_failure);
 
-		/* Mark the PE to be removed permanently */
-		eeh_pe_state_mark(pe, EEH_PE_REMOVED);
+	/* Mark the PE to be removed permanently */
+	eeh_pe_state_mark(pe, EEH_PE_REMOVED);
 
-		/*
-		 * Shut down the device drivers for good. We mark
-		 * all removed devices correctly to avoid access
-		 * the their PCI config any more.
-		 */
-		if (pe->type & EEH_PE_VF) {
-			eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
-			eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
-		} else {
-			eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
-			eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
+	/*
+	 * Shut down the device drivers for good. We mark
+	 * all removed devices correctly to avoid access
+	 * the their PCI config any more.
+	 */
+	if (pe->type & EEH_PE_VF) {
+		eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
+		eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
+	} else {
+		eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
+		eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
 
-			pci_lock_rescan_remove();
-			pci_hp_remove_devices(bus);
-			pci_unlock_rescan_remove();
-			/* The passed PE should no longer be used */
-			return;
-		}
+		pci_lock_rescan_remove();
+		pci_hp_remove_devices(bus);
+		pci_unlock_rescan_remove();
+		/* The passed PE should no longer be used */
+		return;
 	}
 
 out:
@@ -1206,6 +1201,17 @@
 			eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
 			eeh_handle_normal_event(pe);
 		} else {
+			eeh_for_each_pe(pe, tmp_pe)
+				eeh_pe_for_each_dev(tmp_pe, edev, tmp_edev)
+					edev->mode &= ~EEH_DEV_NO_HANDLER;
+
+			/* Notify all devices to be down */
+			eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
+			eeh_pe_report(
+				"error_detected(permanent failure)", pe,
+				eeh_report_failure, NULL);
+			eeh_set_channel_state(pe, pci_channel_io_perm_failure);
+
 			pci_lock_rescan_remove();
 			list_for_each_entry(hose, &hose_list, list_node) {
 				phb_pe = eeh_phb_pe_get(hose);
@@ -1214,16 +1220,6 @@
 				    (phb_pe->state & EEH_PE_RECOVERING))
 					continue;
 
-				eeh_for_each_pe(pe, tmp_pe)
-					eeh_pe_for_each_dev(tmp_pe, edev, tmp_edev)
-						edev->mode &= ~EEH_DEV_NO_HANDLER;
-
-				/* Notify all devices to be down */
-				eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
-				eeh_set_channel_state(pe, pci_channel_io_perm_failure);
-				eeh_pe_report(
-					"error_detected(permanent failure)", pe,
-					eeh_report_failure, NULL);
 				bus = eeh_pe_bus_get(phb_pe);
 				if (!bus) {
 					pr_err("%s: Cannot find PCI bus for "
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/entry_32.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/entry_32.S
@@ -179,7 +179,7 @@
 2:	/* if from kernel, check interrupted DOZE/NAP mode and
          * check for stack overflow
          */
-	kuap_save_and_lock r11, r12, r9, r2, r0
+	kuap_save_and_lock r11, r12, r9, r2, r6
 	addi	r2, r12, -THREAD
 	lwz	r9,KSP_LIMIT(r12)
 	cmplw	r1,r9			/* if r1 <= ksp_limit */
@@ -284,6 +284,7 @@
 	rlwinm	r9,r9,0,~MSR_EE
 	lwz	r12,_LINK(r11)		/* and return to address in LR */
 	kuap_restore r11, r2, r3, r4, r5
+	lwz	r2, GPR2(r11)
 	b	fast_exception_return
 #endif
 
@@ -335,6 +336,9 @@
 
 	.globl	transfer_to_syscall
 transfer_to_syscall:
+#ifdef CONFIG_PPC_BOOK3S_32
+	kuep_lock r11, r12
+#endif
 #ifdef CONFIG_TRACE_IRQFLAGS
 	andi.	r12,r9,MSR_EE
 	beq-	trace_syscall_entry_irq_off
@@ -704,7 +708,7 @@
 	stw	r10,_CCR(r1)
 	stw	r1,KSP(r3)	/* Set old stack pointer */
 
-	kuap_check r2, r4
+	kuap_check r2, r0
 #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
@@ -777,7 +781,7 @@
 1:	lis	r3,exc_exit_restart_end@ha
 	addi	r3,r3,exc_exit_restart_end@l
 	cmplw	r12,r3
-#if CONFIG_PPC_BOOK3S_601
+#ifdef CONFIG_PPC_BOOK3S_601
 	bge	2b
 #else
 	bge	3f
@@ -785,7 +789,7 @@
 	lis	r4,exc_exit_restart@ha
 	addi	r4,r4,exc_exit_restart@l
 	cmplw	r12,r4
-#if CONFIG_PPC_BOOK3S_601
+#ifdef CONFIG_PPC_BOOK3S_601
 	blt	2b
 #else
 	blt	3f
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/entry_64.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/entry_64.S
@@ -537,6 +537,7 @@
 	/* Save LR into r9 */
 	mflr	r9
 
+	// Flush the link stack
 	.rept 64
 	bl	.+4
 	.endr
@@ -546,6 +547,11 @@
 	.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
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/exceptions-64s.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/exceptions-64s.S
@@ -1090,17 +1090,19 @@
 	bl	machine_check_queue_event
 
 	/*
-	 * We have not used any non-volatile GPRs here, and as a rule
-	 * most exception code including machine check does not.
-	 * Therefore PACA_NAPSTATELOST does not need to be set. Idle
-	 * wakeup will restore volatile registers.
+	 * GPR-loss wakeups are relatively straightforward, because the
+	 * idle sleep code has saved all non-volatile registers on its
+	 * own stack, and r1 in PACAR1.
 	 *
-	 * Load the original SRR1 into r3 for pnv_powersave_wakeup_mce.
+	 * For no-loss wakeups the r1 and lr registers used by the
+	 * early machine check handler have to be restored first. r2 is
+	 * the kernel TOC, so no need to restore it.
 	 *
 	 * Then decrement MCE nesting after finishing with the stack.
 	 */
 	ld	r3,_MSR(r1)
 	ld	r4,_LINK(r1)
+	ld	r1,GPR1(r1)
 
 	lhz	r11,PACA_IN_MCE(r13)
 	subi	r11,r11,1
@@ -1109,7 +1111,7 @@
 	mtlr	r4
 	rlwinm	r10,r3,47-31,30,31
 	cmpwi	cr1,r10,2
-	bltlr	cr1	/* no state loss, return to idle caller */
+	bltlr	cr1	/* no state loss, return to idle caller with r3=SRR1 */
 	b	idle_return_gpr_loss
 #endif
 
@@ -1148,7 +1150,7 @@
 	INT_HANDLER data_access, 0x300, ool=1, dar=1, dsisr=1, kvm=1
 EXC_REAL_END(data_access, 0x300, 0x80)
 EXC_VIRT_BEGIN(data_access, 0x4300, 0x80)
-	INT_HANDLER data_access, 0x300, virt=1, dar=1, dsisr=1
+	INT_HANDLER data_access, 0x300, ool=1, virt=1, dar=1, dsisr=1
 EXC_VIRT_END(data_access, 0x4300, 0x80)
 INT_KVM_HANDLER data_access, 0x300, EXC_STD, PACA_EXGEN, 1
 EXC_COMMON_BEGIN(data_access_common)
@@ -1203,7 +1205,7 @@
 
 
 EXC_REAL_BEGIN(instruction_access, 0x400, 0x80)
-	INT_HANDLER instruction_access, 0x400, kvm=1
+	INT_HANDLER instruction_access, 0x400, ool=1, kvm=1
 EXC_REAL_END(instruction_access, 0x400, 0x80)
 EXC_VIRT_BEGIN(instruction_access, 0x4400, 0x80)
 	INT_HANDLER instruction_access, 0x400, virt=1
@@ -1223,7 +1225,7 @@
 
 
 EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x80)
-	INT_HANDLER instruction_access_slb, 0x480, area=PACA_EXSLB, kvm=1
+	INT_HANDLER instruction_access_slb, 0x480, ool=1, area=PACA_EXSLB, kvm=1
 EXC_REAL_END(instruction_access_slb, 0x480, 0x80)
 EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x80)
 	INT_HANDLER instruction_access_slb, 0x480, virt=1, area=PACA_EXSLB
@@ -1363,17 +1365,17 @@
 	INT_HANDLER decrementer, 0x900, ool=1, bitmask=IRQS_DISABLED, kvm=1
 EXC_REAL_END(decrementer, 0x900, 0x80)
 EXC_VIRT_BEGIN(decrementer, 0x4900, 0x80)
-	INT_HANDLER decrementer, 0x900, virt=1, bitmask=IRQS_DISABLED
+	INT_HANDLER decrementer, 0x900, ool=1, virt=1, bitmask=IRQS_DISABLED
 EXC_VIRT_END(decrementer, 0x4900, 0x80)
 INT_KVM_HANDLER decrementer, 0x900, EXC_STD, PACA_EXGEN, 0
 EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt)
 
 
 EXC_REAL_BEGIN(hdecrementer, 0x980, 0x80)
-	INT_HANDLER hdecrementer, 0x980, hsrr=EXC_HV, kvm=1
+	INT_HANDLER hdecrementer, 0x980, ool=1, hsrr=EXC_HV, kvm=1
 EXC_REAL_END(hdecrementer, 0x980, 0x80)
 EXC_VIRT_BEGIN(hdecrementer, 0x4980, 0x80)
-	INT_HANDLER hdecrementer, 0x980, virt=1, hsrr=EXC_HV, kvm=1
+	INT_HANDLER hdecrementer, 0x980, ool=1, virt=1, hsrr=EXC_HV, kvm=1
 EXC_VIRT_END(hdecrementer, 0x4980, 0x80)
 INT_KVM_HANDLER hdecrementer, 0x980, EXC_HV, PACA_EXGEN, 0
 EXC_COMMON(hdecrementer_common, 0x980, hdec_interrupt)
@@ -2044,15 +2046,8 @@
 	.endr
 	blr
 
-TRAMP_REAL_BEGIN(rfi_flush_fallback)
-	SET_SCRATCH0(r13);
-	GET_PACA(r13);
-	std	r1,PACA_EXRFI+EX_R12(r13)
-	ld	r1,PACAKSAVE(r13)
-	std	r9,PACA_EXRFI+EX_R9(r13)
-	std	r10,PACA_EXRFI+EX_R10(r13)
-	std	r11,PACA_EXRFI+EX_R11(r13)
-	mfctr	r9
+/* 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 */
@@ -2063,7 +2058,7 @@
 	sync
 
 	/*
-	 * The load adresses are at staggered offsets within cachelines,
+	 * The load addresses are at staggered offsets within cachelines,
 	 * which suits some pipelines better (on others it should not
 	 * hurt).
 	 */
@@ -2078,7 +2073,30 @@
 	ld	r11,(0x80 + 8)*7(r10)
 	addi	r10,r10,0x80*8
 	bdnz	1b
+.endm
 
+TRAMP_REAL_BEGIN(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
+
+TRAMP_REAL_BEGIN(rfi_flush_fallback)
+	SET_SCRATCH0(r13);
+	GET_PACA(r13);
+	std	r1,PACA_EXRFI+EX_R12(r13)
+	ld	r1,PACAKSAVE(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)
@@ -2096,32 +2114,7 @@
 	std	r10,PACA_EXRFI+EX_R10(r13)
 	std	r11,PACA_EXRFI+EX_R11(r13)
 	mfctr	r9
-	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_BOOK3S_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
-
-	/* order ld/st prior to dcbt stop all streams with flushing */
-	sync
-
-	/*
-	 * The load adresses 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
-
+	L1D_DISPLACEMENT_FLUSH
 	mtctr	r9
 	ld	r9,PACA_EXRFI+EX_R9(r13)
 	ld	r10,PACA_EXRFI+EX_R10(r13)
@@ -2130,6 +2123,19 @@
 	GET_SCRATCH0(r13);
 	hrfid
 
+USE_TEXT_SECTION()
+
+_GLOBAL(do_uaccess_flush)
+	UACCESS_FLUSH_FIXUP_SECTION
+	nop
+	nop
+	nop
+	blr
+	L1D_DISPLACEMENT_FLUSH
+	blr
+_ASM_NOKPROBE_SYMBOL(do_uaccess_flush)
+EXPORT_SYMBOL(do_uaccess_flush)
+
 /*
  * Real mode exceptions actually use this too, but alternate
  * instruction code patches (which end up in the common .text area)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/fadump.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/fadump.c
@@ -38,8 +38,17 @@
 
 #ifndef CONFIG_PRESERVE_FA_DUMP
 static DEFINE_MUTEX(fadump_mutex);
-struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 };
-struct fadump_mrange_info reserved_mrange_info = { "reserved", NULL, 0, 0, 0 };
+struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0, false };
+
+#define RESERVED_RNGS_SZ	16384 /* 16K - 128 entries */
+#define RESERVED_RNGS_CNT	(RESERVED_RNGS_SZ / \
+				 sizeof(struct fadump_memory_range))
+static struct fadump_memory_range rngs[RESERVED_RNGS_CNT];
+struct fadump_mrange_info reserved_mrange_info = { "reserved", rngs,
+						   RESERVED_RNGS_SZ, 0,
+						   RESERVED_RNGS_CNT, true };
+
+static void __init early_init_dt_scan_reserved_ranges(unsigned long node);
 
 #ifdef CONFIG_CMA
 static struct cma *fadump_cma;
@@ -108,6 +117,11 @@
 int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
 				      int depth, void *data)
 {
+	if (depth == 0) {
+		early_init_dt_scan_reserved_ranges(node);
+		return 0;
+	}
+
 	if (depth != 1)
 		return 0;
 
@@ -265,7 +279,7 @@
  * that is required for a kernel to boot successfully.
  *
  */
-static inline u64 fadump_calculate_reserve_size(void)
+static __init u64 fadump_calculate_reserve_size(void)
 {
 	u64 base, size, bootmem_min;
 	int ret;
@@ -429,10 +443,72 @@
 	return ret;
 }
 
+/*
+ * Returns true, if the given range overlaps with reserved memory ranges
+ * starting at idx. Also, updates idx to index of overlapping memory range
+ * with the given memory range.
+ * False, otherwise.
+ */
+static bool overlaps_reserved_ranges(u64 base, u64 end, int *idx)
+{
+	bool ret = false;
+	int i;
+
+	for (i = *idx; i < reserved_mrange_info.mem_range_cnt; i++) {
+		u64 rbase = reserved_mrange_info.mem_ranges[i].base;
+		u64 rend = rbase + reserved_mrange_info.mem_ranges[i].size;
+
+		if (end <= rbase)
+			break;
+
+		if ((end > rbase) &&  (base < rend)) {
+			*idx = i;
+			ret = true;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Locate a suitable memory area to reserve memory for FADump. While at it,
+ * lookup reserved-ranges & avoid overlap with them, as they are used by F/W.
+ */
+static u64 __init fadump_locate_reserve_mem(u64 base, u64 size)
+{
+	struct fadump_memory_range *mrngs;
+	phys_addr_t mstart, mend;
+	int idx = 0;
+	u64 i, ret = 0;
+
+	mrngs = reserved_mrange_info.mem_ranges;
+	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
+				&mstart, &mend, NULL) {
+		pr_debug("%llu) mstart: %llx, mend: %llx, base: %llx\n",
+			 i, mstart, mend, base);
+
+		if (mstart > base)
+			base = PAGE_ALIGN(mstart);
+
+		while ((mend > base) && ((mend - base) >= size)) {
+			if (!overlaps_reserved_ranges(base, base+size, &idx)) {
+				ret = base;
+				goto out;
+			}
+
+			base = mrngs[idx].base + mrngs[idx].size;
+			base = PAGE_ALIGN(base);
+		}
+	}
+
+out:
+	return ret;
+}
+
 int __init fadump_reserve_mem(void)
 {
-	u64 base, size, mem_boundary, bootmem_min, align = PAGE_SIZE;
-	bool is_memblock_bottom_up = memblock_bottom_up();
+	u64 base, size, mem_boundary, bootmem_min;
 	int ret = 1;
 
 	if (!fw_dump.fadump_enabled)
@@ -453,9 +529,9 @@
 			PAGE_ALIGN(fadump_calculate_reserve_size());
 #ifdef CONFIG_CMA
 		if (!fw_dump.nocma) {
-			align = FADUMP_CMA_ALIGNMENT;
 			fw_dump.boot_memory_size =
-				ALIGN(fw_dump.boot_memory_size, align);
+				ALIGN(fw_dump.boot_memory_size,
+				      FADUMP_CMA_ALIGNMENT);
 		}
 #endif
 
@@ -523,13 +599,9 @@
 		 * Reserve memory at an offset closer to bottom of the RAM to
 		 * minimize the impact of memory hot-remove operation.
 		 */
-		memblock_set_bottom_up(true);
-		base = memblock_find_in_range(base, mem_boundary, size, align);
-
-		/* Restore the previous allocation mode */
-		memblock_set_bottom_up(is_memblock_bottom_up);
+		base = fadump_locate_reserve_mem(base, size);
 
-		if (!base) {
+		if (!base || (base + size > mem_boundary)) {
 			pr_err("Failed to find memory chunk for reservation!\n");
 			goto error_out;
 		}
@@ -557,6 +629,7 @@
 	return ret;
 error_out:
 	fw_dump.fadump_enabled = 0;
+	fw_dump.reserve_dump_area_size = 0;
 	return 0;
 }
 
@@ -726,10 +799,14 @@
 
 static void fadump_free_mem_ranges(struct fadump_mrange_info *mrange_info)
 {
+	if (mrange_info->is_static) {
+		mrange_info->mem_range_cnt = 0;
+		return;
+	}
+
 	kfree(mrange_info->mem_ranges);
-	mrange_info->mem_ranges = NULL;
-	mrange_info->mem_ranges_sz = 0;
-	mrange_info->max_mem_ranges = 0;
+	memset((void *)((u64)mrange_info + RNG_NAME_SZ), 0,
+	       (sizeof(struct fadump_mrange_info) - RNG_NAME_SZ));
 }
 
 /*
@@ -759,7 +836,6 @@
 				       sizeof(struct fadump_memory_range));
 	return 0;
 }
-
 static inline int fadump_add_mem_range(struct fadump_mrange_info *mrange_info,
 				       u64 base, u64 end)
 {
@@ -778,7 +854,12 @@
 		start = mem_ranges[mrange_info->mem_range_cnt - 1].base;
 		size  = mem_ranges[mrange_info->mem_range_cnt - 1].size;
 
-		if ((start + size) == base)
+		/*
+		 * Boot memory area needs separate PT_LOAD segment(s) as it
+		 * is moved to a different location at the time of crash.
+		 * So, fold only if the region is not boot memory area.
+		 */
+		if ((start + size) == base && start >= fw_dump.boot_mem_top)
 			is_adjacent = true;
 	}
 	if (!is_adjacent) {
@@ -786,6 +867,12 @@
 		if (mrange_info->mem_range_cnt == mrange_info->max_mem_ranges) {
 			int ret;
 
+			if (mrange_info->is_static) {
+				pr_err("Reached array size limit for %s memory ranges\n",
+				       mrange_info->name);
+				return -ENOSPC;
+			}
+
 			ret = fadump_alloc_mem_ranges(mrange_info);
 			if (ret)
 				return ret;
@@ -1202,20 +1289,19 @@
  * Scan reserved-ranges to consider them while reserving/releasing
  * memory for FADump.
  */
-static inline int fadump_scan_reserved_mem_ranges(void)
+static void __init early_init_dt_scan_reserved_ranges(unsigned long node)
 {
-	struct device_node *root;
 	const __be32 *prop;
 	int len, ret = -1;
 	unsigned long i;
 
-	root = of_find_node_by_path("/");
-	if (!root)
-		return ret;
+	/* reserved-ranges already scanned */
+	if (reserved_mrange_info.mem_range_cnt != 0)
+		return;
 
-	prop = of_get_property(root, "reserved-ranges", &len);
+	prop = of_get_flat_dt_prop(node, "reserved-ranges", &len);
 	if (!prop)
-		return ret;
+		return;
 
 	/*
 	 * Each reserved range is an (address,size) pair, 2 cells each,
@@ -1237,7 +1323,8 @@
 		}
 	}
 
-	return ret;
+	/* Compact reserved ranges */
+	sort_and_merge_mem_ranges(&reserved_mrange_info);
 }
 
 /*
@@ -1251,32 +1338,21 @@
 	u64 ra_start, ra_end, tstart;
 	int i, ret;
 
-	fadump_scan_reserved_mem_ranges();
-
 	ra_start = fw_dump.reserve_dump_area_start;
 	ra_end = ra_start + fw_dump.reserve_dump_area_size;
 
 	/*
-	 * Add reserved dump area to reserved ranges list
-	 * and exclude all these ranges while releasing memory.
+	 * If reserved ranges array limit is hit, overwrite the last reserved
+	 * memory range with reserved dump area to ensure it is excluded from
+	 * the memory being released (reused for next FADump registration).
 	 */
-	ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
-	if (ret != 0) {
-		/*
-		 * Not enough memory to setup reserved ranges but the system is
-		 * running shortage of memory. So, release all the memory except
-		 * Reserved dump area (reused for next fadump registration).
-		 */
-		if (begin < ra_end && end > ra_start) {
-			if (begin < ra_start)
-				fadump_release_reserved_area(begin, ra_start);
-			if (end > ra_end)
-				fadump_release_reserved_area(ra_end, end);
-		} else
-			fadump_release_reserved_area(begin, end);
+	if (reserved_mrange_info.mem_range_cnt ==
+	    reserved_mrange_info.max_mem_ranges)
+		reserved_mrange_info.mem_range_cnt--;
 
+	ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
+	if (ret != 0)
 		return;
-	}
 
 	/* Get the reserved ranges list in order first. */
 	sort_and_merge_mem_ranges(&reserved_mrange_info);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/fpu.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/fpu.S
@@ -24,6 +24,15 @@
 #include <asm/feature-fixups.h>
 
 #ifdef CONFIG_VSX
+#define __REST_1FPVSR(n,c,base)						\
+BEGIN_FTR_SECTION							\
+	b	2f;							\
+END_FTR_SECTION_IFSET(CPU_FTR_VSX);					\
+	REST_FPR(n,base);						\
+	b	3f;							\
+2:	REST_VSR(n,c,base);						\
+3:
+
 #define __REST_32FPVSRS(n,c,base)					\
 BEGIN_FTR_SECTION							\
 	b	2f;							\
@@ -42,9 +51,11 @@
 2:	SAVE_32VSRS(n,c,base);						\
 3:
 #else
+#define __REST_1FPVSR(n,b,base)		REST_FPR(n, base)
 #define __REST_32FPVSRS(n,b,base)	REST_32FPRS(n, base)
 #define __SAVE_32FPVSRS(n,b,base)	SAVE_32FPRS(n, base)
 #endif
+#define REST_1FPVSR(n,c,base)   __REST_1FPVSR(n,__REG_##c,__REG_##base)
 #define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base)
 #define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
 
@@ -68,6 +79,7 @@
 	SAVE_32FPVSRS(0, R4, R3)
 	mffs	fr0
 	stfd	fr0,FPSTATE_FPSCR(r3)
+	REST_1FPVSR(0, R4, R3)
 	blr
 EXPORT_SYMBOL(store_fp_state)
 
@@ -132,6 +144,7 @@
 2:	SAVE_32FPVSRS(0, R4, R6)
 	mffs	fr0
 	stfd	fr0,FPSTATE_FPSCR(r6)
+	REST_1FPVSR(0, R4, R6)
 	blr
 
 /*
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/head_32.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/head_32.S
@@ -418,14 +418,11 @@
 	cmplw	0,r1,r3
 #endif
 	mfspr	r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
-#else
-	li	r1,_PAGE_PRESENT | _PAGE_EXEC
-#endif
+	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
 #if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
 	bge-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
+	li	r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 #endif
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
@@ -484,13 +481,10 @@
 	lis	r1,PAGE_OFFSET@h		/* check if kernel address */
 	cmplw	0,r1,r3
 	mfspr	r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED
-#else
-	li	r1, _PAGE_PRESENT
-#endif
+	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
 	bge-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
+	li	r1, _PAGE_PRESENT | _PAGE_ACCESSED
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r2,0(r2)		/* get pmd entry */
@@ -564,13 +558,10 @@
 	lis	r1,PAGE_OFFSET@h		/* check if kernel address */
 	cmplw	0,r1,r3
 	mfspr	r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
-#else
-	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT
-#endif
+	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
 	bge-	112f
 	lis	r2, (swapper_pg_dir - PAGE_OFFSET)@ha	/* if kernel address, use */
+	li	r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
 	addi	r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l	/* kernel page table */
 112:	rlwimi	r2,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r2,0(r2)		/* get pmd entry */
@@ -843,7 +834,7 @@
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 	blr
 
-load_segment_registers:
+_GLOBAL(load_segment_registers)
 	li	r0, NUM_USER_SEGMENTS /* load up user segment register values */
 	mtctr	r0		/* for context 0 */
 	li	r3, 0		/* Kp = 0, Ks = 0, VSID = 0 */
@@ -931,7 +922,7 @@
 	 */
 	lis	r5, abatron_pteptrs@h
 	ori	r5, r5, abatron_pteptrs@l
-	stw	r5, 0xf0(r0)	/* This much match your Abatron config */
+	stw	r5, 0xf0(0)	/* This much match your Abatron config */
 	lis	r6, swapper_pg_dir@h
 	ori	r6, r6, swapper_pg_dir@l
 	tophys(r5, r5)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/head_64.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/head_64.S
@@ -420,6 +420,10 @@
 	/* From now on, r24 is expected to be logical cpuid */
 	mr	r24,r5
 
+	/* Create a temp kernel stack for use before relocation is on.	*/
+	ld	r1,PACAEMERGSP(r13)
+	subi	r1,r1,STACK_FRAME_OVERHEAD
+
 	/* See if we need to call a cpu state restore handler */
 	LOAD_REG_ADDR(r23, cur_cpu_spec)
 	ld	r23,0(r23)
@@ -448,10 +452,6 @@
 	sync				/* order paca.run and cur_cpu_spec */
 	isync				/* In case code patching happened */
 
-	/* Create a temp kernel stack for use before relocation is on.	*/
-	ld	r1,PACAEMERGSP(r13)
-	subi	r1,r1,STACK_FRAME_OVERHEAD
-
 	b	__secondary_start
 #endif /* SMP */
 
@@ -945,15 +945,8 @@
 	std	r0,0(r4)
 #endif
 
-	/* The following gets the stack set up with the regs */
-	/* pointing to the real addr of the kernel stack.  This is   */
-	/* all done to support the C function call below which sets  */
-	/* up the htab.  This is done because we have relocated the  */
-	/* kernel but are still running in real mode. */
-
-	LOAD_REG_ADDR(r3,init_thread_union)
-
 	/* set up a stack pointer */
+	LOAD_REG_ADDR(r3,init_thread_union)
 	LOAD_REG_IMMEDIATE(r1,THREAD_SIZE)
 	add	r1,r3,r1
 	li	r0,0
@@ -999,7 +992,7 @@
 	bl	start_kernel
 
 	/* Not reached */
-	trap
+0:	trap
 	EMIT_BUG_ENTRY 0b, __FILE__, __LINE__, 0
 
 /*
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/head_8xx.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/head_8xx.S
@@ -191,7 +191,7 @@
 /* On the MPC8xx, this is a software emulation interrupt.  It occurs
  * for all unimplemented and illegal instructions.
  */
-	EXCEPTION(0x1000, SoftEmu, program_check_exception, EXC_XFER_STD)
+	EXCEPTION(0x1000, SoftEmu, emulation_assist_interrupt, EXC_XFER_STD)
 
 /* Called from DataStoreTLBMiss when perf TLB misses events are activated */
 #ifdef CONFIG_PERF_EVENTS
@@ -229,9 +229,7 @@
 
 InstructionTLBMiss:
 	mtspr	SPRN_SPRG_SCRATCH0, r10
-#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
 	mtspr	SPRN_SPRG_SCRATCH1, r11
-#endif
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
@@ -278,27 +276,23 @@
 #ifdef ITLB_MISS_KERNEL
 	mtcr	r11
 #endif
-#ifdef CONFIG_SWAP
-	rlwinm	r11, r10, 32-5, _PAGE_PRESENT
+	rlwinm	r11, r10, 32-7, _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 20 and 23 must be clear.
 	 * Software indicator bits 22, 24, 25, 26, and 27 must be
 	 * set.  All other Linux PTE bits control the behavior
 	 * of the MMU.
 	 */
-	rlwimi	r10, r10, 0, 0x0f00	/* Clear bits 20-23 */
+	rlwinm	r10, r10, 0, ~0x0f00	/* Clear bits 20-23 */
 	rlwimi	r10, r10, 4, 0x0400	/* Copy _PAGE_EXEC into bit 21 */
 	ori	r10, r10, RPN_PATTERN | 0x200 /* Set 22 and 24-27 */
 	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */
 
 	/* Restore registers */
 0:	mfspr	r10, SPRN_SPRG_SCRATCH0
-#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
 	mfspr	r11, SPRN_SPRG_SCRATCH1
-#endif
 	rfi
 	patch_site	0b, patch__itlbmiss_exit_1
 
@@ -308,9 +302,7 @@
 	addi	r10, r10, 1
 	stw	r10, (itlb_miss_counter - PAGE_OFFSET)@l(0)
 	mfspr	r10, SPRN_SPRG_SCRATCH0
-#if defined(ITLB_MISS_KERNEL) || defined(CONFIG_SWAP)
 	mfspr	r11, SPRN_SPRG_SCRATCH1
-#endif
 	rfi
 #endif
 
@@ -394,11 +386,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-7, _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 24, 25, 26, and 27 must be
 	 * set.  All other Linux PTE bits control the behavior
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/head_fsl_booke.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/head_fsl_booke.S
@@ -238,6 +238,9 @@
 
 	bl	early_init
 
+#ifdef CONFIG_KASAN
+	bl	kasan_early_init
+#endif
 #ifdef CONFIG_RELOCATABLE
 	mr	r3,r30
 	mr	r4,r31
@@ -264,9 +267,6 @@
 /*
  * Decide what sort of machine this is and initialize the MMU.
  */
-#ifdef CONFIG_KASAN
-	bl	kasan_early_init
-#endif
 	mr	r3,r30
 	mr	r4,r31
 	bl	machine_init
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/hw_breakpoint.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/hw_breakpoint.c
@@ -247,6 +247,11 @@
 	return false;
 }
 
+/*
+ * Handle a DABR or DAWR exception.
+ *
+ * Called in atomic context.
+ */
 int hw_breakpoint_handler(struct die_args *args)
 {
 	int rc = NOTIFY_STOP;
@@ -315,6 +320,8 @@
 
 /*
  * Handle single-step exceptions following a DABR hit.
+ *
+ * Called in atomic context.
  */
 static int single_step_dabr_instruction(struct die_args *args)
 {
@@ -355,6 +362,8 @@
 
 /*
  * Handle debug exception notifications.
+ *
+ * Called in atomic context.
  */
 int hw_breakpoint_exceptions_notify(
 		struct notifier_block *unused, unsigned long val, void *data)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/idle.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/idle.c
@@ -37,7 +37,7 @@
 {
 	ppc_md.power_save = NULL;
 	cpuidle_disable = IDLE_POWERSAVE_OFF;
-	return 0;
+	return 1;
 }
 __setup("powersave=off", powersave_off);
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/idle_6xx.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/idle_6xx.S
@@ -129,7 +129,7 @@
 END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	mtspr	SPRN_HID0,r4
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	lwz	r8,TI_LOCAL_FLAGS(r2)	/* set napping bit */
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/idle_book3s.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/idle_book3s.S
@@ -50,28 +50,32 @@
 	std	r1,PACAR1(r13)
 	mflr	r4
 	mfcr	r5
-	/* use stack red zone rather than a new frame for saving regs */
-	std	r2,-8*0(r1)
-	std	r14,-8*1(r1)
-	std	r15,-8*2(r1)
-	std	r16,-8*3(r1)
-	std	r17,-8*4(r1)
-	std	r18,-8*5(r1)
-	std	r19,-8*6(r1)
-	std	r20,-8*7(r1)
-	std	r21,-8*8(r1)
-	std	r22,-8*9(r1)
-	std	r23,-8*10(r1)
-	std	r24,-8*11(r1)
-	std	r25,-8*12(r1)
-	std	r26,-8*13(r1)
-	std	r27,-8*14(r1)
-	std	r28,-8*15(r1)
-	std	r29,-8*16(r1)
-	std	r30,-8*17(r1)
-	std	r31,-8*18(r1)
-	std	r4,-8*19(r1)
-	std	r5,-8*20(r1)
+	/*
+	 * Use the stack red zone rather than a new frame for saving regs since
+	 * in the case of no GPR loss the wakeup code branches directly back to
+	 * the caller without deallocating the stack frame first.
+	 */
+	std	r2,-8*1(r1)
+	std	r14,-8*2(r1)
+	std	r15,-8*3(r1)
+	std	r16,-8*4(r1)
+	std	r17,-8*5(r1)
+	std	r18,-8*6(r1)
+	std	r19,-8*7(r1)
+	std	r20,-8*8(r1)
+	std	r21,-8*9(r1)
+	std	r22,-8*10(r1)
+	std	r23,-8*11(r1)
+	std	r24,-8*12(r1)
+	std	r25,-8*13(r1)
+	std	r26,-8*14(r1)
+	std	r27,-8*15(r1)
+	std	r28,-8*16(r1)
+	std	r29,-8*17(r1)
+	std	r30,-8*18(r1)
+	std	r31,-8*19(r1)
+	std	r4,-8*20(r1)
+	std	r5,-8*21(r1)
 	/* 168 bytes */
 	PPC_STOP
 	b	.	/* catch bugs */
@@ -87,8 +91,8 @@
  */
 _GLOBAL(idle_return_gpr_loss)
 	ld	r1,PACAR1(r13)
-	ld	r4,-8*19(r1)
-	ld	r5,-8*20(r1)
+	ld	r4,-8*20(r1)
+	ld	r5,-8*21(r1)
 	mtlr	r4
 	mtcr	r5
 	/*
@@ -96,38 +100,40 @@
 	 * from PACATOC. This could be avoided for that less common case
 	 * if KVM saved its r2.
 	 */
-	ld	r2,-8*0(r1)
-	ld	r14,-8*1(r1)
-	ld	r15,-8*2(r1)
-	ld	r16,-8*3(r1)
-	ld	r17,-8*4(r1)
-	ld	r18,-8*5(r1)
-	ld	r19,-8*6(r1)
-	ld	r20,-8*7(r1)
-	ld	r21,-8*8(r1)
-	ld	r22,-8*9(r1)
-	ld	r23,-8*10(r1)
-	ld	r24,-8*11(r1)
-	ld	r25,-8*12(r1)
-	ld	r26,-8*13(r1)
-	ld	r27,-8*14(r1)
-	ld	r28,-8*15(r1)
-	ld	r29,-8*16(r1)
-	ld	r30,-8*17(r1)
-	ld	r31,-8*18(r1)
+	ld	r2,-8*1(r1)
+	ld	r14,-8*2(r1)
+	ld	r15,-8*3(r1)
+	ld	r16,-8*4(r1)
+	ld	r17,-8*5(r1)
+	ld	r18,-8*6(r1)
+	ld	r19,-8*7(r1)
+	ld	r20,-8*8(r1)
+	ld	r21,-8*9(r1)
+	ld	r22,-8*10(r1)
+	ld	r23,-8*11(r1)
+	ld	r24,-8*12(r1)
+	ld	r25,-8*13(r1)
+	ld	r26,-8*14(r1)
+	ld	r27,-8*15(r1)
+	ld	r28,-8*16(r1)
+	ld	r29,-8*17(r1)
+	ld	r30,-8*18(r1)
+	ld	r31,-8*19(r1)
 	blr
 
 /*
  * This is the sequence required to execute idle instructions, as
  * specified in ISA v2.07 (and earlier). MSR[IR] and MSR[DR] must be 0.
- *
- * The 0(r1) slot is used to save r2 in isa206, so use that here.
+ * We have to store a GPR somewhere, ptesync, then reload it, and create
+ * a false dependency on the result of the load. It doesn't matter which
+ * GPR we store, or where we store it. We have already stored r2 to the
+ * stack at -8(r1) in isa206_idle_insn_mayloss, so use that.
  */
 #define IDLE_STATE_ENTER_SEQ_NORET(IDLE_INST)			\
 	/* Magic NAP/SLEEP/WINKLE mode enter sequence */	\
-	std	r2,0(r1);					\
+	std	r2,-8(r1);					\
 	ptesync;						\
-	ld	r2,0(r1);					\
+	ld	r2,-8(r1);					\
 236:	cmpd	cr0,r2,r2;					\
 	bne	236b;						\
 	IDLE_INST;						\
@@ -152,28 +158,32 @@
 	std	r1,PACAR1(r13)
 	mflr	r4
 	mfcr	r5
-	/* use stack red zone rather than a new frame for saving regs */
-	std	r2,-8*0(r1)
-	std	r14,-8*1(r1)
-	std	r15,-8*2(r1)
-	std	r16,-8*3(r1)
-	std	r17,-8*4(r1)
-	std	r18,-8*5(r1)
-	std	r19,-8*6(r1)
-	std	r20,-8*7(r1)
-	std	r21,-8*8(r1)
-	std	r22,-8*9(r1)
-	std	r23,-8*10(r1)
-	std	r24,-8*11(r1)
-	std	r25,-8*12(r1)
-	std	r26,-8*13(r1)
-	std	r27,-8*14(r1)
-	std	r28,-8*15(r1)
-	std	r29,-8*16(r1)
-	std	r30,-8*17(r1)
-	std	r31,-8*18(r1)
-	std	r4,-8*19(r1)
-	std	r5,-8*20(r1)
+	/*
+	 * Use the stack red zone rather than a new frame for saving regs since
+	 * in the case of no GPR loss the wakeup code branches directly back to
+	 * the caller without deallocating the stack frame first.
+	 */
+	std	r2,-8*1(r1)
+	std	r14,-8*2(r1)
+	std	r15,-8*3(r1)
+	std	r16,-8*4(r1)
+	std	r17,-8*5(r1)
+	std	r18,-8*6(r1)
+	std	r19,-8*7(r1)
+	std	r20,-8*8(r1)
+	std	r21,-8*9(r1)
+	std	r22,-8*10(r1)
+	std	r23,-8*11(r1)
+	std	r24,-8*12(r1)
+	std	r25,-8*13(r1)
+	std	r26,-8*14(r1)
+	std	r27,-8*15(r1)
+	std	r28,-8*16(r1)
+	std	r29,-8*17(r1)
+	std	r30,-8*18(r1)
+	std	r31,-8*19(r1)
+	std	r4,-8*20(r1)
+	std	r5,-8*21(r1)
 	cmpwi	r3,PNV_THREAD_NAP
 	bne	1f
 	IDLE_STATE_ENTER_SEQ_NORET(PPC_NAP)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/ima_arch.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/ima_arch.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain
+ */
+
+#include <linux/ima.h>
+#include <asm/secure_boot.h>
+
+bool arch_ima_get_secureboot(void)
+{
+	return is_ppc_secureboot_enabled();
+}
+
+/*
+ * The "secure_rules" are enabled only on "secureboot" enabled systems.
+ * These rules verify the file signatures against known good values.
+ * The "appraise_type=imasig|modsig" option allows the known good signature
+ * to be stored as an xattr or as an appended signature.
+ *
+ * To avoid duplicate signature verification as much as possible, the IMA
+ * policy rule for module appraisal is added only if CONFIG_MODULE_SIG
+ * is not enabled.
+ */
+static const char *const secure_rules[] = {
+	"appraise func=KEXEC_KERNEL_CHECK appraise_flag=check_blacklist appraise_type=imasig|modsig",
+#ifndef CONFIG_MODULE_SIG
+	"appraise func=MODULE_CHECK appraise_flag=check_blacklist appraise_type=imasig|modsig",
+#endif
+	NULL
+};
+
+/*
+ * The "trusted_rules" are enabled only on "trustedboot" enabled systems.
+ * These rules add the kexec kernel image and kernel modules file hashes to
+ * the IMA measurement list.
+ */
+static const char *const trusted_rules[] = {
+	"measure func=KEXEC_KERNEL_CHECK",
+	"measure func=MODULE_CHECK",
+	NULL
+};
+
+/*
+ * The "secure_and_trusted_rules" contains rules for both the secure boot and
+ * trusted boot. The "template=ima-modsig" option includes the appended
+ * signature, when available, in the IMA measurement list.
+ */
+static const char *const secure_and_trusted_rules[] = {
+	"measure func=KEXEC_KERNEL_CHECK template=ima-modsig",
+	"measure func=MODULE_CHECK template=ima-modsig",
+	"appraise func=KEXEC_KERNEL_CHECK appraise_flag=check_blacklist appraise_type=imasig|modsig",
+#ifndef CONFIG_MODULE_SIG
+	"appraise func=MODULE_CHECK appraise_flag=check_blacklist appraise_type=imasig|modsig",
+#endif
+	NULL
+};
+
+/*
+ * Returns the relevant IMA arch-specific policies based on the system secure
+ * boot state.
+ */
+const char *const *arch_get_ima_policy(void)
+{
+	if (is_ppc_secureboot_enabled()) {
+		if (IS_ENABLED(CONFIG_MODULE_SIG))
+			set_module_sig_enforced();
+
+		if (is_ppc_trustedboot_enabled())
+			return secure_and_trusted_rules;
+		else
+			return secure_rules;
+	} else if (is_ppc_trustedboot_enabled()) {
+		return trusted_rules;
+	}
+
+	return NULL;
+}
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/iommu.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/iommu.c
@@ -133,17 +133,28 @@
 	return 0;
 }
 
-static struct notifier_block fail_iommu_bus_notifier = {
+/*
+ * PCI and VIO buses need separate notifier_block structs, since they're linked
+ * list nodes.  Sharing a notifier_block would mean that any notifiers later
+ * registered for PCI buses would also get called by VIO buses and vice versa.
+ */
+static struct notifier_block fail_iommu_pci_bus_notifier = {
 	.notifier_call = fail_iommu_bus_notify
 };
 
+#ifdef CONFIG_IBMVIO
+static struct notifier_block fail_iommu_vio_bus_notifier = {
+	.notifier_call = fail_iommu_bus_notify
+};
+#endif
+
 static int __init fail_iommu_setup(void)
 {
 #ifdef CONFIG_PCI
-	bus_register_notifier(&pci_bus_type, &fail_iommu_bus_notifier);
+	bus_register_notifier(&pci_bus_type, &fail_iommu_pci_bus_notifier);
 #endif
 #ifdef CONFIG_IBMVIO
-	bus_register_notifier(&vio_bus_type, &fail_iommu_bus_notifier);
+	bus_register_notifier(&vio_bus_type, &fail_iommu_vio_bus_notifier);
 #endif
 
 	return 0;
@@ -1057,7 +1068,7 @@
 
 	spin_lock_irqsave(&tbl->large_pool.lock, flags);
 	for (i = 0; i < tbl->nr_pools; i++)
-		spin_lock(&tbl->pools[i].lock);
+		spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
 
 	iommu_table_release_pages(tbl);
 
@@ -1085,7 +1096,7 @@
 
 	spin_lock_irqsave(&tbl->large_pool.lock, flags);
 	for (i = 0; i < tbl->nr_pools; i++)
-		spin_lock(&tbl->pools[i].lock);
+		spin_lock_nest_lock(&tbl->pools[i].lock, &tbl->large_pool.lock);
 
 	memset(tbl->it_map, 0, sz);
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/irq.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/irq.c
@@ -619,8 +619,6 @@
 
 	trace_irq_entry(regs);
 
-	check_stack_overflow();
-
 	/*
 	 * Query the platform PIC for the interrupt & ack it.
 	 *
@@ -652,6 +650,8 @@
 	irqsp = hardirq_ctx[raw_smp_processor_id()];
 	sirqsp = softirq_ctx[raw_smp_processor_id()];
 
+	check_stack_overflow();
+
 	/* Already there ? */
 	if (unlikely(cursp == irqsp || cursp == sirqsp)) {
 		__do_irq(regs);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/kprobes.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/kprobes.c
@@ -264,6 +264,10 @@
 	if (user_mode(regs))
 		return 0;
 
+	if (!IS_ENABLED(CONFIG_BOOKE) &&
+	    (!(regs->msr & MSR_IR) || !(regs->msr & MSR_DR)))
+		return 0;
+
 	/*
 	 * We don't want to be preempted for the entire
 	 * duration of kprobe processing
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/kvm.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/kvm.c
@@ -669,7 +669,7 @@
 	on_each_cpu(kvm_map_magic_page, &features, 1);
 
 	/* Quick self-test to see if the mapping works */
-	if (!fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) {
+	if (fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) {
 		kvm_patching_worked = false;
 		return;
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/l2cr_6xx.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/l2cr_6xx.S
@@ -96,7 +96,7 @@
 
 	/* Stop DST streams */
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
@@ -293,7 +293,7 @@
 	isync
 
 	/* Stop DST streams */
-	DSSALL
+	PPC_DSSALL
 	sync
 
 	/* Get the current enable bit of the L3CR into r4 */
@@ -402,7 +402,7 @@
 _GLOBAL(__flush_disable_L1)
 	/* Stop pending alitvec streams and memory accesses */
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
  	sync
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/machine_kexec.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/machine_kexec.c
@@ -114,11 +114,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;
@@ -145,11 +146,18 @@
 	if (!crashk_res.start) {
 #ifdef CONFIG_PPC64
 		/*
-		 * On 64bit we split the RMO in half but cap it at half of
-		 * a small SLB (128MB) since the crash kernel needs to place
-		 * itself and some stacks to be in the first segment.
+		 * On the LPAR platform place the crash kernel to mid of
+		 * RMA size (512MB or more) to ensure the crash kernel
+		 * gets enough space to place itself and some stack to be
+		 * in the first segment. At the same time normal kernel
+		 * also get enough space to allocate memory for essential
+		 * system resource in the first segment. Keep the crash
+		 * kernel starts at 128MB offset on other platforms.
 		 */
-		crashk_res.start = min(0x8000000ULL, (ppc64_rma_size / 2));
+		if (firmware_has_feature(FW_FEATURE_LPAR))
+			crashk_res.start = ppc64_rma_size / 2;
+		else
+			crashk_res.start = min(0x8000000ULL, (ppc64_rma_size / 2));
 #else
 		crashk_res.start = KDUMP_KERNELBASE;
 #endif
@@ -177,6 +185,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);
 	}
@@ -185,7 +194,7 @@
 			"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));
 
 	if (!memblock_is_region_memory(crashk_res.start, crash_size) ||
 	    memblock_reserve(crashk_res.start, crash_size)) {
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/misc_32.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/misc_32.S
@@ -317,126 +317,6 @@
 #endif /* CONFIG_PPC_8xx */
 
 /*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- * This is a no-op on the 601.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- */
-_GLOBAL(flush_icache_range)
-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
-	PURGE_PREFETCHED_INS
-	blr				/* for 601 and e200, do nothing */
-#else
-	rlwinm	r3,r3,0,0,31 - L1_CACHE_SHIFT
-	subf	r4,r3,r4
-	addi	r4,r4,L1_CACHE_BYTES - 1
-	srwi.	r4,r4,L1_CACHE_SHIFT
-	beqlr
-	mtctr	r4
-	mr	r6,r3
-1:	dcbst	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	sync				/* wait for dcbst's to get to ram */
-#ifndef CONFIG_44x
-	mtctr	r4
-2:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	2b
-#else
-	/* Flash invalidate on 44x because we are passed kmapped addresses and
-	   this doesn't work for userspace pages due to the virtually tagged
-	   icache.  Sigh. */
-	iccci	0, r0
-#endif
-	sync				/* additional sync needed on g4 */
-	isync
-	blr
-#endif
-_ASM_NOKPROBE_SYMBOL(flush_icache_range)
-EXPORT_SYMBOL(flush_icache_range)
-
-/*
- * Flush a particular page from the data cache to RAM.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * This is a no-op on the 601 and e200 which have a unified cache.
- *
- *	void __flush_dcache_icache(void *page)
- */
-_GLOBAL(__flush_dcache_icache)
-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
-	PURGE_PREFETCHED_INS
-	blr
-#else
-	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
-	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
-	mtctr	r4
-	mr	r6,r3
-0:	dcbst	0,r3				/* Write line to ram */
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	0b
-	sync
-#ifdef CONFIG_44x
-	/* We don't flush the icache on 44x. Those have a virtual icache
-	 * and we don't have access to the virtual address here (it's
-	 * not the page vaddr but where it's mapped in user space). The
-	 * flushing of the icache on these is handled elsewhere, when
-	 * a change in the address space occurs, before returning to
-	 * user space
-	 */
-BEGIN_MMU_FTR_SECTION
-	blr
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
-#endif /* CONFIG_44x */
-	mtctr	r4
-1:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	1b
-	sync
-	isync
-	blr
-#endif
-
-#ifndef CONFIG_BOOKE
-/*
- * Flush a particular page from the data cache to RAM, identified
- * by its physical address.  We turn off the MMU so we can just use
- * the physical address (this may be a highmem page without a kernel
- * mapping).
- *
- *	void __flush_dcache_icache_phys(unsigned long physaddr)
- */
-_GLOBAL(__flush_dcache_icache_phys)
-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
-	PURGE_PREFETCHED_INS
-	blr					/* for 601 and e200, do nothing */
-#else
-	mfmsr	r10
-	rlwinm	r0,r10,0,28,26			/* clear DR */
-	mtmsr	r0
-	isync
-	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
-	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
-	mtctr	r4
-	mr	r6,r3
-0:	dcbst	0,r3				/* Write line to ram */
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	0b
-	sync
-	mtctr	r4
-1:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	1b
-	sync
-	mtmsr	r10				/* restore DR */
-	isync
-	blr
-#endif
-#endif /* CONFIG_BOOKE */
-
-/*
  * Copy a whole page.  We use the dcbz instruction on the destination
  * to reduce memory traffic (it eliminates the unnecessary reads of
  * the destination into cache).  This requires that the destination
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/misc_64.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/misc_64.S
@@ -49,108 +49,6 @@
 	mtlr	r0
 	blr
 
-	.section	".toc","aw"
-PPC64_CACHES:
-	.tc		ppc64_caches[TC],ppc64_caches
-	.section	".text"
-
-/*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- *
- *   flush all bytes from start through stop-1 inclusive
- */
-
-_GLOBAL_TOC(flush_icache_range)
-BEGIN_FTR_SECTION
-	PURGE_PREFETCHED_INS
-	blr
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-/*
- * Flush the data cache to memory 
- * 
- * Different systems have different cache line sizes
- * and in some cases i-cache and d-cache line sizes differ from
- * each other.
- */
- 	ld	r10,PPC64_CACHES@toc(r2)
-	lwz	r7,DCACHEL1BLOCKSIZE(r10)/* Get cache block size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5		/* ensure we get enough */
-	lwz	r9,DCACHEL1LOGBLOCKSIZE(r10)	/* Get log-2 of cache block size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mtctr	r8
-1:	dcbst	0,r6
-	add	r6,r6,r7
-	bdnz	1b
-	sync
-
-/* Now invalidate the instruction cache */
-	
-	lwz	r7,ICACHEL1BLOCKSIZE(r10)	/* Get Icache block size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5
-	lwz	r9,ICACHEL1LOGBLOCKSIZE(r10)	/* Get log-2 of Icache block size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mtctr	r8
-2:	icbi	0,r6
-	add	r6,r6,r7
-	bdnz	2b
-	isync
-	blr
-_ASM_NOKPROBE_SYMBOL(flush_icache_range)
-EXPORT_SYMBOL(flush_icache_range)
-
-/*
- * Flush a particular page from the data cache to RAM.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- *
- *	void __flush_dcache_icache(void *page)
- */
-_GLOBAL(__flush_dcache_icache)
-/*
- * Flush the data cache to memory 
- * 
- * Different systems have different cache line sizes
- */
-
-BEGIN_FTR_SECTION
-	PURGE_PREFETCHED_INS
-	blr
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-
-/* Flush the dcache */
- 	ld	r7,PPC64_CACHES@toc(r2)
-	clrrdi	r3,r3,PAGE_SHIFT           	    /* Page align */
-	lwz	r4,DCACHEL1BLOCKSPERPAGE(r7)	/* Get # dcache blocks per page */
-	lwz	r5,DCACHEL1BLOCKSIZE(r7)	/* Get dcache block size */
-	mr	r6,r3
-	mtctr	r4
-0:	dcbst	0,r6
-	add	r6,r6,r5
-	bdnz	0b
-	sync
-
-/* Now invalidate the icache */	
-
-	lwz	r4,ICACHEL1BLOCKSPERPAGE(r7)	/* Get # icache blocks per page */
-	lwz	r5,ICACHEL1BLOCKSIZE(r7)	/* Get icache block size */
-	mtctr	r4
-1:	icbi	0,r3
-	add	r3,r3,r5
-	bdnz	1b
-	isync
-	blr
-
 _GLOBAL(__bswapdi2)
 EXPORT_SYMBOL(__bswapdi2)
 	srdi	r8,r3,32
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/paca.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/paca.c
@@ -86,7 +86,7 @@
 	 * This is very early in boot, so no harm done if the kernel crashes at
 	 * this point.
 	 */
-	BUG_ON(shared_lppaca_size >= shared_lppaca_total_size);
+	BUG_ON(shared_lppaca_size > shared_lppaca_total_size);
 
 	return ptr;
 }
@@ -214,11 +214,15 @@
 	/* On Book3E, initialize the TLB miss exception frames */
 	mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
 #else
-	/* In HV mode, we setup both HPACA and PACA to avoid problems
+	/*
+	 * In HV mode, we setup both HPACA and PACA to avoid problems
 	 * if we do a GET_PACA() before the feature fixups have been
-	 * applied
+	 * applied.
+	 *
+	 * Normally you should test against CPU_FTR_HVMODE, but CPU features
+	 * are not yet set up when we first reach here.
 	 */
-	if (early_cpu_has_feature(CPU_FTR_HVMODE))
+	if (mfmsr() & MSR_HV)
 		mtspr(SPRN_SPRG_HPACA, local_paca);
 #endif
 	mtspr(SPRN_SPRG_PACA, local_paca);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/pci-common.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/pci-common.c
@@ -66,23 +66,35 @@
 	pci_dma_ops = 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;
-	u32 prop_32;
 	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.
+	 * the respective device-tree properties. Firstly, try reading
+	 * standard "linux,pci-domain", then try reading "ibm,opal-phbid"
+	 * (only present in powernv OPAL environment), then try device-tree
+	 * alias and as the last try to use lower bits of "reg" property.
 	 */
-	ret = of_property_read_u64(dn, "ibm,opal-phbid", &prop);
+	ret = of_get_pci_domain_nr(dn);
+	if (ret >= 0) {
+		prop = ret;
+		ret = 0;
+	}
+	if (ret)
+		ret = of_property_read_u64(dn, "ibm,opal-phbid", &prop);
+
+	if (ret) {
+		ret = of_alias_get_id(dn, "pci");
+		if (ret >= 0) {
+			prop = ret;
+			ret = 0;
+		}
+	}
 	if (ret) {
+		u32 prop_32;
 		ret = of_property_read_u32_index(dn, "reg", 1, &prop_32);
 		prop = prop_32;
 	}
@@ -90,18 +102,20 @@
 	if (!ret)
 		phb_id = (int)(prop & (MAX_PHBS - 1));
 
+	spin_lock(&hose_spinlock);
+
 	/* 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;
+		goto out_unlock;
 
-	/*
-	 * If not pseries nor powernv, or if fixed PHB numbering tried to add
-	 * the same PHB number twice, then fallback to dynamic PHB numbering.
-	 */
+	/* If everything fails 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);
 
+out_unlock:
+	spin_unlock(&hose_spinlock);
+
 	return phb_id;
 }
 
@@ -112,10 +126,13 @@
 	phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
 	if (phb == NULL)
 		return NULL;
-	spin_lock(&hose_spinlock);
+
 	phb->global_number = get_phb_number(dev);
+
+	spin_lock(&hose_spinlock);
 	list_add_tail(&phb->list_node, &hose_list);
 	spin_unlock(&hose_spinlock);
+
 	phb->dn = dev;
 	phb->is_dynamic = slab_is_available();
 #ifdef CONFIG_PPC64
@@ -347,6 +364,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(pci_find_hose_for_OF_device);
 
 struct pci_controller *pci_find_controller_for_domain(int domain_nr)
 {
@@ -1577,6 +1595,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)
 {
@@ -1669,3 +1688,13 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MOTOROLA, PCI_ANY_ID, fixup_hide_host_resource_fsl);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, fixup_hide_host_resource_fsl);
+
+
+static int __init discover_phbs(void)
+{
+	if (ppc_md.discover_phbs)
+		ppc_md.discover_phbs();
+
+	return 0;
+}
+core_initcall(discover_phbs);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/pci_dn.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/pci_dn.c
@@ -244,9 +244,22 @@
 				continue;
 
 #ifdef CONFIG_EEH
-			/* Release EEH device for the VF */
+			/*
+			 * Release EEH state for this VF. The PCI core
+			 * has already torn down the pci_dev for this VF, but
+			 * we're responsible to removing the eeh_dev since it
+			 * has the same lifetime as the pci_dn that spawned it.
+			 */
 			edev = pdn_to_eeh_dev(pdn);
 			if (edev) {
+				/*
+				 * We allocate pci_dn's for the totalvfs count,
+				 * but only only the vfs that were activated
+				 * have a configured PE.
+				 */
+				if (edev->pe)
+					eeh_rmv_from_parent_pe(edev);
+
 				pdn->edev = NULL;
 				kfree(edev);
 			}
@@ -312,6 +325,7 @@
 	INIT_LIST_HEAD(&pdn->list);
 	parent = of_get_parent(dn);
 	pdn->parent = parent ? PCI_DN(parent) : NULL;
+	of_node_put(parent);
 	if (pdn->parent)
 		list_add_tail(&pdn->list, &pdn->parent->child_list);
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/process.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/process.c
@@ -1218,29 +1218,31 @@
 static void show_instructions(struct pt_regs *regs)
 {
 	int i;
+	unsigned long nip = regs->nip;
 	unsigned long pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
 
 	printk("Instruction dump:");
 
+	/*
+	 * If we were executing with the MMU off for instructions, adjust pc
+	 * rather than printing XXXXXXXX.
+	 */
+	if (!IS_ENABLED(CONFIG_BOOKE) && !(regs->msr & MSR_IR)) {
+		pc = (unsigned long)phys_to_virt(pc);
+		nip = (unsigned long)phys_to_virt(regs->nip);
+	}
+
 	for (i = 0; i < NR_INSN_TO_PRINT; i++) {
 		int instr;
 
 		if (!(i % 8))
 			pr_cont("\n");
 
-#if !defined(CONFIG_BOOKE)
-		/* If executing with the IMMU off, adjust pc rather
-		 * than print XXXXXXXX.
-		 */
-		if (!(regs->msr & MSR_IR))
-			pc = (unsigned long)phys_to_virt(pc);
-#endif
-
 		if (!__kernel_text_address(pc) ||
 		    probe_kernel_address((const void *)pc, instr)) {
 			pr_cont("XXXXXXXX ");
 		} else {
-			if (regs->nip == pc)
+			if (nip == pc)
 				pr_cont("<%08x> ", instr);
 			else
 				pr_cont("%08x ", instr);
@@ -1717,7 +1719,7 @@
 		tm_reclaim_current(0);
 #endif
 
-	memset(regs->gpr, 0, sizeof(regs->gpr));
+	memset(&regs->gpr[1], 0, sizeof(regs->gpr) - sizeof(regs->gpr[0]));
 	regs->ctr = 0;
 	regs->link = 0;
 	regs->xer = 0;
@@ -1999,12 +2001,12 @@
 		return 0;
 
 	do {
-		sp = *(unsigned long *)sp;
+		sp = READ_ONCE_NOCHECK(*(unsigned long *)sp);
 		if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD) ||
 		    p->state == TASK_RUNNING)
 			return 0;
 		if (count > 0) {
-			ip = ((unsigned long *)sp)[STACK_FRAME_LR_SAVE];
+			ip = READ_ONCE_NOCHECK(((unsigned long *)sp)[STACK_FRAME_LR_SAVE]);
 			if (!in_sched_functions(ip))
 				return ip;
 		}
@@ -2079,7 +2081,7 @@
 		 * See if this is an exception frame.
 		 * We look for the "regshere" marker in the current frame.
 		 */
-		if (validate_sp(sp, tsk, STACK_INT_FRAME_SIZE)
+		if (validate_sp(sp, tsk, STACK_FRAME_WITH_PT_REGS)
 		    && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
 			struct pt_regs *regs = (struct pt_regs *)
 				(sp + STACK_FRAME_OVERHEAD);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/prom.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/prom.c
@@ -266,7 +266,7 @@
 };
 
 #if defined(CONFIG_44x) && defined(CONFIG_PPC_FPU)
-static inline void identical_pvr_fixup(unsigned long node)
+static __init void identical_pvr_fixup(unsigned long node)
 {
 	unsigned int pvr;
 	const char *model = of_get_flat_dt_prop(node, "model", NULL);
@@ -685,6 +685,23 @@
 static void tm_init(void) { }
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
+#ifdef CONFIG_PPC64
+static void __init save_fscr_to_task(void)
+{
+	/*
+	 * Ensure the init_task (pid 0, aka swapper) uses the value of FSCR we
+	 * have configured via the device tree features or via __init_FSCR().
+	 * That value will then be propagated to pid 1 (init) and all future
+	 * processes.
+	 */
+	if (early_cpu_has_feature(CPU_FTR_ARCH_207S))
+		init_task.thread.fscr = mfspr(SPRN_FSCR);
+}
+#else
+static inline void save_fscr_to_task(void) {};
+#endif
+
+
 void __init early_init_devtree(void *params)
 {
 	phys_addr_t limit;
@@ -723,6 +740,13 @@
 	of_scan_flat_dt(early_init_dt_scan_root, NULL);
 	of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
 
+	/*
+	 * As generic code authors expect to be able to use static keys
+	 * in early_param() handlers, we initialize the static keys just
+	 * before parsing early params (it's fine to call jump_label_init()
+	 * more than once).
+	 */
+	jump_label_init();
 	parse_early_param();
 
 	/* make sure we've parsed cmdline for mem= before this */
@@ -773,6 +797,8 @@
 		BUG();
 	}
 
+	save_fscr_to_task();
+
 #if defined(CONFIG_SMP) && defined(CONFIG_PPC64)
 	/* We'll later wait for secondaries to check in; there are
 	 * NCPUS-1 non-boot CPUs  :-)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/prom_init.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/prom_init.c
@@ -1053,7 +1053,7 @@
 		.reserved2 = 0,
 		.reserved3 = 0,
 		.subprocessors = 1,
-		.byte22 = OV5_FEAT(OV5_DRMEM_V2),
+		.byte22 = OV5_FEAT(OV5_DRMEM_V2) | OV5_FEAT(OV5_DRC_INFO),
 		.intarch = 0,
 		.mmu = 0,
 		.hash_ext = 0,
@@ -1305,14 +1305,10 @@
 		if (prop_len > sizeof(vec))
 			prom_printf("WARNING: ibm,arch-vec-5-platform-support longer than expected (len: %d)\n",
 				    prop_len);
-		prom_getprop(prom.chosen, "ibm,arch-vec-5-platform-support",
-			     &vec, sizeof(vec));
-		for (i = 0; i < sizeof(vec); i += 2) {
-			prom_debug("%d: index = 0x%x val = 0x%x\n", i / 2
-								  , vec[i]
-								  , vec[i + 1]);
-			prom_parse_platform_support(vec[i], vec[i + 1],
-						    &supported);
+		prom_getprop(prom.chosen, "ibm,arch-vec-5-platform-support", &vec, sizeof(vec));
+		for (i = 0; i < prop_len; i += 2) {
+			prom_debug("%d: index = 0x%x val = 0x%x\n", i / 2, vec[i], vec[i + 1]);
+			prom_parse_platform_support(vec[i], vec[i + 1], &supported);
 		}
 	}
 
@@ -1761,6 +1757,9 @@
 	if (token == 0)
 		prom_panic("Could not get token for ibm,os-term\n");
 	os_term_args.token = cpu_to_be32(token);
+	os_term_args.nargs = cpu_to_be32(1);
+	os_term_args.nret = cpu_to_be32(1);
+	os_term_args.args[0] = cpu_to_be32(__pa(str));
 	prom_rtas_hcall((uint64_t)&os_term_args);
 }
 #endif /* CONFIG_PPC_SVM */
@@ -2920,7 +2919,7 @@
 
 	/* Check if the phy-handle property exists - bail if it does */
 	rv = prom_getprop(node, "phy-handle", prop, sizeof(prop));
-	if (!rv)
+	if (rv <= 0)
 		return;
 
 	/*
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/prom_init_check.sh
+++ linux-ein-5.4.0/arch/powerpc/kernel/prom_init_check.sh
@@ -13,7 +13,7 @@
 # If you really need to reference something from prom_init.o add
 # it to the list below:
 
-grep "^CONFIG_KASAN=y$" .config >/dev/null
+grep "^CONFIG_KASAN=y$" ${KCONFIG_CONFIG} >/dev/null
 if [ $? -eq 0 ]
 then
 	MEM_FUNCS="__memcpy __memset"
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/ptrace.c
@@ -3014,8 +3014,13 @@
 
 			flush_fp_to_thread(child);
 			if (fpidx < (PT_FPSCR - PT_FPR0))
-				memcpy(&tmp, &child->thread.TS_FPR(fpidx),
-				       sizeof(long));
+				if (IS_ENABLED(CONFIG_PPC32)) {
+					// On 32-bit the index we are passed refers to 32-bit words
+					tmp = ((u32 *)child->thread.fp_state.fpr)[fpidx];
+				} else {
+					memcpy(&tmp, &child->thread.TS_FPR(fpidx),
+					       sizeof(long));
+				}
 			else
 				tmp = child->thread.fp_state.fpscr;
 		}
@@ -3047,8 +3052,13 @@
 
 			flush_fp_to_thread(child);
 			if (fpidx < (PT_FPSCR - PT_FPR0))
-				memcpy(&child->thread.TS_FPR(fpidx), &data,
-				       sizeof(long));
+				if (IS_ENABLED(CONFIG_PPC32)) {
+					// On 32-bit the index we are passed refers to 32-bit words
+					((u32 *)child->thread.fp_state.fpr)[fpidx] = data;
+				} else {
+					memcpy(&child->thread.TS_FPR(fpidx), &data,
+					       sizeof(long));
+				}
 			else
 				child->thread.fp_state.fpscr = data;
 			ret = 0;
@@ -3398,4 +3408,7 @@
 		     offsetof(struct user_pt_regs, result));
 
 	BUILD_BUG_ON(sizeof(struct user_pt_regs) > sizeof(struct pt_regs));
+
+	// ptrace_get/put_fpr() rely on PPC32 and VSX being incompatible
+	BUILD_BUG_ON(IS_ENABLED(CONFIG_PPC32) && IS_ENABLED(CONFIG_VSX));
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/rtas.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/rtas.c
@@ -51,10 +51,10 @@
 EXPORT_SYMBOL(rtas);
 
 DEFINE_SPINLOCK(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_data_buf_lock);
+EXPORT_SYMBOL_GPL(rtas_data_buf_lock);
 
-char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
-EXPORT_SYMBOL(rtas_data_buf);
+char rtas_data_buf[RTAS_DATA_BUF_SIZE] __aligned(SZ_4K);
+EXPORT_SYMBOL_GPL(rtas_data_buf);
 
 unsigned long rtas_rmo_buf;
 
@@ -63,7 +63,7 @@
  * This is done like this so rtas_flash can be a module.
  */
 void (*rtas_flash_term_hook)(int);
-EXPORT_SYMBOL(rtas_flash_term_hook);
+EXPORT_SYMBOL_GPL(rtas_flash_term_hook);
 
 /* RTAS use home made raw locking instead of spin_lock_irqsave
  * because those can be called from within really nasty contexts
@@ -311,7 +311,7 @@
  
 	spin_unlock(&progress_lock);
 }
-EXPORT_SYMBOL(rtas_progress);		/* needed by rtas_flash module */
+EXPORT_SYMBOL_GPL(rtas_progress);		/* needed by rtas_flash module */
 
 int rtas_token(const char *service)
 {
@@ -321,7 +321,7 @@
 	tokp = of_get_property(rtas.dev, service, NULL);
 	return tokp ? be32_to_cpu(*tokp) : RTAS_UNKNOWN_SERVICE;
 }
-EXPORT_SYMBOL(rtas_token);
+EXPORT_SYMBOL_GPL(rtas_token);
 
 int rtas_service_present(const char *service)
 {
@@ -398,7 +398,7 @@
 				buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC);
 		}
 		if (buf)
-			memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX);
+			memmove(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX);
 	}
 
 	return buf;
@@ -481,7 +481,7 @@
 	}
 	return ret;
 }
-EXPORT_SYMBOL(rtas_call);
+EXPORT_SYMBOL_GPL(rtas_call);
 
 /* For RTAS_BUSY (-2), delay for 1 millisecond.  For an extended busy status
  * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
@@ -516,7 +516,7 @@
 
 	return ms;
 }
-EXPORT_SYMBOL(rtas_busy_delay);
+EXPORT_SYMBOL_GPL(rtas_busy_delay);
 
 static int rtas_error_rc(int rtas_rc)
 {
@@ -562,7 +562,7 @@
 		return rtas_error_rc(rc);
 	return rc;
 }
-EXPORT_SYMBOL(rtas_get_power_level);
+EXPORT_SYMBOL_GPL(rtas_get_power_level);
 
 int rtas_set_power_level(int powerdomain, int level, int *setlevel)
 {
@@ -580,7 +580,7 @@
 		return rtas_error_rc(rc);
 	return rc;
 }
-EXPORT_SYMBOL(rtas_set_power_level);
+EXPORT_SYMBOL_GPL(rtas_set_power_level);
 
 int rtas_get_sensor(int sensor, int index, int *state)
 {
@@ -598,7 +598,7 @@
 		return rtas_error_rc(rc);
 	return rc;
 }
-EXPORT_SYMBOL(rtas_get_sensor);
+EXPORT_SYMBOL_GPL(rtas_get_sensor);
 
 int rtas_get_sensor_fast(int sensor, int index, int *state)
 {
@@ -659,7 +659,7 @@
 		return rtas_error_rc(rc);
 	return rc;
 }
-EXPORT_SYMBOL(rtas_set_indicator);
+EXPORT_SYMBOL_GPL(rtas_set_indicator);
 
 /*
  * Ignoring RTAS extended delay
@@ -714,6 +714,7 @@
 
 /* Must be in the RMO region, so we place it here */
 static char rtas_os_term_buf[2048];
+static s32 ibm_os_term_token = RTAS_UNKNOWN_SERVICE;
 
 void rtas_os_term(char *str)
 {
@@ -725,16 +726,20 @@
 	 * this property may terminate the partition which we want to avoid
 	 * since it interferes with panic_timeout.
 	 */
-	if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term") ||
-	    RTAS_UNKNOWN_SERVICE == rtas_token("ibm,extended-os-term"))
+	if (ibm_os_term_token == RTAS_UNKNOWN_SERVICE)
 		return;
 
 	snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str);
 
+	/*
+	 * Keep calling as long as RTAS returns a "try again" status,
+	 * but don't use rtas_busy_delay(), which potentially
+	 * schedules.
+	 */
 	do {
-		status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
+		status = rtas_call(ibm_os_term_token, 1, 1, NULL,
 				   __pa(rtas_os_term_buf));
-	} while (rtas_busy_delay(status));
+	} while (rtas_busy_delay_time(status));
 
 	if (status != 0)
 		printk(KERN_EMERG "ibm,os-term call failed %d\n", status);
@@ -842,96 +847,6 @@
 	__rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
 }
 
-enum rtas_cpu_state {
-	DOWN,
-	UP,
-};
-
-#ifndef CONFIG_SMP
-static int rtas_cpu_state_change_mask(enum rtas_cpu_state state,
-				cpumask_var_t cpus)
-{
-	if (!cpumask_empty(cpus)) {
-		cpumask_clear(cpus);
-		return -EINVAL;
-	} else
-		return 0;
-}
-#else
-/* On return cpumask will be altered to indicate CPUs changed.
- * CPUs with states changed will be set in the mask,
- * CPUs with status unchanged will be unset in the mask. */
-static int rtas_cpu_state_change_mask(enum rtas_cpu_state state,
-				cpumask_var_t cpus)
-{
-	int cpu;
-	int cpuret = 0;
-	int ret = 0;
-
-	if (cpumask_empty(cpus))
-		return 0;
-
-	for_each_cpu(cpu, cpus) {
-		struct device *dev = get_cpu_device(cpu);
-
-		switch (state) {
-		case DOWN:
-			cpuret = device_offline(dev);
-			break;
-		case UP:
-			cpuret = device_online(dev);
-			break;
-		}
-		if (cpuret < 0) {
-			pr_debug("%s: cpu_%s for cpu#%d returned %d.\n",
-					__func__,
-					((state == UP) ? "up" : "down"),
-					cpu, cpuret);
-			if (!ret)
-				ret = cpuret;
-			if (state == UP) {
-				/* clear bits for unchanged cpus, return */
-				cpumask_shift_right(cpus, cpus, cpu);
-				cpumask_shift_left(cpus, cpus, cpu);
-				break;
-			} else {
-				/* clear bit for unchanged cpu, continue */
-				cpumask_clear_cpu(cpu, cpus);
-			}
-		}
-		cond_resched();
-	}
-
-	return ret;
-}
-#endif
-
-int rtas_online_cpus_mask(cpumask_var_t cpus)
-{
-	int ret;
-
-	ret = rtas_cpu_state_change_mask(UP, cpus);
-
-	if (ret) {
-		cpumask_var_t tmp_mask;
-
-		if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL))
-			return ret;
-
-		/* Use tmp_mask to preserve cpus mask from first failure */
-		cpumask_copy(tmp_mask, cpus);
-		rtas_offline_cpus_mask(tmp_mask);
-		free_cpumask_var(tmp_mask);
-	}
-
-	return ret;
-}
-
-int rtas_offline_cpus_mask(cpumask_var_t cpus)
-{
-	return rtas_cpu_state_change_mask(DOWN, cpus);
-}
-
 int rtas_ibm_suspend_me(u64 handle)
 {
 	long state;
@@ -939,8 +854,6 @@
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 	struct rtas_suspend_me_data data;
 	DECLARE_COMPLETION_ONSTACK(done);
-	cpumask_var_t offline_mask;
-	int cpuret;
 
 	if (!rtas_service_present("ibm,suspend-me"))
 		return -ENOSYS;
@@ -961,9 +874,6 @@
 		return -EIO;
 	}
 
-	if (!alloc_cpumask_var(&offline_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	atomic_set(&data.working, 0);
 	atomic_set(&data.done, 0);
 	atomic_set(&data.error, 0);
@@ -972,24 +882,8 @@
 
 	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);
-	if (cpuret) {
-		pr_err("%s: Could not bring present CPUs online.\n", __func__);
-		atomic_set(&data.error, cpuret);
-		goto out;
-	}
-
 	cpu_hotplug_disable();
 
-	/* Check if we raced with a CPU-Offline Operation */
-	if (!cpumask_equal(cpu_present_mask, cpu_online_mask)) {
-		pr_info("%s: Raced against a concurrent CPU-Offline\n", __func__);
-		atomic_set(&data.error, -EAGAIN);
-		goto out_hotplug_enable;
-	}
-
 	/* Call function on all CPUs.  One of us will make the
 	 * rtas call
 	 */
@@ -1000,18 +894,11 @@
 	if (atomic_read(&data.error) != 0)
 		printk(KERN_ERR "Error doing global join\n");
 
-out_hotplug_enable:
-	cpu_hotplug_enable();
 
-	/* Take down CPUs not online prior to suspend */
-	cpuret = rtas_offline_cpus_mask(offline_mask);
-	if (cpuret)
-		pr_warn("%s: Could not restore CPUs to offline state.\n",
-				__func__);
+	cpu_hotplug_enable();
 
-out:
 	unlock_device_hotplug();
-	free_cpumask_var(offline_mask);
+
 	return atomic_read(&data.error);
 }
 #else /* CONFIG_PPC_PSERIES */
@@ -1058,6 +945,156 @@
 	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 },		/* Special cased */
+	{ "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;
+
+			/*
+			 * Special case for ibm,platform-dump - NULL buffer
+			 * address is used to indicate end of dump processing
+			 */
+			if (!strcmp(f->name, "ibm,platform-dump") &&
+			    base == 0)
+				return false;
+
+			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 */
 SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
 {
@@ -1095,6 +1132,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) {
 
@@ -1156,6 +1196,9 @@
 	unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
 	u32 base, size, entry;
 	int no_base, no_size, no_entry;
+#ifdef CONFIG_PPC_RTAS_FILTER
+	int i;
+#endif
 
 	/* Get RTAS dev node and fill up our "rtas" structure with infos
 	 * about it.
@@ -1177,6 +1220,13 @@
 	no_entry = of_property_read_u32(rtas.dev, "linux,rtas-entry", &entry);
 	rtas.entry = no_entry ? rtas.base : entry;
 
+	/*
+	 * Discover these now to avoid device tree lookups in the
+	 * panic path.
+	 */
+	if (of_property_read_bool(rtas.dev, "ibm,extended-os-term"))
+		ibm_os_term_token = rtas_token("ibm,os-term");
+
 	/* If RTAS was found, allocate the RMO buffer for it and look for
 	 * the stop-self token if any
 	 */
@@ -1195,6 +1245,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,
@@ -1209,6 +1265,12 @@
 	entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
 	sizep  = of_get_flat_dt_prop(node, "rtas-size", NULL);
 
+#ifdef CONFIG_PPC64
+	/* need this feature to decide the crashkernel offset */
+	if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL))
+		powerpc_firmware_features |= FW_FEATURE_LPAR;
+#endif
+
 	if (basep && entryp && sizep) {
 		rtas.base = *basep;
 		rtas.entry = *entryp;
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/rtas_flash.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/rtas_flash.c
@@ -710,9 +710,9 @@
 	if (!rtas_validate_flash_data.buf)
 		return -ENOMEM;
 
-	flash_block_cache = kmem_cache_create("rtas_flash_cache",
-					      RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
-					      NULL);
+	flash_block_cache = kmem_cache_create_usercopy("rtas_flash_cache",
+						       RTAS_BLK_SIZE, RTAS_BLK_SIZE,
+						       0, 0, RTAS_BLK_SIZE, NULL);
 	if (!flash_block_cache) {
 		printk(KERN_ERR "%s: failed to create block cache\n",
 				__func__);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/secure_boot.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/secure_boot.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain
+ */
+#include <linux/types.h>
+#include <linux/of.h>
+#include <asm/secure_boot.h>
+
+static struct device_node *get_ppc_fw_sb_node(void)
+{
+	static const struct of_device_id ids[] = {
+		{ .compatible = "ibm,secureboot", },
+		{ .compatible = "ibm,secureboot-v1", },
+		{ .compatible = "ibm,secureboot-v2", },
+		{},
+	};
+
+	return of_find_matching_node(NULL, ids);
+}
+
+bool is_ppc_secureboot_enabled(void)
+{
+	struct device_node *node;
+	bool enabled = false;
+
+	node = get_ppc_fw_sb_node();
+	enabled = of_property_read_bool(node, "os-secureboot-enforcing");
+
+	of_node_put(node);
+
+	pr_info("Secure boot mode %s\n", enabled ? "enabled" : "disabled");
+
+	return enabled;
+}
+
+bool is_ppc_trustedboot_enabled(void)
+{
+	struct device_node *node;
+	bool enabled = false;
+
+	node = get_ppc_fw_sb_node();
+	enabled = of_property_read_bool(node, "trusted-enabled");
+
+	of_node_put(node);
+
+	pr_info("Trusted boot mode %s\n", enabled ? "enabled" : "disabled");
+
+	return enabled;
+}
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/security.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/security.c
@@ -16,7 +16,7 @@
 #include <asm/setup.h>
 
 
-unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT;
+u64 powerpc_security_features __read_mostly = SEC_FTR_DEFAULT;
 
 enum count_cache_flush_type {
 	COUNT_CACHE_FLUSH_NONE	= 0x1,
@@ -24,6 +24,7 @@
 	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;
@@ -108,7 +109,7 @@
 static __init int security_feature_debugfs_init(void)
 {
 	debugfs_create_x64("security_features", 0400, powerpc_debugfs_root,
-			   (u64 *)&powerpc_security_features);
+			   &powerpc_security_features);
 	return 0;
 }
 device_initcall(security_feature_debugfs_init);
@@ -141,32 +142,33 @@
 
 	thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV);
 
-	if (rfi_flush || thread_priv) {
+	if (rfi_flush) {
 		struct seq_buf s;
 		seq_buf_init(&s, buf, PAGE_SIZE - 1);
 
-		seq_buf_printf(&s, "Mitigation: ");
-
-		if (rfi_flush)
-			seq_buf_printf(&s, "RFI Flush");
-
-		if (rfi_flush && thread_priv)
-			seq_buf_printf(&s, ", ");
-
+		seq_buf_printf(&s, "Mitigation: RFI Flush");
 		if (thread_priv)
-			seq_buf_printf(&s, "L1D private per thread");
+			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)
@@ -212,11 +214,19 @@
 
 		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 {
@@ -246,6 +256,11 @@
 
 early_param("no_stf_barrier", handle_no_stf_barrier);
 
+enum stf_barrier_type stf_barrier_type_get(void)
+{
+	return stf_enabled_flush_types;
+}
+
 /* This is the generic flag used by other architectures */
 static int __init handle_ssbd(char *p)
 {
@@ -377,18 +392,49 @@
 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 (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {
+	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);
-		count_cache_flush_type = COUNT_CACHE_FLUSH_NONE;
-		pr_info("count-cache-flush: software flush disabled.\n");
+#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");
@@ -407,11 +453,20 @@
 	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 under software control, can't disable\n");
+			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);
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/secvar-ops.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/secvar-ops.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain
+ *
+ * This file initializes secvar operations for PowerPC Secureboot
+ */
+
+#include <linux/cache.h>
+#include <asm/secvar.h>
+
+const struct secvar_operations *secvar_ops __ro_after_init;
+
+void set_secvar_ops(const struct secvar_operations *ops)
+{
+	secvar_ops = ops;
+}
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/secvar-sysfs.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/secvar-sysfs.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 IBM Corporation <nayna@linux.ibm.com>
+ *
+ * This code exposes secure variables to user via sysfs
+ */
+
+#define pr_fmt(fmt) "secvar-sysfs: "fmt
+
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <asm/secvar.h>
+
+#define NAME_MAX_SIZE	   1024
+
+static struct kobject *secvar_kobj;
+static struct kset *secvar_kset;
+
+static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
+			   char *buf)
+{
+	ssize_t rc = 0;
+	struct device_node *node;
+	const char *format;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!of_device_is_available(node))
+		return -ENODEV;
+
+	rc = of_property_read_string(node, "format", &format);
+	if (rc)
+		return rc;
+
+	rc = sprintf(buf, "%s\n", format);
+
+	of_node_put(node);
+
+	return rc;
+}
+
+
+static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	uint64_t dsize;
+	int rc;
+
+	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
+	if (rc) {
+		pr_err("Error retrieving %s variable size %d\n", kobj->name,
+		       rc);
+		return rc;
+	}
+
+	return sprintf(buf, "%llu\n", dsize);
+}
+
+static ssize_t data_read(struct file *filep, struct kobject *kobj,
+			 struct bin_attribute *attr, char *buf, loff_t off,
+			 size_t count)
+{
+	uint64_t dsize;
+	char *data;
+	int rc;
+
+	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
+	if (rc) {
+		pr_err("Error getting %s variable size %d\n", kobj->name, rc);
+		return rc;
+	}
+	pr_debug("dsize is %llu\n", dsize);
+
+	data = kzalloc(dsize, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, data, &dsize);
+	if (rc) {
+		pr_err("Error getting %s variable %d\n", kobj->name, rc);
+		goto data_fail;
+	}
+
+	rc = memory_read_from_buffer(buf, count, &off, data, dsize);
+
+data_fail:
+	kfree(data);
+	return rc;
+}
+
+static ssize_t update_write(struct file *filep, struct kobject *kobj,
+			    struct bin_attribute *attr, char *buf, loff_t off,
+			    size_t count)
+{
+	int rc;
+
+	pr_debug("count is %ld\n", count);
+	rc = secvar_ops->set(kobj->name, strlen(kobj->name) + 1, buf, count);
+	if (rc) {
+		pr_err("Error setting the %s variable %d\n", kobj->name, rc);
+		return rc;
+	}
+
+	return count;
+}
+
+static struct kobj_attribute format_attr = __ATTR_RO(format);
+
+static struct kobj_attribute size_attr = __ATTR_RO(size);
+
+static struct bin_attribute data_attr = __BIN_ATTR_RO(data, 0);
+
+static struct bin_attribute update_attr = __BIN_ATTR_WO(update, 0);
+
+static struct bin_attribute *secvar_bin_attrs[] = {
+	&data_attr,
+	&update_attr,
+	NULL,
+};
+
+static struct attribute *secvar_attrs[] = {
+	&size_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group secvar_attr_group = {
+	.attrs = secvar_attrs,
+	.bin_attrs = secvar_bin_attrs,
+};
+__ATTRIBUTE_GROUPS(secvar_attr);
+
+static struct kobj_type secvar_ktype = {
+	.sysfs_ops	= &kobj_sysfs_ops,
+	.default_groups = secvar_attr_groups,
+};
+
+static int update_kobj_size(void)
+{
+
+	struct device_node *node;
+	u64 varsize;
+	int rc = 0;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!of_device_is_available(node)) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = of_property_read_u64(node, "max-var-size", &varsize);
+	if (rc)
+		goto out;
+
+	data_attr.size = varsize;
+	update_attr.size = varsize;
+
+out:
+	of_node_put(node);
+
+	return rc;
+}
+
+static int secvar_sysfs_load(void)
+{
+	char *name;
+	uint64_t namesize = 0;
+	struct kobject *kobj;
+	int rc;
+
+	name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	do {
+		rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
+		if (rc) {
+			if (rc != -ENOENT)
+				pr_err("error getting secvar from firmware %d\n",
+				       rc);
+			break;
+		}
+
+		kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+		if (!kobj) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		kobject_init(kobj, &secvar_ktype);
+
+		rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
+		if (rc) {
+			pr_warn("kobject_add error %d for attribute: %s\n", rc,
+				name);
+			kobject_put(kobj);
+			kobj = NULL;
+		}
+
+		if (kobj)
+			kobject_uevent(kobj, KOBJ_ADD);
+
+	} while (!rc);
+
+	kfree(name);
+	return rc;
+}
+
+static int secvar_sysfs_init(void)
+{
+	int rc;
+
+	if (!secvar_ops) {
+		pr_warn("secvar: failed to retrieve secvar operations.\n");
+		return -ENODEV;
+	}
+
+	secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
+	if (!secvar_kobj) {
+		pr_err("secvar: Failed to create firmware kobj\n");
+		return -ENOMEM;
+	}
+
+	rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
+	if (rc) {
+		kobject_put(secvar_kobj);
+		return -ENOMEM;
+	}
+
+	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
+	if (!secvar_kset) {
+		pr_err("secvar: sysfs kobject registration failed.\n");
+		kobject_put(secvar_kobj);
+		return -ENOMEM;
+	}
+
+	rc = update_kobj_size();
+	if (rc) {
+		pr_err("Cannot read the size of the attribute\n");
+		return rc;
+	}
+
+	secvar_sysfs_load();
+
+	return 0;
+}
+
+late_initcall(secvar_sysfs_init);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/setup-common.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/setup-common.c
@@ -31,6 +31,7 @@
 #include <linux/memblock.h>
 #include <linux/of_platform.h>
 #include <linux/hugetlb.h>
+#include <linux/security.h>
 #include <asm/debugfs.h>
 #include <asm/io.h>
 #include <asm/paca.h>
@@ -64,6 +65,7 @@
 #include <asm/mmu_context.h>
 #include <asm/cpu_has_feature.h>
 #include <asm/kasan.h>
+#include <asm/secure_boot.h>
 
 #include "setup.h"
 
@@ -855,6 +857,16 @@
 	 */
 	initialize_cache_info();
 
+	/*
+	 * Lock down the kernel if booted in secure mode. This is required to
+	 * maintain kernel integrity.
+	 */
+	if (IS_ENABLED(CONFIG_LOCK_DOWN_IN_SECURE_BOOT)) {
+		if (is_ppc_secureboot_enabled())
+			security_lock_kernel_down("PowerNV Secure Boot mode",
+						  LOCKDOWN_INTEGRITY_MAX);
+	}
+
 	/* Initialize RTAS if available. */
 	rtas_initialize();
 
@@ -903,8 +915,6 @@
 
 	/* On BookE, setup per-core TLB data structures. */
 	setup_tlb_core_data();
-
-	smp_release_cpus();
 #endif
 
 	/* Print various info about the machine that has been gathered so far. */
@@ -925,6 +935,8 @@
 	exc_lvl_early_init();
 	emergency_stack_init();
 
+	smp_release_cpus();
+
 	initmem_init();
 
 	early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/setup_64.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/setup_64.c
@@ -290,18 +290,36 @@
 
 	/* -------- printk is _NOT_ safe to use here ! ------- */
 
-	/* Try new device tree based feature discovery ... */
-	if (!dt_cpu_ftrs_init(__va(dt_ptr)))
-		/* Otherwise use the old style CPU table */
-		identify_cpu(0, mfspr(SPRN_PVR));
-
-	/* Assume we're on cpu 0 for now. Don't write to the paca yet! */
+	/*
+	 * Assume we're on cpu 0 for now.
+	 *
+	 * We need to load a PACA very early for a few reasons.
+	 *
+	 * The stack protector canary is stored in the paca, so as soon as we
+	 * call any stack protected code we need r13 pointing somewhere valid.
+	 *
+	 * If we are using kcov it will call in_task() in its instrumentation,
+	 * which relies on the current task from the PACA.
+	 *
+	 * dt_cpu_ftrs_init() calls into generic OF/fdt code, as well as
+	 * printk(), which can trigger both stack protector and kcov.
+	 *
+	 * percpu variables and spin locks also use the paca.
+	 *
+	 * So set up a temporary paca. It will be replaced below once we know
+	 * what CPU we are on.
+	 */
 	initialise_paca(&boot_paca, 0);
 	setup_paca(&boot_paca);
 	fixup_boot_paca();
 
 	/* -------- printk is now safe to use ------- */
 
+	/* Try new device tree based feature discovery ... */
+	if (!dt_cpu_ftrs_init(__va(dt_ptr)))
+		/* Otherwise use the old style CPU table */
+		identify_cpu(0, mfspr(SPRN_PVR));
+
 	/* Enable early debugging if any specified (see udbg.h) */
 	udbg_early_init();
 
@@ -523,6 +541,8 @@
 	lsizep = of_get_property(np, propnames[3], NULL);
 	if (bsizep == NULL)
 		bsizep = lsizep;
+	if (lsizep == NULL)
+		lsizep = bsizep;
 	if (lsizep != NULL)
 		lsize = be32_to_cpu(*lsizep);
 	if (bsizep != NULL)
@@ -839,7 +859,13 @@
 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)
 {
@@ -849,6 +875,22 @@
 }
 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.
@@ -880,6 +922,32 @@
 	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);
+		static_branch_enable(&uaccess_flush_key);
+		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 void __ref init_fallback_flush(void)
 {
 	u64 l1d_size, limit;
@@ -938,10 +1006,28 @@
 
 	enabled_flush_types = types;
 
-	if (!no_rfi_flush && !cpu_mitigations_off())
+	if (!cpu_mitigations_off() && !no_rfi_flush)
 		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)
 {
@@ -969,9 +1055,63 @@
 
 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);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/signal.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/signal.c
@@ -200,14 +200,27 @@
 	 * normal/non-checkpointed stack pointer.
 	 */
 
+	unsigned long ret = tsk->thread.regs->gpr[1];
+
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 	BUG_ON(tsk != current);
 
 	if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+		preempt_disable();
 		tm_reclaim_current(TM_CAUSE_SIGNAL);
 		if (MSR_TM_TRANSACTIONAL(tsk->thread.regs->msr))
-			return tsk->thread.ckpt_regs.gpr[1];
+			ret = tsk->thread.ckpt_regs.gpr[1];
+
+		/*
+		 * If we treclaim, we must clear the current thread's TM bits
+		 * before re-enabling preemption. Otherwise we might be
+		 * preempted and have the live MSR[TS] changed behind our back
+		 * (tm_recheckpoint_new_task() would recheckpoint). Besides, we
+		 * enter the signal handler in non-transactional state.
+		 */
+		tsk->thread.regs->msr &= ~MSR_TS_MASK;
+		preempt_enable();
 	}
 #endif
-	return tsk->thread.regs->gpr[1];
+	return ret;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/signal_32.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/signal_32.c
@@ -489,19 +489,11 @@
  */
 static int save_tm_user_regs(struct pt_regs *regs,
 			     struct mcontext __user *frame,
-			     struct mcontext __user *tm_frame, int sigret)
+			     struct mcontext __user *tm_frame, int sigret,
+			     unsigned long msr)
 {
-	unsigned long msr = regs->msr;
-
 	WARN_ON(tm_suspend_disabled);
 
-	/* Remove TM bits from thread's MSR.  The MSR in the sigcontext
-	 * just indicates to userland that we were doing a transaction, but we
-	 * don't want to return in transactional state.  This also ensures
-	 * that flush_fp_to_thread won't set TIF_RESTORE_TM again.
-	 */
-	regs->msr &= ~MSR_TS_MASK;
-
 	/* Save both sets of general registers */
 	if (save_general_regs(&current->thread.ckpt_regs, frame)
 	    || save_general_regs(regs, tm_frame))
@@ -912,6 +904,10 @@
 	int sigret;
 	unsigned long tramp;
 	struct pt_regs *regs = tsk->thread.regs;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/* Save the thread's msr before get_tm_stackpointer() changes it */
+	unsigned long msr = regs->msr;
+#endif
 
 	BUG_ON(tsk != current);
 
@@ -944,13 +940,13 @@
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 	tm_frame = &rt_sf->uc_transact.uc_mcontext;
-	if (MSR_TM_ACTIVE(regs->msr)) {
+	if (MSR_TM_ACTIVE(msr)) {
 		if (__put_user((unsigned long)&rt_sf->uc_transact,
 			       &rt_sf->uc.uc_link) ||
 		    __put_user((unsigned long)tm_frame,
 			       &rt_sf->uc_transact.uc_regs))
 			goto badframe;
-		if (save_tm_user_regs(regs, frame, tm_frame, sigret))
+		if (save_tm_user_regs(regs, frame, tm_frame, sigret, msr))
 			goto badframe;
 	}
 	else
@@ -1369,6 +1365,10 @@
 	int sigret;
 	unsigned long tramp;
 	struct pt_regs *regs = tsk->thread.regs;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/* Save the thread's msr before get_tm_stackpointer() changes it */
+	unsigned long msr = regs->msr;
+#endif
 
 	BUG_ON(tsk != current);
 
@@ -1402,9 +1402,9 @@
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 	tm_mctx = &frame->mctx_transact;
-	if (MSR_TM_ACTIVE(regs->msr)) {
+	if (MSR_TM_ACTIVE(msr)) {
 		if (save_tm_user_regs(regs, &frame->mctx, &frame->mctx_transact,
-				      sigret))
+				      sigret, msr))
 			goto badframe;
 	}
 	else
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/signal_64.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/signal_64.c
@@ -192,7 +192,8 @@
 static long setup_tm_sigcontexts(struct sigcontext __user *sc,
 				 struct sigcontext __user *tm_sc,
 				 struct task_struct *tsk,
-				 int signr, sigset_t *set, unsigned long handler)
+				 int signr, sigset_t *set, unsigned long handler,
+				 unsigned long msr)
 {
 	/* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the
 	 * process never used altivec yet (MSR_VEC is zero in pt_regs of
@@ -207,12 +208,11 @@
 	elf_vrreg_t __user *tm_v_regs = sigcontext_vmx_regs(tm_sc);
 #endif
 	struct pt_regs *regs = tsk->thread.regs;
-	unsigned long msr = tsk->thread.regs->msr;
 	long err = 0;
 
 	BUG_ON(tsk != current);
 
-	BUG_ON(!MSR_TM_ACTIVE(regs->msr));
+	BUG_ON(!MSR_TM_ACTIVE(msr));
 
 	WARN_ON(tm_suspend_disabled);
 
@@ -222,13 +222,6 @@
 	 */
 	msr |= tsk->thread.ckpt_regs.msr & (MSR_FP | MSR_VEC | MSR_VSX);
 
-	/* Remove TM bits from thread's MSR.  The MSR in the sigcontext
-	 * just indicates to userland that we were doing a transaction, but we
-	 * don't want to return in transactional state.  This also ensures
-	 * that flush_fp_to_thread won't set TIF_RESTORE_TM again.
-	 */
-	regs->msr &= ~MSR_TS_MASK;
-
 #ifdef CONFIG_ALTIVEC
 	err |= __put_user(v_regs, &sc->v_regs);
 	err |= __put_user(tm_v_regs, &tm_sc->v_regs);
@@ -480,8 +473,10 @@
 	err |= __get_user(tsk->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]);
@@ -824,6 +819,10 @@
 	unsigned long newsp = 0;
 	long err = 0;
 	struct pt_regs *regs = tsk->thread.regs;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	/* Save the thread's msr before get_tm_stackpointer() changes it */
+	unsigned long msr = regs->msr;
+#endif
 
 	BUG_ON(tsk != current);
 
@@ -841,7 +840,7 @@
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __save_altstack(&frame->uc.uc_stack, regs->gpr[1]);
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-	if (MSR_TM_ACTIVE(regs->msr)) {
+	if (MSR_TM_ACTIVE(msr)) {
 		/* The ucontext_t passed to userland points to the second
 		 * ucontext_t (for transactional state) with its uc_link ptr.
 		 */
@@ -849,7 +848,8 @@
 		err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext,
 					    &frame->uc_transact.uc_mcontext,
 					    tsk, ksig->sig, NULL,
-					    (unsigned long)ksig->ka.sa.sa_handler);
+					    (unsigned long)ksig->ka.sa.sa_handler,
+					    msr);
 	} else
 #endif
 	{
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/smp.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/smp.c
@@ -583,11 +583,43 @@
 #endif
 
 #ifdef CONFIG_NMI_IPI
+static void crash_stop_this_cpu(struct pt_regs *regs)
+#else
+static void crash_stop_this_cpu(void *dummy)
+#endif
+{
+	/*
+	 * Just busy wait here and avoid marking CPU as offline to ensure
+	 * register data is captured appropriately.
+	 */
+	while (1)
+		cpu_relax();
+}
+
+void crash_smp_send_stop(void)
+{
+	static bool stopped = false;
+
+	if (stopped)
+		return;
+
+	stopped = true;
+
+#ifdef CONFIG_NMI_IPI
+	smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_stop_this_cpu, 1000000);
+#else
+	smp_call_function(crash_stop_this_cpu, NULL, 0);
+#endif /* CONFIG_NMI_IPI */
+}
+
+#ifdef CONFIG_NMI_IPI
 static void nmi_stop_this_cpu(struct pt_regs *regs)
 {
 	/*
 	 * IRQs are already hard disabled by the smp_handle_nmi_ipi.
 	 */
+	set_cpu_online(smp_processor_id(), false);
+
 	spin_begin();
 	while (1)
 		spin_cpu_relax();
@@ -603,6 +635,15 @@
 static void stop_this_cpu(void *dummy)
 {
 	hard_irq_disable();
+
+	/*
+	 * Offlining CPUs in stop_this_cpu can result in scheduler warnings,
+	 * (see commit de6e5d38417e), but printk_safe_flush_on_panic() wants
+	 * to know other CPUs are offline before it breaks locks to flush
+	 * printk buffers, in case we panic()ed while holding the lock.
+	 */
+	set_cpu_online(smp_processor_id(), false);
+
 	spin_begin();
 	while (1)
 		spin_cpu_relax();
@@ -1254,6 +1295,9 @@
 
 	vdso_getcpu_init();
 #endif
+	set_numa_node(numa_cpu_lookup_table[cpu]);
+	set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu]));
+
 	/* Update topology CPU masks */
 	add_cpu_to_masks(cpu);
 
@@ -1266,9 +1310,6 @@
 	if (!cpumask_equal(cpu_l2_cache_mask(cpu), sibling_mask(cpu)))
 		shared_caches = true;
 
-	set_numa_node(numa_cpu_lookup_table[cpu]);
-	set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu]));
-
 	smp_wmb();
 	notify_cpu_starting(cpu);
 	set_cpu_online(cpu, true);
@@ -1285,10 +1326,12 @@
 	BUG();
 }
 
+#ifdef CONFIG_PROFILING
 int setup_profiling_timer(unsigned int multiplier)
 {
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_SCHED_SMT
 /* cpumask of CPUs with asymetric SMT dependancy */
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/stacktrace.c
@@ -8,6 +8,7 @@
  * Copyright 2018 Nick Piggin, Michael Ellerman, IBM Corp.
  */
 
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/kallsyms.h>
 #include <linux/module.h>
@@ -19,6 +20,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <linux/ftrace.h>
+#include <linux/delay.h>
 #include <asm/kprobes.h>
 
 #include <asm/paca.h>
@@ -230,17 +232,31 @@
 
 static void raise_backtrace_ipi(cpumask_t *mask)
 {
+	struct paca_struct *p;
 	unsigned int cpu;
+	u64 delay_us;
 
 	for_each_cpu(cpu, mask) {
-		if (cpu == smp_processor_id())
+		if (cpu == smp_processor_id()) {
 			handle_backtrace_ipi(NULL);
-		else
-			smp_send_safe_nmi_ipi(cpu, handle_backtrace_ipi, 5 * USEC_PER_SEC);
-	}
+			continue;
+		}
 
-	for_each_cpu(cpu, mask) {
-		struct paca_struct *p = paca_ptrs[cpu];
+		delay_us = 5 * USEC_PER_SEC;
+
+		if (smp_send_safe_nmi_ipi(cpu, handle_backtrace_ipi, delay_us)) {
+			// Now wait up to 5s for the other CPU to do its backtrace
+			while (cpumask_test_cpu(cpu, mask) && delay_us) {
+				udelay(1);
+				delay_us--;
+			}
+
+			// Other CPU cleared itself from the mask
+			if (delay_us)
+				continue;
+		}
+
+		p = paca_ptrs[cpu];
 
 		cpumask_clear_cpu(cpu, mask);
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/swsusp_32.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/swsusp_32.S
@@ -181,7 +181,7 @@
 #ifdef CONFIG_ALTIVEC
 	/* Stop pending alitvec streams and memory accesses */
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
  	sync
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/swsusp_asm64.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/swsusp_asm64.S
@@ -142,7 +142,7 @@
 _GLOBAL(swsusp_arch_resume)
 	/* Stop pending alitvec streams and memory accesses */
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	sync
 
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/sysfs.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/sysfs.c
@@ -31,29 +31,27 @@
 
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
-/*
- * SMT snooze delay stuff, 64-bit only for now
- */
-
 #ifdef CONFIG_PPC64
 
-/* Time in microseconds we delay before sleeping in the idle loop */
-static DEFINE_PER_CPU(long, smt_snooze_delay) = { 100 };
+/*
+ * Snooze delay has not been hooked up since 3fa8cad82b94 ("powerpc/pseries/cpuidle:
+ * smt-snooze-delay cleanup.") and has been broken even longer. As was foretold in
+ * 2014:
+ *
+ *  "ppc64_util currently utilises it. Once we fix ppc64_util, propose to clean
+ *  up the kernel code."
+ *
+ * powerpc-utils stopped using it as of 1.3.8. At some point in the future this
+ * code should be removed.
+ */
 
 static ssize_t store_smt_snooze_delay(struct device *dev,
 				      struct device_attribute *attr,
 				      const char *buf,
 				      size_t count)
 {
-	struct cpu *cpu = container_of(dev, struct cpu, dev);
-	ssize_t ret;
-	long snooze;
-
-	ret = sscanf(buf, "%ld", &snooze);
-	if (ret != 1)
-		return -EINVAL;
-
-	per_cpu(smt_snooze_delay, cpu->dev.id) = snooze;
+	pr_warn_once("%s (%d) stored to unsupported smt_snooze_delay, which has no effect.\n",
+		     current->comm, current->pid);
 	return count;
 }
 
@@ -61,9 +59,9 @@
 				     struct device_attribute *attr,
 				     char *buf)
 {
-	struct cpu *cpu = container_of(dev, struct cpu, dev);
-
-	return sprintf(buf, "%ld\n", per_cpu(smt_snooze_delay, cpu->dev.id));
+	pr_warn_once("%s (%d) read from unsupported smt_snooze_delay\n",
+		     current->comm, current->pid);
+	return sprintf(buf, "100\n");
 }
 
 static DEVICE_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay,
@@ -71,16 +69,10 @@
 
 static int __init setup_smt_snooze_delay(char *str)
 {
-	unsigned int cpu;
-	long snooze;
-
 	if (!cpu_has_feature(CPU_FTR_SMT))
 		return 1;
 
-	snooze = simple_strtol(str, NULL, 10);
-	for_each_possible_cpu(cpu)
-		per_cpu(smt_snooze_delay, cpu) = snooze;
-
+	pr_warn("smt-snooze-delay command line option has no effect\n");
 	return 1;
 }
 __setup("smt-snooze-delay=", setup_smt_snooze_delay);
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/systbl.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/systbl.S
@@ -25,6 +25,7 @@
 #include <asm/syscall_table_64.h>
 #undef __SYSCALL
 #else
+	.p2align	2
 #define __SYSCALL(nr, entry)	.long entry
 #include <asm/syscall_table_32.h>
 #undef __SYSCALL
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/tau_6xx.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/tau_6xx.c
@@ -13,13 +13,14 @@
  */
 
 #include <linux/errno.h>
-#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <asm/reg.h>
@@ -39,9 +40,7 @@
 	unsigned char grew;
 } tau[NR_CPUS];
 
-struct timer_list tau_timer;
-
-#undef DEBUG
+static bool tau_int_enable;
 
 /* TODO: put these in a /proc interface, with some sanity checks, and maybe
  * dynamic adjustment to minimize # of interrupts */
@@ -50,72 +49,49 @@
 #define step_size		2	/* step size when temp goes out of range */
 #define window_expand		1	/* expand the window by this much */
 /* configurable values for shrinking the window */
-#define shrink_timer	2*HZ	/* period between shrinking the window */
+#define shrink_timer	2000	/* period between shrinking the window */
 #define min_window	2	/* minimum window size, degrees C */
 
 static void set_thresholds(unsigned long cpu)
 {
-#ifdef CONFIG_TAU_INT
-	/*
-	 * setup THRM1,
-	 * threshold, valid bit, enable interrupts, interrupt when below threshold
-	 */
-	mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID);
+	u32 maybe_tie = tau_int_enable ? THRM1_TIE : 0;
 
-	/* setup THRM2,
-	 * threshold, valid bit, enable interrupts, interrupt when above threshold
-	 */
-	mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE);
-#else
-	/* same thing but don't enable interrupts */
-	mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID);
-	mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V);
-#endif
+	/* setup THRM1, threshold, valid bit, interrupt when below threshold */
+	mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | maybe_tie | THRM1_TID);
+
+	/* setup THRM2, threshold, valid bit, interrupt when above threshold */
+	mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | maybe_tie);
 }
 
 static 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
@@ -140,17 +116,16 @@
 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
+	if (!tau_int_enable)
+		TAUupdate(cpu);
+
+	/* Stop thermal sensor comparisons and interrupts */
+	mtspr(SPRN_THRM3, 0);
 
 	size = tau[cpu].high - tau[cpu].low;
 	if (size > min_window && ! tau[cpu].grew) {
@@ -173,32 +148,26 @@
 
 	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(struct timer_list *unused)
-{
+static struct workqueue_struct *tau_workq;
 
-	/* schedule ourselves to be run again */
-	mod_timer(&tau_timer, jiffies + shrink_timer) ;
+static void tau_work_func(struct work_struct *work)
+{
+	msleep(shrink_timer);
 	on_each_cpu(tau_timeout, NULL, 0);
+	/* schedule ourselves to be run again */
+	queue_work(tau_workq, work);
 }
 
+DECLARE_WORK(tau_work, tau_work_func);
+
 /*
  * setup the TAU
  *
@@ -231,21 +200,19 @@
 		return 1;
 	}
 
+	tau_int_enable = IS_ENABLED(CONFIG_TAU_INT) &&
+			 !strcmp(cur_cpu_spec->platform, "ppc750");
 
-	/* first, set up the window shrinking timer */
-	timer_setup(&tau_timer, tau_timeout_smp, 0);
-	tau_timer.expires = jiffies + shrink_timer;
-	add_timer(&tau_timer);
+	tau_workq = alloc_workqueue("tau", WQ_UNBOUND, 1, 0);
+	if (!tau_workq)
+		return -ENOMEM;
 
 	on_each_cpu(TAU_init_smp, NULL, 0);
 
-	printk("Thermal assist unit ");
-#ifdef CONFIG_TAU_INT
-	printk("using interrupts, ");
-#else
-	printk("using timers, ");
-#endif
-	printk("shrink_timer: %d jiffies\n", shrink_timer);
+	queue_work(tau_workq, &tau_work);
+
+	pr_info("Thermal assist unit using %s, shrink_timer: %d ms\n",
+		tau_int_enable ? "interrupts" : "workqueue", shrink_timer);
 	tau_initialized = 1;
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/time.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/time.c
@@ -232,7 +232,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;
 	unsigned long save_irq_soft_mask = irq_soft_mask_return();
@@ -522,35 +522,6 @@
 		"i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
-void arch_irq_work_raise(void)
-{
-	preempt_disable();
-	set_irq_work_pending_flag();
-	/*
-	 * Non-nmi code running with interrupts disabled will replay
-	 * irq_happened before it re-enables interrupts, so setthe
-	 * decrementer there instead of causing a hardware exception
-	 * which would immediately hit the masked interrupt handler
-	 * and have the net effect of setting the decrementer in
-	 * irq_happened.
-	 *
-	 * NMI interrupts can not check this when they return, so the
-	 * decrementer hardware exception is raised, which will fire
-	 * when interrupts are next enabled.
-	 *
-	 * BookE does not support this yet, it must audit all NMI
-	 * interrupt handlers to ensure they call nmi_enter() so this
-	 * check would be correct.
-	 */
-	if (IS_ENABLED(CONFIG_BOOKE) || !irqs_disabled() || in_nmi()) {
-		set_dec(1);
-	} else {
-		hard_irq_disable();
-		local_paca->irq_happened |= PACA_IRQ_DEC;
-	}
-	preempt_enable();
-}
-
 #else /* 32-bit */
 
 DEFINE_PER_CPU(u8, irq_work_pending);
@@ -559,16 +530,27 @@
 #define test_irq_work_pending()		__this_cpu_read(irq_work_pending)
 #define clear_irq_work_pending()	__this_cpu_write(irq_work_pending, 0)
 
+#endif /* 32 vs 64 bit */
+
 void arch_irq_work_raise(void)
 {
+	/*
+	 * 64-bit code that uses irq soft-mask can just cause an immediate
+	 * interrupt here that gets soft masked, if this is called under
+	 * local_irq_disable(). It might be possible to prevent that happening
+	 * by noticing interrupts are disabled and setting decrementer pending
+	 * to be replayed when irqs are enabled. The problem there is that
+	 * tracing can call irq_work_raise, including in code that does low
+	 * level manipulations of irq soft-mask state (e.g., trace_hardirqs_on)
+	 * which could get tangled up if we're messing with the same state
+	 * here.
+	 */
 	preempt_disable();
 	set_irq_work_pending_flag();
 	set_dec(1);
 	preempt_enable();
 }
 
-#endif /* 32 vs 64 bit */
-
 #else  /* CONFIG_IRQ_WORK */
 
 #define test_irq_work_pending()	0
@@ -959,6 +941,7 @@
 	vdso_data->wtom_clock_nsec = tk->wall_to_monotonic.tv_nsec;
 	vdso_data->stamp_xtime = xt;
 	vdso_data->stamp_sec_fraction = frac_sec;
+	vdso_data->hrtimer_res = hrtimer_resolution;
 	smp_wmb();
 	++(vdso_data->tb_update_count);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/trace/ftrace.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/trace/ftrace.c
@@ -328,9 +328,7 @@
 
 	/* Is this a known long jump tramp? */
 	for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
-		if (!ftrace_tramps[i])
-			break;
-		else if (ftrace_tramps[i] == tramp)
+		if (ftrace_tramps[i] == tramp)
 			return 0;
 
 	/* Is this a known plt tramp? */
@@ -868,6 +866,17 @@
 
 extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
 
+void ftrace_free_init_tramp(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_FTRACE_TRAMPS && ftrace_tramps[i]; i++)
+		if (ftrace_tramps[i] == (unsigned long)ftrace_tramp_init) {
+			ftrace_tramps[i] = 0;
+			return;
+		}
+}
+
 int __init ftrace_dyn_arch_init(void)
 {
 	int i;
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
@@ -36,6 +36,9 @@
 	/* Save the original return address in A's stack frame */
 	std	r0,LRSAVE(r1)
 
+	/* Create a minimal stack frame for representing B */
+	stdu	r1, -STACK_FRAME_MIN_SIZE(r1)
+
 	/* Create our stack frame + pt_regs */
 	stdu	r1,-SWITCH_FRAME_SIZE(r1)
 
@@ -52,7 +55,7 @@
 	SAVE_10GPRS(22, r1)
 
 	/* Save previous stack pointer (r1) */
-	addi	r8, r1, SWITCH_FRAME_SIZE
+	addi	r8, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
 	std	r8, GPR1(r1)
 
 	/* Load special regs for save below */
@@ -65,6 +68,8 @@
 	mflr	r7
 	/* Save it as pt_regs->nip */
 	std     r7, _NIP(r1)
+	/* Also save it in B's stackframe header for proper unwind */
+	std	r7, LRSAVE+SWITCH_FRAME_SIZE(r1)
 	/* Save the read LR in pt_regs->link */
 	std     r0, _LINK(r1)
 
@@ -121,7 +126,7 @@
 	ld	r2, 24(r1)
 
 	/* Pop our stack frame */
-	addi r1, r1, SWITCH_FRAME_SIZE
+	addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
 
 #ifdef CONFIG_LIVEPATCH
         /* Based on the cmpd above, if the NIP was altered handle livepatch */
@@ -145,7 +150,7 @@
 	mflr	r3
 	mtctr	r3
 	REST_GPR(3, r1)
-	addi	r1, r1, SWITCH_FRAME_SIZE
+	addi	r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
 	mtlr	r0
 	bctr
 
@@ -153,6 +158,9 @@
 	/* Save the original return address in A's stack frame */
 	std	r0, LRSAVE(r1)
 
+	/* Create a minimal stack frame for representing B */
+	stdu	r1, -STACK_FRAME_MIN_SIZE(r1)
+
 	/* Create our stack frame + pt_regs */
 	stdu	r1, -SWITCH_FRAME_SIZE(r1)
 
@@ -166,6 +174,7 @@
 	/* Get the _mcount() call site out of LR */
 	mflr	r7
 	std     r7, _NIP(r1)
+	std	r7, LRSAVE+SWITCH_FRAME_SIZE(r1)
 
 	/* Save callee's TOC in the ABI compliant location */
 	std	r2, 24(r1)
@@ -200,7 +209,7 @@
 	ld	r2, 24(r1)
 
 	/* Pop our stack frame */
-	addi	r1, r1, SWITCH_FRAME_SIZE
+	addi	r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
 
 	/* Reload original LR */
 	ld	r0, LRSAVE(r1)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/traps.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/traps.c
@@ -246,19 +246,26 @@
 
 	if (panic_on_oops)
 		panic("Fatal exception");
-	do_exit(signr);
+	make_task_dead(signr);
 }
 NOKPROBE_SYMBOL(oops_end);
 
+static char *get_mmu_str(void)
+{
+	if (early_radix_enabled())
+		return " MMU=Radix";
+	if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
+		return " MMU=Hash";
+	return "";
+}
+
 static int __die(const char *str, struct pt_regs *regs, long err)
 {
 	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 
-	printk("%s PAGE_SIZE=%luK%s%s%s%s%s%s%s %s\n",
+	printk("%s PAGE_SIZE=%luK%s%s%s%s%s%s %s\n",
 	       IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? "LE" : "BE",
-	       PAGE_SIZE / 1024,
-	       early_radix_enabled() ? " MMU=Radix" : "",
-	       early_mmu_has_feature(MMU_FTR_HPTE_TABLE) ? " MMU=Hash" : "",
+	       PAGE_SIZE / 1024, get_mmu_str(),
 	       IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "",
 	       IS_ENABLED(CONFIG_SMP) ? " SMP" : "",
 	       IS_ENABLED(CONFIG_SMP) ? (" NR_CPUS=" __stringify(NR_CPUS)) : "",
@@ -503,11 +510,14 @@
 #ifdef CONFIG_PPC_BOOK3S_64
 	BUG_ON(get_paca()->in_nmi == 0);
 	if (get_paca()->in_nmi > 1)
-		nmi_panic(regs, "Unrecoverable nested System Reset");
+		die("Unrecoverable nested System Reset", regs, SIGABRT);
 #endif
 	/* Must die if the interrupt is not recoverable */
-	if (!(regs->msr & MSR_RI))
-		nmi_panic(regs, "Unrecoverable System Reset");
+	if (!(regs->msr & MSR_RI)) {
+		/* For the reason explained in die_mce, nmi_exit before die */
+		nmi_exit();
+		die("Unrecoverable System Reset", regs, SIGABRT);
+	}
 
 	if (saved_hsrrs) {
 		mtspr(SPRN_HSRR0, hsrr0);
@@ -851,7 +861,7 @@
 
 	/* Must die if the interrupt is not recoverable */
 	if (!(regs->msr & MSR_RI))
-		nmi_panic(regs, "Unrecoverable Machine check");
+		die("Unrecoverable Machine check", regs, SIGBUS);
 
 	return;
 
@@ -870,7 +880,7 @@
 {
 	unsigned int ra, rb, t, i, sel, instr, rc;
 	const void __user *addr;
-	u8 vbuf[16], *vdst;
+	u8 vbuf[16] __aligned(16), *vdst;
 	unsigned long ea, msr, msr_mask;
 	bool swap;
 
@@ -1414,10 +1424,12 @@
 	return -EINVAL;
 }
 
+#ifdef CONFIG_GENERIC_BUG
 int is_valid_bugaddr(unsigned long addr)
 {
 	return is_kernel_addr(addr);
 }
+#endif
 
 #ifdef CONFIG_MATH_EMULATION
 static int emulate_math(struct pt_regs *regs)
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/vdso.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/vdso.c
@@ -682,7 +682,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-ein-5.4.0.orig/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -156,12 +156,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-ein-5.4.0.orig/arch/powerpc/kernel/vdso64/cacheflush.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/vdso64/cacheflush.S
@@ -35,7 +35,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
@@ -52,7 +52,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-ein-5.4.0.orig/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -186,12 +186,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
 	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-ein-5.4.0.orig/arch/powerpc/kernel/vector.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/vector.S
@@ -32,6 +32,7 @@
 	mfvscr	v0
 	li	r4, VRSTATE_VSCR
 	stvx	v0, r4, r3
+	lvx	v0, 0, r3
 	blr
 EXPORT_SYMBOL(store_vr_state)
 
@@ -102,6 +103,7 @@
 	mfvscr	v0
 	li	r4,VRSTATE_VSCR
 	stvx	v0,r4,r7
+	lvx	v0,0,r7
 	blr
 
 #ifdef CONFIG_VSX
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/powerpc/kernel/vmlinux.lds.S
@@ -6,6 +6,7 @@
 #endif
 
 #define BSS_FIRST_SECTIONS *(.bss.prominit)
+#define RUNTIME_DISCARD_EXIT
 
 #include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
@@ -98,10 +99,11 @@
 		ALIGN_FUNCTION();
 #endif
 		/* careful! __ftr_alt_* sections need to be close to .text */
-		*(.text.hot TEXT_MAIN .text.fixup .text.unlikely .fixup __ftr_alt_* .ref.text);
+		*(.text.hot .text.hot.* TEXT_MAIN .text.fixup .text.unlikely .text.unlikely.* .fixup __ftr_alt_* .ref.text);
 #ifdef CONFIG_PPC64
 		*(.tramp.ftrace.text);
 #endif
+		NOINSTR_TEXT
 		SCHED_TEXT
 		CPUIDLE_TEXT
 		LOCK_TEXT
@@ -144,6 +146,20 @@
 	}
 
 	. = 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)
@@ -196,6 +212,12 @@
 	.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
 		_sinittext = .;
 		INIT_TEXT
+
+		/*
+		 *.init.text might be RO so we must ensure this section ends on
+		 * a page boundary.
+		 */
+		. = ALIGN(PAGE_SIZE);
 		_einittext = .;
 #ifdef CONFIG_PPC64
 		*(.tramp.ftrace.init);
@@ -209,21 +231,9 @@
 		EXIT_TEXT
 	}
 
-	.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
-		INIT_DATA
-	}
-
-	.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
-		INIT_SETUP(16)
-	}
-
-	.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
-		INIT_CALLS
-	}
+	. = ALIGN(PAGE_SIZE);
 
-	.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
-		CON_INITCALL
-	}
+	INIT_DATA_SECTION(16)
 
 	. = ALIGN(8);
 	__ftr_fixup : AT(ADDR(__ftr_fixup) - LOAD_OFFSET) {
@@ -251,9 +261,6 @@
 		__stop___fw_ftr_fixup = .;
 	}
 #endif
-	.init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
-		INIT_RAM_FS
-	}
 
 	PERCPU_SECTION(L1_CACHE_BYTES)
 
@@ -388,9 +395,12 @@
 	DISCARDS
 	/DISCARD/ : {
 		*(*.EMB.apuinfo)
-		*(.glink .iplt .plt .rela* .comment)
+		*(.glink .iplt .plt .comment)
 		*(.gnu.version*)
 		*(.gnu.attributes)
 		*(.eh_frame)
+#ifndef CONFIG_RELOCATABLE
+		*(.rela*)
+#endif
 	}
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kernel/watchdog.c
+++ linux-ein-5.4.0/arch/powerpc/kernel/watchdog.c
@@ -132,6 +132,10 @@
 {
 	cpumask_or(&wd_smp_cpus_stuck, &wd_smp_cpus_stuck, cpumask);
 	cpumask_andnot(&wd_smp_cpus_pending, &wd_smp_cpus_pending, cpumask);
+	/*
+	 * See wd_smp_clear_cpu_pending()
+	 */
+	smp_mb();
 	if (cpumask_empty(&wd_smp_cpus_pending)) {
 		wd_smp_last_reset_tb = tb;
 		cpumask_andnot(&wd_smp_cpus_pending,
@@ -217,13 +221,44 @@
 
 			cpumask_clear_cpu(cpu, &wd_smp_cpus_stuck);
 			wd_smp_unlock(&flags);
+		} else {
+			/*
+			 * The last CPU to clear pending should have reset the
+			 * watchdog so we generally should not find it empty
+			 * here if our CPU was clear. However it could happen
+			 * due to a rare race with another CPU taking the
+			 * last CPU out of the mask concurrently.
+			 *
+			 * We can't add a warning for it. But just in case
+			 * there is a problem with the watchdog that is causing
+			 * the mask to not be reset, try to kick it along here.
+			 */
+			if (unlikely(cpumask_empty(&wd_smp_cpus_pending)))
+				goto none_pending;
 		}
 		return;
 	}
+
 	cpumask_clear_cpu(cpu, &wd_smp_cpus_pending);
+
+	/*
+	 * Order the store to clear pending with the load(s) to check all
+	 * words in the pending mask to check they are all empty. This orders
+	 * with the same barrier on another CPU. This prevents two CPUs
+	 * clearing the last 2 pending bits, but neither seeing the other's
+	 * store when checking if the mask is empty, and missing an empty
+	 * mask, which ends with a false positive.
+	 */
+	smp_mb();
 	if (cpumask_empty(&wd_smp_cpus_pending)) {
 		unsigned long flags;
 
+none_pending:
+		/*
+		 * Double check under lock because more than one CPU could see
+		 * a clear mask with the lockless check after clearing their
+		 * pending bits.
+		 */
 		wd_smp_lock(&flags);
 		if (cpumask_empty(&wd_smp_cpus_pending)) {
 			wd_smp_last_reset_tb = tb;
@@ -314,8 +349,12 @@
 {
 	unsigned long ticks = tb_ticks_per_usec * wd_timer_period_ms * 1000;
 	int cpu = smp_processor_id();
-	u64 tb = get_tb();
+	u64 tb;
 
+	if (!cpumask_test_cpu(cpu, &watchdog_cpumask))
+		return;
+
+	tb = get_tb();
 	if (tb - per_cpu(wd_timer_tb, cpu) >= ticks) {
 		per_cpu(wd_timer_tb, cpu) = tb;
 		wd_smp_clear_cpu_pending(cpu, tb);
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s.c
@@ -867,7 +867,8 @@
 	kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old, new, change);
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+			unsigned flags)
 {
 	return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -31,14 +31,15 @@
 					      gva_t eaddr, void *to, void *from,
 					      unsigned long n)
 {
-	int uninitialized_var(old_pid), old_lpid;
+	int old_pid, old_lpid;
 	unsigned long quadrant, ret = n;
 	bool is_load = !!to;
 
 	/* Can't access quadrants 1 or 2 in non-HV mode, call the HV to do it */
 	if (kvmhv_on_pseries())
 		return plpar_hcall_norets(H_COPY_TOFROM_GUEST, lpid, pid, eaddr,
-					  __pa(to), __pa(from), n);
+					  (to != NULL) ? __pa(to): 0,
+					  (from != NULL) ? __pa(from): 0, n);
 
 	quadrant = 1;
 	if (!pid)
@@ -353,7 +354,13 @@
 
 static pte_t *kvmppc_pte_alloc(void)
 {
-	return kmem_cache_alloc(kvm_pte_cache, GFP_KERNEL);
+	pte_t *pte;
+
+	pte = kmem_cache_alloc(kvm_pte_cache, GFP_KERNEL);
+	/* pmd_populate() will only reference _pa(pte). */
+	kmemleak_ignore(pte);
+
+	return pte;
 }
 
 static void kvmppc_pte_free(pte_t *ptep)
@@ -363,7 +370,13 @@
 
 static pmd_t *kvmppc_pmd_alloc(void)
 {
-	return kmem_cache_alloc(kvm_pmd_cache, GFP_KERNEL);
+	pmd_t *pmd;
+
+	pmd = kmem_cache_alloc(kvm_pmd_cache, GFP_KERNEL);
+	/* pud_populate() will only reference _pa(pmd). */
+	kmemleak_ignore(pmd);
+
+	return pmd;
 }
 
 static void kvmppc_pmd_free(pmd_t *pmdp)
@@ -1091,6 +1104,11 @@
 					 kvm->arch.lpid);
 		gpa += PAGE_SIZE;
 	}
+	/*
+	 * Increase the mmu notifier sequence number to prevent any page
+	 * fault that read the memslot earlier from writing a PTE.
+	 */
+	kvm->mmu_notifier_seq++;
 	spin_unlock(&kvm->mmu_lock);
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_64_vio.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_64_vio.c
@@ -74,6 +74,7 @@
 	struct kvmppc_spapr_tce_iommu_table *stit, *tmp;
 	struct iommu_table_group *table_group = NULL;
 
+	rcu_read_lock();
 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
 
 		table_group = iommu_group_get_iommudata(grp);
@@ -88,7 +89,9 @@
 				kref_put(&stit->kref, kvm_spapr_tce_liobn_put);
 			}
 		}
+		cond_resched_rcu();
 	}
+	rcu_read_unlock();
 }
 
 extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd,
@@ -106,12 +109,14 @@
 	if (!f.file)
 		return -EBADF;
 
+	rcu_read_lock();
 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
 		if (stt == f.file->private_data) {
 			found = true;
 			break;
 		}
 	}
+	rcu_read_unlock();
 
 	fdput(f);
 
@@ -144,6 +149,7 @@
 	if (!tbl)
 		return -EINVAL;
 
+	rcu_read_lock();
 	list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
 		if (tbl != stit->tbl)
 			continue;
@@ -151,14 +157,17 @@
 		if (!kref_get_unless_zero(&stit->kref)) {
 			/* stit is being destroyed */
 			iommu_tce_table_put(tbl);
+			rcu_read_unlock();
 			return -ENOTTY;
 		}
 		/*
 		 * The table is already known to this KVM, we just increased
 		 * its KVM reference counter and can return.
 		 */
+		rcu_read_unlock();
 		return 0;
 	}
+	rcu_read_unlock();
 
 	stit = kzalloc(sizeof(*stit), GFP_KERNEL);
 	if (!stit) {
@@ -364,18 +373,19 @@
 	if (kvmppc_tce_to_ua(stt->kvm, tce, &ua))
 		return H_TOO_HARD;
 
+	rcu_read_lock();
 	list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
 		unsigned long hpa = 0;
 		struct mm_iommu_table_group_mem_t *mem;
 		long shift = stit->tbl->it_page_shift;
 
 		mem = mm_iommu_lookup(stt->kvm->mm, ua, 1ULL << shift);
-		if (!mem)
-			return H_TOO_HARD;
-
-		if (mm_iommu_ua_to_hpa(mem, ua, shift, &hpa))
+		if (!mem || mm_iommu_ua_to_hpa(mem, ua, shift, &hpa)) {
+			rcu_read_unlock();
 			return H_TOO_HARD;
+		}
 	}
+	rcu_read_unlock();
 
 	return H_SUCCESS;
 }
@@ -410,13 +420,19 @@
 	tbl[idx % TCES_PER_PAGE] = tce;
 }
 
-static void kvmppc_clear_tce(struct mm_struct *mm, struct iommu_table *tbl,
-		unsigned long entry)
+static void kvmppc_clear_tce(struct mm_struct *mm, struct kvmppc_spapr_tce_table *stt,
+		struct iommu_table *tbl, unsigned long entry)
 {
-	unsigned long hpa = 0;
-	enum dma_data_direction dir = DMA_NONE;
+	unsigned long i;
+	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+	unsigned long io_entry = entry << (stt->page_shift - tbl->it_page_shift);
+
+	for (i = 0; i < subpages; ++i) {
+		unsigned long hpa = 0;
+		enum dma_data_direction dir = DMA_NONE;
 
-	iommu_tce_xchg_no_kill(mm, tbl, entry, &hpa, &dir);
+		iommu_tce_xchg_no_kill(mm, tbl, io_entry + i, &hpa, &dir);
+	}
 }
 
 static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
@@ -475,6 +491,8 @@
 			break;
 	}
 
+	iommu_tce_kill(tbl, io_entry, subpages);
+
 	return ret;
 }
 
@@ -534,6 +552,8 @@
 			break;
 	}
 
+	iommu_tce_kill(tbl, io_entry, subpages);
+
 	return ret;
 }
 
@@ -580,10 +600,9 @@
 			ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl,
 					entry, ua, dir);
 
-		iommu_tce_kill(stit->tbl, entry, 1);
 
 		if (ret != H_SUCCESS) {
-			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
+			kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl, entry);
 			goto unlock_exit;
 		}
 	}
@@ -659,13 +678,13 @@
 		 */
 		if (get_user(tce, tces + i)) {
 			ret = H_TOO_HARD;
-			goto invalidate_exit;
+			goto unlock_exit;
 		}
 		tce = be64_to_cpu(tce);
 
 		if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua)) {
 			ret = H_PARAMETER;
-			goto invalidate_exit;
+			goto unlock_exit;
 		}
 
 		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -674,19 +693,15 @@
 					iommu_tce_direction(tce));
 
 			if (ret != H_SUCCESS) {
-				kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl,
-						entry);
-				goto invalidate_exit;
+				kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl,
+						 entry + i);
+				goto unlock_exit;
 			}
 		}
 
 		kvmppc_tce_put(stt, entry + i, tce);
 	}
 
-invalidate_exit:
-	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
-		iommu_tce_kill(stit->tbl, entry, npages);
-
 unlock_exit:
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 
@@ -725,20 +740,16 @@
 				continue;
 
 			if (ret == H_TOO_HARD)
-				goto invalidate_exit;
+				return ret;
 
 			WARN_ON_ONCE(1);
-			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
+			kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl, entry + i);
 		}
 	}
 
 	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
 		kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);
 
-invalidate_exit:
-	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
-		iommu_tce_kill(stit->tbl, ioba >> stt->page_shift, npages);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(kvmppc_h_stuff_tce);
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -177,10 +177,13 @@
 	idx -= stt->offset;
 	page = stt->pages[idx / TCES_PER_PAGE];
 	/*
-	 * page must not be NULL in real mode,
-	 * kvmppc_rm_ioba_validate() must have taken care of this.
+	 * kvmppc_rm_ioba_validate() allows pages not be allocated if TCE is
+	 * being cleared, otherwise it returns H_TOO_HARD and we skip this.
 	 */
-	WARN_ON_ONCE_RM(!page);
+	if (!page) {
+		WARN_ON_ONCE_RM(tce != 0);
+		return;
+	}
 	tbl = kvmppc_page_address(page);
 
 	tbl[idx % TCES_PER_PAGE] = tce;
@@ -248,13 +251,19 @@
 		tbl->it_ops->tce_kill(tbl, entry, pages, true);
 }
 
-static void kvmppc_rm_clear_tce(struct kvm *kvm, struct iommu_table *tbl,
-		unsigned long entry)
+static void kvmppc_rm_clear_tce(struct kvm *kvm, struct kvmppc_spapr_tce_table *stt,
+		struct iommu_table *tbl, unsigned long entry)
 {
-	unsigned long hpa = 0;
-	enum dma_data_direction dir = DMA_NONE;
+	unsigned long i;
+	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+	unsigned long io_entry = entry << (stt->page_shift - tbl->it_page_shift);
+
+	for (i = 0; i < subpages; ++i) {
+		unsigned long hpa = 0;
+		enum dma_data_direction dir = DMA_NONE;
 
-	iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, entry, &hpa, &dir);
+		iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, io_entry + i, &hpa, &dir);
+	}
 }
 
 static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm,
@@ -317,6 +326,8 @@
 			break;
 	}
 
+	iommu_tce_kill_rm(tbl, io_entry, subpages);
+
 	return ret;
 }
 
@@ -380,6 +391,8 @@
 			break;
 	}
 
+	iommu_tce_kill_rm(tbl, io_entry, subpages);
+
 	return ret;
 }
 
@@ -425,10 +438,8 @@
 			ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
 					stit->tbl, entry, ua, dir);
 
-		iommu_tce_kill_rm(stit->tbl, entry, 1);
-
 		if (ret != H_SUCCESS) {
-			kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry);
+			kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry);
 			return ret;
 		}
 	}
@@ -568,7 +579,7 @@
 		ua = 0;
 		if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) {
 			ret = H_PARAMETER;
-			goto invalidate_exit;
+			goto unlock_exit;
 		}
 
 		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -577,19 +588,15 @@
 					iommu_tce_direction(tce));
 
 			if (ret != H_SUCCESS) {
-				kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl,
-						entry);
-				goto invalidate_exit;
+				kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl,
+						entry + i);
+				goto unlock_exit;
 			}
 		}
 
 		kvmppc_rm_tce_put(stt, entry + i, tce);
 	}
 
-invalidate_exit:
-	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
-		iommu_tce_kill_rm(stit->tbl, entry, npages);
-
 unlock_exit:
 	if (rmap)
 		unlock_rmap(rmap);
@@ -632,20 +639,16 @@
 				continue;
 
 			if (ret == H_TOO_HARD)
-				goto invalidate_exit;
+				return ret;
 
 			WARN_ON_ONCE_RM(1);
-			kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry);
+			kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry + i);
 		}
 	}
 
 	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
 		kvmppc_rm_tce_put(stt, ioba >> stt->page_shift, tce_value);
 
-invalidate_exit:
-	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
-		iommu_tce_kill_rm(stit->tbl, ioba >> stt->page_shift, npages);
-
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv.c
@@ -58,6 +58,7 @@
 #include <asm/kvm_book3s.h>
 #include <asm/mmu_context.h>
 #include <asm/lppaca.h>
+#include <asm/pmc.h>
 #include <asm/processor.h>
 #include <asm/cputhreads.h>
 #include <asm/page.h>
@@ -2306,8 +2307,10 @@
 		HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP;
 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
 		vcpu->arch.hfscr &= mfspr(SPRN_HFSCR);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 		if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
 			vcpu->arch.hfscr |= HFSCR_TM;
+#endif
 	}
 	if (cpu_has_feature(CPU_FTR_TM_COMP))
 		vcpu->arch.hfscr |= HFSCR_TM;
@@ -2354,7 +2357,7 @@
 	mutex_unlock(&kvm->lock);
 
 	if (!vcore)
-		goto free_vcpu;
+		goto uninit_vcpu;
 
 	spin_lock(&vcore->lock);
 	++vcore->num_threads;
@@ -2371,6 +2374,8 @@
 
 	return vcpu;
 
+uninit_vcpu:
+	kvm_vcpu_uninit(vcpu);
 free_vcpu:
 	kmem_cache_free(kvm_vcpu_cache, vcpu);
 out:
@@ -2534,7 +2539,7 @@
 	cpumask_t *cpu_in_guest;
 	int i;
 
-	cpu = cpu_first_thread_sibling(cpu);
+	cpu = cpu_first_tlb_thread_sibling(cpu);
 	if (nested) {
 		cpumask_set_cpu(cpu, &nested->need_tlb_flush);
 		cpu_in_guest = &nested->cpu_in_guest;
@@ -2548,9 +2553,10 @@
 	 * the other side is the first smp_mb() in kvmppc_run_core().
 	 */
 	smp_mb();
-	for (i = 0; i < threads_per_core; ++i)
-		if (cpumask_test_cpu(cpu + i, cpu_in_guest))
-			smp_call_function_single(cpu + i, do_nothing, NULL, 1);
+	for (i = cpu; i <= cpu_last_tlb_thread_sibling(cpu);
+					i += cpu_tlb_thread_sibling_step())
+		if (cpumask_test_cpu(i, cpu_in_guest))
+			smp_call_function_single(i, do_nothing, NULL, 1);
 }
 
 static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu)
@@ -2581,8 +2587,8 @@
 	 */
 	if (prev_cpu != pcpu) {
 		if (prev_cpu >= 0 &&
-		    cpu_first_thread_sibling(prev_cpu) !=
-		    cpu_first_thread_sibling(pcpu))
+		    cpu_first_tlb_thread_sibling(prev_cpu) !=
+		    cpu_first_tlb_thread_sibling(pcpu))
 			radix_flush_cpu(kvm, prev_cpu, vcpu);
 		if (nested)
 			nested->prev_cpu[vcpu->arch.nested_vcpu_id] = pcpu;
@@ -3554,6 +3560,18 @@
 	    cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
 		kvmppc_restore_tm_hv(vcpu, vcpu->arch.shregs.msr, true);
 
+#ifdef CONFIG_PPC_PSERIES
+	if (kvmhv_on_pseries()) {
+		barrier();
+		if (vcpu->arch.vpa.pinned_addr) {
+			struct lppaca *lp = vcpu->arch.vpa.pinned_addr;
+			get_lppaca()->pmcregs_in_use = lp->pmcregs_in_use;
+		} else {
+			get_lppaca()->pmcregs_in_use = 1;
+		}
+		barrier();
+	}
+#endif
 	kvmhv_load_guest_pmu(vcpu);
 
 	msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX);
@@ -3621,6 +3639,7 @@
 		if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested &&
 		    kvmppc_get_gpr(vcpu, 3) == H_CEDE) {
 			kvmppc_nested_cede(vcpu);
+			kvmppc_set_gpr(vcpu, 3, 0);
 			trap = 0;
 		}
 	} else {
@@ -3635,7 +3654,10 @@
 	vcpu->arch.dec_expires = dec + tb;
 	vcpu->cpu = -1;
 	vcpu->arch.thread_cpu = -1;
+	/* Save guest CTRL register, set runlatch to 1 */
 	vcpu->arch.ctrl = mfspr(SPRN_CTRLF);
+	if (!(vcpu->arch.ctrl & 1))
+		mtspr(SPRN_CTRLT, vcpu->arch.ctrl | 1);
 
 	vcpu->arch.iamr = mfspr(SPRN_IAMR);
 	vcpu->arch.pspb = mfspr(SPRN_PSPB);
@@ -3684,6 +3706,13 @@
 	save_pmu |= nesting_enabled(vcpu->kvm);
 
 	kvmhv_save_guest_pmu(vcpu, save_pmu);
+#ifdef CONFIG_PPC_PSERIES
+	if (kvmhv_on_pseries()) {
+		barrier();
+		get_lppaca()->pmcregs_in_use = ppc_get_pmu_inuse();
+		barrier();
+	}
+#endif
 
 	vc->entry_exit_map = 0x101;
 	vc->in_guest = 0;
@@ -5188,6 +5217,12 @@
 	case KVM_PPC_ALLOCATE_HTAB: {
 		u32 htab_order;
 
+		/* If we're a nested hypervisor, we currently only support radix */
+		if (kvmhv_on_pseries()) {
+			r = -EOPNOTSUPP;
+			break;
+		}
+
 		r = -EFAULT;
 		if (get_user(htab_order, (u32 __user *)argp))
 			break;
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_builtin.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -821,6 +821,7 @@
 				       "r" (0) : "memory");
 		}
 		asm volatile("ptesync": : :"memory");
+		// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
 		asm volatile(PPC_RADIX_INVALIDATE_ERAT_GUEST : : :"memory");
 	} else {
 		for (set = 0; set < kvm->arch.tlb_sets; ++set) {
@@ -831,7 +832,9 @@
 			rb += PPC_BIT(51);	/* increment set number */
 		}
 		asm volatile("ptesync": : :"memory");
-		asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
+		// POWER9 congruence-class TLBIEL leaves ERAT. Flush it now.
+		if (cpu_has_feature(CPU_FTR_ARCH_300))
+			asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
 	}
 }
 
@@ -847,7 +850,7 @@
 	 * Thus we make all 4 threads use the same bit.
 	 */
 	if (cpu_has_feature(CPU_FTR_ARCH_300))
-		pcpu = cpu_first_thread_sibling(pcpu);
+		pcpu = cpu_first_tlb_thread_sibling(pcpu);
 
 	if (nested)
 		need_tlb_flush = &nested->need_tlb_flush;
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_nested.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_nested.c
@@ -51,7 +51,8 @@
 	hr->ppr = vcpu->arch.ppr;
 }
 
-static void byteswap_pt_regs(struct pt_regs *regs)
+/* Use noinline_for_stack due to https://bugs.llvm.org/show_bug.cgi?id=49610 */
+static noinline_for_stack void byteswap_pt_regs(struct pt_regs *regs)
 {
 	unsigned long *addr = (unsigned long *) regs;
 
@@ -231,6 +232,9 @@
 	if (vcpu->kvm->arch.l1_ptcr == 0)
 		return H_NOT_AVAILABLE;
 
+	if (MSR_TM_TRANSACTIONAL(vcpu->arch.shregs.msr))
+		return H_BAD_MODE;
+
 	/* copy parameters in */
 	hv_ptr = kvmppc_get_gpr(vcpu, 4);
 	err = kvm_vcpu_read_guest(vcpu, hv_ptr, &l2_hv,
@@ -252,6 +256,23 @@
 	if (l2_hv.vcpu_token >= NR_CPUS)
 		return H_PARAMETER;
 
+	/*
+	 * L1 must have set up a suspended state to enter the L2 in a
+	 * transactional state, and only in that case. These have to be
+	 * filtered out here to prevent causing a TM Bad Thing in the
+	 * host HRFID. We could synthesize a TM Bad Thing back to the L1
+	 * here but there doesn't seem like much point.
+	 */
+	if (MSR_TM_SUSPENDED(vcpu->arch.shregs.msr)) {
+		if (!MSR_TM_ACTIVE(l2_regs.msr))
+			return H_BAD_MODE;
+	} else {
+		if (l2_regs.msr & MSR_TS_MASK)
+			return H_BAD_MODE;
+		if (WARN_ON_ONCE(vcpu->arch.shregs.msr & MSR_TS_MASK))
+			return H_BAD_MODE;
+	}
+
 	/* translate lpid */
 	l2 = kvmhv_get_nested(vcpu->kvm, l2_hv.lpid, true);
 	if (!l2)
@@ -489,7 +510,7 @@
 	if (eaddr & (0xFFFUL << 52))
 		return H_PARAMETER;
 
-	buf = kzalloc(n, GFP_KERNEL);
+	buf = kzalloc(n, GFP_KERNEL | __GFP_NOWARN);
 	if (!buf)
 		return H_NO_MEM;
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -67,7 +67,7 @@
 		 * so use the bit for the first thread to represent the core.
 		 */
 		if (cpu_has_feature(CPU_FTR_ARCH_300))
-			cpu = cpu_first_thread_sibling(cpu);
+			cpu = cpu_first_tlb_thread_sibling(cpu);
 		cpumask_clear_cpu(cpu, &kvm->arch.need_tlb_flush);
 	}
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -11,6 +11,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>
@@ -291,13 +292,16 @@
  * r3 contains the SRR1 wakeup value, SRR1 is trashed.
  */
 _GLOBAL(idle_kvm_start_guest)
-	ld	r4,PACAEMERGSP(r13)
 	mfcr	r5
 	mflr	r0
-	std	r1,0(r4)
-	std	r5,8(r4)
-	std	r0,16(r4)
-	subi	r1,r4,STACK_FRAME_OVERHEAD
+	std	r5, 8(r1)	// Save CR in caller's frame
+	std	r0, 16(r1)	// Save LR in caller's frame
+	// Create frame on emergency stack
+	ld	r4, PACAEMERGSP(r13)
+	stdu	r1, -SWITCH_FRAME_SIZE(r4)
+	// Switch to new frame on emergency stack
+	mr	r1, r4
+	std	r3, 32(r1)	// Save SRR1 wakeup value
 	SAVE_NVGPRS(r1)
 
 	/*
@@ -349,6 +353,10 @@
 
 kvm_secondary_got_guest:
 
+	// About to go to guest, clear saved SRR1
+	li	r0, 0
+	std	r0, 32(r1)
+
 	/* Set HSTATE_DSCR(r13) to something sensible */
 	ld	r6, PACA_DSCR_DEFAULT(r13)
 	std	r6, HSTATE_DSCR(r13)
@@ -440,13 +448,12 @@
 	mfspr	r4, SPRN_LPCR
 	rlwimi	r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
 	mtspr	SPRN_LPCR, r4
-	/* set up r3 for return */
-	mfspr	r3,SPRN_SRR1
+	// Return SRR1 wakeup value, or 0 if we went into the guest
+	ld	r3, 32(r1)
 	REST_NVGPRS(r1)
-	addi	r1, r1, STACK_FRAME_OVERHEAD
-	ld	r0, 16(r1)
-	ld	r5, 8(r1)
-	ld	r1, 0(r1)
+	ld	r1, 0(r1)	// Switch back to caller stack
+	ld	r0, 16(r1)	// Reload LR
+	ld	r5, 8(r1)	// Reload CR
 	mtlr	r0
 	mtcr	r5
 	blr
@@ -1116,7 +1123,7 @@
 	ld	r7, VCPU_GPR(R7)(r4)
 	bne	ret_to_ultra
 
-	lwz	r0, VCPU_CR(r4)
+	ld	r0, VCPU_CR(r4)
 	mtcr	r0
 
 	ld	r0, VCPU_GPR(R0)(r4)
@@ -1136,7 +1143,7 @@
  *   R3 = UV_RETURN
  */
 ret_to_ultra:
-	lwz	r0, VCPU_CR(r4)
+	ld	r0, VCPU_CR(r4)
 	mtcr	r0
 
 	ld	r0, VCPU_GPR(R3)(r4)
@@ -1487,6 +1494,13 @@
 1:
 #endif /* CONFIG_KVM_XICS */
 
+	/*
+	 * Possibly flush the link stack here, before we do a blr in
+	 * guest_exit_short_path.
+	 */
+1:	nop
+	patch_site 1b patch__call_kvm_flush_link_stack
+
 	/* If we came in through the P9 short path, go back out to C now */
 	lwz	r0, STACK_SLOT_SHORT_PATH(r1)
 	cmpwi	r0, 0
@@ -1963,6 +1977,28 @@
 	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
+
+	/* And on Power9 it's up to 64. */
+BEGIN_FTR_SECTION
+	.rept 32
+	bl	.+4
+	.endr
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+
+	/* Restore LR */
+	mtlr	r0
+	blr
+
 kvmppc_guest_external:
 	/* External interrupt, first check for host_ipi. If this is
 	 * set, we know the host wants us out so let's do it now
@@ -2499,7 +2535,7 @@
 	.globl	hcall_real_table_end
 hcall_real_table_end:
 
-_GLOBAL(kvmppc_h_set_xdabr)
+_GLOBAL_TOC(kvmppc_h_set_xdabr)
 EXPORT_SYMBOL_GPL(kvmppc_h_set_xdabr)
 	andi.	r0, r5, DABRX_USER | DABRX_KERNEL
 	beq	6f
@@ -2509,7 +2545,7 @@
 6:	li	r3, H_PARAMETER
 	blr
 
-_GLOBAL(kvmppc_h_set_dabr)
+_GLOBAL_TOC(kvmppc_h_set_dabr)
 EXPORT_SYMBOL_GPL(kvmppc_h_set_dabr)
 	li	r5, DABRX_USER | DABRX_KERNEL
 3:
@@ -3107,7 +3143,7 @@
 	/* The following code handles the fake_suspend = 1 case */
 	mflr	r0
 	std	r0, PPC_LR_STKOFF(r1)
-	stdu	r1, -PPC_MIN_STKFRM(r1)
+	stdu	r1, -TM_FRAME_SIZE(r1)
 
 	/* Turn on TM. */
 	mfmsr	r8
@@ -3122,10 +3158,42 @@
 END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
 	nop
 
+	/*
+	 * It's possible that treclaim. may modify registers, if we have lost
+	 * track of fake-suspend state in the guest due to it using rfscv.
+	 * Save and restore registers in case this occurs.
+	 */
+	mfspr	r3, SPRN_DSCR
+	mfspr	r4, SPRN_XER
+	mfspr	r5, SPRN_AMR
+	/* SPRN_TAR would need to be saved here if the kernel ever used it */
+	mfcr	r12
+	SAVE_NVGPRS(r1)
+	SAVE_GPR(2, r1)
+	SAVE_GPR(3, r1)
+	SAVE_GPR(4, r1)
+	SAVE_GPR(5, r1)
+	stw	r12, 8(r1)
+	std	r1, HSTATE_HOST_R1(r13)
+
 	/* We have to treclaim here because that's the only way to do S->N */
 	li	r3, TM_CAUSE_KVM_RESCHED
 	TRECLAIM(R3)
 
+	GET_PACA(r13)
+	ld	r1, HSTATE_HOST_R1(r13)
+	REST_GPR(2, r1)
+	REST_GPR(3, r1)
+	REST_GPR(4, r1)
+	REST_GPR(5, r1)
+	lwz	r12, 8(r1)
+	REST_NVGPRS(r1)
+	mtspr	SPRN_DSCR, r3
+	mtspr	SPRN_XER, r4
+	mtspr	SPRN_AMR, r5
+	mtcr	r12
+	HMT_MEDIUM
+
 	/*
 	 * We were in fake suspend, so we are not going to save the
 	 * register state as the guest checkpointed state (since
@@ -3153,7 +3221,7 @@
 	std	r5, VCPU_TFHAR(r9)
 	std	r6, VCPU_TFIAR(r9)
 
-	addi	r1, r1, PPC_MIN_STKFRM
+	addi	r1, r1, TM_FRAME_SIZE
 	ld	r0, PPC_LR_STKOFF(r1)
 	mtlr	r0
 	blr
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_tm.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_tm.c
@@ -3,6 +3,8 @@
  * Copyright 2017 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kvm_host.h>
 
 #include <asm/kvm_ppc.h>
@@ -44,7 +46,18 @@
 	u64 newmsr, bescr;
 	int ra, rs;
 
-	switch (instr & 0xfc0007ff) {
+	/*
+	 * rfid, rfebb, and mtmsrd encode bit 31 = 0 since it's a reserved bit
+	 * in these instructions, so masking bit 31 out doesn't change these
+	 * instructions. For treclaim., tsr., and trechkpt. instructions if bit
+	 * 31 = 0 then they are per ISA invalid forms, however P9 UM, in section
+	 * 4.6.10 Book II Invalid Forms, informs specifically that ignoring bit
+	 * 31 is an acceptable way to handle these invalid forms that have
+	 * bit 31 = 0. Moreover, for emulation purposes both forms (w/ and wo/
+	 * bit 31 set) can generate a softpatch interrupt. Hence both forms
+	 * are handled below for these instructions so they behave the same way.
+	 */
+	switch (instr & PO_XOP_OPCODE_MASK) {
 	case PPC_INST_RFID:
 		/* XXX do we need to check for PR=0 here? */
 		newmsr = vcpu->arch.shregs.srr1;
@@ -105,7 +118,8 @@
 		vcpu->arch.shregs.msr = newmsr;
 		return RESUME_GUEST;
 
-	case PPC_INST_TSR:
+	/* ignore bit 31, see comment above */
+	case (PPC_INST_TSR & PO_XOP_OPCODE_MASK):
 		/* check for PR=1 and arch 2.06 bit set in PCR */
 		if ((msr & MSR_PR) && (vcpu->arch.vcore->pcr & PCR_ARCH_206)) {
 			/* generate an illegal instruction interrupt */
@@ -140,7 +154,8 @@
 		vcpu->arch.shregs.msr = msr;
 		return RESUME_GUEST;
 
-	case PPC_INST_TRECLAIM:
+	/* ignore bit 31, see comment above */
+	case (PPC_INST_TRECLAIM & PO_XOP_OPCODE_MASK):
 		/* check for TM disabled in the HFSCR or MSR */
 		if (!(vcpu->arch.hfscr & HFSCR_TM)) {
 			/* generate an illegal instruction interrupt */
@@ -176,7 +191,8 @@
 		vcpu->arch.shregs.msr &= ~MSR_TS_MASK;
 		return RESUME_GUEST;
 
-	case PPC_INST_TRECHKPT:
+	/* ignore bit 31, see comment above */
+	case (PPC_INST_TRECHKPT & PO_XOP_OPCODE_MASK):
 		/* XXX do we need to check for PR=0 here? */
 		/* check for TM disabled in the HFSCR or MSR */
 		if (!(vcpu->arch.hfscr & HFSCR_TM)) {
@@ -208,6 +224,8 @@
 	}
 
 	/* What should we do here? We didn't recognize the instruction */
-	WARN_ON_ONCE(1);
+	kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+	pr_warn_ratelimited("Unrecognized TM-related instruction %#x for emulation", instr);
+
 	return RESUME_GUEST;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_hv_tm_builtin.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_hv_tm_builtin.c
@@ -23,7 +23,18 @@
 	u64 newmsr, msr, bescr;
 	int rs;
 
-	switch (instr & 0xfc0007ff) {
+	/*
+	 * rfid, rfebb, and mtmsrd encode bit 31 = 0 since it's a reserved bit
+	 * in these instructions, so masking bit 31 out doesn't change these
+	 * instructions. For the tsr. instruction if bit 31 = 0 then it is per
+	 * ISA an invalid form, however P9 UM, in section 4.6.10 Book II Invalid
+	 * Forms, informs specifically that ignoring bit 31 is an acceptable way
+	 * to handle TM-related invalid forms that have bit 31 = 0. Moreover,
+	 * for emulation purposes both forms (w/ and wo/ bit 31 set) can
+	 * generate a softpatch interrupt. Hence both forms are handled below
+	 * for tsr. to make them behave the same way.
+	 */
+	switch (instr & PO_XOP_OPCODE_MASK) {
 	case PPC_INST_RFID:
 		/* XXX do we need to check for PR=0 here? */
 		newmsr = vcpu->arch.shregs.srr1;
@@ -73,7 +84,8 @@
 		vcpu->arch.shregs.msr = newmsr;
 		return 1;
 
-	case PPC_INST_TSR:
+	/* ignore bit 31, see comment above */
+	case (PPC_INST_TSR & PO_XOP_OPCODE_MASK):
 		/* we know the MSR has the TS field = S (0b01) here */
 		msr = vcpu->arch.shregs.msr;
 		/* check for PR=1 and arch 2.06 bit set in PCR */
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_pr.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_pr.c
@@ -1769,10 +1769,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-ein-5.4.0.orig/arch/powerpc/kvm/book3s_rtas.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_rtas.c
@@ -240,6 +240,17 @@
 	 * value so we can restore it on the way out.
 	 */
 	orig_rets = args.rets;
+	if (be32_to_cpu(args.nargs) >= ARRAY_SIZE(args.args)) {
+		/*
+		 * Don't overflow our args array: ensure there is room for
+		 * at least rets[0] (even if the call specifies 0 nret).
+		 *
+		 * Each handler must then check for the correct nargs and nret
+		 * values, but they may always return failure in rets[0].
+		 */
+		rc = -EINVAL;
+		goto fail;
+	}
 	args.rets = &args.args[be32_to_cpu(args.nargs)];
 
 	mutex_lock(&vcpu->kvm->arch.rtas_token_lock);
@@ -267,9 +278,17 @@
 fail:
 	/*
 	 * We only get here if the guest has called RTAS with a bogus
-	 * args pointer. That means we can't get to the args, and so we
-	 * can't fail the RTAS call. So fail right out to userspace,
-	 * which should kill the guest.
+	 * args pointer or nargs/nret values that would overflow the
+	 * array. That means we can't get to the args, and so we can't
+	 * fail the RTAS call. So fail right out to userspace, which
+	 * should kill the guest.
+	 *
+	 * SLOF should actually pass the hcall return value from the
+	 * rtas handler call in r3, so enter_rtas could be modified to
+	 * return a failure indication in r3 and we could return such
+	 * errors to the guest rather than failing to host userspace.
+	 * However old guests that don't test for failure could then
+	 * continue silently after errors, so for now we won't do this.
 	 */
 	return rc;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_xive.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_xive.c
@@ -2005,6 +2005,10 @@
 
 	pr_devel("Creating xive for partition\n");
 
+	/* Already there ? */
+	if (kvm->arch.xive)
+		return -EEXIST;
+
 	xive = kvmppc_xive_get_device(kvm, type);
 	if (!xive)
 		return -ENOMEM;
@@ -2014,12 +2018,6 @@
 	xive->kvm = kvm;
 	mutex_init(&xive->lock);
 
-	/* Already there ? */
-	if (kvm->arch.xive)
-		ret = -EEXIST;
-	else
-		kvm->arch.xive = xive;
-
 	/* We use the default queue size set by the host */
 	xive->q_order = xive_native_default_eq_shift();
 	if (xive->q_order < PAGE_SHIFT)
@@ -2039,6 +2037,7 @@
 	if (ret)
 		return ret;
 
+	kvm->arch.xive = xive;
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/book3s_xive_native.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/book3s_xive_native.c
@@ -50,6 +50,24 @@
 	}
 }
 
+static int kvmppc_xive_native_configure_queue(u32 vp_id, struct xive_q *q,
+					      u8 prio, __be32 *qpage,
+					      u32 order, bool can_escalate)
+{
+	int rc;
+	__be32 *qpage_prev = q->qpage;
+
+	rc = xive_native_configure_queue(vp_id, q, prio, qpage, order,
+					 can_escalate);
+	if (rc)
+		return rc;
+
+	if (qpage_prev)
+		put_page(virt_to_page(qpage_prev));
+
+	return rc;
+}
+
 void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
@@ -234,6 +252,13 @@
 	}
 
 	state = &sb->irq_state[src];
+
+	/* Some sanity checking */
+	if (!state->valid) {
+		pr_devel("%s: source %lx invalid !\n", __func__, irq);
+		return VM_FAULT_SIGBUS;
+	}
+
 	kvmppc_xive_select_irq(state, &hw_num, &xd);
 
 	arch_spin_lock(&sb->lock);
@@ -582,19 +607,14 @@
 		q->guest_qaddr  = 0;
 		q->guest_qshift = 0;
 
-		rc = xive_native_configure_queue(xc->vp_id, q, priority,
-						 NULL, 0, true);
+		rc = kvmppc_xive_native_configure_queue(xc->vp_id, q, priority,
+							NULL, 0, true);
 		if (rc) {
 			pr_err("Failed to reset queue %d for VCPU %d: %d\n",
 			       priority, xc->server_num, rc);
 			return rc;
 		}
 
-		if (q->qpage) {
-			put_page(virt_to_page(q->qpage));
-			q->qpage = NULL;
-		}
-
 		return 0;
 	}
 
@@ -624,17 +644,18 @@
 
 	srcu_idx = srcu_read_lock(&kvm->srcu);
 	gfn = gpa_to_gfn(kvm_eq.qaddr);
-	page = gfn_to_page(kvm, gfn);
-	if (is_error_page(page)) {
+
+	page_size = kvm_host_page_size(vcpu, gfn);
+	if (1ull << kvm_eq.qshift > page_size) {
 		srcu_read_unlock(&kvm->srcu, srcu_idx);
-		pr_err("Couldn't get queue page %llx!\n", kvm_eq.qaddr);
+		pr_warn("Incompatible host page size %lx!\n", page_size);
 		return -EINVAL;
 	}
 
-	page_size = kvm_host_page_size(kvm, gfn);
-	if (1ull << kvm_eq.qshift > page_size) {
+	page = gfn_to_page(kvm, gfn);
+	if (is_error_page(page)) {
 		srcu_read_unlock(&kvm->srcu, srcu_idx);
-		pr_warn("Incompatible host page size %lx!\n", page_size);
+		pr_err("Couldn't get queue page %llx!\n", kvm_eq.qaddr);
 		return -EINVAL;
 	}
 
@@ -653,8 +674,8 @@
 	  * OPAL level because the use of END ESBs is not supported by
 	  * Linux.
 	  */
-	rc = xive_native_configure_queue(xc->vp_id, q, priority,
-					 (__be32 *) qaddr, kvm_eq.qshift, true);
+	rc = kvmppc_xive_native_configure_queue(xc->vp_id, q, priority,
+					(__be32 *) qaddr, kvm_eq.qshift, true);
 	if (rc) {
 		pr_err("Failed to configure queue %d for VCPU %d: %d\n",
 		       priority, xc->server_num, rc);
@@ -1081,7 +1102,6 @@
 	dev->private = xive;
 	xive->dev = dev;
 	xive->kvm = kvm;
-	kvm->arch.xive = xive;
 	mutex_init(&xive->mapping_lock);
 	mutex_init(&xive->lock);
 
@@ -1102,6 +1122,7 @@
 	if (ret)
 		return ret;
 
+	kvm->arch.xive = xive;
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/e500_mmu_host.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/e500_mmu_host.c
@@ -734,7 +734,8 @@
 	return 0;
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+			unsigned flags)
 {
 	/* kvm_unmap_hva flushes everything anyways */
 	kvm_unmap_hva(kvm, start);
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/emulate_loadstore.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/emulate_loadstore.c
@@ -73,7 +73,6 @@
 {
 	struct kvm_run *run = vcpu->run;
 	u32 inst;
-	int ra, rs, rt;
 	enum emulation_result emulated = EMULATE_FAIL;
 	int advance = 1;
 	struct instruction_op op;
@@ -85,10 +84,6 @@
 	if (emulated != EMULATE_DONE)
 		return emulated;
 
-	ra = get_ra(inst);
-	rs = get_rs(inst);
-	rt = get_rt(inst);
-
 	vcpu->arch.mmio_vsx_copy_nums = 0;
 	vcpu->arch.mmio_vsx_offset = 0;
 	vcpu->arch.mmio_copy_type = KVMPPC_VSX_COPY_NONE;
--- linux-ein-5.4.0.orig/arch/powerpc/kvm/powerpc.c
+++ linux-ein-5.4.0/arch/powerpc/kvm/powerpc.c
@@ -1495,7 +1495,7 @@
 {
 	enum emulation_result emulated = EMULATE_DONE;
 
-	if (vcpu->arch.mmio_vsx_copy_nums > 2)
+	if (vcpu->arch.mmio_vmx_copy_nums > 2)
 		return EMULATE_FAIL;
 
 	while (vcpu->arch.mmio_vmx_copy_nums) {
@@ -1513,7 +1513,7 @@
 	return emulated;
 }
 
-int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val)
+static int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val)
 {
 	union kvmppc_one_reg reg;
 	int vmx_offset = 0;
@@ -1531,7 +1531,7 @@
 	return result;
 }
 
-int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val)
+static int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val)
 {
 	union kvmppc_one_reg reg;
 	int vmx_offset = 0;
@@ -1549,7 +1549,7 @@
 	return result;
 }
 
-int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val)
+static int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val)
 {
 	union kvmppc_one_reg reg;
 	int vmx_offset = 0;
@@ -1567,7 +1567,7 @@
 	return result;
 }
 
-int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val)
+static int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val)
 {
 	union kvmppc_one_reg reg;
 	int vmx_offset = 0;
@@ -1592,7 +1592,7 @@
 	unsigned int index = rs & KVM_MMIO_REG_MASK;
 	enum emulation_result emulated = EMULATE_DONE;
 
-	if (vcpu->arch.mmio_vsx_copy_nums > 2)
+	if (vcpu->arch.mmio_vmx_copy_nums > 2)
 		return EMULATE_FAIL;
 
 	vcpu->arch.io_gpr = rs;
@@ -2035,9 +2035,9 @@
 	{
 		struct kvm_enable_cap cap;
 		r = -EFAULT;
-		vcpu_load(vcpu);
 		if (copy_from_user(&cap, argp, sizeof(cap)))
 			goto out;
+		vcpu_load(vcpu);
 		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
 		vcpu_put(vcpu);
 		break;
@@ -2061,9 +2061,9 @@
 	case KVM_DIRTY_TLB: {
 		struct kvm_dirty_tlb dirty;
 		r = -EFAULT;
-		vcpu_load(vcpu);
 		if (copy_from_user(&dirty, argp, sizeof(dirty)))
 			goto out;
+		vcpu_load(vcpu);
 		r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
 		vcpu_put(vcpu);
 		break;
--- linux-ein-5.4.0.orig/arch/powerpc/lib/Makefile
+++ linux-ein-5.4.0/arch/powerpc/lib/Makefile
@@ -16,6 +16,9 @@
 CFLAGS_feature-fixups.o += -DDISABLE_BRANCH_PROFILING
 endif
 
+CFLAGS_code-patching.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
+CFLAGS_feature-fixups.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
+
 obj-y += alloc.o code-patching.o feature-fixups.o pmem.o
 
 ifndef CONFIG_KASAN
@@ -31,8 +34,8 @@
 # 64-bit linker creates .sfpr on demand for final link (vmlinux),
 # so it is only needed for modules, and only for older linkers which
 # do not support --save-restore-funcs
-ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
-extra-$(CONFIG_PPC64)	+= crtsavres.o
+ifeq ($(call ld-ifversion, -lt, 225000000, y)$(CONFIG_PPC64),yy)
+always	+= crtsavres.o
 endif
 
 obj-$(CONFIG_PPC_BOOK3S_64) += copyuser_power7.o copypage_power7.o \
--- linux-ein-5.4.0.orig/arch/powerpc/lib/code-patching.c
+++ linux-ein-5.4.0/arch/powerpc/lib/code-patching.c
@@ -221,6 +221,11 @@
 	return (offset >= -0x2000000 && offset <= 0x1fffffc && !(offset & 0x3));
 }
 
+bool is_offset_in_cond_branch_range(long offset)
+{
+	return offset >= -0x8000 && offset <= 0x7fff && !(offset & 0x3);
+}
+
 /*
  * Helper to check if a given instruction is a conditional branch
  * Derived from the conditional checks in analyse_instr()
@@ -274,7 +279,7 @@
 		offset = offset - (unsigned long)addr;
 
 	/* Check we can represent the target in the instruction format */
-	if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)
+	if (!is_offset_in_cond_branch_range(offset))
 		return 0;
 
 	/* Mask out the flags and target, so they don't step on each other. */
--- linux-ein-5.4.0.orig/arch/powerpc/lib/feature-fixups.c
+++ linux-ein-5.4.0/arch/powerpc/lib/feature-fixups.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/sched/mm.h>
+#include <linux/stop_machine.h>
 #include <asm/cputable.h>
 #include <asm/code-patching.h>
 #include <asm/page.h>
@@ -221,11 +222,143 @@
 		                                           : "unknown");
 }
 
+static int __do_stf_barrier_fixups(void *data)
+{
+	enum stf_barrier_type *types = data;
+
+	do_stf_entry_barrier_fixups(*types);
+	do_stf_exit_barrier_fixups(*types);
+
+	return 0;
+}
 
 void do_stf_barrier_fixups(enum stf_barrier_type types)
 {
-	do_stf_entry_barrier_fixups(types);
-	do_stf_exit_barrier_fixups(types);
+	/*
+	 * The call to the fallback entry flush, and the fallback/sync-ori exit
+	 * flush can not be safely patched in/out while other CPUs are executing
+	 * them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs
+	 * spin in the stop machine core with interrupts hard disabled.
+	 */
+	stop_machine(__do_stf_barrier_fixups, &types, NULL);
+}
+
+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)
--- linux-ein-5.4.0.orig/arch/powerpc/lib/sstep.c
+++ linux-ein-5.4.0/arch/powerpc/lib/sstep.c
@@ -8,6 +8,7 @@
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/prefetch.h>
+#include <asm/cpu_has_feature.h>
 #include <asm/sstep.h>
 #include <asm/processor.h>
 #include <linux/uaccess.h>
@@ -469,6 +470,8 @@
 	} u;
 
 	nb = GETSIZE(op->type);
+	if (nb > sizeof(u))
+		return -EINVAL;
 	if (!address_ok(regs, ea, nb))
 		return -EFAULT;
 	rn = op->reg;
@@ -519,6 +522,8 @@
 	} u;
 
 	nb = GETSIZE(op->type);
+	if (nb > sizeof(u))
+		return -EINVAL;
 	if (!address_ok(regs, ea, nb))
 		return -EFAULT;
 	rn = op->reg;
@@ -563,6 +568,9 @@
 		u8 b[sizeof(__vector128)];
 	} u = {};
 
+	if (size > sizeof(u))
+		return -EINVAL;
+
 	if (!address_ok(regs, ea & ~0xfUL, 16))
 		return -EFAULT;
 	/* align to multiple of size */
@@ -590,6 +598,9 @@
 		u8 b[sizeof(__vector128)];
 	} u;
 
+	if (size > sizeof(u))
+		return -EINVAL;
+
 	if (!address_ok(regs, ea & ~0xfUL, 16))
 		return -EFAULT;
 	/* align to multiple of size */
@@ -906,7 +917,10 @@
 
 #define __put_user_asmx(x, addr, err, op, cr)		\
 	__asm__ __volatile__(				\
+		".machine push\n"			\
+		".machine power8\n"			\
 		"1:	" op " %2,0,%3\n"		\
+		".machine pop\n"			\
 		"	mfcr	%1\n"			\
 		"2:\n"					\
 		".section .fixup,\"ax\"\n"		\
@@ -919,7 +933,10 @@
 
 #define __get_user_asmx(x, addr, err, op)		\
 	__asm__ __volatile__(				\
+		".machine push\n"			\
+		".machine power8\n"			\
 		"1:	"op" %1,0,%2\n"			\
+		".machine pop\n"			\
 		"2:\n"					\
 		".section .fixup,\"ax\"\n"		\
 		"3:	li	%0,%3\n"		\
@@ -2787,12 +2804,14 @@
 		case BARRIER_EIEIO:
 			eieio();
 			break;
+#ifdef CONFIG_PPC64
 		case BARRIER_LWSYNC:
 			asm volatile("lwsync" : : : "memory");
 			break;
 		case BARRIER_PTESYNC:
 			asm volatile("ptesync" : : : "memory");
 			break;
+#endif
 		}
 		break;
 
@@ -2910,7 +2929,7 @@
 			__put_user_asmx(op->val, ea, err, "stbcx.", cr);
 			break;
 		case 2:
-			__put_user_asmx(op->val, ea, err, "stbcx.", cr);
+			__put_user_asmx(op->val, ea, err, "sthcx.", cr);
 			break;
 #endif
 		case 4:
--- linux-ein-5.4.0.orig/arch/powerpc/lib/string_32.S
+++ linux-ein-5.4.0/arch/powerpc/lib/string_32.S
@@ -17,7 +17,7 @@
 LG_CACHELINE_BYTES = L1_CACHE_SHIFT
 CACHELINE_MASK = (L1_CACHE_BYTES-1)
 
-_GLOBAL(__clear_user)
+_GLOBAL(__arch_clear_user)
 /*
  * Use dcbz on the complete cache lines in the destination
  * to set them to zero.  This requires that the destination
@@ -87,4 +87,4 @@
 	EX_TABLE(8b, 91b)
 	EX_TABLE(9b, 91b)
 
-EXPORT_SYMBOL(__clear_user)
+EXPORT_SYMBOL(__arch_clear_user)
--- linux-ein-5.4.0.orig/arch/powerpc/lib/string_64.S
+++ linux-ein-5.4.0/arch/powerpc/lib/string_64.S
@@ -17,7 +17,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.
  *
@@ -58,7 +58,7 @@
 	mr	r3,r4
 	blr
 
-_GLOBAL_TOC(__clear_user)
+_GLOBAL_TOC(__arch_clear_user)
 	cmpdi	r4,32
 	neg	r6,r3
 	li	r0,0
@@ -181,4 +181,4 @@
 	cmpdi	r4,32
 	blt	.Lshort_clear
 	b	.Lmedium_clear
-EXPORT_SYMBOL(__clear_user)
+EXPORT_SYMBOL(__arch_clear_user)
--- linux-ein-5.4.0.orig/arch/powerpc/math-emu/math_efp.c
+++ linux-ein-5.4.0/arch/powerpc/math-emu/math_efp.c
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/prctl.h>
+#include <linux/module.h>
 
 #include <linux/uaccess.h>
 #include <asm/reg.h>
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s32/mmu.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s32/mmu.c
@@ -187,6 +187,7 @@
 	int i;
 	unsigned long base = (unsigned long)_stext - PAGE_OFFSET;
 	unsigned long top = (unsigned long)_etext - PAGE_OFFSET;
+	unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
 	unsigned long size;
 
 	if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
@@ -201,9 +202,10 @@
 		size = block_size(base, top);
 		size = max(size, 128UL << 10);
 		if ((top - base) > size) {
-			if (strict_kernel_rwx_enabled())
-				pr_warn("Kernel _etext not properly aligned\n");
 			size <<= 1;
+			if (strict_kernel_rwx_enabled() && base + size > border)
+				pr_warn("Some RW data is getting mapped X. "
+					"Adjust CONFIG_DATA_SHIFT to avoid that.\n");
 		}
 		setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
 		base += size;
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/hash_utils.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/hash_utils.c
@@ -294,10 +294,18 @@
 		ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
 					       HPTE_V_BOLTED, psize, psize,
 					       ssize);
-
+		if (ret == -1) {
+			/* Try to remove a non bolted entry */
+			ret = mmu_hash_ops.hpte_remove(hpteg);
+			if (ret != -1)
+				ret = mmu_hash_ops.hpte_insert(hpteg, vpn, paddr, tprot,
+							       HPTE_V_BOLTED, psize, psize,
+							       ssize);
+		}
 		if (ret < 0)
 			break;
 
+		cond_resched();
 #ifdef CONFIG_DEBUG_PAGEALLOC
 		if (debug_pagealloc_enabled() &&
 			(paddr >> PAGE_SHIFT) < linear_map_hash_count)
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/iommu_api.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/iommu_api.c
@@ -121,24 +121,6 @@
 		goto free_exit;
 	}
 
-	pageshift = PAGE_SHIFT;
-	for (i = 0; i < entries; ++i) {
-		struct page *page = mem->hpages[i];
-
-		/*
-		 * Allow to use larger than 64k IOMMU pages. Only do that
-		 * if we are backed by hugetlb.
-		 */
-		if ((mem->pageshift > PAGE_SHIFT) && PageHuge(page))
-			pageshift = page_shift(compound_head(page));
-		mem->pageshift = min(mem->pageshift, pageshift);
-		/*
-		 * We don't need struct page reference any more, switch
-		 * to physical address.
-		 */
-		mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
-	}
-
 good_exit:
 	atomic64_set(&mem->mapped, 1);
 	mem->used = 1;
@@ -158,6 +140,27 @@
 		}
 	}
 
+	if (mem->dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) {
+		/*
+		 * Allow to use larger than 64k IOMMU pages. Only do that
+		 * if we are backed by hugetlb. Skip device memory as it is not
+		 * backed with page structs.
+		 */
+		pageshift = PAGE_SHIFT;
+		for (i = 0; i < entries; ++i) {
+			struct page *page = mem->hpages[i];
+
+			if ((mem->pageshift > PAGE_SHIFT) && PageHuge(page))
+				pageshift = page_shift(compound_head(page));
+			mem->pageshift = min(mem->pageshift, pageshift);
+			/*
+			 * We don't need struct page reference any more, switch
+			 * to physical address.
+			 */
+			mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
+		}
+	}
+
 	list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list);
 
 	mutex_unlock(&mem_list_mutex);
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/pgtable.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/pgtable.c
@@ -378,7 +378,6 @@
 	}
 }
 
-#ifdef CONFIG_SMP
 void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int index)
 {
 	unsigned long pgf = (unsigned long)table;
@@ -395,12 +394,6 @@
 
 	return pgtable_free(table, index);
 }
-#else
-void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int index)
-{
-	return pgtable_free(table, index);
-}
-#endif
 
 #ifdef CONFIG_PROC_FS
 atomic_long_t direct_pages_count[MMU_PAGE_COUNT];
@@ -449,6 +442,7 @@
 	set_pte_at(vma->vm_mm, addr, ptep, pte);
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 /*
  * For hash translation mode, we use the deposited table to store hash slot
  * information and they are stored at PTRS_PER_PMD offset from related pmd
@@ -470,6 +464,7 @@
 
 	return true;
 }
+#endif
 
 /*
  * Does the CPU support tlbie?
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/pkeys.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/pkeys.c
@@ -83,13 +83,17 @@
 	scan_pkey_feature();
 
 	/*
-	 * Let's assume 32 pkeys on P8 bare metal, if its not defined by device
-	 * tree. We make this exception since skiboot forgot to expose this
-	 * property on power8.
+	 * Let's assume 32 pkeys on P8/P9 bare metal, if its not defined by device
+	 * tree. We make this exception since some version of skiboot forgot to
+	 * expose this property on power8/9.
 	 */
-	if (!pkeys_devtree_defined && !firmware_has_feature(FW_FEATURE_LPAR) &&
-			cpu_has_feature(CPU_FTRS_POWER8))
-		pkeys_total = 32;
+	if (!pkeys_devtree_defined && !firmware_has_feature(FW_FEATURE_LPAR)) {
+		unsigned long pvr = mfspr(SPRN_PVR);
+
+		if (PVR_VER(pvr) == PVR_POWER8 || PVR_VER(pvr) == PVR_POWER8E ||
+		    PVR_VER(pvr) == PVR_POWER8NVL || PVR_VER(pvr) == PVR_POWER9)
+			pkeys_total = 32;
+	}
 
 	/*
 	 * Adjust the upper limit, based on the number of bits supported by
@@ -367,12 +371,14 @@
 		return true;
 
 	pkey_shift = pkeyshift(pkey);
-	if (execute && !(read_iamr() & (IAMR_EX_BIT << pkey_shift)))
-		return true;
+	if (execute)
+		return !(read_iamr() & (IAMR_EX_BIT << pkey_shift));
+
+	amr = read_amr();
+	if (write)
+		return !(amr & (AMR_WR_BIT << pkey_shift));
 
-	amr = read_amr(); /* Delay reading amr until absolutely needed */
-	return ((!write && !(amr & (AMR_RD_BIT << pkey_shift))) ||
-		(write &&  !(amr & (AMR_WR_BIT << pkey_shift))));
+	return !(amr & (AMR_RD_BIT << pkey_shift));
 }
 
 bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -97,7 +97,7 @@
 
 set_the_pte:
 	set_pte_at(&init_mm, ea, ptep, pfn_pte(pfn, flags));
-	smp_wmb();
+	asm volatile("ptesync": : :"memory");
 	return 0;
 }
 
@@ -155,7 +155,7 @@
 
 set_the_pte:
 	set_pte_at(&init_mm, ea, ptep, pfn_pte(pfn, flags));
-	smp_wmb();
+	asm volatile("ptesync": : :"memory");
 	return 0;
 }
 
@@ -643,21 +643,6 @@
 	}
 }
 
-void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
-				phys_addr_t first_memblock_size)
-{
-	/*
-	 * We don't currently support the first MEMBLOCK not mapping 0
-	 * physical on those processors
-	 */
-	BUG_ON(first_memblock_base != 0);
-
-	/*
-	 * Radix mode is not limited by RMA / VRMA addressing.
-	 */
-	ppc64_rma_size = ULONG_MAX;
-}
-
 #ifdef CONFIG_MEMORY_HOTPLUG
 static void free_pte_table(pte_t *pte_start, pmd_t *pmd)
 {
@@ -1033,8 +1018,8 @@
 				  pte_t entry, unsigned long address, int psize)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED |
-					      _PAGE_RW | _PAGE_EXEC);
+	unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_SOFT_DIRTY |
+					      _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
 
 	unsigned long change = pte_val(entry) ^ pte_val(*ptep);
 	/*
--- linux-ein-5.4.0.orig/arch/powerpc/mm/book3s64/radix_tlb.c
+++ linux-ein-5.4.0/arch/powerpc/mm/book3s64/radix_tlb.c
@@ -639,19 +639,29 @@
 	struct mm_struct *mm = arg;
 	unsigned long pid = mm->context.id;
 
+	/*
+	 * A kthread could have done a mmget_not_zero() after the flushing CPU
+	 * checked mm_is_singlethreaded, and be in the process of
+	 * kthread_use_mm when interrupted here. In that case, current->mm will
+	 * be set to mm, because kthread_use_mm() setting ->mm and switching to
+	 * the mm is done with interrupts off.
+	 */
 	if (current->mm == mm)
-		return; /* Local CPU */
+		goto out_flush;
 
 	if (current->active_mm == mm) {
-		/*
-		 * Must be a kernel thread because sender is single-threaded.
-		 */
-		BUG_ON(current->mm);
+		WARN_ON_ONCE(current->mm != NULL);
+		/* Is a kernel thread and is using mm as the lazy tlb */
 		mmgrab(&init_mm);
-		switch_mm(mm, &init_mm, current);
 		current->active_mm = &init_mm;
+		switch_mm_irqs_off(mm, &init_mm, current);
 		mmdrop(mm);
 	}
+
+	atomic_dec(&mm->context.active_cpus);
+	cpumask_clear_cpu(smp_processor_id(), mm_cpumask(mm));
+
+out_flush:
 	_tlbiel_pid(pid, RIC_FLUSH_ALL);
 }
 
@@ -666,7 +676,6 @@
 	 */
 	smp_call_function_many(mm_cpumask(mm), do_exit_flush_lazy_tlb,
 				(void *)mm, 1);
-	mm_reset_thread_local(mm);
 }
 
 void radix__flush_tlb_mm(struct mm_struct *mm)
--- linux-ein-5.4.0.orig/arch/powerpc/mm/dma-noncoherent.c
+++ linux-ein-5.4.0/arch/powerpc/mm/dma-noncoherent.c
@@ -104,14 +104,14 @@
 #endif
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_sync_page(paddr, size, dir);
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	__dma_sync_page(paddr, size, dir);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/mm/drmem.c
+++ linux-ein-5.4.0/arch/powerpc/mm/drmem.c
@@ -362,10 +362,8 @@
 	if (!drmem_info->lmbs)
 		return;
 
-	for_each_drmem_lmb(lmb) {
+	for_each_drmem_lmb(lmb)
 		read_drconf_v1_cell(lmb, &prop);
-		lmb_set_nid(lmb);
-	}
 }
 
 static void __init init_drmem_v2_lmbs(const __be32 *prop)
@@ -410,8 +408,6 @@
 
 			lmb->aa_index = dr_cell.aa_index;
 			lmb->flags = dr_cell.flags;
-
-			lmb_set_nid(lmb);
 		}
 	}
 }
--- linux-ein-5.4.0.orig/arch/powerpc/mm/fault.c
+++ linux-ein-5.4.0/arch/powerpc/mm/fault.c
@@ -204,9 +204,7 @@
 {
 	int is_exec = TRAP(regs) == 0x400;
 
-	/* NX faults set DSISR_PROTFAULT on the 8xx, DSISR_NOEXEC_OR_G on others */
-	if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT |
-				      DSISR_PROTFAULT))) {
+	if (is_exec) {
 		pr_crit_ratelimited("kernel tried to execute %s page (%lx) - exploit attempt? (uid: %d)\n",
 				    address >= TASK_SIZE ? "exec-protected" : "user",
 				    address,
@@ -233,7 +231,7 @@
 
 	// Read/write fault in a valid region (the exception table search passed
 	// above), but blocked by KUAP is bad, it can never succeed.
-	if (bad_kuap_fault(regs, is_write))
+	if (bad_kuap_fault(regs, address, is_write))
 		return true;
 
 	// What's left? Kernel fault on user in well defined regions (extable
@@ -241,6 +239,9 @@
 	return false;
 }
 
+// This comes from 64-bit struct rt_sigframe + __SIGNAL_FRAMESIZE
+#define SIGFRAME_MAX_SIZE	(4096 + 128)
+
 static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address,
 				struct vm_area_struct *vma, unsigned int flags,
 				bool *must_retry)
@@ -248,7 +249,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 a bit over 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
@@ -273,7 +274,7 @@
 		 * between the last mapped region and the stack will
 		 * expand the stack rather than segfaulting.
 		 */
-		if (address + 2048 >= uregs->gpr[1])
+		if (address + SIGFRAME_MAX_SIZE >= uregs->gpr[1])
 			return false;
 
 		if ((flags & FAULT_FLAG_WRITE) && (flags & FAULT_FLAG_USER) &&
@@ -346,7 +347,6 @@
 static inline void cmo_account_page_fault(void) { }
 #endif /* CONFIG_PPC_SMLPAR */
 
-#ifdef CONFIG_PPC_BOOK3S
 static void sanity_check_fault(bool is_write, bool is_user,
 			       unsigned long error_code, unsigned long address)
 {
@@ -354,12 +354,18 @@
 	 * Userspace trying to access kernel address, we get PROTFAULT for that.
 	 */
 	if (is_user && address >= TASK_SIZE) {
+		if ((long)address == -1)
+			return;
+
 		pr_crit_ratelimited("%s[%d]: User access of kernel address (%lx) - exploit attempt? (uid: %d)\n",
 				   current->comm, current->pid, address,
 				   from_kuid(&init_user_ns, current_uid()));
 		return;
 	}
 
+	if (!IS_ENABLED(CONFIG_PPC_BOOK3S))
+		return;
+
 	/*
 	 * For hash translation mode, we should never get a
 	 * PROTFAULT. Any update to pte to reduce access will result in us
@@ -394,10 +400,6 @@
 
 	WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
 }
-#else
-static void sanity_check_fault(bool is_write, bool is_user,
-			       unsigned long error_code, unsigned long address) { }
-#endif /* CONFIG_PPC_BOOK3S */
 
 /*
  * Define the correct "is_write" bit in error_code based
--- linux-ein-5.4.0.orig/arch/powerpc/mm/hugetlbpage.c
+++ linux-ein-5.4.0/arch/powerpc/mm/hugetlbpage.c
@@ -53,20 +53,24 @@
 	if (pshift >= pdshift) {
 		cachep = PGT_CACHE(PTE_T_ORDER);
 		num_hugepd = 1 << (pshift - pdshift);
+		new = NULL;
 	} else if (IS_ENABLED(CONFIG_PPC_8xx)) {
-		cachep = PGT_CACHE(PTE_INDEX_SIZE);
+		cachep = NULL;
 		num_hugepd = 1;
+		new = pte_alloc_one(mm);
 	} else {
 		cachep = PGT_CACHE(pdshift - pshift);
 		num_hugepd = 1;
+		new = NULL;
 	}
 
-	if (!cachep) {
+	if (!cachep && !new) {
 		WARN_ONCE(1, "No page table cache created for hugetlb tables");
 		return -ENOMEM;
 	}
 
-	new = kmem_cache_alloc(cachep, pgtable_gfp_flags(mm, GFP_KERNEL));
+	if (cachep)
+		new = kmem_cache_alloc(cachep, pgtable_gfp_flags(mm, GFP_KERNEL));
 
 	BUG_ON(pshift > HUGEPD_SHIFT_MASK);
 	BUG_ON((unsigned long)new & HUGEPD_SHIFT_MASK);
@@ -97,7 +101,10 @@
 	if (i < num_hugepd) {
 		for (i = i - 1 ; i >= 0; i--, hpdp--)
 			*hpdp = __hugepd(0);
-		kmem_cache_free(cachep, new);
+		if (cachep)
+			kmem_cache_free(cachep, new);
+		else
+			pte_free(mm, new);
 	} else {
 		kmemleak_ignore(new);
 	}
@@ -324,8 +331,7 @@
 	if (shift >= pdshift)
 		hugepd_free(tlb, hugepte);
 	else if (IS_ENABLED(CONFIG_PPC_8xx))
-		pgtable_free_tlb(tlb, hugepte,
-				 get_hugepd_cache_index(PTE_INDEX_SIZE));
+		pgtable_free_tlb(tlb, hugepte, 0);
 	else
 		pgtable_free_tlb(tlb, hugepte,
 				 get_hugepd_cache_index(pdshift - shift));
@@ -639,12 +645,13 @@
 		 * if we have pdshift and shift value same, we don't
 		 * use pgt cache for hugepd.
 		 */
-		if (pdshift > shift && IS_ENABLED(CONFIG_PPC_8xx))
-			pgtable_cache_add(PTE_INDEX_SIZE);
-		else if (pdshift > shift)
-			pgtable_cache_add(pdshift - shift);
-		else if (IS_ENABLED(CONFIG_PPC_FSL_BOOK3E) || IS_ENABLED(CONFIG_PPC_8xx))
+		if (pdshift > shift) {
+			if (!IS_ENABLED(CONFIG_PPC_8xx))
+				pgtable_cache_add(pdshift - shift);
+		} else if (IS_ENABLED(CONFIG_PPC_FSL_BOOK3E) ||
+			   IS_ENABLED(CONFIG_PPC_8xx)) {
 			pgtable_cache_add(PTE_T_ORDER);
+		}
 
 		configured = true;
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/mm/init-common.c
+++ linux-ein-5.4.0/arch/powerpc/mm/init-common.c
@@ -104,7 +104,7 @@
 	 * as to leave enough 0 bits in the address to contain it. */
 	unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1,
 				     HUGEPD_SHIFT_MASK + 1);
-	struct kmem_cache *new;
+	struct kmem_cache *new = NULL;
 
 	/* It would be nice if this was a BUILD_BUG_ON(), but at the
 	 * moment, gcc doesn't seem to recognize is_power_of_2 as a
@@ -117,7 +117,8 @@
 
 	align = max_t(unsigned long, align, minalign);
 	name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift);
-	new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
+	if (name)
+		new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
 	if (!new)
 		panic("Could not allocate pgtable cache for order %d", shift);
 
--- linux-ein-5.4.0.orig/arch/powerpc/mm/init_64.c
+++ linux-ein-5.4.0/arch/powerpc/mm/init_64.c
@@ -178,7 +178,7 @@
 	unsigned long nr_pfn = page_size / sizeof(struct page);
 	unsigned long start_pfn = page_to_pfn((struct page *)start);
 
-	if ((start_pfn + nr_pfn) > altmap->end_pfn)
+	if ((start_pfn + nr_pfn - 1) > altmap->end_pfn)
 		return true;
 
 	if (start_pfn < altmap->base_pfn)
@@ -279,8 +279,7 @@
 	start = _ALIGN_DOWN(start, page_size);
 	if (altmap) {
 		alt_start = altmap->base_pfn;
-		alt_end = altmap->base_pfn + altmap->reserve +
-			  altmap->free + altmap->alloc + altmap->align;
+		alt_end = altmap->base_pfn + altmap->reserve + altmap->free;
 	}
 
 	pr_debug("vmemmap_free %lx...%lx\n", start, end);
@@ -415,9 +414,16 @@
 	if (!(mfmsr() & MSR_HV))
 		early_check_vec5();
 
-	if (early_radix_enabled())
+	if (early_radix_enabled()) {
 		radix__early_init_devtree();
-	else
+		/*
+		 * We have finalized the translation we are going to use by now.
+		 * Radix mode is not limited by RMA / VRMA addressing.
+		 * Hence don't limit memblock allocations.
+		 */
+		ppc64_rma_size = ULONG_MAX;
+		memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
+	} else
 		hash__early_init_devtree();
 }
 #endif /* CONFIG_PPC_BOOK3S_64 */
--- linux-ein-5.4.0.orig/arch/powerpc/mm/kasan/Makefile
+++ linux-ein-5.4.0/arch/powerpc/mm/kasan/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 KASAN_SANITIZE := n
+KCOV_INSTRUMENT := n
 
 obj-$(CONFIG_PPC32)           += kasan_init_32.o
--- linux-ein-5.4.0.orig/arch/powerpc/mm/kasan/kasan_init_32.c
+++ linux-ein-5.4.0/arch/powerpc/mm/kasan/kasan_init_32.c
@@ -90,8 +90,10 @@
 	if (ret)
 		return ret;
 
-	if (!slab_is_available())
+	if (!slab_is_available()) {
+		k_start = k_start & PAGE_MASK;
 		block = memblock_alloc(k_end - k_start, PAGE_SIZE);
+	}
 
 	for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) {
 		pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
@@ -117,11 +119,11 @@
 
 	kasan_populate_pte(kasan_early_shadow_pte, prot);
 
-	for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) {
+	for (k_cur = k_start & PAGE_MASK; k_cur != k_end; k_cur += PAGE_SIZE) {
 		pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
 		pte_t *ptep = pte_offset_kernel(pmd, k_cur);
 
-		if ((pte_val(*ptep) & PTE_RPN_MASK) != pa)
+		if (pte_page(*ptep) != virt_to_page(lm_alias(kasan_early_shadow_page)))
 			continue;
 
 		__set_pte_at(&init_mm, k_cur, ptep, pfn_pte(PHYS_PFN(pa), prot), 0);
--- linux-ein-5.4.0.orig/arch/powerpc/mm/mem.c
+++ linux-ein-5.4.0/arch/powerpc/mm/mem.c
@@ -48,6 +48,7 @@
 #include <asm/fixmap.h>
 #include <asm/swiotlb.h>
 #include <asm/rtas.h>
+#include <asm/ftrace.h>
 
 #include <mm/mmu_decl.h>
 
@@ -104,6 +105,27 @@
 	return -ENODEV;
 }
 
+#define FLUSH_CHUNK_SIZE SZ_1G
+/**
+ * flush_dcache_range_chunked(): Write any modified data cache blocks out to
+ * memory and invalidate them, in chunks of up to FLUSH_CHUNK_SIZE
+ * Does not invalidate the corresponding instruction cache blocks.
+ *
+ * @start: the start address
+ * @stop: the stop address (exclusive)
+ * @chunk: the max size of the chunks
+ */
+static void flush_dcache_range_chunked(unsigned long start, unsigned long stop,
+				       unsigned long chunk)
+{
+	unsigned long i;
+
+	for (i = start; i < stop; i += chunk) {
+		flush_dcache_range(i, min(stop, i + chunk));
+		cond_resched();
+	}
+}
+
 int __ref arch_add_memory(int nid, u64 start, u64 size,
 			struct mhp_restrictions *restrictions)
 {
@@ -120,7 +142,8 @@
 			start, start + size, rc);
 		return -EFAULT;
 	}
-	flush_dcache_range(start, start + size);
+
+	flush_dcache_range_chunked(start, start + size, FLUSH_CHUNK_SIZE);
 
 	return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
@@ -130,14 +153,14 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct page *page = pfn_to_page(start_pfn) + vmem_altmap_offset(altmap);
 	int ret;
 
-	__remove_pages(page_zone(page), start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 
 	/* Remove htab bolted mappings for this section of memory */
 	start = (unsigned long)__va(start);
-	flush_dcache_range(start, start + size);
+	flush_dcache_range_chunked(start, start + size, FLUSH_CHUNK_SIZE);
+
 	ret = remove_section_mapping(start, start + size);
 	WARN_ON_ONCE(ret);
 
@@ -260,6 +283,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
 
@@ -316,7 +347,124 @@
 	mark_initmem_nx();
 	init_mem_is_free = true;
 	free_initmem_default(POISON_FREE_INITMEM);
+	ftrace_free_init_tramp();
+}
+
+/**
+ * flush_coherent_icache() - if a CPU has a coherent icache, flush it
+ * @addr: The base address to use (can be any valid address, the whole cache will be flushed)
+ * Return true if the cache was flushed, false otherwise
+ */
+static inline bool flush_coherent_icache(unsigned long addr)
+{
+	/*
+	 * For a snooping icache, we still need a dummy icbi to purge all the
+	 * prefetched instructions from the ifetch buffers. We also need a sync
+	 * before the icbi to order the the actual stores to memory that might
+	 * have modified instructions with the icbi.
+	 */
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
+		mb(); /* sync */
+		allow_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
+		icbi((void *)addr);
+		prevent_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
+		mb(); /* sync */
+		isync();
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * invalidate_icache_range() - Flush the icache by issuing icbi across an address range
+ * @start: the start address
+ * @stop: the stop address (exclusive)
+ */
+static void invalidate_icache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long shift = l1_icache_shift();
+	unsigned long bytes = l1_icache_bytes();
+	char *addr = (char *)(start & ~(bytes - 1));
+	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
+	unsigned long i;
+
+	for (i = 0; i < size >> shift; i++, addr += bytes)
+		icbi(addr);
+
+	mb(); /* sync */
+	isync();
+}
+
+/**
+ * flush_icache_range: Write any modified data cache blocks out to memory
+ * and invalidate the corresponding blocks in the instruction cache
+ *
+ * Generic code will call this after writing memory, before executing from it.
+ *
+ * @start: the start address
+ * @stop: the stop address (exclusive)
+ */
+void flush_icache_range(unsigned long start, unsigned long stop)
+{
+	if (flush_coherent_icache(start))
+		return;
+
+	clean_dcache_range(start, stop);
+
+	if (IS_ENABLED(CONFIG_44x)) {
+		/*
+		 * Flash invalidate on 44x because we are passed kmapped
+		 * addresses and this doesn't work for userspace pages due to
+		 * the virtually tagged icache.
+		 */
+		iccci((void *)start);
+		mb(); /* sync */
+		isync();
+	} else
+		invalidate_icache_range(start, stop);
+}
+EXPORT_SYMBOL(flush_icache_range);
+
+#if !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64)
+/**
+ * flush_dcache_icache_phys() - Flush a page by it's physical address
+ * @physaddr: the physical address of the page
+ */
+static void flush_dcache_icache_phys(unsigned long physaddr)
+{
+	unsigned long bytes = l1_dcache_bytes();
+	unsigned long nb = PAGE_SIZE / bytes;
+	unsigned long addr = physaddr & PAGE_MASK;
+	unsigned long msr, msr0;
+	unsigned long loop1 = addr, loop2 = addr;
+
+	msr0 = mfmsr();
+	msr = msr0 & ~MSR_DR;
+	/*
+	 * This must remain as ASM to prevent potential memory accesses
+	 * while the data MMU is disabled
+	 */
+	asm volatile(
+		"   mtctr %2;\n"
+		"   mtmsr %3;\n"
+		"   isync;\n"
+		"0: dcbst   0, %0;\n"
+		"   addi    %0, %0, %4;\n"
+		"   bdnz    0b;\n"
+		"   sync;\n"
+		"   mtctr %2;\n"
+		"1: icbi    0, %1;\n"
+		"   addi    %1, %1, %4;\n"
+		"   bdnz    1b;\n"
+		"   sync;\n"
+		"   mtmsr %5;\n"
+		"   isync;\n"
+		: "+&r" (loop1), "+&r" (loop2)
+		: "r" (nb), "r" (msr), "i" (bytes), "r" (msr0)
+		: "ctr", "memory");
 }
+#endif // !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64)
 
 /*
  * This is called when a page has been modified by the kernel.
@@ -350,12 +498,46 @@
 		__flush_dcache_icache(start);
 		kunmap_atomic(start);
 	} else {
-		__flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT);
+		unsigned long addr = page_to_pfn(page) << PAGE_SHIFT;
+
+		if (flush_coherent_icache(addr))
+			return;
+		flush_dcache_icache_phys(addr);
 	}
 #endif
 }
 EXPORT_SYMBOL(flush_dcache_icache_page);
 
+/**
+ * __flush_dcache_icache(): Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ * @page: the address of the page to flush
+ */
+void __flush_dcache_icache(void *p)
+{
+	unsigned long addr = (unsigned long)p;
+
+	if (flush_coherent_icache(addr))
+		return;
+
+	clean_dcache_range(addr, addr + PAGE_SIZE);
+
+	/*
+	 * We don't flush the icache on 44x. Those have a virtual icache and we
+	 * don't have access to the virtual address here (it's not the page
+	 * vaddr but where it's mapped in user space). The flushing of the
+	 * icache on these is handled elsewhere, when a change in the address
+	 * space occurs, before returning to user space.
+	 */
+
+	if (mmu_has_feature(MMU_FTR_TYPE_44x))
+		return;
+
+	invalidate_icache_range(addr, addr + PAGE_SIZE);
+}
+
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
 	clear_page(page);
--- linux-ein-5.4.0.orig/arch/powerpc/mm/mmu_context.c
+++ linux-ein-5.4.0/arch/powerpc/mm/mmu_context.c
@@ -79,7 +79,7 @@
 	 * context
 	 */
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
-		asm volatile ("dssall");
+		asm volatile (PPC_DSSALL);
 
 	if (new_on_cpu)
 		radix_kvm_prefetch_workaround(next);
--- linux-ein-5.4.0.orig/arch/powerpc/mm/nohash/tlb_low.S
+++ linux-ein-5.4.0/arch/powerpc/mm/nohash/tlb_low.S
@@ -397,7 +397,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
@@ -433,6 +433,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
@@ -458,6 +462,7 @@
 	mtmsr	r6
 	isync
 
+10:
 	mr	r9,r3
 	add	r10,r3,r4
 2:	bl	loadcam_entry
@@ -466,6 +471,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)
@@ -481,6 +490,7 @@
 	tlbwe
 	isync
 
+3:
 	mtlr	r8
 	blr
 #endif
--- linux-ein-5.4.0.orig/arch/powerpc/mm/pgtable_32.c
+++ linux-ein-5.4.0/arch/powerpc/mm/pgtable_32.c
@@ -207,7 +207,7 @@
 	unsigned long numpages = PFN_UP((unsigned long)_einittext) -
 				 PFN_DOWN((unsigned long)_sinittext);
 
-	if (v_block_mapped((unsigned long)_stext + 1))
+	if (v_block_mapped((unsigned long)_sinittext))
 		mmu_mark_initmem_nx();
 	else
 		change_page_attr(page, numpages, PAGE_KERNEL);
@@ -219,8 +219,9 @@
 	struct page *page;
 	unsigned long numpages;
 
-	if (v_block_mapped((unsigned long)_sinittext)) {
+	if (v_block_mapped((unsigned long)_stext + 1)) {
 		mmu_mark_rodata_ro();
+		ptdump_check_wx();
 		return;
 	}
 
--- linux-ein-5.4.0.orig/arch/powerpc/mm/ptdump/hashpagetable.c
+++ linux-ein-5.4.0/arch/powerpc/mm/ptdump/hashpagetable.c
@@ -259,7 +259,7 @@
 	for (i = 0; i < HPTES_PER_GROUP; i += 4, hpte_group += 4) {
 		lpar_rc = plpar_pte_read_4(0, hpte_group, (void *)ptes);
 
-		if (lpar_rc != H_SUCCESS)
+		if (lpar_rc)
 			continue;
 		for (j = 0; j < 4; j++) {
 			if (HPTE_V_COMPARE(ptes[j].v, want_v) &&
--- linux-ein-5.4.0.orig/arch/powerpc/mm/ptdump/ptdump.c
+++ linux-ein-5.4.0/arch/powerpc/mm/ptdump/ptdump.c
@@ -58,6 +58,7 @@
 	unsigned long start_address;
 	unsigned long start_pa;
 	unsigned long last_pa;
+	unsigned long page_size;
 	unsigned int level;
 	u64 current_flags;
 	bool check_wx;
@@ -155,9 +156,9 @@
 #endif
 
 	pt_dump_seq_printf(st->seq, REG "-" REG " ", st->start_address, addr - 1);
-	if (st->start_pa == st->last_pa && st->start_address + PAGE_SIZE != addr) {
+	if (st->start_pa == st->last_pa && st->start_address + st->page_size != addr) {
 		pt_dump_seq_printf(st->seq, "[" REG "]", st->start_pa);
-		delta = PAGE_SIZE >> 10;
+		delta = st->page_size >> 10;
 	} else {
 		pt_dump_seq_printf(st->seq, " " REG " ", st->start_pa);
 		delta = (addr - st->start_address) >> 10;
@@ -173,10 +174,12 @@
 
 static void note_prot_wx(struct pg_state *st, unsigned long addr)
 {
+	pte_t pte = __pte(st->current_flags);
+
 	if (!IS_ENABLED(CONFIG_PPC_DEBUG_WX) || !st->check_wx)
 		return;
 
-	if (!((st->current_flags & pgprot_val(PAGE_KERNEL_X)) == pgprot_val(PAGE_KERNEL_X)))
+	if (!pte_write(pte) || !pte_exec(pte))
 		return;
 
 	WARN_ONCE(1, "powerpc/mm: Found insecure W+X mapping at address %p/%pS\n",
@@ -186,7 +189,7 @@
 }
 
 static void note_page(struct pg_state *st, unsigned long addr,
-	       unsigned int level, u64 val)
+	       unsigned int level, u64 val, unsigned long page_size)
 {
 	u64 flag = val & pg_level[level].mask;
 	u64 pa = val & PTE_RPN_MASK;
@@ -198,6 +201,7 @@
 		st->start_address = addr;
 		st->start_pa = pa;
 		st->last_pa = pa;
+		st->page_size = page_size;
 		pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
 	/*
 	 * Dump the section of virtual memory when:
@@ -209,7 +213,7 @@
 	 */
 	} else if (flag != st->current_flags || level != st->level ||
 		   addr >= st->marker[1].start_address ||
-		   (pa != st->last_pa + PAGE_SIZE &&
+		   (pa != st->last_pa + st->page_size &&
 		    (pa != st->start_pa || st->start_pa != st->last_pa))) {
 
 		/* Check the PTE flags */
@@ -237,6 +241,7 @@
 		st->start_address = addr;
 		st->start_pa = pa;
 		st->last_pa = pa;
+		st->page_size = page_size;
 		st->current_flags = flag;
 		st->level = level;
 	} else {
@@ -252,7 +257,7 @@
 
 	for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
 		addr = start + i * PAGE_SIZE;
-		note_page(st, addr, 4, pte_val(*pte));
+		note_page(st, addr, 4, pte_val(*pte), PAGE_SIZE);
 
 	}
 }
@@ -269,7 +274,7 @@
 			/* pmd exists */
 			walk_pte(st, pmd, addr);
 		else
-			note_page(st, addr, 3, pmd_val(*pmd));
+			note_page(st, addr, 3, pmd_val(*pmd), PMD_SIZE);
 	}
 }
 
@@ -285,7 +290,7 @@
 			/* pud exists */
 			walk_pmd(st, pud, addr);
 		else
-			note_page(st, addr, 2, pud_val(*pud));
+			note_page(st, addr, 2, pud_val(*pud), PUD_SIZE);
 	}
 }
 
@@ -304,7 +309,7 @@
 			/* pgd exists */
 			walk_pud(st, pgd, addr);
 		else
-			note_page(st, addr, 1, pgd_val(*pgd));
+			note_page(st, addr, 1, pgd_val(*pgd), PGDIR_SIZE);
 	}
 }
 
@@ -359,7 +364,7 @@
 
 	/* Traverse kernel page tables */
 	walk_pagetables(&st);
-	note_page(&st, 0, 0, 0);
+	note_page(&st, 0, 0, 0, 0);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/mm/ptdump/shared.c
+++ linux-ein-5.4.0/arch/powerpc/mm/ptdump/shared.c
@@ -17,9 +17,9 @@
 		.clear	= "    ",
 	}, {
 		.mask	= _PAGE_RW,
-		.val	= _PAGE_RW,
-		.set	= "rw",
-		.clear	= "r ",
+		.val	= 0,
+		.set	= "r ",
+		.clear	= "rw",
 	}, {
 		.mask	= _PAGE_EXEC,
 		.val	= _PAGE_EXEC,
@@ -31,6 +31,11 @@
 		.set	= "present",
 		.clear	= "       ",
 	}, {
+		.mask	= _PAGE_COHERENT,
+		.val	= _PAGE_COHERENT,
+		.set	= "coherent",
+		.clear	= "        ",
+	}, {
 		.mask	= _PAGE_GUARDED,
 		.val	= _PAGE_GUARDED,
 		.set	= "guarded",
--- linux-ein-5.4.0.orig/arch/powerpc/mm/slice.c
+++ linux-ein-5.4.0/arch/powerpc/mm/slice.c
@@ -50,7 +50,7 @@
 
 #endif
 
-static inline bool slice_addr_is_low(unsigned long addr)
+static inline notrace bool slice_addr_is_low(unsigned long addr)
 {
 	u64 tmp = (u64)addr;
 
@@ -659,7 +659,7 @@
 				       mm_ctx_user_psize(&current->mm->context), 1);
 }
 
-unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+unsigned int notrace get_slice_psize(struct mm_struct *mm, unsigned long addr)
 {
 	unsigned char *psizes;
 	int index, mask_index;
--- linux-ein-5.4.0.orig/arch/powerpc/net/bpf_jit.h
+++ linux-ein-5.4.0/arch/powerpc/net/bpf_jit.h
@@ -11,6 +11,7 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/types.h>
+#include <asm/code-patching.h>
 
 #ifdef PPC64_ELF_ABI_v1
 #define FUNCTION_DESCR_SIZE	24
@@ -180,13 +181,26 @@
 #define PPC_NEG(d, a)		EMIT(PPC_INST_NEG | ___PPC_RT(d) | ___PPC_RA(a))
 
 /* Long jump; (unconditional 'branch') */
-#define PPC_JMP(dest)		EMIT(PPC_INST_BRANCH |			      \
-				     (((dest) - (ctx->idx * 4)) & 0x03fffffc))
+#define PPC_JMP(dest)							      \
+	do {								      \
+		long offset = (long)(dest) - (ctx->idx * 4);		      \
+		if (!is_offset_in_branch_range(offset)) {		      \
+			pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx);			\
+			return -ERANGE;					      \
+		}							      \
+		EMIT(PPC_INST_BRANCH | (offset & 0x03fffffc));		      \
+	} while (0)
 /* "cond" here covers BO:BI fields. */
-#define PPC_BCC_SHORT(cond, dest)	EMIT(PPC_INST_BRANCH_COND |	      \
-					     (((cond) & 0x3ff) << 16) |	      \
-					     (((dest) - (ctx->idx * 4)) &     \
-					      0xfffc))
+#define PPC_BCC_SHORT(cond, dest)					      \
+	do {								      \
+		long offset = (long)(dest) - (ctx->idx * 4);		      \
+		if (!is_offset_in_cond_branch_range(offset)) {		      \
+			pr_err_ratelimited("Conditional branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx);		\
+			return -ERANGE;					      \
+		}							      \
+		EMIT(PPC_INST_BRANCH_COND | (((cond) & 0x3ff) << 16) | (offset & 0xfffc));					\
+	} while (0)
+
 /* Sign-extended 32-bit immediate load */
 #define PPC_LI32(d, i)		do {					      \
 		if ((int)(uintptr_t)(i) >= -32768 &&			      \
@@ -225,11 +239,6 @@
 #define PPC_FUNC_ADDR(d,i) do { PPC_LI32(d, i); } while(0)
 #endif
 
-static inline bool is_nearbranch(int offset)
-{
-	return (offset < 32768) && (offset >= -32768);
-}
-
 /*
  * The fly in the ointment of code size changing from pass to pass is
  * avoided by padding the short branch case with a NOP.	 If code size differs
@@ -238,7 +247,7 @@
  * state.
  */
 #define PPC_BCC(cond, dest)	do {					      \
-		if (is_nearbranch((dest) - (ctx->idx * 4))) {		      \
+		if (is_offset_in_cond_branch_range((long)(dest) - (ctx->idx * 4))) {	\
 			PPC_BCC_SHORT(cond, dest);			      \
 			PPC_NOP();					      \
 		} else {						      \
--- linux-ein-5.4.0.orig/arch/powerpc/net/bpf_jit64.h
+++ linux-ein-5.4.0/arch/powerpc/net/bpf_jit64.h
@@ -16,18 +16,18 @@
  * with our redzone usage.
  *
  *		[	prev sp		] <-------------
- *		[   nv gpr save area	] 6*8		|
+ *		[   nv gpr save area	] 5*8		|
  *		[    tail_call_cnt	] 8		|
- *		[    local_tmp_var	] 8		|
+ *		[    local_tmp_var	] 16		|
  * fp (r31) -->	[   ebpf stack space	] upto 512	|
  *		[     frame header	] 32/112	|
  * sp (r1) --->	[    stack pointer	] --------------
  */
 
 /* for gpr non volatile registers BPG_REG_6 to 10 */
-#define BPF_PPC_STACK_SAVE	(6*8)
+#define BPF_PPC_STACK_SAVE	(5*8)
 /* for bpf JIT code internal usage */
-#define BPF_PPC_STACK_LOCALS	16
+#define BPF_PPC_STACK_LOCALS	24
 /* stack frame excluding BPF stack, ensure this is quadword aligned */
 #define BPF_PPC_STACKFRAME	(STACK_FRAME_MIN_SIZE + \
 				 BPF_PPC_STACK_LOCALS + BPF_PPC_STACK_SAVE)
--- linux-ein-5.4.0.orig/arch/powerpc/net/bpf_jit_comp64.c
+++ linux-ein-5.4.0/arch/powerpc/net/bpf_jit_comp64.c
@@ -15,6 +15,7 @@
 #include <linux/if_vlan.h>
 #include <asm/kprobes.h>
 #include <linux/bpf.h>
+#include <asm/security_features.h>
 
 #include "bpf_jit64.h"
 
@@ -56,9 +57,9 @@
  *		[	prev sp		] <-------------
  *		[	  ...       	] 		|
  * sp (r1) --->	[    stack pointer	] --------------
- *		[   nv gpr save area	] 6*8
+ *		[   nv gpr save area	] 5*8
  *		[    tail_call_cnt	] 8
- *		[    local_tmp_var	] 8
+ *		[    local_tmp_var	] 16
  *		[   unused red zone	] 208 bytes protected
  */
 static int bpf_jit_stack_local(struct codegen_context *ctx)
@@ -66,12 +67,12 @@
 	if (bpf_has_stack_frame(ctx))
 		return STACK_FRAME_MIN_SIZE + ctx->stack_size;
 	else
-		return -(BPF_PPC_STACK_SAVE + 16);
+		return -(BPF_PPC_STACK_SAVE + 24);
 }
 
 static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx)
 {
-	return bpf_jit_stack_local(ctx) + 8;
+	return bpf_jit_stack_local(ctx) + 16;
 }
 
 static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
@@ -224,7 +225,7 @@
 	PPC_BLRL();
 }
 
-static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out)
+static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out)
 {
 	/*
 	 * By now, the eBPF program has already setup parameters in r3, r4 and r5
@@ -285,14 +286,39 @@
 	bpf_jit_emit_common_epilogue(image, ctx);
 
 	PPC_BCTR();
+
 	/* out: */
+	return 0;
 }
 
+/*
+ * We spill into the redzone always, even if the bpf program has its own stackframe.
+ * Offsets hardcoded based on BPF_PPC_STACK_SAVE -- see bpf_jit_stack_local()
+ */
+void bpf_stf_barrier(void);
+
+asm (
+"		.global bpf_stf_barrier		;"
+"	bpf_stf_barrier:			;"
+"		std	21,-64(1)		;"
+"		std	22,-56(1)		;"
+"		sync				;"
+"		ld	21,-64(1)		;"
+"		ld	22,-56(1)		;"
+"		ori	31,31,0			;"
+"		.rept 14			;"
+"		b	1f			;"
+"	1:					;"
+"		.endr				;"
+"		blr				;"
+);
+
 /* Assemble the body code between the prologue & epilogue */
 static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
 			      struct codegen_context *ctx,
 			      u32 *addrs, bool extra_pass)
 {
+	enum stf_barrier_type stf_barrier = stf_barrier_type_get();
 	const struct bpf_insn *insn = fp->insnsi;
 	int flen = fp->len;
 	int i, ret;
@@ -347,18 +373,25 @@
 			PPC_SUB(dst_reg, dst_reg, src_reg);
 			goto bpf_alu32_trunc;
 		case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */
-		case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */
 		case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */
+			if (!imm) {
+				goto bpf_alu32_trunc;
+			} else if (imm >= -32768 && imm < 32768) {
+				PPC_ADDI(dst_reg, dst_reg, IMM_L(imm));
+			} else {
+				PPC_LI32(b2p[TMP_REG_1], imm);
+				PPC_ADD(dst_reg, dst_reg, b2p[TMP_REG_1]);
+			}
+			goto bpf_alu32_trunc;
+		case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */
 		case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */
-			if (BPF_OP(code) == BPF_SUB)
-				imm = -imm;
-			if (imm) {
-				if (imm >= -32768 && imm < 32768)
-					PPC_ADDI(dst_reg, dst_reg, IMM_L(imm));
-				else {
-					PPC_LI32(b2p[TMP_REG_1], imm);
-					PPC_ADD(dst_reg, dst_reg, b2p[TMP_REG_1]);
-				}
+			if (!imm) {
+				goto bpf_alu32_trunc;
+			} else if (imm > -32768 && imm <= 32768) {
+				PPC_ADDI(dst_reg, dst_reg, IMM_L(-imm));
+			} else {
+				PPC_LI32(b2p[TMP_REG_1], imm);
+				PPC_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]);
 			}
 			goto bpf_alu32_trunc;
 		case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */
@@ -408,8 +441,14 @@
 		case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */
 			if (imm == 0)
 				return -EINVAL;
-			else if (imm == 1)
-				goto bpf_alu32_trunc;
+			if (imm == 1) {
+				if (BPF_OP(code) == BPF_DIV) {
+					goto bpf_alu32_trunc;
+				} else {
+					PPC_LI(dst_reg, 0);
+					break;
+				}
+			}
 
 			PPC_LI32(b2p[TMP_REG_1], imm);
 			switch (BPF_CLASS(code)) {
@@ -645,6 +684,36 @@
 			break;
 
 		/*
+		 * BPF_ST NOSPEC (speculation barrier)
+		 */
+		case BPF_ST | BPF_NOSPEC:
+			if (!security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) ||
+					(!security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) &&
+					(!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) || !cpu_has_feature(CPU_FTR_HVMODE))))
+				break;
+
+			switch (stf_barrier) {
+			case STF_BARRIER_EIEIO:
+				EMIT(0x7c0006ac | 0x02000000);
+				break;
+			case STF_BARRIER_SYNC_ORI:
+				EMIT(PPC_INST_SYNC);
+				PPC_LD(b2p[TMP_REG_1], 13, 0);
+				PPC_ORI(31, 31, 0);
+				break;
+			case STF_BARRIER_FALLBACK:
+				EMIT(PPC_INST_MFLR | ___PPC_RT(b2p[TMP_REG_1]));
+				PPC_LI64(12, dereference_kernel_function_descriptor(bpf_stf_barrier));
+				PPC_MTCTR(12);
+				EMIT(PPC_INST_BCTR | 0x1);
+				PPC_MTLR(b2p[TMP_REG_1]);
+				break;
+			case STF_BARRIER_NONE:
+				break;
+			}
+			break;
+
+		/*
 		 * BPF_ST(X)
 		 */
 		case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */
@@ -989,7 +1058,9 @@
 		 */
 		case BPF_JMP | BPF_TAIL_CALL:
 			ctx->seen |= SEEN_TAILCALL;
-			bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]);
+			ret = bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]);
+			if (ret < 0)
+				return ret;
 			break;
 
 		default:
--- linux-ein-5.4.0.orig/arch/powerpc/perf/callchain.c
+++ linux-ein-5.4.0/arch/powerpc/perf/callchain.c
@@ -64,6 +64,7 @@
 		next_sp = fp[0];
 
 		if (next_sp == sp + STACK_INT_FRAME_SIZE &&
+		    validate_sp(sp, current, STACK_INT_FRAME_SIZE) &&
 		    fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
 			/*
 			 * This looks like an interrupt frame for an
--- linux-ein-5.4.0.orig/arch/powerpc/perf/core-book3s.c
+++ linux-ein-5.4.0/arch/powerpc/perf/core-book3s.c
@@ -133,6 +133,9 @@
 
 bool is_sier_available(void)
 {
+	if (!ppmu)
+		return false;
+
 	if (ppmu->flags & PPMU_HAS_SIER)
 		return true;
 
@@ -1522,9 +1525,16 @@
 	ret = 0;
  out:
 	if (has_branch_stack(event)) {
-		power_pmu_bhrb_enable(event);
-		cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
-					event->attr.branch_sample_type);
+		u64 bhrb_filter = -1;
+
+		if (ppmu->bhrb_filter_map)
+			bhrb_filter = ppmu->bhrb_filter_map(
+				event->attr.branch_sample_type);
+
+		if (bhrb_filter != -1) {
+			cpuhw->bhrb_filter = bhrb_filter;
+			power_pmu_bhrb_enable(event);
+		}
 	}
 
 	perf_pmu_enable(event->pmu);
@@ -1846,7 +1856,6 @@
 	int n;
 	int err;
 	struct cpu_hw_events *cpuhw;
-	u64 bhrb_filter;
 
 	if (!ppmu)
 		return -ENOENT;
@@ -1952,7 +1961,10 @@
 	err = power_check_constraints(cpuhw, events, cflags, n + 1);
 
 	if (has_branch_stack(event)) {
-		bhrb_filter = ppmu->bhrb_filter_map(
+		u64 bhrb_filter = -1;
+
+		if (ppmu->bhrb_filter_map)
+			bhrb_filter = ppmu->bhrb_filter_map(
 					event->attr.branch_sample_type);
 
 		if (bhrb_filter == -1) {
@@ -2065,7 +2077,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)
@@ -2078,6 +2100,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) {
@@ -2106,6 +2139,10 @@
 
 		if (perf_event_overflow(event, &data, regs))
 			power_pmu_stop(event, 0);
+	} else if (period) {
+		/* Account for interrupt in case of invalid SIAR */
+		if (perf_event_account_interrupt(event))
+			power_pmu_stop(event, 0);
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/perf/hv-24x7.c
+++ linux-ein-5.4.0/arch/powerpc/perf/hv-24x7.c
@@ -1313,7 +1313,7 @@
 	}
 
 	domain = event_get_domain(event);
-	if (domain >= HV_PERF_DOMAIN_MAX) {
+	if (domain  == 0 || domain >= HV_PERF_DOMAIN_MAX) {
 		pr_devel("invalid domain %d\n", domain);
 		return -EINVAL;
 	}
@@ -1400,16 +1400,6 @@
 			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-ein-5.4.0.orig/arch/powerpc/perf/hv-gpci-requests.h
+++ linux-ein-5.4.0/arch/powerpc/perf/hv-gpci-requests.h
@@ -79,6 +79,7 @@
 )
 #include I(REQUEST_END)
 
+#ifdef ENABLE_EVENTS_COUNTERINFO_V6
 /*
  * Not available for counter_info_version >= 0x8, use
  * run_instruction_cycles_by_partition(0x100) instead.
@@ -92,10 +93,11 @@
 	__count(0x10,	8,	cycles)
 )
 #include I(REQUEST_END)
+#endif
 
 #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)
@@ -103,6 +105,7 @@
 )
 #include I(REQUEST_END)
 
+#ifdef ENABLE_EVENTS_COUNTERINFO_V6
 #define REQUEST_NAME processor_bus_utilization_abc_links
 #define REQUEST_NUM 0x50
 #define REQUEST_IDX_KIND "hw_chip_id=?"
@@ -194,6 +197,7 @@
 	__count(0x28,	8,	instructions_completed)
 )
 #include I(REQUEST_END)
+#endif
 
 /* Processor_core_power_mode (0x95) skipped, no counters */
 /* Affinity_domain_information_by_virtual_processor (0xA0) skipped,
@@ -223,7 +227,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)
@@ -234,7 +238,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-ein-5.4.0.orig/arch/powerpc/perf/hv-gpci.c
+++ linux-ein-5.4.0/arch/powerpc/perf/hv-gpci.c
@@ -70,7 +70,7 @@
 
 static struct attribute_group event_group = {
 	.name  = "events",
-	.attrs = hv_gpci_event_attrs,
+	/* .attrs is set in init */
 };
 
 #define HV_CAPS_ATTR(_name, _format)				\
@@ -164,7 +164,7 @@
 	 */
 	count = 0;
 	for (i = offset; i < offset + length; i++)
-		count |= arg->bytes[i] << (i - offset);
+		count |= (u64)(arg->bytes[i]) << ((length - 1 - (i - offset)) * 8);
 
 	*value = count;
 out:
@@ -280,6 +280,7 @@
 	int r;
 	unsigned long hret;
 	struct hv_perf_caps caps;
+	struct hv_gpci_request_buffer *arg;
 
 	hv_gpci_assert_offsets_correct();
 
@@ -298,6 +299,36 @@
 	/* sampling not supported */
 	h_gpci_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
 
+	arg = (void *)get_cpu_var(hv_gpci_reqb);
+	memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
+
+	/*
+	 * hcall H_GET_PERF_COUNTER_INFO populates the output
+	 * counter_info_version value based on the system hypervisor.
+	 * Pass the counter request 0x10 corresponds to request type
+	 * 'Dispatch_timebase_by_processor', to get the supported
+	 * counter_info_version.
+	 */
+	arg->params.counter_request = cpu_to_be32(0x10);
+
+	r = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+			virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE);
+	if (r) {
+		pr_devel("hcall failed, can't get supported counter_info_version: 0x%x\n", r);
+		arg->params.counter_info_version_out = 0x8;
+	}
+
+	/*
+	 * Use counter_info_version_out value to assign
+	 * required hv-gpci event list.
+	 */
+	if (arg->params.counter_info_version_out >= 0x8)
+		event_group.attrs = hv_gpci_event_attrs;
+	else
+		event_group.attrs = hv_gpci_event_attrs_v6;
+
+	put_cpu_var(hv_gpci_reqb);
+
 	r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1);
 	if (r)
 		return r;
--- linux-ein-5.4.0.orig/arch/powerpc/perf/hv-gpci.h
+++ linux-ein-5.4.0/arch/powerpc/perf/hv-gpci.h
@@ -53,6 +53,7 @@
 #define REQUEST_FILE "../hv-gpci-requests.h"
 #define NAME_LOWER hv_gpci
 #define NAME_UPPER HV_GPCI
+#define ENABLE_EVENTS_COUNTERINFO_V6
 #include "req-gen/perf.h"
 #undef REQUEST_FILE
 #undef NAME_LOWER
--- linux-ein-5.4.0.orig/arch/powerpc/perf/imc-pmu.c
+++ linux-ein-5.4.0/arch/powerpc/perf/imc-pmu.c
@@ -13,6 +13,7 @@
 #include <asm/cputhreads.h>
 #include <asm/smp.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 
 /* Nest IMC data structures and variables */
 
@@ -44,6 +45,16 @@
 static struct imc_pmu_ref *trace_imc_refc;
 static int trace_imc_mem_size;
 
+/*
+ * Global data structure used to avoid races between thread,
+ * core and trace-imc
+ */
+static struct imc_pmu_ref imc_global_refc = {
+	.lock = __SPIN_LOCK_UNLOCKED(imc_global_refc.lock),
+	.id = 0,
+	.refc = 0,
+};
+
 static struct imc_pmu *imc_event_to_pmu(struct perf_event *event)
 {
 	return container_of(event->pmu, struct imc_pmu, pmu);
@@ -281,6 +292,8 @@
 	attr_group->attrs = attrs;
 	do {
 		ev_val_str = kasprintf(GFP_KERNEL, "event=0x%x", pmu->events[i].value);
+		if (!ev_val_str)
+			continue;
 		dev_str = device_str_attr_create(pmu->events[i].name, ev_val_str);
 		if (!dev_str)
 			continue;
@@ -288,6 +301,8 @@
 		attrs[j++] = dev_str;
 		if (pmu->events[i].scale) {
 			ev_scale_str = kasprintf(GFP_KERNEL, "%s.scale", pmu->events[i].name);
+			if (!ev_scale_str)
+				continue;
 			dev_str = device_str_attr_create(ev_scale_str, pmu->events[i].scale);
 			if (!dev_str)
 				continue;
@@ -297,6 +312,8 @@
 
 		if (pmu->events[i].unit) {
 			ev_unit_str = kasprintf(GFP_KERNEL, "%s.unit", pmu->events[i].name);
+			if (!ev_unit_str)
+				continue;
 			dev_str = device_str_attr_create(ev_unit_str, pmu->events[i].unit);
 			if (!dev_str)
 				continue;
@@ -383,7 +400,7 @@
 				       get_hard_smp_processor_id(cpu));
 		/*
 		 * If this is the last cpu in this chip then, skip the reference
-		 * count mutex lock and make the reference count on this chip zero.
+		 * count lock and make the reference count on this chip zero.
 		 */
 		ref = get_nest_pmu_ref(cpu);
 		if (!ref)
@@ -445,15 +462,15 @@
 	/*
 	 * See if we need to disable the nest PMU.
 	 * If no events are currently in use, then we have to take a
-	 * mutex to ensure that we don't race with another task doing
+	 * lock to ensure that we don't race with another task doing
 	 * enable or disable the nest counters.
 	 */
 	ref = get_nest_pmu_ref(event->cpu);
 	if (!ref)
 		return;
 
-	/* Take the mutex lock for this node and then decrement the reference count */
-	mutex_lock(&ref->lock);
+	/* Take the lock for this node and then decrement the reference count */
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		/*
 		 * The scenario where this is true is, when perf session is
@@ -465,7 +482,7 @@
 		 * an OPAL call to disable the engine in that node.
 		 *
 		 */
-		mutex_unlock(&ref->lock);
+		spin_unlock(&ref->lock);
 		return;
 	}
 	ref->refc--;
@@ -473,7 +490,7 @@
 		rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,
 					    get_hard_smp_processor_id(event->cpu));
 		if (rc) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("nest-imc: Unable to stop the counters for core %d\n", node_id);
 			return;
 		}
@@ -481,7 +498,7 @@
 		WARN(1, "nest-imc: Invalid event reference count\n");
 		ref->refc = 0;
 	}
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
 }
 
 static int nest_imc_event_init(struct perf_event *event)
@@ -540,26 +557,25 @@
 
 	/*
 	 * Get the imc_pmu_ref struct for this node.
-	 * Take the mutex lock and then increment the count of nest pmu events
-	 * inited.
+	 * Take the lock and then increment the count of nest pmu events inited.
 	 */
 	ref = get_nest_pmu_ref(event->cpu);
 	if (!ref)
 		return -EINVAL;
 
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_NEST,
 					     get_hard_smp_processor_id(event->cpu));
 		if (rc) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("nest-imc: Unable to start the counters for node %d\n",
 									node_id);
 			return rc;
 		}
 	}
 	++ref->refc;
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
 
 	event->destroy = nest_imc_counters_release;
 	return 0;
@@ -595,9 +611,8 @@
 		return -ENOMEM;
 	mem_info->vbase = page_address(page);
 
-	/* Init the mutex */
 	core_imc_refc[core_id].id = core_id;
-	mutex_init(&core_imc_refc[core_id].lock);
+	spin_lock_init(&core_imc_refc[core_id].lock);
 
 	rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,
 				__pa((void *)mem_info->vbase),
@@ -686,9 +701,8 @@
 		perf_pmu_migrate_context(&core_imc_pmu->pmu, cpu, ncpu);
 	} else {
 		/*
-		 * If this is the last cpu in this core then, skip taking refernce
-		 * count mutex lock for this core and directly zero "refc" for
-		 * this core.
+		 * If this is the last cpu in this core then skip taking reference
+		 * count lock for this core and directly zero "refc" for this core.
 		 */
 		opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
 				       get_hard_smp_processor_id(cpu));
@@ -698,6 +712,16 @@
 			return -EINVAL;
 
 		ref->refc = 0;
+		/*
+		 * Reduce the global reference count, if this is the
+		 * last cpu in this core and core-imc event running
+		 * in this cpu.
+		 */
+		spin_lock(&imc_global_refc.lock);
+		if (imc_global_refc.id == IMC_DOMAIN_CORE)
+			imc_global_refc.refc--;
+
+		spin_unlock(&imc_global_refc.lock);
 	}
 	return 0;
 }
@@ -710,6 +734,23 @@
 				 ppc_core_imc_cpu_offline);
 }
 
+static void reset_global_refc(struct perf_event *event)
+{
+		spin_lock(&imc_global_refc.lock);
+		imc_global_refc.refc--;
+
+		/*
+		 * If no other thread is running any
+		 * event for this domain(thread/core/trace),
+		 * set the global id to zero.
+		 */
+		if (imc_global_refc.refc <= 0) {
+			imc_global_refc.refc = 0;
+			imc_global_refc.id = 0;
+		}
+		spin_unlock(&imc_global_refc.lock);
+}
+
 static void core_imc_counters_release(struct perf_event *event)
 {
 	int rc, core_id;
@@ -720,17 +761,17 @@
 	/*
 	 * See if we need to disable the IMC PMU.
 	 * If no events are currently in use, then we have to take a
-	 * mutex to ensure that we don't race with another task doing
+	 * lock to ensure that we don't race with another task doing
 	 * enable or disable the core counters.
 	 */
 	core_id = event->cpu / threads_per_core;
 
-	/* Take the mutex lock and decrement the refernce count for this core */
+	/* Take the lock and decrement the refernce count for this core */
 	ref = &core_imc_refc[core_id];
 	if (!ref)
 		return;
 
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		/*
 		 * The scenario where this is true is, when perf session is
@@ -742,7 +783,7 @@
 		 * an OPAL call to disable the engine in that core.
 		 *
 		 */
-		mutex_unlock(&ref->lock);
+		spin_unlock(&ref->lock);
 		return;
 	}
 	ref->refc--;
@@ -750,7 +791,7 @@
 		rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
 					    get_hard_smp_processor_id(event->cpu));
 		if (rc) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("IMC: Unable to stop the counters for core %d\n", core_id);
 			return;
 		}
@@ -758,7 +799,9 @@
 		WARN(1, "core-imc: Invalid event reference count\n");
 		ref->refc = 0;
 	}
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
+
+	reset_global_refc(event);
 }
 
 static int core_imc_event_init(struct perf_event *event)
@@ -794,7 +837,6 @@
 	if ((!pcmi->vbase))
 		return -ENODEV;
 
-	/* Get the core_imc mutex for this core */
 	ref = &core_imc_refc[core_id];
 	if (!ref)
 		return -EINVAL;
@@ -802,22 +844,45 @@
 	/*
 	 * Core pmu units are enabled only when it is used.
 	 * See if this is triggered for the first time.
-	 * If yes, take the mutex lock and enable the core counters.
+	 * If yes, take the lock and enable the core counters.
 	 * If not, just increment the count in core_imc_refc struct.
 	 */
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
 					     get_hard_smp_processor_id(event->cpu));
 		if (rc) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("core-imc: Unable to start the counters for core %d\n",
 									core_id);
 			return rc;
 		}
 	}
 	++ref->refc;
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
+
+	/*
+	 * Since the system can run either in accumulation or trace-mode
+	 * of IMC at a time, core-imc events are allowed only if no other
+	 * trace/thread imc events are enabled/monitored.
+	 *
+	 * Take the global lock, and check the refc.id
+	 * to know whether any other trace/thread imc
+	 * events are running.
+	 */
+	spin_lock(&imc_global_refc.lock);
+	if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_CORE) {
+		/*
+		 * No other trace/thread imc events are running in
+		 * the system, so set the refc.id to core-imc.
+		 */
+		imc_global_refc.id = IMC_DOMAIN_CORE;
+		imc_global_refc.refc++;
+	} else {
+		spin_unlock(&imc_global_refc.lock);
+		return -EBUSY;
+	}
+	spin_unlock(&imc_global_refc.lock);
 
 	event->hw.event_base = (u64)pcmi->vbase + (config & IMC_EVENT_OFFSET_MASK);
 	event->destroy = core_imc_counters_release;
@@ -877,7 +942,23 @@
 
 static int ppc_thread_imc_cpu_offline(unsigned int cpu)
 {
-	mtspr(SPRN_LDBAR, 0);
+	/*
+	 * Set the bit 0 of LDBAR to zero.
+	 *
+	 * If bit 0 of LDBAR is unset, it will stop posting
+	 * the counter data to memory.
+	 * For thread-imc, bit 0 of LDBAR will be set to 1 in the
+	 * event_add function. So reset this bit here, to stop the updates
+	 * to memory in the cpu_offline path.
+	 */
+	mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+
+	/* Reduce the refc if thread-imc event running on this cpu */
+	spin_lock(&imc_global_refc.lock);
+	if (imc_global_refc.id == IMC_DOMAIN_THREAD)
+		imc_global_refc.refc--;
+	spin_unlock(&imc_global_refc.lock);
+
 	return 0;
 }
 
@@ -916,7 +997,22 @@
 	if (!target)
 		return -EINVAL;
 
+	spin_lock(&imc_global_refc.lock);
+	/*
+	 * Check if any other trace/core imc events are running in the
+	 * system, if not set the global id to thread-imc.
+	 */
+	if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_THREAD) {
+		imc_global_refc.id = IMC_DOMAIN_THREAD;
+		imc_global_refc.refc++;
+	} else {
+		spin_unlock(&imc_global_refc.lock);
+		return -EBUSY;
+	}
+	spin_unlock(&imc_global_refc.lock);
+
 	event->pmu->task_ctx_nr = perf_sw_context;
+	event->destroy = reset_global_refc;
 	return 0;
 }
 
@@ -1035,25 +1131,25 @@
 	/*
 	 * imc pmus are enabled only when it is used.
 	 * See if this is triggered for the first time.
-	 * If yes, take the mutex lock and enable the counters.
+	 * If yes, take the lock and enable the counters.
 	 * If not, just increment the count in ref count struct.
 	 */
 	ref = &core_imc_refc[core_id];
 	if (!ref)
 		return -EINVAL;
 
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		if (opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
 		    get_hard_smp_processor_id(smp_processor_id()))) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("thread-imc: Unable to start the counter\
 				for core %d\n", core_id);
 			return -EINVAL;
 		}
 	}
 	++ref->refc;
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
 	return 0;
 }
 
@@ -1063,17 +1159,19 @@
 	int core_id;
 	struct imc_pmu_ref *ref;
 
-	mtspr(SPRN_LDBAR, 0);
-
 	core_id = smp_processor_id() / threads_per_core;
 	ref = &core_imc_refc[core_id];
+	if (!ref) {
+		pr_debug("imc: Failed to get event reference count\n");
+		return;
+	}
 
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	ref->refc--;
 	if (ref->refc == 0) {
 		if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
 		    get_hard_smp_processor_id(smp_processor_id()))) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("thread-imc: Unable to stop the counters\
 				for core %d\n", core_id);
 			return;
@@ -1081,7 +1179,11 @@
 	} else if (ref->refc < 0) {
 		ref->refc = 0;
 	}
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
+
+	/* Set bit 0 of LDBAR to zero, to stop posting updates to memory */
+	mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+
 	/*
 	 * Take a snapshot and calculate the delta and update
 	 * the event counter values.
@@ -1118,9 +1220,8 @@
 		}
 	}
 
-	/* Init the mutex, if not already */
 	trace_imc_refc[core_id].id = core_id;
-	mutex_init(&trace_imc_refc[core_id].lock);
+	spin_lock_init(&trace_imc_refc[core_id].lock);
 
 	mtspr(SPRN_LDBAR, 0);
 	return 0;
@@ -1133,7 +1234,18 @@
 
 static int ppc_trace_imc_cpu_offline(unsigned int cpu)
 {
-	mtspr(SPRN_LDBAR, 0);
+	/*
+	 * No need to set bit 0 of LDBAR to zero, as
+	 * it is set to zero for imc trace-mode
+	 *
+	 * Reduce the refc if any trace-imc event running
+	 * on this cpu.
+	 */
+	spin_lock(&imc_global_refc.lock);
+	if (imc_global_refc.id == IMC_DOMAIN_TRACE)
+		imc_global_refc.refc--;
+	spin_unlock(&imc_global_refc.lock);
+
 	return 0;
 }
 
@@ -1226,29 +1338,26 @@
 	local_mem = get_trace_imc_event_base_addr();
 	ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) | TRACE_IMC_ENABLE;
 
-	if (core_imc_refc)
-		ref = &core_imc_refc[core_id];
+	/* trace-imc reference count */
+	if (trace_imc_refc)
+		ref = &trace_imc_refc[core_id];
 	if (!ref) {
-		/* If core-imc is not enabled, use trace-imc reference count */
-		if (trace_imc_refc)
-			ref = &trace_imc_refc[core_id];
-		if (!ref)
-			return -EINVAL;
+		pr_debug("imc: Failed to get the event reference count\n");
+		return -EINVAL;
 	}
+
 	mtspr(SPRN_LDBAR, ldbar_value);
-	mutex_lock(&ref->lock);
+	spin_lock(&ref->lock);
 	if (ref->refc == 0) {
 		if (opal_imc_counters_start(OPAL_IMC_COUNTERS_TRACE,
 				get_hard_smp_processor_id(smp_processor_id()))) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("trace-imc: Unable to start the counters for core %d\n", core_id);
-			mtspr(SPRN_LDBAR, 0);
 			return -EINVAL;
 		}
 	}
 	++ref->refc;
-	mutex_unlock(&ref->lock);
-
+	spin_unlock(&ref->lock);
 	return 0;
 }
 
@@ -1274,29 +1383,27 @@
 	int core_id = smp_processor_id() / threads_per_core;
 	struct imc_pmu_ref *ref = NULL;
 
-	if (core_imc_refc)
-		ref = &core_imc_refc[core_id];
+	if (trace_imc_refc)
+		ref = &trace_imc_refc[core_id];
 	if (!ref) {
-		/* If core-imc is not enabled, use trace-imc reference count */
-		if (trace_imc_refc)
-			ref = &trace_imc_refc[core_id];
-		if (!ref)
-			return;
+		pr_debug("imc: Failed to get event reference count\n");
+		return;
 	}
-	mtspr(SPRN_LDBAR, 0);
-	mutex_lock(&ref->lock);
+
+	spin_lock(&ref->lock);
 	ref->refc--;
 	if (ref->refc == 0) {
 		if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_TRACE,
 				get_hard_smp_processor_id(smp_processor_id()))) {
-			mutex_unlock(&ref->lock);
+			spin_unlock(&ref->lock);
 			pr_err("trace-imc: Unable to stop the counters for core %d\n", core_id);
 			return;
 		}
 	} else if (ref->refc < 0) {
 		ref->refc = 0;
 	}
-	mutex_unlock(&ref->lock);
+	spin_unlock(&ref->lock);
+
 	trace_imc_event_stop(event, flags);
 }
 
@@ -1314,10 +1421,34 @@
 	if (event->attr.sample_period == 0)
 		return -ENOENT;
 
+	/*
+	 * Take the global lock, and make sure
+	 * no other thread is running any core/thread imc
+	 * events
+	 */
+	spin_lock(&imc_global_refc.lock);
+	if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_TRACE) {
+		/*
+		 * No core/thread imc events are running in the
+		 * system, so set the refc.id to trace-imc.
+		 */
+		imc_global_refc.id = IMC_DOMAIN_TRACE;
+		imc_global_refc.refc++;
+	} else {
+		spin_unlock(&imc_global_refc.lock);
+		return -EBUSY;
+	}
+	spin_unlock(&imc_global_refc.lock);
+
 	event->hw.idx = -1;
 	target = event->hw.target;
 
-	event->pmu->task_ctx_nr = perf_hw_context;
+	/*
+	 * There can only be a single PMU for perf_hw_context events which is assigned to
+	 * core PMU. Hence use "perf_sw_context" for trace_imc.
+	 */
+	event->pmu->task_ctx_nr = perf_sw_context;
+	event->destroy = reset_global_refc;
 	return 0;
 }
 
@@ -1380,10 +1511,10 @@
 	i = 0;
 	for_each_node(nid) {
 		/*
-		 * Mutex lock to avoid races while tracking the number of
+		 * Take the lock to avoid races while tracking the number of
 		 * sessions using the chip's nest pmu units.
 		 */
-		mutex_init(&nest_imc_refc[i].lock);
+		spin_lock_init(&nest_imc_refc[i].lock);
 
 		/*
 		 * Loop to init the "id" with the node_id. Variable "i" initialized to
@@ -1429,10 +1560,10 @@
 static void thread_imc_ldbar_disable(void *dummy)
 {
 	/*
-	 * By Zeroing LDBAR, we disable thread-imc
-	 * updates.
+	 * By setting 0th bit of LDBAR to zero, we disable thread-imc
+	 * updates to memory.
 	 */
-	mtspr(SPRN_LDBAR, 0);
+	mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
 }
 
 void thread_imc_disable(void)
--- linux-ein-5.4.0.orig/arch/powerpc/perf/isa207-common.c
+++ linux-ein-5.4.0/arch/powerpc/perf/isa207-common.c
@@ -269,6 +269,15 @@
 
 		mask  |= CNST_PMC_MASK(pmc);
 		value |= CNST_PMC_VAL(pmc);
+
+		/*
+		 * PMC5 and PMC6 are used to count cycles and instructions and
+		 * they do not support most of the constraint bits. Add a check
+		 * to exclude PMC5/6 from most of the constraints except for
+		 * EBB/BHRB.
+		 */
+		if (pmc >= 5)
+			goto ebb_bhrb;
 	}
 
 	if (pmc <= 4) {
@@ -317,7 +326,8 @@
 		if (event_is_threshold(event) && is_thresh_cmp_valid(event)) {
 			mask  |= CNST_THRESH_MASK;
 			value |= CNST_THRESH_VAL(event >> EVENT_THRESH_SHIFT);
-		}
+		} else if (event_is_threshold(event))
+			return -1;
 	} else {
 		/*
 		 * Special case for PM_MRK_FAB_RSP_MATCH and PM_MRK_FAB_RSP_MATCH_CYC,
@@ -335,6 +345,7 @@
 		}
 	}
 
+ebb_bhrb:
 	if (!pmc && ebb)
 		/* EBB events must specify the PMC */
 		return -1;
@@ -353,8 +364,8 @@
 	 * EBB events are pinned & exclusive, so this should never actually
 	 * hit, but we leave it as a fallback in case.
 	 */
-	mask  |= CNST_EBB_VAL(ebb);
-	value |= CNST_EBB_MASK;
+	mask  |= CNST_EBB_MASK;
+	value |= CNST_EBB_VAL(ebb);
 
 	*maskp = mask;
 	*valp = value;
--- linux-ein-5.4.0.orig/arch/powerpc/perf/power9-pmu.c
+++ linux-ein-5.4.0/arch/powerpc/perf/power9-pmu.c
@@ -131,11 +131,11 @@
 
 /* Table of alternatives, sorted by column 0 */
 static const unsigned int power9_event_alternatives[][MAX_ALT] = {
-	{ PM_INST_DISP,			PM_INST_DISP_ALT },
-	{ PM_RUN_CYC_ALT,		PM_RUN_CYC },
-	{ PM_RUN_INST_CMPL_ALT,		PM_RUN_INST_CMPL },
-	{ PM_LD_MISS_L1,		PM_LD_MISS_L1_ALT },
 	{ PM_BR_2PATH,			PM_BR_2PATH_ALT },
+	{ PM_INST_DISP,			PM_INST_DISP_ALT },
+	{ PM_RUN_CYC_ALT,               PM_RUN_CYC },
+	{ PM_LD_MISS_L1,                PM_LD_MISS_L1_ALT },
+	{ PM_RUN_INST_CMPL_ALT,         PM_RUN_INST_CMPL },
 };
 
 static int power9_get_alternatives(u64 event, unsigned int flags, u64 alt[])
--- linux-ein-5.4.0.orig/arch/powerpc/perf/req-gen/perf.h
+++ linux-ein-5.4.0/arch/powerpc/perf/req-gen/perf.h
@@ -139,6 +139,26 @@
 #define REQUEST_(r_name, r_value, r_idx_1, r_fields)			\
 	r_fields
 
+/* Generate event list for platforms with counter_info_version 0x6 or below */
+static __maybe_unused struct attribute *hv_gpci_event_attrs_v6[] = {
+#include REQUEST_FILE
+	NULL
+};
+
+/*
+ * Based on getPerfCountInfo v1.018 documentation, some of the hv-gpci
+ * events were deprecated for platform firmware that supports
+ * counter_info_version 0x8 or above.
+ * Those deprecated events are still part of platform firmware that
+ * support counter_info_version 0x6 and below. As per the getPerfCountInfo
+ * v1.018 documentation there is no counter_info_version 0x7.
+ * Undefining macro ENABLE_EVENTS_COUNTERINFO_V6, to disable the addition of
+ * deprecated events in "hv_gpci_event_attrs" attribute group, for platforms
+ * that supports counter_info_version 0x8 or above.
+ */
+#undef ENABLE_EVENTS_COUNTERINFO_V6
+
+/* Generate event list for platforms with counter_info_version 0x8 or above*/
 static __maybe_unused struct attribute *hv_gpci_event_attrs[] = {
 #include REQUEST_FILE
 	NULL
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/44x/Kconfig
+++ linux-ein-5.4.0/arch/powerpc/platforms/44x/Kconfig
@@ -178,6 +178,7 @@
 config CURRITUCK
 	bool "IBM Currituck (476fpe) Support"
 	depends on PPC_47x
+	select I2C
 	select SWIOTLB
 	select 476FPE
 	select FORCE_PCI
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/44x/fsp2.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/44x/fsp2.c
@@ -208,6 +208,7 @@
 		if (irq == NO_IRQ) {
 			pr_err("device tree node %pOFn is missing a interrupt",
 			      np);
+			of_node_put(np);
 			return;
 		}
 
@@ -215,6 +216,7 @@
 		if (rc) {
 			pr_err("fsp_of_probe: request_irq failed: np=%pOF rc=%d",
 			      np, rc);
+			of_node_put(np);
 			return;
 		}
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/4xx/cpm.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/4xx/cpm.c
@@ -327,6 +327,6 @@
 static int __init cpm_powersave_off(char *arg)
 {
 	cpm.powersave_off = 1;
-	return 0;
+	return 1;
 }
 __setup("powersave=off", cpm_powersave_off);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/4xx/pci.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/4xx/pci.c
@@ -1242,7 +1242,7 @@
 	if (mbase == NULL) {
 		printk(KERN_ERR "%pOF: Can't map internal config space !",
 			port->node);
-		goto done;
+		return;
 	}
 
 	while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA)
@@ -1252,9 +1252,7 @@
 	}
 	if (attempt)
 		port->link = 1;
-done:
 	iounmap(mbase);
-
 }
 
 static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/512x/clock-commonclk.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -984,7 +984,7 @@
 
 #define NODE_PREP do { \
 	of_address_to_resource(np, 0, &res); \
-	snprintf(devname, sizeof(devname), "%08x.%s", res.start, np->name); \
+	snprintf(devname, sizeof(devname), "%pa.%s", &res.start, np->name); \
 } while (0)
 
 #define NODE_CHK(clkname, clkitem, regnode, regflag) do { \
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/52xx/lite5200_sleep.S
+++ linux-ein-5.4.0/arch/powerpc/platforms/52xx/lite5200_sleep.S
@@ -181,7 +181,7 @@
   udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */
 	mullw	r12, r12, r11
 	mftb	r13	/* start */
-	addi	r12, r13, r12 /* end */
+	add	r12, r13, r12 /* end */
     1:
 	mftb	r13	/* current */
 	cmp	cr0, r13, r12
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
@@ -530,6 +530,7 @@
  err_bcom_rx_irq:
 	bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task);
  err_bcom_rx:
+	free_irq(lpbfifo.irq, &lpbfifo);
  err_irq:
 	iounmap(lpbfifo.regs);
 	lpbfifo.regs = NULL;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -340,7 +340,7 @@
 {
 	int l1irq;
 	int l2irq;
-	struct irq_chip *uninitialized_var(irqchip);
+	struct irq_chip *irqchip;
 	void *hndlr;
 	int type;
 	u32 reg;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -107,7 +107,7 @@
 
 		goto next;
 unreg:
-		platform_device_del(pdev);
+		platform_device_put(pdev);
 err:
 		pr_err("%pOF: registration failed\n", np);
 next:
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c
@@ -94,9 +94,8 @@
 			pr_err("Could not map guts node address\n");
 			return -ENOMEM;
 		}
+		qoriq_pm_ops = &mpc85xx_pm_ops;
 	}
 
-	qoriq_pm_ops = &mpc85xx_pm_ops;
-
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/8xx/cpm1.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/8xx/cpm1.c
@@ -292,6 +292,7 @@
 		out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
 			      CPM_BRG_EN | CPM_BRG_DIV16);
 }
+EXPORT_SYMBOL(cpm_setbrg);
 
 struct cpm_ioport16 {
 	__be16 dir, par, odr_sor, dat, intr;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/8xx/micropatch.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/8xx/micropatch.c
@@ -361,6 +361,17 @@
 	if (IS_ENABLED(CONFIG_SMC_UCODE_PATCH)) {
 		smc_uart_t *smp;
 
+		if (IS_ENABLED(CONFIG_PPC_EARLY_DEBUG_CPM)) {
+			int i;
+
+			for (i = 0; i < sizeof(*smp); i += 4) {
+				u32 __iomem *src = (u32 __iomem *)&cp->cp_dparam[PROFF_SMC1 + i];
+				u32 __iomem *dst = (u32 __iomem *)&cp->cp_dparam[PROFF_DSP1 + i];
+
+				out_be32(dst, in_be32(src));
+			}
+		}
+
 		smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
 		out_be16(&smp->smc_rpbase, 0x1ec0);
 		smp = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/8xx/pic.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/8xx/pic.c
@@ -153,6 +153,7 @@
 	if (mpc8xx_pic_host == NULL) {
 		printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
 		ret = -ENOMEM;
+		goto out;
 	}
 
 	ret = 0;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/Kconfig
+++ linux-ein-5.4.0/arch/powerpc/platforms/Kconfig
@@ -219,12 +219,11 @@
 	  temperature within 2-4 degrees Celsius. This option shows the current
 	  on-die temperature in /proc/cpuinfo if the cpu supports it.
 
-	  Unfortunately, on some chip revisions, this sensor is very inaccurate
-	  and in many cases, does not work at all, so don't assume the cpu
-	  temp is actually what /proc/cpuinfo says it is.
+	  Unfortunately, this sensor is very inaccurate when uncalibrated, so
+	  don't assume the cpu 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
@@ -232,12 +231,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-ein-5.4.0.orig/arch/powerpc/platforms/Kconfig.cputype
+++ linux-ein-5.4.0/arch/powerpc/platforms/Kconfig.cputype
@@ -118,9 +118,9 @@
 	depends on PPC64 && CPU_LITTLE_ENDIAN
 	select ARCH_HAS_FAST_MULTIPLIER
 
-config GENERIC_CPU
+config POWERPC_CPU
 	bool "Generic 32 bits powerpc"
-	depends on PPC32 && !PPC_8xx
+	depends on PPC32 && !PPC_8xx && !PPC_85xx
 
 config CELL_CPU
 	bool "Cell Broadband Engine"
@@ -151,11 +151,11 @@
 
 config E5500_CPU
 	bool "Freescale e5500"
-	depends on E500
+	depends on PPC64 && E500
 
 config E6500_CPU
 	bool "Freescale e6500"
-	depends on E500
+	depends on PPC64 && E500
 
 config 860_CPU
 	bool "8xx family"
@@ -174,11 +174,23 @@
 	depends on PPC_BOOK3S_32
 	select ALTIVEC
 
+config E500_CPU
+	bool "e500 (8540)"
+	depends on PPC_85xx && !PPC_E500MC
+
+config E500MC_CPU
+	bool "e500mc"
+	depends on PPC_85xx && PPC_E500MC
+
+config TOOLCHAIN_DEFAULT_CPU
+	bool "Rely on the toolchain's implicit default CPU"
+	depends on PPC32
+
 endchoice
 
 config TARGET_CPU_BOOL
 	bool
-	default !GENERIC_CPU
+	default !GENERIC_CPU && !TOOLCHAIN_DEFAULT_CPU
 
 config TARGET_CPU
 	string
@@ -193,6 +205,9 @@
 	default "e300c2" if E300C2_CPU
 	default "e300c3" if E300C3_CPU
 	default "G4" if G4_CPU
+	default "8540" if E500_CPU
+	default "e500mc" if E500MC_CPU
+	default "powerpc" if POWERPC_CPU
 
 config PPC_BOOK3S
 	def_bool y
@@ -389,7 +404,7 @@
 
 config PPC_KUAP_DEBUG
 	bool "Extra debugging for Kernel Userspace Access Protection"
-	depends on PPC_HAVE_KUAP && (PPC_RADIX_MMU || PPC_32)
+	depends on PPC_KUAP && (PPC_RADIX_MMU || PPC32)
 	help
 	  Add extra debugging for Kernel Userspace Access Protection (KUAP)
 	  If you're unsure, say N.
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/Kconfig
@@ -44,6 +44,7 @@
 	tristate "SPU file system"
 	default m
 	depends on PPC_CELL
+	depends on COREDUMP
 	select SPU_BASE
 	help
 	  The SPU file system is used to access Synergistic Processing
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/cell/axon_msi.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/axon_msi.c
@@ -226,6 +226,7 @@
 	if (!prop) {
 		dev_dbg(&dev->dev,
 			"axon_msi: no msi-address-(32|64) properties found\n");
+		of_node_put(dn);
 		return -ENOENT;
 	}
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/cell/iommu.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/iommu.c
@@ -976,6 +976,7 @@
 			if (hbase < dbase || (hend > (dbase + dsize))) {
 				pr_debug("iommu: hash window doesn't fit in"
 					 "real DMA window\n");
+				of_node_put(np);
 				return -1;
 			}
 		}
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/cell/pervasive.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/pervasive.c
@@ -77,6 +77,7 @@
 	switch (regs->msr & SRR1_WAKEMASK) {
 	case SRR1_WAKEDEC:
 		set_dec(1);
+		break;
 	case SRR1_WAKEEE:
 		/*
 		 * Handle these when interrupts get re-enabled and we take
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/spufs/file.c
@@ -1978,8 +1978,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(buf, len))
 		return -EFAULT;
@@ -1988,11 +1989,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 = {
@@ -2019,6 +2025,7 @@
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	u32 stat, data;
 	int ret;
 
 	if (!access_ok(buf, len))
@@ -2028,11 +2035,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 = {
@@ -2041,6 +2053,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)
 {
@@ -2049,7 +2066,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];
 	}
@@ -2062,7 +2079,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(buf, len))
 		return -EFAULT;
@@ -2071,11 +2089,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 = {
@@ -2084,27 +2104,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);
@@ -2114,6 +2140,7 @@
 			      size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_dma_info info;
 	int ret;
 
 	if (!access_ok(buf, len))
@@ -2123,11 +2150,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 = {
@@ -2136,13 +2164,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;
@@ -2150,18 +2196,7 @@
 	if (!access_ok(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);
@@ -2171,17 +2206,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-ein-5.4.0.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/cell/spufs/inode.c
@@ -671,6 +671,7 @@
 		return;
 
 	loader = of_get_property(dn, "loader", &size);
+	of_node_put(dn);
 	if (!loader)
 		return;
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/embedded6xx/flipper-pic.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/embedded6xx/flipper-pic.c
@@ -144,7 +144,7 @@
 	}
 	io_base = ioremap(res.start, resource_size(&res));
 
-	pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base);
+	pr_info("controller at 0x%pa mapped to 0x%p\n", &res.start, io_base);
 
 	__flipper_quiesce(io_base);
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -173,7 +173,7 @@
 		return NULL;
 	}
 
-	pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base);
+	pr_info("controller at 0x%pa mapped to 0x%p\n", &res.start, io_base);
 
 	__hlwd_quiesce(io_base);
 
@@ -215,6 +215,7 @@
 			irq_set_chained_handler(cascade_virq,
 						hlwd_pic_irq_cascade);
 			hlwd_irq_host = host;
+			of_node_put(np);
 			break;
 		}
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/embedded6xx/wii.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/embedded6xx/wii.c
@@ -89,8 +89,8 @@
 
 	hw_regs = ioremap(res.start, resource_size(&res));
 	if (hw_regs) {
-		pr_info("%s at 0x%08x mapped to 0x%p\n", name,
-			res.start, hw_regs);
+		pr_info("%s at 0x%pa mapped to 0x%p\n", name,
+			&res.start, hw_regs);
 	}
 
 out_put:
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/maple/setup.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/maple/setup.c
@@ -294,23 +294,6 @@
 	return 1;
 }
 
-define_machine(maple) {
-	.name			= "Maple",
-	.probe			= maple_probe,
-	.setup_arch		= maple_setup_arch,
-	.init_IRQ		= maple_init_IRQ,
-	.pci_irq_fixup		= maple_pci_irq_fixup,
-	.pci_get_legacy_ide_irq	= maple_pci_get_legacy_ide_irq,
-	.restart		= maple_restart,
-	.halt			= maple_halt,
-       	.get_boot_time		= maple_get_boot_time,
-       	.set_rtc_time		= maple_set_rtc_time,
-       	.get_rtc_time		= maple_get_rtc_time,
-      	.calibrate_decr		= generic_calibrate_decr,
-	.progress		= maple_progress,
-	.power_save		= power4_idle,
-};
-
 #ifdef CONFIG_EDAC
 /*
  * Register a platform device for CPC925 memory controller on
@@ -367,3 +350,20 @@
 }
 machine_device_initcall(maple, maple_cpc925_edac_setup);
 #endif
+
+define_machine(maple) {
+	.name			= "Maple",
+	.probe			= maple_probe,
+	.setup_arch		= maple_setup_arch,
+	.init_IRQ		= maple_init_IRQ,
+	.pci_irq_fixup		= maple_pci_irq_fixup,
+	.pci_get_legacy_ide_irq	= maple_pci_get_legacy_ide_irq,
+	.restart		= maple_restart,
+	.halt			= maple_halt,
+	.get_boot_time		= maple_get_boot_time,
+	.set_rtc_time		= maple_set_rtc_time,
+	.get_rtc_time		= maple_get_rtc_time,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= maple_progress,
+	.power_save		= power4_idle,
+};
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powermac/cache.S
+++ linux-ein-5.4.0/arch/powerpc/platforms/powermac/cache.S
@@ -48,7 +48,7 @@
 
 	/* Stop DST streams */
 BEGIN_FTR_SECTION
-	DSSALL
+	PPC_DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
@@ -196,7 +196,7 @@
 	isync
 
 	/* Stop prefetch streams */
-	DSSALL
+	PPC_DSSALL
 	sync
 
 	/* Disable L2 prefetching */
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powermac/low_i2c.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powermac/low_i2c.c
@@ -582,6 +582,7 @@
 	bus->close = kw_i2c_close;
 	bus->xfer = kw_i2c_xfer;
 	mutex_init(&bus->mutex);
+	lockdep_register_key(&bus->lock_key);
 	lockdep_set_class(&bus->mutex, &bus->lock_key);
 	if (controller == busnode)
 		bus->flags = pmac_i2c_multibus;
@@ -811,6 +812,7 @@
 		bus->hostdata = bus + 1;
 		bus->xfer = pmu_i2c_xfer;
 		mutex_init(&bus->mutex);
+		lockdep_register_key(&bus->lock_key);
 		lockdep_set_class(&bus->mutex, &bus->lock_key);
 		bus->flags = pmac_i2c_multibus;
 		list_add(&bus->link, &pmac_i2c_busses);
@@ -934,6 +936,7 @@
 		bus->hostdata = bus + 1;
 		bus->xfer = smu_i2c_xfer;
 		mutex_init(&bus->mutex);
+		lockdep_register_key(&bus->lock_key);
 		lockdep_set_class(&bus->mutex, &bus->lock_key);
 		bus->flags = 0;
 		list_add(&bus->link, &pmac_i2c_busses);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powermac/sleep.S
+++ linux-ein-5.4.0/arch/powerpc/platforms/powermac/sleep.S
@@ -293,14 +293,7 @@
 	 * we do any r1 memory access as we are not sure they
 	 * are in a sane state above the first 256Mb region
 	 */
-	li	r0,16		/* load up segment register values */
-	mtctr	r0		/* for context 0 */
-	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,0x111	/* increment VSID */
-	addis	r4,r4,0x1000	/* address of next segment */
-	bdnz	3b
+	bl	load_segment_registers
 	sync
 	isync
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powermac/smp.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powermac/smp.c
@@ -660,13 +660,13 @@
 
 #endif /* !CONFIG_PPC64 */
 
-/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */
-volatile static long int core99_l2_cache;
-volatile static long int core99_l3_cache;
-
 static void core99_init_caches(int cpu)
 {
 #ifndef CONFIG_PPC64
+	/* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */
+	static long int core99_l2_cache;
+	static long int core99_l3_cache;
+
 	if (!cpu_has_feature(CPU_FTR_L2CR))
 		return;
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/Makefile
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/Makefile
@@ -20,3 +20,4 @@
 obj-$(CONFIG_PPC_VAS)	+= vas.o vas-window.o vas-debug.o
 obj-$(CONFIG_OCXL_BASE)	+= ocxl.o
 obj-$(CONFIG_SCOM_DEBUGFS) += opal-xscom.o
+obj-$(CONFIG_PPC_SECURE_BOOT) += opal-secvar.o
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/memtrace.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/memtrace.c
@@ -30,6 +30,7 @@
 	char name[16];
 };
 
+static DEFINE_MUTEX(memtrace_mutex);
 static u64 memtrace_size;
 
 static struct memtrace_entry *memtrace_array;
@@ -67,6 +68,23 @@
 	return 0;
 }
 
+static void memtrace_clear_range(unsigned long start_pfn,
+				 unsigned long nr_pages)
+{
+	unsigned long pfn;
+
+	/*
+	 * As pages are offline, we cannot trust the memmap anymore. As HIGHMEM
+	 * does not apply, avoid passing around "struct page" and use
+	 * clear_page() instead directly.
+	 */
+	for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) {
+		if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
+			cond_resched();
+		clear_page(__va(PFN_PHYS(pfn)));
+	}
+}
+
 /* called with device_hotplug_lock held */
 static bool memtrace_offline_pages(u32 nid, u64 start_pfn, u64 nr_pages)
 {
@@ -112,6 +130,11 @@
 	for (base_pfn = end_pfn; base_pfn > start_pfn; base_pfn -= nr_pages) {
 		if (memtrace_offline_pages(nid, base_pfn, nr_pages) == true) {
 			/*
+			 * Clear the range while we still have a linear
+			 * mapping.
+			 */
+			memtrace_clear_range(base_pfn, nr_pages);
+			/*
 			 * Remove memory in memory block size chunks so that
 			 * iomem resources are always split to the same size and
 			 * we never try to remove memory that spans two iomem
@@ -268,6 +291,7 @@
 
 static int memtrace_enable_set(void *data, u64 val)
 {
+	int rc = -EAGAIN;
 	u64 bytes;
 
 	/*
@@ -280,25 +304,31 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&memtrace_mutex);
+
 	/* Re-add/online previously removed/offlined memory */
 	if (memtrace_size) {
 		if (memtrace_online())
-			return -EAGAIN;
+			goto out_unlock;
 	}
 
-	if (!val)
-		return 0;
+	if (!val) {
+		rc = 0;
+		goto out_unlock;
+	}
 
 	/* Offline and remove memory */
 	if (memtrace_init_regions_runtime(val))
-		return -EINVAL;
+		goto out_unlock;
 
 	if (memtrace_init_debugfs())
-		return -EINVAL;
+		goto out_unlock;
 
 	memtrace_size = val;
-
-	return 0;
+	rc = 0;
+out_unlock:
+	mutex_unlock(&memtrace_mutex);
+	return rc;
 }
 
 static int memtrace_enable_get(void *data, u64 *val)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/npu-dma.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/npu-dma.c
@@ -384,7 +384,8 @@
 	for (i = 0; i < npucomp->pe_num; ++i) {
 		struct pnv_ioda_pe *pe = npucomp->pe[i];
 
-		if (!pe->table_group.ops->take_ownership)
+		if (!pe->table_group.ops ||
+		    !pe->table_group.ops->take_ownership)
 			continue;
 		pe->table_group.ops->take_ownership(&pe->table_group);
 	}
@@ -400,7 +401,8 @@
 	for (i = 0; i < npucomp->pe_num; ++i) {
 		struct pnv_ioda_pe *pe = npucomp->pe[i];
 
-		if (!pe->table_group.ops->release_ownership)
+		if (!pe->table_group.ops ||
+		    !pe->table_group.ops->release_ownership)
 			continue;
 		pe->table_group.ops->release_ownership(&pe->table_group);
 	}
@@ -560,6 +562,11 @@
 		return -ENODEV;
 
 	hose = pci_bus_to_host(npdev->bus);
+	if (hose->npu == NULL) {
+		dev_info_once(&npdev->dev, "Nvlink1 does not support contexts");
+		return 0;
+	}
+
 	nphb = hose->private_data;
 
 	dev_dbg(&gpdev->dev, "Map LPAR opalid=%llu lparid=%u\n",
@@ -607,6 +614,11 @@
 		return -ENODEV;
 
 	hose = pci_bus_to_host(npdev->bus);
+	if (hose->npu == NULL) {
+		dev_info_once(&npdev->dev, "Nvlink1 does not support contexts");
+		return 0;
+	}
+
 	nphb = hose->private_data;
 
 	dev_dbg(&gpdev->dev, "destroy context opalid=%llu\n",
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-call.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-call.c
@@ -290,3 +290,6 @@
 OPAL_CALL(opal_mpipl_update,			OPAL_MPIPL_UPDATE);
 OPAL_CALL(opal_mpipl_register_tag,		OPAL_MPIPL_REGISTER_TAG);
 OPAL_CALL(opal_mpipl_query_tag,			OPAL_MPIPL_QUERY_TAG);
+OPAL_CALL(opal_secvar_get,			OPAL_SECVAR_GET);
+OPAL_CALL(opal_secvar_get_next,			OPAL_SECVAR_GET_NEXT);
+OPAL_CALL(opal_secvar_enqueue_update,		OPAL_SECVAR_ENQUEUE_UPDATE);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-dump.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-dump.c
@@ -318,15 +318,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;
 
@@ -346,21 +345,39 @@
 	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)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-elog.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-elog.c
@@ -179,14 +179,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;
 
@@ -219,18 +219,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)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-fadump.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-fadump.c
@@ -60,7 +60,7 @@
 	addr = be64_to_cpu(addr);
 	pr_debug("Kernel metadata addr: %llx\n", addr);
 	opal_fdm_active = (void *)addr;
-	if (opal_fdm_active->registered_regions == 0)
+	if (be16_to_cpu(opal_fdm_active->registered_regions) == 0)
 		return;
 
 	ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_BOOT_MEM, &addr);
@@ -95,17 +95,17 @@
 static void opal_fadump_update_config(struct fw_dump *fadump_conf,
 				      const struct opal_fadump_mem_struct *fdm)
 {
-	pr_debug("Boot memory regions count: %d\n", fdm->region_cnt);
+	pr_debug("Boot memory regions count: %d\n", be16_to_cpu(fdm->region_cnt));
 
 	/*
 	 * The destination address of the first boot memory region is the
 	 * destination address of boot memory regions.
 	 */
-	fadump_conf->boot_mem_dest_addr = fdm->rgn[0].dest;
+	fadump_conf->boot_mem_dest_addr = be64_to_cpu(fdm->rgn[0].dest);
 	pr_debug("Destination address of boot memory regions: %#016llx\n",
 		 fadump_conf->boot_mem_dest_addr);
 
-	fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr;
+	fadump_conf->fadumphdr_addr = be64_to_cpu(fdm->fadumphdr_addr);
 }
 
 /*
@@ -126,9 +126,9 @@
 	fadump_conf->boot_memory_size = 0;
 
 	pr_debug("Boot memory regions:\n");
-	for (i = 0; i < fdm->region_cnt; i++) {
-		base = fdm->rgn[i].src;
-		size = fdm->rgn[i].size;
+	for (i = 0; i < be16_to_cpu(fdm->region_cnt); i++) {
+		base = be64_to_cpu(fdm->rgn[i].src);
+		size = be64_to_cpu(fdm->rgn[i].size);
 		pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
 
 		fadump_conf->boot_mem_addr[i] = base;
@@ -143,7 +143,7 @@
 	 * Start address of reserve dump area (permanent reservation) for
 	 * re-registering FADump after dump capture.
 	 */
-	fadump_conf->reserve_dump_area_start = fdm->rgn[0].dest;
+	fadump_conf->reserve_dump_area_start = be64_to_cpu(fdm->rgn[0].dest);
 
 	/*
 	 * Rarely, but it can so happen that system crashes before all
@@ -155,13 +155,14 @@
 	 * Hope the memory that could not be preserved only has pages
 	 * that are usually filtered out while saving the vmcore.
 	 */
-	if (fdm->region_cnt > fdm->registered_regions) {
+	if (be16_to_cpu(fdm->region_cnt) > be16_to_cpu(fdm->registered_regions)) {
 		pr_warn("Not all memory regions were saved!!!\n");
 		pr_warn("  Unsaved memory regions:\n");
-		i = fdm->registered_regions;
-		while (i < fdm->region_cnt) {
+		i = be16_to_cpu(fdm->registered_regions);
+		while (i < be16_to_cpu(fdm->region_cnt)) {
 			pr_warn("\t[%03d] base: 0x%llx, size: 0x%llx\n",
-				i, fdm->rgn[i].src, fdm->rgn[i].size);
+				i, be64_to_cpu(fdm->rgn[i].src),
+				be64_to_cpu(fdm->rgn[i].size));
 			i++;
 		}
 
@@ -170,7 +171,7 @@
 	}
 
 	fadump_conf->boot_mem_top = (fadump_conf->boot_memory_size + hole_size);
-	fadump_conf->boot_mem_regs_cnt = fdm->region_cnt;
+	fadump_conf->boot_mem_regs_cnt = be16_to_cpu(fdm->region_cnt);
 	opal_fadump_update_config(fadump_conf, fdm);
 }
 
@@ -178,35 +179,38 @@
 static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
 {
 	fdm->version = OPAL_FADUMP_VERSION;
-	fdm->region_cnt = 0;
-	fdm->registered_regions = 0;
-	fdm->fadumphdr_addr = 0;
+	fdm->region_cnt = cpu_to_be16(0);
+	fdm->registered_regions = cpu_to_be16(0);
+	fdm->fadumphdr_addr = cpu_to_be64(0);
 }
 
 static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
 {
 	u64 addr = fadump_conf->reserve_dump_area_start;
+	u16 reg_cnt;
 	int i;
 
 	opal_fdm = __va(fadump_conf->kernel_metadata);
 	opal_fadump_init_metadata(opal_fdm);
 
 	/* Boot memory regions */
+	reg_cnt = be16_to_cpu(opal_fdm->region_cnt);
 	for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
-		opal_fdm->rgn[i].src	= fadump_conf->boot_mem_addr[i];
-		opal_fdm->rgn[i].dest	= addr;
-		opal_fdm->rgn[i].size	= fadump_conf->boot_mem_sz[i];
+		opal_fdm->rgn[i].src	= cpu_to_be64(fadump_conf->boot_mem_addr[i]);
+		opal_fdm->rgn[i].dest	= cpu_to_be64(addr);
+		opal_fdm->rgn[i].size	= cpu_to_be64(fadump_conf->boot_mem_sz[i]);
 
-		opal_fdm->region_cnt++;
+		reg_cnt++;
 		addr += fadump_conf->boot_mem_sz[i];
 	}
+	opal_fdm->region_cnt = cpu_to_be16(reg_cnt);
 
 	/*
 	 * Kernel metadata is passed to f/w and retrieved in capture kerenl.
 	 * So, use it to save fadump header address instead of calculating it.
 	 */
-	opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
-				    fadump_conf->boot_memory_size);
+	opal_fdm->fadumphdr_addr = cpu_to_be64(be64_to_cpu(opal_fdm->rgn[0].dest) +
+					       fadump_conf->boot_memory_size);
 
 	opal_fadump_update_config(fadump_conf, opal_fdm);
 
@@ -269,18 +273,21 @@
 static int opal_fadump_register(struct fw_dump *fadump_conf)
 {
 	s64 rc = OPAL_PARAMETER;
+	u16 registered_regs;
 	int i, err = -EIO;
 
-	for (i = 0; i < opal_fdm->region_cnt; i++) {
+	registered_regs = be16_to_cpu(opal_fdm->registered_regions);
+	for (i = 0; i < be16_to_cpu(opal_fdm->region_cnt); i++) {
 		rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE,
-				       opal_fdm->rgn[i].src,
-				       opal_fdm->rgn[i].dest,
-				       opal_fdm->rgn[i].size);
+				       be64_to_cpu(opal_fdm->rgn[i].src),
+				       be64_to_cpu(opal_fdm->rgn[i].dest),
+				       be64_to_cpu(opal_fdm->rgn[i].size));
 		if (rc != OPAL_SUCCESS)
 			break;
 
-		opal_fdm->registered_regions++;
+		registered_regs++;
 	}
+	opal_fdm->registered_regions = cpu_to_be16(registered_regs);
 
 	switch (rc) {
 	case OPAL_SUCCESS:
@@ -291,7 +298,8 @@
 	case OPAL_RESOURCE:
 		/* If MAX regions limit in f/w is hit, warn and proceed. */
 		pr_warn("%d regions could not be registered for MPIPL as MAX limit is reached!\n",
-			(opal_fdm->region_cnt - opal_fdm->registered_regions));
+			(be16_to_cpu(opal_fdm->region_cnt) -
+			 be16_to_cpu(opal_fdm->registered_regions)));
 		fadump_conf->dump_registered = 1;
 		err = 0;
 		break;
@@ -312,7 +320,7 @@
 	 * If some regions were registered before OPAL_MPIPL_ADD_RANGE
 	 * OPAL call failed, unregister all regions.
 	 */
-	if ((err < 0) && (opal_fdm->registered_regions > 0))
+	if ((err < 0) && (be16_to_cpu(opal_fdm->registered_regions) > 0))
 		opal_fadump_unregister(fadump_conf);
 
 	return err;
@@ -328,7 +336,7 @@
 		return -EIO;
 	}
 
-	opal_fdm->registered_regions = 0;
+	opal_fdm->registered_regions = cpu_to_be16(0);
 	fadump_conf->dump_registered = 0;
 	return 0;
 }
@@ -563,19 +571,20 @@
 	else
 		fdm_ptr = opal_fdm;
 
-	for (i = 0; i < fdm_ptr->region_cnt; i++) {
+	for (i = 0; i < be16_to_cpu(fdm_ptr->region_cnt); i++) {
 		/*
 		 * Only regions that are registered for MPIPL
 		 * would have dump data.
 		 */
 		if ((fadump_conf->dump_active) &&
-		    (i < fdm_ptr->registered_regions))
-			dumped_bytes = fdm_ptr->rgn[i].size;
+		    (i < be16_to_cpu(fdm_ptr->registered_regions)))
+			dumped_bytes = be64_to_cpu(fdm_ptr->rgn[i].size);
 
 		seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
-			   fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
+			   be64_to_cpu(fdm_ptr->rgn[i].src),
+			   be64_to_cpu(fdm_ptr->rgn[i].dest));
 		seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
-			   fdm_ptr->rgn[i].size, dumped_bytes);
+			   be64_to_cpu(fdm_ptr->rgn[i].size), dumped_bytes);
 	}
 
 	/* Dump is active. Show reserved area start address. */
@@ -624,6 +633,7 @@
 {
 	const __be32 *prop;
 	unsigned long dn;
+	__be64 be_addr;
 	u64 addr = 0;
 	int i, len;
 	s64 ret;
@@ -680,13 +690,13 @@
 	if (!prop)
 		return;
 
-	ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
-	if ((ret != OPAL_SUCCESS) || !addr) {
+	ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &be_addr);
+	if ((ret != OPAL_SUCCESS) || !be_addr) {
 		pr_err("Failed to get Kernel metadata (%lld)\n", ret);
 		return;
 	}
 
-	addr = be64_to_cpu(addr);
+	addr = be64_to_cpu(be_addr);
 	pr_debug("Kernel metadata addr: %llx\n", addr);
 
 	opal_fdm_active = __va(addr);
@@ -697,14 +707,14 @@
 	}
 
 	/* Kernel regions not registered with f/w for MPIPL */
-	if (opal_fdm_active->registered_regions == 0) {
+	if (be16_to_cpu(opal_fdm_active->registered_regions) == 0) {
 		opal_fdm_active = NULL;
 		return;
 	}
 
-	ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr);
-	if (addr) {
-		addr = be64_to_cpu(addr);
+	ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &be_addr);
+	if (be_addr) {
+		addr = be64_to_cpu(be_addr);
 		pr_debug("CPU metadata addr: %llx\n", addr);
 		opal_cpu_metadata = __va(addr);
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-fadump.h
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-fadump.h
@@ -31,14 +31,14 @@
  * OPAL FADump kernel metadata
  *
  * The address of this structure will be registered with f/w for retrieving
- * and processing during crash dump.
+ * in the capture kernel to process the crash dump.
  */
 struct opal_fadump_mem_struct {
 	u8	version;
 	u8	reserved[3];
-	u16	region_cnt;		/* number of regions */
-	u16	registered_regions;	/* Regions registered for MPIPL */
-	u64	fadumphdr_addr;
+	__be16	region_cnt;		/* number of regions */
+	__be16	registered_regions;	/* Regions registered for MPIPL */
+	__be64	fadumphdr_addr;
 	struct opal_mpipl_region	rgn[FADUMP_MAX_MEM_REGS];
 } __packed;
 
@@ -135,7 +135,7 @@
 	for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) {
 		reg_entry = (struct hdat_fadump_reg_entry *)bufp;
 		val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) :
-		       reg_entry->reg_val);
+		       (u64)(reg_entry->reg_val));
 		opal_fadump_set_regval_regnum(regs,
 					      be32_to_cpu(reg_entry->reg_type),
 					      be32_to_cpu(reg_entry->reg_num),
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-imc.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-imc.c
@@ -59,10 +59,6 @@
 
 	imc_debugfs_parent = debugfs_create_dir("imc", powerpc_debugfs_root);
 
-	/*
-	 * Return here, either because 'imc' directory already exists,
-	 * Or failed to create a new one.
-	 */
 	if (!imc_debugfs_parent)
 		return;
 
@@ -135,7 +131,6 @@
 	}
 
 	pmu_ptr->imc_counter_mmaped = true;
-	export_imc_mode_and_cmd(node, pmu_ptr);
 	kfree(base_addr_arr);
 	kfree(chipid_arr);
 	return 0;
@@ -151,7 +146,7 @@
  *		    and domain as the inputs.
  * Allocates memory for the struct imc_pmu, sets up its domain, size and offsets
  */
-static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain)
+static struct imc_pmu *imc_pmu_create(struct device_node *parent, int pmu_index, int domain)
 {
 	int ret = 0;
 	struct imc_pmu *pmu_ptr;
@@ -159,27 +154,23 @@
 
 	/* Return for unknown domain */
 	if (domain < 0)
-		return -EINVAL;
+		return NULL;
 
 	/* memory for pmu */
 	pmu_ptr = kzalloc(sizeof(*pmu_ptr), GFP_KERNEL);
 	if (!pmu_ptr)
-		return -ENOMEM;
+		return NULL;
 
 	/* Set the domain */
 	pmu_ptr->domain = domain;
 
 	ret = of_property_read_u32(parent, "size", &pmu_ptr->counter_mem_size);
-	if (ret) {
-		ret = -EINVAL;
+	if (ret)
 		goto free_pmu;
-	}
 
 	if (!of_property_read_u32(parent, "offset", &offset)) {
-		if (imc_get_mem_addr_nest(parent, pmu_ptr, offset)) {
-			ret = -EINVAL;
+		if (imc_get_mem_addr_nest(parent, pmu_ptr, offset))
 			goto free_pmu;
-		}
 	}
 
 	/* Function to register IMC pmu */
@@ -190,14 +181,14 @@
 		if (pmu_ptr->domain == IMC_DOMAIN_NEST)
 			kfree(pmu_ptr->mem_info);
 		kfree(pmu_ptr);
-		return ret;
+		return NULL;
 	}
 
-	return 0;
+	return pmu_ptr;
 
 free_pmu:
 	kfree(pmu_ptr);
-	return ret;
+	return NULL;
 }
 
 static void disable_nest_pmu_counters(void)
@@ -254,6 +245,7 @@
 static int opal_imc_counters_probe(struct platform_device *pdev)
 {
 	struct device_node *imc_dev = pdev->dev.of_node;
+	struct imc_pmu *pmu;
 	int pmu_count = 0, domain;
 	bool core_imc_reg = false, thread_imc_reg = false;
 	u32 type;
@@ -269,6 +261,7 @@
 	}
 
 	for_each_compatible_node(imc_dev, NULL, IMC_DTB_UNIT_COMPAT) {
+		pmu = NULL;
 		if (of_property_read_u32(imc_dev, "type", &type)) {
 			pr_warn("IMC Device without type property\n");
 			continue;
@@ -285,7 +278,14 @@
 			domain = IMC_DOMAIN_THREAD;
 			break;
 		case IMC_TYPE_TRACE:
-			domain = IMC_DOMAIN_TRACE;
+			/*
+			 * FIXME. Using trace_imc events to monitor application
+			 * or KVM thread performance can cause a checkstop
+			 * (system crash).
+			 * Disable it for now.
+			 */
+			pr_info_once("IMC: disabling trace_imc PMU\n");
+			domain = -1;
 			break;
 		default:
 			pr_warn("IMC Unknown Device type \n");
@@ -293,9 +293,13 @@
 			break;
 		}
 
-		if (!imc_pmu_create(imc_dev, pmu_count, domain)) {
-			if (domain == IMC_DOMAIN_NEST)
+		pmu = imc_pmu_create(imc_dev, pmu_count, domain);
+		if (pmu != NULL) {
+			if (domain == IMC_DOMAIN_NEST) {
+				if (!imc_debugfs_parent)
+					export_imc_mode_and_cmd(imc_dev, pmu);
 				pmu_count++;
+			}
 			if (domain == IMC_DOMAIN_CORE)
 				core_imc_reg = true;
 			if (domain == IMC_DOMAIN_THREAD)
@@ -303,10 +307,6 @@
 		}
 	}
 
-	/* If none of the nest units are registered, remove debugfs interface */
-	if (pmu_count == 0)
-		debugfs_remove_recursive(imc_debugfs_parent);
-
 	/* If core imc is not registered, unregister thread-imc */
 	if (!core_imc_reg && thread_imc_reg)
 		unregister_thread_imc();
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-irqchip.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -278,6 +278,8 @@
 		else
 			name = kasprintf(GFP_KERNEL, "opal");
 
+		if (!name)
+			continue;
 		/* Install interrupt handler */
 		rc = request_irq(r->start, opal_interrupt, r->flags & IRQD_TRIGGER_MASK,
 				 name, NULL);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-lpc.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-lpc.c
@@ -396,6 +396,7 @@
 		if (!of_get_property(np, "primary", NULL))
 			continue;
 		opal_lpc_chip_id = of_get_ibm_chip_id(np);
+		of_node_put(np);
 		break;
 	}
 	if (opal_lpc_chip_id < 0)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-powercap.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-powercap.c
@@ -196,6 +196,12 @@
 
 		j = 0;
 		pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node);
+		if (!pcaps[i].pg.name) {
+			kfree(pcaps[i].pattrs);
+			kfree(pcaps[i].pg.attrs);
+			goto out_pcaps_pattrs;
+		}
+
 		if (has_min) {
 			powercap_add_attr(min, "powercap-min",
 					  &pcaps[i].pattrs[j]);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-prd.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-prd.c
@@ -372,6 +372,12 @@
 	.priority	= 0,
 };
 
+static struct notifier_block opal_prd_event_nb2 = {
+	.notifier_call	= opal_prd_msg_notifier,
+	.next		= NULL,
+	.priority	= 0,
+};
+
 static int opal_prd_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -393,9 +399,10 @@
 		return rc;
 	}
 
-	rc = opal_message_notifier_register(OPAL_MSG_PRD2, &opal_prd_event_nb);
+	rc = opal_message_notifier_register(OPAL_MSG_PRD2, &opal_prd_event_nb2);
 	if (rc) {
 		pr_err("Couldn't register PRD2 event notifier\n");
+		opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb);
 		return rc;
 	}
 
@@ -404,6 +411,8 @@
 		pr_err("failed to register miscdev\n");
 		opal_message_notifier_unregister(OPAL_MSG_PRD,
 				&opal_prd_event_nb);
+		opal_message_notifier_unregister(OPAL_MSG_PRD2,
+				&opal_prd_event_nb2);
 		return rc;
 	}
 
@@ -414,6 +423,7 @@
 {
 	misc_deregister(&opal_prd_dev);
 	opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb);
+	opal_message_notifier_unregister(OPAL_MSG_PRD2, &opal_prd_event_nb2);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-secvar.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PowerNV code for secure variables
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho
+ *         Nayna Jain
+ *
+ * APIs to access secure variables managed by OPAL.
+ */
+
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <asm/opal.h>
+#include <asm/secvar.h>
+#include <asm/secure_boot.h>
+
+static int opal_status_to_err(int rc)
+{
+	int err;
+
+	switch (rc) {
+	case OPAL_SUCCESS:
+		err = 0;
+		break;
+	case OPAL_UNSUPPORTED:
+		err = -ENXIO;
+		break;
+	case OPAL_PARAMETER:
+		err = -EINVAL;
+		break;
+	case OPAL_RESOURCE:
+		err = -ENOSPC;
+		break;
+	case OPAL_HARDWARE:
+		err = -EIO;
+		break;
+	case OPAL_NO_MEM:
+		err = -ENOMEM;
+		break;
+	case OPAL_EMPTY:
+		err = -ENOENT;
+		break;
+	case OPAL_PARTIAL:
+		err = -EFBIG;
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int opal_get_variable(const char *key, uint64_t ksize,
+			     u8 *data, uint64_t *dsize)
+{
+	int rc;
+
+	if (!key || !dsize)
+		return -EINVAL;
+
+	*dsize = cpu_to_be64(*dsize);
+
+	rc = opal_secvar_get(key, ksize, data, dsize);
+
+	*dsize = be64_to_cpu(*dsize);
+
+	return opal_status_to_err(rc);
+}
+
+static int opal_get_next_variable(const char *key, uint64_t *keylen,
+				  uint64_t keybufsize)
+{
+	int rc;
+
+	if (!key || !keylen)
+		return -EINVAL;
+
+	*keylen = cpu_to_be64(*keylen);
+
+	rc = opal_secvar_get_next(key, keylen, keybufsize);
+
+	*keylen = be64_to_cpu(*keylen);
+
+	return opal_status_to_err(rc);
+}
+
+static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
+			     uint64_t dsize)
+{
+	int rc;
+
+	if (!key || !data)
+		return -EINVAL;
+
+	rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
+
+	return opal_status_to_err(rc);
+}
+
+static const struct secvar_operations opal_secvar_ops = {
+	.get = opal_get_variable,
+	.get_next = opal_get_next_variable,
+	.set = opal_set_variable,
+};
+
+static int opal_secvar_probe(struct platform_device *pdev)
+{
+	if (!opal_check_token(OPAL_SECVAR_GET)
+			|| !opal_check_token(OPAL_SECVAR_GET_NEXT)
+			|| !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
+		pr_err("OPAL doesn't support secure variables\n");
+		return -ENODEV;
+	}
+
+	set_secvar_ops(&opal_secvar_ops);
+
+	return 0;
+}
+
+static const struct of_device_id opal_secvar_match[] = {
+	{ .compatible = "ibm,secvar-backend",},
+	{},
+};
+
+static struct platform_driver opal_secvar_driver = {
+	.driver = {
+		.name = "secvar",
+		.of_match_table = opal_secvar_match,
+	},
+};
+
+static int __init opal_secvar_init(void)
+{
+	return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
+}
+device_initcall(opal_secvar_init);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal-xscom.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -165,6 +165,11 @@
 	ent->chip = chip;
 	snprintf(ent->name, 16, "%08x", chip);
 	ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn);
+	if (!ent->path.data) {
+		kfree(ent);
+		return -ENOMEM;
+	}
+
 	ent->path.size = strlen((char *)ent->path.data);
 
 	dir = debugfs_create_dir(ent->name, root);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/opal.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/opal.c
@@ -776,6 +776,7 @@
 	kobj = kobject_create_and_add("exports", opal_kobj);
 	if (!kobj) {
 		pr_warn("kobject_create_and_add() of exports failed\n");
+		of_node_put(np);
 		return;
 	}
 
@@ -1002,6 +1003,9 @@
 	/* Initialise OPAL Power control interface */
 	opal_power_control_init();
 
+	/* Initialize OPAL secure variables */
+	opal_pdev_init("ibm,secvar-backend");
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/pci-ioda.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -188,7 +188,7 @@
 	unsigned int pe_num = pe->pe_number;
 
 	WARN_ON(pe->pdev);
-	WARN_ON(pe->npucomp); /* NPUs are not supposed to be freed */
+	WARN_ON(pe->npucomp); /* NPUs for nvlink are not supposed to be freed */
 	kfree(pe->npucomp);
 	memset(pe, 0, sizeof(struct pnv_ioda_pe));
 	clear_bit(pe_num, phb->ioda.pe_alloc);
@@ -777,6 +777,34 @@
 	return 0;
 }
 
+static void pnv_ioda_unset_peltv(struct pnv_phb *phb,
+				 struct pnv_ioda_pe *pe,
+				 struct pci_dev *parent)
+{
+	int64_t rc;
+
+	while (parent) {
+		struct pci_dn *pdn = pci_get_pdn(parent);
+
+		if (pdn && pdn->pe_number != IODA_INVALID_PE) {
+			rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number,
+						pe->pe_number,
+						OPAL_REMOVE_PE_FROM_DOMAIN);
+			/* XXX What to do in case of error ? */
+		}
+		parent = parent->bus->self;
+	}
+
+	opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
+				  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+
+	/* Disassociate PE in PELT */
+	rc = opal_pci_set_peltv(phb->opal_id, pe->pe_number,
+				pe->pe_number, OPAL_REMOVE_PE_FROM_DOMAIN);
+	if (rc)
+		pe_warn(pe, "OPAL error %lld remove self from PELTV\n", rc);
+}
+
 static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 {
 	struct pci_dev *parent;
@@ -827,25 +855,13 @@
 	for (rid = pe->rid; rid < rid_end; rid++)
 		phb->ioda.pe_rmap[rid] = IODA_INVALID_PE;
 
-	/* Release from all parents PELT-V */
-	while (parent) {
-		struct pci_dn *pdn = pci_get_pdn(parent);
-		if (pdn && pdn->pe_number != IODA_INVALID_PE) {
-			rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number,
-						pe->pe_number, OPAL_REMOVE_PE_FROM_DOMAIN);
-			/* XXX What to do in case of error ? */
-		}
-		parent = parent->bus->self;
-	}
-
-	opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
-				  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+	/*
+	 * Release from all parents PELT-V. NPUs don't have a PELTV
+	 * table
+	 */
+	if (phb->type != PNV_PHB_NPU_NVLINK && phb->type != PNV_PHB_NPU_OCAPI)
+		pnv_ioda_unset_peltv(phb, pe, parent);
 
-	/* Disassociate PE in PELT */
-	rc = opal_pci_set_peltv(phb->opal_id, pe->pe_number,
-				pe->pe_number, OPAL_REMOVE_PE_FROM_DOMAIN);
-	if (rc)
-		pe_warn(pe, "OPAL error %lld remove self from PELTV\n", rc);
 	rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid,
 			     bcomp, dcomp, fcomp, OPAL_UNMAP_PE);
 	if (rc)
@@ -1062,20 +1078,20 @@
 		return NULL;
 	}
 
-	/* NOTE: We get only one ref to the pci_dev for the pdn, not for the
-	 * pointer in the PE data structure, both should be destroyed at the
-	 * same time. However, this needs to be looked at more closely again
-	 * once we actually start removing things (Hotplug, SR-IOV, ...)
+	/* NOTE: We don't get a reference for the pointer in the PE
+	 * data structure, both the device and PE structures should be
+	 * destroyed at the same time. However, removing nvlink
+	 * devices will need some work.
 	 *
 	 * At some point we want to remove the PDN completely anyways
 	 */
-	pci_dev_get(dev);
 	pdn->pe_number = pe->pe_number;
 	pe->flags = PNV_IODA_PE_DEV;
 	pe->pdev = dev;
 	pe->pbus = NULL;
 	pe->mve_number = -1;
 	pe->rid = dev->bus->number << 8 | pdn->devfn;
+	pe->device_count++;
 
 	pe_info(pe, "Associated device to PE\n");
 
@@ -1084,13 +1100,13 @@
 		pnv_ioda_free_pe(pe);
 		pdn->pe_number = IODA_INVALID_PE;
 		pe->pdev = NULL;
-		pci_dev_put(dev);
 		return NULL;
 	}
 
 	/* Put PE to the list */
+	mutex_lock(&phb->ioda.pe_list_mutex);
 	list_add_tail(&pe->list, &phb->ioda.pe_list);
-
+	mutex_unlock(&phb->ioda.pe_list_mutex);
 	return pe;
 }
 
@@ -1206,6 +1222,14 @@
 	struct pnv_phb *phb = hose->private_data;
 
 	/*
+	 * Intentionally leak a reference on the npu device (for
+	 * nvlink only; this is not an opencapi path) to make sure it
+	 * never goes away, as it's been the case all along and some
+	 * work is needed otherwise.
+	 */
+	pci_dev_get(npu_pdev);
+
+	/*
 	 * 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
@@ -1228,11 +1252,11 @@
 			 */
 			dev_info(&npu_pdev->dev,
 				"Associating to existing PE %x\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->pe_number = pe_num;
 			phb->ioda.pe_rmap[rid] = pe->pe_number;
+			pe->device_count++;
 
 			/* Map the PE to this link */
 			rc = opal_pci_set_pe(phb->opal_id, pe_num, rid,
@@ -1268,8 +1292,6 @@
 {
 	struct pci_controller *hose;
 	struct pnv_phb *phb;
-	struct pci_bus *bus;
-	struct pci_dev *pdev;
 	struct pnv_ioda_pe *pe;
 
 	list_for_each_entry(hose, &hose_list, list_node) {
@@ -1281,11 +1303,6 @@
 			if (phb->model == PNV_PHB_MODEL_NPU2)
 				WARN_ON_ONCE(pnv_npu2_init(hose));
 		}
-		if (phb->type == PNV_PHB_NPU_OCAPI) {
-			bus = hose->bus;
-			list_for_each_entry(pdev, &bus->devices, bus_list)
-				pnv_ioda_setup_dev_PE(pdev);
-		}
 	}
 	list_for_each_entry(hose, &hose_list, list_node) {
 		phb = hose->private_data;
@@ -1558,6 +1575,10 @@
 
 	/* Reserve PE for each VF */
 	for (vf_index = 0; vf_index < num_vfs; vf_index++) {
+		int vf_devfn = pci_iov_virtfn_devfn(pdev, vf_index);
+		int vf_bus = pci_iov_virtfn_bus(pdev, vf_index);
+		struct pci_dn *vf_pdn;
+
 		if (pdn->m64_single_mode)
 			pe_num = pdn->pe_num_map[vf_index];
 		else
@@ -1570,13 +1591,11 @@
 		pe->pbus = NULL;
 		pe->parent_dev = pdev;
 		pe->mve_number = -1;
-		pe->rid = (pci_iov_virtfn_bus(pdev, vf_index) << 8) |
-			   pci_iov_virtfn_devfn(pdev, vf_index);
+		pe->rid = (vf_bus << 8) | vf_devfn;
 
 		pe_info(pe, "VF %04d:%02d:%02d.%d associated with PE#%x\n",
 			hose->global_number, pdev->bus->number,
-			PCI_SLOT(pci_iov_virtfn_devfn(pdev, vf_index)),
-			PCI_FUNC(pci_iov_virtfn_devfn(pdev, vf_index)), pe_num);
+			PCI_SLOT(vf_devfn), PCI_FUNC(vf_devfn), pe_num);
 
 		if (pnv_ioda_configure_pe(phb, pe)) {
 			/* XXX What do we do here ? */
@@ -1590,6 +1609,15 @@
 		list_add_tail(&pe->list, &phb->ioda.pe_list);
 		mutex_unlock(&phb->ioda.pe_list_mutex);
 
+		/* associate this pe to it's pdn */
+		list_for_each_entry(vf_pdn, &pdn->parent->child_list, list) {
+			if (vf_pdn->busno == vf_bus &&
+			    vf_pdn->devfn == vf_devfn) {
+				vf_pdn->pe_number = pe_num;
+				break;
+			}
+		}
+
 		pnv_pci_ioda2_setup_dma_pe(phb, pe);
 #ifdef CONFIG_IOMMU_API
 		iommu_register_group(&pe->table_group,
@@ -2889,9 +2917,6 @@
 	struct pci_dn *pdn;
 	int mul, total_vfs;
 
-	if (!pdev->is_physfn || pci_dev_is_added(pdev))
-		return;
-
 	pdn = pci_get_pdn(pdev);
 	pdn->vfs_expanded = 0;
 	pdn->m64_single_mode = false;
@@ -2966,6 +2991,30 @@
 		res->end = res->start - 1;
 	}
 }
+
+static void pnv_pci_ioda_fixup_iov(struct pci_dev *pdev)
+{
+	if (WARN_ON(pci_dev_is_added(pdev)))
+		return;
+
+	if (pdev->is_virtfn) {
+		struct pnv_ioda_pe *pe = pnv_ioda_get_pe(pdev);
+
+		/*
+		 * VF PEs are single-device PEs so their pdev pointer needs to
+		 * be set. The pdev doesn't exist when the PE is allocated (in
+		 * (pcibios_sriov_enable()) so we fix it up here.
+		 */
+		pe->pdev = pdev;
+		WARN_ON(!(pe->flags & PNV_IODA_PE_VF));
+	} else if (pdev->is_physfn) {
+		/*
+		 * For PFs adjust their allocated IOV resources to match what
+		 * the PHB can support using it's M64 BAR table.
+		 */
+		pnv_pci_ioda_fixup_iov_resources(pdev);
+	}
+}
 #endif /* CONFIG_PCI_IOV */
 
 static void pnv_ioda_setup_pe_res(struct pnv_ioda_pe *pe,
@@ -2976,7 +3025,8 @@
 	int index;
 	int64_t rc;
 
-	if (!res || !res->flags || res->start > res->end)
+	if (!res || !res->flags || res->start > res->end ||
+	    res->flags & IORESOURCE_UNSET)
 		return;
 
 	if (res->flags & IORESOURCE_IO) {
@@ -3383,6 +3433,28 @@
 	return true;
 }
 
+static bool pnv_ocapi_enable_device_hook(struct pci_dev *dev)
+{
+	struct pci_controller *hose = pci_bus_to_host(dev->bus);
+	struct pnv_phb *phb = hose->private_data;
+	struct pci_dn *pdn;
+	struct pnv_ioda_pe *pe;
+
+	if (!phb->initialized)
+		return true;
+
+	pdn = pci_get_pdn(dev);
+	if (!pdn)
+		return false;
+
+	if (pdn->pe_number == IODA_INVALID_PE) {
+		pe = pnv_ioda_setup_dev_PE(dev);
+		if (!pe)
+			return false;
+	}
+	return true;
+}
+
 static long pnv_pci_ioda1_unset_window(struct iommu_table_group *table_group,
 				       int num)
 {
@@ -3512,7 +3584,10 @@
 	struct pnv_phb *phb = pe->phb;
 	struct pnv_ioda_pe *slave, *tmp;
 
+	mutex_lock(&phb->ioda.pe_list_mutex);
 	list_del(&pe->list);
+	mutex_unlock(&phb->ioda.pe_list_mutex);
+
 	switch (phb->type) {
 	case PNV_PHB_IODA1:
 		pnv_pci_ioda1_release_pe_dma(pe);
@@ -3520,6 +3595,8 @@
 	case PNV_PHB_IODA2:
 		pnv_pci_ioda2_release_pe_dma(pe);
 		break;
+	case PNV_PHB_NPU_OCAPI:
+		break;
 	default:
 		WARN_ON(1);
 	}
@@ -3620,7 +3697,8 @@
 };
 
 static const struct pci_controller_ops pnv_npu_ocapi_ioda_controller_ops = {
-	.enable_device_hook	= pnv_pci_enable_device_hook,
+	.enable_device_hook	= pnv_ocapi_enable_device_hook,
+	.release_device		= pnv_pci_release_device,
 	.window_alignment	= pnv_pci_window_alignment,
 	.reset_secondary_bus	= pnv_pci_reset_secondary_bus,
 	.shutdown		= pnv_pci_ioda_shutdown,
@@ -3862,7 +3940,7 @@
 	ppc_md.pcibios_default_alignment = pnv_pci_default_alignment;
 
 #ifdef CONFIG_PCI_IOV
-	ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
+	ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov;
 	ppc_md.pcibios_iov_resource_alignment = pnv_pci_iov_resource_alignment;
 	ppc_md.pcibios_sriov_enable = pnv_pcibios_sriov_enable;
 	ppc_md.pcibios_sriov_disable = pnv_pcibios_sriov_disable;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/pci.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/pci.c
@@ -38,7 +38,7 @@
 
 int pnv_pci_get_slot_id(struct device_node *np, uint64_t *id)
 {
-	struct device_node *parent = np;
+	struct device_node *node = np;
 	u32 bdfn;
 	u64 phbid;
 	int ret;
@@ -48,25 +48,29 @@
 		return -ENXIO;
 
 	bdfn = ((bdfn & 0x00ffff00) >> 8);
-	while ((parent = of_get_parent(parent))) {
-		if (!PCI_DN(parent)) {
-			of_node_put(parent);
+	for (node = np; node; node = of_get_parent(node)) {
+		if (!PCI_DN(node)) {
+			of_node_put(node);
 			break;
 		}
 
-		if (!of_device_is_compatible(parent, "ibm,ioda2-phb") &&
-		    !of_device_is_compatible(parent, "ibm,ioda3-phb")) {
-			of_node_put(parent);
+		if (!of_device_is_compatible(node, "ibm,ioda2-phb") &&
+		    !of_device_is_compatible(node, "ibm,ioda3-phb") &&
+		    !of_device_is_compatible(node, "ibm,ioda2-npu2-opencapi-phb")) {
+			of_node_put(node);
 			continue;
 		}
 
-		ret = of_property_read_u64(parent, "ibm,opal-phbid", &phbid);
+		ret = of_property_read_u64(node, "ibm,opal-phbid", &phbid);
 		if (ret) {
-			of_node_put(parent);
+			of_node_put(node);
 			return -ENXIO;
 		}
 
-		*id = PCI_SLOT_ID(phbid, bdfn);
+		if (of_device_is_compatible(node, "ibm,ioda2-npu2-opencapi-phb"))
+			*id = PCI_PHB_SLOT_ID(phbid);
+		else
+			*id = PCI_SLOT_ID(phbid, bdfn);
 		return 0;
 	}
 
@@ -814,24 +818,6 @@
 {
 	struct pci_controller *hose = pci_bus_to_host(pdev->bus);
 	struct pnv_phb *phb = hose->private_data;
-#ifdef CONFIG_PCI_IOV
-	struct pnv_ioda_pe *pe;
-	struct pci_dn *pdn;
-
-	/* Fix the VF pdn PE number */
-	if (pdev->is_virtfn) {
-		pdn = pci_get_pdn(pdev);
-		WARN_ON(pdn->pe_number != IODA_INVALID_PE);
-		list_for_each_entry(pe, &phb->ioda.pe_list, list) {
-			if (pe->rid == ((pdev->bus->number << 8) |
-			    (pdev->devfn & 0xff))) {
-				pdn->pe_number = pe->pe_number;
-				pe->pdev = pdev;
-				break;
-			}
-		}
-	}
-#endif /* CONFIG_PCI_IOV */
 
 	if (phb && phb->dma_dev_setup)
 		phb->dma_dev_setup(phb, pdev);
@@ -945,6 +931,23 @@
 	if (!firmware_has_feature(FW_FEATURE_OPAL))
 		return;
 
+#ifdef CONFIG_PCIEPORTBUS
+	/*
+	 * On PowerNV PCIe devices are (currently) managed in cooperation
+	 * with firmware. This isn't *strictly* required, but there's enough
+	 * assumptions baked into both firmware and the platform code that
+	 * it's unwise to allow the portbus services to be used.
+	 *
+	 * We need to fix this eventually, but for now set this flag to disable
+	 * the portbus driver. The AER service isn't required since that AER
+	 * events are handled via EEH. The pciehp hotplug driver can't work
+	 * without kernel changes (and portbus binding breaks pnv_php). The
+	 * other services also require some thinking about how we're going
+	 * to integrate them.
+	 */
+	pcie_ports_disabled = true;
+#endif
+
 	/* Look for IODA IO-Hubs. */
 	for_each_compatible_node(np, NULL, "ibm,ioda-hub") {
 		pnv_pci_init_ioda_hub(np);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/powernv.h
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/powernv.h
@@ -35,4 +35,6 @@
 u32 memcons_get_size(struct memcons *mc);
 struct memcons *memcons_init(struct device_node *node, const char *mc_prop_name);
 
+void pnv_rng_init(void);
+
 #endif /* _POWERNV_H */
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/rng.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/rng.c
@@ -17,6 +17,7 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
+#include "powernv.h"
 
 #define DARN_ERR 0xFFFFFFFFFFFFFFFFul
 
@@ -28,7 +29,6 @@
 
 static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 
-
 int powernv_hwrng_present(void)
 {
 	struct powernv_rng *rng;
@@ -43,7 +43,11 @@
 	unsigned long parity;
 
 	/* Calculate the parity of the value */
-	asm ("popcntd %0,%1" : "=r" (parity) : "r" (val));
+	asm (".machine push;   \
+	      .machine power7; \
+	      popcntd %0,%1;   \
+	      .machine pop;"
+	     : "=r" (parity) : "r" (val));
 
 	/* xor our value with the previous mask */
 	val ^= rng->mask;
@@ -59,6 +63,8 @@
 	struct powernv_rng *rng;
 
 	rng = raw_cpu_read(powernv_rng);
+	if (!rng)
+		return 0;
 
 	*v = rng_whiten(rng, __raw_rm_readq(rng->regs_real));
 
@@ -94,9 +100,6 @@
 			return 0;
 		}
 	}
-
-	pr_warn("Unable to use DARN for get_random_seed()\n");
-
 	return -EIO;
 }
 
@@ -159,32 +162,59 @@
 
 	rng_init_per_cpu(rng, dn);
 
-	pr_info_once("Registering arch random hook.\n");
-
 	ppc_md.get_random_seed = powernv_get_random_long;
 
 	return 0;
 }
 
-static __init int rng_init(void)
+static int __init pnv_get_random_long_early(unsigned long *v)
 {
 	struct device_node *dn;
-	int rc;
 
-	for_each_compatible_node(dn, NULL, "ibm,power-rng") {
-		rc = rng_create(dn);
-		if (rc) {
-			pr_err("Failed creating rng for %pOF (%d).\n",
-				dn, rc);
-			continue;
-		}
+	if (!slab_is_available())
+		return 0;
 
-		/* Create devices for hwrng driver */
-		of_platform_device_create(dn, NULL, NULL);
-	}
+	if (cmpxchg(&ppc_md.get_random_seed, pnv_get_random_long_early,
+		    NULL) != pnv_get_random_long_early)
+		return 0;
 
-	initialise_darn();
+	for_each_compatible_node(dn, NULL, "ibm,power-rng")
+		rng_create(dn);
+
+	if (!ppc_md.get_random_seed)
+		return 0;
+	return ppc_md.get_random_seed(v);
+}
+
+void __init pnv_rng_init(void)
+{
+	struct device_node *dn;
+
+	/* Prefer darn over the rest. */
+	if (!initialise_darn())
+		return;
+
+	dn = of_find_compatible_node(NULL, NULL, "ibm,power-rng");
+	if (dn)
+		ppc_md.get_random_seed = pnv_get_random_long_early;
+
+	of_node_put(dn);
+}
+
+static int __init pnv_rng_late_init(void)
+{
+	struct device_node *dn;
+	unsigned long v;
+
+	/* In case it wasn't called during init for some other reason. */
+	if (ppc_md.get_random_seed == pnv_get_random_long_early)
+		pnv_get_random_long_early(&v);
+
+	if (ppc_md.get_random_seed == powernv_get_random_long) {
+		for_each_compatible_node(dn, NULL, "ibm,power-rng")
+			of_platform_device_create(dn, NULL, NULL);
+	}
 
 	return 0;
 }
-machine_subsys_initcall(powernv, rng_init);
+machine_subsys_initcall(powernv, pnv_rng_late_init);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/setup.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/setup.c
@@ -122,12 +122,29 @@
 			type = L1D_FLUSH_ORI;
 	}
 
+	/*
+	 * If we are non-Power9 bare metal, we don't need to flush on kernel
+	 * entry or after user access: they fix a P9 specific vulnerability.
+	 */
+	if (!pvr_version_is(PVR_POWER9)) {
+		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)
@@ -151,6 +168,8 @@
 	powersave_nap = 1;
 
 	/* XXX PMCS */
+
+	pnv_rng_init();
 }
 
 static void __init pnv_init(void)
@@ -169,11 +188,16 @@
 		add_preferred_console("hvc", 0, NULL);
 
 	if (!radix_enabled()) {
+		size_t size = sizeof(struct slb_entry) * mmu_slb_size;
 		int i;
 
 		/* Allocate per cpu area to save old slb contents during MCE */
-		for_each_possible_cpu(i)
-			paca_ptrs[i]->mce_faulty_slbs = memblock_alloc_node(mmu_slb_size, __alignof__(*paca_ptrs[i]->mce_faulty_slbs), cpu_to_node(i));
+		for_each_possible_cpu(i) {
+			paca_ptrs[i]->mce_faulty_slbs =
+					memblock_alloc_node(size,
+						__alignof__(struct slb_entry),
+						cpu_to_node(i));
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/smp.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/smp.c
@@ -43,7 +43,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)
@@ -167,7 +167,6 @@
 	/* Standard hot unplug procedure */
 
 	idle_task_exit();
-	current->active_mm = NULL; /* for sanity */
 	cpu = smp_processor_id();
 	DBG("CPU%d offline\n", cpu);
 	generic_set_cpu_dead(cpu);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/powernv/ultravisor.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/powernv/ultravisor.c
@@ -55,6 +55,7 @@
 		return -ENODEV;
 
 	uv_memcons = memcons_init(node, "memcons");
+	of_node_put(node);
 	if (!uv_memcons)
 		return -ENOENT;
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/ps3/mm.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/ps3/mm.c
@@ -6,6 +6,7 @@
  *  Copyright 2006 Sony Corp.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/memblock.h>
@@ -200,13 +201,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;
 	}
 }
@@ -304,19 +306,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);
 }
 
@@ -1116,6 +1119,7 @@
 	enum ps3_dma_region_type region_type, void *addr, unsigned long len)
 {
 	unsigned long lpar_addr;
+	int result;
 
 	lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0;
 
@@ -1127,6 +1131,16 @@
 		r->offset -= map.r1.offset;
 	r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size);
 
+	dev->core.dma_mask = &r->dma_mask;
+
+	result = dma_set_mask_and_coherent(&dev->core, DMA_BIT_MASK(32));
+
+	if (result < 0) {
+		dev_err(&dev->core, "%s:%d: dma_set_mask_and_coherent failed: %d\n",
+			__func__, __LINE__, result);
+		return result;
+	}
+
 	switch (dev->dev_type) {
 	case PS3_DEVICE_TYPE_SB:
 		r->region_ops =  (USE_DYNAMIC_DMA)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/cmm.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/cmm.c
@@ -411,6 +411,10 @@
 	.dev_name = "cmm",
 };
 
+static void cmm_release_device(struct device *dev)
+{
+}
+
 /**
  * cmm_sysfs_register - Register with sysfs
  *
@@ -426,6 +430,7 @@
 
 	dev->id = 0;
 	dev->bus = &cmm_subsys;
+	dev->release = cmm_release_device;
 
 	if ((rc = device_register(dev)))
 		goto subsys_unregister;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/dlpar.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/dlpar.c
@@ -127,7 +127,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,
@@ -168,6 +167,9 @@
 
 		spin_unlock(&rtas_data_buf_lock);
 
+		if (rtas_busy_delay(rc))
+			continue;
+
 		switch (rc) {
 		case COMPLETE:
 			break;
@@ -216,9 +218,6 @@
 			last_dn = last_dn->parent;
 			break;
 
-		case CALL_AGAIN:
-			break;
-
 		case MORE_MEMORY:
 		case ERR_CFG_USE:
 		default:
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -91,9 +91,6 @@
 
 	BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
 
-	printk("cpu %u (hwid %u) Ready to die...\n",
-	       smp_processor_id(), hard_smp_processor_id());
-
 	rtas_call_unlocked(&args, rtas_stop_self_token, 0, 1, NULL);
 
 	panic("Alas, I survived.\n");
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -27,7 +27,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");
@@ -223,7 +223,7 @@
 			 struct drmem_lmb **end_lmb)
 {
 	struct drmem_lmb *lmb, *start, *end;
-	struct drmem_lmb *last_lmb;
+	struct drmem_lmb *limit;
 
 	start = NULL;
 	for_each_drmem_lmb(lmb) {
@@ -236,10 +236,10 @@
 	if (!start)
 		return -EINVAL;
 
-	end = &start[n_lmbs - 1];
+	end = &start[n_lmbs];
 
-	last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1];
-	if (end > last_lmb)
+	limit = &drmem_info->lmbs[drmem_info->n_lmbs];
+	if (end > limit)
 		return -EINVAL;
 
 	*start_lmb = start;
@@ -279,7 +279,7 @@
 	return dlpar_change_lmb_state(lmb, false);
 }
 
-static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+static int pseries_remove_memblock(unsigned long base, unsigned long memblock_size)
 {
 	unsigned long block_sz, start_pfn;
 	int sections_per_block;
@@ -310,10 +310,11 @@
 
 static int pseries_remove_mem_node(struct device_node *np)
 {
-	const __be32 *regs;
+	const __be32 *prop;
 	unsigned long base;
-	unsigned int lmb_size;
+	unsigned long lmb_size;
 	int ret = -EINVAL;
+	int addr_cells, size_cells;
 
 	/*
 	 * Check to see if we are actually removing memory
@@ -324,12 +325,19 @@
 	/*
 	 * Find the base address and size of the memblock
 	 */
-	regs = of_get_property(np, "reg", NULL);
-	if (!regs)
+	prop = of_get_property(np, "reg", NULL);
+	if (!prop)
 		return ret;
 
-	base = be64_to_cpu(*(unsigned long *)regs);
-	lmb_size = be32_to_cpu(regs[3]);
+	addr_cells = of_n_addr_cells(np);
+	size_cells = of_n_size_cells(np);
+
+	/*
+	 * "reg" property represents (addr,size) tuple.
+	 */
+	base = of_read_number(prop, addr_cells);
+	prop += addr_cells;
+	lmb_size = of_read_number(prop, size_cells);
 
 	pseries_remove_memblock(base, lmb_size);
 	return 0;
@@ -360,8 +368,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;
@@ -374,25 +384,32 @@
 
 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
 {
+	struct memory_block *mem_block;
 	unsigned long block_sz;
 	int rc;
 
 	if (!lmb_is_removable(lmb))
 		return -EINVAL;
 
+	mem_block = lmb_to_memblock(lmb);
+	if (mem_block == NULL)
+		return -EINVAL;
+
 	rc = dlpar_offline_lmb(lmb);
-	if (rc)
+	if (rc) {
+		put_device(&mem_block->dev);
 		return rc;
+	}
 
 	block_sz = pseries_memory_block_size();
 
-	__remove_memory(lmb->nid, lmb->base_addr, block_sz);
+	__remove_memory(mem_block->nid, lmb->base_addr, block_sz);
+	put_device(&mem_block->dev);
 
 	/* Update memory regions for memory remove */
 	memblock_remove(lmb->base_addr, block_sz);
 
 	invalidate_lmb_associativity_index(lmb);
-	lmb_clear_nid(lmb);
 	lmb->flags &= ~DRCONF_MEM_ASSIGNED;
 
 	return 0;
@@ -479,7 +496,7 @@
 	int lmb_found;
 	int rc;
 
-	pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index);
+	pr_debug("Attempting to hot-remove LMB, drc index %x\n", drc_index);
 
 	lmb_found = 0;
 	for_each_drmem_lmb(lmb) {
@@ -493,14 +510,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)
-		pr_info("Failed to hot-remove memory at %llx\n",
-			lmb->base_addr);
-	else
-		pr_info("Memory at %llx was hot-removed\n", lmb->base_addr);
+	} else if (rc) {
+		pr_debug("Failed to hot-remove memory at %llx\n",
+			 lmb->base_addr);
+	} else {
+		pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr);
+	}
 
 	return rc;
 }
@@ -611,7 +629,7 @@
 
 #else
 static inline int pseries_remove_memblock(unsigned long base,
-					  unsigned int memblock_size)
+					  unsigned long memblock_size)
 {
 	return -EOPNOTSUPP;
 }
@@ -649,7 +667,7 @@
 static int dlpar_add_lmb(struct drmem_lmb *lmb)
 {
 	unsigned long block_sz;
-	int rc;
+	int nid, rc;
 
 	if (lmb->flags & DRCONF_MEM_ASSIGNED)
 		return -EINVAL;
@@ -660,11 +678,13 @@
 		return rc;
 	}
 
-	lmb_set_nid(lmb);
 	block_sz = memory_block_size_bytes();
 
+	/* Find the node id for this address. */
+	nid = memory_add_physaddr_to_nid(lmb->base_addr);
+
 	/* Add the memory */
-	rc = __add_memory(lmb->nid, lmb->base_addr, block_sz);
+	rc = __add_memory(nid, lmb->base_addr, block_sz);
 	if (rc) {
 		invalidate_lmb_associativity_index(lmb);
 		return rc;
@@ -672,9 +692,8 @@
 
 	rc = dlpar_online_lmb(lmb);
 	if (rc) {
-		__remove_memory(lmb->nid, lmb->base_addr, block_sz);
+		__remove_memory(nid, lmb->base_addr, block_sz);
 		invalidate_lmb_associativity_index(lmb);
-		lmb_clear_nid(lmb);
 	} else {
 		lmb->flags |= DRCONF_MEM_ASSIGNED;
 	}
@@ -752,8 +771,8 @@
 			if (!drmem_lmb_reserved(lmb))
 				continue;
 
-			pr_info("Memory at %llx (drc index %x) was hot-added\n",
-				lmb->base_addr, lmb->drc_index);
+			pr_debug("Memory at %llx (drc index %x) was hot-added\n",
+				 lmb->base_addr, lmb->drc_index);
 			drmem_remove_lmb_reservation(lmb);
 		}
 		rc = 0;
@@ -943,10 +962,11 @@
 
 static int pseries_add_mem_node(struct device_node *np)
 {
-	const __be32 *regs;
+	const __be32 *prop;
 	unsigned long base;
-	unsigned int lmb_size;
+	unsigned long lmb_size;
 	int ret = -EINVAL;
+	int addr_cells, size_cells;
 
 	/*
 	 * Check to see if we are actually adding memory
@@ -957,12 +977,18 @@
 	/*
 	 * Find the base and size of the memblock
 	 */
-	regs = of_get_property(np, "reg", NULL);
-	if (!regs)
+	prop = of_get_property(np, "reg", NULL);
+	if (!prop)
 		return ret;
 
-	base = be64_to_cpu(*(unsigned long *)regs);
-	lmb_size = be32_to_cpu(regs[3]);
+	addr_cells = of_n_addr_cells(np);
+	size_cells = of_n_size_cells(np);
+	/*
+	 * "reg" property represents (addr,size) tuple.
+	 */
+	base = of_read_number(prop, addr_cells);
+	prop += addr_cells;
+	lmb_size = of_read_number(prop, size_cells);
 
 	/*
 	 * Update memory region to represent the memory add
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/ibmebus.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/ibmebus.c
@@ -450,6 +450,7 @@
 	if (err) {
 		printk(KERN_WARNING "%s: device_register returned %i\n",
 		       __func__, err);
+		put_device(&ibmebus_bus_device);
 		bus_unregister(&ibmebus_bus_type);
 
 		return err;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/iommu.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/iommu.c
@@ -36,7 +36,6 @@
 #include <asm/udbg.h>
 #include <asm/mmzone.h>
 #include <asm/plpar_wrappers.h>
-#include <asm/svm.h>
 
 #include "pseries.h"
 
@@ -133,10 +132,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,
 				unsigned long attrs)
@@ -147,25 +146,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();
@@ -194,7 +193,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);
 	}
 
@@ -210,8 +210,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);
 	}
@@ -262,16 +263,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();
 		}
@@ -286,7 +287,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);
 
@@ -401,6 +402,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);
 
@@ -1320,15 +1334,7 @@
 	of_reconfig_notifier_register(&iommu_reconfig_nb);
 	register_memory_notifier(&iommu_mem_nb);
 
-	/*
-	 * Secure guest memory is inacessible to devices so regular DMA isn't
-	 * possible.
-	 *
-	 * In that case keep devices' dma_map_ops as NULL so that the generic
-	 * DMA code path will use SWIOTLB to bounce buffers for DMA.
-	 */
-	if (!is_secure_guest())
-		set_pci_dma_ops(&dma_iommu_ops);
+	set_pci_dma_ops(&dma_iommu_ops);
 }
 
 static int __init disable_multitce(char *str)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/lpar.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/lpar.c
@@ -522,8 +522,10 @@
 
 	if (cmd) {
 		rc = init_cpu_associativity();
-		if (rc)
+		if (rc) {
+			destroy_cpu_associativity();
 			goto out;
+		}
 
 		for_each_possible_cpu(cpu) {
 			disp = per_cpu_ptr(&vcpu_disp_data, cpu);
@@ -1416,22 +1418,22 @@
 
 void __init pseries_lpar_read_hblkrm_characteristics(void)
 {
+	const s32 token = rtas_token("ibm,get-system-parameter");
 	unsigned char local_buffer[SPLPAR_TLB_BIC_MAXLENGTH];
 	int call_status, len, idx, bpsize;
 
 	if (!firmware_has_feature(FW_FEATURE_BLOCK_REMOVE))
 		return;
 
-	spin_lock(&rtas_data_buf_lock);
-	memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
-	call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
-				NULL,
-				SPLPAR_TLB_BIC_TOKEN,
-				__pa(rtas_data_buf),
-				RTAS_DATA_BUF_SIZE);
-	memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH);
-	local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0';
-	spin_unlock(&rtas_data_buf_lock);
+	do {
+		spin_lock(&rtas_data_buf_lock);
+		memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
+		call_status = rtas_call(token, 3, 1, NULL, SPLPAR_TLB_BIC_TOKEN,
+					__pa(rtas_data_buf), RTAS_DATA_BUF_SIZE);
+		memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH);
+		local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0';
+		spin_unlock(&rtas_data_buf_lock);
+	} while (rtas_busy_delay(call_status));
 
 	if (call_status != 0) {
 		pr_warn("%s %s Error calling get-system-parameter (0x%x)\n",
@@ -1992,7 +1994,7 @@
 {
 	char name[16];
 	long i;
-	static struct dentry *vpa_dir;
+	struct dentry *vpa_dir;
 
 	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
 		return 0;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/lparcfg.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/lparcfg.c
@@ -289,6 +289,7 @@
  */
 static void parse_system_parameter_string(struct seq_file *m)
 {
+	const s32 token = rtas_token("ibm,get-system-parameter");
 	int call_status;
 
 	unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
@@ -298,16 +299,15 @@
 		return;
 	}
 
-	spin_lock(&rtas_data_buf_lock);
-	memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
-	call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
-				NULL,
-				SPLPAR_CHARACTERISTICS_TOKEN,
-				__pa(rtas_data_buf),
-				RTAS_DATA_BUF_SIZE);
-	memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
-	local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
-	spin_unlock(&rtas_data_buf_lock);
+	do {
+		spin_lock(&rtas_data_buf_lock);
+		memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
+		call_status = rtas_call(token, 3, 1, NULL, SPLPAR_CHARACTERISTICS_TOKEN,
+					__pa(rtas_data_buf), RTAS_DATA_BUF_SIZE);
+		memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
+		local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
+		spin_unlock(&rtas_data_buf_lock);
+	} while (rtas_busy_delay(call_status));
 
 	if (call_status != 0) {
 		printk(KERN_INFO
@@ -435,10 +435,10 @@
 {
 	unsigned long maxmem = 0;
 
-	maxmem += drmem_info->n_lmbs * drmem_info->lmb_size;
+	maxmem += (unsigned long)drmem_info->n_lmbs * drmem_info->lmb_size;
 	maxmem += hugetlb_total_pages() * PAGE_SIZE;
 
-	seq_printf(m, "MaxMem=%ld\n", maxmem);
+	seq_printf(m, "MaxMem=%lu\n", maxmem);
 }
 
 static int pseries_lparcfg_data(struct seq_file *m, void *v)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/msi.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/msi.c
@@ -4,6 +4,7 @@
  * Copyright 2006-2007 Michael Ellerman, IBM Corp.
  */
 
+#include <linux/crash_dump.h>
 #include <linux/device.h>
 #include <linux/irq.h>
 #include <linux/msi.h>
@@ -458,7 +459,28 @@
 			return hwirq;
 		}
 
-		virq = irq_create_mapping(NULL, hwirq);
+		/*
+		 * Depending on the number of online CPUs in the original
+		 * kernel, it is likely for CPU #0 to be offline in a kdump
+		 * kernel. The associated IRQs in the affinity mappings
+		 * provided by irq_create_affinity_masks() are thus not
+		 * started by irq_startup(), as per-design for managed IRQs.
+		 * This can be a problem with multi-queue block devices driven
+		 * by blk-mq : such a non-started IRQ is very likely paired
+		 * with the single queue enforced by blk-mq during kdump (see
+		 * blk_mq_alloc_tag_set()). This causes the device to remain
+		 * silent and likely hangs the guest at some point.
+		 *
+		 * We don't really care for fine-grained affinity when doing
+		 * kdump actually : simply ignore the pre-computed affinity
+		 * masks in this case and let the default mask with all CPUs
+		 * be used when creating the IRQ mappings.
+		 */
+		if (is_kdump_kernel())
+			virq = irq_create_mapping(NULL, hwirq);
+		else
+			virq = irq_create_mapping_affinity(NULL, hwirq,
+							   entry->affinity);
 
 		if (!virq) {
 			pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/of_helpers.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/of_helpers.c
@@ -45,14 +45,14 @@
 int of_read_drc_info_cell(struct property **prop, const __be32 **curval,
 			struct of_drc_info *data)
 {
-	const char *p;
+	const char *p = (char *)(*curval);
 	const __be32 *p2;
 
 	if (!data)
 		return -EINVAL;
 
 	/* Get drc-type:encode-string */
-	p = data->drc_type = (char*) (*curval);
+	data->drc_type = (char *)p;
 	p = of_prop_next_string(*prop, p);
 	if (!p)
 		return -EINVAL;
@@ -65,9 +65,7 @@
 
 	/* Get drc-index-start:encode-int */
 	p2 = (const __be32 *)p;
-	p2 = of_prop_next_u32(*prop, p2, &data->drc_index_start);
-	if (!p2)
-		return -EINVAL;
+	data->drc_index_start = be32_to_cpu(*p2);
 
 	/* Get drc-name-suffix-start:encode-int */
 	p2 = of_prop_next_u32(*prop, p2, &data->drc_name_suffix_start);
@@ -90,7 +88,7 @@
 		return -EINVAL;
 
 	/* Should now know end of current entry */
-	(*curval) = (void *)p2;
+	(*curval) = (void *)(++p2);
 	data->last_drc_index = data->drc_index_start +
 		((data->num_sequential_elems - 1) * data->sequential_inc);
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/papr_scm.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/papr_scm.c
@@ -152,7 +152,7 @@
 	int len, read;
 	int64_t ret;
 
-	if ((hdr->in_offset + hdr->in_length) >= p->metadata_size)
+	if ((hdr->in_offset + hdr->in_length) > p->metadata_size)
 		return -EINVAL;
 
 	for (len = hdr->in_length; len; len -= read) {
@@ -206,7 +206,7 @@
 	__be64 data_be;
 	int64_t ret;
 
-	if ((hdr->in_offset + hdr->in_length) >= p->metadata_size)
+	if ((hdr->in_offset + hdr->in_length) > p->metadata_size)
 		return -EINVAL;
 
 	for (len = hdr->in_length; len; len -= wrote) {
@@ -342,6 +342,7 @@
 	p->bus = nvdimm_bus_register(NULL, &p->bus_desc);
 	if (!p->bus) {
 		dev_err(dev, "Error creating nvdimm bus %pOF\n", p->dn);
+		kfree(p->bus_desc.provider_name);
 		return -ENXIO;
 	}
 
@@ -498,6 +499,7 @@
 
 	nvdimm_bus_unregister(p->bus);
 	drc_pmem_unbind(p);
+	kfree(p->bus_desc.provider_name);
 	kfree(p);
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -66,6 +66,7 @@
 int remove_phb_dynamic(struct pci_controller *phb)
 {
 	struct pci_bus *b = phb->bus;
+	struct pci_host_bridge *host_bridge = to_pci_host_bridge(b->bridge);
 	struct resource *res;
 	int rc, i;
 
@@ -92,7 +93,8 @@
 	/* Remove the PCI bus and unregister the bridge device from sysfs */
 	phb->bus = NULL;
 	pci_remove_bus(b);
-	device_unregister(b->bridge);
+	host_bridge->bus = NULL;
+	device_unregister(&host_bridge->dev);
 
 	/* Now release the IO resource */
 	if (res->flags & IORESOURCE_IO)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/pseries.h
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/pseries.h
@@ -114,4 +114,6 @@
 void pseries_setup_rfi_flush(void);
 void pseries_lpar_read_hblkrm_characteristics(void);
 
+void pseries_rng_init(void);
+
 #endif /* _PSERIES_PSERIES_H */
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/ras.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/ras.c
@@ -184,7 +184,6 @@
 	case EPOW_SHUTDOWN_ON_UPS:
 		pr_emerg("Loss of system power detected. System is running on"
 			 " UPS/battery. Check RTAS error log for details\n");
-		orderly_poweroff(true);
 		break;
 
 	case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
@@ -395,10 +394,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))))
 
 static inline struct rtas_error_log *fwnmi_get_errlog(void)
 {
@@ -494,18 +494,55 @@
 	return 0; /* need to perform reset */
 }
 
+static int mce_handle_err_realmode(int disposition, u8 error_type)
+{
+#ifdef CONFIG_PPC_BOOK3S_64
+	if (disposition == RTAS_DISP_NOT_RECOVERED) {
+		switch (error_type) {
+		case	MC_ERROR_TYPE_SLB:
+		case	MC_ERROR_TYPE_ERAT:
+			/*
+			 * Store the old slb content in paca before flushing.
+			 * Print this when we go to virtual mode.
+			 * There are chances that we may hit MCE again if there
+			 * is a parity error on the SLB entry we trying to read
+			 * for saving. Hence limit the slb saving to single
+			 * level of recursion.
+			 */
+			if (local_paca->in_mce == 1)
+				slb_save_contents(local_paca->mce_faulty_slbs);
+			flush_and_reload_slb();
+			disposition = RTAS_DISP_FULLY_RECOVERED;
+			break;
+		default:
+			break;
+		}
+	} else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
+		/* Platform corrected itself but could be degraded */
+		pr_err("MCE: limited recovery, system may be degraded\n");
+		disposition = RTAS_DISP_FULLY_RECOVERED;
+	}
+#endif
+	return disposition;
+}
 
-static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
+static int mce_handle_err_virtmode(struct pt_regs *regs,
+				   struct rtas_error_log *errp,
+				   struct pseries_mc_errorlog *mce_log,
+				   int disposition)
 {
 	struct mce_error_info mce_err = { 0 };
-	unsigned long eaddr = 0, paddr = 0;
-	struct pseries_errorlog *pseries_log;
-	struct pseries_mc_errorlog *mce_log;
-	int disposition = rtas_error_disposition(errp);
 	int initiator = rtas_error_initiator(errp);
 	int severity = rtas_error_severity(errp);
+	unsigned long eaddr = 0, paddr = 0;
 	u8 error_type, err_sub_type;
 
+	if (!mce_log)
+		goto out;
+
+	error_type = mce_log->error_type;
+	err_sub_type = rtas_mc_error_sub_type(mce_log);
+
 	if (initiator == RTAS_INITIATOR_UNKNOWN)
 		mce_err.initiator = MCE_INITIATOR_UNKNOWN;
 	else if (initiator == RTAS_INITIATOR_CPU)
@@ -544,18 +581,7 @@
 	mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
 	mce_err.error_class = MCE_ECLASS_UNKNOWN;
 
-	if (!rtas_error_extended(errp))
-		goto out;
-
-	pseries_log = get_pseries_errorlog(errp, PSERIES_ELOG_SECT_ID_MCE);
-	if (pseries_log == NULL)
-		goto out;
-
-	mce_log = (struct pseries_mc_errorlog *)pseries_log->data;
-	error_type = mce_log->error_type;
-	err_sub_type = rtas_mc_error_sub_type(mce_log);
-
-	switch (mce_log->error_type) {
+	switch (error_type) {
 	case MC_ERROR_TYPE_UE:
 		mce_err.error_type = MCE_ERROR_TYPE_UE;
 		switch (err_sub_type) {
@@ -652,40 +678,45 @@
 		mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
 		break;
 	}
-
-#ifdef CONFIG_PPC_BOOK3S_64
-	if (disposition == RTAS_DISP_NOT_RECOVERED) {
-		switch (error_type) {
-		case	MC_ERROR_TYPE_SLB:
-		case	MC_ERROR_TYPE_ERAT:
-			/*
-			 * Store the old slb content in paca before flushing.
-			 * Print this when we go to virtual mode.
-			 * There are chances that we may hit MCE again if there
-			 * is a parity error on the SLB entry we trying to read
-			 * for saving. Hence limit the slb saving to single
-			 * level of recursion.
-			 */
-			if (local_paca->in_mce == 1)
-				slb_save_contents(local_paca->mce_faulty_slbs);
-			flush_and_reload_slb();
-			disposition = RTAS_DISP_FULLY_RECOVERED;
-			break;
-		default:
-			break;
-		}
-	} else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
-		/* Platform corrected itself but could be degraded */
-		printk(KERN_ERR "MCE: limited recovery, system may "
-		       "be degraded\n");
-		disposition = RTAS_DISP_FULLY_RECOVERED;
-	}
-#endif
-
 out:
 	save_mce_event(regs, disposition == RTAS_DISP_FULLY_RECOVERED,
-			&mce_err, regs->nip, eaddr, paddr);
+		       &mce_err, regs->nip, eaddr, paddr);
+	return disposition;
+}
+
+static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
+{
+	struct pseries_errorlog *pseries_log;
+	struct pseries_mc_errorlog *mce_log = NULL;
+	int disposition = rtas_error_disposition(errp);
+	u8 error_type;
+
+	if (!rtas_error_extended(errp))
+		goto out;
+
+	pseries_log = get_pseries_errorlog(errp, PSERIES_ELOG_SECT_ID_MCE);
+	if (!pseries_log)
+		goto out;
+
+	mce_log = (struct pseries_mc_errorlog *)pseries_log->data;
+	error_type = mce_log->error_type;
+
+	disposition = mce_handle_err_realmode(disposition, error_type);
 
+	/*
+	 * Enable translation as we will be accessing per-cpu variables
+	 * in save_mce_event() which may fall outside RMO region, also
+	 * leave it enabled because subsequently we will be queuing work
+	 * to workqueues where again per-cpu variables accessed, besides
+	 * fwnmi_release_errinfo() crashes when called in realmode on
+	 * pseries.
+	 * Note: All the realmode handling like flushing SLB entries for
+	 *       SLB multihit is done by now.
+	 */
+out:
+	mtmsr(mfmsr() | MSR_IR | MSR_DR);
+	disposition = mce_handle_err_virtmode(regs, errp, mce_log,
+					      disposition);
 	return disposition;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/rng.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/rng.c
@@ -10,6 +10,7 @@
 #include <asm/archrandom.h>
 #include <asm/machdep.h>
 #include <asm/plpar_wrappers.h>
+#include "pseries.h"
 
 
 static int pseries_get_random_long(unsigned long *v)
@@ -24,18 +25,13 @@
 	return 0;
 }
 
-static __init int rng_init(void)
+void __init pseries_rng_init(void)
 {
 	struct device_node *dn;
 
 	dn = of_find_compatible_node(NULL, NULL, "ibm,random");
 	if (!dn)
-		return -ENODEV;
-
-	pr_info("Registering arch random hook.\n");
-
+		return;
 	ppc_md.get_random_seed = pseries_get_random_long;
-
-	return 0;
+	of_node_put(dn);
 }
-machine_subsys_initcall(pseries, rng_init);
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/setup.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/setup.c
@@ -74,6 +74,9 @@
 #include "pseries.h"
 #include "../../../../drivers/pci/pci.h"
 
+DEFINE_STATIC_KEY_FALSE(shared_processor);
+EXPORT_SYMBOL(shared_processor);
+
 int CMO_PrPSP = -1;
 int CMO_SecPSP = -1;
 unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K);
@@ -558,6 +561,14 @@
 
 	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);
 }
 
 #ifdef CONFIG_PCI_IOV
@@ -758,6 +769,10 @@
 
 	if (firmware_has_feature(FW_FEATURE_LPAR)) {
 		vpa_init(boot_cpuid);
+
+		if (lppaca_shared_proc(get_lppaca()))
+			static_branch_enable(&shared_processor);
+
 		ppc_md.power_save = pseries_lpar_idle;
 		ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
 #ifdef CONFIG_PCI_IOV
@@ -777,6 +792,8 @@
 
 	if (swiotlb_force == SWIOTLB_FORCE)
 		ppc_swiotlb_enable = 1;
+
+	pseries_rng_init();
 }
 
 static void pseries_panic(char *str)
--- linux-ein-5.4.0.orig/arch/powerpc/platforms/pseries/suspend.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/suspend.c
@@ -13,7 +13,6 @@
 #include <asm/mmu.h>
 #include <asm/rtas.h>
 #include <asm/topology.h>
-#include "../../kernel/cacheinfo.h"
 
 static u64 stream_id;
 static struct device suspend_dev;
@@ -78,9 +77,7 @@
 	 * Update configuration which can be modified based on device tree
 	 * changes during resume.
 	 */
-	cacheinfo_cpu_offline(smp_processor_id());
 	post_mobility_fixup();
-	cacheinfo_cpu_online(smp_processor_id());
 }
 
 /**
@@ -132,15 +129,11 @@
 			       struct device_attribute *attr,
 			       const char *buf, size_t count)
 {
-	cpumask_var_t offline_mask;
 	int rc;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (!alloc_cpumask_var(&offline_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	stream_id = simple_strtoul(buf, NULL, 16);
 
 	do {
@@ -150,32 +143,16 @@
 	} while (rc == -EAGAIN);
 
 	if (!rc) {
-		/* All present CPUs must be online */
-		cpumask_andnot(offline_mask, cpu_present_mask,
-				cpu_online_mask);
-		rc = rtas_online_cpus_mask(offline_mask);
-		if (rc) {
-			pr_err("%s: Could not bring present CPUs online.\n",
-					__func__);
-			goto out;
-		}
-
 		stop_topology_update();
 		rc = pm_suspend(PM_SUSPEND_MEM);
 		start_topology_update();
-
-		/* Take down CPUs not online prior to suspend */
-		if (!rtas_offline_cpus_mask(offline_mask))
-			pr_warn("%s: Could not restore CPUs to offline "
-					"state.\n", __func__);
 	}
 
 	stream_id = 0;
 
 	if (!rc)
 		rc = count;
-out:
-	free_cpumask_var(offline_mask);
+
 	return rc;
 }
 
@@ -210,7 +187,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-ein-5.4.0.orig/arch/powerpc/platforms/pseries/vio.c
+++ linux-ein-5.4.0/arch/powerpc/platforms/pseries/vio.c
@@ -36,7 +36,6 @@
 	.name = "vio",
 	.type = "",
 	.dev.init_name = "vio",
-	.dev.bus = &vio_bus_type,
 };
 
 #ifdef CONFIG_PPC_SMLPAR
@@ -1176,6 +1175,8 @@
 	if (tbl == NULL)
 		return NULL;
 
+	kref_init(&tbl->it_kref);
+
 	of_parse_dma_window(dev->dev.of_node, dma_window,
 			    &tbl->it_index, &offset, &size);
 
--- linux-ein-5.4.0.orig/arch/powerpc/purgatory/Makefile
+++ linux-ein-5.4.0/arch/powerpc/purgatory/Makefile
@@ -4,6 +4,11 @@
 
 targets += trampoline.o purgatory.ro kexec-purgatory.c
 
+# When profile-guided optimization is enabled, llvm emits two different
+# overlapping text sections, which is not supported by kexec. Remove profile
+# optimization flags.
+KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
+
 LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined
 
 $(obj)/purgatory.ro: $(obj)/trampoline.o FORCE
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/dart_iommu.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/dart_iommu.c
@@ -403,9 +403,10 @@
 	}
 
 	/* Initialize the DART HW */
-	if (dart_init(dn) != 0)
+	if (dart_init(dn) != 0) {
+		of_node_put(dn);
 		return;
-
+	}
 	/*
 	 * U4 supports a DART bypass, we use it for 64-bit capable devices to
 	 * improve performance.  However, that only works for devices connected
@@ -418,6 +419,7 @@
 
 	/* Setup pci_dma ops */
 	set_pci_dma_ops(&dma_iommu_ops);
+	of_node_put(dn);
 }
 
 #ifdef CONFIG_PM
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/dcr-low.S
+++ linux-ein-5.4.0/arch/powerpc/sysdev/dcr-low.S
@@ -11,7 +11,7 @@
 #include <asm/export.h>
 
 #define DCR_ACCESS_PROLOG(table) \
-	cmpli	cr0,r3,1024;	 \
+	cmplwi	cr0,r3,1024;	 \
 	rlwinm  r3,r3,4,18,27;   \
 	lis     r5,table@h;      \
 	ori     r5,r5,table@l;   \
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/fsl_gtm.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/fsl_gtm.c
@@ -86,7 +86,7 @@
  */
 struct gtm_timer *gtm_get_timer16(void)
 {
-	struct gtm *gtm = NULL;
+	struct gtm *gtm;
 	int i;
 
 	list_for_each_entry(gtm, &gtms, list_node) {
@@ -103,7 +103,7 @@
 		spin_unlock_irq(&gtm->lock);
 	}
 
-	if (gtm)
+	if (!list_empty(&gtms))
 		return ERR_PTR(-EBUSY);
 	return ERR_PTR(-ENODEV);
 }
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/fsl_msi.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/fsl_msi.c
@@ -211,8 +211,10 @@
 			dev_err(&pdev->dev,
 				"node %pOF has an invalid fsl,msi phandle %u\n",
 				hose->dn, np->phandle);
+			of_node_put(np);
 			return -EINVAL;
 		}
+		of_node_put(np);
 	}
 
 	for_each_pci_msi_entry(entry, pdev) {
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/fsl_pci.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/fsl_pci.c
@@ -520,6 +520,7 @@
 	struct resource rsrc;
 	const int *bus_range;
 	u8 hdr_type, progif;
+	u32 class_code;
 	struct device_node *dev;
 	struct ccsr_pci __iomem *pci;
 	u16 temp;
@@ -593,6 +594,13 @@
 			PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
 		if (fsl_pcie_check_link(hose))
 			hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+		/* Fix Class Code to PCI_CLASS_BRIDGE_PCI_NORMAL for pre-3.0 controller */
+		if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0) {
+			early_read_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, &class_code);
+			class_code &= 0xff;
+			class_code |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
+			early_write_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, class_code);
+		}
 	} else {
 		/*
 		 * Set PBFR(PCI Bus Function Register)[10] = 1 to
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/fsl_pci.h
+++ linux-ein-5.4.0/arch/powerpc/sysdev/fsl_pci.h
@@ -18,6 +18,7 @@
 
 #define PCIE_LTSSM	0x0404		/* PCIE Link Training and Status */
 #define PCIE_LTSSM_L0	0x16		/* L0 state */
+#define PCIE_FSL_CSR_CLASSCODE	0x474	/* FSL GPEX CSR */
 #define PCIE_IP_REV_2_2		0x02080202 /* PCIE IP block version Rev2.2 */
 #define PCIE_IP_REV_3_0		0x02080300 /* PCIE IP block version Rev3.0 */
 #define PIWAR_EN		0x80000000	/* Enable */
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/fsl_rio.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/fsl_rio.c
@@ -505,8 +505,10 @@
 	if (rc) {
 		dev_err(&dev->dev, "Can't get %pOF property 'reg'\n",
 				rmu_node);
+		of_node_put(rmu_node);
 		goto err_rmu;
 	}
+	of_node_put(rmu_node);
 	rmu_regs_win = ioremap(rmu_regs.start, resource_size(&rmu_regs));
 	if (!rmu_regs_win) {
 		dev_err(&dev->dev, "Unable to map rmu register window\n");
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/mpic_msgr.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/mpic_msgr.c
@@ -191,7 +191,7 @@
 
 	/* IO map the message register block. */
 	of_address_to_resource(np, 0, &rsrc);
-	msgr_block_addr = ioremap(rsrc.start, resource_size(&rsrc));
+	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-ein-5.4.0.orig/arch/powerpc/sysdev/tsi108_pci.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/tsi108_pci.c
@@ -216,9 +216,8 @@
 
 	(hose)->ops = &tsi108_direct_pci_ops;
 
-	printk(KERN_INFO "Found tsi108 PCI host bridge at 0x%08x. "
-	       "Firmware bus number: %d->%d\n",
-	       rsrc.start, hose->first_busno, hose->last_busno);
+	pr_info("Found tsi108 PCI host bridge at 0x%pa. Firmware bus number: %d->%d\n",
+		&rsrc.start, hose->first_busno, hose->last_busno);
 
 	/* Interpret the "ranges" property */
 	/* This also maps the I/O region and sets isa_io/mem_base */
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xics/icp-hv.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xics/icp-hv.c
@@ -174,6 +174,7 @@
 
 	icp_ops = &icp_hv_ops;
 
+	of_node_put(np);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xics/icp-opal.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xics/icp-opal.c
@@ -195,6 +195,7 @@
 
 	printk("XICS: Using OPAL ICP fallbacks\n");
 
+	of_node_put(np);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xive/common.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xive/common.c
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/msi.h>
+#include <linux/vmalloc.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
@@ -68,13 +69,6 @@
 /* Xive state for each CPU */
 static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu);
 
-/*
- * A "disabled" interrupt should never fire, to catch problems
- * we set its logical number to this
- */
-#define XIVE_BAD_IRQ		0x7fffffff
-#define XIVE_MAX_IRQ		(XIVE_BAD_IRQ - 1)
-
 /* An invalid CPU target */
 #define XIVE_INVALID_TARGET	(-1)
 
@@ -263,6 +257,13 @@
 	xmon_printf("\n");
 }
 
+static struct irq_data *xive_get_irq_data(u32 hw_irq)
+{
+	unsigned int irq = irq_find_mapping(xive_irq_domain, hw_irq);
+
+	return irq ? irq_get_irq_data(irq) : NULL;
+}
+
 int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)
 {
 	int rc;
@@ -279,6 +280,9 @@
 	xmon_printf("IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
 		    hw_irq, target, prio, lirq);
 
+	if (!d)
+		d = xive_get_irq_data(hw_irq);
+
 	if (d) {
 		struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
 		u64 val = xive_esb_read(xd, XIVE_ESB_GET);
@@ -972,12 +976,22 @@
 				  enum irqchip_irq_state which, bool *state)
 {
 	struct xive_irq_data *xd = irq_data_get_irq_handler_data(data);
+	u8 pq;
 
 	switch (which) {
 	case IRQCHIP_STATE_ACTIVE:
-		*state = !xd->stale_p &&
-			 (xd->saved_p ||
-			  !!(xive_esb_read(xd, XIVE_ESB_GET) & XIVE_ESB_VAL_P));
+		pq = xive_esb_read(xd, XIVE_ESB_GET);
+
+		/*
+		 * The esb value being all 1's means we couldn't get
+		 * the PQ state of the interrupt through mmio. It may
+		 * happen, for example when querying a PHB interrupt
+		 * while the PHB is in an error state. We consider the
+		 * interrupt to be inactive in that case.
+		 */
+		*state = (pq != XIVE_ESB_INVALID) && !xd->stale_p &&
+			(xd->saved_p || (!!(pq & XIVE_ESB_VAL_P) &&
+			 !irqd_irq_disabled(data)));
 		return 0;
 	default:
 		return -EINVAL;
@@ -1007,12 +1021,16 @@
 void xive_cleanup_irq_data(struct xive_irq_data *xd)
 {
 	if (xd->eoi_mmio) {
+		unmap_kernel_range((unsigned long)xd->eoi_mmio,
+				   1u << xd->esb_shift);
 		iounmap(xd->eoi_mmio);
 		if (xd->eoi_mmio == xd->trig_mmio)
 			xd->trig_mmio = NULL;
 		xd->eoi_mmio = NULL;
 	}
 	if (xd->trig_mmio) {
+		unmap_kernel_range((unsigned long)xd->trig_mmio,
+				   1u << xd->esb_shift);
 		iounmap(xd->trig_mmio);
 		xd->trig_mmio = NULL;
 	}
@@ -1035,6 +1053,15 @@
 	xd->target = XIVE_INVALID_TARGET;
 	irq_set_handler_data(virq, xd);
 
+	/*
+	 * Turn OFF by default the interrupt being mapped. A side
+	 * effect of this check is the mapping the ESB page of the
+	 * interrupt in the Linux address space. This prevents page
+	 * fault issues in the crash handler which masks all
+	 * interrupts.
+	 */
+	xive_esb_read(xd, XIVE_ESB_SET_PQ_01);
+
 	return 0;
 }
 
@@ -1132,7 +1159,7 @@
 	xc = per_cpu(xive_cpu, cpu);
 
 	/* Check if we are already setup */
-	if (xc->hw_ipi != 0)
+	if (xc->hw_ipi != XIVE_BAD_IRQ)
 		return 0;
 
 	/* Grab an IPI from the backend, this will populate xc->hw_ipi */
@@ -1169,7 +1196,7 @@
 	/* Disable the IPI and free the IRQ data */
 
 	/* Already cleaned up ? */
-	if (xc->hw_ipi == 0)
+	if (xc->hw_ipi == XIVE_BAD_IRQ)
 		return;
 
 	/* Mask the IPI */
@@ -1325,6 +1352,7 @@
 		if (np)
 			xc->chip_id = of_get_ibm_chip_id(np);
 		of_node_put(np);
+		xc->hw_ipi = XIVE_BAD_IRQ;
 
 		per_cpu(xive_cpu, cpu) = xc;
 	}
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xive/native.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xive/native.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/cpumask.h>
 #include <linux/mm.h>
+#include <linux/kmemleak.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
@@ -312,7 +313,7 @@
 	s64 rc;
 
 	/* Free the IPI */
-	if (!xc->hw_ipi)
+	if (xc->hw_ipi == XIVE_BAD_IRQ)
 		return;
 	for (;;) {
 		rc = opal_xive_free_irq(xc->hw_ipi);
@@ -320,7 +321,7 @@
 			msleep(OPAL_BUSY_DELAY_MS);
 			continue;
 		}
-		xc->hw_ipi = 0;
+		xc->hw_ipi = XIVE_BAD_IRQ;
 		break;
 	}
 }
@@ -646,6 +647,7 @@
 			pr_err("Failed to allocate provisioning page\n");
 			return false;
 		}
+		kmemleak_ignore(p);
 		opal_xive_donate_page(chip, __pa(p));
 	}
 	return true;
@@ -776,7 +778,7 @@
 	if (out_qpage)
 		*out_qpage = be64_to_cpu(qpage);
 	if (out_qsize)
-		*out_qsize = be32_to_cpu(qsize);
+		*out_qsize = be64_to_cpu(qsize);
 	if (out_qeoi_page)
 		*out_qeoi_page = be64_to_cpu(qeoi_page);
 	if (out_escalate_irq)
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xive/spapr.c
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xive/spapr.c
@@ -392,20 +392,28 @@
 	data->esb_shift = esb_shift;
 	data->trig_page = trig_page;
 
+	data->hw_irq = hw_irq;
+
 	/*
 	 * No chip-id for the sPAPR backend. This has an impact how we
 	 * pick a target. See xive_pick_irq_target().
 	 */
 	data->src_chip = XIVE_INVALID_CHIP_ID;
 
+	/*
+	 * When the H_INT_ESB flag is set, the H_INT_ESB hcall should
+	 * be used for interrupt management. Skip the remapping of the
+	 * ESB pages which are not available.
+	 */
+	if (data->flags & XIVE_IRQ_FLAG_H_INT_ESB)
+		return 0;
+
 	data->eoi_mmio = ioremap(data->eoi_page, 1u << data->esb_shift);
 	if (!data->eoi_mmio) {
 		pr_err("Failed to map EOI page for irq 0x%x\n", hw_irq);
 		return -ENOMEM;
 	}
 
-	data->hw_irq = hw_irq;
-
 	/* Full function page supports trigger */
 	if (flags & XIVE_SRC_TRIGGER) {
 		data->trig_mmio = data->eoi_mmio;
@@ -414,6 +422,7 @@
 
 	data->trig_mmio = ioremap(data->trig_page, 1u << data->esb_shift);
 	if (!data->trig_mmio) {
+		iounmap(data->eoi_mmio);
 		pr_err("Failed to map trigger page for irq 0x%x\n", hw_irq);
 		return -ENOMEM;
 	}
@@ -552,11 +561,11 @@
 
 static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc)
 {
-	if (!xc->hw_ipi)
+	if (xc->hw_ipi == XIVE_BAD_IRQ)
 		return;
 
 	xive_irq_bitmap_free(xc->hw_ipi);
-	xc->hw_ipi = 0;
+	xc->hw_ipi = XIVE_BAD_IRQ;
 }
 #endif /* CONFIG_SMP */
 
@@ -675,6 +684,7 @@
 	}
 
 	reg = of_get_property(rootdn, "ibm,plat-res-int-priorities", &len);
+	of_node_put(rootdn);
 	if (!reg) {
 		pr_err("Failed to read 'ibm,plat-res-int-priorities' property\n");
 		return false;
--- linux-ein-5.4.0.orig/arch/powerpc/sysdev/xive/xive-internal.h
+++ linux-ein-5.4.0/arch/powerpc/sysdev/xive/xive-internal.h
@@ -5,6 +5,13 @@
 #ifndef __XIVE_INTERNAL_H
 #define __XIVE_INTERNAL_H
 
+/*
+ * A "disabled" interrupt should never fire, to catch problems
+ * we set its logical number to this
+ */
+#define XIVE_BAD_IRQ		0x7fffffff
+#define XIVE_MAX_IRQ		(XIVE_BAD_IRQ - 1)
+
 /* Each CPU carry one of these with various per-CPU state */
 struct xive_cpu {
 #ifdef CONFIG_SMP
--- linux-ein-5.4.0.orig/arch/powerpc/tools/relocs_check.sh
+++ linux-ein-5.4.0/arch/powerpc/tools/relocs_check.sh
@@ -10,24 +10,29 @@
 # based on relocs_check.pl
 # Copyright © 2009 IBM Corporation
 
-if [ $# -lt 2 ]; then
-	echo "$0 [path to objdump] [path to vmlinux]" 1>&2
+if [ $# -lt 3 ]; then
+	echo "$0 [path to objdump] [path to nm] [path to vmlinux]" 1>&2
 	exit 1
 fi
 
-# Have Kbuild supply the path to objdump so we handle cross compilation.
+# Have Kbuild supply the path to objdump and nm so we handle cross compilation.
 objdump="$1"
-vmlinux="$2"
+nm="$2"
+vmlinux="$3"
+
+# Remove from the bad relocations those that match an undefined weak symbol
+# which will result in an absolute relocation to 0.
+# Weak unresolved symbols are of that form in nm output:
+# "                  w _binary__btf_vmlinux_bin_end"
+undef_weak_symbols=$($nm "$vmlinux" | awk '$1 ~ /w/ { print $2 }')
 
 bad_relocs=$(
-"$objdump" -R "$vmlinux" |
+$objdump -R "$vmlinux" |
 	# Only look at relocation lines.
 	grep -E '\<R_' |
 	# These relocations are okay
 	# On PPC64:
 	#	R_PPC64_RELATIVE, R_PPC64_NONE
-	#	R_PPC64_ADDR64 mach_<name>
-	#	R_PPC64_ADDR64 __crc_<name>
 	# On PPC:
 	#	R_PPC_RELATIVE, R_PPC_ADDR16_HI,
 	#	R_PPC_ADDR16_HA,R_PPC_ADDR16_LO,
@@ -39,8 +44,7 @@
 R_PPC_ADDR16_HA
 R_PPC_RELATIVE
 R_PPC_NONE' |
-	grep -E -v '\<R_PPC64_ADDR64[[:space:]]+mach_' |
-	grep -E -v '\<R_PPC64_ADDR64[[:space:]]+__crc_'
+	([ "$undef_weak_symbols" ] && grep -F -w -v "$undef_weak_symbols" || cat)
 )
 
 if [ -z "$bad_relocs" ]; then
--- linux-ein-5.4.0.orig/arch/powerpc/tools/unrel_branch_check.sh
+++ linux-ein-5.4.0/arch/powerpc/tools/unrel_branch_check.sh
@@ -18,14 +18,14 @@
 #__end_interrupts should be located within the first 64K
 
 end_intr=0x$(
-"$objdump" -R "$vmlinux" -d --start-address=0xc000000000000000		\
+$objdump -R "$vmlinux" -d --start-address=0xc000000000000000           \
 		 --stop-address=0xc000000000010000 |
 grep '\<__end_interrupts>:' |
 awk '{print $1}'
 )
 
 BRANCHES=$(
-"$objdump" -R "$vmlinux" -D --start-address=0xc000000000000000		\
+$objdump -R "$vmlinux" -D --start-address=0xc000000000000000           \
 		--stop-address=${end_intr} |
 grep -e "^c[0-9a-f]*:[[:space:]]*\([0-9a-f][0-9a-f][[:space:]]\)\{4\}[[:space:]]*b" |
 grep -v '\<__start_initialization_multiplatform>' |
--- linux-ein-5.4.0.orig/arch/powerpc/xmon/Makefile
+++ linux-ein-5.4.0/arch/powerpc/xmon/Makefile
@@ -1,9 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for xmon
 
-# Disable clang warning for using setjmp without setjmp.h header
-subdir-ccflags-y := $(call cc-disable-warning, builtin-requires-header)
-
 GCOV_PROFILE := n
 KCOV_INSTRUMENT := n
 UBSAN_SANITIZE := n
--- linux-ein-5.4.0.orig/arch/powerpc/xmon/nonstdio.c
+++ linux-ein-5.4.0/arch/powerpc/xmon/nonstdio.c
@@ -178,7 +178,7 @@
 
 	if (n && rc == 0) {
 		/* No udbg hooks, fallback to printk() - dangerous */
-		printk("%s", xmon_outbuf);
+		pr_cont("%s", xmon_outbuf);
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/powerpc/xmon/xmon.c
+++ linux-ein-5.4.0/arch/powerpc/xmon/xmon.c
@@ -25,6 +25,7 @@
 #include <linux/nmi.h>
 #include <linux/ctype.h>
 #include <linux/highmem.h>
+#include <linux/security.h>
 
 #include <asm/debugfs.h>
 #include <asm/ptrace.h>
@@ -187,6 +188,8 @@
 static void dump_tlb_book3e(void);
 #endif
 
+static void clear_all_bpt(void);
+
 #ifdef CONFIG_PPC64
 #define REG		"%.16lx"
 #else
@@ -283,10 +286,38 @@
 "  U	show uptime information\n"
 "  ?	help\n"
 "  # n	limit output to n lines per page (for dp, dpa, dl)\n"
-"  zr	reboot\n\
-  zh	halt\n"
+"  zr	reboot\n"
+"  zh	halt\n"
 ;
 
+#ifdef CONFIG_SECURITY
+static bool xmon_is_locked_down(void)
+{
+	static bool lockdown;
+
+	if (!lockdown) {
+		lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
+		if (lockdown) {
+			printf("xmon: Disabled due to kernel lockdown\n");
+			xmon_is_ro = true;
+		}
+	}
+
+	if (!xmon_is_ro) {
+		xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
+		if (xmon_is_ro)
+			printf("xmon: Read-only due to kernel lockdown\n");
+	}
+
+	return lockdown;
+}
+#else /* CONFIG_SECURITY */
+static inline bool xmon_is_locked_down(void)
+{
+	return false;
+}
+#endif
+
 static struct pt_regs *xmon_regs;
 
 static inline void sync(void)
@@ -438,7 +469,10 @@
 
 	return false;
 }
-#endif /* CONFIG_SMP */
+#else /* CONFIG_SMP */
+static inline void get_output_lock(void) {}
+static inline void release_output_lock(void) {}
+#endif
 
 static inline int unrecoverable_excp(struct pt_regs *regs)
 {
@@ -455,6 +489,7 @@
 	int cmd = 0;
 	struct bpt *bp;
 	long recurse_jmp[JMP_BUF_LEN];
+	bool locked_down;
 	unsigned long offset;
 	unsigned long flags;
 #ifdef CONFIG_SMP
@@ -465,6 +500,8 @@
 	local_irq_save(flags);
 	hard_irq_disable();
 
+	locked_down = xmon_is_locked_down();
+
 	if (!fromipi) {
 		tracing_enabled = tracing_is_on();
 		tracing_off();
@@ -518,7 +555,8 @@
 
 	if (!fromipi) {
 		get_output_lock();
-		excprint(regs);
+		if (!locked_down)
+			excprint(regs);
 		if (bp) {
 			printf("cpu 0x%x stopped at breakpoint 0x%tx (",
 			       cpu, BP_NUM(bp));
@@ -570,10 +608,14 @@
 		}
 		remove_bpts();
 		disable_surveillance();
-		/* for breakpoint or single step, print the current instr. */
-		if (bp || TRAP(regs) == 0xd00)
-			ppc_inst_dump(regs->nip, 1, 0);
-		printf("enter ? for help\n");
+
+		if (!locked_down) {
+			/* for breakpoint or single step, print curr insn */
+			if (bp || TRAP(regs) == 0xd00)
+				ppc_inst_dump(regs->nip, 1, 0);
+			printf("enter ? for help\n");
+		}
+
 		mb();
 		xmon_gate = 1;
 		barrier();
@@ -597,8 +639,9 @@
 			spin_cpu_relax();
 			touch_nmi_watchdog();
 		} else {
-			cmd = cmds(regs);
-			if (cmd != 0) {
+			if (!locked_down)
+				cmd = cmds(regs);
+			if (locked_down || cmd != 0) {
 				/* exiting xmon */
 				insert_bpts();
 				xmon_gate = 0;
@@ -635,13 +678,16 @@
 			       "can't continue\n");
 		remove_bpts();
 		disable_surveillance();
-		/* for breakpoint or single step, print the current instr. */
-		if (bp || TRAP(regs) == 0xd00)
-			ppc_inst_dump(regs->nip, 1, 0);
-		printf("enter ? for help\n");
+		if (!locked_down) {
+			/* for breakpoint or single step, print current insn */
+			if (bp || TRAP(regs) == 0xd00)
+				ppc_inst_dump(regs->nip, 1, 0);
+			printf("enter ? for help\n");
+		}
 	}
 
-	cmd = cmds(regs);
+	if (!locked_down)
+		cmd = cmds(regs);
 
 	insert_bpts();
 	in_xmon = 0;
@@ -670,7 +716,10 @@
 		}
 	}
 #endif
-	insert_cpu_bpts();
+	if (locked_down)
+		clear_all_bpt();
+	else
+		insert_cpu_bpts();
 
 	touch_nmi_watchdog();
 	local_irq_restore(flags);
@@ -1894,15 +1943,14 @@
 
 	printf("pidr   = %.16lx  tidr  = %.16lx\n",
 		mfspr(SPRN_PID), mfspr(SPRN_TIDR));
-	printf("asdr   = %.16lx  psscr = %.16lx\n",
-		mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
-					: mfspr(SPRN_PSSCR_PR));
+	printf("psscr  = %.16lx\n",
+		hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR));
 
 	if (!hv)
 		return;
 
-	printf("ptcr   = %.16lx\n",
-		mfspr(SPRN_PTCR));
+	printf("ptcr   = %.16lx  asdr  = %.16lx\n",
+		mfspr(SPRN_PTCR), mfspr(SPRN_ASDR));
 #endif
 }
 
@@ -3762,6 +3810,11 @@
 #ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_xmon(int key)
 {
+	if (xmon_is_locked_down()) {
+		clear_all_bpt();
+		xmon_init(0);
+		return;
+	}
 	/* ensure xmon is enabled */
 	xmon_init(1);
 	debugger(get_irq_regs());
@@ -3783,7 +3836,6 @@
 device_initcall(setup_xmon_sysrq);
 #endif /* CONFIG_MAGIC_SYSRQ */
 
-#ifdef CONFIG_DEBUG_FS
 static void clear_all_bpt(void)
 {
 	int i;
@@ -3801,18 +3853,22 @@
 		iabr = NULL;
 		dabr.enabled = 0;
 	}
-
-	printf("xmon: All breakpoints cleared\n");
 }
 
+#ifdef CONFIG_DEBUG_FS
 static int xmon_dbgfs_set(void *data, u64 val)
 {
 	xmon_on = !!val;
 	xmon_init(xmon_on);
 
 	/* make sure all breakpoints removed when disabling */
-	if (!xmon_on)
+	if (!xmon_on) {
 		clear_all_bpt();
+		get_output_lock();
+		printf("xmon: All breakpoints cleared\n");
+		release_output_lock();
+	}
+
 	return 0;
 }
 
@@ -3838,7 +3894,11 @@
 
 static int __init early_parse_xmon(char *p)
 {
-	if (!p || strncmp(p, "early", 5) == 0) {
+	if (xmon_is_locked_down()) {
+		xmon_init(0);
+		xmon_early = 0;
+		xmon_on = 0;
+	} else if (!p || strncmp(p, "early", 5) == 0) {
 		/* just "xmon" is equivalent to "xmon=early" */
 		xmon_init(1);
 		xmon_early = 1;
--- linux-ein-5.4.0.orig/arch/riscv/Kconfig
+++ linux-ein-5.4.0/arch/riscv/Kconfig
@@ -31,6 +31,7 @@
 	select GENERIC_SMP_IDLE_THREAD
 	select GENERIC_ATOMIC64 if !64BIT
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_DMA_CONTIGUOUS
@@ -51,16 +52,16 @@
 	select PCI_MSI if PCI
 	select RISCV_TIMER
 	select GENERIC_IRQ_MULTI_HANDLER
-	select GENERIC_ARCH_TOPOLOGY if SMP
+	select GENERIC_ARCH_TOPOLOGY
 	select ARCH_HAS_PTE_SPECIAL
 	select ARCH_HAS_MMIOWB
 	select HAVE_EBPF_JIT if 64BIT
 	select EDAC_SUPPORT
 	select ARCH_HAS_GIGANTIC_PAGE
 	select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
-	select SPARSEMEM_STATIC if 32BIT
 	select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
 	select HAVE_ARCH_MMAP_RND_BITS
+	select HAVE_COPY_THREAD_TLS
 
 config ARCH_MMAP_RND_BITS_MIN
 	default 18 if 64BIT
@@ -100,7 +101,9 @@
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	select SPARSEMEM_VMEMMAP_ENABLE
+	depends on MMU
+	select SPARSEMEM_STATIC if 32BIT && SPARSEMEM
+	select SPARSEMEM_VMEMMAP_ENABLE if 64BIT
 
 config ARCH_SELECT_MEMORY_MODEL
 	def_bool ARCH_SPARSEMEM_ENABLE
@@ -272,6 +275,19 @@
 
 source "kernel/Kconfig.hz"
 
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
 endmenu
 
 menu "Boot options"
--- linux-ein-5.4.0.orig/arch/riscv/Makefile
+++ linux-ein-5.4.0/arch/riscv/Makefile
@@ -34,11 +34,28 @@
 	KBUILD_LDFLAGS += -melf32lriscv
 endif
 
+ifeq ($(CONFIG_LD_IS_LLD),y)
+ifeq ($(shell test $(CONFIG_LLD_VERSION) -lt 150000; echo $$?),0)
+	KBUILD_CFLAGS += -mno-relax
+	KBUILD_AFLAGS += -mno-relax
+ifneq ($(LLVM_IAS),1)
+	KBUILD_CFLAGS += -Wa,-mno-relax
+	KBUILD_AFLAGS += -Wa,-mno-relax
+endif
+endif
+endif
+
 # ISA string setting
 riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
 riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
 riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
 riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
+
+# Newer binutils versions default to ISA spec version 20191213 which moves some
+# instructions from the I extension to the Zicsr and Zifencei extensions.
+toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei)
+riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei
+
 KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
 KBUILD_AFLAGS += -march=$(riscv-march-y)
 
@@ -58,7 +75,11 @@
         KBUILD_CFLAGS += -fno-omit-frame-pointer
 endif
 
+# Avoid generating .eh_frame sections.
+KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
+
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
+KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax)
 
 # GCC versions that support the "-mstrict-align" option default to allowing
 # unaligned accesses.  While unaligned accesses are explicitly allowed in the
--- linux-ein-5.4.0.orig/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ linux-ein-5.4.0/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -83,6 +83,7 @@
 	phy-mode = "gmii";
 	phy-handle = <&phy0>;
 	phy0: ethernet-phy@0 {
+		compatible = "ethernet-phy-id0007.0771";
 		reg = <0>;
 	};
 };
--- linux-ein-5.4.0.orig/arch/riscv/configs/defconfig
+++ linux-ein-5.4.0/arch/riscv/configs/defconfig
@@ -62,6 +62,8 @@
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/asm-prototypes.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/asm-prototypes.h
@@ -4,4 +4,8 @@
 #include <linux/ftrace.h>
 #include <asm-generic/asm-prototypes.h>
 
+long long __lshrti3(long long a, int b);
+long long __ashrti3(long long a, int b);
+long long __ashlti3(long long a, int b);
+
 #endif /* _ASM_RISCV_PROTOTYPES_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/barrier.h
@@ -58,8 +58,16 @@
  * The AQ/RL pair provides a RCpc critical section, but there's not really any
  * way we can take advantage of that here because the ordering is only enforced
  * on that one lock.  Thus, we're just doing a full fence.
+ *
+ * Since we allow writeX to be called from preemptive regions we need at least
+ * an "o" in the predecessor set to ensure device writes are visible before the
+ * task is marked as available for scheduling on a new hart.  While I don't see
+ * any concrete reason we need a full IO fence, it seems safer to just upgrade
+ * this in order to avoid any IO crossing a scheduling boundary.  In both
+ * instances the scheduler pairs this with an mb(), so nothing is necessary on
+ * the new hart.
  */
-#define smp_mb__after_spinlock()	RISCV_FENCE(rw,rw)
+#define smp_mb__after_spinlock()	RISCV_FENCE(iorw,iorw)
 
 #include <asm-generic/barrier.h>
 
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/cmpxchg.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/cmpxchg.h
@@ -179,7 +179,7 @@
 			"	bnez %1, 0b\n"				\
 			"1:\n"						\
 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
-			: "rJ" (__old), "rJ" (__new)			\
+			: "rJ" ((long)__old), "rJ" (__new)		\
 			: "memory");					\
 		break;							\
 	case 8:								\
@@ -224,7 +224,7 @@
 			RISCV_ACQUIRE_BARRIER				\
 			"1:\n"						\
 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
-			: "rJ" (__old), "rJ" (__new)			\
+			: "rJ" ((long)__old), "rJ" (__new)		\
 			: "memory");					\
 		break;							\
 	case 8:								\
@@ -270,7 +270,7 @@
 			"	bnez %1, 0b\n"				\
 			"1:\n"						\
 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
-			: "rJ" (__old), "rJ" (__new)			\
+			: "rJ" ((long)__old), "rJ" (__new)		\
 			: "memory");					\
 		break;							\
 	case 8:								\
@@ -316,7 +316,7 @@
 			"	fence rw, rw\n"				\
 			"1:\n"						\
 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
-			: "rJ" (__old), "rJ" (__new)			\
+			: "rJ" ((long)__old), "rJ" (__new)		\
 			: "memory");					\
 		break;							\
 	case 8:								\
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/ftrace.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/ftrace.h
@@ -10,9 +10,19 @@
 #endif
 #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
 
+/*
+ * Clang prior to 13 had "mcount" instead of "_mcount":
+ * https://reviews.llvm.org/D98881
+ */
+#if defined(CONFIG_CC_IS_GCC) || CONFIG_CLANG_VERSION >= 130000
+#define MCOUNT_NAME _mcount
+#else
+#define MCOUNT_NAME mcount
+#endif
+
 #define ARCH_SUPPORTS_FTRACE_OPS 1
 #ifndef __ASSEMBLY__
-void _mcount(void);
+void MCOUNT_NAME(void);
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
 	return addr;
@@ -33,7 +43,7 @@
  * both auipc and jalr at the same time.
  */
 
-#define MCOUNT_ADDR		((unsigned long)_mcount)
+#define MCOUNT_ADDR		((unsigned long)MCOUNT_NAME)
 #define JALR_SIGN_MASK		(0x00000800)
 #define JALR_OFFSET_MASK	(0x00000fff)
 #define AUIPC_OFFSET_MASK	(0xfffff000)
@@ -63,4 +73,11 @@
  * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here.
  */
 #define MCOUNT_INSN_SIZE 8
+
+#ifndef __ASSEMBLY__
+struct dyn_ftrace;
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+#define ftrace_init_nop ftrace_init_nop
+#endif
+
 #endif
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/io.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/io.h
@@ -252,9 +252,9 @@
 __io_reads_ins(ins,  u8, b, __io_pbr(), __io_par(addr))
 __io_reads_ins(ins, u16, w, __io_pbr(), __io_par(addr))
 __io_reads_ins(ins, u32, l, __io_pbr(), __io_par(addr))
-#define insb(addr, buffer, count) __insb((void __iomem *)(long)addr, buffer, count)
-#define insw(addr, buffer, count) __insw((void __iomem *)(long)addr, buffer, count)
-#define insl(addr, buffer, count) __insl((void __iomem *)(long)addr, buffer, count)
+#define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count)
+#define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count)
+#define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count)
 
 __io_writes_outs(writes,  u8, b, __io_bw(), __io_aw())
 __io_writes_outs(writes, u16, w, __io_bw(), __io_aw())
@@ -266,22 +266,22 @@
 __io_writes_outs(outs,  u8, b, __io_pbw(), __io_paw())
 __io_writes_outs(outs, u16, w, __io_pbw(), __io_paw())
 __io_writes_outs(outs, u32, l, __io_pbw(), __io_paw())
-#define outsb(addr, buffer, count) __outsb((void __iomem *)(long)addr, buffer, count)
-#define outsw(addr, buffer, count) __outsw((void __iomem *)(long)addr, buffer, count)
-#define outsl(addr, buffer, count) __outsl((void __iomem *)(long)addr, buffer, count)
+#define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count)
+#define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count)
+#define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count)
 
 #ifdef CONFIG_64BIT
 __io_reads_ins(reads, u64, q, __io_br(), __io_ar(addr))
 #define readsq(addr, buffer, count) __readsq(addr, buffer, count)
 
 __io_reads_ins(ins, u64, q, __io_pbr(), __io_par(addr))
-#define insq(addr, buffer, count) __insq((void __iomem *)addr, buffer, count)
+#define insq(addr, buffer, count) __insq(PCI_IOBASE + (addr), buffer, count)
 
 __io_writes_outs(writes, u64, q, __io_bw(), __io_aw())
 #define writesq(addr, buffer, count) __writesq(addr, buffer, count)
 
 __io_writes_outs(outs, u64, q, __io_pbr(), __io_paw())
-#define outsq(addr, buffer, count) __outsq((void __iomem *)addr, buffer, count)
+#define outsq(addr, buffer, count) __outsq(PCI_IOBASE + (addr), buffer, count)
 #endif
 
 #include <asm-generic/io.h>
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/page.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/page.h
@@ -119,7 +119,10 @@
 
 #endif /* __ASSEMBLY__ */
 
-#define virt_addr_valid(vaddr)	(pfn_valid(virt_to_pfn(vaddr)))
+#define virt_addr_valid(vaddr)	({						\
+	unsigned long _addr = (unsigned long)vaddr;				\
+	(unsigned long)(_addr) >= PAGE_OFFSET && pfn_valid(virt_to_pfn(_addr));	\
+})
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/pgtable-32.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/pgtable-32.h
@@ -14,4 +14,6 @@
 #define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE - 1))
 
+#define MAX_POSSIBLE_PHYSMEM_BITS 34
+
 #endif /* _ASM_RISCV_PGTABLE_32_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/processor.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/processor.h
@@ -22,6 +22,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/barrier.h>
+
 struct task_struct;
 struct pt_regs;
 
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/seccomp.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/seccomp.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
+
+#include <asm/unistd.h>
+
+#include <asm-generic/seccomp.h>
+
+#endif /* _ASM_SECCOMP_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/thread_info.h
@@ -12,7 +12,11 @@
 #include <linux/const.h>
 
 /* thread information allocation */
+#ifdef CONFIG_64BIT
+#define THREAD_SIZE_ORDER	(2)
+#else
 #define THREAD_SIZE_ORDER	(1)
+#endif
 #define THREAD_SIZE		(PAGE_SIZE << THREAD_SIZE_ORDER)
 
 #ifndef __ASSEMBLY__
@@ -75,6 +79,7 @@
 #define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 #define TIF_SYSCALL_TRACEPOINT  6       /* syscall tracepoint instrumentation */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing */
+#define TIF_SECCOMP		8	/* syscall secure computing */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
@@ -82,11 +87,13 @@
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 
 #define _TIF_WORK_MASK \
 	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
 #define _TIF_SYSCALL_WORK \
-	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
+	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT | \
+	 _TIF_SECCOMP)
 
 #endif /* _ASM_RISCV_THREAD_INFO_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/riscv/include/asm/uaccess.h
@@ -235,7 +235,7 @@
 	might_fault();						\
 	access_ok(__p, sizeof(*__p)) ?		\
 		__get_user((x), __p) :				\
-		((x) = 0, -EFAULT);				\
+		((x) = (__force __typeof__(x))0, -EFAULT);	\
 })
 
 #define __put_user_asm(insn, x, ptr, err)			\
--- linux-ein-5.4.0.orig/arch/riscv/include/uapi/asm/auxvec.h
+++ linux-ein-5.4.0/arch/riscv/include/uapi/asm/auxvec.h
@@ -10,4 +10,7 @@
 /* vDSO location */
 #define AT_SYSINFO_EHDR 33
 
+/* entries in ARCH_DLINFO */
+#define AT_VECTOR_SIZE_ARCH	1
+
 #endif /* _UAPI_ASM_RISCV_AUXVEC_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/uapi/asm/setup.h
+++ linux-ein-5.4.0/arch/riscv/include/uapi/asm/setup.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+
+#ifndef _UAPI_ASM_RISCV_SETUP_H
+#define _UAPI_ASM_RISCV_SETUP_H
+
+#define COMMAND_LINE_SIZE	1024
+
+#endif /* _UAPI_ASM_RISCV_SETUP_H */
--- linux-ein-5.4.0.orig/arch/riscv/include/uapi/asm/unistd.h
+++ linux-ein-5.4.0/arch/riscv/include/uapi/asm/unistd.h
@@ -18,9 +18,10 @@
 #ifdef __LP64__
 #define __ARCH_WANT_NEW_STAT
 #define __ARCH_WANT_SET_GET_RLIMIT
-#define __ARCH_WANT_SYS_CLONE3
 #endif /* __LP64__ */
 
+#define __ARCH_WANT_SYS_CLONE3
+
 #include <asm-generic/unistd.h>
 
 /*
--- linux-ein-5.4.0.orig/arch/riscv/kernel/cacheinfo.c
+++ linux-ein-5.4.0/arch/riscv/kernel/cacheinfo.c
@@ -16,7 +16,7 @@
 	this_leaf->type = type;
 }
 
-static int __init_cache_level(unsigned int cpu)
+int init_cache_level(unsigned int cpu)
 {
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct device_node *np = of_cpu_device_node_get(cpu);
@@ -58,7 +58,7 @@
 	return 0;
 }
 
-static int __populate_cache_leaves(unsigned int cpu)
+int populate_cache_leaves(unsigned int cpu)
 {
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
@@ -95,6 +95,3 @@
 
 	return 0;
 }
-
-DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
-DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
--- linux-ein-5.4.0.orig/arch/riscv/kernel/entry.S
+++ linux-ein-5.4.0/arch/riscv/kernel/entry.S
@@ -226,8 +226,26 @@
 	/* Check to make sure we don't jump to a bogus syscall number. */
 	li t0, __NR_syscalls
 	la s0, sys_ni_syscall
-	/* Syscall number held in a7 */
-	bgeu a7, t0, 1f
+	/*
+	 * The tracer can change syscall number to valid/invalid value.
+	 * We use syscall_set_nr helper in syscall_trace_enter thus we
+	 * cannot trust the current value in a7 and have to reload from
+	 * the current task pt_regs.
+	 */
+	REG_L a7, PT_A7(sp)
+	/*
+	 * Syscall number held in a7.
+	 * If syscall number is above allowed value, redirect to ni_syscall.
+	 */
+	bge a7, t0, 1f
+	/*
+	 * Check if syscall is rejected by tracer or seccomp, i.e., a7 == -1.
+	 * If yes, we pretend it was executed.
+	 */
+	li t1, -1
+	beq a7, t1, ret_from_syscall_rejected
+	blt a7, t1, 1f
+	/* Call syscall */
 	la s0, sys_call_table
 	slli t0, a7, RISCV_LGPTR
 	add s0, s0, t0
@@ -238,6 +256,12 @@
 ret_from_syscall:
 	/* Set user a0 to kernel a0 */
 	REG_S a0, PT_A0(sp)
+	/*
+	 * We didn't execute the actual syscall.
+	 * Seccomp already set return value for the current task pt_regs.
+	 * (If it was configured with SECCOMP_RET_ERRNO/TRACE)
+	 */
+ret_from_syscall_rejected:
 	/* Trace syscalls, but only if requested by the user. */
 	REG_L t0, TASK_TI_FLAGS(tp)
 	andi t0, t0, _TIF_SYSCALL_WORK
@@ -387,6 +411,7 @@
 ENDPROC(__switch_to)
 
 	.section ".rodata"
+	.align LGREG
 	/* Exception vector table */
 ENTRY(excp_vect_table)
 	RISCV_PTR do_trap_insn_misaligned
--- linux-ein-5.4.0.orig/arch/riscv/kernel/ftrace.c
+++ linux-ein-5.4.0/arch/riscv/kernel/ftrace.c
@@ -88,6 +88,25 @@
 	return __ftrace_modify_call(rec->ip, addr, false);
 }
 
+
+/*
+ * This is called early on, and isn't wrapped by
+ * ftrace_arch_code_modify_{prepare,post_process}() and therefor doesn't hold
+ * text_mutex, which triggers a lockdep failure.  SMP isn't running so we could
+ * just directly poke the text, but it's simpler to just take the lock
+ * ourselves.
+ */
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
+{
+	int out;
+
+	ftrace_arch_code_modify_prepare();
+	out = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
+	ftrace_arch_code_modify_post_process();
+
+	return out;
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
 	int ret = __ftrace_modify_call((unsigned long)&ftrace_call,
@@ -142,7 +161,7 @@
 	 */
 	old = *parent;
 
-	if (function_graph_enter(old, self_addr, frame_pointer, parent))
+	if (!function_graph_enter(old, self_addr, frame_pointer, parent))
 		*parent = return_hooker;
 }
 
--- linux-ein-5.4.0.orig/arch/riscv/kernel/head.S
+++ linux-ein-5.4.0/arch/riscv/kernel/head.S
@@ -26,6 +26,10 @@
 	/* reserved */
 	.word 0
 	.balign 8
+#ifdef CONFIG_RISCV_M_MODE
+	/* Image load offset (0MB) from start of RAM for M-mode */
+	.dword 0
+#else
 #if __riscv_xlen == 64
 	/* Image load offset(2MB) from start of RAM */
 	.dword 0x200000
@@ -33,6 +37,7 @@
 	/* Image load offset(4MB) from start of RAM */
 	.dword 0x400000
 #endif
+#endif
 	/* Effective size of kernel image */
 	.dword _end - _start
 	.dword __HEAD_FLAGS
--- linux-ein-5.4.0.orig/arch/riscv/kernel/mcount.S
+++ linux-ein-5.4.0/arch/riscv/kernel/mcount.S
@@ -47,8 +47,8 @@
 
 ENTRY(ftrace_stub)
 #ifdef CONFIG_DYNAMIC_FTRACE
-       .global _mcount
-       .set    _mcount, ftrace_stub
+       .global MCOUNT_NAME
+       .set    MCOUNT_NAME, ftrace_stub
 #endif
 	ret
 ENDPROC(ftrace_stub)
@@ -78,7 +78,7 @@
 #endif
 
 #ifndef CONFIG_DYNAMIC_FTRACE
-ENTRY(_mcount)
+ENTRY(MCOUNT_NAME)
 	la	t4, ftrace_stub
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	la	t0, ftrace_graph_return
@@ -124,6 +124,6 @@
 	jalr	t5
 	RESTORE_ABI_STATE
 	ret
-ENDPROC(_mcount)
+ENDPROC(MCOUNT_NAME)
 #endif
-EXPORT_SYMBOL(_mcount)
+EXPORT_SYMBOL(MCOUNT_NAME)
--- linux-ein-5.4.0.orig/arch/riscv/kernel/module.c
+++ linux-ein-5.4.0/arch/riscv/kernel/module.c
@@ -8,6 +8,23 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/moduleloader.h>
+#include <linux/vmalloc.h>
+#include <linux/sizes.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+
+/*
+ * The auipc+jalr instruction pair can reach any PC-relative offset
+ * in the range [-2^31 - 2^11, 2^31 - 2^11)
+ */
+static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
+{
+#ifdef CONFIG_32BIT
+	return true;
+#else
+	return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11));
+#endif
+}
 
 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
 {
@@ -91,7 +108,7 @@
 	ptrdiff_t offset = (void *)v - (void *)location;
 	s32 hi20;
 
-	if (offset != (s32)offset) {
+	if (!riscv_insn_valid_32bit_offset(offset)) {
 		pr_err(
 		  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 		  me->name, (long long)v, location);
@@ -193,10 +210,9 @@
 				       Elf_Addr v)
 {
 	ptrdiff_t offset = (void *)v - (void *)location;
-	s32 fill_v = offset;
 	u32 hi20, lo12;
 
-	if (offset != fill_v) {
+	if (!riscv_insn_valid_32bit_offset(offset)) {
 		/* Only emit the plt entry if offset over 32-bit range */
 		if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
 			offset = module_emit_plt_entry(me, v);
@@ -220,10 +236,9 @@
 				   Elf_Addr v)
 {
 	ptrdiff_t offset = (void *)v - (void *)location;
-	s32 fill_v = offset;
 	u32 hi20, lo12;
 
-	if (offset != fill_v) {
+	if (!riscv_insn_valid_32bit_offset(offset)) {
 		pr_err(
 		  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 		  me->name, (long long)v, location);
@@ -386,3 +401,15 @@
 
 	return 0;
 }
+
+#if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
+#define VMALLOC_MODULE_START \
+	 max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
+void *module_alloc(unsigned long size)
+{
+	return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
+				    VMALLOC_END, GFP_KERNEL,
+				    PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+				    __builtin_return_address(0));
+}
+#endif
--- linux-ein-5.4.0.orig/arch/riscv/kernel/module.lds
+++ linux-ein-5.4.0/arch/riscv/kernel/module.lds
@@ -2,7 +2,7 @@
 /* Copyright (C) 2017 Andes Technology Corporation */
 
 SECTIONS {
-	.plt (NOLOAD) : { BYTE(0) }
-	.got (NOLOAD) : { BYTE(0) }
-	.got.plt (NOLOAD) : { BYTE(0) }
+	.plt : { BYTE(0) }
+	.got : { BYTE(0) }
+	.got.plt : { BYTE(0) }
 }
--- linux-ein-5.4.0.orig/arch/riscv/kernel/perf_callchain.c
+++ linux-ein-5.4.0/arch/riscv/kernel/perf_callchain.c
@@ -60,10 +60,11 @@
 void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
 			 struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	unsigned long fp = 0;
 
 	/* RISC-V does not support perf in guest mode. */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+	if (guest_cbs && guest_cbs->is_in_guest())
 		return;
 
 	fp = regs->s0;
@@ -76,7 +77,7 @@
 
 bool fill_callchain(unsigned long pc, void *entry)
 {
-	return perf_callchain_store(entry, pc);
+	return perf_callchain_store(entry, pc) == 0;
 }
 
 void notrace walk_stackframe(struct task_struct *task,
@@ -84,8 +85,10 @@
 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 			   struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
 	/* RISC-V does not support perf in guest mode. */
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		pr_warn("RISC-V does not support perf in guest mode!");
 		return;
 	}
--- linux-ein-5.4.0.orig/arch/riscv/kernel/process.c
+++ linux-ein-5.4.0/arch/riscv/kernel/process.c
@@ -99,11 +99,13 @@
 	return 0;
 }
 
-int copy_thread(unsigned long clone_flags, unsigned long usp,
-	unsigned long arg, struct task_struct *p)
+int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
+	unsigned long arg, struct task_struct *p, unsigned long tls)
 {
 	struct pt_regs *childregs = task_pt_regs(p);
 
+	memset(&p->thread.s, 0, sizeof(p->thread.s));
+
 	/* p->thread holds context to be restored by __switch_to() */
 	if (unlikely(p->flags & PF_KTHREAD)) {
 		/* Kernel thread */
@@ -120,7 +122,7 @@
 		if (usp) /* User fork */
 			childregs->sp = usp;
 		if (clone_flags & CLONE_SETTLS)
-			childregs->tp = childregs->a5;
+			childregs->tp = tls;
 		childregs->a0 = 0; /* Return value of fork() */
 		p->thread.ra = (unsigned long)ret_from_fork;
 	}
--- linux-ein-5.4.0.orig/arch/riscv/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/riscv/kernel/ptrace.c
@@ -154,6 +154,16 @@
 		if (tracehook_report_syscall_entry(regs))
 			syscall_set_nr(current, regs, -1);
 
+	/*
+	 * Do the secure computing after ptrace; failures should be fast.
+	 * If this fails we might have return value in a0 from seccomp
+	 * (via SECCOMP_RET_ERRNO/TRACE).
+	 */
+	if (secure_computing(NULL) == -1) {
+		syscall_set_nr(current, regs, -1);
+		return;
+	}
+
 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, syscall_get_nr(current, regs));
--- linux-ein-5.4.0.orig/arch/riscv/kernel/smp.c
+++ linux-ein-5.4.0/arch/riscv/kernel/smp.c
@@ -51,7 +51,7 @@
 			return i;
 
 	pr_err("Couldn't find cpu id for hartid [%d]\n", hartid);
-	return i;
+	return -ENOENT;
 }
 
 void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out)
--- linux-ein-5.4.0.orig/arch/riscv/kernel/smpboot.c
+++ linux-ein-5.4.0/arch/riscv/kernel/smpboot.c
@@ -46,6 +46,8 @@
 {
 	int cpuid;
 
+	store_cpu_topology(smp_processor_id());
+
 	/* This covers non-smp usecase mandated by "nosmp" option */
 	if (max_cpus == 0)
 		return;
@@ -142,8 +144,8 @@
 	current->active_mm = mm;
 
 	trap_init();
+	store_cpu_topology(smp_processor_id());
 	notify_cpu_starting(smp_processor_id());
-	update_siblings_masks(smp_processor_id());
 	set_cpu_online(smp_processor_id(), 1);
 	/*
 	 * Remote TLB flushes are ignored while the CPU is offline, so emit
--- linux-ein-5.4.0.orig/arch/riscv/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/riscv/kernel/stacktrace.c
@@ -63,7 +63,7 @@
 
 #else /* !CONFIG_FRAME_POINTER */
 
-static void notrace walk_stackframe(struct task_struct *task,
+void notrace walk_stackframe(struct task_struct *task,
 	struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
 {
 	unsigned long sp, pc;
@@ -89,7 +89,7 @@
 	while (!kstack_end(ksp)) {
 		if (__kernel_text_address(pc) && unlikely(fn(pc, arg)))
 			break;
-		pc = (*ksp++) - 0x4;
+		pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/riscv/kernel/sys_riscv.c
+++ linux-ein-5.4.0/arch/riscv/kernel/sys_riscv.c
@@ -8,6 +8,7 @@
 #include <linux/syscalls.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
+#include <asm-generic/mman-common.h>
 
 static long riscv_sys_mmap(unsigned long addr, unsigned long len,
 			   unsigned long prot, unsigned long flags,
@@ -16,6 +17,7 @@
 {
 	if (unlikely(offset & (~PAGE_MASK >> page_shift_offset)))
 		return -EINVAL;
+
 	return ksys_mmap_pgoff(addr, len, prot, flags, fd,
 			       offset >> (PAGE_SHIFT - page_shift_offset));
 }
--- linux-ein-5.4.0.orig/arch/riscv/kernel/time.c
+++ linux-ein-5.4.0/arch/riscv/kernel/time.c
@@ -4,6 +4,8 @@
  * Copyright (C) 2017 SiFive
  */
 
+#include <linux/of_clk.h>
+#include <linux/clockchips.h>
 #include <linux/clocksource.h>
 #include <linux/delay.h>
 #include <asm/sbi.h>
@@ -24,5 +26,9 @@
 	riscv_timebase = prop;
 
 	lpj_fine = riscv_timebase / HZ;
+
+	of_clk_init(NULL);
 	timer_probe();
+
+	tick_setup_hrtimer_broadcast();
 }
--- linux-ein-5.4.0.orig/arch/riscv/kernel/traps.c
+++ linux-ein-5.4.0/arch/riscv/kernel/traps.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/irq.h>
+#include <linux/kexec.h>
 
 #include <asm/processor.h>
 #include <asm/ptrace.h>
@@ -43,6 +44,9 @@
 
 	ret = notify_die(DIE_OOPS, str, regs, 0, regs->scause, SIGSEGV);
 
+	if (regs && kexec_should_crash(current))
+		crash_kexec(regs);
+
 	bust_spinlocks(0);
 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
 	spin_unlock_irq(&die_lock);
@@ -53,7 +57,7 @@
 	if (panic_on_oops)
 		panic("Fatal exception");
 	if (ret != NOTIFY_STOP)
-		do_exit(SIGSEGV);
+		make_task_dead(SIGSEGV);
 }
 
 void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
--- linux-ein-5.4.0.orig/arch/riscv/kernel/vdso/Makefile
+++ linux-ein-5.4.0/arch/riscv/kernel/vdso/Makefile
@@ -20,6 +20,9 @@
 
 obj-y += vdso.o vdso-syms.o
 CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+ifneq ($(filter vgettimeofday, $(vdso-syms)),)
+CPPFLAGS_vdso.lds += -DHAS_VGETTIMEOFDAY
+endif
 
 # Disable gcov profiling for VDSO code
 GCOV_PROFILE := n
@@ -33,15 +36,15 @@
 	$(call if_changed,vdsold)
 
 # We also create a special relocatable object that should mirror the symbol
-# table and layout of the linked DSO.  With ld -R we can then refer to
-# these symbols in the kernel code rather than hand-coded addresses.
+# table and layout of the linked DSO. With ld --just-symbols we can then
+# refer to these symbols in the kernel code rather than hand-coded addresses.
 
 SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
 	-Wl,--build-id -Wl,--hash-style=both
 $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
 	$(call if_changed,vdsold)
 
-LDFLAGS_vdso-syms.o := -r -R
+LDFLAGS_vdso-syms.o := -r --just-symbols
 $(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE
 	$(call if_changed,ld)
 
@@ -58,7 +61,8 @@
       cmd_vdsold = $(CC) $(KBUILD_CFLAGS) $(call cc-option, -no-pie) -nostdlib -nostartfiles $(SYSCFLAGS_$(@F)) \
                            -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp && \
                    $(CROSS_COMPILE)objcopy \
-                           $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@
+                           $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \
+                   rm $@.tmp
 
 # install commands for the unstripped file
 quiet_cmd_vdso_install = INSTALL $@
--- linux-ein-5.4.0.orig/arch/riscv/kernel/vdso/vdso.lds.S
+++ linux-ein-5.4.0/arch/riscv/kernel/vdso/vdso.lds.S
@@ -62,9 +62,11 @@
 	LINUX_4.15 {
 	global:
 		__vdso_rt_sigreturn;
+#ifdef HAS_VGETTIMEOFDAY
 		__vdso_gettimeofday;
 		__vdso_clock_gettime;
 		__vdso_clock_getres;
+#endif
 		__vdso_getcpu;
 		__vdso_flush_icache;
 	local: *;
--- linux-ein-5.4.0.orig/arch/riscv/lib/tishift.S
+++ linux-ein-5.4.0/arch/riscv/lib/tishift.S
@@ -4,34 +4,73 @@
  */
 
 #include <linux/linkage.h>
+#include <asm-generic/export.h>
 
-ENTRY(__lshrti3)
+SYM_FUNC_START(__lshrti3)
 	beqz	a2, .L1
 	li	a5,64
 	sub	a5,a5,a2
-	addi	sp,sp,-16
 	sext.w	a4,a5
 	blez	a5, .L2
 	sext.w	a2,a2
-	sll	a4,a1,a4
 	srl	a0,a0,a2
-	srl	a1,a1,a2
+	sll	a4,a1,a4
+	srl	a2,a1,a2
 	or	a0,a0,a4
-	sd	a1,8(sp)
-	sd	a0,0(sp)
-	ld	a0,0(sp)
-	ld	a1,8(sp)
-	addi	sp,sp,16
-	ret
+	mv	a1,a2
 .L1:
 	ret
 .L2:
-	negw	a4,a4
-	srl	a1,a1,a4
-	sd	a1,0(sp)
-	sd	zero,8(sp)
-	ld	a0,0(sp)
-	ld	a1,8(sp)
-	addi	sp,sp,16
+	negw	a0,a4
+	li	a2,0
+	srl	a0,a1,a0
+	mv	a1,a2
+	ret
+SYM_FUNC_END(__lshrti3)
+EXPORT_SYMBOL(__lshrti3)
+
+SYM_FUNC_START(__ashrti3)
+	beqz	a2, .L3
+	li	a5,64
+	sub	a5,a5,a2
+	sext.w	a4,a5
+	blez	a5, .L4
+	sext.w	a2,a2
+	srl	a0,a0,a2
+	sll	a4,a1,a4
+	sra	a2,a1,a2
+	or	a0,a0,a4
+	mv	a1,a2
+.L3:
+	ret
+.L4:
+	negw	a0,a4
+	srai	a2,a1,0x3f
+	sra	a0,a1,a0
+	mv	a1,a2
+	ret
+SYM_FUNC_END(__ashrti3)
+EXPORT_SYMBOL(__ashrti3)
+
+SYM_FUNC_START(__ashlti3)
+	beqz	a2, .L5
+	li	a5,64
+	sub	a5,a5,a2
+	sext.w	a4,a5
+	blez	a5, .L6
+	sext.w	a2,a2
+	sll	a1,a1,a2
+	srl	a4,a0,a4
+	sll	a2,a0,a2
+	or	a1,a1,a4
+	mv	a0,a2
+.L5:
+	ret
+.L6:
+	negw	a1,a4
+	li	a2,0
+	sll	a1,a0,a1
+	mv	a0,a2
 	ret
-ENDPROC(__lshrti3)
+SYM_FUNC_END(__ashlti3)
+EXPORT_SYMBOL(__ashlti3)
--- linux-ein-5.4.0.orig/arch/riscv/mm/cacheflush.c
+++ linux-ein-5.4.0/arch/riscv/mm/cacheflush.c
@@ -14,6 +14,7 @@
 {
 	sbi_remote_fence_i(NULL);
 }
+EXPORT_SYMBOL(flush_icache_all);
 
 /*
  * Performs an icache flush for the given MM context.  RISC-V has no direct
@@ -70,6 +71,8 @@
 {
 	struct page *page = pte_page(pte);
 
-	if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+	if (!test_bit(PG_dcache_clean, &page->flags)) {
 		flush_icache_all();
+		set_bit(PG_dcache_clean, &page->flags);
+	}
 }
--- linux-ein-5.4.0.orig/arch/riscv/mm/fault.c
+++ linux-ein-5.4.0/arch/riscv/mm/fault.c
@@ -189,7 +189,7 @@
 		(addr < PAGE_SIZE) ? "NULL pointer dereference" :
 		"paging request", addr);
 	die(regs, "Oops");
-	do_exit(SIGKILL);
+	make_task_dead(SIGKILL);
 
 	/*
 	 * We ran out of memory, call the OOM killer, and return the userspace
--- linux-ein-5.4.0.orig/arch/riscv/mm/init.c
+++ linux-ein-5.4.0/arch/riscv/mm/init.c
@@ -98,7 +98,7 @@
 	for_each_memblock(memory, reg) {
 		phys_addr_t end = reg->base + reg->size;
 
-		if (reg->base <= vmlinux_end && vmlinux_end <= end) {
+		if (reg->base <= vmlinux_start && vmlinux_end <= end) {
 			mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET);
 
 			/*
@@ -115,8 +115,9 @@
 	/* Reserve from the start of the kernel to the end of the kernel */
 	memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
 
-	set_max_mapnr(PFN_DOWN(mem_size));
-	max_low_pfn = PFN_DOWN(memblock_end_of_DRAM());
+	max_pfn = PFN_DOWN(memblock_end_of_DRAM());
+	max_low_pfn = max_pfn;
+	set_max_mapnr(max_low_pfn);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	setup_initrd();
@@ -166,12 +167,11 @@
 
 	ptep = &fixmap_pte[pte_index(addr)];
 
-	if (pgprot_val(prot)) {
+	if (pgprot_val(prot))
 		set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
-	} else {
+	else
 		pte_clear(&init_mm, addr, ptep);
-		local_flush_tlb_page(addr);
-	}
+	local_flush_tlb_page(addr);
 }
 
 static pte_t *__init get_pte_virt(phys_addr_t pa)
--- linux-ein-5.4.0.orig/arch/riscv/mm/tlbflush.c
+++ linux-ein-5.4.0/arch/riscv/mm/tlbflush.c
@@ -2,6 +2,7 @@
 
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/sched.h>
 #include <asm/sbi.h>
 
 void flush_tlb_all(void)
@@ -9,13 +10,33 @@
 	sbi_remote_sfence_vma(NULL, 0, -1);
 }
 
+/*
+ * This function must not be called with cmask being null.
+ * Kernel may panic if cmask is NULL.
+ */
 static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start,
 				  unsigned long size)
 {
 	struct cpumask hmask;
+	unsigned int cpuid;
 
-	riscv_cpuid_to_hartid_mask(cmask, &hmask);
-	sbi_remote_sfence_vma(hmask.bits, start, size);
+	if (cpumask_empty(cmask))
+		return;
+
+	cpuid = get_cpu();
+
+	if (cpumask_any_but(cmask, cpuid) >= nr_cpu_ids) {
+		/* local cpu is the only cpu present in cpumask */
+		if (size <= PAGE_SIZE)
+			local_flush_tlb_page(start);
+		else
+			local_flush_tlb_all();
+	} else {
+		riscv_cpuid_to_hartid_mask(cmask, &hmask);
+		sbi_remote_sfence_vma(cpumask_bits(&hmask), start, size);
+	}
+
+	put_cpu();
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
--- linux-ein-5.4.0.orig/arch/riscv/net/bpf_jit_comp.c
+++ linux-ein-5.4.0/arch/riscv/net/bpf_jit_comp.c
@@ -120,6 +120,11 @@
 	return false;
 }
 
+static void mark_fp(struct rv_jit_context *ctx)
+{
+	__set_bit(RV_CTX_F_SEEN_S5, &ctx->flags);
+}
+
 static void mark_call(struct rv_jit_context *ctx)
 {
 	__set_bit(RV_CTX_F_SEEN_CALL, &ctx->flags);
@@ -596,7 +601,8 @@
 
 	emit(rv_addi(RV_REG_SP, RV_REG_SP, stack_adjust), ctx);
 	/* Set return value. */
-	emit(rv_addi(RV_REG_A0, RV_REG_A5, 0), ctx);
+	if (reg == RV_REG_RA)
+		emit(rv_addi(RV_REG_A0, RV_REG_A5, 0), ctx);
 	emit(rv_jalr(RV_REG_ZERO, reg, 0), ctx);
 }
 
@@ -631,14 +637,14 @@
 		return -1;
 	emit(rv_bgeu(RV_REG_A2, RV_REG_T1, off >> 1), ctx);
 
-	/* if (--TCC < 0)
+	/* if (TCC-- < 0)
 	 *     goto out;
 	 */
 	emit(rv_addi(RV_REG_T1, tcc, -1), ctx);
 	off = (tc_ninsn - (ctx->ninsns - start_insn)) << 2;
 	if (is_13b_check(off, insn))
 		return -1;
-	emit(rv_blt(RV_REG_T1, RV_REG_ZERO, off >> 1), ctx);
+	emit(rv_blt(tcc, RV_REG_ZERO, off >> 1), ctx);
 
 	/* prog = array->ptrs[index];
 	 * if (!prog)
@@ -1307,6 +1313,10 @@
 		emit(rv_ld(rd, 0, RV_REG_T1), ctx);
 		break;
 
+	/* speculation barrier */
+	case BPF_ST | BPF_NOSPEC:
+		break;
+
 	/* ST: *(size *)(dst + off) = imm */
 	case BPF_ST | BPF_MEM | BPF_B:
 		emit_imm(RV_REG_T1, imm, ctx);
@@ -1426,6 +1436,10 @@
 {
 	int stack_adjust = 0, store_offset, bpf_stack_adjust;
 
+	bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16);
+	if (bpf_stack_adjust)
+		mark_fp(ctx);
+
 	if (seen_reg(RV_REG_RA, ctx))
 		stack_adjust += 8;
 	stack_adjust += 8; /* RV_REG_FP */
@@ -1443,7 +1457,6 @@
 		stack_adjust += 8;
 
 	stack_adjust = round_up(stack_adjust, 16);
-	bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16);
 	stack_adjust += bpf_stack_adjust;
 
 	store_offset = stack_adjust - 8;
--- linux-ein-5.4.0.orig/arch/s390/Kconfig
+++ linux-ein-5.4.0/arch/s390/Kconfig
@@ -155,6 +155,7 @@
 	select HAVE_KERNEL_UNCOMPRESSED
 	select HAVE_KERNEL_XZ
 	select HAVE_KPROBES
+	select HAVE_KPROBES_ON_FTRACE
 	select HAVE_KRETPROBES
 	select HAVE_KVM
 	select HAVE_LIVEPATCH
@@ -541,7 +542,6 @@
 config KEXEC_FILE
 	bool "kexec file based system call"
 	select KEXEC_CORE
-	select BUILD_BIN2C
 	depends on CRYPTO
 	depends on CRYPTO_SHA256
 	depends on CRYPTO_SHA256_S390
@@ -920,7 +920,7 @@
 config APPLDATA_BASE
 	def_bool n
 	prompt "Linux - VM Monitor Stream, base infrastructure"
-	depends on PROC_FS
+	depends on PROC_SYSCTL
 	help
 	  This provides a kernel interface for creating and updating z/VM APPLDATA
 	  monitor records. The monitor records are updated at certain time
@@ -1006,3 +1006,11 @@
 	  the KVM hypervisor.
 
 endmenu
+
+config KMSG_IDS
+	def_bool y
+	prompt "Kernel message numbers"
+	help
+	  Select this option if you want to include a message number to the
+	  prefix for kernel messages issued by the s390 architecture and
+	  driver code. See "Documentation/s390/kmsg.txt" for more details.
--- linux-ein-5.4.0.orig/arch/s390/Makefile
+++ linux-ein-5.4.0/arch/s390/Makefile
@@ -31,6 +31,16 @@
 KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-disable-warning, address-of-packed-member)
 KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO),-g)
 KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO_DWARF4), $(call cc-option, -gdwarf-4,))
+
+ifdef CONFIG_CC_IS_GCC
+	ifeq ($(call cc-ifversion, -ge, 1200, y), y)
+		ifeq ($(call cc-ifversion, -lt, 1300, y), y)
+			KBUILD_CFLAGS += $(call cc-disable-warning, array-bounds)
+			KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-disable-warning, array-bounds)
+		endif
+	endif
+endif
+
 UTS_MACHINE	:= s390x
 STACK_SIZE	:= $(if $(CONFIG_KASAN),65536,16384)
 CHECKFLAGS	+= -D__s390__ -D__s390x__
@@ -69,7 +79,7 @@
 #
 cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls
 
-ifeq ($(call cc-option-yn,-mpacked-stack),y)
+ifeq ($(call cc-option-yn,-mpacked-stack -mbackchain -msoft-float),y)
 cflags-$(CONFIG_PACK_STACK)  += -mpacked-stack -D__PACK_STACK
 aflags-$(CONFIG_PACK_STACK)  += -D__PACK_STACK
 endif
@@ -146,7 +156,7 @@
 #KBUILD_IMAGE is necessary for packaging targets like rpm-pkg, deb-pkg...
 KBUILD_IMAGE	:= $(boot)/bzImage
 
-install: vmlinux
+install:
 	$(Q)$(MAKE) $(build)=$(boot) $@
 
 bzImage: vmlinux
--- linux-ein-5.4.0.orig/arch/s390/appldata/appldata_os.c
+++ linux-ein-5.4.0/arch/s390/appldata/appldata_os.c
@@ -75,7 +75,7 @@
 				   (waiting for I/O)               */
 
 	/* per cpu data */
-	struct appldata_os_per_cpu os_cpu[0];
+	struct appldata_os_per_cpu os_cpu[];
 } __attribute__((packed));
 
 static struct appldata_os_data *appldata_os_data;
--- linux-ein-5.4.0.orig/arch/s390/boot/Makefile
+++ linux-ein-5.4.0/arch/s390/boot/Makefile
@@ -37,7 +37,7 @@
 obj-y	:= head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o
 obj-y	+= string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
 obj-y	+= version.o pgm_check_info.o ctype.o text_dma.o
-obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST)	+= uv.o
+obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE))	+= uv.o
 obj-$(CONFIG_RELOCATABLE)	+= machine_kexec_reloc.o
 obj-$(CONFIG_RANDOMIZE_BASE)	+= kaslr.o
 targets	:= bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)
@@ -70,7 +70,7 @@
 $(obj)/startup.a: $(OBJECTS) FORCE
 	$(call if_changed,ar)
 
-install: $(CONFIGURE) $(obj)/bzImage
+install:
 	sh -x  $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/bzImage \
 	      System.map "$(INSTALL_PATH)"
 
--- linux-ein-5.4.0.orig/arch/s390/boot/compressed/decompressor.c
+++ linux-ein-5.4.0/arch/s390/boot/compressed/decompressor.c
@@ -30,13 +30,13 @@
 extern unsigned char _compressed_end[];
 
 #ifdef CONFIG_HAVE_KERNEL_BZIP2
-#define HEAP_SIZE	0x400000
+#define BOOT_HEAP_SIZE	0x400000
 #else
-#define HEAP_SIZE	0x10000
+#define BOOT_HEAP_SIZE	0x10000
 #endif
 
 static unsigned long free_mem_ptr = (unsigned long) _end;
-static unsigned long free_mem_end_ptr = (unsigned long) _end + HEAP_SIZE;
+static unsigned long free_mem_end_ptr = (unsigned long) _end + BOOT_HEAP_SIZE;
 
 #ifdef CONFIG_KERNEL_GZIP
 #include "../../../../lib/decompress_inflate.c"
@@ -62,7 +62,7 @@
 #include "../../../../lib/decompress_unxz.c"
 #endif
 
-#define decompress_offset ALIGN((unsigned long)_end + HEAP_SIZE, PAGE_SIZE)
+#define decompress_offset ALIGN((unsigned long)_end + BOOT_HEAP_SIZE, PAGE_SIZE)
 
 unsigned long mem_safe_offset(void)
 {
@@ -80,6 +80,6 @@
 	void *output = (void *)decompress_offset;
 
 	__decompress(_compressed_start, _compressed_end - _compressed_start,
-		     NULL, NULL, output, 0, NULL, error);
+		     NULL, NULL, output, vmlinux.image_size, NULL, error);
 	return output;
 }
--- linux-ein-5.4.0.orig/arch/s390/boot/compressed/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/s390/boot/compressed/vmlinux.lds.S
@@ -78,10 +78,19 @@
 		_compressed_start = .;
 		*(.vmlinux.bin.compressed)
 		_compressed_end = .;
-		FILL(0xff);
-		. = ALIGN(4096);
 	}
-	. = ALIGN(256);
+
+#define SB_TRAILER_SIZE 32
+	/* Trailer needed for Secure Boot */
+	. += SB_TRAILER_SIZE; /* make sure .sb.trailer does not overwrite the previous section */
+	. = ALIGN(4096) - SB_TRAILER_SIZE;
+	.sb.trailer : {
+		QUAD(0)
+		QUAD(0)
+		QUAD(0)
+		QUAD(0x000000207a49504c)
+	}
+
 	.bss : {
 		_bss = . ;
 		*(.bss)
--- linux-ein-5.4.0.orig/arch/s390/boot/head.S
+++ linux-ein-5.4.0/arch/s390/boot/head.S
@@ -360,22 +360,23 @@
 # the save area and does disabled wait with a faulty address.
 #
 ENTRY(startup_pgm_check_handler)
-	stmg	%r0,%r15,__LC_SAVE_AREA_SYNC
-	la	%r1,4095
-	stctg	%c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1)
-	mvc	__LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC
-	mvc	__LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW
+	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
+	la	%r8,4095
+	stctg	%c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r8)
+	stmg	%r0,%r7,__LC_GPREGS_SAVE_AREA-4095(%r8)
+	mvc	__LC_GPREGS_SAVE_AREA-4095+64(64,%r8),__LC_SAVE_AREA_SYNC
+	mvc	__LC_PSW_SAVE_AREA-4095(16,%r8),__LC_PGM_OLD_PSW
 	mvc	__LC_RETURN_PSW(16),__LC_PGM_OLD_PSW
 	ni	__LC_RETURN_PSW,0xfc	# remove IO and EX bits
 	ni	__LC_RETURN_PSW+1,0xfb	# remove MCHK bit
 	oi	__LC_RETURN_PSW+1,0x2	# set wait state bit
-	larl	%r2,.Lold_psw_disabled_wait
-	stg	%r2,__LC_PGM_NEW_PSW+8
-	l	%r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r2)
+	larl	%r9,.Lold_psw_disabled_wait
+	stg	%r9,__LC_PGM_NEW_PSW+8
+	l	%r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r9)
 	brasl	%r14,print_pgm_check_info
 .Lold_psw_disabled_wait:
-	la	%r1,4095
-	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+	la	%r8,4095
+	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r8)
 	lpswe	__LC_RETURN_PSW		# disabled wait
 .Ldump_info_stack:
 	.long	0x5000 + PAGE_SIZE - STACK_FRAME_OVERHEAD
--- linux-ein-5.4.0.orig/arch/s390/boot/ipl_parm.c
+++ linux-ein-5.4.0/arch/s390/boot/ipl_parm.c
@@ -14,6 +14,7 @@
 char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
 struct ipl_parameter_block __bootdata_preserved(ipl_block);
 int __bootdata_preserved(ipl_block_valid);
+unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL;
 
 unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE;
 unsigned long __bootdata(memory_end);
@@ -27,22 +28,25 @@
 	register unsigned long _addr asm("0") = (unsigned long)addr;
 	register unsigned long _rc asm("1") = 0;
 	unsigned long reg1, reg2;
-	psw_t old = S390_lowcore.program_new_psw;
+	psw_t old;
 
 	asm volatile(
+		"	mvc	0(16,%[psw_old]),0(%[psw_pgm])\n"
 		"	epsw	%0,%1\n"
-		"	st	%0,%[psw_pgm]\n"
-		"	st	%1,%[psw_pgm]+4\n"
+		"	st	%0,0(%[psw_pgm])\n"
+		"	st	%1,4(%[psw_pgm])\n"
 		"	larl	%0,1f\n"
-		"	stg	%0,%[psw_pgm]+8\n"
+		"	stg	%0,8(%[psw_pgm])\n"
 		"	diag	%[addr],%[subcode],0x308\n"
-		"1:	nopr	%%r7\n"
+		"1:	mvc	0(16,%[psw_pgm]),0(%[psw_old])\n"
 		: "=&d" (reg1), "=&a" (reg2),
-		  [psw_pgm] "=Q" (S390_lowcore.program_new_psw),
+		  "+Q" (S390_lowcore.program_new_psw),
+		  "=Q" (old),
 		  [addr] "+d" (_addr), "+d" (_rc)
-		: [subcode] "d" (subcode)
+		: [subcode] "d" (subcode),
+		  [psw_old] "a" (&old),
+		  [psw_pgm] "a" (&S390_lowcore.program_new_psw)
 		: "cc", "memory");
-	S390_lowcore.program_new_psw = old;
 	return _rc;
 }
 
@@ -69,30 +73,44 @@
 static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
 					  const struct ipl_parameter_block *ipb)
 {
-	size_t count;
-	size_t i;
+	const __u8 *scp_data;
+	__u32 scp_data_len;
 	int has_lowercase;
+	size_t count = 0;
+	size_t i;
+
+	switch (ipb->pb0_hdr.pbt) {
+	case IPL_PBT_FCP:
+		scp_data_len = ipb->fcp.scp_data_len;
+		scp_data = ipb->fcp.scp_data;
+		break;
+	case IPL_PBT_NVME:
+		scp_data_len = ipb->nvme.scp_data_len;
+		scp_data = ipb->nvme.scp_data;
+		break;
+	default:
+		goto out;
+	}
 
-	count = min(size - 1, scpdata_length(ipb->fcp.scp_data,
-					     ipb->fcp.scp_data_len));
+	count = min(size - 1, scpdata_length(scp_data, scp_data_len));
 	if (!count)
 		goto out;
 
 	has_lowercase = 0;
 	for (i = 0; i < count; i++) {
-		if (!isascii(ipb->fcp.scp_data[i])) {
+		if (!isascii(scp_data[i])) {
 			count = 0;
 			goto out;
 		}
-		if (!has_lowercase && islower(ipb->fcp.scp_data[i]))
+		if (!has_lowercase && islower(scp_data[i]))
 			has_lowercase = 1;
 	}
 
 	if (has_lowercase)
-		memcpy(dest, ipb->fcp.scp_data, count);
+		memcpy(dest, scp_data, count);
 	else
 		for (i = 0; i < count; i++)
-			dest[i] = tolower(ipb->fcp.scp_data[i]);
+			dest[i] = tolower(scp_data[i]);
 out:
 	dest[count] = '\0';
 	return count;
@@ -114,6 +132,7 @@
 			parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
 		break;
 	case IPL_PBT_FCP:
+	case IPL_PBT_NVME:
 		rc = ipl_block_get_ascii_scpdata(
 			parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
 		break;
@@ -229,6 +248,19 @@
 		if (!strcmp(param, "vmalloc") && val)
 			vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE);
 
+		if (!strcmp(param, "dfltcc")) {
+			if (!strcmp(val, "off"))
+				zlib_dfltcc_support = ZLIB_DFLTCC_DISABLED;
+			else if (!strcmp(val, "on"))
+				zlib_dfltcc_support = ZLIB_DFLTCC_FULL;
+			else if (!strcmp(val, "def_only"))
+				zlib_dfltcc_support = ZLIB_DFLTCC_DEFLATE_ONLY;
+			else if (!strcmp(val, "inf_only"))
+				zlib_dfltcc_support = ZLIB_DFLTCC_INFLATE_ONLY;
+			else if (!strcmp(val, "always"))
+				zlib_dfltcc_support = ZLIB_DFLTCC_FULL_DEBUG;
+		}
+
 		if (!strcmp(param, "noexec")) {
 			rc = kstrtobool(val, &enabled);
 			if (!rc && !enabled)
--- linux-ein-5.4.0.orig/arch/s390/boot/ipl_report.c
+++ linux-ein-5.4.0/arch/s390/boot/ipl_report.c
@@ -57,11 +57,19 @@
 	if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE &&
 	    intersects(INITRD_START, INITRD_SIZE, safe_addr, size))
 		safe_addr = INITRD_START + INITRD_SIZE;
+	if (intersects(safe_addr, size, (unsigned long)comps, comps->len)) {
+		safe_addr = (unsigned long)comps + comps->len;
+		goto repeat;
+	}
 	for_each_rb_entry(comp, comps)
 		if (intersects(safe_addr, size, comp->addr, comp->len)) {
 			safe_addr = comp->addr + comp->len;
 			goto repeat;
 		}
+	if (intersects(safe_addr, size, (unsigned long)certs, certs->len)) {
+		safe_addr = (unsigned long)certs + certs->len;
+		goto repeat;
+	}
 	for_each_rb_entry(cert, certs)
 		if (intersects(safe_addr, size, cert->addr, cert->len)) {
 			safe_addr = cert->addr + cert->len;
--- linux-ein-5.4.0.orig/arch/s390/boot/kaslr.c
+++ linux-ein-5.4.0/arch/s390/boot/kaslr.c
@@ -75,7 +75,7 @@
 		*(unsigned long *) prng.parm_block ^= seed;
 		for (i = 0; i < 16; i++) {
 			cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block,
-				  (char *) entropy, (char *) entropy,
+				  (u8 *) entropy, (u8 *) entropy,
 				  sizeof(entropy));
 			memcpy(prng.parm_block, entropy, sizeof(entropy));
 		}
--- linux-ein-5.4.0.orig/arch/s390/boot/mem_detect.c
+++ linux-ein-5.4.0/arch/s390/boot/mem_detect.c
@@ -70,24 +70,27 @@
 	register unsigned long _ry asm("4") = 0x10; /* storage configuration */
 	int rc = -1;				    /* fail */
 	unsigned long reg1, reg2;
-	psw_t old = S390_lowcore.program_new_psw;
+	psw_t old;
 
 	asm volatile(
+		"	mvc	0(16,%[psw_old]),0(%[psw_pgm])\n"
 		"	epsw	%0,%1\n"
-		"	st	%0,%[psw_pgm]\n"
-		"	st	%1,%[psw_pgm]+4\n"
+		"	st	%0,0(%[psw_pgm])\n"
+		"	st	%1,4(%[psw_pgm])\n"
 		"	larl	%0,1f\n"
-		"	stg	%0,%[psw_pgm]+8\n"
+		"	stg	%0,8(%[psw_pgm])\n"
 		"	diag	%[rx],%[ry],0x260\n"
 		"	ipm	%[rc]\n"
 		"	srl	%[rc],28\n"
-		"1:\n"
+		"1:	mvc	0(16,%[psw_pgm]),0(%[psw_old])\n"
 		: "=&d" (reg1), "=&a" (reg2),
-		  [psw_pgm] "=Q" (S390_lowcore.program_new_psw),
+		  "+Q" (S390_lowcore.program_new_psw),
+		  "=Q" (old),
 		  [rc] "+&d" (rc), [ry] "+d" (_ry)
-		: [rx] "d" (_rx1), "d" (_rx2)
+		: [rx] "d" (_rx1), "d" (_rx2),
+		  [psw_old] "a" (&old),
+		  [psw_pgm] "a" (&S390_lowcore.program_new_psw)
 		: "cc", "memory");
-	S390_lowcore.program_new_psw = old;
 	return rc == 0 ? _ry : -1;
 }
 
@@ -112,24 +115,30 @@
 
 static int tprot(unsigned long addr)
 {
-	unsigned long pgm_addr;
+	unsigned long reg1, reg2;
 	int rc = -EFAULT;
-	psw_t old = S390_lowcore.program_new_psw;
+	psw_t old;
 
-	S390_lowcore.program_new_psw.mask = __extract_psw();
 	asm volatile(
-		"	larl	%[pgm_addr],1f\n"
-		"	stg	%[pgm_addr],%[psw_pgm_addr]\n"
+		"	mvc	0(16,%[psw_old]),0(%[psw_pgm])\n"
+		"	epsw	%[reg1],%[reg2]\n"
+		"	st	%[reg1],0(%[psw_pgm])\n"
+		"	st	%[reg2],4(%[psw_pgm])\n"
+		"	larl	%[reg1],1f\n"
+		"	stg	%[reg1],8(%[psw_pgm])\n"
 		"	tprot	0(%[addr]),0\n"
 		"	ipm	%[rc]\n"
 		"	srl	%[rc],28\n"
-		"1:\n"
-		: [pgm_addr] "=&d"(pgm_addr),
-		  [psw_pgm_addr] "=Q"(S390_lowcore.program_new_psw.addr),
-		  [rc] "+&d"(rc)
-		: [addr] "a"(addr)
+		"1:	mvc	0(16,%[psw_pgm]),0(%[psw_old])\n"
+		: [reg1] "=&d" (reg1),
+		  [reg2] "=&a" (reg2),
+		  [rc] "+&d" (rc),
+		  "=Q" (S390_lowcore.program_new_psw.addr),
+		  "=Q" (old)
+		: [psw_old] "a" (&old),
+		  [psw_pgm] "a" (&S390_lowcore.program_new_psw),
+		  [addr] "a" (addr)
 		: "cc", "memory");
-	S390_lowcore.program_new_psw = old;
 	return rc;
 }
 
--- linux-ein-5.4.0.orig/arch/s390/boot/startup.c
+++ linux-ein-5.4.0/arch/s390/boot/startup.c
@@ -170,6 +170,11 @@
 		handle_relocs(__kaslr_offset);
 
 	if (__kaslr_offset) {
+		/*
+		 * Save KASLR offset for early dumps, before vmcore_info is set.
+		 * Mark as uneven to distinguish from real vmcore_info pointer.
+		 */
+		S390_lowcore.vmcore_info = __kaslr_offset | 0x1UL;
 		/* Clear non-relocated kernel */
 		if (IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED))
 			memset(img, 0, vmlinux.image_size);
--- linux-ein-5.4.0.orig/arch/s390/boot/text_dma.S
+++ linux-ein-5.4.0/arch/s390/boot/text_dma.S
@@ -9,16 +9,6 @@
 #include <asm/errno.h>
 #include <asm/sigp.h>
 
-#ifdef CC_USING_EXPOLINE
-	.pushsection .dma.text.__s390_indirect_jump_r14,"axG"
-__dma__s390_indirect_jump_r14:
-	larl	%r1,0f
-	ex	0,0(%r1)
-	j	.
-0:	br	%r14
-	.popsection
-#endif
-
 	.section .dma.text,"ax"
 /*
  * Simplified version of expoline thunk. The normal thunks can not be used here,
@@ -27,11 +17,10 @@
  * affects a few functions that are not performance-relevant.
  */
 	.macro BR_EX_DMA_r14
-#ifdef CC_USING_EXPOLINE
-	jg	__dma__s390_indirect_jump_r14
-#else
-	br	%r14
-#endif
+	larl	%r1,0f
+	ex	0,0(%r1)
+	j	.
+0:	br	%r14
 	.endm
 
 /*
--- linux-ein-5.4.0.orig/arch/s390/boot/uv.c
+++ linux-ein-5.4.0/arch/s390/boot/uv.c
@@ -3,7 +3,13 @@
 #include <asm/facility.h>
 #include <asm/sections.h>
 
+/* will be used in arch/s390/kernel/uv.c */
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
 int __bootdata_preserved(prot_virt_guest);
+#endif
+#if IS_ENABLED(CONFIG_KVM)
+struct uv_info __bootdata_preserved(uv_info);
+#endif
 
 void uv_query_info(void)
 {
@@ -15,10 +21,25 @@
 	if (!test_facility(158))
 		return;
 
-	if (uv_call(0, (uint64_t)&uvcb))
+	/* rc==0x100 means that there is additional data we do not process */
+	if (uv_call(0, (uint64_t)&uvcb) && uvcb.header.rc != 0x100)
 		return;
 
+	if (IS_ENABLED(CONFIG_KVM)) {
+		memcpy(uv_info.inst_calls_list, uvcb.inst_calls_list, sizeof(uv_info.inst_calls_list));
+		uv_info.uv_base_stor_len = uvcb.uv_base_stor_len;
+		uv_info.guest_base_stor_len = uvcb.conf_base_phys_stor_len;
+		uv_info.guest_virt_base_stor_len = uvcb.conf_base_virt_stor_len;
+		uv_info.guest_virt_var_stor_len = uvcb.conf_virt_var_stor_len;
+		uv_info.guest_cpu_stor_len = uvcb.cpu_stor_len;
+		uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE);
+		uv_info.max_num_sec_conf = uvcb.max_num_sec_conf;
+		uv_info.max_guest_cpus = uvcb.max_guest_cpus;
+	}
+
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
 	if (test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list) &&
 	    test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list))
 		prot_virt_guest = 1;
+#endif
 }
--- linux-ein-5.4.0.orig/arch/s390/configs/debug_defconfig
+++ linux-ein-5.4.0/arch/s390/configs/debug_defconfig
@@ -62,7 +62,6 @@
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 CONFIG_STATIC_KEYS_SELFTEST=y
-CONFIG_REFCOUNT_FULL=y
 CONFIG_LOCK_EVENT_COUNTS=y
 CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
--- linux-ein-5.4.0.orig/arch/s390/crypto/aes_s390.c
+++ linux-ein-5.4.0/arch/s390/crypto/aes_s390.c
@@ -861,7 +861,7 @@
 					     unsigned int nbytes)
 {
 	gw->walk_bytes_remain -= nbytes;
-	scatterwalk_unmap(&gw->walk);
+	scatterwalk_unmap(gw->walk_ptr);
 	scatterwalk_advance(&gw->walk, nbytes);
 	scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain);
 	gw->walk_ptr = NULL;
@@ -936,7 +936,7 @@
 		goto out;
 	}
 
-	scatterwalk_unmap(&gw->walk);
+	scatterwalk_unmap(gw->walk_ptr);
 	gw->walk_ptr = NULL;
 
 	gw->ptr = gw->buf;
--- linux-ein-5.4.0.orig/arch/s390/crypto/arch_random.c
+++ linux-ein-5.4.0/arch/s390/crypto/arch_random.c
@@ -2,122 +2,17 @@
 /*
  * s390 arch random implementation.
  *
- * Copyright IBM Corp. 2017, 2018
+ * Copyright IBM Corp. 2017, 2020
  * Author(s): Harald Freudenberger
- *
- * The s390_arch_random_generate() function may be called from random.c
- * in interrupt context. So this implementation does the best to be very
- * fast. There is a buffer of random data which is asynchronously checked
- * and filled by a workqueue thread.
- * If there are enough bytes in the buffer the s390_arch_random_generate()
- * just delivers these bytes. Otherwise false is returned until the
- * worker thread refills the buffer.
- * The worker fills the rng buffer by pulling fresh entropy from the
- * high quality (but slow) true hardware random generator. This entropy
- * is then spread over the buffer with an pseudo random generator PRNG.
- * As the arch_get_random_seed_long() fetches 8 bytes and the calling
- * function add_interrupt_randomness() counts this as 1 bit entropy the
- * distribution needs to make sure there is in fact 1 bit entropy contained
- * in 8 bytes of the buffer. The current values pull 32 byte entropy
- * and scatter this into a 2048 byte buffer. So 8 byte in the buffer
- * will contain 1 bit of entropy.
- * The worker thread is rescheduled based on the charge level of the
- * buffer but at least with 500 ms delay to avoid too much CPU consumption.
- * So the max. amount of rng data delivered via arch_get_random_seed is
- * limited to 4k bytes per second.
  */
 
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 #include <linux/random.h>
-#include <linux/slab.h>
 #include <linux/static_key.h>
-#include <linux/workqueue.h>
 #include <asm/cpacf.h>
 
 DEFINE_STATIC_KEY_FALSE(s390_arch_random_available);
 
 atomic64_t s390_arch_random_counter = ATOMIC64_INIT(0);
 EXPORT_SYMBOL(s390_arch_random_counter);
-
-#define ARCH_REFILL_TICKS (HZ/2)
-#define ARCH_PRNG_SEED_SIZE 32
-#define ARCH_RNG_BUF_SIZE 2048
-
-static DEFINE_SPINLOCK(arch_rng_lock);
-static u8 *arch_rng_buf;
-static unsigned int arch_rng_buf_idx;
-
-static void arch_rng_refill_buffer(struct work_struct *);
-static DECLARE_DELAYED_WORK(arch_rng_work, arch_rng_refill_buffer);
-
-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes)
-{
-	/* lock rng buffer */
-	if (!spin_trylock(&arch_rng_lock))
-		return false;
-
-	/* try to resolve the requested amount of bytes from the buffer */
-	arch_rng_buf_idx -= nbytes;
-	if (arch_rng_buf_idx < ARCH_RNG_BUF_SIZE) {
-		memcpy(buf, arch_rng_buf + arch_rng_buf_idx, nbytes);
-		atomic64_add(nbytes, &s390_arch_random_counter);
-		spin_unlock(&arch_rng_lock);
-		return true;
-	}
-
-	/* not enough bytes in rng buffer, refill is done asynchronously */
-	spin_unlock(&arch_rng_lock);
-
-	return false;
-}
-EXPORT_SYMBOL(s390_arch_random_generate);
-
-static void arch_rng_refill_buffer(struct work_struct *unused)
-{
-	unsigned int delay = ARCH_REFILL_TICKS;
-
-	spin_lock(&arch_rng_lock);
-	if (arch_rng_buf_idx > ARCH_RNG_BUF_SIZE) {
-		/* buffer is exhausted and needs refill */
-		u8 seed[ARCH_PRNG_SEED_SIZE];
-		u8 prng_wa[240];
-		/* fetch ARCH_PRNG_SEED_SIZE bytes of entropy */
-		cpacf_trng(NULL, 0, seed, sizeof(seed));
-		/* blow this entropy up to ARCH_RNG_BUF_SIZE with PRNG */
-		memset(prng_wa, 0, sizeof(prng_wa));
-		cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED,
-			   &prng_wa, NULL, 0, seed, sizeof(seed));
-		cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN,
-			   &prng_wa, arch_rng_buf, ARCH_RNG_BUF_SIZE, NULL, 0);
-		arch_rng_buf_idx = ARCH_RNG_BUF_SIZE;
-	}
-	delay += (ARCH_REFILL_TICKS * arch_rng_buf_idx) / ARCH_RNG_BUF_SIZE;
-	spin_unlock(&arch_rng_lock);
-
-	/* kick next check */
-	queue_delayed_work(system_long_wq, &arch_rng_work, delay);
-}
-
-static int __init s390_arch_random_init(void)
-{
-	/* all the needed PRNO subfunctions available ? */
-	if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG) &&
-	    cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) {
-
-		/* alloc arch random working buffer */
-		arch_rng_buf = kmalloc(ARCH_RNG_BUF_SIZE, GFP_KERNEL);
-		if (!arch_rng_buf)
-			return -ENOMEM;
-
-		/* kick worker queue job to fill the random buffer */
-		queue_delayed_work(system_long_wq,
-				   &arch_rng_work, ARCH_REFILL_TICKS);
-
-		/* enable arch random to the outside world */
-		static_branch_enable(&s390_arch_random_available);
-	}
-
-	return 0;
-}
-arch_initcall(s390_arch_random_init);
--- linux-ein-5.4.0.orig/arch/s390/crypto/paes_s390.c
+++ linux-ein-5.4.0/arch/s390/crypto/paes_s390.c
@@ -5,7 +5,7 @@
  * s390 implementation of the AES Cipher Algorithm with protected keys.
  *
  * s390 Version:
- *   Copyright IBM Corp. 2017,2019
+ *   Copyright IBM Corp. 2017,2020
  *   Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  *		Harald Freudenberger <freude@de.ibm.com>
  */
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/cpufeature.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <crypto/xts.h>
 #include <asm/cpacf.h>
@@ -31,11 +32,11 @@
  * is called. As paes can handle different kinds of key blobs
  * and padding is also possible, the limits need to be generous.
  */
-#define PAES_MIN_KEYSIZE 64
-#define PAES_MAX_KEYSIZE 256
+#define PAES_MIN_KEYSIZE 16
+#define PAES_MAX_KEYSIZE 320
 
 static u8 *ctrblk;
-static DEFINE_SPINLOCK(ctrblk_lock);
+static DEFINE_MUTEX(ctrblk_lock);
 
 static cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
 
@@ -52,19 +53,46 @@
 	unsigned int keylen;
 };
 
-static inline int _copy_key_to_kb(struct key_blob *kb,
-				  const u8 *key,
-				  unsigned int keylen)
-{
-	if (keylen <= sizeof(kb->keybuf))
+static inline int _key_to_kb(struct key_blob *kb,
+			     const u8 *key,
+			     unsigned int keylen)
+{
+	struct clearkey_header {
+		u8  type;
+		u8  res0[3];
+		u8  version;
+		u8  res1[3];
+		u32 keytype;
+		u32 len;
+	} __packed * h;
+
+	switch (keylen) {
+	case 16:
+	case 24:
+	case 32:
+		/* clear key value, prepare pkey clear key token in keybuf */
+		memset(kb->keybuf, 0, sizeof(kb->keybuf));
+		h = (struct clearkey_header *) kb->keybuf;
+		h->version = 0x02; /* TOKVER_CLEAR_KEY */
+		h->keytype = (keylen - 8) >> 3;
+		h->len = keylen;
+		memcpy(kb->keybuf + sizeof(*h), key, keylen);
+		kb->keylen = sizeof(*h) + keylen;
 		kb->key = kb->keybuf;
-	else {
-		kb->key = kmalloc(keylen, GFP_KERNEL);
-		if (!kb->key)
-			return -ENOMEM;
+		break;
+	default:
+		/* other key material, let pkey handle this */
+		if (keylen <= sizeof(kb->keybuf))
+			kb->key = kb->keybuf;
+		else {
+			kb->key = kmalloc(keylen, GFP_KERNEL);
+			if (!kb->key)
+				return -ENOMEM;
+		}
+		memcpy(kb->key, key, keylen);
+		kb->keylen = keylen;
+		break;
 	}
-	memcpy(kb->key, key, keylen);
-	kb->keylen = keylen;
 
 	return 0;
 }
@@ -81,16 +109,18 @@
 struct s390_paes_ctx {
 	struct key_blob kb;
 	struct pkey_protkey pk;
+	spinlock_t pk_lock;
 	unsigned long fc;
 };
 
 struct s390_pxts_ctx {
 	struct key_blob kb[2];
 	struct pkey_protkey pk[2];
+	spinlock_t pk_lock;
 	unsigned long fc;
 };
 
-static inline int __paes_convert_key(struct key_blob *kb,
+static inline int __paes_keyblob2pkey(struct key_blob *kb,
 				     struct pkey_protkey *pk)
 {
 	int i, ret;
@@ -105,22 +135,18 @@
 	return ret;
 }
 
-static int __paes_set_key(struct s390_paes_ctx *ctx)
+static inline int __paes_convert_key(struct s390_paes_ctx *ctx)
 {
-	unsigned long fc;
+	struct pkey_protkey pkey;
 
-	if (__paes_convert_key(&ctx->kb, &ctx->pk))
+	if (__paes_keyblob2pkey(&ctx->kb, &pkey))
 		return -EINVAL;
 
-	/* Pick the correct function code based on the protected key type */
-	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 :
-		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 :
-		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0;
-
-	/* Check if the function code is available */
-	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
+	spin_lock_bh(&ctx->pk_lock);
+	memcpy(&ctx->pk, &pkey, sizeof(pkey));
+	spin_unlock_bh(&ctx->pk_lock);
 
-	return ctx->fc ? 0 : -EINVAL;
+	return 0;
 }
 
 static int ecb_paes_init(struct crypto_tfm *tfm)
@@ -128,6 +154,7 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	ctx->kb.key = NULL;
+	spin_lock_init(&ctx->pk_lock);
 
 	return 0;
 }
@@ -139,6 +166,24 @@
 	_free_kb_keybuf(&ctx->kb);
 }
 
+static inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx)
+{
+	unsigned long fc;
+
+	if (__paes_convert_key(ctx))
+		return -EINVAL;
+
+	/* Pick the correct function code based on the protected key type */
+	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 :
+		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 :
+		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0;
+
+	/* Check if the function code is available */
+	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
+
+	return ctx->fc ? 0 : -EINVAL;
+}
+
 static int ecb_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 			    unsigned int key_len)
 {
@@ -146,13 +191,14 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	_free_kb_keybuf(&ctx->kb);
-	rc = _copy_key_to_kb(&ctx->kb, in_key, key_len);
+	rc = _key_to_kb(&ctx->kb, in_key, key_len);
 	if (rc)
 		return rc;
 
-	if (__paes_set_key(ctx)) {
+	if (__ecb_paes_set_key(ctx)) {
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		return -EINVAL;
+
 	}
 	return 0;
 }
@@ -164,18 +210,31 @@
 	struct s390_paes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
 	unsigned int nbytes, n, k;
 	int ret;
+	struct {
+		u8 key[MAXPROTKEYSIZE];
+	} param;
 
 	ret = blkcipher_walk_virt(desc, walk);
+	if (ret)
+		return ret;
+
+	spin_lock_bh(&ctx->pk_lock);
+	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+	spin_unlock_bh(&ctx->pk_lock);
+
 	while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
 		/* only use complete blocks */
 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
-		k = cpacf_km(ctx->fc | modifier, ctx->pk.protkey,
+		k = cpacf_km(ctx->fc | modifier, &param,
 			     walk->dst.virt.addr, walk->src.virt.addr, n);
 		if (k)
 			ret = blkcipher_walk_done(desc, walk, nbytes - k);
 		if (k < n) {
-			if (__paes_set_key(ctx) != 0)
+			if (__paes_convert_key(ctx))
 				return blkcipher_walk_done(desc, walk, -EIO);
+			spin_lock_bh(&ctx->pk_lock);
+			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+			spin_unlock_bh(&ctx->pk_lock);
 		}
 	}
 	return ret;
@@ -229,6 +288,7 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	ctx->kb.key = NULL;
+	spin_lock_init(&ctx->pk_lock);
 
 	return 0;
 }
@@ -240,11 +300,11 @@
 	_free_kb_keybuf(&ctx->kb);
 }
 
-static int __cbc_paes_set_key(struct s390_paes_ctx *ctx)
+static inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx)
 {
 	unsigned long fc;
 
-	if (__paes_convert_key(&ctx->kb, &ctx->pk))
+	if (__paes_convert_key(ctx))
 		return -EINVAL;
 
 	/* Pick the correct function code based on the protected key type */
@@ -265,7 +325,7 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	_free_kb_keybuf(&ctx->kb);
-	rc = _copy_key_to_kb(&ctx->kb, in_key, key_len);
+	rc = _key_to_kb(&ctx->kb, in_key, key_len);
 	if (rc)
 		return rc;
 
@@ -288,22 +348,31 @@
 	} param;
 
 	ret = blkcipher_walk_virt(desc, walk);
+	if (ret)
+		return ret;
+
 	memcpy(param.iv, walk->iv, AES_BLOCK_SIZE);
+	spin_lock_bh(&ctx->pk_lock);
 	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+	spin_unlock_bh(&ctx->pk_lock);
+
 	while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
 		/* only use complete blocks */
 		n = nbytes & ~(AES_BLOCK_SIZE - 1);
 		k = cpacf_kmc(ctx->fc | modifier, &param,
 			      walk->dst.virt.addr, walk->src.virt.addr, n);
-		if (k)
+		if (k) {
+			memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
 			ret = blkcipher_walk_done(desc, walk, nbytes - k);
+		}
 		if (k < n) {
-			if (__cbc_paes_set_key(ctx) != 0)
+			if (__paes_convert_key(ctx))
 				return blkcipher_walk_done(desc, walk, -EIO);
+			spin_lock_bh(&ctx->pk_lock);
 			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+			spin_unlock_bh(&ctx->pk_lock);
 		}
 	}
-	memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
 	return ret;
 }
 
@@ -357,6 +426,7 @@
 
 	ctx->kb[0].key = NULL;
 	ctx->kb[1].key = NULL;
+	spin_lock_init(&ctx->pk_lock);
 
 	return 0;
 }
@@ -369,12 +439,27 @@
 	_free_kb_keybuf(&ctx->kb[1]);
 }
 
-static int __xts_paes_set_key(struct s390_pxts_ctx *ctx)
+static inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx)
+{
+	struct pkey_protkey pkey0, pkey1;
+
+	if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) ||
+	    __paes_keyblob2pkey(&ctx->kb[1], &pkey1))
+		return -EINVAL;
+
+	spin_lock_bh(&ctx->pk_lock);
+	memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0));
+	memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1));
+	spin_unlock_bh(&ctx->pk_lock);
+
+	return 0;
+}
+
+static inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx)
 {
 	unsigned long fc;
 
-	if (__paes_convert_key(&ctx->kb[0], &ctx->pk[0]) ||
-	    __paes_convert_key(&ctx->kb[1], &ctx->pk[1]))
+	if (__xts_paes_convert_key(ctx))
 		return -EINVAL;
 
 	if (ctx->pk[0].type != ctx->pk[1].type)
@@ -406,10 +491,10 @@
 
 	_free_kb_keybuf(&ctx->kb[0]);
 	_free_kb_keybuf(&ctx->kb[1]);
-	rc = _copy_key_to_kb(&ctx->kb[0], in_key, key_len);
+	rc = _key_to_kb(&ctx->kb[0], in_key, key_len);
 	if (rc)
 		return rc;
-	rc = _copy_key_to_kb(&ctx->kb[1], in_key + key_len, key_len);
+	rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len);
 	if (rc)
 		return rc;
 
@@ -449,15 +534,19 @@
 	} xts_param;
 
 	ret = blkcipher_walk_virt(desc, walk);
+	if (ret)
+		return ret;
+
 	keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64;
 	offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0;
-retry:
+
 	memset(&pcc_param, 0, sizeof(pcc_param));
 	memcpy(pcc_param.tweak, walk->iv, sizeof(pcc_param.tweak));
+	spin_lock_bh(&ctx->pk_lock);
 	memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen);
-	cpacf_pcc(ctx->fc, pcc_param.key + offset);
-
 	memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen);
+	spin_unlock_bh(&ctx->pk_lock);
+	cpacf_pcc(ctx->fc, pcc_param.key + offset);
 	memcpy(xts_param.init, pcc_param.xts, 16);
 
 	while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
@@ -468,11 +557,15 @@
 		if (k)
 			ret = blkcipher_walk_done(desc, walk, nbytes - k);
 		if (k < n) {
-			if (__xts_paes_set_key(ctx) != 0)
+			if (__xts_paes_convert_key(ctx))
 				return blkcipher_walk_done(desc, walk, -EIO);
-			goto retry;
+			spin_lock_bh(&ctx->pk_lock);
+			memcpy(xts_param.key + offset,
+			       ctx->pk[0].protkey, keylen);
+			spin_unlock_bh(&ctx->pk_lock);
 		}
 	}
+
 	return ret;
 }
 
@@ -525,6 +618,7 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	ctx->kb.key = NULL;
+	spin_lock_init(&ctx->pk_lock);
 
 	return 0;
 }
@@ -536,11 +630,11 @@
 	_free_kb_keybuf(&ctx->kb);
 }
 
-static int __ctr_paes_set_key(struct s390_paes_ctx *ctx)
+static inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx)
 {
 	unsigned long fc;
 
-	if (__paes_convert_key(&ctx->kb, &ctx->pk))
+	if (__paes_convert_key(ctx))
 		return -EINVAL;
 
 	/* Pick the correct function code based on the protected key type */
@@ -562,7 +656,7 @@
 	struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	_free_kb_keybuf(&ctx->kb);
-	rc = _copy_key_to_kb(&ctx->kb, in_key, key_len);
+	rc = _key_to_kb(&ctx->kb, in_key, key_len);
 	if (rc)
 		return rc;
 
@@ -595,47 +689,62 @@
 	u8 buf[AES_BLOCK_SIZE], *ctrptr;
 	unsigned int nbytes, n, k;
 	int ret, locked;
-
-	locked = spin_trylock(&ctrblk_lock);
+	struct {
+		u8 key[MAXPROTKEYSIZE];
+	} param;
 
 	ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE);
+	if (ret)
+		return ret;
+
+	spin_lock_bh(&ctx->pk_lock);
+	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+	spin_unlock_bh(&ctx->pk_lock);
+
+	locked = mutex_trylock(&ctrblk_lock);
+
+
 	while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
 		n = AES_BLOCK_SIZE;
 		if (nbytes >= 2*AES_BLOCK_SIZE && locked)
 			n = __ctrblk_init(ctrblk, walk->iv, nbytes);
 		ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
-		k = cpacf_kmctr(ctx->fc | modifier, ctx->pk.protkey,
-				walk->dst.virt.addr, walk->src.virt.addr,
-				n, ctrptr);
+		k = cpacf_kmctr(ctx->fc | modifier, &param, walk->dst.virt.addr,
+				walk->src.virt.addr, n, ctrptr);
 		if (k) {
 			if (ctrptr == ctrblk)
 				memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE,
 				       AES_BLOCK_SIZE);
 			crypto_inc(walk->iv, AES_BLOCK_SIZE);
-			ret = blkcipher_walk_done(desc, walk, nbytes - n);
+			ret = blkcipher_walk_done(desc, walk, nbytes - k);
 		}
 		if (k < n) {
-			if (__ctr_paes_set_key(ctx) != 0) {
+			if (__paes_convert_key(ctx)) {
 				if (locked)
-					spin_unlock(&ctrblk_lock);
+					mutex_unlock(&ctrblk_lock);
 				return blkcipher_walk_done(desc, walk, -EIO);
 			}
+			spin_lock_bh(&ctx->pk_lock);
+			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+			spin_unlock_bh(&ctx->pk_lock);
 		}
 	}
 	if (locked)
-		spin_unlock(&ctrblk_lock);
+		mutex_unlock(&ctrblk_lock);
 	/*
 	 * final block may be < AES_BLOCK_SIZE, copy only nbytes
 	 */
 	if (nbytes) {
 		while (1) {
-			if (cpacf_kmctr(ctx->fc | modifier,
-					ctx->pk.protkey, buf,
+			if (cpacf_kmctr(ctx->fc | modifier, &param, buf,
 					walk->src.virt.addr, AES_BLOCK_SIZE,
 					walk->iv) == AES_BLOCK_SIZE)
 				break;
-			if (__ctr_paes_set_key(ctx) != 0)
+			if (__paes_convert_key(ctx))
 				return blkcipher_walk_done(desc, walk, -EIO);
+			spin_lock_bh(&ctx->pk_lock);
+			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
+			spin_unlock_bh(&ctx->pk_lock);
 		}
 		memcpy(walk->dst.virt.addr, buf, nbytes);
 		crypto_inc(walk->iv, AES_BLOCK_SIZE);
@@ -697,12 +806,12 @@
 
 static void paes_s390_fini(void)
 {
-	if (ctrblk)
-		free_page((unsigned long) ctrblk);
 	__crypto_unregister_alg(&ctr_paes_alg);
 	__crypto_unregister_alg(&xts_paes_alg);
 	__crypto_unregister_alg(&cbc_paes_alg);
 	__crypto_unregister_alg(&ecb_paes_alg);
+	if (ctrblk)
+		free_page((unsigned long) ctrblk);
 }
 
 static int __init paes_s390_init(void)
@@ -740,14 +849,14 @@
 	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) ||
 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) ||
 	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) {
-		ret = crypto_register_alg(&ctr_paes_alg);
-		if (ret)
-			goto out_err;
 		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
 		if (!ctrblk) {
 			ret = -ENOMEM;
 			goto out_err;
 		}
+		ret = crypto_register_alg(&ctr_paes_alg);
+		if (ret)
+			goto out_err;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/arch/s390/crypto/sha_common.c
+++ linux-ein-5.4.0/arch/s390/crypto/sha_common.c
@@ -74,14 +74,17 @@
 	struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
 	unsigned int bsize = crypto_shash_blocksize(desc->tfm);
 	u64 bits;
-	unsigned int n, mbl_offset;
+	unsigned int n;
+	int mbl_offset;
 
 	n = ctx->count % bsize;
 	bits = ctx->count * 8;
-	mbl_offset = s390_crypto_shash_parmsize(ctx->func) / sizeof(u32);
+	mbl_offset = s390_crypto_shash_parmsize(ctx->func);
 	if (mbl_offset < 0)
 		return -EINVAL;
 
+	mbl_offset = mbl_offset / sizeof(u32);
+
 	/* set total msg bit length (mbl) in CPACF parmblock */
 	switch (ctx->func) {
 	case CPACF_KLMD_SHA_1:
--- linux-ein-5.4.0.orig/arch/s390/hypfs/hypfs_diag.c
+++ linux-ein-5.4.0/arch/s390/hypfs/hypfs_diag.c
@@ -437,7 +437,7 @@
 	int rc;
 
 	if (diag204_probe()) {
-		pr_err("The hardware system does not support hypfs\n");
+		pr_info("The hardware system does not support hypfs\n");
 		return -ENODATA;
 	}
 
--- linux-ein-5.4.0.orig/arch/s390/hypfs/hypfs_vm.c
+++ linux-ein-5.4.0/arch/s390/hypfs/hypfs_vm.c
@@ -20,6 +20,7 @@
 
 static char local_guest[] = "        ";
 static char all_guests[] = "*       ";
+static char *all_groups = all_guests;
 static char *guest_query;
 
 struct diag2fc_data {
@@ -62,10 +63,11 @@
 
 	memcpy(parm_list.userid, query, NAME_LEN);
 	ASCEBC(parm_list.userid, NAME_LEN);
-	parm_list.addr = (unsigned long) addr ;
+	memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
+	ASCEBC(parm_list.aci_grp, NAME_LEN);
+	parm_list.addr = (unsigned long)addr;
 	parm_list.size = size;
 	parm_list.fmt = 0x02;
-	memset(parm_list.aci_grp, 0x40, NAME_LEN);
 	rc = -1;
 
 	diag_stat_inc(DIAG_STAT_X2FC);
--- linux-ein-5.4.0.orig/arch/s390/hypfs/inode.c
+++ linux-ein-5.4.0/arch/s390/hypfs/inode.c
@@ -501,9 +501,9 @@
 	hypfs_vm_exit();
 fail_hypfs_diag_exit:
 	hypfs_diag_exit();
+	pr_err("Initialization of hypfs failed with rc=%i\n", rc);
 fail_dbfs_exit:
 	hypfs_dbfs_exit();
-	pr_err("Initialization of hypfs failed with rc=%i\n", rc);
 	return rc;
 }
 device_initcall(hypfs_init)
--- linux-ein-5.4.0.orig/arch/s390/include/asm/archrandom.h
+++ linux-ein-5.4.0/arch/s390/include/asm/archrandom.h
@@ -2,7 +2,7 @@
 /*
  * Kernel interface for the s390 arch_random_* functions
  *
- * Copyright IBM Corp. 2017
+ * Copyright IBM Corp. 2017, 2022
  *
  * Author: Harald Freudenberger <freude@de.ibm.com>
  *
@@ -14,47 +14,41 @@
 #ifdef CONFIG_ARCH_RANDOM
 
 #include <linux/static_key.h>
+#include <linux/preempt.h>
 #include <linux/atomic.h>
+#include <asm/cpacf.h>
 
 DECLARE_STATIC_KEY_FALSE(s390_arch_random_available);
 extern atomic64_t s390_arch_random_counter;
 
-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes);
-
-static inline bool arch_has_random(void)
-{
-	return false;
-}
-
-static inline bool arch_has_random_seed(void)
-{
-	if (static_branch_likely(&s390_arch_random_available))
-		return true;
-	return false;
-}
-
-static inline bool arch_get_random_long(unsigned long *v)
+static inline bool __must_check arch_get_random_long(unsigned long *v)
 {
 	return false;
 }
 
-static inline bool arch_get_random_int(unsigned int *v)
+static inline bool __must_check arch_get_random_int(unsigned int *v)
 {
 	return false;
 }
 
-static inline bool arch_get_random_seed_long(unsigned long *v)
+static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
 {
-	if (static_branch_likely(&s390_arch_random_available)) {
-		return s390_arch_random_generate((u8 *)v, sizeof(*v));
+	if (static_branch_likely(&s390_arch_random_available) &&
+	    in_task()) {
+		cpacf_trng(NULL, 0, (u8 *)v, sizeof(*v));
+		atomic64_add(sizeof(*v), &s390_arch_random_counter);
+		return true;
 	}
 	return false;
 }
 
-static inline bool arch_get_random_seed_int(unsigned int *v)
+static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
 {
-	if (static_branch_likely(&s390_arch_random_available)) {
-		return s390_arch_random_generate((u8 *)v, sizeof(*v));
+	if (static_branch_likely(&s390_arch_random_available) &&
+	    in_task()) {
+		cpacf_trng(NULL, 0, (u8 *)v, sizeof(*v));
+		atomic64_add(sizeof(*v), &s390_arch_random_counter);
+		return true;
 	}
 	return false;
 }
--- linux-ein-5.4.0.orig/arch/s390/include/asm/cpu_mf.h
+++ linux-ein-5.4.0/arch/s390/include/asm/cpu_mf.h
@@ -109,7 +109,9 @@
 	unsigned int AS:2;	    /* 29-30 PSW address-space control	 */
 	unsigned int I:1;	    /* 31 entry valid or invalid	 */
 	unsigned int CL:2;	    /* 32-33 Configuration Level	 */
-	unsigned int:14;
+	unsigned int H:1;	    /* 34 Host Indicator		 */
+	unsigned int LS:1;	    /* 35 Limited Sampling		 */
+	unsigned int:12;
 	unsigned int prim_asn:16;   /* primary ASN			 */
 	unsigned long long ia;	    /* Instruction Address		 */
 	unsigned long long gpp;     /* Guest Program Parameter		 */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/ctl_reg.h
+++ linux-ein-5.4.0/arch/s390/include/asm/ctl_reg.h
@@ -11,6 +11,8 @@
 #include <linux/bits.h>
 
 #define CR0_CLOCK_COMPARATOR_SIGN	BIT(63 - 10)
+#define CR0_FETCH_PROTECTION_OVERRIDE	BIT(63 - 38)
+#define CR0_STORAGE_PROTECTION_OVERRIDE	BIT(63 - 39)
 #define CR0_EMERGENCY_SIGNAL_SUBMASK	BIT(63 - 49)
 #define CR0_EXTERNAL_CALL_SUBMASK	BIT(63 - 50)
 #define CR0_CLOCK_COMPARATOR_SUBMASK	BIT(63 - 52)
--- linux-ein-5.4.0.orig/arch/s390/include/asm/debug.h
+++ linux-ein-5.4.0/arch/s390/include/asm/debug.h
@@ -4,8 +4,8 @@
  *
  *    Copyright IBM Corp. 1999, 2000
  */
-#ifndef DEBUG_H
-#define DEBUG_H
+#ifndef _ASM_S390_DEBUG_H
+#define _ASM_S390_DEBUG_H
 
 #include <linux/string.h>
 #include <linux/spinlock.h>
@@ -416,4 +416,4 @@
 #define PRINT_FATAL(x...)	printk(KERN_DEBUG PRINTK_HEADER x)
 #endif /* DASD_DEBUG */
 
-#endif /* DEBUG_H */
+#endif /* _ASM_S390_DEBUG_H */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/diag.h
+++ linux-ein-5.4.0/arch/s390/include/asm/diag.h
@@ -298,10 +298,8 @@
 union diag318_info {
 	unsigned long val;
 	struct {
-		unsigned int cpnc : 8;
-		unsigned int cpvc_linux : 24;
-		unsigned char cpvc_distro[3];
-		unsigned char zero;
+		unsigned long cpnc : 8;
+		unsigned long cpvc : 56;
 	};
 };
 
--- linux-ein-5.4.0.orig/arch/s390/include/asm/fpu/api.h
+++ linux-ein-5.4.0/arch/s390/include/asm/fpu/api.h
@@ -76,7 +76,7 @@
 #define KERNEL_VXR_HIGH		(KERNEL_VXR_V16V23|KERNEL_VXR_V24V31)
 
 #define KERNEL_VXR		(KERNEL_VXR_LOW|KERNEL_VXR_HIGH)
-#define KERNEL_FPR		(KERNEL_FPC|KERNEL_VXR_V0V7)
+#define KERNEL_FPR		(KERNEL_FPC|KERNEL_VXR_LOW)
 
 struct kernel_fpu;
 
--- linux-ein-5.4.0.orig/arch/s390/include/asm/ftrace.h
+++ linux-ein-5.4.0/arch/s390/include/asm/ftrace.h
@@ -27,6 +27,7 @@
 
 extern char ftrace_graph_caller_end;
 extern unsigned long ftrace_plt;
+extern void *ftrace_func;
 
 struct dyn_arch_ftrace { };
 
--- linux-ein-5.4.0.orig/arch/s390/include/asm/futex.h
+++ linux-ein-5.4.0/arch/s390/include/asm/futex.h
@@ -16,7 +16,8 @@
 		"3: jl    1b\n"						\
 		"   lhi   %0,0\n"					\
 		"4: sacf  768\n"					\
-		EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)		\
+		EX_TABLE(0b,4b) EX_TABLE(1b,4b)				\
+		EX_TABLE(2b,4b) EX_TABLE(3b,4b)				\
 		: "=d" (ret), "=&d" (oldval), "=&d" (newval),		\
 		  "=m" (*uaddr)						\
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
--- linux-ein-5.4.0.orig/arch/s390/include/asm/gmap.h
+++ linux-ein-5.4.0/arch/s390/include/asm/gmap.h
@@ -9,6 +9,7 @@
 #ifndef _ASM_S390_GMAP_H
 #define _ASM_S390_GMAP_H
 
+#include <linux/radix-tree.h>
 #include <linux/refcount.h>
 
 /* Generic bits for GMAP notification on DAT table entry changes. */
@@ -31,6 +32,7 @@
  * @table: pointer to the page directory
  * @asce: address space control element for gmap page table
  * @pfault_enabled: defines if pfaults are applicable for the guest
+ * @guest_handle: protected virtual machine handle for the ultravisor
  * @host_to_rmap: radix tree with gmap_rmap lists
  * @children: list of shadow gmap structures
  * @pt_list: list of all page tables used in the shadow guest address space
@@ -54,6 +56,8 @@
 	unsigned long asce_end;
 	void *private;
 	bool pfault_enabled;
+	/* only set for protected virtual machines */
+	unsigned long guest_handle;
 	/* Additional data for shadow guest address spaces */
 	struct radix_tree_root host_to_rmap;
 	struct list_head children;
@@ -144,4 +148,6 @@
 
 void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
 			     unsigned long gaddr, unsigned long vmaddr);
+int gmap_mark_unmergeable(void);
+void s390_reset_acc(struct mm_struct *mm);
 #endif /* _ASM_S390_GMAP_H */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/hugetlb.h
+++ linux-ein-5.4.0/arch/s390/include/asm/hugetlb.h
@@ -35,9 +35,11 @@
 static inline int prepare_hugepage_range(struct file *file,
 			unsigned long addr, unsigned long len)
 {
-	if (len & ~HPAGE_MASK)
+	struct hstate *h = hstate_file(file);
+
+	if (len & ~huge_page_mask(h))
 		return -EINVAL;
-	if (addr & ~HPAGE_MASK)
+	if (addr & ~huge_page_mask(h))
 		return -EINVAL;
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/s390/include/asm/ipl.h
+++ linux-ein-5.4.0/arch/s390/include/asm/ipl.h
@@ -21,6 +21,7 @@
 		struct ipl_pb0_common common;
 		struct ipl_pb0_fcp fcp;
 		struct ipl_pb0_ccw ccw;
+		struct ipl_pb0_nvme nvme;
 		char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
 	};
 } __packed __aligned(PAGE_SIZE);
@@ -30,6 +31,11 @@
 #define IPL_BP_FCP_LEN (sizeof(struct ipl_pl_hdr) + \
 			      sizeof(struct ipl_pb0_fcp))
 #define IPL_BP0_FCP_LEN (sizeof(struct ipl_pb0_fcp))
+
+#define IPL_BP_NVME_LEN (sizeof(struct ipl_pl_hdr) + \
+			      sizeof(struct ipl_pb0_nvme))
+#define IPL_BP0_NVME_LEN (sizeof(struct ipl_pb0_nvme))
+
 #define IPL_BP_CCW_LEN (sizeof(struct ipl_pl_hdr) + \
 			      sizeof(struct ipl_pb0_ccw))
 #define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
@@ -59,6 +65,7 @@
 	IPL_TYPE_FCP		= 4,
 	IPL_TYPE_FCP_DUMP	= 8,
 	IPL_TYPE_NSS		= 16,
+	IPL_TYPE_NVME		= 32,
 };
 
 struct ipl_info
@@ -74,6 +81,10 @@
 			u64 lun;
 		} fcp;
 		struct {
+			u32 fid;
+			u32 nsid;
+		} nvme;
+		struct {
 			char name[NSS_NAME_SIZE + 1];
 		} nss;
 	} data;
@@ -109,6 +120,7 @@
 			     unsigned char flags, unsigned short cert);
 int ipl_report_add_certificate(struct ipl_report *report, void *key,
 			       unsigned long addr, unsigned long len);
+bool ipl_get_secureboot(void);
 
 /*
  * DIAG 308 support
--- linux-ein-5.4.0.orig/arch/s390/include/asm/kexec.h
+++ linux-ein-5.4.0/arch/s390/include/asm/kexec.h
@@ -9,6 +9,8 @@
 #ifndef _S390_KEXEC_H
 #define _S390_KEXEC_H
 
+#include <linux/module.h>
+
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/setup.h>
@@ -74,7 +76,21 @@
 int arch_kexec_do_relocs(int r_type, void *loc, unsigned long val,
 			 unsigned long addr);
 
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+	void *ipl_buf;
+};
+
 extern const struct kexec_file_ops s390_kexec_image_ops;
 extern const struct kexec_file_ops s390_kexec_elf_ops;
 
+#ifdef CONFIG_KEXEC_FILE
+struct purgatory_info;
+int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
+				     Elf_Shdr *section,
+				     const Elf_Shdr *relsec,
+				     const Elf_Shdr *symtab);
+#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add
+#endif
 #endif /*_S390_KEXEC_H */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/kprobes.h
+++ linux-ein-5.4.0/arch/s390/include/asm/kprobes.h
@@ -54,7 +54,6 @@
 struct arch_specific_insn {
 	/* copy of original instruction */
 	kprobe_opcode_t *insn;
-	unsigned int is_ftrace_insn : 1;
 };
 
 struct prev_kprobe {
--- linux-ein-5.4.0.orig/arch/s390/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/s390/include/asm/kvm_host.h
@@ -31,12 +31,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 50000
 
 /* s390-specific vcpu->requests bit members */
@@ -122,6 +122,17 @@
 	__u32 reserved;
 };
 
+#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
+			  CR0_MEASUREMENT_ALERT_SUBMASK)
+#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
+			   CR14_EXTERNAL_DAMAGE_SUBMASK)
+
+#define SIDAD_SIZE_MASK		0xff
+#define sida_origin(sie_block) \
+	((sie_block)->sidad & PAGE_MASK)
+#define sida_size(sie_block) \
+	((((sie_block)->sidad & SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)
+
 #define CPUSTAT_STOPPED    0x80000000
 #define CPUSTAT_WAIT       0x10000000
 #define CPUSTAT_ECALL_PEND 0x08000000
@@ -155,7 +166,13 @@
 	__u8	reserved08[4];		/* 0x0008 */
 #define PROG_IN_SIE (1<<0)
 	__u32	prog0c;			/* 0x000c */
-	__u8	reserved10[16];		/* 0x0010 */
+	union {
+		__u8	reserved10[16];		/* 0x0010 */
+		struct {
+			__u64	pv_handle_cpu;
+			__u64	pv_handle_config;
+		};
+	};
 #define PROG_BLOCK_SIE	(1<<0)
 #define PROG_REQUEST	(1<<1)
 	atomic_t prog20;		/* 0x0020 */
@@ -204,10 +221,23 @@
 #define ICPT_PARTEXEC	0x38
 #define ICPT_IOINST	0x40
 #define ICPT_KSS	0x5c
+#define ICPT_MCHKREQ	0x60
+#define ICPT_INT_ENABLE	0x64
+#define ICPT_PV_INSTR	0x68
+#define ICPT_PV_NOTIFY	0x6c
+#define ICPT_PV_PREF	0x70
 	__u8	icptcode;		/* 0x0050 */
 	__u8	icptstatus;		/* 0x0051 */
 	__u16	ihcpu;			/* 0x0052 */
-	__u8	reserved54[2];		/* 0x0054 */
+	__u8	reserved54;		/* 0x0054 */
+#define IICTL_CODE_NONE		 0x00
+#define IICTL_CODE_MCHK		 0x01
+#define IICTL_CODE_EXT		 0x02
+#define IICTL_CODE_IO		 0x03
+#define IICTL_CODE_RESTART	 0x04
+#define IICTL_CODE_SPECIFICATION 0x10
+#define IICTL_CODE_OPERAND	 0x11
+	__u8	iictl;			/* 0x0055 */
 	__u16	ipa;			/* 0x0056 */
 	__u32	ipb;			/* 0x0058 */
 	__u32	scaoh;			/* 0x005c */
@@ -228,9 +258,10 @@
 #define ECB3_RI  0x01
 	__u8    ecb3;			/* 0x0063 */
 	__u32	scaol;			/* 0x0064 */
-	__u8	reserved68;		/* 0x0068 */
+	__u8	sdf;			/* 0x0068 */
 	__u8    epdx;			/* 0x0069 */
-	__u8    reserved6a[2];		/* 0x006a */
+	__u8	cpnc;			/* 0x006a */
+	__u8	reserved6b;		/* 0x006b */
 	__u32	todpr;			/* 0x006c */
 #define GISA_FORMAT1 0x00000001
 	__u32	gd;			/* 0x0070 */
@@ -244,31 +275,58 @@
 #define HPID_KVM	0x4
 #define HPID_VSIE	0x5
 	__u8	hpid;			/* 0x00b8 */
-	__u8	reservedb9[11];		/* 0x00b9 */
-	__u16	extcpuaddr;		/* 0x00c4 */
-	__u16	eic;			/* 0x00c6 */
+	__u8	reservedb9[7];		/* 0x00b9 */
+	union {
+		struct {
+			__u32	eiparams;	/* 0x00c0 */
+			__u16	extcpuaddr;	/* 0x00c4 */
+			__u16	eic;		/* 0x00c6 */
+		};
+		__u64	mcic;			/* 0x00c0 */
+	} __packed;
 	__u32	reservedc8;		/* 0x00c8 */
-	__u16	pgmilc;			/* 0x00cc */
-	__u16	iprcc;			/* 0x00ce */
-	__u32	dxc;			/* 0x00d0 */
-	__u16	mcn;			/* 0x00d4 */
-	__u8	perc;			/* 0x00d6 */
-	__u8	peratmid;		/* 0x00d7 */
+	union {
+		struct {
+			__u16	pgmilc;		/* 0x00cc */
+			__u16	iprcc;		/* 0x00ce */
+		};
+		__u32	edc;			/* 0x00cc */
+	} __packed;
+	union {
+		struct {
+			__u32	dxc;		/* 0x00d0 */
+			__u16	mcn;		/* 0x00d4 */
+			__u8	perc;		/* 0x00d6 */
+			__u8	peratmid;	/* 0x00d7 */
+		};
+		__u64	faddr;			/* 0x00d0 */
+	} __packed;
 	__u64	peraddr;		/* 0x00d8 */
 	__u8	eai;			/* 0x00e0 */
 	__u8	peraid;			/* 0x00e1 */
 	__u8	oai;			/* 0x00e2 */
 	__u8	armid;			/* 0x00e3 */
 	__u8	reservede4[4];		/* 0x00e4 */
-	__u64	tecmc;			/* 0x00e8 */
-	__u8	reservedf0[12];		/* 0x00f0 */
+	union {
+		__u64	tecmc;		/* 0x00e8 */
+		struct {
+			__u16	subchannel_id;	/* 0x00e8 */
+			__u16	subchannel_nr;	/* 0x00ea */
+			__u32	io_int_parm;	/* 0x00ec */
+			__u32	io_int_word;	/* 0x00f0 */
+		};
+	} __packed;
+	__u8	reservedf4[8];		/* 0x00f4 */
 #define CRYCB_FORMAT_MASK 0x00000003
 #define CRYCB_FORMAT0 0x00000000
 #define CRYCB_FORMAT1 0x00000001
 #define CRYCB_FORMAT2 0x00000003
 	__u32	crycbd;			/* 0x00fc */
 	__u64	gcr[16];		/* 0x0100 */
-	__u64	gbea;			/* 0x0180 */
+	union {
+		__u64	gbea;		/* 0x0180 */
+		__u64	sidad;
+	};
 	__u8    reserved188[8];		/* 0x0188 */
 	__u64   sdnxo;			/* 0x0190 */
 	__u8    reserved198[8];		/* 0x0198 */
@@ -296,7 +354,9 @@
 struct sie_page {
 	struct kvm_s390_sie_block sie_block;
 	struct mcck_volatile_info mcck_info;	/* 0x0200 */
-	__u8 reserved218[1000];		/* 0x0218 */
+	__u8 reserved218[360];		/* 0x0218 */
+	__u64 pv_grregs[16];		/* 0x0380 */
+	__u8 reserved400[512];		/* 0x0400 */
 	struct kvm_s390_itdb itdb;	/* 0x0600 */
 	__u8 reserved700[2304];		/* 0x0700 */
 };
@@ -470,6 +530,7 @@
 	IRQ_PEND_PFAULT_INIT,
 	IRQ_PEND_EXT_HOST,
 	IRQ_PEND_EXT_SERVICE,
+	IRQ_PEND_EXT_SERVICE_EV,
 	IRQ_PEND_EXT_TIMING,
 	IRQ_PEND_EXT_CPU_TIMER,
 	IRQ_PEND_EXT_CLOCK_COMP,
@@ -514,6 +575,7 @@
 			   (1UL << IRQ_PEND_EXT_TIMING)     | \
 			   (1UL << IRQ_PEND_EXT_HOST)       | \
 			   (1UL << IRQ_PEND_EXT_SERVICE)    | \
+			   (1UL << IRQ_PEND_EXT_SERVICE_EV) | \
 			   (1UL << IRQ_PEND_VIRTIO)         | \
 			   (1UL << IRQ_PEND_PFAULT_INIT)    | \
 			   (1UL << IRQ_PEND_PFAULT_DONE))
@@ -530,6 +592,13 @@
 #define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
 			    (1UL << IRQ_PEND_MCHK_EX))
 
+#define IRQ_PEND_EXT_II_MASK ((1UL << IRQ_PEND_EXT_CPU_TIMER)  | \
+			      (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
+			      (1UL << IRQ_PEND_EXT_EMERGENCY)  | \
+			      (1UL << IRQ_PEND_EXT_EXTERNAL)   | \
+			      (1UL << IRQ_PEND_EXT_SERVICE)    | \
+			      (1UL << IRQ_PEND_EXT_SERVICE_EV))
+
 struct kvm_s390_interrupt_info {
 	struct list_head list;
 	u64	type;
@@ -588,6 +657,7 @@
 
 struct kvm_s390_float_interrupt {
 	unsigned long pending_irqs;
+	unsigned long masked_irqs;
 	spinlock_t lock;
 	struct list_head lists[FIRQ_LIST_COUNT];
 	int counters[FIRQ_MAX_COUNT];
@@ -639,6 +709,11 @@
 	unsigned long last_bp;
 };
 
+struct kvm_s390_pv_vcpu {
+	u64 handle;
+	unsigned long stor_base;
+};
+
 struct kvm_vcpu_arch {
 	struct kvm_s390_sie_block *sie_block;
 	/* if vsie is active, currently executed shadow sie control block */
@@ -667,6 +742,8 @@
 	__u64 cputm_start;
 	bool gs_enabled;
 	bool skey_enabled;
+	struct kvm_s390_pv_vcpu pv;
+	union diag318_info diag318_info;
 };
 
 struct kvm_vm_stat {
@@ -695,9 +772,6 @@
 	bool masked;
 	bool swap;
 	bool suppressible;
-	struct rw_semaphore maps_lock;
-	struct list_head maps;
-	atomic_t nr_maps;
 };
 
 #define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
@@ -840,6 +914,13 @@
 	DECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);
 };
 
+struct kvm_s390_pv {
+	u64 handle;
+	u64 guest_len;
+	unsigned long stor_base;
+	void *stor_var;
+};
+
 struct kvm_arch{
 	void *sca;
 	int use_esca;
@@ -873,8 +954,10 @@
 	atomic64_t cmma_dirty_pages;
 	/* subset of available cpu features enabled by user space */
 	DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
+	/* indexed by vcpu_idx */
 	DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);
 	struct kvm_s390_gisa_interrupt gisa_int;
+	struct kvm_s390_pv pv;
 };
 
 #define KVM_HVA_ERR_BAD		(-1UL)
--- linux-ein-5.4.0.orig/arch/s390/include/asm/lowcore.h
+++ linux-ein-5.4.0/arch/s390/include/asm/lowcore.h
@@ -141,7 +141,9 @@
 
 	/* br %r1 trampoline */
 	__u16	br_r1_trampoline;		/* 0x0400 */
-	__u8	pad_0x0402[0x0e00-0x0402];	/* 0x0402 */
+	__u32	return_lpswe;			/* 0x0402 */
+	__u32	return_mcck_lpswe;		/* 0x0406 */
+	__u8	pad_0x040a[0x0e00-0x040a];	/* 0x040a */
 
 	/*
 	 * 0xe00 contains the address of the IPL Parameter Information
--- linux-ein-5.4.0.orig/arch/s390/include/asm/mmu.h
+++ linux-ein-5.4.0/arch/s390/include/asm/mmu.h
@@ -16,6 +16,8 @@
 	unsigned long asce;
 	unsigned long asce_limit;
 	unsigned long vdso_base;
+	/* The mmu context belongs to a secure guest. */
+	atomic_t is_protected;
 	/*
 	 * The following bitfields need a down_write on the mm
 	 * semaphore when they are written to. As they are only
--- linux-ein-5.4.0.orig/arch/s390/include/asm/mmu_context.h
+++ linux-ein-5.4.0/arch/s390/include/asm/mmu_context.h
@@ -23,6 +23,7 @@
 	INIT_LIST_HEAD(&mm->context.gmap_list);
 	cpumask_clear(&mm->context.cpu_attach_mask);
 	atomic_set(&mm->context.flush_count, 0);
+	atomic_set(&mm->context.is_protected, 0);
 	mm->context.gmap_asce = 0;
 	mm->context.flush_mm = 0;
 	mm->context.compat_mm = test_thread_flag(TIF_31BIT);
--- linux-ein-5.4.0.orig/arch/s390/include/asm/numa.h
+++ linux-ein-5.4.0/arch/s390/include/asm/numa.h
@@ -17,7 +17,6 @@
 
 void numa_setup(void);
 int numa_pfn_to_nid(unsigned long pfn);
-int __node_distance(int a, int b);
 void numa_update_cpu_topology(void);
 
 extern cpumask_t node_to_cpumask_map[MAX_NUMNODES];
--- linux-ein-5.4.0.orig/arch/s390/include/asm/page.h
+++ linux-ein-5.4.0/arch/s390/include/asm/page.h
@@ -20,6 +20,8 @@
 #define PAGE_SIZE	_PAGE_SIZE
 #define PAGE_MASK	_PAGE_MASK
 #define PAGE_DEFAULT_ACC	0
+/* storage-protection override */
+#define PAGE_SPO_ACC		9
 #define PAGE_DEFAULT_KEY	(PAGE_DEFAULT_ACC << 4)
 
 #define HPAGE_SHIFT	20
@@ -33,6 +35,8 @@
 #define ARCH_HAS_PREPARE_HUGEPAGE
 #define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH
 
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+
 #include <asm/setup.h>
 #ifndef __ASSEMBLY__
 
@@ -40,7 +44,7 @@
 
 static inline void storage_key_init_range(unsigned long start, unsigned long end)
 {
-	if (PAGE_DEFAULT_KEY)
+	if (PAGE_DEFAULT_KEY != 0)
 		__storage_key_init_range(start, end);
 }
 
@@ -151,6 +155,11 @@
 #define HAVE_ARCH_FREE_PAGE
 #define HAVE_ARCH_ALLOC_PAGE
 
+#if IS_ENABLED(CONFIG_PGSTE)
+int arch_make_page_accessible(struct page *page);
+#define HAVE_ARCH_MAKE_PAGE_ACCESSIBLE
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #define __PAGE_OFFSET		0x0UL
--- linux-ein-5.4.0.orig/arch/s390/include/asm/pci.h
+++ linux-ein-5.4.0/arch/s390/include/asm/pci.h
@@ -8,6 +8,7 @@
 #include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/iommu.h>
+#include <linux/pci_hotplug.h>
 #include <asm-generic/pci.h>
 #include <asm/pci_clp.h>
 #include <asm/pci_debug.h>
@@ -24,10 +25,16 @@
 int pci_proc_domain(struct pci_bus *);
 
 #define ZPCI_BUS_NR			0	/* default bus number */
-#define ZPCI_DEVFN			0	/* default device number */
 
 #define ZPCI_NR_DMA_SPACES		1
 #define ZPCI_NR_DEVICES			CONFIG_PCI_NR_FUNCTIONS
+#define ZPCI_DOMAIN_BITMAP_SIZE		(1 << 16)
+
+#ifdef PCI
+#if (ZPCI_NR_DEVICES > ZPCI_DOMAIN_BITMAP_SIZE)
+# error ZPCI_NR_DEVICES can not be bigger than ZPCI_DOMAIN_BITMAP_SIZE
+#endif
+#endif /* PCI */
 
 /* PCI Function Controls */
 #define ZPCI_FC_FN_ENABLED		0x80
@@ -95,10 +102,26 @@
 
 struct s390_domain;
 
+#define ZPCI_FUNCTIONS_PER_BUS 256
+struct zpci_bus {
+	struct kref		kref;
+	struct pci_bus		*bus;
+	struct zpci_dev		*function[ZPCI_FUNCTIONS_PER_BUS];
+	struct list_head	resources;
+	struct list_head	bus_next;
+	int			pchid;
+	int			domain_nr;
+	bool			multifunction;
+	enum pci_bus_speed	max_bus_speed;
+};
+
 /* Private data per function */
 struct zpci_dev {
-	struct pci_bus	*bus;
+	struct zpci_bus *zbus;
 	struct list_head entry;		/* list of all zpci_devices, needed for hotplug, etc. */
+	struct list_head bus_next;
+	struct kref kref;
+	struct hotplug_slot hotplug_slot;
 
 	enum zpci_state state;
 	u32		fid;		/* function ID, used by sclp */
@@ -107,7 +130,12 @@
 	u16		pchid;		/* physical channel ID */
 	u8		pfgid;		/* function group ID */
 	u8		pft;		/* pci function type */
-	u16		domain;
+	u8		port;
+	u8		rid_available	: 1;
+	u8		has_hp_slot	: 1;
+	u8		is_physfn	: 1;
+	u8		reserved	: 5;
+	unsigned int	devfn;		/* DEVFN part of the RID*/
 
 	struct mutex lock;
 	u8 pfip[CLP_PFIP_NR_SEGMENTS];	/* pci function internal path */
@@ -167,15 +195,19 @@
 
 extern const struct attribute_group *zpci_attr_groups[];
 extern unsigned int s390_pci_force_floating __initdata;
+extern unsigned int s390_pci_no_rid;
 
 /* -----------------------------------------------------------------------------
   Prototypes
 ----------------------------------------------------------------------------- */
 /* Base stuff */
-int zpci_create_device(struct zpci_dev *);
-void zpci_remove_device(struct zpci_dev *zdev);
+int zpci_create_device(struct zpci_dev *zdev);
+void zpci_remove_device(struct zpci_dev *zdev, bool set_error);
 int zpci_enable_device(struct zpci_dev *);
 int zpci_disable_device(struct zpci_dev *);
+void zpci_device_reserved(struct zpci_dev *zdev);
+bool zpci_is_device_configured(struct zpci_dev *zdev);
+
 int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
 int zpci_unregister_ioat(struct zpci_dev *, u8);
 void zpci_remove_reserved_devices(void);
@@ -183,12 +215,15 @@
 /* CLP */
 int clp_scan_pci_devices(void);
 int clp_rescan_pci_devices(void);
-int clp_rescan_pci_devices_simple(void);
+int clp_rescan_pci_devices_simple(u32 *fid);
 int clp_add_pci_device(u32, u32, int);
 int clp_enable_fh(struct zpci_dev *, u8);
 int clp_disable_fh(struct zpci_dev *);
 int clp_get_state(u32 fid, enum zpci_state *state);
 
+/* UID */
+void update_uid_checking(bool new);
+
 /* IOMMU Interface */
 int zpci_init_iommu(struct zpci_dev *zdev);
 void zpci_destroy_iommu(struct zpci_dev *zdev);
@@ -224,7 +259,14 @@
 /* Helpers */
 static inline struct zpci_dev *to_zpci(struct pci_dev *pdev)
 {
-	return pdev->sysdata;
+	struct zpci_bus *zbus = pdev->sysdata;
+
+	return zbus->function[pdev->devfn];
+}
+
+static inline struct zpci_dev *to_zpci_dev(struct device *dev)
+{
+	return to_zpci(to_pci_dev(dev));
 }
 
 struct zpci_dev *get_zdev_by_fid(u32);
--- linux-ein-5.4.0.orig/arch/s390/include/asm/pci_clp.h
+++ linux-ein-5.4.0/arch/s390/include/asm/pci_clp.h
@@ -93,7 +93,10 @@
 struct clp_rsp_query_pci {
 	struct clp_rsp_hdr hdr;
 	u16 vfn;			/* virtual fn number */
-	u16			:  6;
+	u16			:  3;
+	u16 rid_avail		:  1;
+	u16 is_physfn		:  1;
+	u16 reserved1		:  1;
 	u16 mio_addr_avail	:  1;
 	u16 util_str_avail	:  1;	/* utility string available? */
 	u16 pfgid		:  8;	/* pci function group id */
@@ -102,12 +105,16 @@
 	u16 pchid;
 	__le32 bar[PCI_BAR_COUNT];
 	u8 pfip[CLP_PFIP_NR_SEGMENTS];	/* pci function internal path */
-	u32			: 16;
+	u16			: 12;
+	u16 port		:  4;
 	u8 fmb_len;
 	u8 pft;				/* pci function type */
 	u64 sdma;			/* start dma as */
 	u64 edma;			/* end dma as */
-	u32 reserved[11];
+#define ZPCI_RID_MASK_DEVFN 0x00ff
+	u16 rid;			/* BUS/DEVFN PCI address */
+	u16 reserved0;
+	u32 reserved[10];
 	u32 uid;			/* user defined id */
 	u8 util_str[CLP_UTIL_STR_LEN];	/* utility string */
 	u32 reserved2[16];
--- linux-ein-5.4.0.orig/arch/s390/include/asm/pci_io.h
+++ linux-ein-5.4.0/arch/s390/include/asm/pci_io.h
@@ -8,14 +8,21 @@
 #include <linux/slab.h>
 #include <asm/pci_insn.h>
 
+/* I/O size constraints */
+#define ZPCI_MAX_READ_SIZE	8
+#define ZPCI_MAX_WRITE_SIZE	128
+#define ZPCI_BOUNDARY_SIZE	(1 << 12)
+#define ZPCI_BOUNDARY_MASK	(ZPCI_BOUNDARY_SIZE - 1)
+
 /* I/O Map */
 #define ZPCI_IOMAP_SHIFT		48
-#define ZPCI_IOMAP_ADDR_BASE		0x8000000000000000UL
+#define ZPCI_IOMAP_ADDR_SHIFT		62
+#define ZPCI_IOMAP_ADDR_BASE		(1UL << ZPCI_IOMAP_ADDR_SHIFT)
 #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))
+	(1UL << (ZPCI_IOMAP_ADDR_SHIFT - ZPCI_IOMAP_SHIFT))
 #define ZPCI_IOMAP_ADDR_IDX_MASK						\
-	(~ZPCI_IOMAP_ADDR_OFF_MASK - ZPCI_IOMAP_ADDR_BASE)
+	((ZPCI_IOMAP_ADDR_BASE - 1) & ~ZPCI_IOMAP_ADDR_OFF_MASK)
 
 struct zpci_iomap_entry {
 	u32 fh;
@@ -120,16 +127,18 @@
 int zpci_write_block(volatile void __iomem *dst, const void *src,
 		     unsigned long len);
 
-static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
+static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max)
 {
-	int count = len > max ? max : len, size = 1;
+	int offset = dst & ZPCI_BOUNDARY_MASK;
+	int size;
 
-	while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
-		dst = dst >> 1;
-		src = src >> 1;
-		size = size << 1;
-	}
-	return size;
+	size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max);
+	if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8))
+		return size;
+
+	if (size >= 8)
+		return 8;
+	return rounddown_pow_of_two(size);
 }
 
 static inline int zpci_memcpy_fromio(void *dst,
@@ -139,8 +148,9 @@
 	int size, rc = 0;
 
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) src,
-					       (u64) dst, n, 8);
+		size = zpci_get_max_io_size((u64 __force) src,
+					    (u64) dst, n,
+					    ZPCI_MAX_READ_SIZE);
 		rc = zpci_read_single(dst, src, size);
 		if (rc)
 			break;
@@ -160,8 +170,9 @@
 		return -EINVAL;
 
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) dst,
-					       (u64) src, n, 128);
+		size = zpci_get_max_io_size((u64 __force) dst,
+					    (u64) src, n,
+					    ZPCI_MAX_WRITE_SIZE);
 		if (size > 8) /* main path */
 			rc = zpci_write_block(dst, src, size);
 		else
--- linux-ein-5.4.0.orig/arch/s390/include/asm/percpu.h
+++ linux-ein-5.4.0/arch/s390/include/asm/percpu.h
@@ -29,15 +29,15 @@
 	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__;						\
+	prev__ = READ_ONCE(*ptr__);					\
 	do {								\
 		old__ = prev__;						\
 		new__ = old__ op (val);					\
 		prev__ = cmpxchg(ptr__, old__, new__);			\
 	} while (prev__ != old__);					\
-	preempt_enable();						\
+	preempt_enable_notrace();					\
 	new__;								\
 })
 
@@ -68,7 +68,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)) {		\
@@ -84,7 +84,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)
@@ -95,14 +95,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__;							\
 })
 
@@ -114,14 +114,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")
@@ -136,10 +136,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__;								\
 })
 
@@ -152,10 +152,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__;								\
 })
 
@@ -171,11 +171,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-ein-5.4.0.orig/arch/s390/include/asm/pgalloc.h
+++ linux-ein-5.4.0/arch/s390/include/asm/pgalloc.h
@@ -56,7 +56,12 @@
 		crst_table_init(table, _REGION2_ENTRY_EMPTY);
 	return (p4d_t *) table;
 }
-#define p4d_free(mm, p4d) crst_table_free(mm, (unsigned long *) p4d)
+
+static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
+{
+	if (!mm_p4d_folded(mm))
+		crst_table_free(mm, (unsigned long *) p4d);
+}
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 {
@@ -65,7 +70,12 @@
 		crst_table_init(table, _REGION3_ENTRY_EMPTY);
 	return (pud_t *) table;
 }
-#define pud_free(mm, pud) crst_table_free(mm, (unsigned long *) pud)
+
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
+{
+	if (!mm_pud_folded(mm))
+		crst_table_free(mm, (unsigned long *) pud);
+}
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
@@ -83,6 +93,8 @@
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
+	if (mm_pmd_folded(mm))
+		return;
 	pgtable_pmd_page_dtor(virt_to_page(pmd));
 	crst_table_free(mm, (unsigned long *) pmd);
 }
--- linux-ein-5.4.0.orig/arch/s390/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/s390/include/asm/pgtable.h
@@ -19,6 +19,7 @@
 #include <linux/atomic.h>
 #include <asm/bug.h>
 #include <asm/page.h>
+#include <asm/uv.h>
 
 extern pgd_t swapper_pg_dir[];
 extern void paging_init(void);
@@ -522,6 +523,15 @@
 	return 0;
 }
 
+static inline int mm_is_protected(struct mm_struct *mm)
+{
+#ifdef CONFIG_PGSTE
+	if (unlikely(atomic_read(&mm->context.is_protected)))
+		return 1;
+#endif
+	return 0;
+}
+
 static inline int mm_alloc_pgste(struct mm_struct *mm)
 {
 #ifdef CONFIG_PGSTE
@@ -756,6 +766,12 @@
 	return (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) != 0;
 }
 
+#define pud_write pud_write
+static inline int pud_write(pud_t pud)
+{
+	return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0;
+}
+
 static inline int pmd_dirty(pmd_t pmd)
 {
 	int dirty = 1;
@@ -1071,7 +1087,12 @@
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pte_t *ptep)
 {
-	return ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
+	pte_t res;
+
+	res = ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
+	if (mm_is_protected(mm) && pte_present(res))
+		uv_convert_from_secure(pte_val(res) & PAGE_MASK);
+	return res;
 }
 
 #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
@@ -1083,7 +1104,12 @@
 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
 				     unsigned long addr, pte_t *ptep)
 {
-	return ptep_xchg_direct(vma->vm_mm, addr, ptep, __pte(_PAGE_INVALID));
+	pte_t res;
+
+	res = ptep_xchg_direct(vma->vm_mm, addr, ptep, __pte(_PAGE_INVALID));
+	if (mm_is_protected(vma->vm_mm) && pte_present(res))
+		uv_convert_from_secure(pte_val(res) & PAGE_MASK);
+	return res;
 }
 
 /*
@@ -1098,12 +1124,17 @@
 					    unsigned long addr,
 					    pte_t *ptep, int full)
 {
+	pte_t res;
+
 	if (full) {
-		pte_t pte = *ptep;
+		res = *ptep;
 		*ptep = __pte(_PAGE_INVALID);
-		return pte;
+	} else {
+		res = ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
 	}
-	return ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
+	if (mm_is_protected(mm) && pte_present(res))
+		uv_convert_from_secure(pte_val(res) & PAGE_MASK);
+	return res;
 }
 
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
@@ -1173,8 +1204,6 @@
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t entry)
 {
-	if (!MACHINE_HAS_NX)
-		pte_val(entry) &= ~_PAGE_NOEXEC;
 	if (pte_present(entry))
 		pte_val(entry) &= ~_PAGE_UNUSED;
 	if (mm_has_pgste(mm))
@@ -1191,6 +1220,8 @@
 {
 	pte_t __pte;
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
+	if (!MACHINE_HAS_NX)
+		pte_val(__pte) &= ~_PAGE_NOEXEC;
 	return pte_mkyoung(__pte);
 }
 
@@ -1241,26 +1272,46 @@
 #define pgd_offset(mm, address) pgd_offset_raw(READ_ONCE((mm)->pgd), address)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
+static inline p4d_t *p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd, unsigned long address)
+{
+	if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R1)
+		return (p4d_t *) pgd_deref(pgd) + p4d_index(address);
+	return (p4d_t *) pgdp;
+}
+#define p4d_offset_lockless p4d_offset_lockless
+
+static inline p4d_t *p4d_offset(pgd_t *pgdp, unsigned long address)
+{
+	return p4d_offset_lockless(pgdp, *pgdp, address);
+}
+
+static inline pud_t *pud_offset_lockless(p4d_t *p4dp, p4d_t p4d, unsigned long address)
+{
+	if ((p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R2)
+		return (pud_t *) p4d_deref(p4d) + pud_index(address);
+	return (pud_t *) p4dp;
+}
+#define pud_offset_lockless pud_offset_lockless
+
+static inline pud_t *pud_offset(p4d_t *p4dp, unsigned long address)
 {
-	if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R1)
-		return (p4d_t *) pgd_deref(*pgd) + p4d_index(address);
-	return (p4d_t *) pgd;
+	return pud_offset_lockless(p4dp, *p4dp, address);
 }
+#define pud_offset pud_offset
 
-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
+static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud, unsigned long address)
 {
-	if ((p4d_val(*p4d) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R2)
-		return (pud_t *) p4d_deref(*p4d) + pud_index(address);
-	return (pud_t *) p4d;
+	if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R3)
+		return (pmd_t *) pud_deref(pud) + pmd_index(address);
+	return (pmd_t *) pudp;
 }
+#define pmd_offset_lockless pmd_offset_lockless
 
-static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
+static inline pmd_t *pmd_offset(pud_t *pudp, unsigned long address)
 {
-	if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R3)
-		return (pmd_t *) pud_deref(*pud) + pmd_index(address);
-	return (pmd_t *) pud;
+	return pmd_offset_lockless(pudp, *pudp, address);
 }
+#define pmd_offset pmd_offset
 
 static inline pte_t *pte_offset(pmd_t *pmd, unsigned long address)
 {
--- linux-ein-5.4.0.orig/arch/s390/include/asm/preempt.h
+++ linux-ein-5.4.0/arch/s390/include/asm/preempt.h
@@ -52,10 +52,17 @@
 
 static inline void __preempt_count_add(int val)
 {
-	if (__builtin_constant_p(val) && (val >= -128) && (val <= 127))
-		__atomic_add_const(val, &S390_lowcore.preempt_count);
-	else
-		__atomic_add(val, &S390_lowcore.preempt_count);
+	/*
+	 * With some obscure config options and CONFIG_PROFILE_ALL_BRANCHES
+	 * enabled, gcc 12 fails to handle __builtin_constant_p().
+	 */
+	if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES)) {
+		if (__builtin_constant_p(val) && (val >= -128) && (val <= 127)) {
+			__atomic_add_const(val, &S390_lowcore.preempt_count);
+			return;
+		}
+	}
+	__atomic_add(val, &S390_lowcore.preempt_count);
 }
 
 static inline void __preempt_count_sub(int val)
--- linux-ein-5.4.0.orig/arch/s390/include/asm/processor.h
+++ linux-ein-5.4.0/arch/s390/include/asm/processor.h
@@ -162,6 +162,7 @@
 #define INIT_THREAD {							\
 	.ksp = sizeof(init_stack) + (unsigned long) &init_stack,	\
 	.fpu.regs = (void *) init_task.thread.fpu.fprs,			\
+	.last_break = 1,						\
 }
 
 /*
@@ -214,7 +215,7 @@
 	return sp;
 }
 
-static __no_kasan_or_inline unsigned short stap(void)
+static __always_inline unsigned short stap(void)
 {
 	unsigned short cpu_address;
 
@@ -253,7 +254,7 @@
  * Set PSW mask to specified value, while leaving the
  * PSW addr pointing to the next instruction.
  */
-static __no_kasan_or_inline void __load_psw_mask(unsigned long mask)
+static __always_inline void __load_psw_mask(unsigned long mask)
 {
 	unsigned long addr;
 	psw_t psw;
--- linux-ein-5.4.0.orig/arch/s390/include/asm/qdio.h
+++ linux-ein-5.4.0/arch/s390/include/asm/qdio.h
@@ -227,7 +227,7 @@
  * @sbal: absolute SBAL address
  */
 struct sl_element {
-	unsigned long sbal;
+	u64 sbal;
 } __attribute__ ((packed));
 
 /**
--- linux-ein-5.4.0.orig/arch/s390/include/asm/sclp.h
+++ linux-ein-5.4.0/arch/s390/include/asm/sclp.h
@@ -129,6 +129,8 @@
 int sclp_chp_read_info(struct sclp_chp_info *info);
 int sclp_pci_configure(u32 fid);
 int sclp_pci_deconfigure(u32 fid);
+int sclp_ap_configure(u32 apid);
+int sclp_ap_deconfigure(u32 apid);
 int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid);
 int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
--- linux-ein-5.4.0.orig/arch/s390/include/asm/setup.h
+++ linux-ein-5.4.0/arch/s390/include/asm/setup.h
@@ -8,6 +8,7 @@
 
 #include <linux/bits.h>
 #include <uapi/asm/setup.h>
+#include <linux/build_bug.h>
 
 #define EP_OFFSET		0x10008
 #define EP_STRING		"S390EP"
@@ -38,6 +39,7 @@
 #define MACHINE_FLAG_NX		BIT(15)
 #define MACHINE_FLAG_GS		BIT(16)
 #define MACHINE_FLAG_SCC	BIT(17)
+#define MACHINE_FLAG_PCI_MIO	BIT(18)
 
 #define LPP_MAGIC		BIT(31)
 #define LPP_PID_MASK		_AC(0xffffffff, UL)
@@ -80,6 +82,13 @@
 	char command_line[ARCH_COMMAND_LINE_SIZE];	/* 0x10480 */
 };
 
+extern unsigned int zlib_dfltcc_support;
+#define ZLIB_DFLTCC_DISABLED		0
+#define ZLIB_DFLTCC_FULL		1
+#define ZLIB_DFLTCC_DEFLATE_ONLY	2
+#define ZLIB_DFLTCC_INFLATE_ONLY	3
+#define ZLIB_DFLTCC_FULL_DEBUG		4
+
 extern int noexec_disabled;
 extern int memory_end_set;
 extern unsigned long memory_end;
@@ -105,6 +114,7 @@
 #define MACHINE_HAS_NX		(S390_lowcore.machine_flags & MACHINE_FLAG_NX)
 #define MACHINE_HAS_GS		(S390_lowcore.machine_flags & MACHINE_FLAG_GS)
 #define MACHINE_HAS_SCC		(S390_lowcore.machine_flags & MACHINE_FLAG_SCC)
+#define MACHINE_HAS_PCI_MIO	(S390_lowcore.machine_flags & MACHINE_FLAG_PCI_MIO)
 
 /*
  * Console mode. Override with conmode=
@@ -157,6 +167,12 @@
 	return __kaslr_offset;
 }
 
+static inline u32 gen_lpswe(unsigned long addr)
+{
+	BUILD_BUG_ON(addr > 0xfff);
+	return 0xb2b20000 | addr;
+}
+
 #else /* __ASSEMBLY__ */
 
 #define IPL_DEVICE	(IPL_DEVICE_OFFSET)
--- linux-ein-5.4.0.orig/arch/s390/include/asm/stacktrace.h
+++ linux-ein-5.4.0/arch/s390/include/asm/stacktrace.h
@@ -79,12 +79,16 @@
 	CALL_ARGS_4(arg1, arg2, arg3, arg4);				\
 	register unsigned long r4 asm("6") = (unsigned long)(arg5)
 
-#define CALL_FMT_0 "=&d" (r2) :
-#define CALL_FMT_1 "+&d" (r2) :
-#define CALL_FMT_2 CALL_FMT_1 "d" (r3),
-#define CALL_FMT_3 CALL_FMT_2 "d" (r4),
-#define CALL_FMT_4 CALL_FMT_3 "d" (r5),
-#define CALL_FMT_5 CALL_FMT_4 "d" (r6),
+/*
+ * To keep this simple mark register 2-6 as being changed (volatile)
+ * by the called function, even though register 6 is saved/nonvolatile.
+ */
+#define CALL_FMT_0 "=&d" (r2)
+#define CALL_FMT_1 "+&d" (r2)
+#define CALL_FMT_2 CALL_FMT_1, "+&d" (r3)
+#define CALL_FMT_3 CALL_FMT_2, "+&d" (r4)
+#define CALL_FMT_4 CALL_FMT_3, "+&d" (r5)
+#define CALL_FMT_5 CALL_FMT_4, "+&d" (r6)
 
 #define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
 #define CALL_CLOBBER_4 CALL_CLOBBER_5
@@ -105,10 +109,118 @@
 		"	brasl	14,%[_fn]\n"				\
 		"	la	15,0(%[_prev])\n"			\
 		: [_prev] "=&a" (prev), CALL_FMT_##nr			\
-		  [_stack] "a" (stack),					\
+		: [_stack] "a" (stack),					\
 		  [_bc] "i" (offsetof(struct stack_frame, back_chain)),	\
 		  [_fn] "X" (fn) : CALL_CLOBBER_##nr);			\
 	r2;								\
 })
 
+#define CALL_LARGS_0(...)						\
+	long dummy = 0
+#define CALL_LARGS_1(t1, a1)						\
+	long arg1  = (long)(t1)(a1)
+#define CALL_LARGS_2(t1, a1, t2, a2)					\
+	CALL_LARGS_1(t1, a1);						\
+	long arg2 = (long)(t2)(a2)
+#define CALL_LARGS_3(t1, a1, t2, a2, t3, a3)				\
+	CALL_LARGS_2(t1, a1, t2, a2);					\
+	long arg3 = (long)(t3)(a3)
+#define CALL_LARGS_4(t1, a1, t2, a2, t3, a3, t4, a4)			\
+	CALL_LARGS_3(t1, a1, t2, a2, t3, a3);				\
+	long arg4  = (long)(t4)(a4)
+#define CALL_LARGS_5(t1, a1, t2, a2, t3, a3, t4, a4, t5, a5)		\
+	CALL_LARGS_4(t1, a1, t2, a2, t3, a3, t4, a4);			\
+	long arg5 = (long)(t5)(a5)
+
+#define CALL_REGS_0							\
+	register long r2 asm("2") = dummy
+#define CALL_REGS_1							\
+	register long r2 asm("2") = arg1
+#define CALL_REGS_2							\
+	CALL_REGS_1;							\
+	register long r3 asm("3") = arg2
+#define CALL_REGS_3							\
+	CALL_REGS_2;							\
+	register long r4 asm("4") = arg3
+#define CALL_REGS_4							\
+	CALL_REGS_3;							\
+	register long r5 asm("5") = arg4
+#define CALL_REGS_5							\
+	CALL_REGS_4;							\
+	register long r6 asm("6") = arg5
+
+#define CALL_TYPECHECK_0(...)
+#define CALL_TYPECHECK_1(t, a, ...)					\
+	typecheck(t, a)
+#define CALL_TYPECHECK_2(t, a, ...)					\
+	CALL_TYPECHECK_1(__VA_ARGS__);					\
+	typecheck(t, a)
+#define CALL_TYPECHECK_3(t, a, ...)					\
+	CALL_TYPECHECK_2(__VA_ARGS__);					\
+	typecheck(t, a)
+#define CALL_TYPECHECK_4(t, a, ...)					\
+	CALL_TYPECHECK_3(__VA_ARGS__);					\
+	typecheck(t, a)
+#define CALL_TYPECHECK_5(t, a, ...)					\
+	CALL_TYPECHECK_4(__VA_ARGS__);					\
+	typecheck(t, a)
+
+#define CALL_PARM_0(...) void
+#define CALL_PARM_1(t, a, ...) t
+#define CALL_PARM_2(t, a, ...) t, CALL_PARM_1(__VA_ARGS__)
+#define CALL_PARM_3(t, a, ...) t, CALL_PARM_2(__VA_ARGS__)
+#define CALL_PARM_4(t, a, ...) t, CALL_PARM_3(__VA_ARGS__)
+#define CALL_PARM_5(t, a, ...) t, CALL_PARM_4(__VA_ARGS__)
+#define CALL_PARM_6(t, a, ...) t, CALL_PARM_5(__VA_ARGS__)
+
+/*
+ * Use call_on_stack() to call a function switching to a specified
+ * stack. Proper sign and zero extension of function arguments is
+ * done. Usage:
+ *
+ * rc = call_on_stack(nr, stack, rettype, fn, t1, a1, t2, a2, ...)
+ *
+ * - nr specifies the number of function arguments of fn.
+ * - stack specifies the stack to be used.
+ * - fn is the function to be called.
+ * - rettype is the return type of fn.
+ * - t1, a1, ... are pairs, where t1 must match the type of the first
+ *   argument of fn, t2 the second, etc. a1 is the corresponding
+ *   first function argument (not name), etc.
+ */
+#define call_on_stack(nr, stack, rettype, fn, ...)			\
+({									\
+	rettype (*__fn)(CALL_PARM_##nr(__VA_ARGS__)) = fn;		\
+	unsigned long frame = current_frame_address();			\
+	unsigned long __stack = stack;					\
+	unsigned long prev;						\
+	CALL_LARGS_##nr(__VA_ARGS__);					\
+	CALL_REGS_##nr;							\
+									\
+	CALL_TYPECHECK_##nr(__VA_ARGS__);				\
+	asm volatile(							\
+		"	lgr	%[_prev],15\n"				\
+		"	lg	15,%[_stack]\n"				\
+		"	stg	%[_frame],%[_bc](15)\n"			\
+		"	brasl	14,%[_fn]\n"				\
+		"	lgr	15,%[_prev]\n"				\
+		: [_prev] "=&d" (prev), CALL_FMT_##nr			\
+		: [_stack] "R" (__stack),				\
+		  [_bc] "i" (offsetof(struct stack_frame, back_chain)),	\
+		  [_frame] "d" (frame),					\
+		  [_fn] "X" (__fn) : CALL_CLOBBER_##nr);		\
+	(rettype)r2;							\
+})
+
+#define CALL_ON_STACK_NORETURN(fn, stack)				\
+({									\
+	asm volatile(							\
+		"	la	15,0(%[_stack])\n"			\
+		"	xc	%[_bc](8,15),%[_bc](15)\n"		\
+		"	brasl	14,%[_fn]\n"				\
+		::[_bc] "i" (offsetof(struct stack_frame, back_chain)),	\
+		  [_stack] "a" (stack), [_fn] "X" (fn));		\
+	BUG();								\
+})
+
 #endif /* _ASM_S390_STACKTRACE_H */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/syscall.h
+++ linux-ein-5.4.0/arch/s390/include/asm/syscall.h
@@ -33,7 +33,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,
--- linux-ein-5.4.0.orig/arch/s390/include/asm/timex.h
+++ linux-ein-5.4.0/arch/s390/include/asm/timex.h
@@ -10,8 +10,9 @@
 #ifndef _ASM_S390_TIMEX_H
 #define _ASM_S390_TIMEX_H
 
-#include <asm/lowcore.h>
+#include <linux/preempt.h>
 #include <linux/time64.h>
+#include <asm/lowcore.h>
 
 /* The value of the TOD clock for 1.1.1970. */
 #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
@@ -154,7 +155,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]);
@@ -176,6 +177,7 @@
 {
 	return (cycles_t) get_tod_clock() >> 2;
 }
+#define get_cycles get_cycles
 
 int get_phys_clock(unsigned long *clock);
 void init_cpu_timer(void);
@@ -186,15 +188,18 @@
 /**
  * get_clock_monotonic - returns current time in clock rate units
  *
- * The caller must ensure that preemption is disabled.
  * The clock and tod_clock_base get changed via stop_machine.
- * Therefore preemption must be disabled when calling this
- * function, otherwise the returned value is not guaranteed to
- * be monotonic.
+ * Therefore preemption must be disabled, otherwise the returned
+ * value is not guaranteed to be monotonic.
  */
 static inline unsigned long long get_tod_clock_monotonic(void)
 {
-	return get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
+	unsigned long long tod;
+
+	preempt_disable_notrace();
+	tod = get_tod_clock() - *(unsigned long long *) &tod_clock_base[1];
+	preempt_enable_notrace();
+	return tod;
 }
 
 /**
--- linux-ein-5.4.0.orig/arch/s390/include/asm/topology.h
+++ linux-ein-5.4.0/arch/s390/include/asm/topology.h
@@ -68,11 +68,8 @@
 
 #ifdef CONFIG_NUMA
 
-#define cpu_to_node cpu_to_node
-static inline int cpu_to_node(int cpu)
-{
-	return cpu_topology[cpu].node_id;
-}
+extern int __cpu_to_node(int cpu);
+#define cpu_to_node __cpu_to_node
 
 /* Returns a pointer to the cpumask of CPUs on node 'node'. */
 #define cpumask_of_node cpumask_of_node
@@ -83,8 +80,6 @@
 
 #define pcibus_to_node(bus) __pcibus_to_node(bus)
 
-#define node_distance(a, b) __node_distance(a, b)
-
 #else /* !CONFIG_NUMA */
 
 #define numa_node_id numa_node_id
--- linux-ein-5.4.0.orig/arch/s390/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/s390/include/asm/uaccess.h
@@ -60,54 +60,109 @@
 #define INLINE_COPY_TO_USER
 #endif
 
+unsigned long __must_check
+_copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key);
+
+static __always_inline unsigned long __must_check
+copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key)
+{
+	if (likely(check_copy_size(to, n, false)))
+		n = _copy_from_user_key(to, from, n, key);
+	return n;
+}
+
+unsigned long __must_check
+_copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key);
+
+static __always_inline unsigned long __must_check
+copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key)
+{
+	if (likely(check_copy_size(from, n, true)))
+		n = _copy_to_user_key(to, from, n, key);
+	return n;
+}
+
+union oac {
+	unsigned int val;
+	struct {
+		struct {
+			unsigned short key : 4;
+			unsigned short	   : 4;
+			unsigned short as  : 2;
+			unsigned short	   : 4;
+			unsigned short k   : 1;
+			unsigned short a   : 1;
+		} oac1;
+		struct {
+			unsigned short key : 4;
+			unsigned short	   : 4;
+			unsigned short as  : 2;
+			unsigned short	   : 4;
+			unsigned short k   : 1;
+			unsigned short a   : 1;
+		} oac2;
+	};
+};
+
 #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
 
-#define __put_get_user_asm(to, from, size, spec)		\
-({								\
-	register unsigned long __reg0 asm("0") = spec;		\
-	int __rc;						\
-								\
-	asm volatile(						\
-		"0:	mvcos	%1,%3,%2\n"			\
-		"1:	xr	%0,%0\n"			\
-		"2:\n"						\
-		".pushsection .fixup, \"ax\"\n"			\
-		"3:	lhi	%0,%5\n"			\
-		"	jg	2b\n"				\
-		".popsection\n"					\
-		EX_TABLE(0b,3b) EX_TABLE(1b,3b)			\
-		: "=d" (__rc), "+Q" (*(to))			\
-		: "d" (size), "Q" (*(from)),			\
-		  "d" (__reg0), "K" (-EFAULT)			\
-		: "cc");					\
-	__rc;							\
+#define __put_get_user_asm(to, from, size, oac_spec)			\
+({									\
+	int __rc;							\
+									\
+	asm volatile(							\
+		"	lr	0,%[spec]\n"				\
+		"0:	mvcos	%[_to],%[_from],%[_size]\n"		\
+		"1:	xr	%[rc],%[rc]\n"				\
+		"2:\n"							\
+		".pushsection .fixup, \"ax\"\n"				\
+		"3:	lhi	%[rc],%[retval]\n"			\
+		"	jg	2b\n"					\
+		".popsection\n"						\
+		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
+		: [rc] "=&d" (__rc), [_to] "+Q" (*(to))			\
+		: [_size] "d" (size), [_from] "Q" (*(from)),		\
+		  [retval] "K" (-EFAULT), [spec] "d" (oac_spec.val)	\
+		: "cc", "0");						\
+	__rc;								\
 })
 
+#define __put_user_asm(to, from, size)				\
+	__put_get_user_asm(to, from, size, ((union oac) {	\
+		.oac1.as = PSW_BITS_AS_PRIMARY,			\
+		.oac1.a = 1					\
+	}))
+
+#define __get_user_asm(to, from, size)				\
+	__put_get_user_asm(to, from, size, ((union oac) {	\
+		.oac2.as = PSW_BITS_AS_PRIMARY,			\
+		.oac2.a = 1					\
+	}))							\
+
 static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
 {
-	unsigned long spec = 0x010000UL;
 	int rc;
 
 	switch (size) {
 	case 1:
-		rc = __put_get_user_asm((unsigned char __user *)ptr,
-					(unsigned char *)x,
-					size, spec);
+		rc = __put_user_asm((unsigned char __user *)ptr,
+				    (unsigned char *)x,
+				    size);
 		break;
 	case 2:
-		rc = __put_get_user_asm((unsigned short __user *)ptr,
-					(unsigned short *)x,
-					size, spec);
+		rc = __put_user_asm((unsigned short __user *)ptr,
+				    (unsigned short *)x,
+				    size);
 		break;
 	case 4:
-		rc = __put_get_user_asm((unsigned int __user *)ptr,
-					(unsigned int *)x,
-					size, spec);
+		rc = __put_user_asm((unsigned int __user *)ptr,
+				    (unsigned int *)x,
+				    size);
 		break;
 	case 8:
-		rc = __put_get_user_asm((unsigned long __user *)ptr,
-					(unsigned long *)x,
-					size, spec);
+		rc = __put_user_asm((unsigned long __user *)ptr,
+				    (unsigned long *)x,
+				    size);
 		break;
 	}
 	return rc;
@@ -115,29 +170,28 @@
 
 static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
 {
-	unsigned long spec = 0x01UL;
 	int rc;
 
 	switch (size) {
 	case 1:
-		rc = __put_get_user_asm((unsigned char *)x,
-					(unsigned char __user *)ptr,
-					size, spec);
+		rc = __get_user_asm((unsigned char *)x,
+				    (unsigned char __user *)ptr,
+				    size);
 		break;
 	case 2:
-		rc = __put_get_user_asm((unsigned short *)x,
-					(unsigned short __user *)ptr,
-					size, spec);
+		rc = __get_user_asm((unsigned short *)x,
+				    (unsigned short __user *)ptr,
+				    size);
 		break;
 	case 4:
-		rc = __put_get_user_asm((unsigned int *)x,
-					(unsigned int __user *)ptr,
-					size, spec);
+		rc = __get_user_asm((unsigned int *)x,
+				    (unsigned int __user *)ptr,
+				    size);
 		break;
 	case 8:
-		rc = __put_get_user_asm((unsigned long *)x,
-					(unsigned long __user *)ptr,
-					size, spec);
+		rc = __get_user_asm((unsigned long *)x,
+				    (unsigned long __user *)ptr,
+				    size);
 		break;
 	}
 	return rc;
@@ -276,6 +330,6 @@
 }
 
 int copy_to_user_real(void __user *dest, void *src, unsigned long count);
-void s390_kernel_write(void *dst, const void *src, size_t size);
+void *s390_kernel_write(void *dst, const void *src, size_t size);
 
 #endif /* __S390_UACCESS_H */
--- linux-ein-5.4.0.orig/arch/s390/include/asm/uv.h
+++ linux-ein-5.4.0/arch/s390/include/asm/uv.h
@@ -14,23 +14,67 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/bug.h>
+#include <linux/sched.h>
 #include <asm/page.h>
+#include <asm/gmap.h>
+
+#define UVC_CC_OK	0
+#define UVC_CC_ERROR	1
+#define UVC_CC_BUSY	2
+#define UVC_CC_PARTIAL	3
 
 #define UVC_RC_EXECUTED		0x0001
 #define UVC_RC_INV_CMD		0x0002
 #define UVC_RC_INV_STATE	0x0003
 #define UVC_RC_INV_LEN		0x0005
 #define UVC_RC_NO_RESUME	0x0007
+#define UVC_RC_NEED_DESTROY	0x8000
 
 #define UVC_CMD_QUI			0x0001
+#define UVC_CMD_INIT_UV			0x000f
+#define UVC_CMD_CREATE_SEC_CONF		0x0100
+#define UVC_CMD_DESTROY_SEC_CONF	0x0101
+#define UVC_CMD_CREATE_SEC_CPU		0x0120
+#define UVC_CMD_DESTROY_SEC_CPU		0x0121
+#define UVC_CMD_CONV_TO_SEC_STOR	0x0200
+#define UVC_CMD_CONV_FROM_SEC_STOR	0x0201
+#define UVC_CMD_SET_SEC_CONF_PARAMS	0x0300
+#define UVC_CMD_UNPACK_IMG		0x0301
+#define UVC_CMD_VERIFY_IMG		0x0302
+#define UVC_CMD_CPU_RESET		0x0310
+#define UVC_CMD_CPU_RESET_INITIAL	0x0311
+#define UVC_CMD_PREPARE_RESET		0x0320
+#define UVC_CMD_CPU_RESET_CLEAR		0x0321
+#define UVC_CMD_CPU_SET_STATE		0x0330
+#define UVC_CMD_SET_UNSHARE_ALL		0x0340
+#define UVC_CMD_PIN_PAGE_SHARED		0x0341
+#define UVC_CMD_UNPIN_PAGE_SHARED	0x0342
 #define UVC_CMD_SET_SHARED_ACCESS	0x1000
 #define UVC_CMD_REMOVE_SHARED_ACCESS	0x1001
 
 /* Bits in installed uv calls */
 enum uv_cmds_inst {
 	BIT_UVC_CMD_QUI = 0,
+	BIT_UVC_CMD_INIT_UV = 1,
+	BIT_UVC_CMD_CREATE_SEC_CONF = 2,
+	BIT_UVC_CMD_DESTROY_SEC_CONF = 3,
+	BIT_UVC_CMD_CREATE_SEC_CPU = 4,
+	BIT_UVC_CMD_DESTROY_SEC_CPU = 5,
+	BIT_UVC_CMD_CONV_TO_SEC_STOR = 6,
+	BIT_UVC_CMD_CONV_FROM_SEC_STOR = 7,
 	BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
 	BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
+	BIT_UVC_CMD_SET_SEC_PARMS = 11,
+	BIT_UVC_CMD_UNPACK_IMG = 13,
+	BIT_UVC_CMD_VERIFY_IMG = 14,
+	BIT_UVC_CMD_CPU_RESET = 15,
+	BIT_UVC_CMD_CPU_RESET_INITIAL = 16,
+	BIT_UVC_CMD_CPU_SET_STATE = 17,
+	BIT_UVC_CMD_PREPARE_RESET = 18,
+	BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET = 19,
+	BIT_UVC_CMD_UNSHARE_ALL = 20,
+	BIT_UVC_CMD_PIN_PAGE_SHARED = 21,
+	BIT_UVC_CMD_UNPIN_PAGE_SHARED = 22,
 };
 
 struct uv_cb_header {
@@ -40,13 +84,127 @@
 	u16 rrc;	/* Return Reason Code */
 } __packed __aligned(8);
 
+/* Query Ultravisor Information */
 struct uv_cb_qui {
 	struct uv_cb_header header;
 	u64 reserved08;
 	u64 inst_calls_list[4];
-	u64 reserved30[15];
+	u64 reserved30[2];
+	u64 uv_base_stor_len;
+	u64 reserved48;
+	u64 conf_base_phys_stor_len;
+	u64 conf_base_virt_stor_len;
+	u64 conf_virt_var_stor_len;
+	u64 cpu_stor_len;
+	u32 reserved70[3];
+	u32 max_num_sec_conf;
+	u64 max_guest_stor_addr;
+	u8  reserved88[158 - 136];
+	u16 max_guest_cpus;
+	u8  reserveda0[200 - 160];
+} __packed __aligned(8);
+
+/* Initialize Ultravisor */
+struct uv_cb_init {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 stor_origin;
+	u64 stor_len;
+	u64 reserved28[4];
+} __packed __aligned(8);
+
+/* Create Guest Configuration */
+struct uv_cb_cgc {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 guest_handle;
+	u64 conf_base_stor_origin;
+	u64 conf_virt_stor_origin;
+	u64 reserved30;
+	u64 guest_stor_origin;
+	u64 guest_stor_len;
+	u64 guest_sca;
+	u64 guest_asce;
+	u64 reserved58[5];
+} __packed __aligned(8);
+
+/* Create Secure CPU */
+struct uv_cb_csc {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 cpu_handle;
+	u64 guest_handle;
+	u64 stor_origin;
+	u8  reserved30[6];
+	u16 num;
+	u64 state_origin;
+	u64 reserved40[4];
+} __packed __aligned(8);
+
+/* Convert to Secure */
+struct uv_cb_cts {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 guest_handle;
+	u64 gaddr;
+} __packed __aligned(8);
+
+/* Convert from Secure / Pin Page Shared */
+struct uv_cb_cfs {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 paddr;
+} __packed __aligned(8);
+
+/* Set Secure Config Parameter */
+struct uv_cb_ssc {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 guest_handle;
+	u64 sec_header_origin;
+	u32 sec_header_len;
+	u32 reserved2c;
+	u64 reserved30[4];
 } __packed __aligned(8);
 
+/* Unpack */
+struct uv_cb_unp {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 guest_handle;
+	u64 gaddr;
+	u64 tweak[2];
+	u64 reserved38[3];
+} __packed __aligned(8);
+
+#define PV_CPU_STATE_OPR	1
+#define PV_CPU_STATE_STP	2
+#define PV_CPU_STATE_CHKSTP	3
+#define PV_CPU_STATE_OPR_LOAD	5
+
+struct uv_cb_cpu_set_state {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 cpu_handle;
+	u8  reserved20[7];
+	u8  state;
+	u64 reserved28[5];
+};
+
+/*
+ * A common UV call struct for calls that take no payload
+ * Examples:
+ * Destroy cpu/config
+ * Verify
+ */
+struct uv_cb_nodata {
+	struct uv_cb_header header;
+	u64 reserved08[2];
+	u64 handle;
+	u64 reserved20[4];
+} __packed __aligned(8);
+
+/* Set Shared Access */
 struct uv_cb_share {
 	struct uv_cb_header header;
 	u64 reserved08[3];
@@ -54,21 +212,76 @@
 	u64 reserved28;
 } __packed __aligned(8);
 
-static inline int uv_call(unsigned long r1, unsigned long r2)
+static inline int __uv_call(unsigned long r1, unsigned long r2)
 {
 	int cc;
 
 	asm volatile(
-		"0:	.insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
-		"		brc	3,0b\n"
-		"		ipm	%[cc]\n"
-		"		srl	%[cc],28\n"
+		"	.insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
+		"	ipm	%[cc]\n"
+		"	srl	%[cc],28\n"
 		: [cc] "=d" (cc)
 		: [r1] "a" (r1), [r2] "a" (r2)
 		: "memory", "cc");
 	return cc;
 }
 
+static inline int uv_call(unsigned long r1, unsigned long r2)
+{
+	int cc;
+
+	do {
+		cc = __uv_call(r1, r2);
+	} while (cc > 1);
+	return cc;
+}
+
+/* Low level uv_call that avoids stalls for long running busy conditions  */
+static inline int uv_call_sched(unsigned long r1, unsigned long r2)
+{
+	int cc;
+
+	do {
+		cc = __uv_call(r1, r2);
+		cond_resched();
+	} while (cc > 1);
+	return cc;
+}
+
+/*
+ * special variant of uv_call that only transports the cpu or guest
+ * handle and the command, like destroy or verify.
+ */
+static inline int uv_cmd_nodata(u64 handle, u16 cmd, u16 *rc, u16 *rrc)
+{
+	struct uv_cb_nodata uvcb = {
+		.header.cmd = cmd,
+		.header.len = sizeof(uvcb),
+		.handle = handle,
+	};
+	int cc;
+
+	WARN(!handle, "No handle provided to Ultravisor call cmd %x\n", cmd);
+	cc = uv_call_sched(0, (u64)&uvcb);
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+	return cc ? -EINVAL : 0;
+}
+
+struct uv_info {
+	unsigned long inst_calls_list[4];
+	unsigned long uv_base_stor_len;
+	unsigned long guest_base_stor_len;
+	unsigned long guest_virt_base_stor_len;
+	unsigned long guest_virt_var_stor_len;
+	unsigned long guest_cpu_stor_len;
+	unsigned long max_sec_stor_addr;
+	unsigned int max_num_sec_conf;
+	unsigned short max_guest_cpus;
+};
+
+extern struct uv_info uv_info;
+
 #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
 extern int prot_virt_guest;
 
@@ -121,11 +334,40 @@
 	return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
 }
 
-void uv_query_info(void);
 #else
 #define is_prot_virt_guest() 0
 static inline int uv_set_shared(unsigned long addr) { return 0; }
 static inline int uv_remove_shared(unsigned long addr) { return 0; }
+#endif
+
+#if IS_ENABLED(CONFIG_KVM)
+extern int prot_virt_host;
+
+static inline int is_prot_virt_host(void)
+{
+	return prot_virt_host;
+}
+
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
+int uv_convert_from_secure(unsigned long paddr);
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
+
+void setup_uv(void);
+void adjust_to_uv_max(unsigned long *vmax);
+#else
+#define is_prot_virt_host() 0
+static inline void setup_uv(void) {}
+static inline void adjust_to_uv_max(unsigned long *vmax) {}
+
+static inline int uv_convert_from_secure(unsigned long paddr)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || IS_ENABLED(CONFIG_KVM)
+void uv_query_info(void);
+#else
 static inline void uv_query_info(void) {}
 #endif
 
--- linux-ein-5.4.0.orig/arch/s390/include/asm/vdso.h
+++ linux-ein-5.4.0/arch/s390/include/asm/vdso.h
@@ -36,6 +36,7 @@
 	__u32 tk_shift;			/* Shift used for xtime_nsec	0x60 */
 	__u32 ts_dir;			/* TOD steering direction	0x64 */
 	__u64 ts_end;			/* TOD steering end		0x68 */
+	__u32 hrtimer_res;		/* hrtimer resolution		0x70 */
 };
 
 struct vdso_per_cpu_data {
--- linux-ein-5.4.0.orig/arch/s390/include/uapi/asm/ipl.h
+++ linux-ein-5.4.0/arch/s390/include/uapi/asm/ipl.h
@@ -27,6 +27,7 @@
 	IPL_PBT_FCP = 0,
 	IPL_PBT_SCP_DATA = 1,
 	IPL_PBT_CCW = 2,
+	IPL_PBT_NVME = 4,
 };
 
 /* IPL Parameter Block 0 with common fields */
@@ -67,6 +68,30 @@
 #define IPL_PB0_FCP_OPT_IPL	0x10
 #define IPL_PB0_FCP_OPT_DUMP	0x20
 
+/* IPL Parameter Block 0 for NVMe */
+struct ipl_pb0_nvme {
+	__u32 len;
+	__u8  pbt;
+	__u8  reserved1[3];
+	__u8  loadparm[8];
+	__u8  reserved2[304];
+	__u8  opt;
+	__u8  reserved3[3];
+	__u32 fid;
+	__u8 reserved4[12];
+	__u32 nsid;
+	__u8 reserved5[4];
+	__u32 bootprog;
+	__u8 reserved6[12];
+	__u64 br_lba;
+	__u32 scp_data_len;
+	__u8  reserved7[260];
+	__u8  scp_data[];
+} __packed;
+
+#define IPL_PB0_NVME_OPT_IPL	0x10
+#define IPL_PB0_NVME_OPT_DUMP	0x20
+
 /* IPL Parameter Block 0 for CCW */
 struct ipl_pb0_ccw {
 	__u32 len;
--- linux-ein-5.4.0.orig/arch/s390/include/uapi/asm/kvm.h
+++ linux-ein-5.4.0/arch/s390/include/uapi/asm/kvm.h
@@ -231,11 +231,13 @@
 #define KVM_SYNC_GSCB   (1UL << 9)
 #define KVM_SYNC_BPBC   (1UL << 10)
 #define KVM_SYNC_ETOKEN (1UL << 11)
+#define KVM_SYNC_DIAG318 (1UL << 12)
 
 #define KVM_SYNC_S390_VALID_FIELDS \
 	(KVM_SYNC_PREFIX | KVM_SYNC_GPRS | KVM_SYNC_ACRS | KVM_SYNC_CRS | \
 	 KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT | KVM_SYNC_VRS | KVM_SYNC_RICCB | \
-	 KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN)
+	 KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN | \
+	 KVM_SYNC_DIAG318)
 
 /* length and alignment of the sdnx as a power of two */
 #define SDNXC 8
@@ -264,7 +266,8 @@
 	__u8 reserved2 : 7;
 	__u8 padding1[51];	/* riccb needs to be 64byte aligned */
 	__u8 riccb[64];		/* runtime instrumentation controls block */
-	__u8 padding2[192];	/* sdnx needs to be 256byte aligned */
+	__u64 diag318;		/* diagnose 0x318 info */
+	__u8 padding2[184];	/* sdnx needs to be 256byte aligned */
 	union {
 		__u8 sdnx[SDNXL];  /* state description annex */
 		struct {
--- linux-ein-5.4.0.orig/arch/s390/include/uapi/asm/pkey.h
+++ linux-ein-5.4.0/arch/s390/include/uapi/asm/pkey.h
@@ -25,10 +25,11 @@
 #define MAXPROTKEYSIZE	64	/* a protected key blob may be up to 64 bytes */
 #define MAXCLRKEYSIZE	32	   /* a clear key value may be up to 32 bytes */
 #define MAXAESCIPHERKEYSIZE 136  /* our aes cipher keys have always 136 bytes */
+#define MINEP11AESKEYBLOBSIZE 256  /* min EP11 AES key blob size  */
+#define MAXEP11AESKEYBLOBSIZE 320  /* max EP11 AES key blob size */
 
-/* Minimum and maximum size of a key blob */
+/* Minimum size of a key blob */
 #define MINKEYBLOBSIZE	SECKEYBLOBSIZE
-#define MAXKEYBLOBSIZE	MAXAESCIPHERKEYSIZE
 
 /* defines for the type field within the pkey_protkey struct */
 #define PKEY_KEYTYPE_AES_128		      1
@@ -39,6 +40,7 @@
 enum pkey_key_type {
 	PKEY_TYPE_CCA_DATA   = (__u32) 1,
 	PKEY_TYPE_CCA_CIPHER = (__u32) 2,
+	PKEY_TYPE_EP11	     = (__u32) 3,
 };
 
 /* the newer ioctls use a pkey_key_size enum for key size information */
@@ -200,7 +202,7 @@
 
 /*
  * Generate secure key, version 2.
- * Generate either a CCA AES secure key or a CCA AES cipher key.
+ * Generate CCA AES secure key, CCA AES cipher key or EP11 AES secure key.
  * There needs to be a list of apqns given with at least one entry in there.
  * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain
  * is not supported. The implementation walks through the list of apqns and
@@ -210,10 +212,13 @@
  * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to
  * generate a list of apqns based on the key type to generate.
  * The keygenflags argument is passed to the low level generation functions
- * individual for the key type and has a key type specific meaning. Currently
- * only CCA AES cipher keys react to this parameter: Use one or more of the
- * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher
- * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
+ * individual for the key type and has a key type specific meaning. When
+ * generating CCA cipher keys you can use one or more of the PKEY_KEYGEN_*
+ * flags to widen the export possibilities. By default a cipher key is
+ * only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
+ * The keygenflag argument for generating an EP11 AES key should either be 0
+ * to use the defaults which are XCP_BLOB_ENCRYPT, XCP_BLOB_DECRYPT and
+ * XCP_BLOB_PROTKEY_EXTRACTABLE or a valid combination of XCP_BLOB_* flags.
  */
 struct pkey_genseck2 {
 	struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets*/
@@ -229,8 +234,8 @@
 
 /*
  * Generate secure key from clear key value, version 2.
- * Construct a CCA AES secure key or CCA AES cipher key from a given clear key
- * value.
+ * Construct an CCA AES secure key, CCA AES cipher key or EP11 AES secure
+ * key from a given clear key value.
  * There needs to be a list of apqns given with at least one entry in there.
  * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain
  * is not supported. The implementation walks through the list of apqns and
@@ -240,10 +245,13 @@
  * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to
  * generate a list of apqns based on the key type to generate.
  * The keygenflags argument is passed to the low level generation functions
- * individual for the key type and has a key type specific meaning. Currently
- * only CCA AES cipher keys react to this parameter: Use one or more of the
- * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher
- * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
+ * individual for the key type and has a key type specific meaning. When
+ * generating CCA cipher keys you can use one or more of the PKEY_KEYGEN_*
+ * flags to widen the export possibilities. By default a cipher key is
+ * only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
+ * The keygenflag argument for generating an EP11 AES key should either be 0
+ * to use the defaults which are XCP_BLOB_ENCRYPT, XCP_BLOB_DECRYPT and
+ * XCP_BLOB_PROTKEY_EXTRACTABLE or a valid combination of XCP_BLOB_* flags.
  */
 struct pkey_clr2seck2 {
 	struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */
@@ -266,14 +274,19 @@
  * with one apqn able to handle this key.
  * The function also checks for the master key verification patterns
  * of the key matching to the current or alternate mkvp of the apqn.
- * Currently CCA AES secure keys and CCA AES cipher keys are supported.
- * The flags field is updated with some additional info about the apqn mkvp
+ * For CCA AES secure keys and CCA AES cipher keys this means to check
+ * the key's mkvp against the current or old mkvp of the apqns. The flags
+ * field is updated with some additional info about the apqn mkvp
  * match: If the current mkvp matches to the key's mkvp then the
  * PKEY_FLAGS_MATCH_CUR_MKVP bit is set, if the alternate mkvp matches to
  * the key's mkvp the PKEY_FLAGS_MATCH_ALT_MKVP is set. For CCA keys the
  * alternate mkvp is the old master key verification pattern.
  * CCA AES secure keys are also checked to have the CPACF export allowed
  * bit enabled (XPRTCPAC) in the kmf1 field.
+ * EP11 keys are also supported and the wkvp of the key is checked against
+ * the current wkvp of the apqns. There is no alternate for this type of
+ * key and so on a match the flag PKEY_FLAGS_MATCH_CUR_MKVP always is set.
+ * EP11 keys are also checked to have XCP_BLOB_PROTKEY_EXTRACTABLE set.
  * The ioctl returns 0 as long as the given or found apqn matches to
  * matches with the current or alternate mkvp to the key's mkvp. If the given
  * apqn does not match or there is no such apqn found, -1 with errno
@@ -313,16 +326,20 @@
 /*
  * Build a list of APQNs based on a key blob given.
  * Is able to find out which type of secure key is given (CCA AES secure
- * key or CCA AES cipher key) and tries to find all matching crypto cards
- * based on the MKVP and maybe other criterias (like CCA AES cipher keys
- * need a CEX5C or higher). The list of APQNs is further filtered by the key's
- * mkvp which needs to match to either the current mkvp or the alternate mkvp
- * (which is the old mkvp on CCA adapters) of the apqns. The flags argument may
- * be used to limit the matching apqns. If the PKEY_FLAGS_MATCH_CUR_MKVP is
- * given, only the current mkvp of each apqn is compared. Likewise with the
- * PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it is assumed to
- * return apqns where either the current or the alternate mkvp
+ * key, CCA AES cipher key or EP11 AES key) and tries to find all matching
+ * crypto cards based on the MKVP and maybe other criterias (like CCA AES
+ * cipher keys need a CEX5C or higher, EP11 keys with BLOB_PKEY_EXTRACTABLE
+ * need a CEX7 and EP11 api version 4). The list of APQNs is further filtered
+ * by the key's mkvp which needs to match to either the current mkvp (CCA and
+ * EP11) or the alternate mkvp (old mkvp, CCA adapters only) of the apqns. The
+ * flags argument may be used to limit the matching apqns. If the
+ * PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current mkvp of each apqn is
+ * compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it
+ * is assumed to return apqns where either the current or the alternate mkvp
  * matches. At least one of the matching flags needs to be given.
+ * The flags argument for EP11 keys has no further action and is currently
+ * ignored (but needs to be given as PKEY_FLAGS_MATCH_CUR_MKVP) as there is only
+ * the wkvp from the key to match against the apqn's wkvp.
  * The list of matching apqns is stored into the space given by the apqns
  * argument and the number of stored entries goes into apqn_entries. If the list
  * is empty (apqn_entries is 0) the apqn_entries field is updated to the number
@@ -356,6 +373,10 @@
  * If both are given, it is assumed to return apqns where either the
  * current or the alternate mkvp matches. If no match flag is given
  * (flags is 0) the mkvp values are ignored for the match process.
+ * For EP11 keys there is only the current wkvp. So if the apqns should also
+ * match to a given wkvp, then the PKEY_FLAGS_MATCH_CUR_MKVP flag should be
+ * set. The wkvp value is 32 bytes but only the leftmost 16 bytes are compared
+ * against the leftmost 16 byte of the wkvp of the apqn.
  * The list of matching apqns is stored into the space given by the apqns
  * argument and the number of stored entries goes into apqn_entries. If the list
  * is empty (apqn_entries is 0) the apqn_entries field is updated to the number
--- linux-ein-5.4.0.orig/arch/s390/include/uapi/asm/zcrypt.h
+++ linux-ein-5.4.0/arch/s390/include/uapi/asm/zcrypt.h
@@ -36,12 +36,12 @@
  * - length(n_modulus) = inputdatalength
  */
 struct ica_rsa_modexpo {
-	char __user  *inputdata;
-	unsigned int  inputdatalength;
-	char __user  *outputdata;
-	unsigned int  outputdatalength;
-	char __user  *b_key;
-	char __user  *n_modulus;
+	__u8 __user  *inputdata;
+	__u32	      inputdatalength;
+	__u8 __user  *outputdata;
+	__u32	      outputdatalength;
+	__u8 __user  *b_key;
+	__u8 __user  *n_modulus;
 };
 
 /**
@@ -59,15 +59,15 @@
  * - length(u_mult_inv) = inputdatalength/2 + 8
  */
 struct ica_rsa_modexpo_crt {
-	char __user  *inputdata;
-	unsigned int  inputdatalength;
-	char __user  *outputdata;
-	unsigned int  outputdatalength;
-	char __user  *bp_key;
-	char __user  *bq_key;
-	char __user  *np_prime;
-	char __user  *nq_prime;
-	char __user  *u_mult_inv;
+	__u8 __user  *inputdata;
+	__u32	      inputdatalength;
+	__u8 __user  *outputdata;
+	__u32	      outputdatalength;
+	__u8 __user  *bp_key;
+	__u8 __user  *bq_key;
+	__u8 __user  *np_prime;
+	__u8 __user  *nq_prime;
+	__u8 __user  *u_mult_inv;
 };
 
 /**
@@ -83,67 +83,67 @@
  *	    key block
  */
 struct CPRBX {
-	unsigned short	cprb_len;	/* CPRB length	      220	 */
-	unsigned char	cprb_ver_id;	/* CPRB version id.   0x02	 */
-	unsigned char	pad_000[3];	/* Alignment pad bytes		 */
-	unsigned char	func_id[2];	/* function id	      0x5432	 */
-	unsigned char	cprb_flags[4];	/* Flags			 */
-	unsigned int	req_parml;	/* request parameter buffer len	 */
-	unsigned int	req_datal;	/* request data buffer		 */
-	unsigned int	rpl_msgbl;	/* reply  message block length	 */
-	unsigned int	rpld_parml;	/* replied parameter block len	 */
-	unsigned int	rpl_datal;	/* reply data block len		 */
-	unsigned int	rpld_datal;	/* replied data block len	 */
-	unsigned int	req_extbl;	/* request extension block len	 */
-	unsigned char	pad_001[4];	/* reserved			 */
-	unsigned int	rpld_extbl;	/* replied extension block len	 */
-	unsigned char	padx000[16 - sizeof(char *)];
-	unsigned char  *req_parmb;	/* request parm block 'address'	 */
-	unsigned char	padx001[16 - sizeof(char *)];
-	unsigned char  *req_datab;	/* request data block 'address'	 */
-	unsigned char	padx002[16 - sizeof(char *)];
-	unsigned char  *rpl_parmb;	/* reply parm block 'address'	 */
-	unsigned char	padx003[16 - sizeof(char *)];
-	unsigned char  *rpl_datab;	/* reply data block 'address'	 */
-	unsigned char	padx004[16 - sizeof(char *)];
-	unsigned char  *req_extb;	/* request extension block 'addr'*/
-	unsigned char	padx005[16 - sizeof(char *)];
-	unsigned char  *rpl_extb;	/* reply extension block 'address'*/
-	unsigned short	ccp_rtcode;	/* server return code		 */
-	unsigned short	ccp_rscode;	/* server reason code		 */
-	unsigned int	mac_data_len;	/* Mac Data Length		 */
-	unsigned char	logon_id[8];	/* Logon Identifier		 */
-	unsigned char	mac_value[8];	/* Mac Value			 */
-	unsigned char	mac_content_flgs;/* Mac content flag byte	 */
-	unsigned char	pad_002;	/* Alignment			 */
-	unsigned short	domain;		/* Domain			 */
-	unsigned char	usage_domain[4];/* Usage domain			 */
-	unsigned char	cntrl_domain[4];/* Control domain		 */
-	unsigned char	S390enf_mask[4];/* S/390 enforcement mask	 */
-	unsigned char	pad_004[36];	/* reserved			 */
+	__u16	     cprb_len;		/* CPRB length	      220	 */
+	__u8	     cprb_ver_id;	/* CPRB version id.   0x02	 */
+	__u8	     pad_000[3];	/* Alignment pad bytes		 */
+	__u8	     func_id[2];	/* function id	      0x5432	 */
+	__u8	     cprb_flags[4];	/* Flags			 */
+	__u32	     req_parml;		/* request parameter buffer len	 */
+	__u32	     req_datal;		/* request data buffer		 */
+	__u32	     rpl_msgbl;		/* reply  message block length	 */
+	__u32	     rpld_parml;	/* replied parameter block len	 */
+	__u32	     rpl_datal;		/* reply data block len		 */
+	__u32	     rpld_datal;	/* replied data block len	 */
+	__u32	     req_extbl;		/* request extension block len	 */
+	__u8	     pad_001[4];	/* reserved			 */
+	__u32	     rpld_extbl;	/* replied extension block len	 */
+	__u8	     padx000[16 - sizeof(__u8 *)];
+	__u8 __user *req_parmb;		/* request parm block 'address'	 */
+	__u8	     padx001[16 - sizeof(__u8 *)];
+	__u8 __user *req_datab;		/* request data block 'address'	 */
+	__u8	     padx002[16 - sizeof(__u8 *)];
+	__u8 __user *rpl_parmb;		/* reply parm block 'address'	 */
+	__u8	     padx003[16 - sizeof(__u8 *)];
+	__u8 __user *rpl_datab;		/* reply data block 'address'	 */
+	__u8	     padx004[16 - sizeof(__u8 *)];
+	__u8 __user *req_extb;		/* request extension block 'addr'*/
+	__u8	     padx005[16 - sizeof(__u8 *)];
+	__u8 __user *rpl_extb;		/* reply extension block 'address'*/
+	__u16	     ccp_rtcode;	/* server return code		 */
+	__u16	     ccp_rscode;	/* server reason code		 */
+	__u32	     mac_data_len;	/* Mac Data Length		 */
+	__u8	     logon_id[8];	/* Logon Identifier		 */
+	__u8	     mac_value[8];	/* Mac Value			 */
+	__u8	     mac_content_flgs;	/* Mac content flag byte	 */
+	__u8	     pad_002;		/* Alignment			 */
+	__u16	     domain;		/* Domain			 */
+	__u8	     usage_domain[4];	/* Usage domain			 */
+	__u8	     cntrl_domain[4];	/* Control domain		 */
+	__u8	     S390enf_mask[4];	/* S/390 enforcement mask	 */
+	__u8	     pad_004[36];	/* reserved			 */
 } __attribute__((packed));
 
 /**
  * xcRB
  */
 struct ica_xcRB {
-	unsigned short	agent_ID;
-	unsigned int	user_defined;
-	unsigned short	request_ID;
-	unsigned int	request_control_blk_length;
-	unsigned char	padding1[16 - sizeof(char *)];
-	char __user    *request_control_blk_addr;
-	unsigned int	request_data_length;
-	char		padding2[16 - sizeof(char *)];
-	char __user    *request_data_address;
-	unsigned int	reply_control_blk_length;
-	char		padding3[16 - sizeof(char *)];
-	char __user    *reply_control_blk_addr;
-	unsigned int	reply_data_length;
-	char		padding4[16 - sizeof(char *)];
-	char __user    *reply_data_addr;
-	unsigned short	priority_window;
-	unsigned int	status;
+	__u16	      agent_ID;
+	__u32	      user_defined;
+	__u16	      request_ID;
+	__u32	      request_control_blk_length;
+	__u8	      _padding1[16 - sizeof(__u8 *)];
+	__u8 __user  *request_control_blk_addr;
+	__u32	      request_data_length;
+	__u8	      _padding2[16 - sizeof(__u8 *)];
+	__u8 __user  *request_data_address;
+	__u32	      reply_control_blk_length;
+	__u8	      _padding3[16 - sizeof(__u8 *)];
+	__u8 __user  *reply_control_blk_addr;
+	__u32	      reply_data_length;
+	__u8	      __padding4[16 - sizeof(__u8 *)];
+	__u8 __user  *reply_data_addr;
+	__u16	      priority_window;
+	__u32	      status;
 } __attribute__((packed));
 
 /**
@@ -161,17 +161,17 @@
  * @payload_len:	Payload length
  */
 struct ep11_cprb {
-	__u16		cprb_len;
-	unsigned char	cprb_ver_id;
-	unsigned char	pad_000[2];
-	unsigned char	flags;
-	unsigned char	func_id[2];
-	__u32		source_id;
-	__u32		target_id;
-	__u32		ret_code;
-	__u32		reserved1;
-	__u32		reserved2;
-	__u32		payload_len;
+	__u16	cprb_len;
+	__u8	cprb_ver_id;
+	__u8	pad_000[2];
+	__u8	flags;
+	__u8	func_id[2];
+	__u32	source_id;
+	__u32	target_id;
+	__u32	ret_code;
+	__u32	reserved1;
+	__u32	reserved2;
+	__u32	payload_len;
 } __attribute__((packed));
 
 /**
@@ -197,13 +197,13 @@
  */
 struct ep11_urb {
 	__u16		targets_num;
-	__u64		targets;
+	__u8 __user    *targets;
 	__u64		weight;
 	__u64		req_no;
 	__u64		req_len;
-	__u64		req;
+	__u8 __user    *req;
 	__u64		resp_len;
-	__u64		resp;
+	__u8 __user    *resp;
 } __attribute__((packed));
 
 /**
@@ -237,7 +237,9 @@
 	struct zcrypt_device_status_ext device[MAX_ZDEV_ENTRIES_EXT];
 };
 
-#define AUTOSELECT 0xFFFFFFFF
+#define AUTOSELECT  0xFFFFFFFF
+#define AUTOSEL_AP  ((__u16) 0xFFFF)
+#define AUTOSEL_DOM ((__u16) 0xFFFF)
 
 #define ZCRYPT_IOCTL_MAGIC 'z'
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/Makefile
+++ linux-ein-5.4.0/arch/s390/kernel/Makefile
@@ -78,7 +78,11 @@
 obj-$(CONFIG_PERF_EVENTS)	+= perf_cpum_cf_diag.o
 
 obj-$(CONFIG_TRACEPOINTS)	+= trace.o
+obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE))	+= uv.o
 
 # vdso
 obj-y				+= vdso64/
 obj-$(CONFIG_COMPAT_VDSO)	+= vdso32/
+
+# kernel message catalog
+obj-$(CONFIG_KMSG_IDS)		+= kmsg.o
--- linux-ein-5.4.0.orig/arch/s390/kernel/asm-offsets.c
+++ linux-ein-5.4.0/arch/s390/kernel/asm-offsets.c
@@ -76,6 +76,7 @@
 	OFFSET(__VDSO_TK_SHIFT, vdso_data, tk_shift);
 	OFFSET(__VDSO_TS_DIR, vdso_data, ts_dir);
 	OFFSET(__VDSO_TS_END, vdso_data, ts_end);
+	OFFSET(__VDSO_CLOCK_REALTIME_RES, vdso_data, hrtimer_res);
 	OFFSET(__VDSO_ECTG_BASE, vdso_per_cpu_data, ectg_timer_base);
 	OFFSET(__VDSO_ECTG_USER, vdso_per_cpu_data, ectg_user_time);
 	OFFSET(__VDSO_CPU_NR, vdso_per_cpu_data, cpu_nr);
@@ -87,7 +88,6 @@
 	DEFINE(__CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE);
 	DEFINE(__CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_COARSE);
 	DEFINE(__CLOCK_THREAD_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID);
-	DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
 	DEFINE(__CLOCK_COARSE_RES, LOW_RES_NSEC);
 	BLANK();
 	/* idle data offsets */
@@ -125,6 +125,8 @@
 	OFFSET(__LC_EXT_DAMAGE_CODE, lowcore, external_damage_code);
 	OFFSET(__LC_MCCK_FAIL_STOR_ADDR, lowcore, failing_storage_address);
 	OFFSET(__LC_LAST_BREAK, lowcore, breaking_event_addr);
+	OFFSET(__LC_RETURN_LPSWE, lowcore, return_lpswe);
+	OFFSET(__LC_RETURN_MCCK_LPSWE, lowcore, return_mcck_lpswe);
 	OFFSET(__LC_RST_OLD_PSW, lowcore, restart_old_psw);
 	OFFSET(__LC_EXT_OLD_PSW, lowcore, external_old_psw);
 	OFFSET(__LC_SVC_OLD_PSW, lowcore, svc_old_psw);
--- linux-ein-5.4.0.orig/arch/s390/kernel/cpcmd.c
+++ linux-ein-5.4.0/arch/s390/kernel/cpcmd.c
@@ -37,10 +37,12 @@
 
 static int diag8_response(int cmdlen, char *response, int *rlen)
 {
+	unsigned long _cmdlen = cmdlen | 0x40000000L;
+	unsigned long _rlen = *rlen;
 	register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
 	register unsigned long reg3 asm ("3") = (addr_t) response;
-	register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
-	register unsigned long reg5 asm ("5") = *rlen;
+	register unsigned long reg4 asm ("4") = _cmdlen;
+	register unsigned long reg5 asm ("5") = _rlen;
 
 	asm volatile(
 		"	diag	%2,%0,0x8\n"
--- linux-ein-5.4.0.orig/arch/s390/kernel/crash_dump.c
+++ linux-ein-5.4.0/arch/s390/kernel/crash_dump.c
@@ -44,7 +44,7 @@
 	u64 fprs[16];
 	u32 fpc;
 	u32 prefix;
-	u64 todpreg;
+	u32 todpreg;
 	u64 timer;
 	u64 todcmp;
 	u64 vxrs_low[16];
--- linux-ein-5.4.0.orig/arch/s390/kernel/debug.c
+++ linux-ein-5.4.0/arch/s390/kernel/debug.c
@@ -198,9 +198,10 @@
 	if (!areas)
 		goto fail_malloc_areas;
 	for (i = 0; i < nr_areas; i++) {
+		/* GFP_NOWARN to avoid user triggerable WARN, we handle fails */
 		areas[i] = kmalloc_array(pages_per_area,
 					 sizeof(debug_entry_t *),
-					 GFP_KERNEL);
+					 GFP_KERNEL | __GFP_NOWARN);
 		if (!areas[i])
 			goto fail_malloc_areas2;
 		for (j = 0; j < pages_per_area; j++) {
@@ -326,24 +327,6 @@
 		goto out;
 
 	rc->mode = mode & ~S_IFMT;
-
-	/* create root directory */
-	rc->debugfs_root_entry = debugfs_create_dir(rc->name,
-						    debug_debugfs_root_entry);
-
-	/* append new element to linked list */
-	if (!debug_area_first) {
-		/* first element in list */
-		debug_area_first = rc;
-		rc->prev = NULL;
-	} else {
-		/* append element to end of list */
-		debug_area_last->next = rc;
-		rc->prev = debug_area_last;
-	}
-	debug_area_last = rc;
-	rc->next = NULL;
-
 	refcount_set(&rc->ref_count, 1);
 out:
 	return rc;
@@ -403,27 +386,10 @@
  */
 static void debug_info_put(debug_info_t *db_info)
 {
-	int i;
-
 	if (!db_info)
 		return;
-	if (refcount_dec_and_test(&db_info->ref_count)) {
-		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-			if (!db_info->views[i])
-				continue;
-			debugfs_remove(db_info->debugfs_entries[i]);
-		}
-		debugfs_remove(db_info->debugfs_root_entry);
-		if (db_info == debug_area_first)
-			debug_area_first = db_info->next;
-		if (db_info == debug_area_last)
-			debug_area_last = db_info->prev;
-		if (db_info->prev)
-			db_info->prev->next = db_info->next;
-		if (db_info->next)
-			db_info->next->prev = db_info->prev;
+	if (refcount_dec_and_test(&db_info->ref_count))
 		debug_info_free(db_info);
-	}
 }
 
 /*
@@ -647,6 +613,31 @@
 	return 0; /* success */
 }
 
+/* Create debugfs entries and add to internal list. */
+static void _debug_register(debug_info_t *id)
+{
+	/* create root directory */
+	id->debugfs_root_entry = debugfs_create_dir(id->name,
+						    debug_debugfs_root_entry);
+
+	/* append new element to linked list */
+	if (!debug_area_first) {
+		/* first element in list */
+		debug_area_first = id;
+		id->prev = NULL;
+	} else {
+		/* append element to end of list */
+		debug_area_last->next = id;
+		id->prev = debug_area_last;
+	}
+	debug_area_last = id;
+	id->next = NULL;
+
+	debug_register_view(id, &debug_level_view);
+	debug_register_view(id, &debug_flush_view);
+	debug_register_view(id, &debug_pages_view);
+}
+
 /**
  * debug_register_mode() - creates and initializes debug area.
  *
@@ -676,19 +667,16 @@
 	if ((uid != 0) || (gid != 0))
 		pr_warn("Root becomes the owner of all s390dbf files in sysfs\n");
 	BUG_ON(!initialized);
-	mutex_lock(&debug_mutex);
 
 	/* create new debug_info */
 	rc = debug_info_create(name, pages_per_area, nr_areas, buf_size, mode);
-	if (!rc)
-		goto out;
-	debug_register_view(rc, &debug_level_view);
-	debug_register_view(rc, &debug_flush_view);
-	debug_register_view(rc, &debug_pages_view);
-out:
-	if (!rc)
+	if (rc) {
+		mutex_lock(&debug_mutex);
+		_debug_register(rc);
+		mutex_unlock(&debug_mutex);
+	} else {
 		pr_err("Registering debug feature %s failed\n", name);
-	mutex_unlock(&debug_mutex);
+	}
 	return rc;
 }
 EXPORT_SYMBOL(debug_register_mode);
@@ -717,6 +705,27 @@
 }
 EXPORT_SYMBOL(debug_register);
 
+/* Remove debugfs entries and remove from internal list. */
+static void _debug_unregister(debug_info_t *id)
+{
+	int i;
+
+	for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+		if (!id->views[i])
+			continue;
+		debugfs_remove(id->debugfs_entries[i]);
+	}
+	debugfs_remove(id->debugfs_root_entry);
+	if (id == debug_area_first)
+		debug_area_first = id->next;
+	if (id == debug_area_last)
+		debug_area_last = id->prev;
+	if (id->prev)
+		id->prev->next = id->next;
+	if (id->next)
+		id->next->prev = id->prev;
+}
+
 /**
  * debug_unregister() - give back debug area.
  *
@@ -730,8 +739,10 @@
 	if (!id)
 		return;
 	mutex_lock(&debug_mutex);
-	debug_info_put(id);
+	_debug_unregister(id);
 	mutex_unlock(&debug_mutex);
+
+	debug_info_put(id);
 }
 EXPORT_SYMBOL(debug_unregister);
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/diag.c
+++ linux-ein-5.4.0/arch/s390/kernel/diag.c
@@ -84,7 +84,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)
@@ -133,7 +133,7 @@
 }
 EXPORT_SYMBOL(diag_stat_inc);
 
-void diag_stat_inc_norecursion(enum diag_stat_enum nr)
+void notrace diag_stat_inc_norecursion(enum diag_stat_enum nr)
 {
 	this_cpu_inc(diag_stat.counter[nr]);
 	trace_s390_diagnose_norecursion(diag_map[nr].code);
--- linux-ein-5.4.0.orig/arch/s390/kernel/dis.c
+++ linux-ein-5.4.0/arch/s390/kernel/dis.c
@@ -461,10 +461,11 @@
 				ptr += sprintf(ptr, "%%c%i", value);
 			else if (operand->flags & OPERAND_VR)
 				ptr += sprintf(ptr, "%%v%i", value);
-			else if (operand->flags & OPERAND_PCREL)
-				ptr += sprintf(ptr, "%lx", (signed int) value
-								      + addr);
-			else if (operand->flags & OPERAND_SIGNED)
+			else if (operand->flags & OPERAND_PCREL) {
+				void *pcrel = (void *)((int)value + addr);
+
+				ptr += sprintf(ptr, "%px", pcrel);
+			} else if (operand->flags & OPERAND_SIGNED)
 				ptr += sprintf(ptr, "%i", value);
 			else
 				ptr += sprintf(ptr, "%u", value);
@@ -536,7 +537,7 @@
 		else
 			*ptr++ = ' ';
 		addr = regs->psw.addr + start - 32;
-		ptr += sprintf(ptr, "%016lx: ", addr);
+		ptr += sprintf(ptr, "%px: ", (void *)addr);
 		if (start + opsize >= end)
 			break;
 		for (i = 0; i < opsize; i++)
@@ -556,7 +557,7 @@
 
 void print_fn_code(unsigned char *code, unsigned long len)
 {
-	char buffer[64], *ptr;
+	char buffer[128], *ptr;
 	int opsize, i;
 
 	while (len) {
@@ -564,7 +565,7 @@
 		opsize = insn_length(*code);
 		if (opsize > len)
 			break;
-		ptr += sprintf(ptr, "%p: ", code);
+		ptr += sprintf(ptr, "%px: ", code);
 		for (i = 0; i < opsize; i++)
 			ptr += sprintf(ptr, "%02x", code[i]);
 		*ptr++ = '\t';
--- linux-ein-5.4.0.orig/arch/s390/kernel/dumpstack.c
+++ linux-ein-5.4.0/arch/s390/kernel/dumpstack.c
@@ -210,5 +210,5 @@
 	if (panic_on_oops)
 		panic("Fatal exception: panic_on_oops");
 	oops_exit();
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
--- linux-ein-5.4.0.orig/arch/s390/kernel/early.c
+++ linux-ein-5.4.0/arch/s390/kernel/early.c
@@ -169,6 +169,8 @@
 	psw_t psw;
 
 	psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA;
+	if (IS_ENABLED(CONFIG_KASAN))
+		psw.mask |= PSW_MASK_DAT;
 	psw.addr = (unsigned long) s390_base_ext_handler;
 	S390_lowcore.external_new_psw = psw;
 	psw.addr = (unsigned long) s390_base_pgm_handler;
@@ -250,6 +252,10 @@
 		clock_comparator_max = -1ULL >> 1;
 		__ctl_set_bit(0, 53);
 	}
+	if (IS_ENABLED(CONFIG_PCI) && test_facility(153)) {
+		S390_lowcore.machine_flags |= MACHINE_FLAG_PCI_MIO;
+		/* the control bit is set during PCI initialization */
+	}
 }
 
 static inline void save_vector_registers(void)
--- linux-ein-5.4.0.orig/arch/s390/kernel/entry.S
+++ linux-ein-5.4.0/arch/s390/kernel/entry.S
@@ -115,26 +115,29 @@
 
 	.macro	SWITCH_ASYNC savearea,timer
 	tmhh	%r8,0x0001		# interrupting from user ?
-	jnz	1f
+	jnz	2f
 	lgr	%r14,%r9
+	cghi	%r14,__LC_RETURN_LPSWE
+	je	0f
 	slg	%r14,BASED(.Lcritical_start)
 	clg	%r14,BASED(.Lcritical_length)
-	jhe	0f
+	jhe	1f
+0:
 	lghi	%r11,\savearea		# inside critical section, do cleanup
 	brasl	%r14,cleanup_critical
 	tmhh	%r8,0x0001		# retest problem state after cleanup
-	jnz	1f
-0:	lg	%r14,__LC_ASYNC_STACK	# are we already on the target stack?
+	jnz	2f
+1:	lg	%r14,__LC_ASYNC_STACK	# are we already on the target stack?
 	slgr	%r14,%r15
 	srag	%r14,%r14,STACK_SHIFT
-	jnz	2f
+	jnz	3f
 	CHECK_STACK \savearea
 	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-	j	3f
-1:	UPDATE_VTIME %r14,%r15,\timer
+	j	4f
+2:	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)
+3:	lg	%r15,__LC_ASYNC_STACK	# load async stack
+4:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	.endm
 
 	.macro UPDATE_VTIME w1,w2,enter_timer
@@ -365,9 +368,9 @@
 	jnz	.Lsysc_nr_ok
 	# svc 0: system call number in %r1
 	llgfr	%r1,%r1				# clear high word in r1
+	sth	%r1,__PT_INT_CODE+2(%r11)
 	cghi	%r1,NR_syscalls
 	jnl	.Lsysc_nr_ok
-	sth	%r1,__PT_INT_CODE+2(%r11)
 	slag	%r8,%r1,3
 .Lsysc_nr_ok:
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
@@ -401,7 +404,7 @@
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 	lmg	%r11,%r15,__PT_R11(%r11)
-	lpswe	__LC_RETURN_PSW
+	b	__LC_RETURN_LPSWE(%r0)
 .Lsysc_done:
 
 #
@@ -608,43 +611,50 @@
 	BPOFF
 	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
 	lg	%r10,__LC_LAST_BREAK
-	lg	%r12,__LC_CURRENT
+	srag	%r11,%r10,12
+	jnz	0f
+	/* if __LC_LAST_BREAK is < 4096, it contains one of
+	 * the lpswe addresses in lowcore. Set it to 1 (initial state)
+	 * to prevent leaking that address to userspace.
+	 */
+	lghi	%r10,1
+0:	lg	%r12,__LC_CURRENT
 	lghi	%r11,0
 	larl	%r13,cleanup_critical
 	lmg	%r8,%r9,__LC_PGM_OLD_PSW
 	tmhh	%r8,0x0001		# test problem state bit
-	jnz	2f			# -> fault in user space
+	jnz	3f			# -> fault in user space
 #if IS_ENABLED(CONFIG_KVM)
 	# cleanup critical section for program checks in sie64a
 	lgr	%r14,%r9
 	slg	%r14,BASED(.Lsie_critical_start)
 	clg	%r14,BASED(.Lsie_critical_length)
-	jhe	0f
+	jhe	1f
 	lg	%r14,__SF_SIE_CONTROL(%r15)	# get control block pointer
 	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
 	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
 	larl	%r9,sie_exit			# skip forward to sie_exit
 	lghi	%r11,_PIF_GUEST_FAULT
 #endif
-0:	tmhh	%r8,0x4000		# PER bit set in old PSW ?
-	jnz	1f			# -> enabled, can't be a double fault
+1:	tmhh	%r8,0x4000		# PER bit set in old PSW ?
+	jnz	2f			# -> enabled, can't be a double fault
 	tm	__LC_PGM_ILC+3,0x80	# check for per exception
 	jnz	.Lpgm_svcper		# -> single stepped svc
-1:	CHECK_STACK __LC_SAVE_AREA_SYNC
+2:	CHECK_STACK __LC_SAVE_AREA_SYNC
 	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-	# CHECK_VMAP_STACK branches to stack_overflow or 4f
-	CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
-2:	UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
+	# CHECK_VMAP_STACK branches to stack_overflow or 5f
+	CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,5f
+3:	UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
 	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 	lg	%r15,__LC_KERNEL_STACK
 	lgr	%r14,%r12
 	aghi	%r14,__TASK_thread	# pointer to thread_struct
 	lghi	%r13,__LC_PGM_TDB
 	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
-	jz	3f
+	jz	4f
 	mvc	__THREAD_trap_tdb(256,%r14),0(%r13)
-3:	stg	%r10,__THREAD_last_break(%r14)
-4:	lgr	%r13,%r11
+4:	stg	%r10,__THREAD_last_break(%r14)
+5:	lgr	%r13,%r11
 	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	stmg	%r0,%r7,__PT_R0(%r11)
 	# clear user controlled registers to prevent speculative use
@@ -663,14 +673,14 @@
 	stg	%r13,__PT_FLAGS(%r11)
 	stg	%r10,__PT_ARGS(%r11)
 	tm	__LC_PGM_ILC+3,0x80	# check for per exception
-	jz	5f
+	jz	6f
 	tmhh	%r8,0x0001		# kernel per event ?
 	jz	.Lpgm_kprobe
 	oi	__PT_FLAGS+7(%r11),_PIF_PER_TRAP
 	mvc	__THREAD_per_address(8,%r14),__LC_PER_ADDRESS
 	mvc	__THREAD_per_cause(2,%r14),__LC_PER_CODE
 	mvc	__THREAD_per_paid(1,%r14),__LC_PER_ACCESS_ID
-5:	REENABLE_IRQS
+6:	REENABLE_IRQS
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 	larl	%r1,pgm_check_table
 	llgh	%r10,__PT_INT_CODE+2(%r11)
@@ -775,7 +785,7 @@
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 .Lio_exit_kernel:
 	lmg	%r11,%r15,__PT_R11(%r11)
-	lpswe	__LC_RETURN_PSW
+	b	__LC_RETURN_LPSWE(%r0)
 .Lio_done:
 
 #
@@ -983,6 +993,7 @@
  * Load idle PSW. The second "half" of this function is in .Lcleanup_idle.
  */
 ENTRY(psw_idle)
+	stg	%r14,(__SF_GPRS+8*8)(%r15)
 	stg	%r3,__SF_EMPTY(%r15)
 	larl	%r1,.Lpsw_idle_lpsw+4
 	stg	%r1,__SF_EMPTY+8(%r15)
@@ -1214,7 +1225,7 @@
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 0:	lmg	%r11,%r15,__PT_R11(%r11)
-	lpswe	__LC_RETURN_MCCK_PSW
+	b	__LC_RETURN_MCCK_LPSWE
 
 .Lmcck_panic:
 	lg	%r15,__LC_NODAT_STACK
@@ -1271,6 +1282,8 @@
 #endif
 
 ENTRY(cleanup_critical)
+	cghi	%r9,__LC_RETURN_LPSWE
+	je	.Lcleanup_lpswe
 #if IS_ENABLED(CONFIG_KVM)
 	clg	%r9,BASED(.Lcleanup_table_sie)	# .Lsie_gmap
 	jl	0f
@@ -1424,6 +1437,7 @@
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
 	mvc	0(64,%r11),__PT_R8(%r9)
 	lmg	%r0,%r7,__PT_R0(%r9)
+.Lcleanup_lpswe:
 1:	lmg	%r8,%r9,__LC_RETURN_PSW
 	BR_EX	%r14,%r11
 .Lcleanup_sysc_restore_insn:
--- linux-ein-5.4.0.orig/arch/s390/kernel/entry.h
+++ linux-ein-5.4.0/arch/s390/kernel/entry.h
@@ -24,6 +24,8 @@
 
 void do_protection_exception(struct pt_regs *regs);
 void do_dat_exception(struct pt_regs *regs);
+void do_secure_storage_access(struct pt_regs *regs);
+void do_non_secure_storage_access(struct pt_regs *regs);
 
 void addressing_exception(struct pt_regs *regs);
 void data_exception(struct pt_regs *regs);
--- linux-ein-5.4.0.orig/arch/s390/kernel/ftrace.c
+++ linux-ein-5.4.0/arch/s390/kernel/ftrace.c
@@ -57,6 +57,7 @@
  * >	brasl	%r0,ftrace_caller	# offset 0
  */
 
+void *ftrace_func __read_mostly = ftrace_stub;
 unsigned long ftrace_plt;
 
 static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
@@ -72,15 +73,6 @@
 #endif
 }
 
-static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn)
-{
-#ifdef CONFIG_KPROBES
-	if (insn->opc == BREAKPOINT_INSTRUCTION)
-		return 1;
-#endif
-	return 0;
-}
-
 static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_KPROBES
@@ -114,16 +106,6 @@
 		/* Initial code replacement */
 		ftrace_generate_orig_insn(&orig);
 		ftrace_generate_nop_insn(&new);
-	} else if (is_kprobe_on_ftrace(&old)) {
-		/*
-		 * If we find a breakpoint instruction, a kprobe has been
-		 * placed at the beginning of the function. We write the
-		 * constant KPROBE_ON_FTRACE_NOP into the remaining four
-		 * bytes of the original instruction so that the kprobes
-		 * handler can execute a nop, if it reaches this breakpoint.
-		 */
-		ftrace_generate_kprobe_call_insn(&orig);
-		ftrace_generate_kprobe_nop_insn(&new);
 	} else {
 		/* Replace ftrace call with a nop. */
 		ftrace_generate_call_insn(&orig, rec->ip);
@@ -142,21 +124,10 @@
 
 	if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
 		return -EFAULT;
-	if (is_kprobe_on_ftrace(&old)) {
-		/*
-		 * If we find a breakpoint instruction, a kprobe has been
-		 * placed at the beginning of the function. We write the
-		 * constant KPROBE_ON_FTRACE_CALL into the remaining four
-		 * bytes of the original instruction so that the kprobes
-		 * handler can execute a brasl if it reaches this breakpoint.
-		 */
-		ftrace_generate_kprobe_nop_insn(&orig);
-		ftrace_generate_kprobe_call_insn(&new);
-	} else {
-		/* Replace nop with an ftrace call. */
-		ftrace_generate_nop_insn(&orig);
-		ftrace_generate_call_insn(&new, rec->ip);
-	}
+	/* Replace nop with an ftrace call. */
+	ftrace_generate_nop_insn(&orig);
+	ftrace_generate_call_insn(&new, rec->ip);
+
 	/* Verify that the to be replaced code matches what we expect. */
 	if (memcmp(&orig, &old, sizeof(old)))
 		return -EINVAL;
@@ -166,6 +137,7 @@
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
+	ftrace_func = func;
 	return 0;
 }
 
@@ -241,3 +213,45 @@
 }
 
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_KPROBES_ON_FTRACE
+void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+		struct ftrace_ops *ops, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb;
+	struct kprobe *p = get_kprobe((kprobe_opcode_t *)ip);
+
+	if (unlikely(!p) || kprobe_disabled(p))
+		return;
+
+	if (kprobe_running()) {
+		kprobes_inc_nmissed_count(p);
+		return;
+	}
+
+	__this_cpu_write(current_kprobe, p);
+
+	kcb = get_kprobe_ctlblk();
+	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+	instruction_pointer_set(regs, ip);
+
+	if (!p->pre_handler || !p->pre_handler(p, regs)) {
+
+		instruction_pointer_set(regs, ip + MCOUNT_INSN_SIZE);
+
+		if (unlikely(p->post_handler)) {
+			kcb->kprobe_status = KPROBE_HIT_SSDONE;
+			p->post_handler(p, regs, 0);
+		}
+	}
+	__this_cpu_write(current_kprobe, NULL);
+}
+NOKPROBE_SYMBOL(kprobe_ftrace_handler);
+
+int arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+	p->ainsn.insn = NULL;
+	return 0;
+}
+#endif
--- linux-ein-5.4.0.orig/arch/s390/kernel/ipl.c
+++ linux-ein-5.4.0/arch/s390/kernel/ipl.c
@@ -39,6 +39,7 @@
 #define IPL_CCW_STR		"ccw"
 #define IPL_FCP_STR		"fcp"
 #define IPL_FCP_DUMP_STR	"fcp_dump"
+#define IPL_NVME_STR		"nvme"
 #define IPL_NSS_STR		"nss"
 
 #define DUMP_CCW_STR		"ccw"
@@ -93,6 +94,8 @@
 		return IPL_FCP_DUMP_STR;
 	case IPL_TYPE_NSS:
 		return IPL_NSS_STR;
+	case IPL_TYPE_NVME:
+		return IPL_NVME_STR;
 	case IPL_TYPE_UNKNOWN:
 	default:
 		return IPL_UNKNOWN_STR;
@@ -133,6 +136,7 @@
 
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static struct ipl_parameter_block *reipl_block_fcp;
+static struct ipl_parameter_block *reipl_block_nvme;
 static struct ipl_parameter_block *reipl_block_ccw;
 static struct ipl_parameter_block *reipl_block_nss;
 static struct ipl_parameter_block *reipl_block_actual;
@@ -258,6 +262,8 @@
 			return IPL_TYPE_FCP_DUMP;
 		else
 			return IPL_TYPE_FCP;
+	case IPL_PBT_NVME:
+		return IPL_TYPE_NVME;
 	}
 	return IPL_TYPE_UNKNOWN;
 }
@@ -314,6 +320,8 @@
 	case IPL_TYPE_FCP:
 	case IPL_TYPE_FCP_DUMP:
 		return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
+	case IPL_TYPE_NVME:
+		return sprintf(page, "%08ux\n", ipl_block.nvme.fid);
 	default:
 		return 0;
 	}
@@ -342,15 +350,35 @@
 
 	return memory_read_from_buffer(buf, count, &off, scp_data, size);
 }
+
+static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
+				 struct bin_attribute *attr, char *buf,
+				 loff_t off, size_t count)
+{
+	unsigned int size = ipl_block.nvme.scp_data_len;
+	void *scp_data = &ipl_block.nvme.scp_data;
+
+	return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
 static struct bin_attribute ipl_scp_data_attr =
 	__BIN_ATTR(scp_data, S_IRUGO, ipl_scp_data_read, NULL, PAGE_SIZE);
 
+static struct bin_attribute ipl_nvme_scp_data_attr =
+	__BIN_ATTR(scp_data, S_IRUGO, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
+
 static struct bin_attribute *ipl_fcp_bin_attrs[] = {
 	&ipl_parameter_attr,
 	&ipl_scp_data_attr,
 	NULL,
 };
 
+static struct bin_attribute *ipl_nvme_bin_attrs[] = {
+	&ipl_parameter_attr,
+	&ipl_nvme_scp_data_attr,
+	NULL,
+};
+
 /* FCP ipl device attributes */
 
 DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
@@ -362,6 +390,16 @@
 DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n",
 		   (unsigned long long)ipl_block.fcp.br_lba);
 
+/* NVMe ipl device attributes */
+DEFINE_IPL_ATTR_RO(ipl_nvme, fid, "0x%08llx\n",
+		   (unsigned long long)ipl_block.nvme.fid);
+DEFINE_IPL_ATTR_RO(ipl_nvme, nsid, "0x%08llx\n",
+		   (unsigned long long)ipl_block.nvme.nsid);
+DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
+		   (unsigned long long)ipl_block.nvme.bootprog);
+DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
+		   (unsigned long long)ipl_block.nvme.br_lba);
+
 static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
 				     struct kobj_attribute *attr, char *page)
 {
@@ -396,6 +434,24 @@
 	.bin_attrs = ipl_fcp_bin_attrs,
 };
 
+static struct attribute *ipl_nvme_attrs[] = {
+	&sys_ipl_type_attr.attr,
+	&sys_ipl_nvme_fid_attr.attr,
+	&sys_ipl_nvme_nsid_attr.attr,
+	&sys_ipl_nvme_bootprog_attr.attr,
+	&sys_ipl_nvme_br_lba_attr.attr,
+	&sys_ipl_ccw_loadparm_attr.attr,
+	&sys_ipl_secure_attr.attr,
+	&sys_ipl_has_secure_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ipl_nvme_attr_group = {
+	.attrs = ipl_nvme_attrs,
+	.bin_attrs = ipl_nvme_bin_attrs,
+};
+
+
 /* CCW ipl device attributes */
 
 static struct attribute *ipl_ccw_attrs_vm[] = {
@@ -429,6 +485,8 @@
 
 static struct attribute *ipl_unknown_attrs[] = {
 	&sys_ipl_type_attr.attr,
+	&sys_ipl_secure_attr.attr,
+	&sys_ipl_has_secure_attr.attr,
 	NULL,
 };
 
@@ -471,6 +529,9 @@
 	case IPL_TYPE_FCP_DUMP:
 		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
 		break;
+	case IPL_TYPE_NVME:
+		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nvme_attr_group);
+		break;
 	default:
 		rc = sysfs_create_group(&ipl_kset->kobj,
 					&ipl_unknown_attr_group);
@@ -706,6 +767,93 @@
 	.bin_attrs = reipl_fcp_bin_attrs,
 };
 
+/* NVME reipl device attributes */
+
+static ssize_t reipl_nvme_scpdata_read(struct file *filp, struct kobject *kobj,
+				      struct bin_attribute *attr,
+				      char *buf, loff_t off, size_t count)
+{
+	size_t size = reipl_block_nvme->nvme.scp_data_len;
+	void *scp_data = reipl_block_nvme->nvme.scp_data;
+
+	return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
+static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
+				       struct bin_attribute *attr,
+				       char *buf, loff_t off, size_t count)
+{
+	size_t scpdata_len = count;
+	size_t padding;
+
+	if (off)
+		return -EINVAL;
+
+	memcpy(reipl_block_nvme->nvme.scp_data, buf, count);
+	if (scpdata_len % 8) {
+		padding = 8 - (scpdata_len % 8);
+		memset(reipl_block_nvme->nvme.scp_data + scpdata_len,
+		       0, padding);
+		scpdata_len += padding;
+	}
+
+	reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
+	reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len;
+	reipl_block_nvme->nvme.scp_data_len = scpdata_len;
+
+	return count;
+}
+
+static struct bin_attribute sys_reipl_nvme_scp_data_attr =
+	__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_nvme_scpdata_read,
+		   reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
+
+static struct bin_attribute *reipl_nvme_bin_attrs[] = {
+	&sys_reipl_nvme_scp_data_attr,
+	NULL,
+};
+
+DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n",
+		   reipl_block_nvme->nvme.fid);
+DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n",
+		   reipl_block_nvme->nvme.nsid);
+DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
+		   reipl_block_nvme->nvme.bootprog);
+DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n",
+		   reipl_block_nvme->nvme.br_lba);
+
+/* nvme wrapper */
+static ssize_t reipl_nvme_loadparm_show(struct kobject *kobj,
+				       struct kobj_attribute *attr, char *page)
+{
+	return reipl_generic_loadparm_show(reipl_block_nvme, page);
+}
+
+static ssize_t reipl_nvme_loadparm_store(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					const char *buf, size_t len)
+{
+	return reipl_generic_loadparm_store(reipl_block_nvme, buf, len);
+}
+
+static struct kobj_attribute sys_reipl_nvme_loadparm_attr =
+	__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nvme_loadparm_show,
+					    reipl_nvme_loadparm_store);
+
+static struct attribute *reipl_nvme_attrs[] = {
+	&sys_reipl_nvme_fid_attr.attr,
+	&sys_reipl_nvme_nsid_attr.attr,
+	&sys_reipl_nvme_bootprog_attr.attr,
+	&sys_reipl_nvme_br_lba_attr.attr,
+	&sys_reipl_nvme_loadparm_attr.attr,
+	NULL,
+};
+
+static struct attribute_group reipl_nvme_attr_group = {
+	.attrs = reipl_nvme_attrs,
+	.bin_attrs = reipl_nvme_bin_attrs
+};
+
 /* CCW reipl device attributes */
 DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
 
@@ -850,6 +998,9 @@
 	case IPL_TYPE_FCP:
 		reipl_block_actual = reipl_block_fcp;
 		break;
+	case IPL_TYPE_NVME:
+		reipl_block_actual = reipl_block_nvme;
+		break;
 	case IPL_TYPE_NSS:
 		reipl_block_actual = reipl_block_nss;
 		break;
@@ -876,6 +1027,8 @@
 		rc = reipl_set_type(IPL_TYPE_CCW);
 	else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
 		rc = reipl_set_type(IPL_TYPE_FCP);
+	else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
+		rc = reipl_set_type(IPL_TYPE_NVME);
 	else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
 		rc = reipl_set_type(IPL_TYPE_NSS);
 	return (rc != 0) ? rc : len;
@@ -886,6 +1039,7 @@
 
 static struct kset *reipl_kset;
 static struct kset *reipl_fcp_kset;
+static struct kset *reipl_nvme_kset;
 
 static void __reipl_run(void *unused)
 {
@@ -898,6 +1052,10 @@
 		diag308(DIAG308_SET, reipl_block_fcp);
 		diag308(DIAG308_LOAD_CLEAR, NULL);
 		break;
+	case IPL_TYPE_NVME:
+		diag308(DIAG308_SET, reipl_block_nvme);
+		diag308(DIAG308_LOAD_CLEAR, NULL);
+		break;
 	case IPL_TYPE_NSS:
 		diag308(DIAG308_SET, reipl_block_nss);
 		diag308(DIAG308_LOAD_CLEAR, NULL);
@@ -1034,6 +1192,49 @@
 	return 0;
 }
 
+static int __init reipl_nvme_init(void)
+{
+	int rc;
+
+	reipl_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!reipl_block_nvme)
+		return -ENOMEM;
+
+	/* sysfs: create kset for mixing attr group and bin attrs */
+	reipl_nvme_kset = kset_create_and_add(IPL_NVME_STR, NULL,
+					     &reipl_kset->kobj);
+	if (!reipl_nvme_kset) {
+		free_page((unsigned long) reipl_block_nvme);
+		return -ENOMEM;
+	}
+
+	rc = sysfs_create_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
+	if (rc) {
+		kset_unregister(reipl_nvme_kset);
+		free_page((unsigned long) reipl_block_nvme);
+		return rc;
+	}
+
+	if (ipl_info.type == IPL_TYPE_NVME) {
+		memcpy(reipl_block_nvme, &ipl_block, sizeof(ipl_block));
+		/*
+		 * Fix loadparm: There are systems where the (SCSI) LOADPARM
+		 * is invalid in the IPL parameter block, so take it
+		 * always from sclp_ipl_info.
+		 */
+		memcpy(reipl_block_nvme->nvme.loadparm, sclp_ipl_info.loadparm,
+		       LOADPARM_LEN);
+	} else {
+		reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN;
+		reipl_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
+		reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
+		reipl_block_nvme->nvme.pbt = IPL_PBT_NVME;
+		reipl_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_IPL;
+	}
+	reipl_capabilities |= IPL_TYPE_NVME;
+	return 0;
+}
+
 static int __init reipl_type_init(void)
 {
 	enum ipl_type reipl_type = ipl_info.type;
@@ -1049,6 +1250,9 @@
 	if (reipl_block->pb0_hdr.pbt == IPL_PBT_FCP) {
 		memcpy(reipl_block_fcp, reipl_block, size);
 		reipl_type = IPL_TYPE_FCP;
+	} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_NVME) {
+		memcpy(reipl_block_nvme, reipl_block, size);
+		reipl_type = IPL_TYPE_NVME;
 	} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
 		memcpy(reipl_block_ccw, reipl_block, size);
 		reipl_type = IPL_TYPE_CCW;
@@ -1075,6 +1279,9 @@
 	rc = reipl_fcp_init();
 	if (rc)
 		return rc;
+	rc = reipl_nvme_init();
+	if (rc)
+		return rc;
 	rc = reipl_nss_init();
 	if (rc)
 		return rc;
@@ -1691,6 +1898,10 @@
 		ipl_info.data.fcp.wwpn = ipl_block.fcp.wwpn;
 		ipl_info.data.fcp.lun = ipl_block.fcp.lun;
 		break;
+	case IPL_TYPE_NVME:
+		ipl_info.data.nvme.fid = ipl_block.nvme.fid;
+		ipl_info.data.nvme.nsid = ipl_block.nvme.nsid;
+		break;
 	case IPL_TYPE_NSS:
 	case IPL_TYPE_UNKNOWN:
 		/* We have no info to copy */
@@ -1783,7 +1994,7 @@
 
 	buf = vzalloc(report->size);
 	if (!buf)
-		return ERR_PTR(-ENOMEM);
+		goto out;
 	ptr = buf;
 
 	memcpy(ptr, report->ipib, report->ipib->hdr.len);
@@ -1822,6 +2033,7 @@
 	}
 
 	BUG_ON(ptr > buf + report->size);
+out:
 	return buf;
 }
 
@@ -1842,3 +2054,8 @@
 }
 
 #endif
+
+bool ipl_get_secureboot(void)
+{
+	return !!ipl_secure_flag;
+}
--- linux-ein-5.4.0.orig/arch/s390/kernel/irq.c
+++ linux-ein-5.4.0/arch/s390/kernel/irq.c
@@ -294,11 +294,6 @@
 	return IRQ_HANDLED;
 }
 
-static struct irqaction external_interrupt = {
-	.name	 = "EXT",
-	.handler = do_ext_interrupt,
-};
-
 void __init init_ext_interrupts(void)
 {
 	int idx;
@@ -308,7 +303,8 @@
 
 	irq_set_chip_and_handler(EXT_INTERRUPT,
 				 &dummy_irq_chip, handle_percpu_irq);
-	setup_irq(EXT_INTERRUPT, &external_interrupt);
+	if (request_irq(EXT_INTERRUPT, do_ext_interrupt, 0, "EXT", NULL))
+		panic("Failed to register EXT interrupt\n");
 }
 
 static DEFINE_SPINLOCK(irq_subclass_lock);
--- linux-ein-5.4.0.orig/arch/s390/kernel/jump_label.c
+++ linux-ein-5.4.0/arch/s390/kernel/jump_label.c
@@ -36,7 +36,7 @@
 	unsigned char *ipe = (unsigned char *)expected;
 	unsigned char *ipn = (unsigned char *)new;
 
-	pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
+	pr_emerg("Jump label code mismatch at %pS [%px]\n", ipc, ipc);
 	pr_emerg("Found:    %6ph\n", ipc);
 	pr_emerg("Expected: %6ph\n", ipe);
 	pr_emerg("New:      %6ph\n", ipn);
--- linux-ein-5.4.0.orig/arch/s390/kernel/kmsg.c
+++ linux-ein-5.4.0/arch/s390/kernel/kmsg.c
@@ -0,0 +1,114 @@
+/*
+ * Message printing with message catalog prefixes.
+ *
+ * Copyright IBM Corp. 2012
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/jhash.h>
+#include <linux/device.h>
+
+static inline u32 __printk_jhash(const void *key, u32 length)
+{
+	u32 a, b, c, len;
+	const u8 *k;
+	u8 zk[12];
+
+	a = b = 0x9e3779b9;
+	c = 0;
+	for (len = length + 12, k = key; len >= 12; len -= 12, k += 12) {
+		if (len >= 24) {
+			a += k[0] | k[1] << 8 | k[2] << 16 | k[3] << 24;
+			b += k[4] | k[5] << 8 | k[6] << 16 | k[7] << 24;
+			c += k[8] | k[9] << 8 | k[10] << 16 | k[11] << 24;
+		} else {
+			memset(zk, 0, 12);
+			memcpy(zk, k, len - 12);
+			a += zk[0] | zk[1] << 8 | zk[2] << 16 | zk[3] << 24;
+			b += zk[4] | zk[5] << 8 | zk[6] << 16 | zk[7] << 24;
+			c += (u32) zk[8] << 8;
+			c += (u32) zk[9] << 16;
+			c += (u32) zk[10] << 24;
+			c += length;
+		}
+		a -= b + c; a ^= (c>>13);
+		b -= a + c; b ^= (a<<8);
+		c -= a + b; c ^= (b>>13);
+		a -= b + c; a ^= (c>>12);
+		b -= a + c; b ^= (a<<16);
+		c -= a + b; c ^= (b>>5);
+		a -= b + c; a ^= (c>>3);
+		b -= a + c; b ^= (a<<10);
+		c -= a + b; c ^= (b>>15);
+	}
+	return c;
+}
+
+/**
+ * __jhash_string - calculate the six digit jhash of a string
+ * @str: string to calculate the jhash
+ */
+unsigned long long __jhash_string(const char *str)
+{
+	return __printk_jhash(str, strlen(str)) & 0xffffff;
+}
+EXPORT_SYMBOL(__jhash_string);
+
+static int __dev_printk_hash(const char *level, const struct device *dev,
+			     struct va_format *vaf)
+{
+	if (!dev)
+		return printk("%s(NULL device *): %pV", level, vaf);
+
+	return printk("%s%s.%06x: %pV", level, dev_driver_string(dev),
+		      __printk_jhash(vaf->fmt, strlen(vaf->fmt)) & 0xffffff,
+		      vaf);
+}
+
+int dev_printk_hash(const char *level, const struct device *dev,
+		    const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	r = __dev_printk_hash(level, dev, &vaf);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(dev_printk_hash);
+
+#define define_dev_printk_hash_level(func, kern_level)		\
+int func(const struct device *dev, const char *fmt, ...)	\
+{								\
+	struct va_format vaf;					\
+	va_list args;						\
+	int r;							\
+								\
+	va_start(args, fmt);					\
+								\
+	vaf.fmt = fmt;						\
+	vaf.va = &args;						\
+								\
+	r = __dev_printk_hash(kern_level, dev, &vaf);		\
+	va_end(args);						\
+								\
+	return r;						\
+}								\
+EXPORT_SYMBOL(func);
+
+define_dev_printk_hash_level(dev_emerg_hash, KERN_EMERG);
+define_dev_printk_hash_level(dev_alert_hash, KERN_ALERT);
+define_dev_printk_hash_level(dev_crit_hash, KERN_CRIT);
+define_dev_printk_hash_level(dev_err_hash, KERN_ERR);
+define_dev_printk_hash_level(dev_warn_hash, KERN_WARNING);
+define_dev_printk_hash_level(dev_notice_hash, KERN_NOTICE);
+define_dev_printk_hash_level(_dev_info_hash, KERN_INFO);
--- linux-ein-5.4.0.orig/arch/s390/kernel/kprobes.c
+++ linux-ein-5.4.0/arch/s390/kernel/kprobes.c
@@ -56,21 +56,10 @@
 
 static void copy_instruction(struct kprobe *p)
 {
-	unsigned long ip = (unsigned long) p->addr;
 	s64 disp, new_disp;
 	u64 addr, new_addr;
 
-	if (ftrace_location(ip) == ip) {
-		/*
-		 * If kprobes patches the instruction that is morphed by
-		 * ftrace make sure that kprobes always sees the branch
-		 * "jg .+24" that skips the mcount block or the "brcl 0,0"
-		 * in case of hotpatch.
-		 */
-		ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
-		p->ainsn.is_ftrace_insn = 1;
-	} else
-		memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8));
+	memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8));
 	p->opcode = p->ainsn.insn[0];
 	if (!probe_is_insn_relative_long(p->ainsn.insn))
 		return;
@@ -136,11 +125,6 @@
 }
 NOKPROBE_SYMBOL(arch_prepare_kprobe);
 
-int arch_check_ftrace_location(struct kprobe *p)
-{
-	return 0;
-}
-
 struct swap_insn_args {
 	struct kprobe *p;
 	unsigned int arm_kprobe : 1;
@@ -149,28 +133,11 @@
 static int swap_instruction(void *data)
 {
 	struct swap_insn_args *args = data;
-	struct ftrace_insn new_insn, *insn;
 	struct kprobe *p = args->p;
-	size_t len;
+	u16 opc;
 
-	new_insn.opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
-	len = sizeof(new_insn.opc);
-	if (!p->ainsn.is_ftrace_insn)
-		goto skip_ftrace;
-	len = sizeof(new_insn);
-	insn = (struct ftrace_insn *) p->addr;
-	if (args->arm_kprobe) {
-		if (is_ftrace_nop(insn))
-			new_insn.disp = KPROBE_ON_FTRACE_NOP;
-		else
-			new_insn.disp = KPROBE_ON_FTRACE_CALL;
-	} else {
-		ftrace_generate_call_insn(&new_insn, (unsigned long)p->addr);
-		if (insn->disp == KPROBE_ON_FTRACE_NOP)
-			ftrace_generate_nop_insn(&new_insn);
-	}
-skip_ftrace:
-	s390_kernel_write(p->addr, &new_insn, len);
+	opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
+	s390_kernel_write(p->addr, &opc, sizeof(opc));
 	return 0;
 }
 NOKPROBE_SYMBOL(swap_instruction);
@@ -255,6 +222,7 @@
 {
 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
 	kcb->kprobe_status = kcb->prev_kprobe.status;
+	kcb->prev_kprobe.kp = NULL;
 }
 NOKPROBE_SYMBOL(pop_kprobe);
 
@@ -464,24 +432,6 @@
 	unsigned long ip = regs->psw.addr;
 	int fixup = probe_get_fixup_type(p->ainsn.insn);
 
-	/* Check if the kprobes location is an enabled ftrace caller */
-	if (p->ainsn.is_ftrace_insn) {
-		struct ftrace_insn *insn = (struct ftrace_insn *) p->addr;
-		struct ftrace_insn call_insn;
-
-		ftrace_generate_call_insn(&call_insn, (unsigned long) p->addr);
-		/*
-		 * A kprobe on an enabled ftrace call site actually single
-		 * stepped an unconditional branch (ftrace nop equivalent).
-		 * Now we need to fixup things and pretend that a brasl r0,...
-		 * was executed instead.
-		 */
-		if (insn->disp == KPROBE_ON_FTRACE_CALL) {
-			ip += call_insn.disp * 2 - MCOUNT_INSN_SIZE;
-			regs->gprs[0] = (unsigned long)p->addr + sizeof(*insn);
-		}
-	}
-
 	if (fixup & FIXUP_PSW_NORMAL)
 		ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
 
@@ -509,12 +459,11 @@
 	if (!p)
 		return 0;
 
+	resume_execution(p, regs);
 	if (kcb->kprobe_status != KPROBE_REENTER && p->post_handler) {
 		kcb->kprobe_status = KPROBE_HIT_SSDONE;
 		p->post_handler(p, regs, 0);
 	}
-
-	resume_execution(p, regs);
 	pop_kprobe(kcb);
 	preempt_enable_no_resched();
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/machine_kexec.c
+++ linux-ein-5.4.0/arch/s390/kernel/machine_kexec.c
@@ -164,7 +164,9 @@
 #ifdef CONFIG_CRASH_DUMP
 	int rc;
 
+	preempt_disable();
 	rc = CALL_ON_STACK(do_start_kdump, S390_lowcore.nodat_stack, 1, image);
+	preempt_enable();
 	return rc == 0;
 #else
 	return false;
@@ -254,10 +256,10 @@
 	VMCOREINFO_SYMBOL(lowcore_ptr);
 	VMCOREINFO_SYMBOL(high_memory);
 	VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS);
-	mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
 	vmcoreinfo_append_str("SDMA=%lx\n", __sdma);
 	vmcoreinfo_append_str("EDMA=%lx\n", __edma);
 	vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
+	mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note());
 }
 
 void machine_shutdown(void)
--- linux-ein-5.4.0.orig/arch/s390/kernel/machine_kexec_file.c
+++ linux-ein-5.4.0/arch/s390/kernel/machine_kexec_file.c
@@ -12,6 +12,7 @@
 #include <linux/kexec.h>
 #include <linux/module_signature.h>
 #include <linux/verification.h>
+#include <linux/vmalloc.h>
 #include <asm/boot_data.h>
 #include <asm/ipl.h>
 #include <asm/setup.h>
@@ -28,6 +29,7 @@
 	const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
 	struct module_signature *ms;
 	unsigned long sig_len;
+	int ret;
 
 	/* Skip signature verification when not secure IPLed. */
 	if (!ipl_secure_flag)
@@ -62,11 +64,18 @@
 		return -EBADMSG;
 	}
 
-	return verify_pkcs7_signature(kernel, kernel_len,
-				      kernel + kernel_len, sig_len,
-				      VERIFY_USE_PLATFORM_KEYRING,
-				      VERIFYING_MODULE_SIGNATURE,
-				      NULL, NULL);
+	ret = verify_pkcs7_signature(kernel, kernel_len,
+				     kernel + kernel_len, sig_len,
+				     VERIFY_USE_SECONDARY_KEYRING,
+				     VERIFYING_MODULE_SIGNATURE,
+				     NULL, NULL);
+	if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
+		ret = verify_pkcs7_signature(kernel, kernel_len,
+					     kernel + kernel_len, sig_len,
+					     VERIFY_USE_PLATFORM_KEYRING,
+					     VERIFYING_MODULE_SIGNATURE,
+					     NULL, NULL);
+	return ret;
 }
 #endif /* CONFIG_KEXEC_SIG */
 
@@ -151,7 +160,7 @@
 		buf.mem += crashk_res.start;
 	buf.memsz = buf.bufsz;
 
-	data->parm->initrd_start = buf.mem;
+	data->parm->initrd_start = data->memsz;
 	data->parm->initrd_size = buf.memsz;
 	data->memsz += buf.memsz;
 
@@ -170,13 +179,12 @@
 	struct kexec_buf buf;
 	unsigned long addr;
 	void *ptr, *end;
+	int ret;
 
 	buf.image = image;
 
 	data->memsz = ALIGN(data->memsz, PAGE_SIZE);
 	buf.mem = data->memsz;
-	if (image->type == KEXEC_TYPE_CRASH)
-		buf.mem += crashk_res.start;
 
 	ptr = (void *)ipl_cert_list_addr;
 	end = ptr + ipl_cert_list_size;
@@ -199,9 +207,13 @@
 		ptr += len;
 	}
 
+	ret = -ENOMEM;
 	buf.buffer = ipl_report_finish(data->report);
+	if (!buf.buffer)
+		goto out;
 	buf.bufsz = data->report->size;
 	buf.memsz = buf.bufsz;
+	image->arch.ipl_buf = buf.buffer;
 
 	data->memsz += buf.memsz;
 
@@ -209,7 +221,12 @@
 		data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
 	*lc_ipl_parmblock_ptr = (__u32)buf.mem;
 
-	return kexec_add_buffer(&buf);
+	if (image->type == KEXEC_TYPE_CRASH)
+		buf.mem += crashk_res.start;
+
+	ret = kexec_add_buffer(&buf);
+out:
+	return ret;
 }
 
 void *kexec_file_add_components(struct kimage *image,
@@ -269,6 +286,7 @@
 {
 	Elf_Rela *relas;
 	int i, r_type;
+	int ret;
 
 	relas = (void *)pi->ehdr + relsec->sh_offset;
 
@@ -303,7 +321,11 @@
 		addr = section->sh_addr + relas[i].r_offset;
 
 		r_type = ELF64_R_TYPE(relas[i].r_info);
-		arch_kexec_do_relocs(r_type, loc, val, addr);
+		ret = arch_kexec_do_relocs(r_type, loc, val, addr);
+		if (ret) {
+			pr_err("Unknown rela relocation: %d\n", r_type);
+			return -ENOEXEC;
+		}
 	}
 	return 0;
 }
@@ -321,3 +343,11 @@
 
 	return kexec_image_probe_default(image, buf, buf_len);
 }
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
+{
+	vfree(image->arch.ipl_buf);
+	image->arch.ipl_buf = NULL;
+
+	return kexec_image_post_load_cleanup_default(image);
+}
--- linux-ein-5.4.0.orig/arch/s390/kernel/machine_kexec_reloc.c
+++ linux-ein-5.4.0/arch/s390/kernel/machine_kexec_reloc.c
@@ -28,6 +28,7 @@
 		break;
 	case R_390_64:		/* Direct 64 bit.  */
 	case R_390_GLOB_DAT:
+	case R_390_JMP_SLOT:
 		*(u64 *)loc = val;
 		break;
 	case R_390_PC16:	/* PC relative 16 bit.	*/
--- linux-ein-5.4.0.orig/arch/s390/kernel/mcount.S
+++ linux-ein-5.4.0/arch/s390/kernel/mcount.S
@@ -26,6 +26,12 @@
 #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_EX	%r14
@@ -35,25 +41,39 @@
 ENTRY(ftrace_caller)
 	.globl	ftrace_regs_caller
 	.set	ftrace_regs_caller,ftrace_caller
+	stg	%r14,(__SF_GPRS+8*8)(%r15)	# save traced function caller
+	lghi	%r14,0				# save condition code
+	ipm	%r14				# don't put any instructions
+	sllg	%r14,%r14,16			# clobbering CC before this point
 	lgr	%r1,%r15
 #if !(defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT))
 	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)
+	stg	%r14,(STACK_PTREGS_PSW)(%r15)
+	lg	%r14,(__SF_GPRS+8*8)(%r1)	# restore original return address
+	stosm	(STACK_PTREGS_PSW)(%r15),0
+	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
 	aghik	%r2,%r0,-MCOUNT_INSN_SIZE
 	lgrl	%r4,function_trace_op
-	lgrl	%r1,ftrace_trace_function
+	lgrl	%r1,ftrace_func
 #else
 	lgr	%r2,%r0
 	aghi	%r2,-MCOUNT_INSN_SIZE
 	larl	%r4,function_trace_op
 	lg	%r4,0(%r4)
-	larl	%r1,ftrace_trace_function
+	larl	%r1,ftrace_func
 	lg	%r1,0(%r1)
 #endif
 	lgr	%r3,%r14
--- linux-ein-5.4.0.orig/arch/s390/kernel/nmi.c
+++ linux-ein-5.4.0/arch/s390/kernel/nmi.c
@@ -179,7 +179,7 @@
 		       "malfunction (code 0x%016lx).\n", mcck.mcck_code);
 		printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
 		       current->comm, current->pid);
-		do_exit(SIGSEGV);
+		make_task_dead(SIGSEGV);
 	}
 }
 EXPORT_SYMBOL_GPL(s390_handle_mcck);
--- linux-ein-5.4.0.orig/arch/s390/kernel/perf_cpum_cf.c
+++ linux-ein-5.4.0/arch/s390/kernel/perf_cpum_cf.c
@@ -199,7 +199,7 @@
 	[PERF_COUNT_HW_BUS_CYCLES]	    = -1,
 };
 
-static int __hw_perf_event_init(struct perf_event *event)
+static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
 {
 	struct perf_event_attr *attr = &event->attr;
 	struct hw_perf_event *hwc = &event->hw;
@@ -207,7 +207,7 @@
 	int err = 0;
 	u64 ev;
 
-	switch (attr->type) {
+	switch (type) {
 	case PERF_TYPE_RAW:
 		/* Raw events are used to access counters directly,
 		 * hence do not permit excludes */
@@ -292,19 +292,38 @@
 	return err;
 }
 
+/* Events CPU_CYLCES and INSTRUCTIONS can be submitted with two different
+ * attribute::type values:
+ * - PERF_TYPE_HARDWARE:
+ * - pmu->type:
+ * Handle both type of invocations identical. They address the same hardware.
+ * The result is different when event modifiers exclude_kernel and/or
+ * exclude_user are also set.
+ */
+static int cpumf_pmu_event_type(struct perf_event *event)
+{
+	u64 ev = event->attr.config;
+
+	if (cpumf_generic_events_basic[PERF_COUNT_HW_CPU_CYCLES] == ev ||
+	    cpumf_generic_events_basic[PERF_COUNT_HW_INSTRUCTIONS] == ev ||
+	    cpumf_generic_events_user[PERF_COUNT_HW_CPU_CYCLES] == ev ||
+	    cpumf_generic_events_user[PERF_COUNT_HW_INSTRUCTIONS] == ev)
+		return PERF_TYPE_HARDWARE;
+	return PERF_TYPE_RAW;
+}
+
 static int cpumf_pmu_event_init(struct perf_event *event)
 {
+	unsigned int type = event->attr.type;
 	int err;
 
-	switch (event->attr.type) {
-	case PERF_TYPE_HARDWARE:
-	case PERF_TYPE_HW_CACHE:
-	case PERF_TYPE_RAW:
-		err = __hw_perf_event_init(event);
-		break;
-	default:
+	if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_RAW)
+		err = __hw_perf_event_init(event, type);
+	else if (event->pmu->type == type)
+		/* Registered as unknown PMU */
+		err = __hw_perf_event_init(event, cpumf_pmu_event_type(event));
+	else
 		return -ENOENT;
-	}
 
 	if (unlikely(err) && event->destroy)
 		event->destroy(event);
@@ -553,7 +572,7 @@
 		return -ENODEV;
 
 	cpumf_pmu.attr_groups = cpumf_cf_event_group();
-	rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW);
+	rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", -1);
 	if (rc)
 		pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc);
 	return rc;
--- linux-ein-5.4.0.orig/arch/s390/kernel/perf_cpum_cf_diag.c
+++ linux-ein-5.4.0/arch/s390/kernel/perf_cpum_cf_diag.c
@@ -243,13 +243,13 @@
 	int err = -ENOENT;
 
 	debug_sprintf_event(cf_diag_dbg, 5,
-			    "%s event %p cpu %d config %#llx "
+			    "%s event %p cpu %d config %#llx type:%u "
 			    "sample_type %#llx cf_diag_events %d\n", __func__,
-			    event, event->cpu, attr->config, attr->sample_type,
-			    atomic_read(&cf_diag_events));
+			    event, event->cpu, attr->config, event->pmu->type,
+			    attr->sample_type, atomic_read(&cf_diag_events));
 
 	if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG ||
-	    event->attr.type != PERF_TYPE_RAW)
+	    event->attr.type != event->pmu->type)
 		goto out;
 
 	/* Raw events are used to access counters directly,
@@ -308,7 +308,7 @@
 	case CPUMF_CTR_SET_CRYPTO:
 		if (info->csvn >= 1 && info->csvn <= 5)
 			ctrset_size = 16;
-		else if (info->csvn == 6)
+		else if (info->csvn == 6 || info->csvn == 7)
 			ctrset_size = 20;
 		break;
 	case CPUMF_CTR_SET_EXT:
@@ -318,7 +318,7 @@
 			ctrset_size = 48;
 		else if (info->csvn >= 3 && info->csvn <= 5)
 			ctrset_size = 128;
-		else if (info->csvn == 6)
+		else if (info->csvn == 6 || info->csvn == 7)
 			ctrset_size = 160;
 		break;
 	case CPUMF_CTR_SET_MT_DIAG:
@@ -693,7 +693,7 @@
 	}
 	debug_register_view(cf_diag_dbg, &debug_sprintf_view);
 
-	rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", PERF_TYPE_RAW);
+	rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", -1);
 	if (rc) {
 		debug_unregister_view(cf_diag_dbg, &debug_sprintf_view);
 		debug_unregister(cf_diag_dbg);
--- linux-ein-5.4.0.orig/arch/s390/kernel/perf_cpum_cf_events.c
+++ linux-ein-5.4.0/arch/s390/kernel/perf_cpum_cf_events.c
@@ -238,6 +238,134 @@
 CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
 CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
 
+CPUMF_EVENT_ATTR(cf_z15, L1D_RO_EXCL_WRITES, 0x0080);
+CPUMF_EVENT_ATTR(cf_z15, DTLB2_WRITES, 0x0081);
+CPUMF_EVENT_ATTR(cf_z15, DTLB2_MISSES, 0x0082);
+CPUMF_EVENT_ATTR(cf_z15, DTLB2_HPAGE_WRITES, 0x0083);
+CPUMF_EVENT_ATTR(cf_z15, DTLB2_GPAGE_WRITES, 0x0084);
+CPUMF_EVENT_ATTR(cf_z15, L1D_L2D_SOURCED_WRITES, 0x0085);
+CPUMF_EVENT_ATTR(cf_z15, ITLB2_WRITES, 0x0086);
+CPUMF_EVENT_ATTR(cf_z15, ITLB2_MISSES, 0x0087);
+CPUMF_EVENT_ATTR(cf_z15, L1I_L2I_SOURCED_WRITES, 0x0088);
+CPUMF_EVENT_ATTR(cf_z15, TLB2_PTE_WRITES, 0x0089);
+CPUMF_EVENT_ATTR(cf_z15, TLB2_CRSTE_WRITES, 0x008a);
+CPUMF_EVENT_ATTR(cf_z15, TLB2_ENGINES_BUSY, 0x008b);
+CPUMF_EVENT_ATTR(cf_z15, TX_C_TEND, 0x008c);
+CPUMF_EVENT_ATTR(cf_z15, TX_NC_TEND, 0x008d);
+CPUMF_EVENT_ATTR(cf_z15, L1C_TLB2_MISSES, 0x008f);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0090);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES, 0x0091);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV, 0x0092);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES, 0x0093);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x0094);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x0095);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES, 0x0096);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x0097);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x0098);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES, 0x0099);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x009a);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x009b);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES, 0x009c);
+CPUMF_EVENT_ATTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES, 0x009d);
+CPUMF_EVENT_ATTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO, 0x009e);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES, 0x00a2);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES, 0x00a3);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV, 0x00a4);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES, 0x00a5);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x00a6);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x00a7);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES, 0x00a8);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x00a9);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x00aa);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES, 0x00ab);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x00ac);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x00ad);
+CPUMF_EVENT_ATTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES, 0x00ae);
+CPUMF_EVENT_ATTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES, 0x00af);
+CPUMF_EVENT_ATTR(cf_z15, BCD_DFP_EXECUTION_SLOTS, 0x00e0);
+CPUMF_EVENT_ATTR(cf_z15, VX_BCD_EXECUTION_SLOTS, 0x00e1);
+CPUMF_EVENT_ATTR(cf_z15, DECIMAL_INSTRUCTIONS, 0x00e2);
+CPUMF_EVENT_ATTR(cf_z15, LAST_HOST_TRANSLATIONS, 0x00e8);
+CPUMF_EVENT_ATTR(cf_z15, TX_NC_TABORT, 0x00f3);
+CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_NO_SPECIAL, 0x00f4);
+CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_SPECIAL, 0x00f5);
+CPUMF_EVENT_ATTR(cf_z15, DFLT_ACCESS, 0x00f7);
+CPUMF_EVENT_ATTR(cf_z15, DFLT_CYCLES, 0x00fc);
+CPUMF_EVENT_ATTR(cf_z15, DFLT_CC, 0x00108);
+CPUMF_EVENT_ATTR(cf_z15, DFLT_CCFINISH, 0x00109);
+CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
+CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
+CPUMF_EVENT_ATTR(cf_z16, L1D_RO_EXCL_WRITES, 0x0080);
+CPUMF_EVENT_ATTR(cf_z16, DTLB2_WRITES, 0x0081);
+CPUMF_EVENT_ATTR(cf_z16, DTLB2_MISSES, 0x0082);
+CPUMF_EVENT_ATTR(cf_z16, CRSTE_1MB_WRITES, 0x0083);
+CPUMF_EVENT_ATTR(cf_z16, DTLB2_GPAGE_WRITES, 0x0084);
+CPUMF_EVENT_ATTR(cf_z16, ITLB2_WRITES, 0x0086);
+CPUMF_EVENT_ATTR(cf_z16, ITLB2_MISSES, 0x0087);
+CPUMF_EVENT_ATTR(cf_z16, TLB2_PTE_WRITES, 0x0089);
+CPUMF_EVENT_ATTR(cf_z16, TLB2_CRSTE_WRITES, 0x008a);
+CPUMF_EVENT_ATTR(cf_z16, TLB2_ENGINES_BUSY, 0x008b);
+CPUMF_EVENT_ATTR(cf_z16, TX_C_TEND, 0x008c);
+CPUMF_EVENT_ATTR(cf_z16, TX_NC_TEND, 0x008d);
+CPUMF_EVENT_ATTR(cf_z16, L1C_TLB2_MISSES, 0x008f);
+CPUMF_EVENT_ATTR(cf_z16, DCW_REQ, 0x0091);
+CPUMF_EVENT_ATTR(cf_z16, DCW_REQ_IV, 0x0092);
+CPUMF_EVENT_ATTR(cf_z16, DCW_REQ_CHIP_HIT, 0x0093);
+CPUMF_EVENT_ATTR(cf_z16, DCW_REQ_DRAWER_HIT, 0x0094);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_CHIP, 0x0095);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_CHIP_IV, 0x0096);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_CHIP_CHIP_HIT, 0x0097);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_CHIP_DRAWER_HIT, 0x0098);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_MODULE, 0x0099);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_DRAWER, 0x009a);
+CPUMF_EVENT_ATTR(cf_z16, DCW_OFF_DRAWER, 0x009b);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_CHIP_MEMORY, 0x009c);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_MODULE_MEMORY, 0x009d);
+CPUMF_EVENT_ATTR(cf_z16, DCW_ON_DRAWER_MEMORY, 0x009e);
+CPUMF_EVENT_ATTR(cf_z16, DCW_OFF_DRAWER_MEMORY, 0x009f);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_MODULE_IV, 0x00a0);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_MODULE_CHIP_HIT, 0x00a1);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_MODULE_DRAWER_HIT, 0x00a2);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_DRAWER_IV, 0x00a3);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_DRAWER_CHIP_HIT, 0x00a4);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_ON_DRAWER_DRAWER_HIT, 0x00a5);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_OFF_DRAWER_IV, 0x00a6);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_OFF_DRAWER_CHIP_HIT, 0x00a7);
+CPUMF_EVENT_ATTR(cf_z16, IDCW_OFF_DRAWER_DRAWER_HIT, 0x00a8);
+CPUMF_EVENT_ATTR(cf_z16, ICW_REQ, 0x00a9);
+CPUMF_EVENT_ATTR(cf_z16, ICW_REQ_IV, 0x00aa);
+CPUMF_EVENT_ATTR(cf_z16, ICW_REQ_CHIP_HIT, 0x00ab);
+CPUMF_EVENT_ATTR(cf_z16, ICW_REQ_DRAWER_HIT, 0x00ac);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_CHIP, 0x00ad);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_CHIP_IV, 0x00ae);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_CHIP_CHIP_HIT, 0x00af);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_CHIP_DRAWER_HIT, 0x00b0);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_MODULE, 0x00b1);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_DRAWER, 0x00b2);
+CPUMF_EVENT_ATTR(cf_z16, ICW_OFF_DRAWER, 0x00b3);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_CHIP_MEMORY, 0x00b4);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_MODULE_MEMORY, 0x00b5);
+CPUMF_EVENT_ATTR(cf_z16, ICW_ON_DRAWER_MEMORY, 0x00b6);
+CPUMF_EVENT_ATTR(cf_z16, ICW_OFF_DRAWER_MEMORY, 0x00b7);
+CPUMF_EVENT_ATTR(cf_z16, BCD_DFP_EXECUTION_SLOTS, 0x00e0);
+CPUMF_EVENT_ATTR(cf_z16, VX_BCD_EXECUTION_SLOTS, 0x00e1);
+CPUMF_EVENT_ATTR(cf_z16, DECIMAL_INSTRUCTIONS, 0x00e2);
+CPUMF_EVENT_ATTR(cf_z16, LAST_HOST_TRANSLATIONS, 0x00e8);
+CPUMF_EVENT_ATTR(cf_z16, TX_NC_TABORT, 0x00f4);
+CPUMF_EVENT_ATTR(cf_z16, TX_C_TABORT_NO_SPECIAL, 0x00f5);
+CPUMF_EVENT_ATTR(cf_z16, TX_C_TABORT_SPECIAL, 0x00f6);
+CPUMF_EVENT_ATTR(cf_z16, DFLT_ACCESS, 0x00f8);
+CPUMF_EVENT_ATTR(cf_z16, DFLT_CYCLES, 0x00fd);
+CPUMF_EVENT_ATTR(cf_z16, SORTL, 0x0100);
+CPUMF_EVENT_ATTR(cf_z16, DFLT_CC, 0x0109);
+CPUMF_EVENT_ATTR(cf_z16, DFLT_CCFINISH, 0x010a);
+CPUMF_EVENT_ATTR(cf_z16, NNPA_INVOCATIONS, 0x010b);
+CPUMF_EVENT_ATTR(cf_z16, NNPA_COMPLETIONS, 0x010c);
+CPUMF_EVENT_ATTR(cf_z16, NNPA_WAIT_LOCK, 0x010d);
+CPUMF_EVENT_ATTR(cf_z16, NNPA_HOLD_LOCK, 0x010e);
+CPUMF_EVENT_ATTR(cf_z16, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
+CPUMF_EVENT_ATTR(cf_z16, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
+
 static struct attribute *cpumcf_fvn1_pmu_event_attr[] __initdata = {
 	CPUMF_EVENT_PTR(cf_fvn1, CPU_CYCLES),
 	CPUMF_EVENT_PTR(cf_fvn1, INSTRUCTIONS),
@@ -286,7 +414,7 @@
 	NULL,
 };
 
-static struct attribute *cpumcf_svn_6_pmu_event_attr[] __initdata = {
+static struct attribute *cpumcf_svn_67_pmu_event_attr[] __initdata = {
 	CPUMF_EVENT_PTR(cf_svn_12345, PRNG_FUNCTIONS),
 	CPUMF_EVENT_PTR(cf_svn_12345, PRNG_CYCLES),
 	CPUMF_EVENT_PTR(cf_svn_12345, PRNG_BLOCKED_FUNCTIONS),
@@ -516,6 +644,141 @@
 	NULL,
 };
 
+static struct attribute *cpumcf_z15_pmu_event_attr[] __initdata = {
+	CPUMF_EVENT_PTR(cf_z15, L1D_RO_EXCL_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, DTLB2_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, DTLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z15, DTLB2_HPAGE_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, DTLB2_GPAGE_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_L2D_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, ITLB2_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, ITLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_L2I_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, TLB2_PTE_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, TLB2_CRSTE_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, TLB2_ENGINES_BUSY),
+	CPUMF_EVENT_PTR(cf_z15, TX_C_TEND),
+	CPUMF_EVENT_PTR(cf_z15, TX_NC_TEND),
+	CPUMF_EVENT_PTR(cf_z15, L1C_TLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONDRAWER_L4_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_OFFDRAWER_L4_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1D_ONCHIP_L3_SOURCED_WRITES_RO),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCHIP_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV),
+	CPUMF_EVENT_PTR(cf_z15, L1I_ONDRAWER_L4_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, L1I_OFFDRAWER_L4_SOURCED_WRITES),
+	CPUMF_EVENT_PTR(cf_z15, BCD_DFP_EXECUTION_SLOTS),
+	CPUMF_EVENT_PTR(cf_z15, VX_BCD_EXECUTION_SLOTS),
+	CPUMF_EVENT_PTR(cf_z15, DECIMAL_INSTRUCTIONS),
+	CPUMF_EVENT_PTR(cf_z15, LAST_HOST_TRANSLATIONS),
+	CPUMF_EVENT_PTR(cf_z15, TX_NC_TABORT),
+	CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_NO_SPECIAL),
+	CPUMF_EVENT_PTR(cf_z15, TX_C_TABORT_SPECIAL),
+	CPUMF_EVENT_PTR(cf_z15, DFLT_ACCESS),
+	CPUMF_EVENT_PTR(cf_z15, DFLT_CYCLES),
+	CPUMF_EVENT_PTR(cf_z15, DFLT_CC),
+	CPUMF_EVENT_PTR(cf_z15, DFLT_CCFINISH),
+	CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE),
+	CPUMF_EVENT_PTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE),
+	NULL,
+};
+
+static struct attribute *cpumcf_z16_pmu_event_attr[] __initdata = {
+	CPUMF_EVENT_PTR(cf_z16, L1D_RO_EXCL_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, DTLB2_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, DTLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z16, CRSTE_1MB_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, DTLB2_GPAGE_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, ITLB2_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, ITLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z16, TLB2_PTE_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, TLB2_CRSTE_WRITES),
+	CPUMF_EVENT_PTR(cf_z16, TLB2_ENGINES_BUSY),
+	CPUMF_EVENT_PTR(cf_z16, TX_C_TEND),
+	CPUMF_EVENT_PTR(cf_z16, TX_NC_TEND),
+	CPUMF_EVENT_PTR(cf_z16, L1C_TLB2_MISSES),
+	CPUMF_EVENT_PTR(cf_z16, DCW_REQ),
+	CPUMF_EVENT_PTR(cf_z16, DCW_REQ_IV),
+	CPUMF_EVENT_PTR(cf_z16, DCW_REQ_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, DCW_REQ_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_CHIP),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_CHIP_IV),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_CHIP_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_CHIP_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_MODULE),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_DRAWER),
+	CPUMF_EVENT_PTR(cf_z16, DCW_OFF_DRAWER),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_CHIP_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_MODULE_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, DCW_ON_DRAWER_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, DCW_OFF_DRAWER_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_MODULE_IV),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_MODULE_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_MODULE_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_DRAWER_IV),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_DRAWER_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_ON_DRAWER_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_OFF_DRAWER_IV),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_OFF_DRAWER_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, IDCW_OFF_DRAWER_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, ICW_REQ),
+	CPUMF_EVENT_PTR(cf_z16, ICW_REQ_IV),
+	CPUMF_EVENT_PTR(cf_z16, ICW_REQ_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, ICW_REQ_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_CHIP),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_CHIP_IV),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_CHIP_CHIP_HIT),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_CHIP_DRAWER_HIT),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_MODULE),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_DRAWER),
+	CPUMF_EVENT_PTR(cf_z16, ICW_OFF_DRAWER),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_CHIP_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_MODULE_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, ICW_ON_DRAWER_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, ICW_OFF_DRAWER_MEMORY),
+	CPUMF_EVENT_PTR(cf_z16, BCD_DFP_EXECUTION_SLOTS),
+	CPUMF_EVENT_PTR(cf_z16, VX_BCD_EXECUTION_SLOTS),
+	CPUMF_EVENT_PTR(cf_z16, DECIMAL_INSTRUCTIONS),
+	CPUMF_EVENT_PTR(cf_z16, LAST_HOST_TRANSLATIONS),
+	CPUMF_EVENT_PTR(cf_z16, TX_NC_TABORT),
+	CPUMF_EVENT_PTR(cf_z16, TX_C_TABORT_NO_SPECIAL),
+	CPUMF_EVENT_PTR(cf_z16, TX_C_TABORT_SPECIAL),
+	CPUMF_EVENT_PTR(cf_z16, DFLT_ACCESS),
+	CPUMF_EVENT_PTR(cf_z16, DFLT_CYCLES),
+	CPUMF_EVENT_PTR(cf_z16, SORTL),
+	CPUMF_EVENT_PTR(cf_z16, DFLT_CC),
+	CPUMF_EVENT_PTR(cf_z16, DFLT_CCFINISH),
+	CPUMF_EVENT_PTR(cf_z16, NNPA_INVOCATIONS),
+	CPUMF_EVENT_PTR(cf_z16, NNPA_COMPLETIONS),
+	CPUMF_EVENT_PTR(cf_z16, NNPA_WAIT_LOCK),
+	CPUMF_EVENT_PTR(cf_z16, NNPA_HOLD_LOCK),
+	CPUMF_EVENT_PTR(cf_z16, MT_DIAG_CYCLES_ONE_THR_ACTIVE),
+	CPUMF_EVENT_PTR(cf_z16, MT_DIAG_CYCLES_TWO_THR_ACTIVE),
+	NULL,
+};
+
 /* END: CPUM_CF COUNTER DEFINITIONS ===================================== */
 
 static struct attribute_group cpumcf_pmu_events_group = {
@@ -596,8 +859,8 @@
 	case 1 ... 5:
 		csvn = cpumcf_svn_12345_pmu_event_attr;
 		break;
-	case 6:
-		csvn = cpumcf_svn_6_pmu_event_attr;
+	case 6 ... 7:
+		csvn = cpumcf_svn_67_pmu_event_attr;
 		break;
 	default:
 		csvn = none;
@@ -624,9 +887,15 @@
 		break;
 	case 0x3906:
 	case 0x3907:
+		model = cpumcf_z14_pmu_event_attr;
+		break;
 	case 0x8561:
 	case 0x8562:
-		model = cpumcf_z14_pmu_event_attr;
+		model = cpumcf_z15_pmu_event_attr;
+		break;
+	case 0x3931:
+	case 0x3932:
+		model = cpumcf_z16_pmu_event_attr;
 		break;
 	default:
 		model = none;
--- linux-ein-5.4.0.orig/arch/s390/kernel/perf_cpum_sf.c
+++ linux-ein-5.4.0/arch/s390/kernel/perf_cpum_sf.c
@@ -193,7 +193,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;
@@ -232,6 +232,7 @@
 			sfb->num_sdbt++;
 			/* Link current page to tail of chain */
 			*tail = (unsigned long)(void *) new + 1;
+			tail_prev = tail;
 			tail = new;
 		}
 
@@ -241,10 +242,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 */
@@ -1169,7 +1182,7 @@
 	sample = (struct hws_basic_entry *) *sdbt;
 	while ((unsigned long *) sample < (unsigned long *) te) {
 		/* Check for an empty sample */
-		if (!sample->def)
+		if (!sample->def || sample->LS)
 			break;
 
 		/* Update perf event period */
@@ -1300,18 +1313,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",
@@ -1406,8 +1429,8 @@
 		idx = aux->empty_mark + 1;
 		for (i = 0; i < range_scan; i++, idx++) {
 			te = aux_sdb_trailer(aux, idx);
-			te->flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
-			te->flags = te->flags & ~SDB_TE_ALERT_REQ_MASK;
+			te->flags &= ~(SDB_TE_BUFFER_FULL_MASK |
+				       SDB_TE_ALERT_REQ_MASK);
 			te->overflow = 0;
 		}
 		/* Save the position of empty SDBs */
@@ -1454,8 +1477,7 @@
 	te = aux_sdb_trailer(aux, alert_index);
 	do {
 		orig_flags = te->flags;
-		orig_overflow = te->overflow;
-		*overflow = orig_overflow;
+		*overflow = orig_overflow = te->overflow;
 		if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
 			/*
 			 * SDB is already set by hardware.
@@ -1566,6 +1588,7 @@
 	perf_aux_output_end(handle, size);
 	num_sdb = aux->sfb.num_sdb;
 
+	num_sdb = aux->sfb.num_sdb;
 	while (!done) {
 		/* Get an output handle */
 		aux = perf_aux_output_begin(handle, cpuhw->event);
@@ -1688,7 +1711,7 @@
 	}
 
 	/* Allocate aux_buffer struct for the event */
-	aux = kmalloc(sizeof(struct aux_buffer), GFP_KERNEL);
+	aux = kzalloc(sizeof(struct aux_buffer), GFP_KERNEL);
 	if (!aux)
 		goto no_aux;
 	sfb = &aux->sfb;
@@ -2194,4 +2217,4 @@
 }
 
 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-ein-5.4.0.orig/arch/s390/kernel/perf_event.c
+++ linux-ein-5.4.0/arch/s390/kernel/perf_event.c
@@ -224,9 +224,13 @@
 			   struct pt_regs *regs)
 {
 	struct unwind_state state;
+	unsigned long addr;
 
-	unwind_for_each_frame(&state, current, regs, 0)
-		perf_callchain_store(entry, state.ip);
+	unwind_for_each_frame(&state, current, regs, 0) {
+		addr = unwind_get_return_address(&state);
+		if (!addr || perf_callchain_store(entry, addr))
+			return;
+	}
 }
 
 /* Perf definitions for PMU event attributes in sysfs */
--- linux-ein-5.4.0.orig/arch/s390/kernel/pgm_check.S
+++ linux-ein-5.4.0/arch/s390/kernel/pgm_check.S
@@ -78,8 +78,8 @@
 PGM_CHECK(do_dat_exception)		/* 3a */
 PGM_CHECK(do_dat_exception)		/* 3b */
 PGM_CHECK_DEFAULT			/* 3c */
-PGM_CHECK_DEFAULT			/* 3d */
-PGM_CHECK_DEFAULT			/* 3e */
+PGM_CHECK(do_secure_storage_access)	/* 3d */
+PGM_CHECK(do_non_secure_storage_access)	/* 3e */
 PGM_CHECK_DEFAULT			/* 3f */
 PGM_CHECK_DEFAULT			/* 40 */
 PGM_CHECK_DEFAULT			/* 41 */
--- linux-ein-5.4.0.orig/arch/s390/kernel/process.c
+++ linux-ein-5.4.0/arch/s390/kernel/process.c
@@ -76,6 +76,18 @@
 
 	memcpy(dst, src, arch_task_struct_size);
 	dst->thread.fpu.regs = dst->thread.fpu.fprs;
+
+	/*
+	 * Don't transfer over the runtime instrumentation or the guarded
+	 * storage control block pointers. These fields are cleared here instead
+	 * of in copy_thread() to avoid premature freeing of associated memory
+	 * on fork() failure. Wait to clear the RI flag because ->stack still
+	 * refers to the source thread.
+	 */
+	dst->thread.ri_cb = NULL;
+	dst->thread.gs_cb = NULL;
+	dst->thread.gs_bc_cb = NULL;
+
 	return 0;
 }
 
@@ -105,6 +117,7 @@
 	p->thread.system_timer = 0;
 	p->thread.hardirq_timer = 0;
 	p->thread.softirq_timer = 0;
+	p->thread.last_break = 1;
 
 	frame->sf.back_chain = 0;
 	/* new return point is ret_from_fork */
@@ -132,13 +145,11 @@
 	frame->childregs.flags = 0;
 	if (new_stackp)
 		frame->childregs.gprs[15] = new_stackp;
-
-	/* Don't copy runtime instrumentation info */
-	p->thread.ri_cb = NULL;
+	/*
+	 * Clear the runtime instrumentation flag after the above childregs
+	 * copy. The CB pointer was already cleared in arch_dup_task_struct().
+	 */
 	frame->childregs.psw.mask &= ~PSW_MASK_RI;
-	/* Don't copy guarded storage control block */
-	p->thread.gs_cb = NULL;
-	p->thread.gs_bc_cb = NULL;
 
 	/* Set a new TLS ?  */
 	if (clone_flags & CLONE_SETTLS) {
--- linux-ein-5.4.0.orig/arch/s390/kernel/processor.c
+++ linux-ein-5.4.0/arch/s390/kernel/processor.c
@@ -165,8 +165,9 @@
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
 	unsigned long n = (unsigned long) v - 1;
+	unsigned long first = cpumask_first(cpu_online_mask);
 
-	if (!n)
+	if (n == first)
 		show_cpu_summary(m, v);
 	if (!machine_has_cpu_mhz)
 		return 0;
@@ -179,6 +180,8 @@
 {
 	if (*pos)
 		*pos = cpumask_next(*pos - 1, cpu_online_mask);
+	else
+		*pos = cpumask_first(cpu_online_mask);
 	return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL;
 }
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/s390/kernel/ptrace.c
@@ -324,6 +324,25 @@
 		child->thread.per_user.end = data;
 }
 
+static void fixup_int_code(struct task_struct *child, addr_t data)
+{
+	struct pt_regs *regs = task_pt_regs(child);
+	int ilc = regs->int_code >> 16;
+	u16 insn;
+
+	if (ilc > 6)
+		return;
+
+	if (ptrace_access_vm(child, regs->psw.addr - (regs->int_code >> 16),
+			&insn, sizeof(insn), FOLL_FORCE) != sizeof(insn))
+		return;
+
+	/* double check that tracee stopped on svc instruction */
+	if ((insn >> 8) != 0xa)
+		return;
+
+	regs->int_code = 0x20000 | (data & 0xffff);
+}
 /*
  * Write a word to the user area of a process at location addr. This
  * operation does have an additional problem compared to peek_user.
@@ -335,7 +354,9 @@
 	struct user *dummy = NULL;
 	addr_t offset;
 
+
 	if (addr < (addr_t) &dummy->regs.acrs) {
+		struct pt_regs *regs = task_pt_regs(child);
 		/*
 		 * psw and gprs are stored on the stack
 		 */
@@ -353,7 +374,11 @@
 				/* Invalid addressing mode bits */
 				return -EINVAL;
 		}
-		*(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data;
+
+		if (test_pt_regs_flag(regs, PIF_SYSCALL) &&
+			addr == offsetof(struct user, regs.gprs[2]))
+			fixup_int_code(child, data);
+		*(addr_t *)((addr_t) &regs->psw + addr) = data;
 
 	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
 		/*
@@ -388,6 +413,7 @@
 		/*
 		 * floating point control reg. is in the thread structure
 		 */
+		save_fpu_regs();
 		if ((unsigned int) data != 0 ||
 		    test_fp_ctl(data >> (BITS_PER_LONG - 32)))
 			return -EINVAL;
@@ -477,9 +503,7 @@
 		}
 		return 0;
 	case PTRACE_GET_LAST_BREAK:
-		put_user(child->thread.last_break,
-			 (unsigned long __user *) data);
-		return 0;
+		return put_user(child->thread.last_break, (unsigned long __user *)data);
 	case PTRACE_ENABLE_TE:
 		if (!MACHINE_HAS_TE)
 			return -EIO;
@@ -719,6 +743,10 @@
 			regs->psw.mask = (regs->psw.mask & ~PSW_MASK_BA) |
 				(__u64)(tmp & PSW32_ADDR_AMODE);
 		} else {
+
+			if (test_pt_regs_flag(regs, PIF_SYSCALL) &&
+				addr == offsetof(struct compat_user, regs.gprs[2]))
+				fixup_int_code(child, data);
 			/* gpr 0-15 */
 			*(__u32*)((addr_t) &regs->psw + addr*2 + 4) = tmp;
 		}
@@ -746,6 +774,7 @@
 		/*
 		 * floating point control reg. is in the thread structure
 		 */
+		save_fpu_regs();
 		if (test_fp_ctl(tmp))
 			return -EINVAL;
 		child->thread.fpu.fpc = data;
@@ -827,9 +856,7 @@
 		}
 		return 0;
 	case PTRACE_GET_LAST_BREAK:
-		put_user(child->thread.last_break,
-			 (unsigned int __user *) data);
-		return 0;
+		return put_user(child->thread.last_break, (unsigned int __user *)data);
 	}
 	return compat_ptrace_request(child, request, addr, data);
 }
@@ -838,40 +865,45 @@
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
 	unsigned long mask = -1UL;
+	long ret = -1;
 
 	/*
 	 * The sysc_tracesys code in entry.S stored the system
 	 * call number to gprs[2].
 	 */
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    (tracehook_report_syscall_entry(regs) ||
-	     regs->gprs[2] >= NR_syscalls)) {
+	    tracehook_report_syscall_entry(regs)) {
 		/*
-		 * Tracing decided this syscall should not happen or the
-		 * debugger stored an invalid system call number. Skip
+		 * Tracing decided this syscall should not happen. Skip
 		 * the system call and the system call restart handling.
 		 */
-		clear_pt_regs_flag(regs, PIF_SYSCALL);
-		return -1;
+		goto skip;
 	}
 
 	/* Do the secure computing check after ptrace. */
 	if (secure_computing(NULL)) {
 		/* seccomp failures shouldn't expose any additional code. */
-		return -1;
+		goto skip;
 	}
 
 	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-		trace_sys_enter(regs, regs->gprs[2]);
+		trace_sys_enter(regs, regs->int_code & 0xffff);
 
 	if (is_compat_task())
 		mask = 0xffffffff;
 
-	audit_syscall_entry(regs->gprs[2], regs->orig_gpr2 & mask,
+	audit_syscall_entry(regs->int_code & 0xffff, regs->orig_gpr2 & mask,
 			    regs->gprs[3] &mask, regs->gprs[4] &mask,
 			    regs->gprs[5] &mask);
 
+	if ((signed long)regs->gprs[2] >= NR_syscalls) {
+		regs->gprs[2] = -ENOSYS;
+		ret = -ENOSYS;
+	}
 	return regs->gprs[2];
+skip:
+	clear_pt_regs_flag(regs, PIF_SYSCALL);
+	return ret;
 }
 
 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
@@ -976,9 +1008,7 @@
 	int rc = 0;
 	freg_t fprs[__NUM_FPRS];
 
-	if (target == current)
-		save_fpu_regs();
-
+	save_fpu_regs();
 	if (MACHINE_HAS_VX)
 		convert_vx_to_fp(fprs, target->thread.fpu.vxrs);
 	else
@@ -1256,7 +1286,6 @@
 		cb->pc == 1 &&
 		cb->qc == 0 &&
 		cb->reserved2 == 0 &&
-		cb->key == PAGE_DEFAULT_KEY &&
 		cb->reserved3 == 0 &&
 		cb->reserved4 == 0 &&
 		cb->reserved5 == 0 &&
@@ -1320,7 +1349,11 @@
 		kfree(data);
 		return -EINVAL;
 	}
-
+	/*
+	 * Override access key in any case, since user space should
+	 * not be able to set it, nor should it care about it.
+	 */
+	ri_cb.key = PAGE_DEFAULT_KEY >> 4;
 	preempt_disable();
 	if (!target->thread.ri_cb)
 		target->thread.ri_cb = data;
--- linux-ein-5.4.0.orig/arch/s390/kernel/runtime_instr.c
+++ linux-ein-5.4.0/arch/s390/kernel/runtime_instr.c
@@ -57,7 +57,7 @@
 	cb->k = 1;
 	cb->ps = 1;
 	cb->pc = 1;
-	cb->key = PAGE_DEFAULT_KEY;
+	cb->key = PAGE_DEFAULT_KEY >> 4;
 	cb->v = 1;
 }
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/setup.c
+++ linux-ein-5.4.0/arch/s390/kernel/setup.c
@@ -49,6 +49,7 @@
 #include <linux/memory.h>
 #include <linux/compat.h>
 #include <linux/start_kernel.h>
+#include <linux/security.h>
 
 #include <asm/boot_data.h>
 #include <asm/ipl.h>
@@ -73,6 +74,7 @@
 #include <asm/nospec-branch.h>
 #include <asm/mem_detect.h>
 #include <asm/uv.h>
+#include <asm/asm-offsets.h>
 #include "entry.h"
 
 /*
@@ -92,10 +94,6 @@
 
 unsigned long int_hwcap = 0;
 
-#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
-int __bootdata_preserved(prot_virt_guest);
-#endif
-
 int __bootdata(noexec_disabled);
 int __bootdata(memory_end_set);
 unsigned long __bootdata(memory_end);
@@ -111,6 +109,8 @@
 unsigned long __bootdata_preserved(__sdma);
 unsigned long __bootdata_preserved(__edma);
 unsigned long __bootdata_preserved(__kaslr_offset);
+unsigned int __bootdata_preserved(zlib_dfltcc_support);
+EXPORT_SYMBOL(zlib_dfltcc_support);
 
 unsigned long VMALLOC_START;
 EXPORT_SYMBOL(VMALLOC_START);
@@ -161,7 +161,7 @@
 	else if (CONSOLE_IS_3270)
 		add_preferred_console("tty3270", 0, NULL);
 	else if (CONSOLE_IS_VT220)
-		add_preferred_console("ttyS", 1, NULL);
+		add_preferred_console("ttysclp", 0, NULL);
 	else if (CONSOLE_IS_HVC)
 		add_preferred_console("hvc", 0, NULL);
 }
@@ -355,7 +355,6 @@
 
 void __init arch_call_rest_init(void)
 {
-	struct stack_frame *frame;
 	unsigned long stack;
 
 	stack = stack_alloc();
@@ -368,13 +367,7 @@
 	set_task_stack_end_magic(current);
 	stack += STACK_INIT_OFFSET;
 	S390_lowcore.kernel_stack = stack;
-	frame = (struct stack_frame *) stack;
-	memset(frame, 0, sizeof(*frame));
-	/* Branch to rest_init on the new stack, never returns */
-	asm volatile(
-		"	la	15,0(%[_frame])\n"
-		"	jg	rest_init\n"
-		: : [_frame] "a" (frame));
+	CALL_ON_STACK_NORETURN(rest_init, stack);
 }
 
 static void __init setup_lowcore_dat_off(void)
@@ -457,6 +450,8 @@
 	lc->spinlock_index = 0;
 	arch_spin_lock_setup(0);
 	lc->br_r1_trampoline = 0x07f1;	/* br %r1 */
+	lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW);
+	lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
 
 	set_prefix((u32)(unsigned long) lc);
 	lowcore_ptr[0] = lc;
@@ -571,6 +566,9 @@
 			vmax = _REGION1_SIZE; /* 4-level kernel page table */
 	}
 
+	if (is_prot_virt_host())
+		adjust_to_uv_max(&vmax);
+
 	/* module area is at the end of the kernel address space. */
 	MODULES_END = vmax;
 	MODULES_VADDR = MODULES_END - MODULES_LEN;
@@ -631,7 +629,7 @@
 /*
  * Make sure that the area behind memory_end is protected
  */
-static void reserve_memory_end(void)
+static void __init reserve_memory_end(void)
 {
 	if (memory_end_set)
 		memblock_reserve(memory_end, ULONG_MAX);
@@ -640,7 +638,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)
@@ -652,7 +650,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)
@@ -845,9 +843,6 @@
 		storage_key_init_range(reg->base, reg->base + reg->size);
 	}
 	psw_set_key(PAGE_DEFAULT_KEY);
-
-	/* Only cosmetics */
-	memblock_enforce_memory_limit(memblock_end_of_DRAM());
 }
 
 /*
@@ -926,9 +921,9 @@
 	if (MACHINE_HAS_VX) {
 		elf_hwcap |= HWCAP_S390_VXRS;
 		if (test_facility(134))
-			elf_hwcap |= HWCAP_S390_VXRS_EXT;
-		if (test_facility(135))
 			elf_hwcap |= HWCAP_S390_VXRS_BCD;
+		if (test_facility(135))
+			elf_hwcap |= HWCAP_S390_VXRS_EXT;
 		if (test_facility(148))
 			elf_hwcap |= HWCAP_S390_VXRS_EXT2;
 		if (test_facility(152))
@@ -1012,6 +1007,11 @@
 	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);
+
+#ifdef CONFIG_ARCH_RANDOM
+	if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
+		static_branch_enable(&s390_arch_random_available);
+#endif
 }
 
 /*
@@ -1038,8 +1038,7 @@
 {
 	union diag318_info diag318_info = {
 		.cpnc = CPNC_LINUX,
-		.cpvc_linux = 0,
-		.cpvc_distro = {0},
+		.cpvc = 0,
 	};
 
 	if (!sclp.has_diag318)
@@ -1059,7 +1058,7 @@
 
 	if (!early_ipl_comp_list_addr)
 		return;
-	if (ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)
+	if (ipl_block.hdr.flags & IPL_PL_FLAG_SIPL)
 		pr_info("Linux is running with Secure-IPL enabled\n");
 	else
 		pr_info("Linux is running with Secure-IPL disabled\n");
@@ -1103,6 +1102,12 @@
 
 	log_component_list();
 
+#ifdef CONFIG_LOCK_DOWN_IN_SECURE_BOOT
+	if (ipl_get_secureboot())
+		security_lock_kernel_down("Secure IPL",
+					  LOCKDOWN_INTEGRITY_MAX);
+#endif
+
 	/* Have one command line that is parsed and saved in /proc/cmdline */
 	/* boot_command_line has been already set up in early.c */
 	*cmdline_p = boot_command_line;
@@ -1117,6 +1122,7 @@
 	if (IS_ENABLED(CONFIG_EXPOLINE_AUTO))
 		nospec_auto_detect();
 
+	jump_label_init();
 	parse_early_param();
 #ifdef CONFIG_CRASH_DUMP
 	/* Deactivate elfcorehdr= kernel parameter */
@@ -1151,6 +1157,8 @@
 	 */
 	memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT));
 
+	if (is_prot_virt_host())
+		setup_uv();
 	setup_memory_end();
 	setup_memory();
 	dma_contiguous_reserve(memory_end);
--- linux-ein-5.4.0.orig/arch/s390/kernel/smp.c
+++ linux-ein-5.4.0/arch/s390/kernel/smp.c
@@ -145,7 +145,7 @@
 
 static inline int pcpu_stopped(struct pcpu *pcpu)
 {
-	u32 uninitialized_var(status);
+	u32 status;
 
 	if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
 			0, &status) != SIGP_CC_STATUS_STORED)
@@ -212,6 +212,8 @@
 	lc->spinlock_lockval = arch_spin_lockval(cpu);
 	lc->spinlock_index = 0;
 	lc->br_r1_trampoline = 0x07f1;	/* br %r1 */
+	lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW);
+	lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
 	if (nmi_alloc_per_cpu(lc))
 		goto out_async;
 	if (vdso_alloc_per_cpu(lc))
@@ -262,10 +264,13 @@
 	lc->spinlock_index = 0;
 	lc->percpu_offset = __per_cpu_offset[cpu];
 	lc->kernel_asce = S390_lowcore.kernel_asce;
+	lc->user_asce = S390_lowcore.kernel_asce;
 	lc->machine_flags = S390_lowcore.machine_flags;
 	lc->user_timer = lc->system_timer =
 		lc->steal_timer = lc->avg_steal_timer = 0;
 	__ctl_store(lc->cregs_save_area, 0, 15);
+	lc->cregs_save_area[1] = lc->kernel_asce;
+	lc->cregs_save_area[7] = lc->vdso_asce;
 	save_access_regs((unsigned int *) lc->access_regs_save_area);
 	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
 	       sizeof(lc->stfle_fac_list));
@@ -398,7 +403,7 @@
 	return -1;
 }
 
-bool arch_vcpu_is_preempted(int cpu)
+bool notrace arch_vcpu_is_preempted(int cpu)
 {
 	if (test_cpu_flag_of(CIF_ENABLED_WAIT, cpu))
 		return false;
@@ -408,7 +413,7 @@
 }
 EXPORT_SYMBOL(arch_vcpu_is_preempted);
 
-void smp_yield_cpu(int cpu)
+void notrace smp_yield_cpu(int cpu)
 {
 	if (MACHINE_HAS_DIAG9C) {
 		diag_stat_inc_norecursion(DIAG_STAT_X09C);
@@ -724,39 +729,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;
 }
 
@@ -805,18 +838,21 @@
 
 	/* Add CPUs present at boot */
 	get_online_cpus();
-	__smp_rescan_cpus(info, 0);
+	__smp_rescan_cpus(info, true);
 	put_online_cpus();
 	memblock_free_early((unsigned long)info, sizeof(*info));
 }
 
 static void smp_init_secondary(void)
 {
-	int cpu = smp_processor_id();
+	int cpu = raw_smp_processor_id();
 
 	S390_lowcore.last_update_clock = get_tod_clock();
 	restore_access_regs(S390_lowcore.access_regs_save_area);
+	set_cpu_flag(CIF_ASCE_PRIMARY);
+	set_cpu_flag(CIF_ASCE_SECONDARY);
 	cpu_init();
+	rcu_cpu_starting(cpu);
 	preempt_disable();
 	init_cpu_timer();
 	vtime_init();
@@ -843,30 +879,18 @@
 	S390_lowcore.restart_source = -1UL;
 	__ctl_load(S390_lowcore.cregs_save_area, 0, 15);
 	__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT);
-	CALL_ON_STACK(smp_init_secondary, S390_lowcore.kernel_stack, 0);
+	CALL_ON_STACK_NORETURN(smp_init_secondary, S390_lowcore.kernel_stack);
 }
 
 /* Upping and downing of CPUs */
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
-	struct pcpu *pcpu;
-	int base, i, rc;
+	struct pcpu *pcpu = pcpu_devices + cpu;
+	int rc;
 
-	pcpu = pcpu_devices + cpu;
 	if (pcpu->state != CPU_STATE_CONFIGURED)
 		return -EIO;
-	base = smp_get_base_cpu(cpu);
-	for (i = 0; i <= smp_cpu_mtid; i++) {
-		if (base + i < nr_cpu_ids)
-			if (cpu_online(base + i))
-				break;
-	}
-	/*
-	 * If this is the first CPU of the core to get online
-	 * do an initial CPU reset.
-	 */
-	if (i > smp_cpu_mtid &&
-	    pcpu_sigp_retry(pcpu_devices + base, SIGP_INITIAL_CPU_RESET, 0) !=
+	if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
 	    SIGP_CC_ORDER_CODE_ACCEPTED)
 		return -EIO;
 
@@ -1148,7 +1172,7 @@
 	smp_get_core_info(info, 0);
 	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);
--- linux-ein-5.4.0.orig/arch/s390/kernel/sthyi.c
+++ linux-ein-5.4.0/arch/s390/kernel/sthyi.c
@@ -460,9 +460,9 @@
  *
  * Fills the destination with system information returned by the STHYI
  * instruction. The data is generated by emulation or execution of STHYI,
- * if available. The return value is the condition code that would be
- * returned, the rc parameter is the return code which is passed in
- * register R2 + 1.
+ * if available. The return value is either a negative error value or
+ * the condition code that would be returned, the rc parameter is the
+ * return code which is passed in register R2 + 1.
  */
 int sthyi_fill(void *dst, u64 *rc)
 {
--- linux-ein-5.4.0.orig/arch/s390/kernel/time.c
+++ linux-ein-5.4.0/arch/s390/kernel/time.c
@@ -310,6 +310,7 @@
 
 	vdso_data->tk_mult = tk->tkr_mono.mult;
 	vdso_data->tk_shift = tk->tkr_mono.shift;
+	vdso_data->hrtimer_res = hrtimer_resolution;
 	smp_wmb();
 	++vdso_data->tb_update_count;
 }
@@ -353,8 +354,9 @@
 static DEFINE_MUTEX(clock_sync_mutex);
 static unsigned long clock_sync_flags;
 
-#define CLOCK_SYNC_HAS_STP	0
-#define CLOCK_SYNC_STP		1
+#define CLOCK_SYNC_HAS_STP		0
+#define CLOCK_SYNC_STP			1
+#define CLOCK_SYNC_STPINFO_VALID	2
 
 /*
  * The get_clock function for the physical clock. It will get the current
@@ -591,6 +593,22 @@
 	queue_work(time_sync_wq, &stp_work);
 }
 
+static int __store_stpinfo(void)
+{
+	int rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
+
+	if (rc)
+		clear_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
+	else
+		set_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
+	return rc;
+}
+
+static int stpinfo_valid(void)
+{
+	return stp_online && test_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
+}
+
 static int stp_sync_clock(void *data)
 {
 	struct clock_sync_data *sync = data;
@@ -612,8 +630,7 @@
 			if (rc == 0) {
 				sync->clock_delta = clock_delta;
 				clock_sync_global(clock_delta);
-				rc = chsc_sstpi(stp_page, &stp_info,
-						sizeof(struct stp_sstpi));
+				rc = __store_stpinfo();
 				if (rc == 0 && stp_info.tmd != 2)
 					rc = -EAGAIN;
 			}
@@ -658,7 +675,7 @@
 	if (rc)
 		goto out_unlock;
 
-	rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
+	rc = __store_stpinfo();
 	if (rc || stp_info.c == 0)
 		goto out_unlock;
 
@@ -695,10 +712,14 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online)
-		return -ENODATA;
-	return sprintf(buf, "%016llx\n",
-		       *(unsigned long long *) stp_info.ctnid);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid())
+		ret = sprintf(buf, "%016llx\n",
+			      *(unsigned long long *) stp_info.ctnid);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL);
@@ -707,9 +728,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online)
-		return -ENODATA;
-	return sprintf(buf, "%i\n", stp_info.ctn);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid())
+		ret = sprintf(buf, "%i\n", stp_info.ctn);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL);
@@ -718,9 +743,13 @@
 				   struct device_attribute *attr,
 				   char *buf)
 {
-	if (!stp_online || !(stp_info.vbits & 0x2000))
-		return -ENODATA;
-	return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid() && (stp_info.vbits & 0x2000))
+		ret = sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL);
@@ -729,9 +758,13 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	if (!stp_online || !(stp_info.vbits & 0x8000))
-		return -ENODATA;
-	return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid() && (stp_info.vbits & 0x8000))
+		ret = sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL);
@@ -740,9 +773,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online)
-		return -ENODATA;
-	return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid())
+		ret = sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(stratum, 0400, stp_stratum_show, NULL);
@@ -751,9 +788,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online || !(stp_info.vbits & 0x0800))
-		return -ENODATA;
-	return sprintf(buf, "%i\n", (int) stp_info.tto);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid() && (stp_info.vbits & 0x0800))
+		ret = sprintf(buf, "%i\n", (int) stp_info.tto);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(time_offset, 0400, stp_time_offset_show, NULL);
@@ -762,9 +803,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online || !(stp_info.vbits & 0x4000))
-		return -ENODATA;
-	return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid() && (stp_info.vbits & 0x4000))
+		ret = sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(time_zone_offset, 0400,
@@ -774,9 +819,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online)
-		return -ENODATA;
-	return sprintf(buf, "%i\n", stp_info.tmd);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid())
+		ret = sprintf(buf, "%i\n", stp_info.tmd);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL);
@@ -785,9 +834,13 @@
 				struct device_attribute *attr,
 				char *buf)
 {
-	if (!stp_online)
-		return -ENODATA;
-	return sprintf(buf, "%i\n", stp_info.tst);
+	ssize_t ret = -ENODATA;
+
+	mutex_lock(&stp_work_mutex);
+	if (stpinfo_valid())
+		ret = sprintf(buf, "%i\n", stp_info.tst);
+	mutex_unlock(&stp_work_mutex);
+	return ret;
 }
 
 static DEVICE_ATTR(timing_state, 0400, stp_timing_state_show, NULL);
--- linux-ein-5.4.0.orig/arch/s390/kernel/topology.c
+++ linux-ein-5.4.0/arch/s390/kernel/topology.c
@@ -65,6 +65,13 @@
 
 cpumask_t cpus_with_topology;
 
+int __cpu_to_node(int cpu)
+{
+	return cpu_topology[cpu].node_id;
+}
+
+EXPORT_SYMBOL(__cpu_to_node);
+
 static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
 	cpumask_t mask;
--- linux-ein-5.4.0.orig/arch/s390/kernel/trace.c
+++ linux-ein-5.4.0/arch/s390/kernel/trace.c
@@ -14,7 +14,7 @@
 
 static DEFINE_PER_CPU(unsigned int, diagnose_trace_depth);
 
-void trace_s390_diagnose_norecursion(int diag_nr)
+void notrace trace_s390_diagnose_norecursion(int diag_nr)
 {
 	unsigned long flags;
 	unsigned int *depth;
--- linux-ein-5.4.0.orig/arch/s390/kernel/unwind_bc.c
+++ linux-ein-5.4.0/arch/s390/kernel/unwind_bc.c
@@ -60,6 +60,11 @@
 		ip = READ_ONCE_NOCHECK(sf->gprs[8]);
 		reliable = false;
 		regs = NULL;
+		if (!__kernel_text_address(ip)) {
+			/* skip bogus %r14 */
+			state->regs = NULL;
+			return unwind_next_frame(state);
+		}
 	} else {
 		sf = (struct stack_frame *) state->sp;
 		sp = READ_ONCE_NOCHECK(sf->back_chain);
--- linux-ein-5.4.0.orig/arch/s390/kernel/uv.c
+++ linux-ein-5.4.0/arch/s390/kernel/uv.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common Ultravisor functions and initialization
+ *
+ * Copyright IBM Corp. 2019, 2020
+ */
+#define KMSG_COMPONENT "prot_virt"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+#include <linux/bitmap.h>
+#include <linux/memblock.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <asm/facility.h>
+#include <asm/sections.h>
+#include <asm/uv.h>
+
+/* the bootdata_preserved fields come from ones in arch/s390/boot/uv.c */
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
+int __bootdata_preserved(prot_virt_guest);
+#endif
+
+#if IS_ENABLED(CONFIG_KVM)
+int prot_virt_host;
+EXPORT_SYMBOL(prot_virt_host);
+struct uv_info __bootdata_preserved(uv_info);
+EXPORT_SYMBOL(uv_info);
+
+static int __init prot_virt_setup(char *val)
+{
+	bool enabled;
+	int rc;
+
+	rc = kstrtobool(val, &enabled);
+	if (!rc && enabled)
+		prot_virt_host = 1;
+
+	if (is_prot_virt_guest() && prot_virt_host) {
+		prot_virt_host = 0;
+		pr_warn("Protected virtualization not available in protected guests.");
+	}
+
+	if (prot_virt_host && !test_facility(158)) {
+		prot_virt_host = 0;
+		pr_warn("Protected virtualization not supported by the hardware.");
+	}
+
+	return rc;
+}
+early_param("prot_virt", prot_virt_setup);
+
+static int __init uv_init(unsigned long stor_base, unsigned long stor_len)
+{
+	struct uv_cb_init uvcb = {
+		.header.cmd = UVC_CMD_INIT_UV,
+		.header.len = sizeof(uvcb),
+		.stor_origin = stor_base,
+		.stor_len = stor_len,
+	};
+
+	if (uv_call(0, (uint64_t)&uvcb)) {
+		pr_err("Ultravisor init failed with rc: 0x%x rrc: 0%x\n",
+		       uvcb.header.rc, uvcb.header.rrc);
+		return -1;
+	}
+	return 0;
+}
+
+void __init setup_uv(void)
+{
+	unsigned long uv_stor_base;
+
+	uv_stor_base = (unsigned long)memblock_alloc_try_nid(
+		uv_info.uv_base_stor_len, SZ_1M, SZ_2G,
+		MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE);
+	if (!uv_stor_base) {
+		pr_warn("Failed to reserve %lu bytes for ultravisor base storage\n",
+			uv_info.uv_base_stor_len);
+		goto fail;
+	}
+
+	if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) {
+		memblock_free(uv_stor_base, uv_info.uv_base_stor_len);
+		goto fail;
+	}
+
+	pr_info("Reserving %luMB as ultravisor base storage\n",
+		uv_info.uv_base_stor_len >> 20);
+	return;
+fail:
+	pr_info("Disabling support for protected virtualization");
+	prot_virt_host = 0;
+}
+
+void adjust_to_uv_max(unsigned long *vmax)
+{
+	*vmax = min_t(unsigned long, *vmax, uv_info.max_sec_stor_addr);
+}
+
+/*
+ * Requests the Ultravisor to pin the page in the shared state. This will
+ * cause an intercept when the guest attempts to unshare the pinned page.
+ */
+static int uv_pin_shared(unsigned long paddr)
+{
+	struct uv_cb_cfs uvcb = {
+		.header.cmd = UVC_CMD_PIN_PAGE_SHARED,
+		.header.len = sizeof(uvcb),
+		.paddr = paddr,
+	};
+
+	if (uv_call(0, (u64)&uvcb))
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * Requests the Ultravisor to encrypt a guest page and make it
+ * accessible to the host for paging (export).
+ *
+ * @paddr: Absolute host address of page to be exported
+ */
+int uv_convert_from_secure(unsigned long paddr)
+{
+	struct uv_cb_cfs uvcb = {
+		.header.cmd = UVC_CMD_CONV_FROM_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.paddr = paddr
+	};
+
+	if (uv_call(0, (u64)&uvcb))
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * Calculate the expected ref_count for a page that would otherwise have no
+ * further pins. This was cribbed from similar functions in other places in
+ * the kernel, but with some slight modifications. We know that a secure
+ * page can not be a huge page for example.
+ */
+static int expected_page_refs(struct page *page)
+{
+	int res;
+
+	res = page_mapcount(page);
+	if (PageSwapCache(page)) {
+		res++;
+	} else if (page_mapping(page)) {
+		res++;
+		if (page_has_private(page))
+			res++;
+	}
+	return res;
+}
+
+static int make_secure_pte(pte_t *ptep, unsigned long addr,
+			   struct page *exp_page, struct uv_cb_header *uvcb)
+{
+	pte_t entry = READ_ONCE(*ptep);
+	struct page *page;
+	int expected, cc = 0;
+
+	if (!pte_present(entry))
+		return -ENXIO;
+	if (pte_val(entry) & _PAGE_INVALID)
+		return -ENXIO;
+
+	page = pte_page(entry);
+	if (page != exp_page)
+		return -ENXIO;
+	if (PageWriteback(page))
+		return -EAGAIN;
+	expected = expected_page_refs(page);
+	if (!page_ref_freeze(page, expected))
+		return -EBUSY;
+	set_bit(PG_arch_1, &page->flags);
+	/*
+	 * If the UVC does not succeed or fail immediately, we don't want to
+	 * loop for long, or we might get stall notifications.
+	 * On the other hand, this is a complex scenario and we are holding a lot of
+	 * locks, so we can't easily sleep and reschedule. We try only once,
+	 * and if the UVC returned busy or partial completion, we return
+	 * -EAGAIN and we let the callers deal with it.
+	 */
+	cc = __uv_call(0, (u64)uvcb);
+	page_ref_unfreeze(page, expected);
+	/*
+	 * Return -ENXIO if the page was not mapped, -EINVAL for other errors.
+	 * If busy or partially completed, return -EAGAIN.
+	 */
+	if (cc == UVC_CC_OK)
+		return 0;
+	else if (cc == UVC_CC_BUSY || cc == UVC_CC_PARTIAL)
+		return -EAGAIN;
+	return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
+}
+
+/*
+ * Requests the Ultravisor to make a page accessible to a guest.
+ * If it's brought in the first time, it will be cleared. If
+ * it has been exported before, it will be decrypted and integrity
+ * checked.
+ */
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
+{
+	struct vm_area_struct *vma;
+	bool local_drain = false;
+	spinlock_t *ptelock;
+	unsigned long uaddr;
+	struct page *page;
+	pte_t *ptep;
+	int rc;
+
+again:
+	rc = -EFAULT;
+	down_read(&gmap->mm->mmap_sem);
+
+	uaddr = __gmap_translate(gmap, gaddr);
+	if (IS_ERR_VALUE(uaddr))
+		goto out;
+	vma = find_vma(gmap->mm, uaddr);
+	if (!vma)
+		goto out;
+	/*
+	 * Secure pages cannot be huge and userspace should not combine both.
+	 * In case userspace does it anyway this will result in an -EFAULT for
+	 * the unpack. The guest is thus never reaching secure mode. If
+	 * userspace is playing dirty tricky with mapping huge pages later
+	 * on this will result in a segmentation fault.
+	 */
+	if (is_vm_hugetlb_page(vma))
+		goto out;
+
+	rc = -ENXIO;
+	page = follow_page(vma, uaddr, FOLL_WRITE);
+	if (IS_ERR_OR_NULL(page))
+		goto out;
+
+	lock_page(page);
+	ptep = get_locked_pte(gmap->mm, uaddr, &ptelock);
+	rc = make_secure_pte(ptep, uaddr, page, uvcb);
+	pte_unmap_unlock(ptep, ptelock);
+	unlock_page(page);
+out:
+	up_read(&gmap->mm->mmap_sem);
+
+	if (rc == -EAGAIN) {
+		/*
+		 * If we are here because the UVC returned busy or partial
+		 * completion, this is just a useless check, but it is safe.
+		 */
+		wait_on_page_writeback(page);
+	} else if (rc == -EBUSY) {
+		/*
+		 * If we have tried a local drain and the page refcount
+		 * still does not match our expected safe value, try with a
+		 * system wide drain. This is needed if the pagevecs holding
+		 * the page are on a different CPU.
+		 */
+		if (local_drain) {
+			lru_add_drain_all();
+			/* We give up here, and let the caller try again */
+			return -EAGAIN;
+		}
+		/*
+		 * We are here if the page refcount does not match the
+		 * expected safe value. The main culprits are usually
+		 * pagevecs. With lru_add_drain() we drain the pagevecs
+		 * on the local CPU so that hopefully the refcount will
+		 * reach the expected safe value.
+		 */
+		lru_add_drain();
+		local_drain = true;
+		/* And now we try again immediately after draining */
+		goto again;
+	} else if (rc == -ENXIO) {
+		if (gmap_fault(gmap, gaddr, FAULT_FLAG_WRITE))
+			return -EFAULT;
+		return -EAGAIN;
+	}
+	return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_make_secure);
+
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
+{
+	struct uv_cb_cts uvcb = {
+		.header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.guest_handle = gmap->guest_handle,
+		.gaddr = gaddr,
+	};
+
+	return gmap_make_secure(gmap, gaddr, &uvcb);
+}
+EXPORT_SYMBOL_GPL(gmap_convert_to_secure);
+
+/*
+ * To be called with the page locked or with an extra reference! This will
+ * prevent gmap_make_secure from touching the page concurrently. Having 2
+ * parallel make_page_accessible is fine, as the UV calls will become a
+ * no-op if the page is already exported.
+ */
+int arch_make_page_accessible(struct page *page)
+{
+	int rc = 0;
+
+	/* Hugepage cannot be protected, so nothing to do */
+	if (PageHuge(page))
+		return 0;
+
+	/*
+	 * PG_arch_1 is used in 3 places:
+	 * 1. for kernel page tables during early boot
+	 * 2. for storage keys of huge pages and KVM
+	 * 3. As an indication that this page might be secure. This can
+	 *    overindicate, e.g. we set the bit before calling
+	 *    convert_to_secure.
+	 * As secure pages are never huge, all 3 variants can co-exists.
+	 */
+	if (!test_bit(PG_arch_1, &page->flags))
+		return 0;
+
+	rc = uv_pin_shared(page_to_phys(page));
+	if (!rc) {
+		clear_bit(PG_arch_1, &page->flags);
+		return 0;
+	}
+
+	rc = uv_convert_from_secure(page_to_phys(page));
+	if (!rc) {
+		clear_bit(PG_arch_1, &page->flags);
+		return 0;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(arch_make_page_accessible);
+
+#endif
+
+#if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || IS_ENABLED(CONFIG_KVM)
+static ssize_t uv_query_facilities(struct kobject *kobj,
+				   struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%lx\n%lx\n%lx\n%lx\n",
+			uv_info.inst_calls_list[0],
+			uv_info.inst_calls_list[1],
+			uv_info.inst_calls_list[2],
+			uv_info.inst_calls_list[3]);
+}
+
+static struct kobj_attribute uv_query_facilities_attr =
+	__ATTR(facilities, 0444, uv_query_facilities, NULL);
+
+static ssize_t uv_query_max_guest_cpus(struct kobject *kobj,
+				       struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%d\n",
+			uv_info.max_guest_cpus);
+}
+
+static struct kobj_attribute uv_query_max_guest_cpus_attr =
+	__ATTR(max_cpus, 0444, uv_query_max_guest_cpus, NULL);
+
+static ssize_t uv_query_max_guest_vms(struct kobject *kobj,
+				      struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%d\n",
+			uv_info.max_num_sec_conf);
+}
+
+static struct kobj_attribute uv_query_max_guest_vms_attr =
+	__ATTR(max_guests, 0444, uv_query_max_guest_vms, NULL);
+
+static ssize_t uv_query_max_guest_addr(struct kobject *kobj,
+				       struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%lx\n",
+			uv_info.max_sec_stor_addr);
+}
+
+static struct kobj_attribute uv_query_max_guest_addr_attr =
+	__ATTR(max_address, 0444, uv_query_max_guest_addr, NULL);
+
+static struct attribute *uv_query_attrs[] = {
+	&uv_query_facilities_attr.attr,
+	&uv_query_max_guest_cpus_attr.attr,
+	&uv_query_max_guest_vms_attr.attr,
+	&uv_query_max_guest_addr_attr.attr,
+	NULL,
+};
+
+static struct attribute_group uv_query_attr_group = {
+	.attrs = uv_query_attrs,
+};
+
+static ssize_t uv_is_prot_virt_guest(struct kobject *kobj,
+				     struct kobj_attribute *attr, char *page)
+{
+	int val = 0;
+
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
+	val = prot_virt_guest;
+#endif
+	return scnprintf(page, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t uv_is_prot_virt_host(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *page)
+{
+	int val = 0;
+
+#if IS_ENABLED(CONFIG_KVM)
+	val = prot_virt_host;
+#endif
+
+	return scnprintf(page, PAGE_SIZE, "%d\n", val);
+}
+
+static struct kobj_attribute uv_prot_virt_guest =
+	__ATTR(prot_virt_guest, 0444, uv_is_prot_virt_guest, NULL);
+
+static struct kobj_attribute uv_prot_virt_host =
+	__ATTR(prot_virt_host, 0444, uv_is_prot_virt_host, NULL);
+
+static const struct attribute *uv_prot_virt_attrs[] = {
+	&uv_prot_virt_guest.attr,
+	&uv_prot_virt_host.attr,
+	NULL,
+};
+
+static struct kset *uv_query_kset;
+static struct kobject *uv_kobj;
+
+static int __init uv_info_init(void)
+{
+	int rc = -ENOMEM;
+
+	if (!test_facility(158))
+		return 0;
+
+	uv_kobj = kobject_create_and_add("uv", firmware_kobj);
+	if (!uv_kobj)
+		return -ENOMEM;
+
+	rc = sysfs_create_files(uv_kobj, uv_prot_virt_attrs);
+	if (rc)
+		goto out_kobj;
+
+	uv_query_kset = kset_create_and_add("query", NULL, uv_kobj);
+	if (!uv_query_kset)
+		goto out_ind_files;
+
+	rc = sysfs_create_group(&uv_query_kset->kobj, &uv_query_attr_group);
+	if (!rc)
+		return 0;
+
+	kset_unregister(uv_query_kset);
+out_ind_files:
+	sysfs_remove_files(uv_kobj, uv_prot_virt_attrs);
+out_kobj:
+	kobject_del(uv_kobj);
+	kobject_put(uv_kobj);
+	return rc;
+}
+device_initcall(uv_info_init);
+#endif
--- linux-ein-5.4.0.orig/arch/s390/kernel/vdso64/Makefile
+++ linux-ein-5.4.0/arch/s390/kernel/vdso64/Makefile
@@ -18,8 +18,8 @@
 
 KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS))
 KBUILD_CFLAGS_64 += -m64 -fPIC -shared -fno-common -fno-builtin
-KBUILD_CFLAGS_64 += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
-		    -Wl,--hash-style=both
+ldflags-y := -fPIC -shared -nostdlib -soname=linux-vdso64.so.1 \
+	     --hash-style=both --build-id -T
 
 $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64)
 $(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_64)
@@ -37,8 +37,8 @@
 $(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) FORCE
-	$(call if_changed,vdso64ld)
+$(obj)/vdso64.so.dbg: $(obj)/vdso64.lds $(obj-vdso64) FORCE
+	$(call if_changed,ld)
 
 # strip rule for the .so file
 $(obj)/%.so: OBJCOPYFLAGS := -S
@@ -50,8 +50,6 @@
 	$(call if_changed_dep,vdso64as)
 
 # actual build commands
-quiet_cmd_vdso64ld = VDSO64L $@
-      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $(filter %.lds %.o,$^) -o $@
 quiet_cmd_vdso64as = VDSO64A $@
       cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
 
--- linux-ein-5.4.0.orig/arch/s390/kernel/vdso64/clock_getres.S
+++ linux-ein-5.4.0/arch/s390/kernel/vdso64/clock_getres.S
@@ -17,12 +17,14 @@
 	.type  __kernel_clock_getres,@function
 __kernel_clock_getres:
 	CFI_STARTPROC
-	larl	%r1,4f
+	larl	%r1,3f
+	lg	%r0,0(%r1)
 	cghi	%r2,__CLOCK_REALTIME_COARSE
 	je	0f
 	cghi	%r2,__CLOCK_MONOTONIC_COARSE
 	je	0f
-	larl	%r1,3f
+	larl	%r1,_vdso_data
+	llgf	%r0,__VDSO_CLOCK_REALTIME_RES(%r1)
 	cghi	%r2,__CLOCK_REALTIME
 	je	0f
 	cghi	%r2,__CLOCK_MONOTONIC
@@ -36,7 +38,6 @@
 	jz	2f
 0:	ltgr	%r3,%r3
 	jz	1f				/* res == NULL */
-	lg	%r0,0(%r1)
 	xc	0(8,%r3),0(%r3)			/* set tp->tv_sec to zero */
 	stg	%r0,8(%r3)			/* store tp->tv_usec */
 1:	lghi	%r2,0
@@ -45,6 +46,5 @@
 	svc	0
 	br	%r14
 	CFI_ENDPROC
-3:	.quad	__CLOCK_REALTIME_RES
-4:	.quad	__CLOCK_COARSE_RES
+3:	.quad	__CLOCK_COARSE_RES
 	.size	__kernel_clock_getres,.-__kernel_clock_getres
--- linux-ein-5.4.0.orig/arch/s390/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/s390/kernel/vmlinux.lds.S
@@ -15,6 +15,8 @@
 /* Handle ro_after_init data on our own. */
 #define RO_AFTER_INIT_DATA
 
+#define RUNTIME_DISCARD_EXIT
+
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/vmlinux.lds.h>
 
@@ -124,6 +126,7 @@
 	/*
 	 * Table with the patch locations to undo expolines
 	*/
+	. = ALIGN(4);
 	.nospec_call_table : {
 		__nospec_call_start = . ;
 		*(.s390_indirect*)
@@ -188,5 +191,6 @@
 	DISCARDS
 	/DISCARD/ : {
 		*(.eh_frame)
+		*(.interp)
 	}
 }
--- linux-ein-5.4.0.orig/arch/s390/kernel/vtime.c
+++ linux-ein-5.4.0/arch/s390/kernel/vtime.c
@@ -136,7 +136,8 @@
 		"	stck	%1"	/* Store current tod clock value */
 #endif
 		: "=Q" (S390_lowcore.last_update_timer),
-		  "=Q" (S390_lowcore.last_update_clock));
+		  "=Q" (S390_lowcore.last_update_clock)
+		: : "cc");
 	clock = S390_lowcore.last_update_clock - clock;
 	timer -= S390_lowcore.last_update_timer;
 
@@ -216,7 +217,7 @@
 	avg_steal = S390_lowcore.avg_steal_timer / 2;
 	if ((s64) steal > 0) {
 		S390_lowcore.steal_timer = 0;
-		account_steal_time(steal);
+		account_steal_time(cputime_to_nsecs(steal));
 		avg_steal += steal;
 	}
 	S390_lowcore.avg_steal_timer = avg_steal;
--- linux-ein-5.4.0.orig/arch/s390/kvm/Makefile
+++ linux-ein-5.4.0/arch/s390/kvm/Makefile
@@ -9,6 +9,6 @@
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-objs += diag.o gaccess.o guestdbg.o vsie.o
+kvm-objs += diag.o gaccess.o guestdbg.o vsie.o pv.o
 
 obj-$(CONFIG_KVM) += kvm.o
--- linux-ein-5.4.0.orig/arch/s390/kvm/diag.c
+++ linux-ein-5.4.0/arch/s390/kvm/diag.c
@@ -2,7 +2,7 @@
 /*
  * handling diagnose instructions
  *
- * Copyright IBM Corp. 2008, 2011
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
@@ -187,6 +187,10 @@
 		return -EOPNOTSUPP;
 	}
 
+	/*
+	 * no need to check the return value of vcpu_stop as it can only have
+	 * an error for protvirt, but protvirt means user cpu state
+	 */
 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
 		kvm_s390_vcpu_stop(vcpu);
 	vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
--- linux-ein-5.4.0.orig/arch/s390/kvm/gaccess.c
+++ linux-ein-5.4.0/arch/s390/kvm/gaccess.c
@@ -9,6 +9,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm_types.h>
 #include <linux/err.h>
+#include <linux/bitfield.h>
 
 #include <asm/pgtable.h>
 #include <asm/gmap.h>
@@ -794,48 +795,268 @@
 	return 1;
 }
 
-static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
-			    unsigned long *pages, unsigned long nr_pages,
-			    const union asce asce, enum gacc_mode mode)
+static int vm_check_access_key(struct kvm *kvm, u8 access_key,
+			       enum gacc_mode mode, gpa_t gpa)
+{
+	u8 storage_key, access_control;
+	bool fetch_protected;
+	unsigned long hva;
+	int r;
+
+	if (access_key == 0)
+		return 0;
+
+	hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
+	if (kvm_is_error_hva(hva))
+		return PGM_ADDRESSING;
+
+	down_read(&current->mm->mmap_sem);
+	r = get_guest_storage_key(current->mm, hva, &storage_key);
+	up_read(&current->mm->mmap_sem);
+	if (r)
+		return r;
+	access_control = FIELD_GET(_PAGE_ACC_BITS, storage_key);
+	if (access_control == access_key)
+		return 0;
+	fetch_protected = storage_key & _PAGE_FP_BIT;
+	if ((mode == GACC_FETCH || mode == GACC_IFETCH) && !fetch_protected)
+		return 0;
+	return PGM_PROTECTION;
+}
+
+static bool fetch_prot_override_applicable(struct kvm_vcpu *vcpu, enum gacc_mode mode,
+					   union asce asce)
+{
+	psw_t *psw = &vcpu->arch.sie_block->gpsw;
+	unsigned long override;
+
+	if (mode == GACC_FETCH || mode == GACC_IFETCH) {
+		/* check if fetch protection override enabled */
+		override = vcpu->arch.sie_block->gcr[0];
+		override &= CR0_FETCH_PROTECTION_OVERRIDE;
+		/* not applicable if subject to DAT && private space */
+		override = override && !(psw_bits(*psw).dat && asce.p);
+		return override;
+	}
+	return false;
+}
+
+static bool fetch_prot_override_applies(unsigned long ga, unsigned int len)
+{
+	return ga < 2048 && ga + len <= 2048;
+}
+
+static bool storage_prot_override_applicable(struct kvm_vcpu *vcpu)
+{
+	/* check if storage protection override enabled */
+	return vcpu->arch.sie_block->gcr[0] & CR0_STORAGE_PROTECTION_OVERRIDE;
+}
+
+static bool storage_prot_override_applies(u8 access_control)
+{
+	/* matches special storage protection override key (9) -> allow */
+	return access_control == PAGE_SPO_ACC;
+}
+
+static int vcpu_check_access_key(struct kvm_vcpu *vcpu, u8 access_key,
+				 enum gacc_mode mode, union asce asce, gpa_t gpa,
+				 unsigned long ga, unsigned int len)
+{
+	u8 storage_key, access_control;
+	unsigned long hva;
+	int r;
+
+	/* access key 0 matches any storage key -> allow */
+	if (access_key == 0)
+		return 0;
+	/*
+	 * caller needs to ensure that gfn is accessible, so we can
+	 * assume that this cannot fail
+	 */
+	hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gpa));
+	down_read(&current->mm->mmap_sem);
+	r = get_guest_storage_key(current->mm, hva, &storage_key);
+	up_read(&current->mm->mmap_sem);
+	if (r)
+		return r;
+	access_control = FIELD_GET(_PAGE_ACC_BITS, storage_key);
+	/* access key matches storage key -> allow */
+	if (access_control == access_key)
+		return 0;
+	if (mode == GACC_FETCH || mode == GACC_IFETCH) {
+		/* it is a fetch and fetch protection is off -> allow */
+		if (!(storage_key & _PAGE_FP_BIT))
+			return 0;
+		if (fetch_prot_override_applicable(vcpu, mode, asce) &&
+		    fetch_prot_override_applies(ga, len))
+			return 0;
+	}
+	if (storage_prot_override_applicable(vcpu) &&
+	    storage_prot_override_applies(access_control))
+		return 0;
+	return PGM_PROTECTION;
+}
+
+/**
+ * guest_range_to_gpas() - Calculate guest physical addresses of page fragments
+ * covering a logical range
+ * @vcpu: virtual cpu
+ * @ga: guest address, start of range
+ * @ar: access register
+ * @gpas: output argument, may be NULL
+ * @len: length of range in bytes
+ * @asce: address-space-control element to use for translation
+ * @mode: access mode
+ * @access_key: access key to mach the range's storage keys against
+ *
+ * Translate a logical range to a series of guest absolute addresses,
+ * such that the concatenation of page fragments starting at each gpa make up
+ * the whole range.
+ * The translation is performed as if done by the cpu for the given @asce, @ar,
+ * @mode and state of the @vcpu.
+ * If the translation causes an exception, its program interruption code is
+ * returned and the &struct kvm_s390_pgm_info pgm member of @vcpu is modified
+ * such that a subsequent call to kvm_s390_inject_prog_vcpu() will inject
+ * a correct exception into the guest.
+ * The resulting gpas are stored into @gpas, unless it is NULL.
+ *
+ * Note: All fragments except the first one start at the beginning of a page.
+ *	 When deriving the boundaries of a fragment from a gpa, all but the last
+ *	 fragment end at the end of the page.
+ *
+ * Return:
+ * * 0		- success
+ * * <0		- translation could not be performed, for example if  guest
+ *		  memory could not be accessed
+ * * >0		- an access exception occurred. In this case the returned value
+ *		  is the program interruption code and the contents of pgm may
+ *		  be used to inject an exception into the guest.
+ */
+static int guest_range_to_gpas(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
+			       unsigned long *gpas, unsigned long len,
+			       const union asce asce, enum gacc_mode mode,
+			       u8 access_key)
 {
 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
+	unsigned int offset = offset_in_page(ga);
+	unsigned int fragment_len;
 	int lap_enabled, rc = 0;
 	enum prot_type prot;
+	unsigned long gpa;
 
 	lap_enabled = low_address_protection_enabled(vcpu, asce);
-	while (nr_pages) {
+	while (min(PAGE_SIZE - offset, len) > 0) {
+		fragment_len = min(PAGE_SIZE - offset, len);
 		ga = kvm_s390_logical_to_effective(vcpu, ga);
 		if (mode == GACC_STORE && lap_enabled && is_low_address(ga))
 			return trans_exc(vcpu, PGM_PROTECTION, ga, ar, mode,
 					 PROT_TYPE_LA);
-		ga &= PAGE_MASK;
 		if (psw_bits(*psw).dat) {
-			rc = guest_translate(vcpu, ga, pages, asce, mode, &prot);
+			rc = guest_translate(vcpu, ga, &gpa, asce, mode, &prot);
 			if (rc < 0)
 				return rc;
 		} else {
-			*pages = kvm_s390_real_to_abs(vcpu, ga);
-			if (kvm_is_error_gpa(vcpu->kvm, *pages))
+			gpa = kvm_s390_real_to_abs(vcpu, ga);
+			if (kvm_is_error_gpa(vcpu->kvm, gpa))
 				rc = PGM_ADDRESSING;
 		}
 		if (rc)
 			return trans_exc(vcpu, rc, ga, ar, mode, prot);
-		ga += PAGE_SIZE;
-		pages++;
-		nr_pages--;
+		rc = vcpu_check_access_key(vcpu, access_key, mode, asce, gpa, ga,
+					   fragment_len);
+		if (rc)
+			return trans_exc(vcpu, rc, ga, ar, mode, PROT_TYPE_KEYC);
+		if (gpas)
+			*gpas++ = gpa;
+		offset = 0;
+		ga += fragment_len;
+		len -= fragment_len;
 	}
 	return 0;
 }
 
-int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, void *data,
-		 unsigned long len, enum gacc_mode mode)
+static int access_guest_page(struct kvm *kvm, enum gacc_mode mode, gpa_t gpa,
+			     void *data, unsigned int len)
+{
+	const unsigned int offset = offset_in_page(gpa);
+	const gfn_t gfn = gpa_to_gfn(gpa);
+	int rc;
+
+	if (mode == GACC_STORE)
+		rc = kvm_write_guest_page(kvm, gfn, data, offset, len);
+	else
+		rc = kvm_read_guest_page(kvm, gfn, data, offset, len);
+	return rc;
+}
+
+static int
+access_guest_page_with_key(struct kvm *kvm, enum gacc_mode mode, gpa_t gpa,
+			   void *data, unsigned int len, u8 access_key)
+{
+	struct kvm_memory_slot *slot;
+	bool writable;
+	gfn_t gfn;
+	hva_t hva;
+	int rc;
+
+	gfn = gpa >> PAGE_SHIFT;
+	slot = gfn_to_memslot(kvm, gfn);
+	hva = gfn_to_hva_memslot_prot(slot, gfn, &writable);
+
+	if (kvm_is_error_hva(hva))
+		return PGM_ADDRESSING;
+	/*
+	 * Check if it's a ro memslot, even tho that can't occur (they're unsupported).
+	 * Don't try to actually handle that case.
+	 */
+	if (!writable && mode == GACC_STORE)
+		return -EOPNOTSUPP;
+	hva += offset_in_page(gpa);
+	if (mode == GACC_STORE)
+		rc = copy_to_user_key((void __user *)hva, data, len, access_key);
+	else
+		rc = copy_from_user_key(data, (void __user *)hva, len, access_key);
+	if (rc)
+		return PGM_PROTECTION;
+	if (mode == GACC_STORE)
+		mark_page_dirty(kvm, gfn);
+	return 0;
+}
+
+int access_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, void *data,
+			      unsigned long len, enum gacc_mode mode, u8 access_key)
+{
+	int offset = offset_in_page(gpa);
+	int fragment_len;
+	int rc;
+
+	while (min(PAGE_SIZE - offset, len) > 0) {
+		fragment_len = min(PAGE_SIZE - offset, len);
+		rc = access_guest_page_with_key(kvm, mode, gpa, data, fragment_len, access_key);
+		if (rc)
+			return rc;
+		offset = 0;
+		len -= fragment_len;
+		data += fragment_len;
+		gpa += fragment_len;
+	}
+	return 0;
+}
+
+int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
+			  void *data, unsigned long len, enum gacc_mode mode,
+			  u8 access_key)
 {
 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
-	unsigned long _len, nr_pages, gpa, idx;
-	unsigned long pages_array[2];
-	unsigned long *pages;
+	unsigned long nr_pages, idx;
+	unsigned long gpa_array[2];
+	unsigned int fragment_len;
+	unsigned long *gpas;
+	enum prot_type prot;
 	int need_ipte_lock;
 	union asce asce;
+	bool try_storage_prot_override;
+	bool try_fetch_prot_override;
 	int rc;
 
 	if (!len)
@@ -845,55 +1066,85 @@
 	if (rc)
 		return rc;
 	nr_pages = (((ga & ~PAGE_MASK) + len - 1) >> PAGE_SHIFT) + 1;
-	pages = pages_array;
-	if (nr_pages > ARRAY_SIZE(pages_array))
-		pages = vmalloc(array_size(nr_pages, sizeof(unsigned long)));
-	if (!pages)
+	gpas = gpa_array;
+	if (nr_pages > ARRAY_SIZE(gpa_array))
+		gpas = vmalloc(array_size(nr_pages, sizeof(unsigned long)));
+	if (!gpas)
 		return -ENOMEM;
+	try_fetch_prot_override = fetch_prot_override_applicable(vcpu, mode, asce);
+	try_storage_prot_override = storage_prot_override_applicable(vcpu);
 	need_ipte_lock = psw_bits(*psw).dat && !asce.r;
 	if (need_ipte_lock)
 		ipte_lock(vcpu);
-	rc = guest_page_range(vcpu, ga, ar, pages, nr_pages, asce, mode);
-	for (idx = 0; idx < nr_pages && !rc; idx++) {
-		gpa = *(pages + idx) + (ga & ~PAGE_MASK);
-		_len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len);
-		if (mode == GACC_STORE)
-			rc = kvm_write_guest(vcpu->kvm, gpa, data, _len);
-		else
-			rc = kvm_read_guest(vcpu->kvm, gpa, data, _len);
-		len -= _len;
-		ga += _len;
-		data += _len;
+	/*
+	 * Since we do the access further down ultimately via a move instruction
+	 * that does key checking and returns an error in case of a protection
+	 * violation, we don't need to do the check during address translation.
+	 * Skip it by passing access key 0, which matches any storage key,
+	 * obviating the need for any further checks. As a result the check is
+	 * handled entirely in hardware on access, we only need to take care to
+	 * forego key protection checking if fetch protection override applies or
+	 * retry with the special key 9 in case of storage protection override.
+	 */
+	rc = guest_range_to_gpas(vcpu, ga, ar, gpas, len, asce, mode, 0);
+	if (rc)
+		goto out_unlock;
+	for (idx = 0; idx < nr_pages; idx++) {
+		fragment_len = min(PAGE_SIZE - offset_in_page(gpas[idx]), len);
+		if (try_fetch_prot_override && fetch_prot_override_applies(ga, fragment_len)) {
+			rc = access_guest_page(vcpu->kvm, mode, gpas[idx],
+					       data, fragment_len);
+		} else {
+			rc = access_guest_page_with_key(vcpu->kvm, mode, gpas[idx],
+							data, fragment_len, access_key);
+		}
+		if (rc == PGM_PROTECTION && try_storage_prot_override)
+			rc = access_guest_page_with_key(vcpu->kvm, mode, gpas[idx],
+							data, fragment_len, PAGE_SPO_ACC);
+		if (rc == PGM_PROTECTION)
+			prot = PROT_TYPE_KEYC;
+		if (rc)
+			break;
+		len -= fragment_len;
+		data += fragment_len;
+		ga = kvm_s390_logical_to_effective(vcpu, ga + fragment_len);
 	}
+	if (rc > 0)
+		rc = trans_exc(vcpu, rc, ga, ar, mode, prot);
+out_unlock:
 	if (need_ipte_lock)
 		ipte_unlock(vcpu);
-	if (nr_pages > ARRAY_SIZE(pages_array))
-		vfree(pages);
+	if (nr_pages > ARRAY_SIZE(gpa_array))
+		vfree(gpas);
 	return rc;
 }
 
 int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
 		      void *data, unsigned long len, enum gacc_mode mode)
 {
-	unsigned long _len, gpa;
+	unsigned int fragment_len;
+	unsigned long gpa;
 	int rc = 0;
 
 	while (len && !rc) {
 		gpa = kvm_s390_real_to_abs(vcpu, gra);
-		_len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len);
-		if (mode)
-			rc = write_guest_abs(vcpu, gpa, data, _len);
-		else
-			rc = read_guest_abs(vcpu, gpa, data, _len);
-		len -= _len;
-		gra += _len;
-		data += _len;
+		fragment_len = min(PAGE_SIZE - offset_in_page(gpa), len);
+		rc = access_guest_page(vcpu->kvm, mode, gpa, data, fragment_len);
+		len -= fragment_len;
+		gra += fragment_len;
+		data += fragment_len;
 	}
 	return rc;
 }
 
 /**
- * guest_translate_address - translate guest logical into guest absolute address
+ * guest_translate_address_with_key - translate guest logical into guest absolute address
+ * @vcpu: virtual cpu
+ * @gva: Guest virtual address
+ * @ar: Access register
+ * @gpa: Guest physical address
+ * @mode: Translation access mode
+ * @access_key: access key to mach the storage key with
  *
  * Parameter semantics are the same as the ones from guest_translate.
  * The memory contents at the guest address are not changed.
@@ -901,11 +1152,10 @@
  * Note: The IPTE lock is not taken during this function, so the caller
  * has to take care of this.
  */
-int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
-			    unsigned long *gpa, enum gacc_mode mode)
+int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
+				     unsigned long *gpa, enum gacc_mode mode,
+				     u8 access_key)
 {
-	psw_t *psw = &vcpu->arch.sie_block->gpsw;
-	enum prot_type prot;
 	union asce asce;
 	int rc;
 
@@ -913,47 +1163,59 @@
 	rc = get_vcpu_asce(vcpu, &asce, gva, ar, mode);
 	if (rc)
 		return rc;
-	if (is_low_address(gva) && low_address_protection_enabled(vcpu, asce)) {
-		if (mode == GACC_STORE)
-			return trans_exc(vcpu, PGM_PROTECTION, gva, 0,
-					 mode, PROT_TYPE_LA);
-	}
-
-	if (psw_bits(*psw).dat && !asce.r) {	/* Use DAT? */
-		rc = guest_translate(vcpu, gva, gpa, asce, mode, &prot);
-		if (rc > 0)
-			return trans_exc(vcpu, rc, gva, 0, mode, prot);
-	} else {
-		*gpa = kvm_s390_real_to_abs(vcpu, gva);
-		if (kvm_is_error_gpa(vcpu->kvm, *gpa))
-			return trans_exc(vcpu, rc, gva, PGM_ADDRESSING, mode, 0);
-	}
-
-	return rc;
+	return guest_range_to_gpas(vcpu, gva, ar, gpa, 1, asce, mode,
+				   access_key);
 }
 
 /**
  * check_gva_range - test a range of guest virtual addresses for accessibility
+ * @vcpu: virtual cpu
+ * @gva: Guest virtual address
+ * @ar: Access register
+ * @length: Length of test range
+ * @mode: Translation access mode
+ * @access_key: access key to mach the storage keys with
  */
 int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
-		    unsigned long length, enum gacc_mode mode)
+		    unsigned long length, enum gacc_mode mode, u8 access_key)
 {
-	unsigned long gpa;
-	unsigned long currlen;
+	union asce asce;
 	int rc = 0;
 
+	rc = get_vcpu_asce(vcpu, &asce, gva, ar, mode);
+	if (rc)
+		return rc;
 	ipte_lock(vcpu);
-	while (length > 0 && !rc) {
-		currlen = min(length, PAGE_SIZE - (gva % PAGE_SIZE));
-		rc = guest_translate_address(vcpu, gva, ar, &gpa, mode);
-		gva += currlen;
-		length -= currlen;
-	}
+	rc = guest_range_to_gpas(vcpu, gva, ar, NULL, length, asce, mode,
+				 access_key);
 	ipte_unlock(vcpu);
 
 	return rc;
 }
 
+/**
+ * check_gpa_range - test a range of guest physical addresses for accessibility
+ * @kvm: virtual machine instance
+ * @gpa: guest physical address
+ * @length: length of test range
+ * @mode: access mode to test, relevant for storage keys
+ * @access_key: access key to mach the storage keys with
+ */
+int check_gpa_range(struct kvm *kvm, unsigned long gpa, unsigned long length,
+		    enum gacc_mode mode, u8 access_key)
+{
+	unsigned int fragment_len;
+	int rc = 0;
+
+	while (length && !rc) {
+		fragment_len = min(PAGE_SIZE - offset_in_page(gpa), length);
+		rc = vm_check_access_key(kvm, access_key, mode, gpa);
+		length -= fragment_len;
+		gpa += fragment_len;
+	}
+	return rc;
+}
+
 /**
  * kvm_s390_check_low_addr_prot_real - check for low-address protection
  * @gra: Guest real address
--- linux-ein-5.4.0.orig/arch/s390/kvm/gaccess.h
+++ linux-ein-5.4.0/arch/s390/kvm/gaccess.h
@@ -18,17 +18,14 @@
 
 /**
  * kvm_s390_real_to_abs - convert guest real address to guest absolute address
- * @vcpu - guest virtual cpu
+ * @prefix - guest prefix
  * @gra - guest real address
  *
  * Returns the guest absolute address that corresponds to the passed guest real
- * address @gra of a virtual guest cpu by applying its prefix.
+ * address @gra of by applying the given prefix.
  */
-static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu,
-						 unsigned long gra)
+static inline unsigned long _kvm_s390_real_to_abs(u32 prefix, unsigned long gra)
 {
-	unsigned long prefix  = kvm_s390_get_prefix(vcpu);
-
 	if (gra < 2 * PAGE_SIZE)
 		gra += prefix;
 	else if (gra >= prefix && gra < prefix + 2 * PAGE_SIZE)
@@ -37,6 +34,43 @@
 }
 
 /**
+ * kvm_s390_real_to_abs - convert guest real address to guest absolute address
+ * @vcpu - guest virtual cpu
+ * @gra - guest real address
+ *
+ * Returns the guest absolute address that corresponds to the passed guest real
+ * address @gra of a virtual guest cpu by applying its prefix.
+ */
+static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu,
+						 unsigned long gra)
+{
+	return _kvm_s390_real_to_abs(kvm_s390_get_prefix(vcpu), gra);
+}
+
+/**
+ * _kvm_s390_logical_to_effective - convert guest logical to effective address
+ * @psw: psw of the guest
+ * @ga: guest logical address
+ *
+ * Convert a guest logical address to an effective address by applying the
+ * rules of the addressing mode defined by bits 31 and 32 of the given PSW
+ * (extendended/basic addressing mode).
+ *
+ * Depending on the addressing mode, the upper 40 bits (24 bit addressing
+ * mode), 33 bits (31 bit addressing mode) or no bits (64 bit addressing
+ * mode) of @ga will be zeroed and the remaining bits will be returned.
+ */
+static inline unsigned long _kvm_s390_logical_to_effective(psw_t *psw,
+							   unsigned long ga)
+{
+	if (psw_bits(*psw).eaba == PSW_BITS_AMODE_64BIT)
+		return ga;
+	if (psw_bits(*psw).eaba == PSW_BITS_AMODE_31BIT)
+		return ga & ((1UL << 31) - 1);
+	return ga & ((1UL << 24) - 1);
+}
+
+/**
  * kvm_s390_logical_to_effective - convert guest logical to effective address
  * @vcpu: guest virtual cpu
  * @ga: guest logical address
@@ -52,13 +86,7 @@
 static inline unsigned long kvm_s390_logical_to_effective(struct kvm_vcpu *vcpu,
 							  unsigned long ga)
 {
-	psw_t *psw = &vcpu->arch.sie_block->gpsw;
-
-	if (psw_bits(*psw).eaba == PSW_BITS_AMODE_64BIT)
-		return ga;
-	if (psw_bits(*psw).eaba == PSW_BITS_AMODE_31BIT)
-		return ga & ((1UL << 31) - 1);
-	return ga & ((1UL << 24) - 1);
+	return _kvm_s390_logical_to_effective(&vcpu->arch.sie_block->gpsw, ga);
 }
 
 /*
@@ -158,24 +186,34 @@
 	GACC_IFETCH,
 };
 
-int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
-			    u8 ar, unsigned long *gpa, enum gacc_mode mode);
+int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
+				     unsigned long *gpa, enum gacc_mode mode,
+				     u8 access_key);
+
 int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
-		    unsigned long length, enum gacc_mode mode);
+		    unsigned long length, enum gacc_mode mode, u8 access_key);
+
+int check_gpa_range(struct kvm *kvm, unsigned long gpa, unsigned long length,
+		    enum gacc_mode mode, u8 access_key);
 
-int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, void *data,
-		 unsigned long len, enum gacc_mode mode);
+int access_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, void *data,
+			      unsigned long len, enum gacc_mode mode, u8 access_key);
+
+int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
+			  void *data, unsigned long len, enum gacc_mode mode,
+			  u8 access_key);
 
 int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
 		      void *data, unsigned long len, enum gacc_mode mode);
 
 /**
- * write_guest - copy data from kernel space to guest space
+ * write_guest_with_key - copy data from kernel space to guest space
  * @vcpu: virtual cpu
  * @ga: guest address
  * @ar: access register
  * @data: source address in kernel space
  * @len: number of bytes to copy
+ * @access_key: access key the storage key needs to match
  *
  * Copy @len bytes from @data (kernel space) to @ga (guest address).
  * In order to copy data to guest space the PSW of the vcpu is inspected:
@@ -186,8 +224,8 @@
  * The addressing mode of the PSW is also inspected, so that address wrap
  * around is taken into account for 24-, 31- and 64-bit addressing mode,
  * if the to be copied data crosses page boundaries in guest address space.
- * In addition also low address and DAT protection are inspected before
- * copying any data (key protection is currently not implemented).
+ * In addition low address, DAT and key protection checks are performed before
+ * copying any data.
  *
  * This function modifies the 'struct kvm_s390_pgm_info pgm' member of @vcpu.
  * In case of an access exception (e.g. protection exception) pgm will contain
@@ -215,10 +253,53 @@
  *	 if data has been changed in guest space in case of an exception.
  */
 static inline __must_check
+int write_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
+			 void *data, unsigned long len, u8 access_key)
+{
+	return access_guest_with_key(vcpu, ga, ar, data, len, GACC_STORE,
+				     access_key);
+}
+
+/**
+ * write_guest - copy data from kernel space to guest space
+ * @vcpu: virtual cpu
+ * @ga: guest address
+ * @ar: access register
+ * @data: source address in kernel space
+ * @len: number of bytes to copy
+ *
+ * The behaviour of write_guest is identical to write_guest_with_key, except
+ * that the PSW access key is used instead of an explicit argument.
+ */
+static inline __must_check
 int write_guest(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, void *data,
 		unsigned long len)
 {
-	return access_guest(vcpu, ga, ar, data, len, GACC_STORE);
+	u8 access_key = psw_bits(vcpu->arch.sie_block->gpsw).key;
+
+	return write_guest_with_key(vcpu, ga, ar, data, len, access_key);
+}
+
+/**
+ * read_guest_with_key - copy data from guest space to kernel space
+ * @vcpu: virtual cpu
+ * @ga: guest address
+ * @ar: access register
+ * @data: destination address in kernel space
+ * @len: number of bytes to copy
+ * @access_key: access key the storage key needs to match
+ *
+ * Copy @len bytes from @ga (guest address) to @data (kernel space).
+ *
+ * The behaviour of read_guest_with_key is identical to write_guest_with_key,
+ * except that data will be copied from guest space to kernel space.
+ */
+static inline __must_check
+int read_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
+			void *data, unsigned long len, u8 access_key)
+{
+	return access_guest_with_key(vcpu, ga, ar, data, len, GACC_FETCH,
+				     access_key);
 }
 
 /**
@@ -231,14 +312,16 @@
  *
  * Copy @len bytes from @ga (guest address) to @data (kernel space).
  *
- * The behaviour of read_guest is identical to write_guest, except that
- * data will be copied from guest space to kernel space.
+ * The behaviour of read_guest is identical to read_guest_with_key, except
+ * that the PSW access key is used instead of an explicit argument.
  */
 static inline __must_check
 int read_guest(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, void *data,
 	       unsigned long len)
 {
-	return access_guest(vcpu, ga, ar, data, len, GACC_FETCH);
+	u8 access_key = psw_bits(vcpu->arch.sie_block->gpsw).key;
+
+	return read_guest_with_key(vcpu, ga, ar, data, len, access_key);
 }
 
 /**
@@ -259,7 +342,10 @@
 int read_guest_instr(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
 		     unsigned long len)
 {
-	return access_guest(vcpu, ga, 0, data, len, GACC_IFETCH);
+	u8 access_key = psw_bits(vcpu->arch.sie_block->gpsw).key;
+
+	return access_guest_with_key(vcpu, ga, 0, data, len, GACC_IFETCH,
+				     access_key);
 }
 
 /**
--- linux-ein-5.4.0.orig/arch/s390/kvm/intercept.c
+++ linux-ein-5.4.0/arch/s390/kvm/intercept.c
@@ -2,7 +2,7 @@
 /*
  * in-kernel handling for sie intercepts
  *
- * Copyright IBM Corp. 2008, 2014
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
@@ -16,6 +16,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/irq.h>
 #include <asm/sysinfo.h>
+#include <asm/uv.h>
 
 #include "kvm-s390.h"
 #include "gaccess.h"
@@ -79,6 +80,10 @@
 			return rc;
 	}
 
+	/*
+	 * no need to check the return value of vcpu_stop as it can only have
+	 * an error for protvirt, but protvirt means user cpu state
+	 */
 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
 		kvm_s390_vcpu_stop(vcpu);
 	return -EOPNOTSUPP;
@@ -231,6 +236,13 @@
 
 	vcpu->stat.exit_program_interruption++;
 
+	/*
+	 * Intercept 8 indicates a loop of specification exceptions
+	 * for protected guests.
+	 */
+	if (kvm_s390_pv_cpu_is_protected(vcpu))
+		return -EOPNOTSUPP;
+
 	if (guestdbg_enabled(vcpu) && per_event(vcpu)) {
 		rc = kvm_s390_handle_per_event(vcpu);
 		if (rc)
@@ -318,18 +330,18 @@
 
 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 
-	/* Make sure that the source is paged-in */
-	rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg2],
-				     reg2, &srcaddr, GACC_FETCH);
+	/* Ensure that the source is paged-in, no actual access -> no key checking */
+	rc = guest_translate_address_with_key(vcpu, vcpu->run->s.regs.gprs[reg2],
+					      reg2, &srcaddr, GACC_FETCH, 0);
 	if (rc)
 		return kvm_s390_inject_prog_cond(vcpu, rc);
 	rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0);
 	if (rc != 0)
 		return rc;
 
-	/* Make sure that the destination is paged-in */
-	rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg1],
-				     reg1, &dstaddr, GACC_STORE);
+	/* Ensure that the source is paged-in, no actual access -> no key checking */
+	rc = guest_translate_address_with_key(vcpu, vcpu->run->s.regs.gprs[reg1],
+					      reg1, &dstaddr, GACC_STORE, 0);
 	if (rc)
 		return kvm_s390_inject_prog_cond(vcpu, rc);
 	rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1);
@@ -360,8 +372,8 @@
  */
 int handle_sthyi(struct kvm_vcpu *vcpu)
 {
-	int reg1, reg2, r = 0;
-	u64 code, addr, cc = 0, rc = 0;
+	int reg1, reg2, cc = 0, r = 0;
+	u64 code, addr, rc = 0;
 	struct sthyi_sctns *sctns = NULL;
 
 	if (!test_kvm_facility(vcpu->kvm, 74))
@@ -384,7 +396,7 @@
 		goto out;
 	}
 
-	if (addr & ~PAGE_MASK)
+	if (!kvm_s390_pv_cpu_is_protected(vcpu) && (addr & ~PAGE_MASK))
 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
 	sctns = (void *)get_zeroed_page(GFP_KERNEL);
@@ -392,13 +404,21 @@
 		return -ENOMEM;
 
 	cc = sthyi_fill(sctns, &rc);
-
+	if (cc < 0) {
+		free_page((unsigned long)sctns);
+		return cc;
+	}
 out:
 	if (!cc) {
-		r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
-		if (r) {
-			free_page((unsigned long)sctns);
-			return kvm_s390_inject_prog_cond(vcpu, r);
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			memcpy((void *)(sida_origin(vcpu->arch.sie_block)),
+			       sctns, PAGE_SIZE);
+		} else {
+			r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
+			if (r) {
+				free_page((unsigned long)sctns);
+				return kvm_s390_inject_prog_cond(vcpu, r);
+			}
 		}
 	}
 
@@ -444,6 +464,97 @@
 	return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
 }
 
+static int handle_pv_spx(struct kvm_vcpu *vcpu)
+{
+	u32 pref = *(u32 *)vcpu->arch.sie_block->sidad;
+
+	kvm_s390_set_prefix(vcpu, pref);
+	trace_kvm_s390_handle_prefix(vcpu, 1, pref);
+	return 0;
+}
+
+static int handle_pv_sclp(struct kvm_vcpu *vcpu)
+{
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+
+	spin_lock(&fi->lock);
+	/*
+	 * 2 cases:
+	 * a: an sccb answering interrupt was already pending or in flight.
+	 *    As the sccb value is not known we can simply set some value to
+	 *    trigger delivery of a saved SCCB. UV will then use its saved
+	 *    copy of the SCCB value.
+	 * b: an error SCCB interrupt needs to be injected so we also inject
+	 *    a fake SCCB address. Firmware will use the proper one.
+	 * This makes sure, that both errors and real sccb returns will only
+	 * be delivered after a notification intercept (instruction has
+	 * finished) but not after others.
+	 */
+	fi->srv_signal.ext_params |= 0x43000;
+	set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
+	clear_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
+	spin_unlock(&fi->lock);
+	return 0;
+}
+
+static int handle_pv_uvc(struct kvm_vcpu *vcpu)
+{
+	struct uv_cb_share *guest_uvcb = (void *)vcpu->arch.sie_block->sidad;
+	struct uv_cb_cts uvcb = {
+		.header.cmd	= UVC_CMD_UNPIN_PAGE_SHARED,
+		.header.len	= sizeof(uvcb),
+		.guest_handle	= kvm_s390_pv_get_handle(vcpu->kvm),
+		.gaddr		= guest_uvcb->paddr,
+	};
+	int rc;
+
+	if (guest_uvcb->header.cmd != UVC_CMD_REMOVE_SHARED_ACCESS) {
+		WARN_ONCE(1, "Unexpected notification intercept for UVC 0x%x\n",
+			  guest_uvcb->header.cmd);
+		return 0;
+	}
+	rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb);
+	/*
+	 * If the unpin did not succeed, the guest will exit again for the UVC
+	 * and we will retry the unpin.
+	 */
+	if (rc == -EINVAL)
+		return 0;
+	/*
+	 * If we got -EAGAIN here, we simply return it. It will eventually
+	 * get propagated all the way to userspace, which should then try
+	 * again.
+	 */
+	return rc;
+}
+
+static int handle_pv_notification(struct kvm_vcpu *vcpu)
+{
+	int ret;
+
+	if (vcpu->arch.sie_block->ipa == 0xb210)
+		return handle_pv_spx(vcpu);
+	if (vcpu->arch.sie_block->ipa == 0xb220)
+		return handle_pv_sclp(vcpu);
+	if (vcpu->arch.sie_block->ipa == 0xb9a4)
+		return handle_pv_uvc(vcpu);
+	if (vcpu->arch.sie_block->ipa >> 8 == 0xae) {
+		/*
+		 * Besides external call, other SIGP orders also cause a
+		 * 108 (pv notify) intercept. In contrast to external call,
+		 * these orders need to be emulated and hence the appropriate
+		 * place to handle them is in handle_instruction().
+		 * So first try kvm_s390_handle_sigp_pei() and if that isn't
+		 * successful, go on with handle_instruction().
+		 */
+		ret = kvm_s390_handle_sigp_pei(vcpu);
+		if (!ret)
+			return ret;
+	}
+
+	return handle_instruction(vcpu);
+}
+
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
 {
 	int rc, per_rc = 0;
@@ -480,6 +591,28 @@
 	case ICPT_KSS:
 		rc = kvm_s390_skey_check_enable(vcpu);
 		break;
+	case ICPT_MCHKREQ:
+	case ICPT_INT_ENABLE:
+		/*
+		 * PSW bit 13 or a CR (0, 6, 14) changed and we might
+		 * now be able to deliver interrupts. The pre-run code
+		 * will take care of this.
+		 */
+		rc = 0;
+		break;
+	case ICPT_PV_INSTR:
+		rc = handle_instruction(vcpu);
+		break;
+	case ICPT_PV_NOTIFY:
+		rc = handle_pv_notification(vcpu);
+		break;
+	case ICPT_PV_PREF:
+		rc = 0;
+		gmap_convert_to_secure(vcpu->arch.gmap,
+				       kvm_s390_get_prefix(vcpu));
+		gmap_convert_to_secure(vcpu->arch.gmap,
+				       kvm_s390_get_prefix(vcpu) + PAGE_SIZE);
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
--- linux-ein-5.4.0.orig/arch/s390/kvm/interrupt.c
+++ linux-ein-5.4.0/arch/s390/kvm/interrupt.c
@@ -2,7 +2,7 @@
 /*
  * handling kvm guest interrupts
  *
- * Copyright IBM Corp. 2008, 2015
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  */
@@ -81,8 +81,9 @@
 		struct esca_block *sca = vcpu->kvm->arch.sca;
 		union esca_sigp_ctrl *sigp_ctrl =
 			&(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-		union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+		union esca_sigp_ctrl new_val = {0}, old_val;
 
+		old_val = READ_ONCE(*sigp_ctrl);
 		new_val.scn = src_id;
 		new_val.c = 1;
 		old_val.c = 0;
@@ -93,8 +94,9 @@
 		struct bsca_block *sca = vcpu->kvm->arch.sca;
 		union bsca_sigp_ctrl *sigp_ctrl =
 			&(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-		union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+		union bsca_sigp_ctrl new_val = {0}, old_val;
 
+		old_val = READ_ONCE(*sigp_ctrl);
 		new_val.scn = src_id;
 		new_val.c = 1;
 		old_val.c = 0;
@@ -124,16 +126,18 @@
 		struct esca_block *sca = vcpu->kvm->arch.sca;
 		union esca_sigp_ctrl *sigp_ctrl =
 			&(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-		union esca_sigp_ctrl old = *sigp_ctrl;
+		union esca_sigp_ctrl old;
 
+		old = READ_ONCE(*sigp_ctrl);
 		expect = old.value;
 		rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
 	} else {
 		struct bsca_block *sca = vcpu->kvm->arch.sca;
 		union bsca_sigp_ctrl *sigp_ctrl =
 			&(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-		union bsca_sigp_ctrl old = *sigp_ctrl;
+		union bsca_sigp_ctrl old;
 
+		old = READ_ONCE(*sigp_ctrl);
 		expect = old.value;
 		rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
 	}
@@ -324,8 +328,11 @@
 
 static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu)
 {
-	return vcpu->kvm->arch.float_int.pending_irqs |
-		vcpu->arch.local_int.pending_irqs;
+	unsigned long pending = vcpu->kvm->arch.float_int.pending_irqs |
+				vcpu->arch.local_int.pending_irqs;
+
+	pending &= ~vcpu->kvm->arch.float_int.masked_irqs;
+	return pending;
 }
 
 static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
@@ -383,10 +390,18 @@
 		__clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &active_mask);
 	if (!(vcpu->arch.sie_block->gcr[0] & CR0_CPU_TIMER_SUBMASK))
 		__clear_bit(IRQ_PEND_EXT_CPU_TIMER, &active_mask);
-	if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK))
+	if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) {
 		__clear_bit(IRQ_PEND_EXT_SERVICE, &active_mask);
+		__clear_bit(IRQ_PEND_EXT_SERVICE_EV, &active_mask);
+	}
 	if (psw_mchk_disabled(vcpu))
 		active_mask &= ~IRQ_PEND_MCHK_MASK;
+	/* PV guest cpus can have a single interruption injected at a time. */
+	if (kvm_s390_pv_cpu_is_protected(vcpu) &&
+	    vcpu->arch.sie_block->iictl != IICTL_CODE_NONE)
+		active_mask &= ~(IRQ_PEND_EXT_II_MASK |
+				 IRQ_PEND_IO_MASK |
+				 IRQ_PEND_MCHK_MASK);
 	/*
 	 * Check both floating and local interrupt's cr14 because
 	 * bit IRQ_PEND_MCHK_REP could be set in both cases.
@@ -408,13 +423,13 @@
 static void __set_cpu_idle(struct kvm_vcpu *vcpu)
 {
 	kvm_s390_set_cpuflags(vcpu, CPUSTAT_WAIT);
-	set_bit(vcpu->vcpu_id, vcpu->kvm->arch.idle_mask);
+	set_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.idle_mask);
 }
 
 static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
 {
 	kvm_s390_clear_cpuflags(vcpu, CPUSTAT_WAIT);
-	clear_bit(vcpu->vcpu_id, vcpu->kvm->arch.idle_mask);
+	clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.idle_mask);
 }
 
 static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
@@ -479,19 +494,23 @@
 static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-	int rc;
+	int rc = 0;
 
 	vcpu->stat.deliver_cputm++;
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,
 					 0, 0);
-
-	rc  = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
-			   (u16 *)__LC_EXT_INT_CODE);
-	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
-	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
-			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
-			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
+		vcpu->arch.sie_block->eic = EXT_IRQ_CPU_TIMER;
+	} else {
+		rc  = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
+				   (u16 *)__LC_EXT_INT_CODE);
+		rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
+		rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+		rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	}
 	clear_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
 	return rc ? -EFAULT : 0;
 }
@@ -499,19 +518,23 @@
 static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-	int rc;
+	int rc = 0;
 
 	vcpu->stat.deliver_ckc++;
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,
 					 0, 0);
-
-	rc  = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP,
-			   (u16 __user *)__LC_EXT_INT_CODE);
-	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
-	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
-			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
-			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
+		vcpu->arch.sie_block->eic = EXT_IRQ_CLK_COMP;
+	} else {
+		rc  = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP,
+				   (u16 __user *)__LC_EXT_INT_CODE);
+		rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
+		rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+		rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	}
 	clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
 	return rc ? -EFAULT : 0;
 }
@@ -553,6 +576,20 @@
 	union mci mci;
 	int rc;
 
+	/*
+	 * All other possible payload for a machine check (e.g. the register
+	 * contents in the save area) will be handled by the ultravisor, as
+	 * the hypervisor does not not have the needed information for
+	 * protected guests.
+	 */
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_MCHK;
+		vcpu->arch.sie_block->mcic = mchk->mcic;
+		vcpu->arch.sie_block->faddr = mchk->failing_storage_address;
+		vcpu->arch.sie_block->edc = mchk->ext_damage_code;
+		return 0;
+	}
+
 	mci.val = mchk->mcic;
 	/* take care of lazy register loading */
 	save_fpu_regs();
@@ -696,17 +733,21 @@
 static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-	int rc;
+	int rc = 0;
 
 	VCPU_EVENT(vcpu, 3, "%s", "deliver: cpu restart");
 	vcpu->stat.deliver_restart_signal++;
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0);
 
-	rc  = write_guest_lc(vcpu,
-			     offsetof(struct lowcore, restart_old_psw),
-			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-	rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw),
-			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_RESTART;
+	} else {
+		rc  = write_guest_lc(vcpu,
+				     offsetof(struct lowcore, restart_old_psw),
+				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+		rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw),
+				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	}
 	clear_bit(IRQ_PEND_RESTART, &li->pending_irqs);
 	return rc ? -EFAULT : 0;
 }
@@ -748,6 +789,12 @@
 	vcpu->stat.deliver_emergency_signal++;
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
 					 cpu_addr, 0);
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
+		vcpu->arch.sie_block->eic = EXT_IRQ_EMERGENCY_SIG;
+		vcpu->arch.sie_block->extcpuaddr = cpu_addr;
+		return 0;
+	}
 
 	rc  = put_guest_lc(vcpu, EXT_IRQ_EMERGENCY_SIG,
 			   (u16 *)__LC_EXT_INT_CODE);
@@ -776,6 +823,12 @@
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
 					 KVM_S390_INT_EXTERNAL_CALL,
 					 extcall.code, 0);
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
+		vcpu->arch.sie_block->eic = EXT_IRQ_EXTERNAL_CALL;
+		vcpu->arch.sie_block->extcpuaddr = extcall.code;
+		return 0;
+	}
 
 	rc  = put_guest_lc(vcpu, EXT_IRQ_EXTERNAL_CALL,
 			   (u16 *)__LC_EXT_INT_CODE);
@@ -787,6 +840,21 @@
 	return rc ? -EFAULT : 0;
 }
 
+static int __deliver_prog_pv(struct kvm_vcpu *vcpu, u16 code)
+{
+	switch (code) {
+	case PGM_SPECIFICATION:
+		vcpu->arch.sie_block->iictl = IICTL_CODE_SPECIFICATION;
+		break;
+	case PGM_OPERAND:
+		vcpu->arch.sie_block->iictl = IICTL_CODE_OPERAND;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -807,6 +875,10 @@
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
 					 pgm_info.code, 0);
 
+	/* PER is handled by the ultravisor */
+	if (kvm_s390_pv_cpu_is_protected(vcpu))
+		return __deliver_prog_pv(vcpu, pgm_info.code & ~PGM_PER);
+
 	switch (pgm_info.code & ~PGM_PER) {
 	case PGM_AFX_TRANSLATION:
 	case PGM_ASX_TRANSLATION:
@@ -902,20 +974,49 @@
 	return rc ? -EFAULT : 0;
 }
 
+#define SCCB_MASK 0xFFFFFFF8
+#define SCCB_EVENT_PENDING 0x3
+
+static int write_sclp(struct kvm_vcpu *vcpu, u32 parm)
+{
+	int rc;
+
+	if (kvm_s390_pv_cpu_get_handle(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
+		vcpu->arch.sie_block->eic = EXT_IRQ_SERVICE_SIG;
+		vcpu->arch.sie_block->eiparams = parm;
+		return 0;
+	}
+
+	rc  = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE);
+	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
+	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+	rc |= put_guest_lc(vcpu, parm,
+			   (u32 *)__LC_EXT_PARAMS);
+
+	return rc ? -EFAULT : 0;
+}
+
 static int __must_check __deliver_service(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	struct kvm_s390_ext_info ext;
-	int rc = 0;
 
 	spin_lock(&fi->lock);
-	if (!(test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs))) {
+	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs) ||
+	    !(test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs))) {
 		spin_unlock(&fi->lock);
 		return 0;
 	}
 	ext = fi->srv_signal;
 	memset(&fi->srv_signal, 0, sizeof(ext));
 	clear_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
+	clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs);
+	if (kvm_s390_pv_cpu_is_protected(vcpu))
+		set_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
 	spin_unlock(&fi->lock);
 
 	VCPU_EVENT(vcpu, 4, "deliver: sclp parameter 0x%x",
@@ -924,16 +1025,31 @@
 	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE,
 					 ext.ext_params, 0);
 
-	rc  = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE);
-	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR);
-	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
-			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
-			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-	rc |= put_guest_lc(vcpu, ext.ext_params,
-			   (u32 *)__LC_EXT_PARAMS);
+	return write_sclp(vcpu, ext.ext_params);
+}
 
-	return rc ? -EFAULT : 0;
+static int __must_check __deliver_service_ev(struct kvm_vcpu *vcpu)
+{
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_ext_info ext;
+
+	spin_lock(&fi->lock);
+	if (!(test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs))) {
+		spin_unlock(&fi->lock);
+		return 0;
+	}
+	ext = fi->srv_signal;
+	/* only clear the event bit */
+	fi->srv_signal.ext_params &= ~SCCB_EVENT_PENDING;
+	clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs);
+	spin_unlock(&fi->lock);
+
+	VCPU_EVENT(vcpu, 4, "%s", "deliver: sclp parameter event");
+	vcpu->stat.deliver_service_signal++;
+	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE,
+					 ext.ext_params, 0);
+
+	return write_sclp(vcpu, SCCB_EVENT_PENDING);
 }
 
 static int __must_check __deliver_pfault_done(struct kvm_vcpu *vcpu)
@@ -1028,6 +1144,15 @@
 {
 	int rc;
 
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->iictl = IICTL_CODE_IO;
+		vcpu->arch.sie_block->subchannel_id = io->subchannel_id;
+		vcpu->arch.sie_block->subchannel_nr = io->subchannel_nr;
+		vcpu->arch.sie_block->io_int_parm = io->io_int_parm;
+		vcpu->arch.sie_block->io_int_word = io->io_int_word;
+		return 0;
+	}
+
 	rc  = put_guest_lc(vcpu, io->subchannel_id, (u16 *)__LC_SUBCHANNEL_ID);
 	rc |= put_guest_lc(vcpu, io->subchannel_nr, (u16 *)__LC_SUBCHANNEL_NR);
 	rc |= put_guest_lc(vcpu, io->io_int_parm, (u32 *)__LC_IO_INT_PARM);
@@ -1329,6 +1454,9 @@
 		case IRQ_PEND_EXT_SERVICE:
 			rc = __deliver_service(vcpu);
 			break;
+		case IRQ_PEND_EXT_SERVICE_EV:
+			rc = __deliver_service_ev(vcpu);
+			break;
 		case IRQ_PEND_PFAULT_DONE:
 			rc = __deliver_pfault_done(vcpu);
 			break;
@@ -1421,7 +1549,7 @@
 	if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL)
 		return -EINVAL;
 
-	if (sclp.has_sigpif)
+	if (sclp.has_sigpif && !kvm_s390_pv_cpu_get_handle(vcpu))
 		return sca_inject_ext_call(vcpu, src_id);
 
 	if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
@@ -1682,9 +1810,6 @@
 	return inti;
 }
 
-#define SCCB_MASK 0xFFFFFFF8
-#define SCCB_EVENT_PENDING 0x3
-
 static int __inject_service(struct kvm *kvm,
 			     struct kvm_s390_interrupt_info *inti)
 {
@@ -1693,6 +1818,11 @@
 	kvm->stat.inject_service_signal++;
 	spin_lock(&fi->lock);
 	fi->srv_signal.ext_params |= inti->ext.ext_params & SCCB_EVENT_PENDING;
+
+	/* We always allow events, track them separately from the sccb ints */
+	if (fi->srv_signal.ext_params & SCCB_EVENT_PENDING)
+		set_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs);
+
 	/*
 	 * Early versions of the QEMU s390 bios will inject several
 	 * service interrupts after another without handling a
@@ -1774,7 +1904,14 @@
 	kvm->stat.inject_io++;
 	isc = int_word_to_isc(inti->io.io_int_word);
 
-	if (gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) {
+	/*
+	 * Do not make use of gisa in protected mode. We do not use the lock
+	 * checking variant as this is just a performance optimization and we
+	 * do not hold the lock here. This is ok as the code will pick
+	 * interrupts from both "lists" for delivery.
+	 */
+	if (!kvm_s390_pv_get_handle(kvm) &&
+	    gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) {
 		VM_EVENT(kvm, 4, "%s isc %1u", "inject: I/O (AI/gisa)", isc);
 		gisa_set_ipm_gisc(gi->origin, isc);
 		kfree(inti);
@@ -1835,7 +1972,8 @@
 		break;
 	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
 		if (!(type & KVM_S390_INT_IO_AI_MASK &&
-		      kvm->arch.gisa_int.origin))
+		      kvm->arch.gisa_int.origin) ||
+		      kvm_s390_pv_cpu_get_handle(dst_vcpu))
 			kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
 		break;
 	default:
@@ -1982,6 +2120,13 @@
 	return test_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
 }
 
+int kvm_s390_is_restart_irq_pending(struct kvm_vcpu *vcpu)
+{
+	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+	return test_bit(IRQ_PEND_RESTART, &li->pending_irqs);
+}
+
 void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -2081,6 +2226,10 @@
 	struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
 	int i;
 
+	mutex_lock(&kvm->lock);
+	if (!kvm_s390_pv_is_protected(kvm))
+		fi->masked_irqs = 0;
+	mutex_unlock(&kvm->lock);
 	spin_lock(&fi->lock);
 	fi->pending_irqs = 0;
 	memset(&fi->srv_signal, 0, sizeof(fi->srv_signal));
@@ -2147,7 +2296,8 @@
 			n++;
 		}
 	}
-	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs)) {
+	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs) ||
+	    test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs)) {
 		if (n == max_irqs) {
 			/* signal userspace to try again */
 			ret = -ENOMEM;
@@ -2191,7 +2341,7 @@
 		return -EINVAL;
 
 	if (!test_kvm_facility(kvm, 72))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	mutex_lock(&fi->ais_lock);
 	ais.simm = fi->simm;
@@ -2328,9 +2478,6 @@
 	if (!adapter)
 		return -ENOMEM;
 
-	INIT_LIST_HEAD(&adapter->maps);
-	init_rwsem(&adapter->maps_lock);
-	atomic_set(&adapter->nr_maps, 0);
 	adapter->id = adapter_info.id;
 	adapter->isc = adapter_info.isc;
 	adapter->maskable = adapter_info.maskable;
@@ -2355,87 +2502,12 @@
 	return ret;
 }
 
-static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
-{
-	struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
-	struct s390_map_info *map;
-	int ret;
-
-	if (!adapter || !addr)
-		return -EINVAL;
-
-	map = kzalloc(sizeof(*map), GFP_KERNEL);
-	if (!map) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	INIT_LIST_HEAD(&map->list);
-	map->guest_addr = addr;
-	map->addr = gmap_translate(kvm->arch.gmap, addr);
-	if (map->addr == -EFAULT) {
-		ret = -EFAULT;
-		goto out;
-	}
-	ret = get_user_pages_fast(map->addr, 1, FOLL_WRITE, &map->page);
-	if (ret < 0)
-		goto out;
-	BUG_ON(ret != 1);
-	down_write(&adapter->maps_lock);
-	if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) {
-		list_add_tail(&map->list, &adapter->maps);
-		ret = 0;
-	} else {
-		put_page(map->page);
-		ret = -EINVAL;
-	}
-	up_write(&adapter->maps_lock);
-out:
-	if (ret)
-		kfree(map);
-	return ret;
-}
-
-static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
-{
-	struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
-	struct s390_map_info *map, *tmp;
-	int found = 0;
-
-	if (!adapter || !addr)
-		return -EINVAL;
-
-	down_write(&adapter->maps_lock);
-	list_for_each_entry_safe(map, tmp, &adapter->maps, list) {
-		if (map->guest_addr == addr) {
-			found = 1;
-			atomic_dec(&adapter->nr_maps);
-			list_del(&map->list);
-			put_page(map->page);
-			kfree(map);
-			break;
-		}
-	}
-	up_write(&adapter->maps_lock);
-
-	return found ? 0 : -EINVAL;
-}
-
 void kvm_s390_destroy_adapters(struct kvm *kvm)
 {
 	int i;
-	struct s390_map_info *map, *tmp;
 
-	for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) {
-		if (!kvm->arch.adapters[i])
-			continue;
-		list_for_each_entry_safe(map, tmp,
-					 &kvm->arch.adapters[i]->maps, list) {
-			list_del(&map->list);
-			put_page(map->page);
-			kfree(map);
-		}
+	for (i = 0; i < MAX_S390_IO_ADAPTERS; i++)
 		kfree(kvm->arch.adapters[i]);
-	}
 }
 
 static int modify_io_adapter(struct kvm_device *dev,
@@ -2457,11 +2529,14 @@
 		if (ret > 0)
 			ret = 0;
 		break;
+	/*
+	 * The following operations are no longer needed and therefore no-ops.
+	 * The gpa to hva translation is done when an IRQ route is set up. The
+	 * set_irq code uses get_user_pages_remote() to do the actual write.
+	 */
 	case KVM_S390_IO_ADAPTER_MAP:
-		ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr);
-		break;
 	case KVM_S390_IO_ADAPTER_UNMAP:
-		ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr);
+		ret = 0;
 		break;
 	default:
 		ret = -EINVAL;
@@ -2500,7 +2575,7 @@
 	int ret = 0;
 
 	if (!test_kvm_facility(kvm, 72))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
 		return -EFAULT;
@@ -2580,7 +2655,7 @@
 	struct kvm_s390_ais_all ais;
 
 	if (!test_kvm_facility(kvm, 72))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais)))
 		return -EFAULT;
@@ -2700,19 +2775,15 @@
 	return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
 }
 
-static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
-					  u64 addr)
+static struct page *get_map_page(struct kvm *kvm, u64 uaddr)
 {
-	struct s390_map_info *map;
+	struct page *page = NULL;
 
-	if (!adapter)
-		return NULL;
-
-	list_for_each_entry(map, &adapter->maps, list) {
-		if (map->guest_addr == addr)
-			return map;
-	}
-	return NULL;
+	down_read(&kvm->mm->mmap_sem);
+	get_user_pages_remote(NULL, kvm->mm, uaddr, 1, FOLL_WRITE,
+			      &page, NULL, NULL);
+	up_read(&kvm->mm->mmap_sem);
+	return page;
 }
 
 static int adapter_indicators_set(struct kvm *kvm,
@@ -2721,30 +2792,35 @@
 {
 	unsigned long bit;
 	int summary_set, idx;
-	struct s390_map_info *info;
+	struct page *ind_page, *summary_page;
 	void *map;
 
-	info = get_map_info(adapter, adapter_int->ind_addr);
-	if (!info)
+	ind_page = get_map_page(kvm, adapter_int->ind_addr);
+	if (!ind_page)
 		return -1;
-	map = page_address(info->page);
-	bit = get_ind_bit(info->addr, adapter_int->ind_offset, adapter->swap);
-	set_bit(bit, map);
-	idx = srcu_read_lock(&kvm->srcu);
-	mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
-	set_page_dirty_lock(info->page);
-	info = get_map_info(adapter, adapter_int->summary_addr);
-	if (!info) {
-		srcu_read_unlock(&kvm->srcu, idx);
+	summary_page = get_map_page(kvm, adapter_int->summary_addr);
+	if (!summary_page) {
+		put_page(ind_page);
 		return -1;
 	}
-	map = page_address(info->page);
-	bit = get_ind_bit(info->addr, adapter_int->summary_offset,
-			  adapter->swap);
+
+	idx = srcu_read_lock(&kvm->srcu);
+	map = page_address(ind_page);
+	bit = get_ind_bit(adapter_int->ind_addr,
+			  adapter_int->ind_offset, adapter->swap);
+	set_bit(bit, map);
+	mark_page_dirty(kvm, adapter_int->ind_addr >> PAGE_SHIFT);
+	set_page_dirty_lock(ind_page);
+	map = page_address(summary_page);
+	bit = get_ind_bit(adapter_int->summary_addr,
+			  adapter_int->summary_offset, adapter->swap);
 	summary_set = test_and_set_bit(bit, map);
-	mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
-	set_page_dirty_lock(info->page);
+	mark_page_dirty(kvm, adapter_int->summary_addr >> PAGE_SHIFT);
+	set_page_dirty_lock(summary_page);
 	srcu_read_unlock(&kvm->srcu, idx);
+
+	put_page(ind_page);
+	put_page(summary_page);
 	return summary_set ? 0 : 1;
 }
 
@@ -2766,9 +2842,7 @@
 	adapter = get_io_adapter(kvm, e->adapter.adapter_id);
 	if (!adapter)
 		return -1;
-	down_read(&adapter->maps_lock);
 	ret = adapter_indicators_set(kvm, adapter, &e->adapter);
-	up_read(&adapter->maps_lock);
 	if ((ret > 0) && !adapter->masked) {
 		ret = kvm_s390_inject_airq(kvm, adapter);
 		if (ret == 0)
@@ -2819,23 +2893,27 @@
 			  struct kvm_kernel_irq_routing_entry *e,
 			  const struct kvm_irq_routing_entry *ue)
 {
-	int ret;
+	u64 uaddr;
 
 	switch (ue->type) {
+	/* we store the userspace addresses instead of the guest addresses */
 	case KVM_IRQ_ROUTING_S390_ADAPTER:
 		e->set = set_adapter_int;
-		e->adapter.summary_addr = ue->u.adapter.summary_addr;
-		e->adapter.ind_addr = ue->u.adapter.ind_addr;
+		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.summary_addr);
+		if (uaddr == -EFAULT)
+			return -EFAULT;
+		e->adapter.summary_addr = uaddr;
+		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.ind_addr);
+		if (uaddr == -EFAULT)
+			return -EFAULT;
+		e->adapter.ind_addr = uaddr;
 		e->adapter.summary_offset = ue->u.adapter.summary_offset;
 		e->adapter.ind_offset = ue->u.adapter.ind_offset;
 		e->adapter.adapter_id = ue->u.adapter.adapter_id;
-		ret = 0;
-		break;
+		return 0;
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
 	}
-
-	return ret;
 }
 
 int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
@@ -2984,18 +3062,19 @@
 
 static void __airqs_kick_single_vcpu(struct kvm *kvm, u8 deliverable_mask)
 {
-	int vcpu_id, online_vcpus = atomic_read(&kvm->online_vcpus);
+	int vcpu_idx, online_vcpus = atomic_read(&kvm->online_vcpus);
 	struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int;
 	struct kvm_vcpu *vcpu;
+	u8 vcpu_isc_mask;
 
-	for_each_set_bit(vcpu_id, kvm->arch.idle_mask, online_vcpus) {
-		vcpu = kvm_get_vcpu(kvm, vcpu_id);
+	for_each_set_bit(vcpu_idx, kvm->arch.idle_mask, online_vcpus) {
+		vcpu = kvm_get_vcpu(kvm, vcpu_idx);
 		if (psw_ioint_disabled(vcpu))
 			continue;
-		deliverable_mask &= (u8)(vcpu->arch.sie_block->gcr[6] >> 24);
-		if (deliverable_mask) {
+		vcpu_isc_mask = (u8)(vcpu->arch.sie_block->gcr[6] >> 24);
+		if (deliverable_mask & vcpu_isc_mask) {
 			/* lately kicked but not yet running */
-			if (test_and_set_bit(vcpu_id, gi->kicked_mask))
+			if (test_and_set_bit(vcpu_idx, gi->kicked_mask))
 				return;
 			kvm_s390_vcpu_wakeup(vcpu);
 			return;
--- linux-ein-5.4.0.orig/arch/s390/kvm/kvm-s390.c
+++ linux-ein-5.4.0/arch/s390/kvm/kvm-s390.c
@@ -2,7 +2,7 @@
 /*
  * hosting IBM Z kernel virtual machines (s390x)
  *
- * Copyright IBM Corp. 2008, 2018
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
@@ -44,6 +44,7 @@
 #include <asm/cpacf.h>
 #include <asm/timex.h>
 #include <asm/ap.h>
+#include <asm/uv.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 
@@ -219,6 +220,7 @@
 static struct gmap_notifier gmap_notifier;
 static struct gmap_notifier vsie_gmap_notifier;
 debug_info_t *kvm_s390_dbf;
+debug_info_t *kvm_s390_dbf_uv;
 
 /* Section: not file related */
 int kvm_arch_hardware_enable(void)
@@ -232,8 +234,10 @@
 	return 0;
 }
 
+/* forward declarations */
 static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
 			      unsigned long end);
+static int sca_switch_to_extended(struct kvm *kvm);
 
 static void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta)
 {
@@ -318,31 +322,31 @@
 
 static inline int plo_test_bit(unsigned char nr)
 {
-	register unsigned long r0 asm("0") = (unsigned long) nr | 0x100;
+	unsigned long function = (unsigned long)nr | 0x100;
 	int cc;
 
 	asm volatile(
+		"	lgr	0,%[function]\n"
 		/* Parameter registers are ignored for "test bit" */
 		"	plo	0,0,0,0(0)\n"
 		"	ipm	%0\n"
 		"	srl	%0,28\n"
 		: "=d" (cc)
-		: "d" (r0)
-		: "cc");
+		: [function] "d" (function)
+		: "cc", "0");
 	return cc == 0;
 }
 
 static __always_inline void __insn32_query(unsigned int opcode, u8 *query)
 {
-	register unsigned long r0 asm("0") = 0;	/* query function */
-	register unsigned long r1 asm("1") = (unsigned long) query;
-
 	asm volatile(
-		/* Parameter regs are ignored */
+		"	lghi	0,0\n"
+		"	lgr	1,%[query]\n"
+		/* Parameter registers are ignored */
 		"	.insn	rrf,%[opc] << 16,2,4,6,0\n"
 		:
-		: "d" (r0), "a" (r1), [opc] "i" (opcode)
-		: "cc", "memory");
+		: [query] "d" ((unsigned long)query), [opc] "i" (opcode)
+		: "cc", "memory", "0", "1");
 }
 
 #define INSN_SORTL 0xb938
@@ -453,16 +457,19 @@
 
 int kvm_arch_init(void *opaque)
 {
-	int rc;
+	int rc = -ENOMEM;
 
 	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)) {
-		rc = -ENOMEM;
-		goto out_debug_unreg;
-	}
+	kvm_s390_dbf_uv = debug_register("kvm-uv", 32, 1, 7 * sizeof(long));
+	if (!kvm_s390_dbf_uv)
+		goto out;
+
+	if (debug_register_view(kvm_s390_dbf, &debug_sprintf_view) ||
+	    debug_register_view(kvm_s390_dbf_uv, &debug_sprintf_view))
+		goto out;
 
 	kvm_s390_cpu_feat_init();
 
@@ -470,19 +477,17 @@
 	rc = kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
 	if (rc) {
 		pr_err("A FLIC registration call failed with rc=%d\n", rc);
-		goto out_debug_unreg;
+		goto out;
 	}
 
 	rc = kvm_s390_gib_init(GAL_ISC);
 	if (rc)
-		goto out_gib_destroy;
+		goto out;
 
 	return 0;
 
-out_gib_destroy:
-	kvm_s390_gib_destroy();
-out_debug_unreg:
-	debug_unregister(kvm_s390_dbf);
+out:
+	kvm_arch_exit();
 	return rc;
 }
 
@@ -490,6 +495,7 @@
 {
 	kvm_s390_gib_destroy();
 	debug_unregister(kvm_s390_dbf);
+	debug_unregister(kvm_s390_dbf_uv);
 }
 
 /* Section: device related */
@@ -532,6 +538,9 @@
 	case KVM_CAP_S390_CMMA_MIGRATION:
 	case KVM_CAP_S390_AIS:
 	case KVM_CAP_S390_AIS_MIGRATION:
+	case KVM_CAP_S390_VCPU_RESETS:
+	case KVM_CAP_S390_DIAG318:
+	case KVM_CAP_S390_MEM_OP_EXTENSION:
 		r = 1;
 		break;
 	case KVM_CAP_S390_HPAGE_1M:
@@ -566,6 +575,9 @@
 	case KVM_CAP_S390_BPB:
 		r = test_facility(82);
 		break;
+	case KVM_CAP_S390_PROTECTED:
+		r = is_prot_virt_host();
+		break;
 	default:
 		r = 0;
 	}
@@ -1084,6 +1096,8 @@
 	return 0;
 }
 
+static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
+
 static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
 {
 	struct kvm_s390_vm_tod_clock gtod;
@@ -1093,7 +1107,7 @@
 
 	if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
 		return -EINVAL;
-	kvm_s390_set_tod_clock(kvm, &gtod);
+	__kvm_s390_set_tod_clock(kvm, &gtod);
 
 	VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
 		gtod.epoch_idx, gtod.tod);
@@ -1124,7 +1138,7 @@
 			   sizeof(gtod.tod)))
 		return -EFAULT;
 
-	kvm_s390_set_tod_clock(kvm, &gtod);
+	__kvm_s390_set_tod_clock(kvm, &gtod);
 	VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
 	return 0;
 }
@@ -1136,6 +1150,16 @@
 	if (attr->flags)
 		return -EINVAL;
 
+	mutex_lock(&kvm->lock);
+	/*
+	 * For protected guests, the TOD is managed by the ultravisor, so trying
+	 * to change it will never bring the expected results.
+	 */
+	if (kvm_s390_pv_is_protected(kvm)) {
+		ret = -EOPNOTSUPP;
+		goto out_unlock;
+	}
+
 	switch (attr->attr) {
 	case KVM_S390_VM_TOD_EXT:
 		ret = kvm_s390_set_tod_ext(kvm, attr);
@@ -1150,6 +1174,9 @@
 		ret = -ENXIO;
 		break;
 	}
+
+out_unlock:
+	mutex_unlock(&kvm->lock);
 	return ret;
 }
 
@@ -1932,6 +1959,9 @@
 			start = slot + 1;
 	}
 
+	if (start >= slots->used_slots)
+		return slots->used_slots - 1;
+
 	if (gfn >= memslots[start].base_gfn &&
 	    gfn < memslots[start].base_gfn + memslots[start].npages) {
 		atomic_set(&slots->lru_slot, start);
@@ -1979,6 +2009,10 @@
 		ms = slots->memslots + slotidx;
 		ofs = 0;
 	}
+
+	if (cur_gfn < ms->base_gfn)
+		ofs = 0;
+
 	ofs = find_next_bit(kvm_second_dirty_bitmap(ms), ms->npages, ofs);
 	while ((slotidx > 0) && (ofs >= ms->npages)) {
 		slotidx--;
@@ -2160,6 +2194,271 @@
 	return r;
 }
 
+static int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp)
+{
+	struct kvm_vcpu *vcpu;
+	u16 rc, rrc;
+	int ret = 0;
+	int i;
+
+	/*
+	 * We ignore failures and try to destroy as many CPUs as possible.
+	 * At the same time we must not free the assigned resources when
+	 * this fails, as the ultravisor has still access to that memory.
+	 * So kvm_s390_pv_destroy_cpu can leave a "wanted" memory leak
+	 * behind.
+	 * We want to return the first failure rc and rrc, though.
+	 */
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		mutex_lock(&vcpu->mutex);
+		if (kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc) && !ret) {
+			*rcp = rc;
+			*rrcp = rrc;
+			ret = -EIO;
+		}
+		mutex_unlock(&vcpu->mutex);
+	}
+	return ret;
+}
+
+static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc)
+{
+	int i, r = 0;
+	u16 dummy;
+
+	struct kvm_vcpu *vcpu;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		mutex_lock(&vcpu->mutex);
+		r = kvm_s390_pv_create_cpu(vcpu, rc, rrc);
+		mutex_unlock(&vcpu->mutex);
+		if (r)
+			break;
+	}
+	if (r)
+		kvm_s390_cpus_from_pv(kvm, &dummy, &dummy);
+	return r;
+}
+
+static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
+{
+	int r = 0;
+	u16 dummy;
+	void __user *argp = (void __user *)cmd->data;
+
+	switch (cmd->cmd) {
+	case KVM_PV_ENABLE: {
+		r = -EINVAL;
+		if (kvm_s390_pv_is_protected(kvm))
+			break;
+
+		/*
+		 *  FMT 4 SIE needs esca. As we never switch back to bsca from
+		 *  esca, we need no cleanup in the error cases below
+		 */
+		r = sca_switch_to_extended(kvm);
+		if (r)
+			break;
+
+		down_write(&current->mm->mmap_sem);
+		r = gmap_mark_unmergeable();
+		up_write(&current->mm->mmap_sem);
+		if (r)
+			break;
+
+		r = kvm_s390_pv_init_vm(kvm, &cmd->rc, &cmd->rrc);
+		if (r)
+			break;
+
+		r = kvm_s390_cpus_to_pv(kvm, &cmd->rc, &cmd->rrc);
+		if (r)
+			kvm_s390_pv_deinit_vm(kvm, &dummy, &dummy);
+
+		/* we need to block service interrupts from now on */
+		set_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs);
+		break;
+	}
+	case KVM_PV_DISABLE: {
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = kvm_s390_cpus_from_pv(kvm, &cmd->rc, &cmd->rrc);
+		/*
+		 * If a CPU could not be destroyed, destroy VM will also fail.
+		 * There is no point in trying to destroy it. Instead return
+		 * the rc and rrc from the first CPU that failed destroying.
+		 */
+		if (r)
+			break;
+		r = kvm_s390_pv_deinit_vm(kvm, &cmd->rc, &cmd->rrc);
+
+		/* no need to block service interrupts any more */
+		clear_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs);
+		break;
+	}
+	case KVM_PV_SET_SEC_PARMS: {
+		struct kvm_s390_pv_sec_parm parms = {};
+		void *hdr;
+
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = -EFAULT;
+		if (copy_from_user(&parms, argp, sizeof(parms)))
+			break;
+
+		/* Currently restricted to 8KB */
+		r = -EINVAL;
+		if (parms.length > PAGE_SIZE * 2)
+			break;
+
+		r = -ENOMEM;
+		hdr = vmalloc(parms.length);
+		if (!hdr)
+			break;
+
+		r = -EFAULT;
+		if (!copy_from_user(hdr, (void __user *)parms.origin,
+				    parms.length))
+			r = kvm_s390_pv_set_sec_parms(kvm, hdr, parms.length,
+						      &cmd->rc, &cmd->rrc);
+
+		vfree(hdr);
+		break;
+	}
+	case KVM_PV_UNPACK: {
+		struct kvm_s390_pv_unp unp = {};
+
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = -EFAULT;
+		if (copy_from_user(&unp, argp, sizeof(unp)))
+			break;
+
+		r = kvm_s390_pv_unpack(kvm, unp.addr, unp.size, unp.tweak,
+				       &cmd->rc, &cmd->rrc);
+		break;
+	}
+	case KVM_PV_VERIFY: {
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
+				  UVC_CMD_VERIFY_IMG, &cmd->rc, &cmd->rrc);
+		KVM_UV_EVENT(kvm, 3, "PROTVIRT VERIFY: rc %x rrc %x", cmd->rc,
+			     cmd->rrc);
+		break;
+	}
+	case KVM_PV_PREP_RESET: {
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
+				  UVC_CMD_PREPARE_RESET, &cmd->rc, &cmd->rrc);
+		KVM_UV_EVENT(kvm, 3, "PROTVIRT PREP RESET: rc %x rrc %x",
+			     cmd->rc, cmd->rrc);
+		break;
+	}
+	case KVM_PV_UNSHARE_ALL: {
+		r = -EINVAL;
+		if (!kvm_s390_pv_is_protected(kvm))
+			break;
+
+		r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
+				  UVC_CMD_SET_UNSHARE_ALL, &cmd->rc, &cmd->rrc);
+		KVM_UV_EVENT(kvm, 3, "PROTVIRT UNSHARE: rc %x rrc %x",
+			     cmd->rc, cmd->rrc);
+		break;
+	}
+	default:
+		r = -ENOTTY;
+	}
+	return r;
+}
+
+static bool access_key_invalid(u8 access_key)
+{
+	return access_key > 0xf;
+}
+
+static int kvm_s390_vm_mem_op(struct kvm *kvm, struct kvm_s390_mem_op *mop)
+{
+	void __user *uaddr = (void __user *)mop->buf;
+	u64 supported_flags;
+	void *tmpbuf = NULL;
+	int r, srcu_idx;
+
+	supported_flags = KVM_S390_MEMOP_F_SKEY_PROTECTION
+			  | KVM_S390_MEMOP_F_CHECK_ONLY;
+	if (mop->flags & ~supported_flags || !mop->size)
+		return -EINVAL;
+	if (mop->size > MEM_OP_MAX_SIZE)
+		return -E2BIG;
+	if (kvm_s390_pv_is_protected(kvm))
+		return -EINVAL;
+	if (mop->flags & KVM_S390_MEMOP_F_SKEY_PROTECTION) {
+		if (access_key_invalid(mop->key))
+			return -EINVAL;
+	} else {
+		mop->key = 0;
+	}
+	if (!(mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)) {
+		tmpbuf = vmalloc(mop->size);
+		if (!tmpbuf)
+			return -ENOMEM;
+	}
+
+	srcu_idx = srcu_read_lock(&kvm->srcu);
+
+	if (kvm_is_error_gpa(kvm, mop->gaddr)) {
+		r = PGM_ADDRESSING;
+		goto out_unlock;
+	}
+
+	switch (mop->op) {
+	case KVM_S390_MEMOP_ABSOLUTE_READ: {
+		if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
+			r = check_gpa_range(kvm, mop->gaddr, mop->size, GACC_FETCH, mop->key);
+		} else {
+			r = access_guest_abs_with_key(kvm, mop->gaddr, tmpbuf,
+						      mop->size, GACC_FETCH, mop->key);
+			if (r == 0) {
+				if (copy_to_user(uaddr, tmpbuf, mop->size))
+					r = -EFAULT;
+			}
+		}
+		break;
+	}
+	case KVM_S390_MEMOP_ABSOLUTE_WRITE: {
+		if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
+			r = check_gpa_range(kvm, mop->gaddr, mop->size, GACC_STORE, mop->key);
+		} else {
+			if (copy_from_user(tmpbuf, uaddr, mop->size)) {
+				r = -EFAULT;
+				break;
+			}
+			r = access_guest_abs_with_key(kvm, mop->gaddr, tmpbuf,
+						      mop->size, GACC_STORE, mop->key);
+		}
+		break;
+	}
+	default:
+		r = -EINVAL;
+	}
+
+out_unlock:
+	srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+	vfree(tmpbuf);
+	return r;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
 		       unsigned int ioctl, unsigned long arg)
 {
@@ -2257,6 +2556,42 @@
 		mutex_unlock(&kvm->slots_lock);
 		break;
 	}
+	case KVM_S390_PV_COMMAND: {
+		struct kvm_pv_cmd args;
+
+		/* protvirt means user cpu state */
+		kvm_s390_set_user_cpu_state_ctrl(kvm);
+		r = 0;
+		if (!is_prot_virt_host()) {
+			r = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&args, argp, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+		if (args.flags) {
+			r = -EINVAL;
+			break;
+		}
+		mutex_lock(&kvm->lock);
+		r = kvm_s390_handle_pv(kvm, &args);
+		mutex_unlock(&kvm->lock);
+		if (copy_to_user(argp, &args, sizeof(args))) {
+			r = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case KVM_S390_MEM_OP: {
+		struct kvm_s390_mem_op mem_op;
+
+		if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0)
+			r = kvm_s390_vm_mem_op(kvm, &mem_op);
+		else
+			r = -EFAULT;
+		break;
+	}
 	default:
 		r = -ENOTTY;
 	}
@@ -2520,6 +2855,8 @@
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
+	u16 rc, rrc;
+
 	VCPU_EVENT(vcpu, 3, "%s", "free cpu");
 	trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
 	kvm_s390_clear_local_irqs(vcpu);
@@ -2532,6 +2869,9 @@
 
 	if (vcpu->kvm->arch.use_cmma)
 		kvm_s390_vcpu_unsetup_cmma(vcpu);
+	/* We can not hold the vcpu mutex here, we are already dying */
+	if (kvm_s390_pv_cpu_get_handle(vcpu))
+		kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc);
 	free_page((unsigned long)(vcpu->arch.sie_block));
 
 	kvm_vcpu_uninit(vcpu);
@@ -2556,10 +2896,20 @@
 
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
+	u16 rc, rrc;
+
 	kvm_free_vcpus(kvm);
 	sca_dispose(kvm);
-	debug_unregister(kvm->arch.dbf);
 	kvm_s390_gisa_destroy(kvm);
+	/*
+	 * We are already at the end of life and kvm->lock is not taken.
+	 * This is ok as the file descriptor is closed by now and nobody
+	 * can mess with the pv state. To avoid lockdep_assert_held from
+	 * complaining we do not use kvm_s390_pv_is_protected.
+	 */
+	if (kvm_s390_pv_get_handle(kvm))
+		kvm_s390_pv_deinit_vm(kvm, &rc, &rrc);
+	debug_unregister(kvm->arch.dbf);
 	free_page((unsigned long)kvm->arch.sie_page2);
 	if (!kvm_is_ucontrol(kvm))
 		gmap_remove(kvm->arch.gmap);
@@ -2655,6 +3005,9 @@
 	unsigned int vcpu_idx;
 	u32 scaol, scaoh;
 
+	if (kvm->arch.use_esca)
+		return 0;
+
 	new_sca = alloc_pages_exact(sizeof(*new_sca), GFP_KERNEL|__GFP_ZERO);
 	if (!new_sca)
 		return -ENOMEM;
@@ -2715,7 +3068,8 @@
 				    KVM_SYNC_ACRS |
 				    KVM_SYNC_CRS |
 				    KVM_SYNC_ARCH0 |
-				    KVM_SYNC_PFAULT;
+				    KVM_SYNC_PFAULT |
+				    KVM_SYNC_DIAG318;
 	kvm_s390_set_prefix(vcpu, 0);
 	if (test_kvm_facility(vcpu->kvm, 64))
 		vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
@@ -2847,35 +3201,6 @@
 
 }
 
-static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
-{
-	/* this equals initial cpu reset in pop, but we don't switch to ESA */
-	vcpu->arch.sie_block->gpsw.mask = 0UL;
-	vcpu->arch.sie_block->gpsw.addr = 0UL;
-	kvm_s390_set_prefix(vcpu, 0);
-	kvm_s390_set_cpu_timer(vcpu, 0);
-	vcpu->arch.sie_block->ckc       = 0UL;
-	vcpu->arch.sie_block->todpr     = 0;
-	memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
-	vcpu->arch.sie_block->gcr[0]  = CR0_UNUSED_56 |
-					CR0_INTERRUPT_KEY_SUBMASK |
-					CR0_MEASUREMENT_ALERT_SUBMASK;
-	vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 |
-					CR14_UNUSED_33 |
-					CR14_EXTERNAL_DAMAGE_SUBMASK;
-	/* 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))
-		kvm_s390_vcpu_stop(vcpu);
-	kvm_s390_clear_local_irqs(vcpu);
-}
-
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 {
 	mutex_lock(&vcpu->kvm->lock);
@@ -2968,6 +3293,7 @@
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
 	int rc = 0;
+	u16 uvrc, uvrrc;
 
 	atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
 						    CPUSTAT_SM |
@@ -3035,6 +3361,14 @@
 
 	kvm_s390_vcpu_crypto_setup(vcpu);
 
+	mutex_lock(&vcpu->kvm->lock);
+	if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+		rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc);
+		if (rc)
+			kvm_s390_vcpu_unsetup_cmma(vcpu);
+	}
+	mutex_unlock(&vcpu->kvm->lock);
+
 	return rc;
 }
 
@@ -3091,6 +3425,7 @@
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
 {
+	clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.gisa_int.kicked_mask);
 	return kvm_s390_vcpu_has_irq(vcpu, 0);
 }
 
@@ -3290,10 +3625,60 @@
 	return r;
 }
 
-static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu)
 {
-	kvm_s390_vcpu_initial_reset(vcpu);
-	return 0;
+	vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI;
+	vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+	memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb));
+
+	kvm_clear_async_pf_completion_queue(vcpu);
+	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
+		kvm_s390_vcpu_stop(vcpu);
+	kvm_s390_clear_local_irqs(vcpu);
+}
+
+static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+{
+	/* Initial reset is a superset of the normal reset */
+	kvm_arch_vcpu_ioctl_normal_reset(vcpu);
+
+	/* this equals initial cpu reset in pop, but we don't switch to ESA */
+	vcpu->arch.sie_block->gpsw.mask = 0;
+	vcpu->arch.sie_block->gpsw.addr = 0;
+	kvm_s390_set_prefix(vcpu, 0);
+	kvm_s390_set_cpu_timer(vcpu, 0);
+	vcpu->arch.sie_block->ckc = 0;
+	memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr));
+	vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK;
+	vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK;
+	vcpu->run->s.regs.fpc = 0;
+	/*
+	 * Do not reset these registers in the protected case, as some of
+	 * them are overlayed and they are not accessible in this case
+	 * anyway.
+	 */
+	if (!kvm_s390_pv_cpu_is_protected(vcpu)) {
+		vcpu->arch.sie_block->gbea = 1;
+		vcpu->arch.sie_block->pp = 0;
+		vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
+		vcpu->arch.sie_block->todpr = 0;
+	}
+}
+
+static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu)
+{
+	struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+
+	/* Clear reset is a superset of the initial reset */
+	kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+
+	memset(&regs->gprs, 0, sizeof(regs->gprs));
+	memset(&regs->vrs, 0, sizeof(regs->vrs));
+	memset(&regs->acrs, 0, sizeof(regs->acrs));
+	memset(&regs->gscb, 0, sizeof(regs->gscb));
+
+	regs->etoken = 0;
+	regs->etoken_extension = 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
@@ -3342,10 +3727,6 @@
 
 	vcpu_load(vcpu);
 
-	if (test_fp_ctl(fpu->fpc)) {
-		ret = -EINVAL;
-		goto out;
-	}
 	vcpu->run->s.regs.fpc = fpu->fpc;
 	if (MACHINE_HAS_VX)
 		convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs,
@@ -3353,7 +3734,6 @@
 	else
 		memcpy(vcpu->run->s.regs.fprs, &fpu->fprs, sizeof(fpu->fprs));
 
-out:
 	vcpu_put(vcpu);
 	return ret;
 }
@@ -3463,16 +3843,22 @@
 	vcpu_load(vcpu);
 
 	/* user space knows about this interface - let it control the state */
-	vcpu->kvm->arch.user_cpu_state_ctrl = 1;
+	kvm_s390_set_user_cpu_state_ctrl(vcpu->kvm);
 
 	switch (mp_state->mp_state) {
 	case KVM_MP_STATE_STOPPED:
-		kvm_s390_vcpu_stop(vcpu);
+		rc = kvm_s390_vcpu_stop(vcpu);
 		break;
 	case KVM_MP_STATE_OPERATING:
-		kvm_s390_vcpu_start(vcpu);
+		rc = kvm_s390_vcpu_start(vcpu);
 		break;
 	case KVM_MP_STATE_LOAD:
+		if (!kvm_s390_pv_cpu_is_protected(vcpu)) {
+			rc = -ENXIO;
+			break;
+		}
+		rc = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_OPR_LOAD);
+		break;
 	case KVM_MP_STATE_CHECK_STOP:
 		/* fall through - CHECK_STOP and LOAD are not supported yet */
 	default:
@@ -3568,14 +3954,12 @@
 	return 0;
 }
 
-void kvm_s390_set_tod_clock(struct kvm *kvm,
-			    const struct kvm_s390_vm_tod_clock *gtod)
+static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
 {
 	struct kvm_vcpu *vcpu;
 	struct kvm_s390_tod_clock_ext htod;
 	int i;
 
-	mutex_lock(&kvm->lock);
 	preempt_disable();
 
 	get_tod_clock_ext((char *)&htod);
@@ -3596,7 +3980,15 @@
 
 	kvm_s390_vcpu_unblock_all(kvm);
 	preempt_enable();
+}
+
+int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
+{
+	if (!mutex_trylock(&kvm->lock))
+		return 0;
+	__kvm_s390_set_tod_clock(kvm, gtod);
 	mutex_unlock(&kvm->lock);
+	return 1;
 }
 
 /**
@@ -3725,7 +4117,7 @@
 		kvm_s390_patch_guest_per_regs(vcpu);
 	}
 
-	clear_bit(vcpu->vcpu_id, vcpu->kvm->arch.gisa_int.kicked_mask);
+	clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.gisa_int.kicked_mask);
 
 	vcpu->arch.sie_block->icptcode = 0;
 	cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags);
@@ -3824,9 +4216,11 @@
 	return vcpu_post_run_fault_in_sie(vcpu);
 }
 
+#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK)
 static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
 	int rc, exit_reason;
+	struct sie_page *sie_page = (struct sie_page *)vcpu->arch.sie_block;
 
 	/*
 	 * We try to hold kvm->srcu during most of vcpu_run (except when run-
@@ -3848,8 +4242,28 @@
 		guest_enter_irqoff();
 		__disable_cpu_timer_accounting(vcpu);
 		local_irq_enable();
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			memcpy(sie_page->pv_grregs,
+			       vcpu->run->s.regs.gprs,
+			       sizeof(sie_page->pv_grregs));
+		}
 		exit_reason = sie64a(vcpu->arch.sie_block,
 				     vcpu->run->s.regs.gprs);
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			memcpy(vcpu->run->s.regs.gprs,
+			       sie_page->pv_grregs,
+			       sizeof(sie_page->pv_grregs));
+			/*
+			 * We're not allowed to inject interrupts on intercepts
+			 * that leave the guest state in an "in-between" state
+			 * where the next SIE entry will do a continuation.
+			 * Fence interrupts in our "internal" PSW.
+			 */
+			if (vcpu->arch.sie_block->icptcode == ICPT_PV_INSTR ||
+			    vcpu->arch.sie_block->icptcode == ICPT_PV_PREF) {
+				vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK;
+			}
+		}
 		local_irq_disable();
 		__enable_cpu_timer_accounting(vcpu);
 		guest_exit_irqoff();
@@ -3863,7 +4277,7 @@
 	return rc;
 }
 
-static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void sync_regs_fmt2(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	struct runtime_instr_cb *riccb;
 	struct gs_cb *gscb;
@@ -3872,16 +4286,7 @@
 	gscb = (struct gs_cb *) &kvm_run->s.regs.gscb;
 	vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
 	vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
-	if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX)
-		kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
-	if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) {
-		memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128);
-		/* some control register changes require a tlb flush */
-		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
-	}
 	if (kvm_run->kvm_dirty_regs & KVM_SYNC_ARCH0) {
-		kvm_s390_set_cpu_timer(vcpu, kvm_run->s.regs.cputm);
-		vcpu->arch.sie_block->ckc = kvm_run->s.regs.ckc;
 		vcpu->arch.sie_block->todpr = kvm_run->s.regs.todpr;
 		vcpu->arch.sie_block->pp = kvm_run->s.regs.pp;
 		vcpu->arch.sie_block->gbea = kvm_run->s.regs.gbea;
@@ -3893,6 +4298,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_DIAG318) {
+		vcpu->arch.diag318_info.val = kvm_run->s.regs.diag318;
+		vcpu->arch.sie_block->cpnc = vcpu->arch.diag318_info.cpnc;
+		VCPU_EVENT(vcpu, 3, "setting cpnc to %d", vcpu->arch.diag318_info.cpnc);
+	}
 	/*
 	 * If userspace sets the riccb (e.g. after migration) to a valid state,
 	 * we should enable RI here instead of doing the lazy enablement.
@@ -3922,6 +4332,36 @@
 		vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
 		vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0;
 	}
+	if (MACHINE_HAS_GS) {
+		preempt_disable();
+		__ctl_set_bit(2, 4);
+		if (current->thread.gs_cb) {
+			vcpu->arch.host_gscb = current->thread.gs_cb;
+			save_gs_cb(vcpu->arch.host_gscb);
+		}
+		if (vcpu->arch.gs_enabled) {
+			current->thread.gs_cb = (struct gs_cb *)
+						&vcpu->run->s.regs.gscb;
+			restore_gs_cb(current->thread.gs_cb);
+		}
+		preempt_enable();
+	}
+	/* SIE will load etoken directly from SDNX and therefore kvm_run */
+}
+
+static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX)
+		kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
+	if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) {
+		memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128);
+		/* some control register changes require a tlb flush */
+		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+	}
+	if (kvm_run->kvm_dirty_regs & KVM_SYNC_ARCH0) {
+		kvm_s390_set_cpu_timer(vcpu, kvm_run->s.regs.cputm);
+		vcpu->arch.sie_block->ckc = kvm_run->s.regs.ckc;
+	}
 	save_access_regs(vcpu->arch.host_acrs);
 	restore_access_regs(vcpu->run->s.regs.acrs);
 	/* save host (userspace) fprs/vrs */
@@ -3936,23 +4376,48 @@
 	if (test_fp_ctl(current->thread.fpu.fpc))
 		/* User space provided an invalid FPC, let's clear it */
 		current->thread.fpu.fpc = 0;
+
+	/* Sync fmt2 only data */
+	if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) {
+		sync_regs_fmt2(vcpu, kvm_run);
+	} else {
+		/*
+		 * In several places we have to modify our internal view to
+		 * not do things that are disallowed by the ultravisor. For
+		 * example we must not inject interrupts after specific exits
+		 * (e.g. 112 prefix page not secure). We do this by turning
+		 * off the machine check, external and I/O interrupt bits
+		 * of our PSW copy. To avoid getting validity intercepts, we
+		 * do only accept the condition code from userspace.
+		 */
+		vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_CC;
+		vcpu->arch.sie_block->gpsw.mask |= kvm_run->psw_mask &
+						   PSW_MASK_CC;
+	}
+
+	kvm_run->kvm_dirty_regs = 0;
+}
+
+static void store_regs_fmt2(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	kvm_run->s.regs.todpr = vcpu->arch.sie_block->todpr;
+	kvm_run->s.regs.pp = vcpu->arch.sie_block->pp;
+	kvm_run->s.regs.gbea = vcpu->arch.sie_block->gbea;
+	kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC;
+	kvm_run->s.regs.diag318 = vcpu->arch.diag318_info.val;
 	if (MACHINE_HAS_GS) {
 		preempt_disable();
 		__ctl_set_bit(2, 4);
-		if (current->thread.gs_cb) {
-			vcpu->arch.host_gscb = current->thread.gs_cb;
-			save_gs_cb(vcpu->arch.host_gscb);
-		}
-		if (vcpu->arch.gs_enabled) {
-			current->thread.gs_cb = (struct gs_cb *)
-						&vcpu->run->s.regs.gscb;
-			restore_gs_cb(current->thread.gs_cb);
-		}
+		if (vcpu->arch.gs_enabled)
+			save_gs_cb(current->thread.gs_cb);
+		current->thread.gs_cb = vcpu->arch.host_gscb;
+		restore_gs_cb(vcpu->arch.host_gscb);
+		if (!vcpu->arch.host_gscb)
+			__ctl_clear_bit(2, 4);
+		vcpu->arch.host_gscb = NULL;
 		preempt_enable();
 	}
-	/* SIE will load etoken directly from SDNX and therefore kvm_run */
-
-	kvm_run->kvm_dirty_regs = 0;
+	/* SIE will save etoken directly into SDNX and therefore kvm_run */
 }
 
 static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -3963,13 +4428,9 @@
 	memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128);
 	kvm_run->s.regs.cputm = kvm_s390_get_cpu_timer(vcpu);
 	kvm_run->s.regs.ckc = vcpu->arch.sie_block->ckc;
-	kvm_run->s.regs.todpr = vcpu->arch.sie_block->todpr;
-	kvm_run->s.regs.pp = vcpu->arch.sie_block->pp;
-	kvm_run->s.regs.gbea = vcpu->arch.sie_block->gbea;
 	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;
 	save_access_regs(vcpu->run->s.regs.acrs);
 	restore_access_regs(vcpu->arch.host_acrs);
 	/* Save guest register state */
@@ -3978,19 +4439,8 @@
 	/* Restore will be done lazily at return */
 	current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
 	current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
-	if (MACHINE_HAS_GS) {
-		__ctl_set_bit(2, 4);
-		if (vcpu->arch.gs_enabled)
-			save_gs_cb(current->thread.gs_cb);
-		preempt_disable();
-		current->thread.gs_cb = vcpu->arch.host_gscb;
-		restore_gs_cb(vcpu->arch.host_gscb);
-		preempt_enable();
-		if (!vcpu->arch.host_gscb)
-			__ctl_clear_bit(2, 4);
-		vcpu->arch.host_gscb = NULL;
-	}
-	/* SIE will save etoken directly into SDNX and therefore kvm_run */
+	if (likely(!kvm_s390_pv_cpu_is_protected(vcpu)))
+		store_regs_fmt2(vcpu, kvm_run);
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -4014,6 +4464,10 @@
 
 	kvm_sigset_activate(vcpu);
 
+	/*
+	 * no need to check the return value of vcpu_start as it can only have
+	 * an error for protvirt, but protvirt means user cpu state
+	 */
 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) {
 		kvm_s390_vcpu_start(vcpu);
 	} else if (is_vcpu_stopped(vcpu)) {
@@ -4151,18 +4605,27 @@
 	kvm_s390_sync_request(KVM_REQ_ENABLE_IBS, vcpu);
 }
 
-void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
+int kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
 {
-	int i, online_vcpus, started_vcpus = 0;
+	int i, online_vcpus, r = 0, started_vcpus = 0;
 
 	if (!is_vcpu_stopped(vcpu))
-		return;
+		return 0;
 
 	trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1);
 	/* Only one cpu at a time may enter/leave the STOPPED state. */
 	spin_lock(&vcpu->kvm->arch.start_stop_lock);
 	online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
 
+	/* Let's tell the UV that we want to change into the operating state */
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_OPR);
+		if (r) {
+			spin_unlock(&vcpu->kvm->arch.start_stop_lock);
+			return r;
+		}
+	}
+
 	for (i = 0; i < online_vcpus; i++) {
 		if (!is_vcpu_stopped(vcpu->kvm->vcpus[i]))
 			started_vcpus++;
@@ -4182,31 +4645,52 @@
 
 	kvm_s390_clear_cpuflags(vcpu, CPUSTAT_STOPPED);
 	/*
+	 * The real PSW might have changed due to a RESTART interpreted by the
+	 * ultravisor. We block all interrupts and let the next sie exit
+	 * refresh our view.
+	 */
+	if (kvm_s390_pv_cpu_is_protected(vcpu))
+		vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK;
+	/*
 	 * Another VCPU might have used IBS while we were offline.
 	 * Let's play safe and flush the VCPU at startup.
 	 */
 	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 	spin_unlock(&vcpu->kvm->arch.start_stop_lock);
-	return;
+	return 0;
 }
 
-void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
+int kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
 {
-	int i, online_vcpus, started_vcpus = 0;
+	int i, online_vcpus, r = 0, started_vcpus = 0;
 	struct kvm_vcpu *started_vcpu = NULL;
 
 	if (is_vcpu_stopped(vcpu))
-		return;
+		return 0;
 
 	trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0);
 	/* Only one cpu at a time may enter/leave the STOPPED state. */
 	spin_lock(&vcpu->kvm->arch.start_stop_lock);
 	online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
 
-	/* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */
-	kvm_s390_clear_stop_irq(vcpu);
+	/* Let's tell the UV that we want to change into the stopped state */
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_STP);
+		if (r) {
+			spin_unlock(&vcpu->kvm->arch.start_stop_lock);
+			return r;
+		}
+	}
 
+	/*
+	 * Set the VCPU to STOPPED and THEN clear the interrupt flag,
+	 * now that the SIGP STOP and SIGP STOP AND STORE STATUS orders
+	 * have been fully processed. This will ensure that the VCPU
+	 * is kept BUSY if another VCPU is inquiring with SIGP SENSE.
+	 */
 	kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOPPED);
+	kvm_s390_clear_stop_irq(vcpu);
+
 	__disable_ibs_on_vcpu(vcpu);
 
 	for (i = 0; i < online_vcpus; i++) {
@@ -4225,7 +4709,7 @@
 	}
 
 	spin_unlock(&vcpu->kvm->arch.start_stop_lock);
-	return;
+	return 0;
 }
 
 static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
@@ -4252,37 +4736,74 @@
 	return r;
 }
 
-static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu,
+static long kvm_s390_vcpu_sida_op(struct kvm_vcpu *vcpu,
 				  struct kvm_s390_mem_op *mop)
 {
 	void __user *uaddr = (void __user *)mop->buf;
+	int r = 0;
+
+	if (mop->flags || !mop->size)
+		return -EINVAL;
+	if (mop->size + mop->sida_offset < mop->size)
+		return -EINVAL;
+	if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block))
+		return -E2BIG;
+	if (!kvm_s390_pv_cpu_is_protected(vcpu))
+		return -EINVAL;
+
+	switch (mop->op) {
+	case KVM_S390_MEMOP_SIDA_READ:
+		if (copy_to_user(uaddr, (void *)(sida_origin(vcpu->arch.sie_block) +
+				 mop->sida_offset), mop->size))
+			r = -EFAULT;
+
+		break;
+	case KVM_S390_MEMOP_SIDA_WRITE:
+		if (copy_from_user((void *)(sida_origin(vcpu->arch.sie_block) +
+				   mop->sida_offset), uaddr, mop->size))
+			r = -EFAULT;
+		break;
+	}
+	return r;
+}
+
+static long kvm_s390_vcpu_mem_op(struct kvm_vcpu *vcpu,
+				 struct kvm_s390_mem_op *mop)
+{
+	void __user *uaddr = (void __user *)mop->buf;
 	void *tmpbuf = NULL;
-	int r, srcu_idx;
+	int r = 0;
 	const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION
-				    | KVM_S390_MEMOP_F_CHECK_ONLY;
+				    | KVM_S390_MEMOP_F_CHECK_ONLY
+				    | KVM_S390_MEMOP_F_SKEY_PROTECTION;
 
 	if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size)
 		return -EINVAL;
-
 	if (mop->size > MEM_OP_MAX_SIZE)
 		return -E2BIG;
-
+	if (kvm_s390_pv_cpu_is_protected(vcpu))
+		return -EINVAL;
+	if (mop->flags & KVM_S390_MEMOP_F_SKEY_PROTECTION) {
+		if (access_key_invalid(mop->key))
+			return -EINVAL;
+	} else {
+		mop->key = 0;
+	}
 	if (!(mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)) {
 		tmpbuf = vmalloc(mop->size);
 		if (!tmpbuf)
 			return -ENOMEM;
 	}
 
-	srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
-
 	switch (mop->op) {
 	case KVM_S390_MEMOP_LOGICAL_READ:
 		if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
-			r = check_gva_range(vcpu, mop->gaddr, mop->ar,
-					    mop->size, GACC_FETCH);
+			r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size,
+					    GACC_FETCH, mop->key);
 			break;
 		}
-		r = read_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size);
+		r = read_guest_with_key(vcpu, mop->gaddr, mop->ar, tmpbuf,
+					mop->size, mop->key);
 		if (r == 0) {
 			if (copy_to_user(uaddr, tmpbuf, mop->size))
 				r = -EFAULT;
@@ -4290,22 +4811,19 @@
 		break;
 	case KVM_S390_MEMOP_LOGICAL_WRITE:
 		if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
-			r = check_gva_range(vcpu, mop->gaddr, mop->ar,
-					    mop->size, GACC_STORE);
+			r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size,
+					    GACC_STORE, mop->key);
 			break;
 		}
 		if (copy_from_user(tmpbuf, uaddr, mop->size)) {
 			r = -EFAULT;
 			break;
 		}
-		r = write_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size);
+		r = write_guest_with_key(vcpu, mop->gaddr, mop->ar, tmpbuf,
+					 mop->size, mop->key);
 		break;
-	default:
-		r = -EINVAL;
 	}
 
-	srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
-
 	if (r > 0 && (mop->flags & KVM_S390_MEMOP_F_INJECT_EXCEPTION) != 0)
 		kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
 
@@ -4313,6 +4831,31 @@
 	return r;
 }
 
+static long kvm_s390_vcpu_memsida_op(struct kvm_vcpu *vcpu,
+				     struct kvm_s390_mem_op *mop)
+{
+	int r, srcu_idx;
+
+	srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+
+	switch (mop->op) {
+	case KVM_S390_MEMOP_LOGICAL_READ:
+	case KVM_S390_MEMOP_LOGICAL_WRITE:
+		r = kvm_s390_vcpu_mem_op(vcpu, mop);
+		break;
+	case KVM_S390_MEMOP_SIDA_READ:
+	case KVM_S390_MEMOP_SIDA_WRITE:
+		/* we are locked against sida going away by the vcpu->mutex */
+		r = kvm_s390_vcpu_sida_op(vcpu, mop);
+		break;
+	default:
+		r = -EINVAL;
+	}
+
+	srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
+	return r;
+}
+
 long kvm_arch_vcpu_async_ioctl(struct file *filp,
 			       unsigned int ioctl, unsigned long arg)
 {
@@ -4348,13 +4891,14 @@
 	void __user *argp = (void __user *)arg;
 	int idx;
 	long r;
+	u16 rc, rrc;
 
 	vcpu_load(vcpu);
 
 	switch (ioctl) {
 	case KVM_S390_STORE_STATUS:
 		idx = srcu_read_lock(&vcpu->kvm->srcu);
-		r = kvm_s390_vcpu_store_status(vcpu, arg);
+		r = kvm_s390_store_status_unloaded(vcpu, arg);
 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
 	case KVM_S390_SET_INITIAL_PSW: {
@@ -4366,12 +4910,43 @@
 		r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
 		break;
 	}
+	case KVM_S390_CLEAR_RESET:
+		r = 0;
+		kvm_arch_vcpu_ioctl_clear_reset(vcpu);
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
+					  UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc);
+			VCPU_EVENT(vcpu, 3, "PROTVIRT RESET CLEAR VCPU: rc %x rrc %x",
+				   rc, rrc);
+		}
+		break;
 	case KVM_S390_INITIAL_RESET:
-		r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+		r = 0;
+		kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
+					  UVC_CMD_CPU_RESET_INITIAL,
+					  &rc, &rrc);
+			VCPU_EVENT(vcpu, 3, "PROTVIRT RESET INITIAL VCPU: rc %x rrc %x",
+				   rc, rrc);
+		}
+		break;
+	case KVM_S390_NORMAL_RESET:
+		r = 0;
+		kvm_arch_vcpu_ioctl_normal_reset(vcpu);
+		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+			r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
+					  UVC_CMD_CPU_RESET, &rc, &rrc);
+			VCPU_EVENT(vcpu, 3, "PROTVIRT RESET NORMAL VCPU: rc %x rrc %x",
+				   rc, rrc);
+		}
 		break;
 	case KVM_SET_ONE_REG:
 	case KVM_GET_ONE_REG: {
 		struct kvm_one_reg reg;
+		r = -EINVAL;
+		if (kvm_s390_pv_cpu_is_protected(vcpu))
+			break;
 		r = -EFAULT;
 		if (copy_from_user(&reg, argp, sizeof(reg)))
 			break;
@@ -4434,7 +5009,7 @@
 		struct kvm_s390_mem_op mem_op;
 
 		if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0)
-			r = kvm_s390_guest_mem_op(vcpu, &mem_op);
+			r = kvm_s390_vcpu_memsida_op(vcpu, &mem_op);
 		else
 			r = -EFAULT;
 		break;
@@ -4520,6 +5095,26 @@
 	if (mem->guest_phys_addr + mem->memory_size > kvm->arch.mem_limit)
 		return -EINVAL;
 
+	/* When we are protected, we should not change the memory slots */
+	if (kvm_s390_pv_get_handle(kvm))
+		return -EINVAL;
+
+	if (!kvm->arch.migration_mode)
+		return 0;
+
+	/*
+	 * Turn off migration mode when:
+	 * - userspace creates a new memslot with dirty logging off,
+	 * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
+	 *   dirty logging is turned off.
+	 * Migration mode expects dirty page logging being enabled to store
+	 * its dirty bitmap.
+	 */
+	if (change != KVM_MR_DELETE &&
+	    !(mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+		WARN(kvm_s390_vm_stop_migration(kvm),
+		     "Failed to stop migration mode");
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/s390/kvm/kvm-s390.h
+++ linux-ein-5.4.0/arch/s390/kvm/kvm-s390.h
@@ -2,7 +2,7 @@
 /*
  * definition for kvm on s390
  *
- * Copyright IBM Corp. 2008, 2009
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
@@ -15,6 +15,7 @@
 #include <linux/hrtimer.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/lockdep.h>
 #include <asm/facility.h>
 #include <asm/processor.h>
 #include <asm/sclp.h>
@@ -25,6 +26,17 @@
 #define IS_ITDB_VALID(vcpu)	((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
 
 extern debug_info_t *kvm_s390_dbf;
+extern debug_info_t *kvm_s390_dbf_uv;
+
+#define KVM_UV_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
+do { \
+	debug_sprintf_event((d_kvm)->arch.dbf, d_loglevel, d_string "\n", \
+	  d_args); \
+	debug_sprintf_event(kvm_s390_dbf_uv, d_loglevel, \
+			    "%d: " d_string "\n", (d_kvm)->userspace_pid, \
+			    d_args); \
+} while (0)
+
 #define KVM_EVENT(d_loglevel, d_string, d_args...)\
 do { \
 	debug_sprintf_event(kvm_s390_dbf, d_loglevel, d_string "\n", \
@@ -67,7 +79,7 @@
 
 static inline int is_vcpu_idle(struct kvm_vcpu *vcpu)
 {
-	return test_bit(vcpu->vcpu_id, vcpu->kvm->arch.idle_mask);
+	return test_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.idle_mask);
 }
 
 static inline int kvm_is_ucontrol(struct kvm *kvm)
@@ -196,6 +208,48 @@
 	return kvm->arch.user_cpu_state_ctrl != 0;
 }
 
+static inline void kvm_s390_set_user_cpu_state_ctrl(struct kvm *kvm)
+{
+	if (kvm->arch.user_cpu_state_ctrl)
+		return;
+
+	VM_EVENT(kvm, 3, "%s", "ENABLE: Userspace CPU state control");
+	kvm->arch.user_cpu_state_ctrl = 1;
+}
+
+/* implemented in pv.c */
+int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc);
+int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc);
+int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc);
+int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc);
+int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc,
+			      u16 *rrc);
+int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size,
+		       unsigned long tweak, u16 *rc, u16 *rrc);
+int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state);
+
+static inline u64 kvm_s390_pv_get_handle(struct kvm *kvm)
+{
+	return kvm->arch.pv.handle;
+}
+
+static inline u64 kvm_s390_pv_cpu_get_handle(struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.pv.handle;
+}
+
+static inline bool kvm_s390_pv_is_protected(struct kvm *kvm)
+{
+	lockdep_assert_held(&kvm->lock);
+	return !!kvm_s390_pv_get_handle(kvm);
+}
+
+static inline bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu)
+{
+	lockdep_assert_held(&vcpu->mutex);
+	return !!kvm_s390_pv_cpu_get_handle(vcpu);
+}
+
 /* implemented in interrupt.c */
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
@@ -281,13 +335,12 @@
 int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
 
 /* implemented in kvm-s390.c */
-void kvm_s390_set_tod_clock(struct kvm *kvm,
-			    const struct kvm_s390_vm_tod_clock *gtod);
+int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
 long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
 int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
 int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
-void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu);
-void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu);
+int kvm_s390_vcpu_start(struct kvm_vcpu *vcpu);
+int kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu);
 bool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu);
@@ -373,6 +426,7 @@
 int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu);
 extern struct kvm_device_ops kvm_flic_ops;
 int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu);
+int kvm_s390_is_restart_irq_pending(struct kvm_vcpu *vcpu);
 void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu);
 int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu,
 			   void __user *buf, int len);
--- linux-ein-5.4.0.orig/arch/s390/kvm/priv.c
+++ linux-ein-5.4.0/arch/s390/kvm/priv.c
@@ -2,7 +2,7 @@
 /*
  * handling privileged instructions
  *
- * Copyright IBM Corp. 2008, 2018
+ * Copyright IBM Corp. 2008, 2020
  *
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *               Christian Borntraeger <borntraeger@de.ibm.com>
@@ -103,7 +103,20 @@
 		return kvm_s390_inject_prog_cond(vcpu, rc);
 
 	VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
-	kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
+	/*
+	 * To set the TOD clock the kvm lock must be taken, but the vcpu lock
+	 * is already held in handle_set_clock. The usual lock order is the
+	 * opposite.  As SCK is deprecated and should not be used in several
+	 * cases, for example when the multiple epoch facility or TOD clock
+	 * steering facility is installed (see Principles of Operation),  a
+	 * slow path can be used.  If the lock can not be taken via try_lock,
+	 * the instruction will be retried via -EAGAIN at a later point in
+	 * time.
+	 */
+	if (!kvm_s390_try_set_tod_clock(vcpu->kvm, &gtod)) {
+		kvm_s390_retry_instr(vcpu);
+		return -EAGAIN;
+	}
 
 	kvm_s390_set_psw_cc(vcpu, 0);
 	return 0;
@@ -398,6 +411,8 @@
 		up_read(&current->mm->mmap_sem);
 		if (rc == -EFAULT)
 			return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+		if (rc == -EAGAIN)
+			continue;
 		if (rc < 0)
 			return rc;
 		start += PAGE_SIZE;
@@ -626,10 +641,12 @@
 	 * available for the guest are AQIC and TAPQ with the t bit set
 	 * since we do not set IC.3 (FIII) we currently will only intercept
 	 * the AQIC function code.
+	 * Note: running nested under z/VM can result in intercepts for other
+	 * function codes, e.g. PQAP(QCI). We do not support this and bail out.
 	 */
 	reg0 = vcpu->run->s.regs.gprs[0];
 	fc = (reg0 >> 24) & 0xff;
-	if (WARN_ON_ONCE(fc != 0x03))
+	if (fc != 0x03)
 		return -EOPNOTSUPP;
 
 	/* PQAP instruction is allowed for guest kernel only */
@@ -872,7 +889,7 @@
 
 	operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
 
-	if (operand2 & 0xfff)
+	if (!kvm_s390_pv_cpu_is_protected(vcpu) && (operand2 & 0xfff))
 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
 	switch (fc) {
@@ -893,8 +910,13 @@
 		handle_stsi_3_2_2(vcpu, (void *) mem);
 		break;
 	}
-
-	rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE);
+	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+		memcpy((void *)sida_origin(vcpu->arch.sie_block), (void *)mem,
+		       PAGE_SIZE);
+		rc = 0;
+	} else {
+		rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE);
+	}
 	if (rc) {
 		rc = kvm_s390_inject_prog_cond(vcpu, rc);
 		goto out;
@@ -1432,10 +1454,11 @@
 
 static int handle_tprot(struct kvm_vcpu *vcpu)
 {
-	u64 address1, address2;
-	unsigned long hva, gpa;
-	int ret = 0, cc = 0;
+	u64 address, operand2;
+	unsigned long gpa;
+	u8 access_key;
 	bool writable;
+	int ret, cc;
 	u8 ar;
 
 	vcpu->stat.instruction_tprot++;
@@ -1443,43 +1466,46 @@
 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
-	kvm_s390_get_base_disp_sse(vcpu, &address1, &address2, &ar, NULL);
+	kvm_s390_get_base_disp_sse(vcpu, &address, &operand2, &ar, NULL);
+	access_key = (operand2 & 0xf0) >> 4;
 
-	/* we only handle the Linux memory detection case:
-	 * access key == 0
-	 * everything else goes to userspace. */
-	if (address2 & 0xf0)
-		return -EOPNOTSUPP;
 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
 		ipte_lock(vcpu);
-	ret = guest_translate_address(vcpu, address1, ar, &gpa, GACC_STORE);
-	if (ret == PGM_PROTECTION) {
+
+	ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
+					       GACC_STORE, access_key);
+	if (ret == 0) {
+		gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
+	} else if (ret == PGM_PROTECTION) {
+		writable = false;
 		/* Write protected? Try again with read-only... */
-		cc = 1;
-		ret = guest_translate_address(vcpu, address1, ar, &gpa,
-					      GACC_FETCH);
+		ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
+						       GACC_FETCH, access_key);
 	}
-	if (ret) {
-		if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) {
-			ret = kvm_s390_inject_program_int(vcpu, ret);
-		} else if (ret > 0) {
-			/* Translation not available */
-			kvm_s390_set_psw_cc(vcpu, 3);
+	if (ret >= 0) {
+		cc = -1;
+
+		/* Fetching permitted; storing permitted */
+		if (ret == 0 && writable)
+			cc = 0;
+		/* Fetching permitted; storing not permitted */
+		else if (ret == 0 && !writable)
+			cc = 1;
+		/* Fetching not permitted; storing not permitted */
+		else if (ret == PGM_PROTECTION)
+			cc = 2;
+		/* Translation not available */
+		else if (ret != PGM_ADDRESSING && ret != PGM_TRANSLATION_SPEC)
+			cc = 3;
+
+		if (cc != -1) {
+			kvm_s390_set_psw_cc(vcpu, cc);
 			ret = 0;
+		} else {
+			ret = kvm_s390_inject_program_int(vcpu, ret);
 		}
-		goto out_unlock;
 	}
 
-	hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
-	if (kvm_is_error_hva(hva)) {
-		ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-	} else {
-		if (!writable)
-			cc = 1;		/* Write not permitted ==> read-only */
-		kvm_s390_set_psw_cc(vcpu, cc);
-		/* Note: CC2 only occurs for storage keys (not supported yet) */
-	}
-out_unlock:
 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
 		ipte_unlock(vcpu);
 	return ret;
--- linux-ein-5.4.0.orig/arch/s390/kvm/pv.c
+++ linux-ein-5.4.0/arch/s390/kvm/pv.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hosting Protected Virtual Machines
+ *
+ * Copyright IBM Corp. 2019, 2020
+ *    Author(s): Janosch Frank <frankja@linux.ibm.com>
+ */
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/pagemap.h>
+#include <linux/sched/signal.h>
+#include <asm/pgalloc.h>
+#include <asm/gmap.h>
+#include <asm/uv.h>
+#include <asm/mman.h>
+#include "kvm-s390.h"
+
+int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
+{
+	int cc = 0;
+
+	if (kvm_s390_pv_cpu_get_handle(vcpu)) {
+		cc = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
+				   UVC_CMD_DESTROY_SEC_CPU, rc, rrc);
+
+		KVM_UV_EVENT(vcpu->kvm, 3,
+			     "PROTVIRT DESTROY VCPU %d: rc %x rrc %x",
+			     vcpu->vcpu_id, *rc, *rrc);
+		WARN_ONCE(cc, "protvirt destroy cpu failed rc %x rrc %x",
+			  *rc, *rrc);
+	}
+	/* Intended memory leak for something that should never happen. */
+	if (!cc)
+		free_pages(vcpu->arch.pv.stor_base,
+			   get_order(uv_info.guest_cpu_stor_len));
+
+	free_page(sida_origin(vcpu->arch.sie_block));
+	vcpu->arch.sie_block->pv_handle_cpu = 0;
+	vcpu->arch.sie_block->pv_handle_config = 0;
+	memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
+	vcpu->arch.sie_block->sdf = 0;
+	/*
+	 * The sidad field (for sdf == 2) is now the gbea field (for sdf == 0).
+	 * Use the reset value of gbea to avoid leaking the kernel pointer of
+	 * the just freed sida.
+	 */
+	vcpu->arch.sie_block->gbea = 1;
+	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+
+	return cc ? EIO : 0;
+}
+
+int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
+{
+	struct uv_cb_csc uvcb = {
+		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
+		.header.len = sizeof(uvcb),
+	};
+	int cc;
+
+	if (kvm_s390_pv_cpu_get_handle(vcpu))
+		return -EINVAL;
+
+	vcpu->arch.pv.stor_base = __get_free_pages(GFP_KERNEL,
+						   get_order(uv_info.guest_cpu_stor_len));
+	if (!vcpu->arch.pv.stor_base)
+		return -ENOMEM;
+
+	/* Input */
+	uvcb.guest_handle = kvm_s390_pv_get_handle(vcpu->kvm);
+	uvcb.num = vcpu->arch.sie_block->icpua;
+	uvcb.state_origin = (u64)vcpu->arch.sie_block;
+	uvcb.stor_origin = (u64)vcpu->arch.pv.stor_base;
+
+	/* Alloc Secure Instruction Data Area Designation */
+	vcpu->arch.sie_block->sidad = __get_free_page(GFP_KERNEL | __GFP_ZERO);
+	if (!vcpu->arch.sie_block->sidad) {
+		free_pages(vcpu->arch.pv.stor_base,
+			   get_order(uv_info.guest_cpu_stor_len));
+		return -ENOMEM;
+	}
+
+	cc = uv_call(0, (u64)&uvcb);
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+	KVM_UV_EVENT(vcpu->kvm, 3,
+		     "PROTVIRT CREATE VCPU: cpu %d handle %llx rc %x rrc %x",
+		     vcpu->vcpu_id, uvcb.cpu_handle, uvcb.header.rc,
+		     uvcb.header.rrc);
+
+	if (cc) {
+		u16 dummy;
+
+		kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
+		return -EIO;
+	}
+
+	/* Output */
+	vcpu->arch.pv.handle = uvcb.cpu_handle;
+	vcpu->arch.sie_block->pv_handle_cpu = uvcb.cpu_handle;
+	vcpu->arch.sie_block->pv_handle_config = kvm_s390_pv_get_handle(vcpu->kvm);
+	vcpu->arch.sie_block->sdf = 2;
+	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+	return 0;
+}
+
+/* only free resources when the destroy was successful */
+static void kvm_s390_pv_dealloc_vm(struct kvm *kvm)
+{
+	vfree(kvm->arch.pv.stor_var);
+	free_pages(kvm->arch.pv.stor_base,
+		   get_order(uv_info.guest_base_stor_len));
+	memset(&kvm->arch.pv, 0, sizeof(kvm->arch.pv));
+}
+
+static int kvm_s390_pv_alloc_vm(struct kvm *kvm)
+{
+	unsigned long base = uv_info.guest_base_stor_len;
+	unsigned long virt = uv_info.guest_virt_var_stor_len;
+	unsigned long npages = 0, vlen = 0;
+	struct kvm_memory_slot *memslot;
+
+	kvm->arch.pv.stor_var = NULL;
+	kvm->arch.pv.stor_base = __get_free_pages(GFP_KERNEL, get_order(base));
+	if (!kvm->arch.pv.stor_base)
+		return -ENOMEM;
+
+	/*
+	 * Calculate current guest storage for allocation of the
+	 * variable storage, which is based on the length in MB.
+	 *
+	 * Slots are sorted by GFN
+	 */
+	mutex_lock(&kvm->slots_lock);
+	memslot = kvm_memslots(kvm)->memslots;
+	npages = memslot->base_gfn + memslot->npages;
+	mutex_unlock(&kvm->slots_lock);
+
+	kvm->arch.pv.guest_len = npages * PAGE_SIZE;
+
+	/* Allocate variable storage */
+	vlen = ALIGN(virt * ((npages * PAGE_SIZE) / HPAGE_SIZE), PAGE_SIZE);
+	vlen += uv_info.guest_virt_base_stor_len;
+	kvm->arch.pv.stor_var = vzalloc(vlen);
+	if (!kvm->arch.pv.stor_var)
+		goto out_err;
+	return 0;
+
+out_err:
+	kvm_s390_pv_dealloc_vm(kvm);
+	return -ENOMEM;
+}
+
+/* this should not fail, but if it does, we must not free the donated memory */
+int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
+{
+	int cc;
+
+	/* make all pages accessible before destroying the guest */
+	s390_reset_acc(kvm->mm);
+
+	cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
+			   UVC_CMD_DESTROY_SEC_CONF, rc, rrc);
+	WRITE_ONCE(kvm->arch.gmap->guest_handle, 0);
+	atomic_set(&kvm->mm->context.is_protected, 0);
+	KVM_UV_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", *rc, *rrc);
+	WARN_ONCE(cc, "protvirt destroy vm failed rc %x rrc %x", *rc, *rrc);
+	/* Inteded memory leak on "impossible" error */
+	if (!cc)
+		kvm_s390_pv_dealloc_vm(kvm);
+	return cc ? -EIO : 0;
+}
+
+int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
+{
+	struct uv_cb_cgc uvcb = {
+		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
+		.header.len = sizeof(uvcb)
+	};
+	int cc, ret;
+	u16 dummy;
+
+	ret = kvm_s390_pv_alloc_vm(kvm);
+	if (ret)
+		return ret;
+
+	/* Inputs */
+	uvcb.guest_stor_origin = 0; /* MSO is 0 for KVM */
+	uvcb.guest_stor_len = kvm->arch.pv.guest_len;
+	uvcb.guest_asce = kvm->arch.gmap->asce;
+	uvcb.guest_sca = (unsigned long)kvm->arch.sca;
+	uvcb.conf_base_stor_origin = (u64)kvm->arch.pv.stor_base;
+	uvcb.conf_virt_stor_origin = (u64)kvm->arch.pv.stor_var;
+
+	cc = uv_call_sched(0, (u64)&uvcb);
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+	KVM_UV_EVENT(kvm, 3, "PROTVIRT CREATE VM: handle %llx len %llx rc %x rrc %x",
+		     uvcb.guest_handle, uvcb.guest_stor_len, *rc, *rrc);
+
+	/* Outputs */
+	kvm->arch.pv.handle = uvcb.guest_handle;
+
+	if (cc) {
+		if (uvcb.header.rc & UVC_RC_NEED_DESTROY)
+			kvm_s390_pv_deinit_vm(kvm, &dummy, &dummy);
+		else
+			kvm_s390_pv_dealloc_vm(kvm);
+		return -EIO;
+	}
+	kvm->arch.gmap->guest_handle = uvcb.guest_handle;
+	atomic_set(&kvm->mm->context.is_protected, 1);
+	return 0;
+}
+
+int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc,
+			      u16 *rrc)
+{
+	struct uv_cb_ssc uvcb = {
+		.header.cmd = UVC_CMD_SET_SEC_CONF_PARAMS,
+		.header.len = sizeof(uvcb),
+		.sec_header_origin = (u64)hdr,
+		.sec_header_len = length,
+		.guest_handle = kvm_s390_pv_get_handle(kvm),
+	};
+	int cc = uv_call(0, (u64)&uvcb);
+
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+	KVM_UV_EVENT(kvm, 3, "PROTVIRT VM SET PARMS: rc %x rrc %x",
+		     *rc, *rrc);
+	return cc ? -EINVAL : 0;
+}
+
+static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak,
+		      u64 offset, u16 *rc, u16 *rrc)
+{
+	struct uv_cb_unp uvcb = {
+		.header.cmd = UVC_CMD_UNPACK_IMG,
+		.header.len = sizeof(uvcb),
+		.guest_handle = kvm_s390_pv_get_handle(kvm),
+		.gaddr = addr,
+		.tweak[0] = tweak,
+		.tweak[1] = offset,
+	};
+	int ret = gmap_make_secure(kvm->arch.gmap, addr, &uvcb);
+
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+
+	if (ret && ret != -EAGAIN)
+		KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: failed addr %llx with rc %x rrc %x",
+			     uvcb.gaddr, *rc, *rrc);
+	return ret;
+}
+
+int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size,
+		       unsigned long tweak, u16 *rc, u16 *rrc)
+{
+	u64 offset = 0;
+	int ret = 0;
+
+	if (addr & ~PAGE_MASK || !size || size & ~PAGE_MASK)
+		return -EINVAL;
+
+	KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: start addr %lx size %lx",
+		     addr, size);
+
+	while (offset < size) {
+		ret = unpack_one(kvm, addr, tweak, offset, rc, rrc);
+		if (ret == -EAGAIN) {
+			cond_resched();
+			if (fatal_signal_pending(current))
+				break;
+			continue;
+		}
+		if (ret)
+			break;
+		addr += PAGE_SIZE;
+		offset += PAGE_SIZE;
+	}
+	if (!ret)
+		KVM_UV_EVENT(kvm, 3, "%s", "PROTVIRT VM UNPACK: successful");
+	return ret;
+}
+
+int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state)
+{
+	struct uv_cb_cpu_set_state uvcb = {
+		.header.cmd	= UVC_CMD_CPU_SET_STATE,
+		.header.len	= sizeof(uvcb),
+		.cpu_handle	= kvm_s390_pv_cpu_get_handle(vcpu),
+		.state		= state,
+	};
+	int cc;
+
+	cc = uv_call(0, (u64)&uvcb);
+	KVM_UV_EVENT(vcpu->kvm, 3, "PROTVIRT SET CPU %d STATE %d rc %x rrc %x",
+		     vcpu->vcpu_id, state, uvcb.header.rc, uvcb.header.rrc);
+	if (cc)
+		return -EINVAL;
+	return 0;
+}
--- linux-ein-5.4.0.orig/arch/s390/kvm/sigp.c
+++ linux-ein-5.4.0/arch/s390/kvm/sigp.c
@@ -151,22 +151,10 @@
 static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter,
 			   u64 *status_reg)
 {
-	unsigned int i;
-	struct kvm_vcpu *v;
-	bool all_stopped = true;
-
-	kvm_for_each_vcpu(i, v, vcpu->kvm) {
-		if (v == vcpu)
-			continue;
-		if (!is_vcpu_stopped(v))
-			all_stopped = false;
-	}
-
 	*status_reg &= 0xffffffff00000000UL;
 
 	/* Reject set arch order, with czam we're always in z/Arch mode. */
-	*status_reg |= (all_stopped ? SIGP_STATUS_INVALID_PARAMETER :
-					SIGP_STATUS_INCORRECT_STATE);
+	*status_reg |= SIGP_STATUS_INVALID_PARAMETER;
 	return SIGP_CC_STATUS_STORED;
 }
 
@@ -288,6 +276,34 @@
 	if (!dst_vcpu)
 		return SIGP_CC_NOT_OPERATIONAL;
 
+	/*
+	 * SIGP RESTART, SIGP STOP, and SIGP STOP AND STORE STATUS orders
+	 * are processed asynchronously. Until the affected VCPU finishes
+	 * its work and calls back into KVM to clear the (RESTART or STOP)
+	 * interrupt, we need to return any new non-reset orders "busy".
+	 *
+	 * This is important because a single VCPU could issue:
+	 *  1) SIGP STOP $DESTINATION
+	 *  2) SIGP SENSE $DESTINATION
+	 *
+	 * If the SIGP SENSE would not be rejected as "busy", it could
+	 * return an incorrect answer as to whether the VCPU is STOPPED
+	 * or OPERATING.
+	 */
+	if (order_code != SIGP_INITIAL_CPU_RESET &&
+	    order_code != SIGP_CPU_RESET) {
+		/*
+		 * Lockless check. Both SIGP STOP and SIGP (RE)START
+		 * properly synchronize everything while processing
+		 * their orders, while the guest cannot observe a
+		 * difference when issuing other orders from two
+		 * different VCPUs.
+		 */
+		if (kvm_s390_is_stop_irq_pending(dst_vcpu) ||
+		    kvm_s390_is_restart_irq_pending(dst_vcpu))
+			return SIGP_CC_BUSY;
+	}
+
 	switch (order_code) {
 	case SIGP_SENSE:
 		vcpu->stat.instruction_sigp_sense++;
@@ -464,9 +480,9 @@
 	struct kvm_vcpu *dest_vcpu;
 	u8 order_code = kvm_s390_get_base_disp_rs(vcpu, NULL);
 
-	trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
-
 	if (order_code == SIGP_EXTERNAL_CALL) {
+		trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
+
 		dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
 		BUG_ON(dest_vcpu == NULL);
 
--- linux-ein-5.4.0.orig/arch/s390/kvm/vsie.c
+++ linux-ein-5.4.0/arch/s390/kvm/vsie.c
@@ -168,7 +168,8 @@
 			    sizeof(struct kvm_s390_apcb0)))
 		return -EFAULT;
 
-	bitmap_and(apcb_s, apcb_s, apcb_h, sizeof(struct kvm_s390_apcb0));
+	bitmap_and(apcb_s, apcb_s, apcb_h,
+		   BITS_PER_BYTE * sizeof(struct kvm_s390_apcb0));
 
 	return 0;
 }
@@ -190,7 +191,8 @@
 			    sizeof(struct kvm_s390_apcb1)))
 		return -EFAULT;
 
-	bitmap_and(apcb_s, apcb_s, apcb_h, sizeof(struct kvm_s390_apcb1));
+	bitmap_and(apcb_s, apcb_s, apcb_h,
+		   BITS_PER_BYTE * sizeof(struct kvm_s390_apcb1));
 
 	return 0;
 }
@@ -540,14 +542,17 @@
 	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
 		scb_s->eca |= scb_o->eca & ECA_CEI;
 	/* Epoch Extension */
-	if (test_kvm_facility(vcpu->kvm, 139))
+	if (test_kvm_facility(vcpu->kvm, 139)) {
 		scb_s->ecd |= scb_o->ecd & ECD_MEF;
+		scb_s->epdx = scb_o->epdx;
+	}
 
 	/* etoken */
 	if (test_kvm_facility(vcpu->kvm, 156))
 		scb_s->ecd |= scb_o->ecd & ECD_ETOKENF;
 
 	scb_s->hpid = HPID_VSIE;
+	scb_s->cpnc = scb_o->cpnc;
 
 	prepare_ibc(vcpu, vsie_page);
 	rc = shadow_crycb(vcpu, vsie_page);
@@ -1202,6 +1207,7 @@
 		scb_s->iprcc = PGM_ADDRESSING;
 		scb_s->pgmilc = 4;
 		scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, 4);
+		rc = 1;
 	}
 	return rc;
 }
--- linux-ein-5.4.0.orig/arch/s390/lib/string.c
+++ linux-ein-5.4.0/arch/s390/lib/string.c
@@ -246,14 +246,13 @@
 #ifdef __HAVE_ARCH_STRRCHR
 char *strrchr(const char *s, int c)
 {
-       size_t len = __strend(s) - s;
+	ssize_t len = __strend(s) - s;
 
-       if (len)
-	       do {
-		       if (s[len] == (char) c)
-			       return (char *) s + len;
-	       } while (--len > 0);
-       return NULL;
+	do {
+		if (s[len] == (char)c)
+			return (char *)s + len;
+	} while (--len >= 0);
+	return NULL;
 }
 EXPORT_SYMBOL(strrchr);
 #endif
--- linux-ein-5.4.0.orig/arch/s390/lib/uaccess.c
+++ linux-ein-5.4.0/arch/s390/lib/uaccess.c
@@ -64,10 +64,13 @@
 {
 	mm_segment_t old_fs;
 	unsigned long asce, cr;
+	unsigned long flags;
 
 	old_fs = current->thread.mm_segment;
 	if (old_fs & 1)
 		return old_fs;
+	/* protect against a concurrent page table upgrade */
+	local_irq_save(flags);
 	current->thread.mm_segment |= 1;
 	asce = S390_lowcore.kernel_asce;
 	if (likely(old_fs == USER_DS)) {
@@ -83,6 +86,7 @@
 		__ctl_load(asce, 7, 7);
 		set_cpu_flag(CIF_ASCE_SECONDARY);
 	}
+	local_irq_restore(flags);
 	return old_fs;
 }
 EXPORT_SYMBOL(enable_sacf_uaccess);
@@ -98,10 +102,16 @@
 EXPORT_SYMBOL(disable_sacf_uaccess);
 
 static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
-						 unsigned long size)
+						 unsigned long size, unsigned long key)
 {
-	register unsigned long reg0 asm("0") = 0x01UL;
 	unsigned long tmp1, tmp2;
+	union oac spec = {
+		.oac2.key = key,
+		.oac2.as = PSW_BITS_AS_PRIMARY,
+		.oac2.k = 1,
+		.oac2.a = 1,
+	};
+	register unsigned long reg0 asm("0") = spec.val;
 
 	tmp1 = -4096UL;
 	asm volatile(
@@ -128,7 +138,7 @@
 }
 
 static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
-						unsigned long size)
+						unsigned long size, unsigned long key)
 {
 	unsigned long tmp1, tmp2;
 	mm_segment_t old_fs;
@@ -137,12 +147,12 @@
 	tmp1 = -256UL;
 	asm volatile(
 		"   sacf  0\n"
-		"0: mvcp  0(%0,%2),0(%1),%3\n"
+		"0: mvcp  0(%0,%2),0(%1),%[key]\n"
 		"7: jz    5f\n"
 		"1: algr  %0,%3\n"
 		"   la    %1,256(%1)\n"
 		"   la    %2,256(%2)\n"
-		"2: mvcp  0(%0,%2),0(%1),%3\n"
+		"2: mvcp  0(%0,%2),0(%1),%[key]\n"
 		"8: jnz   1b\n"
 		"   j     5f\n"
 		"3: la    %4,255(%1)\n"	/* %4 = ptr + 255 */
@@ -151,7 +161,7 @@
 		"   slgr  %4,%1\n"
 		"   clgr  %0,%4\n"	/* copy crosses next page boundary? */
 		"   jnh   6f\n"
-		"4: mvcp  0(%4,%2),0(%1),%3\n"
+		"4: mvcp  0(%4,%2),0(%1),%[key]\n"
 		"9: slgr  %0,%4\n"
 		"   j     6f\n"
 		"5: slgr  %0,%0\n"
@@ -159,24 +169,53 @@
 		EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
 		EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
 		: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
-		: : "cc", "memory");
+		: [key] "d" (key << 4)
+		: "cc", "memory");
 	disable_sacf_uaccess(old_fs);
 	return size;
 }
 
-unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
+static unsigned long raw_copy_from_user_key(void *to, const void __user *from,
+					    unsigned long n, unsigned long key)
 {
 	if (copy_with_mvcos())
-		return copy_from_user_mvcos(to, from, n);
-	return copy_from_user_mvcp(to, from, n);
+		return copy_from_user_mvcos(to, from, n, key);
+	return copy_from_user_mvcp(to, from, n, key);
+}
+
+unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+	return raw_copy_from_user_key(to, from, n, 0);
 }
 EXPORT_SYMBOL(raw_copy_from_user);
 
+unsigned long _copy_from_user_key(void *to, const void __user *from,
+				  unsigned long n, unsigned long key)
+{
+	unsigned long res = n;
+
+	might_fault();
+	if (likely(access_ok(from, n))) {
+		kasan_check_write(to, n);
+		res = raw_copy_from_user_key(to, from, n, key);
+	}
+	if (unlikely(res))
+		memset(to + (n - res), 0, res);
+	return res;
+}
+EXPORT_SYMBOL(_copy_from_user_key);
+
 static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
-					       unsigned long size)
+					       unsigned long size, unsigned long key)
 {
-	register unsigned long reg0 asm("0") = 0x010000UL;
 	unsigned long tmp1, tmp2;
+	union oac spec = {
+		.oac1.key = key,
+		.oac1.as = PSW_BITS_AS_PRIMARY,
+		.oac1.k = 1,
+		.oac1.a = 1,
+	};
+	register unsigned long reg0 asm("0") = spec.val;
 
 	tmp1 = -4096UL;
 	asm volatile(
@@ -203,7 +242,7 @@
 }
 
 static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
-					      unsigned long size)
+					      unsigned long size, unsigned long key)
 {
 	unsigned long tmp1, tmp2;
 	mm_segment_t old_fs;
@@ -212,12 +251,12 @@
 	tmp1 = -256UL;
 	asm volatile(
 		"   sacf  0\n"
-		"0: mvcs  0(%0,%1),0(%2),%3\n"
+		"0: mvcs  0(%0,%1),0(%2),%[key]\n"
 		"7: jz    5f\n"
 		"1: algr  %0,%3\n"
 		"   la    %1,256(%1)\n"
 		"   la    %2,256(%2)\n"
-		"2: mvcs  0(%0,%1),0(%2),%3\n"
+		"2: mvcs  0(%0,%1),0(%2),%[key]\n"
 		"8: jnz   1b\n"
 		"   j     5f\n"
 		"3: la    %4,255(%1)\n" /* %4 = ptr + 255 */
@@ -226,7 +265,7 @@
 		"   slgr  %4,%1\n"
 		"   clgr  %0,%4\n"	/* copy crosses next page boundary? */
 		"   jnh   6f\n"
-		"4: mvcs  0(%4,%1),0(%2),%3\n"
+		"4: mvcs  0(%4,%1),0(%2),%[key]\n"
 		"9: slgr  %0,%4\n"
 		"   j     6f\n"
 		"5: slgr  %0,%0\n"
@@ -234,24 +273,49 @@
 		EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
 		EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
 		: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
-		: : "cc", "memory");
+		: [key] "d" (key << 4)
+		: "cc", "memory");
 	disable_sacf_uaccess(old_fs);
 	return size;
 }
 
-unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
+static unsigned long raw_copy_to_user_key(void __user *to, const void *from,
+					  unsigned long n, unsigned long key)
 {
 	if (copy_with_mvcos())
-		return copy_to_user_mvcos(to, from, n);
-	return copy_to_user_mvcs(to, from, n);
+		return copy_to_user_mvcos(to, from, n, key);
+	return copy_to_user_mvcs(to, from, n, key);
+}
+
+unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	return raw_copy_to_user_key(to, from, n, 0);
 }
 EXPORT_SYMBOL(raw_copy_to_user);
 
+unsigned long _copy_to_user_key(void __user *to, const void *from,
+				unsigned long n, unsigned long key)
+{
+	might_fault();
+	if (access_ok(to, n)) {
+		kasan_check_read(from, n);
+		n = raw_copy_to_user_key(to, from, n, key);
+	}
+	return n;
+}
+EXPORT_SYMBOL(_copy_to_user_key);
+
 static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
 					       unsigned long size)
 {
-	register unsigned long reg0 asm("0") = 0x010001UL;
 	unsigned long tmp1, tmp2;
+	union oac spec = {
+		.oac1.as = PSW_BITS_AS_PRIMARY,
+		.oac1.a = 1,
+		.oac2.as = PSW_BITS_AS_PRIMARY,
+		.oac2.a = 1,
+	};
+	register unsigned long reg0 asm("0") = spec.val;
 
 	tmp1 = -4096UL;
 	/* FIXME: copy with reduced length. */
@@ -314,8 +378,12 @@
 
 static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
 {
-	register unsigned long reg0 asm("0") = 0x010000UL;
 	unsigned long tmp1, tmp2;
+	union oac spec = {
+		.oac1.as = PSW_BITS_AS_PRIMARY,
+		.oac1.a = 1,
+	};
+	register unsigned long reg0 asm("0") = spec.val;
 
 	tmp1 = -4096UL;
 	asm volatile(
@@ -335,7 +403,7 @@
 		"4: slgr  %0,%0\n"
 		"5:\n"
 		EX_TABLE(0b,2b) EX_TABLE(3b,5b)
-		: "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
+		: "+&a" (size), "+&a" (to), "+a" (tmp1), "=&a" (tmp2)
 		: "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
 	return size;
 }
--- linux-ein-5.4.0.orig/arch/s390/mm/fault.c
+++ linux-ein-5.4.0/arch/s390/mm/fault.c
@@ -38,6 +38,7 @@
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
 #include <asm/facility.h>
+#include <asm/uv.h>
 #include "../kernel/entry.h"
 
 #define __FAIL_ADDR_MASK -4096L
@@ -432,7 +433,9 @@
 	flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 	if (user_mode(regs))
 		flags |= FAULT_FLAG_USER;
-	if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
+	if ((trans_exc_code & store_indication) == 0x400)
+		access = VM_WRITE;
+	if (access == VM_WRITE)
 		flags |= FAULT_FLAG_WRITE;
 	down_read(&mm->mmap_sem);
 
@@ -816,3 +819,80 @@
 early_initcall(pfault_irq_init);
 
 #endif /* CONFIG_PFAULT */
+
+#if IS_ENABLED(CONFIG_PGSTE)
+void do_secure_storage_access(struct pt_regs *regs)
+{
+	unsigned long addr = regs->int_parm_long & __FAIL_ADDR_MASK;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	struct page *page;
+	int rc;
+
+	switch (get_fault_type(regs)) {
+	case USER_FAULT:
+		mm = current->mm;
+		down_read(&mm->mmap_sem);
+		vma = find_vma(mm, addr);
+		if (!vma) {
+			up_read(&mm->mmap_sem);
+			do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP);
+			break;
+		}
+		page = follow_page(vma, addr, FOLL_WRITE | FOLL_GET);
+		if (IS_ERR_OR_NULL(page)) {
+			up_read(&mm->mmap_sem);
+			break;
+		}
+		if (arch_make_page_accessible(page))
+			send_sig(SIGSEGV, current, 0);
+		put_page(page);
+		up_read(&mm->mmap_sem);
+		break;
+	case KERNEL_FAULT:
+		page = phys_to_page(addr);
+		if (unlikely(!try_get_page(page)))
+			break;
+		rc = arch_make_page_accessible(page);
+		put_page(page);
+		if (rc)
+			BUG();
+		break;
+	case VDSO_FAULT:
+		/* fallthrough */
+	case GMAP_FAULT:
+		/* fallthrough */
+	default:
+		do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP);
+		WARN_ON_ONCE(1);
+	}
+}
+NOKPROBE_SYMBOL(do_secure_storage_access);
+
+void do_non_secure_storage_access(struct pt_regs *regs)
+{
+	unsigned long gaddr = regs->int_parm_long & __FAIL_ADDR_MASK;
+	struct gmap *gmap = (struct gmap *)S390_lowcore.gmap;
+
+	if (get_fault_type(regs) != GMAP_FAULT) {
+		do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP);
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (gmap_convert_to_secure(gmap, gaddr) == -EINVAL)
+		send_sig(SIGSEGV, current, 0);
+}
+NOKPROBE_SYMBOL(do_non_secure_storage_access);
+
+#else
+void do_secure_storage_access(struct pt_regs *regs)
+{
+	default_trap_handler(regs);
+}
+
+void do_non_secure_storage_access(struct pt_regs *regs)
+{
+	default_trap_handler(regs);
+}
+#endif
--- linux-ein-5.4.0.orig/arch/s390/mm/gmap.c
+++ linux-ein-5.4.0/arch/s390/mm/gmap.c
@@ -684,9 +684,10 @@
 		vmaddr |= gaddr & ~PMD_MASK;
 		/* Get pointer to the page table entry */
 		ptep = get_locked_pte(gmap->mm, vmaddr, &ptl);
-		if (likely(ptep))
+		if (likely(ptep)) {
 			ptep_zap_unused(gmap->mm, vmaddr, ptep, 0);
-		pte_unmap_unlock(ptep, ptl);
+			pte_unmap_unlock(ptep, ptl);
+		}
 	}
 }
 EXPORT_SYMBOL_GPL(__gmap_zap);
@@ -787,14 +788,18 @@
 static inline unsigned long *gmap_table_walk(struct gmap *gmap,
 					     unsigned long gaddr, int level)
 {
+	const int asce_type = gmap->asce & _ASCE_TYPE_MASK;
 	unsigned long *table;
 
 	if ((gmap->asce & _ASCE_TYPE_MASK) + 4 < (level * 4))
 		return NULL;
 	if (gmap_is_shadow(gmap) && gmap->removed)
 		return NULL;
-	if (gaddr & (-1UL << (31 + ((gmap->asce & _ASCE_TYPE_MASK) >> 2)*11)))
+
+	if (asce_type != _ASCE_TYPE_REGION1 &&
+	    gaddr & (-1UL << (31 + (asce_type >> 2) * 11)))
 		return NULL;
+
 	table = gmap->table;
 	switch (gmap->asce & _ASCE_TYPE_MASK) {
 	case _ASCE_TYPE_REGION1:
@@ -1173,6 +1178,7 @@
 static inline void gmap_insert_rmap(struct gmap *sg, unsigned long vmaddr,
 				    struct gmap_rmap *rmap)
 {
+	struct gmap_rmap *temp;
 	void __rcu **slot;
 
 	BUG_ON(!gmap_is_shadow(sg));
@@ -1180,6 +1186,12 @@
 	if (slot) {
 		rmap->next = radix_tree_deref_slot_protected(slot,
 							&sg->guest_table_lock);
+		for (temp = rmap->next; temp; temp = temp->next) {
+			if (temp->raddr == rmap->raddr) {
+				kfree(rmap);
+				return;
+			}
+		}
 		radix_tree_replace_slot(&sg->host_to_rmap, slot, rmap);
 	} else {
 		rmap->next = NULL;
@@ -1840,6 +1852,7 @@
 		goto out_free;
 	} else if (*table & _REGION_ENTRY_ORIGIN) {
 		rc = -EAGAIN;		/* Race with shadow */
+		goto out_free;
 	}
 	crst_table_init(s_r3t, _REGION3_ENTRY_EMPTY);
 	/* mark as invalid as long as the parent table is not protected */
@@ -2480,23 +2493,36 @@
 }
 EXPORT_SYMBOL_GPL(gmap_sync_dirty_log_pmd);
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static int thp_split_walk_pmd_entry(pmd_t *pmd, unsigned long addr,
+				    unsigned long end, struct mm_walk *walk)
+{
+	struct vm_area_struct *vma = walk->vma;
+
+	split_huge_pmd(vma, pmd, addr);
+	return 0;
+}
+
+static const struct mm_walk_ops thp_split_walk_ops = {
+	.pmd_entry	= thp_split_walk_pmd_entry,
+};
+
 static inline void thp_split_mm(struct mm_struct *mm)
 {
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	struct vm_area_struct *vma;
-	unsigned long addr;
 
 	for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
-		for (addr = vma->vm_start;
-		     addr < vma->vm_end;
-		     addr += PAGE_SIZE)
-			follow_page(vma, addr, FOLL_SPLIT);
 		vma->vm_flags &= ~VM_HUGEPAGE;
 		vma->vm_flags |= VM_NOHUGEPAGE;
+		walk_page_vma(vma, &thp_split_walk_ops, NULL);
 	}
 	mm->def_flags |= VM_NOHUGEPAGE;
-#endif
 }
+#else
+static inline void thp_split_mm(struct mm_struct *mm)
+{
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
  * Remove all empty zero pages from the mapping for lazy refaulting
@@ -2548,6 +2574,22 @@
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
 
+int gmap_mark_unmergeable(void)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (ksm_madvise(vma, vma->vm_start, vma->vm_end,
+				MADV_UNMERGEABLE, &vma->vm_flags)) {
+			return -ENOMEM;
+		}
+	}
+	mm->def_flags &= ~VM_MERGEABLE;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gmap_mark_unmergeable);
+
 /*
  * Enable storage key handling from now on and initialize the storage
  * keys with the default key.
@@ -2560,6 +2602,18 @@
 	return 0;
 }
 
+/*
+ * Give a chance to schedule after setting a key to 256 pages.
+ * We only hold the mm lock, which is a rwsem and the kvm srcu.
+ * Both can sleep.
+ */
+static int __s390_enable_skey_pmd(pmd_t *pmd, unsigned long addr,
+				  unsigned long next, struct mm_walk *walk)
+{
+	cond_resched();
+	return 0;
+}
+
 static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr,
 				      unsigned long hmask, unsigned long next,
 				      struct mm_walk *walk)
@@ -2582,18 +2636,19 @@
 	end = start + HPAGE_SIZE - 1;
 	__storage_key_init_range(start, end);
 	set_bit(PG_arch_1, &page->flags);
+	cond_resched();
 	return 0;
 }
 
 static const struct mm_walk_ops enable_skey_walk_ops = {
 	.hugetlb_entry		= __s390_enable_skey_hugetlb,
 	.pte_entry		= __s390_enable_skey_pte,
+	.pmd_entry		= __s390_enable_skey_pmd,
 };
 
 int s390_enable_skey(void)
 {
 	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
 	int rc = 0;
 
 	down_write(&mm->mmap_sem);
@@ -2601,16 +2656,11 @@
 		goto out_up;
 
 	mm->context.uses_skeys = 1;
-	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		if (ksm_madvise(vma, vma->vm_start, vma->vm_end,
-				MADV_UNMERGEABLE, &vma->vm_flags)) {
-			mm->context.uses_skeys = 0;
-			rc = -ENOMEM;
-			goto out_up;
-		}
+	rc = gmap_mark_unmergeable();
+	if (rc) {
+		mm->context.uses_skeys = 0;
+		goto out_up;
 	}
-	mm->def_flags &= ~VM_MERGEABLE;
-
 	walk_page_range(mm, 0, TASK_SIZE, &enable_skey_walk_ops, NULL);
 
 out_up:
@@ -2640,3 +2690,38 @@
 	up_write(&mm->mmap_sem);
 }
 EXPORT_SYMBOL_GPL(s390_reset_cmma);
+
+/*
+ * make inaccessible pages accessible again
+ */
+static int __s390_reset_acc(pte_t *ptep, unsigned long addr,
+			    unsigned long next, struct mm_walk *walk)
+{
+	pte_t pte = READ_ONCE(*ptep);
+
+	if (pte_present(pte))
+		WARN_ON_ONCE(uv_convert_from_secure(pte_val(pte) & PAGE_MASK));
+	return 0;
+}
+
+static const struct mm_walk_ops reset_acc_walk_ops = {
+	.pte_entry		= __s390_reset_acc,
+};
+
+#include <linux/sched/mm.h>
+void s390_reset_acc(struct mm_struct *mm)
+{
+	/*
+	 * we might be called during
+	 * reset:                             we walk the pages and clear
+	 * close of all kvm file descriptors: we walk the pages and clear
+	 * exit of process on fd closure:     vma already gone, do nothing
+	 */
+	if (!mmget_not_zero(mm))
+		return;
+	down_read(&mm->mmap_sem);
+	walk_page_range(mm, 0, TASK_SIZE, &reset_acc_walk_ops, NULL);
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+}
+EXPORT_SYMBOL_GPL(s390_reset_acc);
--- linux-ein-5.4.0.orig/arch/s390/mm/hugetlbpage.c
+++ linux-ein-5.4.0/arch/s390/mm/hugetlbpage.c
@@ -2,7 +2,7 @@
 /*
  *  IBM System z Huge TLB Page Support for Kernel.
  *
- *    Copyright IBM Corp. 2007,2016
+ *    Copyright IBM Corp. 2007,2020
  *    Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
@@ -11,6 +11,9 @@
 
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
+#include <linux/mman.h>
+#include <linux/sched/mm.h>
+#include <linux/security.h>
 
 /*
  * If the bit selected by single-bit bitmask "a" is set within "x", move
@@ -114,7 +117,7 @@
 					     _PAGE_YOUNG);
 #ifdef CONFIG_MEM_SOFT_DIRTY
 		pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY,
-					     _PAGE_DIRTY);
+					     _PAGE_SOFT_DIRTY);
 #endif
 		pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_NOEXEC,
 					     _PAGE_NOEXEC);
@@ -156,10 +159,13 @@
 		rste &= ~_SEGMENT_ENTRY_NOEXEC;
 
 	/* Set correct table type for 2G hugepages */
-	if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
-		rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE;
-	else
+	if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) {
+		if (likely(pte_present(pte)))
+			rste |= _REGION3_ENTRY_LARGE;
+		rste |= _REGION_ENTRY_TYPE_R3;
+	} else if (likely(pte_present(pte)))
 		rste |= _SEGMENT_ENTRY_LARGE;
+
 	clear_huge_pte_skeys(mm, rste);
 	pte_val(*ptep) = rste;
 }
@@ -267,3 +273,98 @@
 	return 1;
 }
 __setup("hugepagesz=", setup_hugepagesz);
+
+static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
+		unsigned long addr, unsigned long len,
+		unsigned long pgoff, unsigned long flags)
+{
+	struct hstate *h = hstate_file(file);
+	struct vm_unmapped_area_info info;
+
+	info.flags = 0;
+	info.length = len;
+	info.low_limit = current->mm->mmap_base;
+	info.high_limit = TASK_SIZE;
+	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
+	info.align_offset = 0;
+	return vm_unmapped_area(&info);
+}
+
+static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
+		unsigned long addr0, unsigned long len,
+		unsigned long pgoff, unsigned long flags)
+{
+	struct hstate *h = hstate_file(file);
+	struct vm_unmapped_area_info info;
+	unsigned long addr;
+
+	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+	info.length = len;
+	info.low_limit = max(PAGE_SIZE, mmap_min_addr);
+	info.high_limit = current->mm->mmap_base;
+	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
+	info.align_offset = 0;
+	addr = vm_unmapped_area(&info);
+
+	/*
+	 * A failed mmap() very likely causes application failure,
+	 * so fall back to the bottom-up function here. This scenario
+	 * can happen with large stack limits and large mmap()
+	 * allocations.
+	 */
+	if (addr & ~PAGE_MASK) {
+		VM_BUG_ON(addr != -ENOMEM);
+		info.flags = 0;
+		info.low_limit = TASK_UNMAPPED_BASE;
+		info.high_limit = TASK_SIZE;
+		addr = vm_unmapped_area(&info);
+	}
+
+	return addr;
+}
+
+unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+		unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct hstate *h = hstate_file(file);
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	int rc;
+
+	if (len & ~huge_page_mask(h))
+		return -EINVAL;
+	if (len > TASK_SIZE - mmap_min_addr)
+		return -ENOMEM;
+
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(file, addr, len))
+			return -EINVAL;
+		goto check_asce_limit;
+	}
+
+	if (addr) {
+		addr = ALIGN(addr, huge_page_size(h));
+		vma = find_vma(mm, addr);
+		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
+		    (!vma || addr + len <= vm_start_gap(vma)))
+			goto check_asce_limit;
+	}
+
+	if (mm->get_unmapped_area == arch_get_unmapped_area)
+		addr = hugetlb_get_unmapped_area_bottomup(file, addr, len,
+				pgoff, flags);
+	else
+		addr = hugetlb_get_unmapped_area_topdown(file, addr, len,
+				pgoff, flags);
+	if (addr & ~PAGE_MASK)
+		return addr;
+
+check_asce_limit:
+	if (addr + len > current->mm->context.asce_limit &&
+	    addr + len <= TASK_SIZE) {
+		rc = crst_table_upgrade(mm, addr + len);
+		if (rc)
+			return (unsigned long) rc;
+	}
+	return addr;
+}
--- linux-ein-5.4.0.orig/arch/s390/mm/init.c
+++ linux-ein-5.4.0/arch/s390/mm/init.c
@@ -168,9 +168,9 @@
 		return;
 
 	/* make sure bounce buffers are shared */
+	swiotlb_force = SWIOTLB_FORCE;
 	swiotlb_init(1);
 	swiotlb_update_mem_attributes();
-	swiotlb_force = SWIOTLB_FORCE;
 }
 
 void __init mem_init(void)
@@ -291,10 +291,8 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct zone *zone;
 
-	zone = page_zone(pfn_to_page(start_pfn));
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 	vmem_remove_mapping(start, size);
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
--- linux-ein-5.4.0.orig/arch/s390/mm/kasan_init.c
+++ linux-ein-5.4.0/arch/s390/mm/kasan_init.c
@@ -101,6 +101,9 @@
 	pgt_prot = pgprot_val(PAGE_KERNEL_EXEC);
 	sgt_prot = pgprot_val(SEGMENT_KERNEL_EXEC);
 
+	/*
+	 * The first 1MB of 1:1 mapping is mapped with 4KB pages
+	 */
 	while (address < end) {
 		pg_dir = pgd_offset_k(address);
 		if (pgd_none(*pg_dir)) {
@@ -146,30 +149,26 @@
 
 		pm_dir = pmd_offset(pu_dir, address);
 		if (pmd_none(*pm_dir)) {
-			if (mode == POPULATE_ZERO_SHADOW &&
-			    IS_ALIGNED(address, PMD_SIZE) &&
+			if (IS_ALIGNED(address, PMD_SIZE) &&
 			    end - address >= PMD_SIZE) {
-				pmd_populate(&init_mm, pm_dir,
-						kasan_early_shadow_pte);
-				address = (address + PMD_SIZE) & PMD_MASK;
-				continue;
-			}
-			/* the first megabyte of 1:1 is mapped with 4k pages */
-			if (has_edat && address && end - address >= PMD_SIZE &&
-			    mode != POPULATE_ZERO_SHADOW) {
-				void *page;
-
-				if (mode == POPULATE_ONE2ONE) {
-					page = (void *)address;
-				} else {
-					page = kasan_early_alloc_segment();
-					memset(page, 0, _SEGMENT_SIZE);
+				if (mode == POPULATE_ZERO_SHADOW) {
+					pmd_populate(&init_mm, pm_dir, kasan_early_shadow_pte);
+					address = (address + PMD_SIZE) & PMD_MASK;
+					continue;
+				} else if (has_edat && address) {
+					void *page;
+
+					if (mode == POPULATE_ONE2ONE) {
+						page = (void *)address;
+					} else {
+						page = kasan_early_alloc_segment();
+						memset(page, 0, _SEGMENT_SIZE);
+					}
+					pmd_val(*pm_dir) = __pa(page) | sgt_prot;
+					address = (address + PMD_SIZE) & PMD_MASK;
+					continue;
 				}
-				pmd_val(*pm_dir) = __pa(page) | sgt_prot;
-				address = (address + PMD_SIZE) & PMD_MASK;
-				continue;
 			}
-
 			pt_dir = kasan_early_pte_alloc();
 			pmd_populate(&init_mm, pm_dir, pt_dir);
 		} else if (pmd_large(*pm_dir)) {
--- linux-ein-5.4.0.orig/arch/s390/mm/maccess.c
+++ linux-ein-5.4.0/arch/s390/mm/maccess.c
@@ -55,22 +55,29 @@
  */
 static DEFINE_SPINLOCK(s390_kernel_write_lock);
 
-void notrace s390_kernel_write(void *dst, const void *src, size_t size)
+notrace void *s390_kernel_write(void *dst, const void *src, size_t size)
 {
+	void *tmp = dst;
 	unsigned long flags;
 	long copied;
 
 	spin_lock_irqsave(&s390_kernel_write_lock, flags);
-	while (size) {
-		copied = s390_kernel_write_odd(dst, src, size);
-		dst += copied;
-		src += copied;
-		size -= copied;
+	if (!(flags & PSW_MASK_DAT)) {
+		memcpy(dst, src, size);
+	} else {
+		while (size) {
+			copied = s390_kernel_write_odd(tmp, src, size);
+			tmp += copied;
+			src += copied;
+			size -= copied;
+		}
 	}
 	spin_unlock_irqrestore(&s390_kernel_write_lock, flags);
+
+	return dst;
 }
 
-static int __memcpy_real(void *dest, void *src, size_t count)
+static int __no_sanitize_address __memcpy_real(void *dest, void *src, size_t count)
 {
 	register unsigned long _dest asm("2") = (unsigned long) dest;
 	register unsigned long _len1 asm("3") = (unsigned long) count;
@@ -91,19 +98,23 @@
 	return rc;
 }
 
-static unsigned long _memcpy_real(unsigned long dest, unsigned long src,
-				  unsigned long count)
+static unsigned long __no_sanitize_address _memcpy_real(unsigned long dest,
+							unsigned long src,
+							unsigned long count)
 {
 	int irqs_disabled, rc;
 	unsigned long flags;
 
 	if (!count)
 		return 0;
-	flags = __arch_local_irq_stnsm(0xf8UL);
+	flags = arch_local_irq_save();
 	irqs_disabled = arch_irqs_disabled_flags(flags);
 	if (!irqs_disabled)
 		trace_hardirqs_off();
+	__arch_local_irq_stnsm(0xf8); // disable DAT
 	rc = __memcpy_real((void *) dest, (void *) src, (size_t) count);
+	if (flags & PSW_MASK_DAT)
+		__arch_local_irq_stosm(0x04); // enable DAT
 	if (!irqs_disabled)
 		trace_hardirqs_on();
 	__arch_local_irq_ssm(flags);
@@ -115,9 +126,15 @@
  */
 int memcpy_real(void *dest, void *src, size_t count)
 {
-	if (S390_lowcore.nodat_stack != 0)
-		return CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack,
-				     3, dest, src, count);
+	int rc;
+
+	if (S390_lowcore.nodat_stack != 0) {
+		preempt_disable();
+		rc = CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack, 3,
+				   dest, src, count);
+		preempt_enable();
+		return rc;
+	}
 	/*
 	 * This is a really early memcpy_real call, the stacks are
 	 * not set up yet. Just call _memcpy_real on the early boot
--- linux-ein-5.4.0.orig/arch/s390/mm/page-states.c
+++ linux-ein-5.4.0/arch/s390/mm/page-states.c
@@ -112,7 +112,7 @@
 		next = pmd_addr_end(addr, end);
 		if (pmd_none(*pmd) || pmd_large(*pmd))
 			continue;
-		page = virt_to_page(pmd_val(*pmd));
+		page = phys_to_page(pmd_val(*pmd));
 		set_bit(PG_arch_1, &page->flags);
 	} while (pmd++, addr = next, addr != end);
 }
@@ -130,8 +130,8 @@
 		if (pud_none(*pud) || pud_large(*pud))
 			continue;
 		if (!pud_folded(*pud)) {
-			page = virt_to_page(pud_val(*pud));
-			for (i = 0; i < 3; i++)
+			page = phys_to_page(pud_val(*pud));
+			for (i = 0; i < 4; i++)
 				set_bit(PG_arch_1, &page[i].flags);
 		}
 		mark_kernel_pmd(pud, addr, next);
@@ -151,8 +151,8 @@
 		if (p4d_none(*p4d))
 			continue;
 		if (!p4d_folded(*p4d)) {
-			page = virt_to_page(p4d_val(*p4d));
-			for (i = 0; i < 3; i++)
+			page = phys_to_page(p4d_val(*p4d));
+			for (i = 0; i < 4; i++)
 				set_bit(PG_arch_1, &page[i].flags);
 		}
 		mark_kernel_pud(p4d, addr, next);
@@ -173,8 +173,8 @@
 		if (pgd_none(*pgd))
 			continue;
 		if (!pgd_folded(*pgd)) {
-			page = virt_to_page(pgd_val(*pgd));
-			for (i = 0; i < 3; i++)
+			page = phys_to_page(pgd_val(*pgd));
+			for (i = 0; i < 4; i++)
 				set_bit(PG_arch_1, &page[i].flags);
 		}
 		mark_kernel_p4d(pgd, addr, next);
--- linux-ein-5.4.0.orig/arch/s390/mm/pgalloc.c
+++ linux-ein-5.4.0/arch/s390/mm/pgalloc.c
@@ -70,8 +70,20 @@
 {
 	struct mm_struct *mm = arg;
 
-	if (current->active_mm == mm)
-		set_user_asce(mm);
+	/* we must change all active ASCEs to avoid the creation of new TLBs */
+	if (current->active_mm == mm) {
+		S390_lowcore.user_asce = mm->context.asce;
+		if (current->thread.mm_segment == USER_DS) {
+			__ctl_load(S390_lowcore.user_asce, 1, 1);
+			/* Mark user-ASCE present in CR1 */
+			clear_cpu_flag(CIF_ASCE_PRIMARY);
+		}
+		if (current->thread.mm_segment == USER_DS_SACF) {
+			__ctl_load(S390_lowcore.user_asce, 7, 7);
+			/* enable_sacf_uaccess does all or nothing */
+			WARN_ON(!test_cpu_flag(CIF_ASCE_SECONDARY));
+		}
+	}
 	__tlb_flush_local();
 }
 
@@ -243,13 +255,15 @@
 		/* Free 2K page table fragment of a 4K page */
 		bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
 		spin_lock_bh(&mm->context.lock);
-		mask = atomic_xor_bits(&page->_refcount, 1U << (bit + 24));
+		mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));
 		mask >>= 24;
 		if (mask & 3)
 			list_add(&page->lru, &mm->context.pgtable_list);
 		else
 			list_del(&page->lru);
 		spin_unlock_bh(&mm->context.lock);
+		mask = atomic_xor_bits(&page->_refcount, 0x10U << (bit + 24));
+		mask >>= 24;
 		if (mask != 0)
 			return;
 	} else {
--- linux-ein-5.4.0.orig/arch/s390/mm/pgtable.c
+++ linux-ein-5.4.0/arch/s390/mm/pgtable.c
@@ -699,7 +699,7 @@
 		pte_clear(mm, addr, ptep);
 	}
 	if (reset)
-		pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK;
+		pgste_val(pgste) &= ~(_PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT);
 	pgste_set_unlock(ptep, pgste);
 	preempt_enable();
 }
@@ -716,7 +716,7 @@
 	pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT;
 	ptev = pte_val(*ptep);
 	if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE))
-		page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1);
+		page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 0);
 	pgste_set_unlock(ptep, pgste);
 	preempt_enable();
 }
@@ -970,6 +970,7 @@
 int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
 			unsigned long *oldpte, unsigned long *oldpgste)
 {
+	struct vm_area_struct *vma;
 	unsigned long pgstev;
 	spinlock_t *ptl;
 	pgste_t pgste;
@@ -979,6 +980,10 @@
 	WARN_ON_ONCE(orc > ESSA_MAX);
 	if (unlikely(orc > ESSA_MAX))
 		return -EINVAL;
+
+	vma = find_vma(mm, hva);
+	if (!vma || hva < vma->vm_start || is_vm_hugetlb_page(vma))
+		return -EFAULT;
 	ptep = get_locked_pte(mm, hva, &ptl);
 	if (unlikely(!ptep))
 		return -EFAULT;
@@ -1071,10 +1076,14 @@
 int set_pgste_bits(struct mm_struct *mm, unsigned long hva,
 			unsigned long bits, unsigned long value)
 {
+	struct vm_area_struct *vma;
 	spinlock_t *ptl;
 	pgste_t new;
 	pte_t *ptep;
 
+	vma = find_vma(mm, hva);
+	if (!vma || hva < vma->vm_start || is_vm_hugetlb_page(vma))
+		return -EFAULT;
 	ptep = get_locked_pte(mm, hva, &ptl);
 	if (unlikely(!ptep))
 		return -EFAULT;
@@ -1099,9 +1108,13 @@
  */
 int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep)
 {
+	struct vm_area_struct *vma;
 	spinlock_t *ptl;
 	pte_t *ptep;
 
+	vma = find_vma(mm, hva);
+	if (!vma || hva < vma->vm_start || is_vm_hugetlb_page(vma))
+		return -EFAULT;
 	ptep = get_locked_pte(mm, hva, &ptl);
 	if (unlikely(!ptep))
 		return -EFAULT;
--- linux-ein-5.4.0.orig/arch/s390/mm/vmem.c
+++ linux-ein-5.4.0/arch/s390/mm/vmem.c
@@ -415,6 +415,10 @@
 		     SET_MEMORY_RO | SET_MEMORY_X);
 	__set_memory(__stext_dma, (__etext_dma - __stext_dma) >> PAGE_SHIFT,
 		     SET_MEMORY_RO | SET_MEMORY_X);
+
+	/* we need lowcore executable for our LPSWE instructions */
+	set_memory_x(0, 1);
+
 	pr_info("Write protected kernel read-only data: %luk\n",
 		(unsigned long)(__end_rodata - _stext) >> 10);
 }
--- linux-ein-5.4.0.orig/arch/s390/net/bpf_jit_comp.c
+++ linux-ein-5.4.0/arch/s390/net/bpf_jit_comp.c
@@ -23,6 +23,7 @@
 #include <linux/filter.h>
 #include <linux/init.h>
 #include <linux/bpf.h>
+#include <linux/mm.h>
 #include <asm/cacheflush.h>
 #include <asm/dis.h>
 #include <asm/facility.h>
@@ -113,7 +114,7 @@
 {
 	u32 r1 = reg2hex[b1];
 
-	if (!jit->seen_reg[r1] && r1 >= 6 && r1 <= 15)
+	if (r1 >= 6 && r1 <= 15 && !jit->seen_reg[r1])
 		jit->seen_reg[r1] = 1;
 }
 
@@ -568,10 +569,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 */
@@ -593,17 +594,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
@@ -618,10 +624,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 */
@@ -674,6 +680,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 */
@@ -768,10 +776,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 */
@@ -792,10 +800,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 */
@@ -817,10 +825,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 */
@@ -842,10 +850,10 @@
 		EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0);
 		break;
 	case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */
-		if (imm == 0)
-			break;
-		/* sra %dst,imm(%r0) */
-		EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
+		if (imm != 0) {
+			/* sra %dst,imm(%r0) */
+			EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
+		}
 		EMIT_ZERO(dst_reg);
 		break;
 	case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */
@@ -913,6 +921,11 @@
 		}
 		break;
 	/*
+	 * BPF_NOSPEC (speculation barrier)
+	 */
+	case BPF_ST | BPF_NOSPEC:
+		break;
+	/*
 	 * BPF_ST(X)
 	 */
 	case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */
@@ -1369,10 +1382,10 @@
 	}
 
 	memset(&jit, 0, sizeof(jit));
-	jit.addrs = kcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
+	jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
 	if (jit.addrs == NULL) {
 		fp = orig_fp;
-		goto out;
+		goto free_addrs;
 	}
 	/*
 	 * Three initial passes:
@@ -1422,7 +1435,7 @@
 	if (!fp->is_func || extra_pass) {
 		bpf_prog_fill_jited_linfo(fp, jit.addrs + 1);
 free_addrs:
-		kfree(jit.addrs);
+		kvfree(jit.addrs);
 		kfree(jit_data);
 		fp->aux->jit_data = NULL;
 	}
--- linux-ein-5.4.0.orig/arch/s390/numa/numa.c
+++ linux-ein-5.4.0/arch/s390/numa/numa.c
@@ -49,12 +49,6 @@
 		mode->update_cpu_topology();
 }
 
-int __node_distance(int a, int b)
-{
-	return mode->distance ? mode->distance(a, b) : 0;
-}
-EXPORT_SYMBOL(__node_distance);
-
 int numa_debug_enabled;
 
 /*
--- linux-ein-5.4.0.orig/arch/s390/pci/Makefile
+++ linux-ein-5.4.0/arch/s390/pci/Makefile
@@ -4,4 +4,5 @@
 #
 
 obj-$(CONFIG_PCI)	+= pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \
-			   pci_event.o pci_debug.o pci_insn.o pci_mmio.o
+			   pci_event.o pci_debug.o pci_insn.o pci_mmio.o \
+			   pci_bus.o
--- linux-ein-5.4.0.orig/arch/s390/pci/pci.c
+++ linux-ein-5.4.0/arch/s390/pci/pci.c
@@ -35,17 +35,21 @@
 #include <asm/pci_clp.h>
 #include <asm/pci_dma.h>
 
+#include "pci_bus.h"
+
 /* list of all detected zpci devices */
 static LIST_HEAD(zpci_list);
 static DEFINE_SPINLOCK(zpci_list_lock);
 
-static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
+static DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE);
 static DEFINE_SPINLOCK(zpci_domain_lock);
 
 #define ZPCI_IOMAP_ENTRIES						\
 	min(((unsigned long) ZPCI_NR_DEVICES * PCI_BAR_COUNT / 2),	\
 	    ZPCI_IOMAP_MAX_ENTRIES)
 
+unsigned int s390_pci_no_rid;
+
 static DEFINE_SPINLOCK(zpci_iomap_lock);
 static unsigned long *zpci_iomap_bitmap;
 struct zpci_iomap_entry *zpci_iomap_start;
@@ -86,17 +90,12 @@
 	spin_unlock(&zpci_list_lock);
 
 	list_for_each_entry_safe(zdev, tmp, &remove, entry)
-		zpci_remove_device(zdev);
-}
-
-static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus)
-{
-	return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL;
+		zpci_device_reserved(zdev);
 }
 
 int pci_domain_nr(struct pci_bus *bus)
 {
-	return ((struct zpci_dev *) bus->sysdata)->domain;
+	return ((struct zpci_bus *) bus->sysdata)->domain_nr;
 }
 EXPORT_SYMBOL_GPL(pci_domain_nr);
 
@@ -223,7 +222,7 @@
 /* combine single writes by using store-block insn */
 void __iowrite64_copy(void __iomem *to, const void *from, size_t count)
 {
-       zpci_memcpy_toio(to, from, count);
+	zpci_memcpy_toio(to, from, count * 8);
 }
 
 void __iomem *ioremap(unsigned long ioaddr, unsigned long size)
@@ -371,29 +370,17 @@
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
 		    int size, u32 *val)
 {
-	struct zpci_dev *zdev = get_zdev_by_bus(bus);
-	int ret;
+	struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn);
 
-	if (!zdev || devfn != ZPCI_DEVFN)
-		ret = -ENODEV;
-	else
-		ret = zpci_cfg_load(zdev, where, val, size);
-
-	return ret;
+	return (zdev) ? zpci_cfg_load(zdev, where, val, size) : -ENODEV;
 }
 
 static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
 		     int size, u32 val)
 {
-	struct zpci_dev *zdev = get_zdev_by_bus(bus);
-	int ret;
+	struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn);
 
-	if (!zdev || devfn != ZPCI_DEVFN)
-		ret = -ENODEV;
-	else
-		ret = zpci_cfg_store(zdev, where, val, size);
-
-	return ret;
+	return (zdev) ? zpci_cfg_store(zdev, where, val, size) : -ENODEV;
 }
 
 static struct pci_ops pci_root_ops = {
@@ -423,7 +410,7 @@
 
 		if (zpci_use_mio(zdev))
 			pdev->resource[i].start =
-				(resource_size_t __force) zdev->bars[i].mio_wb;
+				(resource_size_t __force) zdev->bars[i].mio_wt;
 		else
 			pdev->resource[i].start = (resource_size_t __force)
 				pci_iomap_range_fh(pdev, i, 0, 0);
@@ -504,15 +491,15 @@
 	return r;
 }
 
-static int zpci_setup_bus_resources(struct zpci_dev *zdev,
-				    struct list_head *resources)
+int zpci_setup_bus_resources(struct zpci_dev *zdev,
+			     struct list_head *resources)
 {
 	unsigned long addr, size, flags;
 	struct resource *res;
 	int i, entry;
 
 	snprintf(zdev->res_name, sizeof(zdev->res_name),
-		 "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR);
+		 "PCI Bus %04x:%02x", zdev->uid, ZPCI_BUS_NR);
 
 	for (i = 0; i < PCI_BAR_COUNT; i++) {
 		if (!zdev->bars[i].size)
@@ -530,7 +517,7 @@
 			flags |= IORESOURCE_MEM_64;
 
 		if (zpci_use_mio(zdev))
-			addr = (unsigned long) zdev->bars[i].mio_wb;
+			addr = (unsigned long) zdev->bars[i].mio_wt;
 		else
 			addr = ZPCI_ADDR(entry);
 		size = 1UL << zdev->bars[i].size;
@@ -563,9 +550,12 @@
 
 int pcibios_add_device(struct pci_dev *pdev)
 {
+	struct zpci_dev *zdev = to_zpci(pdev);
 	struct resource *res;
 	int i;
 
+	/* The pdev has a reference to the zdev via its bus */
+	zpci_zdev_get(zdev);
 	if (pdev->is_physfn)
 		pdev->no_vf_scan = 1;
 
@@ -585,7 +575,10 @@
 
 void pcibios_release_device(struct pci_dev *pdev)
 {
+	struct zpci_dev *zdev = to_zpci(pdev);
+
 	zpci_unmap_resources(pdev);
+	zpci_zdev_put(zdev);
 }
 
 int pcibios_enable_device(struct pci_dev *pdev, int mask)
@@ -649,86 +642,54 @@
 };
 #endif /* CONFIG_HIBERNATE_CALLBACKS */
 
-static int zpci_alloc_domain(struct zpci_dev *zdev)
+static int __zpci_register_domain(int domain)
 {
-	if (zpci_unique_uid) {
-		zdev->domain = (u16) zdev->uid;
-		if (zdev->domain >= ZPCI_NR_DEVICES)
-			return 0;
-
-		spin_lock(&zpci_domain_lock);
-		if (test_bit(zdev->domain, zpci_domain)) {
-			spin_unlock(&zpci_domain_lock);
-			return -EEXIST;
-		}
-		set_bit(zdev->domain, zpci_domain);
-		spin_unlock(&zpci_domain_lock);
-		return 0;
-	}
-
 	spin_lock(&zpci_domain_lock);
-	zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES);
-	if (zdev->domain == ZPCI_NR_DEVICES) {
+	if (test_bit(domain, zpci_domain)) {
 		spin_unlock(&zpci_domain_lock);
-		return -ENOSPC;
+		pr_err("Domain %04x is already assigned\n", domain);
+		return -EEXIST;
 	}
-	set_bit(zdev->domain, zpci_domain);
+	set_bit(domain, zpci_domain);
 	spin_unlock(&zpci_domain_lock);
-	return 0;
+	return domain;
 }
 
-static void zpci_free_domain(struct zpci_dev *zdev)
+static int __zpci_alloc_domain(void)
 {
-	if (zdev->domain >= ZPCI_NR_DEVICES)
-		return;
+	int domain;
 
 	spin_lock(&zpci_domain_lock);
-	clear_bit(zdev->domain, zpci_domain);
+	/*
+	 * We can always auto allocate domains below ZPCI_NR_DEVICES.
+	 * There is either a free domain or we have reached the maximum in
+	 * which case we would have bailed earlier.
+	 */
+	domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES);
+	set_bit(domain, zpci_domain);
 	spin_unlock(&zpci_domain_lock);
+	return domain;
 }
 
-void pcibios_remove_bus(struct pci_bus *bus)
+int zpci_alloc_domain(int domain)
 {
-	struct zpci_dev *zdev = get_zdev_by_bus(bus);
-
-	zpci_exit_slot(zdev);
-	zpci_cleanup_bus_resources(zdev);
-	zpci_destroy_iommu(zdev);
-	zpci_free_domain(zdev);
-
-	spin_lock(&zpci_list_lock);
-	list_del(&zdev->entry);
-	spin_unlock(&zpci_list_lock);
-
-	zpci_dbg(3, "rem fid:%x\n", zdev->fid);
-	kfree(zdev);
+	if (zpci_unique_uid) {
+		if (domain)
+			return __zpci_register_domain(domain);
+		pr_warn("UID checking was active but no UID is provided: switching to automatic domain allocation\n");
+		update_uid_checking(false);
+	}
+	return __zpci_alloc_domain();
 }
 
-static int zpci_scan_bus(struct zpci_dev *zdev)
+void zpci_free_domain(int domain)
 {
-	LIST_HEAD(resources);
-	int ret;
-
-	ret = zpci_setup_bus_resources(zdev, &resources);
-	if (ret)
-		goto error;
-
-	zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
-				      zdev, &resources);
-	if (!zdev->bus) {
-		ret = -EIO;
-		goto error;
-	}
-	zdev->bus->max_bus_speed = zdev->max_bus_speed;
-	pci_bus_add_devices(zdev->bus);
-	return 0;
-
-error:
-	zpci_cleanup_bus_resources(zdev);
-	pci_free_resource_list(&resources);
-	return ret;
+	spin_lock(&zpci_domain_lock);
+	clear_bit(domain, zpci_domain);
+	spin_unlock(&zpci_domain_lock);
 }
 
+
 int zpci_enable_device(struct zpci_dev *zdev)
 {
 	int rc;
@@ -754,21 +715,68 @@
 int zpci_disable_device(struct zpci_dev *zdev)
 {
 	zpci_dma_exit_device(zdev);
+	/*
+	 * The zPCI function may already be disabled by the platform, this is
+	 * detected in clp_disable_fh() which becomes a no-op.
+	 */
 	return clp_disable_fh(zdev);
 }
 EXPORT_SYMBOL_GPL(zpci_disable_device);
 
+bool zpci_is_device_configured(struct zpci_dev *zdev)
+{
+	enum zpci_state state = zdev->state;
+
+	return state != ZPCI_FN_STATE_RESERVED &&
+		state != ZPCI_FN_STATE_STANDBY;
+}
+
+/* zpci_remove_device - Removes the given zdev from the PCI core
+ * @zdev: the zdev to be removed from the PCI core
+ * @set_error: if true the device's error state is set to permanent failure
+ *
+ * Sets a zPCI device to a configured but offline state; the zPCI
+ * device is still accessible through its hotplug slot and the zPCI
+ * API but is removed from the common code PCI bus, making it
+ * no longer available to drivers.
+ */
+void zpci_remove_device(struct zpci_dev *zdev, bool set_error)
+{
+	struct zpci_bus *zbus = zdev->zbus;
+	struct pci_dev *pdev;
+
+	if (!zdev->zbus->bus)
+		return;
+
+	pdev = pci_get_slot(zbus->bus, zdev->devfn);
+	if (pdev) {
+		if (set_error)
+			pdev->error_state = pci_channel_io_perm_failure;
+		if (pdev->is_virtfn) {
+			zpci_remove_virtfn(pdev, zdev->vfn);
+			/* balance pci_get_slot */
+			pci_dev_put(pdev);
+			return;
+		}
+		pci_stop_and_remove_bus_device_locked(pdev);
+		/* balance pci_get_slot */
+		pci_dev_put(pdev);
+	}
+}
+
 int zpci_create_device(struct zpci_dev *zdev)
 {
 	int rc;
 
-	rc = zpci_alloc_domain(zdev);
-	if (rc)
-		goto out;
+	kref_init(&zdev->kref);
+
+	spin_lock(&zpci_list_lock);
+	list_add_tail(&zdev->entry, &zpci_list);
+	spin_unlock(&zpci_list_lock);
 
 	rc = zpci_init_iommu(zdev);
 	if (rc)
-		goto out_free;
+		goto out;
 
 	mutex_init(&zdev->lock);
 	if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
@@ -776,36 +784,81 @@
 		if (rc)
 			goto out_destroy_iommu;
 	}
-	rc = zpci_scan_bus(zdev);
+
+	rc = zpci_bus_device_register(zdev, &pci_root_ops);
 	if (rc)
 		goto out_disable;
 
-	spin_lock(&zpci_list_lock);
-	list_add_tail(&zdev->entry, &zpci_list);
-	spin_unlock(&zpci_list_lock);
-
-	zpci_init_slot(zdev);
-
 	return 0;
 
 out_disable:
 	if (zdev->state == ZPCI_FN_STATE_ONLINE)
 		zpci_disable_device(zdev);
+
 out_destroy_iommu:
 	zpci_destroy_iommu(zdev);
-out_free:
-	zpci_free_domain(zdev);
 out:
+	spin_lock(&zpci_list_lock);
+	list_del(&zdev->entry);
+	spin_unlock(&zpci_list_lock);
 	return rc;
 }
 
-void zpci_remove_device(struct zpci_dev *zdev)
+/**
+ * zpci_device_reserved() - Mark device as resverved
+ * @zdev: the zpci_dev that was reserved
+ *
+ * Handle the case that a given zPCI function was reserved by another system.
+ * After a call to this function the zpci_dev can not be found via
+ * get_zdev_by_fid() anymore but may still be accessible via existing
+ * references though it will not be functional anymore.
+ */
+void zpci_device_reserved(struct zpci_dev *zdev)
+{
+	if (zdev->has_hp_slot)
+		zpci_exit_slot(zdev);
+	/*
+	 * Remove device from zpci_list as it is going away. This also
+	 * makes sure we ignore subsequent zPCI events for this device.
+	 */
+	spin_lock(&zpci_list_lock);
+	list_del(&zdev->entry);
+	spin_unlock(&zpci_list_lock);
+	zdev->state = ZPCI_FN_STATE_RESERVED;
+	zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
+	zpci_zdev_put(zdev);
+}
+
+void zpci_release_device(struct kref *kref)
 {
-	if (!zdev->bus)
-		return;
+	struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
 
-	pci_stop_root_bus(zdev->bus);
-	pci_remove_root_bus(zdev->bus);
+	if (zdev->zbus->bus)
+		zpci_remove_device(zdev, false);
+
+	switch (zdev->state) {
+	case ZPCI_FN_STATE_ONLINE:
+	case ZPCI_FN_STATE_CONFIGURED:
+		zpci_disable_device(zdev);
+		fallthrough;
+	case ZPCI_FN_STATE_STANDBY:
+		if (zdev->has_hp_slot)
+			zpci_exit_slot(zdev);
+		spin_lock(&zpci_list_lock);
+		list_del(&zdev->entry);
+		spin_unlock(&zpci_list_lock);
+		zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
+		fallthrough;
+	case ZPCI_FN_STATE_RESERVED:
+		zpci_cleanup_bus_resources(zdev);
+		zpci_bus_device_unregister(zdev);
+		zpci_destroy_iommu(zdev);
+		fallthrough;
+	default:
+		break;
+	}
+	zpci_dbg(3, "rem fid:%x\n", zdev->fid);
+	kfree(zdev);
 }
 
 int zpci_report_error(struct pci_dev *pdev,
@@ -854,7 +907,6 @@
 }
 
 static unsigned int s390_pci_probe __initdata = 1;
-static unsigned int s390_pci_no_mio __initdata;
 unsigned int s390_pci_force_floating __initdata;
 static unsigned int s390_pci_initialized;
 
@@ -865,13 +917,17 @@
 		return NULL;
 	}
 	if (!strcmp(str, "nomio")) {
-		s390_pci_no_mio = 1;
+		S390_lowcore.machine_flags &= ~MACHINE_FLAG_PCI_MIO;
 		return NULL;
 	}
 	if (!strcmp(str, "force_floating")) {
 		s390_pci_force_floating = 1;
 		return NULL;
 	}
+	if (!strcmp(str, "norid")) {
+		s390_pci_no_rid = 1;
+		return NULL;
+	}
 	return str;
 }
 
@@ -890,7 +946,7 @@
 	if (!test_facility(69) || !test_facility(71))
 		return 0;
 
-	if (test_facility(153) && !s390_pci_no_mio) {
+	if (MACHINE_HAS_PCI_MIO) {
 		static_branch_enable(&have_mio);
 		ctl_set_bit(2, 5);
 	}
@@ -934,5 +990,5 @@
 void zpci_rescan(void)
 {
 	if (zpci_is_enabled())
-		clp_rescan_pci_devices_simple();
+		clp_rescan_pci_devices_simple(NULL);
 }
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_bus.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_bus.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2020
+ *
+ * Author(s):
+ *   Pierre Morel <pmorel@linux.ibm.com>
+ *
+ */
+
+#define KMSG_COMPONENT "zpci"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/jump_label.h>
+#include <linux/pci.h>
+#include <linux/printk.h>
+
+#include <asm/pci_clp.h>
+#include <asm/pci_dma.h>
+
+#include "pci_bus.h"
+
+static LIST_HEAD(zbus_list);
+static DEFINE_SPINLOCK(zbus_list_lock);
+static int zpci_nb_devices;
+
+/* zpci_bus_scan
+ * @zbus: the zbus holding the zdevices
+ * @ops: the pci operations
+ *
+ * The domain number must be set before pci_scan_root_bus is called.
+ * This function can be called once the domain is known, hence
+ * when the function_0 is dicovered.
+ */
+static int zpci_bus_scan(struct zpci_bus *zbus, int domain, struct pci_ops *ops)
+{
+	struct pci_bus *bus;
+	int rc;
+
+	rc = zpci_alloc_domain(domain);
+	if (rc < 0)
+		return rc;
+	zbus->domain_nr = rc;
+
+	bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources);
+	if (!bus) {
+		zpci_free_domain(zbus->domain_nr);
+		return -EFAULT;
+	}
+
+	zbus->bus = bus;
+	pci_bus_add_devices(bus);
+	return 0;
+}
+
+static void zpci_bus_release(struct kref *kref)
+{
+	struct zpci_bus *zbus = container_of(kref, struct zpci_bus, kref);
+
+	if (zbus->bus) {
+		pci_lock_rescan_remove();
+		pci_stop_root_bus(zbus->bus);
+
+		zpci_free_domain(zbus->domain_nr);
+		pci_free_resource_list(&zbus->resources);
+
+		pci_remove_root_bus(zbus->bus);
+		pci_unlock_rescan_remove();
+	}
+
+	spin_lock(&zbus_list_lock);
+	list_del(&zbus->bus_next);
+	spin_unlock(&zbus_list_lock);
+	kfree(zbus);
+}
+
+static void zpci_bus_put(struct zpci_bus *zbus)
+{
+	kref_put(&zbus->kref, zpci_bus_release);
+}
+
+static struct zpci_bus *zpci_bus_get(int pchid)
+{
+	struct zpci_bus *zbus;
+
+	spin_lock(&zbus_list_lock);
+	list_for_each_entry(zbus, &zbus_list, bus_next) {
+		if (pchid == zbus->pchid) {
+			kref_get(&zbus->kref);
+			goto out_unlock;
+		}
+	}
+	zbus = NULL;
+out_unlock:
+	spin_unlock(&zbus_list_lock);
+	return zbus;
+}
+
+static struct zpci_bus *zpci_bus_alloc(int pchid)
+{
+	struct zpci_bus *zbus;
+
+	zbus = kzalloc(sizeof(*zbus), GFP_KERNEL);
+	if (!zbus)
+		return NULL;
+
+	zbus->pchid = pchid;
+	INIT_LIST_HEAD(&zbus->bus_next);
+	spin_lock(&zbus_list_lock);
+	list_add_tail(&zbus->bus_next, &zbus_list);
+	spin_unlock(&zbus_list_lock);
+
+	kref_init(&zbus->kref);
+	INIT_LIST_HEAD(&zbus->resources);
+
+	return zbus;
+}
+
+#ifdef CONFIG_PCI_IOV
+static int zpci_bus_link_virtfn(struct pci_dev *pdev,
+		struct pci_dev *virtfn, int vfid)
+{
+	int rc;
+
+	rc = pci_iov_sysfs_link(pdev, virtfn, vfid);
+	if (rc)
+		return rc;
+
+	virtfn->is_virtfn = 1;
+	virtfn->multifunction = 0;
+	virtfn->physfn = pci_dev_get(pdev);
+
+	return 0;
+}
+
+static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
+		struct pci_dev *virtfn, int vfn)
+{
+	int i, cand_devfn;
+	struct zpci_dev *zdev;
+	struct pci_dev *pdev;
+	int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
+	int rc = 0;
+
+	if (!zbus->multifunction)
+		return 0;
+
+	/* If the parent PF for the given VF is also configured in the
+	 * instance, it must be on the same zbus.
+	 * We can then identify the parent PF by checking what
+	 * devfn the VF would have if it belonged to that PF using the PF's
+	 * stride and offset. Only if this candidate devfn matches the
+	 * actual devfn will we link both functions.
+	 */
+	for (i = 0; i < ZPCI_FUNCTIONS_PER_BUS; i++) {
+		zdev = zbus->function[i];
+		if (zdev && zdev->is_physfn) {
+			pdev = pci_get_slot(zbus->bus, zdev->devfn);
+			if (!pdev)
+				continue;
+			cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
+			if (cand_devfn == virtfn->devfn) {
+				rc = zpci_bus_link_virtfn(pdev, virtfn, vfid);
+				/* balance pci_get_slot() */
+				pci_dev_put(pdev);
+				break;
+			}
+			/* balance pci_get_slot() */
+			pci_dev_put(pdev);
+		}
+	}
+	return rc;
+}
+#else
+static inline int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
+		struct pci_dev *virtfn, int vfn)
+{
+	return 0;
+}
+#endif
+
+void pcibios_bus_add_device(struct pci_dev *pdev)
+{
+	struct zpci_dev *zdev = to_zpci(pdev);
+
+	/*
+	 * With pdev->no_vf_scan the common PCI probing code does not
+	 * perform PF/VF linking.
+	 */
+	if (zdev->vfn) {
+		zpci_bus_setup_virtfn(zdev->zbus, pdev, zdev->vfn);
+		pdev->no_command_memory = 1;
+	}
+}
+
+static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
+{
+	struct pci_bus *bus;
+	struct resource_entry *window, *n;
+	struct resource *res;
+	struct pci_dev *pdev;
+	int rc;
+
+	bus = zbus->bus;
+	if (!bus)
+		return -EINVAL;
+
+	pdev = pci_get_slot(bus, zdev->devfn);
+	if (pdev) {
+		/* Device is already known. */
+		pci_dev_put(pdev);
+		return 0;
+	}
+
+	rc = zpci_init_slot(zdev);
+	if (rc)
+		return rc;
+	zdev->has_hp_slot = 1;
+
+	resource_list_for_each_entry_safe(window, n, &zbus->resources) {
+		res = window->res;
+		pci_bus_add_resource(bus, res, 0);
+	}
+
+	pdev = pci_scan_single_device(bus, zdev->devfn);
+	if (pdev)
+		pci_bus_add_device(pdev);
+
+	return 0;
+}
+
+static void zpci_bus_add_devices(struct zpci_bus *zbus)
+{
+	int i;
+
+	for (i = 1; i < ZPCI_FUNCTIONS_PER_BUS; i++)
+		if (zbus->function[i])
+			zpci_bus_add_device(zbus, zbus->function[i]);
+
+	pci_lock_rescan_remove();
+	pci_bus_add_devices(zbus->bus);
+	pci_unlock_rescan_remove();
+}
+
+int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
+{
+	struct zpci_bus *zbus = NULL;
+	int rc = -EBADF;
+
+	if (zpci_nb_devices == ZPCI_NR_DEVICES) {
+		pr_warn("Adding PCI function %08x failed because the configured limit of %d is reached\n",
+			zdev->fid, ZPCI_NR_DEVICES);
+		return -ENOSPC;
+	}
+	zpci_nb_devices++;
+
+	if (zdev->devfn >= ZPCI_FUNCTIONS_PER_BUS)
+		return -EINVAL;
+
+	if (!s390_pci_no_rid && zdev->rid_available)
+		zbus = zpci_bus_get(zdev->pchid);
+
+	if (!zbus) {
+		zbus = zpci_bus_alloc(zdev->pchid);
+		if (!zbus)
+			return -ENOMEM;
+	}
+
+	zdev->zbus = zbus;
+	if (zbus->function[zdev->devfn]) {
+		pr_err("devfn %04x is already assigned\n", zdev->devfn);
+		goto error; /* rc already set */
+	}
+	zbus->function[zdev->devfn] = zdev;
+
+	zpci_setup_bus_resources(zdev, &zbus->resources);
+
+	if (zbus->bus) {
+		if (!zbus->multifunction) {
+			WARN_ONCE(1, "zbus is not multifunction\n");
+			goto error_bus;
+		}
+		if (!zdev->rid_available) {
+			WARN_ONCE(1, "rid_available not set for multifunction\n");
+			goto error_bus;
+		}
+		rc = zpci_bus_add_device(zbus, zdev);
+		if (rc)
+			goto error_bus;
+	} else if (zdev->devfn == 0) {
+		if (zbus->multifunction && !zdev->rid_available) {
+			WARN_ONCE(1, "rid_available not set on function 0 for multifunction\n");
+			goto error_bus;
+		}
+		rc = zpci_bus_scan(zbus, (u16)zdev->uid, ops);
+		if (rc)
+			goto error_bus;
+		zpci_bus_add_devices(zbus);
+		rc = zpci_init_slot(zdev);
+		if (rc)
+			goto error_bus;
+		zdev->has_hp_slot = 1;
+		zbus->multifunction = zdev->rid_available;
+		zbus->max_bus_speed = zdev->max_bus_speed;
+	} else {
+		zbus->multifunction = 1;
+	}
+
+	return 0;
+
+error_bus:
+	zpci_nb_devices--;
+	zbus->function[zdev->devfn] = NULL;
+error:
+	pr_err("Adding PCI function %08x failed\n", zdev->fid);
+	zpci_bus_put(zbus);
+	return rc;
+}
+
+void zpci_bus_device_unregister(struct zpci_dev *zdev)
+{
+	struct zpci_bus *zbus = zdev->zbus;
+
+	zpci_nb_devices--;
+	zbus->function[zdev->devfn] = NULL;
+	zpci_bus_put(zbus);
+}
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_bus.h
+++ linux-ein-5.4.0/arch/s390/pci/pci_bus.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright IBM Corp. 2020
+ *
+ * Author(s):
+ *   Pierre Morel <pmorel@linux.ibm.com>
+ *
+ */
+
+int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops);
+void zpci_bus_device_unregister(struct zpci_dev *zdev);
+int zpci_bus_init(void);
+
+void zpci_release_device(struct kref *kref);
+static inline void zpci_zdev_put(struct zpci_dev *zdev)
+{
+	kref_put(&zdev->kref, zpci_release_device);
+}
+
+static inline void zpci_zdev_get(struct zpci_dev *zdev)
+{
+	kref_get(&zdev->kref);
+}
+
+int zpci_alloc_domain(int domain);
+void zpci_free_domain(int domain);
+int zpci_setup_bus_resources(struct zpci_dev *zdev,
+			     struct list_head *resources);
+
+static inline struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus,
+					       unsigned int devfn)
+{
+	struct zpci_bus *zbus = bus->sysdata;
+
+	return (devfn >= ZPCI_FUNCTIONS_PER_BUS) ? NULL : zbus->function[devfn];
+}
+
+#ifdef CONFIG_PCI_IOV
+static inline void zpci_remove_virtfn(struct pci_dev *pdev, int vfn)
+{
+
+	pci_lock_rescan_remove();
+	/* Linux' vfid's start at 0 vfn at 1 */
+	pci_iov_remove_virtfn(pdev->physfn, vfn - 1);
+	pci_unlock_rescan_remove();
+}
+#else /* CONFIG_PCI_IOV */
+static inline void zpci_remove_virtfn(struct pci_dev *pdev, int vfn) {}
+#endif /* CONFIG_PCI_IOV */
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_clp.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_clp.c
@@ -24,7 +24,7 @@
 
 bool zpci_unique_uid;
 
-static void update_uid_checking(bool new)
+void update_uid_checking(bool new)
 {
 	if (zpci_unique_uid != new)
 		zpci_dbg(1, "uid checking:%d\n", new);
@@ -155,8 +155,13 @@
 	zdev->pfgid = response->pfgid;
 	zdev->pft = response->pft;
 	zdev->vfn = response->vfn;
+	zdev->port = response->port;
 	zdev->uid = response->uid;
 	zdev->fmb_length = sizeof(u32) * response->fmb_len;
+	zdev->rid_available = response->rid_avail;
+	zdev->is_physfn = response->is_physfn;
+	if (!s390_pci_no_rid && zdev->rid_available)
+		zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
 
 	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
 	if (response->util_str_avail) {
@@ -240,12 +245,14 @@
 }
 
 /*
- * Enable/Disable a given PCI function defined by its function handle.
+ * Enable/Disable a given PCI function and update its function handle if
+ * necessary
  */
-static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
+static int clp_set_pci_fn(struct zpci_dev *zdev, u8 nr_dma_as, u8 command)
 {
 	struct clp_req_rsp_set_pci *rrb;
 	int rc, retries = 100;
+	u32 fid = zdev->fid;
 
 	rrb = clp_alloc_block(GFP_KERNEL);
 	if (!rrb)
@@ -256,7 +263,7 @@
 		rrb->request.hdr.len = sizeof(rrb->request);
 		rrb->request.hdr.cmd = CLP_SET_PCI_FN;
 		rrb->response.hdr.len = sizeof(rrb->response);
-		rrb->request.fh = *fh;
+		rrb->request.fh = zdev->fh;
 		rrb->request.oc = command;
 		rrb->request.ndas = nr_dma_as;
 
@@ -269,12 +276,17 @@
 		}
 	} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
 
-	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
-		*fh = rrb->response.fh;
-	else {
+	if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
 		zpci_err("Set PCI FN:\n");
 		zpci_err_clp(rrb->response.hdr.rsp, rc);
-		rc = -EIO;
+	}
+
+	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
+		zdev->fh = rrb->response.fh;
+	} else if (!rc && rrb->response.hdr.rsp == CLP_RC_SETPCIFN_ALRDY &&
+			rrb->response.fh == 0) {
+		/* Function is already in desired state - update handle */
+		rc = clp_rescan_pci_devices_simple(&fid);
 	}
 	clp_free_block(rrb);
 	return rc;
@@ -282,18 +294,17 @@
 
 int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
 {
-	u32 fh = zdev->fh;
 	int rc;
 
-	rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
-	zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
+	rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
+	zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
 	if (rc)
 		goto out;
 
-	zdev->fh = fh;
 	if (zpci_use_mio(zdev)) {
-		rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_MIO);
-		zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
+		rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_MIO);
+		zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
+				zdev->fid, zdev->fh, rc);
 		if (rc)
 			clp_disable_fh(zdev);
 	}
@@ -303,17 +314,13 @@
 
 int clp_disable_fh(struct zpci_dev *zdev)
 {
-	u32 fh = zdev->fh;
 	int rc;
 
 	if (!zdev_enabled(zdev))
 		return 0;
 
-	rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
-	zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
-	if (!rc)
-		zdev->fh = fh;
-
+	rc = clp_set_pci_fn(zdev, 0, CLP_SET_DISABLE_PCI_FN);
+	zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
 	return rc;
 }
 
@@ -370,10 +377,14 @@
 static void __clp_update(struct clp_fh_list_entry *entry, void *data)
 {
 	struct zpci_dev *zdev;
+	u32 *fid = data;
 
 	if (!entry->vendor_id)
 		return;
 
+	if (fid && *fid != entry->fid)
+		return;
+
 	zdev = get_zdev_by_fid(entry->fid);
 	if (!zdev)
 		return;
@@ -413,7 +424,10 @@
 	return rc;
 }
 
-int clp_rescan_pci_devices_simple(void)
+/* Rescan PCI functions and refresh function handles. If fid is non-NULL only
+ * refresh the handle of the function matching @fid
+ */
+int clp_rescan_pci_devices_simple(u32 *fid)
 {
 	struct clp_req_rsp_list_pci *rrb;
 	int rc;
@@ -422,7 +436,7 @@
 	if (!rrb)
 		return -ENOMEM;
 
-	rc = clp_list_pci(rrb, NULL, __clp_update);
+	rc = clp_list_pci(rrb, fid, __clp_update);
 
 	clp_free_block(rrb);
 	return rc;
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_dma.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_dma.c
@@ -543,6 +543,17 @@
 		s->dma_length = 0;
 	}
 }
+
+static unsigned long *bitmap_vzalloc(size_t bits, gfp_t flags)
+{
+	size_t n = BITS_TO_LONGS(bits);
+	size_t bytes;
+
+	if (unlikely(check_mul_overflow(n, sizeof(unsigned long), &bytes)))
+		return NULL;
+
+	return vzalloc(bytes);
+}
 	
 int zpci_dma_init_device(struct zpci_dev *zdev)
 {
@@ -579,13 +590,13 @@
 				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);
+	zdev->iommu_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
 	if (!zdev->iommu_bitmap) {
 		rc = -ENOMEM;
 		goto free_dma_table;
 	}
 	if (!s390_iommu_strict) {
-		zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8);
+		zdev->lazy_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
 		if (!zdev->lazy_bitmap) {
 			rc = -ENOMEM;
 			goto free_bitmap;
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_event.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_event.c
@@ -14,6 +14,8 @@
 #include <asm/pci_debug.h>
 #include <asm/sclp.h>
 
+#include "pci_bus.h"
+
 /* Content Code Description for PCI Function Error */
 struct zpci_ccdf_err {
 	u32 reserved1;
@@ -53,7 +55,7 @@
 	zpci_err_hex(ccdf, sizeof(*ccdf));
 
 	if (zdev)
-		pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
+		pdev = pci_get_slot(zdev->zbus->bus, zdev->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);
@@ -74,46 +76,52 @@
 static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 {
 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-	struct pci_dev *pdev = NULL;
 	enum zpci_state state;
+	struct pci_dev *pdev;
 	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");
 	zpci_err_hex(ccdf, sizeof(*ccdf));
 
 	switch (ccdf->pec) {
 	case 0x0301: /* Reserved|Standby -> Configured */
 		if (!zdev) {
-			ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
-			if (ret)
-				break;
-			zdev = get_zdev_by_fid(ccdf->fid);
+			ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 1);
+			break;
 		}
-		if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY)
+		/* the configuration request may be stale */
+		if (zdev->state != ZPCI_FN_STATE_STANDBY)
 			break;
-		zdev->state = ZPCI_FN_STATE_CONFIGURED;
 		zdev->fh = ccdf->fh;
+		zdev->state = ZPCI_FN_STATE_CONFIGURED;
 		ret = zpci_enable_device(zdev);
 		if (ret)
 			break;
+
+		/* the PCI function will be scanned once function 0 appears */
+		if (!zdev->zbus->bus)
+			break;
+
+		pdev = pci_scan_single_device(zdev->zbus->bus, zdev->devfn);
+		if (!pdev)
+			break;
+
+		pci_bus_add_device(pdev);
 		pci_lock_rescan_remove();
-		pci_rescan_bus(zdev->bus);
+		pci_bus_add_devices(zdev->zbus->bus);
 		pci_unlock_rescan_remove();
 		break;
 	case 0x0302: /* Reserved -> Standby */
-		if (!zdev)
+		if (!zdev) {
 			clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
+			break;
+		}
+		zdev->fh = ccdf->fh;
 		break;
 	case 0x0303: /* Deconfiguration requested */
 		if (!zdev)
 			break;
-		if (pdev)
-			pci_stop_and_remove_bus_device_locked(pdev);
+		zpci_remove_device(zdev, false);
 
 		ret = zpci_disable_device(zdev);
 		if (ret)
@@ -128,19 +136,17 @@
 	case 0x0304: /* Configured -> Standby|Reserved */
 		if (!zdev)
 			break;
-		if (pdev) {
-			/* Give the driver a hint that the function is
-			 * already unusable. */
-			pdev->error_state = pci_channel_io_perm_failure;
-			pci_stop_and_remove_bus_device_locked(pdev);
-		}
+		/* Give the driver a hint that the function is
+		 * already unusable.
+		 */
+		zpci_remove_device(zdev, true);
 
 		zdev->fh = ccdf->fh;
 		zpci_disable_device(zdev);
 		zdev->state = ZPCI_FN_STATE_STANDBY;
 		if (!clp_get_state(ccdf->fid, &state) &&
 		    state == ZPCI_FN_STATE_RESERVED) {
-			zpci_remove_device(zdev);
+			zpci_device_reserved(zdev);
 		}
 		break;
 	case 0x0306: /* 0x308 or 0x302 for multiple devices */
@@ -149,12 +155,11 @@
 	case 0x0308: /* Standby -> Reserved */
 		if (!zdev)
 			break;
-		zpci_remove_device(zdev);
+		zpci_device_reserved(zdev);
 		break;
 	default:
 		break;
 	}
-	pci_dev_put(pdev);
 }
 
 void zpci_event_availability(void *data)
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_irq.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_irq.c
@@ -115,7 +115,6 @@
 	.name = "PCI-MSI",
 	.irq_unmask = pci_msi_unmask_irq,
 	.irq_mask = pci_msi_mask_irq,
-	.irq_set_affinity = zpci_set_irq_affinity,
 };
 
 static void zpci_handle_cpu_local_irq(bool rescan)
@@ -276,7 +275,9 @@
 		rc = -EIO;
 		if (hwirq - bit >= msi_vecs)
 			break;
-		irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE, msi->affinity);
+		irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE,
+				(irq_delivery == DIRECTED) ?
+				msi->affinity : NULL);
 		if (irq < 0)
 			return -ENOMEM;
 		rc = irq_set_msi_desc(irq, msi);
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_mmio.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_mmio.c
@@ -11,6 +11,113 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
+#include <asm/pci_io.h>
+#include <asm/pci_debug.h>
+
+static inline void zpci_err_mmio(u8 cc, u8 status, u64 offset)
+{
+	struct {
+		u64 offset;
+		u8 cc;
+		u8 status;
+	} data = {offset, cc, status};
+
+	zpci_err_hex(&data, sizeof(data));
+}
+
+static inline int __pcistb_mio_inuser(
+		void __iomem *ioaddr, const void __user *src,
+		u64 len, u8 *status)
+{
+	int cc = -ENXIO;
+
+	asm volatile (
+		"       sacf 256\n"
+		"0:     .insn   rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n"
+		"1:     ipm     %[cc]\n"
+		"       srl     %[cc],28\n"
+		"2:     sacf 768\n"
+		EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
+		: [cc] "+d" (cc), [len] "+d" (len)
+		: [ioaddr] "a" (ioaddr), [src] "Q" (*((u8 __force *)src))
+		: "cc", "memory");
+	*status = len >> 24 & 0xff;
+	return cc;
+}
+
+static inline int __pcistg_mio_inuser(
+		void __iomem *ioaddr, const void __user *src,
+		u64 ulen, u8 *status)
+{
+	register u64 addr asm("2") = (u64 __force) ioaddr;
+	register u64 len asm("3") = ulen;
+	int cc = -ENXIO;
+	u64 val = 0;
+	u64 cnt = ulen;
+	u8 tmp;
+
+	/*
+	 * copy 0 < @len <= 8 bytes from @src into the right most bytes of
+	 * a register, then store it to PCI at @ioaddr while in secondary
+	 * address space. pcistg then uses the user mappings.
+	 */
+	asm volatile (
+		"       sacf    256\n"
+		"0:     llgc    %[tmp],0(%[src])\n"
+		"4:	sllg	%[val],%[val],8\n"
+		"       aghi    %[src],1\n"
+		"       ogr     %[val],%[tmp]\n"
+		"       brctg   %[cnt],0b\n"
+		"1:     .insn   rre,0xb9d40000,%[val],%[ioaddr]\n"
+		"2:     ipm     %[cc]\n"
+		"       srl     %[cc],28\n"
+		"3:     sacf    768\n"
+		EX_TABLE(0b, 3b) EX_TABLE(4b, 3b) EX_TABLE(1b, 3b) EX_TABLE(2b, 3b)
+		:
+		[src] "+a" (src), [cnt] "+d" (cnt),
+		[val] "+d" (val), [tmp] "=d" (tmp),
+		[len] "+d" (len), [cc] "+d" (cc),
+		[ioaddr] "+a" (addr)
+		:: "cc", "memory");
+	*status = len >> 24 & 0xff;
+
+	/* did we read everything from user memory? */
+	if (!cc && cnt != 0)
+		cc = -EFAULT;
+
+	return cc;
+}
+
+static inline int __memcpy_toio_inuser(void __iomem *dst,
+				   const void __user *src, size_t n)
+{
+	int size, rc = 0;
+	u8 status = 0;
+	mm_segment_t old_fs;
+
+	if (!src)
+		return -EINVAL;
+
+	old_fs = enable_sacf_uaccess();
+	while (n > 0) {
+		size = zpci_get_max_io_size((u64 __force) dst,
+					    (u64 __force) src, n,
+					    ZPCI_MAX_WRITE_SIZE);
+		if (size > 8) /* main path */
+			rc = __pcistb_mio_inuser(dst, src, size, &status);
+		else
+			rc = __pcistg_mio_inuser(dst, src, size, &status);
+		if (rc)
+			break;
+		src += size;
+		dst += size;
+		n -= size;
+	}
+	disable_sacf_uaccess(old_fs);
+	if (rc)
+		zpci_err_mmio(rc, status, (__force u64) dst);
+	return rc;
+}
 
 static long get_pfn(unsigned long user_addr, unsigned long access,
 		    unsigned long *pfn)
@@ -21,7 +128,7 @@
 	down_read(&current->mm->mmap_sem);
 	ret = -EINVAL;
 	vma = find_vma(current->mm, user_addr);
-	if (!vma)
+	if (!vma || user_addr < vma->vm_start)
 		goto out;
 	ret = -EACCES;
 	if (!(vma->vm_flags & access))
@@ -46,6 +153,20 @@
 
 	if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
 		return -EINVAL;
+
+	/*
+	 * Only support read access to MIO capable devices on a MIO enabled
+	 * system. Otherwise we would have to check for every address if it is
+	 * a special ZPCI_ADDR and we would have to do a get_pfn() which we
+	 * don't need for MIO capable devices.
+	 */
+	if (static_branch_likely(&have_mio)) {
+		ret = __memcpy_toio_inuser((void  __iomem *) mmio_addr,
+					user_buffer,
+					length);
+		return ret;
+	}
+
 	if (length > 64) {
 		buf = kmalloc(length, GFP_KERNEL);
 		if (!buf)
@@ -56,7 +177,8 @@
 	ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
 	if (ret)
 		goto out;
-	io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
+	io_addr = (void __iomem *)((pfn << PAGE_SHIFT) |
+			(mmio_addr & ~PAGE_MASK));
 
 	ret = -EFAULT;
 	if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
@@ -72,6 +194,78 @@
 	return ret;
 }
 
+static inline int __pcilg_mio_inuser(
+		void __user *dst, const void __iomem *ioaddr,
+		u64 ulen, u8 *status)
+{
+	register u64 addr asm("2") = (u64 __force) ioaddr;
+	register u64 len asm("3") = ulen;
+	u64 cnt = ulen;
+	int shift = ulen * 8;
+	int cc = -ENXIO;
+	u64 val, tmp;
+
+	/*
+	 * read 0 < @len <= 8 bytes from the PCI memory mapped at @ioaddr (in
+	 * user space) into a register using pcilg then store these bytes at
+	 * user address @dst
+	 */
+	asm volatile (
+		"       sacf    256\n"
+		"0:     .insn   rre,0xb9d60000,%[val],%[ioaddr]\n"
+		"1:     ipm     %[cc]\n"
+		"       srl     %[cc],28\n"
+		"       ltr     %[cc],%[cc]\n"
+		"       jne     4f\n"
+		"2:     ahi     %[shift],-8\n"
+		"       srlg    %[tmp],%[val],0(%[shift])\n"
+		"3:     stc     %[tmp],0(%[dst])\n"
+		"5:	aghi	%[dst],1\n"
+		"       brctg   %[cnt],2b\n"
+		"4:     sacf    768\n"
+		EX_TABLE(0b, 4b) EX_TABLE(1b, 4b) EX_TABLE(3b, 4b) EX_TABLE(5b, 4b)
+		:
+		[cc] "+d" (cc), [val] "=d" (val), [len] "+d" (len),
+		[dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp),
+		[shift] "+d" (shift)
+		:
+		[ioaddr] "a" (addr)
+		: "cc", "memory");
+
+	/* did we write everything to the user space buffer? */
+	if (!cc && cnt != 0)
+		cc = -EFAULT;
+
+	*status = len >> 24 & 0xff;
+	return cc;
+}
+
+static inline int __memcpy_fromio_inuser(void __user *dst,
+				     const void __iomem *src,
+				     unsigned long n)
+{
+	int size, rc = 0;
+	u8 status;
+	mm_segment_t old_fs;
+
+	old_fs = enable_sacf_uaccess();
+	while (n > 0) {
+		size = zpci_get_max_io_size((u64 __force) src,
+					    (u64 __force) dst, n,
+					    ZPCI_MAX_READ_SIZE);
+		rc = __pcilg_mio_inuser(dst, src, size, &status);
+		if (rc)
+			break;
+		src += size;
+		dst += size;
+		n -= size;
+	}
+	disable_sacf_uaccess(old_fs);
+	if (rc)
+		zpci_err_mmio(rc, status, (__force u64) dst);
+	return rc;
+}
+
 SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
 		void __user *, user_buffer, size_t, length)
 {
@@ -86,12 +280,27 @@
 
 	if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
 		return -EINVAL;
+
+	/*
+	 * Only support write access to MIO capable devices on a MIO enabled
+	 * system. Otherwise we would have to check for every address if it is
+	 * a special ZPCI_ADDR and we would have to do a get_pfn() which we
+	 * don't need for MIO capable devices.
+	 */
+	if (static_branch_likely(&have_mio)) {
+		ret = __memcpy_fromio_inuser(
+				user_buffer, (const void __iomem *)mmio_addr,
+				length);
+		return ret;
+	}
+
 	if (length > 64) {
 		buf = kmalloc(length, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
-	} else
+	} else {
 		buf = local_buf;
+	}
 
 	ret = get_pfn(mmio_addr, VM_READ, &pfn);
 	if (ret)
--- linux-ein-5.4.0.orig/arch/s390/pci/pci_sysfs.c
+++ linux-ein-5.4.0/arch/s390/pci/pci_sysfs.c
@@ -13,6 +13,8 @@
 #include <linux/stat.h>
 #include <linux/pci.h>
 
+#include "../../../drivers/pci/pci.h"
+
 #include <asm/sclp.h>
 
 #define zpci_attr(name, fmt, member)					\
@@ -31,6 +33,7 @@
 zpci_attr(pfgid, "0x%02x\n", pfgid);
 zpci_attr(vfn, "0x%04x\n", vfn);
 zpci_attr(pft, "0x%02x\n", pft);
+zpci_attr(port, "%d\n", port);
 zpci_attr(uid, "0x%x\n", uid);
 zpci_attr(segment0, "0x%02x\n", pfip[0]);
 zpci_attr(segment1, "0x%02x\n", pfip[1]);
@@ -49,31 +52,50 @@
 static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
 			     const char *buf, size_t count)
 {
+	struct kernfs_node *kn;
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct zpci_dev *zdev = to_zpci(pdev);
-	int ret;
-
-	if (!device_remove_file_self(dev, attr))
-		return count;
+	int ret = 0;
 
+	/* Can't use device_remove_self() here as that would lead us to lock
+	 * the pci_rescan_remove_lock while holding the device' kernfs lock.
+	 * This would create a possible deadlock with disable_slot() which is
+	 * not directly protected by the device' kernfs lock but takes it
+	 * during the device removal which happens under
+	 * pci_rescan_remove_lock.
+	 *
+	 * This is analogous to sdev_store_delete() in
+	 * drivers/scsi/scsi_sysfs.c
+	 */
+	kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
+	WARN_ON_ONCE(!kn);
+	/* device_remove_file() serializes concurrent calls ignoring all but
+	 * the first
+	 */
+	device_remove_file(dev, attr);
+
+	/* A concurrent call to recover_store() may slip between
+	 * sysfs_break_active_protection() and the sysfs file removal.
+	 * Once it unblocks from pci_lock_rescan_remove() the original pdev
+	 * will already be removed.
+	 */
 	pci_lock_rescan_remove();
-	pci_stop_and_remove_bus_device(pdev);
-	ret = zpci_disable_device(zdev);
-	if (ret)
-		goto error;
-
-	ret = zpci_enable_device(zdev);
-	if (ret)
-		goto error;
-
-	pci_rescan_bus(zdev->bus);
+	if (pci_dev_is_added(pdev)) {
+		pci_stop_and_remove_bus_device(pdev);
+		ret = zpci_disable_device(zdev);
+		if (ret)
+			goto out;
+
+		ret = zpci_enable_device(zdev);
+		if (ret)
+			goto out;
+		pci_rescan_bus(zdev->zbus->bus);
+	}
+out:
 	pci_unlock_rescan_remove();
-
-	return count;
-
-error:
-	pci_unlock_rescan_remove();
-	return ret;
+	if (kn)
+		sysfs_unbreak_active_protection(kn);
+	return ret ? ret : count;
 }
 static DEVICE_ATTR_WO(recover);
 
@@ -121,6 +143,7 @@
 	&dev_attr_pchid.attr,
 	&dev_attr_pfgid.attr,
 	&dev_attr_pft.attr,
+	&dev_attr_port.attr,
 	&dev_attr_vfn.attr,
 	&dev_attr_uid.attr,
 	&dev_attr_recover.attr,
--- linux-ein-5.4.0.orig/arch/s390/purgatory/Makefile
+++ linux-ein-5.4.0/arch/s390/purgatory/Makefile
@@ -15,8 +15,10 @@
 $(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S FORCE
 	$(call if_changed_rule,as_o_S)
 
-$(obj)/string.o: $(srctree)/arch/s390/lib/string.c FORCE
-	$(call if_changed_rule,cc_o_c)
+KCOV_INSTRUMENT := n
+GCOV_PROFILE := n
+UBSAN_SANITIZE := n
+KASAN_SANITIZE := n
 
 KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes
 KBUILD_CFLAGS += -Wno-pointer-sign -Wno-sign-compare
--- linux-ein-5.4.0.orig/arch/s390/purgatory/head.S
+++ linux-ein-5.4.0/arch/s390/purgatory/head.S
@@ -62,14 +62,15 @@
 	jh	10b
 .endm
 
-.macro START_NEXT_KERNEL base
+.macro START_NEXT_KERNEL base subcode
 	lg	%r4,kernel_entry-\base(%r13)
 	lg	%r5,load_psw_mask-\base(%r13)
 	ogr	%r4,%r5
 	stg	%r4,0(%r0)
 
 	xgr	%r0,%r0
-	diag	%r0,%r0,0x308
+	lghi	%r1,\subcode
+	diag	%r0,%r1,0x308
 .endm
 
 .text
@@ -123,7 +124,7 @@
 	je	.start_crash_kernel
 
 	/* start normal kernel */
-	START_NEXT_KERNEL .base_crash
+	START_NEXT_KERNEL .base_crash 0
 
 .return_old_kernel:
 	lmg	%r6,%r15,gprregs-.base_crash(%r13)
@@ -227,7 +228,7 @@
 	MEMCPY	%r9,%r10,%r11
 
 	/* start crash kernel */
-	START_NEXT_KERNEL .base_dst
+	START_NEXT_KERNEL .base_dst 1
 
 
 load_psw_mask:
--- linux-ein-5.4.0.orig/arch/s390/purgatory/string.c
+++ linux-ein-5.4.0/arch/s390/purgatory/string.c
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+#define __HAVE_ARCH_MEMCMP	/* arch function */
+#include "../lib/string.c"
--- linux-ein-5.4.0.orig/arch/sh/Kconfig
+++ linux-ein-5.4.0/arch/sh/Kconfig
@@ -2,6 +2,7 @@
 config SUPERH
 	def_bool y
 	select ARCH_HAS_BINFMT_FLAT if !MMU
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_PTE_SPECIAL
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_MIGHT_HAVE_PC_PARPORT
--- linux-ein-5.4.0.orig/arch/sh/Kconfig.debug
+++ linux-ein-5.4.0/arch/sh/Kconfig.debug
@@ -26,6 +26,17 @@
 	  every function call and will therefore incur a major
 	  performance hit. Most users should say N.
 
+config EARLY_PRINTK
+	bool "Early printk"
+	depends on SH_STANDARD_BIOS
+	help
+	  Say Y here to redirect kernel printk messages to the serial port
+	  used by the SH-IPL bootloader, starting very early in the boot
+	  process and ending when the kernel's serial console is initialised.
+	  This option is only useful while porting the kernel to a new machine,
+	  when the kernel may crash or hang before the serial console is
+	  initialised.  If unsure, say N.
+
 config 4KSTACKS
 	bool "Use 4Kb for kernel stacks instead of 8Kb"
 	depends on DEBUG_KERNEL && (MMU || BROKEN) && !PAGE_SIZE_64KB
@@ -58,6 +69,7 @@
 
 config DWARF_UNWINDER
 	bool "Enable the DWARF unwinder for stacktraces"
+	depends on DEBUG_KERNEL
 	select FRAME_POINTER
 	depends on SUPERH32
 	default n
--- linux-ein-5.4.0.orig/arch/sh/boards/mach-ap325rxa/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-ap325rxa/setup.c
@@ -529,7 +529,7 @@
 	device_initialize(&ap325rxa_ceu_device.dev);
 	dma_declare_coherent_memory(&ap325rxa_ceu_device.dev,
 			ceu_dma_membase, ceu_dma_membase,
-			ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1);
+			CEU_BUFFER_MEMORY_SIZE);
 
 	platform_device_add(&ap325rxa_ceu_device);
 
--- linux-ein-5.4.0.orig/arch/sh/boards/mach-ecovec24/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-ecovec24/setup.c
@@ -1442,15 +1442,13 @@
 	device_initialize(&ecovec_ceu_devices[0]->dev);
 	dma_declare_coherent_memory(&ecovec_ceu_devices[0]->dev,
 				    ceu0_dma_membase, ceu0_dma_membase,
-				    ceu0_dma_membase +
-				    CEU_BUFFER_MEMORY_SIZE - 1);
+				    CEU_BUFFER_MEMORY_SIZE);
 	platform_device_add(ecovec_ceu_devices[0]);
 
 	device_initialize(&ecovec_ceu_devices[1]->dev);
 	dma_declare_coherent_memory(&ecovec_ceu_devices[1]->dev,
 				    ceu1_dma_membase, ceu1_dma_membase,
-				    ceu1_dma_membase +
-				    CEU_BUFFER_MEMORY_SIZE - 1);
+				    CEU_BUFFER_MEMORY_SIZE);
 	platform_device_add(ecovec_ceu_devices[1]);
 
 	gpiod_add_lookup_table(&cn12_power_gpiod_table);
--- linux-ein-5.4.0.orig/arch/sh/boards/mach-kfr2r09/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-kfr2r09/setup.c
@@ -603,7 +603,7 @@
 	device_initialize(&kfr2r09_ceu_device.dev);
 	dma_declare_coherent_memory(&kfr2r09_ceu_device.dev,
 			ceu_dma_membase, ceu_dma_membase,
-			ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1);
+			CEU_BUFFER_MEMORY_SIZE);
 
 	platform_device_add(&kfr2r09_ceu_device);
 
--- linux-ein-5.4.0.orig/arch/sh/boards/mach-landisk/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-landisk/setup.c
@@ -82,6 +82,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-ein-5.4.0.orig/arch/sh/boards/mach-migor/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-migor/setup.c
@@ -604,7 +604,7 @@
 	device_initialize(&migor_ceu_device.dev);
 	dma_declare_coherent_memory(&migor_ceu_device.dev,
 			ceu_dma_membase, ceu_dma_membase,
-			ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1);
+			CEU_BUFFER_MEMORY_SIZE);
 
 	platform_device_add(&migor_ceu_device);
 
--- linux-ein-5.4.0.orig/arch/sh/boards/mach-se/7724/setup.c
+++ linux-ein-5.4.0/arch/sh/boards/mach-se/7724/setup.c
@@ -939,15 +939,13 @@
 	device_initialize(&ms7724se_ceu_devices[0]->dev);
 	dma_declare_coherent_memory(&ms7724se_ceu_devices[0]->dev,
 				    ceu0_dma_membase, ceu0_dma_membase,
-				    ceu0_dma_membase +
-				    CEU_BUFFER_MEMORY_SIZE - 1);
+				    CEU_BUFFER_MEMORY_SIZE);
 	platform_device_add(ms7724se_ceu_devices[0]);
 
 	device_initialize(&ms7724se_ceu_devices[1]->dev);
 	dma_declare_coherent_memory(&ms7724se_ceu_devices[1]->dev,
 				    ceu1_dma_membase, ceu1_dma_membase,
-				    ceu1_dma_membase +
-				    CEU_BUFFER_MEMORY_SIZE - 1);
+				    CEU_BUFFER_MEMORY_SIZE);
 	platform_device_add(ms7724se_ceu_devices[1]);
 
 	return platform_add_devices(ms7724se_devices,
--- linux-ein-5.4.0.orig/arch/sh/configs/sh03_defconfig
+++ linux-ein-5.4.0/arch/sh/configs/sh03_defconfig
@@ -46,7 +46,6 @@
 CONFIG_SCSI=m
 CONFIG_BLK_DEV_SD=m
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
--- linux-ein-5.4.0.orig/arch/sh/drivers/dma/Kconfig
+++ linux-ein-5.4.0/arch/sh/drivers/dma/Kconfig
@@ -63,8 +63,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-ein-5.4.0.orig/arch/sh/drivers/dma/dma-sh.c
+++ linux-ein-5.4.0/arch/sh/drivers/dma/dma-sh.c
@@ -19,6 +19,18 @@
 #include <cpu/dma.h>
 
 /*
+ * Some of the SoCs feature two DMAC modules. In such a case, the channels are
+ * distributed equally among them.
+ */
+#ifdef	SH_DMAC_BASE1
+#define	SH_DMAC_NR_MD_CH	(CONFIG_NR_ONCHIP_DMA_CHANNELS / 2)
+#else
+#define	SH_DMAC_NR_MD_CH	CONFIG_NR_ONCHIP_DMA_CHANNELS
+#endif
+
+#define	SH_DMAC_CH_SZ		0x10
+
+/*
  * Define the default configuration for dual address memory-memory transfer.
  * The 0x400 value represents auto-request, external->external.
  */
@@ -29,7 +41,7 @@
 	unsigned long base = SH_DMAC_BASE0;
 
 #ifdef SH_DMAC_BASE1
-	if (chan >= 6)
+	if (chan >= SH_DMAC_NR_MD_CH)
 		base = SH_DMAC_BASE1;
 #endif
 
@@ -40,13 +52,13 @@
 {
 	unsigned long base = dma_find_base(chan);
 
-	/* Normalize offset calculation */
-	if (chan >= 9)
-		chan -= 6;
-	if (chan >= 4)
-		base += 0x10;
+	chan = (chan % SH_DMAC_NR_MD_CH) * SH_DMAC_CH_SZ;
+
+	/* DMAOR is placed inside the channel register space. Step over it. */
+	if (chan >= DMAOR)
+		base += SH_DMAC_CH_SZ;
 
-	return base + (chan * 0x10);
+	return base + chan;
 }
 
 #ifdef CONFIG_SH_DMA_IRQ_MULTI
@@ -250,12 +262,11 @@
 #define NR_DMAOR	1
 #endif
 
-/*
- * DMAOR bases are broken out amongst channel groups. DMAOR0 manages
- * channels 0 - 5, DMAOR1 6 - 11 (optional).
- */
-#define dmaor_read_reg(n)		__raw_readw(dma_find_base((n)*6))
-#define dmaor_write_reg(n, data)	__raw_writew(data, dma_find_base(n)*6)
+#define dmaor_read_reg(n)		__raw_readw(dma_find_base((n) * \
+						    SH_DMAC_NR_MD_CH) + DMAOR)
+#define dmaor_write_reg(n, data)	__raw_writew(data, \
+						     dma_find_base((n) * \
+						     SH_DMAC_NR_MD_CH) + DMAOR)
 
 static inline int dmaor_reset(int no)
 {
--- linux-ein-5.4.0.orig/arch/sh/include/asm/pgalloc.h
+++ linux-ein-5.4.0/arch/sh/include/asm/pgalloc.h
@@ -12,6 +12,7 @@
 extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
 extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
 extern void pmd_free(struct mm_struct *mm, pmd_t *pmd);
+#define __pmd_free_tlb(tlb, pmdp, addr)		pmd_free((tlb)->mm, (pmdp))
 #endif
 
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
@@ -33,13 +34,4 @@
 	tlb_remove_page((tlb), (pte));			\
 } while (0)
 
-#if CONFIG_PGTABLE_LEVELS > 2
-#define __pmd_free_tlb(tlb, pmdp, addr)			\
-do {							\
-	struct page *page = virt_to_page(pmdp);		\
-	pgtable_pmd_page_dtor(page);			\
-	tlb_remove_page((tlb), page);			\
-} while (0);
-#endif
-
 #endif /* __ASM_SH_PGALLOC_H */
--- linux-ein-5.4.0.orig/arch/sh/include/asm/processor.h
+++ linux-ein-5.4.0/arch/sh/include/asm/processor.h
@@ -173,6 +173,8 @@
 #define instruction_size(insn)	(4)
 #endif
 
+void select_idle_routine(void);
+
 #endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_SUPERH32
--- linux-ein-5.4.0.orig/arch/sh/include/asm/processor_32.h
+++ linux-ein-5.4.0/arch/sh/include/asm/processor_32.h
@@ -51,6 +51,7 @@
 #define SR_FD		0x00008000
 #define SR_MD		0x40000000
 
+#define SR_USER_MASK	0x00000303	// M, Q, S, T bits
 /*
  * DSP structure and data
  */
--- linux-ein-5.4.0.orig/arch/sh/include/asm/sections.h
+++ linux-ein-5.4.0/arch/sh/include/asm/sections.h
@@ -4,7 +4,7 @@
 
 #include <asm-generic/sections.h>
 
-extern long __machvec_start, __machvec_end;
+extern char __machvec_start[], __machvec_end[];
 extern char __uncached_start, __uncached_end;
 extern char __start_eh_frame[], __stop_eh_frame[];
 
--- linux-ein-5.4.0.orig/arch/sh/include/asm/sfp-machine.h
+++ linux-ein-5.4.0/arch/sh/include/asm/sfp-machine.h
@@ -13,6 +13,14 @@
 #ifndef _SFP_MACHINE_H
 #define _SFP_MACHINE_H
 
+#ifdef __BIG_ENDIAN__
+#define __BYTE_ORDER __BIG_ENDIAN
+#define __LITTLE_ENDIAN 0
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define __BIG_ENDIAN 0
+#endif
+
 #define _FP_W_TYPE_SIZE		32
 #define _FP_W_TYPE		unsigned long
 #define _FP_WS_TYPE		signed long
--- linux-ein-5.4.0.orig/arch/sh/include/cpu-sh2a/cpu/sh7269.h
+++ linux-ein-5.4.0/arch/sh/include/cpu-sh2a/cpu/sh7269.h
@@ -78,8 +78,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-ein-5.4.0.orig/arch/sh/include/cpu-sh4/cpu/sh7734.h
+++ linux-ein-5.4.0/arch/sh/include/cpu-sh4/cpu/sh7734.h
@@ -134,7 +134,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-ein-5.4.0.orig/arch/sh/kernel/cpu/fpu.c
+++ linux-ein-5.4.0/arch/sh/kernel/cpu/fpu.c
@@ -62,18 +62,20 @@
 	}
 
 	if (!tsk_used_math(tsk)) {
-		local_irq_enable();
+		int ret;
 		/*
 		 * does a slab alloc which can sleep
 		 */
-		if (init_fpu(tsk)) {
+		local_irq_enable();
+		ret = init_fpu(tsk);
+		local_irq_disable();
+		if (ret) {
 			/*
 			 * ran out of memory!
 			 */
-			do_group_exit(SIGKILL);
+			force_sig(SIGKILL);
 			return;
 		}
-		local_irq_disable();
 	}
 
 	grab_fpu(regs);
--- linux-ein-5.4.0.orig/arch/sh/kernel/cpu/sh2/probe.c
+++ linux-ein-5.4.0/arch/sh/kernel/cpu/sh2/probe.c
@@ -21,7 +21,7 @@
 	if (!of_flat_dt_is_compatible(node, "jcore,cache"))
 		return 0;
 
-	j2_ccr_base = (u32 __iomem *)of_flat_dt_translate_address(node);
+	j2_ccr_base = ioremap(of_flat_dt_translate_address(node), 4);
 
 	return 1;
 }
--- linux-ein-5.4.0.orig/arch/sh/kernel/cpu/sh4/sq.c
+++ linux-ein-5.4.0/arch/sh/kernel/cpu/sh4/sq.c
@@ -380,7 +380,7 @@
 	if (unlikely(!sq_cache))
 		return ret;
 
-	sq_bitmap = kzalloc(size, GFP_KERNEL);
+	sq_bitmap = kcalloc(size, sizeof(long), GFP_KERNEL);
 	if (unlikely(!sq_bitmap))
 		goto out;
 
--- linux-ein-5.4.0.orig/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ linux-ein-5.4.0/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -73,8 +73,9 @@
 	BUILD_BUG_ON(SMP_MSG_NR >= 8);
 
 	for (i = 0; i < SMP_MSG_NR; i++)
-		request_irq(104 + i, ipi_interrupt_handler,
-			    IRQF_PERCPU, "IPI", (void *)(long)i);
+		if (request_irq(104 + i, ipi_interrupt_handler,
+			    IRQF_PERCPU, "IPI", (void *)(long)i))
+			pr_err("Failed to request irq %d\n", i);
 
 	for (i = 0; i < max_cpus; i++)
 		set_cpu_present(i, true);
--- linux-ein-5.4.0.orig/arch/sh/kernel/dma-coherent.c
+++ linux-ein-5.4.0/arch/sh/kernel/dma-coherent.c
@@ -25,7 +25,7 @@
 	 * Pages from the page allocator may have data present in
 	 * cache. So flush the cache before using uncached memory.
 	 */
-	arch_sync_dma_for_device(dev, virt_to_phys(ret), size,
+	arch_sync_dma_for_device(virt_to_phys(ret), size,
 			DMA_BIDIRECTIONAL);
 
 	ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size);
@@ -59,8 +59,8 @@
 	iounmap(vaddr);
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	void *addr = sh_cacheop_vaddr(phys_to_virt(paddr));
 
--- linux-ein-5.4.0.orig/arch/sh/kernel/entry-common.S
+++ linux-ein-5.4.0/arch/sh/kernel/entry-common.S
@@ -199,7 +199,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
@@ -353,7 +353,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
 	!
@@ -392,7 +392,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-ein-5.4.0.orig/arch/sh/kernel/head_32.S
+++ linux-ein-5.4.0/arch/sh/kernel/head_32.S
@@ -64,7 +64,7 @@
 	ldc	r0, r6_bank
 #endif
 
-#ifdef CONFIG_OF_FLATTREE
+#ifdef CONFIG_OF_EARLY_FLATTREE
 	mov	r4, r12		! Store device tree blob pointer in r12
 #endif
 	
@@ -315,7 +315,7 @@
 10:		
 #endif
 
-#ifdef CONFIG_OF_FLATTREE
+#ifdef CONFIG_OF_EARLY_FLATTREE
 	mov.l	8f, r0		! Make flat device tree available early.
 	jsr	@r0
 	 mov	r12, r4
@@ -346,7 +346,7 @@
 5:	.long	start_kernel
 6:	.long	cpu_init
 7:	.long	init_thread_union
-#if defined(CONFIG_OF_FLATTREE)
+#if defined(CONFIG_OF_EARLY_FLATTREE)
 8:	.long	sh_fdt_init
 #endif
 
--- linux-ein-5.4.0.orig/arch/sh/kernel/idle.c
+++ linux-ein-5.4.0/arch/sh/kernel/idle.c
@@ -15,6 +15,7 @@
 #include <linux/smp.h>
 #include <linux/atomic.h>
 #include <asm/pgalloc.h>
+#include <asm/processor.h>
 #include <asm/smp.h>
 #include <asm/bl_bit.h>
 
--- linux-ein-5.4.0.orig/arch/sh/kernel/machvec.c
+++ linux-ein-5.4.0/arch/sh/kernel/machvec.c
@@ -19,8 +19,8 @@
 #define MV_NAME_SIZE 32
 
 #define for_each_mv(mv) \
-	for ((mv) = (struct sh_machine_vector *)&__machvec_start; \
-	     (mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \
+	for ((mv) = (struct sh_machine_vector *)__machvec_start; \
+	     (mv) && (unsigned long)(mv) < (unsigned long)__machvec_end; \
 	     (mv)++)
 
 static struct sh_machine_vector * __init get_mv_byname(const char *name)
@@ -86,8 +86,8 @@
 	if (!machvec_selected) {
 		unsigned long machvec_size;
 
-		machvec_size = ((unsigned long)&__machvec_end -
-				(unsigned long)&__machvec_start);
+		machvec_size = ((unsigned long)__machvec_end -
+				(unsigned long)__machvec_start);
 
 		/*
 		 * Sanity check for machvec section alignment. Ensure
@@ -101,7 +101,7 @@
 		 * vector (usually the only one) from .machvec.init.
 		 */
 		if (machvec_size >= sizeof(struct sh_machine_vector))
-			sh_mv = *(struct sh_machine_vector *)&__machvec_start;
+			sh_mv = *(struct sh_machine_vector *)__machvec_start;
 	}
 
 	printk(KERN_NOTICE "Booting machvec: %s\n", get_system_type());
--- linux-ein-5.4.0.orig/arch/sh/kernel/nmi_debug.c
+++ linux-ein-5.4.0/arch/sh/kernel/nmi_debug.c
@@ -49,7 +49,7 @@
 	register_die_notifier(&nmi_debug_nb);
 
 	if (*str != '=')
-		return 0;
+		return 1;
 
 	for (p = str + 1; *p; p = sep + 1) {
 		sep = strchr(p, ',');
@@ -70,6 +70,6 @@
 			break;
 	}
 
-	return 0;
+	return 1;
 }
 __setup("nmi_debug", nmi_debug_setup);
--- linux-ein-5.4.0.orig/arch/sh/kernel/setup.c
+++ linux-ein-5.4.0/arch/sh/kernel/setup.c
@@ -43,6 +43,7 @@
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
 #include <asm/mmzone.h>
+#include <asm/processor.h>
 #include <asm/sparsemem.h>
 
 /*
@@ -243,7 +244,7 @@
 {
 }
 
-#ifdef CONFIG_OF_FLATTREE
+#ifdef CONFIG_OF_EARLY_FLATTREE
 void __ref sh_fdt_init(phys_addr_t dt_phys)
 {
 	static int done = 0;
@@ -330,7 +331,7 @@
 	/* Let earlyprintk output early console messages */
 	early_platform_driver_probe("earlyprintk", 1, 1);
 
-#ifdef CONFIG_OF_FLATTREE
+#ifdef CONFIG_OF_EARLY_FLATTREE
 #ifdef CONFIG_USE_BUILTIN_DTB
 	unflatten_and_copy_device_tree();
 #else
@@ -362,3 +363,57 @@
 {
 	return sh_mv.mv_mode_pins() & pin;
 }
+
+void __init arch_cpu_finalize_init(void)
+{
+	char *p = &init_utsname()->machine[2]; /* "sh" */
+
+	select_idle_routine();
+
+	current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+
+	switch (current_cpu_data.family) {
+	case CPU_FAMILY_SH2:
+		*p++ = '2';
+		break;
+	case CPU_FAMILY_SH2A:
+		*p++ = '2';
+		*p++ = 'a';
+		break;
+	case CPU_FAMILY_SH3:
+		*p++ = '3';
+		break;
+	case CPU_FAMILY_SH4:
+		*p++ = '4';
+		break;
+	case CPU_FAMILY_SH4A:
+		*p++ = '4';
+		*p++ = 'a';
+		break;
+	case CPU_FAMILY_SH4AL_DSP:
+		*p++ = '4';
+		*p++ = 'a';
+		*p++ = 'l';
+		*p++ = '-';
+		*p++ = 'd';
+		*p++ = 's';
+		*p++ = 'p';
+		break;
+	case CPU_FAMILY_UNKNOWN:
+		/*
+		 * Specifically use CPU_FAMILY_UNKNOWN rather than
+		 * default:, so we're able to have the compiler whine
+		 * about unhandled enumerations.
+		 */
+		break;
+	}
+
+	pr_info("CPU: %s\n", get_cpu_subtype(&current_cpu_data));
+
+#ifndef __LITTLE_ENDIAN__
+	/* 'eb' means 'Endian Big' */
+	*p++ = 'e';
+	*p++ = 'b';
+#endif
+	*p = '\0';
+}
--- linux-ein-5.4.0.orig/arch/sh/kernel/signal_32.c
+++ linux-ein-5.4.0/arch/sh/kernel/signal_32.c
@@ -116,6 +116,7 @@
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p)
 {
 	unsigned int err = 0;
+	unsigned int sr = regs->sr & ~SR_USER_MASK;
 
 #define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
 			COPY(regs[1]);
@@ -131,6 +132,8 @@
 	COPY(sr);	COPY(pc);
 #undef COPY
 
+	regs->sr = (regs->sr & SR_USER_MASK) | sr;
+
 #ifdef CONFIG_SH_FPU
 	if (boot_cpu_data.flags & CPU_HAS_FPU) {
 		int owned_fp;
--- linux-ein-5.4.0.orig/arch/sh/kernel/traps.c
+++ linux-ein-5.4.0/arch/sh/kernel/traps.c
@@ -57,7 +57,7 @@
 	if (panic_on_oops)
 		panic("Fatal exception");
 
-	do_exit(SIGSEGV);
+	make_task_dead(SIGSEGV);
 }
 
 void die_if_kernel(const char *str, struct pt_regs *regs, long err)
--- linux-ein-5.4.0.orig/arch/sh/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/sh/kernel/vmlinux.lds.S
@@ -10,6 +10,7 @@
 #define LOAD_OFFSET	0
 OUTPUT_ARCH(sh)
 #endif
+#define RUNTIME_DISCARD_EXIT
 
 #include <asm/thread_info.h>
 #include <asm/cache.h>
--- linux-ein-5.4.0.orig/arch/sh/math-emu/math.c
+++ linux-ein-5.4.0/arch/sh/math-emu/math.c
@@ -468,109 +468,6 @@
 }
 
 /**
- *	denormal_to_double - Given denormalized float number,
- *	                     store double float
- *
- *	@fpu: Pointer to sh_fpu_soft structure
- *	@n: Index to FP register
- */
-static void denormal_to_double(struct sh_fpu_soft_struct *fpu, int n)
-{
-	unsigned long du, dl;
-	unsigned long x = fpu->fpul;
-	int exp = 1023 - 126;
-
-	if (x != 0 && (x & 0x7f800000) == 0) {
-		du = (x & 0x80000000);
-		while ((x & 0x00800000) == 0) {
-			x <<= 1;
-			exp--;
-		}
-		x &= 0x007fffff;
-		du |= (exp << 20) | (x >> 3);
-		dl = x << 29;
-
-		fpu->fp_regs[n] = du;
-		fpu->fp_regs[n+1] = dl;
-	}
-}
-
-/**
- *	ieee_fpe_handler - Handle denormalized number exception
- *
- *	@regs: Pointer to register structure
- *
- *	Returns 1 when it's handled (should not cause exception).
- */
-static int ieee_fpe_handler(struct pt_regs *regs)
-{
-	unsigned short insn = *(unsigned short *)regs->pc;
-	unsigned short finsn;
-	unsigned long nextpc;
-	int nib[4] = {
-		(insn >> 12) & 0xf,
-		(insn >> 8) & 0xf,
-		(insn >> 4) & 0xf,
-		insn & 0xf};
-
-	if (nib[0] == 0xb ||
-	    (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
-		regs->pr = regs->pc + 4;
-
-	if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
-		nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
-		if (regs->sr & 1)
-			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
-		else
-			nextpc = regs->pc + 4;
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
-		if (regs->sr & 1)
-			nextpc = regs->pc + 4;
-		else
-			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else if (nib[0] == 0x4 && nib[3] == 0xb &&
-		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
-		nextpc = regs->regs[nib[1]];
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
-		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
-		nextpc = regs->pc + 4 + regs->regs[nib[1]];
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else if (insn == 0x000b) { /* rts */
-		nextpc = regs->pr;
-		finsn = *(unsigned short *) (regs->pc + 2);
-	} else {
-		nextpc = regs->pc + 2;
-		finsn = insn;
-	}
-
-	if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
-		struct task_struct *tsk = current;
-
-		if ((tsk->thread.xstate->softfpu.fpscr & (1 << 17))) {
-			/* FPU error */
-			denormal_to_double (&tsk->thread.xstate->softfpu,
-					    (finsn >> 8) & 0xf);
-			tsk->thread.xstate->softfpu.fpscr &=
-				~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
-			task_thread_info(tsk)->status |= TS_USEDFPU;
-		} else {
-			force_sig_fault(SIGFPE, FPE_FLTINV,
-					(void __user *)regs->pc);
-		}
-
-		regs->pc = nextpc;
-		return 1;
-	}
-
-	return 0;
-}
-
-/**
  * fpu_init - Initialize FPU registers
  * @fpu: Pointer to software emulated FPU registers.
  */
--- linux-ein-5.4.0.orig/arch/sh/math-emu/sfp-util.h
+++ linux-ein-5.4.0/arch/sh/math-emu/sfp-util.h
@@ -67,7 +67,3 @@
   } while (0)
 
 #define abort()	return 0
-
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-
--- linux-ein-5.4.0.orig/arch/sh/mm/init.c
+++ linux-ein-5.4.0/arch/sh/mm/init.c
@@ -434,9 +434,7 @@
 {
 	unsigned long start_pfn = PFN_DOWN(start);
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct zone *zone;
 
-	zone = page_zone(pfn_to_page(start_pfn));
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
--- linux-ein-5.4.0.orig/arch/sparc/Kconfig
+++ linux-ein-5.4.0/arch/sparc/Kconfig
@@ -52,6 +52,7 @@
 config SPARC32
 	def_bool !64BIT
 	select ARCH_32BIT_OFF_T
+	select ARCH_HAS_CPU_FINALIZE_INIT if !SMP
 	select ARCH_HAS_SYNC_DMA_FOR_CPU
 	select GENERIC_ATOMIC64
 	select CLZ_TAB
@@ -65,7 +66,6 @@
 	select HAVE_KRETPROBES
 	select HAVE_KPROBES
 	select HAVE_RCU_TABLE_FREE if SMP
-	select HAVE_RCU_TABLE_NO_INVALIDATE if HAVE_RCU_TABLE_FREE
 	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
 	select HAVE_DYNAMIC_FTRACE
@@ -322,7 +322,7 @@
 	  This config option is actually maximum order plus one. For example,
 	  a value of 13 means that the largest free memory block is 2^12 pages.
 
-if SPARC64
+if SPARC64 || COMPILE_TEST
 source "kernel/power/Kconfig"
 endif
 
@@ -525,7 +525,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
--- linux-ein-5.4.0.orig/arch/sparc/configs/sparc64_defconfig
+++ linux-ein-5.4.0/arch/sparc/configs/sparc64_defconfig
@@ -73,7 +73,6 @@
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
--- linux-ein-5.4.0.orig/arch/sparc/include/asm/io_64.h
+++ linux-ein-5.4.0/arch/sparc/include/asm/io_64.h
@@ -407,6 +407,7 @@
 }
 
 #define ioremap_nocache(X,Y)		ioremap((X),(Y))
+#define ioremap_uc(X,Y)			ioremap((X),(Y))
 #define ioremap_wc(X,Y)			ioremap((X),(Y))
 #define ioremap_wt(X,Y)			ioremap((X),(Y))
 
--- linux-ein-5.4.0.orig/arch/sparc/include/asm/mman.h
+++ linux-ein-5.4.0/arch/sparc/include/asm/mman.h
@@ -57,35 +57,39 @@
 {
 	if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_ADI))
 		return 0;
-	if (prot & PROT_ADI) {
-		if (!adi_capable())
-			return 0;
+	return 1;
+}
 
-		if (addr) {
-			struct vm_area_struct *vma;
+#define arch_validate_flags(vm_flags) arch_validate_flags(vm_flags)
+/* arch_validate_flags() - Ensure combination of flags is valid for a
+ *	VMA.
+ */
+static inline bool arch_validate_flags(unsigned long vm_flags)
+{
+	/* If ADI is being enabled on this VMA, check for ADI
+	 * capability on the platform and ensure VMA is suitable
+	 * for ADI
+	 */
+	if (vm_flags & VM_SPARC_ADI) {
+		if (!adi_capable())
+			return false;
 
-			vma = find_vma(current->mm, addr);
-			if (vma) {
-				/* ADI can not be enabled on PFN
-				 * mapped pages
-				 */
-				if (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))
-					return 0;
+		/* ADI can not be enabled on PFN mapped pages */
+		if (vm_flags & (VM_PFNMAP | VM_MIXEDMAP))
+			return false;
 
-				/* Mergeable pages can become unmergeable
-				 * if ADI is enabled on them even if they
-				 * have identical data on them. This can be
-				 * because ADI enabled pages with identical
-				 * data may still not have identical ADI
-				 * tags on them. Disallow ADI on mergeable
-				 * pages.
-				 */
-				if (vma->vm_flags & VM_MERGEABLE)
-					return 0;
-			}
-		}
+		/* Mergeable pages can become unmergeable
+		 * if ADI is enabled on them even if they
+		 * have identical data on them. This can be
+		 * because ADI enabled pages with identical
+		 * data may still not have identical ADI
+		 * tags on them. Disallow ADI on mergeable
+		 * pages.
+		 */
+		if (vm_flags & VM_MERGEABLE)
+			return false;
 	}
-	return 1;
+	return true;
 }
 #endif /* CONFIG_SPARC64 */
 
--- linux-ein-5.4.0.orig/arch/sparc/include/asm/timex_32.h
+++ linux-ein-5.4.0/arch/sparc/include/asm/timex_32.h
@@ -9,8 +9,6 @@
 
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 
-/* XXX Maybe do something better at some point... -DaveM */
-typedef unsigned long cycles_t;
-#define get_cycles()	(0)
+#include <asm-generic/timex.h>
 
 #endif
--- linux-ein-5.4.0.orig/arch/sparc/include/asm/tlb_64.h
+++ linux-ein-5.4.0/arch/sparc/include/asm/tlb_64.h
@@ -28,6 +28,15 @@
 #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
 #define tlb_flush(tlb)	flush_tlb_pending()
 
+/*
+ * SPARC64's hardware TLB fill does not use the Linux page-tables
+ * and therefore we don't need a TLBI when freeing page-table pages.
+ */
+
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+#define tlb_needs_table_invalidate()	(false)
+#endif
+
 #include <asm-generic/tlb.h>
 
 #endif /* _SPARC64_TLB_H */
--- linux-ein-5.4.0.orig/arch/sparc/include/uapi/asm/ipcbuf.h
+++ linux-ein-5.4.0/arch/sparc/include/uapi/asm/ipcbuf.h
@@ -15,19 +15,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-ein-5.4.0.orig/arch/sparc/kernel/ioport.c
+++ linux-ein-5.4.0/arch/sparc/kernel/ioport.c
@@ -356,7 +356,9 @@
 void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
 		dma_addr_t dma_addr, unsigned long attrs)
 {
-	if (!sparc_dma_free_resource(cpu_addr, PAGE_ALIGN(size)))
+	size = PAGE_ALIGN(size);
+
+	if (!sparc_dma_free_resource(cpu_addr, size))
 		return;
 
 	dma_make_coherent(dma_addr, size);
@@ -366,8 +368,8 @@
 
 /* IIep is write-through, not flushing on cpu to device transfer. */
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	if (dir != PCI_DMA_TODEVICE)
 		dma_make_coherent(paddr, PAGE_ALIGN(size));
--- linux-ein-5.4.0.orig/arch/sparc/kernel/mdesc.c
+++ linux-ein-5.4.0/arch/sparc/kernel/mdesc.c
@@ -39,6 +39,7 @@
 	u32	node_sz; /* node block size */
 	u32	name_sz; /* name block size */
 	u32	data_sz; /* data block size */
+	char	data[];
 } __attribute__((aligned(16)));
 
 struct mdesc_elem {
@@ -612,7 +613,7 @@
 
 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
 {
-	return (struct mdesc_elem *) (mdesc + 1);
+	return (struct mdesc_elem *) mdesc->data;
 }
 
 static void *name_block(struct mdesc_hdr *mdesc)
--- linux-ein-5.4.0.orig/arch/sparc/kernel/ptrace_32.c
+++ linux-ein-5.4.0/arch/sparc/kernel/ptrace_32.c
@@ -46,82 +46,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,
@@ -130,82 +127,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-ein-5.4.0.orig/arch/sparc/kernel/ptrace_64.c
+++ linux-ein-5.4.0/arch/sparc/kernel/ptrace_64.c
@@ -572,19 +572,13 @@
 			for (; count > 0 && pos < 32; count--) {
 				if (access_process_vm(target,
 						      (unsigned long)
-						      &reg_window[pos],
+						      &reg_window[pos++],
 						      &reg, sizeof(reg),
 						      FOLL_FORCE)
 				    != sizeof(reg))
 					return -EFAULT;
-				if (access_process_vm(target,
-						      (unsigned long) u,
-						      &reg, sizeof(reg),
-						      FOLL_FORCE | FOLL_WRITE)
-				    != sizeof(reg))
+				if (put_user(reg, u++))
 					return -EFAULT;
-				pos++;
-				u++;
 			}
 		}
 	}
@@ -684,12 +678,7 @@
 			}
 		} else {
 			for (; count > 0 && pos < 32; count--) {
-				if (access_process_vm(target,
-						      (unsigned long)
-						      u,
-						      &reg, sizeof(reg),
-						      FOLL_FORCE)
-				    != sizeof(reg))
+				if (get_user(reg, u++))
 					return -EFAULT;
 				if (access_process_vm(target,
 						      (unsigned long)
--- linux-ein-5.4.0.orig/arch/sparc/kernel/setup_32.c
+++ linux-ein-5.4.0/arch/sparc/kernel/setup_32.c
@@ -422,3 +422,10 @@
 }
 
 subsys_initcall(topology_init);
+
+#if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
+void __init arch_cpu_finalize_init(void)
+{
+	cpu_data(0).udelay_val = loops_per_jiffy;
+}
+#endif
--- linux-ein-5.4.0.orig/arch/sparc/kernel/smp_64.c
+++ linux-ein-5.4.0/arch/sparc/kernel/smp_64.c
@@ -1039,38 +1039,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
@@ -1080,18 +1051,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();
@@ -1114,17 +1080,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);
 
@@ -1134,14 +1098,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();
--- linux-ein-5.4.0.orig/arch/sparc/kernel/traps_32.c
+++ linux-ein-5.4.0/arch/sparc/kernel/traps_32.c
@@ -86,9 +86,7 @@
 	}
 	printk("Instruction DUMP:");
 	instruction_dump ((unsigned long *) regs->pc);
-	if(regs->psr & PSR_PS)
-		do_exit(SIGKILL);
-	do_exit(SIGSEGV);
+	make_task_dead((regs->psr & PSR_PS) ? SIGKILL : SIGSEGV);
 }
 
 void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
--- linux-ein-5.4.0.orig/arch/sparc/kernel/traps_64.c
+++ linux-ein-5.4.0/arch/sparc/kernel/traps_64.c
@@ -275,14 +275,13 @@
 			asi = (regs->tstate >> 24); /* saved %asi       */
 		else
 			asi = (insn >> 5);	    /* immediate asi    */
-		if ((asi & 0xf2) == ASI_PNF) {
-			if (insn & 0x1000000) {     /* op3[5:4]=3       */
-				handle_ldf_stq(insn, regs);
-				return true;
-			} else if (insn & 0x200000) { /* op3[2], stores */
+		if ((asi & 0xf6) == ASI_PNF) {
+			if (insn & 0x200000)        /* op3[2], stores   */
 				return false;
-			}
-			handle_ld_nf(insn, regs);
+			if (insn & 0x1000000)       /* op3[5:4]=3 (fp)  */
+				handle_ldf_stq(insn, regs);
+			else
+				handle_ld_nf(insn, regs);
 			return true;
 		}
 	}
@@ -2565,9 +2564,7 @@
 	}
 	if (panic_on_oops)
 		panic("Fatal exception");
-	if (regs->tstate & TSTATE_PRIV)
-		do_exit(SIGKILL);
-	do_exit(SIGSEGV);
+	make_task_dead((regs->tstate & TSTATE_PRIV)? SIGKILL : SIGSEGV);
 }
 EXPORT_SYMBOL(die_if_kernel);
 
--- linux-ein-5.4.0.orig/arch/sparc/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/sparc/kernel/vmlinux.lds.S
@@ -172,12 +172,14 @@
 	}
 	PERCPU_SECTION(SMP_CACHE_BYTES)
 
-#ifdef CONFIG_JUMP_LABEL
 	. = ALIGN(PAGE_SIZE);
 	.exit.text : {
 		EXIT_TEXT
 	}
-#endif
+
+	.exit.data : {
+		EXIT_DATA
+	}
 
 	. = ALIGN(PAGE_SIZE);
 	__init_end = .;
--- linux-ein-5.4.0.orig/arch/sparc/lib/iomap.c
+++ linux-ein-5.4.0/arch/sparc/lib/iomap.c
@@ -19,8 +19,10 @@
 EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
 
+#ifdef CONFIG_PCI
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
 	/* nothing to do */
 }
 EXPORT_SYMBOL(pci_iounmap);
+#endif
--- linux-ein-5.4.0.orig/arch/sparc/lib/memset.S
+++ linux-ein-5.4.0/arch/sparc/lib/memset.S
@@ -142,6 +142,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-ein-5.4.0.orig/arch/sparc/mm/init_32.c
+++ linux-ein-5.4.0/arch/sparc/mm/init_32.c
@@ -197,6 +197,9 @@
 	size = memblock_phys_mem_size() - memblock_reserved_size();
 	*pages_avail = (size >> PAGE_SHIFT) - high_pages;
 
+	/* Only allow low memory to be allocated via memblock allocation */
+	memblock_set_current_limit(max_low_pfn << PAGE_SHIFT);
+
 	return max_pfn;
 }
 
--- linux-ein-5.4.0.orig/arch/sparc/mm/init_64.c
+++ linux-ein-5.4.0/arch/sparc/mm/init_64.c
@@ -2904,7 +2904,7 @@
 	if (!page)
 		return NULL;
 	if (!pgtable_pte_page_ctor(page)) {
-		free_unref_page(page);
+		__free_page(page);
 		return NULL;
 	}
 	return (pte_t *) page_address(page);
--- linux-ein-5.4.0.orig/arch/sparc/mm/srmmu.c
+++ linux-ein-5.4.0/arch/sparc/mm/srmmu.c
@@ -379,7 +379,6 @@
 		return NULL;
 	page = pfn_to_page(__nocache_pa(pte) >> PAGE_SHIFT);
 	if (!pgtable_pte_page_ctor(page)) {
-		__free_page(page);
 		return NULL;
 	}
 	return page;
--- linux-ein-5.4.0.orig/arch/sparc/net/bpf_jit_comp_64.c
+++ linux-ein-5.4.0/arch/sparc/net/bpf_jit_comp_64.c
@@ -1287,6 +1287,9 @@
 			return 1;
 		break;
 	}
+	/* speculation barrier */
+	case BPF_ST | BPF_NOSPEC:
+		break;
 	/* ST: *(size *)(dst + off) = imm */
 	case BPF_ST | BPF_MEM | BPF_W:
 	case BPF_ST | BPF_MEM | BPF_H:
--- linux-ein-5.4.0.orig/arch/um/Kconfig
+++ linux-ein-5.4.0/arch/um/Kconfig
@@ -5,6 +5,7 @@
 config UML
 	bool
 	default y
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_KCOV
 	select ARCH_NO_PREEMPT
 	select HAVE_ARCH_AUDITSYSCALL
@@ -14,6 +15,7 @@
 	select HAVE_FUTEX_CMPXCHG if FUTEX
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_DEBUG_BUGVERBOSE
+	select HAVE_COPY_THREAD_TLS
 	select GENERIC_IRQ_SHOW
 	select GENERIC_CPU_DEVICES
 	select GENERIC_CLOCKEVENTS
--- linux-ein-5.4.0.orig/arch/um/Kconfig.debug
+++ linux-ein-5.4.0/arch/um/Kconfig.debug
@@ -17,6 +17,7 @@
 	bool "Enable gcov support"
 	depends on DEBUG_INFO
 	depends on !KCOV
+	depends on !MODULES
 	help
 	  This option allows developers to retrieve coverage data from a UML
 	  session.
--- linux-ein-5.4.0.orig/arch/um/Makefile
+++ linux-ein-5.4.0/arch/um/Makefile
@@ -132,14 +132,23 @@
 # The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
+# Avoid binutils 2.39+ warnings by marking the stack non-executable and
+# ignorning warnings for the kallsyms sections.
+LDFLAGS_EXECSTACK = -z noexecstack
+ifeq ($(CONFIG_LD_IS_BFD),y)
+LDFLAGS_EXECSTACK += $(call ld-option,--no-warn-rwx-segments)
+endif
+
 LD_FLAGS_CMDLINE = $(foreach opt,$(KBUILD_LDFLAGS),-Wl,$(opt))
 
 # Used by link-vmlinux.sh which has special support for um link
 export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
+export LDFLAGS_vmlinux := $(LDFLAGS_EXECSTACK)
 
 # When cleaning we don't include .config, so we don't include
 # TT or skas makefiles and don't clean skas_ptregs.h.
 CLEAN_FILES += linux x.i gmon.out
+MRPROPER_DIRS += arch/$(SUBARCH)/include/generated
 
 archclean:
 	@find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
--- linux-ein-5.4.0.orig/arch/um/configs/i386_defconfig
+++ linux-ein-5.4.0/arch/um/configs/i386_defconfig
@@ -35,6 +35,7 @@
 CONFIG_XTERM_CHAN=y
 CONFIG_CON_CHAN="pts"
 CONFIG_SSL_CHAN="pts"
+CONFIG_SOUND=m
 CONFIG_UML_SOUND=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
--- linux-ein-5.4.0.orig/arch/um/configs/x86_64_defconfig
+++ linux-ein-5.4.0/arch/um/configs/x86_64_defconfig
@@ -33,6 +33,7 @@
 CONFIG_XTERM_CHAN=y
 CONFIG_CON_CHAN="pts"
 CONFIG_SSL_CHAN="pts"
+CONFIG_SOUND=m
 CONFIG_UML_SOUND=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
--- linux-ein-5.4.0.orig/arch/um/drivers/Kconfig
+++ linux-ein-5.4.0/arch/um/drivers/Kconfig
@@ -104,24 +104,14 @@
 
 config UML_SOUND
 	tristate "Sound support"
+	depends on SOUND
+	select SOUND_OSS_CORE
 	help
 	  This option enables UML sound support.  If enabled, it will pull in
-	  soundcore and the UML hostaudio relay, which acts as a intermediary
+	  the UML hostaudio relay, which acts as a intermediary
 	  between the host's dsp and mixer devices and the UML sound system.
 	  It is safe to say 'Y' here.
 
-config SOUND
-	tristate
-	default UML_SOUND
-
-config SOUND_OSS_CORE
-	bool
-	default UML_SOUND
-
-config HOSTAUDIO
-	tristate
-	default UML_SOUND
-
 endmenu
 
 menu "UML Network Devices"
@@ -337,7 +327,7 @@
 endmenu
 
 config VIRTIO_UML
-	tristate "UML driver for virtio devices"
+	bool "UML driver for virtio devices"
 	select VIRTIO
 	help
 	  This driver provides support for virtio based paravirtual device
--- linux-ein-5.4.0.orig/arch/um/drivers/Makefile
+++ linux-ein-5.4.0/arch/um/drivers/Makefile
@@ -52,7 +52,7 @@
 obj-$(CONFIG_MCONSOLE) += mconsole.o
 obj-$(CONFIG_MMAPPER) += mmapper_kern.o 
 obj-$(CONFIG_BLK_DEV_UBD) += ubd.o 
-obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
+obj-$(CONFIG_UML_SOUND) += hostaudio.o
 obj-$(CONFIG_NULL_CHAN) += null.o 
 obj-$(CONFIG_PORT_CHAN) += port.o
 obj-$(CONFIG_PTY_CHAN) += pty.o
--- linux-ein-5.4.0.orig/arch/um/drivers/chan_user.c
+++ linux-ein-5.4.0/arch/um/drivers/chan_user.c
@@ -26,10 +26,10 @@
 	n = read(fd, c_out, sizeof(*c_out));
 	if (n > 0)
 		return n;
-	else if (errno == EAGAIN)
-		return 0;
 	else if (n == 0)
 		return -EIO;
+	else if (errno == EAGAIN)
+		return 0;
 	return -errno;
 }
 
@@ -220,7 +220,7 @@
 		       unsigned long *stack_out)
 {
 	struct winch_data data;
-	int fds[2], n, err;
+	int fds[2], n, err, pid;
 	char c;
 
 	err = os_pipe(fds, 1, 1);
@@ -238,8 +238,9 @@
 	 * problem with /dev/net/tun, which if held open by this
 	 * thread, prevents the TUN/TAP device from being reused.
 	 */
-	err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out);
-	if (err < 0) {
+	pid = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out);
+	if (pid < 0) {
+		err = pid;
 		printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n",
 		       -err);
 		goto out_close;
@@ -256,13 +257,14 @@
 		goto out_close;
 	}
 
-	if (os_set_fd_block(*fd_out, 0)) {
+	err = os_set_fd_block(*fd_out, 0);
+	if (err) {
 		printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd "
 		       "non-blocking.\n");
 		goto out_close;
 	}
 
-	return err;
+	return pid;
 
  out_close:
 	close(fds[1]);
--- linux-ein-5.4.0.orig/arch/um/drivers/mconsole_kern.c
+++ linux-ein-5.4.0/arch/um/drivers/mconsole_kern.c
@@ -217,7 +217,7 @@
 
 void mconsole_stop(struct mc_request *req)
 {
-	deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
+	block_signals();
 	os_set_fd_block(req->originating_fd, 1);
 	mconsole_reply(req, "stopped", 0, 0);
 	for (;;) {
@@ -240,6 +240,7 @@
 	}
 	os_set_fd_block(req->originating_fd, 0);
 	mconsole_reply(req, "", 0, 0);
+	unblock_signals();
 }
 
 static DEFINE_SPINLOCK(mc_devices_lock);
--- linux-ein-5.4.0.orig/arch/um/drivers/net_kern.c
+++ linux-ein-5.4.0/arch/um/drivers/net_kern.c
@@ -204,7 +204,7 @@
 	return 0;
 }
 
-static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct uml_net_private *lp = netdev_priv(dev);
 	unsigned long flags;
--- linux-ein-5.4.0.orig/arch/um/drivers/slip_user.c
+++ linux-ein-5.4.0/arch/um/drivers/slip_user.c
@@ -145,7 +145,8 @@
 	}
 	sfd = err;
 
-	if (set_up_tty(sfd))
+	err = set_up_tty(sfd);
+	if (err)
 		goto out_close2;
 
 	pri->slave = sfd;
--- linux-ein-5.4.0.orig/arch/um/drivers/ubd_kern.c
+++ linux-ein-5.4.0/arch/um/drivers/ubd_kern.c
@@ -47,18 +47,25 @@
 /* Max request size is determined by sector mask - 32K */
 #define UBD_MAX_REQUEST (8 * sizeof(long))
 
+struct io_desc {
+	char *buffer;
+	unsigned long length;
+	unsigned long sector_mask;
+	unsigned long long cow_offset;
+	unsigned long bitmap_words[2];
+};
+
 struct io_thread_req {
 	struct request *req;
 	int fds[2];
 	unsigned long offsets[2];
 	unsigned long long offset;
-	unsigned long length;
-	char *buffer;
 	int sectorsize;
-	unsigned long sector_mask;
-	unsigned long long cow_offset;
-	unsigned long bitmap_words[2];
 	int error;
+
+	int desc_cnt;
+	/* io_desc has to be the last element of the struct */
+	struct io_desc io_desc[];
 };
 
 
@@ -524,12 +531,7 @@
 				blk_queue_max_write_zeroes_sectors(io_req->req->q, 0);
 				blk_queue_flag_clear(QUEUE_FLAG_DISCARD, io_req->req->q);
 			}
-			if ((io_req->error) || (io_req->buffer == NULL))
-				blk_mq_end_request(io_req->req, io_req->error);
-			else {
-				if (!blk_update_request(io_req->req, io_req->error, io_req->length))
-					__blk_mq_end_request(io_req->req, io_req->error);
-			}
+			blk_mq_end_request(io_req->req, io_req->error);
 			kfree(io_req);
 		}
 	}
@@ -945,6 +947,7 @@
 	blk_queue_write_cache(ubd_dev->queue, true, false);
 
 	blk_queue_max_segments(ubd_dev->queue, MAX_SG);
+	blk_queue_segment_boundary(ubd_dev->queue, PAGE_SIZE - 1);
 	err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
 	if(err){
 		*error_out = "Failed to register device";
@@ -1288,37 +1291,74 @@
 	*cow_offset += bitmap_offset;
 }
 
-static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
+static void cowify_req(struct io_thread_req *req, struct io_desc *segment,
+		       unsigned long offset, unsigned long *bitmap,
 		       __u64 bitmap_offset, __u64 bitmap_len)
 {
-	__u64 sector = req->offset >> SECTOR_SHIFT;
+	__u64 sector = offset >> SECTOR_SHIFT;
 	int i;
 
-	if (req->length > (sizeof(req->sector_mask) * 8) << SECTOR_SHIFT)
+	if (segment->length > (sizeof(segment->sector_mask) * 8) << SECTOR_SHIFT)
 		panic("Operation too long");
 
 	if (req_op(req->req) == REQ_OP_READ) {
-		for (i = 0; i < req->length >> SECTOR_SHIFT; i++) {
+		for (i = 0; i < segment->length >> SECTOR_SHIFT; i++) {
 			if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
 				ubd_set_bit(i, (unsigned char *)
-					    &req->sector_mask);
+					    &segment->sector_mask);
 		}
+	} else {
+		cowify_bitmap(offset, segment->length, &segment->sector_mask,
+			      &segment->cow_offset, bitmap, bitmap_offset,
+			      segment->bitmap_words, bitmap_len);
 	}
-	else cowify_bitmap(req->offset, req->length, &req->sector_mask,
-			   &req->cow_offset, bitmap, bitmap_offset,
-			   req->bitmap_words, bitmap_len);
 }
 
-static int ubd_queue_one_vec(struct blk_mq_hw_ctx *hctx, struct request *req,
-		u64 off, struct bio_vec *bvec)
+static void ubd_map_req(struct ubd *dev, struct io_thread_req *io_req,
+			struct request *req)
+{
+	struct bio_vec bvec;
+	struct req_iterator iter;
+	int i = 0;
+	unsigned long byte_offset = io_req->offset;
+	int op = req_op(req);
+
+	if (op == REQ_OP_WRITE_ZEROES || op == REQ_OP_DISCARD) {
+		io_req->io_desc[0].buffer = NULL;
+		io_req->io_desc[0].length = blk_rq_bytes(req);
+	} else {
+		rq_for_each_segment(bvec, req, iter) {
+			BUG_ON(i >= io_req->desc_cnt);
+
+			io_req->io_desc[i].buffer =
+				page_address(bvec.bv_page) + bvec.bv_offset;
+			io_req->io_desc[i].length = bvec.bv_len;
+			i++;
+		}
+	}
+
+	if (dev->cow.file) {
+		for (i = 0; i < io_req->desc_cnt; i++) {
+			cowify_req(io_req, &io_req->io_desc[i], byte_offset,
+				   dev->cow.bitmap, dev->cow.bitmap_offset,
+				   dev->cow.bitmap_len);
+			byte_offset += io_req->io_desc[i].length;
+		}
+
+	}
+}
+
+static struct io_thread_req *ubd_alloc_req(struct ubd *dev, struct request *req,
+					   int desc_cnt)
 {
-	struct ubd *dev = hctx->queue->queuedata;
 	struct io_thread_req *io_req;
-	int ret;
+	int i;
 
-	io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC);
+	io_req = kmalloc(sizeof(*io_req) +
+			 (desc_cnt * sizeof(struct io_desc)),
+			 GFP_ATOMIC);
 	if (!io_req)
-		return -ENOMEM;
+		return NULL;
 
 	io_req->req = req;
 	if (dev->cow.file)
@@ -1326,26 +1366,41 @@
 	else
 		io_req->fds[0] = dev->fd;
 	io_req->error = 0;
-
-	if (bvec != NULL) {
-		io_req->buffer = page_address(bvec->bv_page) + bvec->bv_offset;
-		io_req->length = bvec->bv_len;
-	} else {
-		io_req->buffer = NULL;
-		io_req->length = blk_rq_bytes(req);
-	}
-
 	io_req->sectorsize = SECTOR_SIZE;
 	io_req->fds[1] = dev->fd;
-	io_req->cow_offset = -1;
-	io_req->offset = off;
-	io_req->sector_mask = 0;
+	io_req->offset = (u64) blk_rq_pos(req) << SECTOR_SHIFT;
 	io_req->offsets[0] = 0;
 	io_req->offsets[1] = dev->cow.data_offset;
 
-	if (dev->cow.file)
-		cowify_req(io_req, dev->cow.bitmap,
-			   dev->cow.bitmap_offset, dev->cow.bitmap_len);
+	for (i = 0 ; i < desc_cnt; i++) {
+		io_req->io_desc[i].sector_mask = 0;
+		io_req->io_desc[i].cow_offset = -1;
+	}
+
+	return io_req;
+}
+
+static int ubd_submit_request(struct ubd *dev, struct request *req)
+{
+	int segs = 0;
+	struct io_thread_req *io_req;
+	int ret;
+	int op = req_op(req);
+
+	if (op == REQ_OP_FLUSH)
+		segs = 0;
+	else if (op == REQ_OP_WRITE_ZEROES || op == REQ_OP_DISCARD)
+		segs = 1;
+	else
+		segs = blk_rq_nr_phys_segments(req);
+
+	io_req = ubd_alloc_req(dev, req, segs);
+	if (!io_req)
+		return -ENOMEM;
+
+	io_req->desc_cnt = segs;
+	if (segs)
+		ubd_map_req(dev, io_req, req);
 
 	ret = os_write_file(thread_fd, &io_req, sizeof(io_req));
 	if (ret != sizeof(io_req)) {
@@ -1356,22 +1411,6 @@
 	return ret;
 }
 
-static int queue_rw_req(struct blk_mq_hw_ctx *hctx, struct request *req)
-{
-	struct req_iterator iter;
-	struct bio_vec bvec;
-	int ret;
-	u64 off = (u64)blk_rq_pos(req) << SECTOR_SHIFT;
-
-	rq_for_each_segment(bvec, req, iter) {
-		ret = ubd_queue_one_vec(hctx, req, off, &bvec);
-		if (ret < 0)
-			return ret;
-		off += bvec.bv_len;
-	}
-	return 0;
-}
-
 static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx,
 				 const struct blk_mq_queue_data *bd)
 {
@@ -1384,17 +1423,12 @@
 	spin_lock_irq(&ubd_dev->lock);
 
 	switch (req_op(req)) {
-	/* operations with no lentgth/offset arguments */
 	case REQ_OP_FLUSH:
-		ret = ubd_queue_one_vec(hctx, req, 0, NULL);
-		break;
 	case REQ_OP_READ:
 	case REQ_OP_WRITE:
-		ret = queue_rw_req(hctx, req);
-		break;
 	case REQ_OP_DISCARD:
 	case REQ_OP_WRITE_ZEROES:
-		ret = ubd_queue_one_vec(hctx, req, (u64)blk_rq_pos(req) << 9, NULL);
+		ret = ubd_submit_request(ubd_dev, req);
 		break;
 	default:
 		WARN_ON_ONCE(1);
@@ -1482,22 +1516,22 @@
  * will result in unpredictable behaviour and/or crashes.
  */
 
-static int update_bitmap(struct io_thread_req *req)
+static int update_bitmap(struct io_thread_req *req, struct io_desc *segment)
 {
 	int n;
 
-	if(req->cow_offset == -1)
+	if (segment->cow_offset == -1)
 		return map_error(0);
 
-	n = os_pwrite_file(req->fds[1], &req->bitmap_words,
-			  sizeof(req->bitmap_words), req->cow_offset);
-	if (n != sizeof(req->bitmap_words))
+	n = os_pwrite_file(req->fds[1], &segment->bitmap_words,
+			  sizeof(segment->bitmap_words), segment->cow_offset);
+	if (n != sizeof(segment->bitmap_words))
 		return map_error(-n);
 
 	return map_error(0);
 }
 
-static void do_io(struct io_thread_req *req)
+static void do_io(struct io_thread_req *req, struct io_desc *desc)
 {
 	char *buf = NULL;
 	unsigned long len;
@@ -1512,21 +1546,20 @@
 		return;
 	}
 
-	nsectors = req->length / req->sectorsize;
+	nsectors = desc->length / req->sectorsize;
 	start = 0;
 	do {
-		bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
+		bit = ubd_test_bit(start, (unsigned char *) &desc->sector_mask);
 		end = start;
 		while((end < nsectors) &&
-		      (ubd_test_bit(end, (unsigned char *)
-				    &req->sector_mask) == bit))
+		      (ubd_test_bit(end, (unsigned char *) &desc->sector_mask) == bit))
 			end++;
 
 		off = req->offset + req->offsets[bit] +
 			start * req->sectorsize;
 		len = (end - start) * req->sectorsize;
-		if (req->buffer != NULL)
-			buf = &req->buffer[start * req->sectorsize];
+		if (desc->buffer != NULL)
+			buf = &desc->buffer[start * req->sectorsize];
 
 		switch (req_op(req->req)) {
 		case REQ_OP_READ:
@@ -1566,7 +1599,8 @@
 		start = end;
 	} while(start < nsectors);
 
-	req->error = update_bitmap(req);
+	req->offset += len;
+	req->error = update_bitmap(req, desc);
 }
 
 /* Changed in start_io_thread, which is serialized by being called only
@@ -1599,14 +1633,21 @@
 		}
 
 		for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
+			struct io_thread_req *req = (*io_req_buffer)[count];
+			int i;
+
 			io_count++;
-			do_io((*io_req_buffer)[count]);
+			for (i = 0; !req->error && i < req->desc_cnt; i++)
+				do_io(req, &(req->io_desc[i]));
+
 		}
 
 		written = 0;
 
 		do {
-			res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
+			res = os_write_file(kernel_fd,
+					    ((char *) io_req_buffer) + written,
+					    n - written);
 			if (res >= 0) {
 				written += res;
 			}
--- linux-ein-5.4.0.orig/arch/um/drivers/vector_kern.c
+++ linux-ein-5.4.0/arch/um/drivers/vector_kern.c
@@ -746,6 +746,7 @@
 
 	if (parsed == NULL) {
 		*error_out = "vector_config failed to parse parameters";
+		kfree(params);
 		return -EINVAL;
 	}
 
--- linux-ein-5.4.0.orig/arch/um/drivers/virtio_uml.c
+++ linux-ein-5.4.0/arch/um/drivers/virtio_uml.c
@@ -4,12 +4,12 @@
  *
  * Copyright(c) 2019 Intel Corporation
  *
- * This module allows virtio devices to be used over a vhost-user socket.
+ * This driver allows virtio devices to be used over a vhost-user socket.
  *
  * Guest devices can be instantiated by kernel module or command line
  * parameters. One device will be created for each parameter. Syntax:
  *
- *		[virtio_uml.]device=<socket>:<virtio_id>[:<platform_id>]
+ *		virtio_uml.device=<socket>:<virtio_id>[:<platform_id>]
  * where:
  *		<socket>	:= vhost-user socket path to connect
  *		<virtio_id>	:= virtio device id (as in virtio_ids.h)
@@ -83,7 +83,7 @@
 	return 0;
 }
 
-static int full_read(int fd, void *buf, int len)
+static int full_read(int fd, void *buf, int len, bool abortable)
 {
 	int rc;
 
@@ -93,7 +93,7 @@
 			buf += rc;
 			len -= rc;
 		}
-	} while (len && (rc > 0 || rc == -EINTR));
+	} while (len && (rc > 0 || rc == -EINTR || (!abortable && rc == -EAGAIN)));
 
 	if (rc < 0)
 		return rc;
@@ -104,7 +104,7 @@
 
 static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
 {
-	return full_read(fd, msg, sizeof(msg->header));
+	return full_read(fd, msg, sizeof(msg->header), true);
 }
 
 static int vhost_user_recv(int fd, struct vhost_user_msg *msg,
@@ -118,7 +118,7 @@
 	size = msg->header.size;
 	if (size > max_payload_size)
 		return -EPROTO;
-	return full_read(fd, &msg->payload, size);
+	return full_read(fd, &msg->payload, size, false);
 }
 
 static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
@@ -959,6 +959,7 @@
 	}
 
 	os_close_file(vu_dev->sock);
+	kfree(vu_dev);
 }
 
 /* Platform device */
@@ -977,7 +978,7 @@
 	if (!pdata)
 		return -EINVAL;
 
-	vu_dev = devm_kzalloc(&pdev->dev, sizeof(*vu_dev), GFP_KERNEL);
+	vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);
 	if (!vu_dev)
 		return -ENOMEM;
 
@@ -993,7 +994,7 @@
 		rc = os_connect_socket(pdata->socket_path);
 	} while (rc == -EINTR);
 	if (rc < 0)
-		return rc;
+		goto error_free;
 	vu_dev->sock = rc;
 
 	rc = vhost_user_init(vu_dev);
@@ -1009,6 +1010,8 @@
 
 error_init:
 	os_close_file(vu_dev->sock);
+error_free:
+	kfree(vu_dev);
 	return rc;
 }
 
--- linux-ein-5.4.0.orig/arch/um/drivers/xterm.c
+++ linux-ein-5.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-ein-5.4.0.orig/arch/um/include/asm/common.lds.S
+++ linux-ein-5.4.0/arch/um/include/asm/common.lds.S
@@ -83,8 +83,8 @@
 	__preinit_array_end = .;
   }
   .init_array : {
-        /* dummy - we call this ourselves */
 	__init_array_start = .;
+	*(.init_array)
 	__init_array_end = .;
   }
   .fini_array : {
--- linux-ein-5.4.0.orig/arch/um/include/asm/ptrace-generic.h
+++ linux-ein-5.4.0/arch/um/include/asm/ptrace-generic.h
@@ -36,7 +36,7 @@
 extern unsigned long getreg(struct task_struct *child, int regno);
 extern int putreg(struct task_struct *child, int regno, unsigned long value);
 
-extern int arch_copy_tls(struct task_struct *new);
+extern int arch_set_tls(struct task_struct *new, unsigned long tls);
 extern void clear_flushed_tls(struct task_struct *task);
 extern int syscall_trace_enter(struct pt_regs *regs);
 extern void syscall_trace_leave(struct pt_regs *regs);
--- linux-ein-5.4.0.orig/arch/um/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/um/include/asm/thread_info.h
@@ -63,6 +63,7 @@
 #define TIF_RESTORE_SIGMASK	7
 #define TIF_NOTIFY_RESUME	8
 #define TIF_SECCOMP		9	/* secure computing */
+#define TIF_SINGLESTEP		10	/* single stepping userspace */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
@@ -70,5 +71,6 @@
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
+#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 
 #endif
--- linux-ein-5.4.0.orig/arch/um/include/asm/timex.h
+++ linux-ein-5.4.0/arch/um/include/asm/timex.h
@@ -2,13 +2,8 @@
 #ifndef __UM_TIMEX_H
 #define __UM_TIMEX_H
 
-typedef unsigned long cycles_t;
-
-static inline cycles_t get_cycles (void)
-{
-	return 0;
-}
-
 #define CLOCK_TICK_RATE (HZ)
 
+#include <asm-generic/timex.h>
+
 #endif
--- linux-ein-5.4.0.orig/arch/um/include/shared/kern_util.h
+++ linux-ein-5.4.0/arch/um/include/shared/kern_util.h
@@ -49,7 +49,7 @@
  * Are we disallowed to sleep? Used to choose between GFP_KERNEL and
  * GFP_ATOMIC.
  */
-extern int __cant_sleep(void);
+extern int __uml_cant_sleep(void);
 extern int get_current_pid(void);
 extern int copy_from_user_proc(void *to, void *from, int size);
 extern int cpu(void);
--- linux-ein-5.4.0.orig/arch/um/include/shared/registers.h
+++ linux-ein-5.4.0/arch/um/include/shared/registers.h
@@ -16,8 +16,8 @@
 extern int save_fpx_registers(int pid, unsigned long *fp_regs);
 extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
 extern int save_registers(int pid, struct uml_pt_regs *regs);
-extern int restore_registers(int pid, struct uml_pt_regs *regs);
-extern int init_registers(int pid);
+extern int restore_pid_registers(int pid, struct uml_pt_regs *regs);
+extern int init_pid_registers(int pid);
 extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs);
 extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
 extern int get_fp_registers(int pid, unsigned long *regs);
--- linux-ein-5.4.0.orig/arch/um/kernel/Makefile
+++ linux-ein-5.4.0/arch/um/kernel/Makefile
@@ -21,7 +21,6 @@
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)	+= gprof_syms.o
-obj-$(CONFIG_GCOV)	+= gmon_syms.o
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 
--- linux-ein-5.4.0.orig/arch/um/kernel/dyn.lds.S
+++ linux-ein-5.4.0/arch/um/kernel/dyn.lds.S
@@ -6,6 +6,12 @@
 ENTRY(_start)
 jiffies = jiffies_64;
 
+VERSION {
+  {
+    local: *;
+  };
+}
+
 SECTIONS
 {
   PROVIDE (__executable_start = START);
@@ -103,6 +109,7 @@
      be empty, which isn't pretty.  */
   . = ALIGN(32 / 8);
   .preinit_array     : { *(.preinit_array) }
+  .init_array     : { *(.init_array) }
   .fini_array     : { *(.fini_array) }
   .data           : {
     INIT_TASK_DATA(KERNEL_STACK_SIZE)
--- linux-ein-5.4.0.orig/arch/um/kernel/exec.c
+++ linux-ein-5.4.0/arch/um/kernel/exec.c
@@ -44,7 +44,7 @@
 {
 	PT_REGS_IP(regs) = eip;
 	PT_REGS_SP(regs) = esp;
-	current->ptrace &= ~PT_DTRACE;
+	clear_thread_flag(TIF_SINGLESTEP);
 #ifdef SUBARCH_EXECVE1
 	SUBARCH_EXECVE1(regs->regs);
 #endif
--- linux-ein-5.4.0.orig/arch/um/kernel/process.c
+++ linux-ein-5.4.0/arch/um/kernel/process.c
@@ -153,8 +153,8 @@
 	userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs);
 }
 
-int copy_thread(unsigned long clone_flags, unsigned long sp,
-		unsigned long arg, struct task_struct * p)
+int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
+		unsigned long arg, struct task_struct * p, unsigned long tls)
 {
 	void (*handler)(void);
 	int kthread = current->flags & PF_KTHREAD;
@@ -188,7 +188,7 @@
 		 * Set a new TLS for the child thread?
 		 */
 		if (clone_flags & CLONE_SETTLS)
-			ret = arch_copy_tls(p);
+			ret = arch_set_tls(p, tls);
 	}
 
 	return ret;
@@ -258,7 +258,7 @@
 	local_irq_enable();
 }
 
-int __cant_sleep(void) {
+int __uml_cant_sleep(void) {
 	return in_atomic() || irqs_disabled() || in_interrupt();
 	/* Is in_interrupt() really needed? */
 }
@@ -380,7 +380,7 @@
 {
 	struct task_struct *task = t ? t : current;
 
-	if (!(task->ptrace & PT_DTRACE))
+	if (!test_thread_flag(TIF_SINGLESTEP))
 		return 0;
 
 	if (task->thread.singlestep_syscall)
--- linux-ein-5.4.0.orig/arch/um/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/um/kernel/ptrace.c
@@ -12,7 +12,7 @@
 
 void user_enable_single_step(struct task_struct *child)
 {
-	child->ptrace |= PT_DTRACE;
+	set_tsk_thread_flag(child, TIF_SINGLESTEP);
 	child->thread.singlestep_syscall = 0;
 
 #ifdef SUBARCH_SET_SINGLESTEPPING
@@ -22,7 +22,7 @@
 
 void user_disable_single_step(struct task_struct *child)
 {
-	child->ptrace &= ~PT_DTRACE;
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 	child->thread.singlestep_syscall = 0;
 
 #ifdef SUBARCH_SET_SINGLESTEPPING
@@ -121,7 +121,7 @@
 }
 
 /*
- * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
+ * XXX Check TIF_SINGLESTEP for singlestepping check and
  * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
  */
 int syscall_trace_enter(struct pt_regs *regs)
@@ -145,7 +145,7 @@
 	audit_syscall_exit(regs);
 
 	/* Fake a debug trap */
-	if (ptraced & PT_DTRACE)
+	if (test_thread_flag(TIF_SINGLESTEP))
 		send_sigtrap(&regs->regs, 0);
 
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
--- linux-ein-5.4.0.orig/arch/um/kernel/sigio.c
+++ linux-ein-5.4.0/arch/um/kernel/sigio.c
@@ -35,14 +35,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-ein-5.4.0.orig/arch/um/kernel/signal.c
+++ linux-ein-5.4.0/arch/um/kernel/signal.c
@@ -53,7 +53,7 @@
 	unsigned long sp;
 	int err;
 
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+	if (test_thread_flag(TIF_SINGLESTEP) && (current->ptrace & PT_PTRACED))
 		singlestep = 1;
 
 	/* Did we come from a system call? */
@@ -128,7 +128,7 @@
 	 * on the host.  The tracing thread will check this flag and
 	 * PTRACE_SYSCALL if necessary.
 	 */
-	if (current->ptrace & PT_DTRACE)
+	if (test_thread_flag(TIF_SINGLESTEP))
 		current->thread.singlestep_syscall =
 			is_syscall(PT_REGS_IP(&current->thread.regs));
 
--- linux-ein-5.4.0.orig/arch/um/kernel/tlb.c
+++ linux-ein-5.4.0/arch/um/kernel/tlb.c
@@ -126,6 +126,9 @@
 	struct host_vm_op *last;
 	int fd = -1, ret = 0;
 
+	if (virt + len > STUB_START && virt < STUB_END)
+		return -EINVAL;
+
 	if (hvc->userspace)
 		fd = phys_mapping(phys, &offset);
 	else
@@ -163,7 +166,7 @@
 	struct host_vm_op *last;
 	int ret = 0;
 
-	if ((addr >= STUB_START) && (addr < STUB_END))
+	if (addr + len > STUB_START && addr < STUB_END)
 		return -EINVAL;
 
 	if (hvc->index != 0) {
@@ -193,6 +196,9 @@
 	struct host_vm_op *last;
 	int ret = 0;
 
+	if (addr + len > STUB_START && addr < STUB_END)
+		return -EINVAL;
+
 	if (hvc->index != 0) {
 		last = &hvc->ops[hvc->index - 1];
 		if ((last->type == MPROTECT) &&
@@ -433,6 +439,10 @@
 	struct mm_id *mm_id;
 
 	address &= PAGE_MASK;
+
+	if (address >= STUB_START && address < STUB_END)
+		goto kill;
+
 	pgd = pgd_offset(mm, address);
 	if (!pgd_present(*pgd))
 		goto kill;
--- linux-ein-5.4.0.orig/arch/um/kernel/um_arch.c
+++ linux-ein-5.4.0/arch/um/kernel/um_arch.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  */
 
+#include <linux/cpu.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -77,7 +78,7 @@
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+	return *pos < nr_cpu_ids ? cpu_data + *pos : NULL;
 }
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
@@ -353,7 +354,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-ein-5.4.0.orig/arch/um/kernel/uml.lds.S
+++ linux-ein-5.4.0/arch/um/kernel/uml.lds.S
@@ -7,6 +7,12 @@
 ENTRY(_start)
 jiffies = jiffies_64;
 
+VERSION {
+  {
+    local: *;
+  };
+}
+
 SECTIONS
 {
   /* This must contain the right address - not quite the default ELF one.*/
--- linux-ein-5.4.0.orig/arch/um/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/um/kernel/vmlinux.lds.S
@@ -1,4 +1,4 @@
-
+#define RUNTIME_DISCARD_EXIT
 KERNEL_STACK_SIZE = 4096 * (1 << CONFIG_KERNEL_STACK_ORDER);
 
 #ifdef CONFIG_LD_SCRIPT_STATIC
--- linux-ein-5.4.0.orig/arch/um/os-Linux/file.c
+++ linux-ein-5.4.0/arch/um/os-Linux/file.c
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <linux/falloc.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
--- linux-ein-5.4.0.orig/arch/um/os-Linux/helper.c
+++ linux-ein-5.4.0/arch/um/os-Linux/helper.c
@@ -45,7 +45,7 @@
 	unsigned long stack, sp;
 	int pid, fds[2], ret, n;
 
-	stack = alloc_stack(0, __cant_sleep());
+	stack = alloc_stack(0, __uml_cant_sleep());
 	if (stack == 0)
 		return -ENOMEM;
 
@@ -69,7 +69,7 @@
 	data.pre_data = pre_data;
 	data.argv = argv;
 	data.fd = fds[1];
-	data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
+	data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
 					uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
 	pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
 	if (pid < 0) {
@@ -116,7 +116,7 @@
 	unsigned long stack, sp;
 	int pid, status, err;
 
-	stack = alloc_stack(0, __cant_sleep());
+	stack = alloc_stack(0, __uml_cant_sleep());
 	if (stack == 0)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/arch/um/os-Linux/irq.c
+++ linux-ein-5.4.0/arch/um/os-Linux/irq.c
@@ -48,7 +48,7 @@
 int os_event_mask(int irq_type)
 {
 	if (irq_type == IRQ_READ)
-		return EPOLLIN | EPOLLPRI;
+		return EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
 	if (irq_type == IRQ_WRITE)
 		return EPOLLOUT;
 	return 0;
--- linux-ein-5.4.0.orig/arch/um/os-Linux/main.c
+++ linux-ein-5.4.0/arch/um/os-Linux/main.c
@@ -170,7 +170,7 @@
 	 * that they won't be delivered after the exec, when
 	 * they are definitely not expected.
 	 */
-	unblock_signals_trace();
+	unblock_signals();
 
 	os_info("\n");
 	/* Reboot */
--- linux-ein-5.4.0.orig/arch/um/os-Linux/registers.c
+++ linux-ein-5.4.0/arch/um/os-Linux/registers.c
@@ -21,7 +21,7 @@
 	return 0;
 }
 
-int restore_registers(int pid, struct uml_pt_regs *regs)
+int restore_pid_registers(int pid, struct uml_pt_regs *regs)
 {
 	int err;
 
@@ -36,7 +36,7 @@
 static unsigned long exec_regs[MAX_REG_NR];
 static unsigned long exec_fp_regs[FP_SIZE];
 
-int init_registers(int pid)
+int init_pid_registers(int pid)
 {
 	int err;
 
--- linux-ein-5.4.0.orig/arch/um/os-Linux/skas/process.c
+++ linux-ein-5.4.0/arch/um/os-Linux/skas/process.c
@@ -5,6 +5,7 @@
  */
 
 #include <stdlib.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <sched.h>
 #include <errno.h>
@@ -641,10 +642,24 @@
 	UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
 }
 
+static bool noreboot;
+
+static int __init noreboot_cmd_param(char *str, int *add)
+{
+	noreboot = true;
+	return 0;
+}
+
+__uml_setup("noreboot", noreboot_cmd_param,
+"noreboot\n"
+"    Rather than rebooting, exit always, akin to QEMU's -no-reboot option.\n"
+"    This is useful if you're using CONFIG_PANIC_TIMEOUT in order to catch\n"
+"    crashes in CI\n");
+
 void reboot_skas(void)
 {
 	block_signals_trace();
-	UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
+	UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT);
 }
 
 void __switch_mm(struct mm_id *mm_idp)
--- linux-ein-5.4.0.orig/arch/um/os-Linux/start_up.c
+++ linux-ein-5.4.0/arch/um/os-Linux/start_up.c
@@ -336,7 +336,7 @@
 	check_tmpexec();
 
 	pid = start_ptraced_child();
-	if (init_registers(pid))
+	if (init_pid_registers(pid))
 		fatal("Failed to initialize default registers");
 	stop_ptraced_child(pid, 1, 1);
 }
--- linux-ein-5.4.0.orig/arch/um/os-Linux/umid.c
+++ linux-ein-5.4.0/arch/um/os-Linux/umid.c
@@ -137,20 +137,13 @@
 {
 	char pid[sizeof("nnnnn\0")], *end, *file;
 	int dead, fd, p, n, err;
-	size_t filelen;
+	size_t filelen = strlen(dir) + sizeof("/pid") + 1;
 
-	err = asprintf(&file, "%s/pid", dir);
-	if (err < 0)
-		return 0;
+	file = malloc(filelen);
+	if (!file)
+		return -ENOMEM;
 
-	filelen = strlen(file);
-
-	n = snprintf(file, filelen, "%s/pid", dir);
-	if (n >= filelen) {
-		printk(UM_KERN_ERR "is_umdir_used - pid filename too long\n");
-		err = -E2BIG;
-		goto out;
-	}
+	snprintf(file, filelen, "%s/pid", dir);
 
 	dead = 0;
 	fd = open(file, O_RDONLY);
--- linux-ein-5.4.0.orig/arch/um/os-Linux/util.c
+++ linux-ein-5.4.0/arch/um/os-Linux/util.c
@@ -166,23 +166,38 @@
 "quiet\n"
 "    Turns off information messages during boot.\n\n");
 
+/*
+ * The os_info/os_warn functions will be called by helper threads. These
+ * have a very limited stack size and using the libc formatting functions
+ * may overflow the stack.
+ * So pull in the kernel vscnprintf and use that instead with a fixed
+ * on-stack buffer.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
 void os_info(const char *fmt, ...)
 {
+	char buf[256];
 	va_list list;
+	int len;
 
 	if (quiet_info)
 		return;
 
 	va_start(list, fmt);
-	vfprintf(stderr, fmt, list);
+	len = vscnprintf(buf, sizeof(buf), fmt, list);
+	fwrite(buf, len, 1, stderr);
 	va_end(list);
 }
 
 void os_warn(const char *fmt, ...)
 {
+	char buf[256];
 	va_list list;
+	int len;
 
 	va_start(list, fmt);
-	vfprintf(stderr, fmt, list);
+	len = vscnprintf(buf, sizeof(buf), fmt, list);
+	fwrite(buf, len, 1, stderr);
 	va_end(list);
 }
--- linux-ein-5.4.0.orig/arch/x86/Kconfig
+++ linux-ein-5.4.0/arch/x86/Kconfig
@@ -60,6 +60,7 @@
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_CLOCKSOURCE_INIT
 	select ARCH_HAS_ACPI_TABLE_UPGRADE	if ACPI
+	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEVMEM_IS_ALLOWED
 	select ARCH_HAS_ELF_RANDOMIZE
@@ -73,7 +74,6 @@
 	select ARCH_HAS_PMEM_API		if X86_64
 	select ARCH_HAS_PTE_DEVMAP		if X86_64
 	select ARCH_HAS_PTE_SPECIAL
-	select ARCH_HAS_REFCOUNT
 	select ARCH_HAS_UACCESS_FLUSHCACHE	if X86_64
 	select ARCH_HAS_UACCESS_MCSAFE		if X86_64 && X86_MCE
 	select ARCH_HAS_SET_MEMORY
@@ -550,6 +550,7 @@
 	depends on X86_EXTENDED_PLATFORM
 	depends on NUMA
 	depends on EFI
+	depends on KEXEC_CORE
 	depends on X86_X2APIC
 	depends on PCI
 	---help---
@@ -1424,7 +1425,7 @@
 
 config HIGHMEM64G
 	bool "64GB"
-	depends on !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !WINCHIP3D && !MK6
+	depends on !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !MWINCHIP3D && !MK6
 	select X86_PAE
 	---help---
 	  Select this if you have a 32-bit processor and more than 4
@@ -1540,7 +1541,6 @@
 
 config AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT
 	bool "Activate AMD Secure Memory Encryption (SME) by default"
-	default y
 	depends on AMD_MEM_ENCRYPT
 	---help---
 	  Say yes to have system memory encrypted by default if running on
@@ -1990,6 +1990,7 @@
 	depends on ACPI
 	select UCS2_STRING
 	select EFI_RUNTIME_WRAPPERS
+	select ARCH_USE_MEMREMAP_PROT
 	---help---
 	  This enables the kernel to use EFI runtime services that are
 	  available (such as the EFI variable services).
@@ -2480,6 +2481,25 @@
 
 endmenu
 
+config GDS_FORCE_MITIGATION
+	bool "Force GDS Mitigation"
+	depends on CPU_SUP_INTEL
+	default n
+	help
+	  Gather Data Sampling (GDS) is a hardware vulnerability which allows
+	  unprivileged speculative access to data which was previously stored in
+	  vector registers.
+
+	  This option is equivalent to setting gather_data_sampling=force on the
+	  command line. The microcode mitigation is used if present, otherwise
+	  AVX is disabled as a mitigation. On affected systems that are missing
+	  the microcode any userspace code that unconditionally uses AVX will
+	  break with this option set.
+
+	  Setting this option on systems not vulnerable to GDS has no effect.
+
+	  If in doubt, say N.
+
 config ARCH_HAS_ADD_PAGES
 	def_bool y
 	depends on X86_64 && ARCH_ENABLE_MEMORY_HOTPLUG
@@ -2500,6 +2520,31 @@
 	def_bool y
 	depends on X86_64 || X86_PAE
 
+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
+
 config ARCH_ENABLE_HUGEPAGE_MIGRATION
 	def_bool y
 	depends on X86_64 && HUGETLB_PAGE && MIGRATION
--- linux-ein-5.4.0.orig/arch/x86/Kconfig.cpu
+++ linux-ein-5.4.0/arch/x86/Kconfig.cpu
@@ -372,7 +372,7 @@
 config X86_MINIMUM_CPU_FAMILY
 	int
 	default "64" if X86_64
-	default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCRUSOE || MCORE2 || MK7 || MK8)
+	default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCORE2 || MK7 || MK8)
 	default "5" if X86_32 && X86_CMPXCHG64
 	default "4"
 
--- linux-ein-5.4.0.orig/arch/x86/Makefile
+++ linux-ein-5.4.0/arch/x86/Makefile
@@ -34,12 +34,13 @@
 REALMODE_CFLAGS	:= $(M16_CFLAGS) -g -Os -DDISABLE_BRANCH_PROFILING \
 		   -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
 		   -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
-		   -mno-mmx -mno-sse
+		   -mno-mmx -mno-sse $(call cc-option,-fcf-protection=none)
 
 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))
+REALMODE_CFLAGS += $(CLANG_FLAGS)
 export REALMODE_CFLAGS
 
 # BITS is used as extension for files which are available in a 32 bit
@@ -61,6 +62,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
--- linux-ein-5.4.0.orig/arch/x86/boot/Makefile
+++ linux-ein-5.4.0/arch/x86/boot/Makefile
@@ -87,7 +87,7 @@
 
 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
@@ -100,7 +100,7 @@
 AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
-LDFLAGS_setup.elf	:= -m elf_i386 -T
+LDFLAGS_setup.elf	:= -m elf_i386 -z noexecstack -T
 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
 	$(call if_changed,ld)
 
--- linux-ein-5.4.0.orig/arch/x86/boot/bioscall.S
+++ linux-ein-5.4.0/arch/x86/boot/bioscall.S
@@ -32,7 +32,7 @@
 	movw	%dx, %si
 	movw	%sp, %di
 	movw	$11, %cx
-	rep; movsd
+	rep; movsl
 
 	/* Pop full state from the stack */
 	popal
@@ -67,7 +67,7 @@
 	jz	4f
 	movw	%sp, %si
 	movw	$11, %cx
-	rep; movsd
+	rep; movsl
 4:	addw	$44, %sp
 
 	/* Restore state and return */
--- linux-ein-5.4.0.orig/arch/x86/boot/boot.h
+++ linux-ein-5.4.0/arch/x86/boot/boot.h
@@ -110,66 +110,78 @@
 
 static inline u8 rdfs8(addr_t addr)
 {
+	u8 *ptr = (u8 *)absolute_pointer(addr);
 	u8 v;
-	asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
+	asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*ptr));
 	return v;
 }
 static inline u16 rdfs16(addr_t addr)
 {
+	u16 *ptr = (u16 *)absolute_pointer(addr);
 	u16 v;
-	asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+	asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
 	return v;
 }
 static inline u32 rdfs32(addr_t addr)
 {
+	u32 *ptr = (u32 *)absolute_pointer(addr);
 	u32 v;
-	asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+	asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
 	return v;
 }
 
 static inline void wrfs8(u8 v, addr_t addr)
 {
-	asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
+	u8 *ptr = (u8 *)absolute_pointer(addr);
+	asm volatile("movb %1,%%fs:%0" : "+m" (*ptr) : "qi" (v));
 }
 static inline void wrfs16(u16 v, addr_t addr)
 {
-	asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
+	u16 *ptr = (u16 *)absolute_pointer(addr);
+	asm volatile("movw %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
 }
 static inline void wrfs32(u32 v, addr_t addr)
 {
-	asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
+	u32 *ptr = (u32 *)absolute_pointer(addr);
+	asm volatile("movl %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
 }
 
 static inline u8 rdgs8(addr_t addr)
 {
+	u8 *ptr = (u8 *)absolute_pointer(addr);
 	u8 v;
-	asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
+	asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*ptr));
 	return v;
 }
 static inline u16 rdgs16(addr_t addr)
 {
+	u16 *ptr = (u16 *)absolute_pointer(addr);
 	u16 v;
-	asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+	asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
 	return v;
 }
 static inline u32 rdgs32(addr_t addr)
 {
+	u32 *ptr = (u32 *)absolute_pointer(addr);
 	u32 v;
-	asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+	asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
 	return v;
 }
 
 static inline void wrgs8(u8 v, addr_t addr)
 {
-	asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
+	u8 *ptr = (u8 *)absolute_pointer(addr);
+	asm volatile("movb %1,%%gs:%0" : "+m" (*ptr) : "qi" (v));
 }
 static inline void wrgs16(u16 v, addr_t addr)
 {
-	asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
+	u16 *ptr = (u16 *)absolute_pointer(addr);
+	asm volatile("movw %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
 }
 static inline void wrgs32(u32 v, addr_t addr)
 {
-	asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
+	u32 *ptr = (u32 *)absolute_pointer(addr);
+	asm volatile("movl %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
 }
 
 /* Note: these only return true/false, not a signed return value! */
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/Makefile
+++ linux-ein-5.4.0/arch/x86/boot/compressed/Makefile
@@ -38,6 +38,8 @@
 KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
 KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
 KBUILD_CFLAGS += -Wno-pointer-sign
+# 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
@@ -55,6 +57,10 @@
 KBUILD_LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
 	&& echo "-z noreloc-overflow -pie --no-dynamic-linker")
 endif
+
+KBUILD_LDFLAGS += -z noexecstack
+KBUILD_LDFLAGS += $(call ld-option,--no-warn-rwx-segments)
+
 LDFLAGS_vmlinux := -T
 
 hostprogs-y	:= mkpiggy
@@ -102,7 +108,7 @@
 quiet_cmd_check_data_rel = DATAREL $@
 define cmd_check_data_rel
 	for obj in $(filter %.o,$^); do \
-		${CROSS_COMPILE}readelf -S $$obj | grep -qF .rel.local && { \
+		$(READELF) -S $$obj | grep -qF .rel.local && { \
 			echo "error: $$obj has data relocations!" >&2; \
 			exit 1; \
 		} || true; \
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/acpi.c
+++ linux-ein-5.4.0/arch/x86/boot/compressed/acpi.c
@@ -393,7 +393,13 @@
 	table = table_addr + sizeof(struct acpi_table_srat);
 
 	while (table + sizeof(struct acpi_subtable_header) < table_end) {
+
 		sub_table = (struct acpi_subtable_header *)table;
+		if (!sub_table->length) {
+			debug_putstr("Invalid zero length SRAT subtable.\n");
+			return 0;
+		}
+
 		if (sub_table->type == ACPI_SRAT_TYPE_MEMORY_AFFINITY) {
 			struct acpi_srat_mem_affinity *ma;
 
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/head_32.S
+++ linux-ein-5.4.0/arch/x86/boot/compressed/head_32.S
@@ -49,16 +49,17 @@
  * 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
+ * _bss, _ebss, _got, _egot and _end, 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
+ * R_386_RELATIVE relocations, we mark _bss, _ebss, _got, _egot and _end as
  * hidden:
  */
 	.hidden _bss
 	.hidden _ebss
 	.hidden _got
 	.hidden _egot
+	.hidden _end
 
 	__HEAD
 ENTRY(startup_32)
@@ -106,7 +107,7 @@
 	notl	%eax
 	andl    %eax, %ebx
 	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
-	jge	1f
+	jae	1f
 #endif
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
 1:
@@ -209,7 +210,7 @@
 #endif
 
 	.text
-.Lrelocated:
+SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
 
 /*
  * Clear BSS (stack is currently empty)
@@ -260,6 +261,7 @@
  */
 	xorl	%ebx, %ebx
 	jmp	*%eax
+SYM_FUNC_END(.Lrelocated)
 
 #ifdef CONFIG_EFI_STUB
 	.data
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/head_64.S
+++ linux-ein-5.4.0/arch/x86/boot/compressed/head_64.S
@@ -42,6 +42,7 @@
 	.hidden _ebss
 	.hidden _got
 	.hidden _egot
+	.hidden _end
 
 	__HEAD
 	.code32
@@ -106,7 +107,7 @@
 	notl	%eax
 	andl	%eax, %ebx
 	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
-	jge	1f
+	jae	1f
 #endif
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
 1:
@@ -244,6 +245,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
@@ -292,7 +298,7 @@
 	notq	%rax
 	andq	%rax, %rbp
 	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
-	jge	1f
+	jae	1f
 #endif
 	movq	$LOAD_PHYSICAL_ADDR, %rbp
 1:
@@ -375,11 +381,25 @@
 	/* Save the trampoline address in RCX */
 	movq	%rax, %rcx
 
+	/* Set up 32-bit addressable stack */
+	leaq	TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp
+
 	/*
-	 * Load the address of trampoline_return() into RDI.
-	 * It will be used by the trampoline to return to the main code.
+	 * Preserve live 64-bit registers on the stack: this is necessary
+	 * because the architecture does not guarantee that GPRs will retain
+	 * their full 64-bit values across a 32-bit mode switch.
+	 */
+	pushq	%rbp
+	pushq	%rbx
+	pushq	%rsi
+
+	/*
+	 * Push the 64-bit address of trampoline_return() onto the new stack.
+	 * It will be used by the trampoline to return to the main code. Due to
+	 * the 32-bit mode switch, it cannot be kept it in a register either.
 	 */
 	leaq	trampoline_return(%rip), %rdi
+	pushq	%rdi
 
 	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
 	pushq	$__KERNEL32_CS
@@ -387,6 +407,11 @@
 	pushq	%rax
 	lretq
 trampoline_return:
+	/* Restore live 64-bit registers */
+	popq	%rsi
+	popq	%rbx
+	popq	%rbp
+
 	/* Restore the stack, the 32-bit trampoline uses its own stack */
 	leaq	boot_stack_end(%rbx), %rsp
 
@@ -511,7 +536,7 @@
 #endif
 
 	.text
-.Lrelocated:
+SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
 
 /*
  * Clear BSS (stack is currently empty)
@@ -540,6 +565,7 @@
  * Jump to the decompressed kernel.
  */
 	jmp	*%rax
+SYM_FUNC_END(.Lrelocated)
 
 /*
  * Adjust the global offset table
@@ -566,7 +592,7 @@
 /*
  * This is the 32-bit trampoline that will be copied over to low memory.
  *
- * RDI contains the return address (might be above 4G).
+ * Return address is at the top of the stack (might be above 4G).
  * ECX contains the base address of the trampoline memory.
  * Non zero RDX means trampoline needs to enable 5-level paging.
  */
@@ -576,9 +602,6 @@
 	movl	%eax, %ds
 	movl	%eax, %ss
 
-	/* Set up new stack */
-	leal	TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
-
 	/* Disable paging */
 	movl	%cr0, %eax
 	btrl	$X86_CR0_PG_BIT, %eax
@@ -635,9 +658,10 @@
 	lret
 
 	.code64
-.Lpaging_enabled:
+SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
 	/* Return from the trampoline */
-	jmp	*%rdi
+	retq
+SYM_FUNC_END(.Lpaging_enabled)
 
 	/*
          * The trampoline code has a size limit.
@@ -647,11 +671,12 @@
 	.org	trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
 
 	.code32
-.Lno_longmode:
+SYM_FUNC_START_LOCAL_NOALIGN(.Lno_longmode)
 	/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
 1:
 	hlt
 	jmp     1b
+SYM_FUNC_END(.Lno_longmode)
 
 #include "../../kernel/verify_cpu.S"
 
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/kaslr_64.c
+++ linux-ein-5.4.0/arch/x86/boot/compressed/kaslr_64.c
@@ -29,9 +29,6 @@
 #define __PAGE_OFFSET __PAGE_OFFSET_BASE
 #include "../../mm/ident_map.c"
 
-/* Used by pgtable.h asm code to force instruction serialization. */
-unsigned long __force_order;
-
 /* Used to track our page table allocation area. */
 struct alloc_pgt_data {
 	unsigned char *pgt_buf;
--- linux-ein-5.4.0.orig/arch/x86/boot/compressed/pgtable_64.c
+++ linux-ein-5.4.0/arch/x86/boot/compressed/pgtable_64.c
@@ -5,15 +5,6 @@
 #include "pgtable.h"
 #include "../string.h"
 
-/*
- * __force_order is used by special_insns.h asm code to force instruction
- * serialization.
- *
- * It is not referenced from the code, but GCC < 5 with -fPIE would fail
- * due to an undefined symbol. Define it to make these ancient GCCs work.
- */
-unsigned long __force_order;
-
 #define BIOS_START_MIN		0x20000U	/* 128K, less than this is insane */
 #define BIOS_START_MAX		0x9f000U	/* 640K, absolute maximum */
 
--- linux-ein-5.4.0.orig/arch/x86/boot/main.c
+++ linux-ein-5.4.0/arch/x86/boot/main.c
@@ -33,7 +33,7 @@
 		u16 cl_offset;
 	};
 	const struct old_cmdline * const oldcmd =
-		(const struct old_cmdline *)OLD_CL_ADDRESS;
+		absolute_pointer(OLD_CL_ADDRESS);
 
 	BUILD_BUG_ON(sizeof(boot_params) != 4096);
 	memcpy(&boot_params.hdr, &hdr, sizeof(hdr));
--- linux-ein-5.4.0.orig/arch/x86/boot/pmjump.S
+++ linux-ein-5.4.0/arch/x86/boot/pmjump.S
@@ -40,13 +40,13 @@
 
 	# Transition to 32-bit mode
 	.byte	0x66, 0xea		# ljmpl opcode
-2:	.long	in_pm32			# offset
+2:	.long	.Lin_pm32		# offset
 	.word	__BOOT_CS		# segment
 ENDPROC(protected_mode_jump)
 
 	.code32
 	.section ".text32","ax"
-GLOBAL(in_pm32)
+SYM_FUNC_START_LOCAL_NOALIGN(.Lin_pm32)
 	# Set up data segments for flat 32-bit mode
 	movl	%ecx, %ds
 	movl	%ecx, %es
@@ -72,4 +72,4 @@
 	lldt	%cx
 
 	jmpl	*%eax			# Jump to the 32-bit entrypoint
-ENDPROC(in_pm32)
+SYM_FUNC_END(.Lin_pm32)
--- linux-ein-5.4.0.orig/arch/x86/boot/setup.ld
+++ linux-ein-5.4.0/arch/x86/boot/setup.ld
@@ -20,7 +20,7 @@
 	.initdata	: { *(.initdata) }
 	__end_init = .;
 
-	.text		: { *(.text) }
+	.text		: { *(.text .text.*) }
 	.text32		: { *(.text32) }
 
 	. = ALIGN(16);
--- linux-ein-5.4.0.orig/arch/x86/boot/video-vga.c
+++ linux-ein-5.4.0/arch/x86/boot/video-vga.c
@@ -188,7 +188,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-ein-5.4.0.orig/arch/x86/configs/i386_defconfig
+++ linux-ein-5.4.0/arch/x86/configs/i386_defconfig
@@ -137,7 +137,6 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SPI_ATTRS=y
@@ -205,7 +204,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
--- linux-ein-5.4.0.orig/arch/x86/configs/x86_64_defconfig
+++ linux-ein-5.4.0/arch/x86/configs/x86_64_defconfig
@@ -136,7 +136,6 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SPI_ATTRS=y
@@ -201,7 +200,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
--- linux-ein-5.4.0.orig/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
+++ linux-ein-5.4.0/arch/x86/crypto/aes_ctrby8_avx-x86_64.S
@@ -127,10 +127,6 @@
 
 /* generate a unique variable for ddq_add_x */
 
-.macro setddq n
-	var_ddq_add = ddq_add_\n
-.endm
-
 /* generate a unique variable for xmm register */
 .macro setxdata n
 	var_xdata = %xmm\n
@@ -140,9 +136,7 @@
 
 .macro club name, id
 .altmacro
-	.if \name == DDQ_DATA
-		setddq %\id
-	.elseif \name == XDATA
+	.if \name == XDATA
 		setxdata %\id
 	.endif
 .noaltmacro
@@ -165,9 +159,8 @@
 
 	.set i, 1
 	.rept (by - 1)
-		club DDQ_DATA, i
 		club XDATA, i
-		vpaddq	var_ddq_add(%rip), xcounter, var_xdata
+		vpaddq	(ddq_add_1 + 16 * (i - 1))(%rip), xcounter, var_xdata
 		vptest	ddq_low_msk(%rip), var_xdata
 		jnz 1f
 		vpaddq	ddq_high_add_1(%rip), var_xdata, var_xdata
@@ -180,8 +173,7 @@
 	vmovdqa	1*16(p_keys), xkeyA
 
 	vpxor	xkey0, xdata0, xdata0
-	club DDQ_DATA, by
-	vpaddq	var_ddq_add(%rip), xcounter, xcounter
+	vpaddq	(ddq_add_1 + 16 * (by - 1))(%rip), xcounter, xcounter
 	vptest	ddq_low_msk(%rip), xcounter
 	jnz	1f
 	vpaddq	ddq_high_add_1(%rip), xcounter, xcounter
--- linux-ein-5.4.0.orig/arch/x86/crypto/aesni-intel_asm.S
+++ linux-ein-5.4.0/arch/x86/crypto/aesni-intel_asm.S
@@ -266,7 +266,7 @@
 	PSHUFB_XMM %xmm2, %xmm0
 	movdqu %xmm0, CurCount(%arg2) # ctx_data.current_counter = iv
 
-	PRECOMPUTE \SUBKEY, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7,
+	PRECOMPUTE \SUBKEY, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7
 	movdqu HashKey(%arg2), %xmm13
 
 	CALC_AAD_HASH %xmm13, \AAD, \AADLEN, %xmm0, %xmm1, %xmm2, %xmm3, \
@@ -319,7 +319,7 @@
 
 	# Main loop - Encrypt/Decrypt remaining blocks
 
-	cmp	$0, %r13
+	test	%r13, %r13
 	je	_zero_cipher_left_\@
 	sub	$64, %r13
 	je	_four_cipher_left_\@
@@ -438,7 +438,7 @@
 
 	mov PBlockLen(%arg2), %r12
 
-	cmp $0, %r12
+	test %r12, %r12
 	je _partial_done\@
 
 	GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
@@ -475,7 +475,7 @@
 	add	$8, %r10
 	sub	$8, %r11
 	psrldq	$8, %xmm0
-	cmp	$0, %r11
+	test	%r11, %r11
 	je	_return_T_done_\@
 _T_4_\@:
 	movd	%xmm0, %eax
@@ -483,7 +483,7 @@
 	add	$4, %r10
 	sub	$4, %r11
 	psrldq	$4, %xmm0
-	cmp	$0, %r11
+	test	%r11, %r11
 	je	_return_T_done_\@
 _T_123_\@:
 	movd	%xmm0, %eax
@@ -620,7 +620,7 @@
 
 	/* read the last <16B of AAD */
 _get_AAD_rest\@:
-	cmp	   $0, %r11
+	test	   %r11, %r11
 	je	   _get_AAD_done\@
 
 	READ_PARTIAL_BLOCK %r10, %r11, \TMP1, \TMP7
@@ -641,7 +641,7 @@
 .macro PARTIAL_BLOCK CYPH_PLAIN_OUT PLAIN_CYPH_IN PLAIN_CYPH_LEN DATA_OFFSET \
 	AAD_HASH operation
 	mov 	PBlockLen(%arg2), %r13
-	cmp	$0, %r13
+	test	%r13, %r13
 	je	_partial_block_done_\@	# Leave Macro if no partial blocks
 	# Read in input data without over reading
 	cmp	$16, \PLAIN_CYPH_LEN
@@ -693,7 +693,7 @@
 	PSHUFB_XMM	%xmm2, %xmm3
 	pxor	%xmm3, \AAD_HASH
 
-	cmp	$0, %r10
+	test	%r10, %r10
 	jl	_partial_incomplete_1_\@
 
 	# GHASH computation for the last <16 Byte block
@@ -728,7 +728,7 @@
 	PSHUFB_XMM %xmm2, %xmm9
 	pxor	%xmm9, \AAD_HASH
 
-	cmp	$0, %r10
+	test	%r10, %r10
 	jl	_partial_incomplete_2_\@
 
 	# GHASH computation for the last <16 Byte block
@@ -748,7 +748,7 @@
 	PSHUFB_XMM	%xmm2, %xmm9
 .endif
 	# output encrypted Bytes
-	cmp	$0, %r10
+	test	%r10, %r10
 	jl	_partial_fill_\@
 	mov	%r13, %r12
 	mov	$16, %r13
@@ -978,7 +978,7 @@
 * arg1, %arg3, %arg4 are used as pointers only, not modified
 * %r11 is the data offset value
 */
-.macro GHASH_4_ENCRYPT_4_PARALLEL_ENC TMP1 TMP2 TMP3 TMP4 TMP5 \
+.macro GHASH_4_ENCRYPT_4_PARALLEL_enc TMP1 TMP2 TMP3 TMP4 TMP5 \
 TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
 
 	movdqa	  \XMM1, \XMM5
@@ -1186,7 +1186,7 @@
 * arg1, %arg3, %arg4 are used as pointers only, not modified
 * %r11 is the data offset value
 */
-.macro GHASH_4_ENCRYPT_4_PARALLEL_DEC TMP1 TMP2 TMP3 TMP4 TMP5 \
+.macro GHASH_4_ENCRYPT_4_PARALLEL_dec TMP1 TMP2 TMP3 TMP4 TMP5 \
 TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
 
 	movdqa	  \XMM1, \XMM5
@@ -1946,7 +1946,7 @@
 ENDPROC(aesni_set_key)
 
 /*
- * void aesni_enc(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+ * void aesni_enc(const void *ctx, u8 *dst, const u8 *src)
  */
 ENTRY(aesni_enc)
 	FRAME_BEGIN
@@ -2137,7 +2137,7 @@
 ENDPROC(_aesni_enc4)
 
 /*
- * void aesni_dec (struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
+ * void aesni_dec (const void *ctx, u8 *dst, const u8 *src)
  */
 ENTRY(aesni_dec)
 	FRAME_BEGIN
@@ -2726,25 +2726,18 @@
 	pxor CTR, IV;
 
 /*
- * void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
- *			 bool enc, u8 *iv)
+ * void aesni_xts_encrypt(const struct crypto_aes_ctx *ctx, u8 *dst,
+ *			  const u8 *src, unsigned int len, le128 *iv)
  */
-ENTRY(aesni_xts_crypt8)
+ENTRY(aesni_xts_encrypt)
 	FRAME_BEGIN
-	cmpb $0, %cl
-	movl $0, %ecx
-	movl $240, %r10d
-	leaq _aesni_enc4, %r11
-	leaq _aesni_dec4, %rax
-	cmovel %r10d, %ecx
-	cmoveq %rax, %r11
 
 	movdqa .Lgf128mul_x_ble_mask, GF128MUL_MASK
 	movups (IVP), IV
 
 	mov 480(KEYP), KLEN
-	addq %rcx, KEYP
 
+.Lxts_enc_loop4:
 	movdqa IV, STATE1
 	movdqu 0x00(INP), INC
 	pxor INC, STATE1
@@ -2768,71 +2761,103 @@
 	pxor INC, STATE4
 	movdqu IV, 0x30(OUTP)
 
-	CALL_NOSPEC %r11
+	call _aesni_enc4
 
 	movdqu 0x00(OUTP), INC
 	pxor INC, STATE1
 	movdqu STATE1, 0x00(OUTP)
 
-	_aesni_gf128mul_x_ble()
-	movdqa IV, STATE1
-	movdqu 0x40(INP), INC
-	pxor INC, STATE1
-	movdqu IV, 0x40(OUTP)
-
 	movdqu 0x10(OUTP), INC
 	pxor INC, STATE2
 	movdqu STATE2, 0x10(OUTP)
 
-	_aesni_gf128mul_x_ble()
-	movdqa IV, STATE2
-	movdqu 0x50(INP), INC
-	pxor INC, STATE2
-	movdqu IV, 0x50(OUTP)
-
 	movdqu 0x20(OUTP), INC
 	pxor INC, STATE3
 	movdqu STATE3, 0x20(OUTP)
 
-	_aesni_gf128mul_x_ble()
-	movdqa IV, STATE3
-	movdqu 0x60(INP), INC
-	pxor INC, STATE3
-	movdqu IV, 0x60(OUTP)
-
 	movdqu 0x30(OUTP), INC
 	pxor INC, STATE4
 	movdqu STATE4, 0x30(OUTP)
 
 	_aesni_gf128mul_x_ble()
-	movdqa IV, STATE4
-	movdqu 0x70(INP), INC
-	pxor INC, STATE4
-	movdqu IV, 0x70(OUTP)
 
-	_aesni_gf128mul_x_ble()
+	add $64, INP
+	add $64, OUTP
+	sub $64, LEN
+	ja .Lxts_enc_loop4
+
 	movups IV, (IVP)
 
-	CALL_NOSPEC %r11
+	FRAME_END
+	ret
+ENDPROC(aesni_xts_encrypt)
+
+/*
+ * void aesni_xts_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst,
+ *			  const u8 *src, unsigned int len, le128 *iv)
+ */
+ENTRY(aesni_xts_decrypt)
+	FRAME_BEGIN
+
+	movdqa .Lgf128mul_x_ble_mask, GF128MUL_MASK
+	movups (IVP), IV
+
+	mov 480(KEYP), KLEN
+	add $240, KEYP
 
-	movdqu 0x40(OUTP), INC
+.Lxts_dec_loop4:
+	movdqa IV, STATE1
+	movdqu 0x00(INP), INC
 	pxor INC, STATE1
-	movdqu STATE1, 0x40(OUTP)
+	movdqu IV, 0x00(OUTP)
 
-	movdqu 0x50(OUTP), INC
+	_aesni_gf128mul_x_ble()
+	movdqa IV, STATE2
+	movdqu 0x10(INP), INC
+	pxor INC, STATE2
+	movdqu IV, 0x10(OUTP)
+
+	_aesni_gf128mul_x_ble()
+	movdqa IV, STATE3
+	movdqu 0x20(INP), INC
+	pxor INC, STATE3
+	movdqu IV, 0x20(OUTP)
+
+	_aesni_gf128mul_x_ble()
+	movdqa IV, STATE4
+	movdqu 0x30(INP), INC
+	pxor INC, STATE4
+	movdqu IV, 0x30(OUTP)
+
+	call _aesni_dec4
+
+	movdqu 0x00(OUTP), INC
+	pxor INC, STATE1
+	movdqu STATE1, 0x00(OUTP)
+
+	movdqu 0x10(OUTP), INC
 	pxor INC, STATE2
-	movdqu STATE2, 0x50(OUTP)
+	movdqu STATE2, 0x10(OUTP)
 
-	movdqu 0x60(OUTP), INC
+	movdqu 0x20(OUTP), INC
 	pxor INC, STATE3
-	movdqu STATE3, 0x60(OUTP)
+	movdqu STATE3, 0x20(OUTP)
 
-	movdqu 0x70(OUTP), INC
+	movdqu 0x30(OUTP), INC
 	pxor INC, STATE4
-	movdqu STATE4, 0x70(OUTP)
+	movdqu STATE4, 0x30(OUTP)
+
+	_aesni_gf128mul_x_ble()
+
+	add $64, INP
+	add $64, OUTP
+	sub $64, LEN
+	ja .Lxts_dec_loop4
+
+	movups IV, (IVP)
 
 	FRAME_END
 	ret
-ENDPROC(aesni_xts_crypt8)
+ENDPROC(aesni_xts_decrypt)
 
 #endif
--- linux-ein-5.4.0.orig/arch/x86/crypto/aesni-intel_avx-x86_64.S
+++ linux-ein-5.4.0/arch/x86/crypto/aesni-intel_avx-x86_64.S
@@ -370,7 +370,7 @@
 
 
 _initial_blocks_encrypted\@:
-        cmp     $0, %r13
+        test    %r13, %r13
         je      _zero_cipher_left\@
 
         sub     $128, %r13
@@ -529,7 +529,7 @@
         vmovdqu HashKey(arg2), %xmm13
 
         mov PBlockLen(arg2), %r12
-        cmp $0, %r12
+        test %r12, %r12
         je _partial_done\@
 
 	#GHASH computation for the last <16 Byte block
@@ -574,7 +574,7 @@
         add     $8, %r10
         sub     $8, %r11
         vpsrldq $8, %xmm9, %xmm9
-        cmp     $0, %r11
+        test    %r11, %r11
         je     _return_T_done\@
 _T_4\@:
         vmovd   %xmm9, %eax
@@ -582,7 +582,7 @@
         add     $4, %r10
         sub     $4, %r11
         vpsrldq     $4, %xmm9, %xmm9
-        cmp     $0, %r11
+        test    %r11, %r11
         je     _return_T_done\@
 _T_123\@:
         vmovd     %xmm9, %eax
@@ -626,7 +626,7 @@
 	cmp     $16, %r11
 	jge     _get_AAD_blocks\@
 	vmovdqu \T8, \T7
-	cmp     $0, %r11
+	test    %r11, %r11
 	je      _get_AAD_done\@
 
 	vpxor   \T7, \T7, \T7
@@ -645,7 +645,7 @@
 	vpxor   \T1, \T7, \T7
 	jmp     _get_AAD_rest8\@
 _get_AAD_rest4\@:
-	cmp     $0, %r11
+	test    %r11, %r11
 	jle      _get_AAD_rest0\@
 	mov     (%r10), %eax
 	movq    %rax, \T1
@@ -750,7 +750,7 @@
 .macro PARTIAL_BLOCK GHASH_MUL CYPH_PLAIN_OUT PLAIN_CYPH_IN PLAIN_CYPH_LEN DATA_OFFSET \
         AAD_HASH ENC_DEC
         mov 	PBlockLen(arg2), %r13
-        cmp	$0, %r13
+        test	%r13, %r13
         je	_partial_block_done_\@	# Leave Macro if no partial blocks
         # Read in input data without over reading
         cmp	$16, \PLAIN_CYPH_LEN
@@ -802,7 +802,7 @@
         vpshufb	%xmm2, %xmm3, %xmm3
         vpxor	%xmm3, \AAD_HASH, \AAD_HASH
 
-        cmp	$0, %r10
+        test	%r10, %r10
         jl	_partial_incomplete_1_\@
 
         # GHASH computation for the last <16 Byte block
@@ -837,7 +837,7 @@
         vpshufb %xmm2, %xmm9, %xmm9
         vpxor	%xmm9, \AAD_HASH, \AAD_HASH
 
-        cmp	$0, %r10
+        test	%r10, %r10
         jl	_partial_incomplete_2_\@
 
         # GHASH computation for the last <16 Byte block
@@ -857,7 +857,7 @@
         vpshufb	%xmm2, %xmm9, %xmm9
 .endif
         # output encrypted Bytes
-        cmp	$0, %r10
+        test	%r10, %r10
         jl	_partial_fill_\@
         mov	%r13, %r12
         mov	$16, %r13
--- linux-ein-5.4.0.orig/arch/x86/crypto/aesni-intel_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/aesni-intel_glue.c
@@ -83,10 +83,8 @@
 
 asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
 			     unsigned int key_len);
-asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out,
-			  const u8 *in);
-asmlinkage void aesni_dec(struct crypto_aes_ctx *ctx, u8 *out,
-			  const u8 *in);
+asmlinkage void aesni_enc(const void *ctx, u8 *out, const u8 *in);
+asmlinkage void aesni_dec(const void *ctx, u8 *out, const u8 *in);
 asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out,
 			      const u8 *in, unsigned int len);
 asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out,
@@ -99,6 +97,12 @@
 #define AVX_GEN2_OPTSIZE 640
 #define AVX_GEN4_OPTSIZE 4096
 
+asmlinkage void aesni_xts_encrypt(const struct crypto_aes_ctx *ctx, u8 *out,
+				  const u8 *in, unsigned int len, u8 *iv);
+
+asmlinkage void aesni_xts_decrypt(const struct crypto_aes_ctx *ctx, u8 *out,
+				  const u8 *in, unsigned int len, u8 *iv);
+
 #ifdef CONFIG_X86_64
 
 static void (*aesni_ctr_enc_tfm)(struct crypto_aes_ctx *ctx, u8 *out,
@@ -106,9 +110,6 @@
 asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out,
 			      const u8 *in, unsigned int len, u8 *iv);
 
-asmlinkage void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, u8 *out,
-				 const u8 *in, bool enc, u8 *iv);
-
 /* asmlinkage void aesni_gcm_enc()
  * void *ctx,  AES Key schedule. Starts on a 16 byte boundary.
  * struct gcm_context_data.  May be uninitialized.
@@ -550,29 +551,24 @@
 }
 
 
-static void aesni_xts_tweak(void *ctx, u8 *out, const u8 *in)
-{
-	aesni_enc(ctx, out, in);
-}
-
-static void aesni_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void aesni_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv, GLUE_FUNC_CAST(aesni_enc));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, aesni_enc);
 }
 
-static void aesni_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void aesni_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv, GLUE_FUNC_CAST(aesni_dec));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, aesni_dec);
 }
 
-static void aesni_xts_enc8(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void aesni_xts_enc32(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	aesni_xts_crypt8(ctx, (u8 *)dst, (const u8 *)src, true, (u8 *)iv);
+	aesni_xts_encrypt(ctx, dst, src, 32 * AES_BLOCK_SIZE, (u8 *)iv);
 }
 
-static void aesni_xts_dec8(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void aesni_xts_dec32(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	aesni_xts_crypt8(ctx, (u8 *)dst, (const u8 *)src, false, (u8 *)iv);
+	aesni_xts_decrypt(ctx, dst, src, 32 * AES_BLOCK_SIZE, (u8 *)iv);
 }
 
 static const struct common_glue_ctx aesni_enc_xts = {
@@ -580,11 +576,11 @@
 	.fpu_blocks_limit = 1,
 
 	.funcs = { {
-		.num_blocks = 8,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_enc8) }
+		.num_blocks = 32,
+		.fn_u = { .xts = aesni_xts_enc32 }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_enc) }
+		.fn_u = { .xts = aesni_xts_enc }
 	} }
 };
 
@@ -593,11 +589,11 @@
 	.fpu_blocks_limit = 1,
 
 	.funcs = { {
-		.num_blocks = 8,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_dec8) }
+		.num_blocks = 32,
+		.fn_u = { .xts = aesni_xts_dec32 }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_dec) }
+		.fn_u = { .xts = aesni_xts_dec }
 	} }
 };
 
@@ -606,8 +602,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct aesni_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&aesni_enc_xts, req,
-				   XTS_TWEAK_CAST(aesni_xts_tweak),
+	return glue_xts_req_128bit(&aesni_enc_xts, req, aesni_enc,
 				   aes_ctx(ctx->raw_tweak_ctx),
 				   aes_ctx(ctx->raw_crypt_ctx),
 				   false);
@@ -618,8 +613,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct aesni_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&aesni_dec_xts, req,
-				   XTS_TWEAK_CAST(aesni_xts_tweak),
+	return glue_xts_req_128bit(&aesni_dec_xts, req, aesni_enc,
 				   aes_ctx(ctx->raw_tweak_ctx),
 				   aes_ctx(ctx->raw_crypt_ctx),
 				   true);
@@ -707,7 +701,8 @@
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	unsigned long auth_tag_len = crypto_aead_authsize(tfm);
 	const struct aesni_gcm_tfm_s *gcm_tfm = aesni_gcm_tfm;
-	struct gcm_context_data data AESNI_ALIGN_ATTR;
+	u8 databuf[sizeof(struct gcm_context_data) + (AESNI_ALIGN - 8)] __aligned(8);
+	struct gcm_context_data *data = PTR_ALIGN((void *)databuf, AESNI_ALIGN);
 	struct scatter_walk dst_sg_walk = {};
 	unsigned long left = req->cryptlen;
 	unsigned long len, srclen, dstlen;
@@ -760,8 +755,7 @@
 	}
 
 	kernel_fpu_begin();
-	gcm_tfm->init(aes_ctx, &data, iv,
-		hash_subkey, assoc, assoclen);
+	gcm_tfm->init(aes_ctx, data, iv, hash_subkey, assoc, assoclen);
 	if (req->src != req->dst) {
 		while (left) {
 			src = scatterwalk_map(&src_sg_walk);
@@ -771,10 +765,10 @@
 			len = min(srclen, dstlen);
 			if (len) {
 				if (enc)
-					gcm_tfm->enc_update(aes_ctx, &data,
+					gcm_tfm->enc_update(aes_ctx, data,
 							     dst, src, len);
 				else
-					gcm_tfm->dec_update(aes_ctx, &data,
+					gcm_tfm->dec_update(aes_ctx, data,
 							     dst, src, len);
 			}
 			left -= len;
@@ -792,10 +786,10 @@
 			len = scatterwalk_clamp(&src_sg_walk, left);
 			if (len) {
 				if (enc)
-					gcm_tfm->enc_update(aes_ctx, &data,
+					gcm_tfm->enc_update(aes_ctx, data,
 							     src, src, len);
 				else
-					gcm_tfm->dec_update(aes_ctx, &data,
+					gcm_tfm->dec_update(aes_ctx, data,
 							     src, src, len);
 			}
 			left -= len;
@@ -804,7 +798,7 @@
 			scatterwalk_done(&src_sg_walk, 1, left);
 		}
 	}
-	gcm_tfm->finalize(aes_ctx, &data, authTag, auth_tag_len);
+	gcm_tfm->finalize(aes_ctx, data, authTag, auth_tag_len);
 	kernel_fpu_end();
 
 	if (!assocmem)
@@ -853,7 +847,8 @@
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
 	void *aes_ctx = &(ctx->aes_key_expanded);
-	u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+	u8 ivbuf[16 + (AESNI_ALIGN - 8)] __aligned(8);
+	u8 *iv = PTR_ALIGN(&ivbuf[0], AESNI_ALIGN);
 	unsigned int i;
 	__be32 counter = cpu_to_be32(1);
 
@@ -880,7 +875,8 @@
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
 	void *aes_ctx = &(ctx->aes_key_expanded);
-	u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+	u8 ivbuf[16 + (AESNI_ALIGN - 8)] __aligned(8);
+	u8 *iv = PTR_ALIGN(&ivbuf[0], AESNI_ALIGN);
 	unsigned int i;
 
 	if (unlikely(req->assoclen != 16 && req->assoclen != 20))
@@ -1010,7 +1006,8 @@
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct generic_gcmaes_ctx *ctx = generic_gcmaes_ctx_get(tfm);
 	void *aes_ctx = &(ctx->aes_key_expanded);
-	u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+	u8 ivbuf[16 + (AESNI_ALIGN - 8)] __aligned(8);
+	u8 *iv = PTR_ALIGN(&ivbuf[0], AESNI_ALIGN);
 	__be32 counter = cpu_to_be32(1);
 
 	memcpy(iv, req->iv, 12);
@@ -1026,7 +1023,8 @@
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct generic_gcmaes_ctx *ctx = generic_gcmaes_ctx_get(tfm);
 	void *aes_ctx = &(ctx->aes_key_expanded);
-	u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+	u8 ivbuf[16 + (AESNI_ALIGN - 8)] __aligned(8);
+	u8 *iv = PTR_ALIGN(&ivbuf[0], AESNI_ALIGN);
 
 	memcpy(iv, req->iv, 12);
 	*((__be32 *)(iv+12)) = counter;
--- linux-ein-5.4.0.orig/arch/x86/crypto/camellia_aesni_avx2_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/camellia_aesni_avx2_glue.c
@@ -19,20 +19,17 @@
 #define CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS 32
 
 /* 32-way AVX2/AES-NI parallel cipher functions */
-asmlinkage void camellia_ecb_enc_32way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-asmlinkage void camellia_ecb_dec_32way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-
-asmlinkage void camellia_cbc_dec_32way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-asmlinkage void camellia_ctr_32way(struct camellia_ctx *ctx, u8 *dst,
-				   const u8 *src, le128 *iv);
-
-asmlinkage void camellia_xts_enc_32way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
-asmlinkage void camellia_xts_dec_32way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
+asmlinkage void camellia_ecb_enc_32way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void camellia_ecb_dec_32way(const void *ctx, u8 *dst, const u8 *src);
+
+asmlinkage void camellia_cbc_dec_32way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void camellia_ctr_32way(const void *ctx, u8 *dst, const u8 *src,
+				   le128 *iv);
+
+asmlinkage void camellia_xts_enc_32way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
+asmlinkage void camellia_xts_dec_32way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
 
 static const struct common_glue_ctx camellia_enc = {
 	.num_funcs = 4,
@@ -40,16 +37,16 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_enc_32way) }
+		.fn_u = { .ecb = camellia_ecb_enc_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_enc_16way) }
+		.fn_u = { .ecb = camellia_ecb_enc_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk_2way) }
+		.fn_u = { .ecb = camellia_enc_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk) }
+		.fn_u = { .ecb = camellia_enc_blk }
 	} }
 };
 
@@ -59,16 +56,16 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_ctr_32way) }
+		.fn_u = { .ctr = camellia_ctr_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_ctr_16way) }
+		.fn_u = { .ctr = camellia_ctr_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr_2way) }
+		.fn_u = { .ctr = camellia_crypt_ctr_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr) }
+		.fn_u = { .ctr = camellia_crypt_ctr }
 	} }
 };
 
@@ -78,13 +75,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_32way) }
+		.fn_u = { .xts = camellia_xts_enc_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_16way) }
+		.fn_u = { .xts = camellia_xts_enc_16way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc) }
+		.fn_u = { .xts = camellia_xts_enc }
 	} }
 };
 
@@ -94,16 +91,16 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_dec_32way) }
+		.fn_u = { .ecb = camellia_ecb_dec_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_dec_16way) }
+		.fn_u = { .ecb = camellia_ecb_dec_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk_2way) }
+		.fn_u = { .ecb = camellia_dec_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .ecb = camellia_dec_blk }
 	} }
 };
 
@@ -113,16 +110,16 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_cbc_dec_32way) }
+		.fn_u = { .cbc = camellia_cbc_dec_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_cbc_dec_16way) }
+		.fn_u = { .cbc = camellia_cbc_dec_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_decrypt_cbc_2way) }
+		.fn_u = { .cbc = camellia_decrypt_cbc_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .cbc = camellia_dec_blk }
 	} }
 };
 
@@ -132,13 +129,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_32way) }
+		.fn_u = { .xts = camellia_xts_dec_32way }
 	}, {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_16way) }
+		.fn_u = { .xts = camellia_xts_dec_16way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec) }
+		.fn_u = { .xts = camellia_xts_dec }
 	} }
 };
 
@@ -161,8 +158,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
-					   req);
+	return glue_cbc_encrypt_req_128bit(camellia_enc_blk, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -180,8 +176,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&camellia_enc_xts, req,
-				   XTS_TWEAK_CAST(camellia_enc_blk),
+	return glue_xts_req_128bit(&camellia_enc_xts, req, camellia_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
 }
 
@@ -190,8 +185,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&camellia_dec_xts, req,
-				   XTS_TWEAK_CAST(camellia_enc_blk),
+	return glue_xts_req_128bit(&camellia_dec_xts, req, camellia_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/camellia_aesni_avx_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/camellia_aesni_avx_glue.c
@@ -18,41 +18,36 @@
 #define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
 
 /* 16-way parallel cipher functions (avx/aes-ni) */
-asmlinkage void camellia_ecb_enc_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
+asmlinkage void camellia_ecb_enc_16way(const void *ctx, u8 *dst, const u8 *src);
 EXPORT_SYMBOL_GPL(camellia_ecb_enc_16way);
 
-asmlinkage void camellia_ecb_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
+asmlinkage void camellia_ecb_dec_16way(const void *ctx, u8 *dst, const u8 *src);
 EXPORT_SYMBOL_GPL(camellia_ecb_dec_16way);
 
-asmlinkage void camellia_cbc_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
+asmlinkage void camellia_cbc_dec_16way(const void *ctx, u8 *dst, const u8 *src);
 EXPORT_SYMBOL_GPL(camellia_cbc_dec_16way);
 
-asmlinkage void camellia_ctr_16way(struct camellia_ctx *ctx, u8 *dst,
-				   const u8 *src, le128 *iv);
+asmlinkage void camellia_ctr_16way(const void *ctx, u8 *dst, const u8 *src,
+				   le128 *iv);
 EXPORT_SYMBOL_GPL(camellia_ctr_16way);
 
-asmlinkage void camellia_xts_enc_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
+asmlinkage void camellia_xts_enc_16way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
 EXPORT_SYMBOL_GPL(camellia_xts_enc_16way);
 
-asmlinkage void camellia_xts_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
+asmlinkage void camellia_xts_dec_16way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
 EXPORT_SYMBOL_GPL(camellia_xts_dec_16way);
 
-void camellia_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void camellia_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(camellia_enc_blk));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, camellia_enc_blk);
 }
 EXPORT_SYMBOL_GPL(camellia_xts_enc);
 
-void camellia_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void camellia_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(camellia_dec_blk));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, camellia_dec_blk);
 }
 EXPORT_SYMBOL_GPL(camellia_xts_dec);
 
@@ -62,13 +57,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_enc_16way) }
+		.fn_u = { .ecb = camellia_ecb_enc_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk_2way) }
+		.fn_u = { .ecb = camellia_enc_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk) }
+		.fn_u = { .ecb = camellia_enc_blk }
 	} }
 };
 
@@ -78,13 +73,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_ctr_16way) }
+		.fn_u = { .ctr = camellia_ctr_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr_2way) }
+		.fn_u = { .ctr = camellia_crypt_ctr_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr) }
+		.fn_u = { .ctr = camellia_crypt_ctr }
 	} }
 };
 
@@ -94,10 +89,10 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_16way) }
+		.fn_u = { .xts = camellia_xts_enc_16way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc) }
+		.fn_u = { .xts = camellia_xts_enc }
 	} }
 };
 
@@ -107,13 +102,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_dec_16way) }
+		.fn_u = { .ecb = camellia_ecb_dec_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk_2way) }
+		.fn_u = { .ecb = camellia_dec_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .ecb = camellia_dec_blk }
 	} }
 };
 
@@ -123,13 +118,13 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_cbc_dec_16way) }
+		.fn_u = { .cbc = camellia_cbc_dec_16way }
 	}, {
 		.num_blocks = 2,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_decrypt_cbc_2way) }
+		.fn_u = { .cbc = camellia_decrypt_cbc_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .cbc = camellia_dec_blk }
 	} }
 };
 
@@ -139,10 +134,10 @@
 
 	.funcs = { {
 		.num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_16way) }
+		.fn_u = { .xts = camellia_xts_dec_16way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec) }
+		.fn_u = { .xts = camellia_xts_dec }
 	} }
 };
 
@@ -165,8 +160,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
-					   req);
+	return glue_cbc_encrypt_req_128bit(camellia_enc_blk, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -206,8 +200,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&camellia_enc_xts, req,
-				   XTS_TWEAK_CAST(camellia_enc_blk),
+	return glue_xts_req_128bit(&camellia_enc_xts, req, camellia_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
 }
 
@@ -216,8 +209,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&camellia_dec_xts, req,
-				   XTS_TWEAK_CAST(camellia_enc_blk),
+	return glue_xts_req_128bit(&camellia_dec_xts, req, camellia_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/camellia_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/camellia_glue.c
@@ -18,19 +18,17 @@
 #include <asm/crypto/glue_helper.h>
 
 /* regular block cipher functions */
-asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst,
-				   const u8 *src, bool xor);
+asmlinkage void __camellia_enc_blk(const void *ctx, u8 *dst, const u8 *src,
+				   bool xor);
 EXPORT_SYMBOL_GPL(__camellia_enc_blk);
-asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst,
-				 const u8 *src);
+asmlinkage void camellia_dec_blk(const void *ctx, u8 *dst, const u8 *src);
 EXPORT_SYMBOL_GPL(camellia_dec_blk);
 
 /* 2-way parallel cipher functions */
-asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst,
-					const u8 *src, bool xor);
+asmlinkage void __camellia_enc_blk_2way(const void *ctx, u8 *dst, const u8 *src,
+					bool xor);
 EXPORT_SYMBOL_GPL(__camellia_enc_blk_2way);
-asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst,
-				      const u8 *src);
+asmlinkage void camellia_dec_blk_2way(const void *ctx, u8 *dst, const u8 *src);
 EXPORT_SYMBOL_GPL(camellia_dec_blk_2way);
 
 static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
@@ -1267,8 +1265,10 @@
 	return camellia_setkey(&tfm->base, key, key_len);
 }
 
-void camellia_decrypt_cbc_2way(void *ctx, u128 *dst, const u128 *src)
+void camellia_decrypt_cbc_2way(const void *ctx, u8 *d, const u8 *s)
 {
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 	u128 iv = *src;
 
 	camellia_dec_blk_2way(ctx, (u8 *)dst, (u8 *)src);
@@ -1277,9 +1277,11 @@
 }
 EXPORT_SYMBOL_GPL(camellia_decrypt_cbc_2way);
 
-void camellia_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void camellia_crypt_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblk;
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	if (dst != src)
 		*dst = *src;
@@ -1291,9 +1293,11 @@
 }
 EXPORT_SYMBOL_GPL(camellia_crypt_ctr);
 
-void camellia_crypt_ctr_2way(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void camellia_crypt_ctr_2way(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblks[2];
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	if (dst != src) {
 		dst[0] = src[0];
@@ -1315,10 +1319,10 @@
 
 	.funcs = { {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk_2way) }
+		.fn_u = { .ecb = camellia_enc_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk) }
+		.fn_u = { .ecb = camellia_enc_blk }
 	} }
 };
 
@@ -1328,10 +1332,10 @@
 
 	.funcs = { {
 		.num_blocks = 2,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr_2way) }
+		.fn_u = { .ctr = camellia_crypt_ctr_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr) }
+		.fn_u = { .ctr = camellia_crypt_ctr }
 	} }
 };
 
@@ -1341,10 +1345,10 @@
 
 	.funcs = { {
 		.num_blocks = 2,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk_2way) }
+		.fn_u = { .ecb = camellia_dec_blk_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .ecb = camellia_dec_blk }
 	} }
 };
 
@@ -1354,10 +1358,10 @@
 
 	.funcs = { {
 		.num_blocks = 2,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_decrypt_cbc_2way) }
+		.fn_u = { .cbc = camellia_decrypt_cbc_2way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_dec_blk) }
+		.fn_u = { .cbc = camellia_dec_blk }
 	} }
 };
 
@@ -1373,8 +1377,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
-					   req);
+	return glue_cbc_encrypt_req_128bit(camellia_enc_blk, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
--- linux-ein-5.4.0.orig/arch/x86/crypto/cast6_avx_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/cast6_avx_glue.c
@@ -20,20 +20,17 @@
 
 #define CAST6_PARALLEL_BLOCKS 8
 
-asmlinkage void cast6_ecb_enc_8way(struct cast6_ctx *ctx, u8 *dst,
-				   const u8 *src);
-asmlinkage void cast6_ecb_dec_8way(struct cast6_ctx *ctx, u8 *dst,
-				   const u8 *src);
-
-asmlinkage void cast6_cbc_dec_8way(struct cast6_ctx *ctx, u8 *dst,
-				   const u8 *src);
-asmlinkage void cast6_ctr_8way(struct cast6_ctx *ctx, u8 *dst, const u8 *src,
+asmlinkage void cast6_ecb_enc_8way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void cast6_ecb_dec_8way(const void *ctx, u8 *dst, const u8 *src);
+
+asmlinkage void cast6_cbc_dec_8way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void cast6_ctr_8way(const void *ctx, u8 *dst, const u8 *src,
 			       le128 *iv);
 
-asmlinkage void cast6_xts_enc_8way(struct cast6_ctx *ctx, u8 *dst,
-				   const u8 *src, le128 *iv);
-asmlinkage void cast6_xts_dec_8way(struct cast6_ctx *ctx, u8 *dst,
-				   const u8 *src, le128 *iv);
+asmlinkage void cast6_xts_enc_8way(const void *ctx, u8 *dst, const u8 *src,
+				   le128 *iv);
+asmlinkage void cast6_xts_dec_8way(const void *ctx, u8 *dst, const u8 *src,
+				   le128 *iv);
 
 static int cast6_setkey_skcipher(struct crypto_skcipher *tfm,
 				 const u8 *key, unsigned int keylen)
@@ -41,21 +38,21 @@
 	return cast6_setkey(&tfm->base, key, keylen);
 }
 
-static void cast6_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void cast6_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(__cast6_encrypt));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, __cast6_encrypt);
 }
 
-static void cast6_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void cast6_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(__cast6_decrypt));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, __cast6_decrypt);
 }
 
-static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void cast6_crypt_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblk;
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	le128_to_be128(&ctrblk, iv);
 	le128_inc(iv);
@@ -70,10 +67,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(cast6_ecb_enc_8way) }
+		.fn_u = { .ecb = cast6_ecb_enc_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_encrypt) }
+		.fn_u = { .ecb = __cast6_encrypt }
 	} }
 };
 
@@ -83,10 +80,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_ctr_8way) }
+		.fn_u = { .ctr = cast6_ctr_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr) }
+		.fn_u = { .ctr = cast6_crypt_ctr }
 	} }
 };
 
@@ -96,10 +93,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_enc_8way) }
+		.fn_u = { .xts = cast6_xts_enc_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_enc) }
+		.fn_u = { .xts = cast6_xts_enc }
 	} }
 };
 
@@ -109,10 +106,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(cast6_ecb_dec_8way) }
+		.fn_u = { .ecb = cast6_ecb_dec_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_decrypt) }
+		.fn_u = { .ecb = __cast6_decrypt }
 	} }
 };
 
@@ -122,10 +119,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(cast6_cbc_dec_8way) }
+		.fn_u = { .cbc = cast6_cbc_dec_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__cast6_decrypt) }
+		.fn_u = { .cbc = __cast6_decrypt }
 	} }
 };
 
@@ -135,10 +132,10 @@
 
 	.funcs = { {
 		.num_blocks = CAST6_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_dec_8way) }
+		.fn_u = { .xts = cast6_xts_dec_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_dec) }
+		.fn_u = { .xts = cast6_xts_dec }
 	} }
 };
 
@@ -154,8 +151,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__cast6_encrypt),
-					   req);
+	return glue_cbc_encrypt_req_128bit(__cast6_encrypt, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -199,8 +195,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct cast6_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&cast6_enc_xts, req,
-				   XTS_TWEAK_CAST(__cast6_encrypt),
+	return glue_xts_req_128bit(&cast6_enc_xts, req, __cast6_encrypt,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
 }
 
@@ -209,8 +204,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct cast6_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&cast6_dec_xts, req,
-				   XTS_TWEAK_CAST(__cast6_encrypt),
+	return glue_xts_req_128bit(&cast6_dec_xts, req, __cast6_encrypt,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/chacha-avx512vl-x86_64.S
+++ linux-ein-5.4.0/arch/x86/crypto/chacha-avx512vl-x86_64.S
@@ -172,7 +172,7 @@
 	# xor remaining bytes from partial register into output
 	mov		%rcx,%rax
 	and		$0xf,%rcx
-	jz		.Ldone8
+	jz		.Ldone2
 	mov		%rax,%r9
 	and		$~0xf,%r9
 
@@ -438,7 +438,7 @@
 	# xor remaining bytes from partial register into output
 	mov		%rcx,%rax
 	and		$0xf,%rcx
-	jz		.Ldone8
+	jz		.Ldone4
 	mov		%rax,%r9
 	and		$~0xf,%r9
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
+++ linux-ein-5.4.0/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
@@ -170,7 +170,7 @@
 
 	## branch into array
 	lea	jump_table(%rip), bufp
-	movzxw  (bufp, %rax, 2), len
+	movzwq  (bufp, %rax, 2), len
 	lea	crc_array(%rip), bufp
 	lea     (bufp, len, 1), bufp
 	JMP_NOSPEC bufp
--- linux-ein-5.4.0.orig/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -19,6 +19,7 @@
 #include <crypto/internal/simd.h>
 #include <asm/cpu_device_id.h>
 #include <asm/simd.h>
+#include <asm/unaligned.h>
 
 #define GHASH_BLOCK_SIZE	16
 #define GHASH_DIGEST_SIZE	16
@@ -54,7 +55,6 @@
 			const u8 *key, unsigned int keylen)
 {
 	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
-	be128 *x = (be128 *)key;
 	u64 a, b;
 
 	if (keylen != GHASH_BLOCK_SIZE) {
@@ -63,8 +63,8 @@
 	}
 
 	/* perform multiplication by 'x' in GF(2^128) */
-	a = be64_to_cpu(x->a);
-	b = be64_to_cpu(x->b);
+	a = get_unaligned_be64(key);
+	b = get_unaligned_be64(key + 8);
 
 	ctx->shash.a = (b << 1) | (a >> 63);
 	ctx->shash.b = (a << 1) | (b >> 63);
--- linux-ein-5.4.0.orig/arch/x86/crypto/glue_helper.c
+++ linux-ein-5.4.0/arch/x86/crypto/glue_helper.c
@@ -134,7 +134,8 @@
 				src -= num_blocks - 1;
 				dst -= num_blocks - 1;
 
-				gctx->funcs[i].fn_u.cbc(ctx, dst, src);
+				gctx->funcs[i].fn_u.cbc(ctx, (u8 *)dst,
+							(const u8 *)src);
 
 				nbytes -= func_bytes;
 				if (nbytes < bsize)
@@ -188,7 +189,9 @@
 
 			/* Process multi-block batch */
 			do {
-				gctx->funcs[i].fn_u.ctr(ctx, dst, src, &ctrblk);
+				gctx->funcs[i].fn_u.ctr(ctx, (u8 *)dst,
+							(const u8 *)src,
+							&ctrblk);
 				src += num_blocks;
 				dst += num_blocks;
 				nbytes -= func_bytes;
@@ -210,7 +213,8 @@
 
 		be128_to_le128(&ctrblk, (be128 *)walk.iv);
 		memcpy(&tmp, walk.src.virt.addr, nbytes);
-		gctx->funcs[gctx->num_funcs - 1].fn_u.ctr(ctx, &tmp, &tmp,
+		gctx->funcs[gctx->num_funcs - 1].fn_u.ctr(ctx, (u8 *)&tmp,
+							  (const u8 *)&tmp,
 							  &ctrblk);
 		memcpy(walk.dst.virt.addr, &tmp, nbytes);
 		le128_to_be128((be128 *)walk.iv, &ctrblk);
@@ -240,7 +244,8 @@
 
 		if (nbytes >= func_bytes) {
 			do {
-				gctx->funcs[i].fn_u.xts(ctx, dst, src,
+				gctx->funcs[i].fn_u.xts(ctx, (u8 *)dst,
+							(const u8 *)src,
 							walk->iv);
 
 				src += num_blocks;
@@ -354,8 +359,8 @@
 }
 EXPORT_SYMBOL_GPL(glue_xts_req_128bit);
 
-void glue_xts_crypt_128bit_one(void *ctx, u128 *dst, const u128 *src, le128 *iv,
-			       common_glue_func_t fn)
+void glue_xts_crypt_128bit_one(const void *ctx, u8 *dst, const u8 *src,
+			       le128 *iv, common_glue_func_t fn)
 {
 	le128 ivblk = *iv;
 
@@ -363,13 +368,13 @@
 	gf128mul_x_ble(iv, &ivblk);
 
 	/* CC <- T xor C */
-	u128_xor(dst, src, (u128 *)&ivblk);
+	u128_xor((u128 *)dst, (const u128 *)src, (u128 *)&ivblk);
 
 	/* PP <- D(Key2,CC) */
-	fn(ctx, (u8 *)dst, (u8 *)dst);
+	fn(ctx, dst, dst);
 
 	/* P <- T xor PP */
-	u128_xor(dst, dst, (u128 *)&ivblk);
+	u128_xor((u128 *)dst, (u128 *)dst, (u128 *)&ivblk);
 }
 EXPORT_SYMBOL_GPL(glue_xts_crypt_128bit_one);
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/nhpoly1305-avx2-glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/nhpoly1305-avx2-glue.c
@@ -29,7 +29,7 @@
 		return crypto_nhpoly1305_update(desc, src, srclen);
 
 	do {
-		unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE);
+		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
 
 		kernel_fpu_begin();
 		crypto_nhpoly1305_update_helper(desc, src, n, _nh_avx2);
--- linux-ein-5.4.0.orig/arch/x86/crypto/nhpoly1305-sse2-glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/nhpoly1305-sse2-glue.c
@@ -29,7 +29,7 @@
 		return crypto_nhpoly1305_update(desc, src, srclen);
 
 	do {
-		unsigned int n = min_t(unsigned int, srclen, PAGE_SIZE);
+		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
 
 		kernel_fpu_begin();
 		crypto_nhpoly1305_update_helper(desc, src, n, _nh_sse2);
--- linux-ein-5.4.0.orig/arch/x86/crypto/serpent_avx2_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/serpent_avx2_glue.c
@@ -19,18 +19,16 @@
 #define SERPENT_AVX2_PARALLEL_BLOCKS 16
 
 /* 16-way AVX2 parallel cipher functions */
-asmlinkage void serpent_ecb_enc_16way(struct serpent_ctx *ctx, u8 *dst,
-				      const u8 *src);
-asmlinkage void serpent_ecb_dec_16way(struct serpent_ctx *ctx, u8 *dst,
-				      const u8 *src);
-asmlinkage void serpent_cbc_dec_16way(void *ctx, u128 *dst, const u128 *src);
+asmlinkage void serpent_ecb_enc_16way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void serpent_ecb_dec_16way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void serpent_cbc_dec_16way(const void *ctx, u8 *dst, const u8 *src);
 
-asmlinkage void serpent_ctr_16way(void *ctx, u128 *dst, const u128 *src,
+asmlinkage void serpent_ctr_16way(const void *ctx, u8 *dst, const u8 *src,
 				  le128 *iv);
-asmlinkage void serpent_xts_enc_16way(struct serpent_ctx *ctx, u8 *dst,
-				      const u8 *src, le128 *iv);
-asmlinkage void serpent_xts_dec_16way(struct serpent_ctx *ctx, u8 *dst,
-				      const u8 *src, le128 *iv);
+asmlinkage void serpent_xts_enc_16way(const void *ctx, u8 *dst, const u8 *src,
+				      le128 *iv);
+asmlinkage void serpent_xts_dec_16way(const void *ctx, u8 *dst, const u8 *src,
+				      le128 *iv);
 
 static int serpent_setkey_skcipher(struct crypto_skcipher *tfm,
 				   const u8 *key, unsigned int keylen)
@@ -44,13 +42,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_enc_16way) }
+		.fn_u = { .ecb = serpent_ecb_enc_16way }
 	}, {
 		.num_blocks = 8,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_enc_8way_avx) }
+		.fn_u = { .ecb = serpent_ecb_enc_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) }
+		.fn_u = { .ecb = __serpent_encrypt }
 	} }
 };
 
@@ -60,13 +58,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_16way) }
+		.fn_u = { .ctr = serpent_ctr_16way }
 	},  {
 		.num_blocks = 8,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_8way_avx) }
+		.fn_u = { .ctr = serpent_ctr_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(__serpent_crypt_ctr) }
+		.fn_u = { .ctr = __serpent_crypt_ctr }
 	} }
 };
 
@@ -76,13 +74,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_16way) }
+		.fn_u = { .xts = serpent_xts_enc_16way }
 	}, {
 		.num_blocks = 8,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_8way_avx) }
+		.fn_u = { .xts = serpent_xts_enc_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc) }
+		.fn_u = { .xts = serpent_xts_enc }
 	} }
 };
 
@@ -92,13 +90,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_dec_16way) }
+		.fn_u = { .ecb = serpent_ecb_dec_16way }
 	}, {
 		.num_blocks = 8,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_dec_8way_avx) }
+		.fn_u = { .ecb = serpent_ecb_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .ecb = __serpent_decrypt }
 	} }
 };
 
@@ -108,13 +106,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_cbc_dec_16way) }
+		.fn_u = { .cbc = serpent_cbc_dec_16way }
 	}, {
 		.num_blocks = 8,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_cbc_dec_8way_avx) }
+		.fn_u = { .cbc = serpent_cbc_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .cbc = __serpent_decrypt }
 	} }
 };
 
@@ -124,13 +122,13 @@
 
 	.funcs = { {
 		.num_blocks = 16,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_16way) }
+		.fn_u = { .xts = serpent_xts_dec_16way }
 	}, {
 		.num_blocks = 8,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_8way_avx) }
+		.fn_u = { .xts = serpent_xts_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec) }
+		.fn_u = { .xts = serpent_xts_dec }
 	} }
 };
 
@@ -146,8 +144,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
-					   req);
+	return glue_cbc_encrypt_req_128bit(__serpent_encrypt, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -166,8 +163,8 @@
 	struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
 	return glue_xts_req_128bit(&serpent_enc_xts, req,
-				   XTS_TWEAK_CAST(__serpent_encrypt),
-				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
+				   __serpent_encrypt, &ctx->tweak_ctx,
+				   &ctx->crypt_ctx, false);
 }
 
 static int xts_decrypt(struct skcipher_request *req)
@@ -176,8 +173,8 @@
 	struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
 	return glue_xts_req_128bit(&serpent_dec_xts, req,
-				   XTS_TWEAK_CAST(__serpent_encrypt),
-				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
+				   __serpent_encrypt, &ctx->tweak_ctx,
+				   &ctx->crypt_ctx, true);
 }
 
 static struct skcipher_alg serpent_algs[] = {
--- linux-ein-5.4.0.orig/arch/x86/crypto/serpent_avx_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/serpent_avx_glue.c
@@ -20,33 +20,35 @@
 #include <asm/crypto/serpent-avx.h>
 
 /* 8-way parallel cipher functions */
-asmlinkage void serpent_ecb_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_ecb_enc_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
 EXPORT_SYMBOL_GPL(serpent_ecb_enc_8way_avx);
 
-asmlinkage void serpent_ecb_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_ecb_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
 EXPORT_SYMBOL_GPL(serpent_ecb_dec_8way_avx);
 
-asmlinkage void serpent_cbc_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_cbc_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
 EXPORT_SYMBOL_GPL(serpent_cbc_dec_8way_avx);
 
-asmlinkage void serpent_ctr_8way_avx(struct serpent_ctx *ctx, u8 *dst,
-				     const u8 *src, le128 *iv);
+asmlinkage void serpent_ctr_8way_avx(const void *ctx, u8 *dst, const u8 *src,
+				     le128 *iv);
 EXPORT_SYMBOL_GPL(serpent_ctr_8way_avx);
 
-asmlinkage void serpent_xts_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_xts_enc_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src, le128 *iv);
 EXPORT_SYMBOL_GPL(serpent_xts_enc_8way_avx);
 
-asmlinkage void serpent_xts_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_xts_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src, le128 *iv);
 EXPORT_SYMBOL_GPL(serpent_xts_dec_8way_avx);
 
-void __serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void __serpent_crypt_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblk;
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	le128_to_be128(&ctrblk, iv);
 	le128_inc(iv);
@@ -56,17 +58,15 @@
 }
 EXPORT_SYMBOL_GPL(__serpent_crypt_ctr);
 
-void serpent_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void serpent_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(__serpent_encrypt));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, __serpent_encrypt);
 }
 EXPORT_SYMBOL_GPL(serpent_xts_enc);
 
-void serpent_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void serpent_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(__serpent_decrypt));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, __serpent_decrypt);
 }
 EXPORT_SYMBOL_GPL(serpent_xts_dec);
 
@@ -102,10 +102,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_enc_8way_avx) }
+		.fn_u = { .ecb = serpent_ecb_enc_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) }
+		.fn_u = { .ecb = __serpent_encrypt }
 	} }
 };
 
@@ -115,10 +115,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_8way_avx) }
+		.fn_u = { .ctr = serpent_ctr_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(__serpent_crypt_ctr) }
+		.fn_u = { .ctr = __serpent_crypt_ctr }
 	} }
 };
 
@@ -128,10 +128,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_8way_avx) }
+		.fn_u = { .xts = serpent_xts_enc_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc) }
+		.fn_u = { .xts = serpent_xts_enc }
 	} }
 };
 
@@ -141,10 +141,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_dec_8way_avx) }
+		.fn_u = { .ecb = serpent_ecb_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .ecb = __serpent_decrypt }
 	} }
 };
 
@@ -154,10 +154,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_cbc_dec_8way_avx) }
+		.fn_u = { .cbc = serpent_cbc_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .cbc = __serpent_decrypt }
 	} }
 };
 
@@ -167,10 +167,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_8way_avx) }
+		.fn_u = { .xts = serpent_xts_dec_8way_avx }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec) }
+		.fn_u = { .xts = serpent_xts_dec }
 	} }
 };
 
@@ -186,8 +186,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
-					   req);
+	return glue_cbc_encrypt_req_128bit(__serpent_encrypt, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -206,8 +205,8 @@
 	struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
 	return glue_xts_req_128bit(&serpent_enc_xts, req,
-				   XTS_TWEAK_CAST(__serpent_encrypt),
-				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
+				   __serpent_encrypt, &ctx->tweak_ctx,
+				   &ctx->crypt_ctx, false);
 }
 
 static int xts_decrypt(struct skcipher_request *req)
@@ -216,8 +215,8 @@
 	struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
 	return glue_xts_req_128bit(&serpent_dec_xts, req,
-				   XTS_TWEAK_CAST(__serpent_encrypt),
-				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
+				   __serpent_encrypt, &ctx->tweak_ctx,
+				   &ctx->crypt_ctx, true);
 }
 
 static struct skcipher_alg serpent_algs[] = {
--- linux-ein-5.4.0.orig/arch/x86/crypto/serpent_sse2_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/serpent_sse2_glue.c
@@ -31,9 +31,11 @@
 	return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen);
 }
 
-static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
+static void serpent_decrypt_cbc_xway(const void *ctx, u8 *d, const u8 *s)
 {
 	u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 	unsigned int j;
 
 	for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++)
@@ -45,9 +47,11 @@
 		u128_xor(dst + (j + 1), dst + (j + 1), ivs + j);
 }
 
-static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void serpent_crypt_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblk;
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	le128_to_be128(&ctrblk, iv);
 	le128_inc(iv);
@@ -56,10 +60,12 @@
 	u128_xor(dst, src, (u128 *)&ctrblk);
 }
 
-static void serpent_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src,
+static void serpent_crypt_ctr_xway(const void *ctx, u8 *d, const u8 *s,
 				   le128 *iv)
 {
 	be128 ctrblks[SERPENT_PARALLEL_BLOCKS];
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 	unsigned int i;
 
 	for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
@@ -79,10 +85,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_enc_blk_xway) }
+		.fn_u = { .ecb = serpent_enc_blk_xway }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) }
+		.fn_u = { .ecb = __serpent_encrypt }
 	} }
 };
 
@@ -92,10 +98,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr_xway) }
+		.fn_u = { .ctr = serpent_crypt_ctr_xway }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) }
+		.fn_u = { .ctr = serpent_crypt_ctr }
 	} }
 };
 
@@ -105,10 +111,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(serpent_dec_blk_xway) }
+		.fn_u = { .ecb = serpent_dec_blk_xway }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .ecb = __serpent_decrypt }
 	} }
 };
 
@@ -118,10 +124,10 @@
 
 	.funcs = { {
 		.num_blocks = SERPENT_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_decrypt_cbc_xway) }
+		.fn_u = { .cbc = serpent_decrypt_cbc_xway }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) }
+		.fn_u = { .cbc = __serpent_decrypt }
 	} }
 };
 
@@ -137,7 +143,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
+	return glue_cbc_encrypt_req_128bit(__serpent_encrypt,
 					   req);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/twofish_avx_glue.c
+++ linux-ein-5.4.0/arch/x86/crypto/twofish_avx_glue.c
@@ -22,20 +22,17 @@
 #define TWOFISH_PARALLEL_BLOCKS 8
 
 /* 8-way parallel cipher functions */
-asmlinkage void twofish_ecb_enc_8way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src);
-asmlinkage void twofish_ecb_dec_8way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src);
-
-asmlinkage void twofish_cbc_dec_8way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src);
-asmlinkage void twofish_ctr_8way(struct twofish_ctx *ctx, u8 *dst,
-				 const u8 *src, le128 *iv);
-
-asmlinkage void twofish_xts_enc_8way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src, le128 *iv);
-asmlinkage void twofish_xts_dec_8way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src, le128 *iv);
+asmlinkage void twofish_ecb_enc_8way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void twofish_ecb_dec_8way(const void *ctx, u8 *dst, const u8 *src);
+
+asmlinkage void twofish_cbc_dec_8way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void twofish_ctr_8way(const void *ctx, u8 *dst, const u8 *src,
+				 le128 *iv);
+
+asmlinkage void twofish_xts_enc_8way(const void *ctx, u8 *dst, const u8 *src,
+				     le128 *iv);
+asmlinkage void twofish_xts_dec_8way(const void *ctx, u8 *dst, const u8 *src,
+				     le128 *iv);
 
 static int twofish_setkey_skcipher(struct crypto_skcipher *tfm,
 				   const u8 *key, unsigned int keylen)
@@ -43,22 +40,19 @@
 	return twofish_setkey(&tfm->base, key, keylen);
 }
 
-static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
-					const u8 *src)
+static inline void twofish_enc_blk_3way(const void *ctx, u8 *dst, const u8 *src)
 {
 	__twofish_enc_blk_3way(ctx, dst, src, false);
 }
 
-static void twofish_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void twofish_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(twofish_enc_blk));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, twofish_enc_blk);
 }
 
-static void twofish_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void twofish_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv)
 {
-	glue_xts_crypt_128bit_one(ctx, dst, src, iv,
-				  GLUE_FUNC_CAST(twofish_dec_blk));
+	glue_xts_crypt_128bit_one(ctx, dst, src, iv, twofish_dec_blk);
 }
 
 struct twofish_xts_ctx {
@@ -93,13 +87,13 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_enc_8way) }
+		.fn_u = { .ecb = twofish_ecb_enc_8way }
 	}, {
 		.num_blocks = 3,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk_3way) }
+		.fn_u = { .ecb = twofish_enc_blk_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk) }
+		.fn_u = { .ecb = twofish_enc_blk }
 	} }
 };
 
@@ -109,13 +103,13 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_ctr_8way) }
+		.fn_u = { .ctr = twofish_ctr_8way }
 	}, {
 		.num_blocks = 3,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_enc_blk_ctr_3way) }
+		.fn_u = { .ctr = twofish_enc_blk_ctr_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_enc_blk_ctr) }
+		.fn_u = { .ctr = twofish_enc_blk_ctr }
 	} }
 };
 
@@ -125,10 +119,10 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_enc_8way) }
+		.fn_u = { .xts = twofish_xts_enc_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_enc) }
+		.fn_u = { .xts = twofish_xts_enc }
 	} }
 };
 
@@ -138,13 +132,13 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_dec_8way) }
+		.fn_u = { .ecb = twofish_ecb_dec_8way }
 	}, {
 		.num_blocks = 3,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk_3way) }
+		.fn_u = { .ecb = twofish_dec_blk_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk) }
+		.fn_u = { .ecb = twofish_dec_blk }
 	} }
 };
 
@@ -154,13 +148,13 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_cbc_dec_8way) }
+		.fn_u = { .cbc = twofish_cbc_dec_8way }
 	}, {
 		.num_blocks = 3,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk_cbc_3way) }
+		.fn_u = { .cbc = twofish_dec_blk_cbc_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk) }
+		.fn_u = { .cbc = twofish_dec_blk }
 	} }
 };
 
@@ -170,10 +164,10 @@
 
 	.funcs = { {
 		.num_blocks = TWOFISH_PARALLEL_BLOCKS,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_dec_8way) }
+		.fn_u = { .xts = twofish_xts_dec_8way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_dec) }
+		.fn_u = { .xts = twofish_xts_dec }
 	} }
 };
 
@@ -189,8 +183,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(twofish_enc_blk),
-					   req);
+	return glue_cbc_encrypt_req_128bit(twofish_enc_blk, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -208,8 +201,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct twofish_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&twofish_enc_xts, req,
-				   XTS_TWEAK_CAST(twofish_enc_blk),
+	return glue_xts_req_128bit(&twofish_enc_xts, req, twofish_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, false);
 }
 
@@ -218,8 +210,7 @@
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct twofish_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-	return glue_xts_req_128bit(&twofish_dec_xts, req,
-				   XTS_TWEAK_CAST(twofish_enc_blk),
+	return glue_xts_req_128bit(&twofish_dec_xts, req, twofish_enc_blk,
 				   &ctx->tweak_ctx, &ctx->crypt_ctx, true);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/crypto/twofish_glue_3way.c
+++ linux-ein-5.4.0/arch/x86/crypto/twofish_glue_3way.c
@@ -25,21 +25,22 @@
 	return twofish_setkey(&tfm->base, key, keylen);
 }
 
-static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
-					const u8 *src)
+static inline void twofish_enc_blk_3way(const void *ctx, u8 *dst, const u8 *src)
 {
 	__twofish_enc_blk_3way(ctx, dst, src, false);
 }
 
-static inline void twofish_enc_blk_xor_3way(struct twofish_ctx *ctx, u8 *dst,
+static inline void twofish_enc_blk_xor_3way(const void *ctx, u8 *dst,
 					    const u8 *src)
 {
 	__twofish_enc_blk_3way(ctx, dst, src, true);
 }
 
-void twofish_dec_blk_cbc_3way(void *ctx, u128 *dst, const u128 *src)
+void twofish_dec_blk_cbc_3way(const void *ctx, u8 *d, const u8 *s)
 {
 	u128 ivs[2];
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	ivs[0] = src[0];
 	ivs[1] = src[1];
@@ -51,9 +52,11 @@
 }
 EXPORT_SYMBOL_GPL(twofish_dec_blk_cbc_3way);
 
-void twofish_enc_blk_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+void twofish_enc_blk_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblk;
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	if (dst != src)
 		*dst = *src;
@@ -66,10 +69,11 @@
 }
 EXPORT_SYMBOL_GPL(twofish_enc_blk_ctr);
 
-void twofish_enc_blk_ctr_3way(void *ctx, u128 *dst, const u128 *src,
-			      le128 *iv)
+void twofish_enc_blk_ctr_3way(const void *ctx, u8 *d, const u8 *s, le128 *iv)
 {
 	be128 ctrblks[3];
+	u128 *dst = (u128 *)d;
+	const u128 *src = (const u128 *)s;
 
 	if (dst != src) {
 		dst[0] = src[0];
@@ -94,10 +98,10 @@
 
 	.funcs = { {
 		.num_blocks = 3,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk_3way) }
+		.fn_u = { .ecb = twofish_enc_blk_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk) }
+		.fn_u = { .ecb = twofish_enc_blk }
 	} }
 };
 
@@ -107,10 +111,10 @@
 
 	.funcs = { {
 		.num_blocks = 3,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk_ctr_3way) }
+		.fn_u = { .ctr = twofish_enc_blk_ctr_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk_ctr) }
+		.fn_u = { .ctr = twofish_enc_blk_ctr }
 	} }
 };
 
@@ -120,10 +124,10 @@
 
 	.funcs = { {
 		.num_blocks = 3,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk_3way) }
+		.fn_u = { .ecb = twofish_dec_blk_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk) }
+		.fn_u = { .ecb = twofish_dec_blk }
 	} }
 };
 
@@ -133,10 +137,10 @@
 
 	.funcs = { {
 		.num_blocks = 3,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk_cbc_3way) }
+		.fn_u = { .cbc = twofish_dec_blk_cbc_3way }
 	}, {
 		.num_blocks = 1,
-		.fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk) }
+		.fn_u = { .cbc = twofish_dec_blk }
 	} }
 };
 
@@ -152,8 +156,7 @@
 
 static int cbc_encrypt(struct skcipher_request *req)
 {
-	return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(twofish_enc_blk),
-					   req);
+	return glue_cbc_encrypt_req_128bit(twofish_enc_blk, req);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
--- linux-ein-5.4.0.orig/arch/x86/entry/calling.h
+++ linux-ein-5.4.0/arch/x86/entry/calling.h
@@ -6,6 +6,8 @@
 #include <asm/percpu.h>
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
+#include <asm/msr.h>
+#include <asm/nospec-branch.h>
 
 /*
 
@@ -98,13 +100,6 @@
 #define SIZEOF_PTREGS	21*8
 
 .macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0
-	/*
-	 * Push registers and sanitize registers of values that a
-	 * speculation attack might otherwise want to exploit. The
-	 * lower registers are likely clobbered well before they
-	 * could be put to use in a speculative execution gadget.
-	 * Interleave XOR with PUSH for better uop scheduling:
-	 */
 	.if \save_ret
 	pushq	%rsi		/* pt_regs->si */
 	movq	8(%rsp), %rsi	/* temporarily store the return address in %rsi */
@@ -114,57 +109,58 @@
 	pushq   %rsi		/* pt_regs->si */
 	.endif
 	pushq	\rdx		/* pt_regs->dx */
-	xorl	%edx, %edx	/* nospec   dx */
 	pushq   %rcx		/* pt_regs->cx */
-	xorl	%ecx, %ecx	/* nospec   cx */
 	pushq   \rax		/* pt_regs->ax */
 	pushq   %r8		/* pt_regs->r8 */
-	xorl	%r8d, %r8d	/* nospec   r8 */
 	pushq   %r9		/* pt_regs->r9 */
-	xorl	%r9d, %r9d	/* nospec   r9 */
 	pushq   %r10		/* pt_regs->r10 */
-	xorl	%r10d, %r10d	/* nospec   r10 */
 	pushq   %r11		/* pt_regs->r11 */
-	xorl	%r11d, %r11d	/* 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 */
-	xorl	%r12d, %r12d	/* nospec   r12*/
 	pushq	%r13		/* pt_regs->r13 */
-	xorl	%r13d, %r13d	/* nospec   r13*/
 	pushq	%r14		/* pt_regs->r14 */
-	xorl	%r14d, %r14d	/* nospec   r14*/
 	pushq	%r15		/* pt_regs->r15 */
-	xorl	%r15d, %r15d	/* nospec   r15*/
 	UNWIND_HINT_REGS
+
 	.if \save_ret
 	pushq	%rsi		/* return address on top of stack */
 	.endif
+
+	/*
+	 * Sanitize registers of values that a speculation attack might
+	 * otherwise want to exploit. The lower registers are likely clobbered
+	 * well before they could be put to use in a speculative execution
+	 * gadget.
+	 */
+	xorl	%edx,  %edx	/* nospec dx  */
+	xorl	%ecx,  %ecx	/* nospec cx  */
+	xorl	%r8d,  %r8d	/* nospec r8  */
+	xorl	%r9d,  %r9d	/* nospec r9  */
+	xorl	%r10d, %r10d	/* nospec r10 */
+	xorl	%r11d, %r11d	/* nospec r11 */
+	xorl	%ebx,  %ebx	/* nospec rbx */
+	xorl	%ebp,  %ebp	/* nospec rbp */
+	xorl	%r12d, %r12d	/* nospec r12 */
+	xorl	%r13d, %r13d	/* nospec r13 */
+	xorl	%r14d, %r14d	/* nospec r14 */
+	xorl	%r15d, %r15d	/* nospec r15 */
+
 .endm
 
-.macro POP_REGS pop_rdi=1 skip_r11rcx=0
+.macro POP_REGS pop_rdi=1
 	popq %r15
 	popq %r14
 	popq %r13
 	popq %r12
 	popq %rbp
 	popq %rbx
-	.if \skip_r11rcx
-	popq %rsi
-	.else
 	popq %r11
-	.endif
 	popq %r10
 	popq %r9
 	popq %r8
 	popq %rax
-	.if \skip_r11rcx
-	popq %rsi
-	.else
 	popq %rcx
-	.endif
 	popq %rdx
 	popq %rsi
 	.if \pop_rdi
@@ -315,6 +311,62 @@
 #endif
 
 /*
+ * 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
+	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	.Lend_\@
+.Ldo_wrmsr_\@:
+.endif
+
+	movq	PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+	movl	%edx, %eax
+	shr	$32, %rdx
+	wrmsr
+.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
+	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
+.Lend_\@:
+.endm
+
+/*
  * Mitigate Spectre v1 for conditional swapgs code paths.
  *
  * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
--- linux-ein-5.4.0.orig/arch/x86/entry/common.c
+++ linux-ein-5.4.0/arch/x86/entry/common.c
@@ -218,6 +218,7 @@
 	user_enter_irqoff();
 
 	mds_user_clear_cpu_buffers();
+	amd_clear_divider();
 }
 
 #define SYSCALL_EXIT_WORK_FLAGS				\
--- linux-ein-5.4.0.orig/arch/x86/entry/entry_32.S
+++ linux-ein-5.4.0/arch/x86/entry/entry_32.S
@@ -172,7 +172,7 @@
 	ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
 	.if \no_user_check == 0
 	/* coming from usermode? */
-	testl	$SEGMENT_RPL_MASK, PT_CS(%esp)
+	testl	$USER_SEGMENT_RPL_MASK, PT_CS(%esp)
 	jz	.Lend_\@
 	.endif
 	/* On user-cr3? */
@@ -205,64 +205,76 @@
 #define CS_FROM_ENTRY_STACK	(1 << 31)
 #define CS_FROM_USER_CR3	(1 << 30)
 #define CS_FROM_KERNEL		(1 << 29)
+#define CS_FROM_ESPFIX		(1 << 28)
 
 .macro FIXUP_FRAME
 	/*
 	 * The high bits of the CS dword (__csh) are used for CS_FROM_*.
 	 * Clear them in case hardware didn't do this for us.
 	 */
-	andl	$0x0000ffff, 3*4(%esp)
+	andl	$0x0000ffff, 4*4(%esp)
 
 #ifdef CONFIG_VM86
-	testl	$X86_EFLAGS_VM, 4*4(%esp)
+	testl	$X86_EFLAGS_VM, 5*4(%esp)
 	jnz	.Lfrom_usermode_no_fixup_\@
 #endif
-	testl	$SEGMENT_RPL_MASK, 3*4(%esp)
+	testl	$USER_SEGMENT_RPL_MASK, 4*4(%esp)
 	jnz	.Lfrom_usermode_no_fixup_\@
 
-	orl	$CS_FROM_KERNEL, 3*4(%esp)
+	orl	$CS_FROM_KERNEL, 4*4(%esp)
 
 	/*
 	 * When we're here from kernel mode; the (exception) stack looks like:
 	 *
-	 *  5*4(%esp) - <previous context>
-	 *  4*4(%esp) - flags
-	 *  3*4(%esp) - cs
-	 *  2*4(%esp) - ip
-	 *  1*4(%esp) - orig_eax
-	 *  0*4(%esp) - gs / function
+	 *  6*4(%esp) - <previous context>
+	 *  5*4(%esp) - flags
+	 *  4*4(%esp) - cs
+	 *  3*4(%esp) - ip
+	 *  2*4(%esp) - orig_eax
+	 *  1*4(%esp) - gs / function
+	 *  0*4(%esp) - fs
 	 *
 	 * Lets build a 5 entry IRET frame after that, such that struct pt_regs
 	 * is complete and in particular regs->sp is correct. This gives us
-	 * the original 5 enties as gap:
+	 * the original 6 enties as gap:
 	 *
-	 * 12*4(%esp) - <previous context>
-	 * 11*4(%esp) - gap / flags
-	 * 10*4(%esp) - gap / cs
-	 *  9*4(%esp) - gap / ip
-	 *  8*4(%esp) - gap / orig_eax
-	 *  7*4(%esp) - gap / gs / function
-	 *  6*4(%esp) - ss
-	 *  5*4(%esp) - sp
-	 *  4*4(%esp) - flags
-	 *  3*4(%esp) - cs
-	 *  2*4(%esp) - ip
-	 *  1*4(%esp) - orig_eax
-	 *  0*4(%esp) - gs / function
+	 * 14*4(%esp) - <previous context>
+	 * 13*4(%esp) - gap / flags
+	 * 12*4(%esp) - gap / cs
+	 * 11*4(%esp) - gap / ip
+	 * 10*4(%esp) - gap / orig_eax
+	 *  9*4(%esp) - gap / gs / function
+	 *  8*4(%esp) - gap / fs
+	 *  7*4(%esp) - ss
+	 *  6*4(%esp) - sp
+	 *  5*4(%esp) - flags
+	 *  4*4(%esp) - cs
+	 *  3*4(%esp) - ip
+	 *  2*4(%esp) - orig_eax
+	 *  1*4(%esp) - gs / function
+	 *  0*4(%esp) - fs
 	 */
 
 	pushl	%ss		# ss
 	pushl	%esp		# sp (points at ss)
-	addl	$6*4, (%esp)	# point sp back at the previous context
-	pushl	6*4(%esp)	# flags
-	pushl	6*4(%esp)	# cs
-	pushl	6*4(%esp)	# ip
-	pushl	6*4(%esp)	# orig_eax
-	pushl	6*4(%esp)	# gs / function
+	addl	$7*4, (%esp)	# point sp back at the previous context
+	pushl	7*4(%esp)	# flags
+	pushl	7*4(%esp)	# cs
+	pushl	7*4(%esp)	# ip
+	pushl	7*4(%esp)	# orig_eax
+	pushl	7*4(%esp)	# gs / function
+	pushl	7*4(%esp)	# fs
 .Lfrom_usermode_no_fixup_\@:
 .endm
 
 .macro IRET_FRAME
+	/*
+	 * We're called with %ds, %es, %fs, and %gs from the interrupted
+	 * frame, so we shouldn't use them.  Also, we may be in ESPFIX
+	 * mode and therefore have a nonzero SS base and an offset ESP,
+	 * so any attempt to access the stack needs to use SS.  (except for
+	 * accesses through %esp, which automatically use SS.)
+	 */
 	testl $CS_FROM_KERNEL, 1*4(%esp)
 	jz .Lfinished_frame_\@
 
@@ -276,31 +288,40 @@
 	movl	5*4(%esp), %eax		# (modified) regs->sp
 
 	movl	4*4(%esp), %ecx		# flags
-	movl	%ecx, -4(%eax)
+	movl	%ecx, %ss:-1*4(%eax)
 
 	movl	3*4(%esp), %ecx		# cs
 	andl	$0x0000ffff, %ecx
-	movl	%ecx, -8(%eax)
+	movl	%ecx, %ss:-2*4(%eax)
 
 	movl	2*4(%esp), %ecx		# ip
-	movl	%ecx, -12(%eax)
+	movl	%ecx, %ss:-3*4(%eax)
 
 	movl	1*4(%esp), %ecx		# eax
-	movl	%ecx, -16(%eax)
+	movl	%ecx, %ss:-4*4(%eax)
 
 	popl	%ecx
-	lea	-16(%eax), %esp
+	lea	-4*4(%eax), %esp
 	popl	%eax
 .Lfinished_frame_\@:
 .endm
 
-.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0
+.macro SAVE_ALL pt_regs_ax=%eax switch_stacks=0 skip_gs=0 unwind_espfix=0
 	cld
 .if \skip_gs == 0
 	PUSH_GS
 .endif
-	FIXUP_FRAME
 	pushl	%fs
+
+	pushl	%eax
+	movl	$(__KERNEL_PERCPU), %eax
+	movl	%eax, %fs
+.if \unwind_espfix > 0
+	UNWIND_ESPFIX_STACK
+.endif
+	popl	%eax
+
+	FIXUP_FRAME
 	pushl	%es
 	pushl	%ds
 	pushl	\pt_regs_ax
@@ -313,8 +334,6 @@
 	movl	$(__USER_DS), %edx
 	movl	%edx, %ds
 	movl	%edx, %es
-	movl	$(__KERNEL_PERCPU), %edx
-	movl	%edx, %fs
 .if \skip_gs == 0
 	SET_KERNEL_GS %edx
 .endif
@@ -324,8 +343,8 @@
 .endif
 .endm
 
-.macro SAVE_ALL_NMI cr3_reg:req
-	SAVE_ALL
+.macro SAVE_ALL_NMI cr3_reg:req unwind_espfix=0
+	SAVE_ALL unwind_espfix=\unwind_espfix
 
 	BUG_IF_WRONG_CR3
 
@@ -357,6 +376,7 @@
 2:	popl	%es
 3:	popl	%fs
 	POP_GS \pop
+	IRET_FRAME
 .pushsection .fixup, "ax"
 4:	movl	$0, (%esp)
 	jmp	1b
@@ -395,7 +415,8 @@
 
 .macro CHECK_AND_APPLY_ESPFIX
 #ifdef CONFIG_X86_ESPFIX32
-#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
+#define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8)
+#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET
 
 	ALTERNATIVE	"jmp .Lend_\@", "", X86_BUG_ESPFIX
 
@@ -729,7 +750,6 @@
 	movl	%ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset
 #endif
 
-#ifdef CONFIG_RETPOLINE
 	/*
 	 * When switching from a shallower to a deeper call stack
 	 * the RSB may either underflow or use entries populated
@@ -738,7 +758,6 @@
 	 * speculative execution to prevent attack.
 	 */
 	FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
 	/* restore callee-saved registers */
 	popfl
@@ -848,9 +867,10 @@
  * Xen doesn't set %esp to be precisely what the normal SYSENTER
  * entry point expects, so fix it up before using the normal path.
  */
-ENTRY(xen_sysenter_target)
+SYM_CODE_START(xen_sysenter_target)
 	addl	$5*4, %esp			/* remove xen-provided frame */
 	jmp	.Lsysenter_past_esp
+SYM_CODE_END(xen_sysenter_target)
 #endif
 
 /*
@@ -1075,7 +1095,6 @@
 	/* Restore user state */
 	RESTORE_REGS pop=4			# skip orig_eax/error_code
 .Lirq_return:
-	IRET_FRAME
 	/*
 	 * ARCH_HAS_MEMBARRIER_SYNC_CORE rely on IRET core serialization
 	 * when returning from IPI handler and when returning from
@@ -1128,30 +1147,43 @@
  * We can't call C functions using the ESPFIX stack. This code reads
  * the high word of the segment base from the GDT and swiches to the
  * normal stack and adjusts ESP with the matching offset.
+ *
+ * We might be on user CR3 here, so percpu data is not mapped and we can't
+ * access the GDT through the percpu segment.  Instead, use SGDT to find
+ * the cpu_entry_area alias of the GDT.
  */
 #ifdef CONFIG_X86_ESPFIX32
 	/* fixup the stack */
-	mov	GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
-	mov	GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
+	pushl	%ecx
+	subl	$2*4, %esp
+	sgdt	(%esp)
+	movl	2(%esp), %ecx				/* GDT address */
+	/*
+	 * Careful: ECX is a linear pointer, so we need to force base
+	 * zero.  %cs is the only known-linear segment we have right now.
+	 */
+	mov	%cs:GDT_ESPFIX_OFFSET + 4(%ecx), %al	/* bits 16..23 */
+	mov	%cs:GDT_ESPFIX_OFFSET + 7(%ecx), %ah	/* bits 24..31 */
 	shl	$16, %eax
+	addl	$2*4, %esp
+	popl	%ecx
 	addl	%esp, %eax			/* the adjusted stack pointer */
 	pushl	$__KERNEL_DS
 	pushl	%eax
 	lss	(%esp), %esp			/* switch to the normal stack segment */
 #endif
 .endm
+
 .macro UNWIND_ESPFIX_STACK
+	/* It's safe to clobber %eax, all other regs need to be preserved */
 #ifdef CONFIG_X86_ESPFIX32
 	movl	%ss, %eax
 	/* see if on espfix stack */
 	cmpw	$__ESPFIX_SS, %ax
-	jne	27f
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-	movl	%eax, %es
+	jne	.Lno_fixup_\@
 	/* switch to normal stack */
 	FIXUP_ESPFIX_STACK
-27:
+.Lno_fixup_\@:
 #endif
 .endm
 
@@ -1341,11 +1373,6 @@
 
 #ifdef CONFIG_XEN_PV
 ENTRY(xen_hypervisor_callback)
-	pushl	$-1				/* orig_ax = -1 => not a system call */
-	SAVE_ALL
-	ENCODE_FRAME_POINTER
-	TRACE_IRQS_OFF
-
 	/*
 	 * Check to see if we got the event in the critical
 	 * region in xen_iret_direct, after we've reenabled
@@ -1353,16 +1380,17 @@
 	 * iret instruction's behaviour where it delivers a
 	 * pending interrupt when enabling interrupts:
 	 */
-	movl	PT_EIP(%esp), %eax
-	cmpl	$xen_iret_start_crit, %eax
+	cmpl	$xen_iret_start_crit, (%esp)
 	jb	1f
-	cmpl	$xen_iret_end_crit, %eax
+	cmpl	$xen_iret_end_crit, (%esp)
 	jae	1f
-
-	jmp	xen_iret_crit_fixup
-
-ENTRY(xen_do_upcall)
-1:	mov	%esp, %eax
+	call	xen_iret_crit_fixup
+1:
+	pushl	$-1				/* orig_ax = -1 => not a system call */
+	SAVE_ALL
+	ENCODE_FRAME_POINTER
+	TRACE_IRQS_OFF
+	mov	%esp, %eax
 	call	xen_evtchn_do_upcall
 #ifndef CONFIG_PREEMPTION
 	call	xen_maybe_preempt_hcall
@@ -1449,10 +1477,9 @@
 
 common_exception_read_cr2:
 	/* the function address is in %gs's slot on the stack */
-	SAVE_ALL switch_stacks=1 skip_gs=1
+	SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
 
 	ENCODE_FRAME_POINTER
-	UNWIND_ESPFIX_STACK
 
 	/* fixup %gs */
 	GS_TO_REG %ecx
@@ -1474,9 +1501,8 @@
 
 common_exception:
 	/* the function address is in %gs's slot on the stack */
-	SAVE_ALL switch_stacks=1 skip_gs=1
+	SAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1
 	ENCODE_FRAME_POINTER
-	UNWIND_ESPFIX_STACK
 
 	/* fixup %gs */
 	GS_TO_REG %ecx
@@ -1515,6 +1541,10 @@
 	ASM_CLAC
 
 #ifdef CONFIG_X86_ESPFIX32
+	/*
+	 * ESPFIX_SS is only ever set on the return to user path
+	 * after we've switched to the entry stack.
+	 */
 	pushl	%eax
 	movl	%ss, %eax
 	cmpw	$__ESPFIX_SS, %ax
@@ -1550,6 +1580,11 @@
 	movl	%ebx, %esp
 
 .Lnmi_return:
+#ifdef CONFIG_X86_ESPFIX32
+	testl	$CS_FROM_ESPFIX, PT_CS(%esp)
+	jnz	.Lnmi_from_espfix
+#endif
+
 	CHECK_AND_APPLY_ESPFIX
 	RESTORE_ALL_NMI cr3_reg=%edi pop=4
 	jmp	.Lirq_return
@@ -1557,23 +1592,42 @@
 #ifdef CONFIG_X86_ESPFIX32
 .Lnmi_espfix_stack:
 	/*
-	 * create the pointer to lss back
+	 * Create the pointer to LSS back
 	 */
 	pushl	%ss
 	pushl	%esp
 	addl	$4, (%esp)
-	/* copy the iret frame of 12 bytes */
-	.rept 3
-	pushl	16(%esp)
-	.endr
-	pushl	%eax
-	SAVE_ALL_NMI cr3_reg=%edi
+
+	/* Copy the (short) IRET frame */
+	pushl	4*4(%esp)	# flags
+	pushl	4*4(%esp)	# cs
+	pushl	4*4(%esp)	# ip
+
+	pushl	%eax		# orig_ax
+
+	SAVE_ALL_NMI cr3_reg=%edi unwind_espfix=1
 	ENCODE_FRAME_POINTER
-	FIXUP_ESPFIX_STACK			# %eax == %esp
+
+	/* clear CS_FROM_KERNEL, set CS_FROM_ESPFIX */
+	xorl	$(CS_FROM_ESPFIX | CS_FROM_KERNEL), PT_CS(%esp)
+
 	xorl	%edx, %edx			# zero error code
-	call	do_nmi
+	movl	%esp, %eax			# pt_regs pointer
+	jmp	.Lnmi_from_sysenter_stack
+
+.Lnmi_from_espfix:
 	RESTORE_ALL_NMI cr3_reg=%edi
-	lss	12+4(%esp), %esp		# back to espfix stack
+	/*
+	 * Because we cleared CS_FROM_KERNEL, IRET_FRAME 'forgot' to
+	 * fix up the gap and long frame:
+	 *
+	 *  3 - original frame	(exception)
+	 *  2 - ESPFIX block	(above)
+	 *  6 - gap		(FIXUP_FRAME)
+	 *  5 - long frame	(FIXUP_FRAME)
+	 *  1 - orig_ax
+	 */
+	lss	(1+5+6)*4(%esp), %esp			# back to espfix stack
 	jmp	.Lirq_return
 #endif
 END(nmi)
@@ -1592,6 +1646,7 @@
 END(int3)
 
 ENTRY(general_protection)
+	ASM_CLAC
 	pushl	$do_general_protection
 	jmp	common_exception
 END(general_protection)
@@ -1604,13 +1659,13 @@
 END(async_page_fault)
 #endif
 
-ENTRY(rewind_stack_do_exit)
+ENTRY(rewind_stack_and_make_dead)
 	/* Prevent any naive code from trying to unwind to our caller. */
 	xorl	%ebp, %ebp
 
 	movl	PER_CPU_VAR(cpu_current_top_of_stack), %esi
 	leal	-TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%esi), %esp
 
-	call	do_exit
+	call	make_task_dead
 1:	jmp 1b
-END(rewind_stack_do_exit)
+END(rewind_stack_and_make_dead)
--- linux-ein-5.4.0.orig/arch/x86/entry/entry_64.S
+++ linux-ein-5.4.0/arch/x86/entry/entry_64.S
@@ -172,6 +172,11 @@
 	/* IRQs are off. */
 	movq	%rax, %rdi
 	movq	%rsp, %rsi
+
+	/* clobbers %rax, make sure it is after saving the syscall nr */
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	call	do_syscall_64		/* returns with IRQs disabled */
 
 	TRACE_IRQS_IRETQ		/* we're about to change IF */
@@ -248,9 +253,8 @@
 	 * perf profiles. Nothing jumps here.
 	 */
 syscall_return_via_sysret:
-	/* rcx and r11 are already restored (see code above) */
-	UNWIND_HINT_EMPTY
-	POP_REGS pop_rdi=0 skip_r11rcx=1
+	IBRS_EXIT
+	POP_REGS pop_rdi=0
 
 	/*
 	 * Now all regs are restored except RSP and RDI.
@@ -258,6 +262,7 @@
 	 */
 	movq	%rsp, %rdi
 	movq	PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
+	UNWIND_HINT_EMPTY
 
 	pushq	RSP-RDI(%rdi)	/* RSP */
 	pushq	(%rdi)		/* RDI */
@@ -301,7 +306,6 @@
 	movq	%rbx, PER_CPU_VAR(fixed_percpu_data) + stack_canary_offset
 #endif
 
-#ifdef CONFIG_RETPOLINE
 	/*
 	 * When switching from a shallower to a deeper call stack
 	 * the RSB may either underflow or use entries populated
@@ -310,7 +314,6 @@
 	 * speculative execution to prevent attack.
 	 */
 	FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
 	/* restore callee-saved registers */
 	popq	%r15
@@ -512,7 +515,7 @@
  * +----------------------------------------------------+
  */
 ENTRY(interrupt_entry)
-	UNWIND_HINT_FUNC
+	UNWIND_HINT_IRET_REGS offset=16
 	ASM_CLAC
 	cld
 
@@ -544,9 +547,9 @@
 	pushq	5*8(%rdi)		/* regs->eflags */
 	pushq	4*8(%rdi)		/* regs->cs */
 	pushq	3*8(%rdi)		/* regs->ip */
+	UNWIND_HINT_IRET_REGS
 	pushq	2*8(%rdi)		/* regs->orig_ax */
 	pushq	8(%rdi)			/* return address */
-	UNWIND_HINT_FUNC
 
 	movq	(%rdi), %rdi
 	jmp	2f
@@ -616,12 +619,13 @@
 	jz	retint_kernel
 
 	/* Interrupt came from user space */
-GLOBAL(retint_user)
+.Lretint_user:
 	mov	%rsp,%rdi
 	call	prepare_exit_to_usermode
 	TRACE_IRQS_IRETQ
 
 GLOBAL(swapgs_restore_regs_and_return_to_usermode)
+	IBRS_EXIT
 #ifdef CONFIG_DEBUG_ENTRY
 	/* Assert that pt_regs indicates user mode. */
 	testb	$3, CS(%rsp)
@@ -637,6 +641,7 @@
 	 */
 	movq	%rsp, %rdi
 	movq	PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
+	UNWIND_HINT_EMPTY
 
 	/* Copy the IRET frame to the trampoline stack. */
 	pushq	6*8(%rdi)	/* SS */
@@ -1247,7 +1252,13 @@
 	 */
 	FENCE_SWAPGS_KERNEL_ENTRY
 
-	ret
+	/*
+	 * 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)
 
 /*
@@ -1275,12 +1286,20 @@
 	jmp	.Lparanoid_exit_restore
 .Lparanoid_exit_no_swapgs:
 	TRACE_IRQS_IRETQ_DEBUG
+
+	/*
+	 * 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
+
 	/* Always restore stashed CR3 value (see paranoid_entry) */
 	RESTORE_CR3	scratch_reg=%rbx save_reg=%r14
 .Lparanoid_exit_restore:
 	jmp restore_regs_and_return_to_kernel
 END(paranoid_exit)
 
+
 /*
  * Save all registers in pt_regs, and switch GS if needed.
  */
@@ -1300,6 +1319,7 @@
 	FENCE_SWAPGS_USER_ENTRY
 	/* We have user CR3.  Change to kernel CR3. */
 	SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+	IBRS_ENTER
 
 .Lerror_entry_from_usermode_after_swapgs:
 	/* Put us onto the real thread stack. */
@@ -1355,6 +1375,7 @@
 	SWAPGS
 	FENCE_SWAPGS_USER_ENTRY
 	SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+	IBRS_ENTER
 
 	/*
 	 * Pretend that the exception came from user mode: set up pt_regs
@@ -1372,7 +1393,7 @@
 	TRACE_IRQS_OFF
 	testb	$3, CS(%rsp)
 	jz	retint_kernel
-	jmp	retint_user
+	jmp	.Lretint_user
 END(error_exit)
 
 /*
@@ -1460,6 +1481,8 @@
 	PUSH_AND_CLEAR_REGS rdx=(%rdx)
 	ENCODE_FRAME_POINTER
 
+	IBRS_ENTER
+
 	/*
 	 * At this point we no longer need to worry about stack damage
 	 * due to nesting -- we're on the normal thread stack and we're
@@ -1683,6 +1706,9 @@
 	movq	$-1, %rsi
 	call	do_nmi
 
+	/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
+	IBRS_EXIT save_reg=%r15
+
 	/* Always restore stashed CR3 value (see paranoid_entry) */
 	RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
 
@@ -1732,14 +1758,71 @@
 END(ignore_sysret)
 #endif
 
-ENTRY(rewind_stack_do_exit)
+ENTRY(rewind_stack_and_make_dead)
 	UNWIND_HINT_FUNC
 	/* Prevent any naive code from trying to unwind to our caller. */
 	xorl	%ebp, %ebp
 
 	movq	PER_CPU_VAR(cpu_current_top_of_stack), %rax
 	leaq	-PTREGS_SIZE(%rax), %rsp
-	UNWIND_HINT_FUNC sp_offset=PTREGS_SIZE
+	UNWIND_HINT_REGS
 
-	call	do_exit
-END(rewind_stack_do_exit)
+	call	make_task_dead
+END(rewind_stack_and_make_dead)
+
+/*
+ * 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
+	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	%rbp
+	RET
+END(clear_bhb_loop)
+EXPORT_SYMBOL_GPL(clear_bhb_loop)
--- linux-ein-5.4.0.orig/arch/x86/entry/entry_64_compat.S
+++ linux-ein-5.4.0/arch/x86/entry/entry_64_compat.S
@@ -4,7 +4,6 @@
  *
  * Copyright 2000-2002 Andi Kleen, SuSE Labs.
  */
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/current.h>
 #include <asm/errno.h>
@@ -17,6 +16,8 @@
 #include <linux/linkage.h>
 #include <linux/err.h>
 
+#include "calling.h"
+
 	.section .entry.text, "ax"
 
 /*
@@ -106,6 +107,9 @@
 	xorl	%r15d, %r15d		/* nospec   r15 */
 	cld
 
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	/*
 	 * SYSENTER doesn't filter flags, so we need to clear NT and AC
 	 * ourselves.  To save a few cycles, we can check whether
@@ -253,6 +257,9 @@
 	 */
 	TRACE_IRQS_OFF
 
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
+
 	movq	%rsp, %rdi
 	call	do_fast_syscall_32
 	/* XEN PV guests always use IRET path */
@@ -267,6 +274,9 @@
 	 */
 	STACKLEAK_ERASE
 	TRACE_IRQS_ON			/* User mode traces as IRQs on. */
+
+	IBRS_EXIT
+
 	movq	RBX(%rsp), %rbx		/* pt_regs->rbx */
 	movq	RBP(%rsp), %rbp		/* pt_regs->rbp */
 	movq	EFLAGS(%rsp), %r11	/* pt_regs->flags (in r11) */
@@ -408,6 +418,8 @@
 	 * gate turned them off.
 	 */
 	TRACE_IRQS_OFF
+	IBRS_ENTER
+	CLEAR_BRANCH_HISTORY
 
 	movq	%rsp, %rdi
 	call	do_int80_syscall_32
--- linux-ein-5.4.0.orig/arch/x86/entry/syscall_32.c
+++ linux-ein-5.4.0/arch/x86/entry/syscall_32.c
@@ -10,13 +10,11 @@
 #ifdef CONFIG_IA32_EMULATION
 /* On X86_64, we use struct pt_regs * to pass parameters to syscalls */
 #define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
-
-/* this is a lie, but it does not hurt as sys_ni_syscall just returns -EINVAL */
-extern asmlinkage long sys_ni_syscall(const struct pt_regs *);
-
+#define __sys_ni_syscall __ia32_sys_ni_syscall
 #else /* CONFIG_IA32_EMULATION */
 #define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+#define __sys_ni_syscall sys_ni_syscall
 #endif /* CONFIG_IA32_EMULATION */
 
 #include <asm/syscalls_32.h>
@@ -29,6 +27,6 @@
 	 * Smells like a compiler bug -- it doesn't work
 	 * when the & below is removed.
 	 */
-	[0 ... __NR_syscall_compat_max] = &sys_ni_syscall,
+	[0 ... __NR_syscall_compat_max] = &__sys_ni_syscall,
 #include <asm/syscalls_32.h>
 };
--- linux-ein-5.4.0.orig/arch/x86/entry/syscall_64.c
+++ linux-ein-5.4.0/arch/x86/entry/syscall_64.c
@@ -4,11 +4,17 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <linux/syscalls.h>
 #include <asm/asm-offsets.h>
 #include <asm/syscall.h>
 
-/* this is a lie, but it does not hurt as sys_ni_syscall just returns -EINVAL */
-extern asmlinkage long sys_ni_syscall(const struct pt_regs *);
+extern asmlinkage long sys_ni_syscall(void);
+
+SYSCALL_DEFINE0(ni_syscall)
+{
+	return sys_ni_syscall();
+}
+
 #define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
 #define __SYSCALL_X32(nr, sym, qual) __SYSCALL_64(nr, sym, qual)
 #include <asm/syscalls_64.h>
@@ -23,7 +29,7 @@
 	 * Smells like a compiler bug -- it doesn't work
 	 * when the & below is removed.
 	 */
-	[0 ... __NR_syscall_max] = &sys_ni_syscall,
+	[0 ... __NR_syscall_max] = &__x64_sys_ni_syscall,
 #include <asm/syscalls_64.h>
 };
 
@@ -40,7 +46,7 @@
 	 * Smells like a compiler bug -- it doesn't work
 	 * when the & below is removed.
 	 */
-	[0 ... __NR_syscall_x32_max] = &sys_ni_syscall,
+	[0 ... __NR_syscall_x32_max] = &__x64_sys_ni_syscall,
 #include <asm/syscalls_64.h>
 };
 
--- linux-ein-5.4.0.orig/arch/x86/entry/syscalls/syscall_32.tbl
+++ linux-ein-5.4.0/arch/x86/entry/syscalls/syscall_32.tbl
@@ -124,13 +124,13 @@
 110	i386	iopl			sys_iopl			__ia32_sys_iopl
 111	i386	vhangup			sys_vhangup			__ia32_sys_vhangup
 112	i386	idle
-113	i386	vm86old			sys_vm86old			sys_ni_syscall
+113	i386	vm86old			sys_vm86old			__ia32_sys_ni_syscall
 114	i386	wait4			sys_wait4			__ia32_compat_sys_wait4
 115	i386	swapoff			sys_swapoff			__ia32_sys_swapoff
 116	i386	sysinfo			sys_sysinfo			__ia32_compat_sys_sysinfo
 117	i386	ipc			sys_ipc				__ia32_compat_sys_ipc
 118	i386	fsync			sys_fsync			__ia32_sys_fsync
-119	i386	sigreturn		sys_sigreturn			sys32_sigreturn
+119	i386	sigreturn		sys_sigreturn			__ia32_compat_sys_sigreturn
 120	i386	clone			sys_clone			__ia32_compat_sys_x86_clone
 121	i386	setdomainname		sys_setdomainname		__ia32_sys_setdomainname
 122	i386	uname			sys_newuname			__ia32_sys_newuname
@@ -177,14 +177,14 @@
 163	i386	mremap			sys_mremap			__ia32_sys_mremap
 164	i386	setresuid		sys_setresuid16			__ia32_sys_setresuid16
 165	i386	getresuid		sys_getresuid16			__ia32_sys_getresuid16
-166	i386	vm86			sys_vm86			sys_ni_syscall
+166	i386	vm86			sys_vm86			__ia32_sys_ni_syscall
 167	i386	query_module
 168	i386	poll			sys_poll			__ia32_sys_poll
 169	i386	nfsservctl
 170	i386	setresgid		sys_setresgid16			__ia32_sys_setresgid16
 171	i386	getresgid		sys_getresgid16			__ia32_sys_getresgid16
 172	i386	prctl			sys_prctl			__ia32_sys_prctl
-173	i386	rt_sigreturn		sys_rt_sigreturn		sys32_rt_sigreturn
+173	i386	rt_sigreturn		sys_rt_sigreturn		__ia32_compat_sys_rt_sigreturn
 174	i386	rt_sigaction		sys_rt_sigaction		__ia32_compat_sys_rt_sigaction
 175	i386	rt_sigprocmask		sys_rt_sigprocmask		__ia32_compat_sys_rt_sigprocmask
 176	i386	rt_sigpending		sys_rt_sigpending		__ia32_compat_sys_rt_sigpending
--- linux-ein-5.4.0.orig/arch/x86/entry/vdso/Makefile
+++ linux-ein-5.4.0/arch/x86/entry/vdso/Makefile
@@ -178,7 +178,7 @@
 		 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
 VDSO_LDFLAGS = -shared --hash-style=both --build-id \
-	$(call ld-option, --eh-frame-hdr) -Bsymbolic
+	$(call ld-option, --eh-frame-hdr) -Bsymbolic -z noexecstack
 GCOV_PROFILE := n
 
 quiet_cmd_vdso_and_check = VDSO    $@
--- linux-ein-5.4.0.orig/arch/x86/entry/vdso/vdso32-setup.c
+++ linux-ein-5.4.0/arch/x86/entry/vdso/vdso32-setup.c
@@ -11,6 +11,7 @@
 #include <linux/smp.h>
 #include <linux/kernel.h>
 #include <linux/mm_types.h>
+#include <linux/elf.h>
 
 #include <asm/processor.h>
 #include <asm/vdso.h>
--- linux-ein-5.4.0.orig/arch/x86/entry/vdso/vma.c
+++ linux-ein-5.4.0/arch/x86/entry/vdso/vma.c
@@ -222,8 +222,8 @@
 
 	/* Round the lowest possible end address up to a PMD boundary. */
 	end = (start + len + PMD_SIZE - 1) & PMD_MASK;
-	if (end >= TASK_SIZE_MAX)
-		end = TASK_SIZE_MAX;
+	if (end >= DEFAULT_MAP_WINDOW)
+		end = DEFAULT_MAP_WINDOW;
 	end -= len;
 
 	if (end > start) {
@@ -323,7 +323,7 @@
 static __init int vdso_setup(char *s)
 {
 	vdso64_enabled = simple_strtoul(s, NULL, 0);
-	return 0;
+	return 1;
 }
 __setup("vdso=", vdso_setup);
 
--- linux-ein-5.4.0.orig/arch/x86/events/Kconfig
+++ linux-ein-5.4.0/arch/x86/events/Kconfig
@@ -10,11 +10,11 @@
 	available on NehalemEX and more modern processors.
 
 config PERF_EVENTS_INTEL_RAPL
-	tristate "Intel rapl performance events"
-	depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
+	tristate "Intel/AMD rapl performance events"
+	depends on PERF_EVENTS && (CPU_SUP_INTEL || CPU_SUP_AMD) && PCI
 	default y
 	---help---
-	Include support for Intel rapl performance events for power
+	Include support for Intel and AMD rapl performance events for power
 	monitoring on modern processors.
 
 config PERF_EVENTS_INTEL_CSTATE
--- linux-ein-5.4.0.orig/arch/x86/events/Makefile
+++ linux-ein-5.4.0/arch/x86/events/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y					+= core.o probe.o
+obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL)	+= rapl.o
 obj-y					+= amd/
 obj-$(CONFIG_X86_LOCAL_APIC)            += msr.o
 obj-$(CONFIG_CPU_SUP_INTEL)		+= intel/
--- linux-ein-5.4.0.orig/arch/x86/events/amd/core.c
+++ linux-ein-5.4.0/arch/x86/events/amd/core.c
@@ -14,6 +14,10 @@
 static DEFINE_PER_CPU(unsigned long, perf_nmi_tstamp);
 static unsigned long perf_nmi_window;
 
+/* AMD Event 0xFFF: Merge.  Used with Large Increment per Cycle events */
+#define AMD_MERGE_EVENT ((0xFULL << 32) | 0xFFULL)
+#define AMD_MERGE_EVENT_ENABLE (AMD_MERGE_EVENT | ARCH_PERFMON_EVENTSEL_ENABLE)
+
 static __initconst const u64 amd_hw_cache_event_ids
 				[PERF_COUNT_HW_CACHE_MAX]
 				[PERF_COUNT_HW_CACHE_OP_MAX]
@@ -246,6 +250,7 @@
 	[PERF_COUNT_HW_CPU_CYCLES]		= 0x0076,
 	[PERF_COUNT_HW_INSTRUCTIONS]		= 0x00c0,
 	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0xff60,
+	[PERF_COUNT_HW_CACHE_MISSES]		= 0x0964,
 	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x00c2,
 	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x00c3,
 	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= 0x0287,
@@ -301,6 +306,25 @@
 	return offset;
 }
 
+/*
+ * 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 bool amd_is_pair_event_code(struct hw_perf_event *hwc)
+{
+	if (!(x86_pmu.flags & PMU_FL_PAIR))
+		return false;
+
+	switch (amd_get_event_code(hwc)) {
+	case 0x003:	return true;	/* Retired SSE/AVX FLOPs */
+	default:	return false;
+	}
+}
+
 static int amd_core_hw_config(struct perf_event *event)
 {
 	if (event->attr.exclude_host && event->attr.exclude_guest)
@@ -316,15 +340,10 @@
 	else if (event->attr.exclude_guest)
 		event->hw.config |= AMD64_EVENTSEL_HOSTONLY;
 
-	return 0;
-}
+	if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw))
+		event->hw.flags |= PERF_X86_EVENT_PAIR;
 
-/*
- * 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);
+	return 0;
 }
 
 static inline int amd_is_nb_event(struct hw_perf_event *hwc)
@@ -864,6 +883,29 @@
 	}
 }
 
+static struct event_constraint pair_constraint;
+
+static struct event_constraint *
+amd_get_event_constraints_f17h(struct cpu_hw_events *cpuc, int idx,
+			       struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (amd_is_pair_event_code(hwc))
+		return &pair_constraint;
+
+	return &unconstrained;
+}
+
+static void amd_put_event_constraints_f17h(struct cpu_hw_events *cpuc,
+					   struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (is_counter_pair(hwc))
+		--cpuc->n_pair;
+}
+
 static ssize_t amd_event_sysfs_show(char *page, u64 config)
 {
 	u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) |
@@ -907,33 +949,15 @@
 
 static int __init amd_core_pmu_init(void)
 {
+	u64 even_ctr_mask = 0ULL;
+	int i;
+
 	if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
 		return 0;
 
-	/* Avoid calulating the value each time in the NMI handler */
+	/* Avoid calculating the value each time in the NMI handler */
 	perf_nmi_window = msecs_to_jiffies(100);
 
-	switch (boot_cpu_data.x86) {
-	case 0x15:
-		pr_cont("Fam15h ");
-		x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
-		break;
-	case 0x17:
-		pr_cont("Fam17h ");
-		/*
-		 * In family 17h, there are no event constraints in the PMC hardware.
-		 * We fallback to using default amd_get_event_constraints.
-		 */
-		break;
-	case 0x18:
-		pr_cont("Fam18h ");
-		/* Using default amd_get_event_constraints. */
-		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
@@ -948,6 +972,32 @@
 	 */
 	x86_pmu.amd_nb_constraints = 0;
 
+	if (boot_cpu_data.x86 == 0x15) {
+		pr_cont("Fam15h ");
+		x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
+	}
+	if (boot_cpu_data.x86 >= 0x17) {
+		pr_cont("Fam17h+ ");
+		/*
+		 * Family 17h and compatibles have constraints for Large
+		 * Increment per Cycle events: they may only be assigned an
+		 * even numbered counter that has a consecutive adjacent odd
+		 * numbered counter following it.
+		 */
+		for (i = 0; i < x86_pmu.num_counters - 1; i += 2)
+			even_ctr_mask |= BIT_ULL(i);
+
+		pair_constraint = (struct event_constraint)
+				    __EVENT_CONSTRAINT(0, even_ctr_mask, 0,
+				    x86_pmu.num_counters / 2, 0,
+				    PERF_X86_EVENT_PAIR);
+
+		x86_pmu.get_event_constraints = amd_get_event_constraints_f17h;
+		x86_pmu.put_event_constraints = amd_put_event_constraints_f17h;
+		x86_pmu.perf_ctr_pair_en = AMD_MERGE_EVENT_ENABLE;
+		x86_pmu.flags |= PMU_FL_PAIR;
+	}
+
 	pr_cont("core perfctr, ");
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/x86/events/amd/ibs.c
+++ linux-ein-5.4.0/arch/x86/events/amd/ibs.c
@@ -89,6 +89,8 @@
 	u64				max_period;
 	unsigned long			offset_mask[1];
 	int				offset_max;
+	unsigned int			fetch_count_reset_broken : 1;
+	unsigned int			fetch_ignore_if_zero_rip : 1;
 	struct cpu_perf_ibs __percpu	*pcpu;
 
 	struct attribute		**format_attrs;
@@ -310,6 +312,16 @@
 	hwc->config_base = perf_ibs->msr;
 	hwc->config = config;
 
+	/*
+	 * rip recorded by IbsOpRip will not be consistent with rsp and rbp
+	 * recorded as part of interrupt regs. Thus we need to use rip from
+	 * interrupt regs while unwinding call stack. Setting _EARLY flag
+	 * makes sure we unwind call-stack before perf sample rip is set to
+	 * IbsOpRip.
+	 */
+	if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
+		event->attr.sample_type |= __PERF_SAMPLE_CALLCHAIN_EARLY;
+
 	return 0;
 }
 
@@ -334,11 +346,15 @@
 {
 	u64 count = 0;
 
+	/*
+	 * If the internal 27-bit counter rolled over, the count is MaxCnt
+	 * and the lower 7 bits of CurCnt are randomized.
+	 * Otherwise CurCnt has the full 27-bit current counter value.
+	 */
 	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;
+		count = (config & IBS_OP_MAX_CNT) << 4;
+	else if (ibs_caps & IBS_CAPS_RDWROPCNT)
+		count = (config & IBS_OP_CUR_CNT) >> 32;
 
 	return count;
 }
@@ -363,7 +379,12 @@
 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);
+	u64 tmp = hwc->config | config;
+
+	if (perf_ibs->fetch_count_reset_broken)
+		wrmsrl(hwc->config_base, tmp & ~perf_ibs->enable_mask);
+
+	wrmsrl(hwc->config_base, tmp | perf_ibs->enable_mask);
 }
 
 /*
@@ -551,6 +572,7 @@
 		.start		= perf_ibs_start,
 		.stop		= perf_ibs_stop,
 		.read		= perf_ibs_read,
+		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	},
 	.msr			= MSR_AMD64_IBSOPCTL,
 	.config_mask		= IBS_OP_CONFIG_MASK,
@@ -626,18 +648,24 @@
 				       perf_ibs->offset_max,
 				       offset + 1);
 	} while (offset < offset_max);
+	/*
+	 * Read IbsBrTarget, IbsOpData4, and IbsExtdCtl separately
+	 * depending on their availability.
+	 * Can't add to offset_max as they are staggered
+	 */
 	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 (perf_ibs == &perf_ibs_op) {
+			if (ibs_caps & IBS_CAPS_BRNTRGT) {
+				rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
+				size++;
+			}
+			if (ibs_caps & IBS_CAPS_OPDATA4) {
+				rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+				size++;
+			}
 		}
-		if (ibs_caps & IBS_CAPS_OPDATA4) {
-			rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+		if (perf_ibs == &perf_ibs_fetch && (ibs_caps & IBS_CAPS_FETCHCTLEXTD)) {
+			rdmsrl(MSR_AMD64_ICIBSEXTDCTL, *buf++);
 			size++;
 		}
 	}
@@ -647,6 +675,10 @@
 	if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
 		regs.flags &= ~PERF_EFLAGS_EXACT;
 	} else {
+		/* Workaround for erratum #1197 */
+		if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1]))
+			goto out;
+
 		set_linear_ip(&regs, ibs_data.regs[1]);
 		regs.flags |= PERF_EFLAGS_EXACT;
 	}
@@ -661,6 +693,14 @@
 		data.raw = &raw;
 	}
 
+	/*
+	 * rip recorded by IbsOpRip will not be consistent with rsp and rbp
+	 * recorded as part of interrupt regs. Thus we need to use rip from
+	 * interrupt regs while unwinding call stack.
+	 */
+	if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
+		data.callchain = perf_callchain(event, iregs);
+
 	throttle = perf_event_overflow(event, &data, &regs);
 out:
 	if (throttle) {
@@ -733,6 +773,16 @@
 {
 	struct attribute **attr = ibs_op_format_attrs;
 
+	/*
+	 * Some chips fail to reset the fetch count when it is written; instead
+	 * they need a 0-1 transition of IbsFetchEn.
+	 */
+	if (boot_cpu_data.x86 >= 0x16 && boot_cpu_data.x86 <= 0x18)
+		perf_ibs_fetch.fetch_count_reset_broken = 1;
+
+	if (boot_cpu_data.x86 == 0x19 && boot_cpu_data.x86_model < 0x10)
+		perf_ibs_fetch.fetch_ignore_if_zero_rip = 1;
+
 	perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
 
 	if (ibs_caps & IBS_CAPS_OPCNT) {
--- linux-ein-5.4.0.orig/arch/x86/events/amd/iommu.c
+++ linux-ein-5.4.0/arch/x86/events/amd/iommu.c
@@ -18,8 +18,6 @@
 #include "../perf_event.h"
 #include "iommu.h"
 
-#define COUNTER_SHIFT		16
-
 /* iommu pmu conf masks */
 #define GET_CSOURCE(x)     ((x)->conf & 0xFFULL)
 #define GET_DEVID(x)       (((x)->conf >> 8)  & 0xFFFFULL)
@@ -81,12 +79,12 @@
 };
 
 struct amd_iommu_event_desc {
-	struct kobj_attribute attr;
+	struct device_attribute attr;
 	const char *event;
 };
 
-static ssize_t _iommu_event_show(struct kobject *kobj,
-				struct kobj_attribute *attr, char *buf)
+static ssize_t _iommu_event_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct amd_iommu_event_desc *event =
 		container_of(attr, struct amd_iommu_event_desc, attr);
@@ -285,22 +283,31 @@
 	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
 	hwc->state = 0;
 
+	/*
+	 * To account for power-gating, which prevents write to
+	 * the counter, we need to enable the counter
+	 * before setting up counter register.
+	 */
+	perf_iommu_enable_event(event);
+
 	if (flags & PERF_EF_RELOAD) {
-		u64 prev_raw_count = local64_read(&hwc->prev_count);
+		u64 count = 0;
 		struct amd_iommu *iommu = perf_event_2_iommu(event);
 
+		/*
+		 * Since the IOMMU PMU only support counting mode,
+		 * the counter always start with value zero.
+		 */
 		amd_iommu_pc_set_reg(iommu, hwc->iommu_bank, hwc->iommu_cntr,
-				     IOMMU_PC_COUNTER_REG, &prev_raw_count);
+				     IOMMU_PC_COUNTER_REG, &count);
 	}
 
-	perf_iommu_enable_event(event);
 	perf_event_update_userpage(event);
-
 }
 
 static void perf_iommu_read(struct perf_event *event)
 {
-	u64 count, prev, delta;
+	u64 count;
 	struct hw_perf_event *hwc = &event->hw;
 	struct amd_iommu *iommu = perf_event_2_iommu(event);
 
@@ -311,14 +318,11 @@
 	/* IOMMU pc counter register is only 48 bits */
 	count &= GENMASK_ULL(47, 0);
 
-	prev = local64_read(&hwc->prev_count);
-	if (local64_cmpxchg(&hwc->prev_count, prev, count) != prev)
-		return;
-
-	/* Handle 48-bit counter overflow */
-	delta = (count << COUNTER_SHIFT) - (prev << COUNTER_SHIFT);
-	delta >>= COUNTER_SHIFT;
-	local64_add(delta, &event->count);
+	/*
+	 * Since the counter always start with value zero,
+	 * simply just accumulate the count for the event.
+	 */
+	local64_add(count, &event->count);
 }
 
 static void perf_iommu_stop(struct perf_event *event, int flags)
@@ -328,15 +332,16 @@
 	if (hwc->state & PERF_HES_UPTODATE)
 		return;
 
+	/*
+	 * To account for power-gating, in which reading the counter would
+	 * return zero, we need to read the register before disabling.
+	 */
+	perf_iommu_read(event);
+	hwc->state |= PERF_HES_UPTODATE;
+
 	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;
-
-	perf_iommu_read(event);
-	hwc->state |= PERF_HES_UPTODATE;
 }
 
 static int perf_iommu_add(struct perf_event *event, int flags)
@@ -379,7 +384,7 @@
 	while (amd_iommu_v2_event_descs[i].attr.attr.name)
 		i++;
 
-	attrs = kcalloc(i + 1, sizeof(struct attribute **), GFP_KERNEL);
+	attrs = kcalloc(i + 1, sizeof(*attrs), GFP_KERNEL);
 	if (!attrs)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/arch/x86/events/amd/power.c
+++ linux-ein-5.4.0/arch/x86/events/amd/power.c
@@ -217,6 +217,7 @@
 	.stop		= pmu_event_stop,
 	.read		= pmu_event_read,
 	.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	.module		= THIS_MODULE,
 };
 
 static int power_cpu_exit(unsigned int cpu)
--- linux-ein-5.4.0.orig/arch/x86/events/amd/uncore.c
+++ linux-ein-5.4.0/arch/x86/events/amd/uncore.c
@@ -190,15 +190,12 @@
 
 	/*
 	 * NB and Last level cache counters (MSRs) are shared across all cores
-	 * that share the same NB / Last level cache. 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.
+	 * 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:
 	 */
-	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
-		return -EINVAL;
-
-	/* and we do not enable counter overflow interrupts */
 	hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
 	hwc->idx = -1;
 
@@ -306,7 +303,7 @@
 	.start		= amd_uncore_start,
 	.stop		= amd_uncore_stop,
 	.read		= amd_uncore_read,
-	.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	.capabilities	= PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
 };
 
 static struct pmu amd_llc_pmu = {
@@ -317,7 +314,7 @@
 	.start		= amd_uncore_start,
 	.stop		= amd_uncore_stop,
 	.read		= amd_uncore_read,
-	.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	.capabilities	= PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
 };
 
 static struct amd_uncore *amd_uncore_alloc(unsigned int cpu)
--- linux-ein-5.4.0.orig/arch/x86/events/core.c
+++ linux-ein-5.4.0/arch/x86/events/core.c
@@ -375,7 +375,7 @@
 	 * LBR and BTS are still mutually exclusive.
 	 */
 	if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
-		return 0;
+		goto out;
 
 	if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
 		mutex_lock(&pmc_reserve_mutex);
@@ -387,6 +387,7 @@
 		mutex_unlock(&pmc_reserve_mutex);
 	}
 
+out:
 	atomic_inc(&active_events);
 	return 0;
 
@@ -397,11 +398,15 @@
 
 void x86_del_exclusive(unsigned int what)
 {
+	atomic_dec(&active_events);
+
+	/*
+	 * See the comment in x86_add_exclusive().
+	 */
 	if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt)
 		return;
 
 	atomic_dec(&x86_pmu.lbr_exclusive[what]);
-	atomic_dec(&active_events);
 }
 
 int x86_setup_perfctr(struct perf_event *event)
@@ -612,6 +617,7 @@
 	int idx;
 
 	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+		struct hw_perf_event *hwc = &cpuc->events[idx]->hw;
 		u64 val;
 
 		if (!test_bit(idx, cpuc->active_mask))
@@ -621,6 +627,8 @@
 			continue;
 		val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
 		wrmsrl(x86_pmu_config_addr(idx), val);
+		if (is_counter_pair(hwc))
+			wrmsrl(x86_pmu_config_addr(idx + 1), 0);
 	}
 }
 
@@ -693,7 +701,7 @@
 	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)];
+	u64	used;
 };
 
 /* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */
@@ -750,8 +758,12 @@
 	sched->saved_states--;
 	sched->state = sched->saved[sched->saved_states];
 
-	/* continue with next counter: */
-	clear_bit(sched->state.counter++, sched->state.used);
+	/* this assignment didn't work out */
+	/* XXX broken vs EVENT_PAIR */
+	sched->state.used &= ~BIT_ULL(sched->state.counter);
+
+	/* try the next one */
+	sched->state.counter++;
 
 	return true;
 }
@@ -776,20 +788,32 @@
 	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;
+			u64 mask = BIT_ULL(idx);
+
+			if (sched->state.used & mask)
+				continue;
+
+			sched->state.used |= mask;
+			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;
+		u64 mask = BIT_ULL(idx);
 
-			goto done;
-		}
+		if (c->flags & PERF_X86_EVENT_PAIR)
+			mask |= mask << 1;
+
+		if (sched->state.used & mask)
+			continue;
+
+		if (sched->state.nr_gp++ >= sched->max_gp)
+			return false;
+
+		sched->state.used |= mask;
+		goto done;
 	}
 
 	return false;
@@ -866,12 +890,10 @@
 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 n0, i, wmin, wmax, unsched = 0;
 	struct hw_perf_event *hwc;
-
-	bitmap_zero(used_mask, X86_PMC_IDX_MAX);
+	u64 used_mask = 0;
 
 	/*
 	 * Compute the number of events already present; see x86_pmu_add(),
@@ -914,6 +936,8 @@
 	 * fastpath, try to reuse previous register
 	 */
 	for (i = 0; i < n; i++) {
+		u64 mask;
+
 		hwc = &cpuc->event_list[i]->hw;
 		c = cpuc->event_constraint[i];
 
@@ -925,11 +949,16 @@
 		if (!test_bit(hwc->idx, c->idxmsk))
 			break;
 
+		mask = BIT_ULL(hwc->idx);
+		if (is_counter_pair(hwc))
+			mask |= mask << 1;
+
 		/* not already used */
-		if (test_bit(hwc->idx, used_mask))
+		if (used_mask & mask)
 			break;
 
-		__set_bit(hwc->idx, used_mask);
+		used_mask |= mask;
+
 		if (assign)
 			assign[i] = hwc->idx;
 	}
@@ -952,6 +981,15 @@
 		    READ_ONCE(cpuc->excl_cntrs->exclusive_present))
 			gpmax /= 2;
 
+		/*
+		 * Reduce the amount of available counters to allow fitting
+		 * the extra Merge events needed by large increment events.
+		 */
+		if (x86_pmu.flags & PMU_FL_PAIR) {
+			gpmax = x86_pmu.num_counters - cpuc->n_pair;
+			WARN_ON(gpmax <= 0);
+		}
+
 		unsched = perf_assign_events(cpuc->event_constraint, n, wmin,
 					     wmax, gpmax, assign);
 	}
@@ -1032,6 +1070,8 @@
 			return -EINVAL;
 		cpuc->event_list[n] = leader;
 		n++;
+		if (is_counter_pair(&leader->hw))
+			cpuc->n_pair++;
 	}
 	if (!dogrp)
 		return n;
@@ -1046,6 +1086,8 @@
 
 		cpuc->event_list[n] = event;
 		n++;
+		if (is_counter_pair(&event->hw))
+			cpuc->n_pair++;
 	}
 	return n;
 }
@@ -1232,6 +1274,13 @@
 	wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
 
 	/*
+	 * Clear the Merge event counter's upper 16 bits since
+	 * we currently declare a 48-bit counter width
+	 */
+	if (is_counter_pair(hwc))
+		wrmsrl(x86_pmu_event_addr(idx + 1), 0);
+
+	/*
 	 * Due to erratum on certan cpu we need
 	 * a second write to be sure the register
 	 * is updated properly
@@ -1641,9 +1690,12 @@
 
 ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page)
 {
-	struct perf_pmu_events_attr *pmu_attr = \
+	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);
+	u64 config = 0;
+
+	if (pmu_attr->id < x86_pmu.max_events)
+		config = x86_pmu.event_map(pmu_attr->id);
 
 	/* string trumps id */
 	if (pmu_attr->event_str)
@@ -1712,6 +1764,9 @@
 {
 	struct perf_pmu_events_attr *pmu_attr;
 
+	if (idx >= x86_pmu.max_events)
+		return 0;
+
 	pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
 	/* str trumps id */
 	return pmu_attr->event_str || x86_pmu.event_map(idx) ? attr->mode : 0;
@@ -2097,6 +2152,7 @@
 	if (err) {
 		if (event->destroy)
 			event->destroy(event);
+		event->destroy = NULL;
 	}
 
 	if (READ_ONCE(x86_pmu.attr_rdpmc) &&
@@ -2354,10 +2410,11 @@
 void
 perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct unwind_state state;
 	unsigned long addr;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* TODO: We don't support guest os callchain now */
 		return;
 	}
@@ -2463,10 +2520,11 @@
 void
 perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	struct stack_frame frame;
 	const unsigned long __user *fp;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+	if (guest_cbs && guest_cbs->is_in_guest()) {
 		/* TODO: We don't support guest os callchain now */
 		return;
 	}
@@ -2550,18 +2608,21 @@
 
 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();
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
+
+	if (guest_cbs && guest_cbs->is_in_guest())
+		return guest_cbs->get_guest_ip();
 
 	return regs->ip + code_segment_base(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
+	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 	int misc = 0;
 
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-		if (perf_guest_cbs->is_user_mode())
+	if (guest_cbs && guest_cbs->is_in_guest()) {
+		if (guest_cbs->is_user_mode())
 			misc |= PERF_RECORD_MISC_GUEST_USER;
 		else
 			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
--- linux-ein-5.4.0.orig/arch/x86/events/intel/Makefile
+++ linux-ein-5.4.0/arch/x86/events/intel/Makefile
@@ -2,8 +2,6 @@
 obj-$(CONFIG_CPU_SUP_INTEL)		+= core.o bts.o
 obj-$(CONFIG_CPU_SUP_INTEL)		+= ds.o knc.o
 obj-$(CONFIG_CPU_SUP_INTEL)		+= lbr.o p4.o p6.o pt.o
-obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL)	+= intel-rapl-perf.o
-intel-rapl-perf-objs			:= rapl.o
 obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE)	+= intel-uncore.o
 intel-uncore-objs			:= uncore.o uncore_nhmex.o uncore_snb.o uncore_snbep.o
 obj-$(CONFIG_PERF_EVENTS_INTEL_CSTATE)	+= intel-cstate.o
--- linux-ein-5.4.0.orig/arch/x86/events/intel/bts.c
+++ linux-ein-5.4.0/arch/x86/events/intel/bts.c
@@ -63,9 +63,17 @@
 
 static struct pmu bts_pmu;
 
+static int buf_nr_pages(struct page *page)
+{
+	if (!PagePrivate(page))
+		return 1;
+
+	return 1 << page_private(page);
+}
+
 static size_t buf_size(struct page *page)
 {
-	return 1 << (PAGE_SHIFT + page_private(page));
+	return buf_nr_pages(page) * PAGE_SIZE;
 }
 
 static void *
@@ -83,9 +91,7 @@
 	/* 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);
+		pg += buf_nr_pages(page);
 		nbuf++;
 	}
 
@@ -109,7 +115,7 @@
 		unsigned int __nr_pages;
 
 		page = virt_to_page(pages[pg]);
-		__nr_pages = PagePrivate(page) ? 1 << page_private(page) : 1;
+		__nr_pages = buf_nr_pages(page);
 		buf->buf[nbuf].page = page;
 		buf->buf[nbuf].offset = offset;
 		buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0);
--- linux-ein-5.4.0.orig/arch/x86/events/intel/core.c
+++ linux-ein-5.4.0/arch/x86/events/intel/core.c
@@ -243,21 +243,23 @@
 
 static struct event_constraint intel_icl_event_constraints[] = {
 	FIXED_EVENT_CONSTRAINT(0x00c0, 0),	/* INST_RETIRED.ANY */
-	INTEL_UEVENT_CONSTRAINT(0x1c0, 0),	/* INST_RETIRED.PREC_DIST */
+	FIXED_EVENT_CONSTRAINT(0x01c0, 0),	/* INST_RETIRED.PREC_DIST */
 	FIXED_EVENT_CONSTRAINT(0x003c, 1),	/* CPU_CLK_UNHALTED.CORE */
 	FIXED_EVENT_CONSTRAINT(0x0300, 2),	/* CPU_CLK_UNHALTED.REF */
 	FIXED_EVENT_CONSTRAINT(0x0400, 3),	/* SLOTS */
 	INTEL_EVENT_CONSTRAINT_RANGE(0x03, 0x0a, 0xf),
 	INTEL_EVENT_CONSTRAINT_RANGE(0x1f, 0x28, 0xf),
 	INTEL_EVENT_CONSTRAINT(0x32, 0xf),	/* SW_PREFETCH_ACCESS.* */
-	INTEL_EVENT_CONSTRAINT_RANGE(0x48, 0x54, 0xf),
+	INTEL_EVENT_CONSTRAINT_RANGE(0x48, 0x56, 0xf),
 	INTEL_EVENT_CONSTRAINT_RANGE(0x60, 0x8b, 0xf),
 	INTEL_UEVENT_CONSTRAINT(0x04a3, 0xff),  /* CYCLE_ACTIVITY.STALLS_TOTAL */
-	INTEL_UEVENT_CONSTRAINT(0x10a3, 0xff),  /* CYCLE_ACTIVITY.STALLS_MEM_ANY */
+	INTEL_UEVENT_CONSTRAINT(0x10a3, 0xff),  /* CYCLE_ACTIVITY.CYCLES_MEM_ANY */
+	INTEL_UEVENT_CONSTRAINT(0x14a3, 0xff),  /* CYCLE_ACTIVITY.STALLS_MEM_ANY */
 	INTEL_EVENT_CONSTRAINT(0xa3, 0xf),      /* CYCLE_ACTIVITY.* */
 	INTEL_EVENT_CONSTRAINT_RANGE(0xa8, 0xb0, 0xf),
 	INTEL_EVENT_CONSTRAINT_RANGE(0xb7, 0xbd, 0xf),
 	INTEL_EVENT_CONSTRAINT_RANGE(0xd0, 0xe6, 0xf),
+	INTEL_EVENT_CONSTRAINT(0xef, 0xf),
 	INTEL_EVENT_CONSTRAINT_RANGE(0xf0, 0xf4, 0xf),
 	EVENT_CONSTRAINT_END
 };
@@ -1892,8 +1894,8 @@
 
 static struct extra_reg intel_tnt_extra_regs[] __read_mostly = {
 	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
-	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffffff9fffull, RSP_0),
-	INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0xffffff9fffull, RSP_1),
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x800ff0ffffff9fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0xff0ffffff9fffull, RSP_1),
 	EVENT_EXTRA_END
 };
 
@@ -2331,6 +2333,7 @@
 {
 	struct perf_sample_data data;
 	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	struct perf_guest_info_callbacks *guest_cbs;
 	int bit;
 	int handled = 0;
 
@@ -2384,9 +2387,11 @@
 	 */
 	if (__test_and_clear_bit(55, (unsigned long *)&status)) {
 		handled++;
-		if (unlikely(perf_guest_cbs && perf_guest_cbs->is_in_guest() &&
-			perf_guest_cbs->handle_intel_pt_intr))
-			perf_guest_cbs->handle_intel_pt_intr();
+
+		guest_cbs = perf_get_guest_cbs();
+		if (unlikely(guest_cbs && guest_cbs->is_in_guest() &&
+			     guest_cbs->handle_intel_pt_intr))
+			guest_cbs->handle_intel_pt_intr();
 		else
 			intel_pt_interrupt();
 	}
@@ -3998,9 +4003,13 @@
 	INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D,		 3, 0x07000009),
 	INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D,		 4, 0x0f000009),
 	INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D,		 5, 0x0e000002),
-	INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X,		 2, 0x0b000014),
+	INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X,		 1, 0x0b000014),
 	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		 3, 0x00000021),
 	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		 4, 0x00000000),
+	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		 5, 0x00000000),
+	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		 6, 0x00000000),
+	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		 7, 0x00000000),
+	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X,		11, 0x00000000),
 	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_L,		 3, 0x0000007c),
 	INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE,		 3, 0x0000007c),
 	INTEL_CPU_DESC(INTEL_FAM6_KABYLAKE,		 9, 0x0000004e),
@@ -4746,6 +4755,7 @@
 		break;
 
 	case INTEL_FAM6_ATOM_TREMONT_D:
+	case INTEL_FAM6_ATOM_TREMONT:
 		x86_pmu.late_ack = true;
 		memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
 		       sizeof(hw_cache_event_ids));
@@ -5056,7 +5066,7 @@
 		extra_skl_attr = skl_format_attr;
 		mem_attr = icl_events_attrs;
 		tsx_attr = icl_tsx_events_attrs;
-		x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xca, .umask=0x02);
+		x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xc9, .umask=0x04);
 		x86_pmu.lbr_pt_coexist = true;
 		intel_pmu_pebs_data_source_skl(pmem);
 		pr_cont("Icelake events, ");
--- linux-ein-5.4.0.orig/arch/x86/events/intel/cstate.c
+++ linux-ein-5.4.0/arch/x86/events/intel/cstate.c
@@ -40,17 +40,18 @@
  * Model specific counters:
  *	MSR_CORE_C1_RES: CORE C1 Residency Counter
  *			 perf code: 0x00
- *			 Available model: SLM,AMT,GLM,CNL
+ *			 Available model: SLM,AMT,GLM,CNL,TNT
  *			 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,GLM,
- *						CNL,KBL,CML
+ *						CNL,KBL,CML,TNT
  *			       Scope: Core
  *	MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
  *			       perf code: 0x02
  *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
- *						SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL
+ *						SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL,
+ *						TNT
  *			       Scope: Core
  *	MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
  *			       perf code: 0x03
@@ -60,17 +61,18 @@
  *	MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
  *			       perf code: 0x00
  *			       Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
- *						KBL,CML,ICL,TGL
+ *						KBL,CML,ICL,TGL,TNT
  *			       Scope: Package (physical package)
  *	MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
  *			       perf code: 0x01
  *			       Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL,
- *						GLM,CNL,KBL,CML,ICL,TGL
+ *						GLM,CNL,KBL,CML,ICL,TGL,TNT
  *			       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,KNL,GLM,CNL,KBL,CML,ICL,TGL
+ *			       Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
+ *						SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL,
+ *						TNT
  *			       Scope: Package (physical package)
  *	MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
  *			       perf code: 0x03
@@ -87,7 +89,8 @@
  *			       Scope: Package (physical package)
  *	MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
  *			       perf code: 0x06
- *			       Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL
+ *			       Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
+ *						TNT
  *			       Scope: Package (physical package)
  *
  */
@@ -104,14 +107,14 @@
 MODULE_LICENSE("GPL");
 
 #define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format)		\
-static ssize_t __cstate_##_var##_show(struct kobject *kobj,	\
-				struct kobj_attribute *attr,	\
+static ssize_t __cstate_##_var##_show(struct device *dev,	\
+				struct device_attribute *attr,	\
 				char *page)			\
 {								\
 	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);		\
 	return sprintf(page, _format "\n");			\
 }								\
-static struct kobj_attribute format_attr_##_var =		\
+static struct device_attribute format_attr_##_var =		\
 	__ATTR(_name, 0444, __cstate_##_var##_show, NULL)
 
 static ssize_t cstate_get_attr_cpumask(struct device *dev,
@@ -640,8 +643,9 @@
 
 	X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT,   glm_cstates),
 	X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_D, glm_cstates),
-
 	X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates),
+	X86_CSTATES_MODEL(INTEL_FAM6_ATOM_TREMONT_D, glm_cstates),
+	X86_CSTATES_MODEL(INTEL_FAM6_ATOM_TREMONT, glm_cstates),
 
 	X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_L, icl_cstates),
 	X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE,   icl_cstates),
--- linux-ein-5.4.0.orig/arch/x86/events/intel/ds.c
+++ linux-ein-5.4.0/arch/x86/events/intel/ds.c
@@ -669,9 +669,7 @@
 
 static inline void intel_pmu_drain_pebs_buffer(void)
 {
-	struct pt_regs regs;
-
-	x86_pmu.drain_pebs(&regs);
+	x86_pmu.drain_pebs(NULL);
 }
 
 /*
@@ -854,8 +852,13 @@
 	INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL),	/* SLOTS */
 
 	INTEL_PLD_CONSTRAINT(0x1cd, 0xff),			/* MEM_TRANS_RETIRED.LOAD_LATENCY */
-	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x1d0, 0xf),	/* MEM_INST_RETIRED.LOAD */
-	INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x2d0, 0xf),	/* MEM_INST_RETIRED.STORE */
+	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_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_RANGE(0xd1, 0xd4, 0xf), /* MEM_LOAD_*_RETIRED.* */
 
@@ -1713,6 +1716,8 @@
 	old = ((s64)(prev_raw_count << shift) >> shift);
 	local64_add(new - old + count * period, &event->count);
 
+	local64_set(&hwc->period_left, -new);
+
 	perf_event_update_userpage(event);
 
 	return 0;
@@ -1734,6 +1739,7 @@
 	struct x86_perf_regs perf_regs;
 	struct pt_regs *regs = &perf_regs.regs;
 	void *at = get_next_pebs_record_by_bit(base, top, bit);
+	struct pt_regs dummy_iregs;
 
 	if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
 		/*
@@ -1746,6 +1752,9 @@
 	} else if (!intel_pmu_save_and_restart(event))
 		return;
 
+	if (!iregs)
+		iregs = &dummy_iregs;
+
 	while (count > 1) {
 		setup_sample(event, iregs, at, &data, regs);
 		perf_event_output(event, &data, regs);
@@ -1755,16 +1764,22 @@
 	}
 
 	setup_sample(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;
+	if (iregs == &dummy_iregs) {
+		/*
+		 * The PEBS records may be drained in the non-overflow context,
+		 * e.g., large PEBS + context switch. Perf should treat the
+		 * last record the same as other PEBS records, and doesn't
+		 * invoke the generic overflow handler.
+		 */
+		perf_event_output(event, &data, regs);
+	} else {
+		/*
+		 * 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);
 	}
-
 }
 
 static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
@@ -1880,7 +1895,7 @@
 		 */
 		if (!pebs_status && cpuc->pebs_enabled &&
 			!(cpuc->pebs_enabled & (cpuc->pebs_enabled-1)))
-			pebs_status = cpuc->pebs_enabled;
+			pebs_status = p->status = cpuc->pebs_enabled;
 
 		bit = find_first_bit((unsigned long *)&pebs_status,
 					x86_pmu.max_pebs_events);
@@ -1902,7 +1917,7 @@
 		 * that caused the PEBS record. It's called collision.
 		 * If collision happened, the record will be dropped.
 		 */
-		if (p->status != (1ULL << bit)) {
+		if (pebs_status != (1ULL << bit)) {
 			for_each_set_bit(i, (unsigned long *)&pebs_status, size)
 				error[i]++;
 			continue;
--- linux-ein-5.4.0.orig/arch/x86/events/intel/pt.c
+++ linux-ein-5.4.0/arch/x86/events/intel/pt.c
@@ -62,7 +62,7 @@
 	PT_CAP(single_range_output,	0, CPUID_ECX, BIT(2)),
 	PT_CAP(output_subsys,		0, CPUID_ECX, BIT(3)),
 	PT_CAP(payloads_lip,		0, CPUID_ECX, BIT(31)),
-	PT_CAP(num_address_ranges,	1, CPUID_EAX, 0x3),
+	PT_CAP(num_address_ranges,	1, CPUID_EAX, 0x7),
 	PT_CAP(mtc_periods,		1, CPUID_EAX, 0xffff0000),
 	PT_CAP(cycle_thresholds,	1, CPUID_EBX, 0xffff),
 	PT_CAP(psb_periods,		1, CPUID_EBX, 0xffff0000),
@@ -460,7 +460,7 @@
 			pt->filters.filter[range].msr_b = filter->msr_b;
 		}
 
-		rtit_ctl |= filter->config << pt_address_ranges[range].reg_off;
+		rtit_ctl |= (u64)filter->config << pt_address_ranges[range].reg_off;
 	}
 
 	return rtit_ctl;
--- linux-ein-5.4.0.orig/arch/x86/events/intel/uncore.c
+++ linux-ein-5.4.0/arch/x86/events/intel/uncore.c
@@ -92,8 +92,8 @@
 	return map;
 }
 
-ssize_t uncore_event_show(struct kobject *kobj,
-			  struct kobj_attribute *attr, char *buf)
+ssize_t uncore_event_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
 {
 	struct uncore_event_desc *event =
 		container_of(attr, struct uncore_event_desc, attr);
--- linux-ein-5.4.0.orig/arch/x86/events/intel/uncore.h
+++ linux-ein-5.4.0/arch/x86/events/intel/uncore.h
@@ -144,7 +144,7 @@
 #define UNCORE_BOX_FLAG_CFL8_CBOX_MSR_OFFS	2
 
 struct uncore_event_desc {
-	struct kobj_attribute attr;
+	struct device_attribute attr;
 	const char *config;
 };
 
@@ -165,8 +165,8 @@
 struct pci2phy_map *__find_pci2phy_map(int segment);
 int uncore_pcibus_to_physid(struct pci_bus *bus);
 
-ssize_t uncore_event_show(struct kobject *kobj,
-			  struct kobj_attribute *attr, char *buf);
+ssize_t uncore_event_show(struct device *dev,
+			  struct device_attribute *attr, char *buf);
 
 #define INTEL_UNCORE_EVENT_DESC(_name, _config)			\
 {								\
@@ -175,14 +175,14 @@
 }
 
 #define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format)			\
-static ssize_t __uncore_##_var##_show(struct kobject *kobj,		\
-				struct kobj_attribute *attr,		\
+static ssize_t __uncore_##_var##_show(struct device *dev,		\
+				struct device_attribute *attr,		\
 				char *page)				\
 {									\
 	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);			\
 	return sprintf(page, _format "\n");				\
 }									\
-static struct kobj_attribute format_attr_##_var =			\
+static struct device_attribute format_attr_##_var =			\
 	__ATTR(_name, 0444, __uncore_##_var##_show, NULL)
 
 static inline bool uncore_pmc_fixed(int idx)
--- linux-ein-5.4.0.orig/arch/x86/events/intel/uncore_snb.c
+++ linux-ein-5.4.0/arch/x86/events/intel/uncore_snb.c
@@ -15,6 +15,7 @@
 #define PCI_DEVICE_ID_INTEL_SKL_HQ_IMC		0x1910
 #define PCI_DEVICE_ID_INTEL_SKL_SD_IMC		0x190f
 #define PCI_DEVICE_ID_INTEL_SKL_SQ_IMC		0x191f
+#define PCI_DEVICE_ID_INTEL_SKL_E3_IMC		0x1918
 #define PCI_DEVICE_ID_INTEL_KBL_Y_IMC		0x590c
 #define PCI_DEVICE_ID_INTEL_KBL_U_IMC		0x5904
 #define PCI_DEVICE_ID_INTEL_KBL_UQ_IMC		0x5914
@@ -109,6 +110,10 @@
 #define ICL_UNC_CBO_0_PER_CTR0			0x702
 #define ICL_UNC_CBO_MSR_OFFSET			0x8
 
+/* ICL ARB register */
+#define ICL_UNC_ARB_PER_CTR			0x3b1
+#define ICL_UNC_ARB_PERFEVTSEL			0x3b3
+
 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");
@@ -296,15 +301,21 @@
 	snb_uncore_arb.ops = &skl_uncore_msr_ops;
 }
 
+static struct intel_uncore_ops icl_uncore_msr_ops = {
+	.disable_event	= snb_uncore_msr_disable_event,
+	.enable_event	= snb_uncore_msr_enable_event,
+	.read_counter	= uncore_msr_read_counter,
+};
+
 static struct intel_uncore_type icl_uncore_cbox = {
 	.name		= "cbox",
-	.num_counters   = 4,
+	.num_counters   = 2,
 	.perf_ctr_bits	= 44,
 	.perf_ctr	= ICL_UNC_CBO_0_PER_CTR0,
 	.event_ctl	= SNB_UNC_CBO_0_PERFEVTSEL0,
 	.event_mask	= SNB_UNC_RAW_EVENT_MASK,
 	.msr_offset	= ICL_UNC_CBO_MSR_OFFSET,
-	.ops		= &skl_uncore_msr_ops,
+	.ops		= &icl_uncore_msr_ops,
 	.format_group	= &snb_uncore_format_group,
 };
 
@@ -333,13 +344,25 @@
 	.single_fixed	= 1,
 	.event_mask	= SNB_UNC_CTL_EV_SEL_MASK,
 	.format_group	= &icl_uncore_clock_format_group,
-	.ops		= &skl_uncore_msr_ops,
+	.ops		= &icl_uncore_msr_ops,
 	.event_descs	= icl_uncore_events,
 };
 
+static struct intel_uncore_type icl_uncore_arb = {
+	.name		= "arb",
+	.num_counters   = 1,
+	.num_boxes	= 1,
+	.perf_ctr_bits	= 44,
+	.perf_ctr	= ICL_UNC_ARB_PER_CTR,
+	.event_ctl	= ICL_UNC_ARB_PERFEVTSEL,
+	.event_mask	= SNB_UNC_RAW_EVENT_MASK,
+	.ops		= &icl_uncore_msr_ops,
+	.format_group	= &snb_uncore_format_group,
+};
+
 static struct intel_uncore_type *icl_msr_uncores[] = {
 	&icl_uncore_cbox,
-	&snb_uncore_arb,
+	&icl_uncore_arb,
 	&icl_uncore_clockbox,
 	NULL,
 };
@@ -357,7 +380,6 @@
 {
 	uncore_msr_uncores = icl_msr_uncores;
 	icl_uncore_cbox.num_boxes = icl_get_cbox_num();
-	snb_uncore_arb.ops = &skl_uncore_msr_ops;
 }
 
 enum {
@@ -553,6 +575,22 @@
 	return 0;
 }
 
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	/*
+	 * SNB IMC counters are 32-bit and are laid out back to back
+	 * in MMIO space. Therefore we must use a 32-bit accessor function
+	 * using readq() from uncore_mmio_read_counter() causes problems
+	 * because it is reading 64-bit at a time. This is okay for the
+	 * uncore_perf_event_update() function because it drops the upper
+	 * 32-bits but not okay for plain uncore_read_counter() as invoked
+	 * in uncore_pmu_event_start().
+	 */
+	return (u64)readl(box->io_addr + hwc->event_base);
+}
+
 static struct pmu snb_uncore_imc_pmu = {
 	.task_ctx_nr	= perf_invalid_context,
 	.event_init	= snb_uncore_imc_event_init,
@@ -572,7 +610,7 @@
 	.disable_event	= snb_uncore_imc_disable_event,
 	.enable_event	= snb_uncore_imc_enable_event,
 	.hw_config	= snb_uncore_imc_hw_config,
-	.read_counter	= uncore_mmio_read_counter,
+	.read_counter	= snb_uncore_imc_read_counter,
 };
 
 static struct intel_uncore_type snb_uncore_imc = {
@@ -658,6 +696,10 @@
 		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
 	},
 	{ /* IMC */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_E3_IMC),
+		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+	},
+	{ /* IMC */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBL_Y_IMC),
 		.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
 	},
@@ -826,6 +868,7 @@
 	IMC_DEV(SKL_HQ_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core H Quad Core */
 	IMC_DEV(SKL_SD_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core S Dual Core */
 	IMC_DEV(SKL_SQ_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core S Quad Core */
+	IMC_DEV(SKL_E3_IMC, &skl_uncore_pci_driver),  /* Xeon E3 V5 Gen Core processor */
 	IMC_DEV(KBL_Y_IMC, &skl_uncore_pci_driver),  /* 7th Gen Core Y */
 	IMC_DEV(KBL_U_IMC, &skl_uncore_pci_driver),  /* 7th Gen Core U */
 	IMC_DEV(KBL_UQ_IMC, &skl_uncore_pci_driver),  /* 7th Gen Core U Quad Core */
--- linux-ein-5.4.0.orig/arch/x86/events/intel/uncore_snbep.c
+++ linux-ein-5.4.0/arch/x86/events/intel/uncore_snbep.c
@@ -369,11 +369,6 @@
 #define SNR_M2M_PCI_PMON_BOX_CTL		0x438
 #define SNR_M2M_PCI_PMON_UMASK_EXT		0xff
 
-/* SNR PCIE3 */
-#define SNR_PCIE3_PCI_PMON_CTL0			0x508
-#define SNR_PCIE3_PCI_PMON_CTR0			0x4e8
-#define SNR_PCIE3_PCI_PMON_BOX_CTL		0x4e4
-
 /* SNR IMC */
 #define SNR_IMC_MMIO_PMON_FIXED_CTL		0x54
 #define SNR_IMC_MMIO_PMON_FIXED_CTR		0x38
@@ -1098,7 +1093,6 @@
 	SNBEP_PCI_QPI_PORT0_FILTER,
 	SNBEP_PCI_QPI_PORT1_FILTER,
 	BDX_PCI_QPI_PORT2_FILTER,
-	HSWEP_PCI_PCU_3,
 };
 
 static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
@@ -2755,22 +2749,34 @@
 	NULL,
 };
 
-void hswep_uncore_cpu_init(void)
+#define HSWEP_PCU_DID			0x2fc0
+#define HSWEP_PCU_CAPID4_OFFET		0x94
+#define hswep_get_chop(_cap)		(((_cap) >> 6) & 0x3)
+
+static bool hswep_has_limit_sbox(unsigned int device)
 {
-	int pkg = boot_cpu_data.logical_proc_id;
+	struct pci_dev *dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	u32 capid4;
+
+	if (!dev)
+		return false;
+
+	pci_read_config_dword(dev, HSWEP_PCU_CAPID4_OFFET, &capid4);
+	pci_dev_put(dev);
+	if (!hswep_get_chop(capid4))
+		return true;
+
+	return false;
+}
 
+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[pkg].dev[HSWEP_PCI_PCU_3]) {
-		u32 capid4;
-
-		pci_read_config_dword(uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3],
-				      0x94, &capid4);
-		if (((capid4 >> 6) & 0x3) == 0)
-			hswep_uncore_sbox.num_boxes = 2;
-	}
+	if (hswep_has_limit_sbox(HSWEP_PCU_DID))
+		hswep_uncore_sbox.num_boxes = 2;
 
 	uncore_msr_uncores = hswep_msr_uncores;
 }
@@ -3033,11 +3039,6 @@
 		.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 */ }
 };
 
@@ -3129,27 +3130,18 @@
 	EVENT_CONSTRAINT_END
 };
 
+#define BDX_PCU_DID			0x6fc0
+
 void bdx_uncore_cpu_init(void)
 {
-	int pkg = topology_phys_to_logical_pkg(boot_cpu_data.phys_proc_id);
-
 	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;
 
-	/* BDX-DE doesn't have SBOX */
-	if (boot_cpu_data.x86_model == 86) {
-		uncore_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
 	/* Detect systems with no SBOXes */
-	} else if (uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3]) {
-		struct pci_dev *pdev;
-		u32 capid4;
-
-		pdev = uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3];
-		pci_read_config_dword(pdev, 0x94, &capid4);
-		if (((capid4 >> 6) & 0x3) == 0)
-			bdx_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
-	}
+	if ((boot_cpu_data.x86_model == 86) || hswep_has_limit_sbox(BDX_PCU_DID))
+		uncore_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
+
 	hswep_uncore_pcu.constraints = bdx_uncore_pcu_constraints;
 }
 
@@ -3370,11 +3362,6 @@
 		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
 						   BDX_PCI_QPI_PORT2_FILTER),
 	},
-	{ /* PCU.3 (for Capability registers) */
-		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fc0),
-		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-						   HSWEP_PCI_PCU_3),
-	},
 	{ /* end: all zeroes */ }
 };
 
@@ -3493,6 +3480,9 @@
 	struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
 	struct extra_reg *er;
 	int idx = 0;
+	/* Any of the CHA events may be filtered by Thread/Core-ID.*/
+	if (event->hw.config & SNBEP_CBO_PMON_CTL_TID_EN)
+		idx = SKX_CHA_MSR_PMON_BOX_FILTER_TID;
 
 	for (er = skx_uncore_cha_extra_regs; er->msr; er++) {
 		if (er->event != (event->hw.config & er->config_mask))
@@ -3560,6 +3550,7 @@
 	UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
 	UNCORE_EVENT_CONSTRAINT(0xc5, 0xc),
 	UNCORE_EVENT_CONSTRAINT(0xd4, 0xc),
+	UNCORE_EVENT_CONSTRAINT(0xd5, 0xc),
 	EVENT_CONSTRAINT_END
 };
 
@@ -4328,27 +4319,12 @@
 	.format_group	= &snr_m2m_uncore_format_group,
 };
 
-static struct intel_uncore_type snr_uncore_pcie3 = {
-	.name		= "pcie3",
-	.num_counters	= 4,
-	.num_boxes	= 1,
-	.perf_ctr_bits	= 48,
-	.perf_ctr	= SNR_PCIE3_PCI_PMON_CTR0,
-	.event_ctl	= SNR_PCIE3_PCI_PMON_CTL0,
-	.event_mask	= SNBEP_PMON_RAW_EVENT_MASK,
-	.box_ctl	= SNR_PCIE3_PCI_PMON_BOX_CTL,
-	.ops		= &ivbep_uncore_pci_ops,
-	.format_group	= &ivbep_uncore_format_group,
-};
-
 enum {
 	SNR_PCI_UNCORE_M2M,
-	SNR_PCI_UNCORE_PCIE3,
 };
 
 static struct intel_uncore_type *snr_pci_uncores[] = {
 	[SNR_PCI_UNCORE_M2M]		= &snr_uncore_m2m,
-	[SNR_PCI_UNCORE_PCIE3]		= &snr_uncore_pcie3,
 	NULL,
 };
 
@@ -4357,10 +4333,6 @@
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
 		.driver_data = UNCORE_PCI_DEV_FULL_DATA(12, 0, SNR_PCI_UNCORE_M2M, 0),
 	},
-	{ /* PCIe3 */
-		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x334a),
-		.driver_data = UNCORE_PCI_DEV_FULL_DATA(4, 0, SNR_PCI_UNCORE_PCIE3, 0),
-	},
 	{ /* end: all zeroes */ }
 };
 
@@ -4415,7 +4387,7 @@
 		return;
 
 	pci_read_config_dword(pdev, SNR_IMC_MMIO_BASE_OFFSET, &pci_dword);
-	addr = (pci_dword & SNR_IMC_MMIO_BASE_MASK) << 23;
+	addr = ((resource_size_t)pci_dword & SNR_IMC_MMIO_BASE_MASK) << 23;
 
 	pci_read_config_dword(pdev, SNR_IMC_MMIO_MEM0_OFFSET, &pci_dword);
 	addr |= (pci_dword & SNR_IMC_MMIO_MEM0_MASK) << 12;
@@ -4536,6 +4508,7 @@
 	INTEL_UNCORE_EVENT_DESC(write,		"event=0xff,umask=0x21"),
 	INTEL_UNCORE_EVENT_DESC(write.scale,	"3.814697266e-6"),
 	INTEL_UNCORE_EVENT_DESC(write.unit,	"MiB"),
+	{ /* end: all zeroes */ },
 };
 
 static struct intel_uncore_ops snr_uncore_imc_freerunning_ops = {
--- linux-ein-5.4.0.orig/arch/x86/events/msr.c
+++ linux-ein-5.4.0/arch/x86/events/msr.c
@@ -75,8 +75,9 @@
 
 	case INTEL_FAM6_ATOM_GOLDMONT:
 	case INTEL_FAM6_ATOM_GOLDMONT_D:
-
 	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
+	case INTEL_FAM6_ATOM_TREMONT_D:
+	case INTEL_FAM6_ATOM_TREMONT:
 
 	case INTEL_FAM6_XEON_PHI_KNL:
 	case INTEL_FAM6_XEON_PHI_KNM:
--- linux-ein-5.4.0.orig/arch/x86/events/perf_event.h
+++ linux-ein-5.4.0/arch/x86/events/perf_event.h
@@ -77,6 +77,7 @@
 #define PERF_X86_EVENT_AUTO_RELOAD	0x0200 /* use PEBS auto-reload */
 #define PERF_X86_EVENT_LARGE_PEBS	0x0400 /* use large PEBS */
 #define PERF_X86_EVENT_PEBS_VIA_PT	0x0800 /* use PT buffer for PEBS */
+#define PERF_X86_EVENT_PAIR		0x1000 /* Large Increment per Cycle */
 
 struct amd_nb {
 	int nb_id;  /* NorthBridge id */
@@ -272,6 +273,7 @@
 	struct amd_nb			*amd_nb;
 	/* Inverted mask of bits to clear in the perf_ctr ctrl registers */
 	u64				perf_ctr_virt_mask;
+	int				n_pair; /* Large increment events */
 
 	void				*kfree_on_online[X86_PERF_KFREE_MAX];
 };
@@ -686,6 +688,7 @@
 	 * AMD bits
 	 */
 	unsigned int	amd_nb_constraints : 1;
+	u64		perf_ctr_pair_en;
 
 	/*
 	 * Extra registers for events
@@ -735,6 +738,7 @@
 #define PMU_FL_EXCL_ENABLED	0x8 /* exclusive counter active */
 #define PMU_FL_PEBS_ALL		0x10 /* all events are valid PEBS events */
 #define PMU_FL_TFA		0x20 /* deal with TSX force abort */
+#define PMU_FL_PAIR		0x40 /* merge counters for large incr. events */
 
 #define EVENT_VAR(_id)  event_attr_##_id
 #define EVENT_PTR(_id) &event_attr_##_id.attr.attr
@@ -830,6 +834,11 @@
 
 void x86_pmu_disable_all(void);
 
+static inline bool is_counter_pair(struct hw_perf_event *hwc)
+{
+	return hwc->flags & PERF_X86_EVENT_PAIR;
+}
+
 static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
 					  u64 enable_mask)
 {
@@ -837,6 +846,14 @@
 
 	if (hwc->extra_reg.reg)
 		wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config);
+
+	/*
+	 * Add enabled Merge event on next counter
+	 * if large increment event being enabled on this counter
+	 */
+	if (is_counter_pair(hwc))
+		wrmsrl(x86_pmu_config_addr(hwc->idx + 1), x86_pmu.perf_ctr_pair_en);
+
 	wrmsrl(hwc->config_base, (hwc->config | enable_mask) & ~disable_mask);
 }
 
@@ -850,9 +867,13 @@
 
 static inline void x86_pmu_disable_event(struct perf_event *event)
 {
+	u64 disable_mask = __this_cpu_read(cpu_hw_events.perf_ctr_virt_mask);
 	struct hw_perf_event *hwc = &event->hw;
 
-	wrmsrl(hwc->config_base, hwc->config);
+	wrmsrl(hwc->config_base, hwc->config & ~disable_mask);
+
+	if (is_counter_pair(hwc))
+		wrmsrl(x86_pmu_config_addr(hwc->idx + 1), 0);
 }
 
 void x86_pmu_enable_event(struct perf_event *event);
--- linux-ein-5.4.0.orig/arch/x86/events/rapl.c
+++ linux-ein-5.4.0/arch/x86/events/rapl.c
@@ -0,0 +1,793 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support Intel/AMD 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)
+ *
+ * AMD RAPL interface for Fam17h is described in the public PPR:
+ * https://bugzilla.kernel.org/show_bug.cgi?id=206537
+ *
+ * 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
+ *
+ * gpu counter: consumption of the builtin-gpu domain (client only)
+ *	  event: rapl_energy_gpu
+ *    perf code: 0x4
+ *
+ *  psys counter: consumption of the builtin-psys domain (client only)
+ *	  event: rapl_energy_psys
+ *    perf code: 0x5
+ *
+ * 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);
+ */
+
+#define pr_fmt(fmt) "RAPL PMU: " fmt
+
+#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"
+#include "probe.h"
+
+MODULE_LICENSE("GPL");
+
+/*
+ * RAPL energy status counters
+ */
+enum perf_rapl_events {
+	PERF_RAPL_PP0 = 0,		/* all cores */
+	PERF_RAPL_PKG,			/* entire package */
+	PERF_RAPL_RAM,			/* DRAM */
+	PERF_RAPL_PP1,			/* gpu */
+	PERF_RAPL_PSYS,			/* psys */
+
+	PERF_RAPL_MAX,
+	NR_RAPL_DOMAINS = PERF_RAPL_MAX,
+};
+
+static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
+	"pp0-core",
+	"package",
+	"dram",
+	"pp1-gpu",
+	"psys",
+};
+
+/*
+ * event code: LSB 8 bits, passed in attr->config
+ * any other bit is reserved
+ */
+#define RAPL_EVENT_MASK	0xFFULL
+#define RAPL_CNTR_WIDTH 32
+
+#define RAPL_EVENT_ATTR_STR(_name, v, str)					\
+static struct perf_pmu_events_attr event_attr_##v = {				\
+	.attr		= __ATTR(_name, 0444, perf_event_sysfs_show, NULL),	\
+	.id		= 0,							\
+	.event_str	= str,							\
+};
+
+struct rapl_pmu {
+	raw_spinlock_t		lock;
+	int			n_active;
+	int			cpu;
+	struct list_head	active_list;
+	struct pmu		*pmu;
+	ktime_t			timer_interval;
+	struct hrtimer		hrtimer;
+};
+
+struct rapl_pmus {
+	struct pmu		pmu;
+	unsigned int		maxdie;
+	struct rapl_pmu		*pmus[];
+};
+
+struct rapl_model {
+	unsigned long	events;
+	bool		apply_quirk;
+};
+
+ /* 1/2^hw_unit Joule */
+static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly;
+static struct rapl_pmus *rapl_pmus;
+static cpumask_t rapl_cpu_mask;
+static unsigned int rapl_cntr_mask;
+static u64 rapl_timer_ms;
+static struct perf_msr rapl_msrs[];
+
+static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
+{
+	unsigned int dieid = topology_logical_die_id(cpu);
+
+	/*
+	 * The unsigned check also catches the '-1' return value for non
+	 * existent mappings in the topology map.
+	 */
+	return dieid < rapl_pmus->maxdie ? rapl_pmus->pmus[dieid] : NULL;
+}
+
+static inline u64 rapl_read_counter(struct perf_event *event)
+{
+	u64 raw;
+	rdmsrl(event->hw.event_base, raw);
+	return raw;
+}
+
+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 enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer)
+{
+	struct rapl_pmu *pmu = container_of(hrtimer, struct rapl_pmu, hrtimer);
+	struct perf_event *event;
+	unsigned long flags;
+
+	if (!pmu->n_active)
+		return HRTIMER_NORESTART;
+
+	raw_spin_lock_irqsave(&pmu->lock, flags);
+
+	list_for_each_entry(event, &pmu->active_list, active_entry)
+		rapl_event_update(event);
+
+	raw_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 = event->pmu_private;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&pmu->lock, flags);
+	__rapl_pmu_event_start(pmu, event);
+	raw_spin_unlock_irqrestore(&pmu->lock, flags);
+}
+
+static void rapl_pmu_event_stop(struct perf_event *event, int mode)
+{
+	struct rapl_pmu *pmu = event->pmu_private;
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long flags;
+
+	raw_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)
+			hrtimer_cancel(&pmu->hrtimer);
+
+		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;
+	}
+
+	raw_spin_unlock_irqrestore(&pmu->lock, flags);
+}
+
+static int rapl_pmu_event_add(struct perf_event *event, int mode)
+{
+	struct rapl_pmu *pmu = event->pmu_private;
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long flags;
+
+	raw_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);
+
+	raw_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, ret = 0;
+	struct rapl_pmu *pmu;
+
+	/* only look at RAPL events */
+	if (event->attr.type != rapl_pmus->pmu.type)
+		return -ENOENT;
+
+	/* check only supported bits are set */
+	if (event->attr.config & ~RAPL_EVENT_MASK)
+		return -EINVAL;
+
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
+
+	if (!cfg || cfg >= NR_RAPL_DOMAINS + 1)
+		return -EINVAL;
+
+	cfg = array_index_nospec((long)cfg, NR_RAPL_DOMAINS + 1);
+	bit = cfg - 1;
+
+	/* check event supported */
+	if (!(rapl_cntr_mask & (1 << bit)))
+		return -EINVAL;
+
+	/* unsupported modes and filters */
+	if (event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	/* must be done before validate_group */
+	pmu = cpu_to_rapl_pmu(event->cpu);
+	if (!pmu)
+		return -EINVAL;
+	event->cpu = pmu->cpu;
+	event->pmu_private = pmu;
+	event->hw.event_base = rapl_msrs[bit].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,
+};
+
+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-psys,   rapl_psys, "event=0x05");
+
+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");
+RAPL_EVENT_ATTR_STR(energy-psys.unit,   rapl_psys_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");
+RAPL_EVENT_ATTR_STR(energy-psys.scale,   rapl_psys_scale, "2.3283064365386962890625e-10");
+
+/*
+ * There are no default events, but we need to create
+ * "events" group (with empty attrs) before updating
+ * it with detected events.
+ */
+static struct attribute *attrs_empty[] = {
+	NULL,
+};
+
+static struct attribute_group rapl_pmu_events_group = {
+	.name = "events",
+	.attrs = attrs_empty,
+};
+
+PMU_FORMAT_ATTR(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,
+};
+
+static const struct attribute_group *rapl_attr_groups[] = {
+	&rapl_pmu_attr_group,
+	&rapl_pmu_format_group,
+	&rapl_pmu_events_group,
+	NULL,
+};
+
+static struct attribute *rapl_events_cores[] = {
+	EVENT_PTR(rapl_cores),
+	EVENT_PTR(rapl_cores_unit),
+	EVENT_PTR(rapl_cores_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_events_cores_group = {
+	.name  = "events",
+	.attrs = rapl_events_cores,
+};
+
+static struct attribute *rapl_events_pkg[] = {
+	EVENT_PTR(rapl_pkg),
+	EVENT_PTR(rapl_pkg_unit),
+	EVENT_PTR(rapl_pkg_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_events_pkg_group = {
+	.name  = "events",
+	.attrs = rapl_events_pkg,
+};
+
+static struct attribute *rapl_events_ram[] = {
+	EVENT_PTR(rapl_ram),
+	EVENT_PTR(rapl_ram_unit),
+	EVENT_PTR(rapl_ram_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_events_ram_group = {
+	.name  = "events",
+	.attrs = rapl_events_ram,
+};
+
+static struct attribute *rapl_events_gpu[] = {
+	EVENT_PTR(rapl_gpu),
+	EVENT_PTR(rapl_gpu_unit),
+	EVENT_PTR(rapl_gpu_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_events_gpu_group = {
+	.name  = "events",
+	.attrs = rapl_events_gpu,
+};
+
+static struct attribute *rapl_events_psys[] = {
+	EVENT_PTR(rapl_psys),
+	EVENT_PTR(rapl_psys_unit),
+	EVENT_PTR(rapl_psys_scale),
+	NULL,
+};
+
+static struct attribute_group rapl_events_psys_group = {
+	.name  = "events",
+	.attrs = rapl_events_psys,
+};
+
+static bool test_msr(int idx, void *data)
+{
+	return test_bit(idx, (unsigned long *) data);
+}
+
+static struct perf_msr rapl_msrs[] = {
+	[PERF_RAPL_PP0]  = { MSR_PP0_ENERGY_STATUS,      &rapl_events_cores_group, test_msr },
+	[PERF_RAPL_PKG]  = { MSR_PKG_ENERGY_STATUS,      &rapl_events_pkg_group,   test_msr },
+	[PERF_RAPL_RAM]  = { MSR_DRAM_ENERGY_STATUS,     &rapl_events_ram_group,   test_msr },
+	[PERF_RAPL_PP1]  = { MSR_PP1_ENERGY_STATUS,      &rapl_events_gpu_group,   test_msr },
+	[PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group,  test_msr },
+};
+
+static int rapl_cpu_offline(unsigned int cpu)
+{
+	struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
+	int target;
+
+	/* Check if exiting cpu is used for collecting rapl events */
+	if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask))
+		return 0;
+
+	pmu->cpu = -1;
+	/* Find a new cpu to collect rapl events */
+	target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
+
+	/* Migrate rapl events to the new target */
+	if (target < nr_cpu_ids) {
+		cpumask_set_cpu(target, &rapl_cpu_mask);
+		pmu->cpu = target;
+		perf_pmu_migrate_context(pmu->pmu, cpu, target);
+	}
+	return 0;
+}
+
+static int rapl_cpu_online(unsigned int cpu)
+{
+	struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
+	int target;
+
+	if (!pmu) {
+		pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+		if (!pmu)
+			return -ENOMEM;
+
+		raw_spin_lock_init(&pmu->lock);
+		INIT_LIST_HEAD(&pmu->active_list);
+		pmu->pmu = &rapl_pmus->pmu;
+		pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
+		rapl_hrtimer_init(pmu);
+
+		rapl_pmus->pmus[topology_logical_die_id(cpu)] = pmu;
+	}
+
+	/*
+	 * Check if there is an online cpu in the package which collects rapl
+	 * events already.
+	 */
+	target = cpumask_any_and(&rapl_cpu_mask, topology_die_cpumask(cpu));
+	if (target < nr_cpu_ids)
+		return 0;
+
+	cpumask_set_cpu(cpu, &rapl_cpu_mask);
+	pmu->cpu = cpu;
+	return 0;
+}
+
+static int rapl_check_hw_unit(bool apply_quirk)
+{
+	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;
+
+	/*
+	 * DRAM domain on HSW server and KNL has fixed energy unit which can be
+	 * different than the unit from power unit MSR. See
+	 * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2
+	 * of 2. Datasheet, September 2014, Reference Number: 330784-001 "
+	 */
+	if (apply_quirk)
+		rapl_hw_unit[PERF_RAPL_RAM] = 16;
+
+	/*
+	 * Calculate the timer rate:
+	 * Use reference of 200W for scaling the timeout to avoid 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
+	 */
+	rapl_timer_ms = 2;
+	if (rapl_hw_unit[0] < 32) {
+		rapl_timer_ms = (1000 / (2 * 100));
+		rapl_timer_ms *= (1ULL << (32 - rapl_hw_unit[0] - 1));
+	}
+	return 0;
+}
+
+static void __init rapl_advertise(void)
+{
+	int i;
+
+	pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
+		hweight32(rapl_cntr_mask), rapl_timer_ms);
+
+	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]);
+		}
+	}
+}
+
+static void cleanup_rapl_pmus(void)
+{
+	int i;
+
+	for (i = 0; i < rapl_pmus->maxdie; i++)
+		kfree(rapl_pmus->pmus[i]);
+	kfree(rapl_pmus);
+}
+
+static const struct attribute_group *rapl_attr_update[] = {
+	&rapl_events_cores_group,
+	&rapl_events_pkg_group,
+	&rapl_events_ram_group,
+	&rapl_events_gpu_group,
+	&rapl_events_psys_group,
+	NULL,
+};
+
+static int __init init_rapl_pmus(void)
+{
+	int maxdie = topology_max_packages() * topology_max_die_per_package();
+	size_t size;
+
+	size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *);
+	rapl_pmus = kzalloc(size, GFP_KERNEL);
+	if (!rapl_pmus)
+		return -ENOMEM;
+
+	rapl_pmus->maxdie		= maxdie;
+	rapl_pmus->pmu.attr_groups	= rapl_attr_groups;
+	rapl_pmus->pmu.attr_update	= rapl_attr_update;
+	rapl_pmus->pmu.task_ctx_nr	= perf_invalid_context;
+	rapl_pmus->pmu.event_init	= rapl_pmu_event_init;
+	rapl_pmus->pmu.add		= rapl_pmu_event_add;
+	rapl_pmus->pmu.del		= rapl_pmu_event_del;
+	rapl_pmus->pmu.start		= rapl_pmu_event_start;
+	rapl_pmus->pmu.stop		= rapl_pmu_event_stop;
+	rapl_pmus->pmu.read		= rapl_pmu_event_read;
+	rapl_pmus->pmu.module		= THIS_MODULE;
+	rapl_pmus->pmu.capabilities	= PERF_PMU_CAP_NO_EXCLUDE;
+	return 0;
+}
+
+#define X86_RAPL_MODEL_MATCH(model, init)	\
+	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
+
+static struct rapl_model model_snb = {
+	.events		= BIT(PERF_RAPL_PP0) |
+			  BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_PP1),
+	.apply_quirk	= false,
+};
+
+static struct rapl_model model_snbep = {
+	.events		= BIT(PERF_RAPL_PP0) |
+			  BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_RAM),
+	.apply_quirk	= false,
+};
+
+static struct rapl_model model_hsw = {
+	.events		= BIT(PERF_RAPL_PP0) |
+			  BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_RAM) |
+			  BIT(PERF_RAPL_PP1),
+	.apply_quirk	= false,
+};
+
+static struct rapl_model model_hsx = {
+	.events		= BIT(PERF_RAPL_PP0) |
+			  BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_RAM),
+	.apply_quirk	= true,
+};
+
+static struct rapl_model model_knl = {
+	.events		= BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_RAM),
+	.apply_quirk	= true,
+};
+
+static struct rapl_model model_skl = {
+	.events		= BIT(PERF_RAPL_PP0) |
+			  BIT(PERF_RAPL_PKG) |
+			  BIT(PERF_RAPL_RAM) |
+			  BIT(PERF_RAPL_PP1) |
+			  BIT(PERF_RAPL_PSYS),
+	.apply_quirk	= false,
+};
+
+static const struct x86_cpu_id rapl_model_match[] __initconst = {
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE,		model_snb),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X,		model_snbep),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE,		model_snb),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X,		model_snbep),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X,		model_hsx),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_L,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_G,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_G,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X,		model_hsx),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_D,		model_hsx),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL,		model_knl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM,		model_knl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_L,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,		model_hsx),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_L,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_L,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT,		model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_D,	model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS,	model_hsw),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_L,		model_skl),
+	X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE,		model_skl),
+	{},
+};
+
+MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
+
+static int __init rapl_pmu_init(void)
+{
+	const struct x86_cpu_id *id;
+	struct rapl_model *rm;
+	int ret;
+
+	id = x86_match_cpu(rapl_model_match);
+	if (!id)
+		return -ENODEV;
+
+	rm = (struct rapl_model *) id->driver_data;
+	rapl_cntr_mask = perf_msr_probe(rapl_msrs, PERF_RAPL_MAX,
+					false, (void *) &rm->events);
+
+	ret = rapl_check_hw_unit(rm->apply_quirk);
+	if (ret)
+		return ret;
+
+	ret = init_rapl_pmus();
+	if (ret)
+		return ret;
+
+	/*
+	 * Install callbacks. Core will call them for each online cpu.
+	 */
+	ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
+				"perf/x86/rapl:online",
+				rapl_cpu_online, rapl_cpu_offline);
+	if (ret)
+		goto out;
+
+	ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
+	if (ret)
+		goto out1;
+
+	rapl_advertise();
+	return 0;
+
+out1:
+	cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
+out:
+	pr_warn("Initialization failed (%d), disabled\n", ret);
+	cleanup_rapl_pmus();
+	return ret;
+}
+module_init(rapl_pmu_init);
+
+static void __exit intel_rapl_exit(void)
+{
+	cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
+	perf_pmu_unregister(&rapl_pmus->pmu);
+	cleanup_rapl_pmus();
+}
+module_exit(intel_rapl_exit);
--- linux-ein-5.4.0.orig/arch/x86/hyperv/hv_init.c
+++ linux-ein-5.4.0/arch/x86/hyperv/hv_init.c
@@ -19,9 +19,18 @@
 #include <linux/mm.h>
 #include <linux/hyperv.h>
 #include <linux/slab.h>
+#include <linux/kernel.h>
 #include <linux/cpuhotplug.h>
 #include <clocksource/hyperv_timer.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
+
 void *hv_hypercall_pg;
 EXPORT_SYMBOL_GPL(hv_hypercall_pg);
 
@@ -154,7 +163,6 @@
 	struct hv_reenlightenment_control re_ctrl = {
 		.vector = HYPERV_REENLIGHTENMENT_VECTOR,
 		.enabled = 1,
-		.target_vp = hv_vp_index[smp_processor_id()]
 	};
 	struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
 
@@ -163,13 +171,20 @@
 		return;
 	}
 
+	if (!hv_vp_index)
+		return;
+
 	hv_reenlightenment_cb = cb;
 
 	/* Make sure callback is registered before we write to MSRs */
 	wmb();
 
+	re_ctrl.target_vp = hv_vp_index[get_cpu()];
+
 	wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
 	wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl));
+
+	put_cpu();
 }
 EXPORT_SYMBOL_GPL(set_hv_tscchange_cb);
 
@@ -297,7 +312,7 @@
 	 * 1. Register the guest ID
 	 * 2. Enable the hypercall and register the hypercall page
 	 */
-	guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+	guest_id = generate_guest_id(0x80 /*Canonical*/, LINUX_VERSION_CODE, PKG_ABI);
 	wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
 
 	hv_hypercall_pg  = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
@@ -354,11 +369,14 @@
 }
 EXPORT_SYMBOL_GPL(hyperv_cleanup);
 
-void hyperv_report_panic(struct pt_regs *regs, long err)
+void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
 {
 	static bool panic_reported;
 	u64 guest_id;
 
+	if (in_die && !panic_on_oops)
+		return;
+
 	/*
 	 * We prefer to report panic on 'die' chain as we have proper
 	 * registers to report, but if we miss it (e.g. on BUG()) we need
--- linux-ein-5.4.0.orig/arch/x86/hyperv/mmu.c
+++ linux-ein-5.4.0/arch/x86/hyperv/mmu.c
@@ -66,11 +66,17 @@
 	if (!hv_hypercall_pg)
 		goto do_native;
 
-	if (cpumask_empty(cpus))
-		return;
-
 	local_irq_save(flags);
 
+	/*
+	 * Only check the mask _after_ interrupt has been disabled to avoid the
+	 * mask changing under our feet.
+	 */
+	if (cpumask_empty(cpus)) {
+		local_irq_restore(flags);
+		return;
+	}
+
 	flush_pcpu = (struct hv_tlb_flush **)
 		     this_cpu_ptr(hyperv_pcpu_input_arg);
 
--- linux-ein-5.4.0.orig/arch/x86/ia32/ia32_aout.c
+++ linux-ein-5.4.0/arch/x86/ia32/ia32_aout.c
@@ -140,6 +140,7 @@
 	set_personality_ia32(false);
 
 	setup_new_exec(bprm);
+	install_exec_creds(bprm);
 
 	regs->cs = __USER32_CS;
 	regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
@@ -156,8 +157,6 @@
 	if (retval < 0)
 		return retval;
 
-	install_exec_creds(bprm);
-
 	if (N_MAGIC(ex) == OMAGIC) {
 		unsigned long text_addr, map_size;
 
--- linux-ein-5.4.0.orig/arch/x86/ia32/ia32_signal.c
+++ linux-ein-5.4.0/arch/x86/ia32/ia32_signal.c
@@ -21,6 +21,7 @@
 #include <linux/personality.h>
 #include <linux/compat.h>
 #include <linux/binfmts.h>
+#include <linux/syscalls.h>
 #include <asm/ucontext.h>
 #include <linux/uaccess.h>
 #include <asm/fpu/internal.h>
@@ -118,7 +119,7 @@
 	return err;
 }
 
-asmlinkage long sys32_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(sigreturn)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
@@ -144,7 +145,7 @@
 	return 0;
 }
 
-asmlinkage long sys32_rt_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe_ia32 __user *frame;
--- linux-ein-5.4.0.orig/arch/x86/include/asm/acenv.h
+++ linux-ein-5.4.0/arch/x86/include/asm/acenv.h
@@ -13,7 +13,19 @@
 
 /* Asm macros */
 
-#define ACPI_FLUSH_CPU_CACHE()	wbinvd()
+/*
+ * ACPI_FLUSH_CPU_CACHE() flushes caches on entering sleep states.
+ * It is required to prevent data loss.
+ *
+ * While running inside virtual machine, the kernel can bypass cache flushing.
+ * Changing sleep state in a virtual machine doesn't affect the host system
+ * sleep state and cannot lead to data loss.
+ */
+#define ACPI_FLUSH_CPU_CACHE()					\
+do {								\
+	if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR))	\
+		wbinvd();					\
+} while (0)
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/apic.h
+++ linux-ein-5.4.0/arch/x86/include/asm/apic.h
@@ -140,6 +140,7 @@
 extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
 extern void init_bsp_APIC(void);
+extern void apic_intr_mode_select(void);
 extern void apic_intr_mode_init(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
@@ -173,6 +174,7 @@
 extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
 extern void lapic_assign_system_vectors(void);
 extern void lapic_assign_legacy_vector(unsigned int isairq, bool replace);
+extern void lapic_update_legacy_vectors(void);
 extern void lapic_online(void);
 extern void lapic_offline(void);
 extern bool apic_needs_pit(void);
@@ -188,6 +190,7 @@
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
 static inline void init_bsp_APIC(void) { }
+static inline void apic_intr_mode_select(void) { }
 static inline void apic_intr_mode_init(void) { }
 static inline void lapic_assign_system_vectors(void) { }
 static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
@@ -195,16 +198,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 ||
@@ -257,6 +250,7 @@
 
 extern int x2apic_mode;
 extern int x2apic_phys;
+extern void __init x2apic_set_max_apicid(u32 apicid);
 extern void __init check_x2apic(void);
 extern void x2apic_setup(void);
 static inline int x2apic_enabled(void)
@@ -452,6 +446,14 @@
 	apic_eoi();
 }
 
+
+static inline bool lapic_vector_set_in_irr(unsigned int vector)
+{
+	u32 irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
+
+	return !!(irr & (1U << (vector % 32)));
+}
+
 static inline unsigned default_get_apic_id(unsigned long x)
 {
 	unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
--- linux-ein-5.4.0.orig/arch/x86/include/asm/apm.h
+++ linux-ein-5.4.0/arch/x86/include/asm/apm.h
@@ -35,6 +35,7 @@
 	__asm__ __volatile__(APM_DO_ZERO_SEGS
 		"pushl %%edi\n\t"
 		"pushl %%ebp\n\t"
+		ANNOTATE_RETPOLINE_SAFE /* FRBS */
 		"lcall *%%cs:apm_bios_entry\n\t"
 		"setc %%al\n\t"
 		"popl %%ebp\n\t"
@@ -59,6 +60,7 @@
 	__asm__ __volatile__(APM_DO_ZERO_SEGS
 		"pushl %%edi\n\t"
 		"pushl %%ebp\n\t"
+		ANNOTATE_RETPOLINE_SAFE /* FRBS */
 		"lcall *%%cs:apm_bios_entry\n\t"
 		"setc %%bl\n\t"
 		"popl %%ebp\n\t"
--- linux-ein-5.4.0.orig/arch/x86/include/asm/archrandom.h
+++ linux-ein-5.4.0/arch/x86/include/asm/archrandom.h
@@ -73,10 +73,6 @@
 	return ok;
 }
 
-/* Conditional execution based on CPU type */
-#define arch_has_random()	static_cpu_has(X86_FEATURE_RDRAND)
-#define arch_has_random_seed()	static_cpu_has(X86_FEATURE_RDSEED)
-
 /*
  * These are the generic interfaces; they must not be declared if the
  * stubs in <linux/random.h> are to be invoked,
@@ -86,22 +82,22 @@
 
 static inline bool arch_get_random_long(unsigned long *v)
 {
-	return arch_has_random() ? rdrand_long(v) : false;
+	return static_cpu_has(X86_FEATURE_RDRAND) ? rdrand_long(v) : false;
 }
 
 static inline bool arch_get_random_int(unsigned int *v)
 {
-	return arch_has_random() ? rdrand_int(v) : false;
+	return static_cpu_has(X86_FEATURE_RDRAND) ? rdrand_int(v) : false;
 }
 
 static inline bool arch_get_random_seed_long(unsigned long *v)
 {
-	return arch_has_random_seed() ? rdseed_long(v) : false;
+	return static_cpu_has(X86_FEATURE_RDSEED) ? rdseed_long(v) : false;
 }
 
 static inline bool arch_get_random_seed_int(unsigned int *v)
 {
-	return arch_has_random_seed() ? rdseed_int(v) : false;
+	return static_cpu_has(X86_FEATURE_RDSEED) ? rdseed_int(v) : false;
 }
 
 extern void x86_init_rdrand(struct cpuinfo_x86 *c);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/asm.h
+++ linux-ein-5.4.0/arch/x86/include/asm/asm.h
@@ -7,9 +7,11 @@
 # define __ASM_FORM_RAW(x)     x
 # define __ASM_FORM_COMMA(x) x,
 #else
-# define __ASM_FORM(x)	" " #x " "
-# define __ASM_FORM_RAW(x)     #x
-# define __ASM_FORM_COMMA(x) " " #x ","
+#include <linux/stringify.h>
+
+# define __ASM_FORM(x)	" " __stringify(x) " "
+# define __ASM_FORM_RAW(x)     __stringify(x)
+# define __ASM_FORM_COMMA(x) " " __stringify(x) ","
 #endif
 
 #ifndef __x86_64__
@@ -139,9 +141,6 @@
 # define _ASM_EXTABLE_EX(from, to)				\
 	_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
 
-# define _ASM_EXTABLE_REFCOUNT(from, to)			\
-	_ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount)
-
 # define _ASM_NOKPROBE(entry)					\
 	.pushsection "_kprobe_blacklist","aw" ;			\
 	_ASM_ALIGN ;						\
@@ -170,9 +169,6 @@
 # define _ASM_EXTABLE_EX(from, to)				\
 	_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
 
-# define _ASM_EXTABLE_REFCOUNT(from, to)			\
-	_ASM_EXTABLE_HANDLE(from, to, ex_handler_refcount)
-
 /* For C file, we already have NOKPROBE_SYMBOL macro */
 #endif
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/barrier.h
+++ linux-ein-5.4.0/arch/x86/include/asm/barrier.h
@@ -84,4 +84,22 @@
 
 #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-ein-5.4.0.orig/arch/x86/include/asm/bugs.h
+++ linux-ein-5.4.0/arch/x86/include/asm/bugs.h
@@ -4,8 +4,6 @@
 
 #include <asm/processor.h>
 
-extern void check_bugs(void);
-
 #if defined(CONFIG_CPU_SUP_INTEL)
 void check_mpx_erratum(struct cpuinfo_x86 *c);
 #else
--- linux-ein-5.4.0.orig/arch/x86/include/asm/cacheinfo.h
+++ linux-ein-5.4.0/arch/x86/include/asm/cacheinfo.h
@@ -2,7 +2,7 @@
 #ifndef _ASM_X86_CACHEINFO_H
 #define _ASM_X86_CACHEINFO_H
 
-void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id);
-void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id);
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu);
+void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c, int cpu);
 
 #endif /* _ASM_X86_CACHEINFO_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/compat.h
+++ linux-ein-5.4.0/arch/x86/include/asm/compat.h
@@ -31,15 +31,13 @@
 typedef u64 __attribute__((aligned(4))) compat_u64;
 
 struct compat_stat {
-	compat_dev_t	st_dev;
-	u16		__pad1;
+	u32		st_dev;
 	compat_ino_t	st_ino;
 	compat_mode_t	st_mode;
 	compat_nlink_t	st_nlink;
 	__compat_uid_t	st_uid;
 	__compat_gid_t	st_gid;
-	compat_dev_t	st_rdev;
-	u16		__pad2;
+	u32		st_rdev;
 	u32		st_size;
 	u32		st_blksize;
 	u32		st_blocks;
--- linux-ein-5.4.0.orig/arch/x86/include/asm/cpu_device_id.h
+++ linux-ein-5.4.0/arch/x86/include/asm/cpu_device_id.h
@@ -5,9 +5,163 @@
 /*
  * 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
+
+#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.
+ *
+ * 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_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				\
+}
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL_FEATURE - 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.
+ *
+ * The steppings arguments of X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE() is
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family, model, feature, data) \
+	X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(vendor, family, model, \
+						X86_STEPPING_ANY, feature, 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.
--- linux-ein-5.4.0.orig/arch/x86/include/asm/cpu_entry_area.h
+++ linux-ein-5.4.0/arch/x86/include/asm/cpu_entry_area.h
@@ -78,8 +78,12 @@
 
 	/*
 	 * The GDT is just below entry_stack and thus serves (on x86_64) as
-	 * a a read-only guard page.
+	 * a read-only guard page. On 32-bit the GDT must be writeable, so
+	 * it needs an extra guard page.
 	 */
+#ifdef CONFIG_X86_32
+	char guard_entry_stack[PAGE_SIZE];
+#endif
 	struct entry_stack_page entry_stack_page;
 
 	/*
@@ -94,7 +98,6 @@
 	 */
 	struct cea_exception_stacks estacks;
 #endif
-#ifdef CONFIG_CPU_SUP_INTEL
 	/*
 	 * Per CPU debug store for Intel performance monitoring. Wastes a
 	 * full page at the moment.
@@ -105,11 +108,9 @@
 	 * Reserve enough fixmap PTEs.
 	 */
 	struct debug_store_buffers cpu_debug_buffers;
-#endif
 };
 
-#define CPU_ENTRY_AREA_SIZE	(sizeof(struct cpu_entry_area))
-#define CPU_ENTRY_AREA_TOT_SIZE	(CPU_ENTRY_AREA_SIZE * NR_CPUS)
+#define CPU_ENTRY_AREA_SIZE		(sizeof(struct cpu_entry_area))
 
 DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
 DECLARE_PER_CPU(struct cea_exception_stacks *, cea_exception_stacks);
@@ -117,17 +118,23 @@
 extern void setup_cpu_entry_areas(void);
 extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags);
 
+/* Single page reserved for the readonly IDT mapping: */
 #define	CPU_ENTRY_AREA_RO_IDT		CPU_ENTRY_AREA_BASE
 #define CPU_ENTRY_AREA_PER_CPU		(CPU_ENTRY_AREA_RO_IDT + PAGE_SIZE)
 
 #define CPU_ENTRY_AREA_RO_IDT_VADDR	((void *)CPU_ENTRY_AREA_RO_IDT)
 
-#define CPU_ENTRY_AREA_MAP_SIZE			\
-	(CPU_ENTRY_AREA_PER_CPU + CPU_ENTRY_AREA_TOT_SIZE - CPU_ENTRY_AREA_BASE)
+#ifdef CONFIG_X86_32
+#define CPU_ENTRY_AREA_MAP_SIZE		(CPU_ENTRY_AREA_PER_CPU +		\
+					 (CPU_ENTRY_AREA_SIZE * NR_CPUS) -	\
+					 CPU_ENTRY_AREA_BASE)
+#else
+#define CPU_ENTRY_AREA_MAP_SIZE		P4D_SIZE
+#endif
 
 extern struct cpu_entry_area *get_cpu_entry_area(int cpu);
 
-static inline struct entry_stack *cpu_entry_stack(int cpu)
+static __always_inline struct entry_stack *cpu_entry_stack(int cpu)
 {
 	return &get_cpu_entry_area(cpu)->entry_stack_page.stack;
 }
--- linux-ein-5.4.0.orig/arch/x86/include/asm/cpufeature.h
+++ linux-ein-5.4.0/arch/x86/include/asm/cpufeature.h
@@ -30,6 +30,10 @@
 	CPUID_7_ECX,
 	CPUID_8000_0007_EBX,
 	CPUID_7_EDX,
+	CPUID_8000_001F_EAX,
+	CPUID_8000_0021_EAX,
+	CPUID_LNX_5,
+	NR_CPUID_WORDS,
 };
 
 #ifdef CONFIG_X86_FEATURE_NAMES
@@ -49,7 +53,7 @@
 extern const char * const x86_bug_flags[NBUGINTS*32];
 
 #define test_cpu_cap(c, bit)						\
-	 test_bit(bit, (unsigned long *)((c)->x86_capability))
+	 arch_test_bit(bit, (unsigned long *)((c)->x86_capability))
 
 /*
  * There are 32 bits/features in each mask word.  The high bits
@@ -88,8 +92,11 @@
 	   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) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 20, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 21, feature_bit) ||	\
 	   REQUIRED_MASK_CHECK					  ||	\
-	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 22))
 
 #define DISABLED_MASK_BIT_SET(feature_bit)				\
 	 ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  0, feature_bit) ||	\
@@ -111,8 +118,11 @@
 	   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) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 20, feature_bit) ||	\
+	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 21, feature_bit) ||	\
 	   DISABLED_MASK_CHECK					  ||	\
-	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
+	   BUILD_BUG_ON_ZERO(NCAPINTS != 22))
 
 #define cpu_has(c, bit)							\
 	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :	\
--- linux-ein-5.4.0.orig/arch/x86/include/asm/cpufeatures.h
+++ linux-ein-5.4.0/arch/x86/include/asm/cpufeatures.h
@@ -13,8 +13,8 @@
 /*
  * Defines x86 CPU feature bits
  */
-#define NCAPINTS			19	   /* N 32-bit words worth of info */
-#define NBUGINTS			1	   /* N 32-bit bug flags */
+#define NCAPINTS			22	   /* 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
@@ -96,6 +96,7 @@
 #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 */
+/* FREE!                                ( 3*32+17) */
 #define X86_FEATURE_LFENCE_RDTSC	( 3*32+18) /* "" LFENCE synchronizes RDTSC */
 #define X86_FEATURE_ACC_POWER		( 3*32+19) /* AMD Accumulated Power Mechanism */
 #define X86_FEATURE_NOPL		( 3*32+20) /* The NOPL (0F 1F) instructions */
@@ -107,6 +108,7 @@
 #define X86_FEATURE_EXTD_APICID		( 3*32+26) /* Extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM		( 3*32+27) /* AMD multi-node processor */
 #define X86_FEATURE_APERFMPERF		( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */
+/* free					( 3*32+29) */
 #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 */
 
@@ -199,17 +201,17 @@
 #define X86_FEATURE_INVPCID_SINGLE	( 7*32+ 7) /* 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_SME			( 7*32+10) /* AMD Secure Memory Encryption */
+/* FREE!                                ( 7*32+10) */
 #define X86_FEATURE_PTI			( 7*32+11) /* Kernel Page Table Isolation enabled */
-#define X86_FEATURE_RETPOLINE		( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_AMD	( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
+#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_PPIN		( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2		( 7*32+15) /* Code and Data Prioritization L2 */
 #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_MBA			( 7*32+18) /* Memory Bandwidth Allocation */
 #define X86_FEATURE_RSB_CTXSW		( 7*32+19) /* "" Fill RSB on context switches */
-#define X86_FEATURE_SEV			( 7*32+20) /* AMD Secure Encrypted Virtualization */
+/* FREE!                                ( 7*32+20) */
 #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. */
@@ -284,6 +286,11 @@
 #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 */
+#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 */
+#define X86_FEATURE_MSR_TSX_CTRL	(11*32+18) /* "" MSR IA32_TSX_CTRL (Intel) implemented */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX512_BF16		(12*32+ 5) /* AVX512 BFLOAT16 instructions */
@@ -300,6 +307,7 @@
 #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 */
@@ -357,6 +365,7 @@
 #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_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */
+#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_TSX_FORCE_ABORT	(18*32+13) /* "" TSX_FORCE_ABORT */
 #define X86_FEATURE_PCONFIG		(18*32+18) /* Intel PCONFIG */
@@ -366,6 +375,24 @@
 #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 */
 
+/* AMD-defined memory encryption features, CPUID level 0x8000001f (EAX), word 19 */
+#define X86_FEATURE_SME			(19*32+ 0) /* AMD Secure Memory Encryption */
+#define X86_FEATURE_SEV			(19*32+ 1) /* AMD Secure Encrypted Virtualization */
+#define X86_FEATURE_VM_PAGE_FLUSH	(19*32+ 2) /* "" VM Page Flush MSR is supported */
+#define X86_FEATURE_SEV_ES		(19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
+#define X86_FEATURE_SME_COHERENT	(19*32+10) /* "" AMD hardware-enforced cache coherency */
+
+/*
+ * 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	(21*32+ 1) /* "" Clear branch history at syscall entry using SW loop */
+#define X86_FEATURE_BHI_CTRL		(21*32+ 2) /* "" BHI_DIS_S HW control available */
+#define X86_FEATURE_CLEAR_BHB_HW	(21*32+ 3) /* "" BHI_DIS_S HW control enabled */
+#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */
+
 /*
  * BUG word(s)
  */
@@ -401,5 +428,15 @@
 #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(26) /* CPU is affected by RETBleed */
+#define X86_BUG_EIBRS_PBRSB		X86_BUG(27) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
+#define X86_BUG_MMIO_UNKNOWN		X86_BUG(28) /* CPU is too old and its MMIO Stale Data status is unknown */
+#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 */
 #endif /* _ASM_X86_CPUFEATURES_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crash.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crash.h
@@ -2,10 +2,18 @@
 #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,
 		struct boot_params *params);
 void crash_smp_send_stop(void);
 
+#ifdef CONFIG_KEXEC_CORE
+void __init crash_reserve_low_1M(void);
+#else
+static inline void __init crash_reserve_low_1M(void) { }
+#endif
+
 #endif /* _ASM_X86_CRASH_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crypto/camellia.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crypto/camellia.h
@@ -32,65 +32,60 @@
 			       unsigned int keylen);
 
 /* regular block cipher functions */
-asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst,
-				   const u8 *src, bool xor);
-asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst,
-				 const u8 *src);
+asmlinkage void __camellia_enc_blk(const void *ctx, u8 *dst, const u8 *src,
+				   bool xor);
+asmlinkage void camellia_dec_blk(const void *ctx, u8 *dst, const u8 *src);
 
 /* 2-way parallel cipher functions */
-asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst,
-					const u8 *src, bool xor);
-asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst,
-				      const u8 *src);
+asmlinkage void __camellia_enc_blk_2way(const void *ctx, u8 *dst, const u8 *src,
+					bool xor);
+asmlinkage void camellia_dec_blk_2way(const void *ctx, u8 *dst, const u8 *src);
 
 /* 16-way parallel cipher functions (avx/aes-ni) */
-asmlinkage void camellia_ecb_enc_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-asmlinkage void camellia_ecb_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-
-asmlinkage void camellia_cbc_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src);
-asmlinkage void camellia_ctr_16way(struct camellia_ctx *ctx, u8 *dst,
-				   const u8 *src, le128 *iv);
-
-asmlinkage void camellia_xts_enc_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
-asmlinkage void camellia_xts_dec_16way(struct camellia_ctx *ctx, u8 *dst,
-				       const u8 *src, le128 *iv);
+asmlinkage void camellia_ecb_enc_16way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void camellia_ecb_dec_16way(const void *ctx, u8 *dst, const u8 *src);
 
-static inline void camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst,
-				    const u8 *src)
+asmlinkage void camellia_cbc_dec_16way(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void camellia_ctr_16way(const void *ctx, u8 *dst, const u8 *src,
+				   le128 *iv);
+
+asmlinkage void camellia_xts_enc_16way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
+asmlinkage void camellia_xts_dec_16way(const void *ctx, u8 *dst, const u8 *src,
+				       le128 *iv);
+
+static inline void camellia_enc_blk(const void *ctx, u8 *dst, const u8 *src)
 {
 	__camellia_enc_blk(ctx, dst, src, false);
 }
 
-static inline void camellia_enc_blk_xor(struct camellia_ctx *ctx, u8 *dst,
-					const u8 *src)
+static inline void camellia_enc_blk_xor(const void *ctx, u8 *dst, const u8 *src)
 {
 	__camellia_enc_blk(ctx, dst, src, true);
 }
 
-static inline void camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst,
+static inline void camellia_enc_blk_2way(const void *ctx, u8 *dst,
 					 const u8 *src)
 {
 	__camellia_enc_blk_2way(ctx, dst, src, false);
 }
 
-static inline void camellia_enc_blk_xor_2way(struct camellia_ctx *ctx, u8 *dst,
+static inline void camellia_enc_blk_xor_2way(const void *ctx, u8 *dst,
 					     const u8 *src)
 {
 	__camellia_enc_blk_2way(ctx, dst, src, true);
 }
 
 /* glue helpers */
-extern void camellia_decrypt_cbc_2way(void *ctx, u128 *dst, const u128 *src);
-extern void camellia_crypt_ctr(void *ctx, u128 *dst, const u128 *src,
+extern void camellia_decrypt_cbc_2way(const void *ctx, u8 *dst, const u8 *src);
+extern void camellia_crypt_ctr(const void *ctx, u8 *dst, const u8 *src,
 			       le128 *iv);
-extern void camellia_crypt_ctr_2way(void *ctx, u128 *dst, const u128 *src,
+extern void camellia_crypt_ctr_2way(const void *ctx, u8 *dst, const u8 *src,
 				    le128 *iv);
 
-extern void camellia_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv);
-extern void camellia_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv);
+extern void camellia_xts_enc(const void *ctx, u8 *dst, const u8 *src,
+			     le128 *iv);
+extern void camellia_xts_dec(const void *ctx, u8 *dst, const u8 *src,
+			     le128 *iv);
 
 #endif /* ASM_X86_CAMELLIA_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crypto/glue_helper.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crypto/glue_helper.h
@@ -11,18 +11,13 @@
 #include <asm/fpu/api.h>
 #include <crypto/b128ops.h>
 
-typedef void (*common_glue_func_t)(void *ctx, u8 *dst, const u8 *src);
-typedef void (*common_glue_cbc_func_t)(void *ctx, u128 *dst, const u128 *src);
-typedef void (*common_glue_ctr_func_t)(void *ctx, u128 *dst, const u128 *src,
+typedef void (*common_glue_func_t)(const void *ctx, u8 *dst, const u8 *src);
+typedef void (*common_glue_cbc_func_t)(const void *ctx, u8 *dst, const u8 *src);
+typedef void (*common_glue_ctr_func_t)(const void *ctx, u8 *dst, const u8 *src,
 				       le128 *iv);
-typedef void (*common_glue_xts_func_t)(void *ctx, u128 *dst, const u128 *src,
+typedef void (*common_glue_xts_func_t)(const void *ctx, u8 *dst, const u8 *src,
 				       le128 *iv);
 
-#define GLUE_FUNC_CAST(fn) ((common_glue_func_t)(fn))
-#define GLUE_CBC_FUNC_CAST(fn) ((common_glue_cbc_func_t)(fn))
-#define GLUE_CTR_FUNC_CAST(fn) ((common_glue_ctr_func_t)(fn))
-#define GLUE_XTS_FUNC_CAST(fn) ((common_glue_xts_func_t)(fn))
-
 struct common_glue_func_entry {
 	unsigned int num_blocks; /* number of blocks that @fn will process */
 	union {
@@ -116,7 +111,8 @@
 			       common_glue_func_t tweak_fn, void *tweak_ctx,
 			       void *crypt_ctx, bool decrypt);
 
-extern void glue_xts_crypt_128bit_one(void *ctx, u128 *dst, const u128 *src,
-				      le128 *iv, common_glue_func_t fn);
+extern void glue_xts_crypt_128bit_one(const void *ctx, u8 *dst,
+				      const u8 *src, le128 *iv,
+				      common_glue_func_t fn);
 
 #endif /* _CRYPTO_GLUE_HELPER_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crypto/serpent-avx.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crypto/serpent-avx.h
@@ -15,26 +15,26 @@
 	struct serpent_ctx crypt_ctx;
 };
 
-asmlinkage void serpent_ecb_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_ecb_enc_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
-asmlinkage void serpent_ecb_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_ecb_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
 
-asmlinkage void serpent_cbc_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_cbc_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src);
-asmlinkage void serpent_ctr_8way_avx(struct serpent_ctx *ctx, u8 *dst,
-				     const u8 *src, le128 *iv);
+asmlinkage void serpent_ctr_8way_avx(const void *ctx, u8 *dst, const u8 *src,
+				     le128 *iv);
 
-asmlinkage void serpent_xts_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_xts_enc_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src, le128 *iv);
-asmlinkage void serpent_xts_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_xts_dec_8way_avx(const void *ctx, u8 *dst,
 					 const u8 *src, le128 *iv);
 
-extern void __serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src,
+extern void __serpent_crypt_ctr(const void *ctx, u8 *dst, const u8 *src,
 				le128 *iv);
 
-extern void serpent_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv);
-extern void serpent_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv);
+extern void serpent_xts_enc(const void *ctx, u8 *dst, const u8 *src, le128 *iv);
+extern void serpent_xts_dec(const void *ctx, u8 *dst, const u8 *src, le128 *iv);
 
 extern int xts_serpent_setkey(struct crypto_skcipher *tfm, const u8 *key,
 			      unsigned int keylen);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crypto/serpent-sse2.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crypto/serpent-sse2.h
@@ -9,25 +9,23 @@
 
 #define SERPENT_PARALLEL_BLOCKS 4
 
-asmlinkage void __serpent_enc_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void __serpent_enc_blk_4way(const struct serpent_ctx *ctx, u8 *dst,
 				       const u8 *src, bool xor);
-asmlinkage void serpent_dec_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_dec_blk_4way(const struct serpent_ctx *ctx, u8 *dst,
 				     const u8 *src);
 
-static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-					const u8 *src)
+static inline void serpent_enc_blk_xway(const void *ctx, u8 *dst, const u8 *src)
 {
 	__serpent_enc_blk_4way(ctx, dst, src, false);
 }
 
-static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
-					    const u8 *src)
+static inline void serpent_enc_blk_xway_xor(const struct serpent_ctx *ctx,
+					    u8 *dst, const u8 *src)
 {
 	__serpent_enc_blk_4way(ctx, dst, src, true);
 }
 
-static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-					const u8 *src)
+static inline void serpent_dec_blk_xway(const void *ctx, u8 *dst, const u8 *src)
 {
 	serpent_dec_blk_4way(ctx, dst, src);
 }
@@ -36,25 +34,23 @@
 
 #define SERPENT_PARALLEL_BLOCKS 8
 
-asmlinkage void __serpent_enc_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void __serpent_enc_blk_8way(const struct serpent_ctx *ctx, u8 *dst,
 				       const u8 *src, bool xor);
-asmlinkage void serpent_dec_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+asmlinkage void serpent_dec_blk_8way(const struct serpent_ctx *ctx, u8 *dst,
 				     const u8 *src);
 
-static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-				   const u8 *src)
+static inline void serpent_enc_blk_xway(const void *ctx, u8 *dst, const u8 *src)
 {
 	__serpent_enc_blk_8way(ctx, dst, src, false);
 }
 
-static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
-				       const u8 *src)
+static inline void serpent_enc_blk_xway_xor(const struct serpent_ctx *ctx,
+					    u8 *dst, const u8 *src)
 {
 	__serpent_enc_blk_8way(ctx, dst, src, true);
 }
 
-static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
-				   const u8 *src)
+static inline void serpent_dec_blk_xway(const void *ctx, u8 *dst, const u8 *src)
 {
 	serpent_dec_blk_8way(ctx, dst, src);
 }
--- linux-ein-5.4.0.orig/arch/x86/include/asm/crypto/twofish.h
+++ linux-ein-5.4.0/arch/x86/include/asm/crypto/twofish.h
@@ -7,22 +7,19 @@
 #include <crypto/b128ops.h>
 
 /* regular block cipher functions from twofish_x86_64 module */
-asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst,
-				const u8 *src);
-asmlinkage void twofish_dec_blk(struct twofish_ctx *ctx, u8 *dst,
-				const u8 *src);
+asmlinkage void twofish_enc_blk(const void *ctx, u8 *dst, const u8 *src);
+asmlinkage void twofish_dec_blk(const void *ctx, u8 *dst, const u8 *src);
 
 /* 3-way parallel cipher functions */
-asmlinkage void __twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
-				       const u8 *src, bool xor);
-asmlinkage void twofish_dec_blk_3way(struct twofish_ctx *ctx, u8 *dst,
-				     const u8 *src);
+asmlinkage void __twofish_enc_blk_3way(const void *ctx, u8 *dst, const u8 *src,
+				       bool xor);
+asmlinkage void twofish_dec_blk_3way(const void *ctx, u8 *dst, const u8 *src);
 
 /* helpers from twofish_x86_64-3way module */
-extern void twofish_dec_blk_cbc_3way(void *ctx, u128 *dst, const u128 *src);
-extern void twofish_enc_blk_ctr(void *ctx, u128 *dst, const u128 *src,
+extern void twofish_dec_blk_cbc_3way(const void *ctx, u8 *dst, const u8 *src);
+extern void twofish_enc_blk_ctr(const void *ctx, u8 *dst, const u8 *src,
 				le128 *iv);
-extern void twofish_enc_blk_ctr_3way(void *ctx, u128 *dst, const u128 *src,
+extern void twofish_enc_blk_ctr_3way(const void *ctx, u8 *dst, const u8 *src,
 				     le128 *iv);
 
 #endif /* ASM_X86_TWOFISH_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/disabled-features.h
+++ linux-ein-5.4.0/arch/x86/include/asm/disabled-features.h
@@ -84,6 +84,9 @@
 #define DISABLED_MASK16	(DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP)
 #define DISABLED_MASK17	0
 #define DISABLED_MASK18	0
-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
+#define DISABLED_MASK19	0
+#define DISABLED_MASK20	0
+#define DISABLED_MASK21	0
+#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22)
 
 #endif /* _ASM_X86_DISABLED_FEATURES_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/dma.h
+++ linux-ein-5.4.0/arch/x86/include/asm/dma.h
@@ -74,7 +74,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-ein-5.4.0.orig/arch/x86/include/asm/emulate_prefix.h
+++ linux-ein-5.4.0/arch/x86/include/asm/emulate_prefix.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_EMULATE_PREFIX_H
+#define _ASM_X86_EMULATE_PREFIX_H
+
+/*
+ * Virt escape sequences to trigger instruction emulation;
+ * ideally these would decode to 'whole' instruction and not destroy
+ * the instruction stream; sadly this is not true for the 'kvm' one :/
+ */
+
+#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
+#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */
+
+#endif
--- linux-ein-5.4.0.orig/arch/x86/include/asm/fixmap.h
+++ linux-ein-5.4.0/arch/x86/include/asm/fixmap.h
@@ -156,7 +156,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_XXL
--- linux-ein-5.4.0.orig/arch/x86/include/asm/fpu/api.h
+++ linux-ein-5.4.0/arch/x86/include/asm/fpu/api.h
@@ -16,14 +16,25 @@
  * Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It
  * disables preemption so be careful if you intend to use it for long periods
  * of time.
- * If you intend to use the FPU in softirq you need to check first with
+ * If you intend to use the FPU in irq/softirq you need to check first with
  * irq_fpu_usable() if it is possible.
  */
-extern void kernel_fpu_begin(void);
+
+/* Kernel FPU states to initialize in kernel_fpu_begin_mask() */
+#define KFPU_387	_BITUL(0)	/* 387 state will be initialized */
+#define KFPU_MXCSR	_BITUL(1)	/* MXCSR will be initialized */
+
+extern void kernel_fpu_begin_mask(unsigned int kfpu_mask);
 extern void kernel_fpu_end(void);
 extern bool irq_fpu_usable(void);
 extern void fpregs_mark_activate(void);
 
+/* Code that is unaware of kernel_fpu_begin_mask() can use this */
+static inline void kernel_fpu_begin(void)
+{
+	kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
+}
+
 /*
  * Use fpregs_lock() while editing CPU's FPU registers or fpu->state.
  * A context switch will (and softirq might) save CPU's FPU registers to
--- linux-ein-5.4.0.orig/arch/x86/include/asm/fpu/internal.h
+++ linux-ein-5.4.0/arch/x86/include/asm/fpu/internal.h
@@ -41,7 +41,7 @@
 extern void fpu__init_cpu(void);
 extern void fpu__init_system_xstate(void);
 extern void fpu__init_cpu_xstate(void);
-extern void fpu__init_system(struct cpuinfo_x86 *c);
+extern void fpu__init_system(void);
 extern void fpu__init_check_bugs(void);
 extern void fpu__resume_cpu(void);
 extern u64 fpu__get_supported_xfeatures_mask(void);
@@ -102,6 +102,7 @@
 }
 extern void fpstate_sanitize_xstate(struct fpu *fpu);
 
+/* Returns 0 or the negated trap number, which results in -EFAULT for #PF */
 #define user_insn(insn, output, input...)				\
 ({									\
 	int err;							\
@@ -109,14 +110,14 @@
 	might_fault();							\
 									\
 	asm volatile(ASM_STAC "\n"					\
-		     "1:" #insn "\n\t"					\
+		     "1: " #insn "\n"					\
 		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
-		     "3:  movl $-1,%[err]\n"				\
+		     "3:  negl %%eax\n"					\
 		     "    jmp  2b\n"					\
 		     ".previous\n"					\
-		     _ASM_EXTABLE(1b, 3b)				\
-		     : [err] "=r" (err), output				\
+		     _ASM_EXTABLE_FAULT(1b, 3b)				\
+		     : [err] "=a" (err), output				\
 		     : "0"(0), input);					\
 	err;								\
 })
@@ -203,6 +204,14 @@
 		asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
 }
 
+static inline void fxsave(struct fxregs_state *fx)
+{
+	if (IS_ENABLED(CONFIG_X86_32))
+		asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
+	else
+		asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
+}
+
 /* These macros all use (%edi)/(%rdi) as the single memory argument. */
 #define XSAVE		".byte " REX_PREFIX "0x0f,0xae,0x27"
 #define XSAVEOPT	".byte " REX_PREFIX "0x0f,0xae,0x37"
@@ -210,16 +219,20 @@
 #define XRSTOR		".byte " REX_PREFIX "0x0f,0xae,0x2f"
 #define XRSTORS		".byte " REX_PREFIX "0x0f,0xc7,0x1f"
 
+/*
+ * After this @err contains 0 on success or the negated trap number when
+ * the operation raises an exception. For faults this results in -EFAULT.
+ */
 #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"				\
+		     "3: negl %%eax\n\t"				\
 		     "jmp 2b\n\t"					\
 		     ".popsection\n\t"					\
-		     _ASM_EXTABLE(1b, 3b)				\
-		     : [err] "=r" (err)					\
+		     _ASM_EXTABLE_FAULT(1b, 3b)				\
+		     : [err] "=a" (err)					\
 		     : "D" (st), "m" (*st), "a" (lmask), "d" (hmask)	\
 		     : "memory")
 
@@ -271,28 +284,6 @@
  * This function is called only during boot time when x86 caps are not set
  * up and alternative can not be used yet.
  */
-static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
-{
-	u64 mask = -1;
-	u32 lmask = mask;
-	u32 hmask = mask >> 32;
-	int err;
-
-	WARN_ON(system_state != SYSTEM_BOOTING);
-
-	if (boot_cpu_has(X86_FEATURE_XSAVES))
-		XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
-	else
-		XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
-
-	/* We should never fault when copying to a kernel buffer: */
-	WARN_ON_FPU(err);
-}
-
-/*
- * This function is called only during boot time when x86 caps are not set
- * up and alternative can not be used yet.
- */
 static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
 {
 	u64 mask = -1;
@@ -509,7 +500,7 @@
 
 static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
 {
-	return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
+	return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
 }
 
 /*
@@ -569,9 +560,11 @@
  * The FPU context is only stored/restored for a user task and
  * PF_KTHREAD is used to distinguish between kernel and user threads.
  */
-static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
+static inline void switch_fpu_prepare(struct task_struct *prev, int cpu)
 {
-	if (static_cpu_has(X86_FEATURE_FPU) && !(current->flags & PF_KTHREAD)) {
+	struct fpu *old_fpu = &prev->thread.fpu;
+
+	if (static_cpu_has(X86_FEATURE_FPU) && !(prev->flags & PF_KTHREAD)) {
 		if (!copy_fpregs_to_fpstate(old_fpu))
 			old_fpu->last_cpu = -1;
 		else
@@ -590,10 +583,11 @@
  * Load PKRU from the FPU context if available. Delay loading of the
  * complete FPU state until the return to userland.
  */
-static inline void switch_fpu_finish(struct fpu *new_fpu)
+static inline void switch_fpu_finish(struct task_struct *next)
 {
 	u32 pkru_val = init_pkru_value;
 	struct pkru_state *pk;
+	struct fpu *next_fpu = &next->thread.fpu;
 
 	if (!static_cpu_has(X86_FEATURE_FPU))
 		return;
@@ -607,10 +601,17 @@
 	 * PKRU state is switched eagerly because it needs to be valid before we
 	 * return to userland e.g. for a copy_to_user() operation.
 	 */
-	if (current->mm) {
-		pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU);
-		if (pk)
-			pkru_val = pk->pkru;
+	if (!(next->flags & PF_KTHREAD)) {
+		/*
+		 * If the PKRU bit in xsave.header.xfeatures is not set,
+		 * then the PKRU component was in init state, which means
+		 * XRSTOR will set PKRU to 0. If the bit is not set then
+		 * get_xsave_addr() will return NULL because the PKRU value
+		 * in memory is not valid. This means pkru_val has to be
+		 * set to 0 and not to init_pkru_value.
+		 */
+		pk = get_xsave_addr(&next_fpu->state.xsave, XFEATURE_PKRU);
+		pkru_val = pk ? pk->pkru : 0;
 	}
 	__write_pkru(pkru_val);
 }
@@ -619,6 +620,11 @@
  * MXCSR and XCR definitions:
  */
 
+static inline void ldmxcsr(u32 mxcsr)
+{
+	asm volatile("ldmxcsr %0" :: "m" (mxcsr));
+}
+
 extern unsigned int mxcsr_feature_mask;
 
 #define XCR_XFEATURE_ENABLED_MASK	0x00000000
--- linux-ein-5.4.0.orig/arch/x86/include/asm/hyperv-tlfs.h
+++ linux-ein-5.4.0/arch/x86/include/asm/hyperv-tlfs.h
@@ -721,7 +721,7 @@
 	u64 guest_rip;
 
 	u32 hv_clean_fields;
-	u32 hv_padding_32;
+	u32 padding32_1;
 	u32 hv_synthetic_controls;
 	struct {
 		u32 nested_flush_hypercall:1;
@@ -729,7 +729,7 @@
 		u32 reserved:30;
 	}  __packed hv_enlightenments_control;
 	u32 hv_vp_id;
-
+	u32 padding32_2;
 	u64 hv_vm_id;
 	u64 partition_assist_page;
 	u64 padding64_4[4];
--- linux-ein-5.4.0.orig/arch/x86/include/asm/i8259.h
+++ linux-ein-5.4.0/arch/x86/include/asm/i8259.h
@@ -67,6 +67,8 @@
 	void (*make_irq)(unsigned int irq);
 };
 
+void legacy_pic_pcat_compat(void);
+
 extern struct legacy_pic *legacy_pic;
 extern struct legacy_pic null_legacy_pic;
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/insn.h
+++ linux-ein-5.4.0/arch/x86/include/asm/insn.h
@@ -45,6 +45,7 @@
 		struct insn_field immediate2;	/* for 64bit imm or seg16 */
 	};
 
+	int	emulate_prefix_size;
 	insn_attr_t attr;
 	unsigned char opnd_bytes;
 	unsigned char addr_bytes;
@@ -128,6 +129,11 @@
 	return (insn->vex_prefix.nbytes == 4);
 }
 
+static inline int insn_has_emulate_prefix(struct insn *insn)
+{
+	return !!insn->emulate_prefix_size;
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
@@ -195,6 +201,21 @@
 	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
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/intel-family.h
+++ linux-ein-5.4.0/arch/x86/include/asm/intel-family.h
@@ -35,6 +35,9 @@
  * The #define line may optionally include a comment including platform names.
  */
 
+/* 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
@@ -86,6 +89,19 @@
 #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_ALDERLAKE_N		0xBE
+
+#define INTEL_FAM6_RAPTORLAKE		0xB7
+#define INTEL_FAM6_RAPTORLAKE_P		0xBA
+#define INTEL_FAM6_RAPTORLAKE_S		0xBF
+
 /* "Small Core" Processors (Atom) */
 
 #define INTEL_FAM6_ATOM_BONNELL		0x1C /* Diamondville, Pineview */
@@ -111,12 +127,16 @@
 
 #define INTEL_FAM6_ATOM_TREMONT_D	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 */
+
 /* Useful macros */
 #define INTEL_CPU_FAM_ANY(_family, _model, _driver_data)	\
 {								\
--- linux-ein-5.4.0.orig/arch/x86/include/asm/kasan.h
+++ linux-ein-5.4.0/arch/x86/include/asm/kasan.h
@@ -28,9 +28,12 @@
 #ifdef CONFIG_KASAN
 void __init kasan_early_init(void);
 void __init kasan_init(void);
+void __init kasan_populate_shadow_for_vaddr(void *va, size_t size, int nid);
 #else
 static inline void kasan_early_init(void) { }
 static inline void kasan_init(void) { }
+static inline void kasan_populate_shadow_for_vaddr(void *va, size_t size,
+						   int nid) { }
 #endif
 
 #endif
--- linux-ein-5.4.0.orig/arch/x86/include/asm/kexec.h
+++ linux-ein-5.4.0/arch/x86/include/asm/kexec.h
@@ -22,6 +22,7 @@
 
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/page.h>
 #include <asm/ptrace.h>
@@ -201,6 +202,14 @@
 extern void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages);
 #define arch_kexec_pre_free_pages arch_kexec_pre_free_pages
 
+#ifdef CONFIG_KEXEC_FILE
+struct purgatory_info;
+int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
+				     Elf_Shdr *section,
+				     const Elf_Shdr *relsec,
+				     const Elf_Shdr *symtab);
+#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add
+#endif
 #endif
 
 typedef void crash_vmclear_fn(void);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/kvm_host.h
+++ linux-ein-5.4.0/arch/x86/include/asm/kvm_host.h
@@ -380,19 +380,17 @@
 	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
 	unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
 	u64 (*get_pdptr)(struct kvm_vcpu *vcpu, int index);
-	int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err,
+	int (*page_fault)(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u32 err,
 			  bool prefault);
 	void (*inject_page_fault)(struct kvm_vcpu *vcpu,
 				  struct x86_exception *fault);
-	gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access,
-			    struct x86_exception *exception);
+	gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gpa_t gva_or_gpa,
+			    u32 access, struct x86_exception *exception);
 	gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
 			       struct x86_exception *exception);
 	int (*sync_page)(struct kvm_vcpu *vcpu,
 			 struct kvm_mmu_page *sp);
 	void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva, hpa_t root_hpa);
-	void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
-			   u64 *spte, const void *pte);
 	hpa_t root_hpa;
 	gpa_t root_cr3;
 	union kvm_mmu_role mmu_role;
@@ -550,6 +548,7 @@
 	unsigned long cr4;
 	unsigned long cr4_guest_owned_bits;
 	unsigned long cr8;
+	u32 host_pkru;
 	u32 pkru;
 	u32 hflags;
 	u64 efer;
@@ -564,6 +563,7 @@
 	u64 ia32_misc_enable_msr;
 	u64 smbase;
 	u64 smi_count;
+	bool at_instruction_boundary;
 	bool tpr_access_reporting;
 	u64 ia32_xss;
 	u64 microcode_version;
@@ -667,10 +667,10 @@
 	bool pvclock_set_guest_stopped_request;
 
 	struct {
+		u8 preempted;
 		u64 msr_val;
 		u64 last_steal;
-		struct gfn_to_hva_cache stime;
-		struct kvm_steal_time steal;
+		struct gfn_to_pfn_cache cache;
 	} st;
 
 	u64 tsc_offset;
@@ -943,7 +943,6 @@
 struct kvm_vm_stat {
 	ulong mmu_shadow_zapped;
 	ulong mmu_pte_write;
-	ulong mmu_pte_updated;
 	ulong mmu_pde_zapped;
 	ulong mmu_flooded;
 	ulong mmu_recycled;
@@ -983,6 +982,8 @@
 	u64 irq_injections;
 	u64 nmi_injections;
 	u64 req_event;
+	u64 preemption_reported;
+	u64 preemption_other;
 };
 
 struct x86_instruction_info;
@@ -1098,7 +1099,7 @@
 	void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
 	void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
 	void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
-	void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+	int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
 	int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
 	int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
 	int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);
@@ -1128,8 +1129,9 @@
 	bool (*xsaves_supported)(void);
 	bool (*umip_emulated)(void);
 	bool (*pt_supported)(void);
+	bool (*pku_supported)(void);
 
-	int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
+	int (*check_nested_events)(struct kvm_vcpu *vcpu);
 	void (*request_immediate_exit)(struct kvm_vcpu *vcpu);
 
 	void (*sched_in)(struct kvm_vcpu *kvm, int cpu);
@@ -1158,7 +1160,7 @@
 	void (*enable_log_dirty_pt_masked)(struct kvm *kvm,
 					   struct kvm_memory_slot *slot,
 					   gfn_t offset, unsigned long mask);
-	int (*write_log_dirty)(struct kvm_vcpu *vcpu);
+	int (*write_log_dirty)(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
 
 	/* pmu operations of sub-arch */
 	const struct kvm_pmu_ops *pmu_ops;
@@ -1450,7 +1452,7 @@
 
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
 
-int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u64 error_code,
+int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 error_code,
 		       void *insn, int insn_len);
 void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
 void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid);
@@ -1551,12 +1553,14 @@
 	_ASM_EXTABLE(666b, 667b)
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end);
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+			unsigned flags);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
 int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
+int kvm_cpu_has_extint(struct kvm_vcpu *v);
 int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
@@ -1607,8 +1611,8 @@
 static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq)
 {
 	/* We can only post Fixed and LowPrio IRQs */
-	return (irq->delivery_mode == dest_Fixed ||
-		irq->delivery_mode == dest_LowestPrio);
+	return (irq->delivery_mode == APIC_DM_FIXED ||
+		irq->delivery_mode == APIC_DM_LOWEST);
 }
 
 static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
--- linux-ein-5.4.0.orig/arch/x86/include/asm/kvm_para.h
+++ linux-ein-5.4.0/arch/x86/include/asm/kvm_para.h
@@ -6,8 +6,6 @@
 #include <asm/alternative.h>
 #include <uapi/asm/kvm_para.h>
 
-extern void kvmclock_init(void);
-
 #ifdef CONFIG_KVM_GUEST
 bool kvm_check_and_clear_guest_paused(void);
 #else
@@ -85,13 +83,14 @@
 }
 
 #ifdef CONFIG_KVM_GUEST
+void kvmclock_init(void);
+void kvmclock_disable(void);
 bool kvm_para_available(void);
 unsigned int kvm_arch_para_features(void);
 unsigned int kvm_arch_para_hints(void);
 void kvm_async_pf_task_wait(u32 token, int interrupt_kernel);
 void kvm_async_pf_task_wake(u32 token);
 u32 kvm_read_and_reset_pf_reason(void);
-extern void kvm_disable_steal_time(void);
 void do_async_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
@@ -126,10 +125,6 @@
 	return 0;
 }
 
-static inline void kvm_disable_steal_time(void)
-{
-	return;
-}
 #endif
 
 #endif /* _ASM_X86_KVM_PARA_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/kvmclock.h
+++ linux-ein-5.4.0/arch/x86/include/asm/kvmclock.h
@@ -2,6 +2,20 @@
 #ifndef _ASM_X86_KVM_CLOCK_H
 #define _ASM_X86_KVM_CLOCK_H
 
+#include <linux/percpu.h>
+
 extern struct clocksource kvm_clock;
 
+DECLARE_PER_CPU(struct pvclock_vsyscall_time_info *, hv_clock_per_cpu);
+
+static inline struct pvclock_vcpu_time_info *this_cpu_pvti(void)
+{
+	return &this_cpu_read(hv_clock_per_cpu)->pvti;
+}
+
+static inline struct pvclock_vsyscall_time_info *this_cpu_hvclock(void)
+{
+	return this_cpu_read(hv_clock_per_cpu);
+}
+
 #endif /* _ASM_X86_KVM_CLOCK_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/linkage.h
+++ linux-ein-5.4.0/arch/x86/include/asm/linkage.h
@@ -13,9 +13,13 @@
 
 #ifdef __ASSEMBLY__
 
-#define GLOBAL(name)	\
-	.globl name;	\
-	name:
+/*
+ * GLOBAL is DEPRECATED
+ *
+ * use SYM_DATA_START, SYM_FUNC_START, SYM_INNER_LABEL, SYM_CODE_START, or
+ * similar
+ */
+#define GLOBAL(name)	SYM_ENTRY(name, SYM_L_GLOBAL, SYM_A_NONE)
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_ALIGNMENT_16)
 #define __ALIGN		.p2align 4, 0x90
--- linux-ein-5.4.0.orig/arch/x86/include/asm/mce.h
+++ linux-ein-5.4.0/arch/x86/include/asm/mce.h
@@ -290,6 +290,7 @@
 /* These may be used by multiple smca_hwid_mcatypes */
 enum smca_bank_types {
 	SMCA_LS = 0,	/* Load Store */
+	SMCA_LS_V2,	/* Load Store */
 	SMCA_IF,	/* Instruction Fetch */
 	SMCA_L2_CACHE,	/* L2 Cache */
 	SMCA_DE,	/* Decoder Unit */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/mem_encrypt.h
+++ linux-ein-5.4.0/arch/x86/include/asm/mem_encrypt.h
@@ -43,13 +43,13 @@
 int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
 int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
 
-/* Architecture __weak replacement functions */
-void __init mem_encrypt_init(void);
 void __init mem_encrypt_free_decrypted_mem(void);
 
 bool sme_active(void);
 bool sev_active(void);
 
+void __init mem_encrypt_init(void);
+
 #define __bss_decrypted __attribute__((__section__(".bss..decrypted")))
 
 #else	/* !CONFIG_AMD_MEM_ENCRYPT */
@@ -77,6 +77,8 @@
 static inline int __init
 early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
 
+static inline void mem_encrypt_init(void) { }
+
 #define __bss_decrypted
 
 #endif	/* CONFIG_AMD_MEM_ENCRYPT */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/microcode.h
+++ linux-ein-5.4.0/arch/x86/include/asm/microcode.h
@@ -5,10 +5,12 @@
 #include <asm/cpu.h>
 #include <linux/earlycpio.h>
 #include <linux/initrd.h>
+#include <asm/microcode_amd.h>
 
 struct ucode_patch {
 	struct list_head plist;
 	void *data;		/* Intel uses only this one */
+	unsigned int size;
 	u32 patch_id;
 	u16 equiv_cpu;
 };
@@ -130,14 +132,16 @@
 int __init microcode_init(void);
 extern void __init load_ucode_bsp(void);
 extern void load_ucode_ap(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);
 extern bool initrd_gone;
+void microcode_bsp_resume(void);
 #else
 static inline int __init microcode_init(void)			{ return 0; };
 static inline void __init load_ucode_bsp(void)			{ }
 static inline void load_ucode_ap(void)				{ }
-static inline void reload_early_microcode(void)			{ }
+static inline void reload_early_microcode(unsigned int cpu)	{ }
+static inline void microcode_bsp_resume(void)			{ }
 static inline bool
 get_builtin_firmware(struct cpio_data *cd, const char *name)	{ return false; }
 #endif
--- linux-ein-5.4.0.orig/arch/x86/include/asm/microcode_amd.h
+++ linux-ein-5.4.0/arch/x86/include/asm/microcode_amd.h
@@ -41,18 +41,20 @@
 	unsigned int			mpb[0];
 };
 
-#define PATCH_MAX_SIZE PAGE_SIZE
+#define PATCH_MAX_SIZE (3 * PAGE_SIZE)
 
 #ifdef CONFIG_MICROCODE_AMD
 extern void __init load_ucode_amd_bsp(unsigned int family);
 extern void load_ucode_amd_ap(unsigned int family);
 extern int __init save_microcode_in_initrd_amd(unsigned int family);
-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(unsigned int family) {}
 static inline int __init
 save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
-void reload_ucode_amd(void) {}
+static inline void reload_ucode_amd(unsigned int cpu) {}
+static inline void amd_check_microcode(void) {}
 #endif
 #endif /* _ASM_X86_MICROCODE_AMD_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/msr-index.h
+++ linux-ein-5.4.0/arch/x86/include/asm/msr-index.h
@@ -47,6 +47,15 @@
 #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)
+
+/* A mask for bits which the kernel toggles when controlling mitigations */
+#define SPEC_CTRL_MITIGATIONS_MASK	(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD \
+							| SPEC_CTRL_RRSBA_DIS_S \
+							| SPEC_CTRL_BHI_DIS_S)
 
 #define MSR_IA32_PRED_CMD		0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB			BIT(0)	   /* Indirect Branch Prediction Barrier */
@@ -82,6 +91,7 @@
 #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
@@ -105,6 +115,54 @@
 						 * 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)	/*
@@ -119,6 +177,13 @@
 #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
@@ -411,6 +476,13 @@
 #define MSR_AMD64_OSVW_STATUS		0xc0010141
 #define MSR_AMD64_LS_CFG		0xc0011020
 #define MSR_AMD64_DC_CFG		0xc0011022
+#define MSR_AMD64_TW_CFG		0xc0011023
+
+#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
@@ -428,14 +500,20 @@
 #define MSR_AMD64_IBSOP_REG_MASK	((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1)
 #define MSR_AMD64_IBSCTL		0xc001103a
 #define MSR_AMD64_IBSBRTARGET		0xc001103b
+#define MSR_AMD64_ICIBSEXTDCTL		0xc001103c
 #define MSR_AMD64_IBSOPDATA4		0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX	8 /* includes MSR_AMD64_IBSBRTARGET */
+#define MSR_AMD64_VM_PAGE_FLUSH		0xc001011e
 #define MSR_AMD64_SEV			0xc0010131
 #define MSR_AMD64_SEV_ENABLED_BIT	0
 #define MSR_AMD64_SEV_ENABLED		BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)
 
 #define MSR_AMD64_VIRT_SPEC_CTRL	0xc001011f
 
+/* Zen4 */
+#define MSR_ZEN4_BP_CFG			0xc001102e
+#define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5
+
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF			0xc00000e9
 
@@ -478,9 +556,6 @@
 #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
@@ -510,6 +585,8 @@
 #define MSR_K7_HWCR			0xc0010015
 #define MSR_K7_HWCR_SMMLOCK_BIT		0
 #define MSR_K7_HWCR_SMMLOCK		BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
+#define MSR_K7_HWCR_IRPERF_EN_BIT	30
+#define MSR_K7_HWCR_IRPERF_EN		BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT)
 #define MSR_K7_FID_VID_CTL		0xc0010041
 #define MSR_K7_FID_VID_STATUS		0xc0010042
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/msr.h
+++ linux-ein-5.4.0/arch/x86/include/asm/msr.h
@@ -88,7 +88,7 @@
  * think of extending them - you will be slapped with a stinking trout or a frozen
  * shark will reach you, wherever you are! You've been warned.
  */
-static inline unsigned long long notrace __rdmsr(unsigned int msr)
+static __always_inline unsigned long long __rdmsr(unsigned int msr)
 {
 	DECLARE_ARGS(val, low, high);
 
@@ -100,7 +100,7 @@
 	return EAX_EDX_VAL(val, low, high);
 }
 
-static inline void notrace __wrmsr(unsigned int msr, u32 low, u32 high)
+static __always_inline void __wrmsr(unsigned int msr, u32 low, u32 high)
 {
 	asm volatile("1: wrmsr\n"
 		     "2:\n"
--- linux-ein-5.4.0.orig/arch/x86/include/asm/nmi.h
+++ linux-ein-5.4.0/arch/x86/include/asm/nmi.h
@@ -41,7 +41,6 @@
 	struct list_head	list;
 	nmi_handler_t		handler;
 	u64			max_duration;
-	struct irq_work		irq_work;
 	unsigned long		flags;
 	const char		*name;
 };
--- linux-ein-5.4.0.orig/arch/x86/include/asm/nospec-branch.h
+++ linux-ein-5.4.0/arch/x86/include/asm/nospec-branch.h
@@ -4,11 +4,14 @@
 #define _ASM_X86_NOSPEC_BRANCH_H_
 
 #include <linux/static_key.h>
+#include <linux/frame.h>
 
 #include <asm/alternative.h>
 #include <asm/alternative-asm.h>
 #include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
+#include <asm/unwind_hints.h>
+#include <asm/percpu.h>
 
 /*
  * This should be used immediately before a retpoline alternative. It tells
@@ -44,6 +47,7 @@
  * the optimal version — two calls, each with their own speculation
  * trap should their return address end up getting used, in a loop.
  */
+#ifdef CONFIG_X86_64
 #define __FILL_RETURN_BUFFER(reg, nr, sp)	\
 	mov	$(nr/2), reg;			\
 771:						\
@@ -59,9 +63,24 @@
 	lfence;					\
 	jmp	775b;				\
 774:						\
+	add	$(BITS_PER_LONG/8) * 2, sp;	\
 	dec	reg;				\
 	jnz	771b;				\
+	/* barrier for jnz misprediction */	\
+	lfence;
+#else
+/*
+ * i386 doesn't unconditionally have LFENCE, as such it can't
+ * do a loop.
+ */
+#define __FILL_RETURN_BUFFER(reg, nr, sp)	\
+	.rept nr;				\
+	call	772f;				\
+	int3;					\
+772:;						\
+	.endr;					\
 	add	$(BITS_PER_LONG/8) * nr, sp;
+#endif
 
 #ifdef __ASSEMBLY__
 
@@ -115,7 +134,7 @@
 	ANNOTATE_NOSPEC_ALTERNATIVE
 	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_AMD
+		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_LFENCE
 #else
 	jmp	*\reg
 #endif
@@ -126,26 +145,49 @@
 	ANNOTATE_NOSPEC_ALTERNATIVE
 	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_AMD
+		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_LFENCE
 #else
 	call	*\reg
 #endif
 .endm
 
+.macro ISSUE_UNBALANCED_RET_GUARD
+	call .Lunbalanced_ret_guard_\@
+	int3
+.Lunbalanced_ret_guard_\@:
+	add $(BITS_PER_LONG/8), %_ASM_SP
+	lfence
+.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
-#ifdef CONFIG_RETPOLINE
-	ANNOTATE_NOSPEC_ALTERNATIVE
-	ALTERNATIVE "jmp .Lskip_rsb_\@",				\
-		__stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP))	\
-		\ftr
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req ftr2
+.ifb \ftr2
+	ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
+.else
+	ALTERNATIVE_2 "jmp .Lskip_rsb_\@", "", \ftr, "jmp .Lunbalanced_\@", \ftr2
+.endif
+	__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
+.Lunbalanced_\@:
+	ISSUE_UNBALANCED_RET_GUARD
 .Lskip_rsb_\@:
-#endif
 .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__ */
 
 #define ANNOTATE_RETPOLINE_SAFE					\
@@ -154,6 +196,10 @@
 	_ASM_PTR " 999b\n\t"					\
 	".popsection\n\t"
 
+#ifdef CONFIG_X86_64
+extern void clear_bhb_loop(void);
+#endif
+
 #ifdef CONFIG_RETPOLINE
 #ifdef CONFIG_X86_64
 
@@ -171,7 +217,7 @@
 	"lfence;\n"						\
 	ANNOTATE_RETPOLINE_SAFE					\
 	"call *%[thunk_target]\n",				\
-	X86_FEATURE_RETPOLINE_AMD)
+	X86_FEATURE_RETPOLINE_LFENCE)
 # define THUNK_TARGET(addr) [thunk_target] "r" (addr)
 
 #else /* CONFIG_X86_32 */
@@ -201,7 +247,7 @@
 	"lfence;\n"						\
 	ANNOTATE_RETPOLINE_SAFE					\
 	"call *%[thunk_target]\n",				\
-	X86_FEATURE_RETPOLINE_AMD)
+	X86_FEATURE_RETPOLINE_LFENCE)
 
 # define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
 #endif
@@ -213,9 +259,12 @@
 /* The Spectre V2 mitigation variants */
 enum spectre_v2_mitigation {
 	SPECTRE_V2_NONE,
-	SPECTRE_V2_RETPOLINE_GENERIC,
-	SPECTRE_V2_RETPOLINE_AMD,
-	SPECTRE_V2_IBRS_ENHANCED,
+	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 */
@@ -279,6 +328,9 @@
 
 /* The Intel SPEC CTRL MSR base value cache */
 extern u64 x86_spec_ctrl_base;
+DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
+extern void update_spec_ctrl_cond(u64 val);
+extern u64 spec_ctrl_current(void);
 
 /*
  * With retpoline, we must use IBRS to restrict branch prediction
@@ -288,18 +340,16 @@
  */
 #define firmware_restrict_branch_speculation_start()			\
 do {									\
-	u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;			\
-									\
 	preempt_disable();						\
-	alternative_msr_write(MSR_IA32_SPEC_CTRL, val,			\
+	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 {									\
-	u64 val = x86_spec_ctrl_base;					\
-									\
-	alternative_msr_write(MSR_IA32_SPEC_CTRL, val,			\
+	alternative_msr_write(MSR_IA32_SPEC_CTRL,			\
+			      spec_ctrl_current(),			\
 			      X86_FEATURE_USE_IBRS_FW);			\
 	preempt_enable();						\
 } while (0)
@@ -311,6 +361,8 @@
 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>
 
 /**
@@ -320,7 +372,7 @@
  * combination with microcode which triggers a CPU buffer flush when the
  * instruction is executed.
  */
-static inline void mds_clear_cpu_buffers(void)
+static __always_inline void mds_clear_cpu_buffers(void)
 {
 	static const u16 ds = __KERNEL_DS;
 
@@ -341,7 +393,7 @@
  *
  * Clear CPU buffers if the corresponding static key is enabled
  */
-static inline void mds_user_clear_cpu_buffers(void)
+static __always_inline void mds_user_clear_cpu_buffers(void)
 {
 	if (static_branch_likely(&mds_user_clear))
 		mds_clear_cpu_buffers();
--- linux-ein-5.4.0.orig/arch/x86/include/asm/numa.h
+++ linux-ein-5.4.0/arch/x86/include/asm/numa.h
@@ -11,13 +11,6 @@
 
 #define NR_NODE_MEMBLKS		(MAX_NUMNODES*2)
 
-/*
- * Too small node sizes may confuse the VM badly. Usually they
- * result from BIOS bugs. So dont recognize nodes as standalone
- * NUMA entities that have less than this amount of RAM listed:
- */
-#define NODE_MIN_SIZE (4*1024*1024)
-
 extern int numa_off;
 
 /*
--- linux-ein-5.4.0.orig/arch/x86/include/asm/page_64_types.h
+++ linux-ein-5.4.0/arch/x86/include/asm/page_64_types.h
@@ -15,7 +15,7 @@
 #define THREAD_SIZE_ORDER	(2 + KASAN_STACK_ORDER)
 #define THREAD_SIZE  (PAGE_SIZE << THREAD_SIZE_ORDER)
 
-#define EXCEPTION_STACK_ORDER (0 + KASAN_STACK_ORDER)
+#define EXCEPTION_STACK_ORDER (1 + KASAN_STACK_ORDER)
 #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
 
 #define IRQ_STACK_ORDER (2 + KASAN_STACK_ORDER)
--- linux-ein-5.4.0.orig/arch/x86/include/asm/pci-direct.h
+++ linux-ein-5.4.0/arch/x86/include/asm/pci-direct.h
@@ -10,9 +10,11 @@
 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);
 #endif /* _ASM_X86_PCI_DIRECT_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/x86/include/asm/pgtable.h
@@ -253,6 +253,7 @@
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+/* NOTE: when predicate huge page, consider also pmd_devmap, or use pmd_large */
 static inline int pmd_trans_huge(pmd_t pmd)
 {
 	return (pmd_val(pmd) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE;
@@ -624,12 +625,15 @@
 	return __pmd(val);
 }
 
-/* mprotect needs to preserve PAT bits when updating vm_page_prot */
+/*
+ * mprotect needs to preserve PAT and encryption bits when updating
+ * vm_page_prot
+ */
 #define pgprot_modify pgprot_modify
 static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
 {
 	pgprotval_t preservebits = pgprot_val(oldprot) & _PAGE_CHG_MASK;
-	pgprotval_t addbits = pgprot_val(newprot);
+	pgprotval_t addbits = pgprot_val(newprot) & ~_PAGE_CHG_MASK;
 	return __pgprot(preservebits | addbits);
 }
 
@@ -1371,8 +1375,8 @@
 #endif
 #endif
 
-#define PKRU_AD_BIT 0x1
-#define PKRU_WD_BIT 0x2
+#define PKRU_AD_BIT 0x1u
+#define PKRU_WD_BIT 0x2u
 #define PKRU_BITS_PER_PKEY 2
 
 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
--- linux-ein-5.4.0.orig/arch/x86/include/asm/pgtable_32_types.h
+++ linux-ein-5.4.0/arch/x86/include/asm/pgtable_32_types.h
@@ -44,11 +44,11 @@
  * Define this here and validate with BUILD_BUG_ON() in pgtable_32.c
  * to avoid include recursion hell
  */
-#define CPU_ENTRY_AREA_PAGES	(NR_CPUS * 40)
+#define CPU_ENTRY_AREA_PAGES	(NR_CPUS * 39)
 
-#define CPU_ENTRY_AREA_BASE						\
-	((FIXADDR_TOT_START - PAGE_SIZE * (CPU_ENTRY_AREA_PAGES + 1))   \
-	 & PMD_MASK)
+/* The +1 is for the readonly IDT page: */
+#define CPU_ENTRY_AREA_BASE	\
+	((FIXADDR_TOT_START - PAGE_SIZE*(CPU_ENTRY_AREA_PAGES+1)) & PMD_MASK)
 
 #define LDT_BASE_ADDR		\
 	((CPU_ENTRY_AREA_BASE - PAGE_SIZE) & PMD_MASK)
--- linux-ein-5.4.0.orig/arch/x86/include/asm/pgtable_types.h
+++ linux-ein-5.4.0/arch/x86/include/asm/pgtable_types.h
@@ -123,7 +123,7 @@
  */
 #define _PAGE_CHG_MASK	(PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT |		\
 			 _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY |	\
-			 _PAGE_SOFT_DIRTY | _PAGE_DEVMAP)
+			 _PAGE_SOFT_DIRTY | _PAGE_DEVMAP | _PAGE_ENC)
 #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE)
 
 /*
@@ -147,6 +147,7 @@
 #endif
 
 #define _PAGE_CACHE_MASK	(_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)
+#define _PAGE_LARGE_CACHE_MASK	(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT_LARGE)
 #define _PAGE_NOCACHE		(cachemode2protval(_PAGE_CACHE_MODE_UC))
 #define _PAGE_CACHE_WP		(cachemode2protval(_PAGE_CACHE_MODE_WP))
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/pkeys.h
+++ linux-ein-5.4.0/arch/x86/include/asm/pkeys.h
@@ -4,6 +4,11 @@
 
 #define ARCH_DEFAULT_PKEY	0
 
+/*
+ * If more than 16 keys are ever supported, a thorough audit
+ * will be necessary to ensure that the types that store key
+ * numbers and masks have sufficient capacity.
+ */
 #define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1)
 
 extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
--- linux-ein-5.4.0.orig/arch/x86/include/asm/processor.h
+++ linux-ein-5.4.0/arch/x86/include/asm/processor.h
@@ -334,7 +334,7 @@
 #define INVALID_IO_BITMAP_OFFSET	0x8000
 
 struct entry_stack {
-	unsigned long		words[64];
+	char	stack[PAGE_SIZE];
 };
 
 struct entry_stack_page {
@@ -507,15 +507,6 @@
 }
 
 /*
- * Thread-synchronous status.
- *
- * This is different from the flags in that nobody else
- * ever touches our thread-synchronous status, so we don't
- * have to worry about atomic accesses.
- */
-#define TS_COMPAT		0x0002	/* 32bit syscall active (64BIT)*/
-
-/*
  * Set IOPL bits in EFLAGS from given mask
  */
 static inline void native_set_iopl_mask(unsigned mask)
@@ -936,9 +927,11 @@
 #ifdef CONFIG_CPU_SUP_AMD
 extern u16 amd_get_nb_id(int cpu);
 extern u32 amd_get_nodes_per_socket(void);
+extern void amd_clear_divider(void);
 #else
 static inline u16 amd_get_nb_id(int cpu)		{ return 0; }
 static inline u32 amd_get_nodes_per_socket(void)	{ return 0; }
+static inline void amd_clear_divider(void)		{ }
 #endif
 
 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
@@ -995,4 +988,6 @@
 	TAA_MITIGATION_TSX_DISABLED,
 };
 
+extern bool gds_ucode_mitigated(void);
+
 #endif /* _ASM_X86_PROCESSOR_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/proto.h
+++ linux-ein-5.4.0/arch/x86/include/asm/proto.h
@@ -4,6 +4,8 @@
 
 #include <asm/ldt.h>
 
+struct task_struct;
+
 /* misc architecture specific prototypes */
 
 void syscall_init(void);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/ptrace.h
+++ linux-ein-5.4.0/arch/x86/include/asm/ptrace.h
@@ -309,8 +309,8 @@
 	static const unsigned int argument_offs[] = {
 #ifdef __i386__
 		offsetof(struct pt_regs, ax),
-		offsetof(struct pt_regs, cx),
 		offsetof(struct pt_regs, dx),
+		offsetof(struct pt_regs, cx),
 #define NR_REG_ARGUMENTS 3
 #else
 		offsetof(struct pt_regs, di),
--- linux-ein-5.4.0.orig/arch/x86/include/asm/realmode.h
+++ linux-ein-5.4.0/arch/x86/include/asm/realmode.h
@@ -82,6 +82,7 @@
 }
 
 void reserve_real_mode(void);
+void load_trampoline_pgtable(void);
 
 #endif /* __ASSEMBLY__ */
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/reboot.h
+++ linux-ein-5.4.0/arch/x86/include/asm/reboot.h
@@ -25,6 +25,8 @@
 #define MRR_BIOS	0
 #define MRR_APM		1
 
+void cpu_emergency_disable_virtualization(void);
+
 typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
 void nmi_panic_self_stop(struct pt_regs *regs);
 void nmi_shootdown_cpus(nmi_shootdown_cb callback);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/required-features.h
+++ linux-ein-5.4.0/arch/x86/include/asm/required-features.h
@@ -101,6 +101,9 @@
 #define REQUIRED_MASK16	0
 #define REQUIRED_MASK17	0
 #define REQUIRED_MASK18	0
-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
+#define REQUIRED_MASK19	0
+#define REQUIRED_MASK20	0
+#define REQUIRED_MASK21	0
+#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22)
 
 #endif /* _ASM_X86_REQUIRED_FEATURES_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/resctrl_sched.h
+++ linux-ein-5.4.0/arch/x86/include/asm/resctrl_sched.h
@@ -51,24 +51,27 @@
  *   simple as possible.
  * Must be called with preemption disabled.
  */
-static void __resctrl_sched_in(void)
+static inline void __resctrl_sched_in(struct task_struct *tsk)
 {
 	struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
 	u32 closid = state->default_closid;
 	u32 rmid = state->default_rmid;
+	u32 tmp;
 
 	/*
 	 * If this task has a closid/rmid assigned, use it.
 	 * Else use the closid/rmid assigned to this cpu.
 	 */
 	if (static_branch_likely(&rdt_alloc_enable_key)) {
-		if (current->closid)
-			closid = current->closid;
+		tmp = READ_ONCE(tsk->closid);
+		if (tmp)
+			closid = tmp;
 	}
 
 	if (static_branch_likely(&rdt_mon_enable_key)) {
-		if (current->rmid)
-			rmid = current->rmid;
+		tmp = READ_ONCE(tsk->rmid);
+		if (tmp)
+			rmid = tmp;
 	}
 
 	if (closid != state->cur_closid || rmid != state->cur_rmid) {
@@ -78,15 +81,15 @@
 	}
 }
 
-static inline void resctrl_sched_in(void)
+static inline void resctrl_sched_in(struct task_struct *tsk)
 {
 	if (static_branch_likely(&rdt_enable_key))
-		__resctrl_sched_in();
+		__resctrl_sched_in(tsk);
 }
 
 #else
 
-static inline void resctrl_sched_in(void) {}
+static inline void resctrl_sched_in(struct task_struct *tsk) {}
 
 #endif /* CONFIG_X86_CPU_RESCTRL */
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/segment.h
+++ linux-ein-5.4.0/arch/x86/include/asm/segment.h
@@ -31,6 +31,18 @@
  */
 #define SEGMENT_RPL_MASK	0x3
 
+/*
+ * When running on Xen PV, the actual privilege level of the kernel is 1,
+ * not 0. Testing the Requested Privilege Level in a segment selector to
+ * determine whether the context is user mode or kernel mode with
+ * SEGMENT_RPL_MASK is wrong because the PV kernel's privilege level
+ * matches the 0x3 mask.
+ *
+ * Testing with USER_SEGMENT_RPL_MASK is valid for both native and Xen PV
+ * kernels because privilege level 2 is never used.
+ */
+#define USER_SEGMENT_RPL_MASK	0x2
+
 /* User mode is privilege level 3: */
 #define USER_RPL		0x3
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/set_memory.h
+++ linux-ein-5.4.0/arch/x86/include/asm/set_memory.h
@@ -85,28 +85,35 @@
 void set_kernel_text_ro(void);
 
 #ifdef CONFIG_X86_64
-static inline int set_mce_nospec(unsigned long pfn)
+/*
+ * Prevent speculative access to the page by either unmapping
+ * it (if we do not require access to any part of the page) or
+ * marking it uncacheable (if we want to try to retrieve data
+ * from non-poisoned lines in the page).
+ */
+static inline int set_mce_nospec(unsigned long pfn, bool unmap)
 {
 	unsigned long decoy_addr;
 	int rc;
 
 	/*
-	 * Mark the linear address as UC to make sure we don't log more
-	 * errors because of speculative access to the page.
 	 * We would like to just call:
-	 *      set_memory_uc((unsigned long)pfn_to_kaddr(pfn), 1);
+	 *      set_memory_XX((unsigned long)pfn_to_kaddr(pfn), 1);
 	 * but doing that would radically increase the odds of a
 	 * speculative access to the poison page because we'd have
 	 * the virtual address of the kernel 1:1 mapping sitting
 	 * around in registers.
 	 * Instead we get tricky.  We create a non-canonical address
 	 * that looks just like the one we want, but has bit 63 flipped.
-	 * This relies on set_memory_uc() properly sanitizing any __pa()
+	 * This relies on set_memory_XX() properly sanitizing any __pa()
 	 * results with __PHYSICAL_MASK or PTE_PFN_MASK.
 	 */
 	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
 
-	rc = set_memory_uc(decoy_addr, 1);
+	if (unmap)
+		rc = set_memory_np(decoy_addr, 1);
+	else
+		rc = set_memory_uc(decoy_addr, 1);
 	if (rc)
 		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn);
 	return rc;
--- linux-ein-5.4.0.orig/arch/x86/include/asm/setup.h
+++ linux-ein-5.4.0/arch/x86/include/asm/setup.h
@@ -94,27 +94,16 @@
 void *extend_brk(size_t size, size_t align);
 
 /*
- * Reserve space in the brk section.  The name must be unique within
- * the file, and somewhat descriptive.  The size is in bytes.  Must be
- * used at file scope.
+ * Reserve space in the .brk section, which is a block of memory from which the
+ * caller is allowed to allocate very early (before even memblock is available)
+ * by calling extend_brk().  All allocated memory will be eventually converted
+ * to memblock.  Any leftover unallocated memory will be freed.
  *
- * (This uses a temp function to wrap the asm so we can pass it the
- * size parameter; otherwise we wouldn't be able to.  We can't use a
- * "section" attribute on a normal variable because it always ends up
- * being @progbits, which ends up allocating space in the vmlinux
- * executable.)
+ * The size is in bytes.
  */
-#define RESERVE_BRK(name,sz)						\
-	static void __section(.discard.text) __used notrace		\
-	__brk_reservation_fn_##name##__(void) {				\
-		asm volatile (						\
-			".pushsection .brk_reservation,\"aw\",@nobits;" \
-			".brk." #name ":"				\
-			" 1:.skip %c0;"					\
-			" .size .brk." #name ", . - 1b;"		\
-			" .popsection"					\
-			: : "i" (sz));					\
-	}
+#define RESERVE_BRK(name, size)					\
+	__section(.bss..brk) __aligned(1) __used	\
+	static char __brk_##name[size]
 
 /* Helper for reserving space for arrays of things */
 #define RESERVE_BRK_ARRAY(type, name, entries)		\
@@ -132,12 +121,19 @@
 
 #endif /* __i386__ */
 #endif /* _SETUP */
-#else
-#define RESERVE_BRK(name,sz)				\
-	.pushsection .brk_reservation,"aw",@nobits;	\
-.brk.name:						\
-1:	.skip sz;					\
-	.size .brk.name,.-1b;				\
+
+#else  /* __ASSEMBLY */
+
+.macro __RESERVE_BRK name, size
+	.pushsection .bss..brk, "aw"
+SYM_DATA_START(__brk_\name)
+	.skip \size
+SYM_DATA_END(__brk_\name)
 	.popsection
+.endm
+
+#define RESERVE_BRK(name, size) __RESERVE_BRK name, size
+
 #endif /* __ASSEMBLY__ */
+
 #endif /* _ASM_X86_SETUP_H */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/smap.h
+++ linux-ein-5.4.0/arch/x86/include/asm/smap.h
@@ -57,8 +57,10 @@
 {
 	unsigned long flags;
 
-	asm volatile (ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC,
-				  X86_FEATURE_SMAP)
+	asm volatile ("# smap_save\n\t"
+		      ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
+		      "pushf; pop %0; " __ASM_CLAC "\n\t"
+		      "1:"
 		      : "=rm" (flags) : : "memory", "cc");
 
 	return flags;
@@ -66,7 +68,10 @@
 
 static __always_inline void smap_restore(unsigned long flags)
 {
-	asm volatile (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP)
+	asm volatile ("# smap_restore\n\t"
+		      ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
+		      "push %0; popf\n\t"
+		      "1:"
 		      : : "g" (flags) : "memory", "cc");
 }
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/special_insns.h
+++ linux-ein-5.4.0/arch/x86/include/asm/special_insns.h
@@ -10,45 +10,47 @@
 #include <linux/jump_label.h>
 
 /*
- * Volatile isn't enough to prevent the compiler from reordering the
- * read/write functions for the control registers and messing everything up.
- * A memory clobber would solve the problem, but would prevent reordering of
- * all loads stores around it, which can hurt performance. Solution is to
- * use a variable and mimic reads and writes to it to enforce serialization
+ * The compiler should not reorder volatile asm statements with respect to each
+ * other: they should execute in program order. However GCC 4.9.x and 5.x have
+ * a bug (which was fixed in 8.1, 7.3 and 6.5) where they might reorder
+ * volatile asm. The write functions are not affected since they have memory
+ * clobbers preventing reordering. To prevent reads from being reordered with
+ * respect to writes, use a dummy memory operand.
  */
-extern unsigned long __force_order;
+
+#define __FORCE_ORDER "m"(*(unsigned int *)0x1000UL)
 
 void native_write_cr0(unsigned long val);
 
 static inline unsigned long native_read_cr0(void)
 {
 	unsigned long val;
-	asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
+	asm volatile("mov %%cr0,%0\n\t" : "=r" (val) : __FORCE_ORDER);
 	return val;
 }
 
 static inline unsigned long native_read_cr2(void)
 {
 	unsigned long val;
-	asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order));
+	asm volatile("mov %%cr2,%0\n\t" : "=r" (val) : __FORCE_ORDER);
 	return val;
 }
 
 static inline void native_write_cr2(unsigned long val)
 {
-	asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order));
+	asm volatile("mov %0,%%cr2": : "r" (val) : "memory");
 }
 
 static inline unsigned long __native_read_cr3(void)
 {
 	unsigned long val;
-	asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order));
+	asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER);
 	return val;
 }
 
 static inline void native_write_cr3(unsigned long val)
 {
-	asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order));
+	asm volatile("mov %0,%%cr3": : "r" (val) : "memory");
 }
 
 static inline unsigned long native_read_cr4(void)
@@ -63,10 +65,10 @@
 	asm volatile("1: mov %%cr4, %0\n"
 		     "2:\n"
 		     _ASM_EXTABLE(1b, 2b)
-		     : "=r" (val), "=m" (__force_order) : "0" (0));
+		     : "=r" (val) : "0" (0), __FORCE_ORDER);
 #else
 	/* CR4 always exists on x86_64. */
-	asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
+	asm volatile("mov %%cr4,%0\n\t" : "=r" (val) : __FORCE_ORDER);
 #endif
 	return val;
 }
--- linux-ein-5.4.0.orig/arch/x86/include/asm/stackprotector.h
+++ linux-ein-5.4.0/arch/x86/include/asm/stackprotector.h
@@ -55,8 +55,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-ein-5.4.0.orig/arch/x86/include/asm/suspend_32.h
+++ linux-ein-5.4.0/arch/x86/include/asm/suspend_32.h
@@ -21,7 +21,6 @@
 #endif
 	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;
@@ -30,6 +29,7 @@
 	unsigned long tr;
 	unsigned long safety;
 	unsigned long return_address;
+	bool misc_enable_saved;
 } __attribute__((packed));
 
 /* routines for saving/restoring kernel state */
--- linux-ein-5.4.0.orig/arch/x86/include/asm/suspend_64.h
+++ linux-ein-5.4.0/arch/x86/include/asm/suspend_64.h
@@ -14,9 +14,13 @@
  * Image of the saved processor state, used by the low level ACPI suspend to
  * RAM code and by the low level hibernation code.
  *
- * If you modify it, fix arch/x86/kernel/acpi/wakeup_64.S and make sure that
- * __save/__restore_processor_state(), defined in arch/x86/kernel/suspend_64.c,
- * still work as required.
+ * If you modify it, check how it is used in arch/x86/kernel/acpi/wakeup_64.S
+ * and make sure that __save/__restore_processor_state(), defined in
+ * arch/x86/power/cpu.c, still work as required.
+ *
+ * Because the structure is packed, make sure to avoid unaligned members. For
+ * optimisation purposes but also because tools like kmemleak only search for
+ * pointers that are aligned.
  */
 struct saved_context {
 	struct pt_regs regs;
@@ -36,7 +40,6 @@
 
 	unsigned long cr0, cr2, cr3, cr4;
 	u64 misc_enable;
-	bool misc_enable_saved;
 	struct saved_msrs saved_msrs;
 	unsigned long efer;
 	u16 gdt_pad; /* Unused */
@@ -48,6 +51,7 @@
 	unsigned long tr;
 	unsigned long safety;
 	unsigned long return_address;
+	bool misc_enable_saved;
 } __attribute__((packed));
 
 #define loaddebug(thread,register) \
--- linux-ein-5.4.0.orig/arch/x86/include/asm/svm.h
+++ linux-ein-5.4.0/arch/x86/include/asm/svm.h
@@ -119,6 +119,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-ein-5.4.0.orig/arch/x86/include/asm/sync_core.h
+++ linux-ein-5.4.0/arch/x86/include/asm/sync_core.h
@@ -16,12 +16,13 @@
 	/* With PTI, we unconditionally serialize before running user code. */
 	if (static_cpu_has(X86_FEATURE_PTI))
 		return;
+
 	/*
-	 * Return from interrupt and NMI is done through iret, which is core
-	 * serializing.
+	 * Even if we're in an interrupt, we might reschedule before returning,
+	 * in which case we could switch to a different thread in the same mm
+	 * and return using SYSRET or SYSEXIT.  Instead of trying to keep
+	 * track of our need to sync the core, just sync right away.
 	 */
-	if (in_irq() || in_nmi())
-		return;
 	sync_core();
 }
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/syscall_wrapper.h
+++ linux-ein-5.4.0/arch/x86/include/asm/syscall_wrapper.h
@@ -6,18 +6,37 @@
 #ifndef _ASM_X86_SYSCALL_WRAPPER_H
 #define _ASM_X86_SYSCALL_WRAPPER_H
 
+struct pt_regs;
+
 /* Mapping of registers to parameters for syscalls on x86-64 and x32 */
 #define SC_X86_64_REGS_TO_ARGS(x, ...)					\
 	__MAP(x,__SC_ARGS						\
 		,,regs->di,,regs->si,,regs->dx				\
 		,,regs->r10,,regs->r8,,regs->r9)			\
 
+
+/* SYSCALL_PT_ARGS is Adapted from s390x */
+#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6)			\
+	SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp))
+#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5)				\
+	SYSCALL_PT_ARG4(m, t1, t2, t3, t4),  m(t5, (regs->di))
+#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4)				\
+	SYSCALL_PT_ARG3(m, t1, t2, t3),  m(t4, (regs->si))
+#define SYSCALL_PT_ARG3(m, t1, t2, t3)					\
+	SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx))
+#define SYSCALL_PT_ARG2(m, t1, t2)					\
+	SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx))
+#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx))
+#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
+
+#define __SC_COMPAT_CAST(t, a)						\
+	(__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U)))	\
+	(unsigned int)a
+
 /* Mapping of registers to parameters for syscalls on i386 */
 #define SC_IA32_REGS_TO_ARGS(x, ...)					\
-	__MAP(x,__SC_ARGS						\
-	      ,,(unsigned int)regs->bx,,(unsigned int)regs->cx		\
-	      ,,(unsigned int)regs->dx,,(unsigned int)regs->si		\
-	      ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
+	SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST,				\
+			__MAP(x, __SC_TYPE, __VA_ARGS__))		\
 
 #ifdef CONFIG_IA32_EMULATION
 /*
@@ -28,13 +47,21 @@
  * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
  * case as well.
  */
+#define __IA32_COMPAT_SYS_STUB0(x, name)				\
+	asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs);\
+	ALLOW_ERROR_INJECTION(__ia32_compat_sys_##name, ERRNO);		\
+	asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs)\
+	{								\
+		return __se_compat_sys_##name();			\
+	}
+
 #define __IA32_COMPAT_SYS_STUBx(x, name, ...)				\
 	asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs);\
 	ALLOW_ERROR_INJECTION(__ia32_compat_sys##name, ERRNO);		\
 	asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs)\
 	{								\
 		return __se_compat_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\
-	}								\
+	}
 
 #define __IA32_SYS_STUBx(x, name, ...)					\
 	asmlinkage long __ia32_sys##name(const struct pt_regs *regs);	\
@@ -48,16 +75,23 @@
  * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias
  * named __ia32_sys_*()
  */
-#define SYSCALL_DEFINE0(sname)					\
-	SYSCALL_METADATA(_##sname, 0);				\
-	asmlinkage long __x64_sys_##sname(void);		\
-	ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);	\
-	SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname);	\
-	asmlinkage long __x64_sys_##sname(void)
-
-#define COND_SYSCALL(name)						\
-	cond_syscall(__x64_sys_##name);					\
-	cond_syscall(__ia32_sys_##name)
+
+#define SYSCALL_DEFINE0(sname)						\
+	SYSCALL_METADATA(_##sname, 0);					\
+	asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
+	ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);		\
+	SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname);		\
+	asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
+
+#define COND_SYSCALL(name)							\
+	asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused)	\
+	{									\
+		return sys_ni_syscall();					\
+	}									\
+	asmlinkage __weak long __ia32_sys_##name(const struct pt_regs *__unused)\
+	{									\
+		return sys_ni_syscall();					\
+	}
 
 #define SYS_NI(name)							\
 	SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers);		\
@@ -75,15 +109,24 @@
  * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
  * with x86_64 obviously do not need such care.
  */
+#define __X32_COMPAT_SYS_STUB0(x, name, ...)				\
+	asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs);\
+	ALLOW_ERROR_INJECTION(__x32_compat_sys_##name, ERRNO);		\
+	asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs)\
+	{								\
+		return __se_compat_sys_##name();\
+	}
+
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)				\
 	asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs);\
 	ALLOW_ERROR_INJECTION(__x32_compat_sys##name, ERRNO);		\
 	asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs)\
 	{								\
 		return __se_compat_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
-	}								\
+	}
 
 #else /* CONFIG_X86_X32 */
+#define __X32_COMPAT_SYS_STUB0(x, name)
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)
 #endif /* CONFIG_X86_X32 */
 
@@ -94,6 +137,17 @@
  * mapping of registers to parameters, we need to generate stubs for each
  * of them.
  */
+#define COMPAT_SYSCALL_DEFINE0(name)					\
+	static long __se_compat_sys_##name(void);			\
+	static inline long __do_compat_sys_##name(void);		\
+	__IA32_COMPAT_SYS_STUB0(x, name)				\
+	__X32_COMPAT_SYS_STUB0(x, name)					\
+	static long __se_compat_sys_##name(void)			\
+	{								\
+		return __do_compat_sys_##name();			\
+	}								\
+	static inline long __do_compat_sys_##name(void)
+
 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)					\
 	static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
 	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
@@ -181,15 +235,19 @@
  * macros to work correctly.
  */
 #ifndef SYSCALL_DEFINE0
-#define SYSCALL_DEFINE0(sname)					\
-	SYSCALL_METADATA(_##sname, 0);				\
-	asmlinkage long __x64_sys_##sname(void);		\
-	ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);	\
-	asmlinkage long __x64_sys_##sname(void)
+#define SYSCALL_DEFINE0(sname)						\
+	SYSCALL_METADATA(_##sname, 0);					\
+	asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
+	ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);		\
+	asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
 #endif
 
 #ifndef COND_SYSCALL
-#define COND_SYSCALL(name) cond_syscall(__x64_sys_##name)
+#define COND_SYSCALL(name) 							\
+	asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused)	\
+	{									\
+		return sys_ni_syscall();					\
+	}
 #endif
 
 #ifndef SYS_NI
@@ -201,7 +259,6 @@
  * For VSYSCALLS, we need to declare these three syscalls with the new
  * pt_regs-based calling convention for in-kernel use.
  */
-struct pt_regs;
 asmlinkage long __x64_sys_getcpu(const struct pt_regs *regs);
 asmlinkage long __x64_sys_gettimeofday(const struct pt_regs *regs);
 asmlinkage long __x64_sys_time(const struct pt_regs *regs);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/x86/include/asm/thread_info.h
@@ -221,10 +221,31 @@
 
 #endif
 
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_COMPAT		0x0002	/* 32bit syscall active (64BIT)*/
+
+#ifndef __ASSEMBLY__
 #ifdef CONFIG_COMPAT
 #define TS_I386_REGS_POKED	0x0004	/* regs poked by 32-bit ptracer */
+#define TS_COMPAT_RESTART	0x0008
+
+#define arch_set_restart_data	arch_set_restart_data
+
+static inline void arch_set_restart_data(struct restart_block *restart)
+{
+	struct thread_info *ti = current_thread_info();
+	if (ti->status & TS_COMPAT)
+		ti->status |= TS_COMPAT_RESTART;
+	else
+		ti->status &= ~TS_COMPAT_RESTART;
+}
 #endif
-#ifndef __ASSEMBLY__
 
 #ifdef CONFIG_X86_32
 #define in_ia32_syscall() true
--- linux-ein-5.4.0.orig/arch/x86/include/asm/timex.h
+++ linux-ein-5.4.0/arch/x86/include/asm/timex.h
@@ -5,6 +5,15 @@
 #include <asm/processor.h>
 #include <asm/tsc.h>
 
+static inline unsigned long random_get_entropy(void)
+{
+	if (!IS_ENABLED(CONFIG_X86_TSC) &&
+	    !cpu_feature_enabled(X86_FEATURE_TSC))
+		return random_get_entropy_fallback();
+	return rdtsc();
+}
+#define random_get_entropy random_get_entropy
+
 /* Assume we use the PIT time source for the clock tick */
 #define CLOCK_TICK_RATE		PIT_TICK_RATE
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/topology.h
+++ linux-ein-5.4.0/arch/x86/include/asm/topology.h
@@ -110,6 +110,8 @@
 #define topology_die_id(cpu)			(cpu_data(cpu).cpu_die_id)
 #define topology_core_id(cpu)			(cpu_data(cpu).cpu_core_id)
 
+extern unsigned int __max_die_per_package;
+
 #ifdef CONFIG_SMP
 #define topology_die_cpumask(cpu)		(per_cpu(cpu_die_map, cpu))
 #define topology_core_cpumask(cpu)		(per_cpu(cpu_core_map, cpu))
@@ -118,8 +120,6 @@
 extern unsigned int __max_logical_packages;
 #define topology_max_packages()			(__max_logical_packages)
 
-extern unsigned int __max_die_per_package;
-
 static inline int topology_max_die_per_package(void)
 {
 	return __max_die_per_package;
--- linux-ein-5.4.0.orig/arch/x86/include/asm/tsc.h
+++ linux-ein-5.4.0/arch/x86/include/asm/tsc.h
@@ -22,13 +22,12 @@
 
 static inline cycles_t get_cycles(void)
 {
-#ifndef CONFIG_X86_TSC
-	if (!boot_cpu_has(X86_FEATURE_TSC))
+	if (!IS_ENABLED(CONFIG_X86_TSC) &&
+	    !cpu_feature_enabled(X86_FEATURE_TSC))
 		return 0;
-#endif
-
 	return rdtsc();
 }
+#define get_cycles get_cycles
 
 extern struct system_counterval_t convert_art_to_tsc(u64 art);
 extern struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns);
--- linux-ein-5.4.0.orig/arch/x86/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/x86/include/asm/uaccess.h
@@ -378,18 +378,6 @@
 		     : "=r" (err), ltype(x)				\
 		     : "m" (__m(addr)), "i" (errret), "0" (err))
 
-#define __get_user_asm_nozero(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("\n"						\
-		     "1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
-		     ".section .fixup,\"ax\"\n"				\
-		     "3:	mov %3,%0\n"				\
-		     "	jmp 2b\n"					\
-		     ".previous\n"					\
-		     _ASM_EXTABLE_UA(1b, 3b)				\
-		     : "=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.
@@ -453,6 +441,103 @@
 	__builtin_expect(__gu_err, 0);					\
 })
 
+#ifdef CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT
+#define __try_cmpxchg_user_asm(itype, ltype, _ptr, _pold, _new, label)	({ \
+	bool success;							\
+	__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold);		\
+	__typeof__(*(_ptr)) __old = *_old;				\
+	__typeof__(*(_ptr)) __new = (_new);				\
+	asm_volatile_goto("\n"						\
+		     "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\
+		     _ASM_EXTABLE_UA(1b, %l[label])			\
+		     : CC_OUT(z) (success),				\
+		       [ptr] "+m" (*_ptr),				\
+		       [old] "+a" (__old)				\
+		     : [new] ltype (__new)				\
+		     : "memory"						\
+		     : label);						\
+	if (unlikely(!success))						\
+		*_old = __old;						\
+	likely(success);					})
+
+#ifdef CONFIG_X86_32
+#define __try_cmpxchg64_user_asm(_ptr, _pold, _new, label)	({	\
+	bool success;							\
+	__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold);		\
+	__typeof__(*(_ptr)) __old = *_old;				\
+	__typeof__(*(_ptr)) __new = (_new);				\
+	asm_volatile_goto("\n"						\
+		     "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n"		\
+		     _ASM_EXTABLE_UA(1b, %l[label])			\
+		     : CC_OUT(z) (success),				\
+		       "+A" (__old),					\
+		       [ptr] "+m" (*_ptr)				\
+		     : "b" ((u32)__new),				\
+		       "c" ((u32)((u64)__new >> 32))			\
+		     : "memory"						\
+		     : label);						\
+	if (unlikely(!success))						\
+		*_old = __old;						\
+	likely(success);					})
+#endif // CONFIG_X86_32
+#else  // !CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT
+#define __try_cmpxchg_user_asm(itype, ltype, _ptr, _pold, _new, label)	({ \
+	int __err = 0;							\
+	bool success;							\
+	__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold);		\
+	__typeof__(*(_ptr)) __old = *_old;				\
+	__typeof__(*(_ptr)) __new = (_new);				\
+	asm volatile("\n"						\
+		     "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\
+		     CC_SET(z)						\
+		     "2:\n"						\
+		     _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG,	\
+					   %[errout])			\
+		     : CC_OUT(z) (success),				\
+		       [errout] "+r" (__err),				\
+		       [ptr] "+m" (*_ptr),				\
+		       [old] "+a" (__old)				\
+		     : [new] ltype (__new)				\
+		     : "memory");					\
+	if (unlikely(__err))						\
+		goto label;						\
+	if (unlikely(!success))						\
+		*_old = __old;						\
+	likely(success);					})
+
+#ifdef CONFIG_X86_32
+/*
+ * Unlike the normal CMPXCHG, hardcode ECX for both success/fail and error.
+ * There are only six GPRs available and four (EAX, EBX, ECX, and EDX) are
+ * hardcoded by CMPXCHG8B, leaving only ESI and EDI.  If the compiler uses
+ * both ESI and EDI for the memory operand, compilation will fail if the error
+ * is an input+output as there will be no register available for input.
+ */
+#define __try_cmpxchg64_user_asm(_ptr, _pold, _new, label)	({	\
+	int __result;							\
+	__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold);		\
+	__typeof__(*(_ptr)) __old = *_old;				\
+	__typeof__(*(_ptr)) __new = (_new);				\
+	asm volatile("\n"						\
+		     "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n"		\
+		     "mov $0, %%ecx\n\t"				\
+		     "setz %%cl\n"					\
+		     "2:\n"						\
+		     _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %%ecx) \
+		     : [result]"=c" (__result),				\
+		       "+A" (__old),					\
+		       [ptr] "+m" (*_ptr)				\
+		     : "b" ((u32)__new),				\
+		       "c" ((u32)((u64)__new >> 32))			\
+		     : "memory", "cc");					\
+	if (unlikely(__result < 0))					\
+		goto label;						\
+	if (unlikely(!__result))					\
+		*_old = __old;						\
+	likely(__result);					})
+#endif // CONFIG_X86_32
+#endif // CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT
+
 /* FIXME: this hack is definitely wrong -AK */
 struct __large_struct { unsigned long buf[100]; };
 #define __m(x) (*(struct __large_struct __user *)(x))
@@ -734,6 +819,51 @@
 	if (unlikely(__gu_err)) goto err_label;					\
 } while (0)
 
+extern void __try_cmpxchg_user_wrong_size(void);
+
+#ifndef CONFIG_X86_32
+#define __try_cmpxchg64_user_asm(_ptr, _oldp, _nval, _label)		\
+	__try_cmpxchg_user_asm("q", "r", (_ptr), (_oldp), (_nval), _label)
+#endif
+
+/*
+ * Force the pointer to u<size> to match the size expected by the asm helper.
+ * clang/LLVM compiles all cases and only discards the unused paths after
+ * processing errors, which breaks i386 if the pointer is an 8-byte value.
+ */
+#define unsafe_try_cmpxchg_user(_ptr, _oldp, _nval, _label) ({			\
+	bool __ret;								\
+	__chk_user_ptr(_ptr);							\
+	switch (sizeof(*(_ptr))) {						\
+	case 1:	__ret = __try_cmpxchg_user_asm("b", "q",			\
+					       (__force u8 *)(_ptr), (_oldp),	\
+					       (_nval), _label);		\
+		break;								\
+	case 2:	__ret = __try_cmpxchg_user_asm("w", "r",			\
+					       (__force u16 *)(_ptr), (_oldp),	\
+					       (_nval), _label);		\
+		break;								\
+	case 4:	__ret = __try_cmpxchg_user_asm("l", "r",			\
+					       (__force u32 *)(_ptr), (_oldp),	\
+					       (_nval), _label);		\
+		break;								\
+	case 8:	__ret = __try_cmpxchg64_user_asm((__force u64 *)(_ptr), (_oldp),\
+						 (_nval), _label);		\
+		break;								\
+	default: __try_cmpxchg_user_wrong_size();				\
+	}									\
+	__ret;						})
+
+/* "Returns" 0 on success, 1 on failure, -EFAULT if the access faults. */
+#define __try_cmpxchg_user(_ptr, _oldp, _nval, _label)	({		\
+	int __ret = -EFAULT;						\
+	__uaccess_begin_nospec();					\
+	__ret = !unsafe_try_cmpxchg_user(_ptr, _oldp, _nval, _label);	\
+_label:									\
+	__uaccess_end();						\
+	__ret;								\
+							})
+
 /*
  * We want the unsafe accessors to always be inlined and use
  * the error labels - thus the macro games.
--- linux-ein-5.4.0.orig/arch/x86/include/asm/uaccess_32.h
+++ linux-ein-5.4.0/arch/x86/include/asm/uaccess_32.h
@@ -23,33 +23,6 @@
 static __always_inline unsigned long
 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	if (__builtin_constant_p(n)) {
-		unsigned long ret;
-
-		switch (n) {
-		case 1:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u8 *)to, from, ret,
-					      "b", "b", "=q", 1);
-			__uaccess_end();
-			return ret;
-		case 2:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u16 *)to, from, ret,
-					      "w", "w", "=r", 2);
-			__uaccess_end();
-			return ret;
-		case 4:
-			ret = 0;
-			__uaccess_begin_nospec();
-			__get_user_asm_nozero(*(u32 *)to, from, ret,
-					      "l", "k", "=r", 4);
-			__uaccess_end();
-			return ret;
-		}
-	}
 	return __copy_user_ll(to, (__force const void *)from, n);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/uaccess_64.h
+++ linux-ein-5.4.0/arch/x86/include/asm/uaccess_64.h
@@ -65,117 +65,13 @@
 static __always_inline __must_check unsigned long
 raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
 {
-	int ret = 0;
-
-	if (!__builtin_constant_p(size))
-		return copy_user_generic(dst, (__force void *)src, size);
-	switch (size) {
-	case 1:
-		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u8 *)dst, (u8 __user *)src,
-			      ret, "b", "b", "=q", 1);
-		__uaccess_end();
-		return ret;
-	case 2:
-		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src,
-			      ret, "w", "w", "=r", 2);
-		__uaccess_end();
-		return ret;
-	case 4:
-		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u32 *)dst, (u32 __user *)src,
-			      ret, "l", "k", "=r", 4);
-		__uaccess_end();
-		return ret;
-	case 8:
-		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
-			      ret, "q", "", "=r", 8);
-		__uaccess_end();
-		return ret;
-	case 10:
-		__uaccess_begin_nospec();
-		__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
-			       ret, "q", "", "=r", 10);
-		if (likely(!ret))
-			__get_user_asm_nozero(*(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_nozero(*(u64 *)dst, (u64 __user *)src,
-			       ret, "q", "", "=r", 16);
-		if (likely(!ret))
-			__get_user_asm_nozero(*(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);
-	}
+	return copy_user_generic(dst, (__force void *)src, size);
 }
 
 static __always_inline __must_check unsigned long
 raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
 {
-	int ret = 0;
-
-	if (!__builtin_constant_p(size))
-		return copy_user_generic((__force void *)dst, src, size);
-	switch (size) {
-	case 1:
-		__uaccess_begin();
-		__put_user_asm(*(u8 *)src, (u8 __user *)dst,
-			      ret, "b", "b", "iq", 1);
-		__uaccess_end();
-		return ret;
-	case 2:
-		__uaccess_begin();
-		__put_user_asm(*(u16 *)src, (u16 __user *)dst,
-			      ret, "w", "w", "ir", 2);
-		__uaccess_end();
-		return ret;
-	case 4:
-		__uaccess_begin();
-		__put_user_asm(*(u32 *)src, (u32 __user *)dst,
-			      ret, "l", "k", "ir", 4);
-		__uaccess_end();
-		return ret;
-	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 (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 (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);
-	}
+	return copy_user_generic((__force void *)dst, src, size);
 }
 
 static __always_inline __must_check
--- linux-ein-5.4.0.orig/arch/x86/include/asm/unwind.h
+++ linux-ein-5.4.0/arch/x86/include/asm/unwind.h
@@ -19,7 +19,7 @@
 #if defined(CONFIG_UNWINDER_ORC)
 	bool signal, full_regs;
 	unsigned long sp, bp, ip;
-	struct pt_regs *regs;
+	struct pt_regs *regs, *prev_regs;
 #elif defined(CONFIG_UNWINDER_FRAME_POINTER)
 	bool got_irq;
 	unsigned long *bp, *orig_sp, ip;
--- linux-ein-5.4.0.orig/arch/x86/include/asm/virtext.h
+++ linux-ein-5.4.0/arch/x86/include/asm/virtext.h
@@ -30,15 +30,22 @@
 }
 
 
-/** Disable VMX on the current CPU
+/**
+ * cpu_vmxoff() - Disable VMX on the current CPU
  *
- * vmxoff causes a undefined-opcode exception if vmxon was not run
- * on the CPU previously. Only call this function if you know VMX
- * is enabled.
+ * Disable VMX and clear CR4.VMXE (even if VMXOFF faults)
+ *
+ * Note, VMXOFF causes a #UD if the CPU is !post-VMXON, but it's impossible to
+ * atomically track post-VMXON state, e.g. this may be called in NMI context.
+ * Eat all faults as all other faults on VMXOFF faults are mode related, i.e.
+ * faults are guaranteed to be due to the !post-VMXON check unless the CPU is
+ * magically in RM, VM86, compat mode, or at CPL>0.
  */
 static inline void cpu_vmxoff(void)
 {
-	asm volatile ("vmxoff");
+	asm_volatile_goto("1: vmxoff\n\t"
+			  _ASM_EXTABLE(1b, %l[fault]) :::: fault);
+fault:
 	cr4_clear_bits(X86_CR4_VMXE);
 }
 
@@ -88,12 +95,6 @@
 		return 0;
 	}
 
-	if (boot_cpu_data.extended_cpuid_level < SVM_CPUID_FUNC) {
-		if (msg)
-			*msg = "can't execute cpuid_8000000a";
-		return 0;
-	}
-
 	if (!boot_cpu_has(X86_FEATURE_SVM)) {
 		if (msg)
 			*msg = "svm not available";
@@ -113,7 +114,21 @@
 
 	wrmsrl(MSR_VM_HSAVE_PA, 0);
 	rdmsrl(MSR_EFER, efer);
-	wrmsrl(MSR_EFER, efer & ~EFER_SVME);
+	if (efer & EFER_SVME) {
+		/*
+		 * Force GIF=1 prior to disabling SVM to ensure INIT and NMI
+		 * aren't blocked, e.g. if a fatal error occurred between CLGI
+		 * and STGI.  Note, STGI may #UD if SVM is disabled from NMI
+		 * context between reading EFER and executing STGI.  In that
+		 * case, GIF must already be set, otherwise the NMI would have
+		 * been blocked, so just eat the fault.
+		 */
+		asm_volatile_goto("1: stgi\n\t"
+				  _ASM_EXTABLE(1b, %l[fault])
+				  ::: "memory" : fault);
+fault:
+		wrmsrl(MSR_EFER, efer & ~EFER_SVME);
+	}
 }
 
 /** Makes sure SVM is disabled, if it is supported on the CPU
--- linux-ein-5.4.0.orig/arch/x86/include/asm/vmx.h
+++ linux-ein-5.4.0/arch/x86/include/asm/vmx.h
@@ -19,8 +19,8 @@
 /*
  * Definitions of Primary Processor-Based VM-Execution Controls.
  */
-#define CPU_BASED_VIRTUAL_INTR_PENDING          0x00000004
-#define CPU_BASED_USE_TSC_OFFSETING             0x00000008
+#define CPU_BASED_INTR_WINDOW_EXITING           0x00000004
+#define CPU_BASED_USE_TSC_OFFSETTING            0x00000008
 #define CPU_BASED_HLT_EXITING                   0x00000080
 #define CPU_BASED_INVLPG_EXITING                0x00000200
 #define CPU_BASED_MWAIT_EXITING                 0x00000400
@@ -31,7 +31,7 @@
 #define CPU_BASED_CR8_LOAD_EXITING              0x00080000
 #define CPU_BASED_CR8_STORE_EXITING             0x00100000
 #define CPU_BASED_TPR_SHADOW                    0x00200000
-#define CPU_BASED_VIRTUAL_NMI_PENDING		0x00400000
+#define CPU_BASED_NMI_WINDOW_EXITING		0x00400000
 #define CPU_BASED_MOV_DR_EXITING                0x00800000
 #define CPU_BASED_UNCOND_IO_EXITING             0x01000000
 #define CPU_BASED_USE_IO_BITMAPS                0x02000000
--- linux-ein-5.4.0.orig/arch/x86/include/asm/x86_init.h
+++ linux-ein-5.4.0/arch/x86/include/asm/x86_init.h
@@ -51,12 +51,14 @@
  *				are set up.
  * @intr_init:			interrupt init code
  * @trap_init:			platform specific trap setup
+ * @intr_mode_select:		interrupt delivery mode selection
  * @intr_mode_init:		interrupt delivery mode setup
  */
 struct x86_init_irqs {
 	void (*pre_vector_init)(void);
 	void (*intr_init)(void);
 	void (*trap_init)(void);
+	void (*intr_mode_select)(void);
 	void (*intr_mode_init)(void);
 };
 
--- linux-ein-5.4.0.orig/arch/x86/include/asm/xen/interface.h
+++ linux-ein-5.4.0/arch/x86/include/asm/xen/interface.h
@@ -379,12 +379,9 @@
  * Prefix forces emulation of some non-trapping instructions.
  * Currently only CPUID.
  */
-#ifdef __ASSEMBLY__
-#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
-#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
-#else
-#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
-#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
-#endif
+#include <asm/emulate_prefix.h>
+
+#define XEN_EMULATE_PREFIX __ASM_FORM(.byte __XEN_EMULATE_PREFIX ;)
+#define XEN_CPUID          XEN_EMULATE_PREFIX __ASM_FORM(cpuid)
 
 #endif /* _ASM_X86_XEN_INTERFACE_H */
--- linux-ein-5.4.0.orig/arch/x86/include/uapi/asm/unistd.h
+++ linux-ein-5.4.0/arch/x86/include/uapi/asm/unistd.h
@@ -2,8 +2,15 @@
 #ifndef _UAPI_ASM_X86_UNISTD_H
 #define _UAPI_ASM_X86_UNISTD_H
 
-/* x32 syscall flag bit */
-#define __X32_SYSCALL_BIT	0x40000000UL
+/*
+ * x32 syscall flag bit.  Some user programs expect syscall NR macros
+ * and __X32_SYSCALL_BIT to have type int, even though syscall numbers
+ * are, for practical purposes, unsigned long.
+ *
+ * Fortunately, expressions like (nr & ~__X32_SYSCALL_BIT) do the right
+ * thing regardless.
+ */
+#define __X32_SYSCALL_BIT	0x40000000
 
 #ifndef __KERNEL__
 # ifdef __i386__
--- linux-ein-5.4.0.orig/arch/x86/include/uapi/asm/vmx.h
+++ linux-ein-5.4.0/arch/x86/include/uapi/asm/vmx.h
@@ -33,7 +33,7 @@
 #define EXIT_REASON_TRIPLE_FAULT        2
 #define EXIT_REASON_INIT_SIGNAL			3
 
-#define EXIT_REASON_PENDING_INTERRUPT   7
+#define EXIT_REASON_INTERRUPT_WINDOW    7
 #define EXIT_REASON_NMI_WINDOW          8
 #define EXIT_REASON_TASK_SWITCH         9
 #define EXIT_REASON_CPUID               10
@@ -94,7 +94,7 @@
 	{ EXIT_REASON_EXTERNAL_INTERRUPT,    "EXTERNAL_INTERRUPT" }, \
 	{ EXIT_REASON_TRIPLE_FAULT,          "TRIPLE_FAULT" }, \
 	{ EXIT_REASON_INIT_SIGNAL,           "INIT_SIGNAL" }, \
-	{ EXIT_REASON_PENDING_INTERRUPT,     "PENDING_INTERRUPT" }, \
+	{ EXIT_REASON_INTERRUPT_WINDOW,      "INTERRUPT_WINDOW" }, \
 	{ EXIT_REASON_NMI_WINDOW,            "NMI_WINDOW" }, \
 	{ EXIT_REASON_TASK_SWITCH,           "TASK_SWITCH" }, \
 	{ EXIT_REASON_CPUID,                 "CPUID" }, \
--- linux-ein-5.4.0.orig/arch/x86/kernel/acpi/boot.c
+++ linux-ein-5.4.0/arch/x86/kernel/acpi/boot.c
@@ -140,6 +140,9 @@
 		       madt->address);
 	}
 
+	if (madt->flags & ACPI_MADT_PCAT_COMPAT)
+		legacy_pic_pcat_compat();
+
 	default_acpi_madt_oem_check(madt->header.oem_id,
 				    madt->header.oem_table_id);
 
@@ -1339,6 +1342,17 @@
 	return 0;
 }
 
+static int __init disable_acpi_xsdt(const struct dmi_system_id *d)
+{
+	if (!acpi_force) {
+		pr_notice("%s detected: force use of acpi=rsdt\n", d->ident);
+		acpi_gbl_do_not_use_xsdt = TRUE;
+	} else {
+		pr_notice("Warning: DMI blacklist says broken, but acpi XSDT forced\n");
+	}
+	return 0;
+}
+
 static int __init dmi_disable_acpi(const struct dmi_system_id *d)
 {
 	if (!acpi_force) {
@@ -1463,6 +1477,19 @@
 		     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
 		     },
 	 },
+	/*
+	 * Boxes that need ACPI XSDT use disabled due to corrupted tables
+	 */
+	{
+	 .callback = disable_acpi_xsdt,
+	 .ident = "Advantech DAC-BJ01",
+	 .matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Bearlake CRB Board"),
+		     DMI_MATCH(DMI_BIOS_VERSION, "V1.12"),
+		     DMI_MATCH(DMI_BIOS_DATE, "02/01/2011"),
+		     },
+	 },
 	{}
 };
 
@@ -1553,10 +1580,18 @@
 	/*
 	 * Initialize the ACPI boot-time table parser.
 	 */
-	if (acpi_table_init()) {
+	if (acpi_locate_initial_tables())
 		disable_acpi();
-		return;
-	}
+	else
+		acpi_reserve_initial_tables();
+}
+
+int __init early_acpi_boot_init(void)
+{
+	if (acpi_disabled)
+		return 1;
+
+	acpi_table_init_complete();
 
 	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
 
@@ -1569,18 +1604,9 @@
 		} else {
 			printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
 			disable_acpi();
-			return;
+			return 1;
 		}
 	}
-}
-
-int __init early_acpi_boot_init(void)
-{
-	/*
-	 * If acpi_disabled, bail out
-	 */
-	if (acpi_disabled)
-		return 1;
 
 	/*
 	 * Process the Multiple APIC Description Table (MADT), if present
@@ -1740,7 +1766,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-ein-5.4.0.orig/arch/x86/kernel/acpi/cstate.c
+++ linux-ein-5.4.0/arch/x86/kernel/acpi/cstate.c
@@ -161,7 +161,8 @@
 
 	/* Make sure we are running on right CPU */
 
-	retval = work_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx);
+	retval = call_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx,
+			     false);
 	if (retval == 0) {
 		/* Use the hint in CST */
 		percpu_entry->states[cx->index].eax = cx->address;
--- linux-ein-5.4.0.orig/arch/x86/kernel/acpi/wakeup_32.S
+++ linux-ein-5.4.0/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,14 +3,14 @@
 #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
 
 	.code32
 	ALIGN
 
-ENTRY(wakeup_pmode_return)
-wakeup_pmode_return:
+SYM_CODE_START(wakeup_pmode_return)
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss
 	movw	%ax, %fs
@@ -38,7 +38,9 @@
 
 	# jump to place where we left off
 	movl	saved_eip, %eax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%eax
+SYM_CODE_END(wakeup_pmode_return)
 
 bogus_magic:
 	jmp	bogus_magic
@@ -72,7 +74,7 @@
 	popfl
 	ret
 
-ENTRY(do_suspend_lowlevel)
+SYM_CODE_START(do_suspend_lowlevel)
 	call	save_processor_state
 	call	save_registers
 	pushl	$3
@@ -87,6 +89,7 @@
 	call	restore_registers
 	call	restore_processor_state
 	ret
+SYM_CODE_END(do_suspend_lowlevel)
 
 .data
 ALIGN
--- linux-ein-5.4.0.orig/arch/x86/kernel/acpi/wakeup_64.S
+++ linux-ein-5.4.0/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,6 +7,7 @@
 #include <asm/msr.h>
 #include <asm/asm-offsets.h>
 #include <asm/frame.h>
+#include <asm/nospec-branch.h>
 
 # Copyright 2003 Pavel Machek <pavel@suse.cz
 
@@ -39,6 +40,7 @@
 	movq	saved_rbp, %rbp
 
 	movq	saved_rip, %rax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%rax
 ENDPROC(wakeup_long64)
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/alternative.c
+++ linux-ein-5.4.0/arch/x86/kernel/alternative.c
@@ -374,6 +374,17 @@
 	u8 insn_buff[MAX_PATCH_LEN];
 
 	DPRINTK("alt table %px, -> %px", start, end);
+
+	/*
+	 * In the case CONFIG_X86_5LEVEL=y, KASAN_SHADOW_START is defined using
+	 * cpu_feature_enabled(X86_FEATURE_LA57) and is therefore patched here.
+	 * During the process, KASAN becomes confused seeing partial LA57
+	 * conversion and triggers a false-positive out-of-bound report.
+	 *
+	 * Disable KASAN until the patching is complete.
+	 */
+	kasan_disable_current();
+
 	/*
 	 * The scan order should be from start to end. A later scanned
 	 * alternative code can overwrite previously scanned alternative code.
@@ -434,6 +445,8 @@
 
 		text_poke_early(instr, insn_buff, insn_buff_sz);
 	}
+
+	kasan_enable_current();
 }
 
 #ifdef CONFIG_SMP
@@ -772,8 +785,8 @@
 	} else {
 		local_irq_save(flags);
 		memcpy(addr, opcode, len);
-		local_irq_restore(flags);
 		sync_core();
+		local_irq_restore(flags);
 
 		/*
 		 * Could also do a CLFLUSH here to speed up CPU recovery; but
--- linux-ein-5.4.0.orig/arch/x86/kernel/amd_nb.c
+++ linux-ein-5.4.0/arch/x86/kernel/amd_nb.c
@@ -18,10 +18,13 @@
 #define PCI_DEVICE_ID_AMD_17H_ROOT	0x1450
 #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT	0x15d0
 #define PCI_DEVICE_ID_AMD_17H_M30H_ROOT	0x1480
+#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT	0x1630
 #define PCI_DEVICE_ID_AMD_17H_DF_F4	0x1464
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
+#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F4 0x144c
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
+#define PCI_DEVICE_ID_AMD_19H_DF_F4	0x1654
 
 /* Protect the PCI config register pairs used for SMN and DF indirect access. */
 static DEFINE_MUTEX(smn_mutex);
@@ -32,6 +35,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) },
 	{}
 };
 
@@ -50,8 +54,10 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
 	{}
 };
 EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
@@ -65,7 +71,9 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
 	{}
 };
--- linux-ein-5.4.0.orig/arch/x86/kernel/aperture_64.c
+++ linux-ein-5.4.0/arch/x86/kernel/aperture_64.c
@@ -126,32 +126,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)
 {
@@ -240,8 +214,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-ein-5.4.0.orig/arch/x86/kernel/apic/apic.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/apic.c
@@ -42,6 +42,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>
@@ -167,7 +168,7 @@
 {
 	apic_calibrate_pmtmr = 1;
 	notsc_setup(NULL);
-	return 0;
+	return 1;
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 #endif
@@ -352,8 +353,6 @@
 		 * According to Intel, MFENCE can do the serialization here.
 		 */
 		asm volatile("mfence" : : : "memory");
-
-		printk_once(KERN_DEBUG "TSC deadline timer enabled\n");
 		return;
 	}
 
@@ -411,10 +410,9 @@
 		if (vector && !eilvt_entry_is_changeable(vector, new))
 			/* may not change if vectors are different */
 			return rsvd;
-		rsvd = atomic_cmpxchg(&eilvt_offsets[offset], rsvd, new);
-	} while (rsvd != new);
+	} while (!atomic_try_cmpxchg(&eilvt_offsets[offset], &rsvd, new));
 
-	rsvd &= ~APIC_EILVT_MASKED;
+	rsvd = new & ~APIC_EILVT_MASKED;
 	if (rsvd && rsvd != vector)
 		pr_info("LVT offset %d assigned for vector 0x%02x\n",
 			offset, rsvd);
@@ -474,6 +472,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;
@@ -552,7 +553,7 @@
 #define DEADLINE_MODEL_MATCH_REV(model, rev)	\
 	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)rev }
 
-static u32 hsx_deadline_rev(void)
+static __init u32 hsx_deadline_rev(void)
 {
 	switch (boot_cpu_data.x86_stepping) {
 	case 0x02: return 0x3a; /* EP */
@@ -562,7 +563,7 @@
 	return ~0U;
 }
 
-static u32 bdx_deadline_rev(void)
+static __init u32 bdx_deadline_rev(void)
 {
 	switch (boot_cpu_data.x86_stepping) {
 	case 0x02: return 0x00000011;
@@ -574,7 +575,7 @@
 	return ~0U;
 }
 
-static u32 skx_deadline_rev(void)
+static __init u32 skx_deadline_rev(void)
 {
 	switch (boot_cpu_data.x86_stepping) {
 	case 0x03: return 0x01000136;
@@ -587,7 +588,7 @@
 	return ~0U;
 }
 
-static const struct x86_cpu_id deadline_match[] = {
+static const struct x86_cpu_id deadline_match[] __initconst = {
 	DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X,	hsx_deadline_rev),
 	DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X,	0x0b000020),
 	DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_D,	bdx_deadline_rev),
@@ -609,18 +610,19 @@
 	{},
 };
 
-static void apic_check_deadline_errata(void)
+static __init bool apic_validate_deadline_timer(void)
 {
 	const struct x86_cpu_id *m;
 	u32 rev;
 
-	if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER) ||
-	    boot_cpu_has(X86_FEATURE_HYPERVISOR))
-		return;
+	if (!boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
+		return false;
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		return true;
 
 	m = x86_match_cpu(deadline_match);
 	if (!m)
-		return;
+		return true;
 
 	/*
 	 * Function pointers will have the MSB set due to address layout,
@@ -632,11 +634,12 @@
 		rev = (u32)m->driver_data;
 
 	if (boot_cpu_data.microcode >= rev)
-		return;
+		return true;
 
 	setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
 	pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; "
 	       "please update microcode to version: 0x%x (or later)\n", rev);
+	return false;
 }
 
 /*
@@ -830,8 +833,17 @@
 	if (!tsc_khz || !cpu_khz)
 		return true;
 
-	/* Is there an APIC at all? */
-	if (!boot_cpu_has(X86_FEATURE_APIC))
+	/* Is there an APIC at all or is it disabled? */
+	if (!boot_cpu_has(X86_FEATURE_APIC) || disable_apic)
+		return true;
+
+	/*
+	 * If interrupt delivery mode is legacy PIC or virtual wire without
+	 * configuration, the local APIC timer wont be set up. Make sure
+	 * that the PIT is initialized.
+	 */
+	if (apic_intr_mode == APIC_PIC ||
+	    apic_intr_mode == APIC_VIRTUAL_WIRE_NO_CONFIG)
 		return true;
 
 	/* Virt guests may lack ARAT, but still have DEADLINE */
@@ -1322,7 +1334,7 @@
 
 enum apic_intr_mode_id apic_intr_mode __ro_after_init;
 
-static int __init apic_intr_mode_select(void)
+static int __init __apic_intr_mode_select(void)
 {
 	/* Check kernel option */
 	if (disable_apic) {
@@ -1384,6 +1396,12 @@
 	return APIC_SYMMETRIC_IO;
 }
 
+/* Select the interrupt delivery mode for the BSP */
+void __init apic_intr_mode_select(void)
+{
+	apic_intr_mode = __apic_intr_mode_select();
+}
+
 /*
  * An initial setup of the virtual wire mode.
  */
@@ -1440,8 +1458,6 @@
 {
 	bool upmode = IS_ENABLED(CONFIG_UP_LATE_INIT);
 
-	apic_intr_mode = apic_intr_mode_select();
-
 	switch (apic_intr_mode) {
 	case APIC_PIC:
 		pr_info("APIC: Keep in PIC mode(8259)\n");
@@ -1873,20 +1889,22 @@
 		return;
 
 	if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
-		/* IR is required if there is APIC ID > 255 even when running
-		 * under KVM
+		/*
+		 * Using X2APIC without IR is not architecturally supported
+		 * on bare metal but may be supported in guests.
 		 */
-		if (max_physical_apicid > 255 ||
-		    !x86_init.hyper.x2apic_available()) {
+		if (!x86_init.hyper.x2apic_available()) {
 			pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
 			x2apic_disable();
 			return;
 		}
 
 		/*
-		 * without IR all CPUs can be addressed by IOAPIC/MSI
-		 * only in physical mode
+		 * Without IR, all CPUs can be addressed by IOAPIC/MSI only
+		 * in physical mode, and CPUs with an APIC ID that cannnot
+		 * be addressed must not be brought online.
 		 */
+		x2apic_set_max_apicid(255);
 		x2apic_phys = 1;
 	}
 	x2apic_enable();
@@ -2085,7 +2103,8 @@
 {
 	unsigned int new_apicid;
 
-	apic_check_deadline_errata();
+	if (apic_validate_deadline_timer())
+		pr_info("TSC deadline timer available\n");
 
 	if (x2apic_mode) {
 		boot_cpu_physical_apicid = read_apic_id();
@@ -2334,6 +2353,11 @@
 	[0 ... NR_CPUS - 1] = -1,
 };
 
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+	return phys_id == cpuid_to_apicid[cpu];
+}
+
 #ifdef CONFIG_SMP
 /**
  * apic_id_is_primary_thread - Check whether APIC ID belongs to a primary thread
@@ -2554,6 +2578,7 @@
 	end_local_APIC_setup();
 	irq_remap_enable_fault_handling();
 	setup_IO_APIC();
+	lapic_update_legacy_vectors();
 }
 
 #ifdef CONFIG_UP_LATE_INIT
--- linux-ein-5.4.0.orig/arch/x86/kernel/apic/io_apic.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/io_apic.c
@@ -1046,6 +1046,16 @@
 	if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {
 		irq = mp_irqs[idx].srcbusirq;
 		legacy = mp_is_legacy_irq(irq);
+		/*
+		 * IRQ2 is unusable for historical reasons on systems which
+		 * have a legacy PIC. See the comment vs. IRQ2 further down.
+		 *
+		 * If this gets removed at some point then the related code
+		 * in lapic_assign_system_vectors() needs to be adjusted as
+		 * well.
+		 */
+		if (legacy && irq == PIC_CASCADE_IR)
+			return -EINVAL;
 	}
 
 	mutex_lock(&ioapic_mutex);
@@ -1727,9 +1737,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;
@@ -1766,7 +1777,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
@@ -1948,7 +1961,8 @@
 	.irq_set_affinity	= ioapic_set_affinity,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_get_irqchip_state	= ioapic_irq_get_chip_state,
-	.flags			= IRQCHIP_SKIP_SET_WAKE,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 static struct irq_chip ioapic_ir_chip __read_mostly = {
@@ -1961,7 +1975,8 @@
 	.irq_set_affinity	= ioapic_set_affinity,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_get_irqchip_state	= ioapic_irq_get_chip_state,
-	.flags			= IRQCHIP_SKIP_SET_WAKE,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -2253,6 +2268,7 @@
 	legacy_pic->init(0);
 	legacy_pic->make_irq(0);
 	apic_write(APIC_LVT0, APIC_DM_EXTINT);
+	legacy_pic->unmask(0);
 
 	unlock_ExtINT_logic();
 
@@ -2326,12 +2342,12 @@
 	ip->irqdomain = irq_domain_create_linear(fn, hwirqs, cfg->ops,
 						 (void *)(long)ioapic);
 
-	/* Release fw handle if it was allocated above */
-	if (!cfg->dev)
-		irq_domain_free_fwnode(fn);
-
-	if (!ip->irqdomain)
+	if (!ip->irqdomain) {
+		/* Release fw handle if it was allocated above */
+		if (!cfg->dev)
+			irq_domain_free_fwnode(fn);
 		return -ENOMEM;
+	}
 
 	ip->irqdomain->parent = parent;
 
@@ -2345,8 +2361,13 @@
 
 static void ioapic_destroy_irqdomain(int idx)
 {
+	struct ioapic_domain_cfg *cfg = &ioapics[idx].irqdomain_cfg;
+	struct fwnode_handle *fn = ioapics[idx].irqdomain->fwnode;
+
 	if (ioapics[idx].irqdomain) {
 		irq_domain_remove(ioapics[idx].irqdomain);
+		if (!cfg->dev)
+			irq_domain_free_fwnode(fn);
 		ioapics[idx].irqdomain = NULL;
 	}
 }
@@ -2434,17 +2455,21 @@
 
 unsigned int arch_dynirq_lower_bound(unsigned int from)
 {
+	unsigned int ret;
+
 	/*
 	 * dmar_alloc_hwirq() may be called before setup_IO_APIC(), so use
 	 * gsi_top if ioapic_dynirq_base hasn't been initialized yet.
 	 */
-	if (!ioapic_initialized)
-		return gsi_top;
+	ret = ioapic_dynirq_base ? : gsi_top;
+
 	/*
-	 * For DT enabled machines ioapic_dynirq_base is irrelevant and not
-	 * updated. So simply return @from if ioapic_dynirq_base == 0.
+	 * For DT enabled machines ioapic_dynirq_base is irrelevant and
+	 * always 0. gsi_top can be 0 if there is no IO/APIC registered.
+	 * 0 is an invalid interrupt number for dynamic allocations. Return
+	 * @from instead.
 	 */
-	return ioapic_dynirq_base ? : from;
+	return ret ? : from;
 }
 
 #ifdef CONFIG_X86_32
--- linux-ein-5.4.0.orig/arch/x86/kernel/apic/msi.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/msi.c
@@ -23,10 +23,8 @@
 
 static struct irq_domain *msi_default_domain;
 
-static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg)
 {
-	struct irq_cfg *cfg = irqd_cfg(data);
-
 	msg->address_hi = MSI_ADDR_BASE_HI;
 
 	if (x2apic_enabled())
@@ -47,6 +45,129 @@
 		MSI_DATA_VECTOR(cfg->vector);
 }
 
+static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	__irq_msi_compose_msg(irqd_cfg(data), msg);
+}
+
+static void irq_msi_update_msg(struct irq_data *irqd, struct irq_cfg *cfg)
+{
+	struct msi_msg msg[2] = { [1] = { }, };
+
+	__irq_msi_compose_msg(cfg, msg);
+	irq_data_get_irq_chip(irqd)->irq_write_msi_msg(irqd, msg);
+}
+
+static int
+msi_set_affinity(struct irq_data *irqd, const struct cpumask *mask, bool force)
+{
+	struct irq_cfg old_cfg, *cfg = irqd_cfg(irqd);
+	struct irq_data *parent = irqd->parent_data;
+	unsigned int cpu;
+	int ret;
+
+	/* Save the current configuration */
+	cpu = cpumask_first(irq_data_get_effective_affinity_mask(irqd));
+	old_cfg = *cfg;
+
+	/* Allocate a new target vector */
+	ret = parent->chip->irq_set_affinity(parent, mask, force);
+	if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
+		return ret;
+
+	/*
+	 * For non-maskable and non-remapped MSI interrupts the migration
+	 * to a different destination CPU and a different vector has to be
+	 * done careful to handle the possible stray interrupt which can be
+	 * caused by the non-atomic update of the address/data pair.
+	 *
+	 * Direct update is possible when:
+	 * - The MSI is maskable (remapped MSI does not use this code path)).
+	 *   The quirk bit is not set in this case.
+	 * - The new vector is the same as the old vector
+	 * - The old vector is MANAGED_IRQ_SHUTDOWN_VECTOR (interrupt starts up)
+	 * - The interrupt is not yet started up
+	 * - The new destination CPU is the same as the old destination CPU
+	 */
+	if (!irqd_msi_nomask_quirk(irqd) ||
+	    cfg->vector == old_cfg.vector ||
+	    old_cfg.vector == MANAGED_IRQ_SHUTDOWN_VECTOR ||
+	    !irqd_is_started(irqd) ||
+	    cfg->dest_apicid == old_cfg.dest_apicid) {
+		irq_msi_update_msg(irqd, cfg);
+		return ret;
+	}
+
+	/*
+	 * Paranoia: Validate that the interrupt target is the local
+	 * CPU.
+	 */
+	if (WARN_ON_ONCE(cpu != smp_processor_id())) {
+		irq_msi_update_msg(irqd, cfg);
+		return ret;
+	}
+
+	/*
+	 * Redirect the interrupt to the new vector on the current CPU
+	 * first. This might cause a spurious interrupt on this vector if
+	 * the device raises an interrupt right between this update and the
+	 * update to the final destination CPU.
+	 *
+	 * If the vector is in use then the installed device handler will
+	 * denote it as spurious which is no harm as this is a rare event
+	 * and interrupt handlers have to cope with spurious interrupts
+	 * anyway. If the vector is unused, then it is marked so it won't
+	 * trigger the 'No irq handler for vector' warning in do_IRQ().
+	 *
+	 * This requires to hold vector lock to prevent concurrent updates to
+	 * the affected vector.
+	 */
+	lock_vector_lock();
+
+	/*
+	 * Mark the new target vector on the local CPU if it is currently
+	 * unused. Reuse the VECTOR_RETRIGGERED state which is also used in
+	 * the CPU hotplug path for a similar purpose. This cannot be
+	 * undone here as the current CPU has interrupts disabled and
+	 * cannot handle the interrupt before the whole set_affinity()
+	 * section is done. In the CPU unplug case, the current CPU is
+	 * about to vanish and will not handle any interrupts anymore. The
+	 * vector is cleaned up when the CPU comes online again.
+	 */
+	if (IS_ERR_OR_NULL(this_cpu_read(vector_irq[cfg->vector])))
+		this_cpu_write(vector_irq[cfg->vector], VECTOR_RETRIGGERED);
+
+	/* Redirect it to the new vector on the local CPU temporarily */
+	old_cfg.vector = cfg->vector;
+	irq_msi_update_msg(irqd, &old_cfg);
+
+	/* Now transition it to the target CPU */
+	irq_msi_update_msg(irqd, cfg);
+
+	/*
+	 * All interrupts after this point are now targeted at the new
+	 * vector/CPU.
+	 *
+	 * Drop vector lock before testing whether the temporary assignment
+	 * to the local CPU was hit by an interrupt raised in the device,
+	 * because the retrigger function acquires vector lock again.
+	 */
+	unlock_vector_lock();
+
+	/*
+	 * Check whether the transition raced with a device interrupt and
+	 * is pending in the local APICs IRR. It is safe to do this outside
+	 * of vector lock as the irq_desc::lock of this interrupt is still
+	 * held and interrupts are disabled: The check is not accessing the
+	 * underlying vector store. It's just checking the local APIC's
+	 * IRR.
+	 */
+	if (lapic_vector_set_in_irr(cfg->vector))
+		irq_data_get_irq_chip(irqd)->irq_retrigger(irqd);
+
+	return ret;
+}
+
 /*
  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
  * which implement the MSI or MSI-X Capability Structure.
@@ -58,7 +179,9 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_compose_msi_msg	= irq_msi_compose_msg,
-	.flags			= IRQCHIP_SKIP_SET_WAKE,
+	.irq_set_affinity	= msi_set_affinity,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
@@ -142,10 +265,13 @@
 		msi_default_domain =
 			pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
 						  parent);
-		irq_domain_free_fwnode(fn);
 	}
-	if (!msi_default_domain)
+	if (!msi_default_domain) {
+		irq_domain_free_fwnode(fn);
 		pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
+	} else {
+		msi_default_domain->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK;
+	}
 }
 
 #ifdef CONFIG_IRQ_REMAP
@@ -156,7 +282,8 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
-	.flags			= IRQCHIP_SKIP_SET_WAKE,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 static struct msi_domain_info pci_msi_ir_domain_info = {
@@ -178,7 +305,8 @@
 	if (!fn)
 		return NULL;
 	d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
-	irq_domain_free_fwnode(fn);
+	if (!d)
+		irq_domain_free_fwnode(fn);
 	return d;
 }
 #endif
@@ -198,7 +326,8 @@
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_compose_msi_msg	= irq_msi_compose_msg,
 	.irq_write_msi_msg	= dmar_msi_write_msg,
-	.flags			= IRQCHIP_SKIP_SET_WAKE,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info,
@@ -241,7 +370,8 @@
 	if (fn) {
 		dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info,
 						    x86_vector_domain);
-		irq_domain_free_fwnode(fn);
+		if (!dmar_domain)
+			irq_domain_free_fwnode(fn);
 	}
 out:
 	mutex_unlock(&dmar_lock);
@@ -295,7 +425,7 @@
 	.irq_retrigger = irq_chip_retrigger_hierarchy,
 	.irq_compose_msi_msg = irq_msi_compose_msg,
 	.irq_write_msi_msg = hpet_msi_write_msg,
-	.flags = IRQCHIP_SKIP_SET_WAKE,
+	.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
 static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info,
@@ -366,7 +496,10 @@
 	}
 
 	d = msi_create_irq_domain(fn, domain_info, parent);
-	irq_domain_free_fwnode(fn);
+	if (!d) {
+		irq_domain_free_fwnode(fn);
+		kfree(domain_info);
+	}
 	return d;
 }
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/apic/vector.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/vector.c
@@ -272,20 +272,24 @@
 	const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
 	int node = irq_data_get_node(irqd);
 
-	if (node == NUMA_NO_NODE)
-		goto all;
-	/* Try the intersection of @affmsk and node mask */
-	cpumask_and(vector_searchmask, cpumask_of_node(node), affmsk);
-	if (!assign_vector_locked(irqd, vector_searchmask))
-		return 0;
-	/* Try the node mask */
-	if (!assign_vector_locked(irqd, cpumask_of_node(node)))
-		return 0;
-all:
+	if (node != NUMA_NO_NODE) {
+		/* Try the intersection of @affmsk and node mask */
+		cpumask_and(vector_searchmask, cpumask_of_node(node), affmsk);
+		if (!assign_vector_locked(irqd, vector_searchmask))
+			return 0;
+	}
+
 	/* Try the full affinity mask */
 	cpumask_and(vector_searchmask, affmsk, cpu_online_mask);
 	if (!assign_vector_locked(irqd, vector_searchmask))
 		return 0;
+
+	if (node != NUMA_NO_NODE) {
+		/* Try the node mask */
+		if (!assign_vector_locked(irqd, cpumask_of_node(node)))
+			return 0;
+	}
+
 	/* Try the full online mask */
 	return assign_vector_locked(irqd, cpu_online_mask);
 }
@@ -446,12 +450,10 @@
 	trace_vector_activate(irqd->irq, apicd->is_managed,
 			      apicd->can_reserve, reserve);
 
-	/* Nothing to do for fixed assigned vectors */
-	if (!apicd->can_reserve && !apicd->is_managed)
-		return 0;
-
 	raw_spin_lock_irqsave(&vector_lock, flags);
-	if (reserve || irqd_is_managed_and_shutdown(irqd))
+	if (!apicd->can_reserve && !apicd->is_managed)
+		assign_irq_vector_any_locked(irqd);
+	else if (reserve || irqd_is_managed_and_shutdown(irqd))
 		vector_assign_managed_shutdown(irqd);
 	else if (apicd->is_managed)
 		ret = activate_managed(irqd);
@@ -556,6 +558,10 @@
 		irqd->chip_data = apicd;
 		irqd->hwirq = virq + i;
 		irqd_set_single_target(irqd);
+
+		/* Don't invoke affinity setter on deactivated interrupts */
+		irqd_set_affinity_on_activate(irqd);
+
 		/*
 		 * Legacy vectors are already assigned when the IOAPIC
 		 * takes them over. They stay on the same vector. This is
@@ -674,6 +680,26 @@
 	irq_matrix_assign_system(vector_matrix, ISA_IRQ_VECTOR(irq), replace);
 }
 
+void __init lapic_update_legacy_vectors(void)
+{
+	unsigned int i;
+
+	if (IS_ENABLED(CONFIG_X86_IO_APIC) && nr_ioapics > 0)
+		return;
+
+	/*
+	 * If the IO/APIC is disabled via config, kernel command line or
+	 * lack of enumeration then all legacy interrupts are routed
+	 * through the PIC. Make sure that they are marked as legacy
+	 * vectors. PIC_CASCADE_IRQ has already been marked in
+	 * lapic_assign_system_vectors().
+	 */
+	for (i = 0; i < nr_legacy_irqs(); i++) {
+		if (i != PIC_CASCADE_IR)
+			lapic_assign_legacy_vector(i, true);
+	}
+}
+
 void __init lapic_assign_system_vectors(void)
 {
 	unsigned int i, vector = 0;
@@ -703,7 +729,6 @@
 	x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
 						   NULL);
 	BUG_ON(x86_vector_domain == NULL);
-	irq_domain_free_fwnode(fn);
 	irq_set_default_host(x86_vector_domain);
 
 	arch_init_msi_domain(x86_vector_domain);
@@ -769,20 +794,10 @@
 static int apic_set_affinity(struct irq_data *irqd,
 			     const struct cpumask *dest, bool force)
 {
-	struct apic_chip_data *apicd = apic_chip_data(irqd);
 	int err;
 
-	/*
-	 * Core code can call here for inactive interrupts. For inactive
-	 * interrupts which use managed or reservation mode there is no
-	 * point in going through the vector assignment right now as the
-	 * activation will assign a vector which fits the destination
-	 * cpumask. Let the core code store the destination mask and be
-	 * done with it.
-	 */
-	if (!irqd_is_activated(irqd) &&
-	    (apicd->is_managed || apicd->can_reserve))
-		return IRQ_SET_MASK_OK;
+	if (WARN_ON_ONCE(!irqd_is_activated(irqd)))
+		return -EIO;
 
 	raw_spin_lock(&vector_lock);
 	cpumask_and(vector_searchmask, dest, cpu_online_mask);
--- linux-ein-5.4.0.orig/arch/x86/kernel/apic/x2apic_cluster.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/x2apic_cluster.c
@@ -29,7 +29,8 @@
 {
 	u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
 
-	x2apic_wrmsr_fence();
+	/* x2apic MSRs are special and need a special fence: */
+	weak_wrmsr_fence();
 	__x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
 }
 
@@ -41,7 +42,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);
 
 	tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
--- linux-ein-5.4.0.orig/arch/x86/kernel/apic/x2apic_phys.c
+++ linux-ein-5.4.0/arch/x86/kernel/apic/x2apic_phys.c
@@ -8,6 +8,12 @@
 int x2apic_phys;
 
 static struct apic apic_x2apic_phys;
+static u32 x2apic_max_apicid __ro_after_init;
+
+void __init x2apic_set_max_apicid(u32 apicid)
+{
+	x2apic_max_apicid = apicid;
+}
 
 static int __init set_x2apic_phys_mode(char *arg)
 {
@@ -37,7 +43,8 @@
 {
 	u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
 
-	x2apic_wrmsr_fence();
+	/* x2apic MSRs are special and need a special fence: */
+	weak_wrmsr_fence();
 	__x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
 }
 
@@ -48,7 +55,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);
 
@@ -89,7 +97,10 @@
 
 static int x2apic_phys_probe(void)
 {
-	if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
+	if (!x2apic_mode)
+		return 0;
+
+	if (x2apic_phys || x2apic_fadt_phys())
 		return 1;
 
 	return apic == &apic_x2apic_phys;
@@ -98,6 +109,9 @@
 /* Common x2apic functions, also used by x2apic_cluster */
 int x2apic_apic_id_valid(u32 apicid)
 {
+	if (x2apic_max_apicid && apicid > x2apic_max_apicid)
+		return 0;
+
 	return 1;
 }
 
@@ -116,7 +130,8 @@
 {
 	unsigned long cfg = __prepare_ICR(which, vector, 0);
 
-	x2apic_wrmsr_fence();
+	/* x2apic MSRs are special and need a special fence: */
+	weak_wrmsr_fence();
 	native_x2apic_icr_write(cfg, 0);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/apm_32.c
+++ linux-ein-5.4.0/arch/x86/kernel/apm_32.c
@@ -238,12 +238,6 @@
 #endif
 
 /*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define	APM_MINOR_DEV	134
-
-/*
  * Various options can be changed at boot time as follows:
  * (We allow underscores for compatibility with the modules code)
  *	apm=on/off			enable/disable APM
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/amd.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/amd.c
@@ -26,10 +26,6 @@
 
 #include "cpu.h"
 
-static const int amd_erratum_383[];
-static const int amd_erratum_400[];
-static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum);
-
 /*
  * nodes_per_socket: Stores the number of nodes per socket.
  * Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
@@ -37,6 +33,87 @@
  */
 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));
+
+/* #1054: Instructions Retired Performance Counter May Be Inaccurate */
+static const int amd_erratum_1054[] =
+	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 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, 0x90, 0x0, 0x91, 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 const int amd_erratum_1485[] =
+	AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x19, 0x10, 0x0, 0x1f, 0xf),
+			   AMD_MODEL_RANGE(0x19, 0x60, 0x0, 0xaf, 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 };
@@ -334,7 +411,6 @@
  */
 static void amd_get_topology(struct cpuinfo_x86 *c)
 {
-	u8 node_id;
 	int cpu = smp_processor_id();
 
 	/* get information required for multi-node processors */
@@ -344,7 +420,7 @@
 
 		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
 
-		node_id  = ecx & 0xff;
+		c->cpu_die_id  = ecx & 0xff;
 
 		if (c->x86 == 0x15)
 			c->cu_id = ebx & 0xff;
@@ -364,15 +440,15 @@
 		if (!err)
 			c->x86_coreid_bits = get_count_order(c->x86_max_cores);
 
-		cacheinfo_amd_init_llc_id(c, cpu, node_id);
+		cacheinfo_amd_init_llc_id(c, cpu);
 
 	} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
 		u64 value;
 
 		rdmsrl(MSR_FAM10H_NODE_ID, value);
-		node_id = value & 7;
+		c->cpu_die_id = value & 7;
 
-		per_cpu(cpu_llc_id, cpu) = node_id;
+		per_cpu(cpu_llc_id, cpu) = c->cpu_die_id;
 	} else
 		return;
 
@@ -397,7 +473,7 @@
 	/* Convert the initial APIC ID into the socket ID */
 	c->phys_proc_id = c->initial_apicid >> bits;
 	/* use socket ID also for last level cache */
-	per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
+	per_cpu(cpu_llc_id, cpu) = c->cpu_die_id = c->phys_proc_id;
 }
 
 u16 amd_get_nb_id(int cpu)
@@ -545,12 +621,12 @@
 		u32 ecx;
 
 		ecx = cpuid_ecx(0x8000001e);
-		nodes_per_socket = ((ecx >> 8) & 7) + 1;
+		__max_die_per_package = nodes_per_socket = ((ecx >> 8) & 7) + 1;
 	} else if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) {
 		u64 value;
 
 		rdmsrl(MSR_FAM10H_NODE_ID, value);
-		nodes_per_socket = ((value >> 3) & 7) + 1;
+		__max_die_per_package = nodes_per_socket = ((value >> 3) & 7) + 1;
 	}
 
 	if (!boot_cpu_has(X86_FEATURE_AMD_SSBD) &&
@@ -587,7 +663,7 @@
 	 *	      If BIOS has not enabled SME then don't advertise the
 	 *	      SME feature (set in scattered.c).
 	 *   For SEV: If BIOS has not enabled SEV then don't advertise the
-	 *            SEV feature (set in scattered.c).
+	 *            SEV and SEV_ES feature (set in scattered.c).
 	 *
 	 *   In all cases, since support for SME and SEV requires long mode,
 	 *   don't advertise the feature under CONFIG_X86_32.
@@ -615,9 +691,10 @@
 		return;
 
 clear_all:
-		clear_cpu_cap(c, X86_FEATURE_SME);
+		setup_clear_cpu_cap(X86_FEATURE_SME);
 clear_sev:
-		clear_cpu_cap(c, X86_FEATURE_SEV);
+		setup_clear_cpu_cap(X86_FEATURE_SEV);
+		setup_clear_cpu_cap(X86_FEATURE_SEV_ES);
 	}
 }
 
@@ -794,8 +871,6 @@
 		set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
 }
 
-#define MSR_AMD64_DE_CFG	0xC0011029
-
 static void init_amd_ln(struct cpuinfo_x86 *c)
 {
 	/*
@@ -894,12 +969,73 @@
 	node_reclaim_distance = 32;
 #endif
 
+	/* 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);
+	}
+
 	/*
-	 * Fix erratum 1076: CPB feature bit not being set in CPUID.
-	 * Always set it, except when running under a hypervisor.
+	 * Work around Erratum 1386.  The XSAVES instruction malfunctions in
+	 * certain circumstances on Zen1/2 uarch, and not all parts have had
+	 * updated microcode at the time of writing (March 2023).
+	 *
+	 * Affected parts all have no supervisor XSAVE states, meaning that
+	 * the XSAVEC instruction (which works fine) is equivalent.
 	 */
-	if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_CPB))
-		set_cpu_cap(c, X86_FEATURE_CPB);
+	if (c->x86 == 0x17)
+		clear_cpu_cap(c, X86_FEATURE_XSAVES);
+}
+
+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)
@@ -956,8 +1092,8 @@
 		 * 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);
+		msr_set_bit(MSR_AMD64_DE_CFG,
+			    MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT);
 
 		/* A serializing LFENCE stops RDTSC speculation */
 		set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
@@ -978,6 +1114,24 @@
 	/* 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);
+
+	/*
+	 * Turn on the Instructions Retired free counter on machines not
+	 * susceptible to erratum #1054 "Instructions Retired Performance
+	 * Counter May Be Inaccurate".
+	 */
+	if (cpu_has(c, X86_FEATURE_IRPERF) &&
+	    !cpu_has_amd_erratum(c, amd_erratum_1054))
+		msr_set_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT);
+
+	check_null_seg_clears_base(c);
+
+	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
@@ -1073,70 +1227,6 @@
 
 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_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;
-}
-
 void set_dr_addr_mask(unsigned long mask, int dr)
 {
 	if (!boot_cpu_has(X86_FEATURE_BPEXT))
@@ -1155,3 +1245,33 @@
 		break;
 	}
 }
+
+static void zenbleed_check_cpu(void *unused)
+{
+	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+
+	zenbleed_check(c);
+
+	if (!cpu_has(c, X86_FEATURE_HYPERVISOR) &&
+	     cpu_has_amd_erratum(c, amd_erratum_1485))
+		msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT);
+}
+
+void amd_check_microcode(void)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		return;
+
+	on_each_cpu(zenbleed_check_cpu, NULL, 1);
+}
+
+/*
+ * Issue a DIV 0/1 insn to clear any division data from previous DIV
+ * operations.
+ */
+void noinstr 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-ein-5.4.0.orig/arch/x86/kernel/cpu/bugs.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/bugs.c
@@ -9,7 +9,6 @@
  *	- Andrew D. Balsa (code cleanup).
  */
 #include <linux/init.h>
-#include <linux/utsname.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/nospec.h>
@@ -25,32 +24,71 @@
 #include <asm/msr.h>
 #include <asm/vmx.h>
 #include <asm/paravirt.h>
-#include <asm/alternative.h>
 #include <asm/pgtable.h>
-#include <asm/set_memory.h>
 #include <asm/intel-family.h>
 #include <asm/e820/api.h>
 #include <asm/hypervisor.h>
+#include <linux/bpf.h>
 
 #include "cpu.h"
 
 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);
 
-/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
+/* 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);
+
+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);
+}
+
 /*
- * The vendor and possibly platform specific bits which can be modified in
- * x86_spec_ctrl_base.
+ * 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().
  */
-static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
+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.
@@ -73,100 +111,63 @@
 DEFINE_STATIC_KEY_FALSE(mds_idle_clear);
 EXPORT_SYMBOL_GPL(mds_idle_clear);
 
-void __init check_bugs(void)
-{
-	identify_boot_cpu();
-
-	/*
-	 * 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);
-	}
+/* 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))
+	if (cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL)) {
 		rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
 
-	/* Allow STIBP in MSR_SPEC_CTRL if supported */
-	if (boot_cpu_has(X86_FEATURE_STIBP))
-		x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
+		/*
+		 * Previously running kernel (kexec), may have some controls
+		 * turned ON. Clear them and let the mitigations setup below
+		 * rediscover them based on configuration.
+		 */
+		x86_spec_ctrl_base &= ~SPEC_CTRL_MITIGATIONS_MASK;
+	}
+
+	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();
-	ssb_select_mitigation();
-	l1tf_select_mitigation();
-	mds_select_mitigation();
-	taa_select_mitigation();
-
-	arch_smt_update();
-
-#ifdef CONFIG_X86_32
 	/*
-	 * Check whether we are able to run this kernel safely on SMP.
-	 *
-	 * - i386 is no longer supported.
-	 * - In order to run on anything without a TSC, we need to be
-	 *   compiled for a i486.
+	 * retbleed_select_mitigation() relies on the state set by
+	 * spectre_v2_select_mitigation(); specifically it wants to know about
+	 * spectre_v2=ibrs.
 	 */
-	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();
-
-	fpu__init_check_bugs();
-#else /* CONFIG_X86_64 */
-	alternative_instructions();
-
+	retbleed_select_mitigation();
 	/*
-	 * 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.
+	 * spectre_v2_user_select_mitigation() relies on the state set by
+	 * retbleed_select_mitigation(); specifically the STIBP selection is
+	 * forced for UNRET.
 	 */
-	if (!direct_gbpages)
-		set_memory_4k((unsigned long)__va(0), 1);
-#endif
+	spectre_v2_user_select_mitigation();
+	ssb_select_mitigation();
+	l1tf_select_mitigation();
+	md_clear_select_mitigation();
+	srbds_select_mitigation();
+	gds_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, hostval = x86_spec_ctrl_base;
+	u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
 	struct thread_info *ti = current_thread_info();
 
-	/* Is MSR_SPEC_CTRL implemented ? */
 	if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
-		/*
-		 * Restrict guest_spec_ctrl to supported values. Clear the
-		 * modifiable bits in the host base value and or the
-		 * modifiable bits from the guest value.
-		 */
-		guestval = hostval & ~x86_spec_ctrl_mask;
-		guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
-
-		/* SSBD controlled in MSR_SPEC_CTRL */
-		if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-		    static_cpu_has(X86_FEATURE_AMD_SSBD))
-			hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
-
-		/* Conditional STIBP enabled? */
-		if (static_branch_unlikely(&switch_to_cond_stibp))
-			hostval |= stibp_tif_to_spec_ctrl(ti->flags);
-
 		if (hostval != guestval) {
 			msrval = setguest ? guestval : hostval;
 			wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -245,8 +246,6 @@
 		    (mds_nosmt || cpu_mitigations_auto_nosmt()))
 			cpu_smt_disable(false);
 	}
-
-	pr_info("%s\n", mds_strings[mds_mitigation]);
 }
 
 static int __init mds_cmdline(char *str)
@@ -286,8 +285,6 @@
 
 static void __init taa_select_mitigation(void)
 {
-	u64 ia32_cap;
-
 	if (!boot_cpu_has_bug(X86_BUG_TAA)) {
 		taa_mitigation = TAA_MITIGATION_OFF;
 		return;
@@ -296,7 +293,7 @@
 	/* TSX previously disabled by tsx=off */
 	if (!boot_cpu_has(X86_FEATURE_RTM)) {
 		taa_mitigation = TAA_MITIGATION_TSX_DISABLED;
-		goto out;
+		return;
 	}
 
 	if (cpu_mitigations_off()) {
@@ -304,9 +301,13 @@
 		return;
 	}
 
-	/* TAA mitigation is turned off on the cmdline (tsx_async_abort=off) */
-	if (taa_mitigation == TAA_MITIGATION_OFF)
-		goto out;
+	/*
+	 * 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;
@@ -322,9 +323,8 @@
 	 * On MDS_NO=1 CPUs if ARCH_CAP_TSX_CTRL_MSR is not set, microcode
 	 * update is required.
 	 */
-	ia32_cap = x86_read_arch_cap_msr();
-	if ( (ia32_cap & ARCH_CAP_MDS_NO) &&
-	    !(ia32_cap & ARCH_CAP_TSX_CTRL_MSR))
+	if ( (x86_arch_cap_msr & ARCH_CAP_MDS_NO) &&
+	    !(x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR))
 		taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
 
 	/*
@@ -338,9 +338,6 @@
 
 	if (taa_nosmt || cpu_mitigations_auto_nosmt())
 		cpu_smt_disable(false);
-
-out:
-	pr_info("%s\n", taa_strings[taa_mitigation]);
 }
 
 static int __init tsx_async_abort_parse_cmdline(char *str)
@@ -365,6 +362,383 @@
 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) ||
+	     boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN) ||
+	     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]);
+	else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+		pr_info("MMIO Stale Data: Unknown: No mitigations\n");
+}
+
+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_FORCE,
+	GDS_MITIGATION_FULL,
+	GDS_MITIGATION_FULL_LOCKED,
+	GDS_MITIGATION_HYPERVISOR,
+};
+
+#if IS_ENABLED(CONFIG_GDS_FORCE_MITIGATION)
+static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FORCE;
+#else
+static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL;
+#endif
+
+static const char * const gds_strings[] = {
+	[GDS_MITIGATION_OFF]		= "Vulnerable",
+	[GDS_MITIGATION_UCODE_NEEDED]	= "Vulnerable: No microcode",
+	[GDS_MITIGATION_FORCE]		= "Mitigation: AVX disabled, 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_FORCE:
+	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)) {
+		if (gds_mitigation == GDS_MITIGATION_FORCE) {
+			/*
+			 * This only needs to be done on the boot CPU so do it
+			 * here rather than in update_gds_msr()
+			 */
+			setup_clear_cpu_cap(X86_FEATURE_AVX);
+			pr_warn("Microcode update needed! Disabling AVX as mitigation.\n");
+		} else {
+			gds_mitigation = GDS_MITIGATION_UCODE_NEEDED;
+		}
+		goto out;
+	}
+
+	/* Microcode has mitigation, use it */
+	if (gds_mitigation == GDS_MITIGATION_FORCE)
+		gds_mitigation = GDS_MITIGATION_FULL;
+
+	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;
+	else if (!strcmp(str, "force"))
+		gds_mitigation = GDS_MITIGATION_FORCE;
+
+	return 0;
+}
+early_param("gather_data_sampling", gds_parse_cmdline);
+
+#undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V1 : " fmt
 
 enum spectre_v1_mitigation {
@@ -456,13 +830,106 @@
 }
 early_param("nospectre_v1", nospectre_v1_cmdline);
 
-#undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 : " fmt
-
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
 	SPECTRE_V2_NONE;
 
-static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init =
+#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_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
+#define RETBLEED_COMPILER_MSG "WARNING: kernel not compiled with RETPOLINE or -mfunction-return capable compiler!\n"
+#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 CONFIG_RETPOLINE
@@ -486,6 +953,33 @@
 static inline const char *spectre_v2_module_string(void) { return ""; }
 #endif
 
+#define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+#define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS+LFENCE mitigation and SMT, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_IBRS_PERF_MSG "WARNING: IBRS mitigation selected on Enhanced IBRS CPU, this may cause unnecessary performance loss\n"
+
+#ifdef CONFIG_BPF_SYSCALL
+void unpriv_ebpf_notify(int new_state)
+{
+	if (new_state)
+		return;
+
+	/* Unprivileged eBPF is enabled */
+
+	switch (spectre_v2_enabled) {
+	case SPECTRE_V2_EIBRS:
+		pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+		break;
+	case SPECTRE_V2_EIBRS_LFENCE:
+		if (sched_smt_active())
+			pr_err(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+		break;
+	default:
+		break;
+	}
+}
+#endif
+
 static inline bool match_option(const char *arg, int arglen, const char *opt)
 {
 	int len = strlen(opt);
@@ -500,7 +994,11 @@
 	SPECTRE_V2_CMD_FORCE,
 	SPECTRE_V2_CMD_RETPOLINE,
 	SPECTRE_V2_CMD_RETPOLINE_GENERIC,
-	SPECTRE_V2_CMD_RETPOLINE_AMD,
+	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 {
@@ -541,13 +1039,15 @@
 		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(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_parse_user_cmdline(void)
 {
 	char arg[20];
 	int ret, i;
 
-	switch (v2_cmd) {
+	switch (spectre_v2_cmd) {
 	case SPECTRE_V2_CMD_NONE:
 		return SPECTRE_V2_USER_CMD_NONE;
 	case SPECTRE_V2_CMD_FORCE:
@@ -573,8 +1073,20 @@
 	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(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_user_select_mitigation(void)
 {
 	enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
 	bool smt_possible = IS_ENABLED(CONFIG_SMP);
@@ -587,7 +1099,7 @@
 	    cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
 		smt_possible = false;
 
-	cmd = spectre_v2_parse_user_cmdline(v2_cmd);
+	cmd = spectre_v2_parse_user_cmdline();
 	switch (cmd) {
 	case SPECTRE_V2_USER_CMD_NONE:
 		goto set_mode;
@@ -608,24 +1120,17 @@
 		break;
 	}
 
-	/*
-	 * 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;
-
 	/* 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:
@@ -641,28 +1146,45 @@
 			"always-on" : "conditional");
 	}
 
-	/* If enhanced IBRS is enabled no STIBP required */
-	if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+	/*
+	 * 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;
 
 	/*
-	 * If SMT is not possible or STIBP is not available clear the STIBP
-	 * mode.
+	 * 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 (!smt_possible || !boot_cpu_has(X86_FEATURE_STIBP))
-		mode = SPECTRE_V2_USER_NONE;
+	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:
-	spectre_v2_user = mode;
-	/* Only print the STIBP mode when SMT possible */
-	if (smt_possible)
-		pr_info("%s\n", spectre_v2_user_strings[mode]);
+	pr_info("%s\n", spectre_v2_user_strings[mode]);
 }
 
 static const char * const spectre_v2_strings[] = {
 	[SPECTRE_V2_NONE]			= "Vulnerable",
-	[SPECTRE_V2_RETPOLINE_GENERIC]		= "Mitigation: Full generic retpoline",
-	[SPECTRE_V2_RETPOLINE_AMD]		= "Mitigation: Full AMD retpoline",
-	[SPECTRE_V2_IBRS_ENHANCED]		= "Mitigation: Enhanced IBRS",
+	[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 {
@@ -673,9 +1195,14 @@
 	{ "off",		SPECTRE_V2_CMD_NONE,		  false },
 	{ "on",			SPECTRE_V2_CMD_FORCE,		  true  },
 	{ "retpoline",		SPECTRE_V2_CMD_RETPOLINE,	  false },
-	{ "retpoline,amd",	SPECTRE_V2_CMD_RETPOLINE_AMD,	  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)
@@ -711,17 +1238,48 @@
 	}
 
 	if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
-	     cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
-	     cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+	     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);
+		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_RETPOLINE_AMD &&
-	    boot_cpu_data.x86_vendor != X86_VENDOR_HYGON &&
-	    boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
-		pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+	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;
 	}
 
@@ -730,6 +1288,160 @@
 	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)) {
+			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();
@@ -750,86 +1462,164 @@
 	case SPECTRE_V2_CMD_FORCE:
 	case SPECTRE_V2_CMD_AUTO:
 		if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
-			mode = SPECTRE_V2_IBRS_ENHANCED;
-			/* Force it so VMEXIT will restore correctly */
-			x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-			wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
-			goto specv2_set_mode;
+			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;
 		}
-		if (IS_ENABLED(CONFIG_RETPOLINE))
-			goto retpoline_auto;
+
+		mode = spectre_v2_select_retpoline();
 		break;
-	case SPECTRE_V2_CMD_RETPOLINE_AMD:
-		if (IS_ENABLED(CONFIG_RETPOLINE))
-			goto retpoline_amd;
+
+	case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
+		pr_err(SPECTRE_V2_LFENCE_MSG);
+		mode = SPECTRE_V2_LFENCE;
 		break;
+
 	case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
-		if (IS_ENABLED(CONFIG_RETPOLINE))
-			goto retpoline_generic;
+		mode = SPECTRE_V2_RETPOLINE;
 		break;
+
 	case SPECTRE_V2_CMD_RETPOLINE:
-		if (IS_ENABLED(CONFIG_RETPOLINE))
-			goto retpoline_auto;
+		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;
 	}
-	pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!");
-	return;
 
-retpoline_auto:
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
-	    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
-	retpoline_amd:
-		if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
-			pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n");
-			goto retpoline_generic;
-		}
-		mode = SPECTRE_V2_RETPOLINE_AMD;
-		setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
-		setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
-	} else {
-	retpoline_generic:
-		mode = SPECTRE_V2_RETPOLINE_GENERIC;
+	if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+		pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+
+	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;
 	}
 
-specv2_set_mode:
+	/*
+	 * 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\n", spectre_v2_strings[mode]);
 
 	/*
-	 * If spectre v2 protection has been enabled, unconditionally fill
-	 * RSB during a context switch; this protects against two independent
-	 * issues:
+	 * 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.
 	 *
-	 *	- RSB underflow (and switch to BTB) on Skylake+
-	 *	- SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs
+	 *    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 means the kernel is safe because it has no indirect
-	 * branches. Enhanced IBRS protects firmware too, so, enable restricted
-	 * speculation around firmware calls only when Enhanced IBRS isn't
-	 * supported.
+	 * 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) && mode != SPECTRE_V2_IBRS_ENHANCED) {
+	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");
 	}
 
 	/* Set up IBPB and STIBP depending on the general spectre V2 command */
-	spectre_v2_user_select_mitigation(cmd);
+	spectre_v2_cmd = cmd;
 }
 
 static void update_stibp_msr(void * __unused)
 {
-	wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+	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. */
@@ -875,20 +1665,27 @@
 	if (!boot_cpu_has_bug(X86_BUG_MSBDS_ONLY))
 		return;
 
-	if (sched_smt_active())
+	if (sched_smt_active()) {
 		static_branch_enable(&mds_idle_clear);
-	else
+	} 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"
 
 void cpu_bugs_smt_update(void)
 {
 	mutex_lock(&spec_ctrl_mutex);
 
-	switch (spectre_v2_user) {
+	if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+	    spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+		pr_warn_once(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+
+	switch (spectre_v2_user_stibp) {
 	case SPECTRE_V2_USER_NONE:
 		break;
 	case SPECTRE_V2_USER_STRICT:
@@ -923,6 +1720,16 @@
 		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);
 }
 
@@ -1027,16 +1834,6 @@
 	}
 
 	/*
-	 * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
-	 * bit in the mask to allow guests to use the mitigation even in the
-	 * case where the host does not enable it.
-	 */
-	if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-	    static_cpu_has(X86_FEATURE_AMD_SSBD)) {
-		x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
-	}
-
-	/*
 	 * 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
@@ -1053,7 +1850,7 @@
 			x86_amd_ssb_disable();
 		} else {
 			x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-			wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+			update_spec_ctrl(x86_spec_ctrl_base);
 		}
 	}
 
@@ -1127,19 +1924,40 @@
 	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 == SPECTRE_V2_USER_NONE)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
 			return 0;
 		/*
-		 * Indirect branch speculation is always disabled in strict
-		 * mode.
+		 * 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 (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
-		    spectre_v2_user == 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;
@@ -1149,15 +1967,19 @@
 		 * Indirect branch speculation is always allowed when
 		 * mitigation is force disabled.
 		 */
-		if (spectre_v2_user == SPECTRE_V2_USER_NONE)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
 			return -EPERM;
-		if (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
-		    spectre_v2_user == SPECTRE_V2_USER_STRICT_PREFERRED)
+
+		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;
@@ -1183,7 +2005,8 @@
 {
 	if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP)
 		ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE);
-	if (spectre_v2_user == SPECTRE_V2_USER_SECCOMP)
+	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
@@ -1214,22 +2037,21 @@
 	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
 		return PR_SPEC_NOT_AFFECTED;
 
-	switch (spectre_v2_user) {
-	case SPECTRE_V2_USER_NONE:
+	if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+	    spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
 		return PR_SPEC_ENABLE;
-	case SPECTRE_V2_USER_PRCTL:
-	case SPECTRE_V2_USER_SECCOMP:
+	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;
-	case SPECTRE_V2_USER_STRICT:
-	case SPECTRE_V2_USER_STRICT_PREFERRED:
+	} 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;
-	default:
+	else
 		return PR_SPEC_NOT_AFFECTED;
-	}
 }
 
 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
@@ -1247,7 +2069,7 @@
 void x86_spec_ctrl_setup_ap(void)
 {
 	if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
-		wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+		update_spec_ctrl(x86_spec_ctrl_base);
 
 	if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
 		x86_amd_ssb_disable();
@@ -1463,22 +2285,39 @@
 		       sched_smt_active() ? "vulnerable" : "disabled");
 }
 
+static ssize_t mmio_stale_data_show_state(char *buf)
+{
+	if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+		return sysfs_emit(buf, "Unknown: No mitigations\n");
+
+	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_enabled == SPECTRE_V2_IBRS_ENHANCED)
+	if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
 		return "";
 
-	switch (spectre_v2_user) {
+	switch (spectre_v2_user_stibp) {
 	case SPECTRE_V2_USER_NONE:
-		return ", STIBP: disabled";
+		return "; STIBP: disabled";
 	case SPECTRE_V2_USER_STRICT:
-		return ", STIBP: forced";
+		return "; STIBP: forced";
 	case SPECTRE_V2_USER_STRICT_PREFERRED:
-		return ", STIBP: always-on";
+		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 "; STIBP: conditional";
 	}
 	return "";
 }
@@ -1487,14 +2326,84 @@
 {
 	if (boot_cpu_has(X86_FEATURE_IBPB)) {
 		if (static_key_enabled(&switch_mm_always_ibpb))
-			return ", IBPB: always-on";
+			return "; IBPB: always-on";
 		if (static_key_enabled(&switch_mm_cond_ibpb))
-			return ", IBPB: conditional";
-		return ", IBPB: disabled";
+			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 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 spectre_v2_show_state(char *buf)
+{
+	if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
+		return sprintf(buf, "Vulnerable: LFENCE\n");
+
+	if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+		return sprintf(buf, "Vulnerable: eIBRS with unprivileged eBPF\n");
+
+	if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+	    spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+		return sprintf(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n");
+
+	return sprintf(buf, "%s%s%s%s%s%s%s%s\n",
+		       spectre_v2_strings[spectre_v2_enabled],
+		       ibpb_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());
+}
+
+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 cpu_show_common(struct device *dev, struct device_attribute *attr,
 			       char *buf, unsigned int bug)
 {
@@ -1515,12 +2424,7 @@
 		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\n", spectre_v2_strings[spectre_v2_enabled],
-			       ibpb_state(),
-			       boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
-			       stibp_state(),
-			       boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
-			       spectre_v2_module_string());
+		return spectre_v2_show_state(buf);
 
 	case X86_BUG_SPEC_STORE_BYPASS:
 		return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
@@ -1539,6 +2443,19 @@
 	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:
+	case X86_BUG_MMIO_UNKNOWN:
+		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);
+
 	default:
 		break;
 	}
@@ -1585,4 +2502,27 @@
 {
 	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)
+{
+	if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
+		return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_UNKNOWN);
+	else
+		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);
+}
 #endif
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/cacheinfo.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/cacheinfo.c
@@ -646,7 +646,7 @@
 	return i;
 }
 
-void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu)
 {
 	/*
 	 * We may have multiple LLCs if L3 caches exist, so check if we
@@ -657,7 +657,7 @@
 
 	if (c->x86 < 0x17) {
 		/* LLC is at the node level. */
-		per_cpu(cpu_llc_id, cpu) = node_id;
+		per_cpu(cpu_llc_id, cpu) = c->cpu_die_id;
 	} else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
 		/*
 		 * LLC is at the core complex level.
@@ -684,7 +684,7 @@
 	}
 }
 
-void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
+void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c, int cpu)
 {
 	/*
 	 * We may have multiple LLCs if L3 caches exist, so check if we
@@ -985,7 +985,7 @@
 	this_leaf->priv = base->nb;
 }
 
-static int __init_cache_level(unsigned int cpu)
+int init_cache_level(unsigned int cpu)
 {
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 
@@ -1014,7 +1014,7 @@
 	id4_regs->id = c->apicid >> index_msb;
 }
 
-static int __populate_cache_leaves(unsigned int cpu)
+int populate_cache_leaves(unsigned int cpu)
 {
 	unsigned int idx, ret;
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
@@ -1033,6 +1033,3 @@
 
 	return 0;
 }
-
-DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
-DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/common.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/common.c
@@ -17,10 +17,14 @@
 #include <linux/init.h>
 #include <linux/kprobes.h>
 #include <linux/kgdb.h>
+#include <linux/mem_encrypt.h>
 #include <linux/smp.h>
+#include <linux/cpu.h>
 #include <linux/io.h>
 #include <linux/syscore_ops.h>
+#include <linux/utsname.h>
 
+#include <asm/alternative.h>
 #include <asm/stackprotector.h>
 #include <asm/perf_event.h>
 #include <asm/mmu_context.h>
@@ -57,6 +61,7 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/uv/uv.h>
 #endif
+#include <asm/set_memory.h>
 
 #include "cpu.h"
 
@@ -366,6 +371,9 @@
 	cr4_clear_bits(X86_CR4_UMIP);
 }
 
+/* These bits should not change their value after CPU init is finished. */
+static const unsigned long cr4_pinned_mask =
+	X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | X86_CR4_FSGSBASE;
 static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
 static unsigned long cr4_pinned_bits __ro_after_init;
 
@@ -374,7 +382,7 @@
 	unsigned long bits_missing = 0;
 
 set_register:
-	asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order));
+	asm volatile("mov %0,%%cr0": "+r" (val) : : "memory");
 
 	if (static_branch_likely(&cr_pinning)) {
 		if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
@@ -390,20 +398,20 @@
 
 void native_write_cr4(unsigned long val)
 {
-	unsigned long bits_missing = 0;
+	unsigned long bits_changed = 0;
 
 set_register:
-	asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits));
+	asm volatile("mov %0,%%cr4": "+r" (val) : : "memory");
 
 	if (static_branch_likely(&cr_pinning)) {
-		if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) {
-			bits_missing = ~val & cr4_pinned_bits;
-			val |= bits_missing;
+		if (unlikely((val & cr4_pinned_mask) != cr4_pinned_bits)) {
+			bits_changed = (val & cr4_pinned_mask) ^ cr4_pinned_bits;
+			val = (val & ~cr4_pinned_mask) | cr4_pinned_bits;
 			goto set_register;
 		}
-		/* Warn after we've set the missing bits. */
-		WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n",
-			  bits_missing);
+		/* Warn after we've corrected the changed bits. */
+		WARN_ONCE(bits_changed, "pinned CR4 bits changed: 0x%lx!?\n",
+			  bits_changed);
 	}
 }
 EXPORT_SYMBOL(native_write_cr4);
@@ -415,7 +423,7 @@
 	if (boot_cpu_has(X86_FEATURE_PCID))
 		cr4 |= X86_CR4_PCIDE;
 	if (static_branch_likely(&cr_pinning))
-		cr4 |= cr4_pinned_bits;
+		cr4 = (cr4 & ~cr4_pinned_mask) | cr4_pinned_bits;
 
 	__write_cr4(cr4);
 
@@ -430,10 +438,7 @@
  */
 static void __init setup_cr_pinning(void)
 {
-	unsigned long mask;
-
-	mask = (X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP);
-	cr4_pinned_bits = this_cpu_read(cpu_tlbstate.cr4) & mask;
+	cr4_pinned_bits = this_cpu_read(cpu_tlbstate.cr4) & cr4_pinned_mask;
 	static_key_enable(&cr_pinning.key);
 }
 
@@ -444,8 +449,6 @@
 
 static __always_inline void setup_pku(struct cpuinfo_x86 *c)
 {
-	struct pkru_state *pk;
-
 	/* check the boot processor, plus compile options for PKU: */
 	if (!cpu_feature_enabled(X86_FEATURE_PKU))
 		return;
@@ -456,15 +459,12 @@
 		return;
 
 	cr4_set_bits(X86_CR4_PKE);
-	pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU);
-	if (pk)
-		pk->pkru = init_pkru_value;
 	/*
 	 * Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE
 	 * cpuid bit to be set.  We need to ensure that we
 	 * update that bit in this CPU's "cpu_info".
 	 */
-	get_cpu_cap(c);
+	set_cpu_cap(c, X86_FEATURE_OSPKE);
 }
 
 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
@@ -961,6 +961,12 @@
 	if (c->extended_cpuid_level >= 0x8000000a)
 		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
+	if (c->extended_cpuid_level >= 0x8000001f)
+		c->x86_capability[CPUID_8000_001F_EAX] = cpuid_eax(0x8000001f);
+
+	if (c->extended_cpuid_level >= 0x80000021)
+		c->x86_capability[CPUID_8000_0021_EAX] = cpuid_eax(0x80000021);
+
 	init_scattered_cpuid_features(c);
 	init_speculation_control(c);
 	init_cqm(c);
@@ -1024,6 +1030,10 @@
 #define MSBDS_ONLY		BIT(5)
 #define NO_SWAPGS		BIT(6)
 #define NO_ITLB_MULTIHIT	BIT(7)
+#define NO_SPECTRE_V2		BIT(8)
+#define NO_EIBRS_PBRSB		BIT(9)
+#define NO_MMIO			BIT(10)
+#define NO_BHI			BIT(11)
 
 #define VULNWL(_vendor, _family, _model, _whitelist)	\
 	{ X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
@@ -1044,6 +1054,11 @@
 	VULNWL(NSC,	5, X86_MODEL_ANY,	NO_SPECULATION),
 
 	/* Intel Family 6 */
+	VULNWL_INTEL(TIGERLAKE,			NO_MMIO),
+	VULNWL_INTEL(TIGERLAKE_L,		NO_MMIO),
+	VULNWL_INTEL(ALDERLAKE,			NO_MMIO),
+	VULNWL_INTEL(ALDERLAKE_L,		NO_MMIO),
+
 	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),
@@ -1062,9 +1077,9 @@
 	VULNWL_INTEL(ATOM_AIRMONT_MID,		NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
 	VULNWL_INTEL(ATOM_AIRMONT_NP,		NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
 
-	VULNWL_INTEL(ATOM_GOLDMONT,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
-	VULNWL_INTEL(ATOM_GOLDMONT_D,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
-	VULNWL_INTEL(ATOM_GOLDMONT_PLUS,	NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_GOLDMONT,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+	VULNWL_INTEL(ATOM_GOLDMONT_D,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+	VULNWL_INTEL(ATOM_GOLDMONT_PLUS,	NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB),
 
 	/*
 	 * Technically, swapgs isn't serializing on AMD (despite it previously
@@ -1074,65 +1089,146 @@
 	 * good enough for our purposes.
 	 */
 
-	VULNWL_INTEL(ATOM_TREMONT_D,		NO_ITLB_MULTIHIT),
+	VULNWL_INTEL(ATOM_TREMONT,		NO_EIBRS_PBRSB),
+	VULNWL_INTEL(ATOM_TREMONT_L,		NO_EIBRS_PBRSB),
+	VULNWL_INTEL(ATOM_TREMONT_D,		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),
-	VULNWL_AMD(0x10,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-	VULNWL_AMD(0x11,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
-	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_AMD(0x0f,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI),
+	VULNWL_AMD(0x10,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI),
+	VULNWL_AMD(0x11,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI),
+	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | 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),
-	VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
+	VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI),
+	VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI),
+
+	/* Zhaoxin Family 7 */
+	VULNWL(CENTAUR,	7, X86_MODEL_ANY,	NO_SPECTRE_V2 | NO_MMIO | NO_BHI),
+	VULNWL(ZHAOXIN,	7, X86_MODEL_ANY,	NO_SPECTRE_V2 | NO_MMIO | NO_BHI),
 	{}
 };
 
-static bool __init cpu_matches(unsigned long which)
+#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 VULNBL_HYGON(family, blacklist)		\
+	VULNBL(HYGON, 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)
+
+static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
+	VULNBL_INTEL_STEPPINGS(IVYBRIDGE,	X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(HASWELL,		X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(HASWELL_L,	X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(HASWELL_G,	X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(HASWELL_X,	X86_STEPPING_ANY,		MMIO),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_D,	X86_STEPPING_ANY,		MMIO),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_G,	X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(BROADWELL_X,	X86_STEPPING_ANY,		MMIO),
+	VULNBL_INTEL_STEPPINGS(BROADWELL,	X86_STEPPING_ANY,		SRBDS),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE_X,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE_L,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS | SRBDS),
+	VULNBL_INTEL_STEPPINGS(SKYLAKE,		X86_STEPPING_ANY,		MMIO | RETBLEED | GDS | SRBDS),
+	VULNBL_INTEL_STEPPINGS(KABYLAKE_L,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS | SRBDS),
+	VULNBL_INTEL_STEPPINGS(KABYLAKE,	X86_STEPPING_ANY,		MMIO | RETBLEED | GDS | SRBDS),
+	VULNBL_INTEL_STEPPINGS(CANNONLAKE_L,	X86_STEPPING_ANY,		RETBLEED),
+	VULNBL_INTEL_STEPPINGS(ICELAKE_L,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED | GDS),
+	VULNBL_INTEL_STEPPINGS(ICELAKE_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),
+	VULNBL_INTEL_STEPPINGS(COMETLAKE_L,	X86_STEPPINGS(0x0, 0x0),	MMIO | RETBLEED),
+	VULNBL_INTEL_STEPPINGS(COMETLAKE_L,	X86_STEPPING_ANY,		MMIO | MMIO_SBDS | RETBLEED | GDS),
+	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_D,	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),
+	VULNBL_HYGON(0x18, RETBLEED | SMT_RSB),
+	{}
+};
+
+static bool __init cpu_matches(const struct x86_cpu_id *table, unsigned long which)
 {
-	const struct x86_cpu_id *m = x86_match_cpu(cpu_vuln_whitelist);
+	const struct x86_cpu_id *m = x86_match_cpu(table);
 
 	return m && !!(m->driver_data & which);
 }
 
 u64 x86_read_arch_cap_msr(void)
 {
-	u64 ia32_cap = 0;
+	u64 x86_arch_cap_msr = 0;
 
 	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
-		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
+		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, x86_arch_cap_msr);
+
+	return x86_arch_cap_msr;
+}
 
-	return ia32_cap;
+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 ia32_cap = x86_read_arch_cap_msr();
+	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(NO_ITLB_MULTIHIT) && !(ia32_cap & ARCH_CAP_PSCHANGE_MC_NO))
+	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(NO_SPECULATION))
+	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(NO_SSB) && !(ia32_cap & ARCH_CAP_SSB_NO) &&
+	if (!cpu_matches(cpu_vuln_whitelist, NO_SPECTRE_V2))
+		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 (ia32_cap & ARCH_CAP_IBRS_ALL)
+	if (x86_arch_cap_msr & ARCH_CAP_IBRS_ALL)
 		setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
 
-	if (!cpu_matches(NO_MDS) && !(ia32_cap & ARCH_CAP_MDS_NO)) {
+	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(MSBDS_ONLY))
+		if (cpu_matches(cpu_vuln_whitelist, MSBDS_ONLY))
 			setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
 	}
 
-	if (!cpu_matches(NO_SWAPGS))
+	if (!cpu_matches(cpu_vuln_whitelist, NO_SWAPGS))
 		setup_force_cpu_bug(X86_BUG_SWAPGS);
 
 	/*
@@ -1145,21 +1241,81 @@
 	 * 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 (!(ia32_cap & ARCH_CAP_TAA_NO) &&
+	if (!(x86_arch_cap_msr & ARCH_CAP_TAA_NO) &&
 	    (cpu_has(c, X86_FEATURE_RTM) ||
-	     (ia32_cap & ARCH_CAP_TSX_CTRL_MSR)))
+	     (x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR)))
 		setup_force_cpu_bug(X86_BUG_TAA);
 
-	if (cpu_matches(NO_MELTDOWN))
+	/*
+	 * 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.
+	 *
+	 * Set X86_BUG_MMIO_UNKNOWN for CPUs that are neither in the blacklist,
+	 * nor in the whitelist and also don't enumerate MSR ARCH_CAP MMIO bits.
+	 */
+	if (!arch_cap_mmio_immune(x86_arch_cap_msr)) {
+		if (cpu_matches(cpu_vuln_blacklist, MMIO))
+			setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
+		else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO))
+			setup_force_cpu_bug(X86_BUG_MMIO_UNKNOWN);
+	}
+
+	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);
+
+	/* 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 (ia32_cap & ARCH_CAP_RDCL_NO)
+	if (x86_arch_cap_msr & ARCH_CAP_RDCL_NO)
 		return;
 
 	setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
 
-	if (cpu_matches(NO_L1TF))
+	if (cpu_matches(cpu_vuln_whitelist, NO_L1TF))
 		return;
 
 	setup_force_cpu_bug(X86_BUG_L1TF);
@@ -1235,8 +1391,6 @@
 
 	cpu_set_bug_bits(c);
 
-	fpu__init_system(c);
-
 #ifdef CONFIG_X86_32
 	/*
 	 * Regardless of whether PCID is enumerated, the SDM says
@@ -1296,9 +1450,8 @@
 	early_identify_cpu(&boot_cpu_data);
 }
 
-static void detect_null_seg_behavior(struct cpuinfo_x86 *c)
+static bool detect_null_seg_behavior(void)
 {
-#ifdef CONFIG_X86_64
 	/*
 	 * Empirically, writing zero to a segment selector on AMD does
 	 * not clear the base, whereas writing zero to a segment
@@ -1319,10 +1472,43 @@
 	wrmsrl(MSR_FS_BASE, 1);
 	loadsegment(fs, 0);
 	rdmsrl(MSR_FS_BASE, tmp);
-	if (tmp != 0)
-		set_cpu_bug(c, X86_BUG_NULL_SEG);
 	wrmsrl(MSR_FS_BASE, old_base);
-#endif
+	return tmp == 0;
+}
+
+void check_null_seg_clears_base(struct cpuinfo_x86 *c)
+{
+	/* BUG_NULL_SEG is only relevant with 64bit userspace */
+	if (!IS_ENABLED(CONFIG_X86_64))
+		return;
+
+	/* Zen3 CPUs advertise Null Selector Clears Base in CPUID. */
+	if (c->extended_cpuid_level >= 0x80000021 &&
+	    cpuid_eax(0x80000021) & BIT(6))
+		return;
+
+	/*
+	 * CPUID bit above wasn't set. If this kernel is still running
+	 * as a HV guest, then the HV has decided not to advertize
+	 * that CPUID bit for whatever reason.	For example, one
+	 * member of the migration pool might be vulnerable.  Which
+	 * means, the bug is present: set the BUG flag and return.
+	 */
+	if (cpu_has(c, X86_FEATURE_HYPERVISOR)) {
+		set_cpu_bug(c, X86_BUG_NULL_SEG);
+		return;
+	}
+
+	/*
+	 * Zen2 CPUs also have this behaviour, but no CPUID bit.
+	 * 0x18 is the respective family for Hygon.
+	 */
+	if ((c->x86 == 0x17 || c->x86 == 0x18) &&
+	    detect_null_seg_behavior())
+		return;
+
+	/* All the remaining ones are affected */
+	set_cpu_bug(c, X86_BUG_NULL_SEG);
 }
 
 static void generic_identify(struct cpuinfo_x86 *c)
@@ -1358,8 +1544,6 @@
 
 	get_model_name(c); /* Default name */
 
-	detect_null_seg_behavior(c);
-
 	/*
 	 * ESPFIX is a strange bug.  All real CPUs have it.  Paravirt
 	 * systems that run Linux at CPL > 0 may or may not have the
@@ -1597,6 +1781,9 @@
 	mtrr_ap_init();
 	validate_apic_and_package_id(c);
 	x86_spec_ctrl_setup_ap();
+	update_srbds_msr();
+	if (boot_cpu_has_bug(X86_BUG_GDS))
+		update_gds_msr();
 }
 
 static __init int setup_noclflush(char *arg)
@@ -1785,7 +1972,7 @@
 	unsigned long cpudata = vdso_encode_cpunode(cpu, early_cpu_to_node(cpu));
 	struct desc_struct d = { };
 
-	if (boot_cpu_has(X86_FEATURE_RDTSCP))
+	if (boot_cpu_has(X86_FEATURE_RDTSCP) || boot_cpu_has(X86_FEATURE_RDPID))
 		write_rdtscp_aux(cpudata);
 
 	/* Store CPU and node number in limit. */
@@ -1895,8 +2082,6 @@
 	clear_all_debug_regs();
 	dbg_restore_debug_regs();
 
-	fpu__init_cpu();
-
 	if (is_uv_system())
 		uv_cpu_init();
 
@@ -1954,8 +2139,6 @@
 	clear_all_debug_regs();
 	dbg_restore_debug_regs();
 
-	fpu__init_cpu();
-
 	load_fixmap_gdt(cpu);
 }
 #endif
@@ -1974,6 +2157,8 @@
 	/* Reload CPUID max function as it might've changed. */
 	info.cpuid_level = cpuid_eax(0);
 
+	amd_check_microcode();
+
 	/*
 	 * Copy all capability leafs to pick up the synthetic ones so that
 	 * memcmp() below doesn't fail on that. The ones coming from CPUID will
@@ -2000,3 +2185,69 @@
 	/* Check whether IPI broadcasting can be enabled */
 	apic_smt_update();
 }
+
+void __init arch_cpu_finalize_init(void)
+{
+	identify_boot_cpu();
+
+	/*
+	 * 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);
+	}
+
+	/*
+	 * Must be before alternatives because it might set or clear
+	 * feature bits.
+	 */
+	fpu__init_system();
+	fpu__init_cpu();
+
+	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();
+	}
+
+	/*
+	 * This needs to be called before any devices perform DMA
+	 * operations that might use the SWIOTLB bounce buffers. It will
+	 * mark the bounce buffers as decrypted so that their usage will
+	 * not cause "plain-text" data to be decrypted when accessed. It
+	 * must be called after late_time_init() so that Hyper-V x86/x64
+	 * hypercalls work when the SWIOTLB bounce buffers are decrypted.
+	 */
+	mem_encrypt_init();
+}
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/cpu.h
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/cpu.h
@@ -73,10 +73,14 @@
 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);
+extern void check_null_seg_clears_base(struct cpuinfo_x86 *c);
 
 unsigned int aperfmperf_get_khz(int cpu);
+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);
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/hygon.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/hygon.c
@@ -64,7 +64,6 @@
  */
 static void hygon_get_topology(struct cpuinfo_x86 *c)
 {
-	u8 node_id;
 	int cpu = smp_processor_id();
 
 	/* get information required for multi-node processors */
@@ -74,7 +73,7 @@
 
 		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
 
-		node_id  = ecx & 0xff;
+		c->cpu_die_id  = ecx & 0xff;
 
 		c->cpu_core_id = ebx & 0xff;
 
@@ -89,17 +88,21 @@
 		if (!err)
 			c->x86_coreid_bits = get_count_order(c->x86_max_cores);
 
-		/* Socket ID is ApicId[6] for these processors. */
-		c->phys_proc_id = c->apicid >> APICID_SOCKET_ID_BIT;
+		/*
+		 * Socket ID is ApicId[6] for the processors with model <= 0x3
+		 * when running on host.
+		 */
+		if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && c->x86_model <= 0x3)
+			c->phys_proc_id = c->apicid >> APICID_SOCKET_ID_BIT;
 
-		cacheinfo_hygon_init_llc_id(c, cpu, node_id);
+		cacheinfo_hygon_init_llc_id(c, cpu);
 	} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
 		u64 value;
 
 		rdmsrl(MSR_FAM10H_NODE_ID, value);
-		node_id = value & 7;
+		c->cpu_die_id = value & 7;
 
-		per_cpu(cpu_llc_id, cpu) = node_id;
+		per_cpu(cpu_llc_id, cpu) = c->cpu_die_id;
 	} else
 		return;
 
@@ -122,7 +125,7 @@
 	/* Convert the initial APIC ID into the socket ID */
 	c->phys_proc_id = c->initial_apicid >> bits;
 	/* use socket ID also for last level cache */
-	per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
+	per_cpu(cpu_llc_id, cpu) = c->cpu_die_id = c->phys_proc_id;
 }
 
 static void srat_detect_node(struct cpuinfo_x86 *c)
@@ -336,8 +339,8 @@
 		 * 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);
+		msr_set_bit(MSR_AMD64_DE_CFG,
+			    MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT);
 
 		/* A serializing LFENCE stops RDTSC speculation */
 		set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
@@ -351,6 +354,8 @@
 	/* Hygon 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);
+
+	check_null_seg_clears_base(c);
 }
 
 static void cpu_detect_tlb_hygon(struct cpuinfo_x86 *c)
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/intel.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/intel.c
@@ -97,7 +97,7 @@
 static int __init ring3mwait_disable(char *__unused)
 {
 	ring3mwait_disabled = true;
-	return 0;
+	return 1;
 }
 __setup("ring3mwait=disable", ring3mwait_disable);
 
@@ -187,6 +187,90 @@
 	return false;
 }
 
+#define MSR_IA32_TME_ACTIVATE		0x982
+
+/* Helpers to access TME_ACTIVATE MSR */
+#define TME_ACTIVATE_LOCKED(x)		(x & 0x1)
+#define TME_ACTIVATE_ENABLED(x)		(x & 0x2)
+
+#define TME_ACTIVATE_POLICY(x)		((x >> 4) & 0xf)	/* Bits 7:4 */
+#define TME_ACTIVATE_POLICY_AES_XTS_128	0
+
+#define TME_ACTIVATE_KEYID_BITS(x)	((x >> 32) & 0xf)	/* Bits 35:32 */
+
+#define TME_ACTIVATE_CRYPTO_ALGS(x)	((x >> 48) & 0xffff)	/* Bits 63:48 */
+#define TME_ACTIVATE_CRYPTO_AES_XTS_128	1
+
+/* Values for mktme_status (SW only construct) */
+#define MKTME_ENABLED			0
+#define MKTME_DISABLED			1
+#define MKTME_UNINITIALIZED		2
+static int mktme_status = MKTME_UNINITIALIZED;
+
+static void detect_tme_early(struct cpuinfo_x86 *c)
+{
+	u64 tme_activate, tme_policy, tme_crypto_algs;
+	int keyid_bits = 0, nr_keyids = 0;
+	static u64 tme_activate_cpu0 = 0;
+
+	rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate);
+
+	if (mktme_status != MKTME_UNINITIALIZED) {
+		if (tme_activate != tme_activate_cpu0) {
+			/* Broken BIOS? */
+			pr_err_once("x86/tme: configuration is inconsistent between CPUs\n");
+			pr_err_once("x86/tme: MKTME is not usable\n");
+			mktme_status = MKTME_DISABLED;
+
+			/* Proceed. We may need to exclude bits from x86_phys_bits. */
+		}
+	} else {
+		tme_activate_cpu0 = tme_activate;
+	}
+
+	if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) {
+		pr_info_once("x86/tme: not enabled by BIOS\n");
+		mktme_status = MKTME_DISABLED;
+		return;
+	}
+
+	if (mktme_status != MKTME_UNINITIALIZED)
+		goto detect_keyid_bits;
+
+	pr_info("x86/tme: enabled by BIOS\n");
+
+	tme_policy = TME_ACTIVATE_POLICY(tme_activate);
+	if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128)
+		pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy);
+
+	tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate);
+	if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) {
+		pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n",
+				tme_crypto_algs);
+		mktme_status = MKTME_DISABLED;
+	}
+detect_keyid_bits:
+	keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate);
+	nr_keyids = (1UL << keyid_bits) - 1;
+	if (nr_keyids) {
+		pr_info_once("x86/mktme: enabled by BIOS\n");
+		pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids);
+	} else {
+		pr_info_once("x86/mktme: disabled by BIOS\n");
+	}
+
+	if (mktme_status == MKTME_UNINITIALIZED) {
+		/* MKTME is usable */
+		mktme_status = MKTME_ENABLED;
+	}
+
+	/*
+	 * KeyID bits effectively lower the number of physical address
+	 * bits.  Update cpuinfo_x86::x86_phys_bits accordingly.
+	 */
+	c->x86_phys_bits -= keyid_bits;
+}
+
 static void early_init_intel(struct cpuinfo_x86 *c)
 {
 	u64 misc_enable;
@@ -339,6 +423,13 @@
 	 */
 	if (detect_extended_topology_early(c) < 0)
 		detect_ht_early(c);
+
+	/*
+	 * Adjust the number of physical bits early because it affects the
+	 * valid bits of the MTRR mask registers.
+	 */
+	if (cpu_has(c, X86_FEATURE_TME))
+		detect_tme_early(c);
 }
 
 #ifdef CONFIG_X86_32
@@ -540,90 +631,6 @@
 	}
 }
 
-#define MSR_IA32_TME_ACTIVATE		0x982
-
-/* Helpers to access TME_ACTIVATE MSR */
-#define TME_ACTIVATE_LOCKED(x)		(x & 0x1)
-#define TME_ACTIVATE_ENABLED(x)		(x & 0x2)
-
-#define TME_ACTIVATE_POLICY(x)		((x >> 4) & 0xf)	/* Bits 7:4 */
-#define TME_ACTIVATE_POLICY_AES_XTS_128	0
-
-#define TME_ACTIVATE_KEYID_BITS(x)	((x >> 32) & 0xf)	/* Bits 35:32 */
-
-#define TME_ACTIVATE_CRYPTO_ALGS(x)	((x >> 48) & 0xffff)	/* Bits 63:48 */
-#define TME_ACTIVATE_CRYPTO_AES_XTS_128	1
-
-/* Values for mktme_status (SW only construct) */
-#define MKTME_ENABLED			0
-#define MKTME_DISABLED			1
-#define MKTME_UNINITIALIZED		2
-static int mktme_status = MKTME_UNINITIALIZED;
-
-static void detect_tme(struct cpuinfo_x86 *c)
-{
-	u64 tme_activate, tme_policy, tme_crypto_algs;
-	int keyid_bits = 0, nr_keyids = 0;
-	static u64 tme_activate_cpu0 = 0;
-
-	rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate);
-
-	if (mktme_status != MKTME_UNINITIALIZED) {
-		if (tme_activate != tme_activate_cpu0) {
-			/* Broken BIOS? */
-			pr_err_once("x86/tme: configuration is inconsistent between CPUs\n");
-			pr_err_once("x86/tme: MKTME is not usable\n");
-			mktme_status = MKTME_DISABLED;
-
-			/* Proceed. We may need to exclude bits from x86_phys_bits. */
-		}
-	} else {
-		tme_activate_cpu0 = tme_activate;
-	}
-
-	if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) {
-		pr_info_once("x86/tme: not enabled by BIOS\n");
-		mktme_status = MKTME_DISABLED;
-		return;
-	}
-
-	if (mktme_status != MKTME_UNINITIALIZED)
-		goto detect_keyid_bits;
-
-	pr_info("x86/tme: enabled by BIOS\n");
-
-	tme_policy = TME_ACTIVATE_POLICY(tme_activate);
-	if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128)
-		pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy);
-
-	tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate);
-	if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) {
-		pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n",
-				tme_crypto_algs);
-		mktme_status = MKTME_DISABLED;
-	}
-detect_keyid_bits:
-	keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate);
-	nr_keyids = (1UL << keyid_bits) - 1;
-	if (nr_keyids) {
-		pr_info_once("x86/mktme: enabled by BIOS\n");
-		pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids);
-	} else {
-		pr_info_once("x86/mktme: disabled by BIOS\n");
-	}
-
-	if (mktme_status == MKTME_UNINITIALIZED) {
-		/* MKTME is usable */
-		mktme_status = MKTME_ENABLED;
-	}
-
-	/*
-	 * KeyID bits effectively lower the number of physical address
-	 * bits.  Update cpuinfo_x86::x86_phys_bits accordingly.
-	 */
-	c->x86_phys_bits -= keyid_bits;
-}
-
 static void init_cpuid_fault(struct cpuinfo_x86 *c)
 {
 	u64 msr;
@@ -758,9 +765,6 @@
 	if (cpu_has(c, X86_FEATURE_VMX))
 		detect_vmx_virtcap(c);
 
-	if (cpu_has(c, X86_FEATURE_TME))
-		detect_tme(c);
-
 	init_intel_misc_features(c);
 
 	if (tsx_ctrl_state == TSX_CTRL_ENABLE)
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/match.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/match.c
@@ -16,12 +16,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, ...)
@@ -34,13 +39,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;
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/amd.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/amd.c
@@ -78,6 +78,7 @@
 
 static struct smca_bank_name smca_names[] = {
 	[SMCA_LS]	= { "load_store",	"Load Store Unit" },
+	[SMCA_LS_V2]	= { "load_store",	"Load Store Unit" },
 	[SMCA_IF]	= { "insn_fetch",	"Instruction Fetch Unit" },
 	[SMCA_L2_CACHE]	= { "l2_cache",		"L2 Cache" },
 	[SMCA_DE]	= { "decode_unit",	"Decode Unit" },
@@ -138,6 +139,7 @@
 
 	/* ZN Core (HWID=0xB0) MCA types */
 	{ SMCA_LS,	 HWID_MCATYPE(0xB0, 0x0), 0x1FFFFF },
+	{ SMCA_LS_V2,	 HWID_MCATYPE(0xB0, 0x10), 0xFFFFFF },
 	{ SMCA_IF,	 HWID_MCATYPE(0xB0, 0x1), 0x3FFF },
 	{ SMCA_L2_CACHE, HWID_MCATYPE(0xB0, 0x2), 0xF },
 	{ SMCA_DE,	 HWID_MCATYPE(0xB0, 0x3), 0x1FF },
@@ -266,10 +268,10 @@
 	smca_set_misc_banks_map(bank, cpu);
 
 	/* Return early if this bank was already initialized. */
-	if (smca_banks[bank].hwid)
+	if (smca_banks[bank].hwid && smca_banks[bank].hwid->hwid_mcatype != 0)
 		return;
 
-	if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
+	if (rdmsr_safe(MSR_AMD64_SMCA_MCx_IPID(bank), &low, &high)) {
 		pr_warn("Failed to read MCA_IPID for bank %d\n", bank);
 		return;
 	}
@@ -1161,9 +1163,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 const char *get_name(unsigned int bank, struct threshold_block *b)
@@ -1196,8 +1201,9 @@
 	return buf_mcatype;
 }
 
-static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
-				     unsigned int block, u32 address)
+static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb,
+				     unsigned int bank, unsigned int block,
+				     u32 address)
 {
 	struct threshold_block *b = NULL;
 	u32 low, high;
@@ -1241,16 +1247,12 @@
 
 	INIT_LIST_HEAD(&b->miscj);
 
-	if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
-		list_add(&b->miscj,
-			 &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
-	} else {
-		per_cpu(threshold_banks, cpu)[bank]->blocks = b;
-	}
+	if (tb->blocks)
+		list_add(&b->miscj, &tb->blocks->miscj);
+	else
+		tb->blocks = b;
 
-	err = kobject_init_and_add(&b->kobj, &threshold_ktype,
-				   per_cpu(threshold_banks, cpu)[bank]->kobj,
-				   get_name(bank, b));
+	err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(bank, b));
 	if (err)
 		goto out_free;
 recurse:
@@ -1258,7 +1260,7 @@
 	if (!address)
 		return 0;
 
-	err = allocate_threshold_blocks(cpu, bank, block, address);
+	err = allocate_threshold_blocks(cpu, tb, bank, block, address);
 	if (err)
 		goto out_free;
 
@@ -1343,8 +1345,6 @@
 		goto out_free;
 	}
 
-	per_cpu(threshold_banks, cpu)[bank] = b;
-
 	if (is_shared_bank(bank)) {
 		refcount_set(&b->cpus, 1);
 
@@ -1355,9 +1355,13 @@
 		}
 	}
 
-	err = allocate_threshold_blocks(cpu, bank, 0, msr_ops.misc(bank));
-	if (!err)
-		goto out;
+	err = allocate_threshold_blocks(cpu, b, bank, 0, msr_ops.misc(bank));
+	if (err)
+		goto out_free;
+
+	per_cpu(threshold_banks, cpu)[bank] = b;
+
+	return 0;
 
  out_free:
 	kfree(b);
@@ -1366,8 +1370,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;
@@ -1377,13 +1385,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-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/core.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/core.c
@@ -42,6 +42,7 @@
 #include <linux/export.h>
 #include <linux/jump_label.h>
 #include <linux/set_memory.h>
+#include <linux/kexec.h>
 
 #include <asm/intel-family.h>
 #include <asm/processor.h>
@@ -310,11 +311,18 @@
 	panic("Panicing machine check CPU died");
 }
 
-static void mce_panic(const char *msg, struct mce *final, char *exp)
+static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
 {
-	int apei_err = 0;
 	struct llist_node *pending;
 	struct mce_evt_llist *l;
+	int apei_err = 0;
+	struct page *p;
+
+	/*
+	 * Allow instrumentation around external facilities usage. Not that it
+	 * matters a whole lot since the machine is going to panic anyway.
+	 */
+	instrumentation_begin();
 
 	if (!fake_panic) {
 		/*
@@ -329,7 +337,7 @@
 	} else {
 		/* Don't log too much for fake panic */
 		if (atomic_inc_return(&mce_fake_panicked) > 1)
-			return;
+			goto out;
 	}
 	pending = mce_gen_pool_prepare_records();
 	/* First print corrected ones that are still unlogged */
@@ -364,9 +372,26 @@
 	if (!fake_panic) {
 		if (panic_timeout == 0)
 			panic_timeout = mca_cfg.panic_timeout;
+
+		/*
+		 * Kdump skips the poisoned page in order to avoid
+		 * touching the error bits again. Poison the page even
+		 * if the error is fatal and the machine is about to
+		 * panic.
+		 */
+		if (kexec_crash_loaded()) {
+			if (final && (final->status & MCI_STATUS_ADDRV)) {
+				p = pfn_to_online_page(final->addr >> PAGE_SHIFT);
+				if (p)
+					SetPageHWPoison(p);
+			}
+		}
 		panic(msg);
 	} else
 		pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg);
+
+out:
+	instrumentation_end();
 }
 
 /* Support code for software error injection */
@@ -388,10 +413,38 @@
 	return -1;
 }
 
+static void ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr)
+{
+	if (wrmsr) {
+		pr_emerg("MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+			 (unsigned int)regs->cx, (unsigned int)regs->dx, (unsigned int)regs->ax,
+			 regs->ip, (void *)regs->ip);
+	} else {
+		pr_emerg("MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+			 (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
+	}
+
+	show_stack_regs(regs);
+
+	panic("MCA architectural violation!\n");
+
+	while (true)
+		cpu_relax();
+}
+
+__visible bool ex_handler_rdmsr_fault(const struct exception_table_entry *fixup,
+				      struct pt_regs *regs, int trapnr,
+				      unsigned long error_code,
+				      unsigned long fault_addr)
+{
+	ex_handler_msr_mce(regs, false);
+	return true;
+}
+
 /* MSR access wrappers used for error injection */
 static u64 mce_rdmsrl(u32 msr)
 {
-	u64 v;
+	DECLARE_ARGS(val, low, high);
 
 	if (__this_cpu_read(injectm.finished)) {
 		int offset = msr_to_offset(msr);
@@ -401,21 +454,33 @@
 		return *(u64 *)((char *)this_cpu_ptr(&injectm) + offset);
 	}
 
-	if (rdmsrl_safe(msr, &v)) {
-		WARN_ONCE(1, "mce: Unable to read MSR 0x%x!\n", msr);
-		/*
-		 * Return zero in case the access faulted. This should
-		 * not happen normally but can happen if the CPU does
-		 * something weird, or if the code is buggy.
-		 */
-		v = 0;
-	}
+	/*
+	 * RDMSR on MCA MSRs should not fault. If they do, this is very much an
+	 * architectural violation and needs to be reported to hw vendor. Panic
+	 * the box to not allow any further progress.
+	 */
+	asm volatile("1: rdmsr\n"
+		     "2:\n"
+		     _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_rdmsr_fault)
+		     : EAX_EDX_RET(val, low, high) : "c" (msr));
+
 
-	return v;
+	return EAX_EDX_VAL(val, low, high);
+}
+
+__visible bool ex_handler_wrmsr_fault(const struct exception_table_entry *fixup,
+				      struct pt_regs *regs, int trapnr,
+				      unsigned long error_code,
+				      unsigned long fault_addr)
+{
+	ex_handler_msr_mce(regs, true);
+	return true;
 }
 
 static void mce_wrmsrl(u32 msr, u64 v)
 {
+	u32 low, high;
+
 	if (__this_cpu_read(injectm.finished)) {
 		int offset = msr_to_offset(msr);
 
@@ -423,7 +488,15 @@
 			*(u64 *)((char *)this_cpu_ptr(&injectm) + offset) = v;
 		return;
 	}
-	wrmsrl(msr, v);
+
+	low  = (u32)v;
+	high = (u32)(v >> 32);
+
+	/* See comment in mce_rdmsrl() */
+	asm volatile("1: wrmsr\n"
+		     "2:\n"
+		     _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_wrmsr_fault)
+		     : : "c" (msr), "a"(low), "d" (high) : "memory");
 }
 
 /*
@@ -533,6 +606,13 @@
 }
 EXPORT_SYMBOL_GPL(mce_is_memory_error);
 
+static bool whole_page(struct mce *m)
+{
+	if (!mca_cfg.ser || !(m->status & MCI_STATUS_MISCV))
+		return true;
+	return MCI_MISC_ADDR_LSB(m->misc) >= PAGE_SHIFT;
+}
+
 bool mce_is_correctable(struct mce *m)
 {
 	if (m->cpuvendor == X86_VENDOR_AMD && m->status & MCI_STATUS_DEFERRED)
@@ -601,7 +681,7 @@
 	if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
 		pfn = mce->addr >> PAGE_SHIFT;
 		if (!memory_failure(pfn, 0))
-			set_mce_nospec(pfn);
+			set_mce_nospec(pfn, whole_page(mce));
 	}
 
 	return NOTIFY_OK;
@@ -636,7 +716,7 @@
 /*
  * Read ADDR and MISC registers.
  */
-static void mce_read_aux(struct mce *m, int i)
+static noinstr void mce_read_aux(struct mce *m, int i)
 {
 	if (m->status & MCI_STATUS_MISCV)
 		m->misc = mce_rdmsrl(msr_ops.misc(i));
@@ -814,8 +894,8 @@
 		if (quirk_no_way_out)
 			quirk_no_way_out(i, m, regs);
 
+		m->bank = i;
 		if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
-			m->bank = i;
 			mce_read_aux(m, i);
 			*msg = tmp;
 			return 1;
@@ -1016,10 +1096,13 @@
  * Synchronize between CPUs after main scanning loop.
  * This invokes the bulk of the Monarch processing.
  */
-static int mce_end(int order)
+static noinstr int mce_end(int order)
 {
-	int ret = -1;
 	u64 timeout = (u64)mca_cfg.monarch_timeout * NSEC_PER_USEC;
+	int ret = -1;
+
+	/* Allow instrumentation around external facilities. */
+	instrumentation_begin();
 
 	if (!timeout)
 		goto reset;
@@ -1063,7 +1146,8 @@
 		/*
 		 * Don't reset anything. That's done by the Monarch.
 		 */
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	/*
@@ -1078,6 +1162,10 @@
 	 * Let others run again.
 	 */
 	atomic_set(&mce_executing, 0);
+
+out:
+	instrumentation_end();
+
 	return ret;
 }
 
@@ -1103,7 +1191,7 @@
 	if (ret)
 		pr_err("Memory error not recovered");
 	else
-		set_mce_nospec(m->addr >> PAGE_SHIFT);
+		set_mce_nospec(m->addr >> PAGE_SHIFT, whole_page(m));
 	return ret;
 }
 
@@ -1306,8 +1394,10 @@
 	 * When there's any problem use only local no_way_out state.
 	 */
 	if (!lmce) {
-		if (mce_end(order) < 0)
-			no_way_out = worst >= MCE_PANIC_SEVERITY;
+		if (mce_end(order) < 0) {
+			if (!no_way_out)
+				no_way_out = worst >= MCE_PANIC_SEVERITY;
+		}
 	} else {
 		/*
 		 * If there was a fatal machine check we should have
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/inject.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/inject.c
@@ -347,7 +347,7 @@
 	char buf[MAX_FLAG_OPT_SIZE], *__buf;
 	int err;
 
-	if (cnt > MAX_FLAG_OPT_SIZE)
+	if (!cnt || cnt > MAX_FLAG_OPT_SIZE)
 		return -EINVAL;
 
 	if (copy_from_user(&buf, ubuf, cnt))
@@ -511,7 +511,7 @@
 	 */
 	if (inj_type == DFR_INT_INJ) {
 		i_mce.status |= MCI_STATUS_DEFERRED;
-		i_mce.status |= (i_mce.status & ~MCI_STATUS_UC);
+		i_mce.status &= ~MCI_STATUS_UC;
 	}
 
 	/*
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/intel.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/intel.c
@@ -489,17 +489,18 @@
 			return;
 
 		if ((val & 3UL) == 1UL) {
-			/* PPIN available but disabled: */
+			/* PPIN locked in disabled mode */
 			return;
 		}
 
-		/* If PPIN is disabled, but not locked, try to enable: */
-		if (!(val & 3UL)) {
+		/* If PPIN is disabled, try to enable */
+		if (!(val & 2UL)) {
 			wrmsrl_safe(MSR_PPIN_CTL,  val | 2UL);
 			rdmsrl_safe(MSR_PPIN_CTL, &val);
 		}
 
-		if ((val & 3UL) == 2UL)
+		/* Is the enable bit set? */
+		if (val & 2UL)
 			set_cpu_cap(c, X86_FEATURE_INTEL_PPIN);
 	}
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/internal.h
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/internal.h
@@ -172,4 +172,14 @@
 static inline bool amd_filter_mce(struct mce *m)			{ return false; };
 #endif
 
+__visible bool ex_handler_rdmsr_fault(const struct exception_table_entry *fixup,
+				      struct pt_regs *regs, int trapnr,
+				      unsigned long error_code,
+				      unsigned long fault_addr);
+
+__visible bool ex_handler_wrmsr_fault(const struct exception_table_entry *fixup,
+				      struct pt_regs *regs, int trapnr,
+				      unsigned long error_code,
+				      unsigned long fault_addr);
+
 #endif /* __X86_MCE_INTERNAL_H__ */
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/severity.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/severity.c
@@ -9,9 +9,11 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
-#include <asm/mce.h>
 #include <linux/uaccess.h>
 
+#include <asm/mce.h>
+#include <asm/intel-family.h>
+
 #include "internal.h"
 
 /*
@@ -40,9 +42,14 @@
 	unsigned char context;
 	unsigned char excp;
 	unsigned char covered;
+	unsigned char cpu_model;
+	unsigned char cpu_minstepping;
+	unsigned char bank_lo, bank_hi;
 	char *msg;
 } severities[] = {
 #define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
+#define BANK_RANGE(l, h) .bank_lo = l, .bank_hi = h
+#define MODEL_STEPPING(m, s) .cpu_model = m, .cpu_minstepping = s
 #define  KERNEL		.context = IN_KERNEL
 #define  USER		.context = IN_USER
 #define  KERNEL_RECOV	.context = IN_KERNEL_RECOV
@@ -97,7 +104,6 @@
 		KEEP, "Corrected error",
 		NOSER, BITCLR(MCI_STATUS_UC)
 		),
-
 	/*
 	 * known AO MCACODs reported via MCE or CMC:
 	 *
@@ -113,6 +119,18 @@
 		AO, "Action optional: last level cache writeback error",
 		SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
 		),
+	/*
+	 * Quirk for Skylake/Cascade Lake. Patrol scrubber may be configured
+	 * to report uncorrected errors using CMCI with a special signature.
+	 * UC=0, MSCOD=0x0010, MCACOD=binary(000X 0000 1100 XXXX) reported
+	 * in one of the memory controller banks.
+	 * Set severity to "AO" for same action as normal patrol scrub error.
+	 */
+	MCESEV(
+		AO, "Uncorrected Patrol Scrub Error",
+		SER, MASK(MCI_STATUS_UC|MCI_ADDR|0xffffeff0, MCI_ADDR|0x001000c0),
+		MODEL_STEPPING(INTEL_FAM6_SKYLAKE_X, 4), BANK_RANGE(13, 18)
+	),
 
 	/* ignore OVER for UCNA */
 	MCESEV(
@@ -320,6 +338,12 @@
 			continue;
 		if (s->excp && excp != s->excp)
 			continue;
+		if (s->cpu_model && boot_cpu_data.x86_model != s->cpu_model)
+			continue;
+		if (s->cpu_minstepping && boot_cpu_data.x86_stepping < s->cpu_minstepping)
+			continue;
+		if (s->bank_lo && (m->bank < s->bank_lo || m->bank > s->bank_hi))
+			continue;
 		if (msg)
 			*msg = s->msg;
 		s->covered = 1;
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mce/therm_throt.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mce/therm_throt.c
@@ -188,7 +188,7 @@
 	/* if we just entered the thermal event */
 	if (new_event) {
 		if (event == THERMAL_THROTTLING_EVENT)
-			pr_crit("CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
+			pr_warn("CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
 				this_cpu,
 				level == CORE_LEVEL ? "Core" : "Package",
 				state->count);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/microcode/amd.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/microcode/amd.c
@@ -55,7 +55,9 @@
 };
 
 static u32 ucode_new_rev;
-static u8 amd_ucode_patch[PATCH_MAX_SIZE];
+
+/* One blob per node. */
+static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE];
 
 /*
  * Microcode patch container file is prepended to the initrd in cpio
@@ -429,7 +431,7 @@
 	patch	= (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
 #else
 	new_rev = &ucode_new_rev;
-	patch	= &amd_ucode_patch;
+	patch	= &amd_ucode_patch[0];
 #endif
 
 	desc.cpuid_1_eax = cpuid_1_eax;
@@ -441,7 +443,13 @@
 		return ret;
 
 	native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
-	if (rev >= mc->hdr.patch_id)
+
+	/*
+	 * Allow application of the same revision to pick up SMT-specific
+	 * changes even if the revision of the other SMT thread is already
+	 * up-to-date.
+	 */
+	if (rev > mc->hdr.patch_id)
 		return ret;
 
 	if (!__apply_microcode_amd(mc)) {
@@ -523,8 +531,12 @@
 
 	native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 
-	/* Check whether we have saved a new patch already: */
-	if (*new_rev && rev < mc->hdr.patch_id) {
+	/*
+	 * Check whether a new patch has been saved already. Also, allow application of
+	 * the same revision in order to pick up SMT-thread-specific configuration even
+	 * if the sibling SMT thread already has an up-to-date revision.
+	 */
+	if (*new_rev && rev <= mc->hdr.patch_id) {
 		if (!__apply_microcode_amd(mc)) {
 			*new_rev = mc->hdr.patch_id;
 			return;
@@ -538,8 +550,7 @@
 	apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false);
 }
 
-static enum ucode_state
-load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
+static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
 
 int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
 {
@@ -557,19 +568,19 @@
 	if (!desc.mc)
 		return -EINVAL;
 
-	ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size);
+	ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
 	if (ret > UCODE_UPDATED)
 		return -EINVAL;
 
 	return 0;
 }
 
-void reload_ucode_amd(void)
+void reload_ucode_amd(unsigned int cpu)
 {
-	struct microcode_amd *mc;
 	u32 rev, dummy;
+	struct microcode_amd *mc;
 
-	mc = (struct microcode_amd *)amd_ucode_patch;
+	mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)];
 
 	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 
@@ -689,7 +700,7 @@
 	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 
 	/* need to apply patch? */
-	if (rev >= mc_amd->hdr.patch_id) {
+	if (rev > mc_amd->hdr.patch_id) {
 		ret = UCODE_OK;
 		goto out;
 	}
@@ -783,6 +794,7 @@
 		kfree(patch);
 		return -EINVAL;
 	}
+	patch->size = *patch_size;
 
 	mc_hdr      = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
 	proc_id     = mc_hdr->processor_rev_id;
@@ -834,9 +846,10 @@
 	return UCODE_OK;
 }
 
-static enum ucode_state
-load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
+static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
 {
+	struct cpuinfo_x86 *c;
+	unsigned int nid, cpu;
 	struct ucode_patch *p;
 	enum ucode_state ret;
 
@@ -849,22 +862,22 @@
 		return ret;
 	}
 
-	p = find_patch(0);
-	if (!p) {
-		return ret;
-	} else {
-		if (boot_cpu_data.microcode >= p->patch_id)
-			return ret;
+	for_each_node(nid) {
+		cpu = cpumask_first(cpumask_of_node(nid));
+		c = &cpu_data(cpu);
+
+		p = find_patch(cpu);
+		if (!p)
+			continue;
 
-		ret = UCODE_NEW;
-	}
+		if (c->microcode >= p->patch_id)
+			continue;
 
-	/* save BSP's matching patch for early load */
-	if (!save)
-		return ret;
+		ret = UCODE_NEW;
 
-	memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
-	memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), PATCH_MAX_SIZE));
+		memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE);
+		memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
+	}
 
 	return ret;
 }
@@ -890,12 +903,11 @@
 {
 	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 || !bsp)
+	if (!refresh_fw)
 		return UCODE_OK;
 
 	if (c->x86 >= 0x15)
@@ -910,7 +922,7 @@
 	if (!verify_container(fw->data, fw->size, false))
 		goto fw_release;
 
-	ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
+	ret = load_microcode_amd(c->x86, fw->data, fw->size);
 
  fw_release:
 	release_firmware(fw);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/microcode/core.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/microcode/core.c
@@ -322,7 +322,7 @@
 #endif
 }
 
-void reload_early_microcode(void)
+void reload_early_microcode(unsigned int cpu)
 {
 	int vendor, family;
 
@@ -336,7 +336,7 @@
 		break;
 	case X86_VENDOR_AMD:
 		if (family >= 0x10)
-			reload_ucode_amd();
+			reload_ucode_amd(cpu);
 		break;
 	default:
 		break;
@@ -626,16 +626,16 @@
 	if (val != 1)
 		return size;
 
-	tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true);
-	if (tmp_ret != UCODE_NEW)
-		return size;
-
 	get_online_cpus();
 
 	ret = check_online_cpus();
 	if (ret)
 		goto put;
 
+	tmp_ret = microcode_ops->request_microcode_fw(bsp, &microcode_pdev->dev, true);
+	if (tmp_ret != UCODE_NEW)
+		goto put;
+
 	mutex_lock(&microcode_mutex);
 	ret = microcode_reload_late();
 	mutex_unlock(&microcode_mutex);
@@ -772,9 +772,9 @@
 };
 
 /**
- * mc_bp_resume - Update boot CPU microcode during resume.
+ * microcode_bsp_resume - Update boot CPU microcode during resume.
  */
-static void mc_bp_resume(void)
+void microcode_bsp_resume(void)
 {
 	int cpu = smp_processor_id();
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -782,11 +782,11 @@
 	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 = {
-	.resume			= mc_bp_resume,
+	.resume			= microcode_bsp_resume,
 };
 
 static int mc_cpu_starting(unsigned int cpu)
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/microcode/intel.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/microcode/intel.c
@@ -100,53 +100,6 @@
 	return find_matching_signature(mc, csig, cpf);
 }
 
-/*
- * Given CPU signature and a microcode patch, this function finds if the
- * microcode patch has matching family and model with the CPU.
- *
- * %true - if there's a match
- * %false - otherwise
- */
-static bool microcode_matches(struct microcode_header_intel *mc_header,
-			      unsigned long sig)
-{
-	unsigned long total_size = get_totalsize(mc_header);
-	unsigned long data_size = get_datasize(mc_header);
-	struct extended_sigtable *ext_header;
-	unsigned int fam_ucode, model_ucode;
-	struct extended_signature *ext_sig;
-	unsigned int fam, model;
-	int ext_sigcount, i;
-
-	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 true;
-
-	/* Look for ext. headers: */
-	if (total_size <= data_size + MC_HEADER_SIZE)
-		return false;
-
-	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 true;
-
-		ext_sig++;
-	}
-	return false;
-}
-
 static struct ucode_patch *memdup_patch(void *data, unsigned int size)
 {
 	struct ucode_patch *p;
@@ -164,7 +117,7 @@
 	return p;
 }
 
-static void save_microcode_patch(void *data, unsigned int size)
+static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size)
 {
 	struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
 	struct ucode_patch *iter, *tmp, *p = NULL;
@@ -210,6 +163,9 @@
 	if (!p)
 		return;
 
+	if (!find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
+		return;
+
 	/*
 	 * Save for early loading. On 32-bit, that needs to be a physical
 	 * address as the APs are running from physical addresses, before
@@ -344,13 +300,14 @@
 
 		size -= mc_size;
 
-		if (!microcode_matches(mc_header, uci->cpu_sig.sig)) {
+		if (!find_matching_signature(data, uci->cpu_sig.sig,
+					     uci->cpu_sig.pf)) {
 			data += mc_size;
 			continue;
 		}
 
 		if (save) {
-			save_microcode_patch(data, mc_size);
+			save_microcode_patch(uci, data, mc_size);
 			goto next;
 		}
 
@@ -483,14 +440,14 @@
  * Save this microcode patch. It will be loaded early when a CPU is
  * hot-added or resumes.
  */
-static void save_mc_for_early(u8 *mc, unsigned int size)
+static void save_mc_for_early(struct ucode_cpu_info *uci, u8 *mc, unsigned int size)
 {
 	/* Synchronization during CPU hotplug. */
 	static DEFINE_MUTEX(x86_cpu_microcode_mutex);
 
 	mutex_lock(&x86_cpu_microcode_mutex);
 
-	save_microcode_patch(mc, size);
+	save_microcode_patch(uci, mc, size);
 	show_saved_mc();
 
 	mutex_unlock(&x86_cpu_microcode_mutex);
@@ -702,7 +659,6 @@
 	else
 		iup = &intel_ucode_patch;
 
-reget:
 	if (!*iup) {
 		patch = __load_ucode_intel(&uci);
 		if (!patch)
@@ -713,12 +669,7 @@
 
 	uci.mc = *iup;
 
-	if (apply_microcode_early(&uci, true)) {
-		/* Mixed-silicon system? Try to refetch the proper patch: */
-		*iup = NULL;
-
-		goto reget;
-	}
+	apply_microcode_early(&uci, true);
 }
 
 static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
@@ -934,7 +885,7 @@
 	 * permanent memory. So it will be loaded early when a CPU is hot added
 	 * or resumes.
 	 */
-	save_mc_for_early(new_mc, new_mc_size);
+	save_mc_for_early(uci, new_mc, new_mc_size);
 
 	pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
 		 cpu, new_rev, uci->cpu_sig.rev);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mshyperv.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mshyperv.c
@@ -82,7 +82,7 @@
 	inc_irq_stat(hyperv_stimer0_count);
 	if (hv_stimer0_handler)
 		hv_stimer0_handler();
-	add_interrupt_randomness(HYPERV_STIMER0_VECTOR, 0);
+	add_interrupt_randomness(HYPERV_STIMER0_VECTOR);
 	ack_APIC_irq();
 
 	exiting_irq();
@@ -227,8 +227,8 @@
 	ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
 	ms_hyperv.hints    = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
 
-	pr_info("Hyper-V: features 0x%x, hints 0x%x\n",
-		ms_hyperv.features, ms_hyperv.hints);
+	pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n",
+		ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
 
 	ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS);
 	ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS);
@@ -263,6 +263,16 @@
 			cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
 	}
 
+	/*
+	 * Hyper-V expects to get crash register data or kmsg when
+	 * crash enlightment is available and system crashes. Set
+	 * crash_kexec_post_notifiers to be true to make sure that
+	 * calling crash enlightment interface before running kdump
+	 * kernel.
+	 */
+	if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
+		crash_kexec_post_notifiers = true;
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
 	    ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mtrr/generic.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mtrr/generic.c
@@ -167,9 +167,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;
@@ -261,6 +258,9 @@
 	int repeat;
 	u64 partial_end;
 
+	/* Make end inclusive instead of exclusive */
+	end--;
+
 	if (!mtrr_state_set)
 		return MTRR_TYPE_INVALID;
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/mtrr/mtrr.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/mtrr/mtrr.c
@@ -794,8 +794,6 @@
 	if (!use_intel() || mtrr_aps_delayed_init)
 		return;
 
-	rcu_cpu_starting(smp_processor_id());
-
 	/*
 	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries
 	 * changed, but this routine will be called in cpu boot time,
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/resctrl/core.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/resctrl/core.c
@@ -260,6 +260,7 @@
 	r->num_closid = edx.split.cos_max + 1;
 	r->membw.max_delay = eax.split.max_delay + 1;
 	r->default_ctrl = MAX_MBA_BW;
+	r->membw.mbm_width = MBM_CNTR_WIDTH;
 	if (ecx & MBA_IS_LINEAR) {
 		r->membw.delay_linear = true;
 		r->membw.min_bw = MAX_MBA_BW - r->membw.max_delay;
@@ -289,6 +290,7 @@
 	/* AMD does not use delay */
 	r->membw.delay_linear = false;
 
+	r->membw.mbm_width = MBM_CNTR_WIDTH_AMD;
 	r->membw.min_bw = 0;
 	r->membw.bw_gran = 1;
 	/* Max value is 2048, Data width should be 4 in decimal */
@@ -578,12 +580,16 @@
 	d->id = id;
 	cpumask_set_cpu(cpu, &d->cpu_mask);
 
+	rdt_domain_reconfigure_cdp(r);
+
 	if (r->alloc_capable && domain_setup_ctrlval(r, d)) {
 		kfree(d);
 		return;
 	}
 
 	if (r->mon_capable && domain_setup_mon_state(r, d)) {
+		kfree(d->ctrl_val);
+		kfree(d->mbps_val);
 		kfree(d);
 		return;
 	}
@@ -618,7 +624,7 @@
 		if (static_branch_unlikely(&rdt_mon_enable_key))
 			rmdir_mondata_subdir_allrdtgrp(r, d->id);
 		list_del(&d->list);
-		if (is_mbm_enabled())
+		if (r->mon_capable && is_mbm_enabled())
 			cancel_delayed_work(&d->mbm_over);
 		if (is_llc_occupancy_enabled() &&  has_busy_rmid(r, d)) {
 			/*
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/resctrl/internal.h
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/resctrl/internal.h
@@ -32,6 +32,7 @@
 #define CQM_LIMBOCHECK_INTERVAL	1000
 
 #define MBM_CNTR_WIDTH			24
+#define MBM_CNTR_WIDTH_AMD		44
 #define MBM_OVERFLOW_INTERVAL		1000
 #define MAX_MBA_BW			100u
 #define MBA_IS_LINEAR			0x4
@@ -57,6 +58,7 @@
 }
 
 DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
+DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
 
 /**
  * struct mon_evt - Entry in the event list of a resource
@@ -274,7 +276,6 @@
  * struct mbm_state - status for each MBM counter in each domain
  * @chunks:	Total data moved (multiply by rdt_group.mon_scale to get bytes)
  * @prev_msr	Value of IA32_QM_CTR for this RMID last time we read it
- * @chunks_bw	Total local data moved. Used for bandwidth calculation
  * @prev_bw_msr:Value of previous IA32_QM_CTR for bandwidth counting
  * @prev_bw	The most recent bandwidth in MBps
  * @delta_bw	Difference between the current and previous bandwidth
@@ -283,7 +284,6 @@
 struct mbm_state {
 	u64	chunks;
 	u64	prev_msr;
-	u64	chunks_bw;
 	u64	prev_bw_msr;
 	u32	prev_bw;
 	u32	delta_bw;
@@ -367,6 +367,7 @@
  * @min_bw:		Minimum memory bandwidth percentage user can request
  * @bw_gran:		Granularity at which the memory bandwidth is allocated
  * @delay_linear:	True if memory B/W delay is in linear scale
+ * @mbm_width:		memory B/W monitor counter width
  * @mba_sc:		True if MBA software controller(mba_sc) is enabled
  * @mb_map:		Mapping of memory B/W percentage to memory B/W delay
  */
@@ -375,6 +376,7 @@
 	u32		min_bw;
 	u32		bw_gran;
 	u32		delay_linear;
+	u32		mbm_width;
 	bool		mba_sc;
 	u32		*mb_map;
 };
@@ -600,5 +602,6 @@
 void __check_limbo(struct rdt_domain *d, bool force_free);
 bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r);
 bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r);
+void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
 
 #endif /* _ASM_X86_RESCTRL_INTERNAL_H */
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/resctrl/monitor.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -216,21 +216,21 @@
 
 static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr)
 {
-	u64 shift = 64 - MBM_CNTR_WIDTH, chunks;
+	u64 shift, chunks;
 
+	shift = 64 - rdt_resources_all[RDT_RESOURCE_MBA].membw.mbm_width;
 	chunks = (cur_msr << shift) - (prev_msr << shift);
 	return chunks >>= shift;
 }
 
-static int __mon_event_count(u32 rmid, struct rmid_read *rr)
+static u64 __mon_event_count(u32 rmid, struct rmid_read *rr)
 {
 	struct mbm_state *m;
 	u64 chunks, tval;
 
 	tval = __rmid_read(rmid, rr->evtid);
 	if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) {
-		rr->val = tval;
-		return -EINVAL;
+		return tval;
 	}
 	switch (rr->evtid) {
 	case QOS_L3_OCCUP_EVENT_ID:
@@ -244,10 +244,10 @@
 		break;
 	default:
 		/*
-		 * Code would never reach here because
-		 * an invalid event id would fail the __rmid_read.
+		 * Code would never reach here because an invalid
+		 * event id would fail the __rmid_read.
 		 */
-		return -EINVAL;
+		return RMID_VAL_ERROR;
 	}
 
 	if (rr->first) {
@@ -279,8 +279,6 @@
 		return;
 
 	chunks = mbm_overflow_count(m->prev_bw_msr, tval);
-	m->chunks_bw += chunks;
-	m->chunks = m->chunks_bw;
 	cur_bw = (chunks * r->mon_scale) >> 20;
 
 	if (m->delta_comp)
@@ -299,23 +297,29 @@
 	struct rdtgroup *rdtgrp, *entry;
 	struct rmid_read *rr = info;
 	struct list_head *head;
+	u64 ret_val;
 
 	rdtgrp = rr->rgrp;
 
-	if (__mon_event_count(rdtgrp->mon.rmid, rr))
-		return;
+	ret_val = __mon_event_count(rdtgrp->mon.rmid, rr);
 
 	/*
-	 * For Ctrl groups read data from child monitor groups.
+	 * For Ctrl groups read data from child monitor groups and
+	 * add them together. Count events which are read successfully.
+	 * Discard the rmid_read's reporting errors.
 	 */
 	head = &rdtgrp->mon.crdtgrp_list;
 
 	if (rdtgrp->type == RDTCTRL_GROUP) {
 		list_for_each_entry(entry, head, mon.crdtgrp_list) {
-			if (__mon_event_count(entry->mon.rmid, rr))
-				return;
+			if (__mon_event_count(entry->mon.rmid, rr) == 0)
+				ret_val = 0;
 		}
 	}
+
+	/* Report error if none of rmid_reads are successful */
+	if (ret_val)
+		rr->val = ret_val;
 }
 
 /*
@@ -450,15 +454,14 @@
 	}
 	if (is_mbm_local_enabled()) {
 		rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID;
+		__mon_event_count(rmid, &rr);
 
 		/*
 		 * Call the MBA software controller only for the
 		 * control groups and when user has enabled
 		 * the software controller explicitly.
 		 */
-		if (!is_mba_sc(NULL))
-			__mon_event_count(rmid, &rr);
-		else
+		if (is_mba_sc(NULL))
 			mbm_bw_count(rmid, &rr);
 	}
 }
@@ -514,7 +517,7 @@
 
 	mutex_lock(&rdtgroup_mutex);
 
-	if (!static_branch_likely(&rdt_enable_key))
+	if (!static_branch_likely(&rdt_mon_enable_key))
 		goto out_unlock;
 
 	d = get_domain_from_cpu(cpu, &rdt_resources_all[RDT_RESOURCE_L3]);
@@ -543,7 +546,7 @@
 	unsigned long delay = msecs_to_jiffies(delay_ms);
 	int cpu;
 
-	if (!static_branch_likely(&rdt_enable_key))
+	if (!static_branch_likely(&rdt_mon_enable_key))
 		return;
 	cpu = cpumask_any(&dom->cpu_mask);
 	dom->mbm_work_cpu = cpu;
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/resctrl/pseudo_lock.c
@@ -416,6 +416,7 @@
 	struct pseudo_lock_region *plr = rdtgrp->plr;
 	u32 rmid_p, closid_p;
 	unsigned long i;
+	u64 saved_msr;
 #ifdef CONFIG_KASAN
 	/*
 	 * The registers used for local register variables are also used
@@ -459,6 +460,7 @@
 	 * the buffer and evict pseudo-locked memory read earlier from the
 	 * cache.
 	 */
+	saved_msr = __rdmsr(MSR_MISC_FEATURE_CONTROL);
 	__wrmsr(MSR_MISC_FEATURE_CONTROL, prefetch_disable_bits, 0x0);
 	closid_p = this_cpu_read(pqr_state.cur_closid);
 	rmid_p = this_cpu_read(pqr_state.cur_rmid);
@@ -510,7 +512,7 @@
 	__wrmsr(IA32_PQR_ASSOC, rmid_p, closid_p);
 
 	/* Re-enable the hardware prefetcher(s) */
-	wrmsr(MSR_MISC_FEATURE_CONTROL, 0x0, 0x0);
+	wrmsrl(MSR_MISC_FEATURE_CONTROL, saved_msr);
 	local_irq_enable();
 
 	plr->thread_done = 1;
@@ -867,6 +869,7 @@
 static int measure_cycles_lat_fn(void *_plr)
 {
 	struct pseudo_lock_region *plr = _plr;
+	u32 saved_low, saved_high;
 	unsigned long i;
 	u64 start, end;
 	void *mem_r;
@@ -875,6 +878,7 @@
 	/*
 	 * Disable hardware prefetchers.
 	 */
+	rdmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
 	wrmsr(MSR_MISC_FEATURE_CONTROL, prefetch_disable_bits, 0x0);
 	mem_r = READ_ONCE(plr->kmem);
 	/*
@@ -891,7 +895,7 @@
 		end = rdtsc_ordered();
 		trace_pseudo_lock_mem_latency((u32)(end - start));
 	}
-	wrmsr(MSR_MISC_FEATURE_CONTROL, 0x0, 0x0);
+	wrmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
 	local_irq_enable();
 	plr->thread_done = 1;
 	wake_up_interruptible(&plr->lock_thread_wq);
@@ -936,6 +940,7 @@
 	u64 hits_before = 0, hits_after = 0, miss_before = 0, miss_after = 0;
 	struct perf_event *miss_event, *hit_event;
 	int hit_pmcnum, miss_pmcnum;
+	u32 saved_low, saved_high;
 	unsigned int line_size;
 	unsigned int size;
 	unsigned long i;
@@ -969,6 +974,7 @@
 	/*
 	 * Disable hardware prefetchers.
 	 */
+	rdmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
 	wrmsr(MSR_MISC_FEATURE_CONTROL, prefetch_disable_bits, 0x0);
 
 	/* Initialize rest of local variables */
@@ -1027,7 +1033,7 @@
 	 */
 	rmb();
 	/* Re-enable hardware prefetchers */
-	wrmsr(MSR_MISC_FEATURE_CONTROL, 0x0, 0x0);
+	wrmsr(MSR_MISC_FEATURE_CONTROL, saved_low, saved_high);
 	local_irq_enable();
 out_hit:
 	perf_event_release_kernel(hit_event);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -311,7 +311,7 @@
 	 * executing task might have its own closid selected. Just reuse
 	 * the context switch code.
 	 */
-	resctrl_sched_in();
+	resctrl_sched_in(current);
 }
 
 /*
@@ -507,85 +507,102 @@
 	return ret ?: nbytes;
 }
 
-struct task_move_callback {
-	struct callback_head	work;
-	struct rdtgroup		*rdtgrp;
-};
-
-static void move_myself(struct callback_head *head)
+/**
+ * rdtgroup_remove - the helper to remove resource group safely
+ * @rdtgrp: resource group to remove
+ *
+ * On resource group creation via a mkdir, an extra kernfs_node reference is
+ * taken to ensure that the rdtgroup structure remains accessible for the
+ * rdtgroup_kn_unlock() calls where it is removed.
+ *
+ * Drop the extra reference here, then free the rdtgroup structure.
+ *
+ * Return: void
+ */
+static void rdtgroup_remove(struct rdtgroup *rdtgrp)
 {
-	struct task_move_callback *callback;
-	struct rdtgroup *rdtgrp;
-
-	callback = container_of(head, struct task_move_callback, work);
-	rdtgrp = callback->rdtgrp;
+	kernfs_put(rdtgrp->kn);
+	kfree(rdtgrp);
+}
 
+static void _update_task_closid_rmid(void *task)
+{
 	/*
-	 * If resource group was deleted before this task work callback
-	 * was invoked, then assign the task to root group and free the
-	 * resource group.
+	 * If the task is still current on this CPU, update PQR_ASSOC MSR.
+	 * Otherwise, the MSR is updated when the task is scheduled in.
 	 */
-	if (atomic_dec_and_test(&rdtgrp->waitcount) &&
-	    (rdtgrp->flags & RDT_DELETED)) {
-		current->closid = 0;
-		current->rmid = 0;
-		kfree(rdtgrp);
-	}
-
-	preempt_disable();
-	/* update PQR_ASSOC MSR to make resource group go into effect */
-	resctrl_sched_in();
-	preempt_enable();
+	if (task == current)
+		resctrl_sched_in(task);
+}
 
-	kfree(callback);
+static void update_task_closid_rmid(struct task_struct *t)
+{
+	if (IS_ENABLED(CONFIG_SMP) && task_curr(t))
+		smp_call_function_single(task_cpu(t), _update_task_closid_rmid, t, 1);
+	else
+		_update_task_closid_rmid(t);
 }
 
 static int __rdtgroup_move_task(struct task_struct *tsk,
 				struct rdtgroup *rdtgrp)
 {
-	struct task_move_callback *callback;
-	int ret;
-
-	callback = kzalloc(sizeof(*callback), GFP_KERNEL);
-	if (!callback)
-		return -ENOMEM;
-	callback->work.func = move_myself;
-	callback->rdtgrp = rdtgrp;
+	/* If the task is already in rdtgrp, no need to move the task. */
+	if ((rdtgrp->type == RDTCTRL_GROUP && tsk->closid == rdtgrp->closid &&
+	     tsk->rmid == rdtgrp->mon.rmid) ||
+	    (rdtgrp->type == RDTMON_GROUP && tsk->rmid == rdtgrp->mon.rmid &&
+	     tsk->closid == rdtgrp->mon.parent->closid))
+		return 0;
 
 	/*
-	 * Take a refcount, so rdtgrp cannot be freed before the
-	 * callback has been invoked.
+	 * Set the task's closid/rmid before the PQR_ASSOC MSR can be
+	 * updated by them.
+	 *
+	 * For ctrl_mon groups, move both closid and rmid.
+	 * For monitor groups, can move the tasks only from
+	 * their parent CTRL group.
 	 */
-	atomic_inc(&rdtgrp->waitcount);
-	ret = task_work_add(tsk, &callback->work, true);
-	if (ret) {
-		/*
-		 * Task is exiting. Drop the refcount and free the callback.
-		 * No need to check the refcount as the group cannot be
-		 * deleted before the write function unlocks rdtgroup_mutex.
-		 */
-		atomic_dec(&rdtgrp->waitcount);
-		kfree(callback);
-		rdt_last_cmd_puts("Task exited\n");
-	} else {
-		/*
-		 * For ctrl_mon groups move both closid and rmid.
-		 * For monitor groups, can move the tasks only from
-		 * their parent CTRL group.
-		 */
-		if (rdtgrp->type == RDTCTRL_GROUP) {
-			tsk->closid = rdtgrp->closid;
-			tsk->rmid = rdtgrp->mon.rmid;
-		} else if (rdtgrp->type == RDTMON_GROUP) {
-			if (rdtgrp->mon.parent->closid == tsk->closid) {
-				tsk->rmid = rdtgrp->mon.rmid;
-			} else {
-				rdt_last_cmd_puts("Can't move task to different control group\n");
-				ret = -EINVAL;
-			}
+
+	if (rdtgrp->type == RDTCTRL_GROUP) {
+		WRITE_ONCE(tsk->closid, rdtgrp->closid);
+		WRITE_ONCE(tsk->rmid, rdtgrp->mon.rmid);
+	} else if (rdtgrp->type == RDTMON_GROUP) {
+		if (rdtgrp->mon.parent->closid == tsk->closid) {
+			WRITE_ONCE(tsk->rmid, rdtgrp->mon.rmid);
+		} else {
+			rdt_last_cmd_puts("Can't move task to different control group\n");
+			return -EINVAL;
 		}
 	}
-	return ret;
+
+	/*
+	 * Ensure the task's closid and rmid are written before determining if
+	 * the task is current that will decide if it will be interrupted.
+	 * This pairs with the full barrier between the rq->curr update and
+	 * resctrl_sched_in() during context switch.
+	 */
+	smp_mb();
+
+	/*
+	 * By now, the task's closid and rmid are set. If the task is current
+	 * on a CPU, the PQR_ASSOC MSR needs to be updated to make the resource
+	 * group go into effect. If the task is not current, the MSR will be
+	 * updated when the task is scheduled in.
+	 */
+	update_task_closid_rmid(tsk);
+
+	return 0;
+}
+
+static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
+{
+	return (rdt_alloc_capable &&
+	       (r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
+}
+
+static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
+{
+	return (rdt_mon_capable &&
+	       (r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
 }
 
 /**
@@ -603,8 +620,7 @@
 
 	rcu_read_lock();
 	for_each_process_thread(p, t) {
-		if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
-		    (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid)) {
+		if (is_closid_match(t, r) || is_rmid_match(t, r)) {
 			ret = 1;
 			break;
 		}
@@ -699,12 +715,15 @@
 static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
 {
 	struct task_struct *p, *t;
+	pid_t pid;
 
 	rcu_read_lock();
 	for_each_process_thread(p, t) {
-		if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
-		    (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid))
-			seq_printf(s, "%d\n", t->pid);
+		if (is_closid_match(t, r) || is_rmid_match(t, r)) {
+			pid = task_pid_vnr(t);
+			if (pid)
+				seq_printf(s, "%d\n", pid);
+		}
 	}
 	rcu_read_unlock();
 }
@@ -1027,6 +1046,7 @@
 	_d_cdp = rdt_find_domain(_r_cdp, d->id, NULL);
 	if (WARN_ON(IS_ERR_OR_NULL(_d_cdp))) {
 		_r_cdp = NULL;
+		_d_cdp = NULL;
 		ret = -EINVAL;
 	}
 
@@ -1617,7 +1637,6 @@
 	if (IS_ERR(kn_subdir))
 		return PTR_ERR(kn_subdir);
 
-	kernfs_get(kn_subdir);
 	ret = rdtgroup_kn_set_ugid(kn_subdir);
 	if (ret)
 		return ret;
@@ -1640,7 +1659,6 @@
 	kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
 	if (IS_ERR(kn_info))
 		return PTR_ERR(kn_info);
-	kernfs_get(kn_info);
 
 	ret = rdtgroup_add_files(kn_info, RF_TOP_INFO);
 	if (ret)
@@ -1661,12 +1679,6 @@
 			goto out_destroy;
 	}
 
-	/*
-	 * This extra ref will be put in kernfs_remove() and guarantees
-	 * that @rdtgrp->kn is always accessible.
-	 */
-	kernfs_get(kn_info);
-
 	ret = rdtgroup_kn_set_ugid(kn_info);
 	if (ret)
 		goto out_destroy;
@@ -1695,12 +1707,6 @@
 	if (dest_kn)
 		*dest_kn = kn;
 
-	/*
-	 * This extra ref will be put in kernfs_remove() and guarantees
-	 * that @rdtgrp->kn is always accessible.
-	 */
-	kernfs_get(kn);
-
 	ret = rdtgroup_kn_set_ugid(kn);
 	if (ret)
 		goto out_destroy;
@@ -1741,9 +1747,6 @@
 	struct rdt_domain *d;
 	int cpu;
 
-	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	if (level == RDT_RESOURCE_L3)
 		update = l3_qos_cfg_update;
 	else if (level == RDT_RESOURCE_L2)
@@ -1751,6 +1754,9 @@
 	else
 		return -EINVAL;
 
+	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+		return -ENOMEM;
+
 	r_l = &rdt_resources_all[level];
 	list_for_each_entry(d, &r_l->domains, list) {
 		/* Pick one CPU from each domain instance to update MSR */
@@ -1769,6 +1775,19 @@
 	return 0;
 }
 
+/* Restore the qos cfg state when a domain comes online */
+void rdt_domain_reconfigure_cdp(struct rdt_resource *r)
+{
+	if (!r->alloc_capable)
+		return;
+
+	if (r == &rdt_resources_all[RDT_RESOURCE_L2DATA])
+		l2_qos_cfg_update(&r->alloc_enabled);
+
+	if (r == &rdt_resources_all[RDT_RESOURCE_L3DATA])
+		l3_qos_cfg_update(&r->alloc_enabled);
+}
+
 /*
  * Enable or disable the MBA software controller
  * which helps user specify bandwidth in MBps.
@@ -1914,8 +1933,7 @@
 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
 			rdtgroup_pseudo_lock_remove(rdtgrp);
 		kernfs_unbreak_active_protection(kn);
-		kernfs_put(rdtgrp->kn);
-		kfree(rdtgrp);
+		rdtgroup_remove(rdtgrp);
 	} else {
 		kernfs_unbreak_active_protection(kn);
 	}
@@ -1970,17 +1988,15 @@
 
 	if (rdt_mon_capable) {
 		ret = mongroup_create_dir(rdtgroup_default.kn,
-					  NULL, "mon_groups",
+					  &rdtgroup_default, "mon_groups",
 					  &kn_mongrp);
 		if (ret < 0)
 			goto out_info;
-		kernfs_get(kn_mongrp);
 
 		ret = mkdir_mondata_all(rdtgroup_default.kn,
 					&rdtgroup_default, &kn_mondata);
 		if (ret < 0)
 			goto out_mongrp;
-		kernfs_get(kn_mondata);
 		rdtgroup_default.mon.mon_data_kn = kn_mondata;
 	}
 
@@ -2146,18 +2162,6 @@
 	return 0;
 }
 
-static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
-{
-	return (rdt_alloc_capable &&
-		(r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
-}
-
-static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
-{
-	return (rdt_mon_capable &&
-		(r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
-}
-
 /*
  * Move tasks from one to the other group. If @from is NULL, then all tasks
  * in the systems are moved unconditionally (used for teardown).
@@ -2175,22 +2179,26 @@
 	for_each_process_thread(p, t) {
 		if (!from || is_closid_match(t, from) ||
 		    is_rmid_match(t, from)) {
-			t->closid = to->closid;
-			t->rmid = to->mon.rmid;
+			WRITE_ONCE(t->closid, to->closid);
+			WRITE_ONCE(t->rmid, to->mon.rmid);
 
-#ifdef CONFIG_SMP
 			/*
-			 * This is safe on x86 w/o barriers as the ordering
-			 * of writing to task_cpu() and t->on_cpu is
-			 * reverse to the reading here. The detection is
-			 * inaccurate as tasks might move or schedule
-			 * before the smp function call takes place. In
-			 * such a case the function call is pointless, but
+			 * Order the closid/rmid stores above before the loads
+			 * in task_curr(). This pairs with the full barrier
+			 * between the rq->curr update and resctrl_sched_in()
+			 * during context switch.
+			 */
+			smp_mb();
+
+			/*
+			 * If the task is on a CPU, set the CPU in the mask.
+			 * The detection is inaccurate as tasks might move or
+			 * schedule before the smp function call takes place.
+			 * In such a case the function call is pointless, but
 			 * there is no other side effect.
 			 */
-			if (mask && t->on_cpu)
+			if (IS_ENABLED(CONFIG_SMP) && mask && task_curr(t))
 				cpumask_set_cpu(task_cpu(t), mask);
-#endif
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -2205,7 +2213,11 @@
 	list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) {
 		free_rmid(sentry->mon.rmid);
 		list_del(&sentry->mon.crdtgrp_list);
-		kfree(sentry);
+
+		if (atomic_read(&sentry->waitcount) != 0)
+			sentry->flags = RDT_DELETED;
+		else
+			rdtgroup_remove(sentry);
 	}
 }
 
@@ -2243,7 +2255,11 @@
 
 		kernfs_remove(rdtgrp->kn);
 		list_del(&rdtgrp->rdtgroup_list);
-		kfree(rdtgrp);
+
+		if (atomic_read(&rdtgrp->waitcount) != 0)
+			rdtgrp->flags = RDT_DELETED;
+		else
+			rdtgroup_remove(rdtgrp);
 	}
 	/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
 	update_closid_rmid(cpu_online_mask, &rdtgroup_default);
@@ -2343,11 +2359,6 @@
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
 
-	/*
-	 * This extra ref will be put in kernfs_remove() and guarantees
-	 * that kn is always accessible.
-	 */
-	kernfs_get(kn);
 	ret = rdtgroup_kn_set_ugid(kn);
 	if (ret)
 		goto out_destroy;
@@ -2446,7 +2457,7 @@
 	/*
 	 * Create the mon_data directory first.
 	 */
-	ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn);
+	ret = mongroup_create_dir(parent_kn, prgrp, "mon_data", &kn);
 	if (ret)
 		return ret;
 
@@ -2645,7 +2656,7 @@
 	uint files = 0;
 	int ret;
 
-	prdtgrp = rdtgroup_kn_lock_live(prgrp_kn);
+	prdtgrp = rdtgroup_kn_lock_live(parent_kn);
 	if (!prdtgrp) {
 		ret = -ENODEV;
 		goto out_unlock;
@@ -2683,8 +2694,8 @@
 	/*
 	 * kernfs_remove() will drop the reference count on "kn" which
 	 * will free it. But we still need it to stick around for the
-	 * rdtgroup_kn_unlock(kn} call below. Take one extra reference
-	 * here, which will be dropped inside rdtgroup_kn_unlock().
+	 * rdtgroup_kn_unlock(kn) call. Take one extra reference here,
+	 * which will be dropped by kernfs_put() in rdtgroup_remove().
 	 */
 	kernfs_get(kn);
 
@@ -2718,18 +2729,19 @@
 	kernfs_activate(kn);
 
 	/*
-	 * The caller unlocks the prgrp_kn upon success.
+	 * The caller unlocks the parent_kn upon success.
 	 */
 	return 0;
 
 out_idfree:
 	free_rmid(rdtgrp->mon.rmid);
 out_destroy:
+	kernfs_put(rdtgrp->kn);
 	kernfs_remove(rdtgrp->kn);
 out_free_rgrp:
 	kfree(rdtgrp);
 out_unlock:
-	rdtgroup_kn_unlock(prgrp_kn);
+	rdtgroup_kn_unlock(parent_kn);
 	return ret;
 }
 
@@ -2737,7 +2749,7 @@
 {
 	kernfs_remove(rgrp->kn);
 	free_rmid(rgrp->mon.rmid);
-	kfree(rgrp);
+	rdtgroup_remove(rgrp);
 }
 
 /*
@@ -2767,7 +2779,7 @@
 	 */
 	list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list);
 
-	rdtgroup_kn_unlock(prgrp_kn);
+	rdtgroup_kn_unlock(parent_kn);
 	return ret;
 }
 
@@ -2810,7 +2822,7 @@
 		 * Create an empty mon_groups directory to hold the subset
 		 * of tasks and cpus to monitor.
 		 */
-		ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL);
+		ret = mongroup_create_dir(kn, rdtgrp, "mon_groups", NULL);
 		if (ret) {
 			rdt_last_cmd_puts("kernfs subdir error\n");
 			goto out_del_list;
@@ -2826,7 +2838,7 @@
 out_common_fail:
 	mkdir_rdt_prepare_clean(rdtgrp);
 out_unlock:
-	rdtgroup_kn_unlock(prgrp_kn);
+	rdtgroup_kn_unlock(parent_kn);
 	return ret;
 }
 
@@ -2899,11 +2911,6 @@
 	WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
 	list_del(&rdtgrp->mon.crdtgrp_list);
 
-	/*
-	 * one extra hold on this, will drop when we kfree(rdtgrp)
-	 * in rdtgroup_kn_unlock()
-	 */
-	kernfs_get(kn);
 	kernfs_remove(rdtgrp->kn);
 
 	return 0;
@@ -2915,11 +2922,6 @@
 	rdtgrp->flags = RDT_DELETED;
 	list_del(&rdtgrp->rdtgroup_list);
 
-	/*
-	 * one extra hold on this, will drop when we kfree(rdtgrp)
-	 * in rdtgroup_kn_unlock()
-	 */
-	kernfs_get(kn);
 	kernfs_remove(rdtgrp->kn);
 	return 0;
 }
@@ -2952,13 +2954,13 @@
 	closid_free(rdtgrp->closid);
 	free_rmid(rdtgrp->mon.rmid);
 
+	rdtgroup_ctrl_remove(kn, rdtgrp);
+
 	/*
 	 * Free all the child monitor group rmids.
 	 */
 	free_all_child_rdtgrp(rdtgrp);
 
-	rdtgroup_ctrl_remove(kn, rdtgrp);
-
 	return 0;
 }
 
@@ -2985,7 +2987,8 @@
 	 * If the rdtgroup is a mon group and parent directory
 	 * is a valid "mon_groups" directory, remove the mon group.
 	 */
-	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn) {
+	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn &&
+	    rdtgrp != &rdtgroup_default) {
 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
 			ret = rdtgroup_ctrl_remove(kn, rdtgrp);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/scattered.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/scattered.c
@@ -26,6 +26,8 @@
 static const struct cpuid_bit cpuid_bits[] = {
 	{ X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
 	{ X86_FEATURE_EPB,		CPUID_ECX,  3, 0x00000006, 0 },
+	{ X86_FEATURE_RRSBA_CTRL,	CPUID_EDX,  2, 0x00000007, 2 },
+	{ X86_FEATURE_BHI_CTRL,		CPUID_EDX,  4, 0x00000007, 2 },
 	{ X86_FEATURE_CQM_LLC,		CPUID_EDX,  1, 0x0000000f, 0 },
 	{ X86_FEATURE_CQM_OCCUP_LLC,	CPUID_EDX,  0, 0x0000000f, 1 },
 	{ X86_FEATURE_CQM_MBM_TOTAL,	CPUID_EDX,  1, 0x0000000f, 1 },
@@ -39,8 +41,6 @@
 	{ X86_FEATURE_CPB,		CPUID_EDX,  9, 0x80000007, 0 },
 	{ X86_FEATURE_PROC_FEEDBACK,    CPUID_EDX, 11, 0x80000007, 0 },
 	{ X86_FEATURE_MBA,		CPUID_EBX,  6, 0x80000008, 0 },
-	{ X86_FEATURE_SME,		CPUID_EAX,  0, 0x8000001f, 0 },
-	{ X86_FEATURE_SEV,		CPUID_EAX,  1, 0x8000001f, 0 },
 	{ 0, 0, 0, 0, 0 }
 };
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/topology.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/topology.c
@@ -25,10 +25,10 @@
 #define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
 #define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
 
-#ifdef CONFIG_SMP
 unsigned int __max_die_per_package __read_mostly = 1;
 EXPORT_SYMBOL(__max_die_per_package);
 
+#ifdef CONFIG_SMP
 /*
  * Check if given CPUID extended toplogy "leaf" is implemented
  */
@@ -79,7 +79,7 @@
 	 * initial apic id, which also represents 32-bit extended x2apic id.
 	 */
 	c->initial_apicid = edx;
-	smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
+	smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx));
 #endif
 	return 0;
 }
@@ -107,7 +107,8 @@
 	 */
 	cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
 	c->initial_apicid = edx;
-	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
+	core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
+	smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx));
 	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 	die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 	die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
--- linux-ein-5.4.0.orig/arch/x86/kernel/cpu/tsx.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/tsx.c
@@ -55,24 +55,6 @@
 	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))
@@ -86,9 +68,22 @@
 	char arg[5] = {};
 	int ret;
 
-	if (!tsx_ctrl_is_supported())
+	/*
+	 * 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.
+	 */
+	if (!(x86_read_arch_cap_msr() & ARCH_CAP_TSX_CTRL_MSR))
 		return;
 
+	setup_force_cpu_cap(X86_FEATURE_MSR_TSX_CTRL);
+
 	ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
 	if (ret >= 0) {
 		if (!strcmp(arg, "on")) {
@@ -115,11 +110,12 @@
 		tsx_disable();
 
 		/*
-		 * tsx_disable() will change the state of the
-		 * RTM CPUID bit.  Clear it here since it is now
-		 * expected to be not set.
+		 * 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) {
 
 		/*
@@ -131,10 +127,10 @@
 		tsx_enable();
 
 		/*
-		 * tsx_enable() will change the state of the
-		 * RTM CPUID bit.  Force it here since it is now
-		 * expected to be set.
+		 * 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-ein-5.4.0.orig/arch/x86/kernel/cpu/umwait.c
+++ linux-ein-5.4.0/arch/x86/kernel/cpu/umwait.c
@@ -17,12 +17,6 @@
  */
 static u32 umwait_control_cached = UMWAIT_CTRL_VAL(100000, UMWAIT_C02_ENABLE);
 
-u32 get_umwait_control_msr(void)
-{
-	return umwait_control_cached;
-}
-EXPORT_SYMBOL_GPL(get_umwait_control_msr);
-
 /*
  * Cache the original IA32_UMWAIT_CONTROL MSR value which is configured by
  * hardware or BIOS before kernel boot.
--- linux-ein-5.4.0.orig/arch/x86/kernel/crash.c
+++ linux-ein-5.4.0/arch/x86/kernel/crash.c
@@ -24,6 +24,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/memblock.h>
 
 #include <asm/processor.h>
 #include <asm/hardirq.h>
@@ -36,9 +37,9 @@
 #include <linux/kdebug.h>
 #include <asm/cpu.h>
 #include <asm/reboot.h>
-#include <asm/virtext.h>
 #include <asm/intel_pt.h>
 #include <asm/crash.h>
+#include <asm/cmdline.h>
 
 /* Used while preparing memory map entries for second kernel */
 struct crash_memmap_data {
@@ -68,6 +69,19 @@
 	rcu_read_unlock();
 }
 
+/*
+ * When the crashkernel option is specified, only use the low
+ * 1M for the real mode trampoline.
+ */
+void __init crash_reserve_low_1M(void)
+{
+	if (cmdline_find_option(boot_command_line, "crashkernel", NULL, 0) < 0)
+		return;
+
+	memblock_reserve(0, 1<<20);
+	pr_info("Reserving the low 1M of memory for crashkernel\n");
+}
+
 #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
 
 static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
@@ -79,15 +93,6 @@
 	 */
 	cpu_crash_vmclear_loaded_vmcss();
 
-	/* Disable VMX or SVM if needed.
-	 *
-	 * We need to disable virtualization on all CPUs.
-	 * Having VMX or SVM enabled on any CPU may break rebooting
-	 * after the kdump kernel has finished its task.
-	 */
-	cpu_emergency_vmxoff();
-	cpu_emergency_svm_disable();
-
 	/*
 	 * Disable Intel PT to stop its logging
 	 */
@@ -146,12 +151,7 @@
 	 */
 	cpu_crash_vmclear_loaded_vmcss();
 
-	/* Booting kdump kernel with VMX or SVM enabled won't work,
-	 * because (among other limitations) we can't disable paging
-	 * with the virt flags.
-	 */
-	cpu_emergency_vmxoff();
-	cpu_emergency_svm_disable();
+	cpu_emergency_disable_virtualization();
 
 	/*
 	 * Disable Intel PT to stop its logging
@@ -349,7 +349,7 @@
 	struct crash_memmap_data cmd;
 	struct crash_mem *cmem;
 
-	cmem = vzalloc(sizeof(struct crash_mem));
+	cmem = vzalloc(struct_size(cmem, ranges, 1));
 	if (!cmem)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/doublefault.c
+++ linux-ein-5.4.0/arch/x86/kernel/doublefault.c
@@ -65,6 +65,9 @@
 	.ss		= __KERNEL_DS,
 	.ds		= __USER_DS,
 	.fs		= __KERNEL_PERCPU,
+#ifndef CONFIG_X86_32_LAZY_GS
+	.gs		= __KERNEL_STACK_CANARY,
+#endif
 
 	.__cr3		= __pa_nodebug(swapper_pg_dir),
 };
--- linux-ein-5.4.0.orig/arch/x86/kernel/dumpstack.c
+++ linux-ein-5.4.0/arch/x86/kernel/dumpstack.c
@@ -171,7 +171,6 @@
 	printk("%sCall Trace:\n", log_lvl);
 
 	unwind_start(&state, task, regs, stack);
-	stack = stack ? : get_stack_pointer(task, regs);
 	regs = unwind_get_entry_regs(&state, &partial);
 
 	/*
@@ -190,9 +189,13 @@
 	 * - hardirq stack
 	 * - entry stack
 	 */
-	for ( ; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
+	for (stack = stack ?: get_stack_pointer(task, regs);
+	     stack;
+	     stack = stack_info.next_sp) {
 		const char *stack_name;
 
+		stack = PTR_ALIGN(stack, sizeof(long));
+
 		if (get_stack_info(stack, task, &stack_info, &visit_mask)) {
 			/*
 			 * We weren't on a valid stack.  It's possible that
@@ -326,7 +329,7 @@
 }
 NOKPROBE_SYMBOL(oops_begin);
 
-void __noreturn rewind_stack_do_exit(int signr);
+void __noreturn rewind_stack_and_make_dead(int signr);
 
 void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
 {
@@ -361,7 +364,7 @@
 	 * reuse the task stack and that existing poisons are invalid.
 	 */
 	kasan_unpoison_task_stack(current);
-	rewind_stack_do_exit(signr);
+	rewind_stack_and_make_dead(signr);
 }
 NOKPROBE_SYMBOL(oops_end);
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/early-quirks.c
+++ linux-ein-5.4.0/arch/x86/kernel/early-quirks.c
@@ -28,6 +28,37 @@
 #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);
+	}
+}
+
 static void __init fix_hypertransport_config(int num, int slot, int func)
 {
 	u32 htcfg;
@@ -515,6 +546,7 @@
 	.stolen_size = gen9_stolen_size,
 };
 
+/* Intel integrated GPUs for which we need to reserve "stolen memory" */
 static const struct pci_device_id intel_early_ids[] __initconst = {
 	INTEL_I830_IDS(&i830_early_ops),
 	INTEL_I845G_IDS(&i845_early_ops),
@@ -587,6 +619,13 @@
 	u16 device;
 	int i;
 
+	/*
+	 * Reserve "stolen memory" for an integrated GPU.  If we've already
+	 * found one, there's nothing to do for other (discrete) GPUs.
+	 */
+	if (resource_size(&intel_graphics_stolen_res))
+		return;
+
 	device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
 
 	for (i = 0; i < ARRAY_SIZE(intel_early_ids); i++) {
@@ -699,7 +738,7 @@
 	{ PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
 	  PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
-	  QFLAG_APPLY_ONCE, intel_graphics_quirks },
+	  0, intel_graphics_quirks },
 	/*
 	 * HPET on the current version of the Baytrail platform has accuracy
 	 * problems: it will halt in deep idle state - so we disable it.
@@ -710,10 +749,9 @@
 	 */
 	{ PCI_VENDOR_ID_INTEL, 0x0f00,
 		PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
-	{ PCI_VENDOR_ID_INTEL, 0x3ec4,
-		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},
 	{}
 };
 
@@ -766,6 +804,10 @@
 				    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);
@@ -792,8 +834,13 @@
 
 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-ein-5.4.0.orig/arch/x86/kernel/fpu/core.c
+++ linux-ein-5.4.0/arch/x86/kernel/fpu/core.c
@@ -82,7 +82,7 @@
 }
 EXPORT_SYMBOL(irq_fpu_usable);
 
-void kernel_fpu_begin(void)
+void kernel_fpu_begin_mask(unsigned int kfpu_mask)
 {
 	preempt_disable();
 
@@ -101,8 +101,15 @@
 		copy_fpregs_to_fpstate(&current->thread.fpu);
 	}
 	__cpu_invalidate_fpregs_state();
+
+	/* Put sane initial values into the control registers. */
+	if (likely(kfpu_mask & KFPU_MXCSR) && boot_cpu_has(X86_FEATURE_XMM))
+		ldmxcsr(MXCSR_DEFAULT);
+
+	if (unlikely(kfpu_mask & KFPU_387) && boot_cpu_has(X86_FEATURE_FPU))
+		asm volatile ("fninit");
 }
-EXPORT_SYMBOL_GPL(kernel_fpu_begin);
+EXPORT_SYMBOL_GPL(kernel_fpu_begin_mask);
 
 void kernel_fpu_end(void)
 {
--- linux-ein-5.4.0.orig/arch/x86/kernel/fpu/init.c
+++ linux-ein-5.4.0/arch/x86/kernel/fpu/init.c
@@ -50,7 +50,7 @@
 	fpu__init_cpu_xstate();
 }
 
-static bool fpu__probe_without_cpuid(void)
+static bool __init fpu__probe_without_cpuid(void)
 {
 	unsigned long cr0;
 	u16 fsw, fcw;
@@ -68,7 +68,7 @@
 	return fsw == 0 && (fcw & 0x103f) == 0x003f;
 }
 
-static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
+static void __init fpu__init_system_early_generic(void)
 {
 	if (!boot_cpu_has(X86_FEATURE_CPUID) &&
 	    !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
@@ -139,9 +139,6 @@
 unsigned int fpu_kernel_xstate_size;
 EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size);
 
-/* Get alignment of the TYPE. */
-#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)
-
 /*
  * Enforce that 'MEMBER' is the last field of 'TYPE'.
  *
@@ -149,8 +146,8 @@
  * because that's how C aligns structs.
  */
 #define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
-	BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
-					   TYPE_ALIGN(TYPE)))
+	BUILD_BUG_ON(sizeof(TYPE) !=         \
+		     ALIGN(offsetofend(TYPE, MEMBER), _Alignof(TYPE)))
 
 /*
  * We append the 'struct fpu' to the task_struct:
@@ -242,9 +239,9 @@
  */
 static void __init fpu__init_parse_early_param(void)
 {
-	char arg[32];
+	char arg[128];
 	char *argptr = arg;
-	int bit;
+	int arglen, res, bit;
 
 #ifdef CONFIG_X86_32
 	if (cmdline_find_option_bool(boot_command_line, "no387"))
@@ -267,22 +264,36 @@
 	if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
 		setup_clear_cpu_cap(X86_FEATURE_XSAVES);
 
-	if (cmdline_find_option(boot_command_line, "clearcpuid", arg,
-				sizeof(arg)) &&
-	    get_option(&argptr, &bit) &&
-	    bit >= 0 &&
-	    bit < NCAPINTS * 32)
-		setup_clear_cpu_cap(bit);
+	arglen = cmdline_find_option(boot_command_line, "clearcpuid", arg, sizeof(arg));
+	if (arglen <= 0)
+		return;
+
+	pr_info("Clearing CPUID bits:");
+	do {
+		res = get_option(&argptr, &bit);
+		if (res == 0 || res == 3)
+			break;
+
+		/* If the argument was too long, the last bit may be cut off */
+		if (res == 1 && arglen >= sizeof(arg))
+			break;
+
+		if (bit >= 0 && bit < NCAPINTS * 32) {
+			pr_cont(" " X86_CAP_FMT, x86_cap_flag(bit));
+			setup_clear_cpu_cap(bit);
+		}
+	} while (res == 2);
+	pr_cont("\n");
 }
 
 /*
  * Called on the boot CPU once per system bootup, to set up the initial
  * FPU state that is later cloned into all processes:
  */
-void __init fpu__init_system(struct cpuinfo_x86 *c)
+void __init fpu__init_system(void)
 {
 	fpu__init_parse_early_param();
-	fpu__init_system_early_generic(c);
+	fpu__init_system_early_generic();
 
 	/*
 	 * The FPU has to be operational for some of the
--- linux-ein-5.4.0.orig/arch/x86/kernel/fpu/regset.c
+++ linux-ein-5.4.0/arch/x86/kernel/fpu/regset.c
@@ -124,7 +124,7 @@
 	/*
 	 * A whole standard-format XSAVE buffer is needed:
 	 */
-	if ((pos != 0) || (count < fpu_user_xstate_size))
+	if (pos != 0 || count != fpu_user_xstate_size)
 		return -EFAULT;
 
 	xsave = &fpu->state.xsave;
--- linux-ein-5.4.0.orig/arch/x86/kernel/fpu/signal.c
+++ linux-ein-5.4.0/arch/x86/kernel/fpu/signal.c
@@ -289,13 +289,17 @@
 		return 0;
 	}
 
-	if (!access_ok(buf, size))
-		return -EACCES;
+	if (!access_ok(buf, size)) {
+		ret = -EACCES;
+		goto out;
+	}
 
-	if (!static_cpu_has(X86_FEATURE_FPU))
-		return fpregs_soft_set(current, NULL,
-				       0, sizeof(struct user_i387_ia32_struct),
-				       NULL, buf) != 0;
+	if (!static_cpu_has(X86_FEATURE_FPU)) {
+		ret = fpregs_soft_set(current, NULL, 0,
+				      sizeof(struct user_i387_ia32_struct),
+				      NULL, buf);
+		goto out;
+	}
 
 	if (use_xsave()) {
 		struct _fpx_sw_bytes fx_sw_user;
@@ -333,7 +337,7 @@
 	if (ia32_fxstate) {
 		ret = __copy_from_user(&env, buf, sizeof(env));
 		if (ret)
-			goto err_out;
+			goto out;
 		envp = &env;
 	} else {
 		/*
@@ -352,6 +356,7 @@
 			fpregs_unlock();
 			return 0;
 		}
+		fpregs_deactivate(fpu);
 		fpregs_unlock();
 	}
 
@@ -368,7 +373,7 @@
 				ret = validate_xstate_header(&fpu->state.xsave.header);
 		}
 		if (ret)
-			goto err_out;
+			goto out;
 
 		sanitize_restored_xstate(&fpu->state, envp, xfeatures, fx_only);
 
@@ -381,7 +386,7 @@
 		ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size);
 		if (ret) {
 			ret = -EFAULT;
-			goto err_out;
+			goto out;
 		}
 
 		sanitize_restored_xstate(&fpu->state, envp, xfeatures, fx_only);
@@ -396,16 +401,18 @@
 	} else {
 		ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size);
 		if (ret)
-			goto err_out;
+			goto out;
 
 		fpregs_lock();
 		ret = copy_kernel_to_fregs_err(&fpu->state.fsave);
 	}
 	if (!ret)
 		fpregs_mark_activate();
+	else
+		fpregs_deactivate(fpu);
 	fpregs_unlock();
 
-err_out:
+out:
 	if (ret)
 		fpu__clear(fpu);
 	return ret;
--- linux-ein-5.4.0.orig/arch/x86/kernel/fpu/xstate.c
+++ linux-ein-5.4.0/arch/x86/kernel/fpu/xstate.c
@@ -399,12 +399,32 @@
 }
 
 /*
+ * All supported features have either init state all zeros or are
+ * handled in setup_init_fpu() individually. This is an explicit
+ * feature list and does not use XFEATURE_MASK*SUPPORTED to catch
+ * newly added supported features at build time and make people
+ * actually look at the init state for the new feature.
+ */
+#define XFEATURES_INIT_FPSTATE_HANDLED		\
+	(XFEATURE_MASK_FP |			\
+	 XFEATURE_MASK_SSE |			\
+	 XFEATURE_MASK_YMM |			\
+	 XFEATURE_MASK_OPMASK |			\
+	 XFEATURE_MASK_ZMM_Hi256 |		\
+	 XFEATURE_MASK_Hi16_ZMM	 |		\
+	 XFEATURE_MASK_PKRU |			\
+	 XFEATURE_MASK_BNDREGS |		\
+	 XFEATURE_MASK_BNDCSR)
+
+/*
  * setup the xstate image representing the init state
  */
 static void __init setup_init_fpu_buf(void)
 {
 	static int on_boot_cpu __initdata = 1;
 
+	BUILD_BUG_ON(XCNTXT_MASK != XFEATURES_INIT_FPSTATE_HANDLED);
+
 	WARN_ON_FPU(!on_boot_cpu);
 	on_boot_cpu = 0;
 
@@ -423,10 +443,22 @@
 	copy_kernel_to_xregs_booting(&init_fpstate.xsave);
 
 	/*
-	 * Dump the init state again. This is to identify the init state
-	 * of any feature which is not represented by all zero's.
+	 * All components are now in init state. Read the state back so
+	 * that init_fpstate contains all non-zero init state. This only
+	 * works with XSAVE, but not with XSAVEOPT and XSAVES because
+	 * those use the init optimization which skips writing data for
+	 * components in init state.
+	 *
+	 * XSAVE could be used, but that would require to reshuffle the
+	 * data when XSAVES is available because XSAVES uses xstate
+	 * compaction. But doing so is a pointless exercise because most
+	 * components have an all zeros init state except for the legacy
+	 * ones (FP and SSE). Those can be saved with FXSAVE into the
+	 * legacy area. Adding new features requires to ensure that init
+	 * state is all zeroes or if not to add the necessary handling
+	 * here.
 	 */
-	copy_xregs_to_kernel_booting(&init_fpstate.xsave);
+	fxsave(&init_fpstate.fxsave);
 }
 
 static int xfeature_uncompacted_offset(int xfeature_nr)
@@ -773,6 +805,14 @@
 	fpu__init_prepare_fx_sw_frame();
 	setup_init_fpu_buf();
 	setup_xstate_comp();
+
+	/*
+	 * CPU capabilities initialization runs before FPU init. So
+	 * X86_FEATURE_OSXSAVE is not set. Now that XSAVE is completely
+	 * functional, set the feature bit so depending code works.
+	 */
+	setup_force_cpu_cap(X86_FEATURE_OSXSAVE);
+
 	print_xstate_offset_size();
 
 	pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n",
@@ -895,8 +935,6 @@
 
 #ifdef CONFIG_ARCH_HAS_PKEYS
 
-#define NR_VALID_PKRU_BITS (CONFIG_NR_PROTECTION_KEYS * 2)
-#define PKRU_VALID_MASK (NR_VALID_PKRU_BITS - 1)
 /*
  * This will go out and modify PKRU register to set the access
  * rights for @pkey to @init_val.
@@ -915,6 +953,13 @@
 	if (!boot_cpu_has(X86_FEATURE_OSPKE))
 		return -EINVAL;
 
+	/*
+	 * This code should only be called with valid 'pkey'
+	 * values originating from in-kernel users.  Complain
+	 * if a bad value is observed.
+	 */
+	WARN_ON_ONCE(pkey >= arch_max_pkey());
+
 	/* Set the bits we need in PKRU:  */
 	if (init_val & PKEY_DISABLE_ACCESS)
 		new_pkru_bits |= PKRU_AD_BIT;
@@ -952,18 +997,31 @@
 	return true;
 }
 
-/*
- * This is similar to user_regset_copyout(), but will not add offset to
- * the source data pointer or increment pos, count, kbuf, and ubuf.
- */
-static inline void
-__copy_xstate_to_kernel(void *kbuf, const void *data,
-			unsigned int offset, unsigned int size, unsigned int size_total)
+static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count)
 {
-	if (offset < size_total) {
-		unsigned int copy = min(size, size_total - offset);
+	if (*pos < to) {
+		unsigned size = to - *pos;
+
+		if (size > *count)
+			size = *count;
+		memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
+		*kbuf += size;
+		*pos += size;
+		*count -= size;
+	}
+}
 
-		memcpy(kbuf + offset, data, copy);
+static void copy_part(unsigned offset, unsigned size, void *from,
+			void **kbuf, unsigned *pos, unsigned *count)
+{
+	fill_gap(offset, kbuf, pos, count);
+	if (size > *count)
+		size = *count;
+	if (size) {
+		memcpy(*kbuf, from, size);
+		*kbuf += size;
+		*pos += size;
+		*count -= size;
 	}
 }
 
@@ -976,8 +1034,9 @@
  */
 int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
 {
-	unsigned int offset, size;
 	struct xstate_header header;
+	const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
+	unsigned count = size_total;
 	int i;
 
 	/*
@@ -993,46 +1052,42 @@
 	header.xfeatures = xsave->header.xfeatures;
 	header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR;
 
+	if (header.xfeatures & XFEATURE_MASK_FP)
+		copy_part(0, off_mxcsr,
+			  &xsave->i387, &kbuf, &offset_start, &count);
+	if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
+		copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
+			  &xsave->i387.mxcsr, &kbuf, &offset_start, &count);
+	if (header.xfeatures & XFEATURE_MASK_FP)
+		copy_part(offsetof(struct fxregs_state, st_space), 128,
+			  &xsave->i387.st_space, &kbuf, &offset_start, &count);
+	if (header.xfeatures & XFEATURE_MASK_SSE)
+		copy_part(xstate_offsets[XFEATURE_SSE], 256,
+			  &xsave->i387.xmm_space, &kbuf, &offset_start, &count);
+	/*
+	 * Fill xsave->i387.sw_reserved value for ptrace frame:
+	 */
+	copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
+		  xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
 	/*
 	 * Copy xregs_state->header:
 	 */
-	offset = offsetof(struct xregs_state, header);
-	size = sizeof(header);
+	copy_part(offsetof(struct xregs_state, header), sizeof(header),
+		  &header, &kbuf, &offset_start, &count);
 
-	__copy_xstate_to_kernel(kbuf, &header, offset, size, size_total);
-
-	for (i = 0; i < XFEATURE_MAX; i++) {
+	for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
 		/*
 		 * Copy only in-use xstates:
 		 */
 		if ((header.xfeatures >> i) & 1) {
 			void *src = __raw_xsave_addr(xsave, i);
 
-			offset = xstate_offsets[i];
-			size = xstate_sizes[i];
-
-			/* The next component has to fit fully into the output buffer: */
-			if (offset + size > size_total)
-				break;
-
-			__copy_xstate_to_kernel(kbuf, src, offset, size, size_total);
+			copy_part(xstate_offsets[i], xstate_sizes[i],
+				  src, &kbuf, &offset_start, &count);
 		}
 
 	}
-
-	if (xfeatures_mxcsr_quirk(header.xfeatures)) {
-		offset = offsetof(struct fxregs_state, mxcsr);
-		size = MXCSR_AND_FLAGS_SIZE;
-		__copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total);
-	}
-
-	/*
-	 * Fill xsave->i387.sw_reserved value for ptrace frame:
-	 */
-	offset = offsetof(struct fxregs_state, sw_reserved);
-	size = sizeof(xstate_fx_sw_bytes);
-
-	__copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total);
+	fill_gap(size_total, &kbuf, &offset_start, &count);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/ftrace_32.S
+++ linux-ein-5.4.0/arch/x86/kernel/ftrace_32.S
@@ -89,7 +89,7 @@
 	ret
 END(ftrace_caller)
 
-ENTRY(ftrace_regs_caller)
+SYM_CODE_START(ftrace_regs_caller)
 	/*
 	 * We're here from an mcount/fentry CALL, and the stack frame looks like:
 	 *
@@ -163,6 +163,7 @@
 	popl	%eax
 
 	jmp	.Lftrace_ret
+SYM_CODE_END(ftrace_regs_caller)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
--- linux-ein-5.4.0.orig/arch/x86/kernel/head64.c
+++ linux-ein-5.4.0/arch/x86/kernel/head64.c
@@ -383,6 +383,8 @@
 {
 	memset(__bss_start, 0,
 	       (unsigned long) __bss_stop - (unsigned long) __bss_start);
+	memset(__brk_base, 0,
+	       (unsigned long) __brk_limit - (unsigned long) __brk_base);
 }
 
 static unsigned long get_cmd_line_ptr(void)
--- linux-ein-5.4.0.orig/arch/x86/kernel/head_32.S
+++ linux-ein-5.4.0/arch/x86/kernel/head_32.S
@@ -26,6 +26,7 @@
 #include <asm/bootparam.h>
 #include <asm/export.h>
 #include <asm/pgtable_32.h>
+#include <asm/nospec-branch.h>
 
 /* Physical address */
 #define pa(X) ((X) - __PAGE_OFFSET)
@@ -64,7 +65,7 @@
  * can.
  */
 __HEAD
-ENTRY(startup_32)
+SYM_CODE_START(startup_32)
 	movl pa(initial_stack),%ecx
 	
 	/* test KEEP_SEGMENTS flag to see if the bootloader is asking
@@ -153,6 +154,7 @@
 
 	movl pa(subarch_entries)(,%eax,4), %eax
 	subl $__PAGE_OFFSET, %eax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp *%eax
 
 .Lbad_subarch:
@@ -172,6 +174,7 @@
 #else
 	jmp .Ldefault_entry
 #endif /* CONFIG_PARAVIRT */
+SYM_CODE_END(startup_32)
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
@@ -302,6 +305,7 @@
 	movl setup_once_ref,%eax
 	andl %eax,%eax
 	jz 1f				# Did we do this already?
+	ANNOTATE_RETPOLINE_SAFE
 	call *%eax
 1:
 
@@ -571,6 +575,16 @@
 #  error "Kernel PMDs should be 1, 2 or 3"
 # endif
 	.align PAGE_SIZE		/* needs to be page-sized too */
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+	/*
+	 * PTI needs another page so sync_initial_pagetable() works correctly
+	 * and does not scribble over the data which is placed behind the
+	 * actual initial_page_table. See clone_pgd_range().
+	 */
+	.fill 1024, 4, 0
+#endif
+
 #endif
 
 .data
--- linux-ein-5.4.0.orig/arch/x86/kernel/hpet.c
+++ linux-ein-5.4.0/arch/x86/kernel/hpet.c
@@ -9,6 +9,7 @@
 
 #include <asm/hpet.h>
 #include <asm/time.h>
+#include <asm/mwait.h>
 
 #undef  pr_fmt
 #define pr_fmt(fmt) "hpet: " fmt
@@ -806,6 +807,83 @@
 	return false;
 }
 
+static bool __init mwait_pc10_supported(void)
+{
+	unsigned int eax, ebx, ecx, mwait_substates;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+		return false;
+
+	if (!cpu_feature_enabled(X86_FEATURE_MWAIT))
+		return false;
+
+	if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+		return false;
+
+	cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates);
+
+	return (ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) &&
+	       (ecx & CPUID5_ECX_INTERRUPT_BREAK) &&
+	       (mwait_substates & (0xF << 28));
+}
+
+/*
+ * Check whether the system supports PC10. If so force disable HPET as that
+ * stops counting in PC10. This check is overbroad as it does not take any
+ * of the following into account:
+ *
+ *	- ACPI tables
+ *	- Enablement of intel_idle
+ *	- Command line arguments which limit intel_idle C-state support
+ *
+ * That's perfectly fine. HPET is a piece of hardware designed by committee
+ * and the only reasons why it is still in use on modern systems is the
+ * fact that it is impossible to reliably query TSC and CPU frequency via
+ * CPUID or firmware.
+ *
+ * If HPET is functional it is useful for calibrating TSC, but this can be
+ * done via PMTIMER as well which seems to be the last remaining timer on
+ * X86/INTEL platforms that has not been completely wreckaged by feature
+ * creep.
+ *
+ * In theory HPET support should be removed altogether, but there are older
+ * systems out there which depend on it because TSC and APIC timer are
+ * dysfunctional in deeper C-states.
+ *
+ * It's only 20 years now that hardware people have been asked to provide
+ * reliable and discoverable facilities which can be used for timekeeping
+ * and per CPU timer interrupts.
+ *
+ * The probability that this problem is going to be solved in the
+ * forseeable future is close to zero, so the kernel has to be cluttered
+ * with heuristics to keep up with the ever growing amount of hardware and
+ * firmware trainwrecks. Hopefully some day hardware people will understand
+ * that the approach of "This can be fixed in software" is not sustainable.
+ * Hope dies last...
+ */
+static bool __init hpet_is_pc10_damaged(void)
+{
+	unsigned long long pcfg;
+
+	/* Check whether PC10 substates are supported */
+	if (!mwait_pc10_supported())
+		return false;
+
+	/* Check whether PC10 is enabled in PKG C-state limit */
+	rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, pcfg);
+	if ((pcfg & 0xF) < 8)
+		return false;
+
+	if (hpet_force_user) {
+		pr_warn("HPET force enabled via command line, but dysfunctional in PC10.\n");
+		return false;
+	}
+
+	pr_info("HPET dysfunctional in PC10. Force disabled.\n");
+	boot_hpet_disable = true;
+	return true;
+}
+
 /**
  * hpet_enable - Try to setup the HPET timer. Returns 1 on success.
  */
@@ -819,6 +897,9 @@
 	if (!is_hpet_capable())
 		return 0;
 
+	if (hpet_is_pc10_damaged())
+		return 0;
+
 	hpet_set_mapping();
 	if (!hpet_virt_address)
 		return 0;
--- linux-ein-5.4.0.orig/arch/x86/kernel/i8259.c
+++ linux-ein-5.4.0/arch/x86/kernel/i8259.c
@@ -32,6 +32,7 @@
  */
 static void init_8259A(int auto_eoi);
 
+static bool pcat_compat __ro_after_init;
 static int i8259A_auto_eoi;
 DEFINE_RAW_SPINLOCK(i8259A_lock);
 
@@ -114,6 +115,7 @@
 	disable_irq_nosync(irq);
 	io_apic_irqs &= ~(1<<irq);
 	irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
+	irq_set_status_flags(irq, IRQ_LEVEL);
 	enable_irq(irq);
 	lapic_assign_legacy_vector(irq, true);
 }
@@ -207,7 +209,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;
 		}
@@ -300,15 +302,32 @@
 
 static int probe_8259A(void)
 {
+	unsigned char new_val, probe_val = ~(1 << PIC_CASCADE_IR);
 	unsigned long flags;
-	unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
-	unsigned char new_val;
+
+	/*
+	 * If MADT has the PCAT_COMPAT flag set, then do not bother probing
+	 * for the PIC. Some BIOSes leave the PIC uninitialized and probing
+	 * fails.
+	 *
+	 * Right now this causes problems as quite some code depends on
+	 * nr_legacy_irqs() > 0 or has_legacy_pic() == true. This is silly
+	 * when the system has an IO/APIC because then PIC is not required
+	 * at all, except for really old machines where the timer interrupt
+	 * must be routed through the PIC. So just pretend that the PIC is
+	 * there and let legacy_pic->init() initialize it for nothing.
+	 *
+	 * Alternatively this could just try to initialize the PIC and
+	 * repeat the probe, but for cases where there is no PIC that's
+	 * just pointless.
+	 */
+	if (pcat_compat)
+		return nr_legacy_irqs();
+
 	/*
-	 * Check to see if we have a PIC.
-	 * Mask all except the cascade and read
-	 * back the value we just wrote. If we don't
-	 * have a PIC, we will read 0xff as opposed to the
-	 * value we wrote.
+	 * Check to see if we have a PIC.  Mask all except the cascade and
+	 * read back the value we just wrote. If we don't have a PIC, we
+	 * will read 0xff as opposed to the value we wrote.
 	 */
 	raw_spin_lock_irqsave(&i8259A_lock, flags);
 
@@ -430,5 +449,9 @@
 
 	return 0;
 }
-
 device_initcall(i8259A_init_ops);
+
+void __init legacy_pic_pcat_compat(void)
+{
+	pcat_compat = true;
+}
--- linux-ein-5.4.0.orig/arch/x86/kernel/idt.c
+++ linux-ein-5.4.0/arch/x86/kernel/idt.c
@@ -318,7 +318,11 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 	for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
-		set_bit(i, system_vectors);
+		/*
+		 * Don't set the non assigned system vectors in the
+		 * system_vectors bitmap. Otherwise they show up in
+		 * /proc/interrupts.
+		 */
 		entry = spurious_entries_start + 8 * (i - FIRST_SYSTEM_VECTOR);
 		set_intr_gate(i, entry);
 	}
--- linux-ein-5.4.0.orig/arch/x86/kernel/ima_arch.c
+++ linux-ein-5.4.0/arch/x86/kernel/ima_arch.c
@@ -10,8 +10,6 @@
 
 static enum efi_secureboot_mode get_sb_mode(void)
 {
-	efi_char16_t efi_SecureBoot_name[] = L"SecureBoot";
-	efi_char16_t efi_SetupMode_name[] = L"SecureBoot";
 	efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
 	efi_status_t status;
 	unsigned long size;
@@ -25,7 +23,7 @@
 	}
 
 	/* Get variable contents into buffer */
-	status = efi.get_variable(efi_SecureBoot_name, &efi_variable_guid,
+	status = efi.get_variable(L"SecureBoot", &efi_variable_guid,
 				  NULL, &size, &secboot);
 	if (status == EFI_NOT_FOUND) {
 		pr_info("ima: secureboot mode disabled\n");
@@ -38,7 +36,7 @@
 	}
 
 	size = sizeof(setupmode);
-	status = efi.get_variable(efi_SetupMode_name, &efi_variable_guid,
+	status = efi.get_variable(L"SetupMode", &efi_variable_guid,
 				  NULL, &size, &setupmode);
 
 	if (status != EFI_SUCCESS)	/* ignore unknown SetupMode */
--- linux-ein-5.4.0.orig/arch/x86/kernel/irq.c
+++ linux-ein-5.4.0/arch/x86/kernel/irq.c
@@ -295,8 +295,10 @@
 {
 	if (handler)
 		kvm_posted_intr_wakeup_handler = handler;
-	else
+	else {
 		kvm_posted_intr_wakeup_handler = dummy_handler;
+		synchronize_rcu();
+	}
 }
 EXPORT_SYMBOL_GPL(kvm_set_posted_intr_wakeup_handler);
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/irq_64.c
+++ linux-ein-5.4.0/arch/x86/kernel/irq_64.c
@@ -43,7 +43,7 @@
 		pages[i] = pfn_to_page(pa >> PAGE_SHIFT);
 	}
 
-	va = vmap(pages, IRQ_STACK_SIZE / PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
+	va = vmap(pages, IRQ_STACK_SIZE / PAGE_SIZE, VM_MAP, PAGE_KERNEL);
 	if (!va)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/irqinit.c
+++ linux-ein-5.4.0/arch/x86/kernel/irqinit.c
@@ -72,8 +72,10 @@
 
 	legacy_pic->init(0);
 
-	for (i = 0; i < nr_legacy_irqs(); i++)
+	for (i = 0; i < nr_legacy_irqs(); i++) {
 		irq_set_chip_and_handler(i, chip, handle_level_irq);
+		irq_set_status_flags(i, IRQ_LEVEL);
+	}
 }
 
 void __init init_IRQ(void)
--- linux-ein-5.4.0.orig/arch/x86/kernel/kexec-bzimage64.c
+++ linux-ein-5.4.0/arch/x86/kernel/kexec-bzimage64.c
@@ -210,8 +210,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-ein-5.4.0.orig/arch/x86/kernel/kprobes/core.c
+++ linux-ein-5.4.0/arch/x86/kernel/kprobes/core.c
@@ -157,6 +157,8 @@
 int can_boost(struct insn *insn, void *addr)
 {
 	kprobe_opcode_t opcode;
+	insn_byte_t prefix;
+	int i;
 
 	if (search_exception_tables((unsigned long)addr))
 		return 0;	/* Page fault may occur on this address. */
@@ -169,9 +171,14 @@
 	if (insn->opcode.nbytes != 1)
 		return 0;
 
-	/* Can't boost Address-size override prefix */
-	if (unlikely(inat_is_address_size_prefix(insn->attr)))
-		return 0;
+	for_each_insn_prefix(insn, i, prefix) {
+		insn_attr_t attr;
+
+		attr = inat_get_opcode_attribute(prefix);
+		/* Can't boost Address-size override prefix and CS override prefix */
+		if (prefix == 0x2e || inat_is_address_size_prefix(attr))
+			return 0;
+	}
 
 	opcode = insn->opcode.bytes[0];
 
@@ -196,8 +203,8 @@
 		/* clear and set flags are boostable */
 		return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
 	default:
-		/* CS override prefix and call are not boostable */
-		return (opcode != 0x2e && opcode != 0x9a);
+		/* call is not boostable */
+		return opcode != 0x9a;
 	}
 }
 
@@ -351,6 +358,10 @@
 	kernel_insn_init(insn, dest, MAX_INSN_SIZE);
 	insn_get_length(insn);
 
+	/* We can not probe force emulate prefixed instruction */
+	if (insn_has_emulate_prefix(insn))
+		return 0;
+
 	/* Another subsystem puts a breakpoint, failed to recover */
 	if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
 		return 0;
@@ -746,16 +757,11 @@
 NOKPROBE_SYMBOL(kretprobe_trampoline);
 STACK_FRAME_NON_STANDARD(kretprobe_trampoline);
 
-static struct kprobe kretprobe_kprobe = {
-	.addr = (void *)kretprobe_trampoline,
-};
-
 /*
  * Called from kretprobe_trampoline
  */
 __used __visible void *trampoline_handler(struct pt_regs *regs)
 {
-	struct kprobe_ctlblk *kcb;
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
 	struct hlist_node *tmp;
@@ -765,16 +771,12 @@
 	void *frame_pointer;
 	bool skipped = false;
 
-	preempt_disable();
-
 	/*
 	 * Set a dummy kprobe for avoiding kretprobe recursion.
 	 * Since kretprobe never run in kprobe handler, kprobe must not
 	 * be running at this point.
 	 */
-	kcb = get_kprobe_ctlblk();
-	__this_cpu_write(current_kprobe, &kretprobe_kprobe);
-	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+	kprobe_busy_begin();
 
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
@@ -850,7 +852,7 @@
 			__this_cpu_write(current_kprobe, &ri->rp->kp);
 			ri->ret_addr = correct_ret_addr;
 			ri->rp->handler(ri, regs);
-			__this_cpu_write(current_kprobe, &kretprobe_kprobe);
+			__this_cpu_write(current_kprobe, &kprobe_busy);
 		}
 
 		recycle_rp_inst(ri, &empty_rp);
@@ -866,8 +868,7 @@
 
 	kretprobe_hash_unlock(current, &flags);
 
-	__this_cpu_write(current_kprobe, NULL);
-	preempt_enable();
+	kprobe_busy_end();
 
 	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
 		hlist_del(&ri->hlist);
@@ -1029,6 +1030,11 @@
 		 * 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,
--- linux-ein-5.4.0.orig/arch/x86/kernel/kprobes/opt.c
+++ linux-ein-5.4.0/arch/x86/kernel/kprobes/opt.c
@@ -43,8 +43,8 @@
 		/* This function only handles jump-optimized kprobe */
 		if (kp && kprobe_optimized(kp)) {
 			op = container_of(kp, struct optimized_kprobe, kp);
-			/* If op->list is not empty, op is under optimizing */
-			if (list_empty(&op->list))
+			/* If op is optimized or under unoptimizing */
+			if (list_empty(&op->list) || optprobe_queued_unopt(op))
 				goto found;
 		}
 	}
@@ -314,7 +314,7 @@
 
 	for (i = 1; i < op->optinsn.size; i++) {
 		p = get_kprobe(op->kp.addr + i);
-		if (p && !kprobe_disabled(p))
+		if (p && !kprobe_disarmed(p))
 			return -EEXIST;
 	}
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/kvm.c
+++ linux-ein-5.4.0/arch/x86/kernel/kvm.c
@@ -24,6 +24,7 @@
 #include <linux/debugfs.h>
 #include <linux/nmi.h>
 #include <linux/swait.h>
+#include <linux/syscore_ops.h>
 #include <asm/timer.h>
 #include <asm/cpu.h>
 #include <asm/traps.h>
@@ -33,6 +34,7 @@
 #include <asm/apicdef.h>
 #include <asm/hypervisor.h>
 #include <asm/tlb.h>
+#include <asm/reboot.h>
 
 static int kvmapf = 1;
 
@@ -57,6 +59,7 @@
 DEFINE_PER_CPU_DECRYPTED(struct kvm_steal_time, steal_time) __aligned(64) __visible;
 static int has_steal_clock = 0;
 
+static int has_guest_poll = 0;
 /*
  * No need for any "IO delay" on KVM
  */
@@ -321,8 +324,7 @@
 
 		wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
 		__this_cpu_write(apf_reason.enabled, 1);
-		printk(KERN_INFO"KVM setup async PF for cpu %d\n",
-		       smp_processor_id());
+		pr_info("setup async PF for cpu %d\n", smp_processor_id());
 	}
 
 	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
@@ -347,35 +349,17 @@
 	wrmsrl(MSR_KVM_ASYNC_PF_EN, 0);
 	__this_cpu_write(apf_reason.enabled, 0);
 
-	printk(KERN_INFO"Unregister pv shared memory for cpu %d\n",
-	       smp_processor_id());
+	pr_info("disable async PF for cpu %d\n", smp_processor_id());
 }
 
-static void kvm_pv_guest_cpu_reboot(void *unused)
+static void kvm_disable_steal_time(void)
 {
-	/*
-	 * We disable PV EOI before we load a new kernel by kexec,
-	 * since MSR_KVM_PV_EOI_EN stores a pointer into old kernel's memory.
-	 * New kernel can re-enable when it boots.
-	 */
-	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
-		wrmsrl(MSR_KVM_PV_EOI_EN, 0);
-	kvm_pv_disable_apf();
-	kvm_disable_steal_time();
-}
+	if (!has_steal_clock)
+		return;
 
-static int kvm_pv_reboot_notify(struct notifier_block *nb,
-				unsigned long code, void *unused)
-{
-	if (code == SYS_RESTART)
-		on_each_cpu(kvm_pv_guest_cpu_reboot, NULL, 1);
-	return NOTIFY_DONE;
+	wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
 }
 
-static struct notifier_block kvm_pv_reboot_nb = {
-	.notifier_call = kvm_pv_reboot_notify,
-};
-
 static u64 kvm_steal_clock(int cpu)
 {
 	u64 steal;
@@ -393,14 +377,6 @@
 	return steal;
 }
 
-void kvm_disable_steal_time(void)
-{
-	if (!has_steal_clock)
-		return;
-
-	wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
-}
-
 static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
 {
 	early_set_memory_decrypted((unsigned long) ptr, size);
@@ -428,6 +404,27 @@
 	}
 }
 
+static void kvm_guest_cpu_offline(bool shutdown)
+{
+	kvm_disable_steal_time();
+	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
+		wrmsrl(MSR_KVM_PV_EOI_EN, 0);
+	kvm_pv_disable_apf();
+	if (!shutdown)
+		apf_task_wake_all();
+	kvmclock_disable();
+}
+
+static int kvm_cpu_online(unsigned int cpu)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	kvm_guest_cpu_init();
+	local_irq_restore(flags);
+	return 0;
+}
+
 #ifdef CONFIG_SMP
 #define KVM_IPI_CLUSTER_SIZE	(2 * BITS_PER_LONG)
 
@@ -464,7 +461,7 @@
 		} else if (apic_id < min && max - apic_id < KVM_IPI_CLUSTER_SIZE) {
 			ipi_bitmap <<= min - apic_id;
 			min = apic_id;
-		} else if (apic_id < min + KVM_IPI_CLUSTER_SIZE) {
+		} else if (apic_id > min && apic_id < min + KVM_IPI_CLUSTER_SIZE) {
 			max = apic_id < max ? max : apic_id;
 		} else {
 			ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap,
@@ -547,31 +544,46 @@
 	kvm_spinlock_init();
 }
 
-static void kvm_guest_cpu_offline(void)
+static int kvm_cpu_down_prepare(unsigned int cpu)
 {
-	kvm_disable_steal_time();
-	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
-		wrmsrl(MSR_KVM_PV_EOI_EN, 0);
-	kvm_pv_disable_apf();
-	apf_task_wake_all();
-}
+	unsigned long flags;
 
-static int kvm_cpu_online(unsigned int cpu)
-{
-	local_irq_disable();
-	kvm_guest_cpu_init();
-	local_irq_enable();
+	local_irq_save(flags);
+	kvm_guest_cpu_offline(false);
+	local_irq_restore(flags);
 	return 0;
 }
 
-static int kvm_cpu_down_prepare(unsigned int cpu)
+#endif
+
+static int kvm_suspend(void)
 {
-	local_irq_disable();
-	kvm_guest_cpu_offline();
-	local_irq_enable();
+	u64 val = 0;
+
+	kvm_guest_cpu_offline(false);
+
+#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL
+	if (kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL))
+		rdmsrl(MSR_KVM_POLL_CONTROL, val);
+	has_guest_poll = !(val & 1);
+#endif
 	return 0;
 }
+
+static void kvm_resume(void)
+{
+	kvm_cpu_online(raw_smp_processor_id());
+
+#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL
+	if (kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL) && has_guest_poll)
+		wrmsrl(MSR_KVM_POLL_CONTROL, 0);
 #endif
+}
+
+static struct syscore_ops kvm_syscore_ops = {
+	.suspend	= kvm_suspend,
+	.resume		= kvm_resume,
+};
 
 static void __init kvm_apf_trap_init(void)
 {
@@ -606,6 +618,37 @@
 	native_flush_tlb_others(flushmask, info);
 }
 
+static void kvm_pv_guest_cpu_reboot(void *unused)
+{
+	kvm_guest_cpu_offline(true);
+}
+
+static int kvm_pv_reboot_notify(struct notifier_block *nb,
+				unsigned long code, void *unused)
+{
+	if (code == SYS_RESTART)
+		on_each_cpu(kvm_pv_guest_cpu_reboot, NULL, 1);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kvm_pv_reboot_nb = {
+	.notifier_call = kvm_pv_reboot_notify,
+};
+
+/*
+ * After a PV feature is registered, the host will keep writing to the
+ * registered memory location. If the guest happens to shutdown, this memory
+ * won't be valid. In cases like kexec, in which you install a new kernel, this
+ * means a random memory location will be kept being written.
+ */
+#ifdef CONFIG_KEXEC_CORE
+static void kvm_crash_shutdown(struct pt_regs *regs)
+{
+	kvm_guest_cpu_offline(true);
+	native_machine_crash_shutdown(regs);
+}
+#endif
+
 static void __init kvm_guest_init(void)
 {
 	int i;
@@ -649,6 +692,12 @@
 	kvm_guest_cpu_init();
 #endif
 
+#ifdef CONFIG_KEXEC_CORE
+	machine_ops.crash_shutdown = kvm_crash_shutdown;
+#endif
+
+	register_syscore_ops(&kvm_syscore_ops);
+
 	/*
 	 * Hard lockup detection is enabled by default. Disable it, as guests
 	 * can get false positives too easily, for example if the host is
--- linux-ein-5.4.0.orig/arch/x86/kernel/kvmclock.c
+++ linux-ein-5.4.0/arch/x86/kernel/kvmclock.c
@@ -20,13 +20,12 @@
 #include <asm/hypervisor.h>
 #include <asm/mem_encrypt.h>
 #include <asm/x86_init.h>
-#include <asm/reboot.h>
 #include <asm/kvmclock.h>
 
 static int kvmclock __initdata = 1;
 static int kvmclock_vsyscall __initdata = 1;
-static int msr_kvm_system_time __ro_after_init = MSR_KVM_SYSTEM_TIME;
-static int msr_kvm_wall_clock __ro_after_init = MSR_KVM_WALL_CLOCK;
+static int msr_kvm_system_time __ro_after_init;
+static int msr_kvm_wall_clock __ro_after_init;
 static u64 kvm_sched_clock_offset __ro_after_init;
 
 static int __init parse_no_kvmclock(char *arg)
@@ -51,18 +50,9 @@
 static struct pvclock_vsyscall_time_info
 			hv_clock_boot[HVC_BOOT_ARRAY_SIZE] __bss_decrypted __aligned(PAGE_SIZE);
 static struct pvclock_wall_clock wall_clock __bss_decrypted;
-static DEFINE_PER_CPU(struct pvclock_vsyscall_time_info *, hv_clock_per_cpu);
 static struct pvclock_vsyscall_time_info *hvclock_mem;
-
-static inline struct pvclock_vcpu_time_info *this_cpu_pvti(void)
-{
-	return &this_cpu_read(hv_clock_per_cpu)->pvti;
-}
-
-static inline struct pvclock_vsyscall_time_info *this_cpu_hvclock(void)
-{
-	return this_cpu_read(hv_clock_per_cpu);
-}
+DEFINE_PER_CPU(struct pvclock_vsyscall_time_info *, hv_clock_per_cpu);
+EXPORT_PER_CPU_SYMBOL_GPL(hv_clock_per_cpu);
 
 /*
  * The wallclock is the time of day when we booted. Since then, some time may
@@ -197,28 +187,10 @@
 }
 #endif
 
-/*
- * After the clock is registered, the host will keep writing to the
- * registered memory location. If the guest happens to shutdown, this memory
- * won't be valid. In cases like kexec, in which you install a new kernel, this
- * means a random memory location will be kept being written. So before any
- * kind of shutdown from our side, we unregister the clock by writing anything
- * that does not have the 'enable' bit set in the msr
- */
-#ifdef CONFIG_KEXEC_CORE
-static void kvm_crash_shutdown(struct pt_regs *regs)
-{
-	native_write_msr(msr_kvm_system_time, 0, 0);
-	kvm_disable_steal_time();
-	native_machine_crash_shutdown(regs);
-}
-#endif
-
-static void kvm_shutdown(void)
+void kvmclock_disable(void)
 {
-	native_write_msr(msr_kvm_system_time, 0, 0);
-	kvm_disable_steal_time();
-	native_machine_shutdown();
+	if (msr_kvm_system_time)
+		native_write_msr(msr_kvm_system_time, 0, 0);
 }
 
 static void __init kvmclock_init_mem(void)
@@ -315,7 +287,10 @@
 	if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) {
 		msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
 		msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
-	} else if (!kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
+	} else if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
+		msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
+		msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
+	} else {
 		return;
 	}
 
@@ -346,10 +321,6 @@
 #endif
 	x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
 	x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
-	machine_ops.shutdown  = kvm_shutdown;
-#ifdef CONFIG_KEXEC_CORE
-	machine_ops.crash_shutdown  = kvm_crash_shutdown;
-#endif
 	kvm_get_preset_lpj();
 
 	/*
--- linux-ein-5.4.0.orig/arch/x86/kernel/module.c
+++ linux-ein-5.4.0/arch/x86/kernel/module.c
@@ -114,6 +114,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;
--- linux-ein-5.4.0.orig/arch/x86/kernel/nmi.c
+++ linux-ein-5.4.0/arch/x86/kernel/nmi.c
@@ -104,18 +104,21 @@
 }
 fs_initcall(nmi_warning_debugfs);
 
-static void nmi_max_handler(struct irq_work *w)
+static void nmi_check_duration(struct nmiaction *action, u64 duration)
 {
-	struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
 	int remainder_ns, decimal_msecs;
-	u64 whole_msecs = READ_ONCE(a->max_duration);
 
-	remainder_ns = do_div(whole_msecs, (1000 * 1000));
+	if (duration < nmi_longest_ns || duration < action->max_duration)
+		return;
+
+	action->max_duration = duration;
+
+	remainder_ns = do_div(duration, (1000 * 1000));
 	decimal_msecs = remainder_ns / 1000;
 
 	printk_ratelimited(KERN_INFO
 		"INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
-		a->handler, whole_msecs, decimal_msecs);
+		action->handler, duration, decimal_msecs);
 }
 
 static int nmi_handle(unsigned int type, struct pt_regs *regs)
@@ -142,11 +145,7 @@
 		delta = sched_clock() - delta;
 		trace_nmi_handler(a->handler, (int)delta, thishandled);
 
-		if (delta < nmi_longest_ns || delta < a->max_duration)
-			continue;
-
-		a->max_duration = delta;
-		irq_work_queue(&a->irq_work);
+		nmi_check_duration(a, delta);
 	}
 
 	rcu_read_unlock();
@@ -164,8 +163,6 @@
 	if (!action->handler)
 		return -EINVAL;
 
-	init_irq_work(&action->irq_work, nmi_max_handler);
-
 	raw_spin_lock_irqsave(&desc->lock, flags);
 
 	/*
--- linux-ein-5.4.0.orig/arch/x86/kernel/pmem.c
+++ linux-ein-5.4.0/arch/x86/kernel/pmem.c
@@ -27,6 +27,11 @@
 	 * simply here to trigger the module to load on demand.
 	 */
 	pdev = platform_device_alloc("e820_pmem", -1);
-	return platform_device_add(pdev);
+
+	rc = platform_device_add(pdev);
+	if (rc)
+		platform_device_put(pdev);
+
+	return rc;
 }
 device_initcall(register_e820_pmem);
--- linux-ein-5.4.0.orig/arch/x86/kernel/process.c
+++ linux-ein-5.4.0/arch/x86/kernel/process.c
@@ -428,28 +428,20 @@
 
 	lockdep_assert_irqs_disabled();
 
-	/*
-	 * If TIF_SSBD is different, select the proper mitigation
-	 * method. Note that if SSBD mitigation is disabled or permanentely
-	 * enabled this branch can't be taken because nothing can set
-	 * TIF_SSBD.
-	 */
-	if (tif_diff & _TIF_SSBD) {
-		if (static_cpu_has(X86_FEATURE_VIRT_SSBD)) {
+	/* 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)) {
+	} 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)) {
-			msr |= ssbd_tif_to_spec_ctrl(tifn);
-			updmsr  = true;
-		}
+	} 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,
-	 * otherwise avoid the MSR write.
-	 */
+	/* 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);
@@ -457,7 +449,7 @@
 	}
 
 	if (updmsr)
-		wrmsrl(MSR_IA32_SPEC_CTRL, msr);
+		update_spec_ctrl_cond(msr);
 }
 
 static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
@@ -667,6 +659,10 @@
  */
 static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 {
+	/* User has disallowed the use of MWAIT. Fallback to HALT */
+	if (boot_option_idle_override == IDLE_NOMWAIT)
+		return 0;
+
 	if (c->x86_vendor != X86_VENDOR_INTEL)
 		return 0;
 
@@ -777,9 +773,8 @@
 	} else if (!strcmp(str, "nomwait")) {
 		/*
 		 * If the boot option of "idle=nomwait" is added,
-		 * it means that mwait will be disabled for CPU C2/C3
-		 * states. In such case it won't touch the variable
-		 * of boot_option_idle_override.
+		 * it means that mwait will be disabled for CPU C1/C2/C3
+		 * states.
 		 */
 		boot_option_idle_override = IDLE_NOMWAIT;
 	} else
--- linux-ein-5.4.0.orig/arch/x86/kernel/process_32.c
+++ linux-ein-5.4.0/arch/x86/kernel/process_32.c
@@ -229,14 +229,12 @@
 {
 	struct thread_struct *prev = &prev_p->thread,
 			     *next = &next_p->thread;
-	struct fpu *prev_fpu = &prev->fpu;
-	struct fpu *next_fpu = &next->fpu;
 	int cpu = smp_processor_id();
 
 	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
 
 	if (!test_thread_flag(TIF_NEED_FPU_LOAD))
-		switch_fpu_prepare(prev_fpu, cpu);
+		switch_fpu_prepare(prev_p, cpu);
 
 	/*
 	 * Save away %gs. No need to save %fs, as it was saved on the
@@ -292,10 +290,10 @@
 
 	this_cpu_write(current_task, next_p);
 
-	switch_fpu_finish(next_fpu);
+	switch_fpu_finish(next_p);
 
 	/* Load the Intel cache allocation PQR MSR. */
-	resctrl_sched_in();
+	resctrl_sched_in(next_p);
 
 	return prev_p;
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/process_64.c
+++ linux-ein-5.4.0/arch/x86/kernel/process_64.c
@@ -316,7 +316,7 @@
 		 */
 		mutex_lock(&task->mm->context.lock);
 		ldt = task->mm->context.ldt;
-		if (unlikely(idx >= ldt->nr_entries))
+		if (unlikely(!ldt || idx >= ldt->nr_entries))
 			base = 0;
 		else
 			base = get_desc_base(ldt->entries + idx);
@@ -505,15 +505,13 @@
 {
 	struct thread_struct *prev = &prev_p->thread;
 	struct thread_struct *next = &next_p->thread;
-	struct fpu *prev_fpu = &prev->fpu;
-	struct fpu *next_fpu = &next->fpu;
 	int cpu = smp_processor_id();
 
 	WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_ENTRY) &&
 		     this_cpu_read(irq_count) != -1);
 
 	if (!test_thread_flag(TIF_NEED_FPU_LOAD))
-		switch_fpu_prepare(prev_fpu, cpu);
+		switch_fpu_prepare(prev_p, cpu);
 
 	/* We must save %fs and %gs before load_TLS() because
 	 * %fs and %gs may be cleared by load_TLS().
@@ -565,7 +563,7 @@
 	this_cpu_write(current_task, next_p);
 	this_cpu_write(cpu_current_top_of_stack, task_top_of_stack(next_p));
 
-	switch_fpu_finish(next_fpu);
+	switch_fpu_finish(next_p);
 
 	/* Reload sp0. */
 	update_task_stack(next_p);
@@ -612,7 +610,7 @@
 	}
 
 	/* Load the Intel cache allocation PQR MSR. */
-	resctrl_sched_in();
+	resctrl_sched_in(next_p);
 
 	return prev_p;
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/quirks.c
+++ linux-ein-5.4.0/arch/x86/kernel/quirks.c
@@ -95,7 +95,7 @@
 static void ich_force_enable_hpet(struct pci_dev *dev)
 {
 	u32 val;
-	u32 uninitialized_var(rcba);
+	u32 rcba;
 	int err = 0;
 
 	if (hpet_address || force_hpet_address)
@@ -185,7 +185,7 @@
 static void old_ich_force_hpet_resume(void)
 {
 	u32 val;
-	u32 uninitialized_var(gen_cntl);
+	u32 gen_cntl;
 
 	if (!force_hpet_address || !cached_dev)
 		return;
@@ -207,7 +207,7 @@
 static void old_ich_force_enable_hpet(struct pci_dev *dev)
 {
 	u32 val;
-	u32 uninitialized_var(gen_cntl);
+	u32 gen_cntl;
 
 	if (hpet_address || force_hpet_address)
 		return;
@@ -298,7 +298,7 @@
 
 static void vt8237_force_enable_hpet(struct pci_dev *dev)
 {
-	u32 uninitialized_var(val);
+	u32 val;
 
 	if (hpet_address || force_hpet_address)
 		return;
@@ -429,7 +429,7 @@
 
 static void nvidia_force_enable_hpet(struct pci_dev *dev)
 {
-	u32 uninitialized_var(val);
+	u32 val;
 
 	if (hpet_address || force_hpet_address)
 		return;
--- linux-ein-5.4.0.orig/arch/x86/kernel/reboot.c
+++ linux-ein-5.4.0/arch/x86/kernel/reboot.c
@@ -32,6 +32,7 @@
 #include <asm/realmode.h>
 #include <asm/x86_init.h>
 #include <asm/efi.h>
+#include <asm/nospec-branch.h>
 
 /*
  * Power off function, if any
@@ -113,25 +114,17 @@
 	spin_unlock(&rtc_lock);
 
 	/*
-	 * Switch back to the initial page table.
+	 * Switch to the trampoline page table.
 	 */
-#ifdef CONFIG_X86_32
-	load_cr3(initial_page_table);
-#else
-	write_cr3(real_mode_header->trampoline_pgd);
-
-	/* Exiting long mode will fail if CR4.PCIDE is set. */
-	if (boot_cpu_has(X86_FEATURE_PCID))
-		cr4_clear_bits(X86_CR4_PCIDE);
-#endif
+	load_trampoline_pgtable();
 
 	/* 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
@@ -197,6 +190,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",
@@ -380,10 +381,11 @@
 	},
 	{	/* Handle problems with rebooting on the OptiPlex 990. */
 		.callback = set_pci_reboot,
-		.ident = "Dell OptiPlex 990",
+		.ident = "Dell OptiPlex 990 BIOS A0x",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
+			DMI_MATCH(DMI_BIOS_VERSION, "A0"),
 		},
 	},
 	{	/* Handle problems with rebooting on Dell 300's */
@@ -469,6 +471,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,
@@ -478,7 +489,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"),
+		},
+	},
 	{ }
 };
 
@@ -518,42 +568,29 @@
 	}
 }
 
-static void vmxoff_nmi(int cpu, struct pt_regs *regs)
-{
-	cpu_emergency_vmxoff();
-}
+static inline void nmi_shootdown_cpus_on_restart(void);
 
-/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
-static void emergency_vmx_disable_all(void)
+static void emergency_reboot_disable_virtualization(void)
 {
 	/* Just make sure we won't change CPUs while doing this */
 	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.
+	 * Disable virtualization on all CPUs before rebooting to avoid hanging
+	 * the system, as VMX and SVM block INIT when running in the host.
 	 *
-	 * 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.
+	 * 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 disable VMX/SVM and halt.
 	 *
-	 * 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 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.
-	 */
-	if (cpu_has_vmx() && cpu_vmx_enabled()) {
-		/* Disable VMX on this CPU. */
-		cpu_vmxoff();
+	 * Do the NMI shootdown even if virtualization is off on _this_ CPU, as
+	 * other CPUs may have virtualization enabled.
+	 */
+	if (cpu_has_vmx() || cpu_has_svm(NULL)) {
+		/* Safely force _this_ CPU out of VMX/SVM operation. */
+		cpu_emergency_disable_virtualization();
 
-		/* Halt and disable VMX on the other CPUs */
-		nmi_shootdown_cpus(vmxoff_nmi);
+		/* Disable VMX/SVM and halt on other CPUs. */
+		nmi_shootdown_cpus_on_restart();
 
 	}
 }
@@ -590,7 +627,7 @@
 	unsigned short mode;
 
 	if (reboot_emergency)
-		emergency_vmx_disable_all();
+		emergency_reboot_disable_virtualization();
 
 	tboot_shutdown(TB_SHUTDOWN_REBOOT);
 
@@ -795,6 +832,17 @@
 /* This is the CPU performing the emergency shutdown work. */
 int crashing_cpu = -1;
 
+/*
+ * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
+ * reboot.  VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
+ * GIF=0, i.e. if the crash occurred between CLGI and STGI.
+ */
+void cpu_emergency_disable_virtualization(void)
+{
+	cpu_emergency_vmxoff();
+	cpu_emergency_svm_disable();
+}
+
 #if defined(CONFIG_SMP)
 
 static nmi_shootdown_cb shootdown_callback;
@@ -817,7 +865,14 @@
 		return NMI_HANDLED;
 	local_irq_disable();
 
-	shootdown_callback(cpu, regs);
+	if (shootdown_callback)
+		shootdown_callback(cpu, regs);
+
+	/*
+	 * Prepare the CPU for reboot _after_ invoking the callback so that the
+	 * callback can safely use virtualization instructions, e.g. VMCLEAR.
+	 */
+	cpu_emergency_disable_virtualization();
 
 	atomic_dec(&waiting_for_crash_ipi);
 	/* Assume hlt works */
@@ -828,18 +883,32 @@
 	return NMI_HANDLED;
 }
 
-/*
- * Halt all other CPUs, calling the specified function on each of them
+/**
+ * nmi_shootdown_cpus - Stop other CPUs via NMI
+ * @callback:	Optional callback to be invoked from the NMI handler
+ *
+ * The NMI handler on the remote CPUs invokes @callback, if not
+ * NULL, first and then disables virtualization to ensure that
+ * INIT is recognized during reboot.
  *
- * This function can be used to halt all other CPUs on crash
- * or emergency reboot time. The function passed as parameter
- * will be called inside a NMI handler on all CPUs.
+ * nmi_shootdown_cpus() can only be invoked once. After the first
+ * invocation all other CPUs are stuck in crash_nmi_callback() and
+ * cannot respond to a second NMI.
  */
 void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 {
 	unsigned long msecs;
+
 	local_irq_disable();
 
+	/*
+	 * Avoid certain doom if a shootdown already occurred; re-registering
+	 * the NMI handler will cause list corruption, modifying the callback
+	 * will do who knows what, etc...
+	 */
+	if (WARN_ON_ONCE(crash_ipi_issued))
+		return;
+
 	/* Make a note of crashing cpu. Will be used in NMI callback. */
 	crashing_cpu = safe_smp_processor_id();
 
@@ -867,7 +936,17 @@
 		msecs--;
 	}
 
-	/* Leave the nmi callback set */
+	/*
+	 * Leave the nmi callback set, shootdown is a one-time thing.  Clearing
+	 * the callback could result in a NULL pointer dereference if a CPU
+	 * (finally) responds after the timeout expires.
+	 */
+}
+
+static inline void nmi_shootdown_cpus_on_restart(void)
+{
+	if (!crash_ipi_issued)
+		nmi_shootdown_cpus(NULL);
 }
 
 /*
@@ -897,6 +976,8 @@
 	/* No other CPUs to shoot down */
 }
 
+static inline void nmi_shootdown_cpus_on_restart(void) { }
+
 void run_crash_ipi_callback(struct pt_regs *regs)
 {
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/relocate_kernel_32.S
+++ linux-ein-5.4.0/arch/x86/kernel/relocate_kernel_32.S
@@ -8,6 +8,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
@@ -165,6 +166,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-ein-5.4.0.orig/arch/x86/kernel/relocate_kernel_64.S
+++ linux-ein-5.4.0/arch/x86/kernel/relocate_kernel_64.S
@@ -9,6 +9,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
@@ -192,6 +193,7 @@
 1:
 	popq	%rdx
 	leaq	PAGE_SIZE(%r10), %rsp
+	ANNOTATE_RETPOLINE_SAFE
 	call	*%rdx
 
 	/* get the re-entry point of the peer system */
--- linux-ein-5.4.0.orig/arch/x86/kernel/setup.c
+++ linux-ein-5.4.0/arch/x86/kernel/setup.c
@@ -73,6 +73,7 @@
 #include <linux/jiffies.h>
 #include <linux/mem_encrypt.h>
 #include <linux/sizes.h>
+#include <linux/security.h>
 
 #include <linux/usb/xhci-dbgp.h>
 #include <video/edid.h>
@@ -1027,6 +1028,13 @@
 	if (efi_enabled(EFI_BOOT))
 		efi_init();
 
+	efi_set_secure_boot(boot_params.secure_boot);
+
+#ifdef CONFIG_LOCK_DOWN_IN_SECURE_BOOT
+	if (efi_enabled(EFI_SECURE_BOOT))
+		security_lock_kernel_down("EFI Secure Boot mode", LOCKDOWN_INTEGRITY_MAX);
+#endif
+
 	dmi_setup();
 
 	/*
@@ -1126,6 +1134,7 @@
 		efi_fake_memmap();
 		efi_find_mirror();
 		efi_esrt_init();
+		efi_mokvar_table_init();
 
 		/*
 		 * The EFI specification says that boot service code won't be
@@ -1179,23 +1188,13 @@
 	/* Allocate bigger log buffer */
 	setup_log_buf(1);
 
-	if (efi_enabled(EFI_BOOT)) {
-		switch (boot_params.secure_boot) {
-		case efi_secureboot_mode_disabled:
-			pr_info("Secure boot disabled\n");
-			break;
-		case efi_secureboot_mode_enabled:
-			pr_info("Secure boot enabled\n");
-			break;
-		default:
-			pr_info("Secure boot could not be determined\n");
-			break;
-		}
-	}
+	efi_set_secure_boot(boot_params.secure_boot);
 
 	reserve_initrd();
 
 	acpi_table_upgrade();
+	/* Look for ACPI tables and reserve memory occupied by them. */
+	acpi_boot_table_init();
 
 	vsmp_init();
 
@@ -1203,11 +1202,6 @@
 
 	early_platform_quirks();
 
-	/*
-	 * Parse the ACPI tables for possible boot-time SMP configuration.
-	 */
-	acpi_boot_table_init();
-
 	early_acpi_boot_init();
 
 	initmem_init();
--- linux-ein-5.4.0.orig/arch/x86/kernel/signal.c
+++ linux-ein-5.4.0/arch/x86/kernel/signal.c
@@ -241,10 +241,11 @@
 	     void __user **fpstate)
 {
 	/* Default to using normal stack */
+	bool nested_altstack = on_sig_stack(regs->sp);
+	bool entering_altstack = false;
 	unsigned long math_size = 0;
 	unsigned long sp = regs->sp;
 	unsigned long buf_fx = 0;
-	int onsigstack = on_sig_stack(sp);
 	int ret;
 
 	/* redzone */
@@ -253,15 +254,23 @@
 
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (sas_ss_flags(sp) == 0)
+		/*
+		 * This checks nested_altstack via sas_ss_flags(). Sensible
+		 * programs use SS_AUTODISARM, which disables that check, and
+		 * programs that don't use SS_AUTODISARM get compatible.
+		 */
+		if (sas_ss_flags(sp) == 0) {
 			sp = current->sas_ss_sp + current->sas_ss_size;
+			entering_altstack = true;
+		}
 	} else if (IS_ENABLED(CONFIG_X86_32) &&
-		   !onsigstack &&
+		   !nested_altstack &&
 		   regs->ss != __USER_DS &&
 		   !(ka->sa.sa_flags & SA_RESTORER) &&
 		   ka->sa.sa_restorer) {
 		/* This is the legacy signal stack switching. */
 		sp = (unsigned long) ka->sa.sa_restorer;
+		entering_altstack = true;
 	}
 
 	sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32),
@@ -274,8 +283,15 @@
 	 * If we are on the alternate signal stack and would overflow it, don't.
 	 * Return an always-bogus address instead so we will die with SIGSEGV.
 	 */
-	if (onsigstack && !likely(on_sig_stack(sp)))
+	if (unlikely((nested_altstack || entering_altstack) &&
+		     !__on_sig_stack(sp))) {
+
+		if (show_unhandled_signals && printk_ratelimit())
+			pr_info("%s[%d] overflowed sigaltstack\n",
+				current->comm, task_pid_nr(current));
+
 		return (void __user *)-1L;
+	}
 
 	/* save i387 and extended state */
 	ret = copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size);
@@ -770,30 +786,8 @@
 
 static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
 {
-	/*
-	 * This function is fundamentally broken as currently
-	 * implemented.
-	 *
-	 * The idea is that we want to trigger a call to the
-	 * restart_block() syscall and that we want in_ia32_syscall(),
-	 * in_x32_syscall(), etc. to match whatever they were in the
-	 * syscall being restarted.  We assume that the syscall
-	 * instruction at (regs->ip - 2) matches whatever syscall
-	 * instruction we used to enter in the first place.
-	 *
-	 * The problem is that we can get here when ptrace pokes
-	 * syscall-like values into regs even if we're not in a syscall
-	 * at all.
-	 *
-	 * For now, we maintain historical behavior and guess based on
-	 * stored state.  We could do better by saving the actual
-	 * syscall arch in restart_block or (with caveats on x32) by
-	 * checking if regs->ip points to 'int $0x80'.  The current
-	 * behavior is incorrect if a tracer has a different bitness
-	 * than the tracee.
-	 */
 #ifdef CONFIG_IA32_EMULATION
-	if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
+	if (current_thread_info()->status & TS_COMPAT_RESTART)
 		return __NR_ia32_restart_syscall;
 #endif
 #ifdef CONFIG_X86_X32_ABI
--- linux-ein-5.4.0.orig/arch/x86/kernel/smp.c
+++ linux-ein-5.4.0/arch/x86/kernel/smp.c
@@ -31,7 +31,7 @@
 #include <asm/mce.h>
 #include <asm/trace/irq_vectors.h>
 #include <asm/kexec.h>
-#include <asm/virtext.h>
+#include <asm/reboot.h>
 
 /*
  *	Some notes on x86 processor bugs affecting SMP operation:
@@ -121,7 +121,7 @@
 	if (raw_smp_processor_id() == atomic_read(&stopping_cpu))
 		return NMI_HANDLED;
 
-	cpu_emergency_vmxoff();
+	cpu_emergency_disable_virtualization();
 	stop_this_cpu(NULL);
 
 	return NMI_HANDLED;
@@ -134,7 +134,7 @@
 asmlinkage __visible void smp_reboot_interrupt(void)
 {
 	ipi_entering_ack_irq();
-	cpu_emergency_vmxoff();
+	cpu_emergency_disable_virtualization();
 	stop_this_cpu(NULL);
 	irq_exit();
 }
--- linux-ein-5.4.0.orig/arch/x86/kernel/smpboot.c
+++ linux-ein-5.4.0/arch/x86/kernel/smpboot.c
@@ -99,6 +99,17 @@
 DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
+struct mwait_cpu_dead {
+	unsigned int	control;
+	unsigned int	status;
+};
+
+/*
+ * Cache line aligned data for mwait_play_dead(). Separate on purpose so
+ * that it's unlikely to be touched by other CPUs.
+ */
+static DEFINE_PER_CPU_ALIGNED(struct mwait_cpu_dead, mwait_cpu_dead);
+
 /* Logical package management. We might want to allocate that dynamically */
 unsigned int __max_logical_packages __read_mostly;
 EXPORT_SYMBOL(__max_logical_packages);
@@ -224,6 +235,8 @@
 #endif
 	load_current_idt();
 	cpu_init();
+	fpu__init_cpu();
+	rcu_cpu_starting(raw_smp_processor_id());
 	x86_cpuinit.early_percpu_clock_init();
 	preempt_disable();
 	smp_callin();
@@ -262,6 +275,14 @@
 
 	wmb();
 	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+
+	/*
+	 * 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();
 }
 
 /**
@@ -1591,14 +1612,28 @@
 	if (ret)
 		return ret;
 
-	/*
-	 * Disable the local APIC. Otherwise IPI broadcasts will reach
-	 * it. It still responds normally to INIT, NMI, SMI, and SIPI
-	 * messages.
-	 */
-	apic_soft_disable();
 	cpu_disable_common();
 
+        /*
+         * Disable the local APIC. Otherwise IPI broadcasts will reach
+         * it. It still responds normally to INIT, NMI, SMI, and SIPI
+         * messages.
+         *
+         * Disabling the APIC must happen after cpu_disable_common()
+         * which invokes fixup_irqs().
+         *
+         * Disabling the APIC preserves already set bits in IRR, but
+         * an interrupt arriving after disabling the local APIC does not
+         * set the corresponding IRR bit.
+         *
+         * fixup_irqs() scans IRR for set bits so it can raise a not
+         * yet handled interrupt on the new destination CPU via an IPI
+         * but obviously it can't do so for IRR bits which are not set.
+         * IOW, interrupts arriving after disabling the local APIC will
+         * be lost.
+         */
+	apic_soft_disable();
+
 	return 0;
 }
 
@@ -1652,10 +1687,10 @@
  */
 static inline void mwait_play_dead(void)
 {
+	struct mwait_cpu_dead *md = this_cpu_ptr(&mwait_cpu_dead);
 	unsigned int eax, ebx, ecx, edx;
 	unsigned int highest_cstate = 0;
 	unsigned int highest_subcstate = 0;
-	void *mwait_ptr;
 	int i;
 
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
@@ -1690,13 +1725,6 @@
 			(highest_subcstate - 1);
 	}
 
-	/*
-	 * This should be a memory location in a cache line which is
-	 * unlikely to be touched by other processors.  The actual
-	 * content is immaterial as it is not actually modified in any way.
-	 */
-	mwait_ptr = &current_thread_info()->flags;
-
 	wbinvd();
 
 	while (1) {
@@ -1708,9 +1736,9 @@
 		 * case where we return around the loop.
 		 */
 		mb();
-		clflush(mwait_ptr);
+		clflush(md);
 		mb();
-		__monitor(mwait_ptr, 0, 0);
+		__monitor(md, 0, 0);
 		mb();
 		__mwait(eax, 0);
 		/*
--- linux-ein-5.4.0.orig/arch/x86/kernel/stacktrace.c
+++ linux-ein-5.4.0/arch/x86/kernel/stacktrace.c
@@ -58,7 +58,6 @@
 			 * or a page fault), which can make frame pointers
 			 * unreliable.
 			 */
-
 			if (IS_ENABLED(CONFIG_FRAME_POINTER))
 				return -EINVAL;
 		}
@@ -81,10 +80,6 @@
 	if (unwind_error(&state))
 		return -EINVAL;
 
-	/* Success path for non-user tasks, i.e. kthreads and idle tasks */
-	if (!(task->flags & (PF_KTHREAD | PF_IDLE)))
-		return -EINVAL;
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/step.c
+++ linux-ein-5.4.0/arch/x86/kernel/step.c
@@ -175,8 +175,7 @@
 	 *
 	 * NOTE: this means that set/clear TIF_BLOCKSTEP is only safe if
 	 * task is current or it can't be running, otherwise we can race
-	 * with __switch_to_xtra(). We rely on ptrace_freeze_traced() but
-	 * PTRACE_KILL is not safe.
+	 * with __switch_to_xtra(). We rely on ptrace_freeze_traced().
 	 */
 	local_irq_disable();
 	debugctl = get_debugctlmsr();
--- linux-ein-5.4.0.orig/arch/x86/kernel/sys_x86_64.c
+++ linux-ein-5.4.0/arch/x86/kernel/sys_x86_64.c
@@ -70,9 +70,6 @@
 	if (*str == 0)
 		return 1;
 
-	if (*str == '=')
-		str++;
-
 	if (!strcmp(str, "32"))
 		va_align.flags = ALIGN_VA_32;
 	else if (!strcmp(str, "64"))
@@ -82,11 +79,11 @@
 	else if (!strcmp(str, "on"))
 		va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;
 	else
-		return 0;
+		pr_warn("invalid option value: 'align_va_addr=%s'\n", str);
 
 	return 1;
 }
-__setup("align_va_addr", control_va_addr_alignment);
+__setup("align_va_addr=", control_va_addr_alignment);
 
 SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 		unsigned long, prot, unsigned long, flags,
--- linux-ein-5.4.0.orig/arch/x86/kernel/sysfb_efi.c
+++ linux-ein-5.4.0/arch/x86/kernel/sysfb_efi.c
@@ -264,6 +264,22 @@
 					"Lenovo ideapad D330-10IGM"),
 		},
 	},
+	{
+		/* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+					"IdeaPad Duet 3 10IGL5"),
+		},
+	},
+	{
+		/* Lenovo Yoga Book X91F / X91L */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			/* Non exact match to match F + L versions */
+			DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
+		},
+	},
 	{},
 };
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/sysfb_simplefb.c
+++ linux-ein-5.4.0/arch/x86/kernel/sysfb_simplefb.c
@@ -90,11 +90,11 @@
 	if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
 		size <<= 16;
 	length = mode->height * mode->stride;
-	length = PAGE_ALIGN(length);
 	if (length > size) {
 		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
 		return -EINVAL;
 	}
+	length = PAGE_ALIGN(length);
 
 	/* setup IORESOURCE_MEM as framebuffer memory */
 	memset(&res, 0, sizeof(res));
--- linux-ein-5.4.0.orig/arch/x86/kernel/tboot.c
+++ linux-ein-5.4.0/arch/x86/kernel/tboot.c
@@ -512,9 +512,6 @@
 	if (!tboot_enabled())
 		return 0;
 
-	if (intel_iommu_tboot_noforce)
-		return 1;
-
 	if (no_iommu || swiotlb || dmar_disabled)
 		pr_warning("Forcing Intel-IOMMU to enabled\n");
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/time.c
+++ linux-ein-5.4.0/arch/x86/kernel/time.c
@@ -25,10 +25,6 @@
 #include <asm/hpet.h>
 #include <asm/time.h>
 
-#ifdef CONFIG_X86_64
-__visible volatile unsigned long jiffies __cacheline_aligned_in_smp = INITIAL_JIFFIES;
-#endif
-
 unsigned long profile_pc(struct pt_regs *regs)
 {
 	unsigned long pc = instruction_pointer(regs);
@@ -91,10 +87,18 @@
 
 static __init void x86_late_time_init(void)
 {
+	/*
+	 * Before PIT/HPET init, select the interrupt mode. This is required
+	 * to make the decision whether PIT should be initialized correct.
+	 */
+	x86_init.irqs.intr_mode_select();
+
+	/* Setup the legacy timers */
 	x86_init.timers.timer_init();
+
 	/*
-	 * After PIT/HPET timers init, select and setup
-	 * the final interrupt mode for delivering IRQs.
+	 * After PIT/HPET timers init, set up the final interrupt mode for
+	 * delivering IRQs.
 	 */
 	x86_init.irqs.intr_mode_init();
 	tsc_init();
--- linux-ein-5.4.0.orig/arch/x86/kernel/tsc.c
+++ linux-ein-5.4.0/arch/x86/kernel/tsc.c
@@ -1162,6 +1162,12 @@
 
 EXPORT_SYMBOL_GPL(mark_tsc_unstable);
 
+static void __init tsc_disable_clocksource_watchdog(void)
+{
+	clocksource_tsc_early.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
+	clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
+}
+
 static void __init check_system_tsc_reliable(void)
 {
 #if defined(CONFIG_MGEODEGX1) || defined(CONFIG_MGEODE_LX) || defined(CONFIG_X86_GENERIC)
@@ -1178,6 +1184,23 @@
 #endif
 	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE))
 		tsc_clocksource_reliable = 1;
+
+	/*
+	 * Disable the clocksource watchdog when the system has:
+	 *  - TSC running at constant frequency
+	 *  - TSC which does not stop in C-States
+	 *  - the TSC_ADJUST register which allows to detect even minimal
+	 *    modifications
+	 *  - not more than two sockets. As the number of sockets cannot be
+	 *    evaluated at the early boot stage where this has to be
+	 *    invoked, check the number of online memory nodes as a
+	 *    fallback solution which is an reasonable estimate.
+	 */
+	if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
+	    boot_cpu_has(X86_FEATURE_NONSTOP_TSC) &&
+	    boot_cpu_has(X86_FEATURE_TSC_ADJUST) &&
+	    nr_online_nodes <= 2)
+		tsc_disable_clocksource_watchdog();
 }
 
 /*
@@ -1369,9 +1392,6 @@
 	if (tsc_unstable)
 		goto unreg;
 
-	if (tsc_clocksource_reliable || no_tsc_watchdog)
-		clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
-
 	if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
 		clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 
@@ -1506,7 +1526,7 @@
 	}
 
 	if (tsc_clocksource_reliable || no_tsc_watchdog)
-		clocksource_tsc_early.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
+		tsc_disable_clocksource_watchdog();
 
 	clocksource_register_khz(&clocksource_tsc_early, tsc_khz);
 	detect_art();
--- linux-ein-5.4.0.orig/arch/x86/kernel/tsc_msr.c
+++ linux-ein-5.4.0/arch/x86/kernel/tsc_msr.c
@@ -15,18 +15,46 @@
 #include <asm/param.h>
 #include <asm/tsc.h>
 
-#define MAX_NUM_FREQS	9
+#define MAX_NUM_FREQS	16 /* 4 bits to select the frequency */
+
+/*
+ * The frequency numbers in the SDM are e.g. 83.3 MHz, which does not contain a
+ * lot of accuracy which leads to clock drift. As far as we know Bay Trail SoCs
+ * use a 25 MHz crystal and Cherry Trail uses a 19.2 MHz crystal, the crystal
+ * is the source clk for a root PLL which outputs 1600 and 100 MHz. It is
+ * unclear if the root PLL outputs are used directly by the CPU clock PLL or
+ * if there is another PLL in between.
+ * This does not matter though, we can model the chain of PLLs as a single PLL
+ * with a quotient equal to the quotients of all PLLs in the chain multiplied.
+ * So we can create a simplified model of the CPU clock setup using a reference
+ * clock of 100 MHz plus a quotient which gets us as close to the frequency
+ * from the SDM as possible.
+ * For the 83.3 MHz example from above this would give us 100 MHz * 5 / 6 =
+ * 83 and 1/3 MHz, which matches exactly what has been measured on actual hw.
+ */
+#define TSC_REFERENCE_KHZ 100000
+
+struct muldiv {
+	u32 multiplier;
+	u32 divider;
+};
 
 /*
  * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
  * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
  * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
  * so we need manually differentiate SoC families. This is what the
- * field msr_plat does.
+ * field use_msr_plat does.
  */
 struct freq_desc {
-	u8 msr_plat;	/* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
+	bool use_msr_plat;
+	struct muldiv muldiv[MAX_NUM_FREQS];
+	/*
+	 * Some CPU frequencies in the SDM do not map to known PLL freqs, in
+	 * that case the muldiv array is empty and the freqs array is used.
+	 */
 	u32 freqs[MAX_NUM_FREQS];
+	u32 mask;
 };
 
 /*
@@ -35,31 +63,86 @@
  * by MSR based on SDM.
  */
 static const struct freq_desc freq_desc_pnw = {
-	0, { 0, 0, 0, 0, 0, 99840, 0, 83200 }
+	.use_msr_plat = false,
+	.freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 },
+	.mask = 0x07,
 };
 
 static const struct freq_desc freq_desc_clv = {
-	0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 }
+	.use_msr_plat = false,
+	.freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 },
+	.mask = 0x07,
 };
 
+/*
+ * Bay Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ *  000:   100 *  5 /  6  =  83.3333 MHz
+ *  001:   100 *  1 /  1  = 100.0000 MHz
+ *  010:   100 *  4 /  3  = 133.3333 MHz
+ *  011:   100 *  7 /  6  = 116.6667 MHz
+ *  100:   100 *  4 /  5  =  80.0000 MHz
+ */
 static const struct freq_desc freq_desc_byt = {
-	1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 }
+	.use_msr_plat = true,
+	.muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 },
+		    { 4, 5 } },
+	.mask = 0x07,
 };
 
+/*
+ * Cherry Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0000:   100 *  5 /  6  =  83.3333 MHz
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ * 0011:   100 *  7 /  6  = 116.6667 MHz
+ * 0100:   100 *  4 /  5  =  80.0000 MHz
+ * 0101:   100 * 14 / 15  =  93.3333 MHz
+ * 0110:   100 *  9 / 10  =  90.0000 MHz
+ * 0111:   100 *  8 /  9  =  88.8889 MHz
+ * 1000:   100 *  7 /  8  =  87.5000 MHz
+ */
 static const struct freq_desc freq_desc_cht = {
-	1, { 83300, 100000, 133300, 116700, 80000, 93300, 90000, 88900, 87500 }
+	.use_msr_plat = true,
+	.muldiv = { { 5, 6 }, {  1,  1 }, { 4,  3 }, { 7, 6 },
+		    { 4, 5 }, { 14, 15 }, { 9, 10 }, { 8, 9 },
+		    { 7, 8 } },
+	.mask = 0x0f,
 };
 
+/*
+ * Merriefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ */
 static const struct freq_desc freq_desc_tng = {
-	1, { 0, 100000, 133300, 0, 0, 0, 0, 0 }
+	.use_msr_plat = true,
+	.muldiv = { { 0, 0 }, { 1, 1 }, { 4, 3 } },
+	.mask = 0x07,
 };
 
+/*
+ * Moorefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0000:   100 *  5 /  6  =  83.3333 MHz
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ * 0011:   100 *  1 /  1  = 100.0000 MHz
+ */
 static const struct freq_desc freq_desc_ann = {
-	1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 }
+	.use_msr_plat = true,
+	.muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 1, 1 } },
+	.mask = 0x0f,
 };
 
+/*
+ * 24 MHz crystal? : 24 * 13 / 4 = 78 MHz
+ * Frequency step for Lightning Mountain SoC is fixed to 78 MHz,
+ * so all the frequency entries are 78000.
+ */
 static const struct freq_desc freq_desc_lgm = {
-	1, { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 }
+	.use_msr_plat = true,
+	.freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000,
+		   78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 },
+	.mask = 0x0f,
 };
 
 static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
@@ -81,17 +164,19 @@
  */
 unsigned long cpu_khz_from_msr(void)
 {
-	u32 lo, hi, ratio, freq;
+	u32 lo, hi, ratio, freq, tscref;
 	const struct freq_desc *freq_desc;
 	const struct x86_cpu_id *id;
+	const struct muldiv *md;
 	unsigned long res;
+	int index;
 
 	id = x86_match_cpu(tsc_msr_cpu_ids);
 	if (!id)
 		return 0;
 
 	freq_desc = (struct freq_desc *)id->driver_data;
-	if (freq_desc->msr_plat) {
+	if (freq_desc->use_msr_plat) {
 		rdmsr(MSR_PLATFORM_INFO, lo, hi);
 		ratio = (lo >> 8) & 0xff;
 	} else {
@@ -101,12 +186,28 @@
 
 	/* Get FSB FREQ ID */
 	rdmsr(MSR_FSB_FREQ, lo, hi);
+	index = lo & freq_desc->mask;
+	md = &freq_desc->muldiv[index];
 
-	/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
-	freq = freq_desc->freqs[lo & 0x7];
+	/*
+	 * Note this also catches cases where the index points to an unpopulated
+	 * part of muldiv, in that case the else will set freq and res to 0.
+	 */
+	if (md->divider) {
+		tscref = TSC_REFERENCE_KHZ * md->multiplier;
+		freq = DIV_ROUND_CLOSEST(tscref, md->divider);
+		/*
+		 * Multiplying by ratio before the division has better
+		 * accuracy than just calculating freq * ratio.
+		 */
+		res = DIV_ROUND_CLOSEST(tscref * ratio, md->divider);
+	} else {
+		freq = freq_desc->freqs[index];
+		res = freq * ratio;
+	}
 
-	/* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
-	res = freq * ratio;
+	if (freq == 0)
+		pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index);
 
 #ifdef CONFIG_X86_LOCAL_APIC
 	lapic_timer_period = (freq * 1000) / HZ;
--- linux-ein-5.4.0.orig/arch/x86/kernel/tsc_sync.c
+++ linux-ein-5.4.0/arch/x86/kernel/tsc_sync.c
@@ -30,6 +30,7 @@
 };
 
 static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
+static struct timer_list tsc_sync_check_timer;
 
 /*
  * TSC's on different sockets may be reset asynchronously.
@@ -77,6 +78,46 @@
 	}
 }
 
+/*
+ * Normally the tsc_sync will be checked every time system enters idle
+ * state, but there is still caveat that a system won't enter idle,
+ * either because it's too busy or configured purposely to not enter
+ * idle.
+ *
+ * So setup a periodic timer (every 10 minutes) to make sure the check
+ * is always on.
+ */
+
+#define SYNC_CHECK_INTERVAL		(HZ * 600)
+
+static void tsc_sync_check_timer_fn(struct timer_list *unused)
+{
+	int next_cpu;
+
+	tsc_verify_tsc_adjust(false);
+
+	/* Run the check for all onlined CPUs in turn */
+	next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
+	if (next_cpu >= nr_cpu_ids)
+		next_cpu = cpumask_first(cpu_online_mask);
+
+	tsc_sync_check_timer.expires += SYNC_CHECK_INTERVAL;
+	add_timer_on(&tsc_sync_check_timer, next_cpu);
+}
+
+static int __init start_sync_check_timer(void)
+{
+	if (!cpu_feature_enabled(X86_FEATURE_TSC_ADJUST) || tsc_clocksource_reliable)
+		return 0;
+
+	timer_setup(&tsc_sync_check_timer, tsc_sync_check_timer_fn, 0);
+	tsc_sync_check_timer.expires = jiffies + SYNC_CHECK_INTERVAL;
+	add_timer(&tsc_sync_check_timer);
+
+	return 0;
+}
+late_initcall(start_sync_check_timer);
+
 static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
 				   unsigned int cpu, bool bootcpu)
 {
--- linux-ein-5.4.0.orig/arch/x86/kernel/unwind_orc.c
+++ linux-ein-5.4.0/arch/x86/kernel/unwind_orc.c
@@ -90,22 +90,27 @@
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
 {
 	struct ftrace_ops *ops;
-	unsigned long caller;
+	unsigned long tramp_addr, offset;
 
 	ops = ftrace_ops_trampoline(ip);
 	if (!ops)
 		return NULL;
 
+	/* Set tramp_addr to the start of the code copied by the trampoline */
 	if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
-		caller = (unsigned long)ftrace_regs_call;
+		tramp_addr = (unsigned long)ftrace_regs_caller;
 	else
-		caller = (unsigned long)ftrace_call;
+		tramp_addr = (unsigned long)ftrace_caller;
+
+	/* Now place tramp_addr to the location within the trampoline ip is at */
+	offset = ip - ops->trampoline;
+	tramp_addr += offset;
 
 	/* Prevent unlikely recursion */
-	if (ip == caller)
+	if (ip == tramp_addr)
 		return NULL;
 
-	return orc_find(caller);
+	return orc_find(tramp_addr);
 }
 #else
 static struct orc_entry *orc_ftrace_find(unsigned long ip)
@@ -142,9 +147,6 @@
 {
 	static struct orc_entry *orc;
 
-	if (!orc_init)
-		return NULL;
-
 	if (ip == 0)
 		return &null_orc_entry;
 
@@ -360,8 +362,8 @@
 	if (!stack_access_ok(state, addr, sizeof(struct pt_regs)))
 		return false;
 
-	*ip = regs->ip;
-	*sp = regs->sp;
+	*ip = READ_ONCE_NOCHECK(regs->ip);
+	*sp = READ_ONCE_NOCHECK(regs->sp);
 	return true;
 }
 
@@ -373,14 +375,43 @@
 	if (!stack_access_ok(state, addr, IRET_FRAME_SIZE))
 		return false;
 
-	*ip = regs->ip;
-	*sp = regs->sp;
+	*ip = READ_ONCE_NOCHECK(regs->ip);
+	*sp = READ_ONCE_NOCHECK(regs->sp);
 	return true;
 }
 
+/*
+ * If state->regs is non-NULL, and points to a full pt_regs, just get the reg
+ * value from state->regs.
+ *
+ * Otherwise, if state->regs just points to IRET regs, and the previous frame
+ * had full regs, it's safe to get the value from the previous regs.  This can
+ * happen when early/late IRQ entry code gets interrupted by an NMI.
+ */
+static bool get_reg(struct unwind_state *state, unsigned int reg_off,
+		    unsigned long *val)
+{
+	unsigned int reg = reg_off/8;
+
+	if (!state->regs)
+		return false;
+
+	if (state->full_regs) {
+		*val = READ_ONCE_NOCHECK(((unsigned long *)state->regs)[reg]);
+		return true;
+	}
+
+	if (state->prev_regs) {
+		*val = READ_ONCE_NOCHECK(((unsigned long *)state->prev_regs)[reg]);
+		return true;
+	}
+
+	return false;
+}
+
 bool unwind_next_frame(struct unwind_state *state)
 {
-	unsigned long ip_p, sp, orig_ip = state->ip, prev_sp = state->sp;
+	unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
 	enum stack_type prev_type = state->stack_info.type;
 	struct orc_entry *orc;
 	bool indirect = false;
@@ -398,8 +429,11 @@
 	/*
 	 * Find the orc_entry associated with the text address.
 	 *
-	 * Decrement call return addresses by one so they work for sibling
-	 * calls and calls to noreturn functions.
+	 * For a call frame (as opposed to a signal frame), state->ip points to
+	 * the instruction after the call.  That instruction's stack layout
+	 * could be different from the call instruction's layout, for example
+	 * if the call was to a noreturn function.  So get the ORC data for the
+	 * call instruction itself.
 	 */
 	orc = orc_find(state->signal ? state->ip : state->ip - 1);
 	if (!orc) {
@@ -442,39 +476,35 @@
 		break;
 
 	case ORC_REG_R10:
-		if (!state->regs || !state->full_regs) {
+		if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
 			orc_warn("missing regs for base reg R10 at ip %pB\n",
 				 (void *)state->ip);
 			goto err;
 		}
-		sp = state->regs->r10;
 		break;
 
 	case ORC_REG_R13:
-		if (!state->regs || !state->full_regs) {
+		if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
 			orc_warn("missing regs for base reg R13 at ip %pB\n",
 				 (void *)state->ip);
 			goto err;
 		}
-		sp = state->regs->r13;
 		break;
 
 	case ORC_REG_DI:
-		if (!state->regs || !state->full_regs) {
+		if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
 			orc_warn("missing regs for base reg DI at ip %pB\n",
 				 (void *)state->ip);
 			goto err;
 		}
-		sp = state->regs->di;
 		break;
 
 	case ORC_REG_DX:
-		if (!state->regs || !state->full_regs) {
+		if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) {
 			orc_warn("missing regs for base reg DX at ip %pB\n",
 				 (void *)state->ip);
 			goto err;
 		}
-		sp = state->regs->dx;
 		break;
 
 	default:
@@ -501,6 +531,7 @@
 
 		state->sp = sp;
 		state->regs = NULL;
+		state->prev_regs = NULL;
 		state->signal = false;
 		break;
 
@@ -512,6 +543,7 @@
 		}
 
 		state->regs = (struct pt_regs *)sp;
+		state->prev_regs = NULL;
 		state->full_regs = true;
 		state->signal = true;
 		break;
@@ -523,6 +555,8 @@
 			goto err;
 		}
 
+		if (state->full_regs)
+			state->prev_regs = state->regs;
 		state->regs = (void *)sp - IRET_FRAME_OFFSET;
 		state->full_regs = false;
 		state->signal = true;
@@ -531,14 +565,14 @@
 	default:
 		orc_warn("unknown .orc_unwind entry type %d for ip %pB\n",
 			 orc->type, (void *)orig_ip);
-		break;
+		goto err;
 	}
 
 	/* Find BP: */
 	switch (orc->bp_reg) {
 	case ORC_REG_UNDEFINED:
-		if (state->regs && state->full_regs)
-			state->bp = state->regs->bp;
+		if (get_reg(state, offsetof(struct pt_regs, bp), &tmp))
+			state->bp = tmp;
 		break;
 
 	case ORC_REG_PREV_SP:
@@ -585,17 +619,20 @@
 	memset(state, 0, sizeof(*state));
 	state->task = task;
 
+	if (!orc_init)
+		goto err;
+
 	/*
 	 * Refuse to unwind the stack of a task while it's executing on another
 	 * CPU.  This check is racy, but that's ok: the unwinder has other
 	 * checks to prevent it from going off the rails.
 	 */
 	if (task_on_another_cpu(task))
-		goto done;
+		goto err;
 
 	if (regs) {
 		if (user_mode(regs))
-			goto done;
+			goto the_end;
 
 		state->ip = regs->ip;
 		state->sp = regs->sp;
@@ -614,9 +651,10 @@
 	} else {
 		struct inactive_task_frame *frame = (void *)task->thread.sp;
 
-		state->sp = task->thread.sp;
+		state->sp = task->thread.sp + sizeof(*frame);
 		state->bp = READ_ONCE_NOCHECK(frame->bp);
 		state->ip = READ_ONCE_NOCHECK(frame->ret_addr);
+		state->signal = (void *)state->ip == ret_from_fork;
 	}
 
 	if (get_stack_info((unsigned long *)state->sp, state->task,
@@ -628,6 +666,7 @@
 		 * generate some kind of backtrace if this happens.
 		 */
 		void *next_page = (void *)PAGE_ALIGN((unsigned long)state->sp);
+		state->error = true;
 		if (get_stack_info(next_page, state->task, &state->stack_info,
 				   &state->stack_mask))
 			return;
@@ -653,8 +692,9 @@
 
 	return;
 
-done:
+err:
+	state->error = true;
+the_end:
 	state->stack_info.type = STACK_TYPE_UNKNOWN;
-	return;
 }
 EXPORT_SYMBOL_GPL(__unwind_start);
--- linux-ein-5.4.0.orig/arch/x86/kernel/uprobes.c
+++ linux-ein-5.4.0/arch/x86/kernel/uprobes.c
@@ -255,12 +255,13 @@
 
 static bool is_prefix_bad(struct insn *insn)
 {
+	insn_byte_t p;
 	int i;
 
-	for (i = 0; i < insn->prefixes.nbytes; i++) {
+	for_each_insn_prefix(insn, i, p) {
 		insn_attr_t attr;
 
-		attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
+		attr = inat_get_opcode_attribute(p);
 		switch (attr) {
 		case INAT_MAKE_PREFIX(INAT_PFX_ES):
 		case INAT_MAKE_PREFIX(INAT_PFX_CS):
@@ -715,13 +716,15 @@
 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) {
 	case 0xeb:	/* jmp 8 */
 	case 0xe9:	/* jmp 32 */
-	case 0x90:	/* prefix* + nop; same as jmp with .offs = 0 */
 		break;
+	case 0x90:	/* prefix* + nop; same as jmp with .offs = 0 */
+		goto setup;
 
 	case 0xe8:	/* call relative */
 		branch_clear_offset(auprobe, insn);
@@ -746,11 +749,12 @@
 	 * 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;
 	}
 
+setup:
 	auprobe->branch.opc1 = opc1;
 	auprobe->branch.ilen = insn->length;
 	auprobe->branch.offs = insn->immediate.value;
--- linux-ein-5.4.0.orig/arch/x86/kernel/vmlinux.lds.S
+++ linux-ein-5.4.0/arch/x86/kernel/vmlinux.lds.S
@@ -21,6 +21,8 @@
 #define LOAD_OFFSET __START_KERNEL_map
 #endif
 
+#define RUNTIME_DISCARD_EXIT
+
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
@@ -36,13 +38,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)
 /*
  * On 64-bit, align RODATA to 2MB so we retain large page mappings for
@@ -362,6 +364,7 @@
 	.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
 		__bss_start = .;
 		*(.bss..page_aligned)
+		. = ALIGN(PAGE_SIZE);
 		*(BSS_MAIN)
 		BSS_DECRYPTED
 		. = ALIGN(PAGE_SIZE);
@@ -380,7 +383,7 @@
 	.brk : AT(ADDR(.brk) - LOAD_OFFSET) {
 		__brk_base = .;
 		. += 64 * 1024;		/* 64k alignment slop space */
-		*(.brk_reservation)	/* areas brk users have reserved */
+		*(.bss..brk)		/* areas brk users have reserved */
 		__brk_limit = .;
 	}
 
--- linux-ein-5.4.0.orig/arch/x86/kernel/x86_init.c
+++ linux-ein-5.4.0/arch/x86/kernel/x86_init.c
@@ -58,6 +58,7 @@
 		.pre_vector_init	= init_ISA_irqs,
 		.intr_init		= native_init_IRQ,
 		.trap_init		= x86_init_noop,
+		.intr_mode_select	= apic_intr_mode_select,
 		.intr_mode_init		= apic_intr_mode_init
 	},
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/cpuid.c
+++ linux-ein-5.4.0/arch/x86/kvm/cpuid.c
@@ -352,6 +352,7 @@
 	unsigned f_umip = kvm_x86_ops->umip_emulated() ? F(UMIP) : 0;
 	unsigned f_intel_pt = kvm_x86_ops->pt_supported() ? F(INTEL_PT) : 0;
 	unsigned f_la57;
+	unsigned f_pku = kvm_x86_ops->pku_supported() ? F(PKU) : 0;
 
 	/* cpuid 7.0.ebx */
 	const u32 kvm_cpuid_7_0_ebx_x86_features =
@@ -363,7 +364,7 @@
 
 	/* cpuid 7.0.ecx*/
 	const u32 kvm_cpuid_7_0_ecx_x86_features =
-		F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
+		F(AVX512VBMI) | F(LA57) | 0 /*PKU*/ | 0 /*OSPKE*/ | F(RDPID) |
 		F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
 		F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
 		F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/;
@@ -392,6 +393,7 @@
 		/* Set LA57 based on hardware capability. */
 		entry->ecx |= f_la57;
 		entry->ecx |= f_umip;
+		entry->ecx |= f_pku;
 		/* PKU is not yet implemented for shadow paging. */
 		if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
 			entry->ecx &= ~F(PKU);
@@ -402,7 +404,8 @@
 			entry->edx |= F(SPEC_CTRL);
 		if (boot_cpu_has(X86_FEATURE_STIBP))
 			entry->edx |= F(INTEL_STIBP);
-		if (boot_cpu_has(X86_FEATURE_SSBD))
+		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
@@ -504,7 +507,7 @@
 
 	r = -E2BIG;
 
-	if (*nent >= maxnent)
+	if (WARN_ON(*nent >= maxnent))
 		goto out;
 
 	do_host_cpuid(entry, function, 0);
@@ -589,6 +592,11 @@
 		union cpuid10_eax eax;
 		union cpuid10_edx edx;
 
+		if (!static_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
+			entry->eax = entry->ebx = entry->ecx = entry->edx = 0;
+			break;
+		}
+
 		perf_get_x86_pmu_capability(&cap);
 
 		/*
@@ -742,9 +750,16 @@
 		unsigned virt_as = max((entry->eax >> 8) & 0xff, 48U);
 		unsigned phys_as = entry->eax & 0xff;
 
-		if (!g_phys_as)
+		/*
+		 * Use bare metal's MAXPHADDR if the CPU doesn't report guest
+		 * MAXPHYADDR separately, or if TDP (NPT) is disabled, as the
+		 * guest version "applies only to guests using nested paging".
+		 */
+		if (!g_phys_as || !tdp_enabled)
 			g_phys_as = phys_as;
+
 		entry->eax = g_phys_as | (virt_as << 8);
+		entry->ecx &= ~(GENMASK(31, 16) | GENMASK(11, 8));
 		entry->edx = 0;
 		entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;
 		cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX);
@@ -759,7 +774,8 @@
 			entry->ebx |= F(AMD_IBRS);
 		if (boot_cpu_has(X86_FEATURE_STIBP))
 			entry->ebx |= F(AMD_STIBP);
-		if (boot_cpu_has(X86_FEATURE_SSBD))
+		if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
+		    boot_cpu_has(X86_FEATURE_AMD_SSBD))
 			entry->ebx |= F(AMD_SSBD);
 		if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
 			entry->ebx |= F(AMD_SSB_NO);
@@ -776,6 +792,9 @@
 		entry->ecx = entry->edx = 0;
 		break;
 	case 0x8000001a:
+		entry->eax &= GENMASK(2, 0);
+		entry->ebx = entry->ecx = entry->edx = 0;
+		break;
 	case 0x8000001e:
 		break;
 	/*Add support for Centaur's CPUID instruction*/
@@ -810,6 +829,9 @@
 static int do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 func,
 			 int *nent, int maxnent, unsigned int type)
 {
+	if (*nent >= maxnent)
+		return -E2BIG;
+
 	if (type == KVM_GET_EMULATED_CPUID)
 		return __do_cpuid_func_emulated(entry, func, nent, maxnent);
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/cpuid.h
+++ linux-ein-5.4.0/arch/x86/kvm/cpuid.h
@@ -53,12 +53,15 @@
 	[CPUID_7_ECX]         = {         7, 0, CPUID_ECX},
 	[CPUID_8000_0007_EBX] = {0x80000007, 0, CPUID_EBX},
 	[CPUID_7_EDX]         = {         7, 0, CPUID_EDX},
+	[CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX},
 };
 
 static __always_inline struct cpuid_reg x86_feature_cpuid(unsigned x86_feature)
 {
 	unsigned x86_leaf = x86_feature / 32;
 
+	BUILD_BUG_ON(NR_CPUID_WORDS != NCAPINTS);
+	BUILD_BUG_ON(x86_leaf == CPUID_LNX_5);
 	BUILD_BUG_ON(x86_leaf >= ARRAY_SIZE(reverse_cpuid));
 	BUILD_BUG_ON(reverse_cpuid[x86_leaf].function == 0);
 
@@ -154,6 +157,20 @@
 	return x86_stepping(best->eax);
 }
 
+static inline bool guest_has_spec_ctrl_msr(struct kvm_vcpu *vcpu)
+{
+	return (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
+		guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) ||
+		guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) ||
+		guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD));
+}
+
+static inline bool guest_has_pred_cmd_msr(struct kvm_vcpu *vcpu)
+{
+	return (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
+		guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB));
+}
+
 static inline bool supports_cpuid_fault(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.msr_platform_info & MSR_PLATFORM_INFO_CPUID_FAULT;
--- linux-ein-5.4.0.orig/arch/x86/kvm/emulate.c
+++ linux-ein-5.4.0/arch/x86/kvm/emulate.c
@@ -22,6 +22,7 @@
 #include "kvm_cache_regs.h"
 #include <asm/kvm_emulate.h>
 #include <linux/stringify.h>
+#include <asm/fpu/api.h>
 #include <asm/debugreg.h>
 #include <asm/nospec-branch.h>
 
@@ -775,8 +776,7 @@
 			   ctxt->mode, linear);
 }
 
-static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst,
-			     enum x86emul_mode mode)
+static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
 {
 	ulong linear;
 	int rc;
@@ -786,41 +786,71 @@
 
 	if (ctxt->op_bytes != sizeof(unsigned long))
 		addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1);
-	rc = __linearize(ctxt, addr, &max_size, 1, false, true, mode, &linear);
+	rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear);
 	if (rc == X86EMUL_CONTINUE)
 		ctxt->_eip = addr.ea;
 	return rc;
 }
 
+static inline int emulator_recalc_and_set_mode(struct x86_emulate_ctxt *ctxt)
+{
+	u64 efer;
+	struct desc_struct cs;
+	u16 selector;
+	u32 base3;
+
+	ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+
+	if (!(ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE)) {
+		/* Real mode. cpu must not have long mode active */
+		if (efer & EFER_LMA)
+			return X86EMUL_UNHANDLEABLE;
+		ctxt->mode = X86EMUL_MODE_REAL;
+		return X86EMUL_CONTINUE;
+	}
+
+	if (ctxt->eflags & X86_EFLAGS_VM) {
+		/* Protected/VM86 mode. cpu must not have long mode active */
+		if (efer & EFER_LMA)
+			return X86EMUL_UNHANDLEABLE;
+		ctxt->mode = X86EMUL_MODE_VM86;
+		return X86EMUL_CONTINUE;
+	}
+
+	if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS))
+		return X86EMUL_UNHANDLEABLE;
+
+	if (efer & EFER_LMA) {
+		if (cs.l) {
+			/* Proper long mode */
+			ctxt->mode = X86EMUL_MODE_PROT64;
+		} else if (cs.d) {
+			/* 32 bit compatibility mode*/
+			ctxt->mode = X86EMUL_MODE_PROT32;
+		} else {
+			ctxt->mode = X86EMUL_MODE_PROT16;
+		}
+	} else {
+		/* Legacy 32 bit / 16 bit mode */
+		ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+	}
+
+	return X86EMUL_CONTINUE;
+}
+
 static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst)
 {
-	return assign_eip(ctxt, dst, ctxt->mode);
+	return assign_eip(ctxt, dst);
 }
 
-static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
-			  const struct desc_struct *cs_desc)
+static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst)
 {
-	enum x86emul_mode mode = ctxt->mode;
-	int rc;
+	int rc = emulator_recalc_and_set_mode(ctxt);
 
-#ifdef CONFIG_X86_64
-	if (ctxt->mode >= X86EMUL_MODE_PROT16) {
-		if (cs_desc->l) {
-			u64 efer = 0;
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
 
-			ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
-			if (efer & EFER_LMA)
-				mode = X86EMUL_MODE_PROT64;
-		} else
-			mode = X86EMUL_MODE_PROT32; /* temporary value */
-	}
-#endif
-	if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32)
-		mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
-	rc = assign_eip(ctxt, dst, mode);
-	if (rc == X86EMUL_CONTINUE)
-		ctxt->mode = mode;
-	return rc;
+	return assign_eip(ctxt, dst);
 }
 
 static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
@@ -1075,8 +1105,23 @@
 	}
 }
 
+static void emulator_get_fpu(void)
+{
+	fpregs_lock();
+
+	fpregs_assert_state_consistent();
+	if (test_thread_flag(TIF_NEED_FPU_LOAD))
+		switch_fpu_return();
+}
+
+static void emulator_put_fpu(void)
+{
+	fpregs_unlock();
+}
+
 static void read_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg)
 {
+	emulator_get_fpu();
 	switch (reg) {
 	case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
 	case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
@@ -1098,11 +1143,13 @@
 #endif
 	default: BUG();
 	}
+	emulator_put_fpu();
 }
 
 static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
 			  int reg)
 {
+	emulator_get_fpu();
 	switch (reg) {
 	case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
 	case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
@@ -1124,10 +1171,12 @@
 #endif
 	default: BUG();
 	}
+	emulator_put_fpu();
 }
 
 static void read_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
 {
+	emulator_get_fpu();
 	switch (reg) {
 	case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
 	case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
@@ -1139,10 +1188,12 @@
 	case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
 	default: BUG();
 	}
+	emulator_put_fpu();
 }
 
 static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
 {
+	emulator_get_fpu();
 	switch (reg) {
 	case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
 	case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
@@ -1154,6 +1205,7 @@
 	case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
 	default: BUG();
 	}
+	emulator_put_fpu();
 }
 
 static int em_fninit(struct x86_emulate_ctxt *ctxt)
@@ -1161,7 +1213,9 @@
 	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
 		return emulate_nm(ctxt);
 
+	emulator_get_fpu();
 	asm volatile("fninit");
+	emulator_put_fpu();
 	return X86EMUL_CONTINUE;
 }
 
@@ -1172,7 +1226,9 @@
 	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
 		return emulate_nm(ctxt);
 
+	emulator_get_fpu();
 	asm volatile("fnstcw %0": "+m"(fcw));
+	emulator_put_fpu();
 
 	ctxt->dst.val = fcw;
 
@@ -1186,7 +1242,9 @@
 	if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
 		return emulate_nm(ctxt);
 
+	emulator_get_fpu();
 	asm volatile("fnstsw %0": "+m"(fsw));
+	emulator_put_fpu();
 
 	ctxt->dst.val = fsw;
 
@@ -1685,11 +1743,6 @@
 		goto exception;
 	}
 
-	if (!seg_desc.p) {
-		err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
-		goto exception;
-	}
-
 	dpl = seg_desc.dpl;
 
 	switch (seg) {
@@ -1729,12 +1782,6 @@
 	case VCPU_SREG_TR:
 		if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
 			goto exception;
-		old_desc = seg_desc;
-		seg_desc.type |= 2; /* busy */
-		ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc,
-						  sizeof(seg_desc), &ctxt->exception);
-		if (ret != X86EMUL_CONTINUE)
-			return ret;
 		break;
 	case VCPU_SREG_LDTR:
 		if (seg_desc.s || seg_desc.type != 2)
@@ -1753,6 +1800,11 @@
 		break;
 	}
 
+	if (!seg_desc.p) {
+		err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
+		goto exception;
+	}
+
 	if (seg_desc.s) {
 		/* mark segment as accessed */
 		if (!(seg_desc.type & 1)) {
@@ -1767,8 +1819,17 @@
 		if (ret != X86EMUL_CONTINUE)
 			return ret;
 		if (emul_is_noncanonical_address(get_desc_base(&seg_desc) |
-				((u64)base3 << 32), ctxt))
-			return emulate_gp(ctxt, 0);
+						 ((u64)base3 << 32), ctxt))
+			return emulate_gp(ctxt, err_code);
+	}
+
+	if (seg == VCPU_SREG_TR) {
+		old_desc = seg_desc;
+		seg_desc.type |= 2; /* busy */
+		ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc,
+						  sizeof(seg_desc), &ctxt->exception);
+		if (ret != X86EMUL_CONTINUE)
+			return ret;
 	}
 load:
 	ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg);
@@ -1988,7 +2049,7 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	if (ctxt->modrm_reg == VCPU_SREG_SS)
+	if (seg == VCPU_SREG_SS)
 		ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS;
 	if (ctxt->op_bytes > 2)
 		rsp_increment(ctxt, ctxt->op_bytes - 2);
@@ -2205,7 +2266,7 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
+	rc = assign_eip_far(ctxt, ctxt->src.val);
 	/* Error handling is not implemented. */
 	if (rc != X86EMUL_CONTINUE)
 		return X86EMUL_UNHANDLEABLE;
@@ -2286,7 +2347,7 @@
 				       &new_desc);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
-	rc = assign_eip_far(ctxt, eip, &new_desc);
+	rc = assign_eip_far(ctxt, eip);
 	/* Error handling is not implemented. */
 	if (rc != X86EMUL_CONTINUE)
 		return X86EMUL_UNHANDLEABLE;
@@ -2861,6 +2922,8 @@
 	ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
 	*reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
 							      (u32)msr_data;
+	if (efer & EFER_LMA)
+		ctxt->mode = X86EMUL_MODE_PROT64;
 
 	return X86EMUL_CONTINUE;
 }
@@ -2919,6 +2982,7 @@
 	ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
 
 	ctxt->_eip = rdx;
+	ctxt->mode = usermode;
 	*reg_write(ctxt, VCPU_REGS_RSP) = rcx;
 
 	return X86EMUL_CONTINUE;
@@ -3515,7 +3579,7 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
+	rc = assign_eip_far(ctxt, ctxt->src.val);
 	if (rc != X86EMUL_CONTINUE)
 		goto fail;
 
@@ -3588,7 +3652,7 @@
 	u64 tsc_aux = 0;
 
 	if (ctxt->ops->get_msr(ctxt, MSR_TSC_AUX, &tsc_aux))
-		return emulate_gp(ctxt, 0);
+		return emulate_ud(ctxt);
 	ctxt->dst.val = tsc_aux;
 	return X86EMUL_CONTINUE;
 }
@@ -3662,11 +3726,25 @@
 
 static int em_cr_write(struct x86_emulate_ctxt *ctxt)
 {
-	if (ctxt->ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val))
+	int cr_num = ctxt->modrm_reg;
+	int r;
+
+	if (ctxt->ops->set_cr(ctxt, cr_num, ctxt->src.val))
 		return emulate_gp(ctxt, 0);
 
 	/* Disable writeback. */
 	ctxt->dst.type = OP_NONE;
+
+	if (cr_num == 0) {
+		/*
+		 * CR0 write might have updated CR0.PE and/or CR0.PG
+		 * which can affect the cpu's execution mode.
+		 */
+		r = emulator_recalc_and_set_mode(ctxt);
+		if (r != X86EMUL_CONTINUE)
+			return r;
+	}
+
 	return X86EMUL_CONTINUE;
 }
 
@@ -4021,6 +4099,12 @@
 	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;
@@ -4094,8 +4178,12 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
+	emulator_get_fpu();
+
 	rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
 
+	emulator_put_fpu();
+
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
@@ -4138,6 +4226,8 @@
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
+	emulator_get_fpu();
+
 	if (size < __fxstate_size(16)) {
 		rc = fxregs_fixup(&fx_state, size);
 		if (rc != X86EMUL_CONTINUE)
@@ -4153,6 +4243,8 @@
 		rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state));
 
 out:
+	emulator_put_fpu();
+
 	return rc;
 }
 
@@ -4555,7 +4647,7 @@
 };
 
 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 = { {
@@ -5160,6 +5252,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 {
@@ -5212,16 +5305,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)
@@ -5305,10 +5410,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)
@@ -5450,7 +5560,9 @@
 {
 	int rc;
 
+	emulator_get_fpu();
 	rc = asm_safe("fwait");
+	emulator_put_fpu();
 
 	if (unlikely(rc != X86EMUL_CONTINUE))
 		return emulate_exception(ctxt, MF_VECTOR, 0, false);
@@ -5779,6 +5891,8 @@
 	}
 
 	ctxt->eip = ctxt->_eip;
+	if (ctxt->mode != X86EMUL_MODE_PROT64)
+		ctxt->eip = (u32)ctxt->_eip;
 
 done:
 	if (rc == X86EMUL_PROPAGATE_FAULT) {
--- linux-ein-5.4.0.orig/arch/x86/kvm/hyperv.c
+++ linux-ein-5.4.0/arch/x86/kvm/hyperv.c
@@ -205,7 +205,7 @@
 	struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
 	int ret;
 
-	if (!synic->active && !host)
+	if (!synic->active && (!host || data))
 		return 1;
 
 	trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host);
@@ -251,6 +251,9 @@
 	case HV_X64_MSR_EOM: {
 		int i;
 
+		if (!synic->active)
+			break;
+
 		for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
 			kvm_hv_notify_acked_sint(vcpu, i);
 		break;
@@ -306,6 +309,9 @@
 	struct kvm_lapic_irq irq;
 	int ret, vector;
 
+	if (KVM_BUG_ON(!lapic_in_kernel(vcpu), vcpu->kvm))
+		return -EINVAL;
+
 	if (sint >= ARRAY_SIZE(synic->sint))
 		return -EINVAL;
 
@@ -514,6 +520,11 @@
 {
 	union hv_stimer_config new_config = {.as_uint64 = config},
 		old_config = {.as_uint64 = stimer->config.as_uint64};
+	struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+	struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+
+	if (!synic->active && (!host || config))
+		return 1;
 
 	trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id,
 				       stimer->index, config, host);
@@ -533,15 +544,23 @@
 static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count,
 			    bool host)
 {
+	struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+	struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+
+	if (!synic->active && (!host || count))
+		return 1;
+
 	trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id,
 				      stimer->index, count, host);
 
 	stimer_cleanup(stimer);
 	stimer->count = count;
-	if (stimer->count == 0)
-		stimer->config.enable = 0;
-	else if (stimer->config.auto_enable)
-		stimer->config.enable = 1;
+	if (!host) {
+		if (stimer->count == 0)
+			stimer->config.enable = 0;
+		else if (stimer->config.auto_enable)
+			stimer->config.enable = 1;
+	}
 
 	if (stimer->config.enable)
 		stimer_mark_pending(stimer, false);
@@ -809,11 +828,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;
 }
 
@@ -852,11 +872,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;
 }
 
@@ -1499,11 +1520,13 @@
 
 		all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL;
 
+		if (all_cpus)
+			goto check_and_send_ipi;
+
 		if (!sparse_banks_len)
 			goto ret_success;
 
-		if (!all_cpus &&
-		    kvm_read_guest(kvm,
+		if (kvm_read_guest(kvm,
 				   ingpa + offsetof(struct hv_send_ipi_ex,
 						    vp_set.bank_contents),
 				   sparse_banks,
@@ -1511,6 +1534,7 @@
 			return HV_STATUS_INVALID_HYPERCALL_INPUT;
 	}
 
+check_and_send_ipi:
 	if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
 		return HV_STATUS_INVALID_HYPERCALL_INPUT;
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/i8259.c
+++ linux-ein-5.4.0/arch/x86/kvm/i8259.c
@@ -460,10 +460,14 @@
 	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_lock(s);
-		pic_ioport_write(&s->pics[addr >> 7], addr, data);
+		pic_ioport_write(&s->pics[1], addr, data);
 		pic_unlock(s);
 		break;
 	case 0x4d0:
--- linux-ein-5.4.0.orig/arch/x86/kvm/ioapic.c
+++ linux-ein-5.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>
@@ -68,13 +69,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 :
@@ -291,6 +293,7 @@
 
 		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 */
--- linux-ein-5.4.0.orig/arch/x86/kvm/irq.c
+++ linux-ein-5.4.0/arch/x86/kvm/irq.c
@@ -40,29 +40,10 @@
  * check if there is pending interrupt from
  * non-APIC source without intack.
  */
-static int kvm_cpu_has_extint(struct kvm_vcpu *v)
-{
-	u8 accept = kvm_apic_accept_pic_intr(v);
-
-	if (accept) {
-		if (irqchip_split(v->kvm))
-			return pending_userspace_extint(v);
-		else
-			return v->kvm->arch.vpic->output;
-	} else
-		return 0;
-}
-
-/*
- * check if there is injectable interrupt:
- * when virtual interrupt delivery enabled,
- * interrupt from apic will handled by hardware,
- * we don't need to check it here.
- */
-int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
+int kvm_cpu_has_extint(struct kvm_vcpu *v)
 {
 	/*
-	 * FIXME: interrupt.injected represents an interrupt that it's
+	 * FIXME: interrupt.injected represents an interrupt whose
 	 * side-effects have already been applied (e.g. bit from IRR
 	 * already moved to ISR). Therefore, it is incorrect to rely
 	 * on interrupt.injected to know if there is a pending
@@ -75,6 +56,23 @@
 	if (!lapic_in_kernel(v))
 		return v->arch.interrupt.injected;
 
+	if (!kvm_apic_accept_pic_intr(v))
+		return 0;
+
+	if (irqchip_split(v->kvm))
+		return pending_userspace_extint(v);
+	else
+		return v->kvm->arch.vpic->output;
+}
+
+/*
+ * check if there is injectable interrupt:
+ * when virtual interrupt delivery enabled,
+ * interrupt from apic will handled by hardware,
+ * we don't need to check it here.
+ */
+int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
+{
 	if (kvm_cpu_has_extint(v))
 		return 1;
 
@@ -90,20 +88,6 @@
  */
 int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
 {
-	/*
-	 * FIXME: interrupt.injected represents an interrupt that it's
-	 * side-effects have already been applied (e.g. bit from IRR
-	 * already moved to ISR). Therefore, it is incorrect to rely
-	 * on interrupt.injected to know if there is a pending
-	 * interrupt in the user-mode LAPIC.
-	 * This leads to nVMX/nSVM not be able to distinguish
-	 * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on
-	 * pending interrupt or should re-inject an injected
-	 * interrupt.
-	 */
-	if (!lapic_in_kernel(v))
-		return v->arch.interrupt.injected;
-
 	if (kvm_cpu_has_extint(v))
 		return 1;
 
@@ -117,16 +101,21 @@
  */
 static int kvm_cpu_get_extint(struct kvm_vcpu *v)
 {
-	if (kvm_cpu_has_extint(v)) {
-		if (irqchip_split(v->kvm)) {
-			int vector = v->arch.pending_external_vector;
-
-			v->arch.pending_external_vector = -1;
-			return vector;
-		} else
-			return kvm_pic_read_irq(v->kvm); /* PIC */
-	} else
+	if (!kvm_cpu_has_extint(v)) {
+		WARN_ON(!lapic_in_kernel(v));
 		return -1;
+	}
+
+	if (!lapic_in_kernel(v))
+		return v->arch.interrupt.nr;
+
+	if (irqchip_split(v->kvm)) {
+		int vector = v->arch.pending_external_vector;
+
+		v->arch.pending_external_vector = -1;
+		return vector;
+	} else
+		return kvm_pic_read_irq(v->kvm); /* PIC */
 }
 
 /*
@@ -134,13 +123,7 @@
  */
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
 {
-	int vector;
-
-	if (!lapic_in_kernel(v))
-		return v->arch.interrupt.nr;
-
-	vector = kvm_cpu_get_extint(v);
-
+	int vector = kvm_cpu_get_extint(v);
 	if (vector != -1)
 		return vector;			/* PIC */
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/irq_comm.c
+++ linux-ein-5.4.0/arch/x86/kvm/irq_comm.c
@@ -416,7 +416,7 @@
 
 			kvm_set_msi_irq(vcpu->kvm, entry, &irq);
 
-			if (irq.level && kvm_apic_match_dest(vcpu, NULL, 0,
+			if (irq.trig_mode && kvm_apic_match_dest(vcpu, NULL, 0,
 						irq.dest_id, irq.dest_mode))
 				__set_bit(irq.vector, ioapic_handled_vectors);
 		}
--- linux-ein-5.4.0.orig/arch/x86/kvm/kvm_cache_regs.h
+++ linux-ein-5.4.0/arch/x86/kvm/kvm_cache_regs.h
@@ -7,7 +7,7 @@
 #define KVM_POSSIBLE_CR0_GUEST_BITS X86_CR0_TS
 #define KVM_POSSIBLE_CR4_GUEST_BITS				  \
 	(X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR  \
-	 | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_PGE)
+	 | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_PGE | X86_CR4_TSD)
 
 #define BUILD_KVM_GPR_ACCESSORS(lname, uname)				      \
 static __always_inline unsigned long kvm_##lname##_read(struct kvm_vcpu *vcpu)\
--- linux-ein-5.4.0.orig/arch/x86/kvm/lapic.c
+++ linux-ein-5.4.0/arch/x86/kvm/lapic.c
@@ -118,7 +118,8 @@
 
 bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu)
 {
-	return pi_inject_timer && kvm_vcpu_apicv_active(vcpu);
+	return pi_inject_timer && kvm_vcpu_apicv_active(vcpu) &&
+		(kvm_mwait_in_guest(vcpu->kvm) || kvm_hlt_in_guest(vcpu->kvm));
 }
 EXPORT_SYMBOL_GPL(kvm_can_post_timer_interrupt);
 
@@ -637,9 +638,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) {
 		printk(KERN_WARNING "Can't read EOI MSR value: 0x%llx\n",
 			   (unsigned long long)vcpu->arch.pv_eoi.msr_val);
+		return false;
+	}
 	return val & 0x1;
 }
 
@@ -952,6 +955,10 @@
 	*r = -1;
 
 	if (irq->shorthand == APIC_DEST_SELF) {
+		if (KVM_BUG_ON(!src, kvm)) {
+			*r = 0;
+			return true;
+		}
 		*r = kvm_apic_set_irq(src->vcpu, irq, dest_map);
 		return true;
 	}
@@ -1056,11 +1063,8 @@
 						       apic->regs + APIC_TMR);
 		}
 
-		if (vcpu->arch.apicv_active)
-			kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
-		else {
+		if (kvm_x86_ops->deliver_posted_interrupt(vcpu, vector)) {
 			kvm_lapic_set_irr(vector, apic);
-
 			kvm_make_request(KVM_REQ_EVENT, vcpu);
 			kvm_vcpu_kick(vcpu);
 		}
@@ -1333,6 +1337,9 @@
 	if (!apic_x2apic_mode(apic))
 		valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI);
 
+	if (alignment + len > 4)
+		return 1;
+
 	if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset)))
 		return 1;
 
@@ -1685,7 +1692,7 @@
 
 	hrtimer_start(&apic->lapic_timer.timer,
 		apic->lapic_timer.target_expiration,
-		HRTIMER_MODE_ABS);
+		HRTIMER_MODE_ABS_HARD);
 }
 
 bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
@@ -1926,15 +1933,20 @@
 	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];
 		kvm_lapic_set_reg(apic, reg, val);
-
 		break;
+	}
 
 	case APIC_LVTT:
 		if (!kvm_apic_sw_enabled(apic))
@@ -2081,7 +2093,7 @@
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
 
-	if (!lapic_in_kernel(vcpu) || apic_lvtt_oneshot(apic) ||
+	if (!kvm_apic_present(vcpu) || apic_lvtt_oneshot(apic) ||
 			apic_lvtt_period(apic))
 		return;
 
@@ -2092,10 +2104,7 @@
 
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-	struct kvm_lapic *apic = vcpu->arch.apic;
-
-	apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
-		     | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4));
+	apic_set_tpr(vcpu->arch.apic, (cr8 & 0x0f) << 4);
 }
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
@@ -2235,13 +2244,17 @@
 {
 	u32 reg = kvm_lapic_get_reg(apic, lvt_type);
 	int vector, mode, trig_mode;
+	int r;
 
 	if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
 		vector = reg & APIC_VECTOR_MASK;
 		mode = reg & APIC_MODE_MASK;
 		trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
-		return __apic_accept_irq(apic, mode, vector, 1, trig_mode,
-					NULL);
+
+		r = __apic_accept_irq(apic, mode, vector, 1, trig_mode, NULL);
+		if (r && lvt_type == APIC_LVTPC)
+			kvm_lapic_set_reg(apic, APIC_LVTPC, reg | APIC_LVT_MASKED);
+		return r;
 	}
 	return 0;
 }
@@ -2326,7 +2339,7 @@
 	struct kvm_lapic *apic = vcpu->arch.apic;
 	u32 ppr;
 
-	if (!kvm_apic_hw_enabled(apic))
+	if (!kvm_apic_present(vcpu))
 		return -1;
 
 	__apic_update_ppr(apic, &ppr);
--- linux-ein-5.4.0.orig/arch/x86/kvm/mmu.c
+++ linux-ein-5.4.0/arch/x86/kvm/mmu.c
@@ -343,6 +343,8 @@
 {
 	BUG_ON((u64)(unsigned)access_mask != access_mask);
 	BUG_ON((mmio_mask & mmio_value) != mmio_value);
+	WARN_ON(mmio_value & (shadow_nonpresent_or_rsvd_mask << shadow_nonpresent_or_rsvd_mask_len));
+	WARN_ON(mmio_value & shadow_nonpresent_or_rsvd_lower_gfn_mask);
 	shadow_mmio_value = mmio_value | SPTE_MMIO_MASK;
 	shadow_mmio_mask = mmio_mask | SPTE_SPECIAL_MASK;
 	shadow_mmio_access_mask = access_mask;
@@ -405,11 +407,11 @@
 }
 
 /*
- * Due to limited space in PTEs, the MMIO generation is a 19 bit subset of
+ * Due to limited space in PTEs, the MMIO generation is a 18 bit subset of
  * the memslots generation and is derived as follows:
  *
  * Bits 0-8 of the MMIO generation are propagated to spte bits 3-11
- * Bits 9-18 of the MMIO generation are propagated to spte bits 52-61
+ * Bits 9-17 of the MMIO generation are propagated to spte bits 54-62
  *
  * The KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS flag is intentionally not included in
  * the MMIO generation number, as doing so would require stealing a bit from
@@ -418,25 +420,38 @@
  * requires a full MMU zap).  The flag is instead explicitly queried when
  * checking for MMIO spte cache hits.
  */
-#define MMIO_SPTE_GEN_MASK		GENMASK_ULL(18, 0)
 
 #define MMIO_SPTE_GEN_LOW_START		3
 #define MMIO_SPTE_GEN_LOW_END		11
+
+#define MMIO_SPTE_GEN_HIGH_START	PT64_SECOND_AVAIL_BITS_SHIFT
+#define MMIO_SPTE_GEN_HIGH_END		62
+
 #define MMIO_SPTE_GEN_LOW_MASK		GENMASK_ULL(MMIO_SPTE_GEN_LOW_END, \
 						    MMIO_SPTE_GEN_LOW_START)
-
-#define MMIO_SPTE_GEN_HIGH_START	52
-#define MMIO_SPTE_GEN_HIGH_END		61
 #define MMIO_SPTE_GEN_HIGH_MASK		GENMASK_ULL(MMIO_SPTE_GEN_HIGH_END, \
 						    MMIO_SPTE_GEN_HIGH_START)
+
+#define MMIO_SPTE_GEN_LOW_BITS		(MMIO_SPTE_GEN_LOW_END - MMIO_SPTE_GEN_LOW_START + 1)
+#define MMIO_SPTE_GEN_HIGH_BITS		(MMIO_SPTE_GEN_HIGH_END - MMIO_SPTE_GEN_HIGH_START + 1)
+
+/* remember to adjust the comment above as well if you change these */
+static_assert(MMIO_SPTE_GEN_LOW_BITS == 9 && MMIO_SPTE_GEN_HIGH_BITS == 9);
+
+#define MMIO_SPTE_GEN_LOW_SHIFT		(MMIO_SPTE_GEN_LOW_START - 0)
+#define MMIO_SPTE_GEN_HIGH_SHIFT	(MMIO_SPTE_GEN_HIGH_START - MMIO_SPTE_GEN_LOW_BITS)
+
+#define MMIO_SPTE_GEN_MASK		GENMASK_ULL(MMIO_SPTE_GEN_LOW_BITS + MMIO_SPTE_GEN_HIGH_BITS - 1, 0)
+
 static u64 generation_mmio_spte_mask(u64 gen)
 {
 	u64 mask;
 
 	WARN_ON(gen & ~MMIO_SPTE_GEN_MASK);
+	BUILD_BUG_ON((MMIO_SPTE_GEN_HIGH_MASK | MMIO_SPTE_GEN_LOW_MASK) & SPTE_SPECIAL_MASK);
 
-	mask = (gen << MMIO_SPTE_GEN_LOW_START) & MMIO_SPTE_GEN_LOW_MASK;
-	mask |= (gen << MMIO_SPTE_GEN_HIGH_START) & MMIO_SPTE_GEN_HIGH_MASK;
+	mask = (gen << MMIO_SPTE_GEN_LOW_SHIFT) & MMIO_SPTE_GEN_LOW_MASK;
+	mask |= (gen << MMIO_SPTE_GEN_HIGH_SHIFT) & MMIO_SPTE_GEN_HIGH_MASK;
 	return mask;
 }
 
@@ -444,10 +459,8 @@
 {
 	u64 gen;
 
-	spte &= ~shadow_mmio_mask;
-
-	gen = (spte & MMIO_SPTE_GEN_LOW_MASK) >> MMIO_SPTE_GEN_LOW_START;
-	gen |= (spte & MMIO_SPTE_GEN_HIGH_MASK) >> MMIO_SPTE_GEN_HIGH_START;
+	gen = (spte & MMIO_SPTE_GEN_LOW_MASK) >> MMIO_SPTE_GEN_LOW_SHIFT;
+	gen |= (spte & MMIO_SPTE_GEN_HIGH_MASK) >> MMIO_SPTE_GEN_HIGH_SHIFT;
 	return gen;
 }
 
@@ -538,16 +551,20 @@
 static u8 kvm_get_shadow_phys_bits(void)
 {
 	/*
-	 * boot_cpu_data.x86_phys_bits is reduced when MKTME is detected
-	 * in CPU detection code, but MKTME treats those reduced bits as
-	 * 'keyID' thus they are not reserved bits. Therefore for MKTME
-	 * we should still return physical address bits reported by CPUID.
-	 */
-	if (!boot_cpu_has(X86_FEATURE_TME) ||
-	    WARN_ON_ONCE(boot_cpu_data.extended_cpuid_level < 0x80000008))
-		return boot_cpu_data.x86_phys_bits;
+	 * boot_cpu_data.x86_phys_bits is reduced when MKTME or SME are detected
+	 * in CPU detection code, but the processor treats those reduced bits as
+	 * 'keyID' thus they are not reserved bits. Therefore KVM needs to look at
+	 * the physical address bits reported by CPUID.
+	 */
+	if (likely(boot_cpu_data.extended_cpuid_level >= 0x80000008))
+		return cpuid_eax(0x80000008) & 0xff;
 
-	return cpuid_eax(0x80000008) & 0xff;
+	/*
+	 * Quite weird to have VMX or SVM but not MAXPHYADDR; probably a VM with
+	 * custom CPUID.  Proceed with whatever the kernel found since these features
+	 * aren't virtualizable (SME/SEV also require CPUIDs higher than 0x80000008).
+	 */
+	return boot_cpu_data.x86_phys_bits;
 }
 
 static void kvm_mmu_reset_all_pte_masks(void)
@@ -576,16 +593,15 @@
 	 * the most significant bits of legal physical address space.
 	 */
 	shadow_nonpresent_or_rsvd_mask = 0;
-	low_phys_bits = boot_cpu_data.x86_cache_bits;
-	if (boot_cpu_data.x86_cache_bits <
-	    52 - shadow_nonpresent_or_rsvd_mask_len) {
+	low_phys_bits = boot_cpu_data.x86_phys_bits;
+	if (boot_cpu_has_bug(X86_BUG_L1TF) &&
+	    !WARN_ON_ONCE(boot_cpu_data.x86_cache_bits >=
+			  52 - shadow_nonpresent_or_rsvd_mask_len)) {
+		low_phys_bits = boot_cpu_data.x86_cache_bits
+			- shadow_nonpresent_or_rsvd_mask_len;
 		shadow_nonpresent_or_rsvd_mask =
-			rsvd_bits(boot_cpu_data.x86_cache_bits -
-				  shadow_nonpresent_or_rsvd_mask_len,
-				  boot_cpu_data.x86_cache_bits - 1);
-		low_phys_bits -= shadow_nonpresent_or_rsvd_mask_len;
-	} else
-		WARN_ON_ONCE(boot_cpu_has_bug(X86_BUG_L1TF));
+			rsvd_bits(low_phys_bits, boot_cpu_data.x86_cache_bits - 1);
+	}
 
 	shadow_nonpresent_or_rsvd_lower_gfn_mask =
 		GENMASK_ULL(low_phys_bits - 1, PAGE_SHIFT);
@@ -1282,12 +1298,12 @@
 	return __mmu_gfn_lpage_is_disallowed(gfn, level, slot);
 }
 
-static int host_mapping_level(struct kvm *kvm, gfn_t gfn)
+static int host_mapping_level(struct kvm_vcpu *vcpu, gfn_t gfn)
 {
 	unsigned long page_size;
 	int i, ret = 0;
 
-	page_size = kvm_host_page_size(kvm, gfn);
+	page_size = kvm_host_page_size(vcpu, gfn);
 
 	for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
 		if (page_size >= KVM_HPAGE_SIZE(i))
@@ -1337,7 +1353,7 @@
 	if (unlikely(*force_pt_level))
 		return PT_PAGE_TABLE_LEVEL;
 
-	host_level = host_mapping_level(vcpu->kvm, large_gfn);
+	host_level = host_mapping_level(vcpu, large_gfn);
 
 	if (host_level == PT_PAGE_TABLE_LEVEL)
 		return host_level;
@@ -1814,10 +1830,10 @@
  * Emulate arch specific page modification logging for the
  * nested hypervisor
  */
-int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu)
+int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu, gpa_t l2_gpa)
 {
 	if (kvm_x86_ops->write_log_dirty)
-		return kvm_x86_ops->write_log_dirty(vcpu);
+		return kvm_x86_ops->write_log_dirty(vcpu, l2_gpa);
 
 	return 0;
 }
@@ -2040,7 +2056,8 @@
 	return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler);
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+			unsigned flags)
 {
 	return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp);
 }
@@ -2126,7 +2143,7 @@
  * aggregate version in order to make the slab shrinker
  * faster
  */
-static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, unsigned long nr)
+static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, long nr)
 {
 	kvm->arch.n_used_mmu_pages += nr;
 	percpu_counter_add(&kvm_total_used_mmu_pages, nr);
@@ -2226,13 +2243,6 @@
 {
 }
 
-static void nonpaging_update_pte(struct kvm_vcpu *vcpu,
-				 struct kvm_mmu_page *sp, u64 *spte,
-				 const void *pte)
-{
-	WARN_ON(1);
-}
-
 #define KVM_PAGE_ARRAY_NR 16
 
 struct kvm_mmu_pages {
@@ -3528,7 +3538,7 @@
  * - true: let the vcpu to access on the same address again.
  * - false: let the real page fault path to fix it.
  */
-static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level,
+static bool fast_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int level,
 			    u32 error_code)
 {
 	struct kvm_shadow_walk_iterator iterator;
@@ -3548,7 +3558,7 @@
 	do {
 		u64 new_spte;
 
-		for_each_shadow_entry_lockless(vcpu, gva, iterator, spte)
+		for_each_shadow_entry_lockless(vcpu, cr2_or_gpa, iterator, spte)
 			if (!is_shadow_present_pte(spte) ||
 			    iterator.level < level)
 				break;
@@ -3626,7 +3636,7 @@
 
 	} while (true);
 
-	trace_fast_page_fault(vcpu, gva, error_code, iterator.sptep,
+	trace_fast_page_fault(vcpu, cr2_or_gpa, error_code, iterator.sptep,
 			      spte, fault_handled);
 	walk_shadow_page_lockless_end(vcpu);
 
@@ -3634,10 +3644,11 @@
 }
 
 static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
-			 gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable);
+			 gpa_t cr2_or_gpa, kvm_pfn_t *pfn, bool write,
+			 bool *writable);
 static int make_mmu_pages_available(struct kvm_vcpu *vcpu);
 
-static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
+static int nonpaging_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
 			 gfn_t gfn, bool prefault)
 {
 	int r;
@@ -3663,16 +3674,16 @@
 		gfn &= ~(KVM_PAGES_PER_HPAGE(level) - 1);
 	}
 
-	if (fast_page_fault(vcpu, v, level, error_code))
+	if (fast_page_fault(vcpu, gpa, level, error_code))
 		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))
+	if (try_async_pf(vcpu, prefault, gfn, gpa, &pfn, write, &map_writable))
 		return RET_PF_RETRY;
 
-	if (handle_abnormal_pfn(vcpu, v, gfn, pfn, ACC_ALL, &r))
+	if (handle_abnormal_pfn(vcpu, gpa, gfn, pfn, ACC_ALL, &r))
 		return r;
 
 	r = RET_PF_RETRY;
@@ -3683,7 +3694,7 @@
 		goto out_unlock;
 	if (likely(!force_pt_level))
 		transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
-	r = __direct_map(vcpu, v, write, map_writable, level, pfn,
+	r = __direct_map(vcpu, gpa, write, map_writable, level, pfn,
 			 prefault, false);
 out_unlock:
 	spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3981,7 +3992,7 @@
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_sync_roots);
 
-static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr,
+static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gpa_t vaddr,
 				  u32 access, struct x86_exception *exception)
 {
 	if (exception)
@@ -3989,7 +4000,7 @@
 	return vaddr;
 }
 
-static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr,
+static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gpa_t vaddr,
 					 u32 access,
 					 struct x86_exception *exception)
 {
@@ -4149,13 +4160,14 @@
 	walk_shadow_page_lockless_end(vcpu);
 }
 
-static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
+static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa,
 				u32 error_code, bool prefault)
 {
-	gfn_t gfn = gva >> PAGE_SHIFT;
+	gfn_t gfn = gpa >> PAGE_SHIFT;
 	int r;
 
-	pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
+	/* Note, paging is disabled, ergo gva == gpa. */
+	pgprintk("%s: gva %lx error %x\n", __func__, gpa, error_code);
 
 	if (page_fault_handle_page_track(vcpu, error_code, gfn))
 		return RET_PF_EMULATE;
@@ -4167,11 +4179,12 @@
 	MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa));
 
 
-	return nonpaging_map(vcpu, gva & PAGE_MASK,
+	return nonpaging_map(vcpu, gpa & PAGE_MASK,
 			     error_code, gfn, prefault);
 }
 
-static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
+static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
+				   gfn_t gfn)
 {
 	struct kvm_arch_async_pf arch;
 
@@ -4180,11 +4193,13 @@
 	arch.direct_map = vcpu->arch.mmu->direct_map;
 	arch.cr3 = vcpu->arch.mmu->get_cr3(vcpu);
 
-	return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
+	return kvm_setup_async_pf(vcpu, cr2_or_gpa,
+				  kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
 }
 
 static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
-			 gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable)
+			 gpa_t cr2_or_gpa, kvm_pfn_t *pfn, bool write,
+			 bool *writable)
 {
 	struct kvm_memory_slot *slot;
 	bool async;
@@ -4204,12 +4219,12 @@
 		return false; /* *pfn has correct page already */
 
 	if (!prefault && kvm_can_do_async_pf(vcpu)) {
-		trace_kvm_try_async_get_page(gva, gfn);
+		trace_kvm_try_async_get_page(cr2_or_gpa, gfn);
 		if (kvm_find_async_pf_gfn(vcpu, gfn)) {
-			trace_kvm_async_pf_doublefault(gva, gfn);
+			trace_kvm_async_pf_doublefault(cr2_or_gpa, gfn);
 			kvm_make_request(KVM_REQ_APF_HALT, vcpu);
 			return true;
-		} else if (kvm_arch_setup_async_pf(vcpu, gva, gfn))
+		} else if (kvm_arch_setup_async_pf(vcpu, cr2_or_gpa, gfn))
 			return true;
 	}
 
@@ -4222,6 +4237,12 @@
 {
 	int r = 1;
 
+#ifndef CONFIG_X86_64
+	/* A 64-bit CR2 should be impossible on 32-bit KVM. */
+	if (WARN_ON_ONCE(fault_address >> 32))
+		return -EFAULT;
+#endif
+
 	vcpu->arch.l1tf_flush_l1d = true;
 	switch (vcpu->arch.apf.host_apf_reason) {
 	default:
@@ -4259,7 +4280,7 @@
 	return kvm_mtrr_check_gfn_range_consistency(vcpu, gfn, page_num);
 }
 
-static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
+static int tdp_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
 			  bool prefault)
 {
 	kvm_pfn_t pfn;
@@ -4328,7 +4349,6 @@
 	context->gva_to_gpa = nonpaging_gva_to_gpa;
 	context->sync_page = nonpaging_sync_page;
 	context->invlpg = nonpaging_invlpg;
-	context->update_pte = nonpaging_update_pte;
 	context->root_level = 0;
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->direct_map = true;
@@ -4564,7 +4584,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);
@@ -4646,7 +4666,15 @@
 void
 reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
 {
-	bool uses_nx = context->nx ||
+	/*
+	 * KVM uses NX when TDP is disabled to handle a variety of scenarios,
+	 * notably for huge SPTEs if iTLB multi-hit mitigation is enabled and
+	 * to generate correct permissions for CR0.WP=0/CR4.SMEP=1/EFER.NX=0.
+	 * The iTLB multi-hit workaround can be toggled at any time, so assume
+	 * NX can be used by any non-nested shadow MMU to avoid having to reset
+	 * MMU contexts.  Note, KVM forces EFER.NX=1 when TDP is disabled.
+	 */
+	bool uses_nx = context->nx || !tdp_enabled ||
 		context->mmu_role.base.smep_andnot_wp;
 	struct rsvd_bits_validate *shadow_zero_check;
 	int i;
@@ -4907,7 +4935,6 @@
 	context->gva_to_gpa = paging64_gva_to_gpa;
 	context->sync_page = paging64_sync_page;
 	context->invlpg = paging64_invlpg;
-	context->update_pte = paging64_update_pte;
 	context->shadow_root_level = level;
 	context->direct_map = false;
 }
@@ -4936,7 +4963,6 @@
 	context->gva_to_gpa = paging32_gva_to_gpa;
 	context->sync_page = paging32_sync_page;
 	context->invlpg = paging32_invlpg;
-	context->update_pte = paging32_update_pte;
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->direct_map = false;
 }
@@ -5011,7 +5037,6 @@
 	context->page_fault = tdp_page_fault;
 	context->sync_page = nonpaging_sync_page;
 	context->invlpg = nonpaging_invlpg;
-	context->update_pte = nonpaging_update_pte;
 	context->shadow_root_level = kvm_x86_ops->get_tdp_level(vcpu);
 	context->direct_map = true;
 	context->set_cr3 = kvm_x86_ops->set_tdp_cr3;
@@ -5144,7 +5169,6 @@
 	context->gva_to_gpa = ept_gva_to_gpa;
 	context->sync_page = ept_sync_page;
 	context->invlpg = ept_invlpg;
-	context->update_pte = ept_update_pte;
 	context->root_level = PT64_ROOT_4LEVEL;
 	context->direct_map = false;
 	context->mmu_role.as_u64 = new_role.as_u64;
@@ -5284,19 +5308,6 @@
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_unload);
 
-static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
-				  struct kvm_mmu_page *sp, u64 *spte,
-				  const void *new)
-{
-	if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
-		++vcpu->kvm->stat.mmu_pde_zapped;
-		return;
-        }
-
-	++vcpu->kvm->stat.mmu_pte_updated;
-	vcpu->arch.mmu->update_pte(vcpu, sp, spte, new);
-}
-
 static bool need_remote_flush(u64 old, u64 new)
 {
 	if (!is_shadow_present_pte(old))
@@ -5462,14 +5473,10 @@
 
 		local_flush = true;
 		while (npte--) {
-			u32 base_role = vcpu->arch.mmu->mmu_role.base.word;
-
 			entry = *spte;
 			mmu_page_zap_pte(vcpu->kvm, sp, spte);
-			if (gentry &&
-			      !((sp->role.word ^ base_role)
-			      & mmu_base_role_mask.word) && rmap_can_add(vcpu))
-				mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
+			if (gentry && sp->role.level != PG_LEVEL_4K)
+				++vcpu->kvm->stat.mmu_pde_zapped;
 			if (need_remote_flush(entry, *spte))
 				remote_flush = true;
 			++spte;
@@ -5516,7 +5523,7 @@
 	return 0;
 }
 
-int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u64 error_code,
+int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 error_code,
 		       void *insn, int insn_len)
 {
 	int r, emulation_type = 0;
@@ -5525,18 +5532,18 @@
 	/* With shadow page tables, fault_address contains a GVA or nGPA.  */
 	if (vcpu->arch.mmu->direct_map) {
 		vcpu->arch.gpa_available = true;
-		vcpu->arch.gpa_val = cr2;
+		vcpu->arch.gpa_val = cr2_or_gpa;
 	}
 
 	r = RET_PF_INVALID;
 	if (unlikely(error_code & PFERR_RSVD_MASK)) {
-		r = handle_mmio_page_fault(vcpu, cr2, direct);
+		r = handle_mmio_page_fault(vcpu, cr2_or_gpa, direct);
 		if (r == RET_PF_EMULATE)
 			goto emulate;
 	}
 
 	if (r == RET_PF_INVALID) {
-		r = vcpu->arch.mmu->page_fault(vcpu, cr2,
+		r = vcpu->arch.mmu->page_fault(vcpu, cr2_or_gpa,
 					       lower_32_bits(error_code),
 					       false);
 		WARN_ON(r == RET_PF_INVALID);
@@ -5556,7 +5563,7 @@
 	 */
 	if (vcpu->arch.mmu->direct_map &&
 	    (error_code & PFERR_NESTED_GUEST_PAGE) == PFERR_NESTED_GUEST_PAGE) {
-		kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(cr2));
+		kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(cr2_or_gpa));
 		return 1;
 	}
 
@@ -5571,7 +5578,7 @@
 	 * explicitly shadowing L1's page tables, i.e. unprotecting something
 	 * for L1 isn't going to magically fix whatever issue cause L2 to fail.
 	 */
-	if (!mmio_info_in_cache(vcpu, cr2, direct) && !is_guest_mode(vcpu))
+	if (!mmio_info_in_cache(vcpu, cr2_or_gpa, direct) && !is_guest_mode(vcpu))
 		emulation_type = EMULTYPE_ALLOW_RETRY;
 emulate:
 	/*
@@ -5586,7 +5593,7 @@
 			return 1;
 	}
 
-	return x86_emulate_instruction(vcpu, cr2, emulation_type, insn,
+	return x86_emulate_instruction(vcpu, cr2_or_gpa, emulation_type, insn,
 				       insn_len);
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_page_fault);
@@ -5629,14 +5636,16 @@
 	uint i;
 
 	if (pcid == kvm_get_active_pcid(vcpu)) {
-		mmu->invlpg(vcpu, gva, mmu->root_hpa);
+		if (mmu->invlpg)
+			mmu->invlpg(vcpu, gva, mmu->root_hpa);
 		tlb_flush = true;
 	}
 
 	for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) {
 		if (VALID_PAGE(mmu->prev_roots[i].hpa) &&
 		    pcid == kvm_get_pcid(vcpu, mmu->prev_roots[i].cr3)) {
-			mmu->invlpg(vcpu, gva, mmu->prev_roots[i].hpa);
+			if (mmu->invlpg)
+				mmu->invlpg(vcpu, gva, mmu->prev_roots[i].hpa);
 			tlb_flush = true;
 		}
 	}
@@ -5814,6 +5823,7 @@
 {
 	struct kvm_mmu_page *sp, *node;
 	int nr_zapped, batch = 0;
+	bool unstable;
 
 restart:
 	list_for_each_entry_safe_reverse(sp, node,
@@ -5846,11 +5856,12 @@
 			goto restart;
 		}
 
-		if (__kvm_mmu_prepare_zap_page(kvm, sp,
-				&kvm->arch.zapped_obsolete_pages, &nr_zapped)) {
-			batch += nr_zapped;
+		unstable = __kvm_mmu_prepare_zap_page(kvm, sp,
+				&kvm->arch.zapped_obsolete_pages, &nr_zapped);
+		batch += nr_zapped;
+
+		if (unstable)
 			goto restart;
-		}
 	}
 
 	/*
@@ -6232,25 +6243,16 @@
 	u64 mask;
 
 	/*
-	 * Set the reserved bits and the present bit of an paging-structure
-	 * entry to generate page fault with PFER.RSV = 1.
-	 */
-
-	/*
-	 * Mask the uppermost physical address bit, which would be reserved as
-	 * long as the supported physical address width is less than 52.
-	 */
-	mask = 1ull << 51;
-
-	/* Set the present bit. */
-	mask |= 1ull;
-
-	/*
-	 * If reserved bit is not supported, clear the present bit to disable
-	 * mmio page fault.
+	 * Set a reserved PA bit in MMIO SPTEs to generate page faults with
+	 * PFEC.RSVD=1 on MMIO accesses.  64-bit PTEs (PAE, x86-64, and EPT
+	 * paging) support a maximum of 52 bits of PA, i.e. if the CPU supports
+	 * 52-bit physical addresses then there are no reserved PA bits in the
+	 * PTEs and so the reserved PA approach must be disabled.
 	 */
-	if (IS_ENABLED(CONFIG_X86_64) && shadow_phys_bits == 52)
-		mask &= ~1ull;
+	if (shadow_phys_bits < 52)
+		mask = BIT_ULL(51) | PT_PRESENT_MASK;
+	else
+		mask = 0;
 
 	kvm_mmu_set_mmio_spte_mask(mask, mask, ACC_WRITE_MASK | ACC_USER_MASK);
 }
@@ -6445,6 +6447,7 @@
 				cond_resched_lock(&kvm->mmu_lock);
 		}
 	}
+	kvm_mmu_commit_zap_page(kvm, &invalid_list);
 
 	spin_unlock(&kvm->mmu_lock);
 	srcu_read_unlock(&kvm->srcu, rcu_idx);
--- linux-ein-5.4.0.orig/arch/x86/kvm/mmu.h
+++ linux-ein-5.4.0/arch/x86/kvm/mmu.h
@@ -48,7 +48,7 @@
 	if (e < s)
 		return 0;
 
-	return ((1ULL << (e - s + 1)) - 1) << s;
+	return ((2ULL << (e - s)) - 1) << s;
 }
 
 void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask, u64 mmio_value, u64 access_mask);
@@ -209,7 +209,7 @@
 void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
 bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
 				    struct kvm_memory_slot *slot, u64 gfn);
-int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu);
+int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
 
 int kvm_mmu_post_init_vm(struct kvm *kvm);
 void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
--- linux-ein-5.4.0.orig/arch/x86/kvm/mmutrace.h
+++ linux-ein-5.4.0/arch/x86/kvm/mmutrace.h
@@ -249,13 +249,13 @@
 
 TRACE_EVENT(
 	fast_page_fault,
-	TP_PROTO(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
+	TP_PROTO(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u32 error_code,
 		 u64 *sptep, u64 old_spte, bool retry),
-	TP_ARGS(vcpu, gva, error_code, sptep, old_spte, retry),
+	TP_ARGS(vcpu, cr2_or_gpa, error_code, sptep, old_spte, retry),
 
 	TP_STRUCT__entry(
 		__field(int, vcpu_id)
-		__field(gva_t, gva)
+		__field(gpa_t, cr2_or_gpa)
 		__field(u32, error_code)
 		__field(u64 *, sptep)
 		__field(u64, old_spte)
@@ -265,7 +265,7 @@
 
 	TP_fast_assign(
 		__entry->vcpu_id = vcpu->vcpu_id;
-		__entry->gva = gva;
+		__entry->cr2_or_gpa = cr2_or_gpa;
 		__entry->error_code = error_code;
 		__entry->sptep = sptep;
 		__entry->old_spte = old_spte;
@@ -273,9 +273,9 @@
 		__entry->retry = retry;
 	),
 
-	TP_printk("vcpu %d gva %lx error_code %s sptep %p old %#llx"
+	TP_printk("vcpu %d gva %llx error_code %s sptep %p old %#llx"
 		  " new %llx spurious %d fixed %d", __entry->vcpu_id,
-		  __entry->gva, __print_flags(__entry->error_code, "|",
+		  __entry->cr2_or_gpa, __print_flags(__entry->error_code, "|",
 		  kvm_mmu_trace_pferr_flags), __entry->sptep,
 		  __entry->old_spte, __entry->new_spte,
 		  __spte_satisfied(old_spte), __spte_satisfied(new_spte)
@@ -339,7 +339,7 @@
 		/* These depend on page entry type, so compute them now.  */
 		__field(bool, r)
 		__field(bool, x)
-		__field(u8, u)
+		__field(signed char, u)
 	),
 
 	TP_fast_assign(
--- linux-ein-5.4.0.orig/arch/x86/kvm/mtrr.c
+++ linux-ein-5.4.0/arch/x86/kvm/mtrr.c
@@ -192,11 +192,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;
--- linux-ein-5.4.0.orig/arch/x86/kvm/paging_tmpl.h
+++ linux-ein-5.4.0/arch/x86/kvm/paging_tmpl.h
@@ -33,10 +33,9 @@
 	#define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT
 	#define PT_HAVE_ACCESSED_DIRTY(mmu) true
 	#ifdef CONFIG_X86_64
-	#define PT_MAX_FULL_LEVELS 4
-	#define CMPXCHG cmpxchg
+	#define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL
+	#define CMPXCHG "cmpxchgq"
 	#else
-	#define CMPXCHG cmpxchg64
 	#define PT_MAX_FULL_LEVELS 2
 	#endif
 #elif PTTYPE == 32
@@ -52,7 +51,7 @@
 	#define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT
 	#define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT
 	#define PT_HAVE_ACCESSED_DIRTY(mmu) true
-	#define CMPXCHG cmpxchg
+	#define CMPXCHG "cmpxchgl"
 #elif PTTYPE == PTTYPE_EPT
 	#define pt_element_t u64
 	#define guest_walker guest_walkerEPT
@@ -65,8 +64,10 @@
 	#define PT_GUEST_DIRTY_SHIFT 9
 	#define PT_GUEST_ACCESSED_SHIFT 8
 	#define PT_HAVE_ACCESSED_DIRTY(mmu) ((mmu)->ept_ad)
-	#define CMPXCHG cmpxchg64
 	#define PT_MAX_FULL_LEVELS 4
+	#ifdef CONFIG_X86_64
+	#define CMPXCHG "cmpxchgq"
+	#endif
 #else
 	#error Invalid PTTYPE value
 #endif
@@ -90,8 +91,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;
 };
@@ -132,43 +133,39 @@
 			       pt_element_t __user *ptep_user, unsigned index,
 			       pt_element_t orig_pte, pt_element_t new_pte)
 {
-	int npages;
-	pt_element_t ret;
-	pt_element_t *table;
-	struct page *page;
-
-	npages = get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &page);
-	if (likely(npages == 1)) {
-		table = kmap_atomic(page);
-		ret = CMPXCHG(&table[index], orig_pte, new_pte);
-		kunmap_atomic(table);
-
-		kvm_release_page_dirty(page);
-	} else {
-		struct vm_area_struct *vma;
-		unsigned long vaddr = (unsigned long)ptep_user & PAGE_MASK;
-		unsigned long pfn;
-		unsigned long paddr;
-
-		down_read(&current->mm->mmap_sem);
-		vma = find_vma_intersection(current->mm, vaddr, vaddr + PAGE_SIZE);
-		if (!vma || !(vma->vm_flags & VM_PFNMAP)) {
-			up_read(&current->mm->mmap_sem);
-			return -EFAULT;
-		}
-		pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-		paddr = pfn << PAGE_SHIFT;
-		table = memremap(paddr, PAGE_SIZE, MEMREMAP_WB);
-		if (!table) {
-			up_read(&current->mm->mmap_sem);
-			return -EFAULT;
-		}
-		ret = CMPXCHG(&table[index], orig_pte, new_pte);
-		memunmap(table);
-		up_read(&current->mm->mmap_sem);
-	}
+	int r = -EFAULT;
+
+	if (!user_access_begin(ptep_user, sizeof(pt_element_t)))
+		return -EFAULT;
 
-	return (ret != orig_pte);
+#ifdef CMPXCHG
+	asm volatile("1:" LOCK_PREFIX CMPXCHG " %[new], %[ptr]\n"
+		     "mov $0, %[r]\n"
+		     "setnz %b[r]\n"
+		     "2:"
+		     _ASM_EXTABLE_UA(1b, 2b)
+		     : [ptr] "+m" (*ptep_user),
+		       [old] "+a" (orig_pte),
+		       [r] "+q" (r)
+		     : [new] "r" (new_pte)
+		     : "memory");
+#else
+	asm volatile("1:" LOCK_PREFIX "cmpxchg8b %[ptr]\n"
+		     "movl $0, %[r]\n"
+		     "jz 2f\n"
+		     "incl %[r]\n"
+		     "2:"
+		     _ASM_EXTABLE_UA(1b, 2b)
+		     : [ptr] "+m" (*ptep_user),
+		       [old] "+A" (orig_pte),
+		       [r] "+rm" (r)
+		     : [new_lo] "b" ((u32)new_pte),
+		       [new_hi] "c" ((u32)(new_pte >> 32))
+		     : "memory");
+#endif
+
+	user_access_end();
+	return r;
 }
 
 static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu,
@@ -220,7 +217,7 @@
 static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
 					     struct kvm_mmu *mmu,
 					     struct guest_walker *walker,
-					     int write_fault)
+					     gpa_t addr, int write_fault)
 {
 	unsigned level, index;
 	pt_element_t pte, orig_pte;
@@ -245,7 +242,7 @@
 				!(pte & PT_GUEST_DIRTY_MASK)) {
 			trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
 #if PTTYPE == PTTYPE_EPT
-			if (kvm_arch_write_log_dirty(vcpu))
+			if (kvm_arch_write_log_dirty(vcpu, addr))
 				return -EINVAL;
 #endif
 			pte |= PT_GUEST_DIRTY_MASK;
@@ -291,11 +288,11 @@
 }
 
 /*
- * Fetch a guest pte for a guest virtual address
+ * Fetch a guest pte for a guest virtual address, or for an L2's GPA.
  */
 static int FNAME(walk_addr_generic)(struct guest_walker *walker,
 				    struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
-				    gva_t addr, u32 access)
+				    gpa_t addr, u32 access)
 {
 	int ret;
 	pt_element_t pte;
@@ -406,13 +403,15 @@
 		}
 
 		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));
 
 	pte_pkey = FNAME(gpte_pkeys)(vcpu, pte);
 	accessed_dirty = have_ad ? pte_access & PT_GUEST_ACCESSED_MASK : 0;
 
 	/* Convert to ACC_*_MASK flags for struct guest_walker.  */
-	walker->pt_access = FNAME(gpte_access)(pt_access ^ walk_nx_mask);
 	walker->pte_access = FNAME(gpte_access)(pte_access ^ walk_nx_mask);
 	errcode = permission_fault(vcpu, mmu, walker->pte_access, pte_pkey, access);
 	if (unlikely(errcode))
@@ -442,7 +441,8 @@
 			(PT_GUEST_DIRTY_SHIFT - PT_GUEST_ACCESSED_SHIFT);
 
 	if (unlikely(!accessed_dirty)) {
-		ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault);
+		ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker,
+							addr, write_fault);
 		if (unlikely(ret < 0))
 			goto error;
 		else if (ret)
@@ -450,7 +450,8 @@
 	}
 
 	pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
-		 __func__, (u64)pte, walker->pte_access, walker->pt_access);
+		 __func__, (u64)pte, walker->pte_access,
+		 walker->pt_access[walker->level - 1]);
 	return 1;
 
 error:
@@ -496,7 +497,7 @@
 }
 
 static int FNAME(walk_addr)(struct guest_walker *walker,
-			    struct kvm_vcpu *vcpu, gva_t addr, u32 access)
+			    struct kvm_vcpu *vcpu, gpa_t addr, u32 access)
 {
 	return FNAME(walk_addr_generic)(walker, vcpu, vcpu->arch.mmu, addr,
 					access);
@@ -611,7 +612,7 @@
  * If the guest tries to write a write-protected page, we need to
  * emulate this operation, return 1 to indicate this case.
  */
-static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
+static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
 			 struct guest_walker *gw,
 			 int write_fault, int hlevel,
 			 kvm_pfn_t pfn, bool map_writable, bool prefault,
@@ -619,7 +620,7 @@
 {
 	struct kvm_mmu_page *sp = NULL;
 	struct kvm_shadow_walk_iterator it;
-	unsigned direct_access, access = gw->pt_access;
+	unsigned int direct_access, access;
 	int top_level, ret;
 	gfn_t gfn, base_gfn;
 
@@ -651,6 +652,7 @@
 		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);
 		}
@@ -765,7 +767,7 @@
  *  Returns: 1 if we need to emulate the instruction, 0 otherwise, or
  *           a negative value on error.
  */
-static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
+static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gpa_t addr, u32 error_code,
 			     bool prefault)
 {
 	int write_fault = error_code & PFERR_WRITE_MASK;
@@ -945,18 +947,19 @@
 	spin_unlock(&vcpu->kvm->mmu_lock);
 }
 
-static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access,
+/* Note, @addr is a GPA when gva_to_gpa() translates an L2 GPA to an L1 GPA. */
+static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gpa_t addr, u32 access,
 			       struct x86_exception *exception)
 {
 	struct guest_walker walker;
 	gpa_t gpa = UNMAPPED_GVA;
 	int r;
 
-	r = FNAME(walk_addr)(&walker, vcpu, vaddr, access);
+	r = FNAME(walk_addr)(&walker, vcpu, addr, access);
 
 	if (r) {
 		gpa = gfn_to_gpa(walker.gfn);
-		gpa |= vaddr & ~PAGE_MASK;
+		gpa |= addr & ~PAGE_MASK;
 	} else if (exception)
 		*exception = walker.fault;
 
@@ -964,7 +967,8 @@
 }
 
 #if PTTYPE != PTTYPE_EPT
-static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
+/* Note, gva_to_gpa_nested() is only used to translate L2 GVAs. */
+static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gpa_t vaddr,
 				      u32 access,
 				      struct x86_exception *exception)
 {
@@ -972,6 +976,11 @@
 	gpa_t gpa = UNMAPPED_GVA;
 	int r;
 
+#ifndef CONFIG_X86_64
+	/* A 64-bit GVA should be impossible on 32-bit KVM. */
+	WARN_ON_ONCE(vaddr >> 32);
+#endif
+
 	r = FNAME(walk_addr_nested)(&walker, vcpu, vaddr, access);
 
 	if (r) {
--- linux-ein-5.4.0.orig/arch/x86/kvm/pmu.c
+++ linux-ein-5.4.0/arch/x86/kvm/pmu.c
@@ -143,7 +143,6 @@
 void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 {
 	unsigned config, type = PERF_TYPE_RAW;
-	u8 event_select, unit_mask;
 	struct kvm *kvm = pmc->vcpu->kvm;
 	struct kvm_pmu_event_filter *filter;
 	int i;
@@ -175,23 +174,18 @@
 	if (!allow_event)
 		return;
 
-	event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
-	unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
-
 	if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
 			  ARCH_PERFMON_EVENTSEL_INV |
 			  ARCH_PERFMON_EVENTSEL_CMASK |
 			  HSW_IN_TX |
 			  HSW_IN_TX_CHECKPOINTED))) {
-		config = kvm_x86_ops->pmu_ops->find_arch_event(pmc_to_pmu(pmc),
-						      event_select,
-						      unit_mask);
+		config = kvm_x86_ops->pmu_ops->pmc_perf_hw_id(pmc);
 		if (config != PERF_COUNT_HW_MAX)
 			type = PERF_TYPE_HARDWARE;
 	}
 
 	if (type == PERF_TYPE_RAW)
-		config = eventsel & X86_RAW_EVENT_MASK;
+		config = eventsel & AMD64_RAW_EVENT_MASK;
 
 	pmc_reprogram_counter(pmc, type, config,
 			      !(eventsel & ARCH_PERFMON_EVENTSEL_USR),
--- linux-ein-5.4.0.orig/arch/x86/kvm/pmu.h
+++ linux-ein-5.4.0/arch/x86/kvm/pmu.h
@@ -2,6 +2,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)
@@ -20,8 +22,7 @@
 };
 
 struct kvm_pmu_ops {
-	unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
-				    u8 unit_mask);
+	unsigned int (*pmc_perf_hw_id)(struct kvm_pmc *pmc);
 	unsigned (*find_fixed_event)(int idx);
 	bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
 	struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
@@ -86,8 +87,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;
 }
@@ -97,8 +102,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-ein-5.4.0.orig/arch/x86/kvm/pmu_amd.c
+++ linux-ein-5.4.0/arch/x86/kvm/pmu_amd.c
@@ -44,6 +44,22 @@
 	[7] = { 0xd1, 0x00, PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
 };
 
+/* duplicated from amd_f17h_perfmon_event_map. */
+static struct kvm_event_hw_type_mapping amd_f17h_event_mapping[] = {
+	[0] = { 0x76, 0x00, PERF_COUNT_HW_CPU_CYCLES },
+	[1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
+	[2] = { 0x60, 0xff, PERF_COUNT_HW_CACHE_REFERENCES },
+	[3] = { 0x64, 0x09, PERF_COUNT_HW_CACHE_MISSES },
+	[4] = { 0xc2, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+	[5] = { 0xc3, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+	[6] = { 0x87, 0x02, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
+	[7] = { 0x87, 0x01, PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
+};
+
+/* amd_pmc_perf_hw_id depends on these being the same size */
+static_assert(ARRAY_SIZE(amd_event_mapping) ==
+	     ARRAY_SIZE(amd_f17h_event_mapping));
+
 static unsigned int get_msr_base(struct kvm_pmu *pmu, enum pmu_type type)
 {
 	struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
@@ -126,21 +142,27 @@
 	return &pmu->gp_counters[msr_to_index(msr)];
 }
 
-static unsigned amd_find_arch_event(struct kvm_pmu *pmu,
-				    u8 event_select,
-				    u8 unit_mask)
+static unsigned int amd_pmc_perf_hw_id(struct kvm_pmc *pmc)
 {
+	struct kvm_event_hw_type_mapping *event_mapping;
+	u8 event_select = pmc->eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
+	u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 	int i;
 
+	if (guest_cpuid_family(pmc->vcpu) >= 0x17)
+		event_mapping = amd_f17h_event_mapping;
+	else
+		event_mapping = amd_event_mapping;
+
 	for (i = 0; i < ARRAY_SIZE(amd_event_mapping); i++)
-		if (amd_event_mapping[i].eventsel == event_select
-		    && amd_event_mapping[i].unit_mask == unit_mask)
+		if (event_mapping[i].eventsel == event_select
+		    && event_mapping[i].unit_mask == unit_mask)
 			break;
 
 	if (i == ARRAY_SIZE(amd_event_mapping))
 		return PERF_COUNT_HW_MAX;
 
-	return amd_event_mapping[i].event_type;
+	return event_mapping[i].event_type;
 }
 
 /* return PERF_COUNT_HW_MAX as AMD doesn't have fixed events */
@@ -245,12 +267,10 @@
 	/* MSR_EVNTSELn */
 	pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_EVNTSEL);
 	if (pmc) {
-		if (data == pmc->eventsel)
-			return 0;
-		if (!(data & pmu->reserved_bits)) {
+		data &= ~pmu->reserved_bits;
+		if (data != pmc->eventsel)
 			reprogram_gp_counter(pmc, data);
-			return 0;
-		}
+		return 0;
 	}
 
 	return 1;
@@ -266,7 +286,7 @@
 		pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
 
 	pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
-	pmu->reserved_bits = 0xffffffff00200000ull;
+	pmu->reserved_bits = 0xfffffff000280000ull;
 	pmu->version = 1;
 	/* not applicable to AMD; but clean them to prevent any fall out */
 	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
@@ -302,7 +322,7 @@
 }
 
 struct kvm_pmu_ops amd_pmu_ops = {
-	.find_arch_event = amd_find_arch_event,
+	.pmc_perf_hw_id = amd_pmc_perf_hw_id,
 	.find_fixed_event = amd_find_fixed_event,
 	.pmc_is_enabled = amd_pmc_is_enabled,
 	.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
--- linux-ein-5.4.0.orig/arch/x86/kvm/svm.c
+++ linux-ein-5.4.0/arch/x86/kvm/svm.c
@@ -47,6 +47,7 @@
 #include <asm/kvm_para.h>
 #include <asm/irq_remapping.h>
 #include <asm/spec-ctrl.h>
+#include <asm/cpu_device_id.h>
 
 #include <asm/virtext.h>
 #include "trace.h"
@@ -516,6 +517,9 @@
 	c->intercept_dr = h->intercept_dr | g->intercept_dr;
 	c->intercept_exceptions = h->intercept_exceptions | g->intercept_exceptions;
 	c->intercept = h->intercept | g->intercept;
+
+	c->intercept |= (1ULL << INTERCEPT_VMLOAD);
+	c->intercept |= (1ULL << INTERCEPT_VMSAVE);
 }
 
 static inline struct vmcb *get_host_vmcb(struct vcpu_svm *svm)
@@ -787,9 +791,6 @@
 		if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))
 			return 0;
 	} else {
-		if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE)
-			pr_err("%s: ip 0x%lx next 0x%llx\n",
-			       __func__, kvm_rip_read(vcpu), svm->next_rip);
 		kvm_rip_write(vcpu, svm->next_rip);
 	}
 	svm_set_interrupt_shadow(vcpu, 0);
@@ -892,6 +893,11 @@
 		return 0;
 	}
 
+	if (sev_active()) {
+		pr_info("KVM is unsupported when running as an SEV guest\n");
+		return 0;
+	}
+
 	return 1;
 }
 
@@ -998,33 +1004,32 @@
 static int svm_cpu_init(int cpu)
 {
 	struct svm_cpu_data *sd;
-	int r;
 
 	sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
 	if (!sd)
 		return -ENOMEM;
 	sd->cpu = cpu;
-	r = -ENOMEM;
 	sd->save_area = alloc_page(GFP_KERNEL);
 	if (!sd->save_area)
-		goto err_1;
+		goto free_cpu_data;
 
 	if (svm_sev_enabled()) {
-		r = -ENOMEM;
 		sd->sev_vmcbs = kmalloc_array(max_sev_asid + 1,
 					      sizeof(void *),
 					      GFP_KERNEL);
 		if (!sd->sev_vmcbs)
-			goto err_1;
+			goto free_save_area;
 	}
 
 	per_cpu(svm_data, cpu) = sd;
 
 	return 0;
 
-err_1:
+free_save_area:
+	__free_page(sd->save_area);
+free_cpu_data:
 	kfree(sd);
-	return r;
+	return -ENOMEM;
 
 }
 
@@ -1298,6 +1303,47 @@
 	}
 }
 
+/*
+ * The default MMIO mask is a single bit (excluding the present bit),
+ * which could conflict with the memory encryption bit. Check for
+ * memory encryption support and override the default MMIO mask if
+ * memory encryption is enabled.
+ */
+static __init void svm_adjust_mmio_mask(void)
+{
+	unsigned int enc_bit, mask_bit;
+	u64 msr, mask;
+
+	/* If there is no memory encryption support, use existing mask */
+	if (cpuid_eax(0x80000000) < 0x8000001f)
+		return;
+
+	/* If memory encryption is not enabled, use existing mask */
+	rdmsrl(MSR_K8_SYSCFG, msr);
+	if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
+		return;
+
+	enc_bit = cpuid_ebx(0x8000001f) & 0x3f;
+	mask_bit = boot_cpu_data.x86_phys_bits;
+
+	/* Increment the mask bit if it is the same as the encryption bit */
+	if (enc_bit == mask_bit)
+		mask_bit++;
+
+	/*
+	 * If the mask bit location is below 52, then some bits above the
+	 * physical addressing limit will always be reserved, so use the
+	 * rsvd_bits() function to generate the mask. This mask, along with
+	 * the present bit, will be used to generate a page fault with
+	 * PFER.RSV = 1.
+	 *
+	 * If the mask bit location is 52 (or above), then clear the mask.
+	 */
+	mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0;
+
+	kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK);
+}
+
 static __init int svm_hardware_setup(void)
 {
 	int cpu;
@@ -1352,6 +1398,8 @@
 		}
 	}
 
+	svm_adjust_mmio_mask();
+
 	for_each_possible_cpu(cpu) {
 		r = svm_cpu_init(cpu);
 		if (r)
@@ -1399,12 +1447,7 @@
 		}
 	}
 
-	if (vgif) {
-		if (!boot_cpu_has(X86_FEATURE_VGIF))
-			vgif = false;
-		else
-			pr_info("Virtual GIF supported\n");
-	}
+	vgif = false; /* Disabled for CVE-2021-3653 */
 
 	return 0;
 
@@ -1739,7 +1782,7 @@
 
 	for_each_possible_cpu(cpu) {
 		sd = per_cpu(svm_data, cpu);
-		sd->sev_vmcbs[pos] = NULL;
+		sd->sev_vmcbs[asid] = NULL;
 	}
 }
 
@@ -1750,9 +1793,25 @@
 	__sev_asid_free(sev->asid);
 }
 
-static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
+static void sev_decommission(unsigned int handle)
 {
 	struct sev_data_decommission *decommission;
+
+	if (!handle)
+		return;
+
+	decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
+	if (!decommission)
+		return;
+
+	decommission->handle = handle;
+	sev_guest_decommission(decommission, NULL);
+
+	kfree(decommission);
+}
+
+static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
+{
 	struct sev_data_deactivate *data;
 
 	if (!handle)
@@ -1770,15 +1829,7 @@
 	sev_guest_df_flush(NULL);
 	kfree(data);
 
-	decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
-	if (!decommission)
-		return;
-
-	/* decommission handle */
-	decommission->handle = handle;
-	sev_guest_decommission(decommission, NULL);
-
-	kfree(decommission);
+	sev_decommission(handle);
 }
 
 static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
@@ -1791,6 +1842,8 @@
 	struct page **pages;
 	unsigned long first, last;
 
+	lockdep_assert_held(&kvm->lock);
+
 	if (ulen == 0 || uaddr + ulen < uaddr)
 		return NULL;
 
@@ -1818,7 +1871,7 @@
 		return NULL;
 
 	/* Pin the user virtual address. */
-	npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages);
+	npinned = get_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
 	if (npinned != npages) {
 		pr_err("SEV: Failure locking %lu pages.\n", npages);
 		goto err;
@@ -1852,7 +1905,8 @@
 	uint8_t *page_virtual;
 	unsigned long i;
 
-	if (npages == 0 || pages == NULL)
+	if (this_cpu_has(X86_FEATURE_SME_COHERENT) || npages == 0 ||
+	    pages == NULL)
 		return;
 
 	for (i = 0; i < npages; i++) {
@@ -1883,6 +1937,10 @@
 	struct kvm_svm *kvm_svm = __vmalloc(sizeof(struct kvm_svm),
 					    GFP_KERNEL_ACCOUNT | __GFP_ZERO,
 					    PAGE_KERNEL);
+
+	if (!kvm_svm)
+		return NULL;
+
 	return &kvm_svm->kvm;
 }
 
@@ -1910,6 +1968,7 @@
 		list_for_each_safe(pos, q, head) {
 			__unregister_enc_region_locked(kvm,
 				list_entry(pos, struct enc_region, list));
+			cond_resched();
 		}
 	}
 
@@ -3191,8 +3250,8 @@
 			return NESTED_EXIT_HOST;
 		break;
 	case SVM_EXIT_EXCP_BASE + PF_VECTOR:
-		/* When we're shadowing, trap PFs, but not async PF */
-		if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
+		/* Trap async PF even if not shadowing */
+		if (!npt_enabled || svm->vcpu.arch.apf.host_apf_reason)
 			return NESTED_EXIT_HOST;
 		break;
 	default:
@@ -3281,7 +3340,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;
@@ -3548,7 +3607,13 @@
 	svm->nested.intercept            = nested_vmcb->control.intercept;
 
 	svm_flush_tlb(&svm->vcpu, true);
-	svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
+
+	svm->vmcb->control.int_ctl &=
+			V_INTR_MASKING_MASK | V_GIF_ENABLE_MASK | V_GIF_MASK;
+
+	svm->vmcb->control.int_ctl |= nested_vmcb->control.int_ctl &
+			(V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK);
+
 	if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
 		svm->vcpu.arch.hflags |= HF_VINTR_MASK;
 	else
@@ -3924,6 +3989,12 @@
 	return 1;
 }
 
+static int invd_interception(struct vcpu_svm *svm)
+{
+	/* Treat an INVD instruction as a NOP and just skip it. */
+	return kvm_skip_emulated_instruction(&svm->vcpu);
+}
+
 static int invlpg_interception(struct vcpu_svm *svm)
 {
 	if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
@@ -4001,7 +4072,7 @@
 	err = 0;
 	if (cr >= 16) { /* mov to cr */
 		cr -= 16;
-		val = kvm_register_read(&svm->vcpu, reg);
+		val = kvm_register_readl(&svm->vcpu, reg);
 		switch (cr) {
 		case 0:
 			if (!check_selective_cr0_intercepted(svm, val))
@@ -4046,7 +4117,7 @@
 			kvm_queue_exception(&svm->vcpu, UD_VECTOR);
 			return 1;
 		}
-		kvm_register_write(&svm->vcpu, reg, val);
+		kvm_register_writel(&svm->vcpu, reg, val);
 	}
 	return kvm_complete_insn_gp(&svm->vcpu, err);
 }
@@ -4076,13 +4147,13 @@
 	if (dr >= 16) { /* mov to DRn */
 		if (!kvm_require_dr(&svm->vcpu, dr - 16))
 			return 1;
-		val = kvm_register_read(&svm->vcpu, reg);
+		val = kvm_register_readl(&svm->vcpu, reg);
 		kvm_set_dr(&svm->vcpu, dr - 16, val);
 	} else {
 		if (!kvm_require_dr(&svm->vcpu, dr))
 			return 1;
 		kvm_get_dr(&svm->vcpu, dr, &val);
-		kvm_register_write(&svm->vcpu, reg, val);
+		kvm_register_writel(&svm->vcpu, reg, val);
 	}
 
 	return kvm_skip_emulated_instruction(&svm->vcpu);
@@ -4109,9 +4180,9 @@
 	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;
+	case MSR_AMD64_DE_CFG:
+		if (cpu_feature_enabled(X86_FEATURE_LFENCE_RDTSC))
+			msr->data |= MSR_AMD64_DE_CFG_LFENCE_SERIALIZE;
 		break;
 	default:
 		return 1;
@@ -4184,8 +4255,7 @@
 		break;
 	case MSR_IA32_SPEC_CTRL:
 		if (!msr_info->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
+		    !guest_has_spec_ctrl_msr(vcpu))
 			return 1;
 
 		msr_info->data = svm->spec_ctrl;
@@ -4214,7 +4284,7 @@
 			msr_info->data = 0x1E;
 		}
 		break;
-	case MSR_F10H_DECFG:
+	case MSR_AMD64_DE_CFG:
 		msr_info->data = svm->msr_decfg;
 		break;
 	default:
@@ -4269,16 +4339,13 @@
 		break;
 	case MSR_IA32_SPEC_CTRL:
 		if (!msr->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
+		    !guest_has_spec_ctrl_msr(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))
+		if (kvm_spec_ctrl_test_value(data))
 			return 1;
 
 		svm->spec_ctrl = data;
-
 		if (!data)
 			break;
 
@@ -4297,18 +4364,17 @@
 		break;
 	case MSR_IA32_PRED_CMD:
 		if (!msr->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB))
+		    !guest_has_pred_cmd_msr(vcpu))
 			return 1;
 
 		if (data & ~PRED_CMD_IBPB)
 			return 1;
-
+		if (!boot_cpu_has(X86_FEATURE_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:
@@ -4385,7 +4451,7 @@
 	case MSR_VM_IGNNE:
 		vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
 		break;
-	case MSR_F10H_DECFG: {
+	case MSR_AMD64_DE_CFG: {
 		struct kvm_msr_entry msr_entry;
 
 		msr_entry.index = msr->index;
@@ -4521,8 +4587,6 @@
 		break;
 	}
 	case AVIC_IPI_FAILURE_INVALID_TARGET:
-		WARN_ONCE(1, "Invalid IPI target: index=%u, vcpu=%d, icr=%#0x:%#0x\n",
-			  index, svm->vcpu.vcpu_id, icrh, icrl);
 		break;
 	case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
 		WARN_ONCE(1, "Invalid backing page\n");
@@ -4776,7 +4840,7 @@
 	[SVM_EXIT_RDPMC]			= rdpmc_interception,
 	[SVM_EXIT_CPUID]			= cpuid_interception,
 	[SVM_EXIT_IRET]                         = iret_interception,
-	[SVM_EXIT_INVD]                         = emulate_on_interception,
+	[SVM_EXIT_INVD]                         = invd_interception,
 	[SVM_EXIT_PAUSE]			= pause_interception,
 	[SVM_EXIT_HLT]				= halt_interception,
 	[SVM_EXIT_INVLPG]			= invlpg_interception,
@@ -5074,8 +5138,6 @@
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
-	BUG_ON(!(gif_set(svm)));
-
 	trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
 	++vcpu->stat.irq_injections;
 
@@ -5141,8 +5203,11 @@
 	return;
 }
 
-static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
+static int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
 {
+	if (!vcpu->arch.apicv_active)
+		return -1;
+
 	kvm_lapic_set_irr(vec, vcpu->arch.apic);
 	smp_mb__after_atomic();
 
@@ -5154,6 +5219,8 @@
 		put_cpu();
 	} else
 		kvm_vcpu_wake_up(vcpu);
+
+	return 0;
 }
 
 static bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
@@ -5329,6 +5396,7 @@
 			 * - Tell IOMMU to use legacy mode for this interrupt.
 			 * - Retrieve ga_tag of prior interrupt remapping data.
 			 */
+			pi.prev_ga_tag = 0;
 			pi.is_guest_mode = false;
 			ret = irq_set_vcpu_affinity(host_irq, &pi);
 
@@ -5650,6 +5718,8 @@
 
 	local_irq_enable();
 
+	amd_clear_divider();
+
 	asm volatile (
 		"push %%" _ASM_BP "; \n\t"
 		"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -5968,7 +6038,7 @@
 
 static bool svm_xsaves_supported(void)
 {
-	return false;
+	return boot_cpu_has(X86_FEATURE_XSAVES);
 }
 
 static bool svm_umip_emulated(void)
@@ -5986,6 +6056,11 @@
 	return true;
 }
 
+static bool svm_pku_supported(void)
+{
+	return false;
+}
+
 #define PRE_EX(exit)  { .exit_code = (exit), \
 			.stage = X86_ICPT_PRE_EXCEPT, }
 #define POST_EX(exit) { .exit_code = (exit), \
@@ -6173,7 +6248,8 @@
 
 static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu)
 {
-
+	if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_INTR)
+		vcpu->arch.at_instruction_boundary = true;
 }
 
 static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
@@ -6413,8 +6489,10 @@
 
 	/* Bind ASID to this guest */
 	ret = sev_bind_asid(kvm, start->handle, error);
-	if (ret)
+	if (ret) {
+		sev_decommission(start->handle);
 		goto e_free_session;
+	}
 
 	/* return handle to userspace */
 	params.handle = start->handle;
@@ -7031,12 +7109,20 @@
 	if (!region)
 		return -ENOMEM;
 
+	mutex_lock(&kvm->lock);
 	region->pages = sev_pin_memory(kvm, range->addr, range->size, &region->npages, 1);
 	if (!region->pages) {
 		ret = -ENOMEM;
+		mutex_unlock(&kvm->lock);
 		goto e_free;
 	}
 
+	region->uaddr = range->addr;
+	region->size = range->size;
+
+	list_add_tail(&region->list, &sev->regions_list);
+	mutex_unlock(&kvm->lock);
+
 	/*
 	 * The guest may change the memory encryption attribute from C=0 -> C=1
 	 * or vice versa for this memory range. Lets make sure caches are
@@ -7045,13 +7131,6 @@
 	 */
 	sev_clflush_pages(region->pages, region->npages);
 
-	region->uaddr = range->addr;
-	region->size = range->size;
-
-	mutex_lock(&kvm->lock);
-	list_add_tail(&region->list, &sev->regions_list);
-	mutex_unlock(&kvm->lock);
-
 	return ret;
 
 e_free:
@@ -7278,6 +7357,7 @@
 	.xsaves_supported = svm_xsaves_supported,
 	.umip_emulated = svm_umip_emulated,
 	.pt_supported = svm_pt_supported,
+	.pku_supported = svm_pku_supported,
 
 	.set_supported_cpuid = svm_set_supported_cpuid,
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/trace.h
+++ linux-ein-5.4.0/arch/x86/kvm/trace.h
@@ -1483,16 +1483,16 @@
 	TP_ARGS(msg, err),
 
 	TP_STRUCT__entry(
-		__field(const char *, msg)
+		__string(msg, msg)
 		__field(u32, err)
 	),
 
 	TP_fast_assign(
-		__entry->msg = msg;
+		__assign_str(msg, msg);
 		__entry->err = err;
 	),
 
-	TP_printk("%s%s", __entry->msg, !__entry->err ? "" :
+	TP_printk("%s%s", __get_str(msg), !__entry->err ? "" :
 		__print_symbolic(__entry->err, VMX_VMENTER_INSTRUCTION_ERRORS))
 );
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/capabilities.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/capabilities.h
@@ -12,6 +12,7 @@
 extern bool __read_mostly enable_unrestricted_guest;
 extern bool __read_mostly enable_ept_ad_bits;
 extern bool __read_mostly enable_pml;
+extern bool __read_mostly enable_apicv;
 extern int __read_mostly pt_mode;
 
 #define PT_MODE_SYSTEM		0
@@ -145,6 +146,11 @@
 		SECONDARY_EXEC_DESC;
 }
 
+static inline bool vmx_pku_supported(void)
+{
+	return boot_cpu_has(X86_FEATURE_PKU);
+}
+
 static inline bool cpu_has_vmx_rdtscp(void)
 {
 	return vmcs_config.cpu_based_2nd_exec_ctrl &
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/evmcs.c
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/evmcs.c
@@ -303,14 +303,13 @@
 };
 const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
 
-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
+__init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
 {
 	vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;
 	vmcs_conf->cpu_based_2nd_exec_ctrl &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
 
 	vmcs_conf->vmexit_ctrl &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
 	vmcs_conf->vmentry_ctrl &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
-
 }
 #endif
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/evmcs.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/evmcs.h
@@ -58,7 +58,9 @@
 	 SECONDARY_EXEC_SHADOW_VMCS |					\
 	 SECONDARY_EXEC_TSC_SCALING |					\
 	 SECONDARY_EXEC_PAUSE_LOOP_EXITING)
-#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
+#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL					\
+	(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |				\
+	 VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
 #define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
 #define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
 
@@ -184,7 +186,7 @@
 	vp_ap->enlighten_vmentry = 1;
 }
 
-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
+__init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
 #else /* !IS_ENABLED(CONFIG_HYPERV) */
 static inline void evmcs_write64(unsigned long field, u64 value) {}
 static inline void evmcs_write32(unsigned long field, u32 value) {}
@@ -193,7 +195,6 @@
 static inline u32 evmcs_read32(unsigned long field) { return 0; }
 static inline u16 evmcs_read16(unsigned long field) { return 0; }
 static inline void evmcs_load(u64 phys_addr) {}
-static inline void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) {}
 static inline void evmcs_touch_msr_bitmap(void) {}
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/nested.c
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/nested.c
@@ -11,6 +11,7 @@
 #include "mmu.h"
 #include "nested.h"
 #include "trace.h"
+#include "vmx.h"
 #include "x86.h"
 
 static bool __read_mostly enable_shadow_vmcs = 1;
@@ -223,7 +224,7 @@
 		return;
 
 	kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
-	vmx->nested.hv_evmcs_vmptr = -1ull;
+	vmx->nested.hv_evmcs_vmptr = 0;
 	vmx->nested.hv_evmcs = NULL;
 }
 
@@ -302,7 +303,7 @@
 	cpu = get_cpu();
 	prev = vmx->loaded_vmcs;
 	vmx->loaded_vmcs = vmcs;
-	vmx_vcpu_load_vmcs(vcpu, cpu);
+	vmx_vcpu_load_vmcs(vcpu, cpu, prev);
 	vmx_sync_vmcs_host_state(vmx, prev);
 	put_cpu();
 
@@ -1060,7 +1061,7 @@
 		BIT_ULL(49) | BIT_ULL(54) | BIT_ULL(55) |
 		/* reserved */
 		BIT_ULL(31) | GENMASK_ULL(47, 45) | GENMASK_ULL(63, 56);
-	u64 vmx_basic = vmx->nested.msrs.basic;
+	u64 vmx_basic = vmcs_config.nested.basic;
 
 	if (!is_bitwise_subset(vmx_basic, data, feature_and_reserved))
 		return -EINVAL;
@@ -1083,36 +1084,42 @@
 	return 0;
 }
 
-static int
-vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
+static void vmx_get_control_msr(struct nested_vmx_msrs *msrs, u32 msr_index,
+				u32 **low, u32 **high)
 {
-	u64 supported;
-	u32 *lowp, *highp;
-
 	switch (msr_index) {
 	case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
-		lowp = &vmx->nested.msrs.pinbased_ctls_low;
-		highp = &vmx->nested.msrs.pinbased_ctls_high;
+		*low = &msrs->pinbased_ctls_low;
+		*high = &msrs->pinbased_ctls_high;
 		break;
 	case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
-		lowp = &vmx->nested.msrs.procbased_ctls_low;
-		highp = &vmx->nested.msrs.procbased_ctls_high;
+		*low = &msrs->procbased_ctls_low;
+		*high = &msrs->procbased_ctls_high;
 		break;
 	case MSR_IA32_VMX_TRUE_EXIT_CTLS:
-		lowp = &vmx->nested.msrs.exit_ctls_low;
-		highp = &vmx->nested.msrs.exit_ctls_high;
+		*low = &msrs->exit_ctls_low;
+		*high = &msrs->exit_ctls_high;
 		break;
 	case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
-		lowp = &vmx->nested.msrs.entry_ctls_low;
-		highp = &vmx->nested.msrs.entry_ctls_high;
+		*low = &msrs->entry_ctls_low;
+		*high = &msrs->entry_ctls_high;
 		break;
 	case MSR_IA32_VMX_PROCBASED_CTLS2:
-		lowp = &vmx->nested.msrs.secondary_ctls_low;
-		highp = &vmx->nested.msrs.secondary_ctls_high;
+		*low = &msrs->secondary_ctls_low;
+		*high = &msrs->secondary_ctls_high;
 		break;
 	default:
 		BUG();
 	}
+}
+
+static int
+vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
+{
+	u32 *lowp, *highp;
+	u64 supported;
+
+	vmx_get_control_msr(&vmcs_config.nested, msr_index, &lowp, &highp);
 
 	supported = vmx_control_msr(*lowp, *highp);
 
@@ -1124,6 +1131,7 @@
 	if (!is_bitwise_subset(supported, data, GENMASK_ULL(63, 32)))
 		return -EINVAL;
 
+	vmx_get_control_msr(&vmx->nested.msrs, msr_index, &lowp, &highp);
 	*lowp = data;
 	*highp = data >> 32;
 	return 0;
@@ -1137,10 +1145,8 @@
 		BIT_ULL(28) | BIT_ULL(29) | BIT_ULL(30) |
 		/* reserved */
 		GENMASK_ULL(13, 9) | BIT_ULL(31);
-	u64 vmx_misc;
-
-	vmx_misc = vmx_control_msr(vmx->nested.msrs.misc_low,
-				   vmx->nested.msrs.misc_high);
+	u64 vmx_misc = vmx_control_msr(vmcs_config.nested.misc_low,
+				       vmcs_config.nested.misc_high);
 
 	if (!is_bitwise_subset(vmx_misc, data, feature_and_reserved_bits))
 		return -EINVAL;
@@ -1168,10 +1174,8 @@
 
 static int vmx_restore_vmx_ept_vpid_cap(struct vcpu_vmx *vmx, u64 data)
 {
-	u64 vmx_ept_vpid_cap;
-
-	vmx_ept_vpid_cap = vmx_control_msr(vmx->nested.msrs.ept_caps,
-					   vmx->nested.msrs.vpid_caps);
+	u64 vmx_ept_vpid_cap = vmx_control_msr(vmcs_config.nested.ept_caps,
+					       vmcs_config.nested.vpid_caps);
 
 	/* Every bit is either reserved or a feature bit. */
 	if (!is_bitwise_subset(vmx_ept_vpid_cap, data, -1ULL))
@@ -1182,20 +1186,21 @@
 	return 0;
 }
 
-static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
+static u64 *vmx_get_fixed0_msr(struct nested_vmx_msrs *msrs, u32 msr_index)
 {
-	u64 *msr;
-
 	switch (msr_index) {
 	case MSR_IA32_VMX_CR0_FIXED0:
-		msr = &vmx->nested.msrs.cr0_fixed0;
-		break;
+		return &msrs->cr0_fixed0;
 	case MSR_IA32_VMX_CR4_FIXED0:
-		msr = &vmx->nested.msrs.cr4_fixed0;
-		break;
+		return &msrs->cr4_fixed0;
 	default:
 		BUG();
 	}
+}
+
+static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
+{
+	const u64 *msr = vmx_get_fixed0_msr(&vmcs_config.nested, msr_index);
 
 	/*
 	 * 1 bits (which indicates bits which "must-be-1" during VMX operation)
@@ -1204,7 +1209,7 @@
 	if (!is_bitwise_subset(data, *msr, -1ULL))
 		return -EINVAL;
 
-	*msr = data;
+	*vmx_get_fixed0_msr(&vmx->nested.msrs, msr_index) = data;
 	return 0;
 }
 
@@ -1265,7 +1270,7 @@
 		vmx->nested.msrs.vmcs_enum = data;
 		return 0;
 	case MSR_IA32_VMX_VMFUNC:
-		if (data & ~vmx->nested.msrs.vmfunc_controls)
+		if (data & ~vmcs_config.nested.vmfunc_controls)
 			return -EINVAL;
 		vmx->nested.msrs.vmfunc_controls = data;
 		return 0;
@@ -1828,7 +1833,8 @@
 	if (!nested_enlightened_vmentry(vcpu, &evmcs_gpa))
 		return 1;
 
-	if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
+	if (unlikely(!vmx->nested.hv_evmcs ||
+		     evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
 		if (!vmx->nested.hv_evmcs)
 			vmx->nested.current_vmptr = -1ull;
 
@@ -2056,20 +2062,19 @@
 			 ~PIN_BASED_VMX_PREEMPTION_TIMER);
 
 	/* Posted interrupts setting is only taken from vmcs12.  */
-	if (nested_cpu_has_posted_intr(vmcs12)) {
+	vmx->nested.pi_pending = false;
+	if (nested_cpu_has_posted_intr(vmcs12))
 		vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv;
-		vmx->nested.pi_pending = false;
-	} else {
+	else
 		exec_control &= ~PIN_BASED_POSTED_INTR;
-	}
 	pin_controls_set(vmx, exec_control);
 
 	/*
 	 * EXEC CONTROLS
 	 */
 	exec_control = vmx_exec_control(vmx); /* L0's desires */
-	exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
-	exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
+	exec_control &= ~CPU_BASED_INTR_WINDOW_EXITING;
+	exec_control &= ~CPU_BASED_NMI_WINDOW_EXITING;
 	exec_control &= ~CPU_BASED_TPR_SHADOW;
 	exec_control |= vmcs12->cpu_based_vm_exec_control;
 
@@ -2230,6 +2235,8 @@
 		vmcs_writel(GUEST_TR_BASE, vmcs12->guest_tr_base);
 		vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base);
 		vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base);
+
+		vmx->segment_cache.bitmask = 0;
 	}
 
 	if (!hv_evmcs || !(hv_evmcs->hv_clean_fields &
@@ -2418,6 +2425,16 @@
 				entry_failure_code))
 		return -EINVAL;
 
+	/*
+	 * Immediately write vmcs02.GUEST_CR3.  It will be propagated to vmcs12
+	 * on nested VM-Exit, which can occur without actually running L2 and
+	 * thus without hitting vmx_set_cr3(), e.g. if L1 is entering L2 with
+	 * vmcs12.GUEST_ACTIVITYSTATE=HLT, in which case KVM will intercept the
+	 * transition to HLT instead of running L2.
+	 */
+	if (enable_ept)
+		vmcs_writel(GUEST_CR3, vmcs12->guest_cr3);
+
 	/* Late preparation of GUEST_PDPTRs now that EFER and CRs are set. */
 	if (load_guest_pdptrs_vmcs12 && nested_cpu_has_ept(vmcs12) &&
 	    is_pae_paging(vcpu)) {
@@ -2442,7 +2459,7 @@
 		return -EINVAL;
 
 	if (CC(!nested_cpu_has_virtual_nmis(vmcs12) &&
-	       nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING)))
+	       nested_cpu_has(vmcs12, CPU_BASED_NMI_WINDOW_EXITING)))
 		return -EINVAL;
 
 	return 0;
@@ -2762,7 +2779,7 @@
 					struct vmcs12 *vmcs12,
 					u32 *exit_qual)
 {
-	bool ia32e;
+	bool ia32e = !!(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE);
 
 	*exit_qual = ENTRY_FAIL_DEFAULT;
 
@@ -2779,6 +2796,13 @@
 		return -EINVAL;
 	}
 
+	if (CC((vmcs12->guest_cr0 & (X86_CR0_PG | X86_CR0_PE)) == X86_CR0_PG))
+		return -EINVAL;
+
+	if (CC(ia32e && !(vmcs12->guest_cr4 & X86_CR4_PAE)) ||
+	    CC(ia32e && !(vmcs12->guest_cr0 & X86_CR0_PG)))
+		return -EINVAL;
+
 	/*
 	 * If the load IA32_EFER VM-entry control is 1, the following checks
 	 * are performed on the field for the IA32_EFER MSR:
@@ -2790,7 +2814,6 @@
 	 */
 	if (to_vmx(vcpu)->nested.nested_run_pending &&
 	    (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) {
-		ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
 		if (CC(!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer)) ||
 		    CC(ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA)) ||
 		    CC(((vmcs12->guest_cr0 & X86_CR0_PG) &&
@@ -2847,35 +2870,8 @@
 		vmx->loaded_vmcs->host_state.cr4 = cr4;
 	}
 
-	asm(
-		"sub $%c[wordsize], %%" _ASM_SP "\n\t" /* temporarily adjust RSP for CALL */
-		"cmp %%" _ASM_SP ", %c[host_state_rsp](%[loaded_vmcs]) \n\t"
-		"je 1f \n\t"
-		__ex("vmwrite %%" _ASM_SP ", %[HOST_RSP]") "\n\t"
-		"mov %%" _ASM_SP ", %c[host_state_rsp](%[loaded_vmcs]) \n\t"
-		"1: \n\t"
-		"add $%c[wordsize], %%" _ASM_SP "\n\t" /* un-adjust RSP */
-
-		/* Check if vmlaunch or vmresume is needed */
-		"cmpb $0, %c[launched](%[loaded_vmcs])\n\t"
-
-		/*
-		 * VMLAUNCH and VMRESUME clear RFLAGS.{CF,ZF} on VM-Exit, set
-		 * RFLAGS.CF on VM-Fail Invalid and set RFLAGS.ZF on VM-Fail
-		 * Valid.  vmx_vmenter() directly "returns" RFLAGS, and so the
-		 * results of VM-Enter is captured via CC_{SET,OUT} to vm_fail.
-		 */
-		"call vmx_vmenter\n\t"
-
-		CC_SET(be)
-	      : ASM_CALL_CONSTRAINT, CC_OUT(be) (vm_fail)
-	      :	[HOST_RSP]"r"((unsigned long)HOST_RSP),
-		[loaded_vmcs]"r"(vmx->loaded_vmcs),
-		[launched]"i"(offsetof(struct loaded_vmcs, launched)),
-		[host_state_rsp]"i"(offsetof(struct loaded_vmcs, host_state.rsp)),
-		[wordsize]"i"(sizeof(ulong))
-	      : "memory"
-	);
+	vm_fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
+				 __vmx_vcpu_run_flags(vmx));
 
 	if (vmx->msr_autoload.host.nr)
 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
@@ -3049,14 +3045,16 @@
 	u32 exit_qual;
 
 	evaluate_pending_interrupts = exec_controls_get(vmx) &
-		(CPU_BASED_VIRTUAL_INTR_PENDING | CPU_BASED_VIRTUAL_NMI_PENDING);
+		(CPU_BASED_INTR_WINDOW_EXITING | CPU_BASED_NMI_WINDOW_EXITING);
 	if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu))
 		evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu);
 
-	if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
+	if (!vmx->nested.nested_run_pending ||
+	    !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
 		vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
 	if (kvm_mpx_supported() &&
-		!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))
+	    (!vmx->nested.nested_run_pending ||
+	     !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
 		vmx->nested.vmcs01_guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
 
 	/*
@@ -3083,8 +3081,10 @@
 	prepare_vmcs02_early(vmx, vmcs12);
 
 	if (from_vmentry) {
-		if (unlikely(!nested_get_vmcs12_pages(vcpu)))
+		if (unlikely(!nested_get_vmcs12_pages(vcpu))) {
+			vmx_switch_vmcs(vcpu, &vmx->vmcs01);
 			return NVMX_VMENTRY_KVM_INTERNAL_ERROR;
+		}
 
 		if (nested_vmx_check_vmentry_hw(vcpu)) {
 			vmx_switch_vmcs(vcpu, &vmx->vmcs01);
@@ -3096,7 +3096,7 @@
 	}
 
 	enter_guest_mode(vcpu);
-	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
+	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
 		vcpu->arch.tsc_offset += vmcs12->tsc_offset;
 
 	if (prepare_vmcs02(vcpu, vmcs12, &exit_qual))
@@ -3160,7 +3160,7 @@
 	 * 26.7 "VM-entry failures during or after loading guest state".
 	 */
 vmentry_fail_vmexit_guest_mode:
-	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
+	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
 		vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
 	leave_guest_mode(vcpu);
 
@@ -3273,8 +3273,8 @@
 	 */
 	if ((vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) &&
 	    !(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK) &&
-	    !(vmcs12->cpu_based_vm_exec_control & CPU_BASED_VIRTUAL_NMI_PENDING) &&
-	    !((vmcs12->cpu_based_vm_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING) &&
+	    !(vmcs12->cpu_based_vm_exec_control & CPU_BASED_NMI_WINDOW_EXITING) &&
+	    !((vmcs12->cpu_based_vm_exec_control & CPU_BASED_INTR_WINDOW_EXITING) &&
 	      (vmcs12->guest_rflags & X86_EFLAGS_IF))) {
 		vmx->nested.nested_run_pending = 0;
 		return kvm_vcpu_halt(vcpu);
@@ -3433,7 +3433,16 @@
 	u32 intr_info = nr | INTR_INFO_VALID_MASK;
 
 	if (vcpu->arch.exception.has_error_code) {
-		vmcs12->vm_exit_intr_error_code = vcpu->arch.exception.error_code;
+		/*
+		 * Intel CPUs do not generate error codes with bits 31:16 set,
+		 * and more importantly VMX disallows setting bits 31:16 in the
+		 * injected error code for VM-Entry.  Drop the bits to mimic
+		 * hardware and avoid inducing failure on nested VM-Entry if L1
+		 * chooses to inject the exception back to L2.  AMD CPUs _do_
+		 * generate "full" 32-bit error codes, so KVM allows userspace
+		 * to inject exception error codes with bits 31:16 set.
+		 */
+		vmcs12->vm_exit_intr_error_code = (u16)vcpu->arch.exception.error_code;
 		intr_info |= INTR_INFO_DELIVER_CODE_MASK;
 	}
 
@@ -3449,7 +3458,7 @@
 	nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, intr_info, exit_qual);
 }
 
-static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
+static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	unsigned long exit_qual;
@@ -3496,8 +3505,7 @@
 		return 0;
 	}
 
-	if ((kvm_cpu_has_interrupt(vcpu) || external_intr) &&
-	    nested_exit_on_intr(vcpu)) {
+	if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(vcpu)) {
 		if (block_nested_events)
 			return -EBUSY;
 		nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
@@ -3733,12 +3741,12 @@
 	/* update exit information fields: */
 	vmcs12->vm_exit_reason = exit_reason;
 	vmcs12->exit_qualification = exit_qualification;
-	vmcs12->vm_exit_intr_info = exit_intr_info;
-
-	vmcs12->idt_vectoring_info_field = 0;
-	vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
-	vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 
+	/*
+	 * On VM-Exit due to a failed VM-Entry, the VMCS isn't marked launched
+	 * and only EXIT_REASON and EXIT_QUALIFICATION are updated, all other
+	 * exit info fields are unmodified.
+	 */
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
 		vmcs12->launch_state = 1;
 
@@ -3750,8 +3758,13 @@
 		 * Transfer the event that L0 or L1 may wanted to inject into
 		 * L2 to IDT_VECTORING_INFO_FIELD.
 		 */
+		vmcs12->idt_vectoring_info_field = 0;
 		vmcs12_save_pending_event(vcpu, vmcs12);
 
+		vmcs12->vm_exit_intr_info = exit_intr_info;
+		vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+		vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+
 		/*
 		 * According to spec, there's no need to store the guest's
 		 * MSRs if the exit is due to a VM-entry failure that occurs
@@ -3764,14 +3777,6 @@
 			nested_vmx_abort(vcpu,
 					 VMX_ABORT_SAVE_GUEST_MSR_FAIL);
 	}
-
-	/*
-	 * Drop what we picked up for L2 via vmx_complete_interrupts. It is
-	 * preserved above and would only end up incorrectly in L1.
-	 */
-	vcpu->arch.nmi_injected = false;
-	kvm_clear_exception_queue(vcpu);
-	kvm_clear_interrupt_queue(vcpu);
 }
 
 /*
@@ -3913,6 +3918,10 @@
 	};
 	vmx_set_segment(vcpu, &seg, VCPU_SREG_TR);
 
+	memset(&seg, 0, sizeof(seg));
+	seg.unusable = 1;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_LDTR);
+
 	kvm_set_dr(vcpu, 7, 0x400);
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 
@@ -4074,7 +4083,7 @@
 	if (nested_cpu_has_preemption_timer(vmcs12))
 		hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
 
-	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
+	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
 		vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
 
 	if (likely(!vmx->fail)) {
@@ -4106,8 +4115,30 @@
 		WARN_ON_ONCE(nested_early_check);
 	}
 
+	/*
+	 * Drop events/exceptions that were queued for re-injection to L2
+	 * (picked up via vmx_complete_interrupts()), as well as exceptions
+	 * that were pending for L2.  Note, this must NOT be hoisted above
+	 * prepare_vmcs12(), events/exceptions queued for re-injection need to
+	 * be captured in vmcs12 (see vmcs12_save_pending_event()).
+	 */
+	vcpu->arch.nmi_injected = false;
+	kvm_clear_exception_queue(vcpu);
+	kvm_clear_interrupt_queue(vcpu);
+
 	vmx_switch_vmcs(vcpu, &vmx->vmcs01);
 
+	/*
+	 * If IBRS is advertised to the vCPU, KVM must flush the indirect
+	 * branch predictors when transitioning from L2 to L1, as L1 expects
+	 * hardware (KVM in this case) to provide separate predictor modes.
+	 * Bare metal isolates VMX root (host) from VMX non-root (guest), but
+	 * doesn't isolate different VMCSs, i.e. in this case, doesn't provide
+	 * separate modes for L2 vs L1.
+	 */
+	if (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL))
+		indirect_branch_prediction_barrier();
+
 	/* Update any VMCS fields that might have changed while L2 ran */
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
@@ -4147,17 +4178,8 @@
 	vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
 	if (likely(!vmx->fail)) {
-		/*
-		 * TODO: SDM says that with acknowledge interrupt on
-		 * exit, bit 31 of the VM-exit interrupt information
-		 * (valid interrupt) is always set to 1 on
-		 * EXIT_REASON_EXTERNAL_INTERRUPT, so we shouldn't
-		 * need kvm_cpu_has_interrupt().  See the commit
-		 * message for details.
-		 */
-		if (nested_exit_intr_ack_set(vcpu) &&
-		    exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT &&
-		    kvm_cpu_has_interrupt(vcpu)) {
+		if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT &&
+		    nested_exit_intr_ack_set(vcpu)) {
 			int irq = kvm_cpu_get_interrupt(vcpu);
 			WARN_ON(irq < 0);
 			vmcs12->vm_exit_intr_info = irq |
@@ -4599,32 +4621,28 @@
 {
 	unsigned long field;
 	u64 field_value;
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 	u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 	int len;
 	gva_t gva = 0;
-	struct vmcs12 *vmcs12;
+	struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
+						    : get_vmcs12(vcpu);
 	struct x86_exception e;
 	short offset;
 
 	if (!nested_vmx_check_permission(vcpu))
 		return 1;
 
-	if (to_vmx(vcpu)->nested.current_vmptr == -1ull)
+	/*
+	 * In VMX non-root operation, when the VMCS-link pointer is -1ull,
+	 * any VMREAD sets the ALU flags for VMfailInvalid.
+	 */
+	if (vmx->nested.current_vmptr == -1ull ||
+	    (is_guest_mode(vcpu) &&
+	     get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
 		return nested_vmx_failInvalid(vcpu);
 
-	if (!is_guest_mode(vcpu))
-		vmcs12 = get_vmcs12(vcpu);
-	else {
-		/*
-		 * When vmcs->vmcs_link_pointer is -1ull, any VMREAD
-		 * to shadowed-field sets the ALU flags for VMfailInvalid.
-		 */
-		if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
-			return nested_vmx_failInvalid(vcpu);
-		vmcs12 = get_shadow_vmcs12(vcpu);
-	}
-
 	/* Decode instruction info and find the field to read */
 	field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
 
@@ -4653,8 +4671,10 @@
 				vmx_instruction_info, true, len, &gva))
 			return 1;
 		/* _system ok, nested_vmx_check_permission has verified cpl=0 */
-		if (kvm_write_guest_virt_system(vcpu, gva, &field_value, len, &e))
+		if (kvm_write_guest_virt_system(vcpu, gva, &field_value, len, &e)) {
 			kvm_inject_page_fault(vcpu, &e);
+			return 1;
+		}
 	}
 
 	return nested_vmx_succeed(vcpu);
@@ -4701,13 +4721,20 @@
 	 */
 	u64 field_value = 0;
 	struct x86_exception e;
-	struct vmcs12 *vmcs12;
+	struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
+						    : get_vmcs12(vcpu);
 	short offset;
 
 	if (!nested_vmx_check_permission(vcpu))
 		return 1;
 
-	if (vmx->nested.current_vmptr == -1ull)
+	/*
+	 * In VMX non-root operation, when the VMCS-link pointer is -1ull,
+	 * any VMWRITE sets the ALU flags for VMfailInvalid.
+	 */
+	if (vmx->nested.current_vmptr == -1ull ||
+	    (is_guest_mode(vcpu) &&
+	     get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
 		return nested_vmx_failInvalid(vcpu);
 
 	if (vmx_instruction_info & (1u << 10))
@@ -4726,6 +4753,12 @@
 
 
 	field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
+
+	offset = vmcs_field_to_offset(field);
+	if (offset < 0)
+		return nested_vmx_failValid(vcpu,
+			VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+
 	/*
 	 * If the vCPU supports "VMWRITE to any supported field in the
 	 * VMCS," then the "read-only" fields are actually read/write.
@@ -4735,29 +4768,12 @@
 		return nested_vmx_failValid(vcpu,
 			VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
 
-	if (!is_guest_mode(vcpu)) {
-		vmcs12 = get_vmcs12(vcpu);
-
-		/*
-		 * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
-		 * vmcs12, else we may crush a field or consume a stale value.
-		 */
-		if (!is_shadow_field_rw(field))
-			copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
-	} else {
-		/*
-		 * When vmcs->vmcs_link_pointer is -1ull, any VMWRITE
-		 * to shadowed-field sets the ALU flags for VMfailInvalid.
-		 */
-		if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
-			return nested_vmx_failInvalid(vcpu);
-		vmcs12 = get_shadow_vmcs12(vcpu);
-	}
-
-	offset = vmcs_field_to_offset(field);
-	if (offset < 0)
-		return nested_vmx_failValid(vcpu,
-			VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+	/*
+	 * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
+	 * vmcs12, else we may crush a field or consume a stale value.
+	 */
+	if (!is_guest_mode(vcpu) && !is_shadow_field_rw(field))
+		copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
 
 	/*
 	 * Some Intel CPUs intentionally drop the reserved bits of the AR byte
@@ -5100,7 +5116,7 @@
 	}
 
 	vmcs12 = get_vmcs12(vcpu);
-	if ((vmcs12->vm_function_control & (1 << function)) == 0)
+	if (!(vmcs12->vm_function_control & BIT_ULL(function)))
 		goto fail;
 
 	switch (function) {
@@ -5120,24 +5136,17 @@
 	return 1;
 }
 
-
-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;
 
@@ -5164,6 +5173,24 @@
 	return false;
 }
 
+static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
+				       struct vmcs12 *vmcs12)
+{
+	unsigned long exit_qualification;
+	unsigned short port;
+	int size;
+
+	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);
+}
+
 /*
  * Return 1 if we should exit from L2 to L1 to handle an MSR access access,
  * rather than handle it ourselves in L0. I.e., check whether L1 expressed
@@ -5298,7 +5325,7 @@
 
 	/* Decode instruction info and find the field to access */
 	vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
-	field = kvm_register_read(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
+	field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
 
 	/* Out-of-range fields always cause a VM exit from L2 to L1 */
 	if (field >> 15)
@@ -5351,7 +5378,7 @@
 				vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
 				KVM_ISA_VMX);
 
-	switch (exit_reason) {
+	switch ((u16)exit_reason) {
 	case EXIT_REASON_EXCEPTION_NMI:
 		if (is_nmi(intr_info))
 			return false;
@@ -5370,10 +5397,10 @@
 		return false;
 	case EXIT_REASON_TRIPLE_FAULT:
 		return true;
-	case EXIT_REASON_PENDING_INTERRUPT:
-		return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_INTR_PENDING);
+	case EXIT_REASON_INTERRUPT_WINDOW:
+		return nested_cpu_has(vmcs12, CPU_BASED_INTR_WINDOW_EXITING);
 	case EXIT_REASON_NMI_WINDOW:
-		return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING);
+		return nested_cpu_has(vmcs12, CPU_BASED_NMI_WINDOW_EXITING);
 	case EXIT_REASON_TASK_SWITCH:
 		return true;
 	case EXIT_REASON_CPUID:
@@ -5569,11 +5596,14 @@
 	if (is_guest_mode(vcpu)) {
 		sync_vmcs02_to_vmcs12(vcpu, vmcs12);
 		sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
-	} else if (!vmx->nested.need_vmcs12_to_shadow_sync) {
-		if (vmx->nested.hv_evmcs)
-			copy_enlightened_to_vmcs12(vmx);
-		else if (enable_shadow_vmcs)
-			copy_shadow_to_vmcs12(vmx);
+	} else  {
+		copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
+		if (!vmx->nested.need_vmcs12_to_shadow_sync) {
+			if (vmx->nested.hv_evmcs)
+				copy_enlightened_to_vmcs12(vmx);
+			else if (enable_shadow_vmcs)
+				copy_shadow_to_vmcs12(vmx);
+		}
 	}
 
 	BUILD_BUG_ON(sizeof(user_vmx_nested_state->vmcs12) < VMCS12_SIZE);
@@ -5784,8 +5814,7 @@
  * bit in the high half is on if the corresponding bit in the control field
  * may be on. See also vmx_control_verify().
  */
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-				bool apicv)
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)
 {
 	/*
 	 * Note that as a general rule, the high half of the MSRs (bits in
@@ -5812,7 +5841,7 @@
 		PIN_BASED_EXT_INTR_MASK |
 		PIN_BASED_NMI_EXITING |
 		PIN_BASED_VIRTUAL_NMIS |
-		(apicv ? PIN_BASED_POSTED_INTR : 0);
+		(enable_apicv ? PIN_BASED_POSTED_INTR : 0);
 	msrs->pinbased_ctls_high |=
 		PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
 		PIN_BASED_VMX_PREEMPTION_TIMER;
@@ -5861,8 +5890,8 @@
 	msrs->procbased_ctls_low =
 		CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR;
 	msrs->procbased_ctls_high &=
-		CPU_BASED_VIRTUAL_INTR_PENDING |
-		CPU_BASED_VIRTUAL_NMI_PENDING | CPU_BASED_USE_TSC_OFFSETING |
+		CPU_BASED_INTR_WINDOW_EXITING |
+		CPU_BASED_NMI_WINDOW_EXITING | CPU_BASED_USE_TSC_OFFSETTING |
 		CPU_BASED_HLT_EXITING | CPU_BASED_INVLPG_EXITING |
 		CPU_BASED_MWAIT_EXITING | CPU_BASED_CR3_LOAD_EXITING |
 		CPU_BASED_CR3_STORE_EXITING |
@@ -5908,7 +5937,8 @@
 		SECONDARY_EXEC_RDRAND_EXITING |
 		SECONDARY_EXEC_ENABLE_INVPCID |
 		SECONDARY_EXEC_RDSEED_EXITING |
-		SECONDARY_EXEC_XSAVES;
+		SECONDARY_EXEC_XSAVES |
+		SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
 
 	/*
 	 * We can emulate "VMCS shadowing," even if the hardware
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/nested.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/nested.h
@@ -17,8 +17,7 @@
 };
 
 void vmx_leave_nested(struct kvm_vcpu *vcpu);
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-				bool apicv);
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps);
 void nested_vmx_hardware_unsetup(void);
 __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
 void nested_vmx_vcpu_setup(void);
@@ -33,6 +32,8 @@
 int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata);
 int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
 			u32 vmx_instruction_info, bool wr, int len, gva_t *ret);
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+				 int size);
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 {
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/ops.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/ops.h
@@ -13,6 +13,8 @@
 #define __ex(x) __kvm_handle_fault_on_reboot(x)
 
 asmlinkage void vmread_error(unsigned long field, bool fault);
+__attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field,
+							 bool fault);
 void vmwrite_error(unsigned long field, unsigned long value);
 void vmclear_error(struct vmcs *vmcs, u64 phys_addr);
 void vmptrld_error(struct vmcs *vmcs, u64 phys_addr);
@@ -70,15 +72,28 @@
 	asm volatile("1: vmread %2, %1\n\t"
 		     ".byte 0x3e\n\t" /* branch taken hint */
 		     "ja 3f\n\t"
-		     "mov %2, %%" _ASM_ARG1 "\n\t"
-		     "xor %%" _ASM_ARG2 ", %%" _ASM_ARG2 "\n\t"
-		     "2: call vmread_error\n\t"
-		     "xor %k1, %k1\n\t"
+
+		     /*
+		      * VMREAD failed.  Push '0' for @fault, push the failing
+		      * @field, and bounce through the trampoline to preserve
+		      * volatile registers.
+		      */
+		     "push $0\n\t"
+		     "push %2\n\t"
+		     "2:call vmread_error_trampoline\n\t"
+
+		     /*
+		      * Unwind the stack.  Note, the trampoline zeros out the
+		      * memory for @fault so that the result is '0' on error.
+		      */
+		     "pop %2\n\t"
+		     "pop %1\n\t"
 		     "3:\n\t"
 
+		     /* VMREAD faulted.  As above, except push '1' for @fault. */
 		     ".pushsection .fixup, \"ax\"\n\t"
-		     "4: mov %2, %%" _ASM_ARG1 "\n\t"
-		     "mov $1, %%" _ASM_ARG2 "\n\t"
+		     "4: push $1\n\t"
+		     "push %2\n\t"
 		     "jmp 2b\n\t"
 		     ".popsection\n\t"
 		     _ASM_EXTABLE(1b, 4b)
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/pmu_intel.c
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/pmu_intel.c
@@ -26,7 +26,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 */
@@ -64,10 +64,11 @@
 		reprogram_counter(pmu, bit);
 }
 
-static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
-				      u8 event_select,
-				      u8 unit_mask)
+static unsigned int intel_pmc_perf_hw_id(struct kvm_pmc *pmc)
 {
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+	u8 event_select = pmc->eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
+	u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
@@ -84,10 +85,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 comparing it with globl_ctrl bits. */
@@ -128,16 +133,20 @@
 	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;
 	*mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP];
-
-	return &counters[idx];
+	return &counters[array_index_nospec(idx, num_counters)];
 }
 
 static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
@@ -288,7 +297,9 @@
 
 	pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
 					 x86_pmu.num_counters_gp);
+	eax.split.bit_width = min_t(int, eax.split.bit_width, x86_pmu.bit_width_gp);
 	pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
+	eax.split.mask_length = min_t(int, eax.split.mask_length, x86_pmu.events_mask_len);
 	pmu->available_event_types = ~entry->ebx &
 					((1ull << eax.split.mask_length) - 1);
 
@@ -298,6 +309,8 @@
 		pmu->nr_arch_fixed_counters =
 			min_t(int, edx.split.num_counters_fixed,
 			      x86_pmu.num_counters_fixed);
+		edx.split.bit_width_fixed = min_t(int,
+			edx.split.bit_width_fixed, x86_pmu.bit_width_fixed);
 		pmu->counter_bitmask[KVM_PMC_FIXED] =
 			((u64)1 << edx.split.bit_width_fixed) - 1;
 	}
@@ -362,7 +375,7 @@
 }
 
 struct kvm_pmu_ops intel_pmu_ops = {
-	.find_arch_event = intel_find_arch_event,
+	.pmc_perf_hw_id = intel_pmc_perf_hw_id,
 	.find_fixed_event = intel_find_fixed_event,
 	.pmc_is_enabled = intel_pmc_is_enabled,
 	.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/run_flags.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/run_flags.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_VMX_RUN_FLAGS_H
+#define __KVM_X86_VMX_RUN_FLAGS_H
+
+#define VMX_RUN_VMRESUME	(1 << 0)
+#define VMX_RUN_SAVE_SPEC_CTRL	(1 << 1)
+
+#endif /* __KVM_X86_VMX_RUN_FLAGS_H */
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/vmenter.S
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/vmenter.S
@@ -4,6 +4,7 @@
 #include <asm/bitsperlong.h>
 #include <asm/kvm_vcpu_regs.h>
 #include <asm/nospec-branch.h>
+#include "run_flags.h"
 
 #define WORD_SIZE (BITS_PER_LONG / 8)
 
@@ -30,73 +31,11 @@
 	.text
 
 /**
- * vmx_vmenter - VM-Enter the current loaded VMCS
- *
- * %RFLAGS.ZF:	!VMCS.LAUNCHED, i.e. controls VMLAUNCH vs. VMRESUME
- *
- * Returns:
- *	%RFLAGS.CF is set on VM-Fail Invalid
- *	%RFLAGS.ZF is set on VM-Fail Valid
- *	%RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * Note that VMRESUME/VMLAUNCH fall-through and return directly if
- * they VM-Fail, whereas a successful VM-Enter + VM-Exit will jump
- * to vmx_vmexit.
- */
-ENTRY(vmx_vmenter)
-	/* EFLAGS.ZF is set if VMCS.LAUNCHED == 0 */
-	je 2f
-
-1:	vmresume
-	ret
-
-2:	vmlaunch
-	ret
-
-3:	cmpb $0, kvm_rebooting
-	je 4f
-	ret
-4:	ud2
-
-	.pushsection .fixup, "ax"
-5:	jmp 3b
-	.popsection
-
-	_ASM_EXTABLE(1b, 5b)
-	_ASM_EXTABLE(2b, 5b)
-
-ENDPROC(vmx_vmenter)
-
-/**
- * vmx_vmexit - Handle a VMX VM-Exit
- *
- * Returns:
- *	%RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * This is vmx_vmenter's partner in crime.  On a VM-Exit, control will jump
- * here after hardware loads the host's state, i.e. this is the destination
- * referred to by VMCS.HOST_RIP.
- */
-ENTRY(vmx_vmexit)
-#ifdef CONFIG_RETPOLINE
-	ALTERNATIVE "jmp .Lvmexit_skip_rsb", "", X86_FEATURE_RETPOLINE
-	/* Preserve guest's RAX, it's used to stuff the RSB. */
-	push %_ASM_AX
-
-	/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
-	FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
-
-	pop %_ASM_AX
-.Lvmexit_skip_rsb:
-#endif
-	ret
-ENDPROC(vmx_vmexit)
-
-/**
  * __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
- * @vmx:	struct vcpu_vmx * (forwarded to vmx_update_host_rsp)
+ * @vmx:	struct vcpu_vmx *
  * @regs:	unsigned long * (to guest registers)
- * @launched:	%true if the VMCS has been launched
+ * @flags:	VMX_RUN_VMRESUME:	use VMRESUME instead of VMLAUNCH
+ *		VMX_RUN_SAVE_SPEC_CTRL: save guest SPEC_CTRL into vmx->spec_ctrl
  *
  * Returns:
  *	0 on VM-Exit, 1 on VM-Fail
@@ -115,24 +54,29 @@
 #endif
 	push %_ASM_BX
 
+	/* Save @vmx for SPEC_CTRL handling */
+	push %_ASM_ARG1
+
+	/* Save @flags for SPEC_CTRL handling */
+	push %_ASM_ARG3
+
 	/*
 	 * Save @regs, _ASM_ARG2 may be modified by vmx_update_host_rsp() and
 	 * @regs is needed after VM-Exit to save the guest's register values.
 	 */
 	push %_ASM_ARG2
 
-	/* Copy @launched to BL, _ASM_ARG3 is volatile. */
+	/* Copy @flags to BL, _ASM_ARG3 is volatile. */
 	mov %_ASM_ARG3B, %bl
 
-	/* Adjust RSP to account for the CALL to vmx_vmenter(). */
-	lea -WORD_SIZE(%_ASM_SP), %_ASM_ARG2
+	lea (%_ASM_SP), %_ASM_ARG2
 	call vmx_update_host_rsp
 
 	/* Load @regs to RAX. */
 	mov (%_ASM_SP), %_ASM_AX
 
 	/* Check if vmlaunch or vmresume is needed */
-	cmpb $0, %bl
+	testb $VMX_RUN_VMRESUME, %bl
 
 	/* Load guest registers.  Don't clobber flags. */
 	mov VCPU_RBX(%_ASM_AX), %_ASM_BX
@@ -154,11 +98,25 @@
 	/* Load guest RAX.  This kills the @regs pointer! */
 	mov VCPU_RAX(%_ASM_AX), %_ASM_AX
 
-	/* Enter guest mode */
-	call vmx_vmenter
+	/* Check EFLAGS.ZF from 'testb' above */
+	jz .Lvmlaunch
+
+/*
+ * If VMRESUME/VMLAUNCH and corresponding vmexit succeed, execution resumes at
+ * the 'vmx_vmexit' label below.
+ */
+.Lvmresume:
+	vmresume
+	jmp .Lvmfail
+
+.Lvmlaunch:
+	vmlaunch
+	jmp .Lvmfail
+
+	_ASM_EXTABLE(.Lvmresume, .Lfixup)
+	_ASM_EXTABLE(.Lvmlaunch, .Lfixup)
 
-	/* Jump on VM-Fail. */
-	jbe 2f
+SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
 
 	/* Temporarily save guest's RAX. */
 	push %_ASM_AX
@@ -185,19 +143,21 @@
 	mov %r15, VCPU_R15(%_ASM_AX)
 #endif
 
-	/* Clear RAX to indicate VM-Exit (as opposed to VM-Fail). */
-	xor %eax, %eax
+	/* Clear return value to indicate VM-Exit (as opposed to VM-Fail). */
+	xor %ebx, %ebx
 
+.Lclear_regs:
 	/*
-	 * Clear all general purpose registers except RSP and RAX to prevent
+	 * Clear all general purpose registers except RSP and RBX to prevent
 	 * speculative use of the guest's values, even those that are reloaded
 	 * via the stack.  In theory, an L1 cache miss when restoring registers
 	 * could lead to speculative execution with the guest's values.
 	 * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
 	 * free.  RSP and RAX are exempt as RSP is restored by hardware during
-	 * VM-Exit and RAX is explicitly loaded with 0 or 1 to return VM-Fail.
+	 * VM-Exit and RBX is explicitly loaded with 0 or 1 to hold the return
+	 * value.
 	 */
-1:	xor %ebx, %ebx
+	xor %eax, %eax
 	xor %ecx, %ecx
 	xor %edx, %edx
 	xor %esi, %esi
@@ -216,8 +176,34 @@
 
 	/* "POP" @regs. */
 	add $WORD_SIZE, %_ASM_SP
-	pop %_ASM_BX
 
+	/*
+	 * 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.
+         */
+
+	FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT,\
+			   X86_FEATURE_RSB_VMEXIT_LITE
+
+
+	pop %_ASM_ARG2	/* @flags */
+	pop %_ASM_ARG1	/* @vmx */
+
+	call vmx_spec_ctrl_restore_host
+
+	CLEAR_BRANCH_HISTORY_VMEXIT
+
+	/* Put return value in AX */
+	mov %_ASM_BX, %_ASM_AX
+
+	pop %_ASM_BX
 #ifdef CONFIG_X86_64
 	pop %r12
 	pop %r13
@@ -230,7 +216,74 @@
 	pop %_ASM_BP
 	ret
 
-	/* VM-Fail.  Out-of-line to avoid a taken Jcc after VM-Exit. */
-2:	mov $1, %eax
-	jmp 1b
+.Lfixup:
+	cmpb $0, kvm_rebooting
+	jne .Lvmfail
+	ud2
+.Lvmfail:
+	/* VM-Fail: set return value to 1 */
+	mov $1, %_ASM_BX
+	jmp .Lclear_regs
+
 ENDPROC(__vmx_vcpu_run)
+
+
+.section .text, "ax"
+
+/**
+ * vmread_error_trampoline - Trampoline from inline asm to vmread_error()
+ * @field:	VMCS field encoding that failed
+ * @fault:	%true if the VMREAD faulted, %false if it failed
+
+ * Save and restore volatile registers across a call to vmread_error().  Note,
+ * all parameters are passed on the stack.
+ */
+ENTRY(vmread_error_trampoline)
+	push %_ASM_BP
+	mov  %_ASM_SP, %_ASM_BP
+
+	push %_ASM_AX
+	push %_ASM_CX
+	push %_ASM_DX
+#ifdef CONFIG_X86_64
+	push %rdi
+	push %rsi
+	push %r8
+	push %r9
+	push %r10
+	push %r11
+#endif
+#ifdef CONFIG_X86_64
+	/* Load @field and @fault to arg1 and arg2 respectively. */
+	mov 3*WORD_SIZE(%rbp), %_ASM_ARG2
+	mov 2*WORD_SIZE(%rbp), %_ASM_ARG1
+#else
+	/* Parameters are passed on the stack for 32-bit (see asmlinkage). */
+	push 3*WORD_SIZE(%ebp)
+	push 2*WORD_SIZE(%ebp)
+#endif
+
+	call vmread_error
+
+#ifndef CONFIG_X86_64
+	add $8, %esp
+#endif
+
+	/* Zero out @fault, which will be popped into the result register. */
+	_ASM_MOV $0, 3*WORD_SIZE(%_ASM_BP)
+
+#ifdef CONFIG_X86_64
+	pop %r11
+	pop %r10
+	pop %r9
+	pop %r8
+	pop %rsi
+	pop %rdi
+#endif
+	pop %_ASM_DX
+	pop %_ASM_CX
+	pop %_ASM_AX
+	pop %_ASM_BP
+
+	ret
+ENDPROC(vmread_error_trampoline)
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/vmx.c
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/vmx.c
@@ -31,6 +31,7 @@
 #include <asm/apic.h>
 #include <asm/asm.h>
 #include <asm/cpu.h>
+#include <asm/cpu_device_id.h>
 #include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/fpu/internal.h>
@@ -95,7 +96,7 @@
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
-static bool __read_mostly enable_apicv = 1;
+bool __read_mostly enable_apicv = 1;
 module_param(enable_apicv, bool, S_IRUGO);
 
 /*
@@ -204,6 +205,9 @@
 #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;
@@ -335,6 +339,60 @@
 	return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
 }
 
+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;
+
+	msr = __rdmsr(MSR_IA32_MCU_OPT_CTRL);
+	msr |= FB_CLEAR_DIS;
+	native_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;
+	native_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 const struct kernel_param_ops vmentry_l1d_flush_ops = {
 	.set = vmentry_l1d_flush_set,
 	.get = vmentry_l1d_flush_get,
@@ -648,43 +706,15 @@
 }
 
 #ifdef CONFIG_KEXEC_CORE
-/*
- * This bitmap is used to indicate whether the vmclear
- * operation is enabled on all cpus. All disabled by
- * default.
- */
-static cpumask_t crash_vmclear_enabled_bitmap = CPU_MASK_NONE;
-
-static inline void crash_enable_local_vmclear(int cpu)
-{
-	cpumask_set_cpu(cpu, &crash_vmclear_enabled_bitmap);
-}
-
-static inline void crash_disable_local_vmclear(int cpu)
-{
-	cpumask_clear_cpu(cpu, &crash_vmclear_enabled_bitmap);
-}
-
-static inline int crash_local_vmclear_enabled(int cpu)
-{
-	return cpumask_test_cpu(cpu, &crash_vmclear_enabled_bitmap);
-}
-
 static void crash_vmclear_local_loaded_vmcss(void)
 {
 	int cpu = raw_smp_processor_id();
 	struct loaded_vmcs *v;
 
-	if (!crash_local_vmclear_enabled(cpu))
-		return;
-
 	list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu),
 			    loaded_vmcss_on_cpu_link)
 		vmcs_clear(v->vmcs);
 }
-#else
-static inline void crash_enable_local_vmclear(int cpu) { }
-static inline void crash_disable_local_vmclear(int cpu) { }
 #endif /* CONFIG_KEXEC_CORE */
 
 static void __loaded_vmcs_clear(void *arg)
@@ -696,19 +726,24 @@
 		return; /* vcpu migration can race with cpu offline */
 	if (per_cpu(current_vmcs, cpu) == loaded_vmcs->vmcs)
 		per_cpu(current_vmcs, cpu) = NULL;
-	crash_disable_local_vmclear(cpu);
+
+	vmcs_clear(loaded_vmcs->vmcs);
+	if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched)
+		vmcs_clear(loaded_vmcs->shadow_vmcs);
+
 	list_del(&loaded_vmcs->loaded_vmcss_on_cpu_link);
 
 	/*
-	 * we should ensure updating loaded_vmcs->loaded_vmcss_on_cpu_link
-	 * is before setting loaded_vmcs->vcpu to -1 which is done in
-	 * loaded_vmcs_init. Otherwise, other cpu can see vcpu = -1 fist
-	 * then adds the vmcs into percpu list before it is deleted.
+	 * Ensure all writes to loaded_vmcs, including deleting it from its
+	 * current percpu list, complete before setting loaded_vmcs->vcpu to
+	 * -1, otherwise a different cpu can see vcpu == -1 first and add
+	 * loaded_vmcs to its percpu list before it's deleted from this cpu's
+	 * list. Pairs with the smp_rmb() in vmx_vcpu_load_vmcs().
 	 */
 	smp_wmb();
 
-	loaded_vmcs_init(loaded_vmcs);
-	crash_enable_local_vmclear(cpu);
+	loaded_vmcs->cpu = -1;
+	loaded_vmcs->launched = 0;
 }
 
 void loaded_vmcs_clear(struct loaded_vmcs *loaded_vmcs)
@@ -808,15 +843,15 @@
 /*
  * Check if MSR is intercepted for currently loaded MSR bitmap.
  */
-static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
+static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr)
 {
 	unsigned long *msr_bitmap;
 	int f = sizeof(unsigned long);
 
-	if (!cpu_has_vmx_msr_bitmap())
+	if (!(exec_controls_get(vmx) & CPU_BASED_USE_MSR_BITMAPS))
 		return true;
 
-	msr_bitmap = to_vmx(vcpu)->loaded_vmcs->msr_bitmap;
+	msr_bitmap = vmx->loaded_vmcs->msr_bitmap;
 
 	if (msr <= 0x1fff) {
 		return !!test_bit(msr, msr_bitmap + 0x800 / f);
@@ -828,6 +863,24 @@
 	return true;
 }
 
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)
+{
+	unsigned int flags = 0;
+
+	if (vmx->loaded_vmcs->launched)
+		flags |= VMX_RUN_VMRESUME;
+
+	/*
+	 * If writes to the SPEC_CTRL MSR aren't intercepted, the guest is free
+	 * to change it directly without causing a vmexit.  In that case read
+	 * it after vmexit and store it in vmx->spec_ctrl.
+	 */
+	if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
+		flags |= VMX_RUN_SAVE_SPEC_CTRL;
+
+	return flags;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 		unsigned long entry, unsigned long exit)
 {
@@ -1153,6 +1206,10 @@
 					   vmx->guest_msrs[i].mask);
 
 	}
+
+    	if (vmx->nested.need_vmcs12_to_shadow_sync)
+		nested_sync_vmcs12_to_shadow(vcpu);
+
 	if (vmx->guest_state_loaded)
 		return;
 
@@ -1309,33 +1366,44 @@
 		pi_set_on(pi_desc);
 }
 
-void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu)
+void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu,
+			struct loaded_vmcs *buddy)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	bool already_loaded = vmx->loaded_vmcs->cpu == cpu;
+	struct vmcs *prev;
 
 	if (!already_loaded) {
 		loaded_vmcs_clear(vmx->loaded_vmcs);
 		local_irq_disable();
-		crash_disable_local_vmclear(cpu);
 
 		/*
-		 * Read loaded_vmcs->cpu should be before fetching
-		 * loaded_vmcs->loaded_vmcss_on_cpu_link.
-		 * See the comments in __loaded_vmcs_clear().
+		 * Ensure loaded_vmcs->cpu is read before adding loaded_vmcs to
+		 * this cpu's percpu list, otherwise it may not yet be deleted
+		 * from its previous cpu's percpu list.  Pairs with the
+		 * smb_wmb() in __loaded_vmcs_clear().
 		 */
 		smp_rmb();
 
 		list_add(&vmx->loaded_vmcs->loaded_vmcss_on_cpu_link,
 			 &per_cpu(loaded_vmcss_on_cpu, cpu));
-		crash_enable_local_vmclear(cpu);
 		local_irq_enable();
 	}
 
-	if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
+	prev = per_cpu(current_vmcs, cpu);
+	if (prev != vmx->loaded_vmcs->vmcs) {
 		per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
 		vmcs_load(vmx->loaded_vmcs->vmcs);
-		indirect_branch_prediction_barrier();
+
+		/*
+		 * No indirect branch prediction barrier needed when switching
+		 * the active VMCS within a vCPU, unless IBRS is advertised to
+		 * the vCPU.  To minimize the number of IBPBs executed, KVM
+		 * performs IBPB on nested VM-Exit (a single nested transition
+		 * may switch the active VMCS multiple times).
+		 */
+		if (!buddy || WARN_ON_ONCE(buddy->vmcs != prev))
+			indirect_branch_prediction_barrier();
 	}
 
 	if (!already_loaded) {
@@ -1380,11 +1448,10 @@
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-	vmx_vcpu_load_vmcs(vcpu, cpu);
+	vmx_vcpu_load_vmcs(vcpu, cpu, NULL);
 
 	vmx_vcpu_pi_load(vcpu, cpu);
 
-	vmx->host_pkru = read_pkru();
 	vmx->host_debugctlmsr = get_debugctlmsr();
 }
 
@@ -1552,7 +1619,7 @@
 
 static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
-	unsigned long rip;
+	unsigned long rip, orig_rip;
 
 	/*
 	 * Using VMCS.VM_EXIT_INSTRUCTION_LEN on EPT misconfig depends on
@@ -1564,8 +1631,17 @@
 	 */
 	if (!static_cpu_has(X86_FEATURE_HYPERVISOR) ||
 	    to_vmx(vcpu)->exit_reason != EXIT_REASON_EPT_MISCONFIG) {
-		rip = kvm_rip_read(vcpu);
-		rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+		orig_rip = kvm_rip_read(vcpu);
+		rip = orig_rip + vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+#ifdef CONFIG_X86_64
+		/*
+		 * We need to mask out the high 32 bits of RIP if not in 64-bit
+		 * mode, but just finding out that we are in 64-bit mode is
+		 * quite expensive.  Only do it if there was a carry.
+		 */
+		if (unlikely(((rip ^ orig_rip) >> 31) == 3) && !is_64_bit_mode(vcpu))
+			rip = (u32)rip;
+#endif
 		kvm_rip_write(vcpu, rip);
 	} else {
 		if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))
@@ -1602,7 +1678,17 @@
 	kvm_deliver_exception_payload(vcpu);
 
 	if (has_error_code) {
-		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+		/*
+		 * Despite the error code being architecturally defined as 32
+		 * bits, and the VMCS field being 32 bits, Intel CPUs and thus
+		 * VMX don't actually supporting setting bits 31:16.  Hardware
+		 * will (should) never provide a bogus error code, but AMD CPUs
+		 * do generate error codes with bits 31:16 set, and so KVM's
+		 * ABI lets userspace shove in arbitrary 32-bit values.  Drop
+		 * the upper bits to avoid VM-Fail, losing information that
+		 * does't really exist is preferable to killing the VM.
+		 */
+		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, (u16)error_code);
 		intr_info |= INTR_INFO_DELIVER_CODE_MASK;
 	}
 
@@ -1696,7 +1782,7 @@
 	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 
 	if (is_guest_mode(vcpu) &&
-	    (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING))
+	    (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING))
 		return vcpu->arch.tsc_offset - vmcs12->tsc_offset;
 
 	return vcpu->arch.tsc_offset;
@@ -1714,7 +1800,7 @@
 	 * to the newly set TSC to get L2's TSC.
 	 */
 	if (is_guest_mode(vcpu) &&
-	    (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING))
+	    (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING))
 		g_tsc_offset = vmcs12->tsc_offset;
 
 	trace_kvm_write_tsc_offset(vcpu->vcpu_id,
@@ -1790,7 +1876,7 @@
 		break;
 	case MSR_IA32_SPEC_CTRL:
 		if (!msr_info->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL))
+		    !guest_has_spec_ctrl_msr(vcpu))
 			return 1;
 
 		msr_info->data = to_vmx(vcpu)->spec_ctrl;
@@ -1973,15 +2059,13 @@
 		break;
 	case MSR_IA32_SPEC_CTRL:
 		if (!msr_info->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL))
+		    !guest_has_spec_ctrl_msr(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))
+		if (kvm_spec_ctrl_test_value(data))
 			return 1;
 
 		vmx->spec_ctrl = data;
-
 		if (!data)
 			break;
 
@@ -2003,12 +2087,13 @@
 		break;
 	case MSR_IA32_PRED_CMD:
 		if (!msr_info->host_initiated &&
-		    !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL))
+		    !guest_has_pred_cmd_msr(vcpu))
 			return 1;
 
 		if (data & ~PRED_CMD_IBPB)
 			return 1;
-
+		if (!boot_cpu_has(X86_FEATURE_IBPB))
+			return 1;
 		if (!data)
 			break;
 
@@ -2140,6 +2225,8 @@
 			(index >= 2 * intel_pt_validate_cap(vmx->pt_desc.caps,
 					PT_CAP_num_address_ranges)))
 			return 1;
+		if (is_noncanonical_address(data, vcpu))
+			return 1;
 		if (index % 2)
 			vmx->pt_desc.guest.addr_b[index / 2] = data;
 		else
@@ -2168,9 +2255,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;
 }
 
@@ -2250,21 +2341,6 @@
 	    !hv_get_vp_assist_page(cpu))
 		return -EFAULT;
 
-	INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
-	INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
-	spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
-
-	/*
-	 * Now we can enable the vmclear operation in kdump
-	 * since the loaded_vmcss_on_cpu list on this cpu
-	 * has been initialized.
-	 *
-	 * Though the cpu is not in VMX operation now, there
-	 * is no problem to enable the vmclear operation
-	 * for the loaded_vmcss_on_cpu list is empty!
-	 */
-	crash_enable_local_vmclear(cpu);
-
 	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
 
 	test_bits = FEATURE_CONTROL_LOCKED;
@@ -2351,7 +2427,7 @@
 	      CPU_BASED_CR3_STORE_EXITING |
 	      CPU_BASED_UNCOND_IO_EXITING |
 	      CPU_BASED_MOV_DR_EXITING |
-	      CPU_BASED_USE_TSC_OFFSETING |
+	      CPU_BASED_USE_TSC_OFFSETTING |
 	      CPU_BASED_MWAIT_EXITING |
 	      CPU_BASED_MONITOR_EXITING |
 	      CPU_BASED_INVLPG_EXITING |
@@ -2521,8 +2597,10 @@
 	vmcs_conf->vmexit_ctrl         = _vmexit_control;
 	vmcs_conf->vmentry_ctrl        = _vmentry_control;
 
-	if (static_branch_unlikely(&enable_evmcs))
+#if IS_ENABLED(CONFIG_HYPERV)
+	if (enlightened_vmcs)
 		evmcs_sanitize_exec_ctrls(vmcs_conf);
+#endif
 
 	return 0;
 }
@@ -2973,6 +3051,9 @@
 
 static int get_ept_level(struct kvm_vcpu *vcpu)
 {
+	/* Nested EPT currently only supports 4-level walks. */
+	if (is_guest_mode(vcpu) && nested_cpu_has_ept(get_vmcs12(vcpu)))
+		return 4;
 	if (cpu_has_vmx_ept_5levels() && (cpuid_maxphyaddr(vcpu) > 48))
 		return 5;
 	return 4;
@@ -2995,6 +3076,7 @@
 void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
 	struct kvm *kvm = vcpu->kvm;
+	bool update_guest_cr3 = true;
 	unsigned long guest_cr3;
 	u64 eptp;
 
@@ -3011,15 +3093,18 @@
 			spin_unlock(&to_kvm_vmx(kvm)->ept_pointer_lock);
 		}
 
-		if (enable_unrestricted_guest || is_paging(vcpu) ||
-		    is_guest_mode(vcpu))
+		/* Loading vmcs02.GUEST_CR3 is handled by nested VM-Enter. */
+		if (is_guest_mode(vcpu))
+			update_guest_cr3 = false;
+		else if (enable_unrestricted_guest || is_paging(vcpu))
 			guest_cr3 = kvm_read_cr3(vcpu);
 		else
 			guest_cr3 = to_kvm_vmx(kvm)->ept_identity_map_addr;
 		ept_load_pdptrs(vcpu);
 	}
 
-	vmcs_writel(GUEST_CR3, guest_cr3);
+	if (update_guest_cr3)
+		vmcs_writel(GUEST_CR3, guest_cr3);
 }
 
 int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -3160,18 +3245,15 @@
 {
 	u32 ar;
 
-	if (var->unusable || !var->present)
-		ar = 1 << 16;
-	else {
-		ar = var->type & 15;
-		ar |= (var->s & 1) << 4;
-		ar |= (var->dpl & 3) << 5;
-		ar |= (var->present & 1) << 7;
-		ar |= (var->avl & 1) << 12;
-		ar |= (var->l & 1) << 13;
-		ar |= (var->db & 1) << 14;
-		ar |= (var->g & 1) << 15;
-	}
+	ar = var->type & 15;
+	ar |= (var->s & 1) << 4;
+	ar |= (var->dpl & 3) << 5;
+	ar |= (var->present & 1) << 7;
+	ar |= (var->avl & 1) << 12;
+	ar |= (var->l & 1) << 13;
+	ar |= (var->db & 1) << 14;
+	ar |= (var->g & 1) << 15;
+	ar |= (var->unusable || !var->present) << 16;
 
 	return ar;
 }
@@ -3844,24 +3926,29 @@
  * 2. If target vcpu isn't running(root mode), kick it to pick up the
  * interrupt from PIR in next vmentry.
  */
-static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
+static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	int r;
 
 	r = vmx_deliver_nested_posted_interrupt(vcpu, vector);
 	if (!r)
-		return;
+		return 0;
+
+	if (!vcpu->arch.apicv_active)
+		return -1;
 
 	if (pi_test_and_set_pir(vector, &vmx->pi_desc))
-		return;
+		return 0;
 
 	/* If a previous notification has sent the IPI, nothing to do.  */
 	if (pi_test_and_set_on(&vmx->pi_desc))
-		return;
+		return 0;
 
 	if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false))
 		kvm_vcpu_kick(vcpu);
+
+	return 0;
 }
 
 /*
@@ -3929,6 +4016,8 @@
 
 void set_cr4_guest_host_mask(struct vcpu_vmx *vmx)
 {
+	BUILD_BUG_ON(KVM_CR4_GUEST_OWNED_BITS & ~KVM_POSSIBLE_CR4_GUEST_BITS);
+
 	vmx->vcpu.arch.cr4_guest_owned_bits = KVM_CR4_GUEST_OWNED_BITS;
 	if (enable_ept)
 		vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE;
@@ -4364,11 +4453,13 @@
 	vpid_sync_context(vmx->vpid);
 	if (init_event)
 		vmx_clear_hlt(vcpu);
+
+	vmx_update_fb_clear_dis(vcpu, vmx);
 }
 
 static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
-	exec_controls_setbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_INTR_PENDING);
+	exec_controls_setbit(to_vmx(vcpu), CPU_BASED_INTR_WINDOW_EXITING);
 }
 
 static void enable_nmi_window(struct kvm_vcpu *vcpu)
@@ -4379,7 +4470,7 @@
 		return;
 	}
 
-	exec_controls_setbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_NMI_PENDING);
+	exec_controls_setbit(to_vmx(vcpu), CPU_BASED_NMI_WINDOW_EXITING);
 }
 
 static void vmx_inject_irq(struct kvm_vcpu *vcpu)
@@ -4491,8 +4582,13 @@
 
 static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
 {
-	return (!to_vmx(vcpu)->nested.nested_run_pending &&
-		vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+	if (to_vmx(vcpu)->nested.nested_run_pending)
+		return false;
+
+	if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu))
+		return true;
+
+	return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
 		!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
 			(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
 }
@@ -4586,7 +4682,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,
@@ -4707,7 +4803,7 @@
 	return 0;
 }
 
-static int handle_external_interrupt(struct kvm_vcpu *vcpu)
+static __always_inline int handle_external_interrupt(struct kvm_vcpu *vcpu)
 {
 	++vcpu->stat.irq_exits;
 	return 1;
@@ -4979,21 +5075,6 @@
 	vmcs_writel(GUEST_DR7, val);
 }
 
-static int handle_cpuid(struct kvm_vcpu *vcpu)
-{
-	return kvm_emulate_cpuid(vcpu);
-}
-
-static int handle_rdmsr(struct kvm_vcpu *vcpu)
-{
-	return kvm_emulate_rdmsr(vcpu);
-}
-
-static int handle_wrmsr(struct kvm_vcpu *vcpu)
-{
-	return kvm_emulate_wrmsr(vcpu);
-}
-
 static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
 {
 	kvm_apic_update_ppr(vcpu);
@@ -5002,7 +5083,7 @@
 
 static int handle_interrupt_window(struct kvm_vcpu *vcpu)
 {
-	exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_INTR_PENDING);
+	exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_INTR_WINDOW_EXITING);
 
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
 
@@ -5010,11 +5091,6 @@
 	return 1;
 }
 
-static int handle_halt(struct kvm_vcpu *vcpu)
-{
-	return kvm_emulate_halt(vcpu);
-}
-
 static int handle_vmcall(struct kvm_vcpu *vcpu)
 {
 	return kvm_emulate_hypercall(vcpu);
@@ -5220,7 +5296,7 @@
 static int handle_nmi_window(struct kvm_vcpu *vcpu)
 {
 	WARN_ON_ONCE(!enable_vnmi);
-	exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_VIRTUAL_NMI_PENDING);
+	exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_NMI_WINDOW_EXITING);
 	++vcpu->stat.nmi_window_exits;
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
 
@@ -5241,7 +5317,7 @@
 	WARN_ON_ONCE(vmx->emulation_required && vmx->nested.nested_run_pending);
 
 	intr_window_requested = exec_controls_get(vmx) &
-				CPU_BASED_VIRTUAL_INTR_PENDING;
+				CPU_BASED_INTR_WINDOW_EXITING;
 
 	while (vmx->emulation_required && count-- != 0) {
 		if (intr_window_requested && vmx_interrupt_allowed(vcpu))
@@ -5562,11 +5638,11 @@
 	[EXIT_REASON_IO_INSTRUCTION]          = handle_io,
 	[EXIT_REASON_CR_ACCESS]               = handle_cr,
 	[EXIT_REASON_DR_ACCESS]               = handle_dr,
-	[EXIT_REASON_CPUID]                   = handle_cpuid,
-	[EXIT_REASON_MSR_READ]                = handle_rdmsr,
-	[EXIT_REASON_MSR_WRITE]               = handle_wrmsr,
-	[EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
-	[EXIT_REASON_HLT]                     = handle_halt,
+	[EXIT_REASON_CPUID]                   = kvm_emulate_cpuid,
+	[EXIT_REASON_MSR_READ]                = kvm_emulate_rdmsr,
+	[EXIT_REASON_MSR_WRITE]               = kvm_emulate_wrmsr,
+	[EXIT_REASON_INTERRUPT_WINDOW]        = handle_interrupt_window,
+	[EXIT_REASON_HLT]                     = kvm_emulate_halt,
 	[EXIT_REASON_INVD]		      = handle_invd,
 	[EXIT_REASON_INVLPG]		      = handle_invlpg,
 	[EXIT_REASON_RDPMC]                   = handle_rdpmc,
@@ -5904,6 +5980,7 @@
 			(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;
@@ -5939,9 +6016,23 @@
 	}
 
 	if (exit_reason < kvm_vmx_max_exit_handlers
-	    && kvm_vmx_exit_handlers[exit_reason])
+	    && kvm_vmx_exit_handlers[exit_reason]) {
+#ifdef CONFIG_RETPOLINE
+		if (exit_reason == EXIT_REASON_MSR_WRITE)
+			return kvm_emulate_wrmsr(vcpu);
+		else if (exit_reason == EXIT_REASON_PREEMPTION_TIMER)
+			return handle_preemption_timer(vcpu);
+		else if (exit_reason == EXIT_REASON_INTERRUPT_WINDOW)
+			return handle_interrupt_window(vcpu);
+		else if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
+			return handle_external_interrupt(vcpu);
+		else if (exit_reason == EXIT_REASON_HLT)
+			return kvm_emulate_halt(vcpu);
+		else if (exit_reason == EXIT_REASON_EPT_MISCONFIG)
+			return handle_ept_misconfig(vcpu);
+#endif
 		return kvm_vmx_exit_handlers[exit_reason](vcpu);
-	else {
+	} else {
 		vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n",
 				exit_reason);
 		dump_vmcs();
@@ -6269,6 +6360,7 @@
 	);
 
 	kvm_after_interrupt(vcpu);
+	vcpu->arch.at_instruction_boundary = true;
 }
 STACK_FRAME_NON_STANDARD(handle_external_interrupt_irqoff);
 
@@ -6438,23 +6530,6 @@
 					msrs[i].host, false);
 }
 
-static void atomic_switch_umwait_control_msr(struct vcpu_vmx *vmx)
-{
-	u32 host_umwait_control;
-
-	if (!vmx_has_waitpkg(vmx))
-		return;
-
-	host_umwait_control = get_umwait_control_msr();
-
-	if (vmx->msr_ia32_umwait_control != host_umwait_control)
-		add_atomic_switch_msr(vmx, MSR_IA32_UMWAIT_CONTROL,
-			vmx->msr_ia32_umwait_control,
-			host_umwait_control, false);
-	else
-		clear_atomic_switch_msr(vmx, MSR_IA32_UMWAIT_CONTROL);
-}
-
 static void vmx_update_hv_timer(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6489,7 +6564,30 @@
 	}
 }
 
-bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs, bool launched);
+void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx,
+					unsigned int flags)
+{
+	u64 hostval = this_cpu_read(x86_spec_ctrl_current);
+
+	if (!cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL))
+		return;
+
+	if (flags & VMX_RUN_SAVE_SPEC_CTRL)
+		vmx->spec_ctrl = __rdmsr(MSR_IA32_SPEC_CTRL);
+
+	/*
+	 * 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) ||
+	    vmx->spec_ctrl != hostval)
+		native_wrmsrl(MSR_IA32_SPEC_CTRL, hostval);
+
+	barrier_nospec();
+}
 
 static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
@@ -6511,8 +6609,11 @@
 		vmcs_write32(PLE_WINDOW, vmx->ple_window);
 	}
 
-	if (vmx->nested.need_vmcs12_to_shadow_sync)
-		nested_sync_vmcs12_to_shadow(vcpu);
+	/*
+	 * We did this in prepare_switch_to_guest, because it needs to
+	 * be within srcu_read_lock.
+	 */
+	WARN_ON_ONCE(vmx->nested.need_vmcs12_to_shadow_sync);
 
 	if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
 		vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -6541,15 +6642,9 @@
 
 	kvm_load_guest_xcr0(vcpu);
 
-	if (static_cpu_has(X86_FEATURE_PKU) &&
-	    kvm_read_cr4_bits(vcpu, X86_CR4_PKE) &&
-	    vcpu->arch.pkru != vmx->host_pkru)
-		__write_pkru(vcpu->arch.pkru);
-
 	pt_guest_enter(vmx);
 
 	atomic_switch_perf_msrs(vmx);
-	atomic_switch_umwait_control_msr(vmx);
 
 	if (enable_preemption_timer)
 		vmx_update_hv_timer(vcpu);
@@ -6571,34 +6666,21 @@
 		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_disable_fb_clear(vmx);
 
 	if (vcpu->arch.cr2 != read_cr2())
 		write_cr2(vcpu->arch.cr2);
 
 	vmx->fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-				   vmx->loaded_vmcs->launched);
+				   __vmx_vcpu_run_flags(vmx));
 
 	vcpu->arch.cr2 = read_cr2();
 
-	/*
-	 * 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 = native_read_msr(MSR_IA32_SPEC_CTRL);
-
-	x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0);
+	vmx_enable_fb_clear(vmx);
 
 	/* All fields are clean at this point */
 	if (static_branch_unlikely(&enable_evmcs))
@@ -6634,18 +6716,6 @@
 
 	pt_guest_exit(vmx);
 
-	/*
-	 * eager fpu is enabled if PKEY is supported and CR4 is switched
-	 * back on host, so it is safe to read guest PKRU from current
-	 * XSAVE.
-	 */
-	if (static_cpu_has(X86_FEATURE_PKU) &&
-	    kvm_read_cr4_bits(vcpu, X86_CR4_PKE)) {
-		vcpu->arch.pkru = rdpkru();
-		if (vcpu->arch.pkru != vmx->host_pkru)
-			__write_pkru(vmx->host_pkru);
-	}
-
 	kvm_put_guest_xcr0(vcpu);
 
 	vmx->nested.nested_run_pending = 0;
@@ -6670,6 +6740,10 @@
 	struct kvm_vmx *kvm_vmx = __vmalloc(sizeof(struct kvm_vmx),
 					    GFP_KERNEL_ACCOUNT | __GFP_ZERO,
 					    PAGE_KERNEL);
+
+	if (!kvm_vmx)
+		return NULL;
+
 	return &kvm_vmx->kvm;
 }
 
@@ -6793,8 +6867,7 @@
 
 	if (nested)
 		nested_vmx_setup_ctls_msrs(&vmx->nested.msrs,
-					   vmx_capability.ept,
-					   kvm_vcpu_apicv_active(&vmx->vcpu));
+					   vmx_capability.ept);
 	else
 		memset(&vmx->nested.msrs, 0, sizeof(vmx->nested.msrs));
 
@@ -6876,8 +6949,7 @@
 	if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0)
 		return -EIO;
 	if (nested)
-		nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept,
-					   enable_apicv);
+		nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept);
 	if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
 		printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
 				smp_processor_id());
@@ -7123,6 +7195,40 @@
 	to_vmx(vcpu)->req_immediate_exit = 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);
+
+	/* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+	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)
@@ -7130,19 +7236,60 @@
 	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.
 	 */
-	if (info->intercept == x86_intercept_rdtscp &&
-	    !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
-		ctxt->exception.vector = UD_VECTOR;
-		ctxt->exception.error_code_valid = false;
-		return X86EMUL_PROPAGATE_FAULT;
-	}
+	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);
+
+	case x86_intercept_lgdt:
+	case x86_intercept_lidt:
+	case x86_intercept_lldt:
+	case x86_intercept_ltr:
+	case x86_intercept_sgdt:
+	case x86_intercept_sidt:
+	case x86_intercept_sldt:
+	case x86_intercept_str:
+		if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC))
+			return X86EMUL_CONTINUE;
+
+		/* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+		break;
+
+	case x86_intercept_pause:
+		/*
+		 * PAUSE is a single-byte NOP with a REPE prefix, i.e. collides
+		 * with vanilla NOPs in the emulator.  Apply the interception
+		 * check only to actual PAUSE instructions.  Don't check
+		 * PAUSE-loop-exiting, software can't expect a given PAUSE to
+		 * exit, i.e. KVM is within its rights to allow L2 to execute
+		 * the PAUSE.
+		 */
+		if ((info->rep_prefix != REPE_PREFIX) ||
+		    !nested_cpu_has2(vmcs12, CPU_BASED_PAUSE_EXITING))
+			return X86EMUL_CONTINUE;
+
+		break;
 
 	/* TODO: check more intercepts... */
-	return X86EMUL_CONTINUE;
+	default:
+		break;
+	}
+
+	return X86EMUL_UNHANDLEABLE;
 }
 
 #ifdef CONFIG_X86_64
@@ -7238,11 +7385,11 @@
 	kvm_flush_pml_buffers(kvm);
 }
 
-static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu)
+static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu, gpa_t gpa)
 {
 	struct vmcs12 *vmcs12;
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	gpa_t gpa, dst;
+	gpa_t dst;
 
 	if (is_guest_mode(vcpu)) {
 		WARN_ON_ONCE(vmx->nested.pml_full);
@@ -7261,7 +7408,7 @@
 			return 1;
 		}
 
-		gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS) & ~0xFFFull;
+		gpa &= ~0xFFFull;
 		dst = vmcs12->pml_address + sizeof(u64) * vmcs12->guest_pml_index;
 
 		if (kvm_write_guest_page(vcpu->kvm, gpa_to_gfn(dst), &gpa,
@@ -7727,7 +7874,7 @@
 
 	if (nested) {
 		nested_vmx_setup_ctls_msrs(&vmcs_config.nested,
-					   vmx_capability.ept, enable_apicv);
+					   vmx_capability.ept);
 
 		r = nested_vmx_hardware_setup(kvm_vmx_exit_handlers);
 		if (r)
@@ -7861,6 +8008,7 @@
 	.xsaves_supported = vmx_xsaves_supported,
 	.umip_emulated = vmx_umip_emulated,
 	.pt_supported = vmx_pt_supported,
+	.pku_supported = vmx_pku_supported,
 
 	.request_immediate_exit = vmx_request_immediate_exit,
 
@@ -7949,7 +8097,7 @@
 
 static int __init vmx_init(void)
 {
-	int r;
+	int r, cpu;
 
 #if IS_ENABLED(CONFIG_HYPERV)
 	/*
@@ -8003,6 +8151,15 @@
 		return r;
 	}
 
+	vmx_setup_fb_clear_ctrl();
+
+	for_each_possible_cpu(cpu) {
+		INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
+
+		INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
+		spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
+	}
+
 #ifdef CONFIG_KEXEC_CORE
 	rcu_assign_pointer(crash_vmclear_loaded_vmcss,
 			   crash_vmclear_local_loaded_vmcss);
--- linux-ein-5.4.0.orig/arch/x86/kvm/vmx/vmx.h
+++ linux-ein-5.4.0/arch/x86/kvm/vmx/vmx.h
@@ -10,12 +10,11 @@
 #include "capabilities.h"
 #include "ops.h"
 #include "vmcs.h"
+#include "run_flags.h"
 
 extern const u32 vmx_msr_index[];
 extern u64 host_efer;
 
-extern u32 get_umwait_control_msr(void);
-
 #define MSR_TYPE_R	1
 #define MSR_TYPE_W	2
 #define MSR_TYPE_RW	3
@@ -282,8 +281,11 @@
 	u64 msr_ia32_feature_control;
 	u64 msr_ia32_feature_control_valid_bits;
 	u64 ept_pointer;
+	u64 msr_ia32_mcu_opt_ctrl;
+	bool disable_fb_clear;
 
 	struct pt_desc pt_desc;
+
 };
 
 enum ept_pointers_status {
@@ -304,7 +306,8 @@
 };
 
 bool nested_vmx_allowed(struct kvm_vcpu *vcpu);
-void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu);
+void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu,
+			struct loaded_vmcs *buddy);
 void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
 int allocate_vpid(void);
 void free_vpid(int vpid);
@@ -334,6 +337,10 @@
 struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr);
 void pt_update_intercept_for_msr(struct vcpu_vmx *vmx);
 void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
+void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
+bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
+		    unsigned int flags);
 
 #define POSTED_INTR_ON  0
 #define POSTED_INTR_SN  1
@@ -513,7 +520,7 @@
 
 static inline bool vmx_has_waitpkg(struct vcpu_vmx *vmx)
 {
-	return vmx->secondary_exec_control &
+	return secondary_exec_controls_get(vmx) &
 		SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
 }
 
--- linux-ein-5.4.0.orig/arch/x86/kvm/x86.c
+++ linux-ein-5.4.0/arch/x86/kvm/x86.c
@@ -68,6 +68,7 @@
 #include <asm/mshyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/intel_pt.h>
+#include <asm/emulate_prefix.h>
 #include <clocksource/hyperv_timer.h>
 
 #define CREATE_TRACE_POINTS
@@ -92,6 +93,8 @@
 static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 #endif
 
+static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
+
 #define VM_STAT(x, ...) offsetof(struct kvm, stat.x), KVM_STAT_VM, ## __VA_ARGS__
 #define VCPU_STAT(x, ...) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU, ## __VA_ARGS__
 
@@ -100,6 +103,7 @@
 
 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
 static void process_nmi(struct kvm_vcpu *vcpu);
+static void process_smi(struct kvm_vcpu *vcpu);
 static void enter_smm(struct kvm_vcpu *vcpu);
 static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
 static void store_regs(struct kvm_vcpu *vcpu);
@@ -164,6 +168,10 @@
 	u32 msrs[KVM_NR_SHARED_MSRS];
 };
 
+/* Enable/disable SMT_RSB bug mitigation */
+bool __read_mostly mitigate_smt_rsb;
+module_param(mitigate_smt_rsb, bool, 0444);
+
 struct kvm_shared_msrs {
 	struct user_return_notifier urn;
 	bool registered;
@@ -203,9 +211,10 @@
 	{ "nmi_injections", VCPU_STAT(nmi_injections) },
 	{ "req_event", VCPU_STAT(req_event) },
 	{ "l1d_flush", VCPU_STAT(l1d_flush) },
+	{ "preemption_reported", VCPU_STAT(preemption_reported) },
+	{ "preemption_other", VCPU_STAT(preemption_other) },
 	{ "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) },
 	{ "mmu_pte_write", VM_STAT(mmu_pte_write) },
-	{ "mmu_pte_updated", VM_STAT(mmu_pte_updated) },
 	{ "mmu_pde_zapped", VM_STAT(mmu_pde_zapped) },
 	{ "mmu_flooded", VM_STAT(mmu_flooded) },
 	{ "mmu_recycled", VM_STAT(mmu_recycled) },
@@ -300,13 +309,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);
@@ -442,6 +452,14 @@
 		 * for #DB exceptions under VMX.
 		 */
 		vcpu->arch.dr6 ^= payload & DR6_RTM;
+
+		/*
+		 * The #DB payload is defined as compatible with the 'pending
+		 * debug exceptions' field under VMX, not DR6. While bit 12 is
+		 * defined in the 'pending debug exceptions' field (enabled
+		 * breakpoint), it is reserved and must be zero in DR6.
+		 */
+		vcpu->arch.dr6 &= ~BIT(12);
 		break;
 	case PF_VECTOR:
 		vcpu->arch.cr2 = payload;
@@ -464,8 +482,6 @@
 
 	if (!vcpu->arch.exception.pending && !vcpu->arch.exception.injected) {
 	queue:
-		if (has_error && !is_protmode(vcpu))
-			has_error = false;
 		if (reinject) {
 			/*
 			 * On vmentry, vcpu->arch.exception.pending is only
@@ -821,11 +837,25 @@
 			xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0);
 		vcpu->guest_xcr0_loaded = 1;
 	}
+
+	if (static_cpu_has(X86_FEATURE_PKU) &&
+	    (kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ||
+	     (vcpu->arch.xcr0 & XFEATURE_MASK_PKRU)) &&
+	    vcpu->arch.pkru != vcpu->arch.host_pkru)
+		__write_pkru(vcpu->arch.pkru);
 }
 EXPORT_SYMBOL_GPL(kvm_load_guest_xcr0);
 
 void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
 {
+	if (static_cpu_has(X86_FEATURE_PKU) &&
+	    (kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ||
+	     (vcpu->arch.xcr0 & XFEATURE_MASK_PKRU))) {
+		vcpu->arch.pkru = rdpkru();
+		if (vcpu->arch.pkru != vcpu->arch.host_pkru)
+			__write_pkru(vcpu->arch.host_pkru);
+	}
+
 	if (vcpu->guest_xcr0_loaded) {
 		if (vcpu->arch.xcr0 != host_xcr0)
 			xsetbv(XCR_XFEATURE_ENABLED_MASK, host_xcr0);
@@ -885,9 +915,38 @@
 }
 EXPORT_SYMBOL_GPL(kvm_set_xcr);
 
+static u64 kvm_host_cr4_reserved_bits(struct cpuinfo_x86 *c)
+{
+	u64 reserved_bits = CR4_RESERVED_BITS;
+
+	if (!cpu_has(c, X86_FEATURE_XSAVE))
+		reserved_bits |= X86_CR4_OSXSAVE;
+
+	if (!cpu_has(c, X86_FEATURE_SMEP))
+		reserved_bits |= X86_CR4_SMEP;
+
+	if (!cpu_has(c, X86_FEATURE_SMAP))
+		reserved_bits |= X86_CR4_SMAP;
+
+	if (!cpu_has(c, X86_FEATURE_FSGSBASE))
+		reserved_bits |= X86_CR4_FSGSBASE;
+
+	if (!cpu_has(c, X86_FEATURE_PKU))
+		reserved_bits |= X86_CR4_PKE;
+
+	if (!cpu_has(c, X86_FEATURE_LA57) &&
+	    !(cpuid_ecx(0x7) & bit(X86_FEATURE_LA57)))
+		reserved_bits |= X86_CR4_LA57;
+
+	if (!cpu_has(c, X86_FEATURE_UMIP) && !kvm_x86_ops->umip_emulated())
+		reserved_bits |= X86_CR4_UMIP;
+
+	return reserved_bits;
+}
+
 static int kvm_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
-	if (cr4 & CR4_RESERVED_BITS)
+	if (cr4 & cr4_reserved_bits)
 		return -EINVAL;
 
 	if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) && (cr4 & X86_CR4_OSXSAVE))
@@ -918,7 +977,8 @@
 {
 	unsigned long old_cr4 = kvm_read_cr4(vcpu);
 	unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
-				   X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE;
+				   X86_CR4_SMEP;
+	unsigned long mmu_role_bits = pdptr_bits | X86_CR4_SMAP | X86_CR4_PKE;
 
 	if (kvm_valid_cr4(vcpu, cr4))
 		return 1;
@@ -926,6 +986,8 @@
 	if (is_long_mode(vcpu)) {
 		if (!(cr4 & X86_CR4_PAE))
 			return 1;
+		if ((cr4 ^ old_cr4) & X86_CR4_LA57)
+			return 1;
 	} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
 		   && ((cr4 ^ old_cr4) & pdptr_bits)
 		   && !load_pdptrs(vcpu, vcpu->arch.walk_mmu,
@@ -944,7 +1006,7 @@
 	if (kvm_x86_ops->set_cr4(vcpu, cr4))
 		return 1;
 
-	if (((cr4 ^ old_cr4) & pdptr_bits) ||
+	if (((cr4 ^ old_cr4) & mmu_role_bits) ||
 	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
 		kvm_mmu_reset_context(vcpu);
 
@@ -1053,9 +1115,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;
@@ -1092,9 +1156,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 */
@@ -1159,7 +1225,7 @@
 	MSR_IA32_UMWAIT_CONTROL,
 
 	MSR_ARCH_PERFMON_FIXED_CTR0, MSR_ARCH_PERFMON_FIXED_CTR1,
-	MSR_ARCH_PERFMON_FIXED_CTR0 + 2, MSR_ARCH_PERFMON_FIXED_CTR0 + 3,
+	MSR_ARCH_PERFMON_FIXED_CTR0 + 2,
 	MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_STATUS,
 	MSR_CORE_PERF_GLOBAL_CTRL, MSR_CORE_PERF_GLOBAL_OVF_CTRL,
 	MSR_ARCH_PERFMON_PERFCTR0, MSR_ARCH_PERFMON_PERFCTR1,
@@ -1180,6 +1246,13 @@
 	MSR_ARCH_PERFMON_EVENTSEL0 + 12, MSR_ARCH_PERFMON_EVENTSEL0 + 13,
 	MSR_ARCH_PERFMON_EVENTSEL0 + 14, MSR_ARCH_PERFMON_EVENTSEL0 + 15,
 	MSR_ARCH_PERFMON_EVENTSEL0 + 16, MSR_ARCH_PERFMON_EVENTSEL0 + 17,
+
+	MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3,
+	MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3,
+	MSR_F15H_PERF_CTL0, MSR_F15H_PERF_CTL1, MSR_F15H_PERF_CTL2,
+	MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
+	MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
+	MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
 };
 
 static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_all)];
@@ -1270,7 +1343,7 @@
 	MSR_IA32_VMX_EPT_VPID_CAP,
 	MSR_IA32_VMX_VMFUNC,
 
-	MSR_F10H_DECFG,
+	MSR_AMD64_DE_CFG,
 	MSR_IA32_UCODE_REV,
 	MSR_IA32_ARCH_CAPABILITIES,
 };
@@ -1327,10 +1400,22 @@
 	 * 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_bug(X86_BUG_TAA) && boot_cpu_has(X86_FEATURE_RTM) &&
-	    (data & ARCH_CAP_TSX_CTRL_MSR))
+	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;
 }
 
@@ -2484,7 +2569,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
@@ -2580,45 +2668,47 @@
 
 static void record_steal_time(struct kvm_vcpu *vcpu)
 {
+	struct kvm_host_map map;
+	struct kvm_steal_time *st;
+
 	if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
 		return;
 
-	if (unlikely(kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.st.stime,
-		&vcpu->arch.st.steal, sizeof(struct kvm_steal_time))))
+	/* -EAGAIN is returned in atomic context so we can just return. */
+	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT,
+			&map, &vcpu->arch.st.cache, false))
 		return;
 
+	st = map.hva +
+		offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS);
+
 	/*
 	 * Doing a TLB flush here, on the guest's behalf, can avoid
 	 * expensive IPIs.
 	 */
 	trace_kvm_pv_tlb_flush(vcpu->vcpu_id,
-		vcpu->arch.st.steal.preempted & KVM_VCPU_FLUSH_TLB);
-	if (xchg(&vcpu->arch.st.steal.preempted, 0) & KVM_VCPU_FLUSH_TLB)
+		st->preempted & KVM_VCPU_FLUSH_TLB);
+	if (xchg(&st->preempted, 0) & KVM_VCPU_FLUSH_TLB)
 		kvm_vcpu_flush_tlb(vcpu, false);
 
-	if (vcpu->arch.st.steal.version & 1)
-		vcpu->arch.st.steal.version += 1;  /* first time write, random junk */
+	vcpu->arch.st.preempted = 0;
 
-	vcpu->arch.st.steal.version += 1;
+	if (st->version & 1)
+		st->version += 1;  /* first time write, random junk */
 
-	kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime,
-		&vcpu->arch.st.steal, sizeof(struct kvm_steal_time));
+	st->version += 1;
 
 	smp_wmb();
 
-	vcpu->arch.st.steal.steal += current->sched_info.run_delay -
+	st->steal += current->sched_info.run_delay -
 		vcpu->arch.st.last_steal;
 	vcpu->arch.st.last_steal = current->sched_info.run_delay;
 
-	kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime,
-		&vcpu->arch.st.steal, sizeof(struct kvm_steal_time));
-
 	smp_wmb();
 
-	vcpu->arch.st.steal.version += 1;
+	st->version += 1;
 
-	kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.st.stime,
-		&vcpu->arch.st.steal, sizeof(struct kvm_steal_time));
+	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
 }
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -2634,6 +2724,7 @@
 	case MSR_AMD64_PATCH_LOADER:
 	case MSR_AMD64_BU_CFG2:
 	case MSR_AMD64_DC_CFG:
+	case MSR_AMD64_TW_CFG:
 	case MSR_F15H_EX_CFG:
 		break;
 
@@ -2685,7 +2776,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);
@@ -2695,6 +2786,10 @@
 			if (!msr_info->host_initiated) {
 				s64 adj = data - vcpu->arch.ia32_tsc_adjust_msr;
 				adjust_tsc_offset_guest(vcpu, adj);
+				/* Before back to guest, tsc_timestamp must be adjusted
+				 * as well, otherwise guest's percpu pvclock time could jump.
+				 */
+				kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 			}
 			vcpu->arch.ia32_tsc_adjust_msr = data;
 		}
@@ -2771,11 +2866,6 @@
 		if (data & KVM_STEAL_RESERVED_MASK)
 			return 1;
 
-		if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.st.stime,
-						data & KVM_STEAL_VALID_BITS,
-						sizeof(struct kvm_steal_time)))
-			return 1;
-
 		vcpu->arch.st.msr_val = data;
 
 		if (!(data & KVM_MSR_ENABLED))
@@ -2911,7 +3001,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;
 		}
@@ -2941,6 +3034,7 @@
 	case MSR_AMD64_BU_CFG2:
 	case MSR_IA32_PERF_CTL:
 	case MSR_AMD64_DC_CFG:
+	case MSR_AMD64_TW_CFG:
 	case MSR_F15H_EX_CFG:
 		msr_info->data = 0;
 		break;
@@ -2991,7 +3085,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:
@@ -3261,10 +3355,15 @@
 		r = KVM_CLOCK_TSC_STABLE;
 		break;
 	case KVM_CAP_X86_DISABLE_EXITS:
-		r |=  KVM_X86_DISABLE_EXITS_HLT | KVM_X86_DISABLE_EXITS_PAUSE |
-		      KVM_X86_DISABLE_EXITS_CSTATE;
-		if(kvm_can_mwait_in_guest())
-			r |= KVM_X86_DISABLE_EXITS_MWAIT;
+		r = KVM_X86_DISABLE_EXITS_PAUSE;
+
+		if (!mitigate_smt_rsb) {
+			r |= KVM_X86_DISABLE_EXITS_HLT |
+			     KVM_X86_DISABLE_EXITS_CSTATE;
+
+			if (kvm_can_mwait_in_guest())
+				r |= KVM_X86_DISABLE_EXITS_MWAIT;
+		}
 		break;
 	case KVM_CAP_X86_SMM:
 		/* SMBASE is usually relocated above 1M on modern chipsets,
@@ -3437,10 +3536,6 @@
 
 	kvm_x86_ops->vcpu_load(vcpu, cpu);
 
-	fpregs_assert_state_consistent();
-	if (test_thread_flag(TIF_NEED_FPU_LOAD))
-		switch_fpu_return();
-
 	/* Apply any externally detected TSC adjustments (due to suspend) */
 	if (unlikely(vcpu->arch.tsc_offset_adjustment)) {
 		adjust_tsc_offset_host(vcpu, vcpu->arch.tsc_offset_adjustment);
@@ -3480,15 +3575,38 @@
 
 static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 {
+	struct kvm_host_map map;
+	struct kvm_steal_time *st;
+
+	/*
+	 * The vCPU can be marked preempted if and only if the VM-Exit was on
+	 * an instruction boundary and will not trigger guest emulation of any
+	 * kind (see vcpu_run).  Vendor specific code controls (conservatively)
+	 * when this is true, for example allowing the vCPU to be marked
+	 * preempted if and only if the VM-Exit was due to a host interrupt.
+	 */
+	if (!vcpu->arch.at_instruction_boundary) {
+		vcpu->stat.preemption_other++;
+		return;
+	}
+
+	vcpu->stat.preemption_reported++;
 	if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
 		return;
 
-	vcpu->arch.st.steal.preempted = KVM_VCPU_PREEMPTED;
+	if (vcpu->arch.st.preempted)
+		return;
+
+	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
+			&vcpu->arch.st.cache, true))
+		return;
+
+	st = map.hva +
+		offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS);
+
+	st->preempted = vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
 
-	kvm_write_guest_offset_cached(vcpu->kvm, &vcpu->arch.st.stime,
-			&vcpu->arch.st.steal.preempted,
-			offsetof(struct kvm_steal_time, preempted),
-			sizeof(vcpu->arch.st.steal.preempted));
+	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -3549,22 +3667,33 @@
 
 static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * We can accept userspace's request for interrupt injection
+	 * as long as we have a place to store the interrupt number.
+	 * The actual injection will happen when the CPU is able to
+	 * deliver the interrupt.
+	 */
+	if (kvm_cpu_has_extint(vcpu))
+		return false;
+
+	/* Acknowledging ExtINT does not happen if LINT0 is masked.  */
 	return (!lapic_in_kernel(vcpu) ||
 		kvm_apic_accept_pic_intr(vcpu));
 }
 
-/*
- * if userspace requested an interrupt window, check that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
 static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
 {
-	return kvm_arch_interrupt_allowed(vcpu) &&
-		!kvm_cpu_has_interrupt(vcpu) &&
+	/*
+	 * Do not cause an interrupt window exit if an exception
+	 * is pending or an event needs reinjection; userspace
+	 * might want to inject the interrupt manually using KVM_SET_REGS
+	 * or KVM_SET_SREGS.  For that to work, we must be at an
+	 * instruction boundary and with no events half-injected.
+	 */
+	return (kvm_arch_interrupt_allowed(vcpu) &&
+		kvm_cpu_accept_dm_intr(vcpu) &&
 		!kvm_event_needs_reinjection(vcpu) &&
-		kvm_cpu_accept_dm_intr(vcpu);
+		!vcpu->arch.exception.pending);
 }
 
 static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
@@ -3624,7 +3753,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;
@@ -3695,6 +3824,10 @@
 {
 	process_nmi(vcpu);
 
+
+	if (kvm_check_request(KVM_REQ_SMI, vcpu))
+		process_smi(vcpu);
+
 	/*
 	 * The API doesn't provide the instruction length for software
 	 * exceptions, so don't report them. As long as the guest RIP
@@ -3844,12 +3977,11 @@
 {
 	unsigned long val;
 
+	memset(dbgregs, 0, sizeof(*dbgregs));
 	memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
 	kvm_get_dr(vcpu, 6, &val);
 	dbgregs->dr6 = val;
 	dbgregs->dr7 = vcpu->arch.dr7;
-	dbgregs->flags = 0;
-	memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -4421,6 +4553,7 @@
 	case KVM_SET_NESTED_STATE: {
 		struct kvm_nested_state __user *user_kvm_nested_state = argp;
 		struct kvm_nested_state kvm_state;
+		int idx;
 
 		r = -EINVAL;
 		if (!kvm_x86_ops->set_nested_state)
@@ -4444,7 +4577,9 @@
 		    && !(kvm_state.flags & KVM_STATE_NESTED_GUEST_MODE))
 			break;
 
+		idx = srcu_read_lock(&vcpu->kvm->srcu);
 		r = kvm_x86_ops->set_nested_state(vcpu, user_kvm_nested_state, &kvm_state);
+		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
 	}
 	case KVM_GET_SUPPORTED_HV_CPUID: {
@@ -4786,15 +4921,26 @@
 		if (cap->args[0] & ~KVM_X86_DISABLE_VALID_EXITS)
 			break;
 
-		if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) &&
-			kvm_can_mwait_in_guest())
-			kvm->arch.mwait_in_guest = true;
-		if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT)
-			kvm->arch.hlt_in_guest = true;
 		if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
 			kvm->arch.pause_in_guest = true;
-		if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
-			kvm->arch.cstate_in_guest = true;
+
+#define SMT_RSB_MSG "This processor is affected by the Cross-Thread Return Predictions vulnerability. " \
+		    "KVM_CAP_X86_DISABLE_EXITS should only be used with SMT disabled or trusted guests."
+
+		if (!mitigate_smt_rsb) {
+			if (boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible() &&
+			    (cap->args[0] & ~KVM_X86_DISABLE_EXITS_PAUSE))
+				pr_warn_once(SMT_RSB_MSG);
+
+			if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) &&
+			    kvm_can_mwait_in_guest())
+				kvm->arch.mwait_in_guest = true;
+			if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT)
+				kvm->arch.hlt_in_guest = true;
+			if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
+				kvm->arch.cstate_in_guest = true;
+		}
+
 		r = 0;
 		break;
 	case KVM_CAP_MSR_PLATFORM_INFO:
@@ -4973,10 +5119,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: {
@@ -4996,10 +5145,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: {
@@ -5151,6 +5303,10 @@
 			if (!kvm_x86_ops->rdtscp_supported())
 				continue;
 			break;
+		case MSR_IA32_UMWAIT_CONTROL:
+			if (!boot_cpu_has(X86_FEATURE_WAITPKG))
+				continue;
+			break;
 		case MSR_IA32_RTIT_CTL:
 		case MSR_IA32_RTIT_STATUS:
 			if (!kvm_x86_ops->pt_supported())
@@ -5471,6 +5627,7 @@
 
 int handle_ud(struct kvm_vcpu *vcpu)
 {
+	static const char kvm_emulate_prefix[] = { __KVM_EMULATE_PREFIX };
 	int emul_type = EMULTYPE_TRAP_UD;
 	char sig[5]; /* ud2; .ascii "kvm" */
 	struct x86_exception e;
@@ -5478,7 +5635,7 @@
 	if (force_emulation_prefix &&
 	    kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
 				sig, sizeof(sig), &e) == 0 &&
-	    memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
+	    memcmp(sig, kvm_emulate_prefix, sizeof(sig)) == 0) {
 		kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
 		emul_type = EMULTYPE_TRAP_UD_FORCED;
 	}
@@ -6185,7 +6342,10 @@
 
 static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_flags)
 {
-	emul_to_vcpu(ctxt)->arch.hflags = emul_flags;
+	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
+	vcpu->arch.hflags = emul_flags;
+	kvm_mmu_reset_context(vcpu);
 }
 
 static int emulator_pre_leave_smm(struct x86_emulate_ctxt *ctxt,
@@ -6356,11 +6516,11 @@
 	return 1;
 }
 
-static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2,
+static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
 				  bool write_fault_to_shadow_pgtable,
 				  int emulation_type)
 {
-	gpa_t gpa = cr2;
+	gpa_t gpa = cr2_or_gpa;
 	kvm_pfn_t pfn;
 
 	if (!(emulation_type & EMULTYPE_ALLOW_RETRY))
@@ -6374,7 +6534,7 @@
 		 * Write permission should be allowed since only
 		 * write access need to be emulated.
 		 */
-		gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2, NULL);
+		gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2_or_gpa, NULL);
 
 		/*
 		 * If the mapping is invalid in guest, let cpu retry
@@ -6431,10 +6591,10 @@
 }
 
 static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
-			      unsigned long cr2,  int emulation_type)
+			      gpa_t cr2_or_gpa,  int emulation_type)
 {
 	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
-	unsigned long last_retry_eip, last_retry_addr, gpa = cr2;
+	unsigned long last_retry_eip, last_retry_addr, gpa = cr2_or_gpa;
 
 	last_retry_eip = vcpu->arch.last_retry_eip;
 	last_retry_addr = vcpu->arch.last_retry_addr;
@@ -6463,14 +6623,14 @@
 	if (x86_page_table_writing_insn(ctxt))
 		return false;
 
-	if (ctxt->eip == last_retry_eip && last_retry_addr == cr2)
+	if (ctxt->eip == last_retry_eip && last_retry_addr == cr2_or_gpa)
 		return false;
 
 	vcpu->arch.last_retry_eip = ctxt->eip;
-	vcpu->arch.last_retry_addr = cr2;
+	vcpu->arch.last_retry_addr = cr2_or_gpa;
 
 	if (!vcpu->arch.mmu->direct_map)
-		gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2, NULL);
+		gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2_or_gpa, NULL);
 
 	kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
 
@@ -6616,11 +6776,8 @@
 	return false;
 }
 
-int x86_emulate_instruction(struct kvm_vcpu *vcpu,
-			    unsigned long cr2,
-			    int emulation_type,
-			    void *insn,
-			    int insn_len)
+int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
+			    int emulation_type, void *insn, int insn_len)
 {
 	int r;
 	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
@@ -6666,10 +6823,13 @@
 				kvm_queue_exception(vcpu, UD_VECTOR);
 				return 1;
 			}
-			if (reexecute_instruction(vcpu, cr2, write_fault_to_spt,
-						emulation_type))
+			if (reexecute_instruction(vcpu, cr2_or_gpa,
+						  write_fault_to_spt,
+						  emulation_type))
 				return 1;
-			if (ctxt->have_exception) {
+
+			if (ctxt->have_exception &&
+			    !(emulation_type & EMULTYPE_SKIP)) {
 				/*
 				 * #UD should result in just EMULATION_FAILED, and trap-like
 				 * exception should not be encountered during decode.
@@ -6701,7 +6861,7 @@
 		return 1;
 	}
 
-	if (retry_instruction(ctxt, cr2, emulation_type))
+	if (retry_instruction(ctxt, cr2_or_gpa, emulation_type))
 		return 1;
 
 	/* this is needed for vmware backdoor interface to work since it
@@ -6713,7 +6873,7 @@
 
 restart:
 	/* Save the faulting GPA (cr2) in the address field */
-	ctxt->exception.address = cr2;
+	ctxt->exception.address = cr2_or_gpa;
 
 	r = x86_emulate_insn(ctxt);
 
@@ -6721,7 +6881,7 @@
 		return 1;
 
 	if (r == EMULATION_FAILED) {
-		if (reexecute_instruction(vcpu, cr2, write_fault_to_spt,
+		if (reexecute_instruction(vcpu, cr2_or_gpa, write_fault_to_spt,
 					emulation_type))
 			return 1;
 
@@ -6760,7 +6920,7 @@
 		if (!ctxt->have_exception ||
 		    exception_type(ctxt->exception.vector) == EXCPT_TRAP) {
 			kvm_rip_write(vcpu, ctxt->eip);
-			if (r && ctxt->tf)
+			if (r && (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
 				r = kvm_vcpu_do_singlestep(vcpu);
 			__kvm_set_rflags(vcpu, ctxt->eflags);
 		}
@@ -7182,7 +7342,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;
 	}
@@ -7217,6 +7377,8 @@
 	if (r)
 		goto out_free_percpu;
 
+	mitigate_smt_rsb &= boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible();
+
 	kvm_x86_ops = ops;
 
 	kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
@@ -7264,6 +7426,7 @@
 	cpuhp_remove_state_nocalls(CPUHP_AP_X86_KVM_CLK_ONLINE);
 #ifdef CONFIG_X86_64
 	pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier);
+	cancel_work_sync(&pvclock_gtod_work);
 #endif
 	kvm_x86_ops = NULL;
 	kvm_mmu_module_exit();
@@ -7496,14 +7659,21 @@
 	kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
 }
 
-static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
+static void kvm_inject_exception(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->arch.exception.error_code && !is_protmode(vcpu))
+               vcpu->arch.exception.error_code = false;
+       kvm_x86_ops->queue_exception(vcpu);
+}
+
+static int inject_pending_event(struct kvm_vcpu *vcpu)
 {
 	int r;
 
 	/* try to reinject previous events if any */
 
 	if (vcpu->arch.exception.injected)
-		kvm_x86_ops->queue_exception(vcpu);
+		kvm_inject_exception(vcpu);
 	/*
 	 * Do not inject an NMI or interrupt if there is a pending
 	 * exception.  Exceptions and interrupts are recognized at
@@ -7532,7 +7702,7 @@
 	 * from L2 to L1.
 	 */
 	if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
-		r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
+		r = kvm_x86_ops->check_nested_events(vcpu);
 		if (r != 0)
 			return r;
 	}
@@ -7569,7 +7739,7 @@
 			}
 		}
 
-		kvm_x86_ops->queue_exception(vcpu);
+		kvm_inject_exception(vcpu);
 	}
 
 	/* Don't consider new event if we re-injected an event */
@@ -7594,7 +7764,7 @@
 		 * KVM_REQ_EVENT only on certain events and not unconditionally?
 		 */
 		if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
-			r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
+			r = kvm_x86_ops->check_nested_events(vcpu);
 			if (r != 0)
 				return r;
 		}
@@ -7905,9 +8075,8 @@
 	kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
 }
 
-int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
-		unsigned long start, unsigned long end,
-		bool blockable)
+void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+					    unsigned long start, unsigned long end)
 {
 	unsigned long apic_address;
 
@@ -7918,8 +8087,6 @@
 	apic_address = gfn_to_hva(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT);
 	if (start <= apic_address && apic_address < end)
 		kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD);
-
-	return 0;
 }
 
 void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
@@ -8071,7 +8238,7 @@
 			goto out;
 		}
 
-		if (inject_pending_event(vcpu, req_int_win) != 0)
+		if (inject_pending_event(vcpu) != 0)
 			req_immediate_exit = true;
 		else {
 			/* Enable SMI/NMI/IRQ window open exits if needed.
@@ -8163,8 +8330,12 @@
 	trace_kvm_entry(vcpu->vcpu_id);
 	guest_enter_irqoff();
 
-	/* The preempt notifier should have taken care of the FPU already.  */
-	WARN_ON_ONCE(test_thread_flag(TIF_NEED_FPU_LOAD));
+	/* Save host pkru register if supported */
+	vcpu->arch.host_pkru = read_pkru();
+
+	fpregs_assert_state_consistent();
+	if (test_thread_flag(TIF_NEED_FPU_LOAD))
+		switch_fpu_return();
 
 	if (unlikely(vcpu->arch.switch_db_regs)) {
 		set_debugreg(0, 7);
@@ -8174,6 +8345,8 @@
 		set_debugreg(vcpu->arch.eff_db[3], 3);
 		set_debugreg(vcpu->arch.dr6, 6);
 		vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
+	} else if (unlikely(hw_breakpoint_active())) {
+		set_debugreg(0, 7);
 	}
 
 	kvm_x86_ops->run(vcpu);
@@ -8256,6 +8429,8 @@
 	return r;
 
 cancel_injection:
+	if (req_immediate_exit)
+		kvm_make_request(KVM_REQ_EVENT, vcpu);
 	kvm_x86_ops->cancel_injection(vcpu);
 	if (unlikely(vcpu->arch.apic_attention))
 		kvm_lapic_sync_from_vapic(vcpu);
@@ -8300,7 +8475,7 @@
 static inline bool kvm_vcpu_running(struct kvm_vcpu *vcpu)
 {
 	if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events)
-		kvm_x86_ops->check_nested_events(vcpu, false);
+		kvm_x86_ops->check_nested_events(vcpu);
 
 	return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
 		!vcpu->arch.apf.halted);
@@ -8315,6 +8490,13 @@
 	vcpu->arch.l1tf_flush_l1d = true;
 
 	for (;;) {
+		/*
+		 * If another guest vCPU requests a PV TLB flush in the middle
+		 * of instruction emulation, the rest of the emulation could
+		 * use a stale page translation. Assume that any code after
+		 * this point can start executing an instruction.
+		 */
+		vcpu->arch.at_instruction_boundary = false;
 		if (kvm_vcpu_running(vcpu)) {
 			r = vcpu_enter_guest(vcpu);
 		} else {
@@ -8436,12 +8618,26 @@
 	return 0;
 }
 
+static void kvm_save_current_fpu(struct fpu *fpu)
+{
+	/*
+	 * If the target FPU state is not resident in the CPU registers, just
+	 * memcpy() from current, else save CPU state directly to the target.
+	 */
+	if (test_thread_flag(TIF_NEED_FPU_LOAD))
+		memcpy(&fpu->state, &current->thread.fpu.state,
+		       fpu_kernel_xstate_size);
+	else
+		copy_fpregs_to_fpstate(fpu);
+}
+
 /* Swap (qemu) user FPU context for the guest FPU context. */
 static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 {
 	fpregs_lock();
 
-	copy_fpregs_to_fpstate(vcpu->arch.user_fpu);
+	kvm_save_current_fpu(vcpu->arch.user_fpu);
+
 	/* PKRU is separately restored in kvm_x86_ops->run.  */
 	__copy_kernel_to_fpregs(&vcpu->arch.guest_fpu->state,
 				~XFEATURE_MASK_PKRU);
@@ -8457,7 +8653,8 @@
 {
 	fpregs_lock();
 
-	copy_fpregs_to_fpstate(vcpu->arch.guest_fpu);
+	kvm_save_current_fpu(vcpu->arch.guest_fpu);
+
 	copy_kernel_to_fpregs(&vcpu->arch.user_fpu->state);
 
 	fpregs_mark_activate();
@@ -8679,6 +8876,8 @@
 				    struct kvm_mp_state *mp_state)
 {
 	vcpu_load(vcpu);
+	if (kvm_mpx_supported())
+		kvm_load_guest_fpu(vcpu);
 
 	kvm_apic_accept_events(vcpu);
 	if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED &&
@@ -8687,6 +8886,8 @@
 	else
 		mp_state->mp_state = vcpu->arch.mp_state;
 
+	if (kvm_mpx_supported())
+		kvm_put_guest_fpu(vcpu);
 	vcpu_put(vcpu);
 	return 0;
 }
@@ -9046,6 +9247,9 @@
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
 	void *wbinvd_dirty_mask = vcpu->arch.wbinvd_dirty_mask;
+	struct gfn_to_pfn_cache *cache = &vcpu->arch.st.cache;
+
+	kvm_release_pfn(cache->pfn, cache->dirty, cache);
 
 	kvmclock_reset(vcpu);
 
@@ -9110,17 +9314,13 @@
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.apf.msr_val = 0;
-
-	vcpu_load(vcpu);
-	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)
 {
+	unsigned long old_cr0 = kvm_read_cr0(vcpu);
+
 	kvm_lapic_reset(vcpu, init_event);
 
 	vcpu->arch.hflags = 0;
@@ -9190,6 +9390,17 @@
 	vcpu->arch.ia32_xss = 0;
 
 	kvm_x86_ops->vcpu_reset(vcpu, init_event);
+
+	/*
+	 * Reset the MMU context if paging was enabled prior to INIT (which is
+	 * implied if CR0.PG=1 as CR0 will be '0' prior to RESET).  Unlike the
+	 * standard CR0/CR4/EFER modification paths, only CR0.PG needs to be
+	 * checked because it is unconditionally cleared on INIT and all other
+	 * paging related bits are ignored if paging is disabled, i.e. CR0.WP,
+	 * CR4, and EFER changes are all irrelevant if CR0.PG was '0'.
+	 */
+	if (old_cr0 & X86_CR0_PG)
+		kvm_mmu_reset_context(vcpu);
 }
 
 void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
@@ -9308,6 +9519,8 @@
 	if (r != 0)
 		return r;
 
+	cr4_reserved_bits = kvm_host_cr4_reserved_bits(&boot_cpu_data);
+
 	if (kvm_has_tsc_control) {
 		/*
 		 * Make sure the user can only configure tsc_khz values that
@@ -9648,6 +9861,13 @@
 {
 	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;
@@ -9710,11 +9930,18 @@
 
 void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen)
 {
+	struct kvm_vcpu *vcpu;
+	int i;
+
 	/*
 	 * memslots->generation has been incremented.
 	 * mmio generation may have reached its maximum value.
 	 */
 	kvm_mmu_invalidate_mmio_sptes(kvm, gen);
+
+	/* Force re-initialization of steal_time cache */
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vcpu_kick(vcpu);
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
@@ -9722,6 +9949,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;
 }
 
@@ -9966,7 +10197,7 @@
 	      work->arch.cr3 != vcpu->arch.mmu->get_cr3(vcpu))
 		return;
 
-	vcpu->arch.mmu->page_fault(vcpu, work->gva, 0, true);
+	vcpu->arch.mmu->page_fault(vcpu, work->cr2_or_gpa, 0, true);
 }
 
 static inline u32 kvm_async_pf_hash_fn(gfn_t gfn)
@@ -10079,7 +10310,7 @@
 {
 	struct x86_exception fault;
 
-	trace_kvm_async_pf_not_present(work->arch.token, work->gva);
+	trace_kvm_async_pf_not_present(work->arch.token, work->cr2_or_gpa);
 	kvm_add_async_pf_gfn(vcpu, work->arch.gfn);
 
 	if (kvm_can_deliver_async_pf(vcpu) &&
@@ -10114,7 +10345,7 @@
 		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);
+	trace_kvm_async_pf_ready(work->arch.token, work->cr2_or_gpa);
 
 	if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED &&
 	    !apf_get_user(vcpu, &val)) {
@@ -10163,9 +10394,9 @@
 }
 EXPORT_SYMBOL_GPL(kvm_arch_end_assignment);
 
-bool kvm_arch_has_assigned_device(struct kvm *kvm)
+bool noinstr kvm_arch_has_assigned_device(struct kvm *kvm)
 {
-	return atomic_read(&kvm->arch.assigned_device_count);
+	return arch_atomic_read(&kvm->arch.assigned_device_count);
 }
 EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device);
 
@@ -10245,6 +10476,32 @@
 EXPORT_SYMBOL_GPL(kvm_arch_no_poll);
 
 
+int kvm_spec_ctrl_test_value(u64 value)
+{
+	/*
+	 * test that setting IA32_SPEC_CTRL to given value
+	 * is allowed by the host processor
+	 */
+
+	u64 saved_value;
+	unsigned long flags;
+	int ret = 0;
+
+	local_irq_save(flags);
+
+	if (rdmsrl_safe(MSR_IA32_SPEC_CTRL, &saved_value))
+		ret = 1;
+	else if (wrmsrl_safe(MSR_IA32_SPEC_CTRL, value))
+		ret = 1;
+	else
+		wrmsrl(MSR_IA32_SPEC_CTRL, saved_value);
+
+	local_irq_restore(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_spec_ctrl_test_value);
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
--- linux-ein-5.4.0.orig/arch/x86/kvm/x86.h
+++ linux-ein-5.4.0/arch/x86/kvm/x86.h
@@ -286,7 +286,7 @@
 bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
 					  int page_num);
 bool kvm_vector_hashing_enabled(void);
-int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
+int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
 			    int emulation_type, void *insn, int insn_len);
 
 #define KVM_SUPPORTED_XCR0     (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
@@ -368,5 +368,6 @@
 
 void kvm_load_guest_xcr0(struct kvm_vcpu *vcpu);
 void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu);
+int kvm_spec_ctrl_test_value(u64 value);
 
 #endif
--- linux-ein-5.4.0.orig/arch/x86/lib/delay.c
+++ linux-ein-5.4.0/arch/x86/lib/delay.c
@@ -43,8 +43,8 @@
 		"	jnz 2b		\n"
 		"3:	dec %0		\n"
 
-		: /* we don't need output */
-		:"a" (loops)
+		: "+a" (loops)
+		:
 	);
 }
 
--- linux-ein-5.4.0.orig/arch/x86/lib/insn-eval.c
+++ linux-ein-5.4.0/arch/x86/lib/insn-eval.c
@@ -70,14 +70,15 @@
 {
 	int idx = INAT_SEG_REG_DEFAULT;
 	int num_overrides = 0, i;
+	insn_byte_t p;
 
 	insn_get_prefixes(insn);
 
 	/* Look for any segment override prefixes. */
-	for (i = 0; i < insn->prefixes.nbytes; i++) {
+	for_each_insn_prefix(insn, i, p) {
 		insn_attr_t attr;
 
-		attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
+		attr = inat_get_opcode_attribute(p);
 		switch (attr) {
 		case INAT_MAKE_PREFIX(INAT_PFX_CS):
 			idx = INAT_SEG_REG_CS;
--- linux-ein-5.4.0.orig/arch/x86/lib/insn.c
+++ linux-ein-5.4.0/arch/x86/lib/insn.c
@@ -13,6 +13,8 @@
 #include <asm/inat.h>
 #include <asm/insn.h>
 
+#include <asm/emulate_prefix.h>
+
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)	\
 	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@
 		insn->addr_bytes = 4;
 }
 
+static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
+static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
+
+static int __insn_get_emulate_prefix(struct insn *insn,
+				     const insn_byte_t *prefix, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
+			goto err_out;
+	}
+
+	insn->emulate_prefix_size = len;
+	insn->next_byte += len;
+
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static void insn_get_emulate_prefix(struct insn *insn)
+{
+	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
+		return;
+
+	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
+}
+
 /**
  * insn_get_prefixes - scan x86 instruction prefix bytes
  * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@
 	if (prefixes->got)
 		return;
 
+	insn_get_emulate_prefix(insn);
+
 	nb = 0;
 	lb = 0;
 	b = peek_next(insn_byte_t, insn);
--- linux-ein-5.4.0.orig/arch/x86/lib/iomap_copy_64.S
+++ linux-ein-5.4.0/arch/x86/lib/iomap_copy_64.S
@@ -10,6 +10,6 @@
  */
 ENTRY(__iowrite32_copy)
 	movl %edx,%ecx
-	rep movsd
+	rep movsl
 	ret
 ENDPROC(__iowrite32_copy)
--- linux-ein-5.4.0.orig/arch/x86/lib/iomem.c
+++ linux-ein-5.4.0/arch/x86/lib/iomem.c
@@ -22,7 +22,7 @@
 		     : "memory");
 }
 
-void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
+static void string_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
 {
 	if (unlikely(!n))
 		return;
@@ -38,9 +38,8 @@
 	}
 	rep_movs(to, (const void *)from, n);
 }
-EXPORT_SYMBOL(memcpy_fromio);
 
-void memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
+static void string_memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
 {
 	if (unlikely(!n))
 		return;
@@ -56,14 +55,64 @@
 	}
 	rep_movs((void *)to, (const void *) from, n);
 }
+
+static void unrolled_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
+{
+	const volatile char __iomem *in = from;
+	char *out = to;
+	int i;
+
+	for (i = 0; i < n; ++i)
+		out[i] = readb(&in[i]);
+}
+
+static void unrolled_memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
+{
+	volatile char __iomem *out = to;
+	const char *in = from;
+	int i;
+
+	for (i = 0; i < n; ++i)
+		writeb(in[i], &out[i]);
+}
+
+static void unrolled_memset_io(volatile void __iomem *a, int b, size_t c)
+{
+	volatile char __iomem *mem = a;
+	int i;
+
+	for (i = 0; i < c; ++i)
+		writeb(b, &mem[i]);
+}
+
+void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
+{
+	if (sev_key_active())
+		unrolled_memcpy_fromio(to, from, n);
+	else
+		string_memcpy_fromio(to, from, n);
+}
+EXPORT_SYMBOL(memcpy_fromio);
+
+void memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
+{
+	if (sev_key_active())
+		unrolled_memcpy_toio(to, from, n);
+	else
+		string_memcpy_toio(to, from, n);
+}
 EXPORT_SYMBOL(memcpy_toio);
 
 void memset_io(volatile void __iomem *a, int b, size_t c)
 {
-	/*
-	 * TODO: memset can mangle the IO patterns quite a bit.
-	 * perhaps it would be better to use a dumb one:
-	 */
-	memset((void *)a, b, c);
+	if (sev_key_active()) {
+		unrolled_memset_io(a, b, c);
+	} else {
+		/*
+		 * TODO: memset can mangle the IO patterns quite a bit.
+		 * perhaps it would be better to use a dumb one:
+		 */
+		memset((void *)a, b, c);
+	}
 }
 EXPORT_SYMBOL(memset_io);
--- linux-ein-5.4.0.orig/arch/x86/lib/memcpy_64.S
+++ linux-ein-5.4.0/arch/x86/lib/memcpy_64.S
@@ -15,8 +15,6 @@
  * to a jmp to memcpy_erms which does the REP; MOVSB mem copy.
  */
 
-.weak memcpy
-
 /*
  * memcpy - Copy a memory block.
  *
@@ -29,7 +27,7 @@
  * rax original destination
  */
 ENTRY(__memcpy)
-ENTRY(memcpy)
+SYM_FUNC_START_WEAK(memcpy)
 	ALTERNATIVE_2 "jmp memcpy_orig", "", X86_FEATURE_REP_GOOD, \
 		      "jmp memcpy_erms", X86_FEATURE_ERMS
 
--- linux-ein-5.4.0.orig/arch/x86/lib/memmove_64.S
+++ linux-ein-5.4.0/arch/x86/lib/memmove_64.S
@@ -24,9 +24,7 @@
  * Output:
  * rax: dest
  */
-.weak memmove
-
-ENTRY(memmove)
+SYM_FUNC_START_WEAK(memmove)
 ENTRY(__memmove)
 
 	/* Handle more 32 bytes in loop */
--- linux-ein-5.4.0.orig/arch/x86/lib/memset_64.S
+++ linux-ein-5.4.0/arch/x86/lib/memset_64.S
@@ -6,8 +6,6 @@
 #include <asm/alternative-asm.h>
 #include <asm/export.h>
 
-.weak memset
-
 /*
  * ISO C memset - set a memory block to a byte value. This function uses fast
  * string to get better performance than the original function. The code is
@@ -19,7 +17,7 @@
  *
  * rax   original destination
  */
-ENTRY(memset)
+SYM_FUNC_START_WEAK(memset)
 ENTRY(__memset)
 	/*
 	 * Some CPUs support enhanced REP MOVSB/STOSB feature. It is recommended
--- linux-ein-5.4.0.orig/arch/x86/lib/misc.c
+++ linux-ein-5.4.0/arch/x86/lib/misc.c
@@ -6,7 +6,7 @@
  */
 int num_digits(int val)
 {
-	int m = 10;
+	long long m = 10;
 	int d = 1;
 
 	if (val < 0) {
--- linux-ein-5.4.0.orig/arch/x86/lib/mmx_32.c
+++ linux-ein-5.4.0/arch/x86/lib/mmx_32.c
@@ -26,6 +26,16 @@
 #include <asm/fpu/api.h>
 #include <asm/asm.h>
 
+/*
+ * Use KFPU_387.  MMX instructions are not affected by MXCSR,
+ * but both AMD and Intel documentation states that even integer MMX
+ * operations will result in #MF if an exception is pending in FCW.
+ *
+ * EMMS is not needed afterwards because, after calling kernel_fpu_end(),
+ * any subsequent user of the 387 stack will reinitialize it using
+ * KFPU_387.
+ */
+
 void *_mmx_memcpy(void *to, const void *from, size_t len)
 {
 	void *p;
@@ -37,7 +47,7 @@
 	p = to;
 	i = len >> 6; /* len/64 */
 
-	kernel_fpu_begin();
+	kernel_fpu_begin_mask(KFPU_387);
 
 	__asm__ __volatile__ (
 		"1: prefetch (%0)\n"		/* This set is 28 bytes */
@@ -127,7 +137,7 @@
 {
 	int i;
 
-	kernel_fpu_begin();
+	kernel_fpu_begin_mask(KFPU_387);
 
 	__asm__ __volatile__ (
 		"  pxor %%mm0, %%mm0\n" : :
@@ -160,7 +170,7 @@
 {
 	int i;
 
-	kernel_fpu_begin();
+	kernel_fpu_begin_mask(KFPU_387);
 
 	/*
 	 * maybe the prefetch stuff can go before the expensive fnsave...
@@ -247,7 +257,7 @@
 {
 	int i;
 
-	kernel_fpu_begin();
+	kernel_fpu_begin_mask(KFPU_387);
 
 	__asm__ __volatile__ (
 		"  pxor %%mm0, %%mm0\n" : :
@@ -282,7 +292,7 @@
 {
 	int i;
 
-	kernel_fpu_begin();
+	kernel_fpu_begin_mask(KFPU_387);
 
 	__asm__ __volatile__ (
 		"1: prefetch (%0)\n"
--- linux-ein-5.4.0.orig/arch/x86/lib/msr-smp.c
+++ linux-ein-5.4.0/arch/x86/lib/msr-smp.c
@@ -253,7 +253,7 @@
 	rv->err = wrmsr_safe_regs(rv->regs);
 }
 
-int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
+int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
 {
 	int err;
 	struct msr_regs_info rv;
@@ -266,7 +266,7 @@
 }
 EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu);
 
-int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
+int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
 {
 	int err;
 	struct msr_regs_info rv;
--- linux-ein-5.4.0.orig/arch/x86/lib/usercopy_64.c
+++ linux-ein-5.4.0/arch/x86/lib/usercopy_64.c
@@ -24,6 +24,7 @@
 	asm volatile(
 		"	testq  %[size8],%[size8]\n"
 		"	jz     4f\n"
+		"	.align 16\n"
 		"0:	movq $0,(%[dst])\n"
 		"	addq   $8,%[dst]\n"
 		"	decl %%ecx ; jnz   0b\n"
@@ -119,7 +120,7 @@
 	 */
 	if (size < 8) {
 		if (!IS_ALIGNED(dest, 4) || size != 4)
-			clean_cache_range(dst, 1);
+			clean_cache_range(dst, size);
 	} else {
 		if (!IS_ALIGNED(dest, 8)) {
 			dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
@@ -141,7 +142,7 @@
 
 	/* cache copy and flush to align dest */
 	if (!IS_ALIGNED(dest, 8)) {
-		unsigned len = min_t(unsigned, size, ALIGN(dest, 8) - dest);
+		size_t len = min_t(size_t, size, ALIGN(dest, 8) - dest);
 
 		memcpy((void *) dest, (void *) source, len);
 		clean_cache_range((void *) dest, len);
--- linux-ein-5.4.0.orig/arch/x86/lib/x86-opcode-map.txt
+++ linux-ein-5.4.0/arch/x86/lib/x86-opcode-map.txt
@@ -333,7 +333,7 @@
 06: CLTS
 07: SYSRET (o64)
 08: INVD
-09: WBINVD
+09: WBINVD | WBNOINVD (F3)
 0a:
 0b: UD2 (1B)
 0c:
@@ -364,7 +364,7 @@
 # a ModR/M byte.
 1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev
 1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv
-1c:
+1c: Grp20 (1A),(1C)
 1d:
 1e:
 1f: NOP Ev
@@ -792,6 +792,8 @@
 f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
 f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
 f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
+f8: MOVDIR64B Gv,Mdqq (66) | ENQCMD Gv,Mdqq (F2) | ENQCMDS Gv,Mdqq (F3)
+f9: MOVDIRI My,Gy
 EndTable
 
 Table: 3-byte opcode 2 (0x0f 0x3a)
@@ -907,7 +909,7 @@
 
 GrpTable: Grp3_2
 0: TEST Ev,Iz
-1:
+1: TEST Ev,Iz
 2: NOT Ev
 3: NEG Ev
 4: MUL rAX,Ev
@@ -943,9 +945,9 @@
 EndTable
 
 GrpTable: Grp7
-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B)
 3: LIDT Ms
 4: SMSW Mw/Rv
 5: rdpkru (110),(11B) | wrpkru (111),(11B)
@@ -1020,7 +1022,7 @@
 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
 4: XSAVE | ptwrite Ey (F3),(11B)
 5: XRSTOR | lfence (11B)
-6: XSAVEOPT | clwb (66) | mfence (11B)
+6: XSAVEOPT | clwb (66) | mfence (11B) | TPAUSE Rd (66),(11B) | UMONITOR Rv (F3),(11B) | UMWAIT Rd (F2),(11B)
 7: clflush | clflushopt (66) | sfence (11B)
 EndTable
 
@@ -1051,6 +1053,10 @@
 6: vscatterpf1qps/d Wx (66),(ev)
 EndTable
 
+GrpTable: Grp20
+0: cldemote Mb
+EndTable
+
 # AMD's Prefetch Group
 GrpTable: GrpP
 0: PREFETCH
--- linux-ein-5.4.0.orig/arch/x86/math-emu/fpu_system.h
+++ linux-ein-5.4.0/arch/x86/math-emu/fpu_system.h
@@ -107,6 +107,8 @@
 #define FPU_access_ok(y,z)	if ( !access_ok(y,z) ) \
 				math_abort(FPU_info,SIGSEGV)
 #define FPU_abort		math_abort(FPU_info, SIGSEGV)
+#define FPU_copy_from_user(to, from, n)	\
+		do { if (copy_from_user(to, from, n)) FPU_abort; } while (0)
 
 #undef FPU_IGNORE_CODE_SEGV
 #ifdef FPU_IGNORE_CODE_SEGV
@@ -122,7 +124,7 @@
 #define	FPU_code_access_ok(z) FPU_access_ok((void __user *)FPU_EIP,z)
 #endif
 
-#define FPU_get_user(x,y)       get_user((x),(y))
-#define FPU_put_user(x,y)       put_user((x),(y))
+#define FPU_get_user(x,y) do { if (get_user((x),(y))) FPU_abort; } while (0)
+#define FPU_put_user(x,y) do { if (put_user((x),(y))) FPU_abort; } while (0)
 
 #endif
--- linux-ein-5.4.0.orig/arch/x86/math-emu/reg_ld_str.c
+++ linux-ein-5.4.0/arch/x86/math-emu/reg_ld_str.c
@@ -85,7 +85,7 @@
 
 	RE_ENTRANT_CHECK_OFF;
 	FPU_access_ok(s, 10);
-	__copy_from_user(sti_ptr, s, 10);
+	FPU_copy_from_user(sti_ptr, s, 10);
 	RE_ENTRANT_CHECK_ON;
 
 	return FPU_tagof(sti_ptr);
@@ -1126,9 +1126,9 @@
 	/* Copy all registers in stack order. */
 	RE_ENTRANT_CHECK_OFF;
 	FPU_access_ok(s, 80);
-	__copy_from_user(register_base + offset, s, other);
+	FPU_copy_from_user(register_base + offset, s, other);
 	if (offset)
-		__copy_from_user(register_base, s + other, offset);
+		FPU_copy_from_user(register_base, s + other, offset);
 	RE_ENTRANT_CHECK_ON;
 
 	for (i = 0; i < 8; i++) {
--- linux-ein-5.4.0.orig/arch/x86/math-emu/wm_sqrt.S
+++ linux-ein-5.4.0/arch/x86/math-emu/wm_sqrt.S
@@ -209,7 +209,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-ein-5.4.0.orig/arch/x86/mm/cpu_entry_area.c
+++ linux-ein-5.4.0/arch/x86/mm/cpu_entry_area.c
@@ -4,22 +4,72 @@
 #include <linux/percpu.h>
 #include <linux/kallsyms.h>
 #include <linux/kcore.h>
+#include <linux/prandom.h>
 
 #include <asm/cpu_entry_area.h>
 #include <asm/pgtable.h>
 #include <asm/fixmap.h>
 #include <asm/desc.h>
+#include <asm/kasan.h>
+#include <asm/setup.h>
 
 static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage);
 
 #ifdef CONFIG_X86_64
 static DEFINE_PER_CPU_PAGE_ALIGNED(struct exception_stacks, exception_stacks);
 DEFINE_PER_CPU(struct cea_exception_stacks*, cea_exception_stacks);
+
+static DEFINE_PER_CPU_READ_MOSTLY(unsigned long, _cea_offset);
+
+static __always_inline unsigned int cea_offset(unsigned int cpu)
+{
+	return per_cpu(_cea_offset, cpu);
+}
+
+static __init void init_cea_offsets(void)
+{
+	unsigned int max_cea;
+	unsigned int i, j;
+
+	if (!kaslr_enabled()) {
+		for_each_possible_cpu(i)
+			per_cpu(_cea_offset, i) = i;
+		return;
+	}
+
+	max_cea = (CPU_ENTRY_AREA_MAP_SIZE - PAGE_SIZE) / CPU_ENTRY_AREA_SIZE;
+
+	/* O(sodding terrible) */
+	for_each_possible_cpu(i) {
+		unsigned int cea;
+
+again:
+		cea = prandom_u32_max(max_cea);
+
+		for_each_possible_cpu(j) {
+			if (cea_offset(j) == cea)
+				goto again;
+
+			if (i == j)
+				break;
+		}
+
+		per_cpu(_cea_offset, i) = cea;
+	}
+}
+#else /* !X86_64 */
+DECLARE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack);
+
+static __always_inline unsigned int cea_offset(unsigned int cpu)
+{
+	return cpu;
+}
+static inline void init_cea_offsets(void) { }
 #endif
 
 struct cpu_entry_area *get_cpu_entry_area(int cpu)
 {
-	unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE;
+	unsigned long va = CPU_ENTRY_AREA_PER_CPU + cea_offset(cpu) * CPU_ENTRY_AREA_SIZE;
 	BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0);
 
 	return (struct cpu_entry_area *) va;
@@ -135,6 +185,9 @@
 	pgprot_t tss_prot = PAGE_KERNEL;
 #endif
 
+	kasan_populate_shadow_for_vaddr(cea, CPU_ENTRY_AREA_SIZE,
+					early_cpu_to_node(cpu));
+
 	cea_set_pte(&cea->gdt, get_cpu_gdt_paddr(cpu), gdt_prot);
 
 	cea_map_percpu_pages(&cea->entry_stack_page,
@@ -178,7 +231,8 @@
 #ifdef CONFIG_X86_32
 	unsigned long start, end;
 
-	BUILD_BUG_ON(CPU_ENTRY_AREA_PAGES * PAGE_SIZE < CPU_ENTRY_AREA_MAP_SIZE);
+	/* The +1 is for the readonly IDT: */
+	BUILD_BUG_ON((CPU_ENTRY_AREA_PAGES+1)*PAGE_SIZE != CPU_ENTRY_AREA_MAP_SIZE);
 	BUG_ON(CPU_ENTRY_AREA_BASE & ~PMD_MASK);
 
 	start = CPU_ENTRY_AREA_BASE;
@@ -194,6 +248,8 @@
 {
 	unsigned int cpu;
 
+	init_cea_offsets();
+
 	setup_cpu_entry_area_ptes();
 
 	for_each_possible_cpu(cpu)
--- linux-ein-5.4.0.orig/arch/x86/mm/extable.c
+++ linux-ein-5.4.0/arch/x86/mm/extable.c
@@ -45,55 +45,6 @@
 EXPORT_SYMBOL_GPL(ex_handler_fault);
 
 /*
- * Handler for UD0 exception following a failed test against the
- * result of a refcount inc/dec/add/sub.
- */
-__visible bool ex_handler_refcount(const struct exception_table_entry *fixup,
-				   struct pt_regs *regs, int trapnr,
-				   unsigned long error_code,
-				   unsigned long fault_addr)
-{
-	/* First unconditionally saturate the refcount. */
-	*(int *)regs->cx = INT_MIN / 2;
-
-	/*
-	 * Strictly speaking, this reports the fixup destination, not
-	 * the fault location, and not the actually overflowing
-	 * instruction, which is the instruction before the "js", but
-	 * since that instruction could be a variety of lengths, just
-	 * report the location after the overflow, which should be close
-	 * enough for finding the overflow, as it's at least back in
-	 * the function, having returned from .text.unlikely.
-	 */
-	regs->ip = ex_fixup_addr(fixup);
-
-	/*
-	 * This function has been called because either a negative refcount
-	 * value was seen by any of the refcount functions, or a zero
-	 * refcount value was seen by refcount_dec().
-	 *
-	 * If we crossed from INT_MAX to INT_MIN, OF (Overflow Flag: result
-	 * wrapped around) will be set. Additionally, seeing the refcount
-	 * reach 0 will set ZF (Zero Flag: result was zero). In each of
-	 * these cases we want a report, since it's a boundary condition.
-	 * The SF case is not reported since it indicates post-boundary
-	 * manipulations below zero or above INT_MAX. And if none of the
-	 * flags are set, something has gone very wrong, so report it.
-	 */
-	if (regs->flags & (X86_EFLAGS_OF | X86_EFLAGS_ZF)) {
-		bool zero = regs->flags & X86_EFLAGS_ZF;
-
-		refcount_error_report(regs, zero ? "hit zero" : "overflow");
-	} else if ((regs->flags & X86_EFLAGS_SF) == 0) {
-		/* Report if none of OF, ZF, nor SF are set. */
-		refcount_error_report(regs, "unexpected saturation");
-	}
-
-	return true;
-}
-EXPORT_SYMBOL(ex_handler_refcount);
-
-/*
  * Handler for when we fail to restore a task's FPU state.  We should never get
  * here because the FPU state of a task using the FPU (task->thread.fpu.state)
  * should always be valid.  However, past bugs have allowed userspace to set
--- linux-ein-5.4.0.orig/arch/x86/mm/fault.c
+++ linux-ein-5.4.0/arch/x86/mm/fault.c
@@ -189,7 +189,7 @@
 	return pmd_k;
 }
 
-void vmalloc_sync_all(void)
+static void vmalloc_sync(void)
 {
 	unsigned long address;
 
@@ -197,7 +197,7 @@
 		return;
 
 	for (address = VMALLOC_START & PMD_MASK;
-	     address >= TASK_SIZE_MAX && address < FIXADDR_TOP;
+	     address >= TASK_SIZE_MAX && address < VMALLOC_END;
 	     address += PMD_SIZE) {
 		struct page *page;
 
@@ -216,6 +216,16 @@
 	}
 }
 
+void vmalloc_sync_mappings(void)
+{
+	vmalloc_sync();
+}
+
+void vmalloc_sync_unmappings(void)
+{
+	vmalloc_sync();
+}
+
 /*
  * 32-bit:
  *
@@ -318,11 +328,23 @@
 
 #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);
 }
 
+void vmalloc_sync_unmappings(void)
+{
+	/*
+	 * Unmappings never allocate or free p4d/pud pages.
+	 * No work is required here.
+	 */
+}
+
 /*
  * 64-bit:
  *
--- linux-ein-5.4.0.orig/arch/x86/mm/ident_map.c
+++ linux-ein-5.4.0/arch/x86/mm/ident_map.c
@@ -26,18 +26,31 @@
 	for (; addr < end; addr = next) {
 		pud_t *pud = pud_page + pud_index(addr);
 		pmd_t *pmd;
+		bool use_gbpage;
 
 		next = (addr & PUD_MASK) + PUD_SIZE;
 		if (next > end)
 			next = end;
 
-		if (info->direct_gbpages) {
-			pud_t pudval;
+		/* if this is already a gbpage, this portion is already mapped */
+		if (pud_large(*pud))
+			continue;
+
+		/* Is using a gbpage allowed? */
+		use_gbpage = info->direct_gbpages;
 
-			if (pud_present(*pud))
-				continue;
+		/* Don't use gbpage if it maps more than the requested region. */
+		/* at the begining: */
+		use_gbpage &= ((addr & ~PUD_MASK) == 0);
+		/* ... or at the end: */
+		use_gbpage &= ((next & ~PUD_MASK) == 0);
+
+		/* Never overwrite existing mappings */
+		use_gbpage &= !pud_present(*pud);
+
+		if (use_gbpage) {
+			pud_t pudval;
 
-			addr &= PUD_MASK;
 			pudval = __pud((addr - info->offset) | info->page_flag);
 			set_pud(pud, pudval);
 			continue;
@@ -62,6 +75,7 @@
 			  unsigned long addr, unsigned long end)
 {
 	unsigned long next;
+	int result;
 
 	for (; addr < end; addr = next) {
 		p4d_t *p4d = p4d_page + p4d_index(addr);
@@ -73,13 +87,20 @@
 
 		if (p4d_present(*p4d)) {
 			pud = pud_offset(p4d, 0);
-			ident_pud_init(info, pud, addr, next);
+			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;
-		ident_pud_init(info, pud, addr, next);
+
+		result = ident_pud_init(info, pud, addr, next);
+		if (result)
+			return result;
+
 		set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag));
 	}
 
--- linux-ein-5.4.0.orig/arch/x86/mm/init.c
+++ linux-ein-5.4.0/arch/x86/mm/init.c
@@ -7,8 +7,10 @@
 #include <linux/swapops.h>
 #include <linux/kmemleak.h>
 #include <linux/sched/task.h>
+#include <linux/sched/mm.h>
 
 #include <asm/set_memory.h>
+#include <asm/cpu_device_id.h>
 #include <asm/e820/api.h>
 #include <asm/init.h>
 #include <asm/page.h>
@@ -25,6 +27,7 @@
 #include <asm/cpufeature.h>
 #include <asm/pti.h>
 #include <asm/text-patching.h>
+#include <asm/paravirt.h>
 
 /*
  * We need to define the tracepoints somewhere, and tlb.c
@@ -121,8 +124,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++) {
@@ -210,6 +211,24 @@
 	}
 }
 
+#define INTEL_MATCH(_model) { .vendor  = X86_VENDOR_INTEL,	\
+			      .family  = 6,			\
+			      .model = _model,			\
+			    }
+/*
+ * INVLPG may not properly flush Global entries
+ * on these CPUs when PCIDs are enabled.
+ */
+static const struct x86_cpu_id invlpg_miss_ids[] = {
+	INTEL_MATCH(INTEL_FAM6_ALDERLAKE   ),
+	INTEL_MATCH(INTEL_FAM6_ALDERLAKE_L ),
+	INTEL_MATCH(INTEL_FAM6_ALDERLAKE_N ),
+	INTEL_MATCH(INTEL_FAM6_RAPTORLAKE  ),
+	INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_P),
+	INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_S),
+	{}
+};
+
 static void setup_pcid(void)
 {
 	if (!IS_ENABLED(CONFIG_X86_64))
@@ -218,6 +237,12 @@
 	if (!boot_cpu_has(X86_FEATURE_PCID))
 		return;
 
+	if (x86_match_cpu(invlpg_miss_ids)) {
+		pr_info("Incomplete global flushes, disabling PCID");
+		setup_clear_cpu_cap(X86_FEATURE_PCID);
+		return;
+	}
+
 	if (boot_cpu_has(X86_FEATURE_PGE)) {
 		/*
 		 * This can't be cr4_set_bits_and_update_boot() -- the
@@ -712,9 +737,12 @@
 	spinlock_t *ptl;
 	pte_t *ptep;
 
-	poking_mm = copy_init_mm();
+	poking_mm = mm_alloc();
 	BUG_ON(!poking_mm);
 
+	/* Xen PV guests need the PGD to be pinned. */
+	paravirt_arch_dup_mmap(NULL, poking_mm);
+
 	/*
 	 * Randomize the poking address, but make sure that the following page
 	 * will be mapped at the same PMD. We need 2 pages, so find space for 3,
--- linux-ein-5.4.0.orig/arch/x86/mm/init_32.c
+++ linux-ein-5.4.0/arch/x86/mm/init_32.c
@@ -779,6 +779,9 @@
 	 * important here.
 	 */
 	set_highmem_pages_init();
+#ifdef CONFIG_HIGHMEM
+	set_default_mem_hotplug_zone(ZONE_HIGHMEM);
+#endif
 
 	/* this will put all low memory onto the freelists */
 	memblock_free_all();
@@ -865,10 +868,8 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct zone *zone;
 
-	zone = page_zone(pfn_to_page(start_pfn));
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 }
 #endif
 
--- linux-ein-5.4.0.orig/arch/x86/mm/init_64.c
+++ linux-ein-5.4.0/arch/x86/mm/init_64.c
@@ -1212,10 +1212,8 @@
 {
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
-	struct page *page = pfn_to_page(start_pfn) + vmem_altmap_offset(altmap);
-	struct zone *zone = page_zone(page);
 
-	__remove_pages(zone, start_pfn, nr_pages, altmap);
+	__remove_pages(start_pfn, nr_pages, altmap);
 	kernel_physical_mapping_remove(start, start + size);
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
@@ -1357,18 +1355,18 @@
 		return 0;
 
 	p4d = p4d_offset(pgd, addr);
-	if (p4d_none(*p4d))
+	if (!p4d_present(*p4d))
 		return 0;
 
 	pud = pud_offset(p4d, addr);
-	if (pud_none(*pud))
+	if (!pud_present(*pud))
 		return 0;
 
 	if (pud_large(*pud))
 		return pfn_valid(pud_pfn(*pud));
 
 	pmd = pmd_offset(pud, addr);
-	if (pmd_none(*pmd))
+	if (!pmd_present(*pmd))
 		return 0;
 
 	if (pmd_large(*pmd))
--- linux-ein-5.4.0.orig/arch/x86/mm/ioremap.c
+++ linux-ein-5.4.0/arch/x86/mm/ioremap.c
@@ -106,6 +106,24 @@
 	return 0;
 }
 
+/*
+ * The EFI runtime services data area is not covered by walk_mem_res(), but must
+ * be mapped encrypted when SEV is active.
+ */
+static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *desc)
+{
+	if (!sev_active())
+		return;
+
+	if (!IS_ENABLED(CONFIG_EFI))
+		return;
+
+	if (efi_mem_type(addr) == EFI_RUNTIME_SERVICES_DATA ||
+	    (efi_mem_type(addr) == EFI_BOOT_SERVICES_DATA &&
+	     efi_mem_attributes(addr) & EFI_MEMORY_RUNTIME))
+		desc->flags |= IORES_MAP_ENCRYPTED;
+}
+
 static int __ioremap_collect_map_flags(struct resource *res, void *arg)
 {
 	struct ioremap_desc *desc = arg;
@@ -124,6 +142,9 @@
  * To avoid multiple resource walks, this function walks resources marked as
  * IORESOURCE_MEM and IORESOURCE_BUSY and looking for system RAM and/or a
  * resource described not as IORES_DESC_NONE (e.g. IORES_DESC_ACPI_TABLES).
+ *
+ * After that, deal with misc other ranges in __ioremap_check_other() which do
+ * not fall into the above category.
  */
 static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
 				struct ioremap_desc *desc)
@@ -135,6 +156,8 @@
 	memset(desc, 0, sizeof(struct ioremap_desc));
 
 	walk_mem_res(start, end, desc, __ioremap_collect_map_flags);
+
+	__ioremap_check_other(addr, desc);
 }
 
 /*
@@ -193,9 +216,15 @@
 	 * Mappings have to be page-aligned
 	 */
 	offset = phys_addr & ~PAGE_MASK;
-	phys_addr &= PHYSICAL_PAGE_MASK;
+	phys_addr &= PAGE_MASK;
 	size = PAGE_ALIGN(last_addr+1) - phys_addr;
 
+	/*
+	 * Mask out any bits not part of the actual physical
+	 * address, like memory encryption bits.
+	 */
+	phys_addr &= PHYSICAL_PAGE_MASK;
+
 	retval = reserve_memtype(phys_addr, (u64)phys_addr + size,
 						pcm, &new_pcm);
 	if (retval) {
--- linux-ein-5.4.0.orig/arch/x86/mm/kasan_init_64.c
+++ linux-ein-5.4.0/arch/x86/mm/kasan_init_64.c
@@ -293,6 +293,18 @@
 	kasan_map_early_shadow(init_top_pgt);
 }
 
+void __init kasan_populate_shadow_for_vaddr(void *va, size_t size, int nid)
+{
+	unsigned long shadow_start, shadow_end;
+
+	shadow_start = (unsigned long)kasan_mem_to_shadow(va);
+	shadow_start = round_down(shadow_start, PAGE_SIZE);
+	shadow_end = (unsigned long)kasan_mem_to_shadow(va + size);
+	shadow_end = round_up(shadow_end, PAGE_SIZE);
+
+	kasan_populate_shadow(shadow_start, shadow_end, nid);
+}
+
 void __init kasan_init(void)
 {
 	int i;
@@ -356,9 +368,6 @@
 		kasan_mem_to_shadow((void *)PAGE_OFFSET + MAXMEM),
 		shadow_cpu_entry_begin);
 
-	kasan_populate_shadow((unsigned long)shadow_cpu_entry_begin,
-			      (unsigned long)shadow_cpu_entry_end, 0);
-
 	kasan_populate_early_shadow(shadow_cpu_entry_end,
 			kasan_mem_to_shadow((void *)__START_KERNEL_map));
 
--- linux-ein-5.4.0.orig/arch/x86/mm/kaslr.c
+++ linux-ein-5.4.0/arch/x86/mm/kaslr.c
@@ -182,11 +182,11 @@
 		set_p4d(p4d_tramp,
 			__p4d(_KERNPG_TABLE | __pa(pud_page_tramp)));
 
-		set_pgd(&trampoline_pgd_entry,
-			__pgd(_KERNPG_TABLE | __pa(p4d_page_tramp)));
+		trampoline_pgd_entry =
+			__pgd(_KERNPG_TABLE | __pa(p4d_page_tramp));
 	} else {
-		set_pgd(&trampoline_pgd_entry,
-			__pgd(_KERNPG_TABLE | __pa(pud_page_tramp)));
+		trampoline_pgd_entry =
+			__pgd(_KERNPG_TABLE | __pa(pud_page_tramp));
 	}
 }
 
--- linux-ein-5.4.0.orig/arch/x86/mm/mem_encrypt.c
+++ linux-ein-5.4.0/arch/x86/mm/mem_encrypt.c
@@ -229,7 +229,7 @@
 	if (pgprot_val(old_prot) == pgprot_val(new_prot))
 		return;
 
-	pa = pfn << page_level_shift(level);
+	pa = pfn << PAGE_SHIFT;
 	size = page_level_size(level);
 
 	/*
@@ -375,6 +375,7 @@
 
 	return false;
 }
+EXPORT_SYMBOL_GPL(sev_active);
 
 /* Architecture __weak replacement functions */
 void __init mem_encrypt_free_decrypted_mem(void)
--- linux-ein-5.4.0.orig/arch/x86/mm/mem_encrypt_identity.c
+++ linux-ein-5.4.0/arch/x86/mm/mem_encrypt_identity.c
@@ -27,6 +27,15 @@
 #undef CONFIG_PARAVIRT_XXL
 #undef CONFIG_PARAVIRT_SPINLOCKS
 
+/*
+ * This code runs before CPU feature bits are set. By default, the
+ * pgtable_l5_enabled() function uses bit X86_FEATURE_LA57 to determine if
+ * 5-level paging is active, so that won't work here. USE_EARLY_PGTABLE_L5
+ * is provided to handle this situation and, instead, use a variable that
+ * has been set by the early boot code.
+ */
+#define USE_EARLY_PGTABLE_L5
+
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mem_encrypt.h>
@@ -45,8 +54,8 @@
 #define PMD_FLAGS_LARGE		(__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
 
 #define PMD_FLAGS_DEC		PMD_FLAGS_LARGE
-#define PMD_FLAGS_DEC_WP	((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
-				 (_PAGE_PAT | _PAGE_PWT))
+#define PMD_FLAGS_DEC_WP	((PMD_FLAGS_DEC & ~_PAGE_LARGE_CACHE_MASK) | \
+				 (_PAGE_PAT_LARGE | _PAGE_PWT))
 
 #define PMD_FLAGS_ENC		(PMD_FLAGS_LARGE | _PAGE_ENC)
 
@@ -570,7 +579,8 @@
 	cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
 				     ((u64)bp->ext_cmd_line_ptr << 32));
 
-	cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer));
+	if (cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer)) < 0)
+		return;
 
 	if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
 		sme_me_mask = me_mask;
--- linux-ein-5.4.0.orig/arch/x86/mm/mmio-mod.c
+++ linux-ein-5.4.0/arch/x86/mm/mmio-mod.c
@@ -372,7 +372,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;
@@ -402,7 +402,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-ein-5.4.0.orig/arch/x86/mm/numa.c
+++ linux-ein-5.4.0/arch/x86/mm/numa.c
@@ -581,13 +581,6 @@
 		if (start >= end)
 			continue;
 
-		/*
-		 * Don't confuse VM with a node that doesn't have the
-		 * minimum amount of memory:
-		 */
-		if (end && (end - start) < NODE_MIN_SIZE)
-			continue;
-
 		alloc_node_data(nid);
 	}
 
@@ -822,7 +815,7 @@
 		return;
 	}
 	mask = node_to_cpumask_map[node];
-	if (!mask) {
+	if (!cpumask_available(mask)) {
 		pr_err("node_to_cpumask_map[%i] NULL\n", node);
 		dump_stack();
 		return;
@@ -868,7 +861,7 @@
 		dump_stack();
 		return cpu_none_mask;
 	}
-	if (node_to_cpumask_map[node] == NULL) {
+	if (!cpumask_available(node_to_cpumask_map[node])) {
 		printk(KERN_WARNING
 			"cpumask_of_node(%d): no node_to_cpumask_map!\n",
 			node);
--- linux-ein-5.4.0.orig/arch/x86/mm/numa_emulation.c
+++ linux-ein-5.4.0/arch/x86/mm/numa_emulation.c
@@ -321,7 +321,7 @@
 					      u64 addr, u64 max_addr, u64 size)
 {
 	return split_nodes_size_interleave_uniform(ei, pi, addr, max_addr, size,
-			0, NULL, NUMA_NO_NODE);
+			0, NULL, 0);
 }
 
 int __init setup_emu2phys_nid(int *dfl_phys_nid)
--- linux-ein-5.4.0.orig/arch/x86/mm/pageattr.c
+++ linux-ein-5.4.0/arch/x86/mm/pageattr.c
@@ -42,7 +42,8 @@
 	unsigned long	pfn;
 	unsigned int	flags;
 	unsigned int	force_split		: 1,
-			force_static_prot	: 1;
+			force_static_prot	: 1,
+			force_flush_all		: 1;
 	struct page	**pages;
 };
 
@@ -352,10 +353,10 @@
 		return;
 	}
 
-	if (cpa->numpages <= tlb_single_page_flush_ceiling)
-		on_each_cpu(__cpa_flush_tlb, cpa, 1);
-	else
+	if (cpa->force_flush_all || cpa->numpages > tlb_single_page_flush_ceiling)
 		flush_tlb_all();
+	else
+		on_each_cpu(__cpa_flush_tlb, cpa, 1);
 
 	if (!cache)
 		return;
@@ -1584,6 +1585,8 @@
 		alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 		alias_cpa.curpage = 0;
 
+		cpa->force_flush_all = 1;
+
 		ret = __change_page_attr_set_clr(&alias_cpa, 0);
 		if (ret)
 			return ret;
@@ -1604,6 +1607,7 @@
 		alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 		alias_cpa.curpage = 0;
 
+		cpa->force_flush_all = 1;
 		/*
 		 * The high mapping range is imprecise, so ignore the
 		 * return value.
@@ -1963,7 +1967,7 @@
 	/*
 	 * Before changing the encryption attribute, we need to flush caches.
 	 */
-	cpa_flush(&cpa, 1);
+	cpa_flush(&cpa, !this_cpu_has(X86_FEATURE_SME_COHERENT));
 
 	ret = __change_page_attr_set_clr(&cpa, 1);
 
@@ -2215,7 +2219,7 @@
 		.pgd = pgd,
 		.numpages = numpages,
 		.mask_set = __pgprot(0),
-		.mask_clr = __pgprot(0),
+		.mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW)),
 		.flags = 0,
 	};
 
@@ -2224,12 +2228,6 @@
 	if (!(__supported_pte_mask & _PAGE_NX))
 		goto out;
 
-	if (!(page_flags & _PAGE_NX))
-		cpa.mask_clr = __pgprot(_PAGE_NX);
-
-	if (!(page_flags & _PAGE_RW))
-		cpa.mask_clr = __pgprot(_PAGE_RW);
-
 	if (!(page_flags & _PAGE_ENC))
 		cpa.mask_clr = pgprot_encrypted(cpa.mask_clr);
 
--- linux-ein-5.4.0.orig/arch/x86/mm/pat.c
+++ linux-ein-5.4.0/arch/x86/mm/pat.c
@@ -75,7 +75,7 @@
 static int __init pat_debug_setup(char *str)
 {
 	pat_debug_enable = 1;
-	return 0;
+	return 1;
 }
 __setup("debugpat", pat_debug_setup);
 
@@ -1132,12 +1132,14 @@
 
 static void *memtype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	kfree(v);
 	++*pos;
 	return memtype_get_idx(*pos);
 }
 
 static void memtype_seq_stop(struct seq_file *seq, void *v)
 {
+	kfree(v);
 }
 
 static int memtype_seq_show(struct seq_file *seq, void *v)
@@ -1146,7 +1148,6 @@
 
 	seq_printf(seq, "%s @ 0x%Lx-0x%Lx\n", cattr_name(print_entry->type),
 			print_entry->start, print_entry->end);
-	kfree(print_entry);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/x86/mm/pgtable.c
+++ linux-ein-5.4.0/arch/x86/mm/pgtable.c
@@ -643,8 +643,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)
 {
 	/* Sanitize 'prot' against any unsupported bits: */
 	pgprot_val(flags) &= __default_kernel_pte_mask;
@@ -826,6 +826,8 @@
 	}
 
 	free_page((unsigned long)pmd_sv);
+
+	pgtable_pmd_page_dtor(virt_to_page(pmd));
 	free_page((unsigned long)pmd);
 
 	return 1;
--- linux-ein-5.4.0.orig/arch/x86/mm/pkeys.c
+++ linux-ein-5.4.0/arch/x86/mm/pkeys.c
@@ -10,7 +10,6 @@
 
 #include <asm/cpufeature.h>             /* boot_cpu_has, ...            */
 #include <asm/mmu_context.h>            /* vma_pkey()                   */
-#include <asm/fpu/internal.h>		/* init_fpstate			*/
 
 int __execute_only_pkey(struct mm_struct *mm)
 {
@@ -154,7 +153,6 @@
 static ssize_t init_pkru_write_file(struct file *file,
 		 const char __user *user_buf, size_t count, loff_t *ppos)
 {
-	struct pkru_state *pk;
 	char buf[32];
 	ssize_t len;
 	u32 new_init_pkru;
@@ -177,10 +175,6 @@
 		return -EINVAL;
 
 	WRITE_ONCE(init_pkru_value, new_init_pkru);
-	pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU);
-	if (!pk)
-		return -EINVAL;
-	pk->pkru = new_init_pkru;
 	return count;
 }
 
--- linux-ein-5.4.0.orig/arch/x86/mm/tlb.c
+++ linux-ein-5.4.0/arch/x86/mm/tlb.c
@@ -327,8 +327,14 @@
 	/*
 	 * The membarrier system call requires a full memory barrier and
 	 * core serialization before returning to user-space, after
-	 * storing to rq->curr. Writing to CR3 provides that full
-	 * memory barrier and core serializing instruction.
+	 * storing to rq->curr, when changing mm.  This is because
+	 * membarrier() sends IPIs to all CPUs that are in the target mm
+	 * to make them issue memory barriers.  However, if another CPU
+	 * switches to/from the target mm concurrently with
+	 * membarrier(), it can cause that CPU not to receive an IPI
+	 * when it really should issue a memory barrier.  Writing to CR3
+	 * provides that full memory barrier and core serializing
+	 * instruction.
 	 */
 	if (real_prev == next) {
 		VM_WARN_ON(this_cpu_read(cpu_tlbstate.ctxs[prev_asid].ctx_id) !=
--- linux-ein-5.4.0.orig/arch/x86/net/bpf_jit_comp.c
+++ linux-ein-5.4.0/arch/x86/net/bpf_jit_comp.c
@@ -138,6 +138,19 @@
 			     BIT(BPF_REG_AX));
 }
 
+/*
+ * 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));
+}
+
 static bool is_axreg(u32 reg)
 {
 	return reg == BPF_REG_0;
@@ -715,6 +728,13 @@
 			}
 			break;
 
+			/* speculation barrier */
+		case BPF_ST | BPF_NOSPEC:
+			if (boot_cpu_has(X86_FEATURE_XMM2))
+				/* Emit 'lfence' */
+				EMIT3(0x0F, 0xAE, 0xE8);
+			break;
+
 			/* ST: *(u8*)(dst_reg + off) = imm */
 		case BPF_ST | BPF_MEM | BPF_B:
 			if (is_ereg(dst_reg))
@@ -748,9 +768,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) ||
-			    /* We 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);
@@ -1038,7 +1057,16 @@
 		}
 
 		if (image) {
-			if (unlikely(proglen + ilen > oldproglen)) {
+			/*
+			 * 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;
 			}
@@ -1106,7 +1134,7 @@
 		extra_pass = true;
 		goto skip_init_addrs;
 	}
-	addrs = kmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL);
+	addrs = kvmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL);
 	if (!addrs) {
 		prog = orig_prog;
 		goto out_addrs;
@@ -1183,7 +1211,7 @@
 		if (image)
 			bpf_prog_fill_jited_linfo(prog, addrs + 1);
 out_addrs:
-		kfree(addrs);
+		kvfree(addrs);
 		kfree(jit_data);
 		prog->aux->jit_data = NULL;
 	}
--- linux-ein-5.4.0.orig/arch/x86/net/bpf_jit_comp32.c
+++ linux-ein-5.4.0/arch/x86/net/bpf_jit_comp32.c
@@ -1705,6 +1705,12 @@
 			i++;
 			break;
 		}
+		/* speculation barrier */
+		case BPF_ST | BPF_NOSPEC:
+			if (boot_cpu_has(X86_FEATURE_XMM2))
+				/* Emit 'lfence' */
+				EMIT3(0x0F, 0xAE, 0xE8);
+			break;
 		/* ST: *(u8*)(dst_reg + off) = imm */
 		case BPF_ST | BPF_MEM | BPF_H:
 		case BPF_ST | BPF_MEM | BPF_B:
@@ -1847,14 +1853,16 @@
 			case BPF_B:
 			case BPF_H:
 			case BPF_W:
-				if (!bpf_prog->aux->verifier_zext)
+				if (bpf_prog->aux->verifier_zext)
 					break;
 				if (dstk) {
 					EMIT3(0xC7, add_1reg(0x40, IA32_EBP),
 					      STACK_VAR(dst_hi));
 					EMIT(0x0, 4);
 				} else {
-					EMIT3(0xC7, add_1reg(0xC0, dst_hi), 0);
+					/* xor dst_hi,dst_hi */
+					EMIT2(0x33,
+					      add_2reg(0xC0, dst_hi, dst_hi));
 				}
 				break;
 			case BPF_DW:
@@ -2013,8 +2021,8 @@
 		case BPF_JMP | BPF_JSET | BPF_X:
 		case BPF_JMP32 | BPF_JSET | BPF_X: {
 			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
-			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
-			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+			u8 dreg_lo = IA32_EAX;
+			u8 dreg_hi = IA32_EDX;
 			u8 sreg_lo = sstk ? IA32_ECX : src_lo;
 			u8 sreg_hi = sstk ? IA32_EBX : src_hi;
 
@@ -2026,6 +2034,13 @@
 					      add_2reg(0x40, IA32_EBP,
 						       IA32_EDX),
 					      STACK_VAR(dst_hi));
+			} else {
+				/* mov dreg_lo,dst_lo */
+				EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo));
+				if (is_jmp64)
+					/* mov dreg_hi,dst_hi */
+					EMIT2(0x89,
+					      add_2reg(0xC0, dreg_hi, dst_hi));
 			}
 
 			if (sstk) {
@@ -2039,17 +2054,19 @@
 			}
 			/* and dreg_lo,sreg_lo */
 			EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
-			/* and dreg_hi,sreg_hi */
-			EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
-			/* or dreg_lo,dreg_hi */
-			EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+			if (is_jmp64) {
+				/* and dreg_hi,sreg_hi */
+				EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
+				/* or dreg_lo,dreg_hi */
+				EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+			}
 			goto emit_cond_jmp;
 		}
 		case BPF_JMP | BPF_JSET | BPF_K:
 		case BPF_JMP32 | BPF_JSET | BPF_K: {
 			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
-			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
-			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+			u8 dreg_lo = IA32_EAX;
+			u8 dreg_hi = IA32_EDX;
 			u8 sreg_lo = IA32_ECX;
 			u8 sreg_hi = IA32_EBX;
 			u32 hi;
@@ -2062,6 +2079,13 @@
 					      add_2reg(0x40, IA32_EBP,
 						       IA32_EDX),
 					      STACK_VAR(dst_hi));
+			} else {
+				/* mov dreg_lo,dst_lo */
+				EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo));
+				if (is_jmp64)
+					/* mov dreg_hi,dst_hi */
+					EMIT2(0x89,
+					      add_2reg(0xC0, dreg_hi, dst_hi));
 			}
 
 			/* mov ecx,imm32 */
@@ -2260,7 +2284,16 @@
 		}
 
 		if (image) {
-			if (unlikely(proglen + ilen > oldproglen)) {
+			/*
+			 * 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;
 			}
--- linux-ein-5.4.0.orig/arch/x86/pci/common.c
+++ linux-ein-5.4.0/arch/x86/pci/common.c
@@ -33,6 +33,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;
 
@@ -605,6 +606,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;
--- linux-ein-5.4.0.orig/arch/x86/pci/early.c
+++ linux-ein-5.4.0/arch/x86/pci/early.c
@@ -51,6 +51,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-ein-5.4.0.orig/arch/x86/pci/fixup.c
+++ linux-ein-5.4.0/arch/x86/pci/fixup.c
@@ -7,6 +7,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <linux/vgaarb.h>
+#include <asm/amd_nb.h>
 #include <asm/hpet.h>
 #include <asm/pci_x86.h>
 
@@ -572,6 +573,10 @@
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa1ec, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa1ed, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26c, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26d, pci_invalid_bar);
 
 /*
  * Device [1022:7808]
@@ -589,6 +594,17 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7808, pci_fixup_amd_ehci_pme);
 
 /*
+ * 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);
+
+/*
  * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff]
  *
  * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to
@@ -764,4 +780,68 @@
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
 
+#define RS690_LOWER_TOP_OF_DRAM2	0x30
+#define RS690_LOWER_TOP_OF_DRAM2_VALID	0x1
+#define RS690_UPPER_TOP_OF_DRAM2	0x31
+#define RS690_HTIU_NB_INDEX		0xA8
+#define RS690_HTIU_NB_INDEX_WR_ENABLE	0x100
+#define RS690_HTIU_NB_DATA		0xAC
+
+/*
+ * Some BIOS implementations support RAM above 4GB, but do not configure the
+ * PCI host to respond to bus master accesses for these addresses. These
+ * implementations set the TOP_OF_DRAM_SLOT1 register correctly, so PCI DMA
+ * works as expected for addresses below 4GB.
+ *
+ * Reference: "AMD RS690 ASIC Family Register Reference Guide" (pg. 2-57)
+ * https://www.amd.com/system/files/TechDocs/43372_rs690_rrg_3.00o.pdf
+ */
+static void rs690_fix_64bit_dma(struct pci_dev *pdev)
+{
+	u32 val = 0;
+	phys_addr_t top_of_dram = __pa(high_memory - 1) + 1;
+
+	if (top_of_dram <= (1ULL << 32))
+		return;
+
+	pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+				RS690_LOWER_TOP_OF_DRAM2);
+	pci_read_config_dword(pdev, RS690_HTIU_NB_DATA, &val);
+
+	if (val)
+		return;
+
+	pci_info(pdev, "Adjusting top of DRAM to %pa for 64-bit DMA support\n", &top_of_dram);
+
+	pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+		RS690_UPPER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
+	pci_write_config_dword(pdev, RS690_HTIU_NB_DATA, top_of_dram >> 32);
+
+	pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+		RS690_LOWER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
+	pci_write_config_dword(pdev, RS690_HTIU_NB_DATA,
+		top_of_dram | RS690_LOWER_TOP_OF_DRAM2_VALID);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma);
+
+#endif
+
+#ifdef CONFIG_AMD_NB
+
+#define AMD_15B8_RCC_DEV2_EPF0_STRAP2                                  0x10136008
+#define AMD_15B8_RCC_DEV2_EPF0_STRAP2_NO_SOFT_RESET_DEV2_F0_MASK       0x00000080L
+
+static void quirk_clear_strap_no_soft_reset_dev2_f0(struct pci_dev *dev)
+{
+	u32 data;
+
+	if (!amd_smn_read(0, AMD_15B8_RCC_DEV2_EPF0_STRAP2, &data)) {
+		data &= ~AMD_15B8_RCC_DEV2_EPF0_STRAP2_NO_SOFT_RESET_DEV2_F0_MASK;
+		if (amd_smn_write(0, AMD_15B8_RCC_DEV2_EPF0_STRAP2, data))
+			pci_err(dev, "Failed to write data 0x%x\n", data);
+	} else {
+		pci_err(dev, "Failed to read data\n");
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0);
 #endif
--- linux-ein-5.4.0.orig/arch/x86/pci/intel_mid_pci.c
+++ linux-ein-5.4.0/arch/x86/pci/intel_mid_pci.c
@@ -33,6 +33,7 @@
 #include <asm/hw_irq.h>
 #include <asm/io_apic.h>
 #include <asm/intel-mid.h>
+#include <asm/acpi.h>
 
 #define PCIE_CAP_OFFSET	0x100
 
--- linux-ein-5.4.0.orig/arch/x86/pci/xen.c
+++ linux-ein-5.4.0/arch/x86/pci/xen.c
@@ -26,6 +26,7 @@
 #include <asm/xen/pci.h>
 #include <asm/xen/cpuid.h>
 #include <asm/apic.h>
+#include <asm/acpi.h>
 #include <asm/i8259.h>
 
 static int xen_pcifront_enable_irq(struct pci_dev *dev)
@@ -441,6 +442,11 @@
 
 	x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs;
 	x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+	/*
+	 * With XEN PIRQ/Eventchannels in use PCI/MSI[-X] masking is solely
+	 * controlled by the hypervisor.
+	 */
+	pci_msi_ignore_mask = 1;
 }
 #endif
 
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/efi.c
+++ linux-ein-5.4.0/arch/x86/platform/efi/efi.c
@@ -85,6 +85,11 @@
 #ifdef CONFIG_EFI_RCI2_TABLE
 	&rci2_table_phys,
 #endif
+	&efi.tpm_log,
+	&efi.tpm_final_log,
+#ifdef CONFIG_LOAD_UEFI_KEYS
+	&efi.mokvar_table,
+#endif
 };
 
 u64 efi_setup;		/* efi setup_data physical address */
@@ -504,7 +509,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 ||
@@ -529,14 +533,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,
@@ -953,16 +959,14 @@
 
 	if (efi_alloc_page_tables()) {
 		pr_err("Failed to allocate EFI page tables\n");
-		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-		return;
+		goto err;
 	}
 
 	efi_merge_regions();
 	new_memmap = efi_map_regions(&count, &pg_shift);
 	if (!new_memmap) {
 		pr_err("Error reallocating memory, EFI runtime non-functional!\n");
-		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-		return;
+		goto err;
 	}
 
 	pa = __pa(new_memmap);
@@ -976,8 +980,7 @@
 
 	if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) {
 		pr_err("Failed to remap late EFI memory map\n");
-		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-		return;
+		goto err;
 	}
 
 	if (efi_enabled(EFI_DBG)) {
@@ -985,12 +988,11 @@
 		efi_print_memmap();
 	}
 
-	BUG_ON(!efi.systab);
+	if (WARN_ON(!efi.systab))
+		goto err;
 
-	if (efi_setup_page_tables(pa, 1 << pg_shift)) {
-		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-		return;
-	}
+	if (efi_setup_page_tables(pa, 1 << pg_shift))
+		goto err;
 
 	efi_sync_low_kernel_mappings();
 
@@ -1010,9 +1012,9 @@
 	}
 
 	if (status != EFI_SUCCESS) {
-		pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
-			 status);
-		panic("EFI call to SetVirtualAddressMap() failed!");
+		pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
+		       status);
+		goto err;
 	}
 
 	efi_free_boot_services();
@@ -1041,6 +1043,10 @@
 
 	/* clean DUMMY object */
 	efi_delete_dummy_variable();
+	return;
+
+err:
+	clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 }
 
 void __init efi_enter_virtual_mode(void)
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/efi_64.c
+++ linux-ein-5.4.0/arch/x86/platform/efi/efi_64.c
@@ -217,28 +217,30 @@
 	gfp_mask = GFP_KERNEL | __GFP_ZERO;
 	efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER);
 	if (!efi_pgd)
-		return -ENOMEM;
+		goto fail;
 
 	pgd = efi_pgd + pgd_index(EFI_VA_END);
 	p4d = p4d_alloc(&init_mm, pgd, EFI_VA_END);
-	if (!p4d) {
-		free_page((unsigned long)efi_pgd);
-		return -ENOMEM;
-	}
+	if (!p4d)
+		goto free_pgd;
 
 	pud = pud_alloc(&init_mm, p4d, EFI_VA_END);
-	if (!pud) {
-		if (pgtable_l5_enabled())
-			free_page((unsigned long) pgd_page_vaddr(*pgd));
-		free_pages((unsigned long)efi_pgd, PGD_ALLOCATION_ORDER);
-		return -ENOMEM;
-	}
+	if (!pud)
+		goto free_p4d;
 
 	efi_mm.pgd = efi_pgd;
 	mm_init_cpumask(&efi_mm);
 	init_new_context(NULL, &efi_mm);
 
 	return 0;
+
+free_p4d:
+	if (pgtable_l5_enabled())
+		free_page((unsigned long)pgd_page_vaddr(*pgd));
+free_pgd:
+	free_pages((unsigned long)efi_pgd, PGD_ALLOCATION_ORDER);
+fail:
+	return -ENOMEM;
 }
 
 /*
@@ -316,7 +318,7 @@
 static inline phys_addr_t
 virt_to_phys_or_null_size(void *va, unsigned long size)
 {
-	bool bad_size;
+	phys_addr_t pa;
 
 	if (!va)
 		return 0;
@@ -324,16 +326,13 @@
 	if (virt_addr_valid(va))
 		return virt_to_phys(va);
 
-	/*
-	 * A fully aligned variable on the stack is guaranteed not to
-	 * cross a page bounary. Try to catch strings on the stack by
-	 * checking that 'size' is a power of two.
-	 */
-	bad_size = size > PAGE_SIZE || !is_power_of_2(size);
+	pa = slow_virt_to_phys(va);
 
-	WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size);
+	/* check if the object crosses a page boundary */
+	if (WARN_ON((pa ^ (pa + size - 1)) & PAGE_MASK))
+		return 0;
 
-	return slow_virt_to_phys(va);
+	return pa;
 }
 
 #define virt_to_phys_or_null(addr)				\
@@ -392,11 +391,12 @@
 		return 0;
 
 	page = alloc_page(GFP_KERNEL|__GFP_DMA32);
-	if (!page)
-		panic("Unable to allocate EFI runtime stack < 4GB\n");
+	if (!page) {
+		pr_err("Unable to allocate EFI runtime stack < 4GB\n");
+		return 1;
+	}
 
-	efi_scratch.phys_stack = virt_to_phys(page_address(page));
-	efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
+	efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */
 
 	npages = (_etext - _text) >> PAGE_SHIFT;
 	text = __pa(_text);
@@ -790,6 +790,8 @@
 efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
 		       u32 *attr, unsigned long *data_size, void *data)
 {
+	u8 buf[24] __aligned(8);
+	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
 	efi_status_t status;
 	u32 phys_name, phys_vendor, phys_attr;
 	u32 phys_data_size, phys_data;
@@ -797,14 +799,19 @@
 
 	spin_lock_irqsave(&efi_runtime_lock, flags);
 
+	*vnd = *vendor;
+
 	phys_data_size = virt_to_phys_or_null(data_size);
-	phys_vendor = virt_to_phys_or_null(vendor);
+	phys_vendor = virt_to_phys_or_null(vnd);
 	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
 	phys_attr = virt_to_phys_or_null(attr);
 	phys_data = virt_to_phys_or_null_size(data, *data_size);
 
-	status = efi_thunk(get_variable, phys_name, phys_vendor,
-			   phys_attr, phys_data_size, phys_data);
+	if (!phys_name || (data && !phys_data))
+		status = EFI_INVALID_PARAMETER;
+	else
+		status = efi_thunk(get_variable, phys_name, phys_vendor,
+				   phys_attr, phys_data_size, phys_data);
 
 	spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -815,19 +822,25 @@
 efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
 		       u32 attr, unsigned long data_size, void *data)
 {
+	u8 buf[24] __aligned(8);
+	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
 	u32 phys_name, phys_vendor, phys_data;
 	efi_status_t status;
 	unsigned long flags;
 
 	spin_lock_irqsave(&efi_runtime_lock, flags);
 
+	*vnd = *vendor;
+
 	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-	phys_vendor = virt_to_phys_or_null(vendor);
+	phys_vendor = virt_to_phys_or_null(vnd);
 	phys_data = virt_to_phys_or_null_size(data, data_size);
 
-	/* If data_size is > sizeof(u32) we've got problems */
-	status = efi_thunk(set_variable, phys_name, phys_vendor,
-			   attr, data_size, phys_data);
+	if (!phys_name || (data && !phys_data))
+		status = EFI_INVALID_PARAMETER;
+	else
+		status = efi_thunk(set_variable, phys_name, phys_vendor,
+				   attr, data_size, phys_data);
 
 	spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -839,6 +852,8 @@
 				   u32 attr, unsigned long data_size,
 				   void *data)
 {
+	u8 buf[24] __aligned(8);
+	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
 	u32 phys_name, phys_vendor, phys_data;
 	efi_status_t status;
 	unsigned long flags;
@@ -846,13 +861,17 @@
 	if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
 		return EFI_NOT_READY;
 
+	*vnd = *vendor;
+
 	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-	phys_vendor = virt_to_phys_or_null(vendor);
+	phys_vendor = virt_to_phys_or_null(vnd);
 	phys_data = virt_to_phys_or_null_size(data, data_size);
 
-	/* If data_size is > sizeof(u32) we've got problems */
-	status = efi_thunk(set_variable, phys_name, phys_vendor,
-			   attr, data_size, phys_data);
+	if (!phys_name || (data && !phys_data))
+		status = EFI_INVALID_PARAMETER;
+	else
+		status = efi_thunk(set_variable, phys_name, phys_vendor,
+				   attr, data_size, phys_data);
 
 	spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -864,21 +883,29 @@
 			    efi_char16_t *name,
 			    efi_guid_t *vendor)
 {
+	u8 buf[24] __aligned(8);
+	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
 	efi_status_t status;
 	u32 phys_name_size, phys_name, phys_vendor;
 	unsigned long flags;
 
 	spin_lock_irqsave(&efi_runtime_lock, flags);
 
+	*vnd = *vendor;
+
 	phys_name_size = virt_to_phys_or_null(name_size);
-	phys_vendor = virt_to_phys_or_null(vendor);
+	phys_vendor = virt_to_phys_or_null(vnd);
 	phys_name = virt_to_phys_or_null_size(name, *name_size);
 
-	status = efi_thunk(get_next_variable, phys_name_size,
-			   phys_name, phys_vendor);
+	if (!phys_name)
+		status = EFI_INVALID_PARAMETER;
+	else
+		status = efi_thunk(get_next_variable, phys_name_size,
+				   phys_name, phys_vendor);
 
 	spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
+	*vendor = *vnd;
 	return status;
 }
 
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/efi_stub_32.S
+++ linux-ein-5.4.0/arch/x86/platform/efi/efi_stub_32.S
@@ -8,6 +8,7 @@
 
 #include <linux/linkage.h>
 #include <asm/page_types.h>
+#include <asm/nospec-branch.h>
 
 /*
  * efi_call_phys(void *, ...) is a function with variable parameters.
@@ -39,6 +40,7 @@
 	 */
 	movl	$1f, %edx
 	subl	$__PAGE_OFFSET, %edx
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	jmp	*%edx
 1:
 
@@ -74,6 +76,7 @@
 	/*
 	 * 5. Call the physical function.
 	 */
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	jmp	*%ecx
 
 2:
@@ -96,6 +99,7 @@
 	 * adding EIP with PAGE_OFFSET.
 	 */
 	movl	$1f, %edx
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	jmp	*%edx
 1:
 
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/efi_stub_64.S
+++ linux-ein-5.4.0/arch/x86/platform/efi/efi_stub_64.S
@@ -12,6 +12,7 @@
 #include <asm/msr.h>
 #include <asm/processor-flags.h>
 #include <asm/page_types.h>
+#include <asm/nospec-branch.h>
 
 #define SAVE_XMM			\
 	mov %rsp, %rax;			\
@@ -50,6 +51,7 @@
 	mov %r8, %r9
 	mov %rcx, %r8
 	mov %rsi, %rcx
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	call *%rdi
 	addq $48, %rsp
 	RESTORE_XMM
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/efi_thunk_64.S
+++ linux-ein-5.4.0/arch/x86/platform/efi/efi_thunk_64.S
@@ -22,6 +22,7 @@
 #include <linux/linkage.h>
 #include <asm/page_types.h>
 #include <asm/segment.h>
+#include <asm/nospec-branch.h>
 
 	.text
 	.code64
@@ -54,6 +55,7 @@
 
 	leaq	__efi64_thunk(%rip), %rbx
 	subq	%rax, %rbx
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	call	*%rbx
 
 	movq	efi_saved_sp(%rip), %rsp
@@ -135,6 +137,7 @@
 	movl	%eax, %es
 	movl	%eax, %ss
 
+	ANNOTATE_RETPOLINE_SAFE /* FRBS */
 	call	*%edi
 
 	/* We must preserve return value */
--- linux-ein-5.4.0.orig/arch/x86/platform/efi/quirks.c
+++ linux-ein-5.4.0/arch/x86/platform/efi/quirks.c
@@ -260,10 +260,6 @@
 		return;
 	}
 
-	/* No need to reserve regions that will never be freed. */
-	if (md.attribute & EFI_MEMORY_RUNTIME)
-		return;
-
 	size += addr % EFI_PAGE_SIZE;
 	size = round_up(size, EFI_PAGE_SIZE);
 	addr = round_down(addr, EFI_PAGE_SIZE);
@@ -283,7 +279,8 @@
 		return;
 	}
 
-	new = early_memremap(new_phys, new_size);
+	new = early_memremap_prot(new_phys, new_size,
+				  pgprot_val(pgprot_encrypted(FIXMAP_PAGE_NORMAL)));
 	if (!new) {
 		pr_err("Failed to map new boot services memmap\n");
 		return;
@@ -293,6 +290,8 @@
 	early_memunmap(new, new_size);
 
 	efi_memmap_install(new_phys, num_entries);
+	e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED);
+	e820__update_table(e820_table);
 }
 
 /*
--- linux-ein-5.4.0.orig/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ linux-ein-5.4.0/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -81,7 +81,7 @@
 		return;
 	}
 
-	if (!!test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == state)
+	if (test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == !!state)
 		return; /* Nothing new to report. */
 
 	input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
--- linux-ein-5.4.0.orig/arch/x86/platform/olpc/olpc.c
+++ linux-ein-5.4.0/arch/x86/platform/olpc/olpc.c
@@ -274,7 +274,7 @@
 
 static struct olpc_ec_driver ec_xo1_5_driver = {
 	.ec_cmd = olpc_xo1_ec_cmd,
-#ifdef CONFIG_OLPC_XO1_5_SCI
+#ifdef CONFIG_OLPC_XO15_SCI
 	/*
 	 * XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
 	 * compiled in
--- linux-ein-5.4.0.orig/arch/x86/platform/pvh/head.S
+++ linux-ein-5.4.0/arch/x86/platform/pvh/head.S
@@ -16,6 +16,7 @@
 #include <asm/boot.h>
 #include <asm/processor-flags.h>
 #include <asm/msr.h>
+#include <asm/nospec-branch.h>
 #include <xen/interface/elfnote.h>
 
 	__HEAD
@@ -105,6 +106,7 @@
 	/* startup_64 expects boot_params in %rsi. */
 	mov $_pa(pvh_bootparams), %rsi
 	mov $_pa(startup_64), %rax
+	ANNOTATE_RETPOLINE_SAFE
 	jmp *%rax
 
 #else /* CONFIG_X86_64 */
--- linux-ein-5.4.0.orig/arch/x86/platform/uv/uv_irq.c
+++ linux-ein-5.4.0/arch/x86/platform/uv/uv_irq.c
@@ -167,9 +167,10 @@
 		goto out;
 
 	uv_domain = irq_domain_create_tree(fn, &uv_domain_ops, NULL);
-	irq_domain_free_fwnode(fn);
 	if (uv_domain)
 		uv_domain->parent = x86_vector_domain;
+	else
+		irq_domain_free_fwnode(fn);
 out:
 	mutex_unlock(&uv_lock);
 
--- linux-ein-5.4.0.orig/arch/x86/power/cpu.c
+++ linux-ein-5.4.0/arch/x86/power/cpu.c
@@ -25,6 +25,7 @@
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
 #include <asm/cpu_device_id.h>
+#include <asm/microcode.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -40,7 +41,8 @@
 	struct saved_msr *end = msr + ctxt->saved_msrs.num;
 
 	while (msr < end) {
-		msr->valid = !rdmsrl_safe(msr->info.msr_no, &msr->info.reg.q);
+		if (msr->valid)
+			rdmsrl(msr->info.msr_no, msr->info.reg.q);
 		msr++;
 	}
 }
@@ -262,6 +264,13 @@
 	x86_platform.restore_sched_clock_state();
 	mtrr_bp_restore();
 	perf_restore_debug_store();
+
+	microcode_bsp_resume();
+
+	/*
+	 * This needs to happen after the microcode has been updated upon resume
+	 * because some of the MSRs are "emulated" in microcode.
+	 */
 	msr_restore_context(ctxt);
 }
 
@@ -421,8 +430,10 @@
 	}
 
 	for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
+		u64 dummy;
+
 		msr_array[i].info.msr_no	= msr_id[j];
-		msr_array[i].valid		= false;
+		msr_array[i].valid		= !rdmsrl_safe(msr_id[j], &dummy);
 		msr_array[i].info.reg.q		= 0;
 	}
 	saved_msrs->num   = total_num;
@@ -509,10 +520,32 @@
 	return ret;
 }
 
+static void pm_save_spec_msr(void)
+{
+	struct msr_enumeration {
+		u32 msr_no;
+		u32 feature;
+	} msr_enum[] = {
+		{ MSR_IA32_SPEC_CTRL,	 X86_FEATURE_MSR_SPEC_CTRL },
+		{ MSR_IA32_TSX_CTRL,	 X86_FEATURE_MSR_TSX_CTRL },
+		{ MSR_TSX_FORCE_ABORT,	 X86_FEATURE_TSX_FORCE_ABORT },
+		{ MSR_IA32_MCU_OPT_CTRL, X86_FEATURE_SRBDS_CTRL },
+		{ MSR_AMD64_LS_CFG,	 X86_FEATURE_LS_CFG_SSBD },
+		{ MSR_AMD64_DE_CFG,	 X86_FEATURE_LFENCE_RDTSC },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msr_enum); i++) {
+		if (boot_cpu_has(msr_enum[i].feature))
+			msr_build_context(&msr_enum[i].msr_no, 1);
+	}
+}
+
 static int pm_check_save_msr(void)
 {
 	dmi_check_system(msr_save_dmi_table);
 	pm_cpu_check(msr_save_cpu_table);
+	pm_save_spec_msr();
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/x86/power/hibernate_asm_32.S
+++ linux-ein-5.4.0/arch/x86/power/hibernate_asm_32.S
@@ -35,7 +35,7 @@
 	ret
 ENDPROC(swsusp_arch_suspend)
 
-ENTRY(restore_image)
+SYM_CODE_START(restore_image)
 	/* prepare to jump to the image kernel */
 	movl	restore_jump_address, %ebx
 	movl	restore_cr3, %ebp
@@ -45,9 +45,10 @@
 	/* jump to relocated restore code */
 	movl	relocated_restore_code, %eax
 	jmpl	*%eax
+SYM_CODE_END(restore_image)
 
 /* code below has been relocated to a safe page */
-ENTRY(core_restore_code)
+SYM_CODE_START(core_restore_code)
 	movl	temp_pgt, %eax
 	movl	%eax, %cr3
 
@@ -77,6 +78,7 @@
 
 done:
 	jmpl	*%ebx
+SYM_CODE_END(core_restore_code)
 
 	/* code below belongs to the image kernel */
 	.align PAGE_SIZE
--- linux-ein-5.4.0.orig/arch/x86/power/hibernate_asm_64.S
+++ linux-ein-5.4.0/arch/x86/power/hibernate_asm_64.S
@@ -21,6 +21,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
 #include <asm/frame.h>
+#include <asm/nospec-branch.h>
 
 ENTRY(swsusp_arch_suspend)
 	movq	$saved_context, %rax
@@ -66,6 +67,7 @@
 
 	/* 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 */
@@ -96,6 +98,7 @@
 
 .Ldone:
 	/* jump to the restore_registers address from the image header */
+	ANNOTATE_RETPOLINE_SAFE
 	jmpq	*%r8
 
 	 /* code below belongs to the image kernel */
--- linux-ein-5.4.0.orig/arch/x86/purgatory/Makefile
+++ linux-ein-5.4.0/arch/x86/purgatory/Makefile
@@ -14,18 +14,26 @@
 
 CFLAGS_sha256.o := -D__DISABLE_EXPORTS
 
+# When profile-guided optimization is enabled, llvm emits two different
+# overlapping text sections, which is not supported by kexec. Remove profile
+# optimization flags.
+KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
+
 LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib
 targets += purgatory.ro
 
+# Sanitizer, etc. runtimes are unavailable and cannot be linked here.
+GCOV_PROFILE	:= n
 KASAN_SANITIZE	:= n
+UBSAN_SANITIZE	:= n
 KCOV_INSTRUMENT := n
 
 # These are adjustments to the compiler flags used for objects that
 # make up the standalone purgatory.ro
 
 PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
-PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss
-PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN)
+PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss -g0
+PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING
 
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
@@ -55,6 +63,9 @@
 CFLAGS_REMOVE_string.o		+= $(PURGATORY_CFLAGS_REMOVE)
 CFLAGS_string.o			+= $(PURGATORY_CFLAGS)
 
+AFLAGS_REMOVE_setup-x86_$(BITS).o	+= -g -Wa,-gdwarf-2
+AFLAGS_REMOVE_entry64.o			+= -g -Wa,-gdwarf-2
+
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
 		$(call if_changed,ld)
 
--- linux-ein-5.4.0.orig/arch/x86/realmode/init.c
+++ linux-ein-5.4.0/arch/x86/realmode/init.c
@@ -8,6 +8,7 @@
 #include <asm/pgtable.h>
 #include <asm/realmode.h>
 #include <asm/tlbflush.h>
+#include <asm/crash.h>
 
 struct real_mode_header *real_mode_header;
 u32 *trampoline_cr4_features;
@@ -15,6 +16,32 @@
 /* Hold the pgd entry used on booting additional CPUs */
 pgd_t trampoline_pgd_entry;
 
+void load_trampoline_pgtable(void)
+{
+#ifdef CONFIG_X86_32
+	load_cr3(initial_page_table);
+#else
+	/*
+	 * This function is called before exiting to real-mode and that will
+	 * fail with CR4.PCIDE still set.
+	 */
+	if (boot_cpu_has(X86_FEATURE_PCID))
+		cr4_clear_bits(X86_CR4_PCIDE);
+
+	write_cr3(real_mode_header->trampoline_pgd);
+#endif
+
+	/*
+	 * The CR3 write above will not flush global TLB entries.
+	 * Stale, global entries from previous page tables may still be
+	 * present.  Flush those stale entries.
+	 *
+	 * This ensures that memory accessed while running with
+	 * trampoline_pgd is *actually* mapped into trampoline_pgd.
+	 */
+	__flush_tlb_all();
+}
+
 void __init reserve_real_mode(void)
 {
 	phys_addr_t mem;
@@ -34,6 +61,7 @@
 
 	memblock_reserve(mem, size);
 	set_real_mode_mem(mem);
+	crash_reserve_low_1M();
 }
 
 static void __init setup_real_mode(void)
@@ -48,6 +76,7 @@
 #ifdef CONFIG_X86_64
 	u64 *trampoline_pgd;
 	u64 efer;
+	int i;
 #endif
 
 	base = (unsigned char *)real_mode_header;
@@ -106,8 +135,17 @@
 		trampoline_header->flags |= TH_FLAGS_SME_ACTIVE;
 
 	trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
+
+	/* Map the real mode stub as virtual == physical */
 	trampoline_pgd[0] = trampoline_pgd_entry.pgd;
-	trampoline_pgd[511] = init_top_pgt[511].pgd;
+
+	/*
+	 * Include the entirety of the kernel mapping into the trampoline
+	 * PGD.  This way, all mappings present in the normal kernel page
+	 * tables are usable while running on trampoline_pgd.
+	 */
+	for (i = pgd_index(__PAGE_OFFSET); i < PTRS_PER_PGD; i++)
+		trampoline_pgd[i] = init_top_pgt[i].pgd;
 #endif
 }
 
--- linux-ein-5.4.0.orig/arch/x86/realmode/rm/trampoline_32.S
+++ linux-ein-5.4.0/arch/x86/realmode/rm/trampoline_32.S
@@ -23,13 +23,14 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page_types.h>
+#include <asm/nospec-branch.h>
 #include "realmode.h"
 
 	.text
 	.code16
 
 	.balign	PAGE_SIZE
-ENTRY(trampoline_start)
+SYM_CODE_START(trampoline_start)
 	wbinvd			# Needed for NUMA-Q should be harmless for others
 
 	LJMPW_RM(1f)
@@ -54,11 +55,14 @@
 	lmsw	%dx			# into protected mode
 
 	ljmpl	$__BOOT_CS, $pa_startup_32
+SYM_CODE_END(trampoline_start)
 
 	.section ".text32","ax"
 	.code32
-ENTRY(startup_32)			# note: also used from wakeup_asm.S
+SYM_CODE_START(startup_32)			# note: also used from wakeup_asm.S
+	ANNOTATE_RETPOLINE_SAFE
 	jmp	*%eax
+SYM_CODE_END(startup_32)
 
 	.bss
 	.balign 8
--- linux-ein-5.4.0.orig/arch/x86/realmode/rm/wakeup_asm.S
+++ linux-ein-5.4.0/arch/x86/realmode/rm/wakeup_asm.S
@@ -73,7 +73,7 @@
 	movw	%ax, %fs
 	movw	%ax, %gs
 
-	lidtl	wakeup_idt
+	lidtl	.Lwakeup_idt
 
 	/* Clear the EFLAGS */
 	pushl $0
@@ -171,8 +171,8 @@
 
 	/* This is the standard real-mode IDT */
 	.balign	16
-GLOBAL(wakeup_idt)
+.Lwakeup_idt:
 	.word	0xffff		/* limit */
 	.long	0		/* address */
 	.word	0
-END(wakeup_idt)
+END(.Lwakeup_idt)
--- linux-ein-5.4.0.orig/arch/x86/tools/chkobjdump.awk
+++ linux-ein-5.4.0/arch/x86/tools/chkobjdump.awk
@@ -10,6 +10,7 @@
 
 /^GNU objdump/ {
 	verstr = ""
+	gsub(/\(.*\)/, "");
 	for (i = 3; i <= NF; i++)
 		if (match($(i), "^[0-9]")) {
 			verstr = $(i);
--- linux-ein-5.4.0.orig/arch/x86/tools/gen-insn-attr-x86.awk
+++ linux-ein-5.4.0/arch/x86/tools/gen-insn-attr-x86.awk
@@ -69,7 +69,7 @@
 
 	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
 
@@ -257,7 +257,7 @@
 	return add_flags(imm, mod)
 }
 
-/^[0-9a-f]+\:/ {
+/^[0-9a-f]+:/ {
 	if (NR == 1)
 		next
 	# get index
--- linux-ein-5.4.0.orig/arch/x86/tools/relocs.c
+++ linux-ein-5.4.0/arch/x86/tools/relocs.c
@@ -867,9 +867,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;
 
@@ -910,9 +912,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;
 
--- linux-ein-5.4.0.orig/arch/x86/um/ldt.c
+++ linux-ein-5.4.0/arch/x86/um/ldt.c
@@ -23,9 +23,11 @@
 {
 	long res;
 	void *stub_addr;
+
+	BUILD_BUG_ON(sizeof(*desc) % sizeof(long));
+
 	res = syscall_stub_data(mm_idp, (unsigned long *)desc,
-				(sizeof(*desc) + sizeof(long) - 1) &
-				    ~(sizeof(long) - 1),
+				sizeof(*desc) / sizeof(long),
 				addr, &stub_addr);
 	if (!res) {
 		unsigned long args[] = { func,
--- linux-ein-5.4.0.orig/arch/x86/um/shared/sysdep/syscalls_32.h
+++ linux-ein-5.4.0/arch/x86/um/shared/sysdep/syscalls_32.h
@@ -6,10 +6,9 @@
 #include <asm/unistd.h>
 #include <sysdep/ptrace.h>
 
-typedef long syscall_handler_t(struct pt_regs);
+typedef long syscall_handler_t(struct syscall_args);
 
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
-	((long (*)(struct syscall_args)) \
-	 (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
+	((*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
--- linux-ein-5.4.0.orig/arch/x86/um/shared/sysdep/syscalls_64.h
+++ linux-ein-5.4.0/arch/x86/um/shared/sysdep/syscalls_64.h
@@ -10,13 +10,12 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 
-typedef long syscall_handler_t(void);
+typedef long syscall_handler_t(long, long, long, long, long, long);
 
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
-	(((long (*)(long, long, long, long, long, long)) \
-	  (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(&regs->regs), \
+	(((*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(&regs->regs), \
 		 		      UPT_SYSCALL_ARG2(&regs->regs), \
 				      UPT_SYSCALL_ARG3(&regs->regs), \
 				      UPT_SYSCALL_ARG4(&regs->regs), \
--- linux-ein-5.4.0.orig/arch/x86/um/syscalls_64.c
+++ linux-ein-5.4.0/arch/x86/um/syscalls_64.c
@@ -11,6 +11,7 @@
 #include <linux/uaccess.h>
 #include <asm/prctl.h> /* XXX This should get the constants from libc */
 #include <os.h>
+#include <registers.h>
 
 long arch_prctl(struct task_struct *task, int option,
 		unsigned long __user *arg2)
@@ -35,7 +36,7 @@
 	switch (option) {
 	case ARCH_SET_FS:
 	case ARCH_SET_GS:
-		ret = restore_registers(pid, &current->thread.regs.regs);
+		ret = restore_pid_registers(pid, &current->thread.regs.regs);
 		if (ret)
 			return ret;
 		break;
--- linux-ein-5.4.0.orig/arch/x86/um/tls_32.c
+++ linux-ein-5.4.0/arch/x86/um/tls_32.c
@@ -65,9 +65,6 @@
 	struct thread_struct *t = &task->thread;
 	int idx;
 
-	if (!t->arch.tls_array)
-		return GDT_ENTRY_TLS_MIN;
-
 	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
 		if (!t->arch.tls_array[idx].present)
 			return idx + GDT_ENTRY_TLS_MIN;
@@ -215,14 +212,12 @@
 	return 0;
 }
 
-int arch_copy_tls(struct task_struct *new)
+int arch_set_tls(struct task_struct *new, unsigned long tls)
 {
 	struct user_desc info;
 	int idx, ret = -EFAULT;
 
-	if (copy_from_user(&info,
-			   (void __user *) UPT_SI(&new->thread.regs.regs),
-			   sizeof(info)))
+	if (copy_from_user(&info, (void __user *) tls, sizeof(info)))
 		goto out;
 
 	ret = -EINVAL;
@@ -242,9 +237,6 @@
 {
 	struct thread_struct *t = &task->thread;
 
-	if (!t->arch.tls_array)
-		goto clear;
-
 	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
 		return -EINVAL;
 
--- linux-ein-5.4.0.orig/arch/x86/um/tls_64.c
+++ linux-ein-5.4.0/arch/x86/um/tls_64.c
@@ -6,14 +6,13 @@
 {
 }
 
-int arch_copy_tls(struct task_struct *t)
+int arch_set_tls(struct task_struct *t, unsigned long tls)
 {
 	/*
 	 * If CLONE_SETTLS is set, we need to save the thread id
-	 * (which is argument 5, child_tid, of clone) so it can be set
-	 * during context switches.
+	 * so it can be set during context switches.
 	 */
-	t->thread.arch.fs = t->thread.regs.regs.gp[R8 / sizeof(long)];
+	t->thread.arch.fs = tls;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/arch/x86/um/vdso/Makefile
+++ linux-ein-5.4.0/arch/x86/um/vdso/Makefile
@@ -62,7 +62,7 @@
 		       -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
 		 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
-VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv
+VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv -z noexecstack
 GCOV_PROFILE := n
 
 #
--- linux-ein-5.4.0.orig/arch/x86/um/vdso/um_vdso.c
+++ linux-ein-5.4.0/arch/x86/um/vdso/um_vdso.c
@@ -17,8 +17,10 @@
 {
 	long ret;
 
-	asm("syscall" : "=a" (ret) :
-		"0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory");
+	asm("syscall"
+		: "=a" (ret)
+		: "0" (__NR_clock_gettime), "D" (clock), "S" (ts)
+		: "rcx", "r11", "memory");
 
 	return ret;
 }
@@ -29,8 +31,10 @@
 {
 	long ret;
 
-	asm("syscall" : "=a" (ret) :
-		"0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+	asm("syscall"
+		: "=a" (ret)
+		: "0" (__NR_gettimeofday), "D" (tv), "S" (tz)
+		: "rcx", "r11", "memory");
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/arch/x86/xen/enlighten_hvm.c
+++ linux-ein-5.4.0/arch/x86/xen/enlighten_hvm.c
@@ -175,6 +175,8 @@
        return 0;
 }
 
+static bool no_vector_callback __initdata;
+
 static void __init xen_hvm_guest_init(void)
 {
 	if (xen_pv_domain())
@@ -194,7 +196,7 @@
 
 	xen_panic_handler_init();
 
-	if (xen_feature(XENFEAT_hvm_callback_vector))
+	if (!no_vector_callback && xen_feature(XENFEAT_hvm_callback_vector))
 		xen_have_vector_callback = 1;
 
 	xen_hvm_smp_init();
@@ -220,6 +222,13 @@
 }
 early_param("xen_nopv", xen_parse_nopv);
 
+static __init int xen_parse_no_vector_callback(char *arg)
+{
+	no_vector_callback = true;
+	return 0;
+}
+early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
+
 bool __init xen_hvm_need_lapic(void)
 {
 	if (xen_pv_domain())
--- linux-ein-5.4.0.orig/arch/x86/xen/enlighten_pv.c
+++ linux-ein-5.4.0/arch/x86/xen/enlighten_pv.c
@@ -727,8 +727,8 @@
 	preempt_enable();
 }
 
-static void xen_convert_trap_info(const struct desc_ptr *desc,
-				  struct trap_info *traps)
+static unsigned xen_convert_trap_info(const struct desc_ptr *desc,
+				      struct trap_info *traps, bool full)
 {
 	unsigned in, out, count;
 
@@ -738,17 +738,18 @@
 	for (in = out = 0; in < count; in++) {
 		gate_desc *entry = (gate_desc *)(desc->address) + in;
 
-		if (cvt_gate_to_trap(in, entry, &traps[out]))
+		if (cvt_gate_to_trap(in, entry, &traps[out]) || full)
 			out++;
 	}
-	traps[out].address = 0;
+
+	return out;
 }
 
 void xen_copy_trap_info(struct trap_info *traps)
 {
 	const struct desc_ptr *desc = this_cpu_ptr(&idt_desc);
 
-	xen_convert_trap_info(desc, traps);
+	xen_convert_trap_info(desc, traps, true);
 }
 
 /* Load a new IDT into Xen.  In principle this can be per-CPU, so we
@@ -758,6 +759,7 @@
 {
 	static DEFINE_SPINLOCK(lock);
 	static struct trap_info traps[257];
+	unsigned out;
 
 	trace_xen_cpu_load_idt(desc);
 
@@ -765,7 +767,8 @@
 
 	memcpy(this_cpu_ptr(&idt_desc), desc, sizeof(idt_desc));
 
-	xen_convert_trap_info(desc, traps);
+	out = xen_convert_trap_info(desc, traps, false);
+	memset(&traps[out], 0, sizeof(traps[0]));
 
 	xen_mc_flush();
 	if (HYPERVISOR_set_trap_table(traps))
@@ -905,14 +908,15 @@
 static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
 {
 	int ret;
+#ifdef CONFIG_X86_64
+	unsigned int which;
+	u64 base;
+#endif
 
 	ret = 0;
 
 	switch (msr) {
 #ifdef CONFIG_X86_64
-		unsigned which;
-		u64 base;
-
 	case MSR_FS_BASE:		which = SEGBASE_FS; goto set;
 	case MSR_KERNEL_GS_BASE:	which = SEGBASE_GS_USER; goto set;
 	case MSR_GS_BASE:		which = SEGBASE_GS_KERNEL; goto set;
@@ -1182,6 +1186,11 @@
 	x86_platform.legacy.rtc = 1;
 }
 
+static void __init xen_domu_set_legacy_features(void)
+{
+	x86_platform.legacy.rtc = 0;
+}
+
 /* First C function to be called on Xen boot */
 asmlinkage __visible void __init xen_start_kernel(void)
 {
@@ -1215,6 +1224,7 @@
 	x86_platform.get_nmi_reason = xen_get_nmi_reason;
 
 	x86_init.resources.memory_setup = xen_memory_setup;
+	x86_init.irqs.intr_mode_select	= x86_init_noop;
 	x86_init.irqs.intr_mode_init	= x86_init_noop;
 	x86_init.oem.arch_setup = xen_arch_setup;
 	x86_init.oem.banner = xen_banner;
@@ -1351,6 +1361,8 @@
 		add_preferred_console("xenboot", 0, NULL);
 		if (pci_xen)
 			x86_init.pci.arch_init = pci_xen_init;
+		x86_platform.set_legacy_features =
+				xen_domu_set_legacy_features;
 	} else {
 		const struct dom0_vga_console_info *info =
 			(void *)((char *)xen_start_info +
@@ -1380,6 +1392,15 @@
 		x86_init.mpparse.get_smp_config = x86_init_uint_noop;
 
 		xen_boot_params_init_edd();
+
+#ifdef CONFIG_ACPI
+		/*
+		 * Disable selecting "Firmware First mode" for correctable
+		 * memory errors, as this is the duty of the hypervisor to
+		 * decide.
+		 */
+		acpi_disable_cmcff = 1;
+#endif
 	}
 
 	if (!boot_params.screen_info.orig_video_isVGA)
--- linux-ein-5.4.0.orig/arch/x86/xen/p2m.c
+++ linux-ein-5.4.0/arch/x86/xen/p2m.c
@@ -622,8 +622,8 @@
 	}
 
 	/* Expanded the p2m? */
-	if (pfn > xen_p2m_last_pfn) {
-		xen_p2m_last_pfn = pfn;
+	if (pfn >= xen_p2m_last_pfn) {
+		xen_p2m_last_pfn = ALIGN(pfn + 1, P2M_PER_PAGE);
 		HYPERVISOR_shared_info->arch.max_pfn = xen_p2m_last_pfn;
 	}
 
@@ -714,9 +714,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) {
@@ -730,10 +733,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:
@@ -754,17 +793,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-ein-5.4.0.orig/arch/x86/xen/pmu.c
+++ linux-ein-5.4.0/arch/x86/xen/pmu.c
@@ -512,10 +512,7 @@
 	return ret;
 }
 
-bool is_xen_pmu(int cpu)
-{
-	return (get_xenpmu_data() != NULL);
-}
+bool is_xen_pmu;
 
 void xen_pmu_init(int cpu)
 {
@@ -526,7 +523,7 @@
 
 	BUILD_BUG_ON(sizeof(struct xen_pmu_data) > PAGE_SIZE);
 
-	if (xen_hvm_domain())
+	if (xen_hvm_domain() || (cpu != 0 && !is_xen_pmu))
 		return;
 
 	xenpmu_data = (struct xen_pmu_data *)get_zeroed_page(GFP_KERNEL);
@@ -547,7 +544,8 @@
 	per_cpu(xenpmu_shared, cpu).xenpmu_data = xenpmu_data;
 	per_cpu(xenpmu_shared, cpu).flags = 0;
 
-	if (cpu == 0) {
+	if (!is_xen_pmu) {
+		is_xen_pmu = true;
 		perf_register_guest_info_callbacks(&xen_guest_cbs);
 		xen_pmu_arch_init();
 	}
--- linux-ein-5.4.0.orig/arch/x86/xen/pmu.h
+++ linux-ein-5.4.0/arch/x86/xen/pmu.h
@@ -4,6 +4,8 @@
 
 #include <xen/interface/xenpmu.h>
 
+extern bool is_xen_pmu;
+
 irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id);
 #ifdef CONFIG_XEN_HAVE_VPMU
 void xen_pmu_init(int cpu);
@@ -12,7 +14,6 @@
 static inline void xen_pmu_init(int cpu) {}
 static inline void xen_pmu_finish(int cpu) {}
 #endif
-bool is_xen_pmu(int cpu);
 bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err);
 bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err);
 int pmu_apic_update(uint32_t reg);
--- linux-ein-5.4.0.orig/arch/x86/xen/smp.c
+++ linux-ein-5.4.0/arch/x86/xen/smp.c
@@ -32,30 +32,30 @@
 
 void xen_smp_intr_free(unsigned int cpu)
 {
+	kfree(per_cpu(xen_resched_irq, cpu).name);
+	per_cpu(xen_resched_irq, cpu).name = NULL;
 	if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
 		per_cpu(xen_resched_irq, cpu).irq = -1;
-		kfree(per_cpu(xen_resched_irq, cpu).name);
-		per_cpu(xen_resched_irq, cpu).name = NULL;
 	}
+	kfree(per_cpu(xen_callfunc_irq, cpu).name);
+	per_cpu(xen_callfunc_irq, cpu).name = NULL;
 	if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
 		per_cpu(xen_callfunc_irq, cpu).irq = -1;
-		kfree(per_cpu(xen_callfunc_irq, cpu).name);
-		per_cpu(xen_callfunc_irq, cpu).name = NULL;
 	}
+	kfree(per_cpu(xen_debug_irq, cpu).name);
+	per_cpu(xen_debug_irq, cpu).name = NULL;
 	if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
 		per_cpu(xen_debug_irq, cpu).irq = -1;
-		kfree(per_cpu(xen_debug_irq, cpu).name);
-		per_cpu(xen_debug_irq, cpu).name = NULL;
 	}
+	kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
+	per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
 	if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
 				       NULL);
 		per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
-		kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
-		per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
 	}
 }
 
@@ -65,6 +65,7 @@
 	char *resched_name, *callfunc_name, *debug_name;
 
 	resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+	per_cpu(xen_resched_irq, cpu).name = resched_name;
 	rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
 				    cpu,
 				    xen_reschedule_interrupt,
@@ -74,9 +75,9 @@
 	if (rc < 0)
 		goto fail;
 	per_cpu(xen_resched_irq, cpu).irq = rc;
-	per_cpu(xen_resched_irq, cpu).name = resched_name;
 
 	callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+	per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
 	rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
 				    cpu,
 				    xen_call_function_interrupt,
@@ -86,18 +87,21 @@
 	if (rc < 0)
 		goto fail;
 	per_cpu(xen_callfunc_irq, cpu).irq = rc;
-	per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
 
-	debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
-	rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
-				     IRQF_PERCPU | IRQF_NOBALANCING,
-				     debug_name, NULL);
-	if (rc < 0)
-		goto fail;
-	per_cpu(xen_debug_irq, cpu).irq = rc;
-	per_cpu(xen_debug_irq, cpu).name = debug_name;
+	if (!xen_fifo_events) {
+		debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
+		per_cpu(xen_debug_irq, cpu).name = debug_name;
+		rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu,
+					     xen_debug_interrupt,
+					     IRQF_PERCPU | IRQF_NOBALANCING,
+					     debug_name, NULL);
+		if (rc < 0)
+			goto fail;
+		per_cpu(xen_debug_irq, cpu).irq = rc;
+	}
 
 	callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
+	per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
 	rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
 				    cpu,
 				    xen_call_function_single_interrupt,
@@ -107,7 +111,6 @@
 	if (rc < 0)
 		goto fail;
 	per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
-	per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
 
 	return 0;
 
--- linux-ein-5.4.0.orig/arch/x86/xen/smp_hvm.c
+++ linux-ein-5.4.0/arch/x86/xen/smp_hvm.c
@@ -19,6 +19,12 @@
 	xen_vcpu_setup(0);
 
 	/*
+	 * Called again in case the kernel boots on vcpu >= MAX_VIRT_CPUS.
+	 * Refer to comments in xen_hvm_init_time_ops().
+	 */
+	xen_hvm_init_time_ops();
+
+	/*
 	 * The alternative logic (which patches the unlock/lock) runs before
 	 * the smp bootup up code is activated. Hence we need to set this up
 	 * the core kernel is being patched. Otherwise we will have only
--- linux-ein-5.4.0.orig/arch/x86/xen/smp_pv.c
+++ linux-ein-5.4.0/arch/x86/xen/smp_pv.c
@@ -28,6 +28,7 @@
 #include <asm/desc.h>
 #include <asm/pgtable.h>
 #include <asm/cpu.h>
+#include <asm/fpu/internal.h>
 
 #include <xen/interface/xen.h>
 #include <xen/interface/vcpu.h>
@@ -53,6 +54,7 @@
 static DEFINE_PER_CPU(struct xen_common_irq, xen_pmu_irq) = { .irq = -1 };
 
 static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id);
+void asm_cpu_bringup_and_idle(void);
 
 static void cpu_bringup(void)
 {
@@ -60,6 +62,7 @@
 
 	cr4_init();
 	cpu_init();
+	fpu__init_cpu();
 	touch_softlockup_watchdog();
 	preempt_disable();
 
@@ -92,22 +95,23 @@
 	cpu_bringup();
 	boot_init_stack_canary();
 	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+	prevent_tail_call_optimization();
 }
 
 void xen_smp_intr_free_pv(unsigned int cpu)
 {
+	kfree(per_cpu(xen_irq_work, cpu).name);
+	per_cpu(xen_irq_work, cpu).name = NULL;
 	if (per_cpu(xen_irq_work, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
 		per_cpu(xen_irq_work, cpu).irq = -1;
-		kfree(per_cpu(xen_irq_work, cpu).name);
-		per_cpu(xen_irq_work, cpu).name = NULL;
 	}
 
+	kfree(per_cpu(xen_pmu_irq, cpu).name);
+	per_cpu(xen_pmu_irq, cpu).name = NULL;
 	if (per_cpu(xen_pmu_irq, cpu).irq >= 0) {
 		unbind_from_irqhandler(per_cpu(xen_pmu_irq, cpu).irq, NULL);
 		per_cpu(xen_pmu_irq, cpu).irq = -1;
-		kfree(per_cpu(xen_pmu_irq, cpu).name);
-		per_cpu(xen_pmu_irq, cpu).name = NULL;
 	}
 }
 
@@ -117,6 +121,7 @@
 	char *callfunc_name, *pmu_name;
 
 	callfunc_name = kasprintf(GFP_KERNEL, "irqwork%d", cpu);
+	per_cpu(xen_irq_work, cpu).name = callfunc_name;
 	rc = bind_ipi_to_irqhandler(XEN_IRQ_WORK_VECTOR,
 				    cpu,
 				    xen_irq_work_interrupt,
@@ -126,10 +131,10 @@
 	if (rc < 0)
 		goto fail;
 	per_cpu(xen_irq_work, cpu).irq = rc;
-	per_cpu(xen_irq_work, cpu).name = callfunc_name;
 
-	if (is_xen_pmu(cpu)) {
+	if (is_xen_pmu) {
 		pmu_name = kasprintf(GFP_KERNEL, "pmu%d", cpu);
+		per_cpu(xen_pmu_irq, cpu).name = pmu_name;
 		rc = bind_virq_to_irqhandler(VIRQ_XENPMU, cpu,
 					     xen_pmu_irq_handler,
 					     IRQF_PERCPU|IRQF_NOBALANCING,
@@ -137,7 +142,6 @@
 		if (rc < 0)
 			goto fail;
 		per_cpu(xen_pmu_irq, cpu).irq = rc;
-		per_cpu(xen_pmu_irq, cpu).name = pmu_name;
 	}
 
 	return 0;
@@ -309,7 +313,7 @@
 	 * pointing just below where pt_regs would be if it were a normal
 	 * kernel entry.
 	 */
-	ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+	ctxt->user_regs.eip = (unsigned long)asm_cpu_bringup_and_idle;
 	ctxt->flags = VGCF_IN_KERNEL;
 	ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
 	ctxt->user_regs.ds = __USER_DS;
--- linux-ein-5.4.0.orig/arch/x86/xen/spinlock.c
+++ linux-ein-5.4.0/arch/x86/xen/spinlock.c
@@ -75,6 +75,7 @@
 	     cpu, per_cpu(lock_kicker_irq, cpu));
 
 	name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+	per_cpu(irq_name, cpu) = name;
 	irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
 				     cpu,
 				     dummy_handler,
@@ -85,7 +86,6 @@
 	if (irq >= 0) {
 		disable_irq(irq); /* make sure it's never delivered */
 		per_cpu(lock_kicker_irq, cpu) = irq;
-		per_cpu(irq_name, cpu) = name;
 	}
 
 	printk("cpu %d spinlock event irq %d\n", cpu, irq);
@@ -93,13 +93,23 @@
 
 void xen_uninit_lock_cpu(int cpu)
 {
+	int irq;
+
 	if (!xen_pvspin)
 		return;
 
-	unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
-	per_cpu(lock_kicker_irq, cpu) = -1;
 	kfree(per_cpu(irq_name, cpu));
 	per_cpu(irq_name, 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;
 }
 
 PV_CALLEE_SAVE_REGS_THUNK(xen_vcpu_stolen);
--- linux-ein-5.4.0.orig/arch/x86/xen/time.c
+++ linux-ein-5.4.0/arch/x86/xen/time.c
@@ -547,6 +547,11 @@
 
 void __init xen_hvm_init_time_ops(void)
 {
+	static bool hvm_time_initialized;
+
+	if (hvm_time_initialized)
+		return;
+
 	/*
 	 * vector callback is needed otherwise we cannot receive interrupts
 	 * on cpu > 0 and at this point we don't know how many cpus are
@@ -556,7 +561,22 @@
 		return;
 
 	if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
-		pr_info("Xen doesn't support pvclock on HVM, disable pv timer");
+		pr_info_once("Xen doesn't support pvclock on HVM, disable pv timer");
+		return;
+	}
+
+	/*
+	 * Only MAX_VIRT_CPUS 'vcpu_info' are embedded inside 'shared_info'.
+	 * The __this_cpu_read(xen_vcpu) is still NULL when Xen HVM guest
+	 * boots on vcpu >= MAX_VIRT_CPUS (e.g., kexec), To access
+	 * __this_cpu_read(xen_vcpu) via xen_clocksource_read() will panic.
+	 *
+	 * The xen_hvm_init_time_ops() should be called again later after
+	 * __this_cpu_read(xen_vcpu) is available.
+	 */
+	if (!__this_cpu_read(xen_vcpu)) {
+		pr_info("Delay xen_init_time_common() as kernel is running on vcpu=%d\n",
+			xen_vcpu_nr(0));
 		return;
 	}
 
@@ -568,6 +588,8 @@
 	x86_platform.calibrate_tsc = xen_tsc_khz;
 	x86_platform.get_wallclock = xen_get_wallclock;
 	x86_platform.set_wallclock = xen_set_wallclock;
+
+	hvm_time_initialized = true;
 }
 #endif
 
--- linux-ein-5.4.0.orig/arch/x86/xen/xen-asm_32.S
+++ linux-ein-5.4.0/arch/x86/xen/xen-asm_32.S
@@ -56,7 +56,7 @@
 	_ASM_EXTABLE(1b,2b)
 .endm
 
-ENTRY(xen_iret)
+SYM_CODE_START(xen_iret)
 	/* test eflags for special cases */
 	testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
 	jnz hyper_iret
@@ -122,14 +122,14 @@
 hyper_iret:
 	/* put this out of line since its very rarely used */
 	jmp hypercall_page + __HYPERVISOR_iret * 32
+SYM_CODE_END(xen_iret)
 
 	.globl xen_iret_start_crit, xen_iret_end_crit
 
 /*
- * This is called by xen_hypervisor_callback in entry.S when it sees
+ * This is called by xen_hypervisor_callback in entry_32.S when it sees
  * that the EIP at the time of interrupt was between
- * xen_iret_start_crit and xen_iret_end_crit.  We're passed the EIP in
- * %eax so we can do a more refined determination of what to do.
+ * xen_iret_start_crit and xen_iret_end_crit.
  *
  * The stack format at this point is:
  *	----------------
@@ -138,70 +138,46 @@
  *	 eflags		}  outer exception info
  *	 cs		}
  *	 eip		}
- *	---------------- <- edi (copy dest)
- *	 eax		:  outer eax if it hasn't been restored
  *	----------------
- *	 eflags		}  nested exception info
- *	 cs		}   (no ss/esp because we're nested
- *	 eip		}    from the same ring)
- *	 orig_eax	}<- esi (copy src)
- *	 - - - - - - - -
- *	 fs		}
- *	 es		}
- *	 ds		}  SAVE_ALL state
- *	 eax		}
- *	  :		:
- *	 ebx		}<- esp
+ *	 eax		:  outer eax if it hasn't been restored
  *	----------------
+ *	 eflags		}
+ *	 cs		}  nested exception info
+ *	 eip		}
+ *	 return address	: (into xen_hypervisor_callback)
  *
- * In order to deliver the nested exception properly, we need to shift
- * everything from the return addr up to the error code so it sits
- * just under the outer exception info.  This means that when we
- * handle the exception, we do it in the context of the outer
- * exception rather than starting a new one.
+ * In order to deliver the nested exception properly, we need to discard the
+ * nested exception frame such that when we handle the exception, we do it
+ * in the context of the outer exception rather than starting a new one.
  *
- * The only caveat is that if the outer eax hasn't been restored yet
- * (ie, it's still on stack), we need to insert its value into the
- * SAVE_ALL state before going on, since it's usermode state which we
- * eventually need to restore.
+ * The only caveat is that if the outer eax hasn't been restored yet (i.e.
+ * it's still on stack), we need to restore its value here.
  */
-ENTRY(xen_iret_crit_fixup)
+SYM_CODE_START(xen_iret_crit_fixup)
 	/*
 	 * Paranoia: Make sure we're really coming from kernel space.
 	 * One could imagine a case where userspace jumps into the
 	 * critical range address, but just before the CPU delivers a
-	 * GP, it decides to deliver an interrupt instead.  Unlikely?
-	 * Definitely.  Easy to avoid?  Yes.  The Intel documents
-	 * explicitly say that the reported EIP for a bad jump is the
-	 * jump instruction itself, not the destination, but some
-	 * virtual environments get this wrong.
-	 */
-	movl PT_CS(%esp), %ecx
-	andl $SEGMENT_RPL_MASK, %ecx
-	cmpl $USER_RPL, %ecx
-	je 2f
-
-	lea PT_ORIG_EAX(%esp), %esi
-	lea PT_EFLAGS(%esp), %edi
+	 * PF, it decides to deliver an interrupt instead.  Unlikely?
+	 * Definitely.  Easy to avoid?  Yes.
+	 */
+	testb $2, 2*4(%esp)		/* nested CS */
+	jnz 2f
 
 	/*
 	 * If eip is before iret_restore_end then stack
 	 * hasn't been restored yet.
 	 */
-	cmp $iret_restore_end, %eax
+	cmpl $iret_restore_end, 1*4(%esp)
 	jae 1f
 
-	movl 0+4(%edi), %eax		/* copy EAX (just above top of frame) */
-	movl %eax, PT_EAX(%esp)
-
-	lea ESP_OFFSET(%edi), %edi	/* move dest up over saved regs */
-
-	/* set up the copy */
-1:	std
-	mov $PT_EIP / 4, %ecx		/* saved regs up to orig_eax */
-	rep movsl
-	cld
-
-	lea 4(%edi), %esp		/* point esp to new frame */
-2:	jmp xen_do_upcall
-
+	movl 4*4(%esp), %eax		/* load outer EAX */
+	ret $4*4			/* discard nested EIP, CS, and EFLAGS as
+					 * well as the just restored EAX */
+
+1:
+	ret $3*4			/* discard nested EIP, CS, and EFLAGS */
+
+2:
+	ret
+SYM_CODE_END(xen_iret_crit_fixup)
--- linux-ein-5.4.0.orig/arch/x86/xen/xen-head.S
+++ linux-ein-5.4.0/arch/x86/xen/xen-head.S
@@ -35,7 +35,11 @@
 	rep __ASM_SIZE(stos)
 
 	mov %_ASM_SI, xen_start_info
-	mov $init_thread_union+THREAD_SIZE, %_ASM_SP
+#ifdef CONFIG_X86_64
+	mov initial_stack(%rip), %rsp
+#else
+	mov initial_stack, %esp
+#endif
 
 #ifdef CONFIG_X86_64
 	/* Set up %gs.
@@ -51,9 +55,19 @@
 	wrmsr
 #endif
 
-	jmp xen_start_kernel
+	call xen_start_kernel
 END(startup_xen)
 	__FINIT
+
+#ifdef CONFIG_XEN_PV_SMP
+.pushsection .text
+SYM_CODE_START(asm_cpu_bringup_and_idle)
+	UNWIND_HINT_EMPTY
+
+	call cpu_bringup_and_idle
+SYM_CODE_END(asm_cpu_bringup_and_idle)
+.popsection
+#endif
 #endif
 
 .pushsection .text
--- linux-ein-5.4.0.orig/arch/x86/xen/xen-ops.h
+++ linux-ein-5.4.0/arch/x86/xen/xen-ops.h
@@ -30,6 +30,8 @@
 extern struct shared_info xen_dummy_shared_info;
 extern struct shared_info *HYPERVISOR_shared_info;
 
+extern bool xen_fifo_events;
+
 void xen_setup_mfn_list_list(void);
 void xen_build_mfn_list_list(void);
 void xen_setup_machphys_mapping(void);
--- linux-ein-5.4.0.orig/arch/xtensa/Kconfig
+++ linux-ein-5.4.0/arch/xtensa/Kconfig
@@ -22,11 +22,12 @@
 	select HAVE_ARCH_JUMP_LABEL
 	select HAVE_ARCH_KASAN if MMU
 	select HAVE_ARCH_TRACEHOOK
+	select HAVE_COPY_THREAD_TLS
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_DMA_CONTIGUOUS
 	select HAVE_EXIT_THREAD
 	select HAVE_FUNCTION_TRACER
-	select HAVE_FUTEX_CMPXCHG if !MMU
+	select HAVE_FUTEX_CMPXCHG if !MMU && FUTEX
 	select HAVE_HW_BREAKPOINT if PERF_EVENTS
 	select HAVE_IRQ_TIME_ACCOUNTING
 	select HAVE_OPROFILE
--- linux-ein-5.4.0.orig/arch/xtensa/boot/Makefile
+++ linux-ein-5.4.0/arch/xtensa/boot/Makefile
@@ -9,8 +9,7 @@
 
 
 # KBUILD_CFLAGS used when building rest of boot (takes effect recursively)
-KBUILD_CFLAGS	+= -fno-builtin -Iarch/$(ARCH)/boot/include
-HOSTFLAGS	+= -Iarch/$(ARCH)/boot/include
+KBUILD_CFLAGS	+= -fno-builtin
 
 BIG_ENDIAN	:= $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
 
--- linux-ein-5.4.0.orig/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi
+++ linux-ein-5.4.0/arch/xtensa/boot/dts/xtfpga-flash-128m.dtsi
@@ -8,19 +8,19 @@
 			reg = <0x00000000 0x08000000>;
 			bank-width = <2>;
 			device-width = <2>;
-			partition@0x0 {
+			partition@0 {
 				label = "data";
 				reg = <0x00000000 0x06000000>;
 			};
-			partition@0x6000000 {
+			partition@6000000 {
 				label = "boot loader area";
 				reg = <0x06000000 0x00800000>;
 			};
-			partition@0x6800000 {
+			partition@6800000 {
 				label = "kernel image";
 				reg = <0x06800000 0x017e0000>;
 			};
-			partition@0x7fe0000 {
+			partition@7fe0000 {
 				label = "boot environment";
 				reg = <0x07fe0000 0x00020000>;
 			};
--- linux-ein-5.4.0.orig/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
+++ linux-ein-5.4.0/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
@@ -8,19 +8,19 @@
 			reg = <0x08000000 0x01000000>;
 			bank-width = <2>;
 			device-width = <2>;
-			partition@0x0 {
+			partition@0 {
 				label = "boot loader area";
 				reg = <0x00000000 0x00400000>;
 			};
-			partition@0x400000 {
+			partition@400000 {
 				label = "kernel image";
 				reg = <0x00400000 0x00600000>;
 			};
-			partition@0xa00000 {
+			partition@a00000 {
 				label = "data";
 				reg = <0x00a00000 0x005e0000>;
 			};
-			partition@0xfe0000 {
+			partition@fe0000 {
 				label = "boot environment";
 				reg = <0x00fe0000 0x00020000>;
 			};
--- linux-ein-5.4.0.orig/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
+++ linux-ein-5.4.0/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
@@ -8,11 +8,11 @@
 			reg = <0x08000000 0x00400000>;
 			bank-width = <2>;
 			device-width = <2>;
-			partition@0x0 {
+			partition@0 {
 				label = "boot loader area";
 				reg = <0x00000000 0x003f0000>;
 			};
-			partition@0x3f0000 {
+			partition@3f0000 {
 				label = "boot environment";
 				reg = <0x003f0000 0x00010000>;
 			};
--- linux-ein-5.4.0.orig/arch/xtensa/boot/lib/zmem.c
+++ linux-ein-5.4.0/arch/xtensa/boot/lib/zmem.c
@@ -4,13 +4,14 @@
 /* bits taken from ppc */
 
 extern void *avail_ram, *end_avail;
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp);
 
-void exit (void)
+static void exit(void)
 {
   for (;;);
 }
 
-void *zalloc(unsigned size)
+static void *zalloc(unsigned int size)
 {
         void *p = avail_ram;
 
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/core.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/core.h
@@ -6,6 +6,10 @@
 
 #include <variant/core.h>
 
+#ifndef XCHAL_HAVE_DIV32
+#define XCHAL_HAVE_DIV32 0
+#endif
+
 #ifndef XCHAL_HAVE_EXCLUSIVE
 #define XCHAL_HAVE_EXCLUSIVE 0
 #endif
@@ -18,4 +22,13 @@
 #define XCHAL_SPANNING_WAY 0
 #endif
 
+#ifndef XCHAL_HW_MIN_VERSION
+#if defined(XCHAL_HW_MIN_VERSION_MAJOR) && defined(XCHAL_HW_MIN_VERSION_MINOR)
+#define XCHAL_HW_MIN_VERSION (XCHAL_HW_MIN_VERSION_MAJOR * 100 + \
+			      XCHAL_HW_MIN_VERSION_MINOR)
+#else
+#define XCHAL_HW_MIN_VERSION 0
+#endif
+#endif
+
 #endif
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/kmem_layout.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/kmem_layout.h
@@ -11,6 +11,7 @@
 #ifndef _XTENSA_KMEM_LAYOUT_H
 #define _XTENSA_KMEM_LAYOUT_H
 
+#include <asm/core.h>
 #include <asm/types.h>
 
 #ifdef CONFIG_MMU
@@ -65,6 +66,34 @@
 
 #endif
 
+/* KIO definition */
+
+#if XCHAL_HAVE_PTP_MMU
+#define XCHAL_KIO_CACHED_VADDR		0xe0000000
+#define XCHAL_KIO_BYPASS_VADDR		0xf0000000
+#define XCHAL_KIO_DEFAULT_PADDR		0xf0000000
+#else
+#define XCHAL_KIO_BYPASS_VADDR		XCHAL_KIO_PADDR
+#define XCHAL_KIO_DEFAULT_PADDR		0x90000000
+#endif
+#define XCHAL_KIO_SIZE			0x10000000
+
+#if (!XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY) && defined(CONFIG_USE_OF)
+#define XCHAL_KIO_PADDR			xtensa_get_kio_paddr()
+#ifndef __ASSEMBLY__
+extern unsigned long xtensa_kio_paddr;
+
+static inline unsigned long xtensa_get_kio_paddr(void)
+{
+	return xtensa_kio_paddr;
+}
+#endif
+#else
+#define XCHAL_KIO_PADDR			XCHAL_KIO_DEFAULT_PADDR
+#endif
+
+/* KERNEL_STACK definition */
+
 #ifndef CONFIG_KASAN
 #define KERNEL_STACK_SHIFT	13
 #else
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/page.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/page.h
@@ -181,10 +181,6 @@
 #define pfn_valid(pfn) \
 	((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
 
-#ifdef CONFIG_DISCONTIGMEM
-# error CONFIG_DISCONTIGMEM not supported
-#endif
-
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_virt(page)	__va(page_to_pfn(page) << PAGE_SHIFT)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/pgtable.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/pgtable.h
@@ -70,7 +70,7 @@
  */
 #define VMALLOC_START		(XCHAL_KSEG_CACHED_VADDR - 0x10000000)
 #define VMALLOC_END		(VMALLOC_START + 0x07FEFFFF)
-#define TLBTEMP_BASE_1		(VMALLOC_END + 1)
+#define TLBTEMP_BASE_1		(VMALLOC_START + 0x08000000)
 #define TLBTEMP_BASE_2		(TLBTEMP_BASE_1 + DCACHE_WAY_SIZE)
 #if 2 * DCACHE_WAY_SIZE > ICACHE_WAY_SIZE
 #define TLBTEMP_SIZE		(2 * DCACHE_WAY_SIZE)
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/processor.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/processor.h
@@ -225,8 +225,8 @@
 
 #define xtensa_set_sr(x, sr) \
 	({ \
-	 unsigned int v = (unsigned int)(x); \
-	 __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: "a"(v)); \
+	 __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: \
+			       "a"((unsigned int)(x))); \
 	 })
 
 #define xtensa_get_sr(sr) \
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/syscall.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/syscall.h
@@ -51,7 +51,7 @@
 					    struct pt_regs *regs,
 					    int error, long val)
 {
-	regs->areg[0] = (long) error ? error : val;
+	regs->areg[2] = (long) error ? error : val;
 }
 
 #define SYSCALL_MAX_ARGS 6
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/thread_info.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/thread_info.h
@@ -55,6 +55,10 @@
 	mm_segment_t		addr_limit;	/* thread address space */
 
 	unsigned long		cpenable;
+#if XCHAL_HAVE_EXCLUSIVE
+	/* result of the most recent exclusive store */
+	unsigned long		atomctl8;
+#endif
 
 	/* Allocate storage for extra user states and coprocessor states. */
 #if XTENSA_HAVE_COPROCESSORS
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/timex.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/timex.h
@@ -29,10 +29,6 @@
 
 extern unsigned long ccount_freq;
 
-typedef unsigned long long cycles_t;
-
-#define get_cycles()	(0)
-
 void local_timer_setup(unsigned cpu);
 
 /*
@@ -59,4 +55,6 @@
 	xtensa_set_sr(ccompare, SREG_CCOMPARE + LINUX_TIMER);
 }
 
+#include <asm-generic/timex.h>
+
 #endif	/* _XTENSA_TIMEX_H */
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/uaccess.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/uaccess.h
@@ -300,7 +300,7 @@
 	return -EFAULT;
 }
 #else
-long strncpy_from_user(char *dst, const char *src, long count);
+long strncpy_from_user(char *dst, const char __user *src, long count);
 #endif
 
 /*
--- linux-ein-5.4.0.orig/arch/xtensa/include/asm/vectors.h
+++ linux-ein-5.4.0/arch/xtensa/include/asm/vectors.h
@@ -21,50 +21,14 @@
 #include <asm/core.h>
 #include <asm/kmem_layout.h>
 
-#if XCHAL_HAVE_PTP_MMU
-#define XCHAL_KIO_CACHED_VADDR		0xe0000000
-#define XCHAL_KIO_BYPASS_VADDR		0xf0000000
-#define XCHAL_KIO_DEFAULT_PADDR		0xf0000000
-#else
-#define XCHAL_KIO_BYPASS_VADDR		XCHAL_KIO_PADDR
-#define XCHAL_KIO_DEFAULT_PADDR		0x90000000
-#endif
-#define XCHAL_KIO_SIZE			0x10000000
-
-#if (!XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY) && defined(CONFIG_OF)
-#define XCHAL_KIO_PADDR			xtensa_get_kio_paddr()
-#ifndef __ASSEMBLY__
-extern unsigned long xtensa_kio_paddr;
-
-static inline unsigned long xtensa_get_kio_paddr(void)
-{
-	return xtensa_kio_paddr;
-}
-#endif
-#else
-#define XCHAL_KIO_PADDR			XCHAL_KIO_DEFAULT_PADDR
-#endif
-
-#if defined(CONFIG_MMU)
-
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
-/* Image Virtual Start Address */
-#define KERNELOFFSET			(XCHAL_KSEG_CACHED_VADDR + \
-					 CONFIG_KERNEL_LOAD_ADDRESS - \
+#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
+#define KERNELOFFSET			(CONFIG_KERNEL_LOAD_ADDRESS + \
+					 XCHAL_KSEG_CACHED_VADDR - \
 					 XCHAL_KSEG_PADDR)
 #else
 #define KERNELOFFSET			CONFIG_KERNEL_LOAD_ADDRESS
 #endif
 
-#else /* !defined(CONFIG_MMU) */
-  /* MMU Not being used - Virtual == Physical */
-
-/* Location of the start of the kernel text, _start */
-#define KERNELOFFSET			CONFIG_KERNEL_LOAD_ADDRESS
-
-
-#endif /* CONFIG_MMU */
-
 #define RESET_VECTOR1_VADDR		(XCHAL_RESET_VECTOR1_VADDR)
 #ifdef CONFIG_VECTORS_OFFSET
 #define VECBASE_VADDR			(KERNELOFFSET - CONFIG_VECTORS_OFFSET)
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/asm-offsets.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/asm-offsets.c
@@ -93,6 +93,9 @@
 	DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
 	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
 	DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
+#if XCHAL_HAVE_EXCLUSIVE
+	DEFINE(THREAD_ATOMCTL8, offsetof (struct thread_info, atomctl8));
+#endif
 #if XTENSA_HAVE_COPROCESSORS
 	DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0));
 	DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/coprocessor.S
+++ linux-ein-5.4.0/arch/xtensa/kernel/coprocessor.S
@@ -37,7 +37,7 @@
 	.if XTENSA_HAVE_COPROCESSOR(x);					\
 		.align 4;						\
 	.Lsave_cp_regs_cp##x:						\
-		xchal_cp##x##_store a2 a4 a5 a6 a7;			\
+		xchal_cp##x##_store a2 a3 a4 a5 a6;			\
 		jx	a0;						\
 	.endif
 
@@ -54,7 +54,7 @@
 	.if XTENSA_HAVE_COPROCESSOR(x);					\
 		.align 4;						\
 	.Lload_cp_regs_cp##x:						\
-		xchal_cp##x##_load a2 a4 a5 a6 a7;			\
+		xchal_cp##x##_load a2 a3 a4 a5 a6;			\
 		jx	a0;						\
 	.endif
 
@@ -109,37 +109,6 @@
 	.previous
 
 /*
- * coprocessor_flush(struct thread_info*, index)
- *                             a2        a3
- *
- * Save coprocessor registers for coprocessor 'index'.
- * The register values are saved to or loaded from the coprocessor area 
- * inside the task_info structure.
- *
- * Note that this function doesn't update the coprocessor_owner information!
- *
- */
-
-ENTRY(coprocessor_flush)
-
-	/* reserve 4 bytes on stack to save a0 */
-	abi_entry(4)
-
-	s32i	a0, a1, 0
-	movi	a0, .Lsave_cp_regs_jump_table
-	addx8	a3, a3, a0
-	l32i	a4, a3, 4
-	l32i	a3, a3, 0
-	add	a2, a2, a4
-	beqz	a3, 1f
-	callx0	a3
-1:	l32i	a0, a1, 0
-
-	abi_ret(4)
-
-ENDPROC(coprocessor_flush)
-
-/*
  * Entry condition:
  *
  *   a0:	trashed, original value saved on stack (PT_AREG0)
@@ -261,6 +230,39 @@
 
 ENDPROC(fast_coprocessor)
 
+	.text
+
+/*
+ * coprocessor_flush(struct thread_info*, index)
+ *                             a2        a3
+ *
+ * Save coprocessor registers for coprocessor 'index'.
+ * The register values are saved to or loaded from the coprocessor area
+ * inside the task_info structure.
+ *
+ * Note that this function doesn't update the coprocessor_owner information!
+ *
+ */
+
+ENTRY(coprocessor_flush)
+
+	/* reserve 4 bytes on stack to save a0 */
+	abi_entry(4)
+
+	s32i	a0, a1, 0
+	movi	a0, .Lsave_cp_regs_jump_table
+	addx8	a3, a3, a0
+	l32i	a4, a3, 4
+	l32i	a3, a3, 0
+	add	a2, a2, a4
+	beqz	a3, 1f
+	callx0	a3
+1:	l32i	a0, a1, 0
+
+	abi_ret(4)
+
+ENDPROC(coprocessor_flush)
+
 	.data
 
 ENTRY(coprocessor_owner)
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/entry.S
+++ linux-ein-5.4.0/arch/xtensa/kernel/entry.S
@@ -374,6 +374,11 @@
 	s32i	a2, a1, PT_LCOUNT
 #endif
 
+#if XCHAL_HAVE_EXCLUSIVE
+	/* Clear exclusive access monitor set by interrupted code */
+	clrex
+#endif
+
 	/* It is now save to restore the EXC_TABLE_FIXUP variable. */
 
 	rsr	a2, exccause
@@ -1892,6 +1897,7 @@
 
 	mov	a6, a2
 	call4	do_syscall_trace_enter
+	beqz	a6, .Lsyscall_exit
 	l32i	a7, a2, PT_SYSCALL
 
 1:
@@ -1906,8 +1912,6 @@
 
 	addx4	a4, a7, a4
 	l32i	a4, a4, 0
-	movi	a5, sys_ni_syscall;
-	beq	a4, a5, 1f
 
 	/* Load args: arg0 - arg5 are passed via regs. */
 
@@ -1927,6 +1931,7 @@
 
 	s32i	a6, a2, PT_AREG2
 	bnez	a3, 1f
+.Lsyscall_exit:
 	abi_ret(4)
 
 1:
@@ -2024,6 +2029,12 @@
 	s32i	a3, a4, THREAD_CPENABLE
 #endif
 
+#if XCHAL_HAVE_EXCLUSIVE
+	l32i	a3, a5, THREAD_ATOMCTL8
+	getex	a3
+	s32i	a3, a4, THREAD_ATOMCTL8
+#endif
+
 	/* Flush register file. */
 
 	spill_registers_kernel
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/irq.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/irq.c
@@ -145,7 +145,7 @@
 
 void __init init_IRQ(void)
 {
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 	irqchip_init();
 #else
 #ifdef CONFIG_HAVE_SMP
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/jump_label.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/jump_label.c
@@ -40,7 +40,7 @@
 {
 	struct patch *patch = data;
 
-	if (atomic_inc_return(&patch->cpu_count) == 1) {
+	if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) {
 		local_patch_text(patch->addr, patch->data, patch->sz);
 		atomic_inc(&patch->cpu_count);
 	} else {
@@ -61,7 +61,7 @@
 			.data = data,
 		};
 		stop_machine_cpuslocked(patch_text_stop_machine,
-					&patch, NULL);
+					&patch, cpu_online_mask);
 	} else {
 		unsigned long flags;
 
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/pci-dma.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/pci-dma.c
@@ -44,8 +44,8 @@
 		}
 }
 
-void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_BIDIRECTIONAL:
@@ -62,8 +62,8 @@
 	}
 }
 
-void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
-		size_t size, enum dma_data_direction dir)
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+		enum dma_data_direction dir)
 {
 	switch (dir) {
 	case DMA_BIDIRECTIONAL:
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/perf_event.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/perf_event.c
@@ -13,17 +13,26 @@
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
 
+#include <asm/core.h>
 #include <asm/processor.h>
 #include <asm/stacktrace.h>
 
+#define XTENSA_HWVERSION_RG_2015_0	260000
+
+#if XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RG_2015_0
+#define XTENSA_PMU_ERI_BASE		0x00101000
+#else
+#define XTENSA_PMU_ERI_BASE		0x00001000
+#endif
+
 /* Global control/status for all perf counters */
-#define XTENSA_PMU_PMG			0x1000
+#define XTENSA_PMU_PMG			XTENSA_PMU_ERI_BASE
 /* Perf counter values */
-#define XTENSA_PMU_PM(i)		(0x1080 + (i) * 4)
+#define XTENSA_PMU_PM(i)		(XTENSA_PMU_ERI_BASE + 0x80 + (i) * 4)
 /* Perf counter control registers */
-#define XTENSA_PMU_PMCTRL(i)		(0x1100 + (i) * 4)
+#define XTENSA_PMU_PMCTRL(i)		(XTENSA_PMU_ERI_BASE + 0x100 + (i) * 4)
 /* Perf counter status registers */
-#define XTENSA_PMU_PMSTAT(i)		(0x1180 + (i) * 4)
+#define XTENSA_PMU_PMSTAT(i)		(XTENSA_PMU_ERI_BASE + 0x180 + (i) * 4)
 
 #define XTENSA_PMU_PMG_PMEN		0x1
 
@@ -401,7 +410,7 @@
 	.read = xtensa_pmu_read,
 };
 
-static int xtensa_pmu_setup(int cpu)
+static int xtensa_pmu_setup(unsigned int cpu)
 {
 	unsigned i;
 
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/process.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/process.c
@@ -202,8 +202,9 @@
  * involved.  Much simpler to just not copy those live frames across.
  */
 
-int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
-		unsigned long thread_fn_arg, struct task_struct *p)
+int copy_thread_tls(unsigned long clone_flags, unsigned long usp_thread_fn,
+		unsigned long thread_fn_arg, struct task_struct *p,
+		unsigned long tls)
 {
 	struct pt_regs *childregs = task_pt_regs(p);
 
@@ -264,9 +265,8 @@
 			       &regs->areg[XCHAL_NUM_AREGS - len/4], len);
 		}
 
-		/* The thread pointer is passed in the '4th argument' (= a5) */
 		if (clone_flags & CLONE_SETTLS)
-			childregs->threadptr = childregs->areg[5];
+			childregs->threadptr = tls;
 	} else {
 		p->thread.ra = MAKE_RA_FOR_CALL(
 				(unsigned long)ret_from_kernel_thread, 1);
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/ptrace.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/ptrace.c
@@ -225,12 +225,12 @@
 
 void user_enable_single_step(struct task_struct *child)
 {
-	child->ptrace |= PT_SINGLESTEP;
+	set_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
 void user_disable_single_step(struct task_struct *child)
 {
-	child->ptrace &= ~PT_SINGLESTEP;
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
 /*
@@ -542,14 +542,28 @@
 	return ret;
 }
 
-void do_syscall_trace_enter(struct pt_regs *regs)
+void do_syscall_trace_leave(struct pt_regs *regs);
+int do_syscall_trace_enter(struct pt_regs *regs)
 {
+	if (regs->syscall == NO_SYSCALL)
+		regs->areg[2] = -ENOSYS;
+
 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-	    tracehook_report_syscall_entry(regs))
+	    tracehook_report_syscall_entry(regs)) {
+		regs->areg[2] = -ENOSYS;
 		regs->syscall = NO_SYSCALL;
+		return 0;
+	}
+
+	if (regs->syscall == NO_SYSCALL) {
+		do_syscall_trace_leave(regs);
+		return 0;
+	}
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, syscall_get_nr(current, regs));
+
+	return 1;
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/setup.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/setup.c
@@ -64,7 +64,7 @@
 extern int initrd_below_start_ok;
 #endif
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 void *dtb_start = __dtb_start;
 #endif
 
@@ -126,7 +126,7 @@
 
 #endif /* CONFIG_BLK_DEV_INITRD */
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 
 static int __init parse_tag_fdt(const bp_tag_t *tag)
 {
@@ -136,7 +136,7 @@
 
 __tagtable(BP_TAG_FDT, parse_tag_fdt);
 
-#endif /* CONFIG_OF */
+#endif /* CONFIG_USE_OF */
 
 static int __init parse_tag_cmdline(const bp_tag_t* tag)
 {
@@ -184,7 +184,7 @@
 }
 #endif
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 
 #if !XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY
 unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR;
@@ -233,7 +233,7 @@
 		strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
 }
 
-#endif /* CONFIG_OF */
+#endif /* CONFIG_USE_OF */
 
 /*
  * Initialize architecture. (Early stage)
@@ -254,7 +254,7 @@
 	if (bp_start)
 		parse_bootparam(bp_start);
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 	early_init_devtree(dtb_start);
 #endif
 
@@ -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-ein-5.4.0.orig/arch/xtensa/kernel/signal.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/signal.c
@@ -465,7 +465,7 @@
 		/* Set up the stack frame */
 		ret = setup_frame(&ksig, sigmask_to_save(), regs);
 		signal_setup_done(ret, &ksig, 0);
-		if (current->ptrace & PT_SINGLESTEP)
+		if (test_thread_flag(TIF_SINGLESTEP))
 			task_pt_regs(current)->icountlevel = 1;
 
 		return;
@@ -491,7 +491,7 @@
 	/* If there's no signal to deliver, we just restore the saved mask.  */
 	restore_saved_sigmask();
 
-	if (current->ptrace & PT_SINGLESTEP)
+	if (test_thread_flag(TIF_SINGLESTEP))
 		task_pt_regs(current)->icountlevel = 1;
 	return;
 }
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/time.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/time.c
@@ -160,6 +160,7 @@
 	cpu = of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu");
 	if (cpu) {
 		clk = of_clk_get(cpu, 0);
+		of_node_put(cpu);
 		if (!IS_ERR(clk)) {
 			ccount_freq = clk_get_rate(clk);
 			return;
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/traps.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/traps.c
@@ -543,5 +543,5 @@
 	if (panic_on_oops)
 		panic("Fatal exception");
 
-	do_exit(err);
+	make_task_dead(err);
 }
--- linux-ein-5.4.0.orig/arch/xtensa/kernel/xtensa_ksyms.c
+++ linux-ein-5.4.0/arch/xtensa/kernel/xtensa_ksyms.c
@@ -87,13 +87,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();
 }
--- linux-ein-5.4.0.orig/arch/xtensa/mm/cache.c
+++ linux-ein-5.4.0/arch/xtensa/mm/cache.c
@@ -71,8 +71,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();
 		}
 	}
 }
@@ -157,6 +159,7 @@
 		if (!alias && !mapping)
 			return;
 
+		preempt_disable();
 		virt = TLBTEMP_BASE_1 + (phys & DCACHE_ALIAS_MASK);
 		__flush_invalidate_dcache_page_alias(virt, phys);
 
@@ -167,6 +170,7 @@
 
 		if (mapping)
 			__invalidate_icache_page_alias(virt, phys);
+		preempt_enable();
 	}
 
 	/* There shouldn't be an entry in the cache for this page anymore. */
@@ -200,8 +204,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();
 }
 EXPORT_SYMBOL(local_flush_cache_page);
 
@@ -228,11 +234,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);
 	}
@@ -266,7 +274,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 */
@@ -281,9 +291,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);
@@ -305,7 +317,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-ein-5.4.0.orig/arch/xtensa/mm/kasan_init.c
+++ linux-ein-5.4.0/arch/xtensa/mm/kasan_init.c
@@ -56,7 +56,9 @@
 
 		for (k = 0; k < PTRS_PER_PTE; ++k, ++j) {
 			phys_addr_t phys =
-				memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
+				memblock_phys_alloc_range(PAGE_SIZE, PAGE_SIZE,
+							  0,
+							  MEMBLOCK_ALLOC_ANYWHERE);
 
 			if (!phys)
 				panic("Failed to allocate page table page\n");
--- linux-ein-5.4.0.orig/arch/xtensa/mm/mmu.c
+++ linux-ein-5.4.0/arch/xtensa/mm/mmu.c
@@ -101,7 +101,7 @@
 
 void init_kio(void)
 {
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_USE_OF)
 	/*
 	 * Update the IO area mapping in case xtensa_kio_paddr has changed
 	 */
--- linux-ein-5.4.0.orig/arch/xtensa/mm/tlb.c
+++ linux-ein-5.4.0/arch/xtensa/mm/tlb.c
@@ -216,6 +216,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;
@@ -231,8 +233,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-ein-5.4.0.orig/arch/xtensa/platforms/iss/console.c
+++ linux-ein-5.4.0/arch/xtensa/platforms/iss/console.c
@@ -168,9 +168,13 @@
 
 int __init rs_init(void)
 {
-	tty_port_init(&serial_port);
+	int ret;
 
 	serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
+	if (!serial_driver)
+		return -ENOMEM;
+
+	tty_port_init(&serial_port);
 
 	pr_info("%s %s\n", serial_name, serial_version);
 
@@ -190,8 +194,15 @@
 	tty_set_operations(serial_driver, &serial_ops);
 	tty_port_link_device(&serial_port, serial_driver, 0);
 
-	if (tty_register_driver(serial_driver))
-		panic("Couldn't register serial driver\n");
+	ret = tty_register_driver(serial_driver);
+	if (ret) {
+		pr_err("Couldn't register serial driver\n");
+		tty_driver_kref_put(serial_driver);
+		tty_port_destroy(&serial_port);
+
+		return ret;
+	}
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/arch/xtensa/platforms/iss/network.c
+++ linux-ein-5.4.0/arch/xtensa/platforms/iss/network.c
@@ -204,7 +204,7 @@
 	return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
 }
 
-unsigned short tuntap_protocol(struct sk_buff *skb)
+static unsigned short tuntap_protocol(struct sk_buff *skb)
 {
 	return eth_type_trans(skb, skb->dev);
 }
@@ -231,7 +231,7 @@
 
 	init += sizeof(TRANSPORT_TUNTAP_NAME) - 1;
 	if (*init == ',') {
-		rem = split_if_spec(init + 1, &mac_str, &dev_name);
+		rem = split_if_spec(init + 1, &mac_str, &dev_name, NULL);
 		if (rem != NULL) {
 			pr_err("%s: extra garbage on specification : '%s'\n",
 			       dev->name, rem);
@@ -477,7 +477,7 @@
 	return -EINVAL;
 }
 
-void iss_net_user_timer_expire(struct timer_list *unused)
+static void iss_net_user_timer_expire(struct timer_list *unused)
 {
 }
 
--- linux-ein-5.4.0.orig/arch/xtensa/platforms/xtfpga/setup.c
+++ linux-ein-5.4.0/arch/xtensa/platforms/xtfpga/setup.c
@@ -50,8 +50,12 @@
 
 void platform_restart(void)
 {
-	/* Flush and reset the mmu, simulate a processor reset, and
-	 * jump to the reset vector. */
+	/* Try software reset first. */
+	WRITE_ONCE(*(u32 *)XTFPGA_SWRST_VADDR, 0xdead);
+
+	/* If software reset did not work, flush and reset the mmu,
+	 * simulate a processor reset, and jump to the reset vector.
+	 */
 	cpu_reset();
 	/* control never gets here */
 }
@@ -81,7 +85,7 @@
 
 #endif
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 
 static void __init xtfpga_clk_setup(struct device_node *np)
 {
@@ -144,6 +148,7 @@
 
 	if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
 		update_local_mac(eth);
+	of_node_put(eth);
 	return 0;
 }
 arch_initcall(machine_setup);
@@ -299,4 +304,4 @@
  */
 arch_initcall(xtavnet_init);
 
-#endif /* CONFIG_OF */
+#endif /* CONFIG_USE_OF */
--- linux-ein-5.4.0.orig/block/bfq-cgroup.c
+++ linux-ein-5.4.0/block/bfq-cgroup.c
@@ -536,6 +536,7 @@
 				   */
 	bfqg->bfqd = bfqd;
 	bfqg->active_entities = 0;
+	bfqg->online = true;
 	bfqg->rq_pos_tree = RB_ROOT;
 }
 
@@ -564,28 +565,11 @@
 	entity->sched_data = &parent->sched_data;
 }
 
-static struct bfq_group *bfq_lookup_bfqg(struct bfq_data *bfqd,
-					 struct blkcg *blkcg)
+static void bfq_link_bfqg(struct bfq_data *bfqd, struct bfq_group *bfqg)
 {
-	struct blkcg_gq *blkg;
-
-	blkg = blkg_lookup(blkcg, bfqd->queue);
-	if (likely(blkg))
-		return blkg_to_bfqg(blkg);
-	return NULL;
-}
-
-struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
-				     struct blkcg *blkcg)
-{
-	struct bfq_group *bfqg, *parent;
+	struct bfq_group *parent;
 	struct bfq_entity *entity;
 
-	bfqg = bfq_lookup_bfqg(bfqd, blkcg);
-
-	if (unlikely(!bfqg))
-		return NULL;
-
 	/*
 	 * Update chain of bfq_groups as we might be handling a leaf group
 	 * which, along with some of its relatives, has not been hooked yet
@@ -593,16 +577,37 @@
 	 */
 	entity = &bfqg->entity;
 	for_each_entity(entity) {
-		bfqg = container_of(entity, struct bfq_group, entity);
-		if (bfqg != bfqd->root_group) {
-			parent = bfqg_parent(bfqg);
+		struct bfq_group *curr_bfqg = container_of(entity,
+						struct bfq_group, entity);
+		if (curr_bfqg != bfqd->root_group) {
+			parent = bfqg_parent(curr_bfqg);
 			if (!parent)
 				parent = bfqd->root_group;
-			bfq_group_set_parent(bfqg, parent);
+			bfq_group_set_parent(curr_bfqg, parent);
 		}
 	}
+}
 
-	return bfqg;
+struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio)
+{
+	struct blkcg_gq *blkg = bio->bi_blkg;
+	struct bfq_group *bfqg;
+
+	while (blkg) {
+		if (!blkg->online) {
+			blkg = blkg->parent;
+			continue;
+		}
+		bfqg = blkg_to_bfqg(blkg);
+		if (bfqg->online) {
+			bio_associate_blkg_from_css(bio, &blkg->blkcg->css);
+			return bfqg;
+		}
+		blkg = blkg->parent;
+	}
+	bio_associate_blkg_from_css(bio,
+				&bfqg_to_blkg(bfqd->root_group)->blkcg->css);
+	return bfqd->root_group;
 }
 
 /**
@@ -624,6 +629,18 @@
 {
 	struct bfq_entity *entity = &bfqq->entity;
 
+	/*
+	 * oom_bfqq is not allowed to move, oom_bfqq will hold ref to root_group
+	 * until elevator exit.
+	 */
+	if (bfqq == &bfqd->oom_bfqq)
+		return;
+	/*
+	 * Get extra reference to prevent bfqq from being freed in
+	 * next possible expire or deactivate.
+	 */
+	bfqq->ref++;
+
 	/* If bfqq is empty, then bfq_bfqq_expire also invokes
 	 * bfq_del_bfqq_busy, thereby removing bfqq and its entity
 	 * from data structures related to current group. Otherwise we
@@ -653,6 +670,8 @@
 
 	if (!bfqd->in_service_queue && !bfqd->rq_in_driver)
 		bfq_schedule_dispatch(bfqd);
+	/* release extra ref taken above, bfqq may happen to be freed now */
+	bfq_put_queue(bfqq);
 }
 
 /**
@@ -664,41 +683,58 @@
  * Move bic to blkcg, assuming that bfqd->lock is held; which makes
  * sure that the reference to cgroup is valid across the call (see
  * comments in bfq_bic_update_cgroup on this issue)
- *
- * NOTE: an alternative approach might have been to store the current
- * cgroup in bfqq and getting a reference to it, reducing the lookup
- * time here, at the price of slightly more complex code.
  */
-static struct bfq_group *__bfq_bic_change_cgroup(struct bfq_data *bfqd,
-						struct bfq_io_cq *bic,
-						struct blkcg *blkcg)
+static void *__bfq_bic_change_cgroup(struct bfq_data *bfqd,
+				     struct bfq_io_cq *bic,
+				     struct bfq_group *bfqg)
 {
 	struct bfq_queue *async_bfqq = bic_to_bfqq(bic, 0);
 	struct bfq_queue *sync_bfqq = bic_to_bfqq(bic, 1);
-	struct bfq_group *bfqg;
 	struct bfq_entity *entity;
 
-	bfqg = bfq_find_set_group(bfqd, blkcg);
-
-	if (unlikely(!bfqg))
-		bfqg = bfqd->root_group;
-
 	if (async_bfqq) {
 		entity = &async_bfqq->entity;
 
 		if (entity->sched_data != &bfqg->sched_data) {
 			bic_set_bfqq(bic, NULL, 0);
-			bfq_log_bfqq(bfqd, async_bfqq,
-				     "bic_change_group: %p %d",
-				     async_bfqq, async_bfqq->ref);
-			bfq_put_queue(async_bfqq);
+			bfq_release_process_ref(bfqd, async_bfqq);
 		}
 	}
 
 	if (sync_bfqq) {
-		entity = &sync_bfqq->entity;
-		if (entity->sched_data != &bfqg->sched_data)
-			bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
+		if (!sync_bfqq->new_bfqq && !bfq_bfqq_coop(sync_bfqq)) {
+			/* We are the only user of this bfqq, just move it */
+			if (sync_bfqq->entity.sched_data != &bfqg->sched_data)
+				bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
+		} else {
+			struct bfq_queue *bfqq;
+
+			/*
+			 * The queue was merged to a different queue. Check
+			 * that the merge chain still belongs to the same
+			 * cgroup.
+			 */
+			for (bfqq = sync_bfqq; bfqq; bfqq = bfqq->new_bfqq)
+				if (bfqq->entity.sched_data !=
+				    &bfqg->sched_data)
+					break;
+			if (bfqq) {
+				/*
+				 * Some queue changed cgroup so the merge is
+				 * not valid anymore. We cannot easily just
+				 * cancel the merge (by clearing new_bfqq) as
+				 * there may be other processes using this
+				 * queue and holding refs to all queues below
+				 * sync_bfqq->new_bfqq. Similarly if the merge
+				 * already happened, we need to detach from
+				 * bfqq now so that we cannot merge bio to a
+				 * request from the old cgroup.
+				 */
+				bfq_put_cooperator(sync_bfqq);
+				bfq_release_process_ref(bfqd, sync_bfqq);
+				bic_set_bfqq(bic, NULL, 1);
+			}
+		}
 	}
 
 	return bfqg;
@@ -707,20 +743,24 @@
 void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio)
 {
 	struct bfq_data *bfqd = bic_to_bfqd(bic);
-	struct bfq_group *bfqg = NULL;
+	struct bfq_group *bfqg = bfq_bio_bfqg(bfqd, bio);
 	uint64_t serial_nr;
 
-	rcu_read_lock();
-	serial_nr = __bio_blkcg(bio)->css.serial_nr;
+	serial_nr = bfqg_to_blkg(bfqg)->blkcg->css.serial_nr;
 
 	/*
 	 * Check whether blkcg has changed.  The condition may trigger
 	 * spuriously on a newly created cic but there's no harm.
 	 */
 	if (unlikely(!bfqd) || likely(bic->blkcg_serial_nr == serial_nr))
-		goto out;
+		return;
 
-	bfqg = __bfq_bic_change_cgroup(bfqd, bic, __bio_blkcg(bio));
+	/*
+	 * New cgroup for this process. Make sure it is linked to bfq internal
+	 * cgroup hierarchy.
+	 */
+	bfq_link_bfqg(bfqd, bfqg);
+	__bfq_bic_change_cgroup(bfqd, bic, bfqg);
 	/*
 	 * Update blkg_path for bfq_log_* functions. We cache this
 	 * path, and update it here, for the following
@@ -773,8 +813,6 @@
 	 */
 	blkg_path(bfqg_to_blkg(bfqg), bfqg->blkg_path, sizeof(bfqg->blkg_path));
 	bic->blkcg_serial_nr = serial_nr;
-out:
-	rcu_read_unlock();
 }
 
 /**
@@ -792,39 +830,53 @@
 /**
  * bfq_reparent_leaf_entity - move leaf entity to the root_group.
  * @bfqd: the device data structure with the root group.
- * @entity: the entity to move.
+ * @entity: the entity to move, if entity is a leaf; or the parent entity
+ *	    of an active leaf entity to move, if entity is not a leaf.
  */
 static void bfq_reparent_leaf_entity(struct bfq_data *bfqd,
-				     struct bfq_entity *entity)
+				     struct bfq_entity *entity,
+				     int ioprio_class)
 {
-	struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
+	struct bfq_queue *bfqq;
+	struct bfq_entity *child_entity = entity;
+
+	while (child_entity->my_sched_data) { /* leaf not reached yet */
+		struct bfq_sched_data *child_sd = child_entity->my_sched_data;
+		struct bfq_service_tree *child_st = child_sd->service_tree +
+			ioprio_class;
+		struct rb_root *child_active = &child_st->active;
+
+		child_entity = bfq_entity_of(rb_first(child_active));
+
+		if (!child_entity)
+			child_entity = child_sd->in_service_entity;
+	}
 
+	bfqq = bfq_entity_to_bfqq(child_entity);
 	bfq_bfqq_move(bfqd, bfqq, bfqd->root_group);
 }
 
 /**
- * bfq_reparent_active_entities - move to the root group all active
- *                                entities.
+ * bfq_reparent_active_queues - move to the root group all active queues.
  * @bfqd: the device data structure with the root group.
  * @bfqg: the group to move from.
- * @st: the service tree with the entities.
+ * @st: the service tree to start the search from.
  */
-static void bfq_reparent_active_entities(struct bfq_data *bfqd,
-					 struct bfq_group *bfqg,
-					 struct bfq_service_tree *st)
+static void bfq_reparent_active_queues(struct bfq_data *bfqd,
+				       struct bfq_group *bfqg,
+				       struct bfq_service_tree *st,
+				       int ioprio_class)
 {
 	struct rb_root *active = &st->active;
-	struct bfq_entity *entity = NULL;
-
-	if (!RB_EMPTY_ROOT(&st->active))
-		entity = bfq_entity_of(rb_first(active));
+	struct bfq_entity *entity;
 
-	for (; entity ; entity = bfq_entity_of(rb_first(active)))
-		bfq_reparent_leaf_entity(bfqd, entity);
+	while ((entity = bfq_entity_of(rb_first(active))))
+		bfq_reparent_leaf_entity(bfqd, entity, ioprio_class);
 
 	if (bfqg->sched_data.in_service_entity)
 		bfq_reparent_leaf_entity(bfqd,
-			bfqg->sched_data.in_service_entity);
+					 bfqg->sched_data.in_service_entity,
+					 ioprio_class);
 }
 
 /**
@@ -857,13 +909,6 @@
 		st = bfqg->sched_data.service_tree + i;
 
 		/*
-		 * The idle tree may still contain bfq_queues belonging
-		 * to exited task because they never migrated to a different
-		 * cgroup from the one being destroyed now.
-		 */
-		bfq_flush_idle_tree(st);
-
-		/*
 		 * It may happen that some queues are still active
 		 * (busy) upon group destruction (if the corresponding
 		 * processes have been forced to terminate). We move
@@ -875,13 +920,27 @@
 		 * There is no need to put the sync queues, as the
 		 * scheduler has taken no reference.
 		 */
-		bfq_reparent_active_entities(bfqd, bfqg, st);
+		bfq_reparent_active_queues(bfqd, bfqg, st, i);
+
+		/*
+		 * The idle tree may still contain bfq_queues
+		 * belonging to exited task because they never
+		 * migrated to a different cgroup from the one being
+		 * destroyed now. In addition, even
+		 * bfq_reparent_active_queues() may happen to add some
+		 * entities to the idle tree. It happens if, in some
+		 * of the calls to bfq_bfqq_move() performed by
+		 * bfq_reparent_active_queues(), the queue to move is
+		 * empty and gets expired.
+		 */
+		bfq_flush_idle_tree(st);
 	}
 
 	__bfq_deactivate_entity(entity, false);
 
 put_async_queues:
 	bfq_put_async_queues(bfqd, bfqg);
+	bfqg->online = false;
 
 	spin_unlock_irqrestore(&bfqd->lock, flags);
 	/*
@@ -1370,7 +1429,7 @@
 	bfq_end_wr_async_queues(bfqd, bfqd->root_group);
 }
 
-struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd, struct blkcg *blkcg)
+struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio)
 {
 	return bfqd->root_group;
 }
@@ -1380,6 +1439,10 @@
 	return bfqq->bfqd->root_group;
 }
 
+void bfqg_and_blkg_get(struct bfq_group *bfqg) {}
+
+void bfqg_and_blkg_put(struct bfq_group *bfqg) {}
+
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node)
 {
 	struct bfq_group *bfqg;
--- linux-ein-5.4.0.orig/block/bfq-iosched.c
+++ linux-ein-5.4.0/block/bfq-iosched.c
@@ -420,6 +420,8 @@
  */
 void bfq_schedule_dispatch(struct bfq_data *bfqd)
 {
+	lockdep_assert_held(&bfqd->lock);
+
 	if (bfqd->queued != 0) {
 		bfq_log(bfqd, "schedule dispatch");
 		blk_mq_run_hw_queues(bfqd->queue, true);
@@ -614,6 +616,10 @@
 		bfqq->pos_root = NULL;
 	}
 
+	/* oom_bfqq does not participate in queue merging */
+	if (bfqq == &bfqd->oom_bfqq)
+		return;
+
 	/*
 	 * bfqq cannot be merged any longer (see comments in
 	 * bfq_setup_cooperator): no point in adding bfqq into the
@@ -2206,10 +2212,9 @@
 
 }
 
-static bool bfq_bio_merge(struct blk_mq_hw_ctx *hctx, struct bio *bio,
+static bool bfq_bio_merge(struct request_queue *q, struct bio *bio,
 		unsigned int nr_segs)
 {
-	struct request_queue *q = hctx->queue;
 	struct bfq_data *bfqd = q->elevator->elevator_data;
 	struct request *free = NULL;
 	/*
@@ -2224,10 +2229,17 @@
 
 	spin_lock_irq(&bfqd->lock);
 
-	if (bic)
+	if (bic) {
+		/*
+		 * Make sure cgroup info is uptodate for current process before
+		 * considering the merge.
+		 */
+		bfq_bic_update_cgroup(bic, bio);
+
 		bfqd->bio_bfqq = bic_to_bfqq(bic, op_is_sync(bio->bi_opf));
-	else
+	} else {
 		bfqd->bio_bfqq = NULL;
+	}
 	bfqd->bio_bic = bic;
 
 	ret = blk_mq_sched_try_merge(q, bio, nr_segs, &free);
@@ -2248,14 +2260,15 @@
 	__rq = bfq_find_rq_fmerge(bfqd, bio, q);
 	if (__rq && elv_bio_merge_ok(__rq, bio)) {
 		*req = __rq;
+
+		if (blk_discard_mergable(__rq))
+			return ELEVATOR_DISCARD_MERGE;
 		return ELEVATOR_FRONT_MERGE;
 	}
 
 	return ELEVATOR_NO_MERGE;
 }
 
-static struct bfq_queue *bfq_init_rq(struct request *rq);
-
 static void bfq_request_merged(struct request_queue *q, struct request *req,
 			       enum elv_merge type)
 {
@@ -2264,7 +2277,7 @@
 	    blk_rq_pos(req) <
 	    blk_rq_pos(container_of(rb_prev(&req->rb_node),
 				    struct request, rb_node))) {
-		struct bfq_queue *bfqq = bfq_init_rq(req);
+		struct bfq_queue *bfqq = RQ_BFQQ(req);
 		struct bfq_data *bfqd;
 		struct request *prev, *next_rq;
 
@@ -2316,8 +2329,8 @@
 static void bfq_requests_merged(struct request_queue *q, struct request *rq,
 				struct request *next)
 {
-	struct bfq_queue *bfqq = bfq_init_rq(rq),
-		*next_bfqq = bfq_init_rq(next);
+	struct bfq_queue *bfqq = RQ_BFQQ(rq),
+		*next_bfqq = RQ_BFQQ(next);
 
 	if (!bfqq)
 		return;
@@ -2496,6 +2509,14 @@
 	if (process_refs == 0 || new_process_refs == 0)
 		return NULL;
 
+	/*
+	 * Make sure merged queues belong to the same parent. Parents could
+	 * have changed since the time we decided the two queues are suitable
+	 * for merging.
+	 */
+	if (new_bfqq->entity.parent != bfqq->entity.parent)
+		return NULL;
+
 	bfq_log_bfqq(bfqq->bfqd, bfqq, "scheduling merge with queue %d",
 		new_bfqq->pid);
 
@@ -2520,6 +2541,15 @@
 	 * are likely to increase the throughput.
 	 */
 	bfqq->new_bfqq = new_bfqq;
+	/*
+	 * The above assignment schedules the following redirections:
+	 * each time some I/O for bfqq arrives, the process that
+	 * generated that I/O is disassociated from bfqq and
+	 * associated with new_bfqq. Here we increases new_bfqq->ref
+	 * in advance, adding the number of processes that are
+	 * expected to be associated with new_bfqq as they happen to
+	 * issue I/O.
+	 */
 	new_bfqq->ref += process_refs;
 	return new_bfqq;
 }
@@ -2579,6 +2609,10 @@
 {
 	struct bfq_queue *in_service_bfqq, *new_bfqq;
 
+	/* if a merge has already been setup, then proceed with that first */
+	if (bfqq->new_bfqq)
+		return bfqq->new_bfqq;
+
 	/*
 	 * Do not perform queue merging if the device is non
 	 * rotational and performs internal queueing. In fact, such a
@@ -2633,9 +2667,6 @@
 	if (bfq_too_late_for_merging(bfqq))
 		return NULL;
 
-	if (bfqq->new_bfqq)
-		return bfqq->new_bfqq;
-
 	if (!io_struct || unlikely(bfqq == &bfqd->oom_bfqq))
 		return NULL;
 
@@ -2713,8 +2744,6 @@
 	}
 }
 
-
-static
 void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 {
 	/*
@@ -2935,6 +2964,7 @@
 	}
 
 	bfqd->in_service_queue = bfqq;
+	bfqd->in_serv_last_pos = 0;
 }
 
 /*
@@ -3444,6 +3474,10 @@
 static bool idling_needed_for_service_guarantees(struct bfq_data *bfqd,
 						 struct bfq_queue *bfqq)
 {
+	/* No point in idling for bfqq if it won't get requests any longer */
+	if (unlikely(!bfqq_process_refs(bfqq)))
+		return false;
+
 	return (bfqq->wr_coeff > 1 &&
 		(bfqd->wr_busy_queues <
 		 bfq_tot_busy_queues(bfqd) ||
@@ -4077,6 +4111,10 @@
 		bfqq_sequential_and_IO_bound,
 		idling_boosts_thr;
 
+	/* No point in idling for bfqq if it won't get requests any longer */
+	if (unlikely(!bfqq_process_refs(bfqq)))
+		return false;
+
 	bfqq_sequential_and_IO_bound = !BFQQ_SEEKY(bfqq) &&
 		bfq_bfqq_IO_bound(bfqq) && bfq_bfqq_has_short_ttime(bfqq);
 
@@ -4170,6 +4208,10 @@
 	struct bfq_data *bfqd = bfqq->bfqd;
 	bool idling_boosts_thr_with_no_issue, idling_needed_for_service_guar;
 
+	/* No point in idling for bfqq if it won't get requests any longer */
+	if (unlikely(!bfqq_process_refs(bfqq)))
+		return false;
+
 	if (unlikely(bfqd->strict_guarantees))
 		return true;
 
@@ -4779,7 +4821,7 @@
 	struct bfq_data *bfqd = hctx->queue->elevator->elevator_data;
 	struct request *rq;
 	struct bfq_queue *in_serv_queue;
-	bool waiting_rq, idle_timer_disabled;
+	bool waiting_rq, idle_timer_disabled = false;
 
 	spin_lock_irq(&bfqd->lock);
 
@@ -4787,14 +4829,15 @@
 	waiting_rq = in_serv_queue && bfq_bfqq_wait_request(in_serv_queue);
 
 	rq = __bfq_dispatch_request(hctx);
-
-	idle_timer_disabled =
-		waiting_rq && !bfq_bfqq_wait_request(in_serv_queue);
+	if (in_serv_queue == bfqd->in_service_queue) {
+		idle_timer_disabled =
+			waiting_rq && !bfq_bfqq_wait_request(in_serv_queue);
+	}
 
 	spin_unlock_irq(&bfqd->lock);
-
-	bfq_update_dispatch_stats(hctx->queue, rq, in_serv_queue,
-				  idle_timer_disabled);
+	bfq_update_dispatch_stats(hctx->queue, rq,
+			idle_timer_disabled ? in_serv_queue : NULL,
+				idle_timer_disabled);
 
 	return rq;
 }
@@ -4810,9 +4853,7 @@
 {
 	struct bfq_queue *item;
 	struct hlist_node *n;
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
 	struct bfq_group *bfqg = bfqq_group(bfqq);
-#endif
 
 	if (bfqq->bfqd)
 		bfq_log_bfqq(bfqq->bfqd, bfqq, "put_queue: %p %d",
@@ -4885,12 +4926,10 @@
 		bfqq->bfqd->last_completed_rq_bfqq = NULL;
 
 	kmem_cache_free(bfq_pool, bfqq);
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
 	bfqg_and_blkg_put(bfqg);
-#endif
 }
 
-static void bfq_put_cooperator(struct bfq_queue *bfqq)
+void bfq_put_cooperator(struct bfq_queue *bfqq)
 {
 	struct bfq_queue *__bfqq, *next;
 
@@ -4994,7 +5033,7 @@
 	if (bfqq->new_ioprio >= IOPRIO_BE_NR) {
 		pr_crit("bfq_set_next_ioprio_data: new_ioprio %d\n",
 			bfqq->new_ioprio);
-		bfqq->new_ioprio = IOPRIO_BE_NR;
+		bfqq->new_ioprio = IOPRIO_BE_NR - 1;
 	}
 
 	bfqq->entity.new_weight = bfq_ioprio_to_weight(bfqq->new_ioprio);
@@ -5121,14 +5160,7 @@
 	struct bfq_queue *bfqq;
 	struct bfq_group *bfqg;
 
-	rcu_read_lock();
-
-	bfqg = bfq_find_set_group(bfqd, __bio_blkcg(bio));
-	if (!bfqg) {
-		bfqq = &bfqd->oom_bfqq;
-		goto out;
-	}
-
+	bfqg = bfq_bio_bfqg(bfqd, bio);
 	if (!is_sync) {
 		async_bfqq = bfq_async_queue_prio(bfqd, bfqg, ioprio_class,
 						  ioprio);
@@ -5172,7 +5204,6 @@
 out:
 	bfqq->ref++; /* get a process reference to this queue */
 	bfq_log_bfqq(bfqd, bfqq, "get_queue, at end: %p, %d", bfqq, bfqq->ref);
-	rcu_read_unlock();
 	return bfqq;
 }
 
@@ -5475,6 +5506,8 @@
 					   unsigned int cmd_flags) {}
 #endif /* CONFIG_BFQ_CGROUP_DEBUG */
 
+static struct bfq_queue *bfq_init_rq(struct request *rq);
+
 static void bfq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
 			       bool at_head)
 {
@@ -5485,17 +5518,14 @@
 	unsigned int cmd_flags;
 
 	spin_lock_irq(&bfqd->lock);
+	bfqq = bfq_init_rq(rq);
 	if (blk_mq_sched_try_insert_merge(q, rq)) {
 		spin_unlock_irq(&bfqd->lock);
 		return;
 	}
 
-	spin_unlock_irq(&bfqd->lock);
-
 	blk_mq_sched_request_inserted(rq);
 
-	spin_lock_irq(&bfqd->lock);
-	bfqq = bfq_init_rq(rq);
 	if (!bfqq || at_head || blk_rq_is_passthrough(rq)) {
 		if (at_head)
 			list_add(&rq->queuelist, &bfqd->dispatch);
@@ -5881,18 +5911,6 @@
 	struct bfq_data *bfqd;
 
 	/*
-	 * Requeue and finish hooks are invoked in blk-mq without
-	 * checking whether the involved request is actually still
-	 * referenced in the scheduler. To handle this fact, the
-	 * following two checks make this function exit in case of
-	 * spurious invocations, for which there is nothing to do.
-	 *
-	 * First, check whether rq has nothing to do with an elevator.
-	 */
-	if (unlikely(!(rq->rq_flags & RQF_ELVPRIV)))
-		return;
-
-	/*
 	 * rq either is not associated with any icq, or is an already
 	 * requeued request that has not (yet) been re-inserted into
 	 * a bfq_queue.
@@ -6198,20 +6216,28 @@
 	return bfqq;
 }
 
-static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq)
+static void
+bfq_idle_slice_timer_body(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 {
-	struct bfq_data *bfqd = bfqq->bfqd;
 	enum bfqq_expiration reason;
 	unsigned long flags;
 
 	spin_lock_irqsave(&bfqd->lock, flags);
-	bfq_clear_bfqq_wait_request(bfqq);
 
+	/*
+	 * Considering that bfqq may be in race, we should firstly check
+	 * whether bfqq is in service before doing something on it. If
+	 * the bfqq in race is not in service, it has already been expired
+	 * through __bfq_bfqq_expire func and its wait_request flags has
+	 * been cleared in __bfq_bfqd_reset_in_service func.
+	 */
 	if (bfqq != bfqd->in_service_queue) {
 		spin_unlock_irqrestore(&bfqd->lock, flags);
 		return;
 	}
 
+	bfq_clear_bfqq_wait_request(bfqq);
+
 	if (bfq_bfqq_budget_timeout(bfqq))
 		/*
 		 * Also here the queue can be safely expired
@@ -6233,8 +6259,8 @@
 	bfq_bfqq_expire(bfqd, bfqq, true, reason);
 
 schedule_dispatch:
-	spin_unlock_irqrestore(&bfqd->lock, flags);
 	bfq_schedule_dispatch(bfqd);
+	spin_unlock_irqrestore(&bfqd->lock, flags);
 }
 
 /*
@@ -6256,7 +6282,7 @@
 	 * early.
 	 */
 	if (bfqq)
-		bfq_idle_slice_timer_body(bfqq);
+		bfq_idle_slice_timer_body(bfqd, bfqq);
 
 	return HRTIMER_NORESTART;
 }
@@ -6371,10 +6397,10 @@
 
 	hrtimer_cancel(&bfqd->idle_slice_timer);
 
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
 	/* release oom-queue reference to root group */
 	bfqg_and_blkg_put(bfqd->root_group);
 
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
 	blkcg_deactivate_policy(bfqd->queue, &blkcg_policy_bfq);
 #else
 	spin_lock_irq(&bfqd->lock);
@@ -6383,6 +6409,8 @@
 	spin_unlock_irq(&bfqd->lock);
 #endif
 
+	wbt_enable_default(bfqd->queue);
+
 	kfree(bfqd);
 }
 
--- linux-ein-5.4.0.orig/block/bfq-iosched.h
+++ linux-ein-5.4.0/block/bfq-iosched.h
@@ -896,6 +896,8 @@
 
 	/* reference counter (see comments in bfq_bic_update_cgroup) */
 	int ref;
+	/* Is bfq_group still online? */
+	bool online;
 
 	struct bfq_entity entity;
 	struct bfq_sched_data sched_data;
@@ -916,6 +918,7 @@
 
 #else
 struct bfq_group {
+	struct bfq_entity entity;
 	struct bfq_sched_data sched_data;
 
 	struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR];
@@ -948,7 +951,9 @@
 void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
 		     bool compensate, enum bfqq_expiration reason);
 void bfq_put_queue(struct bfq_queue *bfqq);
+void bfq_put_cooperator(struct bfq_queue *bfqq);
 void bfq_end_wr_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
+void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq);
 void bfq_schedule_dispatch(struct bfq_data *bfqd);
 void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
 
@@ -973,8 +978,7 @@
 void bfq_init_entity(struct bfq_entity *entity, struct bfq_group *bfqg);
 void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio);
 void bfq_end_wr_async(struct bfq_data *bfqd);
-struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
-				     struct blkcg *blkcg);
+struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio);
 struct blkcg_gq *bfqg_to_blkg(struct bfq_group *bfqg);
 struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node);
--- linux-ein-5.4.0.orig/block/bio-integrity.c
+++ linux-ein-5.4.0/block/bio-integrity.c
@@ -24,6 +24,18 @@
 	flush_workqueue(kintegrityd_wq);
 }
 
+void __bio_integrity_free(struct bio_set *bs, struct bio_integrity_payload *bip)
+{
+	if (bs && mempool_initialized(&bs->bio_integrity_pool)) {
+		if (bip->bip_vec)
+			bvec_free(&bs->bvec_integrity_pool, bip->bip_vec,
+				  bip->bip_slab);
+		mempool_free(bip, &bs->bio_integrity_pool);
+	} else {
+		kfree(bip);
+	}
+}
+
 /**
  * bio_integrity_alloc - Allocate integrity payload and attach it to bio
  * @bio:	bio to attach integrity metadata to
@@ -75,7 +87,7 @@
 
 	return bip;
 err:
-	mempool_free(bip, &bs->bio_integrity_pool);
+	__bio_integrity_free(bs, bip);
 	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(bio_integrity_alloc);
@@ -87,7 +99,7 @@
  * Description: Used to free the integrity portion of a bio. Usually
  * called from bio_free().
  */
-static void bio_integrity_free(struct bio *bio)
+void bio_integrity_free(struct bio *bio)
 {
 	struct bio_integrity_payload *bip = bio_integrity(bio);
 	struct bio_set *bs = bio->bi_pool;
@@ -96,14 +108,7 @@
 		kfree(page_address(bip->bip_vec->bv_page) +
 		      bip->bip_vec->bv_offset);
 
-	if (bs && mempool_initialized(&bs->bio_integrity_pool)) {
-		bvec_free(&bs->bvec_integrity_pool, bip->bip_vec, bip->bip_slab);
-
-		mempool_free(bip, &bs->bio_integrity_pool);
-	} else {
-		kfree(bip);
-	}
-
+	__bio_integrity_free(bs, bip);
 	bio->bi_integrity = NULL;
 	bio->bi_opf &= ~REQ_INTEGRITY;
 }
@@ -278,7 +283,6 @@
 
 		if (ret == 0) {
 			printk(KERN_ERR "could not attach integrity payload\n");
-			kfree(buf);
 			status = BLK_STS_RESOURCE;
 			goto err_end_io;
 		}
@@ -376,7 +380,7 @@
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_disk);
 	unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
-	bip->bip_iter.bi_sector += bytes_done >> 9;
+	bip->bip_iter.bi_sector += bio_integrity_intervals(bi, bytes_done >> 9);
 	bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 
@@ -420,6 +424,7 @@
 
 	bip->bip_vcnt = bip_src->bip_vcnt;
 	bip->bip_iter = bip_src->bip_iter;
+	bip->bip_flags = bip_src->bip_flags & ~BIP_BLOCK_INTEGRITY;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/block/bio.c
+++ linux-ein-5.4.0/block/bio.c
@@ -233,6 +233,9 @@
 void bio_uninit(struct bio *bio)
 {
 	bio_disassociate_blkg(bio);
+
+	if (bio_integrity(bio))
+		bio_integrity_free(bio);
 }
 EXPORT_SYMBOL(bio_uninit);
 
@@ -302,7 +305,7 @@
 {
 	struct bio *parent = bio->bi_private;
 
-	if (!parent->bi_status)
+	if (bio->bi_status && !parent->bi_status)
 		parent->bi_status = bio->bi_status;
 	bio_put(bio);
 	return parent;
@@ -536,6 +539,56 @@
 EXPORT_SYMBOL(zero_fill_bio_iter);
 
 /**
+ * bio_truncate - truncate the bio to small size of @new_size
+ * @bio:	the bio to be truncated
+ * @new_size:	new size for truncating the bio
+ *
+ * Description:
+ *   Truncate the bio to new size of @new_size. If bio_op(bio) is
+ *   REQ_OP_READ, zero the truncated part. This function should only
+ *   be used for handling corner cases, such as bio eod.
+ */
+void bio_truncate(struct bio *bio, unsigned new_size)
+{
+	struct bio_vec bv;
+	struct bvec_iter iter;
+	unsigned int done = 0;
+	bool truncated = false;
+
+	if (new_size >= bio->bi_iter.bi_size)
+		return;
+
+	if (bio_op(bio) != REQ_OP_READ)
+		goto exit;
+
+	bio_for_each_segment(bv, bio, iter) {
+		if (done + bv.bv_len > new_size) {
+			unsigned offset;
+
+			if (!truncated)
+				offset = new_size - done;
+			else
+				offset = 0;
+			zero_user(bv.bv_page, bv.bv_offset + offset,
+				  bv.bv_len - offset);
+			truncated = true;
+		}
+		done += bv.bv_len;
+	}
+
+ exit:
+	/*
+	 * Don't touch bvec table here and make it really immutable, since
+	 * fs bio user has to retrieve all pages via bio_for_each_segment_all
+	 * in its .end_bio() callback.
+	 *
+	 * It is enough to truncate bio by updating .bi_size since we can make
+	 * correct bvec with the updated .bi_size for drivers.
+	 */
+	bio->bi_iter.bi_size = new_size;
+}
+
+/**
  * bio_put - release a reference to a bio
  * @bio:   bio to release reference to
  *
@@ -631,8 +684,8 @@
 		struct page *page, unsigned int len, unsigned int off,
 		bool *same_page)
 {
-	phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) +
-		bv->bv_offset + bv->bv_len - 1;
+	size_t bv_end = bv->bv_offset + bv->bv_len;
+	phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) + bv_end - 1;
 	phys_addr_t page_addr = page_to_phys(page);
 
 	if (vec_end_addr + 1 != page_addr + off)
@@ -641,9 +694,9 @@
 		return false;
 
 	*same_page = ((vec_end_addr & PAGE_MASK) == page_addr);
-	if (!*same_page && pfn_to_page(PFN_DOWN(vec_end_addr)) + 1 != page)
-		return false;
-	return true;
+	if (*same_page)
+		return true;
+	return (bv->bv_page + bv_end / PAGE_SIZE) == (page + off / PAGE_SIZE);
 }
 
 static bool bio_try_merge_pc_page(struct request_queue *q, struct bio *bio,
@@ -657,7 +710,7 @@
 
 	if ((addr1 | mask) != (addr2 | mask))
 		return false;
-	if (bv->bv_len + len > queue_max_segment_size(q))
+	if (len > queue_max_segment_size(q) - bv->bv_len)
 		return false;
 	return __bio_try_merge_page(bio, page, len, offset, same_page);
 }
@@ -751,10 +804,14 @@
 	if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
 		return false;
 
-	if (bio->bi_vcnt > 0 && !bio_full(bio, len)) {
+	if (bio->bi_vcnt > 0) {
 		struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
 
 		if (page_is_mergeable(bv, page, len, off, same_page)) {
+			if (bio->bi_iter.bi_size > UINT_MAX - len) {
+				*same_page = false;
+				return false;
+			}
 			bv->bv_len += len;
 			bio->bi_iter.bi_size += len;
 			return true;
@@ -827,7 +884,7 @@
 		return;
 
 	bio_for_each_segment_all(bvec, bio, iter_all) {
-		if (mark_dirty && !PageCompound(bvec->bv_page))
+		if (mark_dirty)
 			set_page_dirty_lock(bvec->bv_page);
 		put_page(bvec->bv_page);
 	}
@@ -1570,7 +1627,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;
 
@@ -1634,8 +1691,7 @@
 	struct bvec_iter_all iter_all;
 
 	bio_for_each_segment_all(bvec, bio, iter_all) {
-		if (!PageCompound(bvec->bv_page))
-			set_page_dirty_lock(bvec->bv_page);
+		set_page_dirty_lock(bvec->bv_page);
 	}
 }
 
@@ -1683,7 +1739,7 @@
 	struct bvec_iter_all iter_all;
 
 	bio_for_each_segment_all(bvec, bio, iter_all) {
-		if (!PageDirty(bvec->bv_page) && !PageCompound(bvec->bv_page))
+		if (!PageDirty(bvec->bv_page))
 			goto defer;
 	}
 
@@ -1698,14 +1754,14 @@
 	schedule_work(&bio_dirty_work);
 }
 
-void update_io_ticks(struct hd_struct *part, unsigned long now)
+void update_io_ticks(struct hd_struct *part, unsigned long now, bool end)
 {
 	unsigned long stamp;
 again:
 	stamp = READ_ONCE(part->stamp);
 	if (unlikely(stamp != now)) {
 		if (likely(cmpxchg(&part->stamp, stamp, now) == stamp)) {
-			__part_stat_add(part, io_ticks, 1);
+			__part_stat_add(part, io_ticks, end ? now - stamp : 1);
 		}
 	}
 	if (part->partno) {
@@ -1721,7 +1777,7 @@
 
 	part_stat_lock();
 
-	update_io_ticks(part, jiffies);
+	update_io_ticks(part, jiffies, false);
 	part_stat_inc(part, ios[sgrp]);
 	part_stat_add(part, sectors[sgrp], sectors);
 	part_inc_in_flight(q, part, op_is_write(op));
@@ -1739,7 +1795,7 @@
 
 	part_stat_lock();
 
-	update_io_ticks(part, now);
+	update_io_ticks(part, now, true);
 	part_stat_add(part, nsecs[sgrp], jiffies_to_nsecs(duration));
 	part_stat_add(part, time_in_queue, duration);
 	part_dec_in_flight(q, part, op_is_write(req_op));
@@ -2122,7 +2178,7 @@
 	rcu_read_lock();
 
 	if (src->bi_blkg)
-		__bio_associate_blkg(dst, src->bi_blkg);
+		bio_associate_blkg_from_css(dst, &bio_blkcg(src)->css);
 
 	rcu_read_unlock();
 }
--- linux-ein-5.4.0.orig/block/blk-cgroup.c
+++ linux-ein-5.4.0/block/blk-cgroup.c
@@ -855,13 +855,20 @@
 			goto fail;
 		}
 
+		if (radix_tree_preload(GFP_KERNEL)) {
+			blkg_free(new_blkg);
+			ret = -ENOMEM;
+			goto fail;
+		}
+
 		rcu_read_lock();
 		spin_lock_irq(&q->queue_lock);
 
 		blkg = blkg_lookup_check(pos, pol, q);
 		if (IS_ERR(blkg)) {
 			ret = PTR_ERR(blkg);
-			goto fail_unlock;
+			blkg_free(new_blkg);
+			goto fail_preloaded;
 		}
 
 		if (blkg) {
@@ -870,10 +877,12 @@
 			blkg = blkg_create(pos, q, new_blkg);
 			if (IS_ERR(blkg)) {
 				ret = PTR_ERR(blkg);
-				goto fail_unlock;
+				goto fail_preloaded;
 			}
 		}
 
+		radix_tree_preload_end();
+
 		if (pos == blkcg)
 			goto success;
 	}
@@ -883,6 +892,8 @@
 	ctx->body = input;
 	return 0;
 
+fail_preloaded:
+	radix_tree_preload_end();
 fail_unlock:
 	spin_unlock_irq(&q->queue_lock);
 	rcu_read_unlock();
@@ -1078,6 +1089,8 @@
  */
 void blkcg_destroy_blkgs(struct blkcg *blkcg)
 {
+	might_sleep();
+
 	spin_lock_irq(&blkcg->lock);
 
 	while (!hlist_empty(&blkcg->blkg_list)) {
@@ -1085,14 +1098,20 @@
 						struct blkcg_gq, blkcg_node);
 		struct request_queue *q = blkg->q;
 
-		if (spin_trylock(&q->queue_lock)) {
-			blkg_destroy(blkg);
-			spin_unlock(&q->queue_lock);
-		} else {
+		if (need_resched() || !spin_trylock(&q->queue_lock)) {
+			/*
+			 * Given that the system can accumulate a huge number
+			 * of blkgs in pathological cases, check to see if we
+			 * need to rescheduling to avoid softlockup.
+			 */
 			spin_unlock_irq(&blkcg->lock);
-			cpu_relax();
+			cond_resched();
 			spin_lock_irq(&blkcg->lock);
+			continue;
 		}
+
+		blkg_destroy(blkg);
+		spin_unlock(&q->queue_lock);
 	}
 
 	spin_unlock_irq(&blkcg->lock);
@@ -1219,13 +1238,15 @@
 	if (preloaded)
 		radix_tree_preload_end();
 
-	ret = blk_iolatency_init(q);
+	ret = blk_throtl_init(q);
 	if (ret)
 		goto err_destroy_all;
 
-	ret = blk_throtl_init(q);
-	if (ret)
+	ret = blk_iolatency_init(q);
+	if (ret) {
+		blk_throtl_exit(q);
 		goto err_destroy_all;
+	}
 	return 0;
 
 err_destroy_all:
@@ -1424,6 +1445,10 @@
 		list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
 			pol->pd_init_fn(blkg->pd[pol->plid]);
 
+	if (pol->pd_online_fn)
+		list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
+			pol->pd_online_fn(blkg->pd[pol->plid]);
+
 	__set_bit(pol->plid, q->blkcg_pols);
 	ret = 0;
 
@@ -1441,10 +1466,14 @@
 	/* alloc failed, nothing's initialized yet, free everything */
 	spin_lock_irq(&q->queue_lock);
 	list_for_each_entry(blkg, &q->blkg_list, q_node) {
+		struct blkcg *blkcg = blkg->blkcg;
+
+		spin_lock(&blkcg->lock);
 		if (blkg->pd[pol->plid]) {
 			pol->pd_free_fn(blkg->pd[pol->plid]);
 			blkg->pd[pol->plid] = NULL;
 		}
+		spin_unlock(&blkcg->lock);
 	}
 	spin_unlock_irq(&q->queue_lock);
 	ret = -ENOMEM;
@@ -1476,12 +1505,16 @@
 	__clear_bit(pol->plid, q->blkcg_pols);
 
 	list_for_each_entry(blkg, &q->blkg_list, q_node) {
+		struct blkcg *blkcg = blkg->blkcg;
+
+		spin_lock(&blkcg->lock);
 		if (blkg->pd[pol->plid]) {
 			if (pol->pd_offline_fn)
 				pol->pd_offline_fn(blkg->pd[pol->plid]);
 			pol->pd_free_fn(blkg->pd[pol->plid]);
 			blkg->pd[pol->plid] = NULL;
 		}
+		spin_unlock(&blkcg->lock);
 	}
 
 	spin_unlock_irq(&q->queue_lock);
--- linux-ein-5.4.0.orig/block/blk-core.c
+++ linux-ein-5.4.0/block/blk-core.c
@@ -502,6 +502,7 @@
 		goto fail_stats;
 
 	q->backing_dev_info->ra_pages = VM_READAHEAD_PAGES;
+	q->backing_dev_info->io_pages = VM_READAHEAD_PAGES;
 	q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
 	q->backing_dev_info->name = "block";
 	q->node = node_id;
@@ -742,11 +743,10 @@
 {
 	char b[BDEVNAME_SIZE];
 
-	printk(KERN_INFO "attempt to access beyond end of device\n");
-	printk(KERN_INFO "%s: rw=%d, want=%Lu, limit=%Lu\n",
-			bio_devname(bio, b), bio->bi_opf,
-			(unsigned long long)bio_end_sector(bio),
-			(long long)maxsector);
+	pr_info_ratelimited("attempt to access beyond end of device\n"
+			    "%s: rw=%d, want=%llu, limit=%llu\n",
+			    bio_devname(bio, b), bio->bi_opf,
+			    bio_end_sector(bio), maxsector);
 }
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -793,10 +793,7 @@
 
 		if (op_is_flush(bio->bi_opf) && !bio_sectors(bio))
 			return false;
-
-		WARN_ONCE(1,
-		       "generic_make_request: Trying to write "
-			"to read-only block-device %s (partno %d)\n",
+		pr_warn("Trying to write to read-only block-device %s (partno %d)\n",
 			bio_devname(bio, b), part->partno);
 		/* Older lvm-tools actually trigger this */
 		return false;
@@ -886,11 +883,14 @@
 	}
 
 	/*
-	 * For a REQ_NOWAIT based request, return -EOPNOTSUPP
-	 * if queue is not a request based queue.
+	 * Non-mq queues do not honor REQ_NOWAIT, so complete a bio
+	 * with BLK_STS_AGAIN status in order to catch -EAGAIN and
+	 * to give a chance to the caller to repeat request gracefully.
 	 */
-	if ((bio->bi_opf & REQ_NOWAIT) && !queue_is_mq(q))
-		goto not_supported;
+	if ((bio->bi_opf & REQ_NOWAIT) && !queue_is_mq(q)) {
+		status = BLK_STS_AGAIN;
+		goto end_io;
+	}
 
 	if (should_fail_bio(bio))
 		goto end_io;
@@ -1333,7 +1333,7 @@
 		part_stat_lock();
 		part = req->part;
 
-		update_io_ticks(part, jiffies);
+		update_io_ticks(part, jiffies, true);
 		part_stat_inc(part, ios[sgrp]);
 		part_stat_add(part, nsecs[sgrp], now - req->start_time_ns);
 		part_stat_add(part, time_in_queue, nsecs_to_jiffies64(now - req->start_time_ns));
@@ -1375,7 +1375,7 @@
 		rq->part = part;
 	}
 
-	update_io_ticks(part, jiffies);
+	update_io_ticks(part, jiffies, false);
 
 	part_stat_unlock();
 }
--- linux-ein-5.4.0.orig/block/blk-flush.c
+++ linux-ein-5.4.0/block/blk-flush.c
@@ -69,6 +69,7 @@
 #include <linux/blkdev.h>
 #include <linux/gfp.h>
 #include <linux/blk-mq.h>
+#include <linux/lockdep.h>
 
 #include "blk.h"
 #include "blk-mq.h"
@@ -221,8 +222,10 @@
 		return;
 	}
 
-	if (fq->rq_status != BLK_STS_OK)
+	if (fq->rq_status != BLK_STS_OK) {
 		error = fq->rq_status;
+		fq->rq_status = BLK_STS_OK;
+	}
 
 	hctx = flush_rq->mq_hctx;
 	if (!q->elevator) {
@@ -398,7 +401,7 @@
 	 */
 	if ((policy & REQ_FSEQ_DATA) &&
 	    !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
-		blk_mq_request_bypass_insert(rq, false);
+		blk_mq_request_bypass_insert(rq, false, false);
 		return;
 	}
 
@@ -492,6 +495,9 @@
 	INIT_LIST_HEAD(&fq->flush_queue[1]);
 	INIT_LIST_HEAD(&fq->flush_data_in_flight);
 
+	lockdep_register_key(&fq->key);
+	lockdep_set_class(&fq->mq_flush_lock, &fq->key);
+
 	return fq;
 
  fail_rq:
@@ -506,6 +512,7 @@
 	if (!fq)
 		return;
 
+	lockdep_unregister_key(&fq->key);
 	kfree(fq->flush_rq);
 	kfree(fq);
 }
--- linux-ein-5.4.0.orig/block/blk-ioc.c
+++ linux-ein-5.4.0/block/blk-ioc.c
@@ -84,6 +84,7 @@
 	 * making it impossible to determine icq_cache.  Record it in @icq.
 	 */
 	icq->__rcu_icq_cache = et->icq_cache;
+	icq->flags |= ICQ_DESTROYED;
 	call_rcu(&icq->__rcu_head, icq_free_icq_rcu);
 }
 
@@ -212,15 +213,21 @@
 {
 	unsigned long flags;
 
+	rcu_read_lock();
 	while (!list_empty(icq_list)) {
 		struct io_cq *icq = list_entry(icq_list->next,
 						struct io_cq, q_node);
 		struct io_context *ioc = icq->ioc;
 
 		spin_lock_irqsave(&ioc->lock, flags);
+		if (icq->flags & ICQ_DESTROYED) {
+			spin_unlock_irqrestore(&ioc->lock, flags);
+			continue;
+		}
 		ioc_destroy_icq(icq);
 		spin_unlock_irqrestore(&ioc->lock, flags);
 	}
+	rcu_read_unlock();
 }
 
 /**
--- linux-ein-5.4.0.orig/block/blk-iocost.c
+++ linux-ein-5.4.0/block/blk-iocost.c
@@ -248,7 +248,9 @@
 
 	/* 1/64k is granular enough and can easily be handled w/ u32 */
 	HWEIGHT_WHOLE		= 1 << 16,
+};
 
+enum {
 	/*
 	 * As vtime is used to calculate the cost of each IO, it needs to
 	 * be fairly high precision.  For example, it should be able to
@@ -271,6 +273,11 @@
 	VRATE_MIN		= VTIME_PER_USEC * VRATE_MIN_PPM / MILLION,
 	VRATE_CLAMP_ADJ_PCT	= 4,
 
+	/* switch iff the conditions are met for longer than this */
+	AUTOP_CYCLE_NSEC	= 10LLU * NSEC_PER_SEC,
+};
+
+enum {
 	/* if IOs end up waiting for requests, issue less */
 	RQ_WAIT_BUSY_PCT	= 5,
 
@@ -288,9 +295,6 @@
 	SURPLUS_SCALE_ABS	= HWEIGHT_WHOLE / 50,	/* + 2% */
 	SURPLUS_MIN_ADJ_DELTA	= HWEIGHT_WHOLE / 33,	/* 3% */
 
-	/* switch iff the conditions are met for longer than this */
-	AUTOP_CYCLE_NSEC	= 10LLU * NSEC_PER_SEC,
-
 	/*
 	 * Count IO size in 4k pages.  The 12bit shift helps keeping
 	 * size-proportional components of cost calculation in closer
@@ -469,7 +473,7 @@
 	 */
 	atomic64_t			vtime;
 	atomic64_t			done_vtime;
-	atomic64_t			abs_vdebt;
+	u64				abs_vdebt;
 	u64				last_vtime;
 
 	/*
@@ -785,9 +789,14 @@
 
 	*page = *seqio = *randio = 0;
 
-	if (bps)
-		*page = DIV64_U64_ROUND_UP(VTIME_PER_SEC,
-					   DIV_ROUND_UP_ULL(bps, IOC_PAGE_SIZE));
+	if (bps) {
+		u64 bps_pages = DIV_ROUND_UP_ULL(bps, IOC_PAGE_SIZE);
+
+		if (bps_pages)
+			*page = DIV64_U64_ROUND_UP(VTIME_PER_SEC, bps_pages);
+		else
+			*page = 1;
+	}
 
 	if (seqiops) {
 		v = DIV64_U64_ROUND_UP(VTIME_PER_SEC, seqiops);
@@ -1145,7 +1154,7 @@
 	struct iocg_wake_ctx ctx = { .iocg = iocg };
 	u64 margin_ns = (u64)(ioc->period_us *
 			      WAITQ_TIMER_MARGIN_PCT / 100) * NSEC_PER_USEC;
-	u64 abs_vdebt, vdebt, vshortage, expires, oexpires;
+	u64 vdebt, vshortage, expires, oexpires;
 	s64 vbudget;
 	u32 hw_inuse;
 
@@ -1155,18 +1164,15 @@
 	vbudget = now->vnow - atomic64_read(&iocg->vtime);
 
 	/* pay off debt */
-	abs_vdebt = atomic64_read(&iocg->abs_vdebt);
-	vdebt = abs_cost_to_cost(abs_vdebt, hw_inuse);
+	vdebt = abs_cost_to_cost(iocg->abs_vdebt, hw_inuse);
 	if (vdebt && vbudget > 0) {
 		u64 delta = min_t(u64, vbudget, vdebt);
 		u64 abs_delta = min(cost_to_abs_cost(delta, hw_inuse),
-				    abs_vdebt);
+				    iocg->abs_vdebt);
 
 		atomic64_add(delta, &iocg->vtime);
 		atomic64_add(delta, &iocg->done_vtime);
-		atomic64_sub(abs_delta, &iocg->abs_vdebt);
-		if (WARN_ON_ONCE(atomic64_read(&iocg->abs_vdebt) < 0))
-			atomic64_set(&iocg->abs_vdebt, 0);
+		iocg->abs_vdebt -= abs_delta;
 	}
 
 	/*
@@ -1212,7 +1218,7 @@
 	return HRTIMER_NORESTART;
 }
 
-static void iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
+static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now, u64 cost)
 {
 	struct ioc *ioc = iocg->ioc;
 	struct blkcg_gq *blkg = iocg_to_blkg(iocg);
@@ -1222,18 +1228,24 @@
 	u64 expires, oexpires;
 	u32 hw_inuse;
 
+	lockdep_assert_held(&iocg->waitq.lock);
+
 	/* debt-adjust vtime */
 	current_hweight(iocg, NULL, &hw_inuse);
-	vtime += abs_cost_to_cost(atomic64_read(&iocg->abs_vdebt), hw_inuse);
+	vtime += abs_cost_to_cost(iocg->abs_vdebt, hw_inuse);
 
-	/* clear or maintain depending on the overage */
-	if (time_before_eq64(vtime, now->vnow)) {
+	/*
+	 * Clear or maintain depending on the overage. Non-zero vdebt is what
+	 * guarantees that @iocg is online and future iocg_kick_delay() will
+	 * clear use_delay. Don't leave it on when there's no vdebt.
+	 */
+	if (!iocg->abs_vdebt || time_before_eq64(vtime, now->vnow)) {
 		blkcg_clear_delay(blkg);
-		return;
+		return false;
 	}
 	if (!atomic_read(&blkg->use_delay) &&
 	    time_before_eq64(vtime, now->vnow + vmargin))
-		return;
+		return false;
 
 	/* use delay */
 	if (cost) {
@@ -1250,19 +1262,23 @@
 	oexpires = ktime_to_ns(hrtimer_get_softexpires(&iocg->delay_timer));
 	if (hrtimer_is_queued(&iocg->delay_timer) &&
 	    abs(oexpires - expires) <= margin_ns / 4)
-		return;
+		return true;
 
 	hrtimer_start_range_ns(&iocg->delay_timer, ns_to_ktime(expires),
 			       margin_ns / 4, HRTIMER_MODE_ABS);
+	return true;
 }
 
 static enum hrtimer_restart iocg_delay_timer_fn(struct hrtimer *timer)
 {
 	struct ioc_gq *iocg = container_of(timer, struct ioc_gq, delay_timer);
 	struct ioc_now now;
+	unsigned long flags;
 
+	spin_lock_irqsave(&iocg->waitq.lock, flags);
 	ioc_now(iocg->ioc, &now);
 	iocg_kick_delay(iocg, &now, 0);
+	spin_unlock_irqrestore(&iocg->waitq.lock, flags);
 
 	return HRTIMER_NORESTART;
 }
@@ -1317,7 +1333,7 @@
 		return false;
 
 	/* is something in flight? */
-	if (atomic64_read(&iocg->done_vtime) < atomic64_read(&iocg->vtime))
+	if (atomic64_read(&iocg->done_vtime) != atomic64_read(&iocg->vtime))
 		return false;
 
 	return true;
@@ -1370,14 +1386,13 @@
 	 * should have woken up in the last period and expire idle iocgs.
 	 */
 	list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
-		if (!waitqueue_active(&iocg->waitq) &&
-		    !atomic64_read(&iocg->abs_vdebt) && !iocg_is_idle(iocg))
+		if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
+		    !iocg_is_idle(iocg))
 			continue;
 
 		spin_lock(&iocg->waitq.lock);
 
-		if (waitqueue_active(&iocg->waitq) ||
-		    atomic64_read(&iocg->abs_vdebt)) {
+		if (waitqueue_active(&iocg->waitq) || iocg->abs_vdebt) {
 			/* might be oversleeping vtime / hweight changes, kick */
 			iocg_kick_waitq(iocg, &now);
 			iocg_kick_delay(iocg, &now, 0);
@@ -1540,19 +1555,39 @@
 	if (rq_wait_pct > RQ_WAIT_BUSY_PCT ||
 	    missed_ppm[READ] > ppm_rthr ||
 	    missed_ppm[WRITE] > ppm_wthr) {
+		/* clearly missing QoS targets, slow down vrate */
 		ioc->busy_level = max(ioc->busy_level, 0);
 		ioc->busy_level++;
 	} else if (rq_wait_pct <= RQ_WAIT_BUSY_PCT * UNBUSY_THR_PCT / 100 &&
 		   missed_ppm[READ] <= ppm_rthr * UNBUSY_THR_PCT / 100 &&
 		   missed_ppm[WRITE] <= ppm_wthr * UNBUSY_THR_PCT / 100) {
-		/* take action iff there is contention */
-		if (nr_shortages && !nr_lagging) {
+		/* QoS targets are being met with >25% margin */
+		if (nr_shortages) {
+			/*
+			 * We're throttling while the device has spare
+			 * capacity.  If vrate was being slowed down, stop.
+			 */
 			ioc->busy_level = min(ioc->busy_level, 0);
-			/* redistribute surpluses first */
-			if (!nr_surpluses)
+
+			/*
+			 * If there are IOs spanning multiple periods, wait
+			 * them out before pushing the device harder.  If
+			 * there are surpluses, let redistribution work it
+			 * out first.
+			 */
+			if (!nr_lagging && !nr_surpluses)
 				ioc->busy_level--;
+		} else {
+			/*
+			 * Nobody is being throttled and the users aren't
+			 * issuing enough IOs to saturate the device.  We
+			 * simply don't know how close the device is to
+			 * saturation.  Coast.
+			 */
+			ioc->busy_level = 0;
 		}
 	} else {
+		/* inside the hysterisis margin, we're good */
 		ioc->busy_level = 0;
 	}
 
@@ -1593,7 +1628,7 @@
 				      vrate_min, vrate_max);
 		}
 
-		trace_iocost_ioc_vrate_adj(ioc, vrate, &missed_ppm, rq_wait_pct,
+		trace_iocost_ioc_vrate_adj(ioc, vrate, missed_ppm, rq_wait_pct,
 					   nr_lagging, nr_shortages,
 					   nr_surpluses);
 
@@ -1602,7 +1637,7 @@
 			ioc->period_us * vrate * INUSE_MARGIN_PCT, 100);
 	} else if (ioc->busy_level != prev_busy_level || nr_lagging) {
 		trace_iocost_ioc_vrate_adj(ioc, atomic64_read(&ioc->vtime_rate),
-					   &missed_ppm, rq_wait_pct, nr_lagging,
+					   missed_ppm, rq_wait_pct, nr_lagging,
 					   nr_shortages, nr_surpluses);
 	}
 
@@ -1720,26 +1755,49 @@
 	 * tests are racy but the races aren't systemic - we only miss once
 	 * in a while which is fine.
 	 */
-	if (!waitqueue_active(&iocg->waitq) &&
-	    !atomic64_read(&iocg->abs_vdebt) &&
+	if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
 	    time_before_eq64(vtime + cost, now.vnow)) {
 		iocg_commit_bio(iocg, bio, cost);
 		return;
 	}
 
 	/*
-	 * We're over budget.  If @bio has to be issued regardless,
-	 * remember the abs_cost instead of advancing vtime.
-	 * iocg_kick_waitq() will pay off the debt before waking more IOs.
+	 * We activated above but w/o any synchronization. Deactivation is
+	 * synchronized with waitq.lock and we won't get deactivated as long
+	 * as we're waiting or has debt, so we're good if we're activated
+	 * here. In the unlikely case that we aren't, just issue the IO.
+	 */
+	spin_lock_irq(&iocg->waitq.lock);
+
+	if (unlikely(list_empty(&iocg->active_list))) {
+		spin_unlock_irq(&iocg->waitq.lock);
+		iocg_commit_bio(iocg, bio, cost);
+		return;
+	}
+
+	/*
+	 * We're over budget. If @bio has to be issued regardless, remember
+	 * the abs_cost instead of advancing vtime. iocg_kick_waitq() will pay
+	 * off the debt before waking more IOs.
+	 *
 	 * This way, the debt is continuously paid off each period with the
-	 * actual budget available to the cgroup.  If we just wound vtime,
-	 * we would incorrectly use the current hw_inuse for the entire
-	 * amount which, for example, can lead to the cgroup staying
-	 * blocked for a long time even with substantially raised hw_inuse.
+	 * actual budget available to the cgroup. If we just wound vtime, we
+	 * would incorrectly use the current hw_inuse for the entire amount
+	 * which, for example, can lead to the cgroup staying blocked for a
+	 * long time even with substantially raised hw_inuse.
+	 *
+	 * An iocg with vdebt should stay online so that the timer can keep
+	 * deducting its vdebt and [de]activate use_delay mechanism
+	 * accordingly. We don't want to race against the timer trying to
+	 * clear them and leave @iocg inactive w/ dangling use_delay heavily
+	 * penalizing the cgroup and its descendants.
 	 */
 	if (bio_issue_as_root_blkg(bio) || fatal_signal_pending(current)) {
-		atomic64_add(abs_cost, &iocg->abs_vdebt);
-		iocg_kick_delay(iocg, &now, cost);
+		iocg->abs_vdebt += abs_cost;
+		if (iocg_kick_delay(iocg, &now, cost))
+			blkcg_schedule_throttle(rqos->q,
+					(bio->bi_opf & REQ_SWAP) == REQ_SWAP);
+		spin_unlock_irq(&iocg->waitq.lock);
 		return;
 	}
 
@@ -1756,20 +1814,6 @@
 	 * All waiters are on iocg->waitq and the wait states are
 	 * synchronized using waitq.lock.
 	 */
-	spin_lock_irq(&iocg->waitq.lock);
-
-	/*
-	 * We activated above but w/o any synchronization.  Deactivation is
-	 * synchronized with waitq.lock and we won't get deactivated as
-	 * long as we're waiting, so we're good if we're activated here.
-	 * In the unlikely case that we are deactivated, just issue the IO.
-	 */
-	if (unlikely(list_empty(&iocg->active_list))) {
-		spin_unlock_irq(&iocg->waitq.lock);
-		iocg_commit_bio(iocg, bio, cost);
-		return;
-	}
-
 	init_waitqueue_func_entry(&wait.wait, iocg_wake_fn);
 	wait.wait.private = current;
 	wait.bio = bio;
@@ -1801,6 +1845,7 @@
 	struct ioc_now now;
 	u32 hw_inuse;
 	u64 abs_cost, cost;
+	unsigned long flags;
 
 	/* bypass if disabled or for root cgroup */
 	if (!ioc->enabled || !iocg->level)
@@ -1820,15 +1865,28 @@
 		iocg->cursor = bio_end;
 
 	/*
-	 * Charge if there's enough vtime budget and the existing request
-	 * has cost assigned.  Otherwise, account it as debt.  See debt
-	 * handling in ioc_rqos_throttle() for details.
+	 * Charge if there's enough vtime budget and the existing request has
+	 * cost assigned.
 	 */
 	if (rq->bio && rq->bio->bi_iocost_cost &&
-	    time_before_eq64(atomic64_read(&iocg->vtime) + cost, now.vnow))
+	    time_before_eq64(atomic64_read(&iocg->vtime) + cost, now.vnow)) {
 		iocg_commit_bio(iocg, bio, cost);
-	else
-		atomic64_add(abs_cost, &iocg->abs_vdebt);
+		return;
+	}
+
+	/*
+	 * Otherwise, account it as debt if @iocg is online, which it should
+	 * be for the vast majority of cases. See debt handling in
+	 * ioc_rqos_throttle() for details.
+	 */
+	spin_lock_irqsave(&iocg->waitq.lock, flags);
+	if (likely(!list_empty(&iocg->active_list))) {
+		iocg->abs_vdebt += abs_cost;
+		iocg_kick_delay(iocg, &now, cost);
+	} else {
+		iocg_commit_bio(iocg, bio, cost);
+	}
+	spin_unlock_irqrestore(&iocg->waitq.lock, flags);
 }
 
 static void ioc_rqos_done_bio(struct rq_qos *rqos, struct bio *bio)
@@ -1998,7 +2056,6 @@
 	iocg->ioc = ioc;
 	atomic64_set(&iocg->vtime, now.vnow);
 	atomic64_set(&iocg->done_vtime, now.vnow);
-	atomic64_set(&iocg->abs_vdebt, 0);
 	atomic64_set(&iocg->active_period, atomic64_read(&ioc->cur_period));
 	INIT_LIST_HEAD(&iocg->active_list);
 	iocg->hweight_active = HWEIGHT_WHOLE;
@@ -2026,14 +2083,15 @@
 {
 	struct ioc_gq *iocg = pd_to_iocg(pd);
 	struct ioc *ioc = iocg->ioc;
+	unsigned long flags;
 
 	if (ioc) {
-		spin_lock(&ioc->lock);
+		spin_lock_irqsave(&ioc->lock, flags);
 		if (!list_empty(&iocg->active_list)) {
 			propagate_active_weight(iocg, 0, 0);
 			list_del_init(&iocg->active_list);
 		}
-		spin_unlock(&ioc->lock);
+		spin_unlock_irqrestore(&ioc->lock, flags);
 
 		hrtimer_cancel(&iocg->waitq_timer);
 		hrtimer_cancel(&iocg->delay_timer);
--- linux-ein-5.4.0.orig/block/blk-iolatency.c
+++ linux-ein-5.4.0/block/blk-iolatency.c
@@ -86,7 +86,17 @@
 struct blk_iolatency {
 	struct rq_qos rqos;
 	struct timer_list timer;
-	atomic_t enabled;
+
+	/*
+	 * ->enabled is the master enable switch gating the throttling logic and
+	 * inflight tracking. The number of cgroups which have iolat enabled is
+	 * tracked in ->enable_cnt, and ->enable is flipped on/off accordingly
+	 * from ->enable_work with the request_queue frozen. For details, See
+	 * blkiolatency_enable_work_fn().
+	 */
+	bool enabled;
+	atomic_t enable_cnt;
+	struct work_struct enable_work;
 };
 
 static inline struct blk_iolatency *BLKIOLATENCY(struct rq_qos *rqos)
@@ -94,11 +104,6 @@
 	return container_of(rqos, struct blk_iolatency, rqos);
 }
 
-static inline bool blk_iolatency_enabled(struct blk_iolatency *blkiolat)
-{
-	return atomic_read(&blkiolat->enabled) > 0;
-}
-
 struct child_latency_info {
 	spinlock_t lock;
 
@@ -463,7 +468,7 @@
 	struct blkcg_gq *blkg = bio->bi_blkg;
 	bool issue_as_root = bio_issue_as_root_blkg(bio);
 
-	if (!blk_iolatency_enabled(blkiolat))
+	if (!blkiolat->enabled)
 		return;
 
 	while (blkg && blkg->parent) {
@@ -593,7 +598,6 @@
 	u64 window_start;
 	u64 now = ktime_to_ns(ktime_get());
 	bool issue_as_root = bio_issue_as_root_blkg(bio);
-	bool enabled = false;
 	int inflight = 0;
 
 	blkg = bio->bi_blkg;
@@ -604,8 +608,7 @@
 	if (!iolat)
 		return;
 
-	enabled = blk_iolatency_enabled(iolat->blkiolat);
-	if (!enabled)
+	if (!iolat->blkiolat->enabled)
 		return;
 
 	while (blkg && blkg->parent) {
@@ -643,6 +646,7 @@
 	struct blk_iolatency *blkiolat = BLKIOLATENCY(rqos);
 
 	del_timer_sync(&blkiolat->timer);
+	flush_work(&blkiolat->enable_work);
 	blkcg_deactivate_policy(rqos->q, &blkcg_policy_iolatency);
 	kfree(blkiolat);
 }
@@ -714,6 +718,44 @@
 	rcu_read_unlock();
 }
 
+/**
+ * blkiolatency_enable_work_fn - Enable or disable iolatency on the device
+ * @work: enable_work of the blk_iolatency of interest
+ *
+ * iolatency needs to keep track of the number of in-flight IOs per cgroup. This
+ * is relatively expensive as it involves walking up the hierarchy twice for
+ * every IO. Thus, if iolatency is not enabled in any cgroup for the device, we
+ * want to disable the in-flight tracking.
+ *
+ * We have to make sure that the counting is balanced - we don't want to leak
+ * the in-flight counts by disabling accounting in the completion path while IOs
+ * are in flight. This is achieved by ensuring that no IO is in flight by
+ * freezing the queue while flipping ->enabled. As this requires a sleepable
+ * context, ->enabled flipping is punted to this work function.
+ */
+static void blkiolatency_enable_work_fn(struct work_struct *work)
+{
+	struct blk_iolatency *blkiolat = container_of(work, struct blk_iolatency,
+						      enable_work);
+	bool enabled;
+
+	/*
+	 * There can only be one instance of this function running for @blkiolat
+	 * and it's guaranteed to be executed at least once after the latest
+	 * ->enabled_cnt modification. Acting on the latest ->enable_cnt is
+	 * sufficient.
+	 *
+	 * Also, we know @blkiolat is safe to access as ->enable_work is flushed
+	 * in blkcg_iolatency_exit().
+	 */
+	enabled = atomic_read(&blkiolat->enable_cnt);
+	if (enabled != blkiolat->enabled) {
+		blk_mq_freeze_queue(blkiolat->rqos.q);
+		blkiolat->enabled = enabled;
+		blk_mq_unfreeze_queue(blkiolat->rqos.q);
+	}
+}
+
 int blk_iolatency_init(struct request_queue *q)
 {
 	struct blk_iolatency *blkiolat;
@@ -739,17 +781,15 @@
 	}
 
 	timer_setup(&blkiolat->timer, blkiolatency_timer_fn, 0);
+	INIT_WORK(&blkiolat->enable_work, blkiolatency_enable_work_fn);
 
 	return 0;
 }
 
-/*
- * return 1 for enabling iolatency, return -1 for disabling iolatency, otherwise
- * return 0.
- */
-static int iolatency_set_min_lat_nsec(struct blkcg_gq *blkg, u64 val)
+static void iolatency_set_min_lat_nsec(struct blkcg_gq *blkg, u64 val)
 {
 	struct iolatency_grp *iolat = blkg_to_lat(blkg);
+	struct blk_iolatency *blkiolat = iolat->blkiolat;
 	u64 oldval = iolat->min_lat_nsec;
 
 	iolat->min_lat_nsec = val;
@@ -757,13 +797,15 @@
 	iolat->cur_win_nsec = min_t(u64, iolat->cur_win_nsec,
 				    BLKIOLATENCY_MAX_WIN_SIZE);
 
-	if (!oldval && val)
-		return 1;
+	if (!oldval && val) {
+		if (atomic_inc_return(&blkiolat->enable_cnt) == 1)
+			schedule_work(&blkiolat->enable_work);
+	}
 	if (oldval && !val) {
 		blkcg_clear_delay(blkg);
-		return -1;
+		if (atomic_dec_return(&blkiolat->enable_cnt) == 0)
+			schedule_work(&blkiolat->enable_work);
 	}
-	return 0;
 }
 
 static void iolatency_clear_scaling(struct blkcg_gq *blkg)
@@ -795,7 +837,6 @@
 	u64 lat_val = 0;
 	u64 oldval;
 	int ret;
-	int enable = 0;
 
 	ret = blkg_conf_prep(blkcg, &blkcg_policy_iolatency, buf, &ctx);
 	if (ret)
@@ -830,37 +871,12 @@
 	blkg = ctx.blkg;
 	oldval = iolat->min_lat_nsec;
 
-	enable = iolatency_set_min_lat_nsec(blkg, lat_val);
-	if (enable) {
-		WARN_ON_ONCE(!blk_get_queue(blkg->q));
-		blkg_get(blkg);
-	}
-
-	if (oldval != iolat->min_lat_nsec) {
+	iolatency_set_min_lat_nsec(blkg, lat_val);
+	if (oldval != iolat->min_lat_nsec)
 		iolatency_clear_scaling(blkg);
-	}
-
 	ret = 0;
 out:
 	blkg_conf_finish(&ctx);
-	if (ret == 0 && enable) {
-		struct iolatency_grp *tmp = blkg_to_lat(blkg);
-		struct blk_iolatency *blkiolat = tmp->blkiolat;
-
-		blk_mq_freeze_queue(blkg->q);
-
-		if (enable == 1)
-			atomic_inc(&blkiolat->enabled);
-		else if (enable == -1)
-			atomic_dec(&blkiolat->enabled);
-		else
-			WARN_ON_ONCE(1);
-
-		blk_mq_unfreeze_queue(blkg->q);
-
-		blkg_put(blkg);
-		blk_put_queue(blkg->q);
-	}
 	return ret ?: nbytes;
 }
 
@@ -1001,14 +1017,8 @@
 {
 	struct iolatency_grp *iolat = pd_to_lat(pd);
 	struct blkcg_gq *blkg = lat_to_blkg(iolat);
-	struct blk_iolatency *blkiolat = iolat->blkiolat;
-	int ret;
 
-	ret = iolatency_set_min_lat_nsec(blkg, 0);
-	if (ret == 1)
-		atomic_inc(&blkiolat->enabled);
-	if (ret == -1)
-		atomic_dec(&blkiolat->enabled);
+	iolatency_set_min_lat_nsec(blkg, 0);
 	iolatency_clear_scaling(blkg);
 }
 
--- linux-ein-5.4.0.orig/block/blk-map.c
+++ linux-ein-5.4.0/block/blk-map.c
@@ -151,7 +151,7 @@
 	return 0;
 
 unmap_rq:
-	__blk_rq_unmap_user(bio);
+	blk_rq_unmap_user(bio);
 fail:
 	rq->bio = NULL;
 	return ret;
--- linux-ein-5.4.0.orig/block/blk-merge.c
+++ linux-ein-5.4.0/block/blk-merge.c
@@ -7,6 +7,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 #include <linux/scatterlist.h>
+#include <linux/blk-cgroup.h>
 
 #include <trace/events/block.h>
 
@@ -154,20 +155,23 @@
 	if (max_sectors > start_offset)
 		return max_sectors - start_offset;
 
-	return sectors & (lbs - 1);
+	return sectors & ~(lbs - 1);
 }
 
-static unsigned get_max_segment_size(const struct request_queue *q,
-				     unsigned offset)
+static inline unsigned get_max_segment_size(const struct request_queue *q,
+					    struct page *start_page,
+					    unsigned long offset)
 {
 	unsigned long mask = queue_segment_boundary(q);
 
-	/* default segment boundary mask means no boundary limit */
-	if (mask == BLK_SEG_BOUNDARY_MASK)
-		return queue_max_segment_size(q);
+	offset = mask & (page_to_phys(start_page) + offset);
 
-	return min_t(unsigned long, mask - (mask & offset) + 1,
-		     queue_max_segment_size(q));
+	/*
+	 * overflow may be triggered in case of zero page physical address
+	 * on 32bit arch, use queue's max segment size when that happens.
+	 */
+	return min_not_zero(mask - offset + 1,
+			(unsigned long)queue_max_segment_size(q));
 }
 
 /**
@@ -201,7 +205,8 @@
 	unsigned seg_size = 0;
 
 	while (len && *nsegs < max_segs) {
-		seg_size = get_max_segment_size(q, bv->bv_offset + total_len);
+		seg_size = get_max_segment_size(q, bv->bv_page,
+						bv->bv_offset + total_len);
 		seg_size = min(seg_size, len);
 
 		(*nsegs)++;
@@ -366,6 +371,14 @@
 	switch (bio_op(rq->bio)) {
 	case REQ_OP_DISCARD:
 	case REQ_OP_SECURE_ERASE:
+		if (queue_max_discard_segments(rq->q) > 1) {
+			struct bio *bio = rq->bio;
+
+			for_each_bio(bio)
+				nr_phys_segs++;
+			return nr_phys_segs;
+		}
+		return 1;
 	case REQ_OP_WRITE_ZEROES:
 		return 0;
 	case REQ_OP_WRITE_SAME:
@@ -404,7 +417,8 @@
 
 	while (nbytes > 0) {
 		unsigned offset = bvec->bv_offset + total;
-		unsigned len = min(get_max_segment_size(q, offset), nbytes);
+		unsigned len = min(get_max_segment_size(q, bvec->bv_page,
+					offset), nbytes);
 		struct page *page = bvec->bv_page;
 
 		/*
@@ -463,7 +477,7 @@
 			     struct scatterlist *sglist,
 			     struct scatterlist **sg)
 {
-	struct bio_vec uninitialized_var(bvec), bvprv = { NULL };
+	struct bio_vec bvec, bvprv = { NULL };
 	struct bvec_iter iter;
 	int nsegs = 0;
 	bool new_bio = false;
@@ -548,15 +562,29 @@
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
 
+static inline unsigned int blk_rq_get_max_segments(struct request *rq)
+{
+	if (req_op(rq) == REQ_OP_DISCARD)
+		return queue_max_discard_segments(rq->q);
+	return queue_max_segments(rq->q);
+}
+
 static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
 		unsigned int nr_phys_segs)
 {
-	if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(req->q))
+	if (!blk_cgroup_mergeable(req, bio))
 		goto no_merge;
 
 	if (blk_integrity_merge_bio(req->q, req, bio) == false)
 		goto no_merge;
 
+	/* discard request merge won't add new segment */
+	if (req_op(req) == REQ_OP_DISCARD)
+		return 1;
+
+	if (req->nr_phys_segments + nr_phys_segs > blk_rq_get_max_segments(req))
+		goto no_merge;
+
 	/*
 	 * This will form the start of a new hw segment.  Bump both
 	 * counters.
@@ -635,7 +663,10 @@
 		return 0;
 
 	total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
-	if (total_phys_segments > queue_max_segments(q))
+	if (total_phys_segments > blk_rq_get_max_segments(req))
+		return 0;
+
+	if (!blk_cgroup_mergeable(req, next->bio))
 		return 0;
 
 	if (blk_integrity_merge_rq(q, req, next) == false)
@@ -690,21 +721,6 @@
 		part_stat_unlock();
 	}
 }
-/*
- * Two cases of handling DISCARD merge:
- * If max_discard_segments > 1, the driver takes every bio
- * as a range and send them to controller together. The ranges
- * needn't to be contiguous.
- * Otherwise, the bios/requests will be handled as same as
- * others which should be contiguous.
- */
-static inline bool blk_discard_mergable(struct request *req)
-{
-	if (req_op(req) == REQ_OP_DISCARD &&
-	    queue_max_discard_segments(req->q) > 1)
-		return true;
-	return false;
-}
 
 static enum elv_merge blk_try_req_merge(struct request *req,
 					struct request *next)
@@ -861,6 +877,10 @@
 	if (rq->rq_disk != bio->bi_disk)
 		return false;
 
+	/* don't merge across cgroup boundaries */
+	if (!blk_cgroup_mergeable(rq, bio))
+		return false;
+
 	/* only merge integrity protected bio into ditto rq */
 	if (blk_integrity_merge_bio(rq->q, rq, bio) == false)
 		return false;
--- linux-ein-5.4.0.orig/block/blk-mq-debugfs.c
+++ linux-ein-5.4.0/block/blk-mq-debugfs.c
@@ -125,6 +125,9 @@
 	QUEUE_FLAG_NAME(REGISTERED),
 	QUEUE_FLAG_NAME(SCSI_PASSTHROUGH),
 	QUEUE_FLAG_NAME(QUIESCED),
+	QUEUE_FLAG_NAME(PCI_P2PDMA),
+	QUEUE_FLAG_NAME(ZONE_RESETALL),
+	QUEUE_FLAG_NAME(RQ_ALLOC_TIME),
 };
 #undef QUEUE_FLAG_NAME
 
@@ -880,6 +883,9 @@
 	char name[20];
 	int i;
 
+	if (!q->debugfs_dir)
+		return;
+
 	snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
 	hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
 
--- linux-ein-5.4.0.orig/block/blk-mq-sched.c
+++ linux-ein-5.4.0/block/blk-mq-sched.c
@@ -59,8 +59,7 @@
 }
 
 /*
- * Mark a hardware queue as needing a restart. For shared queues, maintain
- * a count of how many hardware queues are marked for restart.
+ * Mark a hardware queue as needing a restart.
  */
 void blk_mq_sched_mark_restart_hctx(struct blk_mq_hw_ctx *hctx)
 {
@@ -77,19 +76,32 @@
 		return;
 	clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
 
+	/*
+	 * Order clearing SCHED_RESTART and list_empty_careful(&hctx->dispatch)
+	 * in blk_mq_run_hw_queue(). Its pair is the barrier in
+	 * blk_mq_dispatch_rq_list(). So dispatch code won't see SCHED_RESTART,
+	 * meantime new request added to hctx->dispatch is missed to check in
+	 * blk_mq_run_hw_queue().
+	 */
+	smp_mb();
+
 	blk_mq_run_hw_queue(hctx, true);
 }
 
 /*
  * Only SCSI implements .get_budget and .put_budget, and SCSI restarts
  * its queue by itself in its completion handler, so we don't need to
- * restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
+ * restart queue if .get_budget() fails to get the budget.
+ *
+ * Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
+ * be run again.  This is necessary to avoid starving flushes.
  */
-static void blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
+static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
 {
 	struct request_queue *q = hctx->queue;
 	struct elevator_queue *e = q->elevator;
 	LIST_HEAD(rq_list);
+	int ret = 0;
 
 	do {
 		struct request *rq;
@@ -97,6 +109,11 @@
 		if (e->type->ops.has_work && !e->type->ops.has_work(hctx))
 			break;
 
+		if (!list_empty_careful(&hctx->dispatch)) {
+			ret = -EAGAIN;
+			break;
+		}
+
 		if (!blk_mq_get_dispatch_budget(hctx))
 			break;
 
@@ -113,6 +130,8 @@
 		 */
 		list_add(&rq->queuelist, &rq_list);
 	} while (blk_mq_dispatch_rq_list(q, &rq_list, true));
+
+	return ret;
 }
 
 static struct blk_mq_ctx *blk_mq_next_ctx(struct blk_mq_hw_ctx *hctx,
@@ -129,17 +148,26 @@
 /*
  * Only SCSI implements .get_budget and .put_budget, and SCSI restarts
  * its queue by itself in its completion handler, so we don't need to
- * restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
+ * restart queue if .get_budget() fails to get the budget.
+ *
+ * Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
+ * to be run again.  This is necessary to avoid starving flushes.
  */
-static void blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
+static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
 {
 	struct request_queue *q = hctx->queue;
 	LIST_HEAD(rq_list);
 	struct blk_mq_ctx *ctx = READ_ONCE(hctx->dispatch_from);
+	int ret = 0;
 
 	do {
 		struct request *rq;
 
+		if (!list_empty_careful(&hctx->dispatch)) {
+			ret = -EAGAIN;
+			break;
+		}
+
 		if (!sbitmap_any_bit_set(&hctx->ctx_map))
 			break;
 
@@ -165,21 +193,17 @@
 	} while (blk_mq_dispatch_rq_list(q, &rq_list, true));
 
 	WRITE_ONCE(hctx->dispatch_from, ctx);
+	return ret;
 }
 
-void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
+int __blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
 {
 	struct request_queue *q = hctx->queue;
 	struct elevator_queue *e = q->elevator;
 	const bool has_sched_dispatch = e && e->type->ops.dispatch_request;
+	int ret = 0;
 	LIST_HEAD(rq_list);
 
-	/* RCU or SRCU read lock is needed before checking quiesced flag */
-	if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)))
-		return;
-
-	hctx->run++;
-
 	/*
 	 * If we have previous entries on our dispatch list, grab them first for
 	 * more fair dispatch.
@@ -208,19 +232,41 @@
 		blk_mq_sched_mark_restart_hctx(hctx);
 		if (blk_mq_dispatch_rq_list(q, &rq_list, false)) {
 			if (has_sched_dispatch)
-				blk_mq_do_dispatch_sched(hctx);
+				ret = blk_mq_do_dispatch_sched(hctx);
 			else
-				blk_mq_do_dispatch_ctx(hctx);
+				ret = blk_mq_do_dispatch_ctx(hctx);
 		}
 	} else if (has_sched_dispatch) {
-		blk_mq_do_dispatch_sched(hctx);
+		ret = blk_mq_do_dispatch_sched(hctx);
 	} else if (hctx->dispatch_busy) {
 		/* dequeue request one by one from sw queue if queue is busy */
-		blk_mq_do_dispatch_ctx(hctx);
+		ret = blk_mq_do_dispatch_ctx(hctx);
 	} else {
 		blk_mq_flush_busy_ctxs(hctx, &rq_list);
 		blk_mq_dispatch_rq_list(q, &rq_list, false);
 	}
+
+	return ret;
+}
+
+void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
+{
+	struct request_queue *q = hctx->queue;
+
+	/* RCU or SRCU read lock is needed before checking quiesced flag */
+	if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)))
+		return;
+
+	hctx->run++;
+
+	/*
+	 * A return of -EAGAIN is an indication that hctx->dispatch is not
+	 * empty and we must run again in order to avoid starving flushes.
+	 */
+	if (__blk_mq_sched_dispatch_requests(hctx) == -EAGAIN) {
+		if (__blk_mq_sched_dispatch_requests(hctx) == -EAGAIN)
+			blk_mq_run_hw_queue(hctx, true);
+	}
 }
 
 bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
@@ -325,14 +371,16 @@
 		unsigned int nr_segs)
 {
 	struct elevator_queue *e = q->elevator;
-	struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
-	struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, bio->bi_opf, ctx);
+	struct blk_mq_ctx *ctx;
+	struct blk_mq_hw_ctx *hctx;
 	bool ret = false;
 	enum hctx_type type;
 
 	if (e && e->type->ops.bio_merge)
-		return e->type->ops.bio_merge(hctx, bio, nr_segs);
+		return e->type->ops.bio_merge(q, bio, nr_segs);
 
+	ctx = blk_mq_get_ctx(q);
+	hctx = blk_mq_map_queue(q, bio->bi_opf, ctx);
 	type = hctx->type;
 	if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
 			!list_empty_careful(&ctx->rq_lists[type])) {
@@ -361,13 +409,19 @@
 				       bool has_sched,
 				       struct request *rq)
 {
-	/* dispatch flush rq directly */
-	if (rq->rq_flags & RQF_FLUSH_SEQ) {
-		spin_lock(&hctx->lock);
-		list_add(&rq->queuelist, &hctx->dispatch);
-		spin_unlock(&hctx->lock);
+	/*
+	 * dispatch flush and passthrough rq directly
+	 *
+	 * passthrough request has to be added to hctx->dispatch directly.
+	 * For some reason, device may be in one situation which can't
+	 * handle FS request, so STS_RESOURCE is always returned and the
+	 * FS request will be added to hctx->dispatch. However passthrough
+	 * request may be required at that time for fixing the problem. If
+	 * passthrough request is added to scheduler queue, there isn't any
+	 * chance to dispatch it given we prioritize requests in hctx->dispatch.
+	 */
+	if ((rq->rq_flags & RQF_FLUSH_SEQ) || blk_rq_is_passthrough(rq))
 		return true;
-	}
 
 	if (has_sched)
 		rq->rq_flags |= RQF_SORTED;
@@ -391,8 +445,32 @@
 
 	WARN_ON(e && (rq->tag != -1));
 
-	if (blk_mq_sched_bypass_insert(hctx, !!e, rq))
+	if (blk_mq_sched_bypass_insert(hctx, !!e, rq)) {
+		/*
+		 * Firstly normal IO request is inserted to scheduler queue or
+		 * sw queue, meantime we add flush request to dispatch queue(
+		 * hctx->dispatch) directly and there is at most one in-flight
+		 * flush request for each hw queue, so it doesn't matter to add
+		 * flush request to tail or front of the dispatch queue.
+		 *
+		 * Secondly in case of NCQ, flush request belongs to non-NCQ
+		 * command, and queueing it will fail when there is any
+		 * in-flight normal IO request(NCQ command). When adding flush
+		 * rq to the front of hctx->dispatch, it is easier to introduce
+		 * extra time to flush rq's latency because of S_SCHED_RESTART
+		 * compared with adding to the tail of dispatch queue, then
+		 * chance of flush merge is increased, and less flush requests
+		 * will be issued to controller. It is observed that ~10% time
+		 * is saved in blktests block/004 on disk attached to AHCI/NCQ
+		 * drive when adding flush rq to the front of hctx->dispatch.
+		 *
+		 * Simply queue flush rq to the front of hctx->dispatch so that
+		 * intensive flush workloads can benefit in case of NCQ HW.
+		 */
+		at_head = (rq->rq_flags & RQF_FLUSH_SEQ) ? true : at_head;
+		blk_mq_request_bypass_insert(rq, at_head, false);
 		goto run;
+	}
 
 	if (e && e->type->ops.insert_requests) {
 		LIST_HEAD(list);
--- linux-ein-5.4.0.orig/block/blk-mq-sched.h
+++ linux-ein-5.4.0/block/blk-mq-sched.h
@@ -66,7 +66,7 @@
 	struct request_queue *q = rq->q;
 	struct elevator_queue *e = q->elevator;
 
-	if (e && e->type->ops.requeue_request)
+	if ((rq->rq_flags & RQF_ELVPRIV) && e && e->type->ops.requeue_request)
 		e->type->ops.requeue_request(rq);
 }
 
--- linux-ein-5.4.0.orig/block/blk-mq-sysfs.c
+++ linux-ein-5.4.0/block/blk-mq-sysfs.c
@@ -36,8 +36,6 @@
 	struct blk_mq_hw_ctx *hctx = container_of(kobj, struct blk_mq_hw_ctx,
 						  kobj);
 
-	cancel_delayed_work_sync(&hctx->run_work);
-
 	if (hctx->flags & BLK_MQ_F_BLOCKING)
 		cleanup_srcu_struct(hctx->srcu);
 	blk_free_flush_queue(hctx->fq);
@@ -166,20 +164,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_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_tags = {
@@ -247,7 +250,7 @@
 {
 	struct request_queue *q = hctx->queue;
 	struct blk_mq_ctx *ctx;
-	int i, ret;
+	int i, j, ret;
 
 	if (!hctx->nr_ctx)
 		return 0;
@@ -259,9 +262,16 @@
 	hctx_for_each_ctx(hctx, ctx, i) {
 		ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu);
 		if (ret)
-			break;
+			goto out;
 	}
 
+	return 0;
+out:
+	hctx_for_each_ctx(hctx, ctx, j) {
+		if (j < i)
+			kobject_del(&ctx->kobj);
+	}
+	kobject_del(&hctx->kobj);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/block/blk-mq.c
+++ linux-ein-5.4.0/block/blk-mq.c
@@ -579,7 +579,14 @@
 	q->mq_ops->complete(rq);
 }
 
-static void __blk_mq_complete_request(struct request *rq)
+/**
+ * blk_mq_complete_request - end I/O on a request
+ * @rq:		the request being processed
+ *
+ * Description:
+ *	Complete a request by scheduling the ->complete_rq operation.
+ **/
+void blk_mq_complete_request(struct request *rq)
 {
 	struct blk_mq_ctx *ctx = rq->mq_ctx;
 	struct request_queue *q = rq->q;
@@ -625,6 +632,7 @@
 	}
 	put_cpu();
 }
+EXPORT_SYMBOL(blk_mq_complete_request);
 
 static void hctx_unlock(struct blk_mq_hw_ctx *hctx, int srcu_idx)
 	__releases(hctx->srcu)
@@ -646,23 +654,6 @@
 		*srcu_idx = srcu_read_lock(hctx->srcu);
 }
 
-/**
- * blk_mq_complete_request - end I/O on a request
- * @rq:		the request being processed
- *
- * Description:
- *	Ends all I/O on a request. It does not handle partial completions.
- *	The actual completion happens out-of-order, through a IPI handler.
- **/
-bool blk_mq_complete_request(struct request *rq)
-{
-	if (unlikely(blk_should_fake_timeout(rq->q)))
-		return false;
-	__blk_mq_complete_request(rq);
-	return true;
-}
-EXPORT_SYMBOL(blk_mq_complete_request);
-
 int blk_mq_request_started(struct request *rq)
 {
 	return blk_mq_rq_state(rq) != MQ_RQ_IDLE;
@@ -733,7 +724,6 @@
 	/* this request will be re-inserted to io scheduler queue */
 	blk_mq_sched_requeue_request(rq);
 
-	BUG_ON(!list_empty(&rq->queuelist));
 	blk_mq_add_to_requeue_list(rq, true, kick_requeue_list);
 }
 EXPORT_SYMBOL(blk_mq_requeue_request);
@@ -761,7 +751,7 @@
 		 * merge.
 		 */
 		if (rq->rq_flags & RQF_DONTPREP)
-			blk_mq_request_bypass_insert(rq, false);
+			blk_mq_request_bypass_insert(rq, false, false);
 		else
 			blk_mq_sched_insert_request(rq, true, false, false);
 	}
@@ -829,10 +819,10 @@
 			       void *priv, bool reserved)
 {
 	/*
-	 * If we find a request that is inflight and the queue matches,
+	 * If we find a request that isn't idle and the queue matches,
 	 * we know the queue is busy. Return false to stop the iteration.
 	 */
-	if (rq->state == MQ_RQ_IN_FLIGHT && rq->q == hctx->queue) {
+	if (blk_mq_request_started(rq) && rq->q == hctx->queue) {
 		bool *busy = priv;
 
 		*busy = true;
@@ -1113,7 +1103,7 @@
 static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx *hctx,
 				 struct request *rq)
 {
-	struct sbitmap_queue *sbq = &hctx->tags->bitmap_tags;
+	struct sbitmap_queue *sbq;
 	struct wait_queue_head *wq;
 	wait_queue_entry_t *wait;
 	bool ret;
@@ -1136,6 +1126,10 @@
 	if (!list_empty_careful(&wait->entry))
 		return false;
 
+	if (blk_mq_tag_is_reserved(rq->mq_hctx->sched_tags, rq->internal_tag))
+		sbq = &hctx->tags->breserved_tags;
+	else
+		sbq = &hctx->tags->bitmap_tags;
 	wq = &bt_wait_ptr(sbq, hctx)->wait;
 
 	spin_lock_irq(&wq->lock);
@@ -1151,6 +1145,22 @@
 	__add_wait_queue(wq, wait);
 
 	/*
+	 * Add one explicit barrier since blk_mq_get_driver_tag() may
+	 * not imply barrier in case of failure.
+	 *
+	 * Order adding us to wait queue and allocating driver tag.
+	 *
+	 * The pair is the one implied in sbitmap_queue_wake_up() which
+	 * orders clearing sbitmap tag bits and waitqueue_active() in
+	 * __sbitmap_queue_wake_up(), since waitqueue_active() is lockless
+	 *
+	 * Otherwise, re-order of adding wait queue and getting driver tag
+	 * may cause __sbitmap_queue_wake_up() to wake up nothing because
+	 * the waitqueue_active() may not observe us in wait queue.
+	 */
+	smp_mb();
+
+	/*
 	 * It's possible that a tag was freed in the window between the
 	 * allocation failure and adding the hardware queue to the wait
 	 * queue.
@@ -1205,6 +1215,23 @@
 
 #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
 
+static void blk_mq_handle_dev_resource(struct request *rq,
+				       struct list_head *list)
+{
+	struct request *next =
+		list_first_entry_or_null(list, struct request, queuelist);
+
+	/*
+	 * If an I/O scheduler has been configured and we got a driver tag for
+	 * the next request already, free it.
+	 */
+	if (next)
+		blk_mq_put_driver_tag(next);
+
+	list_add(&rq->queuelist, list);
+	__blk_mq_requeue_request(rq);
+}
+
 /*
  * Returns true if we did some work AND can potentially do more.
  */
@@ -1216,6 +1243,7 @@
 	bool no_tag = false;
 	int errors, queued;
 	blk_status_t ret = BLK_STS_OK;
+	bool no_budget_avail = false;
 
 	if (list_empty(list))
 		return false;
@@ -1232,8 +1260,11 @@
 		rq = list_first_entry(list, struct request, queuelist);
 
 		hctx = rq->mq_hctx;
-		if (!got_budget && !blk_mq_get_dispatch_budget(hctx))
+		if (!got_budget && !blk_mq_get_dispatch_budget(hctx)) {
+			blk_mq_put_driver_tag(rq);
+			no_budget_avail = true;
 			break;
+		}
 
 		if (!blk_mq_get_driver_tag(rq)) {
 			/*
@@ -1272,17 +1303,7 @@
 
 		ret = q->mq_ops->queue_rq(hctx, &bd);
 		if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE) {
-			/*
-			 * If an I/O scheduler has been configured and we got a
-			 * driver tag for the next request already, free it
-			 * again.
-			 */
-			if (!list_empty(list)) {
-				nxt = list_first_entry(list, struct request, queuelist);
-				blk_mq_put_driver_tag(nxt);
-			}
-			list_add(&rq->queuelist, list);
-			__blk_mq_requeue_request(rq);
+			blk_mq_handle_dev_resource(rq, list);
 			break;
 		}
 
@@ -1313,10 +1334,19 @@
 			q->mq_ops->commit_rqs(hctx);
 
 		spin_lock(&hctx->lock);
-		list_splice_init(list, &hctx->dispatch);
+		list_splice_tail_init(list, &hctx->dispatch);
 		spin_unlock(&hctx->lock);
 
 		/*
+		 * Order adding requests to hctx->dispatch and checking
+		 * SCHED_RESTART flag. The pair of this smp_mb() is the one
+		 * in blk_mq_sched_restart(). Avoid restart code path to
+		 * miss the new added requests to hctx->dispatch, meantime
+		 * SCHED_RESTART is observed here.
+		 */
+		smp_mb();
+
+		/*
 		 * If SCHED_RESTART was set by the caller of this function and
 		 * it is no longer set that means that it was cleared by another
 		 * thread and hence that a queue rerun is needed.
@@ -1338,13 +1368,15 @@
 		 *
 		 * If driver returns BLK_STS_RESOURCE and SCHED_RESTART
 		 * bit is set, run queue after a delay to avoid IO stalls
-		 * that could otherwise occur if the queue is idle.
+		 * that could otherwise occur if the queue is idle.  We'll do
+		 * similar if we couldn't get budget and SCHED_RESTART is set.
 		 */
 		needs_restart = blk_mq_sched_needs_restart(hctx);
 		if (!needs_restart ||
 		    (no_tag && list_empty_careful(&hctx->dispatch_wait.entry)))
 			blk_mq_run_hw_queue(hctx, true);
-		else if (needs_restart && (ret == BLK_STS_RESOURCE))
+		else if (needs_restart && (ret == BLK_STS_RESOURCE ||
+					   no_budget_avail))
 			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
 
 		blk_mq_update_dispatch_busy(hctx, true);
@@ -1668,12 +1700,16 @@
  * Should only be used carefully, when the caller knows we want to
  * bypass a potential IO scheduler on the target device.
  */
-void blk_mq_request_bypass_insert(struct request *rq, bool run_queue)
+void blk_mq_request_bypass_insert(struct request *rq, bool at_head,
+				  bool run_queue)
 {
 	struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
 
 	spin_lock(&hctx->lock);
-	list_add_tail(&rq->queuelist, &hctx->dispatch);
+	if (at_head)
+		list_add(&rq->queuelist, &hctx->dispatch);
+	else
+		list_add_tail(&rq->queuelist, &hctx->dispatch);
 	spin_unlock(&hctx->lock);
 
 	if (run_queue)
@@ -1863,7 +1899,8 @@
 	if (bypass_insert)
 		return BLK_STS_RESOURCE;
 
-	blk_mq_request_bypass_insert(rq, run_queue);
+	blk_mq_sched_insert_request(rq, false, run_queue, false);
+
 	return BLK_STS_OK;
 }
 
@@ -1879,7 +1916,7 @@
 
 	ret = __blk_mq_try_issue_directly(hctx, rq, cookie, false, true);
 	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
-		blk_mq_request_bypass_insert(rq, true);
+		blk_mq_request_bypass_insert(rq, false, true);
 	else if (ret != BLK_STS_OK)
 		blk_mq_end_request(rq, ret);
 
@@ -1913,7 +1950,7 @@
 		if (ret != BLK_STS_OK) {
 			if (ret == BLK_STS_RESOURCE ||
 					ret == BLK_STS_DEV_RESOURCE) {
-				blk_mq_request_bypass_insert(rq,
+				blk_mq_request_bypass_insert(rq, false,
 							list_empty(list));
 				break;
 			}
@@ -2487,18 +2524,6 @@
 	 * If the cpu isn't present, the cpu is mapped to first hctx.
 	 */
 	for_each_possible_cpu(i) {
-		hctx_idx = set->map[HCTX_TYPE_DEFAULT].mq_map[i];
-		/* unmapped hw queue can be remapped after CPU topo changed */
-		if (!set->tags[hctx_idx] &&
-		    !__blk_mq_alloc_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
-			 */
-			set->map[HCTX_TYPE_DEFAULT].mq_map[i] = 0;
-		}
 
 		ctx = per_cpu_ptr(q->queue_ctx, i);
 		for (j = 0; j < set->nr_maps; j++) {
@@ -2507,6 +2532,18 @@
 						HCTX_TYPE_DEFAULT, i);
 				continue;
 			}
+			hctx_idx = set->map[j].mq_map[i];
+			/* unmapped hw queue can be remapped after CPU topo changed */
+			if (!set->tags[hctx_idx] &&
+			    !__blk_mq_alloc_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
+				 */
+				set->map[j].mq_map[i] = 0;
+			}
 
 			hctx = blk_mq_map_queue_type(q, j, i);
 			ctx->hctxs[j] = hctx;
@@ -2943,10 +2980,12 @@
 /* tags can _not_ be used after returning from blk_mq_exit_queue */
 void blk_mq_exit_queue(struct request_queue *q)
 {
-	struct blk_mq_tag_set	*set = q->tag_set;
+	struct blk_mq_tag_set *set = q->tag_set;
 
-	blk_mq_del_queue_tag_set(q);
+	/* Checks hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED. */
 	blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
+	/* May clear BLK_MQ_F_TAG_QUEUE_SHARED in hctx->flags. */
+	blk_mq_del_queue_tag_set(q);
 }
 
 static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
@@ -3003,6 +3042,14 @@
 
 static int blk_mq_update_queue_map(struct blk_mq_tag_set *set)
 {
+	/*
+	 * blk_mq_map_queues() and multiple .map_queues() implementations
+	 * expect that set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the
+	 * number of hardware queues.
+	 */
+	if (set->nr_maps == 1)
+		set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
+
 	if (set->ops->map_queues && !is_kdump_kernel()) {
 		int i;
 
@@ -3265,7 +3312,9 @@
 
 	if (set->nr_maps == 1 && nr_hw_queues > nr_cpu_ids)
 		nr_hw_queues = nr_cpu_ids;
-	if (nr_hw_queues < 1 || nr_hw_queues == set->nr_hw_queues)
+	if (nr_hw_queues < 1)
+		return;
+	if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues)
 		return;
 
 	list_for_each_entry(q, &set->tag_list, tag_set_list)
@@ -3290,8 +3339,8 @@
 
 	prev_nr_hw_queues = set->nr_hw_queues;
 	set->nr_hw_queues = nr_hw_queues;
-	blk_mq_update_queue_map(set);
 fallback:
+	blk_mq_update_queue_map(set);
 	list_for_each_entry(q, &set->tag_list, tag_set_list) {
 		blk_mq_realloc_hw_ctxs(set, q);
 		if (q->nr_hw_queues != set->nr_hw_queues) {
--- linux-ein-5.4.0.orig/block/blk-mq.h
+++ linux-ein-5.4.0/block/blk-mq.h
@@ -66,7 +66,8 @@
  */
 void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
 				bool at_head);
-void blk_mq_request_bypass_insert(struct request *rq, bool run_queue);
+void blk_mq_request_bypass_insert(struct request *rq, bool at_head,
+				  bool run_queue);
 void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
 				struct list_head *list);
 
--- linux-ein-5.4.0.orig/block/blk-pm.c
+++ linux-ein-5.4.0/block/blk-pm.c
@@ -67,6 +67,10 @@
 
 	WARN_ON_ONCE(q->rpm_status != RPM_ACTIVE);
 
+	spin_lock_irq(&q->queue_lock);
+	q->rpm_status = RPM_SUSPENDING;
+	spin_unlock_irq(&q->queue_lock);
+
 	/*
 	 * Increase the pm_only counter before checking whether any
 	 * non-PM blk_queue_enter() calls are in progress to avoid that any
@@ -89,15 +93,14 @@
 	/* Switch q_usage_counter back to per-cpu mode. */
 	blk_mq_unfreeze_queue(q);
 
-	spin_lock_irq(&q->queue_lock);
-	if (ret < 0)
+	if (ret < 0) {
+		spin_lock_irq(&q->queue_lock);
+		q->rpm_status = RPM_ACTIVE;
 		pm_runtime_mark_last_busy(q->dev);
-	else
-		q->rpm_status = RPM_SUSPENDING;
-	spin_unlock_irq(&q->queue_lock);
+		spin_unlock_irq(&q->queue_lock);
 
-	if (ret)
 		blk_clear_pm_only(q);
+	}
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/block/blk-rq-qos.c
+++ linux-ein-5.4.0/block/blk-rq-qos.c
@@ -266,8 +266,8 @@
 	if (!has_sleeper && acquire_inflight_cb(rqw, private_data))
 		return;
 
-	prepare_to_wait_exclusive(&rqw->wait, &data.wq, TASK_UNINTERRUPTIBLE);
-	has_sleeper = !wq_has_single_sleeper(&rqw->wait);
+	has_sleeper = !prepare_to_wait_exclusive(&rqw->wait, &data.wq,
+						 TASK_UNINTERRUPTIBLE);
 	do {
 		/* The memory barrier in set_task_state saves us here. */
 		if (data.got_token)
--- linux-ein-5.4.0.orig/block/blk-rq-qos.h
+++ linux-ein-5.4.0/block/blk-rq-qos.h
@@ -7,6 +7,7 @@
 #include <linux/blk_types.h>
 #include <linux/atomic.h>
 #include <linux/wait.h>
+#include <linux/blk-mq.h>
 
 #include "blk-mq-debugfs.h"
 
@@ -99,8 +100,21 @@
 
 static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
 {
+	/*
+	 * No IO can be in-flight when adding rqos, so freeze queue, which
+	 * is fine since we only support rq_qos for blk-mq queue.
+	 *
+	 * Reuse ->queue_lock for protecting against other concurrent
+	 * rq_qos adding/deleting
+	 */
+	blk_mq_freeze_queue(q);
+
+	spin_lock_irq(&q->queue_lock);
 	rqos->next = q->rq_qos;
 	q->rq_qos = rqos;
+	spin_unlock_irq(&q->queue_lock);
+
+	blk_mq_unfreeze_queue(q);
 
 	if (rqos->ops->debugfs_attrs)
 		blk_mq_debugfs_register_rqos(rqos);
@@ -110,12 +124,22 @@
 {
 	struct rq_qos **cur;
 
+	/*
+	 * See comment in rq_qos_add() about freezing queue & using
+	 * ->queue_lock.
+	 */
+	blk_mq_freeze_queue(q);
+
+	spin_lock_irq(&q->queue_lock);
 	for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) {
 		if (*cur == rqos) {
 			*cur = rqos->next;
 			break;
 		}
 	}
+	spin_unlock_irq(&q->queue_lock);
+
+	blk_mq_unfreeze_queue(q);
 
 	blk_mq_debugfs_unregister_rqos(rqos);
 }
--- linux-ein-5.4.0.orig/block/blk-settings.c
+++ linux-ein-5.4.0/block/blk-settings.c
@@ -328,7 +328,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;
 
@@ -473,6 +473,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)
@@ -586,6 +594,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);
@@ -664,6 +676,9 @@
 		printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n",
 		       top, bottom);
 	}
+
+	t->backing_dev_info->io_pages =
+		t->limits.max_sectors >> (PAGE_SHIFT - 9);
 }
 EXPORT_SYMBOL(disk_stack_limits);
 
--- linux-ein-5.4.0.orig/block/blk-sysfs.c
+++ linux-ein-5.4.0/block/blk-sysfs.c
@@ -891,9 +891,16 @@
 
 	blk_free_queue_stats(q->stats);
 
-	if (queue_is_mq(q))
+	if (queue_is_mq(q)) {
+		struct blk_mq_hw_ctx *hctx;
+		int i;
+
 		cancel_delayed_work_sync(&q->requeue_work);
 
+		queue_for_each_hw_ctx(q, hctx, i)
+			cancel_delayed_work_sync(&hctx->run_work);
+	}
+
 	blk_exit_queue(q);
 
 	blk_queue_free_zone_bitmaps(q);
@@ -1053,15 +1060,17 @@
 	 */
 	if (queue_is_mq(q))
 		blk_mq_unregister_dev(disk_to_dev(disk), q);
-
-	kobject_uevent(&q->kobj, KOBJ_REMOVE);
-	kobject_del(&q->kobj);
 	blk_trace_remove_sysfs(disk_to_dev(disk));
 
 	mutex_lock(&q->sysfs_lock);
 	if (q->elevator)
 		elv_unregister_queue(q);
 	mutex_unlock(&q->sysfs_lock);
+
+	/* Now that we've deleted all child objects, we can delete the queue. */
+	kobject_uevent(&q->kobj, KOBJ_REMOVE);
+	kobject_del(&q->kobj);
+
 	mutex_unlock(&q->sysfs_dir_lock);
 
 	kobject_put(&disk_to_dev(disk)->kobj);
--- linux-ein-5.4.0.orig/block/blk-throttle.c
+++ linux-ein-5.4.0/block/blk-throttle.c
@@ -1374,6 +1374,7 @@
 		   tg_bps_limit(tg, READ), tg_bps_limit(tg, WRITE),
 		   tg_iops_limit(tg, READ), tg_iops_limit(tg, WRITE));
 
+	rcu_read_lock();
 	/*
 	 * Update has_rules[] flags for the updated tg's subtree.  A tg is
 	 * considered to have rules if either the tg itself or any of its
@@ -1401,6 +1402,7 @@
 		this_tg->latency_target = max(this_tg->latency_target,
 				parent_tg->latency_target);
 	}
+	rcu_read_unlock();
 
 	/*
 	 * We're already holding queue_lock and know @tg is valid.  Let's
@@ -2414,6 +2416,7 @@
 void blk_throtl_exit(struct request_queue *q)
 {
 	BUG_ON(!q->td);
+	del_timer_sync(&q->td->service_queue.pending_timer);
 	throtl_shutdown_wq(q);
 	blkcg_deactivate_policy(q, &blkcg_policy_throtl);
 	free_percpu(q->td->latency_buckets[READ]);
--- linux-ein-5.4.0.orig/block/blk-timeout.c
+++ linux-ein-5.4.0/block/blk-timeout.c
@@ -20,13 +20,11 @@
 }
 __setup("fail_io_timeout=", setup_fail_io_timeout);
 
-int blk_should_fake_timeout(struct request_queue *q)
+bool __blk_should_fake_timeout(struct request_queue *q)
 {
-	if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags))
-		return 0;
-
 	return should_fail(&fail_io_timeout, 1);
 }
+EXPORT_SYMBOL_GPL(__blk_should_fake_timeout);
 
 static int __init fail_io_timeout_debugfs(void)
 {
--- linux-ein-5.4.0.orig/block/blk-wbt.c
+++ linux-ein-5.4.0/block/blk-wbt.c
@@ -77,7 +77,8 @@
 
 static inline bool rwb_enabled(struct rq_wb *rwb)
 {
-	return rwb && rwb->wb_normal != 0;
+	return rwb && rwb->enable_state != WBT_STATE_OFF_DEFAULT &&
+		      rwb->wb_normal != 0;
 }
 
 static void wb_timestamp(struct rq_wb *rwb, unsigned long *var)
@@ -644,9 +645,13 @@
 void wbt_enable_default(struct request_queue *q)
 {
 	struct rq_qos *rqos = wbt_rq_qos(q);
+
 	/* Throttling already enabled? */
-	if (rqos)
+	if (rqos) {
+		if (RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT)
+			RQWB(rqos)->enable_state = WBT_STATE_ON_DEFAULT;
 		return;
+	}
 
 	/* Queue not registered? Maybe shutting down... */
 	if (!blk_queue_registered(q))
@@ -710,7 +715,7 @@
 	rwb = RQWB(rqos);
 	if (rwb->enable_state == WBT_STATE_ON_DEFAULT) {
 		blk_stat_deactivate(rwb->cb);
-		rwb->wb_normal = 0;
+		rwb->enable_state = WBT_STATE_OFF_DEFAULT;
 	}
 }
 EXPORT_SYMBOL_GPL(wbt_disable_default);
--- linux-ein-5.4.0.orig/block/blk-wbt.h
+++ linux-ein-5.4.0/block/blk-wbt.h
@@ -34,6 +34,7 @@
 enum {
 	WBT_STATE_ON_DEFAULT	= 1,
 	WBT_STATE_ON_MANUAL	= 2,
+	WBT_STATE_OFF_DEFAULT
 };
 
 struct rq_wb {
--- linux-ein-5.4.0.orig/block/blk-zoned.c
+++ linux-ein-5.4.0/block/blk-zoned.c
@@ -202,32 +202,14 @@
 }
 EXPORT_SYMBOL_GPL(blkdev_report_zones);
 
-/*
- * Special case of zone reset operation to reset all zones in one command,
- * useful for applications like mkfs.
- */
-static int __blkdev_reset_all_zones(struct block_device *bdev, gfp_t gfp_mask)
-{
-	struct bio *bio = bio_alloc(gfp_mask, 0);
-	int ret;
-
-	/* across the zones operations, don't need any sectors */
-	bio_set_dev(bio, bdev);
-	bio_set_op_attrs(bio, REQ_OP_ZONE_RESET_ALL, 0);
-
-	ret = submit_bio_wait(bio);
-	bio_put(bio);
-
-	return ret;
-}
-
 static inline bool blkdev_allow_reset_all_zones(struct block_device *bdev,
+						sector_t sector,
 						sector_t nr_sectors)
 {
 	if (!blk_queue_zone_resetall(bdev_get_queue(bdev)))
 		return false;
 
-	if (nr_sectors != part_nr_sects_read(bdev->bd_part))
+	if (sector || nr_sectors != part_nr_sects_read(bdev->bd_part))
 		return false;
 	/*
 	 * REQ_OP_ZONE_RESET_ALL can be executed only if the block device is
@@ -271,9 +253,6 @@
 		/* Out of range */
 		return -EINVAL;
 
-	if (blkdev_allow_reset_all_zones(bdev, nr_sectors))
-		return  __blkdev_reset_all_zones(bdev, gfp_mask);
-
 	/* Check alignment (handle eventual smaller last zone) */
 	zone_sectors = blk_queue_zone_sectors(q);
 	if (sector & (zone_sectors - 1))
@@ -285,17 +264,24 @@
 
 	blk_start_plug(&plug);
 	while (sector < end_sector) {
-
 		bio = blk_next_bio(bio, 0, gfp_mask);
-		bio->bi_iter.bi_sector = sector;
 		bio_set_dev(bio, bdev);
-		bio_set_op_attrs(bio, REQ_OP_ZONE_RESET, 0);
 
+		/*
+		 * Special case for the zone reset operation that reset all
+		 * zones, this is useful for applications like mkfs.
+		 */
+		if (blkdev_allow_reset_all_zones(bdev, sector, nr_sectors)) {
+			bio->bi_opf = REQ_OP_ZONE_RESET_ALL;
+			break;
+		}
+
+		bio->bi_opf = REQ_OP_ZONE_RESET;
+		bio->bi_iter.bi_sector = sector;
 		sector += zone_sectors;
 
 		/* This may take a while, so be nice to others */
 		cond_resched();
-
 	}
 
 	ret = submit_bio_wait(bio);
@@ -330,9 +316,6 @@
 	if (!blk_queue_is_zoned(q))
 		return -ENOTTY;
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
 	if (copy_from_user(&rep, argp, sizeof(struct blk_zone_report)))
 		return -EFAULT;
 
@@ -388,9 +371,6 @@
 	if (!blk_queue_is_zoned(q))
 		return -ENOTTY;
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
 	if (!(mode & FMODE_WRITE))
 		return -EBADF;
 
--- linux-ein-5.4.0.orig/block/blk.h
+++ linux-ein-5.4.0/block/blk.h
@@ -30,6 +30,7 @@
 	 * at the same time
 	 */
 	struct request		*orig_rq;
+	struct lock_class_key	key;
 	spinlock_t		mq_flush_lock;
 };
 
@@ -121,6 +122,7 @@
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 void blk_flush_integrity(void);
 bool __bio_integrity_endio(struct bio *);
+void bio_integrity_free(struct bio *bio);
 static inline bool bio_integrity_endio(struct bio *bio)
 {
 	if (bio_integrity(bio))
@@ -166,6 +168,9 @@
 {
 	return true;
 }
+static inline void bio_integrity_free(struct bio *bio)
+{
+}
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
 unsigned long blk_rq_timeout(unsigned long timeout);
@@ -209,17 +214,9 @@
 
 struct hd_struct *__disk_get_part(struct gendisk *disk, int partno);
 
-#ifdef CONFIG_FAIL_IO_TIMEOUT
-int blk_should_fake_timeout(struct request_queue *);
 ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
 ssize_t part_timeout_store(struct device *, struct device_attribute *,
 				const char *, size_t);
-#else
-static inline int blk_should_fake_timeout(struct request_queue *q)
-{
-	return 0;
-}
-#endif
 
 void __blk_queue_split(struct request_queue *q, struct bio **bio,
 		unsigned int *nr_segs);
--- linux-ein-5.4.0.orig/block/bsg-lib.c
+++ linux-ein-5.4.0/block/bsg-lib.c
@@ -181,9 +181,12 @@
 void bsg_job_done(struct bsg_job *job, int result,
 		  unsigned int reply_payload_rcv_len)
 {
+	struct request *rq = blk_mq_rq_from_pdu(job);
+
 	job->result = result;
 	job->reply_payload_rcv_len = reply_payload_rcv_len;
-	blk_mq_complete_request(blk_mq_rq_from_pdu(job));
+	if (likely(!blk_should_fake_timeout(rq->q)))
+		blk_mq_complete_request(rq);
 }
 EXPORT_SYMBOL_GPL(bsg_job_done);
 
@@ -266,7 +269,7 @@
 	struct request *req = bd->rq;
 	struct bsg_set *bset =
 		container_of(q->tag_set, struct bsg_set, tag_set);
-	int sts = BLK_STS_IOERR;
+	blk_status_t sts = BLK_STS_IOERR;
 	int ret;
 
 	blk_mq_start_request(req);
--- linux-ein-5.4.0.orig/block/bsg.c
+++ linux-ein-5.4.0/block/bsg.c
@@ -157,8 +157,10 @@
 		return PTR_ERR(rq);
 
 	ret = q->bsg_dev.ops->fill_hdr(rq, &hdr, mode);
-	if (ret)
+	if (ret) {
+		blk_put_request(rq);
 		return ret;
+	}
 
 	rq->timeout = msecs_to_jiffies(hdr.timeout);
 	if (!rq->timeout)
@@ -369,10 +371,13 @@
 	case SG_GET_RESERVED_SIZE:
 	case SG_SET_RESERVED_SIZE:
 	case SG_EMULATED_HOST:
-	case SCSI_IOCTL_SEND_COMMAND:
 		return scsi_cmd_ioctl(bd->queue, NULL, file->f_mode, cmd, uarg);
 	case SG_IO:
 		return bsg_sg_io(bd->queue, file->f_mode, uarg);
+	case SCSI_IOCTL_SEND_COMMAND:
+		pr_warn_ratelimited("%s: calling unsupported SCSI_IOCTL_SEND_COMMAND\n",
+				current->comm);
+		return -EINVAL;
 	default:
 		return -ENOTTY;
 	}
--- linux-ein-5.4.0.orig/block/compat_ioctl.c
+++ linux-ein-5.4.0/block/compat_ioctl.c
@@ -6,6 +6,7 @@
 #include <linux/compat.h>
 #include <linux/elevator.h>
 #include <linux/hdreg.h>
+#include <linux/pr.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/types.h>
@@ -354,6 +355,10 @@
 	 * but we call blkdev_ioctl, which gets the lock for us
 	 */
 	case BLKRRPART:
+	case BLKREPORTZONE:
+	case BLKRESETZONE:
+	case BLKGETZONESZ:
+	case BLKGETNRZONES:
 		return blkdev_ioctl(bdev, mode, cmd,
 				(unsigned long)compat_ptr(arg));
 	case BLKBSZSET_32:
@@ -388,7 +393,7 @@
 		return 0;
 	case BLKGETSIZE:
 		size = i_size_read(bdev->bd_inode);
-		if ((size >> 9) > ~0UL)
+		if ((size >> 9) > ~(compat_ulong_t)0)
 			return -EFBIG;
 		return compat_put_ulong(arg, size >> 9);
 
@@ -401,6 +406,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-ein-5.4.0.orig/block/elevator.c
+++ linux-ein-5.4.0/block/elevator.c
@@ -337,6 +337,9 @@
 	__rq = elv_rqhash_find(q, bio->bi_iter.bi_sector);
 	if (__rq && elv_bio_merge_ok(__rq, bio)) {
 		*req = __rq;
+
+		if (blk_discard_mergable(__rq))
+			return ELEVATOR_DISCARD_MERGE;
 		return ELEVATOR_BACK_MERGE;
 	}
 
@@ -522,8 +525,6 @@
 		kobject_del(&e->kobj);
 
 		e->registered = 0;
-		/* Re-enable throttling in case elevator disabled it */
-		wbt_enable_default(q);
 	}
 }
 
--- linux-ein-5.4.0.orig/block/genhd.c
+++ linux-ein-5.4.0/block/genhd.c
@@ -222,14 +222,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;
 	}
@@ -634,10 +637,8 @@
 	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
 	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
 
-	if (disk->flags & GENHD_FL_HIDDEN) {
-		dev_set_uevent_suppress(ddev, 0);
+	if (disk->flags & GENHD_FL_HIDDEN)
 		return;
-	}
 
 	/* No minors to use for partitions */
 	if (!disk_part_scan_enabled(disk))
--- linux-ein-5.4.0.orig/block/ioprio.c
+++ linux-ein-5.4.0/block/ioprio.c
@@ -207,6 +207,7 @@
 				pgrp = task_pgrp(current);
 			else
 				pgrp = find_vpid(who);
+			read_lock(&tasklist_lock);
 			do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
 				tmpio = get_task_ioprio(p);
 				if (tmpio < 0)
@@ -216,6 +217,8 @@
 				else
 					ret = ioprio_best(ret, tmpio);
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+			read_unlock(&tasklist_lock);
+
 			break;
 		case IOPRIO_WHO_USER:
 			uid = make_kuid(current_user_ns(), who);
--- linux-ein-5.4.0.orig/block/kyber-iosched.c
+++ linux-ein-5.4.0/block/kyber-iosched.c
@@ -562,11 +562,12 @@
 	}
 }
 
-static bool kyber_bio_merge(struct blk_mq_hw_ctx *hctx, struct bio *bio,
+static bool kyber_bio_merge(struct request_queue *q, struct bio *bio,
 		unsigned int nr_segs)
 {
+	struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
+	struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, bio->bi_opf, ctx);
 	struct kyber_hctx_data *khd = hctx->sched_data;
-	struct blk_mq_ctx *ctx = blk_mq_get_ctx(hctx->queue);
 	struct kyber_ctx_queue *kcq = &khd->kcqs[ctx->index_hw[hctx->type]];
 	unsigned int sched_domain = kyber_sched_domain(bio->bi_opf);
 	struct list_head *rq_list = &kcq->rq_list[sched_domain];
--- linux-ein-5.4.0.orig/block/mq-deadline.c
+++ linux-ein-5.4.0/block/mq-deadline.c
@@ -452,6 +452,8 @@
 
 		if (elv_bio_merge_ok(__rq, bio)) {
 			*rq = __rq;
+			if (blk_discard_mergable(__rq))
+				return ELEVATOR_DISCARD_MERGE;
 			return ELEVATOR_FRONT_MERGE;
 		}
 	}
@@ -459,10 +461,9 @@
 	return ELEVATOR_NO_MERGE;
 }
 
-static bool dd_bio_merge(struct blk_mq_hw_ctx *hctx, struct bio *bio,
+static bool dd_bio_merge(struct request_queue *q, struct bio *bio,
 		unsigned int nr_segs)
 {
-	struct request_queue *q = hctx->queue;
 	struct deadline_data *dd = q->elevator->elevator_data;
 	struct request *free = NULL;
 	bool ret;
--- linux-ein-5.4.0.orig/block/partition-generic.c
+++ linux-ein-5.4.0/block/partition-generic.c
@@ -272,6 +272,7 @@
 	struct disk_part_tbl *ptbl =
 		rcu_dereference_protected(disk->part_tbl, 1);
 	struct hd_struct *part;
+	struct block_device *bdev;
 
 	if (partno >= ptbl->len)
 		return;
@@ -292,6 +293,12 @@
 	 * "in-use" until we really free the gendisk.
 	 */
 	blk_invalidate_devt(part_devt(part));
+
+	bdev = bdget(part_devt(part));
+	if (bdev) {
+		remove_inode_hash(bdev->bd_inode);
+		bdput(bdev);
+	}
 	hd_struct_kill(part);
 }
 
--- linux-ein-5.4.0.orig/block/partitions/amiga.c
+++ linux-ein-5.4.0/block/partitions/amiga.c
@@ -11,11 +11,19 @@
 #define pr_fmt(fmt) fmt
 
 #include <linux/types.h>
+#include <linux/mm_types.h>
+#include <linux/overflow.h>
 #include <linux/affs_hardblocks.h>
 
 #include "check.h"
 #include "amiga.h"
 
+/* magic offsets in partition DosEnvVec */
+#define NR_HD	3
+#define NR_SECT	5
+#define LO_CYL	9
+#define HI_CYL	10
+
 static __inline__ u32
 checksum_block(__be32 *m, int size)
 {
@@ -32,8 +40,12 @@
 	unsigned char *data;
 	struct RigidDiskBlock *rdb;
 	struct PartitionBlock *pb;
-	int start_sect, nr_sects, blk, part, res = 0;
-	int blksize = 1;	/* Multiplier for disk block size */
+	u64 start_sect, nr_sects;
+	sector_t blk, end_sect;
+	u32 cylblk;		/* rdb_CylBlocks = nr_heads*sect_per_track */
+	u32 nr_hd, nr_sect, lo_cyl, hi_cyl;
+	int part, res = 0;
+	unsigned int blksize = 1;	/* Multiplier for disk block size */
 	int slot = 1;
 	char b[BDEVNAME_SIZE];
 
@@ -43,7 +55,7 @@
 		data = read_part_sector(state, blk, &sect);
 		if (!data) {
 			if (warn_no_part)
-				pr_err("Dev %s: unable to read RDB block %d\n",
+				pr_err("Dev %s: unable to read RDB block %llu\n",
 				       bdevname(state->bdev, b), blk);
 			res = -1;
 			goto rdb_done;
@@ -60,12 +72,12 @@
 		*(__be32 *)(data+0xdc) = 0;
 		if (checksum_block((__be32 *)data,
 				be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
-			pr_err("Trashed word at 0xd0 in block %d ignored in checksum calculation\n",
+			pr_err("Trashed word at 0xd0 in block %llu ignored in checksum calculation\n",
 			       blk);
 			break;
 		}
 
-		pr_err("Dev %s: RDB in block %d has bad checksum\n",
+		pr_err("Dev %s: RDB in block %llu has bad checksum\n",
 		       bdevname(state->bdev, b), blk);
 	}
 
@@ -81,12 +93,17 @@
 	}
 	blk = be32_to_cpu(rdb->rdb_PartitionList);
 	put_dev_sector(sect);
-	for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
-		blk *= blksize;	/* Read in terms partition table understands */
+	for (part = 1; (s32) blk>0 && part<=16; part++, put_dev_sector(sect)) {
+		/* Read in terms partition table understands */
+		if (check_mul_overflow(blk, (sector_t) blksize, &blk)) {
+			pr_err("Dev %s: overflow calculating partition block %llu! Skipping partitions %u and beyond\n",
+				bdevname(state->bdev, b), blk, part);
+			break;
+		}
 		data = read_part_sector(state, blk, &sect);
 		if (!data) {
 			if (warn_no_part)
-				pr_err("Dev %s: unable to read partition block %d\n",
+				pr_err("Dev %s: unable to read partition block %llu\n",
 				       bdevname(state->bdev, b), blk);
 			res = -1;
 			goto rdb_done;
@@ -98,19 +115,70 @@
 		if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
 			continue;
 
-		/* Tell Kernel about it */
+		/* RDB gives us more than enough rope to hang ourselves with,
+		 * many times over (2^128 bytes if all fields max out).
+		 * Some careful checks are in order, so check for potential
+		 * overflows.
+		 * We are multiplying four 32 bit numbers to one sector_t!
+		 */
+
+		nr_hd   = be32_to_cpu(pb->pb_Environment[NR_HD]);
+		nr_sect = be32_to_cpu(pb->pb_Environment[NR_SECT]);
+
+		/* CylBlocks is total number of blocks per cylinder */
+		if (check_mul_overflow(nr_hd, nr_sect, &cylblk)) {
+			pr_err("Dev %s: heads*sects %u overflows u32, skipping partition!\n",
+				bdevname(state->bdev, b), cylblk);
+			continue;
+		}
+
+		/* check for consistency with RDB defined CylBlocks */
+		if (cylblk > be32_to_cpu(rdb->rdb_CylBlocks)) {
+			pr_warn("Dev %s: cylblk %u > rdb_CylBlocks %u!\n",
+				bdevname(state->bdev, b), cylblk,
+				be32_to_cpu(rdb->rdb_CylBlocks));
+		}
+
+		/* RDB allows for variable logical block size -
+		 * normalize to 512 byte blocks and check result.
+		 */
+
+		if (check_mul_overflow(cylblk, blksize, &cylblk)) {
+			pr_err("Dev %s: partition %u bytes per cyl. overflows u32, skipping partition!\n",
+				bdevname(state->bdev, b), part);
+			continue;
+		}
+
+		/* Calculate partition start and end. Limit of 32 bit on cylblk
+		 * guarantees no overflow occurs if LBD support is enabled.
+		 */
+
+		lo_cyl = be32_to_cpu(pb->pb_Environment[LO_CYL]);
+		start_sect = ((u64) lo_cyl * cylblk);
+
+		hi_cyl = be32_to_cpu(pb->pb_Environment[HI_CYL]);
+		nr_sects = (((u64) hi_cyl - lo_cyl + 1) * cylblk);
 
-		nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
-			    be32_to_cpu(pb->pb_Environment[9])) *
-			   be32_to_cpu(pb->pb_Environment[3]) *
-			   be32_to_cpu(pb->pb_Environment[5]) *
-			   blksize;
 		if (!nr_sects)
 			continue;
-		start_sect = be32_to_cpu(pb->pb_Environment[9]) *
-			     be32_to_cpu(pb->pb_Environment[3]) *
-			     be32_to_cpu(pb->pb_Environment[5]) *
-			     blksize;
+
+		/* Warn user if partition end overflows u32 (AmigaDOS limit) */
+
+		if ((start_sect + nr_sects) > UINT_MAX) {
+			pr_warn("Dev %s: partition %u (%llu-%llu) needs 64 bit device support!\n",
+				bdevname(state->bdev, b), part,
+				start_sect, start_sect + nr_sects);
+		}
+
+		if (check_add_overflow(start_sect, nr_sects, &end_sect)) {
+			pr_err("Dev %s: partition %u (%llu-%llu) needs LBD device support, skipping partition!\n",
+				bdevname(state->bdev, b), part,
+				start_sect, end_sect);
+			continue;
+		}
+
+		/* Tell Kernel about it */
+
 		put_partition(state,slot++,start_sect,nr_sects);
 		{
 			/* Be even more informative to aid mounting */
--- linux-ein-5.4.0.orig/block/sed-opal.c
+++ linux-ein-5.4.0/block/sed-opal.c
@@ -88,8 +88,8 @@
 	u64 lowest_lba;
 
 	size_t pos;
-	u8 cmd[IO_BUFFER_LENGTH];
-	u8 resp[IO_BUFFER_LENGTH];
+	u8 *cmd;
+	u8 *resp;
 
 	struct parsed_resp parsed;
 	size_t prev_d_len;
@@ -2019,6 +2019,8 @@
 		return;
 
 	clean_opal_dev(dev);
+	kfree(dev->resp);
+	kfree(dev->cmd);
 	kfree(dev);
 }
 EXPORT_SYMBOL(free_opal_dev);
@@ -2031,17 +2033,39 @@
 	if (!dev)
 		return NULL;
 
+	/*
+	 * Presumably DMA-able buffers must be cache-aligned. Kmalloc makes
+	 * sure the allocated buffer is DMA-safe in that regard.
+	 */
+	dev->cmd = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
+	if (!dev->cmd)
+		goto err_free_dev;
+
+	dev->resp = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
+	if (!dev->resp)
+		goto err_free_cmd;
+
 	INIT_LIST_HEAD(&dev->unlk_lst);
 	mutex_init(&dev->dev_lock);
 	dev->data = data;
 	dev->send_recv = send_recv;
 	if (check_opal_support(dev) != 0) {
 		pr_debug("Opal is not supported on this device\n");
-		kfree(dev);
-		return NULL;
+		goto err_free_resp;
 	}
 
 	return dev;
+
+err_free_resp:
+	kfree(dev->resp);
+
+err_free_cmd:
+	kfree(dev->cmd);
+
+err_free_dev:
+	kfree(dev);
+
+	return NULL;
 }
 EXPORT_SYMBOL(init_opal_dev);
 
--- linux-ein-5.4.0.orig/certs/Kconfig
+++ linux-ein-5.4.0/certs/Kconfig
@@ -83,4 +83,21 @@
 	  wrapper to incorporate the list into the kernel.  Each <hash> should
 	  be a string of hex digits.
 
+config SYSTEM_REVOCATION_LIST
+	bool "Provide system-wide ring of revocation certificates"
+	depends on SYSTEM_BLACKLIST_KEYRING
+	depends on PKCS7_MESSAGE_PARSER=y
+	help
+	  If set, this allows revocation certificates to be stored in the
+	  blacklist keyring and implements a hook whereby a PKCS#7 message can
+	  be checked to see if it matches such a certificate.
+
+config SYSTEM_REVOCATION_KEYS
+	string "X.509 certificates to be preloaded into the system blacklist keyring"
+	depends on SYSTEM_REVOCATION_LIST
+	help
+	  If set, this option should be the filename of a PEM-formatted file
+	  containing X.509 certificates to be included in the default blacklist
+	  keyring.
+
 endmenu
--- linux-ein-5.4.0.orig/certs/Makefile
+++ linux-ein-5.4.0/certs/Makefile
@@ -3,8 +3,9 @@
 # Makefile for the linux kernel signature checking certificates.
 #
 
-obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o common.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o common.o
+obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o
 ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
 obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
 else
@@ -29,7 +30,7 @@
 	$(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
 endif # CONFIG_SYSTEM_TRUSTED_KEYRING
 
-clean-files := x509_certificate_list .x509.list
+clean-files := x509_certificate_list .x509.list x509_revocation_list
 
 ifeq ($(CONFIG_MODULE_SIG),y)
 ###############################################################################
@@ -46,11 +47,19 @@
 redirect_openssl	= 2>&1
 quiet_redirect_openssl	= 2>&1
 silent_redirect_openssl = 2>/dev/null
+openssl_available       = $(shell openssl help 2>/dev/null && echo yes)
 
 # 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")
+
+ifeq ($(openssl_available),yes)
+X509TEXT=$(shell openssl x509 -in "certs/signing_key.pem" -text 2>/dev/null)
+
+$(if $(findstring rsaEncryption,$(X509TEXT)),,$(shell rm -f "certs/signing_key.pem"))
+endif
+
 $(obj)/signing_key.pem: $(obj)/x509.genkey
 	@$(kecho) "###"
 	@$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
@@ -104,3 +113,17 @@
 $(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
 	$(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
 endif # CONFIG_MODULE_SIG
+
+ifeq ($(CONFIG_SYSTEM_REVOCATION_LIST),y)
+
+$(eval $(call config_filename,SYSTEM_REVOCATION_KEYS))
+
+$(obj)/revocation_certificates.o: $(obj)/x509_revocation_list
+
+quiet_cmd_extract_certs  = EXTRACT_CERTS   $(patsubst "%",%,$(2))
+      cmd_extract_certs  = scripts/extract-cert $(2) $@
+
+targets += x509_revocation_list
+$(obj)/x509_revocation_list: scripts/extract-cert $(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(SYSTEM_REVOCATION_KEYS_FILENAME) FORCE
+	$(call if_changed,extract_certs,$(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_REVOCATION_KEYS))
+endif
--- linux-ein-5.4.0.orig/certs/blacklist.c
+++ linux-ein-5.4.0/certs/blacklist.c
@@ -16,9 +16,15 @@
 #include <linux/seq_file.h>
 #include <keys/system_keyring.h>
 #include "blacklist.h"
+#include "common.h"
 
 static struct key *blacklist_keyring;
 
+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
+extern __initconst const u8 revocation_certificate_list[];
+extern __initconst const unsigned long revocation_certificate_list_size;
+#endif
+
 /*
  * The description must be a type prefix, a colon and then an even number of
  * hex digits.  The hash is kept in the description.
@@ -135,6 +141,61 @@
 }
 EXPORT_SYMBOL_GPL(is_hash_blacklisted);
 
+int is_binary_blacklisted(const u8 *hash, size_t hash_len)
+{
+	if (is_hash_blacklisted(hash, hash_len, "bin") == -EKEYREJECTED)
+		return -EPERM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(is_binary_blacklisted);
+
+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
+/**
+ * add_key_to_revocation_list - Add a revocation certificate to the blacklist
+ * @data: The data blob containing the certificate
+ * @size: The size of data blob
+ */
+int add_key_to_revocation_list(const char *data, size_t size)
+{
+	key_ref_t key;
+
+	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+				   "asymmetric",
+				   NULL,
+				   data,
+				   size,
+				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW),
+				   KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN);
+
+	if (IS_ERR(key)) {
+		pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
+		return PTR_ERR(key);
+	} else {
+		pr_notice("Revoked X.509 cert '%s'\n",
+			  key_ref_to_ptr(key)->description);
+	}
+
+	return 0;
+}
+
+/**
+ * is_key_on_revocation_list - Determine if the key for a PKCS#7 message is revoked
+ * @pkcs7: The PKCS#7 message to check
+ */
+int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
+{
+	int ret;
+
+	ret = pkcs7_validate_trust(pkcs7, blacklist_keyring);
+
+	if (ret == 0)
+		return -EKEYREJECTED;
+
+	return -ENOKEY;
+}
+#endif
+
 /*
  * Initialise the blacklist
  */
@@ -153,7 +214,7 @@
 			      KEY_USR_VIEW | KEY_USR_READ |
 			      KEY_USR_SEARCH,
 			      KEY_ALLOC_NOT_IN_QUOTA |
-			      KEY_FLAG_KEEP,
+			      KEY_ALLOC_SET_KEEP,
 			      NULL, NULL);
 	if (IS_ERR(blacklist_keyring))
 		panic("Can't allocate system blacklist keyring\n");
@@ -168,3 +229,18 @@
  * Must be initialised before we try and load the keys into the keyring.
  */
 device_initcall(blacklist_init);
+
+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
+/*
+ * Load the compiled-in list of revocation X.509 certificates.
+ */
+static __init int load_revocation_certificate_list(void)
+{
+	if (revocation_certificate_list_size)
+		pr_notice("Loading compiled-in revocation X.509 certificates\n");
+
+	return load_certificate_list(revocation_certificate_list, revocation_certificate_list_size,
+				     blacklist_keyring);
+}
+late_initcall(load_revocation_certificate_list);
+#endif
--- linux-ein-5.4.0.orig/certs/blacklist.h
+++ linux-ein-5.4.0/certs/blacklist.h
@@ -1,3 +1,5 @@
 #include <linux/kernel.h>
+#include <linux/errno.h>
+#include <crypto/pkcs7.h>
 
 extern const char __initconst *const blacklist_hashes[];
--- linux-ein-5.4.0.orig/certs/blacklist_hashes.c
+++ linux-ein-5.4.0/certs/blacklist_hashes.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "blacklist.h"
 
-const char __initdata *const blacklist_hashes[] = {
+const char __initconst *const blacklist_hashes[] = {
 #include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
 	, NULL
 };
--- linux-ein-5.4.0.orig/certs/common.c
+++ linux-ein-5.4.0/certs/common.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/key.h>
+#include "common.h"
+
+int load_certificate_list(const u8 cert_list[],
+			  const unsigned long list_size,
+			  const struct key *keyring)
+{
+	key_ref_t key;
+	const u8 *p, *end;
+	size_t plen;
+
+	p = cert_list;
+	end = p + list_size;
+	while (p < end) {
+		/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
+		 * than 256 bytes in size.
+		 */
+		if (end - p < 4)
+			goto dodgy_cert;
+		if (p[0] != 0x30 &&
+		    p[1] != 0x82)
+			goto dodgy_cert;
+		plen = (p[2] << 8) | p[3];
+		plen += 4;
+		if (plen > end - p)
+			goto dodgy_cert;
+
+		key = key_create_or_update(make_key_ref(keyring, 1),
+					   "asymmetric",
+					   NULL,
+					   p,
+					   plen,
+					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+					   KEY_USR_VIEW | KEY_USR_READ),
+					   KEY_ALLOC_NOT_IN_QUOTA |
+					   KEY_ALLOC_BUILT_IN |
+					   KEY_ALLOC_BYPASS_RESTRICTION);
+		if (IS_ERR(key)) {
+			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
+			       PTR_ERR(key));
+			WARN_ON_ONCE(1);
+		} else {
+			pr_notice("Loaded X.509 cert '%s'\n",
+				  key_ref_to_ptr(key)->description);
+			key_ref_put(key);
+		}
+		p += plen;
+	}
+
+	return 0;
+
+dodgy_cert:
+	pr_err("Problem parsing in-kernel X.509 certificate list\n");
+	return 0;
+}
--- linux-ein-5.4.0.orig/certs/common.h
+++ linux-ein-5.4.0/certs/common.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _CERT_COMMON_H
+#define _CERT_COMMON_H
+
+int load_certificate_list(const u8 cert_list[], const unsigned long list_size,
+			  const struct key *keyring);
+
+#endif
--- linux-ein-5.4.0.orig/certs/revocation_certificates.S
+++ linux-ein-5.4.0/certs/revocation_certificates.S
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/export.h>
+#include <linux/init.h>
+
+	__INITRODATA
+
+	.align 8
+	.globl revocation_certificate_list
+revocation_certificate_list:
+__revocation_list_start:
+	.incbin "certs/x509_revocation_list"
+__revocation_list_end:
+
+	.align 8
+	.globl revocation_certificate_list_size
+revocation_certificate_list_size:
+#ifdef CONFIG_64BIT
+	.quad __revocation_list_end - __revocation_list_start
+#else
+	.long __revocation_list_end - __revocation_list_start
+#endif
--- linux-ein-5.4.0.orig/certs/system_keyring.c
+++ linux-ein-5.4.0/certs/system_keyring.c
@@ -15,6 +15,7 @@
 #include <keys/asymmetric-type.h>
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
+#include "common.h"
 
 static struct key *builtin_trusted_keys;
 #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
@@ -136,54 +137,10 @@
  */
 static __init int load_system_certificate_list(void)
 {
-	key_ref_t key;
-	const u8 *p, *end;
-	size_t plen;
-
 	pr_notice("Loading compiled-in X.509 certificates\n");
 
-	p = system_certificate_list;
-	end = p + system_certificate_list_size;
-	while (p < end) {
-		/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
-		 * than 256 bytes in size.
-		 */
-		if (end - p < 4)
-			goto dodgy_cert;
-		if (p[0] != 0x30 &&
-		    p[1] != 0x82)
-			goto dodgy_cert;
-		plen = (p[2] << 8) | p[3];
-		plen += 4;
-		if (plen > end - p)
-			goto dodgy_cert;
-
-		key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
-					   "asymmetric",
-					   NULL,
-					   p,
-					   plen,
-					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
-					   KEY_USR_VIEW | KEY_USR_READ),
-					   KEY_ALLOC_NOT_IN_QUOTA |
-					   KEY_ALLOC_BUILT_IN |
-					   KEY_ALLOC_BYPASS_RESTRICTION);
-		if (IS_ERR(key)) {
-			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
-			       PTR_ERR(key));
-		} else {
-			pr_notice("Loaded X.509 cert '%s'\n",
-				  key_ref_to_ptr(key)->description);
-			key_ref_put(key);
-		}
-		p += plen;
-	}
-
-	return 0;
-
-dodgy_cert:
-	pr_err("Problem parsing in-kernel X.509 certificate list\n");
-	return 0;
+	return load_certificate_list(system_certificate_list, system_certificate_list_size,
+				     builtin_trusted_keys);
 }
 late_initcall(load_system_certificate_list);
 
@@ -241,6 +198,12 @@
 			pr_devel("PKCS#7 platform keyring is not available\n");
 			goto error;
 		}
+
+		ret = is_key_on_revocation_list(pkcs7);
+		if (ret != -ENOKEY) {
+			pr_devel("PKCS#7 platform key is on revocation list\n");
+			goto error;
+		}
 	}
 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
 	if (ret < 0) {
--- linux-ein-5.4.0.orig/crypto/Kconfig
+++ linux-ein-5.4.0/crypto/Kconfig
@@ -242,12 +242,12 @@
 
 config CRYPTO_ECC
 	tristate
+	select CRYPTO_RNG_DEFAULT
 
 config CRYPTO_ECDH
 	tristate "ECDH algorithm"
 	select CRYPTO_ECC
 	select CRYPTO_KPP
-	select CRYPTO_RNG_DEFAULT
 	help
 	  Generic implementation of the ECDH algorithm
 
@@ -309,6 +309,7 @@
 config CRYPTO_AEGIS128_SIMD
 	bool "Support SIMD acceleration for AEGIS-128"
 	depends on CRYPTO_AEGIS128 && ((ARM || ARM64) && KERNEL_MODE_NEON)
+	depends on !ARM || CC_IS_CLANG || GCC_VERSION >= 40800
 	default y
 
 config CRYPTO_AEGIS128_AESNI_SSE2
@@ -499,10 +500,10 @@
 	  encryption.
 
 	  This driver implements a crypto API template that can be
-	  instantiated either as a skcipher or as a aead (depending on the
+	  instantiated either as an skcipher or as an AEAD (depending on the
 	  type of the first template argument), and which defers encryption
 	  and decryption requests to the encapsulated cipher after applying
-	  ESSIV to the input IV. Note that in the aead case, it is assumed
+	  ESSIV to the input IV. Note that in the AEAD case, it is assumed
 	  that the keys are presented in the same format used by the authenc
 	  template, and that the IV appears at the end of the authenticated
 	  associated data (AAD) region (which is how dm-crypt uses it.)
--- linux-ein-5.4.0.orig/crypto/Makefile
+++ linux-ein-5.4.0/crypto/Makefile
@@ -93,7 +93,7 @@
 aegis128-y := aegis128-core.o
 
 ifeq ($(ARCH),arm)
-CFLAGS_aegis128-neon-inner.o += -ffreestanding -march=armv7-a -mfloat-abi=softfp
+CFLAGS_aegis128-neon-inner.o += -ffreestanding -march=armv8-a -mfloat-abi=softfp
 CFLAGS_aegis128-neon-inner.o += -mfpu=crypto-neon-fp-armv8
 aegis128-$(CONFIG_CRYPTO_AEGIS128_SIMD) += aegis128-neon.o aegis128-neon-inner.o
 endif
--- linux-ein-5.4.0.orig/crypto/af_alg.c
+++ linux-ein-5.4.0/crypto/af_alg.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/rwsem.h>
+#include <linux/sched.h>
 #include <linux/sched/signal.h>
 #include <linux/security.h>
 
@@ -128,19 +129,15 @@
 void af_alg_release_parent(struct sock *sk)
 {
 	struct alg_sock *ask = alg_sk(sk);
-	unsigned int nokey = ask->nokey_refcnt;
-	bool last = nokey && !ask->refcnt;
+	unsigned int nokey = atomic_read(&ask->nokey_refcnt);
 
 	sk = ask->parent;
 	ask = alg_sk(sk);
 
-	lock_sock(sk);
-	ask->nokey_refcnt -= nokey;
-	if (!last)
-		last = !--ask->refcnt;
-	release_sock(sk);
+	if (nokey)
+		atomic_dec(&ask->nokey_refcnt);
 
-	if (last)
+	if (atomic_dec_and_test(&ask->refcnt))
 		sock_put(sk);
 }
 EXPORT_SYMBOL_GPL(af_alg_release_parent);
@@ -150,7 +147,7 @@
 	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;
+	struct sockaddr_alg_new *sa = (void *)uaddr;
 	const struct af_alg_type *type;
 	void *private;
 	int err;
@@ -158,7 +155,11 @@
 	if (sock->state == SS_CONNECTED)
 		return -EINVAL;
 
-	if (addr_len < sizeof(*sa))
+	BUILD_BUG_ON(offsetof(struct sockaddr_alg_new, salg_name) !=
+		     offsetof(struct sockaddr_alg, salg_name));
+	BUILD_BUG_ON(offsetof(struct sockaddr_alg, salg_name) != sizeof(*sa));
+
+	if (addr_len < sizeof(*sa) + 1)
 		return -EINVAL;
 
 	/* If caller uses non-allowed flag, return error. */
@@ -166,7 +167,7 @@
 		return -EINVAL;
 
 	sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
-	sa->salg_name[sizeof(sa->salg_name) + addr_len - sizeof(*sa) - 1] = 0;
+	sa->salg_name[addr_len - sizeof(*sa) - 1] = 0;
 
 	type = alg_get_type(sa->salg_type);
 	if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) {
@@ -185,7 +186,7 @@
 
 	err = -EBUSY;
 	lock_sock(sk);
-	if (ask->refcnt | ask->nokey_refcnt)
+	if (atomic_read(&ask->refcnt))
 		goto unlock;
 
 	swap(ask->type, type);
@@ -234,7 +235,7 @@
 	int err = -EBUSY;
 
 	lock_sock(sk);
-	if (ask->refcnt)
+	if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
 		goto unlock;
 
 	type = ask->type;
@@ -299,12 +300,14 @@
 	if (err)
 		goto unlock;
 
-	if (nokey || !ask->refcnt++)
+	if (atomic_inc_return_relaxed(&ask->refcnt) == 1)
 		sock_hold(sk);
-	ask->nokey_refcnt += nokey;
+	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;
-	alg_sk(sk2)->nokey_refcnt = nokey;
 
 	newsock->ops = type->ops;
 	newsock->state = SS_CONNECTED;
@@ -637,6 +640,7 @@
 
 	if (!ctx->used)
 		ctx->merge = 0;
+	ctx->init = ctx->more;
 }
 EXPORT_SYMBOL_GPL(af_alg_pull_tsgl);
 
@@ -736,9 +740,10 @@
  *
  * @sk socket of connection to user space
  * @flags If MSG_DONTWAIT is set, then only report if function would sleep
+ * @min Set to minimum request size if partial requests are allowed.
  * @return 0 when writable memory is available, < 0 upon error
  */
-int af_alg_wait_for_data(struct sock *sk, unsigned flags)
+int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min)
 {
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
 	struct alg_sock *ask = alg_sk(sk);
@@ -756,7 +761,9 @@
 		if (signal_pending(current))
 			break;
 		timeout = MAX_SCHEDULE_TIMEOUT;
-		if (sk_wait_event(sk, &timeout, (ctx->used || !ctx->more),
+		if (sk_wait_event(sk, &timeout,
+				  ctx->init && (!ctx->more ||
+						(min && ctx->used >= min)),
 				  &wait)) {
 			err = 0;
 			break;
@@ -845,10 +852,17 @@
 	}
 
 	lock_sock(sk);
-	if (!ctx->more && ctx->used) {
-		err = -EINVAL;
-		goto unlock;
+	if (ctx->init && !ctx->more) {
+		if (ctx->used) {
+			err = -EINVAL;
+			goto unlock;
+		}
+
+		pr_info_once(
+			"%s sent an empty control message without MSG_MORE.\n",
+			current->comm);
 	}
+	ctx->init = true;
 
 	if (init) {
 		ctx->enc = enc;
@@ -1015,9 +1029,13 @@
 void af_alg_free_resources(struct af_alg_async_req *areq)
 {
 	struct sock *sk = areq->sk;
+	struct af_alg_ctx *ctx;
 
 	af_alg_free_areq_sgls(areq);
 	sock_kfree_s(sk, areq, areq->areqlen);
+
+	ctx = alg_sk(sk)->private;
+	ctx->inflight = false;
 }
 EXPORT_SYMBOL_GPL(af_alg_free_resources);
 
@@ -1043,7 +1061,7 @@
 	af_alg_free_resources(areq);
 	sock_put(sk);
 
-	iocb->ki_complete(iocb, err ? err : resultlen, 0);
+	iocb->ki_complete(iocb, err ? err : (int)resultlen, 0);
 }
 EXPORT_SYMBOL_GPL(af_alg_async_cb);
 
@@ -1081,11 +1099,19 @@
 struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk,
 					   unsigned int areqlen)
 {
-	struct af_alg_async_req *areq = sock_kmalloc(sk, areqlen, GFP_KERNEL);
+	struct af_alg_ctx *ctx = alg_sk(sk)->private;
+	struct af_alg_async_req *areq;
+
+	/* Only one AIO request can be in flight. */
+	if (ctx->inflight)
+		return ERR_PTR(-EBUSY);
 
+	areq = sock_kmalloc(sk, areqlen, GFP_KERNEL);
 	if (unlikely(!areq))
 		return ERR_PTR(-ENOMEM);
 
+	ctx->inflight = true;
+
 	areq->areqlen = areqlen;
 	areq->sk = sk;
 	areq->last_rsgl = NULL;
--- linux-ein-5.4.0.orig/crypto/akcipher.c
+++ linux-ein-5.4.0/crypto/akcipher.c
@@ -119,6 +119,12 @@
 	return -ENOSYS;
 }
 
+static int akcipher_default_set_key(struct crypto_akcipher *tfm,
+				     const void *key, unsigned int keylen)
+{
+	return -ENOSYS;
+}
+
 int crypto_register_akcipher(struct akcipher_alg *alg)
 {
 	struct crypto_alg *base = &alg->base;
@@ -131,6 +137,8 @@
 		alg->encrypt = akcipher_default_op;
 	if (!alg->decrypt)
 		alg->decrypt = akcipher_default_op;
+	if (!alg->set_priv_key)
+		alg->set_priv_key = akcipher_default_set_key;
 
 	akcipher_prepare_alg(alg);
 	return crypto_register_alg(base);
--- linux-ein-5.4.0.orig/crypto/algapi.c
+++ linux-ein-5.4.0/crypto/algapi.c
@@ -217,6 +217,7 @@
 		}
 
 		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
+		    !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
 		    !strcmp(q->cra_name, alg->cra_driver_name))
 			goto err;
 	}
@@ -257,6 +258,7 @@
 	struct crypto_alg *alg;
 	struct crypto_alg *q;
 	LIST_HEAD(list);
+	bool best;
 
 	down_write(&crypto_alg_sem);
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
@@ -280,6 +282,21 @@
 
 	alg->cra_flags |= CRYPTO_ALG_TESTED;
 
+	/* Only satisfy larval waiters if we are the best. */
+	best = true;
+	list_for_each_entry(q, &crypto_alg_list, cra_list) {
+		if (crypto_is_moribund(q) || !crypto_is_larval(q))
+			continue;
+
+		if (strcmp(alg->cra_name, q->cra_name))
+			continue;
+
+		if (q->cra_priority > alg->cra_priority) {
+			best = false;
+			break;
+		}
+	}
+
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
 		if (q == alg)
 			continue;
@@ -303,10 +320,12 @@
 				continue;
 			if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
 				continue;
-			if (!crypto_mod_get(alg))
-				continue;
 
-			larval->adult = alg;
+			if (best && crypto_mod_get(alg))
+				larval->adult = alg;
+			else
+				larval->adult = ERR_PTR(-EAGAIN);
+
 			continue;
 		}
 
@@ -356,7 +375,7 @@
 	err = wait_for_completion_killable(&larval->completion);
 	WARN_ON(err);
 	if (!err)
-		crypto_probing_notify(CRYPTO_MSG_ALG_LOADED, larval);
+		crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);
 
 out:
 	crypto_larval_kill(&larval->alg);
@@ -669,11 +688,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);
@@ -681,22 +698,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-ein-5.4.0.orig/crypto/algboss.c
+++ linux-ein-5.4.0/crypto/algboss.c
@@ -188,8 +188,6 @@
 	if (IS_ERR(thread))
 		goto err_put_larval;
 
-	wait_for_completion_interruptible(&larval->completion);
-
 	return NOTIFY_STOP;
 
 err_put_larval:
--- linux-ein-5.4.0.orig/crypto/algif_aead.c
+++ linux-ein-5.4.0/crypto/algif_aead.c
@@ -78,7 +78,7 @@
 	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
 
 	skcipher_request_set_sync_tfm(skreq, null_tfm);
-	skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG,
+	skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP,
 				      NULL, NULL);
 	skcipher_request_set_crypt(skreq, src, dst, len, NULL);
 
@@ -106,8 +106,8 @@
 	size_t usedpages = 0;		/* [in]  RX bufs to be used from user */
 	size_t processed = 0;		/* [in]  TX bufs to be consumed */
 
-	if (!ctx->used) {
-		err = af_alg_wait_for_data(sk, flags);
+	if (!ctx->init || ctx->more) {
+		err = af_alg_wait_for_data(sk, flags, 0);
 		if (err)
 			return err;
 	}
@@ -291,19 +291,20 @@
 		areq->outlen = outlen;
 
 		aead_request_set_callback(&areq->cra_u.aead_req,
-					  CRYPTO_TFM_REQ_MAY_BACKLOG,
+					  CRYPTO_TFM_REQ_MAY_SLEEP,
 					  af_alg_async_cb, areq);
 		err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) :
 				 crypto_aead_decrypt(&areq->cra_u.aead_req);
 
 		/* AIO operation in progress */
-		if (err == -EINPROGRESS || err == -EBUSY)
+		if (err == -EINPROGRESS)
 			return -EIOCBQUEUED;
 
 		sock_put(sk);
 	} else {
 		/* Synchronous operation */
 		aead_request_set_callback(&areq->cra_u.aead_req,
+					  CRYPTO_TFM_REQ_MAY_SLEEP |
 					  CRYPTO_TFM_REQ_MAY_BACKLOG,
 					  crypto_req_done, &ctx->wait);
 		err = crypto_wait_req(ctx->enc ?
@@ -384,7 +385,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 
 	lock_sock(sk);
-	if (ask->refcnt)
+	if (!atomic_read(&ask->nokey_refcnt))
 		goto unlock_child;
 
 	psk = ask->parent;
@@ -396,11 +397,8 @@
 	if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
 		goto unlock;
 
-	if (!pask->refcnt++)
-		sock_hold(psk);
-
-	ask->refcnt = 1;
-	sock_put(psk);
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
 
 	err = 0;
 
@@ -561,12 +559,6 @@
 
 	INIT_LIST_HEAD(&ctx->tsgl_list);
 	ctx->len = len;
-	ctx->used = 0;
-	atomic_set(&ctx->rcvused, 0);
-	ctx->more = 0;
-	ctx->merge = 0;
-	ctx->enc = 0;
-	ctx->aead_assoclen = 0;
 	crypto_init_wait(&ctx->wait);
 
 	ask->private = ctx;
--- linux-ein-5.4.0.orig/crypto/algif_hash.c
+++ linux-ein-5.4.0/crypto/algif_hash.c
@@ -301,7 +301,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 
 	lock_sock(sk);
-	if (ask->refcnt)
+	if (!atomic_read(&ask->nokey_refcnt))
 		goto unlock_child;
 
 	psk = ask->parent;
@@ -313,11 +313,8 @@
 	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
 		goto unlock;
 
-	if (!pask->refcnt++)
-		sock_hold(psk);
-
-	ask->refcnt = 1;
-	sock_put(psk);
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
 
 	err = 0;
 
--- linux-ein-5.4.0.orig/crypto/algif_skcipher.c
+++ linux-ein-5.4.0/crypto/algif_skcipher.c
@@ -56,13 +56,13 @@
 	struct alg_sock *pask = alg_sk(psk);
 	struct af_alg_ctx *ctx = ask->private;
 	struct crypto_skcipher *tfm = pask->private;
-	unsigned int bs = crypto_skcipher_blocksize(tfm);
+	unsigned int bs = crypto_skcipher_chunksize(tfm);
 	struct af_alg_async_req *areq;
 	int err = 0;
 	size_t len = 0;
 
-	if (!ctx->used) {
-		err = af_alg_wait_for_data(sk, flags);
+	if (!ctx->init || (ctx->more && ctx->used < bs)) {
+		err = af_alg_wait_for_data(sk, flags, bs);
 		if (err)
 			return err;
 	}
@@ -74,14 +74,10 @@
 		return PTR_ERR(areq);
 
 	/* convert iovecs of output buffers into RX SGL */
-	err = af_alg_get_rsgl(sk, msg, flags, areq, -1, &len);
+	err = af_alg_get_rsgl(sk, msg, flags, areq, ctx->used, &len);
 	if (err)
 		goto free;
 
-	/* Process only as much RX buffers for which we have TX data */
-	if (len > ctx->used)
-		len = ctx->used;
-
 	/*
 	 * If more buffers are to be expected to be processed, process only
 	 * full block size buffers.
@@ -127,7 +123,7 @@
 			crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
 
 		/* AIO operation in progress */
-		if (err == -EINPROGRESS || err == -EBUSY)
+		if (err == -EINPROGRESS)
 			return -EIOCBQUEUED;
 
 		sock_put(sk);
@@ -215,7 +211,7 @@
 	struct alg_sock *ask = alg_sk(sk);
 
 	lock_sock(sk);
-	if (ask->refcnt)
+	if (!atomic_read(&ask->nokey_refcnt))
 		goto unlock_child;
 
 	psk = ask->parent;
@@ -227,11 +223,8 @@
 	if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
 		goto unlock;
 
-	if (!pask->refcnt++)
-		sock_hold(psk);
-
-	ask->refcnt = 1;
-	sock_put(psk);
+	atomic_dec(&pask->nokey_refcnt);
+	atomic_set(&ask->nokey_refcnt, 0);
 
 	err = 0;
 
@@ -340,6 +333,7 @@
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
+	memset(ctx, 0, len);
 
 	ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(tfm),
 			       GFP_KERNEL);
@@ -347,16 +341,10 @@
 		sock_kfree_s(sk, ctx, len);
 		return -ENOMEM;
 	}
-
 	memset(ctx->iv, 0, crypto_skcipher_ivsize(tfm));
 
 	INIT_LIST_HEAD(&ctx->tsgl_list);
 	ctx->len = len;
-	ctx->used = 0;
-	atomic_set(&ctx->rcvused, 0);
-	ctx->more = 0;
-	ctx->merge = 0;
-	ctx->enc = 0;
 	crypto_init_wait(&ctx->wait);
 
 	ask->private = ctx;
--- linux-ein-5.4.0.orig/crypto/api.c
+++ linux-ein-5.4.0/crypto/api.c
@@ -97,7 +97,7 @@
 	struct crypto_larval *larval = (void *)alg;
 
 	BUG_ON(!crypto_is_larval(alg));
-	if (larval->adult)
+	if (!IS_ERR_OR_NULL(larval->adult))
 		crypto_mod_put(larval->adult);
 	kfree(larval);
 }
@@ -178,6 +178,8 @@
 		alg = ERR_PTR(-ETIMEDOUT);
 	else if (!alg)
 		alg = ERR_PTR(-ENOENT);
+	else if (IS_ERR(alg))
+		;
 	else if (crypto_is_test_larval(larval) &&
 		 !(alg->cra_flags & CRYPTO_ALG_TESTED))
 		alg = ERR_PTR(-EAGAIN);
@@ -344,13 +346,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)
@@ -567,7 +568,7 @@
 {
 	struct crypto_alg *alg;
 
-	if (unlikely(!mem))
+	if (IS_ERR_OR_NULL(mem))
 		return;
 
 	alg = tfm->__crt_alg;
--- linux-ein-5.4.0.orig/crypto/asymmetric_keys/asym_tpm.c
+++ linux-ein-5.4.0/crypto/asymmetric_keys/asym_tpm.c
@@ -370,7 +370,7 @@
 	memcpy(cur, e, sizeof(e));
 	cur += sizeof(e);
 	/* Zero parameters to satisfy set_pub_key ABI. */
-	memset(cur, 0, SETKEY_PARAMS_SIZE);
+	memzero_explicit(cur, SETKEY_PARAMS_SIZE);
 
 	return cur - buf;
 }
@@ -486,6 +486,7 @@
 	if (ret < 0)
 		goto error_free_tfm;
 
+	ret = -ENOMEM;
 	req = akcipher_request_alloc(tfm, GFP_KERNEL);
 	if (!req)
 		goto error_free_tfm;
--- linux-ein-5.4.0.orig/crypto/asymmetric_keys/pkcs7_verify.c
+++ linux-ein-5.4.0/crypto/asymmetric_keys/pkcs7_verify.c
@@ -79,16 +79,16 @@
 		}
 
 		if (sinfo->msgdigest_len != sig->digest_size) {
-			pr_debug("Sig %u: Invalid digest size (%u)\n",
-				 sinfo->index, sinfo->msgdigest_len);
+			pr_warn("Sig %u: Invalid digest size (%u)\n",
+				sinfo->index, sinfo->msgdigest_len);
 			ret = -EBADMSG;
 			goto error;
 		}
 
 		if (memcmp(sig->digest, sinfo->msgdigest,
 			   sinfo->msgdigest_len) != 0) {
-			pr_debug("Sig %u: Message digest doesn't match\n",
-				 sinfo->index);
+			pr_warn("Sig %u: Message digest doesn't match\n",
+				sinfo->index);
 			ret = -EKEYREJECTED;
 			goto error;
 		}
@@ -488,7 +488,7 @@
 			       const void *data, size_t datalen)
 {
 	if (pkcs7->data) {
-		pr_debug("Data already supplied\n");
+		pr_warn("Data already supplied\n");
 		return -EINVAL;
 	}
 	pkcs7->data = data;
--- linux-ein-5.4.0.orig/crypto/asymmetric_keys/public_key.c
+++ linux-ein-5.4.0/crypto/asymmetric_keys/public_key.c
@@ -119,6 +119,7 @@
 	if (IS_ERR(tfm))
 		return PTR_ERR(tfm);
 
+	ret = -ENOMEM;
 	key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
 		      GFP_KERNEL);
 	if (!key)
@@ -184,6 +185,7 @@
 	if (IS_ERR(tfm))
 		return PTR_ERR(tfm);
 
+	ret = -ENOMEM;
 	req = akcipher_request_alloc(tfm, GFP_KERNEL);
 	if (!req)
 		goto error_free_tfm;
@@ -253,9 +255,10 @@
 	struct crypto_wait cwait;
 	struct crypto_akcipher *tfm;
 	struct akcipher_request *req;
-	struct scatterlist src_sg[2];
+	struct scatterlist src_sg;
 	char alg_name[CRYPTO_MAX_ALG_NAME];
-	char *key, *ptr;
+	char *buf, *ptr;
+	size_t buf_len;
 	int ret;
 
 	pr_devel("==>%s()\n", __func__);
@@ -279,28 +282,31 @@
 	if (!req)
 		goto error_free_tfm;
 
-	key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
-		      GFP_KERNEL);
-	if (!key)
+	buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+			sig->s_size + sig->digest_size);
+
+	buf = kmalloc(buf_len, GFP_KERNEL);
+	if (!buf)
 		goto error_free_req;
 
-	memcpy(key, pkey->key, pkey->keylen);
-	ptr = key + pkey->keylen;
+	memcpy(buf, pkey->key, pkey->keylen);
+	ptr = buf + pkey->keylen;
 	ptr = pkey_pack_u32(ptr, pkey->algo);
 	ptr = pkey_pack_u32(ptr, pkey->paramlen);
 	memcpy(ptr, pkey->params, pkey->paramlen);
 
 	if (pkey->key_is_private)
-		ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
+		ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen);
 	else
-		ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
+		ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen);
 	if (ret)
-		goto error_free_key;
+		goto error_free_buf;
 
-	sg_init_table(src_sg, 2);
-	sg_set_buf(&src_sg[0], sig->s, sig->s_size);
-	sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
-	akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
+	memcpy(buf, sig->s, sig->s_size);
+	memcpy(buf + sig->s_size, sig->digest, sig->digest_size);
+
+	sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size);
+	akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size,
 				   sig->digest_size);
 	crypto_init_wait(&cwait);
 	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
@@ -308,8 +314,8 @@
 				      crypto_req_done, &cwait);
 	ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
 
-error_free_key:
-	kfree(key);
+error_free_buf:
+	kfree(buf);
 error_free_req:
 	akcipher_request_free(req);
 error_free_tfm:
--- linux-ein-5.4.0.orig/crypto/asymmetric_keys/verify_pefile.c
+++ linux-ein-5.4.0/crypto/asymmetric_keys/verify_pefile.c
@@ -74,7 +74,7 @@
 		break;
 
 	default:
-		pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
+		pr_warn("Unknown PEOPT magic = %04hx\n", pe32->magic);
 		return -ELIBBAD;
 	}
 
@@ -95,7 +95,7 @@
 	ctx->certs_size = ddir->certs.size;
 
 	if (!ddir->certs.virtual_address || !ddir->certs.size) {
-		pr_debug("Unsigned PE binary\n");
+		pr_warn("Unsigned PE binary\n");
 		return -ENODATA;
 	}
 
@@ -127,7 +127,7 @@
 	unsigned len;
 
 	if (ctx->sig_len < sizeof(wrapper)) {
-		pr_debug("Signature wrapper too short\n");
+		pr_warn("Signature wrapper too short\n");
 		return -ELIBBAD;
 	}
 
@@ -135,19 +135,23 @@
 	pr_debug("sig wrapper = { %x, %x, %x }\n",
 		 wrapper.length, wrapper.revision, wrapper.cert_type);
 
-	/* Both pesign and sbsign round up the length of certificate table
-	 * (in optional header data directories) to 8 byte alignment.
+	/* sbsign rounds up the length of certificate table (in optional
+	 * header data directories) to 8 byte alignment.  However, the PE
+	 * specification states that while entries are 8-byte aligned, this is
+	 * not included in their length, and as a result, pesign has not
+	 * rounded up since 0.110.
 	 */
-	if (round_up(wrapper.length, 8) != ctx->sig_len) {
-		pr_debug("Signature wrapper len wrong\n");
+	if (wrapper.length > ctx->sig_len) {
+		pr_warn("Signature wrapper bigger than sig len (%x > %x)\n",
+			ctx->sig_len, wrapper.length);
 		return -ELIBBAD;
 	}
 	if (wrapper.revision != WIN_CERT_REVISION_2_0) {
-		pr_debug("Signature is not revision 2.0\n");
+		pr_warn("Signature is not revision 2.0\n");
 		return -ENOTSUPP;
 	}
 	if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
-		pr_debug("Signature certificate type is not PKCS\n");
+		pr_warn("Signature certificate type is not PKCS\n");
 		return -ENOTSUPP;
 	}
 
@@ -160,7 +164,7 @@
 	ctx->sig_offset += sizeof(wrapper);
 	ctx->sig_len -= sizeof(wrapper);
 	if (ctx->sig_len < 4) {
-		pr_debug("Signature data missing\n");
+		pr_warn("Signature data missing\n");
 		return -EKEYREJECTED;
 	}
 
@@ -194,7 +198,7 @@
 		return 0;
 	}
 not_pkcs7:
-	pr_debug("Signature data not PKCS#7\n");
+	pr_warn("Signature data not PKCS#7\n");
 	return -ELIBBAD;
 }
 
@@ -337,8 +341,8 @@
 	digest_size = crypto_shash_digestsize(tfm);
 
 	if (digest_size != ctx->digest_len) {
-		pr_debug("Digest size mismatch (%zx != %x)\n",
-			 digest_size, ctx->digest_len);
+		pr_warn("Digest size mismatch (%zx != %x)\n",
+			digest_size, ctx->digest_len);
 		ret = -EBADMSG;
 		goto error_no_desc;
 	}
@@ -369,7 +373,7 @@
 	 * PKCS#7 certificate.
 	 */
 	if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
-		pr_debug("Digest mismatch\n");
+		pr_warn("Digest mismatch\n");
 		ret = -EKEYREJECTED;
 	} else {
 		pr_debug("The digests match!\n");
--- linux-ein-5.4.0.orig/crypto/asymmetric_keys/x509_public_key.c
+++ linux-ein-5.4.0/crypto/asymmetric_keys/x509_public_key.c
@@ -129,6 +129,11 @@
 	if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0)
 		goto out;
 
+	if (cert->unsupported_sig) {
+		ret = 0;
+		goto out;
+	}
+
 	ret = public_key_verify_signature(cert->pub, cert->sig);
 	if (ret < 0) {
 		if (ret == -ENOPKG) {
--- linux-ein-5.4.0.orig/crypto/authenc.c
+++ linux-ein-5.4.0/crypto/authenc.c
@@ -263,7 +263,7 @@
 		dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
 
 	skcipher_request_set_tfm(skreq, ctx->enc);
-	skcipher_request_set_callback(skreq, aead_request_flags(req),
+	skcipher_request_set_callback(skreq, flags,
 				      req->base.complete, req->base.data);
 	skcipher_request_set_crypt(skreq, src, dst,
 				   req->cryptlen - authsize, req->iv);
--- linux-ein-5.4.0.orig/crypto/cast6_generic.c
+++ linux-ein-5.4.0/crypto/cast6_generic.c
@@ -154,7 +154,7 @@
 EXPORT_SYMBOL_GPL(cast6_setkey);
 
 /*forward quad round*/
-static inline void Q(u32 *block, u8 *Kr, u32 *Km)
+static inline void Q(u32 *block, const u8 *Kr, const u32 *Km)
 {
 	u32 I;
 	block[2] ^= F1(block[3], Kr[0], Km[0]);
@@ -164,7 +164,7 @@
 }
 
 /*reverse quad round*/
-static inline void QBAR(u32 *block, u8 *Kr, u32 *Km)
+static inline void QBAR(u32 *block, const u8 *Kr, const u32 *Km)
 {
 	u32 I;
 	block[3] ^= F1(block[0], Kr[3], Km[3]);
@@ -173,13 +173,14 @@
 	block[2] ^= F1(block[3], Kr[0], Km[0]);
 }
 
-void __cast6_encrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
+void __cast6_encrypt(const void *ctx, u8 *outbuf, const u8 *inbuf)
 {
+	const struct cast6_ctx *c = ctx;
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 block[4];
-	u32 *Km;
-	u8 *Kr;
+	const u32 *Km;
+	const u8 *Kr;
 
 	block[0] = be32_to_cpu(src[0]);
 	block[1] = be32_to_cpu(src[1]);
@@ -211,13 +212,14 @@
 	__cast6_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
 }
 
-void __cast6_decrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
+void __cast6_decrypt(const void *ctx, u8 *outbuf, const u8 *inbuf)
 {
+	const struct cast6_ctx *c = ctx;
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 block[4];
-	u32 *Km;
-	u8 *Kr;
+	const u32 *Km;
+	const u8 *Kr;
 
 	block[0] = be32_to_cpu(src[0]);
 	block[1] = be32_to_cpu(src[1]);
--- linux-ein-5.4.0.orig/crypto/cryptd.c
+++ linux-ein-5.4.0/crypto/cryptd.c
@@ -39,6 +39,10 @@
 };
 
 struct cryptd_queue {
+	/*
+	 * Protected by disabling BH to allow enqueueing from softinterrupt and
+	 * dequeuing from kworker (cryptd_queue_worker()).
+	 */
 	struct cryptd_cpu_queue __percpu *cpu_queue;
 };
 
@@ -125,28 +129,28 @@
 static int cryptd_enqueue_request(struct cryptd_queue *queue,
 				  struct crypto_async_request *request)
 {
-	int cpu, err;
+	int err;
 	struct cryptd_cpu_queue *cpu_queue;
 	refcount_t *refcnt;
 
-	cpu = get_cpu();
+	local_bh_disable();
 	cpu_queue = this_cpu_ptr(queue->cpu_queue);
 	err = crypto_enqueue_request(&cpu_queue->queue, request);
 
 	refcnt = crypto_tfm_ctx(request->tfm);
 
 	if (err == -ENOSPC)
-		goto out_put_cpu;
+		goto out;
 
-	queue_work_on(cpu, cryptd_wq, &cpu_queue->work);
+	queue_work_on(smp_processor_id(), cryptd_wq, &cpu_queue->work);
 
 	if (!refcount_read(refcnt))
-		goto out_put_cpu;
+		goto out;
 
 	refcount_inc(refcnt);
 
-out_put_cpu:
-	put_cpu();
+out:
+	local_bh_enable();
 
 	return err;
 }
@@ -162,15 +166,10 @@
 	cpu_queue = container_of(work, struct cryptd_cpu_queue, work);
 	/*
 	 * Only handle one request at a time to avoid hogging crypto workqueue.
-	 * preempt_disable/enable is used to prevent being preempted by
-	 * cryptd_enqueue_request(). local_bh_disable/enable is used to prevent
-	 * cryptd_enqueue_request() being accessed from software interrupts.
 	 */
 	local_bh_disable();
-	preempt_disable();
 	backlog = crypto_get_backlog(&cpu_queue->queue);
 	req = crypto_dequeue_request(&cpu_queue->queue);
-	preempt_enable();
 	local_bh_enable();
 
 	if (!req)
--- linux-ein-5.4.0.orig/crypto/crypto_user_base.c
+++ linux-ein-5.4.0/crypto/crypto_user_base.c
@@ -213,8 +213,10 @@
 drop_alg:
 	crypto_mod_put(alg);
 
-	if (err)
+	if (err) {
+		kfree_skb(skb);
 		return err;
+	}
 
 	return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 }
--- linux-ein-5.4.0.orig/crypto/crypto_user_stat.c
+++ linux-ein-5.4.0/crypto/crypto_user_stat.c
@@ -328,8 +328,10 @@
 drop_alg:
 	crypto_mod_put(alg);
 
-	if (err)
+	if (err) {
+		kfree_skb(skb);
 		return err;
+	}
 
 	return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 }
--- linux-ein-5.4.0.orig/crypto/drbg.c
+++ linux-ein-5.4.0/crypto/drbg.c
@@ -1035,17 +1035,38 @@
  ******************************************************************/
 
 static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
-			      int reseed)
+			      int reseed, enum drbg_seed_state new_seed_state)
 {
 	int ret = drbg->d_ops->update(drbg, seed, reseed);
 
 	if (ret)
 		return ret;
 
-	drbg->seeded = true;
+	drbg->seeded = new_seed_state;
 	/* 10.1.1.2 / 10.1.1.3 step 5 */
 	drbg->reseed_ctr = 1;
 
+	switch (drbg->seeded) {
+	case DRBG_SEED_STATE_UNSEEDED:
+		/* Impossible, but handle it to silence compiler warnings. */
+		fallthrough;
+	case DRBG_SEED_STATE_PARTIAL:
+		/*
+		 * Require frequent reseeds until the seed source is
+		 * fully initialized.
+		 */
+		drbg->reseed_threshold = 50;
+		break;
+
+	case DRBG_SEED_STATE_FULL:
+		/*
+		 * Seed source has become fully initialized, frequent
+		 * reseeds no longer required.
+		 */
+		drbg->reseed_threshold = drbg_max_requests(drbg);
+		break;
+	}
+
 	return ret;
 }
 
@@ -1065,12 +1086,10 @@
 	return 0;
 }
 
-static void drbg_async_seed(struct work_struct *work)
+static int drbg_seed_from_random(struct drbg_state *drbg)
 {
 	struct drbg_string data;
 	LIST_HEAD(seedlist);
-	struct drbg_state *drbg = container_of(work, struct drbg_state,
-					       seed_work);
 	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
 	unsigned char entropy[32];
 	int ret;
@@ -1081,30 +1100,15 @@
 	drbg_string_fill(&data, entropy, entropylen);
 	list_add_tail(&data.list, &seedlist);
 
-	mutex_lock(&drbg->drbg_mutex);
-
 	ret = drbg_get_random_bytes(drbg, entropy, entropylen);
 	if (ret)
-		goto unlock;
+		goto out;
 
-	/* If nonblocking pool is initialized, deactivate Jitter RNG */
-	crypto_free_rng(drbg->jent);
-	drbg->jent = NULL;
-
-	/* Set seeded to false so that if __drbg_seed fails the
-	 * next generate call will trigger a reseed.
-	 */
-	drbg->seeded = false;
-
-	__drbg_seed(drbg, &seedlist, true);
-
-	if (drbg->seeded)
-		drbg->reseed_threshold = drbg_max_requests(drbg);
-
-unlock:
-	mutex_unlock(&drbg->drbg_mutex);
+	ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL);
 
+out:
 	memzero_explicit(entropy, entropylen);
+	return ret;
 }
 
 /*
@@ -1126,6 +1130,7 @@
 	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
 	struct drbg_string data1;
 	LIST_HEAD(seedlist);
+	enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL;
 
 	/* 9.1 / 9.2 / 9.3.1 step 3 */
 	if (pers && pers->len > (drbg_max_addtl(drbg))) {
@@ -1153,6 +1158,9 @@
 		BUG_ON((entropylen * 2) > sizeof(entropy));
 
 		/* Get seed from in-kernel /dev/urandom */
+		if (!rng_is_initialized())
+			new_seed_state = DRBG_SEED_STATE_PARTIAL;
+
 		ret = drbg_get_random_bytes(drbg, entropy, entropylen);
 		if (ret)
 			goto out;
@@ -1168,7 +1176,23 @@
 						   entropylen);
 			if (ret) {
 				pr_devel("DRBG: jent failed with %d\n", ret);
-				goto out;
+
+				/*
+				 * Do not treat the transient failure of the
+				 * Jitter RNG as an error that needs to be
+				 * reported. The combined number of the
+				 * maximum reseed threshold times the maximum
+				 * number of Jitter RNG transient errors is
+				 * less than the reseed threshold required by
+				 * SP800-90A allowing us to treat the
+				 * transient errors as such.
+				 *
+				 * However, we mandate that at least the first
+				 * seeding operation must succeed with the
+				 * Jitter RNG.
+				 */
+				if (!reseed || ret != -EAGAIN)
+					goto out;
 			}
 
 			drbg_string_fill(&data1, entropy, entropylen * 2);
@@ -1193,7 +1217,7 @@
 		memset(drbg->C, 0, drbg_statelen(drbg));
 	}
 
-	ret = __drbg_seed(drbg, &seedlist, reseed);
+	ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state);
 
 out:
 	memzero_explicit(entropy, entropylen * 2);
@@ -1294,8 +1318,10 @@
 	if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
 		drbg->prev = kzalloc(drbg_sec_strength(drbg->core->flags),
 				     GFP_KERNEL);
-		if (!drbg->prev)
+		if (!drbg->prev) {
+			ret = -ENOMEM;
 			goto fini;
+		}
 		drbg->fips_primed = false;
 	}
 
@@ -1371,19 +1397,25 @@
 	 * here. The spec is a bit convoluted here, we make it simpler.
 	 */
 	if (drbg->reseed_threshold < drbg->reseed_ctr)
-		drbg->seeded = false;
+		drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
 
-	if (drbg->pr || !drbg->seeded) {
+	if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) {
 		pr_devel("DRBG: reseeding before generation (prediction "
 			 "resistance: %s, state %s)\n",
 			 drbg->pr ? "true" : "false",
-			 drbg->seeded ? "seeded" : "unseeded");
+			 (drbg->seeded ==  DRBG_SEED_STATE_FULL ?
+			  "seeded" : "unseeded"));
 		/* 9.3.1 steps 7.1 through 7.3 */
 		len = drbg_seed(drbg, addtl, true);
 		if (len)
 			goto err;
 		/* 9.3.1 step 7.4 */
 		addtl = NULL;
+	} else if (rng_is_initialized() &&
+		   drbg->seeded == DRBG_SEED_STATE_PARTIAL) {
+		len = drbg_seed_from_random(drbg);
+		if (len)
+			goto err;
 	}
 
 	if (addtl && 0 < addtl->len)
@@ -1476,51 +1508,23 @@
 	return 0;
 }
 
-static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
-{
-	struct drbg_state *drbg = container_of(rdy, struct drbg_state,
-					       random_ready);
-
-	schedule_work(&drbg->seed_work);
-}
-
 static int drbg_prepare_hrng(struct drbg_state *drbg)
 {
-	int err;
-
 	/* We do not need an HRNG in test mode. */
 	if (list_empty(&drbg->test_data.list))
 		return 0;
 
-	INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
-	drbg->random_ready.owner = THIS_MODULE;
-	drbg->random_ready.func = drbg_schedule_async_seed;
-
-	err = add_random_ready_callback(&drbg->random_ready);
-
-	switch (err) {
-	case 0:
-		break;
-
-	case -EALREADY:
-		err = 0;
-		/* fall through */
-
-	default:
-		drbg->random_ready.func = NULL;
-		return err;
-	}
-
 	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+	if (IS_ERR(drbg->jent)) {
+		const int err = PTR_ERR(drbg->jent);
 
-	/*
-	 * Require frequent reseeds until the seed source is fully
-	 * initialized.
-	 */
-	drbg->reseed_threshold = 50;
+		drbg->jent = NULL;
+		if (fips_enabled)
+			return err;
+		pr_info("DRBG: Continuing without Jitter RNG\n");
+	}
 
-	return err;
+	return 0;
 }
 
 /*
@@ -1563,7 +1567,7 @@
 	if (!drbg->core) {
 		drbg->core = &drbg_cores[coreref];
 		drbg->pr = pr;
-		drbg->seeded = false;
+		drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
 		drbg->reseed_threshold = drbg_max_requests(drbg);
 
 		ret = drbg_alloc_state(drbg);
@@ -1574,14 +1578,6 @@
 		if (ret)
 			goto free_everything;
 
-		if (IS_ERR(drbg->jent)) {
-			ret = PTR_ERR(drbg->jent);
-			drbg->jent = NULL;
-			if (fips_enabled || ret != -ENOENT)
-				goto free_everything;
-			pr_info("DRBG: Continuing without Jitter RNG\n");
-		}
-
 		reseed = false;
 	}
 
@@ -1614,12 +1610,9 @@
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-	if (drbg->random_ready.func) {
-		del_random_ready_callback(&drbg->random_ready);
-		cancel_work_sync(&drbg->seed_work);
+	if (!IS_ERR_OR_NULL(drbg->jent))
 		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
+	drbg->jent = NULL;
 
 	if (drbg->d_ops)
 		drbg->d_ops->crypto_fini(drbg);
--- linux-ein-5.4.0.orig/crypto/ecc.c
+++ linux-ein-5.4.0/crypto/ecc.c
@@ -1284,10 +1284,11 @@
 static inline void ecc_swap_digits(const u64 *in, u64 *out,
 				   unsigned int ndigits)
 {
+	const __be64 *src = (__force __be64 *)in;
 	int i;
 
 	for (i = 0; i < ndigits; i++)
-		out[i] = __swab64(in[ndigits - 1 - i]);
+		out[i] = be64_to_cpu(src[ndigits - 1 - i]);
 }
 
 static int __ecc_is_key_valid(const struct ecc_curve *curve,
--- linux-ein-5.4.0.orig/crypto/ecdh.c
+++ linux-ein-5.4.0/crypto/ecdh.c
@@ -39,7 +39,8 @@
 	struct ecdh params;
 	unsigned int ndigits;
 
-	if (crypto_ecdh_decode_key(buf, len, &params) < 0)
+	if (crypto_ecdh_decode_key(buf, len, &params) < 0 ||
+	    params.key_size > sizeof(ctx->private_key))
 		return -EINVAL;
 
 	ndigits = ecdh_supported_curve(params.curve_id);
@@ -53,12 +54,13 @@
 		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);
 
+	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
+			     ctx->private_key, params.key_size) < 0) {
+		memzero_explicit(ctx->private_key, params.key_size);
+		return -EINVAL;
+	}
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/crypto/ecdh_helper.c
+++ linux-ein-5.4.0/crypto/ecdh_helper.c
@@ -67,6 +67,9 @@
 	if (secret.type != CRYPTO_KPP_SECRET_TYPE_ECDH)
 		return -EINVAL;
 
+	if (unlikely(len < secret.len))
+		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))
--- linux-ein-5.4.0.orig/crypto/ecrdsa.c
+++ linux-ein-5.4.0/crypto/ecrdsa.c
@@ -112,15 +112,15 @@
 
 	/* Step 1: verify that 0 < r < q, 0 < s < q */
 	if (vli_is_zero(r, ndigits) ||
-	    vli_cmp(r, ctx->curve->n, ndigits) == 1 ||
+	    vli_cmp(r, ctx->curve->n, ndigits) >= 0 ||
 	    vli_is_zero(s, ndigits) ||
-	    vli_cmp(s, ctx->curve->n, ndigits) == 1)
+	    vli_cmp(s, ctx->curve->n, ndigits) >= 0)
 		return -EKEYREJECTED;
 
 	/* Step 2: calculate hash (h) of the message (passed as input) */
 	/* Step 3: calculate e = h \mod q */
 	vli_from_le64(e, digest, ndigits);
-	if (vli_cmp(e, ctx->curve->n, ndigits) == 1)
+	if (vli_cmp(e, ctx->curve->n, ndigits) >= 0)
 		vli_sub(e, e, ctx->curve->n, ndigits);
 	if (vli_is_zero(e, ndigits))
 		e[0] = 1;
@@ -136,7 +136,7 @@
 	/* Step 6: calculate point C = z_1P + z_2Q, and R = x_c \mod q */
 	ecc_point_mult_shamir(&cc, z1, &ctx->curve->g, z2, &ctx->pub_key,
 			      ctx->curve);
-	if (vli_cmp(cc.x, ctx->curve->n, ndigits) == 1)
+	if (vli_cmp(cc.x, ctx->curve->n, ndigits) >= 0)
 		vli_sub(cc.x, cc.x, ctx->curve->n, ndigits);
 
 	/* Step 7: if R == r signature is valid */
--- linux-ein-5.4.0.orig/crypto/essiv.c
+++ linux-ein-5.4.0/crypto/essiv.c
@@ -188,8 +188,12 @@
 	struct aead_request *req = areq->data;
 	struct essiv_aead_request_ctx *rctx = aead_request_ctx(req);
 
-	if (rctx->assoc)
-		kfree(rctx->assoc);
+	if (err == -EINPROGRESS)
+		goto out;
+
+	kfree(rctx->assoc);
+
+out:
 	aead_request_complete(req, err);
 }
 
@@ -265,7 +269,7 @@
 	err = enc ? crypto_aead_encrypt(subreq) :
 		    crypto_aead_decrypt(subreq);
 
-	if (rctx->assoc && err != -EINPROGRESS)
+	if (rctx->assoc && err != -EINPROGRESS && err != -EBUSY)
 		kfree(rctx->assoc);
 	return err;
 }
--- linux-ein-5.4.0.orig/crypto/hash_info.c
+++ linux-ein-5.4.0/crypto/hash_info.c
@@ -26,7 +26,7 @@
 	[HASH_ALGO_TGR_128]	= "tgr128",
 	[HASH_ALGO_TGR_160]	= "tgr160",
 	[HASH_ALGO_TGR_192]	= "tgr192",
-	[HASH_ALGO_SM3_256]	= "sm3-256",
+	[HASH_ALGO_SM3_256]	= "sm3",
 	[HASH_ALGO_STREEBOG_256] = "streebog256",
 	[HASH_ALGO_STREEBOG_512] = "streebog512",
 };
--- linux-ein-5.4.0.orig/crypto/internal.h
+++ linux-ein-5.4.0/crypto/internal.h
@@ -68,7 +68,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-ein-5.4.0.orig/crypto/lrw.c
+++ linux-ein-5.4.0/crypto/lrw.c
@@ -289,7 +289,7 @@
 	crypto_free_skcipher(ctx->child);
 }
 
-static void free(struct skcipher_instance *inst)
+static void free_inst(struct skcipher_instance *inst)
 {
 	crypto_drop_skcipher(skcipher_instance_ctx(inst));
 	kfree(inst);
@@ -401,7 +401,7 @@
 	inst->alg.encrypt = encrypt;
 	inst->alg.decrypt = decrypt;
 
-	inst->free = free;
+	inst->free = free_inst;
 
 	err = skcipher_register_instance(tmpl, inst);
 	if (err)
--- linux-ein-5.4.0.orig/crypto/pcrypt.c
+++ linux-ein-5.4.0/crypto/pcrypt.c
@@ -24,6 +24,8 @@
 
 struct pcrypt_instance_ctx {
 	struct crypto_aead_spawn spawn;
+	struct padata_shell *psenc;
+	struct padata_shell *psdec;
 	atomic_t tfm_count;
 };
 
@@ -32,6 +34,12 @@
 	unsigned int cb_cpu;
 };
 
+static inline struct pcrypt_instance_ctx *pcrypt_tfm_ictx(
+	struct crypto_aead *tfm)
+{
+	return aead_instance_ctx(aead_alg_instance(tfm));
+}
+
 static int pcrypt_aead_setkey(struct crypto_aead *parent,
 			      const u8 *key, unsigned int keylen)
 {
@@ -63,7 +71,6 @@
 	struct padata_priv *padata = pcrypt_request_padata(preq);
 
 	padata->info = err;
-	req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	padata_do_serial(padata);
 }
@@ -72,12 +79,14 @@
 {
 	struct pcrypt_request *preq = pcrypt_padata_request(padata);
 	struct aead_request *req = pcrypt_request_ctx(preq);
+	int ret;
 
-	padata->info = crypto_aead_encrypt(req);
+	ret = crypto_aead_encrypt(req);
 
-	if (padata->info == -EINPROGRESS)
+	if (ret == -EINPROGRESS)
 		return;
 
+	padata->info = ret;
 	padata_do_serial(padata);
 }
 
@@ -90,6 +99,9 @@
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead);
 	u32 flags = aead_request_flags(req);
+	struct pcrypt_instance_ctx *ictx;
+
+	ictx = pcrypt_tfm_ictx(aead);
 
 	memset(padata, 0, sizeof(struct padata_priv));
 
@@ -103,9 +115,11 @@
 			       req->cryptlen, req->iv);
 	aead_request_set_ad(creq, req->assoclen);
 
-	err = padata_do_parallel(pencrypt, padata, &ctx->cb_cpu);
+	err = padata_do_parallel(ictx->psenc, padata, &ctx->cb_cpu);
 	if (!err)
 		return -EINPROGRESS;
+	if (err == -EBUSY)
+		return -EAGAIN;
 
 	return err;
 }
@@ -114,12 +128,14 @@
 {
 	struct pcrypt_request *preq = pcrypt_padata_request(padata);
 	struct aead_request *req = pcrypt_request_ctx(preq);
+	int ret;
 
-	padata->info = crypto_aead_decrypt(req);
+	ret = crypto_aead_decrypt(req);
 
-	if (padata->info == -EINPROGRESS)
+	if (ret == -EINPROGRESS)
 		return;
 
+	padata->info = ret;
 	padata_do_serial(padata);
 }
 
@@ -132,6 +148,9 @@
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
 	struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead);
 	u32 flags = aead_request_flags(req);
+	struct pcrypt_instance_ctx *ictx;
+
+	ictx = pcrypt_tfm_ictx(aead);
 
 	memset(padata, 0, sizeof(struct padata_priv));
 
@@ -145,9 +164,11 @@
 			       req->cryptlen, req->iv);
 	aead_request_set_ad(creq, req->assoclen);
 
-	err = padata_do_parallel(pdecrypt, padata, &ctx->cb_cpu);
+	err = padata_do_parallel(ictx->psdec, padata, &ctx->cb_cpu);
 	if (!err)
 		return -EINPROGRESS;
+	if (err == -EBUSY)
+		return -EAGAIN;
 
 	return err;
 }
@@ -192,6 +213,8 @@
 	struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst);
 
 	crypto_drop_aead(&ctx->spawn);
+	padata_free_shell(ctx->psdec);
+	padata_free_shell(ctx->psenc);
 	kfree(inst);
 }
 
@@ -233,12 +256,22 @@
 	if (!inst)
 		return -ENOMEM;
 
+	err = -ENOMEM;
+
 	ctx = aead_instance_ctx(inst);
+	ctx->psenc = padata_alloc_shell(pencrypt);
+	if (!ctx->psenc)
+		goto out_free_inst;
+
+	ctx->psdec = padata_alloc_shell(pdecrypt);
+	if (!ctx->psdec)
+		goto out_free_psenc;
+
 	crypto_set_aead_spawn(&ctx->spawn, aead_crypto_instance(inst));
 
 	err = crypto_grab_aead(&ctx->spawn, name, 0, 0);
 	if (err)
-		goto out_free_inst;
+		goto out_free_psdec;
 
 	alg = crypto_spawn_aead_alg(&ctx->spawn);
 	err = pcrypt_init_instance(aead_crypto_instance(inst), &alg->base);
@@ -271,6 +304,10 @@
 
 out_drop_aead:
 	crypto_drop_aead(&ctx->spawn);
+out_free_psdec:
+	padata_free_shell(ctx->psdec);
+out_free_psenc:
+	padata_free_shell(ctx->psenc);
 out_free_inst:
 	kfree(inst);
 	goto out;
@@ -362,11 +399,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);
 }
 
 subsys_initcall(pcrypt_init);
--- linux-ein-5.4.0.orig/crypto/rng.c
+++ linux-ein-5.4.0/crypto/rng.c
@@ -34,7 +34,6 @@
 	u8 *buf = NULL;
 	int err;
 
-	crypto_stats_get(alg);
 	if (!seed && slen) {
 		buf = kmalloc(slen, GFP_KERNEL);
 		if (!buf)
@@ -46,6 +45,7 @@
 		seed = buf;
 	}
 
+	crypto_stats_get(alg);
 	err = crypto_rng_alg(tfm)->seed(tfm, seed, slen);
 	crypto_stats_rng_seed(alg, err);
 out:
--- linux-ein-5.4.0.orig/crypto/rsa-pkcs1pad.c
+++ linux-ein-5.4.0/crypto/rsa-pkcs1pad.c
@@ -213,16 +213,14 @@
 		struct crypto_async_request *child_async_req, int err)
 {
 	struct akcipher_request *req = child_async_req->data;
-	struct crypto_async_request async_req;
 
 	if (err == -EINPROGRESS)
-		return;
+		goto out;
 
-	async_req.data = req->base.data;
-	async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req));
-	async_req.flags = child_async_req->flags;
-	req->base.complete(&async_req,
-			pkcs1pad_encrypt_sign_complete(req, err));
+	err = pkcs1pad_encrypt_sign_complete(req, err);
+
+out:
+	akcipher_request_complete(req, err);
 }
 
 static int pkcs1pad_encrypt(struct akcipher_request *req)
@@ -331,15 +329,14 @@
 		struct crypto_async_request *child_async_req, int err)
 {
 	struct akcipher_request *req = child_async_req->data;
-	struct crypto_async_request async_req;
 
 	if (err == -EINPROGRESS)
-		return;
+		goto out;
+
+	err = pkcs1pad_decrypt_complete(req, err);
 
-	async_req.data = req->base.data;
-	async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req));
-	async_req.flags = child_async_req->flags;
-	req->base.complete(&async_req, pkcs1pad_decrypt_complete(req, err));
+out:
+	akcipher_request_complete(req, err);
 }
 
 static int pkcs1pad_decrypt(struct akcipher_request *req)
@@ -475,6 +472,8 @@
 	pos++;
 
 	if (digest_info) {
+		if (digest_info->size > dst_len - pos)
+			goto done;
 		if (crypto_memneq(out_buf + pos, digest_info->data,
 				  digest_info->size))
 			goto done;
@@ -494,7 +493,7 @@
 			   sg_nents_for_len(req->src,
 					    req->src_len + req->dst_len),
 			   req_ctx->out_buf + ctx->key_size,
-			   req->dst_len, ctx->key_size);
+			   req->dst_len, req->src_len);
 	/* Do the actual verification step. */
 	if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
 		   req->dst_len) != 0)
@@ -509,15 +508,14 @@
 		struct crypto_async_request *child_async_req, int err)
 {
 	struct akcipher_request *req = child_async_req->data;
-	struct crypto_async_request async_req;
 
 	if (err == -EINPROGRESS)
-		return;
+		goto out;
+
+	err = pkcs1pad_verify_complete(req, err);
 
-	async_req.data = req->base.data;
-	async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req));
-	async_req.flags = child_async_req->flags;
-	req->base.complete(&async_req, pkcs1pad_verify_complete(req, err));
+out:
+	akcipher_request_complete(req, err);
 }
 
 /*
@@ -537,7 +535,7 @@
 
 	if (WARN_ON(req->dst) ||
 	    WARN_ON(!req->dst_len) ||
-	    !ctx->key_size || req->src_len < ctx->key_size)
+	    !ctx->key_size || req->src_len != ctx->key_size)
 		return -EINVAL;
 
 	req_ctx->out_buf = kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL);
--- linux-ein-5.4.0.orig/crypto/scompress.c
+++ linux-ein-5.4.0/crypto/scompress.c
@@ -124,6 +124,7 @@
 	struct crypto_scomp *scomp = *tfm_ctx;
 	void **ctx = acomp_request_ctx(req);
 	struct scomp_scratch *scratch;
+	unsigned int dlen;
 	int ret;
 
 	if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE)
@@ -135,6 +136,8 @@
 	if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE)
 		req->dlen = SCOMP_SCRATCH_SIZE;
 
+	dlen = req->dlen;
+
 	scratch = raw_cpu_ptr(&scomp_scratch);
 	spin_lock(&scratch->lock);
 
@@ -152,6 +155,9 @@
 				ret = -ENOMEM;
 				goto out;
 			}
+		} else if (req->dlen > dlen) {
+			ret = -ENOSPC;
+			goto out;
 		}
 		scatterwalk_map_and_copy(scratch->dst, req->dst, 0, req->dlen,
 					 1);
--- linux-ein-5.4.0.orig/crypto/seqiv.c
+++ linux-ein-5.4.0/crypto/seqiv.c
@@ -25,7 +25,7 @@
 	struct aead_request *subreq = aead_request_ctx(req);
 	struct crypto_aead *geniv;
 
-	if (err == -EINPROGRESS)
+	if (err == -EINPROGRESS || err == -EBUSY)
 		return;
 
 	if (err)
--- linux-ein-5.4.0.orig/crypto/serpent_generic.c
+++ linux-ein-5.4.0/crypto/serpent_generic.c
@@ -449,8 +449,9 @@
 }
 EXPORT_SYMBOL_GPL(serpent_setkey);
 
-void __serpent_encrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src)
+void __serpent_encrypt(const void *c, u8 *dst, const u8 *src)
 {
+	const struct serpent_ctx *ctx = c;
 	const u32 *k = ctx->expkey;
 	const __le32 *s = (const __le32 *)src;
 	__le32	*d = (__le32 *)dst;
@@ -514,8 +515,9 @@
 	__serpent_encrypt(ctx, dst, src);
 }
 
-void __serpent_decrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src)
+void __serpent_decrypt(const void *c, u8 *dst, const u8 *src)
 {
+	const struct serpent_ctx *ctx = c;
 	const u32 *k = ctx->expkey;
 	const __le32 *s = (const __le32 *)src;
 	__le32	*d = (__le32 *)dst;
--- linux-ein-5.4.0.orig/crypto/shash.c
+++ linux-ein-5.4.0/crypto/shash.c
@@ -20,12 +20,24 @@
 
 static const struct crypto_type crypto_shash_type;
 
-int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-		    unsigned int keylen)
+static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+			   unsigned int keylen)
 {
 	return -ENOSYS;
 }
-EXPORT_SYMBOL_GPL(shash_no_setkey);
+
+/*
+ * Check whether an shash algorithm has a setkey function.
+ *
+ * For CFI compatibility, this must not be an inline function.  This is because
+ * when CFI is enabled, modules won't get the same address for shash_no_setkey
+ * (if it were exported, which inlining would require) as the core kernel will.
+ */
+bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+	return alg->setkey != shash_no_setkey;
+}
+EXPORT_SYMBOL_GPL(crypto_shash_alg_has_setkey);
 
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
 				  unsigned int keylen)
--- linux-ein-5.4.0.orig/crypto/tcrypt.c
+++ linux-ein-5.4.0/crypto/tcrypt.c
@@ -198,8 +198,8 @@
 			goto out;
 	}
 
-	pr_cont("%d operations in %d seconds (%ld bytes)\n",
-		bcount * num_mb, secs, (long)bcount * blen * num_mb);
+	pr_cont("%d operations in %d seconds (%llu bytes)\n",
+		bcount * num_mb, secs, (u64)bcount * blen * num_mb);
 
 out:
 	kfree(rc);
@@ -468,8 +468,8 @@
 			return ret;
 	}
 
-	printk("%d operations in %d seconds (%ld bytes)\n",
-	       bcount, secs, (long)bcount * blen);
+	pr_cont("%d operations in %d seconds (%llu bytes)\n",
+	        bcount, secs, (u64)bcount * blen);
 	return 0;
 }
 
@@ -759,8 +759,8 @@
 			goto out;
 	}
 
-	pr_cont("%d operations in %d seconds (%ld bytes)\n",
-		bcount * num_mb, secs, (long)bcount * blen * num_mb);
+	pr_cont("%d operations in %d seconds (%llu bytes)\n",
+		bcount * num_mb, secs, (u64)bcount * blen * num_mb);
 
 out:
 	kfree(rc);
@@ -1196,8 +1196,8 @@
 			goto out;
 	}
 
-	pr_cont("%d operations in %d seconds (%ld bytes)\n",
-		bcount * num_mb, secs, (long)bcount * blen * num_mb);
+	pr_cont("%d operations in %d seconds (%llu bytes)\n",
+		bcount * num_mb, secs, (u64)bcount * blen * num_mb);
 
 out:
 	kfree(rc);
@@ -1281,15 +1281,6 @@
 			goto out_free_tfm;
 		}
 
-
-	for (i = 0; i < num_mb; ++i)
-		if (testmgr_alloc_buf(data[i].xbuf)) {
-			while (i--)
-				testmgr_free_buf(data[i].xbuf);
-			goto out_free_tfm;
-		}
-
-
 	for (i = 0; i < num_mb; ++i) {
 		data[i].req = skcipher_request_alloc(tfm, GFP_KERNEL);
 		if (!data[i].req) {
@@ -1434,8 +1425,8 @@
 			return ret;
 	}
 
-	pr_cont("%d operations in %d seconds (%ld bytes)\n",
-		bcount, secs, (long)bcount * blen);
+	pr_cont("%d operations in %d seconds (%llu bytes)\n",
+		bcount, secs, (u64)bcount * blen);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/crypto/testmgr.c
+++ linux-ein-5.4.0/crypto/testmgr.c
@@ -2102,6 +2102,7 @@
 	 * If the key or authentication tag size couldn't be set, no need to
 	 * continue to encrypt.
 	 */
+	vec->crypt_error = 0;
 	if (vec->setkey_error || vec->setauthsize_error)
 		goto done;
 
@@ -2245,10 +2246,12 @@
 					req, tsgls);
 		if (err)
 			goto out;
-		err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name, cfg,
-					req, tsgls);
-		if (err)
-			goto out;
+		if (vec.crypt_error == 0) {
+			err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name,
+						cfg, req, tsgls);
+			if (err)
+				goto out;
+		}
 		cond_resched();
 	}
 	err = 0;
@@ -2678,6 +2681,15 @@
 	skcipher_request_set_callback(req, 0, crypto_req_done, &wait);
 	skcipher_request_set_crypt(req, &src, &dst, vec->len, iv);
 	vec->crypt_error = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
+	if (vec->crypt_error != 0) {
+		/*
+		 * The only acceptable error here is for an invalid length, so
+		 * skcipher decryption should fail with the same error too.
+		 * We'll test for this.  But to keep the API usage well-defined,
+		 * explicitly initialize the ciphertext buffer too.
+		 */
+		memset((u8 *)vec->ctext, 0, vec->len);
+	}
 done:
 	snprintf(name, max_namelen, "\"random: len=%u klen=%u\"",
 		 vec->len, vec->klen);
@@ -4104,6 +4116,15 @@
 			.cipher = __VECS(tf_cbc_tv_template)
 		},
 	}, {
+#if IS_ENABLED(CONFIG_CRYPTO_PAES_S390)
+		.alg = "cbc-paes-s390",
+		.fips_allowed = 1,
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = __VECS(aes_cbc_tv_template)
+		}
+	}, {
+#endif
 		.alg = "cbcmac(aes)",
 		.fips_allowed = 1,
 		.test = alg_test_hash,
@@ -4246,6 +4267,15 @@
 			.cipher = __VECS(tf_ctr_tv_template)
 		}
 	}, {
+#if IS_ENABLED(CONFIG_CRYPTO_PAES_S390)
+		.alg = "ctr-paes-s390",
+		.fips_allowed = 1,
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = __VECS(aes_ctr_tv_template)
+		}
+	}, {
+#endif
 		.alg = "cts(cbc(aes))",
 		.test = alg_test_skcipher,
 		.fips_allowed = 1,
@@ -4532,6 +4562,15 @@
 			.cipher = __VECS(xtea_tv_template)
 		}
 	}, {
+#if IS_ENABLED(CONFIG_CRYPTO_PAES_S390)
+		.alg = "ecb-paes-s390",
+		.fips_allowed = 1,
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = __VECS(aes_tv_template)
+		}
+	}, {
+#endif
 		.alg = "ecdh",
 		.test = alg_test_kpp,
 		.fips_allowed = 1,
@@ -5085,6 +5124,15 @@
 			.cipher = __VECS(tf_xts_tv_template)
 		}
 	}, {
+#if IS_ENABLED(CONFIG_CRYPTO_PAES_S390)
+		.alg = "xts-paes-s390",
+		.fips_allowed = 1,
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = __VECS(aes_xts_tv_template)
+		}
+	}, {
+#endif
 		.alg = "xts4096(paes)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
--- linux-ein-5.4.0.orig/crypto/xts.c
+++ linux-ein-5.4.0/crypto/xts.c
@@ -328,7 +328,7 @@
 	crypto_free_cipher(ctx->tweak);
 }
 
-static void free(struct skcipher_instance *inst)
+static void free_inst(struct skcipher_instance *inst)
 {
 	crypto_drop_skcipher(skcipher_instance_ctx(inst));
 	kfree(inst);
@@ -439,7 +439,7 @@
 	inst->alg.encrypt = encrypt;
 	inst->alg.decrypt = decrypt;
 
-	inst->free = free;
+	inst->free = free_inst;
 
 	err = skcipher_register_instance(tmpl, inst);
 	if (err)
--- linux-ein-5.4.0.orig/debian.ein/changelog
+++ linux-ein-5.4.0/debian.ein/changelog
@@ -0,0 +1,19272 @@
+linux-ein (5.4.0-1056.64) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1056.64 -proposed tracker (LP: #2068265)
+
+  [ Ubuntu: 5.4.0-187.207 ]
+
+  * focal/linux: 5.4.0-187.207 -proposed tracker (LP: #2068291)
+  * CVE-2024-26925
+    - netfilter: Cleanup nft_net->module_list from nf_tables_exit_net()
+    - netfilter: nf_tables: release batch on table validation from abort path
+    - netfilter: nf_tables: release mutex after nft_gc_seq_end from abort path
+  * CVE-2024-26643
+    - netfilter: nf_tables: mark set as dead when unbinding anonymous set with
+      timeout
+  * 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|ON|OFF}
+    - 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
+
+ -- Aaron Jauregui <aaron.jauregui@canonical.com>  Thu, 20 Jun 2024 16:15:48 +1000
+
+linux-ein (5.4.0-1055.63) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1055.63 -proposed tracker (LP: #2063785)
+
+  [ Ubuntu: 5.4.0-186.206 ]
+
+  * focal/linux: 5.4.0-186.206 -proposed tracker (LP: #2063812)
+  * Mount CIFS fails with Permission denied (LP: #2061986)
+    - cifs: fix ntlmssp auth when there is no key exchange
+  * USB stick can't be detected (LP: #2040948)
+    - usb: Disable USB3 LPM at shutdown
+  * CVE-2024-26733
+    - net: dev: Convert sa_data to flexible array in struct sockaddr
+    - arp: Prevent overflow in arp_req_get().
+    - stddef: Introduce DECLARE_FLEX_ARRAY() helper
+  * CVE-2024-26712
+    - powerpc/kasan: Fix addr error caused by page alignment
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+  * CVE-2021-47063
+    - drm: bridge/panel: Cleanup connector on bridge detach
+  * [Ubuntu 22.04.4/linux-image-6.5.0-26-generic] Kernel output "UBSAN: array-
+    index-out-of-bounds in /build/linux-hwe-6.5-34pCLi/linux-
+    hwe-6.5-6.5.0/drivers/net/hyperv/netvsc.c:1445:41" multiple times,
+    especially during boot. (LP: #2058477)
+    - hv: hyperv.h: Replace one-element array with flexible-array member
+  * CVE-2024-26614
+    - tcp: make sure init the accept_queue's spinlocks once
+    - ipv6: init the accept_queue's spinlocks in inet6_create
+  * Focal update: v5.4.271 upstream stable release (LP: #2060216)
+    - netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+    - net: ip_tunnel: prevent perpetual headroom growth
+    - tun: Fix xdp_rxq_info's queue_index when detaching
+    - ipv6: fix potential "struct net" leak in inet6_rtm_getaddr()
+    - lan78xx: enable auto speed configuration for LAN7850 if no EEPROM is
+      detected
+    - net: usb: dm9601: fix wrong return value in dm9601_mdio_read
+    - Bluetooth: Avoid potential use-after-free in hci_error_reset
+    - Bluetooth: hci_event: Fix handling of HCI_EV_IO_CAPA_REQUEST
+    - Bluetooth: Enforce validation on max value of connection interval
+    - netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
+    - rtnetlink: fix error logic of IFLA_BRIDGE_FLAGS writing back
+    - efi/capsule-loader: fix incorrect allocation size
+    - power: supply: bq27xxx-i2c: Do not free non existing IRQ
+    - ALSA: Drop leftover snd-rtctimer stuff from Makefile
+    - afs: Fix endless loop in directory parsing
+    - gtp: fix use-after-free and null-ptr-deref in gtp_newlink()
+    - wifi: nl80211: reject iftype change with mesh ID change
+    - btrfs: dev-replace: properly validate device names
+    - dmaengine: fsl-qdma: fix SoC may hang on 16 byte unaligned read
+    - dmaengine: fsl-qdma: init irq after reg initialization
+    - mmc: core: Fix eMMC initialization with 1-bit bus connection
+    - x86/cpu/intel: Detect TME keyid bits before setting MTRR mask registers
+    - cachefiles: fix memory leak in cachefiles_add_cache()
+    - fs,hugetlb: fix NULL pointer dereference in hugetlbs_fill_super
+    - gpio: 74x164: Enable output pins after registers are reset
+    - Linux 5.4.271
+  * Focal update: v5.4.270 upstream stable release (LP: #2060019)
+    - KVM: arm64: vgic-its: Test for valid IRQ in its_sync_lpi_pending_table()
+    - KVM: arm64: vgic-its: Test for valid IRQ in MOVALL handler
+    - net/sched: Retire CBQ qdisc
+    - [Config] updateconfigs for NET_SCH_CBQ
+    - net/sched: Retire ATM qdisc
+    - [Config] updateconfigs for NET_SCH_ATM
+    - net/sched: Retire dsmark qdisc
+    - [Config] updateconfigs for NET_SCH_DSMARK
+    - sched/rt: sysctl_sched_rr_timeslice show default timeslice after reset
+    - memcg: add refcnt for pcpu stock to avoid UAF problem in drain_all_stock()
+    - nilfs2: replace WARN_ONs for invalid DAT metadata block requests
+    - userfaultfd: fix mmap_changing checking in mfill_atomic_hugetlb
+    - sched/rt: Fix sysctl_sched_rr_timeslice intial value
+    - sched/rt: Disallow writing invalid values to sched_rt_period_us
+    - scsi: target: core: Add TMF to tmr_list handling
+    - dmaengine: shdma: increase size of 'dev_id'
+    - dmaengine: fsl-qdma: increase size of 'irq_name'
+    - wifi: cfg80211: fix missing interfaces when dumping
+    - wifi: mac80211: fix race condition on enabling fast-xmit
+    - fbdev: savage: Error out if pixclock equals zero
+    - fbdev: sis: Error out if pixclock equals zero
+    - ahci: asm1166: correct count of reported ports
+    - ahci: add 43-bit DMA address quirk for ASMedia ASM1061 controllers
+    - ext4: avoid allocating blocks from corrupted group in
+      ext4_mb_try_best_found()
+    - ext4: avoid allocating blocks from corrupted group in ext4_mb_find_by_goal()
+    - regulator: pwm-regulator: Add validity checks in continuous .get_voltage
+    - nvmet-tcp: fix nvme tcp ida memory leak
+    - ASoC: sunxi: sun4i-spdif: Add support for Allwinner H616
+    - netfilter: conntrack: check SCTP_CID_SHUTDOWN_ACK for vtag setting in
+      sctp_new
+    - nvmet-fc: abort command when there is no binding
+    - hwmon: (coretemp) Enlarge per package core count limit
+    - scsi: lpfc: Use unsigned type for num_sge
+    - firewire: core: send bus reset promptly on gap count error
+    - virtio-blk: Ensure no requests in virtqueues before deleting vqs.
+    - s390/qeth: Fix potential loss of L3-IP@ in case of network issues
+    - pmdomain: renesas: r8a77980-sysc: CR7 must be always on
+    - tcp: factor out __tcp_close() helper
+    - tcp: return EPOLLOUT from tcp_poll only when notsent_bytes is half the limit
+    - tcp: add annotations around sk->sk_shutdown accesses
+    - pinctrl: pinctrl-rockchip: Fix a bunch of kerneldoc misdemeanours
+    - pinctrl: rockchip: Fix refcount leak in rockchip_pinctrl_parse_groups
+    - spi: mt7621: Fix an error message in mt7621_spi_probe()
+    - net: bridge: clear bridge's private skb space on xmit
+    - selftests/bpf: Avoid running unprivileged tests with alignment requirements
+    - Revert "drm/sun4i: dsi: Change the start delay calculation"
+    - drm/amdgpu: Check for valid number of registers to read
+    - x86/alternatives: Disable KASAN in apply_alternatives()
+    - dm-integrity: don't modify bio's immutable bio_vec in integrity_metadata()
+    - iomap: Set all uptodate bits for an Uptodate page
+    - drm/amdgpu: Fix type of second parameter in trans_msg() callback
+    - arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node
+    - PCI: tegra: Fix reporting GPIO error value
+    - PCI: tegra: Fix OF node reference leak
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one error
+    - dm-crypt: don't modify the data when using authenticated encryption
+    - gtp: fix use-after-free and null-ptr-deref in gtp_genl_dump_pdp()
+    - PCI/MSI: Prevent MSI hardware interrupt number truncation
+    - l2tp: pass correct message length to ip6_append_data
+    - ARM: ep93xx: Add terminator to gpiod_lookup_table
+    - usb: cdns3: fixed memory use after free at cdns3_gadget_ep_disable()
+    - usb: cdns3: fix memory double free when handle zero packet
+    - usb: gadget: ncm: Avoid dropping datagrams of properly parsed NTBs
+    - usb: roles: don't get/set_role() when usb_role_switch is unregistered
+    - IB/hfi1: Fix a memleak in init_credit_return
+    - RDMA/bnxt_re: Return error for SRQ resize
+    - RDMA/srpt: Make debug output more detailed
+    - RDMA/srpt: fix function pointer cast warnings
+    - scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions
+    - bpf, scripts: Correct GPL license name
+    - scsi: jazz_esp: Only build if SCSI core is builtin
+    - nouveau: fix function cast warnings
+    - ipv4: properly combine dev_base_seq and ipv4.dev_addr_genid
+    - ipv6: properly combine dev_base_seq and ipv6.dev_addr_genid
+    - afs: Increase buffer size in afs_update_volume_status()
+    - ipv6: sr: fix possible use-after-free and null-ptr-deref
+    - packet: move from strlcpy with unused retval to strscpy
+    - s390: use the correct count for __iowrite64_copy()
+    - tls: rx: jump to a more appropriate label
+    - tls: rx: drop pointless else after goto
+    - tls: stop recv() if initial process_rx_list gave us non-DATA
+    - netfilter: nf_tables: set dormant flag on hook register failure
+    - drm/syncobj: make lockdep complain on WAIT_FOR_SUBMIT v3
+    - drm/syncobj: call drm_syncobj_fence_add_wait when WAIT_AVAILABLE flag is set
+    - fs/aio: Restrict kiocb_set_cancel_fn() to I/O submitted via libaio
+    - scripts/bpf: Fix xdp_md forward declaration typo
+    - Linux 5.4.270
+  * CVE-2023-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+  * CVE-2021-47070
+    - uio: uio_hv_generic: use devm_kzalloc() for private data alloc
+    - uio_hv_generic: Fix another memory leak in error handling paths
+  * CVE-2024-26622
+    - tomoyo: fix UAF write bug in tomoyo_write_control()
+
+ -- Portia Stephens <portia.stephens@canonical.com>  Mon, 27 May 2024 11:13:00 +1000
+
+linux-ein (5.4.0-1054.62) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1054.62 -proposed tracker (LP: #2063658)
+
+  [ Ubuntu: 5.4.0-182.202 ]
+
+  * focal/linux: 5.4.0-182.202 -proposed tracker (LP: #2063685)
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+  * 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-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 08 May 2024 23:15:07 +0800
+
+linux-ein (5.4.0-1053.61) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1053.61 -proposed tracker (LP: #2063868)
+
+  * system hang after updating kernel (LP#2063553)
+    - SAUCE: crypto: arm64: use simd_skcipher_create() when registering aes
+      internal algs
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 02 May 2024 17:57:37 +0800
+
+linux-ein (5.4.0-1052.60) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1052.60 -proposed tracker (LP: #2059523)
+
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948)
+    - [Config] ein: updateconfigs for MFD_TI_AM335X_TSCADC
+
+  [ Ubuntu: 5.4.0-181.201 ]
+
+  * focal/linux: 5.4.0-181.201 -proposed tracker (LP: #2059549)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+  * Drop fips-checks script from trees (LP: #2055083)
+    - [Packaging] Remove fips-checks script
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948)
+    - PCI: mediatek: Clear interrupt status before dispatching handler
+    - include/linux/units.h: add helpers for kelvin to/from Celsius conversion
+    - units: Add Watt units
+    - units: change from 'L' to 'UL'
+    - units: add the HZ macros
+    - serial: sc16is7xx: set safe default SPI clock frequency
+    - spi: introduce SPI_MODE_X_MASK macro
+    - serial: sc16is7xx: add check for unsupported SPI modes during probe
+    - ext4: allow for the last group to be marked as trimmed
+    - crypto: api - Disallow identical driver names
+    - PM: hibernate: Enforce ordering during image compression/decompression
+    - hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+    - rpmsg: virtio: Free driver_override when rpmsg_remove()
+    - parisc/firmware: Fix F-extend for PDC addresses
+    - arm64: dts: qcom: sdm845: fix USB wakeup interrupt types
+    - mmc: core: Use mrq.sbc in close-ended ffu
+    - nouveau/vmm: don't set addr on the fail path to avoid warning
+    - ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
+    - rename(): fix the locking of subdirectories
+    - block: Remove special-casing of compound pages
+    - mtd: spinand: macronix: Fix MX35LFxGE4AD page size
+    - fs: add mode_strip_sgid() helper
+    - fs: move S_ISGID stripping into the vfs_*() helpers
+    - powerpc: Use always instead of always-y in for crtsavres.o
+    - x86/CPU/AMD: Fix disabling XSAVES on AMD family 0x17 due to erratum
+    - net/smc: fix illegal rmb_desc access in SMC-D connection dump
+    - vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
+    - llc: make llc_ui_sendmsg() more robust against bonding changes
+    - llc: Drop support for ETH_P_TR_802_2.
+    - net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
+    - tracing: Ensure visibility when inserting an element into tracing_map
+    - afs: Hide silly-rename files from userspace
+    - tcp: Add memory barrier to tcp_push()
+    - netlink: fix potential sleeping issue in mqueue_flush_file
+    - net/mlx5: DR, Use the right GVMI number for drop action
+    - net/mlx5: Use kfree(ft->g) in arfs_create_groups()
+    - net/mlx5e: fix a double-free in arfs_create_groups
+    - netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
+    - netfilter: nf_tables: validate NFPROTO_* family
+    - fjes: fix memleaks in fjes_hw_setup
+    - net: fec: fix the unhandled context fault from smmu
+    - btrfs: ref-verify: free ref cache before clearing mount opt
+    - btrfs: tree-checker: fix inline ref size in error messages
+    - btrfs: don't warn if discard range is not aligned to sector
+    - btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
+    - rbd: don't move requests to the running list on errors
+    - gpiolib: acpi: Ignore touchpad wakeup on GPD G1619-04
+    - drm: Don't unref the same fb many times by mistake due to deadlock handling
+    - drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking
+    - drm/bridge: nxp-ptn3460: simplify some error checking
+    - drm/exynos: fix accidental on-stack copy of exynos_drm_plane
+    - drm/exynos: gsc: minor fix for loop iteration in gsc_runtime_resume
+    - gpio: eic-sprd: Clear interrupt after set the interrupt type
+    - spi: bcm-qspi: fix SFDP BFPT read by usig mspi read
+    - mips: Call lose_fpu(0) before initializing fcr31 in mips_set_personality_nan
+    - tick/sched: Preserve number of idle sleeps across CPU hotplug events
+    - x86/entry/ia32: Ensure s32 is sign extended to s64
+    - powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+    - powerpc: Fix build error due to is_valid_bugaddr()
+    - powerpc/mm: Fix build failures due to arch_reserved_kernel_pages()
+    - powerpc: pmd_move_must_withdraw() is only needed for
+      CONFIG_TRANSPARENT_HUGEPAGE
+    - powerpc/lib: Validate size for vector operations
+    - x86/mce: Mark fatal MCE's page as poison to avoid panic in the kdump kernel
+    - perf/core: Fix narrow startup race when creating the perf nr_addr_filters
+      sysfs file
+    - regulator: core: Only increment use_count when enable_count changes
+    - audit: Send netlink ACK before setting connection in auditd_set
+    - ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
+    - PNP: ACPI: fix fortify warning
+    - ACPI: extlog: fix NULL pointer dereference check
+    - FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+    - jfs: fix slab-out-of-bounds Read in dtSearch
+    - jfs: fix array-index-out-of-bounds in dbAdjTree
+    - pstore/ram: Fix crash when setting number of cpus to an odd number
+    - crypto: stm32/crc32 - fix parsing list of devices
+    - afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
+    - rxrpc_find_service_conn_rcu: fix the usage of read_seqbegin_or_lock()
+    - jfs: fix array-index-out-of-bounds in diNewExt
+    - s390/ptrace: handle setting of fpc register correctly
+    - KVM: s390: fix setting of fpc register
+    - SUNRPC: Fix a suspicious RCU usage warning
+    - ecryptfs: Reject casefold directory inodes
+    - ext4: fix inconsistent between segment fstrim and full fstrim
+    - ext4: unify the type of flexbg_size to unsigned int
+    - ext4: remove unnecessary check from alloc_flex_gd()
+    - ext4: avoid online resizing failures due to oversized flex bg
+    - wifi: rt2x00: restart beacon queue when hardware reset
+    - selftests/bpf: satisfy compiler by having explicit return in btf test
+    - selftests/bpf: Fix pyperf180 compilation failure with clang18
+    - scsi: lpfc: Fix possible file string name overflow when updating firmware
+    - PCI: Add no PM reset quirk for NVIDIA Spectrum devices
+    - bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk
+    - ARM: dts: imx7d: Fix coresight funnel ports
+    - ARM: dts: imx7s: Fix lcdif compatible
+    - ARM: dts: imx7s: Fix nand-controller #size-cells
+    - wifi: ath9k: Fix potential array-index-out-of-bounds read in
+      ath9k_htc_txstatus()
+    - bpf: Add map and need_defer parameters to .map_fd_put_ptr()
+    - scsi: libfc: Don't schedule abort twice
+    - scsi: libfc: Fix up timeout error in fc_fcp_rec_error()
+    - ARM: dts: rockchip: fix rk3036 hdmi ports node
+    - ARM: dts: imx25/27-eukrea: Fix RTC node name
+    - ARM: dts: imx: Use flash@0,0 pattern
+    - ARM: dts: imx27: Fix sram node
+    - ARM: dts: imx1: Fix sram node
+    - ARM: dts: imx25/27: Pass timing0
+    - ARM: dts: imx27-apf27dev: Fix LED name
+    - ARM: dts: imx23-sansa: Use preferred i2c-gpios properties
+    - ARM: dts: imx23/28: Fix the DMA controller node name
+    - block: prevent an integer overflow in bvec_try_merge_hw_page
+    - md: Whenassemble the array, consult the superblock of the freshest device
+    - arm64: dts: qcom: msm8996: Fix 'in-ports' is a required property
+    - arm64: dts: qcom: msm8998: Fix 'out-ports' is a required property
+    - wifi: rtl8xxxu: Add additional USB IDs for RTL8192EU devices
+    - wifi: rtlwifi: rtl8723{be,ae}: using calculate_bit_shift()
+    - wifi: cfg80211: free beacon_ies when overridden from hidden BSS
+    - f2fs: fix to check return value of f2fs_reserve_new_block()
+    - ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument
+    - fast_dput(): handle underflows gracefully
+    - RDMA/IPoIB: Fix error code return in ipoib_mcast_join
+    - drm/drm_file: fix use of uninitialized variable
+    - drm/framebuffer: Fix use of uninitialized variable
+    - drm/mipi-dsi: Fix detach call without attach
+    - media: stk1160: Fixed high volume of stk1160_dbg messages
+    - media: rockchip: rga: fix swizzling for RGB formats
+    - PCI: add INTEL_HDA_ARL to pci_ids.h
+    - ALSA: hda: Intel: add HDA_ARL PCI ID support
+    - drm/exynos: Call drm_atomic_helper_shutdown() at shutdown/unbind time
+    - IB/ipoib: Fix mcast list locking
+    - media: ddbridge: fix an error code problem in ddb_probe
+    - drm/msm/dpu: Ratelimit framedone timeout msgs
+    - clk: hi3620: Fix memory leak in hi3620_mmc_clk_init()
+    - clk: mmp: pxa168: Fix memory leak in pxa168_clk_init()
+    - drm/amdgpu: Let KFD sync with VM fences
+    - drm/amdgpu: Drop 'fence' check in 'to_amdgpu_amdkfd_fence()'
+    - leds: trigger: panic: Don't register panic notifier if creating the trigger
+      failed
+    - um: Fix naming clash between UML and scheduler
+    - um: Don't use vfprintf() for os_info()
+    - um: net: Fix return type of uml_net_start_xmit()
+    - i3c: master: cdns: Update maximum prescaler value for i2c clock
+    - mfd: ti_am335x_tscadc: Fix TI SoC dependencies
+    - [Config] updateconfigs for MFD_TI_AM335X_TSCADC
+    - PCI: Only override AMD USB controller if required
+    - PCI: switchtec: Fix stdev_release() crash after surprise hot remove
+    - usb: hub: Replace hardcoded quirk value with BIT() macro
+    - fs/kernfs/dir: obey S_ISGID
+    - PCI/AER: Decode Requester ID when no error info found
+    - libsubcmd: Fix memory leak in uniq()
+    - virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region
+      of size 10" warnings
+    - blk-mq: fix IO hang from sbitmap wakeup race
+    - ceph: fix deadlock or deadcode of misusing dget()
+    - drm/amdgpu: Release 'adev->pm.fw' before return in
+      'amdgpu_device_need_post()'
+    - perf: Fix the nr_addr_filters fix
+    - wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
+    - scsi: isci: Fix an error code problem in isci_io_request_build()
+    - net: remove unneeded break
+    - ixgbe: Remove non-inclusive language
+    - ixgbe: Refactor returning internal error codes
+    - ixgbe: Refactor overtemp event handling
+    - ixgbe: Fix an error handling path in ixgbe_read_iosf_sb_reg_x550()
+    - ipv6: Ensure natural alignment of const ipv6 loopback and router addresses
+    - llc: call sock_orphan() at release time
+    - netfilter: nf_log: replace BUG_ON by WARN_ON_ONCE when putting logger
+    - netfilter: nft_ct: sanitize layer 3 and 4 protocol number in custom
+      expectations
+    - net: ipv4: fix a memleak in ip_setup_cork
+    - af_unix: fix lockdep positive in sk_diag_dump_icons()
+    - SAUCE: Sync apparmor copy of af_unix.c
+    - net: sysfs: Fix /sys/class/net/<iface> path
+    - HID: apple: Add support for the 2021 Magic Keyboard
+    - HID: apple: Swap the Fn and Left Control keys on Apple keyboards
+    - HID: apple: Add 2021 magic keyboard FN key mapping
+    - bonding: remove print in bond_verify_device_path
+    - dmaengine: fsl-qdma: Fix a memory leak related to the status queue DMA
+    - dmaengine: fsl-qdma: Fix a memory leak related to the queue command DMA
+    - phy: renesas: rcar-gen3-usb2: Fix returning wrong error code
+    - dmaengine: fix is_slave_direction() return false when DMA_DEV_TO_DEV
+    - phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+    - net: stmmac: xgmac: fix handling of DPP safety error for DMA channels
+    - selftests: net: avoid just another constant wait
+    - atm: idt77252: fix a memleak in open_card_ubr0
+    - hwmon: (aspeed-pwm-tacho) mutex for tach reading
+    - hwmon: (coretemp) Fix out-of-bounds memory access
+    - hwmon: (coretemp) Fix bogus core_id to attr name mapping
+    - inet: read sk->sk_family once in inet_recv_error()
+    - rxrpc: Fix response to PING RESPONSE ACKs to a dead call
+    - tipc: Check the bearer type before calling tipc_udp_nl_bearer_add()
+    - ppp_async: limit MRU to 64K
+    - netfilter: nft_compat: reject unused compat flag
+    - netfilter: nft_compat: restrict match/target protocol to u16
+    - netfilter: nft_ct: reject direction for ct id
+    - net/af_iucv: clean up a try_then_request_module()
+    - USB: serial: qcserial: add new usb-id for Dell Wireless DW5826e
+    - USB: serial: option: add Fibocom FM101-GL variant
+    - USB: serial: cp210x: add ID for IMST iM871A-USB
+    - hrtimer: Report offline hrtimer enqueue
+    - Input: atkbd - skip ATKBD_CMD_SETLEDS when skipping ATKBD_CMD_GETID
+    - net: stmmac: xgmac: use #define for string constants
+    - net: stmmac: xgmac: fix a typo of register name in DPP safety handling
+    - btrfs: forbid creating subvol qgroups
+    - btrfs: forbid deleting live subvol qgroup
+    - btrfs: send: return EOPNOTSUPP on unknown flags
+    - of: unittest: add overlay gpio test to catch gpio hog problem
+    - of: unittest: Fix compile in the non-dynamic case
+    - spi: ppc4xx: Drop write-only variable
+    - ASoC: rt5645: Fix deadlock in rt5645_jack_detect_work()
+    - MIPS: Add 'memory' clobber to csum_ipv6_magic() inline assembler
+    - i40e: Fix waiting for queues of all VSIs to be disabled
+    - tracing/trigger: Fix to return error if failed to alloc snapshot
+    - mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+    - HID: wacom: generic: Avoid reporting a serial of '0' to userspace
+    - HID: wacom: Do not register input devices until after hid_hw_start
+    - USB: hub: check for alternate port before enabling A_ALT_HNP_SUPPORT
+    - usb: f_mass_storage: forbid async queue when shutdown happen
+    - i2c: i801: Remove i801_set_block_buffer_mode
+    - i2c: i801: Fix block process call transactions
+    - scsi: Revert "scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock"
+    - firewire: core: correct documentation of fw_csr_string() kernel API
+    - kbuild: Fix changing ELF file type for output of gen_btf for big endian
+    - nfc: nci: free rx_data_reassembly skb on NCI device cleanup
+    - xen-netback: properly sync TX responses
+    - ALSA: hda/realtek: Enable headset mic on Vaio VJFE-ADL
+    - binder: signal epoll threads of self-work
+    - misc: fastrpc: Mark all sessions as invalid in cb_remove
+    - ext4: fix double-free of blocks due to wrong extents moved_len
+    - tracing: Fix wasted memory in saved_cmdlines logic
+    - staging: iio: ad5933: fix type mismatch regression
+    - iio: magnetometer: rm3100: add boundary check for the value read from
+      RM3100_REG_TMRC
+    - ring-buffer: Clean ring_buffer_poll_wait() error return
+    - serial: max310x: set default value when reading clock ready bit
+    - serial: max310x: improve crystal stable clock detection
+    - x86/Kconfig: Transmeta Crusoe is CPU family 5, not 6
+    - x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
+    - mmc: slot-gpio: Allow non-sleeping GPIO ro
+    - ALSA: hda/conexant: Add quirk for SWS JS201D
+    - nilfs2: fix data corruption in dsync block recovery for small block sizes
+    - nilfs2: fix hang in nilfs_lookup_dirty_data_buffers()
+    - nfp: use correct macro for LengthSelect in BAR config
+    - nfp: flower: prevent re-adding mac index for bonded port
+    - irqchip/irq-brcmstb-l2: Add write memory barrier before exit
+    - can: j1939: Fix UAF in j1939_sk_match_filter during
+      setsockopt(SO_J1939_FILTER)
+    - pmdomain: core: Move the unused cleanup to a _sync initcall
+    - tracing: Inform kmemleak of saved_cmdlines allocation
+    - Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d"
+    - bus: moxtet: Add spi device table
+    - arch, mm: remove stale mentions of DISCONIGMEM
+    - mips: Fix max_mapnr being uninitialized on early stages
+    - KVM: arm64: vgic-its: Avoid potential UAF in LPI translation cache
+    - netfilter: ipset: fix performance regression in swap operation
+    - netfilter: ipset: Missing gc cancellations fixed
+    - net: prevent mss overflow in skb_segment()
+    - sched/membarrier: reduce the ability to hammer on sys_membarrier
+    - nilfs2: fix potential bug in end_buffer_async_write
+    - PM: runtime: add devm_pm_runtime_enable helper
+    - PM: runtime: Have devm_pm_runtime_enable() handle
+      pm_runtime_dont_use_autosuspend()
+    - drm/msm/dsi: Enable runtime PM
+    - lsm: new security_file_ioctl_compat() hook
+    - Revert "Revert "mtd: rawnand: gpmi: Fix setting busy timeout setting""
+    - net: bcmgenet: Fix EEE implementation
+    - of: unittest: fix EXPECT text for gpio hog errors
+    - of: gpio unittest kfree() wrong object
+    - Linux 5.4.269
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948) //
+    CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+  * CVE-2023-52600
+    - jfs: fix uaf in jfs_evict_inode
+  * CVE-2023-24023
+    - Bluetooth: Add more enc key size check
+  * CVE-2024-26581
+    - netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
+    - netfilter: nft_set_rbtree: skip end interval element from gc
+  * CVE-2024-26589
+    - bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 19 Apr 2024 18:42:55 +0800
+
+linux-ein (5.4.0-1051.59) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1051.59 -proposed tracker (LP: #2059607)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+
+  [ Ubuntu: 5.4.0-177.197 ]
+
+  * focal/linux: 5.4.0-177.197 -proposed tracker (LP: #2059633)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+  * CVE-2023-24023
+    - Bluetooth: Add more enc key size check
+  * CVE-2023-52600
+    - jfs: fix uaf in jfs_evict_inode
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948) //
+    CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+  * CVE-2024-26581
+    - netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
+    - netfilter: nft_set_rbtree: skip end interval element from gc
+  * CVE-2024-26589
+    - bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+
+  [ Ubuntu: 5.4.0-176.196 ]
+
+  * focal/linux: 5.4.0-176.196 -proposed tracker (LP: #2058756)
+  * Problems with HVCS and hotplugging (LP: #2056373)
+    - powerpc/pseries: Fix bad drc_index_start value parsing of drc-info entry
+    - powerpc/pseries: Fix of_read_drc_info_cell() to point at next record
+    - hvcs: Fix hvcs port reference counting
+    - hvcs: Use dev_groups to manage hvcs device attributes
+    - hvcs: Use driver groups to manage driver attributes
+    - hvcs: Get reference to tty in remove
+    - hvcs: Use vhangup in hotplug remove
+    - hvcs: Synchronize hotplug remove with port free
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 11 Apr 2024 21:42:07 +0800
+
+linux-ein (5.4.0-1050.58) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1050.58 -proposed tracker (LP: #2055658)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+    - debian.ein/dkms-versions -- update from kernel-versions (main/2024.03.04)
+
+  * Focal update: v5.4.268 upstream stable release (LP: #2055075)
+    - [Config] ein: Update annotations for CONFIG_MMC_SDHCI_OMAP
+
+  * Focal update: v5.4.267 upstream stable release (LP: #2054406)
+    - [Config] ein: Update annotations for CONFIG_SND_MESON_CODEC_GLUE
+
+  [ Ubuntu: 5.4.0-175.195 ]
+
+  * focal/linux: 5.4.0-175.195 -proposed tracker (LP: #2055684)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+    - [Packaging] update annotations scripts
+    - debian.master/dkms-versions -- update from kernel-versions (main/2024.03.04)
+  * 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
+  * Cranky update-dkms-versions rollout (LP: #2055685)
+    - [Packaging] remove update-dkms-versions
+    - Move debian/dkms-versions to debian.master/dkms-versions
+    - [Packaging] Replace debian/dkms-versions with $(DEBIAN)/dkms-versions
+    - [Packaging] remove update-version-dkms
+  * linux-tools-common: man page of usbip[d] is misplaced (LP: #2054094)
+    - [Packaging] rules: Put usbip manpages in the correct directory
+  * CVE-2024-23851
+    - dm ioctl: log an error if the ioctl structure is corrupted
+    - dm: limit the number of targets and parameter size area
+  * Focal update: v5.4.268 upstream stable release (LP: #2055075)
+    - f2fs: explicitly null-terminate the xattr list
+    - pinctrl: lochnagar: Don't build on MIPS
+    - ALSA: hda - Fix speaker and headset mic pin config for CHUWI CoreBook XPro
+    - ASoC: Intel: Skylake: Fix mem leak in few functions
+    - ASoC: nau8822: Fix incorrect type in assignment and cast to restricted
+      __be16
+    - ASoC: Intel: Skylake: mem leak in skl register function
+    - ASoC: cs43130: Fix the position of const qualifier
+    - ASoC: cs43130: Fix incorrect frame delay configuration
+    - ASoC: rt5650: add mutex to avoid the jack detection failure
+    - nouveau/tu102: flush all pdbs on vmm flush
+    - net/tg3: fix race condition in tg3_reset_task()
+    - ASoC: da7219: Support low DC impedance headset
+    - nvme: introduce helper function to get ctrl state
+    - drm/exynos: fix a potential error pointer dereference
+    - drm/exynos: fix a wrong error checking
+    - clk: rockchip: rk3128: Fix HCLK_OTG gate register
+    - jbd2: correct the printing of write_flags in jbd2_write_superblock()
+    - drm/crtc: Fix uninit-value bug in drm_mode_setcrtc
+    - neighbour: Don't let neigh_forced_gc() disable preemption for long
+    - tracing: Have large events show up as '[LINE TOO BIG]' instead of nothing
+    - tracing: Add size check when printing trace_marker output
+    - ring-buffer: Do not record in NMI if the arch does not support cmpxchg in
+      NMI
+    - reset: hisilicon: hi6220: fix Wvoid-pointer-to-enum-cast warning
+    - Input: atkbd - skip ATKBD_CMD_GETID in translated mode
+    - Input: i8042 - add nomux quirk for Acer P459-G2-M
+    - s390/scm: fix virtual vs physical address confusion
+    - ARC: fix spare error
+    - Input: xpad - add Razer Wolverine V2 support
+    - ARM: sun9i: smp: fix return code check of of_property_match_string
+    - drm/crtc: fix uninitialized variable use
+    - ACPI: resource: Add another DMI match for the TongFang GMxXGxx
+    - binder: use EPOLLERR from eventpoll.h
+    - binder: fix trivial typo of binder_free_buf_locked()
+    - binder: fix comment on binder_alloc_new_buf() return value
+    - uio: Fix use-after-free in uio_open
+    - parport: parport_serial: Add Brainboxes BAR details
+    - parport: parport_serial: Add Brainboxes device IDs and geometry
+    - coresight: etm4x: Fix width of CCITMIN field
+    - x86/lib: Fix overflow when counting digits
+    - EDAC/thunderx: Fix possible out-of-bounds string access
+    - powerpc: add crtsavres.o to always-y instead of extra-y
+    - powerpc/44x: select I2C for CURRITUCK
+    - powerpc/pseries/memhotplug: Quieten some DLPAR operations
+    - powerpc/pseries/memhp: Fix access beyond end of drmem array
+    - selftests/powerpc: Fix error handling in FPU/VMX preemption tests
+    - powerpc/powernv: Add a null pointer check to scom_debug_init_one()
+    - powerpc/powernv: Add a null pointer check in opal_event_init()
+    - powerpc/powernv: Add a null pointer check in opal_powercap_init()
+    - powerpc/imc-pmu: Add a null pointer check in update_events_in_group()
+    - mtd: rawnand: Increment IFC_TIMEOUT_MSECS for nand controller response
+    - ACPI: video: check for error while searching for backlight device parent
+    - ACPI: LPIT: Avoid u32 multiplication overflow
+    - net: netlabel: Fix kerneldoc warnings
+    - netlabel: remove unused parameter in netlbl_netlink_auditinfo()
+    - calipso: fix memory leak in netlbl_calipso_add_pass()
+    - spi: sh-msiof: Enforce fixed DTDL for R-Car H3
+    - mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+    - selinux: Fix error priority for bind with AF_UNSPEC on PF_INET6 socket
+    - crypto: virtio - Handle dataq logic with tasklet
+    - crypto: virtio - don't use 'default m'
+    - virtio_crypto: Introduce VIRTIO_CRYPTO_NOSPC
+    - crypto: ccp - fix memleak in ccp_init_dm_workarea
+    - crypto: af_alg - Disallow multiple in-flight AIO requests
+    - crypto: sahara - remove FLAGS_NEW_KEY logic
+    - crypto: sahara - fix ahash selftest failure
+    - crypto: sahara - fix processing requests with cryptlen < sg->length
+    - crypto: sahara - fix error handling in sahara_hw_descriptor_create()
+    - pstore: ram_core: fix possible overflow in persistent_ram_init_ecc()
+    - gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
+    - crypto: virtio - Wait for tasklet to complete on device remove
+    - crypto: sahara - fix ahash reqsize
+    - crypto: sahara - fix wait_for_completion_timeout() error handling
+    - crypto: sahara - improve error handling in sahara_sha_process()
+    - crypto: sahara - fix processing hash requests with req->nbytes < sg->length
+    - crypto: sahara - do not resize req->src when doing hash operations
+    - crypto: scomp - fix req->dst buffer overflow
+    - blocklayoutdriver: Fix reference leak of pnfs_device_node
+    - NFSv4.1/pnfs: Ensure we handle the error NFS4ERR_RETURNCONFLICT
+    - wifi: rtw88: fix RX filter in FIF_ALLMULTI flag
+    - bpf, lpm: Fix check prefixlen before walking trie
+    - wifi: libertas: stop selecting wext
+    - ARM: dts: qcom: apq8064: correct XOADC register address
+    - ncsi: internal.h: Fix a spello
+    - net/ncsi: Fix netlink major/minor version numbers
+    - firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create()
+    - rtlwifi: Use ffs in <foo>_phy_calculate_bit_shift
+    - wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior
+    - scsi: fnic: Return error if vmalloc() failed
+    - arm64: dts: qcom: sdm845-db845c: correct LED panic indicator
+    - scsi: hisi_sas: Replace with standard error code return value
+    - selftests/net: fix grep checking for fib_nexthop_multiprefix
+    - virtio/vsock: fix logic which reduces credit update messages
+    - dma-mapping: clear dev->dma_mem to NULL after freeing it
+    - wifi: rtlwifi: add calculate_bit_shift()
+    - wifi: rtlwifi: rtl8188ee: phy: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192c: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192cu: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ce: using calculate_bit_shift()
+    - rtlwifi: rtl8192de: make arrays static const, makes object smaller
+    - wifi: rtlwifi: rtl8192de: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ee: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192se: using calculate_bit_shift()
+    - netfilter: nf_tables: mark newset as dead on transaction abort
+    - Bluetooth: Fix bogus check for re-auth no supported with non-ssp
+    - Bluetooth: btmtkuart: fix recv_buf() return value
+    - ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+    - ARM: davinci: always select CONFIG_CPU_ARM926T
+    - RDMA/usnic: Silence uninitialized symbol smatch warnings
+    - media: pvrusb2: fix use after free on context disconnection
+    - drm/bridge: Fix typo in post_disable() description
+    - f2fs: fix to avoid dirent corruption
+    - drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg()
+    - drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check()
+    - drm/radeon: check return value of radeon_ring_lock()
+    - ASoC: cs35l33: Fix GPIO name and drop legacy include
+    - ASoC: cs35l34: Fix GPIO name and drop legacy include
+    - drm/msm/mdp4: flush vblank event on disable
+    - drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks
+    - drm/drv: propagate errors from drm_modeset_register_all()
+    - drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+    - drm/radeon/dpm: fix a memleak in sumo_parse_power_table
+    - drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table
+    - drm/bridge: tc358767: Fix return value on error case
+    - media: cx231xx: fix a memleak in cx231xx_init_isoc
+    - media: dvbdev: drop refcount on error path in dvb_device_open()
+    - drm/amdgpu/debugfs: fix error code when smc register accessors are NULL
+    - drm/amd/pm: fix a double-free in si_dpm_init
+    - drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+    - gpu/drm/radeon: fix two memleaks in radeon_vm_init
+    - drivers: clk: zynqmp: calculate closest mux rate
+    - watchdog: set cdev owner before adding
+    - watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO
+    - watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling
+    - clk: si5341: fix an error code problem in si5341_output_clk_set_rate
+    - mmc: sdhci_omap: Fix TI SoC dependencies
+    - [Config] update annotations for CONFIG_MMC_SDHCI_OMAP
+    - [Config] remove sdhci-omap module for arm64/ppc64el
+    - of: Fix double free in of_parse_phandle_with_args_map
+    - of: unittest: Fix of_count_phandle_with_args() expected value message
+    - binder: fix async space check for 0-sized buffers
+    - binder: fix use-after-free in shinker's callback
+    - Input: atkbd - use ab83 as id when skipping the getid command
+    - Revert "ASoC: atmel: Remove system clock tree configuration for
+      at91sam9g20ek"
+    - binder: fix race between mmput() and do_exit()
+    - binder: fix unused alloc->free_async_space
+    - tick-sched: Fix idle and iowait sleeptime accounting vs CPU hotplug
+    - usb: phy: mxs: remove CONFIG_USB_OTG condition for mxs_phy_is_otg_host()
+    - usb: dwc: ep0: Update request status in dwc3_ep0_stall_restart
+    - Revert "usb: dwc3: Soft reset phy on probe for host"
+    - Revert "usb: dwc3: don't reset device side if dwc3 was configured as host-
+      only"
+    - usb: chipidea: wait controller resume finished for wakeup irq
+    - Revert "usb: typec: class: fix typec_altmode_put_partner to put plugs"
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - usb: mon: Fix atomicity violation in mon_bin_vma_fault
+    - ALSA: oxygen: Fix right channel of capture volume mixer
+    - fbdev: flush deferred work in fb_deferred_io_fsync()
+    - rootfs: Fix support for rootfstype= when root= is given
+    - wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code
+    - wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors
+    - wifi: mwifiex: configure BSSID consistently when starting AP
+    - x86/kvm: Do not try to disable kvmclock if it was not enabled
+    - HID: wacom: Correct behavior when processing some confidence == false
+      touches
+    - mips: Fix incorrect max_low_pfn adjustment
+    - MIPS: Alchemy: Fix an out-of-bound access in db1200_dev_setup()
+    - MIPS: Alchemy: Fix an out-of-bound access in db1550_dev_setup()
+    - serial: 8250: omap: Don't skip resource freeing if
+      pm_runtime_resume_and_get() failed
+    - acpi: property: Let args be NULL in __acpi_node_get_property_reference
+    - software node: Let args be NULL in software_node_get_reference_args
+    - perf genelf: Set ELF program header addresses properly
+    - nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length
+    - nvmet-tcp: fix a crash in nvmet_req_complete()
+    - perf env: Add perf_env__numa_node()
+    - perf record: Move sb_evlist to 'struct record'
+    - perf top: Move sb_evlist to 'struct perf_top'
+    - perf bpf: Decouple creating the evlist from adding the SB event
+    - perf env: Avoid recursively taking env->bpf_progs.lock
+    - apparmor: avoid crash when parsed profile name is empty
+    - serial: imx: Correct clock error message in function probe()
+    - nvmet-tcp: Fix the H2C expected PDU len calculation
+    - PCI: keystone: Fix race condition when initializing PHYs
+    - s390/pci: fix max size calculation in zpci_memcpy_toio()
+    - net: qualcomm: rmnet: fix global oob in rmnet_policy
+    - net: phy: micrel: populate .soft_reset for KSZ9131
+    - net: ravb: Fix dma_addr_t truncation in error case
+    - net: dsa: vsc73xx: Add null pointer check to vsc73xx_gpio_probe
+    - netfilter: nf_tables: skip dead set elements in netlink dump
+    - ipvs: avoid stat macros calls from preemptible context
+    - kdb: Censor attempts to set PROMPT without ENABLE_MEM_READ
+    - kdb: Fix a potential buffer overflow in kdb_local()
+    - mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure
+    - i2c: s3c24xx: fix read transfers in polling mode
+    - i2c: s3c24xx: fix transferring more than one message in polling mode
+    - perf top: Skip side-band event setup if HAVE_LIBBPF_SUPPORT is not set
+    - arm64: dts: armada-3720-turris-mox: set irq type for RTC
+    - Linux 5.4.268
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+  * Focal update: v5.4.267 upstream stable release (LP: #2054406)
+    - nfc: llcp_core: Hold a ref to llcp_local->dev when holding a ref to
+      llcp_local
+    - i40e: Fix filter input checks to prevent config with invalid values
+    - net: sched: em_text: fix possible memory leak in em_text_destroy()
+    - can: raw: add support for SO_TXTIME/SCM_TXTIME
+    - can: raw: add support for SO_MARK
+    - net-timestamp: extend SOF_TIMESTAMPING_OPT_ID to HW timestamps
+    - ARM: sun9i: smp: Fix array-index-out-of-bounds read in sunxi_mc_smp_init
+    - net: bcmgenet: Fix FCS generation for fragmented skbuffs
+    - net: Save and restore msg_namelen in sock_sendmsg
+    - i40e: fix use-after-free in i40e_aqc_add_filters()
+    - ASoC: meson: g12a: extract codec-to-codec utils
+    - [Config] Update annotations for CONFIG_SND_MESON_CODEC_GLUE
+    - ASoC: meson: g12a-tohdmitx: Validate written enum values
+    - ASoC: meson: g12a-tohdmitx: Fix event generation for S/PDIF mux
+    - i40e: Restore VF MSI-X state during PCI reset
+    - net/qla3xxx: switch from 'pci_' to 'dma_' API
+    - net/qla3xxx: fix potential memleak in ql_alloc_buffer_queues
+    - asix: Add check for usbnet_get_endpoints
+    - bnxt_en: Remove mis-applied code from bnxt_cfg_ntp_filters()
+    - net: Implement missing SO_TIMESTAMPING_NEW cmsg support
+    - mm/memory-failure: check the mapcount of the precise page
+    - firewire: ohci: suppress unexpected system reboot in AMD Ryzen machines and
+      ASM108x/VT630x PCIe cards
+    - i2c: core: Fix atomic xfer check for non-preempt config
+    - mm: fix unmap_mapping_range high bits shift bug
+    - mmc: rpmb: fixes pause retune on all RPMB partitions.
+    - mmc: core: Cancel delayed work before releasing host
+    - mmc: sdhci-sprd: Fix eMMC init failure after hw reset
+    - ath10k: Wait until copy complete is actually done before completing
+    - ath10k: Add interrupt summary based CE processing
+    - ath10k: Keep track of which interrupts fired, don't poll them
+    - ath10k: Get rid of "per_ce_irq" hw param
+    - PCI: Extract ATS disabling to a helper function
+    - PCI: Disable ATS for specific Intel IPU E2000 devices
+    - net/dst: use a smaller percpu_counter batch for dst entries accounting
+    - ipv6: make ip6_rt_gc_expire an atomic_t
+    - ipv6: remove max_size check inline with ipv4
+    - ASoC: meson: codec-glue: fix pcm format cast warning
+    - Linux 5.4.267
+  * CVE-2023-23000
+    - phy: tegra: xusb: Fix return value of tegra_xusb_find_port_node function
+  * CVE-2023-23004
+    - malidp: Fix NULL vs IS_ERR() checking
+  * CVE-2023-46838
+    - xen-netback: don't produce zero-size SKB frags
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+  * Focal update: v5.4.266 upstream stable release (LP: #2051655)
+    - ALSA: hda/realtek: Enable headset on Lenovo M90 Gen5
+    - ksmbd: fix wrong name of SMB2_CREATE_ALLOCATION_SIZE
+    - ARM: OMAP2+: Fix null pointer dereference and memory leak in
+      omap_soc_device_init
+    - reset: Fix crash when freeing non-existent optional resets
+    - s390/vx: fix save/restore of fpu kernel context
+    - wifi: mac80211: mesh_plink: fix matches_local logic
+    - net/mlx5: improve some comments
+    - net/mlx5: Fix fw tracer first block check
+    - net/mlx5e: Correct snprintf truncation handling for fw_version buffer used
+      by representors
+    - net: sched: ife: fix potential use-after-free
+    - ethernet: atheros: fix a memleak in atl1e_setup_ring_resources
+    - net/rose: fix races in rose_kill_by_device()
+    - net: check vlan filter feature in vlan_vids_add_by_dev() and
+      vlan_vids_del_by_dev()
+    - afs: Fix the dynamic root's d_delete to always delete unused dentries
+    - afs: Fix dynamic root lookup DNS check
+    - net: warn if gso_type isn't set for a GSO SKB
+    - net: check dev->gso_max_size in gso_features_check()
+    - afs: Fix overwriting of result of DNS query
+    - i2c: aspeed: Handle the coalesced stop conditions with the start conditions.
+    - pinctrl: at91-pio4: use dedicated lock class for IRQ
+    - ALSA: hda/hdmi: Add quirk to force pin connectivity on NUC10
+    - ALSA: hda/hdmi: add force-connect quirk for NUC5CPYB
+    - smb: client: fix NULL deref in asn1_ber_decoder()
+    - btrfs: do not allow non subvolume root targets for snapshot
+    - interconnect: Treat xlate() returning NULL node as an error
+    - iio: imu: inv_mpu6050: fix an error code problem in inv_mpu6050_read_raw
+    - Input: ipaq-micro-keys - add error handling for devm_kmemdup
+    - scsi: bnx2fc: Fix skb double free in bnx2fc_rcv()
+    - iio: common: ms_sensors: ms_sensors_i2c: fix humidity conversion time table
+    - iio: adc: ti_am335x_adc: Fix return value check of tiadc_request_dma()
+    - wifi: cfg80211: Add my certificate
+    - wifi: cfg80211: fix certs build to not depend on file order
+    - USB: serial: ftdi_sio: update Actisense PIDs constant names
+    - USB: serial: option: add Quectel EG912Y module support
+    - USB: serial: option: add Foxconn T99W265 with new baseline
+    - USB: serial: option: add Quectel RM500Q R13 firmware support
+    - Bluetooth: hci_event: Fix not checking if HCI_OP_INQUIRY has been sent
+    - net: 9p: avoid freeing uninit memory in p9pdu_vreadf
+    - net: rfkill: gpio: set GPIO direction
+    - x86/alternatives: Sync core before enabling interrupts
+    - usb: fotg210-hcd: delete an incorrect bounds test
+    - ring-buffer: Fix wake ups when buffer_percent is set to 100
+    - block: Don't invalidate pagecache for invalid falloc modes
+    - Linux 5.4.266
+  * CVE-2024-0607
+    - netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 21 Mar 2024 17:59:35 +0800
+
+linux-ein (5.4.0-1049.56) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1049.56 -proposed tracker (LP: #2055951)
+
+  [ Ubuntu: 5.4.0-174.193 ]
+
+  * focal/linux: 5.4.0-174.193 -proposed tracker (LP: #2055978)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update annotations scripts
+    - debian/dkms-versions -- update from kernel-versions (main/s2024.02.05)
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+  * CVE-2023-23004
+    - malidp: Fix NULL vs IS_ERR() checking
+  * CVE-2023-23000
+    - phy: tegra: xusb: Fix return value of tegra_xusb_find_port_node function
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 14 Mar 2024 13:34:43 +0800
+
+linux-ein (5.4.0-1048.55) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1048.55 -proposed tracker (LP: #2052109)
+
+  * Focal update: v5.4.261 upstream stable release (LP: #2049049)
+    - [Config] ein: remove CONFIG_QCOM_SDM845_LLCC
+
+  * Focal update: v5.4.260 upstream stable release (LP: #2049024)
+    - [Config] ein: cleanup after removing CONFIG_BLK_DEV_SX8
+
+  [ Ubuntu: 5.4.0-173.191 ]
+
+  * focal/linux: 5.4.0-173.191 -proposed tracker (LP: #2052135)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2024.02.05)
+  * CVE-2023-0340
+    - vhost: use kzalloc() instead of kmalloc() followed by memset()
+  * CVE-2023-6915
+    - ida: Fix crash in ida_free when the bitmap is empty
+  * Focal update: v5.4.265 upstream stable release (LP: #2051644)
+    - afs: Fix refcount underflow from error handling race
+    - net: ipv6: support reporting otherwise unknown prefix flags in RTM_NEWPREFIX
+    - qca_debug: Prevent crash on TX ring changes
+    - qca_debug: Fix ethtool -G iface tx behavior
+    - qca_spi: Fix reset behavior
+    - atm: solos-pci: Fix potential deadlock on &cli_queue_lock
+    - atm: solos-pci: Fix potential deadlock on &tx_queue_lock
+    - atm: Fix Use-After-Free in do_vcc_ioctl
+    - qed: Fix a potential use-after-free in qed_cxt_tables_alloc
+    - net: Remove acked SYN flag from packet in the transmit queue correctly
+    - sign-file: Fix incorrect return values check
+    - vsock/virtio: Fix unsigned integer wrap around in
+      virtio_transport_has_space()
+    - net: stmmac: use dev_err_probe() for reporting mdio bus registration failure
+    - net: stmmac: Handle disabled MDIO busses from devicetree
+    - cred: switch to using atomic_long_t
+    - ALSA: hda/hdmi: add force-connect quirks for ASUSTeK Z170 variants
+    - usb: aqc111: check packet for fixup for true limit
+    - blk-throttle: fix lockdep warning of "cgroup_mutex or RCU read lock
+      required!"
+    - bcache: avoid oversize memory allocation by small stripe_size
+    - bcache: add code comments for bch_btree_node_get() and
+      __bch_btree_node_alloc()
+    - bcache: avoid NULL checking to c->root in run_cache_set()
+    - platform/x86: intel_telemetry: Fix kernel doc descriptions
+    - HID: add ALWAYS_POLL quirk for Apple kb
+    - HID: hid-asus: reset the backlight brightness level on resume
+    - HID: multitouch: Add quirk for HONOR GLO-GXXX touchpad
+    - asm-generic: qspinlock: fix queued_spin_value_unlocked() implementation
+    - net: usb: qmi_wwan: claim interface 4 for ZTE MF290
+    - HID: hid-asus: add const to read-only outgoing usb buffer
+    - soundwire: stream: fix NULL pointer dereference for multi_link
+    - ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS
+    - arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify
+    - team: Fix use-after-free when an option instance allocation fails
+    - ring-buffer: Fix memory leak of free page
+    - mmc: block: Be sure to wait while busy in CQE error recovery
+    - powerpc/ftrace: Create a dummy stackframe to fix stack unwind
+    - powerpc/ftrace: Fix stack teardown in ftrace_no_trace
+    - Linux 5.4.265
+  * Focal update: v5.4.264 upstream stable release (LP: #2049935)
+    - hrtimers: Push pending hrtimers away from outgoing CPU earlier
+    - netfilter: ipset: fix race condition between swap/destroy and kernel side
+      add/del/test
+    - tg3: Move the [rt]x_dropped counters to tg3_napi
+    - tg3: Increment tx_dropped in tg3_tso_bug()
+    - kconfig: fix memory leak from range properties
+    - drm/amdgpu: correct chunk_ptr to a pointer to chunk.
+    - of: base: Add of_get_cpu_state_node() to get idle states for a CPU node
+    - ACPI/IORT: Make iort_get_device_domain IRQ domain agnostic
+    - ACPI/IORT: Make iort_msi_map_rid() PCI agnostic
+    - of/iommu: Make of_map_rid() PCI agnostic
+    - of/irq: make of_msi_map_get_device_domain() bus agnostic
+    - of/irq: Make of_msi_map_rid() PCI bus agnostic
+    - of: base: Fix some formatting issues and provide missing descriptions
+    - of: Fix kerneldoc output formatting
+    - of: Add missing 'Return' section in kerneldoc comments
+    - of: dynamic: Fix of_reconfig_get_state_change() return value documentation
+    - ipv6: fix potential NULL deref in fib6_add()
+    - hv_netvsc: rndis_filter needs to select NLS
+    - net: arcnet: Fix RESET flag handling
+    - net: arcnet: com20020 fix error handling
+    - arcnet: restoring support for multiple Sohard Arcnet cards
+    - ipv4: ip_gre: Avoid skb_pull() failure in ipgre_xmit()
+    - net: hns: fix fake link up on xge port
+    - netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
+    - tcp: do not accept ACK of bytes we never sent
+    - bpf: sockmap, updating the sg structure should also update curr
+    - RDMA/bnxt_re: Correct module description string
+    - hwmon: (acpi_power_meter) Fix 4.29 MW bug
+    - ASoC: wm_adsp: fix memleak in wm_adsp_buffer_populate
+    - tracing: Fix a warning when allocating buffered events fails
+    - scsi: be2iscsi: Fix a memleak in beiscsi_init_wrb_handle()
+    - ARM: imx: Check return value of devm_kasprintf in imx_mmdc_perf_init
+    - ARM: dts: imx: make gpt node name generic
+    - ARM: dts: imx7: Declare timers compatible with fsl,imx6dl-gpt
+    - ALSA: pcm: fix out-of-bounds in snd_pcm_state_names
+    - nilfs2: prevent WARNING in nilfs_sufile_set_segment_usage()
+    - tracing: Always update snapshot buffer size
+    - tracing: Fix incomplete locking when disabling buffered events
+    - tracing: Fix a possible race when disabling buffered events
+    - packet: Move reference count in packet_sock to atomic_long_t
+    - arm64: dts: mediatek: mt7622: fix memory node warning check
+    - arm64: dts: mediatek: mt8173-evb: Fix regulator-fixed node names
+    - gpiolib: sysfs: Fix error handling on failed export
+    - mmc: core: add helpers mmc_regulator_enable/disable_vqmmc
+    - mmc: sdhci-sprd: Fix vqmmc not shutting down after the card was pulled
+    - usb: gadget: f_hid: fix report descriptor allocation
+    - parport: Add support for Brainboxes IX/UC/PX parallel cards
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - ARM: PL011: Fix DMA support
+    - serial: sc16is7xx: address RX timeout interrupt errata
+    - serial: 8250_omap: Add earlycon support for the AM654 UART controller
+    - x86/CPU/AMD: Check vendor in the AMD microcode callback
+    - KVM: s390/mm: Properly reset no-dat
+    - nilfs2: fix missing error check for sb_set_blocksize call
+    - io_uring/af_unix: disable sending io_uring over sockets
+    - netlink: don't call ->netlink_bind with table lock held
+    - genetlink: add CAP_NET_ADMIN test for multicast bind
+    - psample: Require 'CAP_NET_ADMIN' when joining "packets" group
+    - drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group
+    - tools headers UAPI: Sync linux/perf_event.h with the kernel sources
+    - cifs: Fix non-availability of dedup breaking generic/304
+    - smb: client: fix potential NULL deref in parse_dfs_referrals()
+    - devcoredump : Serialize devcd_del work
+    - devcoredump: Send uevent once devcd is ready
+    - Linux 5.4.264
+  * CVE-2024-0646
+    - net: tls, update curr on splice as well
+  * CVE-2024-0565
+    - smb: client: fix OOB in receive_encrypted_standard()
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+  * CVE-2023-51782
+    - net/rose: Fix Use-After-Free in rose_ioctl
+  * Focal update: v5.4.263 upstream stable release (LP: #2049084)
+    - driver core: Release all resources during unbind before updating device
+      links
+    - RDMA/irdma: Prevent zero-length STAG registration
+    - PCI: keystone: Drop __init from ks_pcie_add_pcie_{ep,port}()
+    - afs: Make error on cell lookup failure consistent with OpenAFS
+    - drm/panel: simple: Fix Innolux G101ICE-L01 bus flags
+    - drm/panel: simple: Fix Innolux G101ICE-L01 timings
+    - ata: pata_isapnp: Add missing error check for devm_ioport_map()
+    - drm/rockchip: vop: Fix color for RGB888/BGR888 format on VOP full
+    - HID: core: store the unique system identifier in hid_device
+    - HID: fix HID device resource race between HID core and debugging support
+    - ipv4: Correct/silence an endian warning in __ip_do_redirect
+    - net: usb: ax88179_178a: fix failed operations during ax88179_reset
+    - arm/xen: fix xen_vcpu_info allocation alignment
+    - amd-xgbe: handle corner-case during sfp hotplug
+    - amd-xgbe: handle the corner-case during tx completion
+    - amd-xgbe: propagate the correct speed and duplex status
+    - net: axienet: Fix check for partial TX checksum
+    - afs: Return ENOENT if no cell DNS record can be found
+    - afs: Fix file locking on R/O volumes to operate in local mode
+    - nvmet: remove unnecessary ctrl parameter
+    - nvmet: nul-terminate the NQNs passed in the connect command
+    - MIPS: KVM: Fix a build warning about variable set but not used
+    - ext4: add a new helper to check if es must be kept
+    - ext4: factor out __es_alloc_extent() and __es_free_extent()
+    - ext4: use pre-allocated es in __es_insert_extent()
+    - ext4: use pre-allocated es in __es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_insert_delayed_block()
+    - ext4: using nofail preallocation in ext4_es_insert_extent()
+    - ext4: fix slab-use-after-free in ext4_es_insert_extent()
+    - ext4: make sure allocate pending entry not fail
+    - arm64: cpufeature: Extract capped perfmon fields
+    - KVM: arm64: limit PMU version to PMUv3 for ARMv8.1
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA
+    - bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in
+      btree_gc_coalesce()
+    - s390/dasd: protect device queue against concurrent access
+    - USB: serial: option: add Luat Air72*U series products
+    - hv_netvsc: Fix race of register_netdevice_notifier and VF register
+    - hv_netvsc: Mark VF as slave before exposing it to user-mode
+    - dm-delay: fix a race between delay_presuspend and delay_bio
+    - bcache: check return value from btree_node_alloc_replacement()
+    - bcache: prevent potential division by zero error
+    - USB: serial: option: add Fibocom L7xx modules
+    - USB: serial: option: fix FM101R-GL defines
+    - USB: serial: option: don't claim interface 4 for ZTE MF290
+    - USB: dwc2: write HCINT with INTMASK applied
+    - usb: dwc3: set the dma max_seg_size
+    - USB: dwc3: qcom: fix resource leaks on probe deferral
+    - USB: dwc3: qcom: fix wakeup after probe deferral
+    - io_uring: fix off-by one bvec index
+    - pinctrl: avoid reload of p state in list iteration
+    - firewire: core: fix possible memory leak in create_units()
+    - mmc: block: Do not lose cache flush during CQE error recovery
+    - ALSA: hda: Disable power-save on KONTRON SinglePC
+    - ALSA: hda/realtek: Headset Mic VREF to 100%
+    - ALSA: hda/realtek: Add supported ALC257 for ChromeOS
+    - dm-verity: align struct dm_verity_fec_io properly
+    - dm verity: don't perform FEC for failed readahead IO
+    - bcache: revert replacing IS_ERR_OR_NULL with IS_ERR
+    - powerpc: Don't clobber f0/vs0 during fp|altivec register save
+    - btrfs: fix off-by-one when checking chunk map includes logical address
+    - btrfs: send: ensure send_fd is writable
+    - btrfs: make error messages more clear when getting a chunk map
+    - Input: xpad - add HyperX Clutch Gladiate Support
+    - net: stmmac: xgmac: Disable FPE MMC interrupts
+    - ravb: Fix races between ravb_tx_timeout_work() and net related ops
+    - net: ravb: Use pm_runtime_resume_and_get()
+    - net: ravb: Start TX queues after HW initialization succeeded
+    - smb3: fix touch -h of symlink
+    - s390/mm: fix phys vs virt confusion in mark_kernel_pXd() functions family
+    - s390/cmma: fix detection of DAT pages
+    - mtd: cfi_cmdset_0001: Support the absence of protection registers
+    - mtd: cfi_cmdset_0001: Byte swap OTP info
+    - fbdev: stifb: Make the STI next font pointer a 32-bit signed offset
+    - ima: annotate iint mutex to avoid lockdep false positive warnings
+    - ovl: skip overlayfs superblocks at global sync
+    - ima: detect changes to the backing overlay file
+    - scsi: qla2xxx: Simplify the code for aborting SCSI commands
+    - scsi: core: Introduce the scsi_cmd_to_rq() function
+    - scsi: qla2xxx: Use scsi_cmd_to_rq() instead of scsi_cmnd.request
+    - scsi: qla2xxx: Fix system crash due to bad pointer access
+    - cpufreq: imx6q: don't warn for disabling a non-existing frequency
+    - cpufreq: imx6q: Don't disable 792 Mhz OPP unnecessarily
+    - mmc: cqhci: Increase recovery halt timeout
+    - mmc: cqhci: Warn of halt or task clear failure
+    - mmc: cqhci: Fix task clearing in CQE error recovery
+    - mmc: core: convert comma to semicolon
+    - mmc: block: Retry commands in CQE error recovery
+    - Linux 5.4.263
+  * Focal update: v5.4.262 upstream stable release (LP: #2049069)
+    - locking/ww_mutex/test: Fix potential workqueue corruption
+    - perf/core: Bail out early if the request AUX area is out of bound
+    - clocksource/drivers/timer-imx-gpt: Fix potential memory leak
+    - clocksource/drivers/timer-atmel-tcb: Fix initialization on SAM9 hardware
+    - x86/mm: Drop the 4 MB restriction on minimal NUMA node memory size
+    - wifi: mac80211_hwsim: fix clang-specific fortify warning
+    - wifi: mac80211: don't return unset power in ieee80211_get_tx_power()
+    - wifi: ath9k: fix clang-specific fortify warnings
+    - wifi: ath10k: fix clang-specific fortify warning
+    - net: annotate data-races around sk->sk_tx_queue_mapping
+    - net: annotate data-races around sk->sk_dst_pending_confirm
+    - wifi: ath10k: Don't touch the CE interrupt registers after power up
+    - Bluetooth: Fix double free in hci_conn_cleanup
+    - platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e
+    - drm/komeda: drop all currently held locks if deadlock happens
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for Polaris and Tonga
+    - drm/amdgpu: Fix a null pointer access when the smc_rreg pointer is NULL
+    - selftests/efivarfs: create-read: fix a resource leak
+    - crypto: pcrypt - Fix hungtask for PADATA_RESET
+    - RDMA/hfi1: Use FIELD_GET() to extract Link Width
+    - fs/jfs: Add check for negative db_l2nbperpage
+    - fs/jfs: Add validity check for db_maxag and db_agpref
+    - jfs: fix array-index-out-of-bounds in dbFindLeaf
+    - jfs: fix array-index-out-of-bounds in diAlloc
+    - ARM: 9320/1: fix stack depot IRQ stack filter
+    - ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+    - PCI: tegra194: Use FIELD_GET()/FIELD_PREP() with Link Width fields
+    - atm: iphase: Do PCI error checks on own line
+    - scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+    - HID: Add quirk for Dell Pro Wireless Keyboard and Mouse KM5221W
+    - tty: vcc: Add check for kstrdup() in vcc_probe()
+    - usb: gadget: f_ncm: Always set current gadget in ncm_bind()
+    - i2c: sun6i-p2wi: Prevent potential division by zero
+    - media: gspca: cpia1: shift-out-of-bounds in set_flicker
+    - media: vivid: avoid integer overflow
+    - gfs2: ignore negated quota changes
+    - media: cobalt: Use FIELD_GET() to extract Link Width
+    - drm/amd/display: Avoid NULL dereference of timing generator
+    - kgdb: Flush console before entering kgdb on panic
+    - ASoC: ti: omap-mcbsp: Fix runtime PM underflow warnings
+    - pwm: Fix double shift bug
+    - wifi: iwlwifi: Use FW rate for non-data frames
+    - NFSv4.1: fix SP4_MACH_CRED protection for pnfs IO
+    - ipvlan: add ipvlan_route_v6_outbound() helper
+    - tty: Fix uninit-value access in ppp_sync_receive()
+    - net: hns3: fix variable may not initialized problem in hns3_init_mac_addr()
+    - tipc: Fix kernel-infoleak due to uninitialized TLV value
+    - ppp: limit MRU to 64K
+    - xen/events: fix delayed eoi list handling
+    - ptp: annotate data-race around q->head and q->tail
+    - bonding: stop the device in bond_setup_by_slave()
+    - net: ethernet: cortina: Fix max RX frame define
+    - net: ethernet: cortina: Handle large frames
+    - net: ethernet: cortina: Fix MTU max setting
+    - netfilter: nf_conntrack_bridge: initialize err to 0
+    - net: stmmac: Rework stmmac_rx()
+    - net: stmmac: fix rx budget limit check
+    - net/mlx5_core: Clean driver version and name
+    - net/mlx5e: Check return value of snprintf writing to fw_version buffer for
+      representors
+    - macvlan: Don't propagate promisc change to lower dev in passthru
+    - tools/power/turbostat: Fix a knl bug
+    - cifs: spnego: add ';' in HOST_KEY_LEN
+    - media: venus: hfi: add checks to perform sanity on queue pointers
+    - randstruct: Fix gcc-plugin performance mode to stay in group
+    - bpf: Fix precision tracking for BPF_ALU | BPF_TO_BE | BPF_END
+    - scsi: megaraid_sas: Increase register read retry rount from 3 to 30 for
+      selected registers
+    - x86/cpu/hygon: Fix the CPU topology evaluation for real
+    - KVM: x86: hyper-v: Don't auto-enable stimer on write from user-space
+    - KVM: x86: Ignore MSR_AMD64_TW_CFG access
+    - audit: don't take task_lock() in audit_exe_compare() code path
+    - audit: don't WARN_ON_ONCE(!current->mm) in audit_exe_compare()
+    - hvc/xen: fix error path in xen_hvc_init() to always register frontend driver
+    - PCI/sysfs: Protect driver's D3cold preference from user space
+    - ACPI: resource: Do IRQ override on TongFang GMxXGxx
+    - mmc: meson-gx: Remove setting of CMD_CFG_ERROR
+    - genirq/generic_chip: Make irq_remove_generic_chip() irqdomain aware
+    - PCI: keystone: Don't discard .remove() callback
+    - PCI: keystone: Don't discard .probe() callback
+    - parisc/pdc: Add width field to struct pdc_model
+    - clk: qcom: ipq8074: drop the CLK_SET_RATE_PARENT flag from PLL clocks
+    - mmc: vub300: fix an error code
+    - PM: hibernate: Use __get_safe_page() rather than touching the list
+    - PM: hibernate: Clean up sync_read handling in snapshot_write_next()
+    - btrfs: don't arbitrarily slow down delalloc if we're committing
+    - jbd2: fix potential data lost in recovering journal raced with synchronizing
+      fs bdev
+    - quota: explicitly forbid quota files from being encrypted
+    - kernel/reboot: emergency_restart: Set correct system_state
+    - i2c: core: Run atomic i2c xfer when !preemptible
+    - mcb: fix error handling for different scenarios when parsing
+    - dmaengine: stm32-mdma: correct desc prep when channel running
+    - mm/cma: use nth_page() in place of direct struct page manipulation
+    - i3c: master: cdns: Fix reading status register
+    - parisc: Prevent booting 64-bit kernels on PA1.x machines
+    - parisc/pgtable: Do not drop upper 5 address bits of physical address
+    - ALSA: info: Fix potential deadlock at disconnection
+    - ALSA: hda/realtek - Enable internal speaker of ASUS K6500ZC
+    - serial: meson: remove redundant initialization of variable id
+    - tty: serial: meson: retrieve port FIFO size from DT
+    - serial: meson: Use platform_get_irq() to get the interrupt
+    - tty: serial: meson: fix hard LOCKUP on crtscts mode
+    - Bluetooth: btusb: add Realtek 8822CE to usb_device_id table
+    - Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x0cb8:0xc559
+    - bluetooth: Add device 0bda:887b to device tables
+    - bluetooth: Add device 13d3:3571 to device tables
+    - Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables
+    - Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE
+    - Revert ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - net: dsa: lan9303: consequently nested-lock physical MDIO
+    - i2c: i801: fix potential race in i801_block_transaction_byte_by_byte
+    - media: lirc: drop trailing space from scancode transmit
+    - media: sharp: fix sharp encoding
+    - media: venus: hfi_parser: Add check to keep the number of codecs within
+      range
+    - media: venus: hfi: fix the check to handle session buffer requirement
+    - media: venus: hfi: add checks to handle capabilities from firmware
+    - nfsd: fix file memleak on client_opens_release
+    - ext4: apply umask if ACL support is disabled
+    - ext4: correct offset of gdb backup in non meta_bg group to update_backups
+    - ext4: correct return value of ext4_convert_meta_bg
+    - ext4: correct the start block of counting reserved clusters
+    - ext4: remove gdb backup copy for meta bg in setup_new_flex_group_blocks
+    - drm/amdgpu: fix error handling in amdgpu_bo_list_get()
+    - tracing: Have trace_event_file have ref counters
+    - netfilter: nf_tables: pass context to nft_set_destroy()
+    - netfilter: nftables: rename set element data activation/deactivation
+      functions
+    - netfilter: nf_tables: drop map element references from preparation phase
+    - netfilter: nft_set_rbtree: Switch to node list walk for overlap detection
+    - netfilter: nft_set_rbtree: fix null deref on element insertion
+    - netfilter: nft_set_rbtree: fix overlap expiration walk
+    - netfilter: nf_tables: don't skip expired elements during walk
+    - netfilter: nf_tables: GC transaction API to avoid race with control plane
+    - netfilter: nf_tables: adapt set backend to use GC transaction API
+    - netfilter: nft_set_hash: mark set element as dead when deleting from packet
+      path
+    - netfilter: nf_tables: remove busy mark and gc batch API
+    - netfilter: nf_tables: fix GC transaction races with netns and netlink event
+      exit path
+    - netfilter: nf_tables: GC transaction race with netns dismantle
+    - netfilter: nf_tables: GC transaction race with abort path
+    - netfilter: nf_tables: use correct lock to protect gc_list
+    - netfilter: nf_tables: defer gc run if previous batch is still pending
+    - netfilter: nft_set_rbtree: skip sync GC for new elements in this transaction
+    - netfilter: nft_set_rbtree: use read spinlock to avoid datapath contention
+    - netfilter: nft_set_hash: try later when GC hits EAGAIN on iteration
+    - netfilter: nf_tables: fix memleak when more than 255 elements expired
+    - netfilter: nf_tables: unregister flowtable hooks on netns exit
+    - netfilter: nf_tables: double hook unregistration in netns path
+    - netfilter: nftables: update table flags from the commit phase
+    - netfilter: nf_tables: fix table flag updates
+    - netfilter: nf_tables: disable toggling dormant table state more than once
+    - netfilter: nf_tables: bogus EBUSY when deleting flowtable after flush (for
+      5.4)
+    - Linux 5.4.262
+  * Focal update: v5.4.261 upstream stable release (LP: #2049049)
+    - vfs: fix readahead(2) on block devices
+    - genirq/matrix: Exclude managed interrupts in irq_matrix_allocated()
+    - i40e: fix potential memory leaks in i40e_remove()
+    - tcp: call tcp_try_undo_recovery when an RTOd TFO SYNACK is ACKed
+    - wifi: rtw88: debug: Fix the NULL vs IS_ERR() bug for debugfs_create_file()
+    - wifi: mt76: mt7603: rework/fix rx pse hang check
+    - tcp_metrics: add missing barriers on delete
+    - tcp_metrics: properly set tp->snd_ssthresh in tcp_init_metrics()
+    - tcp_metrics: do not create an entry from tcp_init_metrics()
+    - wifi: rtlwifi: fix EDCA limit set by BT coexistence
+    - can: dev: can_restart(): don't crash kernel if carrier is OK
+    - can: dev: can_restart(): fix race condition between controller restart and
+      netif_carrier_on()
+    - thermal: core: prevent potential string overflow
+    - r8169: use tp_to_dev instead of open code
+    - r8169: fix rare issue with broken rx after link-down on RTL8125
+    - chtls: fix tp->rcv_tstamp initialization
+    - tcp: Remove one extra ktime_get_ns() from cookie_init_timestamp
+    - tcp: fix cookie_init_timestamp() overflows
+    - ACPI: sysfs: Fix create_pnp_modalias() and create_of_modalias()
+    - ipv6: avoid atomic fragment on GSO packets
+    - net: add DEV_STATS_READ() helper
+    - ipvlan: properly track tx_errors
+    - regmap: debugfs: Fix a erroneous check after snprintf()
+    - clk: qcom: clk-rcg2: Fix clock rate overflow for high parent frequencies
+    - clk: qcom: gcc-sm8150: use ARRAY_SIZE instead of specifying num_parents
+    - clk: qcom: gcc-sm8150: Fix gcc_sdcc2_apps_clk_src
+    - clk: imx: Select MXC_CLK for CLK_IMX8QXP
+    - clk: keystone: pll: fix a couple NULL vs IS_ERR() checks
+    - clk: npcm7xx: Fix incorrect kfree
+    - clk: mediatek: clk-mt6779: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt6797: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629-eth: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt2701: Add check for mtk_alloc_clk_data
+    - platform/x86: wmi: Fix probe failure when failing to register WMI devices
+    - platform/x86: wmi: remove unnecessary initializations
+    - platform/x86: wmi: Fix opening of char device
+    - hwmon: (coretemp) Fix potentially truncated sysfs attribute name
+    - drm/rockchip: vop: Fix reset of state in duplicate state crtc funcs
+    - drm/rockchip: vop: Fix call to crtc reset helper
+    - drm/radeon: possible buffer overflow
+    - drm/rockchip: cdn-dp: Fix some error handling paths in cdn_dp_probe()
+    - arm64: dts: qcom: sdm845-mtp: fix WiFi configuration
+    - ARM: dts: qcom: mdm9615: populate vsdcc fixed regulator
+    - soc: qcom: llcc cleanup to get rid of sdm845 specific driver file
+    - [Config] remove CONFIG_QCOM_SDM845_LLCC
+    - soc: qcom: Rename llcc-slice to llcc-qcom
+    - [Config] remove llcc-slice module
+    - soc: qcom: llcc: Handle a second device without data corruption
+    - firmware: ti_sci: Replace HTTP links with HTTPS ones
+    - firmware: ti_sci: Mark driver as non removable
+    - clk: scmi: Free scmi_clk allocated when the clocks with invalid info are
+      skipped
+    - hwrng: geode - fix accessing registers
+    - libnvdimm/of_pmem: Use devm_kstrdup instead of kstrdup and check its return
+      value
+    - sched/rt: Provide migrate_disable/enable() inlines
+    - nd_btt: Make BTT lanes preemptible
+    - crypto: caam/qi2 - fix Chacha20 + Poly1305 self test failure
+    - crypto: caam/jr - fix Chacha20 + Poly1305 self test failure
+    - HID: cp2112: Use irqchip template
+    - hid: cp2112: Fix duplicate workqueue initialization
+    - ARM: 9321/1: memset: cast the constant byte to unsigned char
+    - ext4: move 'ix' sanity check to corrent position
+    - scsi: ufs: core: Leave space for '\0' in utf8 desc string
+    - RDMA/hfi1: Workaround truncation compilation error
+    - sh: bios: Revive earlyprintk support
+    - ASoC: Intel: Skylake: Fix mem leak when parsing UUIDs fails
+    - ASoC: ams-delta.c: use component after check
+    - mfd: dln2: Fix double put in dln2_probe
+    - leds: pwm: simplify if condition
+    - leds: pwm: convert to atomic PWM API
+    - leds: pwm: Don't disable the PWM when the LED should be off
+    - ledtrig-cpu: Limit to 8 CPUs
+    - leds: trigger: ledtrig-cpu:: Fix 'output may be truncated' issue for 'cpu'
+    - tty: tty_jobctrl: fix pid memleak in disassociate_ctty()
+    - usb: dwc2: fix possible NULL pointer dereference caused by driver
+      concurrency
+    - dmaengine: ti: edma: handle irq_of_parse_and_map() errors
+    - misc: st_core: Do not call kfree_skb() under spin_lock_irqsave()
+    - tools: iio: privatize globals and functions in iio_generic_buffer.c file
+    - tools: iio: iio_generic_buffer: Fix some integer type and calculation
+    - tools: iio: iio_generic_buffer ensure alignment
+    - USB: usbip: fix stub_dev hub disconnect
+    - dmaengine: pxa_dma: Remove an erroneous BUG_ON() in pxad_free_desc()
+    - f2fs: fix to initialize map.m_pblk in f2fs_precache_extents()
+    - modpost: fix tee MODULE_DEVICE_TABLE built on big-endian host
+    - powerpc/xive: Fix endian conversion size
+    - powerpc/imc-pmu: Use the correct spinlock initializer.
+    - powerpc/pseries: fix potential memory leak in init_cpu_associativity()
+    - i3c: Fix potential refcount leak in i3c_master_register_new_i3c_devs
+    - rtc: pcf85363: fix wrong mask/val parameters in regmap_update_bits call
+    - pcmcia: cs: fix possible hung task and memory leak pccardd()
+    - pcmcia: ds: fix refcount leak in pcmcia_device_add()
+    - pcmcia: ds: fix possible name leak in error path in pcmcia_device_add()
+    - media: bttv: fix use after free error due to btv->timeout timer
+    - media: s3c-camif: Avoid inappropriate kfree()
+    - media: dvb-usb-v2: af9035: fix missing unlock
+    - regmap: prevent noinc writes from clobbering cache
+    - pwm: sti: Avoid conditional gotos
+    - pwm: sti: Reduce number of allocations and drop usage of chip_data
+    - pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume
+    - Input: synaptics-rmi4 - fix use after free in rmi_unregister_function()
+    - llc: verify mac len before reading mac header
+    - tipc: Change nla_policy for bearer-related names to NLA_NUL_STRING
+    - inet: shrink struct flowi_common
+    - dccp: Call security_inet_conn_request() after setting IPv4 addresses.
+    - dccp/tcp: Call security_inet_conn_request() after setting IPv6 addresses.
+    - Fix termination state for idr_for_each_entry_ul()
+    - net: stmmac: xgmac: Enable support for multiple Flexible PPS outputs
+    - net/smc: fix dangling sock under state SMC_APPFINCLOSEWAIT
+    - tg3: power down device only on SYSTEM_POWER_OFF
+    - r8169: respect userspace disabling IFF_MULTICAST
+    - netfilter: xt_recent: fix (increase) ipv6 literal buffer length
+    - netfilter: nft_redir: use `struct nf_nat_range2` throughout and deduplicate
+      eval call-backs
+    - netfilter: nat: fix ipv6 nat redirect with mapped and scoped addresses
+    - drm/syncobj: fix DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
+    - spi: spi-zynq-qspi: add spi-mem to driver kconfig dependencies
+    - fbdev: imsttfb: Fix error path of imsttfb_probe()
+    - fbdev: imsttfb: fix a resource leak in probe
+    - fbdev: fsl-diu-fb: mark wr_reg_wa() static
+    - Revert "mmc: core: Capture correct oemid-bits for eMMC cards"
+    - btrfs: use u64 for buffer sizes in the tree search ioctls
+    - Linux 5.4.261
+  * Focal update: v5.4.260 upstream stable release (LP: #2049024)
+    - mtd: rawnand: marvell: Ensure program page operations are successful
+    - selftests/ftrace: Add new test case which checks non unique symbol
+    - mcb: Return actual parsed size when reading chameleon table
+    - mcb-lpc: Reallocate memory region to avoid memory overlapping
+    - virtio_balloon: Fix endless deflation and inflation on arm64
+    - virtio-mmio: fix memory leak of vm_dev
+    - r8169: fix the KCSAN reported data-race in rtl_tx while reading
+      TxDescArray[entry].opts1
+    - r8169: fix the KCSAN reported data race in rtl_rx while reading desc->opts1
+    - treewide: Spelling fix in comment
+    - igb: Fix potential memory leak in igb_add_ethtool_nfc_entry
+    - neighbour: fix various data-races
+    - igc: Fix ambiguity in the ethtool advertising
+    - net: ieee802154: adf7242: Fix some potential buffer overflow in
+      adf7242_stats_show()
+    - r8152: Increase USB control msg timeout to 5000ms as per spec
+    - r8152: Run the unload routine if we have errors during probe
+    - r8152: Cancel hw_phy_work if we have an error in probe
+    - tcp: fix wrong RTO timeout when received SACK reneging
+    - gtp: uapi: fix GTPA_MAX
+    - gtp: fix fragmentation needed check with gso
+    - iio: exynos-adc: request second interupt only when touchscreen mode is used
+    - i2c: muxes: i2c-mux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-mux-gpmux: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-demux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: stm32f7: Fix PEC handling in case of SMBUS transfers
+    - i2c: aspeed: Fix i2c bus hang in slave read
+    - nvmem: imx: correct nregs for i.MX6ULL
+    - nvmem: imx: correct nregs for i.MX6SLL
+    - nvmem: imx: correct nregs for i.MX6UL
+    - perf/core: Fix potential NULL deref
+    - clk: Sanitize possible_parent_show to Handle Return Value of
+      of_clk_get_parent_name
+    - i40e: Fix wrong check for I40E_TXR_FLAGS_WB_ON_ITR
+    - x86/i8259: Skip probing when ACPI/MADT advertises PCAT compatibility
+    - drm/dp_mst: Fix NULL deref in get_mst_branch_device_by_guid_helper()
+    - arm64: fix a concurrency issue in emulation_proc_handler()
+    - smbdirect: missing rc checks while waiting for rdma events
+    - f2fs: fix to do sanity check on inode type during garbage collection
+    - nfsd: lock_rename() needs both directories to live on the same fs
+    - x86/mm: Simplify RESERVE_BRK()
+    - x86/mm: Fix RESERVE_BRK() for older binutils
+    - ext4: add two helper functions extent_logical_end() and pa_logical_end()
+    - ext4: avoid overlapping preallocations due to overflow
+    - ext4: fix BUG in ext4_mb_new_inode_pa() due to overflow
+    - driver: platform: Add helper for safer setting of driver_override
+    - rpmsg: Constify local variable in field store macro
+    - rpmsg: Fix kfree() of static memory on setting driver_override
+    - rpmsg: Fix calling device_lock() on non-initialized device
+    - rpmsg: glink: Release driver_override
+    - rpmsg: Fix possible refcount leak in rpmsg_register_device_override()
+    - x86: Fix .brk attribute in linker script
+    - Input: i8042 - add Fujitsu Lifebook E5411 to i8042 quirk table
+    - irqchip/stm32-exti: add missing DT IRQ flag translation
+    - dmaengine: ste_dma40: Fix PM disable depth imbalance in d40_probe
+    - Input: synaptics-rmi4 - handle reset delay when using SMBus trsnsport
+    - fbdev: atyfb: only use ioremap_uc() on i386 and ia64
+    - spi: npcm-fiu: Fix UMA reads when dummy.nbytes == 0
+    - netfilter: nfnetlink_log: silence bogus compiler warning
+    - ASoC: rt5650: fix the wrong result of key button
+    - fbdev: uvesafb: Call cn_del_callback() at the end of uvesafb_exit()
+    - scsi: mpt3sas: Fix in error path
+    - platform/x86: asus-wmi: Change ASUS_WMI_BRN_DOWN code from 0x20 to 0x2e
+    - platform/mellanox: mlxbf-tmfifo: Fix a warning message
+    - net: chelsio: cxgb4: add an error code check in t4_load_phy_fw
+    - ata: ahci: fix enum constants for gcc-13
+    - remove the sx8 block driver
+    - [Config] remove CONFIG_BLK_DEV_SX8
+    - Revert "ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver"
+    - PCI: Prevent xHCI driver from claiming AMD VanGogh USB3 DRD device
+    - usb: storage: set 1.50 as the lower bcdDevice for older "Super Top"
+      compatibility
+    - tty: 8250: Remove UC-257 and UC-431
+    - tty: 8250: Add support for additional Brainboxes UC cards
+    - tty: 8250: Add support for Brainboxes UP cards
+    - tty: 8250: Add support for Intashield IS-100
+    - Linux 5.4.260
+  * CVE-2023-51779
+    - Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+  * CVE-2023-22995
+    - usb: dwc3: dwc3-qcom: Add missing platform_device_put() in
+      dwc3_qcom_acpi_register_core
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 20 Feb 2024 19:23:08 +0800
+
+linux-ein (5.4.0-1047.54) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1047.54 -proposed tracker (LP: #2052194)
+
+  [ Ubuntu: 5.4.0-172.190 ]
+
+  * focal/linux: 5.4.0-172.190 -proposed tracker (LP: #2052220)
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+  * CVE-2023-6915
+    - ida: Fix crash in ida_free when the bitmap is empty
+  * CVE-2024-0565
+    - smb: client: fix OOB in receive_encrypted_standard()
+  * CVE-2024-0646
+    - net: tls, update curr on splice as well
+
+ -- Nathan Sweetman <nathan.sweetman@canonical.com>  Fri, 09 Feb 2024 14:33:18 +1030
+
+linux-ein (5.4.0-1046.53) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1046.53 -proposed tracker (LP: #2048256)
+
+  * [PE100A/PCIE] Incorrect PCIE Supply Configuration (LP:#2047889)
+    - dt-bindings: imx6q-pcie: Add "vph-supply" for PHY supply voltage
+    - arm64: dts: imx8mq-evk: add one regulator used to power up pcie phy
+    - PCI: imx6: Enable PHY internal regulator when supplied >3V
+    - SAUCE: arm64/dts: pe100a: add a dummy vph for pcie
+
+  * Audio device disappear after playing audio without setting (LP: #2047884)
+    - ASoC: fsl_sai: Don't disable bitclock for i.MX8MP
+
+  [ Ubuntu: 5.4.0-171.189 ]
+
+  * focal/linux: 5.4.0-171.189 -proposed tracker (LP: #2048282)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+    - [Packaging] update annotations scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2024.01.08)
+  * Page fault in RDMA ODP triggers BUG_ON during MMU notifier registration
+    (LP: #2046534)
+    - RDMA/odp: Ensure the mm is still alive before creating an implicit child
+  * Hotplugging SCSI disk in QEMU VM fails (LP: #2047382)
+    - Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
+  * CVE-2023-6040
+    - netfilter: nf_tables: Reject tables of unsupported family
+  * kernel_selftests failures on kernel-P10d-LPAR10.ppc64el.10
+    (LP: #2032641)
+    - selftests: Skip TM tests on synthetic TM implementations
+  * [Debian] autoreconstruct - Do not generate chmod -x for deleted  files
+    (LP: #2045562)
+    - [Debian] autoreconstruct - Do not generate chmod -x for deleted files
+  * CVE-2023-6931
+    - perf/core: Add a new read format to get a number of lost samples
+    - perf: Fix perf_event_validate_size()
+    - perf: Fix perf_event_validate_size() lockdep splat
+  * CVE-2023-6932
+    - ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+  * CVE-2023-6606
+    - smb: client: fix OOB in smbCalcSize()
+  * CVE-2023-45863
+    - kobject: Fix slab-out-of-bounds in fill_kobj_path()
+  * Focal update: v5.4.259 upstream stable release (LP: #2043724)
+    - RDMA/cxgb4: Check skb value for failure to allocate
+    - lib/test_meminit: fix off-by-one error in test_pages()
+    - pwm: hibvt: Explicitly set .polarity in .get_state()
+    - HID: logitech-hidpp: Fix kernel crash on receiver USB disconnect
+    - quota: Fix slow quotaoff
+    - net: prevent address rewrite in kernel_bind()
+    - drm: etvnaviv: fix bad backport leading to warning
+    - drm/msm/dsi: skip the wait for video mode done if not applicable
+    - ravb: Fix up dma_free_coherent() call in ravb_remove()
+    - ieee802154: ca8210: Fix a potential UAF in ca8210_probe
+    - mlxsw: fix mlxsw_sp2_nve_vxlan_learning_set() return type
+    - xen-netback: use default TX queue size for vifs
+    - drm/vmwgfx: fix typo of sizeof argument
+    - ixgbe: fix crash with empty VF macvlan list
+    - net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()
+    - nfc: nci: assert requested protocol is valid
+    - workqueue: Override implicit ordered attribute in
+      workqueue_apply_unbound_cpumask()
+    - dmaengine: stm32-mdma: abort resume if no ongoing transfer
+    - usb: xhci: xhci-ring: Use sysdev for mapping bounce buffer
+    - net: usb: dm9601: fix uninitialized variable use in dm9601_mdio_read
+    - usb: dwc3: Soft reset phy on probe for host
+    - usb: musb: Get the musb_qh poniter after musb_giveback
+    - usb: musb: Modify the "HWVers" register address
+    - iio: pressure: bmp280: Fix NULL pointer exception
+    - iio: pressure: dps310: Adjust Timeout Settings
+    - iio: pressure: ms5611: ms5611_prom_is_valid false negative bug
+    - mcb: remove is_added flag from mcb_device struct
+    - libceph: use kernel_connect()
+    - ceph: fix incorrect revoked caps assert in ceph_fill_file_size()
+    - Input: powermate - fix use-after-free in powermate_config_complete
+    - Input: psmouse - fix fast_reconnect function for PS/2 mode
+    - Input: xpad - add PXN V900 support
+    - cgroup: Remove duplicates in cgroup v1 tasks file
+    - pinctrl: avoid unsafe code pattern in find_pinctrl()
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call
+    - x86/cpu: Fix AMD erratum #1485 on Zen4-based CPUs
+    - dmaengine: mediatek: Fix deadlock caused by synchronize_irq()
+    - powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
+    - powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
+    - ravb: Fix use-after-free issue in ravb_tx_timeout_work()
+    - Documentation: sysctl: align cells in second content column
+    - usb: hub: Guard against accesses to uninitialized BOS descriptors
+    - Bluetooth: hci_event: Ignore NULL link key
+    - Bluetooth: Reject connection with the device which has same BD_ADDR
+    - Bluetooth: Fix a refcnt underflow problem for hci_conn
+    - Bluetooth: vhci: Fix race when opening vhci device
+    - Bluetooth: hci_event: Fix coding style
+    - Bluetooth: avoid memcmp() out of bounds warning
+    - ice: fix over-shifted variable
+    - nfc: nci: fix possible NULL pointer dereference in send_acknowledge()
+    - regmap: fix NULL deref on lookup
+    - KVM: x86: Mask LVTPC when handling a PMI
+    - netfilter: nft_payload: fix wrong mac header matching
+    - qed: fix LL2 RX buffer allocation
+    - xfrm: fix a data-race in xfrm_gen_index()
+    - xfrm: interface: use DEV_STATS_INC()
+    - net: ipv4: fix return value check in esp_remove_trailer
+    - net: ipv6: fix return value check in esp_remove_trailer
+    - net: rfkill: gpio: prevent value glitch during probe
+    - tcp: fix excessive TLP and RACK timeouts from HZ rounding
+    - tcp: tsq: relax tcp_small_queue_check() when rtx queue contains a single skb
+    - tun: prevent negative ifindex
+    - ipv4: fib: annotate races around nh->nh_saddr_genid and nh->nh_saddr
+    - net: usb: smsc95xx: Fix an error code in smsc95xx_reset()
+    - i40e: prevent crash on probe if hw registers have invalid values
+    - net/sched: sch_hfsc: upgrade 'rt' to 'sc' when it becomes a inner curve
+    - neighbor: tracing: Move pin6 inside CONFIG_IPV6=y section
+    - netfilter: nft_set_rbtree: .deactivate fails if element has expired
+    - net: pktgen: Fix interface flags printing
+    - resource: Add irqresource_disabled()
+    - ACPI: Drop acpi_dev_irqresource_disabled()
+    - ACPI: resource: Skip IRQ override on Asus Vivobook S5602ZA
+    - ACPI: resource: Add Asus ExpertBook B2502 to Asus quirks
+    - ACPI: resource: Skip IRQ override on Asus Expertbook B2402CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1502CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CBA
+    - ARM: dts: ti: omap: Fix noisy serial with overrun-throttle-ms for mapphone
+    - btrfs: return -EUCLEAN for delayed tree ref with a ref count not equals to 1
+    - btrfs: initialize start_slot in btrfs_log_prealloc_extents
+    - i2c: mux: Avoid potential false error message in i2c_mux_add_adapter
+    - overlayfs: set ctime when setting mtime and atime
+    - gpio: timberdale: Fix potential deadlock on &tgpio->lock
+    - ata: libata-eh: Fix compilation warning in ata_eh_link_report()
+    - tracing: relax trace_event_eval_update() execution with cond_resched()
+    - HID: holtek: fix slab-out-of-bounds Write in holtek_kbd_input_event
+    - Bluetooth: Avoid redundant authentication
+    - Bluetooth: hci_core: Fix build warnings
+    - wifi: mac80211: allow transmitting EAPOL frames with tainted key
+    - wifi: cfg80211: avoid leaking stack data into trace
+    - regulator/core: Revert "fix kobject release warning and memory leak in
+      regulator_register()"
+    - sky2: Make sure there is at least one frag_addr available
+    - drm: panel-orientation-quirks: Add quirk for One Mix 2S
+    - btrfs: fix some -Wmaybe-uninitialized warnings in ioctl.c
+    - HID: multitouch: Add required quirk for Synaptics 0xcd7e device
+    - Bluetooth: hci_event: Fix using memcmp when comparing keys
+    - mtd: rawnand: qcom: Unmap the right resource upon probe failure
+    - mtd: spinand: micron: correct bitmask for ecc status
+    - mtd: physmap-core: Restore map_rom fallback
+    - mmc: core: sdio: hold retuning if sdio in 1-bit mode
+    - mmc: core: Capture correct oemid-bits for eMMC cards
+    - Revert "pinctrl: avoid unsafe code pattern in find_pinctrl()"
+    - ACPI: irq: Fix incorrect return value in acpi_register_gsi()
+    - USB: serial: option: add Telit LE910C4-WWX 0x1035 composition
+    - USB: serial: option: add entry for Sierra EM9191 with new firmware
+    - USB: serial: option: add Fibocom to DELL custom modem FM101R-GL
+    - s390/pci: fix iommu bitmap allocation
+    - gpio: vf610: set value before the direction to avoid a glitch
+    - ASoC: pxa: fix a memory leak in probe()
+    - phy: mapphone-mdm6600: Fix runtime disable on probe
+    - phy: mapphone-mdm6600: Fix runtime PM for remove
+    - phy: mapphone-mdm6600: Fix pinctrl_pm handling for sleep pins
+    - Bluetooth: hci_sock: fix slab oob read in create_monitor_event
+    - Bluetooth: hci_sock: Correctly bounds check and pad HCI_MON_NEW_INDEX name
+    - xfrm6: fix inet6_dev refcount underflow problem
+    - Linux 5.4.259
+  * Focal update: v5.4.258 upstream stable release (LP: #2042107)
+    - NFS/pNFS: Report EINVAL errors from connect() to the server
+    - SUNRPC: Mark the cred for revalidation if the server rejects it
+    - tracing: Increase trace array ref count on enable and filter files
+    - ata: libahci: clear pending interrupt status
+    - ext4: remove the 'group' parameter of ext4_trim_extent
+    - ext4: add new helper interface ext4_try_to_trim_range()
+    - ext4: scope ret locally in ext4_try_to_trim_range()
+    - ext4: change s_last_trim_minblks type to unsigned long
+    - ext4: mark group as trimmed only if it was fully scanned
+    - ext4: replace the traditional ternary conditional operator with with
+      max()/min()
+    - ext4: move setting of trimmed bit into ext4_try_to_trim_range()
+    - ext4: do not let fstrim block system suspend
+    - ASoC: meson: spdifin: start hw on dai probe
+    - netfilter: nf_tables: disallow element removal on anonymous sets
+    - bpf: Avoid deadlock when using queue and stack maps from NMI
+    - selftests/tls: Add {} to avoid static checker warning
+    - selftests: tls: swap the TX and RX sockets in some tests
+    - ASoC: imx-audmix: Fix return error with devm_clk_get()
+    - i40e: Fix for persistent lldp support
+    - SAUCE: Revert "UBUNTU: SAUCE: i40e Fix GPF when deleting VMs"
+    - i40e: Remove scheduling while atomic possibility
+    - i40e: Fix warning message and call stack during rmmod i40e driver
+    - i40e: Fix VF VLAN offloading when port VLAN is configured
+    - powerpc/perf/hv-24x7: Update domain value check
+    - dccp: fix dccp_v4_err()/dccp_v6_err() again
+    - net: hns3: add 5ms delay before clear firmware reset irq source
+    - net: bridge: use DEV_STATS_INC()
+    - team: fix null-ptr-deref when team device type is changed
+    - net: rds: Fix possible NULL-pointer dereference
+    - gpio: tb10x: Fix an error handling path in tb10x_gpio_probe()
+    - i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()
+    - Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN
+    - scsi: qla2xxx: Fix update_fcport for current_topology
+    - scsi: qla2xxx: Fix deletion race condition
+    - drm/amd/display: Reinstate LFC optimization
+    - drm/amd/display: Fix LFC multiplier changing erratically
+    - drm/amd/display: prevent potential division by zero errors
+    - ata: libata: disallow dev-initiated LPM transitions to unsupported states
+    - MIPS: Alchemy: only build mmc support helpers if au1xmmc is enabled
+    - clk: tegra: fix error return case for recalc_rate
+    - ARM: dts: ti: omap: motorola-mapphone: Fix abe_clkctrl warning on boot
+    - bus: ti-sysc: Fix SYSC_QUIRK_SWSUP_SIDLE_ACT handling for uart wake-up
+    - xtensa: add default definition for XCHAL_HAVE_DIV32
+    - xtensa: iss/network: make functions static
+    - xtensa: boot: don't add include-dirs
+    - xtensa: boot/lib: fix function prototypes
+    - gpio: pmic-eic-sprd: Add can_sleep flag for PMIC EIC chip
+    - parisc: sba: Fix compile warning wrt list of SBA devices
+    - parisc: iosapic.c: Fix sparse warnings
+    - parisc: drivers: Fix sparse warning
+    - parisc: irq: Make irq_stack_union static to avoid sparse warning
+    - selftests/ftrace: Correctly enable event in instance-event.tc
+    - ring-buffer: Avoid softlockup in ring_buffer_resize()
+    - ata: libata-eh: do not clear ATA_PFLAG_EH_PENDING in ata_eh_reset()
+    - spi: nxp-fspi: reset the FLSHxCR1 registers
+    - bpf: Clarify error expectations from bpf_clone_redirect
+    - powerpc/watchpoints: Annotate atomic context in more places
+    - ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - fbdev/sh7760fb: Depend on FB=y
+    - nvme-pci: do not set the NUMA node of device if it has none
+    - watchdog: iTCO_wdt: No need to stop the timer in probe
+    - watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
+    - i40e: improve locking of mac_filter_hash
+    - i40e: always propagate error value in i40e_set_vsi_promisc()
+    - i40e: fix return of uninitialized aq_ret in i40e_set_vsi_promisc
+    - smack: Record transmuting in smk_transmuted
+    - smack: Retrieve transmuting information in smack_inode_getsecurity()
+    - Smack:- Use overlay inode label in smack_inode_copy_up()
+    - serial: 8250_port: Check IRQ data before use
+    - nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
+    - ALSA: hda: Disable power save for solving pop issue on Lenovo ThinkCentre
+      M70q
+    - ata: libata-scsi: ignore reserved bits for REPORT SUPPORTED OPERATION CODES
+    - i2c: i801: unregister tco_pdev in i801_probe() error path
+    - ring-buffer: Update "shortest_full" in polling
+    - btrfs: properly report 0 avail for very full file systems
+    - net: thunderbolt: Fix TCPv6 GSO checksum calculation
+    - ata: libata-core: Fix ata_port_request_pm() locking
+    - ata: libata-core: Fix port and device removal
+    - ata: libata-core: Do not register PM operations for SAS ports
+    - ata: libata-sata: increase PMP SRST timeout to 10s
+    - fs: binfmt_elf_efpic: fix personality for ELF-FDPIC
+    - rbd: move rbd_dev_refresh() definition
+    - rbd: decouple header read-in from updating rbd_dev->header
+    - rbd: decouple parent info read-in from updating rbd_dev
+    - rbd: take header_rwsem in rbd_dev_refresh() only when updating
+    - Revert "PCI: qcom: Disable write access to read only registers for IP
+      v2.3.3"
+    - scsi: zfcp: Fix a double put in zfcp_port_enqueue()
+    - qed/red_ll2: Fix undefined behavior bug in struct qed_ll2_info
+    - wifi: mwifiex: Fix tlv_buf_left calculation
+    - net: replace calls to sock->ops->connect() with kernel_connect()
+    - net: prevent rewrite of msg_name in sock_sendmsg()
+    - wifi: iwlwifi: dbg_ini: fix structure packing
+    - wifi: mwifiex: Fix oob check condition in mwifiex_process_rx_packet
+    - drivers/net: process the result of hdlc_open() and add call of hdlc_close()
+      in uhdlc_close()
+    - wifi: mt76: mt76x02: fix MT76x0 external LNA gain handling
+    - regmap: rbtree: Fix wrong register marked as in-cache when creating new node
+    - ima: Finish deprecation of IMA_TRUSTED_KEYRING Kconfig
+    - scsi: target: core: Fix deadlock due to recursive locking
+    - NFS4: Trace state recovery operation
+    - NFS: Add a helper nfs_client_for_each_server()
+    - NFSv4: Fix a nfs4_state_manager() race
+    - modpost: add missing else to the "of" check
+    - net: fix possible store tearing in neigh_periodic_work()
+    - ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
+    - net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent
+    - net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
+    - net: nfc: llcp: Add lock when modifying device list
+    - netfilter: handle the connecting collision properly in
+      nf_conntrack_proto_sctp
+    - net: stmmac: dwmac-stm32: fix resume on STM32 MCU
+    - tcp: fix quick-ack counting to count actual ACKs of new data
+    - tcp: fix delayed ACKs for MSS boundary condition
+    - sctp: update transport state when processing a dupcook packet
+    - sctp: update hb timer immediately after users change hb_interval
+    - cpupower: add Makefile dependencies for install targets
+    - RDMA/core: Require admin capabilities to set system parameters
+    - IB/mlx4: Fix the size of a buffer in add_port_entries()
+    - gpio: aspeed: fix the GPIO number passed to pinctrl_gpio_set_config()
+    - gpio: pxa: disable pinctrl calls for MMP_GPIO
+    - RDMA/cma: Fix truncation compilation warning in make_cma_ports
+    - RDMA/uverbs: Fix typo of sizeof argument
+    - RDMA/siw: Fix connection failure handling
+    - RDMA/mlx5: Fix NULL string error
+    - parisc: Restore __ldcw_align for PA-RISC 2.0 processors
+    - NFS: Fix a race in __nfs_list_for_each_server()
+    - ima: rework CONFIG_IMA dependency block
+    - [Config] Update IMA_BLACKLIST_KEYRING and IMA_LOAD_X509
+    - xen/events: replace evtchn_rwlock with RCU
+    - Linux 5.4.258
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 19 Jan 2024 17:10:04 +0800
+
+linux-ein (5.4.0-1045.52) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1045.52 -proposed tracker (LP: #2046958)
+
+  * While playing videos screen goes black and after some period of time it will
+    be restored (LP: #2043226)
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Add media bus format
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Add proper delay after resetting
+      display
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Fix timing when entering/exiting
+      sleep
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 21 Dec 2023 18:41:13 +0800
+
+linux-ein (5.4.0-1044.51) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1044.51 -proposed tracker (LP: #2046115)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+
+  [ Ubuntu: 5.4.0-169.187 ]
+
+  * focal/linux: 5.4.0-169.187 -proposed tracker (LP: #2044375)
+  * USB bus error after upgrading to proposed kernel on lunar, jammy and focal
+    (LP: #2043197)
+    - USB: core: Fix oversight in SuperSpeed initialization
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] update annotations scripts
+
+  [ Ubuntu: 5.4.0-168.186 ]
+
+  * focal/linux: 5.4.0-168.186 -proposed tracker (LP: #2041652)
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284)
+    - erofs: ensure that the post-EOF tails are all zeroed
+    - ARM: pxa: remove use of symbol_get()
+    - mmc: au1xmmc: force non-modular build and remove symbol_get usage
+    - net: enetc: use EXPORT_SYMBOL_GPL for enetc_phc_index
+    - rtc: ds1685: use EXPORT_SYMBOL_GPL for ds1685_rtc_poweroff
+    - modules: only allow symbol_get of EXPORT_SYMBOL_GPL modules
+    - USB: serial: option: add Quectel EM05G variant (0x030e)
+    - USB: serial: option: add FOXCONN T99W368/T99W373 product
+    - HID: wacom: remove the battery when the EKR is off
+    - staging: rtl8712: fix race condition
+    - Bluetooth: btsdio: fix use after free bug in btsdio_remove due to race
+      condition
+    - serial: sc16is7xx: fix bug when first setting GPIO direction
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - fsi: master-ast-cf: Add MODULE_FIRMWARE macro
+    - nilfs2: fix general protection fault in nilfs_lookup_dirty_data_buffers()
+    - nilfs2: fix WARNING in mark_buffer_dirty due to discarded buffer reuse
+    - pinctrl: amd: Don't show `Invalid config param` errors
+    - 9p: virtio: make sure 'offs' is initialized in zc_request
+    - ASoC: da7219: Flush pending AAD IRQ when suspending
+    - ASoC: da7219: Check for failure reading AAD IRQ events
+    - ethernet: atheros: fix return value check in atl1c_tso_csum()
+    - vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
+    - m68k: Fix invalid .section syntax
+    - s390/dasd: use correct number of retries for ERP requests
+    - s390/dasd: fix hanging device after request requeue
+    - fs/nls: make load_nls() take a const parameter
+    - ASoc: codecs: ES8316: Fix DMIC config
+    - ASoC: atmel: Fix the 8K sample parameter in I2SC master
+    - platform/x86: intel: hid: Always call BTNL ACPI method
+    - platform/x86: huawei-wmi: Silence ambient light sensor
+    - security: keys: perform capable check only on privileged operations
+    - clk: fixed-mmio: make COMMON_CLK_FIXED_MMIO depend on HAS_IOMEM
+    - net: usb: qmi_wwan: add Quectel EM05GV2
+    - idmaengine: make FSL_EDMA and INTEL_IDMA64 depends on HAS_IOMEM
+    - scsi: qedi: Fix potential deadlock on &qedi_percpu->p_work_lock
+    - netlabel: fix shift wrapping bug in netlbl_catmap_setlong()
+    - bnx2x: fix page fault following EEH recovery
+    - sctp: handle invalid error codes without calling BUG()
+    - cifs: add a warning when the in-flight count goes negative
+    - scsi: storvsc: Always set no_report_opcodes
+    - ALSA: seq: oss: Fix racy open/close of MIDI devices
+    - platform/mellanox: Fix mlxbf-tmfifo not handling all virtio CONSOLE
+      notifications
+    - powerpc/32s: Fix assembler warning about r0
+    - udf: Check consistency of Space Bitmap Descriptor
+    - udf: Handle error when adding extent to a file
+    - Revert "net: macsec: preserve ingress frame ordering"
+    - reiserfs: Check the return value from __getblk()
+    - eventfd: Export eventfd_ctx_do_read()
+    - eventfd: prevent underflow for eventfd semaphores
+    - new helper: lookup_positive_unlocked()
+    - fs: Fix error checking for d_hash_and_lookup()
+    - tmpfs: verify {g,u}id mount options correctly
+    - OPP: Fix passing 0 to PTR_ERR in _opp_attach_genpd()
+    - x86/asm: Make more symbols local
+    - x86/boot: Annotate local functions
+    - x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved
+    - perf/imx_ddr: don't enable counter0 if none of 4 counters are used
+    - cpufreq: powernow-k8: Use related_cpus instead of cpus in driver.exit()
+    - bpf: Clear the probe_addr for uprobe
+    - tcp: tcp_enter_quickack_mode() should be static
+    - regmap: rbtree: Use alloc_flags for memory allocations
+    - spi: tegra20-sflash: fix to check return value of platform_get_irq() in
+      tegra_sflash_probe()
+    - can: gs_usb: gs_usb_receive_bulk_callback(): count RX overflow errors also
+      in case of OOM
+    - wifi: mwifiex: Fix OOB and integer underflow when rx packets
+    - mwifiex: switch from 'pci_' to 'dma_' API
+    - wifi: mwifiex: fix error recovery in PCIE buffer descriptor management
+    - crypto: stm32 - Properly handle pm_runtime_get failing
+    - Bluetooth: nokia: fix value check in nokia_bluetooth_serdev_probe()
+    - crypto: caam - fix unchecked return value error
+    - hwrng: iproc-rng200 - use semicolons rather than commas to separate
+      statements
+    - hwrng: iproc-rng200 - Implement suspend and resume calls
+    - lwt: Fix return values of BPF xmit ops
+    - lwt: Check LWTUNNEL_XMIT_CONTINUE strictly
+    - fs: ocfs2: namei: check return value of ocfs2_add_entry()
+    - wifi: mwifiex: fix memory leak in mwifiex_histogram_read()
+    - wifi: mwifiex: Fix missed return in oob checks failed path
+    - wifi: ath9k: fix races between ath9k_wmi_cmd and ath9k_wmi_ctrl_rx
+    - wifi: ath9k: protect WMI command response buffer replacement with a lock
+    - wifi: mwifiex: avoid possible NULL skb pointer dereference
+    - wifi: ath9k: use IS_ERR() with debugfs_create_dir()
+    - net: arcnet: Do not call kfree_skb() under local_irq_disable()
+    - mlxsw: i2c: Fix chunk size setting in output mailbox buffer
+    - mlxsw: i2c: Limit single transaction buffer size
+    - netrom: Deny concurrent connect().
+    - drm/bridge: tc358764: Fix debug print parameter order
+    - quota: avoid increasing DQST_LOOKUPS when iterating over dirty/inuse list
+    - quota: factor out dquot_write_dquot()
+    - quota: rename dquot_active() to inode_quota_active()
+    - quota: add new helper dquot_active()
+    - quota: fix dqput() to follow the guarantees dquot_srcu should provide
+    - drm/amdgpu: avoid integer overflow warning in amdgpu_device_resize_fb_bar()
+    - ARM: dts: BCM53573: Drop nonexistent "default-off" LED trigger
+    - ARM: dts: BCM53573: Add cells sizes to PCIe node
+    - ARM: dts: BCM53573: Use updated "spi-gpio" binding properties
+    - drm/etnaviv: fix dumping of active MMU context
+    - ARM: dts: s3c6410: move fixed clocks under root node in Mini6410
+    - ARM: dts: s3c6410: align node SROM bus node name with dtschema in Mini6410
+    - ARM: dts: s3c64xx: align pinctrl with dtschema
+    - ARM: dts: samsung: s3c6410-mini6410: correct ethernet reg addresses (split)
+    - ARM: dts: s5pv210: add RTC 32 KHz clock in SMDKV210
+    - ARM: dts: s5pv210: use defines for IRQ flags in SMDKV210
+    - ARM: dts: s5pv210: correct ethernet unit address in SMDKV210
+    - ARM: dts: s5pv210: add dummy 5V regulator for backlight on SMDKv210
+    - ARM: dts: samsung: s5pv210-smdkv210: correct ethernet reg addresses (split)
+    - drm: adv7511: Fix low refresh rate register for ADV7533/5
+    - ARM: dts: BCM53573: Fix Ethernet info for Luxul devices
+    - arm64: dts: qcom: sdm845: Add missing RPMh power domain to GCC
+    - drm/amdgpu: Update min() to min_t() in 'amdgpu_info_ioctl'
+    - md/bitmap: don't set max_write_behind if there is no write mostly device
+    - md/md-bitmap: hold 'reconfig_mutex' in backlog_store()
+    - drm/tegra: Remove superfluous error messages around platform_get_irq()
+    - drm/tegra: dpaux: Fix incorrect return value of platform_get_irq
+    - of: unittest: fix null pointer dereferencing in
+      of_unittest_find_node_by_name()
+    - drm/armada: Fix off-by-one error in armada_overlay_get_property()
+    - drm/panel: simple: Add missing connector type and pixel format for AUO
+      T215HVN01
+    - ima: Remove deprecated IMA_TRUSTED_KEYRING Kconfig
+    - [Config] Update annotations after CONFIG_IMA_TRUSTED_KEYRING removal
+    - drm/msm/mdp5: Don't leak some plane state
+    - smackfs: Prevent underflow in smk_set_cipso()
+    - audit: fix possible soft lockup in __audit_inode_child()
+    - drm/mediatek: Fix potential memory leak if vmap() fail
+    - of: unittest: Fix overlay type in apply/revert check
+    - ALSA: ac97: Fix possible error value of *rac97
+    - ipmi:ssif: Add check for kstrdup
+    - ipmi:ssif: Fix a memory leak when scanning for an adapter
+    - drivers: clk: keystone: Fix parameter judgment in _of_pll_clk_init()
+    - clk: sunxi-ng: Modify mismatched function name
+    - PCI: Mark NVIDIA T4 GPUs to avoid bus reset
+    - PCI: pciehp: Use RMW accessors for changing LNKCTL
+    - PCI/ASPM: Use RMW accessors for changing LNKCTL
+    - clk: imx: composite-8m: fix clock pauses when set_rate would be a no-op
+    - powerpc/fadump: reset dump area size if fadump memory reserve fails
+    - PCI: Add #defines for Enter Compliance, Transmit Margin
+    - drm/amdgpu: Correct Transmit Margin masks
+    - drm/amdgpu: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/amdgpu: Prefer pcie_capability_read_word()
+    - drm/amdgpu: Use RMW accessors for changing LNKCTL
+    - drm/radeon: Correct Transmit Margin masks
+    - drm/radeon: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/radeon: Prefer pcie_capability_read_word()
+    - drm/radeon: Use RMW accessors for changing LNKCTL
+    - wifi: ath10k: Use RMW accessors for changing LNKCTL
+    - nfs/blocklayout: Use the passed in gfp flags
+    - powerpc/iommu: Fix notifiers being shared by PCI and VIO buses
+    - jfs: validate max amount of blocks before allocation.
+    - fs: lockd: avoid possible wrong NULL parameter
+    - NFSD: da_addr_body field missing in some GETDEVICEINFO replies
+    - NFS: Guard against READDIR loop when entry names exceed MAXNAMELEN
+    - media: v4l2-fwnode: fix v4l2_fwnode_parse_link handling
+    - media: v4l2-fwnode: simplify v4l2_fwnode_parse_link
+    - media: v4l2-core: Fix a potential resource leak in v4l2_fwnode_parse_link()
+    - drivers: usb: smsusb: fix error handling code in smsusb_init_device
+    - media: dib7000p: Fix potential division by zero
+    - media: dvb-usb: m920x: Fix a potential memory leak in m920x_i2c_xfer()
+    - media: cx24120: Add retval check for cx24120_message_send()
+    - media: mediatek: vcodec: Return NULL if no vdec_fb is found
+    - usb: phy: mxs: fix getting wrong state with mxs_phy_is_otg_host()
+    - scsi: iscsi: Add strlen() check in iscsi_if_set{_host}_param()
+    - scsi: be2iscsi: Add length check when parsing nlattrs
+    - scsi: qla4xxx: Add length check when parsing nlattrs
+    - serial: sprd: getting port index via serial aliases only
+    - serial: sprd: remove redundant sprd_port cleanup
+    - serial: sprd: Assign sprd_port after initialized to avoid wrong access
+    - serial: sprd: Fix DMA buffer leak issue
+    - x86/APM: drop the duplicate APM_MINOR_DEV macro
+    - scsi: qedf: Do not touch __user pointer in
+      qedf_dbg_stop_io_on_error_cmd_read() directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_debug_cmd_read()
+      directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_fp_int_cmd_read()
+      directly
+    - coresight: tmc: Explicit type conversions to prevent integer overflow
+    - dma-buf/sync_file: Fix docs syntax
+    - driver core: test_async: fix an error code
+    - IB/uverbs: Fix an potential error pointer dereference
+    - iommu/vt-d: Fix to flush cache of PASID directory table
+    - media: go7007: Remove redundant if statement
+    - USB: gadget: f_mass_storage: Fix unused variable warning
+    - media: i2c: ov5640: Configure HVP lines in s_power callback
+    - media: ov5640: Enable MIPI interface in ov5640_set_power_mipi()
+    - media: i2c: ov2680: Set V4L2_CTRL_FLAG_MODIFY_LAYOUT on flips
+    - media: ov2680: Remove auto-gain and auto-exposure controls
+    - media: ov2680: Fix ov2680_bayer_order()
+    - media: ov2680: Fix vflip / hflip set functions
+    - media: ov2680: Fix regulators being left enabled on ov2680_power_on() errors
+    - scsi: core: Use 32-bit hostnum in scsi_host_lookup()
+    - scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
+    - serial: tegra: handle clk prepare error in tegra_uart_hw_init()
+    - amba: bus: fix refcount leak
+    - Revert "IB/isert: Fix incorrect release of isert connection"
+    - RDMA/siw: Balance the reference of cep->kref in the error path
+    - RDMA/siw: Correct wrong debug message
+    - HID: logitech-dj: Fix error handling in logi_dj_recv_switch_to_dj_mode()
+    - HID: multitouch: Correct devm device reference for hidinput input_dev name
+    - x86/speculation: Mark all Skylake CPUs as vulnerable to GDS
+    - tracing: Fix race issue between cpu buffer write and swap
+    - phy/rockchip: inno-hdmi: use correct vco_div_5 macro on rk3328
+    - phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 recalc_rate
+    - phy/rockchip: inno-hdmi: do not power on rk3328 post pll on reg write
+    - rpmsg: glink: Add check for kstrdup
+    - mtd: rawnand: fsmc: handle clk prepare error in fsmc_nand_resume()
+    - um: Fix hostaudio build errors
+    - dmaengine: ste_dma40: Add missing IRQ check in d40_probe
+    - cpufreq: Fix the race condition while updating the transition_task of policy
+    - virtio_ring: fix avail_wrap_counter in virtqueue_add_packed
+    - skbuff: skb_segment, Call zero copy functions before using skbuff frags
+    - PM / devfreq: Fix leak in devfreq_dev_release()
+    - ALSA: pcm: Fix missing fixup call in compat hw_refine ioctl
+    - ipmi_si: fix a memleak in try_smi_init()
+    - ARM: OMAP2+: Fix -Warray-bounds warning in _pwrdm_state_switch()
+    - backlight/gpio_backlight: Compare against struct fb_info.device
+    - backlight/bd6107: Compare against struct fb_info.device
+    - backlight/lv5207lp: Compare against struct fb_info.device
+    - xtensa: PMU: fix base address for the newer hardware
+    - media: dvb: symbol fixup for dvb_attach()
+    - ntb: Drop packets when qp link is down
+    - ntb: Clean up tx tail index on link down
+    - ntb: Fix calculation ntb_transport_tx_free_entry()
+    - Revert "PCI: Mark NVIDIA T4 GPUs to avoid bus reset"
+    - procfs: block chmod on /proc/thread-self/comm
+    - parisc: Fix /proc/cpuinfo output for lscpu
+    - dlm: fix plock lookup when using multiple lockspaces
+    - dccp: Fix out of bounds access in DCCP error handler
+    - X.509: if signature is unsupported skip validation
+    - net: handle ARPHRD_PPP in dev_is_mac_header_xmit()
+    - fsverity: skip PKCS#7 parser when keyring is empty
+    - pstore/ram: Check start of empty przs during init
+    - s390/ipl: add missing secure/has_secure file to ipl type 'unknown'
+    - crypto: stm32 - fix loop iterating through scatterlist for DMA
+    - cpufreq: brcmstb-avs-cpufreq: Fix -Warray-bounds bug
+    - sc16is7xx: Set iobase to device index
+    - serial: sc16is7xx: fix broken port 0 uart init
+    - usb: typec: tcpci: clear the fault status bit
+    - udf: initialize newblock to 0
+    - drm: fix double free for gbo in drm_gem_vram_init and drm_gem_vram_create
+    - net/ipv6: SKB symmetric hash should incorporate transport ports
+    - scsi: qla2xxx: fix inconsistent TMF timeout
+    - scsi: qla2xxx: Fix erroneous link up failure
+    - scsi: qla2xxx: Turn off noisy message log
+    - scsi: qla2xxx: Remove unsupported ql2xenabledif option
+    - fbdev/ep93xx-fb: Do not assign to struct fb_info.dev
+    - drm/ast: Fix DRAM init on AST2200
+    - lib/test_meminit: allocate pages up to order MAX_ORDER
+    - parisc: led: Fix LAN receive and transmit LEDs
+    - parisc: led: Reduce CPU overhead for disk & lan LED computation
+    - clk: qcom: gcc-mdm9615: use proper parent for pll0_vote clock
+    - soc: qcom: qmi_encdec: Restrict string length in decode
+    - NFSv4/pnfs: minor fix for cleanup path in nfs4_get_device_info
+    - kconfig: fix possible buffer overflow
+    - perf annotate bpf: Don't enclose non-debug code with an assert()
+    - x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm()
+    - perf top: Don't pass an ERR_PTR() directly to perf_session__delete()
+    - watchdog: intel-mid_wdt: add MODULE_ALIAS() to allow auto-load
+    - pwm: lpc32xx: Remove handling of PWM channels
+    - sctp: annotate data-races around sk->sk_wmem_queued
+    - ipv4: annotate data-races around fi->fib_dead
+    - net: read sk->sk_family once in sk_mc_loop()
+    - igb: disable virtualization features on 82580
+    - veth: Fixing transmit return status for dropped packets
+    - net: ipv6/addrconf: avoid integer underflow in ipv6_create_tempaddr
+    - af_unix: Fix data-races around user->unix_inflight.
+    - af_unix: Fix data-race around unix_tot_inflight.
+    - af_unix: Fix data-races around sk->sk_shutdown.
+    - af_unix: Fix data race around sk->sk_err.
+    - kcm: Destroy mutex in kcm_exit_net()
+    - igc: Change IGC_MIN to allow set rx/tx value between 64 and 80
+    - igbvf: Change IGBVF_MIN to allow set rx/tx value between 64 and 80
+    - igb: Change IGB_MIN to allow set rx/tx value between 64 and 80
+    - s390/zcrypt: don't leak memory if dev_set_name() fails
+    - idr: fix param name in idr_alloc_cyclic() doc
+    - ip_tunnels: use DEV_STATS_INC()
+    - net: hns3: fix the port information display when sfp is absent
+    - sh: boards: Fix CEU buffer size passed to dma_declare_coherent_memory()
+    - ata: sata_gemini: Add missing MODULE_DESCRIPTION
+    - ata: pata_ftide010: Add missing MODULE_DESCRIPTION
+    - fuse: nlookup missing decrement in fuse_direntplus_link
+    - btrfs: don't start transaction when joining with TRANS_JOIN_NOSTART
+    - btrfs: use the correct superblock to compare fsid in btrfs_validate_super
+    - mtd: rawnand: brcmnand: Fix crash during the panic_write
+    - mtd: rawnand: brcmnand: Fix potential out-of-bounds access in oob write
+    - mtd: rawnand: brcmnand: Fix potential false time out warning
+    - perf hists browser: Fix hierarchy mode header
+    - perf tools: Handle old data in PERF_RECORD_ATTR
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request payload handling
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request
+    - usb: typec: bus: verify partner exists in typec_altmode_attention
+    - ARM: dts: BCM5301X: Extend RAM to full 256MB for Linksys EA6500 V2
+    - clk: imx8mm: Move 1443X/1416X PLL clock structure to common place
+    - net: ipv4: fix one memleak in __inet_del_ifa()
+    - net: ethernet: mvpp2_main: fix possible OOB write in
+      mvpp2_ethtool_get_rxnfc()
+    - net: ethernet: mtk_eth_soc: fix possible NULL pointer dereference in
+      mtk_hwlro_get_fdir_all()
+    - r8152: check budget for r8152_poll()
+    - kcm: Fix memory leak in error path of kcm_sendmsg()
+    - platform/mellanox: mlxbf-tmfifo: Drop the Rx packet if no more descriptors
+    - mlxbf-tmfifo: sparse tags for config access
+    - platform/mellanox: mlxbf-tmfifo: Drop jumbo frames
+    - net/tls: do not free tls_rec on async operation in bpf_exec_tx_verdict()
+    - ixgbe: fix timestamp configuration code
+    - kcm: Fix error handling for SOCK_DGRAM in kcm_sendmsg().
+    - drm/amd/display: Fix a bug when searching for insert_above_mpcc
+    - parisc: Drop loops_per_jiffy from per_cpu struct
+    - autofs: fix memory leak of waitqueues in autofs_catatonic_mode
+    - btrfs: output extra debug info if we failed to find an inline backref
+    - locks: fix KASAN: use-after-free in trace_event_raw_event_filelock_lock
+    - ACPICA: Add AML_NO_OPERAND_RESOLVE flag to Timer
+    - kernel/fork: beware of __put_task_struct() calling context
+    - ACPI: video: Add backlight=native DMI quirk for Lenovo Ideapad Z470
+    - perf/smmuv3: Enable HiSilicon Erratum 162001900 quirk for HIP08/09
+    - hw_breakpoint: fix single-stepping when using bpf_overflow_handler
+    - devlink: remove reload failed checks in params get/set callbacks
+    - wifi: ath9k: fix printk specifier
+    - wifi: mwifiex: fix fortify warning
+    - crypto: lib/mpi - avoid null pointer deref in mpi_cmp_ui()
+    - tpm_tis: Resend command to recover from data transfer errors
+    - mmc: sdhci-esdhc-imx: improve ESDHC_FLAG_ERR010450
+    - alx: fix OOB-read compiler warning
+    - wifi: mac80211_hwsim: drop short frames
+    - drm/exynos: fix a possible null-pointer dereference due to data race in
+      exynos_drm_crtc_atomic_disable()
+    - bus: ti-sysc: Configure uart quirks for k3 SoC
+    - md: raid1: fix potential OOB in raid1_remove_disk()
+    - ext2: fix datatype of block number in ext2_xattr_set2()
+    - fs/jfs: prevent double-free in dbUnmount() after failed jfs_remount()
+    - jfs: fix invalid free of JFS_IP(ipimap)->i_imap in diUnmount
+    - powerpc/pseries: fix possible memory leak in ibmebus_bus_init()
+    - media: dvb-usb-v2: af9035: Fix null-ptr-deref in af9035_i2c_master_xfer
+    - media: dw2102: Fix null-ptr-deref in dw2102_i2c_transfer()
+    - media: af9005: Fix null-ptr-deref in af9005_i2c_xfer
+    - media: anysee: fix null-ptr-deref in anysee_master_xfer
+    - media: az6007: Fix null-ptr-deref in az6007_i2c_xfer()
+    - media: tuners: qt1010: replace BUG_ON with a regular error
+    - media: pci: cx23885: replace BUG with error return
+    - usb: gadget: fsl_qe_udc: validate endpoint index for ch9 udc
+    - scsi: target: iscsi: Fix buffer overflow in lio_target_nacl_info_show()
+    - serial: cpm_uart: Avoid suspicious locking
+    - media: pci: ipu3-cio2: Initialise timing struct to avoid a compiler warning
+    - kobject: Add sanity check for kset->kobj.ktype in kset_register()
+    - tools features: Add feature test to check if libbfd has buildid support
+    - perf jevents: Make build dependency on test JSONs
+    - perf tools: Add an option to build without libbfd
+    - btrfs: move btrfs_pinned_by_swapfile prototype into volumes.h
+    - btrfs: add a helper to read the superblock metadata_uuid
+    - btrfs: compare the correct fsid/metadata_uuid in btrfs_validate_super
+    - selftests: tracing: Fix to unmount tracefs for recovering environment
+    - md/raid1: fix error: ISO C90 forbids mixed declarations
+    - attr: block mode changes of symlinks
+    - btrfs: fix lockdep splat and potential deadlock after failure running
+      delayed items
+    - tracing: Have current_trace inc the trace array ref count
+    - tracing: Have option files inc the trace array ref count
+    - nfsd: fix change_info in NFSv4 RENAME replies
+    - tracefs: Add missing lockdown check to tracefs_create_dir()
+    - i2c: aspeed: Reset the i2c controller when timeout occurs
+    - scsi: megaraid_sas: Fix deadlock on firmware crashdump
+    - ext4: fix rec_len verify error
+    - mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
+    - drm/amdgpu: fix amdgpu_cs_p1_user_fence
+    - Linux 5.4.257
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284) //
+    CVE-2023-39189
+    - netfilter: nfnetlink_osf: avoid OOB read
+  * CVE-2023-45871
+    - igb: set max size RX buffer when store bad packet is enabled
+  * CVE-2023-39193
+    - netfilter: xt_sctp: validate the flag_info count
+  * CVE-2023-39192
+    - netfilter: xt_u32: validate user space input
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+  * CVE-2023-5717
+    - perf: Disallow mis-matched inherited group reads
+  * CVE-2023-5178
+    - nvmet-tcp: move send/recv error handling in the send/recv methods instead of
+      call-sites
+    - nvmet-tcp: Fix a possible UAF in queue intialization setup
+  * CVE-2023-42754
+    - ipv4: fix null-deref in ipv4_link_failure
+  * Focal update: v5.4.256 upstream stable release (LP: #2039446)
+    - powerpc/pmac/smp: Avoid unused-variable warnings
+    - powerpc/pmac/smp: Drop unnecessary volatile qualifier
+    - Revert "MIPS: Alchemy: fix dbdma2"
+    - Linux 5.4.256
+  * Focal update: v5.4.255 upstream stable release (LP: #2039440)
+    - mmc: sdhci_f_sdh30: convert to devm_platform_ioremap_resource
+    - mmc: sdhci-f-sdh30: Replace with sdhci_pltfm
+    - selftests: forwarding: tc_flower: Relax success criterion
+    - macsec: Fix traffic counters/statistics
+    - macsec: use DEV_STATS_INC()
+    - drm/radeon: Fix integer overflow in radeon_cs_parser_init
+    - ALSA: emu10k1: roll up loops in DSP setup code for Audigy
+    - quota: Properly disable quotas when add_dquot_ref() fails
+    - quota: fix warning in dqgrab()
+    - HID: add quirk for 03f0:464a HP Elite Presenter Mouse
+    - ovl: check type and offset of struct vfsmount in ovl_entry
+    - udf: Fix uninitialized array access for some pathnames
+    - fs: jfs: Fix UBSAN: array-index-out-of-bounds in dbAllocDmapLev
+    - MIPS: dec: prom: Address -Warray-bounds warning
+    - FS: JFS: Fix null-ptr-deref Read in txBegin
+    - FS: JFS: Check for read-only mounted filesystem in txBegin
+    - media: v4l2-mem2mem: add lock to protect parameter num_rdy
+    - media: platform: mediatek: vpu: fix NULL ptr dereference
+    - usb: chipidea: imx: don't request QoS for imx8ulp
+    - gfs2: Fix possible data races in gfs2_show_options()
+    - pcmcia: rsrc_nonstatic: Fix memory leak in nonstatic_release_resource_db()
+    - Bluetooth: L2CAP: Fix use-after-free
+    - drm/amdgpu: Fix potential fence use-after-free v2
+    - ALSA: hda/realtek: Add quirks for Unis H3C Desktop B760 & Q760
+    - ALSA: hda: fix a possible null-pointer dereference due to data race in
+      snd_hdac_regmap_sync()
+    - powerpc/kasan: Disable KCOV in KASAN code
+    - IMA: allow/fix UML builds
+    - iio: add addac subdirectory
+    - iio: adc: stx104: Utilize iomap interface
+    - iio: adc: stx104: Implement and utilize register structures
+    - iio: stx104: Move to addac subdirectory
+    - iio: addac: stx104: Fix race condition for stx104_write_raw()
+    - iio: addac: stx104: Fix race condition when converting analog-to-digital
+    - iommu/amd: Fix "Guest Virtual APIC Table Root Pointer" configuration in IRTE
+    - PM-runtime: add tracepoints for usage_count changes
+    - PM: runtime: Add pm_runtime_get_if_active()
+    - ALSA: hda: Fix unhandled register update during auto-suspend period
+    - irqchip/mips-gic: Get rid of the reliance on irq_cpu_online()
+    - irqchip/mips-gic: Use raw spinlock for gic_lock
+    - interconnect: Move internal structs into a separate file
+    - interconnect: Add helpers for enabling/disabling a path
+    - usb: dwc3: qcom: Add helper functions to enable,disable wake irqs
+    - USB: dwc3: qcom: fix NULL-deref on suspend
+    - mmc: bcm2835: fix deferred probing
+    - mmc: sunxi: fix deferred probing
+    - leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on dev rename
+    - tracing/probes: Have process_fetch_insn() take a void * instead of pt_regs
+    - tracing/probes: Fix to update dynamic data counter if fetcharg uses it
+    - net/ncsi: Fix gma flag setting after response
+    - nfsd4: kill warnings on testing stateids with mismatched clientids
+    - nfsd: Remove incorrect check in nfsd4_validate_stateid
+    - virtio-mmio: convert to devm_platform_ioremap_resource
+    - virtio-mmio: Use to_virtio_mmio_device() to simply code
+    - virtio-mmio: don't break lifecycle of vm_dev
+    - i2c: bcm-iproc: Fix bcm_iproc_i2c_isr deadlock issue
+    - fbdev: mmp: fix value check in mmphw_probe()
+    - powerpc/rtas_flash: allow user copy to flash block cache objects
+    - tty: serial: fsl_lpuart: Clear the error flags by writing 1 for lpuart32
+      platforms
+    - btrfs: fix BUG_ON condition in btrfs_cancel_balance
+    - net: xfrm: Fix xfrm_address_filter OOB read
+    - net: af_key: fix sadb_x_filter validation
+    - xfrm: interface: rename xfrm_interface.c to xfrm_interface_core.c
+    - xfrm: fix slab-use-after-free in decode_session6
+    - ip6_vti: fix slab-use-after-free in decode_session6
+    - ip_vti: fix potential slab-use-after-free in decode_session6
+    - selftests: mirror_gre_changes: Tighten up the TTL test match
+    - ipvs: fix racy memcpy in proc_do_sync_threshold
+    - netfilter: nft_dynset: disallow object maps
+    - team: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - i40e: fix misleading debug logs
+    - net: dsa: mv88e6xxx: Wait for EEPROM done before HW reset
+    - sock: Fix misuse of sk_under_memory_pressure()
+    - net: do not allow gso_size to be set to GSO_BY_FRAGS
+    - bus: ti-sysc: Improve reset to work with modules with no sysconfig
+    - bus: ti-sysc: Flush posted write on enable before reset
+    - ARM: dts: imx7s: Drop dma-apb interrupt-names
+    - ARM: dts: imx: Adjust dma-apbh node name
+    - ARM: dts: imx: Set default tuning step for imx7d usdhc
+    - ARM: dts: imx: Set default tuning step for imx6sx usdhc
+    - ASoC: rt5665: add missed regulator_bulk_disable
+    - ASoC: meson: axg-tdm-formatter: fix channel slot allocation
+    - serial: 8250: Fix oops for port->pm on uart_change_pm()
+    - ALSA: usb-audio: Add support for Mythware XA001AU capture and playback
+      interfaces.
+    - cifs: Release folio lock on fscache read hit.
+    - mmc: wbsd: fix double mmc_free_host() in wbsd_init()
+    - mmc: block: Fix in_flight[issue_type] value error
+    - netfilter: set default timeout to 3 secs for sctp shutdown send and recv
+      state
+    - virtio-net: set queues after driver_ok
+    - net: fix the RTO timer retransmitting skb every 1ms if linear option is
+      enabled
+    - net: xfrm: Amend XFRMA_SEC_CTX nla_policy structure
+    - mmc: f-sdh30: fix order of function calls in sdhci_f_sdh30_remove
+    - net: phy: broadcom: stub c45 read/write for 54810
+    - PCI: acpiphp: Reassign resources on bridge if necessary
+    - dlm: improve plock logging if interrupted
+    - dlm: replace usage of found with dedicated list iterator variable
+    - fs: dlm: add pid to debug log
+    - fs: dlm: change plock interrupted message to debug again
+    - fs: dlm: use dlm_plock_info for do_unlock_close
+    - fs: dlm: fix mismatch of plock results from userspace
+    - MIPS: cpu-features: Enable octeon_cache by cpu_type
+    - MIPS: cpu-features: Use boot_cpu_type for CPU type based features
+    - fbdev: Improve performance of sys_imageblit()
+    - fbdev: Fix sys_imageblit() for arbitrary image widths
+    - fbdev: fix potential OOB read in fast_imageblit()
+    - dm integrity: increase RECALC_SECTORS to improve recalculate speed
+    - dm integrity: reduce vmalloc space footprint on 32-bit architectures
+    - ALSA: pcm: Set per-card upper limit of PCM buffer allocations
+    - ALSA: pcm: Use SG-buffer only when direct DMA is available
+    - ALSA: pcm: Fix potential data race at PCM memory allocation helpers
+    - regmap: Account for register length in SMBus I/O limits
+    - ASoC: fsl_sai: Refine enable/disable TE/RE sequence in trigger()
+    - ASoC: fsl_sai: Add new added registers and new bit definition
+    - ASoC: fsl_sai: Disable bit clock with transmitter
+    - drm/amd/display: do not wait for mpc idle if tg is disabled
+    - drm/amd/display: check TG is non-null before checking if enabled
+    - tracing: Fix memleak due to race between current_tracer and trace
+    - octeontx2-af: SDP: fix receive link config
+    - sock: annotate data-races around prot->memory_pressure
+    - dccp: annotate data-races in dccp_poll()
+    - ipvlan: Fix a reference count leak warning in ipvlan_ns_exit()
+    - net: bgmac: Fix return value check for fixed_phy_register()
+    - net: bcmgenet: Fix return value check for fixed_phy_register()
+    - net: validate veth and vxcan peer ifindexes
+    - igb: Avoid starting unnecessary workqueues
+    - net/sched: fix a qdisc modification with ambiguous command request
+    - net: remove bond_slave_has_mac_rcu()
+    - bonding: fix macvlan over alb bond support
+    - ibmveth: Use dcbf rather than dcbfl
+    - NFSv4: Fix dropped lock for racing OPEN and delegation return
+    - clk: Fix slab-out-of-bounds error in devm_clk_release()
+    - nfsd: Fix race to FREE_STATEID and cl_revoked
+    - batman-adv: Trigger events for auto adjusted MTU
+    - batman-adv: Don't increase MTU when set by user
+    - batman-adv: Do not get eth header before batadv_check_management_packet
+    - batman-adv: Fix TT global entry leak when client roamed back
+    - batman-adv: Fix batadv_v_ogm_aggr_send memory leak
+    - batman-adv: Hold rtnl lock during MTU update via netlink
+    - lib/clz_ctz.c: Fix __clzdi2() and __ctzdi2() for 32-bit kernels
+    - radix tree: remove unused variable
+    - media: vcodec: Fix potential array out-of-bounds in encoder queue_setup
+    - PCI: acpiphp: Use pci_assign_unassigned_bridge_resources() only for non-root
+      bus
+    - drm/display/dp: Fix the DP DSC Receiver cap size
+    - mm: allow a controlled amount of unfairness in the page lock
+    - rtnetlink: Reject negative ifindexes in RTM_NEWLINK
+    - ALSA: pcm: Fix build error on m68k and others
+    - Revert "ALSA: pcm: Use SG-buffer only when direct DMA is available"
+    - interconnect: Do not skip aggregation for disabled paths
+    - ALSA: pcm: Check for null pointer of pointer substream before dereferencing
+      it
+    - Documentation/sysctl: document page_lock_unfairness
+    - irqchip/mips-gic: Don't touch vl_map if a local interrupt is not routable
+    - scsi: snic: Fix double free in snic_tgt_create()
+    - scsi: core: raid_class: Remove raid_component_add()
+    - clk: Fix undefined reference to `clk_rate_exclusive_{get,put}'
+    - pinctrl: renesas: rza2: Add lock around
+      pinctrl_generic{{add,remove}_group,{add,remove}_function}
+    - dma-buf/sw_sync: Avoid recursive lock during fence signal
+    - Linux 5.4.255
+  * Focal update: v5.4.254 upstream stable release (LP: #2039291)
+    - mmc: moxart: read scr register without changing byte order
+    - ipv6: adjust ndisc_is_useropt() to also return true for PIO
+    - dmaengine: pl330: Return DMA_PAUSED when transaction is paused
+    - drm/nouveau/gr: enable memory loads on helper invocation on all channels
+    - radix tree test suite: fix incorrect allocation size for pthreads
+    - nilfs2: fix use-after-free of nilfs_root in dirtying inodes via iput
+    - iio: cros_ec: Fix the allocation size for cros_ec_command
+    - binder: fix memory leak in binder_init()
+    - usb-storage: alauda: Fix uninit-value in alauda_check_media()
+    - usb: dwc3: Properly handle processing of pending events
+    - usb: common: usb-conn-gpio: Prevent bailing out if initial role is none
+    - x86/cpu/amd: Enable Zenbleed fix for AMD Custom APU 0405
+    - x86/mm: Fix VDSO and VVAR placement on 5-level paging machines
+    - x86: Move gds_ucode_mitigated() declaration to header
+    - drm/nouveau/disp: Revert a NULL check inside nouveau_connector_get_modes
+    - selftests/rseq: Fix build with undefined __weak
+    - mISDN: Update parameter type of dsp_cmx_send()
+    - net/packet: annotate data-races around tp->status
+    - bonding: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - dccp: fix data-race around dp->dccps_mss_cache
+    - drivers: net: prevent tun_build_skb() to exceed the packet size limit
+    - IB/hfi1: Fix possible panic during hotplug remove
+    - wifi: cfg80211: fix sband iftype data lookup for AP_VLAN
+    - dmaengine: mcf-edma: Fix a potential un-allocated memory access
+    - net/mlx5: Allow 0 for total host VFs
+    - ibmvnic: Handle DMA unmapping of login buffs in release functions
+    - btrfs: don't stop integrity writeback too early
+    - btrfs: set cache_block_group_error if we find an error
+    - nvme-tcp: fix potential unbalanced freeze & unfreeze
+    - nvme-rdma: fix potential unbalanced freeze & unfreeze
+    - netfilter: nf_tables: report use refcount overflow
+    - scsi: core: Fix legacy /proc parsing buffer overflow
+    - scsi: storvsc: Fix handling of virtual Fibre Channel timeouts
+    - scsi: 53c700: Check that command slot is not NULL
+    - scsi: snic: Fix possible memory leak if device_add() fails
+    - scsi: core: Fix possible memory leak if device_add() fails
+    - alpha: remove __init annotation from exported page_is_ram()
+    - sch_netem: fix issues in netem_change() vs get_dist_table()
+    - Linux 5.4.254
+  * Focal update: v5.4.253 upstream stable release (LP: #2038652)
+    - jbd2: fix incorrect code style
+    - jbd2: fix kernel-doc markups
+    - jbd2: remove redundant buffer io error checks
+    - jbd2: recheck chechpointing non-dirty buffer
+    - jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint
+    - gpio: tps68470: Make tps68470_gpio_output() always set the initial value
+    - bcache: remove 'int n' from parameter list of bch_bucket_alloc_set()
+    - bcache: Fix __bch_btree_node_alloc to make the failure behavior consistent
+    - btrfs: qgroup: catch reserved space leaks at unmount time
+    - btrfs: fix race between quota disable and relocation
+    - btrfs: fix extent buffer leak after tree mod log failure at split_node()
+    - ext4: rename journal_dev to s_journal_dev inside ext4_sb_info
+    - ext4: Fix reusing stale buffer heads from last failed mounting
+    - PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+    - PCI/ASPM: Factor out pcie_wait_for_retrain()
+    - PCI/ASPM: Avoid link retraining race
+    - dlm: cleanup plock_op vs plock_xop
+    - dlm: rearrange async condition return
+    - fs: dlm: interrupt posix locks only when process is killed
+    - ftrace: Add information on number of page groups allocated
+    - ftrace: Check if pages were allocated before calling free_pages()
+    - ftrace: Store the order of pages allocated in ftrace_page
+    - ftrace: Fix possible warning on checking all pages used in
+      ftrace_process_locs()
+    - pwm: meson: Remove redundant assignment to variable fin_freq
+    - pwm: meson: Simplify duplicated per-channel tracking
+    - pwm: meson: fix handling of period/duty if greater than UINT_MAX
+    - scsi: qla2xxx: Fix inconsistent format argument type in qla_os.c
+    - scsi: qla2xxx: Array index may go out of bound
+    - uapi: General notification queue definitions
+    - keys: Fix linking a duplicate key to a keyring's assoc_array
+    - ext4: fix to check return value of freeze_bdev() in ext4_shutdown()
+    - i40e: Fix an NULL vs IS_ERR() bug for debugfs_create_dir()
+    - vxlan: calculate correct header length for GPE
+    - phy: hisilicon: Fix an out of bounds check in hisi_inno_phy_probe()
+    - ethernet: atheros: fix return value check in atl1e_tso_csum()
+    - ipv6 addrconf: fix bug where deleting a mngtmpaddr can create a new
+      temporary address
+    - bonding: reset bond's flags when down link is P2P device
+    - team: reset team's flags when down link is P2P device
+    - platform/x86: msi-laptop: Fix rfkill out-of-sync on MSI Wind U100
+    - net/sched: mqprio: refactor nlattr parsing to a separate function
+    - net/sched: mqprio: add extack to mqprio_parse_nlattr()
+    - net/sched: mqprio: Add length check for TCA_MQPRIO_{MAX/MIN}_RATE64
+    - benet: fix return value check in be_lancer_xmit_workarounds()
+    - RDMA/mlx4: Make check for invalid flags stricter
+    - drm/msm/dpu: drop enum dpu_core_perf_data_bus_id
+    - drm/msm/adreno: Fix snapshot BINDLESS_DATA size
+    - drm/msm: Fix IS_ERR_OR_NULL() vs NULL check in a5xx_submit_in_rb()
+    - ASoC: fsl_spdif: Silence output on stop
+    - block: Fix a source code comment in include/uapi/linux/blkzoned.h
+    - dm raid: fix missing reconfig_mutex unlock in raid_ctr() error paths
+    - ata: pata_ns87415: mark ns87560_tf_read static
+    - ring-buffer: Fix wrong stat of cpu_buffer->read
+    - tracing: Fix warning in trace_buffered_event_disable()
+    - serial: 8250_dw: Preserve original value of DLF register
+    - serial: sifive: Fix sifive_serial_console_setup() section
+    - USB: serial: option: support Quectel EM060K_128
+    - USB: serial: option: add Quectel EC200A module support
+    - USB: serial: simple: add Kaufmann RKS+CAN VCP
+    - USB: serial: simple: sort driver entries
+    - can: gs_usb: gs_can_close(): add missing set of CAN state to
+      CAN_STATE_STOPPED
+    - Revert "usb: dwc3: core: Enable AutoRetry feature in the controller"
+    - usb: dwc3: pci: skip BYT GPIO lookup table for hardwired phy
+    - usb: dwc3: don't reset device side if dwc3 was configured as host-only
+    - usb: ohci-at91: Fix the unhandle interrupt when resume
+    - USB: quirks: add quirk for Focusrite Scarlett
+    - usb: xhci-mtk: set the dma max_seg_size
+    - Revert "usb: xhci: tegra: Fix error check"
+    - Documentation: security-bugs.rst: update preferences when dealing with the
+      linux-distros group
+    - Documentation: security-bugs.rst: clarify CVE handling
+    - staging: ks7010: potential buffer overflow in ks_wlan_set_encode_ext()
+    - hwmon: (nct7802) Fix for temp6 (PECI1) processed even if PECI1 disabled
+    - btrfs: check for commit error at btrfs_attach_transaction_barrier()
+    - tpm_tis: Explicitly check for error code
+    - irq-bcm6345-l1: Do not assume a fixed block to cpu mapping
+    - btrfs: check if the transaction was aborted at btrfs_wait_for_commit()
+    - virtio-net: fix race between set queues and probe
+    - s390/dasd: fix hanging device after quiesce/resume
+    - ASoC: wm8904: Fill the cache for WM8904_ADC_TEST_0 register
+    - dm cache policy smq: ensure IO doesn't prevent cleaner policy progress
+    - ACPI: processor: perflib: Use the "no limit" frequency QoS
+    - ACPI: processor: perflib: Avoid updating frequency QoS unnecessarily
+    - cpufreq: intel_pstate: Drop ACPI _PSS states table patching
+    - btrfs: qgroup: remove one-time use variables for quota_root checks
+    - btrfs: qgroup: return ENOTCONN instead of EINVAL when quotas are not enabled
+    - ASoC: cs42l51: fix driver to properly autoload with automatic module loading
+    - arm64: Add AMPERE1 to the Spectre-BHB affected list
+    - arm64: Fix bit-shifting UB in the MIDR_CPU_MODEL() macro
+    - perf: Fix function pointer case
+    - loop: Select I/O scheduler 'none' from inside add_disk()
+    - word-at-a-time: use the same return type for has_zero regardless of
+      endianness
+    - KVM: s390: fix sthyi error handling
+    - net/mlx5: DR, fix memory leak in mlx5dr_cmd_create_reformat_ctx
+    - net/mlx5e: fix return value check in mlx5e_ipsec_remove_trailer()
+    - rtnetlink: let rtnl_bridge_setlink checks IFLA_BRIDGE_MODE length
+    - perf test uprobe_from_different_cu: Skip if there is no gcc
+    - net: sched: cls_u32: Fix match key mis-addressing
+    - mISDN: hfcpci: Fix potential deadlock on &hc->lock
+    - net: annotate data-races around sk->sk_max_pacing_rate
+    - net: add missing READ_ONCE(sk->sk_rcvlowat) annotation
+    - net: add missing READ_ONCE(sk->sk_sndbuf) annotation
+    - net: add missing READ_ONCE(sk->sk_rcvbuf) annotation
+    - net: add missing data-race annotations around sk->sk_peek_off
+    - net: add missing data-race annotation for sk_ll_usec
+    - bpf: sockmap: Remove preempt_disable in sock_map_sk_acquire
+    - driver core: add device probe log helper
+    - net: ll_temac: Switch to use dev_err_probe() helper
+    - net: ll_temac: fix error checking of irq_of_parse_and_map()
+    - net: dcb: choose correct policy to parse DCB_ATTR_BCN
+    - ip6mr: Fix skb_under_panic in ip6mr_cache_report()
+    - tcp_metrics: fix addr_same() helper
+    - tcp_metrics: annotate data-races around tm->tcpm_stamp
+    - tcp_metrics: annotate data-races around tm->tcpm_lock
+    - tcp_metrics: annotate data-races around tm->tcpm_vals[]
+    - tcp_metrics: annotate data-races around tm->tcpm_net
+    - tcp_metrics: fix data-race in tcpm_suck_dst() vs fastopen
+    - scsi: zfcp: Defer fc_rport blocking until after ADISC response
+    - libceph: fix potential hang in ceph_osdc_notify()
+    - USB: zaurus: Add ID for A-300/B-500/C-700
+    - mtd: spinand: toshiba: Fix ecc_get_status
+    - mtd: rawnand: meson: fix OOB available bytes for ECC
+    - fs/sysv: Null check to prevent null-ptr-deref bug
+    - net: usbnet: Fix WARNING in usbnet_start_xmit/usb_submit_urb
+    - fs: Protect reconfiguration of sb read-write from racing writes
+    - ext2: Drop fragment support
+    - test_firmware: prevent race conditions by a correct implementation of
+      locking
+    - test_firmware: return ENOMEM instead of ENOSPC on failed memory allocation
+    - mtd: rawnand: omap_elm: Fix incorrect type in assignment
+    - powerpc/mm/altmap: Fix altmap boundary check
+    - selftests/rseq: check if libc rseq support is registered
+    - selftests/rseq: Play nice with binaries statically linked against glibc
+      2.35+
+    - PM / wakeirq: support enabling wake-up irq after runtime_suspend called
+    - PM: sleep: wakeirq: fix wake irq arming
+    - ceph: show tasks waiting on caps in debugfs caps file
+    - ceph: use kill_anon_super helper
+    - ceph: defer stopping mdsc delayed_work
+    - arm64: dts: stratix10: fix incorrect I2C property for SCL signal
+    - ARM: dts: imx6sll: Make ssi node name same as other platforms
+    - ARM: dts: imx: Align L2 cache-controller nodename with dtschema
+    - ARM: dts: imx: add usb alias
+    - ARM: dts: imx6sll: fixup of operating points
+    - ARM: dts: nxp/imx6sll: fix wrong property name in usbphy node
+    - driver core: Annotate dev_err_probe() with __must_check
+    - driver code: print symbolic error code
+    - drivers: core: fix kernel-doc markup for dev_err_probe()
+    - Revert "driver core: Annotate dev_err_probe() with __must_check"
+    - Linux 5.4.253
+    - Upstream stable to v5.4.253
+  * CVE-2023-37453
+    - USB: hub: Clean up use of port initialization schemes and retries
+    - USB: hub: Add Kconfig option to reduce number of port initialization retries
+    - USB: core: Unite old scheme and new scheme descriptor reads
+    - usb: hub: Check device descriptor before resusciation
+    - USB: core: Change usb_get_device_descriptor() API
+    - USB: core: Fix race by not overwriting udev->descriptor in hub_port_init()
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 11 Dec 2023 17:06:03 +0800
+
+linux-ein (5.4.0-1043.50) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1043.50 -proposed tracker (LP: #2044653)
+
+  * Amgis-V5][UC20] Cortex A7 Core 1 Bare metal application conflicts with
+    OPTEE/Linux (LP#2023563)
+    - SAUCE: irq-gic: Allow device tree to exclude irqs
+    - SAUCE: amgis: dts: Exclude A7 Core 1 irqs
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 26 Nov 2023 23:57:27 +0800
+
+linux-ein (5.4.0-1042.49) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1042.49 -proposed tracker (LP: #2044059)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync update-dkms-versions helper
+
+  * Amgis v6 hardware (LP: #2043011)
+    - SAUCE: dts: Add Amgis v6 device tree
+
+  * Miscellaneous Ubuntu changes
+    - snap: medina: Adapt to the new config model
+
+  [ Ubuntu: 5.4.0-167.184 ]
+
+  * focal/linux: 5.4.0-167.184 -proposed tracker (LP: #2041988)
+  * CVE-2023-45871
+    - igb: set max size RX buffer when store bad packet is enabled
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 21 Nov 2023 13:00:44 +0800
+
+linux-ein (5.4.0-1041.48) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1041.48 -proposed tracker (LP: #2040956)
+
+  * Focal update: v5.4.251 upstream stable release (LP: #2034918)
+    - SAUCE: drm/panel: AVD101WX-CN: Update drm_panel_init() call
+
+  * Use new annotations model (LP: #2019000)
+    - [Config] ein: sanitize annotations
+    - [Config] ein: Migrate to the new annotations model
+    - [Config] ein: Migrate to the new annotations model
+
+  * CVE-2023-42755
+    - [Config] ein: remove NET_CLS_RSVP and NET_CLS_RSVP6
+
+  * Focal update: v5.4.248 upstream stable release (LP: #2031121)
+    - [Config] ein: updateconfigs for DECNET
+
+  * [Amgis-V5][UC20] LPM Suspend to Mem vs Standby (LP: #2038441)
+    - Revert "UBUNTU: SAUCE: imx7: Suspend/Resume updates"
+    - Revert "UBUNTU: SAUCE: ARM: imx7: Fix memory mapping for iram_tlb_io_desc by
+      removing the executable flag, resulting in a pagetable warning."
+
+  * Missing Marvell firmware (LP: #2037448)
+    - snap: medina: remove Marvell firmwares except sdsd8997_combo_v4.bin
+
+  * Miscellaneous Ubuntu changes
+    - [Config] ein: Change CONFIG_BLK_DEV_LOOP_MIN_COUNT to 8
+    - snap: medina: Remove pahole from build-packages
+
+  [ Ubuntu: 5.4.0-166.183 ]
+
+  * focal/linux: 5.4.0-166.183 -proposed tracker (LP: #2038010)
+  * Use new annotations model (LP: #2019000)
+    - [Packaging] new annotations model infrastructure
+    - [Packaging] config-check: Handle new annotations format 4
+    - [Packaging] rules: Use old-kernelconfig for old configs
+    - [Config] sanitize annotations
+    - [Config] import generated configs into annotation file
+    - [Packaging] kernelconfig: add i386 as supported arch
+    - [Config] Remove all old configs files
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] update annotations scripts
+  * fix typo in config-checks invocation (LP: #2020413)
+    - [Packaging] fix typo when calling the old config-check
+    - [Packaging] fix typo in 4-checks.mk
+  * support python < 3.9 with annotations (LP: #2020531)
+    - [Packaging] kconfig/annotations.py: support older way of merging dicts
+  * CVE-2023-42756
+    - netfilter: ipset: Fix race between IPSET_CMD_CREATE and IPSET_CMD_SWAP
+  * CVE-2023-4623
+    - net/sched: sch_hfsc: Ensure inner classes have fsc curve
+  * Focal update: v5.4.252 upstream stable release (LP: #2036240)
+    - ia64/cpu: Switch to arch_cpu_finalize_init()
+    - m68k/cpu: Switch to arch_cpu_finalize_init()
+    - mips/cpu: Switch to arch_cpu_finalize_init()
+    - sh/cpu: Switch to arch_cpu_finalize_init()
+    - x86/cpufeatures: Add SEV-ES CPU feature
+    - x86/cpu: Add VM page flush MSR availablility as a CPUID feature
+    - x86/cpufeatures: Assign dedicated feature word for CPUID_0x8000001F[EAX]
+    - tools headers cpufeatures: Sync with the kernel sources
+    - x86/cpu, kvm: Add support for CPUID_80000021_EAX
+    - Linux 5.4.252
+    - Upstream stable to v5.4.252
+  * CVE-2023-42755
+    - net/sched: Retire rsvp classifier
+    - [Config] remove NET_CLS_RSVP and NET_CLS_RSVP6
+  * CVE-2023-42753
+    - netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for
+      ip_set_hash_netportnet.c
+  * CVE-2023-34319
+    - xen/netback: Fix buffer overrun triggered by unusual packet
+  * CVE-2023-4921
+    - net: sched: sch_qfq: Fix UAF in qfq_dequeue()
+  * CVE-2023-42752
+    - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU
+  * Avoid address overwrite in kernel_connect (LP: #2035163)
+    - net: Avoid address overwrite in kernel_connect
+  * [regression] Unable to initialize SGX enclaves with XFRM other than 3
+    (LP: #2034745)
+    - x86/fpu: Set X86_FEATURE_OSXSAVE feature after enabling OSXSAVE in CR4
+  * 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().
+  * Focal update: v5.4.251 upstream stable release (LP: #2034918)
+    - x86/smp: Use dedicated cache-line for mwait_play_dead()
+    - video: imsttfb: check for ioremap() failures
+    - fbdev: imsttfb: Fix use after free bug in imsttfb_probe
+    - HID: wacom: Use ktime_t rather than int when dealing with timestamps
+    - drm/i915: Initialise outparam for error return from wait_for_register
+    - scripts/tags.sh: Resolve gtags empty index generation
+    - drm/amdgpu: Validate VM ioctl flags.
+    - bgmac: fix *initial* chip reset to support BCM5358
+    - x86/resctrl: Use is_closid_match() in more places
+    - x86/resctrl: Only show tasks' pid in current pid namespace
+    - md/raid10: check slab-out-of-bounds in md_bitmap_get_counter
+    - md/raid10: fix overflow of md/safe_mode_delay
+    - md/raid10: fix wrong setting of max_corr_read_errors
+    - md/raid10: fix null-ptr-deref of mreplace in raid10_sync_request
+    - md/raid10: fix io loss while replacement replace rdev
+    - irqchip/jcore-aic: Kill use of irq_create_strict_mappings()
+    - irqchip/jcore-aic: Fix missing allocation of IRQ descriptors
+    - tracing/timer: Add missing hrtimer modes to decode_hrtimer_mode().
+    - clocksource/drivers/cadence-ttc: Use ttc driver as platform driver
+    - clocksource/drivers/cadence-ttc: Fix memory leak in ttc_timer_probe
+    - PM: domains: fix integer overflow issues in genpd_parse_state()
+    - powercap: RAPL: Fix CONFIG_IOSF_MBI dependency
+    - ARM: 9303/1: kprobes: avoid missing-declaration warnings
+    - evm: Complete description of evm_inode_setattr()
+    - pstore/ram: Add check for kstrdup
+    - ima: Fix build warnings
+    - wifi: ath9k: fix AR9003 mac hardware hang check register offset calculation
+    - wifi: ath9k: avoid referencing uninit memory in ath9k_wmi_ctrl_rx
+    - samples/bpf: Fix buffer overflow in tcp_basertt
+    - spi: spi-geni-qcom: Correct CS_TOGGLE bit in SPI_TRANS_CFG
+    - wifi: mwifiex: Fix the size of a memory allocation in
+      mwifiex_ret_802_11_scan()
+    - nfc: constify several pointers to u8, char and sk_buff
+    - nfc: llcp: fix possible use of uninitialized variable in
+      nfc_llcp_send_connect()
+    - regulator: core: Fix more error checking for debugfs_create_dir()
+    - regulator: core: Streamline debugfs operations
+    - wifi: orinoco: Fix an error handling path in spectrum_cs_probe()
+    - wifi: orinoco: Fix an error handling path in orinoco_cs_probe()
+    - wifi: atmel: Fix an error handling path in atmel_probe()
+    - wl3501_cs: Fix a bunch of formatting issues related to function docs
+    - wl3501_cs: Remove unnecessary NULL check
+    - wl3501_cs: Fix misspelling and provide missing documentation
+    - net: create netdev->dev_addr assignment helpers
+    - wl3501_cs: use eth_hw_addr_set()
+    - wifi: wl3501_cs: Fix an error handling path in wl3501_probe()
+    - wifi: ray_cs: Utilize strnlen() in parse_addr()
+    - wifi: ray_cs: Drop useless status variable in parse_addr()
+    - wifi: ray_cs: Fix an error handling path in ray_probe()
+    - wifi: ath9k: don't allow to overwrite ENDPOINT0 attributes
+    - wifi: rsi: Do not set MMC_PM_KEEP_POWER in shutdown
+    - watchdog/perf: define dummy watchdog_update_hrtimer_threshold() on correct
+      config
+    - watchdog/perf: more properly prevent false positives with turbo modes
+    - kexec: fix a memory leak in crash_shrink_memory()
+    - memstick r592: make memstick_debug_get_tpc_name() static
+    - wifi: ath9k: Fix possible stall on ath9k_txq_list_has_key()
+    - rtnetlink: extend RTEXT_FILTER_SKIP_STATS to IFLA_VF_INFO
+    - wifi: iwlwifi: pull from TXQs with softirqs disabled
+    - wifi: cfg80211: rewrite merging of inherited elements
+    - wifi: ath9k: convert msecs to jiffies where needed
+    - netlink: fix potential deadlock in netlink_set_err()
+    - netlink: do not hard code device address lenth in fdb dumps
+    - selftests: rtnetlink: remove netdevsim device after ipsec offload test
+    - gtp: Fix use-after-free in __gtp_encap_destroy().
+    - lib/ts_bm: reset initial match offset for every block of text
+    - netfilter: conntrack: dccp: copy entire header to stack buffer, not just
+      basic one
+    - netfilter: nf_conntrack_sip: fix the ct_sip_parse_numerical_param() return
+      value.
+    - ipvlan: Fix return value of ipvlan_queue_xmit()
+    - netlink: Add __sock_i_ino() for __netlink_diag_dump().
+    - radeon: avoid double free in ci_dpm_init()
+    - Input: drv260x - sleep between polling GO bit
+    - ARM: dts: BCM5301X: Drop "clock-names" from the SPI node
+    - Input: adxl34x - do not hardcode interrupt trigger type
+    - drm: sun4i_tcon: use devm_clk_get_enabled in `sun4i_tcon_init_clocks`
+    - RDMA/bnxt_re: Fix to remove an unnecessary log
+    - ARM: dts: gta04: Move model property out of pinctrl node
+    - arm64: dts: qcom: msm8916: correct camss unit address
+    - drm/panel: simple: fix active size for Ampire AM-480272H3TMQW-T01H
+    - ARM: ep93xx: fix missing-prototype warnings
+    - memory: brcmstb_dpfe: fix testing array offset after use
+    - ASoC: es8316: Increment max value for ALC Capture Target Volume control
+    - ASoC: es8316: Do not set rate constraints for unsupported MCLKs
+    - soc/fsl/qe: fix usb.c build errors
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one errors
+    - arm64: dts: renesas: ulcb-kf: Remove flow control for SCIF1
+    - fbdev: omapfb: lcd_mipid: Fix an error handling path in mipid_spi_probe()
+    - drm/amdkfd: Fix potential deallocation of previously deallocated memory.
+    - drm/radeon: fix possible division-by-zero errors
+    - clk: tegra: tegra124-emc: Fix potential memory leak
+    - ALSA: ac97: Fix possible NULL dereference in snd_ac97_mixer
+    - clk: cdce925: check return value of kasprintf()
+    - clk: keystone: sci-clk: check return value of kasprintf()
+    - ASoC: imx-audmix: check return value of devm_kasprintf()
+    - scsi: qedf: Fix NULL dereference in error handling
+    - PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free
+    - scsi: 3w-xxxx: Add error handling for initialization failure in tw_probe()
+    - PCI: pciehp: Cancel bringup sequence if card is not present
+    - PCI: ftpci100: Release the clock resources
+    - PCI: Add pci_clear_master() stub for non-CONFIG_PCI
+    - pinctrl: cherryview: Return correct value if pin in push-pull mode
+    - perf dwarf-aux: Fix off-by-one in die_get_varname()
+    - pinctrl: at91-pio4: check return value of devm_kasprintf()
+    - powerpc/mm/dax: Fix the condition when checking if altmap vmemap can cross-
+      boundary
+    - hwrng: virtio - add an internal buffer
+    - hwrng: virtio - don't wait on cleanup
+    - hwrng: virtio - don't waste entropy
+    - hwrng: virtio - always add a pending request
+    - hwrng: virtio - Fix race on data_avail and actual data
+    - crypto: nx - fix build warnings when DEBUG_FS is not enabled
+    - modpost: fix section mismatch message for R_ARM_ABS32
+    - modpost: fix section mismatch message for R_ARM_{PC24,CALL,JUMP24}
+    - crypto: marvell/cesa - Fix type mismatch warning
+    - modpost: fix off by one in is_executable_section()
+    - ARC: define ASM_NL and __ALIGN(_STR) outside #ifdef __ASSEMBLY__ guard
+    - NFSv4.1: freeze the session table upon receiving NFS4ERR_BADSESSION
+    - hwrng: st - Fix W=1 unused variable warning
+    - hwrng: st - keep clock enabled while hwrng is registered
+    - USB: serial: option: add LARA-R6 01B PIDs
+    - usb: dwc3: gadget: Propagate core init errors to UDC during pullup
+    - block: fix signed int overflow in Amiga partition support
+    - block: change all __u32 annotations to __be32 in affs_hardblocks.h
+    - w1: fix loop in w1_fini()
+    - sh: j2: Use ioremap() to translate device tree address into kernel memory
+    - media: usb: Check az6007_read() return value
+    - media: videodev2.h: Fix struct v4l2_input tuner index comment
+    - usb: dwc3: qcom: Fix potential memory leak
+    - extcon: Fix kernel doc of property fields to avoid warnings
+    - extcon: Fix kernel doc of property capability fields to avoid warnings
+    - usb: phy: phy-tahvo: fix memory leak in tahvo_usb_probe()
+    - usb: hide unused usbfs_notify_suspend/resume functions
+    - mfd: rt5033: Drop rt5033-battery sub-device
+    - KVM: s390: fix KVM_S390_GET_CMMA_BITS for GFNs in memslot holes
+    - usb: dwc3: qcom: Release the correct resources in dwc3_qcom_remove()
+    - mfd: intel-lpss: Add missing check for platform_get_resource
+    - serial: 8250_omap: Use force_suspend and resume for system suspend
+    - mfd: stmfx: Fix error path in stmfx_chip_init
+    - KVM: s390: vsie: fix the length of APCB bitmap
+    - mfd: stmpe: Only disable the regulators if they are enabled
+    - pwm: imx-tpm: force 'real_period' to be zero in suspend
+    - pwm: sysfs: Do not apply state to already disabled PWMs
+    - rtc: st-lpc: Release some resources in st_rtc_probe() in case of error
+    - sctp: fix potential deadlock on &net->sctp.addr_wq_lock
+    - Add MODULE_FIRMWARE() for FIRMWARE_TG357766.
+    - spi: bcm-qspi: return error if neither hif_mspi nor mspi is available
+    - mailbox: ti-msgmgr: Fill non-message tx data fields with 0x0
+    - f2fs: fix error path handling in truncate_dnode()
+    - powerpc: allow PPC_EARLY_DEBUG_CPM only when SERIAL_CPM=y
+    - net: bridge: keep ports without IFF_UNICAST_FLT in BR_PROMISC mode
+    - tcp: annotate data races in __tcp_oow_rate_limited()
+    - xsk: Improve documentation for AF_XDP
+    - xsk: Honor SO_BINDTODEVICE on bind
+    - net/sched: act_pedit: Add size check for TCA_PEDIT_PARMS_EX
+    - net: dsa: tag_sja1105: fix MAC DA patching from meta frames
+    - sh: dma: Fix DMA channel offset calculation
+    - i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in xiic_process()
+    - i2c: xiic: Don't try to handle more interrupt events after error
+    - ALSA: jack: Fix mutex call in snd_jack_report()
+    - NFSD: add encoding of op_recall flag for write delegation
+    - mmc: core: disable TRIM on Kingston EMMC04G-M627
+    - mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
+    - mmc: sdhci: fix DMA configure compatibility issue when 64bit DMA mode is
+      used.
+    - bcache: Remove unnecessary NULL point check in node allocations
+    - integrity: Fix possible multiple allocation in integrity_inode_get()
+    - jffs2: reduce stack usage in jffs2_build_xattr_subsystem()
+    - fs: avoid empty option when generating legacy mount string
+    - ext4: Remove ext4 locking of moved directory
+    - Revert "f2fs: fix potential corruption when moving a directory"
+    - fs: Establish locking order for unrelated directories
+    - fs: Lock moved directories
+    - btrfs: fix race when deleting quota root from the dirty cow roots list
+    - ARM: orion5x: fix d2net gpio initialization
+    - fs: no need to check source
+    - fanotify: disallow mount/sb marks on kernel internal pseudo fs
+    - block: add overflow checks for Amiga partition support
+    - netfilter: nf_tables: fix nat hook table deletion
+    - netfilter: nftables: add helper function to set the base sequence number
+    - netfilter: add helper function to set up the nfnetlink header and use it
+    - netfilter: nf_tables: use net_generic infra for transaction data
+    - netfilter: nf_tables: add rescheduling points during loop detection walks
+    - netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound
+      set/chain
+    - netfilter: nf_tables: reject unbound anonymous set before commit phase
+    - netfilter: nf_tables: unbind non-anonymous set if rule construction fails
+    - netfilter: nf_tables: fix scheduling-while-atomic splat
+    - netfilter: conntrack: Avoid nf_ct_helper_hash uses after free
+    - tty: serial: fsl_lpuart: add earlycon for imx8ulp platform
+    - block/partition: fix signedness issue for Amiga partitions
+    - net: lan743x: Don't sleep in atomic context
+    - workqueue: clean up WORK_* constant types, clarify masking
+    - drm/panel: Initialise panel dev and funcs through drm_panel_init()
+    - drm/panel: Add and fill drm_panel type field
+    - drm/panel: simple: Add connector_type for innolux_at043tn24
+    - igc: Remove delay during TX ring configuration
+    - igc: set TP bit in 'supported' and 'advertising' fields of
+      ethtool_link_ksettings
+    - scsi: qla2xxx: Fix error code in qla2x00_start_sp()
+    - net: mvneta: fix txq_map in case of txq_number==1
+    - ionic: improve irq numa locality
+    - ionic: clean irq affinity on queue deinit
+    - ionic: move irq request to qcq alloc
+    - ionic: ionic_intr_free parameter change
+    - ionic: remove WARN_ON to prevent panic_on_warn
+    - icmp6: Fix null-ptr-deref of ip6_null_entry->rt6i_idev in icmp6_dev().
+    - udp6: fix udp6_ehashfn() typo
+    - ntb: idt: Fix error handling in idt_pci_driver_init()
+    - NTB: amd: Fix error handling in amd_ntb_pci_driver_init()
+    - ntb: intel: Fix error handling in intel_ntb_pci_driver_init()
+    - NTB: ntb_transport: fix possible memory leak while device_register() fails
+    - NTB: ntb_tool: Add check for devm_kcalloc
+    - ipv6/addrconf: fix a potential refcount underflow for idev
+    - platform/x86: wmi: Replace UUID redefinitions by their originals
+    - platform/x86: wmi: Fix indentation in some cases
+    - platform/x86: wmi: remove unnecessary argument
+    - platform/x86: wmi: use guid_t and guid_equal()
+    - platform/x86: wmi: move variables
+    - platform/x86: wmi: Break possible infinite loop when parsing GUID
+    - erofs: avoid infinite loop in z_erofs_do_read_page() when reading beyond EOF
+    - wifi: airo: avoid uninitialized warning in airo_get_rate()
+    - cls_flower: Add extack support for src and dst port range options
+    - net/sched: flower: Ensure both minimum and maximum ports are specified
+    - net/sched: make psched_mtu() RTNL-less safe
+    - pinctrl: amd: Fix mistake in handling clearing pins at startup
+    - pinctrl: amd: Detect internal GPIO0 debounce handling
+    - pinctrl: amd: Only use special debounce behavior for GPIO 0
+    - tpm: tpm_vtpm_proxy: fix a race condition in /dev/vtpmx creation
+    - mtd: rawnand: meson: fix unaligned DMA buffers handling
+    - net: bcmgenet: Ensure MDIO unregistration has clocks enabled
+    - powerpc: Fail build if using recordmcount with binutils v2.37
+    - misc: fastrpc: Create fastrpc scalar with correct buffer count
+    - SUNRPC: Fix UAF in svc_tcp_listen_data_ready()
+    - erofs: fix compact 4B support for 16k block size
+    - ext4: fix wrong unit use in ext4_mb_clear_bb
+    - ext4: only update i_reserved_data_blocks on successful block allocation
+    - jfs: jfs_dmap: Validate db_l2nbperpage while mounting
+    - PCI/PM: Avoid putting EloPOS E2/S2/H2 PCIe Ports in D3cold
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9235
+    - PCI: qcom: Disable write access to read only registers for IP v2.3.3
+    - PCI: rockchip: Assert PCI Configuration Enable bit after probe
+    - PCI: rockchip: Write PCI Device ID to correct register
+    - PCI: rockchip: Add poll and timeout to wait for PHY PLLs to be locked
+    - PCI: rockchip: Fix legacy IRQ generation for RK3399 PCIe endpoint core
+    - PCI: rockchip: Use u32 variable to access 32-bit registers
+    - PCI: rockchip: Set address alignment for endpoint mode
+    - misc: pci_endpoint_test: Free IRQs before removing the device
+    - misc: pci_endpoint_test: Re-init completion for every test
+    - md/raid0: add discard support for the 'original' layout
+    - fs: dlm: return positive pid value for F_GETLK
+    - drm/atomic: Allow vblank-enabled + self-refresh "disable"
+    - drm/rockchip: vop: Leave vblank enabled in self-refresh
+    - serial: atmel: don't enable IRQs prematurely
+    - firmware: stratix10-svc: Fix a potential resource leak in
+      svc_create_memory_pool()
+    - hwrng: imx-rngc - fix the timeout for init and self check
+    - ceph: don't let check_caps skip sending responses for revoke msgs
+    - meson saradc: fix clock divider mask length
+    - Revert "8250: add support for ASIX devices with a FIFO bug"
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in
+      case of error
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() when
+      iterating clk
+    - tracing/histograms: Add histograms to hist_vars if they have referenced
+      variables
+    - ring-buffer: Fix deadloop issue on reading trace_pipe
+    - xtensa: ISS: fix call to split_if_spec
+    - tracing: Fix null pointer dereference in tracing_err_log_open()
+    - tracing/probes: Fix not to count error code to total length
+    - scsi: qla2xxx: Wait for io return on terminate rport
+    - scsi: qla2xxx: Fix potential NULL pointer dereference
+    - scsi: qla2xxx: Check valid rport returned by fc_bsg_to_rport()
+    - scsi: qla2xxx: Correct the index of array
+    - scsi: qla2xxx: Pointer may be dereferenced
+    - scsi: qla2xxx: Remove unused nvme_ls_waitq wait queue
+    - drm/atomic: Fix potential use-after-free in nonblocking commits
+    - perf probe: Add test for regression introduced by switch to
+      die_get_decl_file()
+    - btrfs: fix warning when putting transaction with qgroups enabled after abort
+    - fuse: revalidate: don't invalidate if interrupted
+    - selftests: tc: set timeout to 15 minutes
+    - can: bcm: Fix UAF in bcm_proc_show()
+    - drm/client: Fix memory leak in drm_client_target_cloned
+    - drm/client: Fix memory leak in drm_client_modeset_probe
+    - ext4: correct inline offset when handling xattrs in inode body
+    - debugobjects: Recheck debug_objects_enabled before reporting
+    - nbd: Add the maximum limit of allocated index in nbd_dev_add
+    - md: fix data corruption for raid456 when reshape restart while grow up
+    - md/raid10: prevent soft lockup while flush writes
+    - posix-timers: Ensure timer ID search-loop limit is valid
+    - arm64: mm: fix VA-range sanity check
+    - sched/fair: Don't balance task to its current running CPU
+    - bpf: Address KCSAN report on bpf_lru_list
+    - devlink: report devlink_port_type_warn source device
+    - wifi: wext-core: Fix -Wstringop-overflow warning in
+      ioctl_standard_iw_point()
+    - wifi: iwlwifi: mvm: avoid baid size integer overflow
+    - igb: Fix igb_down hung on surprise removal
+    - spi: bcm63xx: fix max prepend length
+    - fbdev: imxfb: warn about invalid left/right margin
+    - pinctrl: amd: Use amd_pinconf_set() for all config options
+    - net: ethernet: ti: cpsw_ale: Fix cpsw_ale_get_field()/cpsw_ale_set_field()
+    - iavf: Fix use-after-free in free_netdev
+    - net:ipv6: check return value of pskb_trim()
+    - Revert "tcp: avoid the lookup process failing to get sk in ehash table"
+    - fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe
+    - llc: Don't drop packet from non-root netns.
+    - netfilter: nf_tables: fix spurious set element insertion failure
+    - netfilter: nf_tables: can't schedule in nft_chain_validate
+    - tcp: annotate data-races around tp->tcp_tx_delay
+    - net: Replace the limit of TCP_LINGER2 with TCP_FIN_TIMEOUT_MAX
+    - tcp: annotate data-races around tp->linger2
+    - tcp: annotate data-races around rskq_defer_accept
+    - tcp: annotate data-races around tp->notsent_lowat
+    - tcp: annotate data-races around fastopenq.max_qlen
+    - tracing/histograms: Return an error if we fail to add histogram to hist_vars
+      list
+    - Linux 5.4.251
+  * Focal update: v5.4.250 upstream stable release (LP: #2033297)
+    - x86/microcode/AMD: Load late on both threads too
+    - Linux 5.4.250
+  * Focal update: v5.4.249 upstream stable release (LP: #2033278)
+    - nilfs2: reject devices with insufficient block count
+    - mm: rewrite wait_on_page_bit_common() logic
+    - list: add "list_del_init_careful()" to go with "list_empty_careful()"
+    - epoll: ep_autoremove_wake_function should use list_del_init_careful
+    - tracing: Add tracing_reset_all_online_cpus_unlocked() function
+    - x86/purgatory: remove PGO flags
+    - tick/common: Align tick period during sched_timer setup
+    - media: dvbdev: Fix memleak in dvb_register_device
+    - media: dvbdev: fix error logic at dvb_register_device()
+    - media: dvb-core: Fix use-after-free due to race at dvb_register_device()
+    - nilfs2: fix buffer corruption due to concurrent device reads
+    - Drivers: hv: vmbus: Fix vmbus_wait_for_unload() to scan present CPUs
+    - PCI: hv: Fix a race condition bug in hv_pci_query_relations()
+    - cgroup: Do not corrupt task iteration when rebinding subsystem
+    - mmc: meson-gx: remove redundant mmc_request_done() call from irq context
+    - ip_tunnels: allow VXLAN/GENEVE to inherit TOS/TTL from VLAN
+    - writeback: fix dereferencing NULL mapping->host on writeback_page_template
+    - nilfs2: prevent general protection fault in nilfs_clear_dirty_page()
+    - cifs: Clean up DFS referral cache
+    - cifs: Get rid of kstrdup_const()'d paths
+    - cifs: Introduce helpers for finding TCP connection
+    - cifs: Merge is_path_valid() into get_normalized_path()
+    - cifs: Fix potential deadlock when updating vol in cifs_reconnect()
+    - x86/mm: Avoid using set_pgd() outside of real PGD pages
+    - ieee802154: hwsim: Fix possible memory leaks
+    - xfrm: Linearize the skb after offloading if needed.
+    - net: qca_spi: Avoid high load if QCA7000 is not available
+    - mmc: mtk-sd: fix deferred probing
+    - mmc: mvsdio: convert to devm_platform_ioremap_resource
+    - mmc: mvsdio: fix deferred probing
+    - mmc: omap: fix deferred probing
+    - mmc: omap_hsmmc: fix deferred probing
+    - mmc: sdhci-acpi: fix deferred probing
+    - mmc: sh_mmcif: fix deferred probing
+    - mmc: usdhi60rol0: fix deferred probing
+    - ipvs: align inner_mac_header for encapsulation
+    - net: dsa: mt7530: fix trapping frames on non-MT7621 SoC MT7530 switch
+    - be2net: Extend xmit workaround to BE3 chip
+    - netfilter: nf_tables: disallow element updates of bound anonymous sets
+    - netfilter: nfnetlink_osf: fix module autoload
+    - Revert "net: phy: dp83867: perform soft reset and retain established link"
+    - sch_netem: acquire qdisc lock in netem_change()
+    - scsi: target: iscsi: Prevent login threads from racing between each other
+    - HID: wacom: Add error check to wacom_parse_and_register()
+    - arm64: Add missing Set/Way CMO encodings
+    - media: cec: core: don't set last_initiator if tx in progress
+    - nfcsim.c: Fix error checking for debugfs_create_dir
+    - usb: gadget: udc: fix NULL dereference in remove()
+    - s390/cio: unregister device when the only path is gone
+    - ASoC: nau8824: Add quirk to active-high jack-detect
+    - ARM: dts: Fix erroneous ADS touchscreen polarities
+    - drm/exynos: vidi: fix a wrong error return
+    - drm/exynos: fix race condition UAF in exynos_g2d_exec_ioctl
+    - drm/radeon: fix race condition UAF in radeon_gem_set_domain_ioctl
+    - x86/apic: Fix kernel panic when booting with intremap=off and x2apic_phys
+    - i2c: imx-lpi2c: fix type char overflow issue when calculating the clock
+      cycle
+    - mm: fix VM_BUG_ON(PageTail) and BUG_ON(PageWriteback)
+    - mm: make wait_on_page_writeback() wait for multiple pending writebacks
+    - Linux 5.4.249
+  * allow io_uring to be disabled in runtime (LP: #2035116)
+    - io_uring: add a sysctl to disable io_uring system-wide
+  * CVE-2023-31083
+    - Bluetooth: hci_ldisc: check HCI_UART_PROTO_READY flag in HCIUARTGETPROTO
+  * CVE-2023-4132
+    - media: usb: siano: Fix warning due to null work_func_t function pointer
+  * CVE-2023-3772
+    - xfrm: add NULL check in xfrm_update_ae_params
+  * CVE-2023-0597
+    - random32: add noise from network and scheduling activity
+    - x86/kasan: Map shadow for percpu pages on demand
+    - x86/mm: Randomize per-cpu entry area
+    - x86/mm: Recompute physical address for every page of per-CPU CEA mapping
+    - x86/mm: Populate KASAN shadow for entire per-CPU range of CPU entry area
+    - x86/mm: Do not shuffle CPU entry areas without KASLR
+
+  [ Ubuntu: 5.4.0-164.181 ]
+
+  * focal/linux: 5.4.0-164.181 -proposed tracker (LP: #2033867)
+  * Please enable Renesas RZ platform serial installer (LP: #2022361)
+    - [Config] enable hihope RZ/G2M serial console
+  * Azure: hv_netvsc: add support for vlans in AF_PACKET mode (LP: #2030872)
+    - hv_netvsc: add support for vlans in AF_PACKET mode
+  * systemd mount units fail during boot, while file system is correctly mounted
+    (LP: #1837227)
+    - list: introduce list_for_each_continue()
+    - proc/mounts: add cursor
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+  * 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
+  * CVE-2023-4194
+    - net: tun_chr_open(): set sk_uid from current_fsuid()
+    - net: tap_open(): set sk_uid from current_fsuid()
+  * CVE-2023-1206
+    - tcp: Reduce chance of collisions in inet6_hashfn().
+  * CVE-2021-4001
+    - bpf: Fix toctou on read-only map's constant scalar tracking
+  * Focal update: v5.4.248 upstream stable release (LP: #2031121)
+    - test_firmware: fix a memory leak with reqs buffer
+    - KEYS: asymmetric: Copy sig and digest in public_key_verify_signature()
+    - dasd: refactor dasd_ioctl_information
+    - s390/dasd: Use correct lock while counting channel queue length
+    - power: supply: ab8500: Fix external_power_changed race
+    - power: supply: sc27xx: Fix external_power_changed race
+    - power: supply: bq27xxx: Use mod_delayed_work() instead of cancel() +
+      schedule()
+    - ARM: dts: vexpress: add missing cache properties
+    - power: supply: Ratelimit no data debug output
+    - platform/x86: asus-wmi: Ignore WMI events with codes 0x7B, 0xC0
+    - regulator: Fix error checking for debugfs_create_dir
+    - irqchip/meson-gpio: Mark OF related data as maybe unused
+    - power: supply: Fix logic checking if system is running from battery
+    - btrfs: handle memory allocation failure in btrfs_csum_one_bio
+    - parisc: Improve cache flushing for PCXL in arch_sync_dma_for_cpu()
+    - parisc: Flush gatt writes and adjust gatt mask in parisc_agp_mask_memory()
+    - MIPS: Alchemy: fix dbdma2
+    - mips: Move initrd_start check after initrd address sanitisation.
+    - xen/blkfront: Only check REQ_FUA for writes
+    - drm:amd:amdgpu: Fix missing buffer object unlock in failure path
+    - ocfs2: fix use-after-free when unmounting read-only filesystem
+    - ocfs2: check new file size on fallocate call
+    - nios2: dts: Fix tse_mac "max-frame-size" property
+    - nilfs2: fix incomplete buffer cleanup in nilfs_btnode_abort_change_key()
+    - nilfs2: fix possible out-of-bounds segment allocation in resize ioctl
+    - kexec: support purgatories with .text.hot sections
+    - powerpc/purgatory: remove PGO flags
+    - nouveau: fix client work fence deletion race
+    - RDMA/uverbs: Restrict usage of privileged QKEYs
+    - net: usb: qmi_wwan: add support for Compal RXM-G1
+    - ALSA: hda/realtek: Add a quirk for Compaq N14JP6
+    - Remove DECnet support from kernel
+    - [Config] updateconfigs for DECNET
+    - USB: serial: option: add Quectel EM061KGL series
+    - serial: lantiq: add missing interrupt ack
+    - usb: dwc3: gadget: Reset num TRBs before giving back the request
+    - spi: spi-fsl-dspi: Remove unused chip->void_write_data
+    - spi: fsl-dspi: avoid SCK glitches with continuous transfers
+    - netfilter: nfnetlink: skip error delivery on batch in case of ENOMEM
+    - ping6: Fix send to link-local addresses with VRF.
+    - RDMA/rxe: Remove the unused variable obj
+    - RDMA/rxe: Removed unused name from rxe_task struct
+    - RDMA/rxe: Fix the use-before-initialization error of resp_pkts
+    - iavf: remove mask from iavf_irq_enable_queues()
+    - IB/uverbs: Fix to consider event queue closing also upon non-blocking mode
+    - IB/isert: Fix dead lock in ib_isert
+    - IB/isert: Fix possible list corruption in CMA handler
+    - IB/isert: Fix incorrect release of isert connection
+    - ipvlan: fix bound dev checking for IPv6 l3s mode
+    - sctp: fix an error code in sctp_sf_eat_auth()
+    - igb: fix nvm.ops.read() error handling
+    - drm/nouveau/dp: check for NULL nv_connector->native_mode
+    - drm/nouveau/kms: Don't change EDID when it hasn't actually changed
+    - drm/nouveau: add nv_encoder pointer check for NULL
+    - net/sched: cls_api: Fix lockup on flushing explicitly created chain
+    - net: lapbether: only support ethernet devices
+    - net: tipc: resize nlattr array to correct size
+    - selftests/ptp: Fix timestamp printf format for PTP_SYS_OFFSET
+    - afs: Fix vlserver probe RTT handling
+    - neighbour: Remove unused inline function neigh_key_eq16()
+    - net: Remove unused inline function dst_hold_and_use()
+    - neighbour: delete neigh_lookup_nodev as not used
+    - drm/nouveau/kms: Fix NULL pointer dereference in
+      nouveau_connector_detect_depth
+    - mmc: block: ensure error propagation for non-blk
+    - Linux 5.4.248
+  * Focal update: v5.4.247 upstream stable release (LP: #2030818)
+    - blk-iocost: avoid 64-bit division in ioc_timer_fn
+    - block/blk-iocost (gcc13): keep large values in a new enum
+    - i40iw: fix build warning in i40iw_manage_apbvt()
+    - i40e: fix build warnings in i40e_alloc.h
+    - spi: qup: Request DMA before enabling clocks
+    - neighbour: Replace zero-length array with flexible-array member
+    - neighbour: fix unaligned access to pneigh_entry
+    - net: dsa: lan9303: allow vid != 0 in port_fdb_{add|del} methods
+    - Bluetooth: Fix l2cap_disconnect_req deadlock
+    - Bluetooth: L2CAP: Add missing checks for invalid DCID
+    - netfilter: conntrack: fix NULL pointer dereference in nf_confirm_cthelper
+    - netfilter: ipset: Add schedule point in call_ad().
+    - rfs: annotate lockless accesses to sk->sk_rxhash
+    - rfs: annotate lockless accesses to RFS sock flow table
+    - net: sched: move rtm_tca_policy declaration to include file
+    - net: sched: fix possible refcount leak in tc_chain_tmplt_add()
+    - lib: cpu_rmap: Fix potential use-after-free in irq_cpu_rmap_release()
+    - bnxt_en: Query default VLAN before VNIC setup on a VF
+    - batman-adv: Broken sync while rescheduling delayed work
+    - Input: xpad - delete a Razer DeathAdder mouse VID/PID entry
+    - Input: psmouse - fix OOB access in Elantech protocol
+    - ALSA: hda/realtek: Add a quirk for HP Slim Desktop S01
+    - ALSA: hda/realtek: Add Lenovo P3 Tower platform
+    - drm/amdgpu: fix xclk freq on CHIP_STONEY
+    - can: j1939: j1939_sk_send_loop_abort(): improved error queue handling in
+      J1939 Socket
+    - can: j1939: change j1939_netdev_lock type to mutex
+    - can: j1939: avoid possible use-after-free when j1939_can_rx_register fails
+    - ceph: fix use-after-free bug for inodes when flushing capsnaps
+    - Bluetooth: Fix use-after-free in hci_remove_ltk/hci_remove_irk
+    - rbd: move RBD_OBJ_FLAG_COPYUP_ENABLED flag setting
+    - pinctrl: meson-axg: add missing GPIOA_18 gpio group
+    - usb: usbfs: Enforce page requirements for mmap
+    - usb: usbfs: Use consistent mmap functions
+    - bonding (gcc13): synchronize bond_{a,t}lb_xmit() types
+    - i2c: sprd: Delete i2c adapter in .remove's error path
+    - eeprom: at24: also select REGMAP
+    - ext4: only check dquot_initialize_needed() when debugging
+    - drm/atomic: Don't pollute crtc_state->mode_blob with error pointers
+    - rbd: get snapshot context after exclusive lock is ensured to be held
+    - mtd: spinand: macronix: Add support for MX35LFxGE4AD
+    - Linux 5.4.247
+  * 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-3863
+    - nfc: llcp: simplify llcp_sock_connect() error paths
+    - net: nfc: Fix use-after-free caused by nfc_llcp_find_local
+  * CVE-2023-3212
+    - gfs2: Don't deref jdesc in evict
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 26 Oct 2023 23:43:23 +0800
+
+linux-ein (5.4.0-1040.47) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1040.47 -proposed tracker (LP: #2037063)
+
+  * [K4500-NXP][UC20] Enable VPU For HW Accelerated Video Decoding (LP:
+    #2029414)
+    - [Config] ein: Enable Hantro VPU decoder for IMX8mm devices
+
+  * Miscellaneous Ubuntu changes
+    - snap: Import snapcraft.yaml for Medina
+
+  [ Ubuntu: 5.4.0-163.180 ]
+
+  * focal/linux: 5.4.0-163.180 -proposed tracker (LP: #2034247)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+  * 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
+  * 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
+
+  [ Ubuntu: 5.4.0-162.179 ]
+
+  * focal/linux: 5.4.0-162.179 -proposed tracker (LP: #2031128)
+  * libgnutls report "trap invalid opcode" when trying to install packages over
+    https (LP: #2031093)
+    - [Config]: disable CONFIG_GDS_FORCE_MITIGATION
+
+  [ Ubuntu: 5.4.0-160.177 ]
+
+  * focal/linux: 5.4.0-160.177 -proposed tracker (LP: #2031017)
+  * Fix boot test warning for log_check "CPU: 0 PID: 0 at
+    arch/x86/kernel/fpu/xstate.c:878 get_xsave_addr+0x98/0xb0" (LP: #2031022)
+    - x86/pkeys: Revert a5eff7259790 ("x86/pkeys: Add PKRU value to init_fpstate")
+
+  [ Ubuntu: 5.4.0-158.175 ]
+
+  * focal/linux: 5.4.0-158.175 -proposed tracker (LP: #2030466)
+  * CVE-2022-40982
+    - x86/mm: Initialize text poking earlier
+    - x86/mm: fix poking_init() for Xen PV guests
+    - x86/mm: Use mm_alloc() in poking_init()
+    - mm: Move mm_cachep initialization to mm_init()
+    - init: Provide arch_cpu_finalize_init()
+    - x86/cpu: Switch to arch_cpu_finalize_init()
+    - ARM: cpu: Switch to arch_cpu_finalize_init()
+    - sparc/cpu: Switch to arch_cpu_finalize_init()
+    - um/cpu: Switch to arch_cpu_finalize_init()
+    - init: Remove check_bugs() leftovers
+    - init: Invoke arch_cpu_finalize_init() earlier
+    - init, x86: Move mem_encrypt_init() into arch_cpu_finalize_init()
+    - x86/fpu: Remove cpuinfo argument from init functions
+    - x86/fpu: Mark init functions __init
+    - x86/fpu: Move FPU initialization into arch_cpu_finalize_init()
+    - x86/xen: Fix secondary processors' FPU initialization
+    - x86/speculation: Add Gather Data Sampling mitigation
+    - x86/speculation: Add force option to GDS mitigation
+    - x86/speculation: Add Kconfig option for GDS
+    - KVM: Add GDS_NO support to KVM
+    - Documentation/x86: Fix backwards on/off logic about YMM support
+    - [Config]: Enable CONFIG_ARCH_HAS_CPU_FINALIZE_INIT and
+      CONFIG_GDS_FORCE_MITIGATION
+  * CVE-2023-3609
+    - net/sched: cls_u32: Fix reference counter leak leading to overflow
+  * CVE-2023-20593
+    - x86/cpu/amd: Move the errata checking functionality up
+    - x86/cpu/amd: Add a Zenbleed fix
+  * CVE-2023-3611
+    - net/sched: sch_qfq: account for stab overhead in qfq_enqueue
+  * stacked overlay file system mounts that have chroot() called against them
+    appear to be getting locked (by the kernel most likely?) (LP: #2016398)
+    - SAUCE: overlayfs: fix reference count mismatch
+  * Focal update: v5.4.246 upstream stable release (LP: #2028981)
+    - RDMA/efa: Fix unsupported page sizes in device
+    - RDMA/bnxt_re: Enable SRIOV VF support on Broadcom's 57500 adapter series
+    - RDMA/bnxt_re: Refactor queue pair creation code
+    - RDMA/bnxt_re: Fix return value of bnxt_re_process_raw_qp_pkt_rx
+    - iommu/rockchip: Fix unwind goto issue
+    - iommu/amd: Don't block updates to GATag if guest mode is on
+    - dmaengine: pl330: rename _start to prevent build error
+    - net/mlx5: fw_tracer, Fix event handling
+    - netrom: fix info-leak in nr_write_internal()
+    - af_packet: Fix data-races of pkt_sk(sk)->num.
+    - amd-xgbe: fix the false linkup in xgbe_phy_status
+    - mtd: rawnand: ingenic: fix empty stub helper definitions
+    - af_packet: do not use READ_ONCE() in packet_bind()
+    - tcp: deny tcp_disconnect() when threads are waiting
+    - tcp: Return user_mss for TCP_MAXSEG in CLOSE/LISTEN state if user_mss set
+    - net/sched: sch_ingress: Only create under TC_H_INGRESS
+    - net/sched: sch_clsact: Only create under TC_H_CLSACT
+    - net/sched: Reserve TC_H_INGRESS (TC_H_CLSACT) for ingress (clsact) Qdiscs
+    - net/sched: Prohibit regrafting ingress or clsact Qdiscs
+    - net: sched: fix NULL pointer dereference in mq_attach
+    - ocfs2/dlm: move BITS_TO_BYTES() to bitops.h for wider use
+    - net/netlink: fix NETLINK_LIST_MEMBERSHIPS length report
+    - udp6: Fix race condition in udp6_sendmsg & connect
+    - net: dsa: mv88e6xxx: Increase wait after reset deactivation
+    - mtd: rawnand: marvell: ensure timing values are written
+    - mtd: rawnand: marvell: don't set the NAND frequency select
+    - watchdog: menz069_wdt: fix watchdog initialisation
+    - mailbox: mailbox-test: Fix potential double-free in
+      mbox_test_message_write()
+    - ARM: 9295/1: unwind:fix unwind abort for uleb128 case
+    - media: rcar-vin: Select correct interrupt mode for V4L2_FIELD_ALTERNATE
+    - fbdev: modedb: Add 1920x1080 at 60 Hz video mode
+    - fbdev: stifb: Fix info entry in sti_struct on error path
+    - nbd: Fix debugfs_create_dir error checking
+    - ASoC: dwc: limit the number of overrun messages
+    - xfrm: Check if_id in inbound policy/secpath match
+    - ASoC: ssm2602: Add workaround for playback distortions
+    - media: dvb_demux: fix a bug for the continuity counter
+    - media: dvb-usb: az6027: fix three null-ptr-deref in az6027_i2c_xfer()
+    - media: dvb-usb-v2: ec168: fix null-ptr-deref in ec168_i2c_xfer()
+    - media: dvb-usb-v2: ce6230: fix null-ptr-deref in ce6230_i2c_master_xfer()
+    - media: dvb-usb-v2: rtl28xxu: fix null-ptr-deref in rtl28xxu_i2c_xfer
+    - media: dvb-usb: digitv: fix null-ptr-deref in digitv_i2c_xfer()
+    - media: dvb-usb: dw2102: fix uninit-value in su3000_read_mac_address
+    - media: netup_unidvb: fix irq init by register it at the end of probe
+    - media: dvb_ca_en50221: fix a size write bug
+    - media: ttusb-dec: fix memory leak in ttusb_dec_exit_dvb()
+    - media: mn88443x: fix !CONFIG_OF error by drop of_match_ptr from ID table
+    - media: dvb-core: Fix use-after-free due on race condition at dvb_net
+    - media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221
+    - wifi: rtl8xxxu: fix authentication timeout due to incorrect RCR value
+    - ARM: dts: stm32: add pin map for CAN controller on stm32f7
+    - arm64/mm: mark private VM_FAULT_X defines as vm_fault_t
+    - scsi: core: Decrease scsi_device's iorequest_cnt if dispatch failed
+    - wifi: b43: fix incorrect __packed annotation
+    - netfilter: conntrack: define variables exp_nat_nla_policy and any_addr with
+      CONFIG_NF_NAT
+    - ALSA: oss: avoid missing-prototype warnings
+    - atm: hide unused procfs functions
+    - mailbox: mailbox-test: fix a locking issue in mbox_test_message_write()
+    - iio: adc: mxs-lradc: fix the order of two cleanup operations
+    - HID: google: add jewel USB id
+    - HID: wacom: avoid integer overflow in wacom_intuos_inout()
+    - iio: light: vcnl4035: fixed chip ID check
+    - iio: dac: mcp4725: Fix i2c_master_send() return value handling
+    - iio: dac: build ad5758 driver when AD5758 is selected
+    - net: usb: qmi_wwan: Set DTR quirk for BroadMobi BM818
+    - usb: gadget: f_fs: Add unbind event before functionfs_unbind
+    - misc: fastrpc: return -EPIPE to invocations on device removal
+    - misc: fastrpc: reject new invocations during device removal
+    - scsi: stex: Fix gcc 13 warnings
+    - ata: libata-scsi: Use correct device no in ata_find_dev()
+    - flow_dissector: work around stack frame size warning
+    - x86/boot: Wrap literal addresses in absolute_pointer()
+    - ACPI: thermal: drop an always true check
+    - gcc-12: disable '-Wdangling-pointer' warning for now
+    - eth: sun: cassini: remove dead code
+    - kernel/extable.c: use address-of operator on section symbols
+    - treewide: Remove uninitialized_var() usage
+    - lib/dynamic_debug.c: use address-of operator on section symbols
+    - wifi: rtlwifi: remove always-true condition pointed out by GCC 12
+    - mmc: vub300: fix invalid response handling
+    - tty: serial: fsl_lpuart: use UARTCTRL_TXINV to send break instead of
+      UARTCTRL_SBK
+    - selinux: don't use make's grouped targets feature yet
+    - tracing/probe: trace_probe_primary_from_call(): checked list_first_entry
+    - ext4: add EA_INODE checking to ext4_iget()
+    - ext4: set lockdep subclass for the ea_inode in ext4_xattr_inode_cache_find()
+    - ext4: disallow ea_inodes with extended attributes
+    - ext4: add lockdep annotations for i_data_sem for ea_inode's
+    - fbcon: Fix null-ptr-deref in soft_cursor
+    - test_firmware: fix the memory leak of the allocated firmware buffer
+    - regmap: Account for register length when chunking
+    - scsi: dpt_i2o: Remove broken pass-through ioctl (I2OUSERCMD)
+    - scsi: dpt_i2o: Do not process completions with invalid addresses
+    - [Config] updateconfigs for SCSI_DPT_I2O
+    - RDMA/bnxt_re: Remove set but not used variable 'dev_attr'
+    - RDMA/bnxt_re: Remove the qp from list only if the qp destroy succeeds
+    - drm/edid: Fix uninitialized variable in drm_cvt_modes()
+    - wifi: rtlwifi: 8192de: correct checking of IQK reload
+    - drm/edid: fix objtool warning in drm_cvt_modes()
+    - Linux 5.4.246
+  * Focal update: v5.4.245 upstream stable release (LP: #2028980)
+    - cdc_ncm: Implement the 32-bit version of NCM Transfer Block
+    - net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize
+    - power: supply: bq27xxx: After charger plug in/out wait 0.5s for things to
+      stabilize
+    - power: supply: core: Refactor
+      power_supply_set_input_current_limit_from_supplier()
+    - power: supply: bq24190: Call power_supply_changed() after updating input
+      current
+    - fs: fix undefined behavior in bit shift for SB_NOUSER
+    - net/mlx5: devcom only supports 2 ports
+    - net/mlx5: Devcom, serialize devcom registration
+    - cdc_ncm: Fix the build warning
+    - io_uring: always grab lock in io_cancel_async_work()
+    - io_uring: don't drop completion lock before timer is fully initialized
+    - io_uring: have io_kill_timeout() honor the request references
+    - bluetooth: Add cmd validity checks at the start of hci_sock_ioctl()
+    - binder: fix UAF caused by faulty buffer cleanup
+    - ipv{4,6}/raw: fix output xfrm lookup wrt protocol
+    - netfilter: ctnetlink: Support offloaded conntrack entry deletion
+    - Linux 5.4.245
+  * Focal update: v5.4.244 upstream stable release (LP: #2028697)
+    - driver core: add a helper to setup both the of_node and fwnode of a device
+    - drm/mipi-dsi: Set the fwnode for mipi_dsi_device
+    - ARM: 9296/1: HP Jornada 7XX: fix kernel-doc warnings
+    - linux/dim: Do nothing if no time delta between samples
+    - net: Fix load-tearing on sk->sk_stamp in sock_recv_cmsgs().
+    - netfilter: conntrack: fix possible bug_on with enable_hooks=1
+    - netlink: annotate accesses to nlk->cb_running
+    - net: annotate sk->sk_err write from do_recvmmsg()
+    - net: tap: check vlan with eth_type_vlan() method
+    - net: add vlan_get_protocol_and_depth() helper
+    - net: datagram: fix data-races in datagram_poll()
+    - af_unix: Fix a data race of sk->sk_receive_queue->qlen.
+    - af_unix: Fix data races around sk->sk_shutdown.
+    - fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode()
+    - drm/amd/display: Use DC_LOG_DC in the trasform pixel function
+    - regmap: cache: Return error in cache sync operations for REGCACHE_NONE
+    - firmware: arm_sdei: Fix sleep from invalid context BUG
+    - ACPI: EC: Fix oops when removing custom query handlers
+    - drm/tegra: Avoid potential 32-bit integer overflow
+    - ACPICA: Avoid undefined behavior: applying zero offset to null pointer
+    - ACPICA: ACPICA: check null return of ACPI_ALLOCATE_ZEROED in
+      acpi_db_display_objects
+    - wifi: brcmfmac: cfg80211: Pass the PMK in binary instead of hex
+    - ext2: Check block size validity during mount
+    - scsi: lpfc: Prevent lpfc_debugfs_lockstat_write() buffer overflow
+    - net: pasemi: Fix return type of pasemi_mac_start_tx()
+    - net: Catch invalid index in XPS mapping
+    - scsi: target: iscsit: Free cmds before session free
+    - lib: cpu_rmap: Avoid use after free on rmap->obj array entries
+    - scsi: message: mptlan: Fix use after free bug in mptlan_remove() due to race
+      condition
+    - gfs2: Fix inode height consistency check
+    - ext4: set goal start correctly in ext4_mb_normalize_request
+    - ext4: Fix best extent lstart adjustment logic in ext4_mb_new_inode_pa()
+    - f2fs: fix to drop all dirty pages during umount() if cp_error is set
+    - samples/bpf: Fix fout leak in hbm's run_bpf_prog
+    - wifi: iwlwifi: pcie: fix possible NULL pointer dereference
+    - wifi: iwlwifi: pcie: Fix integer overflow in iwl_write_to_user_buf
+    - wifi: iwlwifi: dvm: Fix memcpy: detected field-spanning write backtrace
+    - Bluetooth: L2CAP: fix "bad unlock balance" in l2cap_disconnect_rsp
+    - HID: logitech-hidpp: Don't use the USB serial for USB devices
+    - HID: logitech-hidpp: Reconcile USB and Unifying serials
+    - spi: spi-imx: fix MX51_ECSPI_* macros when cs > 3
+    - HID: wacom: generic: Set battery quirk only when we see battery data
+    - usb: typec: tcpm: fix multiple times discover svids error
+    - serial: 8250: Reinit port->pm on port specific driver unbind
+    - mcb-pci: Reallocate memory region to avoid memory overlapping
+    - sched: Fix KCSAN noinstr violation
+    - recordmcount: Fix memory leaks in the uwrite function
+    - RDMA/core: Fix multiple -Warray-bounds warnings
+    - clk: tegra20: fix gcc-7 constant overflow warning
+    - iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
+    - Input: xpad - add constants for GIP interface numbers
+    - phy: st: miphy28lp: use _poll_timeout functions for waits
+    - mfd: dln2: Fix memory leak in dln2_probe()
+    - btrfs: replace calls to btrfs_find_free_ino with btrfs_find_free_objectid
+    - btrfs: fix space cache inconsistency after error loading it from disk
+    - ASoC: fsl_micfil: register platform component before registering cpu dai
+    - cpupower: Make TSC read per CPU for Mperf monitor
+    - af_key: Reject optional tunnel/BEET mode templates in outbound policies
+    - net: fec: Better handle pm_runtime_get() failing in .remove()
+    - ALSA: firewire-digi00x: prevent potential use after free
+    - vsock: avoid to close connected socket after the timeout
+    - serial: arc_uart: fix of_iomap leak in `arc_serial_probe`
+    - ip6_gre: Fix skb_under_panic in __gre6_xmit()
+    - ip6_gre: Make o_seqno start from 0 in native mode
+    - ip_gre, ip6_gre: Fix race condition on o_seqno in collect_md mode
+    - erspan: get the proto with the md version for collect_md
+    - net: hns3: fix sending pfc frames after reset issue
+    - net: hns3: fix reset delay time to avoid configuration timeout
+    - media: netup_unidvb: fix use-after-free at del_timer()
+    - drm/exynos: fix g2d_open/close helper function definitions
+    - net: nsh: Use correct mac_offset to unwind gso skb in nsh_gso_segment()
+    - net: bcmgenet: Remove phy_stop() from bcmgenet_netif_stop()
+    - net: bcmgenet: Restore phy_stop() depending upon suspend/close
+    - wifi: iwlwifi: mvm: don't trust firmware n_channels
+    - cassini: Fix a memory leak in the error handling path of cas_init_one()
+    - igb: fix bit_shift to be in [1..8] range
+    - vlan: fix a potential uninit-value in vlan_dev_hard_start_xmit()
+    - USB: usbtmc: Fix direction for 0-length ioctl control messages
+    - usb-storage: fix deadlock when a scsi command timeouts more than once
+    - USB: UHCI: adjust zhaoxin UHCI controllers OverCurrent bit value
+    - usb: dwc3: debugfs: Resume dwc3 before accessing registers
+    - usb: typec: altmodes/displayport: fix pin_assignment_show
+    - ALSA: hda: Fix Oops by 9.1 surround channel names
+    - ALSA: hda: Add NVIDIA codec IDs a3 through a7 to patch table
+    - ALSA: hda/realtek: Add a quirk for HP EliteDesk 805
+    - ALSA: hda/realtek: Add quirk for 2nd ASUS GU603
+    - can: j1939: recvmsg(): allow MSG_CMSG_COMPAT flag
+    - can: kvaser_pciefd: Set CAN_STATE_STOPPED in kvaser_pciefd_stop()
+    - can: kvaser_pciefd: Call request_irq() before enabling interrupts
+    - can: kvaser_pciefd: Empty SRB buffer in probe
+    - can: kvaser_pciefd: Clear listen-only bit if not explicitly requested
+    - can: kvaser_pciefd: Do not send EFLUSH command on TFD interrupt
+    - can: kvaser_pciefd: Disable interrupts in probe error path
+    - KVM: x86: do not report a vCPU as preempted outside instruction boundaries
+    - statfs: enforce statfs[64] structure initialization
+    - serial: Add support for Advantech PCI-1611U card
+    - ceph: force updating the msg pointer in non-split case
+    - tpm/tpm_tis: Disable interrupts for more Lenovo devices
+    - powerpc/64s/radix: Fix soft dirty tracking
+    - nilfs2: fix use-after-free bug of nilfs_root in nilfs_evict_inode()
+    - netfilter: nftables: add nft_parse_register_load() and use it
+    - netfilter: nftables: add nft_parse_register_store() and use it
+    - netfilter: nftables: statify nft_parse_register()
+    - netfilter: nf_tables: validate registers coming from userspace.
+    - netfilter: nf_tables: add nft_setelem_parse_key()
+    - netfilter: nf_tables: allow up to 64 bytes in the set element data area
+    - netfilter: nf_tables: stricter validation of element data
+    - netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on NFT_SET_OBJECT
+      flag
+    - netfilter: nf_tables: hold mutex on netns pre_exit path
+    - HID: wacom: Force pen out of prox if no events have been received in a while
+    - HID: wacom: Add new Intuos Pro Small (PTH-460) device IDs
+    - HID: wacom: add three styli to wacom_intuos_get_tool_type
+    - lib/string_helpers: Introduce string_upper() and string_lower() helpers
+    - usb: gadget: u_ether: Convert prints to device prints
+    - usb: gadget: u_ether: Fix host MAC address case
+    - vc_screen: rewrite vcs_size to accept vc, not inode
+    - vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF
+    - s390/qdio: get rid of register asm
+    - s390/qdio: fix do_sqbs() inline assembly constraint
+    - watchdog: sp5100_tco: Immediately trigger upon starting.
+    - spi: fsl-spi: Re-organise transfer bits_per_word adaptation
+    - spi: fsl-cpm: Use 16 bit mode for large transfers with even size
+    - mt76: mt7615: Fix build with older compilers
+    - ALSA: hda/ca0132: add quirk for EVGA X299 DARK
+    - ALSA: hda/realtek: Enable headset onLenovo M70/M90
+    - m68k: Move signal frame following exception on 68020/030
+    - parisc: Handle kgdb breakpoints only in kernel context
+    - parisc: Allow to reboot machine after system halt
+    - gpio: mockup: Fix mode of debugfs files
+    - btrfs: use nofs when cleaning up aborted transactions
+    - selftests/memfd: Fix unknown type name build failure
+    - parisc: Fix flush_dcache_page() for usage from irq context
+    - x86/topology: Fix erroneous smp_num_siblings on Intel Hybrid platforms
+    - debugobjects: Don't wake up kswapd from fill_pool()
+    - fbdev: udlfb: Fix endpoint check
+    - net: fix stack overflow when LRO is disabled for virtual interfaces
+    - udplite: Fix NULL pointer dereference in __sk_mem_raise_allocated().
+    - USB: core: Add routines for endpoint checks in old drivers
+    - USB: sisusbvga: Add endpoint checks
+    - media: radio-shark: Add endpoint checks
+    - net: fix skb leak in __skb_tstamp_tx()
+    - selftests: fib_tests: mute cleanup error message
+    - bpf: Fix mask generation for 32-bit narrow loads of 64-bit fields
+    - ipv6: Fix out-of-bounds access in ipv6_find_tlv()
+    - power: supply: leds: Fix blink to LED on transition
+    - power: supply: bq27xxx: Fix bq27xxx_battery_update() race condition
+    - power: supply: bq27xxx: Fix I2C IRQ race on remove
+    - power: supply: bq27xxx: Fix poll_interval handling and races on remove
+    - power: supply: sbs-charger: Fix INHIBITED bit for Status reg
+    - coresight: Fix signedness bug in tmc_etr_buf_insert_barrier_packet()
+    - xen/pvcalls-back: fix double frees with pvcalls_new_active_socket()
+    - x86/show_trace_log_lvl: Ensure stack pointer is aligned, again
+    - ASoC: Intel: Skylake: Fix declaration of enum skl_ch_cfg
+    - forcedeth: Fix an error handling path in nv_probe()
+    - net/mlx5: Fix error message when failing to allocate device memory
+    - net/mlx5: Devcom, fix error flow in mlx5_devcom_register_device
+    - 3c589_cs: Fix an error handling path in tc589_probe()
+    - Linux 5.4.244
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387)
+    - counter: 104-quad-8: Fix race condition between FLAG and CNTR reads
+    - drm/fb-helper: set x/yres_virtual in drm_fb_helper_check_var
+    - bluetooth: Perform careful capability checks in hci_sock_ioctl()
+    - USB: serial: option: add UNISOC vendor and TOZED LT70C product
+    - iio: adc: palmas_gpadc: fix NULL dereference on rmmod
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Acer Iconia One 7 B1-750
+    - asm-generic/io.h: suppress endianness warnings for readq() and writeq()
+    - USB: dwc3: fix runtime pm imbalance on probe errors
+    - USB: dwc3: fix runtime pm imbalance on unbind
+    - perf sched: Cast PTHREAD_STACK_MIN to int as it may turn into
+      sysconf(__SC_THREAD_STACK_MIN_VALUE)
+    - staging: iio: resolver: ads1210: fix config mode
+    - debugfs: regset32: Add Runtime PM support
+    - xhci: fix debugfs register accesses while suspended
+    - MIPS: fw: Allow firmware to pass a empty env
+    - ipmi:ssif: Add send_retries increment
+    - ipmi: fix SSIF not responding under certain cond.
+    - kheaders: Use array declaration instead of char
+    - pwm: meson: Fix axg ao mux parents
+    - pwm: meson: Fix g12a ao clk81 name
+    - ring-buffer: Sync IRQ works before buffer destruction
+    - reiserfs: Add security prefix to xattr name in reiserfs_security_write()
+    - KVM: nVMX: Emulate NOPs in L2, and PAUSE if it's not intercepted
+    - i2c: omap: Fix standard mode false ACK readings
+    - Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path"
+    - ubifs: Fix memleak when insert_old_idx() failed
+    - ubi: Fix return value overwrite issue in try_write_vid_and_data()
+    - ubifs: Free memory for tmpfile name
+    - selinux: fix Makefile dependencies of flask.h
+    - selinux: ensure av_permissions.h is built when needed
+    - tpm, tpm_tis: Do not skip reset of original interrupt vector
+    - erofs: stop parsing non-compact HEAD index if clusterofs is invalid
+    - erofs: fix potential overflow calculating xattr_isize
+    - drm/rockchip: Drop unbalanced obj unref
+    - drm/vgem: add missing mutex_destroy
+    - drm/probe-helper: Cancel previous job before starting new one
+    - arm64: dts: renesas: r8a77990: Remove bogus voltages from OPP table
+    - arm64: dts: renesas: r8a774c0: Remove bogus voltages from OPP table
+    - EDAC/skx: Fix overflows on the DRAM row address mapping arrays
+    - ARM: dts: qcom: ipq4019: Fix the PCI I/O port range
+    - ARM: dts: qcom: ipq8064: reduce pci IO size to 64K
+    - ARM: dts: qcom: ipq8064: Fix the PCI I/O port range
+    - media: bdisp: Add missing check for create_workqueue
+    - media: uapi: add MEDIA_BUS_FMT_METADATA_FIXED media bus format.
+    - media: av7110: prevent underflow in write_ts_to_decoder()
+    - firmware: qcom_scm: Clear download bit during reboot
+    - drm/msm: fix unbalanced pm_runtime_enable in adreno_gpu_{init, cleanup}
+    - drm/msm/adreno: Defer enabling runpm until hw_init()
+    - drm/msm/adreno: drop bogus pm_runtime_set_active()
+    - mmc: sdhci-of-esdhc: fix quirk to ignore command inhibit for data
+    - drm/lima/lima_drv: Add missing unwind goto in lima_pdev_probe()
+    - regulator: core: Consistently set mutex_owner when using
+      ww_mutex_lock_slow()
+    - regulator: core: Avoid lockdep reports when resolving supplies
+    - x86/apic: Fix atomic update of offset in reserve_eilvt_offset()
+    - media: dm1105: Fix use after free bug in dm1105_remove due to race condition
+    - media: saa7134: fix use after free bug in saa7134_finidev due to race
+      condition
+    - media: rcar_fdp1: simplify error check logic at fdp_open()
+    - media: rcar_fdp1: fix pm_runtime_get_sync() usage count
+    - media: rcar_fdp1: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - media: rcar_fdp1: Fix the correct variable assignments
+    - media: rcar_fdp1: Fix refcount leak in probe and remove function
+    - media: rc: gpio-ir-recv: Fix support for wake-up
+    - regulator: stm32-pwr: fix of_iomap leak
+    - x86/ioapic: Don't return 0 from arch_dynirq_lower_bound()
+    - arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step
+    - debugobject: Prevent init race with static objects
+    - timekeeping: Split jiffies seqlock
+    - tick/sched: Use tick_next_period for lockless quick check
+    - tick/sched: Reduce seqcount held scope in tick_do_update_jiffies64()
+    - tick/sched: Optimize tick_do_update_jiffies64() further
+    - tick: Get rid of tick_period
+    - tick/common: Align tick period with the HZ tick.
+    - wifi: ath6kl: minor fix for allocation size
+    - wifi: ath9k: hif_usb: fix memory leak of remain_skbs
+    - wifi: ath5k: fix an off by one check in ath5k_eeprom_read_freq_list()
+    - wifi: ath6kl: reduce WARN to dev_dbg() in callback
+    - tools: bpftool: Remove invalid \' json escape
+    - wifi: rtw88: mac: Return the original error from rtw_pwr_seq_parser()
+    - wifi: rtw88: mac: Return the original error from rtw_mac_power_switch()
+    - scm: fix MSG_CTRUNC setting condition for SO_PASSSEC
+    - vlan: partially enable SIOCSHWTSTAMP in container
+    - net/packet: annotate accesses to po->xmit
+    - net/packet: convert po->origdev to an atomic flag
+    - net/packet: convert po->auxdata to an atomic flag
+    - scsi: target: iscsit: Fix TAS handling during conn cleanup
+    - scsi: megaraid: Fix mega_cmd_done() CMDID_INT_CMDS
+    - f2fs: handle dqget error in f2fs_transfer_project_quota()
+    - rtlwifi: Start changing RT_TRACE into rtl_dbg
+    - rtlwifi: Replace RT_TRACE with rtl_dbg
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_rfreg()
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_reg()
+    - bpftool: Fix bug for long instructions in program CFG dumps
+    - crypto: drbg - make drbg_prepare_hrng() handle jent instantiation errors
+    - crypto: drbg - Only fail when jent is unavailable in FIPS mode
+    - scsi: lpfc: Fix ioremap issues in lpfc_sli4_pci_mem_setup()
+    - bpf, sockmap: fix deadlocks in the sockhash and sockmap
+    - nvme: handle the persistent internal error AER
+    - nvme: fix async event trace event
+    - nvme-fcloop: fix "inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage"
+    - bpf, sockmap: Revert buggy deadlock fix in the sockhash and sockmap
+    - md/raid10: fix leak of 'r10bio->remaining' for recovery
+    - md/raid10: fix memleak for 'conf->bio_split'
+    - md: update the optimal I/O size on reshape
+    - md/raid10: fix memleak of md thread
+    - wifi: iwlwifi: make the loop for card preparation effective
+    - wifi: iwlwifi: mvm: check firmware response size
+    - ixgbe: Allow flow hash to be set via ethtool
+    - ixgbe: Enable setting RSS table to default values
+    - bpf: Don't EFAULT for getsockopt with optval=NULL
+    - netfilter: nf_tables: don't write table validation state without mutex
+    - ipv4: Fix potential uninit variable access bug in __ip_make_skb()
+    - netlink: Use copy_to_user() for optval in netlink_getsockopt().
+    - net: amd: Fix link leak when verifying config failed
+    - tcp/udp: Fix memleaks of sk and zerocopy skbs with TX timestamp.
+    - pstore: Revert pmsg_lock back to a normal mutex
+    - usb: host: xhci-rcar: remove leftover quirk handling
+    - fpga: bridge: fix kernel-doc parameter description
+    - iio: light: max44009: add missing OF device matching
+    - usb: gadget: udc: renesas_usb3: Fix use after free bug in
+      renesas_usb3_remove due to race condition
+    - PCI: imx6: Install the fault handler only on compatible match
+    - genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
+    - ASoC: es8316: Use IRQF_NO_AUTOEN when requesting the IRQ
+    - ASoC: es8316: Handle optional IRQ assignment
+    - linux/vt_buffer.h: allow either builtin or modular for macros
+    - spi: qup: Don't skip cleanup in remove's error path
+    - spi: fsl-spi: Fix CPM/QE mode Litte Endian
+    - vmci_host: fix a race condition in vmci_host_poll() causing GPF
+    - of: Fix modalias string generation
+    - ia64: mm/contig: fix section mismatch warning/error
+    - ia64: salinfo: placate defined-but-not-used warning
+    - scripts/gdb: bail early if there are no clocks
+    - PM: domains: Fix up terminology with parent/child
+    - scripts/gdb: bail early if there are no generic PD
+    - mtd: spi-nor: cadence-quadspi: Make driver independent of flash geometry
+    - mtd: spi-nor: cadence-quadspi: Provide a way to disable DAC mode
+    - mtd: spi-nor: cadence-quadspi: Don't initialize rx_dma_complete on failure
+    - mtd: spi-nor: cadence-quadspi: Handle probe deferral while requesting DMA
+      channel
+    - spi: cadence-quadspi: fix suspend-resume implementations
+    - uapi/linux/const.h: prefer ISO-friendly __typeof__
+    - sh: sq: Fix incorrect element size for allocating bitmap buffer
+    - usb: chipidea: fix missing goto in `ci_hdrc_probe`
+    - usb: mtu3: fix kernel panic at qmu transfer done irq handler
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - tty: serial: fsl_lpuart: adjust buffer length to the intended size
+    - serial: 8250: Add missing wakeup event reporting
+    - staging: rtl8192e: Fix W_DISABLE# does not work after stop/start
+    - spmi: Add a check for remove callback when removing a SPMI driver
+    - macintosh/windfarm_smu_sat: Add missing of_node_put()
+    - powerpc/mpc512x: fix resource printk format warning
+    - powerpc/wii: fix resource printk format warnings
+    - powerpc/sysdev/tsi108: fix resource printk format warnings
+    - macintosh: via-pmu-led: requires ATA to be set
+    - powerpc/rtas: use memmove for potentially overlapping buffer copy
+    - perf/core: Fix hardlockup failure caused by perf throttle
+    - RDMA/siw: Fix potential page_array out of range access
+    - RDMA/rdmavt: Delete unnecessary NULL check
+    - rtc: omap: include header for omap_rtc_power_off_program prototype
+    - RDMA/mlx4: Prevent shift wrapping in set_user_sq_size()
+    - rtc: meson-vrtc: Use ktime_get_real_ts64() to get the current time
+    - power: supply: generic-adc-battery: fix unit scaling
+    - clk: add missing of_node_put() in "assigned-clocks" property parsing
+    - RDMA/siw: Remove namespace check from siw_netdev_event()
+    - IB/hfi1: Fix SDMA mmu_rb_node not being evicted in LRU order
+    - NFSv4.1: Always send a RECLAIM_COMPLETE after establishing lease
+    - firmware: raspberrypi: Keep count of all consumers
+    - firmware: raspberrypi: Introduce devm_rpi_firmware_get()
+    - input: raspberrypi-ts: Release firmware handle when not needed
+    - Input: raspberrypi-ts - fix refcount leak in rpi_ts_probe
+    - SUNRPC: remove the maximum number of retries in call_bind_status
+    - RDMA/mlx5: Use correct device num_ports when modify DC
+    - clocksource/drivers/davinci: Avoid trailing '\n' hidden in pr_fmt()
+    - clocksource: davinci: axe a pointless __GFP_NOFAIL
+    - clocksource/drivers/davinci: Fix memory leak in davinci_timer_register when
+      init fails
+    - openrisc: Properly store r31 to pt_regs on unhandled exceptions
+    - ext4: fix use-after-free read in ext4_find_extent for bigalloc + inline
+    - leds: TI_LMU_COMMON: select REGMAP instead of depending on it
+    - dmaengine: mv_xor_v2: Fix an error code.
+    - pwm: mtk-disp: Don't check the return code of pwmchip_remove()
+    - pwm: mtk-disp: Adjust the clocks to avoid them mismatch
+    - pwm: mtk-disp: Disable shadow registers before setting backlight values
+    - phy: tegra: xusb: Add missing tegra_xusb_port_unregister for usb2_port and
+      ulpi_port
+    - dmaengine: dw-edma: Fix to change for continuous transfer
+    - dmaengine: dw-edma: Fix to enable to issue dma request on DMA processing
+    - dmaengine: at_xdmac: do not enable all cyclic channels
+    - afs: Fix updating of i_size with dv jump from server
+    - parisc: Fix argument pointer in real64_call_asm()
+    - nilfs2: do not write dirty data after degenerating to read-only
+    - nilfs2: fix infinite loop in nilfs_mdt_get_block()
+    - md/raid10: fix null-ptr-deref in raid10_sync_request
+    - mailbox: zynqmp: Fix IPI isr handling
+    - mailbox: zynqmp: Fix typo in IPI documentation
+    - wifi: rtl8xxxu: RTL8192EU always needs full init
+    - clk: rockchip: rk3399: allow clk_cifout to force clk_cifout_src to reparent
+    - scripts/gdb: fix lx-timerlist for Python3
+    - btrfs: scrub: reject unsupported scrub flags
+    - s390/dasd: fix hanging blockdevice after request requeue
+    - dm clone: call kmem_cache_destroy() in dm_clone_init() error path
+    - dm integrity: call kmem_cache_destroy() in dm_integrity_init() error path
+    - dm flakey: fix a crash with invalid table line
+    - perf auxtrace: Fix address filter entire kernel size
+    - perf intel-pt: Fix CYC timestamps after standalone CBR
+    - debugobject: Ensure pool refill (again)
+    - nohz: Add TICK_DEP_BIT_RCU
+    - tick/nohz: Fix cpu_is_hotpluggable() by checking with nohz subsystem
+    - mailbox: zynq: Switch to flexible array to simplify code
+    - mailbox: zynqmp: Fix counts of child nodes
+    - dm verity: skip redundant verity_handle_err() on I/O errors
+    - dm verity: fix error handling for check_at_most_once on FEC
+    - crypto: inside-secure - irq balance
+    - crypto: safexcel - Cleanup ring IRQ workqueues on load failure
+    - net/ncsi: clear Tx enable mode when handling a Config required AEN
+    - net/sched: cls_api: remove block_cb from driver_list before freeing
+    - sit: update dev->needed_headroom in ipip6_tunnel_bind_dev()
+    - net: dsa: mv88e6xxx: add mv88e6321 rsvd2cpu
+    - writeback: fix call of incorrect macro
+    - net/sched: act_mirred: Add carrier check
+    - rxrpc: Fix hard call timeout units
+    - ionic: remove noise from ethtool rxnfc error msg
+    - af_packet: Don't send zero-byte data in packet_sendmsg_spkt().
+    - drm/amdgpu: add a missing lock for AMDGPU_SCHED
+    - ALSA: caiaq: input: Add error handling for unsupported input methods in
+      `snd_usb_caiaq_input_init`
+    - net: dsa: mt7530: fix corrupt frames using trgmii on 40 MHz XTAL MT7621
+    - virtio_net: split free_unused_bufs()
+    - virtio_net: suppress cpu stall when free_unused_bufs
+    - perf vendor events power9: Remove UTF-8 characters from JSON files
+    - perf map: Delete two variable initialisations before null pointer checks in
+      sort__sym_from_cmp()
+    - perf symbols: Fix return incorrect build_id size in elf_read_build_id()
+    - btrfs: fix btrfs_prev_leaf() to not return the same key twice
+    - btrfs: don't free qgroup space unless specified
+    - btrfs: print-tree: parent bytenr must be aligned to sector size
+    - cifs: fix pcchunk length type in smb2_copychunk_range
+    - platform/x86: touchscreen_dmi: Add info for the Dexp Ursus KX210i
+    - inotify: Avoid reporting event with invalid wd
+    - sh: math-emu: fix macro redefined warning
+    - sh: init: use OF_EARLY_FLATTREE for early init
+    - sh: nmi_debug: fix return value of __setup handler
+    - remoteproc: stm32: Call of_node_put() on iteration error
+    - remoteproc: st: Call of_node_put() on iteration error
+    - ARM: dts: exynos: fix WM8960 clock name in Itop Elite
+    - ARM: dts: s5pv210: correct MIPI CSIS clock name
+    - f2fs: fix potential corruption when moving a directory
+    - drm/panel: otm8009a: Set backlight parent to panel device
+    - drm/amdgpu: fix an amdgpu_irq_put() issue in gmc_v9_0_hw_fini()
+    - drm/amdgpu/gfx: disable gfx9 cp_ecc_error_irq only when enabling legacy gfx
+      ras
+    - drm/amdgpu: disable sdma ecc irq only when sdma RAS is enabled in suspend
+    - HID: wacom: Set a default resolution for older tablets
+    - HID: wacom: insert timestamp to packed Bluetooth (BT) events
+    - ext4: fix WARNING in mb_find_extent
+    - ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum
+    - ext4: fix data races when using cached status extents
+    - ext4: improve error recovery code paths in __ext4_remount()
+    - ext4: fix deadlock when converting an inline directory in nojournal mode
+    - ext4: add bounds checking in get_max_inline_xattr_value_size()
+    - ext4: bail out of ext4_xattr_ibody_get() fails for any reason
+    - ext4: remove a BUG_ON in ext4_mb_release_group_pa()
+    - ext4: fix invalid free tracking in ext4_xattr_move_to_block()
+    - tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH
+    - serial: 8250: Fix serial8250_tx_empty() race with DMA Tx
+    - drbd: correctly submit flush bio on barrier
+    - PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors
+    - PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock
+    - printk: declare printk_deferred_{enter,safe}() in include/linux/printk.h
+    - PM: domains: Restore comment indentation for generic_pm_domain.child_links
+    - drm/msm: Fix double pm_runtime_disable() call
+    - firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
+    - drm/msm/adreno: Fix null ptr access in adreno_gpu_cleanup()
+    - drm/exynos: move to use request_irq by IRQF_NO_AUTOEN flag
+    - mm/page_alloc: fix potential deadlock on zonelist_update_seq seqlock
+    - drm/amd/display: Fix hang when skipping modeset
+    - Linux 5.4.243
+    - Upstream stable to v5.4.243
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387) //
+    CVE-2023-2269
+    - dm ioctl: fix nested locking in table_clear() to remove deadlock concern
+  * Focal update: v5.4.242 upstream stable release (LP: #2025094)
+    - ARM: dts: rockchip: fix a typo error for rk3288 spdif node
+    - arm64: dts: meson-g12-common: specify full DMC range
+    - netfilter: br_netfilter: fix recent physdev match breakage
+    - regulator: fan53555: Explicitly include bits header
+    - virtio_net: bugfix overflow inside xdp_linearize_page()
+    - netfilter: nf_tables: fix ifdef to also consider nf_tables=m
+    - i40e: fix accessing vsi->active_filters without holding lock
+    - i40e: fix i40e_setup_misc_vector() error handling
+    - mlxfw: fix null-ptr-deref in mlxfw_mfa2_tlv_next()
+    - bpf: Fix incorrect verifier pruning due to missing register precision taints
+    - e1000e: Disable TSO on i219-LM card to increase speed
+    - f2fs: Fix f2fs_truncate_partial_nodes ftrace event
+    - Input: i8042 - add quirk for Fujitsu Lifebook A574/H
+    - selftests: sigaltstack: fix -Wuninitialized
+    - scsi: megaraid_sas: Fix fw_crash_buffer_show()
+    - scsi: core: Improve scsi_vpd_inquiry() checks
+    - net: dsa: b53: mmap: add phy ops
+    - s390/ptrace: fix PTRACE_GET_LAST_BREAK error handling
+    - nvme-tcp: fix a possible UAF when failing to allocate an io queue
+    - xen/netback: use same error messages for same errors
+    - iio: light: tsl2772: fix reading proximity-diodes from device tree
+    - nilfs2: initialize unused bytes in segment summary blocks
+    - memstick: fix memory leak if card device is never registered
+    - mmc: sdhci_am654: Set HIGH_SPEED_ENA for SDR12 and SDR25
+    - MIPS: Define RUNTIME_DISCARD_EXIT in LD script
+    - x86/purgatory: Don't generate debug info for purgatory.ro
+    - Revert "ext4: fix use-after-free in ext4_xattr_set_entry"
+    - ext4: remove duplicate definition of ext4_xattr_ibody_inline_set()
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM).
+    - tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
+    - inet6: Remove inet6_destroy_sock() in sk->sk_prot->destroy().
+    - dccp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - sctp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - xfs: fix forkoff miscalculation related to XFS_LITINO(mp)
+    - pwm: meson: Explicitly set .polarity in .get_state()
+    - iio: adc: at91-sama5d2_adc: fix an error code in at91_adc_allocate_trigger()
+    - ASN.1: Fix check for strdup() success
+    - Linux 5.4.242
+    - Upstream stable to v5.4.242
+  * 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-3268
+    - kernel/relay.c: fix read_pos error when multiple readers
+    - relayfs: fix out-of-bounds access in relay_file_read
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-156.173 ]
+
+  * focal/linux: 5.4.0-156.173 -proposed tracker (LP: #2026585)
+  * CVE-2023-3390
+    - netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+  * Focal update: v5.4.241 upstream stable release (LP: #2023930)
+    - scsi: ses: Handle enclosure with just a primary component gracefully
+    - x86/PCI: Add quirk for AMD XHCI controller that loses MSI-X state in D3hot
+    - cgroup/cpuset: Wake up cpuset_attach_wq tasks in cpuset_cancel_attach()
+    - treewide: Replace DECLARE_TASKLET() with DECLARE_TASKLET_OLD()
+    - smb3: fix problem with null cifs super block with previous patch
+    - pinctrl: amd: Use irqchip template
+    - pinctrl: amd: disable and mask interrupts on probe
+    - pinctrl: amd: Disable and mask interrupts on resume
+    - pwm: cros-ec: Explicitly set .polarity in .get_state()
+    - pwm: sprd: Explicitly set .polarity in .get_state()
+    - wifi: mac80211: fix invalid drv_sta_pre_rcu_remove calls for non-uploaded
+      sta
+    - icmp: guard against too small mtu
+    - net: don't let netpoll invoke NAPI if in xmit context
+    - sctp: check send stream number after wait_for_sndbuf
+    - ipv6: Fix an uninit variable access bug in __ip6_make_skb()
+    - gpio: davinci: Add irq chip flag to skip set wake
+    - sunrpc: only free unix grouplist after RCU settles
+    - NFSD: callback request does not use correct credential for AUTH_SYS
+    - xhci: also avoid the XHCI_ZERO_64B_REGS quirk with a passthrough iommu
+    - USB: serial: cp210x: add Silicon Labs IFS-USB-DATACABLE IDs
+    - usb: typec: altmodes/displayport: Fix configure initial pin assignment
+    - USB: serial: option: add Telit FE990 compositions
+    - USB: serial: option: add Quectel RM500U-CN modem
+    - iio: adc: ti-ads7950: Set `can_sleep` flag for GPIO chip
+    - iio: dac: cio-dac: Fix max DAC write value check for 12-bit
+    - tty: serial: sh-sci: Fix transmit end interrupt handler
+    - tty: serial: sh-sci: Fix Rx on RZ/G2L SCI
+    - tty: serial: fsl_lpuart: avoid checking for transfer complete when
+      UARTCTRL_SBK is asserted in lpuart32_tx_empty
+    - nilfs2: fix potential UAF of struct nilfs_sc_info in nilfs_segctor_thread()
+    - nilfs2: fix sysfs interface lifetime
+    - ALSA: hda/realtek: Add quirk for Clevo X370SNW
+    - perf/core: Fix the same task check in perf_event_set_output
+    - ftrace: Mark get_lock_parent_ip() __always_inline
+    - can: j1939: j1939_tp_tx_dat_new(): fix out-of-bounds memory access
+    - tracing: Free error logs of tracing instances
+    - net_sched: prevent NULL dereference if default qdisc setup failed
+    - drm/panfrost: Fix the panfrost_mmu_map_fault_addr() error path
+    - ring-buffer: Fix race while reader and writer are on the same page
+    - mm/swap: fix swap_info_struct race between swapoff and get_swap_pages()
+    - irqdomain: Look for existing mapping only once
+    - irqdomain: Refactor __irq_domain_alloc_irqs()
+    - irqdomain: Fix mapping-creation race
+    - Revert "pinctrl: amd: Disable and mask interrupts on resume"
+    - ALSA: emu10k1: fix capture interrupt handler unlinking
+    - ALSA: hda/sigmatel: add pin overrides for Intel DP45SG motherboard
+    - ALSA: i2c/cs8427: fix iec958 mixer control deactivation
+    - ALSA: firewire-tascam: add missing unwind goto in
+      snd_tscm_stream_start_duplex()
+    - ALSA: hda/sigmatel: fix S/PDIF out on Intel D*45* motherboards
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_disconnect_{req,rsp}
+    - Bluetooth: Fix race condition in hidp_session_thread
+    - btrfs: print checksum type and implementation at mount time
+    - btrfs: fix fast csum implementation detection
+    - mtdblock: tolerate corrected bit-flips
+    - mtd: rawnand: meson: fix bitmask for length in command word
+    - mtd: rawnand: stm32_fmc2: remove unsupported EDO mode
+    - niu: Fix missing unwind goto in niu_alloc_channels()
+    - qlcnic: check pci_reset_function result
+    - sctp: fix a potential overflow in sctp_ifwdtsn_skip
+    - RDMA/core: Fix GID entry ref leak when create_ah fails
+    - udp6: fix potential access to stale information
+    - net: macb: fix a memory corruption in extended buffer descriptor mode
+    - power: supply: cros_usbpd: reclassify "default case!" as debug
+    - i2c: imx-lpi2c: clean rx/tx buffers upon new message
+    - efi: sysfb_efi: Add quirk for Lenovo Yoga Book X91F/L
+    - drm: panel-orientation-quirks: Add quirk for Lenovo Yoga Book X90F
+    - verify_pefile: relax wrapper length check
+    - asymmetric_keys: log on fatal failures in PE/pkcs7
+    - ubi: Fix failure attaching when vid_hdr offset equals to (sub)page size
+    - mtd: ubi: wl: Fix a couple of kernel-doc issues
+    - ubi: Fix deadlock caused by recursively holding work_sem
+    - i2c: ocores: generate stop condition after timeout in polling mode
+    - watchdog: sbsa_wdog: Make sure the timeout programming is within the limits
+    - coresight-etm4: Fix for() loop drvdata->nr_addr_cmp range bug
+    - xfs: show the proper user quota options
+    - xfs: remove the kuid/kgid conversion wrappers
+    - xfs: add a new xfs_sb_version_has_v3inode helper
+    - xfs: only check the superblock version for dinode size calculation
+    - xfs: simplify di_flags2 inheritance in xfs_ialloc
+    - xfs: simplify a check in xfs_ioctl_setattr_check_cowextsize
+    - xfs: remove the di_version field from struct icdinode
+    - xfs: set inode size after creating symlink
+    - xfs: report corruption only as a regular error
+    - xfs: shut down the filesystem if we screw up quota reservation
+    - xfs: consider shutdown in bmapbt cursor delete assert
+    - xfs: don't reuse busy extents on extent trim
+    - xfs: force log and push AIL to clear pinned inodes when aborting mount
+    - Linux 5.4.241
+  * [UBUNTU 20.04] [HPS] Kernel panic with "refcount_t: underflow" in mlx5
+    driver (LP: #2019011)
+    - net/mlx5: cmdif, Avoid skipping reclaim pages if FW is not accessible
+    - net/mlx5: Fix handling of entry refcount when command is not issued to FW
+  * Disable hv-kvp-daemon if /dev/vmbus/hv_kvp is not present (LP: #2024900)
+    - [Packaging] disable hv-kvp-daemon if needed
+  * CVE-2023-35001
+    - netfilter: nf_tables: prevent OOB access in nft_byteorder_eval
+  * CVE-2023-32629
+    - ovl: adhere to the vfs_ vs. ovl_do_ conventions for xattrs
+  * CVE-2023-3141
+    - memstick: r592: Fix UAF bug in r592_remove due to race condition
+  * CVE-2023-3111
+    - btrfs: check return value of btrfs_commit_transaction in relocation
+    - btrfs: unset reloc control if transaction commit fails in
+      prepare_to_relocate()
+  * 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-2022-0168
+    - cifs: move some variables off the stack in smb2_ioctl_query_info
+    - cifs: prevent bad output lengths in smb2_ioctl_query_info()
+    - cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
+  * CVE-2022-27672
+    - x86/speculation: Identify processors vulnerable to SMT RSB predictions
+    - KVM: x86: Mitigate the cross-thread return address predictions bug
+    - Documentation/hw-vuln: Add documentation for Cross-Thread Return Predictions
+  * Severe NFS performance degradation after LP #2003053 (LP: #2022098)
+    - SAUCE: Make NFS file-access stale cache behaviour opt-in
+  * Encountering an issue with memcpy_fromio causing failed boot of SEV-enabled
+    guest (LP: #2020319)
+    - x86/sev: Unroll string mmio with CC_ATTR_GUEST_UNROLL_STRING_IO
+  * Focal update: v5.4.240 upstream stable release (LP: #2023601)
+    - net: tls: fix possible race condition between do_tls_getsockopt_conf() and
+      do_tls_setsockopt_conf()
+    - power: supply: da9150: Fix use after free bug in da9150_charger_remove due
+      to race condition
+    - iavf: fix inverted Rx hash condition leading to disabled hash
+    - iavf: fix non-tunneled IPv6 UDP packet type and hashing
+    - intel/igbvf: free irq on the error path in igbvf_request_msix()
+    - igbvf: Regard vf reset nack as success
+    - i2c: imx-lpi2c: check only for enabled interrupt flags
+    - scsi: scsi_dh_alua: Fix memleak for 'qdata' in alua_activate()
+    - net: usb: smsc95xx: Limit packet length to skb->len
+    - qed/qed_sriov: guard against NULL derefs from qed_iov_get_vf_info
+    - net: qcom/emac: Fix use after free bug in emac_remove due to race condition
+    - net/ps3_gelic_net: Fix RX sk_buff length
+    - net/ps3_gelic_net: Use dma_mapping_error
+    - keys: Do not cache key in task struct if key is requested from kernel thread
+    - bpf: Adjust insufficient default bpf_jit_limit
+    - net/mlx5: Read the TC mapping of all priorities on ETS query
+    - atm: idt77252: fix kmemleak when rmmod idt77252
+    - erspan: do not use skb_mac_header() in ndo_start_xmit()
+    - net/sonic: use dma_mapping_error() for error check
+    - nvme-tcp: fix nvme_tcp_term_pdu to match spec
+    - hvc/xen: prevent concurrent accesses to the shared ring
+    - net: mdio: thunder: Add missing fwnode_handle_put()
+    - Bluetooth: btqcomsmd: Fix command timeout after setting BD address
+    - platform/chrome: cros_ec_chardev: fix kernel data leak from ioctl
+    - hwmon (it87): Fix voltage scaling for chips with 10.9mV ADCs
+    - scsi: qla2xxx: Perform lockless command completion in abort path
+    - uas: Add US_FL_NO_REPORT_OPCODES for JMicron JMS583Gen 2
+    - thunderbolt: Use const qualifier for `ring_interrupt_index`
+    - riscv: Bump COMMAND_LINE_SIZE value to 1024
+    - ca8210: fix mac_len negative array access
+    - m68k: Only force 030 bus error if PC not in exception table
+    - selftests/bpf: check that modifier resolves after pointer
+    - scsi: target: iscsi: Fix an error message in iscsi_check_key()
+    - scsi: ufs: core: Add soft dependency on governor_simpleondemand
+    - scsi: lpfc: Avoid usage of list iterator variable after loop
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FE990
+    - net: usb: qmi_wwan: add Telit 0x1080 composition
+    - sh: sanitize the flags on sigreturn
+    - cifs: empty interface list when server doesn't support query interfaces
+    - scsi: core: Add BLIST_SKIP_VPD_PAGES for SKhynix H28U74301AMR
+    - usb: gadget: u_audio: don't let userspace block driver unbind
+    - fsverity: Remove WQ_UNBOUND from fsverity read workqueue
+    - igb: revert rtnl_lock() that causes deadlock
+    - dm thin: fix deadlock when swapping to thin device
+    - usb: cdns3: Fix issue with using incorrect PCI device function
+    - usb: chipdea: core: fix return -EINVAL if request role is the same with
+      current role
+    - usb: chipidea: core: fix possible concurrent when switch role
+    - wifi: mac80211: fix qos on mesh interfaces
+    - nilfs2: fix kernel-infoleak in nilfs_ioctl_wrap_copy()
+    - i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer()
+    - dm stats: check for and propagate alloc_percpu failure
+    - dm crypt: add cond_resched() to dmcrypt_write()
+    - sched/fair: sanitize vruntime of entity being placed
+    - sched/fair: Sanitize vruntime of entity being migrated
+    - tun: avoid double free in tun_free_netdev
+    - ocfs2: fix data corruption after failed write
+    - fsverity: don't drop pagecache at end of FS_IOC_ENABLE_VERITY
+    - bus: imx-weim: fix branch condition evaluates to a garbage value
+    - md: avoid signed overflow in slot_store()
+    - ALSA: asihpi: check pao in control_message()
+    - ALSA: hda/ca0132: fixup buffer overrun at tuning_ctl_set()
+    - fbdev: tgafb: Fix potential divide by zero
+    - sched_getaffinity: don't assume 'cpumask_size()' is fully initialized
+    - fbdev: nvidia: Fix potential divide by zero
+    - fbdev: intelfb: Fix potential divide by zero
+    - fbdev: lxfb: Fix potential divide by zero
+    - fbdev: au1200fb: Fix potential divide by zero
+    - ca8210: Fix unsigned mac_len comparison with zero in ca8210_skb_tx()
+    - dma-mapping: drop the dev argument to arch_sync_dma_for_*
+    - mips: bmips: BCM6358: disable RAC flush for TP1
+    - mtd: rawnand: meson: invalidate cache on polling ECC bit
+    - scsi: megaraid_sas: Fix crash after a double completion
+    - ptp_qoriq: fix memory leak in probe()
+    - regulator: fix spelling mistake "Cant" -> "Can't"
+    - regulator: Handle deferred clk
+    - net/net_failover: fix txq exceeding warning
+    - can: bcm: bcm_tx_setup(): fix KMSAN uninit-value in vfs_write
+    - s390/vfio-ap: fix memory leak in vfio_ap device driver
+    - i40e: fix registers dump after run ethtool adapter self test
+    - bnxt_en: Fix typo in PCI id to device description string mapping
+    - net: dsa: mv88e6xxx: Enable IGMP snooping on user ports only
+    - net: mvneta: make tx buffer array agnostic
+    - pinctrl: ocelot: Fix alt mode for ocelot
+    - Input: alps - fix compatibility with -funsigned-char
+    - Input: focaltech - use explicitly signed char type
+    - cifs: prevent infinite recursion in CIFSGetDFSRefer()
+    - cifs: fix DFS traversal oops without CONFIG_CIFS_DFS_UPCALL
+    - Input: goodix - add Lenovo Yoga Book X90F to nine_bytes_report DMI table
+    - xen/netback: don't do grant copy across page boundary
+    - pinctrl: at91-pio4: fix domain name assignment
+    - NFSv4: Fix hangs when recovering open state after a server reboot
+    - ALSA: hda/conexant: Partial revert of a quirk for Lenovo
+    - ALSA: usb-audio: Fix regression on detection of Roland VS-100
+    - drm/etnaviv: fix reference leak when mmaping imported buffer
+    - btrfs: scan device in non-exclusive mode
+    - ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+    - net_sched: add __rcu annotation to netdev->qdisc
+    - net: sched: fix race condition in qdisc_graft()
+    - firmware: arm_scmi: Fix device node validation for mailbox transport
+    - gfs2: Always check inode size of inline inodes
+    - Linux 5.4.240
+  * Focal update: v5.4.239 upstream stable release (LP: #2023600)
+    - Linux 5.4.239
+  * CVE-2023-2124
+    - xfs: verify buffer contents when we skip log replay
+  * CVE-2020-36691
+    - netlink: limit recursion depth in policy validation
+  * CVE-2022-1184
+    - ext4: check if directory block is within i_size
+    - ext4: fix check for block being out of directory size
+  * CVE-2022-4269
+    - net: sched: extract qstats update code into functions
+    - net: sched: don't expose action qstats to skb_tc_reinsert()
+    - net/sched: act_mirred: refactor the handle of xmit
+    - net: sched: remove unused tcf_result extension
+    - net/sched: act_mirred: better wording on protection against excessive stack
+      growth
+    - act_mirred: use the backlog for nested calls to mirred ingress
+  * Focal update: v5.4.238 upstream stable release (LP: #2023427)
+    - ext4: fix cgroup writeback accounting with fs-layer encryption
+    - xfrm: Allow transport-mode states with AF_UNSPEC selector
+    - drm/panfrost: Don't sync rpm suspension after mmu flushing
+    - cifs: Move the in_send statistic to __smb_send_rqst()
+    - drm/meson: fix 1px pink line on GXM when scaling video overlay
+    - clk: HI655X: select REGMAP instead of depending on it
+    - docs: Correct missing "d_" prefix for dentry_operations member
+      d_weak_revalidate
+    - scsi: mpt3sas: Fix NULL pointer access in mpt3sas_transport_port_add()
+    - ALSA: hda - add Intel DG1 PCI and HDMI ids
+    - ALSA: hda - controller is in GPU on the DG1
+    - ALSA: hda: Add Alderlake-S PCI ID and HDMI codec vid
+    - ALSA: hda: Add Intel DG2 PCI ID and HDMI codec vid
+    - ALSA: hda: Match only Intel devices with CONTROLLER_IN_GPU()
+    - netfilter: nft_redir: correct value of inet type `.maxattrs`
+    - scsi: core: Fix a comment in function scsi_host_dev_release()
+    - scsi: core: Fix a procfs host directory removal regression
+    - tcp: tcp_make_synack() can be called from process context
+    - nfc: pn533: initialize struct pn533_out_arg properly
+    - ipvlan: Make skb->skb_iif track skb->dev for l3s mode
+    - i40e: Fix kernel crash during reboot when adapter is in recovery mode
+    - qed/qed_dev: guard against a possible division by zero
+    - net: tunnels: annotate lockless accesses to dev->needed_headroom
+    - net: phy: smsc: bail out in lan87xx_read_status if genphy_read_status fails
+    - nfc: st-nci: Fix use after free bug in ndlc_remove due to race condition
+    - net: usb: smsc75xx: Limit packet length to skb->len
+    - nvmet: avoid potential UAF in nvmet_req_complete()
+    - block: sunvdc: add check for mdesc_grab() returning NULL
+    - ipv4: Fix incorrect table ID in IOCTL path
+    - net: usb: smsc75xx: Move packet length check to prevent kernel panic in
+      skb_pull
+    - net/iucv: Fix size of interrupt data
+    - ethernet: sun: add check for the mdesc_grab()
+    - hwmon: (adt7475) Display smoothing attributes in correct order
+    - hwmon: (adt7475) Fix masking of hysteresis registers
+    - hwmon: (xgene) Fix use after free bug in xgene_hwmon_remove due to race
+      condition
+    - hwmon: (ina3221) return prober error code
+    - media: m5mols: fix off-by-one loop termination error
+    - mmc: atmel-mci: fix race between stop command and start of next command
+    - jffs2: correct logic when creating a hole in jffs2_write_begin
+    - ext4: fail ext4_iget if special inode unallocated
+    - ext4: fix task hung in ext4_xattr_delete_inode
+    - drm/amdkfd: Fix an illegal memory access
+    - sh: intc: Avoid spurious sizeof-pointer-div warning
+    - ext4: fix possible double unlock when moving a directory
+    - tty: serial: fsl_lpuart: skip waiting for transmission complete when
+      UARTCTRL_SBK is asserted
+    - interconnect: fix mem leak when freeing nodes
+    - tracing: Check field value in hist_field_name()
+    - tracing: Make tracepoint lockdep check actually test something
+    - ftrace: Fix invalid address access in lookup_rec() when index is 0
+    - fbdev: stifb: Provide valid pixelclock and add fb_check_var() checks
+    - x86/mm: Fix use of uninitialized buffer in sme_enable()
+    - drm/i915: Don't use stolen memory for ring buffers with LLC
+    - serial: 8250_em: Fix UART port type
+    - s390/ipl: add missing intersection check to ipl_report handling
+    - PCI: Unify delay handling for reset and resume
+    - HID: core: Provide new max_buffer_size attribute to over-ride the default
+    - HID: uhid: Over-ride the default maximum data buffer value with our own
+    - Linux 5.4.238
+  * Focal update: v5.4.237 upstream stable release (LP: #2023420)
+    - fs: prevent out-of-bounds array speculation when closing a file descriptor
+    - x86/CPU/AMD: Disable XSAVES on AMD family 0x17
+    - drm/connector: print max_requested_bpc in state debugfs
+    - ext4: fix RENAME_WHITEOUT handling for inline directories
+    - ext4: fix another off-by-one fsmap error on 1k block filesystems
+    - ext4: move where set the MAY_INLINE_DATA flag is set
+    - ext4: fix WARNING in ext4_update_inline_data
+    - ext4: zero i_disksize when initializing the bootloader inode
+    - nfc: change order inside nfc_se_io error path
+    - iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands
+    - iommu/amd: Fix ill-formed ivrs_ioapic, ivrs_hpet and ivrs_acpihid options
+    - iommu/amd: Add a length limitation for the ivrs_acpihid command-line
+      parameter
+    - ipmi:ssif: make ssif_i2c_send() void
+    - ipmi:ssif: resend_msg() cannot fail
+    - ipmi:ssif: Remove rtc_us_timer
+    - ipmi:ssif: Increase the message retry time
+    - ipmi:ssif: Add a timer between request retries
+    - irqdomain: Change the type of 'size' in __irq_domain_add() to be consistent
+    - irqdomain: Fix domain registration race
+    - iommu/vt-d: Fix PASID directory pointer coherency
+    - SMB3: Backup intent flag missing from some more ops
+    - cifs: Fix uninitialized memory read in smb3_qfs_tcon()
+    - scsi: core: Remove the /proc/scsi/${proc_name} directory earlier
+    - ext4: Fix possible corruption when moving a directory
+    - drm/msm/a5xx: fix setting of the CP_PREEMPT_ENABLE_LOCAL register
+    - nfc: fdp: add null check of devm_kmalloc_array in
+      fdp_nci_i2c_read_device_properties
+    - ila: do not generate empty messages in ila_xlat_nl_cmd_get_mapping()
+    - selftests: nft_nat: ensuring the listening side is up before starting the
+      client
+    - net: usb: lan78xx: Remove lots of set but unused 'ret' variables
+    - net: lan78xx: fix accessing the LAN7800's internal phy specific registers
+      from the MAC driver
+    - net: caif: Fix use-after-free in cfusbl_device_notify()
+    - bnxt_en: Avoid order-5 memory allocation for TPA data
+    - netfilter: tproxy: fix deadlock due to missing BH disable
+    - btf: fix resolving BTF_KIND_VAR after ARRAY, STRUCT, UNION, PTR
+    - scsi: megaraid_sas: Update max supported LD IDs to 240
+    - net/smc: fix fallback failed while sendmsg with fastopen
+    - riscv: Use READ_ONCE_NOCHECK in imprecise unwinding stack mode
+    - ext4: Fix deadlock during directory rename
+    - MIPS: Fix a compilation issue
+    - alpha: fix R_ALPHA_LITERAL reloc for large modules
+    - macintosh: windfarm: Use unsigned type for 1-bit bitfields
+    - PCI: Add SolidRun vendor ID
+    - media: ov5640: Fix analogue gain control
+    - ipmi/watchdog: replace atomic_add() and atomic_sub()
+    - ipmi:watchdog: Set panic count to proper value on a panic
+    - drm/i915: Don't use BAR mappings for ring buffers with LLC
+    - x86, vmlinux.lds: Add RUNTIME_DISCARD_EXIT to generic DISCARDS
+    - arch: fix broken BuildID for arm64 and riscv
+    - powerpc/vmlinux.lds: Define RUNTIME_DISCARD_EXIT
+    - powerpc/vmlinux.lds: Don't discard .rela* for relocatable builds
+    - s390: define RUNTIME_DISCARD_EXIT to fix link error with GNU ld < 2.36
+    - sh: define RUNTIME_DISCARD_EXIT
+    - UML: define RUNTIME_DISCARD_EXIT
+    - s390/dasd: add missing discipline function
+    - Linux 5.4.237
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - staging: rtl8192e: Remove function ..dm_check_ac_dc_power calling a script
+    - staging: rtl8192e: Remove call_usermodehelper starting RadioPower.sh
+    - Linux 5.4.236
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 22 Sep 2023 18:38:25 +0800
+
+linux-ein (5.4.0-1039.46) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1039.46 -proposed tracker (LP: #2029267)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] resync getabis
+
+  * [K4500-NXP][UC20] CPU-Freq Interface Not Available On NXP Hardware
+    (LP#2008278)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Enable cpufreq support
+
+  * WIFI/Bluetooth module is not fully reset/initialized at Linux boot Edit
+    (LP#2019041)
+    - SAUCE: amgis: dts: Add MMC simple HW reset driver node
+
+  * Miscellaneous Ubuntu changes
+    - snap: reading: Set grade to devel instead of stable
+    - snap: reading: Remove package-repositories
+
+  [ Ubuntu: 5.4.0-153.170 ]
+
+  * focal/linux: 5.4.0-153.170 -proposed tracker (LP: #2024108)
+  * cls_flower: off-by-one in fl_set_geneve_opt (LP: #2023577)
+    - net/sched: flower: fix possible OOB write in fl_set_geneve_opt()
+  * Some INVLPG implementations can leave Global translations unflushed when
+    PCIDs are enabled (LP: #2023220)
+    - x86/mm: Avoid incomplete Global INVLPG flushes
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 01 Aug 2023 23:03:05 +0800
+
+linux-ein (5.4.0-1038.45) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1038.45 -proposed tracker (LP: #2024158)
+
+  * CVE-2023-1829
+    - [Config] ein: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+  * Request a change to EMMC access rate, to DDR52 (LP#2012080)
+    - SAUCE: mmc: Add device tree quirks2 property
+    - SAUCE: mmc: Allow device tree to disable HS400
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Disable HS200 and HS400
+
+  [ Ubuntu: 5.4.0-152.169 ]
+
+  * focal/linux: 5.4.0-152.169 -proposed tracker (LP: #2023070)
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - wifi: cfg80211: Partial revert "wifi: cfg80211: Fix use after free for wext"
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-151.168 ]
+
+  * focal/linux: 5.4.0-151.168 -proposed tracker (LP: #2019375)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2023.05.15)
+  * CVE-2023-32233
+    - netfilter: nf_tables: deactivate anonymous set from preparation phase
+  * CVE-2023-2612
+    - SAUCE: shiftfs: prevent lock unbalance in shiftfs_create_object()
+  * 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()
+  * Focal update: Focal update: v5.4.235 upstream stable release (LP: #2017706)
+    - HID: asus: Remove check for same LED brightness on set
+    - HID: asus: use spinlock to protect concurrent accesses
+    - HID: asus: use spinlock to safely schedule workers
+    - ARM: OMAP2+: Fix memory leak in realtime_counter_init()
+    - arm64: dts: qcom: qcs404: use symbol names for PCIe resets
+    - ARM: zynq: Fix refcount leak in zynq_early_slcr_init
+    - arm64: dts: meson-gx: Fix Ethernet MAC address unit name
+    - arm64: dts: meson-g12a: Fix internal Ethernet PHY unit name
+    - arm64: dts: meson-gx: Fix the SCPI DVFS node name and unit address
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12A boards
+    - ARM: OMAP1: call platform_device_put() in error case in
+      omap1_dm_timer_init()
+    - ARM: dts: exynos: correct wr-active property in Exynos3250 Rinato
+    - ARM: imx: Call ida_simple_remove() for ida_simple_get
+    - arm64: dts: amlogic: meson-gx: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-axg: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-gx: add missing SCPI sensors compatible
+    - arm64: dts: amlogic: meson-gx: add missing unit address to rng node name
+    - arm64: dts: amlogic: meson-gxl: add missing unit address to eth-phy-mux node
+      name
+    - arm64: dts: amlogic: meson-gxl-s905d-phicomm-n1: fix led node name
+    - ARM: dts: imx7s: correct iomuxc gpr mux controller cells
+    - arm64: dts: mediatek: mt7622: Add missing pwm-cells to pwm node
+    - Revert "scsi: core: run queue if SCSI device queue isn't ready and queue is
+      idle"
+    - block: Limit number of items taken from the I/O scheduler in one go
+    - blk-mq: remove stale comment for blk_mq_sched_mark_restart_hctx
+    - blk-mq: wait on correct sbitmap_queue in blk_mq_mark_tag_wait
+    - blk-mq: correct stale comment of .get_budget
+    - s390/dasd: Prepare for additional path event handling
+    - s390/dasd: Fix potential memleak in dasd_eckd_init()
+    - sched/deadline,rt: Remove unused parameter from pick_next_[rt|dl]_entity()
+    - sched/rt: pick_next_rt_entity(): check list_entry
+    - block: bio-integrity: Copy flags when bio_integrity_payload is cloned
+    - wifi: rsi: Fix memory leak in rsi_coex_attach()
+    - net/wireless: Delete unnecessary checks before the macro call
+      “dev_kfree_skb”
+    - wifi: iwlegacy: common: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: fix memory leak in lbs_init_adapter()
+    - wifi: rtl8xxxu: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - rtlwifi: fix -Wpointer-sign warning
+    - wifi: rtlwifi: Fix global-out-of-bounds bug in
+      _rtl8812ae_phy_set_txpower_limit()
+    - ipw2x00: switch from 'pci_' to 'dma_' API
+    - wifi: ipw2x00: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: ipw2200: fix memory leak in ipw_wdev_init()
+    - wilc1000: let wilc_mac_xmit() return NETDEV_TX_OK
+    - wifi: wilc1000: fix potential memory leak in wilc_mac_xmit()
+    - wifi: brcmfmac: fix potential memory leak in brcmf_netdev_start_xmit()
+    - wifi: brcmfmac: unmap dma buffer in brcmf_msgbuf_alloc_pktid()
+    - wifi: libertas_tf: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: if_usb: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: main: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: cmdresp: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: wl3501_cs: don't call kfree_skb() under spin_lock_irqsave()
+    - crypto: x86/ghash - fix unaligned access in ghash_setkey()
+    - ACPICA: Drop port I/O validation for some regions
+    - genirq: Fix the return type of kstat_cpu_irqs_sum()
+    - lib/mpi: Fix buffer overrun when SG is too long
+    - ACPICA: nsrepair: handle cases without a return value correctly
+    - wifi: orinoco: check return value of hermes_write_wordrec()
+    - wifi: ath9k: htc_hst: free skb in ath9k_htc_rx_msg() if there is no callback
+      function
+    - ath9k: hif_usb: simplify if-if to if-else
+    - ath9k: htc: clean up statistics macros
+    - wifi: ath9k: hif_usb: clean up skbs if ath9k_hif_usb_rx_stream() fails
+    - wifi: ath9k: Fix potential stack-out-of-bounds write in
+      ath9k_wmi_rsp_callback()
+    - ACPI: battery: Fix missing NUL-termination with large strings
+    - crypto: ccp - Failure on re-initialization due to duplicate sysfs filename
+    - crypto: essiv - remove redundant null pointer check before kfree
+    - crypto: essiv - Handle EBUSY correctly
+    - crypto: seqiv - Handle EBUSY correctly
+    - powercap: fix possible name leak in powercap_register_zone()
+    - net/mlx5: Enhance debug print in page allocation failure
+    - irqchip/alpine-msi: Fix refcount leak in alpine_msix_init_domains
+    - irqchip/irq-mvebu-gicp: Fix refcount leak in mvebu_gicp_probe
+    - irqchip/ti-sci: Fix refcount leak in ti_sci_intr_irq_domain_probe
+    - mptcp: add sk_stop_timer_sync helper
+    - net: add sock_init_data_uid()
+    - tun: tun_chr_open(): correctly initialize socket uid
+    - tap: tap_open(): correctly initialize socket uid
+    - OPP: fix error checking in opp_migrate_dentry()
+    - Bluetooth: L2CAP: Fix potential user-after-free
+    - libbpf: Fix alen calculation in libbpf_nla_dump_errormsg()
+    - rds: rds_rm_zerocopy_callback() correct order for list_add_tail()
+    - crypto: rsa-pkcs1pad - Use akcipher_request_complete
+    - m68k: /proc/hardware should depend on PROC_FS
+    - RISC-V: time: initialize hrtimer based broadcast clock event device
+    - usb: gadget: udc: Avoid tasklet passing a global
+    - wifi: iwl3945: Add missing check for create_singlethread_workqueue
+    - wifi: iwl4965: Add missing check for create_singlethread_workqueue()
+    - wifi: mwifiex: fix loop iterator in mwifiex_update_ampdu_txwinsize()
+    - crypto: crypto4xx - Call dma_unmap_page when done
+    - wifi: mac80211: make rate u32 in sta_set_rate_info_rx()
+    - thermal/drivers/hisi: Drop second sensor hi3660
+    - can: esd_usb: Move mislocated storage of SJA1000_ECC_SEG bits in case of a
+      bus error
+    - irqchip/irq-brcmstb-l2: Set IRQ_LEVEL for level triggered interrupts
+    - irqchip/irq-bcm7120-l2: Set IRQ_LEVEL for level triggered interrupts
+    - selftests/net: Interpret UDP_GRO cmsg data as an int value
+    - drm/fourcc: Add missing big-endian XRGB1555 and RGB565 formats
+    - drm: mxsfb: DRM_MXSFB should depend on ARCH_MXS || ARCH_MXC
+    - drm/bridge: megachips: Fix error handling in i2c_register_driver()
+    - drm/vc4: dpi: Add option for inverting pixel clock and output enable
+    - drm/vc4: dpi: Fix format mapping for RGB565
+    - gpu: ipu-v3: common: Add of_node_put() for reference returned by
+      of_graph_get_port_by_id()
+    - drm/msm/hdmi: Add missing check for alloc_ordered_workqueue
+    - pinctrl: stm32: Fix refcount leak in stm32_pctrl_get_irq_domain
+    - ASoC: fsl_sai: initialize is_dsp_mode flag
+    - ALSA: hda/ca0132: minor fix for allocation size
+    - drm/mipi-dsi: Fix byte order of 16-bit DCS set/get brightness
+    - drm/msm: use strscpy instead of strncpy
+    - drm/msm/dpu: Add check for cstate
+    - drm/msm/dpu: Add check for pstates
+    - drm/exynos: Don't reset bridge->next
+    - drm/bridge: Rename bridge helpers targeting a bridge chain
+    - drm/bridge: Introduce drm_bridge_get_next_bridge()
+    - drm: Initialize struct drm_crtc_state.no_vblank from device settings
+    - drm/msm/mdp5: Add check for kzalloc
+    - gpu: host1x: Don't skip assigning syncpoints to channels
+    - drm/mediatek: remove cast to pointers passed to kfree
+    - drm/mediatek: Use NULL instead of 0 for NULL pointer
+    - drm/mediatek: Drop unbalanced obj unref
+    - drm/mediatek: Clean dangling pointer on bind error path
+    - ASoC: soc-compress.c: fixup private_data on snd_soc_new_compress()
+    - gpio: vf610: connect GPIO label to dev name
+    - hwmon: (ltc2945) Handle error case in ltc2945_value_store
+    - scsi: aic94xx: Add missing check for dma_map_single()
+    - spi: bcm63xx-hsspi: fix pm_runtime
+    - spi: bcm63xx-hsspi: Fix multi-bit mode setting
+    - hwmon: (mlxreg-fan) Return zero speed for broken fan
+    - dm: remove flush_scheduled_work() during local_exit()
+    - spi: synquacer: Fix timeout handling in synquacer_spi_transfer_one()
+    - ASoC: dapm: declare missing structure prototypes
+    - ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared
+    - HID: bigben: use spinlock to protect concurrent accesses
+    - HID: bigben_worker() remove unneeded check on report_field
+    - HID: bigben: use spinlock to safely schedule workers
+    - HID: asus: Only set EV_REP if we are adding a mapping
+    - HID: asus: Add report_size to struct asus_touchpad_info
+    - HID: asus: Add support for multi-touch touchpad on Medion Akoya E1239T
+    - HID: asus: Fix mute and touchpad-toggle keys on Medion Akoya E1239T
+    - hid: bigben_probe(): validate report count
+    - nfsd: fix race to check ls_layouts
+    - cifs: Fix lost destroy smbd connection when MR allocate failed
+    - cifs: Fix warning and UAF when destroy the MR list
+    - gfs2: jdata writepage fix
+    - perf llvm: Fix inadvertent file creation
+    - perf tools: Fix auto-complete on aarch64
+    - sparc: allow PM configs for sparc32 COMPILE_TEST
+    - mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read()
+    - clk: qcom: gcc-qcs404: disable gpll[04]_out_aux parents
+    - clk: qcom: gcc-qcs404: fix names of the DSI clocks used as parents
+    - mtd: rawnand: sunxi: Fix the size of the last OOB region
+    - clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed
+    - clk: renesas: cpg-mssr: Use enum clk_reg_layout instead of a boolean flag
+    - clk: renesas: cpg-mssr: Remove superfluous check in resume code
+    - Input: ads7846 - don't report pressure for ads7845
+    - Input: ads7846 - don't check penirq immediately for 7845
+    - clk: qcom: gpucc-sdm845: fix clk_dis_wait being programmed for CX GDSC
+    - powerpc/powernv/ioda: Skip unallocated resources when mapping to PE
+    - clk: Honor CLK_OPS_PARENT_ENABLE in clk_core_is_enabled()
+    - powerpc/pseries/lpar: add missing RTAS retry status handling
+    - powerpc/pseries/lparcfg: add missing RTAS retry status handling
+    - powerpc/rtas: make all exports GPL
+    - powerpc/rtas: ensure 4KB alignment for rtas_data_buf
+    - powerpc/eeh: Small refactor of eeh_handle_normal_event()
+    - powerpc/eeh: Set channel state after notifying the drivers
+    - MIPS: SMP-CPS: fix build error when HOTPLUG_CPU not set
+    - MIPS: vpe-mt: drop physical_memsize
+    - remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
+    - media: platform: ti: Add missing check for devm_regulator_get
+    - powerpc: Remove linker flag from KBUILD_AFLAGS
+    - media: ov5675: Fix memleak in ov5675_init_controls()
+    - media: i2c: ov772x: Fix memleak in ov772x_probe()
+    - media: i2c: ov7670: 0 instead of -EINVAL was returned
+    - media: usb: siano: Fix use after free bugs caused by do_submit_urb
+    - rpmsg: glink: Avoid infinite loop on intent for missing channel
+    - udf: Define EFSCORRUPTED error code
+    - ARM: dts: exynos: Use Exynos5420 compatible for the MIPI video phy
+    - blk-iocost: fix divide by 0 error in calc_lcoefs()
+    - wifi: brcmfmac: Fix potential stack-out-of-bounds in brcmf_c_preinit_dcmds()
+    - rcu: Suppress smp_processor_id() complaint in
+      synchronize_rcu_expedited_wait()
+    - thermal: intel: Fix unsigned comparison with less than zero
+    - timers: Prevent union confusion from unexpected restart_syscall()
+    - x86/bugs: Reset speculation control settings on init
+    - wifi: brcmfmac: ensure CLM version is null-terminated to prevent stack-out-
+      of-bounds
+    - wifi: mt7601u: fix an integer underflow
+    - inet: fix fast path in __inet_hash_connect()
+    - ice: add missing checks for PF vsi type
+    - ACPI: Don't build ACPICA with '-Os'
+    - net: bcmgenet: Add a check for oversized packets
+    - m68k: Check syscall_trace_enter() return code
+    - wifi: mt76: dma: free rx_head in mt76_dma_rx_cleanup
+    - ACPI: video: Fix Lenovo Ideapad Z570 DMI match
+    - net/mlx5: fw_tracer: Fix debug print
+    - coda: Avoid partial allocation of sig_inputArgs
+    - uaccess: Add minimum bounds check on kernel buffer size
+    - drm/amd/display: Fix potential null-deref in dm_resume
+    - drm/omap: dsi: Fix excessive stack usage
+    - HID: Add Mapping for System Microphone Mute
+    - drm/radeon: free iio for atombios when driver shutdown
+    - drm/msm/dsi: Add missing check for alloc_ordered_workqueue
+    - docs/scripts/gdb: add necessary make scripts_gdb step
+    - ASoC: kirkwood: Iterate over array indexes instead of using pointer math
+    - regulator: max77802: Bounds check regulator id against opmode
+    - regulator: s5m8767: Bounds check id indexing into arrays
+    - hwmon: (coretemp) Simplify platform device handling
+    - pinctrl: at91: use devm_kasprintf() to avoid potential leaks
+    - drm: panel-orientation-quirks: Add quirk for Lenovo IdeaPad Duet 3 10IGL5
+    - dm thin: add cond_resched() to various workqueue loops
+    - dm cache: add cond_resched() to various workqueue loops
+    - nfsd: zero out pointers after putting nfsd_files on COPY setup error
+    - wifi: rtl8xxxu: fixing transmisison failure for rtl8192eu
+    - firmware: coreboot: framebuffer: Ignore reserved pixel color bits
+    - rtc: pm8xxx: fix set-alarm race
+    - ipmi_ssif: Rename idle state and check
+    - s390: discard .interp section
+    - s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
+    - s390/kprobes: fix current_kprobe never cleared after kprobes reenter
+    - ARM: dts: exynos: correct HDMI phy compatible in Exynos4
+    - hfs: fix missing hfs_bnode_get() in __hfs_bnode_create
+    - fs: hfsplus: fix UAF issue in hfsplus_put_super
+    - f2fs: fix information leak in f2fs_move_inline_dirents()
+    - f2fs: fix cgroup writeback accounting with fs-layer encryption
+    - ocfs2: fix defrag path triggering jbd2 ASSERT
+    - ocfs2: fix non-auto defrag path not working issue
+    - udf: Truncate added extents on failed expansion
+    - udf: Do not bother merging very long extents
+    - udf: Do not update file length for failed writes to inline files
+    - udf: Preserve link count of system files
+    - udf: Detect system inodes linked into directory hierarchy
+    - udf: Fix file corruption when appending just after end of preallocated
+      extent
+    - KVM: Destroy target device if coalesced MMIO unregistration fails
+    - KVM: s390: disable migration mode when dirty tracking is disabled
+    - x86/virt: Force GIF=1 prior to disabling SVM (for reboot flows)
+    - x86/crash: Disable virt in core NMI crash handler to avoid double shootdown
+    - x86/reboot: Disable virtualization in an emergency if SVM is supported
+    - x86/reboot: Disable SVM, not just VMX, when stopping CPUs
+    - x86/kprobes: Fix __recover_optprobed_insn check optimizing logic
+    - x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe
+      range
+    - x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
+    - x86/microcode/AMD: Add a @cpu parameter to the reloading functions
+    - x86/microcode/AMD: Fix mixed steppings support
+    - x86/speculation: Allow enabling STIBP with legacy IBRS
+    - Documentation/hw-vuln: Document the interaction between IBRS and STIBP
+    - ima: Align ima_file_mmap() parameters with mmap_file LSM hook
+    - irqdomain: Fix association race
+    - irqdomain: Fix disassociation race
+    - irqdomain: Drop bogus fwspec-mapping error handling
+    - ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls()
+    - ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC
+    - ext4: optimize ea_inode block expansion
+    - ext4: refuse to create ea block when umounted
+    - wifi: rtl8xxxu: Use a longer retry limit of 48
+    - wifi: cfg80211: Fix use after free for wext
+    - thermal: intel: powerclamp: Fix cur_state for multi package system
+    - dm flakey: fix logic when corrupting a bio
+    - dm flakey: don't corrupt the zero page
+    - ARM: dts: exynos: correct TMU phandle in Exynos4
+    - ARM: dts: exynos: correct TMU phandle in Odroid XU
+    - rbd: avoid use-after-free in do_rbd_add() when rbd_dev_create() fails
+    - alpha: fix FEN fault handling
+    - mips: fix syscall_get_nr
+    - media: ipu3-cio2: Fix PM runtime usage_count in driver unbind
+    - mm: memcontrol: deprecate charge moving
+    - mm/thp: check and bail out if page in deferred queue already
+    - ktest.pl: Give back console on Ctrt^C on monitor
+    - ktest.pl: Fix missing "end_monitor" when machine check fails
+    - ktest.pl: Add RUN_TIMEOUT option with default unlimited
+    - scsi: qla2xxx: Fix link failure in NPIV environment
+    - scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests
+    - scsi: qla2xxx: Fix erroneous link down
+    - scsi: ses: Don't attach if enclosure has no components
+    - scsi: ses: Fix slab-out-of-bounds in ses_enclosure_data_process()
+    - scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix possible desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix slab-out-of-bounds in ses_intf_remove()
+    - PCI/PM: Observe reset delay irrespective of bridge_d3
+    - PCI: hotplug: Allow marking devices as disconnected during bind/unbind
+    - PCI: Avoid FLR for AMD FCH AHCI adapters
+    - drm/i915/quirks: Add inverted backlight quirk for HP 14-r206nv
+    - drm/radeon: Fix eDP for single-display iMac11,2
+    - wifi: ath9k: use proper statements in conditionals
+    - kbuild: Port silent mode detection to future gnu make.
+    - fs/jfs: fix shift exponent db_agl2size negative
+    - pwm: sifive: Reduce time the controller lock is held
+    - pwm: sifive: Always let the first pwm_apply_state succeed
+    - pwm: stm32-lp: fix the check on arr and cmp registers update
+    - f2fs: use memcpy_{to,from}_page() where possible
+    - fs: f2fs: initialize fsdata in pagecache_write()
+    - um: vector: Fix memory leak in vector_config
+    - ubi: ensure that VID header offset + VID header size <= alloc, size
+    - ubifs: Fix build errors as symbol undefined
+    - ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted
+    - ubifs: Rectify space budget for ubifs_xrename()
+    - ubifs: Fix wrong dirty space budget for dirty inode
+    - ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1
+    - ubifs: Reserve one leb for each journal head while doing budget
+    - ubi: Fix use-after-free when volume resizing failed
+    - ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume()
+    - ubifs: Fix memory leak in alloc_wbufs()
+    - ubi: Fix possible null-ptr-deref in ubi_free_volume()
+    - ubifs: Re-statistic cleaned znode count if commit failed
+    - ubifs: dirty_cow_znode: Fix memleak in error handling path
+    - ubifs: ubifs_writepage: Mark page dirty after writing inode failed
+    - ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show()
+    - ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed
+    - x86: um: vdso: Add '%rcx' and '%r11' to the syscall clobber list
+    - watchdog: at91sam9_wdt: use devm_request_irq to avoid missing free_irq() in
+      error path
+    - watchdog: Fix kmemleak in watchdog_cdev_register
+    - watchdog: pcwd_usb: Fix attempting to access uninitialized memory
+    - netfilter: ctnetlink: fix possible refcount leak in
+      ctnetlink_create_conntrack()
+    - ipv6: Add lwtunnel encap size of all siblings in nexthop calculation
+    - sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop
+    - net: fix __dev_kfree_skb_any() vs drop monitor
+    - 9p/xen: fix version parsing
+    - 9p/xen: fix connection sequence
+    - 9p/rdma: unmap receive dma buffer in rdma_request()/post_recv()
+    - net/mlx5: Geneve, Fix handling of Geneve object id as error code
+    - nfc: fix memory leak of se_io context in nfc_genl_se_io
+    - net/sched: act_sample: fix action bind logic
+    - ARM: dts: spear320-hmi: correct STMPE GPIO compatible
+    - tcp: tcp_check_req() can be called from process context
+    - vc_screen: modify vcs_size() handling in vcs_read()
+    - rtc: sun6i: Make external 32k oscillator optional
+    - rtc: sun6i: Always export the internal oscillator
+    - scsi: ipr: Work around fortify-string warning
+    - thermal: intel: quark_dts: fix error pointer dereference
+    - thermal: intel: BXT_PMIC: select REGMAP instead of depending on it
+    - tracing: Add NULL checks for buffer in ring_buffer_free_read_page()
+    - firmware/efi sysfb_efi: Add quirk for Lenovo IdeaPad Duet 3
+    - mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak
+    - media: uvcvideo: Handle cameras with invalid descriptors
+    - media: uvcvideo: Handle errors from calls to usb_string
+    - media: uvcvideo: Quirk for autosuspend in Logitech B910 and C910
+    - media: uvcvideo: Silence memcpy() run-time false positive warnings
+    - staging: emxx_udc: Add checks for dma_alloc_coherent()
+    - tty: fix out-of-bounds access in tty_driver_lookup_tty()
+    - tty: serial: fsl_lpuart: disable the CTS when send break signal
+    - mei: bus-fixup:upon error print return values of send and receive
+    - tools/iio/iio_utils:fix memory leak
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_status_word()
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_config_word()
+    - usb: host: xhci: mvebu: Iterate over array indexes instead of using pointer
+      math
+    - USB: ene_usb6250: Allocate enough memory for full object
+    - usb: uvc: Enumerate valid values for color matching
+    - kernel/fail_function: fix memory leak with using debugfs_lookup()
+    - PCI: Add ACS quirk for Wangxun NICs
+    - phy: rockchip-typec: Fix unsigned comparison with less than zero
+    - net: tls: avoid hanging tasks on the tx_lock
+    - x86/resctrl: Apply READ_ONCE/WRITE_ONCE to task_struct.{rmid,closid}
+    - x86/resctl: fix scheduler confusion with 'current'
+    - Bluetooth: hci_sock: purge socket queues in the destruct() callback
+    - SAUCE: Revert "UBUNTU: SAUCE: Fix inet_csk_listen_start after CVE-2023-0461"
+    - tcp: Fix listen() regression in 5.4.229.
+    - media: uvcvideo: Provide sync and async uvc_ctrl_status_event
+    - media: uvcvideo: Fix race condition with usb_kill_urb
+    - dt-bindings: rtc: sun6i-a31-rtc: Loosen the requirements on the clocks
+    - Linux 5.4.235
+    - [Config] Drop mxsfb for armhf:generic-lpae
+  * Focal update: v5.4.234 upstream stable release (LP: #2017691)
+    - arm64: dts: rockchip: drop unused LED mode property from rk3328-roc-cc
+    - ARM: dts: rockchip: add power-domains property to dp node on rk3288
+    - ACPI: NFIT: fix a potential deadlock during NFIT teardown
+    - btrfs: send: limit number of clones and allocated memory size
+    - IB/hfi1: Assign npages earlier
+    - neigh: make sure used and confirmed times are valid
+    - HID: core: Fix deadloop in hid_apply_multiplier.
+    - bpf: bpf_fib_lookup should not return neigh in NUD_FAILED state
+    - net: Remove WARN_ON_ONCE(sk->sk_forward_alloc) from sk_stream_kill_queues().
+    - vc_screen: don't clobber return value in vcs_read
+    - dmaengine: sh: rcar-dmac: Check for error num after dma_set_max_seg_size
+    - USB: serial: option: add support for VW/Skoda "Carstick LTE"
+    - USB: core: Don't hold device lock while reading the "descriptors" sysfs file
+    - Linux 5.4.234
+  * CVE-2023-30456
+    - KVM: nVMX: add missing consistency checks for CR0 and CR4
+  * CVE-2023-1859
+    - 9p/xen : Fix use after free bug in xen_9pfs_front_remove due to race
+      condition
+  * CVE-2023-1670
+    - xirc2ps_cs: Fix use after free bug in xirc2ps_detach
+
+  [ Ubuntu: 5.4.0-149.166 ]
+
+  * focal/linux: 5.4.0-149.166 -proposed tracker (LP: #2016591)
+  * Focal update: v5.4.233 upstream stable release (LP: #2015909)
+    - dma-mapping: add generic helpers for mapping sgtable objects
+    - scatterlist: add generic wrappers for iterating over sgtable objects
+    - drm: etnaviv: fix common struct sg_table related issues
+    - drm/etnaviv: don't truncate physical page address
+    - wifi: rtl8xxxu: gen2: Turn on the rate control
+    - powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G
+    - random: always mix cycle counter in add_latent_entropy()
+    - KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception
+    - can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len
+    - powerpc: dts: t208x: Disable 10G on MAC1 and MAC2
+    - alarmtimer: Prevent starvation by small intervals and SIG_IGN
+    - drm/i915/gvt: fix double free bug in split_2MB_gtt_entry
+    - mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
+    - uaccess: Add speculation barrier to copy_from_user()
+    - wifi: mwifiex: Add missing compatible string for SD8787
+    - ext4: Fix function prototype mismatch for ext4_feat_ktype
+    - Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo
+      child qdiscs"
+    - bpf: add missing header file include
+    - Linux 5.4.233
+  *  selftest: fib_tests: Always cleanup before exit  (LP: #2015956)
+    - selftest: fib_tests: Always cleanup before exit
+  * fib_tests.sh in ubuntu_kernel_selftests was skipped silently on Focal
+    (LP: #2015440)
+    - selftests: Fix the executable permissions for fib_tests.sh
+  * Debian autoreconstruct Fix restoration of execute permissions (LP: #2015498)
+    - [Debian] autoreconstruct - fix restoration of execute permissions
+  * kernel: fix __clear_user() inline assembly constraints (LP: #2013088)
+    - s390/uaccess: add missing earlyclobber annotations to __clear_user()
+  * i/o error if next unused loop device is queried (LP: #1856871)
+    - loop: fix I/O error on fsync() in detached loop devices
+  * CVE-2023-1075
+    - net/tls: tls_is_tx_ready() checked list_entry
+  * Focal update: v5.4.232 upstream stable release (LP: #2011625)
+    - firewire: fix memory leak for payload of request subaction to IEC 61883-1
+      FCP region
+    - bus: sunxi-rsb: Fix error handling in sunxi_rsb_init()
+    - ASoC: Intel: bytcr_rt5651: Drop reference count of ACPI device after use
+    - ALSA: hda/via: Avoid potential array out-of-bound in add_secret_dac_path()
+    - arm64: dts: imx8mm: Fix pad control for UART1_DTE_RX
+    - scsi: Revert "scsi: core: map PQ=1, PDT=other values to
+      SCSI_SCAN_TARGET_PRESENT"
+    - WRITE is "data source", not destination...
+    - fix iov_iter_bvec() "direction" argument
+    - fix "direction" argument of iov_iter_kvec()
+    - netrom: Fix use-after-free caused by accept on already connected socket
+    - netfilter: br_netfilter: disable sabotage_in hook after first suppression
+    - squashfs: harden sanity check in squashfs_read_xattr_id_table
+    - net: phy: meson-gxl: Add generic dummy stubs for MMD register access
+    - can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
+    - ata: libata: Fix sata_down_spd_limit() when no link speed is reported
+    - selftests: net: udpgso_bench_rx: Fix 'used uninitialized' compiler warning
+    - selftests: net: udpgso_bench_rx/tx: Stop when wrong CLI args are provided
+    - selftests: net: udpgso_bench_tx: Cater for pending datagrams zerocopy
+      benchmarking
+    - virtio-net: Keep stop() to follow mirror sequence of open()
+    - net: openvswitch: fix flow memory leak in ovs_flow_cmd_new
+    - efi: fix potential NULL deref in efi_mem_reserve_persistent
+    - scsi: target: core: Fix warning on RT kernels
+    - scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
+    - i2c: rk3x: fix a bunch of kernel-doc warnings
+    - net/x25: Fix to not accept on connected socket
+    - iio: adc: stm32-dfsdm: fill module aliases
+    - usb: dwc3: dwc3-qcom: Fix typo in the dwc3 vbus override API
+    - usb: dwc3: qcom: enable vbus override when in OTG dr-mode
+    - usb: gadget: f_fs: Fix unbalanced spinlock in __ffs_ep0_queue_wait
+    - vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
+    - Input: i8042 - move __initconst to fix code styling warning
+    - Input: i8042 - merge quirk tables
+    - Input: i8042 - add TUXEDO devices to i8042 quirk tables
+    - Input: i8042 - add Clevo PCX0DX to i8042 quirk table
+    - fbcon: Check font dimension limits
+    - watchdog: diag288_wdt: do not use stack buffers for hardware data
+    - watchdog: diag288_wdt: fix __diag288() inline assembly
+    - efi: Accept version 2 of memory attributes table
+    - iio: hid: fix the retval in accel_3d_capture_sample
+    - iio: adc: berlin2-adc: Add missing of_node_put() in error path
+    - iio:adc:twl6030: Enable measurements of VUSB, VBAT and others
+    - parisc: Fix return code of pdc_iodc_print()
+    - parisc: Wire up PTRACE_GETREGS/PTRACE_SETREGS for compat case
+    - riscv: disable generation of unwind tables
+    - mm: hugetlb: proc: check for hugetlb shared PMD in /proc/PID/smaps
+    - fpga: stratix10-soc: Fix return value check in s10_ops_write_init()
+    - mm/swapfile: add cond_resched() in get_swap_pages()
+    - Squashfs: fix handling and sanity checking of xattr_ids count
+    - nvmem: core: fix cell removal on error
+    - mm: swap: properly update readahead statistics in unuse_pte_range()
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - serial: 8250_dma: Fix DMA Rx completion race
+    - serial: 8250_dma: Fix DMA Rx rearm race
+    - powerpc/imc-pmu: Revert nest_init_lock to being a mutex
+    - fbdev: smscufx: fix error handling code in ufx_usb_probe
+    - f2fs: fix to do sanity check on i_extra_isize in is_alive()
+    - wifi: brcmfmac: Check the count value of channel spec to prevent out-of-
+      bounds reads
+    - iio:adc:twl6030: Enable measurement of VAC
+    - btrfs: limit device extents to the device size
+    - btrfs: zlib: zero-initialize zlib workspace
+    - ALSA: emux: Avoid potential array out-of-bound in snd_emux_xg_control()
+    - tracing: Fix poll() and select() do not work on per_cpu trace_pipe and
+      trace_pipe_raw
+    - can: j1939: do not wait 250 ms if the same addr was already claimed
+    - IB/hfi1: Restore allocated resources on failed copyout
+    - IB/IPoIB: Fix legacy IPoIB due to wrong number of queues
+    - iommu: Add gfp parameter to iommu_ops::map
+    - RDMA/usnic: use iommu_map_atomic() under spin_lock()
+    - xfrm: fix bug with DSCP copy to v6 from v4 tunnel
+    - bonding: fix error checking in bond_debug_reregister()
+    - net: phy: meson-gxl: use MMD access dummy stubs for GXL, internal PHY
+    - ionic: clean interrupt before enabling queue to avoid credit race
+    - ice: Do not use WQ_MEM_RECLAIM flag for workqueue
+    - rds: rds_rm_zerocopy_callback() use list_first_entry()
+    - selftests: forwarding: lib: quote the sysctl values
+    - ALSA: pci: lx6464es: fix a debug loop
+    - pinctrl: aspeed: Fix confusing types in return value
+    - pinctrl: single: fix potential NULL dereference
+    - pinctrl: intel: Restore the pins that used to be in Direct IRQ mode
+    - net: USB: Fix wrong-direction WARNING in plusb.c
+    - usb: core: add quirk for Alcor Link AK9563 smartcard reader
+    - usb: typec: altmodes/displayport: Fix probe pin assign check
+    - ceph: flush cap releases when the session is flushed
+    - riscv: Fixup race condition on PG_dcache_clean in flush_icache_pte
+    - arm64: dts: meson-gx: Make mmc host controller interrupts level-sensitive
+    - arm64: dts: meson-g12-common: Make mmc host controller interrupts level-
+      sensitive
+    - arm64: dts: meson-axg: Make mmc host controller interrupts level-sensitive
+    - nvme-pci: Move enumeration by class to be last in the table
+    - bpf: Always return target ifindex in bpf_fib_lookup
+    - migrate: hugetlb: check for hugetlb shared PMD in node migration
+    - selftests/bpf: Verify copy_register_state() preserves parent/live fields
+    - ASoC: cs42l56: fix DT probe
+    - tools/virtio: fix the vringh test for virtio ring changes
+    - net/rose: Fix to not accept on connected socket
+    - net: stmmac: do not stop RX_CLK in Rx LPI state for qcs404 SoC
+    - net: sched: sch: Bounds check priority
+    - s390/decompressor: specify __decompress() buf len to avoid overflow
+    - nvme-fc: fix a missing queue put in nvmet_fc_ls_create_association
+    - aio: fix mremap after fork null-deref
+    - btrfs: free device in btrfs_close_devices for a single device filesystem
+    - netfilter: nft_tproxy: restrict to prerouting hook
+    - xfs: remove the xfs_efi_log_item_t typedef
+    - xfs: remove the xfs_efd_log_item_t typedef
+    - xfs: remove the xfs_inode_log_item_t typedef
+    - xfs: factor out a xfs_defer_create_intent helper
+    - xfs: merge the ->log_item defer op into ->create_intent
+    - xfs: merge the ->diff_items defer op into ->create_intent
+    - xfs: turn dfp_intent into a xfs_log_item
+    - xfs: refactor xfs_defer_finish_noroll
+    - xfs: log new intent items created as part of finishing recovered intent
+      items
+    - xfs: fix finobt btree block recovery ordering
+    - xfs: proper replay of deferred ops queued during log recovery
+    - xfs: xfs_defer_capture should absorb remaining block reservations
+    - xfs: xfs_defer_capture should absorb remaining transaction reservation
+    - xfs: clean up bmap intent item recovery checking
+    - xfs: clean up xfs_bui_item_recover iget/trans_alloc/ilock ordering
+    - xfs: fix an incore inode UAF in xfs_bui_recover
+    - xfs: change the order in which child and parent defer ops are finished
+    - xfs: periodically relog deferred intent items
+    - xfs: expose the log push threshold
+    - xfs: only relog deferred intent items if free space in the log gets low
+    - xfs: fix missing CoW blocks writeback conversion retry
+    - xfs: ensure inobt record walks always make forward progress
+    - xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks
+    - xfs: prevent UAF in xfs_log_item_in_current_chkpt
+    - xfs: sync lazy sb accounting on quiesce of read-only mounts
+    - Revert "ipv4: Fix incorrect route flushing when source address is deleted"
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - mmc: sdio: fix possible resource leaks in some error paths
+    - mmc: mmc_spi: fix error handling in mmc_spi_probe()
+    - ALSA: hda/conexant: add a new hda codec SN6180
+    - ALSA: hda/realtek - fixed wrong gpio assigned
+    - sched/psi: Fix use-after-free in ep_remove_wait_queue()
+    - hugetlb: check for undefined shift on 32 bit architectures
+    - Revert "mm: Always release pages to the buddy allocator in
+      memblock_free_late()."
+    - net: Fix unwanted sign extension in netdev_stats_to_stats64()
+    - revert "squashfs: harden sanity check in squashfs_read_xattr_id_table"
+    - ixgbe: allow to increase MTU to 3K with XDP enabled
+    - i40e: add double of VLAN header when computing the max MTU
+    - net: bgmac: fix BCM5358 support by setting correct flags
+    - sctp: sctp_sock_filter(): avoid list_entry() on possibly empty list
+    - dccp/tcp: Avoid negative sk_forward_alloc by ipv6_pinfo.pktoptions.
+    - net/usb: kalmia: Don't pass act_len in usb_bulk_msg error path
+    - net: stmmac: fix order of dwmac5 FlexPPS parametrization sequence
+    - bnxt_en: Fix mqprio and XDP ring checking logic
+    - net: stmmac: Restrict warning on disabling DMA store and fwd mode
+    - ixgbe: add double of VLAN header when computing the max MTU
+    - ipv6: Fix datagram socket connection with DSCP.
+    - ipv6: Fix tcp socket connection with DSCP.
+    - i40e: Add checking for null for nlmsg_find_attr()
+    - kvm: initialize all of the kvm_debugregs structure before sending it to
+      userspace
+    - nilfs2: fix underflow in second superblock position calculations
+    - ASoC: SOF: Intel: hda-dai: fix possible stream_tag leak
+    - net: sched: sch: Fix off by one in htb_activate_prios()
+    - iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()
+    - Linux 5.4.232
+  * CVE-2023-1118
+    - media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
+
+  [ Ubuntu: 5.4.0-148.165 ]
+
+  * focal/linux: 5.4.0-148.165 -proposed tracker (LP: #2016777)
+  * CVE-2023-1829
+    - net/sched: Retire tcindex classifier
+    - [Config]: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 19 Jun 2023 13:05:12 +0800
+
+linux-ein (5.4.0-1037.43) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1037.43 -proposed tracker (LP: #2017272)
+
+  * [K4500-NXP][UC20] Unexpectedly reboot if using the kernel on 'master' branch
+    (LP: #2008068)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Load panel driver early
+
+  * Miscellaneous Ubuntu changes
+    - snap: Add snapcraft.yaml for Reading
+    - snap: reading: Add customized firmware
+    - snap: adopt trim-firmware
+
+  [ Ubuntu: 5.4.0-147.164 ]
+
+  * focal/linux: 5.4.0-147.164 -proposed tracker (LP: #2011959)
+  * CVE-2023-26545
+    - net: mpls: fix stale pointer if allocation fails during device rename
+  * CVE-2023-1281
+    - rcu: Upgrade rcu_swap_protected() to rcu_replace_pointer()
+    - net/sched: tcindex: update imperfect hash filters respecting rcu
+  * Focal update: v5.4.231 upstream stable release (LP: #2011226)
+    - clk: generalize devm_clk_get() a bit
+    - clk: Provide new devm_clk helpers for prepared and enabled clocks
+    - memory: atmel-sdramc: Fix missing clk_disable_unprepare in
+      atmel_ramc_probe()
+    - memory: mvebu-devbus: Fix missing clk_disable_unprepare in
+      mvebu_devbus_probe()
+    - ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts'
+    - ARM: imx27: Retrieve the SYSCTRL base address from devicetree
+    - ARM: imx31: Retrieve the IIM base address from devicetree
+    - ARM: imx35: Retrieve the IIM base address from devicetree
+    - ARM: imx: add missing of_node_put()
+    - HID: intel_ish-hid: Add check for ishtp_dma_tx_map
+    - EDAC/highbank: Fix memory leak in highbank_mc_probe()
+    - tomoyo: fix broken dependency on *.conf.default
+    - RDMA/core: Fix ib block iterator counter overflow
+    - IB/hfi1: Reject a zero-length user expected buffer
+    - IB/hfi1: Reserve user expected TIDs
+    - IB/hfi1: Fix expected receive setup error exit issues
+    - affs: initialize fsdata in affs_truncate()
+    - amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent
+    - amd-xgbe: Delay AN timeout during KR training
+    - bpf: Fix pointer-leak due to insufficient speculative store bypass
+      mitigation
+    - phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in
+      rockchip_usb2phy_power_on()
+    - net: nfc: Fix use-after-free in local_cleanup()
+    - net: wan: Add checks for NULL for utdm in undo_uhdlc_init and unmap_si_regs
+    - gpio: mxc: Always set GPIOs used as interrupt source to INPUT mode
+    - net/sched: sch_taprio: fix possible use-after-free
+    - net: fix a concurrency bug in l2tp_tunnel_register()
+    - l2tp: Serialize access to sk_user_data with sk_callback_lock
+    - l2tp: Don't sleep and disable BH under writer-side sk_callback_lock
+    - net: usb: sr9700: Handle negative len
+    - net: mdio: validate parameter addr in mdiobus_get_phy()
+    - HID: check empty report_list in hid_validate_values()
+    - HID: check empty report_list in bigben_probe()
+    - net: stmmac: fix invalid call to mdiobus_get_phy()
+    - HID: revert CHERRY_MOUSE_000C quirk
+    - usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
+    - usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
+    - net: mlx5: eliminate anonymous module_init & module_exit
+    - drm/panfrost: fix GENERIC_ATOMIC64 dependency
+    - dmaengine: Fix double increment of client_count in dma_chan_get()
+    - net: macb: fix PTP TX timestamp failure due to packet padding
+    - HID: betop: check shape of output reports
+    - dmaengine: xilinx_dma: use devm_platform_ioremap_resource()
+    - dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling
+    - dmaengine: xilinx_dma: call of_node_put() when breaking out of
+      for_each_child_of_node()
+    - tcp: avoid the lookup process failing to get sk in ehash table
+    - w1: fix deadloop in __w1_remove_master_device()
+    - w1: fix WARNING after calling w1_process()
+    - driver core: Fix test_async_probe_init saves device in wrong array
+    - net: dsa: microchip: ksz9477: port map correction in ALU table entry
+      register
+    - tcp: fix rate_app_limited to default to 1
+    - cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist
+    - ASoC: fsl_micfil: Correct the number of steps on SX controls
+    - drm: Add orientation quirk for Lenovo ideapad D330-10IGL
+    - s390/debug: add _ASM_S390_ prefix to header guard
+    - cpufreq: armada-37xx: stop using 0 as NULL pointer
+    - ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
+    - ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
+    - spi: spidev: remove debug messages that access spidev->spi without locking
+    - KVM: s390: interrupt: use READ_ONCE() before cmpxchg()
+    - scsi: hisi_sas: Set a port invalid only if there are no devices attached
+      when refreshing port id
+    - platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD
+    - platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK
+    - lockref: stop doing cpu_relax in the cmpxchg loop
+    - mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
+    - mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
+    - mmc: sdhci-esdhc-imx: correct the tuning start tap and step setting
+    - netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state
+    - fs: reiserfs: remove useless new_opts in reiserfs_remount
+    - Bluetooth: hci_sync: cancel cmd_timer if hci_open failed
+    - scsi: hpsa: Fix allocation size for scsi_host_alloc()
+    - module: Don't wait for GOING modules
+    - tracing: Make sure trace_printk() can output as soon as it can be used
+    - trace_events_hist: add check for return value of 'create_hist_field'
+    - ftrace/scripts: Update the instructions for ftrace-bisect.sh
+    - cifs: Fix oops due to uncleared server->smbd_conn in reconnect
+    - KVM: x86/vmx: Do not skip segment attributes if unusable bit is set
+    - thermal: intel: int340x: Protect trip temperature from concurrent updates
+    - ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment
+    - EDAC/device: Respect any driver-supplied workqueue polling value
+    - EDAC/qcom: Do not pass llcc_driv_data as edac_device_ctl_info's pvt_info
+    - netlink: prevent potential spectre v1 gadgets
+    - net: fix UaF in netns ops registration error path
+    - netfilter: nft_set_rbtree: skip elements in transaction from garbage
+      collection
+    - netlink: annotate data races around nlk->portid
+    - netlink: annotate data races around dst_portid and dst_group
+    - netlink: annotate data races around sk_state
+    - ipv4: prevent potential spectre v1 gadget in ip_metrics_convert()
+    - ipv4: prevent potential spectre v1 gadget in fib_metrics_match()
+    - netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE
+    - netrom: Fix use-after-free of a listening socket.
+    - net/sched: sch_taprio: do not schedule in taprio_reset()
+    - sctp: fail if no bound addresses can be used for a given scope
+    - net: ravb: Fix possible hang if RIS2_QFF1 happen
+    - thermal: intel: int340x: Add locking to int340x_thermal_get_trip_type()
+    - net/tg3: resolve deadlock in tg3_reset_task() during EEH
+    - net/phy/mdio-i2c: Move header file to include/linux/mdio
+    - net: xgene: Move shared header file into include/linux
+    - net: mdio-mux-meson-g12a: force internal PHY off on mux switch
+    - Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI
+      mode"
+    - nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted
+    - block: fix and cleanup bio_check_ro
+    - x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
+    - netfilter: conntrack: unify established states for SCTP paths
+    - perf/x86/amd: fix potential integer overflow on shift of a int
+    - clk: Fix pointer casting to prevent oops in devm_clk_release()
+    - x86/asm: Fix an assembler warning with current binutils
+    - ARM: dts: imx: Fix pca9547 i2c-mux node name
+    - bpf: Skip task with pid=1 in send_signal_common()
+    - blk-cgroup: fix missing pd_online_fn() while activating policy
+    - dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init
+    - sysctl: add a new register_sysctl_init() interface
+    - panic: unset panic_on_warn inside panic()
+    - mm: kasan: do not panic if both panic_on_warn and kasan_multishot set
+    - exit: Add and use make_task_dead.
+    - objtool: Add a missing comma to avoid string concatenation
+    - hexagon: Fix function name in die()
+    - h8300: Fix build errors from do_exit() to make_task_dead() transition
+    - csky: Fix function name in csky_alignment() and die()
+    - ia64: make IA64_MCA_RECOVERY bool instead of tristate
+    - exit: Put an upper limit on how often we can oops
+    - exit: Expose "oops_count" to sysfs
+    - exit: Allow oops_limit to be disabled
+    - panic: Consolidate open-coded panic_on_warn checks
+    - panic: Introduce warn_limit
+    - panic: Expose "warn_count" to sysfs
+    - docs: Fix path paste-o for /sys/kernel/warn_count
+    - exit: Use READ_ONCE() for all oops/warn limit reads
+    - ipv6: ensure sane device mtu in tunnels
+    - Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt
+    - usb: host: xhci-plat: add wakeup entry at sysfs
+    - Revert "xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()"
+    - Linux 5.4.231
+  * CVE-2022-3903
+    - USB: add usb_control_msg_send() and usb_control_msg_recv()
+    - USB: correct API of usb_control_msg_send/recv
+    - USB: move snd_usb_pipe_sanity_check into the USB core
+    - media: mceusb: Use new usb_control_msg_*() routines
+  * CVE-2022-3108
+    - drm/amdkfd: Check for null pointer after calling kmemdup
+  * Focal update: v5.4.230 upstream stable release (LP: #2008946)
+    - pNFS/filelayout: Fix coalescing test for single DS
+    - net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats
+    - RDMA/srp: Move large values to a new enum for gcc13
+    - f2fs: let's avoid panic if extent_tree is not created
+    - wifi: brcmfmac: fix regression for Broadcom PCIe wifi devices
+    - Add exception protection processing for vd in axi_chan_handle_err function
+    - nilfs2: fix general protection fault in nilfs_btree_insert()
+    - efi: fix userspace infinite retry read efivars after EFI runtime services
+      page fault
+    - drm/i915/gt: Reset twice
+    - ALSA: hda/realtek - Turn on power early
+    - xhci-pci: set the dma max_seg_size
+    - usb: xhci: Check endpoint is valid before dereferencing it
+    - xhci: Fix null pointer dereference when host dies
+    - xhci: Add update_hub_device override for PCI xHCI hosts
+    - xhci: Add a flag to disable USB3 lpm on a xhci root port level.
+    - usb: acpi: add helper to check port lpm capability using acpi _DSM
+    - xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
+    - prlimit: do_prlimit needs to have a speculation check
+    - USB: serial: option: add Quectel EM05-G (GR) modem
+    - USB: serial: option: add Quectel EM05-G (CS) modem
+    - USB: serial: option: add Quectel EM05-G (RS) modem
+    - USB: serial: option: add Quectel EC200U modem
+    - USB: serial: option: add Quectel EM05CN (SG) modem
+    - USB: serial: option: add Quectel EM05CN modem
+    - USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
+    - misc: fastrpc: Don't remove map on creater_process and device_release
+    - misc: fastrpc: Fix use-after-free race condition for maps
+    - usb: core: hub: disable autosuspend for TI TUSB8041
+    - comedi: adv_pci1760: Fix PWM instruction handling
+    - mmc: sunxi-mmc: Fix clock refcount imbalance during unbind
+    - btrfs: fix race between quota rescan and disable leading to NULL pointer
+      deref
+    - cifs: do not include page data when checking signature
+    - USB: serial: cp210x: add SCALANCE LPE-9000 device id
+    - usb: host: ehci-fsl: Fix module alias
+    - usb: typec: altmodes/displayport: Add pin assignment helper
+    - usb: typec: altmodes/displayport: Fix pin assignment calculation
+    - usb: gadget: g_webcam: Send color matching descriptor per frame
+    - usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
+    - usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210
+    - dt-bindings: phy: g12a-usb3-pcie-phy: fix compatible string documentation
+    - serial: pch_uart: Pass correct sg to dma_unmap_sg()
+    - dmaengine: tegra210-adma: fix global intr clear
+    - serial: atmel: fix incorrect baudrate setup
+    - gsmi: fix null-deref in gsmi_get_variable
+    - drm/i915: re-disable RC6p on Sandy Bridge
+    - drm/amd/display: Fix set scaling doesn's work
+    - drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix
+    - x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
+    - mm/khugepaged: fix collapse_pte_mapped_thp() to allow anon_vma
+    - Linux 5.4.230
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sat, 22 Apr 2023 18:48:58 +0800
+
+linux-ein (5.4.0-1036.42) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1036.42 -proposed tracker (LP: #2015677)
+
+  * [Amgis-v*] Update device trees for UIO platform driver (LP#2012101)
+    - SAUCE: amgis: dts: Add UIO node
+
+  * [imx8-all][oem-support] CAAM Driver is not loaded (LP: #2009583)
+    - MLKU-129-3 arm64: dts: imx8mp: add secure memory
+    - MLKU-25-4 arm64: dts: imx8m: add secure memory
+
+  * Miscellaneous Ubuntu changes
+    - [Config] ein: Enforce module signature check
+    - SAUCE: Add imx8 modules to signature inclusion list
+
+  [ Ubuntu: 5.4.0-146.163 ]
+
+  * focal/linux: 5.4.0-146.163 -proposed tracker (LP: #2012094)
+  * NFS deathlock with last Kernel 5.4.0-144.161 and 5.15.0-67.74 (LP: #2009325)
+    - NFS: Correct timing for assigning access cache timestamp
+
+  [ Ubuntu: 5.4.0-145.162 ]
+
+  * focal/linux: 5.4.0-145.162 -proposed tracker (LP: #2008389)
+  * [SRU]Update ice driver to support E823 devices (LP: #1986717)
+    - ice: Add device ids for E822 devices
+    - ice: add support for E823 devices
+  * btrfs/154: rename fails with EOVERFLOW when calculating item size during
+    item key collision (LP: #2004132)
+    - btrfs: correctly calculate item size used when item key collision happens
+  * rtcpie in timers from ubuntu_kernel_selftests randomly failing
+    (LP: #1814234)
+    - SAUCE: selftest: rtcpie: Force passing unreliable subtest
+  * [UBUNTU 20.04] KVM: s390: pv: don't allow userspace to set the clock under
+    PV - kernel part (LP: #1999882)
+    - KVM: s390x: fix SCK locking
+    - KVM: s390: pv: don't allow userspace to set the clock under PV
+  * CVE-2021-3669
+    - ipc: replace costly bailout check in sysvipc_find_ipc()
+  * net:fcnal-test.sh 'nettest' command not found on F/K (LP: #2006391)
+    - selftests/net: Find nettest in current directory
+  * xfs: Preallocated ioend transactions cause deadlock due to log buffer
+    exhaustion (LP: #2007219)
+    - xfs: drop submit side trans alloc for append ioends
+  * CVE-2022-4382
+    - USB: gadgetfs: Fix race between mounting and unmounting
+  * CVE-2022-2196
+    - KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
+  * ubuntu_kernel_selftests: net:udpgso_bench.sh failed (LP: #1951447)
+    - selftests: net: udpgso_bench: Fix racing bug between the rx/tx programs
+  * net:fcnal-test.sh didn't return a non-zero value even with some sub-tests
+    failed (LP: #2006692)
+    - selftests: net/fcnal-test.sh: add exit code
+  * Fix selftests/ftracetests/Meta-selftests in Focal (LP: #2006453)
+    - SAUCE: Fix ftrace/Meta-selftests bashism check
+  * CVE-2023-23559
+    - wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 09 Apr 2023 19:07:31 +0800
+
+linux-ein (5.4.0-1035.41) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1035.41 -proposed tracker (LP: #2011767)
+
+  * [UC20][Amgis-V5] Enabling OPTEE based FDE (LP#1995129)
+    - SAUCE: amgis: dts: Remove busfreq node
+    - SAUCE: amgis: dts: Fix OPTEE crash
+    - SAUCE: amgis: dts: Additional OCRAM node for OPTEE
+    - SAUCE: amgis: dts: Add secure memory
+
+  * [Amgis-V5][UC20] System reboot via RPMSG/M4 failed (LP#2009916)
+    - SAUCE: rpmsg: Change virtio bus name
+
+  * [PE100A] Fixes for LAN1 (LP: #1994123)
+    - SAUCE: net: fec: modify ethernet LED behavior for RTL8211E/RTL8211F
+    - net: phy: realtek: fix rtl8211e rx/tx delay config
+
+  * [PE100A] Fix PMIC Settings (LP: #1994118)
+    - SAUCE: arm64/dts: pe100a: modify dvs voltage of buck1~buck4.
+
+  * [PE100A] Add LTE modem support (LP: #1994089)
+    - SAUCE: net: Add support for more quectel modems
+
+  * Cadence MHDP HDMI CEC driver doesn't work when building as a module (LP:
+    #2011779)
+    - SAUCE: drm/cdns: Fix #if checks for CONFIG_DRM_CDNS_HDMI_CEC
+
+  * [PE100A] Wifi patch for WMX6219 module (LP: #1994116)
+    - [Config] CONFIG_RTW88_8822CE=y
+    - Revert "PCI: dwc: Use interrupt disabling instead of masking"
+    - PCI: dwc: Restore MSI Receiver mask during resume
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 17 Mar 2023 00:26:07 +0800
+
+linux-ein (5.4.0-1034.40) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1034.40 -proposed tracker (LP: #2009905)
+
+  * Focal update: v5.4.226 upstream stable release (LP: #2003896)
+    - [Config] updateconfigs for INET_TABLE_PERTURB_ORDER
+
+  * [K4500-NXP][UC20] HMI screen does not turn on at end of first boot process
+    or simple power cycle (LP#2002765)
+    - Revert "UBUNTU: SAUCE: drm: AVD101WX-CN: Assigned bus format to fix
+      warning:"
+
+  * [UC20] failed to bring up PLS63-W, fail rate ~10% (LP: #2008468)
+    - nvmem: core: fix registration vs use race
+
+  * Patch file for cascade-kernel (SF: #00347119)
+    - Revert "UBUNTU: SAUCE: dts: vesta-500: change pad setting to save power"
+
+  [ Ubuntu: 5.4.0-144.161 ]
+
+  * focal/linux: 5.4.0-144.161 -proposed tracker (LP: #2004653)
+  * CVE-2023-0461
+    - SAUCE: Fix inet_csk_listen_start after CVE-2023-0461
+
+  [ Ubuntu: 5.4.0-143.160 ]
+
+  * focal/linux: 5.4.0-143.160 -proposed tracker (LP: #2004385)
+  * NFS: client permission error after adding user to permissible group
+    (LP: #2003053)
+    - NFS: Clear the file access cache upon login
+    - NFS: Judge the file access cache's timestamp in rcu path
+    - NFS: Fix up a sparse warning
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914)
+    - tracing/ring-buffer: Only do full wait when cpu != RING_BUFFER_ALL_CPUS
+    - udf: Discard preallocation before extending file with a hole
+    - udf: Fix preallocation discarding at indirect extent boundary
+    - udf: Do not bother looking for prealloc extents if i_lenExtents matches
+      i_size
+    - udf: Fix extending file within last block
+    - usb: gadget: uvc: Prevent buffer overflow in setup handler
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: cp210x: add Kamstrup RF sniffer PIDs
+    - USB: serial: f81232: fix division by zero on line-speed change
+    - USB: serial: f81534: fix division by zero on line-speed change
+    - igb: Initialize mailbox message for VF reset
+    - xen-netback: move removal of "hotplug-status" to the right place
+    - HID: ite: Add support for Acer S1002 keyboard-dock
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch 10E
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch V 10
+    - HID: uclogic: Add HID_QUIRK_HIDINPUT_FORCE quirk
+    - net: loopback: use NET_NAME_PREDICTABLE for name_assign_type
+    - usb: musb: remove extra check in musb_gadget_vbus_draw
+    - ARM: dts: qcom: apq8064: fix coresight compatible
+    - arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
+    - drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
+    - arm: dts: spear600: Fix clcd interrupt
+    - soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of
+      pm_runtime_get_sync
+    - soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
+    - soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
+    - perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
+    - perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
+    - arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
+    - arm64: dts: mt2712e: Fix unit address for pinctrl node
+    - arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
+    - arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
+    - arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
+    - ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: turris-omnia: Add ethernet aliases
+    - ARM: dts: turris-omnia: Add switch port 6 node
+    - arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
+    - pstore/ram: Fix error return code in ramoops_probe()
+    - ARM: mmp: fix timer_read delay
+    - pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
+    - tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
+    - cpuidle: dt: Return the correct numbers of parsed idle states
+    - alpha: fix syscall entry in !AUDUT_SYSCALL case
+    - PM: hibernate: Fix mistake in kerneldoc comment
+    - fs: don't audit the capability check in simple_xattr_list()
+    - selftests/ftrace: event_triggers: wait longer for test_event_enable
+    - perf: Fix possible memleak in pmu_dev_alloc()
+    - timerqueue: Use rb_entry_safe() in timerqueue_getnext()
+    - proc: fixup uptime selftest
+    - lib/fonts: fix undefined behavior in bit shift for get_default_font
+    - ocfs2: fix memory leak in ocfs2_stack_glue_init()
+    - MIPS: vpe-mt: fix possible memory leak while module exiting
+    - MIPS: vpe-cmp: fix possible memory leak while module exiting
+    - selftests/efivarfs: Add checking of the test return value
+    - PNP: fix name memory leak in pnp_alloc_dev()
+    - perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
+    - irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
+    - EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
+    - nfsd: don't call nfsd_file_put from client states seqfile display
+    - genirq/irqdesc: Don't try to remove non-existing sysfs files
+    - cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
+    - libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
+    - lib/notifier-error-inject: fix error when writing -errno to debugfs file
+    - docs: fault-injection: fix non-working usage of negative values
+    - debugfs: fix error when writing negative value to atomic_t debugfs file
+    - ocfs2: ocfs2_mount_volume does cleanup job before return error
+    - ocfs2: rewrite error handling of ocfs2_fill_super
+    - ocfs2: fix memory leak in ocfs2_mount_volume()
+    - rapidio: fix possible name leaks when rio_add_device() fails
+    - rapidio: rio: fix possible name leak in rio_register_mport()
+    - clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
+    - ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
+    - uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
+    - xen/events: only register debug interrupt for 2-level events
+    - x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
+    - x86/xen: Fix memory leak in xen_init_lock_cpu()
+    - xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
+    - PM: runtime: Improve path in rpm_idle() when no callback
+    - PM: runtime: Do not call __rpm_callback() from rpm_idle()
+    - platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
+    - MIPS: BCM63xx: Add check for NULL for clk in clk_enable
+    - MIPS: OCTEON: warn only once if deprecated link status is being used
+    - fs: sysv: Fix sysv_nblocks() returns wrong value
+    - rapidio: fix possible UAF when kfifo_alloc() fails
+    - eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
+    - relay: fix type mismatch when allocating memory in relay_create_buf()
+    - hfs: Fix OOB Write in hfs_asc2mac
+    - rapidio: devices: fix missing put_device in mport_cdev_open
+    - wifi: ath9k: hif_usb: fix memory leak of urbs in
+      ath9k_hif_usb_dealloc_tx_urbs()
+    - wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
+    - wifi: rtl8xxxu: Fix reading the vendor of combo chips
+    - pata_ipx4xx_cf: Fix unsigned comparison with less than zero
+    - media: i2c: ad5820: Fix error path
+    - can: kvaser_usb: do not increase tx statistics when sending error message
+      frames
+    - can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
+    - can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to
+      {leaf,usbcan}_cmd_can_error_event
+    - can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
+    - can: kvaser_usb_leaf: Set Warning state even without bus errors
+    - can: kvaser_usb_leaf: Fix improved state not being reported
+    - can: kvaser_usb_leaf: Fix wrong CAN state after stopping
+    - can: kvaser_usb_leaf: Fix bogus restart events
+    - can: kvaser_usb: Add struct kvaser_usb_busparams
+    - can: kvaser_usb: Compare requested bittiming parameters with actual
+      parameters in do_set_{,data}_bittiming
+    - clk: renesas: r9a06g032: Repair grave increment error
+    - spi: Update reference to struct spi_controller
+    - drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
+    - ima: Rename internal filter rule functions
+    - ima: Fix fall-through warnings for Clang
+    - ima: Handle -ESTALE returned by ima_filter_rule_match()
+    - media: vivid: fix compose size exceed boundary
+    - bpf: propagate precision in ALU/ALU64 operations
+    - mtd: Fix device name leak when register device failed in add_mtd_device()
+    - wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
+    - media: camss: Clean up received buffers on failed start of streaming
+    - net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
+    - rxrpc: Fix ack.bufferSize to be 0 when generating an ack
+    - drm/radeon: Add the missed acpi_put_table() to fix memory leak
+    - drm/mediatek: Modify dpi power on/off sequence.
+    - ASoC: pxa: fix null-pointer dereference in filter()
+    - regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
+    - amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
+    - integrity: Fix memory leakage in keyring allocation error path
+    - ima: Fix misuse of dereference of pointer in template_desc_init_fields()
+    - wifi: ath10k: Fix return value in ath10k_pci_init()
+    - mtd: lpddr2_nvm: Fix possible null-ptr-deref
+    - Input: elants_i2c - properly handle the reset GPIO when power is off
+    - media: solo6x10: fix possible memory leak in solo_sysfs_init()
+    - media: platform: exynos4-is: Fix error handling in fimc_md_init()
+    - media: videobuf-dma-contig: use dma_mmap_coherent
+    - bpf: Move skb->len == 0 checks into __bpf_redirect
+    - HID: hid-sensor-custom: set fixed size for custom attributes
+    - ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
+    - ALSA: seq: fix undefined behavior in bit shift for
+      SNDRV_SEQ_FILTER_USE_EVENT
+    - regulator: core: use kfree_const() to free space conditionally
+    - clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
+    - bonding: Export skip slave logic to function
+    - bonding: Rename slave_arr to usable_slaves
+    - bonding: fix link recovery in mode 2 when updelay is nonzero
+    - mtd: maps: pxa2xx-flash: fix memory leak in probe
+    - media: imon: fix a race condition in send_packet()
+    - clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
+    - clk: imx: replace osc_hdmi with dummy
+    - pinctrl: pinconf-generic: add missing of_node_put()
+    - media: dvb-core: Fix ignored return value in dvb_register_frontend()
+    - media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
+    - media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
+    - drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
+    - ASoC: dt-bindings: wcd9335: fix reset line polarity in example
+    - ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
+    - NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
+    - NFSv4.2: Fix a memory stomp in decode_attr_security_label
+    - NFSv4.2: Fix initialisation of struct nfs4_label
+    - NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
+    - ALSA: asihpi: fix missing pci_disable_device()
+    - wifi: iwlwifi: mvm: fix double free on tx path.
+    - ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
+    - drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
+    - drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
+    - ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
+    - netfilter: conntrack: set icmpv6 redirects as RELATED
+    - bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
+    - bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
+    - bonding: uninitialized variable in bond_miimon_inspect()
+    - spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
+    - wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys()
+      fails
+    - regulator: core: fix module refcount leak in set_supply()
+    - clk: qcom: clk-krait: fix wrong div2 functions
+    - hsr: Avoid double remove of a node.
+    - configfs: fix possible memory leak in configfs_create_dir()
+    - regulator: core: fix resource leak in regulator_register()
+    - bpf, sockmap: fix race in sock_map_free()
+    - media: saa7164: fix missing pci_disable_device()
+    - ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - SUNRPC: Fix missing release socket in rpc_sockname()
+    - NFSv4.x: Fail client initialisation if state manager thread can't run
+    - mmc: alcor: fix return value check of mmc_add_host()
+    - mmc: moxart: fix return value check of mmc_add_host()
+    - mmc: mxcmmc: fix return value check of mmc_add_host()
+    - mmc: pxamci: fix return value check of mmc_add_host()
+    - mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
+    - mmc: toshsd: fix return value check of mmc_add_host()
+    - mmc: vub300: fix return value check of mmc_add_host()
+    - mmc: wmt-sdmmc: fix return value check of mmc_add_host()
+    - mmc: atmel-mci: fix return value check of mmc_add_host()
+    - mmc: omap_hsmmc: fix return value check of mmc_add_host()
+    - mmc: meson-gx: fix return value check of mmc_add_host()
+    - mmc: via-sdmmc: fix return value check of mmc_add_host()
+    - mmc: wbsd: fix return value check of mmc_add_host()
+    - mmc: mmci: fix return value check of mmc_add_host()
+    - media: c8sectpfe: Add of_node_put() when breaking out of loop
+    - media: coda: Add check for dcoda_iram_alloc
+    - media: coda: Add check for kmalloc
+    - clk: samsung: Fix memory leak in _samsung_clk_register_pll()
+    - spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
+    - wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
+    - wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
+    - blktrace: Fix output non-blktrace event when blk_classic option enabled
+    - clk: socfpga: clk-pll: Remove unused variable 'rc'
+    - clk: socfpga: use clk_hw_register for a5/c5
+    - clk: socfpga: Fix memory leak in socfpga_gate_init()
+    - net: vmw_vsock: vmci: Check memcpy_from_msg()
+    - net: defxx: Fix missing err handling in dfx_init()
+    - net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
+    - drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
+    - of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry()
+      and find_dup_cset_prop()
+    - ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: farsync: Fix kmemleak when rmmods farsync
+    - net/tunnel: wait until all sk_user_data reader finish before releasing the
+      sock
+    - net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd-xgbe: Fix logic around active and passive cables
+    - net: amd-xgbe: Check only the minimum speed for active/passive cables
+    - can: tcan4x5x: Remove invalid write in clear_interrupts
+    - net: lan9303: Fix read error execution path
+    - ntb_netdev: Use dev_kfree_skb_any() in interrupt context
+    - Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
+    - stmmac: fix potential division by 0
+    - apparmor: fix a memleak in multi_transaction_new()
+    - apparmor: fix lockdep warning when removing a namespace
+    - apparmor: Fix abi check to include v8 abi
+    - apparmor: Use pointer to struct aa_label for lbs_cred
+    - RDMA/core: Fix order of nldev_exit call
+    - f2fs: fix normal discard process
+    - RDMA/siw: Fix immediate work request flush to completion queue
+    - RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
+    - RDMA/siw: Set defined status for work completion with undefined status
+    - scsi: scsi_debug: Fix a warning in resp_write_scat()
+    - crypto: ccree - swap SHA384 and SHA512 larval hashes at build time
+    - crypto: ccree - Remove debugfs when platform_driver_register failed
+    - PCI: Check for alloc failure in pci_request_irq()
+    - RDMA/hfi: Decrease PCI device reference count in error path
+    - crypto: ccree - Make cc_debugfs_global_fini() available for module init
+      function
+    - RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create
+      failed
+    - scsi: hpsa: Fix possible memory leak in hpsa_init_one()
+    - crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
+    - scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
+    - scsi: hpsa: Fix error handling in hpsa_add_sas_host()
+    - scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
+    - scsi: fcoe: Fix possible name leak when device_register() fails
+    - scsi: ipr: Fix WARNING in ipr_init()
+    - scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
+    - scsi: snic: Fix possible UAF in snic_tgt_create()
+    - RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
+    - f2fs: avoid victim selection from previous victim section
+    - crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
+    - RDMA/hfi1: Fix error return code in parse_platform_config()
+    - orangefs: Fix sysfs not cleanup when dev init failed
+    - crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
+    - hwrng: amd - Fix PCI device refcount leak
+    - hwrng: geode - Fix PCI device refcount leak
+    - IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
+    - drivers: dio: fix possible memory leak in dio_init()
+    - tty: serial: tegra: Activate RX DMA transfer by request
+    - serial: tegra: Read DMA status before terminating
+    - class: fix possible memory leak in __class_register()
+    - vfio: platform: Do not pass return buffer to ACPI _RST method
+    - uio: uio_dmem_genirq: Fix missing unlock in irq configuration
+    - uio: uio_dmem_genirq: Fix deadlock between irq config and handling
+    - usb: fotg210-udc: Fix ages old endianness issues
+    - staging: vme_user: Fix possible UAF in tsi148_dma_list_add
+    - usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
+    - usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
+    - serial: amba-pl011: avoid SBSA UART accessing DMACR register
+    - serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
+    - serial: pch: Fix PCI device refcount leak in pch_request_dma()
+    - tty: serial: clean up stop-tx part in altera_uart_tx_chars()
+    - tty: serial: altera_uart_{r,t}x_chars() need only uart_port
+    - serial: altera_uart: fix locking in polling mode
+    - serial: sunsab: Fix error handling in sunsab_init()
+    - test_firmware: fix memory leak in test_firmware_init()
+    - misc: ocxl: fix possible name leak in ocxl_file_register_afu()
+    - misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
+    - misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault
+      and gru_handle_user_call_os
+    - cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
+    - cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
+    - counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
+    - usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
+    - usb: gadget: f_hid: optional SETUP/SET_REPORT mode
+    - usb: gadget: f_hid: fix f_hidg lifetime vs cdev
+    - usb: gadget: f_hid: fix refcount leak on error path
+    - drivers: mcb: fix resource leak in mcb_probe()
+    - mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
+    - chardev: fix error handling in cdev_device_add()
+    - i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
+    - staging: rtl8192u: Fix use after free in ieee80211_rx()
+    - staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
+    - vme: Fix error not catched in fake_init()
+    - i2c: ismt: Fix an out-of-bounds bug in ismt_access()
+    - usb: storage: Add check for kcalloc
+    - tracing/hist: Fix issue of losting command info in error_log
+    - samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
+    - fbdev: ssd1307fb: Drop optional dependency
+    - fbdev: pm2fb: fix missing pci_disable_device()
+    - fbdev: via: Fix error in via_core_init()
+    - fbdev: vermilion: decrease reference count in error path
+    - fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
+    - HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
+    - HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
+    - power: supply: fix residue sysfs file in error handle route of
+      __power_supply_register()
+    - perf trace: Return error if a system call doesn't exist
+    - perf trace: Separate 'struct syscall_fmt' definition from syscall_fmts
+      variable
+    - perf trace: Factor out the initialization of syscal_arg_fmt->scnprintf
+    - perf trace: Add the syscall_arg_fmt pointer to syscall_arg
+    - perf trace: Allow associating scnprintf routines with well known arg names
+    - perf trace: Add a strtoul() method to 'struct syscall_arg_fmt'
+    - perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
+    - perf trace: Handle failure when trace point folder is missed
+    - perf symbol: correction while adjusting symbol
+    - HSI: omap_ssi_core: Fix error handling in ssi_init()
+    - power: supply: fix null pointer dereferencing in
+      power_supply_get_battery_info
+    - RDMA/siw: Fix pointer cast warning
+    - include/uapi/linux/swab: Fix potentially missing __always_inline
+    - rtc: snvs: Allow a time difference on clock register read
+    - rtc: pcf85063: Fix reading alarm
+    - iommu/amd: Fix pci device refcount leak in ppr_notifier()
+    - iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
+    - macintosh: fix possible memory leak in macio_add_one_device()
+    - macintosh/macio-adb: check the return value of ioremap()
+    - powerpc/52xx: Fix a resource leak in an error handling path
+    - cxl: Fix refcount leak in cxl_calc_capp_routing
+    - powerpc/xive: add missing iounmap() in error path in
+      xive_spapr_populate_irq_data()
+    - powerpc/perf: callchain validate kernel stack pointer bounds
+    - powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in
+      of_fsl_spi_probe()
+    - powerpc/hv-gpci: Fix hv_gpci event list
+    - selftests/powerpc: Fix resource leaks
+    - pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
+    - remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
+    - remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in
+      adsp_alloc_memory_region()
+    - rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
+    - rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
+    - nfsd: Define the file access mode enum for tracing
+    - NFSD: Add tracepoints to NFSD's duplicate reply cache
+    - nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
+    - mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - nfc: pn533: Clear nfc_target before being used
+    - r6040: Fix kmemleak in probe and remove
+    - rtc: mxc_v2: Add missing clk_disable_unprepare()
+    - openvswitch: Fix flow lookup to use unmasked key
+    - skbuff: Account for tail adjustment during pull operations
+    - mailbox: zynq-ipi: fix error handling while device_register() fails
+    - net_sched: reject TCF_EM_SIMPLE case for complex ematch module
+    - rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
+    - myri10ge: Fix an error handling path in myri10ge_probe()
+    - net: stream: purge sk_error_queue in sk_stream_kill_queues()
+    - rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
+    - binfmt_misc: fix shift-out-of-bounds in check_special_flags
+    - fs: jfs: fix shift-out-of-bounds in dbAllocAG
+    - udf: Avoid double brelse() in udf_rename()
+    - fs: jfs: fix shift-out-of-bounds in dbDiscardAG
+    - ACPICA: Fix error code path in acpi_ds_call_control_method()
+    - nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
+    - acct: fix potential integer overflow in encode_comp_t()
+    - hfs: fix OOB Read in __hfs_brec_find
+    - drm/etnaviv: add missing quirks for GC300
+    - brcmfmac: return error when getting invalid max_flowrings from dongle
+    - wifi: ath9k: verify the expected usb_endpoints are present
+    - wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
+    - ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
+    - ipmi: fix memleak when unload ipmi driver
+    - bpf: make sure skb->len != 0 when redirecting to a tunneling device
+    - net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
+    - hamradio: baycom_epp: Fix return type of baycom_send_packet()
+    - wifi: brcmfmac: Fix potential shift-out-of-bounds in
+      brcmf_fw_alloc_request()
+    - igb: Do not free q_vector unless new one was allocated
+    - s390/ctcm: Fix return type of ctc{mp,}m_tx()
+    - s390/netiucv: Fix return type of netiucv_tx()
+    - s390/lcs: Fix return type of lcs_start_xmit()
+    - drm/rockchip: Use drm_mode_copy()
+    - drm/sti: Use drm_mode_copy()
+    - drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
+    - md/raid1: stop mdx_raid1 thread when raid1 array run failed
+    - net: add atomic_long_t to net_device_stats fields
+    - mrp: introduce active flags to prevent UAF when applicant uninit
+    - ppp: associate skb with a device at tx
+    - bpf: Prevent decl_tag from being referenced in func_proto arg
+    - media: dvb-frontends: fix leak of memory fw
+    - media: dvbdev: adopts refcnt to avoid UAF
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
+    - blk-mq: fix possible memleak when register 'hctx' failed
+    - regulator: core: fix use_count leakage when handling boot-on
+    - mmc: f-sdh30: Add quirks for broken timeout clock capability
+    - media: si470x: Fix use-after-free in si470x_int_in_callback()
+    - clk: st: Fix memory leak in st_of_quadfs_setup()
+    - hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
+    - drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
+    - drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
+    - orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
+    - orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
+    - ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
+    - ALSA: hda: add snd_hdac_stop_streams() helper
+    - ASoC: Intel: Skylake: Fix driver hang during shutdown
+    - ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in
+      mt8173_rt5650_rt5514_dev_probe()
+    - ASoC: audio-graph-card: fix refcount leak of cpu_ep in
+      __graph_for_each_link()
+    - ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in
+      rockchip_pdm_runtime_resume()
+    - ASoC: wm8994: Fix potential deadlock
+    - ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in
+      rk_spdif_runtime_resume()
+    - ASoC: rt5670: Remove unbalanced pm_runtime_put()
+    - pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
+    - pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
+    - ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
+    - ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
+    - usb: dwc3: core: defer probe on ulpi_read_id timeout
+    - HID: wacom: Ensure bootloader PID is usable in hidraw mode
+    - reiserfs: Add missing calls to reiserfs_security_free()
+    - iio: adc: ad_sigma_delta: do not use internal iio_dev lock
+    - iio: adc128s052: add proper .data members in adc128_of_match table
+    - regulator: core: fix deadlock on regulator enable
+    - gcov: add support for checksum field
+    - media: dvbdev: fix build warning due to comments
+    - media: dvbdev: fix refcnt bug
+    - cifs: fix oops during encryption
+    - nvme-pci: fix doorbell buffer value endianness
+    - ata: ahci: Fix PCS quirk application for suspend
+    - nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
+    - objtool: Fix SEGFAULT
+    - powerpc/rtas: avoid device tree lookups in rtas_os_term()
+    - powerpc/rtas: avoid scheduling in rtas_os_term()
+    - HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
+    - HID: plantronics: Additional PIDs for double volume key presses quirk
+    - hfsplus: fix bug causing custom uid and gid being unable to be assigned with
+      mount
+    - ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
+    - ALSA: line6: correct midi status byte when receiving data from podxt
+    - ALSA: line6: fix stack overflow in line6_midi_transmit
+    - pnode: terminate at peers of source
+    - md: fix a crash in mempool_free
+    - mm, compaction: fix fast_isolate_around() to stay within boundaries
+    - f2fs: should put a page when checking the summary info
+    - mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
+    - tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
+    - tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
+    - SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
+    - net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
+    - net/af_packet: make sure to pull mac header
+    - media: stv0288: use explicitly signed char
+    - soc: qcom: Select REMAP_MMIO for LLCC driver
+    - kest.pl: Fix grub2 menu handling for rebooting
+    - ktest.pl minconfig: Unset configs instead of just removing them
+    - mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
+    - btrfs: fix resolving backrefs for inline extent followed by prealloc
+    - ARM: ux500: do not directly dereference __iomem
+    - arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
+    - selftests: Use optional USERCFLAGS and USERLDFLAGS
+    - cpufreq: Init completion before kobject_init_and_add()
+    - binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf
+    - binfmt: Fix error return code in load_elf_fdpic_binary()
+    - dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
+    - dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
+    - dm thin: Use last transaction's pmd->root when commit failed
+    - dm thin: Fix UAF in run_timer_softirq()
+    - dm integrity: Fix UAF in dm_integrity_dtr()
+    - dm clone: Fix UAF in clone_dtr()
+    - dm cache: Fix UAF in destroy()
+    - dm cache: set needs_check flag after aborting metadata
+    - tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
+    - x86/microcode/intel: Do not retry microcode reloading on the APs
+    - tracing/hist: Fix wrong return value in parse_action_params()
+    - tracing: Fix infinite loop in tracing_read_pipe on overflowed
+      print_trace_line
+    - ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
+    - media: dvb-core: Fix double free in dvb_register_device()
+    - cifs: fix confusing debug message
+    - cifs: fix missing display of three mount options
+    - md/bitmap: Fix bitmap chunk size overflow issues
+    - efi: Add iMac Pro 2017 to uefi skip cert quirk
+    - ipmi: fix long wait in unload when IPMI disconnect
+    - mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
+    - ima: Fix a potential NULL pointer access in ima_restore_measurement_list
+    - ipmi: fix use after free in _ipmi_destroy_user()
+    - PCI: Fix pci_device_is_present() for VFs by checking PF
+    - PCI/sysfs: Fix double free in error path
+    - crypto: n2 - add missing hash statesize
+    - iommu/amd: Fix ivrs_acpihid cmdline parsing code
+    - parisc: led: Fix potential null-ptr-deref in start_task()
+    - device_cgroup: Roll back to original exceptions after copy failure
+    - drm/connector: send hotplug uevent on connector cleanup
+    - drm/vmwgfx: Validate the box size for the snooped cursor
+    - ext4: add inode table check in __ext4_get_inode_loc to aovid possible
+      infinite loop
+    - ext4: fix undefined behavior in bit shift for ext4_check_flag_values
+    - ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
+    - ext4: add helper to check quota inums
+    - ext4: fix reserved cluster accounting in __es_remove_extent()
+    - ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
+    - ext4: init quota for 'old.inode' in 'ext4_rename'
+    - ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
+    - ext4: fix corruption when online resizing a 1K bigalloc fs
+    - ext4: fix error code return to user-space in ext4_get_branch()
+    - ext4: avoid BUG_ON when creating xattrs
+    - ext4: fix inode leak in ext4_xattr_inode_create() on an error path
+    - ext4: initialize quota before expanding inode in setproject ioctl
+    - ext4: avoid unaccounted block allocation when expanding inode
+    - ext4: allocate extended attribute value in vmalloc area
+    - btrfs: replace strncpy() with strscpy()
+    - PM/devfreq: governor: Add a private governor_data for governor
+    - media: s5p-mfc: Fix to handle reference queue during finishing
+    - media: s5p-mfc: Clear workbit to handle error condition
+    - media: s5p-mfc: Fix in register read and write for H264
+    - dm thin: resume even if in FAIL mode
+    - perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
+    - perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged
+      data
+    - KVM: x86: optimize more exit handlers in vmx.c
+    - KVM: retpolines: x86: eliminate retpoline from vmx.c exit handlers
+    - KVM: VMX: Rename INTERRUPT_PENDING to INTERRUPT_WINDOW
+    - KVM: VMX: Rename NMI_PENDING to NMI_WINDOW
+    - KVM: VMX: Fix the spelling of CPU_BASED_USE_TSC_OFFSETTING
+    - KVM: nVMX: Properly expose ENABLE_USR_WAIT_PAUSE control to L1
+    - ravb: Fix "failed to switch device to config mode" message during unbind
+    - ext4: goto right label 'failed_mount3a'
+    - ext4: correct inconsistent error msg in nojournal mode
+    - mm/highmem: Lift memcpy_[to|from]_page to core
+    - ext4: use memcpy_to_page() in pagecache_write()
+    - fs: ext4: initialize fsdata in pagecache_write()
+    - ext4: use kmemdup() to replace kmalloc + memcpy
+    - mbcache: don't reclaim used entries
+    - mbcache: add functions to delete entry if unused
+    - ext4: remove EA inode entry from mbcache on inode eviction
+    - ext4: unindent codeblock in ext4_xattr_block_set()
+    - ext4: fix race when reusing xattr blocks
+    - mbcache: automatically delete entries from cache on freeing
+    - ext4: fix deadlock due to mbcache entry corruption
+    - SUNRPC: ensure the matching upcall is in-flight upon downcall
+    - bpf: pull before calling skb_postpull_rcsum()
+    - nfsd: shut down the NFSv4 state objects before the filecache
+    - net: hns3: add interrupts re-initialization while doing VF FLR
+    - net: sched: fix memory leak in tcindex_set_parms
+    - qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
+    - nfc: Fix potential resource leaks
+    - vhost: fix range used in translate_desc()
+    - net: amd-xgbe: add missed tasklet_kill
+    - net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
+    - RDMA/uverbs: Silence shiftTooManyBitsSigned warning
+    - RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
+    - net: sched: atm: dont intepret cls results when asked to drop
+    - net: sched: cbq: dont intepret cls results when asked to drop
+    - perf tools: Fix resources leak in perf_data__open_dir()
+    - drivers/net/bonding/bond_3ad: return when there's no aggregator
+    - usb: rndis_host: Secure rndis_query check against int overflow
+    - drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
+    - caif: fix memory leak in cfctrl_linkup_request()
+    - udf: Fix extension of the last extent in the file
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
+    - x86/bugs: Flush IBP in ib_prctl_set()
+    - nfsd: fix handling of readdir in v4root vs. mount upcall timeout
+    - riscv: uaccess: fix type of 0 variable on error in get_user()
+    - ext4: don't allow journal inode to have encrypt flag
+    - hfs/hfsplus: use WARN_ON for sanity check
+    - hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
+    - mbcache: Avoid nesting of cache->c_list_lock under bit locks
+    - parisc: Align parisc MADV_XXX constants with all other architectures
+    - selftests: Fix kselftest O=objdir build from cluttering top level objdir
+    - selftests: set the BUILD variable to absolute path
+    - driver core: Fix bus_type.match() error handling in __driver_attach()
+    - net: sched: disallow noqueue for qdisc classes
+    - KVM: arm64: Fix S1PTW handling on RO memslots
+    - efi: tpm: Avoid READ_ONCE() for accessing the event log
+    - docs: Fix the docs build with Sphinx 6.0
+    - perf auxtrace: Fix address filter duplicate symbol selection
+    - s390/kexec: fix ipl report address for kdump
+    - s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple()
+    - net/ulp: prevent ULP without clone op from entering the LISTEN status
+    - ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
+    - cifs: Fix uninitialized memory read for smb311 posix symlink create
+    - drm/msm/adreno: Make adreno quirks not overwrite each other
+    - platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during
+      probe
+    - ixgbe: fix pci device refcount leak
+    - ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
+    - wifi: wilc1000: sdio: fix module autoloading
+    - usb: ulpi: defer ulpi_register on ulpi_read_id timeout
+    - jbd2: use the correct print format
+    - quota: Factor out setup of quota inode
+    - ext4: fix bug_on in __es_tree_search caused by bad quota inode
+    - ext4: lost matching-pair of trace in ext4_truncate
+    - ext4: fix use-after-free in ext4_orphan_cleanup
+    - ext4: fix uninititialized value in 'ext4_evict_inode'
+    - netfilter: ipset: Fix overflow before widen in the bitmap_ip_create()
+      function.
+    - powerpc/imc-pmu: Fix use of mutex in IRQs disabled section
+    - x86/boot: Avoid using Intel mnemonics in AT&T syntax asm
+    - EDAC/device: Fix period calculation in edac_device_reset_delay_period()
+    - regulator: da9211: Use irq handler when ready
+    - tipc: improve throughput between nodes in netns
+    - tipc: eliminate checking netns if node established
+    - tipc: fix unexpected link reset due to discovery messages
+    - hvc/xen: lock console list traversal
+    - nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
+    - net/sched: act_mpls: Fix warning during failed attribute validation
+    - net/mlx5: Rename ptp clock info
+    - net/mlx5: Fix ptp max frequency adjustment range
+    - iommu/mediatek-v1: Add error handle for mtk_iommu_probe
+    - iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
+    - x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent
+      unnecessary IPI
+    - x86/resctrl: Fix task CLOSID/RMID update race
+    - drm/virtio: Fix GEM handle creation UAF
+    - arm64: atomics: format whitespace consistently
+    - arm64: atomics: remove LL/SC trampolines
+    - arm64: cmpxchg_double*: hazard against entire exchange variable
+    - efi: fix NULL-deref in init error path
+    - mm: Always release pages to the buddy allocator in memblock_free_late().
+    - Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout"
+    - tipc: fix use-after-free in tipc_disc_rcv()
+    - tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
+    - tipc: Add a missing case of TIPC_DIRECT_MSG type
+    - ocfs2: fix freeing uninitialized resource on ocfs2_dlm_shutdown
+    - tipc: call tipc_lxc_xmit without holding node_read_lock
+    - Linux 5.4.229
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2023-0266 was assigned for this issue.
+    - ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2022-41218 is assigned to those bugs above.
+    - media: dvb-core: Fix UAF due to refcount races at releasing
+  * Focal update: v5.4.228 upstream stable release (LP: #2003904)
+    - x86/smpboot: Move rcu_cpu_starting() earlier
+    - mm/hugetlb: fix races when looking up a CONT-PTE/PMD size hugetlb page
+    - block: unhash blkdev part inode when the part is deleted
+    - ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx()
+    - pinctrl: meditatek: Startup with the IRQs disabled
+    - can: sja1000: fix size of OCR_MODE_MASK define
+    - can: mcba_usb: Fix termination command argument
+    - ASoC: ops: Correct bounds check for second channel on SX controls
+    - Linux 5.4.228
+  * Focal update: v5.4.227 upstream stable release (LP: #2003901)
+    - arm64: dts: rockchip: keep I2S1 disabled for GPIO function on ROCK Pi 4
+      series
+    - arm: dts: rockchip: fix node name for hym8563 rtc
+    - ARM: dts: rockchip: fix ir-receiver node names
+    - ARM: dts: rockchip: rk3188: fix lcdc1-rgb24 node name
+    - ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels
+    - ARM: 9266/1: mm: fix no-MMU ZERO_PAGE() implementation
+    - ARM: dts: rockchip: disable arm_global_timer on rk3066 and rk3188
+    - 9p/fd: Use P9_HDRSZ for header size
+    - regulator: slg51000: Wait after asserting CS pin
+    - ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
+    - btrfs: send: avoid unaligned encoded writes when attempting to clone range
+    - ASoC: soc-pcm: Add NULL check in BE reparenting
+    - regulator: twl6030: fix get status of twl6032 regulators
+    - fbcon: Use kzalloc() in fbcon_prepare_logo()
+    - 9p/xen: check logical size for buffer size
+    - net: usb: qmi_wwan: add u-blox 0x1342 composition
+    - mm/khugepaged: take the right locks for page table retraction
+    - mm/khugepaged: fix GUP-fast interaction by sending IPI
+    - mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths
+    - xen/netback: do some code cleanup
+    - xen/netback: don't call kfree_skb() with interrupts disabled
+    - Revert "net: dsa: b53: Fix valid setting for MDB entries"
+    - media: v4l2-dv-timings.c: fix too strict blanking sanity checks
+    - memcg: fix possible use-after-free in memcg_write_event_control()
+    - mm/gup: fix gup_pud_range() for dax
+    - KVM: s390: vsie: Fix the initialization of the epoch extension (epdx) field
+    - drm/shmem-helper: Remove errant put in error path
+    - HID: usbhid: Add ALWAYS_POLL quirk for some mice
+    - HID: hid-lg4ff: Add check for empty lbuf
+    - HID: core: fix shift-out-of-bounds in hid_report_raw_event
+    - can: af_can: fix NULL pointer dereference in can_rcv_filter
+    - ieee802154: cc2520: Fix error return code in cc2520_hw_init()
+    - ca8210: Fix crash by zero initializing data
+    - drm/bridge: ti-sn65dsi86: Fix output polarity setting bug
+    - gpio: amd8111: Fix PCI device reference count leak
+    - e1000e: Fix TX dispatch condition
+    - igb: Allocate MSI-X vector when testing
+    - af_unix: Get user_ns from in_skb in unix_diag_get_exact().
+    - Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn()
+    - Bluetooth: Fix not cleanup led when bt_init fails
+    - net: dsa: ksz: Check return value
+    - selftests: rtnetlink: correct xfrm policy rule in kci_test_ipsec_offload
+    - mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add()
+    - net: encx24j600: Add parentheses to fix precedence
+    - net: encx24j600: Fix invalid logic in reading of MISTAT register
+    - xen-netfront: Fix NULL sring after live migration
+    - net: mvneta: Prevent out of bounds read in mvneta_config_rss()
+    - i40e: Fix not setting default xps_cpus after reset
+    - i40e: Fix for VF MAC address 0
+    - i40e: Disallow ip4 and ip6 l4_4_bytes
+    - NFC: nci: Bounds check struct nfc_target arrays
+    - nvme initialize core quirks before calling nvme_init_subsystem
+    - net: stmmac: fix "snps,axi-config" node property parsing
+    - net: thunderx: Fix missing destroy_workqueue of nicvf_rx_mode_wq
+    - net: hisilicon: Fix potential use-after-free in hisi_femac_rx()
+    - net: hisilicon: Fix potential use-after-free in hix5hd2_rx()
+    - tipc: Fix potential OOB in tipc_link_proto_rcv()
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - ipv4: Fix incorrect route flushing when table ID 0 is used
+    - ethernet: aeroflex: fix potential skb leak in greth_init_rings()
+    - net: plip: don't call kfree_skb/dev_kfree_skb() under spin_lock_irq()
+    - ipv6: avoid use-after-free in ip6_fragment()
+    - net: mvneta: Fix an out of bounds check
+    - can: esd_usb: Allow REC and TEC to return to zero
+    - Linux 5.4.227
+  * 5.15.0-58.64 breaks xen bridge networking (pvh domU) (LP: #2002889) // Focal
+    update: v5.4.227 upstream stable release (LP: #2003901)
+    - xen/netback: fix build warning
+  * Focal update: v5.4.226 upstream stable release (LP: #2003896)
+    - wifi: mac80211: fix memory free error when registering wiphy fail
+    - wifi: mac80211_hwsim: fix debugfs attribute ps with rc table support
+    - audit: fix undefined behavior in bit shift for AUDIT_BIT
+    - wifi: mac80211: Fix ack frame idr leak when mesh has no route
+    - spi: stm32: fix stm32_spi_prepare_mbr() that halves spi clk for every run
+    - drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
+    - block, bfq: fix null pointer dereference in bfq_bio_bfqg()
+    - arm64/syscall: Include asm/ptrace.h in syscall_wrapper header.
+    - RISC-V: vdso: Do not add missing symbols to version section in linker script
+    - MIPS: pic32: treat port as signed integer
+    - af_key: Fix send_acquire race with pfkey_register
+    - ARM: dts: am335x-pcm-953: Define fixed regulators in root node
+    - ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove
+    - regulator: core: fix kobject release warning and memory leak in
+      regulator_register()
+    - regulator: core: fix UAF in destroy_regulator()
+    - bus: sunxi-rsb: Support atomic transfers
+    - tee: optee: fix possible memory leak in optee_register_device()
+    - ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl
+    - net: liquidio: simplify if expression
+    - nfc/nci: fix race with opening and closing
+    - net: pch_gbe: fix potential memleak in pch_gbe_tx_queue()
+    - 9p/fd: fix issue of list_del corruption in p9_fd_cancel()
+    - ARM: mxs: fix memory leak in mxs_machine_init()
+    - net/mlx4: Check retval of mlx4_bitmap_init
+    - net/qla3xxx: fix potential memleak in ql3xxx_send()
+    - net: pch_gbe: fix pci device refcount leak while module exiting
+    - nfp: add port from netdev validation for EEPROM access
+    - Drivers: hv: vmbus: fix double free in the error path of
+      vmbus_add_channel_work()
+    - Drivers: hv: vmbus: fix possible memory leak in vmbus_device_register()
+    - net/mlx5: Fix FW tracer timestamp calculation
+    - tipc: set con sock in tipc_conn_alloc
+    - tipc: add an extra conn_get in tipc_conn_alloc
+    - tipc: check skb_linearize() return value in tipc_disc_rcv()
+    - xfrm: Fix ignored return value in xfrm6_init()
+    - NFC: nci: fix memory leak in nci_rx_data_packet()
+    - regulator: twl6030: re-add TWL6032_SUBCLASS
+    - bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending()
+    - dccp/tcp: Reset saddr on failure after inet6?_hash_connect().
+    - s390/dasd: fix no record found for raw_track_access
+    - nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st-nci: fix memory leaks in EVT_TRANSACTION
+    - net: thunderx: Fix the ACPI memory leak
+    - s390/crashdump: fix TOD programmable field size
+    - lib/vdso: use "grep -E" instead of "egrep"
+    - usb: dwc3: exynos: Fix remove() function
+    - arm64: dts: rockchip: lower rk3399-puma-haikou SD controller clock frequency
+    - iio: light: apds9960: fix wrong register for gesture gain
+    - iio: core: Fix entry not deleted when iio_register_sw_trigger_type() fails
+    - init/Kconfig: fix CC_HAS_ASM_GOTO_TIED_OUTPUT test with dash
+    - nios2: add FORCE for vmlinuz.gz
+    - iio: ms5611: Simplify IO callback parameters
+    - iio: pressure: ms5611: fixed value compensation bug
+    - ceph: do not update snapshot context when there is no new snapshot
+    - ceph: avoid putting the realm twice when decoding snaps fails
+    - firmware: google: Release devices before unregistering the bus
+    - firmware: coreboot: Register bus in module init
+    - nilfs2: fix nilfs_sufile_mark_dirty() not set segment usage as dirty
+    - gcov: clang: fix the buffer overflow issue
+    - Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode
+    - ASoC: Intel: bytcht_es8316: Add quirk for the Nanote UMPC-01
+    - serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
+    - xen/platform-pci: add missing free_irq() in error path
+    - platform/x86: asus-wmi: add missing pci_dev_put() in asus_wmi_set_xusb2pr()
+    - platform/x86: acer-wmi: Enable SW_TABLET_MODE on Switch V 10 (SW5-017)
+    - platform/x86: hp-wmi: Ignore Smart Experience App event
+    - [Config] updateconfigs for INET_TABLE_PERTURB_ORDER
+    - tcp: configurable source port perturb table size
+    - net: usb: qmi_wwan: add Telit 0x103a composition
+    - dm integrity: flush the journal on suspend
+    - binder: avoid potential data leakage when copying txn
+    - binder: read pre-translated fds from sender buffer
+    - binder: defer copies of pre-patched txn data
+    - binder: fix pointer cast warning
+    - binder: Address corner cases in deferred copy and fixup
+    - binder: Gracefully handle BINDER_TYPE_FDA objects with num_fds=0
+    - btrfs: free btrfs_path before copying root refs to userspace
+    - btrfs: free btrfs_path before copying fspath to userspace
+    - btrfs: free btrfs_path before copying subvol info to userspace
+    - btrfs: sysfs: normalize the error handling branch in btrfs_init_sysfs()
+    - drm/amd/dc/dce120: Fix audio register mapping, stop triggering KASAN
+    - drm/amdgpu: always register an MMU notifier for userptr
+    - fuse: lock inode unconditionally in fuse_fallocate()
+    - btrfs: free btrfs_path before copying inodes to userspace
+    - spi: spi-imx: Fix spi_bus_clk if requested clock is higher than input clock
+    - btrfs: move QUOTA_ENABLED check to rescan_should_stop from
+      btrfs_qgroup_rescan_worker
+    - drm/amdgpu: update drm_display_info correctly when the edid is read
+    - drm/amdgpu: Partially revert "drm/amdgpu: update drm_display_info correctly
+      when the edid is read"
+    - btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit()
+    - iio: health: afe4403: Fix oob read in afe4403_read_raw
+    - iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
+    - iio: light: rpr0521: add missing Kconfig dependencies
+    - scripts/faddr2line: Fix regression in name resolution on ppc64le
+    - hwmon: (i5500_temp) fix missing pci_disable_device()
+    - hwmon: (ibmpex) Fix possible UAF when ibmpex_register_bmc() fails
+    - of: property: decrement node refcount in of_fwnode_get_reference_args()
+    - net/mlx5: Fix uninitialized variable bug in outlen_write()
+    - net/mlx5e: Fix use-after-free when reverting termination table
+    - can: sja1000_isa: sja1000_isa_probe(): add missing free_sja1000dev()
+    - can: cc770: cc770_isa_probe(): add missing free_cc770dev()
+    - qlcnic: fix sleep-in-atomic-context bugs caused by msleep
+    - wifi: cfg80211: fix buffer overflow in elem comparison
+    - net: phy: fix null-ptr-deref while probe() failed
+    - net: net_netdev: Fix error handling in ntb_netdev_init_module()
+    - net/9p: Fix a potential socket leak in p9_socket_open
+    - net: ethernet: nixge: fix NULL dereference
+    - dsa: lan9303: Correct stat name
+    - net: hsr: Fix potential use-after-free
+    - afs: Fix fileserver probe RTT handling
+    - net: tun: Fix use-after-free in tun_detach()
+    - packet: do not set TP_STATUS_CSUM_VALID on CHECKSUM_COMPLETE
+    - sctp: fix memory leak in sctp_stream_outq_migrate()
+    - net: ethernet: renesas: ravb: Fix promiscuous mode after system resumed
+    - hwmon: (coretemp) Check for null before removing sysfs attrs
+    - hwmon: (coretemp) fix pci device refcount leak in nv1a_ram_new()
+    - net/mlx5: DR, Fix uninitialized var warning
+    - error-injection: Add prompt for function error injection
+    - tools/vm/slabinfo-gnuplot: use "grep -E" instead of "egrep"
+    - nilfs2: fix NULL pointer dereference in nilfs_palloc_commit_free_entry()
+    - x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
+    - pinctrl: intel: Save and restore pins in "direct IRQ" mode
+    - mmc: mmc_test: Fix removal of debugfs file
+    - mmc: core: Fix ambiguous TRIM and DISCARD arg
+    - mmc: sdhci-esdhc-imx: correct CQHCI exit halt state check
+    - mmc: sdhci-sprd: Fix no reset data and command after voltage switch
+    - tracing: Free buffers when a used dynamic event is removed
+    - arm64: Fix panic() when Spectre-v2 causes Spectre-BHB to re-allocate KVM
+      vectors
+    - arm64: errata: Fix KVM Spectre-v2 mitigation selection for Cortex-A57/A72
+    - mm: Fix '.data.once' orphan section warning
+    - ASoC: ops: Fix bounds check for _sx controls
+    - pinctrl: single: Fix potential division by zero
+    - iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init()
+    - parisc: Increase size of gcc stack frame check
+    - xtensa: increase size of gcc stack frame check
+    - parisc: Increase FRAME_WARN to 2048 bytes on parisc
+    - Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is
+      enabled
+    - selftests: net: add delete nexthop route warning test
+    - selftests: net: fix nexthop warning cleanup double ip typo
+    - ipv4: Handle attempt to delete multipath route when fib_info contains an nh
+      reference
+    - ipv4: Fix route deletion when nexthop info is not specified
+    - tracing/ring-buffer: Have polling block on watermark
+    - nvme: restrict management ioctls to admin
+    - nvme: ensure subsystem reset is single threaded
+    - x86/tsx: Add a feature bit for TSX control MSR support
+    - x86/pm: Add enumeration check before spec MSRs save/restore setup
+    - x86/ioremap: Fix page aligned size calculation in __ioremap_caller()
+    - Revert "clocksource/drivers/riscv: Events are stopped during CPU suspend"
+    - char: tpm: Protect tpm_pm_suspend with locks
+    - mmc: sdhci: use FIELD_GET for preset value bit masks
+    - mmc: sdhci: Fix voltage switch delay
+    - proc: avoid integer type confusion in get_proc_long
+    - proc: proc_skip_spaces() shouldn't think it is working on C strings
+    - v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails
+    - ipc/sem: Fix dangling sem_array access in semtimedop race
+    - Linux 5.4.226
+  * CVE-2022-4139
+    - drm/i915: fix TLB invalidation for Gen12 video and compute engines
+  * Focal update: v5.4.225 upstream stable release (LP: #2002347)
+    - xfs: preserve rmapbt swapext block reservation from freed blocks
+    - xfs: rename xfs_bmap_is_real_extent to is_written_extent
+    - xfs: redesign the reflink remap loop to fix blkres depletion crash
+    - xfs: use MMAPLOCK around filemap_map_pages()
+    - xfs: preserve inode versioning across remounts
+    - xfs: drain the buf delwri queue before xfsaild idles
+    - phy: stm32: fix an error code in probe
+    - wifi: cfg80211: silence a sparse RCU warning
+    - wifi: cfg80211: fix memory leak in query_regdb_file()
+    - bpf, sockmap: Fix the sk->sk_forward_alloc warning of sk_stream_kill_queues
+    - HID: hyperv: fix possible memory leak in mousevsc_probe()
+    - net: gso: fix panic on frag_list with mixed head alloc types
+    - net: tun: Fix memory leaks of napi_get_frags
+    - bnxt_en: Fix possible crash in bnxt_hwrm_set_coal()
+    - bnxt_en: fix potentially incorrect return value for ndo_rx_flow_steer
+    - net: fman: Unregister ethernet device on removal
+    - capabilities: fix undefined behavior in bit shift for CAP_TO_MASK
+    - net: lapbether: fix issue of dev reference count leakage in
+      lapbeth_device_event()
+    - hamradio: fix issue of dev reference count leakage in bpq_device_event()
+    - drm/vc4: Fix missing platform_unregister_drivers() call in
+      vc4_drm_register()
+    - ipv6: addrlabel: fix infoleak when sending struct ifaddrlblmsg to network
+    - can: af_can: fix NULL pointer dereference in can_rx_register()
+    - tipc: fix the msg->req tlv len check in
+      tipc_nl_compat_name_table_dump_header
+    - dmaengine: pxa_dma: use platform_get_irq_optional
+    - dmaengine: mv_xor_v2: Fix a resource leak in mv_xor_v2_remove()
+    - drivers: net: xgene: disable napi when register irq failed in
+      xgene_enet_open()
+    - perf stat: Fix printing os->prefix in CSV metrics output
+    - net: nixge: disable napi when enable interrupts failed in nixge_open()
+    - net/mlx5: Allow async trigger completion execution on single CPU systems
+    - net: cpsw: disable napi in cpsw_ndo_open()
+    - net: cxgb3_main: disable napi when bind qsets failed in cxgb_up()
+    - cxgb4vf: shut down the adapter when t4vf_update_port_info() failed in
+      cxgb4vf_open()
+    - ethernet: s2io: disable napi when start nic failed in s2io_card_up()
+    - net: mv643xx_eth: disable napi when init rxq or txq failed in
+      mv643xx_eth_open()
+    - ethernet: tundra: free irq when alloc ring failed in tsi108_open()
+    - net: macvlan: fix memory leaks of macvlan_common_newlink
+    - riscv: process: fix kernel info leakage
+    - arm64: efi: Fix handling of misaligned runtime regions and drop warning
+    - MIPS: jump_label: Fix compat branch range check
+    - mmc: cqhci: Provide helper for resetting both SDHCI and CQHCI
+    - mmc: sdhci-of-arasan: Fix SDHCI_RESET_ALL for CQHCI
+    - mmc: sdhci-tegra: Fix SDHCI_RESET_ALL for CQHCI
+    - ALSA: hda/ca0132: add quirk for EVGA Z390 DARK
+    - ALSA: hda: fix potential memleak in 'add_widget_node'
+    - ALSA: usb-audio: Add quirk entry for M-Audio Micro
+    - ALSA: usb-audio: Add DSD support for Accuphase DAC-60
+    - vmlinux.lds.h: Fix placement of '.data..decrypted' section
+    - nilfs2: fix deadlock in nilfs_count_free_blocks()
+    - nilfs2: fix use-after-free bug of ns_writer on remount
+    - drm/i915/dmabuf: fix sg_table handling in map_dma_buf
+    - btrfs: selftests: fix wrong error check in btrfs_free_dummy_root()
+    - udf: Fix a slab-out-of-bounds write bug in udf_find_entry()
+    - can: j1939: j1939_send_one(): fix missing CAN header initialization
+    - cert host tools: Stop complaining about deprecated OpenSSL functions
+    - dmaengine: at_hdmac: Fix at_lli struct definition
+    - dmaengine: at_hdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
+    - dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
+    - dmaengine: at_hdmac: Fix impossible condition
+    - dmaengine: at_hdmac: Check return code of dma_async_device_register
+    - net: tun: call napi_schedule_prep() to ensure we own a napi
+    - x86/cpu: Restore AMD's DE_CFG MSR after resume
+    - ASoC: wm5102: Revert "ASoC: wm5102: Fix PM disable depth imbalance in
+      wm5102_probe"
+    - ASoC: wm5110: Revert "ASoC: wm5110: Fix PM disable depth imbalance in
+      wm5110_probe"
+    - ASoC: wm8997: Revert "ASoC: wm8997: Fix PM disable depth imbalance in
+      wm8997_probe"
+    - ASoC: wm8962: Add an event handler for TEMP_HP and TEMP_SPK
+    - spi: intel: Fix the offset to get the 64K erase opcode
+    - ASoC: codecs: jz4725b: add missed Line In power control bit
+    - ASoC: codecs: jz4725b: fix reported volume for Master ctl
+    - ASoC: codecs: jz4725b: use right control for Capture Volume
+    - ASoC: codecs: jz4725b: fix capture selector naming
+    - selftests/futex: fix build for clang
+    - selftests/intel_pstate: fix build for ARCH=x86_64
+    - NFSv4: Retry LOCK on OLD_STATEID during delegation return
+    - i2c: i801: add lis3lv02d's I2C address for Vostro 5568
+    - drm/imx: imx-tve: Fix return type of imx_tve_connector_mode_valid
+    - btrfs: remove pointless and double ulist frees in error paths of qgroup
+      tests
+    - ASoC: codecs: jz4725b: Fix spelling mistake "Sourc" -> "Source", "Routee" ->
+      "Route"
+    - spi: stm32: Print summary 'callbacks suppressed' message
+    - ASoC: core: Fix use-after-free in snd_soc_exit()
+    - serial: 8250_omap: remove wait loop from Errata i202 workaround
+    - serial: 8250: omap: Fix unpaired pm_runtime_put_sync() in omap8250_remove()
+    - serial: 8250: omap: Flush PM QOS work on remove
+    - serial: imx: Add missing .thaw_noirq hook
+    - tty: n_gsm: fix sleep-in-atomic-context bug in gsm_control_send
+    - ASoC: soc-utils: Remove __exit for snd_soc_util_exit()
+    - block: sed-opal: kmalloc the cmd/resp buffers
+    - siox: fix possible memory leak in siox_device_add()
+    - parport_pc: Avoid FIFO port location truncation
+    - pinctrl: devicetree: fix null pointer dereferencing in pinctrl_dt_to_map
+    - arm64: dts: imx8mm: Fix NAND controller size-cells
+    - arm64: dts: imx8mn: Fix NAND controller size-cells
+    - ata: libata-transport: fix double ata_host_put() in ata_tport_add()
+    - net: bgmac: Drop free_netdev() from bgmac_enet_remove()
+    - mISDN: fix possible memory leak in mISDN_dsp_element_register()
+    - net: liquidio: release resources when liquidio driver open failed
+    - mISDN: fix misuse of put_device() in mISDN_register_device()
+    - net: macvlan: Use built-in RCU list checking
+    - net: caif: fix double disconnect client in chnl_net_open()
+    - bnxt_en: Remove debugfs when pci_register_driver failed
+    - xen/pcpu: fix possible memory leak in register_pcpu()
+    - drbd: use after free in drbd_create_device()
+    - platform/x86/intel: pmc: Don't unconditionally attach Intel PMC when
+      virtualized
+    - net/x25: Fix skb leak in x25_lapb_receive_frame()
+    - cifs: Fix wrong return value checking when GETFLAGS
+    - net: thunderbolt: Fix error handling in tbnet_init()
+    - cifs: add check for returning value of SMB2_set_info_init
+    - ftrace: Fix the possible incorrect kernel message
+    - ftrace: Optimize the allocation for mcount entries
+    - ftrace: Fix null pointer dereference in ftrace_add_mod()
+    - ring_buffer: Do not deactivate non-existant pages
+    - ALSA: usb-audio: Drop snd_BUG_ON() from snd_usbmidi_output_open()
+    - Revert "usb: dwc3: disable USB core PHY management"
+    - slimbus: stream: correct presence rate frequencies
+    - speakup: fix a segfault caused by switching consoles
+    - USB: serial: option: add Sierra Wireless EM9191
+    - USB: serial: option: remove old LARA-R6 PID
+    - USB: serial: option: add u-blox LARA-R6 00B modem
+    - USB: serial: option: add u-blox LARA-L6 modem
+    - USB: serial: option: add Fibocom FM160 0x0111 composition
+    - usb: add NO_LPM quirk for Realforce 87U Keyboard
+    - usb: chipidea: fix deadlock in ci_otg_del_timer
+    - iio: adc: at91_adc: fix possible memory leak in at91_adc_allocate_trigger()
+    - iio: trigger: sysfs: fix possible memory leak in iio_sysfs_trig_init()
+    - iio: pressure: ms5611: changed hardcoded SPI speed to value limited
+    - dm ioctl: fix misbehavior if list_versions races with module loading
+    - serial: 8250: Fall back to non-DMA Rx if IIR_RDI occurs
+    - serial: 8250_lpss: Configure DMA also w/o DMA filter
+    - Input: iforce - invert valid length check when fetching device IDs
+    - scsi: zfcp: Fix double free of FSF request when qdio send fails
+    - mmc: core: properly select voltage range without power cycle
+    - mmc: sdhci-pci-o2micro: fix card detect fail issue caused by CD# debounce
+      timeout
+    - mmc: sdhci-pci: Fix possible memory leak caused by missing pci_dev_put()
+    - docs: update mediator contact information in CoC doc
+    - misc/vmw_vmci: fix an infoleak in vmci_host_do_receive_datagram()
+    - serial: 8250: Flush DMA Rx on RLSI
+    - ring-buffer: Include dropped pages in counting dirty patches
+    - scsi: target: tcm_loop: Fix possible name leak in tcm_loop_setup_hba_bus()
+    - kprobes: Skip clearing aggrprobe's post_handler in kprobe-on-ftrace case
+    - Input: i8042 - fix leaking of platform device on module removal
+    - macvlan: enforce a consistent minimal mtu
+    - tcp: cdg: allow tcp_cdg_release() to be called multiple times
+    - kcm: avoid potential race in kcm_tx_work
+    - bpf, test_run: Fix alignment problem in bpf_prog_test_run_skb()
+    - kcm: close race conditions on sk_receive_queue
+    - 9p: trans_fd/p9_conn_cancel: drop client lock earlier
+    - gfs2: Check sb_bsize_shift after reading superblock
+    - gfs2: Switch from strlcpy to strscpy
+    - 9p/trans_fd: always use O_NONBLOCK read/write
+    - mm: fs: initialize fsdata passed to write_begin/write_end interface
+    - ntfs: fix use-after-free in ntfs_attr_find()
+    - ntfs: fix out-of-bounds read in ntfs_attr_find()
+    - ntfs: check overflow when iterating ATTR_RECORDs
+    - Linux 5.4.225
+  * CVE-2022-47520
+    - wifi: wilc1000: validate pairwise and authentication suite offsets
+  * CVE-2022-3545
+    - nfp: fix use-after-free in area_cache_get()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 10 Mar 2023 12:24:57 +0800
+
+linux-ein (5.4.0-1033.39) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1033.39 -proposed tracker (LP: #2007484)
+
+  * Focal update: v5.4.221 upstream stable release (LP: #1997993)
+    - [Config] updateconfigs for ARM64_ERRATUM_1742098
+
+  * [UC20][Amgis-V5] AVR watchdog on reboot (LP#1999760)
+    - SAUCE: dts: amgis: Remove safe and v2 device tree files
+    - SAUCE: amgis: dts: Default to camera enable
+    - SAUCE: amgis: dts: v3 and v4 cleanup
+    - SAUCE: amgis: dts: v5 hardware GPIO configuration
+
+  * [UC20][Amgis-V5] Enabling OPTEE based FDE (LP #1995129)
+    - SAUCE: dts: amgis: Enable optee node
+
+  * [UC20][Amgis-V5] go standby mode and then resume pushing the power button
+    (LP #1995144)
+    - SAUCE: dts: amgis: Enable wake-up GPIO pin
+
+  * [UC20] Camera does not work after resume from suspend (LP #1999815)
+    - SAUCE: imx: gpcv2: Fix PGC CPU mapping after resume
+
+  [ Ubuntu: 5.4.0-139.156 ]
+
+  * focal/linux: 5.4.0-139.156 -proposed tracker (LP: #2003486)
+  * Revoke & rotate to new signing key (LP: #2002812)
+    - [Packaging] Revoke and rotate to new signing key
+
+  [ Ubuntu: 5.4.0-138.155 ]
+
+  * focal/linux: 5.4.0-138.155 -proposed tracker (LP: #2001845)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+  * Focal update: v5.4.224 upstream stable release (LP: #1999273)
+    - RDMA/cma: Use output interface for net_dev check
+    - IB/hfi1: Correctly move list in sc_disable()
+    - NFSv4.1: Handle RECLAIM_COMPLETE trunking errors
+    - NFSv4.1: We must always send RECLAIM_COMPLETE after a reboot
+    - nfs4: Fix kmemleak when allocate slot failed
+    - net: dsa: Fix possible memory leaks in dsa_loop_init()
+    - RDMA/core: Fix null-ptr-deref in ib_core_cleanup()
+    - RDMA/qedr: clean up work queue on failure in qedr_alloc_resources()
+    - nfc: s3fwrn5: Fix potential memory leak in s3fwrn5_nci_send()
+    - nfc: nfcmrvl: Fix potential memory leak in nfcmrvl_i2c_nci_send()
+    - net: fec: fix improper use of NETDEV_TX_BUSY
+    - ata: pata_legacy: fix pdc20230_set_piomode()
+    - net: sched: Fix use after free in red_enqueue()
+    - net: tun: fix bugs for oversize packet when napi frags enabled
+    - netfilter: nf_tables: release flow rule object from commit path
+    - ipvs: use explicitly signed chars
+    - ipvs: fix WARNING in __ip_vs_cleanup_batch()
+    - ipvs: fix WARNING in ip_vs_app_net_cleanup()
+    - rose: Fix NULL pointer dereference in rose_send_frame()
+    - mISDN: fix possible memory leak in mISDN_register_device()
+    - isdn: mISDN: netjet: fix wrong check of device registration
+    - btrfs: fix inode list leak during backref walking at resolve_indirect_refs()
+    - btrfs: fix inode list leak during backref walking at find_parent_nodes()
+    - btrfs: fix ulist leaks in error paths of qgroup self tests
+    - Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
+    - net: mdio: fix undefined behavior in bit shift for __mdiobus_register
+    - net, neigh: Fix null-ptr-deref in neigh_table_clear()
+    - ipv6: fix WARNING in ip6_route_net_exit_late()
+    - media: s5p_cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: cros-ec-cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: dvb-frontends/drxk: initialize err to 0
+    - media: meson: vdec: fix possible refcount leak in vdec_probe()
+    - scsi: core: Restrict legal sdev_state transitions via sysfs
+    - HID: saitek: add madcatz variant of MMO7 mouse device ID
+    - i2c: xiic: Add platform module alias
+    - xfs: don't fail verifier on empty attr3 leaf block
+    - xfs: use ordered buffers to initialize dquot buffers during quotacheck
+    - xfs: gut error handling in xfs_trans_unreserve_and_mod_sb()
+    - xfs: group quota should return EDQUOT when prj quota enabled
+    - xfs: don't fail unwritten extent conversion on writeback due to edquot
+    - xfs: Add the missed xfs_perag_put() for xfs_ifree_cluster()
+    - Bluetooth: L2CAP: Fix attempting to access uninitialized memory
+    - block, bfq: protect 'bfqd->queued' by 'bfqd->lock'
+    - binder: fix UAF of alloc->vma in race with munmap()
+    - btrfs: fix type of parameter generation in btrfs_get_dentry
+    - tcp/udp: Make early_demux back namespacified.
+    - kprobe: reverse kp->flags when arm_kprobe failed
+    - tools/nolibc/string: Fix memcmp() implementation
+    - tracing/histogram: Update document for KEYS_MAX size
+    - capabilities: fix potential memleak on error path from vfs_getxattr_alloc()
+    - fuse: add file_modified() to fallocate
+    - efi: random: reduce seed size to 32 bytes
+    - perf/x86/intel: Fix pebs event constraints for ICL
+    - perf/x86/intel: Add Cooper Lake stepping to isolation_ucodes[]
+    - ALSA: usb-audio: Add quirks for MacroSilicon MS2100/MS2106 devices
+    - parisc: Make 8250_gsc driver dependend on CONFIG_PARISC
+    - parisc: Export iosapic_serial_irq() symbol for serial port driver
+    - parisc: Avoid printing the hardware path twice
+    - ext4: fix warning in 'ext4_da_release_space'
+    - ext4: fix BUG_ON() when directory entry has invalid rec_len
+    - KVM: x86: Mask off reserved bits in CPUID.8000001AH
+    - KVM: x86: Mask off reserved bits in CPUID.80000008H
+    - KVM: x86: emulator: em_sysexit should update ctxt->mode
+    - KVM: x86: emulator: introduce emulator_recalc_and_set_mode
+    - KVM: x86: emulator: update the emulation mode after CR0 write
+    - mtd: rawnand: gpmi: Set WAIT_FOR_READY timeout based on program/erase times
+    - drm/rockchip: dsi: Force synchronous probe
+    - drm/i915/sdvo: Filter out invalid outputs more sensibly
+    - drm/i915/sdvo: Setup DDC fully before output init
+    - wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
+    - ipc: remove memcg accounting for sops objects in do_semtimedop()
+    - Linux 5.4.224
+  * Focal update: v5.4.223 upstream stable release (LP: #1999179)
+    - can: j1939: transport: j1939_session_skb_drop_old():
+      spin_unlock_irqrestore() before kfree_skb()
+    - can: kvaser_usb: Fix possible completions during init_completion
+    - ALSA: Use del_timer_sync() before freeing timer
+    - ALSA: au88x0: use explicitly signed char
+    - USB: add RESET_RESUME quirk for NVIDIA Jetson devices in RCM
+    - usb: dwc3: gadget: Stop processing more requests on IMI
+    - usb: dwc3: gadget: Don't set IMI for no_interrupt
+    - usb: bdc: change state when port disconnected
+    - usb: xhci: add XHCI_SPURIOUS_SUCCESS to ASM1042 despite being a V0.96
+      controller
+    - mtd: rawnand: marvell: Use correct logic for nand-keep-config
+    - xhci: Remove device endpoints from bandwidth list when freeing the device
+    - tools: iio: iio_utils: fix digit calculation
+    - iio: light: tsl2583: Fix module unloading
+    - fbdev: smscufx: Fix several use-after-free bugs
+    - mac802154: Fix LQI recording
+    - drm/msm/dsi: fix memory corruption with too many bridges
+    - drm/msm/hdmi: fix memory corruption with too many bridges
+    - mmc: core: Fix kernel panic when remove non-standard SDIO card
+    - kernfs: fix use-after-free in __kernfs_remove
+    - perf auxtrace: Fix address filter symbol name match for modules
+    - s390/futex: add missing EX_TABLE entry to __futex_atomic_op()
+    - s390/pci: add missing EX_TABLE entries to
+      __pcistg_mio_inuser()/__pcilg_mio_inuser()
+    - xfs: finish dfops on every insert range shift iteration
+    - xfs: clear XFS_DQ_FREEING if we can't lock the dquot buffer to flush
+    - xfs: force the log after remapping a synchronous-writes file
+    - Xen/gntdev: don't ignore kernel unmapping error
+    - xen/gntdev: Prevent leaking grants
+    - mm,hugetlb: take hugetlb_lock before decrementing h->resv_huge_pages
+    - net: ieee802154: fix error return code in dgram_bind()
+    - media: v4l2: Fix v4l2_i2c_subdev_set_name function documentation
+    - drm/msm: Fix return type of mdp4_lvds_connector_mode_valid
+    - arc: iounmap() arg is volatile
+    - ALSA: ac97: fix possible memory leak in snd_ac97_dev_register()
+    - tipc: fix a null-ptr-deref in tipc_topsrv_accept
+    - net: netsec: fix error handling in netsec_register_mdio()
+    - x86/unwind/orc: Fix unreliable stack dump with gcov
+    - amd-xgbe: fix the SFP compliance codes check for DAC cables
+    - amd-xgbe: add the bit rate quirk for Molex cables
+    - kcm: annotate data-races around kcm->rx_psock
+    - kcm: annotate data-races around kcm->rx_wait
+    - net: fix UAF issue in nfqnl_nf_hook_drop() when ops_init() failed
+    - net: lantiq_etop: don't free skb when returning NETDEV_TX_BUSY
+    - tcp: fix indefinite deferral of RTO with SACK reneging
+    - can: mscan: mpc5xxx: mpc5xxx_can_probe(): add missing put_clock() in error
+      path
+    - PM: hibernate: Allow hybrid sleep to work with s2idle
+    - media: vivid: s_fbuf: add more sanity checks
+    - media: vivid: dev->bitmap_cap wasn't freed in all cases
+    - media: v4l2-dv-timings: add sanity checks for blanking values
+    - media: videodev2.h: V4L2_DV_BT_BLANKING_HEIGHT should check 'interlaced'
+    - i40e: Fix ethtool rx-flow-hash setting for X722
+    - i40e: Fix VF hang when reset is triggered on another VF
+    - i40e: Fix flow-type by setting GL_HASH_INSET registers
+    - net: ksz884x: fix missing pci_disable_device() on error in pcidev_init()
+    - PM: domains: Fix handling of unavailable/disabled idle states
+    - ALSA: aoa: i2sbus: fix possible memory leak in i2sbus_add_dev()
+    - ALSA: aoa: Fix I2S device accounting
+    - openvswitch: switch from WARN to pr_warn
+    - net: ehea: fix possible memory leak in ehea_register_port()
+    - nh: fix scope used to find saddr when adding non gw nh
+    - net/mlx5e: Do not increment ESN when updating IPsec ESN state
+    - net/mlx5: Fix possible use-after-free in async command interface
+    - net: enetc: survive memory pressure without crashing
+    - can: rcar_canfd: rcar_canfd_handle_global_receive(): fix IRQ storm on global
+      FIFO receive
+    - Linux 5.4.223
+  * Focal update: v5.4.222 upstream stable release (LP: #1997994)
+    - once: fix section mismatch on clang builds
+    - Linux 5.4.222
+  * Focal update: v5.4.221 upstream stable release (LP: #1997993)
+    - xfs: open code insert range extent split helper
+    - xfs: rework insert range into an atomic operation
+    - xfs: rework collapse range into an atomic operation
+    - xfs: add a function to deal with corrupt buffers post-verifiers
+    - xfs: xfs_buf_corruption_error should take __this_address
+    - xfs: fix buffer corruption reporting when xfs_dir3_free_header_check fails
+    - xfs: check owner of dir3 data blocks
+    - xfs: check owner of dir3 blocks
+    - xfs: Use scnprintf() for avoiding potential buffer overflow
+    - xfs: remove the xfs_disk_dquot_t and xfs_dquot_t
+    - xfs: remove the xfs_dq_logitem_t typedef
+    - xfs: remove the xfs_qoff_logitem_t typedef
+    - xfs: Replace function declaration by actual definition
+    - xfs: factor out quotaoff intent AIL removal and memory free
+    - xfs: fix unmount hang and memory leak on shutdown during quotaoff
+    - xfs: preserve default grace interval during quotacheck
+    - xfs: Lower CIL flush limit for large logs
+    - xfs: Throttle commits on delayed background CIL push
+    - xfs: factor common AIL item deletion code
+    - xfs: tail updates only need to occur when LSN changes
+    - xfs: don't write a corrupt unmount record to force summary counter recalc
+    - xfs: trylock underlying buffer on dquot flush
+    - xfs: factor out a new xfs_log_force_inode helper
+    - xfs: reflink should force the log out if mounted with wsync
+    - xfs: move inode flush to the sync workqueue
+    - xfs: fix use-after-free on CIL context on shutdown
+    - ocfs2: clear dinode links count in case of error
+    - ocfs2: fix BUG when iput after ocfs2_mknod fails
+    - x86/microcode/AMD: Apply the patch early on every logical thread
+    - hwmon/coretemp: Handle large core ID value
+    - ata: ahci-imx: Fix MODULE_ALIAS
+    - ata: ahci: Match EM_MAX_SLOTS with SATA_PMP_MAX_PORTS
+    - KVM: arm64: vgic: Fix exit condition in scan_its_table()
+    - media: venus: dec: Handle the case where find_format fails
+    - [Config] updateconfigs for ARM64_ERRATUM_1742098
+    - arm64: errata: Remove AES hwcap for COMPAT tasks
+    - r8152: add PID for the Lenovo OneLink+ Dock
+    - btrfs: fix processing of delayed data refs during backref walking
+    - btrfs: fix processing of delayed tree block refs during backref walking
+    - ACPI: extlog: Handle multiple records
+    - tipc: Fix recognition of trial period
+    - tipc: fix an information leak in tipc_topsrv_kern_subscr
+    - HID: magicmouse: Do not set BTN_MOUSE on double report
+    - net/atm: fix proc_mpc_write incorrect return value
+    - net: phy: dp83867: Extend RX strap quirk for SGMII mode
+    - net: sched: cake: fix null pointer access issue when cake_init() fails
+    - net: hns: fix possible memory leak in hnae_ae_register()
+    - iommu/vt-d: Clean up si_domain in the init_dmars() error path
+    - arm64: topology: move store_cpu_topology() to shared code
+    - riscv: topology: fix default topology reporting
+    - ACPI: video: Force backlight native for more TongFang devices
+    - Makefile.debug: re-enable debug info for .S files
+    - hv_netvsc: Fix race between VF offering and VF association message from host
+    - mm: /proc/pid/smaps_rollup: fix no vma's null-deref
+    - Linux 5.4.221
+  * Focal update: v5.4.220 upstream stable release (LP: #1996812)
+    - ALSA: oss: Fix potential deadlock at unregistration
+    - ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
+    - ALSA: usb-audio: Fix potential memory leaks
+    - ALSA: usb-audio: Fix NULL dererence at error path
+    - ALSA: hda/realtek: remove ALC289_FIXUP_DUAL_SPK for Dell 5530
+    - ALSA: hda/realtek: Correct pin configs for ASUS G533Z
+    - ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
+    - ALSA: hda/realtek: Add Intel Reference SSID to support headset keys
+    - mtd: rawnand: atmel: Unmap streaming DMA mappings
+    - cifs: destage dirty pages before re-reading them for cache=none
+    - cifs: Fix the error length of VALIDATE_NEGOTIATE_INFO message
+    - iio: dac: ad5593r: Fix i2c read protocol requirements
+    - iio: pressure: dps310: Refactor startup procedure
+    - iio: pressure: dps310: Reset chip after timeout
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - can: kvaser_usb: Fix use of uninitialized completion
+    - can: kvaser_usb_leaf: Fix overread with an invalid command
+    - can: kvaser_usb_leaf: Fix TX queue out of sync after restart
+    - can: kvaser_usb_leaf: Fix CAN state after restart
+    - mmc: sdhci-sprd: Fix minimum clock limit
+    - fs: dlm: fix race between test_bit() and queue_work()
+    - fs: dlm: handle -EBUSY first in lock arg validation
+    - HID: multitouch: Add memory barriers
+    - quota: Check next/prev free block number after reading from quota file
+    - ASoC: wcd9335: fix order of Slimbus unprepare/disable
+    - regulator: qcom_rpm: Fix circular deferral regression
+    - RISC-V: Make port I/O string accessors actually work
+    - parisc: fbdev/stifb: Align graphics memory size to 4MB
+    - riscv: Allow PROT_WRITE-only mmap()
+    - riscv: Pass -mno-relax only on lld < 15.0.0
+    - UM: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - PCI: Sanitise firmware BAR assignments behind a PCI-PCI bridge
+    - powerpc/boot: Explicitly disable usage of SPE instructions
+    - fbdev: smscufx: Fix use-after-free in ufx_ops_open()
+    - btrfs: fix race between quota enable and quota rescan ioctl
+    - f2fs: increase the limit for reserve_root
+    - f2fs: fix to do sanity check on destination blkaddr during recovery
+    - f2fs: fix to do sanity check on summary info
+    - nilfs2: fix use-after-free bug of struct nilfs_root
+    - jbd2: wake up journal waiters in FIFO order, not LIFO
+    - ext4: avoid crash when inline data creation follows DIO write
+    - ext4: fix null-ptr-deref in ext4_write_info
+    - ext4: make ext4_lazyinit_thread freezable
+    - ext4: place buffer head allocation before handle start
+    - livepatch: fix race between fork and KLP transition
+    - ftrace: Properly unset FTRACE_HASH_FL_MOD
+    - ring-buffer: Allow splice to read previous partially read pages
+    - ring-buffer: Have the shortest_full queue be the shortest not longest
+    - ring-buffer: Check pending waiters when doing wake ups as well
+    - ring-buffer: Fix race between reset page and reading page
+    - media: cedrus: Set the platform driver data earlier
+    - KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
+    - KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
+    - KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
+    - gcov: support GCC 12.1 and newer compilers
+    - drm/nouveau: fix a use-after-free in nouveau_gem_prime_import_sg_table()
+    - selinux: use "grep -E" instead of "egrep"
+    - tracing: Disable interrupt or preemption before acquiring arch_spinlock_t
+    - userfaultfd: open userfaultfds with O_RDONLY
+    - sh: machvec: Use char[] for section boundaries
+    - ARM: 9247/1: mm: set readonly for MT_MEMORY_RO with ARM_LPAE
+    - nfsd: Fix a memory leak in an error handling path
+    - wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
+    - wifi: mac80211: allow bw change during channel switch in mesh
+    - bpftool: Fix a wrong type cast in btf_dumper_int
+    - x86/resctrl: Fix to restore to original value when re-enabling hardware
+      prefetch register
+    - wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
+    - spi: qup: add missing clk_disable_unprepare on error in spi_qup_resume()
+    - spi: qup: add missing clk_disable_unprepare on error in
+      spi_qup_pm_resume_runtime()
+    - wifi: rtl8xxxu: Fix skb misuse in TX queue selection
+    - bpf: btf: fix truncated last_member_type_id in btf_struct_resolve
+    - wifi: rtl8xxxu: gen2: Fix mistake in path B IQ calibration
+    - net: fs_enet: Fix wrong check in do_pd_setup
+    - bpf: Ensure correct locking around vulnerable function find_vpid()
+    - x86/microcode/AMD: Track patch allocation size explicitly
+    - spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe
+    - netfilter: nft_fib: Fix for rpath check with VRF devices
+    - spi: s3c64xx: Fix large transfers with DMA
+    - vhost/vsock: Use kvmalloc/kvfree for larger packets.
+    - sctp: handle the error returned from sctp_auth_asoc_init_active_key
+    - tcp: fix tcp_cwnd_validate() to not forget is_cwnd_limited
+    - net: rds: don't hold sock lock when cancelling work from
+      rds_tcp_reset_callbacks()
+    - bnx2x: fix potential memory leak in bnx2x_tpa_stop()
+    - net/ieee802154: reject zero-sized raw_sendmsg()
+    - once: add DO_ONCE_SLOW() for sleepable contexts
+    - net: mvpp2: fix mvpp2 debugfs leak
+    - drm: bridge: adv7511: fix CEC power down control register offset
+    - drm/mipi-dsi: Detach devices when removing the host
+    - platform/chrome: fix double-free in chromeos_laptop_prepare()
+    - platform/chrome: fix memory corruption in ioctl
+    - platform/x86: msi-laptop: Fix old-ec check for backlight registering
+    - platform/x86: msi-laptop: Fix resource cleanup
+    - drm: fix drm_mipi_dbi build errors
+    - drm/bridge: megachips: Fix a null pointer dereference bug
+    - ASoC: rsnd: Add check for rsnd_mod_power_on
+    - ALSA: hda: beep: Simplify keep-power-at-enable behavior
+    - drm/omap: dss: Fix refcount leak bugs
+    - mmc: au1xmmc: Fix an error handling path in au1xmmc_probe()
+    - ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API
+    - drm/msm/dpu: index dpu_kms->hw_vbif using vbif_idx
+    - ALSA: dmaengine: increment buffer pointer atomically
+    - mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
+    - ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe
+    - ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe
+    - ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe
+    - ALSA: hda/hdmi: Don't skip notification handling during PM operation
+    - memory: pl353-smc: Fix refcount leak bug in pl353_smc_probe()
+    - memory: of: Fix refcount leak bug in of_get_ddr_timings()
+    - soc: qcom: smsm: Fix refcount leak bugs in qcom_smsm_probe()
+    - soc: qcom: smem_state: Add refcounting for the 'state->of_node'
+    - ARM: dts: turris-omnia: Fix mpp26 pin name and comment
+    - ARM: dts: kirkwood: lsxl: fix serial line
+    - ARM: dts: kirkwood: lsxl: remove first ethernet port
+    - ARM: dts: exynos: correct s5k6a3 reset polarity on Midas family
+    - ARM: Drop CMDLINE_* dependency on ATAGS
+    - ARM: dts: exynos: fix polarity of VBUS GPIO of Origen
+    - iio: adc: at91-sama5d2_adc: fix AT91_SAMA5D2_MR_TRACKTIM_MAX
+    - iio: adc: at91-sama5d2_adc: check return status for pressure and touch
+    - iio: adc: at91-sama5d2_adc: lock around oversampling and sample freq
+    - iio: inkern: only release the device node when done with it
+    - iio: ABI: Fix wrong format of differential capacitance channel ABI.
+    - clk: meson: Hold reference returned by of_get_parent()
+    - clk: oxnas: Hold reference returned by of_get_parent()
+    - clk: berlin: Add of_node_put() for of_get_parent()
+    - clk: tegra: Fix refcount leak in tegra210_clock_init
+    - clk: tegra: Fix refcount leak in tegra114_clock_init
+    - clk: tegra20: Fix refcount leak in tegra20_clock_init
+    - HSI: omap_ssi: Fix refcount leak in ssi_probe
+    - HSI: omap_ssi_port: Fix dma_map_sg error check
+    - media: exynos4-is: fimc-is: Add of_node_put() when breaking out of loop
+    - tty: xilinx_uartps: Fix the ignore_status
+    - media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
+    - RDMA/rxe: Fix "kernel NULL pointer dereference" error
+    - RDMA/rxe: Fix the error caused by qp->sk
+    - misc: ocxl: fix possible refcount leak in afu_ioctl()
+    - dyndbg: fix module.dyndbg handling
+    - dyndbg: let query-modname override actual module name
+    - mtd: devices: docg3: check the return value of devm_ioremap() in the probe
+    - RDMA/siw: Always consume all skbuf data in sk_data_ready() upcall.
+    - ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
+    - ata: fix ata_id_has_devslp()
+    - ata: fix ata_id_has_ncq_autosense()
+    - ata: fix ata_id_has_dipm()
+    - mtd: rawnand: meson: fix bit map use in meson_nfc_ecc_correct()
+    - md/raid5: Ensure stripe_fill happens on non-read IO with journal
+    - xhci: Don't show warning for reinit on known broken suspend
+    - usb: gadget: function: fix dangling pnp_string in f_printer.c
+    - drivers: serial: jsm: fix some leaks in probe
+    - tty: serial: fsl_lpuart: disable dma rx/tx use flags in lpuart_dma_shutdown
+    - phy: qualcomm: call clk_disable_unprepare in the error handling
+    - staging: vt6655: fix some erroneous memory clean-up loops
+    - firmware: google: Test spinlock on panic path to avoid lockups
+    - serial: 8250: Fix restoring termios speed after suspend
+    - scsi: libsas: Fix use-after-free bug in smp_execute_task_sg()
+    - fsi: core: Check error number after calling ida_simple_get
+    - mfd: intel_soc_pmic: Fix an error handling path in
+      intel_soc_pmic_i2c_probe()
+    - mfd: fsl-imx25: Fix an error handling path in mx25_tsadc_setup_irq()
+    - mfd: lp8788: Fix an error handling path in lp8788_probe()
+    - mfd: lp8788: Fix an error handling path in lp8788_irq_init() and
+      lp8788_irq_init()
+    - mfd: fsl-imx25: Fix check for platform_get_irq() errors
+    - mfd: sm501: Add check for platform_driver_register()
+    - clk: mediatek: mt8183: mfgcfg: Propagate rate changes to parent
+    - dmaengine: ioat: stop mod_timer from resurrecting deleted timer in
+      __cleanup()
+    - spmi: pmic-arb: correct duplicate APID to PPID mapping logic
+    - clk: bcm2835: fix bcm2835_clock_rate_from_divisor declaration
+    - clk: ti: dra7-atl: Fix reference leak in of_dra7_atl_clk_probe
+    - clk: ast2600: BCLK comes from EPLL
+    - mailbox: bcm-ferxrm-mailbox: Fix error check for dma_map_sg
+    - powerpc/math_emu/efp: Include module.h
+    - powerpc/sysdev/fsl_msi: Add missing of_node_put()
+    - powerpc/pci_dn: Add missing of_node_put()
+    - powerpc/powernv: add missing of_node_put() in opal_export_attrs()
+    - x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition
+    - powerpc/64s: Fix GENERIC_CPU build flags for PPC970 / G5
+    - powerpc: Fix SPE Power ISA properties for e500v1 platforms
+    - cgroup/cpuset: Enable update_tasks_cpumask() on top_cpuset
+    - iommu/omap: Fix buffer overflow in debugfs
+    - crypto: akcipher - default implementation for setting a private key
+    - crypto: ccp - Release dma channels before dmaengine unrgister
+    - iommu/iova: Fix module config properly
+    - kbuild: remove the target in signal traps when interrupted
+    - crypto: cavium - prevent integer overflow loading firmware
+    - f2fs: fix race condition on setting FI_NO_EXTENT flag
+    - ACPI: video: Add Toshiba Satellite/Portege Z830 quirk
+    - MIPS: BCM47XX: Cast memcmp() of function to (void *)
+    - powercap: intel_rapl: fix UBSAN shift-out-of-bounds issue
+    - thermal: intel_powerclamp: Use get_cpu() instead of smp_processor_id() to
+      avoid crash
+    - NFSD: Return nfserr_serverfault if splice_ok but buf->pages have data
+    - wifi: brcmfmac: fix invalid address access when enabling SCAN log level
+    - bpftool: Clear errno after libcap's checks
+    - openvswitch: Fix double reporting of drops in dropwatch
+    - openvswitch: Fix overreporting of drops in dropwatch
+    - tcp: annotate data-race around tcp_md5sig_pool_populated
+    - wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()
+    - xfrm: Update ipcomp_scratches with NULL when freed
+    - wifi: brcmfmac: fix use-after-free bug in brcmf_netdev_start_xmit()
+    - Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
+    - Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
+    - can: bcm: check the result of can_send() in bcm_can_tx()
+    - wifi: rt2x00: don't run Rt5592 IQ calibration on MT7620
+    - wifi: rt2x00: set correct TX_SW_CFG1 MAC register for MT7620
+    - wifi: rt2x00: set VGC gain for both chains of MT7620
+    - wifi: rt2x00: set SoC wmac clock register
+    - wifi: rt2x00: correctly set BBP register 86 for MT7620
+    - net: If sock is dead don't access sock's sk_wq in sk_stream_wait_memory
+    - Bluetooth: L2CAP: Fix user-after-free
+    - drm/nouveau/nouveau_bo: fix potential memory leak in nouveau_bo_alloc()
+    - drm: Use size_t type for len variable in drm_copy_field()
+    - drm: Prevent drm_copy_field() to attempt copying a NULL pointer
+    - drm/amd/display: fix overflow on MIN_I64 definition
+    - drm/vc4: vec: Fix timings for VEC modes
+    - drm: panel-orientation-quirks: Add quirk for Anbernic Win600
+    - platform/x86: msi-laptop: Change DMI match / alias strings to fix module
+      autoloading
+    - drm/amdgpu: fix initial connector audio value
+    - mmc: sdhci-msm: add compatible string check for sdm670
+    - ARM: dts: imx7d-sdb: config the max pressure for tsc2046
+    - ARM: dts: imx6q: add missing properties for sram
+    - ARM: dts: imx6dl: add missing properties for sram
+    - ARM: dts: imx6qp: add missing properties for sram
+    - ARM: dts: imx6sl: add missing properties for sram
+    - ARM: dts: imx6sll: add missing properties for sram
+    - ARM: dts: imx6sx: add missing properties for sram
+    - btrfs: scrub: try to fix super block errors
+    - clk: zynqmp: Fix stack-out-of-bounds in strncpy`
+    - media: cx88: Fix a null-ptr-deref bug in buffer_prepare()
+    - clk: zynqmp: pll: rectify rate rounding in zynqmp_pll_round_rate
+    - scsi: 3w-9xxx: Avoid disabling device if failing to enable it
+    - nbd: Fix hung when signal interrupts nbd_start_device_ioctl()
+    - power: supply: adp5061: fix out-of-bounds read in adp5061_get_chg_type()
+    - staging: vt6655: fix potential memory leak
+    - ata: libahci_platform: Sanity check the DT child nodes number
+    - bcache: fix set_at_max_writeback_rate() for multiple attached devices
+    - HID: roccat: Fix use-after-free in roccat_read()
+    - md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d
+    - usb: host: xhci: Fix potential memory leak in xhci_alloc_stream_info()
+    - usb: musb: Fix musb_gadget.c rxstate overflow bug
+    - Revert "usb: storage: Add quirk for Samsung Fit flash"
+    - staging: rtl8723bs: fix a potential memory leak in rtw_init_cmd_priv()
+    - nvme: copy firmware_rev on each init
+    - nvmet-tcp: add bounds check on Transfer Tag
+    - usb: idmouse: fix an uninit-value in idmouse_open
+    - clk: bcm2835: Make peripheral PLLC critical
+    - perf intel-pt: Fix segfault in intel_pt_print_info() with uClibc
+    - net: ieee802154: return -EINVAL for unknown addr type
+    - Revert "net/ieee802154: reject zero-sized raw_sendmsg()"
+    - net/ieee802154: don't warn zero-sized raw_sendmsg()
+    - ext4: continue to expand file system when the target size doesn't reach
+    - efi: libstub: drop pointless get_memory_map() call
+    - inet: fully convert sk->sk_rx_dst to RCU rules
+    - thermal: intel_powerclamp: Use first online CPU as control_cpu
+    - Linux 5.4.220
+  * Focal update: v5.4.219 upstream stable release (LP: #1996804)
+    - Linux 5.4.219
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 16 Feb 2023 23:33:02 +0800
+
+linux-ein (5.4.0-1032.38) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1032.38 -proposed tracker (LP: #2006609)
+
+  * [UC20][QCA-BT] The bluetooth interface is unstable (LP: #1999613)
+    - SAUCE: bluetooth: Add support for Qualcomm's HCI IBS protocol
+    - [Config] Enable HCI IBS protocol
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 09 Feb 2023 12:40:51 +0800
+
+linux-ein (5.4.0-1031.37) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1031.37 -proposed tracker (LP: #2002802)
+
+  * [K4500-NXP][B0+DV-2][UC20] Sometimes show kernel messages 'mmc2: cqhci:
+    timeout for tag 31' (LP: #2000621)
+    - mmc: sdhci-esdhc-imx: disable CMDQ support
+
+  [ Ubuntu: 5.4.0-137.154 ]
+
+  * focal/linux: 5.4.0-137.154 -proposed tracker (LP: #2001969)
+  * CVE-2022-3643
+    - 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
+  * CVE-2022-45934
+    - Bluetooth: L2CAP: Fix u8 overflow
+  * CVE-2022-42896
+    - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
+
+  [ Ubuntu: 5.4.0-136.153 ]
+
+  * focal/linux: 5.4.0-136.153 -proposed tracker (LP: #1997835)
+  * Expose built-in trusted and revoked certificates (LP: #1996892)
+    - [Packaging] Expose built-in trusted and revoked certificates
+  * [UBUNTU 20.04] KVM: PV: ext call delivered twice when receiver in PSW wait
+    (LP: #1995941)
+    - KVM: s390: pv: don't present the ecall interrupt twice
+  * [UBUNTU 20.04] boot: Add s390x secure boot trailer (LP: #1996071)
+    - s390/boot: add secure boot trailer
+  * Fix rfkill causing soft blocked wifi (LP: #1996198)
+    - platform/x86: hp_wmi: Fix rfkill causing soft blocked wifi
+  * md: Replace snprintf with scnprintf (LP: #1993315)
+    - md: Replace snprintf with scnprintf
+  * input/keyboard: the keyboard on some Asus laptops can't work (LP: #1992266)
+    - ACPI: resource: Skip IRQ override on Asus Vivobook K3402ZA/K3502ZA
+    - ACPI: resource: Add ASUS model S5402ZA to quirks
+  * Focal update: v5.4.218 upstream stable release (LP: #1995530)
+    - mm: pagewalk: Fix race between unmap and page walker
+    - perf tools: Fixup get_current_dir_name() compilation
+    - firmware: arm_scmi: Add SCMI PM driver remove routine
+    - dmaengine: xilinx_dma: cleanup for fetching xlnx,num-fstores property
+    - dmaengine: xilinx_dma: Report error in case of dma_set_mask_and_coherent API
+      failure
+    - ARM: dts: fix Moxa SDIO 'compatible', remove 'sdhci' misnomer
+    - scsi: qedf: Fix a UAF bug in __qedf_probe()
+    - net/ieee802154: fix uninit value bug in dgram_sendmsg
+    - um: Cleanup syscall_handler_t cast in syscalls_32.h
+    - um: Cleanup compiler warning in arch/x86/um/tls_32.c
+    - arch: um: Mark the stack non-executable to fix a binutils warning
+    - usb: mon: make mmapped memory read only
+    - USB: serial: ftdi_sio: fix 300 bps rate for SIO
+    - mmc: core: Replace with already defined values for readability
+    - mmc: core: Terminate infinite loop in SD-UHS voltage switch
+    - rpmsg: qcom: glink: replace strncpy() with strscpy_pad()
+    - nilfs2: fix leak of nilfs_root in case of writer thread creation failure
+    - nilfs2: replace WARN_ONs by nilfs_error for checkpoint acquisition failure
+    - ceph: don't truncate file in atomic_open
+    - random: clamp credited irq bits to maximum mixed
+    - ALSA: hda: Fix position reporting on Poulsbo
+    - efi: Correct Macmini DMI match in uefi cert quirk
+    - USB: serial: qcserial: add new usb-id for Dell branded EM7455
+    - random: restore O_NONBLOCK support
+    - random: avoid reading two cache lines on irq randomness
+    - random: use expired timer rather than wq for mixing fast pool
+    - Input: xpad - add supported devices as contributed on github
+    - Input: xpad - fix wireless 360 controller breaking after suspend
+    - Linux 5.4.218
+  * Focal update: v5.4.217 upstream stable release (LP: #1995528)
+    - xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag
+    - xfs: introduce XFS_MAX_FILEOFF
+    - xfs: truncate should remove all blocks, not just to the end of the page
+      cache
+    - xfs: fix s_maxbytes computation on 32-bit kernels
+    - xfs: fix IOCB_NOWAIT handling in xfs_file_dio_aio_read
+    - xfs: refactor remote attr value buffer invalidation
+    - xfs: fix memory corruption during remote attr value buffer invalidation
+    - xfs: move incore structures out of xfs_da_format.h
+    - xfs: streamline xfs_attr3_leaf_inactive
+    - xfs: fix uninitialized variable in xfs_attr3_leaf_inactive
+    - xfs: remove unused variable 'done'
+    - Makefile.extrawarn: Move -Wcast-function-type-strict to W=1
+    - docs: update mediator information in CoC docs
+    - Linux 5.4.217
+  * Focal update: v5.4.216 upstream stable release (LP: #1995526)
+    - uas: add no-uas quirk for Hiksemi usb_disk
+    - usb-storage: Add Hiksemi USB3-FW to IGNORE_UAS
+    - uas: ignore UAS for Thinkplus chips
+    - net: usb: qmi_wwan: Add new usb-id for Dell branded EM7455
+    - clk: ingenic-tcu: Properly enable registers before accessing timers
+    - ARM: dts: integrator: Tag PCI host with device_type
+    - ntfs: fix BUG_ON in ntfs_lookup_inode_by_name()
+    - libata: add ATA_HORKAGE_NOLPM for Pioneer BDR-207M and BDR-205
+    - mmc: moxart: fix 4-bit bus width and remove 8-bit bus width
+    - mm/page_alloc: fix race condition between build_all_zonelists and page
+      allocation
+    - mm: prevent page_frag_alloc() from corrupting the memory
+    - mm/migrate_device.c: flush TLB while holding PTL
+    - mm: fix madivse_pageout mishandling on non-LRU page
+    - media: dvb_vb2: fix possible out of bound access
+    - ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver
+    - ARM: dts: am33xx: Fix MMCHS0 dma properties
+    - soc: sunxi: sram: Actually claim SRAM regions
+    - soc: sunxi: sram: Prevent the driver from being unbound
+    - soc: sunxi_sram: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - soc: sunxi: sram: Fix probe function ordering issues
+    - soc: sunxi: sram: Fix debugfs info for A64 SRAM C
+    - Revert "drm: bridge: analogix/dp: add panel prepare/unprepare in
+      suspend/resume time"
+    - Input: melfas_mip4 - fix return value check in mip4_probe()
+    - usbnet: Fix memory leak in usbnet_disconnect()
+    - nvme: add new line after variable declatation
+    - nvme: Fix IOC_PR_CLEAR and IOC_PR_RELEASE ioctls for nvme devices
+    - selftests: Fix the if conditions of in test_extra_filter()
+    - clk: imx: imx6sx: remove the SET_RATE_PARENT flag for QSPI clocks
+    - clk: iproc: Do not rely on node name for correct PLL setup
+    - Linux 5.4.216
+  * Focal update: v5.4.215 upstream stable release (LP: #1993203)
+    - of: fdt: fix off-by-one error in unflatten_dt_nodes()
+    - NFSv4: Turn off open-by-filehandle and NFS re-export for NFSv4.0
+    - gpio: mpc8xxx: Fix support for IRQ_TYPE_LEVEL_LOW flow_type in mpc85xx
+    - drm/meson: Correct OSD1 global alpha value
+    - drm/meson: Fix OSD1 RGB to YCbCr coefficient
+    - parisc: ccio-dma: Add missing iounmap in error path in ccio_probe()
+    - ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC
+    - task_stack, x86/cea: Force-inline stack helpers
+    - tracing: hold caller_addr to hardirq_{enable,disable}_ip
+    - cifs: revalidate mapping when doing direct writes
+    - cifs: don't send down the destination address to sendmsg for a SOCK_STREAM
+    - MAINTAINERS: add Chandan as xfs maintainer for 5.4.y
+    - iomap: iomap that extends beyond EOF should be marked dirty
+    - ASoC: nau8824: Fix semaphore unbalance at error paths
+    - regulator: pfuze100: Fix the global-out-of-bounds access in
+      pfuze100_regulator_probe()
+    - rxrpc: Fix local destruction being repeated
+    - rxrpc: Fix calc of resend age
+    - ALSA: hda/sigmatel: Keep power up while beep is enabled
+    - ALSA: hda/tegra: Align BDL entry to 4KB boundary
+    - net: usb: qmi_wwan: add Quectel RM520N
+    - afs: Return -EAGAIN, not -EREMOTEIO, when a file already locked
+    - MIPS: OCTEON: irq: Fix octeon_irq_force_ciu_mapping()
+    - mksysmap: Fix the mismatch of 'L0' symbols in System.map
+    - video: fbdev: pxa3xx-gcu: Fix integer overflow in pxa3xx_gcu_write
+    - cgroup: Add missing cpus_read_lock() to cgroup_attach_task_all()
+    - ALSA: hda/sigmatel: Fix unused variable warning for beep power change
+    - usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind
+    - usb: dwc3: Issue core soft reset before enabling run/stop
+    - usb: dwc3: gadget: Prevent repeat pullup()
+    - usb: dwc3: gadget: Refactor pullup()
+    - usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup()
+    - usb: dwc3: gadget: Avoid duplicate requests to enable Run/Stop
+    - usb: xhci-mtk: get the microframe boundary for ESIT
+    - usb: xhci-mtk: add only one extra CS for FS/LS INTR
+    - usb: xhci-mtk: use @sch_tt to check whether need do TT schedule
+    - usb: xhci-mtk: add a function to (un)load bandwidth info
+    - usb: xhci-mtk: add some schedule error number
+    - usb: xhci-mtk: allow multiple Start-Split in a microframe
+    - usb: xhci-mtk: relax TT periodic bandwidth allocation
+    - wifi: mac80211: Fix UAF in ieee80211_scan_rx()
+    - tty/serial: atmel: RS485 & ISO7816: wait for TXRDY before sending data
+    - serial: atmel: remove redundant assignment in rs485_config
+    - tty: serial: atmel: Preserve previous USART mode if RS485 disabled
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: cdns3: fix issue with rearming ISO OUT endpoint
+    - Revert "usb: add quirks for Lenovo OneLink+ Dock"
+    - Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio"
+    - USB: core: Fix RST error in hub.c
+    - USB: serial: option: add Quectel BG95 0x0203 composition
+    - USB: serial: option: add Quectel RM520N
+    - ALSA: hda/tegra: set depop delay for tegra
+    - ALSA: hda: add Intel 5 Series / 3400 PCI DID
+    - ALSA: hda/realtek: Add quirk for Huawei WRT-WX9
+    - ALSA: hda/realtek: Re-arrange quirk table entries
+    - ALSA: hda/realtek: Add pincfg for ASUS G513 HP jack
+    - ALSA: hda/realtek: Add pincfg for ASUS G533Z HP jack
+    - ALSA: hda/realtek: Add quirk for ASUS GA503R laptop
+    - ALSA: hda/realtek: Enable 4-speaker output Dell Precision 5530 laptop
+    - efi: libstub: check Shim mode using MokSBStateRT
+    - mm/slub: fix to return errno if kmalloc() fails
+    - arm64: dts: rockchip: Pull up wlan wake# on Gru-Bob
+    - arm64: dts: rockchip: Set RK3399-Gru PCLK_EDP to 24 MHz
+    - arm64: dts: rockchip: Remove 'enable-active-low' from rk3399-puma
+    - netfilter: nf_conntrack_sip: fix ct_sip_walk_headers
+    - netfilter: nf_conntrack_irc: Tighten matching on DCC message
+    - netfilter: nfnetlink_osf: fix possible bogus match in nf_osf_find()
+    - iavf: Fix cached head and tail value for iavf_get_tx_pending
+    - ipvlan: Fix out-of-bound bugs caused by unset skb->mac_header
+    - net: team: Unsync device addresses on ndo_stop
+    - MIPS: lantiq: export clk_get_io() for lantiq_wdt.ko
+    - MIPS: Loongson32: Fix PHY-mode being left unspecified
+    - iavf: Fix bad page state
+    - i40e: Fix set max_tx_rate when it is lower than 1 Mbps
+    - of: mdio: Add of_node_put() when breaking out of for_each_xx
+    - net/sched: taprio: avoid disabling offload when it was never enabled
+    - net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child
+      qdiscs
+    - netfilter: ebtables: fix memory leak when blob is malformed
+    - can: gs_usb: gs_can_open(): fix race dev->can.state condition
+    - perf jit: Include program header in ELF files
+    - perf kcore_copy: Do not check /proc/modules is unchanged
+    - net: sunhme: Fix packet reception for len < RX_COPY_THRESHOLD
+    - net: sched: fix possible refcount leak in tc_new_tfilter()
+    - serial: Create uart_xmit_advance()
+    - serial: tegra: Use uart_xmit_advance(), fixes icount.tx accounting
+    - serial: tegra-tcu: Use uart_xmit_advance(), fixes icount.tx accounting
+    - s390/dasd: fix Oops in dasd_alias_get_start_dev due to missing pavgroup
+    - usb: xhci-mtk: fix issue of out-of-bounds array access
+    - cifs: always initialize struct msghdr smb_msg completely
+    - Drivers: hv: Never allocate anything besides framebuffer from framebuffer
+      memory region
+    - drm/amd/display: Limit user regamma to a valid value
+    - drm/rockchip: Fix return type of cdn_dp_connector_mode_valid
+    - workqueue: don't skip lockdep work dependency in cancel_work_sync()
+    - ext4: fix bug in extents parsing when eh_entries == 0 and eh_depth > 0
+    - xfs: replace -EIO with -EFSCORRUPTED for corrupt metadata
+    - xfs: slightly tweak an assert in xfs_fs_map_blocks
+    - xfs: add missing assert in xfs_fsmap_owner_from_rmap
+    - xfs: range check ri_cnt when recovering log items
+    - xfs: attach dquots and reserve quota blocks during unwritten conversion
+    - xfs: convert EIO to EFSCORRUPTED when log contents are invalid
+    - xfs: constify the buffer pointer arguments to error functions
+    - xfs: always log corruption errors
+    - xfs: fix some memory leaks in log recovery
+    - xfs: stabilize insert range start boundary to avoid COW writeback race
+    - xfs: use bitops interface for buf log item AIL flag check
+    - xfs: refactor agfl length computation function
+    - xfs: split the sunit parameter update into two parts
+    - xfs: don't commit sunit/swidth updates to disk if that would cause repair
+      failures
+    - xfs: fix an ABBA deadlock in xfs_rename
+    - xfs: fix use-after-free when aborting corrupt attr inactivation
+    - ext4: make directory inode spreading reflect flexbg size
+    - Linux 5.4.215
+  * Focal update: v5.4.214 upstream stable release (LP: #1993196)
+    - drm/msm/rd: Fix FIFO-full deadlock
+    - HID: ishtp-hid-clientHID: ishtp-hid-client: Fix comment typo
+    - hid: intel-ish-hid: ishtp: Fix ishtp client sending disordered message
+    - tg3: Disable tg3 device on system reboot to avoid triggering AER
+    - ieee802154: cc2520: add rc code in cc2520_tx()
+    - Input: iforce - add support for Boeder Force Feedback Wheel
+    - nvmet-tcp: fix unhandled tcp states in nvmet_tcp_state_change()
+    - perf/arm_pmu_platform: fix tests for platform_get_irq() failure
+    - platform/x86: acer-wmi: Acer Aspire One AOD270/Packard Bell Dot keymap fixes
+    - usb: storage: Add ASUS <0x0b05:0x1932> to IGNORE_UAS
+    - mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()
+    - net: dp83822: disable rx error interrupt
+    - soc: fsl: select FSL_GUTS driver for DPIO
+    - tracefs: Only clobber mode/uid/gid on remount if asked
+    - Linux 5.4.214
+  * Focal update: v5.4.213 upstream stable release (LP: #1992211)
+    - efi: capsule-loader: Fix use-after-free in efi_capsule_write
+    - wifi: iwlegacy: 4965: corrected fix for potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - fs: only do a memory barrier for the first set_buffer_uptodate()
+    - Revert "mm: kmemleak: take a full lowmem check in kmemleak_*_phys()"
+    - net: dp83822: disable false carrier interrupt
+    - drm/msm/dsi: fix the inconsistent indenting
+    - drm/msm/dsi: Fix number of regulators for msm8996_dsi_cfg
+    - platform/x86: pmc_atom: Fix SLP_TYPx bitfield mask
+    - iio: adc: mcp3911: make use of the sign bit
+    - ieee802154/adf7242: defer destroy_workqueue call
+    - wifi: cfg80211: debugfs: fix return type in ht40allow_map_read()
+    - Revert "xhci: turn off port power in shutdown"
+    - net: sched: tbf: don't call qdisc_put() while holding tree lock
+    - ethernet: rocker: fix sleep in atomic context bug in neigh_timer_handler
+    - kcm: fix strp_init() order and cleanup
+    - sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb
+    - tcp: annotate data-race around challenge_timestamp
+    - Revert "sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb"
+    - net/smc: Remove redundant refcount increase
+    - serial: fsl_lpuart: RS485 RTS polariy is inverse
+    - staging: rtl8712: fix use after free bugs
+    - powerpc: align syscall table for ppc32
+    - vt: Clear selection before changing the font
+    - tty: serial: lpuart: disable flow control while waiting for the transmit
+      engine to complete
+    - Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flag
+    - iio: adc: mcp3911: use correct formula for AD conversion
+    - misc: fastrpc: fix memory corruption on probe
+    - misc: fastrpc: fix memory corruption on open
+    - USB: serial: ftdi_sio: add Omron CS1W-CIF31 device id
+    - binder: fix UAF of ref->proc caused by race condition
+    - usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup
+    - drm/i915/reg: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops
+    - Revert "clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops"
+    - clk: core: Fix runtime PM sequence in clk_core_unprepare()
+    - Input: rk805-pwrkey - fix module autoloading
+    - clk: bcm: rpi: Fix error handling of raspberrypi_fw_get_rate
+    - hwmon: (gpio-fan) Fix array out of bounds access
+    - gpio: pca953x: Add mutex_lock for regcache sync in PM
+    - thunderbolt: Use the actual buffer in tb_async_error()
+    - xhci: Add grace period after xHC start to prevent premature runtime suspend.
+    - USB: serial: cp210x: add Decagon UCA device id
+    - USB: serial: option: add support for OPPO R11 diag port
+    - USB: serial: option: add Quectel EM060K modem
+    - USB: serial: option: add support for Cinterion MV32-WA/WB RmNet mode
+    - usb: typec: altmodes/displayport: correct pin assignment for UFP receptacles
+    - usb: dwc2: fix wrong order of phy_power_on and phy_init
+    - USB: cdc-acm: Add Icom PMR F3400 support (0c26:0020)
+    - usb-storage: Add ignore-residue quirk for NXP PN7462AU
+    - s390/hugetlb: fix prepare_hugepage_range() check for 2 GB hugepages
+    - s390: fix nospec table alignments
+    - USB: core: Prevent nested device-reset calls
+    - usb: gadget: mass_storage: Fix cdrom data transfers on MAC-OS
+    - driver core: Don't probe devices after bus_type.match() probe deferral
+    - wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected
+    - net: mac802154: Fix a condition in the receive path
+    - ALSA: seq: oss: Fix data-race for max_midi_devs access
+    - ALSA: seq: Fix data-race at module auto-loading
+    - drm/i915/glk: ECS Liva Q2 needs GLK HDMI port timing quirk
+    - btrfs: harden identification of a stale device
+    - usb: dwc3: fix PHY disable sequence
+    - usb: dwc3: disable USB core PHY management
+    - USB: serial: ch341: fix lost character on LCR updates
+    - USB: serial: ch341: fix disabled rx timer on older devices
+    - scsi: megaraid_sas: Fix double kfree()
+    - drm/gem: Fix GEM handle release errors
+    - drm/amdgpu: Check num_gfx_rings for gfx v9_0 rb setup.
+    - drm/radeon: add a force flush to delay work when radeon
+    - parisc: ccio-dma: Handle kmalloc failure in ccio_init_resources()
+    - parisc: Add runtime check to prevent PA2.0 kernels on PA1.x machines
+    - arm64: cacheinfo: Fix incorrect assignment of signed error value to unsigned
+      fw_level
+    - fbdev: chipsfb: Add missing pci_disable_device() in chipsfb_pci_init()
+    - drm/amdgpu: mmVM_L2_CNTL3 register not initialized correctly
+    - ALSA: emu10k1: Fix out of bounds access in snd_emu10k1_pcm_channel_alloc()
+    - ALSA: aloop: Fix random zeros in capture data when using jiffies timer
+    - ALSA: usb-audio: Fix an out-of-bounds bug in
+      __snd_usb_parse_audio_interface()
+    - kprobes: Prohibit probes in gate area
+    - debugfs: add debugfs_lookup_and_remove()
+    - nvmet: fix a use-after-free
+    - scsi: mpt3sas: Fix use-after-free warning
+    - scsi: lpfc: Add missing destroy_workqueue() in error path
+    - cgroup: Optimize single thread migration
+    - cgroup: Elide write-locking threadgroup_rwsem when updating csses on an
+      empty subtree
+    - cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock
+    - smb3: missing inode locks in punch hole
+    - ARM: dts: imx6qdl-kontron-samx6i: remove duplicated node
+    - regulator: core: Clean up on enable failure
+    - RDMA/cma: Fix arguments order in net device validation
+    - soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugs
+    - RDMA/hns: Fix supported page size
+    - netfilter: br_netfilter: Drop dst references before setting.
+    - rxrpc: Fix an insufficiently large sglist in rxkad_verify_packet_2()
+    - afs: Use the operation issue time instead of the reply time for callbacks
+    - sch_sfb: Don't assume the skb is still around after enqueueing to child
+    - tipc: fix shift wrapping bug in map_get()
+    - i40e: Fix kernel crash during module removal
+    - RDMA/siw: Pass a pointer to virt_to_page()
+    - ipv6: sr: fix out-of-bounds read when setting HMAC data.
+    - RDMA/mlx5: Set local port to one when accessing counters
+    - nvme-tcp: fix UAF when detecting digest errors
+    - tcp: fix early ETIMEDOUT after spurious non-SACK RTO
+    - sch_sfb: Also store skb len before calling child enqueue
+    - x86/nospec: Fix i386 RSB stuffing
+    - MIPS: loongson32: ls1c: Fix hang during startup
+    - Linux 5.4.213
+  * CVE-2022-2663
+    - netfilter: nf_conntrack_irc: Fix forged IP logic
+  * CVE-2022-3061
+    - video: fbdev: i740fb: Error out if 'pixclock' equals zero
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sat, 14 Jan 2023 16:17:47 +0800
+
+linux-ein (5.4.0-1030.36) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1030.36 -proposed tracker (LP: #2001879)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * remove a space from model in the device tree (LP: #2001574)
+    - SAUCE: dts: vesta-500: drop the last space from model
+
+  * [UC20] Improper network interface name for wwan interface (LP: #1999616)
+    - net: usb: cdc_ether: added support for Thales Cinterion PLSx3 modem family.
+    - SAUCE: net: usb: cdc_ether: add pls62 modem ids
+
+  * Set LED Behavior for Hard Reboot (LP: #1991304)
+    - SAUCE: dts: vesta-500: Fix the led level and let them on
+
+  * [imx8-bms] Disable SDMA (LP: #1997367)
+    - dmaengine: imx-sdma: restart cyclic channel if needed
+    - dmaengine: imx-sdma: fix cyclic buffer race condition
+    - dmaengine: imx-sdma: only restart cyclic channel when enabled
+
+  * [imx8-bms] Fail to boot OS (LP: #1995467)
+    - SAUCE: serial: sc16is7xx: setup GPIO controller later in probe
+    - SAUCE: serial: sc16is7xx: Change error path order
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 05 Jan 2023 23:08:21 +0800
+
+linux-ein (5.4.0-1029.35) focal; urgency=medium
+
+  * [UC20] Failed to change wifi MAC (LP: #1998279)
+    - SAUCE: ath10k: Add macaddr kernel module parameter
+
+  * Read serial number and MAC address from fuses (device provisioning) (LP:
+    #1991298)
+    - SAUCE: ath10k: Getting macaddr from Uboot
+
+  * Patch file for cascade-kernel (SF: #00347119)
+    - SAUCE: dts: vesta-500: change pad setting to save power
+
+  * Tillamook: Wifi need additional binary file to work (LP: #1990944)
+    - ath10k: add QCA9377 sdio hw_param item
+    - ath10k: switch to ieee80211_tx_dequeue_ni
+    - SAUCE: ath10k: sdio: skip cal_data if without cal_firmware
+
+  * Tillamook: [UC20] Could not detect any USB device (LP: #1991203)
+    - MLK-14285-1 usb: phy: add usb mode for usb_phy
+    - MLK-14285-2 usb: chipidea: set mode for usb phy driver
+    - MLK-13308-2 usb: phy: phy-mxs-usb: handle USB PHY event
+    - MLK-14285-3 usb: phy: mxs: optimize disconnect line condition
+
+  * Tillamook: (image) Secure boot for UC20 (LP: #1991185)
+    - SAUCE: dts: vesta-500: add ocram definition for optee-os
+
+  * Tillamook: (image) Create classic20-x02 image (LP: #1991167)
+    - SAUNCE: dts: add vesta-500 dts and overlay dts
+    - SAUCE: scripts: add support for building dtbo
+    - kbuild: Silence unavoidable dtc overlay warnings
+    - SAUCE: vesta_overlay: support dt overlay for vesta
+    - [Config] enable vesta overlay manager
+
+  * [K4500-NXP] Failed to probe caam_jr device message is shown in dmesg (LP:
+    #1993138)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Disable job ring 2 node
+
+  [ Ubuntu: 5.4.0-135.152 ]
+
+  * focal/linux: 5.4.0-135.152 -proposed tracker (LP: #1997412)
+  * containerd sporadic timeouts (LP: #1996678)
+    - epoll: call final ep_events_available() check under the lock
+    - epoll: check for events when removing a timed out thread from the wait queue
+    - Revert "fs: check FMODE_LSEEK to control internal pipe splicing"
+  * CVE-2022-3621
+    - nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
+  * CVE-2022-3565
+    - mISDN: fix use-after-free bugs in l1oip timer handlers
+  * 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-3564
+    - 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-3594
+    - r8152: Rate limit overflow messages
+  * CVE-2022-42703
+    - mm/rmap.c: don't reuse anon_vma if we just want a copy
+
+  [ Ubuntu: 5.4.0-132.148 ]
+
+  * CVE-2022-42719
+    - mac80211: mlme: find auth challenge directly
+    - wifi: mac80211: don't parse mbssid in assoc response
+    - wifi: mac80211: fix MBSSID parsing use-after-free
+  * iavf: SR-IOV VFs error with no traffic flow when MTU greater than 1500
+    (LP: #1983656)
+    - iavf: Fix set max MTU size with port VLAN and jumbo frames
+    - i40e: Fix VF set max MTU size
+  * fib_nexthop_nongw.sh from ubuntu_kernel_selftests failed on B-5.4
+    (LP: #1990800)
+    - SAUCE: selftests/net: skipping tests for older ip command releases
+  * CVE-2022-29901
+    - Revert "x86/speculation: Add RSB VM Exit protections"
+    - Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
+    - 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/kvm/vmx: Make noinstr clean
+    - 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: Remove skip_r11rcx
+    - 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
+    - intel_idle: Disable IBRS during long idle
+    - x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
+    - 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: Use TEST %REG,%REG instead of CMP $0,%REG in vmenter.S
+    - KVM/nVMX: Use __vmx_vcpu_run in nested_vmx_check_vmentry_hw
+    - KVM: VMX: Flatten __vmx_vcpu_run()
+    - KVM: VMX: Convert launched argument to flags
+    - 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
+  * ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+    systems (LP: #1990985)
+    - ACPI: processor_idle: Skip dummy wait if kernel is in guest
+    - ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+      systems
+  * cgroup: all controllers mounted when using 'cgroup_no_v1=' (LP: #1988584)
+    - cgroup-v1: add disabled controller check in cgroup1_parse_param()
+  * Focal update: v5.4.212 upstream stable release (LP: #1991156)
+    - audit: fix potential double free on error path from fsnotify_add_inode_mark
+    - parisc: Fix exception handler for fldw and fstw instructions
+    - kernel/sys_ni: add compat entry for fadvise64_64
+    - usb: cdns3: Fix issue for clear halt endpoint
+    - pinctrl: amd: Don't save/restore interrupt status and wake status bits
+    - sched/deadline: Unthrottle PI boosted threads while enqueuing
+    - sched/deadline: Fix stale throttling on de-/boosted tasks
+    - sched/deadline: Fix priority inheritance with multiple scheduling classes
+    - kernel/sched: Remove dl_boosted flag comment
+    - xfrm: fix refcount leak in __xfrm_policy_check()
+    - SUNRPC: RPC level errors should set task->tk_rpc_status
+    - rose: check NULL rose_loopback_neigh->loopback
+    - net/mlx5e: Properly disable vlan strip on non-UL reps
+    - net: moxa: get rid of asymmetry in DMA mapping/unmapping
+    - bonding: 802.3ad: fix no transmission of LACPDUs
+    - net: ipvtap - add __init/__exit annotations to module init/exit funcs
+    - netfilter: ebtables: reject blobs that don't provide all entry points
+    - bnxt_en: fix NQ resource accounting during vf creation on 57500 chips
+    - netfilter: nft_payload: report ERANGE for too long offset and length
+    - netfilter: nft_payload: do not truncate csum_offset and csum_type
+    - netfilter: nft_osf: restrict osf to ipv4, ipv6 and inet families
+    - netfilter: nft_tunnel: restrict it to netdev family
+    - net: Fix data-races around weight_p and dev_weight_[rt]x_bias.
+    - net: Fix data-races around netdev_tstamp_prequeue.
+    - ratelimit: Fix data-races in ___ratelimit().
+    - net: Fix a data-race around sysctl_tstamp_allow_data.
+    - net: Fix a data-race around sysctl_net_busy_poll.
+    - net: Fix a data-race around sysctl_net_busy_read.
+    - net: Fix a data-race around netdev_budget.
+    - net: Fix a data-race around netdev_budget_usecs.
+    - net: Fix a data-race around sysctl_somaxconn.
+    - ixgbe: stop resetting SYSTIME in ixgbe_ptp_start_cyclecounter
+    - btrfs: fix silent failure when deleting root reference
+    - btrfs: replace: drop assert for suspended replace
+    - btrfs: add info when mount fails due to stale replace target
+    - btrfs: check if root is readonly while setting security xattr
+    - x86/unwind/orc: Unwind ftrace trampolines with correct ORC entry
+    - loop: Check for overflow while configuring loop
+    - asm-generic: sections: refactor memory_intersects
+    - s390: fix double free of GS and RI CBs on fork() failure
+    - ACPI: processor: Remove freq Qos request for all CPUs
+    - mm/hugetlb: fix hugetlb not supporting softdirty tracking
+    - md: call __md_stop_writes in md_stop
+    - perf/x86/intel/uncore: Fix broken read_counter() for SNB IMC PMU
+    - scsi: storvsc: Remove WQ_MEM_RECLAIM from storvsc_error_wq
+    - mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()
+    - s390/mm: do not trigger write fault when vma does not allow VM_WRITE
+    - x86/bugs: Add "unknown" reporting for MMIO Stale Data
+    - kbuild: Fix include path in scripts/Makefile.modpost
+    - Bluetooth: L2CAP: Fix build errors in some archs
+    - HID: steam: Prevent NULL pointer dereference in steam_{recv,send}_report
+    - udmabuf: Set the DMA mask for the udmabuf device (v2)
+    - media: pvrusb2: fix memory leak in pvr_probe
+    - HID: hidraw: fix memory leak in hidraw_release()
+    - fbdev: fb_pm2fb: Avoid potential divide by zero error
+    - ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is
+      dead
+    - bpf: Don't redirect packets with invalid pkt_len
+    - mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
+    - btrfs: introduce btrfs_lookup_match_dir
+    - btrfs: do not pin logs too early during renames
+    - btrfs: unify lookup return value when dir entry is missing
+    - drm/amd/display: Avoid MPC infinite loop
+    - drm/amd/display: clear optc underflow before turn off odm clock
+    - neigh: fix possible DoS due to net iface start/stop loop
+    - s390/hypfs: avoid error message under KVM
+    - drm/amd/display: Fix pixel clock programming
+    - netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to y
+    - btrfs: tree-checker: check for overlapping extent items
+    - lib/vdso: Let do_coarse() return 0 to simplify the callsite
+    - lib/vdso: Mark do_hres() and do_coarse() as __always_inline
+    - kprobes: don't call disarm_kprobe() for disabled kprobes
+    - net/af_packet: check len when min_header_len equals to 0
+    - net: neigh: don't call kfree_skb() under spin_lock_irqsave()
+    - Linux 5.4.212
+  * Focal update: v5.4.211 upstream stable release (LP: #1990190)
+    - Makefile: link with -z noexecstack --no-warn-rwx-segments
+    - x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments
+    - scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"
+    - ALSA: bcd2000: Fix a UAF bug on the error path of probing
+    - igc: Remove _I_PHY_ID checking
+    - wifi: mac80211_hwsim: fix race condition in pending packet
+    - wifi: mac80211_hwsim: add back erroneously removed cast
+    - wifi: mac80211_hwsim: use 32-bit skb cookie
+    - add barriers to buffer_uptodate and set_buffer_uptodate
+    - HID: wacom: Only report rotation for art pen
+    - HID: wacom: Don't register pad_input for touch switch
+    - KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case
+    - KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case
+    - KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0
+    - KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value
+    - KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks
+    - KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP
+    - mm/mremap: hold the rmap lock in write mode when moving page table entries.
+    - ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model
+    - ALSA: hda/cirrus - support for iMac 12,1 model
+    - ALSA: hda/realtek: Add quirk for another Asus K42JZ model
+    - tty: vt: initialize unicode screen buffer
+    - vfs: Check the truncate maximum size in inode_newsize_ok()
+    - fs: Add missing umask strip in vfs_tmpfile
+    - thermal: sysfs: Fix cooling_device_stats_setup() error code path
+    - fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters
+    - usbnet: Fix linkwatch use-after-free on disconnect
+    - ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()
+    - parisc: Fix device names in /proc/iomem
+    - parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode
+    - drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error
+    - drm/nouveau: fix another off-by-one in nvbios_addr
+    - drm/amdgpu: Check BO's requested pinning domains against its
+      preferred_domains
+    - iio: light: isl29028: Fix the warning in isl29028_remove()
+    - fuse: limit nsec
+    - serial: mvebu-uart: uart2 error bits clearing
+    - md-raid10: fix KASAN warning
+    - ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()
+    - PCI: Add defines for normal and subtractive PCI bridges
+    - powerpc/fsl-pci: Fix Class Code of PCIe Root Port
+    - powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E
+    - powerpc/powernv: Avoid crashing if rng is NULL
+    - MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - coresight: Clear the connection field properly
+    - USB: HCD: Fix URB giveback issue in tasklet function
+    - ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC
+    - arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC
+    - netfilter: nf_tables: fix null deref due to zeroed list head
+    - epoll: autoremove wakers even more aggressively
+    - x86: Handle idle=nomwait cmdline properly for x86_idle
+    - arm64: Do not forget syscall when starting a new thread.
+    - arm64: fix oops in concurrently setting insn_emulation sysctls
+    - ext2: Add more validity checks for inode counts
+    - genirq: Don't return error on missing optional irq_request_resources()
+    - wait: Fix __wait_event_hrtimeout for RT/DL tasks
+    - ARM: dts: imx6ul: add missing properties for sram
+    - ARM: dts: imx6ul: change operating-points to uint32-matrix
+    - ARM: dts: imx6ul: fix csi node compatible
+    - ARM: dts: imx6ul: fix lcdif node compatible
+    - ARM: dts: imx6ul: fix qspi node compatible
+    - spi: synquacer: Add missing clk_disable_unprepare()
+    - ARM: OMAP2+: display: Fix refcount leak bug
+    - ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks
+    - ACPI: PM: save NVS memory for Lenovo G40-45
+    - ACPI: LPSS: Fix missing check in register_device_clock()
+    - arm64: dts: qcom: ipq8074: fix NAND node name
+    - arm64: dts: allwinner: a64: orangepi-win: Fix LED node name
+    - ARM: shmobile: rcar-gen2: Increase refcount for new reference
+    - PM: hibernate: defer device probing when resuming from hibernation
+    - selinux: Add boundary check in put_entry()
+    - spi: spi-rspi: Fix PIO fallback on RZ platforms
+    - ARM: findbit: fix overflowing offset
+    - meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init
+    - ARM: bcm: Fix refcount leak in bcm_kona_smc_init
+    - x86/pmem: Fix platform-device leak in error path
+    - ARM: dts: ast2500-evb: fix board compatible
+    - ARM: dts: ast2600-evb: fix board compatible
+    - soc: fsl: guts: machine variable might be unset
+    - ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg
+    - ARM: OMAP2+: Fix refcount leak in omapdss_init_of
+    - ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init
+    - cpufreq: zynq: Fix refcount leak in zynq_get_revision
+    - soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register
+    - ARM: dts: qcom: pm8841: add required thermal-sensor-cells
+    - bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()
+    - arm64: dts: mt7622: fix BPI-R64 WPS button
+    - erofs: avoid consecutive detection for Highmem memory
+    - blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created
+    - regulator: of: Fix refcount leak bug in of_get_regulation_constraints()
+    - nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()
+    - thermal/tools/tmon: Include pthread and time headers in tmon.h
+    - dm: return early from dm_pr_call() if DM device is suspended
+    - ath10k: do not enforce interrupt trigger type
+    - wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()
+    - drm/mipi-dbi: align max_chunk to 2 in spi_transfer
+    - drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()
+    - drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function
+    - drm: adv7511: override i2c address of cec before accessing it
+    - i2c: Fix a potential use after free
+    - media: tw686x: Register the irq at the end of probe
+    - wifi: iwlegacy: 4965: fix potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - drm: bridge: adv7511: Add check for mipi_dsi_driver_register
+    - drm/mcde: Fix refcount leak in mcde_dsi_bind
+    - media: hdpvr: fix error value returns in hdpvr_read
+    - drm/vc4: plane: Remove subpixel positioning check
+    - drm/vc4: plane: Fix margin calculations for the right/bottom edges
+    - drm/vc4: dsi: Correct DSI divider calculations
+    - crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE
+    - drm/rockchip: vop: Don't crash for invalid duplicate_state()
+    - drm/rockchip: Fix an error handling path rockchip_dp_probe()
+    - drm/mediatek: dpi: Remove output format of YUV
+    - drm/mediatek: dpi: Only enable dpi after the bridge is enabled
+    - drm: bridge: sii8620: fix possible off-by-one
+    - drm/msm/mdp5: Fix global state lock backoff
+    - crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq
+    - media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment
+    - mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()
+    - drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.
+    - tcp: make retransmitted SKB fit into the send window
+    - libbpf: Fix the name of a reused map
+    - selftests: timers: valid-adjtimex: build fix for newer toolchains
+    - selftests: timers: clocksource-switch: fix passing errors from child
+    - fs: check FMODE_LSEEK to control internal pipe splicing
+    - wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()
+    - wifi: p54: Fix an error handling path in p54spi_probe()
+    - wifi: p54: add missing parentheses in p54_flush()
+    - selftests/bpf: fix a test for snprintf() overflow
+    - can: pch_can: do not report txerr and rxerr during bus-off
+    - can: rcar_can: do not report txerr and rxerr during bus-off
+    - can: sja1000: do not report txerr and rxerr during bus-off
+    - can: hi311x: do not report txerr and rxerr during bus-off
+    - can: sun4i_can: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off
+    - can: usb_8dev: do not report txerr and rxerr during bus-off
+    - can: error: specify the values of data[5..7] of CAN error frames
+    - can: pch_can: pch_can_error(): initialize errc before using it
+    - Bluetooth: hci_intel: Add check for platform_driver_register
+    - i2c: cadence: Support PEC for SMBus block read
+    - i2c: mux-gpmux: Add of_node_put() when breaking out of loop
+    - wifi: wil6210: debugfs: fix uninitialized variable use in
+      `wil_write_file_wmi()`
+    - wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue
+    - wifi: libertas: Fix possible refcount leak in if_usb_probe()
+    - net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS
+    - crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of
+    - iavf: Fix max_rate limiting
+    - netdevsim: Avoid allocation warnings triggered from user space
+    - net: rose: fix netdev reference changes
+    - dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock
+    - clk: renesas: r9a06g032: Fix UART clkgrp bitsel
+    - mtd: maps: Fix refcount leak in of_flash_probe_versatile
+    - mtd: maps: Fix refcount leak in ap_flash_init
+    - mtd: rawnand: meson: Fix a potential double free issue
+    - HID: cp2112: prevent a buffer overflow in cp2112_xfer()
+    - mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release
+    - mtd: partitions: Fix refcount leak in parse_redboot_of
+    - mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path
+    - fpga: altera-pr-ip: fix unsigned comparison with less than zero
+    - usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe
+    - usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe
+    - usb: xhci: tegra: Fix error check
+    - clk: mediatek: reset: Fix written reset bit offset
+    - misc: rtsx: Fix an error handling path in rtsx_pci_probe()
+    - driver core: fix potential deadlock in __driver_attach
+    - clk: qcom: clk-krait: unlock spin after mux completion
+    - usb: host: xhci: use snprintf() in xhci_decode_trb()
+    - clk: qcom: ipq8074: fix NSS port frequency tables
+    - clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks
+    - clk: qcom: camcc-sdm845: Fix topology around titan_top power domain
+    - soundwire: bus_type: fix remove and shutdown support
+    - intel_th: Fix a resource leak in an error handling path
+    - intel_th: msu-sink: Potential dereference of null pointer
+    - intel_th: msu: Fix vmalloced buffers
+    - staging: rtl8192u: Fix sleep in atomic context bug in
+      dm_fsync_timer_callback
+    - mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch
+    - memstick/ms_block: Fix some incorrect memory allocation
+    - memstick/ms_block: Fix a memory leak
+    - mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R
+    - scsi: smartpqi: Fix DMA direction for RAID requests
+    - usb: gadget: udc: amd5536 depends on HAS_DMA
+    - RDMA/hns: Fix incorrect clearing of interrupt status register
+    - RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event
+    - RDMA/hfi1: fix potential memory leak in setup_base_ctxt()
+    - gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()
+    - mmc: cavium-octeon: Add of_node_put() when breaking out of loop
+    - mmc: cavium-thunderx: Add of_node_put() when breaking out of loop
+    - HID: alps: Declare U1_UNICORN_LEGACY support
+    - PCI: tegra194: Fix Root Port interrupt handling
+    - PCI: tegra194: Fix link up retry sequence
+    - USB: serial: fix tty-port initialized comments
+    - platform/olpc: Fix uninitialized data in debugfs write
+    - mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region
+    - RDMA/rxe: Fix error unwind in rxe_create_qp()
+    - null_blk: fix ida error handling in null_add_dev()
+    - jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()
+    - ext4: recover csum seed of tmp_inode after migrating to extents
+    - jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted
+    - opp: Fix error check in dev_pm_opp_attach_genpd()
+    - ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe
+    - ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe
+    - ASoC: codecs: da7210: add check for i2c_add_driver
+    - ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe
+    - serial: 8250_dw: Store LSR into lsr_saved_flags in dw8250_tx_wait_empty()
+    - ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV
+    - ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV
+    - profiling: fix shift too large makes kernel panic
+    - tty: n_gsm: fix non flow control frames during mux flow off
+    - tty: n_gsm: fix packet re-transmission without open control channel
+    - tty: n_gsm: fix race condition in gsmld_write()
+    - remoteproc: qcom: wcnss: Fix handling of IRQs
+    - vfio/ccw: Do not change FSM state in subchannel event
+    - tty: n_gsm: fix wrong T1 retry count handling
+    - tty: n_gsm: fix DM command
+    - tty: n_gsm: fix missing corner cases in gsmld_poll()
+    - iommu/exynos: Handle failed IOMMU device registration properly
+    - rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge
+    - kfifo: fix kfifo_to_user() return type
+    - mfd: t7l66xb: Drop platform disable callback
+    - mfd: max77620: Fix refcount leak in max77620_initialise_fps
+    - iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop
+    - s390/zcore: fix race when reading from hardware system area
+    - ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()
+    - fuse: Remove the control interface for virtio-fs
+    - ASoC: audio-graph-card: Add of_node_put() in fail path
+    - watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in
+      armada_37xx_wdt_probe()
+    - video: fbdev: amba-clcd: Fix refcount leak bugs
+    - video: fbdev: sis: fix typos in SiS_GetModeID()
+    - powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32
+    - powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and
+      alias
+    - powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader
+    - powerpc/xive: Fix refcount leak in xive_get_max_prio
+    - powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address
+    - perf symbol: Fail to read phdr workaround
+    - kprobes: Forbid probing on trampoline and BPF code areas
+    - powerpc/pci: Fix PHB numbering when using opal-phbid
+    - genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO
+    - scripts/faddr2line: Fix vmlinux detection on arm64
+    - x86/numa: Use cpumask_available instead of hardcoded NULL check
+    - video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()
+    - tools/thermal: Fix possible path truncations
+    - video: fbdev: vt8623fb: Check the size of screen before memset_io()
+    - video: fbdev: arkfb: Check the size of screen before memset_io()
+    - video: fbdev: s3fb: Check the size of screen before memset_io()
+    - scsi: zfcp: Fix missing auto port scan and thus missing target ports
+    - scsi: qla2xxx: Fix discovery issues in FC-AL topology
+    - scsi: qla2xxx: Turn off multi-queue for 8G adapters
+    - scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection
+    - x86/olpc: fix 'logical not is only applied to the left hand side'
+    - spmi: trace: fix stack-out-of-bound access in SPMI tracing functions
+    - kexec, KEYS, s390: Make use of built-in and secondary keyring for signature
+      verification
+    - tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH
+    - btrfs: reset block group chunk force if we have to wait
+    - ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
+    - ext4: make sure ext4_append() always allocates new block
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - ext4: update s_overhead_clusters in the superblock during an on-line resize
+    - ext4: fix extent status tree race in writeback error recovery path
+    - ext4: correct max_inline_xattr_value_size computing
+    - ext4: correct the misjudgment in ext4_iget_extra_inode
+    - intel_th: pci: Add Raptor Lake-S CPU support
+    - intel_th: pci: Add Raptor Lake-S PCH support
+    - intel_th: pci: Add Meteor Lake-P support
+    - dm raid: fix address sanitizer warning in raid_resume
+    - dm raid: fix address sanitizer warning in raid_status
+    - dm thin: fix use-after-free crash in dm_sm_register_threshold_callback
+    - dm writecache: set a default MAX_WRITEBACK_JOBS
+    - ACPI: CPPC: Do not prevent CPPC from working in the future
+    - timekeeping: contribute wall clock to rng on time change
+    - firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails
+    - iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)
+    - btrfs: reject log replay if there is unsupported RO compat flag
+    - KVM: Add infrastructure and macro to mark VM as bugged
+    - KVM: x86: Check lapic_in_kernel() before attempting to set a SynIC irq
+    - KVM: x86: Avoid theoretical NULL pointer dereference in
+      kvm_irq_delivery_to_apic_fast()
+    - tcp: fix over estimation in sk_forced_mem_schedule()
+    - scsi: sg: Allow waiting for commands to complete on removed device
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression
+    - net/9p: Initialize the iounit field during fid creation
+    - net_sched: cls_route: disallow handle of 0
+    - ALSA: info: Fix llseek return value when using callback
+    - rds: add missing barrier to release_refill
+    - ata: libata-eh: Add missing command name
+    - mmc: pxamci: Fix another error handling path in pxamci_probe()
+    - mmc: pxamci: Fix an error handling path in pxamci_probe()
+    - btrfs: fix lost error handling when looking up extended ref on log replay
+    - tracing: Have filter accept "common_cpu" to be consistent
+    - can: ems_usb: fix clang's -Wunaligned-access warning
+    - apparmor: fix quiet_denied for file rules
+    - apparmor: fix absroot causing audited secids to begin with =
+    - apparmor: Fix failed mount permission check error message
+    - apparmor: fix aa_label_asxprint return check
+    - apparmor: fix overlapping attachment computation
+    - apparmor: fix reference count leak in aa_pivotroot()
+    - apparmor: Fix memleak in aa_simple_write_to_buffer()
+    - Documentation: ACPI: EINJ: Fix obsolete example
+    - NFSv4.1: Don't decrease the value of seq_nr_highest_sent
+    - NFSv4.1: Handle NFS4ERR_DELAY replies to OP_SEQUENCE correctly
+    - NFSv4: Fix races in the legacy idmapper upcall
+    - NFSv4.1: RECLAIM_COMPLETE must handle EACCES
+    - NFSv4/pnfs: Fix a use-after-free bug in open
+    - can: mcp251x: Fix race condition on receive interrupt
+    - sunrpc: fix expiry of auth creds
+    - SUNRPC: Reinitialise the backchannel request buffers before reuse
+    - devlink: Fix use-after-free after a failed reload
+    - net: bgmac: Fix a BUG triggered by wrong bytes_compl
+    - pinctrl: nomadik: Fix refcount leak in nmk_pinctrl_dt_subnode_to_map
+    - pinctrl: qcom: msm8916: Allow CAMSS GP clocks to be muxed
+    - pinctrl: sunxi: Add I/O bias setting for H6 R-PIO
+    - ACPI: property: Return type of acpi_add_nondev_subnodes() should be bool
+    - geneve: do not use RT_TOS for IPv6 flowlabel
+    - plip: avoid rcu debug splat
+    - vsock: Fix memory leak in vsock_connect()
+    - vsock: Set socket state back to SS_UNCONNECTED in vsock_connect_timeout()
+    - dt-bindings: arm: qcom: fix MSM8916 MTP compatibles
+    - tools/vm/slabinfo: use alphabetic order when two values are equal
+    - tools build: Switch to new openssl API for test-libcrypto
+    - NTB: ntb_tool: uninitialized heap data in tool_fn_write()
+    - nfp: ethtool: fix the display error of `ethtool -m DEVNAME`
+    - xen/xenbus: fix return type in xenbus_file_read()
+    - atm: idt77252: fix use-after-free bugs caused by tst_timer
+    - dpaa2-eth: trace the allocated address instead of page struct
+    - tee: add overflow check in register_shm_helper()
+    - nios2: page fault et.al. are *not* restartable syscalls...
+    - nios2: don't leave NULLs in sys_call_table[]
+    - nios2: traced syscall does need to check the syscall number
+    - nios2: fix syscall restart checks
+    - nios2: restarts apply only to the first sigframe we build...
+    - nios2: add force_successful_syscall_return()
+    - iavf: Fix adminq error handling
+    - clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks
+    - netfilter: nf_tables: really skip inactive sets when allocating name
+    - powerpc/pci: Fix get_phb_number() locking
+    - net: dsa: mv88e6060: prevent crash on an unused port
+    - net: moxa: pass pdev instead of ndev to DMA functions
+    - net: dsa: microchip: ksz9477: fix fdb_dump last invalid entry
+    - ice: Ignore EEXIST when setting promisc mode
+    - i40e: Fix to stop tx_timeout recovery if GLOBR fails
+    - fec: Fix timer capture timing in `fec_ptp_enable_pps()`
+    - igb: Add lock to avoid data race
+    - gcc-plugins: Undefine LATENT_ENTROPY_PLUGIN when plugin disabled for a file
+    - locking/atomic: Make test_and_*_bit() ordered on failure
+    - drm/meson: Fix refcount bugs in meson_vpu_has_available_connectors()
+    - PCI: Add ACS quirk for Broadcom BCM5750x NICs
+    - usb: cdns3 fix use-after-free at workaround 2
+    - usb: gadget: uvc: call uvc uvcg_warn on completed status instead of
+      uvcg_info
+    - irqchip/tegra: Fix overflow implicit truncation warnings
+    - drm/meson: Fix overflow implicit truncation warnings
+    - usb: host: ohci-ppc-of: Fix refcount leak bug
+    - usb: renesas: Fix refcount leak bug
+    - vboxguest: Do not use devm for irq
+    - clk: qcom: ipq8074: dont disable gcc_sleep_clk_src
+    - scsi: lpfc: Prevent buffer overflow crashes in debugfs with malformed user
+      input
+    - gadgetfs: ep_io - wait until IRQ finishes
+    - cxl: Fix a memory leak in an error handling path
+    - PCI/ACPI: Guard ARM64-specific mcfg_quirks
+    - um: add "noreboot" command line option for PANIC_TIMEOUT=-1 setups
+    - selftests/kprobe: Do not test for GRP/ without event failures
+    - dmaengine: sprd: Cleanup in .remove() after pm_runtime_get_sync() failed
+    - nvmet-tcp: fix lockdep complaint on nvmet_tcp_wq flush during queue teardown
+    - drivers:md:fix a potential use-after-free bug
+    - ext4: avoid remove directory when directory is corrupted
+    - ext4: avoid resizing to a partial cluster size
+    - lib/list_debug.c: Detect uninitialized lists
+    - tty: serial: Fix refcount leak bug in ucc_uart.c
+    - vfio: Clear the caps->buf to NULL after free
+    - mips: cavium-octeon: Fix missing of_node_put() in octeon2_usb_clocks_start
+    - riscv: mmap with PROT_WRITE but no PROT_READ is invalid
+    - RISC-V: Add fast call path of crash_kexec()
+    - watchdog: export lockup_detector_reconfigure
+    - powerpc/32: Don't always pass -mcpu=powerpc to the compiler
+    - ALSA: core: Add async signal helpers
+    - ALSA: timer: Use deferred fasync helper
+    - f2fs: fix to avoid use f2fs_bug_on() in f2fs_new_node_page()
+    - smb3: check xattr value length earlier
+    - powerpc/64: Init jump labels before parse_early_param()
+    - video: fbdev: i740fb: Check the argument of i740_calc_vclk()
+    - MIPS: tlbex: Explicitly compare _PAGE_NO_EXEC against 0
+    - tracing/probes: Have kprobes and uprobes use $COMM too
+    - can: j1939: j1939_sk_queue_activate_next_locked(): replace WARN_ON_ONCE with
+      netdev_warn_once()
+    - can: j1939: j1939_session_destroy(): fix memory leak of skbs
+    - btrfs: only write the sectors in the vertical stripe which has data stripes
+    - btrfs: raid56: don't trust any cached sector in __raid56_parity_recover()
+    - Linux 5.4.211
+  * CVE-2022-3028
+    - af_key: Do not call xfrm_probe_algs in parallel
+  * CVE-2022-2978
+    - fs: fix UAF/GPF bug in nilfs_mdt_destroy
+  * CVE-2022-40768
+    - scsi: stex: Properly zero out the passthrough command structure
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 05 Dec 2022 19:40:05 +0800
+
+linux-ein (5.4.0-1028.34) focal; urgency=medium
+
+  * Dummy entry.
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 05 Dec 2022 14:25:56 +0800
+
+linux-imx (5.4.0-1028.34) focal; urgency=medium
+
+  * Focal update: v5.4.208 upstream stable release (LP: #1988225)
+    - [Config] updateconfigs for IMA_TEMPLATE
+    - [Config] updateconfigs for REFCOUNT_FULL
+
+  * [K4500-NXP][UC20] Integrate graphics driver needed for running QT
+    application (LP: #1990021)
+    - SAUCE: drm: AVD101WX-CN: Assigned bus format to fix warning:
+    - Revert "UBUNTU: SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove gpu node now at
+      the imx8mm.dtsi contains gpu nodes."
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove the 2d/3d GPU nodes that enable
+      the etnaviv driver.
+
+  * M4-RPMSG driver race condition (LP: #1991153)
+    - SAUCE: rpmsg: Fix race condition
+    - SAUCE: rpmsg: Use static prefix for globals
+    - SAUCE: rpmsg: Code clean-up
+
+  * [imx8-pdk] Fail to run perf (LP: #1987467)
+    - tools: perf: metricgroup: add metricgroup for each PMU
+    - perf vendor events: add JSON metrics for imx8 DDR Perf
+    - MLK-23195-4 tool: perf: imx8mp-ddr: correct the master ID
+    - MLK-23302-1 tools: perf: pmu-event: add socname for struct pmu_event
+    - MLK-23302-2 tools: perf: header: add support for checking socname
+    - MLK-23302-3 tools: perf: metricgroup: match metric with socname if needed
+    - MLK-23302-4 tools: perf: pmu-events: add SocName in DDR JSON file
+    - MLK-23724-1 tools: perf: fix metricgroup add metric events multiple times
+    - perf stat: Improve runtime stat for interval mode
+    - MLK-24053-2 perf vendor events: add ddr bandwidth usage metric for i.MX8MP
+    - perf/imx_ddr: Add driver for DDR PMU in i.MX8MPlus
+    - perf/imx_ddr: Dump AXI ID filter info to userspace
+    - perf/imx_ddr: Add stop event counters support for i.MX8MP
+    - MLK-23195-3 perf/imx_ddr: speed up overflow frequency of cycle counter
+    - bindings: perf: imx-ddr: Add new compatible string
+    - MLK-23417-1 perf/imx_ddr: Add AXI ID PORT CHANNEL filter support
+    - MLK-23417-3 perf/imx_ddr: Add driver support for i.MX8DXL DDR Perf
+    - MLK-23418-1 perf/imx_ddr: Extend driver for PMU in DRAM Block(DB)
+    - MLK-23418-3 perf/imx_ddr: Add clock support for Perf in DB
+    - MLK-23418-4 perf/imx_ddr: Add driver support for i.MX8DXL DB Perf
+
+  [ Ubuntu: 5.4.0-131.147 ]
+
+  * CVE-2022-2602
+    - SAUCE: io_uring/af_unix: defer registered files gc to io_uring release
+    - SAUCE: io_uring/af_unix: fix memleak during unix GC
+  * CVE-2022-41674
+    - SAUCE: wifi: cfg80211: fix u8 overflow in
+      cfg80211_update_notlisted_nontrans()
+    - SAUCE: wifi: cfg80211/mac80211: reject bad MBSSID elements
+    - SAUCE: wifi: cfg80211: ensure length byte is present before access
+    - SAUCE: wifi: mac80211_hwsim: avoid mac80211 warning on bad rate
+    - SAUCE: wifi: cfg80211: update hidden BSSes to avoid WARN_ON
+  * CVE-2022-42721
+    - SAUCE: wifi: cfg80211: avoid nontransmitted BSS list corruption
+  * CVE-2022-42720
+    - SAUCE: wifi: cfg80211: fix BSS refcounting bugs
+
+  [ Ubuntu: 5.4.0-128.144 ]
+
+  * focal/linux: 5.4.0-128.144 -proposed tracker (LP: #1990152)
+  * CVE-2022-3176
+    - io_uring: disable polling pollfree files
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809)
+    - selftests/net: test nexthop without gw
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809) // icmp_redirect.sh in ubuntu_kernel_selftests failed on
+    Jammy 5.15.0-49.55 (LP: #1990124)
+    - ip: fix triggering of 'icmp redirect'
+
+  [ Ubuntu: 5.4.0-127.143 ]
+
+  * focal/linux: 5.4.0-127.143 -proposed tracker (LP: #1989892)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.09.19)
+  * [UBUNTU 20.04] mlx5 driver crashes on accessing device attributes during
+    recovery (LP: #1987287)
+    - net/mlx5: Avoid processing commands before cmdif is ready
+  * Focal update: v5.4.210 upstream stable release (LP: #1989230)
+    - thermal: Fix NULL pointer dereferences in of_thermal_ functions
+    - ACPI: video: Force backlight native for some TongFang devices
+    - ACPI: video: Shortening quirk list by identifying Clevo by board_name only
+    - ACPI: APEI: Better fix to avoid spamming the console with old error logs
+    - bpf: Verifer, adjust_scalar_min_max_vals to always call update_reg_bounds()
+    - selftests/bpf: Extend verifier and bpf_sock tests for dst_port loads
+    - bpf: Test_verifier, #70 error message updates for 32-bit right shift
+    - KVM: Don't null dereference ops->destroy
+    - selftests: KVM: Handle compiler optimizations in ucall
+    - media: v4l2-mem2mem: Apply DST_QUEUE_OFF_BASE on MMAP buffers across ioctls
+    - macintosh/adb: fix oob read in do_adb_query() function
+    - x86/speculation: Add RSB VM Exit protections
+    - x86/speculation: Add LFENCE to RSB fill sequence
+    - Linux 5.4.210
+  * Focal update: v5.4.209 upstream stable release (LP: #1989228)
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
+    - ntfs: fix use-after-free in ntfs_ucsncmp()
+    - s390/archrandom: prevent CPACF trng invocations in interrupt context
+    - tcp: Fix data-races around sysctl_tcp_dsack.
+    - tcp: Fix a data-race around sysctl_tcp_app_win.
+    - tcp: Fix a data-race around sysctl_tcp_adv_win_scale.
+    - tcp: Fix a data-race around sysctl_tcp_frto.
+    - tcp: Fix a data-race around sysctl_tcp_nometrics_save.
+    - ice: check (DD | EOF) bits on Rx descriptor rather than (EOP | RS)
+    - ice: do not setup vlan for loopback VSI
+    - scsi: ufs: host: Hold reference returned by of_parse_phandle()
+    - tcp: Fix a data-race around sysctl_tcp_limit_output_bytes.
+    - tcp: Fix a data-race around sysctl_tcp_challenge_ack_limit.
+    - net: ping6: Fix memleak in ipv6_renew_options().
+    - ipv6/addrconf: fix a null-ptr-deref bug for ip6_ptr
+    - igmp: Fix data-races around sysctl_igmp_qrv.
+    - net: sungem_phy: Add of_node_put() for reference returned by of_get_parent()
+    - tcp: Fix a data-race around sysctl_tcp_min_tso_segs.
+    - tcp: Fix a data-race around sysctl_tcp_min_rtt_wlen.
+    - tcp: Fix a data-race around sysctl_tcp_autocorking.
+    - tcp: Fix a data-race around sysctl_tcp_invalid_ratelimit.
+    - Documentation: fix sctp_wmem in ip-sysctl.rst
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_delay_ns.
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_nr.
+    - i40e: Fix interface init with MSI interrupts (no MSI-X)
+    - sctp: fix sleep in atomic context bug in timer handlers
+    - virtio-net: fix the race between refill work and close
+    - perf symbol: Correct address for bss symbols
+    - sfc: disable softirqs for ptp TX
+    - sctp: leave the err path free in sctp_stream_init to sctp_stream_free
+    - ARM: crypto: comment out gcc warning that breaks clang builds
+    - mt7601u: add USB device ID for some versions of XiaoDu WiFi Dongle.
+    - scsi: core: Fix race between handling STS_RESOURCE and completion
+    - Linux 5.4.209
+  * Focal update: v5.4.208 upstream stable release (LP: #1988225)
+    - pinctrl: stm32: fix optional IRQ support to gpios
+    - riscv: add as-options for modules with assembly compontents
+    - mlxsw: spectrum_router: Fix IPv4 nexthop gateway indication
+    - lockdown: Fix kexec lockdown bypass with ima policy
+    - xen/gntdev: Ignore failure to unmap INVALID_GRANT_HANDLE
+    - PCI: hv: Fix multi-MSI to allow more than one MSI vector
+    - PCI: hv: Fix hv_arch_irq_unmask() for multi-MSI
+    - PCI: hv: Reuse existing IRTE allocation in compose_msi_msg()
+    - PCI: hv: Fix interrupt mapping for multi-MSI
+    - serial: mvebu-uart: correctly report configured baudrate value
+    - xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in
+      xfrm_bundle_lookup()
+    - power/reset: arm-versatile: Fix refcount leak in versatile_reboot_probe
+    - pinctrl: ralink: Check for null return of devm_kcalloc
+    - perf/core: Fix data race between perf_event_set_output() and
+      perf_mmap_close()
+    - igc: Reinstate IGC_REMOVED logic and implement it properly
+    - ip: Fix data-races around sysctl_ip_no_pmtu_disc.
+    - ip: Fix data-races around sysctl_ip_fwd_use_pmtu.
+    - ip: Fix data-races around sysctl_ip_nonlocal_bind.
+    - ip: Fix a data-race around sysctl_fwmark_reflect.
+    - tcp/dccp: Fix a data-race around sysctl_tcp_fwmark_accept.
+    - tcp: Fix data-races around sysctl_tcp_mtu_probing.
+    - tcp: Fix data-races around sysctl_tcp_base_mss.
+    - tcp: Fix data-races around sysctl_tcp_min_snd_mss.
+    - tcp: Fix a data-race around sysctl_tcp_mtu_probe_floor.
+    - tcp: Fix a data-race around sysctl_tcp_probe_threshold.
+    - tcp: Fix a data-race around sysctl_tcp_probe_interval.
+    - i2c: cadence: Change large transfer count reset logic to be unconditional
+    - net: stmmac: fix dma queue left shift overflow issue
+    - net/tls: Fix race in TLS device down flow
+    - igmp: Fix data-races around sysctl_igmp_llm_reports.
+    - igmp: Fix a data-race around sysctl_igmp_max_memberships.
+    - tcp: Fix data-races around sysctl_tcp_syncookies.
+    - tcp: Fix data-races around sysctl_tcp_reordering.
+    - tcp: Fix data-races around some timeout sysctl knobs.
+    - tcp: Fix a data-race around sysctl_tcp_notsent_lowat.
+    - tcp: Fix a data-race around sysctl_tcp_tw_reuse.
+    - tcp: Fix data-races around sysctl_max_syn_backlog.
+    - tcp: Fix data-races around sysctl_tcp_fastopen.
+    - iavf: Fix handling of dummy receive descriptors
+    - i40e: Fix erroneous adapter reinitialization during recovery process
+    - ixgbe: Add locking to prevent panic when setting sriov_numvfs to zero
+    - gpio: pca953x: only use single read/write for No AI mode
+    - be2net: Fix buffer overflow in be_get_module_eeprom
+    - ipv4: Fix a data-race around sysctl_fib_multipath_use_neigh.
+    - udp: Fix a data-race around sysctl_udp_l3mdev_accept.
+    - tcp: Fix data-races around sysctl knobs related to SYN option.
+    - tcp: Fix a data-race around sysctl_tcp_early_retrans.
+    - tcp: Fix data-races around sysctl_tcp_recovery.
+    - tcp: Fix a data-race around sysctl_tcp_thin_linear_timeouts.
+    - tcp: Fix data-races around sysctl_tcp_slow_start_after_idle.
+    - tcp: Fix a data-race around sysctl_tcp_retrans_collapse.
+    - tcp: Fix a data-race around sysctl_tcp_stdurg.
+    - tcp: Fix a data-race around sysctl_tcp_rfc1337.
+    - tcp: Fix data-races around sysctl_tcp_max_reordering.
+    - spi: bcm2835: bcm2835_spi_handle_err(): fix NULL pointer deref for non DMA
+      transfers
+    - mm/mempolicy: fix uninit-value in mpol_rebind_policy()
+    - bpf: Make sure mac_header was set before using it
+    - dlm: fix pending remove if msg allocation fails
+    - ima: remove the IMA_TEMPLATE Kconfig option
+    - [Config] updateconfigs for IMA_TEMPLATE
+    - locking/refcount: Define constants for saturation and max refcount values
+    - locking/refcount: Ensure integer operands are treated as signed
+    - locking/refcount: Remove unused refcount_*_checked() variants
+    - locking/refcount: Move the bulk of the REFCOUNT_FULL implementation into the
+      <linux/refcount.h> header
+    - locking/refcount: Improve performance of generic REFCOUNT_FULL code
+    - locking/refcount: Move saturation warnings out of line
+    - locking/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
+    - locking/refcount: Consolidate implementations of refcount_t
+    - [Config] updateconfigs for REFCOUNT_FULL
+    - x86: get rid of small constant size cases in raw_copy_{to,from}_user()
+    - x86/uaccess: Implement macros for CMPXCHG on user addresses
+    - mmap locking API: initial implementation as rwsem wrappers
+    - x86/mce: Deduplicate exception handling
+    - bitfield.h: Fix "type of reg too small for mask" test
+    - ALSA: memalloc: Align buffer allocations in page size
+    - Bluetooth: Add bt_skb_sendmsg helper
+    - Bluetooth: Add bt_skb_sendmmsg helper
+    - Bluetooth: SCO: Replace use of memcpy_from_msg with bt_skb_sendmsg
+    - Bluetooth: RFCOMM: Replace use of memcpy_from_msg with bt_skb_sendmmsg
+    - Bluetooth: Fix passing NULL to PTR_ERR
+    - Bluetooth: SCO: Fix sco_send_frame returning skb->len
+    - Bluetooth: Fix bt_skb_sendmmsg not allocating partial chunks
+    - tty: drivers/tty/, stop using tty_schedule_flip()
+    - tty: the rest, stop using tty_schedule_flip()
+    - tty: drop tty_schedule_flip()
+    - tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
+    - tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
+    - x86: drop bogus "cc" clobber from __try_cmpxchg_user_asm()
+    - Linux 5.4.208
+  * Focal update: v5.4.207 upstream stable release (LP: #1988219)
+    - ALSA: hda - Add fixup for Dell Latitidue E5430
+    - ALSA: hda/conexant: Apply quirk for another HP ProDesk 600 G3 model
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc221
+    - ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop
+    - xen/netback: avoid entering xenvif_rx_next_skb() with an empty rx queue
+    - tracing/histograms: Fix memory leak problem
+    - net: sock: tracing: Fix sock_exceed_buf_limit not to dereference stale
+      pointer
+    - ip: fix dflt addr selection for connected nexthop
+    - ARM: 9213/1: Print message about disabled Spectre workarounds only once
+    - ARM: 9214/1: alignment: advance IT state after emulating Thumb instruction
+    - wifi: mac80211: fix queue selection for mesh/OCB interfaces
+    - cgroup: Use separate src/dst nodes when preloading css_sets for migration
+    - drm/panfrost: Fix shrinker list corruption by madvise IOCTL
+    - nilfs2: fix incorrect masking of permission flags for symlinks
+    - Revert "evm: Fix memleak in init_desc"
+    - sched/rt: Disable RT_RUNTIME_SHARE by default
+    - ext4: fix race condition between ext4_write and ext4_convert_inline_data
+    - ARM: dts: imx6qdl-ts7970: Fix ngpio typo and count
+    - ARM: 9209/1: Spectre-BHB: avoid pr_info() every time a CPU comes out of idle
+    - ARM: 9210/1: Mark the FDT_FIXED sections as shareable
+    - drm/i915: fix a possible refcount leak in intel_dp_add_mst_connector()
+    - ima: Fix a potential integer overflow in ima_appraise_measurement
+    - ASoC: sgtl5000: Fix noise on shutdown/remove
+    - net: stmmac: dwc-qos: Disable split header for Tegra194
+    - inetpeer: Fix data-races around sysctl.
+    - net: Fix data-races around sysctl_mem.
+    - cipso: Fix data-races around sysctl.
+    - icmp: Fix data-races around sysctl.
+    - ipv4: Fix a data-race around sysctl_fib_sync_mem.
+    - ARM: dts: at91: sama5d2: Fix typo in i2s1 node
+    - ARM: dts: sunxi: Fix SPI NOR campatible on Orange Pi Zero
+    - drm/i915/gt: Serialize TLB invalidates with GT resets
+    - icmp: Fix a data-race around sysctl_icmp_ratelimit.
+    - icmp: Fix a data-race around sysctl_icmp_ratemask.
+    - raw: Fix a data-race around sysctl_raw_l3mdev_accept.
+    - ipv4: Fix data-races around sysctl_ip_dynaddr.
+    - net: ftgmac100: Hold reference returned by of_get_child_by_name()
+    - sfc: fix use after free when disabling sriov
+    - seg6: fix skb checksum evaluation in SRH encapsulation/insertion
+    - seg6: fix skb checksum in SRv6 End.B6 and End.B6.Encaps behaviors
+    - seg6: bpf: fix skb checksum in bpf_push_seg6_encap()
+    - sfc: fix kernel panic when creating VF
+    - mm: sysctl: fix missing numa_stat when !CONFIG_HUGETLB_PAGE
+    - virtio_mmio: Add missing PM calls to freeze/restore
+    - virtio_mmio: Restore guest page size on resume
+    - netfilter: br_netfilter: do not skip all hooks with 0 priority
+    - cpufreq: pmac32-cpufreq: Fix refcount leak bug
+    - platform/x86: hp-wmi: Ignore Sanitization Mode event
+    - net: tipc: fix possible refcount leak in tipc_sk_create()
+    - NFC: nxp-nci: don't print header length mismatch on i2c error
+    - nvme: fix regression when disconnect a recovering ctrl
+    - net: sfp: fix memory leak in sfp_probe()
+    - ASoC: ops: Fix off by one in range control validation
+    - ASoC: wm5110: Fix DRE control
+    - ASoC: cs47l15: Fix event generation for low power mux control
+    - ASoC: madera: Fix event generation for OUT1 demux
+    - ASoC: madera: Fix event generation for rate controls
+    - irqchip: or1k-pic: Undefine mask_ack for level triggered hardware
+    - x86: Clear .brk area at early boot
+    - soc: ixp4xx/npe: Fix unused match warning
+    - ARM: dts: stm32: use the correct clock source for CEC on stm32mp151
+    - signal handling: don't use BUG_ON() for debugging
+    - USB: serial: ftdi_sio: add Belimo device ids
+    - usb: typec: add missing uevent when partner support PD
+    - usb: dwc3: gadget: Fix event pending check
+    - tty: serial: samsung_tty: set dma burst_size to 1
+    - serial: 8250: fix return error code in serial8250_request_std_resource()
+    - serial: stm32: Clear prev values before setting RTS delays
+    - serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle
+    - can: m_can: m_can_tx_handler(): fix use after free of skb
+    - Linux 5.4.207
+  * Focal update: v5.4.206 upstream stable release (LP: #1988215)
+    - Linux 5.4.206
+  * Focal update: v5.4.205 upstream stable release (LP: #1988214)
+    - esp: limit skb_page_frag_refill use to a single page
+    - mm/slub: add missing TID updates on slab deactivation
+    - can: bcm: use call_rcu() instead of costly synchronize_rcu()
+    - can: grcan: grcan_probe(): remove extra of_node_get()
+    - can: gs_usb: gs_usb_open/close(): fix memory leak
+    - usbnet: fix memory leak in error case
+    - net: rose: fix UAF bug caused by rose_t0timer_expiry
+    - iommu/vt-d: Fix PCI bus rescan device hot add
+    - fbdev: fbmem: Fix logo center image dx issue
+    - video: of_display_timing.h: include errno.h
+    - powerpc/powernv: delay rng platform device creation until later in boot
+    - can: kvaser_usb: replace run-time checks with struct kvaser_usb_driver_info
+    - can: kvaser_usb: kvaser_usb_leaf: fix CAN clock frequency regression
+    - can: kvaser_usb: kvaser_usb_leaf: fix bittiming limits
+    - xfs: remove incorrect ASSERT in xfs_rename
+    - ARM: meson: Fix refcount leak in meson_smp_prepare_cpus
+    - pinctrl: sunxi: a83t: Fix NAND function name for some pins
+    - pinctrl: sunxi: sunxi_pconf_set: use correct offset
+    - ARM: at91: pm: use proper compatible for sama5d2's rtc
+    - ARM: at91: pm: use proper compatibles for sam9x60's rtc and rtt
+    - ibmvnic: Properly dispose of all skbs during a failover.
+    - selftests: forwarding: fix flood_unicast_test when h2 supports
+      IFF_UNICAST_FLT
+    - selftests: forwarding: fix learning_test when h1 supports IFF_UNICAST_FLT
+    - selftests: forwarding: fix error message in learning_test
+    - i2c: cadence: Unregister the clk notifier in error path
+    - dmaengine: imx-sdma: Allow imx8m for imx7 FW revs
+    - misc: rtsx_usb: fix use of dma mapped buffer for usb bulk transfer
+    - misc: rtsx_usb: use separate command and response buffers
+    - misc: rtsx_usb: set return value in rsp_buf alloc err path
+    - dt-bindings: dma: allwinner,sun50i-a64-dma: Fix min/max typo
+    - ida: don't use BUG_ON() for debugging
+    - dmaengine: pl330: Fix lockdep warning about non-static key
+    - dmaengine: at_xdma: handle errors of at_xdmac_alloc_desc() correctly
+    - dmaengine: ti: Fix refcount leak in ti_dra7_xbar_route_allocate
+    - dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate
+    - Linux 5.4.205
+  * Focal update: v5.4.204 upstream stable release (LP: #1988212)
+    - ipv6: take care of disable_policy when restoring routes
+    - nvdimm: Fix badblocks clear off-by-one error
+    - powerpc/prom_init: Fix kernel config grep
+    - powerpc/bpf: Fix use of user_pt_regs in uapi
+    - dm raid: fix accesses beyond end of raid member array
+    - dm raid: fix KASAN warning in raid5_add_disks
+    - s390/archrandom: simplify back to earlier design and initialize earlier
+    - SUNRPC: Fix READ_PLUS crasher
+    - net: rose: fix UAF bugs caused by timer handler
+    - net: usb: ax88179_178a: Fix packet receiving
+    - virtio-net: fix race between ndo_open() and virtio_device_ready()
+    - selftests/net: pass ipv6_args to udpgso_bench's IPv6 TCP test
+    - net: tun: unlink NAPI from device on destruction
+    - net: tun: stop NAPI when detaching queues
+    - RDMA/qedr: Fix reporting QP timeout attribute
+    - linux/dim: Fix divide by 0 in RDMA DIM
+    - usbnet: fix memory allocation in helpers
+    - net: ipv6: unexport __init-annotated seg6_hmac_net_init()
+    - caif_virtio: fix race between virtio_device_ready() and ndo_open()
+    - PM / devfreq: exynos-ppmu: Fix refcount leak in of_get_devfreq_events
+    - s390: remove unneeded 'select BUILD_BIN2C'
+    - netfilter: nft_dynset: restore set element counter when failing to update
+    - net/sched: act_api: Notify user space if any actions were flushed before
+      error
+    - net: bonding: fix possible NULL deref in rlb code
+    - net: bonding: fix use-after-free after 802.3ad slave unbind
+    - nfc: nfcmrvl: Fix irq_of_parse_and_map() return value
+    - NFC: nxp-nci: Don't issue a zero length i2c_master_read()
+    - net: tun: avoid disabling NAPI twice
+    - xen/gntdev: Avoid blocking in unmap_grant_pages()
+    - hwmon: (ibmaem) don't call platform_device_del() if platform_device_add()
+      fails
+    - net: dsa: bcm_sf2: force pause link settings
+    - sit: use min
+    - ipv6/sit: fix ipip6_tunnel_get_prl return value
+    - rseq/selftests,x86_64: Add rseq_offset_deref_addv()
+    - selftests/rseq: remove ARRAY_SIZE define from individual tests
+    - selftests/rseq: introduce own copy of rseq uapi header
+    - selftests/rseq: Remove useless assignment to cpu variable
+    - selftests/rseq: Remove volatile from __rseq_abi
+    - selftests/rseq: Introduce rseq_get_abi() helper
+    - selftests/rseq: Introduce thread pointer getters
+    - selftests/rseq: Uplift rseq selftests for compatibility with glibc-2.35
+    - selftests/rseq: Fix ppc32: wrong rseq_cs 32-bit field pointer on big endian
+    - selftests/rseq: Fix ppc32 missing instruction selection "u" and "x" for
+      load/store
+    - selftests/rseq: Fix ppc32 offsets by using long rather than off_t
+    - selftests/rseq: Fix warnings about #if checks of undefined tokens
+    - selftests/rseq: Remove arm/mips asm goto compiler work-around
+    - selftests/rseq: Fix: work-around asm goto compiler bugs
+    - selftests/rseq: x86-64: use %fs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: x86-32: use %gs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: Change type of rseq_offset to ptrdiff_t
+    - xen/blkfront: fix leaking data in shared pages
+    - xen/netfront: fix leaking data in shared pages
+    - xen/netfront: force data bouncing when backend is untrusted
+    - xen/blkfront: force data bouncing when backend is untrusted
+    - xen/arm: Fix race in RB-tree based P2M accounting
+    - net: usb: qmi_wwan: add Telit 0x1060 composition
+    - net: usb: qmi_wwan: add Telit 0x1070 composition
+    - clocksource/drivers/ixp4xx: remove EXPORT_SYMBOL_GPL from
+      ixp4xx_timer_setup()
+    - Linux 5.4.204
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 09 Nov 2022 19:19:19 +0800
+
+linux-imx (5.4.0-1027.33) focal; urgency=medium
+
+  * [K4500-NXP] Update the device tree to load Vivante graphics drivers (LP:
+    #1990021)
+    - arm64: dts: imx8mm: Add GPU nodes for 2D and 3D core
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove gpu node now at the imx8mm.dtsi
+      contains gpu nodes.
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 03 Oct 2022 18:15:38 +0800
+
+linux-imx (5.4.0-1026.32) focal; urgency=medium
+
+  * Focal update: v5.4.198 upstream stable release (LP: #1982409)
+    - PCI: imx6: Fix PERST# start-up sequence
+
+  * [US20.04[UC20] RPMSG driver support (LP: #1968362)
+    - SAUCE: ARM: imx: Add M4 rpmsg module that allows applications to send and
+      request data to and from the M4.
+    - [Config] Set CONFIG_RPMSG_AMGIS_M4_DEVICES=m for armhf
+
+  * [K4500-NXP][UC20] Snap for testing HSM chip (LP: #1984131)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Swap i2c-1 and i2c-2 buses for STSAFE
+      TPM compatibility with RPI platform.
+
+  * [K4500-NXP] Set GPIO defaults for WIFI_ENABLE and CELL_MODEM_RESET (LP:
+    #1990059)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Set GPIO defaults for WIFI_ENABLE and
+      CELL_MODEM_RESET
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Delete user_gpio and tmp103 nodes to
+      disable kernel boot warnings
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Device tree cleanup and correction of
+      CMA size.
+
+  * Miscellaneous upstream changes
+    - LF-1235 clk: imx: Revert the changes for pll pfd gate clock
+
+  [ Ubuntu: 5.4.0-126.142 ]
+
+  * focal/linux: 5.4.0-126.142 -proposed tracker (LP: #1987819)
+  * [SRU] fnic driver on needs to be updated to 1.6.0.53 on Focal (LP: #1984011)
+    - scsi: fnic: Change shost_printk() to FNIC_FCS_DBG()
+    - scsi: fnic: Avoid looping in TRANS ETH on unload
+    - scsi: fnic: Change shost_printk() to FNIC_MAIN_DBG()
+    - scsi: fnic: Set scsi_set_resid() only for underflow
+    - scsi: fnic: Validate io_req before others
+  * Focal update: v5.4.203 upstream stable release (LP: #1986999)
+    - drm: remove drm_fb_helper_modinit
+    - powerpc/ftrace: Remove ftrace init tramp once kernel init is complete
+    - kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add]
+    - net: mscc: ocelot: allow unregistered IP multicast flooding
+    - ARM: 8989/1: use .fpu assembler directives instead of assembler arguments
+    - ARM: 8990/1: use VFP assembler mnemonics in register load/store macros
+    - ARM: 8971/1: replace the sole use of a symbol with its definition
+    - crypto: arm/sha256-neon - avoid ADRL pseudo instruction
+    - crypto: arm/sha512-neon - avoid ADRL pseudo instruction
+    - ARM: 8933/1: replace Sun/Solaris style flag on section directive
+    - ARM: 8929/1: use APSR_nzcv instead of r15 as mrc operand
+    - ARM: OMAP2+: drop unnecessary adrl
+    - ARM: 9029/1: Make iwmmxt.S support Clang's integrated assembler
+    - crypto: arm - use Kconfig based compiler checks for crypto opcodes
+    - crypto: arm/ghash-ce - define fpu before fpu registers are referenced
+    - Linux 5.4.203
+  * Focal update: v5.4.202 upstream stable release (LP: #1986995)
+    - random: schedule mix_interrupt_randomness() less often
+    - ALSA: hda/via: Fix missing beep setup
+    - ALSA: hda/conexant: Fix missing beep setup
+    - ALSA: hda/realtek - ALC897 headset MIC no sound
+    - ALSA: hda/realtek: Add quirk for Clevo PD70PNT
+    - net: openvswitch: fix parsing of nw_proto for IPv6 fragments
+    - mmc: sdhci-pci-o2micro: Fix card detect by dealing with debouncing
+    - ata: libata: add qc->flags in ata_qc_complete_template tracepoint
+    - dm era: commit metadata in postsuspend after worker stops
+    - dm mirror log: clear log bits up to BITS_PER_LONG boundary
+    - random: quiet urandom warning ratelimit suppression message
+    - USB: serial: option: add Telit LE910Cx 0x1250 composition
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: option: add Quectel RM500K module support
+    - bpf: Fix request_sock leak in sk lookup helpers
+    - phy: aquantia: Fix AN when higher speeds than 1G are not advertised
+    - bonding: ARP monitor spams NETDEV_NOTIFY_PEERS notifiers
+    - net/sched: sch_netem: Fix arithmetic in netem_dump() for 32-bit platforms
+    - drm/msm/mdp4: Fix refcount leak in mdp4_modeset_init_intf
+    - erspan: do not assume transport header is always set
+    - net/tls: fix tls_sk_proto_close executed repeatedly
+    - udmabuf: add back sanity check
+    - x86/xen: Remove undefined behavior in setup_features()
+    - MIPS: Remove repetitive increase irq_err_count
+    - afs: Fix dynamic root getattr
+    - ice: ethtool: advertise 1000M speeds properly
+    - regmap-irq: Fix a bug in regmap_irq_enable() for type_in_mask chips
+    - igb: Make DMA faster when CPU is active on the PCIe link
+    - virtio_net: fix xdp_rxq_info bug after suspend/resume
+    - Revert "net/tls: fix tls_sk_proto_close executed repeatedly"
+    - gpio: winbond: Fix error code in winbond_gpio_get()
+    - s390/cpumf: Handle events cycles and instructions identical
+    - iio: adc: vf610: fix conversion mode sysfs node name
+    - xhci: turn off port power in shutdown
+    - usb: chipidea: udc: check request status before setting device address
+    - iio:chemical:ccs811: rearrange iio trigger get and register
+    - iio:accel:bma180: rearrange iio trigger get and register
+    - iio:accel:mxc4005: rearrange iio trigger get and register
+    - iio: accel: mma8452: ignore the return value of reset operation
+    - iio: gyro: mpu3050: Fix the error handling in mpu3050_power_up()
+    - iio: trigger: sysfs: fix use-after-free on remove
+    - iio: adc: stm32: fix maximum clock rate for stm32mp15x
+    - iio: adc: axp288: Override TS pin bias current for some models
+    - xtensa: xtfpga: Fix refcount leak bug in setup
+    - xtensa: Fix refcount leak bug in time.c
+    - parisc: Enable ARCH_HAS_STRICT_MODULE_RWX
+    - powerpc: Enable execve syscall exit tracepoint
+    - powerpc/rtas: Allow ibm,platform-dump RTAS call with null buffer address
+    - powerpc/powernv: wire up rng during setup_arch
+    - ARM: dts: imx6qdl: correct PU regulator ramp delay
+    - ARM: exynos: Fix refcount leak in exynos_map_pmu
+    - soc: bcm: brcmstb: pm: pm-arm: Fix refcount leak in brcmstb_pm_probe
+    - ARM: Fix refcount leak in axxia_boot_secondary
+    - ARM: cns3xxx: Fix refcount leak in cns3xxx_init
+    - modpost: fix section mismatch check for exported init/exit sections
+    - random: update comment from copy_to_user() -> copy_to_iter()
+    - kbuild: link vmlinux only once for CONFIG_TRIM_UNUSED_KSYMS (2nd attempt)
+    - powerpc/pseries: wire up rng during setup_arch()
+    - Linux 5.4.202
+  * Focal update: v5.4.201 upstream stable release (LP: #1986993)
+    - dm: remove special-casing of bio-based immutable singleton target on NVMe
+    - usb: gadget: u_ether: fix regression in setting fixed MAC address
+    - tcp: add some entropy in __inet_hash_connect()
+    - tcp: use different parts of the port_offset for index and offset
+    - tcp: add small random increments to the source port
+    - tcp: dynamically allocate the perturb table used by source ports
+    - tcp: increase source port perturb table to 2^16
+    - tcp: drop the hash_32() part from the index calculation
+    - arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer
+    - Linux 5.4.201
+  * Focal update: v5.4.200 upstream stable release (LP: #1983152)
+    - Revert "UBUNTU: SAUCE: random: Make getrandom() ready earlier"
+    - 9p: missing chunk of "fs/9p: Don't update file type when updating file
+      attributes"
+    - bpf: Fix incorrect memory charge cost calculation in stack_map_alloc()
+    - nfc: st21nfca: fix incorrect sizing calculations in EVT_TRANSACTION
+    - crypto: blake2s - generic C library implementation and selftest
+    - lib/crypto: blake2s: move hmac construction into wireguard
+    - lib/crypto: sha1: re-roll loops to reduce code size
+    - compat_ioctl: remove /dev/random commands
+    - random: don't forget compat_ioctl on urandom
+    - random: Don't wake crng_init_wait when crng_init == 1
+    - random: Add a urandom_read_nowait() for random APIs that don't warn
+    - random: add GRND_INSECURE to return best-effort non-cryptographic bytes
+    - random: ignore GRND_RANDOM in getentropy(2)
+    - random: make /dev/random be almost like /dev/urandom
+    - random: remove the blocking pool
+    - random: delete code to pull data into pools
+    - random: remove kernel.random.read_wakeup_threshold
+    - random: remove unnecessary unlikely()
+    - random: convert to ENTROPY_BITS for better code readability
+    - random: Add and use pr_fmt()
+    - random: fix typo in add_timer_randomness()
+    - random: remove some dead code of poolinfo
+    - random: split primary/secondary crng init paths
+    - random: avoid warnings for !CONFIG_NUMA builds
+    - x86: Remove arch_has_random, arch_has_random_seed
+    - powerpc: Remove arch_has_random, arch_has_random_seed
+    - s390: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Use false with bool
+    - linux/random.h: Mark CONFIG_ARCH_RANDOM functions __must_check
+    - powerpc: Use bool in archrandom.h
+    - random: add arch_get_random_*long_early()
+    - random: avoid arch_get_random_seed_long() when collecting IRQ randomness
+    - random: remove dead code left over from blocking pool
+    - MAINTAINERS: co-maintain random.c
+    - crypto: blake2s - include <linux/bug.h> instead of <asm/bug.h>
+    - crypto: blake2s - adjust include guard naming
+    - random: document add_hwgenerator_randomness() with other input functions
+    - random: remove unused irq_flags argument from add_interrupt_randomness()
+    - random: use BLAKE2s instead of SHA1 in extraction
+    - random: do not sign extend bytes for rotation when mixing
+    - random: do not re-init if crng_reseed completes before primary init
+    - random: mix bootloader randomness into pool
+    - random: harmonize "crng init done" messages
+    - random: use IS_ENABLED(CONFIG_NUMA) instead of ifdefs
+    - random: initialize ChaCha20 constants with correct endianness
+    - random: early initialization of ChaCha constants
+    - random: avoid superfluous call to RDRAND in CRNG extraction
+    - random: don't reset crng_init_cnt on urandom_read()
+    - random: fix typo in comments
+    - random: cleanup poolinfo abstraction
+    - random: cleanup integer types
+    - random: remove incomplete last_data logic
+    - random: remove unused extract_entropy() reserved argument
+    - random: rather than entropy_store abstraction, use global
+    - random: remove unused OUTPUT_POOL constants
+    - random: de-duplicate INPUT_POOL constants
+    - random: prepend remaining pool constants with POOL_
+    - random: cleanup fractional entropy shift constants
+    - random: access input_pool_data directly rather than through pointer
+    - random: selectively clang-format where it makes sense
+    - random: simplify arithmetic function flow in account()
+    - random: continually use hwgenerator randomness
+    - random: access primary_pool directly rather than through pointer
+    - random: only call crng_finalize_init() for primary_crng
+    - random: use computational hash for entropy extraction
+    - random: simplify entropy debiting
+    - random: use linear min-entropy accumulation crediting
+    - random: always wake up entropy writers after extraction
+    - random: make credit_entropy_bits() always safe
+    - random: remove use_input_pool parameter from crng_reseed()
+    - random: remove batched entropy locking
+    - random: fix locking in crng_fast_load()
+    - random: use RDSEED instead of RDRAND in entropy extraction
+    - random: get rid of secondary crngs
+    - random: inline leaves of rand_initialize()
+    - random: ensure early RDSEED goes through mixer on init
+    - random: do not xor RDRAND when writing into /dev/random
+    - random: absorb fast pool into input pool after fast load
+    - random: use simpler fast key erasure flow on per-cpu keys
+    - random: use hash function for crng_slow_load()
+    - random: make more consistent use of integer types
+    - random: remove outdated INT_MAX >> 6 check in urandom_read()
+    - random: zero buffer after reading entropy from userspace
+    - random: fix locking for crng_init in crng_reseed()
+    - random: tie batched entropy generation to base_crng generation
+    - random: remove ifdef'd out interrupt bench
+    - random: remove unused tracepoints
+    - random: add proper SPDX header
+    - random: deobfuscate irq u32/u64 contributions
+    - random: introduce drain_entropy() helper to declutter crng_reseed()
+    - random: remove useless header comment
+    - random: remove whitespace and reorder includes
+    - random: group initialization wait functions
+    - random: group crng functions
+    - random: group entropy extraction functions
+    - random: group entropy collection functions
+    - random: group userspace read/write functions
+    - random: group sysctl functions
+    - random: rewrite header introductory comment
+    - random: defer fast pool mixing to worker
+    - random: do not take pool spinlock at boot
+    - random: unify early init crng load accounting
+    - random: check for crng_init == 0 in add_device_randomness()
+    - random: pull add_hwgenerator_randomness() declaration into random.h
+    - random: clear fast pool, crng, and batches in cpuhp bring up
+    - random: round-robin registers as ulong, not u32
+    - random: only wake up writers after zap if threshold was passed
+    - random: cleanup UUID handling
+    - random: unify cycles_t and jiffies usage and types
+    - random: do crng pre-init loading in worker rather than irq
+    - random: give sysctl_random_min_urandom_seed a more sensible value
+    - random: don't let 644 read-only sysctls be written to
+    - random: replace custom notifier chain with standard one
+    - random: use SipHash as interrupt entropy accumulator
+    - random: make consistent usage of crng_ready()
+    - random: reseed more often immediately after booting
+    - random: check for signal and try earlier when generating entropy
+    - random: skip fast_init if hwrng provides large chunk of entropy
+    - random: treat bootloader trust toggle the same way as cpu trust toggle
+    - random: re-add removed comment about get_random_{u32,u64} reseeding
+    - random: mix build-time latent entropy into pool at init
+    - random: do not split fast init input in add_hwgenerator_randomness()
+    - random: do not allow user to keep crng key around on stack
+    - random: check for signal_pending() outside of need_resched() check
+    - random: check for signals every PAGE_SIZE chunk of /dev/[u]random
+    - random: allow partial reads if later user copies fail
+    - random: make random_get_entropy() return an unsigned long
+    - random: document crng_fast_key_erasure() destination possibility
+    - random: fix sysctl documentation nits
+    - init: call time_init() before rand_initialize()
+    - ia64: define get_cycles macro for arch-override
+    - s390: define get_cycles macro for arch-override
+    - parisc: define get_cycles macro for arch-override
+    - alpha: define get_cycles macro for arch-override
+    - powerpc: define get_cycles macro for arch-override
+    - timekeeping: Add raw clock fallback for random_get_entropy()
+    - m68k: use fallback for random_get_entropy() instead of zero
+    - mips: use fallback for random_get_entropy() instead of just c0 random
+    - arm: use fallback for random_get_entropy() instead of zero
+    - nios2: use fallback for random_get_entropy() instead of zero
+    - x86/tsc: Use fallback for random_get_entropy() instead of zero
+    - um: use fallback for random_get_entropy() instead of zero
+    - sparc: use fallback for random_get_entropy() instead of zero
+    - xtensa: use fallback for random_get_entropy() instead of zero
+    - random: insist on random_get_entropy() existing in order to simplify
+    - random: do not use batches when !crng_ready()
+    - random: use first 128 bits of input as fast init
+    - random: do not pretend to handle premature next security model
+    - random: order timer entropy functions below interrupt functions
+    - random: do not use input pool from hard IRQs
+    - random: help compiler out with fast_mix() by using simpler arguments
+    - siphash: use one source of truth for siphash permutations
+    - random: use symbolic constants for crng_init states
+    - random: avoid initializing twice in credit race
+    - random: move initialization out of reseeding hot path
+    - random: remove ratelimiting for in-kernel unseeded randomness
+    - random: use proper jiffies comparison macro
+    - random: handle latent entropy and command line from random_init()
+    - random: credit architectural init the exact amount
+    - random: use static branch for crng_ready()
+    - random: remove extern from functions in header
+    - random: use proper return types on get_random_{int,long}_wait()
+    - random: make consistent use of buf and len
+    - random: move initialization functions out of hot pages
+    - random: move randomize_page() into mm where it belongs
+    - random: unify batched entropy implementations
+    - random: convert to using fops->read_iter()
+    - random: convert to using fops->write_iter()
+    - random: wire up fops->splice_{read,write}_iter()
+    - random: check for signals after page of pool writes
+    - Revert "random: use static branch for crng_ready()"
+    - crypto: drbg - always seeded with SP800-90B compliant noise source
+    - crypto: drbg - prepare for more fine-grained tracking of seeding state
+    - crypto: drbg - track whether DRBG was seeded with !rng_is_initialized()
+    - crypto: drbg - move dynamic ->reseed_threshold adjustments to __drbg_seed()
+    - crypto: drbg - always try to free Jitter RNG instance
+    - crypto: drbg - make reseeding from get_random_bytes() synchronous
+    - random: avoid checking crng_ready() twice in random_init()
+    - random: mark bootloader randomness code as __init
+    - random: account for arch randomness in bits
+    - powerpc/kasan: Silence KASAN warnings in __get_wchan()
+    - ASoC: nau8822: Add operation for internal PLL off and on
+    - dma-debug: make things less spammy under memory pressure
+    - ASoC: cs42l52: Fix TLV scales for mixer controls
+    - ASoC: cs35l36: Update digital volume TLV
+    - ASoC: cs53l30: Correct number of volume levels on SX controls
+    - ASoC: cs42l52: Correct TLV for Bypass Volume
+    - ASoC: cs42l56: Correct typo in minimum level for SX volume controls
+    - ata: libata-core: fix NULL pointer deref in ata_host_alloc_pinfo()
+    - ASoC: wm8962: Fix suspend while playing music
+    - ASoC: es8328: Fix event generation for deemphasis control
+    - ASoC: wm_adsp: Fix event generation for wm_adsp_fw_put()
+    - scsi: vmw_pvscsi: Expand vcpuHint to 16 bits
+    - scsi: lpfc: Fix port stuck in bypassed state after LIP in PT2PT topology
+    - scsi: lpfc: Allow reduced polling rate for nvme_admin_async_event cmd
+      completion
+    - scsi: ipr: Fix missing/incorrect resource cleanup in error case
+    - scsi: pmcraid: Fix missing resource cleanup in error case
+    - ALSA: hda/realtek - Add HW8326 support
+    - virtio-mmio: fix missing put_device() when vm_cmdline_parent registration
+      failed
+    - nfc: nfcmrvl: Fix memory leak in nfcmrvl_play_deferred
+    - ipv6: Fix signed integer overflow in l2tp_ip6_sendmsg
+    - net: ethernet: mtk_eth_soc: fix misuse of mem alloc interface
+      netdev[napi]_alloc_frag
+    - random: credit cpu and bootloader seeds by default
+    - pNFS: Don't keep retrying if the server replied NFS4ERR_LAYOUTUNAVAILABLE
+    - clocksource: hyper-v: unexport __init-annotated hv_init_clocksource()
+    - i40e: Fix adding ADQ filter to TC0
+    - i40e: Fix calculating the number of queue pairs
+    - i40e: Fix call trace in setup_tx_descriptors
+    - tty: goldfish: Fix free_irq() on remove
+    - misc: atmel-ssc: Fix IRQ check in ssc_probe
+    - mlxsw: spectrum_cnt: Reorder counter pools
+    - net: bgmac: Fix an erroneous kfree() in bgmac_remove()
+    - arm64: ftrace: fix branch range checks
+    - certs/blacklist_hashes.c: fix const confusion in certs blacklist
+    - faddr2line: Fix overlapping text section failures, the sequel
+    - irqchip/gic/realview: Fix refcount leak in realview_gic_of_init
+    - irqchip/gic-v3: Fix error handling in gic_populate_ppi_partitions
+    - irqchip/gic-v3: Fix refcount leak in gic_populate_ppi_partitions
+    - i2c: designware: Use standard optional ref clock implementation
+    - comedi: vmk80xx: fix expression for tx buffer size
+    - USB: serial: option: add support for Cinterion MV31 with new baseline
+    - USB: serial: io_ti: add Agilent E5805A support
+    - usb: dwc2: Fix memory leak in dwc2_hcd_init
+    - usb: gadget: lpc32xx_udc: Fix refcount leak in lpc32xx_udc_probe
+    - serial: 8250: Store to lsr_save_flags after lsr read
+    - dm mirror log: round up region bitmap size to BITS_PER_LONG
+    - ext4: fix bug_on ext4_mb_use_inode_pa
+    - ext4: make variable "count" signed
+    - ext4: add reserved GDT blocks check
+    - ALSA: hda/realtek: fix right sounds and mute/micmute LEDs for HP machine
+    - virtio-pci: Remove wrong address verification in vp_del_vqs()
+    - net/sched: act_police: more accurate MTU policing
+    - net: openvswitch: fix leak of nested actions
+    - arm64: kprobes: Use BRK instead of single-step when executing instructions
+      out-of-line
+    - RISC-V: fix barrier() use in <vdso/processor.h>
+    - riscv: Less inefficient gcc tishift helpers (and export their symbols)
+    - powerpc/mm: Switch obsolete dssall to .long
+    - Linux 5.4.200
+  * Focal update: v5.4.199 upstream stable release (LP: #1983150)
+    - Linux 5.4.199
+  * Focal update: v5.4.198 upstream stable release (LP: #1982409)
+    - binfmt_flat: do not stop relocating GOT entries prematurely on riscv
+    - ALSA: hda/realtek - Fix microphone noise on ASUS TUF B550M-PLUS
+    - USB: serial: option: add Quectel BG95 modem
+    - USB: new quirk for Dell Gen 2 devices
+    - perf/x86/intel: Fix event constraints for ICL
+    - ptrace/um: Replace PT_DTRACE with TIF_SINGLESTEP
+    - ptrace/xtensa: Replace PT_SINGLESTEP with TIF_SINGLESTEP
+    - ptrace: Reimplement PTRACE_KILL by always sending SIGKILL
+    - btrfs: add "0x" prefix for unsupported optional features
+    - btrfs: repair super block num_devices automatically
+    - drm/virtio: fix NULL pointer dereference in virtio_gpu_conn_get_modes
+    - mwifiex: add mutex lock for call in mwifiex_dfs_chan_sw_work_queue
+    - b43legacy: Fix assigning negative value to unsigned variable
+    - b43: Fix assigning negative value to unsigned variable
+    - ipw2x00: Fix potential NULL dereference in libipw_xmit()
+    - ipv6: fix locking issues with loops over idev->addr_list
+    - fbcon: Consistently protect deferred_takeover with console_lock()
+    - ACPICA: Avoid cache flush inside virtual machines
+    - drm/komeda: return early if drm_universal_plane_init() fails.
+    - ALSA: jack: Access input_dev under mutex
+    - spi: spi-rspi: Remove setting {src,dst}_{addr,addr_width} based on DMA
+      direction
+    - tools/power turbostat: fix ICX DRAM power numbers
+    - drm/amd/pm: fix double free in si_parse_power_table()
+    - ath9k: fix QCA9561 PA bias level
+    - media: venus: hfi: avoid null dereference in deinit
+    - media: pci: cx23885: Fix the error handling in cx23885_initdev()
+    - media: cx25821: Fix the warning when removing the module
+    - md/bitmap: don't set sb values if can't pass sanity check
+    - mmc: jz4740: Apply DMA engine limits to maximum segment size
+    - scsi: megaraid: Fix error check return value of register_chrdev()
+    - drm/plane: Move range check for format_count earlier
+    - drm/amd/pm: fix the compile warning
+    - arm64: compat: Do not treat syscall number as ESR_ELx for a bad syscall
+    - drm: msm: fix error check return value of irq_of_parse_and_map()
+    - ipv6: Don't send rs packets to the interface of ARPHRD_TUNNEL
+    - net/mlx5: fs, delete the FTE when there are no rules attached to it
+    - ASoC: dapm: Don't fold register value changes into notifications
+    - mlxsw: spectrum_dcb: Do not warn about priority changes
+    - drm/amdgpu/ucode: Remove firmware load type check in amdgpu_ucode_free_bo
+    - HID: bigben: fix slab-out-of-bounds Write in bigben_probe
+    - ASoC: tscs454: Add endianness flag in snd_soc_component_driver
+    - s390/preempt: disable __preempt_count_add() optimization for
+      PROFILE_ALL_BRANCHES
+    - spi: stm32-qspi: Fix wait_cmd timeout in APM mode
+    - dma-debug: change allocation mode from GFP_NOWAIT to GFP_ATIOMIC
+    - ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default
+    - ipmi:ssif: Check for NULL msg when handling events and messages
+    - ipmi: Fix pr_fmt to avoid compilation issues
+    - rtlwifi: Use pr_warn instead of WARN_ONCE
+    - media: coda: limit frame interval enumeration to supported encoder frame
+      sizes
+    - media: cec-adap.c: fix is_configuring state
+    - openrisc: start CPU timer early in boot
+    - nvme-pci: fix a NULL pointer dereference in nvme_alloc_admin_tags
+    - ASoC: rt5645: Fix errorenous cleanup order
+    - nbd: Fix hung on disconnect request if socket is closed before
+    - net: phy: micrel: Allow probing without .driver_data
+    - media: exynos4-is: Fix compile warning
+    - ASoC: max98357a: remove dependency on GPIOLIB
+    - rxrpc: Return an error to sendmsg if call failed
+    - eth: tg3: silence the GCC 12 array-bounds warning
+    - selftests/bpf: fix btf_dump/btf_dump due to recent clang change
+    - IB/rdmavt: add missing locks in rvt_ruc_loopback
+    - ARM: dts: ox820: align interrupt controller node name with dtschema
+    - PM / devfreq: rk3399_dmc: Disable edev on remove()
+    - fs: jfs: fix possible NULL pointer dereference in dbFree()
+    - ARM: OMAP1: clock: Fix UART rate reporting algorithm
+    - powerpc/fadump: Fix fadump to work with a different endian capture kernel
+    - fat: add ratelimit to fat*_ent_bread()
+    - ARM: versatile: Add missing of_node_put in dcscb_init
+    - ARM: dts: exynos: add atmel,24c128 fallback to Samsung EEPROM
+    - ARM: hisi: Add missing of_node_put after of_find_compatible_node
+    - PCI: Avoid pci_dev_lock() AB/BA deadlock with sriov_numvfs_store()
+    - tracing: incorrect isolate_mote_t cast in mm_vmscan_lru_isolate
+    - powerpc/xics: fix refcount leak in icp_opal_init()
+    - powerpc/powernv: fix missing of_node_put in uv_init()
+    - macintosh/via-pmu: Fix build failure when CONFIG_INPUT is disabled
+    - powerpc/iommu: Add missing of_node_put in iommu_init_early_dart
+    - RDMA/hfi1: Prevent panic when SDMA is disabled
+    - drm: fix EDID struct for old ARM OABI format
+    - ath9k: fix ar9003_get_eepmisc
+    - drm/edid: fix invalid EDID extension block filtering
+    - drm/bridge: adv7511: clean up CEC adapter when probe fails
+    - ASoC: mediatek: Fix error handling in mt8173_max98090_dev_probe
+    - ASoC: mediatek: Fix missing of_node_put in mt2701_wm8960_machine_probe
+    - x86/delay: Fix the wrong asm constraint in delay_loop()
+    - drm/mediatek: Fix mtk_cec_mask()
+    - drm/vc4: txp: Don't set TXP_VSTART_AT_EOF
+    - drm/vc4: txp: Force alpha to be 0xff if it's disabled
+    - bpf: Fix excessive memory allocation in stack_map_alloc()
+    - nl80211: show SSID for P2P_GO interfaces
+    - drm/komeda: Fix an undefined behavior bug in komeda_plane_add()
+    - drm: mali-dp: potential dereference of null pointer
+    - spi: spi-ti-qspi: Fix return value handling of wait_for_completion_timeout
+    - NFC: NULL out the dev->rfkill to prevent UAF
+    - efi: Add missing prototype for efi_capsule_setup_info
+    - drbd: fix duplicate array initializer
+    - HID: hid-led: fix maximum brightness for Dream Cheeky
+    - HID: elan: Fix potential double free in elan_input_configured
+    - drm/bridge: Fix error handling in analogix_dp_probe
+    - sched/fair: Fix cfs_rq_clock_pelt() for throttled cfs_rq
+    - spi: img-spfi: Fix pm_runtime_get_sync() error checking
+    - cpufreq: Fix possible race in cpufreq online error path
+    - ath9k_htc: fix potential out of bounds access with invalid
+      rxstatus->rs_keyix
+    - inotify: show inotify mask flags in proc fdinfo
+    - fsnotify: fix wrong lockdep annotations
+    - of: overlay: do not break notify on NOTIFY_{OK|STOP}
+    - scsi: ufs: core: Exclude UECxx from SFR dump list
+    - x86/pm: Fix false positive kmemleak report in msr_build_context()
+    - x86/speculation: Add missing prototype for unpriv_ebpf_notify()
+    - ASoC: rk3328: fix disabling mclk on pclk probe failure
+    - perf tools: Add missing headers needed by util/data.h
+    - drm/msm/disp/dpu1: set vbif hw config to NULL to avoid use after memory free
+      during pm runtime resume
+    - drm/msm/dsi: fix error checks and return values for DSI xmit functions
+    - drm/msm/hdmi: check return value after calling
+      platform_get_resource_byname()
+    - drm/msm/hdmi: fix error check return value of irq_of_parse_and_map()
+    - drm/rockchip: vop: fix possible null-ptr-deref in vop_bind()
+    - virtio_blk: fix the discard_granularity and discard_alignment queue limits
+    - x86: Fix return value of __setup handlers
+    - irqchip/exiu: Fix acknowledgment of edge triggered interrupts
+    - irqchip/aspeed-i2c-ic: Fix irq_of_parse_and_map() return value
+    - x86/mm: Cleanup the control_va_addr_alignment() __setup handler
+    - regulator: core: Fix enable_count imbalance with EXCLUSIVE_GET
+    - drm/msm/mdp5: Return error code in mdp5_pipe_release when deadlock is
+      detected
+    - drm/msm/mdp5: Return error code in mdp5_mixer_release when deadlock is
+      detected
+    - drm/msm: return an error pointer in msm_gem_prime_get_sg_table()
+    - media: uvcvideo: Fix missing check to determine if element is found in list
+    - iomap: iomap_write_failed fix
+    - Revert "cpufreq: Fix possible race in cpufreq online error path"
+    - perf/amd/ibs: Use interrupt regs ip for stack unwinding
+    - ASoC: fsl: Fix refcount leak in imx_sgtl5000_probe
+    - ASoC: mxs-saif: Fix refcount leak in mxs_saif_probe
+    - regulator: pfuze100: Fix refcount leak in pfuze_parse_regulators_dt
+    - scripts/faddr2line: Fix overlapping text section failures
+    - media: aspeed: Fix an error handling path in aspeed_video_probe()
+    - media: st-delta: Fix PM disable depth imbalance in delta_probe
+    - media: exynos4-is: Change clk_disable to clk_disable_unprepare
+    - media: pvrusb2: fix array-index-out-of-bounds in pvr2_i2c_core_init
+    - media: vsp1: Fix offset calculation for plane cropping
+    - Bluetooth: fix dangling sco_conn and use-after-free in sco_sock_timeout
+    - m68k: math-emu: Fix dependencies of math emulation support
+    - sctp: read sk->sk_bound_dev_if once in sctp_rcv()
+    - media: ov7670: remove ov7670_power_off from ov7670_remove
+    - ext4: reject the 'commit' option on ext2 filesystems
+    - drm/msm/a6xx: Fix refcount leak in a6xx_gpu_init
+    - drm: msm: fix possible memory leak in mdp5_crtc_cursor_set()
+    - thermal/drivers/broadcom: Fix potential NULL dereference in sr_thermal_probe
+    - ASoC: wm2000: fix missing clk_disable_unprepare() on error in
+      wm2000_anc_transition()
+    - NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx
+    - rxrpc: Fix listen() setting the bar too high for the prealloc rings
+    - rxrpc: Don't try to resend the request if we're receiving the reply
+    - rxrpc: Fix overlapping ACK accounting
+    - rxrpc: Don't let ack.previousPacket regress
+    - rxrpc: Fix decision on when to generate an IDLE ACK
+    - net/smc: postpone sk_refcnt increment in connect()
+    - arm64: dts: rockchip: Move drive-impedance-ohm to emmc phy on rk3399
+    - ARM: dts: suniv: F1C100: fix watchdog compatible
+    - soc: qcom: smp2p: Fix missing of_node_put() in smp2p_parse_ipc
+    - soc: qcom: smsm: Fix missing of_node_put() in smsm_parse_ipc
+    - PCI: cadence: Fix find_first_zero_bit() limit
+    - PCI: rockchip: Fix find_first_zero_bit() limit
+    - KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry
+    - can: xilinx_can: mark bit timing constants as const
+    - ARM: dts: bcm2835-rpi-zero-w: Fix GPIO line name for Wifi/BT
+    - ARM: dts: bcm2837-rpi-cm3-io3: Fix GPIO line names for SMPS I2C
+    - ARM: dts: bcm2837-rpi-3-b-plus: Fix GPIO line name of power LED
+    - ARM: dts: bcm2835-rpi-b: Fix GPIO line names
+    - misc: ocxl: fix possible double free in ocxl_file_register_afu
+    - crypto: marvell/cesa - ECB does not IV
+    - arm: mediatek: select arch timer for mt7629
+    - powerpc/fadump: fix PT_LOAD segment for boot memory area
+    - mfd: ipaq-micro: Fix error check return value of platform_get_irq()
+    - scsi: fcoe: Fix Wstringop-overflow warnings in fcoe_wwn_from_mac()
+    - firmware: arm_scmi: Fix list protocols enumeration in the base protocol
+    - nvdimm: Allow overwrite in the presence of disabled dimms
+    - pinctrl: mvebu: Fix irq_of_parse_and_map() return value
+    - drivers/base/node.c: fix compaction sysfs file leak
+    - dax: fix cache flush on PMD-mapped pages
+    - powerpc/8xx: export 'cpm_setbrg' for modules
+    - powerpc/idle: Fix return value of __setup() handler
+    - powerpc/4xx/cpm: Fix return value of __setup() handler
+    - proc: fix dentry/inode overinstantiating under /proc/${pid}/net
+    - ipc/mqueue: use get_tree_nodev() in mqueue_get_tree()
+    - PCI: imx6: Fix PERST# start-up sequence
+    - tty: fix deadlock caused by calling printk() under tty_port->lock
+    - crypto: cryptd - Protect per-CPU resource by disabling BH.
+    - Input: sparcspkr - fix refcount leak in bbc_beep_probe
+    - powerpc/64: Only WARN if __pa()/__va() called with bad addresses
+    - powerpc/perf: Fix the threshold compare group constraint for power9
+    - macintosh: via-pmu and via-cuda need RTC_LIB
+    - powerpc/fsl_rio: Fix refcount leak in fsl_rio_setup
+    - mfd: davinci_voicecodec: Fix possible null-ptr-deref davinci_vc_probe()
+    - mailbox: forward the hrtimer if not queued and under a lock
+    - RDMA/hfi1: Prevent use of lock before it is initialized
+    - Input: stmfts - do not leave device disabled in stmfts_input_open
+    - f2fs: fix dereference of stale list iterator after loop body
+    - iommu/mediatek: Add list_del in mtk_iommu_remove
+    - i2c: at91: use dma safe buffers
+    - i2c: at91: Initialize dma_buf in at91_twi_xfer()
+    - NFS: Do not report EINTR/ERESTARTSYS as mapping errors
+    - NFS: Do not report flush errors in nfs_write_end()
+    - NFS: Don't report errors from nfs_pageio_complete() more than once
+    - NFSv4/pNFS: Do not fail I/O when we fail to allocate the pNFS layout
+    - video: fbdev: clcdfb: Fix refcount leak in clcdfb_of_vram_setup
+    - dmaengine: stm32-mdma: remove GISR1 register
+    - iommu/amd: Increase timeout waiting for GA log enablement
+    - perf c2c: Use stdio interface if slang is not supported
+    - perf jevents: Fix event syntax error caused by ExtSel
+    - f2fs: fix to avoid f2fs_bug_on() in dec_valid_node_count()
+    - f2fs: fix to do sanity check on block address in f2fs_do_zero_range()
+    - f2fs: fix to clear dirty inode in f2fs_evict_inode()
+    - f2fs: fix deadloop in foreground GC
+    - f2fs: don't need inode lock for system hidden quota
+    - f2fs: fix fallocate to use file_modified to update permissions consistently
+    - wifi: mac80211: fix use-after-free in chanctx code
+    - iwlwifi: mvm: fix assert 1F04 upon reconfig
+    - fs-writeback: writeback_sb_inodes：Recalculate 'wrote' according skipped
+      pages
+    - efi: Do not import certificates from UEFI Secure Boot for T2 Macs
+    - bfq: Split shared queues on move between cgroups
+    - bfq: Update cgroup information before merging bio
+    - bfq: Track whether bfq_group is still online
+    - ext4: fix use-after-free in ext4_rename_dir_prepare
+    - ext4: fix warning in ext4_handle_inode_extension
+    - ext4: fix bug_on in ext4_writepages
+    - ext4: verify dir block before splitting it
+    - ext4: avoid cycles in directory h-tree
+    - ACPI: property: Release subnode properties with data nodes
+    - tracing: Fix potential double free in create_var_ref()
+    - PCI/PM: Fix bridge_d3_blacklist[] Elo i2 overwrite of Gigabyte X299
+    - PCI: qcom: Fix runtime PM imbalance on probe errors
+    - PCI: qcom: Fix unbalanced PHY init on probe errors
+    - mm, compaction: fast_find_migrateblock() should return pfn in the target
+      zone
+    - dlm: fix plock invalid read
+    - dlm: fix missing lkb refcount handling
+    - ocfs2: dlmfs: fix error handling of user_dlm_destroy_lock
+    - scsi: dc395x: Fix a missing check on list iterator
+    - scsi: ufs: qcom: Add a readl() to make sure ref_clk gets enabled
+    - drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
+    - drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
+    - drm/nouveau/clk: Fix an incorrect NULL check on list iterator
+    - drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
+    - md: fix an incorrect NULL check in does_sb_need_changing
+    - md: fix an incorrect NULL check in md_reload_sb
+    - mtd: cfi_cmdset_0002: Move and rename
+      chip_check/chip_ready/chip_good_for_write
+    - media: coda: Fix reported H264 profile
+    - media: coda: Add more H264 levels for CODA960
+    - Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
+    - RDMA/hfi1: Fix potential integer multiplication overflow errors
+    - irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375,
+      A38x, A39x
+    - irqchip: irq-xtensa-mx: fix initial IRQ affinity
+    - mac80211: upgrade passive scan to active scan on DFS channels after beacon
+      rx
+    - um: chan_user: Fix winch_tramp() return value
+    - um: Fix out-of-bounds read in LDT setup
+    - iommu/msm: Fix an incorrect NULL check on list iterator
+    - nodemask.h: fix compilation error with GCC12
+    - hugetlb: fix huge_pmd_unshare address update
+    - rtl818x: Prevent using not initialized queues
+    - ASoC: rt5514: Fix event generation for "DSP Voice Wake Up" control
+    - carl9170: tx: fix an incorrect use of list iterator
+    - serial: pch: don't overwrite xmit->buf[0] by x_char
+    - tilcdc: tilcdc_external: fix an incorrect NULL check on list iterator
+    - gma500: fix an incorrect NULL check on list iterator
+    - arm64: dts: qcom: ipq8074: fix the sleep clock frequency
+    - phy: qcom-qmp: fix struct clk leak on probe errors
+    - ARM: pxa: maybe fix gpio lookup tables
+    - docs/conf.py: Cope with removal of language=None in Sphinx 5.0.0
+    - dt-bindings: gpio: altera: correct interrupt-cells
+    - blk-iolatency: Fix inflight count imbalances and IO hangs on offline
+    - phy: qcom-qmp: fix reset-controller leak on probe errors
+    - Kconfig: add config option for asm goto w/ outputs
+    - RDMA/rxe: Generate a completion for unsupported/invalid opcode
+    - MIPS: IP27: Remove incorrect `cpu_has_fpu' override
+    - bfq: Avoid merging queues with different parents
+    - bfq: Drop pointless unlock-lock pair
+    - bfq: Remove pointless bfq_init_rq() calls
+    - bfq: Get rid of __bio_blkcg() usage
+    - bfq: Make sure bfqg for which we are queueing requests is online
+    - block: fix bio_clone_blkg_association() to associate with proper blkcg_gq
+    - md: bcache: check the return value of kzalloc() in detached_dev_do_request()
+    - pcmcia: db1xxx_ss: restrict to MIPS_DB1XXX boards
+    - staging: greybus: codecs: fix type confusion of list iterator variable
+    - iio: adc: ad7124: Remove shift from scan_type
+    - tty: goldfish: Use tty_port_destroy() to destroy port
+    - tty: serial: owl: Fix missing clk_disable_unprepare() in owl_uart_probe
+    - tty: serial: fsl_lpuart: fix potential bug when using both of_alias_get_id
+      and ida_simple_get
+    - usb: usbip: fix a refcount leak in stub_probe()
+    - usb: usbip: add missing device lock on tweak configuration cmd
+    - USB: storage: karma: fix rio_karma_init return
+    - usb: musb: Fix missing of_node_put() in omap2430_probe
+    - staging: fieldbus: Fix the error handling path in
+      anybuss_host_common_probe()
+    - pwm: lp3943: Fix duty calculation in case period was clamped
+    - rpmsg: qcom_smd: Fix irq_of_parse_and_map() return value
+    - usb: dwc3: pci: Fix pm_runtime_get_sync() error checking
+    - firmware: stratix10-svc: fix a missing check on list iterator
+    - iio: adc: stmpe-adc: Fix wait_for_completion_timeout return value check
+    - iio: adc: sc27xx: fix read big scale voltage not right
+    - iio: adc: sc27xx: Fine tune the scale calibration values
+    - rpmsg: qcom_smd: Fix returning 0 if irq_of_parse_and_map() fails
+    - phy: qcom-qmp: fix pipe-clock imbalance on power-on failure
+    - serial: sifive: Report actual baud base rather than fixed 115200
+    - coresight: cpu-debug: Replace mutex with mutex_trylock on panic notifier
+    - soc: rockchip: Fix refcount leak in rockchip_grf_init
+    - clocksource/drivers/riscv: Events are stopped during CPU suspend
+    - rtc: mt6397: check return value after calling platform_get_resource()
+    - serial: meson: acquire port->lock in startup()
+    - serial: 8250_fintek: Check SER_RS485_RTS_* only with RS485
+    - serial: digicolor-usart: Don't allow CS5-6
+    - serial: rda-uart: Don't allow CS5-6
+    - serial: txx9: Don't allow CS5-6
+    - serial: sh-sci: Don't allow CS5-6
+    - serial: sifive: Sanitize CSIZE and c_iflag
+    - serial: st-asc: Sanitize CSIZE and correct PARENB for CS7
+    - serial: stm32-usart: Correct CSIZE, bits, and parity
+    - firmware: dmi-sysfs: Fix memory leak in dmi_sysfs_register_handle
+    - bus: ti-sysc: Fix warnings for unbind for serial
+    - driver: base: fix UAF when driver_attach failed
+    - driver core: fix deadlock in __device_attach
+    - watchdog: ts4800_wdt: Fix refcount leak in ts4800_wdt_probe
+    - ASoC: fsl_sai: Fix FSL_SAI_xDR/xFR definition
+    - clocksource/drivers/oxnas-rps: Fix irq_of_parse_and_map() return value
+    - s390/crypto: fix scatterwalk_unmap() callers in AES-GCM
+    - net: sched: fixed barrier to prevent skbuff sticking in qdisc backlog
+    - net: ethernet: mtk_eth_soc: out of bounds read in mtk_hwlro_get_fdir_entry()
+    - net: dsa: mv88e6xxx: Fix refcount leak in mv88e6xxx_mdios_register
+    - modpost: fix removing numeric suffixes
+    - jffs2: fix memory leak in jffs2_do_fill_super
+    - ubi: ubi_create_volume: Fix use-after-free when volume creation failed
+    - nfp: only report pause frame configuration for physical device
+    - net/mlx5: Don't use already freed action pointer
+    - net/mlx5e: Update netdev features after changing XDP state
+    - net: sched: add barrier to fix packet stuck problem for lockless qdisc
+    - tcp: tcp_rtx_synack() can be called from process context
+    - afs: Fix infinite loop found by xfstest generic/676
+    - tipc: check attribute length for bearer name
+    - perf c2c: Fix sorting in percent_rmt_hitm_cmp()
+    - mips: cpc: Fix refcount leak in mips_cpc_default_phys_base
+    - tracing: Fix sleeping function called from invalid context on RT kernel
+    - tracing: Avoid adding tracer option before update_tracer_options
+    - f2fs: remove WARN_ON in f2fs_is_valid_blkaddr
+    - i2c: cadence: Increase timeout per message if necessary
+    - m68knommu: set ZERO_PAGE() to the allocated zeroed page
+    - m68knommu: fix undefined reference to `_init_sp'
+    - dmaengine: zynqmp_dma: In struct zynqmp_dma_chan fix desc_size data type
+    - NFSv4: Don't hold the layoutget locks across multiple RPC calls
+    - video: fbdev: pxa3xx-gcu: release the resources correctly in
+      pxa3xx_gcu_probe/remove()
+    - xprtrdma: treat all calls not a bcall when bc_serv is NULL
+    - netfilter: nat: really support inet nat without l3 address
+    - ata: pata_octeon_cf: Fix refcount leak in octeon_cf_probe
+    - netfilter: nf_tables: memleak flow rule from commit path
+    - xen: unexport __init-annotated xen_xlate_map_ballooned_pages()
+    - af_unix: Fix a data-race in unix_dgram_peer_wake_me().
+    - bpf, arm64: Clear prog->jited_len along prog->jited
+    - net: dsa: lantiq_gswip: Fix refcount leak in gswip_gphy_fw_list
+    - net/mlx4_en: Fix wrong return value on ioctl EEPROM query failure
+    - SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
+    - net: mdio: unexport __init-annotated mdio_bus_init()
+    - net: xfrm: unexport __init-annotated xfrm4_protocol_init()
+    - net: ipv6: unexport __init-annotated seg6_hmac_init()
+    - net/mlx5: Rearm the FW tracer after each tracer event
+    - net/mlx5: fs, fail conflicting actions
+    - ip_gre: test csum_start instead of transport header
+    - net: altera: Fix refcount leak in altera_tse_mdio_create
+    - drm: imx: fix compiler warning with gcc-12
+    - iio: dummy: iio_simple_dummy: check the return value of kstrdup()
+    - iio: st_sensors: Add a local lock for protecting odr
+    - lkdtm/usercopy: Expand size of "out of frame" object
+    - tty: synclink_gt: Fix null-pointer-dereference in slgt_clean()
+    - tty: Fix a possible resource leak in icom_probe
+    - drivers: staging: rtl8192u: Fix deadlock in ieee80211_beacons_stop()
+    - drivers: staging: rtl8192e: Fix deadlock in rtllib_beacons_stop()
+    - USB: host: isp116x: check return value after calling platform_get_resource()
+    - drivers: tty: serial: Fix deadlock in sa1100_set_termios()
+    - drivers: usb: host: Fix deadlock in oxu_bus_suspend()
+    - USB: hcd-pci: Fully suspend across freeze/thaw cycle
+    - usb: dwc2: gadget: don't reset gadget's driver->bus
+    - misc: rtsx: set NULL intfdata when probe fails
+    - extcon: Modify extcon device to be created after driver data is set
+    - clocksource/drivers/sp804: Avoid error on multiple instances
+    - staging: rtl8712: fix uninit-value in usb_read8() and friends
+    - staging: rtl8712: fix uninit-value in r871xu_drv_init()
+    - serial: msm_serial: disable interrupts in __msm_console_write()
+    - kernfs: Separate kernfs_pr_cont_buf and rename_lock.
+    - watchdog: wdat_wdt: Stop watchdog when rebooting the system
+    - md: protect md_unregister_thread from reentrancy
+    - scsi: myrb: Fix up null pointer access on myrb_cleanup()
+    - ceph: allow ceph.dir.rctime xattr to be updatable
+    - drm/radeon: fix a possible null pointer dereference
+    - modpost: fix undefined behavior of is_arm_mapping_symbol()
+    - x86/cpu: Elide KCSAN for cpu_has() and friends
+    - nbd: call genl_unregister_family() first in nbd_cleanup()
+    - nbd: fix race between nbd_alloc_config() and module removal
+    - cifs: version operations for smb20 unneeded when legacy support disabled
+    - nodemask: Fix return values to be unsigned
+    - vringh: Fix loop descriptors check in the indirect cases
+    - scripts/gdb: change kernel config dumping method
+    - ALSA: hda/conexant - Fix loopback issue with CX20632
+    - cifs: return errors during session setup during reconnects
+    - ata: libata-transport: fix {dma|pio|xfer}_mode sysfs files
+    - mmc: block: Fix CQE recovery reset success
+    - nfc: st21nfca: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st21nfca: fix memory leaks in EVT_TRANSACTION handling
+    - ixgbe: fix bcast packets Rx on VF after promisc removal
+    - ixgbe: fix unexpected VLAN Rx in promisc mode on VF
+    - Input: bcm5974 - set missing URB_NO_TRANSFER_DMA_MAP urb flag
+    - powerpc/32: Fix overread/overwrite of thread_struct via ptrace
+    - md/raid0: Ignore RAID0 layout if the second zone has only one device
+    - mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
+    - tcp: fix tcp_mtup_probe_success vs wrong snd_cwnd
+    - Linux 5.4.198
+  * Focal update: v5.4.197 upstream stable release (LP: #1981758)
+    - x86/pci/xen: Disable PCI/MSI[-X] masking for XEN_HVM guests
+    - staging: rtl8723bs: prevent ->Ssid overflow in rtw_wx_set_scan()
+    - Input: goodix - fix spurious key release events
+    - tcp: change source port randomizarion at connect() time
+    - secure_seq: use the 64 bits of the siphash for port offset calculation
+    - media: vim2m: Register video device after setting up internals
+    - media: vim2m: initialize the media device earlier
+    - ACPI: sysfs: Make sparse happy about address space in use
+    - ACPI: sysfs: Fix BERT error region memory mapping
+    - pinctrl: sunxi: fix f1c100s uart2 function
+    - net: af_key: check encryption module availability consistency
+    - net: ftgmac100: Disable hardware checksum on AST2600
+    - i2c: ismt: Provide a DMA buffer for Interrupt Cause Logging
+    - drivers: i2c: thunderx: Allow driver to work with ACPI defined TWSI
+      controllers
+    - assoc_array: Fix BUG_ON during garbage collect
+    - cfg80211: set custom regdomain after wiphy registration
+    - drm/i915: Fix -Wstringop-overflow warning in call to intel_read_wm_latency()
+    - exec: Force single empty string when argv is empty
+    - netfilter: conntrack: re-fetch conntrack after insertion
+    - crypto: ecrdsa - Fix incorrect use of vli_cmp
+    - zsmalloc: fix races between asynchronous zspage free and page migration
+    - dm integrity: fix error code in dm_integrity_ctr()
+    - dm crypt: make printing of the key constant-time
+    - dm stats: add cond_resched when looping over entries
+    - dm verity: set DM_TARGET_IMMUTABLE feature flag
+    - raid5: introduce MD_BROKEN
+    - HID: multitouch: Add support for Google Whiskers Touchpad
+    - tpm: Fix buffer access in tpm2_get_tpm_pt()
+    - tpm: ibmvtpm: Correct the return value in tpm_ibmvtpm_probe()
+    - docs: submitting-patches: Fix crossref to 'The canonical patch format'
+    - NFS: Memory allocation failures are not server fatal errors
+    - NFSD: Fix possible sleep during nfsd4_release_lockowner()
+    - bpf: Enlarge offset check value to INT_MAX in bpf_skb_{load,store}_bytes
+    - Linux 5.4.197
+  * Focal update: v5.4.196 upstream stable release (LP: #1981111)
+    - x86/xen: Make the boot CPU idle task reliable
+    - x86/xen: Make the secondary CPU idle tasks reliable
+    - rtc: fix use-after-free on device removal
+    - um: Cleanup syscall_handler_t definition/cast, fix warning
+    - Input: add bounds checking to input_set_capability()
+    - Input: stmfts - fix reference leak in stmfts_input_open
+    - crypto: stm32 - fix reference leak in stm32_crc_remove
+    - crypto: x86/chacha20 - Avoid spurious jumps to other functions
+    - ALSA: hda/realtek: Enable headset mic on Lenovo P360
+    - nvme-multipath: fix hang when disk goes live over reconnect
+    - rtc: mc146818-lib: Fix the AltCentury for AMD platforms
+    - MIPS: lantiq: check the return value of kzalloc()
+    - drbd: remove usage of list iterator variable after loop
+    - platform/chrome: cros_ec_debugfs: detach log reader wq from devm
+    - ARM: 9191/1: arm/stacktrace, kasan: Silence KASAN warnings in unwind_frame()
+    - nilfs2: fix lockdep warnings in page operations for btree nodes
+    - nilfs2: fix lockdep warnings during disk space reclamation
+    - mmc: core: Specify timeouts for BKOPS and CACHE_FLUSH for eMMC
+    - mmc: block: Use generic_cmd6_time when modifying INAND_CMD38_ARG_EXT_CSD
+    - mmc: core: Default to generic_cmd6_time as timeout in __mmc_switch()
+    - SUNRPC: Clean up scheduling of autoclose
+    - SUNRPC: Prevent immediate close+reconnect
+    - SUNRPC: Don't call connect() more than once on a TCP socket
+    - ALSA: wavefront: Proper check of get_user() error
+    - perf: Fix sys_perf_event_open() race against self
+    - Fix double fget() in vhost_net_set_backend()
+    - PCI/PM: Avoid putting Elo i2 PCIe Ports in D3cold
+    - KVM: x86/mmu: Update number of zapped pages even if page list is stable
+    - crypto: qcom-rng - fix infinite loop on requests not multiple of WORD_SZ
+    - drm/dp/mst: fix a possible memory leak in fetch_monitor_name()
+    - dma-buf: fix use of DMA_BUF_SET_NAME_{A,B} in userspace
+    - ARM: dts: aspeed-g6: remove FWQSPID group in pinctrl dtsi
+    - ARM: dts: aspeed-g6: fix SPI1/SPI2 quad pin group
+    - net: macb: Increment rx bd head after allocating skb and buffer
+    - net/sched: act_pedit: sanitize shift argument before usage
+    - net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()
+    - net: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()
+    - ice: fix possible under reporting of ethtool Tx and Rx statistics
+    - clk: at91: generated: consider range when calculating best rate
+    - net/qla3xxx: Fix a test in ql_reset_work()
+    - NFC: nci: fix sleep in atomic context bugs caused by nci_skb_alloc
+    - net/mlx5e: Properly block LRO when XDP is enabled
+    - ARM: 9196/1: spectre-bhb: enable for Cortex-A15
+    - ARM: 9197/1: spectre-bhb: fix loop8 sequence for Thumb2
+    - igb: skip phy status check where unavailable
+    - net: bridge: Clear offload_fwd_mark when passing frame up bridge interface.
+    - gpio: gpio-vf610: do not touch other bits when set the target bit
+    - gpio: mvebu/pwm: Refuse requests with inverted polarity
+    - perf bench numa: Address compiler error on s390
+    - scsi: qla2xxx: Fix missed DMA unmap for aborted commands
+    - mac80211: fix rx reordering with non explicit / psmp ack policy
+    - selftests: add ping test with ping_group_range tuned
+    - ethernet: tulip: fix missing pci_disable_device() on error in
+      tulip_init_one()
+    - net: stmmac: fix missing pci_disable_device() on error in stmmac_pci_probe()
+    - net: atlantic: verify hw_head_ lies within TX buffer ring
+    - Input: ili210x - fix reset timing
+    - block: return ELEVATOR_DISCARD_MERGE if possible
+    - net: stmmac: disable Split Header (SPH) for Intel platforms
+    - firmware_loader: use kernel credentials when reading firmware
+    - ARM: dts: imx7: Use audio_mclk_post_div instead audio_mclk_root_clk
+    - Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE""
+    - x86/xen: fix booting 32-bit pv guest
+    - x86/xen: Mark cpu_bringup_and_idle() as dead_end_function
+    - i2c: mt7621: fix missing clk_disable_unprepare() on error in mtk_i2c_probe()
+    - afs: Fix afs_getattr() to refetch file status if callback break occurred
+    - Linux 5.4.196
+  * 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()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 19 Sep 2022 00:41:11 +0800
+
+linux-imx (5.4.0-1025.31) focal; urgency=medium
+
+  * [X6MED][Feature] Bluetooth - no FW license & cannot initialise (LP:
+    #1933593)
+    - [Config] imx: armhf: CONFIG_IMX_SDMA=y
+
+  [ Ubuntu: 5.4.0-125.141 ]
+
+  * focal/linux: 5.4.0-125.141 -proposed tracker (LP: #1983947)
+  * nbd: requests can become stuck when disconnecting from server with qemu-nbd
+    (LP: #1896350)
+    - blk-mq: blk-mq: provide forced completion method
+    - blk-mq: move failure injection out of blk_mq_complete_request
+    - nbd: don't handle response without a corresponding request message
+    - nbd: make sure request completion won't concurrent
+    - nbd: don't clear 'NBD_CMD_INFLIGHT' flag if request is not completed
+    - nbd: fix io hung while disconnecting device
+  * CVE-2021-33656
+    - vt: drop old FONT ioctls
+  * CVE-2021-33061
+    - ixgbe: add the ability for the PF to disable VF link state
+    - ixgbe: add improvement for MDD response functionality
+    - ixgbevf: add disable link state
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 30 Aug 2022 18:28:39 +0800
+
+linux-imx (5.4.0-1024.29) focal; urgency=medium
+
+  * [Reading] Tracking bug for wireless support (LP: #1985008)
+    - SAUCE: net: wireless: brcmfmac: Add path for cypress firmware.
+    - SAUCE: net: wireless: brcmfmac: Support for CYW43439 SDIO
+    - brcmfmac: support 43439 Cypress Vendor and Device ID
+    - brcmfmac: add CYW43439 SR related changes
+
+  * [Reading] Tracking bug for kernel support (LP: #1985002)
+    - net: phy: dp83867: fix hfs boot in rgmii mode
+    - net: dp83867: Fix OF_MDIO config check
+    - SAUCE: arm64: dts: Support msc-sm2s-imx8mlc-mini.
+    - SAUCE: arm64: dts: msc-sm2-imx8m_mlc: Support Keurig.
+    - SAUCE: arm64: dts: imx8mlc_mini: build KDRP device tree
+    - SAUCE: arm64: dts: msc-sm2-imx8m_mlc: Added extcon entry for usb otg.
+    - arm64: dts: imx8mm: Remove incorrect fallback compatible for ocotp
+    - arm64: dts: imx8mm-evk: Assigned clocks for audio plls
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8mm-evk: Assigned clocks for audio plls
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8m: change ocotp node name on i.MX8M SoCs
+    - arm64: dts: imx8mm: add GPC node
+    - arm64: dts: imx8mm: Add the pcie support
+    - arm64: dts: imx8mm: Add the pcie phy support
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Correct pcie phy node.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Add enet wakeup support,
+      including the irq wakeup property.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Add dispmix-reset node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Define lcdif/dsi resets
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Increase cma size
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add csi bridge and mipi csi
+      node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add fsl,dataline for SAI
+      node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add caam snvs and secvio
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add caam snvs clock
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add secure memory
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add the resets pcie
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add gpu device
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add pcie ep support
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: use_dt_domains for pci node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: assign osc_24m to dsi PHY
+      REF clock source
+    - arm64: dts: imx8m: add NVMEM provider and consumer to read soc unique ID
+    - SAUCE: arm64: dts: msc-sm2s-imx8mm_mlc: Added usb over current settings.
+    - SAUCE: drm: Add panel driver for AVD101WX-CN.
+    - SAUCE: drm: Updated panel driver for AVD101WX-CN.
+    - SAUCE: drm: Updated panel driver for AVD101WX-CN init sequence and timing.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mm_mlc: Fixed USB0 otg support.
+    - SAUCE: drm: Fixed AVD101WX-CN display resolution.
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Changed GPIO10 to wifi enable.
+    - SAUCE: irqchip: imx: Corrected typo
+    - drm/panel: add backlight support
+    - MLK-14392-1 input: touch: add focaltech touch screen support
+    - LF-2653 drm/imx: lcdif: implement mode_valid() for CRTC
+    - reset: Kconfig: use 'ARCH_MXC' for reset dispmix
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm-04N0830E-module: add optee device node
+    - [Config] add AVD-TT101WX-CN touchscreen panel
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Use native RTS/CTS functionality of
+      uart2.
+    - drm/drm_panel: no error when no callback
+    - [Config] CONFIG_DRM_IMX_LCDIF=y
+
+  [ Ubuntu: 5.4.0-124.140 ]
+
+  * CVE-2022-2586
+    - SAUCE: netfilter: nf_tables: do not allow SET_ID to refer to another table
+    - SAUCE: netfilter: nf_tables: do not allow RULE_ID to refer to another chain
+  * CVE-2022-2588
+    - SAUCE: net_sched: cls_route: remove from list when handle is 0
+  * CVE-2022-34918
+    - netfilter: nf_tables: stricter validation of element data
+
+  [ Ubuntu: 5.4.0-123.139 ]
+
+  * focal/linux: 5.4.0-123.139 -proposed tracker (LP: #1981284)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.07.11)
+  * Hairpin traffic does not work with centralized NAT gw (LP: #1967856)
+    - net: openvswitch: fix misuse of the cached connection on tuple changes
+  * [UBUNTU 20.04] Include patches to avoid self-detected stall with Secure
+    Execution (LP: #1979296)
+    - KVM: s390: pv: add macros for UVC CC values
+    - KVM: s390: pv: avoid stalls when making pages secure
+    - KVM: s390: pv: avoid stalls for kvm_s390_pv_init_vm
+  * Focal update: v5.4.195 upstream stable release (LP: #1980407)
+    - batman-adv: Don't skb_split skbuffs with frag_list
+    - hwmon: (tmp401) Add OF device ID table
+    - mac80211: Reset MBSSID parameters upon connection
+    - net: Fix features skip in for_each_netdev_feature()
+    - ipv4: drop dst in multicast routing path
+    - drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name()
+    - netlink: do not reset transport header in netlink_recvmsg()
+    - mac80211_hwsim: call ieee80211_tx_prepare_skb under RCU protection
+    - dim: initialize all struct fields
+    - hwmon: (ltq-cputemp) restrict it to SOC_XWAY
+    - s390/ctcm: fix variable dereferenced before check
+    - s390/ctcm: fix potential memory leak
+    - s390/lcs: fix variable dereferenced before check
+    - net/sched: act_pedit: really ensure the skb is writable
+    - net/smc: non blocking recvmsg() return -EAGAIN when no data and
+      signal_pending
+    - net: sfc: ef10: fix memory leak in efx_ef10_mtd_probe()
+    - gfs2: Fix filesystem block deallocation for short writes
+    - hwmon: (f71882fg) Fix negative temperature
+    - ASoC: max98090: Reject invalid values in custom control put()
+    - ASoC: max98090: Generate notifications on changes for custom control
+    - ASoC: ops: Validate input values in snd_soc_put_volsw_range()
+    - s390: disable -Warray-bounds
+    - net: emaclite: Don't advertise 1000BASE-T and do auto negotiation
+    - tcp: resalt the secret every 10 seconds
+    - tty: n_gsm: fix mux activation issues in gsm_config()
+    - usb: cdc-wdm: fix reading stuck on device close
+    - usb: typec: tcpci: Don't skip cleanup in .remove() on error
+    - USB: serial: pl2303: add device id for HP LM930 Display
+    - USB: serial: qcserial: add support for Sierra Wireless EM7590
+    - USB: serial: option: add Fibocom L610 modem
+    - USB: serial: option: add Fibocom MA510 modem
+    - slimbus: qcom: Fix IRQ check in qcom_slim_probe
+    - serial: 8250_mtk: Fix UART_EFR register address
+    - serial: 8250_mtk: Fix register address for XON/XOFF character
+    - drm/nouveau/tegra: Stop using iommu_present()
+    - i40e: i40e_main: fix a missing check on list iterator
+    - cgroup/cpuset: Remove cpus_allowed/mems_allowed setup in cpuset_init_smp()
+    - drm/vmwgfx: Initialize drm_mode_fb_cmd2
+    - MIPS: fix build with gcc-12
+    - net: phy: Fix race condition on link status change
+    - arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map
+    - ping: fix address binding wrt vrf
+    - tty/serial: digicolor: fix possible null-ptr-deref in digicolor_uart_probe()
+    - Linux 5.4.195
+  * Focal update: v5.4.194 upstream stable release (LP: #1980399)
+    - MIPS: Use address-of operator on section symbols
+    - block: drbd: drbd_nl: Make conversion to 'enum drbd_ret_code' explicit
+    - drm/amd/display/dc/gpio/gpio_service: Pass around correct dce_{version,
+      environment} types
+    - drm/i915: Cast remain to unsigned long in eb_relocate_vma
+    - nfp: bpf: silence bitwise vs. logical OR warning
+    - can: grcan: grcan_probe(): fix broken system id check for errata workaround
+      needs
+    - can: grcan: only use the NAPI poll budget for RX
+    - arm: remove CONFIG_ARCH_HAS_HOLES_MEMORYMODEL
+    - [Config] updateconfigs for ARCH_HAS_HOLES_MEMORYMODEL
+    - KVM: x86/pmu: Refactoring find_arch_event() to pmc_perf_hw_id()
+    - x86/asm: Allow to pass macros to __ASM_FORM()
+    - x86: xen: kvm: Gather the definition of emulate prefixes
+    - x86: xen: insn: Decode Xen and KVM emulate-prefix signature
+    - x86: kprobes: Prohibit probing on instruction which has emulate prefix
+    - KVM: x86/svm: Account for family 17h event renumberings in
+      amd_pmc_perf_hw_id
+    - Bluetooth: Fix the creation of hdev->name
+    - mm: fix missing cache flush for all tail pages of compound page
+    - mm: hugetlb: fix missing cache flush in copy_huge_page_from_user()
+    - mm: userfaultfd: fix missing cache flush in mcopy_atomic_pte() and
+      __mcopy_atomic()
+    - Linux 5.4.194
+  * Focal update: v5.4.193 upstream stable release (LP: #1979566)
+    - MIPS: Fix CP0 counter erratum detection for R4k CPUs
+    - parisc: Merge model and model name into one line in /proc/cpuinfo
+    - ALSA: fireworks: fix wrong return count shorter than expected by 4 bytes
+    - gpiolib: of: fix bounds check for 'gpio-reserved-ranges'
+    - Revert "SUNRPC: attempt AF_LOCAL connect on setup"
+    - firewire: fix potential uaf in outbound_phy_packet_callback()
+    - firewire: remove check of list iterator against head past the loop body
+    - firewire: core: extend card->lock in fw_core_handle_bus_reset
+    - ACPICA: Always create namespace nodes using acpi_ns_create_node()
+    - genirq: Synchronize interrupt thread startup
+    - ASoC: da7219: Fix change notifications for tone generator frequency
+    - ASoC: wm8958: Fix change notifications for DSP controls
+    - ASoC: meson: Fix event generation for G12A tohdmi mux
+    - s390/dasd: fix data corruption for ESE devices
+    - s390/dasd: prevent double format of tracks for ESE devices
+    - s390/dasd: Fix read for ESE with blksize < 4k
+    - s390/dasd: Fix read inconsistency for ESE DASD devices
+    - can: grcan: grcan_close(): fix deadlock
+    - can: grcan: use ofdev->dev when allocating DMA memory
+    - nfc: replace improper check device_is_registered() in netlink related
+      functions
+    - NFC: netlink: fix sleep in atomic bug when firmware download timeout
+    - hwmon: (adt7470) Fix warning on module removal
+    - ASoC: dmaengine: Restore NULL prepare_slave_config() callback
+    - RDMA/siw: Fix a condition race issue in MPA request processing
+    - net: ethernet: mediatek: add missing of_node_put() in mtk_sgmii_init()
+    - net: stmmac: dwmac-sun8i: add missing of_node_put() in
+      sun8i_dwmac_register_mdio_mux()
+    - net: emaclite: Add error handling for of_address_to_resource()
+    - selftests: mirror_gre_bridge_1q: Avoid changing PVID while interface is
+      operational
+    - bnxt_en: Fix possible bnxt_open() failure caused by wrong RFS flag
+    - smsc911x: allow using IRQ0
+    - btrfs: always log symlinks in full mode
+    - net: igmp: respect RCU rules in ip_mc_source() and ip_mc_msfilter()
+    - drm/amdkfd: Use drm_priv to pass VM from KFD to amdgpu
+    - NFSv4: Don't invalidate inode attributes on delegation return
+    - kvm: x86/cpuid: Only provide CPUID leaf 0xA if host has architectural PMU
+    - x86/kvm: Preserve BSP MSR_KVM_POLL_CONTROL across suspend/resume
+    - KVM: LAPIC: Enable timer posted-interrupt only when mwait/hlt is advertised
+    - net: ipv6: ensure we call ipv6_mc_down() at most once
+    - block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern
+    - mm: fix unexpected zeroed page mapping with zram swap
+    - ALSA: pcm: Fix races among concurrent hw_params and hw_free calls
+    - ALSA: pcm: Fix races among concurrent read/write and buffer changes
+    - ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls
+    - ALSA: pcm: Fix races among concurrent prealloc proc writes
+    - ALSA: pcm: Fix potential AB/BA lock with buffer_mutex and mmap_lock
+    - tcp: make sure treq->af_specific is initialized
+    - dm: fix mempool NULL pointer race when completing IO
+    - dm: interlock pending dm_io and dm_wait_for_bios_completion
+    - PCI: aardvark: Clear all MSIs at setup
+    - PCI: aardvark: Fix reading MSI interrupt number
+    - mmc: rtsx: add 74 Clocks in power on flow
+    - Linux 5.4.193
+  * CVE-2022-1679
+    - SAUCE: ath9k: fix use-after-free in ath9k_hif_usb_rx_cb
+  * CVE-2022-28893
+    - SUNRPC: Ensure we flush any closed sockets before xs_xprt_free()
+    - SUNRPC: Don't leak sockets in xs_local_connect()
+  * CVE-2022-1734
+    - nfc: nfcmrvl: main: reorder destructive operations in
+      nfcmrvl_nci_unregister_dev to avoid bugs
+  * CVE-2022-1652
+    - floppy: use a statically allocated error counter
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 14 Aug 2022 19:45:48 +0800
+
+linux-imx (5.4.0-1023.28) focal; urgency=medium
+
+  * Focal update: upstream stable patchset v5.4.192 (LP: #1979014)
+    - [Config] updateconfigs for NVM
+
+  * [uc20-x01] System can not wake up from suspend. (LP: #1976604)
+    - soc: imx: gpcv2: support system suspend/resume
+    - SAUCE: imx7: Suspend/Resume updates
+
+  * [PE100A][Core] The system shutdown because the critial temperature of
+    thermal should be config to 105'c not 90'c (LP: #1982989)
+    - SAUCE: imx/pe100a: dts: Set GPU/VPU crit temprature to 105
+
+  [ Ubuntu: 5.4.0-122.138 ]
+
+  * focal/linux: 5.4.0-122.138 -proposed tracker (LP: #1979489)
+  * Remove SAUCE patches from test_vxlan_under_vrf.sh in net of
+    ubuntu_kernel_selftests (LP: #1975691)
+    - Revert "UBUNTU: SAUCE: selftests: net: Don't fail test_vxlan_under_vrf on
+      xfail"
+    - Revert "UBUNTU: SAUCE: selftests: net: Make test for VXLAN underlay in non-
+      default VRF an expected failure"
+  * Enable Asus USB-BT500 Bluetooth dongle(0b05:190e) (LP: #1976613)
+    - Bluetooth: btusb: Add flag to define wideband speech capability
+    - Bluetooth: btrtl: Add support for RTL8761B
+    - Bluetooth: btusb: Add 0x0b05:0x190e Realtek 8761BU (ASUS BT500) device.
+  * [UBUNTU 20.04] rcu stalls with many storage key guests (LP: #1975582)
+    - s390/gmap: voluntarily schedule during key setting
+    - s390/mm: use non-quiescing sske for KVM switch to keyed guest
+  * Ubuntu 5.4.0-117.132-generic 5.4.189 has BUG: kernel NULL pointer
+    dereference, address: 0000000000000034 (LP: #1978719)
+    - mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()
+  * Focal update: upstream stable patchset v5.4.192 (LP: #1979014)
+    - floppy: disable FDRAWCMD by default
+    - [Config] updateconfigs for BLK_DEV_FD_RAWCMD
+    - hamradio: defer 6pack kfree after unregister_netdev
+    - hamradio: remove needs_free_netdev to avoid UAF
+    - lightnvm: disable the subsystem
+    - [Config] updateconfigs for NVM, NVM_PBLK
+    - usb: mtu3: fix USB 3.0 dual-role-switch from device to host
+    - USB: quirks: add a Realtek card reader
+    - USB: quirks: add STRING quirk for VCOM device
+    - USB: serial: whiteheat: fix heap overflow in WHITEHEAT_GET_DTR_RTS
+    - USB: serial: cp210x: add PIDs for Kamstrup USB Meter Reader
+    - USB: serial: option: add support for Cinterion MV32-WA/MV32-WB
+    - USB: serial: option: add Telit 0x1057, 0x1058, 0x1075 compositions
+    - xhci: stop polling roothubs after shutdown
+    - xhci: increase usb U3 -> U0 link resume timeout from 100ms to 500ms
+    - iio: dac: ad5592r: Fix the missing return value.
+    - iio: dac: ad5446: Fix read_raw not returning set value
+    - iio: magnetometer: ak8975: Fix the error handling in ak8975_power_on()
+    - usb: misc: fix improper handling of refcount in uss720_probe()
+    - usb: typec: ucsi: Fix role swapping
+    - usb: gadget: uvc: Fix crash when encoding data for usb request
+    - usb: gadget: configfs: clear deactivation flag in
+      configfs_composite_unbind()
+    - usb: dwc3: core: Fix tx/rx threshold settings
+    - usb: dwc3: gadget: Return proper request status
+    - serial: imx: fix overrun interrupts in DMA mode
+    - serial: 8250: Also set sticky MCR bits in console restoration
+    - serial: 8250: Correct the clock for EndRun PTP/1588 PCIe device
+    - arch_topology: Do not set llc_sibling if llc_id is invalid
+    - hex2bin: make the function hex_to_bin constant-time
+    - hex2bin: fix access beyond string end
+    - video: fbdev: udlfb: properly check endpoint type
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12B boards
+    - arm64: dts: meson: remove CPU opps below 1GHz for SM1 boards
+    - mtd: rawnand: fix ecc parameters for mt7622
+    - USB: Fix xhci event ring dequeue pointer ERDP update issue
+    - ARM: dts: imx6qdl-apalis: Fix sgtl5000 detection issue
+    - phy: samsung: Fix missing of_node_put() in exynos_sata_phy_probe
+    - phy: samsung: exynos5250-sata: fix missing device put in probe error paths
+    - ARM: OMAP2+: Fix refcount leak in omap_gic_of_init
+    - phy: ti: omap-usb2: Fix error handling in omap_usb2_enable_clocks
+    - ARM: dts: at91: Map MCLK for wm8731 on at91sam9g20ek
+    - phy: mapphone-mdm6600: Fix PM error handling in phy_mdm6600_probe
+    - phy: ti: Add missing pm_runtime_disable() in serdes_am654_probe
+    - ARM: dts: Fix mmc order for omap3-gta04
+    - ARM: dts: am3517-evm: Fix misc pinmuxing
+    - ARM: dts: logicpd-som-lv: Fix wrong pinmuxing on OMAP35
+    - ipvs: correctly print the memory size of ip_vs_conn_tab
+    - mtd: rawnand: Fix return value check of wait_for_completion_timeout
+    - bpf, lwt: Fix crash when using bpf_skb_set_tunnel_key() from bpf_xmit lwt
+      hook
+    - tcp: md5: incorrect tcp_header_len for incoming connections
+    - tcp: ensure to use the most recently sent skb when filling the rate sample
+    - sctp: check asoc strreset_chunk in sctp_generate_reconf_event
+    - ARM: dts: imx6ull-colibri: fix vqmmc regulator
+    - arm64: dts: imx8mn-ddr4-evk: Describe the 32.768 kHz PMIC clock
+    - pinctrl: pistachio: fix use of irq_of_parse_and_map()
+    - cpufreq: fix memory leak in sun50i_cpufreq_nvmem_probe
+    - net: hns3: add validity check for message data length
+    - net/smc: sync err code when tcp connection was refused
+    - ip_gre: Make o_seqno start from 0 in native mode
+    - tcp: fix potential xmit stalls caused by TCP_NOTSENT_LOWAT
+    - bus: sunxi-rsb: Fix the return value of sunxi_rsb_device_create()
+    - clk: sunxi: sun9i-mmc: check return value after calling
+      platform_get_resource()
+    - net: bcmgenet: hide status block before TX timestamping
+    - net: dsa: lantiq_gswip: Don't set GSWIP_MII_CFG_RMII_CLK
+    - drm/amd/display: Fix memory leak in dcn21_clock_source_create
+    - tls: Skip tls_append_frag on zero copy size
+    - bnx2x: fix napi API usage sequence
+    - ixgbe: ensure IPsec VF<->PF compatibility
+    - tcp: fix F-RTO may not work correctly when receiving DSACK
+    - ASoC: wm8731: Disable the regulator when probing fails
+    - ip6_gre: Avoid updating tunnel->tun_hlen in __gre6_xmit()
+    - x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
+    - cifs: destage any unwritten data to the server before calling
+      copychunk_write
+    - drivers: net: hippi: Fix deadlock in rr_close()
+    - net: ethernet: stmmac: fix write to sgmii_adapter_base
+    - x86/cpu: Load microcode during restore_processor_state()
+    - tty: n_gsm: fix wrong signal octet encoding in convergence layer type 2
+    - tty: n_gsm: fix malformed counter for out of frame data
+    - netfilter: nft_socket: only do sk lookups when indev is available
+    - tty: n_gsm: fix insufficient txframe size
+    - tty: n_gsm: fix missing explicit ldisc flush
+    - tty: n_gsm: fix wrong command retry handling
+    - tty: n_gsm: fix wrong command frame length field encoding
+    - tty: n_gsm: fix incorrect UA handling
+    - hugetlbfs: get unmapped area below TASK_UNMAPPED_BASE for hugetlbfs
+    - mm, hugetlb: allow for "high" userspace addresses
+    - Linux 5.4.192
+  * CVE-2022-1789
+    - KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID
+  * Focal update: v5.4.191 upstream stable release (LP: #1976116)
+    - etherdevice: Adjust ether_addr* prototypes to silence -Wstringop-overead
+    - mm: page_alloc: fix building error on -Werror=array-compare
+    - tracing: Dump stacktrace trigger to the corresponding instance
+    - gfs2: assign rgrp glock before compute_bitstructs
+    - tcp: fix race condition when creating child sockets from syncookies
+    - tcp: Fix potential use-after-free due to double kfree()
+    - ALSA: usb-audio: Clear MIDI port active flag after draining
+    - ASoC: atmel: Remove system clock tree configuration for at91sam9g20ek
+    - ASoC: msm8916-wcd-digital: Check failure for devm_snd_soc_register_component
+    - dmaengine: imx-sdma: Fix error checking in sdma_event_remap
+    - dmaengine: mediatek:Fix PM usage reference leak of
+      mtk_uart_apdma_alloc_chan_resources
+    - igc: Fix infinite loop in release_swfw_sync
+    - igc: Fix BUG: scheduling while atomic
+    - rxrpc: Restore removed timer deletion
+    - net/smc: Fix sock leak when release after smc_shutdown()
+    - net/packet: fix packet_sock xmit return value checking
+    - net/sched: cls_u32: fix possible leak in u32_init_knode()
+    - l3mdev: l3mdev_master_upper_ifindex_by_index_rcu should be using
+      netdev_master_upper_dev_get_rcu
+    - netlink: reset network and mac headers in netlink_dump()
+    - selftests: mlxsw: vxlan_flooding: Prevent flooding of unwanted packets
+    - ARM: vexpress/spc: Avoid negative array index when !SMP
+    - reset: tegra-bpmp: Restore Handle errors in BPMP response
+    - platform/x86: samsung-laptop: Fix an unsigned comparison which can never be
+      negative
+    - ALSA: usb-audio: Fix undefined behavior due to shift overflowing the
+      constant
+    - vxlan: fix error return code in vxlan_fdb_append
+    - cifs: Check the IOCB_DIRECT flag, not O_DIRECT
+    - mt76: Fix undefined behavior due to shift overflowing the constant
+    - brcmfmac: sdio: Fix undefined behavior due to shift overflowing the constant
+    - dpaa_eth: Fix missing of_node_put in dpaa_get_ts_info()
+    - drm/msm/mdp5: check the return of kzalloc()
+    - net: macb: Restart tx only if queue pointer is lagging
+    - scsi: qedi: Fix failed disconnect handling
+    - stat: fix inconsistency between struct stat and struct compat_stat
+    - EDAC/synopsys: Read the error count from the correct register
+    - oom_kill.c: futex: delay the OOM reaper to allow time for proper futex
+      cleanup
+    - ata: pata_marvell: Check the 'bmdma_addr' beforing reading
+    - dma: at_xdmac: fix a missing check on list iterator
+    - drm/panel/raspberrypi-touchscreen: Avoid NULL deref if not initialised
+    - drm/panel/raspberrypi-touchscreen: Initialise the bridge in prepare
+    - KVM: PPC: Fix TCE handling for VFIO
+    - drm/vc4: Use pm_runtime_resume_and_get to fix pm_runtime_get_sync() usage
+    - powerpc/perf: Fix power9 event alternatives
+    - xtensa: patch_text: Fixup last cpu should be master
+    - xtensa: fix a7 clobbering in coprocessor context load/store
+    - openvswitch: fix OOB access in reserve_sfa_size()
+    - ASoC: soc-dapm: fix two incorrect uses of list iterator
+    - e1000e: Fix possible overflow in LTR decoding
+    - ARC: entry: fix syscall_trace_exit argument
+    - arm_pmu: Validate single/group leader events
+    - ext4: fix symlink file size not match to file content
+    - ext4: fix use-after-free in ext4_search_dir
+    - ext4, doc: fix incorrect h_reserved size
+    - ext4: fix overhead calculation to account for the reserved gdt blocks
+    - ext4: force overhead calculation if the s_overhead_cluster makes no sense
+    - jbd2: fix a potential race while discarding reserved buffers after an abort
+    - spi: atmel-quadspi: Fix the buswidth adjustment between spi-mem and
+      controller
+    - staging: ion: Prevent incorrect reference counting behavour
+    - block/compat_ioctl: fix range check in BLKGETSIZE
+    - Linux 5.4.191
+  * Focal update: v5.4.190 upstream stable release (LP: #1973085)
+    - memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probe
+    - net/sched: flower: fix parsing of ethertype following VLAN header
+    - veth: Ensure eth header is in skb's linear part
+    - gpiolib: acpi: use correct format characters
+    - mlxsw: i2c: Fix initialization error flow
+    - net/sched: fix initialization order when updating chain 0 head
+    - net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link
+    - net/sched: taprio: Check if socket flags are valid
+    - cfg80211: hold bss_lock while updating nontrans_list
+    - drm/msm/dsi: Use connector directly in msm_dsi_manager_connector_init()
+    - net/smc: Fix NULL pointer dereference in smc_pnet_find_ib()
+    - sctp: Initialize daddr on peeled off socket
+    - testing/selftests/mqueue: Fix mq_perf_tests to free the allocated cpu set
+    - nfc: nci: add flush_workqueue to prevent uaf
+    - cifs: potential buffer overflow in handling symlinks
+    - drm/amd: Add USBC connector ID
+    - drm/amd/display: fix audio format not updated after edid updated
+    - drm/amd/display: Update VTEM Infopacket definition
+    - drm/amdkfd: Fix Incorrect VMIDs passed to HWS
+    - drm/amdkfd: Check for potential null return of kmalloc_array()
+    - Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
+    - scsi: target: tcmu: Fix possible page UAF
+    - scsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024
+    - ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs
+    - gpu: ipu-v3: Fix dev_dbg frequency output
+    - regulator: wm8994: Add an off-on delay for WM8994 variant
+    - arm64: alternatives: mark patch_alternative() as `noinstr`
+    - tlb: hugetlb: Add more sizes to tlb_remove_huge_tlb_entry
+    - net: usb: aqc111: Fix out-of-bounds accesses in RX fixup
+    - drm/amd/display: Fix allocate_mst_payload assert on resume
+    - powerpc: Fix virt_addr_valid() for 64-bit Book3E & 32-bit
+    - scsi: mvsas: Add PCI ID of RocketRaid 2640
+    - scsi: megaraid_sas: Target with invalid LUN ID is deleted during scan
+    - drivers: net: slip: fix NPD bug in sl_tx_timeout()
+    - perf/imx_ddr: Fix undefined behavior due to shift overflowing the constant
+    - mm, page_alloc: fix build_zonerefs_node()
+    - mm: kmemleak: take a full lowmem check in kmemleak_*_phys()
+    - gcc-plugins: latent_entropy: use /dev/urandom
+    - ath9k: Properly clear TX status area before reporting to mac80211
+    - ath9k: Fix usage of driver-private space in tx_info
+    - btrfs: remove unused variable in btrfs_{start,write}_dirty_block_groups()
+    - btrfs: mark resumed async balance as writing
+    - ALSA: hda/realtek: Add quirk for Clevo PD50PNT
+    - ALSA: pcm: Test for "silence" field in struct "pcm_format_data"
+    - ipv6: fix panic when forwarding a pkt with no in6 dev
+    - drm/amd/display: don't ignore alpha property on pre-multiplied mode
+    - genirq/affinity: Consider that CPUs on nodes can be unbalanced
+    - tick/nohz: Use WARN_ON_ONCE() to prevent console saturation
+    - ARM: davinci: da850-evm: Avoid NULL pointer dereference
+    - dm integrity: fix memory corruption when tag_size is less than digest size
+    - smp: Fix offline cpu check in flush_smp_call_function_queue()
+    - i2c: pasemi: Wait for write xfers to finish
+    - dma-direct: avoid redundant memory sync for swiotlb
+    - 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()
+    - ax25: fix NPD bug in ax25_disconnect
+    - ax25: Fix NULL pointer dereferences in ax25 timers
+    - ax25: Fix UAF bugs in ax25 timers
+    - Linux 5.4.190
+
+  [ Ubuntu: 5.4.0-121.137 ]
+
+  * focal/linux: 5.4.0-121.137 -proposed tracker (LP: #1978666)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.05.30)
+  * CVE-2022-28388
+    - can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error
+      path
+  * test_vxlan_under_vrf.sh in net from ubuntu_kernel_selftests failed (Check VM
+    connectivity through VXLAN (underlay in the default VRF) [FAIL])
+    (LP: #1871015)
+    - selftests: net: test_vxlan_under_vrf: fix HV connectivity test
+  * [UBUNTU 20.04] CPU-MF: add extended counter set definitions for new IBM z16
+    (LP: #1974433)
+    - s390/cpumf: add new extended counter set for IBM z16
+  * [UBUNTU 20.04] KVM nesting support leaks too much memory, might result in
+    stalls during cleanup (LP: #1974017)
+    - KVM: s390: vsie/gmap: reduce gmap_rmap overhead
+  * [UBUNTU 20.04] Null Pointer issue in nfs code running Ubuntu on IBM Z
+    (LP: #1968096)
+    - NFS: Fix up nfs_ctx_key_to_expire()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 10 Aug 2022 14:53:21 +0800
+
+linux-imx (5.4.0-1022.26) focal; urgency=medium
+
+  * [pe100a] WWAN primary port is missing after resume from suspend (LP:
+    #1981540)
+    - SAUCE: pe100a: Pull platform reset pin low before suspend
+
+  * [PE100A] Custom setup required for LAN1 LED (LP: #1978043)
+    - SAUCE: net: fec: Set custom PHY LED config for PE100A
+
+  * [PE100A] Remove CAN debug messages (LP: #1965849)
+    - SAUCE: imx/pe100a: CAN: Remove debug messages
+
+  * [PE100A] Refine 0016-ethernet-Asus-LAN2-feature-porting.patch (LP: #1970770)
+    - SAUCE: Revert igb changes introduced by "Asus LAN2 feature porting"
+
+  * [PE100A] Syncing between two RTCs doesn't really work (LP: #1967267)
+    - SAUCE: rtc: isl1208: Mark UIE unsupported if there is no IRQ defined
+    - SAUCE: rtc: bq32k: Mark UIE unsupported if there is no IRQ defined
+    - SAUCE: imx/pe100a: dts: Add RTC aliases
+
+  * [PE100A] PCI bus doesn't work if platform-reset is not set as built-in (LP:
+    #1967293)
+    - SAUCE: pe100a: reset: Toggle reset pin on resume only
+    - [Config] CONFIG_RESET_ASUS_PE100A=m
+
+  * [PE100A] systemd does not turn-off device by power key pressed (LP:
+    #1965751)
+    - SAUCE: dts: pe100a: Add clock-names to snvs_pwrkey
+    - [Config] imx: arm64: CONFIG_KEYBOARD_SNVS_PWRKEY=m
+
+  * HDMI not worked after boot kernel (LP: #1965475)
+    - [Config] Enlarge CMA size for higher display resolution
+
+  * [PE100A] Add RTC bq32000 (LP: #1965851)
+    - SAUCE: imx/pe100a: dts: Add RTC bq32000
+
+  * Import eth0 pinctrl changes (LP: #1965852)
+    - SAUCE: pinctrl: modify RGMII TX&RX SRE to slow and other config.
+
+  * [pe100a][us2004]Intel I211 eth didn't bring up (LP: #1965485)
+    - [Config] Enable E100/E1000/E1000E and IGB
+    - [Config] CONFIG_RESET_ASUS_PE100A=y
+
+  * [PE100A]Internal eMMC is not working (LP: #1958199)
+    - [Config] Add driver for REGULATOR_BD718XX
+
+  * [pe100a][us2004]Wireless module not worked (LP: #1965481)
+    - [Config] Enable ath10k
+
+  * [pe100a][us2004]HDMI not worked after boot kernel (LP: #1965475)
+    - clk: imx8mq: add 27MHz PHY ref clock
+    - arm64: dts: imx8mq: add dcss, hdmi and create imx8mq-evk-hdmi.dts file
+    - dts: arm: imx: add imx8mq hdmi
+    - arm64: dts: imx8mq: add DCSS node
+    - arm64: dts: imx8mq: use the DCSS DTRC interrupts
+    - arm64: dts: imx8mq: add DCSS external oscillator support
+    - SAUCE: Fix HDMI output on PE100A
+    - [Config] CONFIG_FB_EFI=n
+
+  * [X6MED][UC20] WARNING: CPU: 0 PID: 1 at arch/arm/mm/dump.c (LP: #1951783)
+    - ARM: add __arm_iomem_set_ro() to write-protect ioremapped area
+    - ARM: imx6: mark OCRAM mapping read-only
+
+  * [imx8-bms] RS485 Send and receive test failed (LP: #1978514)
+    - MLK-21309: dma: engine: sdma: add uart rom script
+    - serial: core: Initialize rs485 RTS polarity already on probe
+
+  * [US20.04][UC20] Camera does not work (LP: #1966824)
+    - SAUCE: dts: amgis: Fix clock used by ov9281_mipi and clock used by clko1.
+    - [Config] Enable REGULATOR_ANATOP as a built-in driver for armhf.
+
+  * [uc20-x01] Can't find audio playback device (LP: #1976600)
+    - SAUCE: ASoC: topology: Avoid card NULL deref in
+      snd_soc_tplg_component_remove()
+
+  * [US20.04]Display not showing imagery (LP: #1970656)
+    - SAUCE: gpu: drm: panel: simple-panel: add DLC0430DCP10RF-2 support
+    - drm/mxsfb: Update mxsfb to support a bridge
+    - drm/mxsfb: Read bus flags from bridge if present
+    - drm/mxsfb: Add defines for the rest of registers
+    - drm/mxsfb: Reset vital registers for a proper initialization
+    - drm/mxsfb: Update register definitions using bit manipulation defines
+    - drm/mxsfb: Update mxsfb with additional pixel formats
+    - drm/mxsfb: Update mxsfb to support LCD reset
+    - drm/mxsfb: Clear OUTSTANDING_REQS bits
+    - MLK-24334-3: drm/mxsfb: Fix the LCD_RESET pin usage
+
+  * [US20.04] OV9281 camera sensor support (LP: #1966824)
+    - SAUCE: media: Add driver for OV9281
+    - SAUCE: media: Fix OV9281 module build and cleanup function names.
+    - SAUCE: media: capture: add grey pixel format used by ov9281 mipi driver.
+    - SAUCE: media: Fix OV9281 calls that search for regulators in the device
+      tree.
+    - SAUCE: dts: amgis: Fix pinctrl-0 for mipi-csi.
+    - [Config] Enable IMX_GPCV2_PM_DOMAINS for armhf.
+
+  * [US20.04] RPMSG driver support (LP: #1968362)
+    - rpmsg: imx: add the initial imx rpmsg support
+    - dt-binding: add imx rpmsg compatibility documentation
+    - rpmsg: imx: extend the rpmsg support for imx8qm and so on
+    - rpmsg: imx: bug fix and clean up the codes
+    - rpmsg: imx_rpmsg: add partition reset notify
+    - rpmsg: imx: enable the tx_block mechanism in the flow
+    - imx-mailbox: add state save and restore
+    - mailbox: imx: change to arch_init()
+    - mailbox: imx: add support for imx v1 mu
+    - SAUCE: ARM: imx: Define M4 related APIs in headers.
+    - clk: imx7d: add A7-M4 AMP power management support
+    - ARM: imx: add i.MX7D bus-freq support
+    - SAUCE: ARM: imx: Add type definition for LPDDR3.
+    - SAUCE: ARM: imx: add suspend/resume support needed for imx7 rpmsg
+      communication with the M4 core.
+    - ARM: imx: add i.MX7D power management support
+    - arm: arch: enable rpmsg for imx amp soc
+    - arm: imx: rename the compatible node of lpm mu driver
+    - MLK-23008 ARM: imx: Remove unused code on i.MX7D suspend driver
+    - LF-1011-26 arm: imx: pm-imx7: fix build break when calling of_flat_dt_match
+    - LF-1011-29 arm: imx: fix build break when calling of_flat_dt_match
+    - SAUCE: ARM: dts: Fix booting imx7 with added changes for
+      suspend/resume/power management.
+    - SAUCE: imx: Fix build error by including cpu type functions.
+    - SAUCE: dts: amgis: Enable rpmsg.
+    - [Config] Enable i.MX7D rpmsg support.
+    - SAUCE: dts: amgis: Fix booting without loading a bare metal m4 application.
+    - SAUCE: ARM: imx7: Use generic names per devicetree specification to fix
+      warnings from pm-imx7.
+    - SAUCE: ARM: imx7: Fix memory mapping for iram_tlb_io_desc by removing the
+      executable flag, resulting in a pagetable warning.
+
+  * [US20.04] Audio does not work (LP: #1966821)
+    - ASoC: tas2562: Introduce the TAS2562 amplifier
+    - ASoC: tas2562: Fix misuse of GENMASK macro
+    - ASoC: tas2562: Add support for digital volume control
+    - ASoC: tas2562: Fixed incorrect amp_level setting.
+    - ASoC: tas2562: Update shutdown GPIO property
+    - ASoC: tas2562: Update shutdown GPIO property
+    - ASoC: tas2562: Add the TAS2110 class-D amplifier
+    - [Config] CONFIG_SND_SOC_TAS2562=m on armhf
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Enable i.MX7D
+    - SAUCE: arm: dts: add Amgis dts files
+    - SAUCE: dts: amgis: Device tree janitorial work
+    - SAUCE: dts: amgis: enable camera in device tree
+    - SAUCE: dts: amgis: use imx internal version of csi bridge/mipi csi node
+    - SAUCE: imx/pe100a: Add dts and defconfig for ASUS PE100A
+    - SAUCE: imx/pe100a: dts: Enable Rohm PMIC on ASUS PE100A
+    - SAUCE: imx/pe100a: dts: Updates for PE100A
+    - SAUCE: imx/pe100a: Add the platform-reset driver to control platform reset
+      gpio
+    - SAUCE: imx/pe100a: Rename the reset driver
+    - [Config] CONFIG_RESET_ASUS_PE100A=m
+    - SAUCE: imx/pe100a: HDMI: auto config physical address for cec
+    - SAUCE: imx/pe100a: hdmi-cec: Set pa only when a property is available
+    - SAUCE: imx/pe100a: HDMI: modify resolution upper limmit to 1920x1080 when
+      noEDID
+    - SAUCE: imx/pe100a: dts: Enable rtc-isl1208
+    - SAUCE: imx/pe100a: dts: Add cpu-alert/crit temperature
+    - SAUCE: imx/pe100a: defconfig: Import thermal config updates
+    - SAUCE: imx/pe100a: dts: Enable Wake-On-LAN
+    - SAUCE: imx/pe100a: extcon: it5201: add IT5201 Type-C CC logic chip
+    - [Config] imx/pe100a: CONFIG_EXTCON_IT5201=m
+    - SAUCE: imx/pe100a: ethernet: Asus LAN2 feature porting
+    - SAUCE: imx/pe100a: dts: EEPROM: support at24 eeprom
+    - SAUCE: imx/pe100a: dts: Audio: disable unavailable sound cards and SAI
+      configurations.
+    - SAUCE: imx/pe100a: defconfig: update defconfig for asus board
+    - SAUCE: imx/pe100a: Gpu: Change gpu shader frequency from 800MHz to 1GHz.
+    - SAUCE: imx/pe100a: CAN: Add MCP2515 support
+    - [Config] imx/pe100a: Enable CONFIG_CAN_MCP251X and CONFIG_CAN_DEBUG_DEVICES
+    - SAUCE: imx/pe100a: enable spi1 and add TCG_TIS_SPI support on 3.0
+    - SAUCE: imx/pe100a: defconfig: Add drivers for moby container engine
+    - SAUCE: imx/pe100a: Remove undefined labels
+    - SAUCE: imx/pe100a: extcon: Fix i2c_device_id array
+    - SAUCE: imx/pe100a: dts: Add usdhc clocks assignment
+    - SAUCE: reset-pe100a: Remove gpio_is_valid() check
+    - SAUCE: net: fec: Fix bit mask definitions
+    - SAUCE: imx/pe100a: Remove assigned PCI clock
+
+  * Miscellaneous upstream changes
+    - soc: imx: fix build error of missing imx_src_is_m4_enabled
+    - irqchip: irq-imx-gpcv2: Add workaround for i.MX8MQ ERR11171
+    - irqchip: irq-imx-gpcv2: Disable cpuidle if no GPC_CORE_WAKE in EL3
+    - irqchip: irq-imx-gpcv2: fix the suspend/resume on imx8mq
+    - MLK-21399 irqchip: Allow i.MX8MQ to call into TF-A
+    - LF-125 irqchip: irq-imx-gpcv2: Fix build error of nosmp
+    - irqchip: imx-gpcv2: Fix build error for imx_v6_v7_defconfig
+    - PCI: imx: add the l1ss feature on imx8m platforms
+    - PCI: imx: enable imx8 pcie pm support
+    - PCI: dwc: Use interrupt disabling instead of masking
+    - PCI: dwc: fix the msi failure after pm operations
+    - Revert "UBUNTU: SAUCE: net: fec: add imx8mq and imx8qm new versions support"
+    - net: fec: add imx8mq and imx8qm new versions support
+    - Revert "net: fec: fix system hang during suspend/resume"
+    - net: fec: add WoL support for i.MX8MQ
+    - net: fec: fix system hang during suspend/resume
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 13 Jul 2022 19:24:36 +0800
+
+linux-imx (5.4.0-1021.23) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.05.30)
+
+  * Focal update: v5.4.184 upstream stable release (LP: #1969242)
+    - [Config] updateconfigs for HARDEN_BRANCH_HISTORY
+
+  * [X6MED][UC20] CAAM crypto engine kernel panic (LP: #1967124)
+    - [Config] enable L2 cache L2X0 and its ERRATA for armhf
+
+  * [imx8-pdk][uc20-x03]Kernel panic while system go into suspend (LP: #1963629)
+    - net: fec: fix system hang during suspend/resume
+
+  * Need POSIX Calls Especially Message Queue (LP: #1944649)
+    - SAUCE: apparmor: move ptrace mediation to more logical task.{h,c}
+    - SAUCE: apparmor: fix setting unconfined mode on a loaded profile
+    - SAUCE: apparmor: fix overlapping attachment computation
+    - SAUCE: apparmor: allow label to carry debug flags
+    - SAUCE: apparmor: extend policydb permission set by making use of the xbits
+    - SAUCE: apparmor: Add fine grained mediation of posix mqueues
+
+  * Enable full-disk encryption (FDE) via OP-TEE (LP: #1953725)
+    - arm: imx: remove GPC low power mode switch
+
+  * [imx8-pdk][imx8-firecpu20][US20.04/UC20] RS-485 didn't worked (LP: #1934083)
+    - MLK-24708 spi: imx: handle EPROBE_DEFER when get cs-gpios number
+
+  * [imx8-pdk][Feature]M7 core (LP: #1935879)
+    - remoteproc: imx_rproc: parse fsl,auto-boot
+    - remoteproc: imx_rproc: initial support for mutilple start/stop method
+    - remoteproc: imx_rproc: make clk optional
+    - remoteproc: imx_rproc: support i.MX7ULP
+    - remoteproc: imx_rproc: support i.MX8MN/P
+    - remoteproc: imx_rproc: support i.MX8ULP
+    - remoteproc: imx_rproc: Fix TCM io memory type
+    - remoteproc: imx_rproc: Fix ignoring mapping vdev regions
+    - remoteproc: imx_rproc: Fix rsc-table name
+    - remoteproc: imx_rproc: Change to ioremap_wc for dram
+    - remoteproc: imx_rproc: Move common structure to header file
+    - remoteproc: imx_rproc: Fix a resource leak in the remove function
+    - remoteproc: imx_rproc: correct firmware reload
+    - MLK-23754-14 remoteproc: elf_loader: drop unneedded memset
+    - MLK-23754-19 remoteproc: add rproc_memcpy
+    - MLK-23754-21 remoteproc: imx_rproc: add imx memcpy functions
+    - SAUCE: remoteproc: imx_rproc: expand the clk array
+
+  * [imx8-pdk] USB port features and functions for OTG (LP: #1936038)
+    - SAUCE: extcon: fix the timer task timeout value
+    - SAUCE: usb: dwc3: add a switch to let drd use extcon on imx8mp
+
+  * [imx8-pdk][Feature]LVDS (LP: #1930804)
+    - MLK-23622-01 soc: imx: Add active wakeup flag for domain with active-wakeup
+      property
+    - MLK-23671-01 soc: imx: Add the rpm always on flag if necessary
+    - MLK-11293: gpio: pca953x: add device_reset() call
+    - gpio: pca953x: no need to do regcache sync without vcc regulator
+    - MLK-23602 gpio: pca953x: no need to show the warning of reg everytime
+
+  * [imx8-pdk] stress-ng cpu cache fail (LP: #1934105)
+    - arm64: dts: imx8m: add cache info
+
+  * [imx8-bms]MAC address not fixed after burned fuse (LP: #1942029)
+    - net: ethernet: add property "nvmem_macaddr_swap" to swap macaddr bytes order
+    - net: fec: add defer probe for of_get_mac_address
+
+  * imx8-pdk: emmc and sdhc index can't be fixed (LP: #1966163)
+    - mmc: add feature of setting slot index via devicetree alias
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: fix the clk for audio and gpu3d
+    - [Config] Enable AUDIOMIX and HDMIMIX reset
+    - SAUCE: clk: clk-imx8mp: Fix gpu2d clks
+    - [config] enable HDMI graphic and audio Kconfigs
+    - [Config] do not enforce reserved CMA sizes in kernel config
+    - [Config] update caam crypto configs
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC=y
+    - SAUCE: sdma: disable rt pm for imx8mp
+    - SAUCE: media: imx8: support to build as module
+
+  * Miscellaneous upstream changes
+    - mfd: Add audiomix support
+    - MA-17597-3 mfd: imx-audiomix: add license for module build
+    - MLK-23250-06: reset: Add hdmimix reset driver
+    - reset: imx: Add audiomix reset controller support
+    - MA-17913 reset: Allow reset-imx7/hdmimix/audiomix driver to be loadable as
+      module
+    - MLK-23159-4 clk: imx: Add i.MX8MP clock driver
+    - arm64: dts: imx8mp: Add clock and power domain to audiomix dts node
+    - MLK-23314-7: clk: imx: clk-audiomix: refine some muxes flags
+    - MLK-23680-1: clk: imx: clk-audiomix: remove sdma root clock
+    - MLK-23886-2: clk: imx: clk-audiomix: fix runtime PM
+    - clk: imx: clk-audiomix: Add SAI PLL frequencies
+    - clk: imx: clk-audiomix: fix PDM clocks
+    - MLK-24307-1 clk: imx: clk-audiomix: enable set parent rate for
+      IMX8MP_CLK_AUDIOMIX_PDM_SEL
+    - ASoC: fsl_sai: Add new added registers and new bit definition
+    - ASoC: fsl-asoc-card: Defer probe when fail to find codec device
+    - clk: imx: Remove the audio ipg clock from imx8mp
+    - MLK-16290 drm: Add drm_of_component_probe_with_match() helper
+    - drm/fourcc: add a 10bits fully packed variant of NV12
+    - drm/imx: Revert a patch which merges imx-drm-core and ipuv3-crtc in one
+      module
+    - drm/imx: Extract IPUv3 specific KMS functions to ipuv3-kms.c (part 1)
+    - drm/imx: Add DPU KMS support (part 2)
+    - MLK-22171 drm/imx: Avoid leaking dangling pointer dev->driver_data to PM ops
+    - MLK-18535-6 drm/imx: core: add LCDIF support
+    - gpu: imx: Add dpu common driver support
+    - drm/imx: Add DPU KMS support (part 1)
+    - MLK-21876-5 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-6 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-7 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-8 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-9 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-10 gpu: drm: dpu: fix headfile reference issue (part 1)
+    - gpu: imx: dpu: framegen: Use bypass clock when display encoder type is TMDS
+    - drm/imx: dpu: crtc: Specify encoder type for framegen_cfg_videomode()
+    - gpu: imx: dpu: framegen: add disp_lpcg clock
+    - MLK-15321-1 gpu: imx: dpu: Add dpu blit engine device
+    - gpu: imx: dpu: fetchunit: Add helper for TKT343664 to fixup burst size
+    - gpu: imx: dpu: fetchunit: Add helper for TKT339017 to fixup stride
+    - gpu: imx: dpu: fetchunit: Use TKT343664's fixup for ->set_burstlength()
+    - gpu: imx: dpu: fetchunit: Use TKT343664&TKT339017's fixups for
+      ->set_baseaddress()
+    - gpu: imx: dpu: fetchunit: Use TKT343664&TKT339017's fixups for
+      ->set_src_stride()
+    - gpu: imx: dpu: fetchunit: Add DPR support
+    - gpu: imx: dpu: Access regs in display engine units wo holding mutex
+    - drm/imx: dpu: crtc: Evade the first dumb frame for DPR/PRG errata
+    - drm/imx: dpu: kms: Add prefetch engine support
+    - drm/imx: dpu: kms: Return properly in case we fail to get plane state to
+      check
+    - drm/imx: dpu: kms: Ensure array idx k >= 0 before accessing sources[]
+    - drm/imx: dpu: crtc: Send vblank event after drm_crtc_vblank_off() in
+      ->atomic_disable()
+    - drm/imx: dpu: crtc: Do not send out bogus vblank event in ->atomic_disable()
+    - drm/imx: dpu: crtc: Remove WARN_ON(!crtc->state->event)
+    - drm/imx: dpu: crtc: Precisely send vbland event if CRTC is active
+    - gpu: imx: dpu: framegen: Add helpers to get/clear sec chan status
+    - drm/imx: dpu: crtc: Warn on FrameGen sec chan empty FIFO read request
+    - drm/imx: dpu: crtc: Wait for FrameGen secondary syncup in ->atomic_enable()
+    - drm/imx: dpu: kms: Support full screen CRTC background
+    - gpu: imx: dpu: Add helpers to peek at auxiliary display submodules
+    - gpu: imx: dpu: common: Add di_grp_id in display client pdev's data
+    - gpu: imx: dpu: common: Introduce master_stream_id in struct dpu_data
+    - gpu: imx: dpu: common: Add helper dpu_get_master_stream_id() support
+    - gpu: imx: dpu: framegen: Add framegen_is_master/slave() helper support
+    - gpu: imx: dpu: extdst: Add extdst_is_master() helper support
+    - gpu: imx: dpu: tcon: Add tcon_is_master/slave() helpers support
+    - gpu: imx: dpu: sc misc: Add helper dpu_pxlink_set_dc_sync_mode() support
+    - gpu: imx: dpu: framegen: Add side-by-side support
+    - gpu: imx: tcon: Add side-by-side support
+    - drm/imx: dpu: crtc: Set crtc group id
+    - drm/imx: dpu: crtc: Peek auxiliary CRTC resources
+    - gpu: imx: dpu: Add pixel combiner support
+    - gpu: imx: dpu: common: Set master stream id to be 1 for i.MX8QM DPU
+    - gpu: imx: dpu: common: Add store9 support for sync mode fixup
+    - gpu: imx: dpu: common: Provide store9 to client pdev via pdata
+    - gpu: imx: dpu: framegen: Add framegen_syncmode_fixup() helper
+    - gpu: imx: dpu: extdst: Add extdst_pixengcfg_syncmode_master() helper
+    - drm/imx: dpu: kms: Add pixel combiner support
+    - drm/imx: dpu: kms: Support proper default blend mode
+    - drm/imx: dpu: plane: Improve bailout path of dpu_plane_create()
+    - drm/imx: dpu: plane: Support full zpos range for planes
+    - drm/imx: dpu: plane: Support alpha in pixel for overlay planes
+    - drm/imx: dpu: plane: Support multiple pixel blend modes
+    - drm/imx: dpu: plane: Add color properties support
+    - gpu: imx: dpu: disengcfg: Do HW initialization in dpu_dec_init()
+    - gpu: imx: dpu: framegen: Cache encoder_type in struct dpu_framegen
+    - gpu: imx: dpu: common: Add flag has_dual_ldb in struct dpu_data
+    - gpu: imx: framegen: Don't enable/disable pixlnk when driving special encoder
+    - gpu: imx: dpu: sc misc: Rename dpu_sc_misc_init() to
+      dpu_sc_misc_get_handle()
+    - gpu: imx: dpu: sc misc: Rename dpu_pxlink_init() to dpu_sc_misc_init()
+    - LF-73 gpu: imx: dpu: sc misc: Initialze KACHUNK_CNT as needed by blit engine
+    - gpu: imx: dpu: common: Initialize SCU misc settings in dpu_resume()
+    - MLK-21378-1 gpu: imx: Add imx8_prg support
+    - MLK-21378-2 gpu: imx: Add imx8_dprc support
+    - gpu: imx: Add imx8 pixel combiner support
+    - drm/imx: ldb: Add i.MX8qm LDB support
+    - drm/imx: ldb: Add i.MX8qxp LDB support
+    - MLK-21876-23 drm/imx: ldb: fix incorrect color displayed for mx8qxp
+    - drm/imx: ldb: Add system power management support
+    - drm/imx: ldb: Add dual channel mode support for i.MX8QXP
+    - drm/imx: Extract IPUv3 specific KMS functions to ipuv3-kms.c (part 2)
+    - drm/imx: ipuv3-crtc: Rename some IPUv3 specific functions
+    - MLK-18535-3 gpu: imx: add LCDIF core driver
+    - MLK-18535-5 drm/imx: add LCDIF DRM/KMS driver
+    - gpu: imx: lcdif: break Kconfig recursive dependency
+    - MLK-18535-10 drm/imx: lcdif: limit the maximum resolution to '1920x1080'
+    - MLK-18560 drm/imx: lcdif: refine bus format sanity check for plane
+    - MLK-18605-14 drm/imx: lcdif: adjust 'max_height' for '1080x1920' mode
+    - MLK-19017-2 gpu: imx: add DISPMIX power domain support for LCDIF
+    - MLK-19017-3 gpu: imx: add system pm support for LCDIF
+    - MLK-19017-4 gpu: imx: lcdif: add rpm status check for suspend/resume
+    - MLK-19083 drm/imx: lcdif: remove untrue condition for pixel format set
+    - MLK-19112 gpu: imx: lcdif: change 'rpm_suspended' to be atomic counter
+    - MLK-19152-1 gpu: imx: lcdif: realize fb horizontal crop via Pigeon Mode
+    - MLK-19152-2 drm/imx: lcdif: force 'mode_changed' when fb width changed
+    - MLK-19152-3 drm/imx: lcdif: add horizontal crop support to plane update
+    - MLK-19199 drm/imx: lcdif: replace FB width usage for cropping
+    - MLK-19158-2 drm/imx: lcdif: improve output bus format config
+    - MLK-19158-3 gpu: imx: lcdif: fix output order for 16bpp BGR formats
+    - MLK-19158-4 drm/imx: lcdif: remove bus format check from PLANE's check
+    - MLK-19158-5 drm/imx: lcdif: add bus format check to CRTC's check
+    - MLK-19318 drm/imx: lcdif: avoid log print when no device attached
+    - MLK-19819-1 drm/imx: lcdif: bypass atomic check when CRTC will be disabled
+    - MLK-19819-2 Revert "MLK-19318 drm/imx: lcdif: avoid log print when no device
+      attached"
+    - MLK-20337 drm/imx: lcdif: block 'active CRTC with no plane' commit
+    - MLK-22158 drm/imx: lcdif: force 'mode_changed' for fb pix fmt change
+    - MLK-21876-10 gpu: drm: lcdif: fix headfile reference issue
+    - drm/imx: lcdif: change DISPMIX reset for IMX8MN
+    - gpu: imx: lcdif: fix build warnings if CONFIG_PM_SLEEP off
+    - drm/imx: Replace reset flow for LCDIF
+    - gpu: imx: lcdif: add imx8mn compatible support
+    - drm/bridge: Add ITE IT6263 LVDS to HDMI transmitter support
+    - MLK-18535-7 drm/bridge: sec-dsim: add bridge driver support
+    - MLK-19081 drm/bridge: sec-dsim: correct args of 'drm_bridge_attach' call
+    - MLK-18605-1 drm/bridge: sec-dsim: add cleanup when detach dsi client
+    - MLK-18605-2 drm/bridge: sec-dsim: allow same panel can be re-attached
+    - MLK-18605-3 drm/bridge: sec-dsim: refuse unknown dsi device attach
+    - MLK-18605-4 drm/bridge: sec-dsim: refine data lanes stop state check
+    - MLK-18605-5 drm/bridge: sec-dsim: correct 'DSIM_FIFOCTRL' offset
+    - MLK-18605-6 drm/bridge: sec-dsim: add fifo pointers initialization
+    - MLK-18605-7 drm/bridge: sec-dsim: correct a register macro misspelt
+    - MLK-18605-8 drm/bridge: sec-dsim: add non-continuous clock support
+    - MLK-18605-9 drm/bridge: sec-dsim: increase timeout values for BTA and LPRX
+    - MLK-18605-10 drm/bridge: sec-dsim: complete mipi panel support
+    - MLK-19017-5 drm/bridge: sec-dsim: add DISPMIX power domain support
+    - MLK-19082 drm/bridge: sec-dsim: wait 'ph_tx_done' for long packet send
+    - MLK-19252-1 drm/bridge: sec-dsim: move PLL check to DSIM Encoder
+    - MLK-19252-3 drm/bridge: sec-dsim: workaround 3 data lanes case
+    - MLK-19252-4 drm/bridge: sec-dsim: improve HT configs
+    - MLK-19252-5 drm/bridge: sec-dsim: improve PLL PMS configs
+    - MLK-19252-6 drm/bridge: sec-dsim: improve DPHY TIMING configs
+    - MLK-19252-7 drm/bridge: sec-dsim: workaround for 720p@60Hz on 4 lanes
+    - MLK-19317-2 drm/bridge: sec-dsim: fine tune for '720p@60Hz' mode on 2 lanes
+    - MLK-19400-1 drm/bridge: sec-dsim: correct one fail branching
+    - MLK-21150-1 drm/bridge: sec-dsim: change uint64_t clk fields to uint32_t
+    - MLK-21150-2 drm/bridge: sec-dsim: refine hblank word count compute
+    - MLK-18535-13 dt-bindings: display: bridge: add sec-dsim bindings
+    - MLK-21150-3 drm/bridge: sec-dsim: add a new property 'pref-rate'
+    - MLK-21150-4 drm/bridge: sec-dsim: a general way to compute PLL PMS
+    - MLK-21252 drm/bridge: sec-dsim: resolve OVERFLOW_BEFORE_WIDEN warns
+    - MLK-21383 drm/bridge: sec-dsim: fix maybe-uninitialized build warnings
+    - MLK-21880-1 drm/bridge: sec-dsim: correct DSIM version register access
+    - MLK-21911 drm/bridge: sec-dsim: free 'pll_pms' to avoid memory leak
+    - MLK-21274-3 drm/bridge: sec-dsim: add defer probe support
+    - MLK-21274-2 drm/bridge: sec-dsim: remove bridge assign for encoder
+    - MLK-20687 drm/bridge: sec-dsim: correct LPM config for Long Packet
+    - MLK-20438 drm/bridge: sec-dsim: remove 'FORCEBTA' for packet send
+    - MLK-17275-2: drm/bridge: it6263: Add support for OF_DYNAMIC
+    - MLK-18535-8 drm/imx: sec_mipi_dsim-imx: add DSIM host driver
+    - drm/imx: add DISPMIX power domain support for SEC DSIM
+    - MLK-19017-6 drm/imx: add system pm support for SEC DSIM
+    - MLK-19017-7 drm/imx: sec-dsim_imx: add rpm status check for suspend/resume
+    - MLK-19158-1 drm/imx: sec-dsim_imx: add bus format check for ENCODER
+    - MLK-19537-3 drm/imx: sec-dsim_imx: remove dphy slave reset
+    - drm/imx: sec-dsim_imx: move PLL check to DSIM Encoder
+    - drm/imx: sec-dsim_imx: improve DPHY TIMING configs
+    - MLK-19400-2 drm/imx: sec-dsim_imx: alter 'rpm_suspended' to a counter
+    - drm/imx: sec-dsim_imx: a general way to compute PLL PMS
+    - drm/imx: sec-dsim_imx: correct DSIM version register access
+    - drm/imx: dsim: change DISPMIX reset for IMX8MN
+    - MLK-22304-1 drm/imx: dsim: fix build warnings if CONFIG_PM_SLEEP off
+    - drm/imx: Replace reset flow for DSIM
+    - drm/imx: sec-dsim_imx: add resets put for probe failure
+    - drm/imx: sec_dsim-imx: add imx8mn compatible support
+    - drm/bridge: Add NWL MIPI DSI host controller support
+    - drm/bridge: nwl-dsi: Add support for video_pll
+    - drm/bridge: nwl-dsi: Add support for clock-drop-level
+    - drm/bridge: nwl-dsi: fix nwl-dsi when used as module
+    - drm/bridge/nwl-dsi: add support for DCSS
+    - drm: bridge: add Cadence MHDP HDMI/DP API
+    - drm: bridge: Add Cadence DP/HDMI core driver
+    - gpu: drm: Add imx8qm/mq DP/HDMI driver
+    - drm: bridge: cadence: Add new api functions
+    - drm: bridge: cadence: Add mhdp audio driver
+    - drm: bridge: cadence: Add CEC driver for cdns mhdp hdmi
+    - drm: bridge: cadence: move struct imx_mhdp_device to drm/imx
+    - drm: imx: add imx8mq hdmi support
+    - drm: bridge: cadence: Add power_on to __cdns_dp_probe
+    - drm: ls1028a: Add DP driver support for LS1028A
+    - drm: bridge: cadence: Add support for periodically poll the connector
+    - drm: imx: hdmi: support arc function
+    - drm: bridge: cadence: Fix return value for set log addr
+    - drm: bridge: cdns dp: Remove link rate/lanes set by device tree
+    - drm: imx: mhdp: add dual mode support for imx8qm
+    - drm: bridge: cdns cec: fix LA failed set issue
+    - DRM: mhdp: HDMI: skip scdc write return check
+    - drm: mhdp: add mutex lock to mhdp register access function
+    - drm: mhdp: reset video mode after hdmi/dp cable plugin
+    - drm: bridge: cadence: hdmi: remove video mode limition
+    - drm/imx/hdp: add hdr10 metadata property
+    - drm/imx/hdp: add colorspace property
+    - drm/imx/hdp: force a mode set when colorspace is changed
+    - drm/imx/hdp: handle the various deep-color settings
+    - MLK-15321-2 gpu: imx: dpu: Add dpu blit engine driver
+    - MLK-15321-3 drm/imx: dpu: Add render feature support
+    - MLK-15321-4 drm/imx: core: Add bliteng as component of imx-drm
+    - MLK-17311 gpu: imx: dpu-blit: enable prefetch feature
+    - MGS-4061 gpu: imx: dpu-blit: fix kernel panic in pm test
+    - MGS-3940 gpu: imx: dpu-blit: fix first frame handler
+    - MGS-4051 gpu: imx: dpu-blit: fix suspend resume issue
+    - MGS-3940 gpu: imx: dpu-blit: fix dpr hang for smaller size
+    - MGS-4265 gpu: imx: dpu-blit: fix video hang with g2d compositor
+    - gpu: imx: dpu-blit: Do not initialize STORE9_STATIC register
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: add busfreq support
+    - drm: imx: dcss: Fix for renaming reservation.h to dma-resv.h
+    - Revert "drm: imx: dcss: Fix for renaming reservation.h to dma-resv.h"
+    - Revert "drm/imx/dcss: add busfreq support"
+    - Revert "drm/imx: Add initial support for DCSS on iMX8MQ"
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: use the external 27MHz phy clock
+    - drm/imx/dcss: add busfreq support
+    - drm/imx/dcss: add support for DEC400D
+    - drm/imx/dcss: add support vor video overlays
+    - drm/imx/dcss: remove reference to P010
+    - drm/imx/dcss: add WRSCL/RDSRC support
+    - drm/imx/dcss: add support for NV12_10LE40 format
+    - drm/imx/dcss: eliminate unnecessary formats from planes
+    - drm/imx/dcss: add color management properties to video planes
+    - drm/imx/dcss: change HDR10 pipes config handling
+    - drm/imx/dcss: add support for tiled formats on overlay planes
+    - drm/imx/dcss: fix crash in DTRC exit routine
+    - drm/imx/dcss: Release DTRC IRQs in case of failure
+    - drm/bridge/nwl-dsi: fix attach flow of downstream bridge
+    - drm: imx: mhdp: Adjustment core rate of DP TX CTRL for LS1028A
+    - LF-46 drm/imx: sec-dsim: use late suspend
+    - drm/imx/hdp: fix issue with non-SCDC HDMI sinks
+    - drm/bridge: nwl-dsi: Add support for component framework
+    - drm/bridge: nwl-dsi: Add support for 8QM and 8QXP
+    - drm/bridge: nwl-dsi: Fix find_panel_or_bridge
+    - gpu: imx: framegen: Use crtc_clock instead of mode clock
+    - drm/bridge: nwl-dsi Correct the DSI init sequence
+    - Revert "drm/imx/hdp: fix issue with non-SCDC HDMI sinks"
+    - drm: hdmi: imx8: fix wrong hdmi type with non-SCDC HDMI sinks
+    - LF-94: drm: hdmi: imx: Add hdmi phy video mode valid function
+    - LF-283 gpu: imx: dpu: common: Get irq count properly
+    - LF-296: drm: mhdp: build mhdp sub-modules into one driver module
+    - LF-282 drm/imx: dpu: Kconfig: Add prompt string for DRM_IMX_DPU
+    - LF-335 drm/bridge: sec-dsim: solve fallthrough build warnings
+    - LF-95-4 drm/bridge: nwl-dsi: Correct register offsets for tx_ulps and
+      pxl2dpi
+    - LF-95-5 drm/imx: imx-ldb: Correct control register offset for i.MX8QM/QXP
+      LDB
+    - drm/bridge: nwl-dsi: Fix phy_ref clock ordering
+    - MLK-21231 gpu: imx: dpu: framegen: Wait for 100ms at most for secondary
+      syncup
+    - LF-323-1: drm/bridge/cdns: move link training to bridge enable function
+    - LF-323-2: drm/bridge/cdns: enhance link training stability
+    - LF-407-1: drm/imx/dcss: fix compilation issues after rebase
+    - LF-407-2: drm/imx/dcss: fix module insertion hang
+    - LF-407-3: drm/imx/dcss: remove unnecessary sleep
+    - LF-424 gpu/imx: lcdif: fix typo for imx_lcdif_dt_ids
+    - LF-425-2 drm/bridge: sec-dsim: use 'attach-bridge' for bridge attach
+    - LF-568-1: drm: bridge: cdns: dp: change bridge_enable/disable name
+    - LF-568-2: drm: gpu: bridge: cdns: Add force mode set flag
+    - MLK-23234-4 gpu: imx: add LCDIFv3 core driver
+    - MLK-23234-6 drm/imx: add LCDIFv3 DRM/KMS driver
+    - MLK-23234-7 drm/imx: core: add LCDIFv3 support
+    - MLK-23234-8 drm/imx: sec-dsim: add imx8mp compatible
+    - MLK-23234-9 drm/imx: sec-dsim: bypass mediamix resets on imx8mp
+    - MLK-23245 gpu: imx: lcdifv3: correct panic thresholds calculation
+    - MLK-23248 gpu: imx: lcdifv3: correct panic enable register typo
+    - MLK-23250-02: drm: lcdifv3: Change frame size limit to 4096
+    - MLK-23250-04: lcdifv3: Add hdmimix lcdifv3 support
+    - MLK-23250-09: drm: imx: pavi: Add PAVI driver for iMX8MP HDMI
+    - MLK-23250-10: drm: imx: hdmi: Add iMX8MP hdmi driver
+    - MLK-23287-3: drm: imx: hdmi: Add iMX8MP hdmi gp audio driver
+    - MLK-23218 gpu: imx: lcdifv3: Change burst size to 256B
+    - LF-900: drm/imx/dcss: Fix kernel panic during suspend
+    - MLK-23252-3 gpu: imx: lcdifv3: Support client specific pdev id
+    - MLK-23252-4 gpu: imx: lcdifv3: Add compatible string for LDB's LCDIFv3
+    - MLK-23252-8 drm/imx: imx-ldb: Rename flag is_imx8 to is_imx8q
+    - MLK-23252-9 drm/imx: imx-ldb: Add i.MX8mp LDB support
+    - LF-794 gpu: cdn: imx8qm: Add firmware loading support
+    - LF-794 gpu: cdn: mhdp-common: Increase the check alive timeout
+    - MLK-23328: drm: bridge: hdmi: Fix no vendor infoframe after resume
+    - MLK-23102-1 drm/imx: dpu: kms: Remove fetchunit pin-off mechanism
+    - MLK-23102-2 gpu: imx: dpu: fetchunit: Remove pin-off operations
+    - MLK-23109 drm/imx: dpu: plane: Always enable DPRC when prefetch is needed
+    - MLK-23107-1 gpu: imx: imx8_dprc: Add helper dprc_disable_repeat_en()
+    - MLK-23107-2 drm/imx: dpu: kms: Disable DPRC repeat_en in ->atomic_flush()
+      where necessary
+    - MLK-23187-1 gpu: imx: dpu: framegen: Increase timeout again when waiting for
+      moving
+    - MLK-23187-2 drm/imx: dpu: crtc: Disable DPRC repeat_en in ->atomic_disable()
+    - MLK-23221: drm/bridge: nwl-dsi: Call panel enable early
+    - LF-841: drm/bridge: nwl-dsi: Fix mode_set
+    - LF-842-1: drm/bridge: nwl-dsi: Change mipi clocks re-parenting
+    - LF-555: drm: mhdp: Improve the AUX channel signal for DP port
+    - MLK-23425-1 gpu/imx: lcdifv3: enable frame clear
+    - MLK-23425-2 gpu/imx: lcdifv3: add dma disable
+    - MLK-23428 drm/imx: sec-dsim: add bound check in runtime suspend/resume
+    - MLK-23522: drm/imx: lcdifv3: remove unsupported formats
+    - MLK-23544: drm: gpu: dw_hdmi: check imx8mp hdmi phy support clk rate
+    - MLK-23538-1: drm: gpu: dw_imx: add CEC enable bit set
+    - LF-452: gpu: drm: bridge: hdmi: Add CEA mode check
+    - MLK-23576 gpu/imx: lcdifv3: add system sleep PM ops
+    - MLK-23545-1: drm: bridge: hdp: Remove force_mode_set flag when cable plugin
+    - MLK-23545-2: drm: imx: mhdp: weston8 UI recovery after cable plugout/in
+    - LF-1189-2 gpu: imx: dpu: tcon: Add MEDIA_BUS_FMT_RGB565_1X30_PADLO support
+    - LF-1189-3 gpu: imx: dpu: framegen: Add DPI encoder support
+    - LF-1189-5 drm/imx: Add LCDIF mux display support
+    - MLK-23767 gpu: imx: dpu: common: avoid deattach multiple power domain
+    - MLK-20486 drm/imx: ldb: Cleanup enc&conn in ->unbind() if necessary
+    - LF-1256-1 drm/imx: imx-ldb: Allocate imx_ldb in ->probe() instead of
+      ->bind()
+    - LF-1256-2 drm/imx: lcdif-mux-display: Allocate lmuxd in ->probe() instead of
+      ->bind()
+    - LF-1256-3 drm/imx: dpu: crtc: Allocate dpu_crtc in ->probe() instead of
+      ->bind()
+    - MLK-23781-1 drm/imx: lcdifv3: move 'lcdifv3_crtc' alloc to probe
+    - MLK-23781-2 drm/imx: lcdifv3: remove 'lcdifv3_plane_deinit()'
+    - MLK-23781-3 drm/imx: sec-dsim: move 'dsim_dev' alloc to probe
+    - MLK-23781-4 drm/imx: sec-dsim: initialize 'rpm_suspended' in probe
+    - MLK-23694-6 drm/imx: ldb: remove PLL clock rate set for i.MX8M
+    - MLK-23694-9 drm/imx: sec-dsim: put resets in unbind() to fix memory leak
+    - MLK-23694-10 drm/imx: sec-dsim: NULL panel ptr when host detached
+    - MLK-23694-11 drm/imx: sec-dsim: allow bind for no display attached
+    - MLK-23817 gpu: imx: dpu: common: Enable power for dpu irq chip at probe
+      stage
+    - MLK-23642-1: drm: bridge: cadence: support HBR and 6 channel
+    - MLK-23885 drm/imx: ldb: Add mode fixup for i.MX8mp LDB in ->atomic_check()
+    - MLK-23903 drm/imx: imx-ldb: Disable both two channels for split mode in
+      enc->disable()
+    - MLK-23904 drm/imx: imx-ldb: Cache split mode status in struct imx_ldb
+    - MLK-23905-1 drm/bridge: Add fsl imx ldb support
+    - MLK-23905-2 drm/imx: imx-ldb: Use platform specific encoder drivers
+    - MLK-23942-6 drm/bridge: fsl-imx-ldb: Add runtime PM support
+    - MLK-23942-7 drm/imx: imx8mp-ldb: Add runtime PM support
+    - MLK-23942-8 drm/imx: imx8qm-ldb: Add runtime PM support
+    - MLK-23942-9 drm/imx: imx8qxp-ldb: Add runtime PM support
+    - LF-621: drm/imx/dcss: add back disabled formats
+    - MLK-24002-1 drm/imx: lcdifv3: enable shadow load for plane update
+    - MLK-24002-2 drm/imx: lcdifv3: put controller enable to CRTC
+    - MLK-24040: drm: imx: pavi: Combine pai and pvi powerup/down function
+    - MLK-24045 drm/imx: sec-dsim: let host unregister later than device
+    - MLK-24065-1: drm: bridge: cadence: fix dp_aux_transfer write return value
+    - MLK-24065-2: drm: bridge: cadence: print error when clock recovery fails
+    - MLK-24065-3: drm: bridge: cadence: use the lane mapping from dt when setting
+      host capabilities
+    - MLK-24072: drm: imx8: correct mhdp files copyright
+    - MLK-24076-2: drm: imx: hdmi: Add copyright
+    - LF-1043: drm/bridge: nwl-dsi: Assert mipi resets before enable
+    - LF-811-1: drm/bridge: Add driver for legacy Freescale Seiko 43WVFIG adapter
+    - MLK-24168 drm/imx: dpu: kms: Avoid -EDEADLK warning when getting crtc_state
+      in ->atomic_check
+    - MLK-24190: drm: imx: dw_hdmi: Add resume function
+    - MLK-24146 drm: dw_hdmi: cec: Add cec suspend/resume function
+    - LF-1444 gpu: imx: dpu: common: Check of_match_device() return value in
+      dpu_probe()
+    - LF-1442-1 drm/imx: sec-dsim: avoid dereference NULL ptr of of_id
+    - LF-1442-2 drm/imx: lcdif: avoid dereference NULL ptr of of_id
+    - LF-1442-3 drm/imx: lcdifv3: avoid dereference NULL ptr of of_id
+    - MLK-24293 gpu/imx: lcdifv3: use late system sleep pm ops
+    - LF-1510: gpu: drm: lcdifv3: null return value check for of_id
+    - LF-1510-2: gpu: drm: dw_hdmi: null return value check
+    - LF-1511: drm: cdn-cec: replace ++i with i++ in loop
+    - LF-1512: drm: cdns mhdp: avoid potentially overflowing
+    - LF-1514: drm: cdns-mhdp: check link rate index
+    - LF-1516: drm: cdns-mhdp: fix error check variable name for clk_pxl_link
+    - MLK-24335: drm: bridge: cdns: hdmi support work in DVI mode
+    - LF-1555: drm: bridge: nwl-dsi: Fix null-pointer dereference
+    - LF-1556: drm/bridge: nwl-dsi: Fix potential null-pointer dereference
+    - MLK-21509-1 gpu: imx: dpu: common: Add signature unit support
+    - MLK-21509-2 gpu: imx: dpu: disengcfg: Add signature select support
+    - MLK-21509-3 drm/imx: dpu: kms: Add auto control mode debugfs CRC support
+    - MLK-21509-4 drm/imx: dpu: crc: Add user-configurable CRC region(ROI) support
+    - LF-1750 gpu: imx: imx8_dprc: Get scu ipc handle in ->probe()
+    - LF-1485: drm: bridge: dw_hdmi: null pointer check
+    - LF-1526: drm/imx/dcss: Fix Coverity issue
+    - MLK-24427-1: drm: gpu: imx: Move cdns driver files to mhdp folder
+    - MLK-24427-2: drm: bridge: cdns: Move DP API functions to separate file
+    - MLK-24427-3: drm: mhdp: Backporting code change from linux-nxp
+    - LF-2011 gpu: imx: imx8_dprc: Check return value of SCU func call in
+      dprc_dpu_gpr_configure()
+    - LF-2010 gpu: imx: imx8_dprc: Check return value of SCU func call in
+      dprc_prg_sel_configure()
+    - MLK-24519 gpu: imx: Increase maximum single pipe width to 2560
+    - MLK-24520: drm: bridge: cdns: increase maximum width from 4096 to 5120.
+    - MLK-24521: drm: bridge: hdmi: Prevent the driver from rejecting VIC 0 modes
+    - MLK-24522: drm/imx: dpu: Increase iMX DRM CTRC size to 5120 x 4096
+    - drm: bridge: dw-hdmi: Report connector status using callback
+    - MLK-24611-1: drm: bridge: synopsys: Add callback function for plug/unplug
+      event
+    - MLK-24611-2: drm: bridge: cdns: Add callback function for plug/unplug event
+    - MLK-24601: drm: imx: mhdp: DP PHY support 1/2 lanes mode
+    - MLK-24608: drm/imx/dcss: disallow certain modes
+    - MLK-24770: drm: mhdp: Sync DPTX capability with Cadence sample code
+    - MLK-24900-1 drm/imx: lcdifv3: Use dts to config LCDIF panic threshold
+    - MLK-24916-1: drm: bridge: synopsys: fix eld length issue
+    - MLK-24916-3: drm: bridge: synopsys: Add HBR support for gp audio
+    - MLK-24998-4 drm/bridge: sec-dsim: use 12MHz for default PHY REF clock
+    - MLK-24998-7 drm/imx: lcdifv3: implement mode_valid() for CRTC
+    - MLK-25012 drm/imx: lcdif: move 'lcdif_crtc' alloc to probe()
+    - MLK-24911-3: drm: imx: sec-dsim: Adjust the LDO trim value
+    - MLK-25101: drm: imx: dw_hdmi: Keep hdmi phy in poweron status
+    - MLK-25228: drm: dw-hdmi: Pass CTS 7-30 Audio InfoFrame
+    - MLK-25156: drm: dw_hdmi: reset hdmi phy power
+    - MLK-24491: drm: bridge: cdns: Add support of i2c-over-aux
+    - MLK-25340-1: drm: imx: hdp: Added power off function
+    - MLK-25340-2: drm: imx: mhdp: Adding power off to driver remove
+    - drm/imx: ipuv3-kms: Move to a new ipuv3 folder
+    - MLK-21876-10 gpu: drm: ipu: fix headfile reference issue (part2)
+    - Revert "drm/imx: Use simple encoder"
+    - Revert "drm/imx: pd: Use bus format/flags provided by the bridge when
+      available"
+    - drm/fourcc: add modifier for vivante compressed tiled layout
+    - MLK-15110-1 drm/fourcc: Add Amphion tiled layout format modifier
+    - MLK-17368-1 drm: add fourcc codes for Verisilicon tiled formats
+    - dt-bindings: firmware: imx: add scu clock type IDs
+    - MLK-23329-01 dt-bindings: imx: update sc ctrl interfaces
+    - media: bus format: Add RGB888_1X30_PADLO support
+    - media: bus format: Add RGB666_1X30_PADLO support
+    - media: bus format: Add RGB101010_1X7X5_SPWG/JEIDA support
+    - LF-1189-1 media: bus format: Add RGB565_1X30_PADLO support
+    - reset: Add driver for dispmix reset
+    - reset: imx8m: Correct clock name for dispmix driver
+    - LF-218 reset: dispmix: remove dev when init mmio regmap
+    - MLK-23250-07: clk: imx: add imx8mp hdmimix clk driver
+    - MLK-23538-2: clk: hdmimix: set cec clock parent to 32k_clk
+    - MLK-23356: reset: Remove noc reset bit from hdmimix reset
+    - MLK-23250-08: phy: Add samsung hdmi phy driver
+    - MLK-23542: phy: support more pixel rates
+    - MLK-24041: phy: fsl: sync code change with LF branch
+    - MLK-24397 phy: samsung hdmi: support more clock rate
+    - MLK-23252-6 phy: freescale: Add i.MX8mp LVDS PHY support
+    - MLK-23616-3 phy: fsl-imx8mp-lvds: Enable/disable APB clock when necessary
+    - MLK-23942-3 phy: freescale: phy-fsl-imx8mp-lvds: Add runtime PM support
+    - irq: imx: irqsteer: add multi-pd support for irqsteer
+    - MLK-23250-05: irqchip: imx-irqsteer: Add reset function
+    - MLK-17290-01 irqchip: imx-irqsteer: add runtime pm support
+    - MLK-23750-1: irqchip: imx: fix ISI_0, CSI_0 can't enter lp when suspend
+    - MA-17912 irqchip: irqsteer: Allow IMX_IRQSTEER to be loadable as module
+    - MLK-23252-1 clk: imx8mp: Add DISP2 pixel clock
+    - MLK-23252-2 clk: imx8mp: Add LDB root clock
+    - MGS-4530-1 add 6.2.4.p4 gpu driver for L4.19
+    - MGS-4530-2 disable busfreq-imx to fix L4.19 dash build
+    - MGS-4530-3 [#imx-1314] include dma-direct.h to fix gpu build for L4.19
+    - gpu: fix access_ok build error
+    - gpu: fix do_gettimeofday build error
+    - gpu: fix totalram_pages build error
+    - gpu: more build fix
+    - gpu: imx: fix gpu boot hang by defer driver register time
+    - MLK-21876-11 gpu: fix build for next-20190524 upgrade
+    - gpu: Update SCU API and change the method to distinguish 8QM/8QXP from other
+      boards
+    - gpu:Integrate 6.4.0 kernel driver for Linux L5.x
+    - gpu: fix build break due to dma headfile include
+    - gpu:Remove dma.h to avoid Linux 5.x build problem
+    - gpu-viv: Fix writecombine/wc build error
+    - MGS-5252 Integrate Vivante 6.4.0.p1 GPU driver
+    - MGS-5176 [#imx-1744] Coverity issue of 6.4.0.p1.
+    - MGS-5176-2 [#imx-1744] Need free the pages if malloc memory failed
+    - MGS-4376 [#imx-1238] fix low performance with CMA allocator
+    - MGS-5283 [#imx-1238] fix GPU memory without CMA
+    - MGS-5283 [#imx-1784] fix GPU AXI bus error
+    - MGS-5284 [#imx-1786] fix GPU panic with vm_mmap failure
+    - MGS-5261 [#imx-1771] fix dummy draw hang for 8MM GPU
+    - QSDK-5959 [#ccc] update the platform driver to support layerscape soc
+    - MGS-5307 gpu: integrate 6.4.0.p2 driver
+    - MGS-5245 [#imx-1755] [8MN_EVK] VTK: fix the gpu dump when enable vProfile
+    - LF-84 [#imx-1834] remove gpu coherent_dma_mask setting
+    - Add Malone decoder and windsor encoder for QXP/QM
+    - Add directory driver/mxc and related scripts
+    - arm64: vpu: m850d: hantro
+    - arm64: vpu: m850d: hantro: mxc config
+    - vpu: hantro: fix build failure
+    - vpu: malone: fix build failure
+    - vpu: windsor: fix build failure
+    - vpu: windsor: remove deprecated using of s_crop/g_crop
+    - vpu: windsor: remove deprecated using of VB2_BUF_STATE_PREPARED
+    - vpu: windsor: fix build error
+    - vpu: malone decoder: porting from 4.19 rc3 release
+    - vpu: malone decoder: porting from 4.19 rc3 release
+    - vpu: windsor encoder: porting from 4.19 rc3 release
+    - vpu: windsor encoder: porting from 4.19 rc3 release
+    - MLK-21876-22 vpu: build for ARM64 only
+    - MLK-21985-2 vpu: malone: b0: fix build for next 20190607 upgrade
+    - MLK-21985-3 vpu: windsor: b0: fix build for next 20190607 upgrade
+    - media: vpu_malone: fix boot warning by intialize device_caps
+    - media: vpu_windsor: fix boot warning by intialize device_caps
+    - vpu: hantro: fix build error when enabling 'CONFIG_DEVICE_THERMAL'
+    - vpu: malone: encoder: add mu2 power domain for imx8qm
+    - vpu: hantro: add decoder for imx845
+    - vpu: hantro: add encoder for imx845 h1
+    - vpu: imx6: add decoder/encoder
+    - vpu: imx6: add decoder/encoder
+    - vpu: hantro_845_h1: fix compat_ptr building issue
+    - vpu: windsor encoder: add vpuenc2 power domain for imx8qm
+    - vpu: windsor encoder: enable mailbox and unify code
+    - vpu: malone decoder: enable mailbox and unify code
+    - vpu: windor encoder: malone decoder: fix kernel panic caused by MU_Init
+    - MLK-22913 vpu: windsor malone: fix kernel panic caused by directly read MU
+    - MLK-22920 vpu: windsor encoder: change the writeable flag synchronously
+    - vpu: hantro: Fix kconfig to depend on ARCH_MXC instead
+    - MLK-22951 mxc: vpu_malone: add missing semicolon
+    - MLK-22952 mxc: vpu_windsor: add missing semicolon
+    - vpu: hantro: Fix kconfig to depend on ARCH_MXC instead
+    - MLK-22945 mxc vpu_malone: disable decode ctx before release it.
+    - MLK-22963 mxc vpu_windsor: fix call vzalloc during spinlock
+    - MLK-22991 mxc: vpu_malone vpu_windsor: check is vpu poweroff when suspend
+    - MLK-22999 mxc: vpu_malone: release debugfs after open to avoid memory leak
+    - LF-80:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:clear eos flag when output streamoff
+    - MLK-10600-1: mxc: sim: Add SIM IP driver support on the i.MX7d-12x12-arm2
+      platform.
+    - MLK-10600-2: mxc: sim: add an option to enable SIM driver build
+    - MLK-10913-1: mxc: sim: Add the SIM driver support for i.MX6UL-EVK platform.
+    - MLK-10959: mxc: sim: Disable cwt timer when tx and enable in rx.
+    - MLK-10968: mxc: sim: Add the init delay detection function in the driver.
+    - MLK-10976: mxc: sim: Using timer interrupt to implement precise timing.
+    - MLK-11354 sim: imx: relapce devm_request_and_ioremap with
+      devm_ioremap_resource
+    - MLK-11777 sim: imx: remove useless code
+    - MLK-11472 sim: imx: set sim1 IOMUX to default state
+    - MLK-14642 imx: sim: fix segment fault caused by user address access
+    - MLK-13473: imx_sim: fix module device table name
+    - MLK-17319-1 imx8: sim: add driver to support EMVSIM module
+    - MLK-17416 imx8: sim: add usleep_range() before reading SPDP Bit
+    - MLK-18485 emvsim: enable CWT for ATR
+    - MLK-22210 mxc: emvsim: enable ICM mode
+    - MLK-22211 mxc: emvsim: should not clear PEF/FEF flag in irq handler
+    - MLK-22213 mxc: emvsim: read TS character before updating value of GPCNT1
+    - MLK-22214 mxc: emvsim: clean up the code in ATR stage
+    - MLK-22215 mxc: emvsim: correct irq mask and clear irq status before
+      receiving
+    - MLK-22216 mxc: emvsim: last character need be transmitted separately with no
+      guard time
+    - MLK-22217 mxc: emvsim: add value adjustment for cwt/bwt timer
+    - sim: emvsim: add multi power domain support
+    - MLK-11442 mlb: imx: add mlb support on imx_4.1.y
+    - imx: mlb: Replace ACCESS_ONCE with READ_ONCE
+    - MLK-11910 mxc: mlb: fix irq unsigned_compare issue
+    - MLK-12185 mlb: imx: fix the operation for mlb status in mlb_isr
+    - MLK-15987 imx: mlb: use dma pool when iram doesn't exist
+    - MLK-15988 imx: mlb: remove clk for mlb 6 pin mode
+    - MLK-15990 imx: mlb: change mlb clock name
+    - MLK-15995 imx: mlb: only use irq_ahb1 for imx6
+    - MLK-15999 imx: mlb: fix build warnings
+    - MLK-15992 imx: mlb: add ipg & hclk clocks for imx8 mlb
+    - MLK-22071-1 mxc: mlb: Fix clock config for imx8qxp platform
+    - mxc: mlb: fix interrupt rw lock dead lock
+    - mxc mlb: Allow compilation on imx8
+    - MLK-23000-1 mxc: mlb: fix kernel dump when use gen_pool_dma_alloc
+    - mxc: IPU3: Forward IPUv3 common driver from imx_4.19.y kernel
+    - mxc: IPU3: Fix not including uapi/linux/sched/types.h
+    - MLK-22399 mxc IPUv3: cpmem: Get 0 u/v_offset in __ipu_ch_offset_calc() for
+      some pfmts
+    - mxc: hdmi-cec: Add imx6 hdmi cec driver
+    - media: mipi csi: add IPU CSI driver
+    - MGS-5372 [#imx-1708] Fix the VX/CL apps hang for 865 GPU/VIP
+    - LF-365 [8QM_MEK/8QXP_MEK]mxc:vpu_malone: need skip tsm when skip not decoded
+      frame
+    - MGS-5326 [#imx-1803] 0058-align-gc_feature_database
+    - LF-503:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:check space of cmd buffer
+    - LF-521: mxc: hantro: [All]arch64 kernel default build using imx_v8_defconfig
+      has many Warnings.100%
+    - LF-561: [8QM_MEK/8QXP_MEK]mxc:vpu_malone:reinit completion before send
+      command
+    - MGS-5226 [#imx-1746] add REG_DisableVIP bit 1
+    - LF-628:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:export frame threshold of frame mode
+    - LF-629: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: donot set end_flag if scode type
+      is BUFFFLUSH in low-latency mode
+    - MGS-5064 [#imx-1868] 0003-CL244120-Prepare-for-NXP-backwards-compatible-
+      requir
+    - MGS-5064 [#imx-1868] 0006-CL244297-align-gc_feature_database
+    - MGS-5064 [#imx-1868] 0010-BUG25711-CL244484-Android-CTS-some-cases-fail-in-
+      gle
+    - MA-16168 [#imx-1903] Fix GPU driver build error and not work issue on 5.4
+      kernel
+    - LF-408-2 [#imx-1873] disable 1M page for dynamic mapping
+    - MGS-5458 [#imx-1708] fix GPU/VIP coreIndex issue
+    - LF-688:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:export fw log via debugfs
+    - LF-690:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:extends the range of frame rate
+      from integers to real numbers
+    - LF-711:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:stream may hang due to the event msg
+      hasn't process in time
+    - MLK-23211-1: arm64: imx8mp: vpu: add vc8000e driver
+    - MA-16211: imx8mp: vpu: Implement hantro vc8000e ioctl32
+    - LF-765 [8QM_MEK/8QXP_MEK]mxc:vpu_malone: add FRAME_SKIP status to record
+      skip-frame
+    - LF-765-2 [8QM_MEK/8QXP_MEK]mxc: vpu_malone: check buffer status before add
+      buffer to queue
+    - MGS-5472 [#ccc] fix gpu resolve alignment issue
+    - LF-165 [#imx-1870] gputop counter test failed
+    - LF-165 [#imx-1870] Fix the error when converting pointer to int for 32 bit
+      system
+    - MGS-5341 [#imx-1870] Fix the uninitialized variable in GPU driver.
+    - MGS-5485 [#imx-1870] fix memory database error
+    - MGS-5485-2 [#imx-1870] fix system out of memory in gpu database
+    - MLK-23263 mxc: vpu_malone: correct vpu decoder used bits of fuse
+    - LF-840-1:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-2:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-3:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-4:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-5:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-6:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-7:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-984:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:report error event when the
+      resolution beyond limit
+    - LF-994 mxc: vpu_malone vpu_windsor: cope with upstream y2038 changes
+    - MLK-23375: arm64: imx8mp: vc8000e: remove legacy ioremap_nocache interface
+    - MGS-5464 [#imx-1915] 0014-CL249917-DEC400-P010_LSB-I010-format
+    - MLK-23377: arm64: imx8mp: vc8000e: fix system hang in suspend/resume
+      operation
+    - MGS-5497-2 [#ccc] fix 6QP 2D MMU exception issue
+    - MA-16364 [#imx-1927] Set 4GB address limit flag on 8mm/8mn as 8mq
+    - MGS-5490 [#imx-1868] 0009-CL247796-Add-cores-in-order-3D-VIP-cores-2D-core-
+      VG-
+    - MGS-5534 [#imx-1960] Add copyright in gc_feature_database.h
+    - MGS-5536-1 [#imx-1962] add memory-region property support
+    - MGS-5536-2 [#imx-1962] fix MMU shift mapping for 4GB truncated mtlb
+    - MLK-23394-2: XUVI/PPM: driver initial version.
+    - MLK-23394-5: XUVI/PPM: add build for XUVI/PPM.
+    - LF-1090:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:synchronize the allocate and free
+      mbi buffer
+    - MGS-5453 [#imx-1895] update gc_feature_database.h file
+    - MLK-23394 XUVI/PPM: decrease the usage count when it isn't in using.
+    - MLK-23377-2: arm64: imx8mp: vc8000e: fix system hang in suspend/resume
+      operation
+    - MGS-5554 [#imx-1868] update gc_feature_database.h and gc_hal_enum.h file
+    - MLK-23394 XUVI/PPM: fix coverity issues
+    - MLK-23220:mxc:vpu_malone:kfifo_alloc failure in VPU driver when memory
+      fragment
+    - LF-1077:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:compatible with ffmpeg h264_v4l2m2m
+      decoder
+    - LF-1078:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:compatible with ffmpeg
+      h264_v4l2m2m encoder
+    - LF-1078-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:compatible with ffmpeg
+      h264_v4l2m2m encoder
+    - LF-1180:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:v4l2 buffer of output stream use
+      virtual memory instead of dma
+    - LF-1181 mxc: vpu_malone: Not send res_change event until dst done_list is
+      empty
+    - MGS-5581 [#imx-1868] integrate vsi patch base on 6.4.0.p2 from 20200306 to
+      20200320
+    - LF-1208:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:instance may hang caused by stop
+      cmd is not sent in some case
+    - LF-1210:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: add LVL_FLOW debug log level to
+      help trace some key information
+    - LF-1091: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: request reasonable buffer size
+      for DCP instead of worst case
+    - LF-1212:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:fix issue in timestamp manager not
+      correctly handle buffers with same timestamp
+    - LF-1211 mxc: vpu_malone: v4l2_poll directly return if firmware already
+      finished
+    - MGS-5607 [#imx-1868] integrate vsi patch base on 6.4.0.p2 from 20200320 to
+      20200408
+    - MLK-23793-1 mxc: emvsim: fix pm issue
+    - MLK-23793-2 mxc: emvsim: add runtime pm support
+    - LF-1220 mxc: vpu_malone: manage mailbox according to runtime PM
+    - LF-1220-2 mxc: vpu_windsor manage mailbox according to runtime PM
+    - MGS-5612 [#IMX-2018] fix weston build error
+    - LF-1236 mxc: vpu_malone: roundup allocated kfifo size to power-of-two
+    - MLK-23394-1 XUVI/PPM: fix coverity issues
+    - MLK-23791 XUVI/PPM: MU: enable runtime PM for MU3
+    - LF-1225: [8QM_MEK/8QXP_MEK]mxc:vpu_malone:fix hevc incorrect dcp buffer size
+    - mxc: gpu: remove use of ioremap_nocache()
+    - mxc: gpu-viv: Remove dma-buf map/unmap hooks
+    - mxc: gpu: cope with upstream y2038 changes
+    - MGS-5616-1 [#ccc] Update some Linux APIs for 5.5 kernel
+    - MGS-5616-2 [#ccc] Remove dma-buf map/unmap hooks for 5.5 kernel
+    - LF-1278:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: implement ctrl to set h264 aspect
+      ratio
+    - MLK-23723: arm64: imx8mp: vpu: fix g1/g2 timeout during suspend/resume
+    - MGS-5596 [#imx-2035] [1/2] PM QoS feature development
+    - MGS-5551 [#imx-1868] Update GPU database
+    - MGS-5653 [#imx-2041] modify clock prepare/unprepare along with power on/off
+    - MA-17115 mxc: vpu_malone: send error event when firmware exception
+    - mxc: vpu_malone: fix build issue as module
+    - mxc: vpu_maline: Fix Kconfig to depends on VIDEO_V4L2
+    - MLK-24009-1 arm64: imx8mp: vpu: vc8000e: fix build issue as module
+    - MLK-24009-2 arm64: imx8mp: vpu: g1/g2: fix build issue as module
+    - MLK-24009-3 arm64: imx8mm: vpu: h1: fix build issue as module
+    - MLK-24009-4 arm64: imx8mq: vpu: g1/g2: fix build issue as module
+    - MLK-24090 mxc: ipu3: ipu_device: Fix AB-BA deadlock between vdoa_lock and
+      ipu_ch_tbl.lock
+    - LF-1406-1:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support insmod separately
+    - LF-1406-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support insmod repeatly
+    - LF-1405-1: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: support insmod separately
+    - LF-1405-2:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: support insmod repeatly
+    - LF-1430-1 mxc: vpu_malone: refine insert scode for VC1 format
+    - LF-1430-2 mxc: vpu_malone: correct VP8 ivf frame header
+    - LF-1430-3 mxc: vpu_malone: unify set payload header
+    - LF-1430-4 mxc: vpu_malone: refine the operation of insert scode
+    - MGS-5060 [#imx-1868] 0021-Update-gc_feature_database.h-to-271754
+    - MGS-5709 [#imx-1439] fix gpu suspend/resume stuck
+    - MGS-5531 [#imx-1868] Fix VIP Hang isse with HW reet
+    - MGS-5768 [#imx-2132] fix android cts memory leak with
+      CL_MEM_USE_HOST_PHYSICAL_ADDR_VIV
+    - MLK-20236 mxc: sim/emvsim: useless call
+    - MGS-5787 [#imx-1868] 0003-CL275293-fix-flop-tp-reset-issue
+    - MGS-5787 [#imx-1868] 0004-CL275303-default-open-flopreset-with-TP
+    - MGS-5787 [#imx-1868] Update database for GPU/VIP
+    - MGS-5789 [#imx-2156] Fix Coverity issue in VIP PM HW workaround
+    - LF-1572 mxc: sim: Unchecked return value
+    - LF-1573 mxc: sim: Unchecked return value
+    - MLK-24363-1 mxc: emvsim: add error check when enable clk
+    - MLK-24363-2 mxc: emvsim: fix error report in probe stage
+    - MLK-24364 mxc: sim: add runtime pm support
+    - LF-1681: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: delete redundant data before
+      start code
+    - MA-17404 [#imx-2206] Kernel code copyright and license issue.
+    - MGS-5806 [#ccc] fix 8mm gpu hang due to dummy draw
+    - MLK-24404-1 mxc: vpu_malone: correct device power usage_count
+    - MLK-24404-2 mxc: vpu_windsor: correct device power usage_count
+    - MLK-24373-1 arm64: imx8mp: vpu: g1/g2: fix blocking issue in suspend
+    - MLK-24373-2 arm64: imx8mp: vpu: g1/g2: fix potential deadlock issue
+    - MLK-24477-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: enable color description in
+      vui
+    - MLK-24477-3:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: improve get/set color api
+    - MGS-5849 Integrate VSI GPU 6.4.3.p0 kernel driver
+    - LF-2138: mxc: vpu_malone: change typedef of 'valid_ts_received' to unsigned
+      int
+    - LF-2111: mxc: vpu_windsor: Avoid hide parameter
+    - MGS-5933-1 [#ccc] reenable m865s gpu TX clock gating
+    - MGS-5928-1 [#ccc] allocate auxiliary memory for cacheable map
+    - MGS-5928-2 [#ccc] support virtual memory in normal zone
+    - MLK-24477-4:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: report color space by try_fmt
+    - MGS-5928-3 [#ccc] fix Android kernel crash problem
+    - MLK-24499: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: set low latency mode through
+      set bframe
+    - MGS-5943 [#imx-2089] 0079-CL290440-KERNEL-SPACE-6.4.x-Always-enable-
+      gcdIGNORE_
+    - MGS-5943 [#imx-2089] 0081-BUG27413-CL290463-KERNEL-SPACE-64x_234062-ocl-fix-
+      th
+    - MGS-5943 [#imx-2089] 0091-KERNEL-SPACE-Update-
+      gc_feature_database.h-to-290561
+    - MLK-24593:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support change bitrate
+      dynamically
+    - MA-17341 [#imx-2211] Remove ts_address code to keep align with Linux
+    - MA-17341-2 [#imx-2211] Fix kernel panic when do stop on android
+    - MA-17683 [#imx-2302] Fix video playback "rcu stall" issue on 8mq
+    - MGS-5972 [#imx-2089] 0011-CL292878-KERNEL-SPACE-dev64x_234062-show-gpu-
+      video-m
+    - MGS-5972 [#imx-2089] 0038-KERNEL-SPACE-Update-
+      gc_feature_database.h-to-295136
+    - MA-18037 [#imx-2356] import vfs namespace to fix GPU module load errors
+    - MGS-6025: sync GPU kernel driver with 20201015 version
+    - MGS-6026 mxc/gpu-viv: integrate 6.4.3.p1 kernel
+    - MGS-6012-5 [#imx-2337] fix 6.4.3.p1 build break for L5.10
+    - MGS-6012-6 [#imx-2337] refine mmap_sem fix for L5.10 kernel
+    - MGS-6010 [#ccc] gpu: add GetSGT callback for reserved_mem
+    - LF-2118 [#ccc] fixed Coverity Issue:6124050
+    - LF-2118-2 [#ccc] fixed Coverity Issue:6124050
+    - MGS-5990-3 [#ccc] refine gpu memory bank configuration
+    - MGS-5990-4 [#ccc] fix the uninitialized variable
+    - MGS-6026-2 sync gpu database with formal 6.4.3.p1
+    - LF-2473 [#ccc] Coverity Issue:10281263
+    - LF-2466 [#ccc] fix the dereference issue
+    - LF-2461 [#ccc] use inline to fix multi-defination
+    - LF-2457 [#ccc] fix the Dereferencing null pointer
+    - LF-2478 [#ccc] fix the dereferencing null pointer
+    - LF-2480 [#ccc] rm DEBUG print as it print below like external mem
+    - LF-2492 [#ccc] check sscanf return value
+    - LF-2473 [#ccc] Coverity Issue:10281263
+    - MGS-4929 [#imx-2382] enable vivante drm for linux build
+    - MGS-6058 [#imx-2391] fix vivante drm build break for L5.10
+    - MGS-6060 gpu-viv: sync 20201116 patch release
+    - MGS-6060-2 gpu-viv: fix build break
+    - MLK-24959: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: move timestamp handler to
+      firmware
+    - MLK-24960: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: move timestamp manager to
+      firmware
+    - MGS-6108 [#imx-2416] fix GPU exception to access the freed MMU page
+    - MGS-6108-2 [#imx-2416] fix vg kernel panic for command unlock
+    - MGS-6108-3 [#imx-2416] fix gcdENABLE_VG logic issue
+    - MLK-21876-21 mxcfb: add uapi headfile for yocto build pass
+    - MLK-21876-17 mxc_v4l2: add uapi headfile for yocto build pass
+    - MLK-24874-3: include: uapi: mxc_v4l2: fix the UAPI_HEADER_TEST failure
+    - MLK-21876-19 pxp_dma: add uapi headfile for yocto build pass
+    - MLK-21876-13 ipu: add uapi headfile for yocto build pass
+    - MLK-24874-5: include: uapi: ipu: fix the UAPI_HEADER_TEST failure
+    - MLK-21876-12 vpu: add handro h1 headfile for Yocto build pass
+    - MA-11994 Add get phys address ioctl to dma-buf.
+    - MLK-16130-2: ASoC: fsl: add machine driver for cadence hdmi
+    - MLK-16159: ASoC: imx_cdnhdmi: refine the N value selection
+    - MLK-16538-2: hdmi api: Relocate hdmi api soure code
+    - MLK-13946-4: ASoC: imx-cdnhdmi: refine machine driver for api changes
+    - MLK-17344-1: ASoC: imx-cdnhdmi: get constraint rate from dts
+    - MLK-17620-2: ASoC: imx-cdnhdmi: switch to generic hdmi codec
+    - MLK-18368-2: ASoC: fsl: support hdmi rx in machine driver
+    - MLK-18833: ASoC: imx-cdnhdmi: fix no sound card issue
+    - MLK-20183-2: ASoC: imx-cdnhdmi: reconfigure the mclk for HDMI on imx8mq
+    - ASoC: imx-cdnhdmi: Fix compile error
+    - MLK-23642-3: ASoC: fsl: imx-cdnhdmi: support 6 channels
+    - MLK-24611-3: ASoC: imx-cdnhdmi: Add hdmi jack
+    - LF-2700: ASoC: fsl: imx-cdnhdmi: Fix error prompt
+    - MLK-23287-1: ASoC: fsl_aud2htx: Add aud2htx module driver
+    - MLK-23906-1: ASoC: fsl_aud2htx: Don't bind clock with regmap
+    - imx busfreq: Add API header file
+    - Add MU module for vpu dependence on QXP/QM
+    - MLK-9769-1 crypto: caam/jr - remove incorrect comment from job ring module
+    - MLK-20204 crypto: caam - remove deadcode on 32-bit platforms
+    - MLK-9769-9 crypto: caam - adjust RNG timing to support more devices
+    - MLK-9769-8 crypto: caam - add a test for the RNG
+    - MLKU-114-1 crypto: caam - reduce page 0 regs access to minimum
+    - MLKU-114-2 crypto: caam - SCU firmware support
+    - MLKU-114-3 crypto: caam - OP-TEE firmware support
+    - MLKU-38-3 crypto: caam - add SNVS / SECVIO support
+    - MLKU-25-3 crypto: caam - add Secure Memory support
+    - MLK-19801-1 crypto: caam - add tag functionality
+    - MLK-19801-2 crypto: caam - add support of tagged keys in caamalg
+    - MLK-10036 crypto: caam - add support for DSM with Mega/Fast mix on
+    - MLK-19449 crypto: caam - Change structure type representing DECO MID
+    - LFV-26 crypto: caam - fix Secure Memory driver init
+    - LF-63-1 crypto: caam - fix SM test init
+    - crypto: caam - fix snvs clk prepare+enable
+    - LF-838: crypto: caam - increase the domain of write memory barrier to full
+      system
+    - MLK-23774 crypto: caam - fix SNVS / SECVIO building as module
+    - MLK-21689 crypto: caam - make snvs clock optional
+    - MLK-23664-2 crypto: caam - allocate RNG instantiation descriptor with
+      GFP_DMA
+    - MLK-24420-1 crypto: caam - update tagged keys functionality and tk
+      transformations for skcipher
+    - MLK-24420-2 crypto: caam - add support for black keys and blobs
+    - MLK-24420-3 crypto: caam - add ioctl calls for black keys and blobs
+      generation
+    - MLK-24497 crypto: caam - update tagged object functionality by adding red
+      key length
+    - MLK-24496 crypto: caam - fix blob encapsulation/decapsulation
+    - MLK-24496 crypto: caam - add tag object header to blob
+    - MLK-24497 crypto: caam - update job descriptor with inline commands
+    - MLK-24517-1 crypto: caam - removed unnecessary validation of black key for
+      blob decapsulation
+    - MLK-24517-2 crypto: caam - removed unnecessary validation of black key for
+      blob encapsulation
+    - MLK-24517-3 crypto: caam - add null terminator to temporary buffer
+    - MLK-24517-4 crypto: caam - validate arguments received from user-space
+    - MLK-23664-3 crypto: caam - use struct hwrng's .init for initialization
+    - MLK-23664-4 crypto: caam - drop global context pointer and init_done
+    - MLK-23664-7 crypto: caam - invalidate entropy register during RNG
+      initialization
+    - MLK-21698: tee:optee: fix shared memory page attribute checks
+    - driver: tee: Handle NULL pointer indication from client
+    - tee: add support for session's client UUID generation
+    - tee: optee: Add support for session login client UUID generation
+    - tee: optee: remove need_resched() before cond_resched()
+    - MLK-16912 PL310: unlock ways during initialization
+    - MLK-16224-1: dmaengine: add src_fifo_num and dst_fifo_num in
+      dma_slave_config
+    - MLK-17385: dma: imx-sdma: update sdma script for multi fifo on SAI
+    - dma: engine: imx-sdma: add mcu_2_ecspi script
+    - dmaengine: imx-sdma: remove ERR009165 on i.mx6ul
+    - dmaengine: imx-sdma: fix ecspi1 rx dma not work on i.mx8mm
+    - dmaengine: imx-sdma: support allocate memory from iram
+    - dmaengine: imx-sdma: Add hdmi audio support in sdma
+    - dmaengine: imx-sdma: add sdma resume back after megafast off
+    - MLK-11259-1: dmaengine: imx-sdma: support dual fifo for DEV_TO_DEV
+    - MLK-16885-1: DMA: imx-sdma: update the buswidth that is supported
+    - include: dma-imx: support dual fifo for for DEV_TO_DEV
+    - dmaengine: imx-sdma: update sdma script for multi fifo on SAI
+    - MLK-22239-1: dmaengine: imx-sdma: Support 24bit/3bytes for sg mode
+    - dma: imx-sdma: Fix issue with IMX_DMATYPE_HDMI
+    - dma: imx-sdma: Add pm_ops to support suspend & resume
+    - MLK-22972 dmaengine: imx-sdma: correct the script number for v3
+    - MLK-23005: dmaengine: imx-sdma: correct data size of channel context
+    - LF-246: dmaengine: imx-sdma: correct is_ram_script checking
+    - LF-301: dmaengine: imx-sdma: Add once more loading firmware
+    - MLK-23400-1: dmaengine: imx-sdma: add sdma restore back for i.mx8mp
+    - MLK-20598 dmaengine: imx-sdma: fix potential system hang
+    - MLK-23869-1 dmaengine: imx-sdma: split sdma init hw and sw
+    - MLK-23869-2 dmaengine: imx-sdma: add runtime suspend/resume
+    - MLK-23869-3: dmaengine: imx-sdma: add sdma_get_firmware_wait
+    - MLK-24071 dmaengine: imx-sdma: fix random channel stop
+    - MLK-23540 dmaengine: imx-sdma: restore DONEx_CONFIG register
+    - MLK-24483-1: dmaengine: imx-sdma: remove ecspi_fixed on imx8mq
+    - MLK-25116-1: dmaengine: imx-sdma: save iram pool for bd allocated
+    - MLK-25116-2: dmaengine: imx-sdma: correct iram_pool check point
+    - LF-3132: dmaengine: imx-sdma: raise up channel0 priority after resume
+    - net: fec: add FEC_QUIRK_HAS_MULTI_QUEUES represents i.MX6SX ENET IP
+    - net: fec: add ndo_select_queue to fix TX bandwidth fluctuations
+    - MLK-16347-6 drm/bridge: adv7511: Add new compatible string
+    - MLK-16918-15 drm/bridge: Update adv7511 driver with some regs for adv7535
+    - MLK-16986-4 drm/bridge: adv7511: set bus_flags and bus_format
+    - MLK-17275-1 drm/bridge: adv7511: Add support for OF_DYNAMIC
+    - MLK-17275-7 drm/bridge: adv7511: Add dsi-channel property
+    - MLK-17650-1 drm/bridge: adv7511: Add support for programmable i2c addresses
+    - MLK-18877-1 drm/bridge: adv7511: Add debug info for HPD event
+    - MLK-17537-1 drm/bridge: Correct the ADV7533 init
+    - MLK-21958-13: drm/bridge: adv7511: Limit supported clocks
+    - drm/bridge: adv7511: Fix of_reconfig
+    - MA-17597-1 gpu: drm: select OF_DYNAMIC in it6263 and adv7511 config
+    - optee: model OP-TEE as a platform device/driver
+    - optee: use uuid for sysfs driver entry
+    - optee: enable support for multi-stage bus enumeration
+    - tpm_ftpm_tee: register driver on TEE bus
+    - hwrng: optee - handle unlimited data rates
+    - hwrng: optee - fix wait use case
+    - optee: Refuse to load the driver under the kdump kernel
+    - optee: fix tee out of memory failure seen during kexec reboot
+    - TEE-349 RPC Busfreq High
+
+  [ Ubuntu: 5.4.0-120.136 ]
+
+  * CVE-2022-21123 // CVE-2022-21125 // CVE-2022-21166
+    - cpu/speculation: Add prototype for cpu_show_srbds()
+    - x86/cpu: Add Jasper Lake to Intel family
+    - 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
+    - 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
+
+  [ Ubuntu: 5.4.0-117.132 ]
+
+  * CVE-2022-1966
+    - netfilter: nf_tables: add nft_set_elem_expr_alloc()
+    - netfilter: nf_tables: disallow non-stateful expression in sets earlier
+
+  [ Ubuntu: 5.4.0-115.129 ]
+
+  * CVE-2022-21499
+    - SAUCE: debug: Lock down kgdb
+
+  [ Ubuntu: 5.4.0-114.128 ]
+
+  * focal/linux: 5.4.0-114.128 -proposed tracker (LP: #1974391)
+  * 32 GT/s PCI link speeds reporting "Unknown speed" in sysfs (LP: #1970798)
+    - PCI: Add 32 GT/s decoding in some macros
+    - PCI: Add pci_speed_string()
+    - PCI: Use pci_speed_string() for all PCI/PCI-X/PCIe strings
+    - PCI: Add PCIE_LNKCAP2_SLS2SPEED() macro
+  * issuing invalid ioctl to /dev/vsock may spam dmesg (LP: #1971480)
+    - vsock: remove ratelimit unknown ioctl message
+  * config CONFIG_HISI_PMU for  kunpeng920 (LP: #1956086)
+    - drivers/perf: hisi: Permit modular builds of HiSilicon uncore drivers
+    - [Config] CONFIG_HISI_PMU=m
+  * Focal update: v5.4.189 upstream stable release (LP: #1971497)
+    - swiotlb: fix info leak with DMA_FROM_DEVICE
+    - USB: serial: pl2303: add IBM device IDs
+    - USB: serial: simple: add Nokia phone driver
+    - netdevice: add the case if dev is NULL
+    - HID: logitech-dj: add new lightspeed receiver id
+    - xfrm: fix tunnel model fragmentation behavior
+    - virtio_console: break out of buf poll on remove
+    - ethernet: sun: Free the coherent when failing in probing
+    - spi: Fix invalid sgs value
+    - net:mcf8390: Use platform_get_irq() to get the interrupt
+    - spi: Fix erroneous sgs value with min_t()
+    - af_key: add __GFP_ZERO flag for compose_sadb_supported in function
+      pfkey_register
+    - net: dsa: microchip: add spi_device_id tables
+    - iommu/iova: Improve 32-bit free space estimate
+    - tpm: fix reference counting for struct tpm_chip
+    - block: Add a helper to validate the block size
+    - virtio-blk: Use blk_validate_block_size() to validate block size
+    - USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c
+    - xhci: fix runtime PM imbalance in USB2 resume
+    - xhci: make xhci_handshake timeout for xhci_reset() adjustable
+    - xhci: fix uninitialized string returned by xhci_decode_ctrl_ctx()
+    - coresight: Fix TRCCONFIGR.QE sysfs interface
+    - iio: afe: rescale: use s64 for temporary scale calculations
+    - iio: inkern: apply consumer scale on IIO_VAL_INT cases
+    - iio: inkern: apply consumer scale when no channel scale is available
+    - iio: inkern: make a best effort on offset calculation
+    - greybus: svc: fix an error handling bug in gb_svc_hello()
+    - clk: uniphier: Fix fixed-rate initialization
+    - KEYS: fix length validation in keyctl_pkey_params_get_2()
+    - Documentation: add link to stable release candidate tree
+    - Documentation: update stable tree link
+    - HID: intel-ish-hid: Use dma_alloc_coherent for firmware update
+    - SUNRPC: avoid race between mod_timer() and del_timer_sync()
+    - NFSD: prevent underflow in nfssvc_decode_writeargs()
+    - NFSD: prevent integer overflow on 32 bit systems
+    - f2fs: fix to unlock page correctly in error path of is_alive()
+    - f2fs: quota: fix loop condition at f2fs_quota_sync()
+    - f2fs: fix to do sanity check on .cp_pack_total_block_count
+    - pinctrl: samsung: drop pin banks references on error paths
+    - spi: mxic: Fix the transmit path
+    - jffs2: fix use-after-free in jffs2_clear_xattr_subsystem
+    - jffs2: fix memory leak in jffs2_do_mount_fs
+    - jffs2: fix memory leak in jffs2_scan_medium
+    - mm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node
+    - mm: invalidate hwpoison page cache page in fault path
+    - mempolicy: mbind_range() set_policy() after vma_merge()
+    - scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands
+    - qed: display VF trust config
+    - qed: validate and restrict untrusted VFs vlan promisc mode
+    - riscv: Fix fill_callchain return value
+    - Revert "Input: clear BTN_RIGHT/MIDDLE on buttonpads"
+    - ALSA: cs4236: fix an incorrect NULL check on list iterator
+    - ALSA: hda/realtek: Fix audio regression on Mi Notebook Pro 2020
+    - mm,hwpoison: unmap poisoned page before invalidation
+    - mm/kmemleak: reset tag when compare object pointer
+    - drbd: fix potential silent data corruption
+    - powerpc/kvm: Fix kvm_use_magic_page
+    - udp: call udp_encap_enable for v6 sockets when enabling encap
+    - ACPI: properties: Consistently return -ENOENT if there are no more
+      references
+    - drivers: hamradio: 6pack: fix UAF bug caused by mod_timer()
+    - mailbox: tegra-hsp: Flush whole channel
+    - block: don't merge across cgroup boundaries if blkcg is enabled
+    - drm/edid: check basic audio support on CEA extension block
+    - video: fbdev: sm712fb: Fix crash in smtcfb_read()
+    - video: fbdev: atari: Atari 2 bpp (STe) palette bugfix
+    - ARM: dts: at91: sama5d2: Fix PMERRLOC resource size
+    - ARM: dts: exynos: fix UART3 pins configuration in Exynos5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5420
+    - carl9170: fix missing bit-wise or operator for tx_params
+    - thermal: int340x: Increase bitmap size
+    - lib/raid6/test: fix multiple definition linking error
+    - crypto: rsa-pkcs1pad - correctly get hash from source scatterlist
+    - crypto: rsa-pkcs1pad - restore signature length check
+    - crypto: rsa-pkcs1pad - fix buffer overread in pkcs1pad_verify_complete()
+    - DEC: Limit PMAX memory probing to R3k systems
+    - media: davinci: vpif: fix unbalanced runtime PM get
+    - xtensa: fix stop_machine_cpuslocked call in patch_text
+    - xtensa: fix xtensa_wsr always writing 0
+    - brcmfmac: firmware: Allocate space for default boardrev in nvram
+    - brcmfmac: pcie: Release firmwares in the brcmf_pcie_setup error path
+    - brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toio
+    - brcmfmac: pcie: Fix crashes due to early IRQs
+    - PCI: pciehp: Clear cmd_busy bit in polling mode
+    - regulator: qcom_smd: fix for_each_child.cocci warnings
+    - crypto: authenc - Fix sleep in atomic context in decrypt_tail
+    - crypto: mxs-dcp - Fix scatterlist processing
+    - spi: tegra114: Add missing IRQ check in tegra_spi_probe
+    - selftests/x86: Add validity check and allow field splitting
+    - audit: log AUDIT_TIME_* records only from rules
+    - crypto: ccree - don't attempt 0 len DMA mappings
+    - spi: pxa2xx-pci: Balance reference count for PCI DMA device
+    - hwmon: (pmbus) Add mutex to regulator ops
+    - hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNING
+    - block: don't delete queue kobject before its children
+    - PM: hibernate: fix __setup handler error handling
+    - PM: suspend: fix return value of __setup handler
+    - hwrng: atmel - disable trng on failure path
+    - crypto: vmx - add missing dependencies
+    - clocksource/drivers/timer-of: Check return value of of_iomap in
+      timer_of_base_init()
+    - ACPI: APEI: fix return value of __setup handlers
+    - crypto: ccp - ccp_dmaengine_unregister release dma channels
+    - hwmon: (pmbus) Add Vin unit off handling
+    - clocksource: acpi_pm: fix return value of __setup handler
+    - sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa
+    - perf/core: Fix address filter parser for multiple filters
+    - perf/x86/intel/pt: Fix address filter config for 32-bit kernel
+    - f2fs: fix missing free nid in f2fs_handle_failed_inode
+    - f2fs: fix to avoid potential deadlock
+    - media: bttv: fix WARNING regression on tunerless devices
+    - media: coda: Fix missing put_device() call in coda_get_vdoa_data
+    - media: hantro: Fix overfill bottom register field name
+    - media: aspeed: Correct value for h-total-pixels
+    - video: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe()
+    - video: fbdev: atmel_lcdfb: fix an error code in atmel_lcdfb_probe()
+    - video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name()
+    - ARM: dts: qcom: ipq4019: fix sleep clock
+    - soc: qcom: rpmpd: Check for null return of devm_kcalloc
+    - soc: qcom: aoss: remove spurious IRQF_ONESHOT flags
+    - arm64: dts: qcom: sm8150: Correct TCS configuration for apps rsc
+    - soc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe
+    - ARM: dts: imx: Add missing LVDS decoder on M53Menlo
+    - media: video/hdmi: handle short reads of hdmi info frame.
+    - media: em28xx: initialize refcount before kref_get
+    - media: usb: go7007: s2250-board: fix leak in probe()
+    - uaccess: fix nios2 and microblaze get_user_8()
+    - ASoC: rt5663: check the return value of devm_kzalloc() in rt5663_parse_dp()
+    - ASoC: ti: davinci-i2s: Add check for clk_enable()
+    - ALSA: spi: Add check for clk_enable()
+    - arm64: dts: ns2: Fix spi-cpol and spi-cpha property
+    - arm64: dts: broadcom: Fix sata nodename
+    - printk: fix return value of printk.devkmsg __setup handler
+    - ASoC: mxs-saif: Handle errors for clk_enable
+    - ASoC: atmel_ssc_dai: Handle errors for clk_enable
+    - ASoC: soc-compress: prevent the potentially use of null pointer
+    - memory: emif: Add check for setup_interrupts
+    - memory: emif: check the pointer temp in get_device_details()
+    - ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction
+    - arm64: dts: rockchip: Fix SDIO regulator supply properties on rk3399-firefly
+    - media: stk1160: If start stream fails, return buffers with
+      VB2_BUF_STATE_QUEUED
+    - ASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe
+    - ASoC: wm8350: Handle error for wm8350_register_irq
+    - ASoC: fsi: Add check for clk_enable
+    - video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of
+    - ivtv: fix incorrect device_caps for ivtvfb
+    - ASoC: dmaengine: do not use a NULL prepare_slave_config() callback
+    - ASoC: mxs: Fix error handling in mxs_sgtl5000_probe
+    - ASoC: imx-es8328: Fix error return code in imx_es8328_probe()
+    - ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in
+      msm8916_wcd_digital_probe
+    - mmc: davinci_mmc: Handle error for clk_enable
+    - ASoC: msm8916-wcd-analog: Fix error handling in pm8916_wcd_analog_spmi_probe
+    - drm/bridge: Fix free wrong object in sii8620_init_rcp_input_dev
+    - drm/bridge: Add missing pm_runtime_disable() in __dw_mipi_dsi_probe
+    - ath10k: fix memory overwrite of the WoWLAN wakeup packet pattern
+    - udmabuf: validate ubuf->pagecount
+    - Bluetooth: hci_serdev: call init_rwsem() before p->open()
+    - mtd: onenand: Check for error irq
+    - mtd: rawnand: gpmi: fix controller timings setting
+    - drm/edid: Don't clear formats if using deep color
+    - drm/amd/display: Fix a NULL pointer dereference in
+      amdgpu_dm_connector_add_common_modes()
+    - ath9k_htc: fix uninit value bugs
+    - KVM: PPC: Fix vmx/vsx mixup in mmio emulation
+    - i40e: don't reserve excessive XDP_PACKET_HEADROOM on XSK Rx to skb
+    - power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probe
+    - ray_cs: Check ioremap return value
+    - powerpc/perf: Don't use perf_hw_context for trace IMC PMU
+    - mt76: mt7603: check sta_rates pointer in mt7603_sta_rate_tbl_update
+    - mt76: mt7615: check sta_rates pointer in mt7615_sta_rate_tbl_update
+    - net: dsa: mv88e6xxx: Enable port policy support on 6097
+    - PCI: aardvark: Fix reading PCI_EXP_RTSTA_PME bit on emulated bridge
+    - power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_init
+    - HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports
+    - iommu/ipmmu-vmsa: Check for error num after setting mask
+    - drm/amd/display: Add affected crtcs to atomic state for dsc mst unplug
+    - IB/cma: Allow XRC INI QPs to set their local ACK timeout
+    - dax: make sure inodes are flushed before destroy cache
+    - iwlwifi: Fix -EIO error code that is never returned
+    - iwlwifi: mvm: Fix an error code in iwl_mvm_up()
+    - dm crypt: fix get_key_size compiler warning if !CONFIG_KEYS
+    - scsi: pm8001: Fix command initialization in pm80XX_send_read_log()
+    - scsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req()
+    - scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config()
+    - scsi: pm8001: Fix abort all task initialization
+    - drm/amd/display: Remove vupdate_int_entry definition
+    - TOMOYO: fix __setup handlers return values
+    - ext2: correct max file size computing
+    - drm/tegra: Fix reference leak in tegra_dsi_ganged_probe
+    - power: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false
+      return
+    - scsi: hisi_sas: Change permission of parameter prot_mask
+    - drm/bridge: cdns-dsi: Make sure to to create proper aliases for dt
+    - bpf, arm64: Call build_prologue() first in first JIT pass
+    - bpf, arm64: Feed byte-offset into bpf line info
+    - libbpf: Skip forward declaration when counting duplicated type names
+    - powerpc/Makefile: Don't pass -mcpu=powerpc64 when building 32-bit
+    - KVM: x86: Fix emulation in writing cr8
+    - KVM: x86/emulator: Defer not-present segment check in
+      __load_segment_descriptor()
+    - hv_balloon: rate-limit "Unhandled message" warning
+    - i2c: xiic: Make bus names unique
+    - power: supply: wm8350-power: Handle error for wm8350_register_irq
+    - power: supply: wm8350-power: Add missing free in free_charger_irq
+    - PCI: Reduce warnings on possible RW1C corruption
+    - mips: DEC: honor CONFIG_MIPS_FP_SUPPORT=n
+    - powerpc/sysdev: fix incorrect use to determine if list is empty
+    - mfd: mc13xxx: Add check for mc13xxx_irq_request
+    - selftests/bpf: Make test_lwt_ip_encap more stable and faster
+    - powerpc: 8xx: fix a return value error in mpc8xx_pic_init
+    - vxcan: enable local echo for sent CAN frames
+    - MIPS: RB532: fix return value of __setup handler
+    - mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init
+    - RDMA/mlx5: Fix memory leak in error flow for subscribe event routine
+    - bpf, sockmap: Fix memleak in tcp_bpf_sendmsg while sk msg is full
+    - bpf, sockmap: Fix more uncharged while msg has more_data
+    - bpf, sockmap: Fix double uncharge the mem of sk_msg
+    - USB: storage: ums-realtek: fix error code in rts51x_read_mem()
+    - Bluetooth: btmtksdio: Fix kernel oops in btmtksdio_interrupt
+    - af_netlink: Fix shift out of bounds in group mask calculation
+    - i2c: mux: demux-pinctrl: do not deactivate a master that is not active
+    - selftests/bpf/test_lirc_mode2.sh: Exit with proper code
+    - tcp: ensure PMTU updates are processed during fastopen
+    - openvswitch: always update flow key after nat
+    - tipc: fix the timer expires after interval 100ms
+    - mfd: asic3: Add missing iounmap() on error asic3_mfd_probe
+    - mxser: fix xmit_buf leak in activate when LSR == 0xff
+    - pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()
+    - misc: alcor_pci: Fix an error handling path
+    - staging:iio:adc:ad7280a: Fix handing of device address bit reversing.
+    - pinctrl: renesas: r8a77470: Reduce size for narrow VIN1 channel
+    - clk: qcom: ipq8074: Use floor ops for SDCC1 clock
+    - phy: dphy: Correct lpx parameter and its derivatives(ta_{get,go,sure})
+    - serial: 8250_mid: Balance reference count for PCI DMA device
+    - serial: 8250: Fix race condition in RTS-after-send handling
+    - iio: adc: Add check for devm_request_threaded_irq
+    - NFS: Return valid errors from nfs2/3_decode_dirent()
+    - dma-debug: fix return value of __setup handlers
+    - clk: imx7d: Remove audio_mclk_root_clk
+    - clk: qcom: clk-rcg2: Update logic to calculate D value for RCG
+    - clk: qcom: clk-rcg2: Update the frac table for pixel clock
+    - remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_region
+    - remoteproc: qcom_wcnss: Add missing of_node_put() in
+      wcnss_alloc_memory_region
+    - clk: actions: Terminate clk_div_table with sentinel element
+    - clk: loongson1: Terminate clk_div_table with sentinel element
+    - clk: clps711x: Terminate clk_div_table with sentinel element
+    - clk: tegra: tegra124-emc: Fix missing put_device() call in
+      emc_ensure_emc_driver
+    - NFS: remove unneeded check in decode_devicenotify_args()
+    - staging: mt7621-dts: fix LEDs and pinctrl on GB-PC1 devicetree
+    - pinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_init
+    - pinctrl: mediatek: paris: Fix "argument" argument type for mtk_pinconf_get()
+    - pinctrl: mediatek: paris: Fix pingroup pin config state readback
+    - pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe
+    - pinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe
+    - tty: hvc: fix return value of __setup handler
+    - kgdboc: fix return value of __setup handler
+    - kgdbts: fix return value of __setup handler
+    - firmware: google: Properly state IOMEM dependency
+    - driver core: dd: fix return value of __setup handler
+    - jfs: fix divide error in dbNextAG
+    - netfilter: nf_conntrack_tcp: preserve liberal flag in tcp options
+    - NFSv4.1: don't retry BIND_CONN_TO_SESSION on session error
+    - clk: qcom: gcc-msm8994: Fix gpll4 width
+    - clk: Initialize orphan req_rate
+    - xen: fix is_xen_pmu()
+    - net: phy: broadcom: Fix brcm_fet_config_init()
+    - selftests: test_vxlan_under_vrf: Fix broken test case
+    - qlcnic: dcb: default to returning -EOPNOTSUPP
+    - net/x25: Fix null-ptr-deref caused by x25_disconnect
+    - NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
+    - net: dsa: bcm_sf2_cfp: fix an incorrect NULL check on list iterator
+    - lib/test: use after free in register_test_dev_kmod()
+    - LSM: general protection fault in legacy_parse_param
+    - gcc-plugins/stackleak: Exactly match strings instead of prefixes
+    - pinctrl: npcm: Fix broken references to chip->parent_device
+    - block, bfq: don't move oom_bfqq
+    - selinux: use correct type for context length
+    - loop: use sysfs_emit() in the sysfs xxx show()
+    - Fix incorrect type in assignment of ipv6 port for audit
+    - irqchip/qcom-pdc: Fix broken locking
+    - irqchip/nvic: Release nvic_base upon failure
+    - bfq: fix use-after-free in bfq_dispatch_request
+    - ACPICA: Avoid walking the ACPI Namespace if it is not there
+    - lib/raid6/test/Makefile: Use $(pound) instead of \# for Make 4.3
+    - Revert "Revert "block, bfq: honor already-setup queue merges""
+    - ACPI/APEI: Limit printable size of BERT table data
+    - PM: core: keep irq flags in device_pm_check_callbacks()
+    - spi: tegra20: Use of_device_get_match_data()
+    - ext4: don't BUG if someone dirty pages without asking ext4 first
+    - ntfs: add sanity check on allocation size
+    - video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow
+    - video: fbdev: w100fb: Reset global state
+    - video: fbdev: cirrusfb: check pixclock to avoid divide by zero
+    - video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit
+    - ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960
+    - ARM: dts: bcm2837: Add the missing L1/L2 cache information
+    - ASoC: madera: Add dependencies on MFD
+    - video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf()
+    - video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of
+      snprintf()
+    - video: fbdev: udlfb: replace snprintf in show functions with sysfs_emit
+    - ASoC: soc-core: skip zero num_dai component in searching dai name
+    - media: cx88-mpeg: clear interrupt status register before streaming video
+    - ARM: tegra: tamonten: Fix I2C3 pad setting
+    - ARM: mmp: Fix failure to remove sram device
+    - video: fbdev: sm712fb: Fix crash in smtcfb_write()
+    - media: Revert "media: em28xx: add missing em28xx_close_extension"
+    - media: hdpvr: initialize dev->worker at hdpvr_register_videodev
+    - mmc: host: Return an error when ->enable_sdio_irq() ops is missing
+    - ALSA: hda/realtek: Add alc256-samsung-headphone fixup
+    - powerpc/lib/sstep: Fix 'sthcx' instruction
+    - powerpc/lib/sstep: Fix build errors with newer binutils
+    - powerpc: Fix build errors with newer binutils
+    - scsi: qla2xxx: Fix stuck session in gpdb
+    - scsi: qla2xxx: Fix wrong FDMI data for 64G adapter
+    - scsi: qla2xxx: Fix warning for missing error code
+    - scsi: qla2xxx: Fix device reconnect in loop topology
+    - scsi: qla2xxx: Add devids and conditionals for 28xx
+    - scsi: qla2xxx: Check for firmware dump already collected
+    - scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair()
+    - scsi: qla2xxx: Fix disk failure to rediscover
+    - scsi: qla2xxx: Fix incorrect reporting of task management failure
+    - scsi: qla2xxx: Fix hang due to session stuck
+    - scsi: qla2xxx: Fix missed DMA unmap for NVMe ls requests
+    - scsi: qla2xxx: Fix N2N inconsistent PLOGI
+    - scsi: qla2xxx: Reduce false trigger to login
+    - scsi: qla2xxx: Use correct feature type field during RFF_ID processing
+    - KVM: Prevent module exit until all VMs are freed
+    - KVM: x86: fix sending PV IPI
+    - ASoC: SOF: Intel: Fix NULL ptr dereference when ENOMEM
+    - ubifs: rename_whiteout: Fix double free for whiteout_ui->data
+    - ubifs: Fix deadlock in concurrent rename whiteout and inode writeback
+    - ubifs: Add missing iput if do_tmpfile() failed in rename whiteout
+    - ubifs: setflags: Make dirtied_ino_d 8 bytes aligned
+    - ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()
+    - ubifs: rename_whiteout: correct old_dir size computing
+    - XArray: Fix xas_create_range() when multi-order entry present
+    - can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path
+    - can: mcba_usb: properly check endpoint type
+    - XArray: Update the LRU list in xas_split()
+    - rtc: check if __rtc_read_time was successful
+    - gfs2: Make sure FITRIM minlen is rounded up to fs block size
+    - net: hns3: fix software vlan talbe of vlan 0 inconsistent with hardware
+    - pinctrl: pinconf-generic: Print arguments for bias-pull-*
+    - pinctrl: nuvoton: npcm7xx: Rename DS() macro to DSTR()
+    - pinctrl: nuvoton: npcm7xx: Use %zu printk format for ARRAY_SIZE()
+    - ASoC: mediatek: mt6358: add missing EXPORT_SYMBOLs
+    - ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
+    - ARM: iop32x: offset IRQ numbers by 1
+    - ACPI: CPPC: Avoid out of bounds access when parsing _CPC data
+    - powerpc/kasan: Fix early region not updated correctly
+    - ASoC: soc-compress: Change the check for codec_dai
+    - mm/mmap: return 1 from stack_guard_gap __setup() handler
+    - mm/memcontrol: return 1 from cgroup.memory __setup() handler
+    - mm/usercopy: return 1 from hardened_usercopy __setup() handler
+    - bpf: Fix comment for helper bpf_current_task_under_cgroup()
+    - dt-bindings: mtd: nand-controller: Fix the reg property description
+    - dt-bindings: mtd: nand-controller: Fix a comment in the examples
+    - dt-bindings: spi: mxic: The interrupt property is not mandatory
+    - ubi: fastmap: Return error code if memory allocation fails in add_aeb()
+    - ASoC: topology: Allow TLV control to be either read or write
+    - ARM: dts: spear1340: Update serial node properties
+    - ARM: dts: spear13xx: Update SPI dma properties
+    - um: Fix uml_mconsole stop/go
+    - openvswitch: Fixed nd target mask field in the flow dump.
+    - KVM: x86/mmu: do compare-and-exchange of gPTE via the user address
+    - KVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activated
+    - ubifs: Rectify space amount budget for mkdir/tmpfile operations
+    - rtc: wm8350: Handle error for wm8350_register_irq
+    - riscv module: remove (NOLOAD)
+    - ARM: 9187/1: JIVE: fix return value of __setup handler
+    - KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs
+    - drm: Add orientation quirk for GPD Win Max
+    - ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111
+    - drm/amd/amdgpu/amdgpu_cs: fix refcount leak of a dma_fence obj
+    - ptp: replace snprintf with sysfs_emit
+    - powerpc: dts: t104xrdb: fix phy type for FMAN 4/5
+    - bpf: Make dst_port field in struct bpf_sock 16-bit wide
+    - scsi: mvsas: Replace snprintf() with sysfs_emit()
+    - scsi: bfa: Replace snprintf() with sysfs_emit()
+    - power: supply: axp20x_battery: properly report current when discharging
+    - ipv6: make mc_forwarding atomic
+    - powerpc: Set crashkernel offset to mid of RMA region
+    - drm/amdgpu: Fix recursive locking warning
+    - PCI: aardvark: Fix support for MSI interrupts
+    - iommu/arm-smmu-v3: fix event handling soft lockup
+    - usb: ehci: add pci device support for Aspeed platforms
+    - PCI: pciehp: Add Qualcomm quirk for Command Completed erratum
+    - power: supply: axp288-charger: Set Vhold to 4.4V
+    - ipv4: Invalidate neighbour for broadcast address upon address addition
+    - dm ioctl: prevent potential spectre v1 gadget
+    - drm/amdkfd: make CRAT table missing message informational only
+    - scsi: pm8001: Fix pm8001_mpi_task_abort_resp()
+    - scsi: aha152x: Fix aha152x_setup() __setup handler return value
+    - net/smc: correct settings of RMB window update limit
+    - mips: ralink: fix a refcount leak in ill_acc_of_setup()
+    - macvtap: advertise link netns via netlink
+    - tuntap: add sanity checks about msg_controllen in sendmsg
+    - bnxt_en: Eliminate unintended link toggle during FW reset
+    - MIPS: fix fortify panic when copying asm exception handlers
+    - scsi: libfc: Fix use after free in fc_exch_abts_resp()
+    - usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evm
+    - xtensa: fix DTC warning unit_address_format
+    - Bluetooth: Fix use after free in hci_send_acl
+    - netlabel: fix out-of-bounds memory accesses
+    - init/main.c: return 1 from handled __setup() functions
+    - minix: fix bug when opening a file with O_DIRECT
+    - clk: si5341: fix reported clk_rate when output divider is 2
+    - w1: w1_therm: fixes w1_seq for ds28ea00 sensors
+    - NFSv4: Protect the state recovery thread against direct reclaim
+    - xen: delay xen_hvm_init_time_ops() if kdump is boot on vcpu>=32
+    - clk: Enforce that disjoints limits are invalid
+    - SUNRPC/call_alloc: async tasks mustn't block waiting for memory
+    - NFS: swap IO handling is slightly different for O_DIRECT IO
+    - NFS: swap-out must always use STABLE writes.
+    - serial: samsung_tty: do not unlock port->lock for uart_write_wakeup()
+    - virtio_console: eliminate anonymous module_init & module_exit
+    - jfs: prevent NULL deref in diFree
+    - SUNRPC: Fix socket waits for write buffer space
+    - parisc: Fix CPU affinity for Lasi, WAX and Dino chips
+    - parisc: Fix patch code locking and flushing
+    - mm: fix race between MADV_FREE reclaim and blkdev direct IO read
+    - KVM: arm64: Check arm64_get_bp_hardening_data() didn't return NULL
+    - drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire()
+    - Drivers: hv: vmbus: Fix potential crash on module unload
+    - scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one()
+    - net/tls: fix slab-out-of-bounds bug in decrypt_internal
+    - net: ipv4: fix route with nexthop object delete warning
+    - net: stmmac: Fix unset max_speed difference between DT and non-DT platforms
+    - drm/imx: Fix memory leak in imx_pd_connector_get_modes
+    - bnxt_en: reserve space inside receive page for skb_shared_info
+    - IB/rdmavt: add lock to call to rvt_error_qp to prevent a race condition
+    - dpaa2-ptp: Fix refcount leak in dpaa2_ptp_probe
+    - ipv6: Fix stats accounting in ip6_pkt_drop
+    - net: openvswitch: don't send internal clone attribute to the userspace.
+    - rxrpc: fix a race in rxrpc_exit_net()
+    - qede: confirm skb is allocated before using
+    - spi: bcm-qspi: fix MSPI only access with bcm_qspi_exec_mem_op()
+    - bpf: Support dual-stack sockets in bpf_tcp_check_syncookie
+    - drbd: Fix five use after free bugs in get_initial_state
+    - SUNRPC: Handle ENOMEM in call_transmit_status()
+    - SUNRPC: Handle low memory situations in call_status()
+    - perf tools: Fix perf's libperf_print callback
+    - perf session: Remap buf if there is no space for event
+    - Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"
+    - mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is
+      complete
+    - lz4: fix LZ4_decompress_safe_partial read out of bound
+    - mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0)
+    - mm/mempolicy: fix mpol_new leak in shared_policy_replace
+    - x86/pm: Save the MSR validity status at context setup
+    - x86/speculation: Restore speculation related MSRs during S3 resume
+    - btrfs: fix qgroup reserve overflow the qgroup limit
+    - arm64: patch_text: Fixup last cpu should be master
+    - ata: sata_dwc_460ex: Fix crash due to OOB write
+    - perf: qcom_l2_pmu: fix an incorrect NULL check on list iterator
+    - irqchip/gic-v3: Fix GICR_CTLR.RWP polling
+    - tools build: Filter out options and warnings not supported by clang
+    - tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts
+    - dmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error"
+    - mmc: mmci_sdmmc: Replace sg_dma_xxx macros
+    - mmc: mmci: stm32: correctly check all elements of sg list
+    - mm: don't skip swap entry even if zap_details specified
+    - arm64: module: remove (NOLOAD) from linker script
+    - mm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning
+    - drm/amdkfd: add missing void argument to function kgd2kfd_init
+    - drm/amdkfd: Fix -Wstrict-prototypes from
+      amdgpu_amdkfd_gfx_10_0_get_functions()
+    - cgroup: Use open-time credentials for process migraton perm checks
+    - cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv
+    - cgroup: Use open-time cgroup namespace for process migration perm checks
+    - selftests: cgroup: Make cg_create() use 0755 for permission instead of 0644
+    - selftests: cgroup: Test open-time credential usage for migration checks
+    - selftests: cgroup: Test open-time cgroup namespace usage for migration
+      checks
+    - cpuidle: PSCI: Move the `has_lpi` check to the beginning of the function
+    - ACPI: processor idle: Check for architectural support for LPI
+    - Linux 5.4.189
+  * Focal update: v5.4.188 upstream stable release (LP: #1971496)
+    - nfsd: cleanup nfsd_file_lru_dispose()
+    - nfsd: Containerise filecache laundrette
+    - net: ipv6: fix skb_over_panic in __ip6_append_data
+    - tpm: Fix error handling in async work
+    - staging: fbtft: fb_st7789v: reset display before initialization
+    - thermal: int340x: fix memory leak in int3400_notify()
+    - llc: fix netdevice reference leaks in llc_ui_bind()
+    - ALSA: pcm: Add stream lock during PCM reset ioctl operations
+    - ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB
+    - ALSA: cmipci: Restore aux vol on suspend/resume
+    - ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec
+    - drivers: net: xgene: Fix regression in CRC stripping
+    - ASoC: sti: Fix deadlock via snd_pcm_stop_xrun() call
+    - ALSA: oss: Fix PCM OSS buffer allocation overflow
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek: Add quirk for ASUS GA402
+    - ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
+    - ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
+    - ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU
+    - crypto: qat - disable registration of algorithms
+    - rcu: Don't deboost before reporting expedited quiescent state
+    - mac80211: fix potential double free on mesh join
+    - tpm: use try_get_ops() in tpm-space.c
+    - nds32: fix access_ok() checks in get/put_user
+    - llc: only change llc->dev when bind() succeeds
+    - Linux 5.4.188
+  * Focal update: v5.4.187 upstream stable release (LP: #1971493)
+    - crypto: qcom-rng - ensure buffer for generate is completely filled
+    - ocfs2: fix crash when initialize filecheck kobj fails
+    - efi: fix return value of __setup handlers
+    - net: phy: marvell: Fix invalid comparison in the resume and suspend
+      functions
+    - net/packet: fix slab-out-of-bounds access in packet_recvmsg()
+    - atm: eni: Add check for dma_map_single
+    - hv_netvsc: Add check for kvmalloc_array
+    - drm/panel: simple: Fix Innolux G070Y2-L01 BPP settings
+    - net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit()
+    - net: dsa: Add missing of_node_put() in dsa_port_parse_of
+    - arm64: fix clang warning about TRAMP_VALIAS
+    - usb: gadget: rndis: prevent integer overflow in rndis_set_response()
+    - usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
+    - usb: usbtmc: Fix bug in pipe direction for control transfers
+    - Input: aiptek - properly check endpoint type
+    - perf symbols: Fix symbol size calculation condition
+    - Linux 5.4.187
+  * Focal update: v5.4.186 upstream stable release (LP: #1969678)
+    - Revert "xfrm: state and policy should fail if XFRMA_IF_ID 0"
+    - sctp: fix the processing for INIT chunk
+    - xfrm: Check if_id in xfrm_migrate
+    - xfrm: Fix xfrm migrate issues when address family changes
+    - arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity
+    - arm64: dts: rockchip: reorder rk3399 hdmi clocks
+    - arm64: dts: agilex: use the compatible "intel,socfpga-agilex-hsotg"
+    - ARM: dts: rockchip: reorder rk322x hmdi clocks
+    - ARM: dts: rockchip: fix a typo on rk3288 crypto-controller
+    - mac80211: refuse aggregations sessions before authorized
+    - MIPS: smp: fill in sibling and core maps earlier
+    - ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE
+    - can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when
+      fully ready
+    - atm: firestream: check the return value of ioremap() in fs_init()
+    - iwlwifi: don't advertise TWT support
+    - drm/vrr: Set VRR capable prop only if it is attached to connector
+    - nl80211: Update bss channel on channel switch for P2P_CLIENT
+    - tcp: make tcp_read_sock() more robust
+    - sfc: extend the locking on mcdi->seqno
+    - kselftest/vm: fix tests build with old libc
+    - fixup for "arm64 entry: Add macro for reading symbol address from the
+      trampoline"
+    - Linux 5.4.186
+  * Focal update: v5.4.185 upstream stable release (LP: #1969672)
+    - clk: qcom: gdsc: Add support to update GDSC transition delay
+    - arm64: dts: armada-3720-turris-mox: Add missing ethernet0 alias
+    - virtio-blk: Don't use MAX_DISCARD_SEGMENTS if max_discard_seg is zero
+    - net: qlogic: check the return value of dma_alloc_coherent() in
+      qed_vf_hw_prepare()
+    - qed: return status of qed_iov_get_link
+    - drm/sun4i: mixer: Fix P010 and P210 format numbers
+    - ARM: dts: aspeed: Fix AST2600 quad spi group
+    - ethernet: Fix error handling in xemaclite_of_probe
+    - net: ethernet: ti: cpts: Handle error for clk_enable
+    - net: ethernet: lpc_eth: Handle error for clk_enable
+    - ax25: Fix NULL pointer dereference in ax25_kill_by_device
+    - net/mlx5: Fix size field in bufferx_reg struct
+    - net/mlx5: Fix a race on command flush flow
+    - NFC: port100: fix use-after-free in port100_send_complete
+    - selftests: pmtu.sh: Kill tcpdump processes launched by subshell.
+    - gpio: ts4900: Do not set DAT and OE together
+    - gianfar: ethtool: Fix refcount leak in gfar_get_ts_info
+    - net: phy: DP83822: clear MISR2 register to disable interrupts
+    - sctp: fix kernel-infoleak for SCTP sockets
+    - net: bcmgenet: Don't claim WOL when its not available
+    - net-sysfs: add check for netdevice being present to speed_show
+    - Revert "xen-netback: remove 'hotplug-status' once it has served its purpose"
+    - Revert "xen-netback: Check for hotplug-status existence before watching"
+    - ipv6: prevent a possible race condition with lifetimes
+    - tracing: Ensure trace buffer is at least 4096 bytes large
+    - selftest/vm: fix map_fixed_noreplace test failure
+    - selftests/memfd: clean up mapping in mfd_fail_write
+    - ARM: Spectre-BHB: provide empty stub for non-config
+    - fuse: fix pipe buffer lifetime for direct_io
+    - staging: gdm724x: fix use after free in gdm_lte_rx()
+    - net: macb: Fix lost RX packet wakeup race in NAPI receive
+    - mmc: meson: Fix usage of meson_mmc_post_req()
+    - riscv: Fix auipc+jalr relocation range checks
+    - arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0
+    - virtio: unexport virtio_finalize_features
+    - virtio: acknowledge all features before access
+    - ARM: fix Thumb2 regression with Spectre BHB
+    - ext4: add check to prevent attempting to resize an fs with sparse_super2
+    - x86/cpufeatures: Mark two free bits in word 3
+    - x86/cpu: Add hardware-enforced cache coherency as a CPUID feature
+    - x86/mm/pat: Don't flush cache if hardware enforces cache coherency across
+      encryption domnains
+    - KVM: SVM: Don't flush cache if hardware enforces cache coherency across
+      encryption domains
+    - Linux 5.4.185
+  * Focal update: v5.4.184 upstream stable release (LP: #1969242)
+    - arm/arm64: Provide a wrapper for SMCCC 1.1 calls
+    - arm/arm64: smccc/psci: add arm_smccc_1_1_get_conduit()
+    - ARM: report Spectre v2 status through sysfs
+    - ARM: early traps initialisation
+    - ARM: use LOADADDR() to get load address of sections
+    - [Config] updateconfigs for HARDEN_BRANCH_HISTORY
+    - ARM: Spectre-BHB workaround
+    - ARM: include unprivileged BPF status in Spectre V2 reporting
+    - ARM: fix build error when BPF_SYSCALL is disabled
+    - ARM: fix co-processor register typo
+    - ARM: Do not use NOCROSSREFS directive with ld.lld
+    - ARM: fix build warning in proc-v7-bugs.c
+    - xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
+    - xen/grant-table: add gnttab_try_end_foreign_access()
+    - xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/netfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/scsifront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/gntalloc: don't use gnttab_query_foreign_access()
+    - xen: remove gnttab_query_foreign_access()
+    - xen/9p: use alloc/free_pages_exact()
+    - xen/pvcalls: use alloc/free_pages_exact()
+    - xen/gnttab: fix gnttab_end_foreign_access() without page specified
+    - xen/netfront: react properly to failing gnttab_end_foreign_access_ref()
+    - Linux 5.4.184
+  * Focal update: v5.4.183 upstream stable release (LP: #1969239)
+    - mac80211_hwsim: report NOACK frames in tx_status
+    - mac80211_hwsim: initialize ieee80211_tx_info at hw_scan_work
+    - i2c: bcm2835: Avoid clock stretching timeouts
+    - ASoC: rt5668: do not block workqueue if card is unbound
+    - ASoC: rt5682: do not block workqueue if card is unbound
+    - Input: clear BTN_RIGHT/MIDDLE on buttonpads
+    - cifs: fix double free race when mount fails in cifs_get_root()
+    - dmaengine: shdma: Fix runtime PM imbalance on error
+    - i2c: cadence: allow COMPILE_TEST
+    - i2c: qup: allow COMPILE_TEST
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FN990
+    - usb: gadget: don't release an existing dev->buf
+    - usb: gadget: clear related members when goto fail
+    - ata: pata_hpt37x: fix PCI clock detection
+    - ALSA: intel_hdmi: Fix reference to PCM buffer address
+    - ASoC: ops: Shift tested values in snd_soc_put_volsw() by +min
+    - xfrm: fix MTU regression
+    - netfilter: fix use-after-free in __nf_register_net_hook()
+    - xfrm: enforce validity of offload input flags
+    - netfilter: nf_queue: don't assume sk is full socket
+    - netfilter: nf_queue: fix possible use-after-free
+    - batman-adv: Request iflink once in batadv-on-batadv check
+    - batman-adv: Request iflink once in batadv_get_real_netdevice
+    - batman-adv: Don't expect inter-netns unique iflink indices
+    - net: dcb: flush lingering app table entries for unregistered devices
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error generated by client
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error cause by server
+    - block: Fix fsync always failed if once failed
+    - xen/netfront: destroy queues before real_num_tx_queues is zeroed
+    - sched/topology: Make sched_init_numa() use a set for the deduplicating sort
+    - sched/topology: Fix sched_domain_topology_level alloc in sched_init_numa()
+    - ia64: ensure proper NUMA distance and possible map initialization
+    - mac80211: fix forwarded mesh frames AC & queue selection
+    - net: stmmac: fix return value of __setup handler
+    - iavf: Fix missing check for running netdev
+    - net: sxgbe: fix return value of __setup handler
+    - net: arcnet: com20020: Fix null-ptr-deref in com20020pci_probe()
+    - ixgbe: xsk: change !netif_carrier_ok() handling in ixgbe_xmit_zc()
+    - efivars: Respect "block" flag in efivar_entry_set_safe()
+    - firmware: arm_scmi: Remove space in MODULE_ALIAS name
+    - ASoC: cs4265: Fix the duplicated control name
+    - can: gs_usb: change active_channels's type from atomic_t to u8
+    - arm64: dts: rockchip: Switch RK3399-Gru DP to SPDIF output
+    - igc: igc_read_phy_reg_gpy: drop premature return
+    - ARM: Fix kgdb breakpoint for Thumb2
+    - ARM: 9182/1: mmu: fix returns from early_param() and __setup() functions
+    - igc: igc_write_phy_reg_gpy: drop premature return
+    - ibmvnic: free reset-work-item when flushing
+    - memfd: fix F_SEAL_WRITE after shmem huge page allocated
+    - soc: fsl: qe: Check of ioremap return value
+    - net: chelsio: cxgb3: check the return value of pci_find_capability()
+    - nl80211: Handle nla_memdup failures in handle_nan_filter
+    - Input: elan_i2c - move regulator_[en|dis]able() out of
+      elan_[en|dis]able_power()
+    - Input: elan_i2c - fix regulator enable count imbalance after suspend/resume
+    - HID: add mapping for KEY_DICTATE
+    - HID: add mapping for KEY_ALL_APPLICATIONS
+    - tracing/histogram: Fix sorting on old "cpu" value
+    - tracing: Fix return value of __setup handlers
+    - btrfs: fix lost prealloc extents beyond eof after full fsync
+    - btrfs: qgroup: fix deadlock between rescan worker and remove qgroup
+    - btrfs: add missing run of delayed items after unlink during log replay
+    - Revert "xfrm: xfrm_state_mtu should return at least 1280 for ipv6"
+    - net: dcb: disable softirqs in dcbnl_flush_dev()
+    - hamradio: fix macro redefine warning
+    - Linux 5.4.183
+  * Focal update: v5.4.182 upstream stable release (LP: #1969236)
+    - cgroup/cpuset: Fix a race between cpuset_attach() and cpu hotplug
+    - clk: jz4725b: fix mmc0 clock gating
+    - vhost/vsock: don't check owner in vhost_vsock_stop() while releasing
+    - parisc/unaligned: Fix fldd and fstd unaligned handlers on 32-bit kernel
+    - parisc/unaligned: Fix ldw() and stw() unalignment handlers
+    - drm/amdgpu: disable MMHUB PG for Picasso
+    - sr9700: sanity check for packet length
+    - USB: zaurus: support another broken Zaurus
+    - x86/fpu: Correct pkru/xstate inconsistency
+    - tee: export teedev_open() and teedev_close_context()
+    - optee: use driver internal tee_context for some rpc
+    - lan743x: fix deadlock in lan743x_phy_link_status_change()
+    - ping: remove pr_err from ping_lookup
+    - perf data: Fix double free in perf_session__delete()
+    - bpf: Do not try bpf_msg_push_data with len 0
+    - net: __pskb_pull_tail() & pskb_carve_frag_list() drop_monitor friends
+    - tipc: Fix end of loop tests for list_for_each_entry()
+    - gso: do not skip outer ip header in case of ipip and net_failover
+    - openvswitch: Fix setting ipv6 fields causing hw csum failure
+    - drm/edid: Always set RGB444
+    - net/mlx5e: Fix wrong return value on ioctl EEPROM query failure
+    - net: ll_temac: check the return value of devm_kmalloc()
+    - net: Force inlining of checksum functions in net/checksum.h
+    - nfp: flower: Fix a potential leak in nfp_tunnel_add_shared_mac()
+    - netfilter: nf_tables: fix memory leak during stateful obj update
+    - net/mlx5: Fix possible deadlock on rule deletion
+    - net/mlx5: Fix wrong limitation of metadata match on ecpf
+    - spi: spi-zynq-qspi: Fix a NULL pointer dereference in
+      zynq_qspi_exec_mem_op()
+    - configfs: fix a race in configfs_{,un}register_subsystem()
+    - RDMA/ib_srp: Fix a deadlock
+    - tracing: Have traceon and traceoff trigger honor the instance
+    - iio: adc: men_z188_adc: Fix a resource leak in an error handling path
+    - iio: adc: ad7124: fix mask used for setting AIN_BUFP & AIN_BUFM bits
+    - iio: Fix error handling for PM
+    - ata: pata_hpt37x: disable primary channel on HPT371
+    - Revert "USB: serial: ch341: add new Product ID for CH341A"
+    - usb: gadget: rndis: add spinlock for rndis response list
+    - tracefs: Set the group ownership in apply_options() not parse_options()
+    - USB: serial: option: add support for DW5829e
+    - USB: serial: option: add Telit LE910R1 compositions
+    - usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
+    - usb: dwc3: gadget: Let the interrupt handler disable bottom halves.
+    - xhci: re-initialize the HC during resume if HCE was set
+    - xhci: Prevent futile URB re-submissions due to incorrect return value.
+    - tty: n_gsm: fix encoding of control signal octet bit DV
+    - tty: n_gsm: fix proper link termination after failed open
+    - tty: n_gsm: fix NULL pointer access due to DLCI release
+    - gpio: tegra186: Fix chip_data type confusion
+    - Revert "drm/nouveau/pmu/gm200-: avoid touching PMU outside of
+      DEVINIT/PREOS/ACR"
+    - memblock: use kfree() to release kmalloced memblock regions
+    - fget: clarify and improve __fget_files() implementation
+    - Linux 5.4.182
+  * CVE-2022-28390
+    - can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
+
+  [ Ubuntu: 5.4.0-113.127 ]
+
+  * focal/linux: 5.4.0-113.127 -proposed tracker (LP: #1973980)
+  * CVE-2022-29581
+    - net/sched: cls_u32: fix netns refcount changes in u32_change()
+  * CVE-2022-1116
+    - io_uring: fix fs->users overflow
+  * ext4: limit length to bitmap_maxbytes (LP: #1972281)
+    - ext4: limit length to bitmap_maxbytes - blocksize in punch_hole
+  * 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
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 16 Jun 2022 14:40:57 +0800
+
+linux-imx (5.4.0-1020.21) focal; urgency=medium
+
+  * CVE-2022-23960
+    - [Config] set CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+
+  * Disable unprivileged BPF by default (LP: #1961338)
+    - [Config] set CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
+
+  * Re-enable DEBUG_INFO_BTF where it was disabled (LP: #1945632)
+    - [Config] Enable CONFIG_DEBUG_INFO_BTF on all arches
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys
+
+  * Focal update: v5.4.129 upstream stable release (LP: #1936242)
+    - [Config] enable CONFIG_SYSTEM_REVOCATION_LIST
+
+  * Kernel worker blocked for long time on system boot (LP: #1973786)
+    - lan743x: fix deadlock in lan743x_phy_link_status_change()
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+
+  [ Ubuntu: 5.4.0-110.124 ]
+
+  * focal/linux: 5.4.0-110.124 -proposed tracker (LP: #1969053)
+  * net/mlx5e: Fix page DMA map/unmap attributes (LP: #1967292)
+    - net/mlx5e: Fix page DMA map/unmap attributes
+  * xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+    (LP: #1966803)
+    - xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+  * LRMv6: add multi-architecture support (LP: #1968774)
+    - [Packaging] resync dkms-build{,--nvidia-N}
+  * xfrm interface cannot be changed anymore (LP: #1968591)
+    - xfrm: fix the if_id check in changelink
+  * Use kernel-testing repo from launchpad for ADT tests (LP: #1968016)
+    - [Debian] Use kernel-testing repo from launchpad
+  * vmx_ldtr_test in ubuntu_kvm_unit_tests failed (FAIL: Expected 0 for L1 LDTR
+    selector (got 50)) (LP: #1956315)
+    - KVM: nVMX: Set LDTR to its architecturally defined value on nested VM-Exit
+  * [SRU][Regression] Revert "PM: ACPI: reboot: Use S5 for reboot" which causes
+    Bus Fatal Error when rebooting system with BCM5720 NIC (LP: #1917471)
+    - Revert "PM: ACPI: reboot: Use S5 for reboot"
+  * Focal update: v5.4.181 upstream stable release (LP: #1967582)
+    - Makefile.extrawarn: Move -Wunaligned-access to W=1
+    - HID:Add support for UGTABLET WP5540
+    - Revert "svm: Add warning message for AVIC IPI invalid target"
+    - serial: parisc: GSC: fix build when IOSAPIC is not set
+    - parisc: Drop __init from map_pages declaration
+    - parisc: Fix data TLB miss in sba_unmap_sg
+    - parisc: Fix sglist access in ccio-dma.c
+    - btrfs: send: in case of IO error log it
+    - platform/x86: ISST: Fix possible circular locking dependency detected
+    - selftests: rtc: Increase test timeout so that all tests run
+    - net: ieee802154: at86rf230: Stop leaking skb's
+    - selftests/zram: Skip max_comp_streams interface on newer kernel
+    - selftests/zram01.sh: Fix compression ratio calculation
+    - selftests/zram: Adapt the situation that /dev/zram0 is being used
+    - ax25: improve the incomplete fix to avoid UAF and NPD bugs
+    - vfs: make freeze_super abort when sync_filesystem returns error
+    - quota: make dquot_quota_sync return errors from ->sync_fs
+    - nvme: fix a possible use-after-free in controller reset during load
+    - nvme-tcp: fix possible use-after-free in transport error_recovery work
+    - nvme-rdma: fix possible use-after-free in transport error_recovery work
+    - drm/amdgpu: fix logic inversion in check
+    - Revert "module, async: async_synchronize_full() on module init iff async is
+      used"
+    - ftrace: add ftrace_init_nop()
+    - module/ftrace: handle patchable-function-entry
+    - arm64: module: rework special section handling
+    - arm64: module/ftrace: intialize PLT at load time
+    - iwlwifi: fix use-after-free
+    - drm/radeon: Fix backlight control on iMac 12,1
+    - ext4: check for out-of-order index extents in ext4_valid_extent_entries()
+    - ext4: check for inconsistent extents between index and leaf block
+    - ext4: prevent partial update of the extent blocks
+    - taskstats: Cleanup the use of task->exit_code
+    - dmaengine: at_xdmac: Start transfer for cyclic channels in issue_pending
+    - vsock: remove vsock from connected table when connect is interrupted by a
+      signal
+    - mmc: block: fix read single on recovery logic
+    - iwlwifi: pcie: fix locking when "HW not ready"
+    - iwlwifi: pcie: gen2: fix locking when "HW not ready"
+    - netfilter: nft_synproxy: unregister hooks on init error path
+    - net: dsa: lan9303: fix reset on probe
+    - net: ieee802154: ca8210: Fix lifs/sifs periods
+    - ping: fix the dif and sdif check in ping_lookup
+    - bonding: force carrier update when releasing slave
+    - drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit
+    - bonding: fix data-races around agg_select_timer
+    - libsubcmd: Fix use-after-free for realloc(..., 0)
+    - ALSA: hda: Fix regression on forced probe mask option
+    - ALSA: hda: Fix missing codec probe on Shenker Dock 15
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw()
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw_range()
+    - powerpc/lib/sstep: fix 'ptesync' build error
+    - mtd: rawnand: gpmi: don't leak PM reference in error path
+    - block/wbt: fix negative inflight counter when remove scsi device
+    - NFS: LOOKUP_DIRECTORY is also ok with symlinks
+    - NFS: Do not report writeback errors in nfs_getattr()
+    - mtd: rawnand: qcom: Fix clock sequencing in qcom_nandc_probe()
+    - mtd: rawnand: brcmnand: Fixed incorrect sub-page ECC status
+    - scsi: lpfc: Fix pt2pt NVMe PRLI reject LOGO loop
+    - EDAC: Fix calculation of returned address and next offset in
+      edac_align_ptr()
+    - net: sched: limit TC_ACT_REPEAT loops
+    - dmaengine: sh: rcar-dmac: Check for error num after setting mask
+    - copy_process(): Move fd_install() out of sighand->siglock critical section
+    - i2c: brcmstb: fix support for DSL and CM variants
+    - Drivers: hv: vmbus: Fix memory leak in vmbus_add_channel_kobj
+    - KVM: x86/pmu: Use AMD64_RAW_EVENT_MASK for PERF_TYPE_RAW
+    - ARM: OMAP2+: hwmod: Add of_node_put() before break
+    - ARM: OMAP2+: adjust the location of put_device() call in omapdss_init_of
+    - irqchip/sifive-plic: Add missing thead,c900-plic match string
+    - netfilter: conntrack: don't refresh sctp entries in closed state
+    - arm64: dts: meson-gx: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: drop BL32 region from SEI510/SEI610
+    - kconfig: let 'shell' return enough output for deep path names
+    - ata: libata-core: Disable TRIM on M88V29
+    - drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
+    - tracing: Fix tp_printk option related with tp_printk_stop_on_boot
+    - net: usb: qmi_wwan: Add support for Dell DW5829e
+    - net: macb: Align the dma and coherent dma masks
+    - kconfig: fix failing to generate auto.conf
+    - Linux 5.4.181
+  * Focal update: v5.4.180 upstream stable release (LP: #1966118)
+    - integrity: check the return value of audit_log_start()
+    - ima: Remove ima_policy file before directory
+    - ima: Allow template selection with ima_template[_fmt]= after ima_hash=
+    - ima: Do not print policy rule with inactive LSM labels
+    - mmc: sdhci-of-esdhc: Check for error num after setting mask
+    - net: phy: marvell: Fix RGMII Tx/Rx delays setting in 88e1121-compatible PHYs
+    - net: phy: marvell: Fix MDI-x polarity setting in 88e1118-compatible PHYs
+    - NFS: Fix initialisation of nfs_client cl_flags field
+    - NFSD: Clamp WRITE offsets
+    - NFSD: Fix offset type in I/O trace points
+    - NFSv4 only print the label when its queried
+    - nfs: nfs4clinet: check the return value of kstrdup()
+    - NFSv4.1: Fix uninitialised variable in devicenotify
+    - NFSv4 remove zero number of fs_locations entries error check
+    - NFSv4 expose nfs_parse_server_name function
+    - drm: panel-orientation-quirks: Add quirk for the 1Netbook OneXPlayer
+    - net: sched: Clarify error message when qdisc kind is unknown
+    - scsi: target: iscsi: Make sure the np under each tpg is unique
+    - scsi: qedf: Fix refcount issue when LOGO is received during TMF
+    - scsi: myrs: Fix crash in error case
+    - PM: hibernate: Remove register_nosave_region_late()
+    - usb: dwc2: gadget: don't try to disable ep0 in dwc2_hsotg_suspend
+    - net: stmmac: dwmac-sun8i: use return val of readl_poll_timeout()
+    - KVM: nVMX: eVMCS: Filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER
+    - riscv: fix build with binutils 2.38
+    - ARM: dts: imx23-evk: Remove MX23_PAD_SSP1_DETECT from hog group
+    - ARM: socfpga: fix missing RESET_CONTROLLER
+    - nvme-tcp: fix bogus request completion when failing to send AER
+    - ACPI/IORT: Check node revision for PMCG resources
+    - PM: s2idle: ACPI: Fix wakeup interrupts handling
+    - net: bridge: fix stale eth hdr pointer in br_dev_xmit
+    - perf probe: Fix ppc64 'perf probe add events failed' case
+    - ARM: dts: meson: Fix the UART compatible strings
+    - staging: fbtft: Fix error path in fbtft_driver_module_init()
+    - ARM: dts: imx6qdl-udoo: Properly describe the SD card detect
+    - usb: f_fs: Fix use-after-free for epfile
+    - misc: fastrpc: avoid double fput() on failed usercopy
+    - ixgbevf: Require large buffers for build_skb on 82599VF
+    - bonding: pair enable_port with slave_arr_updates
+    - ipmr,ip6mr: acquire RTNL before calling ip[6]mr_free_table() on failure path
+    - nfp: flower: fix ida_idx not being released
+    - net: do not keep the dst cache when uncloning an skb dst and its metadata
+    - net: fix a memleak when uncloning an skb dst and its metadata
+    - veth: fix races around rq->rx_notify_masked
+    - net: mdio: aspeed: Add missing MODULE_DEVICE_TABLE
+    - tipc: rate limit warning for received illegal binding update
+    - net: amd-xgbe: disable interrupts during pci removal
+    - vt_ioctl: fix array_index_nospec in vt_setactivate
+    - vt_ioctl: add array_index_nospec to VT_ACTIVATE
+    - n_tty: wake up poll(POLLRDNORM) on receiving data
+    - eeprom: ee1004: limit i2c reads to I2C_SMBUS_BLOCK_MAX
+    - net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
+    - usb: ulpi: Move of_node_put to ulpi_dev_release
+    - usb: ulpi: Call of_node_put correctly
+    - usb: dwc3: gadget: Prevent core from processing stale TRBs
+    - usb: gadget: udc: renesas_usb3: Fix host to USB_ROLE_NONE transition
+    - USB: gadget: validate interface OS descriptor requests
+    - usb: gadget: rndis: check size of RNDIS_MSG_SET command
+    - usb: gadget: f_uac2: Define specific wTerminalType
+    - USB: serial: ftdi_sio: add support for Brainboxes US-159/235/320
+    - USB: serial: option: add ZTE MF286D modem
+    - USB: serial: ch341: add support for GW Instek USB2.0-Serial devices
+    - USB: serial: cp210x: add NCR Retail IO box id
+    - USB: serial: cp210x: add CPI Bulk Coin Recycler id
+    - seccomp: Invalidate seccomp mode to catch death failures
+    - hwmon: (dell-smm) Speed up setting of fan speed
+    - scsi: lpfc: Remove NVMe support if kernel has NVME_FC disabled
+    - perf: Fix list corruption in perf_cgroup_switch()
+    - Linux 5.4.180
+  * Focal update: v5.4.179 upstream stable release (LP: #1965591)
+    - moxart: fix potential use-after-free on remove path
+    - Linux 5.4.179
+  * CVE-2020-27820
+    - drm/nouveau: Add a dedicated mutex for the clients list
+    - drm/nouveau: clean up all clients on device removal
+  * CVE-2022-1016
+    - netfilter: nf_tables: initialize registers in nft_do_chain()
+  * CVE-2022-27223
+    - USB: gadget: validate endpoint index for xilinx udc
+  * CVE-2022-26490
+    - nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
+  * CVE-2021-26401
+    - x86/speculation: Use generic retpoline by default on AMD
+    - x86/speculation: Update link to AMD speculation whitepaper
+    - x86/speculation: Warn about Spectre v2 LFENCE mitigation
+    - x86/speculation: Warn about eIBRS + LFENCE + Unprivileged eBPF + SMT
+  * CVE-2022-0001
+    - x86/speculation: Include unprivileged eBPF status in Spectre v2 mitigation
+      reporting
+
+  [ Ubuntu: 5.4.0-109.123 ]
+
+  * focal/linux: 5.4.0-109.123 -proposed tracker (LP: #1968290)
+  * USB devices not detected during boot on USB 3.0 hubs (LP: #1968210)
+    - SAUCE: Revert "Revert "xhci: Set HCD flag to defer primary roothub
+      registration""
+    - SAUCE: Revert "Revert "usb: core: hcd: Add support for deferring roothub
+      registration""
+
+  [ Ubuntu: 5.4.0-108.122 ]
+
+  * focal/linux: 5.4.0-108.122 -proposed tracker (LP: #1966740)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync dkms-build{,--nvidia-N} from LRMv5
+    - debian/dkms-versions -- update from kernel-versions (main/2022.03.21)
+  * Low RX performance for 40G Solarflare NICs (LP: #1964512)
+    - SAUCE: sfc: The size of the RX recycle ring should be more flexible
+  * [UBUNTU 20.04] KVM: Enable storage key checking for intercepted instruction
+    (LP: #1962831)
+    - selftests: kvm: add _vm_ioctl
+    - selftests: kvm: Introduce the TEST_FAIL macro
+    - KVM: selftests: Add GUEST_ASSERT variants to pass values to host
+    - KVM: s390: gaccess: Refactor gpa and length calculation
+    - KVM: s390: gaccess: Refactor access address range check
+    - KVM: s390: gaccess: Cleanup access to guest pages
+    - s390/uaccess: introduce bit field for OAC specifier
+    - s390/uaccess: fix compile error
+    - s390/uaccess: Add copy_from/to_user_key functions
+    - KVM: s390: Honor storage keys when accessing guest memory
+    - KVM: s390: handle_tprot: Honor storage keys
+    - KVM: s390: selftests: Test TEST PROTECTION emulation
+    - KVM: s390: Add optional storage key checking to MEMOP IOCTL
+    - KVM: s390: Add vm IOCTL for key checked guest absolute memory access
+    - KVM: s390: Rename existing vcpu memop functions
+    - KVM: s390: Add capability for storage key extension of MEM_OP IOCTL
+    - KVM: s390: Update api documentation for memop ioctl
+    - KVM: s390: Clarify key argument for MEM_OP in api docs
+    - KVM: s390: Add missing vm MEM_OP size check
+  * 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon/sec2 - Add workqueue for SEC driver.
+    - crypto: hisilicon/sec2 - update SEC initialization and reset
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117)
+    - crypto: hisilicon - Use one workqueue per qm instead of per qp
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117) // 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon - Unify hardware error init/uninit into QM
+  * [UBUNTU 20.04] Fix SIGP processing on KVM/s390 (LP: #1962578)
+    - KVM: s390: Simplify SIGP Set Arch handling
+    - KVM: s390: Add a routine for setting userspace CPU state
+  * Move virtual graphics drivers from linux-modules-extra to linux-modules
+    (LP: #1960633)
+    - [Packaging] Move VM DRM drivers into modules
+  * Focal update: v5.4.178 upstream stable release (LP: #1964634)
+    - audit: improve audit queue handling when "audit=1" on cmdline
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw_sx()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_xr_sx()
+    - ALSA: usb-audio: Simplify quirk entries with a macro
+    - ALSA: hda/realtek: Add quirk for ASUS GU603
+    - ALSA: hda/realtek: Add missing fixup-model entry for Gigabyte X570 ALC1220
+      quirks
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570S Aorus Master (newer
+      chipset)
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570 Aorus Xtreme after
+      reboot from Windows
+    - btrfs: fix deadlock between quota disable and qgroup rescan worker
+    - drm/nouveau: fix off by one in BIOS boundary checking
+    - mm/kmemleak: avoid scanning potential huge holes
+    - block: bio-integrity: Advance seed correctly for larger interval sizes
+    - memcg: charge fs_context and legacy_fs_context
+    - IB/rdmavt: Validate remote_addr during loopback atomic tests
+    - RDMA/siw: Fix broken RDMA Read Fence/Resume logic.
+    - RDMA/mlx4: Don't continue event handler after memory allocation failure
+    - iommu/vt-d: Fix potential memory leak in intel_setup_irq_remapping()
+    - iommu/amd: Fix loop timeout issue in iommu_ga_log_enable()
+    - spi: bcm-qspi: check for valid cs before applying chip select
+    - spi: mediatek: Avoid NULL pointer crash in interrupt
+    - spi: meson-spicc: add IRQ check in meson_spicc_probe
+    - net: ieee802154: hwsim: Ensure proper channel selection at probe time
+    - net: ieee802154: mcr20a: Fix lifs/sifs periods
+    - net: ieee802154: ca8210: Stop leaking skb's
+    - net: ieee802154: Return meaningful error codes from the netlink helpers
+    - net: macsec: Verify that send_sci is on when setting Tx sci explicitly
+    - net: stmmac: dump gmac4 DMA registers correctly
+    - net: stmmac: ensure PTP time register reads are consistent
+    - drm/i915/overlay: Prevent divide by zero bugs in scaling
+    - ASoC: fsl: Add missing error handling in pcm030_fabric_probe
+    - ASoC: xilinx: xlnx_formatter_pcm: Make buffer bytes multiple of period bytes
+    - ASoC: cpcap: Check for NULL pointer after calling of_get_child_by_name
+    - ASoC: max9759: fix underflow in speaker_gain_control_put()
+    - pinctrl: bcm2835: Fix a few error paths
+    - scsi: bnx2fc: Make bnx2fc_recv_frame() mp safe
+    - nfsd: nfsd4_setclientid_confirm mistakenly expires confirmed client.
+    - selftests: futex: Use variable MAKE instead of make
+    - rtc: cmos: Evaluate century appropriate
+    - EDAC/altera: Fix deferred probing
+    - EDAC/xgene: Fix deferred probing
+    - ext4: fix error handling in ext4_restore_inline_data()
+    - cgroup/cpuset: Fix "suspicious RCU usage" lockdep warning
+    - Linux 5.4.178
+  * Focal update: v5.4.177 upstream stable release (LP: #1964628)
+    - PCI: pciehp: Fix infinite loop in IRQ handler upon power fault
+    - psi: Fix uaf issue when psi trigger is destroyed while being polled
+    - ipheth: fix EOVERFLOW in ipheth_rcvbulk_callback
+    - net: amd-xgbe: ensure to reset the tx_timer_active flag
+    - net: amd-xgbe: Fix skb data length underflow
+    - rtnetlink: make sure to refresh master_dev/m_ops in __rtnl_newlink()
+    - cpuset: Fix the bug that subpart_cpus updated wrongly in update_cpumask()
+    - af_packet: fix data-race in packet_setsockopt / packet_setsockopt
+    - Linux 5.4.177
+  * Focal update: v5.4.176 upstream stable release (LP: #1962345)
+    - s390/hypfs: include z/VM guests with access control group set
+    - scsi: zfcp: Fix failed recovery on gone remote port with non-NPIV FCP
+      devices
+    - udf: Restore i_lenAlloc when inode expansion fails
+    - udf: Fix NULL ptr deref when converting from inline format
+    - PM: wakeup: simplify the output logic of pm_show_wakelocks()
+    - tracing/histogram: Fix a potential memory leak for kstrdup()
+    - tracing: Don't inc err_log entry count if entry allocation fails
+    - fsnotify: fix fsnotify hooks in pseudo filesystems
+    - drm/etnaviv: relax submit size limits
+    - arm64: errata: Fix exec handling in erratum 1418040 workaround
+    - netfilter: nft_payload: do not update layer 4 checksum when mangling
+      fragments
+    - serial: 8250: of: Fix mapped region size when using reg-offset property
+    - serial: stm32: fix software flow control transfer
+    - tty: n_gsm: fix SW flow control encoding/handling
+    - tty: Add support for Brainboxes UC cards.
+    - usb-storage: Add unusual-devs entry for VL817 USB-SATA bridge
+    - usb: common: ulpi: Fix crash in ulpi_match()
+    - usb: gadget: f_sourcesink: Fix isoc transfer for USB_SPEED_SUPER_PLUS
+    - USB: core: Fix hang in usb_kill_urb by adding memory barriers
+    - usb: typec: tcpm: Do not disconnect while receiving VBUS off
+    - ucsi_ccg: Check DEV_INT bit only when starting CCG4
+    - net: sfp: ignore disabled SFP node
+    - powerpc/32: Fix boot failure with GCC latent entropy plugin
+    - i40e: Increase delay to 1 s after global EMP reset
+    - i40e: Fix issue when maximum queues is exceeded
+    - i40e: Fix queues reservation for XDP
+    - i40e: fix unsigned stat widths
+    - rpmsg: char: Fix race between the release of rpmsg_ctrldev and cdev
+    - rpmsg: char: Fix race between the release of rpmsg_eptdev and cdev
+    - scsi: bnx2fc: Flush destroy_work queue before calling bnx2fc_interface_put()
+    - ipv6_tunnel: Rate limit warning messages
+    - net: fix information leakage in /proc/net/ptype
+    - hwmon: (lm90) Mark alert as broken for MAX6646/6647/6649
+    - hwmon: (lm90) Mark alert as broken for MAX6680
+    - ping: fix the sk_bound_dev_if match in ping_lookup
+    - ipv4: avoid using shared IP generator for connected sockets
+    - hwmon: (lm90) Reduce maximum conversion rate for G781
+    - NFSv4: Handle case where the lookup of a directory fails
+    - NFSv4: nfs_atomic_open() can race when looking up a non-regular file
+    - net-procfs: show net devices bound packet types
+    - drm/msm: Fix wrong size calculation
+    - drm/msm/dsi: Fix missing put_device() call in dsi_get_phy
+    - drm/msm/dsi: invalid parameter check in msm_dsi_phy_enable
+    - ipv6: annotate accesses to fn->fn_sernum
+    - NFS: Ensure the server has an up to date ctime before hardlinking
+    - NFS: Ensure the server has an up to date ctime before renaming
+    - netfilter: conntrack: don't increment invalid counter on NF_REPEAT
+    - net: phy: broadcom: hook up soft_reset for BCM54616S
+    - phylib: fix potential use-after-free
+    - rxrpc: Adjust retransmission backoff
+    - hwmon: (lm90) Mark alert as broken for MAX6654
+    - ibmvnic: init ->running_cap_crqs early
+    - ibmvnic: don't spin in tasklet
+    - drm/msm/hdmi: Fix missing put_device() call in msm_hdmi_get_phy
+    - yam: fix a memory leak in yam_siocdevprivate()
+    - net: hns3: handle empty unknown interrupt for VF
+    - ipv4: raw: lock the socket in raw_bind()
+    - ipv4: tcp: send zero IPID in SYNACK messages
+    - ipv4: remove sparse error in ip_neigh_gw4()
+    - dt-bindings: can: tcan4x5x: fix mram-cfg RX FIFO config
+    - fsnotify: invalidate dcache before IN_DELETE event
+    - block: Fix wrong offset in bio_truncate()
+    - mtd: rawnand: mpc5121: Remove unused variable in ads5121_select_chip()
+    - Linux 5.4.176
+  * Focal update: v5.4.175 upstream stable release (LP: #1962330)
+    - rcu: Tighten rcu_advance_cbs_nowake() checks
+    - pinctrl: bcm2835: Drop unused define
+    - pinctrl: bcm2835: Refactor platform data
+    - pinctrl: bcm2835: Add support for all GPIOs on BCM2711
+    - pinctrl: bcm2835: Match BCM7211 compatible string
+    - pinctrl: bcm2835: Add support for wake-up interrupts
+    - pinctrl: bcm2835: Change init order for gpio hogs
+    - ARM: dts: gpio-ranges property is now required
+    - mmc: sdhci-esdhc-imx: disable CMDQ support
+    - select: Fix indefinitely sleeping task in poll_schedule_timeout()
+    - Linux 5.4.175
+
+  [ Ubuntu: 5.4.0-107.121 ]
+
+  * focal/linux: 5.4.0-107.121 -proposed tracker (LP: #1966275)
+  * CVE-2022-27666
+    - esp: Fix possible buffer overflow in ESP transformation
+  * CVE-2022-1055
+    - net: sched: fix use-after-free in tc_new_tfilter()
+  * Pick fixup from v5.4.176 upstream stable release to address cert
+    failure with clock jitter test in NUC7i3DNHE (LP: #1964204)
+    - Bluetooth: refactor malicious adv data check
+
+  [ Ubuntu: 5.4.0-105.119 ]
+
+  * CVE-2022-0847
+    - lib/iov_iter: initialize "flags" in new pipe_buffer
+  * Broken network on some AWS instances with focal/impish kernels
+    (LP: #1961968)
+    - SAUCE: Revert "PCI/MSI: Mask MSI-X vectors only on success"
+  * [UBUNTU 20.04] kernel: Add support for CPU-MF counter second version 7
+    (LP: #1960182)
+    - s390/cpumf: Support for CPU Measurement Facility CSVN 7
+    - s390/cpumf: Support for CPU Measurement Sampling Facility LS bit
+  * Hipersocket page allocation failure on Ubuntu 20.04 based SSC environments
+    (LP: #1959529)
+    - s390/qeth: use memory reserves to back RX buffers
+  * CVE-2022-0516
+    - KVM: s390: Return error on SIDA memop on normal guest
+  * CVE-2022-0435
+    - tipc: improve size validations for received domain records
+  * CVE-2022-0492
+    - cgroup-v1: Require capabilities to set release_agent
+  * Recalled NFSv4 files delegations overwhelm server (LP: #1957986)
+    - NFSv4: Fix delegation handling in update_open_stateid()
+    - NFSv4: nfs4_callback_getattr() should ignore revoked delegations
+    - NFSv4: Delegation recalls should not find revoked delegations
+    - NFSv4: fail nfs4_refresh_delegation_stateid() when the delegation was
+      revoked
+    - NFS: Rename nfs_inode_return_delegation_noreclaim()
+    - NFSv4: Don't remove the delegation from the super_list more than once
+    - NFSv4: Hold the delegation spinlock when updating the seqid
+    - NFSv4: Clear the NFS_DELEGATION_REVOKED flag in
+      nfs_update_inplace_delegation()
+    - NFSv4: Update the stateid seqid in nfs_revoke_delegation()
+    - NFSv4: Revoke the delegation on success in nfs4_delegreturn_done()
+    - NFSv4: Ignore requests to return the delegation if it was revoked
+    - NFSv4: Don't reclaim delegations that have been returned or revoked
+    - NFSv4: nfs4_return_incompatible_delegation() should check delegation
+      validity
+    - NFSv4: Fix nfs4_inode_make_writeable()
+    - NFS: nfs_inode_find_state_and_recover() fix stateid matching
+    - NFSv4: Fix races between open and delegreturn
+    - NFSv4: Handle NFS4ERR_OLD_STATEID in delegreturn
+    - NFSv4: Don't retry the GETATTR on old stateid in nfs4_delegreturn_done()
+    - NFSv4: nfs_inode_evict_delegation() should set NFS_DELEGATION_RETURNING
+    - NFS: Clear NFS_DELEGATION_RETURN_IF_CLOSED when the delegation is returned
+    - NFSv4: Try to return the delegation immediately when marked for return on
+      close
+    - NFSv4: Add accounting for the number of active delegations held
+    - NFSv4: Limit the total number of cached delegations
+    - NFSv4: Ensure the delegation is pinned in nfs_do_return_delegation()
+    - NFSv4: Ensure the delegation cred is pinned when we call delegreturn
+  * Focal update: v5.4.174 upstream stable release (LP: #1960566)
+    - HID: uhid: Fix worker destroying device without any protection
+    - HID: wacom: Reset expected and received contact counts at the same time
+    - HID: wacom: Ignore the confidence flag when a touch is removed
+    - HID: wacom: Avoid using stale array indicies to read contact count
+    - f2fs: fix to do sanity check in is_alive()
+    - nfc: llcp: fix NULL error pointer dereference on sendmsg() after failed
+      bind()
+    - mtd: rawnand: gpmi: Add ERR007117 protection for nfc_apply_timings
+    - mtd: rawnand: gpmi: Remove explicit default gpmi clock setting for i.MX6
+    - x86/gpu: Reserve stolen memory for first integrated Intel GPU
+    - tools/nolibc: x86-64: Fix startup code bug
+    - tools/nolibc: i386: fix initial stack alignment
+    - tools/nolibc: fix incorrect truncation of exit code
+    - rtc: cmos: take rtc_lock while reading from CMOS
+    - media: v4l2-ioctl.c: readbuffers depends on V4L2_CAP_READWRITE
+    - media: flexcop-usb: fix control-message timeouts
+    - media: mceusb: fix control-message timeouts
+    - media: em28xx: fix control-message timeouts
+    - media: cpia2: fix control-message timeouts
+    - media: s2255: fix control-message timeouts
+    - media: dib0700: fix undefined behavior in tuner shutdown
+    - media: redrat3: fix control-message timeouts
+    - media: pvrusb2: fix control-message timeouts
+    - media: stk1160: fix control-message timeouts
+    - can: softing_cs: softingcs_probe(): fix memleak on registration failure
+    - lkdtm: Fix content of section containing lkdtm_rodata_do_nothing()
+    - iommu/io-pgtable-arm-v7s: Add error handle for page table allocation failure
+    - dma_fence_array: Fix PENDING_ERROR leak in dma_fence_array_signaled()
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9125 SATA controller
+    - mm_zone: add function to check if managed dma zone exists
+    - mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed
+      pages
+    - shmem: fix a race between shmem_unused_huge_shrink and shmem_evict_inode
+    - drm/rockchip: dsi: Hold pm-runtime across bind/unbind
+    - drm/rockchip: dsi: Reconfigure hardware on resume()
+    - drm/panel: kingdisplay-kd097d04: Delete panel on attach() failure
+    - drm/panel: innolux-p079zca: Delete panel on attach() failure
+    - drm/rockchip: dsi: Fix unbalanced clock on probe error
+    - Bluetooth: cmtp: fix possible panic when cmtp_init_sockets() fails
+    - clk: bcm-2835: Pick the closest clock rate
+    - clk: bcm-2835: Remove rounding up the dividers
+    - wcn36xx: Indicate beacon not connection loss on MISSED_BEACON_IND
+    - wcn36xx: Release DMA channel descriptor allocations
+    - media: videobuf2: Fix the size printk format
+    - media: aspeed: fix mode-detect always time out at 2nd run
+    - media: em28xx: fix memory leak in em28xx_init_dev
+    - media: aspeed: Update signal status immediately to ensure sane hw state
+    - arm64: dts: meson-gxbb-wetek: fix HDMI in early boot
+    - arm64: dts: meson-gxbb-wetek: fix missing GPIO binding
+    - Bluetooth: stop proccessing malicious adv data
+    - tee: fix put order in teedev_close_context()
+    - media: dmxdev: fix UAF when dvb_register_device() fails
+    - crypto: qce - fix uaf on qce_ahash_register_one
+    - arm64: dts: ti: k3-j721e: correct cache-sets info
+    - tty: serial: atmel: Check return code of dmaengine_submit()
+    - tty: serial: atmel: Call dma_async_issue_pending()
+    - media: rcar-csi2: Correct the selection of hsfreqrange
+    - media: imx-pxp: Initialize the spinlock prior to using it
+    - media: si470x-i2c: fix possible memory leak in si470x_i2c_probe()
+    - media: mtk-vcodec: call v4l2_m2m_ctx_release first when file is released
+    - media: venus: core: Fix a resource leak in the error handling path of
+      'venus_probe()'
+    - netfilter: bridge: add support for pppoe filtering
+    - arm64: dts: qcom: msm8916: fix MMC controller aliases
+    - ACPI: EC: Rework flushing of EC work while suspended to idle
+    - drm/amdgpu: Fix a NULL pointer dereference in
+      amdgpu_connector_lcd_native_mode()
+    - drm/radeon/radeon_kms: Fix a NULL pointer dereference in
+      radeon_driver_open_kms()
+    - arm64: dts: ti: k3-j721e: Fix the L2 cache sets
+    - tty: serial: uartlite: allow 64 bit address
+    - serial: amba-pl011: do not request memory region twice
+    - floppy: Fix hang in watchdog when disk is ejected
+    - staging: rtl8192e: return error code from rtllib_softmac_init()
+    - staging: rtl8192e: rtllib_module: fix error handle case in alloc_rtllib()
+    - Bluetooth: btmtksdio: fix resume failure
+    - media: dib8000: Fix a memleak in dib8000_init()
+    - media: saa7146: mxb: Fix a NULL pointer dereference in mxb_attach()
+    - media: si2157: Fix "warm" tuner state detection
+    - sched/rt: Try to restart rt period timer when rt runtime exceeded
+    - rcu/exp: Mark current CPU as exp-QS in IPI loop second pass
+    - mwifiex: Fix possible ABBA deadlock
+    - xfrm: fix a small bug in xfrm_sa_len()
+    - crypto: stm32/cryp - fix xts and race condition in crypto_engine requests
+    - crypto: stm32/cryp - fix double pm exit
+    - crypto: stm32/cryp - fix lrw chaining mode
+    - ARM: dts: gemini: NAS4220-B: fis-index-block with 128 KiB sectors
+    - media: dw2102: Fix use after free
+    - media: msi001: fix possible null-ptr-deref in msi001_probe()
+    - media: coda/imx-vdoa: Handle dma_set_coherent_mask error codes
+    - drm/msm/dpu: fix safe status debugfs file
+    - drm/bridge: ti-sn65dsi86: Set max register for regmap
+    - media: hantro: Fix probe func error path
+    - xfrm: interface with if_id 0 should return error
+    - xfrm: state and policy should fail if XFRMA_IF_ID 0
+    - ARM: 9159/1: decompressor: Avoid UNPREDICTABLE NOP encoding
+    - usb: ftdi-elan: fix memory leak on device disconnect
+    - ARM: dts: armada-38x: Add generic compatible to UART nodes
+    - mmc: meson-mx-sdio: add IRQ check
+    - selinux: fix potential memleak in selinux_add_opt()
+    - bpftool: Enable line buffering for stdout
+    - x86/mce/inject: Avoid out-of-bounds write when setting flags
+    - ACPI: scan: Create platform device for BCM4752 and LNV4752 ACPI nodes
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      __nonstatic_find_io_region()
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      nonstatic_find_mem_region()
+    - netfilter: ipt_CLUSTERIP: fix refcount leak in clusterip_tg_check()
+    - bpf: Fix SO_RCVBUF/SO_SNDBUF handling in _bpf_setsockopt().
+    - ppp: ensure minimum packet size in ppp_write()
+    - rocker: fix a sleeping in atomic bug
+    - staging: greybus: audio: Check null pointer
+    - fsl/fman: Check for null pointer after calling devm_ioremap
+    - Bluetooth: hci_bcm: Check for error irq
+    - HID: hid-uclogic-params: Invalid parameter check in uclogic_params_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_get_str_desc
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_huion_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_frame_init_v1_buttonpad
+    - debugfs: lockdown: Allow reading debugfs files that are not world readable
+    - net/mlx5e: Don't block routes with nexthop objects in SW
+    - Revert "net/mlx5e: Block offload of outer header csum for UDP tunnels"
+    - net/mlx5: Set command entry semaphore up once got index free
+    - spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe
+    - tpm: add request_locality before write TPM_INT_ENABLE
+    - can: softing: softing_startstop(): fix set but not used variable warning
+    - can: xilinx_can: xcan_probe(): check for error irq
+    - pcmcia: fix setting of kthread task states
+    - net: mcs7830: handle usb read errors properly
+    - ext4: avoid trim error on fs with small groups
+    - ALSA: jack: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: PCM: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: hda: Add missing rwsem around snd_ctl_remove() calls
+    - RDMA/hns: Validate the pkey index
+    - clk: imx8mn: Fix imx8mn_clko1_sels
+    - powerpc/prom_init: Fix improper check of prom_getprop()
+    - ASoC: uniphier: drop selecting non-existing SND_SOC_UNIPHIER_AIO_DMA
+    - ALSA: oss: fix compile error when OSS_DEBUG is enabled
+    - char/mwave: Adjust io port register size
+    - binder: fix handling of error during copy
+    - iommu/io-pgtable-arm: Fix table descriptor paddr formatting
+    - scsi: ufs: Fix race conditions related to driver data
+    - PCI/MSI: Fix pci_irq_vector()/pci_irq_get_affinity()
+    - powerpc/powermac: Add additional missing lockdep_register_key()
+    - RDMA/core: Let ib_find_gid() continue search even after empty entry
+    - RDMA/cma: Let cma_resolve_ib_dev() continue search even after empty entry
+    - ASoC: rt5663: Handle device_property_read_u32_array error codes
+    - clk: stm32: Fix ltdc's clock turn off by clk_disable_unused() after system
+      enter shell
+    - dmaengine: pxa/mmp: stop referencing config->slave_id
+    - iommu/iova: Fix race between FQ timeout and teardown
+    - phy: uniphier-usb3ss: fix unintended writing zeros to PHY register
+    - ASoC: samsung: idma: Check of ioremap return value
+    - misc: lattice-ecp3-config: Fix task hung when firmware load failed
+    - mips: lantiq: add support for clk_set_parent()
+    - mips: bcm63xx: add support for clk_set_parent()
+    - RDMA/cxgb4: Set queue pair state when being queried
+    - of: base: Fix phandle argument length mismatch error message
+    - Bluetooth: Fix debugfs entry leak in hci_register_dev()
+    - fs: dlm: filter user dlm messages for kernel locks
+    - drm/lima: fix warning when CONFIG_DEBUG_SG=y & CONFIG_DMA_API_DEBUG=y
+    - ar5523: Fix null-ptr-deref with unexpected WDCMSG_TARGET_START reply
+    - drm/nouveau/pmu/gm200-: avoid touching PMU outside of DEVINIT/PREOS/ACR
+    - ARM: shmobile: rcar-gen2: Add missing of_node_put()
+    - batman-adv: allow netlink usage in unprivileged containers
+    - usb: gadget: f_fs: Use stream_open() for endpoint files
+    - drm: panel-orientation-quirks: Add quirk for the Lenovo Yoga Book X91F/L
+    - HID: apple: Do not reset quirks when the Fn key is not found
+    - media: b2c2: Add missing check in flexcop_pci_isr:
+    - EDAC/synopsys: Use the quirk for version instead of ddr version
+    - mlxsw: pci: Add shutdown method in PCI driver
+    - drm/bridge: megachips: Ensure both bridges are probed before registration
+    - gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use
+    - HSI: core: Fix return freed object in hsi_new_client
+    - mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
+    - rsi: Fix use-after-free in rsi_rx_done_handler()
+    - rsi: Fix out-of-bounds read in rsi_read_pkt()
+    - usb: uhci: add aspeed ast2600 uhci support
+    - floppy: Add max size check for user space request
+    - x86/mm: Flush global TLB when switching to trampoline page-table
+    - media: uvcvideo: Increase UVC_CTRL_CONTROL_TIMEOUT to 5 seconds.
+    - media: saa7146: hexium_orion: Fix a NULL pointer dereference in
+      hexium_attach()
+    - media: m920x: don't use stack on USB reads
+    - iwlwifi: mvm: synchronize with FW after multicast commands
+    - ath10k: Fix tx hanging
+    - net-sysfs: update the queue counts in the unregistration path
+    - net: phy: prefer 1000baseT over 1000baseKX
+    - gpio: aspeed: Convert aspeed_gpio.lock to raw_spinlock
+    - x86/mce: Mark mce_panic() noinstr
+    - x86/mce: Mark mce_end() noinstr
+    - x86/mce: Mark mce_read_aux() noinstr
+    - net: bonding: debug: avoid printing debug logs when bond is not notifying
+      peers
+    - bpf: Do not WARN in bpf_warn_invalid_xdp_action()
+    - HID: quirks: Allow inverting the absolute X/Y values
+    - media: igorplugusb: receiver overflow should be reported
+    - media: saa7146: hexium_gemini: Fix a NULL pointer dereference in
+      hexium_attach()
+    - mmc: core: Fixup storing of OCR for MMC_QUIRK_NONSTD_SDIO
+    - audit: ensure userspace is penalized the same as the kernel when under
+      pressure
+    - arm64: dts: ls1028a-qds: move rtc node to the correct i2c bus
+    - arm64: tegra: Adjust length of CCPLEX cluster MMIO region
+    - cpufreq: Fix initialization of min and max frequency QoS requests
+    - usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0
+    - ath9k: Fix out-of-bound memcpy in ath9k_hif_usb_rx_stream
+    - iwlwifi: fix leaks/bad data after failed firmware load
+    - iwlwifi: remove module loading failure message
+    - iwlwifi: mvm: Fix calculation of frame length
+    - um: registers: Rename function names to avoid conflicts and build problems
+    - jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
+    - ACPICA: actypes.h: Expand the ACPI_ACCESS_ definitions
+    - ACPICA: Utilities: Avoid deleting the same object twice in a row
+    - ACPICA: Executer: Fix the REFCLASS_REFOF case in acpi_ex_opcode_1A_0T_1R()
+    - ACPICA: Fix wrong interpretation of PCC address
+    - ACPICA: Hardware: Do not flush CPU cache when entering S4 and S5
+    - drm/amdgpu: fixup bad vram size on gmc v8
+    - ACPI: battery: Add the ThinkPad "Not Charging" quirk
+    - btrfs: remove BUG_ON() in find_parent_nodes()
+    - btrfs: remove BUG_ON(!eie) in find_parent_nodes
+    - net: mdio: Demote probed message to debug print
+    - mac80211: allow non-standard VHT MCS-10/11
+    - dm btree: add a defensive bounds check to insert_at()
+    - dm space map common: add bounds check to sm_ll_lookup_bitmap()
+    - net: phy: marvell: configure RGMII delays for 88E1118
+    - net: gemini: allow any RGMII interface mode
+    - regulator: qcom_smd: Align probe function with rpmh-regulator
+    - serial: pl010: Drop CR register reset on set_termios
+    - serial: core: Keep mctrl register state and cached copy in sync
+    - random: do not throw away excess input to crng_fast_load
+    - parisc: Avoid calling faulthandler_disabled() twice
+    - powerpc/6xx: add missing of_node_put
+    - powerpc/powernv: add missing of_node_put
+    - powerpc/cell: add missing of_node_put
+    - powerpc/btext: add missing of_node_put
+    - powerpc/watchdog: Fix missed watchdog reset due to memory ordering race
+    - i2c: i801: Don't silently correct invalid transfer size
+    - powerpc/smp: Move setup_profiling_timer() under CONFIG_PROFILING
+    - i2c: mpc: Correct I2C reset procedure
+    - clk: meson: gxbb: Fix the SDM_EN bit for MPLL0 on GXBB
+    - powerpc/powermac: Add missing lockdep_register_key()
+    - KVM: PPC: Book3S: Suppress failed alloc warning in H_COPY_TOFROM_GUEST
+    - w1: Misuse of get_user()/put_user() reported by sparse
+    - scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup
+    - ALSA: seq: Set upper limit of processed events
+    - powerpc: handle kdump appropriately with crash_kexec_post_notifiers option
+    - MIPS: OCTEON: add put_device() after of_find_device_by_node()
+    - i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters
+    - MIPS: Octeon: Fix build errors using clang
+    - scsi: sr: Don't use GFP_DMA
+    - ASoC: mediatek: mt8173: fix device_node leak
+    - power: bq25890: Enable continuous conversion for ADC at charging
+    - rpmsg: core: Clean up resources on announce_create failure.
+    - crypto: omap-aes - Fix broken pm_runtime_and_get() usage
+    - crypto: stm32/crc32 - Fix kernel BUG triggered in probe()
+    - crypto: caam - replace this_cpu_ptr with raw_cpu_ptr
+    - ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
+    - fuse: Pass correct lend value to filemap_write_and_wait_range()
+    - serial: Fix incorrect rs485 polarity on uart open
+    - cputime, cpuacct: Include guest time in user time in cpuacct.stat
+    - tracing/kprobes: 'nmissed' not showed correctly for kretprobe
+    - iwlwifi: mvm: Increase the scan timeout guard to 30 seconds
+    - s390/mm: fix 2KB pgtable release race
+    - drm/etnaviv: limit submit sizes
+    - drm/nouveau/kms/nv04: use vzalloc for nv04_display
+    - drm/bridge: analogix_dp: Make PSR-exit block less
+    - PCI: pci-bridge-emul: Properly mark reserved PCIe bits in PCI config space
+    - PCI: pci-bridge-emul: Correctly set PCIe capabilities
+    - PCI: pci-bridge-emul: Set PCI_STATUS_CAP_LIST for PCIe device
+    - xfrm: fix policy lookup for ipv6 gre packets
+    - btrfs: fix deadlock between quota enable and other quota operations
+    - btrfs: check the root node for uptodate before returning it
+    - btrfs: respect the max size in the header when activating swap file
+    - ext4: make sure to reset inode lockdep class when quota enabling fails
+    - ext4: make sure quota gets properly shutdown on error
+    - ext4: set csum seed in tmp inode while migrating to extents
+    - ext4: Fix BUG_ON in ext4_bread when write quota data
+    - ext4: don't use the orphan list when migrating an inode
+    - drm/radeon: fix error handling in radeon_driver_open_kms
+    - of: base: Improve argument length mismatch error
+    - firmware: Update Kconfig help text for Google firmware
+    - media: rcar-csi2: Optimize the selection PHTW register
+    - Documentation: dmaengine: Correctly describe dmatest with channel unset
+    - Documentation: ACPI: Fix data node reference documentation
+    - Documentation: refer to config RANDOMIZE_BASE for kernel address-space
+      randomization
+    - Documentation: fix firewire.rst ABI file path error
+    - scsi: core: Show SCMD_LAST in text form
+    - RDMA/hns: Modify the mapping attribute of doorbell to device
+    - RDMA/rxe: Fix a typo in opcode name
+    - dmaengine: stm32-mdma: fix STM32_MDMA_CTBR_TSEL_MASK
+    - Revert "net/mlx5: Add retry mechanism to the command entry index allocation"
+    - powerpc/cell: Fix clang -Wimplicit-fallthrough warning
+    - powerpc/fsl/dts: Enable WA for erratum A-009885 on fman3l MDIO buses
+    - bpftool: Remove inclusion of utilities.mak from Makefiles
+    - ipv4: avoid quadratic behavior in netns dismantle
+    - net/fsl: xgmac_mdio: Fix incorrect iounmap when removing module
+    - parisc: pdc_stable: Fix memory leak in pdcs_register_pathentries
+    - f2fs: fix to reserve space for IO align feature
+    - af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
+    - clk: si5341: Fix clock HW provider cleanup
+    - net: axienet: limit minimum TX ring size
+    - net: axienet: fix number of TX ring slots for available check
+    - net: axienet: increase default TX ring size to 128
+    - rtc: pxa: fix null pointer dereference
+    - inet: frags: annotate races around fqdir->dead and fqdir->high_thresh
+    - netns: add schedule point in ops_exit_list()
+    - xfrm: Don't accidentally set RTO_ONLINK in decode_session4()
+    - gre: Don't accidentally set RTO_ONLINK in gre_fill_metadata_dst()
+    - libcxgb: Don't accidentally set RTO_ONLINK in cxgb_find_route()
+    - perf script: Fix hex dump character output
+    - dmaengine: at_xdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_xdmac: Print debug message after realeasing the lock
+    - dmaengine: at_xdmac: Fix concurrency over xfers_list
+    - dmaengine: at_xdmac: Fix lld view setting
+    - dmaengine: at_xdmac: Fix at_xdmac_lld struct definition
+    - arm64: dts: qcom: msm8996: drop not documented adreno properties
+    - net_sched: restore "mpu xxx" handling
+    - bcmgenet: add WOL IRQ check
+    - net: ethernet: mtk_eth_soc: fix error checking in mtk_mac_config()
+    - dt-bindings: display: meson-dw-hdmi: add missing sound-name-prefix property
+    - dt-bindings: display: meson-vpu: Add missing amlogic,canvas property
+    - scripts/dtc: dtx_diff: remove broken example from help text
+    - lib82596: Fix IRQ check in sni_82596_probe
+    - lib/test_meminit: destroy cache in kmem_cache_alloc_bulk() test
+    - mtd: nand: bbt: Fix corner case in bad block table handling
+    - Revert "ia64: kprobes: Use generic kretprobe trampoline handler"
+    - Linux 5.4.174
+  * Focal update: v5.4.173 upstream stable release (LP: #1959701)
+    - kbuild: Add $(KBUILD_HOSTLDFLAGS) to 'has_libelf' test
+    - devtmpfs regression fix: reconfigure on each mount
+    - orangefs: Fix the size of a memory allocation in orangefs_bufmap_alloc()
+    - perf: Protect perf_guest_cbs with RCU
+    - KVM: s390: Clarify SIGP orders versus STOP/RESTART
+    - media: uvcvideo: fix division by zero at stream start
+    - rtlwifi: rtl8192cu: Fix WARNING when calling local_irq_restore() with
+      interrupts enabled
+    - firmware: qemu_fw_cfg: fix sysfs information leak
+    - firmware: qemu_fw_cfg: fix NULL-pointer deref on duplicate entries
+    - firmware: qemu_fw_cfg: fix kobject leak in probe error path
+    - KVM: x86: remove PMU FIXED_CTR3 from msrs_to_save_all
+    - ALSA: hda/realtek - Fix silent output on Gigabyte X570 Aorus Master after
+      reboot from Windows
+    - mtd: fixup CFI on ixp4xx
+    - ARM: 9025/1: Kconfig: CPU_BIG_ENDIAN depends on !LD_IS_LLD
+    - Linux 5.4.173
+  * Focal update: v5.4.172 upstream stable release (LP: #1959698)
+    - workqueue: Fix unbind_workers() VS wq_worker_running() race
+    - Bluetooth: btusb: fix memory leak in btusb_mtk_submit_wmt_recv_urb()
+    - Bluetooth: bfusb: fix division by zero in send path
+    - USB: core: Fix bug in resuming hub's handling of wakeup requests
+    - USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
+    - mmc: sdhci-pci: Add PCI ID for Intel ADL
+    - veth: Do not record rx queue hint in veth_xmit
+    - mfd: intel-lpss: Fix too early PM enablement in the ACPI ->probe()
+    - drivers core: Use sysfs_emit and sysfs_emit_at for show(device *...)
+      functions
+    - can: gs_usb: fix use of uninitialized variable, detach device on reception
+      of invalid USB data
+    - can: gs_usb: gs_can_start_xmit(): zero-initialize hf->{flags,reserved}
+    - random: fix data race on crng_node_pool
+    - random: fix data race on crng init time
+    - random: fix crash on multiple early calls to add_bootloader_randomness()
+    - media: Revert "media: uvcvideo: Set unique vdev name based in type"
+    - staging: wlan-ng: Avoid bitwise vs logical OR warning in
+      hfa384x_usb_throttlefn()
+    - drm/i915: Avoid bitwise vs logical OR warning in snb_wm_latency_quirk()
+    - staging: greybus: fix stack size warning with UBSAN
+    - Linux 5.4.172
+  * Focal update: v5.4.171 upstream stable release (LP: #1959437)
+    - f2fs: quota: fix potential deadlock
+    - Input: touchscreen - Fix backport of
+      a02dcde595f7cbd240ccd64de96034ad91cffc40
+    - selftests: x86: fix [-Wstringop-overread] warn in test_process_vm_readv()
+    - tracing: Fix check for trace_percpu_buffer validity in get_trace_buf()
+    - tracing: Tag trace_percpu_buffer as a percpu pointer
+    - ieee802154: atusb: fix uninit value in atusb_set_extended_addr
+    - iavf: Fix limit of total number of queues to active queues of VF
+    - RDMA/core: Don't infoleak GRH fields
+    - RDMA/uverbs: Check for null return of kmalloc_array
+    - mac80211: initialize variable have_higher_than_11mbit
+    - i40e: fix use-after-free in i40e_sync_filters_subtask()
+    - i40e: Fix for displaying message regarding NVM version
+    - i40e: Fix incorrect netdev's real number of RX/TX queues
+    - ipv4: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv4: Check attribute length for RTA_FLOW in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY when deleting multipath route
+    - lwtunnel: Validate RTA_ENCAP_TYPE attribute length
+    - batman-adv: mcast: don't send link-local multicast to mcast routers
+    - sch_qfq: prevent shift-out-of-bounds in qfq_init_qdisc
+    - net: phy: micrel: set soft_reset callback to genphy_soft_reset for KSZ8081
+    - power: supply: core: Break capacity loop
+    - power: reset: ltc2952: Fix use of floating point literals
+    - rndis_host: support Hytera digital radios
+    - phonet: refcount leak in pep_sock_accep
+    - ipv6: Continue processing multipath route even if gateway attribute is
+      invalid
+    - ipv6: Do cleanup if attribute validation fails in multipath route
+    - usb: mtu3: fix interval value for intr and isoc
+    - scsi: libiscsi: Fix UAF in iscsi_conn_get_param()/iscsi_conn_teardown()
+    - ip6_vti: initialize __ip6_tnl_parm struct in vti6_siocdevprivate
+    - net: udp: fix alignment problem in udp4_seq_show()
+    - atlantic: Fix buff_ring OOB in aq_ring_rx_clean
+    - mISDN: change function names to avoid conflicts
+    - Linux 5.4.171
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898)
+    - tee: handle lookup of shm with reference count 0
+    - Input: i8042 - add deferred probe support
+    - Input: i8042 - enable deferred probe quirk for ASUS UM325UA
+    - tomoyo: Check exceeded quota early in tomoyo_domain_quota_is_ok().
+    - platform/x86: apple-gmux: use resource_size() with res
+    - memblock: fix memblock_phys_alloc() section mismatch error
+    - recordmcount.pl: fix typo in s390 mcount regex
+    - selinux: initialize proto variable in selinux_ip_postroute_compat()
+    - scsi: lpfc: Terminate string in lpfc_debugfs_nvmeio_trc_write()
+    - net/mlx5: DR, Fix NULL vs IS_ERR checking in dr_domain_init_resources
+    - sctp: use call_rcu to free endpoint
+    - net: usb: pegasus: Do not drop long Ethernet frames
+    - net: lantiq_xrx200: fix statistics of received bytes
+    - NFC: st21nfca: Fix memory leak in device probe and remove
+    - ionic: Initialize the 'lif->dbid_inuse' bitmap
+    - net/mlx5e: Fix wrong features assignment in case of error
+    - selftests/net: udpgso_bench_tx: fix dst ip argument
+    - net/ncsi: check for error return from call to nla_put_u32
+    - fsl/fman: Fix missing put_device() call in fman_port_probe
+    - i2c: validate user data in compat ioctl
+    - nfc: uapi: use kernel size_t to fix user-space builds
+    - uapi: fix linux/nfc.h userspace compilation errors
+    - xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.
+    - usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
+    - usb: mtu3: add memory barrier before set GPD's HWO
+    - usb: mtu3: fix list_head check warning
+    - usb: mtu3: set interval of FS intr and isoc endpoint
+    - binder: fix async_free_space accounting for empty parcels
+    - scsi: vmw_pvscsi: Set residual data length conditionally
+    - Input: appletouch - initialize work before device registration
+    - Input: spaceball - fix parsing of movement data packets
+    - net: fix use-after-free in tw_timer_handler
+    - perf script: Fix CPU filtering of a script's switch events
+    - Linux 5.4.170
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898) // HID_ASUS
+    should depend on USB_HID in stable v4.15 backports (LP: #1959762)
+    - HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option
+  * Focal update: v5.4.169 upstream stable release (LP: #1958557)
+    - net: usb: lan78xx: add Allied Telesis AT29M2-AF
+    - serial: 8250_fintek: Fix garbled text for console
+    - arm64: dts: allwinner: orangepi-zero-plus: fix PHY mode
+    - spi: change clk_disable_unprepare to clk_unprepare
+    - IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
+    - netfilter: fix regression in looped (broad|multi)cast's MAC handling
+    - qlcnic: potential dereference null pointer of rx_queue->page_ring
+    - net: accept UFOv6 packages in virtio_net_hdr_to_skb
+    - net: skip virtio_net_hdr_set_proto if protocol already set
+    - ipmi: Fix UAF when uninstall ipmi_si and ipmi_msghandler module
+    - bonding: fix ad_actor_system option setting to default
+    - fjes: Check for error irq
+    - drivers: net: smc911x: Check for error irq
+    - sfc: falcon: Check null pointer of rx_queue->page_ring
+    - Input: elantech - fix stack out of bound access in
+      elantech_change_report_id()
+    - hwmon: (lm90) Fix usage of CONFIG2 register in detect function
+    - hwmon: (lm90) Add max6654 support to lm90 driver
+    - hwmon: (lm90) Add basic support for TI TMP461
+    - hwmon: (lm90) Introduce flag indicating extended temperature support
+    - hwmon: (lm90) Drop critical attribute support for MAX6654
+    - ALSA: jack: Check the return value of kstrdup()
+    - ALSA: drivers: opl3: Fix incorrect use of vp->state
+    - ALSA: hda/realtek: Amp init fixup for HP ZBook 15 G6
+    - Input: atmel_mxt_ts - fix double free in mxt_read_info_block
+    - ipmi: bail out if init_srcu_struct fails
+    - ipmi: ssif: initialize ssif_info->client early
+    - ipmi: fix initialization when workqueue allocation fails
+    - parisc: Correct completer in lws start
+    - x86/pkey: Fix undefined behaviour with PKRU_WD_BIT
+    - pinctrl: stm32: consider the GPIO offset to expose all the GPIO lines
+    - mmc: sdhci-tegra: Fix switch to HS400ES mode
+    - mmc: core: Disable card detect during shutdown
+    - ARM: 9169/1: entry: fix Thumb2 bug in iWMMXt exception handling
+    - tee: optee: Fix incorrect page free bug
+    - f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr()
+    - usb: gadget: u_ether: fix race in setting MAC address in setup phase
+    - KVM: VMX: Fix stale docs for kvm-intel.emulate_invalid_guest_state
+    - mm: mempolicy: fix THP allocations escaping mempolicy restrictions
+    - pinctrl: mediatek: fix global-out-of-bounds issue
+    - hwmom: (lm90) Fix citical alarm status for MAX6680/MAX6681
+    - hwmon: (lm90) Do not report 'busy' status bit as alarm
+    - ax25: NPD bug when detaching AX25 device
+    - hamradio: defer ax25 kfree after unregister_netdev
+    - hamradio: improve the incomplete fix to avoid NPD
+    - phonet/pep: refuse to enable an unbound pipe
+    - Linux 5.4.169
+  * Focal update: v5.4.168 upstream stable release (LP: #1957991)
+    - KVM: selftests: Make sure kvm_create_max_vcpus test won't hit RLIMIT_NOFILE
+    - mac80211: mark TX-during-stop for TX in in_reconfig
+    - mac80211: send ADDBA requests using the tid/queue of the aggregation session
+    - firmware: arm_scpi: Fix string overflow in SCPI genpd driver
+    - virtio_ring: Fix querying of maximum DMA mapping size for virtio device
+    - recordmcount.pl: look for jgnop instruction as well as bcrl on s390
+    - dm btree remove: fix use after free in rebalance_children()
+    - audit: improve robustness of the audit queue handling
+    - iio: adc: stm32: fix a current leak by resetting pcsel before disabling vdda
+    - nfsd: fix use-after-free due to delegation race
+    - arm64: dts: rockchip: remove mmc-hs400-enhanced-strobe from rk3399-khadas-
+      edge
+    - arm64: dts: rockchip: fix rk3399-leez-p710 vcc3v3-lan supply
+    - arm64: dts: rockchip: fix audio-supply for Rock Pi 4
+    - mac80211: track only QoS data frames for admission control
+    - ARM: socfpga: dts: fix qspi node compatible
+    - clk: Don't parent clks until the parent is fully registered
+    - selftests: net: Correct ping6 expected rc from 2 to 1
+    - s390/kexec_file: fix error handling when applying relocations
+    - sch_cake: do not call cake_destroy() from cake_init()
+    - inet_diag: use jiffies_delta_to_msecs()
+    - inet_diag: fix kernel-infoleak for UDP sockets
+    - selftests: Fix raw socket bind tests with VRF
+    - selftests: Fix IPv6 address bind tests
+    - dmaengine: st_fdma: fix MODULE_ALIAS
+    - selftest/net/forwarding: declare NETIFS p9 p10
+    - mac80211: agg-tx: refactor sending addba
+    - mac80211: agg-tx: don't schedule_and_wake_txq() under sta->lock
+    - mac80211: accept aggregation sessions on 6 GHz
+    - mac80211: fix lookup when adding AddBA extension element
+    - net: sched: lock action when translating it to flow_action infra
+    - flow_offload: return EOPNOTSUPP for the unsupported mpls action type
+    - rds: memory leak in __rds_conn_create()
+    - soc/tegra: fuse: Fix bitwise vs. logical OR warning
+    - igb: Fix removal of unicast MAC filters of VFs
+    - igbvf: fix double free in `igbvf_probe`
+    - ixgbe: set X550 MDIO speed before talking to PHY
+    - netdevsim: Zero-initialize memory for new map's value in function
+      nsim_bpf_map_alloc
+    - net: Fix double 0x prefix print in SKB dump
+    - net/smc: Prevent smc_release() from long blocking
+    - net: systemport: Add global locking for descriptor lifecycle
+    - sit: do not call ipip6_dev_free() from sit_init_net()
+    - USB: NO_LPM quirk Lenovo USB-C to Ethernet Adapher(RTL8153-04)
+    - PCI/MSI: Clear PCI_MSIX_FLAGS_MASKALL on error
+    - PCI/MSI: Mask MSI-X vectors only on success
+    - usb: xhci: Extend support for runtime power management for AMD's Yellow
+      carp.
+    - USB: serial: cp210x: fix CP2105 GPIO registration
+    - USB: serial: option: add Telit FN990 compositions
+    - timekeeping: Really make sure wall_to_monotonic isn't positive
+    - libata: if T_LENGTH is zero, dma direction should be DMA_NONE
+    - drm/amdgpu: correct register access for RLC_JUMP_TABLE_RESTORE
+    - mac80211: validate extended element ID is present
+    - mwifiex: Remove unnecessary braces from HostCmd_SET_SEQ_NO_BSS_INFO
+    - Input: touchscreen - avoid bitwise vs logical OR warning
+    - ARM: dts: imx6ull-pinfunc: Fix CSI_DATA07__ESAI_TX0 pad name
+    - xsk: Do not sleep in poll() when need_wakeup set
+    - media: mxl111sf: change mutex_init() location
+    - fuse: annotate lock in fuse_reverse_inval_entry()
+    - ovl: fix warning in ovl_create_real()
+    - scsi: scsi_debug: Sanity check block descriptor length in resp_mode_select()
+    - rcu: Mark accesses to rcu_state.n_force_qs
+    - mac80211: fix regression in SSN handling of addba tx
+    - net: sched: Fix suspicious RCU usage while accessing tcf_tunnel_info
+    - Revert "xsk: Do not sleep in poll() when need_wakeup set"
+    - xen/blkfront: harden blkfront against event channel storms
+    - xen/netfront: harden netfront against event channel storms
+    - xen/console: harden hvc_xen against event channel storms
+    - xen/netback: fix rx queue stall detection
+    - xen/netback: don't queue unlimited number of packages
+    - Linux 5.4.168
+  * Focal update: v5.4.167 upstream stable release (LP: #1957987)
+    - nfc: fix segfault in nfc_genl_dump_devices_done
+    - drm/msm/dsi: set default num_data_lanes
+    - net/mlx4_en: Update reported link modes for 1/10G
+    - parisc/agp: Annotate parisc agp init functions with __init
+    - i2c: rk3x: Handle a spurious start completion interrupt flag
+    - net: netlink: af_netlink: Prevent empty skb by adding a check on len.
+    - drm/amd/display: Fix for the no Audio bug with Tiled Displays
+    - drm/amd/display: add connector type check for CRC source set
+    - tracing: Fix a kmemleak false positive in tracing_map
+    - KVM: x86: Ignore sparse banks size for an "all CPUs", non-sparse IPI req
+    - selinux: fix race condition when computing ocontext SIDs
+    - bpf: Fix integer overflow in argument calculation for bpf_map_area_alloc
+    - hwmon: (dell-smm) Fix warning on /proc/i8k creation error
+    - memblock: free_unused_memmap: use pageblock units instead of MAX_ORDER
+    - memblock: align freed memory map on pageblock boundaries with SPARSEMEM
+    - memblock: ensure there is no overflow in memblock_overlaps_region()
+    - arm: extend pfn_valid to take into account freed memory map alignment
+    - arm: ioremap: don't abuse pfn_valid() to check if pfn is in RAM
+    - Linux 5.4.167
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-104.118 ]
+
+  * CVE-2022-23960
+    - SAUCE: kvm: arm: fix build on 32-bit
+
+  [ Ubuntu: 5.4.0-103.117 ]
+
+  * CVE-2022-23960
+    - arm64: Add part number for Arm Cortex-A77
+    - arm64: Add Neoverse-N2, Cortex-A710 CPU part definition
+    - arm64: Add Cortex-X2 CPU part definition
+    - arm64: add ID_AA64ISAR2_EL1 sys register
+    - SAUCE: arm64: entry.S: Add ventry overflow sanity checks
+    - SAUCE: arm64: entry: Make the trampoline cleanup optional
+    - SAUCE: arm64: entry: Free up another register on kpti's tramp_exit path
+    - SAUCE: arm64: entry: Move the trampoline data page before the text page
+    - SAUCE: arm64: entry: Allow tramp_alias to access symbols after the 4K
+      boundary
+    - SAUCE: arm64: entry: Don't assume tramp_vectors is the start of the vectors
+    - SAUCE: arm64: entry: Move trampoline macros out of ifdef'd section
+    - SAUCE: arm64: entry: Make the kpti trampoline's kpti sequence optional
+    - SAUCE: arm64: entry: Allow the trampoline text to occupy multiple pages
+    - SAUCE: arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations
+    - SAUCE: arm64: entry: Add vectors that have the bhb mitigation sequences
+    - SAUCE: arm64: entry: Add macro for reading symbol addresses from the
+      trampoline
+    - SAUCE: arm64: Add percpu vectors for EL1
+    - SAUCE: arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of
+      Spectre-v2
+    - SAUCE: KVM: arm64: Add templates for BHB mitigation sequences
+    - SAUCE: arm64: Mitigate spectre style branch history side channels
+    - SAUCE: KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and
+      migrated
+    - SAUCE: arm64: Use the clearbhb instruction in mitigations
+    - [Config]: set CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+  * CVE-2022-25636
+    - netfilter: nf_tables_offload: incorrect flow offload action array size
+  * CVE-2022-0001
+    - 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
+
+  [ Ubuntu: 5.4.0-100.113 ]
+
+  * focal/linux: 5.4.0-100.113 -proposed tracker (LP: #1959900)
+  * CVE-2022-22942
+    - SAUCE: drm/vmwgfx: Fix stale file descriptors on failed usercopy
+  * CVE-2022-0330
+    - drm/i915: Flush TLBs before releasing backing store
+  * Focal update: v5.4.166 upstream stable release (LP: #1957008)
+    - netfilter: selftest: conntrack_vrf.sh: fix file permission
+    - Linux 5.4.166
+    - net/packet: rx_owner_map depends on pg_vec
+    - USB: gadget: bRequestType is a bitfield, not a enum
+    - HID: holtek: fix mouse probing
+    - udp: using datalen to cap ipv6 udp max gso segments
+    - selftests: Calculate udpgso segment count without header adjustment
+  * Focal update: v5.4.165 upstream stable release (LP: #1957007)
+    - serial: tegra: Change lower tolerance baud rate limit for tegra20 and
+      tegra30
+    - ntfs: fix ntfs_test_inode and ntfs_init_locked_inode function type
+    - HID: quirks: Add quirk for the Microsoft Surface 3 type-cover
+    - HID: google: add eel USB id
+    - HID: add hid_is_usb() function to make it simpler for USB detection
+    - HID: add USB_HID dependancy to hid-prodikeys
+    - HID: add USB_HID dependancy to hid-chicony
+    - HID: add USB_HID dependancy on some USB HID drivers
+    - HID: bigbenff: prevent null pointer dereference
+    - HID: wacom: fix problems when device is not a valid USB device
+    - HID: check for valid USB device for many HID drivers
+    - can: kvaser_usb: get CAN clock frequency from device
+    - can: kvaser_pciefd: kvaser_pciefd_rx_error_frame(): increase correct
+      stats->{rx,tx}_errors counter
+    - can: sja1000: fix use after free in ems_pcmcia_add_card()
+    - nfc: fix potential NULL pointer deref in nfc_genl_dump_ses_done
+    - selftests: netfilter: add a vrf+conntrack testcase
+    - vrf: don't run conntrack on vrf with !dflt qdisc
+    - bpf: Fix the off-by-two error in range markings
+    - ice: ignore dropped packets during init
+    - bonding: make tx_rebalance_counter an atomic
+    - nfp: Fix memory leak in nfp_cpp_area_cache_add()
+    - seg6: fix the iif in the IPv6 socket control block
+    - udp: using datalen to cap max gso segments
+    - iavf: restore MSI state on reset
+    - iavf: Fix reporting when setting descriptor count
+    - IB/hfi1: Correct guard on eager buffer deallocation
+    - mm: bdi: initialize bdi_min_ratio when bdi is unregistered
+    - ALSA: ctl: Fix copy of updated id with element read/write
+    - ALSA: hda/realtek - Add headset Mic support for Lenovo ALC897 platform
+    - ALSA: pcm: oss: Fix negative period/buffer sizes
+    - ALSA: pcm: oss: Limit the period size to 16MB
+    - ALSA: pcm: oss: Handle missing errors in snd_pcm_oss_change_params*()
+    - btrfs: clear extent buffer uptodate when we fail to write it
+    - btrfs: replace the BUG_ON in btrfs_del_root_ref with proper error handling
+    - nfsd: Fix nsfd startup race (again)
+    - tracefs: Have new files inherit the ownership of their parent
+    - clk: qcom: regmap-mux: fix parent clock lookup
+    - drm/syncobj: Deal with signalled fences in drm_syncobj_find_fence.
+    - can: pch_can: pch_can_rx_normal: fix use after free
+    - can: m_can: Disable and ignore ELO interrupt
+    - x86/sme: Explicitly map new EFI memmap table as encrypted
+    - libata: add horkage for ASMedia 1092
+    - wait: add wake_up_pollfree()
+    - SAUCE: binder: export __wake_up_pollfree for binder module
+    - binder: use wake_up_pollfree()
+    - signalfd: use wake_up_pollfree()
+    - aio: keep poll requests on waitqueue until completed
+    - aio: fix use-after-free due to missing POLLFREE handling
+    - tracefs: Set all files to the same group ownership as the mount option
+    - block: fix ioprio_get(IOPRIO_WHO_PGRP) vs setuid(2)
+    - qede: validate non LSO skb length
+    - ASoC: qdsp6: q6routing: Fix return value from msm_routing_put_audio_mixer
+    - i40e: Fix failed opcode appearing if handling messages from VF
+    - i40e: Fix pre-set max number of queues for VF
+    - mtd: rawnand: fsmc: Take instruction delay into account
+    - mtd: rawnand: fsmc: Fix timing computation
+    - dt-bindings: net: Reintroduce PHY no lane swap binding
+    - tools build: Remove needless libpython-version feature check that breaks
+      test-all fast path
+    - net: cdc_ncm: Allow for dwNtbOutMaxSize to be unset or zero
+    - net: altera: set a couple error code in probe()
+    - net: fec: only clear interrupt of handling queue in fec_enet_rx_queue()
+    - net, neigh: clear whole pneigh_entry at alloc time
+    - net/qla3xxx: fix an error code in ql_adapter_up()
+    - Revert "UBUNTU: SAUCE: selftests: fib_tests: assign address to dummy1 for
+      rp_filter tests"
+    - selftests/fib_tests: Rework fib_rp_filter_test()
+    - USB: gadget: detect too-big endpoint 0 requests
+    - USB: gadget: zero allocate endpoint 0 buffers
+    - usb: core: config: fix validation of wMaxPacketValue entries
+    - xhci: Remove CONFIG_USB_DEFAULT_PERSIST to prevent xHCI from runtime
+      suspending
+    - usb: core: config: using bit mask instead of individual bits
+    - xhci: avoid race between disable slot command and host runtime suspend
+    - iio: trigger: Fix reference counting
+    - iio: trigger: stm32-timer: fix MODULE_ALIAS
+    - iio: stk3310: Don't return error code in interrupt handler
+    - iio: mma8452: Fix trigger reference couting
+    - iio: ltr501: Don't return error code in trigger handler
+    - iio: kxsd9: Don't return error code in trigger handler
+    - iio: itg3200: Call iio_trigger_notify_done() on error
+    - iio: dln2-adc: Fix lockdep complaint
+    - iio: dln2: Check return value of devm_iio_trigger_register()
+    - iio: at91-sama5d2: Fix incorrect sign extension
+    - iio: adc: axp20x_adc: fix charging current reporting on AXP22x
+    - iio: ad7768-1: Call iio_trigger_notify_done() on error
+    - iio: accel: kxcjk-1013: Fix possible memory leak in probe and remove
+    - irqchip/armada-370-xp: Fix return value of armada_370_xp_msi_alloc()
+    - irqchip/armada-370-xp: Fix support for Multi-MSI interrupts
+    - irqchip/irq-gic-v3-its.c: Force synchronisation when issuing INVALL
+    - irqchip: nvic: Fix offset for Interrupt Priority Offsets
+    - misc: fastrpc: fix improper packet size calculation
+    - bpf: Add selftests to cover packet access corner cases
+    - Linux 5.4.165
+  * Focal update: v5.4.164 upstream stable release (LP: #1956381)
+    - NFSv42: Fix pagecache invalidation after COPY/CLONE
+    - of: clk: Make <linux/of_clk.h> self-contained
+    - arm64: dts: mcbin: support 2W SFP modules
+    - can: j1939: j1939_tp_cmd_recv(): check the dst address of TP.CM_BAM
+    - gfs2: Fix length of holes reported at end-of-file
+    - drm/sun4i: fix unmet dependency on RESET_CONTROLLER for PHY_SUN6I_MIPI_DPHY
+    - mac80211: do not access the IV when it was stripped
+    - net/smc: Transfer remaining wait queue entries during fallback
+    - atlantic: Fix OOB read and write in hw_atl_utils_fw_rpc_wait
+    - net: return correct error code
+    - platform/x86: thinkpad_acpi: Fix WWAN device disabled issue after S3 deep
+    - s390/setup: avoid using memblock_enforce_memory_limit
+    - btrfs: check-integrity: fix a warning on write caching disabled disk
+    - thermal: core: Reset previous low and high trip during thermal zone init
+    - scsi: iscsi: Unblock session then wake up error handler
+    - ata: ahci: Add Green Sardine vendor ID as board_ahci_mobile
+    - ethernet: hisilicon: hns: hns_dsaf_misc: fix a possible array overflow in
+      hns_dsaf_ge_srst_by_port()
+    - net: tulip: de4x5: fix the problem that the array 'lp->phy[8]' may be out of
+      bound
+    - net: ethernet: dec: tulip: de4x5: fix possible array overflows in
+      type3_infoblock()
+    - perf hist: Fix memory leak of a perf_hpp_fmt
+    - perf report: Fix memory leaks around perf_tip()
+    - net/smc: Avoid warning of possible recursive locking
+    - vrf: Reset IPCB/IP6CB when processing outbound pkts in vrf dev xmit
+    - kprobes: Limit max data_size of the kretprobe instances
+    - rt2x00: do not mark device gone on EPROTO errors during start
+    - cpufreq: Fix get_cpu_device() failure in add_cpu_dev_symlink()
+    - s390/pci: move pseudo-MMIO to prevent MIO overlap
+    - sata_fsl: fix UAF in sata_fsl_port_stop when rmmod sata_fsl
+    - sata_fsl: fix warning in remove_proc_entry when rmmod sata_fsl
+    - i2c: stm32f7: flush TX FIFO upon transfer errors
+    - i2c: stm32f7: recover the bus on access timeout
+    - i2c: stm32f7: stop dma transfer in case of NACK
+    - i2c: cbus-gpio: set atomic transfer callback
+    - natsemi: xtensa: fix section mismatch warnings
+    - net: qlogic: qlcnic: Fix a NULL pointer dereference in
+      qlcnic_83xx_add_rings()
+    - net: mpls: Fix notifications when deleting a device
+    - siphash: use _unaligned version by default
+    - net/mlx4_en: Fix an use-after-free bug in mlx4_en_try_alloc_resources()
+    - selftests: net: Correct case name
+    - rxrpc: Fix rxrpc_local leak in rxrpc_lookup_peer()
+    - net: usb: lan78xx: lan78xx_phy_init(): use PHY_POLL instead of "0" if no IRQ
+      is available
+    - net: marvell: mvpp2: Fix the computation of shared CPUs
+    - net: annotate data-races on txq->xmit_lock_owner
+    - ipv4: convert fib_num_tclassid_users to atomic_t
+    - net/rds: correct socket tunable error in rds_tcp_tune()
+    - net/smc: Keep smc_close_final rc during active close
+    - drm/msm: Do hw_init() before capturing GPU state
+    - ipv6: fix memory leak in fib6_rule_suppress
+    - KVM: x86/pmu: Fix reserved bits for AMD PerfEvtSeln register
+    - sched/uclamp: Fix rq->uclamp_max not set on first enqueue
+    - parisc: Fix KBUILD_IMAGE for self-extracting kernel
+    - parisc: Fix "make install" on newer debian releases
+    - vgacon: Propagate console boot parameters before calling `vc_resize'
+    - xhci: Fix commad ring abort, write all 64 bits to CRCR register.
+    - USB: NO_LPM quirk Lenovo Powered USB-C Travel Hub
+    - usb: typec: tcpm: Wait in SNK_DEBOUNCED until disconnect
+    - x86/tsc: Add a timer to make sure TSC_adjust is always checked
+    - x86/tsc: Disable clocksource watchdog for TSC on qualified platorms
+    - x86/64/mm: Map all kernel memory into trampoline_pgd
+    - tty: serial: msm_serial: Deactivate RX DMA for polling support
+    - serial: pl011: Add ACPI SBSA UART match id
+    - serial: core: fix transmit-buffer reset and memleak
+    - serial: 8250_pci: Fix ACCES entries in pci_serial_quirks array
+    - serial: 8250_pci: rewrite pericom_do_set_divisor()
+    - iwlwifi: mvm: retry init flow if failed
+    - parisc: Mark cr16 CPU clocksource unstable on all SMP machines
+    - net/tls: Fix authentication failure in CCM mode
+    - Linux 5.4.164
+  * Focal update: v5.4.163 upstream stable release (LP: #1956380)
+    - USB: serial: option: add Telit LE910S1 0x9200 composition
+    - USB: serial: option: add Fibocom FM101-GL variants
+    - usb: dwc2: gadget: Fix ISOC flow for elapsed frames
+    - usb: dwc2: hcd_queue: Fix use of floating point literal
+    - net: nexthop: fix null pointer dereference when IPv6 is not enabled
+    - usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts
+    - usb: hub: Fix usb enumeration issue due to address0 race
+    - usb: hub: Fix locking issues with address0_mutex
+    - binder: fix test regression due to sender_euid change
+    - ALSA: ctxfi: Fix out-of-range access
+    - media: cec: copy sequence field for the reply
+    - HID: wacom: Use "Confidence" flag to prevent reporting invalid contacts
+    - staging/fbtft: Fix backlight
+    - staging: rtl8192e: Fix use after free in _rtl92e_pci_disconnect()
+    - xen: don't continue xenstore initialization in case of errors
+    - xen: detect uninitialized xenbus in xenbus_init
+    - KVM: PPC: Book3S HV: Prevent POWER7/8 TLB flush flushing SLB
+    - tracing/uprobe: Fix uprobe_perf_open probes iteration
+    - tracing: Fix pid filtering when triggers are attached
+    - mmc: sdhci: Fix ADMA for PAGE_SIZE >= 64KiB
+    - mdio: aspeed: Fix "Link is Down" issue
+    - PCI: aardvark: Deduplicate code in advk_pcie_rd_conf()
+    - PCI: aardvark: Wait for endpoint to be ready before training link
+    - PCI: aardvark: Fix big endian support
+    - PCI: aardvark: Train link immediately after enabling training
+    - PCI: aardvark: Improve link training
+    - PCI: aardvark: Issue PERST via GPIO
+    - PCI: aardvark: Replace custom macros by standard linux/pci_regs.h macros
+    - PCI: aardvark: Don't touch PCIe registers if no card connected
+    - PCI: aardvark: Fix compilation on s390
+    - PCI: aardvark: Move PCIe reset card code to advk_pcie_train_link()
+    - PCI: aardvark: Update comment about disabling link training
+    - PCI: pci-bridge-emul: Fix array overruns, improve safety
+    - PCI: aardvark: Configure PCIe resources from 'ranges' DT property
+    - PCI: aardvark: Fix PCIe Max Payload Size setting
+    - PCI: aardvark: Implement re-issuing config requests on CRS response
+    - PCI: aardvark: Simplify initialization of rootcap on virtual bridge
+    - PCI: aardvark: Fix link training
+    - PCI: aardvark: Fix support for bus mastering and PCI_COMMAND on emulated
+      bridge
+    - PCI: aardvark: Set PCI Bridge Class Code to PCI Bridge
+    - PCI: aardvark: Fix support for PCI_BRIDGE_CTL_BUS_RESET on emulated bridge
+    - pinctrl: armada-37xx: Correct PWM pins definitions
+    - arm64: dts: marvell: armada-37xx: Set pcie_reset_pin to gpio function
+    - proc/vmcore: fix clearing user buffer by properly using clear_user()
+    - netfilter: ipvs: Fix reuse connection if RS weight is 0
+    - ARM: dts: BCM5301X: Fix I2C controller interrupt
+    - ARM: dts: BCM5301X: Add interrupt properties to GPIO node
+    - ASoC: qdsp6: q6routing: Conditionally reset FrontEnd Mixer
+    - ASoC: topology: Add missing rwsem around snd_ctl_remove() calls
+    - net: ieee802154: handle iftypes as u32
+    - firmware: arm_scmi: pm: Propagate return value to caller
+    - NFSv42: Don't fail clone() unless the OP_CLONE operation failed
+    - ARM: socfpga: Fix crash with CONFIG_FORTIRY_SOURCE
+    - scsi: mpt3sas: Fix kernel panic during drive powercycle test
+    - drm/vc4: fix error code in vc4_create_object()
+    - iavf: Prevent changing static ITR values if adaptive moderation is on
+    - ipv6: fix typos in __ip6_finish_output()
+    - nfp: checking parameter process for rx-usecs/tx-usecs is invalid
+    - net: ipv6: add fib6_nh_release_dsts stub
+    - net: nexthop: release IPv6 per-cpu dsts when replacing a nexthop group
+    - scsi: core: sysfs: Fix setting device state to SDEV_RUNNING
+    - net/smc: Ensure the active closing peer first closes clcsock
+    - nvmet-tcp: fix incomplete data digest send
+    - net/ncsi : Add payload to be 32-bit aligned to fix dropped packets
+    - PM: hibernate: use correct mode for swsusp_close()
+    - tcp_cubic: fix spurious Hystart ACK train detections for not-cwnd-limited
+      flows
+    - nvmet: use IOCB_NOWAIT only if the filesystem supports it
+    - igb: fix netpoll exit with traffic
+    - MIPS: use 3-level pgtable for 64KB page size on MIPS_VA_BITS_48
+    - net: vlan: fix underflow for the real_dev refcnt
+    - net/smc: Don't call clcsock shutdown twice when smc shutdown
+    - net: hns3: fix VF RSS failed problem after PF enable multi-TCs
+    - net: mscc: ocelot: don't downgrade timestamping RX filters in SIOCSHWTSTAMP
+    - net: mscc: ocelot: correctly report the timestamping RX filters in ethtool
+    - f2fs: set SBI_NEED_FSCK flag when inconsistent node block found
+    - smb3: do not error on fsync when readonly
+    - vhost/vsock: fix incorrect used length reported to the guest
+    - tracing: Check pid filtering when creating events
+    - s390/mm: validate VMA in PGSTE manipulation functions
+    - shm: extend forced shm destroy to support objects from several IPC nses
+    - NFC: add NCI_UNREG flag to eliminate the race
+    - fuse: release pipe buf after last use
+    - xen: sync include/xen/interface/io/ring.h with Xen's newest version
+    - xen/blkfront: read response from backend only once
+    - xen/blkfront: don't take local copy of a request from the ring page
+    - xen/blkfront: don't trust the backend response data blindly
+    - xen/netfront: read response from backend only once
+    - xen/netfront: don't read data from request on the ring page
+    - xen/netfront: disentangle tx_skb_freelist
+    - xen/netfront: don't trust the backend response data blindly
+    - tty: hvc: replace BUG_ON() with negative return value
+    - Linux 5.4.163
+  * net/mlx5e: EPERM on vlan 0 programming (LP: #1957753)
+    - net/mlx5e: Unblock setting vid 0 for VF in case PF isn't eswitch manager
+  * CVE-2021-4083
+    - fget: check that the fd still exists after getting a ref to it
+  * CVE-2021-4155
+    - xfs: map unwritten blocks in XFS_IOC_{ALLOC, FREE}SP just like fallocate
+
+  [ Ubuntu: 5.4.0-99.112 ]
+
+  * focal/linux: 5.4.0-99.112 -proposed tracker (LP: #1959817)
+  * linux-image-5.4.0-97.110 freezes by accessing cifs shares (LP: #1959665)
+    - Revert "cifs: To match file servers, make sure the server hostname matches"
+    - Revert "cifs: set a minimum of 120s for next dns resolution"
+    - Revert "cifs: use the expiry output of dns_query to schedule next
+      resolution"
+
+  [ Ubuntu: 5.4.0-97.110 ]
+
+  * icmp_redirect from selftests fails on F/kvm (unary operator expected)
+    (LP: #1938964)
+    - selftests: icmp_redirect: pass xfail=0 to log_test()
+  * Focal: CIFS stable updates (LP: #1954926)
+    - cifs: use the expiry output of dns_query to schedule next resolution
+    - cifs: set a minimum of 120s for next dns resolution
+    - cifs: To match file servers, make sure the server hostname matches
+  * seccomp_bpf in seccomp from ubuntu_kernel_selftests failed to build on B-5.4
+    (LP: #1896420)
+    - SAUCE: selftests/seccomp: fix "storage size of 'md' isn't known" build issue
+    - SAUCE: selftests/seccomp: Fix s390x regs not defined issue
+  * system crash when removing ipmi_msghandler module (LP: #1950666)
+    - ipmi: Move remove_work to dedicated workqueue
+    - ipmi: msghandler: Make symbol 'remove_work_wq' static
+  * zcrypt DD: Toleration for new IBM Z Crypto Hardware - (Backport to Ubuntu
+    20.04) (LP: #1954680)
+    - s390/AP: support new dynamic AP bus size limit
+  * [UBUNTU 20.04] KVM hardware diagnose data improvements for guest kernel -
+    kernel part (LP: #1953334)
+    - s390/setup: diag 318: refactor struct
+    - s390/kvm: diagnose 0x318 sync and reset
+    - KVM: s390: remove diag318 reset code
+    - KVM: s390: add debug statement for diag 318 CPNC data
+  * Updates to ib_peer_memory requested by Nvidia (LP: #1947206)
+    - SAUCE: RDMA/core: Updated ib_peer_memory
+  * Include Infiniband Peer Memory interface (LP: #1923104)
+    - IB: Allow calls to ib_umem_get from kernel ULPs
+    - SAUCE: RDMA/core: Introduce peer memory interface
+  * Focal update: v5.4.162 upstream stable release (LP: #1954834)
+    - arm64: zynqmp: Do not duplicate flash partition label property
+    - arm64: zynqmp: Fix serial compatible string
+    - ARM: dts: NSP: Fix mpcore, mmc node names
+    - scsi: lpfc: Fix list_add() corruption in lpfc_drain_txq()
+    - arm64: dts: hisilicon: fix arm,sp805 compatible string
+    - RDMA/bnxt_re: Check if the vlan is valid before reporting
+    - usb: musb: tusb6010: check return value after calling
+      platform_get_resource()
+    - usb: typec: tipd: Remove WARN_ON in tps6598x_block_read
+    - arm64: dts: qcom: msm8998: Fix CPU/L2 idle state latency and residency
+    - arm64: dts: freescale: fix arm,sp805 compatible string
+    - ASoC: SOF: Intel: hda-dai: fix potential locking issue
+    - clk: imx: imx6ul: Move csi_sel mux to correct base register
+    - ASoC: nau8824: Add DMI quirk mechanism for active-high jack-detect
+    - scsi: advansys: Fix kernel pointer leak
+    - firmware_loader: fix pre-allocated buf built-in firmware use
+    - ARM: dts: omap: fix gpmc,mux-add-data type
+    - usb: host: ohci-tmio: check return value after calling
+      platform_get_resource()
+    - ARM: dts: ls1021a: move thermal-zones node out of soc/
+    - ARM: dts: ls1021a-tsn: use generic "jedec,spi-nor" compatible for flash
+    - ALSA: ISA: not for M68K
+    - tty: tty_buffer: Fix the softlockup issue in flush_to_ldisc
+    - MIPS: sni: Fix the build
+    - scsi: target: Fix ordered tag handling
+    - scsi: target: Fix alua_tg_pt_gps_count tracking
+    - iio: imu: st_lsm6dsx: Avoid potential array overflow in st_lsm6dsx_set_odr()
+    - powerpc/5200: dts: fix memory node unit name
+    - ALSA: gus: fix null pointer dereference on pointer block
+    - powerpc/dcr: Use cmplwi instead of 3-argument cmpli
+    - sh: check return code of request_irq
+    - maple: fix wrong return value of maple_bus_init().
+    - f2fs: fix up f2fs_lookup tracepoints
+    - sh: fix kconfig unmet dependency warning for FRAME_POINTER
+    - sh: math-emu: drop unused functions
+    - sh: define __BIG_ENDIAN for math-emu
+    - clk: ingenic: Fix bugs with divided dividers
+    - clk/ast2600: Fix soc revision for AHB
+    - clk: qcom: gcc-msm8996: Drop (again) gcc_aggre1_pnoc_ahb_clk
+    - mips: BCM63XX: ensure that CPU_SUPPORTS_32BIT_KERNEL is set
+    - sched/core: Mitigate race cpus_share_cache()/update_top_cache_domain()
+    - tracing: Save normal string variables
+    - tracing/histogram: Do not copy the fixed-size char array field over the
+      field size
+    - RDMA/netlink: Add __maybe_unused to static inline in C file
+    - perf bpf: Avoid memory leak from perf_env__insert_btf()
+    - perf bench futex: Fix memory leak of perf_cpu_map__new()
+    - perf tests: Remove bash construct from record+zstd_comp_decomp.sh
+    - net: bnx2x: fix variable dereferenced before check
+    - iavf: check for null in iavf_fix_features
+    - iavf: free q_vectors before queues in iavf_disable_vf
+    - iavf: Fix failure to exit out from last all-multicast mode
+    - iavf: prevent accidental free of filter structure
+    - iavf: validate pointers
+    - iavf: Fix for the false positive ASQ/ARQ errors while issuing VF reset
+    - MIPS: generic/yamon-dt: fix uninitialized variable error
+    - mips: bcm63xx: add support for clk_get_parent()
+    - mips: lantiq: add support for clk_get_parent()
+    - platform/x86: hp_accel: Fix an error handling path in 'lis3lv02d_probe()'
+    - scsi: core: sysfs: Fix hang when device state is set via sysfs
+    - net: sched: act_mirred: drop dst for the direction from egress to ingress
+    - net: dpaa2-eth: fix use-after-free in dpaa2_eth_remove
+    - net: virtio_net_hdr_to_skb: count transport header in UFO
+    - i40e: Fix correct max_pkt_size on VF RX queue
+    - i40e: Fix NULL ptr dereference on VSI filter sync
+    - i40e: Fix changing previously set num_queue_pairs for PFs
+    - i40e: Fix ping is lost after configuring ADq on VF
+    - i40e: Fix creation of first queue by omitting it if is not power of two
+    - i40e: Fix display error code in dmesg
+    - NFC: reorganize the functions in nci_request
+    - drm/nouveau: hdmigv100.c: fix corrupted HDMI Vendor InfoFrame
+    - NFC: reorder the logic in nfc_{un,}register_device
+    - KVM: PPC: Book3S HV: Use GLOBAL_TOC for kvmppc_h_set_dabr/xdabr()
+    - perf/x86/intel/uncore: Fix filter_tid mask for CHA events on Skylake Server
+    - perf/x86/intel/uncore: Fix IIO event constraints for Skylake Server
+    - s390/kexec: fix return code handling
+    - arm64: vdso32: suppress error message for 'make mrproper'
+    - tun: fix bonding active backup with arp monitoring
+    - hexagon: export raw I/O routines for modules
+    - ipc: WARN if trying to remove ipc object which is absent
+    - mm: kmemleak: slob: respect SLAB_NOLEAKTRACE flag
+    - x86/hyperv: Fix NULL deref in set_hv_tscchange_cb() if Hyper-V setup fails
+    - s390/kexec: fix memory leak of ipl report buffer
+    - udf: Fix crash after seekdir
+    - btrfs: fix memory ordering between normal and ordered work functions
+    - parisc/sticon: fix reverse colors
+    - cfg80211: call cfg80211_stop_ap when switch from P2P_GO type
+    - drm/udl: fix control-message timeout
+    - drm/nouveau: use drm_dev_unplug() during device removal
+    - drm/i915/dp: Ensure sink rate values are always valid
+    - drm/amdgpu: fix set scaling mode Full/Full aspect/Center not works on vga
+      and dvi connectors
+    - Revert "net: mvpp2: disable force link UP during port init procedure"
+    - perf/core: Avoid put_page() when GUP fails
+    - batman-adv: Consider fragmentation for needed_headroom
+    - batman-adv: Reserve needed_*room for fragments
+    - batman-adv: Don't always reallocate the fragmentation skb head
+    - ASoC: DAPM: Cover regression by kctl change notification fix
+    - usb: max-3421: Use driver data instead of maintaining a list of bound
+      devices
+    - ice: Delete always true check of PF pointer
+    - ALSA: hda: hdac_ext_stream: fix potential locking issues
+    - ALSA: hda: hdac_stream: fix potential locking issue in
+      snd_hdac_stream_assign()
+    - Linux 5.4.162
+  * Focal update: v5.4.161 upstream stable release (LP: #1954828)
+    - scsi: ufs: Fix interrupt error message for shared interrupts
+    - MIPS: Fix assembly error from MIPSr2 code used within MIPS_ISA_ARCH_LEVEL
+    - ext4: fix lazy initialization next schedule time computation in more
+      granular unit
+    - scsi: ufs: Fix tm request when non-fatal error happens
+    - fortify: Explicitly disable Clang support
+    - parisc/entry: fix trace test in syscall exit path
+    - PCI/MSI: Destroy sysfs before freeing entries
+    - PCI/MSI: Deal with devices lying about their MSI mask capability
+    - PCI: Add MSI masking quirk for Nvidia ION AHCI
+    - erofs: remove the occupied parameter from z_erofs_pagevec_enqueue()
+    - erofs: fix unsafe pagevec reuse of hooked pclusters
+    - Linux 5.4.161
+  * Focal update: v5.4.160 upstream stable release (LP: #1953387)
+    - xhci: Fix USB 3.1 enumeration issues by increasing roothub power-on-good
+      delay
+    - usb: xhci: Enable runtime-pm by default on AMD Yellow Carp platform
+    - binder: use euid from cred instead of using task
+    - binder: use cred instead of task for selinux checks
+    - binder: use cred instead of task for getsecid
+    - Input: iforce - fix control-message timeout
+    - Input: elantench - fix misreporting trackpoint coordinates
+    - Input: i8042 - Add quirk for Fujitsu Lifebook T725
+    - libata: fix read log timeout value
+    - ocfs2: fix data corruption on truncate
+    - scsi: qla2xxx: Fix kernel crash when accessing port_speed sysfs file
+    - scsi: qla2xxx: Fix use after free in eh_abort path
+    - mmc: dw_mmc: Dont wait for DRTO on Write RSP error
+    - parisc: Fix ptrace check on syscall return
+    - tpm: Check for integer overflow in tpm2_map_response_body()
+    - firmware/psci: fix application of sizeof to pointer
+    - crypto: s5p-sss - Add error handling in s5p_aes_probe()
+    - media: ite-cir: IR receiver stop working after receive overflow
+    - media: ir-kbd-i2c: improve responsiveness of hauppauge zilog receivers
+    - media: v4l2-ioctl: Fix check_ext_ctrls
+    - ALSA: hda/realtek: Add quirk for Clevo PC70HS
+    - ALSA: hda/realtek: Add a quirk for Acer Spin SP513-54N
+    - ALSA: hda/realtek: Add quirk for ASUS UX550VE
+    - ALSA: hda/realtek: Add quirk for HP EliteBook 840 G7 mute LED
+    - ALSA: ua101: fix division by zero at probe
+    - ALSA: 6fire: fix control and bulk message timeouts
+    - ALSA: line6: fix control and interrupt message timeouts
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 400
+    - ALSA: synth: missing check for possible NULL after the call to kstrdup
+    - ALSA: timer: Fix use-after-free problem
+    - ALSA: timer: Unconditionally unlink slave instances, too
+    - fuse: fix page stealing
+    - x86/sme: Use #define USE_EARLY_PGTABLE_L5 in mem_encrypt_identity.c
+    - x86/cpu: Fix migration safety with X86_BUG_NULL_SEL
+    - x86/irq: Ensure PI wakeup handler is unregistered before module unload
+    - cavium: Return negative value when pci_alloc_irq_vectors() fails
+    - scsi: qla2xxx: Return -ENOMEM if kzalloc() fails
+    - scsi: qla2xxx: Fix unmap of already freed sgl
+    - cavium: Fix return values of the probe function
+    - sfc: Don't use netif_info before net_device setup
+    - hyperv/vmbus: include linux/bitops.h
+    - ARM: dts: sun7i: A20-olinuxino-lime2: Fix ethernet phy-mode
+    - reset: socfpga: add empty driver allowing consumers to probe
+    - mmc: winbond: don't build on M68K
+    - drm: panel-orientation-quirks: Add quirk for Aya Neo 2021
+    - bpf: Define bpf_jit_alloc_exec_limit for arm64 JIT
+    - bpf: Prevent increasing bpf_jit_limit above max
+    - xen/netfront: stop tx queues during live migration
+    - nvmet-tcp: fix a memory leak when releasing a queue
+    - spi: spl022: fix Microwire full duplex mode
+    - net: multicast: calculate csum of looped-back and forwarded packets
+    - watchdog: Fix OMAP watchdog early handling
+    - drm: panel-orientation-quirks: Add quirk for GPD Win3
+    - nvmet-tcp: fix header digest verification
+    - r8169: Add device 10ec:8162 to driver r8169
+    - vmxnet3: do not stop tx queues after netif_device_detach()
+    - nfp: bpf: relax prog rejection for mtu check through max_pkt_offset
+    - net/smc: Correct spelling mistake to TCPF_SYN_RECV
+    - btrfs: clear MISSING device status bit in btrfs_close_one_device
+    - btrfs: fix lost error handling when replaying directory deletes
+    - btrfs: call btrfs_check_rw_degradable only if there is a missing device
+    - ia64: kprobes: Fix to pass correct trampoline address to the handler
+    - hwmon: (pmbus/lm25066) Add offset coefficients
+    - regulator: s5m8767: do not use reset value as DVS voltage if GPIO DVS is
+      disabled
+    - regulator: dt-bindings: samsung,s5m8767: correct s5m8767,pmic-buck-default-
+      dvs-idx property
+    - EDAC/sb_edac: Fix top-of-high-memory value for Broadwell/Haswell
+    - mwifiex: fix division by zero in fw download path
+    - ath6kl: fix division by zero in send path
+    - ath6kl: fix control-message timeout
+    - ath10k: fix control-message timeout
+    - ath10k: fix division by zero in send path
+    - PCI: Mark Atheros QCA6174 to avoid bus reset
+    - rtl8187: fix control-message timeouts
+    - evm: mark evm_fixmode as __ro_after_init
+    - wcn36xx: Fix HT40 capability for 2Ghz band
+    - mwifiex: Read a PCI register after writing the TX ring write pointer
+    - libata: fix checking of DMA state
+    - wcn36xx: handle connection loss indication
+    - rsi: fix occasional initialisation failure with BT coex
+    - rsi: fix key enabled check causing unwanted encryption for vap_id > 0
+    - rsi: fix rate mask set leading to P2P failure
+    - rsi: Fix module dev_oper_mode parameter description
+    - RDMA/qedr: Fix NULL deref for query_qp on the GSI QP
+    - signal: Remove the bogus sigkill_pending in ptrace_stop
+    - signal/mips: Update (_save|_restore)_fp_context to fail with -EFAULT
+    - power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
+    - power: supply: max17042_battery: use VFSOC for capacity when no rsns
+    - KVM: nVMX: Query current VMCS when determining if MSR bitmaps are in use
+    - can: j1939: j1939_tp_cmd_recv(): ignore abort message in the BAM transport
+    - can: j1939: j1939_can_recv(): ignore messages with invalid source address
+    - powerpc/85xx: Fix oops when mpc85xx_smp_guts_ids node cannot be found
+    - serial: core: Fix initializing and restoring termios speed
+    - ALSA: mixer: oss: Fix racy access to slots
+    - ALSA: mixer: fix deadlock in snd_mixer_oss_set_volume
+    - xen/balloon: add late_initcall_sync() for initial ballooning done
+    - PCI: pci-bridge-emul: Fix emulation of W1C bits
+    - PCI: aardvark: Do not clear status bits of masked interrupts
+    - PCI: aardvark: Fix checking for link up via LTSSM state
+    - PCI: aardvark: Do not unmask unused interrupts
+    - PCI: aardvark: Fix reporting Data Link Layer Link Active
+    - PCI: aardvark: Fix return value of MSI domain .alloc() method
+    - PCI: aardvark: Read all 16-bits from PCIE_MSI_PAYLOAD_REG
+    - quota: check block number when reading the block in quota file
+    - quota: correct error number in free_dqentry()
+    - pinctrl: core: fix possible memory leak in pinctrl_enable()
+    - iio: dac: ad5446: Fix ad5622_write() return value
+    - USB: serial: keyspan: fix memleak on probe errors
+    - USB: iowarrior: fix control-message timeouts
+    - USB: chipidea: fix interrupt deadlock
+    - dma-buf: WARN on dmabuf release with pending attachments
+    - drm: panel-orientation-quirks: Update the Lenovo Ideapad D330 quirk (v2)
+    - drm: panel-orientation-quirks: Add quirk for KD Kurio Smart C15200 2-in-1
+    - drm: panel-orientation-quirks: Add quirk for the Samsung Galaxy Book 10.6
+    - Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg()
+    - Bluetooth: fix use-after-free error in lock_sock_nested()
+    - drm/panel-orientation-quirks: add Valve Steam Deck
+    - platform/x86: wmi: do not fail if disabling fails
+    - MIPS: lantiq: dma: add small delay after reset
+    - MIPS: lantiq: dma: reset correct number of channel
+    - locking/lockdep: Avoid RCU-induced noinstr fail
+    - net: sched: update default qdisc visibility after Tx queue cnt changes
+    - smackfs: Fix use-after-free in netlbl_catmap_walk()
+    - x86: Increase exception stack sizes
+    - mwifiex: Run SET_BSS_MODE when changing from P2P to STATION vif-type
+    - mwifiex: Properly initialize private structure on interface type changes
+    - ath10k: high latency fixes for beacon buffer
+    - media: mt9p031: Fix corrupted frame after restarting stream
+    - media: netup_unidvb: handle interrupt properly according to the firmware
+    - media: stm32: Potential NULL pointer dereference in dcmi_irq_thread()
+    - media: uvcvideo: Set capability in s_param
+    - media: uvcvideo: Return -EIO for control errors
+    - media: uvcvideo: Set unique vdev name based in type
+    - media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe()
+    - media: s5p-mfc: Add checking to s5p_mfc_probe().
+    - media: imx: set a media_device bus_info string
+    - media: mceusb: return without resubmitting URB in case of -EPROTO error.
+    - ia64: don't do IA64_CMPXCHG_DEBUG without CONFIG_PRINTK
+    - brcmfmac: Add DMI nvram filename quirk for Cyberbook T116 tablet
+    - media: rcar-csi2: Add checking to rcsi2_start_receiver()
+    - ipmi: Disable some operations during a panic
+    - ACPICA: Avoid evaluating methods too early during system resume
+    - media: ipu3-imgu: imgu_fmt: Handle properly try
+    - media: ipu3-imgu: VIDIOC_QUERYCAP: Fix bus_info
+    - media: usb: dvd-usb: fix uninit-value bug in dibusb_read_eeprom_byte()
+    - net-sysfs: try not to restart the syscall if it will fail eventually
+    - tracefs: Have tracefs directories not set OTH permission bits by default
+    - ath: dfs_pattern_detector: Fix possible null-pointer dereference in
+      channel_detector_create()
+    - iov_iter: Fix iov_iter_get_pages{,_alloc} page fault return value
+    - ACPI: battery: Accept charges over the design capacity as full
+    - leaking_addresses: Always print a trailing newline
+    - memstick: r592: Fix a UAF bug when removing the driver
+    - lib/xz: Avoid overlapping memcpy() with invalid input with in-place
+      decompression
+    - lib/xz: Validate the value before assigning it to an enum variable
+    - workqueue: make sysfs of unbound kworker cpumask more clever
+    - tracing/cfi: Fix cmp_entries_* functions signature mismatch
+    - mwl8k: Fix use-after-free in mwl8k_fw_state_machine()
+    - block: remove inaccurate requeue check
+    - nvmet: fix use-after-free when a port is removed
+    - nvmet-tcp: fix use-after-free when a port is removed
+    - nvme: drop scan_lock and always kick requeue list when removing namespaces
+    - PM: hibernate: Get block device exclusively in swsusp_check()
+    - selftests: kvm: fix mismatched fclose() after popen()
+    - iwlwifi: mvm: disable RX-diversity in powersave
+    - smackfs: use __GFP_NOFAIL for smk_cipso_doi()
+    - ARM: clang: Do not rely on lr register for stacktrace
+    - gre/sit: Don't generate link-local addr if addr_gen_mode is
+      IN6_ADDR_GEN_MODE_NONE
+    - ARM: 9136/1: ARMv7-M uses BE-8, not BE-32
+    - vrf: run conntrack only in context of lower/physdev for locally generated
+      packets
+    - net: annotate data-race in neigh_output()
+    - btrfs: do not take the uuid_mutex in btrfs_rm_device
+    - spi: bcm-qspi: Fix missing clk_disable_unprepare() on error in
+      bcm_qspi_probe()
+    - x86/hyperv: Protect set_hv_tscchange_cb() against getting preempted
+    - parisc: fix warning in flush_tlb_all
+    - task_stack: Fix end_of_stack() for architectures with upwards-growing stack
+    - parisc/unwind: fix unwinder when CONFIG_64BIT is enabled
+    - parisc/kgdb: add kgdb_roundup() to make kgdb work with idle polling
+    - netfilter: conntrack: set on IPS_ASSURED if flows enters internal stream
+      state
+    - selftests/bpf: Fix strobemeta selftest regression
+    - Bluetooth: fix init and cleanup of sco_conn.timeout_work
+    - rcu: Fix existing exp request check in sync_sched_exp_online_cleanup()
+    - drm/v3d: fix wait for TMU write combiner flush
+    - virtio-gpu: fix possible memory allocation failure
+    - net: net_namespace: Fix undefined member in key_remove_domain()
+    - cgroup: Make rebind_subsystems() disable v2 controllers all at once
+    - wilc1000: fix possible memory leak in cfg_scan_result()
+    - Bluetooth: btmtkuart: fix a memleak in mtk_hci_wmt_sync
+    - crypto: caam - disable pkc for non-E SoCs
+    - rxrpc: Fix _usecs_to_jiffies() by using usecs_to_jiffies()
+    - net: dsa: rtl8366rb: Fix off-by-one bug
+    - ath10k: Fix missing frame timestamp for beacon/probe-resp
+    - drm/amdgpu: fix warning for overflow check
+    - media: em28xx: add missing em28xx_close_extension
+    - media: cxd2880-spi: Fix a null pointer dereference on error handling path
+    - media: dvb-usb: fix ununit-value in az6027_rc_query
+    - media: TDA1997x: handle short reads of hdmi info frame.
+    - media: mtk-vpu: Fix a resource leak in the error handling path of
+      'mtk_vpu_probe()'
+    - media: radio-wl1273: Avoid card name truncation
+    - media: si470x: Avoid card name truncation
+    - media: tm6000: Avoid card name truncation
+    - media: cx23885: Fix snd_card_free call on null card pointer
+    - kprobes: Do not use local variable when creating debugfs file
+    - crypto: ecc - fix CRYPTO_DEFAULT_RNG dependency
+    - cpuidle: Fix kobject memory leaks in error paths
+    - media: em28xx: Don't use ops->suspend if it is NULL
+    - ath9k: Fix potential interrupt storm on queue reset
+    - EDAC/amd64: Handle three rank interleaving mode
+    - netfilter: nft_dynset: relax superfluous check on set updates
+    - media: dvb-frontends: mn88443x: Handle errors of clk_prepare_enable()
+    - crypto: qat - detect PFVF collision after ACK
+    - crypto: qat - disregard spurious PFVF interrupts
+    - hwrng: mtk - Force runtime pm ops for sleep ops
+    - b43legacy: fix a lower bounds test
+    - b43: fix a lower bounds test
+    - mmc: sdhci-omap: Fix NULL pointer exception if regulator is not configured
+    - memstick: avoid out-of-range warning
+    - memstick: jmb38x_ms: use appropriate free function in jmb38x_ms_alloc_host()
+    - net, neigh: Fix NTF_EXT_LEARNED in combination with NTF_USE
+    - hwmon: Fix possible memleak in __hwmon_device_register()
+    - hwmon: (pmbus/lm25066) Let compiler determine outer dimension of
+      lm25066_coeff
+    - ath10k: fix max antenna gain unit
+    - drm/msm: uninitialized variable in msm_gem_import()
+    - net: stream: don't purge sk_error_queue in sk_stream_kill_queues()
+    - mmc: mxs-mmc: disable regulator on error and in the remove function
+    - block: ataflop: fix breakage introduced at blk-mq refactoring
+    - platform/x86: thinkpad_acpi: Fix bitwise vs. logical warning
+    - mt76: mt76x02: fix endianness warnings in mt76x02_mac.c
+    - rsi: stop thread firstly in rsi_91x_init() error handling
+    - mwifiex: Send DELBA requests according to spec
+    - phy: micrel: ksz8041nl: do not use power down mode
+    - nvme-rdma: fix error code in nvme_rdma_setup_ctrl
+    - PM: hibernate: fix sparse warnings
+    - clocksource/drivers/timer-ti-dm: Select TIMER_OF
+    - drm/msm: Fix potential NULL dereference in DPU SSPP
+    - smackfs: use netlbl_cfg_cipsov4_del() for deleting cipso_v4_doi
+    - libbpf: Fix BTF data layout checks and allow empty BTF
+    - s390/gmap: don't unconditionally call pte_unmap_unlock() in __gmap_zap()
+    - irq: mips: avoid nested irq_enter()
+    - tcp: don't free a FIN sk_buff in tcp_remove_empty_skb()
+    - samples/kretprobes: Fix return value if register_kretprobe() failed
+    - KVM: s390: Fix handle_sske page fault handling
+    - libertas_tf: Fix possible memory leak in probe and disconnect
+    - libertas: Fix possible memory leak in probe and disconnect
+    - wcn36xx: add proper DMA memory barriers in rx path
+    - drm/amdgpu/gmc6: fix DMA mask from 44 to 40 bits
+    - net: amd-xgbe: Toggle PLL settings during rate change
+    - net: phylink: avoid mvneta warning when setting pause parameters
+    - crypto: pcrypt - Delay write to padata->info
+    - selftests/bpf: Fix fclose/pclose mismatch in test_progs
+    - udp6: allow SO_MARK ctrl msg to affect routing
+    - ibmvnic: don't stop queue in xmit
+    - ibmvnic: Process crqs after enabling interrupts
+    - RDMA/rxe: Fix wrong port_cap_flags
+    - clk: mvebu: ap-cpu-clk: Fix a memory leak in error handling paths
+    - ARM: s3c: irq-s3c24xx: Fix return value check for s3c24xx_init_intc()
+    - arm64: dts: rockchip: Fix GPU register width for RK3328
+    - ARM: dts: qcom: msm8974: Add xo_board reference clock to DSI0 PHY
+    - RDMA/bnxt_re: Fix query SRQ failure
+    - arm64: dts: meson-g12a: Fix the pwm regulator supply properties
+    - ARM: dts: at91: tse850: the emac<->phy interface is rmii
+    - scsi: dc395: Fix error case unwinding
+    - MIPS: loongson64: make CPU_LOONGSON64 depends on MIPS_FP_SUPPORT
+    - JFS: fix memleak in jfs_mount
+    - ALSA: hda: Reduce udelay() at SKL+ position reporting
+    - arm: dts: omap3-gta04a4: accelerometer irq fix
+    - soc/tegra: Fix an error handling path in tegra_powergate_power_up()
+    - memory: fsl_ifc: fix leak of irq and nand_irq in fsl_ifc_ctrl_probe
+    - clk: at91: check pmc node status before registering syscore ops
+    - video: fbdev: chipsfb: use memset_io() instead of memset()
+    - serial: 8250_dw: Drop wrong use of ACPI_PTR()
+    - usb: gadget: hid: fix error code in do_config()
+    - power: supply: rt5033_battery: Change voltage values to µV
+    - scsi: csiostor: Uninitialized data in csio_ln_vnp_read_cbfn()
+    - RDMA/mlx4: Return missed an error if device doesn't support steering
+    - staging: ks7010: select CRYPTO_HASH/CRYPTO_MICHAEL_MIC
+    - ARM: dts: stm32: fix SAI sub nodes register range
+    - ASoC: cs42l42: Correct some register default values
+    - ASoC: cs42l42: Defer probe if request_threaded_irq() returns EPROBE_DEFER
+    - phy: qcom-qusb2: Fix a memory leak on probe
+    - serial: xilinx_uartps: Fix race condition causing stuck TX
+    - HID: u2fzero: clarify error check and length calculations
+    - HID: u2fzero: properly handle timeouts in usb_submit_urb
+    - powerpc/44x/fsp2: add missing of_node_put
+    - mips: cm: Convert to bitfield API to fix out-of-bounds access
+    - power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
+    - apparmor: fix error check
+    - rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined
+    - pnfs/flexfiles: Fix misplaced barrier in nfs4_ff_layout_prepare_ds
+    - drm/plane-helper: fix uninitialized variable reference
+    - PCI: aardvark: Don't spam about PIO Response Status
+    - PCI: aardvark: Fix preserving PCI_EXP_RTCTL_CRSSVE flag on emulated bridge
+    - opp: Fix return in _opp_add_static_v2()
+    - NFS: Fix deadlocks in nfs_scan_commit_list()
+    - fs: orangefs: fix error return code of orangefs_revalidate_lookup()
+    - mtd: spi-nor: hisi-sfc: Remove excessive clk_disable_unprepare()
+    - mtd: core: don't remove debugfs directory if device is in use
+    - dmaengine: at_xdmac: fix AT_XDMAC_CC_PERID() macro
+    - auxdisplay: img-ascii-lcd: Fix lock-up when displaying empty string
+    - auxdisplay: ht16k33: Connect backlight to fbdev
+    - auxdisplay: ht16k33: Fix frame buffer device blanking
+    - soc: fsl: dpaa2-console: free buffer before returning from
+      dpaa2_console_read
+    - netfilter: nfnetlink_queue: fix OOB when mac header was cleared
+    - dmaengine: dmaengine_desc_callback_valid(): Check for `callback_result`
+    - signal/sh: Use force_sig(SIGKILL) instead of do_group_exit(SIGKILL)
+    - m68k: set a default value for MEMORY_RESERVE
+    - watchdog: f71808e_wdt: fix inaccurate report in WDIOC_GETTIMEOUT
+    - ar7: fix kernel builds for compiler test
+    - scsi: qla2xxx: Fix gnl list corruption
+    - scsi: qla2xxx: Turn off target reset during issue_lip
+    - NFSv4: Fix a regression in nfs_set_open_stateid_locked()
+    - i2c: xlr: Fix a resource leak in the error handling path of
+      'xlr_i2c_probe()'
+    - xen-pciback: Fix return in pm_ctrl_init()
+    - net: davinci_emac: Fix interrupt pacing disable
+    - net: vlan: fix a UAF in vlan_dev_real_dev()
+    - ACPI: PMIC: Fix intel_pmic_regs_handler() read accesses
+    - bonding: Fix a use-after-free problem when bond_sysfs_slave_add() failed
+    - mm/zsmalloc.c: close race window between zs_pool_dec_isolated() and
+      zs_unregister_migration()
+    - zram: off by one in read_block_state()
+    - perf bpf: Add missing free to bpf_event__print_bpf_prog_info()
+    - llc: fix out-of-bound array index in llc_sk_dev_hash()
+    - nfc: pn533: Fix double free when pn533_fill_fragment_skbs() fails
+    - arm64: pgtable: make __pte_to_phys/__phys_to_pte_val inline functions
+    - bpf: sockmap, strparser, and tls are reusing qdisc_skb_cb and colliding
+    - net/sched: sch_taprio: fix undefined behavior in ktime_mono_to_any
+    - net: hns3: allow configure ETS bandwidth of all TCs
+    - vsock: prevent unnecessary refcnt inc for nonblocking connect
+    - net/smc: fix sk_refcnt underflow on linkdown and fallback
+    - cxgb4: fix eeprom len when diagnostics not implemented
+    - selftests/net: udpgso_bench_rx: fix port argument
+    - ARM: 9155/1: fix early early_iounmap()
+    - ARM: 9156/1: drop cc-option fallbacks for architecture selection
+    - parisc: Fix set_fixmap() on PA1.x CPUs
+    - irqchip/sifive-plic: Fixup EOI failed when masked
+    - f2fs: should use GFP_NOFS for directory inodes
+    - net, neigh: Enable state migration between NUD_PERMANENT and NTF_USE
+    - 9p/net: fix missing error check in p9_check_errors
+    - ovl: fix deadlock in splice write
+    - powerpc/lib: Add helper to check if offset is within conditional branch
+      range
+    - powerpc/bpf: Validate branch ranges
+    - powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
+    - powerpc/security: Add a helper to query stf_barrier type
+    - powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
+    - mm, oom: pagefault_out_of_memory: don't force global OOM for dying tasks
+    - mm, oom: do not trigger out_of_memory from the #PF
+    - video: backlight: Drop maximum brightness override for brightness zero
+    - s390/cio: check the subchannel validity for dev_busid
+    - s390/tape: fix timer initialization in tape_std_assign()
+    - s390/cio: make ccw_device_dma_* more robust
+    - powerpc/powernv/prd: Unregister OPAL_MSG_PRD2 notifier during module unload
+    - PCI: Add PCI_EXP_DEVCTL_PAYLOAD_* macros
+    - SUNRPC: Partial revert of commit 6f9f17287e78
+    - ath10k: fix invalid dma_addr_t token assignment
+    - selftests/bpf: Fix also no-alu32 strobemeta selftest
+    - Linux 5.4.160
+    - soc/tegra: pmc: Fix imbalanced clock disabling in error code path
+  * Focal update: v5.4.159 upstream stable release (LP: #1953071)
+    - Revert "x86/kvm: fix vcpu-id indexed array sizes"
+    - usb: ehci: handshake CMD_RUN instead of STS_HALT
+    - usb: gadget: Mark USB_FSL_QE broken on 64-bit
+    - usb: musb: Balance list entry in musb_gadget_queue
+    - usb-storage: Add compatibility quirk flags for iODD 2531/2541
+    - binder: don't detect sender/target during buffer cleanup
+    - printk/console: Allow to disable console output by using console="" or
+      console=null
+    - isofs: Fix out of bound access for corrupted isofs image
+    - comedi: dt9812: fix DMA buffers on stack
+    - comedi: ni_usb6501: fix NULL-deref in command paths
+    - comedi: vmk80xx: fix transfer-buffer overflows
+    - comedi: vmk80xx: fix bulk-buffer overflow
+    - comedi: vmk80xx: fix bulk and interrupt message timeouts
+    - staging: r8712u: fix control-message timeout
+    - staging: rtl8192u: fix control-message timeouts
+    - media: staging/intel-ipu3: css: Fix wrong size comparison imgu_css_fw_init
+    - rsi: fix control-message timeout
+    - Linux 5.4.159
+  * Focal update: v5.4.158 upstream stable release (LP: #1953066)
+    - scsi: core: Put LLD module refcnt after SCSI device is released
+    - vrf: Revert "Reset skb conntrack connection..."
+    - net: ethernet: microchip: lan743x: Fix skb allocation failure
+    - media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
+    - Revert "xhci: Set HCD flag to defer primary roothub registration"
+    - Revert "usb: core: hcd: Add support for deferring roothub registration"
+    - sfc: Fix reading non-legacy supported link modes
+    - ARM: 9120/1: Revert "amba: make use of -1 IRQs warn"
+    - Linux 5.4.158
+  * [Ubuntu 20.04] Problem leading IUCV service down (on s390x) (LP: #1913442)
+    - usercopy: mark dma-kmalloc caches as usercopy caches
+
+  [ Ubuntu: 5.4.0-96.109 ]
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - [Config]: add i386 to CONFIG_SYSTEM_REVOCATION_KEYS annotation
+  * CVE-2022-0185
+    - SAUCE: vfs: Out-of-bounds write of heap buffer in fs_context.c
+    - SAUCE: vfs: test that one given mount param is not larger than PAGE_SIZE
+
+  [ Ubuntu: 5.4.0-94.106 ]
+
+  * focal/linux: 5.4.0-94.106 -proposed tracker (LP: #1956628)
+  * [Regression] Focal kernel  5.4.0-92.103 fails to boot when Secure Encrypted
+    Virtualization(SEV) is enabled (LP: #1956575)
+    - x86/ioremap: Map EFI-reserved memory as encrypted for SEV
+
+  [ Ubuntu: 5.4.0-92.103 ]
+
+  * focal/linux: 5.4.0-92.103 -proposed tracker (LP: #1952316)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.29)
+  * CVE-2021-4002
+    - tlb: mmu_gather: add tlb_flush_*_range APIs
+    - hugetlbfs: flush TLBs correctly after huge_pmd_unshare
+  * Re-enable DEBUG_INFO_BTF where it was disabled (LP: #1945632)
+    - [Config] Enable CONFIG_DEBUG_INFO_BTF on all arches
+  * Focal linux-azure: Vm crash on Dv5/Ev5 (LP: #1950462)
+    - KVM: VMX: eVMCS: make evmcs_sanitize_exec_ctrls() work again
+    - jump_label: Fix usage in module __init
+  * Support builtin revoked certificates (LP: #1932029)
+    - Revert "UBUNTU: SAUCE: (lockdown) Make get_cert_list() not complain about
+      cert lists that aren't present."
+    - integrity: Move import of MokListRT certs to a separate routine
+    - integrity: Load certs from the EFI MOK config table
+    - certs: Add ability to preload revocation certs
+    - integrity: Load mokx variables into the blacklist keyring
+    - certs: add 'x509_revocation_list' to gitignore
+    - SAUCE: Dump stack when X.509 certificates cannot be loaded
+    - [Packaging] build canonical-revoked-certs.pem from branch/arch certs
+    - [Packaging] Revoke 2012 UEFI signing certificate as built-in
+    - [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679)
+    - efi: Support for MOK variable config table
+    - efi: mokvar-table: fix some issues in new code
+    - efi: mokvar: add missing include of asm/early_ioremap.h
+    - efi/mokvar: Reserve the table only if it is in boot services data
+    - SAUCE: integrity: add informational messages when revoking certs
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679) // CVE-2020-26541 when certificates are revoked via
+    MokListXRT.
+    - SAUCE: integrity: Load mokx certs from the EFI MOK config table
+  * Focal update: v5.4.157 upstream stable release (LP: #1951883)
+    - ARM: 9133/1: mm: proc-macros: ensure *_tlb_fns are 4B aligned
+    - ARM: 9134/1: remove duplicate memcpy() definition
+    - ARM: 9139/1: kprobes: fix arch_init_kprobes() prototype
+    - ARM: 9141/1: only warn about XIP address when not compile testing
+    - ipv6: use siphash in rt6_exception_hash()
+    - ipv4: use siphash instead of Jenkins in fnhe_hashfun()
+    - usbnet: sanity check for maxpacket
+    - usbnet: fix error return code in usbnet_probe()
+    - Revert "pinctrl: bcm: ns: support updated DT binding as syscon subnode"
+    - ata: sata_mv: Fix the error handling of mv_chip_id()
+    - nfc: port100: fix using -ERRNO as command type mask
+    - net/tls: Fix flipped sign in tls_err_abort() calls
+    - mmc: vub300: fix control-message timeouts
+    - mmc: cqhci: clear HALT state after CQE enable
+    - mmc: dw_mmc: exynos: fix the finding clock sample value
+    - mmc: sdhci: Map more voltage level to SDHCI_POWER_330
+    - mmc: sdhci-esdhc-imx: clear the buffer_read_ready to reset standard tuning
+      circuit
+    - cfg80211: scan: fix RCU in cfg80211_add_nontrans_list()
+    - net: lan78xx: fix division by zero in send path
+    - tcp_bpf: Fix one concurrency problem in the tcp_bpf_send_verdict function
+    - IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt fields
+    - IB/hfi1: Fix abba locking issue with sc_disable()
+    - nvmet-tcp: fix data digest pointer calculation
+    - nvme-tcp: fix data digest pointer calculation
+    - RDMA/mlx5: Set user priority for DCT
+    - arm64: dts: allwinner: h5: NanoPI Neo 2: Fix ethernet node
+    - regmap: Fix possible double-free in regcache_rbtree_exit()
+    - net: batman-adv: fix error handling
+    - net: Prevent infinite while loop in skb_tx_hash()
+    - RDMA/sa_query: Use strscpy_pad instead of memcpy to copy a string
+    - nios2: Make NIOS2_DTB_SOURCE_BOOL depend on !COMPILE_TEST
+    - net: ethernet: microchip: lan743x: Fix driver crash when lan743x_pm_resume
+      fails
+    - net: ethernet: microchip: lan743x: Fix dma allocation failure by using
+      dma_set_mask_and_coherent
+    - net: nxp: lpc_eth.c: avoid hang when bringing interface down
+    - net/tls: Fix flipped sign in async_wait.err assignment
+    - phy: phy_ethtool_ksettings_get: Lock the phy for consistency
+    - phy: phy_start_aneg: Add an unlocked version
+    - sctp: use init_tag from inithdr for ABORT 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
+    - net: use netif_is_bridge_port() to check for IFF_BRIDGE_PORT
+    - cfg80211: correct bridge/4addr mode check
+    - KVM: s390: clear kicked_mask before sleeping again
+    - KVM: s390: preserve deliverable_mask in __airqs_kick_single_vcpu
+    - perf script: Check session->header.env.arch before using it
+    - Linux 5.4.157
+  * keyboard not working on Medion notebook s17 series (LP: #1950536)
+    - ACPI: resources: Add one more Medion model in IRQ override quirk
+  * creat09 from ubuntu_ltp_syscalls and cve-2018-13405 from ubuntu_ltp/cve
+    failed with XFS (LP: #1950239)
+    - xfs: ensure that the inode uid/gid match values match the icdinode ones
+    - xfs: merge the projid fields in struct xfs_icdinode
+    - xfs: remove the icdinode di_uid/di_gid members
+    - xfs: fix up non-directory creation in SGID directories
+  * reuseport_bpf_numa in net from ubuntu_kernel_selftests fails on ppc64le
+    (LP: #1867570)
+    - selftests/net: Fix reuseport_bpf_numa by skipping unavailable nodes
+  * Focal update: v5.4.156 upstream stable release (LP: #1951295)
+    - parisc: math-emu: Fix fall-through warnings
+    - net: switchdev: do not propagate bridge updates across bridges
+    - tee: optee: Fix missing devices unregister during optee_remove
+    - ARM: dts: at91: sama5d2_som1_ek: disable ISC node by default
+    - xtensa: xtfpga: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: xtfpga: Try software restart before simulating CPU reset
+    - NFSD: Keep existing listeners on portlist error
+    - dma-debug: fix sg checks in debug_dma_map_sg()
+    - ASoC: wm8960: Fix clock configuration on slave mode
+    - netfilter: ipvs: make global sysctl readonly in non-init netns
+    - lan78xx: select CRC32
+    - net: dsa: lantiq_gswip: fix register definition
+    - NIOS2: irqflags: rename a redefined register name
+    - net: hns3: reset DWRR of unused tc to zero
+    - net: hns3: add limit ets dwrr bandwidth cannot be 0
+    - net: hns3: disable sriov before unload hclge layer
+    - net: stmmac: Fix E2E delay mechanism
+    - net: enetc: fix ethtool counter name for PM0_TERR
+    - can: rcar_can: fix suspend/resume
+    - can: peak_usb: pcan_usb_fd_decode_status(): fix back to ERROR_ACTIVE state
+      notification
+    - can: peak_pci: peak_pci_remove(): fix UAF
+    - can: j1939: j1939_tp_rxtimer(): fix errant alert in j1939_tp_rxtimer
+    - can: j1939: j1939_netdev_start(): fix UAF for rx_kref of j1939_priv
+    - can: j1939: j1939_xtp_rx_dat_one(): cancel session if receive TP.DT with
+      error length
+    - can: j1939: j1939_xtp_rx_rts_session_new(): abort TP less than 9 bytes
+    - ceph: fix handling of "meta" errors
+    - ocfs2: fix data corruption after conversion from inline format
+    - ocfs2: mount fails with buffer overflow in strlen
+    - elfcore: correct reference to CONFIG_UML
+    - ALSA: usb-audio: Provide quirk for Sennheiser GSP670 Headset
+    - ALSA: hda/realtek: Add quirk for Clevo PC50HS
+    - ASoC: DAPM: Fix missing kctl change notifications
+    - audit: fix possible null-pointer dereference in audit_filter_rules
+    - powerpc64/idle: Fix SP offsets when saving GPRs
+    - KVM: PPC: Book3S HV: Fix stack handling in idle_kvm_start_guest()
+    - KVM: PPC: Book3S HV: Make idle_kvm_start_guest() return 0 if it went to
+      guest
+    - powerpc/idle: Don't corrupt back chain when going idle
+    - mm, slub: fix mismatch between reconstructed freelist depth and cnt
+    - mm, slub: fix potential memoryleak in kmem_cache_open()
+    - nfc: nci: fix the UAF of rf_conn_info object
+    - isdn: cpai: check ctr->cnr to avoid array index out of bound
+    - netfilter: Kconfig: use 'default y' instead of 'm' for bool config option
+    - selftests: netfilter: remove stray bash debug line
+    - gcc-plugins/structleak: add makefile var for disabling structleak
+    - btrfs: deal with errors when checking if a dir entry exists during log
+      replay
+    - net: stmmac: add support for dwmac 3.40a
+    - ARM: dts: spear3xx: Fix gmac node
+    - isdn: mISDN: Fix sleeping function called from invalid context
+    - platform/x86: intel_scu_ipc: Update timeout value in comment
+    - ALSA: hda: avoid write to STATESTS if controller is in reset
+    - Input: snvs_pwrkey - add clk handling
+    - scsi: core: Fix shost->cmd_per_lun calculation in scsi_add_host_with_dma()
+    - tracing: Have all levels of checks prevent recursion
+    - ARM: 9122/1: select HAVE_FUTEX_CMPXCHG
+    - pinctrl: stm32: use valid pin identifier in stm32_pinctrl_resume()
+    - Linux 5.4.156
+  * ubuntu_ltp / finit_module02 fails on v4.15 and other kernels
+    (LP: #1950644) // Focal update: v5.4.156 upstream stable release
+    (LP: #1951295)
+    - vfs: check fd has read access in kernel_read_file_from_fd()
+  * Focal update: v5.4.155 upstream stable release (LP: #1951291)
+    - ovl: simplify file splice
+    - ALSA: usb-audio: Add quirk for VF0770
+    - ALSA: seq: Fix a potential UAF by wrong private_free call order
+    - ALSA: hda/realtek: Complete partial device name to avoid ambiguity
+    - ALSA: hda/realtek: Add quirk for Clevo X170KM-G
+    - ALSA: hda/realtek - ALC236 headset MIC recording issue
+    - ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
+    - nds32/ftrace: Fix Error: invalid operands (*UND* and *UND* sections) for `^'
+    - s390: fix strrchr() implementation
+    - csky: don't let sigreturn play with priveleged bits of status register
+    - csky: Fixup regs.sr broken in ptrace
+    - btrfs: unlock newly allocated extent buffer after error
+    - btrfs: deal with errors when replaying dir entry during log replay
+    - btrfs: deal with errors when adding inode reference during log replay
+    - btrfs: check for error when looking up inode during dir entry replay
+    - watchdog: orion: use 0 for unset heartbeat
+    - x86/resctrl: Free the ctrlval arrays when domain_setup_mon_state() fails
+    - mei: me: add Ice Lake-N device id.
+    - xhci: guard accesses to ep_state in xhci_endpoint_reset()
+    - xhci: Fix command ring pointer corruption while aborting a command
+    - xhci: Enable trust tx length quirk for Fresco FL11 USB controller
+    - cb710: avoid NULL pointer subtraction
+    - efi/cper: use stack buffer for error record decoding
+    - efi: Change down_interruptible() in virt_efi_reset_system() to
+      down_trylock()
+    - usb: musb: dsps: Fix the probe error path
+    - Input: xpad - add support for another USB ID of Nacon GC-100
+    - USB: serial: qcserial: add EM9191 QDL support
+    - USB: serial: option: add Quectel EC200S-CN module support
+    - USB: serial: option: add Telit LE910Cx composition 0x1204
+    - USB: serial: option: add prod. id for Quectel EG91
+    - EDAC/armada-xp: Fix output of uncorrectable error counter
+    - nvmem: Fix shift-out-of-bound (UBSAN) with byte size cells
+    - x86/Kconfig: Do not enable AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT automatically
+    - powerpc/xive: Discard disabled interrupts in get_irqchip_state()
+    - iio: adc: aspeed: set driver data when adc probe.
+    - iio: adc128s052: Fix the error handling path of 'adc128_probe()'
+    - iio: mtk-auxadc: fix case IIO_CHAN_INFO_PROCESSED
+    - iio: light: opt3001: Fixed timeout error when 0 lux
+    - iio: ssp_sensors: add more range checking in ssp_parse_dataframe()
+    - iio: ssp_sensors: fix error code in ssp_print_mcu_debug()
+    - iio: dac: ti-dac5571: fix an error code in probe()
+    - sctp: account stream padding length for reconf chunk
+    - gpio: pca953x: Improve bias setting
+    - net: arc: select CRC32
+    - net: korina: select CRC32
+    - net/mlx5e: Mutually exclude RX-FCS and RX-port-timestamp
+    - net: stmmac: fix get_hw_feature() on old hardware
+    - net: encx24j600: check error in devm_regmap_init_encx24j600
+    - ethernet: s2io: fix setting mac address during resume
+    - nfc: fix error handling of nfc_proto_register()
+    - NFC: digital: fix possible memory leak in digital_tg_listen_mdaa()
+    - NFC: digital: fix possible memory leak in digital_in_send_sdd_req()
+    - pata_legacy: fix a couple uninitialized variable bugs
+    - ata: ahci_platform: fix null-ptr-deref in ahci_platform_enable_regulators()
+    - mlxsw: thermal: Fix out-of-bounds memory accesses
+    - platform/mellanox: mlxreg-io: Fix argument base in kstrtou32() call
+    - drm/panel: olimex-lcd-olinuxino: select CRC32
+    - drm/msm: Fix null pointer dereference on pointer edp
+    - drm/msm/dsi: Fix an error code in msm_dsi_modeset_init()
+    - drm/msm/dsi: fix off by one in dsi_bus_clk_enable error handling
+    - acpi/arm64: fix next_platform_timer() section mismatch error
+    - mqprio: Correct stats in mqprio_dump_class_stats().
+    - qed: Fix missing error code in qed_slowpath_start()
+    - r8152: select CRC32 and CRYPTO/CRYPTO_HASH/CRYPTO_SHA256
+    - ionic: don't remove netdev->dev_addr when syncing uc list
+    - Linux 5.4.155
+  * [UBUNTU 20.04] kernel:  unable to read partitions on virtio-block dasd (kvm)
+    (LP: #1950144) // Focal update: v5.4.155 upstream stable release
+    (LP: #1951291)
+    - virtio: write back F_VERSION_1 before validate
+  * Focal update: v5.4.154 upstream stable release (LP: #1951288)
+    - net: phy: bcm7xxx: Fixed indirect MMD operations
+    - ext4: correct the error path of ext4_write_inline_data_end()
+    - HID: apple: Fix logical maximum and usage maximum of Magic Keyboard JIS
+    - netfilter: ip6_tables: zero-initialize fragment offset
+    - HID: wacom: Add new Intuos BT (CTL-4100WL/CTL-6100WL) device IDs
+    - netfilter: nf_nat_masquerade: make async masq_inet6_event handling generic
+    - netfilter: nf_nat_masquerade: defer conntrack walk to work queue
+    - mac80211: Drop frames from invalid MAC address in ad-hoc mode
+    - m68k: Handle arrivals of multiple signals correctly
+    - net: prevent user from passing illegal stab size
+    - mac80211: check return value of rhashtable_init
+    - net: sun: SUNVNET_COMMON should depend on INET
+    - drm/amdgpu: fix gart.bo pin_count leak
+    - scsi: ses: Fix unsigned comparison with less than zero
+    - scsi: virtio_scsi: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - sched: Always inline is_percpu_thread()
+    - Linux 5.4.154
+  * Focal update: v5.4.153 upstream stable release (LP: #1950014)
+    - Partially revert "usb: Kconfig: using select for USB_COMMON dependency"
+    - USB: cdc-acm: fix racy tty buffer accesses
+    - USB: cdc-acm: fix break reporting
+    - usb: typec: tcpm: handle SRC_STARTUP state if cc changes
+    - xen/privcmd: fix error handling in mmap-resource processing
+    - mmc: meson-gx: do not use memcpy_to/fromio for dram-access-quirk
+    - ovl: fix missing negative dentry check in ovl_rename()
+    - nfsd: fix error handling of register_pernet_subsys() in init_nfsd()
+    - nfsd4: Handle the NFSv4 READDIR 'dircount' hint being zero
+    - xen/balloon: fix cancelled balloon action
+    - ARM: dts: omap3430-sdp: Fix NAND device node
+    - ARM: dts: qcom: apq8064: use compatible which contains chipid
+    - MIPS: BPF: Restore MIPS32 cBPF JIT
+    - bpf, mips: Validate conditional branch offsets
+    - soc: qcom: socinfo: Fixed argument passed to platform_set_data()
+    - ARM: dts: qcom: apq8064: Use 27MHz PXO clock as DSI PLL reference
+    - soc: qcom: mdt_loader: Drop PT_LOAD check on hash segment
+    - ARM: dts: imx: Add missing pinctrl-names for panel on M53Menlo
+    - ARM: dts: imx: Fix USB host power regulator polarity on M53Menlo
+    - arm64: dts: qcom: pm8150: use qcom,pm8998-pon binding
+    - xtensa: move XCHAL_KIO_* definitions to kmem_layout.h
+    - xtensa: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: call irqchip_init only when CONFIG_USE_OF is selected
+    - bpf, arm: Fix register clobbering in div/mod implementation
+    - bpf: Fix integer overflow in prealloc_elems_and_freelist()
+    - phy: mdio: fix memory leak
+    - net_sched: fix NULL deref in fifo_set_limit()
+    - powerpc/fsl/dts: Fix phy-connection-type for fm1mac3
+    - ptp_pch: Load module automatically if ID matches
+    - arm64: dts: freescale: Fix SP805 clock-names
+    - arm64: dts: ls1028a: add missing CAN nodes
+    - ARM: imx6: disable the GIC CPU interface before calling stby-poweroff
+      sequence
+    - net: bridge: use nla_total_size_64bit() in br_get_linkxstats_size()
+    - net/sched: sch_taprio: properly cancel timer from taprio_destroy()
+    - net: sfp: Fix typo in state machine debug string
+    - netlink: annotate data races around nlk->bound
+    - bus: ti-sysc: Use CLKDM_NOAUTO for dra7 dcan1 for errata i893
+    - video: fbdev: gbefb: Only instantiate device when built for IP32
+    - drm/nouveau/debugfs: fix file release memory leak
+    - gve: Correct available tx qpl check
+    - rtnetlink: fix if_nlmsg_stats_size() under estimation
+    - gve: fix gve_get_stats()
+    - i40e: fix endless loop under rtnl
+    - i40e: Fix freeing of uninitialized misc IRQ vector
+    - net: prefer socket bound to interface when not in VRF
+    - i2c: acpi: fix resource leak in reconfiguration device addition
+    - bpf, s390: Fix potential memory leak about jit_data
+    - RISC-V: Include clone3() on rv32
+    - x86/platform/olpc: Correct ifdef symbol to intended CONFIG_OLPC_XO15_SCI
+    - x86/hpet: Use another crystalball to evaluate HPET usability
+    - x86/Kconfig: Correct reference to MWINCHIP3D
+    - Linux 5.4.153
+  * Focal update: v5.4.152 upstream stable release (LP: #1950009)
+    - net: mdio: introduce a shutdown method to mdio device drivers
+    - xen-netback: correct success/error reporting for the SKB-with-fraglist case
+    - sparc64: fix pci_iounmap() when CONFIG_PCI is not set
+    - ext2: fix sleeping in atomic bugs on error
+    - scsi: sd: Free scsi_disk device via put_device()
+    - usb: testusb: Fix for showing the connection speed
+    - usb: dwc2: check return value after calling platform_get_resource()
+    - selftests: be sure to make khdr before other targets
+    - selftests:kvm: fix get_warnings_count() ignoring fscanf() return warn
+    - scsi: ses: Retry failed Send/Receive Diagnostic commands
+    - tools/vm/page-types: remove dependency on opt_file for idle page tracking
+    - KVM: do not shrink halt_poll_ns below grow_start
+    - kvm: x86: Add AMD PMU MSRs to msrs_to_save_all[]
+    - perf/x86: Reset destroy callback on event init failure
+    - silence nfscache allocation warnings with kvzalloc
+    - libata: Add ATA_HORKAGE_NO_NCQ_ON_ATI for Samsung 860 and 870 SSD.
+    - Linux 5.4.152
+  * linux-aws: Fix backport of RDMA/efa: Expose maximum  TX doorbell batch
+    (LP: #1949882)
+    - SAUCE: aws: Fix backport of RDMA/efa: Expose maximum TX doorbell batch
+
+  [ Ubuntu: 5.4.0-91.102 ]
+
+  * focal/linux: 5.4.0-91.102 -proposed tracker (LP: #1949840)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.08)
+  * KVM emulation failure when booting into  VM crash kernel with multiple CPUs
+    (LP: #1948862)
+    - KVM: x86: Properly reset MMU context at vCPU RESET/INIT
+  * aufs: kernel bug with apparmor and fuseblk (LP: #1948470)
+    - SAUCE: aufs: bugfix, stop omitting path->mnt
+  * ebpf:  bpf_redirect fails with ip6 gre interfaces (LP: #1947164)
+    - net: handle ARPHRD_IP6GRE in dev_is_mac_header_xmit()
+  * require CAP_NET_ADMIN to attach N_HCI ldisc (LP: #1949516)
+    - Bluetooth: hci_ldisc: require CAP_NET_ADMIN to attach N_HCI ldisc
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161)
+    - ocfs2: fix remounting needed after setfacl command
+  * ppc64 BPF JIT mod by 1 will not return 0 (LP: #1948351)
+    - powerpc/bpf: Fix BPF_MOD when imm == 1
+  * Drop "UBUNTU: SAUCE: cachefiles: Page leaking in
+    cachefiles_read_backing_file while vmscan is active" (LP: #1947709)
+    - Revert "UBUNTU: SAUCE: cachefiles: Page leaking in
+      cachefiles_read_backing_file while vmscan is active"
+  * Reassign I/O Path of ConnectX-5 Port 1 before Port 2 causes NULL dereference
+    (LP: #1943464)
+    - s390/pci: fix leak of PCI device structure
+    - s390/pci: fix use after free of zpci_dev
+    - s390/pci: fix zpci_zdev_put() on reserve
+  * [SRU][F] USB: serial: pl2303: add support for PL2303HXN (LP: #1948377)
+    - USB: serial: pl2303: add support for PL2303HXN
+    - USB: serial: pl2303: fix line-speed handling on newer chips
+  * Focal update: v5.4.151 upstream stable release (LP: #1947888)
+    - tty: Fix out-of-bound vmalloc access in imageblit
+    - cpufreq: schedutil: Use kobject release() method to free sugov_tunables
+    - cpufreq: schedutil: Destroy mutex before kobject_put() frees the memory
+    - usb: cdns3: fix race condition before setting doorbell
+    - fs-verity: fix signed integer overflow with i_size near S64_MAX
+    - hwmon: (w83793) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83792d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83791d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - scsi: ufs: Fix illegal offset in UPIU event trace
+    - mac80211: fix use-after-free in CCMP/GCMP RX
+    - x86/kvmclock: Move this_cpu_pvti into kvmclock.h
+    - drm/amd/display: Pass PCI deviceid into DC
+    - ipvs: check that ip_vs_conn_tab_bits is between 8 and 20
+    - hwmon: (mlxreg-fan) Return non-zero value when fan current state is enforced
+      from sysfs
+    - mac80211: Fix ieee80211_amsdu_aggregate frag_tail bug
+    - mac80211: limit injected vht mcs/nss in ieee80211_parse_tx_radiotap
+    - mac80211: mesh: fix potentially unaligned access
+    - mac80211-hwsim: fix late beacon hrtimer handling
+    - sctp: break out if skb_header_pointer returns NULL in sctp_rcv_ootb
+    - hwmon: (tmp421) report /PVLD condition as fault
+    - hwmon: (tmp421) fix rounding for negative values
+    - net: ipv4: Fix rtnexthop len when RTA_FLOW is present
+    - e100: fix length calculation in e100_get_regs_len
+    - e100: fix buffer overrun in e100_get_regs
+    - selftests, bpf: test_lwt_ip_encap: Really disable rp_filter
+    - scsi: csiostor: Add module softdep on cxgb4
+    - net: hns3: do not allow call hns3_nic_net_open repeatedly
+    - net: sched: flower: protect fl_walk() with rcu
+    - af_unix: fix races in sk_peer_pid and sk_peer_cred accesses
+    - perf/x86/intel: Update event constraints for ICX
+    - elf: don't use MAP_FIXED_NOREPLACE for elf interpreter mappings
+    - debugfs: debugfs_create_file_size(): use IS_ERR to check for error
+    - ipack: ipoctal: fix stack information leak
+    - ipack: ipoctal: fix tty registration race
+    - ipack: ipoctal: fix tty-registration error handling
+    - ipack: ipoctal: fix missing allocation-failure check
+    - ipack: ipoctal: fix module reference leak
+    - ext4: fix loff_t overflow in ext4_max_bitmap_size()
+    - ext4: fix reserved space counter leakage
+    - ext4: fix potential infinite loop in ext4_dx_readdir()
+    - HID: u2fzero: ignore incomplete packets without data
+    - net: udp: annotate data race around udp_sk(sk)->corkflag
+    - net: stmmac: don't attach interface until resume finishes
+    - PCI: Fix pci_host_bridge struct device release/free handling
+    - libnvdimm/pmem: Fix crash triggered when I/O in-flight during unbind
+    - hso: fix bailout in error case of probe
+    - usb: hso: fix error handling code of hso_create_net_device
+    - usb: hso: remove the bailout parameter
+    - crypto: ccp - fix resource leaks in ccp_run_aes_gcm_cmd()
+    - HID: betop: fix slab-out-of-bounds Write in betop_probe
+    - netfilter: ipset: Fix oversized kvmalloc() calls
+    - HID: usbhid: free raw_report buffers in usbhid_stop
+    - Linux 5.4.151
+  * Focal update: v5.4.150 upstream stable release (LP: #1947886)
+    - usb: gadget: r8a66597: fix a loop in set_feature()
+    - usb: dwc2: gadget: Fix ISOC flow for BDMA and Slave
+    - usb: dwc2: gadget: Fix ISOC transfer complete handling for DDMA
+    - usb: musb: tusb6010: uninitialized data in tusb_fifo_write_unaligned()
+    - cifs: fix incorrect check for null pointer in header_assemble
+    - xen/x86: fix PV trap handling on secondary processors
+    - usb-storage: Add quirk for ScanLogic SL11R-IDE older than 2.6c
+    - USB: serial: cp210x: add ID for GW Instek GDM-834x Digital Multimeter
+    - USB: cdc-acm: fix minor-number release
+    - binder: make sure fd closes complete
+    - staging: greybus: uart: fix tty use after free
+    - Re-enable UAS for LaCie Rugged USB3-FW with fk quirk
+    - USB: serial: mos7840: remove duplicated 0xac24 device ID
+    - USB: serial: option: add Telit LN920 compositions
+    - USB: serial: option: remove duplicate USB device ID
+    - USB: serial: option: add device id for Foxconn T99W265
+    - mcb: fix error handling in mcb_alloc_bus()
+    - erofs: fix up erofs_lookup tracepoint
+    - btrfs: prevent __btrfs_dump_space_info() to underflow its free space
+    - serial: mvebu-uart: fix driver's tx_empty callback
+    - net: hso: fix muxed tty registration
+    - afs: Fix incorrect triggering of sillyrename on 3rd-party invalidation
+    - platform/x86/intel: punit_ipc: Drop wrong use of ACPI_PTR()
+    - enetc: Fix illegal access when reading affinity_hint
+    - bnxt_en: Fix TX timeout when TX ring size is set to the smallest
+    - net/smc: add missing error check in smc_clc_prfx_set()
+    - gpio: uniphier: Fix void functions to remove return value
+    - qed: rdma - don't wait for resources under hw error recovery flow
+    - net/mlx4_en: Don't allow aRFS for encapsulated packets
+    - scsi: iscsi: Adjust iface sysfs attr detection
+    - tty: synclink_gt, drop unneeded forward declarations
+    - tty: synclink_gt: rename a conflicting function name
+    - fpga: machxo2-spi: Return an error on failure
+    - fpga: machxo2-spi: Fix missing error code in machxo2_write_complete()
+    - thermal/core: Potential buffer overflow in thermal_build_list_of_policies()
+    - cifs: fix a sign extension bug
+    - scsi: qla2xxx: Restore initiator in dual mode
+    - scsi: lpfc: Use correct scnprintf() limit
+    - irqchip/goldfish-pic: Select GENERIC_IRQ_CHIP to fix build
+    - irqchip/gic-v3-its: Fix potential VPE leak on error
+    - md: fix a lock order reversal in md_alloc
+    - blktrace: Fix uaf in blk_trace access after removing by sysfs
+    - net: macb: fix use after free on rmmod
+    - net: stmmac: allow CSR clock of 300MHz
+    - m68k: Double cast io functions to unsigned long
+    - ipv6: delay fib6_sernum increase in fib6_add
+    - bpf: Add oversize check before call kvcalloc()
+    - xen/balloon: use a kernel thread instead a workqueue
+    - nvme-multipath: fix ANA state updates when a namespace is not present
+    - sparc32: page align size in arch_dma_alloc
+    - blk-cgroup: fix UAF by grabbing blkcg lock before destroying blkg pd
+    - compiler.h: Introduce absolute_pointer macro
+    - net: i825xx: Use absolute_pointer for memcpy from fixed memory location
+    - sparc: avoid stringop-overread errors
+    - qnx4: avoid stringop-overread errors
+    - parisc: Use absolute_pointer() to define PAGE0
+    - arm64: Mark __stack_chk_guard as __ro_after_init
+    - alpha: Declare virt_to_phys and virt_to_bus parameter as pointer to volatile
+    - net: 6pack: Fix tx timeout and slot time
+    - spi: Fix tegra20 build with CONFIG_PM=n
+    - EDAC/synopsys: Fix wrong value type assignment for edac_mode
+    - thermal/drivers/int340x: Do not set a wrong tcc offset on resume
+    - arm64: dts: marvell: armada-37xx: Extend PCIe MEM space
+    - xen/balloon: fix balloon kthread freezing
+    - qnx4: work around gcc false positive warning bug
+    - Linux 5.4.150
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161) // Focal update:
+    v5.4.150 upstream stable release (LP: #1947886)
+    - ocfs2: drop acl cache for directories too
+  * Focal update: v5.4.149 upstream stable release (LP: #1947885)
+    - PCI: pci-bridge-emul: Fix big-endian support
+    - PCI: aardvark: Indicate error in 'val' when config read fails
+    - PCI: pci-bridge-emul: Add PCIe Root Capabilities Register
+    - PCI: aardvark: Fix reporting CRS value
+    - PCI/ACPI: Add Ampere Altra SOC MCFG quirk
+    - KVM: remember position in kvm->vcpus array
+    - console: consume APC, DM, DCS
+    - s390/pci_mmio: fully validate the VMA before calling follow_pte()
+    - ARM: Qualify enabling of swiotlb_init()
+    - apparmor: remove duplicate macro list_entry_is_head()
+    - ARM: 9077/1: PLT: Move struct plt_entries definition to header
+    - ARM: 9078/1: Add warn suppress parameter to arm_gen_branch_link()
+    - ARM: 9079/1: ftrace: Add MODULE_PLTS support
+    - ARM: 9098/1: ftrace: MODULE_PLT: Fix build problem without DYNAMIC_FTRACE
+    - sctp: validate chunk size in __rcv_asconf_lookup
+    - sctp: add param size validation for SCTP_PARAM_SET_PRIMARY
+    - staging: rtl8192u: Fix bitwise vs logical operator in
+      TranslateRxSignalStuff819xUsb()
+    - um: virtio_uml: fix memory leak on init failures
+    - dmaengine: acpi: Avoid comparison GSI with Linux vIRQ
+    - thermal/drivers/exynos: Fix an error code in exynos_tmu_probe()
+    - 9p/trans_virtio: Remove sysfs file on probe failure
+    - prctl: allow to setup brk for et_dyn executables
+    - nilfs2: use refcount_dec_and_lock() to fix potential UAF
+    - profiling: fix shift-out-of-bounds bugs
+    - pwm: lpc32xx: Don't modify HW state in .probe() after the PWM chip was
+      registered
+    - phy: avoid unnecessary link-up delay in polling mode
+    - net: stmmac: reset Tx desc base address before restarting Tx
+    - Kconfig.debug: drop selecting non-existing HARDLOCKUP_DETECTOR_ARCH
+    - thermal/core: Fix thermal_cooling_device_register() prototype
+    - drivers: base: cacheinfo: Get rid of DEFINE_SMP_CALL_CACHE_FUNCTION()
+    - parisc: Move pci_dev_is_behind_card_dino to where it is used
+    - dmaengine: sprd: Add missing MODULE_DEVICE_TABLE
+    - dmaengine: ioat: depends on !UML
+    - dmaengine: xilinx_dma: Set DMA mask for coherent APIs
+    - ceph: request Fw caps before updating the mtime in ceph_write_iter
+    - ceph: lockdep annotations for try_nonblocking_invalidate
+    - btrfs: fix lockdep warning while mounting sprout fs
+    - nilfs2: fix memory leak in nilfs_sysfs_create_device_group
+    - nilfs2: fix NULL pointer in nilfs_##name##_attr_release
+    - nilfs2: fix memory leak in nilfs_sysfs_create_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_create_snapshot_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_snapshot_group
+    - pwm: img: Don't modify HW state in .remove() callback
+    - pwm: rockchip: Don't modify HW state in .remove() callback
+    - pwm: stm32-lp: Don't modify HW state in .remove() callback
+    - blk-throttle: fix UAF by deleteing timer in blk_throtl_exit()
+    - rtc: rx8010: select REGMAP_I2C
+    - drm/nouveau/nvkm: Replace -ENOSYS with -ENODEV
+    - Linux 5.4.149
+
+  [ Ubuntu: 5.4.0-90.101 ]
+
+  * focal/linux: 5.4.0-90.101 -proposed tracker (LP: #1947260)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.10.18)
+  * Add final-checks to check certificates (LP: #1947174)
+    - [Packaging] Add system trusted and revocation keys final check
+  * No sound on Lenovo laptop models Legion 15IMHG05, Yoga 7 14ITL5, and 13s
+    Gen2 (LP: #1939052)
+    - ALSA: hda/realtek: Quirks to enable speaker output for Lenovo Legion 7i
+      15IMHG05, Yoga 7i 14ITL5/15ITL5, and 13s Gen2 laptops.
+    - ALSA: hda/realtek: Fix for quirk to enable speaker output on the Lenovo 13s
+      Gen2
+  * CVE-2020-36385
+    - 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
+  * Focal update: v5.4.148 upstream stable release (LP: #1946802)
+    - rtc: tps65910: Correct driver module alias
+    - btrfs: wake up async_delalloc_pages waiters after submit
+    - btrfs: reset replace target device to allocation state on close
+    - blk-zoned: allow zone management send operations without CAP_SYS_ADMIN
+    - blk-zoned: allow BLKREPORTZONE without CAP_SYS_ADMIN
+    - PCI/MSI: Skip masking MSI-X on Xen PV
+    - powerpc/perf/hv-gpci: Fix counter value parsing
+    - xen: fix setting of max_pfn in shared_info
+    - include/linux/list.h: add a macro to test if entry is pointing to the head
+    - 9p/xen: Fix end of loop tests for list_for_each_entry
+    - tools/thermal/tmon: Add cross compiling support
+    - pinctrl: stmfx: Fix hazardous u8[] to unsigned long cast
+    - pinctrl: ingenic: Fix incorrect pull up/down info
+    - soc: qcom: aoss: Fix the out of bound usage of cooling_devs
+    - soc: aspeed: lpc-ctrl: Fix boundary check for mmap
+    - soc: aspeed: p2a-ctrl: Fix boundary check for mmap
+    - arm64: head: avoid over-mapping in map_memory
+    - crypto: public_key: fix overflow during implicit conversion
+    - block: bfq: fix bfq_set_next_ioprio_data()
+    - power: supply: max17042: handle fails of reading status register
+    - dm crypt: Avoid percpu_counter spinlock contention in crypt_page_alloc()
+    - VMCI: fix NULL pointer dereference when unmapping queue pair
+    - media: uvc: don't do DMA on stack
+    - media: rc-loopback: return number of emitters rather than error
+    - Revert "dmaengine: imx-sdma: refine to load context only once"
+    - dmaengine: imx-sdma: remove duplicated sdma_load_context
+    - libata: add ATA_HORKAGE_NO_NCQ_TRIM for Samsung 860 and 870 SSDs
+    - ARM: 9105/1: atags_to_fdt: don't warn about stack size
+    - PCI/portdrv: Enable Bandwidth Notification only if port supports it
+    - PCI: Restrict ASMedia ASM1062 SATA Max Payload Size Supported
+    - PCI: Return ~0 data on pciconfig_read() CAP_SYS_ADMIN failure
+    - PCI: xilinx-nwl: Enable the clock through CCF
+    - PCI: aardvark: Fix checking for PIO status
+    - PCI: aardvark: Increase polling delay to 1.5s while waiting for PIO response
+    - PCI: aardvark: Fix masking and unmasking legacy INTx interrupts
+    - HID: input: do not report stylus battery state as "full"
+    - f2fs: quota: fix potential deadlock
+    - scsi: bsg: Remove support for SCSI_IOCTL_SEND_COMMAND
+    - IB/hfi1: Adjust pkey entry in index 0
+    - RDMA/iwcm: Release resources if iw_cm module initialization fails
+    - docs: Fix infiniband uverbs minor number
+    - pinctrl: samsung: Fix pinctrl bank pin count
+    - vfio: Use config not menuconfig for VFIO_NOIOMMU
+    - powerpc/stacktrace: Include linux/delay.h
+    - RDMA/efa: Remove double QP type assignment
+    - f2fs: show f2fs instance in printk_ratelimited
+    - f2fs: reduce the scope of setting fsck tag when de->name_len is zero
+    - openrisc: don't printk() unconditionally
+    - dma-debug: fix debugfs initialization order
+    - SUNRPC: Fix potential memory corruption
+    - scsi: fdomain: Fix error return code in fdomain_probe()
+    - pinctrl: single: Fix error return code in pcs_parse_bits_in_pinctrl_entry()
+    - scsi: smartpqi: Fix an error code in pqi_get_raid_map()
+    - scsi: qedi: Fix error codes in qedi_alloc_global_queues()
+    - scsi: qedf: Fix error codes in qedf_alloc_global_queues()
+    - powerpc/config: Renable MTD_PHYSMAP_OF
+    - scsi: target: avoid per-loop XCOPY buffer allocations
+    - HID: i2c-hid: Fix Elan touchpad regression
+    - KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs
+      are live
+    - platform/x86: dell-smbios-wmi: Add missing kfree in error-exit from
+      run_smbios_call
+    - fscache: Fix cookie key hashing
+    - clk: at91: sam9x60: Don't use audio PLL
+    - clk: at91: clk-generated: pass the id of changeable parent at registration
+    - clk: at91: clk-generated: Limit the requested rate to our range
+    - KVM: PPC: Fix clearing never mapped TCEs in realmode
+    - f2fs: fix to account missing .skipped_gc_rwsem
+    - f2fs: fix unexpected ENOENT comes from f2fs_map_blocks()
+    - f2fs: fix to unmap pages from userspace process in punch_hole()
+    - MIPS: Malta: fix alignment of the devicetree buffer
+    - kbuild: Fix 'no symbols' warning when CONFIG_TRIM_UNUSD_KSYMS=y
+    - userfaultfd: prevent concurrent API initialization
+    - drm/amdgpu: Fix amdgpu_ras_eeprom_init()
+    - ASoC: atmel: ATMEL drivers don't need HAS_DMA
+    - media: dib8000: rewrite the init prbs logic
+    - crypto: mxs-dcp - Use sg_mapping_iter to copy data
+    - PCI: Use pci_update_current_state() in pci_enable_device_flags()
+    - tipc: keep the skb in rcv queue until the whole data is read
+    - iio: dac: ad5624r: Fix incorrect handling of an optional regulator.
+    - iavf: do not override the adapter state in the watchdog task
+    - iavf: fix locking of critical sections
+    - ARM: dts: qcom: apq8064: correct clock names
+    - video: fbdev: kyro: fix a DoS bug by restricting user input
+    - netlink: Deal with ESRCH error in nlmsg_notify()
+    - Smack: Fix wrong semantics in smk_access_entry()
+    - drm: avoid blocking in drm_clients_info's rcu section
+    - igc: Check if num of q_vectors is smaller than max before array access
+    - usb: host: fotg210: fix the endpoint's transactional opportunities
+      calculation
+    - usb: host: fotg210: fix the actual_length of an iso packet
+    - usb: gadget: u_ether: fix a potential null pointer dereference
+    - USB: EHCI: ehci-mv: improve error handling in mv_ehci_enable()
+    - usb: gadget: composite: Allow bMaxPower=0 if self-powered
+    - staging: board: Fix uninitialized spinlock when attaching genpd
+    - tty: serial: jsm: hold port lock when reporting modem line changes
+    - drm/amd/display: Fix timer_per_pixel unit error
+    - drm/amd/amdgpu: Update debugfs link_settings output link_rate field in hex
+    - bpf/tests: Fix copy-and-paste error in double word test
+    - bpf/tests: Do not PASS tests without actually testing the result
+    - video: fbdev: asiliantfb: Error out if 'pixclock' equals zero
+    - video: fbdev: kyro: Error out if 'pixclock' equals zero
+    - video: fbdev: riva: Error out if 'pixclock' equals zero
+    - ipv4: ip_output.c: Fix out-of-bounds warning in ip_copy_addrs()
+    - flow_dissector: Fix out-of-bounds warnings
+    - s390/jump_label: print real address in a case of a jump label bug
+    - s390: make PCI mio support a machine flag
+    - serial: 8250: Define RX trigger levels for OxSemi 950 devices
+    - xtensa: ISS: don't panic in rs_init
+    - hvsi: don't panic on tty_register_driver failure
+    - serial: 8250_pci: make setup_port() parameters explicitly unsigned
+    - staging: ks7010: Fix the initialization of the 'sleep_status' structure
+    - samples: bpf: Fix tracex7 error raised on the missing argument
+    - ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init()
+    - Bluetooth: skip invalid hci_sync_conn_complete_evt
+    - workqueue: Fix possible memory leaks in wq_numa_init()
+    - bonding: 3ad: fix the concurrency between __bond_release_one() and
+      bond_3ad_state_machine_handler()
+    - arm64: tegra: Fix Tegra194 PCIe EP compatible string
+    - ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the
+      matching in-/output
+    - media: imx258: Rectify mismatch of VTS value
+    - media: imx258: Limit the max analogue gain to 480
+    - media: v4l2-dv-timings.c: fix wrong condition in two for-loops
+    - media: TDA1997x: fix tda1997x_query_dv_timings() return value
+    - media: tegra-cec: Handle errors of clk_prepare_enable()
+    - ARM: dts: imx53-ppd: Fix ACHC entry
+    - arm64: dts: qcom: sdm660: use reg value for memory node
+    - net: ethernet: stmmac: Do not use unreachable() in ipq806x_gmac_probe()
+    - drm/msm: mdp4: drop vblank get/put from prepare/complete_commit
+    - selftests/bpf: Fix xdp_tx.c prog section name
+    - Bluetooth: schedule SCO timeouts with delayed_work
+    - Bluetooth: avoid circular locks in sco_sock_connect
+    - net/mlx5: Fix variable type to match 64bit
+    - gpu: drm: amd: amdgpu: amdgpu_i2c: fix possible uninitialized-variable
+      access in amdgpu_i2c_router_select_ddc_port()
+    - drm/display: fix possible null-pointer dereference in dcn10_set_clock()
+    - mac80211: Fix monitor MTU limit so that A-MSDUs get through
+    - ARM: tegra: tamonten: Fix UART pad setting
+    - arm64: tegra: Fix compatible string for Tegra132 CPUs
+    - arm64: dts: ls1046a: fix eeprom entries
+    - nvme-tcp: don't check blk_mq_tag_to_rq when receiving pdu data
+    - Bluetooth: Fix handling of LE Enhanced Connection Complete
+    - opp: Don't print an error if required-opps is missing
+    - serial: sh-sci: fix break handling for sysrq
+    - tcp: enable data-less, empty-cookie SYN with TFO_SERVER_COOKIE_NOT_REQD
+    - rpc: fix gss_svc_init cleanup on failure
+    - staging: rts5208: Fix get_ms_information() heap buffer size
+    - gfs2: Don't call dlm after protocol is unmounted
+    - usb: chipidea: host: fix port index underflow and UBSAN complains
+    - lockd: lockd server-side shouldn't set fl_ops
+    - drm/exynos: Always initialize mapping in exynos_drm_register_dma()
+    - m68knommu: only set CONFIG_ISA_DMA_API for ColdFire sub-arch
+    - btrfs: tree-log: check btrfs_lookup_data_extent return value
+    - ASoC: Intel: Skylake: Fix module configuration for KPB and MIXER
+    - ASoC: Intel: Skylake: Fix passing loadable flag for module
+    - of: Don't allow __of_attached_node_sysfs() without CONFIG_SYSFS
+    - mmc: sdhci-of-arasan: Check return value of non-void funtions
+    - mmc: rtsx_pci: Fix long reads when clock is prescaled
+    - selftests/bpf: Enlarge select() timeout for test_maps
+    - mmc: core: Return correct emmc response in case of ioctl error
+    - cifs: fix wrong release in sess_alloc_buffer() failed path
+    - Revert "USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST
+      quirk set"
+    - usb: musb: musb_dsps: request_irq() after initializing musb
+    - usbip: give back URBs for unsent unlink requests during cleanup
+    - usbip:vhci_hcd USB port can get stuck in the disabled state
+    - ASoC: rockchip: i2s: Fix regmap_ops hang
+    - ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B
+    - drm/amdkfd: Account for SH/SE count when setting up cu masks.
+    - iwlwifi: mvm: fix a memory leak in iwl_mvm_mac_ctxt_beacon_changed
+    - iwlwifi: mvm: avoid static queue number aliasing
+    - iwlwifi: mvm: fix access to BSS elements
+    - net/mlx5: DR, Enable QP retransmission
+    - parport: remove non-zero check on count
+    - ath9k: fix OOB read ar9300_eeprom_restore_internal
+    - ath9k: fix sleeping in atomic context
+    - net: fix NULL pointer reference in cipso_v4_doi_free
+    - fix array-index-out-of-bounds in taprio_change
+    - net: w5100: check return value after calling platform_get_resource()
+    - parisc: fix crash with signals and alloca
+    - ovl: fix BUG_ON() in may_delete() when called from ovl_cleanup()
+    - scsi: BusLogic: Fix missing pr_cont() use
+    - scsi: qla2xxx: Changes to support kdump kernel
+    - scsi: qla2xxx: Sync queue idx with queue_pair_map idx
+    - cpufreq: powernv: Fix init_chip_info initialization in numa=off
+    - s390/pv: fix the forcing of the swiotlb
+    - mm/hugetlb: initialize hugetlb_usage in mm_init
+    - mm,vmscan: fix divide by zero in get_scan_count
+    - memcg: enable accounting for pids in nested pid namespaces
+    - platform/chrome: cros_ec_proto: Send command again when timeout occurs
+    - lib/test_stackinit: Fix static initializer test
+    - net: dsa: lantiq_gswip: fix maximum frame length
+    - drm/msi/mdp4: populate priv->kms in mdp4_kms_init
+    - drm/amdgpu: Fix BUG_ON assert
+    - drm/panfrost: Simplify lock_region calculation
+    - drm/panfrost: Use u64 for size in lock_region
+    - drm/panfrost: Clamp lock region to Bifrost minimum
+    - btrfs: fix upper limit for max_inline for page size 64K
+    - xen: reset legacy rtc flag for PV domU
+    - bnx2x: Fix enabling network interfaces without VFs
+    - arm64/sve: Use correct size when reinitialising SVE state
+    - PM: base: power: don't try to use non-existing RTC for storing data
+    - PCI: Add AMD GPU multi-function power dependencies
+    - drm/amd/amdgpu: Increase HWIP_MAX_INSTANCE to 10
+    - drm/etnaviv: return context from etnaviv_iommu_context_get
+    - drm/etnaviv: put submit prev MMU context when it exists
+    - drm/etnaviv: stop abusing mmu_context as FE running marker
+    - drm/etnaviv: keep MMU context across runtime suspend/resume
+    - drm/etnaviv: exec and MMU state is lost when resetting the GPU
+    - drm/etnaviv: fix MMU context leak on GPU reset
+    - drm/etnaviv: reference MMU context when setting up hardware state
+    - drm/etnaviv: add missing MMU context put when reaping MMU mapping
+    - s390/sclp: fix Secure-IPL facility detection
+    - x86/mm: Fix kern_addr_valid() to cope with existing but not present entries
+    - tipc: fix an use-after-free issue in tipc_recvmsg
+    - net-caif: avoid user-triggerable WARN_ON(1)
+    - ptp: dp83640: don't define PAGE0
+    - net/l2tp: Fix reference count leak in l2tp_udp_recv_core
+    - r6040: Restore MDIO clock frequency after MAC reset
+    - tipc: increase timeout in tipc_sk_enqueue()
+    - perf machine: Initialize srcline string member in add_location struct
+    - net/mlx5: FWTrace, cancel work on alloc pd error flow
+    - net/mlx5: Fix potential sleeping in atomic context
+    - events: Reuse value read using READ_ONCE instead of re-reading it
+    - vhost_net: fix OoB on sendmsg() failure.
+    - net/af_unix: fix a data-race in unix_dgram_poll
+    - net: dsa: destroy the phylink instance on any error in dsa_slave_phy_setup
+    - tcp: fix tp->undo_retrans accounting in tcp_sacktag_one()
+    - qed: Handle management FW error
+    - dt-bindings: arm: Fix Toradex compatible typo
+    - ibmvnic: check failover_pending in login response
+    - KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing
+      registers
+    - net: hns3: pad the short tunnel frame before sending to hardware
+    - net: hns3: change affinity_mask to numa node range
+    - net: hns3: disable mac in flr process
+    - net: hns3: fix the timing issue of VF clearing interrupt sources
+    - mm/memory_hotplug: use "unsigned long" for PFN in zone_for_pfn_range()
+    - dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation
+    - mfd: db8500-prcmu: Adjust map to reality
+    - PCI: Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms
+    - fuse: fix use after free in fuse_read_interrupt()
+    - mfd: Don't use irq_create_mapping() to resolve a mapping
+    - tracing/probes: Reject events which have the same name of existing one
+    - PCI: Add ACS quirks for Cavium multi-function devices
+    - Set fc_nlinfo in nh_create_ipv4, nh_create_ipv6
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit LN920
+    - PCI: ibmphp: Fix double unmap of io_mem
+    - ethtool: Fix an error code in cxgb2.c
+    - NTB: Fix an error code in ntb_msit_probe()
+    - NTB: perf: Fix an error code in perf_setup_inbuf()
+    - mfd: axp20x: Update AXP288 volatile ranges
+    - PCI: Fix pci_dev_str_match_path() alloc while atomic bug
+    - mfd: tqmx86: Clear GPIO IRQ resource when no IRQ is set
+    - KVM: arm64: Handle PSCI resets before userspace touches vCPU state
+    - PCI: Sync __pci_register_driver() stub for CONFIG_PCI=n
+    - mtd: rawnand: cafe: Fix a resource leak in the error handling path of
+      'cafe_nand_probe()'
+    - ARC: export clear_user_page() for modules
+    - perf unwind: Do not overwrite FEATURE_CHECK_LDFLAGS-libunwind-{x86,aarch64}
+    - net: dsa: b53: Fix calculating number of switch ports
+    - netfilter: socket: icmp6: fix use-after-scope
+    - fq_codel: reject silly quantum parameters
+    - qlcnic: Remove redundant unlock in qlcnic_pinit_from_rom
+    - ip_gre: validate csum_start only on pull
+    - net: renesas: sh_eth: Fix freeing wrong tx descriptor
+    - Linux 5.4.148
+  * Focal update: v5.4.147 upstream stable release (LP: #1946795)
+    - Linux 5.4.147
+    - upstream stable to v5.4.147
+  * CVE-2021-3428
+    - ext4: save the error code which triggered an ext4_error() in the superblock
+    - ext4: simulate various I/O and checksum errors when reading metadata
+    - ext4: save all error info in save_error_info() and drop ext4_set_errno()
+    - ext4: check journal inode extents more carefully
+  * ip6gretap / erspan / ip6erspan in rtnetlink.sh from net of
+    ubuntu_kernel_selftests failed on B-5.4-aws / B-5.4-gke / B-5.4-oracle /
+    B-5.4-azure / B-5.4 (LP: #1896448)
+    - SAUCE: selftests: rtnetlink: fixes for older iproute2
+  * CVE-2019-19449
+    - f2fs: fix wrong total_sections check and fsmeta check
+    - f2fs: fix to do sanity check on segment/section count
+  * kernel bug found when disconnecting one fiber channel interface on Cisco
+    Chassis with fnic DRV_VERSION "1.6.0.47" (LP: #1944586)
+    - scsi: fnic: Do not call 'scsi_done()' for unhandled commands
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (unknown type
+    name ‘__u64’) (LP: #1944613)
+    - SAUCE: selftests/memfd: fix __u64 not defined build issue
+  * Medion Notebook Keyboard not working (LP: #1909814)
+    - ACPI: resources: Add DMI-based legacy IRQ override quirk
+  * vrf: fix refcnt leak with vxlan slaves (LP: #1945180)
+    - ipv4: Fix device used for dst_alloc with local routes
+  * Check for changes relevant for security certifications (LP: #1945989)
+    - [Packaging] Add a new fips-checks script
+    - [Packaging] Add fips-checks as part of finalchecks
+  * Fix cold plugged USB device on certain PCIe USB cards (LP: #1945211)
+    - Revert "UBUNTU: SAUCE: Revert "usb: core: reduce power-on-good delay time of
+      root hub""
+    - usb: core: hcd: Add support for deferring roothub registration
+    - xhci: Set HCD flag to defer primary roothub registration
+    - usb: core: hcd: Modularize HCD stop configuration in usb_stop_hcd()
+  * CVE-2021-3759
+    - memcg: enable accounting of ipc resources
+  * Focal update: v5.4.146 upstream stable release (LP: #1946024)
+    - locking/mutex: Fix HANDOFF condition
+    - regmap: fix the offset of register error log
+    - crypto: mxs-dcp - Check for DMA mapping errors
+    - sched/deadline: Fix reset_on_fork reporting of DL tasks
+    - power: supply: axp288_fuel_gauge: Report register-address on readb / writeb
+      errors
+    - crypto: omap-sham - clear dma flags only after omap_sham_update_dma_stop()
+    - sched/deadline: Fix missing clock update in migrate_task_rq_dl()
+    - rcu/tree: Handle VM stoppage in stall detection
+    - hrtimer: Avoid double reprogramming in __hrtimer_start_range_ns()
+    - hrtimer: Ensure timerfd notification for HIGHRES=n
+    - udf: Check LVID earlier
+    - udf: Fix iocharset=utf8 mount option
+    - isofs: joliet: Fix iocharset=utf8 mount option
+    - bcache: add proper error unwinding in bcache_device_init
+    - nvme-tcp: don't update queue count when failing to set io queues
+    - nvme-rdma: don't update queue count when failing to set io queues
+    - nvmet: pass back cntlid on successful completion
+    - power: supply: max17042_battery: fix typo in MAx17042_TOFF
+    - s390/cio: add dev_busid sysfs entry for each subchannel
+    - libata: fix ata_host_start()
+    - crypto: qat - do not ignore errors from enable_vf2pf_comms()
+    - crypto: qat - handle both source of interrupt in VF ISR
+    - crypto: qat - fix reuse of completion variable
+    - crypto: qat - fix naming for init/shutdown VF to PF notifications
+    - crypto: qat - do not export adf_iov_putmsg()
+    - fcntl: fix potential deadlock for &fasync_struct.fa_lock
+    - udf_get_extendedattr() had no boundary checks.
+    - s390/kasan: fix large PMD pages address alignment check
+    - s390/debug: fix debug area life cycle
+    - m68k: emu: Fix invalid free in nfeth_cleanup()
+    - sched: Fix UCLAMP_FLAG_IDLE setting
+    - spi: spi-fsl-dspi: Fix issue with uninitialized dma_slave_config
+    - spi: spi-pic32: Fix issue with uninitialized dma_slave_config
+    - genirq/timings: Fix error return code in irq_timings_test_irqs()
+    - lib/mpi: use kcalloc in mpi_resize
+    - clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock
+      source channel
+    - crypto: qat - use proper type for vf_mask
+    - certs: Trigger creation of RSA module signing key if it's not an RSA key
+    - regulator: vctrl: Use locked regulator_get_voltage in probe path
+    - regulator: vctrl: Avoid lockdep warning in enable/disable ops
+    - spi: sprd: Fix the wrong WDG_LOAD_VAL
+    - spi: spi-zynq-qspi: use wait_for_completion_timeout to make
+      zynq_qspi_exec_mem_op not interruptible
+    - EDAC/i10nm: Fix NVDIMM detection
+    - drm/panfrost: Fix missing clk_disable_unprepare() on error in
+      panfrost_clk_init()
+    - media: TDA1997x: enable EDID support
+    - soc: rockchip: ROCKCHIP_GRF should not default to y, unconditionally
+    - media: cxd2880-spi: Fix an error handling path
+    - bpf: Fix a typo of reuseport map in bpf.h.
+    - bpf: Fix potential memleak and UAF in the verifier.
+    - ARM: dts: aspeed-g6: Fix HVI3C function-group in pinctrl dtsi
+    - arm64: dts: renesas: r8a77995: draak: Remove bogus adv7511w properties
+    - soc: qcom: rpmhpd: Use corner in power_off
+    - media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init
+    - media: dvb-usb: fix uninit-value in vp702x_read_mac_addr
+    - media: dvb-usb: Fix error handling in dvb_usb_i2c_init
+    - media: go7007: remove redundant initialization
+    - media: coda: fix frame_mem_ctrl for YUV420 and YVU420 formats
+    - Bluetooth: sco: prevent information leak in sco_conn_defer_accept()
+    - 6lowpan: iphc: Fix an off-by-one check of array index
+    - netns: protect netns ID lookups with RCU
+    - tcp: seq_file: Avoid skipping sk during tcp_seek_last_pos
+    - ARM: dts: meson8: Use a higher default GPU clock frequency
+    - ARM: dts: meson8b: odroidc1: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: mxq: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: ec100: Fix the pwm regulator supply properties
+    - net/mlx5e: Prohibit inner indir TIRs in IPoIB
+    - cgroup/cpuset: Fix a partition bug with hotplug
+    - net: cipso: fix warnings in netlbl_cipsov4_add_std
+    - i2c: highlander: add IRQ check
+    - leds: lt3593: Put fwnode in any case during ->probe()
+    - leds: trigger: audio: Add an activate callback to ensure the initial
+      brightness is set
+    - media: em28xx-input: fix refcount bug in em28xx_usb_disconnect
+    - media: venus: venc: Fix potential null pointer dereference on pointer fmt
+    - PCI: PM: Avoid forcing PCI_D0 for wakeup reasons inconsistently
+    - PCI: PM: Enable PME if it can be signaled from D3cold
+    - soc: qcom: smsm: Fix missed interrupts if state changes while masked
+    - debugfs: Return error during {full/open}_proxy_open() on rmmod
+    - Bluetooth: increase BTNAMSIZ to 21 chars to fix potential buffer overflow
+    - PM: EM: Increase energy calculation precision
+    - drm/msm/dpu: make dpu_hw_ctl_clear_all_blendstages clear necessary LMs
+    - arm64: dts: exynos: correct GIC CPU interfaces address range on Exynos7
+    - counter: 104-quad-8: Return error when invalid mode during ceiling_write
+    - Bluetooth: fix repeated calls to sco_sock_kill
+    - drm/msm/dsi: Fix some reference counted resource leaks
+    - usb: gadget: udc: at91: add IRQ check
+    - usb: phy: fsl-usb: add IRQ check
+    - usb: phy: twl6030: add IRQ checks
+    - usb: gadget: udc: renesas_usb3: Fix soc_device_match() abuse
+    - usb: host: ohci-tmio: add IRQ check
+    - usb: phy: tahvo: add IRQ check
+    - mac80211: Fix insufficient headroom issue for AMSDU
+    - lockd: Fix invalid lockowner cast after vfs_test_lock
+    - nfsd4: Fix forced-expiry locking
+    - usb: gadget: mv_u3d: request_irq() after initializing UDC
+    - mm/swap: consider max pages in iomap_swapfile_add_extent
+    - Bluetooth: add timeout sanity check to hci_inquiry
+    - i2c: iop3xx: fix deferred probing
+    - i2c: s3c2410: fix IRQ check
+    - rsi: fix error code in rsi_load_9116_firmware()
+    - rsi: fix an error code in rsi_probe()
+    - ASoC: Intel: Skylake: Leave data as is when invoking TLV IPCs
+    - ASoC: Intel: Skylake: Fix module resource and format selection
+    - mmc: dw_mmc: Fix issue with uninitialized dma_slave_config
+    - mmc: moxart: Fix issue with uninitialized dma_slave_config
+    - bpf: Fix possible out of bound write in narrow load handling
+    - CIFS: Fix a potencially linear read overflow
+    - i2c: mt65xx: fix IRQ check
+    - usb: ehci-orion: Handle errors of clk_prepare_enable() in probe
+    - usb: bdc: Fix an error handling path in 'bdc_probe()' when no suitable DMA
+      config is available
+    - tty: serial: fsl_lpuart: fix the wrong mapbase value
+    - ASoC: wcd9335: Fix a double irq free in the remove function
+    - ASoC: wcd9335: Fix a memory leak in the error handling path of the probe
+      function
+    - ASoC: wcd9335: Disable irq on slave ports in the remove function
+    - ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point()
+    - bcma: Fix memory leak for internally-handled cores
+    - brcmfmac: pcie: fix oops on failure to resume and reprobe
+    - ipv6: make exception cache less predictible
+    - ipv4: make exception cache less predictible
+    - net: sched: Fix qdisc_rate_table refcount leak when get tcf_block failed
+    - net: qualcomm: fix QCA7000 checksum handling
+    - octeontx2-af: Fix loop in free and unmap counter
+    - ipv4: fix endianness issue in inet_rtm_getroute_build_skb()
+    - bpf: Introduce BPF nospec instruction for mitigating Spectre v4
+    - bpf: Fix leakage due to insufficient speculative store bypass mitigation
+    - bpf: verifier: Allocate idmap scratch in verifier env
+    - bpf: Fix pointer arithmetic mask tightening under state pruning
+    - tty: Fix data race between tiocsti() and flush_to_ldisc()
+    - perf/x86/amd/ibs: Extend PERF_PMU_CAP_NO_EXCLUDE to IBS Op
+    - x86/resctrl: Fix a maybe-uninitialized build warning treated as error
+    - KVM: s390: index kvm->arch.idle_mask by vcpu_idx
+    - KVM: x86: Update vCPU's hv_clock before back to guest when tsc_offset is
+      adjusted
+    - KVM: nVMX: Unconditionally clear nested.pi_pending on nested VM-Enter
+    - fuse: truncate pagecache on atomic_o_trunc
+    - fuse: flush extending writes
+    - IMA: remove -Wmissing-prototypes warning
+    - IMA: remove the dependency on CRYPTO_MD5
+    - fbmem: don't allow too huge resolutions
+    - backlight: pwm_bl: Improve bootloader/kernel device handover
+    - clk: kirkwood: Fix a clocking boot regression
+    - Linux 5.4.146
+  * AMD A8-7680 (amdgpu): broken Xorg acceleration and hibernation
+    (LP: #1920674) // Focal update: v5.4.146 upstream stable release
+    (LP: #1946024)
+    - drm/amdgpu/acp: Make PM domain really work
+  * Focal update: v5.4.145 upstream stable release (LP: #1945517)
+    - fscrypt: add fscrypt_symlink_getattr() for computing st_size
+    - ext4: report correct st_size for encrypted symlinks
+    - f2fs: report correct st_size for encrypted symlinks
+    - ubifs: report correct st_size for encrypted symlinks
+    - kthread: Fix PF_KTHREAD vs to_kthread() race
+    - xtensa: fix kconfig unmet dependency warning for HAVE_FUTEX_CMPXCHG
+    - gpu: ipu-v3: Fix i.MX IPU-v3 offset calculations for (semi)planar U/V
+      formats
+    - reset: reset-zynqmp: Fixed the argument data type
+    - qed: Fix the VF msix vectors flow
+    - net: macb: Add a NULL check on desc_ptp
+    - qede: Fix memset corruption
+    - perf/x86/intel/pt: Fix mask of num_address_ranges
+    - perf/x86/amd/ibs: Work around erratum #1197
+    - perf/x86/amd/power: Assign pmu.module
+    - cryptoloop: add a deprecation warning
+    - ARM: 8918/2: only build return_address() if needed
+    - ALSA: hda/realtek: Workaround for conflicting SSID on ASUS ROG Strix G17
+    - ALSA: pcm: fix divide error in snd_pcm_lib_ioctl
+    - ARC: wireup clone3 syscall
+    - media: stkwebcam: fix memory leak in stk_camera_probe
+    - igmp: Add ip_mc_list lock in ip_check_mc_rcu
+    - USB: serial: mos7720: improve OOM-handling in read_mos_reg()
+    - ipv4/icmp: l3mdev: Perform icmp error route lookup on source device routing
+      table (v2)
+    - powerpc/boot: Delete unneeded .globl _zimage_start
+    - net: ll_temac: Remove left-over debug message
+    - mm/page_alloc: speed up the iteration of max_order
+    - Revert "r8169: avoid link-up interrupt issue on RTL8106e if user enables
+      ASPM"
+    - x86/events/amd/iommu: Fix invalid Perf result due to IOMMU PMC power-gating
+    - Revert "btrfs: compression: don't try to compress if we don't have enough
+      pages"
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 800
+    - usb: host: xhci-rcar: Don't reload firmware after the completion
+    - usb: mtu3: use @mult for HS isoc or intr
+    - usb: mtu3: fix the wrong HS mult value
+    - xhci: fix unsafe memory usage in xhci tracing
+    - x86/reboot: Limit Dell Optiplex 990 quirk to early BIOS versions
+    - PCI: Call Max Payload Size-related fixup quirks early
+    - Linux 5.4.145
+  * Focal update: v5.4.144 upstream stable release (LP: #1944756)
+    - net: qrtr: fix another OOB Read in qrtr_endpoint_post
+    - ARC: Fix CONFIG_STACKDEPOT
+    - netfilter: conntrack: collect all entries in one cycle
+    - once: Fix panic when module unload
+    - ovl: fix uninitialized pointer read in ovl_lookup_real_one()
+    - mmc: sdhci-msm: Update the software timeout value for sdhc
+    - mm, oom: make the calculation of oom badness more accurate
+    - can: usb: esd_usb2: esd_usb2_rx_event(): fix the interchange of the CAN RX
+      and TX error counters
+    - Revert "USB: serial: ch341: fix character loss at high transfer rates"
+    - USB: serial: option: add new VID/PID to support Fibocom FG150
+    - usb: dwc3: gadget: Fix dwc3_calc_trbs_left()
+    - usb: dwc3: gadget: Stop EP0 transfers during pullup disable
+    - scsi: core: Fix hang of freezing queue between blocking and running device
+    - RDMA/bnxt_re: Add missing spin lock initialization
+    - IB/hfi1: Fix possible null-pointer dereference in _extend_sdma_tx_descs()
+    - e1000e: Fix the max snoop/no-snoop latency for 10M
+    - RDMA/efa: Free IRQ vectors on error flow
+    - ip_gre: add validation for csum_start
+    - xgene-v2: Fix a resource leak in the error handling path of 'xge_probe()'
+    - net: marvell: fix MVNETA_TX_IN_PRGRS bit number
+    - rtnetlink: Return correct error on changing device netns
+    - net: hns3: clear hardware resource when loading driver
+    - net: hns3: fix duplicate node in VLAN list
+    - net: hns3: fix get wrong pfc_en when query PFC configuration
+    - drm/i915: Fix syncmap memory leak
+    - usb: gadget: u_audio: fix race condition on endpoint stop
+    - perf/x86/intel/uncore: Fix integer overflow on 23 bit left shift of a u32
+    - opp: remove WARN when no valid OPPs remain
+    - virtio: Improve vq->broken access to avoid any compiler optimization
+    - virtio_pci: Support surprise removal of virtio pci device
+    - vringh: Use wiov->used to check for read/write desc order
+    - qed: qed ll2 race condition fixes
+    - qed: Fix null-pointer dereference in qed_rdma_create_qp()
+    - drm: Copy drm_wait_vblank to user before returning
+    - drm/nouveau/disp: power down unused DP links during init
+    - net/rds: dma_map_sg is entitled to merge entries
+    - btrfs: fix race between marking inode needs to be logged and log syncing
+    - vt_kdsetmode: extend console locking
+    - bpf: Track contents of read-only maps as scalars
+    - bpf: Fix cast to pointer from integer of different size warning
+    - net: dsa: mt7530: fix VLAN traffic leaks again
+    - KVM: x86/mmu: Treat NX as used (not reserved) for all !TDP shadow MMUs
+    - arm64: dts: qcom: msm8994-angler: Fix gpio-reserved-ranges 85-88
+    - btrfs: fix NULL pointer dereference when deleting device by invalid id
+    - Revert "floppy: reintroduce O_NDELAY fix"
+    - Revert "parisc: Add assembly implementations for memset, strlen, strcpy,
+      strncpy and strcat"
+    - net: don't unconditionally copy_from_user a struct ifreq for socket ioctls
+    - audit: move put_tree() to avoid trim_trees refcount underflow and UAF
+    - Linux 5.4.144
+
+  [ Ubuntu: 5.4.0-89.100 ]
+
+  * focal/linux: 5.4.0-89.100 -proposed tracker (LP: #1944901)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.27)
+  * ext4 journal recovery fails w/ data=journal + mmap (LP: #1847340)
+    - jbd2: introduce/export functions
+      jbd2_journal_submit|finish_inode_data_buffers()
+    - jbd2, ext4, ocfs2: introduce/use journal callbacks
+      j_submit|finish_inode_data_buffers()
+    - ext4: data=journal: fixes for ext4_page_mkwrite()
+    - ext4: data=journal: write-protect pages on j_submit_inode_data_buffers()
+    - ext4: fix mmap write protection for data=journal mode
+  * CVE-2021-40490
+    - ext4: fix race writing to an inline_data file while its xattrs are changing
+  * Obsolete patch "UBUNTU: SAUCE: ext4: fix directory index node split
+    corruption" (LP: #1942902)
+    - Revert "UBUNTU: SAUCE: ext4: fix directory index node split corruption"
+  * psock_snd.sh in net from ubuntu_kernel_selftests ADT failure with
+    focal/groovy/hirsute/impish (LP: #1892213)
+    - selftests/net: remove min gso test in packet_snd
+  * Focal update: v5.4.143 upstream stable release (LP: #1944212)
+    - ext4: fix EXT4_MAX_LOGICAL_BLOCK macro
+    - x86/fpu: Make init_fpstate correct with optimized XSAVE
+    - 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
+    - mtd: cfi_cmdset_0002: fix crash when erasing/writing AMD cards
+    - media: zr364xx: propagate errors from zr364xx_start_readpipe()
+    - media: zr364xx: fix memory leaks in probe()
+    - media: drivers/media/usb: fix memory leak in zr364xx_probe
+    - USB: core: Avoid WARNings for 0-length descriptor requests
+    - dmaengine: xilinx_dma: Fix read-after-free bug when terminating transfers
+    - dmaengine: usb-dmac: Fix PM reference leak in usb_dmac_probe()
+    - ARM: dts: am43x-epos-evm: Reduce i2c0 bus speed for tps65218
+    - dmaengine: of-dma: router_xlate to return -EPROBE_DEFER if controller is not
+      yet available
+    - scsi: megaraid_mm: Fix end of loop tests for list_for_each_entry()
+    - scsi: scsi_dh_rdac: Avoid crash during rdac_bus_attach()
+    - scsi: core: Avoid printing an error if target_alloc() returns -ENXIO
+    - scsi: core: Fix capacity set to zero after offlinining device
+    - ARM: dts: nomadik: Fix up interrupt controller node names
+    - net: usb: lan78xx: don't modify phy_device state concurrently
+    - drm/amd/display: Fix Dynamic bpp issue with 8K30 with Navi 1X
+    - Bluetooth: hidp: use correct wait queue when removing ctrl_wait
+    - iommu: Check if group is NULL before remove device
+    - cpufreq: armada-37xx: forbid cpufreq for 1.2 GHz variant
+    - dccp: add do-while-0 stubs for dccp_pr_debug macros
+    - virtio: Protect vqs list access
+    - vhost: Fix the calculation in vhost_overflow()
+    - bpf: Clear zext_dst of dead insns
+    - bnxt: don't lock the tx queue from napi poll
+    - bnxt: disable napi before canceling DIM
+    - net: 6pack: fix slab-out-of-bounds in decode_data
+    - ptp_pch: Restore dependency on PCI
+    - bnxt_en: Add missing DMA memory barriers
+    - vrf: Reset skb conntrack connection on VRF rcv
+    - virtio-net: support XDP when not more queues
+    - virtio-net: use NETIF_F_GRO_HW instead of NETIF_F_LRO
+    - net: qlcnic: add missed unlock in qlcnic_83xx_flash_read32
+    - net: mdio-mux: Don't ignore memory allocation errors
+    - net: mdio-mux: Handle -EPROBE_DEFER correctly
+    - ovs: clear skb->tstamp in forwarding path
+    - i40e: Fix ATR queue selection
+    - iavf: Fix ping is lost after untrusted VF had tried to change MAC
+    - ovl: add splice file read write helper
+    - mmc: dw_mmc: Fix hang on data CRC error
+    - ALSA: hda - fix the 'Capture Switch' value change notifications
+    - tracing / histogram: Fix NULL pointer dereference on strcmp() on NULL event
+      name
+    - slimbus: messaging: start transaction ids from 1 instead of zero
+    - slimbus: messaging: check for valid transaction id
+    - slimbus: ngd: reset dma setup during runtime pm
+    - ipack: tpci200: fix many double free issues in tpci200_pci_probe
+    - ipack: tpci200: fix memory leak in the tpci200_register
+    - btrfs: prevent rename2 from exchanging a subvol with a directory from
+      different parents
+    - PCI: Increase D3 delay for AMD Renoir/Cezanne XHCI
+    - ASoC: intel: atom: Fix breakage for PCM buffer address setup
+    - mm, memcg: avoid stale protection values when cgroup is above protection
+    - mm: memcontrol: fix occasional OOMs due to proportional memory.low reclaim
+    - fs: warn about impending deprecation of mandatory locks
+    - netfilter: nft_exthdr: fix endianness of tcp option cast
+    - Linux 5.4.143
+  * Focal update: v5.4.142 upstream stable release (LP: #1944202)
+    - iio: adc: ti-ads7950: Ensure CS is deasserted after reading channels
+    - iio: humidity: hdc100x: Add margin to the conversion time
+    - iio: adc: Fix incorrect exit of for-loop
+    - ASoC: xilinx: Fix reference to PCM buffer address
+    - ASoC: intel: atom: Fix reference to PCM buffer address
+    - i2c: dev: zero out array used for i2c reads from userspace
+    - ceph: reduce contention in ceph_check_delayed_caps()
+    - ACPI: NFIT: Fix support for virtual SPA ranges
+    - libnvdimm/region: Fix label activation vs errors
+    - ieee802154: hwsim: fix GPF in hwsim_set_edge_lqi
+    - ieee802154: hwsim: fix GPF in hwsim_new_edge_nl
+    - ASoC: cs42l42: Correct definition of ADC Volume control
+    - ASoC: cs42l42: Don't allow SND_SOC_DAIFMT_LEFT_J
+    - ASoC: cs42l42: Fix inversion of ADC Notch Switch control
+    - ASoC: cs42l42: Remove duplicate control for WNF filter frequency
+    - netfilter: nf_conntrack_bridge: Fix memory leak when error
+    - ASoC: cs42l42: Fix LRCLK frame start edge
+    - net: dsa: mt7530: add the missing RxUnicast MIB counter
+    - platform/x86: pcengines-apuv2: revert wiring up simswitch GPIO as LED
+    - platform/x86: pcengines-apuv2: Add missing terminating entries to gpio-
+      lookup tables
+    - net: phy: micrel: Fix link detection on ksz87xx switch"
+    - ppp: Fix generating ifname when empty IFLA_IFNAME is specified
+    - net: sched: act_mirred: Reset ct info when mirror/redirect skb
+    - iavf: Set RSS LUT and key in reset handle path
+    - psample: Add a fwd declaration for skbuff
+    - net/mlx5: Fix return value from tracer initialization
+    - drm/meson: fix colour distortion from HDR set during vendor u-boot
+    - net: dsa: microchip: Fix ksz_read64()
+    - net: Fix memory leak in ieee802154_raw_deliver
+    - net: igmp: fix data-race in igmp_ifc_timer_expire()
+    - net: dsa: lan9303: fix broken backpressure in .port_fdb_dump
+    - net: dsa: lantiq: fix broken backpressure in .port_fdb_dump
+    - net: dsa: sja1105: fix broken backpressure in .port_fdb_dump
+    - net: bridge: fix memleak in br_add_if()
+    - net: linkwatch: fix failure to restore device state across suspend/resume
+    - tcp_bbr: fix u32 wrap bug in round logic if bbr_init() called after 2B
+      packets
+    - net: igmp: increase size of mr_ifc_count
+    - xen/events: Fix race in set_evtchn_to_irq
+    - vsock/virtio: avoid potential deadlock when vsock device remove
+    - nbd: Aovid double completion of a request
+    - powerpc/kprobes: Fix kprobe Oops happens in booke
+    - x86/tools: Fix objdump version check again
+    - genirq: Provide IRQCHIP_AFFINITY_PRE_STARTUP
+    - x86/msi: Force affinity setup before startup
+    - x86/ioapic: Force affinity setup before startup
+    - x86/resctrl: Fix default monitoring groups reporting
+    - genirq/msi: Ensure deactivation on teardown
+    - genirq/timings: Prevent potential array overflow in __irq_timings_store()
+    - PCI/MSI: Enable and mask MSI-X early
+    - PCI/MSI: Mask all unused MSI-X entries
+    - PCI/MSI: Enforce that MSI-X table entry is masked for update
+    - PCI/MSI: Enforce MSI[X] entry updates to be visible
+    - PCI/MSI: Do not set invalid bits in MSI mask
+    - PCI/MSI: Correct misleading comments
+    - PCI/MSI: Use msi_mask_irq() in pci_msi_shutdown()
+    - PCI/MSI: Protect msi_desc::masked for multi-MSI
+    - KVM: VMX: Use current VMCS to query WAITPKG support for MSR emulation
+    - ceph: add some lockdep assertions around snaprealm handling
+    - ceph: clean up locking annotation for ceph_get_snap_realm and
+      __lookup_snap_realm
+    - ceph: take snap_empty_lock atomically with snaprealm refcount change
+    - vmlinux.lds.h: Handle clang's module.{c,d}tor sections
+    - iommu/vt-d: Fix agaw for a supported 48 bit guest address width
+    - Linux 5.4.142
+  * Focal update: v5.4.141 upstream stable release (LP: #1943484)
+    - KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB
+    - tee: Correct inappropriate usage of TEE_SHM_DMA_BUF flag
+    - media: v4l2-mem2mem: always consider OUTPUT queue during poll
+    - tracing: Reject string operand in the histogram expression
+    - usb: dwc3: Stop active transfers before halting the controller
+    - usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
+    - usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
+    - usb: dwc3: gadget: Prevent EP queuing while stopping transfers
+    - usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
+    - usb: dwc3: gadget: Disable gadget IRQ during pullup disable
+    - usb: dwc3: gadget: Avoid runtime resume if disabling pullup
+    - KVM: X86: MMU: Use the correct inherited permissions to get shadow page
+    - USB:ehci:fix Kunpeng920 ehci hardware problem
+    - ALSA: hda: Add quirk for ASUS Flow x13
+    - ppp: Fix generating ppp unit id when ifname is not specified
+    - ovl: prevent private clone if bind mount is not allowed
+    - btrfs: make qgroup_free_reserved_data take btrfs_inode
+    - btrfs: make btrfs_qgroup_reserve_data take btrfs_inode
+    - btrfs: qgroup: allow to unreserve range without releasing other ranges
+    - btrfs: qgroup: try to flush qgroup space when we get -EDQUOT
+    - btrfs: transaction: Cleanup unused TRANS_STATE_BLOCKED
+    - btrfs: qgroup: remove ASYNC_COMMIT mechanism in favor of reserve retry-
+      after-EDQUOT
+    - btrfs: fix lockdep splat when enabling and disabling qgroups
+    - net: xilinx_emaclite: Do not print real IOMEM pointer
+    - btrfs: qgroup: don't commit transaction when we already hold the handle
+    - btrfs: export and rename qgroup_reserve_meta
+    - btrfs: don't flush from btrfs_delayed_inode_reserve_metadata
+    - Linux 5.4.141
+
+  [ Ubuntu: 5.4.0-88.99 ]
+
+  * focal/linux: 5.4.0-88.99 -proposed tracker (LP: #1944747)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - Revert "UBUNTU: [Config] Disable virtualbox dkms build"
+
+  [ Ubuntu: 5.4.0-87.98 ]
+
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - [Config] Disable virtualbox dkms build
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+  *  LRMv5: switch primary version handling to kernel-versions data set
+    (LP: #1928921)
+    - [Packaging] switch to kernel-versions
+  * disable “CONFIG_HISI_DMA” config for ubuntu version (LP: #1936771)
+    - Disable CONFIG_HISI_DMA
+    - [Config] Record hisi_dma no longer built for arm64
+  * memory leaking when removing a profile (LP: #1939915)
+    - apparmor: Fix memory leak of profile proxy
+  * CryptoExpress EP11 cards are going offline (LP: #1939618)
+    - s390/zcrypt: Support for CCA protected key block version 2
+    - s390: Replace zero-length array with flexible-array member
+    - s390/zcrypt: Use scnprintf() for avoiding potential buffer overflow
+    - s390/zcrypt: replace snprintf/sprintf with scnprintf
+    - s390/ap: Remove ap device suspend and resume callbacks
+    - s390/zcrypt: use fallthrough;
+    - s390/zcrypt: use kvmalloc instead of kmalloc for 256k alloc
+    - s390/ap: remove power management code from ap bus and drivers
+    - s390/ap: introduce new ap function ap_get_qdev()
+    - s390/zcrypt: use kzalloc
+    - s390/zcrypt: fix smatch warnings
+    - s390/zcrypt: code beautification and struct field renames
+    - s390/zcrypt: split ioctl function into smaller code units
+    - s390/ap: rename and clarify ap state machine related stuff
+    - s390/zcrypt: provide cex4 cca sysfs attributes for cex3
+    - s390/ap: rework crypto config info and default domain code
+    - s390/zcrypt: simplify cca_findcard2 loop code
+    - s390/zcrypt: remove set_fs() invocation in zcrypt device driver
+    - s390/ap: remove unnecessary spin_lock_init()
+    - s390/zcrypt: Support for CCA APKA master keys
+    - s390/zcrypt: introduce msg tracking in zcrypt functions
+    - s390/ap: split ap queue state machine state from device state
+    - s390/ap: add error response code field for ap queue devices
+    - s390/ap: add card/queue deconfig state
+    - s390/sclp: Add support for SCLP AP adapter config/deconfig
+    - s390/ap: Support AP card SCLP config and deconfig operations
+    - s390/ap/zcrypt: revisit ap and zcrypt error handling
+    - s390/zcrypt: move ap_msg param one level up the call chain
+    - s390/zcrypt: Introduce Failure Injection feature
+    - s390/zcrypt: fix wrong format specifications
+    - s390/ap: fix ap devices reference counting
+    - s390/zcrypt: return EIO when msg retry limit reached
+    - s390/zcrypt: fix zcard and zqueue hot-unplug memleak
+    - s390/ap: Fix hanging ioctl caused by wrong msg counter
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (LP: #1926142)
+    - SAUCE: selftests/memfd: fix build when F_SEAL_FUTURE_WRITE is not defined
+  * [SRU] Ice driver causes the kernel to crash with Ubuntu 20.04.2 with ethtool
+    specific register commands (LP: #1939855)
+    - ice: Fix bad register reads
+  * ubunut_kernel_selftests: memory-hotplug: avoid spamming logs with
+    dump_page() (LP: #1941829)
+    - selftests: memory-hotplug: avoid spamming logs with dump_page(), ratio limit
+      hot-remove error test
+  * e1000e blocks the boot process when it tried to write checksum to its NVM
+    (LP: #1936998)
+    - e1000e: Do not take care about recovery NVM checksum
+  * Focal update: v5.4.140 upstream stable release (LP: #1941798)
+    - Revert "ACPICA: Fix memory leak caused by _CID repair function"
+    - ALSA: seq: Fix racy deletion of subscriber
+    - arm64: dts: ls1028a: fix node name for the sysclk
+    - ARM: imx: add missing iounmap()
+    - ARM: imx: add missing clk_disable_unprepare()
+    - ARM: dts: imx6qdl-sr-som: Increase the PHY reset duration to 10ms
+    - ARM: dts: colibri-imx6ull: limit SDIO clock to 25MHz
+    - ARM: imx: fix missing 3rd argument in macro imx_mmdc_perf_init
+    - ARM: dts: imx: Swap M53Menlo pinctrl_power_button/pinctrl_power_out pins
+    - arm64: dts: armada-3720-turris-mox: remove mrvl,i2c-fast-mode
+    - ALSA: usb-audio: fix incorrect clock source setting
+    - clk: stm32f4: fix post divisor setup for I2S/SAI PLLs
+    - ARM: dts: am437x-l4: fix typo in can@0 node
+    - omap5-board-common: remove not physically existing vdds_1v8_main fixed-
+      regulator
+    - spi: imx: mx51-ecspi: Reinstate low-speed CONFIGREG delay
+    - spi: imx: mx51-ecspi: Fix low-speed CONFIGREG delay calculation
+    - scsi: sr: Return correct event when media event code is 3
+    - media: videobuf2-core: dequeue if start_streaming fails
+    - dmaengine: imx-dma: configure the generic DMA type to make it work
+    - net, gro: Set inner transport header offset in tcp/udp GRO hook
+    - net: dsa: sja1105: overwrite dynamic FDB entries with static ones in
+      .port_fdb_add
+    - net: dsa: sja1105: invalidate dynamic FDB entries learned concurrently with
+      statically added ones
+    - net: phy: micrel: Fix detection of ksz87xx switch
+    - net: natsemi: Fix missing pci_disable_device() in probe and remove
+    - gpio: tqmx86: really make IRQ optional
+    - sctp: move the active_key update after sh_keys is added
+    - nfp: update ethtool reporting of pauseframe control
+    - net: ipv6: fix returned variable type in ip6_skb_dst_mtu
+    - mips: Fix non-POSIX regexp
+    - bnx2x: fix an error code in bnx2x_nic_load()
+    - net: pegasus: fix uninit-value in get_interrupt_interval
+    - net: fec: fix use-after-free in fec_drv_remove
+    - net: vxge: fix use-after-free in vxge_device_unregister
+    - blk-iolatency: error out if blk_get_queue() failed in iolatency_set_limit()
+    - Bluetooth: defer cleanup of resources in hci_unregister_dev()
+    - USB: usbtmc: Fix RCU stall warning
+    - USB: serial: option: add Telit FD980 composition 0x1056
+    - USB: serial: ch341: fix character loss at high transfer rates
+    - USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2
+    - firmware_loader: use -ETIMEDOUT instead of -EAGAIN in fw_load_sysfs_fallback
+    - firmware_loader: fix use-after-free in firmware_fallback_sysfs
+    - ALSA: hda/realtek: add mic quirk for Acer SF314-42
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 600
+    - usb: cdns3: Fixed incorrect gadget state
+    - usb: gadget: f_hid: added GET_IDLE and SET_IDLE handlers
+    - usb: gadget: f_hid: fixed NULL pointer dereference
+    - usb: gadget: f_hid: idle uses the highest byte for duration
+    - usb: otg-fsm: Fix hrtimer list corruption
+    - clk: fix leak on devm_clk_bulk_get_all() unwind
+    - scripts/tracing: fix the bug that can't parse raw_trace_func
+    - tracing / histogram: Give calculation hist_fields a size
+    - optee: Clear stale cache entries during initialization
+    - tee: add tee_shm_alloc_kernel_buf()
+    - optee: Fix memory leak when failing to register shm pages
+    - tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
+    - staging: rtl8723bs: Fix a resource leak in sd_int_dpc
+    - staging: rtl8712: get rid of flush_scheduled_work
+    - media: rtl28xxu: fix zero-length control request
+    - pipe: increase minimum default pipe size to 2 pages
+    - ext4: fix potential htree corruption when growing large_dir directories
+    - serial: tegra: Only print FIFO error message when an error occurs
+    - serial: 8250_mtk: fix uart corruption issue when rx power off
+    - serial: 8250: Mask out floating 16/32-bit bus bits
+    - MIPS: Malta: Do not byte-swap accesses to the CBUS UART
+    - serial: 8250_pci: Enumerate Elkhart Lake UARTs via dedicated driver
+    - serial: 8250_pci: Avoid irq sharing for MSI(-X) interrupts.
+    - timers: Move clearing of base::timer_running under base:: Lock
+    - pcmcia: i82092: fix a null pointer dereference bug
+    - md/raid10: properly indicate failure when ending a failed write request
+    - KVM: x86: accept userspace interrupt only if no event is injected
+    - KVM: Do not leak memory for duplicate debugfs directories
+    - KVM: x86/mmu: Fix per-cpu counter corruption on 32-bit builds
+    - arm64: vdso: Avoid ISB after reading from cntvct_el0
+    - soc: ixp4xx: fix printing resources
+    - spi: meson-spicc: fix memory leak in meson_spicc_remove
+    - soc: ixp4xx/qmgr: fix invalid __iomem access
+    - perf/x86/amd: Don't touch the AMD64_EVENTSEL_HOSTONLY bit inside the guest
+    - bpf, selftests: Adjust few selftest result_unpriv outcomes
+    - libata: fix ata_pio_sector for CONFIG_HIGHMEM
+    - reiserfs: add check for root_inode in reiserfs_fill_super
+    - reiserfs: check directory items on read from disk
+    - virt_wifi: fix error on connect
+    - alpha: Send stop IPI to send to online CPUs
+    - net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and
+      ql_adapter_reset
+    - arm64: fix compat syscall return truncation
+    - Linux 5.4.140
+  * Focal update: v5.4.139 upstream stable release (LP: #1941796)
+    - btrfs: delete duplicated words + other fixes in comments
+    - btrfs: do not commit logs and transactions during link and rename operations
+    - btrfs: fix race causing unnecessary inode logging during link and rename
+    - btrfs: fix lost inode on log replay after mix of fsync, rename and inode
+      eviction
+    - regulator: rt5033: Fix n_voltages settings for BUCK and LDO
+    - spi: stm32h7: fix full duplex irq handler handling
+    - ASoC: tlv320aic31xx: fix reversed bclk/wclk master bits
+    - r8152: Fix potential PM refcount imbalance
+    - qed: fix possible unpaired spin_{un}lock_bh in _qed_mcp_cmd_and_union()
+    - net: Fix zero-copy head len calculation.
+    - nvme: fix nvme_setup_command metadata trace event
+    - ACPI: fix NULL pointer dereference
+    - Revert "Bluetooth: Shutdown controller after workqueues are flushed or
+      cancelled"
+    - firmware: arm_scmi: Ensure drivers provide a probe function
+    - firmware: arm_scmi: Add delayed response status check
+    - bpf: Inherit expanded/patched seen count from old aux data
+    - bpf: Do not mark insn as seen under speculative path verification
+    - bpf: Fix leakage under speculation on mispredicted branches
+    - bpf: Test_verifier, add alu32 bounds tracking tests
+    - bpf, selftests: Add a verifier test for assigning 32bit reg states to 64bit
+      ones
+    - bpf, selftests: Adjust few selftest outcomes wrt unreachable code
+    - spi: mediatek: Fix fifo transfer
+    - Linux 5.4.139
+  * Focal update: v5.4.138 upstream stable release (LP: #1940559)
+    - net_sched: check error pointer in tcf_dump_walker()
+    - x86/asm: Ensure asm/proto.h can be included stand-alone
+    - btrfs: fix rw device counting in __btrfs_free_extra_devids
+    - btrfs: mark compressed range uptodate only if all bio succeed
+    - x86/kvm: fix vcpu-id indexed array sizes
+    - KVM: add missing compat KVM_CLEAR_DIRTY_LOG
+    - ocfs2: fix zero out valid data
+    - ocfs2: issue zeroout to EOF blocks
+    - can: j1939: j1939_xtp_rx_dat_one(): fix rxtimer value between consecutive
+      TP.DT to 750ms
+    - can: raw: raw_setsockopt(): fix raw_rcv panic for sock UAF
+    - can: mcba_usb_start(): add missing urb->transfer_dma initialization
+    - can: usb_8dev: fix memory leak
+    - can: ems_usb: fix memory leak
+    - can: esd_usb2: fix memory leak
+    - HID: wacom: Re-enable touch by default for Cintiq 24HDT / 27QHDT
+    - NIU: fix incorrect error return, missed in previous revert
+    - nfc: nfcsim: fix use after free during module unload
+    - cfg80211: Fix possible memory leak in function cfg80211_bss_update
+    - netfilter: conntrack: adjust stop timestamp to real expiry value
+    - netfilter: nft_nat: allow to specify layer 4 protocol NAT only
+    - i40e: Fix logic of disabling queues
+    - i40e: Fix firmware LLDP agent related warning
+    - i40e: Fix queue-to-TC mapping on Tx
+    - i40e: Fix log TC creation failure when max num of queues is exceeded
+    - tipc: fix sleeping in tipc accept routine
+    - net: Set true network header for ECN decapsulation
+    - mlx4: Fix missing error code in mlx4_load_one()
+    - net: llc: fix skb_over_panic
+    - net/mlx5: Fix flow table chaining
+    - net/mlx5e: Fix nullptr in mlx5e_hairpin_get_mdev()
+    - sctp: fix return value check in __sctp_rcv_asconf_lookup
+    - tulip: windbond-840: Fix missing pci_disable_device() in probe and remove
+    - sis900: Fix missing pci_disable_device() in probe and remove
+    - can: hi311x: fix a signedness bug in hi3110_cmd()
+    - PCI: mvebu: Setup BAR0 in order to fix MSI
+    - powerpc/pseries: Fix regression while building external modules
+    - i40e: Add additional info to PHY type error
+    - can: j1939: j1939_session_deactivate(): clarify lifetime of session object
+    - Linux 5.4.138
+  * Focal update: v5.4.137 upstream stable release (LP: #1940557)
+    - selftest: fix build error in tools/testing/selftests/vm/userfaultfd.c
+    - tools: Allow proper CC/CXX/... override with LLVM=1 in Makefile.include
+    - KVM: x86: determine if an exception has an error code only when injecting
+      it.
+    - af_unix: fix garbage collect vs MSG_PEEK
+    - workqueue: fix UAF in pwq_unbound_release_workfn()
+    - cgroup1: fix leaked context root causing sporadic NULL deref in LTP
+    - net/802/mrp: fix memleak in mrp_request_join()
+    - net/802/garp: fix memleak in garp_request_join()
+    - net: annotate data race around sk_ll_usec
+    - sctp: move 198 addresses from unusable to private scope
+    - ipv6: allocate enough headroom in ip6_finish_output2()
+    - hfs: add missing clean-up in hfs_fill_super
+    - hfs: fix high memory mapping in hfs_bnode_read
+    - hfs: add lock nesting notation to hfs_find_init
+    - firmware: arm_scmi: Fix possible scmi_linux_errmap buffer overflow
+    - firmware: arm_scmi: Fix range check for the maximum number of pending
+      messages
+    - cifs: fix the out of range assignment to bit fields in
+      parse_server_interfaces
+    - iomap: remove the length variable in iomap_seek_data
+    - iomap: remove the length variable in iomap_seek_hole
+    - ARM: dts: versatile: Fix up interrupt controller node names
+    - ipv6: ip6_finish_output2: set sk into newly allocated nskb
+    - Linux 5.4.137
+  * Focal update: v5.4.136 upstream stable release (LP: #1939899)
+    - igc: Fix use-after-free error during reset
+    - igb: Fix use-after-free error during reset
+    - igc: change default return of igc_read_phy_reg()
+    - ixgbe: Fix an error handling path in 'ixgbe_probe()'
+    - igc: Prefer to use the pci_release_mem_regions method
+    - igc: Fix an error handling path in 'igc_probe()'
+    - igb: Fix an error handling path in 'igb_probe()'
+    - fm10k: Fix an error handling path in 'fm10k_probe()'
+    - e1000e: Fix an error handling path in 'e1000_probe()'
+    - iavf: Fix an error handling path in 'iavf_probe()'
+    - igb: Check if num of q_vectors is smaller than max before array access
+    - igb: Fix position of assignment to *ring
+    - gve: Fix an error handling path in 'gve_probe()'
+    - ipv6: fix 'disable_policy' for fwd packets
+    - selftests: icmp_redirect: remove from checking for IPv6 route get
+    - selftests: icmp_redirect: IPv6 PMTU info should be cleared after redirect
+    - pwm: sprd: Ensure configuring period and duty_cycle isn't wrongly skipped
+    - cxgb4: fix IRQ free race during driver unload
+    - nvme-pci: do not call nvme_dev_remove_admin from nvme_remove
+    - perf probe: Fix dso->nsinfo refcounting
+    - perf env: Fix sibling_dies memory leak
+    - perf test session_topology: Delete session->evlist
+    - perf test event_update: Fix memory leak of evlist
+    - perf dso: Fix memory leak in dso__new_map()
+    - perf script: Fix memory 'threads' and 'cpus' leaks on exit
+    - perf lzma: Close lzma stream on exit
+    - perf probe-file: Delete namelist in del_events() on the error path
+    - perf data: Close all files in close_dir()
+    - spi: imx: add a check for speed_hz before calculating the clock
+    - spi: stm32: Use dma_request_chan() instead dma_request_slave_channel()
+    - spi: stm32: fixes pm_runtime calls in probe/remove
+    - regulator: hi6421: Use correct variable type for regmap api val argument
+    - regulator: hi6421: Fix getting wrong drvdata
+    - spi: mediatek: fix fifo rx mode
+    - ASoC: rt5631: Fix regcache sync errors on resume
+    - liquidio: Fix unintentional sign extension issue on left shift of u16
+    - s390/bpf: Perform r1 range checking before accessing jit->seen_reg[r1]
+    - bpf, sockmap, tcp: sk_prot needs inuse_idx set for proc stats
+    - bpftool: Check malloc return value in mount_bpffs_for_pin
+    - net: fix uninit-value in caif_seqpkt_sendmsg
+    - efi/tpm: Differentiate missing and invalid final event log table.
+    - net: decnet: Fix sleeping inside in af_decnet
+    - KVM: PPC: Book3S: Fix CONFIG_TRANSACTIONAL_MEM=n crash
+    - KVM: PPC: Fix kvm_arch_vcpu_ioctl vcpu_load leak
+    - net: sched: fix memory leak in tcindex_partial_destroy_work
+    - netrom: Decrease sock refcount when sock timers expire
+    - scsi: iscsi: Fix iface sysfs attr detection
+    - scsi: target: Fix protect handling in WRITE SAME(32)
+    - spi: cadence: Correct initialisation of runtime PM again
+    - bnxt_en: Improve bnxt_ulp_stop()/bnxt_ulp_start() call sequence.
+    - bnxt_en: Refresh RoCE capabilities in bnxt_ulp_probe()
+    - bnxt_en: Add missing check for BNXT_STATE_ABORT_ERR in bnxt_fw_rset_task()
+    - bnxt_en: Check abort error state in bnxt_half_open_nic()
+    - net: hisilicon: rename CACHE_LINE_MASK to avoid redefinition
+    - net/tcp_fastopen: fix data races around tfo_active_disable_stamp
+    - net: hns3: fix rx VLAN offload state inconsistent issue
+    - net/sched: act_skbmod: Skip non-Ethernet packets
+    - ipv6: fix another slab-out-of-bounds in fib6_nh_flush_exceptions
+    - nvme-pci: don't WARN_ON in nvme_reset_work if ctrl.state is not RESETTING
+    - Revert "USB: quirks: ignore remote wake-up on Fibocom L850-GL LTE modem"
+    - afs: Fix tracepoint string placement with built-in AFS
+    - r8169: Avoid duplicate sysfs entry creation error
+    - nvme: set the PRACT bit when using Write Zeroes with T10 PI
+    - sctp: update active_key for asoc when old key is being replaced
+    - net: sched: cls_api: Fix the the wrong parameter
+    - drm/panel: raspberrypi-touchscreen: Prevent double-free
+    - proc: Avoid mixing integer types in mem_rw()
+    - s390/ftrace: fix ftrace_update_ftrace_func implementation
+    - s390/boot: fix use of expolines in the DMA code
+    - ALSA: usb-audio: Add missing proc text entry for BESPOKEN type
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum headsets
+    - ALSA: sb: Fix potential ABBA deadlock in CSP driver
+    - ALSA: hdmi: Expose all pins on MSI MS-7C94 board
+    - xhci: Fix lost USB 2 remote wake
+    - KVM: PPC: Book3S: Fix H_RTAS rets buffer overflow
+    - KVM: PPC: Book3S HV Nested: Sanitise H_ENTER_NESTED TM state
+    - usb: hub: Disable USB 3 device initiated lpm if exit latency is too high
+    - usb: hub: Fix link power management max exit latency (MEL) calculations
+    - USB: usb-storage: Add LaCie Rugged USB3-FW to IGNORE_UAS
+    - usb: max-3421: Prevent corruption of freed memory
+    - usb: renesas_usbhs: Fix superfluous irqs happen after usb_pkt_pop()
+    - USB: serial: option: add support for u-blox LARA-R6 family
+    - USB: serial: cp210x: fix comments for GE CS1000
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - usb: dwc2: gadget: Fix sending zero length packet in DDMA mode.
+    - firmware/efi: Tell memblock about EFI iomem reservations
+    - tracing/histogram: Rename "cpu" to "common_cpu"
+    - tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
+    - btrfs: check for missing device in btrfs_trim_fs
+    - media: ngene: Fix out-of-bounds bug in ngene_command_config_free_buf()
+    - ixgbe: Fix packet corruption due to missing DMA sync
+    - selftest: use mmap instead of posix_memalign to allocate memory
+    - userfaultfd: do not untag user pointers
+    - hugetlbfs: fix mount mode command line processing
+    - rbd: don't hold lock_rwsem while running_list is being drained
+    - rbd: always kick acquire on "acquired" and "released" notifications
+    - nds32: fix up stack guard gap
+    - drm: Return -ENOTTY for non-drm ioctls
+    - net: dsa: mv88e6xxx: use correct .stats_set_histogram() on Topaz
+    - net: bcmgenet: ensure EXT_ENERGY_DET_MASK is clear
+    - iio: accel: bma180: Use explicit member assignment
+    - iio: accel: bma180: Fix BMA25x bandwidth register values
+    - btrfs: compression: don't try to compress if we don't have enough pages
+    - PCI: Mark AMD Navi14 GPU ATS as broken
+    - perf inject: Close inject.output on exit
+    - xhci: add xhci_get_virt_ep() helper
+    - Linux 5.4.136
+  * Focal update: v5.4.135 upstream stable release (LP: #1939442)
+    - ARM: dts: gemini: rename mdio to the right name
+    - ARM: dts: gemini: add device_type on pci
+    - ARM: dts: rockchip: fix pinctrl sleep nodename for rk3036-kylin and rk3288
+    - arm64: dts: rockchip: fix pinctrl sleep nodename for rk3399.dtsi
+    - ARM: dts: rockchip: Fix the timer clocks order
+    - ARM: dts: rockchip: Fix IOMMU nodes properties on rk322x
+    - ARM: dts: rockchip: Fix power-controller node names for rk3066a
+    - ARM: dts: rockchip: Fix power-controller node names for rk3188
+    - ARM: dts: rockchip: Fix power-controller node names for rk3288
+    - arm64: dts: rockchip: Fix power-controller node names for px30
+    - arm64: dts: rockchip: Fix power-controller node names for rk3328
+    - reset: ti-syscon: fix to_ti_syscon_reset_data macro
+    - ARM: brcmstb: dts: fix NAND nodes names
+    - ARM: Cygnus: dts: fix NAND nodes names
+    - ARM: NSP: dts: fix NAND nodes names
+    - ARM: dts: BCM63xx: Fix NAND nodes names
+    - ARM: dts: Hurricane 2: Fix NAND nodes names
+    - ARM: dts: imx6: phyFLEX: Fix UART hardware flow control
+    - ARM: imx: pm-imx5: Fix references to imx5_cpu_suspend_info
+    - rtc: mxc_v2: add missing MODULE_DEVICE_TABLE
+    - kbuild: sink stdout from cmd for silent build
+    - ARM: dts: am57xx-cl-som-am57x: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: am437x-gp-evm: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: stm32: fix gpio-keys node on STM32 MCU boards
+    - ARM: dts: stm32: fix RCC node name on stm32f429 MCU
+    - ARM: dts: stm32: fix timer nodes on STM32 MCU to prevent warnings
+    - arm64: dts: juno: Update SCPI nodes as per the YAML schema
+    - ARM: dts: rockchip: fix supply properties in io-domains nodes
+    - ARM: dts: stm32: fix i2c node name on stm32f746 to prevent warnings
+    - ARM: dts: stm32: move stmmac axi config in ethernet node on stm32mp15
+    - soc/tegra: fuse: Fix Tegra234-only builds
+    - firmware: tegra: bpmp: Fix Tegra234-only builds
+    - arm64: dts: ls208xa: remove bus-num from dspi node
+    - arm64: dts: imx8mq: assign PCIe clocks
+    - thermal/core: Correct function name thermal_zone_device_unregister()
+    - kbuild: mkcompile_h: consider timestamp if KBUILD_BUILD_TIMESTAMP is set
+    - rtc: max77686: Do not enforce (incorrect) interrupt trigger type
+    - scsi: aic7xxx: Fix unintentional sign extension issue on left shift of u8
+    - scsi: libsas: Add LUN number check in .slave_alloc callback
+    - scsi: libfc: Fix array index out of bound exception
+    - scsi: qedf: Add check to synchronize abort and flush
+    - sched/fair: Fix CFS bandwidth hrtimer expiry type
+    - s390: introduce proper type handling call_on_stack() macro
+    - cifs: prevent NULL deref in cifs_compose_mount_options()
+    - arm64: dts: armada-3720-turris-mox: add firmware node
+    - firmware: turris-mox-rwtm: add marvell,armada-3700-rwtm-firmware compatible
+      string
+    - arm64: dts: marvell: armada-37xx: move firmware node to generic dtsi file
+    - f2fs: Show casefolding support only when supported
+    - usb: cdns3: Enable TDL_CHK only for OUT ep
+    - Revert "UBUNTU: SAUCE: Revert "mm: memcg/slab: fix memory leak at non-root
+      kmem_cache destroy""
+    - mm: slab: fix kmem_cache_create failed when sysfs node not destroyed
+    - dm writecache: return the exact table values that were set
+    - net: dsa: mv88e6xxx: enable .port_set_policy() on Topaz
+    - net: dsa: mv88e6xxx: enable .rmu_disable() on Topaz
+    - net: ipv6: fix return value of ip6_skb_dst_mtu
+    - netfilter: ctnetlink: suspicious RCU usage in ctnetlink_dump_helpinfo
+    - net/sched: act_ct: fix err check for nf_conntrack_confirm
+    - net: bridge: sync fdb to new unicast-filtering ports
+    - net: bcmgenet: Ensure all TX/RX queues DMAs are disabled
+    - net: ip_tunnel: fix mtu calculation for ETHER tunnel devices
+    - net: moxa: fix UAF in moxart_mac_probe
+    - net: qcom/emac: fix UAF in emac_remove
+    - net: ti: fix UAF in tlan_remove_one
+    - net: send SYNACK packet with accepted fwmark
+    - net: validate lwtstate->data before returning from skb_tunnel_info()
+    - net: fddi: fix UAF in fza_probe
+    - dma-buf/sync_file: Don't leak fences on merge failure
+    - tcp: annotate data races around tp->mtu_info
+    - ipv6: tcp: drop silly ICMPv6 packet too big messages
+    - bpftool: Properly close va_list 'ap' by va_end() on error
+    - perf test bpf: Free obj_buf
+    - udp: annotate data races around unix_sk(sk)->gso_size
+    - Linux 5.4.135
+  * Focal update: v5.4.134 upstream stable release (LP: #1939440)
+    - KVM: mmio: Fix use-after-free Read in kvm_vm_ioctl_unregister_coalesced_mmio
+    - KVM: x86: Use guest MAXPHYADDR from CPUID.0x8000_0008 iff TDP is enabled
+    - KVM: X86: Disable hardware breakpoints unconditionally before kvm_x86->run()
+    - scsi: core: Fix bad pointer dereference when ehandler kthread is invalid
+    - tracing: Do not reference char * as a string in histograms
+    - cgroup: verify that source is a string
+    - fbmem: Do not delete the mode that is still in use
+    - net: moxa: Use devm_platform_get_and_ioremap_resource()
+    - dmaengine: fsl-qdma: check dma_set_mask return value
+    - srcu: Fix broken node geometry after early ssp init
+    - tty: serial: fsl_lpuart: fix the potential risk of division or modulo by
+      zero
+    - misc/libmasm/module: Fix two use after free in ibmasm_init_one
+    - misc: alcor_pci: fix null-ptr-deref when there is no PCI bridge
+    - iio: gyro: fxa21002c: Balance runtime pm + use pm_runtime_resume_and_get().
+    - iio: magn: bmc150: Balance runtime pm + use pm_runtime_resume_and_get()
+    - ALSA: usx2y: Don't call free_pages_exact() with NULL address
+    - Revert "ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro"
+    - w1: ds2438: fixing bug that would always get page0
+    - scsi: hisi_sas: Propagate errors in interrupt_init_v1_hw()
+    - scsi: lpfc: Fix "Unexpected timeout" error in direct attach topology
+    - scsi: lpfc: Fix crash when lpfc_sli4_hba_setup() fails to initialize the
+      SGLs
+    - scsi: core: Cap scsi_host cmd_per_lun at can_queue
+    - ALSA: ac97: fix PM reference leak in ac97_bus_remove()
+    - tty: serial: 8250: serial_cs: Fix a memory leak in error handling path
+    - scsi: scsi_dh_alua: Check for negative result value
+    - fs/jfs: Fix missing error code in lmLogInit()
+    - scsi: megaraid_sas: Fix resource leak in case of probe failure
+    - scsi: megaraid_sas: Early detection of VD deletion through RaidMap update
+    - scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs
+    - scsi: iscsi: Add iscsi_cls_conn refcount helpers
+    - scsi: iscsi: Fix conn use after free during resets
+    - scsi: iscsi: Fix shost->max_id use
+    - scsi: qedi: Fix null ref during abort handling
+    - mfd: da9052/stmpe: Add and modify MODULE_DEVICE_TABLE
+    - mfd: cpcap: Fix cpcap dmamask not set warnings
+    - ASoC: img: Fix PM reference leak in img_i2s_in_probe()
+    - serial: tty: uartlite: fix console setup
+    - s390/sclp_vt220: fix console name to match device
+    - ALSA: sb: Fix potential double-free of CSP mixer elements
+    - powerpc/ps3: Add dma_mask to ps3_dma_region
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak when arm_smmu_rpm_get
+      fails
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak in address translation
+    - gpio: zynq: Check return value of pm_runtime_get_sync
+    - ALSA: ppc: fix error return code in snd_pmac_probe()
+    - selftests/powerpc: Fix "no_handler" EBB selftest
+    - gpio: pca953x: Add support for the On Semi pca9655
+    - ASoC: soc-core: Fix the error return code in
+      snd_soc_of_parse_audio_routing()
+    - s390/processor: always inline stap() and __load_psw_mask()
+    - s390/ipl_parm: fix program check new psw handling
+    - s390/mem_detect: fix diag260() program check new psw handling
+    - s390/mem_detect: fix tprot() program check new psw handling
+    - Input: hideep - fix the uninitialized use in hideep_nvm_unlock()
+    - ALSA: bebob: add support for ToneWeal FW66
+    - ALSA: usb-audio: scarlett2: Fix 18i8 Gen 2 PCM Input count
+    - ALSA: usb-audio: scarlett2: Fix data_mutex lock
+    - ALSA: usb-audio: scarlett2: Fix scarlett2_*_ctl_put() return values
+    - usb: gadget: f_hid: fix endianness issue with descriptors
+    - usb: gadget: hid: fix error return code in hid_bind()
+    - powerpc/boot: Fixup device-tree on little endian
+    - ASoC: Intel: kbl_da7219_max98357a: shrink platform_id below 20 characters
+    - backlight: lm3630a: Fix return code of .update_status() callback
+    - ALSA: hda: Add IRQ check for platform_get_irq()
+    - ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions
+    - staging: rtl8723bs: fix macro value for 2.4Ghz only device
+    - intel_th: Wait until port is in reset before programming it
+    - i2c: core: Disable client irq on reboot/shutdown
+    - power: supply: sc27xx: Add missing MODULE_DEVICE_TABLE
+    - power: supply: sc2731_charger: Add missing MODULE_DEVICE_TABLE
+    - pwm: spear: Don't modify HW state in .remove callback
+    - power: supply: ab8500: Avoid NULL pointers
+    - power: supply: max17042: Do not enforce (incorrect) interrupt trigger type
+    - power: reset: gpio-poweroff: add missing MODULE_DEVICE_TABLE
+    - ARM: 9087/1: kprobes: test-thumb: fix for LLVM_IAS=1
+    - PCI/P2PDMA: Avoid pci_get_slot(), which may sleep
+    - watchdog: Fix possible use-after-free in wdt_startup()
+    - watchdog: sc520_wdt: Fix possible use-after-free in wdt_turnoff()
+    - watchdog: Fix possible use-after-free by calling del_timer_sync()
+    - watchdog: imx_sc_wdt: fix pretimeout
+    - x86/fpu: Return proper error codes from user access functions
+    - PCI: tegra: Add missing MODULE_DEVICE_TABLE
+    - orangefs: fix orangefs df output.
+    - ceph: remove bogus checks and WARN_ONs from ceph_set_page_dirty
+    - NFS: nfs_find_open_context() may only select open files
+    - power: supply: charger-manager: add missing MODULE_DEVICE_TABLE
+    - power: supply: ab8500: add missing MODULE_DEVICE_TABLE
+    - pwm: img: Fix PM reference leak in img_pwm_enable()
+    - pwm: tegra: Don't modify HW state in .remove callback
+    - ACPI: AMBA: Fix resource name in /proc/iomem
+    - ACPI: video: Add quirk for the Dell Vostro 3350
+    - virtio-blk: Fix memory leak among suspend/resume procedure
+    - virtio_net: Fix error handling in virtnet_restore()
+    - virtio_console: Assure used length from device is limited
+    - x86/signal: Detect and prevent an alternate signal stack overflow
+    - f2fs: add MODULE_SOFTDEP to ensure crc32 is included in the initramfs
+    - PCI/sysfs: Fix dsm_label_utf16s_to_utf8s() buffer overrun
+    - power: supply: rt5033_battery: Fix device tree enumeration
+    - NFSv4: Initialise connection to the server in nfs4_alloc_client()
+    - um: fix error return code in slip_open()
+    - um: fix error return code in winch_tramp()
+    - watchdog: aspeed: fix hardware timeout calculation
+    - nfs: fix acl memory leak of posix_acl_create()
+    - ubifs: Set/Clear I_LINKABLE under i_lock for whiteout inode
+    - PCI: iproc: Fix multi-MSI base vector number allocation
+    - PCI: iproc: Support multi-MSI only on uniprocessor kernel
+    - x86/fpu: Limit xstate copy size in xstateregs_set()
+    - pwm: imx1: Don't disable clocks at device remove time
+    - virtio_net: move tx vq operation under tx queue lock
+    - nvme-tcp: can't set sk_user_data without write_lock
+    - ALSA: isa: Fix error return code in snd_cmi8330_probe()
+    - NFSv4/pNFS: Don't call _nfs4_pnfs_v3_ds_connect multiple times
+    - hexagon: use common DISCARDS macro
+    - ARM: dts: gemini-rut1xx: remove duplicate ethernet node
+    - reset: a10sr: add missing of_match_table reference
+    - ARM: exynos: add missing of_node_put for loop iteration
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU/XU3
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid HC1
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU4
+    - memory: atmel-ebi: add missing of_node_put for loop iteration
+    - reset: brcmstb: Add missing MODULE_DEVICE_TABLE
+    - memory: pl353: Fix error return code in pl353_smc_probe()
+    - rtc: fix snprintf() checking in is_rtc_hctosys()
+    - arm64: dts: renesas: v3msk: Fix memory size
+    - ARM: dts: r8a7779, marzen: Fix DU clock names
+    - firmware: tegra: Fix error return code in tegra210_bpmp_init()
+    - firmware: arm_scmi: Reset Rx buffer to max size during async commands
+    - ARM: dts: BCM5301X: Fixup SPI binding
+    - reset: bail if try_module_get() fails
+    - memory: fsl_ifc: fix leak of IO mapping on probe failure
+    - memory: fsl_ifc: fix leak of private memory on probe failure
+    - ARM: dts: am335x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: am437x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: imx6q-dhcom: Fix ethernet reset time properties
+    - ARM: dts: imx6q-dhcom: Fix ethernet plugin detection problems
+    - ARM: dts: imx6q-dhcom: Add gpios pinctrl for i2c bus recovery
+    - thermal/drivers/rcar_gen3_thermal: Fix coefficient calculations
+    - firmware: turris-mox-rwtm: fix reply status decoding function
+    - firmware: turris-mox-rwtm: report failures better
+    - firmware: turris-mox-rwtm: fail probing when firmware does not support hwrng
+    - scsi: be2iscsi: Fix an error handling path in beiscsi_dev_probe()
+    - mips: always link byteswap helpers into decompressor
+    - mips: disable branch profiling in boot/decompress.o
+    - MIPS: vdso: Invalid GIC access through VDSO
+    - scsi: scsi_dh_alua: Fix signedness bug in alua_rtpg()
+    - misc: alcor_pci: fix inverted branch condition
+    - Linux 5.4.134
+
+  [ Ubuntu: 5.4.0-86.97 ]
+
+  * 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
+
+  [ Ubuntu: 5.4.0-84.94 ]
+
+  * focal/linux: 5.4.0-84.94 -proposed tracker (LP: #1941767)
+  * Server boot failure after adding checks for ACPI IRQ override (LP: #1941657)
+    - Revert "ACPI: resources: Add checks for ACPI IRQ override"
+
+  [ Ubuntu: 5.4.0-83.93 ]
+
+  * focal/linux: 5.4.0-83.93 -proposed tracker (LP: #1940159)
+  * fails to launch linux L2 guests on AMD (LP: #1940134) // CVE-2021-3653
+    - KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+      (CVE-2021-3653)
+  * fails to launch linux L2 guests on AMD (LP: #1940134)
+    - SAUCE: Revert "UBUNTU: SAUCE: KVM: nSVM: avoid picking up unsupported bits
+      from L2 in int_ctl"
+
+  [ Ubuntu: 5.4.0-82.92 ]
+
+  * focal/linux: 5.4.0-82.92 -proposed tracker (LP: #1939799)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.08.16)
+  * CVE-2021-3656
+    - SAUCE: KVM: nSVM: always intercept VMLOAD/VMSAVE when nested
+  * CVE-2021-3653
+    - SAUCE: KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+  * [regression] USB device is not detected during boot (LP: #1939638)
+    - SAUCE: Revert "usb: core: reduce power-on-good delay time of root hub"
+  * dev_forward_skb: do not scrub skb mark within the same name space
+    (LP: #1935040)
+    - dev_forward_skb: do not scrub skb mark within the same name space
+  * XPS 9510 (TGL) Screen Brightness could not be changed (LP: #1933566)
+    - SAUCE: drm/i915: Force DPCD backlight mode for Dell XPS 9510(TGL)
+  * Acer Aspire 5 sound driver issues (LP: #1930188)
+    - ALSA: hda/realtek: headphone and mic don't work on an Acer laptop
+  * Sony Dualshock 4 usb dongle crashes the whole system (LP: #1935846)
+    - HID: sony: Workaround for DS4 dongle hotplug kernel crash.
+  * [21.10 FEAT] KVM: Provide a secure guest indication (LP: #1933173)
+    - s390/uv: add prot virt guest/host indication files
+    - s390/uv: fix prot virt host indication compilation
+  * Skip rtcpie test in kselftests/timers if the default RTC device does not
+    exist (LP: #1937991)
+    - selftests: timers: rtcpie: skip test if default RTC device does not exist
+  * Focal update: v5.4.133 upstream stable release (LP: #1938713)
+    - drm/mxsfb: Don't select DRM_KMS_FB_HELPER
+    - drm/zte: Don't select DRM_KMS_FB_HELPER
+    - drm/amd/amdgpu/sriov disable all ip hw status by default
+    - drm/vc4: fix argument ordering in vc4_crtc_get_margins()
+    - net: pch_gbe: Use proper accessors to BE data in pch_ptp_match()
+    - drm/amd/display: fix use_max_lb flag for 420 pixel formats
+    - hugetlb: clear huge pte during flush function on mips platform
+    - atm: iphase: fix possible use-after-free in ia_module_exit()
+    - mISDN: fix possible use-after-free in HFC_cleanup()
+    - atm: nicstar: Fix possible use-after-free in nicstar_cleanup()
+    - net: Treat __napi_schedule_irqoff() as __napi_schedule() on PREEMPT_RT
+    - drm/mediatek: Fix PM reference leak in mtk_crtc_ddp_hw_init()
+    - reiserfs: add check for invalid 1st journal block
+    - drm/virtio: Fix double free on probe failure
+    - drm/sched: Avoid data corruptions
+    - udf: Fix NULL pointer dereference in udf_symlink function
+    - e100: handle eeprom as little endian
+    - igb: handle vlan types with checker enabled
+    - drm/bridge: cdns: Fix PM reference leak in cdns_dsi_transfer()
+    - clk: renesas: r8a77995: Add ZA2 clock
+    - clk: tegra: Ensure that PLLU configuration is applied properly
+    - ipv6: use prandom_u32() for ID generation
+    - RDMA/cxgb4: Fix missing error code in create_qp()
+    - dm space maps: don't reset space map allocation cursor when committing
+    - pinctrl: mcp23s08: fix race condition in irq handler
+    - ice: set the value of global config lock timeout longer
+    - virtio_net: Remove BUG() to avoid machine dead
+    - net: bcmgenet: check return value after calling platform_get_resource()
+    - net: mvpp2: check return value after calling platform_get_resource()
+    - net: micrel: check return value after calling platform_get_resource()
+    - drm/amd/display: Update scaling settings on modeset
+    - drm/amd/display: Release MST resources on switch from MST to SST
+    - drm/amd/display: Set DISPCLK_MAX_ERRDET_CYCLES to 7
+    - drm/amdkfd: use allowed domain for vmbo validation
+    - fjes: check return value after calling platform_get_resource()
+    - selinux: use __GFP_NOWARN with GFP_NOWAIT in the AVC
+    - r8169: avoid link-up interrupt issue on RTL8106e if user enables ASPM
+    - drm/amd/display: Verify Gamma & Degamma LUT sizes in amdgpu_dm_atomic_check
+    - xfrm: Fix error reporting in xfrm_state_construct.
+    - wlcore/wl12xx: Fix wl12xx get_mac error if device is in ELP
+    - wl1251: Fix possible buffer overflow in wl1251_cmd_scan
+    - cw1200: add missing MODULE_DEVICE_TABLE
+    - bpf: Fix up register-based shifts in interpreter to silence KUBSAN
+    - mt76: mt7615: fix fixed-rate tx status reporting
+    - net: fix mistake path for netdev_features_strings
+    - net: sched: fix error return code in tcf_del_walker()
+    - drm/amdkfd: Walk through list with dqm lock hold
+    - rtl8xxxu: Fix device info for RTL8192EU devices
+    - atm: nicstar: use 'dma_free_coherent' instead of 'kfree'
+    - atm: nicstar: register the interrupt handler in the right place
+    - vsock: notify server to shutdown when client has pending signal
+    - RDMA/rxe: Don't overwrite errno from ib_umem_get()
+    - iwlwifi: mvm: don't change band on bound PHY contexts
+    - iwlwifi: pcie: free IML DMA memory allocation
+    - iwlwifi: pcie: fix context info freeing
+    - sfc: avoid double pci_remove of VFs
+    - sfc: error code if SRIOV cannot be disabled
+    - wireless: wext-spy: Fix out-of-bounds warning
+    - media, bpf: Do not copy more entries than user space requested
+    - net: ip: avoid OOM kills with large UDP sends over loopback
+    - RDMA/cma: Fix rdma_resolve_route() memory leak
+    - Bluetooth: btusb: Fixed too many in-token issue for Mediatek Chip.
+    - Bluetooth: Fix the HCI to MGMT status conversion table
+    - Bluetooth: Shutdown controller after workqueues are flushed or cancelled
+    - Bluetooth: btusb: fix bt fiwmare downloading failure issue for qca btsoc.
+    - sctp: validate from_addr_param return
+    - sctp: add size validation when walking chunks
+    - MIPS: loongsoon64: Reserve memory below starting pfn to prevent Oops
+    - MIPS: set mips32r5 for virt extensions
+    - fscrypt: don't ignore minor_hash when hash is 0
+    - crypto: ccp - Annotate SEV Firmware file names
+    - perf bench: Fix 2 memory sanitizer warnings
+    - powerpc/mm: Fix lockup on kernel exec fault
+    - powerpc/barrier: Avoid collision with clang's __lwsync macro
+    - drm/amdgpu: Update NV SIMD-per-CU to 2
+    - drm/radeon: Add the missed drm_gem_object_put() in
+      radeon_user_framebuffer_create()
+    - drm/rockchip: dsi: remove extra component_del() call
+    - drm/amd/display: fix incorrrect valid irq check
+    - pinctrl/amd: Add device HID for new AMD GPIO controller
+    - drm/tegra: Don't set allow_fb_modifiers explicitly
+    - drm/msm/mdp4: Fix modifier support enabling
+    - drm/arm/malidp: Always list modifiers
+    - mmc: sdhci: Fix warning message when accessing RPMB in HS400 mode
+    - mmc: core: clear flags before allowing to retune
+    - mmc: core: Allow UHS-I voltage switch for SDSC cards if supported
+    - ata: ahci_sunxi: Disable DIPM
+    - cpu/hotplug: Cure the cpusets trainwreck
+    - clocksource/arm_arch_timer: Improve Allwinner A64 timer workaround
+    - fpga: stratix10-soc: Add missing fpga_mgr_free() call
+    - MIPS: fix "mipsel-linux-ld: decompress.c:undefined reference to `memmove'"
+    - ASoC: tegra: Set driver_name=tegra for all machine drivers
+    - qemu_fw_cfg: Make fw_cfg_rev_attr a proper kobj_attribute
+    - ipmi/watchdog: Stop watchdog timer when the current action is 'none'
+    - thermal/drivers/int340x/processor_thermal: Fix tcc setting
+    - ubifs: Fix races between xattr_{set|get} and listxattr operations
+    - power: supply: ab8500: Fix an old bug
+    - nvmem: core: add a missing of_node_put
+    - extcon: intel-mrfld: Sync hardware and software state on init
+    - seq_buf: Fix overflow in seq_buf_putmem_hex()
+    - rq-qos: fix missed wake-ups in rq_qos_throttle try two
+    - tracing: Simplify & fix saved_tgids logic
+    - tracing: Resize tgid_map to pid_max, not PID_MAX_DEFAULT
+    - ipack/carriers/tpci200: Fix a double free in tpci200_pci_probe
+    - coresight: tmc-etf: Fix global-out-of-bounds in tmc_update_etf_buffer()
+    - dm btree remove: assign new_root only when removal succeeds
+    - PCI: Leave Apple Thunderbolt controllers on for s2idle or standby
+    - PCI: aardvark: Fix checking for PIO Non-posted Request
+    - PCI: aardvark: Implement workaround for the readback value of VEND_ID
+    - media: subdev: disallow ioctl for saa6588/davinci
+    - media: dtv5100: fix control-request directions
+    - media: zr364xx: fix memory leak in zr364xx_start_readpipe
+    - media: gspca/sq905: fix control-request direction
+    - media: gspca/sunplus: fix zero-length control requests
+    - pinctrl: mcp23s08: Fix missing unlock on error in mcp23s08_irq()
+    - jfs: fix GPF in diFree
+    - smackfs: restrict bytes count in smk_set_cipso()
+    - Linux 5.4.133
+  * Focal update: v5.4.132 upstream stable release (LP: #1938199)
+    - ALSA: usb-audio: fix rate on Ozone Z90 USB headset
+    - ALSA: usb-audio: Fix OOB access at proc output
+    - ALSA: usb-audio: scarlett2: Fix wrong resume call
+    - ALSA: intel8x0: Fix breakage at ac97 clock measurement
+    - ALSA: hda/realtek: Add another ALC236 variant support
+    - ALSA: hda/realtek: Improve fixup for HP Spectre x360 15-df0xxx
+    - ALSA: hda/realtek: Fix bass speaker DAC mapping for Asus UM431D
+    - ALSA: hda/realtek: Apply LED fixup for HP Dragonfly G1, too
+    - media: dvb-usb: fix wrong definition
+    - Input: usbtouchscreen - fix control-request directions
+    - net: can: ems_usb: fix use-after-free in ems_usb_disconnect()
+    - usb: gadget: eem: fix echo command packet response issue
+    - USB: cdc-acm: blacklist Heimann USB Appset device
+    - usb: dwc3: Fix debugfs creation flow
+    - usb: typec: Add the missed altmode_id_remove() in typec_register_altmode()
+    - xhci: solve a double free problem while doing s4
+    - ntfs: fix validity check for file name attribute
+    - copy_page_to_iter(): fix ITER_DISCARD case
+    - iov_iter_fault_in_readable() should do nothing in xarray case
+    - Input: joydev - prevent use of not validated data in JSIOCSBTNMAP ioctl
+    - arm_pmu: Fix write counter incorrect in ARMv7 big-endian mode
+    - ARM: dts: at91: sama5d4: fix pinctrl muxing
+    - btrfs: send: fix invalid path for unlink operations after parent
+      orphanization
+    - btrfs: clear defrag status of a root if starting transaction fails
+    - ext4: cleanup in-core orphan list if ext4_truncate() failed to get a
+      transaction handle
+    - ext4: fix kernel infoleak via ext4_extent_header
+    - ext4: return error code when ext4_fill_flex_info() fails
+    - ext4: correct the cache_nr in tracepoint ext4_es_shrink_exit
+    - ext4: remove check for zero nr_to_scan in ext4_es_scan()
+    - ext4: fix avefreec in find_group_orlov
+    - ext4: use ext4_grp_locked_error in mb_find_extent
+    - can: gw: synchronize rcu operations before removing gw job entry
+    - can: j1939: j1939_sk_init(): set SOCK_RCU_FREE to call sk_destruct() after
+      RCU is done
+    - can: peak_pciefd: pucan_handle_status(): fix a potential starvation issue in
+      TX path
+    - mac80211: remove iwlwifi specific workaround that broke sta NDP tx
+    - SUNRPC: Fix the batch tasks count wraparound.
+    - SUNRPC: Should wake up the privileged task firstly.
+    - perf/smmuv3: Don't trample existing events with global filter
+    - KVM: PPC: Book3S HV: Workaround high stack usage with clang
+    - s390/cio: dont call css_wait_for_slow_path() inside a lock
+    - rtc: stm32: Fix unbalanced clk_disable_unprepare() on probe error path
+    - iio: light: tcs3472: do not free unallocated IRQ
+    - iio: ltr501: mark register holding upper 8 bits of ALS_DATA{0,1} and PS_DATA
+      as volatile, too
+    - iio: ltr501: ltr559: fix initialization of LTR501_ALS_CONTR
+    - iio: ltr501: ltr501_read_ps(): add missing endianness conversion
+    - serial: mvebu-uart: fix calculation of clock divisor
+    - serial: sh-sci: Stop dmaengine transfer in sci_stop_tx()
+    - serial_cs: Add Option International GSM-Ready 56K/ISDN modem
+    - serial_cs: remove wrong GLOBETROTTER.cis entry
+    - ath9k: Fix kernel NULL pointer dereference during ath_reset_internal()
+    - ssb: sdio: Don't overwrite const buffer if block_write fails
+    - rsi: Assign beacon rate settings to the correct rate_info descriptor field
+    - rsi: fix AP mode with WPA failure due to encrypted EAPOL
+    - tracing/histograms: Fix parsing of "sym-offset" modifier
+    - tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing
+    - seq_buf: Make trace_seq_putmem_hex() support data longer than 8
+    - powerpc/stacktrace: Fix spurious "stale" traces in raise_backtrace_ipi()
+    - evm: Execute evm_inode_init_security() only when an HMAC key is loaded
+    - evm: Refuse EVM_ALLOW_METADATA_WRITES only if an HMAC key is loaded
+    - fuse: ignore PG_workingset after stealing
+    - fuse: check connected before queueing on fpq->io
+    - fuse: reject internal errno
+    - spi: Make of_register_spi_device also set the fwnode
+    - media: mdk-mdp: fix pm_runtime_get_sync() usage count
+    - media: s5p: fix pm_runtime_get_sync() usage count
+    - media: sh_vou: fix pm_runtime_get_sync() usage count
+    - media: mtk-vcodec: fix PM runtime get logic
+    - media: s5p-jpeg: fix pm_runtime_get_sync() usage count
+    - media: sti/bdisp: fix pm_runtime_get_sync() usage count
+    - media: exynos-gsc: fix pm_runtime_get_sync() usage count
+    - spi: spi-loopback-test: Fix 'tx_buf' might be 'rx_buf'
+    - spi: spi-topcliff-pch: Fix potential double free in
+      pch_spi_process_messages()
+    - spi: omap-100k: Fix the length judgment problem
+    - regulator: uniphier: Add missing MODULE_DEVICE_TABLE
+    - hwrng: exynos - Fix runtime PM imbalance on error
+    - crypto: nx - add missing MODULE_DEVICE_TABLE
+    - media: sti: fix obj-$(config) targets
+    - media: cpia2: fix memory leak in cpia2_usb_probe
+    - media: cobalt: fix race condition in setting HPD
+    - media: pvrusb2: fix warning in pvr2_i2c_core_done
+    - media: imx: imx7_mipi_csis: Fix logging of only error event counters
+    - crypto: qat - check return code of qat_hal_rd_rel_reg()
+    - crypto: qat - remove unused macro in FW loader
+    - sched/fair: Fix ascii art by relpacing tabs
+    - media: em28xx: Fix possible memory leak of em28xx struct
+    - media: v4l2-core: Avoid the dangling pointer in v4l2_fh_release
+    - media: bt8xx: Fix a missing check bug in bt878_probe
+    - media: st-hva: Fix potential NULL pointer dereferences
+    - Makefile: fix GDB warning with CONFIG_RELR
+    - media: dvd_usb: memory leak in cinergyt2_fe_attach
+    - memstick: rtsx_usb_ms: fix UAF
+    - mmc: sdhci-sprd: use sdhci_sprd_writew
+    - mmc: via-sdmmc: add a check against NULL pointer dereference
+    - crypto: shash - avoid comparing pointers to exported functions under CFI
+    - media: dvb_net: avoid speculation from net slot
+    - media: siano: fix device register error path
+    - media: imx-csi: Skip first few frames from a BT.656 source
+    - hwmon: (max31790) Report correct current pwm duty cycles
+    - hwmon: (max31790) Fix pwmX_enable attributes
+    - drivers/perf: fix the missed ida_simple_remove() in ddr_perf_probe()
+    - KVM: PPC: Book3S HV: Fix TLB management on SMT8 POWER9 and POWER10
+      processors
+    - btrfs: fix error handling in __btrfs_update_delayed_inode
+    - btrfs: abort transaction if we fail to update the delayed inode
+    - btrfs: disable build on platforms having page size 256K
+    - locking/lockdep: Fix the dep path printing for backwards BFS
+    - lockding/lockdep: Avoid to find wrong lock dep path in check_irq_usage()
+    - KVM: s390: get rid of register asm usage
+    - regulator: mt6358: Fix vdram2 .vsel_mask
+    - regulator: da9052: Ensure enough delay time for .set_voltage_time_sel
+    - media: Fix Media Controller API config checks
+    - HID: do not use down_interruptible() when unbinding devices
+    - EDAC/ti: Add missing MODULE_DEVICE_TABLE
+    - ACPI: processor idle: Fix up C-state latency if not ordered
+    - hv_utils: Fix passing zero to 'PTR_ERR' warning
+    - lib: vsprintf: Fix handling of number field widths in vsscanf
+    - ACPI: EC: Make more Asus laptops use ECDT _GPE
+    - block_dump: remove block_dump feature in mark_inode_dirty()
+    - fs: dlm: cancel work sync othercon
+    - random32: Fix implicit truncation warning in prandom_seed_state()
+    - fs: dlm: fix memory leak when fenced
+    - ACPICA: Fix memory leak caused by _CID repair function
+    - ACPI: bus: Call kobject_put() in acpi_init() error path
+    - block: fix race between adding/removing rq qos and normal IO
+    - platform/x86: toshiba_acpi: Fix missing error code in
+      toshiba_acpi_setup_keyboard()
+    - nvmet-fc: do not check for invalid target port in nvmet_fc_handle_fcp_rqst()
+    - EDAC/Intel: Do not load EDAC driver when running as a guest
+    - PCI: hv: Add check for hyperv_initialized in init_hv_pci_drv()
+    - clocksource: Retry clock read if long delays detected
+    - ACPI: tables: Add custom DSDT file as makefile prerequisite
+    - HID: wacom: Correct base usage for capacitive ExpressKey status bits
+    - cifs: fix missing spinlock around update to ses->status
+    - block: fix discard request merge
+    - kthread_worker: fix return value when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - ia64: mca_drv: fix incorrect array size calculation
+    - writeback, cgroup: increment isw_nr_in_flight before grabbing an inode
+    - media: s5p_cec: decrement usage count if disabled
+    - crypto: ixp4xx - dma_unmap the correct address
+    - crypto: ux500 - Fix error return code in hash_hw_final()
+    - sata_highbank: fix deferred probing
+    - pata_rb532_cf: fix deferred probing
+    - media: I2C: change 'RST' to "RSET" to fix multiple build errors
+    - sched/uclamp: Fix wrong implementation of cpu.uclamp.min
+    - sched/uclamp: Fix locking around cpu_util_update_eff()
+    - kbuild: run the checker after the compiler
+    - kbuild: Fix objtool dependency for 'OBJECT_FILES_NON_STANDARD_<obj> := n'
+    - pata_octeon_cf: avoid WARN_ON() in ata_host_activate()
+    - evm: fix writing <securityfs>/evm overflow
+    - crypto: ccp - Fix a resource leak in an error handling path
+    - media: rc: i2c: Fix an error message
+    - pata_ep93xx: fix deferred probing
+    - media: exynos4-is: Fix a use after free in isp_video_release
+    - media: au0828: fix a NULL vs IS_ERR() check
+    - media: tc358743: Fix error return code in tc358743_probe_of()
+    - media: gspca/gl860: fix zero-length control requests
+    - m68k: atari: Fix ATARI_KBD_CORE kconfig unmet dependency warning
+    - media: siano: Fix out-of-bounds warnings in smscore_load_firmware_family2()
+    - crypto: nitrox - fix unchecked variable in nitrox_register_interrupts
+    - crypto: omap-sham - Fix PM reference leak in omap sham ops
+    - mmc: usdhi6rol0: fix error return code in usdhi6_probe()
+    - arm64: consistently use reserved_pg_dir
+    - arm64/mm: Fix ttbr0 values stored in struct thread_info for software-pan
+    - media: s5p-g2d: Fix a memory leak on ctx->fh.m2m_ctx
+    - hwmon: (max31722) Remove non-standard ACPI device IDs
+    - hwmon: (max31790) Fix fan speed reporting for fan7..12
+    - KVM: nVMX: Ensure 64-bit shift when checking VMFUNC bitmap
+    - regulator: hi655x: Fix pass wrong pointer to config.driver_data
+    - btrfs: clear log tree recovering status if starting transaction fails
+    - sched/rt: Fix RT utilization tracking during policy change
+    - sched/rt: Fix Deadline utilization tracking during policy change
+    - sched/uclamp: Fix uclamp_tg_restrict()
+    - spi: spi-sun6i: Fix chipselect/clock bug
+    - crypto: nx - Fix RCU warning in nx842_OF_upd_status
+    - ACPI: sysfs: Fix a buffer overrun problem with description_show()
+    - extcon: extcon-max8997: Fix IRQ freeing at error path
+    - blk-wbt: introduce a new disable state to prevent false positive by
+      rwb_enabled()
+    - blk-wbt: make sure throttle is enabled properly
+    - ACPI: Use DEVICE_ATTR_<RW|RO|WO> macros
+    - ACPI: bgrt: Fix CFI violation
+    - cpufreq: Make cpufreq_online() call driver->offline() on errors
+    - ocfs2: fix snprintf() checking
+    - dax: fix ENOMEM handling in grab_mapping_entry()
+    - xfrm: xfrm_state_mtu should return at least 1280 for ipv6
+    - video: fbdev: imxfb: Fix an error message
+    - net: mvpp2: Put fwnode in error case during ->probe()
+    - net: pch_gbe: Propagate error from devm_gpio_request_one()
+    - pinctrl: renesas: r8a7796: Add missing bias for PRESET# pin
+    - pinctrl: renesas: r8a77990: JTAG pins do not have pull-down capabilities
+    - clk: meson: g12a: fix gp0 and hifi ranges
+    - net: ftgmac100: add missing error return code in ftgmac100_probe()
+    - drm/rockchip: cdn-dp-core: add missing clk_disable_unprepare() on error in
+      cdn_dp_grf_write()
+    - drm/rockchip: dsi: move all lane config except LCDC mux to bind()
+    - ehea: fix error return code in ehea_restart_qps()
+    - net/sched: act_vlan: Fix modify to allow 0
+    - RDMA/core: Sanitize WQ state received from the userspace
+    - RDMA/rxe: Fix failure during driver load
+    - drm: qxl: ensure surf.data is ininitialized
+    - tools/bpftool: Fix error return code in do_batch()
+    - ath10k: go to path err_unsupported when chip id is not supported
+    - ath10k: add missing error return code in ath10k_pci_probe()
+    - wireless: carl9170: fix LEDS build errors & warnings
+    - ieee802154: hwsim: Fix possible memory leak in hwsim_subscribe_all_others
+    - wcn36xx: Move hal_buf allocation to devm_kmalloc in probe
+    - ssb: Fix error return code in ssb_bus_scan()
+    - brcmfmac: fix setting of station info chains bitmask
+    - brcmfmac: correctly report average RSSI in station info
+    - brcmsmac: mac80211_if: Fix a resource leak in an error handling path
+    - ath10k: Fix an error code in ath10k_add_interface()
+    - netlabel: Fix memory leak in netlbl_mgmt_add_common
+    - RDMA/mlx5: Don't add slave port to unaffiliated list
+    - netfilter: nft_exthdr: check for IPv6 packet before further processing
+    - netfilter: nft_osf: check for TCP packet before further processing
+    - netfilter: nft_tproxy: restrict support to TCP and UDP transport protocols
+    - RDMA/rxe: Fix qp reference counting for atomic ops
+    - samples/bpf: Fix the error return code of xdp_redirect's main()
+    - net: ethernet: aeroflex: fix UAF in greth_of_remove
+    - net: ethernet: ezchip: fix UAF in nps_enet_remove
+    - net: ethernet: ezchip: fix error handling
+    - vrf: do not push non-ND strict packets with a source LLA through packet taps
+      again
+    - net: sched: add barrier to ensure correct ordering for lockless qdisc
+    - tls: prevent oversized sendfile() hangs by ignoring MSG_MORE
+    - pkt_sched: sch_qfq: fix qfq_change_class() error path
+    - vxlan: add missing rcu_read_lock() in neigh_reduce()
+    - net/ipv4: swap flow ports when validating source
+    - tc-testing: fix list handling
+    - ieee802154: hwsim: Fix memory leak in hwsim_add_one
+    - ieee802154: hwsim: avoid possible crash in hwsim_del_edge_nl()
+    - mac80211: remove iwlwifi specific workaround NDPs of null_response
+    - net: bcmgenet: Fix attaching to PYH failed on RPi 4B
+    - ipv6: exthdrs: do not blindly use init_net
+    - bpf: Do not change gso_size during bpf_skb_change_proto()
+    - i40e: Fix error handling in i40e_vsi_open
+    - i40e: Fix autoneg disabling for non-10GBaseT links
+    - Revert "ibmvnic: remove duplicate napi_schedule call in open function"
+    - ibmvnic: free tx_pool if tso_pool alloc fails
+    - ipv6: fix out-of-bound access in ip6_parse_tlv()
+    - e1000e: Check the PCIm state
+    - bpfilter: Specify the log level for the kmsg message
+    - gve: Fix swapped vars when fetching max queues
+    - Revert "be2net: disable bh with spin_lock in be_process_mcc"
+    - Bluetooth: mgmt: Fix slab-out-of-bounds in tlv_data_is_valid
+    - Bluetooth: Fix handling of HCI_LE_Advertising_Set_Terminated event
+    - clk: actions: Fix UART clock dividers on Owl S500 SoC
+    - clk: actions: Fix SD clocks factor table on Owl S500 SoC
+    - clk: actions: Fix bisp_factor_table based clocks on Owl S500 SoC
+    - clk: si5341: Avoid divide errors due to bogus register contents
+    - clk: si5341: Update initialization magic
+    - writeback: fix obtain a reference to a freeing memcg css
+    - net: lwtunnel: handle MTU calculation in forwading
+    - net: sched: fix warning in tcindex_alloc_perfect_hash
+    - RDMA/mlx5: Don't access NULL-cleared mpi pointer
+    - MIPS: Fix PKMAP with 32-bit MIPS huge page support
+    - staging: fbtft: Rectify GPIO handling
+    - rcu: Invoke rcu_spawn_core_kthreads() from rcu_spawn_gp_kthread()
+    - tty: nozomi: Fix a resource leak in an error handling function
+    - mwifiex: re-fix for unaligned accesses
+    - iio: adis_buffer: do not return ints in irq handlers
+    - iio: adis16400: do not return ints in irq handlers
+    - iio: accel: bma180: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: bma220: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: hid: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: kxcjk-1013: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio:accel:mxc4005: Drop unnecessary explicit casts in regmap_bulk_read calls
+    - iio: accel: mxc4005: Fix overread of data and alignment issue.
+    - iio: accel: stk8312: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: stk8ba50: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads1015: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: vf610: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: gyro: bmg160: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: humidity: am2315: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: srf08: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: pulsed-light: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: as3935: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: hmc5843: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: bmc150: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: isl29125: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3414: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3472: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: cros_ec_sensors: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: potentiostat: lmp91000: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: rk3328: fix missing clk_disable_unprepare() on error in
+      rk3328_platform_probe()
+    - ASoC: hisilicon: fix missing clk_disable_unprepare() on error in
+      hi6210_i2s_startup()
+    - backlight: lm3630a_bl: Put fwnode in error case during ->probe()
+    - ASoC: rsnd: tidyup loop on rsnd_adg_clk_query()
+    - Input: hil_kbd - fix error return code in hil_dev_connect()
+    - mtd: partitions: redboot: seek fis-index-block in the right node
+    - char: pcmcia: error out if 'num_bytes_read' is greater than 4 in
+      set_protocol()
+    - firmware: stratix10-svc: Fix a resource leak in an error handling path
+    - tty: nozomi: Fix the error handling path of 'nozomi_card_init()'
+    - leds: lm3532: select regmap I2C API
+    - leds: lm36274: cosmetic: rename lm36274_data to chip
+    - leds: lm3692x: Put fwnode in any case during ->probe()
+    - scsi: FlashPoint: Rename si_flags field
+    - fsi: core: Fix return of error values on failures
+    - fsi: scom: Reset the FSI2PIB engine for any error
+    - fsi: occ: Don't accept response from un-initialized OCC
+    - fsi/sbefifo: Clean up correct FIFO when receiving reset request from SBE
+    - fsi/sbefifo: Fix reset timeout
+    - visorbus: fix error return code in visorchipset_init()
+    - s390: appldata depends on PROC_SYSCTL
+    - iommu/dma: Fix IOVA reserve dma ranges
+    - ASoC: mediatek: mtk-btcvsd: Fix an error handling path in
+      'mtk_btcvsd_snd_probe()'
+    - usb: gadget: f_fs: Fix setting of device and driver data cross-references
+    - usb: dwc2: Don't reset the core after setting turnaround time
+    - eeprom: idt_89hpesx: Put fwnode in matching case during ->probe()
+    - eeprom: idt_89hpesx: Restore printing the unsupported fwnode name
+    - iio: at91-sama5d2_adc: remove usage of iio_priv_to_dev() helper
+    - iio: adc: at91-sama5d2: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: hx711: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: mxs-lradc: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads8688: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: rm3100: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - staging: gdm724x: check for buffer overflow in gdm_lte_multi_sdu_pkt()
+    - staging: gdm724x: check for overflow in gdm_lte_netif_rx()
+    - staging: rtl8712: remove redundant check in r871xu_drv_init
+    - staging: rtl8712: fix memory leak in rtl871x_load_fw_cb
+    - staging: mt7621-dts: fix pci address for PCI memory range
+    - serial: 8250: Actually allow UPF_MAGIC_MULTIPLIER baud rates
+    - iio: light: vcnl4035: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: isl29501: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: cs42l42: Correct definition of CS42L42_ADC_PDN_MASK
+    - of: Fix truncation of memory sizes on 32-bit platforms
+    - mtd: rawnand: marvell: add missing clk_disable_unprepare() on error in
+      marvell_nfc_resume()
+    - scsi: mpt3sas: Fix error return value in _scsih_expander_add()
+    - soundwire: stream: Fix test for DP prepare complete
+    - phy: uniphier-pcie: Fix updating phy parameters
+    - phy: ti: dm816x: Fix the error handling path in 'dm816x_usb_phy_probe()
+    - extcon: sm5502: Drop invalid register write in sm5502_reg_data
+    - extcon: max8997: Add missing modalias string
+    - ASoC: atmel-i2s: Fix usage of capture and playback at the same time
+    - configfs: fix memleak in configfs_release_bin_file
+    - leds: as3645a: Fix error return code in as3645a_parse_node()
+    - leds: ktd2692: Fix an error handling path
+    - powerpc: Offline CPU in stop_this_cpu()
+    - serial: mvebu-uart: do not allow changing baudrate when uartclk is not
+      available
+    - serial: mvebu-uart: correctly calculate minimal possible baudrate
+    - arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
+    - vfio/pci: Handle concurrent vma faults
+    - mm/huge_memory.c: don't discard hugepage if other processes are mapping it
+    - mm/z3fold: fix potential memory leak in z3fold_destroy_pool()
+    - selftests/vm/pkeys: fix alloc_random_pkey() to make it really, really random
+    - perf llvm: Return -ENOMEM when asprintf() fails
+    - scsi: target: cxgbit: Unmap DMA buffer before calling target_execute_cmd()
+    - mmc: block: Disable CMDQ on the ioctl path
+    - mmc: vub3000: fix control-request direction
+    - scsi: core: Retry I/O for Notify (Enable Spinup) Required error
+    - iommu/dma: Fix compile warning in 32-bit builds
+    - Linux 5.4.132
+  * Keyboard not working (LP: #1909814) // Focal update: v5.4.132 upstream
+    stable release (LP: #1938199)
+    - ACPI: resources: Add checks for ACPI IRQ override
+  * Focal update: v5.4.131 upstream stable release (LP: #1936245)
+    - KVM: SVM: Periodically schedule when unregistering regions on destroy
+    - s390/stack: fix possible register corruption with stack switch helper
+    - KVM: SVM: Call SEV Guest Decommission if ASID binding fails
+    - xen/events: reset active flag for lateeoi events later
+    - Linux 5.4.131
+  * Focal update: v5.4.130 upstream stable release (LP: #1936244)
+    - scsi: sr: Return appropriate error code when disk is ejected
+    - drm/nouveau: fix dma_address check for CPU/GPU sync
+    - gpio: AMD8111 and TQMX86 require HAS_IOPORT_MAP
+    - RDMA/mlx5: Block FDB rules when not in switchdev mode
+    - Linux 5.4.130
+  * Focal update: v5.4.129 upstream stable release (LP: #1936242)
+    - module: limit enabling module.sig_enforce
+    - drm/nouveau: wait for moving fence after pinning v2
+    - drm/radeon: wait for moving fence after pinning
+    - ARM: 9081/1: fix gcc-10 thumb2-kernel regression
+    - mmc: meson-gx: use memcpy_to/fromio for dram-access-quirk
+    - kbuild: add CONFIG_LD_IS_LLD
+    - arm64: link with -z norelro for LLD or aarch64-elf
+    - MIPS: generic: Update node names to avoid unit addresses
+    - spi: spi-nxp-fspi: move the register operation after the clock enable
+    - Revert "PCI: PM: Do not read power state in pci_enable_device_flags()"
+    - dmaengine: zynqmp_dma: Fix PM reference leak in
+      zynqmp_dma_alloc_chan_resourc()
+    - mac80211: remove warning in ieee80211_get_sband()
+    - mac80211_hwsim: drop pending frames on stop
+    - cfg80211: call cfg80211_leave_ocb when switching away from OCB
+    - dmaengine: rcar-dmac: Fix PM reference leak in rcar_dmac_probe()
+    - dmaengine: mediatek: free the proper desc in desc_free handler
+    - dmaengine: mediatek: do not issue a new desc if one is still current
+    - dmaengine: mediatek: use GFP_NOWAIT instead of GFP_ATOMIC in prep_dma
+    - net: ipv4: Remove unneed BUG() function
+    - mac80211: drop multicast fragments
+    - net: ethtool: clear heap allocations for ethtool function
+    - ping: Check return value of function 'ping_queue_rcv_skb'
+    - inet: annotate date races around sk->sk_txhash
+    - net: phy: dp83867: perform soft reset and retain established link
+    - net: caif: fix memory leak in ldisc_open
+    - net/packet: annotate accesses to po->bind
+    - net/packet: annotate accesses to po->ifindex
+    - r8152: Avoid memcpy() over-reading of ETH_SS_STATS
+    - sh_eth: Avoid memcpy() over-reading of ETH_SS_STATS
+    - r8169: Avoid memcpy() over-reading of ETH_SS_STATS
+    - KVM: selftests: Fix kvm_check_cap() assertion
+    - net: qed: Fix memcpy() overflow of qed_dcbx_params()
+    - recordmcount: Correct st_shndx handling
+    - PCI: Add AMD RS690 quirk to enable 64-bit DMA
+    - net: ll_temac: Add memory-barriers for TX BD access
+    - net: ll_temac: Avoid ndo_start_xmit returning NETDEV_TX_BUSY
+    - pinctrl: stm32: fix the reported number of GPIO lines per bank
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_device_group
+    - KVM: do not allow mapping valid but non-reference-counted pages
+    - i2c: robotfuzz-osif: fix control-request directions
+    - kthread_worker: split code for canceling the delayed work timer
+    - kthread: prevent deadlock when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - mm: add VM_WARN_ON_ONCE_PAGE() macro
+    - mm/rmap: remove unneeded semicolon in page_not_mapped()
+    - mm/rmap: use page_not_mapped in try_to_unmap()
+    - mm, thp: use head page in __migration_entry_wait()
+    - mm/thp: fix __split_huge_pmd_locked() on shmem migration entry
+    - mm/thp: make is_huge_zero_pmd() safe and quicker
+    - mm/thp: try_to_unmap() use TTU_SYNC for safe splitting
+    - mm/thp: fix vma_address() if virtual address below file offset
+    - mm/thp: fix page_address_in_vma() on file THP tails
+    - mm/thp: unmap_mapping_page() to fix THP truncate_cleanup_page()
+    - mm: thp: replace DEBUG_VM BUG with VM_WARN when unmap fails for split
+    - mm: page_vma_mapped_walk(): use page for pvmw->page
+    - mm: page_vma_mapped_walk(): settle PageHuge on entry
+    - mm: page_vma_mapped_walk(): use pmde for *pvmw->pmd
+    - mm: page_vma_mapped_walk(): prettify PVMW_MIGRATION block
+    - mm: page_vma_mapped_walk(): crossing page table boundary
+    - mm: page_vma_mapped_walk(): add a level of indentation
+    - mm: page_vma_mapped_walk(): use goto instead of while (1)
+    - mm: page_vma_mapped_walk(): get vma_address_end() earlier
+    - mm/thp: fix page_vma_mapped_walk() if THP mapped by ptes
+    - mm/thp: another PVMW_SYNC fix in page_vma_mapped_walk()
+    - mm, futex: fix shared futex pgoff on shmem huge page
+    - [Config] enable CONFIG_SYSTEM_REVOCATION_LIST
+    - certs: Add EFI_CERT_X509_GUID support for dbx entries
+    - certs: Move load_system_certificate_list to a common function
+    - Linux 5.4.129
+  * Patch To Fix Bug in the Linux Block Layer Responsible For  Merging BIOs
+    (LP: #1931497)
+    - block: return the correct bvec when checking for gaps
+
+  [ Ubuntu: 5.4.0-81.91 ]
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+  * large_dir in ext4 broken (LP: #1933074)
+    - SAUCE: ext4: fix directory index node split corruption
+  * Some test in kselftest/net on focal source tree were not tested at all
+    (LP: #1934282)
+    - selftests/net: add missing tests to Makefile
+  * curtin: install flash-kernel in arm64 UEFI unexpected (LP: #1918427)
+    - [Packaging] Allow grub-efi-arm* to satisfy recommends on ARM
+  * Add l2tp.sh in net from ubuntu_kernel_selftests back (LP: #1934293)
+    - Revert "UBUNTU: SAUCE: selftests/net -- disable l2tp.sh test"
+  * icmp_redirect.sh in net from ubuntu_kernel_selftests failed on F-OEM-5.6 /
+    F-OEM-5.10 / F-OEM-5.13 / F / G / H (LP: #1880645)
+    - selftests: icmp_redirect: support expected failures
+  * Focal update: v5.4.128 upstream stable release (LP: #1934179)
+    - dmaengine: ALTERA_MSGDMA depends on HAS_IOMEM
+    - dmaengine: QCOM_HIDMA_MGMT depends on HAS_IOMEM
+    - dmaengine: stedma40: add missing iounmap() on error in d40_probe()
+    - afs: Fix an IS_ERR() vs NULL check
+    - mm/memory-failure: make sure wait for page writeback in memory_failure
+    - kvm: LAPIC: Restore guard to prevent illegal APIC register access
+    - batman-adv: Avoid WARN_ON timing related checks
+    - net: ipv4: fix memory leak in netlbl_cipsov4_add_std
+    - vrf: fix maximum MTU
+    - net: rds: fix memory leak in rds_recvmsg
+    - net: lantiq: disable interrupt before sheduling NAPI
+    - udp: fix race between close() and udp_abort()
+    - rtnetlink: Fix regression in bridge VLAN configuration
+    - net/sched: act_ct: handle DNAT tuple collision
+    - net/mlx5e: Remove dependency in IPsec initialization flows
+    - net/mlx5e: Fix page reclaim for dead peer hairpin
+    - net/mlx5: Consider RoCE cap before init RDMA resources
+    - net/mlx5e: allow TSO on VXLAN over VLAN topologies
+    - net/mlx5e: Block offload of outer header csum for UDP tunnels
+    - netfilter: synproxy: Fix out of bounds when parsing TCP options
+    - sch_cake: Fix out of bounds when parsing TCP options and header
+    - alx: Fix an error handling path in 'alx_probe()'
+    - net: stmmac: dwmac1000: Fix extended MAC address registers definition
+    - net: make get_net_ns return error if NET_NS is disabled
+    - qlcnic: Fix an error handling path in 'qlcnic_probe()'
+    - netxen_nic: Fix an error handling path in 'netxen_nic_probe()'
+    - net: qrtr: fix OOB Read in qrtr_endpoint_post
+    - ptp: improve max_adj check against unreasonable values
+    - net: cdc_ncm: switch to eth%d interface naming
+    - lantiq: net: fix duplicated skb in rx descriptor ring
+    - net: usb: fix possible use-after-free in smsc75xx_bind
+    - net: fec_ptp: fix issue caused by refactor the fec_devtype
+    - net: ipv4: fix memory leak in ip_mc_add1_src
+    - net/af_unix: fix a data-race in unix_dgram_sendmsg / unix_release_sock
+    - be2net: Fix an error handling path in 'be_probe()'
+    - net: hamradio: fix memory leak in mkiss_close
+    - net: cdc_eem: fix tx fixup skb leak
+    - cxgb4: fix wrong shift.
+    - bnxt_en: Rediscover PHY capabilities after firmware reset
+    - bnxt_en: Call bnxt_ethtool_free() in bnxt_init_one() error path
+    - icmp: don't send out ICMP messages with a source address of 0.0.0.0
+    - net: ethernet: fix potential use-after-free in ec_bhf_remove
+    - regulator: bd70528: Fix off-by-one for buck123 .n_voltages setting
+    - ASoC: rt5659: Fix the lost powers for the HDA header
+    - spi: stm32-qspi: Always wait BUSY bit to be cleared in stm32_qspi_wait_cmd()
+    - pinctrl: ralink: rt2880: avoid to error in calls is pin is already enabled
+    - radeon: use memcpy_to/fromio for UVD fw upload
+    - hwmon: (scpi-hwmon) shows the negative temperature properly
+    - can: bcm: fix infoleak in struct bcm_msg_head
+    - can: bcm/raw/isotp: use per module netdevice notifier
+    - can: j1939: fix Use-after-Free, hold skb ref while in use
+    - can: mcba_usb: fix memory leak in mcba_usb
+    - usb: core: hub: Disable autosuspend for Cypress CY7C65632
+    - tracing: Do not stop recording cmdlines when tracing is off
+    - tracing: Do not stop recording comms if the trace file is being read
+    - tracing: Do no increment trace_clock_global() by one
+    - PCI: Mark TI C667X to avoid bus reset
+    - PCI: Mark some NVIDIA GPUs to avoid bus reset
+    - PCI: aardvark: Don't rely on jiffies while holding spinlock
+    - PCI: aardvark: Fix kernel panic during PIO transfer
+    - PCI: Add ACS quirk for Broadcom BCM57414 NIC
+    - PCI: Work around Huawei Intelligent NIC VF FLR erratum
+    - KVM: x86: Immediately reset the MMU context when the SMM flag is cleared
+    - ARCv2: save ABI registers across signal handling
+    - x86/process: Check PF_KTHREAD and not current->mm for kernel threads
+    - x86/pkru: Write hardware init value to PKRU when xstate is init
+    - x86/fpu: Reset state for all signal restore failures
+    - dmaengine: pl330: fix wrong usage of spinlock flags in dma_cyclc
+    - cfg80211: make certificate generation more robust
+    - cfg80211: avoid double free of PMSR request
+    - net: ll_temac: Make sure to free skb when it is completely used
+    - net: ll_temac: Fix TX BD buffer overwrite
+    - net: bridge: fix vlan tunnel dst null pointer dereference
+    - net: bridge: fix vlan tunnel dst refcnt when egressing
+    - mm/slub: clarify verification reporting
+    - mm/slub: fix redzoning for small allocations
+    - mm/slub.c: include swab.h
+    - net: stmmac: disable clocks in stmmac_remove_config_dt()
+    - net: fec_ptp: add clock rate zero check
+    - tools headers UAPI: Sync linux/in.h copy with the kernel sources
+    - KVM: arm/arm64: Fix KVM_VGIC_V3_ADDR_TYPE_REDIST read
+    - ARM: OMAP: replace setup_irq() by request_irq()
+    - clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support
+    - clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
+    - clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
+    - usb: dwc3: debugfs: Add and remove endpoint dirs dynamically
+    - usb: dwc3: core: fix kernel panic when do reboot
+    - Linux 5.4.128
+  * linux-azure CIFS DFS oops (LP: #1935833)
+    - cifs: get rid of unused parameter in reconn_setup_dfs_targets()
+    - cifs: handle empty list of targets in cifs_reconnect()
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: improve the test result processing
+  * cifs: On cifs_reconnect, resolve the hostname again (LP: #1929831)
+    - cifs: rename reconn_inval_dfs_target()
+    - cifs: Simplify reconnect code when dfs upcall is enabled
+    - cifs: Avoid error pointer dereference
+    - cifs: On cifs_reconnect, resolve the hostname again.
+  * Pixel format change broken for Elgato Cam Link 4K (LP: #1932367)
+    - (upstream) media: uvcvideo: Fix pixel format change for Elgato Cam Link 4K
+  * Focal update: v5.4.127 upstream stable release (LP: #1933851)
+    - net: ieee802154: fix null deref in parse dev addr
+    - HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for Saitek X65
+    - HID: hid-input: add mapping for emoji picker key
+    - HID: hid-sensor-hub: Return error for hid_set_field() failure
+    - HID: quirks: Add quirk for Lenovo optical mouse
+    - HID: multitouch: set Stylus suffix for Stylus-application devices, too
+    - HID: Add BUS_VIRTUAL to hid_connect logging
+    - HID: usbhid: fix info leak in hid_submit_ctrl
+    - drm/tegra: sor: Do not leak runtime PM reference
+    - ARM: OMAP2+: Fix build warning when mmc_omap is not built
+    - gfs2: Prevent direct-I/O write fallback errors from getting lost
+    - HID: gt683r: add missing MODULE_DEVICE_TABLE
+    - riscv: Use -mno-relax when using lld linker
+    - gfs2: Fix use-after-free in gfs2_glock_shrink_scan
+    - scsi: target: core: Fix warning on realtime kernels
+    - ethernet: myri10ge: Fix missing error code in myri10ge_probe()
+    - scsi: qedf: Do not put host in qedf_vport_create() unconditionally
+    - scsi: scsi_devinfo: Add blacklist entry for HPE OPEN-V
+    - nvme-loop: reset queue count to 1 in nvme_loop_destroy_io_queues()
+    - nvme-loop: clear NVME_LOOP_Q_LIVE when nvme_loop_configure_admin_queue()
+      fails
+    - nvme-loop: check for NVME_LOOP_Q_LIVE in nvme_loop_destroy_admin_queue()
+    - net: ipconfig: Don't override command-line hostnames or domains
+    - drm/amd/display: Allow bandwidth validation for 0 streams.
+    - rtnetlink: Fix missing error code in rtnl_bridge_notify()
+    - net/x25: Return the correct errno code
+    - net: Return the correct errno code
+    - fib: Return the correct errno code
+    - Linux 5.4.127
+  * Focal update: v5.4.126 upstream stable release (LP: #1933369)
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - proc: Track /proc/$pid/attr/ opener mm_struct
+    - ASoC: max98088: fix ni clock divider calculation
+    - spi: Fix spi device unregister flow
+    - net/nfc/rawsock.c: fix a permission check bug
+    - usb: cdns3: Fix runtime PM imbalance on error
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Glavey TM800A550L tablet
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Lenovo Miix 3-830 tablet
+    - vfio-ccw: Serialize FSM IDLE state with I/O completion
+    - ASoC: sti-sas: add missing MODULE_DEVICE_TABLE
+    - spi: sprd: Add missing MODULE_DEVICE_TABLE
+    - isdn: mISDN: netjet: Fix crash in nj_probe:
+    - bonding: init notify_work earlier to avoid uninitialized use
+    - netlink: disable IRQs for netlink_lock_table()
+    - net: mdiobus: get rid of a BUG_ON()
+    - cgroup: disable controllers at parse time
+    - wq: handle VM suspension in stall detection
+    - net/qla3xxx: fix schedule while atomic in ql_sem_spinlock
+    - RDS tcp loopback connection can hang
+    - scsi: bnx2fc: Return failure if io_req is already in ABTS processing
+    - scsi: vmw_pvscsi: Set correct residual data length
+    - scsi: hisi_sas: Drop free_irq() of devm_request_irq() allocated irq
+    - scsi: target: qla2xxx: Wait for stop_phase1 at WWN removal
+    - net: macb: ensure the device is available before accessing GEMGXL control
+      registers
+    - net: appletalk: cops: Fix data race in cops_probe1
+    - net: dsa: microchip: enable phy errata workaround on 9567
+    - nvme-fabrics: decode host pathing error for connect
+    - MIPS: Fix kernel hang under FUNCTION_GRAPH_TRACER and PREEMPT_TRACER
+    - dm verity: fix require_signatures module_param permissions
+    - bnx2x: Fix missing error code in bnx2x_iov_init_one()
+    - nvme-tcp: remove incorrect Kconfig dep in BLK_DEV_NVME
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P2041 i2c controllers
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P1010 i2c controllers
+    - spi: Don't have controller clean up spi device before driver unbind
+    - spi: Cleanup on failure of initial setup
+    - i2c: mpc: Make use of i2c_recover_bus()
+    - i2c: mpc: implement erratum A-004447 workaround
+    - x86/boot: Add .text.* to setup.ld
+    - spi: bcm2835: Fix out-of-bounds access with more than 4 slaves
+    - drm: Fix use-after-free read in drm_getunique()
+    - drm: Lock pointer access in drm_master_release()
+    - kvm: avoid speculation-based attacks from out-of-range memslot accesses
+    - staging: rtl8723bs: Fix uninitialized variables
+    - btrfs: return value from btrfs_mark_extent_written() in case of error
+    - btrfs: promote debugging asserts to full-fledged checks in validate_super
+    - cgroup1: don't allow '\n' in renaming
+    - USB: f_ncm: ncm_bitrate (speed) is unsigned
+    - usb: f_ncm: only first packet of aggregate needs to start timer
+    - usb: pd: Set PD_T_SINK_WAIT_CAP to 310ms
+    - usb: dwc3: ep0: fix NULL pointer exception
+    - usb: musb: fix MUSB_QUIRK_B_DISCONNECT_99 handling
+    - usb: typec: wcove: Use LE to CPU conversion when accessing msg->header
+    - usb: typec: ucsi: Clear PPM capability data in ucsi_init() error path
+    - usb: gadget: f_fs: Ensure io_completion_wq is idle during unbind
+    - USB: serial: ftdi_sio: add NovaTech OrionMX product ID
+    - USB: serial: omninet: add device id for Zyxel Omni 56K Plus
+    - USB: serial: quatech2: fix control-request directions
+    - USB: serial: cp210x: fix alternate function for CP2102N QFN20
+    - usb: gadget: eem: fix wrong eem header operation
+    - usb: fix various gadgets null ptr deref on 10gbps cabling.
+    - usb: fix various gadget panics on 10gbps cabling
+    - regulator: core: resolve supply for boot-on/always-on regulators
+    - regulator: max77620: Use device_set_of_node_from_dev()
+    - usb: typec: mux: Fix copy-paste mistake in typec_mux_match
+    - RDMA/ipoib: Fix warning caused by destroying non-initial netns
+    - RDMA/mlx4: Do not map the core_clock page to user space unless enabled
+    - vmlinux.lds.h: Avoid orphan section with !SMP
+    - perf: Fix data race between pin_count increment/decrement
+    - sched/fair: Make sure to update tg contrib for blocked load
+    - KVM: x86: Ensure liveliness of nested VM-Enter fail tracepoint message
+    - IB/mlx5: Fix initializing CQ fragments buffer
+    - NFS: Fix a potential NULL dereference in nfs_get_client()
+    - NFSv4: Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()
+    - perf session: Correct buffer copying when peeking events
+    - kvm: fix previous commit for 32-bit builds
+    - NFS: Fix use-after-free in nfs4_init_client()
+    - NFSv4: Fix second deadlock in nfs4_evict_inode()
+    - NFSv4: nfs4_proc_set_acl needs to restore NFS_CAP_UIDGID_NOMAP on error.
+    - scsi: core: Fix error handling of scsi_host_alloc()
+    - scsi: core: Fix failure handling of scsi_add_host_with_dma()
+    - scsi: core: Put .shost_dev in failure path if host state changes to RUNNING
+    - scsi: core: Only put parent device if host state differs from SHOST_CREATED
+    - ftrace: Do not blindly read the ip address in ftrace_bug()
+    - tracing: Correct the length check which causes memory corruption
+    - proc: only require mm_struct for writing
+    - Linux 5.4.126
+  * Focal update: v5.4.125 upstream stable release (LP: #1932957)
+    - btrfs: tree-checker: do not error out if extent ref hash doesn't match
+    - net: usb: cdc_ncm: don't spew notifications
+    - ALSA: usb: update old-style static const declaration
+    - nl80211: validate key indexes for cfg80211_registered_device
+    - hwmon: (dell-smm-hwmon) Fix index values
+    - netfilter: conntrack: unregister ipv4 sockopts on error unwind
+    - efi: Allow EFI_MEMORY_XP and EFI_MEMORY_RO both to be cleared
+    - efi: cper: fix snprintf() use in cper_dimm_err_location()
+    - vfio/pci: Fix error return code in vfio_ecap_init()
+    - vfio/pci: zap_vma_ptes() needs MMU
+    - samples: vfio-mdev: fix error handing in mdpy_fb_probe()
+    - vfio/platform: fix module_put call in error flow
+    - ipvs: ignore IP_VS_SVC_F_HASHED flag when adding service
+    - HID: pidff: fix error return code in hid_pidff_init()
+    - HID: i2c-hid: fix format string mismatch
+    - net/sched: act_ct: Fix ct template allocation for zone 0
+    - ACPICA: Clean up context mutex during object deletion
+    - netfilter: nft_ct: skip expectations for confirmed conntrack
+    - netfilter: nfnetlink_cthelper: hit EBUSY on updates if size mismatches
+    - ieee802154: fix error return code in ieee802154_add_iface()
+    - ieee802154: fix error return code in ieee802154_llsec_getparams()
+    - ixgbevf: add correct exception tracing for XDP
+    - ipv6: Fix KASAN: slab-out-of-bounds Read in fib6_nh_flush_exceptions
+    - ice: write register with correct offset
+    - ice: Fix VFR issues for AVF drivers that expect ATQLEN cleared
+    - ice: Allow all LLDP packets from PF to Tx
+    - i2c: qcom-geni: Add shutdown callback for i2c
+    - i40e: optimize for XDP_REDIRECT in xsk path
+    - i40e: add correct exception tracing for XDP
+    - arm64: dts: ls1028a: fix memory node
+    - arm64: dts: zii-ultra: fix 12V_MAIN voltage
+    - ARM: dts: imx7d-meerkat96: Fix the 'tuning-step' property
+    - ARM: dts: imx7d-pico: Fix the 'tuning-step' property
+    - ARM: dts: imx: emcon-avari: Fix nxp,pca8574 #gpio-cells
+    - bus: ti-sysc: Fix flakey idling of uarts and stop using swsup_sidle_act
+    - tipc: add extack messages for bearer/media failure
+    - tipc: fix unique bearer names sanity check
+    - Bluetooth: fix the erroneous flush_work() order
+    - Bluetooth: use correct lock to prevent UAF of hdev object
+    - net: caif: added cfserl_release function
+    - net: caif: add proper error handling
+    - net: caif: fix memory leak in caif_device_notify
+    - net: caif: fix memory leak in cfusbl_device_notify
+    - HID: i2c-hid: Skip ELAN power-on command after reset
+    - HID: magicmouse: fix NULL-deref on disconnect
+    - HID: multitouch: require Finger field to mark Win8 reports as MT
+    - ALSA: timer: Fix master timer notification
+    - ALSA: hda: Fix for mute key LED for HP Pavilion 15-CK0xx
+    - ARM: dts: imx6dl-yapp4: Fix RGMII connection to QCA8334 switch
+    - ARM: dts: imx6q-dhcom: Add PU,VDD1P1,VDD2P5 regulators
+    - ext4: fix bug on in ext4_es_cache_extent as ext4_split_extent_at failed
+    - usb: dwc2: Fix build in periphal-only mode
+    - pid: take a reference when initializing `cad_pid`
+    - ocfs2: fix data corruption by fallocate
+    - nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+    - drm/amdgpu: Don't query CE and UE errors
+    - drm/amdgpu: make sure we unpin the UVD BO
+    - x86/apic: Mark _all_ legacy interrupts when IO/APIC is missing
+    - btrfs: mark ordered extent and inode with error if we fail to finish
+    - btrfs: fix error handling in btrfs_del_csums
+    - btrfs: return errors from btrfs_del_csums in cleanup_ref_head
+    - btrfs: fixup error handling in fixup_inode_link_counts
+    - mm, hugetlb: fix simple resv_huge_pages underflow on UFFDIO_COPY
+    - bnxt_en: Remove the setting of dev_port.
+    - mm: add thp_order
+    - XArray: add xa_get_order
+    - XArray: add xas_split
+    - mm/filemap: fix storing to a THP shadow entry
+    - btrfs: fix unmountable seed device after fstrim
+    - KVM: SVM: Truncate GPR value for DR and CR accesses in !64-bit mode
+    - KVM: arm64: Fix debug register indexing
+    - lib/lz4: explicitly support in-place decompression
+    - xen-pciback: redo VF placement in the virtual topology
+    - i2c: qcom-geni: Suspend and resume the bus during SYSTEM_SLEEP_PM ops
+    - neighbour: allow NUD_NOARP entries to be forced GCed
+    - Linux 5.4.125
+
+  [ Ubuntu: 5.4.0-80.90 ]
+
+  * CVE-2021-33909
+    - SAUCE: seq_file: Disallow extremely large seq buffer allocations
+
+  [ Ubuntu: 5.4.0-79.88 ]
+
+  * focal/linux: 5.4.0-79.88 -proposed tracker (LP: #1934343)
+  * lxd exec fails (LP: #1934187)
+    - SAUCE: Revert "proc: Check /proc/$pid/attr/ writes against file opener"
+
+  [ Ubuntu: 5.4.0-78.87 ]
+
+  * focal/linux: 5.4.0-78.87 -proposed tracker (LP: #1932478)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+    - update dkms package versions
+  * Disable hv-kvp-daemon.service on certain instance types (LP: #1932081)
+    - [Packaging]: Add kernel command line condition to hv-kvp-daemon service
+  * QLogic Direct-Connect host can't discover SCSI-FC or NVMe/FC devices
+    (LP: #1860724)
+    - scsi: qla2xxx: Serialize fc_port alloc in N2N
+    - scsi: qla2xxx: Set Nport ID for N2N
+    - scsi: qla2xxx: Fix point-to-point (N2N) device discovery issue
+    - scsi: qla2xxx: Fix N2N and NVMe connect retry failure
+  * [SRU] Add support for E810 NIC to Ice Driver in Focal (LP: #1912511)
+    - ice: add additional E810 device id
+  * Focal update: v5.4.124 upstream stable release (LP: #1931166)
+    - ALSA: hda/realtek: Headphone volume is controlled by Front mixer
+    - ALSA: usb-audio: scarlett2: Fix device hang with ehci-pci
+    - ALSA: usb-audio: scarlett2: Improve driver startup messages
+    - cifs: set server->cipher_type to AES-128-CCM for SMB3.0
+    - NFSv4: Fix a NULL pointer dereference in pnfs_mark_matching_lsegs_return()
+    - iommu/vt-d: Fix sysfs leak in alloc_iommu()
+    - perf intel-pt: Fix sample instruction bytes
+    - perf intel-pt: Fix transaction abort handling
+    - perf scripts python: exported-sql-viewer.py: Fix copy to clipboard from Top
+      Calls by elapsed Time report
+    - perf scripts python: exported-sql-viewer.py: Fix Array TypeError
+    - perf scripts python: exported-sql-viewer.py: Fix warning display
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - net: hso: fix control-request directions
+    - ath10k: Validate first subframe of A-MSDU before processing the list
+    - dm snapshot: properly fix a crash when an origin has no snapshots
+    - drm/amdgpu/vcn1: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.0: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.5: add cancel_delayed_work_sync before power gate
+    - selftests/gpio: Use TEST_GEN_PROGS_EXTENDED
+    - selftests/gpio: Move include of lib.mk up
+    - selftests/gpio: Fix build when source tree is read only
+    - kgdb: fix gcc-11 warnings harder
+    - Documentation: seccomp: Fix user notification documentation
+    - serial: core: fix suspicious security_locked_down() call
+    - misc/uss720: fix memory leak in uss720_probe
+    - thunderbolt: dma_port: Fix NVM read buffer bounds and offset issue
+    - mei: request autosuspend after sending rx flow control
+    - staging: iio: cdc: ad7746: avoid overwrite of num_channels
+    - iio: gyro: fxas21002c: balance runtime power in error path
+    - iio: adc: ad7768-1: Fix too small buffer passed to
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ad7124: Fix missbalanced regulator enable / disable on error.
+    - iio: adc: ad7124: Fix potential overflow due to non sequential channel
+      numbers
+    - iio: adc: ad7793: Add missing error code in ad7793_setup()
+    - serial: 8250_pci: Add support for new HPE serial device
+    - serial: 8250_pci: handle FL_NOIRQ board flag
+    - USB: trancevibrator: fix control-request direction
+    - USB: usbfs: Don't WARN about excessively large memory allocations
+    - serial: tegra: Fix a mask operation that is always true
+    - serial: sh-sci: Fix off-by-one error in FIFO threshold register setting
+    - serial: rp2: use 'request_firmware' instead of 'request_firmware_nowait'
+    - USB: serial: ti_usb_3410_5052: add startech.com device id
+    - USB: serial: option: add Telit LE910-S1 compositions 0x7010, 0x7011
+    - USB: serial: ftdi_sio: add IDs for IDS GmbH Products
+    - USB: serial: pl2303: add device id for ADLINK ND-6530 GC
+    - thermal/drivers/intel: Initialize RW trip to THERMAL_TEMP_INVALID
+    - usb: dwc3: gadget: Properly track pending and queued SG
+    - usb: gadget: udc: renesas_usb3: Fix a race in usb3_start_pipen()
+    - net: usb: fix memory leak in smsc75xx_bind
+    - spi: spi-geni-qcom: Fix use-after-free on unbind
+    - Bluetooth: cmtp: fix file refcount when cmtp_attach_device fails
+    - fs/nfs: Use fatal_signal_pending instead of signal_pending
+    - NFS: fix an incorrect limit in filelayout_decode_layout()
+    - NFS: Fix an Oopsable condition in __nfs_pageio_add_request()
+    - NFS: Don't corrupt the value of pg_bytes_written in nfs_do_recoalesce()
+    - NFSv4: Fix v4.0/v4.1 SEEK_DATA return -ENOTSUPP when set NFS_V4_2 config
+    - drm/meson: fix shutdown crash when component not probed
+    - net/mlx5e: Fix multipath lag activation
+    - net/mlx5e: Fix nullptr in add_vlan_push_action()
+    - net/mlx4: Fix EEPROM dump support
+    - Revert "net:tipc: Fix a double free in tipc_sk_mcast_rcv"
+    - tipc: wait and exit until all work queues are done
+    - tipc: skb_linearize the head skb when reassembling msgs
+    - spi: spi-fsl-dspi: Fix a resource leak in an error handling path
+    - net: dsa: mt7530: fix VLAN traffic leaks
+    - net: dsa: fix a crash if ->get_sset_count() fails
+    - net: dsa: sja1105: error out on unsupported PHY mode
+    - i2c: s3c2410: fix possible NULL pointer deref on read message after write
+    - i2c: i801: Don't generate an interrupt on bus reset
+    - i2c: sh_mobile: Use new clock calculation formulas for RZ/G2E
+    - perf jevents: Fix getting maximum number of fds
+    - platform/x86: hp_accel: Avoid invoking _INI to speed up resume
+    - gpio: cadence: Add missing MODULE_DEVICE_TABLE
+    - Revert "media: usb: gspca: add a missed check for goto_low_power"
+    - Revert "ALSA: sb: fix a missing check of snd_ctl_add"
+    - Revert "serial: max310x: pass return value of spi_register_driver"
+    - serial: max310x: unregister uart driver in case of failure and abort
+    - Revert "net: fujitsu: fix a potential NULL pointer dereference"
+    - net: fujitsu: fix potential null-ptr-deref
+    - Revert "net/smc: fix a NULL pointer dereference"
+    - net: caif: remove BUG_ON(dev == NULL) in caif_xmit
+    - Revert "char: hpet: fix a missing check of ioremap"
+    - char: hpet: add checks after calling ioremap
+    - Revert "ALSA: gus: add a check of the status of snd_ctl_add"
+    - Revert "ALSA: usx2y: Fix potential NULL pointer dereference"
+    - Revert "isdn: mISDNinfineon: fix potential NULL pointer dereference"
+    - isdn: mISDNinfineon: check/cleanup ioremap failure correctly in setup_io
+    - Revert "ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()"
+    - ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()
+    - Revert "isdn: mISDN: Fix potential NULL pointer dereference of kzalloc"
+    - isdn: mISDN: correctly handle ph_info allocation failure in hfcsusb_ph_info
+    - Revert "dmaengine: qcom_hidma: Check for driver register failure"
+    - dmaengine: qcom_hidma: comment platform_driver_register call
+    - Revert "libertas: add checks for the return value of sysfs_create_group"
+    - libertas: register sysfs groups properly
+    - Revert "ASoC: cs43130: fix a NULL pointer dereference"
+    - ASoC: cs43130: handle errors in cs43130_probe() properly
+    - Revert "media: dvb: Add check on sp8870_readreg"
+    - media: dvb: Add check on sp8870_readreg return
+    - Revert "media: gspca: mt9m111: Check write_bridge for timeout"
+    - media: gspca: mt9m111: Check write_bridge for timeout
+    - Revert "media: gspca: Check the return value of write_bridge for timeout"
+    - media: gspca: properly check for errors in po1030_probe()
+    - Revert "net: liquidio: fix a NULL pointer dereference"
+    - net: liquidio: Add missing null pointer checks
+    - Revert "brcmfmac: add a check for the status of usb_register"
+    - brcmfmac: properly check for bus register errors
+    - btrfs: return whole extents in fiemap
+    - scsi: BusLogic: Fix 64-bit system enumeration error for Buslogic
+    - openrisc: Define memory barrier mb
+    - btrfs: do not BUG_ON in link_to_fixup_dir
+    - platform/x86: hp-wireless: add AMD's hardware id to the supported list
+    - platform/x86: intel_punit_ipc: Append MODULE_DEVICE_TABLE for ACPI
+    - platform/x86: touchscreen_dmi: Add info for the Mediacom Winpad 7.0 W700
+      tablet
+    - SMB3: incorrect file id in requests compounded with open
+    - drm/amd/display: Disconnect non-DP with no EDID
+    - drm/amd/amdgpu: fix refcount leak
+    - drm/amdgpu: Fix a use-after-free
+    - drm/amd/amdgpu: fix a potential deadlock in gpu reset
+    - net: netcp: Fix an error message
+    - net: dsa: fix error code getting shifted with 4 in dsa_slave_get_sset_count
+    - ASoC: cs42l42: Regmap must use_single_read/write
+    - vfio-ccw: Check initialized flag in cp_init()
+    - net: really orphan skbs tied to closing sk
+    - net: fec: fix the potential memory leak in fec_enet_init()
+    - net: mdio: thunder: Fix a double free issue in the .remove function
+    - net: mdio: octeon: Fix some double free issues
+    - openvswitch: meter: fix race when getting now_ms.
+    - tls splice: check SPLICE_F_NONBLOCK instead of MSG_DONTWAIT
+    - net: sched: fix packet stuck problem for lockless qdisc
+    - net: sched: fix tx action rescheduling issue during deactivation
+    - net: sched: fix tx action reschedule issue with stopped queue
+    - net: hso: check for allocation failure in hso_create_bulk_serial_device()
+    - net: bnx2: Fix error return code in bnx2_init_board()
+    - bnxt_en: Include new P5 HV definition in VF check.
+    - mld: fix panic in mld_newpack()
+    - gve: Check TX QPL was actually assigned
+    - gve: Update mgmt_msix_idx if num_ntfy changes
+    - gve: Add NULL pointer checks when freeing irqs.
+    - gve: Upgrade memory barrier in poll routine
+    - gve: Correct SKB queue index validation.
+    - cxgb4: avoid accessing registers when clearing filters
+    - staging: emxx_udc: fix loop in _nbu2ss_nuke()
+    - ASoC: cs35l33: fix an error code in probe()
+    - bpf: Set mac_len in bpf_skb_change_head
+    - ixgbe: fix large MTU request from VF
+    - scsi: libsas: Use _safe() loop in sas_resume_port()
+    - net: lantiq: fix memory corruption in RX ring
+    - ipv6: record frag_max_size in atomic fragments in input path
+    - ALSA: usb-audio: scarlett2: snd_scarlett_gen2_controls_create() can be
+      static
+    - net: ethernet: mtk_eth_soc: Fix packet statistics support for MT7628/88
+    - sch_dsmark: fix a NULL deref in qdisc_reset()
+    - MIPS: alchemy: xxs1500: add gpio-au1000.h header file
+    - MIPS: ralink: export rt_sysc_membase for rt2880_wdt.c
+    - drm/i915/display: fix compiler warning about array overrun
+    - i915: fix build warning in intel_dp_get_link_status()
+    - drivers/net/ethernet: clean up unused assignments
+    - net: hns3: check the return of skb_checksum_help()
+    - Revert "Revert "ALSA: usx2y: Fix potential NULL pointer dereference""
+    - net: hso: bail out on interrupt URB allocation failure
+    - neighbour: Prevent Race condition in neighbour subsytem
+    - usb: core: reduce power-on-good delay time of root hub
+    - Linux 5.4.124
+  * Focal update: v5.4.123 upstream stable release (LP: #1931160)
+    - usb: dwc3: gadget: Enable suspend events
+    - perf unwind: Fix separate debug info files when using elfutils' libdw's
+      unwinder
+    - perf unwind: Set userdata for all __report_module() paths
+    - NFC: nci: fix memory leak in nci_allocate_device
+    - Linux 5.4.123
+  * Focal update: v5.4.122 upstream stable release (LP: #1931159)
+    - firmware: arm_scpi: Prevent the ternary sign expansion bug
+    - openrisc: Fix a memory leak
+    - RDMA/siw: Properly check send and receive CQ pointers
+    - RDMA/siw: Release xarray entry
+    - RDMA/rxe: Clear all QP fields if creation failed
+    - scsi: ufs: core: Increase the usable queue depth
+    - scsi: qla2xxx: Fix error return code in qla82xx_write_flash_dword()
+    - RDMA/mlx5: Recover from fatal event in dual port mode
+    - RDMA/core: Don't access cm_id after its destruction
+    - platform/mellanox: mlxbf-tmfifo: Fix a memory barrier issue
+    - platform/x86: dell-smbios-wmi: Fix oops on rmmod dell_smbios
+    - RDMA/uverbs: Fix a NULL vs IS_ERR() bug
+    - ptrace: make ptrace() fail if the tracee changed its pid unexpectedly
+    - nvmet: seset ns->file when open fails
+    - locking/mutex: clear MUTEX_FLAGS if wait_list is empty due to signal
+    - btrfs: avoid RCU stalls while running delayed iputs
+    - cifs: fix memory leak in smb2_copychunk_range
+    - ALSA: dice: fix stream format for TC Electronic Konnekt Live at high
+      sampling transfer frequency
+    - ALSA: intel8x0: Don't update period unless prepared
+    - ALSA: line6: Fix racy initialization of LINE6 MIDI
+    - ALSA: dice: fix stream format at middle sampling rate for Alesis iO 26
+    - ALSA: firewire-lib: fix calculation for size of IR context payload
+    - ALSA: usb-audio: Validate MS endpoint descriptors
+    - ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro
+    - ALSA: hda: fixup headset for ASUS GU502 laptop
+    - Revert "ALSA: sb8: add a check for request_region"
+    - ALSA: firewire-lib: fix check for the size of isochronous packet payload
+    - ALSA: hda/realtek: reset eapd coeff to default value for alc287
+    - ALSA: hda/realtek: Add some CLOVE SSIDs of ALC293
+    - ALSA: hda/realtek: Fix silent headphone output on ASUS UX430UA
+    - ALSA: hda/realtek: Add fixup for HP OMEN laptop
+    - ALSA: hda/realtek: Add fixup for HP Spectre x360 15-df0xxx
+    - uio_hv_generic: Fix a memory leak in error handling paths
+    - Revert "rapidio: fix a NULL pointer dereference when create_workqueue()
+      fails"
+    - rapidio: handle create_workqueue() failure
+    - Revert "serial: mvebu-uart: Fix to avoid a potential NULL pointer
+      dereference"
+    - drm/amdgpu: disable 3DCGCG on picasso/raven1 to avoid compute hang
+    - drm/amdgpu: update gc golden setting for Navi12
+    - drm/amdgpu: update sdma golden setting for Navi12
+    - mmc: sdhci-pci-gli: increase 1.8V regulator wait
+    - xen-pciback: reconfigure also from backend watch handler
+    - dm snapshot: fix crash with transient storage and zero chunk size
+    - Revert "video: hgafb: fix potential NULL pointer dereference"
+    - Revert "net: stmicro: fix a missing check of clk_prepare"
+    - Revert "leds: lp5523: fix a missing check of return value of lp55xx_read"
+    - Revert "hwmon: (lm80) fix a missing check of bus read in lm80 probe"
+    - Revert "video: imsttfb: fix potential NULL pointer dereferences"
+    - Revert "ecryptfs: replace BUG_ON with error handling code"
+    - Revert "scsi: ufs: fix a missing check of devm_reset_control_get"
+    - Revert "gdrom: fix a memory leak bug"
+    - cdrom: gdrom: deallocate struct gdrom_unit fields in remove_gdrom
+    - cdrom: gdrom: initialize global variable at init time
+    - Revert "media: rcar_drif: fix a memory disclosure"
+    - Revert "rtlwifi: fix a potential NULL pointer dereference"
+    - Revert "qlcnic: Avoid potential NULL pointer dereference"
+    - Revert "niu: fix missing checks of niu_pci_eeprom_read"
+    - ethernet: sun: niu: fix missing checks of niu_pci_eeprom_read()
+    - net: stmicro: handle clk_prepare() failure during init
+    - scsi: ufs: handle cleanup correctly on devm_reset_control_get error
+    - net: rtlwifi: properly check for alloc_workqueue() failure
+    - ics932s401: fix broken handling of errors when word reading fails
+    - leds: lp5523: check return value of lp5xx_read and jump to cleanup code
+    - qlcnic: Add null check after calling netdev_alloc_skb
+    - video: hgafb: fix potential NULL pointer dereference
+    - vgacon: Record video mode changes with VT_RESIZEX
+    - vt: Fix character height handling with VT_RESIZEX
+    - tty: vt: always invoke vc->vc_sw->con_resize callback
+    - nvme-multipath: fix double initialization of ANA state
+    - ext4: fix error handling in ext4_end_enable_verity()
+    - Bluetooth: L2CAP: Fix handling LE modes by L2CAP_OPTIONS
+    - nvmet: use new ana_log_size instead the old one
+    - video: hgafb: correctly handle card detect failure during probe
+    - Bluetooth: SMP: Fail if remote and local public keys are identical
+    - Linux 5.4.122
+  * Focal update: v5.4.121 upstream stable release (LP: #1931158)
+    - x86/msr: Fix wr/rdmsr_safe_regs_on_cpu() prototypes
+    - kgdb: fix gcc-11 warning on indentation
+    - usb: sl811-hcd: improve misleading indentation
+    - cxgb4: Fix the -Wmisleading-indentation warning
+    - isdn: capi: fix mismatched prototypes
+    - pinctrl: ingenic: Improve unreachable code generation
+    - xsk: Simplify detection of empty and full rings
+    - virtio_net: Do not pull payload in skb->head
+    - PCI: thunder: Fix compile testing
+    - dmaengine: dw-edma: Fix crash on loading/unloading driver
+    - ARM: 9066/1: ftrace: pause/unpause function graph tracer in cpu_suspend()
+    - ACPI / hotplug / PCI: Fix reference count leak in enable_slot()
+    - Input: elants_i2c - do not bind to i2c-hid compatible ACPI instantiated
+      devices
+    - Input: silead - add workaround for x86 BIOS-es which bring the chip up in a
+      stuck state
+    - um: Mark all kernel symbols as local
+    - um: Disable CONFIG_GCOV with MODULES
+    - ARM: 9075/1: kernel: Fix interrupted SMC calls
+    - scripts/recordmcount.pl: Fix RISC-V regex for clang
+    - riscv: Workaround mcount name prior to clang-13
+    - scsi: lpfc: Fix illegal memory access on Abort IOCBs
+    - ceph: fix fscache invalidation
+    - scsi: target: tcmu: Return from tcmu_handle_completions() if cmd_id not
+      found
+    - bridge: Fix possible races between assigning rx_handler_data and setting
+      IFF_BRIDGE_PORT bit
+    - drm/amd/display: Fix two cursor duplication when using overlay
+    - gpiolib: acpi: Add quirk to ignore EC wakeups on Dell Venue 10 Pro 5055
+    - ALSA: hda: generic: change the DAC ctl name for LO+SPK or LO+HP
+    - block: reexpand iov_iter after read/write
+    - lib: stackdepot: turn depot_lock spinlock to raw_spinlock
+    - net: stmmac: Do not enable RX FIFO overflow interrupts
+    - ip6_gre: proper dev_{hold|put} in ndo_[un]init methods
+    - sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ip6_tunnel: sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ipv6: remove extra dev_hold() for fallback tunnels
+    - KVM: arm64: Initialize VCPU mdcr_el2 before loading it
+    - tweewide: Fix most Shebang lines
+    - scripts: switch explicitly to Python 3
+    - Linux 5.4.121
+  * Focal update: v5.4.120 upstream stable release (LP: #1930474)
+    - tpm: fix error return code in tpm2_get_cc_attrs_tbl()
+    - tpm, tpm_tis: Extend locality handling to TPM2 in tpm_tis_gen_interrupt()
+    - tpm, tpm_tis: Reserve locality in tpm_tis_resume()
+    - KVM: x86/mmu: Remove the defunct update_pte() paging hook
+    - PM: runtime: Fix unpaired parent child_count for force_resume
+    - fs: dlm: fix debugfs dump
+    - tipc: convert dest node's address to network order
+    - ASoC: Intel: bytcr_rt5640: Enable jack-detect support on Asus T100TAF
+    - net: stmmac: Set FIFO sizes for ipq806x
+    - ASoC: rsnd: core: Check convert rate in rsnd_hw_params
+    - i2c: bail out early when RDWR parameters are wrong
+    - ALSA: hdsp: don't disable if not enabled
+    - ALSA: hdspm: don't disable if not enabled
+    - ALSA: rme9652: don't disable if not enabled
+    - ALSA: bebob: enable to deliver MIDI messages for multiple ports
+    - Bluetooth: Set CONF_NOT_COMPLETE as l2cap_chan default
+    - Bluetooth: initialize skb_queue_head at l2cap_chan_create()
+    - net: bridge: when suppression is enabled exclude RARP packets
+    - Bluetooth: check for zapped sk before connecting
+    - ip6_vti: proper dev_{hold|put} in ndo_[un]init methods
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Chuwi Hi8 tablet
+    - i2c: Add I2C_AQ_NO_REP_START adapter quirk
+    - mac80211: clear the beacon's CRC after channel switch
+    - pinctrl: samsung: use 'int' for register masks in Exynos
+    - mt76: mt76x0: disable GTK offloading
+    - cuse: prevent clone
+    - ASoC: rsnd: call rsnd_ssi_master_clk_start() from rsnd_ssi_init()
+    - Revert "iommu/amd: Fix performance counter initialization"
+    - iommu/amd: Remove performance counter pre-initialization test
+    - drm/amd/display: Force vsync flip when reconfiguring MPCC
+    - selftests: Set CC to clang in lib.mk if LLVM is set
+    - kconfig: nconf: stop endless search loops
+    - ALSA: hda/hdmi: fix race in handling acomp ELD notification at resume
+    - sctp: Fix out-of-bounds warning in sctp_process_asconf_param()
+    - flow_dissector: Fix out-of-bounds warning in __skb_flow_bpf_to_target()
+    - powerpc/smp: Set numa node before updating mask
+    - ASoC: rt286: Generalize support for ALC3263 codec
+    - ethtool: ioctl: Fix out-of-bounds warning in store_link_ksettings_for_user()
+    - net: sched: tapr: prevent cycle_time == 0 in parse_taprio_schedule
+    - samples/bpf: Fix broken tracex1 due to kprobe argument change
+    - powerpc/pseries: Stop calling printk in rtas_stop_self()
+    - drm/amd/display: fixed divide by zero kernel crash during dsc enablement
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_send_pkt
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_mgmt_join
+    - qtnfmac: Fix possible buffer overflow in qtnf_event_handle_external_auth
+    - powerpc/iommu: Annotate nested lock for lockdep
+    - iavf: remove duplicate free resources calls
+    - net: ethernet: mtk_eth_soc: fix RX VLAN offload
+    - bnxt_en: Add PCI IDs for Hyper-V VF devices.
+    - ia64: module: fix symbolizer crash on fdescr
+    - ASoC: rt286: Make RT286_SET_GPIO_* readable and writable
+    - thermal: thermal_of: Fix error return code of
+      thermal_of_populate_bind_params()
+    - f2fs: fix a redundant call to f2fs_balance_fs if an error occurs
+    - PCI: iproc: Fix return value of iproc_msi_irq_domain_alloc()
+    - PCI: Release OF node in pci_scan_device()'s error path
+    - ARM: 9064/1: hw_breakpoint: Do not directly check the event's
+      overflow_handler hook
+    - rpmsg: qcom_glink_native: fix error return code of qcom_glink_rx_data()
+    - NFSv4.2: Always flush out writes in nfs42_proc_fallocate()
+    - NFS: Deal correctly with attribute generation counter overflow
+    - PCI: endpoint: Fix missing destroy_workqueue()
+    - pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
+    - NFSv4.2 fix handling of sr_eof in SEEK's reply
+    - rtc: fsl-ftm-alarm: add MODULE_TABLE()
+    - ceph: fix inode leak on getattr error in __fh_to_dentry
+    - rtc: ds1307: Fix wday settings for rx8130
+    - net: hns3: fix incorrect configuration for igu_egu_hw_err
+    - net: hns3: initialize the message content in hclge_get_link_mode()
+    - net: hns3: add check for HNS3_NIC_STATE_INITED in
+      hns3_reset_notify_up_enet()
+    - net: hns3: fix for vxlan gpe tx checksum bug
+    - net: hns3: use netif_tx_disable to stop the transmit queue
+    - net: hns3: disable phy loopback setting in hclge_mac_start_phy
+    - sctp: do asoc update earlier in sctp_sf_do_dupcook_a
+    - RISC-V: Fix error code returned by riscv_hartid_to_cpuid()
+    - sunrpc: Fix misplaced barrier in call_decode
+    - ethernet:enic: Fix a use after free bug in enic_hard_start_xmit
+    - sctp: fix a SCTP_MIB_CURRESTAB leak in sctp_sf_do_dupcook_b
+    - netfilter: xt_SECMARK: add new revision to fix structure layout
+    - drm/radeon: Fix off-by-one power_state index heap overwrite
+    - drm/radeon: Avoid power table parsing memory leaks
+    - khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
+    - mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
+    - mm/migrate.c: fix potential indeterminate pte entry in
+      migrate_vma_insert_page()
+    - ksm: fix potential missing rmap_item for stable_node
+    - net: fix nla_strcmp to handle more then one trailing null character
+    - smc: disallow TCP_ULP in smc_setsockopt()
+    - netfilter: nfnetlink_osf: Fix a missing skb_header_pointer() NULL check
+    - can: m_can: m_can_tx_work_queue(): fix tx_skb race condition
+    - sched: Fix out-of-bound access in uclamp
+    - sched/fair: Fix unfairness caused by missing load decay
+    - kernel: kexec_file: fix error return code of kexec_calculate_store_digests()
+    - netfilter: nftables: avoid overflows in nft_hash_buckets()
+    - i40e: Fix use-after-free in i40e_client_subtask()
+    - i40e: fix the restart auto-negotiation after FEC modified
+    - i40e: Fix PHY type identifiers for 2.5G and 5G adapters
+    - ARC: entry: fix off-by-one error in syscall number validation
+    - ARC: mm: PAE: use 40-bit physical page mask
+    - powerpc/64s: Fix crashes when toggling stf barrier
+    - powerpc/64s: Fix crashes when toggling entry flush barrier
+    - hfsplus: prevent corruption in shrinking truncate
+    - squashfs: fix divide error in calculate_skip()
+    - userfaultfd: release page in error path to avoid BUG_ON
+    - mm/hugetlb: fix F_SEAL_FUTURE_WRITE
+    - drm/radeon/dpm: Disable sclk switching on Oland when two 4K 60Hz monitors
+      are connected
+    - drm/i915: Avoid div-by-zero on gen2
+    - iio: proximity: pulsedlight: Fix rumtime PM imbalance on error
+    - usb: fotg210-hcd: Fix an error message
+    - hwmon: (occ) Fix poll rate limiting
+    - ACPI: scan: Fix a memory leak in an error handling path
+    - kyber: fix out of bounds access when preempted
+    - nbd: Fix NULL pointer in flush_workqueue
+    - blk-mq: Swap two calls in blk_mq_exit_queue()
+    - iomap: fix sub-page uptodate handling
+    - usb: dwc3: omap: improve extcon initialization
+    - usb: dwc3: pci: Enable usb2-gadget-lpm-disable for Intel Merrifield
+    - usb: xhci: Increase timeout for HC halt
+    - usb: dwc2: Fix gadget DMA unmap direction
+    - usb: core: hub: fix race condition about TRSMRCY of resume
+    - usb: dwc3: gadget: Return success always for kick transfer in ep queue
+    - xhci: Do not use GFP_KERNEL in (potentially) atomic context
+    - xhci: Add reset resume quirk for AMD xhci controller.
+    - iio: gyro: mpu3050: Fix reported temperature value
+    - iio: tsl2583: Fix division by a zero lux_val
+    - cdc-wdm: untangle a circular dependency between callback and softint
+    - KVM: x86: Cancel pvclock_gtod_work on module removal
+    - mm: fix struct page layout on 32-bit systems
+    - FDDI: defxx: Make MMIO the configuration default except for EISA
+    - MIPS: Reinstate platform `__div64_32' handler
+    - MIPS: Avoid DIVU in `__div64_32' is result would be zero
+    - MIPS: Avoid handcoded DIVU in `__div64_32' altogether
+    - thermal/core/fair share: Lock the thermal zone while looping over instances
+    - f2fs: fix error handling in f2fs_end_enable_verity()
+    - ARM: 9011/1: centralize phys-to-virt conversion of DT/ATAGS address
+    - ARM: 9012/1: move device tree mapping out of linear region
+    - ARM: 9020/1: mm: use correct section size macro to describe the FDT virtual
+      address
+    - ARM: 9027/1: head.S: explicitly map DT even if it lives in the first
+      physical section
+    - usb: typec: tcpm: Fix error while calculating PPS out values
+    - kobject_uevent: remove warning in init_uevent_argv()
+    - netfilter: conntrack: Make global sysctls readonly in non-init netns
+    - clk: exynos7: Mark aclk_fsys1_200 as critical
+    - nvme: do not try to reconfigure APST when the controller is not live
+    - ASoC: rsnd: check all BUSIF status when error
+    - Linux 5.4.120
+  * scsi: storvsc: Parameterize number hardware queues (LP: #1930626)
+    - scsi: storvsc: Parameterize number hardware queues
+
+  [ Ubuntu: 5.4.0-77.86 ]
+
+  * UAF on CAN J1939 j1939_can_recv (LP: #1932209)
+    - SAUCE: can: j1939: delay release of j1939_priv after synchronize_rcu
+  * UAF on CAN BCM bcm_rx_handler (LP: #1931855)
+    - SAUCE: can: bcm: delay release of struct bcm_op after synchronize_rcu
+
+  [ Ubuntu: 5.4.0-76.85 ]
+
+  * focal/linux: 5.4.0-76.85 -proposed tracker (LP: #1932123)
+  * Upstream v5.9 introduced 'module' patches that removed exported symbols
+    (LP: #1932065)
+    - SAUCE: Revert "modules: inherit TAINT_PROPRIETARY_MODULE"
+    - SAUCE: Revert "modules: return licensing information from find_symbol"
+    - SAUCE: Revert "modules: rename the licence field in struct symsearch to
+      license"
+    - SAUCE: Revert "modules: unexport __module_address"
+    - SAUCE: Revert "modules: unexport __module_text_address"
+    - SAUCE: Revert "modules: mark each_symbol_section static"
+    - SAUCE: Revert "modules: mark find_symbol static"
+    - SAUCE: Revert "modules: mark ref_module static"
+
+  [ Ubuntu: 5.4.0-75.84 ]
+
+  * focal/linux: 5.4.0-75.84 -proposed tracker (LP: #1930032)
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+  * CVE-2021-33200
+    - bpf: Wrap aux data inside bpf_sanitize_info container
+    - bpf: Fix mask direction swap upon off reg sign change
+    - bpf: No need to simulate speculative domain for immediates
+  * Realtek USB hubs in Dell WD19SC/DC/TB fail to work after exiting s2idle
+    (LP: #1928242)
+    - USB: Verify the port status when timeout happens during port suspend
+  * CVE-2020-26145
+    - ath10k: drop fragments with multicast DA for SDIO
+    - ath10k: add CCMP PN replay protection for fragmented frames for PCIe
+    - ath10k: drop fragments with multicast DA for PCIe
+  * CVE-2020-26141
+    - ath10k: Fix TKIP Michael MIC verification for PCIe
+  * CVE-2020-24588
+    - mac80211: properly handle A-MSDUs that start with an RFC 1042 header
+    - cfg80211: mitigate A-MSDU aggregation attacks
+    - mac80211: drop A-MSDUs on old ciphers
+    - ath10k: drop MPDU which has discard flag set by firmware for SDIO
+  * CVE-2020-26139
+    - mac80211: do not accept/forward invalid EAPOL frames
+  * CVE-2020-24586 // CVE-2020-24587 // CVE-2020-24587 for such cases.
+    - mac80211: extend protection against mixed key and fragment cache attacks
+  * CVE-2020-24586 // CVE-2020-24587
+    - mac80211: prevent mixed key and fragment cache attacks
+    - mac80211: add fragment cache to sta_info
+    - mac80211: check defrag PN against current frame
+    - mac80211: prevent attacks on TKIP/WEP as well
+  * CVE-2020-26147
+    - mac80211: assure all fragments are encrypted
+  * raid10: Block discard is very slow, causing severe delays for mkfs and
+    fstrim operations (LP: #1896578)
+    - md: add md_submit_discard_bio() for submitting discard bio
+    - md/raid10: extend r10bio devs to raid disks
+    - md/raid10: pull the code that wait for blocked dev into one function
+    - md/raid10: improve raid10 discard request
+    - md/raid10: improve discard request for far layout
+    - dm raid: remove unnecessary discard limits for raid0 and raid10
+  * [SRU] mpt3sas: only one vSES is handy even IOC has multi vSES (LP: #1926517)
+    - scsi: mpt3sas: Only one vSES is present even when IOC has multi vSES
+  * kvm: properly tear down PV features on hibernate (LP: #1920944)
+    - x86/kvm: Fix pr_info() for async PF setup/teardown
+    - x86/kvm: Teardown PV features on boot CPU as well
+    - x86/kvm: Disable kvmclock on all CPUs on shutdown
+    - x86/kvm: Disable all PV features on crash
+    - x86/kvm: Unify kvm_pv_guest_cpu_reboot() with kvm_guest_cpu_offline()
+  * Focal update: v5.4.119 upstream stable release (LP: #1929615)
+    - Bluetooth: verify AMP hci_chan before amp_destroy
+    - hsr: use netdev_err() instead of WARN_ONCE()
+    - bluetooth: eliminate the potential race condition when removing the HCI
+      controller
+    - net/nfc: fix use-after-free llcp_sock_bind/connect
+    - Revert "USB: cdc-acm: fix rounding error in TIOCSSERIAL"
+    - tty: moxa: fix TIOCSSERIAL jiffies conversions
+    - tty: amiserial: fix TIOCSSERIAL permission check
+    - USB: serial: usb_wwan: fix TIOCSSERIAL jiffies conversions
+    - staging: greybus: uart: fix TIOCSSERIAL jiffies conversions
+    - USB: serial: ti_usb_3410_5052: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL jiffies conversions
+    - tty: moxa: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL permission check
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for fixed supply
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for pps supply
+    - usb: typec: tcpm: update power supply once partner accepts
+    - usb: xhci-mtk: remove or operator for setting schedule parameters
+    - usb: xhci-mtk: improve bandwidth scheduling with TT
+    - ASoC: samsung: tm2_wm5110: check of of_parse return value
+    - ASoC: Intel: kbl_da7219_max98927: Fix kabylake_ssp_fixup function
+    - MIPS: pci-mt7620: fix PLL lock check
+    - MIPS: pci-rt2880: fix slot 0 configuration
+    - FDDI: defxx: Bail out gracefully with unassigned PCI resource for CSR
+    - PCI: Allow VPD access for QLogic ISP2722
+    - iio:accel:adis16201: Fix wrong axis assignment that prevents loading
+    - misc: lis3lv02d: Fix false-positive WARN on various HP models
+    - misc: vmw_vmci: explicitly initialize vmci_notify_bm_set_msg struct
+    - misc: vmw_vmci: explicitly initialize vmci_datagram payload
+    - md/bitmap: wait for external bitmap writes to complete during tear down
+    - md-cluster: fix use-after-free issue when removing rdev
+    - md: split mddev_find
+    - md: factor out a mddev_find_locked helper from mddev_find
+    - md: md_open returns -EBUSY when entering racing area
+    - md: Fix missing unused status line of /proc/mdstat
+    - ipw2x00: potential buffer overflow in libipw_wx_set_encodeext()
+    - cfg80211: scan: drop entry from hidden_list on overflow
+    - rtw88: Fix array overrun in rtw_get_tx_power_params()
+    - drm/panfrost: Clear MMU irqs before handling the fault
+    - drm/panfrost: Don't try to map pages that are already mapped
+    - drm/radeon: fix copy of uninitialized variable back to userspace
+    - drm/amd/display: Reject non-zero src_y and src_x for video planes
+    - ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Clevo quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 HP quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Dell quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 ASUS quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries
+    - ALSA: hda/realtek: Re-order remaining ALC269 quirk table entries
+    - ALSA: hda/realtek: Re-order ALC662 quirk table entries
+    - ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices
+    - ALSA: hda/realtek: ALC285 Thinkpad jack pin quirk is unreachable
+    - KVM: s390: split kvm_s390_logical_to_effective
+    - KVM: s390: fix guarded storage control register handling
+    - s390: fix detection of vector enhancements facility 1 vs. vector packed
+      decimal facility
+    - KVM: s390: split kvm_s390_real_to_abs
+    - KVM: nVMX: Truncate bits 63:32 of VMCS field on nested check in !64-bit
+    - KVM: Stop looking for coalesced MMIO zones if the bus is destroyed
+    - Revert "i3c master: fix missing destroy_workqueue() on error in
+      i3c_master_register"
+    - ovl: fix missing revert_creds() on error path
+    - usb: gadget: pch_udc: Revert d3cb25a12138 completely
+    - memory: gpmc: fix out of bounds read and dereference on gpmc_cs[]
+    - ARM: dts: exynos: correct fuel gauge interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct MUIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Odroid X/U3 family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on SMDK5250
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Snow
+    - serial: stm32: fix incorrect characters on console
+    - serial: stm32: fix tx_empty condition
+    - usb: typec: tcpci: Check ROLE_CONTROL while interpreting CC_STATUS
+    - regmap: set debugfs_name to NULL after it is freed
+    - mtd: rawnand: fsmc: Fix error code in fsmc_nand_probe()
+    - mtd: rawnand: brcmnand: fix OOB R/W with Hamming ECC
+    - mtd: Handle possible -EPROBE_DEFER from parse_mtd_partitions()
+    - mtd: rawnand: qcom: Return actual error code instead of -ENODEV
+    - arm64: dts: qcom: sm8150: fix number of pins in 'gpio-ranges'
+    - spi: stm32: drop devres version of spi_register_master
+    - arm64: dts: renesas: r8a77980: Fix vin4-7 endpoint binding
+    - x86/microcode: Check for offline CPUs before requesting new microcode
+    - usb: gadget: pch_udc: Replace cpu_to_le32() by lower_32_bits()
+    - usb: gadget: pch_udc: Check if driver is present before calling ->setup()
+    - usb: gadget: pch_udc: Check for DMA mapping error
+    - crypto: qat - don't release uninitialized resources
+    - crypto: qat - ADF_STATUS_PF_RUNNING should be set after adf_dev_init
+    - fotg210-udc: Fix DMA on EP0 for length > max packet size
+    - fotg210-udc: Fix EP0 IN requests bigger than two packets
+    - fotg210-udc: Remove a dubious condition leading to fotg210_done
+    - fotg210-udc: Mask GRP2 interrupts we don't handle
+    - fotg210-udc: Don't DMA more than the buffer can take
+    - fotg210-udc: Complete OUT requests on short packets
+    - mtd: require write permissions for locking and badblock ioctls
+    - bus: qcom: Put child node before return
+    - soundwire: bus: Fix device found flag correctly
+    - phy: marvell: ARMADA375_USBCLUSTER_PHY should not default to y,
+      unconditionally
+    - crypto: qat - fix error path in adf_isr_resource_alloc()
+    - usb: gadget: aspeed: fix dma map failure
+    - USB: gadget: udc: fix wrong pointer passed to IS_ERR() and PTR_ERR()
+    - memory: pl353: fix mask of ECC page_size config register
+    - soundwire: stream: fix memory leak in stream config error path
+    - m68k: mvme147,mvme16x: Don't wipe PCC timer config bits
+    - mtd: rawnand: gpmi: Fix a double free in gpmi_nand_init
+    - irqchip/gic-v3: Fix OF_BAD_ADDR error handling
+    - staging: rtl8192u: Fix potential infinite loop
+    - staging: greybus: uart: fix unprivileged TIOCCSERIAL
+    - PM / devfreq: Use more accurate returned new_freq as resume_freq
+    - spi: Fix use-after-free with devm_spi_alloc_*
+    - soc: qcom: mdt_loader: Validate that p_filesz < p_memsz
+    - soc: qcom: mdt_loader: Detect truncated read of segments
+    - ACPI: CPPC: Replace cppc_attr with kobj_attribute
+    - crypto: qat - Fix a double free in adf_create_ring
+    - cpufreq: armada-37xx: Fix setting TBG parent for load levels
+    - clk: mvebu: armada-37xx-periph: remove .set_parent method for CPU PM clock
+    - cpufreq: armada-37xx: Fix the AVS value for load L1
+    - clk: mvebu: armada-37xx-periph: Fix switching CPU freq from 250 Mhz to 1 GHz
+    - clk: mvebu: armada-37xx-periph: Fix workaround for switching from L1 to L0
+    - cpufreq: armada-37xx: Fix driver cleanup when registration failed
+    - cpufreq: armada-37xx: Fix determining base CPU frequency
+    - spi: fsl-lpspi: Fix PM reference leak in lpspi_prepare_xfer_hardware()
+    - usb: gadget: r8a66597: Add missing null check on return from
+      platform_get_resource
+    - USB: cdc-acm: fix unprivileged TIOCCSERIAL
+    - USB: cdc-acm: fix TIOCGSERIAL implementation
+    - tty: fix return value for unsupported ioctls
+    - serial: core: return early on unsupported ioctls
+    - firmware: qcom-scm: Fix QCOM_SCM configuration
+    - node: fix device cleanups in error handling code
+    - usbip: vudc: fix missing unlock on error in usbip_sockfd_store()
+    - platform/x86: pmc_atom: Match all Beckhoff Automation baytrail boards with
+      critclk_systems DMI table
+    - x86/platform/uv: Fix !KEXEC build failure
+    - usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
+    - usb: dwc2: Fix hibernation between host and device modes.
+    - ttyprintk: Add TTY hangup callback.
+    - xen-blkback: fix compatibility bug with single page rings
+    - soc: aspeed: fix a ternary sign expansion bug
+    - media: vivid: fix assignment of dev->fbuf_out_flags
+    - media: omap4iss: return error code when omap4iss_get() failed
+    - media: aspeed: fix clock handling logic
+    - media: platform: sunxi: sun6i-csi: fix error return code of
+      sun6i_video_start_streaming()
+    - media: m88rs6000t: avoid potential out-of-bounds reads on arrays
+    - drm/amdkfd: fix build error with AMD_IOMMU_V2=m
+    - x86/kprobes: Fix to check non boostable prefixes correctly
+    - pata_arasan_cf: fix IRQ check
+    - pata_ipx4xx_cf: fix IRQ check
+    - sata_mv: add IRQ checks
+    - ata: libahci_platform: fix IRQ check
+    - nvme-tcp: block BH in sk state_change sk callback
+    - nvmet-tcp: fix incorrect locking in state_change sk callback
+    - nvme: retrigger ANA log update if group descriptor isn't found
+    - media: v4l2-ctrls.c: fix race condition in hdl->requests list
+    - vfio/mdev: Do not allow a mdev_type to have a NULL parent pointer
+    - clk: zynqmp: move zynqmp_pll_set_mode out of round_rate callback
+    - clk: qcom: a53-pll: Add missing MODULE_DEVICE_TABLE
+    - clk: uniphier: Fix potential infinite loop
+    - scsi: hisi_sas: Fix IRQ checks
+    - scsi: jazz_esp: Add IRQ check
+    - scsi: sun3x_esp: Add IRQ check
+    - scsi: sni_53c710: Add IRQ check
+    - scsi: ibmvfc: Fix invalid state machine BUG_ON()
+    - mfd: stm32-timers: Avoid clearing auto reload register
+    - nvme-pci: don't simple map sgl when sgls are disabled
+    - HSI: core: fix resource leaks in hsi_add_client_from_dt()
+    - x86/events/amd/iommu: Fix sysfs type mismatch
+    - sched/debug: Fix cgroup_path[] serialization
+    - drivers/block/null_blk/main: Fix a double free in null_init.
+    - HID: plantronics: Workaround for double volume key presses
+    - perf symbols: Fix dso__fprintf_symbols_by_name() to return the number of
+      printed chars
+    - net: lapbether: Prevent racing when checking whether the netif is running
+    - powerpc/fadump: Mark fadump_calculate_reserve_size as __init
+    - powerpc/prom: Mark identical_pvr_fixup as __init
+    - inet: use bigger hash table for IP ID generation
+    - powerpc: Fix HAVE_HARDLOCKUP_DETECTOR_ARCH build configuration
+    - ALSA: core: remove redundant spin_lock pair in snd_card_disconnect
+    - bug: Remove redundant condition check in report_bug
+    - nfc: pn533: prevent potential memory corruption
+    - net: hns3: Limiting the scope of vector_ring_chain variable
+    - mips: bmips: fix syscon-reboot nodes
+    - ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls
+    - ASoC: simple-card: fix possible uninitialized single_cpu local variable
+    - liquidio: Fix unintented sign extension of a left shift of a u16
+    - powerpc/64s: Fix pte update for kernel memory on radix
+    - powerpc/perf: Fix PMU constraint check for EBB events
+    - powerpc: iommu: fix build when neither PCI or IBMVIO is set
+    - mac80211: bail out if cipher schemes are invalid
+    - mt7601u: fix always true expression
+    - KVM: PPC: Book3S HV P9: Restore host CTRL SPR after guest exit
+    - RDMA/qedr: Fix error return code in qedr_iw_connect()
+    - IB/hfi1: Fix error return code in parse_platform_config()
+    - cxgb4: Fix unintentional sign extension issues
+    - net: thunderx: Fix unintentional sign extension issue
+    - RDMA/srpt: Fix error return code in srpt_cm_req_recv()
+    - i2c: img-scb: fix reference leak when pm_runtime_get_sync fails
+    - i2c: imx-lpi2c: fix reference leak when pm_runtime_get_sync fails
+    - i2c: omap: fix reference leak when pm_runtime_get_sync fails
+    - i2c: sprd: fix reference leak when pm_runtime_get_sync fails
+    - i2c: cadence: add IRQ check
+    - i2c: emev2: add IRQ check
+    - i2c: jz4780: add IRQ check
+    - i2c: sh7760: add IRQ check
+    - powerpc/xive: Fix xmon command "dxi"
+    - ASoC: ak5558: correct reset polarity
+    - drm/i915/gvt: Fix error code in intel_gvt_init_device()
+    - perf beauty: Fix fsconfig generator
+    - MIPS: pci-legacy: stop using of_pci_range_to_resource
+    - powerpc/pseries: extract host bridge from pci_bus prior to bus removal
+    - rtlwifi: 8821ae: upgrade PHY and RF parameters
+    - i2c: sh7760: fix IRQ error path
+    - mwl8k: Fix a double Free in mwl8k_probe_hw
+    - vsock/vmci: log once the failed queue pair allocation
+    - gro: fix napi_gro_frags() Fast GRO breakage due to IP alignment check
+    - RDMA/cxgb4: add missing qpid increment
+    - RDMA/i40iw: Fix error unwinding when i40iw_hmc_sd_one fails
+    - ALSA: usb: midi: don't return -ENOMEM when usb_urb_ep_type_check fails
+    - net: davinci_emac: Fix incorrect masking of tx and rx error channel
+    - net: renesas: ravb: Fix a stuck issue when a lot of frames are received
+    - net: phy: intel-xway: enable integrated led functions
+    - ath9k: Fix error check in ath9k_hw_read_revisions() for PCI devices
+    - ath10k: Fix ath10k_wmi_tlv_op_pull_peer_stats_info() unlock without lock
+    - powerpc/52xx: Fix an invalid ASM expression ('addi' used instead of 'add')
+    - bnxt_en: fix ternary sign extension bug in bnxt_show_temp()
+    - ARM: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - arm64: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - net: geneve: modify IP header check in geneve6_xmit_skb and geneve_xmit_skb
+    - selftests: net: mirror_gre_vlan_bridge_1q: Make an FDB entry static
+    - bnxt_en: Fix RX consumer index logic in the error path.
+    - net:emac/emac-mac: Fix a use after free in emac_mac_tx_buf_send
+    - RDMA/siw: Fix a use after free in siw_alloc_mr
+    - RDMA/bnxt_re: Fix a double free in bnxt_qplib_alloc_res
+    - net: bridge: mcast: fix broken length + header check for MRDv6 Adv.
+    - net:nfc:digital: Fix a double free in digital_tg_recv_dep_req
+    - kfifo: fix ternary sign extension bugs
+    - mm/sparse: add the missing sparse_buffer_fini() in error branch
+    - mm/memory-failure: unnecessary amount of unmapping
+    - net: Only allow init netns to set default tcp cong to a restricted algo
+    - smp: Fix smp_call_function_single_async prototype
+    - Revert "net/sctp: fix race condition in sctp_destroy_sock"
+    - sctp: delay auto_asconf init until binding the first addr
+    - Revert "of/fdt: Make sure no-map does not remove already reserved regions"
+    - Revert "fdt: Properly handle "no-map" field in the memory region"
+    - Linux 5.4.119
+  * seccomp_bpf:syscall_faked from kselftests fail on s390x (LP: #1928522)
+    - selftests/seccomp: s390 shares the syscall and return value register
+  * Can't detect intel wifi 6235 (LP: #1920180)
+    - SAUCE: iwlwifi: add new pci id for 6235
+  * Mark kprobe_args_user.tc in kselftest/ftrace as unsupported (LP: #1929527)
+    - selftests/ftrace: Return unsupported for the unconfigured features
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: use $ksft_skip for skipped return code
+  * alsa/sof: make sof driver work in the case of without i915 (focal kernel)
+    (LP: #1927672)
+    - SAUCE: ASoC: SOF: Intel: hda: move the probe_bus ahead of creation of mach
+      device
+  * Fix kdump failures (LP: #1927518)
+    - video: hyperv_fb: Add ratelimit on error message
+    - Drivers: hv: vmbus: Increase wait time for VMbus unload
+    - Drivers: hv: vmbus: Initialize unload_event statically
+  * Ubuntu 20.04 - 'Support flow counters offset for bulk counters'
+    (LP: #1922494)
+    - IB/mlx5: Support flow counters offset for bulk counters
+  * Focal update: v5.4.118 upstream stable release (LP: #1928825)
+    - s390/disassembler: increase ebpf disasm buffer size
+    - ACPI: custom_method: fix potential use-after-free issue
+    - ACPI: custom_method: fix a possible memory leak
+    - ftrace: Handle commands when closing set_ftrace_filter file
+    - ARM: 9056/1: decompressor: fix BSS size calculation for LLVM ld.lld
+    - arm64: dts: marvell: armada-37xx: add syscon compatible to NB clk node
+    - arm64: dts: mt8173: fix property typo of 'phys' in dsi node
+    - ecryptfs: fix kernel panic with null dev_name
+    - mtd: spinand: core: add missing MODULE_DEVICE_TABLE()
+    - mtd: rawnand: atmel: Update ecc_stats.corrected counter
+    - erofs: add unsupported inode i_format check
+    - spi: spi-ti-qspi: Free DMA resources
+    - scsi: qla2xxx: Fix crash in qla2xxx_mqueuecommand()
+    - scsi: mpt3sas: Block PCI config access from userspace during reset
+    - mmc: uniphier-sd: Fix an error handling path in uniphier_sd_probe()
+    - mmc: uniphier-sd: Fix a resource leak in the remove function
+    - mmc: sdhci: Check for reset prior to DMA address unmap
+    - mmc: sdhci-pci: Fix initialization of some SD cards for Intel BYT-based
+      controllers
+    - mmc: block: Update ext_csd.cache_ctrl if it was written
+    - mmc: block: Issue a cache flush only when it's enabled
+    - mmc: core: Do a power cycle when the CMD11 fails
+    - mmc: core: Set read only for SD cards with permanent write protect bit
+    - mmc: core: Fix hanging on I/O during system suspend for removable cards
+    - modules: mark ref_module static
+    - modules: mark find_symbol static
+    - modules: mark each_symbol_section static
+    - modules: unexport __module_text_address
+    - modules: unexport __module_address
+    - modules: rename the licence field in struct symsearch to license
+    - modules: return licensing information from find_symbol
+    - modules: inherit TAINT_PROPRIETARY_MODULE
+    - irqchip/gic-v3: Do not enable irqs when handling spurious interrups
+    - cifs: Return correct error code from smb2_get_enc_key
+    - btrfs: fix metadata extent leak after failure to create subvolume
+    - intel_th: pci: Add Rocket Lake CPU support
+    - posix-timers: Preserve return value in clock_adjtime32()
+    - fbdev: zero-fill colormap in fbcmap.c
+    - bus: ti-sysc: Probe for l4_wkup and l4_cfg interconnect devices first
+    - staging: wimax/i2400m: fix byte-order issue
+    - spi: ath79: always call chipselect function
+    - spi: ath79: remove spi-master setup and cleanup assignment
+    - crypto: api - check for ERR pointers in crypto_destroy_tfm()
+    - crypto: qat - fix unmap invalid dma address
+    - usb: gadget: uvc: add bInterval checking for HS mode
+    - usb: webcam: Invalid size of Processing Unit Descriptor
+    - genirq/matrix: Prevent allocation counter corruption
+    - usb: gadget: f_uac2: validate input parameters
+    - usb: gadget: f_uac1: validate input parameters
+    - usb: dwc3: gadget: Ignore EP queue requests during bus reset
+    - usb: xhci: Fix port minor revision
+    - PCI: PM: Do not read power state in pci_enable_device_flags()
+    - x86/build: Propagate $(CLANG_FLAGS) to $(REALMODE_FLAGS)
+    - tee: optee: do not check memref size on return from Secure World
+    - perf/arm_pmu_platform: Fix error handling
+    - usb: xhci-mtk: support quirk to disable usb2 lpm
+    - xhci: check control context is valid before dereferencing it.
+    - xhci: fix potential array out of bounds with several interrupters
+    - spi: dln2: Fix reference leak to master
+    - spi: omap-100k: Fix reference leak to master
+    - spi: qup: fix PM reference leak in spi_qup_remove()
+    - usb: musb: fix PM reference leak in musb_irq_work()
+    - usb: core: hub: Fix PM reference leak in usb_port_resume()
+    - tty: n_gsm: check error while registering tty devices
+    - intel_th: Consistency and off-by-one fix
+    - phy: phy-twl4030-usb: Fix possible use-after-free in twl4030_usb_remove()
+    - crypto: stm32/hash - Fix PM reference leak on stm32-hash.c
+    - crypto: stm32/cryp - Fix PM reference leak on stm32-cryp.c
+    - crypto: omap-aes - Fix PM reference leak on omap-aes.c
+    - platform/x86: intel_pmc_core: Don't use global pmcdev in quirks
+    - btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s
+    - drm: Added orientation quirk for OneGX1 Pro
+    - drm/qxl: release shadow on shutdown
+    - drm/amd/display: Check for DSC support instead of ASIC revision
+    - drm/amd/display: Don't optimize bandwidth before disabling planes
+    - scsi: lpfc: Fix incorrect dbde assignment when building target abts wqe
+    - scsi: lpfc: Fix pt2pt connection does not recover after LOGO
+    - scsi: target: pscsi: Fix warning in pscsi_complete_cmd()
+    - media: ite-cir: check for receive overflow
+    - media: drivers: media: pci: sta2x11: fix Kconfig dependency on GPIOLIB
+    - media: imx: capture: Return -EPIPE from __capture_legacy_try_fmt()
+    - power: supply: bq27xxx: fix power_avg for newer ICs
+    - extcon: arizona: Fix some issues when HPDET IRQ fires after the jack has
+      been unplugged
+    - extcon: arizona: Fix various races on driver unbind
+    - media: media/saa7164: fix saa7164_encoder_register() memory leak bugs
+    - media: gspca/sq905.c: fix uninitialized variable
+    - power: supply: Use IRQF_ONESHOT
+    - drm/amdgpu: mask the xgmi number of hops reported from psp to kfd
+    - drm/amdkfd: Fix UBSAN shift-out-of-bounds warning
+    - drm/amdgpu : Fix asic reset regression issue introduce by 8f211fe8ac7c4f
+    - drm/amd/display: Fix UBSAN warning for not a valid value for type '_Bool'
+    - drm/amd/display: fix dml prefetch validation
+    - scsi: qla2xxx: Always check the return value of qla24xx_get_isp_stats()
+    - drm/vkms: fix misuse of WARN_ON
+    - scsi: qla2xxx: Fix use after free in bsg
+    - mmc: sdhci-pci: Add PCI IDs for Intel LKF
+    - ata: ahci: Disable SXS for Hisilicon Kunpeng920
+    - scsi: smartpqi: Correct request leakage during reset operations
+    - scsi: smartpqi: Add new PCI IDs
+    - scsi: scsi_dh_alua: Remove check for ASC 24h in alua_rtpg()
+    - media: em28xx: fix memory leak
+    - media: vivid: update EDID
+    - clk: socfpga: arria10: Fix memory leak of socfpga_clk on error return
+    - power: supply: generic-adc-battery: fix possible use-after-free in
+      gab_remove()
+    - power: supply: s3c_adc_battery: fix possible use-after-free in
+      s3c_adc_bat_remove()
+    - media: tc358743: fix possible use-after-free in tc358743_remove()
+    - media: adv7604: fix possible use-after-free in adv76xx_remove()
+    - media: i2c: adv7511-v4l2: fix possible use-after-free in adv7511_remove()
+    - media: i2c: tda1997: Fix possible use-after-free in tda1997x_remove()
+    - media: i2c: adv7842: fix possible use-after-free in adv7842_remove()
+    - media: platform: sti: Fix runtime PM imbalance in regs_show
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init
+    - media: gscpa/stv06xx: fix memory leak
+    - sched/fair: Ignore percpu threads for imbalance pulls
+    - drm/msm/mdp5: Configure PP_SYNC_HEIGHT to double the vtotal
+    - drm/msm/mdp5: Do not multiply vclk line count by 100
+    - drm/amdkfd: Fix cat debugfs hang_hws file causes system crash bug
+    - amdgpu: avoid incorrect %hu format string
+    - drm/amdgpu: fix NULL pointer dereference
+    - scsi: lpfc: Fix crash when a REG_RPI mailbox fails triggering a LOGO
+      response
+    - scsi: lpfc: Fix error handling for mailboxes completed in MBX_POLL mode
+    - scsi: lpfc: Remove unsupported mbox PORT_CAPABILITIES logic
+    - mfd: arizona: Fix rumtime PM imbalance on error
+    - scsi: libfc: Fix a format specifier
+    - s390/archrandom: add parameter check for s390_arch_random_generate
+    - ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer
+    - ALSA: hda/conexant: Re-order CX5066 quirk table entries
+    - ALSA: sb: Fix two use after free in snd_sb_qsound_build
+    - ALSA: usb-audio: Explicitly set up the clock selector
+    - ALSA: usb-audio: More constifications
+    - ALSA: usb-audio: Add dB range mapping for Sennheiser Communications Headset
+      PC 8
+    - ALSA: hda/realtek: GA503 use same quirks as GA401
+    - ALSA: hda/realtek: fix mic boost on Intel NUC 8
+    - ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops
+    - ALSA: hda/realtek: Add quirk for Intel Clevo PCx0Dx
+    - btrfs: fix race when picking most recent mod log operation for an old root
+    - arm64/vdso: Discard .note.gnu.property sections in vDSO
+    - Makefile: Move -Wno-unused-but-set-variable out of GCC only block
+    - virtiofs: fix memory leak in virtio_fs_probe()
+    - ubifs: Only check replay with inode type to judge if inode linked
+    - f2fs: fix to avoid out-of-bounds memory access
+    - mlxsw: spectrum_mr: Update egress RIF list before route's action
+    - openvswitch: fix stack OOB read while fragmenting IPv4 packets
+    - ACPI: GTDT: Don't corrupt interrupt mappings on watchdow probe failure
+    - NFS: Don't discard pNFS layout segments that are marked for return
+    - NFSv4: Don't discard segments marked for return in _pnfs_return_layout()
+    - Input: ili210x - add missing negation for touch indication on ili210x
+    - jffs2: Fix kasan slab-out-of-bounds problem
+    - powerpc/eeh: Fix EEH handling for hugepages in ioremap space.
+    - powerpc: fix EDEADLOCK redefinition error in uapi/asm/errno.h
+    - intel_th: pci: Add Alder Lake-M support
+    - tpm: efi: Use local variable for calculating final log size
+    - tpm: vtpm_proxy: Avoid reading host log when using a virtual device
+    - crypto: rng - fix crypto_rng_reset() refcounting when !CRYPTO_STATS
+    - md/raid1: properly indicate failure when ending a failed write request
+    - dm raid: fix inconclusive reshape layout on fast raid4/5/6 table reload
+      sequences
+    - fuse: fix write deadlock
+    - security: commoncap: fix -Wstringop-overread warning
+    - Fix misc new gcc warnings
+    - jffs2: check the validity of dstlen in jffs2_zlib_compress()
+    - Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
+    - x86/cpu: Initialize MSR_TSC_AUX if RDTSCP *or* RDPID is supported
+    - kbuild: update config_data.gz only when the content of .config is changed
+    - ext4: fix check to prevent false positive report of incorrect used inodes
+    - ext4: do not set SB_ACTIVE in ext4_orphan_cleanup()
+    - ext4: fix error code in ext4_commit_super
+    - media: dvbdev: Fix memory leak in dvb_media_device_free()
+    - media: dvb-usb: Fix use-after-free access
+    - media: dvb-usb: Fix memory leak at error in dvb_usb_device_init()
+    - media: staging/intel-ipu3: Fix memory leak in imu_fmt
+    - media: staging/intel-ipu3: Fix set_fmt error handling
+    - media: staging/intel-ipu3: Fix race condition during set_fmt
+    - usb: gadget: dummy_hcd: fix gpf in gadget_setup
+    - usb: gadget: Fix double free of device descriptor pointers
+    - usb: gadget/function/f_fs string table fix for multiple languages
+    - usb: dwc3: gadget: Fix START_TRANSFER link state check
+    - usb: dwc2: Fix session request interrupt handler
+    - tty: fix memory leak in vc_deallocate
+    - rsi: Use resume_noirq for SDIO
+    - tracing: Map all PIDs to command lines
+    - tracing: Restructure trace_clock_global() to never block
+    - dm persistent data: packed struct should have an aligned() attribute too
+    - dm space map common: fix division bug in sm_ll_find_free_block()
+    - dm integrity: fix missing goto in bitmap_flush_interval error handling
+    - dm rq: fix double free of blk_mq_tag_set in dev remove after table load
+      fails
+    - Linux 5.4.118
+  * Focal update: v5.4.117 upstream stable release (LP: #1928823)
+    - mips: Do not include hi and lo in clobber list for R6
+    - ACPI: tables: x86: Reserve memory occupied by ACPI tables
+    - ACPI: x86: Call acpi_boot_table_init() after acpi_table_upgrade()
+    - net: usb: ax88179_178a: initialize local variables before use
+    - igb: Enable RSS for Intel I211 Ethernet Controller
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_enqueue_hcmd()
+    - bpf: Fix masking negation logic upon negative dst register
+    - bpf: Fix leakage of uninitialized bpf stack under speculation
+    - avoid __memcat_p link failure
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_gen2_enqueue_hcmd()
+    - perf data: Fix error return code in perf_data__create_dir()
+    - perf ftrace: Fix access to pid in array when setting a pid filter
+    - ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX
+    - USB: Add reset-resume quirk for WD19's Realtek Hub
+    - platform/x86: thinkpad_acpi: Correct thermal sensor allocation
+    - scsi: ufs: Unlock on a couple error paths
+    - ovl: allow upperdir inside lowerdir
+    - perf/core: Fix unconditional security_locked_down() call
+    - vfio: Depend on MMU
+    - Linux 5.4.117
+  * r8152 tx status -71 (LP: #1922651) // Focal update: v5.4.117 upstream stable
+    release (LP: #1928823)
+    - USB: Add LPM quirk for Lenovo ThinkPad USB-C Dock Gen2 Ethernet
+  * Focal update: v5.4.116 upstream stable release (LP: #1928821)
+    - bpf: Move off_reg into sanitize_ptr_alu
+    - bpf: Ensure off_reg has no mixed signed bounds for all types
+    - bpf: Rework ptr_limit into alu_limit and add common error path
+    - bpf: Improve verifier error messages for users
+    - bpf: Refactor and streamline bounds check into helper
+    - bpf: Move sanitize_val_alu out of op switch
+    - bpf: Tighten speculative pointer arithmetic mask
+    - bpf: Update selftests to reflect new error states
+    - Linux 5.4.116
+  * Focal update: v5.4.115 upstream stable release (LP: #1927997)
+    - gpio: omap: Save and restore sysconfig
+    - pinctrl: lewisburg: Update number of pins in community
+    - arm64: dts: allwinner: Revert SD card CD GPIO for Pine64-LTS
+    - perf/x86/intel/uncore: Remove uncore extra PCI dev HSWEP_PCI_PCU_3
+    - perf/x86/kvm: Fix Broadwell Xeon stepping in isolation_ucodes[]
+    - perf auxtrace: Fix potential NULL pointer dereference
+    - HID: google: add don USB id
+    - HID: alps: fix error return code in alps_input_configured()
+    - HID: wacom: Assign boolean values to a bool variable
+    - ARM: dts: Fix swapped mmc order for omap3
+    - net: geneve: check skb is large enough for IPv4/IPv6 header
+    - s390/entry: save the caller of psw_idle
+    - xen-netback: Check for hotplug-status existence before watching
+    - cavium/liquidio: Fix duplicate argument
+    - csky: change a Kconfig symbol name to fix e1000 build error
+    - ia64: fix discontig.c section mismatches
+    - ia64: tools: remove duplicate definition of ia64_mf() on ia64
+    - x86/crash: Fix crash_setup_memmap_entries() out-of-bounds access
+    - net: hso: fix NULL-deref on disconnect regression
+    - USB: CDC-ACM: fix poison/unpoison imbalance
+    - Linux 5.4.115
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 17 May 2022 23:22:43 +0800
+
+linux-imx (5.4.0-1013.13) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_OPTEE=y by default on armhf too
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 22 Oct 2021 01:24:50 +0800
+
+linux-imx (5.4.0-1012.12) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix uart3 pinmux functions
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix pinconf for led shutdown & led
+      alarm clear gpios
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: configure uart1 dte mode for
+      RS485/touchflakes
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: add support for FRAM/SPI-NOR flash
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: add support for gpio-wdog
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: enable support for flexcan1
+    - [Config] CONFIG_ADIN_PHY=m
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: uart4 rs485 mode at boot by default
+    - SAUCE: mtd: spi-nor: add support for for Fujitsu MB85RQ4ML FRAM
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix pinmux conf for i2c4 bus
+    - [Config] updateconfigs for NXP/IMX controllers, MTD NOR support built-in
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: switch uart2 to rs485 port
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: stop passing uart2 as boot console
+      output
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: support push-button on led front board
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix bt & wifi power regulator
+      definitions
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add spi entries for common module p1/p2
+      & lte
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: set external rtc as default
+    - SAUCE: arm64: dts: imx8mn-venice-gw7902: set external rtc as default
+    - SAUCE: arm64: dts: imx8m*-venice-gw7902: add reserved memory areas for optee
+    - SAUCE: arm64: dts: imx8m*-venice-gw7902: add firmware entry for optee-tz
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: don't define gpio-hogs for uart-sel
+      pins
+
+  * Miscellaneous upstream changes
+    - can: dev: can_restart(): remove unused code
+    - can: rx-offload: fix long lines
+    - can: rx-offload: can_rx_offload_compare(): fix typo
+    - can: rx-offload: can_rx_offload_irq_offload_timestamp(): don't use
+      assignment in if condition
+    - can: rx-offload: can_rx_offload_reset(): remove no-op function
+    - can: rx-offload: Prepare for CAN FD support
+    - can: flexcan: use devm_platform_ioremap_resource() to simplify code
+    - can: flexcan: flexcan_irq_state(): only read timestamp if needed
+    - can: flexcan: rename macro FLEXCAN_IFLAG_MB() -> FLEXCAN_IFLAG2_MB()
+    - can: flexcan: flexcan_irq(): rename variable reg_iflag -> reg_iflag_rx
+    - can: flexcan: rename struct flexcan_priv::reg_imask{1,2}_default to
+      rx_mask{1,2}
+    - can: flexcan: remove TX mailbox bit from struct flexcan_priv::rx_mask{1,2}
+    - can: flexcan: convert struct flexcan_priv::rx_mask{1,2} to rx_mask
+    - can: flexcan: introduce struct flexcan_priv::tx_mask and make use of it
+    - can: flexcan: flexcan_read_reg_iflag_rx(): optimize reading
+    - can: flexcan: flexcan_irq(): add support for TX mailbox in iflag1
+    - can: flexcan: flexcan_mailbox_read() make use of flexcan_write64() to mark
+      the mailbox as read
+    - can: flexcan: fix spelling mistake "reserverd" -> "reserved"
+    - can: flexcan: sort include files alphabetically
+    - can: flexcan: flexcan_exit_stop_mode(): remove stray empty line
+    - can: flexcan: more register names
+    - can: flexcan: struct flexcan_regs: document registers not affected by soft
+      reset
+    - can: flexcan: quirks: get rid of long lines
+    - can: flexcan: Ack wakeup interrupt separately
+    - can: flexcan: flexcan_probe(): make regulator xceiver optional
+    - can: flexcan: Add check for transceiver maximum bitrate limitation
+    - can: flexcan: add correctable errors correction when HW supports ECC
+    - can: flexcan: add LPSR mode support
+    - can: flexcan: flexcan_set_bittiming(): move setup of CAN-2.0 bitiming into
+      separate function
+    - can: flexcan: use struct canfd_frame for CAN classic frame
+    - can: flexcan: add CAN-FD mode support
+    - can: flexcan: add ISO CAN FD feature support
+    - can: flexcan: add CAN FD BRS support
+    - can: flexcan: add Transceiver Delay Compensation support
+    - can: flexcan: add imx8qm support
+    - can: flexcan: add lx2160ar1 support
+    - can: flexcan: initialize all flexcan memory for ECC function
+    - can: flexcan: add flexcan driver for i.MX8MP
+    - can: flexcan: disable runtime PM if register flexcandev failed
+    - can: flexcan: remove ack_grp and ack_bit handling from driver
+    - can: flexcan: flexcan_setup_stop_mode(): add missing "req_bit" to stop mode
+      property comment
+    - serial: sc16is7xx: Replace zero-length array with flexible-array member
+    - sc16is7xx: Always use falling edge IRQ
+    - sc16is7xx: Use threaded IRQ
+    - sc16is7xx: Allow sharing the IRQ line
+    - sc16is7xx: Read the LSR register for basic device presence check
+    - sc16is7xx: Add flag to activate IrDA mode
+    - sc16is7xx: Set iobase to device index
+    - sc16is7xx: Defer probe if device read fails
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Thu, 21 Oct 2021 14:31:04 +0800
+
+linux-imx (5.4.0-1011.11) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: reserve memory for global dma usage
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: adjust ocram memory sections for optee-
+      lpm
+    - SAUCE: MLK-11488-1 driver: char: sema4: add sema4 support
+    - SAUCE: MLK-11488-2 arm: imx: add HAVE_IMX_AMP for imx6sx
+    - SAUCE: MLK-11488-4 arm: dts: imx6sx: add sema4 support
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add qspi restore node for
+      suspend/resume when M4 is enabled
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add mailbox support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: Add spi-[tx/rx]-bus-width for the FSL
+      QSPI controller
+    - [Config] CONFIG_IMX_SEMA4=y
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix simple-audio-card widget names
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable pixel pipeline module
+    - [Config] FLEXSPI, QUADSPI drivers as modules
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: OV5640 camera module is on i2c4
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: use unique labels instead of colour-ids
+      for gpio-leds
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix gpio-keys pinconfig defs
+    - SAUCE: media: mipi csi: add mixel's mipi csi driver
+    - SAUCE: media: mipi csi: add samsung's mipi csi support
+    - SAUCE: media: mipi csi: accommodate the driver to framework's change
+    - SAUCE: mxc-jpeg: Add v4l2 driver for i.MX8 CAST IP JPEG Encoder/Decoder
+    - SAUCE: mxc-jpeg: Add support for multi power domain
+    - SAUCE: mxc-jpeg: Build mxc-jpeg as module, by default
+    - SAUCE: media: mxc-jpeg: jpeg: Replace stracpy with strscpy
+    - SAUCE: mxc-jpeg: Fix warning at build, for EXPORT_SYMBOL on static variable
+    - SAUCE: MLK-22835: mxc-jpeg: jpeg decoder stuck due to race condition
+    - SAUCE: media: IPU: add IPU csi and prp driver
+    - SAUCE: media: v4l2: add int device framework for backward support
+    - SAUCE: media: capture: add mxc v4l2 capture driver
+    - SAUCE: media: add Kconfig and Makefile for the capture driver
+    - SAUCE: media: add adv7180 video decoder driver
+    - SAUCE: media: v4l2 capture: add v4l2 capture driver based on csi
+    - SAUCE: media: mx6s_capture: accommodate the driver to framework's change
+    - SAUCE: media: v4l2: vadc: Enable vadc driver
+    - SAUCE: media: capture: add ov5640 mipi and parallel driver
+    - SAUCE: media: capture: add ov5640 mipi and parallel driver of subdev version
+    - SAUCE: media: ov5640: fix kernel warning when no camera is plugged in
+    - SAUCE: media: ov5640 mipi: fix kernel warning when no camera is plugged in
+    - SAUCE: media: ov5640 mipi v2: fix kernel warning when no camera is plugged
+      in
+    - SAUCE: media: ov5640 v2: fix kernel warning when no camera is plugged in
+    - SAUCE: media: platform: mxc: capture: ov5640: Disable regulators in
+      ov5640_remove()
+    - SAUCE: LF-237 media: ov5640_mipi: fix regulator dump when i2c access for
+      camera fail
+    - SAUCE: media: platform: mxc: output: Forward IPUv3 V4L2 output driver from
+      imx_4.19.y
+    - SAUCE: media: v4l2: add pxp_v4l2 driver
+    - SAUCE: LF-135 media: mx6s_capture: fix kernel dump when start two instances
+      of capture
+    - SAUCE: LF-300-1 media: mipi csi: make the csi clock usecount to 0 when it's
+      not used
+    - SAUCE: LF-300-2 media: mipi csi: make the csi clock usecount to 0 when it's
+      not used
+    - SAUCE: LF-482 media: mipi csi: fix build warning
+    - SAUCE: MLK-23712: media: capture: add get/set_register callback
+    - SAUCE: LF-1599 media: platform: mxc_vout: Do not check 's->r.width/height<0'
+      in ->vidioc_s_selection
+    - SAUCE: LF-1561 check return value of v4l2_async_notifier_add_subdev
+    - SAUCE: MLK-24261 media: mipi csi: fix kernel dump when do module removal
+    - SAUCE: MLK-24389 media: mx6s_capture: use vb2_fop_mmap instead
+    - SAUCE: LF-1564 media: capture: check return value of devm_kzalloc against
+      NULL
+    - SAUCE: LF-1711 media: mipi csi: check return value of
+      v4l2_async_notifier_add_subdev
+    - SAUCE: LF-1583: mxc-jpeg: Fix possible null pointer dereference
+    - SAUCE: LF-1571: mxc-jpeg: Fix result independent of operands
+    - SAUCE: media: staging: csi: add mipi csi driver support for IMX8
+    - SAUCE: staging: media: imx: add video ops for imx8 mipi csi subdev
+    - SAUCE: staging: media: imx: add V4L2 subdev driver for MIPI CSI2 of Samsung
+    - SAUCE: media: staging: imx: add isi driver support for imx8qm/qxp
+    - SAUCE: MLK-21985-8 media: isi: fix build for next 20190607 upgrade
+    - SAUCE: media: isi: fix boot warning by intialize device_caps
+    - SAUCE: media: staging: imx: add isi core driver support for imx8qm/qxp
+    - SAUCE: media: staging: imx: add isi capture driver support for imx8qm/qxp
+    - SAUCE: media: staging: imx: add V4L2 memory to memory driver for ISI of
+      imx8qxp/qm
+    - SAUCE: staging: media: imx: enable ISI for imx8mn platform
+    - SAUCE: staging: media: imx: add g_parm/s_parm for imx8 capture device
+    - SAUCE: media: staging: imx: add driver for GMSL MAX9286 device
+    - SAUCE: LF-116: staging: media: imx: fix no enum_frameinterval result issue
+    - SAUCE: media: staging: imx: add media device driver support for IMX8
+    - SAUCE: staging: media: imx: add parallel capture interface driver for
+      imx8qxp
+    - SAUCE: staging: media: imx: add video ops for imx8 parallel subdev
+    - SAUCE: LF-101: staging: media: imx: fix XR24 format R and B are opposite
+      issue
+    - SAUCE: LF-356: media: imx8 isi: fix buffer active bit change for QXP C0
+    - SAUCE: LF-364: media: isi: correct capabilities for ISI m2m video device
+    - SAUCE: LF-79: staging: media: imx: replace s_parm/g_parm with
+      s/g_frame_interval
+    - SAUCE: LF-433: staging: media: imx: refine mipi csi2 driver for Samsung
+    - SAUCE: LF-467: media: imx: isi: fix some typo issues
+    - SAUCE: LF-510: staging: media: imx: add s/g_frame_interval support for
+      max9286
+    - SAUCE: LF-486: staging: media: imx: fix uninitialized variable
+    - SAUCE: LF-221: staging: media: imx: fix potential memory out of bound
+    - SAUCE: LF-762: media: correct multi instance management for CSI camera
+    - SAUCE: MLK-23227-3: media: imx: add ISI IER register as platform data
+    - SAUCE: MLK-23227-4: media: imx: add input image source port selection as
+      platform data
+    - SAUCE: MLK-23227-5: media: imx: refine soc version match method for ISI
+    - SAUCE: MLK-23227-6: media: imx: add driver support for ISI of i.MX8MP
+    - SAUCE: MLK-23227-7: media: imx: add multi instance for MIPI CSI driver
+    - SAUCE: MLK-23227-8: media: imx: remove CSI PHY clock operation
+    - SAUCE: MLK-23227-9: media: imx: use no-reset-control property in ISI of
+      i.MX8MP
+    - SAUCE: MLK-23227-11: media: imx: set panic threshold in ISI
+    - SAUCE: MLK-23358-1: media: imx8: fix dereferencing null pointer issue
+    - SAUCE: MLK-23358-2: media: imx: fix variable uninitialized issue
+    - SAUCE: LF-1089: media: imx: fix 1024x768@15 camera issue for imx8qm and qxp
+    - SAUCE: MLK-23578-1: media: m2m: enable ISI m2m feature for i.MX865
+    - SAUCE: MLK-23750-2: media: csi: fix ISI_0, CSI_0 can't enter lp when suspend
+    - SAUCE: MLK-23750-3: media: pi: fix ISI_0, PI_0 can't enter lp when suspend
+    - SAUCE: MLK-23860: media: imx: improve calculation for csi RXHS_SETTLE
+      parameter
+    - SAUCE: MLK-24375-01: mixel: csi2: detach power domain when driver removed
+    - SAUCE: MLK-24375-02: imx: pi: detach power domain when pi drvier removed
+    - SAUCE: MLK-24376: isi: core: depopulate child device when parent driver
+      removed
+    - SAUCE: LF-1409-01: media: imx: isi: export functions in imx8-isi-hw.c file
+    - SAUCE: LF-1409-02: media: isi: cap: export mxc_isi_cap_frame_write_done
+    - SAUCE: LF-1409-03: media: isi: m2m: export mxc_isi_m2m_frame_write_done
+    - SAUCE: LF-1409-04: media: isi: move two methods in isi core driver to hw
+      driver
+    - SAUCE: LF-1409-05: media: isi: config ISI HW driver as a separate driver
+    - SAUCE: LF-1409-06: media: isi: cap: config capture driver as tristate
+    - SAUCE: LF-1409-07: media: isi: m2m: config mem2mem driver as tristate
+    - SAUCE: LF-1409-08: media: isi: core: config ISI core driver as tristate
+    - SAUCE: MLK-24494-1: staging: media: csi: reuse csi driver for isp
+    - SAUCE: MLK-24494-4: staging: media: imx8: work around to support isi + isp
+      dual camera
+    - SAUCE: MLK-24514-1: staging: media: samsung csi: print message when fail to
+      get gpr
+    - SAUCE: MLK-24696: media: csi: return error when no command support
+    - SAUCE: MLK-24745: media: isi: fix pyeiq can't detect camera device
+    - SAUCE: MLK-24746: media: imx8: return directly for independent entity
+    - SAUCE: MLK-24981: media: isi: correct ISI chain buffer mask value
+    - SAUCE: MLK-24982: media: isi: disable ISI channel clock after stream off
+    - SAUCE: MLK-24983-01: media: isi: remove redundant code for clean the list
+    - SAUCE: MLK-24983-02: isi: use list_del_init instead of list_del
+    - SAUCE: MLK-24984: isi: use spin_lock_irqsave in irq handler to disable
+      interrupt
+    - SAUCE: MLK-24986: media: isi: add 4K support for iMX8MN ISI
+    - SAUCE: MLK-24987: media: isi: align discard buffer size to page size
+    - SAUCE: MLK-25000-1: media: csi: Enable V4L2_SUBDEV_FL_HAS_DEVNODE flag
+    - SAUCE: MLK-25027-2: media: isi: add workaround for iMX865 ISI to support 4K
+    - SAUCE: MLK-25027-3: media: isi: remove "fsl,chain_buf" property parse
+    - SAUCE: MLK-25027-4: media: isi: remove 4K feature for ISI channel1
+    - SAUCE: MLK-25039-01: media: isi: m2m: use V4L2 RGBA32 format define in V4L2
+      framework
+    - SAUCE: MLK-25041: media: imx8: media-dev: return if media device has been
+      registered
+    - SAUCE: LF-2474: media: samsung csi: fix string overflow issue
+    - SAUCE: MLK-9662 [V4L2 Capture] Revert patch to re-add support for
+      _G_CHIP_IDENT
+    - SAUCE: MLK-21770: media: v4l: Add packed YUV444 24bpp pixel format
+    - SAUCE: MLK-24477-1:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: enable color
+      description in vui
+    - SAUCE: media: mx6s_capture: remove imx-busfreq support
+    - SAUCE: MMFMWK-7549 [media] videobuf: store field and timestamp when queue
+      USERPTR buffer
+    - SAUCE: media: v4l2: export video_usercopy function
+    - SAUCE: Revert "media: v4l2-ioctl: clear fields in s_parm"
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: switch to fslc mxc csi platform driver
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: switch to ov5640_v2 mxc csi platform
+      driver
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: use clk names that csi fslc driver
+      expects
+    - SAUCE: clk: imx6sx: keep OCRAM_S always ON
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add pxp_v4l2_out support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: let sound card driver control codec clk
+    - [Config] updateconfigs, enable fslc camera drivers, disable upstream
+      versions
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add pinctrl hogs for board_id, run led
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: usb2 host mode for lte-cellular module
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: rs485 uarts are full-duplex with hw
+      flow control
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: update gpio hogs for common port 1,2
+      uart_sel & ttl/rs232 port
+    - SAUCE: clk: imx6sx: explicitly gate gpmi_io & qspi2 clks during init
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable adc support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: cleanup wifi/bt regulators
+    - SAUCE: MLK-13793-6 regulator: anatop: fix min dropout for bypass mode
+    - SAUCE: MLK-23562: regulator: core: adjust supply voltage in bypass
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add power domain for csi
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: allow ldo-bypass for gpc power domain
+    - SAUCE: MLK-22986-1: soc: imx: gpc: add ldo-bypass
+
+  * Miscellaneous upstream changes
+    - Revert "drm/imx/dcss: allow using nearest neighbor interpolation scaling"
+    - Revert "drm/imx/dcss: fix coccinelle warning"
+    - Revert "drm/imx/dcss: fix rotations for Vivante tiled formats"
+    - Revert "drm/imx/dcss: fix unused but set variable warnings"
+    - Revert "drm/imx/dcss: fix compilation issue on 32bit"
+    - Revert "drm/imx/dcss: use drm_bridge_connector API"
+    - Revert "drm/imx: Add initial support for DCSS on iMX8MQ"
+    - Revert "UBUNTU: SAUCE: ARM: dts: imx6sx-x6med35-som: disable rpmsg, don't
+      reserve memory"
+    - Revert "media: v4l2-subdev.h: remove obsolete g/s_parm"
+    - Revert "UBUNTU: [Config] CONFIG_REGULATOR_ANATOP=y on imx6 based platforms"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Tue, 21 Sep 2021 01:54:41 +0800
+
+linux-imx (5.4.0-1010.10) focal; urgency=medium
+
+  * Miscellaneous upstream changes
+    - rtc: m41t80: set range
+    - arm64: dts: imx8m*-venice-gw7902: fix M2_RST# gpio
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 06 Sep 2021 16:33:15 +0800
+
+linux-imx (5.4.0-1009.9) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: fix phandle node definition for bwm-
+      beeper
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: cleanup re-init of i2c2 properties
+    - SAUCE: arm64: dts: imx8mp: support x8high35 bms
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: only emmc, crypto & soc are on the SOM
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add rts-gpios for rs485 uarts
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add gpio-hogs for ttl/rs232 uart_sel,
+      rs485 common port sel
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: ensure P11,P12 are set in rs485 mode
+      from boot
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable s1, s2 push-buttons as wakeup-
+      source
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: support OV5640 camera sensor on csi0
+    - [Config] support OV5640 cmos camera sensors
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: reduce pwm-beeper freq
+    - [Config] disable unused audio codec drivers
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix audmux pinconf
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: support nau8822 audio with simple-
+      sound-card
+    - [Config] CONFIG_SND_SOC_NAU8822=m
+    - [Config] enable IMX PXP, CODA
+    - [Config] DM_CRYPT, SHA256/512, ARMv7/8 AES built-in
+    - SAUCE: arm64: dts: imx8mp: x8high-som: define 2G memory properly
+    - SAUCE: arm64: dts: imx8mp: x8high-som: rename 35som status led node
+    - SAUCE: arm64: dts: imx8mp: x8high-som: rename regulators as per the dt-
+      schema
+    - SAUCE: ARM: dts: imx8mp-x8high-bms: disable rts-gpio for uart2 to enable
+      serial console
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: ldo5 1v8 to power BM28 SDIO VIO
+    - [Config] CONFIG_OF_NUMA=y by default
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: reserve memory for global dma usage
+    - CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C=m
+
+  * Miscellaneous upstream changes
+    - ASoC: fsl: Replace HTTP links with HTTPS ones
+    - arm64: dts: imx8mp: Add dsp node
+    - arm64: dts: imx8mp: remove fallback compatible string for FlexCAN
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Sun, 22 Aug 2021 22:35:14 +0800
+
+linux-imx (5.4.0-1008.8) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] add canonical-hwe-team ppa to get abis
+
+  * Miscellaneous upstream changes
+    - arm64: dts: imx8mn-venice-gw7901: update gpio for revision-B board
+    - i2c: imx: support slave mode for imx I2C driver
+    - arm64: dts: imx8m*-venice-gw7902: fix phy configuration
+    - arm64: dts: imx8m*-venice-gw7902: fix phy configuration for 5.4 kernel
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Wed, 04 Aug 2021 22:58:57 +0800
+
+linux-imx (5.4.0-1007.7) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: only pmic, emmc, crypto & soc are on
+      the SOM
+    - SAUCE: extcon: poll cable status using timer
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: remove optional vbus supply to get
+      usb working
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: read eqos eth mac addr from ocotp-
+      nvmem
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: read fec1/2 eth mac addrs from nvmem-
+      ocotp
+
+  * Miscellaneous upstream changes
+    - usb: dwc3: imx8mp: fix error return code in dwc3_imx8mp_probe()
+    - usb: dwc3: ep0: fix NULL pointer exception
+    - usb: dwc3: core: fix kernel panic when do reboot
+    - usb: dwc3: create debugfs directory under usb root
+    - usb: dwc3: Disable phy suspend after power-on reset
+    - usb: dwc3: debug: Remove newline printout
+    - usb: dwc3: of-simple: add a shutdown
+    - usb: dwc3: gadget: Don't send unintended link state change
+    - usb: dwc3: gadget: Set link state to RX_Detect on disconnect
+    - usb: dwc3: gadget: Clear DCTL.ULSTCHNGREQ before set
+    - usb: dwc3: gadget: Remove END_TRANSFER delay
+    - usb: dwc3: Registering a role switch in the DRD code.
+    - usb: dwc3: Add support for role-switch-default-mode binding
+    - usb: dwc3: Rework clock initialization to be more flexible
+    - usb: dwc3: Rework resets initialization to be more flexible
+    - usb: dwc3: core: don't do suspend for device mode if already suspended
+    - usb: dwc3: Fix GTXFIFOSIZ.TXFDEP macro name
+    - usb: dwc3: select USB_ROLE_SWITCH
+    - usb: dwc3: support continuous runtime PM with dual role
+    - usb: dwc3: gadget: Give back staled requests
+    - usb: dwc3: gadget: Remove unnecessary checks
+    - usb: dwc3: gadget: Refactor dwc3_gadget_ep_dequeue
+    - usb: dwc3: drd: Don't free non-existing irq
+    - usb: dwc3: core: Use role-switch default dr_mode
+    - usb: dwc3: gadget: Store resource index of start cmd
+    - usb: dwc3: gadget: Issue END_TRANSFER to retry isoc transfer
+    - usb: dwc3: gadget: WARN on no-resource status
+    - usb: dwc3: use true,false for dwc->otg_restart_host
+    - usb: dwc3: gadget: make starting isoc transfers more robust
+    - usb: dwc3: gadget: add frame number mask
+    - usb: dwc3: gadget: Refactor ep command completion
+    - usb: dwc3: gadget: Introduce a DWC3 VBUS draw callback
+    - usb: dwc3: gadget: Preserve UDC max speed setting
+    - usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression
+    - cpufreq: imx: Select NVMEM_IMX_OCOTP
+    - cpufreq: Initialize the governors in core_initcall
+    - cpufreq: Make cpufreq_global_kobject static
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Sun, 11 Jul 2021 20:48:24 +0800
+
+linux-imx (5.4.0-1006.6) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx: Add i.mx8mn Gateworks gw7902 dts support
+    - SAUCE: arm64: dts: imx8mn: gw7902: disable gpc, gpu & mu nodes
+    - SAUCE: arm64: dts: imx8mn: gw7902: update usbotg1 clks, clk parents
+    - [Packaging] ignore bpfilter module during crossbuild
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 05 Jul 2021 21:01:45 +0800
+
+linux-imx (5.4.0-1005.5) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: x8high35-pdk: correct copyright in SPDX license ident
+    - [Packaging] Ignore if bpfilter module is missing
+    - SAUCE: ARM: dts: imx: add support for X6MED-35 PDK
+    - [Config] Disable iMX6SL/SLL iMX7D/ULP SoC's
+    - [Packaging] fix armhf imx flavour variables
+    - [Config] remoteproc, rpmsg drivers to be built-in
+    - [Config] disable lpae support for imx6(armhf) systems
+    - [Config] CONFIG_REMOTEPROC_CDEV=y
+    - [Config] cleanup power,cpugreq & clk related configs for armhf
+    - [Config] CONFIG_MMC_SDHCI_ESDHC_IMX=y, CONFIG_MMC_SDHCI_OF_ESDHC=y
+    - [Config] updateconfigs for earlyprintk on imx6sx uart1"
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: available memory to linux is ~511MiB
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add reserved memory for rpmsg
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add rpmsg node for imx6sx
+    - [Config] CONFIG_FEC=m
+    - [Config] CONFIG_REGULATOR_ANATOP=y on imx6 based platforms
+    - SAUCE: ARM: dts: imx6sx-x6med35: fix pinctrl for USB_CC interrupt
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add pinctrl defs for fec rmii support
+    - [Config] CONFIG_SPI_FSL_QUADSPI=y, CONFIG_SPI_FSL_LPSPI=y
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix dt config for usb_otg1
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: usbotg2 config for LTE expansion
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: disable rpmsg, don't reserve memory
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: disable qspi nand-flash for now
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: Assign corresponding power supply for
+      LDOs
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add 5v, 3v3 psu regulators
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable wdog1
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add aliases for watchdog devices
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: disable anatop-regulator
+
+  * Miscellaneous upstream changes
+    - ARM: dts: imx7: Unify temp-grade and speed-grade nodes
+    - ARM: dts: imx: Replace "simple-bus" with "simple-mfd" for anatop
+    - ARM: dts: imx: use generic name bus
+    - ARM: dts: imx: make gpt node name generic
+    - ARM: dts: imx: make kpp node name generic
+    - ARM: dts: imx: make clks node name generic
+    - ARM: dts: imx6sx: Improve UART pins macro defines
+    - ARM: dts: imx6sx: Add missing UART RTS/CTS pins mux
+    - ARM: dts: imx6sx-nitrogen6sx: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-sabreauto: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-sdb: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-softing-vining-2000: Use new pin names with DCE/DTE for
+      UART pins
+    - ARM: dts: imx6sx-udoo-neo: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx: make wdog node name generic
+    - ARM: dts: imx: Align ocotp node name
+    - ARM: dts: imx6sx-softing-vining-2000: Enable PCI support
+    - ARM: dts: imx: Make iomuxc node name generic
+    - ARM: dts: imx: add nvmem property for cpu0
+    - dt-bindings: fec: update the gpr property
+    - ARM: dts: imx: add ethernet stop mode property
+    - ARM: dts: imx6qdl: Use nvmem interface to get fuse data
+    - ARM: dts: imx6sl: Use nvmem interface to get fuse data
+    - ARM: dts: imx: Make tempmon node as child of anatop node
+    - ARM: dts: imx: change ocotp node name on i.MX6/7 SoCs
+    - ARM: dts: imx: change ocotp node name on MXS SoCs
+    - ARM: dts: imx: change iim node name on i.MX SoCs
+    - ARM: dts: imx6qdl: Remove invalid interrupt for GPC node
+    - ARM: dts: imx: Change sdhci node name on i.MX27/i.MX31 SoCs
+    - ARM: dts: imx: Change esdhc node name on i.MX2/i.MX3/i.MX5 SoCs
+    - ARM: dts: imx: Change usdhc node name on i.MX6/i.MX7 SoCs
+    - ARM: dts: imx6sll: Make ssi node name same as other platforms
+    - ARM: dts: imx6sx: Enable ASRC device
+    - ARM: dts: imx6sx-sdb: Add SPDIF support
+    - ARM: dts: imx6sx-sabreauto: Add SPDIF support
+    - ARM: dts: imx6sx-sabreauto: Add cs42888 sound card support
+    - ARM: dts: imx6sx-sdb: Add MQS support
+    - ARM: dts: imx: Align L2 cache-controller nodename with dtschema
+    - ARM: dts: imx6ul: Add ASRC device node
+    - ARM: dts: imx: default to #pwm-cells = <3> in the SoC dtsi files
+    - ASoC: bindings: fsl-asoc-card: Add compatible string for MQS
+    - ASoC: fsl-asoc-card: Add MQS support
+    - ASoC: bindings: fsl_spdif: Add new compatible string for imx6sx
+    - ASoC: fsl_spdif: Add support for imx6sx platform
+    - ASoC: fsl_spdif: Add pm runtime function
+    - ARM: dts: imx6sx: fix the pad QSPI1B_SCLK mux mode for uart3
+    - ARM: dts: imx6sx-sdb: Add headphone detection for sound card
+    - ARM: dts: imx6/7: sync fsl,stop-mode with current flexcan driver
+    - ARM: dts: imx: add usb alias
+    - ARM: dts: imx: Change gpmi nand node name to nand-controller
+    - ARM: dts: imx: make src node name generic
+    - ARM: dts: imx: align name for crypto node and child nodes
+    - remoteproc: use struct_size() helper
+    - remoteproc: Use size_t type for len in da_to_va
+    - remoteproc: Use size_t instead of int for rproc_mem_entry len
+    - remoteproc: Use u64 type for boot_addr
+    - remoteproc: Add elf helpers to access elf64 and elf32 fields
+    - remoteproc: Rename rproc_elf_sanity_check for elf32
+    - remoteproc: Add elf64 support in elf loader
+    - remoteproc: Allow overriding only sanity_check
+    - remoteproc: Adapt coredump to generate correct elf type
+    - remoteproc: re-check state in rproc_trigger_recovery()
+    - remoteproc: remoteproc debugfs file fixes
+    - remoteproc: return error for bad "recovery" debugfs input
+    - remoteproc: Traverse rproc_list under RCU read lock
+    - remoteproc: Introduce "panic" callback in ops
+    - remoteproc: qcom: q6v5: Add common panic handler
+    - remoteproc: qcom: Introduce panic handler for PAS and ADSP
+    - remoteproc: core: Remove casting to rproc_handle_resource_t
+    - remoteproc: introduce is_iomem to rproc_mem_entry
+    - remoteproc: convert to DEFINE_SHOW_ATTRIBUTE
+    - remoteproc: Split firmware name allocation from rproc_alloc()
+    - remoteproc: Simplify default name allocation
+    - remoteproc: add rproc_coredump_set_elf_info
+    - remoteproc: sysmon: Add ability to send type of notification
+    - remoteproc: Use kstrdup_const() rather than kstrdup()
+    - remoteproc: Restructure firmware name allocation
+    - remoteproc: Split rproc_ops allocation from rproc_alloc()
+    - remoteproc: Get rid of tedious error path
+    - remoteproc: Use a local copy for the name field
+    - remoteproc: Add device-managed variants of rproc_alloc/rproc_add
+    - remoteproc: remove rproc_elf32_sanity_check
+    - remoteproc: Add prepare and unprepare ops
+    - remoteproc: Add missing '\n' in log messages
+    - remoteproc: Fix an error code in devm_rproc_alloc()
+    - remoteproc: remoteproc_core: Use 'gnu_printf' format notation
+    - remoteproc: Add new RPROC_DETACHED state
+    - remoteproc: Add new attach() remoteproc operation
+    - remoteproc: Introducing function rproc_attach()
+    - remoteproc: Introducing function rproc_actuate()
+    - remoteproc: Introducing function rproc_validate()
+    - remoteproc: Refactor function rproc_boot()
+    - remoteproc: Refactor function rproc_trigger_auto_boot()
+    - remoteproc: Refactor function rproc_free_vring()
+    - remoteproc: Properly handle firmware name when attaching
+    - remoteproc: Make function rproc_resource_cleanup() public
+    - remoteproc: Move coredump functionality to a new file
+    - remoteproc: Pass size and offset as arguments to segment dump function
+    - remoteproc: Add inline coredump functionality
+    - remoteproc: Add coredump debugfs entry
+    - remoteproc: Introduce rproc_of_parse_firmware() helper
+    - remoteproc: Add remoteproc character device interface
+    - remoteproc: core: Register the character device interface
+    - remoteproc: Change default dump configuration to "disabled"
+    - remoteproc: coredump: Add minidump functionality
+    - remoteproc: add is_iomem to da_to_va
+    - remoteproc: imx_rproc: correct err message
+    - remoteproc: imx_rproc: use devm_ioremap
+    - remoteproc: imx_rproc: add i.MX specific parse fw hook
+    - remoteproc: imx_rproc: support i.MX8MQ/M
+    - remoteproc: imx_rproc: ignore mapping vdev regions
+    - remoteproc: imx_proc: enable virtio/mailbox
+    - remoteproc: imx_rproc: fix return value check in imx_rproc_addr_init()
+    - remoteproc: Remove useless check in rproc_del()
+    - remoteproc: Rename function rproc_actuate()
+    - remoteproc: Add new RPROC_ATTACHED state
+    - remoteproc: Properly represent the attached state
+    - remoteproc: Add new get_loaded_rsc_table() to rproc_ops
+    - remoteproc: imx_rproc: fix build error without CONFIG_MAILBOX
+    - remoteproc: imx_rproc: add missing of_node_put
+    - remoteproc: imx_rproc: enlarge IMX7D_RPROC_MEM_MAX
+    - remoteproc: imx_rproc: move memory parsing to rproc_ops
+    - remoteproc: imx_rproc: support remote cores booted before Linux Kernel
+    - spi: spi-fsl-qspi: Reduce devm_ioremap size to 4 times AHB buffer size
+    - spi: spi-fsl-qspi: Fix return value check of devm_ioremap() in probe
+    - regulator: anatop: Lower error message level for -EPROBE_DEFER
+    - regulator: anatop: Constify anatop_core_rops
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 02 Jul 2021 09:32:58 +0800
+
+linux-imx (5.4.0-1004.4) focal; urgency=medium
+
+  * Bump ABI: 5.4.0-1004.4
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 18 Jun 2021 18:15:48 +0800
+
+linux-imx (5.4.0-1003.3) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM=m
+    - [Config] CONFIG_IMX8MM_THERMAL=m, CONFIG_IMX_SC_THERMAL=m
+    - [Config] CONFIG_NVMEM_IMX_OCOTP_SCU=y, CONFIG_NVMEM_SNVS_LPGPR=y
+    - SAUCE: arm64: dts: fix brcm sdio wifi compatible string
+    - SAUCE: arm64: dts: imx8mp: specify dma-ranges
+    - SAUCE: usb: dwc3: imx8mp: detect dwc3 child nodes with name "usb*"
+    - SAUCE: arm64: dts: imx8mp: A53 cpufreq opp table
+    - SAUCE: arm64: dts: imx8mp: add nvmem entries for A53 speed-grade
+    - SAUCE: arm64: dts: imx8mp: Enable cpu-idle driver
+    - SAUCE: cpufreq: Use imx-cpufreq-dt for i.MX8MP's speed grading
+    - SAUCE: arm64: dts: x8high35-pdk: fix node for wifi sdio card
+    - [Config] select ondemand gov as default
+    - SAUCE: arm64: dts: imx8mp: configure gpio1_01 for ecspi1-cs
+    - SAUCE: arm64: dts: x8high35-pdk: fix cs-pins for uart_exp ports
+    - SAUCE: arm64: dts: x8high35-pdk: enable uart3
+    - SAUCE: arm64: dts: imx8mp: update i2c addr for crypto chip as per HW
+      recommendation
+    - SAUCE: arm64: dts: imx8mm: add gpc iomux compatible
+    - SAUCE: arm64: dts: imx: Add i.mx8mm Gateworks gw7902 dts support
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: add PCI support
+    - [Config] CONFIG_LAN743X=m
+    - SAUCE: regmap: irq: fix ack-invert
+    - [Config] CONFIG_GPIO_PCA953X=y, CONFIG_GPIO_PCA953X_IRQ=y
+    - [Config] updateconfigs for watchdog support
+    - SAUCE: MLK-22404-02 soc: imx: Add power domain driver support for i.mx8m
+      family
+    - SAUCE: MLK-22404-03 arm64: dts: freescale: Add power domain nodes for
+      i.mx8mm
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: add power-domain configs for USB
+      controllers
+    - [Config] CONFIG_IMX8M_PM_DOMAINS=y
+    - SAUCE: clk: imx: imx8mm: set the parent clks of pcie
+    - SAUCE: PCI: imx: set the according disable signal
+    - SAUCE: PCI: imx: enable imx8qm/qxp pcie support
+    - SAUCE: pci: imx: fix build failure due to 5.1 RC7 upgrade
+    - SAUCE: PCI: imx: msi enable bit of rc should be set in resume
+    - SAUCE: PCI: imx: set up the hsio regmap itself
+    - SAUCE: PCI: imx: enable imx8mm pcie support
+    - [Config] CONFIG_PCIE_DW_*=y
+
+  * Miscellaneous upstream changes
+    - thermal: of-thermal: add API for getting sensor ID from DT
+    - thermal: imx_sc: add i.MX system controller thermal support
+    - thermal: imx8mm: Add support for i.MX8MM thermal monitoring unit
+    - thermal: imx_sc_thermal: Align imx sc thermal msg structs to 4
+    - thermal: imx_sc_thermal: Fix incorrect data type
+    - thermal: imx8mm: Add i.MX8MP support
+    - thermal: imx8mm: Fix build warning of incorrect argument type
+    - dt-bindings: firmware: imx: Move system control into dt-binding headfile
+    - thermal: imx_sc_thermal: Add hwmon support
+    - thermal: imx8mm: Replace zero-length array with flexible-array
+    - thermal: imx8mm: Support module autoloading
+    - thermal: imx8mm: Print the correct error code
+    - thermal: imx8mm: Disable the clock on probe failure
+    - arm64: dts: imx8m: add NVMEM provider and consumer to read soc unique ID
+    - nvmem: imx: scu: support hole region check
+    - nvmem: imx: scu: support write
+    - nvmem: imx: scu: fix dependency in Kconfig
+    - nvmem: imx: scu: fix write SIP
+    - nvmem: imx: scu: correct the fuse word index
+    - nvmem: imx: ocotp: introduce ocotp_ctrl_reg
+    - nvmem: imx: ocotp: add i.MX8MP support
+    - nvmem: imx-ocotp: Drop unnecessary initializations
+    - nvmem: imx-ocotp: Improve logic to save many code lines
+    - nvmem: imx-ocotp: add support for the unaliged word count
+    - arm64: dts: imx8mp: Use the correct name for child node "snps, dwc3"
+    - Revert "soc: imx8m: change to use platform driver"
+    - arm64: dts: imx8mp: add flexspi node
+    - arm64: dts: imx8mp: Remove the reference to audio ipg clock on imx8mp
+    - spi: nxp-fspi: Use devm API to fix missed unregistration of controller
+    - spi: fspi: enable fspi on imx8qxp and imx8mm
+    - spi: fspi: dynamically alloc AHB memory
+    - spi: spi-nxp-fspi: Enable the Octal Mode in MCR0
+    - spi: spi-nxp-fspi: Add support for imx8mm, imx8qxp
+    - spi: spi-nxp-fspi: Fix a NULL vs IS_ERR() check in probe
+    - spi: spi-nxp-fspi: Add ACPI support
+    - spi: spi-nxp-fspi: Add support for IP read only
+    - spi: spi-nxp-fspi: Add imx8dxl driver support
+    - spi: spi-nxp-fspi: Implement errata workaround for LS1028A
+    - spi: spi-nxp-fspi: Add imx8dxl support
+    - spi: fspi: enable fspi driver for on imx8mp
+    - dt-bindings: spi: add compatible entry for imx8mp in FlexSPI controller
+    - soc: imx: gpcv2: move to more ideomatic error handling in probe
+    - soc: imx: gpcv2: move domain mapping to domain driver probe
+    - soc: imx: gpcv2: switch to clk_bulk_* API
+    - soc: imx: gpcv2: split power up and power down sequence control
+    - soc: imx: gpcv2: wait for ADB400 handshake
+    - soc: imx: gpcv2: add runtime PM support for power-domains
+    - soc: imx: gpcv2: allow domains without power-sequence control
+    - soc: imx: gpcv2: add support for optional resets
+    - dt-bindings: power: add defines for i.MX8MM power domains
+    - soc: imx: gpcv2: add support for i.MX8MM power domains
+    - soc: imx: gpcv2: Add support for missing i.MX8MM VPU/DISPMIX power domains
+    - soc: imx: gpcv2: move reset assert after requesting domain power up
+    - dt-bindings: add defines for i.MX8MN power domains
+    - soc: imx: gpcv2: add support for i.MX8MN power domains
+    - arm64: dts: imx8mn: add GPC node and power domains
+    - arm64: dts: imx8mn: Add power-domain reference in USB controller
+    - arm64: dts: imx8mn: Add GPU node
+    - dt-bindings: reset: imx7: Add support for i.MX8MN
+    - dt-bindings: reset: imx7: Document usage on i.MX8MP SoC
+    - reset: imx7: Add support for i.MX8MP SoC
+    - reset: imx7: Support module build
+    - dt-bindings: reset: imx8mq: add m4 reset
+    - reset: imx7: add the cm4 reset for i.MX8MQ
+    - arm64: dts: imx8mm: specify dma-ranges
+    - arm64: dts: imx8mn: specify dma-ranges
+    - regmap: provide helpers for simple bit operations
+    - cpufreq: Initialize cpufreq-dt driver earlier
+    - cpufreq: Add i.MX7ULP to cpufreq-dt-platdev blacklist
+    - spi: imx: use true,false for bool variable
+    - spi: imx: fallback to PIO if dma setup failure
+    - spi: introduce fallback to pio
+    - spi: imx: add fallback feature
+    - spi: imx: enable runtime pm support
+    - spi: imx: Fix freeing of DMA channels if spi_bitbang_start() fails
+    - spi: imx: Do not print an error when PIO is used
+    - spi: imx: Remove unneeded probe message
+    - spi: imx: fix runtime pm support for !CONFIG_PM
+    - spi: imx: fix reference leak in two imx operations
+    - spi: imx: fix the unbalanced spi runtime pm management
+    - spi: imx: Improve driver description
+    - spi: imx: add a check for speed_hz before calculating the clock
+    - UBUTNU: SAUCE: arm64: dts: imx8mm-venice-gw7902: add PCIe nodes
+    - dt-bindings: mfd: Add Gateworks System Controller bindings
+    - mfd: Add Gateworks System Controller core driver
+    - hwmon: Add Gateworks System Controller support
+    - lan743x: add MODULE_DEVICE_TABLE for module loading alias
+    - hwmon: (gsc-hwmon) Scale temperature to millidegrees
+    - hwmon: (gsc) add 16bit pre-scaled voltage mode
+    - lan743x: allow mac address to come from dt
+    - dt-bindings: mfd: gateworks-gsc: Add 16bit pre-scaled voltage mode
+    - hwmon: (gsc-hwmon) add fan sensor
+    - dt-bindings: vendor-prefixes: favor "gateworks" over "gw"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 18 Jun 2021 13:38:42 +0800
+
+linux-imx (5.4.0-1002.2) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] add hwe iot-build ppa to get abis
+    - [Packaging] add abi files for imx armhf
+    - [Config] disable drm configs for imx armhf
+    - [Config] CONFIG_MICREL_PHY=y
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM=y, CONFIG_CRYPTO_DEV_ATMEL_ECC=y
+
+  * Miscellaneous upstream changes
+    - media: v4l2-subdev: Introduce [get|set]_mbus_config pad ops
+    - net: phy: micrel.c: add rgmii interface delay possibility to ksz9131
+    - net: phy: micrel: add phy-mode support for the KSZ9031 PHY
+    - net: phy: mchp: Add support for LAN8814 QUAD PHY
+    - Revert "UBUNTU: SAUCE: arm64: dts: remove phy-reset-gpios from ethernet
+      nodes"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Wed, 02 Jun 2021 13:20:33 +0800
+
+linux-imx (5.4.0-1001.1) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Initial focal/imx packaging
+    - [Packaging] updateconfigs and annotations
+    - SAUCE: regulator: pca9450: fix build errors on backported 5.4 based kernel
+    - [Config] update configs for i.MX8 processors
+    - [Config] CONFIG_DWMAC_IMX8=m on i.MX8
+    - [Config] drm: updateconfigs, disable iMX8MP DCSS for now
+    - [Packaging] fix annotatoins for focal updates
+    - SAUCE: arm64: dts: imx8mp: support x8high35 pdk
+    - [Packaging] fix modules-check-imx
+    - [Packaging] arm64: imx: switch kernel format to Image
+    - [Config] CONFIG_SERIAL_IMX_CONSOLE=y
+    - SAUCE: arm64: dts: imx8mp: add optee fw node
+    - [Config] remove layerscape soc suooprt, cleanup configs
+    - SAUCE: arm64: dts: imx8mp: don't advertise broken eee modes for network phys
+    - [Config] CONFIG_USB_DWC3_IMX8MP=m
+    - SAUCE: arm64: dts: imx8mp: fix phy-reset-gpio assignments
+    - SAUCE: arm64: dts: imx8mp: correct wrong addr on i2c gpio expansion
+    - SAUCE: arm64: dts: imx8mp: setup pmic INT_B gpio
+    - SAUCE: regulator: pca9450: only warn if pmic irq allocation fails
+    - SAUCE: arm64: dts: imx8mp: fix uart-exp (ecspi1) SS0 pinconfig
+    - SAUCE: extcon: ptn5150: dont fail if interrupt cannot be configured
+    - SAUCE: arm64: dts: add a53 cpu supplies
+    - SAUCE: arm64: dts: fix usb-vbus pins, cc i2c addresses & add wifi regulator
+      supply
+    - SAUCE: arm64: dts: remove phy-reset-gpios from ethernet nodes
+    - SAUCE: MLK-23173-06 net: stmmac: enable dwmac5 34Bits address width
+    - SAUCE: MLK-23222 net: stmmac: add clocks management for gmac driver
+    - SAUCE: MLK-23251-01: net: stmac: tsn: add tc mqprio support
+    - SAUCE: MGS-5511 net: stmmac: start phylink instance before stmmac_hw_setup()
+    - SAUCE: MLK-23409 net: stmmac: correctly handle mdio bus reset error path
+    - SAUCE: MLK-23784 net: stmmac: disable bus/pclk clocks when probe failed
+    - SAUCE: net: fec: add imx8mq and imx8qm new versions support
+    - SAUCE: MLK-24911-1: soc: imx: Add support to get iMX8mp LDO trim fuse value
+    - [Packaging] build fail - remove bpfilter
+
+  * Miscellaneous upstream changes
+    - arm64: dts: imx8mn-ddr4-evk: Enable GPIO LED
+    - arm64: dts: imx8mn: Add "fsl,imx8mq-src" as src's fallback compatible
+    - arm64: dts: imx8mn: Add system counter node
+    - arm64: dts: imx8mn: Enable cpu-idle driver
+    - arm64: dts: imx8mm: Remove incorrect fallback compatible for ocotp
+    - arm64: dts: imx8mn: add ddr pmu node
+    - arm64: dts: imx8mm-evk: Adjust i2c nodes following alphabetical sort
+    - arm64: dts: imx8mm-evk: Add i2c3 support
+    - arm64: dts: imx8mm-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mq-evk: Adjust nodes following alphabetical sort
+    - arm64: dts: imx8mn-ddr4-evk: Move iomuxc node to end of file
+    - arm64: dts: imx8mq-evk: VDD_ARM power rail is always ON
+    - arm64: dts: imx8mq: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mm: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mn: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mn: Create EVK dtsi file for common use
+    - arm64: dts: imx8mq-evk: Add remote control
+    - arm64: dts: imx8mm: Remove duplicated machine compatible
+    - arm64: dts: imx8mn: Remove duplicated machine compatible
+    - arm64: dts: imx8mn-evk: Remove invalid Atheros properties
+    - arm64: dts: imx8mm: remove "simple-bus" for anatop
+    - arm64: dts: imx8mn: remove "simple-bus" for anatop
+    - arm64: dts: imx8m: Add ddr controller nodes
+    - arm64: dts: imx8mq: increase NOC clock to 800 MHz
+    - arm64: dts: imx8mq: Add eLCDIF controller
+    - arm64: dts: imx8mq: add missing SAI nodes
+    - arm64: dts: imx8mn: Remove setting for IMX8MN_CLK_USB_CORE_REF
+    - arm64: dts: imx8mn-evk: enable usb1 and typec support
+    - arm64: dts: imx8mm: Add missing mux options for UART1 and UART2 signals
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - dt-bindings: arm: Add Google Coral Edge TPU entry
+    - arm64: dts: freescale: add initial support for Google i.MX 8MQ Phanbell
+    - arm64: dts: imx8mm: Add Crypto CAAM support
+    - arm64: dts: imx8mn: add crypto node
+    - arm64: dts: imx8mm: Memory node should be in board DT
+    - arm64: dts: imx8mn: Memory node should be in board DT
+    - arm64: dts: imx8mn: add clock for snvs rtc node
+    - arm64: dts: imx8mn: Init rates and parents configs for clocks
+    - arm64: dts: imx8mm: drop redundant interrupt-parent
+    - arm64: dts: freescale: Add i.MX8MP dtsi support
+    - arm64: dts: freescale: Add i.MX8MP EVK board support
+    - arm64: dts: imx8mq-phanbell: Add support for ethernet
+    - arm64: dts: imx8mm-evk: add phy-reset-gpios for fec1
+    - arm64: dts: imx8mq-evk: add phy-reset-gpios for fec1
+    - arm64: dts: imx8mp-evk: Add GPIO LED support
+    - arm64: dts: imx8mp: Add system counter timer node
+    - arm64: dts: imx8mn: Adjust 1.2GHz OPP voltage to OD mode
+    - arm64: dts: imx: add i.MX8QXP thermal support
+    - arm64: dts: imx8mp: add crypto node
+    - arm64: dts: imx8mm: add snvs clock to pwrkey
+    - arm64: dts: imx8mq: add snvs clock to pwrkey
+    - arm64: dts: imx8mq: Align iomuxc node name
+    - arm64: dts: imx8mp: Add src node
+    - arm64: dts: imx8mn-evk: Add i2c3 support
+    - arm64: dts: imx8mn-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mp-evk: Add i2c3 support
+    - arm64: dts: imx8mp-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mq-phanbell: Add gpio-fan/thermal support
+    - arm64: dts: imx8mn: align name for crypto child nodes
+    - arm64: dts: enable fspi in imx8mm dts
+    - arm64: dts: imx8mq-phanbell: Fix Ethernet PHY post-reset duration
+    - arm64: dts: imx8mm: Add thermal zone support
+    - arm64: dts: imx8mn: Add CPU thermal zone support
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8mn: Add snvs clock to powerkey
+    - arm64: dts: imx8mp: Add snvs clock to powerkey
+    - arm64: dts: imx8mm-evk: Add secondary cpus supply
+    - arm64: dts: imx8m: Fix AIPS reg properties
+    - arm64: dts: imx8mp: Add thermal zones support
+    - arm64: dts: imx8mm: specify #sound-dai-cells for SAI nodes
+    - arm64: dts: freescale: imx8mp: update input_val for AUDIOMIX_BIT_STREAM
+    - arm64: dts: imx8mn: Update VDD_ARM 1.2GHz setpoint voltage
+    - arm64: dts: imx8mp: add "fsl,imx6sx-fec" compatible string
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8mq: Add src node interrupts
+    - arm64: dts: imx8mp: Add src node interrupts
+    - arm64: dts: imx8mq: enable Hantro G1/G2 VPU
+    - arm64: dts: imx8mq: Add mmc aliases
+    - arm64: dts: imx8mq: Add ethernet alias
+    - arm64: dts: imx8mm: sort the aliases
+    - arm64: dts: imx8mp: add i2c aliases
+    - arm64: dts: imx8m: change ocotp node name on i.MX8M SoCs
+    - arm64: dts: imx8m: add mu node
+    - arm64: dts: imx8mp: Add fallback compatible to ocotp node
+    - arm64: dts: imx8mp: add ddr pmu device node
+    - arm64: dts: imx8mm-evk: add two parameters for samsung picophy tuning
+    - arm64: dts: imx8mn-evk: add two parameters for samsung picophy tuning
+    - arm64: dts: imx8m: Add the ENET PPS interrupt
+    - arm64: dts: imx8mq: Add NWL MIPI DSI controller
+    - arm64: dts: imx8mp: Update pinfunc header file
+    - arm64: dts: imx8mm-evk: Add flexspi support
+    - arm64: dts: imx8mm-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mn-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mp-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mm-evk: Replace deprecated phy reset properties
+    - arm64: dts: imx8mq-evk: Replace deprecated phy reset properties
+    - arm64: dts: imx8mq-phanbell: Replace deprecated phy reset properties
+    - arm64: dts: imx8mm-evk: Align regulator names with schema
+    - arm64: dts: imx8mq-evk: Add hog suffix to wl-reg-on
+    - arm64: dts: imx8mm: Split the imx8mm evk board dts to a common dtsi
+    - arm64: dts: imx8mm: Add imx8mm ddr4 evk board support
+    - arm64: dts: imx8mm-evk: Add 32.768 kHz clock to PMIC
+    - arm64: dts: imx8mm-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mm-ddr4-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mn-ddr4-evk: Align regulator names with schema
+    - arm64: dts: imx8mq-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mq-phanbell: Align pin configuration group names with schema
+    - arm64: dts: imx8mp: correct sdma1 clk setting
+    - arm64: dts: imx8mp-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mn-ddr4-evk: fix missing PMIC's interrupt line pull-up
+    - arm64: dts: imx8mm: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: imx8mn: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: imx8mp: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: freescale: Add pmu support on imx8mp
+    - arm64: dts: freescale: Add pmu support on imx8mn
+    - arm64: dts: imx8mp-evk: Correct WDOG_B pin configuration
+    - arm64: dts: imx8mm: Add support for micfil
+    - arm64: dts: imx8mm: Add node for SPDIF
+    - arm64: dts: imx8mq: Configure clock rate for audio plls
+    - arm64: dts: imx8mq-evk: Add spdif sound card support
+    - arm64: dts: imx8mp-evk: add CAN support
+    - arm64: dts: imx8mq-evk: add linux,autosuspend-period property for IR
+    - arm64: dts: imx8mm-evk: add IR support
+    - arm64: dts: imx8mn-evk: add IR support
+    - arm64: dts: imx8mn: Enable Asynchronous Sample Rate Converter
+    - arm64: dts: imx8mn: Add SAI nodes
+    - arm64: dts: imx8mn: Add support for micfil
+    - arm64: dts: imx8mn: Add node for SPDIF
+    - arm64: dtsi: imx8mp: add usb nodes
+    - arm64: dts: imx8mp-evk: enable usb1 as host mode
+    - arm64: dts: imx8mn: Fix duplicate node name
+    - arm64: dts: imx8mn: Configure clock rate for audio plls
+    - arm64: dts: imx8mn-evk: Add sound-wm8524 card nodes
+    - arm64: dts: imx8mn-evk: Add sound-spdif card nodes
+    - arm64: dts: imx8mq: Add clock parents for mipi dphy
+    - arm64: dts: imx8m: add SoC ID compatible
+    - arm64: dts: imx8m: correct assigned clocks for FEC
+    - arm64: dts: imx8mq: assign clock parents for FEC
+    - arm64: dts: imx8m: add mac address for FEC
+    - arm64: dts: imx8m: add fsl,stop-mode property for FEC
+    - arm64: dts: imx8mq: use_dt_domains for pci node
+    - arm64: dts: imx8mn: Add fspi node
+    - pinctrl: core: Add pinctrl_select_default_state() and export it
+    - pinctrl: freescale: Add i.MX8MP pinctrl driver support
+    - pinctrl: freescale: drop the dependency on ARM64 for i.MX8M
+    - pinctrl: imx: Support i.MX8 SoCs pinctrl driver built as module
+    - pinctrl: imx: scu: Support i.MX8 SCU SoCs pinctrl driver built as module
+    - pinctrl: imx8mm: Support building as module
+    - pinctrl: imx8mn: Support building as module
+    - pinctrl: imx8mq: Support building as module
+    - pinctrl: imx8mp: Support building as module
+    - pinctrl: imx8qm: Support building as module
+    - pinctrl: imx: Support building i.MX pinctrl core driver as module
+    - clk: imx8mm: Move 1443X/1416X PLL clock structure to common place
+    - clk: imx8mn: Use common 1443X/1416X PLL clock structure
+    - clk: imx8mq: Add VIDEO2_PLL clock
+    - clk: imx: clk-pll14xx: Make two variables static
+    - clk: imx8mq: Define gates for pll1/2 fixed dividers
+    - clk: imx8mm: Define gates for pll1/2 fixed dividers
+    - clk: imx8mn: Define gates for pll1/2 fixed dividers
+    - clk: imx: imx8mm: mark sys_pll1/2 as fixed clock
+    - clk: imx: imx8mn: mark sys_pll1/2 as fixed clock
+    - clk: imx: imx8mq: mark sys1/2_pll as fixed clock
+    - clk: imx: imx7d: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6sll: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6sx: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6ul: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx8mq: fix sys3_pll_out_sels
+    - clk: imx: imx8mn: drop unused pll enum
+    - clk: imx: clk-divider-gate: fix a typo in comment
+    - clk: imx: clk-divider-gate: drop redundant initialization
+    - clk: imx8m: Set CLK_GET_RATE_NOCACHE on dram clocks
+    - clk: imx: Mark dram pll on 8mm and 8mn with CLK_GET_RATE_NOCACHE
+    - clk: imx6q: disable non functional divider
+    - clk: imx7ulp: Fix watchdog2 clock name typo
+    - clk: imx8m: Suppress bind attrs
+    - clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
+    - clk: imx8qxp-lpcg: Warn against devm_platform_ioremap_resource
+    - clk: imx: Rename the SCCG to SSCG
+    - clk: imx: Replace all the clk based helpers with macros
+    - clk: imx: pllv1: Switch to clk_hw based API
+    - clk: imx: pllv2: Switch to clk_hw based API
+    - clk: imx: imx7ulp composite: Rename to show is clk_hw based
+    - clk: imx: Rename sccg and frac pll register to suggest clk_hw
+    - clk: imx: Rename the imx_clk_pllv4 to imply it's clk_hw based
+    - clk: imx: Rename the imx_clk_pfdv2 to imply it's clk_hw based
+    - clk: imx: Rename the imx_clk_divider_gate to imply it's clk_hw based
+    - clk: imx7up: Rename the clks to hws
+    - clk: imx: clk-pll14xx: Switch to clk_hw based API
+    - clk: imx: clk-composite-8m: Switch to clk_hw based API
+    - clk: imx: add imx_unregister_hw_clocks
+    - clk: imx: add hw API imx_clk_hw_mux2_flags
+    - clk: imx: gate3: Switch to clk_hw based API
+    - clk: imx: Remove __init for imx_obtain_fixed_clk_hw() API
+    - clk: imx: imx8mn: Switch to clk_hw based API
+    - clk: imx: imx8mm: Switch to clk_hw based API
+    - clk: imx: imx8mq: Switch to clk_hw based API
+    - clk: imx: gate4: Switch imx_clk_gate4_flags() to clk_hw based API
+    - clk: imx: Add support for i.MX8MP clock driver
+    - clk: imx8mp: Correct IMX8MP_CLK_HDMI_AXI clock parent
+    - clk: imx8mp: Correct the enet_qos parent clock
+    - clk: imx8mn: add SNVS clock to clock tree
+    - clk: imx: pll14xx: Add new frequency entries for pll1443x table
+    - clk: imx: imx8mp: add ocotp root clk
+    - clk: imx: composite-8m: add imx8m_clk_hw_composite_core
+    - clk: imx: imx8mq: use imx8m_clk_hw_composite_core
+    - clk: imx: imx8mm: use imx8m_clk_hw_composite_core
+    - dt-bindings: clock: imx8mn: add SNVS clock
+    - clk: imx: imx8mn: use imx8m_clk_hw_composite_core
+    - clk: imx8mm: Fix the CLKO1 source select list
+    - clk: imx8mm: Add CLKO2 support
+    - clk: imx: Include clk-provider.h instead of clk.h for i.MX8M SoCs clock
+      driver
+    - clk: imx: drop redundant initialization
+    - clk: imx7ulp: Include clk-provider.h instead of clk.h
+    - clk: imx6sl: Add missing of_node_put()
+    - clk: imx8mq: Add missing of_node_put()
+    - clk: imx8mm: Add missing of_node_put()
+    - clk: imx8mn: Add missing of_node_put()
+    - clk: imx8mp: Add missing of_node_put()
+    - clk: imx8mp: Include slab.h instead of clkdev.h
+    - clk: imx8mm: Remove unused includes
+    - clk: imx8mn: Remove unused includes
+    - dt-bindings: imx: Add clock binding doc for i.MX8MP
+    - clk: imx8mp: Rename the IMX8MP_CLK_HDMI_27M clock
+    - clk: imx: imx8mq: fix a53 cpu clock
+    - clk: imx: imx8mm: fix a53 cpu clock
+    - clk: imx: imx8mn: fix a53 cpu clock
+    - clk: imx: imx8mp: fix a53 cpu clock
+    - dt-bindings: clocks: imx8mp: Add ids for audiomix clocks
+    - clk: imx: pll14xx: Return error if pll type is invalid
+    - clk: imx: clk-sscg-pll: Drop unnecessary initialization
+    - clk: imx: pfdv2: switch to use determine_rate
+    - clk: imx: pfdv2: determine best parent rate
+    - clk: imx: pllv4: use prepare/unprepare
+    - clk: imx8mn: A53 core clock no need to be critical
+    - clk: imx8mm: A53 core clock no need to be critical
+    - clk: imx8mp: A53 core clock no need to be critical
+    - clk: imx8mq: A53 core clock no need to be critical
+    - clk: imx7d: Add PXP clock
+    - clk: imx: clk-gate2: Pass the device to the register function
+    - clk: imx: imx6ul: change flexcan clock to support CiA bitrates
+    - clk: imx: drop the dependency on ARM64 for i.MX8M
+    - clk: imx: clk-sscg-pll: Remove unnecessary blank lines
+    - clk: imx: clk-pllv3: Use readl_relaxed_poll_timeout() for PLL lock wait
+    - clk: imx: gate2: Allow single bit gating clock
+    - clk: imx: pll14xx: Add the device as argument when registering
+    - clk: imx: Add helpers for passing the device as argument
+    - clk: imx8m: drop clk_hw_set_parent for A53
+    - clk: imx: imx8mp: fix pll mux bit
+    - clk: imx8mp: Define gates for pll1/2 fixed dividers
+    - clk: imx8mp: use imx8m_clk_hw_composite_core to simplify code
+    - clk: imx8m: migrate A53 clk root to use composite core
+    - clk: imx: add mux ops for i.MX8M composite clk
+    - clk: imx: add imx8m_clk_hw_composite_bus
+    - clk: imx: use imx8m_clk_hw_composite_bus for i.MX8M bus clk slice
+    - clk: imx8mp: add mu root clk
+    - clk: imx: vf610: add CAAM clock
+    - clk: imx: Use fallthrough pseudo-keyword
+    - clk: imx6sl: Use BIT(x) to avoid shifting signed 32-bit value by 31 bits
+    - clk: imx: Support building i.MX common clock driver as module
+    - clk: imx: Add clock configuration for ARMv7 platforms
+    - clk: imx8m: Support module build
+    - clk: imx8qxp: Support building i.MX8QXP clock driver as module
+    - clk: imx: Explicitly include bits.h
+    - clk: imx: vf610: Add CRC clock
+    - clk: imx: Correct the root clk of media ldb on imx8mp
+    - clk: imx: Correct the memrepair clock on imx8mp
+    - clk: imx: fix composite peripheral flags
+    - clk: imx: fix i.MX7D peripheral clk mux flags
+    - clk: imx: Fix and update kerneldoc
+    - clk: imx: gate2: Fix a few typos
+    - clk: imx8m: fix bus critical clk registration
+    - clk: imx: scu: fix MXC_CLK_SCU module build break
+    - clk: imx: scu: add two cells binding support
+    - clk: imx: scu: bypass cpu power domains
+    - clk: imx: scu: allow scu clk to take device pointer
+    - clk: imx: scu: add runtime pm support
+    - clk: imx: scu: add suspend/resume support
+    - clk: imx: imx8qxp-lpcg: add parsing clocks from device tree
+    - clk: imx: lpcg: allow lpcg clk to take device pointer
+    - clk: imx: clk-imx8qxp-lpcg: add runtime pm support
+    - clk: imx: lpcg: add suspend/resume support
+    - clk: imx: remove unneeded semicolon
+    - clk: imx: remove redundant assignment to pointer np
+    - clk: imx: scu: fix build break when compiled as modules
+    - clk: imx: gate2: Remove the IMX_CLK_GATE2_SINGLE_BIT special case
+    - clk: imx: gate2: Keep the register writing in on place
+    - clk: imx: gate2: Check if clock is enabled against cgr_val
+    - clk: imx: gate2: Add cgr_mask for more flexible number of control bits
+    - clk: imx: gate2: Add locking in is_enabled op
+    - clk: imx: gate2: Remove unused variable ret
+    - clk: imx8mm: drop of_match_ptr from of_device_id table
+    - clk: imx8mn: drop of_match_ptr from of_device_id table
+    - clk: imx8mp: drop of_match_ptr from of_device_id table
+    - clk: imx8mq: drop of_match_ptr from of_device_id table
+    - clk: imx: scu: Make pd_np with static keyword
+    - clk: imx: scu: remove the calling of device_is_bound
+    - clk: imx: fix Kconfig warning for i.MX SCU clk
+    - clk: imx: clk-imx8qxp: Add SCU clocks support for DC0 PLL clocks
+    - clk: imx: clk-imx8qxp: Add SCU clocks support for DC0 bypass clocks
+    - clk: imx: clk-imx8qxp: Register DC0 display clocks with imx_clk_scu2()
+    - clk: imx: clk-imx8qxp: Add some SCU clocks support for MIPI-LVDS subsystems
+    - clk: imx6q: demote warning about pre-boot ldb_di_clk reparenting
+    - clk: imx: clk-imx31: Remove unused static const table 'uart_clks'
+    - clk: imx8mq: add PLL monitor output
+    - clk: imx8mm: add clkout1/2 support
+    - clk: imx8mn: add clkout1/2 support
+    - clk: imx: Move 'imx6sl_set_wait_clk()'s prototype out to accessible header
+    - cpufreq: imx-cpufreq-dt: Add i.MX8MP support
+    - cpufreq: imx-cpufreq-dt: Add "cpu-supply" property check
+    - cpufreq: imx6q: read OCOTP through nvmem for imx6q
+    - cpufreq: imx-cpufreq-dt: Correct i.MX8MP's market segment fuse location
+    - cpufreq: dt: Allow platform specific intermediate callbacks
+    - cpufreq: imx6q-cpufreq: Improve the logic of -EPROBE_DEFER handling
+    - cpufreq: imx-cpufreq-dt: support i.MX7ULP
+    - cpufreq: imx6q: Unconditionally call dev_pm_opp_of_remove_table()
+    - watchdog: imx2_wdt: Remove unnecessary blank line
+    - watchdog: imx2_wdt: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
+    - watchdog: imx2_wdt: Use 'dev' instead of dereferencing it repeatedly
+    - watchdog: imx_sc_wdt: Remove unused includes
+    - watchdog: imx2_wdt: Drop .remove callback
+    - watchdog: imx2_wdt: update contact email
+    - gpio: mxc: Support module build
+    - rtc: imx-sc: Align imx sc msg structs to 4
+    - iopoll: introduce read_poll_timeout macro
+    - iopoll: redefined readx_poll_timeout macro to simplify the code
+    - iopoll: Introduce read_poll_timeout_atomic macro
+    - iopoll: update kerneldoc of read_poll_timeout_atomic()
+    - mmc: sdhci-esdhc-imx: Convert to pinctrl_select_default_state()
+    - mmc: sdhci-esdhc-imx: no fail when no pinctrl available
+    - mmc: sdhci-esdhci-imx: retune needed for Mega/Mix enabled SoCs
+    - mmc: sdhci-esdhc-imx: restore the per_clk rate in PM_RUNTIME
+    - mmc: sdhci-esdhc-imx: add strobe-dll-delay-target support
+    - mmc: sdhci-esdhc-imx: optimize the clock setting
+    - mmc: sdhci-esdhc-imx: optimize the strobe dll setting
+    - mmc: sdhci-esdhc-imx: add flag ESDHC_FLAG_BROKEN_AUTO_CMD23
+    - mmc: sdhci-esdhc-imx: Add an new esdhc_soc_data for i.MX8MM
+    - mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
+    - mmc: sdhci-esdhc-imx: clear DMA_SEL when disable DMA mode
+    - mmc: sdhci-esdhc-imx: restore pin state when resume back
+    - mmc: sdhci: use FIELD_GET for preset value bit masks
+    - mmc: sdhci: use FIELD_GET/PREP for capabilities bit masks
+    - mmc: sdhci: use FIELD_GET/PREP for current capabilities bit masks
+    - mmc: sdhci-esdhc: update contact email
+    - mmc: sdhci-esdhc-imx: Add HS400 support for i.MX6SLL
+    - mmc: host: sdhci-esdhc-imx: add wakeup feature for GPIO CD pin
+    - mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
+    - mmc: sdhci-msm: Introduce new ops to dump vendor specific registers
+    - mmc: sdhci-esdhc-imx: dump internal IC debug status during error
+    - mmc: sdhci-esdhc-imx: Reset before sending tuning command for manual tuning
+    - mmc: sdhci-esdhc-imx: remove unused code
+    - mmc: Set PROBE_PREFER_ASYNCHRONOUS for drivers that existed in v4.4
+    - mmc: sdhci-of-esdhc: make sure delay chain locked for HS400
+    - nvmem: core: add nvmem_cell_read_common
+    - nvmem: core: add nvmem_cell_read_u64
+    - soc: imx8: Using existing serial_number instead of UID
+    - soc: imx-scu: Using existing serial_number instead of UID
+    - soc: imx8mq: Read SOC revision from TF-A
+    - soc: imx8: print SoC type and revision
+    - soc: imx: Add i.MX8MP SoC driver support
+    - soc: imx: Enable compile testing of IMX_SCU_SOC
+    - soc: imx: gpcv2: include linux/sizes.h
+    - soc: imx: increase build coverage for imx8m soc driver
+    - soc: imx: drop COMPILE_TEST for IMX_SCU_SOC
+    - soc: imx8: select SOC_BUS
+    - soc: imx8m: Correct i.MX8MP UID fuse offset
+    - soc: imx8m: fix build warning
+    - soc: imx: scu: use devm_kasprintf
+    - cpuidle: Consolidate disabled state checks
+    - cpuidle: Introduce cpuidle_driver_state_disabled() for driver quirks
+    - ARM: imx: Drop imx_anatop_usb_chrg_detect_disable()
+    - ARM: imx: Add serial number support for i.MX6/7 SoCs
+    - ARM: imx: use generic function to exit coherency
+    - ARM: imx: Correct ocotp id for serial number support of i.MX6ULL/ULZ SoCs
+    - ARM: imx: Fix boot crash if ocotp is not found
+    - ARM: imx: Add i.MX7ULP SoC serial number support
+    - ARM: imx: limit errata selection to Cortex-A9 based designs
+    - ARM: imx: Remove unused include of linux/irqchip/arm-gic.h
+    - ARM: imx: Remove unused includes on mach-imx6q.c
+    - ARM: imx: Remove unused include of linux/of.h on mach-imx6sl.c
+    - ARM: imx: Add missing of_node_put()
+    - ARM: imx: Remove unnecessary blank lines
+    - ARM: imx: Drop unnecessary src_base check
+    - ARM: vf610: report soc info via soc device
+    - ARM: imx: use device_initcall for imx_soc_device_init
+    - ARM: imx: move cpu definitions into a header
+    - soc: imx: move cpu code to drivers/soc/imx
+    - ARM: imx: Provide correct number of resources when registering gpio devices
+    - ARM: imx: Place "Cortex-A/Cortex-M" comment in the correct location
+    - ARM: imx: Use correct SRC base address
+    - ARM: imx: Add revision support for i.MX7ULP revision 2.2
+    - ARM: imx: imx7ulp: Add a comment explaining the B2 silicon version
+    - ARM: imx: mach-imx6q: correctly identify i.MX6QP SoCs
+    - ARM: mach-imx: imx6ul: Print SOC revision on boot
+    - soc: imx: select ARM_GIC_V3 for i.MX8M
+    - ARM: imx: fix imx8m dependencies
+    - soc: imx8m: change to use platform driver
+    - pwm: imx27: Cache duty cycle register value
+    - pwm: imx27: Unconditionally write state to hardware
+    - pwm: imx27: Eliminate error message for defer probe
+    - pwm: imx27: Fix clock handling in pwm_imx27_apply()
+    - pwm: imx27: Simplify helper function to enable and disable clocks
+    - pwm: imx27: Don't disable clocks at device remove time
+    - pwm: imx27: Ensure clocks being on iff the PWM is on
+    - pwm: imx-tpm: Remove unused includes
+    - pwm: imx27: Remove unused include of of_device.h
+    - pwm: imx27: Fix rounding behavior
+    - pwm: imx-tpm: Use 64-bit division macro
+    - pwm: imx27: Use 64-bit division macro
+    - pwm: imx27: Fix overflow for bigger periods
+    - arm64: defconfig: add pca9450 pmic driver
+    - dt-bindings: regulator: add pca9450 regulator yaml
+    - regulator: pca9450: Add sd-vsel GPIO
+    - regulator: pca9450: add pca9450 pmic driver
+    - regulator: pca9450: Convert to use module_i2c_driver
+    - regulator: pca9450: Constify static regulator_ops
+    - regulator: pca9450: Add SD_VSEL GPIO for LDO5
+    - regulator: pca9450: Enable system reset on WDOG_B assertion
+    - phy: freescale: imx8mq-usb: add support for imx8mp usb phy
+    - dt-bindings: phy-imx8mq-usb: add compatible string for imx8mp usb phy
+    - phy: fsl-imx8mq-usb: Constify imx8mq_usb_phy_ops
+    - phy: fsl-imx8mq-usb: Constify imx8mp_usb_phy_ops
+    - phy: freescale: convert to devm_platform_ioremap_resource
+    - dt-bindings: imx: Add pinctrl binding doc for i.MX8MP
+    - dt-bindings: pinctrl: imx8mp: Replace the uint32-array with uint32-matrix
+    - usb: chipidea: debug: create debugfs directory under usb root
+    - usb: chipidea: udc: add new API ci_hdrc_gadget_connect
+    - usb: chipidea: udc: protect usb interrupt enable
+    - usb: chipidea: imx: enable vbus and id wakeup only for OTG events
+    - usb: chipidea: core: change vbus-regulator as optional
+    - usb: chipidea: imx: check data->usbmisc_data against NULL before access
+    - usb: chipidea: imx: change hsic power regulator as optional
+    - usb: chipidea: imx: refine the error handling for hsic
+    - usb: chipidea: imx: pinctrl for HSIC is optional
+    - usb: chipidea: ci_hdrc_imx: restore pinctrl
+    - usb: chipidea: usbmisc_imx: Use of_device_get_match_data()
+    - usb: chipidea: ci_hdrc_imx: Use of_device_get_match_data()
+    - USB: host: Use the correct style for SPDX License Identifier
+    - usb: host: ehci-fsl: Fix incorrectly named function argument
+    - crypto: caam - use mapped_{src,dst}_nents for descriptor
+    - crypto: caam - use devres to unmap memory
+    - crypto: caam - use devres to remove debugfs
+    - crypto: caam - use devres to de-initialize the RNG
+    - crypto: caam - use devres to de-initialize QI
+    - crypto: caam - use devres to populate platform devices
+    - crypto: caam - populate platform devices last
+    - crypto: caam - remove double buffering for ahash
+    - crypto: caam/qi2 - remove double buffering for ahash
+    - crypto: caam - Add support for i.MX8M Mini
+    - crypto: caam - add support for i.MX8M Nano
+    - crypto: caam - add support for i.MX8M Plus
+    - crypto: caam/qi - optimize frame queue cleanup
+    - drm/fsl-dcu: Use simple encoder
+    - drm/etnaviv: avoid deprecated timespec
+    - drm/etnaviv: Use dma_resv locking wrappers
+    - drm/etnaviv: update hardware headers from rnndb
+    - drm/etnaviv: determine product, customer and eco id
+    - drm/etnaviv: show identity information in debugfs
+    - drm/etnaviv: update gc7000 chip identity entry
+    - drm/etnaviv: update hwdb selection logic
+    - drm/etnaviv: add hwdb entry for gc400 found in STM32
+    - drm/etnaviv: Fix typo in comment
+    - drm/etnaviv: Update idle bits
+    - drm/etnaviv: Consider all kwnown idle bits in debugfs
+    - drm/etnaviv: Ignore MC when checking runtime suspend idleness
+    - drm/etnaviv: Warn when GPU doesn't idle fast enough
+    - drm/etnaviv: Replace zero-length array with flexible-array member
+    - drm/etnaviv: request pages from DMA32 zone when needed
+    - drm/etnaviv: remove check for return value of drm_debugfs_create_files()
+    - drm/etnaviv: remove _unlocked suffix in drm_gem_object_put_unlocked
+    - drm/etnaviv: Don't ignore errors on getting clocks
+    - drm/etnaviv: Make the "core" clock mandatory
+    - drm/etnaviv: Simplify clock enable/disable
+    - drm/etnaviv: fix external abort seen on GC600 rev 0x19
+    - drm/etnaviv: always start/stop scheduler in timeout processing
+    - drm/imx: plane_state->fb iff plane_state->crtc
+    - drm/imx: pd: Use bus format/flags provided by the bridge when available
+    - drm/imx: Remove the bogus possible_clones setup
+    - drm/imx: Use simple encoder
+    - drm/imx: Use __drm_atomic_helper_crtc_reset
+    - drm/imx: parallel-display: Adjust bus_flags handling
+    - drm/imx: drop useless best_encoder callback
+    - drm/imx: imx-ldb: remove useless enum
+    - drm/imx: parallel-display: move panel/bridge detection to fail early
+    - drm/imx: imx-tve: Delete an error message in imx_tve_bind()
+    - drm/imx: compile imx directory by default
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: use drm_bridge_connector API
+    - MAINTAINERS: Add entry for i.MX 8MQ DCSS driver
+    - dt-bindings: display: imx: add bindings for DCSS
+    - drm/imx/dcss: fix compilation issue on 32bit
+    - drm/imx/dcss: fix unused but set variable warnings
+    - drm/imx: dw_hdmi-imx: use imx_drm_encoder_parse_of
+    - drm/imx: imx-ldb: reduce scope of edid_len
+    - drm/imx/dcss: fix rotations for Vivante tiled formats
+    - drm/imx/dcss: fix coccinelle warning
+    - drm/imx/dcss: allow using nearest neighbor interpolation scaling
+    - drm/imx: depend on COMMON_CLK to fix compile tests
+    - gpu: drm: imx: convert comma to semicolon
+    - media: imx: enable V4L2_PIX_FMT_XBGR32, _BGRX32, and _RGBX32
+    - media: staging: media: imx: Fix alignment to match open parenthesis
+    - media: staging: media: imx: Use devm_platform_ioremap_resource().
+    - media: imx: Move capture device init to registered
+    - media: imx: Move pads init to probe
+    - media: imx7-mipi-csis: make array 'registers' static const, makes object
+      smaller
+    - media: imx7-mipi-csis: remove subdev_notifier
+    - media: imx: Propagate quantization and encoding in CSI
+    - media: imx: imx7_mipi_csis: Print the RESOL_CH0 register
+    - media: imx: imx7_mipi_csis: Add greyscale formats support
+    - media: imx: imx7-mipi-csis: Filter on CSI-2 data type
+    - media: imx: imx7-media-csi: Remove unneeded register read
+    - media: imx: imx6-media-csi: Replace Y16 with Y10 and Y12
+    - media: imx: imx6-media-csi: Support clamping Y10 and Y12 to Y8
+    - media: imx: imx7-media-csi: Add Y10 and Y12 formats support
+    - media: imx: imx7-media-csi: Support clamping Y10 and Y12 to Y8
+    - staging: media: imx: remove temporary variable
+    - staging: media: imx: remove parentheses
+    - media: imx: imx7-mipi-csis: Centralize initialization of pad formats
+    - media: imx: imx7-mipi-csis: Add missing RAW formats
+    - media: imx: imx7-mipi-csis: Expose correct YUV formats
+    - media: imx: imx7-mipi-csis: Fix MEDIA_BUS_FMT_UYVY8_2X8 data alignment
+    - media: imx: imx7-mipi-csis: Add MEDIA_BUS_FMT_UYVY10_2X10 support
+    - media: imx: imx7-mipi-csis: Rename data_alignment field to width
+    - media: imx: imx7-mipi-csis: Align image width based on format
+    - media: imx: imx7-mipi-csis: Never set MIPI_CSIS_ISPCFG_ALIGN_32BIT
+    - media: imx: imx7-mipi-csis: Align macro definitions
+    - media: imx: imx7-mipi-csis: Remove link setup on source pad
+    - media: imx: imx7-mipi-csis: Cleanup includes
+    - media: imx: imx7-mipi-csis: Don't use imx-media-utils helpers
+    - media: imx: imx7-mipi-csis: Implement the .enum_mbus_code() operation
+    - media: imx: utils: fix and simplify pixel format enumeration
+    - media: imx: utils: fix media bus format enumeration
+    - media: imx: utils: Inline init_mbus_colorimetry() in its caller
+    - media: imx: utils: Handle Bayer format lookup through a selection flag
+    - media: imx: Fix some pixel format selections
+    - media: imx: utils: Rename pixel format selection enumeration
+    - media: imx: utils: Introduce PIXFMT_SEL_IPU
+    - media: imx: utils: Make imx_media_pixfmt handle variable number of codes
+    - media: imx: utils: Split find|enum_format into fourcc and mbus functions
+    - media: imx: utils: Rename format lookup and enumeration functions
+    - media: imx: utils: Constify some mbus and ipu_image arguments
+    - media: imx-media-csc-scaler: Use a shorter name for driver
+    - media: imx: utils: Default colorspace to SRGB
+    - media: staging: media: imx: no need to check return value of debugfs_create
+      functions
+    - media: imx: Parse information from firmware without using callbacks
+    - media: v4l2-mc: add v4l2_create_fwnode_links helpers
+    - media: v4l2: Correct kernel-doc inconsistency
+    - media: entity: Pass entity to get_fwnode_pad operation
+    - media: v4l2-subdev: add v4l2_subdev_get_fwnode_pad_1_to_1
+    - media: video-mux: Parse information from firmware without using callbacks
+    - media: video-mux: Implement get_fwnode_pad op
+    - media: video-mux: Create media links in bound notifier
+    - media: imx: csi: Implement get_fwnode_pad op
+    - media: imx: mipi csi-2: Implement get_fwnode_pad op
+    - media: imx: imx7-mipi-csis: Implement get_fwnode_pad op
+    - media: imx: imx7-media-csi: Implement get_fwnode_pad op
+    - media: imx: mipi csi-2: Create media links in bound notifier
+    - media: imx7: mipi csis: Create media links in bound notifier
+    - media: imx7: csi: Create media links in bound notifier
+    - media: imx: csi: Create media links in bound notifier
+    - media: imx7: csi: Remove imx7_csi_get_upstream_endpoint()
+    - media: imx5/6/7: csi: Mark a bound video mux as a CSI mux
+    - media: imx: csi: Lookup upstream endpoint with imx_media_get_pad_fwnode
+    - media: imx: Create missing links from CSI-2 receiver
+    - media: imx: silence a couple debug messages
+    - media: imx: TODO: Remove media link creation todos
+    - staging/media: Remove unneeded geometry restrictions from i.MX CSI driver
+    - media: staging: media: imx: Update TODO entry
+    - media: staging: media: imx: remove commented code
+    - media: staging: media: imx: remove unnecessary variable use
+    - media: staging/imx: Increase IMX_MEDIA_EOF_TIMEOUT
+    - media: staging: media: imx: Kconfig: support VIDEO_IMX7_CSI for imx8m
+    - media: imx: Clean capture unregister
+    - media: imx7: csi: Fix regression for parallel cameras on i.MX6UL
+    - media: imx7: csi: Fix pad link validation
+    - media: imx6-mipi-csi2: Call remote subdev get_mbus_config to get active
+      lanes
+    - thermal: imx_thermal: Use __maybe_unused instead of CONFIG_PM_SLEEP
+    - thermal: imx: Remove unused includes
+    - thermal: imx: Calling imx_thermal_unregister_legacy_cooling() in .remove
+    - stmmac: platform: add "snps, dwmac-5.10a" IP compatible string
+    - net: ethernet: dwmac: add ethernet glue logic for NXP imx8 chip
+    - net: ethernet: dwmac: Fix an error code in imx_dwmac_probe()
+    - arm64: dts: imx8mp: Correct the gpio ranges of gpio3
+    - clk: imx8mp: Remove the none exist pcie clocks
+    - clk: imx8mq: Correct the pcie1 sels
+    - arm64: dts: imx8mp: add eqos node and alias
+    - arm64: dts: imx8mp: add wdog2/3 nodes
+    - net: fec: remove redundant assignment to pointer bdp
+    - net: fec: Prevent unbind operation
+    - net: ethernet: fec: Replace interrupt driven MDIO with polled IO
+    - net: ethernet: fec: Allow configuration of MDIO bus speed
+    - net: ethernet: fec: Allow the MDIO preamble to be disabled
+    - net: ethernet: fec: Prevent MII event after MII_SPEED write
+    - Revert "net: ethernet: fec: Prevent MII event after MII_SPEED write"
+    - net: ethernet: fec: Revert "net: ethernet: fec: Replace interrupt driven
+      MDIO with polled IO"
+    - net: ethernet: fec: Replace interrupt driven MDIO with polled IO
+    - net: ethernet: fec: move GPR register offset and bit into DT
+    - net: fec: disable correct clk in the err path of fec_enet_clk_enable
+    - net: ethernet: fec: prevent tx starvation under high rx load
+    - net: fec: Set max MTU size to allow the MTU to be changed
+    - net: fec: enable to use PPS feature without time stamping
+    - net: fec: initialize clock with 0 rather than current kernel time
+    - net: fec: get rid of redundant code in fec_ptp_set()
+    - net: fec: replace snprintf() with strlcpy() in fec_ptp_init()
+    - net: ethernet: fec: remove redundant null check before
+      clk_disable_unprepare()
+    - net: fec: ptp: remove unused variable 'ns' in fec_time_keep()
+    - net: fec_mpc52xx: Replace in_interrupt() usage
+    - net: fec: Fix PHY init after phy_reset_after_clk_enable()
+    - net: fec: Fix phy_device lookup for phy_reset_after_clk_enable()
+    - net: fec: fix MDIO probing for some FEC hardware blocks
+    - net: fec: Fix reference count leak in fec series ops
+    - net: fec: put child node on error path
+    - net: fec: Fix temporary RMII clock reset on link up
+    - net: fec: Silence M5272 build warnings
+    - net: stmmac: dwc-qos: use generic device api
+    - net: stmmac: dwc-qos: avoid clk and reset for acpi device
+    - net: stmmac: Print more information in DebugFS DMA Capabilities file
+    - net: stmmac: Let TX and RX interrupts be independently enabled/disabled
+    - net: stmmac: Always use TX coalesce timer value when rescheduling
+    - net: stmmac: Add basic EST support for GMAC5+
+    - net: stmmac: Add basic EST support for XGMAC
+    - net: stmmac: Integrate EST with TAPRIO scheduler API
+    - net: stmmac: Add Frame Preemption support using TAPRIO API
+    - net: stmmac: gmac5+: Add support for Frame Preemption
+    - net: stmmac: xgmac3+: Add support for Frame Preemption
+    - net: stmmac: mmc: Add Frame Preemption counters on GMAC5+ cores
+    - net: stmmac: tc: Fix TAPRIO division operation
+    - net: stmmac: Do not accept invalid MTU values
+    - stmmac: debugfs entry name is not be changed when udev rename device name.
+    - net: stmmac: xgmac: Fix missing return
+    - net: stmmac: gmac5+: Fix missing return
+    - net: stmmac: modified pcs mode support for RGMII
+    - net: stmmac: fix incorrect GMAC_VLAN_TAG register writting in GMAC4+
+    - net: ethernet: stmmac: don't warn about missing optional wakeup IRQ
+    - net: stmmac: fix notifier registration
+    - net: stmmac: use readl_poll_timeout() function in init_systime()
+    - net: stmmac: use readl_poll_timeout() function in dwmac4_dma_reset()
+    - net: stmmac: dwmac_lib: remove unnecessary checks in dwmac_dma_reset()
+    - net: stmmac: Remove WAKE_MAGIC if HW shows no pmt_magic_frame
+    - net: stmmac: Move device_can_wakeup() check earlier in set_wol
+    - net: stmmac: only call pmt() during suspend/resume if HW enables PMT
+    - net: stmmac: Support WOL with phy
+    - net: stmmac: fix failed to suspend if phy based WOL is enabled
+    - net: stmmac: increase the timeout for dma reset
+    - net: stmmac: overwrite the dma_cap.addr64 according to HW design
+    - net: stmmac: fix taprio schedule configuration
+    - net: stmmac: fix taprio configuration when base_time is in the past
+    - extcon: ptn5150: Use generic "interrupts" property
+    - extcon: ptn5150: Simplify getting vbus-gpios with flags
+    - extcon: ptn5150: Lower the noisiness of probe
+    - extcon: ptn5150: Check current USB mode when probing
+    - extcon: ptn5150: Make 'vbus-gpios' optional
+    - extcon: ptn5150: Convert to module_i2c_driver
+    - extcon: ptn5150: Set the VBUS and POLARITY property capability
+    - extcon: ptn5150: Use defines for registers
+    - usb: dwc3: debugfs: do not queue work if try to change mode on non-drd
+    - usb: dwc3: add imx8mp dwc3 glue layer driver
+    - net: fec: add eee mode tx lpi support
+    - net: fec: change the default rx copybreak value to maximum
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 31 May 2021 18:02:41 +0800
+
+linux-imx (5.4.0-1000.1) focal; urgency=medium
+
+  * Initial focal/imx packaging
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 16 Apr 2021 00:50:22 +0800
--- linux-ein-5.4.0.orig/debian.ein/config/annotations
+++ linux-ein-5.4.0/debian.ein/config/annotations
@@ -0,0 +1,4923 @@
+# Menu: HEADER
+# FORMAT: 4
+# ARCH: arm64 armhf
+# FLAVOUR: arm64-ein armhf-ein
+
+include "../../debian.master/config/annotations"
+
+CONFIG_ARCH_ROCKCHIP                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_ROCKCHIP                            note<'LP:1566283 / LP:1825222'>
+
+CONFIG_ARM_HIGHBANK_CPUIDLE                     policy<{'armhf': 'n'}>
+CONFIG_ARM_HIGHBANK_CPUIDLE                     note<'broken on ecx-1000'>
+
+CONFIG_ATA_PIIX                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATA_PIIX                                 note<'LP:1627324'>
+
+CONFIG_CMA_SIZE_MBYTES                          policy<{'arm64': '320', 'armhf': '32'}>
+CONFIG_CMA_SIZE_MBYTES                          note<'LP:1823753'>
+
+CONFIG_CPUFREQ_DT                               policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_CPUFREQ_DT                               note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         note<'for bootspeed'>
+
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_USERSPACE                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CPU_FREQ_GOV_USERSPACE                   note<'not autoloadable'>
+
+CONFIG_DRM_AMDGPU_CIK                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_AMDGPU_CIK                           note<'LP:1661887 for zesty'>
+
+CONFIG_DRM_BOCHS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_BOCHS                                note<'LP#1916290'>
+
+CONFIG_DRM_HISI_HIBMC                           policy<{'arm64': 'n'}>
+CONFIG_DRM_HISI_HIBMC                           note<'LP:1762940'>
+
+CONFIG_DRM_MGAG200                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_MGAG200                              note<'LP#1693337'>
+
+CONFIG_DVB_DUMMY_FE                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_DUMMY_FE                             note<'expert use only'>
+
+CONFIG_EFIVAR_FS                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_EFIVAR_FS                                note<'needed for variable EFI update'>
+
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           note<'LP#1398458'>
+
+CONFIG_GPIO_EM                                  policy<{'armhf': '-'}>
+CONFIG_GPIO_EM                                  note<'h/w not encounted'>
+
+CONFIG_GPIO_TWL4030                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_TWL4030                             note<'LP:#921934'>
+
+CONFIG_HOTPLUG_PCI_SHPC                         policy<{'arm64': 'n'}>
+CONFIG_HOTPLUG_PCI_SHPC                         note<'LP#1374440'>
+
+CONFIG_IPMMU_VMSA                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPMMU_VMSA                               note<'LP:1718734'>
+
+CONFIG_IP_PNP                                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IP_PNP                                   note<'LP:1259861'>
+
+CONFIG_MFD_SM501                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_SM501                                note<'boot essential on OMAP4'>
+
+CONFIG_MFD_TPS65217                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_TPS65217                             note<'boot essential on AM335x'>
+
+CONFIG_MMC_OMAP_HS                              policy<{'armhf': '-'}>
+CONFIG_MMC_OMAP_HS                              note<'boot essential on arm'>
+
+CONFIG_MMC_SDHCI                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_SDHCI                                note<'installation essential on omap/highbank'>
+
+CONFIG_MMC_SDHCI_PLTFM                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_SDHCI_PLTFM                          note<'boot essential on highbank'>
+
+CONFIG_MTD                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTD                                      note<'boot essential on arm'>
+
+CONFIG_MTD_BLOCK                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_BLOCK                                note<'boot essential on arm'>
+
+CONFIG_MTD_DOCG3                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_DOCG3                                note<'LP:1792205'>
+
+CONFIG_MTD_NAND_OMAP2                           policy<{'armhf': '-'}>
+CONFIG_MTD_NAND_OMAP2                           note<'boot essential on arm'>
+
+CONFIG_MTD_NAND_OMAP_BCH                        policy<{'armhf': '-'}>
+CONFIG_MTD_NAND_OMAP_BCH                        note<'boot essential on arm'>
+
+CONFIG_MTD_OF_PARTS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_OF_PARTS                             note<'boot essential on arm'>
+
+CONFIG_MTD_RAW_NAND                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_RAW_NAND                             note<'boot essential on arm'>
+
+CONFIG_NET_VENDOR_EMULEX                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_EMULEX                        note<'LP:1543165'>
+
+CONFIG_NOP_USB_XCEIV                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_NOP_USB_XCEIV                            note<'boot essential on omap/highbank'>
+
+CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT               note<'Selects CONFIG_DRM_LEGACY which is not wanted'>
+
+CONFIG_NR_CPUS                                  policy<{'arm64': '4', 'armhf': '4'}>
+CONFIG_NR_CPUS                                  note<'LP:1864198'>
+
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED           policy<{'arm64': '-'}>
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED           note<'LP:1557690'>
+
+CONFIG_PATA_HPT3X3_DMA                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PATA_HPT3X3_DMA                          note<'DMA mode is documented problematic'>
+
+CONFIG_REGULATOR_FIXED_VOLTAGE                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_REGULATOR_FIXED_VOLTAGE                  note<'boot essential on arm'>
+
+CONFIG_REGULATOR_TPS65217                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_TPS65217                       note<'boot essential on AM335x'>
+
+CONFIG_REGULATOR_TWL4030                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_TWL4030                        note<'boot requisite for omap4'>
+
+CONFIG_RTC_DRV_CMOS                             policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_CMOS                             note<'boot essential on i386/amd64'>
+
+CONFIG_RTC_DRV_EFI                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_EFI                              note<'LP:#1583738'>
+
+CONFIG_RTC_DRV_TWL4030                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_TWL4030                          note<'boot essential on OMAP3/OMAP4'>
+
+CONFIG_SAMPLE_TRACE_PRINTK                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_TRACE_PRINTK                      note<'Required for ftrace selftests'>
+
+CONFIG_SATA_AHCI_PLATFORM                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SATA_AHCI_PLATFORM                       note<'boot essential on highbank'>
+
+CONFIG_SATA_HIGHBANK                            policy<{'armhf': '-'}>
+CONFIG_SATA_HIGHBANK                            note<'LP:1703430'>
+
+CONFIG_SCSI_IPR_DUMP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_IPR_DUMP                            note<'LP:1343109'>
+
+CONFIG_SCSI_IPR_TRACE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_IPR_TRACE                           note<'LP:1343109'>
+
+CONFIG_SERIAL_SH_SCI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SH_SCI                            note<'LP: #2022361'>
+
+CONFIG_SERIAL_SH_SCI_CONSOLE                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SH_SCI_CONSOLE                    note<'LP: #2022361'>
+
+CONFIG_SERIAL_SH_SCI_EARLYCON                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SH_SCI_EARLYCON                   note<'LP: #2022361'>
+
+CONFIG_SND                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND                                      note<'not autoloadable on omap'>
+
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT               note<'LP:1804265'>
+
+CONFIG_SND_HDA_RECONFIG                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_RECONFIG                         note<'allows fixes to be tested live'>
+
+CONFIG_SND_PCM_OSS                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_PCM_OSS                              note<'deprecated in favour of pulseaudio emulation'>
+
+CONFIG_SND_SOC                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC                                  note<'not autoloadable on omap'>
+
+CONFIG_SND_SOC_SOF_NOCODEC_SUPPORT              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SND_SOC_SOF_NOCODEC_SUPPORT              note<'LP:1848490'>
+
+CONFIG_SOUND                                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SOUND                                    note<'not autoloadable on omap'>
+
+CONFIG_TEST_BLACKHOLE_DEV                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TEST_BLACKHOLE_DEV                       note<'Used by net selftests'>
+
+CONFIG_USB_EHCI_HCD_PLATFORM                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_EHCI_HCD_PLATFORM                    note<'Dont use the generic ehci/ohci code on omap, it doesnt work'>
+
+CONFIG_USB_HCD_BCMA                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_HCD_BCMA                             note<'USB_{O,E}HCI_HCD_PLATFORM must be off on omap'>
+
+CONFIG_USB_HCD_SSB                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_HCD_SSB                              note<'USB_{O,E}HCI_HCD_PLATFORM must be off on omap'>
+
+CONFIG_USB_MUSB_HDRC                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_MUSB_HDRC                            note<'not autoloadable on omap'>
+
+CONFIG_USB_XHCI_DBGCAP                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_XHCI_DBGCAP                          note<'LP:1730832'>
+
+CONFIG_XEN_BLKDEV_FRONTEND                      policy<{'arm64': '-'}>
+CONFIG_XEN_BLKDEV_FRONTEND                      note<'not autoloadable -- XEN paravirt support'>
+
+CONFIG_XEN_NETDEV_FRONTEND                      policy<{'arm64': '-'}>
+CONFIG_XEN_NETDEV_FRONTEND                      note<'not autoloadable -- XEN paravirt support'>
+
+
+# ---- Annotations without notes ----
+
+CONFIG_8139CP                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_8139TOO                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_8139TOO_8129                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_8139TOO_PIO                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_8139TOO_TUNE_TWISTER                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_8139_OLD_RX_RESET                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AC97_BUS                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ACENIC                                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ACENIC_OMIT_TIGON_I                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ACPI_ALS                                 policy<{'arm64': 'n'}>
+CONFIG_ACPI_APEI                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_APEI_EINJ                           policy<{'arm64': '-'}>
+CONFIG_ACPI_APEI_ERST_DEBUG                     policy<{'arm64': '-'}>
+CONFIG_ACPI_APEI_GHES                           policy<{'arm64': '-'}>
+CONFIG_ACPI_APEI_MEMORY_FAILURE                 policy<{'arm64': '-'}>
+CONFIG_ACPI_APEI_PCIEAER                        policy<{'arm64': '-'}>
+CONFIG_ACPI_APEI_SEA                            policy<{'arm64': '-'}>
+CONFIG_ACPI_BGRT                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_CONFIGFS                            policy<{'arm64': 'n'}>
+CONFIG_ACPI_CPPC_CPUFREQ                        policy<{'arm64': 'n'}>
+CONFIG_ACPI_CPPC_LIB                            policy<{'arm64': '-'}>
+CONFIG_ACPI_DOCK                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_EC_DEBUGFS                          policy<{'arm64': 'n'}>
+CONFIG_ACPI_HED                                 policy<{'arm64': 'n'}>
+CONFIG_ACPI_HMAT                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_HOTPLUG_MEMORY                      policy<{'arm64': 'n'}>
+CONFIG_ACPI_IPMI                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_NFIT                                policy<{'arm64': 'n'}>
+CONFIG_ACPI_PCI_SLOT                            policy<{'arm64': 'n'}>
+CONFIG_ACPI_TAD                                 policy<{'arm64': 'n'}>
+CONFIG_ACPI_WATCHDOG                            policy<{'arm64': '-'}>
+CONFIG_AD525X_DPOT_I2C                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_AD8366                                   policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_ADAPTEC_STARFIRE                         policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ADF4371                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ADIS16460                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ADM8211                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_AHCI_BRCM                                policy<{'arm64': '-'}>
+CONFIG_AHCI_DM816                               policy<{'armhf': '-'}>
+CONFIG_AHCI_IMX                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_AHCI_MTK                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AHCI_MVEBU                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AHCI_SUNXI                               policy<{'arm64': '-'}>
+CONFIG_AHCI_TEGRA                               policy<{'armhf': '-'}>
+CONFIG_AHCI_XGENE                               policy<{'arm64': '-'}>
+CONFIG_AIC79XX_CMDS_PER_DEVICE                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC79XX_DEBUG_ENABLE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC79XX_DEBUG_MASK                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC79XX_REG_PRETTY_PRINT                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC79XX_RESET_DELAY_MS                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC7XXX_CMDS_PER_DEVICE                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC7XXX_DEBUG_ENABLE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC7XXX_DEBUG_MASK                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC7XXX_REG_PRETTY_PRINT                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC7XXX_RESET_DELAY_MS                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIC94XX_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AIRO_CS                                  policy<{'armhf': 'n'}>
+CONFIG_ALIM7101_WDT                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ALPINE_MSI                               policy<{'armhf': '-'}>
+CONFIG_ALTERA_FREEZE_BRIDGE                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_ALTERA_MBOX                              policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_ALTERA_MSGDMA                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_ALTERA_PR_IP_CORE                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_ALTERA_PR_IP_CORE_PLAT                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ALTERA_TSE                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_ALX                                      policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_AL_FIC                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_AMBA_PL08X                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_AMD8111_ETH                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_AMD_XGBE                                 policy<{'arm64': '-'}>
+CONFIG_AMD_XGBE_DCB                             policy<{'arm64': '-'}>
+CONFIG_ANDROID_BINDERFS                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ANDROID_BINDER_DEVICES                   policy<{'arm64': '"binder,hwbinder,vndbinder"', 'armhf': '"binder,hwbinder,vndbinder"'}>
+CONFIG_APPLICOM                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_APQ_GCC_8084                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_APQ_MMCC_8084                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_AQTION                                   policy<{'arm64': 'n'}>
+CONFIG_ARCH_ACTIONS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_AGILEX                              policy<{'arm64': 'n'}>
+CONFIG_ARCH_ALPINE                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_ARTPEC                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_ASPEED                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_BCM2835                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_BCM_IPROC                           policy<{'arm64': 'n'}>
+CONFIG_ARCH_BERLIN                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_BITMAIN                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_BRCMSTB                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_EMEV2                               policy<{'armhf': '-'}>
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION           policy<{'arm64': '-'}>
+CONFIG_ARCH_EXYNOS                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_EXYNOS3                             policy<{'armhf': '-'}>
+CONFIG_ARCH_EXYNOS4                             policy<{'armhf': '-'}>
+CONFIG_ARCH_EXYNOS5                             policy<{'armhf': '-'}>
+CONFIG_ARCH_HAS_BANDGAP                         policy<{'armhf': '-'}>
+CONFIG_ARCH_HAS_RESET_CONTROLLER                policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_ARCH_HI3xxx                              policy<{'armhf': '-'}>
+CONFIG_ARCH_HIGHBANK                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_HIP01                               policy<{'armhf': '-'}>
+CONFIG_ARCH_HIP04                               policy<{'armhf': '-'}>
+CONFIG_ARCH_HISI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_HIX5HD2                             policy<{'armhf': '-'}>
+CONFIG_ARCH_INLINE_READ_LOCK                    policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_LOCK_BH                 policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_LOCK_IRQ                policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE            policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK                  policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_BH               policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ              policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE       policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK                    policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_BH                 policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ                policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE            policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK                 policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH              policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK                  policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH               policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ              policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE       policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK                   policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_BH                policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ               policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE           policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK                 policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH              policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ             policy<{'arm64': '-'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE      policy<{'arm64': '-'}>
+CONFIG_ARCH_K3                                  policy<{'arm64': 'n'}>
+CONFIG_ARCH_K3_AM6_SOC                          policy<{'arm64': '-'}>
+CONFIG_ARCH_K3_J721E_SOC                        policy<{'arm64': '-'}>
+CONFIG_ARCH_LAYERSCAPE                          policy<{'arm64': 'n'}>
+CONFIG_ARCH_LG1K                                policy<{'arm64': 'n'}>
+CONFIG_ARCH_MDM9615                             policy<{'armhf': '-'}>
+CONFIG_ARCH_MEDIATEK                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_MESON                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_MILBEAUT                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_MILBEAUT_M10V                       policy<{'armhf': '-'}>
+CONFIG_ARCH_MSM8960                             policy<{'armhf': '-'}>
+CONFIG_ARCH_MSM8974                             policy<{'armhf': '-'}>
+CONFIG_ARCH_MSM8X60                             policy<{'armhf': '-'}>
+CONFIG_ARCH_MVEBU                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_MXC                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED              policy<{'armhf': '-'}>
+CONFIG_ARCH_NPCM                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_NPCM7XX                             policy<{'armhf': '-'}>
+CONFIG_ARCH_NR_GPIO                             policy<{'armhf': '0'}>
+CONFIG_ARCH_OMAP                                policy<{'armhf': '-'}>
+CONFIG_ARCH_OMAP2PLUS                           policy<{'armhf': '-'}>
+CONFIG_ARCH_OMAP2PLUS_TYPICAL                   policy<{'armhf': '-'}>
+CONFIG_ARCH_OMAP3                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_OMAP4                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_QCOM                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_R7S72100                            policy<{'armhf': '-'}>
+CONFIG_ARCH_R7S9210                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A73A4                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7740                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7743                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7744                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7745                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A77470                            policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A774A1                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A774C0                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A7778                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7779                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7790                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7791                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7792                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7793                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7794                             policy<{'armhf': '-'}>
+CONFIG_ARCH_R8A7795                             policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A7796                             policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A77965                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A77970                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A77980                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A77990                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R8A77995                            policy<{'arm64': '-'}>
+CONFIG_ARCH_R9A06G032                           policy<{'armhf': '-'}>
+CONFIG_ARCH_RCAR_GEN1                           policy<{'armhf': '-'}>
+CONFIG_ARCH_RCAR_GEN2                           policy<{'armhf': '-'}>
+CONFIG_ARCH_RCAR_GEN3                           policy<{'arm64': '-'}>
+CONFIG_ARCH_RDA                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_REALTEK                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_RENESAS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_RMOBILE                             policy<{'armhf': '-'}>
+CONFIG_ARCH_RZN1                                policy<{'armhf': '-'}>
+CONFIG_ARCH_SEATTLE                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_SH73A0                              policy<{'armhf': '-'}>
+CONFIG_ARCH_SPRD                                policy<{'arm64': 'n'}>
+CONFIG_ARCH_STRATIX10                           policy<{'arm64': 'n'}>
+CONFIG_ARCH_SUNXI                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_SYNQUACER                           policy<{'arm64': 'n'}>
+CONFIG_ARCH_TEGRA                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_TEGRA_114_SOC                       policy<{'armhf': '-'}>
+CONFIG_ARCH_TEGRA_124_SOC                       policy<{'armhf': '-'}>
+CONFIG_ARCH_TEGRA_2x_SOC                        policy<{'armhf': '-'}>
+CONFIG_ARCH_TEGRA_3x_SOC                        policy<{'armhf': '-'}>
+CONFIG_ARCH_THUNDER                             policy<{'arm64': 'n'}>
+CONFIG_ARCH_THUNDER2                            policy<{'arm64': 'n'}>
+CONFIG_ARCH_UNIPHIER                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_VEXPRESS                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA        policy<{'armhf': '-'}>
+CONFIG_ARCH_VEXPRESS_DCSCB                      policy<{'armhf': '-'}>
+CONFIG_ARCH_VEXPRESS_SPC                        policy<{'armhf': '-'}>
+CONFIG_ARCH_VEXPRESS_TC2_PM                     policy<{'armhf': '-'}>
+CONFIG_ARCH_VIRT                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_XGENE                               policy<{'arm64': 'n'}>
+CONFIG_ARCH_ZYNQMP                              policy<{'arm64': 'n'}>
+CONFIG_ARCNET                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCNET_1051                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_1201                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_CAP                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_COM20020                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_COM20020_PCI                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_COM90xx                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_COM90xxIO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_RAW                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARCNET_RIM_I                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARC_EMAC_CORE                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM64_ERRATUM_834220                     policy<{'arm64': 'n'}>
+CONFIG_ARM64_RAS_EXTN                           policy<{'arm64': 'n'}>
+CONFIG_ARM64_RELOC_TEST                         policy<{'arm64': 'm'}>
+CONFIG_ARMADA375_USBCLUSTER_PHY                 policy<{'armhf': '-'}>
+CONFIG_ARMADA_370_CLK                           policy<{'armhf': '-'}>
+CONFIG_ARMADA_370_XP_IRQ                        policy<{'armhf': '-'}>
+CONFIG_ARMADA_370_XP_TIMER                      policy<{'armhf': '-'}>
+CONFIG_ARMADA_375_CLK                           policy<{'armhf': '-'}>
+CONFIG_ARMADA_37XX_CLK                          policy<{'arm64': '-'}>
+CONFIG_ARMADA_37XX_RWTM_MBOX                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARMADA_37XX_WATCHDOG                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARMADA_38X_CLK                           policy<{'armhf': '-'}>
+CONFIG_ARMADA_39X_CLK                           policy<{'armhf': '-'}>
+CONFIG_ARMADA_AP806_SYSCON                      policy<{'arm64': '-'}>
+CONFIG_ARMADA_AP_CPU_CLK                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARMADA_AP_CP_HELPER                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARMADA_CP110_SYSCON                      policy<{'arm64': '-'}>
+CONFIG_ARMADA_THERMAL                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARMADA_XP_CLK                            policy<{'armhf': '-'}>
+CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM       policy<{'arm64': '-'}>
+CONFIG_ARM_AMBA                                 policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ARM_ARMADA_37XX_CPUFREQ                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_ARMADA_8K_CPUFREQ                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_ATAG_DTB_COMPAT                      policy<{'armhf': 'y'}>
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND       policy<{'armhf': 'y'}>
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER policy<{'armhf': 'n'}>
+CONFIG_ARM_BIG_LITTLE_CPUIDLE                   policy<{'armhf': '-'}>
+CONFIG_ARM_BRCMSTB_AVS_CPUFREQ                  policy<{'arm64': '-'}>
+CONFIG_ARM_CCI400_PORT_CTRL                     policy<{'armhf': '-'}>
+CONFIG_ARM_CHARLCD                              policy<{'armhf': '-'}>
+CONFIG_ARM_DMA_IOMMU_ALIGNMENT                  policy<{'armhf': '-'}>
+CONFIG_ARM_DMA_USE_IOMMU                        policy<{'armhf': '-'}>
+CONFIG_ARM_DSU_PMU                              policy<{'arm64': 'n'}>
+CONFIG_ARM_ERRATA_430973                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_720789                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_754327                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_818325_852422                 policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_821420                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_825619                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_852421                        policy<{'armhf': 'n'}>
+CONFIG_ARM_ERRATA_852423                        policy<{'armhf': 'n'}>
+CONFIG_ARM_EXYNOS_BUS_DEVFREQ                   policy<{'armhf': '-'}>
+CONFIG_ARM_EXYNOS_CPUIDLE                       policy<{'armhf': '-'}>
+CONFIG_ARM_GIC_V2M                              policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ARM_GIC_V3                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ARM_GIC_V3_ITS                           policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ARM_GIC_V3_ITS_FSL_MC                    policy<{'arm64': '-'}>
+CONFIG_ARM_GIC_V3_ITS_PCI                       policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ARM_GLOBAL_TIMER                         policy<{'armhf': '-'}>
+CONFIG_ARM_HIGHBANK_CPUFREQ                     policy<{'armhf': '-'}>
+CONFIG_ARM_IMX6Q_CPUFREQ                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_IMX_CPUFREQ_DT                       policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_ARM_L1_CACHE_SHIFT                       policy<{'armhf': '6'}>
+CONFIG_ARM_L1_CACHE_SHIFT_7                     policy<{'armhf': '-'}>
+CONFIG_ARM_LPAE                                 policy<{'armhf': 'n'}>
+CONFIG_ARM_MEDIATEK_CPUFREQ                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_MHU                                  policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_ARM_MVEBU_V7_CPUIDLE                     policy<{'armhf': '-'}>
+CONFIG_ARM_OMAP2PLUS_CPUFREQ                    policy<{'armhf': '-'}>
+CONFIG_ARM_PL172_MPMC                           policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_ARM_QCOM_CPUFREQ_HW                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_QCOM_CPUFREQ_NVMEM                   policy<{'arm64': '-'}>
+CONFIG_ARM_RASPBERRYPI_CPUFREQ                  policy<{'arm64': '-'}>
+CONFIG_ARM_RK3399_DMC_DEVFREQ                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_SBSA_WATCHDOG                        policy<{'arm64': 'n'}>
+CONFIG_ARM_SCMI_CPUFREQ                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_SCMI_POWER_DOMAIN                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_SCMI_PROTOCOL                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARM_SDE_INTERFACE                        policy<{'arm64': 'n'}>
+CONFIG_ARM_SMMU_V3_PMU                          policy<{'arm64': 'n'}>
+CONFIG_ARM_SP805_WATCHDOG                       policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_ARM_TEGRA124_CPUFREQ                     policy<{'armhf': '-'}>
+CONFIG_ARM_TEGRA186_CPUFREQ                     policy<{'armhf': '-'}>
+CONFIG_ARM_TEGRA20_CPUFREQ                      policy<{'armhf': '-'}>
+CONFIG_ARM_TEGRA20_DEVFREQ                      policy<{'armhf': '-'}>
+CONFIG_ARM_TEGRA_DEVFREQ                        policy<{'armhf': '-'}>
+CONFIG_ARM_TIMER_SP804                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ARM_TI_CPUFREQ                           policy<{'armhf': '-'}>
+CONFIG_ARM_VEXPRESS_SPC_CPUFREQ                 policy<{'armhf': '-'}>
+CONFIG_ASPEED_ADC                               policy<{'armhf': '-'}>
+CONFIG_ASPEED_BT_IPMI_BMC                       policy<{'armhf': '-'}>
+CONFIG_ASPEED_KCS_IPMI_BMC                      policy<{'armhf': '-'}>
+CONFIG_ASPEED_LPC_CTRL                          policy<{'armhf': '-'}>
+CONFIG_ASPEED_LPC_SNOOP                         policy<{'armhf': '-'}>
+CONFIG_ASPEED_P2A_CTRL                          policy<{'armhf': '-'}>
+CONFIG_ASPEED_WATCHDOG                          policy<{'armhf': '-'}>
+CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH           policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_AT76C50X_USB                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_ATA_GENERIC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATH10K_AHB                               policy<{'arm64': 'n', 'armhf': '-'}>
+CONFIG_ATH10K_PCI                               policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_ATH10K_SNOC                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATH5K                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATH5K_DEBUG                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATH5K_PCI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATH5K_TRACER                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATH9K_PCI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATH9K_PCI_NO_EEPROM                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATL1                                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ATL1C                                    policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ATL1E                                    policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ATL2                                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ATMEL                                    policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ATM_ENI                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_ENI_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_ENI_TUNE_BURST                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_FORE200E                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_FORE200E_DEBUG                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_FORE200E_TX_RETRY                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_FORE200E_USE_TASKLET                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_HE                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_HE_USE_SUNI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_IA                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_IA_DEBUG                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_IDT77252                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_IDT77252_DEBUG                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_IDT77252_RCV_ALL                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_IDT77252_USE_SUNI                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_LANAI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_NICSTAR                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ATM_NICSTAR_USE_IDT77105                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_NICSTAR_USE_SUNI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ATM_SOLOS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_AURORA_NB8800                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_AXI_DMAC                                 policy<{'arm64': '-'}>
+CONFIG_B43_SDIO                                 policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_BACKLIGHT_PANDORA                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BACKLIGHT_RAVE_SP                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BACKLIGHT_WM831X                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_BATTERY_RX51                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BATTERY_TWL4030_MADC                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BCH                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_BCH_CONST_M                              policy<{'arm64': '14', 'armhf': '14'}>
+CONFIG_BCH_CONST_T                              policy<{'arm64': '4', 'armhf': '4'}>
+CONFIG_BCM2835_MBOX                             policy<{'arm64': '-'}>
+CONFIG_BCM2835_POWER                            policy<{'arm64': '-'}>
+CONFIG_BCM2835_THERMAL                          policy<{'arm64': '-'}>
+CONFIG_BCM2835_VCHIQ                            policy<{'arm64': '-'}>
+CONFIG_BCM2835_WDT                              policy<{'arm64': '-'}>
+CONFIG_BCM7038_L1_IRQ                           policy<{'arm64': '-'}>
+CONFIG_BCM7038_WDT                              policy<{'arm64': '-'}>
+CONFIG_BCM7XXX_PHY                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BCMA_DRIVER_GMAC_CMN                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCMA_DRIVER_GPIO                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCMA_DRIVER_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCMA_HOST_PCI                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCMA_HOST_SOC                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCMA_SFLASH                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BCMGENET                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BCM_FLEXRM_MBOX                          policy<{'arm64': '-'}>
+CONFIG_BCM_IPROC_ADC                            policy<{'arm64': '-'}>
+CONFIG_BCM_KONA_USB2_PHY                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BCM_NET_PHYLIB                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BCM_NS_THERMAL                           policy<{'arm64': '-'}>
+CONFIG_BCM_PDC_MBOX                             policy<{'arm64': '-'}>
+CONFIG_BCM_SR_THERMAL                           policy<{'arm64': '-'}>
+CONFIG_BCM_VIDEOCORE                            policy<{'arm64': '-'}>
+CONFIG_BE2ISCSI                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BE2NET                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BE2NET_BE2                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BE2NET_BE3                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BE2NET_HWMON                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BE2NET_LANCER                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BE2NET_SKYHAWK                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BERLIN2_ADC                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BGMAC                                    policy<{'arm64': '-'}>
+CONFIG_BGMAC_PLATFORM                           policy<{'arm64': '-'}>
+CONFIG_BIG_LITTLE                               policy<{'armhf': 'n'}>
+CONFIG_BINFMT_ELF_FDPIC                         policy<{'armhf': 'n'}>
+CONFIG_BLK_CGROUP_IOCOST                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BLK_DEV_3W_XXXX_RAID                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BLK_RQ_ALLOC_TIME                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BL_SWITCHER                              policy<{'armhf': '-'}>
+CONFIG_BL_SWITCHER_DUMMY_IF                     policy<{'armhf': '-'}>
+CONFIG_BNA                                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BNX2                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BNX2X                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BNX2X_SRIOV                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BNXT                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BNXT_DCB                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BNXT_FLOWER_OFFLOAD                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BNXT_HWMON                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BNXT_SRIOV                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BOARD_TPCI200                            policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_BPF_KPROBE_OVERRIDE                      policy<{'arm64': 'n'}>
+CONFIG_BPF_LIRC_MODE2                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BRCMDBG                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BRCMSTB_L2_IRQ                           policy<{'arm64': '-'}>
+CONFIG_BRCMSTB_PM                               policy<{'arm64': '-'}>
+CONFIG_BRCMSTB_THERMAL                          policy<{'arm64': '-'}>
+CONFIG_BRCM_TRACING                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BROADCOM_PHY                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BTREE                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_BT_HCIBLUECARD                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BT_HCIBT3C                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BT_HCIDTL1                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_BT_HCIRSI                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_BT_HCIUART_IBS                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BT_HCIUART_RTL                           policy<{'arm64': 'n'}>
+CONFIG_BT_QCOMSMD                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CACHE_FEROCEON_L2                        policy<{'armhf': '-'}>
+CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH           policy<{'armhf': '-'}>
+CONFIG_CACHE_L2X0_PMU                           policy<{'armhf': 'n'}>
+CONFIG_CACHE_TAUROS2                            policy<{'armhf': '-'}>
+CONFIG_CACHE_UNIPHIER                           policy<{'armhf': '-'}>
+CONFIG_CAN_DEBUG_DEVICES                        policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_CAN_EMS_PCMCIA                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_F81601                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_J1939                                policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_CAN_JANZ_ICAN3                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CAN_KVASER_PCIEFD                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_M_CAN_PLATFORM                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_M_CAN_TCAN4X5X                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_PEAK_PCMCIA                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_RCAR                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_CAN_RCAR_CANFD                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_CAN_SOFTING_CS                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CAN_XILINXCAN                            policy<{'arm64': 'n'}>
+CONFIG_CAPI_AVM                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CARDBUS                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CARDMAN_4000                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CARDMAN_4040                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CARMINE_DRAM_CUSTOM                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CASSINI                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CAVIUM_CPT                               policy<{'arm64': '-'}>
+CONFIG_CAVIUM_ERRATUM_22375                     policy<{'arm64': 'n'}>
+CONFIG_CAVIUM_ERRATUM_23154                     policy<{'arm64': 'n'}>
+CONFIG_CAVIUM_ERRATUM_27456                     policy<{'arm64': 'n'}>
+CONFIG_CAVIUM_ERRATUM_30115                     policy<{'arm64': 'n'}>
+CONFIG_CAVIUM_PTP                               policy<{'arm64': '-'}>
+CONFIG_CAVIUM_TX2_ERRATUM_219                   policy<{'arm64': 'n'}>
+CONFIG_CDNS_I3C_MASTER                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CEC_GPIO                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CEC_PIN                                  policy<{'arm64': '-'}>
+CONFIG_CEC_PIN_ERROR_INJ                        policy<{'arm64': '-'}>
+CONFIG_CEPH_FS_SECURITY_LABEL                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CFG80211_WEXT_EXPORT                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CGROUP_HUGETLB                           policy<{'arm64': '-'}>
+CONFIG_CHARGER_BD70528                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CHARGER_CPCAP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHARGER_CROS_USBPD                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHARGER_LT3651                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CHARGER_MAX77650                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHARGER_QCOM_SMBB                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHARGER_SC2731                           policy<{'arm64': '-'}>
+CONFIG_CHARGER_TWL4030                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHARGER_UCS1002                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CHECK_SIGNATURE                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_IPSEC_INLINE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_LIB                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T1                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T1_1G                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T3                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T4                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T4VF                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T4_DCB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHELSIO_T4_FCOE                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CHROMEOS_TBMC                            policy<{'arm64': '-'}>
+CONFIG_CHROME_PLATFORMS                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK      policy<{'armhf': '-'}>
+CONFIG_CLKSRC_EXYNOS_MCT                        policy<{'armhf': '-'}>
+CONFIG_CLKSRC_IMX_GPT                           policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_IMX_TPM                           policy<{'armhf': '-'}>
+CONFIG_CLKSRC_MMIO                              policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_CLKSRC_QCOM                              policy<{'armhf': '-'}>
+CONFIG_CLKSRC_TI_32K                            policy<{'armhf': '-'}>
+CONFIG_CLKSRC_VERSATILE                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_ACTIONS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_CLK_BCM_NS2                              policy<{'arm64': '-'}>
+CONFIG_CLK_BCM_SR                               policy<{'arm64': '-'}>
+CONFIG_CLK_EMEV2                                policy<{'armhf': '-'}>
+CONFIG_CLK_HSDK                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CLK_IMX6Q                                policy<{'armhf': 'y'}>
+CONFIG_CLK_IMX6SX                               policy<{'armhf': 'y'}>
+CONFIG_CLK_IMX6UL                               policy<{'armhf': 'y'}>
+CONFIG_CLK_IMX7D                                policy<{'armhf': 'y'}>
+CONFIG_CLK_IMX8MM                               policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_CLK_IMX8MN                               policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_CLK_IMX8MP                               policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_CLK_IMX8MQ                               policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_CLK_IMX8QXP                              policy<{'arm64': 'n'}>
+CONFIG_CLK_OWL_S500                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_OWL_S700                             policy<{'arm64': '-'}>
+CONFIG_CLK_OWL_S900                             policy<{'arm64': '-'}>
+CONFIG_CLK_QORIQ                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CLK_R7S9210                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7740                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7743                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7745                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A77470                             policy<{'armhf': '-'}>
+CONFIG_CLK_R8A774A1                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A774C0                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A7778                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7779                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7790                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7791                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7792                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7794                              policy<{'armhf': '-'}>
+CONFIG_CLK_R8A7795                              policy<{'arm64': '-'}>
+CONFIG_CLK_R8A7796                              policy<{'arm64': '-'}>
+CONFIG_CLK_R8A77965                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A77970                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A77980                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A77990                             policy<{'arm64': '-'}>
+CONFIG_CLK_R8A77995                             policy<{'arm64': '-'}>
+CONFIG_CLK_R9A06G032                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_RASPBERRYPI                          policy<{'arm64': '-'}>
+CONFIG_CLK_RCAR_GEN2                            policy<{'armhf': '-'}>
+CONFIG_CLK_RCAR_GEN2_CPG                        policy<{'armhf': '-'}>
+CONFIG_CLK_RCAR_GEN3_CPG                        policy<{'arm64': '-'}>
+CONFIG_CLK_RCAR_USB2_CLOCK_SEL                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_RENESAS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_RENESAS_CPG_MSSR                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_RENESAS_CPG_MSTP                     policy<{'armhf': '-'}>
+CONFIG_CLK_RENESAS_DIV6                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_RENESAS_LEGACY                       policy<{'armhf': '-'}>
+CONFIG_CLK_RZA1                                 policy<{'armhf': '-'}>
+CONFIG_CLK_SH73A0                               policy<{'armhf': '-'}>
+CONFIG_CLK_SP810                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_SUNXI                                policy<{'arm64': '-'}>
+CONFIG_CLK_SUNXI_CLOCKS                         policy<{'arm64': '-'}>
+CONFIG_CLK_SUNXI_PRCM_SUN6I                     policy<{'arm64': '-'}>
+CONFIG_CLK_SUNXI_PRCM_SUN8I                     policy<{'arm64': '-'}>
+CONFIG_CLK_SUNXI_PRCM_SUN9I                     policy<{'arm64': '-'}>
+CONFIG_CLK_TEGRA_BPMP                           policy<{'armhf': '-'}>
+CONFIG_CLK_TWL6040                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CLK_UNIPHIER                             policy<{'armhf': '-'}>
+CONFIG_CLK_VEXPRESS_OSC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CMDLINE                                  policy<{'arm64': '"cons"', 'armhf': '"console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"'}>
+CONFIG_CMDLINE_EXTEND                           policy<{'armhf': 'n'}>
+CONFIG_CMDLINE_FORCE                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CMDLINE_FROM_BOOTLOADER                  policy<{'armhf': 'y'}>
+CONFIG_CMT_SPEECH                               policy<{'armhf': '-'}>
+CONFIG_CNIC                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMEDI_8254                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_8255_PCI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_1032                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_1500                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_1516                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_1564                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_16XX                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_2032                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_2200                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_3120                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_3501                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_APCI_3XXX                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADDI_WATCHDOG                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADL_PCI6208                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADL_PCI7X3X                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADL_PCI8164                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADL_PCI9111                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADL_PCI9118                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADQ12B                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI1710                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI1720                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI1723                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI1724                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI1760                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ADV_PCI_DIO                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AIO_AIO12_8                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AIO_IIRO_16                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_DIO200                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_DIO200_ISA                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_DIO200_PCI                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PC236                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PC236_ISA                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PC236_PCI                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PC263_ISA                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PC263_PCI                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PCI224                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_AMPLC_PCI230                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_C6XDIGIO                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CB_PCIDAS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CB_PCIDAS64                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CB_PCIDDA                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CB_PCIMDAS                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CB_PCIMDDA                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_CONTEC_PCI_DIO                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAC02                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAQBOARD2000                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS08                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS08_ISA                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS08_PCI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS16                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS16M1                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS1800                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS6402                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DAS800                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DMM32AT                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT2801                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT2811                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT2814                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT2815                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT2817                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT282X                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DT3000                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_DYNA_PCI10XX                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_FL512                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_GSC_HPDI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ICP_MULTI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_II_PCI20KC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ISA_DRIVERS                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMEDI_JR3_PCI                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_KE_COUNTER                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ME4000                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_ME_DAQ                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_MF6X4                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_MITE                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_MPC624                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_MULTIQ3                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_6527                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_65XX                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_660X                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_670X                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_ATMIO                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_ATMIO16D                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_AT_A2150                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_AT_AO                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_LABPC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_LABPC_ISA                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_LABPC_PCI                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_PCIDIO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_PCIMIO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_ROUTING                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_TIO                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_NI_TIOCMD                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCI_DRIVERS                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMEDI_PCL711                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL724                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL726                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL730                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL812                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL816                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCL818                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCM3724                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCMAD                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCMCIA_DRIVERS                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMEDI_PCMDA12                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCMMIO                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_PCMUIO                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_RTD520                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_RTI800                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_RTI802                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_S526                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMEDI_S626                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_ASPEED                        policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_AXG                           policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_AXG_AUDIO                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_BD718XX                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMMON_CLK_CDCE706                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_CDCE925                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_CS2000_CP                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_G12A                          policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_GXBB                          policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_HI3516CV300                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI3519                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI3660                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI3670                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI3798CV200                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI6220                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_HI655X                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_IPROC                         policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_LOCHNAGAR                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MEDIATEK                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON8B                       policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_AO_CLKC                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MESON_CPU_DYNDIV              policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MESON_DUALDIV                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MESON_EE_CLKC                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MESON_MPLL                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_PHASE                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_PLL                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_REGMAP                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_SCLK_DIV                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MESON_VID_PLL_DIV             policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2701                        policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MT2712                        policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_BDPSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_IMGSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_JPGDECSYS              policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_MFGCFG                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_MMSYS                  policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_VDECSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT2712_VENCSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779                        policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_AUDSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_CAMSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_IMGSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_IPESYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_MFGCFG                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_MMSYS                  policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_VDECSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6779_VENCSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6797                        policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6797_IMGSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6797_MMSYS                  policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6797_VDECSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT6797_VENCSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT7622                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7622_AUDSYS                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7622_ETHSYS                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7622_HIFSYS                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7629                        policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7629_ETHSYS                 policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MT7629_HIFSYS                 policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MT8135                        policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_MT8173                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT8183                        policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_AUDIOSYS               policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_CAMSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_IMGSYS                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_IPU_ADL                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CONN               policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CORE0              policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CORE1              policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_MFGCFG                 policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_MMSYS                  policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_VDECSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8183_VENCSYS                policy<{'arm64': '-'}>
+CONFIG_COMMON_CLK_MT8516                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_MT8516_AUDSYS                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_PALMAS                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_QCOM                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_S2MPS11                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SAMSUNG                       policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_SCMI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_CLK_SI514                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI5341                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMMON_CLK_SI5351                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI544                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI570                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_TI_ADPLL                      policy<{'armhf': '-'}>
+CONFIG_COMMON_CLK_VC5                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_VERSATILE                     policy<{'arm64': 'n', 'armhf': '-'}>
+CONFIG_COMMON_CLK_WM831X                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_XGENE                         policy<{'arm64': 'n'}>
+CONFIG_COMMON_CLK_ZYNQMP                        policy<{'arm64': '-'}>
+CONFIG_COMMON_RESET_HI3660                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_COMMON_RESET_HI6220                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CPU_PJ4                                  policy<{'armhf': '-'}>
+CONFIG_CPU_PJ4B                                 policy<{'armhf': '-'}>
+CONFIG_CPU_SW_DOMAIN_PAN                        policy<{'armhf': 'y'}>
+CONFIG_CROS_EC                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_CHARDEV                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_DEBUGFS                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_I2C                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_LIGHTBAR                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_PROTO                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_RPMSG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_SPI                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_SYSFS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_EC_VBC                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CROS_KBD_LED_BACKLIGHT                   policy<{'arm64': '-'}>
+CONFIG_CROS_USBPD_LOGGER                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_AES_ARM                           policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_AES_ARM64                         policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM64_BS                      policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM64_CE                      policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM64_CE_BLK                  policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM64_CE_CCM                  policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK                policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_AES_ARM_BS                        policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_AES_ARM_CE                        policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_AUTHENC                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_CRC32                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_CRYPTD                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_ARTPEC6                       policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_ATMEL_ECC                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_ATMEL_I2C                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_ATMEL_SHA204A                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_BCM_SPU                       policy<{'arm64': '-'}>
+CONFIG_CRYPTO_DEV_CAVIUM_ZIP                    policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_DEV_CHELSIO                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_CHELSIO_TLS                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_CPT                           policy<{'arm64': '-'}>
+CONFIG_CRYPTO_DEV_EXYNOS_RNG                    policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI        policy<{'arm64': '-'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_JR                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE             policy<{'arm64': '9', 'armhf': '9'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE          policy<{'arm64': '7', 'armhf': '7'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API_TEST          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM                policy<{'arm64': '-'}>
+CONFIG_CRYPTO_DEV_HIFN_795X                     policy<{'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG                 policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_HISI_HPRE                     policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_DEV_HISI_SEC                      policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_DEV_HISI_SEC2                     policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_DEV_MARVELL_CESA                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_MEDIATEK                      policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_MXS_DCP                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_NITROX                        policy<{'arm64': '-'}>
+CONFIG_CRYPTO_DEV_NITROX_CNN55XX                policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_DEV_OMAP                          policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_OMAP_AES                      policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_OMAP_DES                      policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_OMAP_SHAM                     policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_QCE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_QCOM_RNG                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_ROCKCHIP                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_CRYPTO_DEV_S5P                           policy<{'armhf': '-'}>
+CONFIG_CRYPTO_DEV_SAFEXCEL                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_DEV_SAHARA                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_ECC                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_ECDH                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_ESSIV                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_GHASH_ARM64_CE                    policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_LIB_DES                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_NHPOLY1305_NEON                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CRYPTO_SHA256_ARM                        policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_SHA256_ARM64                      policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_SHA2_ARM64_CE                     policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_SHA2_ARM_CE                       policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_SHA3_ARM64                        policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_SHA512_ARM                        policy<{'armhf': 'y'}>
+CONFIG_CRYPTO_SHA512_ARM64                      policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_SHA512_ARM64_CE                   policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_SIMD                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_SM3_ARM64_CE                      policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_SM4_ARM64_CE                      policy<{'arm64': 'n'}>
+CONFIG_CRYPTO_XXHASH                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CXD2880_SPI_DRV                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_CYCLADES                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CYZ_INTR                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DDR                                      policy<{'armhf': '-'}>
+CONFIG_DE2104X                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DE2104X_DSL                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DEBUG_ALIGN_RODATA                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DEBUG_ICEDCC                             policy<{'armhf': 'n'}>
+CONFIG_DEBUG_IMX6Q_UART                         policy<{'armhf': 'n'}>
+CONFIG_DEBUG_IMX6SX_UART                        policy<{'armhf': 'y'}>
+CONFIG_DEBUG_IMX6UL_UART                        policy<{'armhf': 'n'}>
+CONFIG_DEBUG_IMX7D_UART                         policy<{'armhf': 'n'}>
+CONFIG_DEBUG_IMX_UART_PORT                      policy<{'armhf': '1'}>
+CONFIG_DEBUG_KERNEL_DC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DEBUG_LL                                 policy<{'armhf': 'y'}>
+CONFIG_DEBUG_LL_INCLUDE                         policy<{'armhf': '"debug/imx.S"'}>
+CONFIG_DEBUG_LL_UART_8250                       policy<{'armhf': 'n'}>
+CONFIG_DEBUG_LL_UART_PL01X                      policy<{'armhf': 'n'}>
+CONFIG_DEBUG_MEMORY_INIT                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DEBUG_PREEMPT                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DEBUG_SEMIHOSTING                        policy<{'armhf': 'n'}>
+CONFIG_DEBUG_UNCOMPRESS                         policy<{'armhf': 'n'}>
+CONFIG_DEBUG_VF_UART_PORT                       policy<{'armhf': '-'}>
+CONFIG_DEFXX                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DEFXX_MMIO                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP                policy<{'armhf': '-'}>
+CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU                policy<{'armhf': '-'}>
+CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DEV_DAX                                  policy<{'arm64': '-'}>
+CONFIG_DEV_DAX_KMEM                             policy<{'arm64': '-'}>
+CONFIG_DL2K                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DM9102                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DMA_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_DMA_OMAP                                 policy<{'armhf': '-'}>
+CONFIG_DMA_SUN6I                                policy<{'arm64': '-'}>
+CONFIG_DMA_VIRT_OPS                             policy<{'arm64': '-'}>
+CONFIG_DM_CLONE                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DM_CRYPT                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DNET                                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_DOVE_CLK                                 policy<{'armhf': '-'}>
+CONFIG_DOVE_THERMAL                             policy<{'armhf': '-'}>
+CONFIG_DPAA2_CONSOLE                            policy<{'arm64': '-'}>
+CONFIG_DPAA_ERRATUM_A050385                     policy<{'arm64': '-'}>
+CONFIG_DPS310                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRA752_THERMAL                           policy<{'armhf': '-'}>
+CONFIG_DRM                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_AMDGPU                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_AMDGPU_GART_DEBUGFS                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_AMDGPU_SI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_AMDGPU_USERPTR                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_AMD_ACP                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_AMD_DC                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_ANALOGIX_DP                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_ARCPGU                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_ARMADA                               policy<{'armhf': 'n'}>
+CONFIG_DRM_ASPEED_GFX                           policy<{'armhf': '-'}>
+CONFIG_DRM_AST                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_ATMEL_HLCDC                          policy<{'armhf': 'n'}>
+CONFIG_DRM_CDNS_AUDIO                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_CDNS_DP                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_CDNS_DSI                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_CDNS_HDMI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_CDNS_HDMI_CEC                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_CDNS_MHDP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_CIRRUS_QEMU                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_DEBUG_MM                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_DW_HDMI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_DW_HDMI_GP_AUDIO                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_DW_MIPI_DSI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_EXYNOS                               policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS5433_DECON                     policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS7_DECON                        policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_DSI                           policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_FIMC                          policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_FIMD                          policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_HDMI                          policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_IPP                           policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_MIC                           policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_MIXER                         policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_ROTATOR                       policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_SCALER                        policy<{'armhf': '-'}>
+CONFIG_DRM_EXYNOS_VIDI                          policy<{'armhf': '-'}>
+CONFIG_DRM_FSL_DCU                              policy<{'armhf': 'n'}>
+CONFIG_DRM_FSL_IMX_LVDS_BRIDGE                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_GEM_SHMEM_HELPER                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_GM12U320                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_HISI_KIRIN                           policy<{'arm64': 'n'}>
+CONFIG_DRM_IMX                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_IMX8MP_LDB                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_CDNS_MHDP                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_DCSS                             policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_DRM_IMX_DPU                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_HDMI                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_IMX_IPUV3                            policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_LCDIF                            policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_DRM_IMX_LCDIFV3                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_LCDIF_MUX_DISPLAY                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_LDB                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_PARALLEL_DISPLAY                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_IMX_SEC_DSIM                         policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_DRM_IMX_TVE                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_ITE_IT6263                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_KMS_HELPER                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_KOMEDA                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_LIMA                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_MALI_DISPLAY                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_MCDE                                 policy<{'armhf': 'n'}>
+CONFIG_DRM_MEDIATEK                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MEDIATEK_HDMI                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MESON                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MESON_DW_HDMI                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_10NM_PHY                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_14NM_PHY                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_20NM_PHY                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_28NM_8960_PHY                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_28NM_PHY                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_DSI_PLL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_GPU_STATE                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_GPU_SUDO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_HDMI_HDCP                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MSM_REGISTER_LOGGING                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_MXS                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MXSFB                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_NOUVEAU                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_NOUVEAU_BACKLIGHT                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_NWL_MIPI_DSI                         policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_DRM_NXP_SEIKO_43WVFIG                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_PANEL_ARM_VERSATILE                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_AVD_TT101WX_CN                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_PANEL_ILITEK_IL9322                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_ILITEK_ILI9881C                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_LG_LB035Q02                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_NEC_NL8048HL11                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_NOVATEK_NT39016                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_RAYDIUM_RM67191                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_RAYDIUM_RM68200                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6D16D0                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E63M0                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_SHARP_LS037V7DW01              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_SONY_ACX565AKM                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_TPO_TD028TTEC1                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_TPO_TD043MTEA1                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_PANFROST                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_QXL                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_RADEON                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_RADEON_USERPTR                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_RCAR_DU                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_RCAR_DW_HDMI                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_RCAR_LVDS                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_RCAR_VSP                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_ROCKCHIP                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_SEC_MIPI_DSIM                        policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_DRM_STM                                  policy<{'armhf': 'n'}>
+CONFIG_DRM_STM_DSI                              policy<{'armhf': '-'}>
+CONFIG_DRM_SUN4I                                policy<{'arm64': '-'}>
+CONFIG_DRM_SUN4I_BACKEND                        policy<{'arm64': '-'}>
+CONFIG_DRM_SUN4I_HDMI                           policy<{'arm64': '-'}>
+CONFIG_DRM_SUN4I_HDMI_CEC                       policy<{'arm64': '-'}>
+CONFIG_DRM_SUN6I_DSI                            policy<{'arm64': '-'}>
+CONFIG_DRM_SUN8I_DW_HDMI                        policy<{'arm64': '-'}>
+CONFIG_DRM_SUN8I_MIXER                          policy<{'arm64': '-'}>
+CONFIG_DRM_SUN8I_TCON_TOP                       policy<{'arm64': '-'}>
+CONFIG_DRM_TEGRA                                policy<{'armhf': '-'}>
+CONFIG_DRM_TEGRA_DEBUG                          policy<{'armhf': '-'}>
+CONFIG_DRM_TEGRA_STAGING                        policy<{'armhf': '-'}>
+CONFIG_DRM_THINE_THC63LVD1024                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_TI_SN65DSI86                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_TOSHIBA_TC358764                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_VC4                                  policy<{'arm64': '-'}>
+CONFIG_DRM_VC4_HDMI_CEC                         policy<{'arm64': '-'}>
+CONFIG_DRM_VRAM_HELPER                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DRM_XEN                                  policy<{'arm64': '-'}>
+CONFIG_DRM_XEN_FRONTEND                         policy<{'arm64': '-'}>
+CONFIG_DVB_A8293                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AF9013                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AF9033                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AS102                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AS102_FE                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_ASCOT2E                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_ATBM8830                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AU8522                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AU8522_DTV                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AU8522_V4L                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_AV7110                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_AV7110_IR                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_AV7110_OSD                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_B2C2_FLEXCOP                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_BCM3510                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_BT8XX                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_BUDGET                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_BUDGET_AV                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_BUDGET_CI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_BUDGET_CORE                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_BUDGET_PATCH                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_CORE                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CX22700                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_CX22702                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CX24110                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_CX24116                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CX24117                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_CX24120                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CX24123                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CXD2099                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_CXD2820R                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CXD2841ER                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_CXD2880                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DDBRIDGE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_DDBRIDGE_MSIENABLE                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_DEMUX_SECTION_LOSS_LOG               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_DIB3000MB                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DIB3000MC                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DIB7000M                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DIB7000P                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DIB8000                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DIB9000                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_DM1105                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_DRX39XYJ                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DRXD                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DRXK                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DS3000                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_DYNAMIC_MINORS                       policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_DVB_EC100                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_FIREDTV                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_FIREDTV_INPUT                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_GP8PSK_FE                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_HELENE                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_HOPPER                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_HORUS3A                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_ISL6405                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_ISL6421                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_ISL6423                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_IX2505V                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_L64781                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_LG2160                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LGDT3305                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LGDT3306A                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LGDT330X                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LGS8GL5                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_LGS8GXX                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LNBH25                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_LNBH29                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_LNBP21                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_LNBP22                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_M88DS3103                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_M88RS2000                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MANTIS                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_MAX_ADAPTERS                         policy<{'arm64': '-', 'armhf': '8'}>
+CONFIG_DVB_MB86A16                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_MB86A20S                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MMAP                                 policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_MN88443X                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_MN88472                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MN88473                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MT312                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MT352                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_MXL5XX                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_NET                                  policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_DVB_NETUP_UNIDVB                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_NGENE                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_NXT200X                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_NXT6000                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_OR51132                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_OR51211                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_PLATFORM_DRIVERS                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_DVB_PLL                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_PLUTO2                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_PT1                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_PT3                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_RTL2830                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_RTL2832                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_RTL2832_SDR                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_S5H1409                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_S5H1411                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_S5H1420                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_S5H1432                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_S921                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_SI2165                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_SI2168                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_SI21XX                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_SMIPCIE                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DVB_SP2                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_SP8870                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_SP887X                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_STB0899                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STB6000                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STB6100                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV0288                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV0297                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV0299                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV0367                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_STV0900                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV090x                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV0910                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_STV6110                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV6110x                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_STV6111                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TC90522                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA10021                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TDA10023                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA10048                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA1004X                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA10071                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA10086                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA18271C2DD                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TDA665x                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TDA8083                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TDA8261                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TDA826X                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TS2020                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TTUSB_BUDGET                         policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TTUSB_DEC                            policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TUA6100                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_TUNER_CX24113                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TUNER_DIB0070                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TUNER_DIB0090                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_TUNER_ITD1000                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_ULE_DEBUG                            policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_USB                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_A800                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AF9005                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AF9005_REMOTE                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AF9015                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AF9035                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_ANYSEE                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AU6610                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AZ6007                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_AZ6027                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_CE6230                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_CINERGY_T2                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_CXUSB                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_CXUSB_ANALOG                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_DVB_USB_DEBUG                            policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_USB_DIB0700                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DIB3000MC                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY                 policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_DVB_USB_DIBUSB_MC                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DIGITV                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DTT200U                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DTV5100                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DVBSKY                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_DW2102                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_EC168                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_GL861                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_GP8PSK                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_LME2510                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_M920X                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_MXL111SF                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_NOVA_T_USB2                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_OPERA1                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_PCTV452E                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_RTL28XXU                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_TECHNISAT_USB2                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_TTUSB2                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_UMT_010                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_V2                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_VP702X                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_VP7045                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_USB_ZD1301                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_VES1820                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_VES1X93                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_ZD1301_DEMOD                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_ZL10036                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_DVB_ZL10039                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DVB_ZL10353                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_DWC_XLGMAC_PCI                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DWMAC_IMX8                               policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_DWMAC_IPQ806X                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DWMAC_MEDIATEK                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DWMAC_MESON                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DWMAC_QCOM_ETHQOS                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DWMAC_ROCKCHIP                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DWMAC_SOCFPGA                            policy<{'arm64': '-'}>
+CONFIG_DWMAC_SUN8I                              policy<{'arm64': '-'}>
+CONFIG_DWMAC_SUNXI                              policy<{'arm64': '-'}>
+CONFIG_DW_APB_ICTL                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DW_APB_TIMER                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DW_APB_TIMER_OF                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_DW_AXI_DMAC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DW_DMAC_PCI                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DW_EDMA                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DW_EDMA_PCIE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DW_I3C_MASTER                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_E100                                     policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_E1000                                    policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_E1000E                                   policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_EARLY_PRINTK                             policy<{'armhf': 'y'}>
+CONFIG_EDAC_ALTERA                              policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_ETHERNET                     policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_NAND                         policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_OCRAM                        policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_QSPI                         policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_SDMMC                        policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_SDRAM                        policy<{'arm64': '-'}>
+CONFIG_EDAC_ALTERA_USB                          policy<{'arm64': '-'}>
+CONFIG_EDAC_ARMADA_XP                           policy<{'armhf': '-'}>
+CONFIG_EDAC_BLUEFIELD                           policy<{'arm64': '-'}>
+CONFIG_EDAC_GHES                                policy<{'arm64': '-'}>
+CONFIG_EDAC_HIGHBANK_L2                         policy<{'armhf': '-'}>
+CONFIG_EDAC_HIGHBANK_MC                         policy<{'armhf': '-'}>
+CONFIG_EDAC_LAYERSCAPE                          policy<{'arm64': '-'}>
+CONFIG_EDAC_LEGACY_SYSFS                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EDAC_QCOM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EDAC_SYNOPSYS                            policy<{'arm64': '-'}>
+CONFIG_EDAC_THUNDERX                            policy<{'arm64': 'n'}>
+CONFIG_EDAC_TI                                  policy<{'armhf': '-'}>
+CONFIG_EDAC_XGENE                               policy<{'arm64': 'n'}>
+CONFIG_EFI_ARMSTUB_DTB_LOADER                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EFI_BOOTLOADER_CONTROL                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EFI_CAPSULE_LOADER                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EFI_TEST                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EFI_VARS_PSTORE                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EINT_MTK                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EMAC_ROCKCHIP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EMBEDDED                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EM_TIMER_STI                             policy<{'armhf': '-'}>
+CONFIG_ENABLE_MUST_CHECK                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ENA_ETHERNET                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ENIC                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EPIC100                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EROFS_FS_SECURITY                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EROFS_FS_ZIP                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ET131X                                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_EXTCON_FSA9480                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EXTCON_IT5201                            policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_EXTCON_QCOM_SPMI_MISC                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EXTCON_USBC_CROS_EC                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_EXYNOS_ADC                               policy<{'armhf': '-'}>
+CONFIG_EXYNOS_AUDSS_CLK_CON                     policy<{'armhf': '-'}>
+CONFIG_EXYNOS_CHIPID                            policy<{'armhf': '-'}>
+CONFIG_EXYNOS_CPU_SUSPEND                       policy<{'armhf': '-'}>
+CONFIG_EXYNOS_IOMMU                             policy<{'armhf': '-'}>
+CONFIG_EXYNOS_IOMMU_DEBUG                       policy<{'armhf': '-'}>
+CONFIG_EXYNOS_MCPM                              policy<{'armhf': '-'}>
+CONFIG_EXYNOS_PMU                               policy<{'armhf': '-'}>
+CONFIG_EXYNOS_PMU_ARM_DRIVERS                   policy<{'armhf': '-'}>
+CONFIG_EXYNOS_PM_DOMAINS                        policy<{'armhf': '-'}>
+CONFIG_EXYNOS_SROM                              policy<{'armhf': '-'}>
+CONFIG_EXYNOS_THERMAL                           policy<{'armhf': '-'}>
+CONFIG_EZCHIP_NPS_MANAGEMENT_ENET               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_EZX_PCAP                                 policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_FARSYNC                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FAT_DEFAULT_IOCHARSET                    policy<{'arm64': '"ascii"', 'armhf': '"ascii"'}>
+CONFIG_FB_3DFX                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_3DFX_ACCEL                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_3DFX_I2C                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_ARK                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_ARMCLCD                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_FB_ASILIANT                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_ATY                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_ATY128                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_ATY128_BACKLIGHT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_ATY_BACKLIGHT                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_ATY_CT                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_ATY_GENERIC_LCD                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_ATY_GX                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_CARMINE                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_CARMINE_DRAM_EVAL                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_CFB_REV_PIXELS_IN_BYTE                policy<{'armhf': '-'}>
+CONFIG_FB_CIRRUS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_CYBER2000                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_CYBER2000_DDC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_DA8XX                                 policy<{'armhf': '-'}>
+CONFIG_FB_DDC                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_EFI                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_I740                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_IMSTT                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_IMX                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FB_KYRO                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_MATROX                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_MATROX_G                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MATROX_I2C                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MATROX_MAVEN                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MATROX_MILLENIUM                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MATROX_MYSTIQUE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MB862XX                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_MB862XX_I2C                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MB862XX_PCI_GDC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_MX3                                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_NEOMAGIC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_NVIDIA                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_NVIDIA_BACKLIGHT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_NVIDIA_DEBUG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_NVIDIA_I2C                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_OMAP2                                 policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV             policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_CONNECTOR_DVI                   policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_CONNECTOR_HDMI                  policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DEBUG_SUPPORT                   policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS                             policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_DEBUG                       policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_DEBUGFS                     policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_DPI                         policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_DSI                         policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_HDMI_COMMON                 policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_INIT                        policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_MIN_FCK_PER_PCK             policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_SDI                         policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET      policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_DSS_VENC                        policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_ENCODER_OPA362                  policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_ENCODER_TFP410                  policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_ENCODER_TPD12S015               policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_NUM_FBS                         policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_PANEL_DPI                       policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_PANEL_DSI_CM                    policy<{'armhf': '-'}>
+CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02        policy<{'armhf': '-'}>
+CONFIG_FB_OMAP4_DSS_HDMI                        policy<{'armhf': '-'}>
+CONFIG_FB_OMAP5_DSS_HDMI                        policy<{'armhf': '-'}>
+CONFIG_FB_PM2                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_PM2_FIFO_DISCONNECT                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_PM3                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA          policy<{'armhf': '-'}>
+CONFIG_FB_RADEON                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_RADEON_BACKLIGHT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_RADEON_DEBUG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_RADEON_I2C                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_RIVA                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_RIVA_BACKLIGHT                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_RIVA_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_RIVA_I2C                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_S3                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_S3_DDC                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SAVAGE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_SAVAGE_ACCEL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SAVAGE_I2C                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SH_MOBILE_LCDC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SIS                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_SIS_300                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SIS_315                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SM712                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_SM750                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_SVGALIB                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FB_SYS_COPYAREA                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_SYS_FILLRECT                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_SYS_FOPS                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_SYS_IMAGEBLIT                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_TRIDENT                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_VOODOO1                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_VT8623                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FB_XILINX                                policy<{'arm64': '-'}>
+CONFIG_FCOE                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FDDI                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FEALNX                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FEC                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FIQ                                      policy<{'armhf': '-'}>
+CONFIG_FIREWIRE                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FIREWIRE_NET                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FIREWIRE_NOSY                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FIREWIRE_OHCI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FIREWIRE_SBP2                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FIREWIRE_SERIAL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FM10K                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FONT_TER16x32                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FORCEDETH                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FORCE_MAX_ZONEORDER                      policy<{'arm64': '11', 'armhf': '11'}>
+CONFIG_FORCE_PCI                                policy<{'armhf': '-'}>
+CONFIG_FPGA                                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_FPGA_BRIDGE                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_DFL                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_DFL_AFU                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FPGA_DFL_FME                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FPGA_DFL_FME_BRIDGE                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FPGA_DFL_FME_MGR                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FPGA_DFL_FME_REGION                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FPGA_DFL_PCI                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FPGA_MGR_ALTERA_CVP                      policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FPGA_MGR_ALTERA_PS_SPI                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_MGR_ICE40_SPI                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_MGR_MACHXO2_SPI                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_MGR_STRATIX10_SOC                   policy<{'arm64': '-'}>
+CONFIG_FPGA_MGR_XILINX_SPI                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FPGA_MGR_ZYNQMP_FPGA                     policy<{'arm64': '-'}>
+CONFIG_FPGA_REGION                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FSCACHE_HISTOGRAM                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FSI                                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_FSI_MASTER_AST_CF                        policy<{'armhf': '-'}>
+CONFIG_FSI_MASTER_GPIO                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FSI_MASTER_HUB                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FSI_NEW_DEV_NODE                         policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FSI_OCC                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FSI_SBEFIFO                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_FSI_SCOM                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_FSL_BMAN_TEST                            policy<{'arm64': '-'}>
+CONFIG_FSL_BMAN_TEST_API                        policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA                                 policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA2                                policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA2_ETH                            policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA2_ETHSW                          policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA2_PTP_CLOCK                      policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA_CHECKING                        policy<{'arm64': '-'}>
+CONFIG_FSL_DPAA_ETH                             policy<{'arm64': '-'}>
+CONFIG_FSL_EDMA                                 policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_FSL_ENETC                                policy<{'arm64': '-'}>
+CONFIG_FSL_ENETC_HW_TIMESTAMPING                policy<{'arm64': '-'}>
+CONFIG_FSL_ENETC_MDIO                           policy<{'arm64': '-'}>
+CONFIG_FSL_ENETC_PTP_CLOCK                      policy<{'arm64': '-'}>
+CONFIG_FSL_ENETC_VF                             policy<{'arm64': '-'}>
+CONFIG_FSL_FMAN                                 policy<{'arm64': '-'}>
+CONFIG_FSL_GUTS                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FSL_IFC                                  policy<{'arm64': '-'}>
+CONFIG_FSL_IMX8_DDR_PMU                         policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_FSL_MC_BUS                               policy<{'arm64': '-'}>
+CONFIG_FSL_MC_DPIO                              policy<{'arm64': '-'}>
+CONFIG_FSL_PQ_MDIO                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FSL_QDMA                                 policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_FSL_QMAN_TEST                            policy<{'arm64': '-'}>
+CONFIG_FSL_XGMAC_MDIO                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FS_VERITY                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FS_VERITY_BUILTIN_SIGNATURES             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FS_VERITY_DEBUG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FTWDT010_WATCHDOG                        policy<{'armhf': 'n'}>
+CONFIG_FUEL_GAUGE_SC27XX                        policy<{'arm64': '-'}>
+CONFIG_FUJITSU_ES                               policy<{'arm64': 'n'}>
+CONFIG_FUSION                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FUSION_CTL                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_FC                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_LAN                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_LOGGING                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_MAX_SGE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_SAS                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FUSION_SPI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FWTTY_MAX_CARD_PORTS                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FWTTY_MAX_TOTAL_PORTS                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_FW_CFG_SYSFS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FW_CFG_SYSFS_CMDLINE                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_FW_LOADER_USER_HELPER                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GADGET_UAC1                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GADGET_UAC1_LEGACY                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GAMEPORT_EMU10K1                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GAMEPORT_FM801                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GEMINI_ETHERNET                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GENERIC_IRQ_DEBUGFS                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GENERIC_PHY_MIPI_DPHY                    policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_GIANFAR                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GIGASET_CAPI                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GMSL_MAX9286                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_GPIO_AMDPT                               policy<{'arm64': 'n'}>
+CONFIG_GPIO_AMD_FCH                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_ASPEED                              policy<{'armhf': '-'}>
+CONFIG_GPIO_BRCMSTB                             policy<{'arm64': '-'}>
+CONFIG_GPIO_BT8XX                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_CADENCE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_DAVINCI                             policy<{'arm64': '-'}>
+CONFIG_GPIO_EIC_SPRD                            policy<{'arm64': '-'}>
+CONFIG_GPIO_EXAR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_FTGPIO010                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_GENERIC_PLATFORM                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_GPIO_HLWD                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_JANZ_TTL                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_LP87565                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_MADERA                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_MAX77650                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_MENZ127                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_GPIO_MLXBF                               policy<{'arm64': '-'}>
+CONFIG_GPIO_MOCKUP                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_GPIO_MOXTET                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_MPC8XXX                             policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_GPIO_MVEBU                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_MXC                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_OMAP                                policy<{'armhf': '-'}>
+CONFIG_GPIO_PCA953X                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_PCA953X_IRQ                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_PCIE_IDIO_24                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_PCI_IDIO_16                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_PL061                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_GPIO_PMIC_EIC_SPRD                       policy<{'arm64': '-'}>
+CONFIG_GPIO_RASPBERRYPI_EXP                     policy<{'arm64': '-'}>
+CONFIG_GPIO_RCAR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_RDC321X                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_SAMA5D2_PIOBU                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_SIOX                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_GPIO_SPRD                                policy<{'arm64': '-'}>
+CONFIG_GPIO_TC3589X                             policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_GPIO_TEGRA                               policy<{'armhf': '-'}>
+CONFIG_GPIO_THUNDERX                            policy<{'arm64': '-'}>
+CONFIG_GPIO_TPS68470                            policy<{'arm64': '-'}>
+CONFIG_GPIO_TQMX86                              policy<{'arm64': '-'}>
+CONFIG_GPIO_TS4800                              policy<{'armhf': '-'}>
+CONFIG_GPIO_TS4900                              policy<{'armhf': 'n'}>
+CONFIG_GPIO_TWL6040                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_GPIO_UNIPHIER                            policy<{'armhf': '-'}>
+CONFIG_GPIO_VF610                               policy<{'armhf': '-'}>
+CONFIG_GPIO_WM831X                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_GPIO_WM8350                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_GPIO_WM8994                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_GPIO_XGENE                               policy<{'arm64': 'n'}>
+CONFIG_GPIO_XGENE_SB                            policy<{'arm64': '-'}>
+CONFIG_GPIO_XILINX                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_GPIO_XLP                                 policy<{'arm64': '-'}>
+CONFIG_GPIO_ZYNQ                                policy<{'arm64': '-'}>
+CONFIG_HAMACHI                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HAPPYMEAL                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HAS_IOPORT_MAP                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_IMX_AMP                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_ANATOP                          policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_BUSFREQ                         policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_DDRC                            policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_GPC                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_GPCV2                           policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_MMDC                            policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_MU                              policy<{'armhf': 'y'}>
+CONFIG_HAVE_IMX_RPMSG                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_IMX_SRC                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_PATA_PLATFORM                       policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_HAVE_S3C2410_I2C                         policy<{'armhf': '-'}>
+CONFIG_HAVE_S3C2410_WATCHDOG                    policy<{'armhf': '-'}>
+CONFIG_HAVE_S3C_RTC                             policy<{'armhf': '-'}>
+CONFIG_HBMC_AM654                               policy<{'arm64': '-'}>
+CONFIG_HDQ_MASTER_OMAP                          policy<{'armhf': '-'}>
+CONFIG_HERMES                                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_HERMES_CACHE_FW_ON_INIT                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HERMES_PRISM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HI13X1_GMAC                              policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_HI3660_MBOX                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HI6220_MBOX                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HID                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HID_CREATIVE_SB0540                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_HID_GOOGLE_HAMMER                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HINIC                                    policy<{'arm64': '-'}>
+CONFIG_HIP04_ETH                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HISILICON_ERRATUM_161010101              policy<{'arm64': 'n'}>
+CONFIG_HISILICON_IRQ_MBIGEN                     policy<{'arm64': '-'}>
+CONFIG_HISILICON_LPC                            policy<{'arm64': '-'}>
+CONFIG_HISI_FEMAC                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HISI_PMU                                 policy<{'arm64': 'n'}>
+CONFIG_HISI_THERMAL                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HIX5HD2_GMAC                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HMEM_REPORTING                           policy<{'arm64': '-'}>
+CONFIG_HMM_MIRROR                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HNS                                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HNS3                                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_HNS3_DCB                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HNS3_ENET                                policy<{'arm64': '-'}>
+CONFIG_HNS3_HCLGE                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HNS3_HCLGEVF                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HNS_DSAF                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HNS_ENET                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HNS_MDIO                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HOSTAP                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_HOSTAP_CS                                policy<{'armhf': 'n'}>
+CONFIG_HOSTAP_FIRMWARE                          policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_HOSTAP_FIRMWARE_NVRAM                    policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_HOSTAP_PCI                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_HOSTAP_PLX                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_HOTPLUG_PCI_ACPI                         policy<{'arm64': 'n'}>
+CONFIG_HOTPLUG_PCI_ACPI_IBM                     policy<{'arm64': '-'}>
+CONFIG_HOTPLUG_PCI_CPCI                         policy<{'arm64': 'n'}>
+CONFIG_HP100                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HSA_AMD                                  policy<{'arm64': '-'}>
+CONFIG_HUGETLBFS                                policy<{'arm64': 'n'}>
+CONFIG_HUGETLB_PAGE                             policy<{'arm64': '-'}>
+CONFIG_HVC_IRQ                                  policy<{'arm64': '-'}>
+CONFIG_HVC_XEN                                  policy<{'arm64': '-'}>
+CONFIG_HVC_XEN_FRONTEND                         policy<{'arm64': '-'}>
+CONFIG_HWPOISON_INJECT                          policy<{'arm64': '-'}>
+CONFIG_HWSPINLOCK_OMAP                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HWSPINLOCK_QCOM                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HWSPINLOCK_SPRD                          policy<{'arm64': '-'}>
+CONFIG_HW_RANDOM_BCM2835                        policy<{'arm64': '-'}>
+CONFIG_HW_RANDOM_CAVIUM                         policy<{'arm64': 'n'}>
+CONFIG_HW_RANDOM_EXYNOS                         policy<{'armhf': '-'}>
+CONFIG_HW_RANDOM_HISI                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HW_RANDOM_HISI_V2                        policy<{'arm64': 'y'}>
+CONFIG_HW_RANDOM_IMX_RNGC                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HW_RANDOM_IPROC_RNG200                   policy<{'arm64': '-'}>
+CONFIG_HW_RANDOM_MESON                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HW_RANDOM_MTK                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HW_RANDOM_OMAP                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_HW_RANDOM_OMAP3_ROM                      policy<{'armhf': '-'}>
+CONFIG_HW_RANDOM_OPTEE                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HW_RANDOM_XGENE                          policy<{'arm64': '-'}>
+CONFIG_HYSDN                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_HYSDN_CAPI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_ALGOBIT                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_I2C_ALI1535                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_ALI1563                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_ALI15X3                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_AMD756                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_AMD8111                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_ASPEED                               policy<{'armhf': '-'}>
+CONFIG_I2C_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_I2C_BCM_IPROC                            policy<{'arm64': '-'}>
+CONFIG_I2C_BRCMSTB                              policy<{'arm64': '-'}>
+CONFIG_I2C_CBUS_GPIO                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_CROS_EC_TUNNEL                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_DESIGNWARE_PCI                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_EXYNOS5                              policy<{'armhf': '-'}>
+CONFIG_I2C_FSI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_I2C_HIX5HD2                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_I801                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_IMX                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_I2C_IMX_LPI2C                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_I2C_ISCH                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_KEMPLD                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_MESON                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_MT65XX                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_MUX_MLXCPLD                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_MV64XXX                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_NFORCE2                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_NOMADIK                              policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_I2C_NVIDIA_GPU                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_OCORES                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_OMAP                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_OWL                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_PIIX4                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_PXA                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_PXA_SLAVE                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_QCOM_GENI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_QUP                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_RCAR                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_RIIC                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_RK3X                                 policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_S3C2410                              policy<{'armhf': '-'}>
+CONFIG_I2C_SCMI                                 policy<{'arm64': 'n'}>
+CONFIG_I2C_SH_MOBILE                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_SI470X                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_I2C_SI4713                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_I2C_SIMTEC                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_SIS5595                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_SIS630                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_SIS96X                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_SPRD                                 policy<{'arm64': '-'}>
+CONFIG_I2C_SYNQUACER                            policy<{'arm64': '-'}>
+CONFIG_I2C_TEGRA                                policy<{'armhf': '-'}>
+CONFIG_I2C_TEGRA_BPMP                           policy<{'armhf': '-'}>
+CONFIG_I2C_THUNDERX                             policy<{'arm64': 'n'}>
+CONFIG_I2C_UNIPHIER                             policy<{'armhf': '-'}>
+CONFIG_I2C_UNIPHIER_F                           policy<{'armhf': '-'}>
+CONFIG_I2C_VERSATILE                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I2C_VIA                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_VIAPRO                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I2C_XGENE_SLIMPRO                        policy<{'arm64': '-'}>
+CONFIG_I2C_XILINX                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_I2C_XLP9XX                               policy<{'arm64': '-'}>
+CONFIG_I40E                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I40EVF                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I40E_DCB                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_I6300ESB_WDT                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_I82092                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IAVF                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ICE                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ICST                                     policy<{'armhf': '-'}>
+CONFIG_IGB                                      policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_IGBVF                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IGB_HWMON                                policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_IGC                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IIO_CROS_EC_ACCEL_LEGACY                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_CROS_EC_BARO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_CROS_EC_LIGHT_PROX                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_CROS_EC_SENSORS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_CROS_EC_SENSORS_CORE                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IIO_RESCALE                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IKCONFIG                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IKCONFIG_PROC                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IKHEADERS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IMA_APPRAISE_MODSIG                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IMX2_WDT                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX7D_ADC                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX7ULP_WDT                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8MM_THERMAL                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8MP_HDMI_PAVI                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX8M_PM_DOMAINS                         policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_IMX8_DPRC                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX8_ISI_CAPTURE                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_ISI_CORE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_ISI_HW                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_ISI_M2M                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_JPEG                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_MEDIA_DEVICE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_MIPI_CSI2                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_MIPI_CSI2_SAM                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_MIPI_CSI2_YAV                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IMX8_PARALLEL_CSI                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX8_PC                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX8_PRG                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_DMA                                  policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_IMX_DPU_BLIT                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_DPU_CORE                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_DSP                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_GPCV2                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_GPCV2_PM_DOMAINS                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_IRQSTEER                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_LCDIFV3_CORE                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_LCDIF_CORE                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_MBOX                                 policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_IMX_REMOTEPROC                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_RPMSG_PINGPONG                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX_SCU                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_SCU_PD                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_SCU_SOC                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_SC_THERMAL                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX_SC_WDT                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX_SDMA                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IMX_SEMA4                                policy<{'armhf': 'y'}>
+CONFIG_IMX_THERMAL                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IMX_WEIM                                 policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_INDIRECT_PIO                             policy<{'arm64': 'n'}>
+CONFIG_INFINIBAND_BNXT_RE                       policy<{'arm64': 'n'}>
+CONFIG_INFINIBAND_CXGB3                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_CXGB4                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_EFA                           policy<{'arm64': 'n'}>
+CONFIG_INFINIBAND_HNS                           policy<{'arm64': '-'}>
+CONFIG_INFINIBAND_HNS_HIP06                     policy<{'arm64': '-'}>
+CONFIG_INFINIBAND_HNS_HIP08                     policy<{'arm64': '-'}>
+CONFIG_INFINIBAND_I40IW                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_IPOIB                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INFINIBAND_IPOIB_CM                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_IPOIB_DEBUG                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_ISER                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INFINIBAND_ISERT                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INFINIBAND_MTHCA                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INFINIBAND_MTHCA_DEBUG                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INFINIBAND_OCRDMA                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INFINIBAND_QEDR                          policy<{'arm64': '-'}>
+CONFIG_INFINIBAND_VMWARE_PVRDMA                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INIT_ON_ALLOC_DEFAULT_ON                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INLINE_READ_LOCK                         policy<{'arm64': '-'}>
+CONFIG_INLINE_READ_LOCK_BH                      policy<{'arm64': '-'}>
+CONFIG_INLINE_READ_LOCK_IRQ                     policy<{'arm64': '-'}>
+CONFIG_INLINE_READ_LOCK_IRQSAVE                 policy<{'arm64': '-'}>
+CONFIG_INLINE_READ_UNLOCK                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INLINE_READ_UNLOCK_BH                    policy<{'arm64': '-'}>
+CONFIG_INLINE_READ_UNLOCK_IRQ                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INLINE_READ_UNLOCK_IRQRESTORE            policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_LOCK                         policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_LOCK_BH                      policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_LOCK_IRQ                     policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_LOCK_IRQSAVE                 policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_TRYLOCK                      policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_TRYLOCK_BH                   policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_UNLOCK_BH                    policy<{'arm64': '-'}>
+CONFIG_INLINE_SPIN_UNLOCK_IRQ                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE            policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_LOCK                        policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_LOCK_BH                     policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_LOCK_IRQ                    policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_LOCK_IRQSAVE                policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_UNLOCK                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INLINE_WRITE_UNLOCK_BH                   policy<{'arm64': '-'}>
+CONFIG_INLINE_WRITE_UNLOCK_IRQ                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE           policy<{'arm64': '-'}>
+CONFIG_INPUT_HISI_POWERKEY                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_MAX77650_ONKEY                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_PCAP                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_INPUT_PM8941_PWRKEY                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_PM8XXX_VIBRATOR                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_INPUT_RAVE_SP_PWRBUTTON                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INPUT_SC27XX_VIBRA                       policy<{'arm64': '-'}>
+CONFIG_INPUT_SOC_BUTTON_ARRAY                   policy<{'arm64': 'n'}>
+CONFIG_INPUT_STPMIC1_ONKEY                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_TWL4030_PWRBUTTON                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_TWL4030_VIBRA                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_TWL6040_VIBRA                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INPUT_WM831X_ON                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND                policy<{'arm64': '-'}>
+CONFIG_INTEL_IDMA64                             policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_INTEL_STRATIX10_RSU                      policy<{'arm64': '-'}>
+CONFIG_INTEL_STRATIX10_SERVICE                  policy<{'arm64': '-'}>
+CONFIG_INTEL_TH_ACPI                            policy<{'arm64': 'n'}>
+CONFIG_INTEL_TH_PCI                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_INTERCONNECT                             policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_INTERCONNECT_QCOM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INTERCONNECT_QCOM_QCS404                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_INTERCONNECT_QCOM_SDM845                 policy<{'arm64': '-'}>
+CONFIG_INTERCONNECT_QCOM_SMD_RPM                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IOMMU_IOVA                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_ION                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IONIC                                    policy<{'arm64': 'n'}>
+CONFIG_ION_CMA_HEAP                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ION_SYSTEM_HEAP                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IPACK_BUS                                policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_IPMI_KCS_BMC                             policy<{'armhf': '-'}>
+CONFIG_IPQ_GCC_4019                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPQ_GCC_806X                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPQ_GCC_8074                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPQ_LCC_806X                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2100                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_IPW2100_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2100_MONITOR                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2200                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_IPW2200_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2200_MONITOR                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2200_PROMISCUOUS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2200_QOS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPW2200_RADIOTAP                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IPWIRELESS                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IP_PNP_BOOTP                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IP_PNP_DHCP                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IP_PNP_RARP                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IRQ_BYPASS_MANAGER                       policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_IRQ_CROSSBAR                             policy<{'armhf': '-'}>
+CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS           policy<{'arm64': '-'}>
+CONFIG_IRQ_SIM                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IRQ_UNIPHIER_AIDET                       policy<{'armhf': '-'}>
+CONFIG_IR_ENE                                   policy<{'arm64': 'n'}>
+CONFIG_IR_FINTEK                                policy<{'arm64': 'n'}>
+CONFIG_IR_ITE_CIR                               policy<{'arm64': 'n'}>
+CONFIG_IR_MESON                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IR_MTK                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IR_NUVOTON                               policy<{'arm64': 'n'}>
+CONFIG_IR_RCMM_DECODER                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IR_RX51                                  policy<{'armhf': '-'}>
+CONFIG_IR_SPI                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IR_SUNXI                                 policy<{'arm64': '-'}>
+CONFIG_ISCSI_IBFT                               policy<{'arm64': 'n'}>
+CONFIG_ISCSI_TARGET_CXGB4                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ISDN_CAPI_MIDDLEWARE                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ISDN_DRV_AVMB1_C4                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ISDN_DRV_AVMB1_T1PCI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ISI                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IWL3945                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_IWL4965                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_IWLDVM                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLEGACY                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLEGACY_DEBUG                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLEGACY_DEBUGFS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLMVM                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_IWLWIFI_BCAST_FILTERING                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI_DEBUGFS                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI_DEVICE_TRACING                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI_LEDS                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWLWIFI_OPMODE_MODULAR                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IWMMXT                                   policy<{'armhf': '-'}>
+CONFIG_IXGB                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IXGBE                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IXGBEVF                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IXGBEVF_IPSEC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IXGBE_DCB                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IXGBE_HWMON                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_IXGBE_IPSEC                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_JFFS2_SUMMARY                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_JME                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_JOYSTICK_FSIA6B                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_JUMP_LABEL                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_K3_DMA                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KEXEC_IMAGE_VERIFY_SIG                   policy<{'arm64': 'y'}>
+CONFIG_KEYBOARD_CROS_EC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KEYBOARD_IMX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_KEYBOARD_MTK_PMIC                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_KEYBOARD_NVEC                            policy<{'armhf': '-'}>
+CONFIG_KEYBOARD_SNVS_PWRKEY                     policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_KEYBOARD_SUN4I_LRADC                     policy<{'arm64': '-'}>
+CONFIG_KEYBOARD_TC3589X                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_KEYBOARD_TEGRA                           policy<{'armhf': '-'}>
+CONFIG_KEYBOARD_TWL4030                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KEYS_REQUEST_CACHE                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_KPC2000                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_KPC2000_CORE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KPC2000_DMA                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KPC2000_I2C                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KPC2000_SPI                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KPSS_XCC                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_KRAITCC                                  policy<{'armhf': '-'}>
+CONFIG_KRAIT_CLOCKS                             policy<{'armhf': '-'}>
+CONFIG_KRAIT_L2_ACCESSORS                       policy<{'armhf': '-'}>
+CONFIG_KSZ884X_PCI                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_AN30259A                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_CR0014114                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_GPIO                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_LM36274                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_LEDS_LM3692X                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_LM3697                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_LEDS_MAX77650                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_LEDS_MT6323                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LEDS_NS2                                 policy<{'armhf': '-'}>
+CONFIG_LEDS_SC27XX_BLTC                         policy<{'arm64': '-'}>
+CONFIG_LEDS_SPI_BYTE                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_TI_LMU_COMMON                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LEDS_TRIGGER_BACKLIGHT                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_TRIGGER_DEFAULT_ON                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_TRIGGER_GPIO                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_TRIGGER_HEARTBEAT                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_TRIGGER_ONESHOT                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_TRIGGER_TIMER                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LEDS_WM831X_STATUS                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LEDS_WM8350                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LEGACY_PTY_COUNT                         policy<{'arm64': '256', 'armhf': '256'}>
+CONFIG_LIB80211_CRYPT_TKIP                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS_CS                              policy<{'armhf': 'n'}>
+CONFIG_LIBERTAS_DEBUG                           policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_LIBERTAS_MESH                            policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_LIBERTAS_SDIO                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS_SPI                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS_THINFIRM                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS_THINFIRM_DEBUG                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_LIBERTAS_THINFIRM_USB                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBERTAS_USB                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_LIBIPW                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_LIBIPW_DEBUG                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_LIQUIDIO                                 policy<{'arm64': '-'}>
+CONFIG_LIQUIDIO_VF                              policy<{'arm64': '-'}>
+CONFIG_LOGO                                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LOGO_LINUX_CLUT224                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_LOGO_LINUX_MONO                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LOGO_LINUX_VGA16                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LOG_BUF_SHIFT                            policy<{'arm64': '17', 'armhf': '17'}>
+CONFIG_LPC_ICH                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LPC_SCH                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_LS_SCFG_MSI                              policy<{'arm64': '-'}>
+CONFIG_MACB_PCI                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MACH_ARMADA_370                          policy<{'armhf': '-'}>
+CONFIG_MACH_ARMADA_375                          policy<{'armhf': '-'}>
+CONFIG_MACH_ARMADA_38X                          policy<{'armhf': '-'}>
+CONFIG_MACH_ARMADA_39X                          policy<{'armhf': '-'}>
+CONFIG_MACH_ARMADA_XP                           policy<{'armhf': '-'}>
+CONFIG_MACH_ARTPEC6                             policy<{'armhf': '-'}>
+CONFIG_MACH_ASPEED_G6                           policy<{'armhf': '-'}>
+CONFIG_MACH_BERLIN_BG2                          policy<{'armhf': '-'}>
+CONFIG_MACH_BERLIN_BG2CD                        policy<{'armhf': '-'}>
+CONFIG_MACH_BERLIN_BG2Q                         policy<{'armhf': '-'}>
+CONFIG_MACH_DOVE                                policy<{'armhf': '-'}>
+CONFIG_MACH_MESON6                              policy<{'armhf': '-'}>
+CONFIG_MACH_MESON8                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT2701                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT6589                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT6592                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT7623                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT7629                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT8127                              policy<{'armhf': '-'}>
+CONFIG_MACH_MT8135                              policy<{'armhf': '-'}>
+CONFIG_MACH_MVEBU_ANY                           policy<{'armhf': '-'}>
+CONFIG_MACH_MVEBU_V7                            policy<{'armhf': '-'}>
+CONFIG_MACH_OMAP3517EVM                         policy<{'armhf': '-'}>
+CONFIG_MACH_OMAP3_PANDORA                       policy<{'armhf': '-'}>
+CONFIG_MACH_OMAP_GENERIC                        policy<{'armhf': '-'}>
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE               policy<{'arm64': '0x1', 'armhf': '0x01b6'}>
+CONFIG_MANTIS_CORE                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MAX5432                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MCB                                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MCB_LPC                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MCB_PCI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MCPM_QUAD_CLUSTER                        policy<{'armhf': '-'}>
+CONFIG_MDIO                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MDIO_ASPEED                              policy<{'armhf': '-'}>
+CONFIG_MDIO_BCM_IPROC                           policy<{'arm64': '-'}>
+CONFIG_MDIO_BCM_UNIMAC                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MDIO_BUS_MUX                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MDIO_BUS_MUX_BCM_IPROC                   policy<{'arm64': '-'}>
+CONFIG_MDIO_BUS_MUX_MESON_G12A                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MDIO_SUN4I                               policy<{'arm64': '-'}>
+CONFIG_MDIO_THUNDER                             policy<{'arm64': 'n'}>
+CONFIG_MDIO_XGENE                               policy<{'arm64': '-'}>
+CONFIG_MDM_GCC_9615                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MDM_LCC_9615                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEDIATEK_MT6577_AUXADC                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEDIATEK_WATCHDOG                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEDIA_ALTERA_CI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEDIA_ANALOG_TV_SUPPORT                  policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MEDIA_ATTACH                             policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MEDIA_CEC_RC                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEDIA_COMMON_OPTIONS                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MEDIA_CONTROLLER_DVB                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MEDIA_CONTROLLER_REQUEST_API             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT                 policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MEDIA_PCI_SUPPORT                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEDIA_RADIO_SUPPORT                      policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MEDIA_SDR_SUPPORT                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MEDIA_TUNER                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_E4000                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_FC0011                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_FC0012                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_FC0013                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_FC2580                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_IT913X                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_M88RS6000T                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MEDIA_TUNER_MAX2165                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MC44S803                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MSI001                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MT2060                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MT2063                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MT20XX                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MT2131                       policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MEDIA_TUNER_MT2266                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MXL301RF                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MEDIA_TUNER_MXL5005S                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_MXL5007T                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_QM1D1B0004                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MEDIA_TUNER_QM1D1C0042                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_QT1010                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_R820T                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_SI2157                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_SIMPLE                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18212                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18218                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18250                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18271                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA827X                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA8290                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TDA9887                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5761                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5767                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_TUA9001                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_XC2028                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_XC4000                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEDIA_TUNER_XC5000                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEGARAID_LEGACY                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEGARAID_MAILBOX                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEGARAID_MM                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MEGARAID_NEWGEN                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEGARAID_SAS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MELLANOX_PLATFORM                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEMORY_FAILURE                           policy<{'arm64': 'n'}>
+CONFIG_MEMORY_NOTIFIER_ERROR_INJECT             policy<{'arm64': 'n'}>
+CONFIG_MEMSTICK_JMICRON_38X                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEMSTICK_R592                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEMSTICK_REALTEK_PCI                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MEMSTICK_TIFM_MS                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MENZ069_WATCHDOG                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MEN_Z188_ADC                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MESON6_TIMER                             policy<{'armhf': '-'}>
+CONFIG_MESON_CANVAS                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_CLK_MEASURE                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_EE_PM_DOMAINS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_EFUSE                              policy<{'arm64': '-'}>
+CONFIG_MESON_GXBB_WATCHDOG                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_GXL_PHY                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_GX_PM_DOMAINS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_GX_SOCINFO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_IRQ_GPIO                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_MX_EFUSE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_MX_SOCINFO                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_SARADC                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MESON_SM                                 policy<{'arm64': '-'}>
+CONFIG_MESON_WATCHDOG                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_AC100                                policy<{'arm64': '-'}>
+CONFIG_MFD_ALTERA_SYSMGR                        policy<{'arm64': '-'}>
+CONFIG_MFD_AXP20X_RSB                           policy<{'arm64': '-'}>
+CONFIG_MFD_CROS_EC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_CROS_EC_DEV                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_CS47L24                              policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_CS47L35                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_CS47L85                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_CS47L90                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_EXYNOS_LPASS                         policy<{'armhf': '-'}>
+CONFIG_MFD_GATEWORKS_GSC                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MFD_HI655X_PMIC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_IMX_AUDIOMIX                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MFD_JANZ_CMODIO                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_LOCHNAGAR                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_MADERA_I2C                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_MAX77650                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_MT6397                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MFD_NVEC                                 policy<{'armhf': '-'}>
+CONFIG_MFD_OMAP_USB_HOST                        policy<{'armhf': '-'}>
+CONFIG_MFD_QCOM_RPM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_RDC321X                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_ROHM_BD718XX                         policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_MFD_SC27XX_PMIC                          policy<{'arm64': '-'}>
+CONFIG_MFD_SPMI_PMIC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_STMFX                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_STPMIC1                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_SUN4I_GPADC                          policy<{'arm64': '-'}>
+CONFIG_MFD_SUN6I_PRCM                           policy<{'arm64': '-'}>
+CONFIG_MFD_TC3589X                              policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_TI_AM335X_TSCADC                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_TPS68470                             policy<{'arm64': 'n'}>
+CONFIG_MFD_TQMX86                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_TWL4030_AUDIO                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_VEXPRESS_SYSREG                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MFD_VX855                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MFD_WM5102                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM5110                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM831X                               policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MFD_WM831X_I2C                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM831X_SPI                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM8350                               policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MFD_WM8350_I2C                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM8400                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM8994                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MFD_WM8997                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MFD_WM8998                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_MICREL_PHY                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MICROCHIP_PHY                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MII                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MILBEAUT_TIMER                           policy<{'armhf': '-'}>
+CONFIG_MISDN_AVMFRITZ                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_HDLC                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MISDN_HFCMULTI                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_HFCPCI                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_INFINEON                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_IPAC                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MISDN_ISAR                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MISDN_NETJET                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_SPEEDFAX                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MISDN_W6692                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MLX4_CORE                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX4_CORE_GEN2                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX4_DEBUG                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX4_EN                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MLX4_EN_DCB                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX4_INFINIBAND                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MLX5_ACCEL                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_CORE                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MLX5_CORE_EN                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_CORE_EN_DCB                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_CORE_IPOIB                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_EN_ARFS                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_EN_IPSEC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_EN_RXNFC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_EN_TLS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_ESWITCH                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_FPGA                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_FPGA_IPSEC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_FPGA_TLS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_INFINIBAND                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_MPFS                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_SW_STEERING                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX5_TLS                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXBF_TMFIFO                             policy<{'arm64': '-'}>
+CONFIG_MLXFW                                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MLXREG_HOTPLUG                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXREG_IO                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXSW_CORE                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MLXSW_CORE_HWMON                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MLXSW_CORE_THERMAL                       policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MLXSW_I2C                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MLXSW_MINIMAL                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MLXSW_PCI                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MLXSW_SPECTRUM                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXSW_SPECTRUM_DCB                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXSW_SWITCHIB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLXSW_SWITCHX2                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MLX_WDT                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_ALCOR                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_ARMMMCI                              policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_MMC_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_MMC_BLOCK_MINORS                         policy<{'arm64': '32', 'armhf': '32'}>
+CONFIG_MMC_CAVIUM_THUNDERX                      policy<{'arm64': '-'}>
+CONFIG_MMC_CB710                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_CQHCI                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_DW                                   policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MMC_DW_BLUEFIELD                         policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MMC_DW_EXYNOS                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MMC_DW_HI3798CV200                       policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MMC_DW_K3                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MMC_DW_PCI                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MMC_DW_PLTFM                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MMC_DW_ROCKCHIP                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_MESON_GX                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_MESON_MX_SDIO                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_MTK                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_MVSDIO                               policy<{'armhf': '-'}>
+CONFIG_MMC_MXC                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_OMAP                                 policy<{'armhf': '-'}>
+CONFIG_MMC_QCOM_DML                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_REALTEK_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_REALTEK_USB                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_RICOH_MMC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHCI_ACPI                           policy<{'arm64': 'n'}>
+CONFIG_MMC_SDHCI_AM654                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHCI_BRCMSTB                        policy<{'arm64': '-'}>
+CONFIG_MMC_SDHCI_CADENCE                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_DOVE                           policy<{'armhf': '-'}>
+CONFIG_MMC_SDHCI_ESDHC_IMX                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_SDHCI_F_SDH30                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_IPROC                          policy<{'arm64': '-'}>
+CONFIG_MMC_SDHCI_MSM                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHCI_OF_ARASAN                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHCI_OF_ASPEED                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHCI_OF_AT91                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHCI_OF_DWCMSHC                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_OF_ESDHC                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_SDHCI_OMAP                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHCI_PCI                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHCI_PXAV3                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHCI_S3C                            policy<{'armhf': '-'}>
+CONFIG_MMC_SDHCI_S3C_DMA                        policy<{'armhf': '-'}>
+CONFIG_MMC_SDHCI_SPRD                           policy<{'arm64': '-'}>
+CONFIG_MMC_SDHCI_TEGRA                          policy<{'armhf': '-'}>
+CONFIG_MMC_SDHCI_XENON                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SDHI                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHI_INTERNAL_DMAC                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDHI_SYS_DMAC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SDRICOH_CS                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_SH_MMCIF                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MMC_SPI                                  policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MMC_STM32_SDMMC                          policy<{'arm64': 'n', 'armhf': '-'}>
+CONFIG_MMC_SUNXI                                policy<{'arm64': '-'}>
+CONFIG_MMC_TIFM_SD                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_TMIO_CORE                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MMC_TOSHIBA_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_UNIPHIER                             policy<{'armhf': '-'}>
+CONFIG_MMC_USDHI6ROL0                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_VIA_SDMMC                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MMC_VUB300                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_MODULE_SIG_FORCE                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MOST_DIM2                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MOXA_INTELLIO                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MOXA_SMARTIO                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MOXTET                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MSCC_OCELOT_SWITCH                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MSCC_OCELOT_SWITCH_OCELOT                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MSM_GCC_8660                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8916                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8960                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8974                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8994                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8996                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_GCC_8998                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_IOMMU                                policy<{'armhf': '-'}>
+CONFIG_MSM_LCC_8960                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_MMCC_8960                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_MMCC_8974                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MSM_MMCC_8996                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MT7601U                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT7603E                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MT7615E                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MT76_CORE                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76_LEDS                                policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_MT76_USB                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x02_LIB                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x02_USB                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x0E                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MT76x0U                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x0_COMMON                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x2E                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MT76x2U                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MT76x2_COMMON                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MTD_BCM47XXSFLASH                        policy<{'armhf': '-'}>
+CONFIG_MTD_BLKDEVS                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_BLOCK_RO                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_CMDLINE_PARTS                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_HYPERBUS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_NAND_CAFE                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_NAND_CORE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_ECC_SW_HAMMING                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_FSL_IFC                         policy<{'arm64': '-'}>
+CONFIG_MTD_NAND_GPMI_NAND                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_NAND_HISI504                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_NAND_MARVELL                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_NAND_MESON                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_NAND_MTK                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_NAND_MXC                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_NAND_MXIC                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_NAND_OMAP_BCH_BUILD                  policy<{'armhf': '-'}>
+CONFIG_MTD_NAND_ORION                           policy<{'armhf': '-'}>
+CONFIG_MTD_NAND_QCOM                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_NAND_SUNXI                           policy<{'arm64': '-'}>
+CONFIG_MTD_NAND_TEGRA                           policy<{'armhf': '-'}>
+CONFIG_MTD_NAND_VF610_NFC                       policy<{'armhf': '-'}>
+CONFIG_MTD_ONENAND_OMAP2                        policy<{'armhf': '-'}>
+CONFIG_MTD_PCMCIA                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_PHYSMAP_GEMINI                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_PHYSMAP_OF                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTD_PHYSMAP_VERSATILE                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTD_SPI_NOR                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_CMDQ                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_CMDQ_MBOX                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_CQDMA                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_EFUSE                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_HSDMA                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_INFRACFG                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_IOMMU                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_IOMMU_V1                             policy<{'armhf': '-'}>
+CONFIG_MTK_PMIC_WRAP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_SCPSYS                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_SMI                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_THERMAL                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_TIMER                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MTK_UART_APDMA                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MUX_ADG792A                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MUX_ADGS1408                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MUX_GPIO                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MUX_MMIO                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MV643XX_ETH                              policy<{'armhf': '-'}>
+CONFIG_MVEBU_CLK_COMMON                         policy<{'armhf': '-'}>
+CONFIG_MVEBU_CLK_COREDIV                        policy<{'armhf': '-'}>
+CONFIG_MVEBU_CLK_CPU                            policy<{'armhf': '-'}>
+CONFIG_MVEBU_DEVBUS                             policy<{'armhf': '-'}>
+CONFIG_MVEBU_GICP                               policy<{'arm64': '-'}>
+CONFIG_MVEBU_ICU                                policy<{'arm64': '-'}>
+CONFIG_MVEBU_MBUS                               policy<{'armhf': '-'}>
+CONFIG_MVEBU_ODMI                               policy<{'arm64': '-'}>
+CONFIG_MVEBU_PIC                                policy<{'arm64': '-'}>
+CONFIG_MVEBU_SEI                                policy<{'arm64': '-'}>
+CONFIG_MVMDIO                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MVNETA                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MVNETA_BM_ENABLE                         policy<{'armhf': '-'}>
+CONFIG_MVPP2                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MV_XOR                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_MV_XOR_V2                                policy<{'arm64': 'n'}>
+CONFIG_MWIFIEX                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MWIFIEX_PCIE                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MWIFIEX_SDIO                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MWIFIEX_USB                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_MWL8K                                    policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_MX3_IPU                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MX3_IPU_IRQS                             policy<{'arm64': '4', 'armhf': '4'}>
+CONFIG_MXC_CAMERA_OV5640_MIPI_V2                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_CAMERA_OV5640_V2                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_CAMERA_OV5647_MIPI                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MXC_CAMERA_OV9281_MIPI_V2                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_CLK                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MXC_CLK_SCU                              policy<{'arm64': '-'}>
+CONFIG_MXC_GPU_VIV                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_HANTRO                               policy<{'arm64': 'm'}>
+CONFIG_MXC_HANTRO_845                           policy<{'arm64': 'm'}>
+CONFIG_MXC_HANTRO_845_H1                        policy<{'arm64': 'm'}>
+CONFIG_MXC_HANTRO_VC8000E                       policy<{'arm64': 'm'}>
+CONFIG_MXC_IMX_DMX_HW                           policy<{'arm64': 'n'}>
+CONFIG_MXC_IPU                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MXC_MIPI_CSI                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_MIPI_CSI2                            policy<{'armhf': 'n'}>
+CONFIG_MXC_MLB                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MXC_MLB150                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_SIM                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MXC_TZIC                                 policy<{'armhf': '-'}>
+CONFIG_MXC_VADC                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MXC_VPU                                  policy<{'armhf': 'n'}>
+CONFIG_MXC_VPU_MALONE                           policy<{'arm64': 'n'}>
+CONFIG_MXC_VPU_WINDSOR                          policy<{'arm64': 'n'}>
+CONFIG_MXS_DMA                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MYRI10GE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NATSEMI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_NCSI_OEM_CMD_GET_MAC                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NE2K_PCI                                 policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_NEED_SG_DMA_LENGTH                       policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_NETFILTER_XT_TARGET_NOTRACK              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_NETXEN_NIC                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NET_9P_XEN                               policy<{'arm64': '-'}>
+CONFIG_NET_CALXEDA_XGMAC                        policy<{'armhf': '-'}>
+CONFIG_NET_DSA_LOOP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ8795                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NET_DSA_SJA1105_TAS                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_FC                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_SB1000                               policy<{'arm64': 'n'}>
+CONFIG_NET_TC_SKB_EXT                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_TULIP                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NET_VENDOR_3COM                          policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_8390                          policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ADAPTEC                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_AGERE                         policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ALACRITECH                    policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ALLWINNER                     policy<{'arm64': '-'}>
+CONFIG_NET_VENDOR_ALTEON                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_AMAZON                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_AMD                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ARC                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ATHEROS                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_AURORA                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_BROCADE                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_CAVIUM                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_CHELSIO                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_CISCO                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_DEC                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_DLINK                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_EZCHIP                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_FREESCALE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_FUJITSU                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_HISILICON                     policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_HP                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_HUAWEI                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_MARVELL                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_MEDIATEK                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NET_VENDOR_MELLANOX                      policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_MICROSEMI                     policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_MYRI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_NATSEMI                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_NETERION                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_NETRONOME                     policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_NI                            policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_NVIDIA                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_OKI                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_PACKET_ENGINES                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_QLOGIC                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_QUALCOMM                      policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_RDC                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_REALTEK                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_RENESAS                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_ROCKER                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_SAMSUNG                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_SILAN                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_SIS                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_SMSC                          policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_SOLARFLARE                    policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_SUN                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_TEHUTI                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_TI                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_VIA                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_WIZNET                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_XILINX                        policy<{'armhf': 'n'}>
+CONFIG_NET_VENDOR_XIRCOM                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_NET_XGENE                                policy<{'arm64': '-'}>
+CONFIG_NET_XGENE_V2                             policy<{'arm64': '-'}>
+CONFIG_NFIT_SECURITY_DEBUG                      policy<{'arm64': '-'}>
+CONFIG_NFP                                      policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_NFP_APP_ABM_NIC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NFP_APP_FLOWER                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NFP_DEBUG                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NFT_FIB_INET                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NF_FLOW_TABLE_INET                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NF_FLOW_TABLE_IPV4                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NF_FLOW_TABLE_IPV6                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NIU                                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NI_XGE_MANAGEMENT_ENET                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_NLS_ASCII                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NOA1305                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NODES_SHIFT                              policy<{'arm64': '2'}>
+CONFIG_NOKIA_MODEM                              policy<{'armhf': '-'}>
+CONFIG_NORTEL_HERMES                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NOUVEAU_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NOUVEAU_DEBUG_DEFAULT                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NOUVEAU_DEBUG_MMU                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NOUVEAU_PLATFORM_DRIVER                  policy<{'armhf': '-'}>
+CONFIG_NOZOMI                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NO_IOPORT_MAP                            policy<{'armhf': '-'}>
+CONFIG_NPCM7XX_KCS_IPMI_BMC                     policy<{'armhf': '-'}>
+CONFIG_NPCM7XX_TIMER                            policy<{'armhf': '-'}>
+CONFIG_NPCM7XX_WATCHDOG                         policy<{'armhf': '-'}>
+CONFIG_NPCM_ADC                                 policy<{'armhf': '-'}>
+CONFIG_NS83820                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_NTB                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NTB_IDT                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_MSI                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_MSI_TEST                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_NETDEV                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_PERF                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_PINGPONG                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_SWITCHTEC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_TOOL                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTB_TRANSPORT                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_NTFS_RW                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NUMA_BALANCING                           policy<{'arm64': 'n'}>
+CONFIG_NVEC_PAZ00                               policy<{'armhf': '-'}>
+CONFIG_NVEC_POWER                               policy<{'armhf': '-'}>
+CONFIG_NVMEM_BCM_OCOTP                          policy<{'arm64': '-'}>
+CONFIG_NVMEM_IMX_IIM                            policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_NVMEM_IMX_OCOTP                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NVMEM_IMX_OCOTP_SCU                      policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_NVMEM_SNVS_LPGPR                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NVMEM_SUNXI_SID                          policy<{'arm64': '-'}>
+CONFIG_NVMEM_VF610_OCOTP                        policy<{'armhf': '-'}>
+CONFIG_NVMEM_ZYNQMP                             policy<{'arm64': '-'}>
+CONFIG_NVME_MULTIPATH                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_OBJAGG                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OCTEONTX2_AF                             policy<{'arm64': '-'}>
+CONFIG_OCTEONTX2_MBOX                           policy<{'arm64': '-'}>
+CONFIG_OF_FPGA_REGION                           policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_OF_PMEM                                  policy<{'arm64': 'y'}>
+CONFIG_OMAP2PLUS_MBOX                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OMAP2_VRFB                               policy<{'armhf': '-'}>
+CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE         policy<{'armhf': '-'}>
+CONFIG_OMAP3_SDRC_AC_TIMING                     policy<{'armhf': '-'}>
+CONFIG_OMAP3_THERMAL                            policy<{'armhf': '-'}>
+CONFIG_OMAP4_THERMAL                            policy<{'armhf': '-'}>
+CONFIG_OMAP5_ERRATA_801819                      policy<{'armhf': '-'}>
+CONFIG_OMAP_32K_TIMER                           policy<{'armhf': '-'}>
+CONFIG_OMAP_CONTROL_PHY                         policy<{'armhf': '-'}>
+CONFIG_OMAP_DM_TIMER                            policy<{'armhf': '-'}>
+CONFIG_OMAP_GPMC                                policy<{'armhf': '-'}>
+CONFIG_OMAP_GPMC_DEBUG                          policy<{'armhf': '-'}>
+CONFIG_OMAP_INTERCONNECT                        policy<{'armhf': '-'}>
+CONFIG_OMAP_INTERCONNECT_BARRIER                policy<{'armhf': '-'}>
+CONFIG_OMAP_IOMMU                               policy<{'armhf': '-'}>
+CONFIG_OMAP_IOMMU_DEBUG                         policy<{'armhf': '-'}>
+CONFIG_OMAP_IRQCHIP                             policy<{'armhf': '-'}>
+CONFIG_OMAP_MBOX_KFIFO_SIZE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OMAP_OCP2SCP                             policy<{'armhf': '-'}>
+CONFIG_OMAP_PACKAGE_CBB                         policy<{'armhf': '-'}>
+CONFIG_OMAP_REMOTEPROC                          policy<{'armhf': '-'}>
+CONFIG_OMAP_RESET_CLOCKS                        policy<{'armhf': '-'}>
+CONFIG_OMAP_SSI                                 policy<{'armhf': '-'}>
+CONFIG_OMAP_USB2                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OMAP_WATCHDOG                            policy<{'armhf': '-'}>
+CONFIG_OPTEE                                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ORINOCO_USB                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ORION_IRQCHIP                            policy<{'armhf': '-'}>
+CONFIG_ORION_TIMER                              policy<{'armhf': '-'}>
+CONFIG_ORION_WATCHDOG                           policy<{'armhf': '-'}>
+CONFIG_OWL_DMA                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OWL_PM_DOMAINS                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OWL_PM_DOMAINS_HELPER                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_OWL_TIMER                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_P54_COMMON                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_P54_LEDS                                 policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_P54_PCI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_P54_SPI                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_P54_SPI_DEFAULT_EEPROM                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_P54_USB                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_PARAVIRT                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PARMAN                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PARPORT_1284                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PARPORT_PC_FIFO                          policy<{'armhf': 'n'}>
+CONFIG_PARPORT_PC_PCMCIA                        policy<{'armhf': 'n'}>
+CONFIG_PARPORT_SERIAL                           policy<{'armhf': '-'}>
+CONFIG_PARTITION_PERCPU                         policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_PATA_ACPI                                policy<{'arm64': 'n'}>
+CONFIG_PATA_ALI                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_AMD                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_ARTOP                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_ATIIXP                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_ATP867X                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_CMD640_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_CMD64X                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_CYPRESS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_EFAR                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_HPT366                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_HPT37X                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_HPT3X2N                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_HPT3X3                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_IMX                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_IT8213                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_IT821X                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_JMICRON                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_LEGACY                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_MARVELL                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_MPIIX                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_NETCELL                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_NINJA32                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_NS87410                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_NS87415                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_OLDPIIX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_OPTI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_OPTIDMA                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_PCMCIA                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_PDC2027X                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_PDC_OLD                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_RADISYS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_RDC                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_RZ1000                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_SCH                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_SERVERWORKS                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_SIL680                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_SIS                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_TOSHIBA                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_TRIFLEX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_VIA                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PATA_WINBOND                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PC104                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PC300TOO                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCCARD                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCI200SYN                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_AL                                  policy<{'arm64': 'n'}>
+CONFIG_PCIE_ALTERA                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_ALTERA_MSI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_ARMADA_8K                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_CADENCE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_CADENCE_EP                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_CADENCE_HOST                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_DW_EP                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_DW_PLAT_EP                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_HISI_STB                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_IPROC                               policy<{'arm64': '-'}>
+CONFIG_PCIE_IPROC_MSI                           policy<{'arm64': '-'}>
+CONFIG_PCIE_IPROC_PLATFORM                      policy<{'arm64': '-'}>
+CONFIG_PCIE_KIRIN                               policy<{'arm64': 'n'}>
+CONFIG_PCIE_MEDIATEK                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_MOBIVEIL                            policy<{'arm64': '-'}>
+CONFIG_PCIE_QCOM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_RCAR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_ROCKCHIP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_ROCKCHIP_EP                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_ROCKCHIP_HOST                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCIE_UNIPHIER                            policy<{'armhf': '-'}>
+CONFIG_PCIE_XILINX                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCIE_XILINX_NWL                          policy<{'arm64': '-'}>
+CONFIG_PCIPCWATCHDOG                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCI_AARDVARK                             policy<{'arm64': '-'}>
+CONFIG_PCI_ATMEL                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCI_BRIDGE_EMUL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PCI_DRA7XX                               policy<{'armhf': '-'}>
+CONFIG_PCI_DRA7XX_EP                            policy<{'armhf': '-'}>
+CONFIG_PCI_DRA7XX_HOST                          policy<{'armhf': '-'}>
+CONFIG_PCI_FTPCI100                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCI_HISI                                 policy<{'arm64': 'n'}>
+CONFIG_PCI_HOST_THUNDER_ECAM                    policy<{'arm64': 'n'}>
+CONFIG_PCI_HOST_THUNDER_PEM                     policy<{'arm64': 'n'}>
+CONFIG_PCI_IMX6                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCI_KEYSTONE                             policy<{'arm64': '-'}>
+CONFIG_PCI_KEYSTONE_EP                          policy<{'arm64': '-'}>
+CONFIG_PCI_KEYSTONE_HOST                        policy<{'arm64': '-'}>
+CONFIG_PCI_LAYERSCAPE                           policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_PCI_LAYERSCAPE_EP                        policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_PCI_MVEBU                                policy<{'armhf': '-'}>
+CONFIG_PCI_RCAR_GEN2                            policy<{'armhf': '-'}>
+CONFIG_PCI_SW_SWITCHTEC                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PCI_TEGRA                                policy<{'armhf': '-'}>
+CONFIG_PCI_V3_SEMI                              policy<{'armhf': 'n'}>
+CONFIG_PCI_XGENE                                policy<{'arm64': 'n'}>
+CONFIG_PCI_XGENE_MSI                            policy<{'arm64': '-'}>
+CONFIG_PCMCIA                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCMCIA_3C574                             policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_3C589                             policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_AXNET                             policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_FMVJ18X                           policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_LOAD_CIS                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCMCIA_NMCLAN                            policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_PCNET                             policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_RAYCS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCMCIA_SMC91C92                          policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_WL3501                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCMCIA_XIRC2PS                           policy<{'armhf': 'm'}>
+CONFIG_PCMCIA_XIRCOM                            policy<{'arm64': '-'}>
+CONFIG_PCNET32                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_PD6729                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PDC_ADMA                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PGTABLE_LEVELS                           policy<{'arm64': '4', 'armhf': '2'}>
+CONFIG_PHY_AM654_SERDES                         policy<{'arm64': '-'}>
+CONFIG_PHY_BCM_NS_USB2                          policy<{'arm64': '-'}>
+CONFIG_PHY_BCM_NS_USB3                          policy<{'arm64': '-'}>
+CONFIG_PHY_BCM_SR_PCIE                          policy<{'arm64': '-'}>
+CONFIG_PHY_BCM_SR_USB                           policy<{'arm64': '-'}>
+CONFIG_PHY_BERLIN_SATA                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_BERLIN_USB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_BRCM_SATA                            policy<{'arm64': '-'}>
+CONFIG_PHY_BRCM_USB                             policy<{'arm64': '-'}>
+CONFIG_PHY_CADENCE_DP                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_CADENCE_DPHY                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_CADENCE_SIERRA                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_CPCAP_USB                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_PHY_DM816X_USB                           policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS5250_SATA                      policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS5250_USB2                      policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS5_USBDRD                       policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS_DP_VIDEO                      policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS_MIPI_VIDEO                    policy<{'armhf': '-'}>
+CONFIG_PHY_EXYNOS_PCIE                          policy<{'armhf': '-'}>
+CONFIG_PHY_FSL_IMX8MP_LVDS                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_HI3660_USB                           policy<{'arm64': '-'}>
+CONFIG_PHY_HI6220_USB                           policy<{'arm64': '-'}>
+CONFIG_PHY_HISI_INNO_USB2                       policy<{'arm64': '-'}>
+CONFIG_PHY_HISTB_COMBPHY                        policy<{'arm64': '-'}>
+CONFIG_PHY_HIX5HD2_SATA                         policy<{'armhf': '-'}>
+CONFIG_PHY_MAPPHONE_MDM6600                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_MESON8B_USB2                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MESON_G12A_USB2                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MESON_G12A_USB3_PCIE                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MESON_GXL_USB2                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MESON_GXL_USB3                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MIXEL_MIPI_DPHY                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_MTK_TPHY                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MTK_UFS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MTK_XSPHY                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MVEBU_A3700_COMPHY                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MVEBU_A3700_UTMI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MVEBU_A38X_COMPHY                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MVEBU_CP110_COMPHY                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_MVEBU_SATA                           policy<{'armhf': '-'}>
+CONFIG_PHY_NS2_PCIE                             policy<{'arm64': '-'}>
+CONFIG_PHY_NS2_USB_DRD                          policy<{'arm64': '-'}>
+CONFIG_PHY_OCELOT_SERDES                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_PXA_28NM_HSIC                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_PXA_28NM_USB2                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_QCOM_APQ8064_SATA                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_IPQ806X_SATA                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_PCIE2                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_QMP                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_QUSB2                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_UFS                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_UFS_14NM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_QCOM_USB_HS                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_QCOM_USB_HSIC                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_RCAR_GEN2                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_RCAR_GEN3_PCIE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_RCAR_GEN3_USB2                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_RCAR_GEN3_USB3                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_DP                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_EMMC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_INNO_HDMI                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_INNO_USB2                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_PCIE                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_TYPEC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_ROCKCHIP_USB                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PHY_SAMSUNG_HDMI_PHY                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_SAMSUNG_USB2                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_SUN4I_USB                            policy<{'arm64': '-'}>
+CONFIG_PHY_SUN6I_MIPI_DPHY                      policy<{'arm64': '-'}>
+CONFIG_PHY_SUN9I_USB                            policy<{'arm64': '-'}>
+CONFIG_PHY_TEGRA_XUSB                           policy<{'armhf': '-'}>
+CONFIG_PHY_TI_GMII_SEL                          policy<{'armhf': '-'}>
+CONFIG_PHY_TUSB1210                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PHY_UNIPHIER_PCIE                        policy<{'armhf': '-'}>
+CONFIG_PHY_UNIPHIER_USB2                        policy<{'armhf': '-'}>
+CONFIG_PHY_UNIPHIER_USB3                        policy<{'armhf': '-'}>
+CONFIG_PHY_XGENE                                policy<{'arm64': 'n'}>
+CONFIG_PINCTRL_AMD                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PINCTRL_APQ8064                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_APQ8084                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_ARMADA_370                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_ARMADA_375                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_ARMADA_37XX                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_ARMADA_38X                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_ARMADA_39X                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_ARMADA_AP806                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_ARMADA_CP110                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_ARMADA_XP                        policy<{'armhf': '-'}>
+CONFIG_PINCTRL_AS370                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_AS3722                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_PINCTRL_ASPEED                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_ASPEED_G6                        policy<{'armhf': '-'}>
+CONFIG_PINCTRL_AXP209                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PINCTRL_BCM2835                          policy<{'arm64': '-'}>
+CONFIG_PINCTRL_BERLIN                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_BERLIN_BG2                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_BERLIN_BG2CD                     policy<{'armhf': '-'}>
+CONFIG_PINCTRL_BERLIN_BG2Q                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_BERLIN_BG4CT                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_BM1880                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_CS47L35                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_CS47L85                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_CS47L90                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_DOVE                             policy<{'armhf': '-'}>
+CONFIG_PINCTRL_EXYNOS                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_EXYNOS_ARM                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IMX50                            policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX51                            policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX6Q                            policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_IMX6SL                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX6SLL                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX6SX                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_IMX6UL                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_IMX7D                            policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_IMX7ULP                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_IMX8MM                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IMX8MN                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IMX8MP                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IMX8MQ                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_IPQ4019                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_IPQ8064                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_IPQ8074                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_IPROC_GPIO                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_LOCHNAGAR                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MDM9615                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MESON                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MESON8                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MESON8B                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MESON8_PMX                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MESON_AXG                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MESON_AXG_PMX                    policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MESON_G12A                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MESON_GXBB                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MESON_GXL                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MSM                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8660                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8916                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8960                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8994                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8996                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8998                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MSM8X74                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MT2701                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MT2712                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT6397                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MT6765                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT6797                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT7622                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT7623                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MT7629                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MT8127                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MT8135                           policy<{'armhf': '-'}>
+CONFIG_PINCTRL_MT8173                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT8183                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MT8516                           policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MTK                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MTK_MOORE                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_MTK_PARIS                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_MVEBU                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_NPCM7XX                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_NS2_MUX                          policy<{'arm64': '-'}>
+CONFIG_PINCTRL_OCELOT                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PINCTRL_OWL                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_PFC_EMEV2                        policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7740                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7743                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7744                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7745                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A77470                     policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A774A1                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A774C0                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A7778                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7779                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7790                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7791                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7792                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7793                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7794                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_PFC_R8A7795                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A7796                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A77965                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A77970                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A77980                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A77990                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_R8A77995                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_PFC_SH73A0                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_QCOM_SPMI_PMIC                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_QCOM_SSBI_PMIC                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_QCS404                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_QDF2XXX                          policy<{'arm64': '-'}>
+CONFIG_PINCTRL_RK805                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_PINCTRL_ROCKCHIP                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_RZA1                             policy<{'armhf': '-'}>
+CONFIG_PINCTRL_RZA2                             policy<{'armhf': '-'}>
+CONFIG_PINCTRL_RZN1                             policy<{'armhf': '-'}>
+CONFIG_PINCTRL_S700                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_S900                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SAMSUNG                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_SC7180                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SDM660                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SDM845                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SH_PFC                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SH_PFC_GPIO                      policy<{'armhf': '-'}>
+CONFIG_PINCTRL_SINGLE                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PINCTRL_SM8150                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PINCTRL_SPRD                             policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SPRD_SC9860                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_STMFX                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PINCTRL_SUN4I_A10                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN50I_A64                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN50I_A64_R                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN50I_H5                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN50I_H6                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN50I_H6_R                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN5I                            policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN6I_A31                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN6I_A31_R                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_A23                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_A23_R                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_A33                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_A83T                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_A83T_R                     policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_H3                         policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_H3_R                       policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN8I_V3S                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN9I_A80                        policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUN9I_A80_R                      policy<{'arm64': '-'}>
+CONFIG_PINCTRL_SUNXI                            policy<{'arm64': '-'}>
+CONFIG_PINCTRL_TEGRA                            policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TEGRA114                         policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TEGRA124                         policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TEGRA20                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TEGRA30                          policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TEGRA_XUSB                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_TI_IODELAY                       policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER                         policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_LD11                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_LD20                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_LD4                     policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_LD6B                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_PRO4                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_PRO5                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_PXS2                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_PXS3                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_UNIPHIER_SLD8                    policy<{'armhf': '-'}>
+CONFIG_PINCTRL_VF610                            policy<{'armhf': '-'}>
+CONFIG_PJ4B_ERRATA_4742                         policy<{'armhf': '-'}>
+CONFIG_PL310_ERRATA_588369                      policy<{'armhf': 'n'}>
+CONFIG_PL310_ERRATA_727915                      policy<{'armhf': 'n'}>
+CONFIG_PL310_ERRATA_753970                      policy<{'armhf': 'n'}>
+CONFIG_PL320_MBOX                               policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_PL330_DMA                                policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_PL353_SMC                                policy<{'armhf': '-'}>
+CONFIG_PLATFORM_SI4713                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_PLAT_ORION                               policy<{'armhf': '-'}>
+CONFIG_PLAT_SAMSUNG                             policy<{'armhf': '-'}>
+CONFIG_PLAT_VERSATILE                           policy<{'armhf': '-'}>
+CONFIG_PLX_HERMES                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PM8916_WATCHDOG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PNP_DEBUG_MESSAGES                       policy<{'arm64': 'y'}>
+CONFIG_POWER_AVS_OMAP                           policy<{'armhf': '-'}>
+CONFIG_POWER_AVS_OMAP_CLASS3                    policy<{'armhf': '-'}>
+CONFIG_POWER_RESET_HISI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_POWER_RESET_MSM                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_POWER_RESET_QCOM_PON                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_POWER_RESET_QNAP                         policy<{'armhf': '-'}>
+CONFIG_POWER_RESET_RMOBILE                      policy<{'armhf': '-'}>
+CONFIG_POWER_RESET_SC27XX                       policy<{'arm64': '-'}>
+CONFIG_POWER_RESET_VEXPRESS                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PREEMPT                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PREEMPTION                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PREEMPT_COUNT                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PREEMPT_RCU                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PREEMPT_TRACER                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PREEMPT_VOLUNTARY                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PRINT_QUOTA_WARNING                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PRISM54                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_PSTORE_CONSOLE                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PSTORE_RAM                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PTP_1588_CLOCK_DTE                       policy<{'arm64': '-'}>
+CONFIG_PTP_1588_CLOCK_QORIQ                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_PWM_BCM_IPROC                            policy<{'arm64': '-'}>
+CONFIG_PWM_BERLIN                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_BRCMSTB                              policy<{'arm64': '-'}>
+CONFIG_PWM_CROS_EC                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_HIBVT                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_IMX1                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_IMX27                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_IMX_TPM                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_MEDIATEK                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_MESON                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_MTK_DISP                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_OMAP_DMTIMER                         policy<{'armhf': '-'}>
+CONFIG_PWM_RCAR                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_RENESAS_TPU                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_ROCKCHIP                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_SAMSUNG                              policy<{'armhf': '-'}>
+CONFIG_PWM_SPRD                                 policy<{'arm64': '-'}>
+CONFIG_PWM_STMPE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PWM_SUN4I                                policy<{'arm64': '-'}>
+CONFIG_PWM_TEGRA                                policy<{'armhf': '-'}>
+CONFIG_PWM_TIECAP                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_TIEHRPWM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_TIPWMSS                              policy<{'armhf': '-'}>
+CONFIG_PWM_TWL                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWM_TWL_LED                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_PWRSEQ_EMMC                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PWRSEQ_SIMPLE                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PXA168_ETH                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCA7000                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_QCA7000_SPI                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_QCA7000_UART                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_QCOM_A53PLL                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_AOSS_QMP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_APCS_IPC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_APR                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_BAM_DMA                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_CLK_APCS_MSM8916                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_CLK_RPM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_CLK_RPMH                            policy<{'arm64': '-'}>
+CONFIG_QCOM_CLK_SMD_RPM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_COINCELL                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_COMMAND_DB                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_EBI2                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_EMAC                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_QCOM_FASTRPC                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_GDSC                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_GENI_SE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_GLINK_SSR                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_GSBI                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_HFPLL                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_HIDMA                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QCOM_HIDMA_MGMT                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QCOM_IOMMU                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_IRQ_COMBINER                        policy<{'arm64': '-'}>
+CONFIG_QCOM_L2_PMU                              policy<{'arm64': '-'}>
+CONFIG_QCOM_L3_PMU                              policy<{'arm64': '-'}>
+CONFIG_QCOM_LLCC                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_MDT_LOADER                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_PDC                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_PM                                  policy<{'armhf': '-'}>
+CONFIG_QCOM_Q6V5_ADSP                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_Q6V5_COMMON                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_Q6V5_MSS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_Q6V5_PAS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_Q6V5_WCSS                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_QFPROM                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_QMI_HELPERS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_RMTFS_MEM                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_RPMCC                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_RPMH                                policy<{'arm64': '-'}>
+CONFIG_QCOM_RPMHPD                              policy<{'arm64': '-'}>
+CONFIG_QCOM_RPROC_COMMON                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SCM                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SCM_32                              policy<{'armhf': '-'}>
+CONFIG_QCOM_SCM_64                              policy<{'arm64': '-'}>
+CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SMD_RPM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SMEM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SMEM_STATE                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SMP2P                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SMSM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SOCINFO                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SPMI_TEMP_ALARM                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_SYSMON                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_TSENS                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_WCNSS_CTRL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_WCNSS_PIL                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCOM_WDT                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCS_GCC_404                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QCS_TURING_404                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED                                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QEDE                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QEDF                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QEDI                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED_FCOE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED_ISCSI                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED_LL2                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED_OOO                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QED_RDMA                                 policy<{'arm64': '-'}>
+CONFIG_QED_SRIOV                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLA3XXX                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLCNIC                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLCNIC_DCB                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLCNIC_HWMON                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLCNIC_SRIOV                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QLGE                                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QORIQ_CPUFREQ                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QRTR                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QRTR_SMD                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QRTR_TUN                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QTNFMAC                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_QTNFMAC_PCIE                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_R6040                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_R8169                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RADIO_ADAPTERS                           policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RADIO_MAXIRADIO                          policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RADIO_SAA7706H                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_SHARK                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_SHARK2                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_SI470X                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_SI4713                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_SI476X                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_TEA575X                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_TEA5764                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_TEF6862                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_WL1273                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RADIO_WL128X                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RANDOM_TRUST_BOOTLOADER                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RAPIDIO                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RAPIDIO_CHMAN                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_CPS_GEN2                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_CPS_XX                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_DEBUG                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_DISC_TIMEOUT                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_DMA_ENGINE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_ENUM_BASIC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_MPORT_CDEV                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_RXS_GEN3                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_TSI568                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_TSI57X                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAPIDIO_TSI721                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RASPBERRYPI_FIRMWARE                     policy<{'arm64': '-'}>
+CONFIG_RASPBERRYPI_POWER                        policy<{'arm64': '-'}>
+CONFIG_RAVB                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RAVE_SP_EEPROM                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_RCAR_DMAC                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RCAR_GEN3_THERMAL                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RCAR_GYRO_ADC                            policy<{'armhf': '-'}>
+CONFIG_RCAR_THERMAL                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RCU_CPU_STALL_TIMEOUT                    policy<{'arm64': '21', 'armhf': '21'}>
+CONFIG_RC_CORE                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RDA_INTC                                 policy<{'armhf': '-'}>
+CONFIG_RDA_TIMER                                policy<{'armhf': '-'}>
+CONFIG_RDMA_RXE                                 policy<{'arm64': 'n'}>
+CONFIG_RDMA_SIW                                 policy<{'arm64': 'n'}>
+CONFIG_READ_ONLY_THP_FOR_FS                     policy<{'arm64': '-'}>
+CONFIG_REED_SOLOMON                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGMAP_AC97                              policy<{'armhf': '-'}>
+CONFIG_REGMAP_SCCB                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGMAP_SLIMBUS                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_ANATOP                         policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_REGULATOR_BD718XX                        policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_REGULATOR_GPIO                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_REGULATOR_HI655X                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_LOCHNAGAR                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_LP87565                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_REGULATOR_MAX77650                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_MCP16502                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_REGULATOR_MT6311                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_MT6323                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_MT6380                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_MT6397                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_PBIAS                          policy<{'armhf': '-'}>
+CONFIG_REGULATOR_PCA9450                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_PCAP                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_QCOM_RPM                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_QCOM_RPMH                      policy<{'arm64': '-'}>
+CONFIG_REGULATOR_QCOM_SMD_RPM                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_QCOM_SPMI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_RK808                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_S2MPA01                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_S2MPS11                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_S5M8767                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_REGULATOR_SC2731                         policy<{'arm64': '-'}>
+CONFIG_REGULATOR_STPMIC1                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_SY8106A                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_REGULATOR_SY8824X                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_REGULATOR_TI_ABB                         policy<{'armhf': '-'}>
+CONFIG_REGULATOR_UNIPHIER                       policy<{'armhf': '-'}>
+CONFIG_REGULATOR_VEXPRESS                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_REGULATOR_WM831X                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_WM8350                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_WM8400                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REGULATOR_WM8994                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_REMOTEPROC_CDEV                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RENESAS_DMA                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RENESAS_INTC_IRQPIN                      policy<{'armhf': '-'}>
+CONFIG_RENESAS_IRQC                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RENESAS_OSTM                             policy<{'armhf': '-'}>
+CONFIG_RENESAS_RZA1_IRQC                        policy<{'armhf': '-'}>
+CONFIG_RENESAS_RZAWDT                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RENESAS_USB_DMAC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RENESAS_WDT                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_ASUS_PE100A                        policy<{'arm64': 'm'}>
+CONFIG_RESET_ATTACK_MITIGATION                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RESET_BERLIN                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_BRCMSTB                            policy<{'arm64': '-'}>
+CONFIG_RESET_DISPMIX                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_HISI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_IMX7                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_IMX_AUDIOMIX                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_IMX_HDMIMIX                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_MESON                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_MESON_AUDIO_ARB                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_QCOM_AOSS                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_QCOM_PDC                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_SCMI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_SIMPLE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RESET_SUNXI                              policy<{'arm64': '-'}>
+CONFIG_RESET_TEGRA_BPMP                         policy<{'armhf': '-'}>
+CONFIG_RESET_TI_SCI                             policy<{'arm64': '-'}>
+CONFIG_RESET_TI_SYSCON                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RESET_UNIPHIER                           policy<{'armhf': '-'}>
+CONFIG_RESET_UNIPHIER_GLUE                      policy<{'armhf': '-'}>
+CONFIG_RING_BUFFER_ALLOW_SWAP                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RIONET                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RIONET_RX_SIZE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RIONET_TX_SIZE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RMNET                                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_ANALOGIX_DP                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_CDN_DP                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_DW_HDMI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_DW_MIPI_DSI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_EFUSE                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_GRF                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_INNO_HDMI                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_IODOMAIN                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_IOMMU                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_LVDS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_MBOX                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_PM_DOMAINS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_RGB                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_RK3066_HDMI                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_SARADC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_THERMAL                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKCHIP_TIMER                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_ROCKER                                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ROCKETPORT                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RPMSG                                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RPMSG_AMGIS_M4_DEVICES                   policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_RPMSG_CHAR                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RPMSG_QCOM_GLINK_NATIVE                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RPMSG_QCOM_GLINK_RPM                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RPMSG_QCOM_GLINK_SMEM                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RPMSG_QCOM_SMD                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RPMSG_VIRTIO                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RSI_91X                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RSI_COEX                                 policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RSI_DEBUGFS                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RSI_SDIO                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RSI_USB                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RST_RCAR                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2400PCI                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT2500PCI                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT2500USB                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT2800PCI                                policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT2800PCI_RT3290                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2800PCI_RT33XX                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2800PCI_RT35XX                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2800PCI_RT53XX                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2800USB                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT2800USB_RT33XX                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800USB_RT3573                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800USB_RT35XX                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800USB_RT53XX                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800USB_RT55XX                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800USB_UNKNOWN                        policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2800_LIB                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT2800_LIB_MMIO                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2X00                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT2X00_DEBUG                             policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT2X00_LIB                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT2X00_LIB_CRYPTO                        policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2X00_LIB_DEBUGFS                       policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT2X00_LIB_FIRMWARE                      policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2X00_LIB_LEDS                          policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_RT2X00_LIB_MMIO                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2X00_LIB_PCI                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RT2X00_LIB_USB                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RT61PCI                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RT73USB                                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RTC_DRV_AM1805                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTC_DRV_ARMADA38X                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_ASPEED                           policy<{'armhf': '-'}>
+CONFIG_RTC_DRV_BD70528                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTC_DRV_BRCMSTB                          policy<{'arm64': '-'}>
+CONFIG_RTC_DRV_CROS_EC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_FSL_FTM_ALARM                    policy<{'arm64': '-'}>
+CONFIG_RTC_DRV_IMXDI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_IMX_SC                           policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_RTC_DRV_ISL12026                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTC_DRV_MESON                            policy<{'armhf': '-'}>
+CONFIG_RTC_DRV_MESON_VRTC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_MT6397                           policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_RTC_DRV_MT7622                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_MV                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_MXC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_MXC_V2                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTC_DRV_OMAP                             policy<{'armhf': '-'}>
+CONFIG_RTC_DRV_PCAP                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RTC_DRV_PCF8523                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_PL030                            policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_RTC_DRV_PL031                            policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_RTC_DRV_PM8XXX                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RTC_DRV_RTD119X                          policy<{'arm64': '-'}>
+CONFIG_RTC_DRV_S3C                              policy<{'armhf': '-'}>
+CONFIG_RTC_DRV_SC27XX                           policy<{'arm64': '-'}>
+CONFIG_RTC_DRV_SH                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTC_DRV_SUN6I                            policy<{'arm64': '-'}>
+CONFIG_RTC_DRV_TEGRA                            policy<{'armhf': '-'}>
+CONFIG_RTC_DRV_WM831X                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RTC_DRV_WM8350                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_RTC_DRV_XGENE                            policy<{'arm64': '-'}>
+CONFIG_RTD119X_WATCHDOG                         policy<{'arm64': '-'}>
+CONFIG_RTL8180                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8188EE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192CE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192DE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192E                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192EE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192SE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8192U                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8723AE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8723BE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTL8723_COMMON                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTL8821AE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTLBTCOEXIST                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTLWIFI_PCI                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_RTS5208                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTW88_8723DE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_RTW88_8822BE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_S2IO                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_S3C2410_WATCHDOG                         policy<{'armhf': '-'}>
+CONFIG_S5P_DEV_MFC                              policy<{'armhf': '-'}>
+CONFIG_SAMPLES                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SAMPLE_CONFIGFS                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_HW_BREAKPOINT                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_KDB                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_KFIFO                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_KOBJECT                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_KPROBES                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_QMI_CLIENT                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_RPMSG_CLIENT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_TRACE_EVENTS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_VFIO_MDEV_MBOCHS                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_VFIO_MDEV_MDPY                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMPLE_VFIO_MDEV_MTTY                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SAMSUNG_MC                               policy<{'armhf': '-'}>
+CONFIG_SATA_ACARD_AHCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_AHCI                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_AHCI_SEATTLE                        policy<{'arm64': '-'}>
+CONFIG_SATA_INIC162X                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_MOBILE_LPM_POLICY                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SATA_MV                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_NV                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_PROMISE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_QSTOR                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_RCAR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SATA_SIL                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_SIL24                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_SIS                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_SVW                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_SX4                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_ULI                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_VIA                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_VITESSE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SATA_ZPODD                               policy<{'arm64': 'n'}>
+CONFIG_SBP_TARGET                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SC27XX_ADC                               policy<{'arm64': '-'}>
+CONFIG_SC27XX_EFUSE                             policy<{'arm64': '-'}>
+CONFIG_SC92031                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCHED_SMT                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCR24X                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SCSI_3W_9XXX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_3W_SAS                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_AACRAID                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_ACARD                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_ADVANSYS                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_AIC79XX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_AIC7XXX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_AIC94XX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_AM53C974                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_ARCMSR                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_BFA_FC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_BNX2X_FCOE                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_BNX2_ISCSI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_CHELSIO_FCOE                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_CXGB3_ISCSI                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_CXGB4_ISCSI                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_DC395x                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_DMX3191D                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_DPT_I2O                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_ESAS2R                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_GDTH                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_HISI_SAS_PCI                        policy<{'arm64': 'n'}>
+CONFIG_SCSI_HPSA                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_HPTIOP                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_INIA100                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_INITIO                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_IPR                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_IPS                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_LOWLEVEL_PCMCIA                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_LPFC                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_LPFC_DEBUG_FS                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_MPT2SAS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_MPT2SAS_MAX_SGE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_MPT3SAS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_MPT3SAS_MAX_SGE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_MVSAS                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_MVSAS_DEBUG                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_MVSAS_TASKLET                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_MVUMI                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_MYRB                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_MYRS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_NSP32                               policy<{'armhf': 'n'}>
+CONFIG_SCSI_PM8001                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_PMCRAID                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_QLA_FC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_QLA_ISCSI                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_QLOGIC_1280                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_SMARTPQI                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_SNIC                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_SNIC_DEBUG_FS                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_STEX                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_SYM53C8XX_2                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_SYM53C8XX_MMIO                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_UFSHCD_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SCSI_UFS_DWC_TC_PCI                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_UFS_HISI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_UFS_MEDIATEK                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_UFS_QCOM                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SCSI_WD719X                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SDM_CAMCC_845                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_DISPCC_845                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_GCC_660                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_GCC_845                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_GPUCC_845                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_LPASSCC_845                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDM_VIDEOCC_845                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SDR_MAX2175                              policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SDR_PLATFORM_DRIVERS                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_SD_ADC_MODULATOR                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SECURITY_INFINIBAND                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE      policy<{'arm64': '0', 'armhf': '0'}>
+CONFIG_SECURITY_SMACK_BRINGUP                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SECURITY_TOMOYO_POLICY_LOADER            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_ACPI_POWER                       policy<{'arm64': 'n'}>
+CONFIG_SENSORS_ARM_SCMI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_AS370                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_GSC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_I5K_AMB                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_INSPUR_IPSPS                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_IR38064                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_ISL68137                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_LOCHNAGAR                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_MLXREG_FAN                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_OCC_P9_SBE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_RASPBERRYPI_HWMON                policy<{'arm64': '-'}>
+CONFIG_SENSORS_SIS5595                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_VEXPRESS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SENSORS_VIA686A                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_VT8231                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_WM831X                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SENSORS_WM8350                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SENSORS_XGENE                            policy<{'arm64': 'n'}>
+CONFIG_SERIAL_8250_BCM2835AUX                   policy<{'arm64': '-'}>
+CONFIG_SERIAL_8250_CS                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIAL_8250_DW                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIAL_8250_EXAR                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_8250_FINTEK                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_8250_MEN_MCB                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SERIAL_8250_MT6577                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_8250_NR_UARTS                     policy<{'arm64': '1', 'armhf': '1'}>
+CONFIG_SERIAL_8250_OMAP                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_8250_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SERIAL_8250_RT288X                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_SERIAL_8250_RUNTIME_UARTS                policy<{'arm64': '0', 'armhf': '0'}>
+CONFIG_SERIAL_8250_UNIPHIER                     policy<{'armhf': '-'}>
+CONFIG_SERIAL_ALTERA_JTAGUART                   policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SERIAL_ALTERA_UART                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SERIAL_ALTERA_UART_BAUDRATE              policy<{'arm64': '-', 'armhf': '115200'}>
+CONFIG_SERIAL_ALTERA_UART_MAXPORTS              policy<{'arm64': '-', 'armhf': '4'}>
+CONFIG_SERIAL_AMBA_PL010                        policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_SERIAL_AMBA_PL011                        policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_SERIAL_AMBA_PL011_CONSOLE                policy<{'arm64': 'y', 'armhf': '-'}>
+CONFIG_SERIAL_ARC                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SERIAL_ARC_NR_PORTS                      policy<{'arm64': '-', 'armhf': '1'}>
+CONFIG_SERIAL_FSL_LINFLEXUART                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SERIAL_IMX                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_IMX_CONSOLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_IPOCTAL                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SERIAL_JSM                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SERIAL_MEN_Z135                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SERIAL_MESON                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_MESON_CONSOLE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_MILBEAUT_USIO                     policy<{'armhf': '-'}>
+CONFIG_SERIAL_MILBEAUT_USIO_PORTS               policy<{'armhf': '-'}>
+CONFIG_SERIAL_MSM                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_MSM_CONSOLE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_MVEBU_CONSOLE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_MVEBU_UART                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_OMAP                              policy<{'armhf': '-'}>
+CONFIG_SERIAL_OMAP_CONSOLE                      policy<{'armhf': '-'}>
+CONFIG_SERIAL_OWL                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_OWL_CONSOLE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_QCOM_GENI                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_RDA                               policy<{'armhf': '-'}>
+CONFIG_SERIAL_RDA_CONSOLE                       policy<{'armhf': '-'}>
+CONFIG_SERIAL_RP2                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SERIAL_RP2_NR_UARTS                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SAMSUNG                           policy<{'armhf': '-'}>
+CONFIG_SERIAL_SAMSUNG_UARTS                     policy<{'armhf': '-'}>
+CONFIG_SERIAL_SAMSUNG_UARTS_4                   policy<{'armhf': '-'}>
+CONFIG_SERIAL_SH_SCI_DMA                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SH_SCI_NR_UARTS                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SERIAL_SIFIVE                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SERIAL_SPRD                              policy<{'arm64': '-'}>
+CONFIG_SERIAL_TEGRA                             policy<{'armhf': '-'}>
+CONFIG_SERIAL_TEGRA_TCU                         policy<{'armhf': '-'}>
+CONFIG_SERIAL_XILINX_PS_UART                    policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SERIO_AMBAKMI                            policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_SERIO_NVEC_PS2                           policy<{'armhf': '-'}>
+CONFIG_SERIO_PCIPS2                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SERIO_SUN4I_PS2                          policy<{'arm64': '-'}>
+CONFIG_SFC                                      policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SFC_FALCON                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SFC_FALCON_MTD                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SFC_MCDI_LOGGING                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SFC_MCDI_MON                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SFC_MTD                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SFC_SRIOV                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SG_SPLIT                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SHUFFLE_PAGE_ALLOCATOR                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SH_ETH                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SH_TIMER_CMT                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SH_TIMER_MTU2                            policy<{'armhf': '-'}>
+CONFIG_SH_TIMER_TMU                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SIMPLE_PM_BUS                            policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_SIOX                                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SIOX_BUS_GPIO                            policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SIS190                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SIS900                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SKFP                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SKGE                                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SKGE_DEBUG                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SKGE_GENESIS                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SKY2                                     policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SKY2_DEBUG                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SLICOSS                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SLIC_DS26522                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SLIMBUS                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SLIM_QCOM_CTRL                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SLIM_QCOM_NGD_CTRL                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SMC91X                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SMSC911X                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SMSC9420                                 policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SMS_SDIO_DRV                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SMS_SIANO_DEBUGFS                        policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_SMS_SIANO_MDTV                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SMS_SIANO_RC                             policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_SMS_USB_DRV                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SM_GCC_8150                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_AD1889                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_ARMAACI                              policy<{'armhf': '-'}>
+CONFIG_SND_ATIIXP                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_ATIIXP_MODEM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_ATMEL_SOC                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_AU8810                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_AU8820                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_AU8830                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_AW2                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_SND_BCM2835_SOC_I2S                      policy<{'arm64': '-'}>
+CONFIG_SND_BEBOB                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_BT87X                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_BT87X_OVERCLOCK                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CA0106                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CMIPCI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_COMPRESS_OFFLOAD                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CS4281                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CS46XX                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CS46XX_NEW_DSP                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_CTXFI                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_DARLA20                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_DARLA24                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_DICE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_DMAENGINE_PCM                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_ECHO3G                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_ENS1370                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_ENS1371                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREFACE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWIRE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWIRE_DIGI00X                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWIRE_LIB                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWIRE_MOTU                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWIRE_TASCAM                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FIREWORKS                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FM801                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_FM801_TEA575X_BOOL                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_GINA20                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_GINA24                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_ALIGNED_MMIO                     policy<{'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_ANALOG                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CA0110                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CA0132                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CA0132_DSP                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CIRRUS                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CMEDIA                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_CONEXANT                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_HDMI                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_REALTEK                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_SI3054                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_SIGMATEL                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CODEC_VIA                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_COMPONENT                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_CORE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_DSP_LOADER                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_GENERIC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_HWDEP                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_INPUT_BEEP                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_INPUT_BEEP_MODE                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_INTEL                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_PATCH_LOADER                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDA_TEGRA                            policy<{'armhf': '-'}>
+CONFIG_SND_HDSP                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_HDSPM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_I2S_HI6210_I2S                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_ICE1724                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_IMX_SOC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_INDIGO                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INDIGODJ                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INDIGODJX                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INDIGOIO                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INDIGOIOX                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INTEL8X0                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INTEL8X0M                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INTEL_DSP_CONFIG                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_INTEL_NHLT                           policy<{'arm64': '-'}>
+CONFIG_SND_ISIGHT                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_KIRKWOOD_SOC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_KORG1212                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_LAYLA20                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_LAYLA24                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_LOLA                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_LX6464ES                             policy<{'arm64': '-'}>
+CONFIG_SND_MESON_AXG_FIFO                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_FRDDR                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_PDM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_SOUND_CARD                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_SPDIFIN                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_SPDIFOUT                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_TDMIN                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_TDMOUT                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_TDM_FORMATTER              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_TDM_INTERFACE              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_AXG_TODDR                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_CODEC_GLUE                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MESON_G12A_TOHDMITX                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MIA                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MIXART                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_MONA                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_NM256                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_OPL3_LIB                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_OPL3_LIB_SEQ                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_OXFW                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_OXYGEN                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_OXYGEN_LIB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_PCI                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_PCM                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_PCMCIA                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_SND_PCM_OSS_PLUGINS                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SND_PCXHR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_PDAUDIOCF                            policy<{'armhf': 'm'}>
+CONFIG_SND_RIPTIDE                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_RME32                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_RME96                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_RME9652                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SAMSUNG_I2S                          policy<{'armhf': '-'}>
+CONFIG_SND_SAMSUNG_PCM                          policy<{'armhf': '-'}>
+CONFIG_SND_SAMSUNG_SPDIF                        policy<{'armhf': '-'}>
+CONFIG_SND_SEQUENCER_OSS                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SEQ_MIDI_EMUL                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ACPI                             policy<{'arm64': '-'}>
+CONFIG_SND_SOC_ADAU1701                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ADAU1761                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_ADAU1761_I2C                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ADAU1761_SPI                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ADAU17X1                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_ADAU_UTILS                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4104                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4118                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4458                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4554                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4613                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK4642                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK5386                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AK5558                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ALC5623                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ALC5632                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_AMD_ACP                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_AMD_CZ_RT5645_MACH               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_APQ8016_SBC                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ARIZONA                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_BD28623                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_COMPRESS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_CPCAP                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_CROS_EC_CODEC                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_CS35L32                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS35L33                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS35L34                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS35L35                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS35L36                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4265                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4270                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4271                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4271_I2C                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4271_SPI                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L42                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L51                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L51_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L52                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L56                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42L73                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42XX8                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS42XX8_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS43130                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4341                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS4349                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CS53L30                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_CX2072X                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_DA7219                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_DAVINCI_MCASP                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_ES7134                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ES7241                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_ES8316                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_EUKREA_TLV320                    policy<{'armhf': 'n'}>
+CONFIG_SND_SOC_FSL_ASOC_CARD                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_FSL_AUD2HTX                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_FSL_SSI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_FSL_UTILS                        policy<{'armhf': '-'}>
+CONFIG_SND_SOC_GTM601                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_I2C_AND_SPI                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMG                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_IMG_I2S_IN                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMG_I2S_OUT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMG_PARALLEL_OUT                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMG_SPDIF_IN                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMG_SPDIF_OUT                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_IMX_AUDMIX                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_AUDMUX                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_CDNHDMI                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_ES8328                       policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_SND_SOC_IMX_MC13783                      policy<{'armhf': 'n'}>
+CONFIG_SND_SOC_IMX_PCM_DMA                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_PCM_FIQ                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_IMX_SGTL5000                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_SPDIF                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_IMX_SSI                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_INNO_RK3036                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_LOCHNAGAR_SC                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_LPASS_APQ8016                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_LPASS_CPU                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_LPASS_IPQ806X                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_LPASS_PLATFORM                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MAX9759                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX98088                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX98090                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MAX98095                         policy<{'armhf': '-'}>
+CONFIG_SND_SOC_MAX98373                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX98504                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX9860                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX9867                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX98927                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MC13783                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_MEDIATEK                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MIKROE_PROTO                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MSM8916_WCD_ANALOG               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MSM8916_WCD_DIGITAL              policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MSM8996                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT2701                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT6351                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT6358                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT6797                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT6797_MT6351                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT8173                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT8183                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT8183_DA7219_MAX98357A          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_NAU8540                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_NAU8810                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_NAU8824                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_NOKIA_RX51                       policy<{'armhf': '-'}>
+CONFIG_SND_SOC_ODROID                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP3_PANDORA                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP3_TWL4030                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP_ABE_TWL6040                 policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP_DMIC                        policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP_MCBSP                       policy<{'armhf': '-'}>
+CONFIG_SND_SOC_OMAP_MCPDM                       policy<{'armhf': '-'}>
+CONFIG_SND_SOC_PCM1681                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM1789                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM1789_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM179X                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM179X_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM179X_SPI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM186X                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM186X_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM186X_SPI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3060                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3060_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3060_SPI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3168A                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3168A_I2C                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM3168A_SPI                     policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM512x                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM512x_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_PCM512x_SPI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_QCOM                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QCOM_COMMON                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_ADM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_AFE                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_AFE_DAI                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_ASM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_ASM_DAI                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_COMMON                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_CORE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_QDSP6_ROUTING                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RCAR                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RK3288_HDMI_ANALOG               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RK3328                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_RK3399_GRU_SOUND                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RL6231                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ROCKCHIP_I2S                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ROCKCHIP_MAX98090                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ROCKCHIP_PDM                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ROCKCHIP_RT5645                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_ROCKCHIP_SPDIF                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RT5514                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RT5514_SPI                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RT5616                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_RT5631                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_RT5640                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_RT5645                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_RT5663                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_RT5677                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_RT5677_SPI                       policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SAMSUNG                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF               policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994              policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SAMSUNG_TM2_WM5110               policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SDM845                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_SGTL5000                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_SH4_FSI                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_SI476X                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_SIGMADSP                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_SIGMADSP_I2C                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_SIGMADSP_REGMAP                  policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_SIRF_AUDIO_CODEC                 policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_SMDK_WM8994_PCM                  policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SNOW                             policy<{'armhf': '-'}>
+CONFIG_SND_SOC_SOF_ACPI                         policy<{'arm64': 'n'}>
+CONFIG_SND_SOC_SOF_NOCODEC                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_SOF_PCI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_SPRD                             policy<{'arm64': '-'}>
+CONFIG_SND_SOC_SPRD_MCDT                        policy<{'arm64': '-'}>
+CONFIG_SND_SOC_SSM2305                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_SSM2602                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_SSM2602_I2C                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_SSM2602_SPI                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_SSM4567                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_STA32X                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_STA350                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_STI_SAS                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_STORM                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_TAS2552                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS2562                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS5086                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS571X                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS5720                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS6424                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TDA7419                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TEGRA                            policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA20_AC97                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA20_DAS                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA20_I2S                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA20_SPDIF                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA30_AHUB                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA30_I2S                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_ALC5632                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_MAX98090                   policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_RT5640                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_RT5677                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_SGTL5000                   policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_TRIMSLICE                  policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_WM8753                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_WM8903                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TEGRA_WM9712                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TFA9879                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TI_EDMA_PCM                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TI_SDMA_PCM                      policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TLV320AIC23                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_I2C                  policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_SPI                  policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC31XX                    policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4                    policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4_I2C                policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4_SPI                policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC3X                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TPA6130A2                        policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TS3A227E                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TSCS42XX                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TSCS454                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_TWL4030                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_TWL6040                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_UDA1334                          policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_UNIPHIER                         policy<{'armhf': '-'}>
+CONFIG_SND_SOC_UNIPHIER_AIO                     policy<{'armhf': '-'}>
+CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC              policy<{'armhf': '-'}>
+CONFIG_SND_SOC_UNIPHIER_LD11                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_UNIPHIER_PXS2                    policy<{'armhf': '-'}>
+CONFIG_SND_SOC_WCD9335                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_SOC_WM5110                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_WM8510                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8523                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8524                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8580                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8711                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8728                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8731                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8737                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8741                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8750                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8753                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8770                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8776                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8782                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8804                           policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8804_I2C                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8804_SPI                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8903                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8904                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8960                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8962                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8974                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8978                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8985                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SOC_WM8994                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_WM9712                           policy<{'armhf': '-'}>
+CONFIG_SND_SOC_WM_ADSP                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_WM_HUBS                          policy<{'armhf': '-'}>
+CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_XILINX_I2S                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_XILINX_SPDIF                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_XTFPGA_I2S                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_ZX_AUD96P22                      policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SND_SUN4I_CODEC                          policy<{'arm64': '-'}>
+CONFIG_SND_SUN4I_I2S                            policy<{'arm64': '-'}>
+CONFIG_SND_SUN4I_SPDIF                          policy<{'arm64': '-'}>
+CONFIG_SND_SUN50I_CODEC_ANALOG                  policy<{'arm64': '-'}>
+CONFIG_SND_SUN8I_ADDA_PR_REGMAP                 policy<{'arm64': '-'}>
+CONFIG_SND_SUN8I_CODEC                          policy<{'arm64': '-'}>
+CONFIG_SND_SUN8I_CODEC_ANALOG                   policy<{'arm64': '-'}>
+CONFIG_SND_TIMER                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_VIA82XX                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_VIA82XX_MODEM                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_VIRTUOSO                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_VX222                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SND_VXPOCKET                             policy<{'armhf': 'm'}>
+CONFIG_SND_VX_LIB                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SND_XEN_FRONTEND                         policy<{'arm64': '-'}>
+CONFIG_SND_YMFPCI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SNI_AVE                                  policy<{'armhf': '-'}>
+CONFIG_SNI_NETSEC                               policy<{'arm64': '-'}>
+CONFIG_SOC_AM33XX                               policy<{'armhf': 'n'}>
+CONFIG_SOC_ASPEED                               policy<{'armhf': '-'}>
+CONFIG_SOC_BRCMSTB                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SOC_DRA7XX                               policy<{'armhf': 'n'}>
+CONFIG_SOC_EXYNOS5250                           policy<{'armhf': '-'}>
+CONFIG_SOC_EXYNOS5260                           policy<{'armhf': '-'}>
+CONFIG_SOC_EXYNOS5410                           policy<{'armhf': '-'}>
+CONFIG_SOC_EXYNOS5420                           policy<{'armhf': '-'}>
+CONFIG_SOC_EXYNOS5800                           policy<{'armhf': '-'}>
+CONFIG_SOC_HAS_OMAP2_SDRC                       policy<{'armhf': '-'}>
+CONFIG_SOC_HAS_REALTIME_COUNTER                 policy<{'armhf': '-'}>
+CONFIG_SOC_IMX5                                 policy<{'armhf': '-'}>
+CONFIG_SOC_IMX50                                policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX51                                policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX53                                policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX6                                 policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX6Q                                policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX6SL                               policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX6SLL                              policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX6SX                               policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX6UL                               policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX7D                                policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX7D_CA7                            policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX7ULP                              policy<{'armhf': 'n'}>
+CONFIG_SOC_IMX8M                                policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_SOC_LS1021A                              policy<{'armhf': 'n'}>
+CONFIG_SOC_OMAP3430                             policy<{'armhf': '-'}>
+CONFIG_SOC_RENESAS                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SOC_SAMSUNG                              policy<{'armhf': '-'}>
+CONFIG_SOC_TEGRA_FLOWCTRL                       policy<{'armhf': '-'}>
+CONFIG_SOC_TEGRA_FUSE                           policy<{'armhf': '-'}>
+CONFIG_SOC_TEGRA_PMC                            policy<{'armhf': '-'}>
+CONFIG_SOC_TEGRA_POWERGATE_BPMP                 policy<{'armhf': '-'}>
+CONFIG_SOC_TI                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SOC_TI81XX                               policy<{'armhf': '-'}>
+CONFIG_SOC_VF610                                policy<{'armhf': 'n'}>
+CONFIG_SPI_ALTERA                               policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_ARMADA_3700                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_ASPEED_SMC                           policy<{'armhf': '-'}>
+CONFIG_SPI_AXI_SPI_ENGINE                       policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_BCM2835                              policy<{'arm64': '-'}>
+CONFIG_SPI_BCM2835AUX                           policy<{'arm64': '-'}>
+CONFIG_SPI_BCM_QSPI                             policy<{'arm64': '-'}>
+CONFIG_SPI_BITBANG                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_BUTTERFLY                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_CADENCE                              policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_DESIGNWARE                           policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_DW_MID_DMA                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_DW_MMIO                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SPI_DW_PCI                               policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_SPI_FSL_DSPI                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_FSL_LPSPI                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_FSL_QUADSPI                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_HISI_SFC                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_HISI_SFC_V3XX                        policy<{'arm64': 'n'}>
+CONFIG_SPI_IMX                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_MESON_SPICC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_MESON_SPIFC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_MT65XX                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_NPCM_FIU                             policy<{'armhf': '-'}>
+CONFIG_SPI_NPCM_PSPI                            policy<{'armhf': '-'}>
+CONFIG_SPI_NXP_FLEXSPI                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_OC_TINY                              policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_OMAP24XX                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_ORION                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_PL022                                policy<{'arm64': 'm', 'armhf': '-'}>
+CONFIG_SPI_PXA2XX                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SPI_PXA2XX_PCI                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_QCOM_GENI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_QCOM_QSPI                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_QUP                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_ROCKCHIP                             policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_RSPI                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_S3C64XX                              policy<{'armhf': '-'}>
+CONFIG_SPI_SH_HSPI                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_SH_MSIOF                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_SIFIVE                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SPI_SLAVE_MT27XX                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPI_SPRD                                 policy<{'arm64': '-'}>
+CONFIG_SPI_SPRD_ADI                             policy<{'arm64': '-'}>
+CONFIG_SPI_SUN4I                                policy<{'arm64': '-'}>
+CONFIG_SPI_SUN6I                                policy<{'arm64': '-'}>
+CONFIG_SPI_SYNQUACER                            policy<{'arm64': '-'}>
+CONFIG_SPI_TEGRA114                             policy<{'armhf': '-'}>
+CONFIG_SPI_TEGRA20_SFLASH                       policy<{'armhf': '-'}>
+CONFIG_SPI_TEGRA20_SLINK                        policy<{'armhf': '-'}>
+CONFIG_SPI_THUNDERX                             policy<{'arm64': 'n'}>
+CONFIG_SPI_TI_QSPI                              policy<{'armhf': '-'}>
+CONFIG_SPI_TLE62X0                              policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPI_UNIPHIER                             policy<{'armhf': '-'}>
+CONFIG_SPI_XLP                                  policy<{'arm64': '-'}>
+CONFIG_SPI_ZYNQMP_GQSPI                         policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_SPMI_MSM_PMIC_ARB                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPMI_PMIC_CLKDIV                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SPRD_COMMON_CLK                          policy<{'arm64': '-'}>
+CONFIG_SPRD_DMA                                 policy<{'arm64': '-'}>
+CONFIG_SPRD_SC9860_CLK                          policy<{'arm64': '-'}>
+CONFIG_SPRD_TIMER                               policy<{'arm64': '-'}>
+CONFIG_SPRD_WATCHDOG                            policy<{'arm64': '-'}>
+CONFIG_SSB_PCMCIAHOST                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SSB_PCMCIAHOST_POSSIBLE                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SSI_PROTOCOL                             policy<{'armhf': '-'}>
+CONFIG_STAGING_APEX_DRIVER                      policy<{'arm64': '-'}>
+CONFIG_STAGING_GASKET_FRAMEWORK                 policy<{'arm64': 'n'}>
+CONFIG_STATIC_KEYS_SELFTEST                     policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_STMMAC_PCI                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_STMP_DEVICE                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_STPMIC1_WATCHDOG                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_STUB_CLK_HI3660                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_STUB_CLK_HI6220                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SUN4I_EMAC                               policy<{'arm64': '-'}>
+CONFIG_SUN4I_GPADC                              policy<{'arm64': '-'}>
+CONFIG_SUN50I_A64_CCU                           policy<{'arm64': '-'}>
+CONFIG_SUN50I_DE2_BUS                           policy<{'arm64': '-'}>
+CONFIG_SUN50I_ERRATUM_UNKNOWN1                  policy<{'arm64': '-'}>
+CONFIG_SUN50I_H6_CCU                            policy<{'arm64': '-'}>
+CONFIG_SUN50I_H6_R_CCU                          policy<{'arm64': '-'}>
+CONFIG_SUN8I_A83T_CCU                           policy<{'arm64': '-'}>
+CONFIG_SUN8I_DE2_CCU                            policy<{'arm64': '-'}>
+CONFIG_SUN8I_H3_CCU                             policy<{'arm64': '-'}>
+CONFIG_SUN8I_R_CCU                              policy<{'arm64': '-'}>
+CONFIG_SUNDANCE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SUNDANCE_MMIO                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SUNGEM                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SUNGEM_PHY                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SUNXI_CCU                                policy<{'arm64': '-'}>
+CONFIG_SUNXI_RSB                                policy<{'arm64': '-'}>
+CONFIG_SUNXI_SRAM                               policy<{'arm64': '-'}>
+CONFIG_SUNXI_WATCHDOG                           policy<{'arm64': '-'}>
+CONFIG_SWIOTLB_XEN                              policy<{'arm64': '-'}>
+CONFIG_SXGBE_ETH                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_SYNCLINKMP                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SYNCLINK_CS                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SYNCLINK_GT                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SYSCTL_SYSCALL                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SYSC_R8A7743                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7745                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A77470                            policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A774A1                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A774C0                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A7779                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7790                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7791                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7792                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7794                             policy<{'armhf': '-'}>
+CONFIG_SYSC_R8A7795                             policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A7796                             policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A77965                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A77970                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A77980                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A77990                            policy<{'arm64': '-'}>
+CONFIG_SYSC_R8A77995                            policy<{'arm64': '-'}>
+CONFIG_SYSC_RCAR                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SYSC_RMOBILE                             policy<{'armhf': '-'}>
+CONFIG_SYS_HYPERVISOR                           policy<{'arm64': '-'}>
+CONFIG_SYS_SUPPORTS_EM_STI                      policy<{'armhf': '-'}>
+CONFIG_SYS_SUPPORTS_SH_CMT                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_SYS_SUPPORTS_SH_MTU2                     policy<{'armhf': '-'}>
+CONFIG_SYS_SUPPORTS_SH_TMU                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TCG_ATMEL                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TCG_FTPM_TEE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TCG_INFINEON                             policy<{'arm64': 'n'}>
+CONFIG_TCG_XEN                                  policy<{'arm64': '-'}>
+CONFIG_TCM_QLA2XXX                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TCM_QLA2XXX_DEBUG                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TEE                                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_TEGRA124_EMC                             policy<{'armhf': '-'}>
+CONFIG_TEGRA20_APB_DMA                          policy<{'armhf': '-'}>
+CONFIG_TEGRA20_EMC                              policy<{'armhf': '-'}>
+CONFIG_TEGRA_AHB                                policy<{'armhf': '-'}>
+CONFIG_TEGRA_BPMP                               policy<{'armhf': '-'}>
+CONFIG_TEGRA_BPMP_THERMAL                       policy<{'armhf': '-'}>
+CONFIG_TEGRA_CLK_DFLL                           policy<{'armhf': '-'}>
+CONFIG_TEGRA_CLK_EMC                            policy<{'armhf': '-'}>
+CONFIG_TEGRA_GMI                                policy<{'armhf': '-'}>
+CONFIG_TEGRA_HOST1X                             policy<{'armhf': '-'}>
+CONFIG_TEGRA_HOST1X_FIREWALL                    policy<{'armhf': '-'}>
+CONFIG_TEGRA_HSP_MBOX                           policy<{'armhf': '-'}>
+CONFIG_TEGRA_IOMMU_GART                         policy<{'armhf': '-'}>
+CONFIG_TEGRA_IOMMU_SMMU                         policy<{'armhf': '-'}>
+CONFIG_TEGRA_IVC                                policy<{'armhf': '-'}>
+CONFIG_TEGRA_MC                                 policy<{'armhf': '-'}>
+CONFIG_TEGRA_SOCTHERM                           policy<{'armhf': '-'}>
+CONFIG_TEGRA_TIMER                              policy<{'armhf': '-'}>
+CONFIG_TEGRA_VDE                                policy<{'armhf': '-'}>
+CONFIG_TEGRA_WATCHDOG                           policy<{'armhf': '-'}>
+CONFIG_TEHUTI                                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TEST_FIRMWARE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_KMOD                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_LKM                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_OBJAGG                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TEST_PARMAN                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TEST_STATIC_KEYS                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_SYSCTL                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_UDELAY                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEST_USER_COPY                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_THERMAL_MMIO                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_THUNDERX2_PMU                            policy<{'arm64': '-'}>
+CONFIG_THUNDER_NIC_BGX                          policy<{'arm64': '-'}>
+CONFIG_THUNDER_NIC_PF                           policy<{'arm64': '-'}>
+CONFIG_THUNDER_NIC_RGX                          policy<{'arm64': '-'}>
+CONFIG_THUNDER_NIC_VF                           policy<{'arm64': '-'}>
+CONFIG_TIGON3                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TIGON3_HWMON                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TIPC_MEDIA_IB                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TI_AM335X_ADC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TI_CPPI41                                policy<{'armhf': '-'}>
+CONFIG_TI_CPSW                                  policy<{'armhf': '-'}>
+CONFIG_TI_CPSW_PHY_SEL                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TI_CPTS                                  policy<{'armhf': '-'}>
+CONFIG_TI_CPTS_MOD                              policy<{'armhf': '-'}>
+CONFIG_TI_DAVINCI_EMAC                          policy<{'armhf': '-'}>
+CONFIG_TI_DAVINCI_MDIO                          policy<{'armhf': '-'}>
+CONFIG_TI_DMA_CROSSBAR                          policy<{'armhf': '-'}>
+CONFIG_TI_EDMA                                  policy<{'armhf': '-'}>
+CONFIG_TI_EMIF                                  policy<{'armhf': '-'}>
+CONFIG_TI_EMIF_SRAM                             policy<{'armhf': '-'}>
+CONFIG_TI_MESSAGE_MANAGER                       policy<{'arm64': '-'}>
+CONFIG_TI_PIPE3                                 policy<{'armhf': '-'}>
+CONFIG_TI_SCI_CLK                               policy<{'arm64': '-'}>
+CONFIG_TI_SCI_CLK_PROBE_FROM_FW                 policy<{'arm64': '-'}>
+CONFIG_TI_SCI_INTA_IRQCHIP                      policy<{'arm64': '-'}>
+CONFIG_TI_SCI_INTA_MSI_DOMAIN                   policy<{'arm64': '-'}>
+CONFIG_TI_SCI_INTR_IRQCHIP                      policy<{'arm64': '-'}>
+CONFIG_TI_SCI_PM_DOMAINS                        policy<{'arm64': '-'}>
+CONFIG_TI_SCI_PROTOCOL                          policy<{'arm64': '-'}>
+CONFIG_TI_SOC_THERMAL                           policy<{'armhf': '-'}>
+CONFIG_TI_SYSC                                  policy<{'armhf': '-'}>
+CONFIG_TI_THERMAL                               policy<{'armhf': '-'}>
+CONFIG_TLAN                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TMD_HERMES                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8505              policy<{'arm64': 'n'}>
+CONFIG_TOUCHSCREEN_FTS                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TOUCHSCREEN_IPROC                        policy<{'arm64': '-'}>
+CONFIG_TOUCHSCREEN_PCAP                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW               policy<{'arm64': '-'}>
+CONFIG_TOUCHSCREEN_SUN4I                        policy<{'arm64': '-'}>
+CONFIG_TOUCHSCREEN_TI_AM335X_TSC                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TOUCHSCREEN_TS4800                       policy<{'armhf': '-'}>
+CONFIG_TOUCHSCREEN_WM831X                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_TPS68470_PMIC_OPREGION                   policy<{'arm64': '-'}>
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_TRANSPARENT_HUGEPAGE                     policy<{'arm64': 'n'}>
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS              policy<{'arm64': '-'}>
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE             policy<{'arm64': '-'}>
+CONFIG_TRANSPARENT_HUGE_PAGECACHE               policy<{'arm64': '-'}>
+CONFIG_TREE_RCU                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TS4800_IRQ                               policy<{'armhf': '-'}>
+CONFIG_TS4800_WATCHDOG                          policy<{'armhf': '-'}>
+CONFIG_TTPCI_EEPROM                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_TULIP                                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TULIP_MMIO                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TULIP_MWI                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TULIP_NAPI                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TURRIS_MOX_RWTM                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TWL4030_CORE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TWL4030_MADC                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TWL4030_POWER                            policy<{'armhf': '-'}>
+CONFIG_TWL4030_USB                              policy<{'armhf': '-'}>
+CONFIG_TWL4030_WATCHDOG                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TWL6030_GPADC                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_TWL6030_USB                              policy<{'armhf': '-'}>
+CONFIG_TWL6040_CORE                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TYPEC_RT1711H                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_TYPHOON                                  policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_UACCESS_WITH_MEMCPY                      policy<{'armhf': 'y'}>
+CONFIG_UCLAMP_TASK_GROUP                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UCSI_ACPI                                policy<{'arm64': 'n'}>
+CONFIG_UEFI_CPER                                policy<{'arm64': '-'}>
+CONFIG_UEFI_CPER_ARM                            policy<{'arm64': '-'}>
+CONFIG_UIO_AEC                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UIO_CIF                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UIO_MF624                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UIO_NETX                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UIO_PCI_GENERIC                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_UIO_SERCOS3                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ULI526X                                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_UNINLINE_SPIN_UNLOCK                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_UNIPHIER_EFUSE                           policy<{'armhf': '-'}>
+CONFIG_UNIPHIER_MDMAC                           policy<{'armhf': '-'}>
+CONFIG_UNIPHIER_SYSTEM_BUS                      policy<{'armhf': '-'}>
+CONFIG_UNIPHIER_THERMAL                         policy<{'armhf': '-'}>
+CONFIG_UNIPHIER_WATCHDOG                        policy<{'armhf': '-'}>
+CONFIG_USB_AIRSPY                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_AMD5536UDC                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_ASPEED_VHUB                          policy<{'armhf': '-'}>
+CONFIG_USB_BDC_UDC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_CDNS3                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_CDNS3_GADGET                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CDNS3_HOST                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CDNS3_PCI_WRAP                       policy<{'arm64': '-'}>
+CONFIG_USB_CONFIGFS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_CONFIGFS_ACM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_ECM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_ECM_SUBSET                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_EEM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_FS                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_HID                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_LB_SS                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_MIDI                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_PRINTER                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_TCM                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_UAC1                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_UAC1_LEGACY               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_UAC2                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_F_UVC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_MASS_STORAGE                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_NCM                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_OBEX                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_PHONET                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_RNDIS                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONFIGFS_SERIAL                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_CONN_GPIO                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_DSBR                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_DWC2                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_DWC2_DUAL_ROLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_DWC2_HOST                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_DWC2_PCI                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_DWC2_PERIPHERAL                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_DWC3_DUAL_ROLE                       policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_USB_DWC3_EXYNOS                          policy<{'armhf': '-'}>
+CONFIG_USB_DWC3_HOST                            policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_USB_DWC3_IMX8MP                          policy<{'arm64': 'm'}>
+CONFIG_USB_DWC3_KEYSTONE                        policy<{'arm64': '-'}>
+CONFIG_USB_DWC3_MESON_G12A                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_DWC3_OMAP                            policy<{'armhf': '-'}>
+CONFIG_USB_DWC3_QCOM                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_EG20T                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_EHCI_EXYNOS                          policy<{'armhf': '-'}>
+CONFIG_USB_EHCI_HCD_NPCM7XX                     policy<{'armhf': '-'}>
+CONFIG_USB_EHCI_HCD_OMAP                        policy<{'armhf': '-'}>
+CONFIG_USB_EHCI_HCD_ORION                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_EHCI_MXC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_EHCI_TEGRA                           policy<{'armhf': '-'}>
+CONFIG_USB_EMXX                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_ETH_EEM                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_FOTG210_UDC                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_FSL_USB2                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_FUNCTIONFS                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_FUNCTIONFS_ETH                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_FUNCTIONFS_GENERIC                   policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_FUNCTIONFS_RNDIS                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_FUSB300                              policy<{'armhf': 'n'}>
+CONFIG_USB_F_EEM                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_F_FS                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_F_UAC1                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_F_UAC1_LEGACY                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_GADGET                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_GADGET_XILINX                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_GOKU                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_G_MULTI                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_G_MULTI_CDC                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_G_MULTI_RNDIS                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_HACKRF                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_IMX21_HCD                            policy<{'armhf': 'n'}>
+CONFIG_USB_ISP1760_DUAL_ROLE                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_ISP1760_HOST_ROLE                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_ISP1761_UDC                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_KEENE                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_LAN78XX                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_MA901                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_MR800                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_MSI2500                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_MTU3                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_MTU3_DEBUG                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_MTU3_DUAL_ROLE                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_MTU3_GADGET                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_MTU3_HOST                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_MUSB_AM335X_CHILD                    policy<{'armhf': '-'}>
+CONFIG_USB_MUSB_AM35X                           policy<{'armhf': '-'}>
+CONFIG_USB_MUSB_DSPS                            policy<{'armhf': '-'}>
+CONFIG_USB_MUSB_DUAL_ROLE                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_MUSB_HOST                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_MUSB_OMAP2PLUS                       policy<{'armhf': '-'}>
+CONFIG_USB_MUSB_SUNXI                           policy<{'arm64': '-'}>
+CONFIG_USB_MUSB_TUSB6010                        policy<{'armhf': '-'}>
+CONFIG_USB_MXS_PHY                              policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_USB_NET2272_DMA                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_NET2280                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_NET_DRIVERS                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_NET_SMSC95XX                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_OHCI_EXYNOS                          policy<{'armhf': '-'}>
+CONFIG_USB_OHCI_HCD_OMAP3                       policy<{'armhf': '-'}>
+CONFIG_USB_OHCI_HCD_PLATFORM                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_RAREMONO                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_RENESAS_USB3                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_RENESAS_USBHS                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_RENESAS_USBHS_HCD                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_RENESAS_USBHS_UDC                    policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_ROLE_SWITCH                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_SI470X                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_SI4713                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_USB_SL811_CS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_SNP_CORE                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_SNP_UDC_PLAT                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_TEGRA_PHY                            policy<{'armhf': '-'}>
+CONFIG_USB_UHCI_ASPEED                          policy<{'armhf': '-'}>
+CONFIG_USB_UHCI_PLATFORM                        policy<{'armhf': '-'}>
+CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC              policy<{'armhf': '-'}>
+CONFIG_USB_USBNET                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_WHCI_HCD                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_XHCI_HISTB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_XHCI_MTK                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_XHCI_MVEBU                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_XHCI_RCAR                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_USB_XHCI_TEGRA                           policy<{'armhf': '-'}>
+CONFIG_USB_ZD1201                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_UWB_WHCI                                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_U_SERIAL_CONSOLE                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VESTA_OVERLAY_MGR                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VEXPRESS_CONFIG                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VEXPRESS_SYSCFG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VFIO_AMBA                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VFIO_MDEV_DEVICE                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VFIO_NOIOMMU                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VFIO_PLATFORM                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VFIO_PLATFORM_AMDXGBE_RESET              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VFIO_PLATFORM_BCMFLEXRM_RESET            policy<{'arm64': '-'}>
+CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VF_USE_ARM_GLOBAL_TIMER                  policy<{'armhf': '-'}>
+CONFIG_VF_USE_PIT_TIMER                         policy<{'armhf': '-'}>
+CONFIG_VGASTATE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VGA_ARB                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VGA_ARB_MAX_GPUS                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIA_RHINE                                policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIA_RHINE_MMIO                           policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIA_VELOCITY                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEOBUF2_DVB                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEOBUF_DMA_CONTIG                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEOBUF_DMA_SG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_AD5820                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_AD9389B                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADP1653                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7170                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7175                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7180                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7183                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7343                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7393                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV748X                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7604                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7604_CEC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_ADV7842                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ADV7842_CEC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_AK7375                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_AK881X                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ALLEGRO_DVT                        policy<{'arm64': '-'}>
+CONFIG_VIDEO_APTINA_PLL                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_ASPEED                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_AU0828                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_AU0828_RC                          policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIDEO_AU0828_V4L2                        policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIDEO_BCM2835                            policy<{'arm64': '-'}>
+CONFIG_VIDEO_BT819                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_BT848                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_BT856                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_BT866                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_CAFE_CCIC                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_CODA                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_CROS_EC_CEC                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX18                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX18_ALSA                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX231XX                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_CX231XX_ALSA                       policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_CX231XX_DVB                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_CX231XX_RC                         policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIDEO_CX2341X                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_CX23885                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX25821                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX25821_ALSA                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_ALSA                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_BLACKBIRD                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_DVB                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_ENABLE_VP3054                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_MPEG                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_CX88_VP3054                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_DT3155                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_DW9714                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_DW9807_VCM                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_EM28XX_DVB                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_ET8EK8                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_FB_IVTV                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_GO7007                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_GO7007_LOADER                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_GO7007_USB                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_GS1662                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_HDPVR                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_HEXIUM_GEMINI                      policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_HEXIUM_ORION                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_I2C                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX214                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX258                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX274                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX319                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX355                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX7_CSI                           policy<{'armhf': '-'}>
+CONFIG_VIDEO_IMX_CAPTURE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_IMX_CSI                            policy<{'armhf': '-'}>
+CONFIG_VIDEO_IMX_MEDIA                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_IMX_PXP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_IMX_VDOA                           policy<{'armhf': 'm'}>
+CONFIG_VIDEO_IVTV                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_IVTV_ALSA                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_KS0127                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_LM3560                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_LM3646                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_M52790                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_M5MOLS                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MEDIATEK_VPU                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_MESON_AO_CEC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_MESON_G12A_AO_CEC                  policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_MESON_VDEC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_ML86V7667                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9M001                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9M032                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9M111                            policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_VIDEO_MT9P031                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9T001                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9T112                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9V032                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MT9V111                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_MX8_CAPTURE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MXB                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_MXC_CAPTURE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MXC_CSI_CAMERA                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MXC_PXP_V4L2                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_NOON010PC30                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OMAP2_VOUT                         policy<{'armhf': '-'}>
+CONFIG_VIDEO_OMAP2_VOUT_VRFB                    policy<{'armhf': '-'}>
+CONFIG_VIDEO_OMAP3                              policy<{'armhf': '-'}>
+CONFIG_VIDEO_OMAP3_DEBUG                        policy<{'armhf': '-'}>
+CONFIG_VIDEO_OMAP4                              policy<{'armhf': '-'}>
+CONFIG_VIDEO_OV13858                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV2659                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV2680                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV2685                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5640                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5645                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5647                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5670                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5675                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV5695                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV6650                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV7251                             policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_VIDEO_OV7640                             policy<{'arm64': 'n', 'armhf': 'm'}>
+CONFIG_VIDEO_OV7670                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV772X                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV7740                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV8856                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV9640                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_OV9650                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_PCI_SKELETON                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_PVRUSB2                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_PVRUSB2_DEBUGIFC                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_VIDEO_PVRUSB2_DVB                        policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIDEO_PVRUSB2_SYSFS                      policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_VIDEO_QCOM_CAMSS                         policy<{'arm64': '-'}>
+CONFIG_VIDEO_QCOM_VENUS                         policy<{'arm64': '-'}>
+CONFIG_VIDEO_RCAR_CSI2                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RCAR_DRIF                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RCAR_VIN                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RENESAS_CEU                        policy<{'armhf': '-'}>
+CONFIG_VIDEO_RENESAS_FCP                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RENESAS_FDP1                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RENESAS_JPU                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RENESAS_VSP1                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_RJ54N1                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_ROCKCHIP_RGA                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_S5C73M3                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_S5K4ECGX                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_S5K5BAF                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_S5K6A3                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_S5K6AA                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA6588                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA6752HS                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA7110                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA7127                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA7134                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7134_ALSA                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7134_DVB                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7134_GO7007                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7134_RC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7146                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7146_VV                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA7164                            policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SAA717X                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAA7185                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS                 policy<{'armhf': '-'}>
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC                 policy<{'armhf': '-'}>
+CONFIG_VIDEO_SAMSUNG_S5P_CEC                    policy<{'armhf': '-'}>
+CONFIG_VIDEO_SAMSUNG_S5P_G2D                    policy<{'armhf': '-'}>
+CONFIG_VIDEO_SAMSUNG_S5P_JPEG                   policy<{'armhf': '-'}>
+CONFIG_VIDEO_SAMSUNG_S5P_MFC                    policy<{'armhf': '-'}>
+CONFIG_VIDEO_SMIAPP                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SMIAPP_PLL                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SOLO6X10                           policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_SR030PC30                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_STK1160                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_STK1160_COMMON                     policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_ST_MIPID02                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_SUN4I_CSI                          policy<{'arm64': '-'}>
+CONFIG_VIDEO_SUN6I_CSI                          policy<{'arm64': '-'}>
+CONFIG_VIDEO_SUNXI                              policy<{'arm64': '-'}>
+CONFIG_VIDEO_TC358743                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_TC358743_CEC                       policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_TEGRA_HDMI_CEC                     policy<{'armhf': '-'}>
+CONFIG_VIDEO_THS7303                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_THS8200                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_TI_CAL                             policy<{'armhf': '-'}>
+CONFIG_VIDEO_TI_CSC                             policy<{'armhf': '-'}>
+CONFIG_VIDEO_TI_SC                              policy<{'armhf': '-'}>
+CONFIG_VIDEO_TI_VPDMA                           policy<{'armhf': '-'}>
+CONFIG_VIDEO_TI_VPE                             policy<{'armhf': '-'}>
+CONFIG_VIDEO_TI_VPE_DEBUG                       policy<{'armhf': '-'}>
+CONFIG_VIDEO_TM6000                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_TM6000_ALSA                        policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_TM6000_DVB                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_TVP514X                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_TVP7002                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_TW5864                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_TW68                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_TW686X                             policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_TW9910                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_UPD64031A                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_UPD64083                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_USBVISION                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_VIDEO_VPX3220                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_VS6624                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_XILINX                             policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIDEO_XILINX_TPG                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIDEO_XILINX_VTC                         policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIRTIO_BALLOON                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIRTIO_BLK_SCSI                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIRTIO_CONSOLE                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIRTIO_FS                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIRTIO_IOMMU                             policy<{'arm64': 'n'}>
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIRTIO_PCI                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VIRTIO_PCI_LEGACY                        policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VIRTIO_PMEM                              policy<{'arm64': 'n'}>
+CONFIG_VME_BUS                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VME_FAKE                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VME_TSI148                               policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VME_USER                                 policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VMIVME_7805                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VMSPLIT_3G_OPT                           policy<{'armhf': 'n'}>
+CONFIG_VMXNET3                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VORTEX                                   policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_VT6655                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_VXGE                                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_VXGE_DEBUG_TRACE_ALL                     policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_W1_MASTER_MATROX                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_W1_MASTER_MXC                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_W1_MASTER_SGI                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_W1_SLAVE_DS250X                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_WANXL                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_WDAT_WDT                                 policy<{'arm64': 'n'}>
+CONFIG_WDTPCI                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_WIL6210                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_WIL6210_DEBUGFS                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_WIL6210_ISR_COR                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_WIL6210_TRACING                          policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_WILINK_PLATFORM_DATA                     policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_WINBOND_840                              policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_WIZNET_BUS_ANY                           policy<{'arm64': '-', 'armhf': 'y'}>
+CONFIG_WIZNET_BUS_DIRECT                        policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_WIZNET_BUS_INDIRECT                      policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_WIZNET_W5100                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WIZNET_W5100_SPI                         policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WIZNET_W5300                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WKUP_M3_IPC                              policy<{'armhf': '-'}>
+CONFIG_WKUP_M3_RPROC                            policy<{'armhf': '-'}>
+CONFIG_WL1251                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WL1251_SDIO                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WL1251_SPI                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WL12XX                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WL18XX                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WLAN_VENDOR_ADMTEK                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_ATMEL                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_CISCO                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_INTEL                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_INTERSIL                     policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_MARVELL                      policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_MEDIATEK                     policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_QUANTENNA                    policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_RALINK                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_RSI                          policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_TI                           policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLAN_VENDOR_ZYDAS                        policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_WLCORE                                   policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WLCORE_SDIO                              policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WLCORE_SPI                               policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WM831X_BACKUP                            policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WM831X_POWER                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WM831X_WATCHDOG                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WM8350_POWER                             policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_WM8350_WATCHDOG                          policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_XARRAY_MULTI                             policy<{'arm64': '-'}>
+CONFIG_XEN                                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_XENFS                                    policy<{'arm64': '-'}>
+CONFIG_XEN_AUTO_XLATE                           policy<{'arm64': '-'}>
+CONFIG_XEN_BACKEND                              policy<{'arm64': '-'}>
+CONFIG_XEN_BALLOON                              policy<{'arm64': '-'}>
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG               policy<{'arm64': '-'}>
+CONFIG_XEN_BLKDEV_BACKEND                       policy<{'arm64': '-'}>
+CONFIG_XEN_COMPAT_XENFS                         policy<{'arm64': '-'}>
+CONFIG_XEN_DEV_EVTCHN                           policy<{'arm64': '-'}>
+CONFIG_XEN_DOM0                                 policy<{'arm64': '-'}>
+CONFIG_XEN_EFI                                  policy<{'arm64': '-'}>
+CONFIG_XEN_FBDEV_FRONTEND                       policy<{'arm64': '-'}>
+CONFIG_XEN_FRONT_PGDIR_SHBUF                    policy<{'arm64': '-'}>
+CONFIG_XEN_GNTDEV                               policy<{'arm64': '-'}>
+CONFIG_XEN_GNTDEV_DMABUF                        policy<{'arm64': '-'}>
+CONFIG_XEN_GRANT_DEV_ALLOC                      policy<{'arm64': '-'}>
+CONFIG_XEN_GRANT_DMA_ALLOC                      policy<{'arm64': '-'}>
+CONFIG_XEN_NETDEV_BACKEND                       policy<{'arm64': '-'}>
+CONFIG_XEN_PRIVCMD                              policy<{'arm64': '-'}>
+CONFIG_XEN_PVCALLS_BACKEND                      policy<{'arm64': '-'}>
+CONFIG_XEN_PVCALLS_FRONTEND                     policy<{'arm64': '-'}>
+CONFIG_XEN_SCRUB_PAGES_DEFAULT                  policy<{'arm64': '-'}>
+CONFIG_XEN_SCSI_BACKEND                         policy<{'arm64': '-'}>
+CONFIG_XEN_SCSI_FRONTEND                        policy<{'arm64': '-'}>
+CONFIG_XEN_SYS_HYPERVISOR                       policy<{'arm64': '-'}>
+CONFIG_XEN_WDT                                  policy<{'arm64': '-'}>
+CONFIG_XEN_XENBUS_FRONTEND                      policy<{'arm64': '-'}>
+CONFIG_XGENE_DMA                                policy<{'arm64': '-'}>
+CONFIG_XGENE_PMU                                policy<{'arm64': '-'}>
+CONFIG_XGENE_SLIMPRO_MBOX                       policy<{'arm64': '-'}>
+CONFIG_XILINX_AXI_EMAC                          policy<{'armhf': '-'}>
+CONFIG_XILINX_DMA                               policy<{'arm64': 'n'}>
+CONFIG_XILINX_PR_DECOUPLER                      policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_XILINX_VCU                               policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_XILINX_XADC                              policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_XILINX_ZYNQMP_DMA                        policy<{'arm64': 'n'}>
+CONFIG_XILLYBUS_PCIE                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_YELLOWFIN                                policy<{'arm64': '-', 'armhf': '-'}>
+CONFIG_YENTA                                    policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_YENTA_ENE_TUNE                           policy<{'arm64': '-'}>
+CONFIG_YENTA_O2                                 policy<{'arm64': '-'}>
+CONFIG_YENTA_RICOH                              policy<{'arm64': '-'}>
+CONFIG_YENTA_TI                                 policy<{'arm64': '-'}>
+CONFIG_YENTA_TOSHIBA                            policy<{'arm64': '-'}>
+CONFIG_ZD1211RW                                 policy<{'arm64': '-', 'armhf': 'm'}>
+CONFIG_ZD1211RW_DEBUG                           policy<{'arm64': '-', 'armhf': 'n'}>
+CONFIG_ZX_TDM                                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ZYNQMP_FIRMWARE                          policy<{'arm64': '-'}>
+CONFIG_ZYNQMP_FIRMWARE_DEBUG                    policy<{'arm64': '-'}>
+CONFIG_ZYNQMP_IPI_MBOX                          policy<{'arm64': '-'}>
+CONFIG_ZYNQMP_PM_DOMAINS                        policy<{'arm64': '-'}>
+CONFIG_ZYNQMP_POWER                             policy<{'arm64': '-'}>
--- linux-ein-5.4.0.orig/debian.ein/control.d/flavour-control.stub
+++ linux-ein-5.4.0/debian.ein/control.d/flavour-control.stub
@@ -0,0 +1,108 @@
+# 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, aufs-dkms, =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
+Breaks: flash-kernel (<< 3.90ubuntu2) [arm64 armhf], s390-tools (<< 2.3.0-0ubuntu3) [s390x]
+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}, crda
+Built-Using: ${linux:BuiltUsing}
+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-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=.
--- linux-ein-5.4.0.orig/debian.ein/control.d/vars.ein
+++ linux-ein-5.4.0/debian.ein/control.d/vars.ein
@@ -0,0 +1,6 @@
+arch="armhf arm64"
+supported="Generic"
+target="Geared toward desktop and server systems."
+desc="=HUMAN= SMP"
+bootloader="grub-pc [amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [amd64 x32] | grub [amd64 x32] | lilo (>= 19.1) [amd64 x32] | flash-kernel [armhf arm64] | grub-ieee1275 [ppc64el]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules"
--- linux-ein-5.4.0.orig/debian.ein/control.stub.in
+++ linux-ein-5.4.0/debian.ein/control.stub.in
@@ -0,0 +1,80 @@
+Source: SRCPKGNAME
+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>,
+ libcap-dev <!stage1>,
+ makedumpfile [amd64] <!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 ppc64el] <!stage1>,
+ openssl <!stage1>,
+ libssl-dev <!stage1>,
+ libaudit-dev <!stage1>,
+ bc <!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>,
+ dwarves <!stage1>,
+Build-Depends-Indep:
+ xmlto <!stage1>,
+ docbook-utils <!stage1>,
+ ghostscript <!stage1>,
+ fig2dev <!stage1>,
+ bzip2 <!stage1>,
+ sharutils <!stage1>,
+ asciidoc <!stage1>,
+ python3-sphinx <!stage1>,
+ python3-sphinx-rtd-theme <!stage1>,
+ python3-docutils <!stage1>,
+Vcs-Git: git://git.launchpad.net/~canonical-hwe-imx/ubuntu/+source/linux-imx/+git/=SERIES=
+Vcs-Browser: https://git.launchpad.net/~canonical-hwe-imx/ubuntu/+source/linux-imx/+git/=SERIES=/log/
+XS-Testsuite: autopkgtest
+#XS-Testsuite-Depends: gcc-4.7 binutils
+
+Package: SRCPKGNAME-headers-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Multi-Arch: foreign
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, coreutils
+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-tools-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-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>.
+
--- linux-ein-5.4.0.orig/debian.ein/copyright
+++ linux-ein-5.4.0/debian.ein/copyright
@@ -0,0 +1,29 @@
+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'.
--- linux-ein-5.4.0.orig/debian.ein/d-i/firmware/README.txt
+++ linux-ein-5.4.0/debian.ein/d-i/firmware/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.ein/d-i/firmware/arm64/README.txt
+++ linux-ein-5.4.0/debian.ein/d-i/firmware/arm64/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.ein/d-i/firmware/armhf/README.txt
+++ linux-ein-5.4.0/debian.ein/d-i/firmware/armhf/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.ein/d-i/firmware/nic-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/firmware/scsi-modules
+++ linux-ein-5.4.0/debian.ein/d-i/firmware/scsi-modules
@@ -0,0 +1,3 @@
+qlogic/1040.bin ?
+qlogic/12160.bin ?
+qlogic/1280.bin ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/kernel-versions
+++ linux-ein-5.4.0/debian.ein/d-i/kernel-versions
@@ -0,0 +1 @@
+# arch	version		flavour		installedname			suffix	bdep
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/block-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/block-modules
@@ -0,0 +1,34 @@
+aoe ?
+aten ?
+bpck ?
+bpck6 ?
+cciss ?
+comm ?
+cpqarray ?
+DAC960 ?
+dstr ?
+epat ?
+epia ?
+fit2 ?
+fit3 ?
+friq ?
+frpw ?
+hpsa ?
+kbic ?
+ktti ?
+nbd ?
+nvme ?
+on20 ?
+on26 ?
+paride ?
+pcd ?
+pd ?
+pf ?
+pg ?
+pt ?
+sdhci-tegra ?
+sx8 ?
+umem ?
+virtio_blk ?
+xen-blkfront ?
+mtip32xx ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/crypto-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/fat-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/fat-modules
@@ -0,0 +1,7 @@
+fat ?
+vfat ?
+
+# Supporting modules ?
+nls_cp437 ?
+nls_iso8859-1 ?
+nls_utf8 ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/fb-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/fb-modules
@@ -0,0 +1,3 @@
+fbcon ?
+vesafb ?
+vga16fb ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/firewire-core-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/firewire-core-modules
@@ -0,0 +1,4 @@
+firewire-core ?
+firewire-ohci ?
+firewire-sbp2 ?
+firewire-net ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/floppy-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/floppy-modules
@@ -0,0 +1 @@
+floppy ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/fs-core-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/fs-core-modules
@@ -0,0 +1,4 @@
+ext2 ?
+jfs ?
+reiserfs ?
+xfs ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/fs-secondary-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/fs-secondary-modules
@@ -0,0 +1,5 @@
+btrfs ?
+fuse ?
+ntfs ?
+hfs ?
+hfsplus ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/input-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/input-modules
@@ -0,0 +1,23 @@
+hid-a4tech ?
+hid-apple ?
+hid-belkin ?
+hid-bright ?
+hid-cherry ?
+hid-chicony ?
+hid-cypress ?
+hid-dell ?
+hid-ezkey ?
+hid-generic ?
+hid-gyration ?
+hid-logitech ?
+hid-logitech-dj ?
+hid-microsoft ?
+hid-monterey ?
+hid-petalynx ?
+hid-pl ?
+hid-samsung ?
+hid-sony ?
+hid-sunplus ?
+hid-tmff ?
+hid-zpff ?
+usbhid ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/ipmi-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/ipmi-modules
@@ -0,0 +1,5 @@
+ipmi_devintf ?
+ipmi_msghandler ?
+ipmi_poweroff ?
+ipmi_si ?
+ipmi_watchdog ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/irda-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/kernel-image
+++ linux-ein-5.4.0/debian.ein/d-i/modules/kernel-image
@@ -0,0 +1,29 @@
+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-ein-5.4.0.orig/debian.ein/d-i/modules/md-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/message-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/message-modules
@@ -0,0 +1,9 @@
+mptbase ?
+mptctl ?
+mptfc ?
+mptlan ?
+mptsas ?
+mpt2sas ?
+mpt3sas ?
+mptscsih ?
+mptspi ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/mouse-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/mouse-modules
@@ -0,0 +1,2 @@
+psmouse ?
+usbmouse ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/multipath-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/multipath-modules
@@ -0,0 +1,3 @@
+dm-multipath ?
+dm-round-robin ?
+dm-service-time ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/nfs-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/nfs-modules
@@ -0,0 +1,6 @@
+nfs ?
+nfs_acl ?
+nfsv3 ?
+lockd ?
+sunrpc ?
+cifs ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/nic-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/nic-modules
@@ -0,0 +1,180 @@
+3c359 ?
+3c501 ?
+3c503 ?
+3c505 ?
+3c507 ?
+3c509 ?
+3c515 ?
+3c523 ?
+3c527 ?
+3c59x ?
+8139cp ?
+8139too ?
+82596 ?
+abyss ?
+ac3200 ?
+adm8211 ?
+airo ?
+airport ?
+alx ?
+amd8111e ?
+arc4 ?
+arcnet ?
+arc-rawmode ?
+arc-rimi ?
+arlan ?
+at1700 ?
+ath5k ?
+ath9k ?
+ath9k_htc ?
+atl1 ?
+atl1c ?
+atl1e ?
+atl2 ?
+atmel ?
+atmel_pci ?
+b44 ?
+be2net ?
+bmac ?
+bnx2 ?
+bnx2x ?
+bonding ?
+brcmfmac ?
+brcmsmac ?
+xgmac ?
+cassini ?
+com20020 ?
+com20020-pci ?
+com90io ?
+com90xx ?
+cs89x0 ?
+de2104x ?
+de4x5 ?
+de600 ?
+de620 ?
+defxx ?
+depca ?
+dl2k ?
+dmfe ?
+dummy ?
+e100 ?
+e1000 ?
+e1000e ?
+e2100 ?
+eepro ?
+eepro100 ?
+eexpress ?
+enic ?
+epic100 ?
+eql ?
+es3210 ?
+eth16i ?
+ewrk3 ?
+fealnx ?
+forcedeth ?
+igb ?
+ps3_gelic ?
+hamachi ?
+hermes ?
+hp ?
+hp100 ?
+hp-plus ?
+i40e ?
+i40evf ?
+ibmtr ?
+ipddp ?
+ipw2100 ?
+ipw2200 ?
+iwl3945 ?
+iwl4965 ?
+iwl-legacy ?
+iwldvm ?
+iwlwifi ?
+ixgb ?
+ixgbe ?
+lance ?
+lanstreamer ?
+lasi_82596 ?
+lne390 ?
+lp486e ?
+mace ?
+mlx4_core ?
+mlx4_en ?
+mlx5_core ?
+mv643xx_eth ?
+myri_sbus ?
+natsemi ?
+ne ?
+ne2 ?
+ne2k-pci ?
+ne3210 ?
+netconsole ?
+netxen_nic ?
+ni5010 ?
+ni52 ?
+ni65 ?
+nicpf ?
+nicvf ?
+niu ?
+ns83820 ?
+olympic ?
+orinoco ?
+orinoco_pci ?
+orinoco_plx ?
+orinoco_tmd ?
+pcnet32 ?
+qlcnic ?
+r815x ?
+r8169 ?
+rate_control ?
+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-ein-5.4.0.orig/debian.ein/d-i/modules/nic-pcmcia-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/nic-shared-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/nic-usb-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/parport-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/parport-modules
@@ -0,0 +1,2 @@
+parport ?
+parport_pc ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/pata-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/pcmcia-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/pcmcia-modules
@@ -0,0 +1,8 @@
+i82092 ?
+i82365 ?
+pcmcia ?
+pcmcia_core ?
+pd6729 ?
+rsrc_nonstatic ?
+tcic ?
+yenta_socket ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/pcmcia-storage-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/pcmcia-storage-modules
@@ -0,0 +1,6 @@
+pata_pcmcia ?
+qlogic_cs ?
+fdomain_cs ?
+aha152x_cs ?
+nsp_cs ?
+sym53c500_cs ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/plip-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/plip-modules
@@ -0,0 +1 @@
+plip ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/ppp-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/ppp-modules
@@ -0,0 +1,6 @@
+ppp_async ?
+ppp_deflate ?
+ppp_mppe ?
+pppoe ?
+pppox ?
+ppp_synctty ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/sata-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/scsi-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/scsi-modules
@@ -0,0 +1,129 @@
+# 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 ?
+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 ?
+ibmvscsic ?
+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 ?
+
+# device handlers
+scsi_dh_alua ?
+scsi_dh_emc ?
+scsi_dh_rdac ?
+scsi_dh_hp_sw ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/serial-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/serial-modules
@@ -0,0 +1,4 @@
+generic_serial ?
+serial_cs ?
+synclink_cs ?
+hyperv-keyboard ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/speakup-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/storage-core-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/usb-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/usb-modules
@@ -0,0 +1,11 @@
+ehci-hcd ?
+isp116x-hcd ?
+isp1760 ?
+ohci-hcd ?
+r8a66597-hcd ?
+sl811_cs ?
+sl811-hcd ?
+u132-hcd ?
+uhci-hcd ?
+xhci-hcd ?
+ehci-tegra ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/modules/virtio-modules
+++ linux-ein-5.4.0/debian.ein/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-ein-5.4.0.orig/debian.ein/d-i/modules/vlan-modules
+++ linux-ein-5.4.0/debian.ein/d-i/modules/vlan-modules
@@ -0,0 +1,3 @@
+slp ?
+garp ?
+8021q ?
--- linux-ein-5.4.0.orig/debian.ein/d-i/package-list
+++ linux-ein-5.4.0/debian.ein/d-i/package-list
@@ -0,0 +1,193 @@
+Package: kernel-image
+Provides: ext3-modules, ext4-modules, squashfs-modules
+Provides_amd64: efi-modules, ext3-modules, ext4-modules, squashfs-modules
+Provides_i386: efi-modules, ext3-modules, ext4-modules, squashfs-modules
+Provides_ppc64el: ext3-modules, ext4-modules, fat-modules, squashfs-modules
+Provides_s390x: ext3-modules, ext4-modules, ppp-modules, squashfs-modules
+Description: kernel image and system map
+
+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: 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-ein-5.4.0.orig/debian.ein/dkms-versions
+++ linux-ein-5.4.0/debian.ein/dkms-versions
@@ -0,0 +1,3 @@
+zfs-linux 0.8.3-1ubuntu12.17
+virtualbox 6.1.50-dfsg-1~ubuntu1.20.04.1
+wireguard-linux-compat 1.0.20201112-1~20.04.1
--- linux-ein-5.4.0.orig/debian.ein/etc/kernelconfig
+++ linux-ein-5.4.0/debian.ein/etc/kernelconfig
@@ -0,0 +1,7 @@
+if [ "$variant" = "ports" ]; then
+	archs=""
+	family='ports'
+else
+	archs="armhf arm64"
+	family='ubuntu'
+fi
--- linux-ein-5.4.0.orig/debian.ein/etc/update.conf
+++ linux-ein-5.4.0/debian.ein/etc/update.conf
@@ -0,0 +1,7 @@
+# WARNING: we do not create update.conf when we are not a
+# derivative. Various cranky components make use of this.
+# If we start unconditionally creating update.conf we need
+# to fix at least cranky close and cranky rebase.
+RELEASE_REPO=git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal
+SOURCE_RELEASE_BRANCH=master-next
+DEBIAN_MASTER=debian.master
--- linux-ein-5.4.0.orig/debian.ein/reconstruct
+++ linux-ein-5.4.0/debian.ein/reconstruct
@@ -0,0 +1,130 @@
+# Recreate any symlinks created since the orig.
+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/config-check'
+chmod +x 'debian/scripts/control-create'
+chmod +x 'debian/scripts/dkms-build'
+chmod +x 'debian/scripts/dkms-build--nvidia-N'
+chmod +x 'debian/scripts/dkms-build--virtualbox-guest'
+chmod +x 'debian/scripts/dkms-build-configure--zfs'
+chmod +x 'debian/scripts/file-downloader'
+chmod +x 'debian/scripts/link-headers'
+chmod +x 'debian/scripts/misc/annotations'
+chmod +x 'debian/scripts/misc/arch-has-odm-enabled.sh'
+chmod +x 'debian/scripts/misc/final-checks'
+chmod +x 'debian/scripts/misc/find-missing-sauce.sh'
+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/kernel-wedge-arch.pl'
+chmod +x 'debian/scripts/misc/kernelconfig'
+chmod +x 'debian/scripts/misc/migrate-annotations'
+chmod +x 'debian/scripts/misc/retag'
+chmod +x 'debian/scripts/misc/splitconfig.pl'
+chmod +x 'debian/scripts/misc/tristate.sh'
+chmod +x 'debian/scripts/misc/update-aufs.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 'samples/bpf/lwt_len_hist.sh'
+chmod +x 'samples/bpf/test_lwt_bpf.sh'
+chmod +x 'scripts/kmsg-doc'
+chmod +x 'scripts/parse-maintainers.pl'
+chmod +x 'snap/local/medina.yaml'
+chmod +x 'snap/local/reading.yaml'
+chmod +x 'tools/testing/selftests/net/fib_nexthop_nongw.sh'
+chmod +x 'tools/testing/selftests/netfilter/conntrack_vrf.sh'
+# Remove any files deleted from the orig.
+rm -f 'Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml'
+rm -f 'Documentation/networking/decnet.txt'
+rm -f 'arch/alpha/include/asm/bugs.h'
+rm -f 'arch/ia64/include/asm/bugs.h'
+rm -f 'arch/m68k/include/asm/bugs.h'
+rm -f 'arch/parisc/include/asm/bugs.h'
+rm -f 'arch/parisc/kernel/module.lds'
+rm -f 'arch/parisc/lib/string.S'
+rm -f 'arch/powerpc/include/asm/bugs.h'
+rm -f 'arch/powerpc/include/uapi/asm/bpf_perf_event.h'
+rm -f 'arch/sh/include/asm/bugs.h'
+rm -f 'arch/sparc/include/asm/bugs.h'
+rm -f 'arch/um/include/asm/bugs.h'
+rm -f 'arch/um/kernel/gmon_syms.c'
+rm -f 'arch/x86/events/intel/rapl.c'
+rm -f 'arch/x86/include/asm/refcount.h'
+rm -f 'arch/xtensa/include/asm/bugs.h'
+rm -f 'drivers/block/sx8.c'
+rm -f 'drivers/clk/imx/clk-sccg-pll.c'
+rm -f 'drivers/crypto/hisilicon/sgl.h'
+rm -f 'drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h'
+rm -f 'drivers/gpu/drm/imx/ipuv3-crtc.c'
+rm -f 'drivers/gpu/drm/imx/ipuv3-plane.c'
+rm -f 'drivers/gpu/drm/imx/ipuv3-plane.h'
+rm -f 'drivers/iio/adc/stx104.c'
+rm -f 'drivers/input/serio/i8042-ppcio.h'
+rm -f 'drivers/net/can/dev.c'
+rm -f 'drivers/net/can/rx-offload.c'
+rm -f 'drivers/net/phy/mdio-i2c.h'
+rm -f 'drivers/net/phy/mdio-xgene.h'
+rm -f 'drivers/soc/imx/soc-imx8.c'
+rm -f 'drivers/soc/qcom/llcc-sdm845.c'
+rm -f 'drivers/soc/qcom/llcc-slice.c'
+rm -f 'drivers/staging/mt7621-dma/mtk-hsdma.c'
+rm -f 'include/Kbuild'
+rm -f 'include/asm-generic/bugs.h'
+rm -f 'include/linux/firmware/imx/types.h'
+rm -f 'include/linux/kd.h'
+rm -f 'include/net/dn.h'
+rm -f 'include/net/dn_dev.h'
+rm -f 'include/net/dn_fib.h'
+rm -f 'include/net/dn_neigh.h'
+rm -f 'include/net/dn_nsp.h'
+rm -f 'include/net/dn_route.h'
+rm -f 'include/trace/events/random.h'
+rm -f 'include/uapi/linux/dn.h'
+rm -f 'include/uapi/linux/netfilter_decnet.h'
+rm -f 'include/uapi/rdma/nes-abi.h'
+rm -f 'kernel/elfcore.c'
+rm -f 'net/decnet/Kconfig'
+rm -f 'net/decnet/Makefile'
+rm -f 'net/decnet/README'
+rm -f 'net/decnet/af_decnet.c'
+rm -f 'net/decnet/dn_dev.c'
+rm -f 'net/decnet/dn_fib.c'
+rm -f 'net/decnet/dn_neigh.c'
+rm -f 'net/decnet/dn_nsp_in.c'
+rm -f 'net/decnet/dn_nsp_out.c'
+rm -f 'net/decnet/dn_route.c'
+rm -f 'net/decnet/dn_rules.c'
+rm -f 'net/decnet/dn_table.c'
+rm -f 'net/decnet/dn_timer.c'
+rm -f 'net/decnet/netfilter/Kconfig'
+rm -f 'net/decnet/netfilter/Makefile'
+rm -f 'net/decnet/netfilter/dn_rtmsg.c'
+rm -f 'net/decnet/sysctl_net_decnet.c'
+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 'net/sched/sch_atm.c'
+rm -f 'net/sched/sch_cbq.c'
+rm -f 'net/sched/sch_dsmark.c'
+rm -f 'net/xfrm/xfrm_interface.c'
+rm -f 'tools/build/feature/test-libpython-version.c'
+exit 0
--- linux-ein-5.4.0.orig/debian.ein/rules.d/arm64.mk
+++ linux-ein-5.4.0/debian.ein/rules.d/arm64.mk
@@ -0,0 +1,27 @@
+human_arch	= ARMv8
+build_arch	= arm64
+header_arch	= arm64
+defconfig	= defconfig
+flavours	= ein
+build_image	= Image
+kernel_file	= arch/$(build_arch)/boot/Image
+install_file	= vmlinuz
+no_dumpfile	= true
+
+loader		= grub
+
+do_linux_tools	= true
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf	= true
+do_tools_bpftool = true
+
+do_common_headers_indep=false
+
+do_dtbs		= true
+disable_d_i = true
+do_libc_dev_package=false
+do_doc_package	= false
+do_source_package= false
+do_dkms_wireguard = true
+do_zfs = true
--- linux-ein-5.4.0.orig/debian.ein/rules.d/armhf.mk
+++ linux-ein-5.4.0/debian.ein/rules.d/armhf.mk
@@ -0,0 +1,27 @@
+human_arch	= ARM (hard float)
+build_arch	= arm
+header_arch	= arm
+defconfig	= defconfig
+flavours	= ein
+build_image	= zImage
+kernel_file	= arch/$(build_arch)/boot/zImage
+install_file	= vmlinuz
+no_dumpfile	= true
+
+loader		= grub
+
+do_linux_tools	= true
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf	= true
+do_tools_bpftool = true
+
+do_common_headers_indep=false
+
+do_dtbs		= true
+disable_d_i = true
+do_libc_dev_package=false
+do_doc_package	= false
+do_source_package= false
+do_dkms_wireguard = true
+do_zfs = true
--- linux-ein-5.4.0.orig/debian.ein/tracking-bug
+++ linux-ein-5.4.0/debian.ein/tracking-bug
@@ -0,0 +1 @@
+2068265 s2024.04.29-1
--- linux-ein-5.4.0.orig/debian.master/changelog
+++ linux-ein-5.4.0/debian.master/changelog
@@ -0,0 +1,41122 @@
+linux (5.4.0-187.207) focal; urgency=medium
+
+  * focal/linux: 5.4.0-187.207 -proposed tracker (LP: #2068291)
+
+  * CVE-2024-26925
+    - netfilter: Cleanup nft_net->module_list from nf_tables_exit_net()
+    - netfilter: nf_tables: release batch on table validation from abort path
+    - netfilter: nf_tables: release mutex after nft_gc_seq_end from abort path
+
+  * CVE-2024-26643
+    - netfilter: nf_tables: mark set as dead when unbinding anonymous set with
+      timeout
+
+  * 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|ON|OFF}
+    - 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
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Mon, 10 Jun 2024 09:47:52 +0200
+
+linux (5.4.0-186.206) focal; urgency=medium
+
+  * focal/linux: 5.4.0-186.206 -proposed tracker (LP: #2063812)
+
+  * Mount CIFS fails with Permission denied (LP: #2061986)
+    - cifs: fix ntlmssp auth when there is no key exchange
+
+  * USB stick can't be detected (LP: #2040948)
+    - usb: Disable USB3 LPM at shutdown
+
+  * CVE-2024-26733
+    - net: dev: Convert sa_data to flexible array in struct sockaddr
+    - arp: Prevent overflow in arp_req_get().
+    - stddef: Introduce DECLARE_FLEX_ARRAY() helper
+
+  * CVE-2024-26712
+    - powerpc/kasan: Fix addr error caused by page alignment
+
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+
+  * CVE-2021-47063
+    - drm: bridge/panel: Cleanup connector on bridge detach
+
+  * [Ubuntu 22.04.4/linux-image-6.5.0-26-generic] Kernel output "UBSAN: array-
+    index-out-of-bounds in /build/linux-hwe-6.5-34pCLi/linux-
+    hwe-6.5-6.5.0/drivers/net/hyperv/netvsc.c:1445:41" multiple times,
+    especially during boot. (LP: #2058477)
+    - hv: hyperv.h: Replace one-element array with flexible-array member
+
+  * CVE-2024-26614
+    - tcp: make sure init the accept_queue's spinlocks once
+    - ipv6: init the accept_queue's spinlocks in inet6_create
+
+  * Focal update: v5.4.271 upstream stable release (LP: #2060216)
+    - netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+    - net: ip_tunnel: prevent perpetual headroom growth
+    - tun: Fix xdp_rxq_info's queue_index when detaching
+    - ipv6: fix potential "struct net" leak in inet6_rtm_getaddr()
+    - lan78xx: enable auto speed configuration for LAN7850 if no EEPROM is
+      detected
+    - net: usb: dm9601: fix wrong return value in dm9601_mdio_read
+    - Bluetooth: Avoid potential use-after-free in hci_error_reset
+    - Bluetooth: hci_event: Fix handling of HCI_EV_IO_CAPA_REQUEST
+    - Bluetooth: Enforce validation on max value of connection interval
+    - netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
+    - rtnetlink: fix error logic of IFLA_BRIDGE_FLAGS writing back
+    - efi/capsule-loader: fix incorrect allocation size
+    - power: supply: bq27xxx-i2c: Do not free non existing IRQ
+    - ALSA: Drop leftover snd-rtctimer stuff from Makefile
+    - afs: Fix endless loop in directory parsing
+    - gtp: fix use-after-free and null-ptr-deref in gtp_newlink()
+    - wifi: nl80211: reject iftype change with mesh ID change
+    - btrfs: dev-replace: properly validate device names
+    - dmaengine: fsl-qdma: fix SoC may hang on 16 byte unaligned read
+    - dmaengine: fsl-qdma: init irq after reg initialization
+    - mmc: core: Fix eMMC initialization with 1-bit bus connection
+    - x86/cpu/intel: Detect TME keyid bits before setting MTRR mask registers
+    - cachefiles: fix memory leak in cachefiles_add_cache()
+    - fs,hugetlb: fix NULL pointer dereference in hugetlbs_fill_super
+    - gpio: 74x164: Enable output pins after registers are reset
+    - Linux 5.4.271
+
+  * Focal update: v5.4.270 upstream stable release (LP: #2060019)
+    - KVM: arm64: vgic-its: Test for valid IRQ in its_sync_lpi_pending_table()
+    - KVM: arm64: vgic-its: Test for valid IRQ in MOVALL handler
+    - net/sched: Retire CBQ qdisc
+    - [Config] updateconfigs for NET_SCH_CBQ
+    - net/sched: Retire ATM qdisc
+    - [Config] updateconfigs for NET_SCH_ATM
+    - net/sched: Retire dsmark qdisc
+    - [Config] updateconfigs for NET_SCH_DSMARK
+    - sched/rt: sysctl_sched_rr_timeslice show default timeslice after reset
+    - memcg: add refcnt for pcpu stock to avoid UAF problem in drain_all_stock()
+    - nilfs2: replace WARN_ONs for invalid DAT metadata block requests
+    - userfaultfd: fix mmap_changing checking in mfill_atomic_hugetlb
+    - sched/rt: Fix sysctl_sched_rr_timeslice intial value
+    - sched/rt: Disallow writing invalid values to sched_rt_period_us
+    - scsi: target: core: Add TMF to tmr_list handling
+    - dmaengine: shdma: increase size of 'dev_id'
+    - dmaengine: fsl-qdma: increase size of 'irq_name'
+    - wifi: cfg80211: fix missing interfaces when dumping
+    - wifi: mac80211: fix race condition on enabling fast-xmit
+    - fbdev: savage: Error out if pixclock equals zero
+    - fbdev: sis: Error out if pixclock equals zero
+    - ahci: asm1166: correct count of reported ports
+    - ahci: add 43-bit DMA address quirk for ASMedia ASM1061 controllers
+    - ext4: avoid allocating blocks from corrupted group in
+      ext4_mb_try_best_found()
+    - ext4: avoid allocating blocks from corrupted group in ext4_mb_find_by_goal()
+    - regulator: pwm-regulator: Add validity checks in continuous .get_voltage
+    - nvmet-tcp: fix nvme tcp ida memory leak
+    - ASoC: sunxi: sun4i-spdif: Add support for Allwinner H616
+    - netfilter: conntrack: check SCTP_CID_SHUTDOWN_ACK for vtag setting in
+      sctp_new
+    - nvmet-fc: abort command when there is no binding
+    - hwmon: (coretemp) Enlarge per package core count limit
+    - scsi: lpfc: Use unsigned type for num_sge
+    - firewire: core: send bus reset promptly on gap count error
+    - virtio-blk: Ensure no requests in virtqueues before deleting vqs.
+    - s390/qeth: Fix potential loss of L3-IP@ in case of network issues
+    - pmdomain: renesas: r8a77980-sysc: CR7 must be always on
+    - tcp: factor out __tcp_close() helper
+    - tcp: return EPOLLOUT from tcp_poll only when notsent_bytes is half the limit
+    - tcp: add annotations around sk->sk_shutdown accesses
+    - pinctrl: pinctrl-rockchip: Fix a bunch of kerneldoc misdemeanours
+    - pinctrl: rockchip: Fix refcount leak in rockchip_pinctrl_parse_groups
+    - spi: mt7621: Fix an error message in mt7621_spi_probe()
+    - net: bridge: clear bridge's private skb space on xmit
+    - selftests/bpf: Avoid running unprivileged tests with alignment requirements
+    - Revert "drm/sun4i: dsi: Change the start delay calculation"
+    - drm/amdgpu: Check for valid number of registers to read
+    - x86/alternatives: Disable KASAN in apply_alternatives()
+    - dm-integrity: don't modify bio's immutable bio_vec in integrity_metadata()
+    - iomap: Set all uptodate bits for an Uptodate page
+    - drm/amdgpu: Fix type of second parameter in trans_msg() callback
+    - arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node
+    - PCI: tegra: Fix reporting GPIO error value
+    - PCI: tegra: Fix OF node reference leak
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one error
+    - dm-crypt: don't modify the data when using authenticated encryption
+    - gtp: fix use-after-free and null-ptr-deref in gtp_genl_dump_pdp()
+    - PCI/MSI: Prevent MSI hardware interrupt number truncation
+    - l2tp: pass correct message length to ip6_append_data
+    - ARM: ep93xx: Add terminator to gpiod_lookup_table
+    - usb: cdns3: fixed memory use after free at cdns3_gadget_ep_disable()
+    - usb: cdns3: fix memory double free when handle zero packet
+    - usb: gadget: ncm: Avoid dropping datagrams of properly parsed NTBs
+    - usb: roles: don't get/set_role() when usb_role_switch is unregistered
+    - IB/hfi1: Fix a memleak in init_credit_return
+    - RDMA/bnxt_re: Return error for SRQ resize
+    - RDMA/srpt: Make debug output more detailed
+    - RDMA/srpt: fix function pointer cast warnings
+    - scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions
+    - bpf, scripts: Correct GPL license name
+    - scsi: jazz_esp: Only build if SCSI core is builtin
+    - nouveau: fix function cast warnings
+    - ipv4: properly combine dev_base_seq and ipv4.dev_addr_genid
+    - ipv6: properly combine dev_base_seq and ipv6.dev_addr_genid
+    - afs: Increase buffer size in afs_update_volume_status()
+    - ipv6: sr: fix possible use-after-free and null-ptr-deref
+    - packet: move from strlcpy with unused retval to strscpy
+    - s390: use the correct count for __iowrite64_copy()
+    - tls: rx: jump to a more appropriate label
+    - tls: rx: drop pointless else after goto
+    - tls: stop recv() if initial process_rx_list gave us non-DATA
+    - netfilter: nf_tables: set dormant flag on hook register failure
+    - drm/syncobj: make lockdep complain on WAIT_FOR_SUBMIT v3
+    - drm/syncobj: call drm_syncobj_fence_add_wait when WAIT_AVAILABLE flag is set
+    - fs/aio: Restrict kiocb_set_cancel_fn() to I/O submitted via libaio
+    - scripts/bpf: Fix xdp_md forward declaration typo
+    - Linux 5.4.270
+
+  * CVE-2023-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+
+  * CVE-2021-47070
+    - uio: uio_hv_generic: use devm_kzalloc() for private data alloc
+    - uio_hv_generic: Fix another memory leak in error handling paths
+
+  * CVE-2024-26622
+    - tomoyo: fix UAF write bug in tomoyo_write_control()
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Fri, 26 Apr 2024 14:01:17 +0200
+
+linux (5.4.0-181.201) focal; urgency=medium
+
+  * focal/linux: 5.4.0-181.201 -proposed tracker (LP: #2059549)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+
+  * Drop fips-checks script from trees (LP: #2055083)
+    - [Packaging] Remove fips-checks script
+
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948)
+    - PCI: mediatek: Clear interrupt status before dispatching handler
+    - include/linux/units.h: add helpers for kelvin to/from Celsius conversion
+    - units: Add Watt units
+    - units: change from 'L' to 'UL'
+    - units: add the HZ macros
+    - serial: sc16is7xx: set safe default SPI clock frequency
+    - spi: introduce SPI_MODE_X_MASK macro
+    - serial: sc16is7xx: add check for unsupported SPI modes during probe
+    - ext4: allow for the last group to be marked as trimmed
+    - crypto: api - Disallow identical driver names
+    - PM: hibernate: Enforce ordering during image compression/decompression
+    - hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+    - rpmsg: virtio: Free driver_override when rpmsg_remove()
+    - parisc/firmware: Fix F-extend for PDC addresses
+    - arm64: dts: qcom: sdm845: fix USB wakeup interrupt types
+    - mmc: core: Use mrq.sbc in close-ended ffu
+    - nouveau/vmm: don't set addr on the fail path to avoid warning
+    - ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
+    - rename(): fix the locking of subdirectories
+    - block: Remove special-casing of compound pages
+    - mtd: spinand: macronix: Fix MX35LFxGE4AD page size
+    - fs: add mode_strip_sgid() helper
+    - fs: move S_ISGID stripping into the vfs_*() helpers
+    - powerpc: Use always instead of always-y in for crtsavres.o
+    - x86/CPU/AMD: Fix disabling XSAVES on AMD family 0x17 due to erratum
+    - net/smc: fix illegal rmb_desc access in SMC-D connection dump
+    - vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
+    - llc: make llc_ui_sendmsg() more robust against bonding changes
+    - llc: Drop support for ETH_P_TR_802_2.
+    - net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
+    - tracing: Ensure visibility when inserting an element into tracing_map
+    - afs: Hide silly-rename files from userspace
+    - tcp: Add memory barrier to tcp_push()
+    - netlink: fix potential sleeping issue in mqueue_flush_file
+    - net/mlx5: DR, Use the right GVMI number for drop action
+    - net/mlx5: Use kfree(ft->g) in arfs_create_groups()
+    - net/mlx5e: fix a double-free in arfs_create_groups
+    - netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
+    - netfilter: nf_tables: validate NFPROTO_* family
+    - fjes: fix memleaks in fjes_hw_setup
+    - net: fec: fix the unhandled context fault from smmu
+    - btrfs: ref-verify: free ref cache before clearing mount opt
+    - btrfs: tree-checker: fix inline ref size in error messages
+    - btrfs: don't warn if discard range is not aligned to sector
+    - btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
+    - rbd: don't move requests to the running list on errors
+    - gpiolib: acpi: Ignore touchpad wakeup on GPD G1619-04
+    - drm: Don't unref the same fb many times by mistake due to deadlock handling
+    - drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking
+    - drm/bridge: nxp-ptn3460: simplify some error checking
+    - drm/exynos: fix accidental on-stack copy of exynos_drm_plane
+    - drm/exynos: gsc: minor fix for loop iteration in gsc_runtime_resume
+    - gpio: eic-sprd: Clear interrupt after set the interrupt type
+    - spi: bcm-qspi: fix SFDP BFPT read by usig mspi read
+    - mips: Call lose_fpu(0) before initializing fcr31 in mips_set_personality_nan
+    - tick/sched: Preserve number of idle sleeps across CPU hotplug events
+    - x86/entry/ia32: Ensure s32 is sign extended to s64
+    - powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+    - powerpc: Fix build error due to is_valid_bugaddr()
+    - powerpc/mm: Fix build failures due to arch_reserved_kernel_pages()
+    - powerpc: pmd_move_must_withdraw() is only needed for
+      CONFIG_TRANSPARENT_HUGEPAGE
+    - powerpc/lib: Validate size for vector operations
+    - x86/mce: Mark fatal MCE's page as poison to avoid panic in the kdump kernel
+    - perf/core: Fix narrow startup race when creating the perf nr_addr_filters
+      sysfs file
+    - regulator: core: Only increment use_count when enable_count changes
+    - audit: Send netlink ACK before setting connection in auditd_set
+    - ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
+    - PNP: ACPI: fix fortify warning
+    - ACPI: extlog: fix NULL pointer dereference check
+    - FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+    - jfs: fix slab-out-of-bounds Read in dtSearch
+    - jfs: fix array-index-out-of-bounds in dbAdjTree
+    - pstore/ram: Fix crash when setting number of cpus to an odd number
+    - crypto: stm32/crc32 - fix parsing list of devices
+    - afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
+    - rxrpc_find_service_conn_rcu: fix the usage of read_seqbegin_or_lock()
+    - jfs: fix array-index-out-of-bounds in diNewExt
+    - s390/ptrace: handle setting of fpc register correctly
+    - KVM: s390: fix setting of fpc register
+    - SUNRPC: Fix a suspicious RCU usage warning
+    - ecryptfs: Reject casefold directory inodes
+    - ext4: fix inconsistent between segment fstrim and full fstrim
+    - ext4: unify the type of flexbg_size to unsigned int
+    - ext4: remove unnecessary check from alloc_flex_gd()
+    - ext4: avoid online resizing failures due to oversized flex bg
+    - wifi: rt2x00: restart beacon queue when hardware reset
+    - selftests/bpf: satisfy compiler by having explicit return in btf test
+    - selftests/bpf: Fix pyperf180 compilation failure with clang18
+    - scsi: lpfc: Fix possible file string name overflow when updating firmware
+    - PCI: Add no PM reset quirk for NVIDIA Spectrum devices
+    - bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk
+    - ARM: dts: imx7d: Fix coresight funnel ports
+    - ARM: dts: imx7s: Fix lcdif compatible
+    - ARM: dts: imx7s: Fix nand-controller #size-cells
+    - wifi: ath9k: Fix potential array-index-out-of-bounds read in
+      ath9k_htc_txstatus()
+    - bpf: Add map and need_defer parameters to .map_fd_put_ptr()
+    - scsi: libfc: Don't schedule abort twice
+    - scsi: libfc: Fix up timeout error in fc_fcp_rec_error()
+    - ARM: dts: rockchip: fix rk3036 hdmi ports node
+    - ARM: dts: imx25/27-eukrea: Fix RTC node name
+    - ARM: dts: imx: Use flash@0,0 pattern
+    - ARM: dts: imx27: Fix sram node
+    - ARM: dts: imx1: Fix sram node
+    - ARM: dts: imx25/27: Pass timing0
+    - ARM: dts: imx27-apf27dev: Fix LED name
+    - ARM: dts: imx23-sansa: Use preferred i2c-gpios properties
+    - ARM: dts: imx23/28: Fix the DMA controller node name
+    - block: prevent an integer overflow in bvec_try_merge_hw_page
+    - md: Whenassemble the array, consult the superblock of the freshest device
+    - arm64: dts: qcom: msm8996: Fix 'in-ports' is a required property
+    - arm64: dts: qcom: msm8998: Fix 'out-ports' is a required property
+    - wifi: rtl8xxxu: Add additional USB IDs for RTL8192EU devices
+    - wifi: rtlwifi: rtl8723{be,ae}: using calculate_bit_shift()
+    - wifi: cfg80211: free beacon_ies when overridden from hidden BSS
+    - f2fs: fix to check return value of f2fs_reserve_new_block()
+    - ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument
+    - fast_dput(): handle underflows gracefully
+    - RDMA/IPoIB: Fix error code return in ipoib_mcast_join
+    - drm/drm_file: fix use of uninitialized variable
+    - drm/framebuffer: Fix use of uninitialized variable
+    - drm/mipi-dsi: Fix detach call without attach
+    - media: stk1160: Fixed high volume of stk1160_dbg messages
+    - media: rockchip: rga: fix swizzling for RGB formats
+    - PCI: add INTEL_HDA_ARL to pci_ids.h
+    - ALSA: hda: Intel: add HDA_ARL PCI ID support
+    - drm/exynos: Call drm_atomic_helper_shutdown() at shutdown/unbind time
+    - IB/ipoib: Fix mcast list locking
+    - media: ddbridge: fix an error code problem in ddb_probe
+    - drm/msm/dpu: Ratelimit framedone timeout msgs
+    - clk: hi3620: Fix memory leak in hi3620_mmc_clk_init()
+    - clk: mmp: pxa168: Fix memory leak in pxa168_clk_init()
+    - drm/amdgpu: Let KFD sync with VM fences
+    - drm/amdgpu: Drop 'fence' check in 'to_amdgpu_amdkfd_fence()'
+    - leds: trigger: panic: Don't register panic notifier if creating the trigger
+      failed
+    - um: Fix naming clash between UML and scheduler
+    - um: Don't use vfprintf() for os_info()
+    - um: net: Fix return type of uml_net_start_xmit()
+    - i3c: master: cdns: Update maximum prescaler value for i2c clock
+    - mfd: ti_am335x_tscadc: Fix TI SoC dependencies
+    - [Config] updateconfigs for MFD_TI_AM335X_TSCADC
+    - PCI: Only override AMD USB controller if required
+    - PCI: switchtec: Fix stdev_release() crash after surprise hot remove
+    - usb: hub: Replace hardcoded quirk value with BIT() macro
+    - fs/kernfs/dir: obey S_ISGID
+    - PCI/AER: Decode Requester ID when no error info found
+    - libsubcmd: Fix memory leak in uniq()
+    - virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region
+      of size 10" warnings
+    - blk-mq: fix IO hang from sbitmap wakeup race
+    - ceph: fix deadlock or deadcode of misusing dget()
+    - drm/amdgpu: Release 'adev->pm.fw' before return in
+      'amdgpu_device_need_post()'
+    - perf: Fix the nr_addr_filters fix
+    - wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
+    - scsi: isci: Fix an error code problem in isci_io_request_build()
+    - net: remove unneeded break
+    - ixgbe: Remove non-inclusive language
+    - ixgbe: Refactor returning internal error codes
+    - ixgbe: Refactor overtemp event handling
+    - ixgbe: Fix an error handling path in ixgbe_read_iosf_sb_reg_x550()
+    - ipv6: Ensure natural alignment of const ipv6 loopback and router addresses
+    - llc: call sock_orphan() at release time
+    - netfilter: nf_log: replace BUG_ON by WARN_ON_ONCE when putting logger
+    - netfilter: nft_ct: sanitize layer 3 and 4 protocol number in custom
+      expectations
+    - net: ipv4: fix a memleak in ip_setup_cork
+    - af_unix: fix lockdep positive in sk_diag_dump_icons()
+    - SAUCE: Sync apparmor copy of af_unix.c
+    - net: sysfs: Fix /sys/class/net/<iface> path
+    - HID: apple: Add support for the 2021 Magic Keyboard
+    - HID: apple: Swap the Fn and Left Control keys on Apple keyboards
+    - HID: apple: Add 2021 magic keyboard FN key mapping
+    - bonding: remove print in bond_verify_device_path
+    - dmaengine: fsl-qdma: Fix a memory leak related to the status queue DMA
+    - dmaengine: fsl-qdma: Fix a memory leak related to the queue command DMA
+    - phy: renesas: rcar-gen3-usb2: Fix returning wrong error code
+    - dmaengine: fix is_slave_direction() return false when DMA_DEV_TO_DEV
+    - phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+    - net: stmmac: xgmac: fix handling of DPP safety error for DMA channels
+    - selftests: net: avoid just another constant wait
+    - atm: idt77252: fix a memleak in open_card_ubr0
+    - hwmon: (aspeed-pwm-tacho) mutex for tach reading
+    - hwmon: (coretemp) Fix out-of-bounds memory access
+    - hwmon: (coretemp) Fix bogus core_id to attr name mapping
+    - inet: read sk->sk_family once in inet_recv_error()
+    - rxrpc: Fix response to PING RESPONSE ACKs to a dead call
+    - tipc: Check the bearer type before calling tipc_udp_nl_bearer_add()
+    - ppp_async: limit MRU to 64K
+    - netfilter: nft_compat: reject unused compat flag
+    - netfilter: nft_compat: restrict match/target protocol to u16
+    - netfilter: nft_ct: reject direction for ct id
+    - net/af_iucv: clean up a try_then_request_module()
+    - USB: serial: qcserial: add new usb-id for Dell Wireless DW5826e
+    - USB: serial: option: add Fibocom FM101-GL variant
+    - USB: serial: cp210x: add ID for IMST iM871A-USB
+    - hrtimer: Report offline hrtimer enqueue
+    - Input: atkbd - skip ATKBD_CMD_SETLEDS when skipping ATKBD_CMD_GETID
+    - net: stmmac: xgmac: use #define for string constants
+    - net: stmmac: xgmac: fix a typo of register name in DPP safety handling
+    - btrfs: forbid creating subvol qgroups
+    - btrfs: forbid deleting live subvol qgroup
+    - btrfs: send: return EOPNOTSUPP on unknown flags
+    - of: unittest: add overlay gpio test to catch gpio hog problem
+    - of: unittest: Fix compile in the non-dynamic case
+    - spi: ppc4xx: Drop write-only variable
+    - ASoC: rt5645: Fix deadlock in rt5645_jack_detect_work()
+    - MIPS: Add 'memory' clobber to csum_ipv6_magic() inline assembler
+    - i40e: Fix waiting for queues of all VSIs to be disabled
+    - tracing/trigger: Fix to return error if failed to alloc snapshot
+    - mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+    - HID: wacom: generic: Avoid reporting a serial of '0' to userspace
+    - HID: wacom: Do not register input devices until after hid_hw_start
+    - USB: hub: check for alternate port before enabling A_ALT_HNP_SUPPORT
+    - usb: f_mass_storage: forbid async queue when shutdown happen
+    - i2c: i801: Remove i801_set_block_buffer_mode
+    - i2c: i801: Fix block process call transactions
+    - scsi: Revert "scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock"
+    - firewire: core: correct documentation of fw_csr_string() kernel API
+    - kbuild: Fix changing ELF file type for output of gen_btf for big endian
+    - nfc: nci: free rx_data_reassembly skb on NCI device cleanup
+    - xen-netback: properly sync TX responses
+    - ALSA: hda/realtek: Enable headset mic on Vaio VJFE-ADL
+    - binder: signal epoll threads of self-work
+    - misc: fastrpc: Mark all sessions as invalid in cb_remove
+    - ext4: fix double-free of blocks due to wrong extents moved_len
+    - tracing: Fix wasted memory in saved_cmdlines logic
+    - staging: iio: ad5933: fix type mismatch regression
+    - iio: magnetometer: rm3100: add boundary check for the value read from
+      RM3100_REG_TMRC
+    - ring-buffer: Clean ring_buffer_poll_wait() error return
+    - serial: max310x: set default value when reading clock ready bit
+    - serial: max310x: improve crystal stable clock detection
+    - x86/Kconfig: Transmeta Crusoe is CPU family 5, not 6
+    - x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
+    - mmc: slot-gpio: Allow non-sleeping GPIO ro
+    - ALSA: hda/conexant: Add quirk for SWS JS201D
+    - nilfs2: fix data corruption in dsync block recovery for small block sizes
+    - nilfs2: fix hang in nilfs_lookup_dirty_data_buffers()
+    - nfp: use correct macro for LengthSelect in BAR config
+    - nfp: flower: prevent re-adding mac index for bonded port
+    - irqchip/irq-brcmstb-l2: Add write memory barrier before exit
+    - can: j1939: Fix UAF in j1939_sk_match_filter during
+      setsockopt(SO_J1939_FILTER)
+    - pmdomain: core: Move the unused cleanup to a _sync initcall
+    - tracing: Inform kmemleak of saved_cmdlines allocation
+    - Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d"
+    - bus: moxtet: Add spi device table
+    - arch, mm: remove stale mentions of DISCONIGMEM
+    - mips: Fix max_mapnr being uninitialized on early stages
+    - KVM: arm64: vgic-its: Avoid potential UAF in LPI translation cache
+    - netfilter: ipset: fix performance regression in swap operation
+    - netfilter: ipset: Missing gc cancellations fixed
+    - net: prevent mss overflow in skb_segment()
+    - sched/membarrier: reduce the ability to hammer on sys_membarrier
+    - nilfs2: fix potential bug in end_buffer_async_write
+    - PM: runtime: add devm_pm_runtime_enable helper
+    - PM: runtime: Have devm_pm_runtime_enable() handle
+      pm_runtime_dont_use_autosuspend()
+    - drm/msm/dsi: Enable runtime PM
+    - lsm: new security_file_ioctl_compat() hook
+    - Revert "Revert "mtd: rawnand: gpmi: Fix setting busy timeout setting""
+    - net: bcmgenet: Fix EEE implementation
+    - of: unittest: fix EXPECT text for gpio hog errors
+    - of: gpio unittest kfree() wrong object
+    - Linux 5.4.269
+
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948) //
+    CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+
+  * CVE-2023-52600
+    - jfs: fix uaf in jfs_evict_inode
+
+  * CVE-2023-24023
+    - Bluetooth: Add more enc key size check
+
+  * CVE-2024-26581
+    - netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
+    - netfilter: nft_set_rbtree: skip end interval element from gc
+
+  * CVE-2024-26589
+    - bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Thu, 28 Mar 2024 15:36:38 +0100
+
+linux (5.4.0-176.196) focal; urgency=medium
+
+  * focal/linux: 5.4.0-176.196 -proposed tracker (LP: #2058756)
+
+  * Problems with HVCS and hotplugging (LP: #2056373)
+    - powerpc/pseries: Fix bad drc_index_start value parsing of drc-info entry
+    - powerpc/pseries: Fix of_read_drc_info_cell() to point at next record
+    - hvcs: Fix hvcs port reference counting
+    - hvcs: Use dev_groups to manage hvcs device attributes
+    - hvcs: Use driver groups to manage driver attributes
+    - hvcs: Get reference to tty in remove
+    - hvcs: Use vhangup in hotplug remove
+    - hvcs: Synchronize hotplug remove with port free
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Fri, 22 Mar 2024 17:05:57 +0100
+
+linux (5.4.0-175.195) focal; urgency=medium
+
+  * focal/linux: 5.4.0-175.195 -proposed tracker (LP: #2055684)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+    - [Packaging] update annotations scripts
+    - debian.master/dkms-versions -- update from kernel-versions (main/2024.03.04)
+
+  * 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
+
+  * Cranky update-dkms-versions rollout (LP: #2055685)
+    - [Packaging] remove update-dkms-versions
+    - Move debian/dkms-versions to debian.master/dkms-versions
+    - [Packaging] Replace debian/dkms-versions with $(DEBIAN)/dkms-versions
+    - [Packaging] remove update-version-dkms
+
+  * linux-tools-common: man page of usbip[d] is misplaced (LP: #2054094)
+    - [Packaging] rules: Put usbip manpages in the correct directory
+
+  * CVE-2024-23851
+    - dm ioctl: log an error if the ioctl structure is corrupted
+    - dm: limit the number of targets and parameter size area
+
+  * Focal update: v5.4.268 upstream stable release (LP: #2055075)
+    - f2fs: explicitly null-terminate the xattr list
+    - pinctrl: lochnagar: Don't build on MIPS
+    - ALSA: hda - Fix speaker and headset mic pin config for CHUWI CoreBook XPro
+    - ASoC: Intel: Skylake: Fix mem leak in few functions
+    - ASoC: nau8822: Fix incorrect type in assignment and cast to restricted
+      __be16
+    - ASoC: Intel: Skylake: mem leak in skl register function
+    - ASoC: cs43130: Fix the position of const qualifier
+    - ASoC: cs43130: Fix incorrect frame delay configuration
+    - ASoC: rt5650: add mutex to avoid the jack detection failure
+    - nouveau/tu102: flush all pdbs on vmm flush
+    - net/tg3: fix race condition in tg3_reset_task()
+    - ASoC: da7219: Support low DC impedance headset
+    - nvme: introduce helper function to get ctrl state
+    - drm/exynos: fix a potential error pointer dereference
+    - drm/exynos: fix a wrong error checking
+    - clk: rockchip: rk3128: Fix HCLK_OTG gate register
+    - jbd2: correct the printing of write_flags in jbd2_write_superblock()
+    - drm/crtc: Fix uninit-value bug in drm_mode_setcrtc
+    - neighbour: Don't let neigh_forced_gc() disable preemption for long
+    - tracing: Have large events show up as '[LINE TOO BIG]' instead of nothing
+    - tracing: Add size check when printing trace_marker output
+    - ring-buffer: Do not record in NMI if the arch does not support cmpxchg in
+      NMI
+    - reset: hisilicon: hi6220: fix Wvoid-pointer-to-enum-cast warning
+    - Input: atkbd - skip ATKBD_CMD_GETID in translated mode
+    - Input: i8042 - add nomux quirk for Acer P459-G2-M
+    - s390/scm: fix virtual vs physical address confusion
+    - ARC: fix spare error
+    - Input: xpad - add Razer Wolverine V2 support
+    - ARM: sun9i: smp: fix return code check of of_property_match_string
+    - drm/crtc: fix uninitialized variable use
+    - ACPI: resource: Add another DMI match for the TongFang GMxXGxx
+    - binder: use EPOLLERR from eventpoll.h
+    - binder: fix trivial typo of binder_free_buf_locked()
+    - binder: fix comment on binder_alloc_new_buf() return value
+    - uio: Fix use-after-free in uio_open
+    - parport: parport_serial: Add Brainboxes BAR details
+    - parport: parport_serial: Add Brainboxes device IDs and geometry
+    - coresight: etm4x: Fix width of CCITMIN field
+    - x86/lib: Fix overflow when counting digits
+    - EDAC/thunderx: Fix possible out-of-bounds string access
+    - powerpc: add crtsavres.o to always-y instead of extra-y
+    - powerpc/44x: select I2C for CURRITUCK
+    - powerpc/pseries/memhotplug: Quieten some DLPAR operations
+    - powerpc/pseries/memhp: Fix access beyond end of drmem array
+    - selftests/powerpc: Fix error handling in FPU/VMX preemption tests
+    - powerpc/powernv: Add a null pointer check to scom_debug_init_one()
+    - powerpc/powernv: Add a null pointer check in opal_event_init()
+    - powerpc/powernv: Add a null pointer check in opal_powercap_init()
+    - powerpc/imc-pmu: Add a null pointer check in update_events_in_group()
+    - mtd: rawnand: Increment IFC_TIMEOUT_MSECS for nand controller response
+    - ACPI: video: check for error while searching for backlight device parent
+    - ACPI: LPIT: Avoid u32 multiplication overflow
+    - net: netlabel: Fix kerneldoc warnings
+    - netlabel: remove unused parameter in netlbl_netlink_auditinfo()
+    - calipso: fix memory leak in netlbl_calipso_add_pass()
+    - spi: sh-msiof: Enforce fixed DTDL for R-Car H3
+    - mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+    - selinux: Fix error priority for bind with AF_UNSPEC on PF_INET6 socket
+    - crypto: virtio - Handle dataq logic with tasklet
+    - crypto: virtio - don't use 'default m'
+    - virtio_crypto: Introduce VIRTIO_CRYPTO_NOSPC
+    - crypto: ccp - fix memleak in ccp_init_dm_workarea
+    - crypto: af_alg - Disallow multiple in-flight AIO requests
+    - crypto: sahara - remove FLAGS_NEW_KEY logic
+    - crypto: sahara - fix ahash selftest failure
+    - crypto: sahara - fix processing requests with cryptlen < sg->length
+    - crypto: sahara - fix error handling in sahara_hw_descriptor_create()
+    - pstore: ram_core: fix possible overflow in persistent_ram_init_ecc()
+    - gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
+    - crypto: virtio - Wait for tasklet to complete on device remove
+    - crypto: sahara - fix ahash reqsize
+    - crypto: sahara - fix wait_for_completion_timeout() error handling
+    - crypto: sahara - improve error handling in sahara_sha_process()
+    - crypto: sahara - fix processing hash requests with req->nbytes < sg->length
+    - crypto: sahara - do not resize req->src when doing hash operations
+    - crypto: scomp - fix req->dst buffer overflow
+    - blocklayoutdriver: Fix reference leak of pnfs_device_node
+    - NFSv4.1/pnfs: Ensure we handle the error NFS4ERR_RETURNCONFLICT
+    - wifi: rtw88: fix RX filter in FIF_ALLMULTI flag
+    - bpf, lpm: Fix check prefixlen before walking trie
+    - wifi: libertas: stop selecting wext
+    - ARM: dts: qcom: apq8064: correct XOADC register address
+    - ncsi: internal.h: Fix a spello
+    - net/ncsi: Fix netlink major/minor version numbers
+    - firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create()
+    - rtlwifi: Use ffs in <foo>_phy_calculate_bit_shift
+    - wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior
+    - scsi: fnic: Return error if vmalloc() failed
+    - arm64: dts: qcom: sdm845-db845c: correct LED panic indicator
+    - scsi: hisi_sas: Replace with standard error code return value
+    - selftests/net: fix grep checking for fib_nexthop_multiprefix
+    - virtio/vsock: fix logic which reduces credit update messages
+    - dma-mapping: clear dev->dma_mem to NULL after freeing it
+    - wifi: rtlwifi: add calculate_bit_shift()
+    - wifi: rtlwifi: rtl8188ee: phy: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192c: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192cu: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ce: using calculate_bit_shift()
+    - rtlwifi: rtl8192de: make arrays static const, makes object smaller
+    - wifi: rtlwifi: rtl8192de: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ee: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192se: using calculate_bit_shift()
+    - netfilter: nf_tables: mark newset as dead on transaction abort
+    - Bluetooth: Fix bogus check for re-auth no supported with non-ssp
+    - Bluetooth: btmtkuart: fix recv_buf() return value
+    - ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+    - ARM: davinci: always select CONFIG_CPU_ARM926T
+    - RDMA/usnic: Silence uninitialized symbol smatch warnings
+    - media: pvrusb2: fix use after free on context disconnection
+    - drm/bridge: Fix typo in post_disable() description
+    - f2fs: fix to avoid dirent corruption
+    - drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg()
+    - drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check()
+    - drm/radeon: check return value of radeon_ring_lock()
+    - ASoC: cs35l33: Fix GPIO name and drop legacy include
+    - ASoC: cs35l34: Fix GPIO name and drop legacy include
+    - drm/msm/mdp4: flush vblank event on disable
+    - drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks
+    - drm/drv: propagate errors from drm_modeset_register_all()
+    - drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+    - drm/radeon/dpm: fix a memleak in sumo_parse_power_table
+    - drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table
+    - drm/bridge: tc358767: Fix return value on error case
+    - media: cx231xx: fix a memleak in cx231xx_init_isoc
+    - media: dvbdev: drop refcount on error path in dvb_device_open()
+    - drm/amdgpu/debugfs: fix error code when smc register accessors are NULL
+    - drm/amd/pm: fix a double-free in si_dpm_init
+    - drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+    - gpu/drm/radeon: fix two memleaks in radeon_vm_init
+    - drivers: clk: zynqmp: calculate closest mux rate
+    - watchdog: set cdev owner before adding
+    - watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO
+    - watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling
+    - clk: si5341: fix an error code problem in si5341_output_clk_set_rate
+    - mmc: sdhci_omap: Fix TI SoC dependencies
+    - [Config] update annotations for CONFIG_MMC_SDHCI_OMAP
+    - [Config] remove sdhci-omap module for arm64/ppc64el
+    - of: Fix double free in of_parse_phandle_with_args_map
+    - of: unittest: Fix of_count_phandle_with_args() expected value message
+    - binder: fix async space check for 0-sized buffers
+    - binder: fix use-after-free in shinker's callback
+    - Input: atkbd - use ab83 as id when skipping the getid command
+    - Revert "ASoC: atmel: Remove system clock tree configuration for
+      at91sam9g20ek"
+    - binder: fix race between mmput() and do_exit()
+    - binder: fix unused alloc->free_async_space
+    - tick-sched: Fix idle and iowait sleeptime accounting vs CPU hotplug
+    - usb: phy: mxs: remove CONFIG_USB_OTG condition for mxs_phy_is_otg_host()
+    - usb: dwc: ep0: Update request status in dwc3_ep0_stall_restart
+    - Revert "usb: dwc3: Soft reset phy on probe for host"
+    - Revert "usb: dwc3: don't reset device side if dwc3 was configured as host-
+      only"
+    - usb: chipidea: wait controller resume finished for wakeup irq
+    - Revert "usb: typec: class: fix typec_altmode_put_partner to put plugs"
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - usb: mon: Fix atomicity violation in mon_bin_vma_fault
+    - ALSA: oxygen: Fix right channel of capture volume mixer
+    - fbdev: flush deferred work in fb_deferred_io_fsync()
+    - rootfs: Fix support for rootfstype= when root= is given
+    - wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code
+    - wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors
+    - wifi: mwifiex: configure BSSID consistently when starting AP
+    - x86/kvm: Do not try to disable kvmclock if it was not enabled
+    - HID: wacom: Correct behavior when processing some confidence == false
+      touches
+    - mips: Fix incorrect max_low_pfn adjustment
+    - MIPS: Alchemy: Fix an out-of-bound access in db1200_dev_setup()
+    - MIPS: Alchemy: Fix an out-of-bound access in db1550_dev_setup()
+    - serial: 8250: omap: Don't skip resource freeing if
+      pm_runtime_resume_and_get() failed
+    - acpi: property: Let args be NULL in __acpi_node_get_property_reference
+    - software node: Let args be NULL in software_node_get_reference_args
+    - perf genelf: Set ELF program header addresses properly
+    - nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length
+    - nvmet-tcp: fix a crash in nvmet_req_complete()
+    - perf env: Add perf_env__numa_node()
+    - perf record: Move sb_evlist to 'struct record'
+    - perf top: Move sb_evlist to 'struct perf_top'
+    - perf bpf: Decouple creating the evlist from adding the SB event
+    - perf env: Avoid recursively taking env->bpf_progs.lock
+    - apparmor: avoid crash when parsed profile name is empty
+    - serial: imx: Correct clock error message in function probe()
+    - nvmet-tcp: Fix the H2C expected PDU len calculation
+    - PCI: keystone: Fix race condition when initializing PHYs
+    - s390/pci: fix max size calculation in zpci_memcpy_toio()
+    - net: qualcomm: rmnet: fix global oob in rmnet_policy
+    - net: phy: micrel: populate .soft_reset for KSZ9131
+    - net: ravb: Fix dma_addr_t truncation in error case
+    - net: dsa: vsc73xx: Add null pointer check to vsc73xx_gpio_probe
+    - netfilter: nf_tables: skip dead set elements in netlink dump
+    - ipvs: avoid stat macros calls from preemptible context
+    - kdb: Censor attempts to set PROMPT without ENABLE_MEM_READ
+    - kdb: Fix a potential buffer overflow in kdb_local()
+    - mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure
+    - i2c: s3c24xx: fix read transfers in polling mode
+    - i2c: s3c24xx: fix transferring more than one message in polling mode
+    - perf top: Skip side-band event setup if HAVE_LIBBPF_SUPPORT is not set
+    - arm64: dts: armada-3720-turris-mox: set irq type for RTC
+    - Linux 5.4.268
+
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+
+  * Focal update: v5.4.267 upstream stable release (LP: #2054406)
+    - nfc: llcp_core: Hold a ref to llcp_local->dev when holding a ref to
+      llcp_local
+    - i40e: Fix filter input checks to prevent config with invalid values
+    - net: sched: em_text: fix possible memory leak in em_text_destroy()
+    - can: raw: add support for SO_TXTIME/SCM_TXTIME
+    - can: raw: add support for SO_MARK
+    - net-timestamp: extend SOF_TIMESTAMPING_OPT_ID to HW timestamps
+    - ARM: sun9i: smp: Fix array-index-out-of-bounds read in sunxi_mc_smp_init
+    - net: bcmgenet: Fix FCS generation for fragmented skbuffs
+    - net: Save and restore msg_namelen in sock_sendmsg
+    - i40e: fix use-after-free in i40e_aqc_add_filters()
+    - ASoC: meson: g12a: extract codec-to-codec utils
+    - [Config] Update annotations for CONFIG_SND_MESON_CODEC_GLUE
+    - ASoC: meson: g12a-tohdmitx: Validate written enum values
+    - ASoC: meson: g12a-tohdmitx: Fix event generation for S/PDIF mux
+    - i40e: Restore VF MSI-X state during PCI reset
+    - net/qla3xxx: switch from 'pci_' to 'dma_' API
+    - net/qla3xxx: fix potential memleak in ql_alloc_buffer_queues
+    - asix: Add check for usbnet_get_endpoints
+    - bnxt_en: Remove mis-applied code from bnxt_cfg_ntp_filters()
+    - net: Implement missing SO_TIMESTAMPING_NEW cmsg support
+    - mm/memory-failure: check the mapcount of the precise page
+    - firewire: ohci: suppress unexpected system reboot in AMD Ryzen machines and
+      ASM108x/VT630x PCIe cards
+    - i2c: core: Fix atomic xfer check for non-preempt config
+    - mm: fix unmap_mapping_range high bits shift bug
+    - mmc: rpmb: fixes pause retune on all RPMB partitions.
+    - mmc: core: Cancel delayed work before releasing host
+    - mmc: sdhci-sprd: Fix eMMC init failure after hw reset
+    - ath10k: Wait until copy complete is actually done before completing
+    - ath10k: Add interrupt summary based CE processing
+    - ath10k: Keep track of which interrupts fired, don't poll them
+    - ath10k: Get rid of "per_ce_irq" hw param
+    - PCI: Extract ATS disabling to a helper function
+    - PCI: Disable ATS for specific Intel IPU E2000 devices
+    - net/dst: use a smaller percpu_counter batch for dst entries accounting
+    - ipv6: make ip6_rt_gc_expire an atomic_t
+    - ipv6: remove max_size check inline with ipv4
+    - ASoC: meson: codec-glue: fix pcm format cast warning
+    - Linux 5.4.267
+
+  * CVE-2023-23000
+    - phy: tegra: xusb: Fix return value of tegra_xusb_find_port_node function
+
+  * CVE-2023-23004
+    - malidp: Fix NULL vs IS_ERR() checking
+
+  * CVE-2023-46838
+    - xen-netback: don't produce zero-size SKB frags
+
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+
+  * Focal update: v5.4.266 upstream stable release (LP: #2051655)
+    - ALSA: hda/realtek: Enable headset on Lenovo M90 Gen5
+    - ksmbd: fix wrong name of SMB2_CREATE_ALLOCATION_SIZE
+    - ARM: OMAP2+: Fix null pointer dereference and memory leak in
+      omap_soc_device_init
+    - reset: Fix crash when freeing non-existent optional resets
+    - s390/vx: fix save/restore of fpu kernel context
+    - wifi: mac80211: mesh_plink: fix matches_local logic
+    - net/mlx5: improve some comments
+    - net/mlx5: Fix fw tracer first block check
+    - net/mlx5e: Correct snprintf truncation handling for fw_version buffer used
+      by representors
+    - net: sched: ife: fix potential use-after-free
+    - ethernet: atheros: fix a memleak in atl1e_setup_ring_resources
+    - net/rose: fix races in rose_kill_by_device()
+    - net: check vlan filter feature in vlan_vids_add_by_dev() and
+      vlan_vids_del_by_dev()
+    - afs: Fix the dynamic root's d_delete to always delete unused dentries
+    - afs: Fix dynamic root lookup DNS check
+    - net: warn if gso_type isn't set for a GSO SKB
+    - net: check dev->gso_max_size in gso_features_check()
+    - afs: Fix overwriting of result of DNS query
+    - i2c: aspeed: Handle the coalesced stop conditions with the start conditions.
+    - pinctrl: at91-pio4: use dedicated lock class for IRQ
+    - ALSA: hda/hdmi: Add quirk to force pin connectivity on NUC10
+    - ALSA: hda/hdmi: add force-connect quirk for NUC5CPYB
+    - smb: client: fix NULL deref in asn1_ber_decoder()
+    - btrfs: do not allow non subvolume root targets for snapshot
+    - interconnect: Treat xlate() returning NULL node as an error
+    - iio: imu: inv_mpu6050: fix an error code problem in inv_mpu6050_read_raw
+    - Input: ipaq-micro-keys - add error handling for devm_kmemdup
+    - scsi: bnx2fc: Fix skb double free in bnx2fc_rcv()
+    - iio: common: ms_sensors: ms_sensors_i2c: fix humidity conversion time table
+    - iio: adc: ti_am335x_adc: Fix return value check of tiadc_request_dma()
+    - wifi: cfg80211: Add my certificate
+    - wifi: cfg80211: fix certs build to not depend on file order
+    - USB: serial: ftdi_sio: update Actisense PIDs constant names
+    - USB: serial: option: add Quectel EG912Y module support
+    - USB: serial: option: add Foxconn T99W265 with new baseline
+    - USB: serial: option: add Quectel RM500Q R13 firmware support
+    - Bluetooth: hci_event: Fix not checking if HCI_OP_INQUIRY has been sent
+    - net: 9p: avoid freeing uninit memory in p9pdu_vreadf
+    - net: rfkill: gpio: set GPIO direction
+    - x86/alternatives: Sync core before enabling interrupts
+    - usb: fotg210-hcd: delete an incorrect bounds test
+    - ring-buffer: Fix wake ups when buffer_percent is set to 100
+    - block: Don't invalidate pagecache for invalid falloc modes
+    - Linux 5.4.266
+
+  * CVE-2024-0607
+    - netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Thu, 07 Mar 2024 17:43:37 +0100
+
+linux (5.4.0-173.191) focal; urgency=medium
+
+  * focal/linux: 5.4.0-173.191 -proposed tracker (LP: #2052135)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2024.02.05)
+
+  * CVE-2023-0340
+    - vhost: use kzalloc() instead of kmalloc() followed by memset()
+
+  * CVE-2023-6915
+    - ida: Fix crash in ida_free when the bitmap is empty
+
+  * Focal update: v5.4.265 upstream stable release (LP: #2051644)
+    - afs: Fix refcount underflow from error handling race
+    - net: ipv6: support reporting otherwise unknown prefix flags in RTM_NEWPREFIX
+    - qca_debug: Prevent crash on TX ring changes
+    - qca_debug: Fix ethtool -G iface tx behavior
+    - qca_spi: Fix reset behavior
+    - atm: solos-pci: Fix potential deadlock on &cli_queue_lock
+    - atm: solos-pci: Fix potential deadlock on &tx_queue_lock
+    - atm: Fix Use-After-Free in do_vcc_ioctl
+    - qed: Fix a potential use-after-free in qed_cxt_tables_alloc
+    - net: Remove acked SYN flag from packet in the transmit queue correctly
+    - sign-file: Fix incorrect return values check
+    - vsock/virtio: Fix unsigned integer wrap around in
+      virtio_transport_has_space()
+    - net: stmmac: use dev_err_probe() for reporting mdio bus registration failure
+    - net: stmmac: Handle disabled MDIO busses from devicetree
+    - cred: switch to using atomic_long_t
+    - ALSA: hda/hdmi: add force-connect quirks for ASUSTeK Z170 variants
+    - usb: aqc111: check packet for fixup for true limit
+    - blk-throttle: fix lockdep warning of "cgroup_mutex or RCU read lock
+      required!"
+    - bcache: avoid oversize memory allocation by small stripe_size
+    - bcache: add code comments for bch_btree_node_get() and
+      __bch_btree_node_alloc()
+    - bcache: avoid NULL checking to c->root in run_cache_set()
+    - platform/x86: intel_telemetry: Fix kernel doc descriptions
+    - HID: add ALWAYS_POLL quirk for Apple kb
+    - HID: hid-asus: reset the backlight brightness level on resume
+    - HID: multitouch: Add quirk for HONOR GLO-GXXX touchpad
+    - asm-generic: qspinlock: fix queued_spin_value_unlocked() implementation
+    - net: usb: qmi_wwan: claim interface 4 for ZTE MF290
+    - HID: hid-asus: add const to read-only outgoing usb buffer
+    - soundwire: stream: fix NULL pointer dereference for multi_link
+    - ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS
+    - arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify
+    - team: Fix use-after-free when an option instance allocation fails
+    - ring-buffer: Fix memory leak of free page
+    - mmc: block: Be sure to wait while busy in CQE error recovery
+    - powerpc/ftrace: Create a dummy stackframe to fix stack unwind
+    - powerpc/ftrace: Fix stack teardown in ftrace_no_trace
+    - Linux 5.4.265
+
+  * Focal update: v5.4.264 upstream stable release (LP: #2049935)
+    - hrtimers: Push pending hrtimers away from outgoing CPU earlier
+    - netfilter: ipset: fix race condition between swap/destroy and kernel side
+      add/del/test
+    - tg3: Move the [rt]x_dropped counters to tg3_napi
+    - tg3: Increment tx_dropped in tg3_tso_bug()
+    - kconfig: fix memory leak from range properties
+    - drm/amdgpu: correct chunk_ptr to a pointer to chunk.
+    - of: base: Add of_get_cpu_state_node() to get idle states for a CPU node
+    - ACPI/IORT: Make iort_get_device_domain IRQ domain agnostic
+    - ACPI/IORT: Make iort_msi_map_rid() PCI agnostic
+    - of/iommu: Make of_map_rid() PCI agnostic
+    - of/irq: make of_msi_map_get_device_domain() bus agnostic
+    - of/irq: Make of_msi_map_rid() PCI bus agnostic
+    - of: base: Fix some formatting issues and provide missing descriptions
+    - of: Fix kerneldoc output formatting
+    - of: Add missing 'Return' section in kerneldoc comments
+    - of: dynamic: Fix of_reconfig_get_state_change() return value documentation
+    - ipv6: fix potential NULL deref in fib6_add()
+    - hv_netvsc: rndis_filter needs to select NLS
+    - net: arcnet: Fix RESET flag handling
+    - net: arcnet: com20020 fix error handling
+    - arcnet: restoring support for multiple Sohard Arcnet cards
+    - ipv4: ip_gre: Avoid skb_pull() failure in ipgre_xmit()
+    - net: hns: fix fake link up on xge port
+    - netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
+    - tcp: do not accept ACK of bytes we never sent
+    - bpf: sockmap, updating the sg structure should also update curr
+    - RDMA/bnxt_re: Correct module description string
+    - hwmon: (acpi_power_meter) Fix 4.29 MW bug
+    - ASoC: wm_adsp: fix memleak in wm_adsp_buffer_populate
+    - tracing: Fix a warning when allocating buffered events fails
+    - scsi: be2iscsi: Fix a memleak in beiscsi_init_wrb_handle()
+    - ARM: imx: Check return value of devm_kasprintf in imx_mmdc_perf_init
+    - ARM: dts: imx: make gpt node name generic
+    - ARM: dts: imx7: Declare timers compatible with fsl,imx6dl-gpt
+    - ALSA: pcm: fix out-of-bounds in snd_pcm_state_names
+    - nilfs2: prevent WARNING in nilfs_sufile_set_segment_usage()
+    - tracing: Always update snapshot buffer size
+    - tracing: Fix incomplete locking when disabling buffered events
+    - tracing: Fix a possible race when disabling buffered events
+    - packet: Move reference count in packet_sock to atomic_long_t
+    - arm64: dts: mediatek: mt7622: fix memory node warning check
+    - arm64: dts: mediatek: mt8173-evb: Fix regulator-fixed node names
+    - gpiolib: sysfs: Fix error handling on failed export
+    - mmc: core: add helpers mmc_regulator_enable/disable_vqmmc
+    - mmc: sdhci-sprd: Fix vqmmc not shutting down after the card was pulled
+    - usb: gadget: f_hid: fix report descriptor allocation
+    - parport: Add support for Brainboxes IX/UC/PX parallel cards
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - ARM: PL011: Fix DMA support
+    - serial: sc16is7xx: address RX timeout interrupt errata
+    - serial: 8250_omap: Add earlycon support for the AM654 UART controller
+    - x86/CPU/AMD: Check vendor in the AMD microcode callback
+    - KVM: s390/mm: Properly reset no-dat
+    - nilfs2: fix missing error check for sb_set_blocksize call
+    - io_uring/af_unix: disable sending io_uring over sockets
+    - netlink: don't call ->netlink_bind with table lock held
+    - genetlink: add CAP_NET_ADMIN test for multicast bind
+    - psample: Require 'CAP_NET_ADMIN' when joining "packets" group
+    - drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group
+    - tools headers UAPI: Sync linux/perf_event.h with the kernel sources
+    - cifs: Fix non-availability of dedup breaking generic/304
+    - smb: client: fix potential NULL deref in parse_dfs_referrals()
+    - devcoredump : Serialize devcd_del work
+    - devcoredump: Send uevent once devcd is ready
+    - Linux 5.4.264
+
+  * CVE-2024-0646
+    - net: tls, update curr on splice as well
+
+  * CVE-2024-0565
+    - smb: client: fix OOB in receive_encrypted_standard()
+
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+
+  * CVE-2023-51782
+    - net/rose: Fix Use-After-Free in rose_ioctl
+
+  * Focal update: v5.4.263 upstream stable release (LP: #2049084)
+    - driver core: Release all resources during unbind before updating device
+      links
+    - RDMA/irdma: Prevent zero-length STAG registration
+    - PCI: keystone: Drop __init from ks_pcie_add_pcie_{ep,port}()
+    - afs: Make error on cell lookup failure consistent with OpenAFS
+    - drm/panel: simple: Fix Innolux G101ICE-L01 bus flags
+    - drm/panel: simple: Fix Innolux G101ICE-L01 timings
+    - ata: pata_isapnp: Add missing error check for devm_ioport_map()
+    - drm/rockchip: vop: Fix color for RGB888/BGR888 format on VOP full
+    - HID: core: store the unique system identifier in hid_device
+    - HID: fix HID device resource race between HID core and debugging support
+    - ipv4: Correct/silence an endian warning in __ip_do_redirect
+    - net: usb: ax88179_178a: fix failed operations during ax88179_reset
+    - arm/xen: fix xen_vcpu_info allocation alignment
+    - amd-xgbe: handle corner-case during sfp hotplug
+    - amd-xgbe: handle the corner-case during tx completion
+    - amd-xgbe: propagate the correct speed and duplex status
+    - net: axienet: Fix check for partial TX checksum
+    - afs: Return ENOENT if no cell DNS record can be found
+    - afs: Fix file locking on R/O volumes to operate in local mode
+    - nvmet: remove unnecessary ctrl parameter
+    - nvmet: nul-terminate the NQNs passed in the connect command
+    - MIPS: KVM: Fix a build warning about variable set but not used
+    - ext4: add a new helper to check if es must be kept
+    - ext4: factor out __es_alloc_extent() and __es_free_extent()
+    - ext4: use pre-allocated es in __es_insert_extent()
+    - ext4: use pre-allocated es in __es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_insert_delayed_block()
+    - ext4: using nofail preallocation in ext4_es_insert_extent()
+    - ext4: fix slab-use-after-free in ext4_es_insert_extent()
+    - ext4: make sure allocate pending entry not fail
+    - arm64: cpufeature: Extract capped perfmon fields
+    - KVM: arm64: limit PMU version to PMUv3 for ARMv8.1
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA
+    - bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in
+      btree_gc_coalesce()
+    - s390/dasd: protect device queue against concurrent access
+    - USB: serial: option: add Luat Air72*U series products
+    - hv_netvsc: Fix race of register_netdevice_notifier and VF register
+    - hv_netvsc: Mark VF as slave before exposing it to user-mode
+    - dm-delay: fix a race between delay_presuspend and delay_bio
+    - bcache: check return value from btree_node_alloc_replacement()
+    - bcache: prevent potential division by zero error
+    - USB: serial: option: add Fibocom L7xx modules
+    - USB: serial: option: fix FM101R-GL defines
+    - USB: serial: option: don't claim interface 4 for ZTE MF290
+    - USB: dwc2: write HCINT with INTMASK applied
+    - usb: dwc3: set the dma max_seg_size
+    - USB: dwc3: qcom: fix resource leaks on probe deferral
+    - USB: dwc3: qcom: fix wakeup after probe deferral
+    - io_uring: fix off-by one bvec index
+    - pinctrl: avoid reload of p state in list iteration
+    - firewire: core: fix possible memory leak in create_units()
+    - mmc: block: Do not lose cache flush during CQE error recovery
+    - ALSA: hda: Disable power-save on KONTRON SinglePC
+    - ALSA: hda/realtek: Headset Mic VREF to 100%
+    - ALSA: hda/realtek: Add supported ALC257 for ChromeOS
+    - dm-verity: align struct dm_verity_fec_io properly
+    - dm verity: don't perform FEC for failed readahead IO
+    - bcache: revert replacing IS_ERR_OR_NULL with IS_ERR
+    - powerpc: Don't clobber f0/vs0 during fp|altivec register save
+    - btrfs: fix off-by-one when checking chunk map includes logical address
+    - btrfs: send: ensure send_fd is writable
+    - btrfs: make error messages more clear when getting a chunk map
+    - Input: xpad - add HyperX Clutch Gladiate Support
+    - net: stmmac: xgmac: Disable FPE MMC interrupts
+    - ravb: Fix races between ravb_tx_timeout_work() and net related ops
+    - net: ravb: Use pm_runtime_resume_and_get()
+    - net: ravb: Start TX queues after HW initialization succeeded
+    - smb3: fix touch -h of symlink
+    - s390/mm: fix phys vs virt confusion in mark_kernel_pXd() functions family
+    - s390/cmma: fix detection of DAT pages
+    - mtd: cfi_cmdset_0001: Support the absence of protection registers
+    - mtd: cfi_cmdset_0001: Byte swap OTP info
+    - fbdev: stifb: Make the STI next font pointer a 32-bit signed offset
+    - ima: annotate iint mutex to avoid lockdep false positive warnings
+    - ovl: skip overlayfs superblocks at global sync
+    - ima: detect changes to the backing overlay file
+    - scsi: qla2xxx: Simplify the code for aborting SCSI commands
+    - scsi: core: Introduce the scsi_cmd_to_rq() function
+    - scsi: qla2xxx: Use scsi_cmd_to_rq() instead of scsi_cmnd.request
+    - scsi: qla2xxx: Fix system crash due to bad pointer access
+    - cpufreq: imx6q: don't warn for disabling a non-existing frequency
+    - cpufreq: imx6q: Don't disable 792 Mhz OPP unnecessarily
+    - mmc: cqhci: Increase recovery halt timeout
+    - mmc: cqhci: Warn of halt or task clear failure
+    - mmc: cqhci: Fix task clearing in CQE error recovery
+    - mmc: core: convert comma to semicolon
+    - mmc: block: Retry commands in CQE error recovery
+    - Linux 5.4.263
+
+  * Focal update: v5.4.262 upstream stable release (LP: #2049069)
+    - locking/ww_mutex/test: Fix potential workqueue corruption
+    - perf/core: Bail out early if the request AUX area is out of bound
+    - clocksource/drivers/timer-imx-gpt: Fix potential memory leak
+    - clocksource/drivers/timer-atmel-tcb: Fix initialization on SAM9 hardware
+    - x86/mm: Drop the 4 MB restriction on minimal NUMA node memory size
+    - wifi: mac80211_hwsim: fix clang-specific fortify warning
+    - wifi: mac80211: don't return unset power in ieee80211_get_tx_power()
+    - wifi: ath9k: fix clang-specific fortify warnings
+    - wifi: ath10k: fix clang-specific fortify warning
+    - net: annotate data-races around sk->sk_tx_queue_mapping
+    - net: annotate data-races around sk->sk_dst_pending_confirm
+    - wifi: ath10k: Don't touch the CE interrupt registers after power up
+    - Bluetooth: Fix double free in hci_conn_cleanup
+    - platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e
+    - drm/komeda: drop all currently held locks if deadlock happens
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for Polaris and Tonga
+    - drm/amdgpu: Fix a null pointer access when the smc_rreg pointer is NULL
+    - selftests/efivarfs: create-read: fix a resource leak
+    - crypto: pcrypt - Fix hungtask for PADATA_RESET
+    - RDMA/hfi1: Use FIELD_GET() to extract Link Width
+    - fs/jfs: Add check for negative db_l2nbperpage
+    - fs/jfs: Add validity check for db_maxag and db_agpref
+    - jfs: fix array-index-out-of-bounds in dbFindLeaf
+    - jfs: fix array-index-out-of-bounds in diAlloc
+    - ARM: 9320/1: fix stack depot IRQ stack filter
+    - ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+    - PCI: tegra194: Use FIELD_GET()/FIELD_PREP() with Link Width fields
+    - atm: iphase: Do PCI error checks on own line
+    - scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+    - HID: Add quirk for Dell Pro Wireless Keyboard and Mouse KM5221W
+    - tty: vcc: Add check for kstrdup() in vcc_probe()
+    - usb: gadget: f_ncm: Always set current gadget in ncm_bind()
+    - i2c: sun6i-p2wi: Prevent potential division by zero
+    - media: gspca: cpia1: shift-out-of-bounds in set_flicker
+    - media: vivid: avoid integer overflow
+    - gfs2: ignore negated quota changes
+    - media: cobalt: Use FIELD_GET() to extract Link Width
+    - drm/amd/display: Avoid NULL dereference of timing generator
+    - kgdb: Flush console before entering kgdb on panic
+    - ASoC: ti: omap-mcbsp: Fix runtime PM underflow warnings
+    - pwm: Fix double shift bug
+    - wifi: iwlwifi: Use FW rate for non-data frames
+    - NFSv4.1: fix SP4_MACH_CRED protection for pnfs IO
+    - ipvlan: add ipvlan_route_v6_outbound() helper
+    - tty: Fix uninit-value access in ppp_sync_receive()
+    - net: hns3: fix variable may not initialized problem in hns3_init_mac_addr()
+    - tipc: Fix kernel-infoleak due to uninitialized TLV value
+    - ppp: limit MRU to 64K
+    - xen/events: fix delayed eoi list handling
+    - ptp: annotate data-race around q->head and q->tail
+    - bonding: stop the device in bond_setup_by_slave()
+    - net: ethernet: cortina: Fix max RX frame define
+    - net: ethernet: cortina: Handle large frames
+    - net: ethernet: cortina: Fix MTU max setting
+    - netfilter: nf_conntrack_bridge: initialize err to 0
+    - net: stmmac: Rework stmmac_rx()
+    - net: stmmac: fix rx budget limit check
+    - net/mlx5_core: Clean driver version and name
+    - net/mlx5e: Check return value of snprintf writing to fw_version buffer for
+      representors
+    - macvlan: Don't propagate promisc change to lower dev in passthru
+    - tools/power/turbostat: Fix a knl bug
+    - cifs: spnego: add ';' in HOST_KEY_LEN
+    - media: venus: hfi: add checks to perform sanity on queue pointers
+    - randstruct: Fix gcc-plugin performance mode to stay in group
+    - bpf: Fix precision tracking for BPF_ALU | BPF_TO_BE | BPF_END
+    - scsi: megaraid_sas: Increase register read retry rount from 3 to 30 for
+      selected registers
+    - x86/cpu/hygon: Fix the CPU topology evaluation for real
+    - KVM: x86: hyper-v: Don't auto-enable stimer on write from user-space
+    - KVM: x86: Ignore MSR_AMD64_TW_CFG access
+    - audit: don't take task_lock() in audit_exe_compare() code path
+    - audit: don't WARN_ON_ONCE(!current->mm) in audit_exe_compare()
+    - hvc/xen: fix error path in xen_hvc_init() to always register frontend driver
+    - PCI/sysfs: Protect driver's D3cold preference from user space
+    - ACPI: resource: Do IRQ override on TongFang GMxXGxx
+    - mmc: meson-gx: Remove setting of CMD_CFG_ERROR
+    - genirq/generic_chip: Make irq_remove_generic_chip() irqdomain aware
+    - PCI: keystone: Don't discard .remove() callback
+    - PCI: keystone: Don't discard .probe() callback
+    - parisc/pdc: Add width field to struct pdc_model
+    - clk: qcom: ipq8074: drop the CLK_SET_RATE_PARENT flag from PLL clocks
+    - mmc: vub300: fix an error code
+    - PM: hibernate: Use __get_safe_page() rather than touching the list
+    - PM: hibernate: Clean up sync_read handling in snapshot_write_next()
+    - btrfs: don't arbitrarily slow down delalloc if we're committing
+    - jbd2: fix potential data lost in recovering journal raced with synchronizing
+      fs bdev
+    - quota: explicitly forbid quota files from being encrypted
+    - kernel/reboot: emergency_restart: Set correct system_state
+    - i2c: core: Run atomic i2c xfer when !preemptible
+    - mcb: fix error handling for different scenarios when parsing
+    - dmaengine: stm32-mdma: correct desc prep when channel running
+    - mm/cma: use nth_page() in place of direct struct page manipulation
+    - i3c: master: cdns: Fix reading status register
+    - parisc: Prevent booting 64-bit kernels on PA1.x machines
+    - parisc/pgtable: Do not drop upper 5 address bits of physical address
+    - ALSA: info: Fix potential deadlock at disconnection
+    - ALSA: hda/realtek - Enable internal speaker of ASUS K6500ZC
+    - serial: meson: remove redundant initialization of variable id
+    - tty: serial: meson: retrieve port FIFO size from DT
+    - serial: meson: Use platform_get_irq() to get the interrupt
+    - tty: serial: meson: fix hard LOCKUP on crtscts mode
+    - Bluetooth: btusb: add Realtek 8822CE to usb_device_id table
+    - Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x0cb8:0xc559
+    - bluetooth: Add device 0bda:887b to device tables
+    - bluetooth: Add device 13d3:3571 to device tables
+    - Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables
+    - Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE
+    - Revert ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - net: dsa: lan9303: consequently nested-lock physical MDIO
+    - i2c: i801: fix potential race in i801_block_transaction_byte_by_byte
+    - media: lirc: drop trailing space from scancode transmit
+    - media: sharp: fix sharp encoding
+    - media: venus: hfi_parser: Add check to keep the number of codecs within
+      range
+    - media: venus: hfi: fix the check to handle session buffer requirement
+    - media: venus: hfi: add checks to handle capabilities from firmware
+    - nfsd: fix file memleak on client_opens_release
+    - ext4: apply umask if ACL support is disabled
+    - ext4: correct offset of gdb backup in non meta_bg group to update_backups
+    - ext4: correct return value of ext4_convert_meta_bg
+    - ext4: correct the start block of counting reserved clusters
+    - ext4: remove gdb backup copy for meta bg in setup_new_flex_group_blocks
+    - drm/amdgpu: fix error handling in amdgpu_bo_list_get()
+    - tracing: Have trace_event_file have ref counters
+    - netfilter: nf_tables: pass context to nft_set_destroy()
+    - netfilter: nftables: rename set element data activation/deactivation
+      functions
+    - netfilter: nf_tables: drop map element references from preparation phase
+    - netfilter: nft_set_rbtree: Switch to node list walk for overlap detection
+    - netfilter: nft_set_rbtree: fix null deref on element insertion
+    - netfilter: nft_set_rbtree: fix overlap expiration walk
+    - netfilter: nf_tables: don't skip expired elements during walk
+    - netfilter: nf_tables: GC transaction API to avoid race with control plane
+    - netfilter: nf_tables: adapt set backend to use GC transaction API
+    - netfilter: nft_set_hash: mark set element as dead when deleting from packet
+      path
+    - netfilter: nf_tables: remove busy mark and gc batch API
+    - netfilter: nf_tables: fix GC transaction races with netns and netlink event
+      exit path
+    - netfilter: nf_tables: GC transaction race with netns dismantle
+    - netfilter: nf_tables: GC transaction race with abort path
+    - netfilter: nf_tables: use correct lock to protect gc_list
+    - netfilter: nf_tables: defer gc run if previous batch is still pending
+    - netfilter: nft_set_rbtree: skip sync GC for new elements in this transaction
+    - netfilter: nft_set_rbtree: use read spinlock to avoid datapath contention
+    - netfilter: nft_set_hash: try later when GC hits EAGAIN on iteration
+    - netfilter: nf_tables: fix memleak when more than 255 elements expired
+    - netfilter: nf_tables: unregister flowtable hooks on netns exit
+    - netfilter: nf_tables: double hook unregistration in netns path
+    - netfilter: nftables: update table flags from the commit phase
+    - netfilter: nf_tables: fix table flag updates
+    - netfilter: nf_tables: disable toggling dormant table state more than once
+    - netfilter: nf_tables: bogus EBUSY when deleting flowtable after flush (for
+      5.4)
+    - Linux 5.4.262
+
+  * Focal update: v5.4.261 upstream stable release (LP: #2049049)
+    - vfs: fix readahead(2) on block devices
+    - genirq/matrix: Exclude managed interrupts in irq_matrix_allocated()
+    - i40e: fix potential memory leaks in i40e_remove()
+    - tcp: call tcp_try_undo_recovery when an RTOd TFO SYNACK is ACKed
+    - wifi: rtw88: debug: Fix the NULL vs IS_ERR() bug for debugfs_create_file()
+    - wifi: mt76: mt7603: rework/fix rx pse hang check
+    - tcp_metrics: add missing barriers on delete
+    - tcp_metrics: properly set tp->snd_ssthresh in tcp_init_metrics()
+    - tcp_metrics: do not create an entry from tcp_init_metrics()
+    - wifi: rtlwifi: fix EDCA limit set by BT coexistence
+    - can: dev: can_restart(): don't crash kernel if carrier is OK
+    - can: dev: can_restart(): fix race condition between controller restart and
+      netif_carrier_on()
+    - thermal: core: prevent potential string overflow
+    - r8169: use tp_to_dev instead of open code
+    - r8169: fix rare issue with broken rx after link-down on RTL8125
+    - chtls: fix tp->rcv_tstamp initialization
+    - tcp: Remove one extra ktime_get_ns() from cookie_init_timestamp
+    - tcp: fix cookie_init_timestamp() overflows
+    - ACPI: sysfs: Fix create_pnp_modalias() and create_of_modalias()
+    - ipv6: avoid atomic fragment on GSO packets
+    - net: add DEV_STATS_READ() helper
+    - ipvlan: properly track tx_errors
+    - regmap: debugfs: Fix a erroneous check after snprintf()
+    - clk: qcom: clk-rcg2: Fix clock rate overflow for high parent frequencies
+    - clk: qcom: gcc-sm8150: use ARRAY_SIZE instead of specifying num_parents
+    - clk: qcom: gcc-sm8150: Fix gcc_sdcc2_apps_clk_src
+    - clk: imx: Select MXC_CLK for CLK_IMX8QXP
+    - clk: keystone: pll: fix a couple NULL vs IS_ERR() checks
+    - clk: npcm7xx: Fix incorrect kfree
+    - clk: mediatek: clk-mt6779: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt6797: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629-eth: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt2701: Add check for mtk_alloc_clk_data
+    - platform/x86: wmi: Fix probe failure when failing to register WMI devices
+    - platform/x86: wmi: remove unnecessary initializations
+    - platform/x86: wmi: Fix opening of char device
+    - hwmon: (coretemp) Fix potentially truncated sysfs attribute name
+    - drm/rockchip: vop: Fix reset of state in duplicate state crtc funcs
+    - drm/rockchip: vop: Fix call to crtc reset helper
+    - drm/radeon: possible buffer overflow
+    - drm/rockchip: cdn-dp: Fix some error handling paths in cdn_dp_probe()
+    - arm64: dts: qcom: sdm845-mtp: fix WiFi configuration
+    - ARM: dts: qcom: mdm9615: populate vsdcc fixed regulator
+    - soc: qcom: llcc cleanup to get rid of sdm845 specific driver file
+    - [Config] remove CONFIG_QCOM_SDM845_LLCC
+    - soc: qcom: Rename llcc-slice to llcc-qcom
+    - [Config] remove llcc-slice module
+    - soc: qcom: llcc: Handle a second device without data corruption
+    - firmware: ti_sci: Replace HTTP links with HTTPS ones
+    - firmware: ti_sci: Mark driver as non removable
+    - clk: scmi: Free scmi_clk allocated when the clocks with invalid info are
+      skipped
+    - hwrng: geode - fix accessing registers
+    - libnvdimm/of_pmem: Use devm_kstrdup instead of kstrdup and check its return
+      value
+    - sched/rt: Provide migrate_disable/enable() inlines
+    - nd_btt: Make BTT lanes preemptible
+    - crypto: caam/qi2 - fix Chacha20 + Poly1305 self test failure
+    - crypto: caam/jr - fix Chacha20 + Poly1305 self test failure
+    - HID: cp2112: Use irqchip template
+    - hid: cp2112: Fix duplicate workqueue initialization
+    - ARM: 9321/1: memset: cast the constant byte to unsigned char
+    - ext4: move 'ix' sanity check to corrent position
+    - scsi: ufs: core: Leave space for '\0' in utf8 desc string
+    - RDMA/hfi1: Workaround truncation compilation error
+    - sh: bios: Revive earlyprintk support
+    - ASoC: Intel: Skylake: Fix mem leak when parsing UUIDs fails
+    - ASoC: ams-delta.c: use component after check
+    - mfd: dln2: Fix double put in dln2_probe
+    - leds: pwm: simplify if condition
+    - leds: pwm: convert to atomic PWM API
+    - leds: pwm: Don't disable the PWM when the LED should be off
+    - ledtrig-cpu: Limit to 8 CPUs
+    - leds: trigger: ledtrig-cpu:: Fix 'output may be truncated' issue for 'cpu'
+    - tty: tty_jobctrl: fix pid memleak in disassociate_ctty()
+    - usb: dwc2: fix possible NULL pointer dereference caused by driver
+      concurrency
+    - dmaengine: ti: edma: handle irq_of_parse_and_map() errors
+    - misc: st_core: Do not call kfree_skb() under spin_lock_irqsave()
+    - tools: iio: privatize globals and functions in iio_generic_buffer.c file
+    - tools: iio: iio_generic_buffer: Fix some integer type and calculation
+    - tools: iio: iio_generic_buffer ensure alignment
+    - USB: usbip: fix stub_dev hub disconnect
+    - dmaengine: pxa_dma: Remove an erroneous BUG_ON() in pxad_free_desc()
+    - f2fs: fix to initialize map.m_pblk in f2fs_precache_extents()
+    - modpost: fix tee MODULE_DEVICE_TABLE built on big-endian host
+    - powerpc/xive: Fix endian conversion size
+    - powerpc/imc-pmu: Use the correct spinlock initializer.
+    - powerpc/pseries: fix potential memory leak in init_cpu_associativity()
+    - i3c: Fix potential refcount leak in i3c_master_register_new_i3c_devs
+    - rtc: pcf85363: fix wrong mask/val parameters in regmap_update_bits call
+    - pcmcia: cs: fix possible hung task and memory leak pccardd()
+    - pcmcia: ds: fix refcount leak in pcmcia_device_add()
+    - pcmcia: ds: fix possible name leak in error path in pcmcia_device_add()
+    - media: bttv: fix use after free error due to btv->timeout timer
+    - media: s3c-camif: Avoid inappropriate kfree()
+    - media: dvb-usb-v2: af9035: fix missing unlock
+    - regmap: prevent noinc writes from clobbering cache
+    - pwm: sti: Avoid conditional gotos
+    - pwm: sti: Reduce number of allocations and drop usage of chip_data
+    - pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume
+    - Input: synaptics-rmi4 - fix use after free in rmi_unregister_function()
+    - llc: verify mac len before reading mac header
+    - tipc: Change nla_policy for bearer-related names to NLA_NUL_STRING
+    - inet: shrink struct flowi_common
+    - dccp: Call security_inet_conn_request() after setting IPv4 addresses.
+    - dccp/tcp: Call security_inet_conn_request() after setting IPv6 addresses.
+    - Fix termination state for idr_for_each_entry_ul()
+    - net: stmmac: xgmac: Enable support for multiple Flexible PPS outputs
+    - net/smc: fix dangling sock under state SMC_APPFINCLOSEWAIT
+    - tg3: power down device only on SYSTEM_POWER_OFF
+    - r8169: respect userspace disabling IFF_MULTICAST
+    - netfilter: xt_recent: fix (increase) ipv6 literal buffer length
+    - netfilter: nft_redir: use `struct nf_nat_range2` throughout and deduplicate
+      eval call-backs
+    - netfilter: nat: fix ipv6 nat redirect with mapped and scoped addresses
+    - drm/syncobj: fix DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
+    - spi: spi-zynq-qspi: add spi-mem to driver kconfig dependencies
+    - fbdev: imsttfb: Fix error path of imsttfb_probe()
+    - fbdev: imsttfb: fix a resource leak in probe
+    - fbdev: fsl-diu-fb: mark wr_reg_wa() static
+    - Revert "mmc: core: Capture correct oemid-bits for eMMC cards"
+    - btrfs: use u64 for buffer sizes in the tree search ioctls
+    - Linux 5.4.261
+
+  * Focal update: v5.4.260 upstream stable release (LP: #2049024)
+    - mtd: rawnand: marvell: Ensure program page operations are successful
+    - selftests/ftrace: Add new test case which checks non unique symbol
+    - mcb: Return actual parsed size when reading chameleon table
+    - mcb-lpc: Reallocate memory region to avoid memory overlapping
+    - virtio_balloon: Fix endless deflation and inflation on arm64
+    - virtio-mmio: fix memory leak of vm_dev
+    - r8169: fix the KCSAN reported data-race in rtl_tx while reading
+      TxDescArray[entry].opts1
+    - r8169: fix the KCSAN reported data race in rtl_rx while reading desc->opts1
+    - treewide: Spelling fix in comment
+    - igb: Fix potential memory leak in igb_add_ethtool_nfc_entry
+    - neighbour: fix various data-races
+    - igc: Fix ambiguity in the ethtool advertising
+    - net: ieee802154: adf7242: Fix some potential buffer overflow in
+      adf7242_stats_show()
+    - r8152: Increase USB control msg timeout to 5000ms as per spec
+    - r8152: Run the unload routine if we have errors during probe
+    - r8152: Cancel hw_phy_work if we have an error in probe
+    - tcp: fix wrong RTO timeout when received SACK reneging
+    - gtp: uapi: fix GTPA_MAX
+    - gtp: fix fragmentation needed check with gso
+    - iio: exynos-adc: request second interupt only when touchscreen mode is used
+    - i2c: muxes: i2c-mux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-mux-gpmux: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-demux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: stm32f7: Fix PEC handling in case of SMBUS transfers
+    - i2c: aspeed: Fix i2c bus hang in slave read
+    - nvmem: imx: correct nregs for i.MX6ULL
+    - nvmem: imx: correct nregs for i.MX6SLL
+    - nvmem: imx: correct nregs for i.MX6UL
+    - perf/core: Fix potential NULL deref
+    - clk: Sanitize possible_parent_show to Handle Return Value of
+      of_clk_get_parent_name
+    - i40e: Fix wrong check for I40E_TXR_FLAGS_WB_ON_ITR
+    - x86/i8259: Skip probing when ACPI/MADT advertises PCAT compatibility
+    - drm/dp_mst: Fix NULL deref in get_mst_branch_device_by_guid_helper()
+    - arm64: fix a concurrency issue in emulation_proc_handler()
+    - smbdirect: missing rc checks while waiting for rdma events
+    - f2fs: fix to do sanity check on inode type during garbage collection
+    - nfsd: lock_rename() needs both directories to live on the same fs
+    - x86/mm: Simplify RESERVE_BRK()
+    - x86/mm: Fix RESERVE_BRK() for older binutils
+    - ext4: add two helper functions extent_logical_end() and pa_logical_end()
+    - ext4: avoid overlapping preallocations due to overflow
+    - ext4: fix BUG in ext4_mb_new_inode_pa() due to overflow
+    - driver: platform: Add helper for safer setting of driver_override
+    - rpmsg: Constify local variable in field store macro
+    - rpmsg: Fix kfree() of static memory on setting driver_override
+    - rpmsg: Fix calling device_lock() on non-initialized device
+    - rpmsg: glink: Release driver_override
+    - rpmsg: Fix possible refcount leak in rpmsg_register_device_override()
+    - x86: Fix .brk attribute in linker script
+    - Input: i8042 - add Fujitsu Lifebook E5411 to i8042 quirk table
+    - irqchip/stm32-exti: add missing DT IRQ flag translation
+    - dmaengine: ste_dma40: Fix PM disable depth imbalance in d40_probe
+    - Input: synaptics-rmi4 - handle reset delay when using SMBus trsnsport
+    - fbdev: atyfb: only use ioremap_uc() on i386 and ia64
+    - spi: npcm-fiu: Fix UMA reads when dummy.nbytes == 0
+    - netfilter: nfnetlink_log: silence bogus compiler warning
+    - ASoC: rt5650: fix the wrong result of key button
+    - fbdev: uvesafb: Call cn_del_callback() at the end of uvesafb_exit()
+    - scsi: mpt3sas: Fix in error path
+    - platform/x86: asus-wmi: Change ASUS_WMI_BRN_DOWN code from 0x20 to 0x2e
+    - platform/mellanox: mlxbf-tmfifo: Fix a warning message
+    - net: chelsio: cxgb4: add an error code check in t4_load_phy_fw
+    - ata: ahci: fix enum constants for gcc-13
+    - remove the sx8 block driver
+    - [Config] remove CONFIG_BLK_DEV_SX8
+    - Revert "ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver"
+    - PCI: Prevent xHCI driver from claiming AMD VanGogh USB3 DRD device
+    - usb: storage: set 1.50 as the lower bcdDevice for older "Super Top"
+      compatibility
+    - tty: 8250: Remove UC-257 and UC-431
+    - tty: 8250: Add support for additional Brainboxes UC cards
+    - tty: 8250: Add support for Brainboxes UP cards
+    - tty: 8250: Add support for Intashield IS-100
+    - Linux 5.4.260
+
+  * CVE-2023-51779
+    - Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+
+  * CVE-2023-22995
+    - usb: dwc3: dwc3-qcom: Add missing platform_device_put() in
+      dwc3_qcom_acpi_register_core
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 02 Feb 2024 14:22:27 +0100
+
+linux (5.4.0-171.189) focal; urgency=medium
+
+  * focal/linux: 5.4.0-171.189 -proposed tracker (LP: #2048282)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+    - [Packaging] update annotations scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2024.01.08)
+
+  * Page fault in RDMA ODP triggers BUG_ON during MMU notifier registration
+    (LP: #2046534)
+    - RDMA/odp: Ensure the mm is still alive before creating an implicit child
+
+  * Hotplugging SCSI disk in QEMU VM fails (LP: #2047382)
+    - Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
+
+  * CVE-2023-6040
+    - netfilter: nf_tables: Reject tables of unsupported family
+
+  * kernel_selftests failures on kernel-P10d-LPAR10.ppc64el.10
+    (LP: #2032641)
+    - selftests: Skip TM tests on synthetic TM implementations
+
+  * [Debian] autoreconstruct - Do not generate chmod -x for deleted  files
+    (LP: #2045562)
+    - [Debian] autoreconstruct - Do not generate chmod -x for deleted files
+
+  * CVE-2023-6931
+    - perf/core: Add a new read format to get a number of lost samples
+    - perf: Fix perf_event_validate_size()
+    - perf: Fix perf_event_validate_size() lockdep splat
+
+  * CVE-2023-6932
+    - ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+
+  * CVE-2023-6606
+    - smb: client: fix OOB in smbCalcSize()
+
+  * CVE-2023-45863
+    - kobject: Fix slab-out-of-bounds in fill_kobj_path()
+
+  * Focal update: v5.4.259 upstream stable release (LP: #2043724)
+    - RDMA/cxgb4: Check skb value for failure to allocate
+    - lib/test_meminit: fix off-by-one error in test_pages()
+    - pwm: hibvt: Explicitly set .polarity in .get_state()
+    - HID: logitech-hidpp: Fix kernel crash on receiver USB disconnect
+    - quota: Fix slow quotaoff
+    - net: prevent address rewrite in kernel_bind()
+    - drm: etvnaviv: fix bad backport leading to warning
+    - drm/msm/dsi: skip the wait for video mode done if not applicable
+    - ravb: Fix up dma_free_coherent() call in ravb_remove()
+    - ieee802154: ca8210: Fix a potential UAF in ca8210_probe
+    - mlxsw: fix mlxsw_sp2_nve_vxlan_learning_set() return type
+    - xen-netback: use default TX queue size for vifs
+    - drm/vmwgfx: fix typo of sizeof argument
+    - ixgbe: fix crash with empty VF macvlan list
+    - net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()
+    - nfc: nci: assert requested protocol is valid
+    - workqueue: Override implicit ordered attribute in
+      workqueue_apply_unbound_cpumask()
+    - dmaengine: stm32-mdma: abort resume if no ongoing transfer
+    - usb: xhci: xhci-ring: Use sysdev for mapping bounce buffer
+    - net: usb: dm9601: fix uninitialized variable use in dm9601_mdio_read
+    - usb: dwc3: Soft reset phy on probe for host
+    - usb: musb: Get the musb_qh poniter after musb_giveback
+    - usb: musb: Modify the "HWVers" register address
+    - iio: pressure: bmp280: Fix NULL pointer exception
+    - iio: pressure: dps310: Adjust Timeout Settings
+    - iio: pressure: ms5611: ms5611_prom_is_valid false negative bug
+    - mcb: remove is_added flag from mcb_device struct
+    - libceph: use kernel_connect()
+    - ceph: fix incorrect revoked caps assert in ceph_fill_file_size()
+    - Input: powermate - fix use-after-free in powermate_config_complete
+    - Input: psmouse - fix fast_reconnect function for PS/2 mode
+    - Input: xpad - add PXN V900 support
+    - cgroup: Remove duplicates in cgroup v1 tasks file
+    - pinctrl: avoid unsafe code pattern in find_pinctrl()
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call
+    - x86/cpu: Fix AMD erratum #1485 on Zen4-based CPUs
+    - dmaengine: mediatek: Fix deadlock caused by synchronize_irq()
+    - powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
+    - powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
+    - ravb: Fix use-after-free issue in ravb_tx_timeout_work()
+    - Documentation: sysctl: align cells in second content column
+    - usb: hub: Guard against accesses to uninitialized BOS descriptors
+    - Bluetooth: hci_event: Ignore NULL link key
+    - Bluetooth: Reject connection with the device which has same BD_ADDR
+    - Bluetooth: Fix a refcnt underflow problem for hci_conn
+    - Bluetooth: vhci: Fix race when opening vhci device
+    - Bluetooth: hci_event: Fix coding style
+    - Bluetooth: avoid memcmp() out of bounds warning
+    - ice: fix over-shifted variable
+    - nfc: nci: fix possible NULL pointer dereference in send_acknowledge()
+    - regmap: fix NULL deref on lookup
+    - KVM: x86: Mask LVTPC when handling a PMI
+    - netfilter: nft_payload: fix wrong mac header matching
+    - qed: fix LL2 RX buffer allocation
+    - xfrm: fix a data-race in xfrm_gen_index()
+    - xfrm: interface: use DEV_STATS_INC()
+    - net: ipv4: fix return value check in esp_remove_trailer
+    - net: ipv6: fix return value check in esp_remove_trailer
+    - net: rfkill: gpio: prevent value glitch during probe
+    - tcp: fix excessive TLP and RACK timeouts from HZ rounding
+    - tcp: tsq: relax tcp_small_queue_check() when rtx queue contains a single skb
+    - tun: prevent negative ifindex
+    - ipv4: fib: annotate races around nh->nh_saddr_genid and nh->nh_saddr
+    - net: usb: smsc95xx: Fix an error code in smsc95xx_reset()
+    - i40e: prevent crash on probe if hw registers have invalid values
+    - net/sched: sch_hfsc: upgrade 'rt' to 'sc' when it becomes a inner curve
+    - neighbor: tracing: Move pin6 inside CONFIG_IPV6=y section
+    - netfilter: nft_set_rbtree: .deactivate fails if element has expired
+    - net: pktgen: Fix interface flags printing
+    - resource: Add irqresource_disabled()
+    - ACPI: Drop acpi_dev_irqresource_disabled()
+    - ACPI: resource: Skip IRQ override on Asus Vivobook S5602ZA
+    - ACPI: resource: Add Asus ExpertBook B2502 to Asus quirks
+    - ACPI: resource: Skip IRQ override on Asus Expertbook B2402CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1502CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CBA
+    - ARM: dts: ti: omap: Fix noisy serial with overrun-throttle-ms for mapphone
+    - btrfs: return -EUCLEAN for delayed tree ref with a ref count not equals to 1
+    - btrfs: initialize start_slot in btrfs_log_prealloc_extents
+    - i2c: mux: Avoid potential false error message in i2c_mux_add_adapter
+    - overlayfs: set ctime when setting mtime and atime
+    - gpio: timberdale: Fix potential deadlock on &tgpio->lock
+    - ata: libata-eh: Fix compilation warning in ata_eh_link_report()
+    - tracing: relax trace_event_eval_update() execution with cond_resched()
+    - HID: holtek: fix slab-out-of-bounds Write in holtek_kbd_input_event
+    - Bluetooth: Avoid redundant authentication
+    - Bluetooth: hci_core: Fix build warnings
+    - wifi: mac80211: allow transmitting EAPOL frames with tainted key
+    - wifi: cfg80211: avoid leaking stack data into trace
+    - regulator/core: Revert "fix kobject release warning and memory leak in
+      regulator_register()"
+    - sky2: Make sure there is at least one frag_addr available
+    - drm: panel-orientation-quirks: Add quirk for One Mix 2S
+    - btrfs: fix some -Wmaybe-uninitialized warnings in ioctl.c
+    - HID: multitouch: Add required quirk for Synaptics 0xcd7e device
+    - Bluetooth: hci_event: Fix using memcmp when comparing keys
+    - mtd: rawnand: qcom: Unmap the right resource upon probe failure
+    - mtd: spinand: micron: correct bitmask for ecc status
+    - mtd: physmap-core: Restore map_rom fallback
+    - mmc: core: sdio: hold retuning if sdio in 1-bit mode
+    - mmc: core: Capture correct oemid-bits for eMMC cards
+    - Revert "pinctrl: avoid unsafe code pattern in find_pinctrl()"
+    - ACPI: irq: Fix incorrect return value in acpi_register_gsi()
+    - USB: serial: option: add Telit LE910C4-WWX 0x1035 composition
+    - USB: serial: option: add entry for Sierra EM9191 with new firmware
+    - USB: serial: option: add Fibocom to DELL custom modem FM101R-GL
+    - s390/pci: fix iommu bitmap allocation
+    - gpio: vf610: set value before the direction to avoid a glitch
+    - ASoC: pxa: fix a memory leak in probe()
+    - phy: mapphone-mdm6600: Fix runtime disable on probe
+    - phy: mapphone-mdm6600: Fix runtime PM for remove
+    - phy: mapphone-mdm6600: Fix pinctrl_pm handling for sleep pins
+    - Bluetooth: hci_sock: fix slab oob read in create_monitor_event
+    - Bluetooth: hci_sock: Correctly bounds check and pad HCI_MON_NEW_INDEX name
+    - xfrm6: fix inet6_dev refcount underflow problem
+    - Linux 5.4.259
+
+  * Focal update: v5.4.258 upstream stable release (LP: #2042107)
+    - NFS/pNFS: Report EINVAL errors from connect() to the server
+    - SUNRPC: Mark the cred for revalidation if the server rejects it
+    - tracing: Increase trace array ref count on enable and filter files
+    - ata: libahci: clear pending interrupt status
+    - ext4: remove the 'group' parameter of ext4_trim_extent
+    - ext4: add new helper interface ext4_try_to_trim_range()
+    - ext4: scope ret locally in ext4_try_to_trim_range()
+    - ext4: change s_last_trim_minblks type to unsigned long
+    - ext4: mark group as trimmed only if it was fully scanned
+    - ext4: replace the traditional ternary conditional operator with with
+      max()/min()
+    - ext4: move setting of trimmed bit into ext4_try_to_trim_range()
+    - ext4: do not let fstrim block system suspend
+    - ASoC: meson: spdifin: start hw on dai probe
+    - netfilter: nf_tables: disallow element removal on anonymous sets
+    - bpf: Avoid deadlock when using queue and stack maps from NMI
+    - selftests/tls: Add {} to avoid static checker warning
+    - selftests: tls: swap the TX and RX sockets in some tests
+    - ASoC: imx-audmix: Fix return error with devm_clk_get()
+    - i40e: Fix for persistent lldp support
+    - SAUCE: Revert "UBUNTU: SAUCE: i40e Fix GPF when deleting VMs"
+    - i40e: Remove scheduling while atomic possibility
+    - i40e: Fix warning message and call stack during rmmod i40e driver
+    - i40e: Fix VF VLAN offloading when port VLAN is configured
+    - powerpc/perf/hv-24x7: Update domain value check
+    - dccp: fix dccp_v4_err()/dccp_v6_err() again
+    - net: hns3: add 5ms delay before clear firmware reset irq source
+    - net: bridge: use DEV_STATS_INC()
+    - team: fix null-ptr-deref when team device type is changed
+    - net: rds: Fix possible NULL-pointer dereference
+    - gpio: tb10x: Fix an error handling path in tb10x_gpio_probe()
+    - i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()
+    - Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN
+    - scsi: qla2xxx: Fix update_fcport for current_topology
+    - scsi: qla2xxx: Fix deletion race condition
+    - drm/amd/display: Reinstate LFC optimization
+    - drm/amd/display: Fix LFC multiplier changing erratically
+    - drm/amd/display: prevent potential division by zero errors
+    - ata: libata: disallow dev-initiated LPM transitions to unsupported states
+    - MIPS: Alchemy: only build mmc support helpers if au1xmmc is enabled
+    - clk: tegra: fix error return case for recalc_rate
+    - ARM: dts: ti: omap: motorola-mapphone: Fix abe_clkctrl warning on boot
+    - bus: ti-sysc: Fix SYSC_QUIRK_SWSUP_SIDLE_ACT handling for uart wake-up
+    - xtensa: add default definition for XCHAL_HAVE_DIV32
+    - xtensa: iss/network: make functions static
+    - xtensa: boot: don't add include-dirs
+    - xtensa: boot/lib: fix function prototypes
+    - gpio: pmic-eic-sprd: Add can_sleep flag for PMIC EIC chip
+    - parisc: sba: Fix compile warning wrt list of SBA devices
+    - parisc: iosapic.c: Fix sparse warnings
+    - parisc: drivers: Fix sparse warning
+    - parisc: irq: Make irq_stack_union static to avoid sparse warning
+    - selftests/ftrace: Correctly enable event in instance-event.tc
+    - ring-buffer: Avoid softlockup in ring_buffer_resize()
+    - ata: libata-eh: do not clear ATA_PFLAG_EH_PENDING in ata_eh_reset()
+    - spi: nxp-fspi: reset the FLSHxCR1 registers
+    - bpf: Clarify error expectations from bpf_clone_redirect
+    - powerpc/watchpoints: Annotate atomic context in more places
+    - ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - fbdev/sh7760fb: Depend on FB=y
+    - nvme-pci: do not set the NUMA node of device if it has none
+    - watchdog: iTCO_wdt: No need to stop the timer in probe
+    - watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
+    - i40e: improve locking of mac_filter_hash
+    - i40e: always propagate error value in i40e_set_vsi_promisc()
+    - i40e: fix return of uninitialized aq_ret in i40e_set_vsi_promisc
+    - smack: Record transmuting in smk_transmuted
+    - smack: Retrieve transmuting information in smack_inode_getsecurity()
+    - Smack:- Use overlay inode label in smack_inode_copy_up()
+    - serial: 8250_port: Check IRQ data before use
+    - nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
+    - ALSA: hda: Disable power save for solving pop issue on Lenovo ThinkCentre
+      M70q
+    - ata: libata-scsi: ignore reserved bits for REPORT SUPPORTED OPERATION CODES
+    - i2c: i801: unregister tco_pdev in i801_probe() error path
+    - ring-buffer: Update "shortest_full" in polling
+    - btrfs: properly report 0 avail for very full file systems
+    - net: thunderbolt: Fix TCPv6 GSO checksum calculation
+    - ata: libata-core: Fix ata_port_request_pm() locking
+    - ata: libata-core: Fix port and device removal
+    - ata: libata-core: Do not register PM operations for SAS ports
+    - ata: libata-sata: increase PMP SRST timeout to 10s
+    - fs: binfmt_elf_efpic: fix personality for ELF-FDPIC
+    - rbd: move rbd_dev_refresh() definition
+    - rbd: decouple header read-in from updating rbd_dev->header
+    - rbd: decouple parent info read-in from updating rbd_dev
+    - rbd: take header_rwsem in rbd_dev_refresh() only when updating
+    - Revert "PCI: qcom: Disable write access to read only registers for IP
+      v2.3.3"
+    - scsi: zfcp: Fix a double put in zfcp_port_enqueue()
+    - qed/red_ll2: Fix undefined behavior bug in struct qed_ll2_info
+    - wifi: mwifiex: Fix tlv_buf_left calculation
+    - net: replace calls to sock->ops->connect() with kernel_connect()
+    - net: prevent rewrite of msg_name in sock_sendmsg()
+    - wifi: iwlwifi: dbg_ini: fix structure packing
+    - wifi: mwifiex: Fix oob check condition in mwifiex_process_rx_packet
+    - drivers/net: process the result of hdlc_open() and add call of hdlc_close()
+      in uhdlc_close()
+    - wifi: mt76: mt76x02: fix MT76x0 external LNA gain handling
+    - regmap: rbtree: Fix wrong register marked as in-cache when creating new node
+    - ima: Finish deprecation of IMA_TRUSTED_KEYRING Kconfig
+    - scsi: target: core: Fix deadlock due to recursive locking
+    - NFS4: Trace state recovery operation
+    - NFS: Add a helper nfs_client_for_each_server()
+    - NFSv4: Fix a nfs4_state_manager() race
+    - modpost: add missing else to the "of" check
+    - net: fix possible store tearing in neigh_periodic_work()
+    - ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
+    - net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent
+    - net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
+    - net: nfc: llcp: Add lock when modifying device list
+    - netfilter: handle the connecting collision properly in
+      nf_conntrack_proto_sctp
+    - net: stmmac: dwmac-stm32: fix resume on STM32 MCU
+    - tcp: fix quick-ack counting to count actual ACKs of new data
+    - tcp: fix delayed ACKs for MSS boundary condition
+    - sctp: update transport state when processing a dupcook packet
+    - sctp: update hb timer immediately after users change hb_interval
+    - cpupower: add Makefile dependencies for install targets
+    - RDMA/core: Require admin capabilities to set system parameters
+    - IB/mlx4: Fix the size of a buffer in add_port_entries()
+    - gpio: aspeed: fix the GPIO number passed to pinctrl_gpio_set_config()
+    - gpio: pxa: disable pinctrl calls for MMP_GPIO
+    - RDMA/cma: Fix truncation compilation warning in make_cma_ports
+    - RDMA/uverbs: Fix typo of sizeof argument
+    - RDMA/siw: Fix connection failure handling
+    - RDMA/mlx5: Fix NULL string error
+    - parisc: Restore __ldcw_align for PA-RISC 2.0 processors
+    - NFS: Fix a race in __nfs_list_for_each_server()
+    - ima: rework CONFIG_IMA dependency block
+    - [Config] Update IMA_BLACKLIST_KEYRING and IMA_LOAD_X509
+    - xen/events: replace evtchn_rwlock with RCU
+    - Linux 5.4.258
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Fri, 05 Jan 2024 14:59:41 +0100
+
+linux (5.4.0-169.187) focal; urgency=medium
+
+  * focal/linux: 5.4.0-169.187 -proposed tracker (LP: #2044375)
+
+  * USB bus error after upgrading to proposed kernel on lunar, jammy and focal
+    (LP: #2043197)
+    - USB: core: Fix oversight in SuperSpeed initialization
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] update annotations scripts
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Thu, 23 Nov 2023 14:04:39 +0100
+
+linux (5.4.0-168.186) focal; urgency=medium
+
+  * focal/linux: 5.4.0-168.186 -proposed tracker (LP: #2041652)
+
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284)
+    - erofs: ensure that the post-EOF tails are all zeroed
+    - ARM: pxa: remove use of symbol_get()
+    - mmc: au1xmmc: force non-modular build and remove symbol_get usage
+    - net: enetc: use EXPORT_SYMBOL_GPL for enetc_phc_index
+    - rtc: ds1685: use EXPORT_SYMBOL_GPL for ds1685_rtc_poweroff
+    - modules: only allow symbol_get of EXPORT_SYMBOL_GPL modules
+    - USB: serial: option: add Quectel EM05G variant (0x030e)
+    - USB: serial: option: add FOXCONN T99W368/T99W373 product
+    - HID: wacom: remove the battery when the EKR is off
+    - staging: rtl8712: fix race condition
+    - Bluetooth: btsdio: fix use after free bug in btsdio_remove due to race
+      condition
+    - serial: sc16is7xx: fix bug when first setting GPIO direction
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - fsi: master-ast-cf: Add MODULE_FIRMWARE macro
+    - nilfs2: fix general protection fault in nilfs_lookup_dirty_data_buffers()
+    - nilfs2: fix WARNING in mark_buffer_dirty due to discarded buffer reuse
+    - pinctrl: amd: Don't show `Invalid config param` errors
+    - 9p: virtio: make sure 'offs' is initialized in zc_request
+    - ASoC: da7219: Flush pending AAD IRQ when suspending
+    - ASoC: da7219: Check for failure reading AAD IRQ events
+    - ethernet: atheros: fix return value check in atl1c_tso_csum()
+    - vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
+    - m68k: Fix invalid .section syntax
+    - s390/dasd: use correct number of retries for ERP requests
+    - s390/dasd: fix hanging device after request requeue
+    - fs/nls: make load_nls() take a const parameter
+    - ASoc: codecs: ES8316: Fix DMIC config
+    - ASoC: atmel: Fix the 8K sample parameter in I2SC master
+    - platform/x86: intel: hid: Always call BTNL ACPI method
+    - platform/x86: huawei-wmi: Silence ambient light sensor
+    - security: keys: perform capable check only on privileged operations
+    - clk: fixed-mmio: make COMMON_CLK_FIXED_MMIO depend on HAS_IOMEM
+    - net: usb: qmi_wwan: add Quectel EM05GV2
+    - idmaengine: make FSL_EDMA and INTEL_IDMA64 depends on HAS_IOMEM
+    - scsi: qedi: Fix potential deadlock on &qedi_percpu->p_work_lock
+    - netlabel: fix shift wrapping bug in netlbl_catmap_setlong()
+    - bnx2x: fix page fault following EEH recovery
+    - sctp: handle invalid error codes without calling BUG()
+    - cifs: add a warning when the in-flight count goes negative
+    - scsi: storvsc: Always set no_report_opcodes
+    - ALSA: seq: oss: Fix racy open/close of MIDI devices
+    - platform/mellanox: Fix mlxbf-tmfifo not handling all virtio CONSOLE
+      notifications
+    - powerpc/32s: Fix assembler warning about r0
+    - udf: Check consistency of Space Bitmap Descriptor
+    - udf: Handle error when adding extent to a file
+    - Revert "net: macsec: preserve ingress frame ordering"
+    - reiserfs: Check the return value from __getblk()
+    - eventfd: Export eventfd_ctx_do_read()
+    - eventfd: prevent underflow for eventfd semaphores
+    - new helper: lookup_positive_unlocked()
+    - fs: Fix error checking for d_hash_and_lookup()
+    - tmpfs: verify {g,u}id mount options correctly
+    - OPP: Fix passing 0 to PTR_ERR in _opp_attach_genpd()
+    - x86/asm: Make more symbols local
+    - x86/boot: Annotate local functions
+    - x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved
+    - perf/imx_ddr: don't enable counter0 if none of 4 counters are used
+    - cpufreq: powernow-k8: Use related_cpus instead of cpus in driver.exit()
+    - bpf: Clear the probe_addr for uprobe
+    - tcp: tcp_enter_quickack_mode() should be static
+    - regmap: rbtree: Use alloc_flags for memory allocations
+    - spi: tegra20-sflash: fix to check return value of platform_get_irq() in
+      tegra_sflash_probe()
+    - can: gs_usb: gs_usb_receive_bulk_callback(): count RX overflow errors also
+      in case of OOM
+    - wifi: mwifiex: Fix OOB and integer underflow when rx packets
+    - mwifiex: switch from 'pci_' to 'dma_' API
+    - wifi: mwifiex: fix error recovery in PCIE buffer descriptor management
+    - crypto: stm32 - Properly handle pm_runtime_get failing
+    - Bluetooth: nokia: fix value check in nokia_bluetooth_serdev_probe()
+    - crypto: caam - fix unchecked return value error
+    - hwrng: iproc-rng200 - use semicolons rather than commas to separate
+      statements
+    - hwrng: iproc-rng200 - Implement suspend and resume calls
+    - lwt: Fix return values of BPF xmit ops
+    - lwt: Check LWTUNNEL_XMIT_CONTINUE strictly
+    - fs: ocfs2: namei: check return value of ocfs2_add_entry()
+    - wifi: mwifiex: fix memory leak in mwifiex_histogram_read()
+    - wifi: mwifiex: Fix missed return in oob checks failed path
+    - wifi: ath9k: fix races between ath9k_wmi_cmd and ath9k_wmi_ctrl_rx
+    - wifi: ath9k: protect WMI command response buffer replacement with a lock
+    - wifi: mwifiex: avoid possible NULL skb pointer dereference
+    - wifi: ath9k: use IS_ERR() with debugfs_create_dir()
+    - net: arcnet: Do not call kfree_skb() under local_irq_disable()
+    - mlxsw: i2c: Fix chunk size setting in output mailbox buffer
+    - mlxsw: i2c: Limit single transaction buffer size
+    - netrom: Deny concurrent connect().
+    - drm/bridge: tc358764: Fix debug print parameter order
+    - quota: avoid increasing DQST_LOOKUPS when iterating over dirty/inuse list
+    - quota: factor out dquot_write_dquot()
+    - quota: rename dquot_active() to inode_quota_active()
+    - quota: add new helper dquot_active()
+    - quota: fix dqput() to follow the guarantees dquot_srcu should provide
+    - drm/amdgpu: avoid integer overflow warning in amdgpu_device_resize_fb_bar()
+    - ARM: dts: BCM53573: Drop nonexistent "default-off" LED trigger
+    - ARM: dts: BCM53573: Add cells sizes to PCIe node
+    - ARM: dts: BCM53573: Use updated "spi-gpio" binding properties
+    - drm/etnaviv: fix dumping of active MMU context
+    - ARM: dts: s3c6410: move fixed clocks under root node in Mini6410
+    - ARM: dts: s3c6410: align node SROM bus node name with dtschema in Mini6410
+    - ARM: dts: s3c64xx: align pinctrl with dtschema
+    - ARM: dts: samsung: s3c6410-mini6410: correct ethernet reg addresses (split)
+    - ARM: dts: s5pv210: add RTC 32 KHz clock in SMDKV210
+    - ARM: dts: s5pv210: use defines for IRQ flags in SMDKV210
+    - ARM: dts: s5pv210: correct ethernet unit address in SMDKV210
+    - ARM: dts: s5pv210: add dummy 5V regulator for backlight on SMDKv210
+    - ARM: dts: samsung: s5pv210-smdkv210: correct ethernet reg addresses (split)
+    - drm: adv7511: Fix low refresh rate register for ADV7533/5
+    - ARM: dts: BCM53573: Fix Ethernet info for Luxul devices
+    - arm64: dts: qcom: sdm845: Add missing RPMh power domain to GCC
+    - drm/amdgpu: Update min() to min_t() in 'amdgpu_info_ioctl'
+    - md/bitmap: don't set max_write_behind if there is no write mostly device
+    - md/md-bitmap: hold 'reconfig_mutex' in backlog_store()
+    - drm/tegra: Remove superfluous error messages around platform_get_irq()
+    - drm/tegra: dpaux: Fix incorrect return value of platform_get_irq
+    - of: unittest: fix null pointer dereferencing in
+      of_unittest_find_node_by_name()
+    - drm/armada: Fix off-by-one error in armada_overlay_get_property()
+    - drm/panel: simple: Add missing connector type and pixel format for AUO
+      T215HVN01
+    - ima: Remove deprecated IMA_TRUSTED_KEYRING Kconfig
+    - [Config] Update annotations after CONFIG_IMA_TRUSTED_KEYRING removal
+    - drm/msm/mdp5: Don't leak some plane state
+    - smackfs: Prevent underflow in smk_set_cipso()
+    - audit: fix possible soft lockup in __audit_inode_child()
+    - drm/mediatek: Fix potential memory leak if vmap() fail
+    - of: unittest: Fix overlay type in apply/revert check
+    - ALSA: ac97: Fix possible error value of *rac97
+    - ipmi:ssif: Add check for kstrdup
+    - ipmi:ssif: Fix a memory leak when scanning for an adapter
+    - drivers: clk: keystone: Fix parameter judgment in _of_pll_clk_init()
+    - clk: sunxi-ng: Modify mismatched function name
+    - PCI: Mark NVIDIA T4 GPUs to avoid bus reset
+    - PCI: pciehp: Use RMW accessors for changing LNKCTL
+    - PCI/ASPM: Use RMW accessors for changing LNKCTL
+    - clk: imx: composite-8m: fix clock pauses when set_rate would be a no-op
+    - powerpc/fadump: reset dump area size if fadump memory reserve fails
+    - PCI: Add #defines for Enter Compliance, Transmit Margin
+    - drm/amdgpu: Correct Transmit Margin masks
+    - drm/amdgpu: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/amdgpu: Prefer pcie_capability_read_word()
+    - drm/amdgpu: Use RMW accessors for changing LNKCTL
+    - drm/radeon: Correct Transmit Margin masks
+    - drm/radeon: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/radeon: Prefer pcie_capability_read_word()
+    - drm/radeon: Use RMW accessors for changing LNKCTL
+    - wifi: ath10k: Use RMW accessors for changing LNKCTL
+    - nfs/blocklayout: Use the passed in gfp flags
+    - powerpc/iommu: Fix notifiers being shared by PCI and VIO buses
+    - jfs: validate max amount of blocks before allocation.
+    - fs: lockd: avoid possible wrong NULL parameter
+    - NFSD: da_addr_body field missing in some GETDEVICEINFO replies
+    - NFS: Guard against READDIR loop when entry names exceed MAXNAMELEN
+    - media: v4l2-fwnode: fix v4l2_fwnode_parse_link handling
+    - media: v4l2-fwnode: simplify v4l2_fwnode_parse_link
+    - media: v4l2-core: Fix a potential resource leak in v4l2_fwnode_parse_link()
+    - drivers: usb: smsusb: fix error handling code in smsusb_init_device
+    - media: dib7000p: Fix potential division by zero
+    - media: dvb-usb: m920x: Fix a potential memory leak in m920x_i2c_xfer()
+    - media: cx24120: Add retval check for cx24120_message_send()
+    - media: mediatek: vcodec: Return NULL if no vdec_fb is found
+    - usb: phy: mxs: fix getting wrong state with mxs_phy_is_otg_host()
+    - scsi: iscsi: Add strlen() check in iscsi_if_set{_host}_param()
+    - scsi: be2iscsi: Add length check when parsing nlattrs
+    - scsi: qla4xxx: Add length check when parsing nlattrs
+    - serial: sprd: getting port index via serial aliases only
+    - serial: sprd: remove redundant sprd_port cleanup
+    - serial: sprd: Assign sprd_port after initialized to avoid wrong access
+    - serial: sprd: Fix DMA buffer leak issue
+    - x86/APM: drop the duplicate APM_MINOR_DEV macro
+    - scsi: qedf: Do not touch __user pointer in
+      qedf_dbg_stop_io_on_error_cmd_read() directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_debug_cmd_read()
+      directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_fp_int_cmd_read()
+      directly
+    - coresight: tmc: Explicit type conversions to prevent integer overflow
+    - dma-buf/sync_file: Fix docs syntax
+    - driver core: test_async: fix an error code
+    - IB/uverbs: Fix an potential error pointer dereference
+    - iommu/vt-d: Fix to flush cache of PASID directory table
+    - media: go7007: Remove redundant if statement
+    - USB: gadget: f_mass_storage: Fix unused variable warning
+    - media: i2c: ov5640: Configure HVP lines in s_power callback
+    - media: ov5640: Enable MIPI interface in ov5640_set_power_mipi()
+    - media: i2c: ov2680: Set V4L2_CTRL_FLAG_MODIFY_LAYOUT on flips
+    - media: ov2680: Remove auto-gain and auto-exposure controls
+    - media: ov2680: Fix ov2680_bayer_order()
+    - media: ov2680: Fix vflip / hflip set functions
+    - media: ov2680: Fix regulators being left enabled on ov2680_power_on() errors
+    - scsi: core: Use 32-bit hostnum in scsi_host_lookup()
+    - scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
+    - serial: tegra: handle clk prepare error in tegra_uart_hw_init()
+    - amba: bus: fix refcount leak
+    - Revert "IB/isert: Fix incorrect release of isert connection"
+    - RDMA/siw: Balance the reference of cep->kref in the error path
+    - RDMA/siw: Correct wrong debug message
+    - HID: logitech-dj: Fix error handling in logi_dj_recv_switch_to_dj_mode()
+    - HID: multitouch: Correct devm device reference for hidinput input_dev name
+    - x86/speculation: Mark all Skylake CPUs as vulnerable to GDS
+    - tracing: Fix race issue between cpu buffer write and swap
+    - phy/rockchip: inno-hdmi: use correct vco_div_5 macro on rk3328
+    - phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 recalc_rate
+    - phy/rockchip: inno-hdmi: do not power on rk3328 post pll on reg write
+    - rpmsg: glink: Add check for kstrdup
+    - mtd: rawnand: fsmc: handle clk prepare error in fsmc_nand_resume()
+    - um: Fix hostaudio build errors
+    - dmaengine: ste_dma40: Add missing IRQ check in d40_probe
+    - cpufreq: Fix the race condition while updating the transition_task of policy
+    - virtio_ring: fix avail_wrap_counter in virtqueue_add_packed
+    - skbuff: skb_segment, Call zero copy functions before using skbuff frags
+    - PM / devfreq: Fix leak in devfreq_dev_release()
+    - ALSA: pcm: Fix missing fixup call in compat hw_refine ioctl
+    - ipmi_si: fix a memleak in try_smi_init()
+    - ARM: OMAP2+: Fix -Warray-bounds warning in _pwrdm_state_switch()
+    - backlight/gpio_backlight: Compare against struct fb_info.device
+    - backlight/bd6107: Compare against struct fb_info.device
+    - backlight/lv5207lp: Compare against struct fb_info.device
+    - xtensa: PMU: fix base address for the newer hardware
+    - media: dvb: symbol fixup for dvb_attach()
+    - ntb: Drop packets when qp link is down
+    - ntb: Clean up tx tail index on link down
+    - ntb: Fix calculation ntb_transport_tx_free_entry()
+    - Revert "PCI: Mark NVIDIA T4 GPUs to avoid bus reset"
+    - procfs: block chmod on /proc/thread-self/comm
+    - parisc: Fix /proc/cpuinfo output for lscpu
+    - dlm: fix plock lookup when using multiple lockspaces
+    - dccp: Fix out of bounds access in DCCP error handler
+    - X.509: if signature is unsupported skip validation
+    - net: handle ARPHRD_PPP in dev_is_mac_header_xmit()
+    - fsverity: skip PKCS#7 parser when keyring is empty
+    - pstore/ram: Check start of empty przs during init
+    - s390/ipl: add missing secure/has_secure file to ipl type 'unknown'
+    - crypto: stm32 - fix loop iterating through scatterlist for DMA
+    - cpufreq: brcmstb-avs-cpufreq: Fix -Warray-bounds bug
+    - sc16is7xx: Set iobase to device index
+    - serial: sc16is7xx: fix broken port 0 uart init
+    - usb: typec: tcpci: clear the fault status bit
+    - udf: initialize newblock to 0
+    - drm: fix double free for gbo in drm_gem_vram_init and drm_gem_vram_create
+    - net/ipv6: SKB symmetric hash should incorporate transport ports
+    - scsi: qla2xxx: fix inconsistent TMF timeout
+    - scsi: qla2xxx: Fix erroneous link up failure
+    - scsi: qla2xxx: Turn off noisy message log
+    - scsi: qla2xxx: Remove unsupported ql2xenabledif option
+    - fbdev/ep93xx-fb: Do not assign to struct fb_info.dev
+    - drm/ast: Fix DRAM init on AST2200
+    - lib/test_meminit: allocate pages up to order MAX_ORDER
+    - parisc: led: Fix LAN receive and transmit LEDs
+    - parisc: led: Reduce CPU overhead for disk & lan LED computation
+    - clk: qcom: gcc-mdm9615: use proper parent for pll0_vote clock
+    - soc: qcom: qmi_encdec: Restrict string length in decode
+    - NFSv4/pnfs: minor fix for cleanup path in nfs4_get_device_info
+    - kconfig: fix possible buffer overflow
+    - perf annotate bpf: Don't enclose non-debug code with an assert()
+    - x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm()
+    - perf top: Don't pass an ERR_PTR() directly to perf_session__delete()
+    - watchdog: intel-mid_wdt: add MODULE_ALIAS() to allow auto-load
+    - pwm: lpc32xx: Remove handling of PWM channels
+    - sctp: annotate data-races around sk->sk_wmem_queued
+    - ipv4: annotate data-races around fi->fib_dead
+    - net: read sk->sk_family once in sk_mc_loop()
+    - igb: disable virtualization features on 82580
+    - veth: Fixing transmit return status for dropped packets
+    - net: ipv6/addrconf: avoid integer underflow in ipv6_create_tempaddr
+    - af_unix: Fix data-races around user->unix_inflight.
+    - af_unix: Fix data-race around unix_tot_inflight.
+    - af_unix: Fix data-races around sk->sk_shutdown.
+    - af_unix: Fix data race around sk->sk_err.
+    - kcm: Destroy mutex in kcm_exit_net()
+    - igc: Change IGC_MIN to allow set rx/tx value between 64 and 80
+    - igbvf: Change IGBVF_MIN to allow set rx/tx value between 64 and 80
+    - igb: Change IGB_MIN to allow set rx/tx value between 64 and 80
+    - s390/zcrypt: don't leak memory if dev_set_name() fails
+    - idr: fix param name in idr_alloc_cyclic() doc
+    - ip_tunnels: use DEV_STATS_INC()
+    - net: hns3: fix the port information display when sfp is absent
+    - sh: boards: Fix CEU buffer size passed to dma_declare_coherent_memory()
+    - ata: sata_gemini: Add missing MODULE_DESCRIPTION
+    - ata: pata_ftide010: Add missing MODULE_DESCRIPTION
+    - fuse: nlookup missing decrement in fuse_direntplus_link
+    - btrfs: don't start transaction when joining with TRANS_JOIN_NOSTART
+    - btrfs: use the correct superblock to compare fsid in btrfs_validate_super
+    - mtd: rawnand: brcmnand: Fix crash during the panic_write
+    - mtd: rawnand: brcmnand: Fix potential out-of-bounds access in oob write
+    - mtd: rawnand: brcmnand: Fix potential false time out warning
+    - perf hists browser: Fix hierarchy mode header
+    - perf tools: Handle old data in PERF_RECORD_ATTR
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request payload handling
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request
+    - usb: typec: bus: verify partner exists in typec_altmode_attention
+    - ARM: dts: BCM5301X: Extend RAM to full 256MB for Linksys EA6500 V2
+    - clk: imx8mm: Move 1443X/1416X PLL clock structure to common place
+    - net: ipv4: fix one memleak in __inet_del_ifa()
+    - net: ethernet: mvpp2_main: fix possible OOB write in
+      mvpp2_ethtool_get_rxnfc()
+    - net: ethernet: mtk_eth_soc: fix possible NULL pointer dereference in
+      mtk_hwlro_get_fdir_all()
+    - r8152: check budget for r8152_poll()
+    - kcm: Fix memory leak in error path of kcm_sendmsg()
+    - platform/mellanox: mlxbf-tmfifo: Drop the Rx packet if no more descriptors
+    - mlxbf-tmfifo: sparse tags for config access
+    - platform/mellanox: mlxbf-tmfifo: Drop jumbo frames
+    - net/tls: do not free tls_rec on async operation in bpf_exec_tx_verdict()
+    - ixgbe: fix timestamp configuration code
+    - kcm: Fix error handling for SOCK_DGRAM in kcm_sendmsg().
+    - drm/amd/display: Fix a bug when searching for insert_above_mpcc
+    - parisc: Drop loops_per_jiffy from per_cpu struct
+    - autofs: fix memory leak of waitqueues in autofs_catatonic_mode
+    - btrfs: output extra debug info if we failed to find an inline backref
+    - locks: fix KASAN: use-after-free in trace_event_raw_event_filelock_lock
+    - ACPICA: Add AML_NO_OPERAND_RESOLVE flag to Timer
+    - kernel/fork: beware of __put_task_struct() calling context
+    - ACPI: video: Add backlight=native DMI quirk for Lenovo Ideapad Z470
+    - perf/smmuv3: Enable HiSilicon Erratum 162001900 quirk for HIP08/09
+    - hw_breakpoint: fix single-stepping when using bpf_overflow_handler
+    - devlink: remove reload failed checks in params get/set callbacks
+    - wifi: ath9k: fix printk specifier
+    - wifi: mwifiex: fix fortify warning
+    - crypto: lib/mpi - avoid null pointer deref in mpi_cmp_ui()
+    - tpm_tis: Resend command to recover from data transfer errors
+    - mmc: sdhci-esdhc-imx: improve ESDHC_FLAG_ERR010450
+    - alx: fix OOB-read compiler warning
+    - wifi: mac80211_hwsim: drop short frames
+    - drm/exynos: fix a possible null-pointer dereference due to data race in
+      exynos_drm_crtc_atomic_disable()
+    - bus: ti-sysc: Configure uart quirks for k3 SoC
+    - md: raid1: fix potential OOB in raid1_remove_disk()
+    - ext2: fix datatype of block number in ext2_xattr_set2()
+    - fs/jfs: prevent double-free in dbUnmount() after failed jfs_remount()
+    - jfs: fix invalid free of JFS_IP(ipimap)->i_imap in diUnmount
+    - powerpc/pseries: fix possible memory leak in ibmebus_bus_init()
+    - media: dvb-usb-v2: af9035: Fix null-ptr-deref in af9035_i2c_master_xfer
+    - media: dw2102: Fix null-ptr-deref in dw2102_i2c_transfer()
+    - media: af9005: Fix null-ptr-deref in af9005_i2c_xfer
+    - media: anysee: fix null-ptr-deref in anysee_master_xfer
+    - media: az6007: Fix null-ptr-deref in az6007_i2c_xfer()
+    - media: tuners: qt1010: replace BUG_ON with a regular error
+    - media: pci: cx23885: replace BUG with error return
+    - usb: gadget: fsl_qe_udc: validate endpoint index for ch9 udc
+    - scsi: target: iscsi: Fix buffer overflow in lio_target_nacl_info_show()
+    - serial: cpm_uart: Avoid suspicious locking
+    - media: pci: ipu3-cio2: Initialise timing struct to avoid a compiler warning
+    - kobject: Add sanity check for kset->kobj.ktype in kset_register()
+    - tools features: Add feature test to check if libbfd has buildid support
+    - perf jevents: Make build dependency on test JSONs
+    - perf tools: Add an option to build without libbfd
+    - btrfs: move btrfs_pinned_by_swapfile prototype into volumes.h
+    - btrfs: add a helper to read the superblock metadata_uuid
+    - btrfs: compare the correct fsid/metadata_uuid in btrfs_validate_super
+    - selftests: tracing: Fix to unmount tracefs for recovering environment
+    - md/raid1: fix error: ISO C90 forbids mixed declarations
+    - attr: block mode changes of symlinks
+    - btrfs: fix lockdep splat and potential deadlock after failure running
+      delayed items
+    - tracing: Have current_trace inc the trace array ref count
+    - tracing: Have option files inc the trace array ref count
+    - nfsd: fix change_info in NFSv4 RENAME replies
+    - tracefs: Add missing lockdown check to tracefs_create_dir()
+    - i2c: aspeed: Reset the i2c controller when timeout occurs
+    - scsi: megaraid_sas: Fix deadlock on firmware crashdump
+    - ext4: fix rec_len verify error
+    - mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
+    - drm/amdgpu: fix amdgpu_cs_p1_user_fence
+    - Linux 5.4.257
+
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284) //
+    CVE-2023-39189
+    - netfilter: nfnetlink_osf: avoid OOB read
+
+  * CVE-2023-45871
+    - igb: set max size RX buffer when store bad packet is enabled
+
+  * CVE-2023-39193
+    - netfilter: xt_sctp: validate the flag_info count
+
+  * CVE-2023-39192
+    - netfilter: xt_u32: validate user space input
+
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+
+  * CVE-2023-5717
+    - perf: Disallow mis-matched inherited group reads
+
+  * CVE-2023-5178
+    - nvmet-tcp: move send/recv error handling in the send/recv methods instead of
+      call-sites
+    - nvmet-tcp: Fix a possible UAF in queue intialization setup
+
+  * CVE-2023-42754
+    - ipv4: fix null-deref in ipv4_link_failure
+
+  * Focal update: v5.4.256 upstream stable release (LP: #2039446)
+    - powerpc/pmac/smp: Avoid unused-variable warnings
+    - powerpc/pmac/smp: Drop unnecessary volatile qualifier
+    - Revert "MIPS: Alchemy: fix dbdma2"
+    - Linux 5.4.256
+
+  * Focal update: v5.4.255 upstream stable release (LP: #2039440)
+    - mmc: sdhci_f_sdh30: convert to devm_platform_ioremap_resource
+    - mmc: sdhci-f-sdh30: Replace with sdhci_pltfm
+    - selftests: forwarding: tc_flower: Relax success criterion
+    - macsec: Fix traffic counters/statistics
+    - macsec: use DEV_STATS_INC()
+    - drm/radeon: Fix integer overflow in radeon_cs_parser_init
+    - ALSA: emu10k1: roll up loops in DSP setup code for Audigy
+    - quota: Properly disable quotas when add_dquot_ref() fails
+    - quota: fix warning in dqgrab()
+    - HID: add quirk for 03f0:464a HP Elite Presenter Mouse
+    - ovl: check type and offset of struct vfsmount in ovl_entry
+    - udf: Fix uninitialized array access for some pathnames
+    - fs: jfs: Fix UBSAN: array-index-out-of-bounds in dbAllocDmapLev
+    - MIPS: dec: prom: Address -Warray-bounds warning
+    - FS: JFS: Fix null-ptr-deref Read in txBegin
+    - FS: JFS: Check for read-only mounted filesystem in txBegin
+    - media: v4l2-mem2mem: add lock to protect parameter num_rdy
+    - media: platform: mediatek: vpu: fix NULL ptr dereference
+    - usb: chipidea: imx: don't request QoS for imx8ulp
+    - gfs2: Fix possible data races in gfs2_show_options()
+    - pcmcia: rsrc_nonstatic: Fix memory leak in nonstatic_release_resource_db()
+    - Bluetooth: L2CAP: Fix use-after-free
+    - drm/amdgpu: Fix potential fence use-after-free v2
+    - ALSA: hda/realtek: Add quirks for Unis H3C Desktop B760 & Q760
+    - ALSA: hda: fix a possible null-pointer dereference due to data race in
+      snd_hdac_regmap_sync()
+    - powerpc/kasan: Disable KCOV in KASAN code
+    - IMA: allow/fix UML builds
+    - iio: add addac subdirectory
+    - iio: adc: stx104: Utilize iomap interface
+    - iio: adc: stx104: Implement and utilize register structures
+    - iio: stx104: Move to addac subdirectory
+    - iio: addac: stx104: Fix race condition for stx104_write_raw()
+    - iio: addac: stx104: Fix race condition when converting analog-to-digital
+    - iommu/amd: Fix "Guest Virtual APIC Table Root Pointer" configuration in IRTE
+    - PM-runtime: add tracepoints for usage_count changes
+    - PM: runtime: Add pm_runtime_get_if_active()
+    - ALSA: hda: Fix unhandled register update during auto-suspend period
+    - irqchip/mips-gic: Get rid of the reliance on irq_cpu_online()
+    - irqchip/mips-gic: Use raw spinlock for gic_lock
+    - interconnect: Move internal structs into a separate file
+    - interconnect: Add helpers for enabling/disabling a path
+    - usb: dwc3: qcom: Add helper functions to enable,disable wake irqs
+    - USB: dwc3: qcom: fix NULL-deref on suspend
+    - mmc: bcm2835: fix deferred probing
+    - mmc: sunxi: fix deferred probing
+    - leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on dev rename
+    - tracing/probes: Have process_fetch_insn() take a void * instead of pt_regs
+    - tracing/probes: Fix to update dynamic data counter if fetcharg uses it
+    - net/ncsi: Fix gma flag setting after response
+    - nfsd4: kill warnings on testing stateids with mismatched clientids
+    - nfsd: Remove incorrect check in nfsd4_validate_stateid
+    - virtio-mmio: convert to devm_platform_ioremap_resource
+    - virtio-mmio: Use to_virtio_mmio_device() to simply code
+    - virtio-mmio: don't break lifecycle of vm_dev
+    - i2c: bcm-iproc: Fix bcm_iproc_i2c_isr deadlock issue
+    - fbdev: mmp: fix value check in mmphw_probe()
+    - powerpc/rtas_flash: allow user copy to flash block cache objects
+    - tty: serial: fsl_lpuart: Clear the error flags by writing 1 for lpuart32
+      platforms
+    - btrfs: fix BUG_ON condition in btrfs_cancel_balance
+    - net: xfrm: Fix xfrm_address_filter OOB read
+    - net: af_key: fix sadb_x_filter validation
+    - xfrm: interface: rename xfrm_interface.c to xfrm_interface_core.c
+    - xfrm: fix slab-use-after-free in decode_session6
+    - ip6_vti: fix slab-use-after-free in decode_session6
+    - ip_vti: fix potential slab-use-after-free in decode_session6
+    - selftests: mirror_gre_changes: Tighten up the TTL test match
+    - ipvs: fix racy memcpy in proc_do_sync_threshold
+    - netfilter: nft_dynset: disallow object maps
+    - team: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - i40e: fix misleading debug logs
+    - net: dsa: mv88e6xxx: Wait for EEPROM done before HW reset
+    - sock: Fix misuse of sk_under_memory_pressure()
+    - net: do not allow gso_size to be set to GSO_BY_FRAGS
+    - bus: ti-sysc: Improve reset to work with modules with no sysconfig
+    - bus: ti-sysc: Flush posted write on enable before reset
+    - ARM: dts: imx7s: Drop dma-apb interrupt-names
+    - ARM: dts: imx: Adjust dma-apbh node name
+    - ARM: dts: imx: Set default tuning step for imx7d usdhc
+    - ARM: dts: imx: Set default tuning step for imx6sx usdhc
+    - ASoC: rt5665: add missed regulator_bulk_disable
+    - ASoC: meson: axg-tdm-formatter: fix channel slot allocation
+    - serial: 8250: Fix oops for port->pm on uart_change_pm()
+    - ALSA: usb-audio: Add support for Mythware XA001AU capture and playback
+      interfaces.
+    - cifs: Release folio lock on fscache read hit.
+    - mmc: wbsd: fix double mmc_free_host() in wbsd_init()
+    - mmc: block: Fix in_flight[issue_type] value error
+    - netfilter: set default timeout to 3 secs for sctp shutdown send and recv
+      state
+    - virtio-net: set queues after driver_ok
+    - net: fix the RTO timer retransmitting skb every 1ms if linear option is
+      enabled
+    - net: xfrm: Amend XFRMA_SEC_CTX nla_policy structure
+    - mmc: f-sdh30: fix order of function calls in sdhci_f_sdh30_remove
+    - net: phy: broadcom: stub c45 read/write for 54810
+    - PCI: acpiphp: Reassign resources on bridge if necessary
+    - dlm: improve plock logging if interrupted
+    - dlm: replace usage of found with dedicated list iterator variable
+    - fs: dlm: add pid to debug log
+    - fs: dlm: change plock interrupted message to debug again
+    - fs: dlm: use dlm_plock_info for do_unlock_close
+    - fs: dlm: fix mismatch of plock results from userspace
+    - MIPS: cpu-features: Enable octeon_cache by cpu_type
+    - MIPS: cpu-features: Use boot_cpu_type for CPU type based features
+    - fbdev: Improve performance of sys_imageblit()
+    - fbdev: Fix sys_imageblit() for arbitrary image widths
+    - fbdev: fix potential OOB read in fast_imageblit()
+    - dm integrity: increase RECALC_SECTORS to improve recalculate speed
+    - dm integrity: reduce vmalloc space footprint on 32-bit architectures
+    - ALSA: pcm: Set per-card upper limit of PCM buffer allocations
+    - ALSA: pcm: Use SG-buffer only when direct DMA is available
+    - ALSA: pcm: Fix potential data race at PCM memory allocation helpers
+    - regmap: Account for register length in SMBus I/O limits
+    - ASoC: fsl_sai: Refine enable/disable TE/RE sequence in trigger()
+    - ASoC: fsl_sai: Add new added registers and new bit definition
+    - ASoC: fsl_sai: Disable bit clock with transmitter
+    - drm/amd/display: do not wait for mpc idle if tg is disabled
+    - drm/amd/display: check TG is non-null before checking if enabled
+    - tracing: Fix memleak due to race between current_tracer and trace
+    - octeontx2-af: SDP: fix receive link config
+    - sock: annotate data-races around prot->memory_pressure
+    - dccp: annotate data-races in dccp_poll()
+    - ipvlan: Fix a reference count leak warning in ipvlan_ns_exit()
+    - net: bgmac: Fix return value check for fixed_phy_register()
+    - net: bcmgenet: Fix return value check for fixed_phy_register()
+    - net: validate veth and vxcan peer ifindexes
+    - igb: Avoid starting unnecessary workqueues
+    - net/sched: fix a qdisc modification with ambiguous command request
+    - net: remove bond_slave_has_mac_rcu()
+    - bonding: fix macvlan over alb bond support
+    - ibmveth: Use dcbf rather than dcbfl
+    - NFSv4: Fix dropped lock for racing OPEN and delegation return
+    - clk: Fix slab-out-of-bounds error in devm_clk_release()
+    - nfsd: Fix race to FREE_STATEID and cl_revoked
+    - batman-adv: Trigger events for auto adjusted MTU
+    - batman-adv: Don't increase MTU when set by user
+    - batman-adv: Do not get eth header before batadv_check_management_packet
+    - batman-adv: Fix TT global entry leak when client roamed back
+    - batman-adv: Fix batadv_v_ogm_aggr_send memory leak
+    - batman-adv: Hold rtnl lock during MTU update via netlink
+    - lib/clz_ctz.c: Fix __clzdi2() and __ctzdi2() for 32-bit kernels
+    - radix tree: remove unused variable
+    - media: vcodec: Fix potential array out-of-bounds in encoder queue_setup
+    - PCI: acpiphp: Use pci_assign_unassigned_bridge_resources() only for non-root
+      bus
+    - drm/display/dp: Fix the DP DSC Receiver cap size
+    - mm: allow a controlled amount of unfairness in the page lock
+    - rtnetlink: Reject negative ifindexes in RTM_NEWLINK
+    - ALSA: pcm: Fix build error on m68k and others
+    - Revert "ALSA: pcm: Use SG-buffer only when direct DMA is available"
+    - interconnect: Do not skip aggregation for disabled paths
+    - ALSA: pcm: Check for null pointer of pointer substream before dereferencing
+      it
+    - Documentation/sysctl: document page_lock_unfairness
+    - irqchip/mips-gic: Don't touch vl_map if a local interrupt is not routable
+    - scsi: snic: Fix double free in snic_tgt_create()
+    - scsi: core: raid_class: Remove raid_component_add()
+    - clk: Fix undefined reference to `clk_rate_exclusive_{get,put}'
+    - pinctrl: renesas: rza2: Add lock around
+      pinctrl_generic{{add,remove}_group,{add,remove}_function}
+    - dma-buf/sw_sync: Avoid recursive lock during fence signal
+    - Linux 5.4.255
+
+  * Focal update: v5.4.254 upstream stable release (LP: #2039291)
+    - mmc: moxart: read scr register without changing byte order
+    - ipv6: adjust ndisc_is_useropt() to also return true for PIO
+    - dmaengine: pl330: Return DMA_PAUSED when transaction is paused
+    - drm/nouveau/gr: enable memory loads on helper invocation on all channels
+    - radix tree test suite: fix incorrect allocation size for pthreads
+    - nilfs2: fix use-after-free of nilfs_root in dirtying inodes via iput
+    - iio: cros_ec: Fix the allocation size for cros_ec_command
+    - binder: fix memory leak in binder_init()
+    - usb-storage: alauda: Fix uninit-value in alauda_check_media()
+    - usb: dwc3: Properly handle processing of pending events
+    - usb: common: usb-conn-gpio: Prevent bailing out if initial role is none
+    - x86/cpu/amd: Enable Zenbleed fix for AMD Custom APU 0405
+    - x86/mm: Fix VDSO and VVAR placement on 5-level paging machines
+    - x86: Move gds_ucode_mitigated() declaration to header
+    - drm/nouveau/disp: Revert a NULL check inside nouveau_connector_get_modes
+    - selftests/rseq: Fix build with undefined __weak
+    - mISDN: Update parameter type of dsp_cmx_send()
+    - net/packet: annotate data-races around tp->status
+    - bonding: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - dccp: fix data-race around dp->dccps_mss_cache
+    - drivers: net: prevent tun_build_skb() to exceed the packet size limit
+    - IB/hfi1: Fix possible panic during hotplug remove
+    - wifi: cfg80211: fix sband iftype data lookup for AP_VLAN
+    - dmaengine: mcf-edma: Fix a potential un-allocated memory access
+    - net/mlx5: Allow 0 for total host VFs
+    - ibmvnic: Handle DMA unmapping of login buffs in release functions
+    - btrfs: don't stop integrity writeback too early
+    - btrfs: set cache_block_group_error if we find an error
+    - nvme-tcp: fix potential unbalanced freeze & unfreeze
+    - nvme-rdma: fix potential unbalanced freeze & unfreeze
+    - netfilter: nf_tables: report use refcount overflow
+    - scsi: core: Fix legacy /proc parsing buffer overflow
+    - scsi: storvsc: Fix handling of virtual Fibre Channel timeouts
+    - scsi: 53c700: Check that command slot is not NULL
+    - scsi: snic: Fix possible memory leak if device_add() fails
+    - scsi: core: Fix possible memory leak if device_add() fails
+    - alpha: remove __init annotation from exported page_is_ram()
+    - sch_netem: fix issues in netem_change() vs get_dist_table()
+    - Linux 5.4.254
+
+  * Focal update: v5.4.253 upstream stable release (LP: #2038652)
+    - jbd2: fix incorrect code style
+    - jbd2: fix kernel-doc markups
+    - jbd2: remove redundant buffer io error checks
+    - jbd2: recheck chechpointing non-dirty buffer
+    - jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint
+    - gpio: tps68470: Make tps68470_gpio_output() always set the initial value
+    - bcache: remove 'int n' from parameter list of bch_bucket_alloc_set()
+    - bcache: Fix __bch_btree_node_alloc to make the failure behavior consistent
+    - btrfs: qgroup: catch reserved space leaks at unmount time
+    - btrfs: fix race between quota disable and relocation
+    - btrfs: fix extent buffer leak after tree mod log failure at split_node()
+    - ext4: rename journal_dev to s_journal_dev inside ext4_sb_info
+    - ext4: Fix reusing stale buffer heads from last failed mounting
+    - PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+    - PCI/ASPM: Factor out pcie_wait_for_retrain()
+    - PCI/ASPM: Avoid link retraining race
+    - dlm: cleanup plock_op vs plock_xop
+    - dlm: rearrange async condition return
+    - fs: dlm: interrupt posix locks only when process is killed
+    - ftrace: Add information on number of page groups allocated
+    - ftrace: Check if pages were allocated before calling free_pages()
+    - ftrace: Store the order of pages allocated in ftrace_page
+    - ftrace: Fix possible warning on checking all pages used in
+      ftrace_process_locs()
+    - pwm: meson: Remove redundant assignment to variable fin_freq
+    - pwm: meson: Simplify duplicated per-channel tracking
+    - pwm: meson: fix handling of period/duty if greater than UINT_MAX
+    - scsi: qla2xxx: Fix inconsistent format argument type in qla_os.c
+    - scsi: qla2xxx: Array index may go out of bound
+    - uapi: General notification queue definitions
+    - keys: Fix linking a duplicate key to a keyring's assoc_array
+    - ext4: fix to check return value of freeze_bdev() in ext4_shutdown()
+    - i40e: Fix an NULL vs IS_ERR() bug for debugfs_create_dir()
+    - vxlan: calculate correct header length for GPE
+    - phy: hisilicon: Fix an out of bounds check in hisi_inno_phy_probe()
+    - ethernet: atheros: fix return value check in atl1e_tso_csum()
+    - ipv6 addrconf: fix bug where deleting a mngtmpaddr can create a new
+      temporary address
+    - bonding: reset bond's flags when down link is P2P device
+    - team: reset team's flags when down link is P2P device
+    - platform/x86: msi-laptop: Fix rfkill out-of-sync on MSI Wind U100
+    - net/sched: mqprio: refactor nlattr parsing to a separate function
+    - net/sched: mqprio: add extack to mqprio_parse_nlattr()
+    - net/sched: mqprio: Add length check for TCA_MQPRIO_{MAX/MIN}_RATE64
+    - benet: fix return value check in be_lancer_xmit_workarounds()
+    - RDMA/mlx4: Make check for invalid flags stricter
+    - drm/msm/dpu: drop enum dpu_core_perf_data_bus_id
+    - drm/msm/adreno: Fix snapshot BINDLESS_DATA size
+    - drm/msm: Fix IS_ERR_OR_NULL() vs NULL check in a5xx_submit_in_rb()
+    - ASoC: fsl_spdif: Silence output on stop
+    - block: Fix a source code comment in include/uapi/linux/blkzoned.h
+    - dm raid: fix missing reconfig_mutex unlock in raid_ctr() error paths
+    - ata: pata_ns87415: mark ns87560_tf_read static
+    - ring-buffer: Fix wrong stat of cpu_buffer->read
+    - tracing: Fix warning in trace_buffered_event_disable()
+    - serial: 8250_dw: Preserve original value of DLF register
+    - serial: sifive: Fix sifive_serial_console_setup() section
+    - USB: serial: option: support Quectel EM060K_128
+    - USB: serial: option: add Quectel EC200A module support
+    - USB: serial: simple: add Kaufmann RKS+CAN VCP
+    - USB: serial: simple: sort driver entries
+    - can: gs_usb: gs_can_close(): add missing set of CAN state to
+      CAN_STATE_STOPPED
+    - Revert "usb: dwc3: core: Enable AutoRetry feature in the controller"
+    - usb: dwc3: pci: skip BYT GPIO lookup table for hardwired phy
+    - usb: dwc3: don't reset device side if dwc3 was configured as host-only
+    - usb: ohci-at91: Fix the unhandle interrupt when resume
+    - USB: quirks: add quirk for Focusrite Scarlett
+    - usb: xhci-mtk: set the dma max_seg_size
+    - Revert "usb: xhci: tegra: Fix error check"
+    - Documentation: security-bugs.rst: update preferences when dealing with the
+      linux-distros group
+    - Documentation: security-bugs.rst: clarify CVE handling
+    - staging: ks7010: potential buffer overflow in ks_wlan_set_encode_ext()
+    - hwmon: (nct7802) Fix for temp6 (PECI1) processed even if PECI1 disabled
+    - btrfs: check for commit error at btrfs_attach_transaction_barrier()
+    - tpm_tis: Explicitly check for error code
+    - irq-bcm6345-l1: Do not assume a fixed block to cpu mapping
+    - btrfs: check if the transaction was aborted at btrfs_wait_for_commit()
+    - virtio-net: fix race between set queues and probe
+    - s390/dasd: fix hanging device after quiesce/resume
+    - ASoC: wm8904: Fill the cache for WM8904_ADC_TEST_0 register
+    - dm cache policy smq: ensure IO doesn't prevent cleaner policy progress
+    - ACPI: processor: perflib: Use the "no limit" frequency QoS
+    - ACPI: processor: perflib: Avoid updating frequency QoS unnecessarily
+    - cpufreq: intel_pstate: Drop ACPI _PSS states table patching
+    - btrfs: qgroup: remove one-time use variables for quota_root checks
+    - btrfs: qgroup: return ENOTCONN instead of EINVAL when quotas are not enabled
+    - ASoC: cs42l51: fix driver to properly autoload with automatic module loading
+    - arm64: Add AMPERE1 to the Spectre-BHB affected list
+    - arm64: Fix bit-shifting UB in the MIDR_CPU_MODEL() macro
+    - perf: Fix function pointer case
+    - loop: Select I/O scheduler 'none' from inside add_disk()
+    - word-at-a-time: use the same return type for has_zero regardless of
+      endianness
+    - KVM: s390: fix sthyi error handling
+    - net/mlx5: DR, fix memory leak in mlx5dr_cmd_create_reformat_ctx
+    - net/mlx5e: fix return value check in mlx5e_ipsec_remove_trailer()
+    - rtnetlink: let rtnl_bridge_setlink checks IFLA_BRIDGE_MODE length
+    - perf test uprobe_from_different_cu: Skip if there is no gcc
+    - net: sched: cls_u32: Fix match key mis-addressing
+    - mISDN: hfcpci: Fix potential deadlock on &hc->lock
+    - net: annotate data-races around sk->sk_max_pacing_rate
+    - net: add missing READ_ONCE(sk->sk_rcvlowat) annotation
+    - net: add missing READ_ONCE(sk->sk_sndbuf) annotation
+    - net: add missing READ_ONCE(sk->sk_rcvbuf) annotation
+    - net: add missing data-race annotations around sk->sk_peek_off
+    - net: add missing data-race annotation for sk_ll_usec
+    - bpf: sockmap: Remove preempt_disable in sock_map_sk_acquire
+    - driver core: add device probe log helper
+    - net: ll_temac: Switch to use dev_err_probe() helper
+    - net: ll_temac: fix error checking of irq_of_parse_and_map()
+    - net: dcb: choose correct policy to parse DCB_ATTR_BCN
+    - ip6mr: Fix skb_under_panic in ip6mr_cache_report()
+    - tcp_metrics: fix addr_same() helper
+    - tcp_metrics: annotate data-races around tm->tcpm_stamp
+    - tcp_metrics: annotate data-races around tm->tcpm_lock
+    - tcp_metrics: annotate data-races around tm->tcpm_vals[]
+    - tcp_metrics: annotate data-races around tm->tcpm_net
+    - tcp_metrics: fix data-race in tcpm_suck_dst() vs fastopen
+    - scsi: zfcp: Defer fc_rport blocking until after ADISC response
+    - libceph: fix potential hang in ceph_osdc_notify()
+    - USB: zaurus: Add ID for A-300/B-500/C-700
+    - mtd: spinand: toshiba: Fix ecc_get_status
+    - mtd: rawnand: meson: fix OOB available bytes for ECC
+    - fs/sysv: Null check to prevent null-ptr-deref bug
+    - net: usbnet: Fix WARNING in usbnet_start_xmit/usb_submit_urb
+    - fs: Protect reconfiguration of sb read-write from racing writes
+    - ext2: Drop fragment support
+    - test_firmware: prevent race conditions by a correct implementation of
+      locking
+    - test_firmware: return ENOMEM instead of ENOSPC on failed memory allocation
+    - mtd: rawnand: omap_elm: Fix incorrect type in assignment
+    - powerpc/mm/altmap: Fix altmap boundary check
+    - selftests/rseq: check if libc rseq support is registered
+    - selftests/rseq: Play nice with binaries statically linked against glibc
+      2.35+
+    - PM / wakeirq: support enabling wake-up irq after runtime_suspend called
+    - PM: sleep: wakeirq: fix wake irq arming
+    - ceph: show tasks waiting on caps in debugfs caps file
+    - ceph: use kill_anon_super helper
+    - ceph: defer stopping mdsc delayed_work
+    - arm64: dts: stratix10: fix incorrect I2C property for SCL signal
+    - ARM: dts: imx6sll: Make ssi node name same as other platforms
+    - ARM: dts: imx: Align L2 cache-controller nodename with dtschema
+    - ARM: dts: imx: add usb alias
+    - ARM: dts: imx6sll: fixup of operating points
+    - ARM: dts: nxp/imx6sll: fix wrong property name in usbphy node
+    - driver core: Annotate dev_err_probe() with __must_check
+    - driver code: print symbolic error code
+    - drivers: core: fix kernel-doc markup for dev_err_probe()
+    - Revert "driver core: Annotate dev_err_probe() with __must_check"
+    - Linux 5.4.253
+    - Upstream stable to v5.4.253
+
+  * CVE-2023-37453
+    - USB: hub: Clean up use of port initialization schemes and retries
+    - USB: hub: Add Kconfig option to reduce number of port initialization retries
+    - USB: core: Unite old scheme and new scheme descriptor reads
+    - usb: hub: Check device descriptor before resusciation
+    - USB: core: Change usb_get_device_descriptor() API
+    - USB: core: Fix race by not overwriting udev->descriptor in hub_port_init()
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Mon, 30 Oct 2023 11:52:53 +0100
+
+linux (5.4.0-166.183) focal; urgency=medium
+
+  * focal/linux: 5.4.0-166.183 -proposed tracker (LP: #2038010)
+
+  * Use new annotations model (LP: #2019000)
+    - [Packaging] new annotations model infrastructure
+    - [Packaging] config-check: Handle new annotations format 4
+    - [Packaging] rules: Use old-kernelconfig for old configs
+    - [Config] sanitize annotations
+    - [Config] import generated configs into annotation file
+    - [Packaging] kernelconfig: add i386 as supported arch
+    - [Config] Remove all old configs files
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] update annotations scripts
+
+  * fix typo in config-checks invocation (LP: #2020413)
+    - [Packaging] fix typo when calling the old config-check
+    - [Packaging] fix typo in 4-checks.mk
+
+  * support python < 3.9 with annotations (LP: #2020531)
+    - [Packaging] kconfig/annotations.py: support older way of merging dicts
+
+  * CVE-2023-42756
+    - netfilter: ipset: Fix race between IPSET_CMD_CREATE and IPSET_CMD_SWAP
+
+  * CVE-2023-4623
+    - net/sched: sch_hfsc: Ensure inner classes have fsc curve
+
+  * Focal update: v5.4.252 upstream stable release (LP: #2036240)
+    - ia64/cpu: Switch to arch_cpu_finalize_init()
+    - m68k/cpu: Switch to arch_cpu_finalize_init()
+    - mips/cpu: Switch to arch_cpu_finalize_init()
+    - sh/cpu: Switch to arch_cpu_finalize_init()
+    - x86/cpufeatures: Add SEV-ES CPU feature
+    - x86/cpu: Add VM page flush MSR availablility as a CPUID feature
+    - x86/cpufeatures: Assign dedicated feature word for CPUID_0x8000001F[EAX]
+    - tools headers cpufeatures: Sync with the kernel sources
+    - x86/cpu, kvm: Add support for CPUID_80000021_EAX
+    - Linux 5.4.252
+    - Upstream stable to v5.4.252
+
+  * CVE-2023-42755
+    - net/sched: Retire rsvp classifier
+    - [Config] remove NET_CLS_RSVP and NET_CLS_RSVP6
+
+  * CVE-2023-42753
+    - netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for
+      ip_set_hash_netportnet.c
+
+  * CVE-2023-34319
+    - xen/netback: Fix buffer overrun triggered by unusual packet
+
+  * CVE-2023-4921
+    - net: sched: sch_qfq: Fix UAF in qfq_dequeue()
+
+  * CVE-2023-42752
+    - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU
+
+  * Avoid address overwrite in kernel_connect (LP: #2035163)
+    - net: Avoid address overwrite in kernel_connect
+
+  * [regression] Unable to initialize SGX enclaves with XFRM other than 3
+    (LP: #2034745)
+    - x86/fpu: Set X86_FEATURE_OSXSAVE feature after enabling OSXSAVE in CR4
+
+  * 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().
+
+  * Focal update: v5.4.251 upstream stable release (LP: #2034918)
+    - x86/smp: Use dedicated cache-line for mwait_play_dead()
+    - video: imsttfb: check for ioremap() failures
+    - fbdev: imsttfb: Fix use after free bug in imsttfb_probe
+    - HID: wacom: Use ktime_t rather than int when dealing with timestamps
+    - drm/i915: Initialise outparam for error return from wait_for_register
+    - scripts/tags.sh: Resolve gtags empty index generation
+    - drm/amdgpu: Validate VM ioctl flags.
+    - bgmac: fix *initial* chip reset to support BCM5358
+    - x86/resctrl: Use is_closid_match() in more places
+    - x86/resctrl: Only show tasks' pid in current pid namespace
+    - md/raid10: check slab-out-of-bounds in md_bitmap_get_counter
+    - md/raid10: fix overflow of md/safe_mode_delay
+    - md/raid10: fix wrong setting of max_corr_read_errors
+    - md/raid10: fix null-ptr-deref of mreplace in raid10_sync_request
+    - md/raid10: fix io loss while replacement replace rdev
+    - irqchip/jcore-aic: Kill use of irq_create_strict_mappings()
+    - irqchip/jcore-aic: Fix missing allocation of IRQ descriptors
+    - tracing/timer: Add missing hrtimer modes to decode_hrtimer_mode().
+    - clocksource/drivers/cadence-ttc: Use ttc driver as platform driver
+    - clocksource/drivers/cadence-ttc: Fix memory leak in ttc_timer_probe
+    - PM: domains: fix integer overflow issues in genpd_parse_state()
+    - powercap: RAPL: Fix CONFIG_IOSF_MBI dependency
+    - ARM: 9303/1: kprobes: avoid missing-declaration warnings
+    - evm: Complete description of evm_inode_setattr()
+    - pstore/ram: Add check for kstrdup
+    - ima: Fix build warnings
+    - wifi: ath9k: fix AR9003 mac hardware hang check register offset calculation
+    - wifi: ath9k: avoid referencing uninit memory in ath9k_wmi_ctrl_rx
+    - samples/bpf: Fix buffer overflow in tcp_basertt
+    - spi: spi-geni-qcom: Correct CS_TOGGLE bit in SPI_TRANS_CFG
+    - wifi: mwifiex: Fix the size of a memory allocation in
+      mwifiex_ret_802_11_scan()
+    - nfc: constify several pointers to u8, char and sk_buff
+    - nfc: llcp: fix possible use of uninitialized variable in
+      nfc_llcp_send_connect()
+    - regulator: core: Fix more error checking for debugfs_create_dir()
+    - regulator: core: Streamline debugfs operations
+    - wifi: orinoco: Fix an error handling path in spectrum_cs_probe()
+    - wifi: orinoco: Fix an error handling path in orinoco_cs_probe()
+    - wifi: atmel: Fix an error handling path in atmel_probe()
+    - wl3501_cs: Fix a bunch of formatting issues related to function docs
+    - wl3501_cs: Remove unnecessary NULL check
+    - wl3501_cs: Fix misspelling and provide missing documentation
+    - net: create netdev->dev_addr assignment helpers
+    - wl3501_cs: use eth_hw_addr_set()
+    - wifi: wl3501_cs: Fix an error handling path in wl3501_probe()
+    - wifi: ray_cs: Utilize strnlen() in parse_addr()
+    - wifi: ray_cs: Drop useless status variable in parse_addr()
+    - wifi: ray_cs: Fix an error handling path in ray_probe()
+    - wifi: ath9k: don't allow to overwrite ENDPOINT0 attributes
+    - wifi: rsi: Do not set MMC_PM_KEEP_POWER in shutdown
+    - watchdog/perf: define dummy watchdog_update_hrtimer_threshold() on correct
+      config
+    - watchdog/perf: more properly prevent false positives with turbo modes
+    - kexec: fix a memory leak in crash_shrink_memory()
+    - memstick r592: make memstick_debug_get_tpc_name() static
+    - wifi: ath9k: Fix possible stall on ath9k_txq_list_has_key()
+    - rtnetlink: extend RTEXT_FILTER_SKIP_STATS to IFLA_VF_INFO
+    - wifi: iwlwifi: pull from TXQs with softirqs disabled
+    - wifi: cfg80211: rewrite merging of inherited elements
+    - wifi: ath9k: convert msecs to jiffies where needed
+    - netlink: fix potential deadlock in netlink_set_err()
+    - netlink: do not hard code device address lenth in fdb dumps
+    - selftests: rtnetlink: remove netdevsim device after ipsec offload test
+    - gtp: Fix use-after-free in __gtp_encap_destroy().
+    - lib/ts_bm: reset initial match offset for every block of text
+    - netfilter: conntrack: dccp: copy entire header to stack buffer, not just
+      basic one
+    - netfilter: nf_conntrack_sip: fix the ct_sip_parse_numerical_param() return
+      value.
+    - ipvlan: Fix return value of ipvlan_queue_xmit()
+    - netlink: Add __sock_i_ino() for __netlink_diag_dump().
+    - radeon: avoid double free in ci_dpm_init()
+    - Input: drv260x - sleep between polling GO bit
+    - ARM: dts: BCM5301X: Drop "clock-names" from the SPI node
+    - Input: adxl34x - do not hardcode interrupt trigger type
+    - drm: sun4i_tcon: use devm_clk_get_enabled in `sun4i_tcon_init_clocks`
+    - RDMA/bnxt_re: Fix to remove an unnecessary log
+    - ARM: dts: gta04: Move model property out of pinctrl node
+    - arm64: dts: qcom: msm8916: correct camss unit address
+    - drm/panel: simple: fix active size for Ampire AM-480272H3TMQW-T01H
+    - ARM: ep93xx: fix missing-prototype warnings
+    - memory: brcmstb_dpfe: fix testing array offset after use
+    - ASoC: es8316: Increment max value for ALC Capture Target Volume control
+    - ASoC: es8316: Do not set rate constraints for unsupported MCLKs
+    - soc/fsl/qe: fix usb.c build errors
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one errors
+    - arm64: dts: renesas: ulcb-kf: Remove flow control for SCIF1
+    - fbdev: omapfb: lcd_mipid: Fix an error handling path in mipid_spi_probe()
+    - drm/amdkfd: Fix potential deallocation of previously deallocated memory.
+    - drm/radeon: fix possible division-by-zero errors
+    - clk: tegra: tegra124-emc: Fix potential memory leak
+    - ALSA: ac97: Fix possible NULL dereference in snd_ac97_mixer
+    - clk: cdce925: check return value of kasprintf()
+    - clk: keystone: sci-clk: check return value of kasprintf()
+    - ASoC: imx-audmix: check return value of devm_kasprintf()
+    - scsi: qedf: Fix NULL dereference in error handling
+    - PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free
+    - scsi: 3w-xxxx: Add error handling for initialization failure in tw_probe()
+    - PCI: pciehp: Cancel bringup sequence if card is not present
+    - PCI: ftpci100: Release the clock resources
+    - PCI: Add pci_clear_master() stub for non-CONFIG_PCI
+    - pinctrl: cherryview: Return correct value if pin in push-pull mode
+    - perf dwarf-aux: Fix off-by-one in die_get_varname()
+    - pinctrl: at91-pio4: check return value of devm_kasprintf()
+    - powerpc/mm/dax: Fix the condition when checking if altmap vmemap can cross-
+      boundary
+    - hwrng: virtio - add an internal buffer
+    - hwrng: virtio - don't wait on cleanup
+    - hwrng: virtio - don't waste entropy
+    - hwrng: virtio - always add a pending request
+    - hwrng: virtio - Fix race on data_avail and actual data
+    - crypto: nx - fix build warnings when DEBUG_FS is not enabled
+    - modpost: fix section mismatch message for R_ARM_ABS32
+    - modpost: fix section mismatch message for R_ARM_{PC24,CALL,JUMP24}
+    - crypto: marvell/cesa - Fix type mismatch warning
+    - modpost: fix off by one in is_executable_section()
+    - ARC: define ASM_NL and __ALIGN(_STR) outside #ifdef __ASSEMBLY__ guard
+    - NFSv4.1: freeze the session table upon receiving NFS4ERR_BADSESSION
+    - hwrng: st - Fix W=1 unused variable warning
+    - hwrng: st - keep clock enabled while hwrng is registered
+    - USB: serial: option: add LARA-R6 01B PIDs
+    - usb: dwc3: gadget: Propagate core init errors to UDC during pullup
+    - block: fix signed int overflow in Amiga partition support
+    - block: change all __u32 annotations to __be32 in affs_hardblocks.h
+    - w1: fix loop in w1_fini()
+    - sh: j2: Use ioremap() to translate device tree address into kernel memory
+    - media: usb: Check az6007_read() return value
+    - media: videodev2.h: Fix struct v4l2_input tuner index comment
+    - usb: dwc3: qcom: Fix potential memory leak
+    - extcon: Fix kernel doc of property fields to avoid warnings
+    - extcon: Fix kernel doc of property capability fields to avoid warnings
+    - usb: phy: phy-tahvo: fix memory leak in tahvo_usb_probe()
+    - usb: hide unused usbfs_notify_suspend/resume functions
+    - mfd: rt5033: Drop rt5033-battery sub-device
+    - KVM: s390: fix KVM_S390_GET_CMMA_BITS for GFNs in memslot holes
+    - usb: dwc3: qcom: Release the correct resources in dwc3_qcom_remove()
+    - mfd: intel-lpss: Add missing check for platform_get_resource
+    - serial: 8250_omap: Use force_suspend and resume for system suspend
+    - mfd: stmfx: Fix error path in stmfx_chip_init
+    - KVM: s390: vsie: fix the length of APCB bitmap
+    - mfd: stmpe: Only disable the regulators if they are enabled
+    - pwm: imx-tpm: force 'real_period' to be zero in suspend
+    - pwm: sysfs: Do not apply state to already disabled PWMs
+    - rtc: st-lpc: Release some resources in st_rtc_probe() in case of error
+    - sctp: fix potential deadlock on &net->sctp.addr_wq_lock
+    - Add MODULE_FIRMWARE() for FIRMWARE_TG357766.
+    - spi: bcm-qspi: return error if neither hif_mspi nor mspi is available
+    - mailbox: ti-msgmgr: Fill non-message tx data fields with 0x0
+    - f2fs: fix error path handling in truncate_dnode()
+    - powerpc: allow PPC_EARLY_DEBUG_CPM only when SERIAL_CPM=y
+    - net: bridge: keep ports without IFF_UNICAST_FLT in BR_PROMISC mode
+    - tcp: annotate data races in __tcp_oow_rate_limited()
+    - xsk: Improve documentation for AF_XDP
+    - xsk: Honor SO_BINDTODEVICE on bind
+    - net/sched: act_pedit: Add size check for TCA_PEDIT_PARMS_EX
+    - net: dsa: tag_sja1105: fix MAC DA patching from meta frames
+    - sh: dma: Fix DMA channel offset calculation
+    - i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in xiic_process()
+    - i2c: xiic: Don't try to handle more interrupt events after error
+    - ALSA: jack: Fix mutex call in snd_jack_report()
+    - NFSD: add encoding of op_recall flag for write delegation
+    - mmc: core: disable TRIM on Kingston EMMC04G-M627
+    - mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
+    - mmc: sdhci: fix DMA configure compatibility issue when 64bit DMA mode is
+      used.
+    - bcache: Remove unnecessary NULL point check in node allocations
+    - integrity: Fix possible multiple allocation in integrity_inode_get()
+    - jffs2: reduce stack usage in jffs2_build_xattr_subsystem()
+    - fs: avoid empty option when generating legacy mount string
+    - ext4: Remove ext4 locking of moved directory
+    - Revert "f2fs: fix potential corruption when moving a directory"
+    - fs: Establish locking order for unrelated directories
+    - fs: Lock moved directories
+    - btrfs: fix race when deleting quota root from the dirty cow roots list
+    - ARM: orion5x: fix d2net gpio initialization
+    - fs: no need to check source
+    - fanotify: disallow mount/sb marks on kernel internal pseudo fs
+    - block: add overflow checks for Amiga partition support
+    - netfilter: nf_tables: fix nat hook table deletion
+    - netfilter: nftables: add helper function to set the base sequence number
+    - netfilter: add helper function to set up the nfnetlink header and use it
+    - netfilter: nf_tables: use net_generic infra for transaction data
+    - netfilter: nf_tables: add rescheduling points during loop detection walks
+    - netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound
+      set/chain
+    - netfilter: nf_tables: reject unbound anonymous set before commit phase
+    - netfilter: nf_tables: unbind non-anonymous set if rule construction fails
+    - netfilter: nf_tables: fix scheduling-while-atomic splat
+    - netfilter: conntrack: Avoid nf_ct_helper_hash uses after free
+    - tty: serial: fsl_lpuart: add earlycon for imx8ulp platform
+    - block/partition: fix signedness issue for Amiga partitions
+    - net: lan743x: Don't sleep in atomic context
+    - workqueue: clean up WORK_* constant types, clarify masking
+    - drm/panel: Initialise panel dev and funcs through drm_panel_init()
+    - drm/panel: Add and fill drm_panel type field
+    - drm/panel: simple: Add connector_type for innolux_at043tn24
+    - igc: Remove delay during TX ring configuration
+    - igc: set TP bit in 'supported' and 'advertising' fields of
+      ethtool_link_ksettings
+    - scsi: qla2xxx: Fix error code in qla2x00_start_sp()
+    - net: mvneta: fix txq_map in case of txq_number==1
+    - ionic: improve irq numa locality
+    - ionic: clean irq affinity on queue deinit
+    - ionic: move irq request to qcq alloc
+    - ionic: ionic_intr_free parameter change
+    - ionic: remove WARN_ON to prevent panic_on_warn
+    - icmp6: Fix null-ptr-deref of ip6_null_entry->rt6i_idev in icmp6_dev().
+    - udp6: fix udp6_ehashfn() typo
+    - ntb: idt: Fix error handling in idt_pci_driver_init()
+    - NTB: amd: Fix error handling in amd_ntb_pci_driver_init()
+    - ntb: intel: Fix error handling in intel_ntb_pci_driver_init()
+    - NTB: ntb_transport: fix possible memory leak while device_register() fails
+    - NTB: ntb_tool: Add check for devm_kcalloc
+    - ipv6/addrconf: fix a potential refcount underflow for idev
+    - platform/x86: wmi: Replace UUID redefinitions by their originals
+    - platform/x86: wmi: Fix indentation in some cases
+    - platform/x86: wmi: remove unnecessary argument
+    - platform/x86: wmi: use guid_t and guid_equal()
+    - platform/x86: wmi: move variables
+    - platform/x86: wmi: Break possible infinite loop when parsing GUID
+    - erofs: avoid infinite loop in z_erofs_do_read_page() when reading beyond EOF
+    - wifi: airo: avoid uninitialized warning in airo_get_rate()
+    - cls_flower: Add extack support for src and dst port range options
+    - net/sched: flower: Ensure both minimum and maximum ports are specified
+    - net/sched: make psched_mtu() RTNL-less safe
+    - pinctrl: amd: Fix mistake in handling clearing pins at startup
+    - pinctrl: amd: Detect internal GPIO0 debounce handling
+    - pinctrl: amd: Only use special debounce behavior for GPIO 0
+    - tpm: tpm_vtpm_proxy: fix a race condition in /dev/vtpmx creation
+    - mtd: rawnand: meson: fix unaligned DMA buffers handling
+    - net: bcmgenet: Ensure MDIO unregistration has clocks enabled
+    - powerpc: Fail build if using recordmcount with binutils v2.37
+    - misc: fastrpc: Create fastrpc scalar with correct buffer count
+    - SUNRPC: Fix UAF in svc_tcp_listen_data_ready()
+    - erofs: fix compact 4B support for 16k block size
+    - ext4: fix wrong unit use in ext4_mb_clear_bb
+    - ext4: only update i_reserved_data_blocks on successful block allocation
+    - jfs: jfs_dmap: Validate db_l2nbperpage while mounting
+    - PCI/PM: Avoid putting EloPOS E2/S2/H2 PCIe Ports in D3cold
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9235
+    - PCI: qcom: Disable write access to read only registers for IP v2.3.3
+    - PCI: rockchip: Assert PCI Configuration Enable bit after probe
+    - PCI: rockchip: Write PCI Device ID to correct register
+    - PCI: rockchip: Add poll and timeout to wait for PHY PLLs to be locked
+    - PCI: rockchip: Fix legacy IRQ generation for RK3399 PCIe endpoint core
+    - PCI: rockchip: Use u32 variable to access 32-bit registers
+    - PCI: rockchip: Set address alignment for endpoint mode
+    - misc: pci_endpoint_test: Free IRQs before removing the device
+    - misc: pci_endpoint_test: Re-init completion for every test
+    - md/raid0: add discard support for the 'original' layout
+    - fs: dlm: return positive pid value for F_GETLK
+    - drm/atomic: Allow vblank-enabled + self-refresh "disable"
+    - drm/rockchip: vop: Leave vblank enabled in self-refresh
+    - serial: atmel: don't enable IRQs prematurely
+    - firmware: stratix10-svc: Fix a potential resource leak in
+      svc_create_memory_pool()
+    - hwrng: imx-rngc - fix the timeout for init and self check
+    - ceph: don't let check_caps skip sending responses for revoke msgs
+    - meson saradc: fix clock divider mask length
+    - Revert "8250: add support for ASIX devices with a FIFO bug"
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in
+      case of error
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() when
+      iterating clk
+    - tracing/histograms: Add histograms to hist_vars if they have referenced
+      variables
+    - ring-buffer: Fix deadloop issue on reading trace_pipe
+    - xtensa: ISS: fix call to split_if_spec
+    - tracing: Fix null pointer dereference in tracing_err_log_open()
+    - tracing/probes: Fix not to count error code to total length
+    - scsi: qla2xxx: Wait for io return on terminate rport
+    - scsi: qla2xxx: Fix potential NULL pointer dereference
+    - scsi: qla2xxx: Check valid rport returned by fc_bsg_to_rport()
+    - scsi: qla2xxx: Correct the index of array
+    - scsi: qla2xxx: Pointer may be dereferenced
+    - scsi: qla2xxx: Remove unused nvme_ls_waitq wait queue
+    - drm/atomic: Fix potential use-after-free in nonblocking commits
+    - perf probe: Add test for regression introduced by switch to
+      die_get_decl_file()
+    - btrfs: fix warning when putting transaction with qgroups enabled after abort
+    - fuse: revalidate: don't invalidate if interrupted
+    - selftests: tc: set timeout to 15 minutes
+    - can: bcm: Fix UAF in bcm_proc_show()
+    - drm/client: Fix memory leak in drm_client_target_cloned
+    - drm/client: Fix memory leak in drm_client_modeset_probe
+    - ext4: correct inline offset when handling xattrs in inode body
+    - debugobjects: Recheck debug_objects_enabled before reporting
+    - nbd: Add the maximum limit of allocated index in nbd_dev_add
+    - md: fix data corruption for raid456 when reshape restart while grow up
+    - md/raid10: prevent soft lockup while flush writes
+    - posix-timers: Ensure timer ID search-loop limit is valid
+    - arm64: mm: fix VA-range sanity check
+    - sched/fair: Don't balance task to its current running CPU
+    - bpf: Address KCSAN report on bpf_lru_list
+    - devlink: report devlink_port_type_warn source device
+    - wifi: wext-core: Fix -Wstringop-overflow warning in
+      ioctl_standard_iw_point()
+    - wifi: iwlwifi: mvm: avoid baid size integer overflow
+    - igb: Fix igb_down hung on surprise removal
+    - spi: bcm63xx: fix max prepend length
+    - fbdev: imxfb: warn about invalid left/right margin
+    - pinctrl: amd: Use amd_pinconf_set() for all config options
+    - net: ethernet: ti: cpsw_ale: Fix cpsw_ale_get_field()/cpsw_ale_set_field()
+    - iavf: Fix use-after-free in free_netdev
+    - net:ipv6: check return value of pskb_trim()
+    - Revert "tcp: avoid the lookup process failing to get sk in ehash table"
+    - fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe
+    - llc: Don't drop packet from non-root netns.
+    - netfilter: nf_tables: fix spurious set element insertion failure
+    - netfilter: nf_tables: can't schedule in nft_chain_validate
+    - tcp: annotate data-races around tp->tcp_tx_delay
+    - net: Replace the limit of TCP_LINGER2 with TCP_FIN_TIMEOUT_MAX
+    - tcp: annotate data-races around tp->linger2
+    - tcp: annotate data-races around rskq_defer_accept
+    - tcp: annotate data-races around tp->notsent_lowat
+    - tcp: annotate data-races around fastopenq.max_qlen
+    - tracing/histograms: Return an error if we fail to add histogram to hist_vars
+      list
+    - Linux 5.4.251
+
+  * Focal update: v5.4.250 upstream stable release (LP: #2033297)
+    - x86/microcode/AMD: Load late on both threads too
+    - Linux 5.4.250
+
+  * Focal update: v5.4.249 upstream stable release (LP: #2033278)
+    - nilfs2: reject devices with insufficient block count
+    - mm: rewrite wait_on_page_bit_common() logic
+    - list: add "list_del_init_careful()" to go with "list_empty_careful()"
+    - epoll: ep_autoremove_wake_function should use list_del_init_careful
+    - tracing: Add tracing_reset_all_online_cpus_unlocked() function
+    - x86/purgatory: remove PGO flags
+    - tick/common: Align tick period during sched_timer setup
+    - media: dvbdev: Fix memleak in dvb_register_device
+    - media: dvbdev: fix error logic at dvb_register_device()
+    - media: dvb-core: Fix use-after-free due to race at dvb_register_device()
+    - nilfs2: fix buffer corruption due to concurrent device reads
+    - Drivers: hv: vmbus: Fix vmbus_wait_for_unload() to scan present CPUs
+    - PCI: hv: Fix a race condition bug in hv_pci_query_relations()
+    - cgroup: Do not corrupt task iteration when rebinding subsystem
+    - mmc: meson-gx: remove redundant mmc_request_done() call from irq context
+    - ip_tunnels: allow VXLAN/GENEVE to inherit TOS/TTL from VLAN
+    - writeback: fix dereferencing NULL mapping->host on writeback_page_template
+    - nilfs2: prevent general protection fault in nilfs_clear_dirty_page()
+    - cifs: Clean up DFS referral cache
+    - cifs: Get rid of kstrdup_const()'d paths
+    - cifs: Introduce helpers for finding TCP connection
+    - cifs: Merge is_path_valid() into get_normalized_path()
+    - cifs: Fix potential deadlock when updating vol in cifs_reconnect()
+    - x86/mm: Avoid using set_pgd() outside of real PGD pages
+    - ieee802154: hwsim: Fix possible memory leaks
+    - xfrm: Linearize the skb after offloading if needed.
+    - net: qca_spi: Avoid high load if QCA7000 is not available
+    - mmc: mtk-sd: fix deferred probing
+    - mmc: mvsdio: convert to devm_platform_ioremap_resource
+    - mmc: mvsdio: fix deferred probing
+    - mmc: omap: fix deferred probing
+    - mmc: omap_hsmmc: fix deferred probing
+    - mmc: sdhci-acpi: fix deferred probing
+    - mmc: sh_mmcif: fix deferred probing
+    - mmc: usdhi60rol0: fix deferred probing
+    - ipvs: align inner_mac_header for encapsulation
+    - net: dsa: mt7530: fix trapping frames on non-MT7621 SoC MT7530 switch
+    - be2net: Extend xmit workaround to BE3 chip
+    - netfilter: nf_tables: disallow element updates of bound anonymous sets
+    - netfilter: nfnetlink_osf: fix module autoload
+    - Revert "net: phy: dp83867: perform soft reset and retain established link"
+    - sch_netem: acquire qdisc lock in netem_change()
+    - scsi: target: iscsi: Prevent login threads from racing between each other
+    - HID: wacom: Add error check to wacom_parse_and_register()
+    - arm64: Add missing Set/Way CMO encodings
+    - media: cec: core: don't set last_initiator if tx in progress
+    - nfcsim.c: Fix error checking for debugfs_create_dir
+    - usb: gadget: udc: fix NULL dereference in remove()
+    - s390/cio: unregister device when the only path is gone
+    - ASoC: nau8824: Add quirk to active-high jack-detect
+    - ARM: dts: Fix erroneous ADS touchscreen polarities
+    - drm/exynos: vidi: fix a wrong error return
+    - drm/exynos: fix race condition UAF in exynos_g2d_exec_ioctl
+    - drm/radeon: fix race condition UAF in radeon_gem_set_domain_ioctl
+    - x86/apic: Fix kernel panic when booting with intremap=off and x2apic_phys
+    - i2c: imx-lpi2c: fix type char overflow issue when calculating the clock
+      cycle
+    - mm: fix VM_BUG_ON(PageTail) and BUG_ON(PageWriteback)
+    - mm: make wait_on_page_writeback() wait for multiple pending writebacks
+    - Linux 5.4.249
+
+  * allow io_uring to be disabled in runtime (LP: #2035116)
+    - io_uring: add a sysctl to disable io_uring system-wide
+
+  * CVE-2023-31083
+    - Bluetooth: hci_ldisc: check HCI_UART_PROTO_READY flag in HCIUARTGETPROTO
+
+  * CVE-2023-4132
+    - media: usb: siano: Fix warning due to null work_func_t function pointer
+
+  * CVE-2023-3772
+    - xfrm: add NULL check in xfrm_update_ae_params
+
+  * CVE-2023-0597
+    - random32: add noise from network and scheduling activity
+    - x86/kasan: Map shadow for percpu pages on demand
+    - x86/mm: Randomize per-cpu entry area
+    - x86/mm: Recompute physical address for every page of per-CPU CEA mapping
+    - x86/mm: Populate KASAN shadow for entire per-CPU range of CPU entry area
+    - x86/mm: Do not shuffle CPU entry areas without KASLR
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Mon, 02 Oct 2023 12:18:58 +0200
+
+linux (5.4.0-164.181) focal; urgency=medium
+
+  * focal/linux: 5.4.0-164.181 -proposed tracker (LP: #2033867)
+
+  * Please enable Renesas RZ platform serial installer (LP: #2022361)
+    - [Config] enable hihope RZ/G2M serial console
+
+  * Azure: hv_netvsc: add support for vlans in AF_PACKET mode (LP: #2030872)
+    - hv_netvsc: add support for vlans in AF_PACKET mode
+
+  * systemd mount units fail during boot, while file system is correctly mounted
+    (LP: #1837227)
+    - list: introduce list_for_each_continue()
+    - proc/mounts: add cursor
+
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+
+  * 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
+
+  * CVE-2023-4194
+    - net: tun_chr_open(): set sk_uid from current_fsuid()
+    - net: tap_open(): set sk_uid from current_fsuid()
+
+  * CVE-2023-1206
+    - tcp: Reduce chance of collisions in inet6_hashfn().
+
+  * CVE-2021-4001
+    - bpf: Fix toctou on read-only map's constant scalar tracking
+
+  * Focal update: v5.4.248 upstream stable release (LP: #2031121)
+    - test_firmware: fix a memory leak with reqs buffer
+    - KEYS: asymmetric: Copy sig and digest in public_key_verify_signature()
+    - dasd: refactor dasd_ioctl_information
+    - s390/dasd: Use correct lock while counting channel queue length
+    - power: supply: ab8500: Fix external_power_changed race
+    - power: supply: sc27xx: Fix external_power_changed race
+    - power: supply: bq27xxx: Use mod_delayed_work() instead of cancel() +
+      schedule()
+    - ARM: dts: vexpress: add missing cache properties
+    - power: supply: Ratelimit no data debug output
+    - platform/x86: asus-wmi: Ignore WMI events with codes 0x7B, 0xC0
+    - regulator: Fix error checking for debugfs_create_dir
+    - irqchip/meson-gpio: Mark OF related data as maybe unused
+    - power: supply: Fix logic checking if system is running from battery
+    - btrfs: handle memory allocation failure in btrfs_csum_one_bio
+    - parisc: Improve cache flushing for PCXL in arch_sync_dma_for_cpu()
+    - parisc: Flush gatt writes and adjust gatt mask in parisc_agp_mask_memory()
+    - MIPS: Alchemy: fix dbdma2
+    - mips: Move initrd_start check after initrd address sanitisation.
+    - xen/blkfront: Only check REQ_FUA for writes
+    - drm:amd:amdgpu: Fix missing buffer object unlock in failure path
+    - ocfs2: fix use-after-free when unmounting read-only filesystem
+    - ocfs2: check new file size on fallocate call
+    - nios2: dts: Fix tse_mac "max-frame-size" property
+    - nilfs2: fix incomplete buffer cleanup in nilfs_btnode_abort_change_key()
+    - nilfs2: fix possible out-of-bounds segment allocation in resize ioctl
+    - kexec: support purgatories with .text.hot sections
+    - powerpc/purgatory: remove PGO flags
+    - nouveau: fix client work fence deletion race
+    - RDMA/uverbs: Restrict usage of privileged QKEYs
+    - net: usb: qmi_wwan: add support for Compal RXM-G1
+    - ALSA: hda/realtek: Add a quirk for Compaq N14JP6
+    - Remove DECnet support from kernel
+    - [Config] updateconfigs for DECNET
+    - USB: serial: option: add Quectel EM061KGL series
+    - serial: lantiq: add missing interrupt ack
+    - usb: dwc3: gadget: Reset num TRBs before giving back the request
+    - spi: spi-fsl-dspi: Remove unused chip->void_write_data
+    - spi: fsl-dspi: avoid SCK glitches with continuous transfers
+    - netfilter: nfnetlink: skip error delivery on batch in case of ENOMEM
+    - ping6: Fix send to link-local addresses with VRF.
+    - RDMA/rxe: Remove the unused variable obj
+    - RDMA/rxe: Removed unused name from rxe_task struct
+    - RDMA/rxe: Fix the use-before-initialization error of resp_pkts
+    - iavf: remove mask from iavf_irq_enable_queues()
+    - IB/uverbs: Fix to consider event queue closing also upon non-blocking mode
+    - IB/isert: Fix dead lock in ib_isert
+    - IB/isert: Fix possible list corruption in CMA handler
+    - IB/isert: Fix incorrect release of isert connection
+    - ipvlan: fix bound dev checking for IPv6 l3s mode
+    - sctp: fix an error code in sctp_sf_eat_auth()
+    - igb: fix nvm.ops.read() error handling
+    - drm/nouveau/dp: check for NULL nv_connector->native_mode
+    - drm/nouveau/kms: Don't change EDID when it hasn't actually changed
+    - drm/nouveau: add nv_encoder pointer check for NULL
+    - net/sched: cls_api: Fix lockup on flushing explicitly created chain
+    - net: lapbether: only support ethernet devices
+    - net: tipc: resize nlattr array to correct size
+    - selftests/ptp: Fix timestamp printf format for PTP_SYS_OFFSET
+    - afs: Fix vlserver probe RTT handling
+    - neighbour: Remove unused inline function neigh_key_eq16()
+    - net: Remove unused inline function dst_hold_and_use()
+    - neighbour: delete neigh_lookup_nodev as not used
+    - drm/nouveau/kms: Fix NULL pointer dereference in
+      nouveau_connector_detect_depth
+    - mmc: block: ensure error propagation for non-blk
+    - Linux 5.4.248
+
+  * Focal update: v5.4.247 upstream stable release (LP: #2030818)
+    - blk-iocost: avoid 64-bit division in ioc_timer_fn
+    - block/blk-iocost (gcc13): keep large values in a new enum
+    - i40iw: fix build warning in i40iw_manage_apbvt()
+    - i40e: fix build warnings in i40e_alloc.h
+    - spi: qup: Request DMA before enabling clocks
+    - neighbour: Replace zero-length array with flexible-array member
+    - neighbour: fix unaligned access to pneigh_entry
+    - net: dsa: lan9303: allow vid != 0 in port_fdb_{add|del} methods
+    - Bluetooth: Fix l2cap_disconnect_req deadlock
+    - Bluetooth: L2CAP: Add missing checks for invalid DCID
+    - netfilter: conntrack: fix NULL pointer dereference in nf_confirm_cthelper
+    - netfilter: ipset: Add schedule point in call_ad().
+    - rfs: annotate lockless accesses to sk->sk_rxhash
+    - rfs: annotate lockless accesses to RFS sock flow table
+    - net: sched: move rtm_tca_policy declaration to include file
+    - net: sched: fix possible refcount leak in tc_chain_tmplt_add()
+    - lib: cpu_rmap: Fix potential use-after-free in irq_cpu_rmap_release()
+    - bnxt_en: Query default VLAN before VNIC setup on a VF
+    - batman-adv: Broken sync while rescheduling delayed work
+    - Input: xpad - delete a Razer DeathAdder mouse VID/PID entry
+    - Input: psmouse - fix OOB access in Elantech protocol
+    - ALSA: hda/realtek: Add a quirk for HP Slim Desktop S01
+    - ALSA: hda/realtek: Add Lenovo P3 Tower platform
+    - drm/amdgpu: fix xclk freq on CHIP_STONEY
+    - can: j1939: j1939_sk_send_loop_abort(): improved error queue handling in
+      J1939 Socket
+    - can: j1939: change j1939_netdev_lock type to mutex
+    - can: j1939: avoid possible use-after-free when j1939_can_rx_register fails
+    - ceph: fix use-after-free bug for inodes when flushing capsnaps
+    - Bluetooth: Fix use-after-free in hci_remove_ltk/hci_remove_irk
+    - rbd: move RBD_OBJ_FLAG_COPYUP_ENABLED flag setting
+    - pinctrl: meson-axg: add missing GPIOA_18 gpio group
+    - usb: usbfs: Enforce page requirements for mmap
+    - usb: usbfs: Use consistent mmap functions
+    - bonding (gcc13): synchronize bond_{a,t}lb_xmit() types
+    - i2c: sprd: Delete i2c adapter in .remove's error path
+    - eeprom: at24: also select REGMAP
+    - ext4: only check dquot_initialize_needed() when debugging
+    - drm/atomic: Don't pollute crtc_state->mode_blob with error pointers
+    - rbd: get snapshot context after exclusive lock is ensured to be held
+    - mtd: spinand: macronix: Add support for MX35LFxGE4AD
+    - Linux 5.4.247
+
+  * 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-3863
+    - nfc: llcp: simplify llcp_sock_connect() error paths
+    - net: nfc: Fix use-after-free caused by nfc_llcp_find_local
+
+  * CVE-2023-3212
+    - gfs2: Don't deref jdesc in evict
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Fri, 01 Sep 2023 15:09:25 +0200
+
+linux (5.4.0-162.179) focal; urgency=medium
+
+  * focal/linux: 5.4.0-162.179 -proposed tracker (LP: #2031128)
+
+  * libgnutls report "trap invalid opcode" when trying to install packages over
+    https (LP: #2031093)
+    - [Config]: disable CONFIG_GDS_FORCE_MITIGATION
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Mon, 14 Aug 2023 10:20:38 +0200
+
+linux (5.4.0-160.177) focal; urgency=medium
+
+  * focal/linux: 5.4.0-160.177 -proposed tracker (LP: #2031017)
+
+  * Fix boot test warning for log_check "CPU: 0 PID: 0 at
+    arch/x86/kernel/fpu/xstate.c:878 get_xsave_addr+0x98/0xb0" (LP: #2031022)
+    - x86/pkeys: Revert a5eff7259790 ("x86/pkeys: Add PKRU value to init_fpstate")
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Thu, 10 Aug 2023 18:25:48 +0200
+
+linux (5.4.0-158.175) focal; urgency=medium
+
+  * focal/linux: 5.4.0-158.175 -proposed tracker (LP: #2030466)
+
+  * CVE-2022-40982
+    - x86/mm: Initialize text poking earlier
+    - x86/mm: fix poking_init() for Xen PV guests
+    - x86/mm: Use mm_alloc() in poking_init()
+    - mm: Move mm_cachep initialization to mm_init()
+    - init: Provide arch_cpu_finalize_init()
+    - x86/cpu: Switch to arch_cpu_finalize_init()
+    - ARM: cpu: Switch to arch_cpu_finalize_init()
+    - sparc/cpu: Switch to arch_cpu_finalize_init()
+    - um/cpu: Switch to arch_cpu_finalize_init()
+    - init: Remove check_bugs() leftovers
+    - init: Invoke arch_cpu_finalize_init() earlier
+    - init, x86: Move mem_encrypt_init() into arch_cpu_finalize_init()
+    - x86/fpu: Remove cpuinfo argument from init functions
+    - x86/fpu: Mark init functions __init
+    - x86/fpu: Move FPU initialization into arch_cpu_finalize_init()
+    - x86/xen: Fix secondary processors' FPU initialization
+    - x86/speculation: Add Gather Data Sampling mitigation
+    - x86/speculation: Add force option to GDS mitigation
+    - x86/speculation: Add Kconfig option for GDS
+    - KVM: Add GDS_NO support to KVM
+    - Documentation/x86: Fix backwards on/off logic about YMM support
+    - [Config]: Enable CONFIG_ARCH_HAS_CPU_FINALIZE_INIT and
+      CONFIG_GDS_FORCE_MITIGATION
+
+  * CVE-2023-3609
+    - net/sched: cls_u32: Fix reference counter leak leading to overflow
+
+  * CVE-2023-20593
+    - x86/cpu/amd: Move the errata checking functionality up
+    - x86/cpu/amd: Add a Zenbleed fix
+
+  * CVE-2023-3611
+    - net/sched: sch_qfq: account for stab overhead in qfq_enqueue
+
+  * stacked overlay file system mounts that have chroot() called against them
+    appear to be getting locked (by the kernel most likely?) (LP: #2016398)
+    - SAUCE: overlayfs: fix reference count mismatch
+
+  * Focal update: v5.4.246 upstream stable release (LP: #2028981)
+    - RDMA/efa: Fix unsupported page sizes in device
+    - RDMA/bnxt_re: Enable SRIOV VF support on Broadcom's 57500 adapter series
+    - RDMA/bnxt_re: Refactor queue pair creation code
+    - RDMA/bnxt_re: Fix return value of bnxt_re_process_raw_qp_pkt_rx
+    - iommu/rockchip: Fix unwind goto issue
+    - iommu/amd: Don't block updates to GATag if guest mode is on
+    - dmaengine: pl330: rename _start to prevent build error
+    - net/mlx5: fw_tracer, Fix event handling
+    - netrom: fix info-leak in nr_write_internal()
+    - af_packet: Fix data-races of pkt_sk(sk)->num.
+    - amd-xgbe: fix the false linkup in xgbe_phy_status
+    - mtd: rawnand: ingenic: fix empty stub helper definitions
+    - af_packet: do not use READ_ONCE() in packet_bind()
+    - tcp: deny tcp_disconnect() when threads are waiting
+    - tcp: Return user_mss for TCP_MAXSEG in CLOSE/LISTEN state if user_mss set
+    - net/sched: sch_ingress: Only create under TC_H_INGRESS
+    - net/sched: sch_clsact: Only create under TC_H_CLSACT
+    - net/sched: Reserve TC_H_INGRESS (TC_H_CLSACT) for ingress (clsact) Qdiscs
+    - net/sched: Prohibit regrafting ingress or clsact Qdiscs
+    - net: sched: fix NULL pointer dereference in mq_attach
+    - ocfs2/dlm: move BITS_TO_BYTES() to bitops.h for wider use
+    - net/netlink: fix NETLINK_LIST_MEMBERSHIPS length report
+    - udp6: Fix race condition in udp6_sendmsg & connect
+    - net: dsa: mv88e6xxx: Increase wait after reset deactivation
+    - mtd: rawnand: marvell: ensure timing values are written
+    - mtd: rawnand: marvell: don't set the NAND frequency select
+    - watchdog: menz069_wdt: fix watchdog initialisation
+    - mailbox: mailbox-test: Fix potential double-free in
+      mbox_test_message_write()
+    - ARM: 9295/1: unwind:fix unwind abort for uleb128 case
+    - media: rcar-vin: Select correct interrupt mode for V4L2_FIELD_ALTERNATE
+    - fbdev: modedb: Add 1920x1080 at 60 Hz video mode
+    - fbdev: stifb: Fix info entry in sti_struct on error path
+    - nbd: Fix debugfs_create_dir error checking
+    - ASoC: dwc: limit the number of overrun messages
+    - xfrm: Check if_id in inbound policy/secpath match
+    - ASoC: ssm2602: Add workaround for playback distortions
+    - media: dvb_demux: fix a bug for the continuity counter
+    - media: dvb-usb: az6027: fix three null-ptr-deref in az6027_i2c_xfer()
+    - media: dvb-usb-v2: ec168: fix null-ptr-deref in ec168_i2c_xfer()
+    - media: dvb-usb-v2: ce6230: fix null-ptr-deref in ce6230_i2c_master_xfer()
+    - media: dvb-usb-v2: rtl28xxu: fix null-ptr-deref in rtl28xxu_i2c_xfer
+    - media: dvb-usb: digitv: fix null-ptr-deref in digitv_i2c_xfer()
+    - media: dvb-usb: dw2102: fix uninit-value in su3000_read_mac_address
+    - media: netup_unidvb: fix irq init by register it at the end of probe
+    - media: dvb_ca_en50221: fix a size write bug
+    - media: ttusb-dec: fix memory leak in ttusb_dec_exit_dvb()
+    - media: mn88443x: fix !CONFIG_OF error by drop of_match_ptr from ID table
+    - media: dvb-core: Fix use-after-free due on race condition at dvb_net
+    - media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221
+    - wifi: rtl8xxxu: fix authentication timeout due to incorrect RCR value
+    - ARM: dts: stm32: add pin map for CAN controller on stm32f7
+    - arm64/mm: mark private VM_FAULT_X defines as vm_fault_t
+    - scsi: core: Decrease scsi_device's iorequest_cnt if dispatch failed
+    - wifi: b43: fix incorrect __packed annotation
+    - netfilter: conntrack: define variables exp_nat_nla_policy and any_addr with
+      CONFIG_NF_NAT
+    - ALSA: oss: avoid missing-prototype warnings
+    - atm: hide unused procfs functions
+    - mailbox: mailbox-test: fix a locking issue in mbox_test_message_write()
+    - iio: adc: mxs-lradc: fix the order of two cleanup operations
+    - HID: google: add jewel USB id
+    - HID: wacom: avoid integer overflow in wacom_intuos_inout()
+    - iio: light: vcnl4035: fixed chip ID check
+    - iio: dac: mcp4725: Fix i2c_master_send() return value handling
+    - iio: dac: build ad5758 driver when AD5758 is selected
+    - net: usb: qmi_wwan: Set DTR quirk for BroadMobi BM818
+    - usb: gadget: f_fs: Add unbind event before functionfs_unbind
+    - misc: fastrpc: return -EPIPE to invocations on device removal
+    - misc: fastrpc: reject new invocations during device removal
+    - scsi: stex: Fix gcc 13 warnings
+    - ata: libata-scsi: Use correct device no in ata_find_dev()
+    - flow_dissector: work around stack frame size warning
+    - x86/boot: Wrap literal addresses in absolute_pointer()
+    - ACPI: thermal: drop an always true check
+    - gcc-12: disable '-Wdangling-pointer' warning for now
+    - eth: sun: cassini: remove dead code
+    - kernel/extable.c: use address-of operator on section symbols
+    - treewide: Remove uninitialized_var() usage
+    - lib/dynamic_debug.c: use address-of operator on section symbols
+    - wifi: rtlwifi: remove always-true condition pointed out by GCC 12
+    - mmc: vub300: fix invalid response handling
+    - tty: serial: fsl_lpuart: use UARTCTRL_TXINV to send break instead of
+      UARTCTRL_SBK
+    - selinux: don't use make's grouped targets feature yet
+    - tracing/probe: trace_probe_primary_from_call(): checked list_first_entry
+    - ext4: add EA_INODE checking to ext4_iget()
+    - ext4: set lockdep subclass for the ea_inode in ext4_xattr_inode_cache_find()
+    - ext4: disallow ea_inodes with extended attributes
+    - ext4: add lockdep annotations for i_data_sem for ea_inode's
+    - fbcon: Fix null-ptr-deref in soft_cursor
+    - test_firmware: fix the memory leak of the allocated firmware buffer
+    - regmap: Account for register length when chunking
+    - scsi: dpt_i2o: Remove broken pass-through ioctl (I2OUSERCMD)
+    - scsi: dpt_i2o: Do not process completions with invalid addresses
+    - [Config] updateconfigs for SCSI_DPT_I2O
+    - RDMA/bnxt_re: Remove set but not used variable 'dev_attr'
+    - RDMA/bnxt_re: Remove the qp from list only if the qp destroy succeeds
+    - drm/edid: Fix uninitialized variable in drm_cvt_modes()
+    - wifi: rtlwifi: 8192de: correct checking of IQK reload
+    - drm/edid: fix objtool warning in drm_cvt_modes()
+    - Linux 5.4.246
+
+  * Focal update: v5.4.245 upstream stable release (LP: #2028980)
+    - cdc_ncm: Implement the 32-bit version of NCM Transfer Block
+    - net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize
+    - power: supply: bq27xxx: After charger plug in/out wait 0.5s for things to
+      stabilize
+    - power: supply: core: Refactor
+      power_supply_set_input_current_limit_from_supplier()
+    - power: supply: bq24190: Call power_supply_changed() after updating input
+      current
+    - fs: fix undefined behavior in bit shift for SB_NOUSER
+    - net/mlx5: devcom only supports 2 ports
+    - net/mlx5: Devcom, serialize devcom registration
+    - cdc_ncm: Fix the build warning
+    - io_uring: always grab lock in io_cancel_async_work()
+    - io_uring: don't drop completion lock before timer is fully initialized
+    - io_uring: have io_kill_timeout() honor the request references
+    - bluetooth: Add cmd validity checks at the start of hci_sock_ioctl()
+    - binder: fix UAF caused by faulty buffer cleanup
+    - ipv{4,6}/raw: fix output xfrm lookup wrt protocol
+    - netfilter: ctnetlink: Support offloaded conntrack entry deletion
+    - Linux 5.4.245
+
+  * Focal update: v5.4.244 upstream stable release (LP: #2028697)
+    - driver core: add a helper to setup both the of_node and fwnode of a device
+    - drm/mipi-dsi: Set the fwnode for mipi_dsi_device
+    - ARM: 9296/1: HP Jornada 7XX: fix kernel-doc warnings
+    - linux/dim: Do nothing if no time delta between samples
+    - net: Fix load-tearing on sk->sk_stamp in sock_recv_cmsgs().
+    - netfilter: conntrack: fix possible bug_on with enable_hooks=1
+    - netlink: annotate accesses to nlk->cb_running
+    - net: annotate sk->sk_err write from do_recvmmsg()
+    - net: tap: check vlan with eth_type_vlan() method
+    - net: add vlan_get_protocol_and_depth() helper
+    - net: datagram: fix data-races in datagram_poll()
+    - af_unix: Fix a data race of sk->sk_receive_queue->qlen.
+    - af_unix: Fix data races around sk->sk_shutdown.
+    - fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode()
+    - drm/amd/display: Use DC_LOG_DC in the trasform pixel function
+    - regmap: cache: Return error in cache sync operations for REGCACHE_NONE
+    - firmware: arm_sdei: Fix sleep from invalid context BUG
+    - ACPI: EC: Fix oops when removing custom query handlers
+    - drm/tegra: Avoid potential 32-bit integer overflow
+    - ACPICA: Avoid undefined behavior: applying zero offset to null pointer
+    - ACPICA: ACPICA: check null return of ACPI_ALLOCATE_ZEROED in
+      acpi_db_display_objects
+    - wifi: brcmfmac: cfg80211: Pass the PMK in binary instead of hex
+    - ext2: Check block size validity during mount
+    - scsi: lpfc: Prevent lpfc_debugfs_lockstat_write() buffer overflow
+    - net: pasemi: Fix return type of pasemi_mac_start_tx()
+    - net: Catch invalid index in XPS mapping
+    - scsi: target: iscsit: Free cmds before session free
+    - lib: cpu_rmap: Avoid use after free on rmap->obj array entries
+    - scsi: message: mptlan: Fix use after free bug in mptlan_remove() due to race
+      condition
+    - gfs2: Fix inode height consistency check
+    - ext4: set goal start correctly in ext4_mb_normalize_request
+    - ext4: Fix best extent lstart adjustment logic in ext4_mb_new_inode_pa()
+    - f2fs: fix to drop all dirty pages during umount() if cp_error is set
+    - samples/bpf: Fix fout leak in hbm's run_bpf_prog
+    - wifi: iwlwifi: pcie: fix possible NULL pointer dereference
+    - wifi: iwlwifi: pcie: Fix integer overflow in iwl_write_to_user_buf
+    - wifi: iwlwifi: dvm: Fix memcpy: detected field-spanning write backtrace
+    - Bluetooth: L2CAP: fix "bad unlock balance" in l2cap_disconnect_rsp
+    - HID: logitech-hidpp: Don't use the USB serial for USB devices
+    - HID: logitech-hidpp: Reconcile USB and Unifying serials
+    - spi: spi-imx: fix MX51_ECSPI_* macros when cs > 3
+    - HID: wacom: generic: Set battery quirk only when we see battery data
+    - usb: typec: tcpm: fix multiple times discover svids error
+    - serial: 8250: Reinit port->pm on port specific driver unbind
+    - mcb-pci: Reallocate memory region to avoid memory overlapping
+    - sched: Fix KCSAN noinstr violation
+    - recordmcount: Fix memory leaks in the uwrite function
+    - RDMA/core: Fix multiple -Warray-bounds warnings
+    - clk: tegra20: fix gcc-7 constant overflow warning
+    - iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
+    - Input: xpad - add constants for GIP interface numbers
+    - phy: st: miphy28lp: use _poll_timeout functions for waits
+    - mfd: dln2: Fix memory leak in dln2_probe()
+    - btrfs: replace calls to btrfs_find_free_ino with btrfs_find_free_objectid
+    - btrfs: fix space cache inconsistency after error loading it from disk
+    - ASoC: fsl_micfil: register platform component before registering cpu dai
+    - cpupower: Make TSC read per CPU for Mperf monitor
+    - af_key: Reject optional tunnel/BEET mode templates in outbound policies
+    - net: fec: Better handle pm_runtime_get() failing in .remove()
+    - ALSA: firewire-digi00x: prevent potential use after free
+    - vsock: avoid to close connected socket after the timeout
+    - serial: arc_uart: fix of_iomap leak in `arc_serial_probe`
+    - ip6_gre: Fix skb_under_panic in __gre6_xmit()
+    - ip6_gre: Make o_seqno start from 0 in native mode
+    - ip_gre, ip6_gre: Fix race condition on o_seqno in collect_md mode
+    - erspan: get the proto with the md version for collect_md
+    - net: hns3: fix sending pfc frames after reset issue
+    - net: hns3: fix reset delay time to avoid configuration timeout
+    - media: netup_unidvb: fix use-after-free at del_timer()
+    - drm/exynos: fix g2d_open/close helper function definitions
+    - net: nsh: Use correct mac_offset to unwind gso skb in nsh_gso_segment()
+    - net: bcmgenet: Remove phy_stop() from bcmgenet_netif_stop()
+    - net: bcmgenet: Restore phy_stop() depending upon suspend/close
+    - wifi: iwlwifi: mvm: don't trust firmware n_channels
+    - cassini: Fix a memory leak in the error handling path of cas_init_one()
+    - igb: fix bit_shift to be in [1..8] range
+    - vlan: fix a potential uninit-value in vlan_dev_hard_start_xmit()
+    - USB: usbtmc: Fix direction for 0-length ioctl control messages
+    - usb-storage: fix deadlock when a scsi command timeouts more than once
+    - USB: UHCI: adjust zhaoxin UHCI controllers OverCurrent bit value
+    - usb: dwc3: debugfs: Resume dwc3 before accessing registers
+    - usb: typec: altmodes/displayport: fix pin_assignment_show
+    - ALSA: hda: Fix Oops by 9.1 surround channel names
+    - ALSA: hda: Add NVIDIA codec IDs a3 through a7 to patch table
+    - ALSA: hda/realtek: Add a quirk for HP EliteDesk 805
+    - ALSA: hda/realtek: Add quirk for 2nd ASUS GU603
+    - can: j1939: recvmsg(): allow MSG_CMSG_COMPAT flag
+    - can: kvaser_pciefd: Set CAN_STATE_STOPPED in kvaser_pciefd_stop()
+    - can: kvaser_pciefd: Call request_irq() before enabling interrupts
+    - can: kvaser_pciefd: Empty SRB buffer in probe
+    - can: kvaser_pciefd: Clear listen-only bit if not explicitly requested
+    - can: kvaser_pciefd: Do not send EFLUSH command on TFD interrupt
+    - can: kvaser_pciefd: Disable interrupts in probe error path
+    - KVM: x86: do not report a vCPU as preempted outside instruction boundaries
+    - statfs: enforce statfs[64] structure initialization
+    - serial: Add support for Advantech PCI-1611U card
+    - ceph: force updating the msg pointer in non-split case
+    - tpm/tpm_tis: Disable interrupts for more Lenovo devices
+    - powerpc/64s/radix: Fix soft dirty tracking
+    - nilfs2: fix use-after-free bug of nilfs_root in nilfs_evict_inode()
+    - netfilter: nftables: add nft_parse_register_load() and use it
+    - netfilter: nftables: add nft_parse_register_store() and use it
+    - netfilter: nftables: statify nft_parse_register()
+    - netfilter: nf_tables: validate registers coming from userspace.
+    - netfilter: nf_tables: add nft_setelem_parse_key()
+    - netfilter: nf_tables: allow up to 64 bytes in the set element data area
+    - netfilter: nf_tables: stricter validation of element data
+    - netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on NFT_SET_OBJECT
+      flag
+    - netfilter: nf_tables: hold mutex on netns pre_exit path
+    - HID: wacom: Force pen out of prox if no events have been received in a while
+    - HID: wacom: Add new Intuos Pro Small (PTH-460) device IDs
+    - HID: wacom: add three styli to wacom_intuos_get_tool_type
+    - lib/string_helpers: Introduce string_upper() and string_lower() helpers
+    - usb: gadget: u_ether: Convert prints to device prints
+    - usb: gadget: u_ether: Fix host MAC address case
+    - vc_screen: rewrite vcs_size to accept vc, not inode
+    - vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF
+    - s390/qdio: get rid of register asm
+    - s390/qdio: fix do_sqbs() inline assembly constraint
+    - watchdog: sp5100_tco: Immediately trigger upon starting.
+    - spi: fsl-spi: Re-organise transfer bits_per_word adaptation
+    - spi: fsl-cpm: Use 16 bit mode for large transfers with even size
+    - mt76: mt7615: Fix build with older compilers
+    - ALSA: hda/ca0132: add quirk for EVGA X299 DARK
+    - ALSA: hda/realtek: Enable headset onLenovo M70/M90
+    - m68k: Move signal frame following exception on 68020/030
+    - parisc: Handle kgdb breakpoints only in kernel context
+    - parisc: Allow to reboot machine after system halt
+    - gpio: mockup: Fix mode of debugfs files
+    - btrfs: use nofs when cleaning up aborted transactions
+    - selftests/memfd: Fix unknown type name build failure
+    - parisc: Fix flush_dcache_page() for usage from irq context
+    - x86/topology: Fix erroneous smp_num_siblings on Intel Hybrid platforms
+    - debugobjects: Don't wake up kswapd from fill_pool()
+    - fbdev: udlfb: Fix endpoint check
+    - net: fix stack overflow when LRO is disabled for virtual interfaces
+    - udplite: Fix NULL pointer dereference in __sk_mem_raise_allocated().
+    - USB: core: Add routines for endpoint checks in old drivers
+    - USB: sisusbvga: Add endpoint checks
+    - media: radio-shark: Add endpoint checks
+    - net: fix skb leak in __skb_tstamp_tx()
+    - selftests: fib_tests: mute cleanup error message
+    - bpf: Fix mask generation for 32-bit narrow loads of 64-bit fields
+    - ipv6: Fix out-of-bounds access in ipv6_find_tlv()
+    - power: supply: leds: Fix blink to LED on transition
+    - power: supply: bq27xxx: Fix bq27xxx_battery_update() race condition
+    - power: supply: bq27xxx: Fix I2C IRQ race on remove
+    - power: supply: bq27xxx: Fix poll_interval handling and races on remove
+    - power: supply: sbs-charger: Fix INHIBITED bit for Status reg
+    - coresight: Fix signedness bug in tmc_etr_buf_insert_barrier_packet()
+    - xen/pvcalls-back: fix double frees with pvcalls_new_active_socket()
+    - x86/show_trace_log_lvl: Ensure stack pointer is aligned, again
+    - ASoC: Intel: Skylake: Fix declaration of enum skl_ch_cfg
+    - forcedeth: Fix an error handling path in nv_probe()
+    - net/mlx5: Fix error message when failing to allocate device memory
+    - net/mlx5: Devcom, fix error flow in mlx5_devcom_register_device
+    - 3c589_cs: Fix an error handling path in tc589_probe()
+    - Linux 5.4.244
+
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387)
+    - counter: 104-quad-8: Fix race condition between FLAG and CNTR reads
+    - drm/fb-helper: set x/yres_virtual in drm_fb_helper_check_var
+    - bluetooth: Perform careful capability checks in hci_sock_ioctl()
+    - USB: serial: option: add UNISOC vendor and TOZED LT70C product
+    - iio: adc: palmas_gpadc: fix NULL dereference on rmmod
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Acer Iconia One 7 B1-750
+    - asm-generic/io.h: suppress endianness warnings for readq() and writeq()
+    - USB: dwc3: fix runtime pm imbalance on probe errors
+    - USB: dwc3: fix runtime pm imbalance on unbind
+    - perf sched: Cast PTHREAD_STACK_MIN to int as it may turn into
+      sysconf(__SC_THREAD_STACK_MIN_VALUE)
+    - staging: iio: resolver: ads1210: fix config mode
+    - debugfs: regset32: Add Runtime PM support
+    - xhci: fix debugfs register accesses while suspended
+    - MIPS: fw: Allow firmware to pass a empty env
+    - ipmi:ssif: Add send_retries increment
+    - ipmi: fix SSIF not responding under certain cond.
+    - kheaders: Use array declaration instead of char
+    - pwm: meson: Fix axg ao mux parents
+    - pwm: meson: Fix g12a ao clk81 name
+    - ring-buffer: Sync IRQ works before buffer destruction
+    - reiserfs: Add security prefix to xattr name in reiserfs_security_write()
+    - KVM: nVMX: Emulate NOPs in L2, and PAUSE if it's not intercepted
+    - i2c: omap: Fix standard mode false ACK readings
+    - Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path"
+    - ubifs: Fix memleak when insert_old_idx() failed
+    - ubi: Fix return value overwrite issue in try_write_vid_and_data()
+    - ubifs: Free memory for tmpfile name
+    - selinux: fix Makefile dependencies of flask.h
+    - selinux: ensure av_permissions.h is built when needed
+    - tpm, tpm_tis: Do not skip reset of original interrupt vector
+    - erofs: stop parsing non-compact HEAD index if clusterofs is invalid
+    - erofs: fix potential overflow calculating xattr_isize
+    - drm/rockchip: Drop unbalanced obj unref
+    - drm/vgem: add missing mutex_destroy
+    - drm/probe-helper: Cancel previous job before starting new one
+    - arm64: dts: renesas: r8a77990: Remove bogus voltages from OPP table
+    - arm64: dts: renesas: r8a774c0: Remove bogus voltages from OPP table
+    - EDAC/skx: Fix overflows on the DRAM row address mapping arrays
+    - ARM: dts: qcom: ipq4019: Fix the PCI I/O port range
+    - ARM: dts: qcom: ipq8064: reduce pci IO size to 64K
+    - ARM: dts: qcom: ipq8064: Fix the PCI I/O port range
+    - media: bdisp: Add missing check for create_workqueue
+    - media: uapi: add MEDIA_BUS_FMT_METADATA_FIXED media bus format.
+    - media: av7110: prevent underflow in write_ts_to_decoder()
+    - firmware: qcom_scm: Clear download bit during reboot
+    - drm/msm: fix unbalanced pm_runtime_enable in adreno_gpu_{init, cleanup}
+    - drm/msm/adreno: Defer enabling runpm until hw_init()
+    - drm/msm/adreno: drop bogus pm_runtime_set_active()
+    - mmc: sdhci-of-esdhc: fix quirk to ignore command inhibit for data
+    - drm/lima/lima_drv: Add missing unwind goto in lima_pdev_probe()
+    - regulator: core: Consistently set mutex_owner when using
+      ww_mutex_lock_slow()
+    - regulator: core: Avoid lockdep reports when resolving supplies
+    - x86/apic: Fix atomic update of offset in reserve_eilvt_offset()
+    - media: dm1105: Fix use after free bug in dm1105_remove due to race condition
+    - media: saa7134: fix use after free bug in saa7134_finidev due to race
+      condition
+    - media: rcar_fdp1: simplify error check logic at fdp_open()
+    - media: rcar_fdp1: fix pm_runtime_get_sync() usage count
+    - media: rcar_fdp1: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - media: rcar_fdp1: Fix the correct variable assignments
+    - media: rcar_fdp1: Fix refcount leak in probe and remove function
+    - media: rc: gpio-ir-recv: Fix support for wake-up
+    - regulator: stm32-pwr: fix of_iomap leak
+    - x86/ioapic: Don't return 0 from arch_dynirq_lower_bound()
+    - arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step
+    - debugobject: Prevent init race with static objects
+    - timekeeping: Split jiffies seqlock
+    - tick/sched: Use tick_next_period for lockless quick check
+    - tick/sched: Reduce seqcount held scope in tick_do_update_jiffies64()
+    - tick/sched: Optimize tick_do_update_jiffies64() further
+    - tick: Get rid of tick_period
+    - tick/common: Align tick period with the HZ tick.
+    - wifi: ath6kl: minor fix for allocation size
+    - wifi: ath9k: hif_usb: fix memory leak of remain_skbs
+    - wifi: ath5k: fix an off by one check in ath5k_eeprom_read_freq_list()
+    - wifi: ath6kl: reduce WARN to dev_dbg() in callback
+    - tools: bpftool: Remove invalid \' json escape
+    - wifi: rtw88: mac: Return the original error from rtw_pwr_seq_parser()
+    - wifi: rtw88: mac: Return the original error from rtw_mac_power_switch()
+    - scm: fix MSG_CTRUNC setting condition for SO_PASSSEC
+    - vlan: partially enable SIOCSHWTSTAMP in container
+    - net/packet: annotate accesses to po->xmit
+    - net/packet: convert po->origdev to an atomic flag
+    - net/packet: convert po->auxdata to an atomic flag
+    - scsi: target: iscsit: Fix TAS handling during conn cleanup
+    - scsi: megaraid: Fix mega_cmd_done() CMDID_INT_CMDS
+    - f2fs: handle dqget error in f2fs_transfer_project_quota()
+    - rtlwifi: Start changing RT_TRACE into rtl_dbg
+    - rtlwifi: Replace RT_TRACE with rtl_dbg
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_rfreg()
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_reg()
+    - bpftool: Fix bug for long instructions in program CFG dumps
+    - crypto: drbg - make drbg_prepare_hrng() handle jent instantiation errors
+    - crypto: drbg - Only fail when jent is unavailable in FIPS mode
+    - scsi: lpfc: Fix ioremap issues in lpfc_sli4_pci_mem_setup()
+    - bpf, sockmap: fix deadlocks in the sockhash and sockmap
+    - nvme: handle the persistent internal error AER
+    - nvme: fix async event trace event
+    - nvme-fcloop: fix "inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage"
+    - bpf, sockmap: Revert buggy deadlock fix in the sockhash and sockmap
+    - md/raid10: fix leak of 'r10bio->remaining' for recovery
+    - md/raid10: fix memleak for 'conf->bio_split'
+    - md: update the optimal I/O size on reshape
+    - md/raid10: fix memleak of md thread
+    - wifi: iwlwifi: make the loop for card preparation effective
+    - wifi: iwlwifi: mvm: check firmware response size
+    - ixgbe: Allow flow hash to be set via ethtool
+    - ixgbe: Enable setting RSS table to default values
+    - bpf: Don't EFAULT for getsockopt with optval=NULL
+    - netfilter: nf_tables: don't write table validation state without mutex
+    - ipv4: Fix potential uninit variable access bug in __ip_make_skb()
+    - netlink: Use copy_to_user() for optval in netlink_getsockopt().
+    - net: amd: Fix link leak when verifying config failed
+    - tcp/udp: Fix memleaks of sk and zerocopy skbs with TX timestamp.
+    - pstore: Revert pmsg_lock back to a normal mutex
+    - usb: host: xhci-rcar: remove leftover quirk handling
+    - fpga: bridge: fix kernel-doc parameter description
+    - iio: light: max44009: add missing OF device matching
+    - usb: gadget: udc: renesas_usb3: Fix use after free bug in
+      renesas_usb3_remove due to race condition
+    - PCI: imx6: Install the fault handler only on compatible match
+    - genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
+    - ASoC: es8316: Use IRQF_NO_AUTOEN when requesting the IRQ
+    - ASoC: es8316: Handle optional IRQ assignment
+    - linux/vt_buffer.h: allow either builtin or modular for macros
+    - spi: qup: Don't skip cleanup in remove's error path
+    - spi: fsl-spi: Fix CPM/QE mode Litte Endian
+    - vmci_host: fix a race condition in vmci_host_poll() causing GPF
+    - of: Fix modalias string generation
+    - ia64: mm/contig: fix section mismatch warning/error
+    - ia64: salinfo: placate defined-but-not-used warning
+    - scripts/gdb: bail early if there are no clocks
+    - PM: domains: Fix up terminology with parent/child
+    - scripts/gdb: bail early if there are no generic PD
+    - mtd: spi-nor: cadence-quadspi: Make driver independent of flash geometry
+    - mtd: spi-nor: cadence-quadspi: Provide a way to disable DAC mode
+    - mtd: spi-nor: cadence-quadspi: Don't initialize rx_dma_complete on failure
+    - mtd: spi-nor: cadence-quadspi: Handle probe deferral while requesting DMA
+      channel
+    - spi: cadence-quadspi: fix suspend-resume implementations
+    - uapi/linux/const.h: prefer ISO-friendly __typeof__
+    - sh: sq: Fix incorrect element size for allocating bitmap buffer
+    - usb: chipidea: fix missing goto in `ci_hdrc_probe`
+    - usb: mtu3: fix kernel panic at qmu transfer done irq handler
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - tty: serial: fsl_lpuart: adjust buffer length to the intended size
+    - serial: 8250: Add missing wakeup event reporting
+    - staging: rtl8192e: Fix W_DISABLE# does not work after stop/start
+    - spmi: Add a check for remove callback when removing a SPMI driver
+    - macintosh/windfarm_smu_sat: Add missing of_node_put()
+    - powerpc/mpc512x: fix resource printk format warning
+    - powerpc/wii: fix resource printk format warnings
+    - powerpc/sysdev/tsi108: fix resource printk format warnings
+    - macintosh: via-pmu-led: requires ATA to be set
+    - powerpc/rtas: use memmove for potentially overlapping buffer copy
+    - perf/core: Fix hardlockup failure caused by perf throttle
+    - RDMA/siw: Fix potential page_array out of range access
+    - RDMA/rdmavt: Delete unnecessary NULL check
+    - rtc: omap: include header for omap_rtc_power_off_program prototype
+    - RDMA/mlx4: Prevent shift wrapping in set_user_sq_size()
+    - rtc: meson-vrtc: Use ktime_get_real_ts64() to get the current time
+    - power: supply: generic-adc-battery: fix unit scaling
+    - clk: add missing of_node_put() in "assigned-clocks" property parsing
+    - RDMA/siw: Remove namespace check from siw_netdev_event()
+    - IB/hfi1: Fix SDMA mmu_rb_node not being evicted in LRU order
+    - NFSv4.1: Always send a RECLAIM_COMPLETE after establishing lease
+    - firmware: raspberrypi: Keep count of all consumers
+    - firmware: raspberrypi: Introduce devm_rpi_firmware_get()
+    - input: raspberrypi-ts: Release firmware handle when not needed
+    - Input: raspberrypi-ts - fix refcount leak in rpi_ts_probe
+    - SUNRPC: remove the maximum number of retries in call_bind_status
+    - RDMA/mlx5: Use correct device num_ports when modify DC
+    - clocksource/drivers/davinci: Avoid trailing '\n' hidden in pr_fmt()
+    - clocksource: davinci: axe a pointless __GFP_NOFAIL
+    - clocksource/drivers/davinci: Fix memory leak in davinci_timer_register when
+      init fails
+    - openrisc: Properly store r31 to pt_regs on unhandled exceptions
+    - ext4: fix use-after-free read in ext4_find_extent for bigalloc + inline
+    - leds: TI_LMU_COMMON: select REGMAP instead of depending on it
+    - dmaengine: mv_xor_v2: Fix an error code.
+    - pwm: mtk-disp: Don't check the return code of pwmchip_remove()
+    - pwm: mtk-disp: Adjust the clocks to avoid them mismatch
+    - pwm: mtk-disp: Disable shadow registers before setting backlight values
+    - phy: tegra: xusb: Add missing tegra_xusb_port_unregister for usb2_port and
+      ulpi_port
+    - dmaengine: dw-edma: Fix to change for continuous transfer
+    - dmaengine: dw-edma: Fix to enable to issue dma request on DMA processing
+    - dmaengine: at_xdmac: do not enable all cyclic channels
+    - afs: Fix updating of i_size with dv jump from server
+    - parisc: Fix argument pointer in real64_call_asm()
+    - nilfs2: do not write dirty data after degenerating to read-only
+    - nilfs2: fix infinite loop in nilfs_mdt_get_block()
+    - md/raid10: fix null-ptr-deref in raid10_sync_request
+    - mailbox: zynqmp: Fix IPI isr handling
+    - mailbox: zynqmp: Fix typo in IPI documentation
+    - wifi: rtl8xxxu: RTL8192EU always needs full init
+    - clk: rockchip: rk3399: allow clk_cifout to force clk_cifout_src to reparent
+    - scripts/gdb: fix lx-timerlist for Python3
+    - btrfs: scrub: reject unsupported scrub flags
+    - s390/dasd: fix hanging blockdevice after request requeue
+    - dm clone: call kmem_cache_destroy() in dm_clone_init() error path
+    - dm integrity: call kmem_cache_destroy() in dm_integrity_init() error path
+    - dm flakey: fix a crash with invalid table line
+    - perf auxtrace: Fix address filter entire kernel size
+    - perf intel-pt: Fix CYC timestamps after standalone CBR
+    - debugobject: Ensure pool refill (again)
+    - nohz: Add TICK_DEP_BIT_RCU
+    - tick/nohz: Fix cpu_is_hotpluggable() by checking with nohz subsystem
+    - mailbox: zynq: Switch to flexible array to simplify code
+    - mailbox: zynqmp: Fix counts of child nodes
+    - dm verity: skip redundant verity_handle_err() on I/O errors
+    - dm verity: fix error handling for check_at_most_once on FEC
+    - crypto: inside-secure - irq balance
+    - crypto: safexcel - Cleanup ring IRQ workqueues on load failure
+    - net/ncsi: clear Tx enable mode when handling a Config required AEN
+    - net/sched: cls_api: remove block_cb from driver_list before freeing
+    - sit: update dev->needed_headroom in ipip6_tunnel_bind_dev()
+    - net: dsa: mv88e6xxx: add mv88e6321 rsvd2cpu
+    - writeback: fix call of incorrect macro
+    - net/sched: act_mirred: Add carrier check
+    - rxrpc: Fix hard call timeout units
+    - ionic: remove noise from ethtool rxnfc error msg
+    - af_packet: Don't send zero-byte data in packet_sendmsg_spkt().
+    - drm/amdgpu: add a missing lock for AMDGPU_SCHED
+    - ALSA: caiaq: input: Add error handling for unsupported input methods in
+      `snd_usb_caiaq_input_init`
+    - net: dsa: mt7530: fix corrupt frames using trgmii on 40 MHz XTAL MT7621
+    - virtio_net: split free_unused_bufs()
+    - virtio_net: suppress cpu stall when free_unused_bufs
+    - perf vendor events power9: Remove UTF-8 characters from JSON files
+    - perf map: Delete two variable initialisations before null pointer checks in
+      sort__sym_from_cmp()
+    - perf symbols: Fix return incorrect build_id size in elf_read_build_id()
+    - btrfs: fix btrfs_prev_leaf() to not return the same key twice
+    - btrfs: don't free qgroup space unless specified
+    - btrfs: print-tree: parent bytenr must be aligned to sector size
+    - cifs: fix pcchunk length type in smb2_copychunk_range
+    - platform/x86: touchscreen_dmi: Add info for the Dexp Ursus KX210i
+    - inotify: Avoid reporting event with invalid wd
+    - sh: math-emu: fix macro redefined warning
+    - sh: init: use OF_EARLY_FLATTREE for early init
+    - sh: nmi_debug: fix return value of __setup handler
+    - remoteproc: stm32: Call of_node_put() on iteration error
+    - remoteproc: st: Call of_node_put() on iteration error
+    - ARM: dts: exynos: fix WM8960 clock name in Itop Elite
+    - ARM: dts: s5pv210: correct MIPI CSIS clock name
+    - f2fs: fix potential corruption when moving a directory
+    - drm/panel: otm8009a: Set backlight parent to panel device
+    - drm/amdgpu: fix an amdgpu_irq_put() issue in gmc_v9_0_hw_fini()
+    - drm/amdgpu/gfx: disable gfx9 cp_ecc_error_irq only when enabling legacy gfx
+      ras
+    - drm/amdgpu: disable sdma ecc irq only when sdma RAS is enabled in suspend
+    - HID: wacom: Set a default resolution for older tablets
+    - HID: wacom: insert timestamp to packed Bluetooth (BT) events
+    - ext4: fix WARNING in mb_find_extent
+    - ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum
+    - ext4: fix data races when using cached status extents
+    - ext4: improve error recovery code paths in __ext4_remount()
+    - ext4: fix deadlock when converting an inline directory in nojournal mode
+    - ext4: add bounds checking in get_max_inline_xattr_value_size()
+    - ext4: bail out of ext4_xattr_ibody_get() fails for any reason
+    - ext4: remove a BUG_ON in ext4_mb_release_group_pa()
+    - ext4: fix invalid free tracking in ext4_xattr_move_to_block()
+    - tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH
+    - serial: 8250: Fix serial8250_tx_empty() race with DMA Tx
+    - drbd: correctly submit flush bio on barrier
+    - PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors
+    - PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock
+    - printk: declare printk_deferred_{enter,safe}() in include/linux/printk.h
+    - PM: domains: Restore comment indentation for generic_pm_domain.child_links
+    - drm/msm: Fix double pm_runtime_disable() call
+    - firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
+    - drm/msm/adreno: Fix null ptr access in adreno_gpu_cleanup()
+    - drm/exynos: move to use request_irq by IRQF_NO_AUTOEN flag
+    - mm/page_alloc: fix potential deadlock on zonelist_update_seq seqlock
+    - drm/amd/display: Fix hang when skipping modeset
+    - Linux 5.4.243
+    - Upstream stable to v5.4.243
+
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387) //
+    CVE-2023-2269
+    - dm ioctl: fix nested locking in table_clear() to remove deadlock concern
+
+  * Focal update: v5.4.242 upstream stable release (LP: #2025094)
+    - ARM: dts: rockchip: fix a typo error for rk3288 spdif node
+    - arm64: dts: meson-g12-common: specify full DMC range
+    - netfilter: br_netfilter: fix recent physdev match breakage
+    - regulator: fan53555: Explicitly include bits header
+    - virtio_net: bugfix overflow inside xdp_linearize_page()
+    - netfilter: nf_tables: fix ifdef to also consider nf_tables=m
+    - i40e: fix accessing vsi->active_filters without holding lock
+    - i40e: fix i40e_setup_misc_vector() error handling
+    - mlxfw: fix null-ptr-deref in mlxfw_mfa2_tlv_next()
+    - bpf: Fix incorrect verifier pruning due to missing register precision taints
+    - e1000e: Disable TSO on i219-LM card to increase speed
+    - f2fs: Fix f2fs_truncate_partial_nodes ftrace event
+    - Input: i8042 - add quirk for Fujitsu Lifebook A574/H
+    - selftests: sigaltstack: fix -Wuninitialized
+    - scsi: megaraid_sas: Fix fw_crash_buffer_show()
+    - scsi: core: Improve scsi_vpd_inquiry() checks
+    - net: dsa: b53: mmap: add phy ops
+    - s390/ptrace: fix PTRACE_GET_LAST_BREAK error handling
+    - nvme-tcp: fix a possible UAF when failing to allocate an io queue
+    - xen/netback: use same error messages for same errors
+    - iio: light: tsl2772: fix reading proximity-diodes from device tree
+    - nilfs2: initialize unused bytes in segment summary blocks
+    - memstick: fix memory leak if card device is never registered
+    - mmc: sdhci_am654: Set HIGH_SPEED_ENA for SDR12 and SDR25
+    - MIPS: Define RUNTIME_DISCARD_EXIT in LD script
+    - x86/purgatory: Don't generate debug info for purgatory.ro
+    - Revert "ext4: fix use-after-free in ext4_xattr_set_entry"
+    - ext4: remove duplicate definition of ext4_xattr_ibody_inline_set()
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM).
+    - tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
+    - inet6: Remove inet6_destroy_sock() in sk->sk_prot->destroy().
+    - dccp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - sctp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - xfs: fix forkoff miscalculation related to XFS_LITINO(mp)
+    - pwm: meson: Explicitly set .polarity in .get_state()
+    - iio: adc: at91-sama5d2_adc: fix an error code in at91_adc_allocate_trigger()
+    - ASN.1: Fix check for strdup() success
+    - Linux 5.4.242
+    - Upstream stable to v5.4.242
+
+  * 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-3268
+    - kernel/relay.c: fix read_pos error when multiple readers
+    - relayfs: fix out-of-bounds access in relay_file_read
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] resync getabis
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Wed, 09 Aug 2023 12:45:40 +0200
+
+linux (5.4.0-156.173) focal; urgency=medium
+
+  * focal/linux: 5.4.0-156.173 -proposed tracker (LP: #2026585)
+
+  * CVE-2023-3390
+    - netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+
+  * Focal update: v5.4.241 upstream stable release (LP: #2023930)
+    - scsi: ses: Handle enclosure with just a primary component gracefully
+    - x86/PCI: Add quirk for AMD XHCI controller that loses MSI-X state in D3hot
+    - cgroup/cpuset: Wake up cpuset_attach_wq tasks in cpuset_cancel_attach()
+    - treewide: Replace DECLARE_TASKLET() with DECLARE_TASKLET_OLD()
+    - smb3: fix problem with null cifs super block with previous patch
+    - pinctrl: amd: Use irqchip template
+    - pinctrl: amd: disable and mask interrupts on probe
+    - pinctrl: amd: Disable and mask interrupts on resume
+    - pwm: cros-ec: Explicitly set .polarity in .get_state()
+    - pwm: sprd: Explicitly set .polarity in .get_state()
+    - wifi: mac80211: fix invalid drv_sta_pre_rcu_remove calls for non-uploaded
+      sta
+    - icmp: guard against too small mtu
+    - net: don't let netpoll invoke NAPI if in xmit context
+    - sctp: check send stream number after wait_for_sndbuf
+    - ipv6: Fix an uninit variable access bug in __ip6_make_skb()
+    - gpio: davinci: Add irq chip flag to skip set wake
+    - sunrpc: only free unix grouplist after RCU settles
+    - NFSD: callback request does not use correct credential for AUTH_SYS
+    - xhci: also avoid the XHCI_ZERO_64B_REGS quirk with a passthrough iommu
+    - USB: serial: cp210x: add Silicon Labs IFS-USB-DATACABLE IDs
+    - usb: typec: altmodes/displayport: Fix configure initial pin assignment
+    - USB: serial: option: add Telit FE990 compositions
+    - USB: serial: option: add Quectel RM500U-CN modem
+    - iio: adc: ti-ads7950: Set `can_sleep` flag for GPIO chip
+    - iio: dac: cio-dac: Fix max DAC write value check for 12-bit
+    - tty: serial: sh-sci: Fix transmit end interrupt handler
+    - tty: serial: sh-sci: Fix Rx on RZ/G2L SCI
+    - tty: serial: fsl_lpuart: avoid checking for transfer complete when
+      UARTCTRL_SBK is asserted in lpuart32_tx_empty
+    - nilfs2: fix potential UAF of struct nilfs_sc_info in nilfs_segctor_thread()
+    - nilfs2: fix sysfs interface lifetime
+    - ALSA: hda/realtek: Add quirk for Clevo X370SNW
+    - perf/core: Fix the same task check in perf_event_set_output
+    - ftrace: Mark get_lock_parent_ip() __always_inline
+    - can: j1939: j1939_tp_tx_dat_new(): fix out-of-bounds memory access
+    - tracing: Free error logs of tracing instances
+    - net_sched: prevent NULL dereference if default qdisc setup failed
+    - drm/panfrost: Fix the panfrost_mmu_map_fault_addr() error path
+    - ring-buffer: Fix race while reader and writer are on the same page
+    - mm/swap: fix swap_info_struct race between swapoff and get_swap_pages()
+    - irqdomain: Look for existing mapping only once
+    - irqdomain: Refactor __irq_domain_alloc_irqs()
+    - irqdomain: Fix mapping-creation race
+    - Revert "pinctrl: amd: Disable and mask interrupts on resume"
+    - ALSA: emu10k1: fix capture interrupt handler unlinking
+    - ALSA: hda/sigmatel: add pin overrides for Intel DP45SG motherboard
+    - ALSA: i2c/cs8427: fix iec958 mixer control deactivation
+    - ALSA: firewire-tascam: add missing unwind goto in
+      snd_tscm_stream_start_duplex()
+    - ALSA: hda/sigmatel: fix S/PDIF out on Intel D*45* motherboards
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_disconnect_{req,rsp}
+    - Bluetooth: Fix race condition in hidp_session_thread
+    - btrfs: print checksum type and implementation at mount time
+    - btrfs: fix fast csum implementation detection
+    - mtdblock: tolerate corrected bit-flips
+    - mtd: rawnand: meson: fix bitmask for length in command word
+    - mtd: rawnand: stm32_fmc2: remove unsupported EDO mode
+    - niu: Fix missing unwind goto in niu_alloc_channels()
+    - qlcnic: check pci_reset_function result
+    - sctp: fix a potential overflow in sctp_ifwdtsn_skip
+    - RDMA/core: Fix GID entry ref leak when create_ah fails
+    - udp6: fix potential access to stale information
+    - net: macb: fix a memory corruption in extended buffer descriptor mode
+    - power: supply: cros_usbpd: reclassify "default case!" as debug
+    - i2c: imx-lpi2c: clean rx/tx buffers upon new message
+    - efi: sysfb_efi: Add quirk for Lenovo Yoga Book X91F/L
+    - drm: panel-orientation-quirks: Add quirk for Lenovo Yoga Book X90F
+    - verify_pefile: relax wrapper length check
+    - asymmetric_keys: log on fatal failures in PE/pkcs7
+    - ubi: Fix failure attaching when vid_hdr offset equals to (sub)page size
+    - mtd: ubi: wl: Fix a couple of kernel-doc issues
+    - ubi: Fix deadlock caused by recursively holding work_sem
+    - i2c: ocores: generate stop condition after timeout in polling mode
+    - watchdog: sbsa_wdog: Make sure the timeout programming is within the limits
+    - coresight-etm4: Fix for() loop drvdata->nr_addr_cmp range bug
+    - xfs: show the proper user quota options
+    - xfs: remove the kuid/kgid conversion wrappers
+    - xfs: add a new xfs_sb_version_has_v3inode helper
+    - xfs: only check the superblock version for dinode size calculation
+    - xfs: simplify di_flags2 inheritance in xfs_ialloc
+    - xfs: simplify a check in xfs_ioctl_setattr_check_cowextsize
+    - xfs: remove the di_version field from struct icdinode
+    - xfs: set inode size after creating symlink
+    - xfs: report corruption only as a regular error
+    - xfs: shut down the filesystem if we screw up quota reservation
+    - xfs: consider shutdown in bmapbt cursor delete assert
+    - xfs: don't reuse busy extents on extent trim
+    - xfs: force log and push AIL to clear pinned inodes when aborting mount
+    - Linux 5.4.241
+
+  * [UBUNTU 20.04] [HPS] Kernel panic with "refcount_t: underflow" in mlx5
+    driver (LP: #2019011)
+    - net/mlx5: cmdif, Avoid skipping reclaim pages if FW is not accessible
+    - net/mlx5: Fix handling of entry refcount when command is not issued to FW
+
+  * Disable hv-kvp-daemon if /dev/vmbus/hv_kvp is not present (LP: #2024900)
+    - [Packaging] disable hv-kvp-daemon if needed
+
+  * CVE-2023-35001
+    - netfilter: nf_tables: prevent OOB access in nft_byteorder_eval
+
+  * CVE-2023-32629
+    - ovl: adhere to the vfs_ vs. ovl_do_ conventions for xattrs
+
+  * CVE-2023-3141
+    - memstick: r592: Fix UAF bug in r592_remove due to race condition
+
+  * CVE-2023-3111
+    - btrfs: check return value of btrfs_commit_transaction in relocation
+    - btrfs: unset reloc control if transaction commit fails in
+      prepare_to_relocate()
+
+  * 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-2022-0168
+    - cifs: move some variables off the stack in smb2_ioctl_query_info
+    - cifs: prevent bad output lengths in smb2_ioctl_query_info()
+    - cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
+
+  * CVE-2022-27672
+    - x86/speculation: Identify processors vulnerable to SMT RSB predictions
+    - KVM: x86: Mitigate the cross-thread return address predictions bug
+    - Documentation/hw-vuln: Add documentation for Cross-Thread Return Predictions
+
+  * Severe NFS performance degradation after LP #2003053 (LP: #2022098)
+    - SAUCE: Make NFS file-access stale cache behaviour opt-in
+
+  * Encountering an issue with memcpy_fromio causing failed boot of SEV-enabled
+    guest (LP: #2020319)
+    - x86/sev: Unroll string mmio with CC_ATTR_GUEST_UNROLL_STRING_IO
+
+  * Focal update: v5.4.240 upstream stable release (LP: #2023601)
+    - net: tls: fix possible race condition between do_tls_getsockopt_conf() and
+      do_tls_setsockopt_conf()
+    - power: supply: da9150: Fix use after free bug in da9150_charger_remove due
+      to race condition
+    - iavf: fix inverted Rx hash condition leading to disabled hash
+    - iavf: fix non-tunneled IPv6 UDP packet type and hashing
+    - intel/igbvf: free irq on the error path in igbvf_request_msix()
+    - igbvf: Regard vf reset nack as success
+    - i2c: imx-lpi2c: check only for enabled interrupt flags
+    - scsi: scsi_dh_alua: Fix memleak for 'qdata' in alua_activate()
+    - net: usb: smsc95xx: Limit packet length to skb->len
+    - qed/qed_sriov: guard against NULL derefs from qed_iov_get_vf_info
+    - net: qcom/emac: Fix use after free bug in emac_remove due to race condition
+    - net/ps3_gelic_net: Fix RX sk_buff length
+    - net/ps3_gelic_net: Use dma_mapping_error
+    - keys: Do not cache key in task struct if key is requested from kernel thread
+    - bpf: Adjust insufficient default bpf_jit_limit
+    - net/mlx5: Read the TC mapping of all priorities on ETS query
+    - atm: idt77252: fix kmemleak when rmmod idt77252
+    - erspan: do not use skb_mac_header() in ndo_start_xmit()
+    - net/sonic: use dma_mapping_error() for error check
+    - nvme-tcp: fix nvme_tcp_term_pdu to match spec
+    - hvc/xen: prevent concurrent accesses to the shared ring
+    - net: mdio: thunder: Add missing fwnode_handle_put()
+    - Bluetooth: btqcomsmd: Fix command timeout after setting BD address
+    - platform/chrome: cros_ec_chardev: fix kernel data leak from ioctl
+    - hwmon (it87): Fix voltage scaling for chips with 10.9mV ADCs
+    - scsi: qla2xxx: Perform lockless command completion in abort path
+    - uas: Add US_FL_NO_REPORT_OPCODES for JMicron JMS583Gen 2
+    - thunderbolt: Use const qualifier for `ring_interrupt_index`
+    - riscv: Bump COMMAND_LINE_SIZE value to 1024
+    - ca8210: fix mac_len negative array access
+    - m68k: Only force 030 bus error if PC not in exception table
+    - selftests/bpf: check that modifier resolves after pointer
+    - scsi: target: iscsi: Fix an error message in iscsi_check_key()
+    - scsi: ufs: core: Add soft dependency on governor_simpleondemand
+    - scsi: lpfc: Avoid usage of list iterator variable after loop
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FE990
+    - net: usb: qmi_wwan: add Telit 0x1080 composition
+    - sh: sanitize the flags on sigreturn
+    - cifs: empty interface list when server doesn't support query interfaces
+    - scsi: core: Add BLIST_SKIP_VPD_PAGES for SKhynix H28U74301AMR
+    - usb: gadget: u_audio: don't let userspace block driver unbind
+    - fsverity: Remove WQ_UNBOUND from fsverity read workqueue
+    - igb: revert rtnl_lock() that causes deadlock
+    - dm thin: fix deadlock when swapping to thin device
+    - usb: cdns3: Fix issue with using incorrect PCI device function
+    - usb: chipdea: core: fix return -EINVAL if request role is the same with
+      current role
+    - usb: chipidea: core: fix possible concurrent when switch role
+    - wifi: mac80211: fix qos on mesh interfaces
+    - nilfs2: fix kernel-infoleak in nilfs_ioctl_wrap_copy()
+    - i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer()
+    - dm stats: check for and propagate alloc_percpu failure
+    - dm crypt: add cond_resched() to dmcrypt_write()
+    - sched/fair: sanitize vruntime of entity being placed
+    - sched/fair: Sanitize vruntime of entity being migrated
+    - tun: avoid double free in tun_free_netdev
+    - ocfs2: fix data corruption after failed write
+    - fsverity: don't drop pagecache at end of FS_IOC_ENABLE_VERITY
+    - bus: imx-weim: fix branch condition evaluates to a garbage value
+    - md: avoid signed overflow in slot_store()
+    - ALSA: asihpi: check pao in control_message()
+    - ALSA: hda/ca0132: fixup buffer overrun at tuning_ctl_set()
+    - fbdev: tgafb: Fix potential divide by zero
+    - sched_getaffinity: don't assume 'cpumask_size()' is fully initialized
+    - fbdev: nvidia: Fix potential divide by zero
+    - fbdev: intelfb: Fix potential divide by zero
+    - fbdev: lxfb: Fix potential divide by zero
+    - fbdev: au1200fb: Fix potential divide by zero
+    - ca8210: Fix unsigned mac_len comparison with zero in ca8210_skb_tx()
+    - dma-mapping: drop the dev argument to arch_sync_dma_for_*
+    - mips: bmips: BCM6358: disable RAC flush for TP1
+    - mtd: rawnand: meson: invalidate cache on polling ECC bit
+    - scsi: megaraid_sas: Fix crash after a double completion
+    - ptp_qoriq: fix memory leak in probe()
+    - regulator: fix spelling mistake "Cant" -> "Can't"
+    - regulator: Handle deferred clk
+    - net/net_failover: fix txq exceeding warning
+    - can: bcm: bcm_tx_setup(): fix KMSAN uninit-value in vfs_write
+    - s390/vfio-ap: fix memory leak in vfio_ap device driver
+    - i40e: fix registers dump after run ethtool adapter self test
+    - bnxt_en: Fix typo in PCI id to device description string mapping
+    - net: dsa: mv88e6xxx: Enable IGMP snooping on user ports only
+    - net: mvneta: make tx buffer array agnostic
+    - pinctrl: ocelot: Fix alt mode for ocelot
+    - Input: alps - fix compatibility with -funsigned-char
+    - Input: focaltech - use explicitly signed char type
+    - cifs: prevent infinite recursion in CIFSGetDFSRefer()
+    - cifs: fix DFS traversal oops without CONFIG_CIFS_DFS_UPCALL
+    - Input: goodix - add Lenovo Yoga Book X90F to nine_bytes_report DMI table
+    - xen/netback: don't do grant copy across page boundary
+    - pinctrl: at91-pio4: fix domain name assignment
+    - NFSv4: Fix hangs when recovering open state after a server reboot
+    - ALSA: hda/conexant: Partial revert of a quirk for Lenovo
+    - ALSA: usb-audio: Fix regression on detection of Roland VS-100
+    - drm/etnaviv: fix reference leak when mmaping imported buffer
+    - btrfs: scan device in non-exclusive mode
+    - ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+    - net_sched: add __rcu annotation to netdev->qdisc
+    - net: sched: fix race condition in qdisc_graft()
+    - firmware: arm_scmi: Fix device node validation for mailbox transport
+    - gfs2: Always check inode size of inline inodes
+    - Linux 5.4.240
+
+  * Focal update: v5.4.239 upstream stable release (LP: #2023600)
+    - Linux 5.4.239
+
+  * CVE-2023-2124
+    - xfs: verify buffer contents when we skip log replay
+
+  * CVE-2020-36691
+    - netlink: limit recursion depth in policy validation
+
+  * CVE-2022-1184
+    - ext4: check if directory block is within i_size
+    - ext4: fix check for block being out of directory size
+
+  * CVE-2022-4269
+    - net: sched: extract qstats update code into functions
+    - net: sched: don't expose action qstats to skb_tc_reinsert()
+    - net/sched: act_mirred: refactor the handle of xmit
+    - net: sched: remove unused tcf_result extension
+    - net/sched: act_mirred: better wording on protection against excessive stack
+      growth
+    - act_mirred: use the backlog for nested calls to mirred ingress
+
+  * Focal update: v5.4.238 upstream stable release (LP: #2023427)
+    - ext4: fix cgroup writeback accounting with fs-layer encryption
+    - xfrm: Allow transport-mode states with AF_UNSPEC selector
+    - drm/panfrost: Don't sync rpm suspension after mmu flushing
+    - cifs: Move the in_send statistic to __smb_send_rqst()
+    - drm/meson: fix 1px pink line on GXM when scaling video overlay
+    - clk: HI655X: select REGMAP instead of depending on it
+    - docs: Correct missing "d_" prefix for dentry_operations member
+      d_weak_revalidate
+    - scsi: mpt3sas: Fix NULL pointer access in mpt3sas_transport_port_add()
+    - ALSA: hda - add Intel DG1 PCI and HDMI ids
+    - ALSA: hda - controller is in GPU on the DG1
+    - ALSA: hda: Add Alderlake-S PCI ID and HDMI codec vid
+    - ALSA: hda: Add Intel DG2 PCI ID and HDMI codec vid
+    - ALSA: hda: Match only Intel devices with CONTROLLER_IN_GPU()
+    - netfilter: nft_redir: correct value of inet type `.maxattrs`
+    - scsi: core: Fix a comment in function scsi_host_dev_release()
+    - scsi: core: Fix a procfs host directory removal regression
+    - tcp: tcp_make_synack() can be called from process context
+    - nfc: pn533: initialize struct pn533_out_arg properly
+    - ipvlan: Make skb->skb_iif track skb->dev for l3s mode
+    - i40e: Fix kernel crash during reboot when adapter is in recovery mode
+    - qed/qed_dev: guard against a possible division by zero
+    - net: tunnels: annotate lockless accesses to dev->needed_headroom
+    - net: phy: smsc: bail out in lan87xx_read_status if genphy_read_status fails
+    - nfc: st-nci: Fix use after free bug in ndlc_remove due to race condition
+    - net: usb: smsc75xx: Limit packet length to skb->len
+    - nvmet: avoid potential UAF in nvmet_req_complete()
+    - block: sunvdc: add check for mdesc_grab() returning NULL
+    - ipv4: Fix incorrect table ID in IOCTL path
+    - net: usb: smsc75xx: Move packet length check to prevent kernel panic in
+      skb_pull
+    - net/iucv: Fix size of interrupt data
+    - ethernet: sun: add check for the mdesc_grab()
+    - hwmon: (adt7475) Display smoothing attributes in correct order
+    - hwmon: (adt7475) Fix masking of hysteresis registers
+    - hwmon: (xgene) Fix use after free bug in xgene_hwmon_remove due to race
+      condition
+    - hwmon: (ina3221) return prober error code
+    - media: m5mols: fix off-by-one loop termination error
+    - mmc: atmel-mci: fix race between stop command and start of next command
+    - jffs2: correct logic when creating a hole in jffs2_write_begin
+    - ext4: fail ext4_iget if special inode unallocated
+    - ext4: fix task hung in ext4_xattr_delete_inode
+    - drm/amdkfd: Fix an illegal memory access
+    - sh: intc: Avoid spurious sizeof-pointer-div warning
+    - ext4: fix possible double unlock when moving a directory
+    - tty: serial: fsl_lpuart: skip waiting for transmission complete when
+      UARTCTRL_SBK is asserted
+    - interconnect: fix mem leak when freeing nodes
+    - tracing: Check field value in hist_field_name()
+    - tracing: Make tracepoint lockdep check actually test something
+    - ftrace: Fix invalid address access in lookup_rec() when index is 0
+    - fbdev: stifb: Provide valid pixelclock and add fb_check_var() checks
+    - x86/mm: Fix use of uninitialized buffer in sme_enable()
+    - drm/i915: Don't use stolen memory for ring buffers with LLC
+    - serial: 8250_em: Fix UART port type
+    - s390/ipl: add missing intersection check to ipl_report handling
+    - PCI: Unify delay handling for reset and resume
+    - HID: core: Provide new max_buffer_size attribute to over-ride the default
+    - HID: uhid: Over-ride the default maximum data buffer value with our own
+    - Linux 5.4.238
+
+  * Focal update: v5.4.237 upstream stable release (LP: #2023420)
+    - fs: prevent out-of-bounds array speculation when closing a file descriptor
+    - x86/CPU/AMD: Disable XSAVES on AMD family 0x17
+    - drm/connector: print max_requested_bpc in state debugfs
+    - ext4: fix RENAME_WHITEOUT handling for inline directories
+    - ext4: fix another off-by-one fsmap error on 1k block filesystems
+    - ext4: move where set the MAY_INLINE_DATA flag is set
+    - ext4: fix WARNING in ext4_update_inline_data
+    - ext4: zero i_disksize when initializing the bootloader inode
+    - nfc: change order inside nfc_se_io error path
+    - iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands
+    - iommu/amd: Fix ill-formed ivrs_ioapic, ivrs_hpet and ivrs_acpihid options
+    - iommu/amd: Add a length limitation for the ivrs_acpihid command-line
+      parameter
+    - ipmi:ssif: make ssif_i2c_send() void
+    - ipmi:ssif: resend_msg() cannot fail
+    - ipmi:ssif: Remove rtc_us_timer
+    - ipmi:ssif: Increase the message retry time
+    - ipmi:ssif: Add a timer between request retries
+    - irqdomain: Change the type of 'size' in __irq_domain_add() to be consistent
+    - irqdomain: Fix domain registration race
+    - iommu/vt-d: Fix PASID directory pointer coherency
+    - SMB3: Backup intent flag missing from some more ops
+    - cifs: Fix uninitialized memory read in smb3_qfs_tcon()
+    - scsi: core: Remove the /proc/scsi/${proc_name} directory earlier
+    - ext4: Fix possible corruption when moving a directory
+    - drm/msm/a5xx: fix setting of the CP_PREEMPT_ENABLE_LOCAL register
+    - nfc: fdp: add null check of devm_kmalloc_array in
+      fdp_nci_i2c_read_device_properties
+    - ila: do not generate empty messages in ila_xlat_nl_cmd_get_mapping()
+    - selftests: nft_nat: ensuring the listening side is up before starting the
+      client
+    - net: usb: lan78xx: Remove lots of set but unused 'ret' variables
+    - net: lan78xx: fix accessing the LAN7800's internal phy specific registers
+      from the MAC driver
+    - net: caif: Fix use-after-free in cfusbl_device_notify()
+    - bnxt_en: Avoid order-5 memory allocation for TPA data
+    - netfilter: tproxy: fix deadlock due to missing BH disable
+    - btf: fix resolving BTF_KIND_VAR after ARRAY, STRUCT, UNION, PTR
+    - scsi: megaraid_sas: Update max supported LD IDs to 240
+    - net/smc: fix fallback failed while sendmsg with fastopen
+    - riscv: Use READ_ONCE_NOCHECK in imprecise unwinding stack mode
+    - ext4: Fix deadlock during directory rename
+    - MIPS: Fix a compilation issue
+    - alpha: fix R_ALPHA_LITERAL reloc for large modules
+    - macintosh: windfarm: Use unsigned type for 1-bit bitfields
+    - PCI: Add SolidRun vendor ID
+    - media: ov5640: Fix analogue gain control
+    - ipmi/watchdog: replace atomic_add() and atomic_sub()
+    - ipmi:watchdog: Set panic count to proper value on a panic
+    - drm/i915: Don't use BAR mappings for ring buffers with LLC
+    - x86, vmlinux.lds: Add RUNTIME_DISCARD_EXIT to generic DISCARDS
+    - arch: fix broken BuildID for arm64 and riscv
+    - powerpc/vmlinux.lds: Define RUNTIME_DISCARD_EXIT
+    - powerpc/vmlinux.lds: Don't discard .rela* for relocatable builds
+    - s390: define RUNTIME_DISCARD_EXIT to fix link error with GNU ld < 2.36
+    - sh: define RUNTIME_DISCARD_EXIT
+    - UML: define RUNTIME_DISCARD_EXIT
+    - s390/dasd: add missing discipline function
+    - Linux 5.4.237
+
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - staging: rtl8192e: Remove function ..dm_check_ac_dc_power calling a script
+    - staging: rtl8192e: Remove call_usermodehelper starting RadioPower.sh
+    - Linux 5.4.236
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Mon, 10 Jul 2023 17:38:56 +0200
+
+linux (5.4.0-153.170) focal; urgency=medium
+
+  * focal/linux: 5.4.0-153.170 -proposed tracker (LP: #2024108)
+
+  * cls_flower: off-by-one in fl_set_geneve_opt (LP: #2023577)
+    - net/sched: flower: fix possible OOB write in fl_set_geneve_opt()
+
+  * Some INVLPG implementations can leave Global translations unflushed when
+    PCIDs are enabled (LP: #2023220)
+    - x86/mm: Avoid incomplete Global INVLPG flushes
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 16 Jun 2023 10:20:20 -0300
+
+linux (5.4.0-152.169) focal; urgency=medium
+
+  * focal/linux: 5.4.0-152.169 -proposed tracker (LP: #2023070)
+
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - wifi: cfg80211: Partial revert "wifi: cfg80211: Fix use after free for wext"
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync getabis
+
+ -- Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>  Tue, 06 Jun 2023 14:45:17 -0700
+
+linux (5.4.0-151.168) focal; urgency=medium
+
+  * focal/linux: 5.4.0-151.168 -proposed tracker (LP: #2019375)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2023.05.15)
+
+  * CVE-2023-32233
+    - netfilter: nf_tables: deactivate anonymous set from preparation phase
+
+  * CVE-2023-2612
+    - SAUCE: shiftfs: prevent lock unbalance in shiftfs_create_object()
+
+  * 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()
+
+  * Focal update: Focal update: v5.4.235 upstream stable release (LP: #2017706)
+    - HID: asus: Remove check for same LED brightness on set
+    - HID: asus: use spinlock to protect concurrent accesses
+    - HID: asus: use spinlock to safely schedule workers
+    - ARM: OMAP2+: Fix memory leak in realtime_counter_init()
+    - arm64: dts: qcom: qcs404: use symbol names for PCIe resets
+    - ARM: zynq: Fix refcount leak in zynq_early_slcr_init
+    - arm64: dts: meson-gx: Fix Ethernet MAC address unit name
+    - arm64: dts: meson-g12a: Fix internal Ethernet PHY unit name
+    - arm64: dts: meson-gx: Fix the SCPI DVFS node name and unit address
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12A boards
+    - ARM: OMAP1: call platform_device_put() in error case in
+      omap1_dm_timer_init()
+    - ARM: dts: exynos: correct wr-active property in Exynos3250 Rinato
+    - ARM: imx: Call ida_simple_remove() for ida_simple_get
+    - arm64: dts: amlogic: meson-gx: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-axg: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-gx: add missing SCPI sensors compatible
+    - arm64: dts: amlogic: meson-gx: add missing unit address to rng node name
+    - arm64: dts: amlogic: meson-gxl: add missing unit address to eth-phy-mux node
+      name
+    - arm64: dts: amlogic: meson-gxl-s905d-phicomm-n1: fix led node name
+    - ARM: dts: imx7s: correct iomuxc gpr mux controller cells
+    - arm64: dts: mediatek: mt7622: Add missing pwm-cells to pwm node
+    - Revert "scsi: core: run queue if SCSI device queue isn't ready and queue is
+      idle"
+    - block: Limit number of items taken from the I/O scheduler in one go
+    - blk-mq: remove stale comment for blk_mq_sched_mark_restart_hctx
+    - blk-mq: wait on correct sbitmap_queue in blk_mq_mark_tag_wait
+    - blk-mq: correct stale comment of .get_budget
+    - s390/dasd: Prepare for additional path event handling
+    - s390/dasd: Fix potential memleak in dasd_eckd_init()
+    - sched/deadline,rt: Remove unused parameter from pick_next_[rt|dl]_entity()
+    - sched/rt: pick_next_rt_entity(): check list_entry
+    - block: bio-integrity: Copy flags when bio_integrity_payload is cloned
+    - wifi: rsi: Fix memory leak in rsi_coex_attach()
+    - net/wireless: Delete unnecessary checks before the macro call
+      “dev_kfree_skb”
+    - wifi: iwlegacy: common: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: fix memory leak in lbs_init_adapter()
+    - wifi: rtl8xxxu: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - rtlwifi: fix -Wpointer-sign warning
+    - wifi: rtlwifi: Fix global-out-of-bounds bug in
+      _rtl8812ae_phy_set_txpower_limit()
+    - ipw2x00: switch from 'pci_' to 'dma_' API
+    - wifi: ipw2x00: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: ipw2200: fix memory leak in ipw_wdev_init()
+    - wilc1000: let wilc_mac_xmit() return NETDEV_TX_OK
+    - wifi: wilc1000: fix potential memory leak in wilc_mac_xmit()
+    - wifi: brcmfmac: fix potential memory leak in brcmf_netdev_start_xmit()
+    - wifi: brcmfmac: unmap dma buffer in brcmf_msgbuf_alloc_pktid()
+    - wifi: libertas_tf: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: if_usb: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: main: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: cmdresp: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: wl3501_cs: don't call kfree_skb() under spin_lock_irqsave()
+    - crypto: x86/ghash - fix unaligned access in ghash_setkey()
+    - ACPICA: Drop port I/O validation for some regions
+    - genirq: Fix the return type of kstat_cpu_irqs_sum()
+    - lib/mpi: Fix buffer overrun when SG is too long
+    - ACPICA: nsrepair: handle cases without a return value correctly
+    - wifi: orinoco: check return value of hermes_write_wordrec()
+    - wifi: ath9k: htc_hst: free skb in ath9k_htc_rx_msg() if there is no callback
+      function
+    - ath9k: hif_usb: simplify if-if to if-else
+    - ath9k: htc: clean up statistics macros
+    - wifi: ath9k: hif_usb: clean up skbs if ath9k_hif_usb_rx_stream() fails
+    - wifi: ath9k: Fix potential stack-out-of-bounds write in
+      ath9k_wmi_rsp_callback()
+    - ACPI: battery: Fix missing NUL-termination with large strings
+    - crypto: ccp - Failure on re-initialization due to duplicate sysfs filename
+    - crypto: essiv - remove redundant null pointer check before kfree
+    - crypto: essiv - Handle EBUSY correctly
+    - crypto: seqiv - Handle EBUSY correctly
+    - powercap: fix possible name leak in powercap_register_zone()
+    - net/mlx5: Enhance debug print in page allocation failure
+    - irqchip/alpine-msi: Fix refcount leak in alpine_msix_init_domains
+    - irqchip/irq-mvebu-gicp: Fix refcount leak in mvebu_gicp_probe
+    - irqchip/ti-sci: Fix refcount leak in ti_sci_intr_irq_domain_probe
+    - mptcp: add sk_stop_timer_sync helper
+    - net: add sock_init_data_uid()
+    - tun: tun_chr_open(): correctly initialize socket uid
+    - tap: tap_open(): correctly initialize socket uid
+    - OPP: fix error checking in opp_migrate_dentry()
+    - Bluetooth: L2CAP: Fix potential user-after-free
+    - libbpf: Fix alen calculation in libbpf_nla_dump_errormsg()
+    - rds: rds_rm_zerocopy_callback() correct order for list_add_tail()
+    - crypto: rsa-pkcs1pad - Use akcipher_request_complete
+    - m68k: /proc/hardware should depend on PROC_FS
+    - RISC-V: time: initialize hrtimer based broadcast clock event device
+    - usb: gadget: udc: Avoid tasklet passing a global
+    - wifi: iwl3945: Add missing check for create_singlethread_workqueue
+    - wifi: iwl4965: Add missing check for create_singlethread_workqueue()
+    - wifi: mwifiex: fix loop iterator in mwifiex_update_ampdu_txwinsize()
+    - crypto: crypto4xx - Call dma_unmap_page when done
+    - wifi: mac80211: make rate u32 in sta_set_rate_info_rx()
+    - thermal/drivers/hisi: Drop second sensor hi3660
+    - can: esd_usb: Move mislocated storage of SJA1000_ECC_SEG bits in case of a
+      bus error
+    - irqchip/irq-brcmstb-l2: Set IRQ_LEVEL for level triggered interrupts
+    - irqchip/irq-bcm7120-l2: Set IRQ_LEVEL for level triggered interrupts
+    - selftests/net: Interpret UDP_GRO cmsg data as an int value
+    - drm/fourcc: Add missing big-endian XRGB1555 and RGB565 formats
+    - drm: mxsfb: DRM_MXSFB should depend on ARCH_MXS || ARCH_MXC
+    - drm/bridge: megachips: Fix error handling in i2c_register_driver()
+    - drm/vc4: dpi: Add option for inverting pixel clock and output enable
+    - drm/vc4: dpi: Fix format mapping for RGB565
+    - gpu: ipu-v3: common: Add of_node_put() for reference returned by
+      of_graph_get_port_by_id()
+    - drm/msm/hdmi: Add missing check for alloc_ordered_workqueue
+    - pinctrl: stm32: Fix refcount leak in stm32_pctrl_get_irq_domain
+    - ASoC: fsl_sai: initialize is_dsp_mode flag
+    - ALSA: hda/ca0132: minor fix for allocation size
+    - drm/mipi-dsi: Fix byte order of 16-bit DCS set/get brightness
+    - drm/msm: use strscpy instead of strncpy
+    - drm/msm/dpu: Add check for cstate
+    - drm/msm/dpu: Add check for pstates
+    - drm/exynos: Don't reset bridge->next
+    - drm/bridge: Rename bridge helpers targeting a bridge chain
+    - drm/bridge: Introduce drm_bridge_get_next_bridge()
+    - drm: Initialize struct drm_crtc_state.no_vblank from device settings
+    - drm/msm/mdp5: Add check for kzalloc
+    - gpu: host1x: Don't skip assigning syncpoints to channels
+    - drm/mediatek: remove cast to pointers passed to kfree
+    - drm/mediatek: Use NULL instead of 0 for NULL pointer
+    - drm/mediatek: Drop unbalanced obj unref
+    - drm/mediatek: Clean dangling pointer on bind error path
+    - ASoC: soc-compress.c: fixup private_data on snd_soc_new_compress()
+    - gpio: vf610: connect GPIO label to dev name
+    - hwmon: (ltc2945) Handle error case in ltc2945_value_store
+    - scsi: aic94xx: Add missing check for dma_map_single()
+    - spi: bcm63xx-hsspi: fix pm_runtime
+    - spi: bcm63xx-hsspi: Fix multi-bit mode setting
+    - hwmon: (mlxreg-fan) Return zero speed for broken fan
+    - dm: remove flush_scheduled_work() during local_exit()
+    - spi: synquacer: Fix timeout handling in synquacer_spi_transfer_one()
+    - ASoC: dapm: declare missing structure prototypes
+    - ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared
+    - HID: bigben: use spinlock to protect concurrent accesses
+    - HID: bigben_worker() remove unneeded check on report_field
+    - HID: bigben: use spinlock to safely schedule workers
+    - HID: asus: Only set EV_REP if we are adding a mapping
+    - HID: asus: Add report_size to struct asus_touchpad_info
+    - HID: asus: Add support for multi-touch touchpad on Medion Akoya E1239T
+    - HID: asus: Fix mute and touchpad-toggle keys on Medion Akoya E1239T
+    - hid: bigben_probe(): validate report count
+    - nfsd: fix race to check ls_layouts
+    - cifs: Fix lost destroy smbd connection when MR allocate failed
+    - cifs: Fix warning and UAF when destroy the MR list
+    - gfs2: jdata writepage fix
+    - perf llvm: Fix inadvertent file creation
+    - perf tools: Fix auto-complete on aarch64
+    - sparc: allow PM configs for sparc32 COMPILE_TEST
+    - mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read()
+    - clk: qcom: gcc-qcs404: disable gpll[04]_out_aux parents
+    - clk: qcom: gcc-qcs404: fix names of the DSI clocks used as parents
+    - mtd: rawnand: sunxi: Fix the size of the last OOB region
+    - clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed
+    - clk: renesas: cpg-mssr: Use enum clk_reg_layout instead of a boolean flag
+    - clk: renesas: cpg-mssr: Remove superfluous check in resume code
+    - Input: ads7846 - don't report pressure for ads7845
+    - Input: ads7846 - don't check penirq immediately for 7845
+    - clk: qcom: gpucc-sdm845: fix clk_dis_wait being programmed for CX GDSC
+    - powerpc/powernv/ioda: Skip unallocated resources when mapping to PE
+    - clk: Honor CLK_OPS_PARENT_ENABLE in clk_core_is_enabled()
+    - powerpc/pseries/lpar: add missing RTAS retry status handling
+    - powerpc/pseries/lparcfg: add missing RTAS retry status handling
+    - powerpc/rtas: make all exports GPL
+    - powerpc/rtas: ensure 4KB alignment for rtas_data_buf
+    - powerpc/eeh: Small refactor of eeh_handle_normal_event()
+    - powerpc/eeh: Set channel state after notifying the drivers
+    - MIPS: SMP-CPS: fix build error when HOTPLUG_CPU not set
+    - MIPS: vpe-mt: drop physical_memsize
+    - remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
+    - media: platform: ti: Add missing check for devm_regulator_get
+    - powerpc: Remove linker flag from KBUILD_AFLAGS
+    - media: ov5675: Fix memleak in ov5675_init_controls()
+    - media: i2c: ov772x: Fix memleak in ov772x_probe()
+    - media: i2c: ov7670: 0 instead of -EINVAL was returned
+    - media: usb: siano: Fix use after free bugs caused by do_submit_urb
+    - rpmsg: glink: Avoid infinite loop on intent for missing channel
+    - udf: Define EFSCORRUPTED error code
+    - ARM: dts: exynos: Use Exynos5420 compatible for the MIPI video phy
+    - blk-iocost: fix divide by 0 error in calc_lcoefs()
+    - wifi: brcmfmac: Fix potential stack-out-of-bounds in brcmf_c_preinit_dcmds()
+    - rcu: Suppress smp_processor_id() complaint in
+      synchronize_rcu_expedited_wait()
+    - thermal: intel: Fix unsigned comparison with less than zero
+    - timers: Prevent union confusion from unexpected restart_syscall()
+    - x86/bugs: Reset speculation control settings on init
+    - wifi: brcmfmac: ensure CLM version is null-terminated to prevent stack-out-
+      of-bounds
+    - wifi: mt7601u: fix an integer underflow
+    - inet: fix fast path in __inet_hash_connect()
+    - ice: add missing checks for PF vsi type
+    - ACPI: Don't build ACPICA with '-Os'
+    - net: bcmgenet: Add a check for oversized packets
+    - m68k: Check syscall_trace_enter() return code
+    - wifi: mt76: dma: free rx_head in mt76_dma_rx_cleanup
+    - ACPI: video: Fix Lenovo Ideapad Z570 DMI match
+    - net/mlx5: fw_tracer: Fix debug print
+    - coda: Avoid partial allocation of sig_inputArgs
+    - uaccess: Add minimum bounds check on kernel buffer size
+    - drm/amd/display: Fix potential null-deref in dm_resume
+    - drm/omap: dsi: Fix excessive stack usage
+    - HID: Add Mapping for System Microphone Mute
+    - drm/radeon: free iio for atombios when driver shutdown
+    - drm/msm/dsi: Add missing check for alloc_ordered_workqueue
+    - docs/scripts/gdb: add necessary make scripts_gdb step
+    - ASoC: kirkwood: Iterate over array indexes instead of using pointer math
+    - regulator: max77802: Bounds check regulator id against opmode
+    - regulator: s5m8767: Bounds check id indexing into arrays
+    - hwmon: (coretemp) Simplify platform device handling
+    - pinctrl: at91: use devm_kasprintf() to avoid potential leaks
+    - drm: panel-orientation-quirks: Add quirk for Lenovo IdeaPad Duet 3 10IGL5
+    - dm thin: add cond_resched() to various workqueue loops
+    - dm cache: add cond_resched() to various workqueue loops
+    - nfsd: zero out pointers after putting nfsd_files on COPY setup error
+    - wifi: rtl8xxxu: fixing transmisison failure for rtl8192eu
+    - firmware: coreboot: framebuffer: Ignore reserved pixel color bits
+    - rtc: pm8xxx: fix set-alarm race
+    - ipmi_ssif: Rename idle state and check
+    - s390: discard .interp section
+    - s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
+    - s390/kprobes: fix current_kprobe never cleared after kprobes reenter
+    - ARM: dts: exynos: correct HDMI phy compatible in Exynos4
+    - hfs: fix missing hfs_bnode_get() in __hfs_bnode_create
+    - fs: hfsplus: fix UAF issue in hfsplus_put_super
+    - f2fs: fix information leak in f2fs_move_inline_dirents()
+    - f2fs: fix cgroup writeback accounting with fs-layer encryption
+    - ocfs2: fix defrag path triggering jbd2 ASSERT
+    - ocfs2: fix non-auto defrag path not working issue
+    - udf: Truncate added extents on failed expansion
+    - udf: Do not bother merging very long extents
+    - udf: Do not update file length for failed writes to inline files
+    - udf: Preserve link count of system files
+    - udf: Detect system inodes linked into directory hierarchy
+    - udf: Fix file corruption when appending just after end of preallocated
+      extent
+    - KVM: Destroy target device if coalesced MMIO unregistration fails
+    - KVM: s390: disable migration mode when dirty tracking is disabled
+    - x86/virt: Force GIF=1 prior to disabling SVM (for reboot flows)
+    - x86/crash: Disable virt in core NMI crash handler to avoid double shootdown
+    - x86/reboot: Disable virtualization in an emergency if SVM is supported
+    - x86/reboot: Disable SVM, not just VMX, when stopping CPUs
+    - x86/kprobes: Fix __recover_optprobed_insn check optimizing logic
+    - x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe
+      range
+    - x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
+    - x86/microcode/AMD: Add a @cpu parameter to the reloading functions
+    - x86/microcode/AMD: Fix mixed steppings support
+    - x86/speculation: Allow enabling STIBP with legacy IBRS
+    - Documentation/hw-vuln: Document the interaction between IBRS and STIBP
+    - ima: Align ima_file_mmap() parameters with mmap_file LSM hook
+    - irqdomain: Fix association race
+    - irqdomain: Fix disassociation race
+    - irqdomain: Drop bogus fwspec-mapping error handling
+    - ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls()
+    - ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC
+    - ext4: optimize ea_inode block expansion
+    - ext4: refuse to create ea block when umounted
+    - wifi: rtl8xxxu: Use a longer retry limit of 48
+    - wifi: cfg80211: Fix use after free for wext
+    - thermal: intel: powerclamp: Fix cur_state for multi package system
+    - dm flakey: fix logic when corrupting a bio
+    - dm flakey: don't corrupt the zero page
+    - ARM: dts: exynos: correct TMU phandle in Exynos4
+    - ARM: dts: exynos: correct TMU phandle in Odroid XU
+    - rbd: avoid use-after-free in do_rbd_add() when rbd_dev_create() fails
+    - alpha: fix FEN fault handling
+    - mips: fix syscall_get_nr
+    - media: ipu3-cio2: Fix PM runtime usage_count in driver unbind
+    - mm: memcontrol: deprecate charge moving
+    - mm/thp: check and bail out if page in deferred queue already
+    - ktest.pl: Give back console on Ctrt^C on monitor
+    - ktest.pl: Fix missing "end_monitor" when machine check fails
+    - ktest.pl: Add RUN_TIMEOUT option with default unlimited
+    - scsi: qla2xxx: Fix link failure in NPIV environment
+    - scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests
+    - scsi: qla2xxx: Fix erroneous link down
+    - scsi: ses: Don't attach if enclosure has no components
+    - scsi: ses: Fix slab-out-of-bounds in ses_enclosure_data_process()
+    - scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix possible desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix slab-out-of-bounds in ses_intf_remove()
+    - PCI/PM: Observe reset delay irrespective of bridge_d3
+    - PCI: hotplug: Allow marking devices as disconnected during bind/unbind
+    - PCI: Avoid FLR for AMD FCH AHCI adapters
+    - drm/i915/quirks: Add inverted backlight quirk for HP 14-r206nv
+    - drm/radeon: Fix eDP for single-display iMac11,2
+    - wifi: ath9k: use proper statements in conditionals
+    - kbuild: Port silent mode detection to future gnu make.
+    - fs/jfs: fix shift exponent db_agl2size negative
+    - pwm: sifive: Reduce time the controller lock is held
+    - pwm: sifive: Always let the first pwm_apply_state succeed
+    - pwm: stm32-lp: fix the check on arr and cmp registers update
+    - f2fs: use memcpy_{to,from}_page() where possible
+    - fs: f2fs: initialize fsdata in pagecache_write()
+    - um: vector: Fix memory leak in vector_config
+    - ubi: ensure that VID header offset + VID header size <= alloc, size
+    - ubifs: Fix build errors as symbol undefined
+    - ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted
+    - ubifs: Rectify space budget for ubifs_xrename()
+    - ubifs: Fix wrong dirty space budget for dirty inode
+    - ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1
+    - ubifs: Reserve one leb for each journal head while doing budget
+    - ubi: Fix use-after-free when volume resizing failed
+    - ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume()
+    - ubifs: Fix memory leak in alloc_wbufs()
+    - ubi: Fix possible null-ptr-deref in ubi_free_volume()
+    - ubifs: Re-statistic cleaned znode count if commit failed
+    - ubifs: dirty_cow_znode: Fix memleak in error handling path
+    - ubifs: ubifs_writepage: Mark page dirty after writing inode failed
+    - ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show()
+    - ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed
+    - x86: um: vdso: Add '%rcx' and '%r11' to the syscall clobber list
+    - watchdog: at91sam9_wdt: use devm_request_irq to avoid missing free_irq() in
+      error path
+    - watchdog: Fix kmemleak in watchdog_cdev_register
+    - watchdog: pcwd_usb: Fix attempting to access uninitialized memory
+    - netfilter: ctnetlink: fix possible refcount leak in
+      ctnetlink_create_conntrack()
+    - ipv6: Add lwtunnel encap size of all siblings in nexthop calculation
+    - sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop
+    - net: fix __dev_kfree_skb_any() vs drop monitor
+    - 9p/xen: fix version parsing
+    - 9p/xen: fix connection sequence
+    - 9p/rdma: unmap receive dma buffer in rdma_request()/post_recv()
+    - net/mlx5: Geneve, Fix handling of Geneve object id as error code
+    - nfc: fix memory leak of se_io context in nfc_genl_se_io
+    - net/sched: act_sample: fix action bind logic
+    - ARM: dts: spear320-hmi: correct STMPE GPIO compatible
+    - tcp: tcp_check_req() can be called from process context
+    - vc_screen: modify vcs_size() handling in vcs_read()
+    - rtc: sun6i: Make external 32k oscillator optional
+    - rtc: sun6i: Always export the internal oscillator
+    - scsi: ipr: Work around fortify-string warning
+    - thermal: intel: quark_dts: fix error pointer dereference
+    - thermal: intel: BXT_PMIC: select REGMAP instead of depending on it
+    - tracing: Add NULL checks for buffer in ring_buffer_free_read_page()
+    - firmware/efi sysfb_efi: Add quirk for Lenovo IdeaPad Duet 3
+    - mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak
+    - media: uvcvideo: Handle cameras with invalid descriptors
+    - media: uvcvideo: Handle errors from calls to usb_string
+    - media: uvcvideo: Quirk for autosuspend in Logitech B910 and C910
+    - media: uvcvideo: Silence memcpy() run-time false positive warnings
+    - staging: emxx_udc: Add checks for dma_alloc_coherent()
+    - tty: fix out-of-bounds access in tty_driver_lookup_tty()
+    - tty: serial: fsl_lpuart: disable the CTS when send break signal
+    - mei: bus-fixup:upon error print return values of send and receive
+    - tools/iio/iio_utils:fix memory leak
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_status_word()
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_config_word()
+    - usb: host: xhci: mvebu: Iterate over array indexes instead of using pointer
+      math
+    - USB: ene_usb6250: Allocate enough memory for full object
+    - usb: uvc: Enumerate valid values for color matching
+    - kernel/fail_function: fix memory leak with using debugfs_lookup()
+    - PCI: Add ACS quirk for Wangxun NICs
+    - phy: rockchip-typec: Fix unsigned comparison with less than zero
+    - net: tls: avoid hanging tasks on the tx_lock
+    - x86/resctrl: Apply READ_ONCE/WRITE_ONCE to task_struct.{rmid,closid}
+    - x86/resctl: fix scheduler confusion with 'current'
+    - Bluetooth: hci_sock: purge socket queues in the destruct() callback
+    - SAUCE: Revert "UBUNTU: SAUCE: Fix inet_csk_listen_start after CVE-2023-0461"
+    - tcp: Fix listen() regression in 5.4.229.
+    - media: uvcvideo: Provide sync and async uvc_ctrl_status_event
+    - media: uvcvideo: Fix race condition with usb_kill_urb
+    - dt-bindings: rtc: sun6i-a31-rtc: Loosen the requirements on the clocks
+    - Linux 5.4.235
+    - [Config] Drop mxsfb for armhf:generic-lpae
+
+  * Focal update: v5.4.234 upstream stable release (LP: #2017691)
+    - arm64: dts: rockchip: drop unused LED mode property from rk3328-roc-cc
+    - ARM: dts: rockchip: add power-domains property to dp node on rk3288
+    - ACPI: NFIT: fix a potential deadlock during NFIT teardown
+    - btrfs: send: limit number of clones and allocated memory size
+    - IB/hfi1: Assign npages earlier
+    - neigh: make sure used and confirmed times are valid
+    - HID: core: Fix deadloop in hid_apply_multiplier.
+    - bpf: bpf_fib_lookup should not return neigh in NUD_FAILED state
+    - net: Remove WARN_ON_ONCE(sk->sk_forward_alloc) from sk_stream_kill_queues().
+    - vc_screen: don't clobber return value in vcs_read
+    - dmaengine: sh: rcar-dmac: Check for error num after dma_set_max_seg_size
+    - USB: serial: option: add support for VW/Skoda "Carstick LTE"
+    - USB: core: Don't hold device lock while reading the "descriptors" sysfs file
+    - Linux 5.4.234
+
+  * CVE-2023-30456
+    - KVM: nVMX: add missing consistency checks for CR0 and CR4
+
+  * CVE-2023-1859
+    - 9p/xen : Fix use after free bug in xen_9pfs_front_remove due to race
+      condition
+
+  * CVE-2023-1670
+    - xirc2ps_cs: Fix use after free bug in xirc2ps_detach
+
+ -- Roxana Nicolescu <roxana.nicolescu@canonical.com>  Fri, 12 May 2023 17:21:29 +0200
+
+linux (5.4.0-149.166) focal; urgency=medium
+
+  * focal/linux: 5.4.0-149.166 -proposed tracker (LP: #2016591)
+
+  * Focal update: v5.4.233 upstream stable release (LP: #2015909)
+    - dma-mapping: add generic helpers for mapping sgtable objects
+    - scatterlist: add generic wrappers for iterating over sgtable objects
+    - drm: etnaviv: fix common struct sg_table related issues
+    - drm/etnaviv: don't truncate physical page address
+    - wifi: rtl8xxxu: gen2: Turn on the rate control
+    - powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G
+    - random: always mix cycle counter in add_latent_entropy()
+    - KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception
+    - can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len
+    - powerpc: dts: t208x: Disable 10G on MAC1 and MAC2
+    - alarmtimer: Prevent starvation by small intervals and SIG_IGN
+    - drm/i915/gvt: fix double free bug in split_2MB_gtt_entry
+    - mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
+    - uaccess: Add speculation barrier to copy_from_user()
+    - wifi: mwifiex: Add missing compatible string for SD8787
+    - ext4: Fix function prototype mismatch for ext4_feat_ktype
+    - Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo
+      child qdiscs"
+    - bpf: add missing header file include
+    - Linux 5.4.233
+
+  *  selftest: fib_tests: Always cleanup before exit  (LP: #2015956)
+    - selftest: fib_tests: Always cleanup before exit
+
+  * fib_tests.sh in ubuntu_kernel_selftests was skipped silently on Focal
+    (LP: #2015440)
+    - selftests: Fix the executable permissions for fib_tests.sh
+
+  * Debian autoreconstruct Fix restoration of execute permissions (LP: #2015498)
+    - [Debian] autoreconstruct - fix restoration of execute permissions
+
+  * kernel: fix __clear_user() inline assembly constraints (LP: #2013088)
+    - s390/uaccess: add missing earlyclobber annotations to __clear_user()
+
+  * i/o error if next unused loop device is queried (LP: #1856871)
+    - loop: fix I/O error on fsync() in detached loop devices
+
+  * CVE-2023-1075
+    - net/tls: tls_is_tx_ready() checked list_entry
+
+  * Focal update: v5.4.232 upstream stable release (LP: #2011625)
+    - firewire: fix memory leak for payload of request subaction to IEC 61883-1
+      FCP region
+    - bus: sunxi-rsb: Fix error handling in sunxi_rsb_init()
+    - ASoC: Intel: bytcr_rt5651: Drop reference count of ACPI device after use
+    - ALSA: hda/via: Avoid potential array out-of-bound in add_secret_dac_path()
+    - arm64: dts: imx8mm: Fix pad control for UART1_DTE_RX
+    - scsi: Revert "scsi: core: map PQ=1, PDT=other values to
+      SCSI_SCAN_TARGET_PRESENT"
+    - WRITE is "data source", not destination...
+    - fix iov_iter_bvec() "direction" argument
+    - fix "direction" argument of iov_iter_kvec()
+    - netrom: Fix use-after-free caused by accept on already connected socket
+    - netfilter: br_netfilter: disable sabotage_in hook after first suppression
+    - squashfs: harden sanity check in squashfs_read_xattr_id_table
+    - net: phy: meson-gxl: Add generic dummy stubs for MMD register access
+    - can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
+    - ata: libata: Fix sata_down_spd_limit() when no link speed is reported
+    - selftests: net: udpgso_bench_rx: Fix 'used uninitialized' compiler warning
+    - selftests: net: udpgso_bench_rx/tx: Stop when wrong CLI args are provided
+    - selftests: net: udpgso_bench_tx: Cater for pending datagrams zerocopy
+      benchmarking
+    - virtio-net: Keep stop() to follow mirror sequence of open()
+    - net: openvswitch: fix flow memory leak in ovs_flow_cmd_new
+    - efi: fix potential NULL deref in efi_mem_reserve_persistent
+    - scsi: target: core: Fix warning on RT kernels
+    - scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
+    - i2c: rk3x: fix a bunch of kernel-doc warnings
+    - net/x25: Fix to not accept on connected socket
+    - iio: adc: stm32-dfsdm: fill module aliases
+    - usb: dwc3: dwc3-qcom: Fix typo in the dwc3 vbus override API
+    - usb: dwc3: qcom: enable vbus override when in OTG dr-mode
+    - usb: gadget: f_fs: Fix unbalanced spinlock in __ffs_ep0_queue_wait
+    - vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
+    - Input: i8042 - move __initconst to fix code styling warning
+    - Input: i8042 - merge quirk tables
+    - Input: i8042 - add TUXEDO devices to i8042 quirk tables
+    - Input: i8042 - add Clevo PCX0DX to i8042 quirk table
+    - fbcon: Check font dimension limits
+    - watchdog: diag288_wdt: do not use stack buffers for hardware data
+    - watchdog: diag288_wdt: fix __diag288() inline assembly
+    - efi: Accept version 2 of memory attributes table
+    - iio: hid: fix the retval in accel_3d_capture_sample
+    - iio: adc: berlin2-adc: Add missing of_node_put() in error path
+    - iio:adc:twl6030: Enable measurements of VUSB, VBAT and others
+    - parisc: Fix return code of pdc_iodc_print()
+    - parisc: Wire up PTRACE_GETREGS/PTRACE_SETREGS for compat case
+    - riscv: disable generation of unwind tables
+    - mm: hugetlb: proc: check for hugetlb shared PMD in /proc/PID/smaps
+    - fpga: stratix10-soc: Fix return value check in s10_ops_write_init()
+    - mm/swapfile: add cond_resched() in get_swap_pages()
+    - Squashfs: fix handling and sanity checking of xattr_ids count
+    - nvmem: core: fix cell removal on error
+    - mm: swap: properly update readahead statistics in unuse_pte_range()
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - serial: 8250_dma: Fix DMA Rx completion race
+    - serial: 8250_dma: Fix DMA Rx rearm race
+    - powerpc/imc-pmu: Revert nest_init_lock to being a mutex
+    - fbdev: smscufx: fix error handling code in ufx_usb_probe
+    - f2fs: fix to do sanity check on i_extra_isize in is_alive()
+    - wifi: brcmfmac: Check the count value of channel spec to prevent out-of-
+      bounds reads
+    - iio:adc:twl6030: Enable measurement of VAC
+    - btrfs: limit device extents to the device size
+    - btrfs: zlib: zero-initialize zlib workspace
+    - ALSA: emux: Avoid potential array out-of-bound in snd_emux_xg_control()
+    - tracing: Fix poll() and select() do not work on per_cpu trace_pipe and
+      trace_pipe_raw
+    - can: j1939: do not wait 250 ms if the same addr was already claimed
+    - IB/hfi1: Restore allocated resources on failed copyout
+    - IB/IPoIB: Fix legacy IPoIB due to wrong number of queues
+    - iommu: Add gfp parameter to iommu_ops::map
+    - RDMA/usnic: use iommu_map_atomic() under spin_lock()
+    - xfrm: fix bug with DSCP copy to v6 from v4 tunnel
+    - bonding: fix error checking in bond_debug_reregister()
+    - net: phy: meson-gxl: use MMD access dummy stubs for GXL, internal PHY
+    - ionic: clean interrupt before enabling queue to avoid credit race
+    - ice: Do not use WQ_MEM_RECLAIM flag for workqueue
+    - rds: rds_rm_zerocopy_callback() use list_first_entry()
+    - selftests: forwarding: lib: quote the sysctl values
+    - ALSA: pci: lx6464es: fix a debug loop
+    - pinctrl: aspeed: Fix confusing types in return value
+    - pinctrl: single: fix potential NULL dereference
+    - pinctrl: intel: Restore the pins that used to be in Direct IRQ mode
+    - net: USB: Fix wrong-direction WARNING in plusb.c
+    - usb: core: add quirk for Alcor Link AK9563 smartcard reader
+    - usb: typec: altmodes/displayport: Fix probe pin assign check
+    - ceph: flush cap releases when the session is flushed
+    - riscv: Fixup race condition on PG_dcache_clean in flush_icache_pte
+    - arm64: dts: meson-gx: Make mmc host controller interrupts level-sensitive
+    - arm64: dts: meson-g12-common: Make mmc host controller interrupts level-
+      sensitive
+    - arm64: dts: meson-axg: Make mmc host controller interrupts level-sensitive
+    - nvme-pci: Move enumeration by class to be last in the table
+    - bpf: Always return target ifindex in bpf_fib_lookup
+    - migrate: hugetlb: check for hugetlb shared PMD in node migration
+    - selftests/bpf: Verify copy_register_state() preserves parent/live fields
+    - ASoC: cs42l56: fix DT probe
+    - tools/virtio: fix the vringh test for virtio ring changes
+    - net/rose: Fix to not accept on connected socket
+    - net: stmmac: do not stop RX_CLK in Rx LPI state for qcs404 SoC
+    - net: sched: sch: Bounds check priority
+    - s390/decompressor: specify __decompress() buf len to avoid overflow
+    - nvme-fc: fix a missing queue put in nvmet_fc_ls_create_association
+    - aio: fix mremap after fork null-deref
+    - btrfs: free device in btrfs_close_devices for a single device filesystem
+    - netfilter: nft_tproxy: restrict to prerouting hook
+    - xfs: remove the xfs_efi_log_item_t typedef
+    - xfs: remove the xfs_efd_log_item_t typedef
+    - xfs: remove the xfs_inode_log_item_t typedef
+    - xfs: factor out a xfs_defer_create_intent helper
+    - xfs: merge the ->log_item defer op into ->create_intent
+    - xfs: merge the ->diff_items defer op into ->create_intent
+    - xfs: turn dfp_intent into a xfs_log_item
+    - xfs: refactor xfs_defer_finish_noroll
+    - xfs: log new intent items created as part of finishing recovered intent
+      items
+    - xfs: fix finobt btree block recovery ordering
+    - xfs: proper replay of deferred ops queued during log recovery
+    - xfs: xfs_defer_capture should absorb remaining block reservations
+    - xfs: xfs_defer_capture should absorb remaining transaction reservation
+    - xfs: clean up bmap intent item recovery checking
+    - xfs: clean up xfs_bui_item_recover iget/trans_alloc/ilock ordering
+    - xfs: fix an incore inode UAF in xfs_bui_recover
+    - xfs: change the order in which child and parent defer ops are finished
+    - xfs: periodically relog deferred intent items
+    - xfs: expose the log push threshold
+    - xfs: only relog deferred intent items if free space in the log gets low
+    - xfs: fix missing CoW blocks writeback conversion retry
+    - xfs: ensure inobt record walks always make forward progress
+    - xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks
+    - xfs: prevent UAF in xfs_log_item_in_current_chkpt
+    - xfs: sync lazy sb accounting on quiesce of read-only mounts
+    - Revert "ipv4: Fix incorrect route flushing when source address is deleted"
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - mmc: sdio: fix possible resource leaks in some error paths
+    - mmc: mmc_spi: fix error handling in mmc_spi_probe()
+    - ALSA: hda/conexant: add a new hda codec SN6180
+    - ALSA: hda/realtek - fixed wrong gpio assigned
+    - sched/psi: Fix use-after-free in ep_remove_wait_queue()
+    - hugetlb: check for undefined shift on 32 bit architectures
+    - Revert "mm: Always release pages to the buddy allocator in
+      memblock_free_late()."
+    - net: Fix unwanted sign extension in netdev_stats_to_stats64()
+    - revert "squashfs: harden sanity check in squashfs_read_xattr_id_table"
+    - ixgbe: allow to increase MTU to 3K with XDP enabled
+    - i40e: add double of VLAN header when computing the max MTU
+    - net: bgmac: fix BCM5358 support by setting correct flags
+    - sctp: sctp_sock_filter(): avoid list_entry() on possibly empty list
+    - dccp/tcp: Avoid negative sk_forward_alloc by ipv6_pinfo.pktoptions.
+    - net/usb: kalmia: Don't pass act_len in usb_bulk_msg error path
+    - net: stmmac: fix order of dwmac5 FlexPPS parametrization sequence
+    - bnxt_en: Fix mqprio and XDP ring checking logic
+    - net: stmmac: Restrict warning on disabling DMA store and fwd mode
+    - ixgbe: add double of VLAN header when computing the max MTU
+    - ipv6: Fix datagram socket connection with DSCP.
+    - ipv6: Fix tcp socket connection with DSCP.
+    - i40e: Add checking for null for nlmsg_find_attr()
+    - kvm: initialize all of the kvm_debugregs structure before sending it to
+      userspace
+    - nilfs2: fix underflow in second superblock position calculations
+    - ASoC: SOF: Intel: hda-dai: fix possible stream_tag leak
+    - net: sched: sch: Fix off by one in htb_activate_prios()
+    - iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()
+    - Linux 5.4.232
+
+  * CVE-2023-1118
+    - media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 18 Apr 2023 17:54:42 +0200
+
+linux (5.4.0-148.165) focal; urgency=medium
+
+  * focal/linux: 5.4.0-148.165 -proposed tracker (LP: #2016777)
+
+  * CVE-2023-1829
+    - net/sched: Retire tcindex classifier
+    - [Config]: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 18 Apr 2023 05:31:58 -0300
+
+linux (5.4.0-147.164) focal; urgency=medium
+
+  * focal/linux: 5.4.0-147.164 -proposed tracker (LP: #2011959)
+
+  * CVE-2023-26545
+    - net: mpls: fix stale pointer if allocation fails during device rename
+
+  * CVE-2023-1281
+    - rcu: Upgrade rcu_swap_protected() to rcu_replace_pointer()
+    - net/sched: tcindex: update imperfect hash filters respecting rcu
+
+  * Focal update: v5.4.231 upstream stable release (LP: #2011226)
+    - clk: generalize devm_clk_get() a bit
+    - clk: Provide new devm_clk helpers for prepared and enabled clocks
+    - memory: atmel-sdramc: Fix missing clk_disable_unprepare in
+      atmel_ramc_probe()
+    - memory: mvebu-devbus: Fix missing clk_disable_unprepare in
+      mvebu_devbus_probe()
+    - ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts'
+    - ARM: imx27: Retrieve the SYSCTRL base address from devicetree
+    - ARM: imx31: Retrieve the IIM base address from devicetree
+    - ARM: imx35: Retrieve the IIM base address from devicetree
+    - ARM: imx: add missing of_node_put()
+    - HID: intel_ish-hid: Add check for ishtp_dma_tx_map
+    - EDAC/highbank: Fix memory leak in highbank_mc_probe()
+    - tomoyo: fix broken dependency on *.conf.default
+    - RDMA/core: Fix ib block iterator counter overflow
+    - IB/hfi1: Reject a zero-length user expected buffer
+    - IB/hfi1: Reserve user expected TIDs
+    - IB/hfi1: Fix expected receive setup error exit issues
+    - affs: initialize fsdata in affs_truncate()
+    - amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent
+    - amd-xgbe: Delay AN timeout during KR training
+    - bpf: Fix pointer-leak due to insufficient speculative store bypass
+      mitigation
+    - phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in
+      rockchip_usb2phy_power_on()
+    - net: nfc: Fix use-after-free in local_cleanup()
+    - net: wan: Add checks for NULL for utdm in undo_uhdlc_init and unmap_si_regs
+    - gpio: mxc: Always set GPIOs used as interrupt source to INPUT mode
+    - net/sched: sch_taprio: fix possible use-after-free
+    - net: fix a concurrency bug in l2tp_tunnel_register()
+    - l2tp: Serialize access to sk_user_data with sk_callback_lock
+    - l2tp: Don't sleep and disable BH under writer-side sk_callback_lock
+    - net: usb: sr9700: Handle negative len
+    - net: mdio: validate parameter addr in mdiobus_get_phy()
+    - HID: check empty report_list in hid_validate_values()
+    - HID: check empty report_list in bigben_probe()
+    - net: stmmac: fix invalid call to mdiobus_get_phy()
+    - HID: revert CHERRY_MOUSE_000C quirk
+    - usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
+    - usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
+    - net: mlx5: eliminate anonymous module_init & module_exit
+    - drm/panfrost: fix GENERIC_ATOMIC64 dependency
+    - dmaengine: Fix double increment of client_count in dma_chan_get()
+    - net: macb: fix PTP TX timestamp failure due to packet padding
+    - HID: betop: check shape of output reports
+    - dmaengine: xilinx_dma: use devm_platform_ioremap_resource()
+    - dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling
+    - dmaengine: xilinx_dma: call of_node_put() when breaking out of
+      for_each_child_of_node()
+    - tcp: avoid the lookup process failing to get sk in ehash table
+    - w1: fix deadloop in __w1_remove_master_device()
+    - w1: fix WARNING after calling w1_process()
+    - driver core: Fix test_async_probe_init saves device in wrong array
+    - net: dsa: microchip: ksz9477: port map correction in ALU table entry
+      register
+    - tcp: fix rate_app_limited to default to 1
+    - cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist
+    - ASoC: fsl_micfil: Correct the number of steps on SX controls
+    - drm: Add orientation quirk for Lenovo ideapad D330-10IGL
+    - s390/debug: add _ASM_S390_ prefix to header guard
+    - cpufreq: armada-37xx: stop using 0 as NULL pointer
+    - ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
+    - ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
+    - spi: spidev: remove debug messages that access spidev->spi without locking
+    - KVM: s390: interrupt: use READ_ONCE() before cmpxchg()
+    - scsi: hisi_sas: Set a port invalid only if there are no devices attached
+      when refreshing port id
+    - platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD
+    - platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK
+    - lockref: stop doing cpu_relax in the cmpxchg loop
+    - mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
+    - mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
+    - mmc: sdhci-esdhc-imx: correct the tuning start tap and step setting
+    - netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state
+    - fs: reiserfs: remove useless new_opts in reiserfs_remount
+    - Bluetooth: hci_sync: cancel cmd_timer if hci_open failed
+    - scsi: hpsa: Fix allocation size for scsi_host_alloc()
+    - module: Don't wait for GOING modules
+    - tracing: Make sure trace_printk() can output as soon as it can be used
+    - trace_events_hist: add check for return value of 'create_hist_field'
+    - ftrace/scripts: Update the instructions for ftrace-bisect.sh
+    - cifs: Fix oops due to uncleared server->smbd_conn in reconnect
+    - KVM: x86/vmx: Do not skip segment attributes if unusable bit is set
+    - thermal: intel: int340x: Protect trip temperature from concurrent updates
+    - ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment
+    - EDAC/device: Respect any driver-supplied workqueue polling value
+    - EDAC/qcom: Do not pass llcc_driv_data as edac_device_ctl_info's pvt_info
+    - netlink: prevent potential spectre v1 gadgets
+    - net: fix UaF in netns ops registration error path
+    - netfilter: nft_set_rbtree: skip elements in transaction from garbage
+      collection
+    - netlink: annotate data races around nlk->portid
+    - netlink: annotate data races around dst_portid and dst_group
+    - netlink: annotate data races around sk_state
+    - ipv4: prevent potential spectre v1 gadget in ip_metrics_convert()
+    - ipv4: prevent potential spectre v1 gadget in fib_metrics_match()
+    - netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE
+    - netrom: Fix use-after-free of a listening socket.
+    - net/sched: sch_taprio: do not schedule in taprio_reset()
+    - sctp: fail if no bound addresses can be used for a given scope
+    - net: ravb: Fix possible hang if RIS2_QFF1 happen
+    - thermal: intel: int340x: Add locking to int340x_thermal_get_trip_type()
+    - net/tg3: resolve deadlock in tg3_reset_task() during EEH
+    - net/phy/mdio-i2c: Move header file to include/linux/mdio
+    - net: xgene: Move shared header file into include/linux
+    - net: mdio-mux-meson-g12a: force internal PHY off on mux switch
+    - Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI
+      mode"
+    - nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted
+    - block: fix and cleanup bio_check_ro
+    - x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
+    - netfilter: conntrack: unify established states for SCTP paths
+    - perf/x86/amd: fix potential integer overflow on shift of a int
+    - clk: Fix pointer casting to prevent oops in devm_clk_release()
+    - x86/asm: Fix an assembler warning with current binutils
+    - ARM: dts: imx: Fix pca9547 i2c-mux node name
+    - bpf: Skip task with pid=1 in send_signal_common()
+    - blk-cgroup: fix missing pd_online_fn() while activating policy
+    - dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init
+    - sysctl: add a new register_sysctl_init() interface
+    - panic: unset panic_on_warn inside panic()
+    - mm: kasan: do not panic if both panic_on_warn and kasan_multishot set
+    - exit: Add and use make_task_dead.
+    - objtool: Add a missing comma to avoid string concatenation
+    - hexagon: Fix function name in die()
+    - h8300: Fix build errors from do_exit() to make_task_dead() transition
+    - csky: Fix function name in csky_alignment() and die()
+    - ia64: make IA64_MCA_RECOVERY bool instead of tristate
+    - exit: Put an upper limit on how often we can oops
+    - exit: Expose "oops_count" to sysfs
+    - exit: Allow oops_limit to be disabled
+    - panic: Consolidate open-coded panic_on_warn checks
+    - panic: Introduce warn_limit
+    - panic: Expose "warn_count" to sysfs
+    - docs: Fix path paste-o for /sys/kernel/warn_count
+    - exit: Use READ_ONCE() for all oops/warn limit reads
+    - ipv6: ensure sane device mtu in tunnels
+    - Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt
+    - usb: host: xhci-plat: add wakeup entry at sysfs
+    - Revert "xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()"
+    - Linux 5.4.231
+
+  * CVE-2022-3903
+    - USB: add usb_control_msg_send() and usb_control_msg_recv()
+    - USB: correct API of usb_control_msg_send/recv
+    - USB: move snd_usb_pipe_sanity_check into the USB core
+    - media: mceusb: Use new usb_control_msg_*() routines
+
+  * CVE-2022-3108
+    - drm/amdkfd: Check for null pointer after calling kmemdup
+
+  * Focal update: v5.4.230 upstream stable release (LP: #2008946)
+    - pNFS/filelayout: Fix coalescing test for single DS
+    - net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats
+    - RDMA/srp: Move large values to a new enum for gcc13
+    - f2fs: let's avoid panic if extent_tree is not created
+    - wifi: brcmfmac: fix regression for Broadcom PCIe wifi devices
+    - Add exception protection processing for vd in axi_chan_handle_err function
+    - nilfs2: fix general protection fault in nilfs_btree_insert()
+    - efi: fix userspace infinite retry read efivars after EFI runtime services
+      page fault
+    - drm/i915/gt: Reset twice
+    - ALSA: hda/realtek - Turn on power early
+    - xhci-pci: set the dma max_seg_size
+    - usb: xhci: Check endpoint is valid before dereferencing it
+    - xhci: Fix null pointer dereference when host dies
+    - xhci: Add update_hub_device override for PCI xHCI hosts
+    - xhci: Add a flag to disable USB3 lpm on a xhci root port level.
+    - usb: acpi: add helper to check port lpm capability using acpi _DSM
+    - xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
+    - prlimit: do_prlimit needs to have a speculation check
+    - USB: serial: option: add Quectel EM05-G (GR) modem
+    - USB: serial: option: add Quectel EM05-G (CS) modem
+    - USB: serial: option: add Quectel EM05-G (RS) modem
+    - USB: serial: option: add Quectel EC200U modem
+    - USB: serial: option: add Quectel EM05CN (SG) modem
+    - USB: serial: option: add Quectel EM05CN modem
+    - USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
+    - misc: fastrpc: Don't remove map on creater_process and device_release
+    - misc: fastrpc: Fix use-after-free race condition for maps
+    - usb: core: hub: disable autosuspend for TI TUSB8041
+    - comedi: adv_pci1760: Fix PWM instruction handling
+    - mmc: sunxi-mmc: Fix clock refcount imbalance during unbind
+    - btrfs: fix race between quota rescan and disable leading to NULL pointer
+      deref
+    - cifs: do not include page data when checking signature
+    - USB: serial: cp210x: add SCALANCE LPE-9000 device id
+    - usb: host: ehci-fsl: Fix module alias
+    - usb: typec: altmodes/displayport: Add pin assignment helper
+    - usb: typec: altmodes/displayport: Fix pin assignment calculation
+    - usb: gadget: g_webcam: Send color matching descriptor per frame
+    - usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
+    - usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210
+    - dt-bindings: phy: g12a-usb3-pcie-phy: fix compatible string documentation
+    - serial: pch_uart: Pass correct sg to dma_unmap_sg()
+    - dmaengine: tegra210-adma: fix global intr clear
+    - serial: atmel: fix incorrect baudrate setup
+    - gsmi: fix null-deref in gsmi_get_variable
+    - drm/i915: re-disable RC6p on Sandy Bridge
+    - drm/amd/display: Fix set scaling doesn's work
+    - drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix
+    - x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
+    - mm/khugepaged: fix collapse_pte_mapped_thp() to allow anon_vma
+    - Linux 5.4.230
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 21 Mar 2023 10:50:49 +0100
+
+linux (5.4.0-146.163) focal; urgency=medium
+
+  * focal/linux: 5.4.0-146.163 -proposed tracker (LP: #2012094)
+
+  * NFS deathlock with last Kernel 5.4.0-144.161 and 5.15.0-67.74 (LP: #2009325)
+    - NFS: Correct timing for assigning access cache timestamp
+
+ -- Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>  Fri, 17 Mar 2023 11:08:20 -0700
+
+linux (5.4.0-145.162) focal; urgency=medium
+
+  * focal/linux: 5.4.0-145.162 -proposed tracker (LP: #2008389)
+
+  * [SRU]Update ice driver to support E823 devices (LP: #1986717)
+    - ice: Add device ids for E822 devices
+    - ice: add support for E823 devices
+
+  * btrfs/154: rename fails with EOVERFLOW when calculating item size during
+    item key collision (LP: #2004132)
+    - btrfs: correctly calculate item size used when item key collision happens
+
+  * rtcpie in timers from ubuntu_kernel_selftests randomly failing
+    (LP: #1814234)
+    - SAUCE: selftest: rtcpie: Force passing unreliable subtest
+
+  * [UBUNTU 20.04] KVM: s390: pv: don't allow userspace to set the clock under
+    PV - kernel part (LP: #1999882)
+    - KVM: s390x: fix SCK locking
+    - KVM: s390: pv: don't allow userspace to set the clock under PV
+
+  * CVE-2021-3669
+    - ipc: replace costly bailout check in sysvipc_find_ipc()
+
+  * net:fcnal-test.sh 'nettest' command not found on F/K (LP: #2006391)
+    - selftests/net: Find nettest in current directory
+
+  * xfs: Preallocated ioend transactions cause deadlock due to log buffer
+    exhaustion (LP: #2007219)
+    - xfs: drop submit side trans alloc for append ioends
+
+  * CVE-2022-4382
+    - USB: gadgetfs: Fix race between mounting and unmounting
+
+  * CVE-2022-2196
+    - KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
+
+  * ubuntu_kernel_selftests: net:udpgso_bench.sh failed (LP: #1951447)
+    - selftests: net: udpgso_bench: Fix racing bug between the rx/tx programs
+
+  * net:fcnal-test.sh didn't return a non-zero value even with some sub-tests
+    failed (LP: #2006692)
+    - selftests: net/fcnal-test.sh: add exit code
+
+  * Fix selftests/ftracetests/Meta-selftests in Focal (LP: #2006453)
+    - SAUCE: Fix ftrace/Meta-selftests bashism check
+
+  * CVE-2023-23559
+    - wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 24 Feb 2023 14:09:22 +0100
+
+linux (5.4.0-144.161) focal; urgency=medium
+
+  * focal/linux: 5.4.0-144.161 -proposed tracker (LP: #2004653)
+
+  * CVE-2023-0461
+    - SAUCE: Fix inet_csk_listen_start after CVE-2023-0461
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 03 Feb 2023 15:30:55 +0100
+
+linux (5.4.0-143.160) focal; urgency=medium
+
+  * focal/linux: 5.4.0-143.160 -proposed tracker (LP: #2004385)
+
+  * NFS: client permission error after adding user to permissible group
+    (LP: #2003053)
+    - NFS: Clear the file access cache upon login
+    - NFS: Judge the file access cache's timestamp in rcu path
+    - NFS: Fix up a sparse warning
+
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914)
+    - tracing/ring-buffer: Only do full wait when cpu != RING_BUFFER_ALL_CPUS
+    - udf: Discard preallocation before extending file with a hole
+    - udf: Fix preallocation discarding at indirect extent boundary
+    - udf: Do not bother looking for prealloc extents if i_lenExtents matches
+      i_size
+    - udf: Fix extending file within last block
+    - usb: gadget: uvc: Prevent buffer overflow in setup handler
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: cp210x: add Kamstrup RF sniffer PIDs
+    - USB: serial: f81232: fix division by zero on line-speed change
+    - USB: serial: f81534: fix division by zero on line-speed change
+    - igb: Initialize mailbox message for VF reset
+    - xen-netback: move removal of "hotplug-status" to the right place
+    - HID: ite: Add support for Acer S1002 keyboard-dock
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch 10E
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch V 10
+    - HID: uclogic: Add HID_QUIRK_HIDINPUT_FORCE quirk
+    - net: loopback: use NET_NAME_PREDICTABLE for name_assign_type
+    - usb: musb: remove extra check in musb_gadget_vbus_draw
+    - ARM: dts: qcom: apq8064: fix coresight compatible
+    - arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
+    - drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
+    - arm: dts: spear600: Fix clcd interrupt
+    - soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of
+      pm_runtime_get_sync
+    - soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
+    - soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
+    - perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
+    - perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
+    - arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
+    - arm64: dts: mt2712e: Fix unit address for pinctrl node
+    - arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
+    - arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
+    - arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
+    - ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: turris-omnia: Add ethernet aliases
+    - ARM: dts: turris-omnia: Add switch port 6 node
+    - arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
+    - pstore/ram: Fix error return code in ramoops_probe()
+    - ARM: mmp: fix timer_read delay
+    - pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
+    - tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
+    - cpuidle: dt: Return the correct numbers of parsed idle states
+    - alpha: fix syscall entry in !AUDUT_SYSCALL case
+    - PM: hibernate: Fix mistake in kerneldoc comment
+    - fs: don't audit the capability check in simple_xattr_list()
+    - selftests/ftrace: event_triggers: wait longer for test_event_enable
+    - perf: Fix possible memleak in pmu_dev_alloc()
+    - timerqueue: Use rb_entry_safe() in timerqueue_getnext()
+    - proc: fixup uptime selftest
+    - lib/fonts: fix undefined behavior in bit shift for get_default_font
+    - ocfs2: fix memory leak in ocfs2_stack_glue_init()
+    - MIPS: vpe-mt: fix possible memory leak while module exiting
+    - MIPS: vpe-cmp: fix possible memory leak while module exiting
+    - selftests/efivarfs: Add checking of the test return value
+    - PNP: fix name memory leak in pnp_alloc_dev()
+    - perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
+    - irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
+    - EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
+    - nfsd: don't call nfsd_file_put from client states seqfile display
+    - genirq/irqdesc: Don't try to remove non-existing sysfs files
+    - cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
+    - libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
+    - lib/notifier-error-inject: fix error when writing -errno to debugfs file
+    - docs: fault-injection: fix non-working usage of negative values
+    - debugfs: fix error when writing negative value to atomic_t debugfs file
+    - ocfs2: ocfs2_mount_volume does cleanup job before return error
+    - ocfs2: rewrite error handling of ocfs2_fill_super
+    - ocfs2: fix memory leak in ocfs2_mount_volume()
+    - rapidio: fix possible name leaks when rio_add_device() fails
+    - rapidio: rio: fix possible name leak in rio_register_mport()
+    - clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
+    - ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
+    - uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
+    - xen/events: only register debug interrupt for 2-level events
+    - x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
+    - x86/xen: Fix memory leak in xen_init_lock_cpu()
+    - xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
+    - PM: runtime: Improve path in rpm_idle() when no callback
+    - PM: runtime: Do not call __rpm_callback() from rpm_idle()
+    - platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
+    - MIPS: BCM63xx: Add check for NULL for clk in clk_enable
+    - MIPS: OCTEON: warn only once if deprecated link status is being used
+    - fs: sysv: Fix sysv_nblocks() returns wrong value
+    - rapidio: fix possible UAF when kfifo_alloc() fails
+    - eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
+    - relay: fix type mismatch when allocating memory in relay_create_buf()
+    - hfs: Fix OOB Write in hfs_asc2mac
+    - rapidio: devices: fix missing put_device in mport_cdev_open
+    - wifi: ath9k: hif_usb: fix memory leak of urbs in
+      ath9k_hif_usb_dealloc_tx_urbs()
+    - wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
+    - wifi: rtl8xxxu: Fix reading the vendor of combo chips
+    - pata_ipx4xx_cf: Fix unsigned comparison with less than zero
+    - media: i2c: ad5820: Fix error path
+    - can: kvaser_usb: do not increase tx statistics when sending error message
+      frames
+    - can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
+    - can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to
+      {leaf,usbcan}_cmd_can_error_event
+    - can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
+    - can: kvaser_usb_leaf: Set Warning state even without bus errors
+    - can: kvaser_usb_leaf: Fix improved state not being reported
+    - can: kvaser_usb_leaf: Fix wrong CAN state after stopping
+    - can: kvaser_usb_leaf: Fix bogus restart events
+    - can: kvaser_usb: Add struct kvaser_usb_busparams
+    - can: kvaser_usb: Compare requested bittiming parameters with actual
+      parameters in do_set_{,data}_bittiming
+    - clk: renesas: r9a06g032: Repair grave increment error
+    - spi: Update reference to struct spi_controller
+    - drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
+    - ima: Rename internal filter rule functions
+    - ima: Fix fall-through warnings for Clang
+    - ima: Handle -ESTALE returned by ima_filter_rule_match()
+    - media: vivid: fix compose size exceed boundary
+    - bpf: propagate precision in ALU/ALU64 operations
+    - mtd: Fix device name leak when register device failed in add_mtd_device()
+    - wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
+    - media: camss: Clean up received buffers on failed start of streaming
+    - net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
+    - rxrpc: Fix ack.bufferSize to be 0 when generating an ack
+    - drm/radeon: Add the missed acpi_put_table() to fix memory leak
+    - drm/mediatek: Modify dpi power on/off sequence.
+    - ASoC: pxa: fix null-pointer dereference in filter()
+    - regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
+    - amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
+    - integrity: Fix memory leakage in keyring allocation error path
+    - ima: Fix misuse of dereference of pointer in template_desc_init_fields()
+    - wifi: ath10k: Fix return value in ath10k_pci_init()
+    - mtd: lpddr2_nvm: Fix possible null-ptr-deref
+    - Input: elants_i2c - properly handle the reset GPIO when power is off
+    - media: solo6x10: fix possible memory leak in solo_sysfs_init()
+    - media: platform: exynos4-is: Fix error handling in fimc_md_init()
+    - media: videobuf-dma-contig: use dma_mmap_coherent
+    - bpf: Move skb->len == 0 checks into __bpf_redirect
+    - HID: hid-sensor-custom: set fixed size for custom attributes
+    - ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
+    - ALSA: seq: fix undefined behavior in bit shift for
+      SNDRV_SEQ_FILTER_USE_EVENT
+    - regulator: core: use kfree_const() to free space conditionally
+    - clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
+    - bonding: Export skip slave logic to function
+    - bonding: Rename slave_arr to usable_slaves
+    - bonding: fix link recovery in mode 2 when updelay is nonzero
+    - mtd: maps: pxa2xx-flash: fix memory leak in probe
+    - media: imon: fix a race condition in send_packet()
+    - clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
+    - clk: imx: replace osc_hdmi with dummy
+    - pinctrl: pinconf-generic: add missing of_node_put()
+    - media: dvb-core: Fix ignored return value in dvb_register_frontend()
+    - media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
+    - media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
+    - drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
+    - ASoC: dt-bindings: wcd9335: fix reset line polarity in example
+    - ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
+    - NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
+    - NFSv4.2: Fix a memory stomp in decode_attr_security_label
+    - NFSv4.2: Fix initialisation of struct nfs4_label
+    - NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
+    - ALSA: asihpi: fix missing pci_disable_device()
+    - wifi: iwlwifi: mvm: fix double free on tx path.
+    - ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
+    - drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
+    - drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
+    - ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
+    - netfilter: conntrack: set icmpv6 redirects as RELATED
+    - bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
+    - bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
+    - bonding: uninitialized variable in bond_miimon_inspect()
+    - spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
+    - wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys()
+      fails
+    - regulator: core: fix module refcount leak in set_supply()
+    - clk: qcom: clk-krait: fix wrong div2 functions
+    - hsr: Avoid double remove of a node.
+    - configfs: fix possible memory leak in configfs_create_dir()
+    - regulator: core: fix resource leak in regulator_register()
+    - bpf, sockmap: fix race in sock_map_free()
+    - media: saa7164: fix missing pci_disable_device()
+    - ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - SUNRPC: Fix missing release socket in rpc_sockname()
+    - NFSv4.x: Fail client initialisation if state manager thread can't run
+    - mmc: alcor: fix return value check of mmc_add_host()
+    - mmc: moxart: fix return value check of mmc_add_host()
+    - mmc: mxcmmc: fix return value check of mmc_add_host()
+    - mmc: pxamci: fix return value check of mmc_add_host()
+    - mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
+    - mmc: toshsd: fix return value check of mmc_add_host()
+    - mmc: vub300: fix return value check of mmc_add_host()
+    - mmc: wmt-sdmmc: fix return value check of mmc_add_host()
+    - mmc: atmel-mci: fix return value check of mmc_add_host()
+    - mmc: omap_hsmmc: fix return value check of mmc_add_host()
+    - mmc: meson-gx: fix return value check of mmc_add_host()
+    - mmc: via-sdmmc: fix return value check of mmc_add_host()
+    - mmc: wbsd: fix return value check of mmc_add_host()
+    - mmc: mmci: fix return value check of mmc_add_host()
+    - media: c8sectpfe: Add of_node_put() when breaking out of loop
+    - media: coda: Add check for dcoda_iram_alloc
+    - media: coda: Add check for kmalloc
+    - clk: samsung: Fix memory leak in _samsung_clk_register_pll()
+    - spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
+    - wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
+    - wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
+    - blktrace: Fix output non-blktrace event when blk_classic option enabled
+    - clk: socfpga: clk-pll: Remove unused variable 'rc'
+    - clk: socfpga: use clk_hw_register for a5/c5
+    - clk: socfpga: Fix memory leak in socfpga_gate_init()
+    - net: vmw_vsock: vmci: Check memcpy_from_msg()
+    - net: defxx: Fix missing err handling in dfx_init()
+    - net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
+    - drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
+    - of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry()
+      and find_dup_cset_prop()
+    - ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: farsync: Fix kmemleak when rmmods farsync
+    - net/tunnel: wait until all sk_user_data reader finish before releasing the
+      sock
+    - net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd-xgbe: Fix logic around active and passive cables
+    - net: amd-xgbe: Check only the minimum speed for active/passive cables
+    - can: tcan4x5x: Remove invalid write in clear_interrupts
+    - net: lan9303: Fix read error execution path
+    - ntb_netdev: Use dev_kfree_skb_any() in interrupt context
+    - Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
+    - stmmac: fix potential division by 0
+    - apparmor: fix a memleak in multi_transaction_new()
+    - apparmor: fix lockdep warning when removing a namespace
+    - apparmor: Fix abi check to include v8 abi
+    - apparmor: Use pointer to struct aa_label for lbs_cred
+    - RDMA/core: Fix order of nldev_exit call
+    - f2fs: fix normal discard process
+    - RDMA/siw: Fix immediate work request flush to completion queue
+    - RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
+    - RDMA/siw: Set defined status for work completion with undefined status
+    - scsi: scsi_debug: Fix a warning in resp_write_scat()
+    - crypto: ccree - swap SHA384 and SHA512 larval hashes at build time
+    - crypto: ccree - Remove debugfs when platform_driver_register failed
+    - PCI: Check for alloc failure in pci_request_irq()
+    - RDMA/hfi: Decrease PCI device reference count in error path
+    - crypto: ccree - Make cc_debugfs_global_fini() available for module init
+      function
+    - RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create
+      failed
+    - scsi: hpsa: Fix possible memory leak in hpsa_init_one()
+    - crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
+    - scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
+    - scsi: hpsa: Fix error handling in hpsa_add_sas_host()
+    - scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
+    - scsi: fcoe: Fix possible name leak when device_register() fails
+    - scsi: ipr: Fix WARNING in ipr_init()
+    - scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
+    - scsi: snic: Fix possible UAF in snic_tgt_create()
+    - RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
+    - f2fs: avoid victim selection from previous victim section
+    - crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
+    - RDMA/hfi1: Fix error return code in parse_platform_config()
+    - orangefs: Fix sysfs not cleanup when dev init failed
+    - crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
+    - hwrng: amd - Fix PCI device refcount leak
+    - hwrng: geode - Fix PCI device refcount leak
+    - IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
+    - drivers: dio: fix possible memory leak in dio_init()
+    - tty: serial: tegra: Activate RX DMA transfer by request
+    - serial: tegra: Read DMA status before terminating
+    - class: fix possible memory leak in __class_register()
+    - vfio: platform: Do not pass return buffer to ACPI _RST method
+    - uio: uio_dmem_genirq: Fix missing unlock in irq configuration
+    - uio: uio_dmem_genirq: Fix deadlock between irq config and handling
+    - usb: fotg210-udc: Fix ages old endianness issues
+    - staging: vme_user: Fix possible UAF in tsi148_dma_list_add
+    - usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
+    - usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
+    - serial: amba-pl011: avoid SBSA UART accessing DMACR register
+    - serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
+    - serial: pch: Fix PCI device refcount leak in pch_request_dma()
+    - tty: serial: clean up stop-tx part in altera_uart_tx_chars()
+    - tty: serial: altera_uart_{r,t}x_chars() need only uart_port
+    - serial: altera_uart: fix locking in polling mode
+    - serial: sunsab: Fix error handling in sunsab_init()
+    - test_firmware: fix memory leak in test_firmware_init()
+    - misc: ocxl: fix possible name leak in ocxl_file_register_afu()
+    - misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
+    - misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault
+      and gru_handle_user_call_os
+    - cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
+    - cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
+    - counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
+    - usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
+    - usb: gadget: f_hid: optional SETUP/SET_REPORT mode
+    - usb: gadget: f_hid: fix f_hidg lifetime vs cdev
+    - usb: gadget: f_hid: fix refcount leak on error path
+    - drivers: mcb: fix resource leak in mcb_probe()
+    - mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
+    - chardev: fix error handling in cdev_device_add()
+    - i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
+    - staging: rtl8192u: Fix use after free in ieee80211_rx()
+    - staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
+    - vme: Fix error not catched in fake_init()
+    - i2c: ismt: Fix an out-of-bounds bug in ismt_access()
+    - usb: storage: Add check for kcalloc
+    - tracing/hist: Fix issue of losting command info in error_log
+    - samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
+    - fbdev: ssd1307fb: Drop optional dependency
+    - fbdev: pm2fb: fix missing pci_disable_device()
+    - fbdev: via: Fix error in via_core_init()
+    - fbdev: vermilion: decrease reference count in error path
+    - fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
+    - HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
+    - HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
+    - power: supply: fix residue sysfs file in error handle route of
+      __power_supply_register()
+    - perf trace: Return error if a system call doesn't exist
+    - perf trace: Separate 'struct syscall_fmt' definition from syscall_fmts
+      variable
+    - perf trace: Factor out the initialization of syscal_arg_fmt->scnprintf
+    - perf trace: Add the syscall_arg_fmt pointer to syscall_arg
+    - perf trace: Allow associating scnprintf routines with well known arg names
+    - perf trace: Add a strtoul() method to 'struct syscall_arg_fmt'
+    - perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
+    - perf trace: Handle failure when trace point folder is missed
+    - perf symbol: correction while adjusting symbol
+    - HSI: omap_ssi_core: Fix error handling in ssi_init()
+    - power: supply: fix null pointer dereferencing in
+      power_supply_get_battery_info
+    - RDMA/siw: Fix pointer cast warning
+    - include/uapi/linux/swab: Fix potentially missing __always_inline
+    - rtc: snvs: Allow a time difference on clock register read
+    - rtc: pcf85063: Fix reading alarm
+    - iommu/amd: Fix pci device refcount leak in ppr_notifier()
+    - iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
+    - macintosh: fix possible memory leak in macio_add_one_device()
+    - macintosh/macio-adb: check the return value of ioremap()
+    - powerpc/52xx: Fix a resource leak in an error handling path
+    - cxl: Fix refcount leak in cxl_calc_capp_routing
+    - powerpc/xive: add missing iounmap() in error path in
+      xive_spapr_populate_irq_data()
+    - powerpc/perf: callchain validate kernel stack pointer bounds
+    - powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in
+      of_fsl_spi_probe()
+    - powerpc/hv-gpci: Fix hv_gpci event list
+    - selftests/powerpc: Fix resource leaks
+    - pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
+    - remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
+    - remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in
+      adsp_alloc_memory_region()
+    - rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
+    - rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
+    - nfsd: Define the file access mode enum for tracing
+    - NFSD: Add tracepoints to NFSD's duplicate reply cache
+    - nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
+    - mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - nfc: pn533: Clear nfc_target before being used
+    - r6040: Fix kmemleak in probe and remove
+    - rtc: mxc_v2: Add missing clk_disable_unprepare()
+    - openvswitch: Fix flow lookup to use unmasked key
+    - skbuff: Account for tail adjustment during pull operations
+    - mailbox: zynq-ipi: fix error handling while device_register() fails
+    - net_sched: reject TCF_EM_SIMPLE case for complex ematch module
+    - rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
+    - myri10ge: Fix an error handling path in myri10ge_probe()
+    - net: stream: purge sk_error_queue in sk_stream_kill_queues()
+    - rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
+    - binfmt_misc: fix shift-out-of-bounds in check_special_flags
+    - fs: jfs: fix shift-out-of-bounds in dbAllocAG
+    - udf: Avoid double brelse() in udf_rename()
+    - fs: jfs: fix shift-out-of-bounds in dbDiscardAG
+    - ACPICA: Fix error code path in acpi_ds_call_control_method()
+    - nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
+    - acct: fix potential integer overflow in encode_comp_t()
+    - hfs: fix OOB Read in __hfs_brec_find
+    - drm/etnaviv: add missing quirks for GC300
+    - brcmfmac: return error when getting invalid max_flowrings from dongle
+    - wifi: ath9k: verify the expected usb_endpoints are present
+    - wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
+    - ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
+    - ipmi: fix memleak when unload ipmi driver
+    - bpf: make sure skb->len != 0 when redirecting to a tunneling device
+    - net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
+    - hamradio: baycom_epp: Fix return type of baycom_send_packet()
+    - wifi: brcmfmac: Fix potential shift-out-of-bounds in
+      brcmf_fw_alloc_request()
+    - igb: Do not free q_vector unless new one was allocated
+    - s390/ctcm: Fix return type of ctc{mp,}m_tx()
+    - s390/netiucv: Fix return type of netiucv_tx()
+    - s390/lcs: Fix return type of lcs_start_xmit()
+    - drm/rockchip: Use drm_mode_copy()
+    - drm/sti: Use drm_mode_copy()
+    - drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
+    - md/raid1: stop mdx_raid1 thread when raid1 array run failed
+    - net: add atomic_long_t to net_device_stats fields
+    - mrp: introduce active flags to prevent UAF when applicant uninit
+    - ppp: associate skb with a device at tx
+    - bpf: Prevent decl_tag from being referenced in func_proto arg
+    - media: dvb-frontends: fix leak of memory fw
+    - media: dvbdev: adopts refcnt to avoid UAF
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
+    - blk-mq: fix possible memleak when register 'hctx' failed
+    - regulator: core: fix use_count leakage when handling boot-on
+    - mmc: f-sdh30: Add quirks for broken timeout clock capability
+    - media: si470x: Fix use-after-free in si470x_int_in_callback()
+    - clk: st: Fix memory leak in st_of_quadfs_setup()
+    - hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
+    - drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
+    - drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
+    - orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
+    - orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
+    - ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
+    - ALSA: hda: add snd_hdac_stop_streams() helper
+    - ASoC: Intel: Skylake: Fix driver hang during shutdown
+    - ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in
+      mt8173_rt5650_rt5514_dev_probe()
+    - ASoC: audio-graph-card: fix refcount leak of cpu_ep in
+      __graph_for_each_link()
+    - ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in
+      rockchip_pdm_runtime_resume()
+    - ASoC: wm8994: Fix potential deadlock
+    - ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in
+      rk_spdif_runtime_resume()
+    - ASoC: rt5670: Remove unbalanced pm_runtime_put()
+    - pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
+    - pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
+    - ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
+    - ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
+    - usb: dwc3: core: defer probe on ulpi_read_id timeout
+    - HID: wacom: Ensure bootloader PID is usable in hidraw mode
+    - reiserfs: Add missing calls to reiserfs_security_free()
+    - iio: adc: ad_sigma_delta: do not use internal iio_dev lock
+    - iio: adc128s052: add proper .data members in adc128_of_match table
+    - regulator: core: fix deadlock on regulator enable
+    - gcov: add support for checksum field
+    - media: dvbdev: fix build warning due to comments
+    - media: dvbdev: fix refcnt bug
+    - cifs: fix oops during encryption
+    - nvme-pci: fix doorbell buffer value endianness
+    - ata: ahci: Fix PCS quirk application for suspend
+    - nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
+    - objtool: Fix SEGFAULT
+    - powerpc/rtas: avoid device tree lookups in rtas_os_term()
+    - powerpc/rtas: avoid scheduling in rtas_os_term()
+    - HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
+    - HID: plantronics: Additional PIDs for double volume key presses quirk
+    - hfsplus: fix bug causing custom uid and gid being unable to be assigned with
+      mount
+    - ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
+    - ALSA: line6: correct midi status byte when receiving data from podxt
+    - ALSA: line6: fix stack overflow in line6_midi_transmit
+    - pnode: terminate at peers of source
+    - md: fix a crash in mempool_free
+    - mm, compaction: fix fast_isolate_around() to stay within boundaries
+    - f2fs: should put a page when checking the summary info
+    - mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
+    - tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
+    - tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
+    - SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
+    - net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
+    - net/af_packet: make sure to pull mac header
+    - media: stv0288: use explicitly signed char
+    - soc: qcom: Select REMAP_MMIO for LLCC driver
+    - kest.pl: Fix grub2 menu handling for rebooting
+    - ktest.pl minconfig: Unset configs instead of just removing them
+    - mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
+    - btrfs: fix resolving backrefs for inline extent followed by prealloc
+    - ARM: ux500: do not directly dereference __iomem
+    - arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
+    - selftests: Use optional USERCFLAGS and USERLDFLAGS
+    - cpufreq: Init completion before kobject_init_and_add()
+    - binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf
+    - binfmt: Fix error return code in load_elf_fdpic_binary()
+    - dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
+    - dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
+    - dm thin: Use last transaction's pmd->root when commit failed
+    - dm thin: Fix UAF in run_timer_softirq()
+    - dm integrity: Fix UAF in dm_integrity_dtr()
+    - dm clone: Fix UAF in clone_dtr()
+    - dm cache: Fix UAF in destroy()
+    - dm cache: set needs_check flag after aborting metadata
+    - tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
+    - x86/microcode/intel: Do not retry microcode reloading on the APs
+    - tracing/hist: Fix wrong return value in parse_action_params()
+    - tracing: Fix infinite loop in tracing_read_pipe on overflowed
+      print_trace_line
+    - ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
+    - media: dvb-core: Fix double free in dvb_register_device()
+    - cifs: fix confusing debug message
+    - cifs: fix missing display of three mount options
+    - md/bitmap: Fix bitmap chunk size overflow issues
+    - efi: Add iMac Pro 2017 to uefi skip cert quirk
+    - ipmi: fix long wait in unload when IPMI disconnect
+    - mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
+    - ima: Fix a potential NULL pointer access in ima_restore_measurement_list
+    - ipmi: fix use after free in _ipmi_destroy_user()
+    - PCI: Fix pci_device_is_present() for VFs by checking PF
+    - PCI/sysfs: Fix double free in error path
+    - crypto: n2 - add missing hash statesize
+    - iommu/amd: Fix ivrs_acpihid cmdline parsing code
+    - parisc: led: Fix potential null-ptr-deref in start_task()
+    - device_cgroup: Roll back to original exceptions after copy failure
+    - drm/connector: send hotplug uevent on connector cleanup
+    - drm/vmwgfx: Validate the box size for the snooped cursor
+    - ext4: add inode table check in __ext4_get_inode_loc to aovid possible
+      infinite loop
+    - ext4: fix undefined behavior in bit shift for ext4_check_flag_values
+    - ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
+    - ext4: add helper to check quota inums
+    - ext4: fix reserved cluster accounting in __es_remove_extent()
+    - ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
+    - ext4: init quota for 'old.inode' in 'ext4_rename'
+    - ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
+    - ext4: fix corruption when online resizing a 1K bigalloc fs
+    - ext4: fix error code return to user-space in ext4_get_branch()
+    - ext4: avoid BUG_ON when creating xattrs
+    - ext4: fix inode leak in ext4_xattr_inode_create() on an error path
+    - ext4: initialize quota before expanding inode in setproject ioctl
+    - ext4: avoid unaccounted block allocation when expanding inode
+    - ext4: allocate extended attribute value in vmalloc area
+    - btrfs: replace strncpy() with strscpy()
+    - PM/devfreq: governor: Add a private governor_data for governor
+    - media: s5p-mfc: Fix to handle reference queue during finishing
+    - media: s5p-mfc: Clear workbit to handle error condition
+    - media: s5p-mfc: Fix in register read and write for H264
+    - dm thin: resume even if in FAIL mode
+    - perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
+    - perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged
+      data
+    - KVM: x86: optimize more exit handlers in vmx.c
+    - KVM: retpolines: x86: eliminate retpoline from vmx.c exit handlers
+    - KVM: VMX: Rename INTERRUPT_PENDING to INTERRUPT_WINDOW
+    - KVM: VMX: Rename NMI_PENDING to NMI_WINDOW
+    - KVM: VMX: Fix the spelling of CPU_BASED_USE_TSC_OFFSETTING
+    - KVM: nVMX: Properly expose ENABLE_USR_WAIT_PAUSE control to L1
+    - ravb: Fix "failed to switch device to config mode" message during unbind
+    - ext4: goto right label 'failed_mount3a'
+    - ext4: correct inconsistent error msg in nojournal mode
+    - mm/highmem: Lift memcpy_[to|from]_page to core
+    - ext4: use memcpy_to_page() in pagecache_write()
+    - fs: ext4: initialize fsdata in pagecache_write()
+    - ext4: use kmemdup() to replace kmalloc + memcpy
+    - mbcache: don't reclaim used entries
+    - mbcache: add functions to delete entry if unused
+    - ext4: remove EA inode entry from mbcache on inode eviction
+    - ext4: unindent codeblock in ext4_xattr_block_set()
+    - ext4: fix race when reusing xattr blocks
+    - mbcache: automatically delete entries from cache on freeing
+    - ext4: fix deadlock due to mbcache entry corruption
+    - SUNRPC: ensure the matching upcall is in-flight upon downcall
+    - bpf: pull before calling skb_postpull_rcsum()
+    - nfsd: shut down the NFSv4 state objects before the filecache
+    - net: hns3: add interrupts re-initialization while doing VF FLR
+    - net: sched: fix memory leak in tcindex_set_parms
+    - qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
+    - nfc: Fix potential resource leaks
+    - vhost: fix range used in translate_desc()
+    - net: amd-xgbe: add missed tasklet_kill
+    - net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
+    - RDMA/uverbs: Silence shiftTooManyBitsSigned warning
+    - RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
+    - net: sched: atm: dont intepret cls results when asked to drop
+    - net: sched: cbq: dont intepret cls results when asked to drop
+    - perf tools: Fix resources leak in perf_data__open_dir()
+    - drivers/net/bonding/bond_3ad: return when there's no aggregator
+    - usb: rndis_host: Secure rndis_query check against int overflow
+    - drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
+    - caif: fix memory leak in cfctrl_linkup_request()
+    - udf: Fix extension of the last extent in the file
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
+    - x86/bugs: Flush IBP in ib_prctl_set()
+    - nfsd: fix handling of readdir in v4root vs. mount upcall timeout
+    - riscv: uaccess: fix type of 0 variable on error in get_user()
+    - ext4: don't allow journal inode to have encrypt flag
+    - hfs/hfsplus: use WARN_ON for sanity check
+    - hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
+    - mbcache: Avoid nesting of cache->c_list_lock under bit locks
+    - parisc: Align parisc MADV_XXX constants with all other architectures
+    - selftests: Fix kselftest O=objdir build from cluttering top level objdir
+    - selftests: set the BUILD variable to absolute path
+    - driver core: Fix bus_type.match() error handling in __driver_attach()
+    - net: sched: disallow noqueue for qdisc classes
+    - KVM: arm64: Fix S1PTW handling on RO memslots
+    - efi: tpm: Avoid READ_ONCE() for accessing the event log
+    - docs: Fix the docs build with Sphinx 6.0
+    - perf auxtrace: Fix address filter duplicate symbol selection
+    - s390/kexec: fix ipl report address for kdump
+    - s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple()
+    - net/ulp: prevent ULP without clone op from entering the LISTEN status
+    - ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
+    - cifs: Fix uninitialized memory read for smb311 posix symlink create
+    - drm/msm/adreno: Make adreno quirks not overwrite each other
+    - platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during
+      probe
+    - ixgbe: fix pci device refcount leak
+    - ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
+    - wifi: wilc1000: sdio: fix module autoloading
+    - usb: ulpi: defer ulpi_register on ulpi_read_id timeout
+    - jbd2: use the correct print format
+    - quota: Factor out setup of quota inode
+    - ext4: fix bug_on in __es_tree_search caused by bad quota inode
+    - ext4: lost matching-pair of trace in ext4_truncate
+    - ext4: fix use-after-free in ext4_orphan_cleanup
+    - ext4: fix uninititialized value in 'ext4_evict_inode'
+    - netfilter: ipset: Fix overflow before widen in the bitmap_ip_create()
+      function.
+    - powerpc/imc-pmu: Fix use of mutex in IRQs disabled section
+    - x86/boot: Avoid using Intel mnemonics in AT&T syntax asm
+    - EDAC/device: Fix period calculation in edac_device_reset_delay_period()
+    - regulator: da9211: Use irq handler when ready
+    - tipc: improve throughput between nodes in netns
+    - tipc: eliminate checking netns if node established
+    - tipc: fix unexpected link reset due to discovery messages
+    - hvc/xen: lock console list traversal
+    - nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
+    - net/sched: act_mpls: Fix warning during failed attribute validation
+    - net/mlx5: Rename ptp clock info
+    - net/mlx5: Fix ptp max frequency adjustment range
+    - iommu/mediatek-v1: Add error handle for mtk_iommu_probe
+    - iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
+    - x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent
+      unnecessary IPI
+    - x86/resctrl: Fix task CLOSID/RMID update race
+    - drm/virtio: Fix GEM handle creation UAF
+    - arm64: atomics: format whitespace consistently
+    - arm64: atomics: remove LL/SC trampolines
+    - arm64: cmpxchg_double*: hazard against entire exchange variable
+    - efi: fix NULL-deref in init error path
+    - mm: Always release pages to the buddy allocator in memblock_free_late().
+    - Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout"
+    - tipc: fix use-after-free in tipc_disc_rcv()
+    - tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
+    - tipc: Add a missing case of TIPC_DIRECT_MSG type
+    - ocfs2: fix freeing uninitialized resource on ocfs2_dlm_shutdown
+    - tipc: call tipc_lxc_xmit without holding node_read_lock
+    - Linux 5.4.229
+
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2023-0266 was assigned for this issue.
+    - ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
+
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2022-41218 is assigned to those bugs above.
+    - media: dvb-core: Fix UAF due to refcount races at releasing
+
+  * Focal update: v5.4.228 upstream stable release (LP: #2003904)
+    - x86/smpboot: Move rcu_cpu_starting() earlier
+    - mm/hugetlb: fix races when looking up a CONT-PTE/PMD size hugetlb page
+    - block: unhash blkdev part inode when the part is deleted
+    - ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx()
+    - pinctrl: meditatek: Startup with the IRQs disabled
+    - can: sja1000: fix size of OCR_MODE_MASK define
+    - can: mcba_usb: Fix termination command argument
+    - ASoC: ops: Correct bounds check for second channel on SX controls
+    - Linux 5.4.228
+
+  * Focal update: v5.4.227 upstream stable release (LP: #2003901)
+    - arm64: dts: rockchip: keep I2S1 disabled for GPIO function on ROCK Pi 4
+      series
+    - arm: dts: rockchip: fix node name for hym8563 rtc
+    - ARM: dts: rockchip: fix ir-receiver node names
+    - ARM: dts: rockchip: rk3188: fix lcdc1-rgb24 node name
+    - ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels
+    - ARM: 9266/1: mm: fix no-MMU ZERO_PAGE() implementation
+    - ARM: dts: rockchip: disable arm_global_timer on rk3066 and rk3188
+    - 9p/fd: Use P9_HDRSZ for header size
+    - regulator: slg51000: Wait after asserting CS pin
+    - ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
+    - btrfs: send: avoid unaligned encoded writes when attempting to clone range
+    - ASoC: soc-pcm: Add NULL check in BE reparenting
+    - regulator: twl6030: fix get status of twl6032 regulators
+    - fbcon: Use kzalloc() in fbcon_prepare_logo()
+    - 9p/xen: check logical size for buffer size
+    - net: usb: qmi_wwan: add u-blox 0x1342 composition
+    - mm/khugepaged: take the right locks for page table retraction
+    - mm/khugepaged: fix GUP-fast interaction by sending IPI
+    - mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths
+    - xen/netback: do some code cleanup
+    - xen/netback: don't call kfree_skb() with interrupts disabled
+    - Revert "net: dsa: b53: Fix valid setting for MDB entries"
+    - media: v4l2-dv-timings.c: fix too strict blanking sanity checks
+    - memcg: fix possible use-after-free in memcg_write_event_control()
+    - mm/gup: fix gup_pud_range() for dax
+    - KVM: s390: vsie: Fix the initialization of the epoch extension (epdx) field
+    - drm/shmem-helper: Remove errant put in error path
+    - HID: usbhid: Add ALWAYS_POLL quirk for some mice
+    - HID: hid-lg4ff: Add check for empty lbuf
+    - HID: core: fix shift-out-of-bounds in hid_report_raw_event
+    - can: af_can: fix NULL pointer dereference in can_rcv_filter
+    - ieee802154: cc2520: Fix error return code in cc2520_hw_init()
+    - ca8210: Fix crash by zero initializing data
+    - drm/bridge: ti-sn65dsi86: Fix output polarity setting bug
+    - gpio: amd8111: Fix PCI device reference count leak
+    - e1000e: Fix TX dispatch condition
+    - igb: Allocate MSI-X vector when testing
+    - af_unix: Get user_ns from in_skb in unix_diag_get_exact().
+    - Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn()
+    - Bluetooth: Fix not cleanup led when bt_init fails
+    - net: dsa: ksz: Check return value
+    - selftests: rtnetlink: correct xfrm policy rule in kci_test_ipsec_offload
+    - mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add()
+    - net: encx24j600: Add parentheses to fix precedence
+    - net: encx24j600: Fix invalid logic in reading of MISTAT register
+    - xen-netfront: Fix NULL sring after live migration
+    - net: mvneta: Prevent out of bounds read in mvneta_config_rss()
+    - i40e: Fix not setting default xps_cpus after reset
+    - i40e: Fix for VF MAC address 0
+    - i40e: Disallow ip4 and ip6 l4_4_bytes
+    - NFC: nci: Bounds check struct nfc_target arrays
+    - nvme initialize core quirks before calling nvme_init_subsystem
+    - net: stmmac: fix "snps,axi-config" node property parsing
+    - net: thunderx: Fix missing destroy_workqueue of nicvf_rx_mode_wq
+    - net: hisilicon: Fix potential use-after-free in hisi_femac_rx()
+    - net: hisilicon: Fix potential use-after-free in hix5hd2_rx()
+    - tipc: Fix potential OOB in tipc_link_proto_rcv()
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - ipv4: Fix incorrect route flushing when table ID 0 is used
+    - ethernet: aeroflex: fix potential skb leak in greth_init_rings()
+    - net: plip: don't call kfree_skb/dev_kfree_skb() under spin_lock_irq()
+    - ipv6: avoid use-after-free in ip6_fragment()
+    - net: mvneta: Fix an out of bounds check
+    - can: esd_usb: Allow REC and TEC to return to zero
+    - Linux 5.4.227
+
+  * 5.15.0-58.64 breaks xen bridge networking (pvh domU) (LP: #2002889) // Focal
+    update: v5.4.227 upstream stable release (LP: #2003901)
+    - xen/netback: fix build warning
+
+  * Focal update: v5.4.226 upstream stable release (LP: #2003896)
+    - wifi: mac80211: fix memory free error when registering wiphy fail
+    - wifi: mac80211_hwsim: fix debugfs attribute ps with rc table support
+    - audit: fix undefined behavior in bit shift for AUDIT_BIT
+    - wifi: mac80211: Fix ack frame idr leak when mesh has no route
+    - spi: stm32: fix stm32_spi_prepare_mbr() that halves spi clk for every run
+    - drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
+    - block, bfq: fix null pointer dereference in bfq_bio_bfqg()
+    - arm64/syscall: Include asm/ptrace.h in syscall_wrapper header.
+    - RISC-V: vdso: Do not add missing symbols to version section in linker script
+    - MIPS: pic32: treat port as signed integer
+    - af_key: Fix send_acquire race with pfkey_register
+    - ARM: dts: am335x-pcm-953: Define fixed regulators in root node
+    - ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove
+    - regulator: core: fix kobject release warning and memory leak in
+      regulator_register()
+    - regulator: core: fix UAF in destroy_regulator()
+    - bus: sunxi-rsb: Support atomic transfers
+    - tee: optee: fix possible memory leak in optee_register_device()
+    - ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl
+    - net: liquidio: simplify if expression
+    - nfc/nci: fix race with opening and closing
+    - net: pch_gbe: fix potential memleak in pch_gbe_tx_queue()
+    - 9p/fd: fix issue of list_del corruption in p9_fd_cancel()
+    - ARM: mxs: fix memory leak in mxs_machine_init()
+    - net/mlx4: Check retval of mlx4_bitmap_init
+    - net/qla3xxx: fix potential memleak in ql3xxx_send()
+    - net: pch_gbe: fix pci device refcount leak while module exiting
+    - nfp: add port from netdev validation for EEPROM access
+    - Drivers: hv: vmbus: fix double free in the error path of
+      vmbus_add_channel_work()
+    - Drivers: hv: vmbus: fix possible memory leak in vmbus_device_register()
+    - net/mlx5: Fix FW tracer timestamp calculation
+    - tipc: set con sock in tipc_conn_alloc
+    - tipc: add an extra conn_get in tipc_conn_alloc
+    - tipc: check skb_linearize() return value in tipc_disc_rcv()
+    - xfrm: Fix ignored return value in xfrm6_init()
+    - NFC: nci: fix memory leak in nci_rx_data_packet()
+    - regulator: twl6030: re-add TWL6032_SUBCLASS
+    - bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending()
+    - dccp/tcp: Reset saddr on failure after inet6?_hash_connect().
+    - s390/dasd: fix no record found for raw_track_access
+    - nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st-nci: fix memory leaks in EVT_TRANSACTION
+    - net: thunderx: Fix the ACPI memory leak
+    - s390/crashdump: fix TOD programmable field size
+    - lib/vdso: use "grep -E" instead of "egrep"
+    - usb: dwc3: exynos: Fix remove() function
+    - arm64: dts: rockchip: lower rk3399-puma-haikou SD controller clock frequency
+    - iio: light: apds9960: fix wrong register for gesture gain
+    - iio: core: Fix entry not deleted when iio_register_sw_trigger_type() fails
+    - init/Kconfig: fix CC_HAS_ASM_GOTO_TIED_OUTPUT test with dash
+    - nios2: add FORCE for vmlinuz.gz
+    - iio: ms5611: Simplify IO callback parameters
+    - iio: pressure: ms5611: fixed value compensation bug
+    - ceph: do not update snapshot context when there is no new snapshot
+    - ceph: avoid putting the realm twice when decoding snaps fails
+    - firmware: google: Release devices before unregistering the bus
+    - firmware: coreboot: Register bus in module init
+    - nilfs2: fix nilfs_sufile_mark_dirty() not set segment usage as dirty
+    - gcov: clang: fix the buffer overflow issue
+    - Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode
+    - ASoC: Intel: bytcht_es8316: Add quirk for the Nanote UMPC-01
+    - serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
+    - xen/platform-pci: add missing free_irq() in error path
+    - platform/x86: asus-wmi: add missing pci_dev_put() in asus_wmi_set_xusb2pr()
+    - platform/x86: acer-wmi: Enable SW_TABLET_MODE on Switch V 10 (SW5-017)
+    - platform/x86: hp-wmi: Ignore Smart Experience App event
+    - [Config] updateconfigs for INET_TABLE_PERTURB_ORDER
+    - tcp: configurable source port perturb table size
+    - net: usb: qmi_wwan: add Telit 0x103a composition
+    - dm integrity: flush the journal on suspend
+    - binder: avoid potential data leakage when copying txn
+    - binder: read pre-translated fds from sender buffer
+    - binder: defer copies of pre-patched txn data
+    - binder: fix pointer cast warning
+    - binder: Address corner cases in deferred copy and fixup
+    - binder: Gracefully handle BINDER_TYPE_FDA objects with num_fds=0
+    - btrfs: free btrfs_path before copying root refs to userspace
+    - btrfs: free btrfs_path before copying fspath to userspace
+    - btrfs: free btrfs_path before copying subvol info to userspace
+    - btrfs: sysfs: normalize the error handling branch in btrfs_init_sysfs()
+    - drm/amd/dc/dce120: Fix audio register mapping, stop triggering KASAN
+    - drm/amdgpu: always register an MMU notifier for userptr
+    - fuse: lock inode unconditionally in fuse_fallocate()
+    - btrfs: free btrfs_path before copying inodes to userspace
+    - spi: spi-imx: Fix spi_bus_clk if requested clock is higher than input clock
+    - btrfs: move QUOTA_ENABLED check to rescan_should_stop from
+      btrfs_qgroup_rescan_worker
+    - drm/amdgpu: update drm_display_info correctly when the edid is read
+    - drm/amdgpu: Partially revert "drm/amdgpu: update drm_display_info correctly
+      when the edid is read"
+    - btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit()
+    - iio: health: afe4403: Fix oob read in afe4403_read_raw
+    - iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
+    - iio: light: rpr0521: add missing Kconfig dependencies
+    - scripts/faddr2line: Fix regression in name resolution on ppc64le
+    - hwmon: (i5500_temp) fix missing pci_disable_device()
+    - hwmon: (ibmpex) Fix possible UAF when ibmpex_register_bmc() fails
+    - of: property: decrement node refcount in of_fwnode_get_reference_args()
+    - net/mlx5: Fix uninitialized variable bug in outlen_write()
+    - net/mlx5e: Fix use-after-free when reverting termination table
+    - can: sja1000_isa: sja1000_isa_probe(): add missing free_sja1000dev()
+    - can: cc770: cc770_isa_probe(): add missing free_cc770dev()
+    - qlcnic: fix sleep-in-atomic-context bugs caused by msleep
+    - wifi: cfg80211: fix buffer overflow in elem comparison
+    - net: phy: fix null-ptr-deref while probe() failed
+    - net: net_netdev: Fix error handling in ntb_netdev_init_module()
+    - net/9p: Fix a potential socket leak in p9_socket_open
+    - net: ethernet: nixge: fix NULL dereference
+    - dsa: lan9303: Correct stat name
+    - net: hsr: Fix potential use-after-free
+    - afs: Fix fileserver probe RTT handling
+    - net: tun: Fix use-after-free in tun_detach()
+    - packet: do not set TP_STATUS_CSUM_VALID on CHECKSUM_COMPLETE
+    - sctp: fix memory leak in sctp_stream_outq_migrate()
+    - net: ethernet: renesas: ravb: Fix promiscuous mode after system resumed
+    - hwmon: (coretemp) Check for null before removing sysfs attrs
+    - hwmon: (coretemp) fix pci device refcount leak in nv1a_ram_new()
+    - net/mlx5: DR, Fix uninitialized var warning
+    - error-injection: Add prompt for function error injection
+    - tools/vm/slabinfo-gnuplot: use "grep -E" instead of "egrep"
+    - nilfs2: fix NULL pointer dereference in nilfs_palloc_commit_free_entry()
+    - x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
+    - pinctrl: intel: Save and restore pins in "direct IRQ" mode
+    - mmc: mmc_test: Fix removal of debugfs file
+    - mmc: core: Fix ambiguous TRIM and DISCARD arg
+    - mmc: sdhci-esdhc-imx: correct CQHCI exit halt state check
+    - mmc: sdhci-sprd: Fix no reset data and command after voltage switch
+    - tracing: Free buffers when a used dynamic event is removed
+    - arm64: Fix panic() when Spectre-v2 causes Spectre-BHB to re-allocate KVM
+      vectors
+    - arm64: errata: Fix KVM Spectre-v2 mitigation selection for Cortex-A57/A72
+    - mm: Fix '.data.once' orphan section warning
+    - ASoC: ops: Fix bounds check for _sx controls
+    - pinctrl: single: Fix potential division by zero
+    - iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init()
+    - parisc: Increase size of gcc stack frame check
+    - xtensa: increase size of gcc stack frame check
+    - parisc: Increase FRAME_WARN to 2048 bytes on parisc
+    - Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is
+      enabled
+    - selftests: net: add delete nexthop route warning test
+    - selftests: net: fix nexthop warning cleanup double ip typo
+    - ipv4: Handle attempt to delete multipath route when fib_info contains an nh
+      reference
+    - ipv4: Fix route deletion when nexthop info is not specified
+    - tracing/ring-buffer: Have polling block on watermark
+    - nvme: restrict management ioctls to admin
+    - nvme: ensure subsystem reset is single threaded
+    - x86/tsx: Add a feature bit for TSX control MSR support
+    - x86/pm: Add enumeration check before spec MSRs save/restore setup
+    - x86/ioremap: Fix page aligned size calculation in __ioremap_caller()
+    - Revert "clocksource/drivers/riscv: Events are stopped during CPU suspend"
+    - char: tpm: Protect tpm_pm_suspend with locks
+    - mmc: sdhci: use FIELD_GET for preset value bit masks
+    - mmc: sdhci: Fix voltage switch delay
+    - proc: avoid integer type confusion in get_proc_long
+    - proc: proc_skip_spaces() shouldn't think it is working on C strings
+    - v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails
+    - ipc/sem: Fix dangling sem_array access in semtimedop race
+    - Linux 5.4.226
+
+  * CVE-2022-4139
+    - drm/i915: fix TLB invalidation for Gen12 video and compute engines
+
+  * Focal update: v5.4.225 upstream stable release (LP: #2002347)
+    - xfs: preserve rmapbt swapext block reservation from freed blocks
+    - xfs: rename xfs_bmap_is_real_extent to is_written_extent
+    - xfs: redesign the reflink remap loop to fix blkres depletion crash
+    - xfs: use MMAPLOCK around filemap_map_pages()
+    - xfs: preserve inode versioning across remounts
+    - xfs: drain the buf delwri queue before xfsaild idles
+    - phy: stm32: fix an error code in probe
+    - wifi: cfg80211: silence a sparse RCU warning
+    - wifi: cfg80211: fix memory leak in query_regdb_file()
+    - bpf, sockmap: Fix the sk->sk_forward_alloc warning of sk_stream_kill_queues
+    - HID: hyperv: fix possible memory leak in mousevsc_probe()
+    - net: gso: fix panic on frag_list with mixed head alloc types
+    - net: tun: Fix memory leaks of napi_get_frags
+    - bnxt_en: Fix possible crash in bnxt_hwrm_set_coal()
+    - bnxt_en: fix potentially incorrect return value for ndo_rx_flow_steer
+    - net: fman: Unregister ethernet device on removal
+    - capabilities: fix undefined behavior in bit shift for CAP_TO_MASK
+    - net: lapbether: fix issue of dev reference count leakage in
+      lapbeth_device_event()
+    - hamradio: fix issue of dev reference count leakage in bpq_device_event()
+    - drm/vc4: Fix missing platform_unregister_drivers() call in
+      vc4_drm_register()
+    - ipv6: addrlabel: fix infoleak when sending struct ifaddrlblmsg to network
+    - can: af_can: fix NULL pointer dereference in can_rx_register()
+    - tipc: fix the msg->req tlv len check in
+      tipc_nl_compat_name_table_dump_header
+    - dmaengine: pxa_dma: use platform_get_irq_optional
+    - dmaengine: mv_xor_v2: Fix a resource leak in mv_xor_v2_remove()
+    - drivers: net: xgene: disable napi when register irq failed in
+      xgene_enet_open()
+    - perf stat: Fix printing os->prefix in CSV metrics output
+    - net: nixge: disable napi when enable interrupts failed in nixge_open()
+    - net/mlx5: Allow async trigger completion execution on single CPU systems
+    - net: cpsw: disable napi in cpsw_ndo_open()
+    - net: cxgb3_main: disable napi when bind qsets failed in cxgb_up()
+    - cxgb4vf: shut down the adapter when t4vf_update_port_info() failed in
+      cxgb4vf_open()
+    - ethernet: s2io: disable napi when start nic failed in s2io_card_up()
+    - net: mv643xx_eth: disable napi when init rxq or txq failed in
+      mv643xx_eth_open()
+    - ethernet: tundra: free irq when alloc ring failed in tsi108_open()
+    - net: macvlan: fix memory leaks of macvlan_common_newlink
+    - riscv: process: fix kernel info leakage
+    - arm64: efi: Fix handling of misaligned runtime regions and drop warning
+    - MIPS: jump_label: Fix compat branch range check
+    - mmc: cqhci: Provide helper for resetting both SDHCI and CQHCI
+    - mmc: sdhci-of-arasan: Fix SDHCI_RESET_ALL for CQHCI
+    - mmc: sdhci-tegra: Fix SDHCI_RESET_ALL for CQHCI
+    - ALSA: hda/ca0132: add quirk for EVGA Z390 DARK
+    - ALSA: hda: fix potential memleak in 'add_widget_node'
+    - ALSA: usb-audio: Add quirk entry for M-Audio Micro
+    - ALSA: usb-audio: Add DSD support for Accuphase DAC-60
+    - vmlinux.lds.h: Fix placement of '.data..decrypted' section
+    - nilfs2: fix deadlock in nilfs_count_free_blocks()
+    - nilfs2: fix use-after-free bug of ns_writer on remount
+    - drm/i915/dmabuf: fix sg_table handling in map_dma_buf
+    - btrfs: selftests: fix wrong error check in btrfs_free_dummy_root()
+    - udf: Fix a slab-out-of-bounds write bug in udf_find_entry()
+    - can: j1939: j1939_send_one(): fix missing CAN header initialization
+    - cert host tools: Stop complaining about deprecated OpenSSL functions
+    - dmaengine: at_hdmac: Fix at_lli struct definition
+    - dmaengine: at_hdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
+    - dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
+    - dmaengine: at_hdmac: Fix impossible condition
+    - dmaengine: at_hdmac: Check return code of dma_async_device_register
+    - net: tun: call napi_schedule_prep() to ensure we own a napi
+    - x86/cpu: Restore AMD's DE_CFG MSR after resume
+    - ASoC: wm5102: Revert "ASoC: wm5102: Fix PM disable depth imbalance in
+      wm5102_probe"
+    - ASoC: wm5110: Revert "ASoC: wm5110: Fix PM disable depth imbalance in
+      wm5110_probe"
+    - ASoC: wm8997: Revert "ASoC: wm8997: Fix PM disable depth imbalance in
+      wm8997_probe"
+    - ASoC: wm8962: Add an event handler for TEMP_HP and TEMP_SPK
+    - spi: intel: Fix the offset to get the 64K erase opcode
+    - ASoC: codecs: jz4725b: add missed Line In power control bit
+    - ASoC: codecs: jz4725b: fix reported volume for Master ctl
+    - ASoC: codecs: jz4725b: use right control for Capture Volume
+    - ASoC: codecs: jz4725b: fix capture selector naming
+    - selftests/futex: fix build for clang
+    - selftests/intel_pstate: fix build for ARCH=x86_64
+    - NFSv4: Retry LOCK on OLD_STATEID during delegation return
+    - i2c: i801: add lis3lv02d's I2C address for Vostro 5568
+    - drm/imx: imx-tve: Fix return type of imx_tve_connector_mode_valid
+    - btrfs: remove pointless and double ulist frees in error paths of qgroup
+      tests
+    - ASoC: codecs: jz4725b: Fix spelling mistake "Sourc" -> "Source", "Routee" ->
+      "Route"
+    - spi: stm32: Print summary 'callbacks suppressed' message
+    - ASoC: core: Fix use-after-free in snd_soc_exit()
+    - serial: 8250_omap: remove wait loop from Errata i202 workaround
+    - serial: 8250: omap: Fix unpaired pm_runtime_put_sync() in omap8250_remove()
+    - serial: 8250: omap: Flush PM QOS work on remove
+    - serial: imx: Add missing .thaw_noirq hook
+    - tty: n_gsm: fix sleep-in-atomic-context bug in gsm_control_send
+    - ASoC: soc-utils: Remove __exit for snd_soc_util_exit()
+    - block: sed-opal: kmalloc the cmd/resp buffers
+    - siox: fix possible memory leak in siox_device_add()
+    - parport_pc: Avoid FIFO port location truncation
+    - pinctrl: devicetree: fix null pointer dereferencing in pinctrl_dt_to_map
+    - arm64: dts: imx8mm: Fix NAND controller size-cells
+    - arm64: dts: imx8mn: Fix NAND controller size-cells
+    - ata: libata-transport: fix double ata_host_put() in ata_tport_add()
+    - net: bgmac: Drop free_netdev() from bgmac_enet_remove()
+    - mISDN: fix possible memory leak in mISDN_dsp_element_register()
+    - net: liquidio: release resources when liquidio driver open failed
+    - mISDN: fix misuse of put_device() in mISDN_register_device()
+    - net: macvlan: Use built-in RCU list checking
+    - net: caif: fix double disconnect client in chnl_net_open()
+    - bnxt_en: Remove debugfs when pci_register_driver failed
+    - xen/pcpu: fix possible memory leak in register_pcpu()
+    - drbd: use after free in drbd_create_device()
+    - platform/x86/intel: pmc: Don't unconditionally attach Intel PMC when
+      virtualized
+    - net/x25: Fix skb leak in x25_lapb_receive_frame()
+    - cifs: Fix wrong return value checking when GETFLAGS
+    - net: thunderbolt: Fix error handling in tbnet_init()
+    - cifs: add check for returning value of SMB2_set_info_init
+    - ftrace: Fix the possible incorrect kernel message
+    - ftrace: Optimize the allocation for mcount entries
+    - ftrace: Fix null pointer dereference in ftrace_add_mod()
+    - ring_buffer: Do not deactivate non-existant pages
+    - ALSA: usb-audio: Drop snd_BUG_ON() from snd_usbmidi_output_open()
+    - Revert "usb: dwc3: disable USB core PHY management"
+    - slimbus: stream: correct presence rate frequencies
+    - speakup: fix a segfault caused by switching consoles
+    - USB: serial: option: add Sierra Wireless EM9191
+    - USB: serial: option: remove old LARA-R6 PID
+    - USB: serial: option: add u-blox LARA-R6 00B modem
+    - USB: serial: option: add u-blox LARA-L6 modem
+    - USB: serial: option: add Fibocom FM160 0x0111 composition
+    - usb: add NO_LPM quirk for Realforce 87U Keyboard
+    - usb: chipidea: fix deadlock in ci_otg_del_timer
+    - iio: adc: at91_adc: fix possible memory leak in at91_adc_allocate_trigger()
+    - iio: trigger: sysfs: fix possible memory leak in iio_sysfs_trig_init()
+    - iio: pressure: ms5611: changed hardcoded SPI speed to value limited
+    - dm ioctl: fix misbehavior if list_versions races with module loading
+    - serial: 8250: Fall back to non-DMA Rx if IIR_RDI occurs
+    - serial: 8250_lpss: Configure DMA also w/o DMA filter
+    - Input: iforce - invert valid length check when fetching device IDs
+    - scsi: zfcp: Fix double free of FSF request when qdio send fails
+    - mmc: core: properly select voltage range without power cycle
+    - mmc: sdhci-pci-o2micro: fix card detect fail issue caused by CD# debounce
+      timeout
+    - mmc: sdhci-pci: Fix possible memory leak caused by missing pci_dev_put()
+    - docs: update mediator contact information in CoC doc
+    - misc/vmw_vmci: fix an infoleak in vmci_host_do_receive_datagram()
+    - serial: 8250: Flush DMA Rx on RLSI
+    - ring-buffer: Include dropped pages in counting dirty patches
+    - scsi: target: tcm_loop: Fix possible name leak in tcm_loop_setup_hba_bus()
+    - kprobes: Skip clearing aggrprobe's post_handler in kprobe-on-ftrace case
+    - Input: i8042 - fix leaking of platform device on module removal
+    - macvlan: enforce a consistent minimal mtu
+    - tcp: cdg: allow tcp_cdg_release() to be called multiple times
+    - kcm: avoid potential race in kcm_tx_work
+    - bpf, test_run: Fix alignment problem in bpf_prog_test_run_skb()
+    - kcm: close race conditions on sk_receive_queue
+    - 9p: trans_fd/p9_conn_cancel: drop client lock earlier
+    - gfs2: Check sb_bsize_shift after reading superblock
+    - gfs2: Switch from strlcpy to strscpy
+    - 9p/trans_fd: always use O_NONBLOCK read/write
+    - mm: fs: initialize fsdata passed to write_begin/write_end interface
+    - ntfs: fix use-after-free in ntfs_attr_find()
+    - ntfs: fix out-of-bounds read in ntfs_attr_find()
+    - ntfs: check overflow when iterating ATTR_RECORDs
+    - Linux 5.4.225
+
+  * CVE-2022-47520
+    - wifi: wilc1000: validate pairwise and authentication suite offsets
+
+  * CVE-2022-3545
+    - nfp: fix use-after-free in area_cache_get()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 01 Feb 2023 15:33:59 +0100
+
+linux (5.4.0-139.156) focal; urgency=medium
+
+  * focal/linux: 5.4.0-139.156 -proposed tracker (LP: #2003486)
+
+  * Revoke & rotate to new signing key (LP: #2002812)
+    - [Packaging] Revoke and rotate to new signing key
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 20 Jan 2023 15:39:15 +0100
+
+linux (5.4.0-138.155) focal; urgency=medium
+
+  * focal/linux: 5.4.0-138.155 -proposed tracker (LP: #2001845)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Focal update: v5.4.224 upstream stable release (LP: #1999273)
+    - RDMA/cma: Use output interface for net_dev check
+    - IB/hfi1: Correctly move list in sc_disable()
+    - NFSv4.1: Handle RECLAIM_COMPLETE trunking errors
+    - NFSv4.1: We must always send RECLAIM_COMPLETE after a reboot
+    - nfs4: Fix kmemleak when allocate slot failed
+    - net: dsa: Fix possible memory leaks in dsa_loop_init()
+    - RDMA/core: Fix null-ptr-deref in ib_core_cleanup()
+    - RDMA/qedr: clean up work queue on failure in qedr_alloc_resources()
+    - nfc: s3fwrn5: Fix potential memory leak in s3fwrn5_nci_send()
+    - nfc: nfcmrvl: Fix potential memory leak in nfcmrvl_i2c_nci_send()
+    - net: fec: fix improper use of NETDEV_TX_BUSY
+    - ata: pata_legacy: fix pdc20230_set_piomode()
+    - net: sched: Fix use after free in red_enqueue()
+    - net: tun: fix bugs for oversize packet when napi frags enabled
+    - netfilter: nf_tables: release flow rule object from commit path
+    - ipvs: use explicitly signed chars
+    - ipvs: fix WARNING in __ip_vs_cleanup_batch()
+    - ipvs: fix WARNING in ip_vs_app_net_cleanup()
+    - rose: Fix NULL pointer dereference in rose_send_frame()
+    - mISDN: fix possible memory leak in mISDN_register_device()
+    - isdn: mISDN: netjet: fix wrong check of device registration
+    - btrfs: fix inode list leak during backref walking at resolve_indirect_refs()
+    - btrfs: fix inode list leak during backref walking at find_parent_nodes()
+    - btrfs: fix ulist leaks in error paths of qgroup self tests
+    - Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
+    - net: mdio: fix undefined behavior in bit shift for __mdiobus_register
+    - net, neigh: Fix null-ptr-deref in neigh_table_clear()
+    - ipv6: fix WARNING in ip6_route_net_exit_late()
+    - media: s5p_cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: cros-ec-cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: dvb-frontends/drxk: initialize err to 0
+    - media: meson: vdec: fix possible refcount leak in vdec_probe()
+    - scsi: core: Restrict legal sdev_state transitions via sysfs
+    - HID: saitek: add madcatz variant of MMO7 mouse device ID
+    - i2c: xiic: Add platform module alias
+    - xfs: don't fail verifier on empty attr3 leaf block
+    - xfs: use ordered buffers to initialize dquot buffers during quotacheck
+    - xfs: gut error handling in xfs_trans_unreserve_and_mod_sb()
+    - xfs: group quota should return EDQUOT when prj quota enabled
+    - xfs: don't fail unwritten extent conversion on writeback due to edquot
+    - xfs: Add the missed xfs_perag_put() for xfs_ifree_cluster()
+    - Bluetooth: L2CAP: Fix attempting to access uninitialized memory
+    - block, bfq: protect 'bfqd->queued' by 'bfqd->lock'
+    - binder: fix UAF of alloc->vma in race with munmap()
+    - btrfs: fix type of parameter generation in btrfs_get_dentry
+    - tcp/udp: Make early_demux back namespacified.
+    - kprobe: reverse kp->flags when arm_kprobe failed
+    - tools/nolibc/string: Fix memcmp() implementation
+    - tracing/histogram: Update document for KEYS_MAX size
+    - capabilities: fix potential memleak on error path from vfs_getxattr_alloc()
+    - fuse: add file_modified() to fallocate
+    - efi: random: reduce seed size to 32 bytes
+    - perf/x86/intel: Fix pebs event constraints for ICL
+    - perf/x86/intel: Add Cooper Lake stepping to isolation_ucodes[]
+    - ALSA: usb-audio: Add quirks for MacroSilicon MS2100/MS2106 devices
+    - parisc: Make 8250_gsc driver dependend on CONFIG_PARISC
+    - parisc: Export iosapic_serial_irq() symbol for serial port driver
+    - parisc: Avoid printing the hardware path twice
+    - ext4: fix warning in 'ext4_da_release_space'
+    - ext4: fix BUG_ON() when directory entry has invalid rec_len
+    - KVM: x86: Mask off reserved bits in CPUID.8000001AH
+    - KVM: x86: Mask off reserved bits in CPUID.80000008H
+    - KVM: x86: emulator: em_sysexit should update ctxt->mode
+    - KVM: x86: emulator: introduce emulator_recalc_and_set_mode
+    - KVM: x86: emulator: update the emulation mode after CR0 write
+    - mtd: rawnand: gpmi: Set WAIT_FOR_READY timeout based on program/erase times
+    - drm/rockchip: dsi: Force synchronous probe
+    - drm/i915/sdvo: Filter out invalid outputs more sensibly
+    - drm/i915/sdvo: Setup DDC fully before output init
+    - wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
+    - ipc: remove memcg accounting for sops objects in do_semtimedop()
+    - Linux 5.4.224
+
+  * Focal update: v5.4.223 upstream stable release (LP: #1999179)
+    - can: j1939: transport: j1939_session_skb_drop_old():
+      spin_unlock_irqrestore() before kfree_skb()
+    - can: kvaser_usb: Fix possible completions during init_completion
+    - ALSA: Use del_timer_sync() before freeing timer
+    - ALSA: au88x0: use explicitly signed char
+    - USB: add RESET_RESUME quirk for NVIDIA Jetson devices in RCM
+    - usb: dwc3: gadget: Stop processing more requests on IMI
+    - usb: dwc3: gadget: Don't set IMI for no_interrupt
+    - usb: bdc: change state when port disconnected
+    - usb: xhci: add XHCI_SPURIOUS_SUCCESS to ASM1042 despite being a V0.96
+      controller
+    - mtd: rawnand: marvell: Use correct logic for nand-keep-config
+    - xhci: Remove device endpoints from bandwidth list when freeing the device
+    - tools: iio: iio_utils: fix digit calculation
+    - iio: light: tsl2583: Fix module unloading
+    - fbdev: smscufx: Fix several use-after-free bugs
+    - mac802154: Fix LQI recording
+    - drm/msm/dsi: fix memory corruption with too many bridges
+    - drm/msm/hdmi: fix memory corruption with too many bridges
+    - mmc: core: Fix kernel panic when remove non-standard SDIO card
+    - kernfs: fix use-after-free in __kernfs_remove
+    - perf auxtrace: Fix address filter symbol name match for modules
+    - s390/futex: add missing EX_TABLE entry to __futex_atomic_op()
+    - s390/pci: add missing EX_TABLE entries to
+      __pcistg_mio_inuser()/__pcilg_mio_inuser()
+    - xfs: finish dfops on every insert range shift iteration
+    - xfs: clear XFS_DQ_FREEING if we can't lock the dquot buffer to flush
+    - xfs: force the log after remapping a synchronous-writes file
+    - Xen/gntdev: don't ignore kernel unmapping error
+    - xen/gntdev: Prevent leaking grants
+    - mm,hugetlb: take hugetlb_lock before decrementing h->resv_huge_pages
+    - net: ieee802154: fix error return code in dgram_bind()
+    - media: v4l2: Fix v4l2_i2c_subdev_set_name function documentation
+    - drm/msm: Fix return type of mdp4_lvds_connector_mode_valid
+    - arc: iounmap() arg is volatile
+    - ALSA: ac97: fix possible memory leak in snd_ac97_dev_register()
+    - tipc: fix a null-ptr-deref in tipc_topsrv_accept
+    - net: netsec: fix error handling in netsec_register_mdio()
+    - x86/unwind/orc: Fix unreliable stack dump with gcov
+    - amd-xgbe: fix the SFP compliance codes check for DAC cables
+    - amd-xgbe: add the bit rate quirk for Molex cables
+    - kcm: annotate data-races around kcm->rx_psock
+    - kcm: annotate data-races around kcm->rx_wait
+    - net: fix UAF issue in nfqnl_nf_hook_drop() when ops_init() failed
+    - net: lantiq_etop: don't free skb when returning NETDEV_TX_BUSY
+    - tcp: fix indefinite deferral of RTO with SACK reneging
+    - can: mscan: mpc5xxx: mpc5xxx_can_probe(): add missing put_clock() in error
+      path
+    - PM: hibernate: Allow hybrid sleep to work with s2idle
+    - media: vivid: s_fbuf: add more sanity checks
+    - media: vivid: dev->bitmap_cap wasn't freed in all cases
+    - media: v4l2-dv-timings: add sanity checks for blanking values
+    - media: videodev2.h: V4L2_DV_BT_BLANKING_HEIGHT should check 'interlaced'
+    - i40e: Fix ethtool rx-flow-hash setting for X722
+    - i40e: Fix VF hang when reset is triggered on another VF
+    - i40e: Fix flow-type by setting GL_HASH_INSET registers
+    - net: ksz884x: fix missing pci_disable_device() on error in pcidev_init()
+    - PM: domains: Fix handling of unavailable/disabled idle states
+    - ALSA: aoa: i2sbus: fix possible memory leak in i2sbus_add_dev()
+    - ALSA: aoa: Fix I2S device accounting
+    - openvswitch: switch from WARN to pr_warn
+    - net: ehea: fix possible memory leak in ehea_register_port()
+    - nh: fix scope used to find saddr when adding non gw nh
+    - net/mlx5e: Do not increment ESN when updating IPsec ESN state
+    - net/mlx5: Fix possible use-after-free in async command interface
+    - net: enetc: survive memory pressure without crashing
+    - can: rcar_canfd: rcar_canfd_handle_global_receive(): fix IRQ storm on global
+      FIFO receive
+    - Linux 5.4.223
+
+  * Focal update: v5.4.222 upstream stable release (LP: #1997994)
+    - once: fix section mismatch on clang builds
+    - Linux 5.4.222
+
+  * Focal update: v5.4.221 upstream stable release (LP: #1997993)
+    - xfs: open code insert range extent split helper
+    - xfs: rework insert range into an atomic operation
+    - xfs: rework collapse range into an atomic operation
+    - xfs: add a function to deal with corrupt buffers post-verifiers
+    - xfs: xfs_buf_corruption_error should take __this_address
+    - xfs: fix buffer corruption reporting when xfs_dir3_free_header_check fails
+    - xfs: check owner of dir3 data blocks
+    - xfs: check owner of dir3 blocks
+    - xfs: Use scnprintf() for avoiding potential buffer overflow
+    - xfs: remove the xfs_disk_dquot_t and xfs_dquot_t
+    - xfs: remove the xfs_dq_logitem_t typedef
+    - xfs: remove the xfs_qoff_logitem_t typedef
+    - xfs: Replace function declaration by actual definition
+    - xfs: factor out quotaoff intent AIL removal and memory free
+    - xfs: fix unmount hang and memory leak on shutdown during quotaoff
+    - xfs: preserve default grace interval during quotacheck
+    - xfs: Lower CIL flush limit for large logs
+    - xfs: Throttle commits on delayed background CIL push
+    - xfs: factor common AIL item deletion code
+    - xfs: tail updates only need to occur when LSN changes
+    - xfs: don't write a corrupt unmount record to force summary counter recalc
+    - xfs: trylock underlying buffer on dquot flush
+    - xfs: factor out a new xfs_log_force_inode helper
+    - xfs: reflink should force the log out if mounted with wsync
+    - xfs: move inode flush to the sync workqueue
+    - xfs: fix use-after-free on CIL context on shutdown
+    - ocfs2: clear dinode links count in case of error
+    - ocfs2: fix BUG when iput after ocfs2_mknod fails
+    - x86/microcode/AMD: Apply the patch early on every logical thread
+    - hwmon/coretemp: Handle large core ID value
+    - ata: ahci-imx: Fix MODULE_ALIAS
+    - ata: ahci: Match EM_MAX_SLOTS with SATA_PMP_MAX_PORTS
+    - KVM: arm64: vgic: Fix exit condition in scan_its_table()
+    - media: venus: dec: Handle the case where find_format fails
+    - [Config] updateconfigs for ARM64_ERRATUM_1742098
+    - arm64: errata: Remove AES hwcap for COMPAT tasks
+    - r8152: add PID for the Lenovo OneLink+ Dock
+    - btrfs: fix processing of delayed data refs during backref walking
+    - btrfs: fix processing of delayed tree block refs during backref walking
+    - ACPI: extlog: Handle multiple records
+    - tipc: Fix recognition of trial period
+    - tipc: fix an information leak in tipc_topsrv_kern_subscr
+    - HID: magicmouse: Do not set BTN_MOUSE on double report
+    - net/atm: fix proc_mpc_write incorrect return value
+    - net: phy: dp83867: Extend RX strap quirk for SGMII mode
+    - net: sched: cake: fix null pointer access issue when cake_init() fails
+    - net: hns: fix possible memory leak in hnae_ae_register()
+    - iommu/vt-d: Clean up si_domain in the init_dmars() error path
+    - arm64: topology: move store_cpu_topology() to shared code
+    - riscv: topology: fix default topology reporting
+    - ACPI: video: Force backlight native for more TongFang devices
+    - Makefile.debug: re-enable debug info for .S files
+    - hv_netvsc: Fix race between VF offering and VF association message from host
+    - mm: /proc/pid/smaps_rollup: fix no vma's null-deref
+    - Linux 5.4.221
+
+  * Focal update: v5.4.220 upstream stable release (LP: #1996812)
+    - ALSA: oss: Fix potential deadlock at unregistration
+    - ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
+    - ALSA: usb-audio: Fix potential memory leaks
+    - ALSA: usb-audio: Fix NULL dererence at error path
+    - ALSA: hda/realtek: remove ALC289_FIXUP_DUAL_SPK for Dell 5530
+    - ALSA: hda/realtek: Correct pin configs for ASUS G533Z
+    - ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
+    - ALSA: hda/realtek: Add Intel Reference SSID to support headset keys
+    - mtd: rawnand: atmel: Unmap streaming DMA mappings
+    - cifs: destage dirty pages before re-reading them for cache=none
+    - cifs: Fix the error length of VALIDATE_NEGOTIATE_INFO message
+    - iio: dac: ad5593r: Fix i2c read protocol requirements
+    - iio: pressure: dps310: Refactor startup procedure
+    - iio: pressure: dps310: Reset chip after timeout
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - can: kvaser_usb: Fix use of uninitialized completion
+    - can: kvaser_usb_leaf: Fix overread with an invalid command
+    - can: kvaser_usb_leaf: Fix TX queue out of sync after restart
+    - can: kvaser_usb_leaf: Fix CAN state after restart
+    - mmc: sdhci-sprd: Fix minimum clock limit
+    - fs: dlm: fix race between test_bit() and queue_work()
+    - fs: dlm: handle -EBUSY first in lock arg validation
+    - HID: multitouch: Add memory barriers
+    - quota: Check next/prev free block number after reading from quota file
+    - ASoC: wcd9335: fix order of Slimbus unprepare/disable
+    - regulator: qcom_rpm: Fix circular deferral regression
+    - RISC-V: Make port I/O string accessors actually work
+    - parisc: fbdev/stifb: Align graphics memory size to 4MB
+    - riscv: Allow PROT_WRITE-only mmap()
+    - riscv: Pass -mno-relax only on lld < 15.0.0
+    - UM: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - PCI: Sanitise firmware BAR assignments behind a PCI-PCI bridge
+    - powerpc/boot: Explicitly disable usage of SPE instructions
+    - fbdev: smscufx: Fix use-after-free in ufx_ops_open()
+    - btrfs: fix race between quota enable and quota rescan ioctl
+    - f2fs: increase the limit for reserve_root
+    - f2fs: fix to do sanity check on destination blkaddr during recovery
+    - f2fs: fix to do sanity check on summary info
+    - nilfs2: fix use-after-free bug of struct nilfs_root
+    - jbd2: wake up journal waiters in FIFO order, not LIFO
+    - ext4: avoid crash when inline data creation follows DIO write
+    - ext4: fix null-ptr-deref in ext4_write_info
+    - ext4: make ext4_lazyinit_thread freezable
+    - ext4: place buffer head allocation before handle start
+    - livepatch: fix race between fork and KLP transition
+    - ftrace: Properly unset FTRACE_HASH_FL_MOD
+    - ring-buffer: Allow splice to read previous partially read pages
+    - ring-buffer: Have the shortest_full queue be the shortest not longest
+    - ring-buffer: Check pending waiters when doing wake ups as well
+    - ring-buffer: Fix race between reset page and reading page
+    - media: cedrus: Set the platform driver data earlier
+    - KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
+    - KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
+    - KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
+    - gcov: support GCC 12.1 and newer compilers
+    - drm/nouveau: fix a use-after-free in nouveau_gem_prime_import_sg_table()
+    - selinux: use "grep -E" instead of "egrep"
+    - tracing: Disable interrupt or preemption before acquiring arch_spinlock_t
+    - userfaultfd: open userfaultfds with O_RDONLY
+    - sh: machvec: Use char[] for section boundaries
+    - ARM: 9247/1: mm: set readonly for MT_MEMORY_RO with ARM_LPAE
+    - nfsd: Fix a memory leak in an error handling path
+    - wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
+    - wifi: mac80211: allow bw change during channel switch in mesh
+    - bpftool: Fix a wrong type cast in btf_dumper_int
+    - x86/resctrl: Fix to restore to original value when re-enabling hardware
+      prefetch register
+    - wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
+    - spi: qup: add missing clk_disable_unprepare on error in spi_qup_resume()
+    - spi: qup: add missing clk_disable_unprepare on error in
+      spi_qup_pm_resume_runtime()
+    - wifi: rtl8xxxu: Fix skb misuse in TX queue selection
+    - bpf: btf: fix truncated last_member_type_id in btf_struct_resolve
+    - wifi: rtl8xxxu: gen2: Fix mistake in path B IQ calibration
+    - net: fs_enet: Fix wrong check in do_pd_setup
+    - bpf: Ensure correct locking around vulnerable function find_vpid()
+    - x86/microcode/AMD: Track patch allocation size explicitly
+    - spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe
+    - netfilter: nft_fib: Fix for rpath check with VRF devices
+    - spi: s3c64xx: Fix large transfers with DMA
+    - vhost/vsock: Use kvmalloc/kvfree for larger packets.
+    - sctp: handle the error returned from sctp_auth_asoc_init_active_key
+    - tcp: fix tcp_cwnd_validate() to not forget is_cwnd_limited
+    - net: rds: don't hold sock lock when cancelling work from
+      rds_tcp_reset_callbacks()
+    - bnx2x: fix potential memory leak in bnx2x_tpa_stop()
+    - net/ieee802154: reject zero-sized raw_sendmsg()
+    - once: add DO_ONCE_SLOW() for sleepable contexts
+    - net: mvpp2: fix mvpp2 debugfs leak
+    - drm: bridge: adv7511: fix CEC power down control register offset
+    - drm/mipi-dsi: Detach devices when removing the host
+    - platform/chrome: fix double-free in chromeos_laptop_prepare()
+    - platform/chrome: fix memory corruption in ioctl
+    - platform/x86: msi-laptop: Fix old-ec check for backlight registering
+    - platform/x86: msi-laptop: Fix resource cleanup
+    - drm: fix drm_mipi_dbi build errors
+    - drm/bridge: megachips: Fix a null pointer dereference bug
+    - ASoC: rsnd: Add check for rsnd_mod_power_on
+    - ALSA: hda: beep: Simplify keep-power-at-enable behavior
+    - drm/omap: dss: Fix refcount leak bugs
+    - mmc: au1xmmc: Fix an error handling path in au1xmmc_probe()
+    - ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API
+    - drm/msm/dpu: index dpu_kms->hw_vbif using vbif_idx
+    - ALSA: dmaengine: increment buffer pointer atomically
+    - mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
+    - ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe
+    - ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe
+    - ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe
+    - ALSA: hda/hdmi: Don't skip notification handling during PM operation
+    - memory: pl353-smc: Fix refcount leak bug in pl353_smc_probe()
+    - memory: of: Fix refcount leak bug in of_get_ddr_timings()
+    - soc: qcom: smsm: Fix refcount leak bugs in qcom_smsm_probe()
+    - soc: qcom: smem_state: Add refcounting for the 'state->of_node'
+    - ARM: dts: turris-omnia: Fix mpp26 pin name and comment
+    - ARM: dts: kirkwood: lsxl: fix serial line
+    - ARM: dts: kirkwood: lsxl: remove first ethernet port
+    - ARM: dts: exynos: correct s5k6a3 reset polarity on Midas family
+    - ARM: Drop CMDLINE_* dependency on ATAGS
+    - ARM: dts: exynos: fix polarity of VBUS GPIO of Origen
+    - iio: adc: at91-sama5d2_adc: fix AT91_SAMA5D2_MR_TRACKTIM_MAX
+    - iio: adc: at91-sama5d2_adc: check return status for pressure and touch
+    - iio: adc: at91-sama5d2_adc: lock around oversampling and sample freq
+    - iio: inkern: only release the device node when done with it
+    - iio: ABI: Fix wrong format of differential capacitance channel ABI.
+    - clk: meson: Hold reference returned by of_get_parent()
+    - clk: oxnas: Hold reference returned by of_get_parent()
+    - clk: berlin: Add of_node_put() for of_get_parent()
+    - clk: tegra: Fix refcount leak in tegra210_clock_init
+    - clk: tegra: Fix refcount leak in tegra114_clock_init
+    - clk: tegra20: Fix refcount leak in tegra20_clock_init
+    - HSI: omap_ssi: Fix refcount leak in ssi_probe
+    - HSI: omap_ssi_port: Fix dma_map_sg error check
+    - media: exynos4-is: fimc-is: Add of_node_put() when breaking out of loop
+    - tty: xilinx_uartps: Fix the ignore_status
+    - media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
+    - RDMA/rxe: Fix "kernel NULL pointer dereference" error
+    - RDMA/rxe: Fix the error caused by qp->sk
+    - misc: ocxl: fix possible refcount leak in afu_ioctl()
+    - dyndbg: fix module.dyndbg handling
+    - dyndbg: let query-modname override actual module name
+    - mtd: devices: docg3: check the return value of devm_ioremap() in the probe
+    - RDMA/siw: Always consume all skbuf data in sk_data_ready() upcall.
+    - ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
+    - ata: fix ata_id_has_devslp()
+    - ata: fix ata_id_has_ncq_autosense()
+    - ata: fix ata_id_has_dipm()
+    - mtd: rawnand: meson: fix bit map use in meson_nfc_ecc_correct()
+    - md/raid5: Ensure stripe_fill happens on non-read IO with journal
+    - xhci: Don't show warning for reinit on known broken suspend
+    - usb: gadget: function: fix dangling pnp_string in f_printer.c
+    - drivers: serial: jsm: fix some leaks in probe
+    - tty: serial: fsl_lpuart: disable dma rx/tx use flags in lpuart_dma_shutdown
+    - phy: qualcomm: call clk_disable_unprepare in the error handling
+    - staging: vt6655: fix some erroneous memory clean-up loops
+    - firmware: google: Test spinlock on panic path to avoid lockups
+    - serial: 8250: Fix restoring termios speed after suspend
+    - scsi: libsas: Fix use-after-free bug in smp_execute_task_sg()
+    - fsi: core: Check error number after calling ida_simple_get
+    - mfd: intel_soc_pmic: Fix an error handling path in
+      intel_soc_pmic_i2c_probe()
+    - mfd: fsl-imx25: Fix an error handling path in mx25_tsadc_setup_irq()
+    - mfd: lp8788: Fix an error handling path in lp8788_probe()
+    - mfd: lp8788: Fix an error handling path in lp8788_irq_init() and
+      lp8788_irq_init()
+    - mfd: fsl-imx25: Fix check for platform_get_irq() errors
+    - mfd: sm501: Add check for platform_driver_register()
+    - clk: mediatek: mt8183: mfgcfg: Propagate rate changes to parent
+    - dmaengine: ioat: stop mod_timer from resurrecting deleted timer in
+      __cleanup()
+    - spmi: pmic-arb: correct duplicate APID to PPID mapping logic
+    - clk: bcm2835: fix bcm2835_clock_rate_from_divisor declaration
+    - clk: ti: dra7-atl: Fix reference leak in of_dra7_atl_clk_probe
+    - clk: ast2600: BCLK comes from EPLL
+    - mailbox: bcm-ferxrm-mailbox: Fix error check for dma_map_sg
+    - powerpc/math_emu/efp: Include module.h
+    - powerpc/sysdev/fsl_msi: Add missing of_node_put()
+    - powerpc/pci_dn: Add missing of_node_put()
+    - powerpc/powernv: add missing of_node_put() in opal_export_attrs()
+    - x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition
+    - powerpc/64s: Fix GENERIC_CPU build flags for PPC970 / G5
+    - powerpc: Fix SPE Power ISA properties for e500v1 platforms
+    - cgroup/cpuset: Enable update_tasks_cpumask() on top_cpuset
+    - iommu/omap: Fix buffer overflow in debugfs
+    - crypto: akcipher - default implementation for setting a private key
+    - crypto: ccp - Release dma channels before dmaengine unrgister
+    - iommu/iova: Fix module config properly
+    - kbuild: remove the target in signal traps when interrupted
+    - crypto: cavium - prevent integer overflow loading firmware
+    - f2fs: fix race condition on setting FI_NO_EXTENT flag
+    - ACPI: video: Add Toshiba Satellite/Portege Z830 quirk
+    - MIPS: BCM47XX: Cast memcmp() of function to (void *)
+    - powercap: intel_rapl: fix UBSAN shift-out-of-bounds issue
+    - thermal: intel_powerclamp: Use get_cpu() instead of smp_processor_id() to
+      avoid crash
+    - NFSD: Return nfserr_serverfault if splice_ok but buf->pages have data
+    - wifi: brcmfmac: fix invalid address access when enabling SCAN log level
+    - bpftool: Clear errno after libcap's checks
+    - openvswitch: Fix double reporting of drops in dropwatch
+    - openvswitch: Fix overreporting of drops in dropwatch
+    - tcp: annotate data-race around tcp_md5sig_pool_populated
+    - wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()
+    - xfrm: Update ipcomp_scratches with NULL when freed
+    - wifi: brcmfmac: fix use-after-free bug in brcmf_netdev_start_xmit()
+    - Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
+    - Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
+    - can: bcm: check the result of can_send() in bcm_can_tx()
+    - wifi: rt2x00: don't run Rt5592 IQ calibration on MT7620
+    - wifi: rt2x00: set correct TX_SW_CFG1 MAC register for MT7620
+    - wifi: rt2x00: set VGC gain for both chains of MT7620
+    - wifi: rt2x00: set SoC wmac clock register
+    - wifi: rt2x00: correctly set BBP register 86 for MT7620
+    - net: If sock is dead don't access sock's sk_wq in sk_stream_wait_memory
+    - Bluetooth: L2CAP: Fix user-after-free
+    - drm/nouveau/nouveau_bo: fix potential memory leak in nouveau_bo_alloc()
+    - drm: Use size_t type for len variable in drm_copy_field()
+    - drm: Prevent drm_copy_field() to attempt copying a NULL pointer
+    - drm/amd/display: fix overflow on MIN_I64 definition
+    - drm/vc4: vec: Fix timings for VEC modes
+    - drm: panel-orientation-quirks: Add quirk for Anbernic Win600
+    - platform/x86: msi-laptop: Change DMI match / alias strings to fix module
+      autoloading
+    - drm/amdgpu: fix initial connector audio value
+    - mmc: sdhci-msm: add compatible string check for sdm670
+    - ARM: dts: imx7d-sdb: config the max pressure for tsc2046
+    - ARM: dts: imx6q: add missing properties for sram
+    - ARM: dts: imx6dl: add missing properties for sram
+    - ARM: dts: imx6qp: add missing properties for sram
+    - ARM: dts: imx6sl: add missing properties for sram
+    - ARM: dts: imx6sll: add missing properties for sram
+    - ARM: dts: imx6sx: add missing properties for sram
+    - btrfs: scrub: try to fix super block errors
+    - clk: zynqmp: Fix stack-out-of-bounds in strncpy`
+    - media: cx88: Fix a null-ptr-deref bug in buffer_prepare()
+    - clk: zynqmp: pll: rectify rate rounding in zynqmp_pll_round_rate
+    - scsi: 3w-9xxx: Avoid disabling device if failing to enable it
+    - nbd: Fix hung when signal interrupts nbd_start_device_ioctl()
+    - power: supply: adp5061: fix out-of-bounds read in adp5061_get_chg_type()
+    - staging: vt6655: fix potential memory leak
+    - ata: libahci_platform: Sanity check the DT child nodes number
+    - bcache: fix set_at_max_writeback_rate() for multiple attached devices
+    - HID: roccat: Fix use-after-free in roccat_read()
+    - md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d
+    - usb: host: xhci: Fix potential memory leak in xhci_alloc_stream_info()
+    - usb: musb: Fix musb_gadget.c rxstate overflow bug
+    - Revert "usb: storage: Add quirk for Samsung Fit flash"
+    - staging: rtl8723bs: fix a potential memory leak in rtw_init_cmd_priv()
+    - nvme: copy firmware_rev on each init
+    - nvmet-tcp: add bounds check on Transfer Tag
+    - usb: idmouse: fix an uninit-value in idmouse_open
+    - clk: bcm2835: Make peripheral PLLC critical
+    - perf intel-pt: Fix segfault in intel_pt_print_info() with uClibc
+    - net: ieee802154: return -EINVAL for unknown addr type
+    - Revert "net/ieee802154: reject zero-sized raw_sendmsg()"
+    - net/ieee802154: don't warn zero-sized raw_sendmsg()
+    - ext4: continue to expand file system when the target size doesn't reach
+    - efi: libstub: drop pointless get_memory_map() call
+    - inet: fully convert sk->sk_rx_dst to RCU rules
+    - thermal: intel_powerclamp: Use first online CPU as control_cpu
+    - Linux 5.4.220
+
+  * Focal update: v5.4.219 upstream stable release (LP: #1996804)
+    - Linux 5.4.219
+
+ -- Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>  Fri, 06 Jan 2023 08:50:27 -0800
+
+linux (5.4.0-137.154) focal; urgency=medium
+
+  * focal/linux: 5.4.0-137.154 -proposed tracker (LP: #2001969)
+
+  * CVE-2022-3643
+    - 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
+
+  * CVE-2022-45934
+    - Bluetooth: L2CAP: Fix u8 overflow
+
+  * CVE-2022-42896
+    - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 05 Jan 2023 13:08:58 -0300
+
+linux (5.4.0-136.153) focal; urgency=medium
+
+  * focal/linux: 5.4.0-136.153 -proposed tracker (LP: #1997835)
+
+  * Expose built-in trusted and revoked certificates (LP: #1996892)
+    - [Packaging] Expose built-in trusted and revoked certificates
+
+  * [UBUNTU 20.04] KVM: PV: ext call delivered twice when receiver in PSW wait
+    (LP: #1995941)
+    - KVM: s390: pv: don't present the ecall interrupt twice
+
+  * [UBUNTU 20.04] boot: Add s390x secure boot trailer (LP: #1996071)
+    - s390/boot: add secure boot trailer
+
+  * Fix rfkill causing soft blocked wifi (LP: #1996198)
+    - platform/x86: hp_wmi: Fix rfkill causing soft blocked wifi
+
+  * md: Replace snprintf with scnprintf (LP: #1993315)
+    - md: Replace snprintf with scnprintf
+
+  * input/keyboard: the keyboard on some Asus laptops can't work (LP: #1992266)
+    - ACPI: resource: Skip IRQ override on Asus Vivobook K3402ZA/K3502ZA
+    - ACPI: resource: Add ASUS model S5402ZA to quirks
+
+  * Focal update: v5.4.218 upstream stable release (LP: #1995530)
+    - mm: pagewalk: Fix race between unmap and page walker
+    - perf tools: Fixup get_current_dir_name() compilation
+    - firmware: arm_scmi: Add SCMI PM driver remove routine
+    - dmaengine: xilinx_dma: cleanup for fetching xlnx,num-fstores property
+    - dmaengine: xilinx_dma: Report error in case of dma_set_mask_and_coherent API
+      failure
+    - ARM: dts: fix Moxa SDIO 'compatible', remove 'sdhci' misnomer
+    - scsi: qedf: Fix a UAF bug in __qedf_probe()
+    - net/ieee802154: fix uninit value bug in dgram_sendmsg
+    - um: Cleanup syscall_handler_t cast in syscalls_32.h
+    - um: Cleanup compiler warning in arch/x86/um/tls_32.c
+    - arch: um: Mark the stack non-executable to fix a binutils warning
+    - usb: mon: make mmapped memory read only
+    - USB: serial: ftdi_sio: fix 300 bps rate for SIO
+    - mmc: core: Replace with already defined values for readability
+    - mmc: core: Terminate infinite loop in SD-UHS voltage switch
+    - rpmsg: qcom: glink: replace strncpy() with strscpy_pad()
+    - nilfs2: fix leak of nilfs_root in case of writer thread creation failure
+    - nilfs2: replace WARN_ONs by nilfs_error for checkpoint acquisition failure
+    - ceph: don't truncate file in atomic_open
+    - random: clamp credited irq bits to maximum mixed
+    - ALSA: hda: Fix position reporting on Poulsbo
+    - efi: Correct Macmini DMI match in uefi cert quirk
+    - USB: serial: qcserial: add new usb-id for Dell branded EM7455
+    - random: restore O_NONBLOCK support
+    - random: avoid reading two cache lines on irq randomness
+    - random: use expired timer rather than wq for mixing fast pool
+    - Input: xpad - add supported devices as contributed on github
+    - Input: xpad - fix wireless 360 controller breaking after suspend
+    - Linux 5.4.218
+
+  * Focal update: v5.4.217 upstream stable release (LP: #1995528)
+    - xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag
+    - xfs: introduce XFS_MAX_FILEOFF
+    - xfs: truncate should remove all blocks, not just to the end of the page
+      cache
+    - xfs: fix s_maxbytes computation on 32-bit kernels
+    - xfs: fix IOCB_NOWAIT handling in xfs_file_dio_aio_read
+    - xfs: refactor remote attr value buffer invalidation
+    - xfs: fix memory corruption during remote attr value buffer invalidation
+    - xfs: move incore structures out of xfs_da_format.h
+    - xfs: streamline xfs_attr3_leaf_inactive
+    - xfs: fix uninitialized variable in xfs_attr3_leaf_inactive
+    - xfs: remove unused variable 'done'
+    - Makefile.extrawarn: Move -Wcast-function-type-strict to W=1
+    - docs: update mediator information in CoC docs
+    - Linux 5.4.217
+
+  * Focal update: v5.4.216 upstream stable release (LP: #1995526)
+    - uas: add no-uas quirk for Hiksemi usb_disk
+    - usb-storage: Add Hiksemi USB3-FW to IGNORE_UAS
+    - uas: ignore UAS for Thinkplus chips
+    - net: usb: qmi_wwan: Add new usb-id for Dell branded EM7455
+    - clk: ingenic-tcu: Properly enable registers before accessing timers
+    - ARM: dts: integrator: Tag PCI host with device_type
+    - ntfs: fix BUG_ON in ntfs_lookup_inode_by_name()
+    - libata: add ATA_HORKAGE_NOLPM for Pioneer BDR-207M and BDR-205
+    - mmc: moxart: fix 4-bit bus width and remove 8-bit bus width
+    - mm/page_alloc: fix race condition between build_all_zonelists and page
+      allocation
+    - mm: prevent page_frag_alloc() from corrupting the memory
+    - mm/migrate_device.c: flush TLB while holding PTL
+    - mm: fix madivse_pageout mishandling on non-LRU page
+    - media: dvb_vb2: fix possible out of bound access
+    - ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver
+    - ARM: dts: am33xx: Fix MMCHS0 dma properties
+    - soc: sunxi: sram: Actually claim SRAM regions
+    - soc: sunxi: sram: Prevent the driver from being unbound
+    - soc: sunxi_sram: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - soc: sunxi: sram: Fix probe function ordering issues
+    - soc: sunxi: sram: Fix debugfs info for A64 SRAM C
+    - Revert "drm: bridge: analogix/dp: add panel prepare/unprepare in
+      suspend/resume time"
+    - Input: melfas_mip4 - fix return value check in mip4_probe()
+    - usbnet: Fix memory leak in usbnet_disconnect()
+    - nvme: add new line after variable declatation
+    - nvme: Fix IOC_PR_CLEAR and IOC_PR_RELEASE ioctls for nvme devices
+    - selftests: Fix the if conditions of in test_extra_filter()
+    - clk: imx: imx6sx: remove the SET_RATE_PARENT flag for QSPI clocks
+    - clk: iproc: Do not rely on node name for correct PLL setup
+    - Linux 5.4.216
+
+  * Focal update: v5.4.215 upstream stable release (LP: #1993203)
+    - of: fdt: fix off-by-one error in unflatten_dt_nodes()
+    - NFSv4: Turn off open-by-filehandle and NFS re-export for NFSv4.0
+    - gpio: mpc8xxx: Fix support for IRQ_TYPE_LEVEL_LOW flow_type in mpc85xx
+    - drm/meson: Correct OSD1 global alpha value
+    - drm/meson: Fix OSD1 RGB to YCbCr coefficient
+    - parisc: ccio-dma: Add missing iounmap in error path in ccio_probe()
+    - ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC
+    - task_stack, x86/cea: Force-inline stack helpers
+    - tracing: hold caller_addr to hardirq_{enable,disable}_ip
+    - cifs: revalidate mapping when doing direct writes
+    - cifs: don't send down the destination address to sendmsg for a SOCK_STREAM
+    - MAINTAINERS: add Chandan as xfs maintainer for 5.4.y
+    - iomap: iomap that extends beyond EOF should be marked dirty
+    - ASoC: nau8824: Fix semaphore unbalance at error paths
+    - regulator: pfuze100: Fix the global-out-of-bounds access in
+      pfuze100_regulator_probe()
+    - rxrpc: Fix local destruction being repeated
+    - rxrpc: Fix calc of resend age
+    - ALSA: hda/sigmatel: Keep power up while beep is enabled
+    - ALSA: hda/tegra: Align BDL entry to 4KB boundary
+    - net: usb: qmi_wwan: add Quectel RM520N
+    - afs: Return -EAGAIN, not -EREMOTEIO, when a file already locked
+    - MIPS: OCTEON: irq: Fix octeon_irq_force_ciu_mapping()
+    - mksysmap: Fix the mismatch of 'L0' symbols in System.map
+    - video: fbdev: pxa3xx-gcu: Fix integer overflow in pxa3xx_gcu_write
+    - cgroup: Add missing cpus_read_lock() to cgroup_attach_task_all()
+    - ALSA: hda/sigmatel: Fix unused variable warning for beep power change
+    - usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind
+    - usb: dwc3: Issue core soft reset before enabling run/stop
+    - usb: dwc3: gadget: Prevent repeat pullup()
+    - usb: dwc3: gadget: Refactor pullup()
+    - usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup()
+    - usb: dwc3: gadget: Avoid duplicate requests to enable Run/Stop
+    - usb: xhci-mtk: get the microframe boundary for ESIT
+    - usb: xhci-mtk: add only one extra CS for FS/LS INTR
+    - usb: xhci-mtk: use @sch_tt to check whether need do TT schedule
+    - usb: xhci-mtk: add a function to (un)load bandwidth info
+    - usb: xhci-mtk: add some schedule error number
+    - usb: xhci-mtk: allow multiple Start-Split in a microframe
+    - usb: xhci-mtk: relax TT periodic bandwidth allocation
+    - wifi: mac80211: Fix UAF in ieee80211_scan_rx()
+    - tty/serial: atmel: RS485 & ISO7816: wait for TXRDY before sending data
+    - serial: atmel: remove redundant assignment in rs485_config
+    - tty: serial: atmel: Preserve previous USART mode if RS485 disabled
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: cdns3: fix issue with rearming ISO OUT endpoint
+    - Revert "usb: add quirks for Lenovo OneLink+ Dock"
+    - Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio"
+    - USB: core: Fix RST error in hub.c
+    - USB: serial: option: add Quectel BG95 0x0203 composition
+    - USB: serial: option: add Quectel RM520N
+    - ALSA: hda/tegra: set depop delay for tegra
+    - ALSA: hda: add Intel 5 Series / 3400 PCI DID
+    - ALSA: hda/realtek: Add quirk for Huawei WRT-WX9
+    - ALSA: hda/realtek: Re-arrange quirk table entries
+    - ALSA: hda/realtek: Add pincfg for ASUS G513 HP jack
+    - ALSA: hda/realtek: Add pincfg for ASUS G533Z HP jack
+    - ALSA: hda/realtek: Add quirk for ASUS GA503R laptop
+    - ALSA: hda/realtek: Enable 4-speaker output Dell Precision 5530 laptop
+    - efi: libstub: check Shim mode using MokSBStateRT
+    - mm/slub: fix to return errno if kmalloc() fails
+    - arm64: dts: rockchip: Pull up wlan wake# on Gru-Bob
+    - arm64: dts: rockchip: Set RK3399-Gru PCLK_EDP to 24 MHz
+    - arm64: dts: rockchip: Remove 'enable-active-low' from rk3399-puma
+    - netfilter: nf_conntrack_sip: fix ct_sip_walk_headers
+    - netfilter: nf_conntrack_irc: Tighten matching on DCC message
+    - netfilter: nfnetlink_osf: fix possible bogus match in nf_osf_find()
+    - iavf: Fix cached head and tail value for iavf_get_tx_pending
+    - ipvlan: Fix out-of-bound bugs caused by unset skb->mac_header
+    - net: team: Unsync device addresses on ndo_stop
+    - MIPS: lantiq: export clk_get_io() for lantiq_wdt.ko
+    - MIPS: Loongson32: Fix PHY-mode being left unspecified
+    - iavf: Fix bad page state
+    - i40e: Fix set max_tx_rate when it is lower than 1 Mbps
+    - of: mdio: Add of_node_put() when breaking out of for_each_xx
+    - net/sched: taprio: avoid disabling offload when it was never enabled
+    - net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child
+      qdiscs
+    - netfilter: ebtables: fix memory leak when blob is malformed
+    - can: gs_usb: gs_can_open(): fix race dev->can.state condition
+    - perf jit: Include program header in ELF files
+    - perf kcore_copy: Do not check /proc/modules is unchanged
+    - net: sunhme: Fix packet reception for len < RX_COPY_THRESHOLD
+    - net: sched: fix possible refcount leak in tc_new_tfilter()
+    - serial: Create uart_xmit_advance()
+    - serial: tegra: Use uart_xmit_advance(), fixes icount.tx accounting
+    - serial: tegra-tcu: Use uart_xmit_advance(), fixes icount.tx accounting
+    - s390/dasd: fix Oops in dasd_alias_get_start_dev due to missing pavgroup
+    - usb: xhci-mtk: fix issue of out-of-bounds array access
+    - cifs: always initialize struct msghdr smb_msg completely
+    - Drivers: hv: Never allocate anything besides framebuffer from framebuffer
+      memory region
+    - drm/amd/display: Limit user regamma to a valid value
+    - drm/rockchip: Fix return type of cdn_dp_connector_mode_valid
+    - workqueue: don't skip lockdep work dependency in cancel_work_sync()
+    - ext4: fix bug in extents parsing when eh_entries == 0 and eh_depth > 0
+    - xfs: replace -EIO with -EFSCORRUPTED for corrupt metadata
+    - xfs: slightly tweak an assert in xfs_fs_map_blocks
+    - xfs: add missing assert in xfs_fsmap_owner_from_rmap
+    - xfs: range check ri_cnt when recovering log items
+    - xfs: attach dquots and reserve quota blocks during unwritten conversion
+    - xfs: convert EIO to EFSCORRUPTED when log contents are invalid
+    - xfs: constify the buffer pointer arguments to error functions
+    - xfs: always log corruption errors
+    - xfs: fix some memory leaks in log recovery
+    - xfs: stabilize insert range start boundary to avoid COW writeback race
+    - xfs: use bitops interface for buf log item AIL flag check
+    - xfs: refactor agfl length computation function
+    - xfs: split the sunit parameter update into two parts
+    - xfs: don't commit sunit/swidth updates to disk if that would cause repair
+      failures
+    - xfs: fix an ABBA deadlock in xfs_rename
+    - xfs: fix use-after-free when aborting corrupt attr inactivation
+    - ext4: make directory inode spreading reflect flexbg size
+    - Linux 5.4.215
+
+  * Focal update: v5.4.214 upstream stable release (LP: #1993196)
+    - drm/msm/rd: Fix FIFO-full deadlock
+    - HID: ishtp-hid-clientHID: ishtp-hid-client: Fix comment typo
+    - hid: intel-ish-hid: ishtp: Fix ishtp client sending disordered message
+    - tg3: Disable tg3 device on system reboot to avoid triggering AER
+    - ieee802154: cc2520: add rc code in cc2520_tx()
+    - Input: iforce - add support for Boeder Force Feedback Wheel
+    - nvmet-tcp: fix unhandled tcp states in nvmet_tcp_state_change()
+    - perf/arm_pmu_platform: fix tests for platform_get_irq() failure
+    - platform/x86: acer-wmi: Acer Aspire One AOD270/Packard Bell Dot keymap fixes
+    - usb: storage: Add ASUS <0x0b05:0x1932> to IGNORE_UAS
+    - mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()
+    - net: dp83822: disable rx error interrupt
+    - soc: fsl: select FSL_GUTS driver for DPIO
+    - tracefs: Only clobber mode/uid/gid on remount if asked
+    - Linux 5.4.214
+
+  * Focal update: v5.4.213 upstream stable release (LP: #1992211)
+    - efi: capsule-loader: Fix use-after-free in efi_capsule_write
+    - wifi: iwlegacy: 4965: corrected fix for potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - fs: only do a memory barrier for the first set_buffer_uptodate()
+    - Revert "mm: kmemleak: take a full lowmem check in kmemleak_*_phys()"
+    - net: dp83822: disable false carrier interrupt
+    - drm/msm/dsi: fix the inconsistent indenting
+    - drm/msm/dsi: Fix number of regulators for msm8996_dsi_cfg
+    - platform/x86: pmc_atom: Fix SLP_TYPx bitfield mask
+    - iio: adc: mcp3911: make use of the sign bit
+    - ieee802154/adf7242: defer destroy_workqueue call
+    - wifi: cfg80211: debugfs: fix return type in ht40allow_map_read()
+    - Revert "xhci: turn off port power in shutdown"
+    - net: sched: tbf: don't call qdisc_put() while holding tree lock
+    - ethernet: rocker: fix sleep in atomic context bug in neigh_timer_handler
+    - kcm: fix strp_init() order and cleanup
+    - sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb
+    - tcp: annotate data-race around challenge_timestamp
+    - Revert "sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb"
+    - net/smc: Remove redundant refcount increase
+    - serial: fsl_lpuart: RS485 RTS polariy is inverse
+    - staging: rtl8712: fix use after free bugs
+    - powerpc: align syscall table for ppc32
+    - vt: Clear selection before changing the font
+    - tty: serial: lpuart: disable flow control while waiting for the transmit
+      engine to complete
+    - Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flag
+    - iio: adc: mcp3911: use correct formula for AD conversion
+    - misc: fastrpc: fix memory corruption on probe
+    - misc: fastrpc: fix memory corruption on open
+    - USB: serial: ftdi_sio: add Omron CS1W-CIF31 device id
+    - binder: fix UAF of ref->proc caused by race condition
+    - usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup
+    - drm/i915/reg: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops
+    - Revert "clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops"
+    - clk: core: Fix runtime PM sequence in clk_core_unprepare()
+    - Input: rk805-pwrkey - fix module autoloading
+    - clk: bcm: rpi: Fix error handling of raspberrypi_fw_get_rate
+    - hwmon: (gpio-fan) Fix array out of bounds access
+    - gpio: pca953x: Add mutex_lock for regcache sync in PM
+    - thunderbolt: Use the actual buffer in tb_async_error()
+    - xhci: Add grace period after xHC start to prevent premature runtime suspend.
+    - USB: serial: cp210x: add Decagon UCA device id
+    - USB: serial: option: add support for OPPO R11 diag port
+    - USB: serial: option: add Quectel EM060K modem
+    - USB: serial: option: add support for Cinterion MV32-WA/WB RmNet mode
+    - usb: typec: altmodes/displayport: correct pin assignment for UFP receptacles
+    - usb: dwc2: fix wrong order of phy_power_on and phy_init
+    - USB: cdc-acm: Add Icom PMR F3400 support (0c26:0020)
+    - usb-storage: Add ignore-residue quirk for NXP PN7462AU
+    - s390/hugetlb: fix prepare_hugepage_range() check for 2 GB hugepages
+    - s390: fix nospec table alignments
+    - USB: core: Prevent nested device-reset calls
+    - usb: gadget: mass_storage: Fix cdrom data transfers on MAC-OS
+    - driver core: Don't probe devices after bus_type.match() probe deferral
+    - wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected
+    - net: mac802154: Fix a condition in the receive path
+    - ALSA: seq: oss: Fix data-race for max_midi_devs access
+    - ALSA: seq: Fix data-race at module auto-loading
+    - drm/i915/glk: ECS Liva Q2 needs GLK HDMI port timing quirk
+    - btrfs: harden identification of a stale device
+    - usb: dwc3: fix PHY disable sequence
+    - usb: dwc3: disable USB core PHY management
+    - USB: serial: ch341: fix lost character on LCR updates
+    - USB: serial: ch341: fix disabled rx timer on older devices
+    - scsi: megaraid_sas: Fix double kfree()
+    - drm/gem: Fix GEM handle release errors
+    - drm/amdgpu: Check num_gfx_rings for gfx v9_0 rb setup.
+    - drm/radeon: add a force flush to delay work when radeon
+    - parisc: ccio-dma: Handle kmalloc failure in ccio_init_resources()
+    - parisc: Add runtime check to prevent PA2.0 kernels on PA1.x machines
+    - arm64: cacheinfo: Fix incorrect assignment of signed error value to unsigned
+      fw_level
+    - fbdev: chipsfb: Add missing pci_disable_device() in chipsfb_pci_init()
+    - drm/amdgpu: mmVM_L2_CNTL3 register not initialized correctly
+    - ALSA: emu10k1: Fix out of bounds access in snd_emu10k1_pcm_channel_alloc()
+    - ALSA: aloop: Fix random zeros in capture data when using jiffies timer
+    - ALSA: usb-audio: Fix an out-of-bounds bug in
+      __snd_usb_parse_audio_interface()
+    - kprobes: Prohibit probes in gate area
+    - debugfs: add debugfs_lookup_and_remove()
+    - nvmet: fix a use-after-free
+    - scsi: mpt3sas: Fix use-after-free warning
+    - scsi: lpfc: Add missing destroy_workqueue() in error path
+    - cgroup: Optimize single thread migration
+    - cgroup: Elide write-locking threadgroup_rwsem when updating csses on an
+      empty subtree
+    - cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock
+    - smb3: missing inode locks in punch hole
+    - ARM: dts: imx6qdl-kontron-samx6i: remove duplicated node
+    - regulator: core: Clean up on enable failure
+    - RDMA/cma: Fix arguments order in net device validation
+    - soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugs
+    - RDMA/hns: Fix supported page size
+    - netfilter: br_netfilter: Drop dst references before setting.
+    - rxrpc: Fix an insufficiently large sglist in rxkad_verify_packet_2()
+    - afs: Use the operation issue time instead of the reply time for callbacks
+    - sch_sfb: Don't assume the skb is still around after enqueueing to child
+    - tipc: fix shift wrapping bug in map_get()
+    - i40e: Fix kernel crash during module removal
+    - RDMA/siw: Pass a pointer to virt_to_page()
+    - ipv6: sr: fix out-of-bounds read when setting HMAC data.
+    - RDMA/mlx5: Set local port to one when accessing counters
+    - nvme-tcp: fix UAF when detecting digest errors
+    - tcp: fix early ETIMEDOUT after spurious non-SACK RTO
+    - sch_sfb: Also store skb len before calling child enqueue
+    - x86/nospec: Fix i386 RSB stuffing
+    - MIPS: loongson32: ls1c: Fix hang during startup
+    - Linux 5.4.213
+
+  * CVE-2022-2663
+    - netfilter: nf_conntrack_irc: Fix forged IP logic
+
+  * CVE-2022-3061
+    - video: fbdev: i740fb: Error out if 'pixclock' equals zero
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 24 Nov 2022 16:40:01 +0100
+
+linux (5.4.0-135.152) focal; urgency=medium
+
+  * focal/linux: 5.4.0-135.152 -proposed tracker (LP: #1997412)
+
+  * containerd sporadic timeouts (LP: #1996678)
+    - epoll: call final ep_events_available() check under the lock
+    - epoll: check for events when removing a timed out thread from the wait queue
+    - Revert "fs: check FMODE_LSEEK to control internal pipe splicing"
+
+  * CVE-2022-3621
+    - nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
+
+  * CVE-2022-3565
+    - mISDN: fix use-after-free bugs in l1oip timer handlers
+
+  * 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-3564
+    - 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-3594
+    - r8152: Rate limit overflow messages
+
+  * CVE-2022-42703
+    - mm/rmap.c: don't reuse anon_vma if we just want a copy
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 23 Nov 2022 16:51:44 -0300
+
+linux (5.4.0-132.148) focal; urgency=medium
+
+  * CVE-2022-42719
+    - mac80211: mlme: find auth challenge directly
+    - wifi: mac80211: don't parse mbssid in assoc response
+    - wifi: mac80211: fix MBSSID parsing use-after-free
+
+  * iavf: SR-IOV VFs error with no traffic flow when MTU greater than 1500
+    (LP: #1983656)
+    - iavf: Fix set max MTU size with port VLAN and jumbo frames
+    - i40e: Fix VF set max MTU size
+
+  * fib_nexthop_nongw.sh from ubuntu_kernel_selftests failed on B-5.4
+    (LP: #1990800)
+    - SAUCE: selftests/net: skipping tests for older ip command releases
+
+  * CVE-2022-29901
+    - Revert "x86/speculation: Add RSB VM Exit protections"
+    - Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
+    - 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/kvm/vmx: Make noinstr clean
+    - 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: Remove skip_r11rcx
+    - 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
+    - intel_idle: Disable IBRS during long idle
+    - x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
+    - 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: Use TEST %REG,%REG instead of CMP $0,%REG in vmenter.S
+    - KVM/nVMX: Use __vmx_vcpu_run in nested_vmx_check_vmentry_hw
+    - KVM: VMX: Flatten __vmx_vcpu_run()
+    - KVM: VMX: Convert launched argument to flags
+    - 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
+
+  * ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+    systems (LP: #1990985)
+    - ACPI: processor_idle: Skip dummy wait if kernel is in guest
+    - ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+      systems
+
+  * cgroup: all controllers mounted when using 'cgroup_no_v1=' (LP: #1988584)
+    - cgroup-v1: add disabled controller check in cgroup1_parse_param()
+
+  * Focal update: v5.4.212 upstream stable release (LP: #1991156)
+    - audit: fix potential double free on error path from fsnotify_add_inode_mark
+    - parisc: Fix exception handler for fldw and fstw instructions
+    - kernel/sys_ni: add compat entry for fadvise64_64
+    - usb: cdns3: Fix issue for clear halt endpoint
+    - pinctrl: amd: Don't save/restore interrupt status and wake status bits
+    - sched/deadline: Unthrottle PI boosted threads while enqueuing
+    - sched/deadline: Fix stale throttling on de-/boosted tasks
+    - sched/deadline: Fix priority inheritance with multiple scheduling classes
+    - kernel/sched: Remove dl_boosted flag comment
+    - xfrm: fix refcount leak in __xfrm_policy_check()
+    - SUNRPC: RPC level errors should set task->tk_rpc_status
+    - rose: check NULL rose_loopback_neigh->loopback
+    - net/mlx5e: Properly disable vlan strip on non-UL reps
+    - net: moxa: get rid of asymmetry in DMA mapping/unmapping
+    - bonding: 802.3ad: fix no transmission of LACPDUs
+    - net: ipvtap - add __init/__exit annotations to module init/exit funcs
+    - netfilter: ebtables: reject blobs that don't provide all entry points
+    - bnxt_en: fix NQ resource accounting during vf creation on 57500 chips
+    - netfilter: nft_payload: report ERANGE for too long offset and length
+    - netfilter: nft_payload: do not truncate csum_offset and csum_type
+    - netfilter: nft_osf: restrict osf to ipv4, ipv6 and inet families
+    - netfilter: nft_tunnel: restrict it to netdev family
+    - net: Fix data-races around weight_p and dev_weight_[rt]x_bias.
+    - net: Fix data-races around netdev_tstamp_prequeue.
+    - ratelimit: Fix data-races in ___ratelimit().
+    - net: Fix a data-race around sysctl_tstamp_allow_data.
+    - net: Fix a data-race around sysctl_net_busy_poll.
+    - net: Fix a data-race around sysctl_net_busy_read.
+    - net: Fix a data-race around netdev_budget.
+    - net: Fix a data-race around netdev_budget_usecs.
+    - net: Fix a data-race around sysctl_somaxconn.
+    - ixgbe: stop resetting SYSTIME in ixgbe_ptp_start_cyclecounter
+    - btrfs: fix silent failure when deleting root reference
+    - btrfs: replace: drop assert for suspended replace
+    - btrfs: add info when mount fails due to stale replace target
+    - btrfs: check if root is readonly while setting security xattr
+    - x86/unwind/orc: Unwind ftrace trampolines with correct ORC entry
+    - loop: Check for overflow while configuring loop
+    - asm-generic: sections: refactor memory_intersects
+    - s390: fix double free of GS and RI CBs on fork() failure
+    - ACPI: processor: Remove freq Qos request for all CPUs
+    - mm/hugetlb: fix hugetlb not supporting softdirty tracking
+    - md: call __md_stop_writes in md_stop
+    - perf/x86/intel/uncore: Fix broken read_counter() for SNB IMC PMU
+    - scsi: storvsc: Remove WQ_MEM_RECLAIM from storvsc_error_wq
+    - mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()
+    - s390/mm: do not trigger write fault when vma does not allow VM_WRITE
+    - x86/bugs: Add "unknown" reporting for MMIO Stale Data
+    - kbuild: Fix include path in scripts/Makefile.modpost
+    - Bluetooth: L2CAP: Fix build errors in some archs
+    - HID: steam: Prevent NULL pointer dereference in steam_{recv,send}_report
+    - udmabuf: Set the DMA mask for the udmabuf device (v2)
+    - media: pvrusb2: fix memory leak in pvr_probe
+    - HID: hidraw: fix memory leak in hidraw_release()
+    - fbdev: fb_pm2fb: Avoid potential divide by zero error
+    - ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is
+      dead
+    - bpf: Don't redirect packets with invalid pkt_len
+    - mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
+    - btrfs: introduce btrfs_lookup_match_dir
+    - btrfs: do not pin logs too early during renames
+    - btrfs: unify lookup return value when dir entry is missing
+    - drm/amd/display: Avoid MPC infinite loop
+    - drm/amd/display: clear optc underflow before turn off odm clock
+    - neigh: fix possible DoS due to net iface start/stop loop
+    - s390/hypfs: avoid error message under KVM
+    - drm/amd/display: Fix pixel clock programming
+    - netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to y
+    - btrfs: tree-checker: check for overlapping extent items
+    - lib/vdso: Let do_coarse() return 0 to simplify the callsite
+    - lib/vdso: Mark do_hres() and do_coarse() as __always_inline
+    - kprobes: don't call disarm_kprobe() for disabled kprobes
+    - net/af_packet: check len when min_header_len equals to 0
+    - net: neigh: don't call kfree_skb() under spin_lock_irqsave()
+    - Linux 5.4.212
+
+  * Focal update: v5.4.211 upstream stable release (LP: #1990190)
+    - Makefile: link with -z noexecstack --no-warn-rwx-segments
+    - x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments
+    - scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"
+    - ALSA: bcd2000: Fix a UAF bug on the error path of probing
+    - igc: Remove _I_PHY_ID checking
+    - wifi: mac80211_hwsim: fix race condition in pending packet
+    - wifi: mac80211_hwsim: add back erroneously removed cast
+    - wifi: mac80211_hwsim: use 32-bit skb cookie
+    - add barriers to buffer_uptodate and set_buffer_uptodate
+    - HID: wacom: Only report rotation for art pen
+    - HID: wacom: Don't register pad_input for touch switch
+    - KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case
+    - KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case
+    - KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0
+    - KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value
+    - KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks
+    - KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP
+    - mm/mremap: hold the rmap lock in write mode when moving page table entries.
+    - ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model
+    - ALSA: hda/cirrus - support for iMac 12,1 model
+    - ALSA: hda/realtek: Add quirk for another Asus K42JZ model
+    - tty: vt: initialize unicode screen buffer
+    - vfs: Check the truncate maximum size in inode_newsize_ok()
+    - fs: Add missing umask strip in vfs_tmpfile
+    - thermal: sysfs: Fix cooling_device_stats_setup() error code path
+    - fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters
+    - usbnet: Fix linkwatch use-after-free on disconnect
+    - ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()
+    - parisc: Fix device names in /proc/iomem
+    - parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode
+    - drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error
+    - drm/nouveau: fix another off-by-one in nvbios_addr
+    - drm/amdgpu: Check BO's requested pinning domains against its
+      preferred_domains
+    - iio: light: isl29028: Fix the warning in isl29028_remove()
+    - fuse: limit nsec
+    - serial: mvebu-uart: uart2 error bits clearing
+    - md-raid10: fix KASAN warning
+    - ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()
+    - PCI: Add defines for normal and subtractive PCI bridges
+    - powerpc/fsl-pci: Fix Class Code of PCIe Root Port
+    - powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E
+    - powerpc/powernv: Avoid crashing if rng is NULL
+    - MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - coresight: Clear the connection field properly
+    - USB: HCD: Fix URB giveback issue in tasklet function
+    - ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC
+    - arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC
+    - netfilter: nf_tables: fix null deref due to zeroed list head
+    - epoll: autoremove wakers even more aggressively
+    - x86: Handle idle=nomwait cmdline properly for x86_idle
+    - arm64: Do not forget syscall when starting a new thread.
+    - arm64: fix oops in concurrently setting insn_emulation sysctls
+    - ext2: Add more validity checks for inode counts
+    - genirq: Don't return error on missing optional irq_request_resources()
+    - wait: Fix __wait_event_hrtimeout for RT/DL tasks
+    - ARM: dts: imx6ul: add missing properties for sram
+    - ARM: dts: imx6ul: change operating-points to uint32-matrix
+    - ARM: dts: imx6ul: fix csi node compatible
+    - ARM: dts: imx6ul: fix lcdif node compatible
+    - ARM: dts: imx6ul: fix qspi node compatible
+    - spi: synquacer: Add missing clk_disable_unprepare()
+    - ARM: OMAP2+: display: Fix refcount leak bug
+    - ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks
+    - ACPI: PM: save NVS memory for Lenovo G40-45
+    - ACPI: LPSS: Fix missing check in register_device_clock()
+    - arm64: dts: qcom: ipq8074: fix NAND node name
+    - arm64: dts: allwinner: a64: orangepi-win: Fix LED node name
+    - ARM: shmobile: rcar-gen2: Increase refcount for new reference
+    - PM: hibernate: defer device probing when resuming from hibernation
+    - selinux: Add boundary check in put_entry()
+    - spi: spi-rspi: Fix PIO fallback on RZ platforms
+    - ARM: findbit: fix overflowing offset
+    - meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init
+    - ARM: bcm: Fix refcount leak in bcm_kona_smc_init
+    - x86/pmem: Fix platform-device leak in error path
+    - ARM: dts: ast2500-evb: fix board compatible
+    - ARM: dts: ast2600-evb: fix board compatible
+    - soc: fsl: guts: machine variable might be unset
+    - ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg
+    - ARM: OMAP2+: Fix refcount leak in omapdss_init_of
+    - ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init
+    - cpufreq: zynq: Fix refcount leak in zynq_get_revision
+    - soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register
+    - ARM: dts: qcom: pm8841: add required thermal-sensor-cells
+    - bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()
+    - arm64: dts: mt7622: fix BPI-R64 WPS button
+    - erofs: avoid consecutive detection for Highmem memory
+    - blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created
+    - regulator: of: Fix refcount leak bug in of_get_regulation_constraints()
+    - nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()
+    - thermal/tools/tmon: Include pthread and time headers in tmon.h
+    - dm: return early from dm_pr_call() if DM device is suspended
+    - ath10k: do not enforce interrupt trigger type
+    - wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()
+    - drm/mipi-dbi: align max_chunk to 2 in spi_transfer
+    - drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()
+    - drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function
+    - drm: adv7511: override i2c address of cec before accessing it
+    - i2c: Fix a potential use after free
+    - media: tw686x: Register the irq at the end of probe
+    - wifi: iwlegacy: 4965: fix potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - drm: bridge: adv7511: Add check for mipi_dsi_driver_register
+    - drm/mcde: Fix refcount leak in mcde_dsi_bind
+    - media: hdpvr: fix error value returns in hdpvr_read
+    - drm/vc4: plane: Remove subpixel positioning check
+    - drm/vc4: plane: Fix margin calculations for the right/bottom edges
+    - drm/vc4: dsi: Correct DSI divider calculations
+    - crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE
+    - drm/rockchip: vop: Don't crash for invalid duplicate_state()
+    - drm/rockchip: Fix an error handling path rockchip_dp_probe()
+    - drm/mediatek: dpi: Remove output format of YUV
+    - drm/mediatek: dpi: Only enable dpi after the bridge is enabled
+    - drm: bridge: sii8620: fix possible off-by-one
+    - drm/msm/mdp5: Fix global state lock backoff
+    - crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq
+    - media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment
+    - mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()
+    - drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.
+    - tcp: make retransmitted SKB fit into the send window
+    - libbpf: Fix the name of a reused map
+    - selftests: timers: valid-adjtimex: build fix for newer toolchains
+    - selftests: timers: clocksource-switch: fix passing errors from child
+    - fs: check FMODE_LSEEK to control internal pipe splicing
+    - wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()
+    - wifi: p54: Fix an error handling path in p54spi_probe()
+    - wifi: p54: add missing parentheses in p54_flush()
+    - selftests/bpf: fix a test for snprintf() overflow
+    - can: pch_can: do not report txerr and rxerr during bus-off
+    - can: rcar_can: do not report txerr and rxerr during bus-off
+    - can: sja1000: do not report txerr and rxerr during bus-off
+    - can: hi311x: do not report txerr and rxerr during bus-off
+    - can: sun4i_can: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off
+    - can: usb_8dev: do not report txerr and rxerr during bus-off
+    - can: error: specify the values of data[5..7] of CAN error frames
+    - can: pch_can: pch_can_error(): initialize errc before using it
+    - Bluetooth: hci_intel: Add check for platform_driver_register
+    - i2c: cadence: Support PEC for SMBus block read
+    - i2c: mux-gpmux: Add of_node_put() when breaking out of loop
+    - wifi: wil6210: debugfs: fix uninitialized variable use in
+      `wil_write_file_wmi()`
+    - wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue
+    - wifi: libertas: Fix possible refcount leak in if_usb_probe()
+    - net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS
+    - crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of
+    - iavf: Fix max_rate limiting
+    - netdevsim: Avoid allocation warnings triggered from user space
+    - net: rose: fix netdev reference changes
+    - dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock
+    - clk: renesas: r9a06g032: Fix UART clkgrp bitsel
+    - mtd: maps: Fix refcount leak in of_flash_probe_versatile
+    - mtd: maps: Fix refcount leak in ap_flash_init
+    - mtd: rawnand: meson: Fix a potential double free issue
+    - HID: cp2112: prevent a buffer overflow in cp2112_xfer()
+    - mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release
+    - mtd: partitions: Fix refcount leak in parse_redboot_of
+    - mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path
+    - fpga: altera-pr-ip: fix unsigned comparison with less than zero
+    - usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe
+    - usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe
+    - usb: xhci: tegra: Fix error check
+    - clk: mediatek: reset: Fix written reset bit offset
+    - misc: rtsx: Fix an error handling path in rtsx_pci_probe()
+    - driver core: fix potential deadlock in __driver_attach
+    - clk: qcom: clk-krait: unlock spin after mux completion
+    - usb: host: xhci: use snprintf() in xhci_decode_trb()
+    - clk: qcom: ipq8074: fix NSS port frequency tables
+    - clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks
+    - clk: qcom: camcc-sdm845: Fix topology around titan_top power domain
+    - soundwire: bus_type: fix remove and shutdown support
+    - intel_th: Fix a resource leak in an error handling path
+    - intel_th: msu-sink: Potential dereference of null pointer
+    - intel_th: msu: Fix vmalloced buffers
+    - staging: rtl8192u: Fix sleep in atomic context bug in
+      dm_fsync_timer_callback
+    - mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch
+    - memstick/ms_block: Fix some incorrect memory allocation
+    - memstick/ms_block: Fix a memory leak
+    - mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R
+    - scsi: smartpqi: Fix DMA direction for RAID requests
+    - usb: gadget: udc: amd5536 depends on HAS_DMA
+    - RDMA/hns: Fix incorrect clearing of interrupt status register
+    - RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event
+    - RDMA/hfi1: fix potential memory leak in setup_base_ctxt()
+    - gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()
+    - mmc: cavium-octeon: Add of_node_put() when breaking out of loop
+    - mmc: cavium-thunderx: Add of_node_put() when breaking out of loop
+    - HID: alps: Declare U1_UNICORN_LEGACY support
+    - PCI: tegra194: Fix Root Port interrupt handling
+    - PCI: tegra194: Fix link up retry sequence
+    - USB: serial: fix tty-port initialized comments
+    - platform/olpc: Fix uninitialized data in debugfs write
+    - mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region
+    - RDMA/rxe: Fix error unwind in rxe_create_qp()
+    - null_blk: fix ida error handling in null_add_dev()
+    - jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()
+    - ext4: recover csum seed of tmp_inode after migrating to extents
+    - jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted
+    - opp: Fix error check in dev_pm_opp_attach_genpd()
+    - ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe
+    - ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe
+    - ASoC: codecs: da7210: add check for i2c_add_driver
+    - ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe
+    - serial: 8250_dw: Store LSR into lsr_saved_flags in dw8250_tx_wait_empty()
+    - ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV
+    - ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV
+    - profiling: fix shift too large makes kernel panic
+    - tty: n_gsm: fix non flow control frames during mux flow off
+    - tty: n_gsm: fix packet re-transmission without open control channel
+    - tty: n_gsm: fix race condition in gsmld_write()
+    - remoteproc: qcom: wcnss: Fix handling of IRQs
+    - vfio/ccw: Do not change FSM state in subchannel event
+    - tty: n_gsm: fix wrong T1 retry count handling
+    - tty: n_gsm: fix DM command
+    - tty: n_gsm: fix missing corner cases in gsmld_poll()
+    - iommu/exynos: Handle failed IOMMU device registration properly
+    - rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge
+    - kfifo: fix kfifo_to_user() return type
+    - mfd: t7l66xb: Drop platform disable callback
+    - mfd: max77620: Fix refcount leak in max77620_initialise_fps
+    - iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop
+    - s390/zcore: fix race when reading from hardware system area
+    - ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()
+    - fuse: Remove the control interface for virtio-fs
+    - ASoC: audio-graph-card: Add of_node_put() in fail path
+    - watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in
+      armada_37xx_wdt_probe()
+    - video: fbdev: amba-clcd: Fix refcount leak bugs
+    - video: fbdev: sis: fix typos in SiS_GetModeID()
+    - powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32
+    - powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and
+      alias
+    - powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader
+    - powerpc/xive: Fix refcount leak in xive_get_max_prio
+    - powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address
+    - perf symbol: Fail to read phdr workaround
+    - kprobes: Forbid probing on trampoline and BPF code areas
+    - powerpc/pci: Fix PHB numbering when using opal-phbid
+    - genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO
+    - scripts/faddr2line: Fix vmlinux detection on arm64
+    - x86/numa: Use cpumask_available instead of hardcoded NULL check
+    - video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()
+    - tools/thermal: Fix possible path truncations
+    - video: fbdev: vt8623fb: Check the size of screen before memset_io()
+    - video: fbdev: arkfb: Check the size of screen before memset_io()
+    - video: fbdev: s3fb: Check the size of screen before memset_io()
+    - scsi: zfcp: Fix missing auto port scan and thus missing target ports
+    - scsi: qla2xxx: Fix discovery issues in FC-AL topology
+    - scsi: qla2xxx: Turn off multi-queue for 8G adapters
+    - scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection
+    - x86/olpc: fix 'logical not is only applied to the left hand side'
+    - spmi: trace: fix stack-out-of-bound access in SPMI tracing functions
+    - kexec, KEYS, s390: Make use of built-in and secondary keyring for signature
+      verification
+    - tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH
+    - btrfs: reset block group chunk force if we have to wait
+    - ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
+    - ext4: make sure ext4_append() always allocates new block
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - ext4: update s_overhead_clusters in the superblock during an on-line resize
+    - ext4: fix extent status tree race in writeback error recovery path
+    - ext4: correct max_inline_xattr_value_size computing
+    - ext4: correct the misjudgment in ext4_iget_extra_inode
+    - intel_th: pci: Add Raptor Lake-S CPU support
+    - intel_th: pci: Add Raptor Lake-S PCH support
+    - intel_th: pci: Add Meteor Lake-P support
+    - dm raid: fix address sanitizer warning in raid_resume
+    - dm raid: fix address sanitizer warning in raid_status
+    - dm thin: fix use-after-free crash in dm_sm_register_threshold_callback
+    - dm writecache: set a default MAX_WRITEBACK_JOBS
+    - ACPI: CPPC: Do not prevent CPPC from working in the future
+    - timekeeping: contribute wall clock to rng on time change
+    - firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails
+    - iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)
+    - btrfs: reject log replay if there is unsupported RO compat flag
+    - KVM: Add infrastructure and macro to mark VM as bugged
+    - KVM: x86: Check lapic_in_kernel() before attempting to set a SynIC irq
+    - KVM: x86: Avoid theoretical NULL pointer dereference in
+      kvm_irq_delivery_to_apic_fast()
+    - tcp: fix over estimation in sk_forced_mem_schedule()
+    - scsi: sg: Allow waiting for commands to complete on removed device
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression
+    - net/9p: Initialize the iounit field during fid creation
+    - net_sched: cls_route: disallow handle of 0
+    - ALSA: info: Fix llseek return value when using callback
+    - rds: add missing barrier to release_refill
+    - ata: libata-eh: Add missing command name
+    - mmc: pxamci: Fix another error handling path in pxamci_probe()
+    - mmc: pxamci: Fix an error handling path in pxamci_probe()
+    - btrfs: fix lost error handling when looking up extended ref on log replay
+    - tracing: Have filter accept "common_cpu" to be consistent
+    - can: ems_usb: fix clang's -Wunaligned-access warning
+    - apparmor: fix quiet_denied for file rules
+    - apparmor: fix absroot causing audited secids to begin with =
+    - apparmor: Fix failed mount permission check error message
+    - apparmor: fix aa_label_asxprint return check
+    - apparmor: fix overlapping attachment computation
+    - apparmor: fix reference count leak in aa_pivotroot()
+    - apparmor: Fix memleak in aa_simple_write_to_buffer()
+    - Documentation: ACPI: EINJ: Fix obsolete example
+    - NFSv4.1: Don't decrease the value of seq_nr_highest_sent
+    - NFSv4.1: Handle NFS4ERR_DELAY replies to OP_SEQUENCE correctly
+    - NFSv4: Fix races in the legacy idmapper upcall
+    - NFSv4.1: RECLAIM_COMPLETE must handle EACCES
+    - NFSv4/pnfs: Fix a use-after-free bug in open
+    - can: mcp251x: Fix race condition on receive interrupt
+    - sunrpc: fix expiry of auth creds
+    - SUNRPC: Reinitialise the backchannel request buffers before reuse
+    - devlink: Fix use-after-free after a failed reload
+    - net: bgmac: Fix a BUG triggered by wrong bytes_compl
+    - pinctrl: nomadik: Fix refcount leak in nmk_pinctrl_dt_subnode_to_map
+    - pinctrl: qcom: msm8916: Allow CAMSS GP clocks to be muxed
+    - pinctrl: sunxi: Add I/O bias setting for H6 R-PIO
+    - ACPI: property: Return type of acpi_add_nondev_subnodes() should be bool
+    - geneve: do not use RT_TOS for IPv6 flowlabel
+    - plip: avoid rcu debug splat
+    - vsock: Fix memory leak in vsock_connect()
+    - vsock: Set socket state back to SS_UNCONNECTED in vsock_connect_timeout()
+    - dt-bindings: arm: qcom: fix MSM8916 MTP compatibles
+    - tools/vm/slabinfo: use alphabetic order when two values are equal
+    - tools build: Switch to new openssl API for test-libcrypto
+    - NTB: ntb_tool: uninitialized heap data in tool_fn_write()
+    - nfp: ethtool: fix the display error of `ethtool -m DEVNAME`
+    - xen/xenbus: fix return type in xenbus_file_read()
+    - atm: idt77252: fix use-after-free bugs caused by tst_timer
+    - dpaa2-eth: trace the allocated address instead of page struct
+    - tee: add overflow check in register_shm_helper()
+    - nios2: page fault et.al. are *not* restartable syscalls...
+    - nios2: don't leave NULLs in sys_call_table[]
+    - nios2: traced syscall does need to check the syscall number
+    - nios2: fix syscall restart checks
+    - nios2: restarts apply only to the first sigframe we build...
+    - nios2: add force_successful_syscall_return()
+    - iavf: Fix adminq error handling
+    - clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks
+    - netfilter: nf_tables: really skip inactive sets when allocating name
+    - powerpc/pci: Fix get_phb_number() locking
+    - net: dsa: mv88e6060: prevent crash on an unused port
+    - net: moxa: pass pdev instead of ndev to DMA functions
+    - net: dsa: microchip: ksz9477: fix fdb_dump last invalid entry
+    - ice: Ignore EEXIST when setting promisc mode
+    - i40e: Fix to stop tx_timeout recovery if GLOBR fails
+    - fec: Fix timer capture timing in `fec_ptp_enable_pps()`
+    - igb: Add lock to avoid data race
+    - gcc-plugins: Undefine LATENT_ENTROPY_PLUGIN when plugin disabled for a file
+    - locking/atomic: Make test_and_*_bit() ordered on failure
+    - drm/meson: Fix refcount bugs in meson_vpu_has_available_connectors()
+    - PCI: Add ACS quirk for Broadcom BCM5750x NICs
+    - usb: cdns3 fix use-after-free at workaround 2
+    - usb: gadget: uvc: call uvc uvcg_warn on completed status instead of
+      uvcg_info
+    - irqchip/tegra: Fix overflow implicit truncation warnings
+    - drm/meson: Fix overflow implicit truncation warnings
+    - usb: host: ohci-ppc-of: Fix refcount leak bug
+    - usb: renesas: Fix refcount leak bug
+    - vboxguest: Do not use devm for irq
+    - clk: qcom: ipq8074: dont disable gcc_sleep_clk_src
+    - scsi: lpfc: Prevent buffer overflow crashes in debugfs with malformed user
+      input
+    - gadgetfs: ep_io - wait until IRQ finishes
+    - cxl: Fix a memory leak in an error handling path
+    - PCI/ACPI: Guard ARM64-specific mcfg_quirks
+    - um: add "noreboot" command line option for PANIC_TIMEOUT=-1 setups
+    - selftests/kprobe: Do not test for GRP/ without event failures
+    - dmaengine: sprd: Cleanup in .remove() after pm_runtime_get_sync() failed
+    - nvmet-tcp: fix lockdep complaint on nvmet_tcp_wq flush during queue teardown
+    - drivers:md:fix a potential use-after-free bug
+    - ext4: avoid remove directory when directory is corrupted
+    - ext4: avoid resizing to a partial cluster size
+    - lib/list_debug.c: Detect uninitialized lists
+    - tty: serial: Fix refcount leak bug in ucc_uart.c
+    - vfio: Clear the caps->buf to NULL after free
+    - mips: cavium-octeon: Fix missing of_node_put() in octeon2_usb_clocks_start
+    - riscv: mmap with PROT_WRITE but no PROT_READ is invalid
+    - RISC-V: Add fast call path of crash_kexec()
+    - watchdog: export lockup_detector_reconfigure
+    - powerpc/32: Don't always pass -mcpu=powerpc to the compiler
+    - ALSA: core: Add async signal helpers
+    - ALSA: timer: Use deferred fasync helper
+    - f2fs: fix to avoid use f2fs_bug_on() in f2fs_new_node_page()
+    - smb3: check xattr value length earlier
+    - powerpc/64: Init jump labels before parse_early_param()
+    - video: fbdev: i740fb: Check the argument of i740_calc_vclk()
+    - MIPS: tlbex: Explicitly compare _PAGE_NO_EXEC against 0
+    - tracing/probes: Have kprobes and uprobes use $COMM too
+    - can: j1939: j1939_sk_queue_activate_next_locked(): replace WARN_ON_ONCE with
+      netdev_warn_once()
+    - can: j1939: j1939_session_destroy(): fix memory leak of skbs
+    - btrfs: only write the sectors in the vertical stripe which has data stripes
+    - btrfs: raid56: don't trust any cached sector in __raid56_parity_recover()
+    - Linux 5.4.211
+
+  * CVE-2022-3028
+    - af_key: Do not call xfrm_probe_algs in parallel
+
+  * CVE-2022-2978
+    - fs: fix UAF/GPF bug in nilfs_mdt_destroy
+
+  * CVE-2022-40768
+    - scsi: stex: Properly zero out the passthrough command structure
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 17 Oct 2022 17:19:41 +0200
+
+linux (5.4.0-131.147) focal; urgency=medium
+
+  * CVE-2022-2602
+    - SAUCE: io_uring/af_unix: defer registered files gc to io_uring release
+    - SAUCE: io_uring/af_unix: fix memleak during unix GC
+
+  * CVE-2022-41674
+    - SAUCE: wifi: cfg80211: fix u8 overflow in
+      cfg80211_update_notlisted_nontrans()
+    - SAUCE: wifi: cfg80211/mac80211: reject bad MBSSID elements
+    - SAUCE: wifi: cfg80211: ensure length byte is present before access
+    - SAUCE: wifi: mac80211_hwsim: avoid mac80211 warning on bad rate
+    - SAUCE: wifi: cfg80211: update hidden BSSes to avoid WARN_ON
+
+  * CVE-2022-42721
+    - SAUCE: wifi: cfg80211: avoid nontransmitted BSS list corruption
+
+  * CVE-2022-42720
+    - SAUCE: wifi: cfg80211: fix BSS refcounting bugs
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 14 Oct 2022 13:32:31 -0300
+
+linux (5.4.0-128.144) focal; urgency=medium
+
+  * focal/linux: 5.4.0-128.144 -proposed tracker (LP: #1990152)
+
+  * CVE-2022-3176
+    - io_uring: disable polling pollfree files
+
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809)
+    - selftests/net: test nexthop without gw
+
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809) // icmp_redirect.sh in ubuntu_kernel_selftests failed on
+    Jammy 5.15.0-49.55 (LP: #1990124)
+    - ip: fix triggering of 'icmp redirect'
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 20 Sep 2022 11:19:18 +0200
+
+linux (5.4.0-127.143) focal; urgency=medium
+
+  * focal/linux: 5.4.0-127.143 -proposed tracker (LP: #1989892)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.09.19)
+
+  * [UBUNTU 20.04] mlx5 driver crashes on accessing device attributes during
+    recovery (LP: #1987287)
+    - net/mlx5: Avoid processing commands before cmdif is ready
+
+  * Focal update: v5.4.210 upstream stable release (LP: #1989230)
+    - thermal: Fix NULL pointer dereferences in of_thermal_ functions
+    - ACPI: video: Force backlight native for some TongFang devices
+    - ACPI: video: Shortening quirk list by identifying Clevo by board_name only
+    - ACPI: APEI: Better fix to avoid spamming the console with old error logs
+    - bpf: Verifer, adjust_scalar_min_max_vals to always call update_reg_bounds()
+    - selftests/bpf: Extend verifier and bpf_sock tests for dst_port loads
+    - bpf: Test_verifier, #70 error message updates for 32-bit right shift
+    - KVM: Don't null dereference ops->destroy
+    - selftests: KVM: Handle compiler optimizations in ucall
+    - media: v4l2-mem2mem: Apply DST_QUEUE_OFF_BASE on MMAP buffers across ioctls
+    - macintosh/adb: fix oob read in do_adb_query() function
+    - x86/speculation: Add RSB VM Exit protections
+    - x86/speculation: Add LFENCE to RSB fill sequence
+    - Linux 5.4.210
+
+  * Focal update: v5.4.209 upstream stable release (LP: #1989228)
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
+    - ntfs: fix use-after-free in ntfs_ucsncmp()
+    - s390/archrandom: prevent CPACF trng invocations in interrupt context
+    - tcp: Fix data-races around sysctl_tcp_dsack.
+    - tcp: Fix a data-race around sysctl_tcp_app_win.
+    - tcp: Fix a data-race around sysctl_tcp_adv_win_scale.
+    - tcp: Fix a data-race around sysctl_tcp_frto.
+    - tcp: Fix a data-race around sysctl_tcp_nometrics_save.
+    - ice: check (DD | EOF) bits on Rx descriptor rather than (EOP | RS)
+    - ice: do not setup vlan for loopback VSI
+    - scsi: ufs: host: Hold reference returned by of_parse_phandle()
+    - tcp: Fix a data-race around sysctl_tcp_limit_output_bytes.
+    - tcp: Fix a data-race around sysctl_tcp_challenge_ack_limit.
+    - net: ping6: Fix memleak in ipv6_renew_options().
+    - ipv6/addrconf: fix a null-ptr-deref bug for ip6_ptr
+    - igmp: Fix data-races around sysctl_igmp_qrv.
+    - net: sungem_phy: Add of_node_put() for reference returned by of_get_parent()
+    - tcp: Fix a data-race around sysctl_tcp_min_tso_segs.
+    - tcp: Fix a data-race around sysctl_tcp_min_rtt_wlen.
+    - tcp: Fix a data-race around sysctl_tcp_autocorking.
+    - tcp: Fix a data-race around sysctl_tcp_invalid_ratelimit.
+    - Documentation: fix sctp_wmem in ip-sysctl.rst
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_delay_ns.
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_nr.
+    - i40e: Fix interface init with MSI interrupts (no MSI-X)
+    - sctp: fix sleep in atomic context bug in timer handlers
+    - virtio-net: fix the race between refill work and close
+    - perf symbol: Correct address for bss symbols
+    - sfc: disable softirqs for ptp TX
+    - sctp: leave the err path free in sctp_stream_init to sctp_stream_free
+    - ARM: crypto: comment out gcc warning that breaks clang builds
+    - mt7601u: add USB device ID for some versions of XiaoDu WiFi Dongle.
+    - scsi: core: Fix race between handling STS_RESOURCE and completion
+    - Linux 5.4.209
+
+  * Focal update: v5.4.208 upstream stable release (LP: #1988225)
+    - pinctrl: stm32: fix optional IRQ support to gpios
+    - riscv: add as-options for modules with assembly compontents
+    - mlxsw: spectrum_router: Fix IPv4 nexthop gateway indication
+    - lockdown: Fix kexec lockdown bypass with ima policy
+    - xen/gntdev: Ignore failure to unmap INVALID_GRANT_HANDLE
+    - PCI: hv: Fix multi-MSI to allow more than one MSI vector
+    - PCI: hv: Fix hv_arch_irq_unmask() for multi-MSI
+    - PCI: hv: Reuse existing IRTE allocation in compose_msi_msg()
+    - PCI: hv: Fix interrupt mapping for multi-MSI
+    - serial: mvebu-uart: correctly report configured baudrate value
+    - xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in
+      xfrm_bundle_lookup()
+    - power/reset: arm-versatile: Fix refcount leak in versatile_reboot_probe
+    - pinctrl: ralink: Check for null return of devm_kcalloc
+    - perf/core: Fix data race between perf_event_set_output() and
+      perf_mmap_close()
+    - igc: Reinstate IGC_REMOVED logic and implement it properly
+    - ip: Fix data-races around sysctl_ip_no_pmtu_disc.
+    - ip: Fix data-races around sysctl_ip_fwd_use_pmtu.
+    - ip: Fix data-races around sysctl_ip_nonlocal_bind.
+    - ip: Fix a data-race around sysctl_fwmark_reflect.
+    - tcp/dccp: Fix a data-race around sysctl_tcp_fwmark_accept.
+    - tcp: Fix data-races around sysctl_tcp_mtu_probing.
+    - tcp: Fix data-races around sysctl_tcp_base_mss.
+    - tcp: Fix data-races around sysctl_tcp_min_snd_mss.
+    - tcp: Fix a data-race around sysctl_tcp_mtu_probe_floor.
+    - tcp: Fix a data-race around sysctl_tcp_probe_threshold.
+    - tcp: Fix a data-race around sysctl_tcp_probe_interval.
+    - i2c: cadence: Change large transfer count reset logic to be unconditional
+    - net: stmmac: fix dma queue left shift overflow issue
+    - net/tls: Fix race in TLS device down flow
+    - igmp: Fix data-races around sysctl_igmp_llm_reports.
+    - igmp: Fix a data-race around sysctl_igmp_max_memberships.
+    - tcp: Fix data-races around sysctl_tcp_syncookies.
+    - tcp: Fix data-races around sysctl_tcp_reordering.
+    - tcp: Fix data-races around some timeout sysctl knobs.
+    - tcp: Fix a data-race around sysctl_tcp_notsent_lowat.
+    - tcp: Fix a data-race around sysctl_tcp_tw_reuse.
+    - tcp: Fix data-races around sysctl_max_syn_backlog.
+    - tcp: Fix data-races around sysctl_tcp_fastopen.
+    - iavf: Fix handling of dummy receive descriptors
+    - i40e: Fix erroneous adapter reinitialization during recovery process
+    - ixgbe: Add locking to prevent panic when setting sriov_numvfs to zero
+    - gpio: pca953x: only use single read/write for No AI mode
+    - be2net: Fix buffer overflow in be_get_module_eeprom
+    - ipv4: Fix a data-race around sysctl_fib_multipath_use_neigh.
+    - udp: Fix a data-race around sysctl_udp_l3mdev_accept.
+    - tcp: Fix data-races around sysctl knobs related to SYN option.
+    - tcp: Fix a data-race around sysctl_tcp_early_retrans.
+    - tcp: Fix data-races around sysctl_tcp_recovery.
+    - tcp: Fix a data-race around sysctl_tcp_thin_linear_timeouts.
+    - tcp: Fix data-races around sysctl_tcp_slow_start_after_idle.
+    - tcp: Fix a data-race around sysctl_tcp_retrans_collapse.
+    - tcp: Fix a data-race around sysctl_tcp_stdurg.
+    - tcp: Fix a data-race around sysctl_tcp_rfc1337.
+    - tcp: Fix data-races around sysctl_tcp_max_reordering.
+    - spi: bcm2835: bcm2835_spi_handle_err(): fix NULL pointer deref for non DMA
+      transfers
+    - mm/mempolicy: fix uninit-value in mpol_rebind_policy()
+    - bpf: Make sure mac_header was set before using it
+    - dlm: fix pending remove if msg allocation fails
+    - ima: remove the IMA_TEMPLATE Kconfig option
+    - [Config] updateconfigs for IMA_TEMPLATE
+    - locking/refcount: Define constants for saturation and max refcount values
+    - locking/refcount: Ensure integer operands are treated as signed
+    - locking/refcount: Remove unused refcount_*_checked() variants
+    - locking/refcount: Move the bulk of the REFCOUNT_FULL implementation into the
+      <linux/refcount.h> header
+    - locking/refcount: Improve performance of generic REFCOUNT_FULL code
+    - locking/refcount: Move saturation warnings out of line
+    - locking/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
+    - locking/refcount: Consolidate implementations of refcount_t
+    - [Config] updateconfigs for REFCOUNT_FULL
+    - x86: get rid of small constant size cases in raw_copy_{to,from}_user()
+    - x86/uaccess: Implement macros for CMPXCHG on user addresses
+    - mmap locking API: initial implementation as rwsem wrappers
+    - x86/mce: Deduplicate exception handling
+    - bitfield.h: Fix "type of reg too small for mask" test
+    - ALSA: memalloc: Align buffer allocations in page size
+    - Bluetooth: Add bt_skb_sendmsg helper
+    - Bluetooth: Add bt_skb_sendmmsg helper
+    - Bluetooth: SCO: Replace use of memcpy_from_msg with bt_skb_sendmsg
+    - Bluetooth: RFCOMM: Replace use of memcpy_from_msg with bt_skb_sendmmsg
+    - Bluetooth: Fix passing NULL to PTR_ERR
+    - Bluetooth: SCO: Fix sco_send_frame returning skb->len
+    - Bluetooth: Fix bt_skb_sendmmsg not allocating partial chunks
+    - tty: drivers/tty/, stop using tty_schedule_flip()
+    - tty: the rest, stop using tty_schedule_flip()
+    - tty: drop tty_schedule_flip()
+    - tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
+    - tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
+    - x86: drop bogus "cc" clobber from __try_cmpxchg_user_asm()
+    - Linux 5.4.208
+
+  * Focal update: v5.4.207 upstream stable release (LP: #1988219)
+    - ALSA: hda - Add fixup for Dell Latitidue E5430
+    - ALSA: hda/conexant: Apply quirk for another HP ProDesk 600 G3 model
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc221
+    - ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop
+    - xen/netback: avoid entering xenvif_rx_next_skb() with an empty rx queue
+    - tracing/histograms: Fix memory leak problem
+    - net: sock: tracing: Fix sock_exceed_buf_limit not to dereference stale
+      pointer
+    - ip: fix dflt addr selection for connected nexthop
+    - ARM: 9213/1: Print message about disabled Spectre workarounds only once
+    - ARM: 9214/1: alignment: advance IT state after emulating Thumb instruction
+    - wifi: mac80211: fix queue selection for mesh/OCB interfaces
+    - cgroup: Use separate src/dst nodes when preloading css_sets for migration
+    - drm/panfrost: Fix shrinker list corruption by madvise IOCTL
+    - nilfs2: fix incorrect masking of permission flags for symlinks
+    - Revert "evm: Fix memleak in init_desc"
+    - sched/rt: Disable RT_RUNTIME_SHARE by default
+    - ext4: fix race condition between ext4_write and ext4_convert_inline_data
+    - ARM: dts: imx6qdl-ts7970: Fix ngpio typo and count
+    - ARM: 9209/1: Spectre-BHB: avoid pr_info() every time a CPU comes out of idle
+    - ARM: 9210/1: Mark the FDT_FIXED sections as shareable
+    - drm/i915: fix a possible refcount leak in intel_dp_add_mst_connector()
+    - ima: Fix a potential integer overflow in ima_appraise_measurement
+    - ASoC: sgtl5000: Fix noise on shutdown/remove
+    - net: stmmac: dwc-qos: Disable split header for Tegra194
+    - inetpeer: Fix data-races around sysctl.
+    - net: Fix data-races around sysctl_mem.
+    - cipso: Fix data-races around sysctl.
+    - icmp: Fix data-races around sysctl.
+    - ipv4: Fix a data-race around sysctl_fib_sync_mem.
+    - ARM: dts: at91: sama5d2: Fix typo in i2s1 node
+    - ARM: dts: sunxi: Fix SPI NOR campatible on Orange Pi Zero
+    - drm/i915/gt: Serialize TLB invalidates with GT resets
+    - icmp: Fix a data-race around sysctl_icmp_ratelimit.
+    - icmp: Fix a data-race around sysctl_icmp_ratemask.
+    - raw: Fix a data-race around sysctl_raw_l3mdev_accept.
+    - ipv4: Fix data-races around sysctl_ip_dynaddr.
+    - net: ftgmac100: Hold reference returned by of_get_child_by_name()
+    - sfc: fix use after free when disabling sriov
+    - seg6: fix skb checksum evaluation in SRH encapsulation/insertion
+    - seg6: fix skb checksum in SRv6 End.B6 and End.B6.Encaps behaviors
+    - seg6: bpf: fix skb checksum in bpf_push_seg6_encap()
+    - sfc: fix kernel panic when creating VF
+    - mm: sysctl: fix missing numa_stat when !CONFIG_HUGETLB_PAGE
+    - virtio_mmio: Add missing PM calls to freeze/restore
+    - virtio_mmio: Restore guest page size on resume
+    - netfilter: br_netfilter: do not skip all hooks with 0 priority
+    - cpufreq: pmac32-cpufreq: Fix refcount leak bug
+    - platform/x86: hp-wmi: Ignore Sanitization Mode event
+    - net: tipc: fix possible refcount leak in tipc_sk_create()
+    - NFC: nxp-nci: don't print header length mismatch on i2c error
+    - nvme: fix regression when disconnect a recovering ctrl
+    - net: sfp: fix memory leak in sfp_probe()
+    - ASoC: ops: Fix off by one in range control validation
+    - ASoC: wm5110: Fix DRE control
+    - ASoC: cs47l15: Fix event generation for low power mux control
+    - ASoC: madera: Fix event generation for OUT1 demux
+    - ASoC: madera: Fix event generation for rate controls
+    - irqchip: or1k-pic: Undefine mask_ack for level triggered hardware
+    - x86: Clear .brk area at early boot
+    - soc: ixp4xx/npe: Fix unused match warning
+    - ARM: dts: stm32: use the correct clock source for CEC on stm32mp151
+    - signal handling: don't use BUG_ON() for debugging
+    - USB: serial: ftdi_sio: add Belimo device ids
+    - usb: typec: add missing uevent when partner support PD
+    - usb: dwc3: gadget: Fix event pending check
+    - tty: serial: samsung_tty: set dma burst_size to 1
+    - serial: 8250: fix return error code in serial8250_request_std_resource()
+    - serial: stm32: Clear prev values before setting RTS delays
+    - serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle
+    - can: m_can: m_can_tx_handler(): fix use after free of skb
+    - Linux 5.4.207
+
+  * Focal update: v5.4.206 upstream stable release (LP: #1988215)
+    - Linux 5.4.206
+
+  * Focal update: v5.4.205 upstream stable release (LP: #1988214)
+    - esp: limit skb_page_frag_refill use to a single page
+    - mm/slub: add missing TID updates on slab deactivation
+    - can: bcm: use call_rcu() instead of costly synchronize_rcu()
+    - can: grcan: grcan_probe(): remove extra of_node_get()
+    - can: gs_usb: gs_usb_open/close(): fix memory leak
+    - usbnet: fix memory leak in error case
+    - net: rose: fix UAF bug caused by rose_t0timer_expiry
+    - iommu/vt-d: Fix PCI bus rescan device hot add
+    - fbdev: fbmem: Fix logo center image dx issue
+    - video: of_display_timing.h: include errno.h
+    - powerpc/powernv: delay rng platform device creation until later in boot
+    - can: kvaser_usb: replace run-time checks with struct kvaser_usb_driver_info
+    - can: kvaser_usb: kvaser_usb_leaf: fix CAN clock frequency regression
+    - can: kvaser_usb: kvaser_usb_leaf: fix bittiming limits
+    - xfs: remove incorrect ASSERT in xfs_rename
+    - ARM: meson: Fix refcount leak in meson_smp_prepare_cpus
+    - pinctrl: sunxi: a83t: Fix NAND function name for some pins
+    - pinctrl: sunxi: sunxi_pconf_set: use correct offset
+    - ARM: at91: pm: use proper compatible for sama5d2's rtc
+    - ARM: at91: pm: use proper compatibles for sam9x60's rtc and rtt
+    - ibmvnic: Properly dispose of all skbs during a failover.
+    - selftests: forwarding: fix flood_unicast_test when h2 supports
+      IFF_UNICAST_FLT
+    - selftests: forwarding: fix learning_test when h1 supports IFF_UNICAST_FLT
+    - selftests: forwarding: fix error message in learning_test
+    - i2c: cadence: Unregister the clk notifier in error path
+    - dmaengine: imx-sdma: Allow imx8m for imx7 FW revs
+    - misc: rtsx_usb: fix use of dma mapped buffer for usb bulk transfer
+    - misc: rtsx_usb: use separate command and response buffers
+    - misc: rtsx_usb: set return value in rsp_buf alloc err path
+    - dt-bindings: dma: allwinner,sun50i-a64-dma: Fix min/max typo
+    - ida: don't use BUG_ON() for debugging
+    - dmaengine: pl330: Fix lockdep warning about non-static key
+    - dmaengine: at_xdma: handle errors of at_xdmac_alloc_desc() correctly
+    - dmaengine: ti: Fix refcount leak in ti_dra7_xbar_route_allocate
+    - dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate
+    - Linux 5.4.205
+
+  * Focal update: v5.4.204 upstream stable release (LP: #1988212)
+    - ipv6: take care of disable_policy when restoring routes
+    - nvdimm: Fix badblocks clear off-by-one error
+    - powerpc/prom_init: Fix kernel config grep
+    - powerpc/bpf: Fix use of user_pt_regs in uapi
+    - dm raid: fix accesses beyond end of raid member array
+    - dm raid: fix KASAN warning in raid5_add_disks
+    - s390/archrandom: simplify back to earlier design and initialize earlier
+    - SUNRPC: Fix READ_PLUS crasher
+    - net: rose: fix UAF bugs caused by timer handler
+    - net: usb: ax88179_178a: Fix packet receiving
+    - virtio-net: fix race between ndo_open() and virtio_device_ready()
+    - selftests/net: pass ipv6_args to udpgso_bench's IPv6 TCP test
+    - net: tun: unlink NAPI from device on destruction
+    - net: tun: stop NAPI when detaching queues
+    - RDMA/qedr: Fix reporting QP timeout attribute
+    - linux/dim: Fix divide by 0 in RDMA DIM
+    - usbnet: fix memory allocation in helpers
+    - net: ipv6: unexport __init-annotated seg6_hmac_net_init()
+    - caif_virtio: fix race between virtio_device_ready() and ndo_open()
+    - PM / devfreq: exynos-ppmu: Fix refcount leak in of_get_devfreq_events
+    - s390: remove unneeded 'select BUILD_BIN2C'
+    - netfilter: nft_dynset: restore set element counter when failing to update
+    - net/sched: act_api: Notify user space if any actions were flushed before
+      error
+    - net: bonding: fix possible NULL deref in rlb code
+    - net: bonding: fix use-after-free after 802.3ad slave unbind
+    - nfc: nfcmrvl: Fix irq_of_parse_and_map() return value
+    - NFC: nxp-nci: Don't issue a zero length i2c_master_read()
+    - net: tun: avoid disabling NAPI twice
+    - xen/gntdev: Avoid blocking in unmap_grant_pages()
+    - hwmon: (ibmaem) don't call platform_device_del() if platform_device_add()
+      fails
+    - net: dsa: bcm_sf2: force pause link settings
+    - sit: use min
+    - ipv6/sit: fix ipip6_tunnel_get_prl return value
+    - rseq/selftests,x86_64: Add rseq_offset_deref_addv()
+    - selftests/rseq: remove ARRAY_SIZE define from individual tests
+    - selftests/rseq: introduce own copy of rseq uapi header
+    - selftests/rseq: Remove useless assignment to cpu variable
+    - selftests/rseq: Remove volatile from __rseq_abi
+    - selftests/rseq: Introduce rseq_get_abi() helper
+    - selftests/rseq: Introduce thread pointer getters
+    - selftests/rseq: Uplift rseq selftests for compatibility with glibc-2.35
+    - selftests/rseq: Fix ppc32: wrong rseq_cs 32-bit field pointer on big endian
+    - selftests/rseq: Fix ppc32 missing instruction selection "u" and "x" for
+      load/store
+    - selftests/rseq: Fix ppc32 offsets by using long rather than off_t
+    - selftests/rseq: Fix warnings about #if checks of undefined tokens
+    - selftests/rseq: Remove arm/mips asm goto compiler work-around
+    - selftests/rseq: Fix: work-around asm goto compiler bugs
+    - selftests/rseq: x86-64: use %fs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: x86-32: use %gs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: Change type of rseq_offset to ptrdiff_t
+    - xen/blkfront: fix leaking data in shared pages
+    - xen/netfront: fix leaking data in shared pages
+    - xen/netfront: force data bouncing when backend is untrusted
+    - xen/blkfront: force data bouncing when backend is untrusted
+    - xen/arm: Fix race in RB-tree based P2M accounting
+    - net: usb: qmi_wwan: add Telit 0x1060 composition
+    - net: usb: qmi_wwan: add Telit 0x1070 composition
+    - clocksource/drivers/ixp4xx: remove EXPORT_SYMBOL_GPL from
+      ixp4xx_timer_setup()
+    - Linux 5.4.204
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 16 Sep 2022 11:05:09 +0200
+
+linux (5.4.0-126.142) focal; urgency=medium
+
+  * focal/linux: 5.4.0-126.142 -proposed tracker (LP: #1987819)
+
+  * [SRU] fnic driver on needs to be updated to 1.6.0.53 on Focal (LP: #1984011)
+    - scsi: fnic: Change shost_printk() to FNIC_FCS_DBG()
+    - scsi: fnic: Avoid looping in TRANS ETH on unload
+    - scsi: fnic: Change shost_printk() to FNIC_MAIN_DBG()
+    - scsi: fnic: Set scsi_set_resid() only for underflow
+    - scsi: fnic: Validate io_req before others
+
+  * Focal update: v5.4.203 upstream stable release (LP: #1986999)
+    - drm: remove drm_fb_helper_modinit
+    - powerpc/ftrace: Remove ftrace init tramp once kernel init is complete
+    - kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add]
+    - net: mscc: ocelot: allow unregistered IP multicast flooding
+    - ARM: 8989/1: use .fpu assembler directives instead of assembler arguments
+    - ARM: 8990/1: use VFP assembler mnemonics in register load/store macros
+    - ARM: 8971/1: replace the sole use of a symbol with its definition
+    - crypto: arm/sha256-neon - avoid ADRL pseudo instruction
+    - crypto: arm/sha512-neon - avoid ADRL pseudo instruction
+    - ARM: 8933/1: replace Sun/Solaris style flag on section directive
+    - ARM: 8929/1: use APSR_nzcv instead of r15 as mrc operand
+    - ARM: OMAP2+: drop unnecessary adrl
+    - ARM: 9029/1: Make iwmmxt.S support Clang's integrated assembler
+    - crypto: arm - use Kconfig based compiler checks for crypto opcodes
+    - crypto: arm/ghash-ce - define fpu before fpu registers are referenced
+    - Linux 5.4.203
+
+  * Focal update: v5.4.202 upstream stable release (LP: #1986995)
+    - random: schedule mix_interrupt_randomness() less often
+    - ALSA: hda/via: Fix missing beep setup
+    - ALSA: hda/conexant: Fix missing beep setup
+    - ALSA: hda/realtek - ALC897 headset MIC no sound
+    - ALSA: hda/realtek: Add quirk for Clevo PD70PNT
+    - net: openvswitch: fix parsing of nw_proto for IPv6 fragments
+    - mmc: sdhci-pci-o2micro: Fix card detect by dealing with debouncing
+    - ata: libata: add qc->flags in ata_qc_complete_template tracepoint
+    - dm era: commit metadata in postsuspend after worker stops
+    - dm mirror log: clear log bits up to BITS_PER_LONG boundary
+    - random: quiet urandom warning ratelimit suppression message
+    - USB: serial: option: add Telit LE910Cx 0x1250 composition
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: option: add Quectel RM500K module support
+    - bpf: Fix request_sock leak in sk lookup helpers
+    - phy: aquantia: Fix AN when higher speeds than 1G are not advertised
+    - bonding: ARP monitor spams NETDEV_NOTIFY_PEERS notifiers
+    - net/sched: sch_netem: Fix arithmetic in netem_dump() for 32-bit platforms
+    - drm/msm/mdp4: Fix refcount leak in mdp4_modeset_init_intf
+    - erspan: do not assume transport header is always set
+    - net/tls: fix tls_sk_proto_close executed repeatedly
+    - udmabuf: add back sanity check
+    - x86/xen: Remove undefined behavior in setup_features()
+    - MIPS: Remove repetitive increase irq_err_count
+    - afs: Fix dynamic root getattr
+    - ice: ethtool: advertise 1000M speeds properly
+    - regmap-irq: Fix a bug in regmap_irq_enable() for type_in_mask chips
+    - igb: Make DMA faster when CPU is active on the PCIe link
+    - virtio_net: fix xdp_rxq_info bug after suspend/resume
+    - Revert "net/tls: fix tls_sk_proto_close executed repeatedly"
+    - gpio: winbond: Fix error code in winbond_gpio_get()
+    - s390/cpumf: Handle events cycles and instructions identical
+    - iio: adc: vf610: fix conversion mode sysfs node name
+    - xhci: turn off port power in shutdown
+    - usb: chipidea: udc: check request status before setting device address
+    - iio:chemical:ccs811: rearrange iio trigger get and register
+    - iio:accel:bma180: rearrange iio trigger get and register
+    - iio:accel:mxc4005: rearrange iio trigger get and register
+    - iio: accel: mma8452: ignore the return value of reset operation
+    - iio: gyro: mpu3050: Fix the error handling in mpu3050_power_up()
+    - iio: trigger: sysfs: fix use-after-free on remove
+    - iio: adc: stm32: fix maximum clock rate for stm32mp15x
+    - iio: adc: axp288: Override TS pin bias current for some models
+    - xtensa: xtfpga: Fix refcount leak bug in setup
+    - xtensa: Fix refcount leak bug in time.c
+    - parisc: Enable ARCH_HAS_STRICT_MODULE_RWX
+    - powerpc: Enable execve syscall exit tracepoint
+    - powerpc/rtas: Allow ibm,platform-dump RTAS call with null buffer address
+    - powerpc/powernv: wire up rng during setup_arch
+    - ARM: dts: imx6qdl: correct PU regulator ramp delay
+    - ARM: exynos: Fix refcount leak in exynos_map_pmu
+    - soc: bcm: brcmstb: pm: pm-arm: Fix refcount leak in brcmstb_pm_probe
+    - ARM: Fix refcount leak in axxia_boot_secondary
+    - ARM: cns3xxx: Fix refcount leak in cns3xxx_init
+    - modpost: fix section mismatch check for exported init/exit sections
+    - random: update comment from copy_to_user() -> copy_to_iter()
+    - kbuild: link vmlinux only once for CONFIG_TRIM_UNUSED_KSYMS (2nd attempt)
+    - powerpc/pseries: wire up rng during setup_arch()
+    - Linux 5.4.202
+
+  * Focal update: v5.4.201 upstream stable release (LP: #1986993)
+    - dm: remove special-casing of bio-based immutable singleton target on NVMe
+    - usb: gadget: u_ether: fix regression in setting fixed MAC address
+    - tcp: add some entropy in __inet_hash_connect()
+    - tcp: use different parts of the port_offset for index and offset
+    - tcp: add small random increments to the source port
+    - tcp: dynamically allocate the perturb table used by source ports
+    - tcp: increase source port perturb table to 2^16
+    - tcp: drop the hash_32() part from the index calculation
+    - arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer
+    - Linux 5.4.201
+
+  * Focal update: v5.4.200 upstream stable release (LP: #1983152)
+    - Revert "UBUNTU: SAUCE: random: Make getrandom() ready earlier"
+    - 9p: missing chunk of "fs/9p: Don't update file type when updating file
+      attributes"
+    - bpf: Fix incorrect memory charge cost calculation in stack_map_alloc()
+    - nfc: st21nfca: fix incorrect sizing calculations in EVT_TRANSACTION
+    - crypto: blake2s - generic C library implementation and selftest
+    - lib/crypto: blake2s: move hmac construction into wireguard
+    - lib/crypto: sha1: re-roll loops to reduce code size
+    - compat_ioctl: remove /dev/random commands
+    - random: don't forget compat_ioctl on urandom
+    - random: Don't wake crng_init_wait when crng_init == 1
+    - random: Add a urandom_read_nowait() for random APIs that don't warn
+    - random: add GRND_INSECURE to return best-effort non-cryptographic bytes
+    - random: ignore GRND_RANDOM in getentropy(2)
+    - random: make /dev/random be almost like /dev/urandom
+    - random: remove the blocking pool
+    - random: delete code to pull data into pools
+    - random: remove kernel.random.read_wakeup_threshold
+    - random: remove unnecessary unlikely()
+    - random: convert to ENTROPY_BITS for better code readability
+    - random: Add and use pr_fmt()
+    - random: fix typo in add_timer_randomness()
+    - random: remove some dead code of poolinfo
+    - random: split primary/secondary crng init paths
+    - random: avoid warnings for !CONFIG_NUMA builds
+    - x86: Remove arch_has_random, arch_has_random_seed
+    - powerpc: Remove arch_has_random, arch_has_random_seed
+    - s390: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Use false with bool
+    - linux/random.h: Mark CONFIG_ARCH_RANDOM functions __must_check
+    - powerpc: Use bool in archrandom.h
+    - random: add arch_get_random_*long_early()
+    - random: avoid arch_get_random_seed_long() when collecting IRQ randomness
+    - random: remove dead code left over from blocking pool
+    - MAINTAINERS: co-maintain random.c
+    - crypto: blake2s - include <linux/bug.h> instead of <asm/bug.h>
+    - crypto: blake2s - adjust include guard naming
+    - random: document add_hwgenerator_randomness() with other input functions
+    - random: remove unused irq_flags argument from add_interrupt_randomness()
+    - random: use BLAKE2s instead of SHA1 in extraction
+    - random: do not sign extend bytes for rotation when mixing
+    - random: do not re-init if crng_reseed completes before primary init
+    - random: mix bootloader randomness into pool
+    - random: harmonize "crng init done" messages
+    - random: use IS_ENABLED(CONFIG_NUMA) instead of ifdefs
+    - random: initialize ChaCha20 constants with correct endianness
+    - random: early initialization of ChaCha constants
+    - random: avoid superfluous call to RDRAND in CRNG extraction
+    - random: don't reset crng_init_cnt on urandom_read()
+    - random: fix typo in comments
+    - random: cleanup poolinfo abstraction
+    - random: cleanup integer types
+    - random: remove incomplete last_data logic
+    - random: remove unused extract_entropy() reserved argument
+    - random: rather than entropy_store abstraction, use global
+    - random: remove unused OUTPUT_POOL constants
+    - random: de-duplicate INPUT_POOL constants
+    - random: prepend remaining pool constants with POOL_
+    - random: cleanup fractional entropy shift constants
+    - random: access input_pool_data directly rather than through pointer
+    - random: selectively clang-format where it makes sense
+    - random: simplify arithmetic function flow in account()
+    - random: continually use hwgenerator randomness
+    - random: access primary_pool directly rather than through pointer
+    - random: only call crng_finalize_init() for primary_crng
+    - random: use computational hash for entropy extraction
+    - random: simplify entropy debiting
+    - random: use linear min-entropy accumulation crediting
+    - random: always wake up entropy writers after extraction
+    - random: make credit_entropy_bits() always safe
+    - random: remove use_input_pool parameter from crng_reseed()
+    - random: remove batched entropy locking
+    - random: fix locking in crng_fast_load()
+    - random: use RDSEED instead of RDRAND in entropy extraction
+    - random: get rid of secondary crngs
+    - random: inline leaves of rand_initialize()
+    - random: ensure early RDSEED goes through mixer on init
+    - random: do not xor RDRAND when writing into /dev/random
+    - random: absorb fast pool into input pool after fast load
+    - random: use simpler fast key erasure flow on per-cpu keys
+    - random: use hash function for crng_slow_load()
+    - random: make more consistent use of integer types
+    - random: remove outdated INT_MAX >> 6 check in urandom_read()
+    - random: zero buffer after reading entropy from userspace
+    - random: fix locking for crng_init in crng_reseed()
+    - random: tie batched entropy generation to base_crng generation
+    - random: remove ifdef'd out interrupt bench
+    - random: remove unused tracepoints
+    - random: add proper SPDX header
+    - random: deobfuscate irq u32/u64 contributions
+    - random: introduce drain_entropy() helper to declutter crng_reseed()
+    - random: remove useless header comment
+    - random: remove whitespace and reorder includes
+    - random: group initialization wait functions
+    - random: group crng functions
+    - random: group entropy extraction functions
+    - random: group entropy collection functions
+    - random: group userspace read/write functions
+    - random: group sysctl functions
+    - random: rewrite header introductory comment
+    - random: defer fast pool mixing to worker
+    - random: do not take pool spinlock at boot
+    - random: unify early init crng load accounting
+    - random: check for crng_init == 0 in add_device_randomness()
+    - random: pull add_hwgenerator_randomness() declaration into random.h
+    - random: clear fast pool, crng, and batches in cpuhp bring up
+    - random: round-robin registers as ulong, not u32
+    - random: only wake up writers after zap if threshold was passed
+    - random: cleanup UUID handling
+    - random: unify cycles_t and jiffies usage and types
+    - random: do crng pre-init loading in worker rather than irq
+    - random: give sysctl_random_min_urandom_seed a more sensible value
+    - random: don't let 644 read-only sysctls be written to
+    - random: replace custom notifier chain with standard one
+    - random: use SipHash as interrupt entropy accumulator
+    - random: make consistent usage of crng_ready()
+    - random: reseed more often immediately after booting
+    - random: check for signal and try earlier when generating entropy
+    - random: skip fast_init if hwrng provides large chunk of entropy
+    - random: treat bootloader trust toggle the same way as cpu trust toggle
+    - random: re-add removed comment about get_random_{u32,u64} reseeding
+    - random: mix build-time latent entropy into pool at init
+    - random: do not split fast init input in add_hwgenerator_randomness()
+    - random: do not allow user to keep crng key around on stack
+    - random: check for signal_pending() outside of need_resched() check
+    - random: check for signals every PAGE_SIZE chunk of /dev/[u]random
+    - random: allow partial reads if later user copies fail
+    - random: make random_get_entropy() return an unsigned long
+    - random: document crng_fast_key_erasure() destination possibility
+    - random: fix sysctl documentation nits
+    - init: call time_init() before rand_initialize()
+    - ia64: define get_cycles macro for arch-override
+    - s390: define get_cycles macro for arch-override
+    - parisc: define get_cycles macro for arch-override
+    - alpha: define get_cycles macro for arch-override
+    - powerpc: define get_cycles macro for arch-override
+    - timekeeping: Add raw clock fallback for random_get_entropy()
+    - m68k: use fallback for random_get_entropy() instead of zero
+    - mips: use fallback for random_get_entropy() instead of just c0 random
+    - arm: use fallback for random_get_entropy() instead of zero
+    - nios2: use fallback for random_get_entropy() instead of zero
+    - x86/tsc: Use fallback for random_get_entropy() instead of zero
+    - um: use fallback for random_get_entropy() instead of zero
+    - sparc: use fallback for random_get_entropy() instead of zero
+    - xtensa: use fallback for random_get_entropy() instead of zero
+    - random: insist on random_get_entropy() existing in order to simplify
+    - random: do not use batches when !crng_ready()
+    - random: use first 128 bits of input as fast init
+    - random: do not pretend to handle premature next security model
+    - random: order timer entropy functions below interrupt functions
+    - random: do not use input pool from hard IRQs
+    - random: help compiler out with fast_mix() by using simpler arguments
+    - siphash: use one source of truth for siphash permutations
+    - random: use symbolic constants for crng_init states
+    - random: avoid initializing twice in credit race
+    - random: move initialization out of reseeding hot path
+    - random: remove ratelimiting for in-kernel unseeded randomness
+    - random: use proper jiffies comparison macro
+    - random: handle latent entropy and command line from random_init()
+    - random: credit architectural init the exact amount
+    - random: use static branch for crng_ready()
+    - random: remove extern from functions in header
+    - random: use proper return types on get_random_{int,long}_wait()
+    - random: make consistent use of buf and len
+    - random: move initialization functions out of hot pages
+    - random: move randomize_page() into mm where it belongs
+    - random: unify batched entropy implementations
+    - random: convert to using fops->read_iter()
+    - random: convert to using fops->write_iter()
+    - random: wire up fops->splice_{read,write}_iter()
+    - random: check for signals after page of pool writes
+    - Revert "random: use static branch for crng_ready()"
+    - crypto: drbg - always seeded with SP800-90B compliant noise source
+    - crypto: drbg - prepare for more fine-grained tracking of seeding state
+    - crypto: drbg - track whether DRBG was seeded with !rng_is_initialized()
+    - crypto: drbg - move dynamic ->reseed_threshold adjustments to __drbg_seed()
+    - crypto: drbg - always try to free Jitter RNG instance
+    - crypto: drbg - make reseeding from get_random_bytes() synchronous
+    - random: avoid checking crng_ready() twice in random_init()
+    - random: mark bootloader randomness code as __init
+    - random: account for arch randomness in bits
+    - powerpc/kasan: Silence KASAN warnings in __get_wchan()
+    - ASoC: nau8822: Add operation for internal PLL off and on
+    - dma-debug: make things less spammy under memory pressure
+    - ASoC: cs42l52: Fix TLV scales for mixer controls
+    - ASoC: cs35l36: Update digital volume TLV
+    - ASoC: cs53l30: Correct number of volume levels on SX controls
+    - ASoC: cs42l52: Correct TLV for Bypass Volume
+    - ASoC: cs42l56: Correct typo in minimum level for SX volume controls
+    - ata: libata-core: fix NULL pointer deref in ata_host_alloc_pinfo()
+    - ASoC: wm8962: Fix suspend while playing music
+    - ASoC: es8328: Fix event generation for deemphasis control
+    - ASoC: wm_adsp: Fix event generation for wm_adsp_fw_put()
+    - scsi: vmw_pvscsi: Expand vcpuHint to 16 bits
+    - scsi: lpfc: Fix port stuck in bypassed state after LIP in PT2PT topology
+    - scsi: lpfc: Allow reduced polling rate for nvme_admin_async_event cmd
+      completion
+    - scsi: ipr: Fix missing/incorrect resource cleanup in error case
+    - scsi: pmcraid: Fix missing resource cleanup in error case
+    - ALSA: hda/realtek - Add HW8326 support
+    - virtio-mmio: fix missing put_device() when vm_cmdline_parent registration
+      failed
+    - nfc: nfcmrvl: Fix memory leak in nfcmrvl_play_deferred
+    - ipv6: Fix signed integer overflow in l2tp_ip6_sendmsg
+    - net: ethernet: mtk_eth_soc: fix misuse of mem alloc interface
+      netdev[napi]_alloc_frag
+    - random: credit cpu and bootloader seeds by default
+    - pNFS: Don't keep retrying if the server replied NFS4ERR_LAYOUTUNAVAILABLE
+    - clocksource: hyper-v: unexport __init-annotated hv_init_clocksource()
+    - i40e: Fix adding ADQ filter to TC0
+    - i40e: Fix calculating the number of queue pairs
+    - i40e: Fix call trace in setup_tx_descriptors
+    - tty: goldfish: Fix free_irq() on remove
+    - misc: atmel-ssc: Fix IRQ check in ssc_probe
+    - mlxsw: spectrum_cnt: Reorder counter pools
+    - net: bgmac: Fix an erroneous kfree() in bgmac_remove()
+    - arm64: ftrace: fix branch range checks
+    - certs/blacklist_hashes.c: fix const confusion in certs blacklist
+    - faddr2line: Fix overlapping text section failures, the sequel
+    - irqchip/gic/realview: Fix refcount leak in realview_gic_of_init
+    - irqchip/gic-v3: Fix error handling in gic_populate_ppi_partitions
+    - irqchip/gic-v3: Fix refcount leak in gic_populate_ppi_partitions
+    - i2c: designware: Use standard optional ref clock implementation
+    - comedi: vmk80xx: fix expression for tx buffer size
+    - USB: serial: option: add support for Cinterion MV31 with new baseline
+    - USB: serial: io_ti: add Agilent E5805A support
+    - usb: dwc2: Fix memory leak in dwc2_hcd_init
+    - usb: gadget: lpc32xx_udc: Fix refcount leak in lpc32xx_udc_probe
+    - serial: 8250: Store to lsr_save_flags after lsr read
+    - dm mirror log: round up region bitmap size to BITS_PER_LONG
+    - ext4: fix bug_on ext4_mb_use_inode_pa
+    - ext4: make variable "count" signed
+    - ext4: add reserved GDT blocks check
+    - ALSA: hda/realtek: fix right sounds and mute/micmute LEDs for HP machine
+    - virtio-pci: Remove wrong address verification in vp_del_vqs()
+    - net/sched: act_police: more accurate MTU policing
+    - net: openvswitch: fix leak of nested actions
+    - arm64: kprobes: Use BRK instead of single-step when executing instructions
+      out-of-line
+    - RISC-V: fix barrier() use in <vdso/processor.h>
+    - riscv: Less inefficient gcc tishift helpers (and export their symbols)
+    - powerpc/mm: Switch obsolete dssall to .long
+    - Linux 5.4.200
+
+  * Focal update: v5.4.199 upstream stable release (LP: #1983150)
+    - Linux 5.4.199
+
+  * Focal update: v5.4.198 upstream stable release (LP: #1982409)
+    - binfmt_flat: do not stop relocating GOT entries prematurely on riscv
+    - ALSA: hda/realtek - Fix microphone noise on ASUS TUF B550M-PLUS
+    - USB: serial: option: add Quectel BG95 modem
+    - USB: new quirk for Dell Gen 2 devices
+    - perf/x86/intel: Fix event constraints for ICL
+    - ptrace/um: Replace PT_DTRACE with TIF_SINGLESTEP
+    - ptrace/xtensa: Replace PT_SINGLESTEP with TIF_SINGLESTEP
+    - ptrace: Reimplement PTRACE_KILL by always sending SIGKILL
+    - btrfs: add "0x" prefix for unsupported optional features
+    - btrfs: repair super block num_devices automatically
+    - drm/virtio: fix NULL pointer dereference in virtio_gpu_conn_get_modes
+    - mwifiex: add mutex lock for call in mwifiex_dfs_chan_sw_work_queue
+    - b43legacy: Fix assigning negative value to unsigned variable
+    - b43: Fix assigning negative value to unsigned variable
+    - ipw2x00: Fix potential NULL dereference in libipw_xmit()
+    - ipv6: fix locking issues with loops over idev->addr_list
+    - fbcon: Consistently protect deferred_takeover with console_lock()
+    - ACPICA: Avoid cache flush inside virtual machines
+    - drm/komeda: return early if drm_universal_plane_init() fails.
+    - ALSA: jack: Access input_dev under mutex
+    - spi: spi-rspi: Remove setting {src,dst}_{addr,addr_width} based on DMA
+      direction
+    - tools/power turbostat: fix ICX DRAM power numbers
+    - drm/amd/pm: fix double free in si_parse_power_table()
+    - ath9k: fix QCA9561 PA bias level
+    - media: venus: hfi: avoid null dereference in deinit
+    - media: pci: cx23885: Fix the error handling in cx23885_initdev()
+    - media: cx25821: Fix the warning when removing the module
+    - md/bitmap: don't set sb values if can't pass sanity check
+    - mmc: jz4740: Apply DMA engine limits to maximum segment size
+    - scsi: megaraid: Fix error check return value of register_chrdev()
+    - drm/plane: Move range check for format_count earlier
+    - drm/amd/pm: fix the compile warning
+    - arm64: compat: Do not treat syscall number as ESR_ELx for a bad syscall
+    - drm: msm: fix error check return value of irq_of_parse_and_map()
+    - ipv6: Don't send rs packets to the interface of ARPHRD_TUNNEL
+    - net/mlx5: fs, delete the FTE when there are no rules attached to it
+    - ASoC: dapm: Don't fold register value changes into notifications
+    - mlxsw: spectrum_dcb: Do not warn about priority changes
+    - drm/amdgpu/ucode: Remove firmware load type check in amdgpu_ucode_free_bo
+    - HID: bigben: fix slab-out-of-bounds Write in bigben_probe
+    - ASoC: tscs454: Add endianness flag in snd_soc_component_driver
+    - s390/preempt: disable __preempt_count_add() optimization for
+      PROFILE_ALL_BRANCHES
+    - spi: stm32-qspi: Fix wait_cmd timeout in APM mode
+    - dma-debug: change allocation mode from GFP_NOWAIT to GFP_ATIOMIC
+    - ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default
+    - ipmi:ssif: Check for NULL msg when handling events and messages
+    - ipmi: Fix pr_fmt to avoid compilation issues
+    - rtlwifi: Use pr_warn instead of WARN_ONCE
+    - media: coda: limit frame interval enumeration to supported encoder frame
+      sizes
+    - media: cec-adap.c: fix is_configuring state
+    - openrisc: start CPU timer early in boot
+    - nvme-pci: fix a NULL pointer dereference in nvme_alloc_admin_tags
+    - ASoC: rt5645: Fix errorenous cleanup order
+    - nbd: Fix hung on disconnect request if socket is closed before
+    - net: phy: micrel: Allow probing without .driver_data
+    - media: exynos4-is: Fix compile warning
+    - ASoC: max98357a: remove dependency on GPIOLIB
+    - rxrpc: Return an error to sendmsg if call failed
+    - eth: tg3: silence the GCC 12 array-bounds warning
+    - selftests/bpf: fix btf_dump/btf_dump due to recent clang change
+    - IB/rdmavt: add missing locks in rvt_ruc_loopback
+    - ARM: dts: ox820: align interrupt controller node name with dtschema
+    - PM / devfreq: rk3399_dmc: Disable edev on remove()
+    - fs: jfs: fix possible NULL pointer dereference in dbFree()
+    - ARM: OMAP1: clock: Fix UART rate reporting algorithm
+    - powerpc/fadump: Fix fadump to work with a different endian capture kernel
+    - fat: add ratelimit to fat*_ent_bread()
+    - ARM: versatile: Add missing of_node_put in dcscb_init
+    - ARM: dts: exynos: add atmel,24c128 fallback to Samsung EEPROM
+    - ARM: hisi: Add missing of_node_put after of_find_compatible_node
+    - PCI: Avoid pci_dev_lock() AB/BA deadlock with sriov_numvfs_store()
+    - tracing: incorrect isolate_mote_t cast in mm_vmscan_lru_isolate
+    - powerpc/xics: fix refcount leak in icp_opal_init()
+    - powerpc/powernv: fix missing of_node_put in uv_init()
+    - macintosh/via-pmu: Fix build failure when CONFIG_INPUT is disabled
+    - powerpc/iommu: Add missing of_node_put in iommu_init_early_dart
+    - RDMA/hfi1: Prevent panic when SDMA is disabled
+    - drm: fix EDID struct for old ARM OABI format
+    - ath9k: fix ar9003_get_eepmisc
+    - drm/edid: fix invalid EDID extension block filtering
+    - drm/bridge: adv7511: clean up CEC adapter when probe fails
+    - ASoC: mediatek: Fix error handling in mt8173_max98090_dev_probe
+    - ASoC: mediatek: Fix missing of_node_put in mt2701_wm8960_machine_probe
+    - x86/delay: Fix the wrong asm constraint in delay_loop()
+    - drm/mediatek: Fix mtk_cec_mask()
+    - drm/vc4: txp: Don't set TXP_VSTART_AT_EOF
+    - drm/vc4: txp: Force alpha to be 0xff if it's disabled
+    - bpf: Fix excessive memory allocation in stack_map_alloc()
+    - nl80211: show SSID for P2P_GO interfaces
+    - drm/komeda: Fix an undefined behavior bug in komeda_plane_add()
+    - drm: mali-dp: potential dereference of null pointer
+    - spi: spi-ti-qspi: Fix return value handling of wait_for_completion_timeout
+    - NFC: NULL out the dev->rfkill to prevent UAF
+    - efi: Add missing prototype for efi_capsule_setup_info
+    - drbd: fix duplicate array initializer
+    - HID: hid-led: fix maximum brightness for Dream Cheeky
+    - HID: elan: Fix potential double free in elan_input_configured
+    - drm/bridge: Fix error handling in analogix_dp_probe
+    - sched/fair: Fix cfs_rq_clock_pelt() for throttled cfs_rq
+    - spi: img-spfi: Fix pm_runtime_get_sync() error checking
+    - cpufreq: Fix possible race in cpufreq online error path
+    - ath9k_htc: fix potential out of bounds access with invalid
+      rxstatus->rs_keyix
+    - inotify: show inotify mask flags in proc fdinfo
+    - fsnotify: fix wrong lockdep annotations
+    - of: overlay: do not break notify on NOTIFY_{OK|STOP}
+    - scsi: ufs: core: Exclude UECxx from SFR dump list
+    - x86/pm: Fix false positive kmemleak report in msr_build_context()
+    - x86/speculation: Add missing prototype for unpriv_ebpf_notify()
+    - ASoC: rk3328: fix disabling mclk on pclk probe failure
+    - perf tools: Add missing headers needed by util/data.h
+    - drm/msm/disp/dpu1: set vbif hw config to NULL to avoid use after memory free
+      during pm runtime resume
+    - drm/msm/dsi: fix error checks and return values for DSI xmit functions
+    - drm/msm/hdmi: check return value after calling
+      platform_get_resource_byname()
+    - drm/msm/hdmi: fix error check return value of irq_of_parse_and_map()
+    - drm/rockchip: vop: fix possible null-ptr-deref in vop_bind()
+    - virtio_blk: fix the discard_granularity and discard_alignment queue limits
+    - x86: Fix return value of __setup handlers
+    - irqchip/exiu: Fix acknowledgment of edge triggered interrupts
+    - irqchip/aspeed-i2c-ic: Fix irq_of_parse_and_map() return value
+    - x86/mm: Cleanup the control_va_addr_alignment() __setup handler
+    - regulator: core: Fix enable_count imbalance with EXCLUSIVE_GET
+    - drm/msm/mdp5: Return error code in mdp5_pipe_release when deadlock is
+      detected
+    - drm/msm/mdp5: Return error code in mdp5_mixer_release when deadlock is
+      detected
+    - drm/msm: return an error pointer in msm_gem_prime_get_sg_table()
+    - media: uvcvideo: Fix missing check to determine if element is found in list
+    - iomap: iomap_write_failed fix
+    - Revert "cpufreq: Fix possible race in cpufreq online error path"
+    - perf/amd/ibs: Use interrupt regs ip for stack unwinding
+    - ASoC: fsl: Fix refcount leak in imx_sgtl5000_probe
+    - ASoC: mxs-saif: Fix refcount leak in mxs_saif_probe
+    - regulator: pfuze100: Fix refcount leak in pfuze_parse_regulators_dt
+    - scripts/faddr2line: Fix overlapping text section failures
+    - media: aspeed: Fix an error handling path in aspeed_video_probe()
+    - media: st-delta: Fix PM disable depth imbalance in delta_probe
+    - media: exynos4-is: Change clk_disable to clk_disable_unprepare
+    - media: pvrusb2: fix array-index-out-of-bounds in pvr2_i2c_core_init
+    - media: vsp1: Fix offset calculation for plane cropping
+    - Bluetooth: fix dangling sco_conn and use-after-free in sco_sock_timeout
+    - m68k: math-emu: Fix dependencies of math emulation support
+    - sctp: read sk->sk_bound_dev_if once in sctp_rcv()
+    - media: ov7670: remove ov7670_power_off from ov7670_remove
+    - ext4: reject the 'commit' option on ext2 filesystems
+    - drm/msm/a6xx: Fix refcount leak in a6xx_gpu_init
+    - drm: msm: fix possible memory leak in mdp5_crtc_cursor_set()
+    - thermal/drivers/broadcom: Fix potential NULL dereference in sr_thermal_probe
+    - ASoC: wm2000: fix missing clk_disable_unprepare() on error in
+      wm2000_anc_transition()
+    - NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx
+    - rxrpc: Fix listen() setting the bar too high for the prealloc rings
+    - rxrpc: Don't try to resend the request if we're receiving the reply
+    - rxrpc: Fix overlapping ACK accounting
+    - rxrpc: Don't let ack.previousPacket regress
+    - rxrpc: Fix decision on when to generate an IDLE ACK
+    - net/smc: postpone sk_refcnt increment in connect()
+    - arm64: dts: rockchip: Move drive-impedance-ohm to emmc phy on rk3399
+    - ARM: dts: suniv: F1C100: fix watchdog compatible
+    - soc: qcom: smp2p: Fix missing of_node_put() in smp2p_parse_ipc
+    - soc: qcom: smsm: Fix missing of_node_put() in smsm_parse_ipc
+    - PCI: cadence: Fix find_first_zero_bit() limit
+    - PCI: rockchip: Fix find_first_zero_bit() limit
+    - KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry
+    - can: xilinx_can: mark bit timing constants as const
+    - ARM: dts: bcm2835-rpi-zero-w: Fix GPIO line name for Wifi/BT
+    - ARM: dts: bcm2837-rpi-cm3-io3: Fix GPIO line names for SMPS I2C
+    - ARM: dts: bcm2837-rpi-3-b-plus: Fix GPIO line name of power LED
+    - ARM: dts: bcm2835-rpi-b: Fix GPIO line names
+    - misc: ocxl: fix possible double free in ocxl_file_register_afu
+    - crypto: marvell/cesa - ECB does not IV
+    - arm: mediatek: select arch timer for mt7629
+    - powerpc/fadump: fix PT_LOAD segment for boot memory area
+    - mfd: ipaq-micro: Fix error check return value of platform_get_irq()
+    - scsi: fcoe: Fix Wstringop-overflow warnings in fcoe_wwn_from_mac()
+    - firmware: arm_scmi: Fix list protocols enumeration in the base protocol
+    - nvdimm: Allow overwrite in the presence of disabled dimms
+    - pinctrl: mvebu: Fix irq_of_parse_and_map() return value
+    - drivers/base/node.c: fix compaction sysfs file leak
+    - dax: fix cache flush on PMD-mapped pages
+    - powerpc/8xx: export 'cpm_setbrg' for modules
+    - powerpc/idle: Fix return value of __setup() handler
+    - powerpc/4xx/cpm: Fix return value of __setup() handler
+    - proc: fix dentry/inode overinstantiating under /proc/${pid}/net
+    - ipc/mqueue: use get_tree_nodev() in mqueue_get_tree()
+    - PCI: imx6: Fix PERST# start-up sequence
+    - tty: fix deadlock caused by calling printk() under tty_port->lock
+    - crypto: cryptd - Protect per-CPU resource by disabling BH.
+    - Input: sparcspkr - fix refcount leak in bbc_beep_probe
+    - powerpc/64: Only WARN if __pa()/__va() called with bad addresses
+    - powerpc/perf: Fix the threshold compare group constraint for power9
+    - macintosh: via-pmu and via-cuda need RTC_LIB
+    - powerpc/fsl_rio: Fix refcount leak in fsl_rio_setup
+    - mfd: davinci_voicecodec: Fix possible null-ptr-deref davinci_vc_probe()
+    - mailbox: forward the hrtimer if not queued and under a lock
+    - RDMA/hfi1: Prevent use of lock before it is initialized
+    - Input: stmfts - do not leave device disabled in stmfts_input_open
+    - f2fs: fix dereference of stale list iterator after loop body
+    - iommu/mediatek: Add list_del in mtk_iommu_remove
+    - i2c: at91: use dma safe buffers
+    - i2c: at91: Initialize dma_buf in at91_twi_xfer()
+    - NFS: Do not report EINTR/ERESTARTSYS as mapping errors
+    - NFS: Do not report flush errors in nfs_write_end()
+    - NFS: Don't report errors from nfs_pageio_complete() more than once
+    - NFSv4/pNFS: Do not fail I/O when we fail to allocate the pNFS layout
+    - video: fbdev: clcdfb: Fix refcount leak in clcdfb_of_vram_setup
+    - dmaengine: stm32-mdma: remove GISR1 register
+    - iommu/amd: Increase timeout waiting for GA log enablement
+    - perf c2c: Use stdio interface if slang is not supported
+    - perf jevents: Fix event syntax error caused by ExtSel
+    - f2fs: fix to avoid f2fs_bug_on() in dec_valid_node_count()
+    - f2fs: fix to do sanity check on block address in f2fs_do_zero_range()
+    - f2fs: fix to clear dirty inode in f2fs_evict_inode()
+    - f2fs: fix deadloop in foreground GC
+    - f2fs: don't need inode lock for system hidden quota
+    - f2fs: fix fallocate to use file_modified to update permissions consistently
+    - wifi: mac80211: fix use-after-free in chanctx code
+    - iwlwifi: mvm: fix assert 1F04 upon reconfig
+    - fs-writeback: writeback_sb_inodes：Recalculate 'wrote' according skipped
+      pages
+    - efi: Do not import certificates from UEFI Secure Boot for T2 Macs
+    - bfq: Split shared queues on move between cgroups
+    - bfq: Update cgroup information before merging bio
+    - bfq: Track whether bfq_group is still online
+    - ext4: fix use-after-free in ext4_rename_dir_prepare
+    - ext4: fix warning in ext4_handle_inode_extension
+    - ext4: fix bug_on in ext4_writepages
+    - ext4: verify dir block before splitting it
+    - ext4: avoid cycles in directory h-tree
+    - ACPI: property: Release subnode properties with data nodes
+    - tracing: Fix potential double free in create_var_ref()
+    - PCI/PM: Fix bridge_d3_blacklist[] Elo i2 overwrite of Gigabyte X299
+    - PCI: qcom: Fix runtime PM imbalance on probe errors
+    - PCI: qcom: Fix unbalanced PHY init on probe errors
+    - mm, compaction: fast_find_migrateblock() should return pfn in the target
+      zone
+    - dlm: fix plock invalid read
+    - dlm: fix missing lkb refcount handling
+    - ocfs2: dlmfs: fix error handling of user_dlm_destroy_lock
+    - scsi: dc395x: Fix a missing check on list iterator
+    - scsi: ufs: qcom: Add a readl() to make sure ref_clk gets enabled
+    - drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
+    - drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
+    - drm/nouveau/clk: Fix an incorrect NULL check on list iterator
+    - drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
+    - md: fix an incorrect NULL check in does_sb_need_changing
+    - md: fix an incorrect NULL check in md_reload_sb
+    - mtd: cfi_cmdset_0002: Move and rename
+      chip_check/chip_ready/chip_good_for_write
+    - media: coda: Fix reported H264 profile
+    - media: coda: Add more H264 levels for CODA960
+    - Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
+    - RDMA/hfi1: Fix potential integer multiplication overflow errors
+    - irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375,
+      A38x, A39x
+    - irqchip: irq-xtensa-mx: fix initial IRQ affinity
+    - mac80211: upgrade passive scan to active scan on DFS channels after beacon
+      rx
+    - um: chan_user: Fix winch_tramp() return value
+    - um: Fix out-of-bounds read in LDT setup
+    - iommu/msm: Fix an incorrect NULL check on list iterator
+    - nodemask.h: fix compilation error with GCC12
+    - hugetlb: fix huge_pmd_unshare address update
+    - rtl818x: Prevent using not initialized queues
+    - ASoC: rt5514: Fix event generation for "DSP Voice Wake Up" control
+    - carl9170: tx: fix an incorrect use of list iterator
+    - serial: pch: don't overwrite xmit->buf[0] by x_char
+    - tilcdc: tilcdc_external: fix an incorrect NULL check on list iterator
+    - gma500: fix an incorrect NULL check on list iterator
+    - arm64: dts: qcom: ipq8074: fix the sleep clock frequency
+    - phy: qcom-qmp: fix struct clk leak on probe errors
+    - ARM: pxa: maybe fix gpio lookup tables
+    - docs/conf.py: Cope with removal of language=None in Sphinx 5.0.0
+    - dt-bindings: gpio: altera: correct interrupt-cells
+    - blk-iolatency: Fix inflight count imbalances and IO hangs on offline
+    - phy: qcom-qmp: fix reset-controller leak on probe errors
+    - Kconfig: add config option for asm goto w/ outputs
+    - RDMA/rxe: Generate a completion for unsupported/invalid opcode
+    - MIPS: IP27: Remove incorrect `cpu_has_fpu' override
+    - bfq: Avoid merging queues with different parents
+    - bfq: Drop pointless unlock-lock pair
+    - bfq: Remove pointless bfq_init_rq() calls
+    - bfq: Get rid of __bio_blkcg() usage
+    - bfq: Make sure bfqg for which we are queueing requests is online
+    - block: fix bio_clone_blkg_association() to associate with proper blkcg_gq
+    - md: bcache: check the return value of kzalloc() in detached_dev_do_request()
+    - pcmcia: db1xxx_ss: restrict to MIPS_DB1XXX boards
+    - staging: greybus: codecs: fix type confusion of list iterator variable
+    - iio: adc: ad7124: Remove shift from scan_type
+    - tty: goldfish: Use tty_port_destroy() to destroy port
+    - tty: serial: owl: Fix missing clk_disable_unprepare() in owl_uart_probe
+    - tty: serial: fsl_lpuart: fix potential bug when using both of_alias_get_id
+      and ida_simple_get
+    - usb: usbip: fix a refcount leak in stub_probe()
+    - usb: usbip: add missing device lock on tweak configuration cmd
+    - USB: storage: karma: fix rio_karma_init return
+    - usb: musb: Fix missing of_node_put() in omap2430_probe
+    - staging: fieldbus: Fix the error handling path in
+      anybuss_host_common_probe()
+    - pwm: lp3943: Fix duty calculation in case period was clamped
+    - rpmsg: qcom_smd: Fix irq_of_parse_and_map() return value
+    - usb: dwc3: pci: Fix pm_runtime_get_sync() error checking
+    - firmware: stratix10-svc: fix a missing check on list iterator
+    - iio: adc: stmpe-adc: Fix wait_for_completion_timeout return value check
+    - iio: adc: sc27xx: fix read big scale voltage not right
+    - iio: adc: sc27xx: Fine tune the scale calibration values
+    - rpmsg: qcom_smd: Fix returning 0 if irq_of_parse_and_map() fails
+    - phy: qcom-qmp: fix pipe-clock imbalance on power-on failure
+    - serial: sifive: Report actual baud base rather than fixed 115200
+    - coresight: cpu-debug: Replace mutex with mutex_trylock on panic notifier
+    - soc: rockchip: Fix refcount leak in rockchip_grf_init
+    - clocksource/drivers/riscv: Events are stopped during CPU suspend
+    - rtc: mt6397: check return value after calling platform_get_resource()
+    - serial: meson: acquire port->lock in startup()
+    - serial: 8250_fintek: Check SER_RS485_RTS_* only with RS485
+    - serial: digicolor-usart: Don't allow CS5-6
+    - serial: rda-uart: Don't allow CS5-6
+    - serial: txx9: Don't allow CS5-6
+    - serial: sh-sci: Don't allow CS5-6
+    - serial: sifive: Sanitize CSIZE and c_iflag
+    - serial: st-asc: Sanitize CSIZE and correct PARENB for CS7
+    - serial: stm32-usart: Correct CSIZE, bits, and parity
+    - firmware: dmi-sysfs: Fix memory leak in dmi_sysfs_register_handle
+    - bus: ti-sysc: Fix warnings for unbind for serial
+    - driver: base: fix UAF when driver_attach failed
+    - driver core: fix deadlock in __device_attach
+    - watchdog: ts4800_wdt: Fix refcount leak in ts4800_wdt_probe
+    - ASoC: fsl_sai: Fix FSL_SAI_xDR/xFR definition
+    - clocksource/drivers/oxnas-rps: Fix irq_of_parse_and_map() return value
+    - s390/crypto: fix scatterwalk_unmap() callers in AES-GCM
+    - net: sched: fixed barrier to prevent skbuff sticking in qdisc backlog
+    - net: ethernet: mtk_eth_soc: out of bounds read in mtk_hwlro_get_fdir_entry()
+    - net: dsa: mv88e6xxx: Fix refcount leak in mv88e6xxx_mdios_register
+    - modpost: fix removing numeric suffixes
+    - jffs2: fix memory leak in jffs2_do_fill_super
+    - ubi: ubi_create_volume: Fix use-after-free when volume creation failed
+    - nfp: only report pause frame configuration for physical device
+    - net/mlx5: Don't use already freed action pointer
+    - net/mlx5e: Update netdev features after changing XDP state
+    - net: sched: add barrier to fix packet stuck problem for lockless qdisc
+    - tcp: tcp_rtx_synack() can be called from process context
+    - afs: Fix infinite loop found by xfstest generic/676
+    - tipc: check attribute length for bearer name
+    - perf c2c: Fix sorting in percent_rmt_hitm_cmp()
+    - mips: cpc: Fix refcount leak in mips_cpc_default_phys_base
+    - tracing: Fix sleeping function called from invalid context on RT kernel
+    - tracing: Avoid adding tracer option before update_tracer_options
+    - f2fs: remove WARN_ON in f2fs_is_valid_blkaddr
+    - i2c: cadence: Increase timeout per message if necessary
+    - m68knommu: set ZERO_PAGE() to the allocated zeroed page
+    - m68knommu: fix undefined reference to `_init_sp'
+    - dmaengine: zynqmp_dma: In struct zynqmp_dma_chan fix desc_size data type
+    - NFSv4: Don't hold the layoutget locks across multiple RPC calls
+    - video: fbdev: pxa3xx-gcu: release the resources correctly in
+      pxa3xx_gcu_probe/remove()
+    - xprtrdma: treat all calls not a bcall when bc_serv is NULL
+    - netfilter: nat: really support inet nat without l3 address
+    - ata: pata_octeon_cf: Fix refcount leak in octeon_cf_probe
+    - netfilter: nf_tables: memleak flow rule from commit path
+    - xen: unexport __init-annotated xen_xlate_map_ballooned_pages()
+    - af_unix: Fix a data-race in unix_dgram_peer_wake_me().
+    - bpf, arm64: Clear prog->jited_len along prog->jited
+    - net: dsa: lantiq_gswip: Fix refcount leak in gswip_gphy_fw_list
+    - net/mlx4_en: Fix wrong return value on ioctl EEPROM query failure
+    - SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
+    - net: mdio: unexport __init-annotated mdio_bus_init()
+    - net: xfrm: unexport __init-annotated xfrm4_protocol_init()
+    - net: ipv6: unexport __init-annotated seg6_hmac_init()
+    - net/mlx5: Rearm the FW tracer after each tracer event
+    - net/mlx5: fs, fail conflicting actions
+    - ip_gre: test csum_start instead of transport header
+    - net: altera: Fix refcount leak in altera_tse_mdio_create
+    - drm: imx: fix compiler warning with gcc-12
+    - iio: dummy: iio_simple_dummy: check the return value of kstrdup()
+    - iio: st_sensors: Add a local lock for protecting odr
+    - lkdtm/usercopy: Expand size of "out of frame" object
+    - tty: synclink_gt: Fix null-pointer-dereference in slgt_clean()
+    - tty: Fix a possible resource leak in icom_probe
+    - drivers: staging: rtl8192u: Fix deadlock in ieee80211_beacons_stop()
+    - drivers: staging: rtl8192e: Fix deadlock in rtllib_beacons_stop()
+    - USB: host: isp116x: check return value after calling platform_get_resource()
+    - drivers: tty: serial: Fix deadlock in sa1100_set_termios()
+    - drivers: usb: host: Fix deadlock in oxu_bus_suspend()
+    - USB: hcd-pci: Fully suspend across freeze/thaw cycle
+    - usb: dwc2: gadget: don't reset gadget's driver->bus
+    - misc: rtsx: set NULL intfdata when probe fails
+    - extcon: Modify extcon device to be created after driver data is set
+    - clocksource/drivers/sp804: Avoid error on multiple instances
+    - staging: rtl8712: fix uninit-value in usb_read8() and friends
+    - staging: rtl8712: fix uninit-value in r871xu_drv_init()
+    - serial: msm_serial: disable interrupts in __msm_console_write()
+    - kernfs: Separate kernfs_pr_cont_buf and rename_lock.
+    - watchdog: wdat_wdt: Stop watchdog when rebooting the system
+    - md: protect md_unregister_thread from reentrancy
+    - scsi: myrb: Fix up null pointer access on myrb_cleanup()
+    - ceph: allow ceph.dir.rctime xattr to be updatable
+    - drm/radeon: fix a possible null pointer dereference
+    - modpost: fix undefined behavior of is_arm_mapping_symbol()
+    - x86/cpu: Elide KCSAN for cpu_has() and friends
+    - nbd: call genl_unregister_family() first in nbd_cleanup()
+    - nbd: fix race between nbd_alloc_config() and module removal
+    - cifs: version operations for smb20 unneeded when legacy support disabled
+    - nodemask: Fix return values to be unsigned
+    - vringh: Fix loop descriptors check in the indirect cases
+    - scripts/gdb: change kernel config dumping method
+    - ALSA: hda/conexant - Fix loopback issue with CX20632
+    - cifs: return errors during session setup during reconnects
+    - ata: libata-transport: fix {dma|pio|xfer}_mode sysfs files
+    - mmc: block: Fix CQE recovery reset success
+    - nfc: st21nfca: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st21nfca: fix memory leaks in EVT_TRANSACTION handling
+    - ixgbe: fix bcast packets Rx on VF after promisc removal
+    - ixgbe: fix unexpected VLAN Rx in promisc mode on VF
+    - Input: bcm5974 - set missing URB_NO_TRANSFER_DMA_MAP urb flag
+    - powerpc/32: Fix overread/overwrite of thread_struct via ptrace
+    - md/raid0: Ignore RAID0 layout if the second zone has only one device
+    - mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
+    - tcp: fix tcp_mtup_probe_success vs wrong snd_cwnd
+    - Linux 5.4.198
+
+  * Focal update: v5.4.197 upstream stable release (LP: #1981758)
+    - x86/pci/xen: Disable PCI/MSI[-X] masking for XEN_HVM guests
+    - staging: rtl8723bs: prevent ->Ssid overflow in rtw_wx_set_scan()
+    - Input: goodix - fix spurious key release events
+    - tcp: change source port randomizarion at connect() time
+    - secure_seq: use the 64 bits of the siphash for port offset calculation
+    - media: vim2m: Register video device after setting up internals
+    - media: vim2m: initialize the media device earlier
+    - ACPI: sysfs: Make sparse happy about address space in use
+    - ACPI: sysfs: Fix BERT error region memory mapping
+    - pinctrl: sunxi: fix f1c100s uart2 function
+    - net: af_key: check encryption module availability consistency
+    - net: ftgmac100: Disable hardware checksum on AST2600
+    - i2c: ismt: Provide a DMA buffer for Interrupt Cause Logging
+    - drivers: i2c: thunderx: Allow driver to work with ACPI defined TWSI
+      controllers
+    - assoc_array: Fix BUG_ON during garbage collect
+    - cfg80211: set custom regdomain after wiphy registration
+    - drm/i915: Fix -Wstringop-overflow warning in call to intel_read_wm_latency()
+    - exec: Force single empty string when argv is empty
+    - netfilter: conntrack: re-fetch conntrack after insertion
+    - crypto: ecrdsa - Fix incorrect use of vli_cmp
+    - zsmalloc: fix races between asynchronous zspage free and page migration
+    - dm integrity: fix error code in dm_integrity_ctr()
+    - dm crypt: make printing of the key constant-time
+    - dm stats: add cond_resched when looping over entries
+    - dm verity: set DM_TARGET_IMMUTABLE feature flag
+    - raid5: introduce MD_BROKEN
+    - HID: multitouch: Add support for Google Whiskers Touchpad
+    - tpm: Fix buffer access in tpm2_get_tpm_pt()
+    - tpm: ibmvtpm: Correct the return value in tpm_ibmvtpm_probe()
+    - docs: submitting-patches: Fix crossref to 'The canonical patch format'
+    - NFS: Memory allocation failures are not server fatal errors
+    - NFSD: Fix possible sleep during nfsd4_release_lockowner()
+    - bpf: Enlarge offset check value to INT_MAX in bpf_skb_{load,store}_bytes
+    - Linux 5.4.197
+
+  * Focal update: v5.4.196 upstream stable release (LP: #1981111)
+    - x86/xen: Make the boot CPU idle task reliable
+    - x86/xen: Make the secondary CPU idle tasks reliable
+    - rtc: fix use-after-free on device removal
+    - um: Cleanup syscall_handler_t definition/cast, fix warning
+    - Input: add bounds checking to input_set_capability()
+    - Input: stmfts - fix reference leak in stmfts_input_open
+    - crypto: stm32 - fix reference leak in stm32_crc_remove
+    - crypto: x86/chacha20 - Avoid spurious jumps to other functions
+    - ALSA: hda/realtek: Enable headset mic on Lenovo P360
+    - nvme-multipath: fix hang when disk goes live over reconnect
+    - rtc: mc146818-lib: Fix the AltCentury for AMD platforms
+    - MIPS: lantiq: check the return value of kzalloc()
+    - drbd: remove usage of list iterator variable after loop
+    - platform/chrome: cros_ec_debugfs: detach log reader wq from devm
+    - ARM: 9191/1: arm/stacktrace, kasan: Silence KASAN warnings in unwind_frame()
+    - nilfs2: fix lockdep warnings in page operations for btree nodes
+    - nilfs2: fix lockdep warnings during disk space reclamation
+    - mmc: core: Specify timeouts for BKOPS and CACHE_FLUSH for eMMC
+    - mmc: block: Use generic_cmd6_time when modifying INAND_CMD38_ARG_EXT_CSD
+    - mmc: core: Default to generic_cmd6_time as timeout in __mmc_switch()
+    - SUNRPC: Clean up scheduling of autoclose
+    - SUNRPC: Prevent immediate close+reconnect
+    - SUNRPC: Don't call connect() more than once on a TCP socket
+    - ALSA: wavefront: Proper check of get_user() error
+    - perf: Fix sys_perf_event_open() race against self
+    - Fix double fget() in vhost_net_set_backend()
+    - PCI/PM: Avoid putting Elo i2 PCIe Ports in D3cold
+    - KVM: x86/mmu: Update number of zapped pages even if page list is stable
+    - crypto: qcom-rng - fix infinite loop on requests not multiple of WORD_SZ
+    - drm/dp/mst: fix a possible memory leak in fetch_monitor_name()
+    - dma-buf: fix use of DMA_BUF_SET_NAME_{A,B} in userspace
+    - ARM: dts: aspeed-g6: remove FWQSPID group in pinctrl dtsi
+    - ARM: dts: aspeed-g6: fix SPI1/SPI2 quad pin group
+    - net: macb: Increment rx bd head after allocating skb and buffer
+    - net/sched: act_pedit: sanitize shift argument before usage
+    - net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()
+    - net: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()
+    - ice: fix possible under reporting of ethtool Tx and Rx statistics
+    - clk: at91: generated: consider range when calculating best rate
+    - net/qla3xxx: Fix a test in ql_reset_work()
+    - NFC: nci: fix sleep in atomic context bugs caused by nci_skb_alloc
+    - net/mlx5e: Properly block LRO when XDP is enabled
+    - ARM: 9196/1: spectre-bhb: enable for Cortex-A15
+    - ARM: 9197/1: spectre-bhb: fix loop8 sequence for Thumb2
+    - igb: skip phy status check where unavailable
+    - net: bridge: Clear offload_fwd_mark when passing frame up bridge interface.
+    - gpio: gpio-vf610: do not touch other bits when set the target bit
+    - gpio: mvebu/pwm: Refuse requests with inverted polarity
+    - perf bench numa: Address compiler error on s390
+    - scsi: qla2xxx: Fix missed DMA unmap for aborted commands
+    - mac80211: fix rx reordering with non explicit / psmp ack policy
+    - selftests: add ping test with ping_group_range tuned
+    - ethernet: tulip: fix missing pci_disable_device() on error in
+      tulip_init_one()
+    - net: stmmac: fix missing pci_disable_device() on error in stmmac_pci_probe()
+    - net: atlantic: verify hw_head_ lies within TX buffer ring
+    - Input: ili210x - fix reset timing
+    - block: return ELEVATOR_DISCARD_MERGE if possible
+    - net: stmmac: disable Split Header (SPH) for Intel platforms
+    - firmware_loader: use kernel credentials when reading firmware
+    - ARM: dts: imx7: Use audio_mclk_post_div instead audio_mclk_root_clk
+    - Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE""
+    - x86/xen: fix booting 32-bit pv guest
+    - x86/xen: Mark cpu_bringup_and_idle() as dead_end_function
+    - i2c: mt7621: fix missing clk_disable_unprepare() on error in mtk_i2c_probe()
+    - afs: Fix afs_getattr() to refetch file status if callback break occurred
+    - Linux 5.4.196
+
+  * 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()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 26 Aug 2022 11:39:48 +0200
+
+linux (5.4.0-125.141) focal; urgency=medium
+
+  * focal/linux: 5.4.0-125.141 -proposed tracker (LP: #1983947)
+
+  * nbd: requests can become stuck when disconnecting from server with qemu-nbd
+    (LP: #1896350)
+    - blk-mq: blk-mq: provide forced completion method
+    - blk-mq: move failure injection out of blk_mq_complete_request
+    - nbd: don't handle response without a corresponding request message
+    - nbd: make sure request completion won't concurrent
+    - nbd: don't clear 'NBD_CMD_INFLIGHT' flag if request is not completed
+    - nbd: fix io hung while disconnecting device
+
+  * CVE-2021-33656
+    - vt: drop old FONT ioctls
+
+  * CVE-2021-33061
+    - ixgbe: add the ability for the PF to disable VF link state
+    - ixgbe: add improvement for MDD response functionality
+    - ixgbevf: add disable link state
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 10 Aug 2022 10:17:28 +0200
+
+linux (5.4.0-124.140) focal; urgency=medium
+
+  * CVE-2022-2586
+    - SAUCE: netfilter: nf_tables: do not allow SET_ID to refer to another table
+    - SAUCE: netfilter: nf_tables: do not allow RULE_ID to refer to another chain
+
+  * CVE-2022-2588
+    - SAUCE: net_sched: cls_route: remove from list when handle is 0
+
+  * CVE-2022-34918
+    - netfilter: nf_tables: stricter validation of element data
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 03 Aug 2022 22:48:34 -0300
+
+linux (5.4.0-123.139) focal; urgency=medium
+
+  * focal/linux: 5.4.0-123.139 -proposed tracker (LP: #1981284)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.07.11)
+
+  * Hairpin traffic does not work with centralized NAT gw (LP: #1967856)
+    - net: openvswitch: fix misuse of the cached connection on tuple changes
+
+  * [UBUNTU 20.04] Include patches to avoid self-detected stall with Secure
+    Execution (LP: #1979296)
+    - KVM: s390: pv: add macros for UVC CC values
+    - KVM: s390: pv: avoid stalls when making pages secure
+    - KVM: s390: pv: avoid stalls for kvm_s390_pv_init_vm
+
+  * Focal update: v5.4.195 upstream stable release (LP: #1980407)
+    - batman-adv: Don't skb_split skbuffs with frag_list
+    - hwmon: (tmp401) Add OF device ID table
+    - mac80211: Reset MBSSID parameters upon connection
+    - net: Fix features skip in for_each_netdev_feature()
+    - ipv4: drop dst in multicast routing path
+    - drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name()
+    - netlink: do not reset transport header in netlink_recvmsg()
+    - mac80211_hwsim: call ieee80211_tx_prepare_skb under RCU protection
+    - dim: initialize all struct fields
+    - hwmon: (ltq-cputemp) restrict it to SOC_XWAY
+    - s390/ctcm: fix variable dereferenced before check
+    - s390/ctcm: fix potential memory leak
+    - s390/lcs: fix variable dereferenced before check
+    - net/sched: act_pedit: really ensure the skb is writable
+    - net/smc: non blocking recvmsg() return -EAGAIN when no data and
+      signal_pending
+    - net: sfc: ef10: fix memory leak in efx_ef10_mtd_probe()
+    - gfs2: Fix filesystem block deallocation for short writes
+    - hwmon: (f71882fg) Fix negative temperature
+    - ASoC: max98090: Reject invalid values in custom control put()
+    - ASoC: max98090: Generate notifications on changes for custom control
+    - ASoC: ops: Validate input values in snd_soc_put_volsw_range()
+    - s390: disable -Warray-bounds
+    - net: emaclite: Don't advertise 1000BASE-T and do auto negotiation
+    - tcp: resalt the secret every 10 seconds
+    - tty: n_gsm: fix mux activation issues in gsm_config()
+    - usb: cdc-wdm: fix reading stuck on device close
+    - usb: typec: tcpci: Don't skip cleanup in .remove() on error
+    - USB: serial: pl2303: add device id for HP LM930 Display
+    - USB: serial: qcserial: add support for Sierra Wireless EM7590
+    - USB: serial: option: add Fibocom L610 modem
+    - USB: serial: option: add Fibocom MA510 modem
+    - slimbus: qcom: Fix IRQ check in qcom_slim_probe
+    - serial: 8250_mtk: Fix UART_EFR register address
+    - serial: 8250_mtk: Fix register address for XON/XOFF character
+    - drm/nouveau/tegra: Stop using iommu_present()
+    - i40e: i40e_main: fix a missing check on list iterator
+    - cgroup/cpuset: Remove cpus_allowed/mems_allowed setup in cpuset_init_smp()
+    - drm/vmwgfx: Initialize drm_mode_fb_cmd2
+    - MIPS: fix build with gcc-12
+    - net: phy: Fix race condition on link status change
+    - arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map
+    - ping: fix address binding wrt vrf
+    - tty/serial: digicolor: fix possible null-ptr-deref in digicolor_uart_probe()
+    - Linux 5.4.195
+
+  * Focal update: v5.4.194 upstream stable release (LP: #1980399)
+    - MIPS: Use address-of operator on section symbols
+    - block: drbd: drbd_nl: Make conversion to 'enum drbd_ret_code' explicit
+    - drm/amd/display/dc/gpio/gpio_service: Pass around correct dce_{version,
+      environment} types
+    - drm/i915: Cast remain to unsigned long in eb_relocate_vma
+    - nfp: bpf: silence bitwise vs. logical OR warning
+    - can: grcan: grcan_probe(): fix broken system id check for errata workaround
+      needs
+    - can: grcan: only use the NAPI poll budget for RX
+    - arm: remove CONFIG_ARCH_HAS_HOLES_MEMORYMODEL
+    - [Config] updateconfigs for ARCH_HAS_HOLES_MEMORYMODEL
+    - KVM: x86/pmu: Refactoring find_arch_event() to pmc_perf_hw_id()
+    - x86/asm: Allow to pass macros to __ASM_FORM()
+    - x86: xen: kvm: Gather the definition of emulate prefixes
+    - x86: xen: insn: Decode Xen and KVM emulate-prefix signature
+    - x86: kprobes: Prohibit probing on instruction which has emulate prefix
+    - KVM: x86/svm: Account for family 17h event renumberings in
+      amd_pmc_perf_hw_id
+    - Bluetooth: Fix the creation of hdev->name
+    - mm: fix missing cache flush for all tail pages of compound page
+    - mm: hugetlb: fix missing cache flush in copy_huge_page_from_user()
+    - mm: userfaultfd: fix missing cache flush in mcopy_atomic_pte() and
+      __mcopy_atomic()
+    - Linux 5.4.194
+
+  * Focal update: v5.4.193 upstream stable release (LP: #1979566)
+    - MIPS: Fix CP0 counter erratum detection for R4k CPUs
+    - parisc: Merge model and model name into one line in /proc/cpuinfo
+    - ALSA: fireworks: fix wrong return count shorter than expected by 4 bytes
+    - gpiolib: of: fix bounds check for 'gpio-reserved-ranges'
+    - Revert "SUNRPC: attempt AF_LOCAL connect on setup"
+    - firewire: fix potential uaf in outbound_phy_packet_callback()
+    - firewire: remove check of list iterator against head past the loop body
+    - firewire: core: extend card->lock in fw_core_handle_bus_reset
+    - ACPICA: Always create namespace nodes using acpi_ns_create_node()
+    - genirq: Synchronize interrupt thread startup
+    - ASoC: da7219: Fix change notifications for tone generator frequency
+    - ASoC: wm8958: Fix change notifications for DSP controls
+    - ASoC: meson: Fix event generation for G12A tohdmi mux
+    - s390/dasd: fix data corruption for ESE devices
+    - s390/dasd: prevent double format of tracks for ESE devices
+    - s390/dasd: Fix read for ESE with blksize < 4k
+    - s390/dasd: Fix read inconsistency for ESE DASD devices
+    - can: grcan: grcan_close(): fix deadlock
+    - can: grcan: use ofdev->dev when allocating DMA memory
+    - nfc: replace improper check device_is_registered() in netlink related
+      functions
+    - NFC: netlink: fix sleep in atomic bug when firmware download timeout
+    - hwmon: (adt7470) Fix warning on module removal
+    - ASoC: dmaengine: Restore NULL prepare_slave_config() callback
+    - RDMA/siw: Fix a condition race issue in MPA request processing
+    - net: ethernet: mediatek: add missing of_node_put() in mtk_sgmii_init()
+    - net: stmmac: dwmac-sun8i: add missing of_node_put() in
+      sun8i_dwmac_register_mdio_mux()
+    - net: emaclite: Add error handling for of_address_to_resource()
+    - selftests: mirror_gre_bridge_1q: Avoid changing PVID while interface is
+      operational
+    - bnxt_en: Fix possible bnxt_open() failure caused by wrong RFS flag
+    - smsc911x: allow using IRQ0
+    - btrfs: always log symlinks in full mode
+    - net: igmp: respect RCU rules in ip_mc_source() and ip_mc_msfilter()
+    - drm/amdkfd: Use drm_priv to pass VM from KFD to amdgpu
+    - NFSv4: Don't invalidate inode attributes on delegation return
+    - kvm: x86/cpuid: Only provide CPUID leaf 0xA if host has architectural PMU
+    - x86/kvm: Preserve BSP MSR_KVM_POLL_CONTROL across suspend/resume
+    - KVM: LAPIC: Enable timer posted-interrupt only when mwait/hlt is advertised
+    - net: ipv6: ensure we call ipv6_mc_down() at most once
+    - block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern
+    - mm: fix unexpected zeroed page mapping with zram swap
+    - ALSA: pcm: Fix races among concurrent hw_params and hw_free calls
+    - ALSA: pcm: Fix races among concurrent read/write and buffer changes
+    - ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls
+    - ALSA: pcm: Fix races among concurrent prealloc proc writes
+    - ALSA: pcm: Fix potential AB/BA lock with buffer_mutex and mmap_lock
+    - tcp: make sure treq->af_specific is initialized
+    - dm: fix mempool NULL pointer race when completing IO
+    - dm: interlock pending dm_io and dm_wait_for_bios_completion
+    - PCI: aardvark: Clear all MSIs at setup
+    - PCI: aardvark: Fix reading MSI interrupt number
+    - mmc: rtsx: add 74 Clocks in power on flow
+    - Linux 5.4.193
+
+  * CVE-2022-1679
+    - SAUCE: ath9k: fix use-after-free in ath9k_hif_usb_rx_cb
+
+  * CVE-2022-28893
+    - SUNRPC: Ensure we flush any closed sockets before xs_xprt_free()
+    - SUNRPC: Don't leak sockets in xs_local_connect()
+
+  * CVE-2022-1734
+    - nfc: nfcmrvl: main: reorder destructive operations in
+      nfcmrvl_nci_unregister_dev to avoid bugs
+
+  * CVE-2022-1652
+    - floppy: use a statically allocated error counter
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 11 Jul 2022 16:54:06 +0200
+
+linux (5.4.0-122.138) focal; urgency=medium
+
+  * focal/linux: 5.4.0-122.138 -proposed tracker (LP: #1979489)
+
+  * Remove SAUCE patches from test_vxlan_under_vrf.sh in net of
+    ubuntu_kernel_selftests (LP: #1975691)
+    - Revert "UBUNTU: SAUCE: selftests: net: Don't fail test_vxlan_under_vrf on
+      xfail"
+    - Revert "UBUNTU: SAUCE: selftests: net: Make test for VXLAN underlay in non-
+      default VRF an expected failure"
+
+  * Enable Asus USB-BT500 Bluetooth dongle(0b05:190e) (LP: #1976613)
+    - Bluetooth: btusb: Add flag to define wideband speech capability
+    - Bluetooth: btrtl: Add support for RTL8761B
+    - Bluetooth: btusb: Add 0x0b05:0x190e Realtek 8761BU (ASUS BT500) device.
+
+  * [UBUNTU 20.04] rcu stalls with many storage key guests (LP: #1975582)
+    - s390/gmap: voluntarily schedule during key setting
+    - s390/mm: use non-quiescing sske for KVM switch to keyed guest
+
+  * Ubuntu 5.4.0-117.132-generic 5.4.189 has BUG: kernel NULL pointer
+    dereference, address: 0000000000000034 (LP: #1978719)
+    - mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()
+
+  * Focal update: upstream stable patchset v5.4.192 (LP: #1979014)
+    - floppy: disable FDRAWCMD by default
+    - [Config] updateconfigs for BLK_DEV_FD_RAWCMD
+    - hamradio: defer 6pack kfree after unregister_netdev
+    - hamradio: remove needs_free_netdev to avoid UAF
+    - lightnvm: disable the subsystem
+    - [Config] updateconfigs for NVM, NVM_PBLK
+    - usb: mtu3: fix USB 3.0 dual-role-switch from device to host
+    - USB: quirks: add a Realtek card reader
+    - USB: quirks: add STRING quirk for VCOM device
+    - USB: serial: whiteheat: fix heap overflow in WHITEHEAT_GET_DTR_RTS
+    - USB: serial: cp210x: add PIDs for Kamstrup USB Meter Reader
+    - USB: serial: option: add support for Cinterion MV32-WA/MV32-WB
+    - USB: serial: option: add Telit 0x1057, 0x1058, 0x1075 compositions
+    - xhci: stop polling roothubs after shutdown
+    - xhci: increase usb U3 -> U0 link resume timeout from 100ms to 500ms
+    - iio: dac: ad5592r: Fix the missing return value.
+    - iio: dac: ad5446: Fix read_raw not returning set value
+    - iio: magnetometer: ak8975: Fix the error handling in ak8975_power_on()
+    - usb: misc: fix improper handling of refcount in uss720_probe()
+    - usb: typec: ucsi: Fix role swapping
+    - usb: gadget: uvc: Fix crash when encoding data for usb request
+    - usb: gadget: configfs: clear deactivation flag in
+      configfs_composite_unbind()
+    - usb: dwc3: core: Fix tx/rx threshold settings
+    - usb: dwc3: gadget: Return proper request status
+    - serial: imx: fix overrun interrupts in DMA mode
+    - serial: 8250: Also set sticky MCR bits in console restoration
+    - serial: 8250: Correct the clock for EndRun PTP/1588 PCIe device
+    - arch_topology: Do not set llc_sibling if llc_id is invalid
+    - hex2bin: make the function hex_to_bin constant-time
+    - hex2bin: fix access beyond string end
+    - video: fbdev: udlfb: properly check endpoint type
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12B boards
+    - arm64: dts: meson: remove CPU opps below 1GHz for SM1 boards
+    - mtd: rawnand: fix ecc parameters for mt7622
+    - USB: Fix xhci event ring dequeue pointer ERDP update issue
+    - ARM: dts: imx6qdl-apalis: Fix sgtl5000 detection issue
+    - phy: samsung: Fix missing of_node_put() in exynos_sata_phy_probe
+    - phy: samsung: exynos5250-sata: fix missing device put in probe error paths
+    - ARM: OMAP2+: Fix refcount leak in omap_gic_of_init
+    - phy: ti: omap-usb2: Fix error handling in omap_usb2_enable_clocks
+    - ARM: dts: at91: Map MCLK for wm8731 on at91sam9g20ek
+    - phy: mapphone-mdm6600: Fix PM error handling in phy_mdm6600_probe
+    - phy: ti: Add missing pm_runtime_disable() in serdes_am654_probe
+    - ARM: dts: Fix mmc order for omap3-gta04
+    - ARM: dts: am3517-evm: Fix misc pinmuxing
+    - ARM: dts: logicpd-som-lv: Fix wrong pinmuxing on OMAP35
+    - ipvs: correctly print the memory size of ip_vs_conn_tab
+    - mtd: rawnand: Fix return value check of wait_for_completion_timeout
+    - bpf, lwt: Fix crash when using bpf_skb_set_tunnel_key() from bpf_xmit lwt
+      hook
+    - tcp: md5: incorrect tcp_header_len for incoming connections
+    - tcp: ensure to use the most recently sent skb when filling the rate sample
+    - sctp: check asoc strreset_chunk in sctp_generate_reconf_event
+    - ARM: dts: imx6ull-colibri: fix vqmmc regulator
+    - arm64: dts: imx8mn-ddr4-evk: Describe the 32.768 kHz PMIC clock
+    - pinctrl: pistachio: fix use of irq_of_parse_and_map()
+    - cpufreq: fix memory leak in sun50i_cpufreq_nvmem_probe
+    - net: hns3: add validity check for message data length
+    - net/smc: sync err code when tcp connection was refused
+    - ip_gre: Make o_seqno start from 0 in native mode
+    - tcp: fix potential xmit stalls caused by TCP_NOTSENT_LOWAT
+    - bus: sunxi-rsb: Fix the return value of sunxi_rsb_device_create()
+    - clk: sunxi: sun9i-mmc: check return value after calling
+      platform_get_resource()
+    - net: bcmgenet: hide status block before TX timestamping
+    - net: dsa: lantiq_gswip: Don't set GSWIP_MII_CFG_RMII_CLK
+    - drm/amd/display: Fix memory leak in dcn21_clock_source_create
+    - tls: Skip tls_append_frag on zero copy size
+    - bnx2x: fix napi API usage sequence
+    - ixgbe: ensure IPsec VF<->PF compatibility
+    - tcp: fix F-RTO may not work correctly when receiving DSACK
+    - ASoC: wm8731: Disable the regulator when probing fails
+    - ip6_gre: Avoid updating tunnel->tun_hlen in __gre6_xmit()
+    - x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
+    - cifs: destage any unwritten data to the server before calling
+      copychunk_write
+    - drivers: net: hippi: Fix deadlock in rr_close()
+    - net: ethernet: stmmac: fix write to sgmii_adapter_base
+    - x86/cpu: Load microcode during restore_processor_state()
+    - tty: n_gsm: fix wrong signal octet encoding in convergence layer type 2
+    - tty: n_gsm: fix malformed counter for out of frame data
+    - netfilter: nft_socket: only do sk lookups when indev is available
+    - tty: n_gsm: fix insufficient txframe size
+    - tty: n_gsm: fix missing explicit ldisc flush
+    - tty: n_gsm: fix wrong command retry handling
+    - tty: n_gsm: fix wrong command frame length field encoding
+    - tty: n_gsm: fix incorrect UA handling
+    - hugetlbfs: get unmapped area below TASK_UNMAPPED_BASE for hugetlbfs
+    - mm, hugetlb: allow for "high" userspace addresses
+    - Linux 5.4.192
+
+  * CVE-2022-1789
+    - KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID
+
+  * Focal update: v5.4.191 upstream stable release (LP: #1976116)
+    - etherdevice: Adjust ether_addr* prototypes to silence -Wstringop-overead
+    - mm: page_alloc: fix building error on -Werror=array-compare
+    - tracing: Dump stacktrace trigger to the corresponding instance
+    - gfs2: assign rgrp glock before compute_bitstructs
+    - tcp: fix race condition when creating child sockets from syncookies
+    - tcp: Fix potential use-after-free due to double kfree()
+    - ALSA: usb-audio: Clear MIDI port active flag after draining
+    - ASoC: atmel: Remove system clock tree configuration for at91sam9g20ek
+    - ASoC: msm8916-wcd-digital: Check failure for devm_snd_soc_register_component
+    - dmaengine: imx-sdma: Fix error checking in sdma_event_remap
+    - dmaengine: mediatek:Fix PM usage reference leak of
+      mtk_uart_apdma_alloc_chan_resources
+    - igc: Fix infinite loop in release_swfw_sync
+    - igc: Fix BUG: scheduling while atomic
+    - rxrpc: Restore removed timer deletion
+    - net/smc: Fix sock leak when release after smc_shutdown()
+    - net/packet: fix packet_sock xmit return value checking
+    - net/sched: cls_u32: fix possible leak in u32_init_knode()
+    - l3mdev: l3mdev_master_upper_ifindex_by_index_rcu should be using
+      netdev_master_upper_dev_get_rcu
+    - netlink: reset network and mac headers in netlink_dump()
+    - selftests: mlxsw: vxlan_flooding: Prevent flooding of unwanted packets
+    - ARM: vexpress/spc: Avoid negative array index when !SMP
+    - reset: tegra-bpmp: Restore Handle errors in BPMP response
+    - platform/x86: samsung-laptop: Fix an unsigned comparison which can never be
+      negative
+    - ALSA: usb-audio: Fix undefined behavior due to shift overflowing the
+      constant
+    - vxlan: fix error return code in vxlan_fdb_append
+    - cifs: Check the IOCB_DIRECT flag, not O_DIRECT
+    - mt76: Fix undefined behavior due to shift overflowing the constant
+    - brcmfmac: sdio: Fix undefined behavior due to shift overflowing the constant
+    - dpaa_eth: Fix missing of_node_put in dpaa_get_ts_info()
+    - drm/msm/mdp5: check the return of kzalloc()
+    - net: macb: Restart tx only if queue pointer is lagging
+    - scsi: qedi: Fix failed disconnect handling
+    - stat: fix inconsistency between struct stat and struct compat_stat
+    - EDAC/synopsys: Read the error count from the correct register
+    - oom_kill.c: futex: delay the OOM reaper to allow time for proper futex
+      cleanup
+    - ata: pata_marvell: Check the 'bmdma_addr' beforing reading
+    - dma: at_xdmac: fix a missing check on list iterator
+    - drm/panel/raspberrypi-touchscreen: Avoid NULL deref if not initialised
+    - drm/panel/raspberrypi-touchscreen: Initialise the bridge in prepare
+    - KVM: PPC: Fix TCE handling for VFIO
+    - drm/vc4: Use pm_runtime_resume_and_get to fix pm_runtime_get_sync() usage
+    - powerpc/perf: Fix power9 event alternatives
+    - xtensa: patch_text: Fixup last cpu should be master
+    - xtensa: fix a7 clobbering in coprocessor context load/store
+    - openvswitch: fix OOB access in reserve_sfa_size()
+    - ASoC: soc-dapm: fix two incorrect uses of list iterator
+    - e1000e: Fix possible overflow in LTR decoding
+    - ARC: entry: fix syscall_trace_exit argument
+    - arm_pmu: Validate single/group leader events
+    - ext4: fix symlink file size not match to file content
+    - ext4: fix use-after-free in ext4_search_dir
+    - ext4, doc: fix incorrect h_reserved size
+    - ext4: fix overhead calculation to account for the reserved gdt blocks
+    - ext4: force overhead calculation if the s_overhead_cluster makes no sense
+    - jbd2: fix a potential race while discarding reserved buffers after an abort
+    - spi: atmel-quadspi: Fix the buswidth adjustment between spi-mem and
+      controller
+    - staging: ion: Prevent incorrect reference counting behavour
+    - block/compat_ioctl: fix range check in BLKGETSIZE
+    - Linux 5.4.191
+
+  * Focal update: v5.4.190 upstream stable release (LP: #1973085)
+    - memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probe
+    - net/sched: flower: fix parsing of ethertype following VLAN header
+    - veth: Ensure eth header is in skb's linear part
+    - gpiolib: acpi: use correct format characters
+    - mlxsw: i2c: Fix initialization error flow
+    - net/sched: fix initialization order when updating chain 0 head
+    - net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link
+    - net/sched: taprio: Check if socket flags are valid
+    - cfg80211: hold bss_lock while updating nontrans_list
+    - drm/msm/dsi: Use connector directly in msm_dsi_manager_connector_init()
+    - net/smc: Fix NULL pointer dereference in smc_pnet_find_ib()
+    - sctp: Initialize daddr on peeled off socket
+    - testing/selftests/mqueue: Fix mq_perf_tests to free the allocated cpu set
+    - nfc: nci: add flush_workqueue to prevent uaf
+    - cifs: potential buffer overflow in handling symlinks
+    - drm/amd: Add USBC connector ID
+    - drm/amd/display: fix audio format not updated after edid updated
+    - drm/amd/display: Update VTEM Infopacket definition
+    - drm/amdkfd: Fix Incorrect VMIDs passed to HWS
+    - drm/amdkfd: Check for potential null return of kmalloc_array()
+    - Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
+    - scsi: target: tcmu: Fix possible page UAF
+    - scsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024
+    - ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs
+    - gpu: ipu-v3: Fix dev_dbg frequency output
+    - regulator: wm8994: Add an off-on delay for WM8994 variant
+    - arm64: alternatives: mark patch_alternative() as `noinstr`
+    - tlb: hugetlb: Add more sizes to tlb_remove_huge_tlb_entry
+    - net: usb: aqc111: Fix out-of-bounds accesses in RX fixup
+    - drm/amd/display: Fix allocate_mst_payload assert on resume
+    - powerpc: Fix virt_addr_valid() for 64-bit Book3E & 32-bit
+    - scsi: mvsas: Add PCI ID of RocketRaid 2640
+    - scsi: megaraid_sas: Target with invalid LUN ID is deleted during scan
+    - drivers: net: slip: fix NPD bug in sl_tx_timeout()
+    - perf/imx_ddr: Fix undefined behavior due to shift overflowing the constant
+    - mm, page_alloc: fix build_zonerefs_node()
+    - mm: kmemleak: take a full lowmem check in kmemleak_*_phys()
+    - gcc-plugins: latent_entropy: use /dev/urandom
+    - ath9k: Properly clear TX status area before reporting to mac80211
+    - ath9k: Fix usage of driver-private space in tx_info
+    - btrfs: remove unused variable in btrfs_{start,write}_dirty_block_groups()
+    - btrfs: mark resumed async balance as writing
+    - ALSA: hda/realtek: Add quirk for Clevo PD50PNT
+    - ALSA: pcm: Test for "silence" field in struct "pcm_format_data"
+    - ipv6: fix panic when forwarding a pkt with no in6 dev
+    - drm/amd/display: don't ignore alpha property on pre-multiplied mode
+    - genirq/affinity: Consider that CPUs on nodes can be unbalanced
+    - tick/nohz: Use WARN_ON_ONCE() to prevent console saturation
+    - ARM: davinci: da850-evm: Avoid NULL pointer dereference
+    - dm integrity: fix memory corruption when tag_size is less than digest size
+    - smp: Fix offline cpu check in flush_smp_call_function_queue()
+    - i2c: pasemi: Wait for write xfers to finish
+    - dma-direct: avoid redundant memory sync for swiotlb
+    - 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()
+    - ax25: fix NPD bug in ax25_disconnect
+    - ax25: Fix NULL pointer dereferences in ax25 timers
+    - ax25: Fix UAF bugs in ax25 timers
+    - Linux 5.4.190
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 22 Jun 2022 15:00:52 +0200
+
+linux (5.4.0-121.137) focal; urgency=medium
+
+  * focal/linux: 5.4.0-121.137 -proposed tracker (LP: #1978666)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.05.30)
+
+  * CVE-2022-28388
+    - can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error
+      path
+
+  * test_vxlan_under_vrf.sh in net from ubuntu_kernel_selftests failed (Check VM
+    connectivity through VXLAN (underlay in the default VRF) [FAIL])
+    (LP: #1871015)
+    - selftests: net: test_vxlan_under_vrf: fix HV connectivity test
+
+  * [UBUNTU 20.04] CPU-MF: add extended counter set definitions for new IBM z16
+    (LP: #1974433)
+    - s390/cpumf: add new extended counter set for IBM z16
+
+  * [UBUNTU 20.04] KVM nesting support leaks too much memory, might result in
+    stalls during cleanup (LP: #1974017)
+    - KVM: s390: vsie/gmap: reduce gmap_rmap overhead
+
+  * [UBUNTU 20.04] Null Pointer issue in nfs code running Ubuntu on IBM Z
+    (LP: #1968096)
+    - NFS: Fix up nfs_ctx_key_to_expire()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 15 Jun 2022 15:13:27 +0200
+
+linux (5.4.0-120.136) focal; urgency=medium
+
+  * CVE-2022-21123 // CVE-2022-21125 // CVE-2022-21166
+    - cpu/speculation: Add prototype for cpu_show_srbds()
+    - x86/cpu: Add Jasper Lake to Intel family
+    - 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
+    - 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
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 10 Jun 2022 10:21:07 -0300
+
+linux (5.4.0-117.132) focal; urgency=medium
+
+  * CVE-2022-1966
+    - netfilter: nf_tables: add nft_set_elem_expr_alloc()
+    - netfilter: nf_tables: disallow non-stateful expression in sets earlier
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 01 Jun 2022 20:07:42 -0300
+
+linux (5.4.0-115.129) focal; urgency=medium
+
+  * CVE-2022-21499
+    - SAUCE: debug: Lock down kgdb
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Sat, 21 May 2022 12:07:10 -0300
+
+linux (5.4.0-114.128) focal; urgency=medium
+
+  * focal/linux: 5.4.0-114.128 -proposed tracker (LP: #1974391)
+
+  * 32 GT/s PCI link speeds reporting "Unknown speed" in sysfs (LP: #1970798)
+    - PCI: Add 32 GT/s decoding in some macros
+    - PCI: Add pci_speed_string()
+    - PCI: Use pci_speed_string() for all PCI/PCI-X/PCIe strings
+    - PCI: Add PCIE_LNKCAP2_SLS2SPEED() macro
+
+  * issuing invalid ioctl to /dev/vsock may spam dmesg (LP: #1971480)
+    - vsock: remove ratelimit unknown ioctl message
+
+  * config CONFIG_HISI_PMU for  kunpeng920 (LP: #1956086)
+    - drivers/perf: hisi: Permit modular builds of HiSilicon uncore drivers
+    - [Config] CONFIG_HISI_PMU=m
+
+  * Focal update: v5.4.189 upstream stable release (LP: #1971497)
+    - swiotlb: fix info leak with DMA_FROM_DEVICE
+    - USB: serial: pl2303: add IBM device IDs
+    - USB: serial: simple: add Nokia phone driver
+    - netdevice: add the case if dev is NULL
+    - HID: logitech-dj: add new lightspeed receiver id
+    - xfrm: fix tunnel model fragmentation behavior
+    - virtio_console: break out of buf poll on remove
+    - ethernet: sun: Free the coherent when failing in probing
+    - spi: Fix invalid sgs value
+    - net:mcf8390: Use platform_get_irq() to get the interrupt
+    - spi: Fix erroneous sgs value with min_t()
+    - af_key: add __GFP_ZERO flag for compose_sadb_supported in function
+      pfkey_register
+    - net: dsa: microchip: add spi_device_id tables
+    - iommu/iova: Improve 32-bit free space estimate
+    - tpm: fix reference counting for struct tpm_chip
+    - block: Add a helper to validate the block size
+    - virtio-blk: Use blk_validate_block_size() to validate block size
+    - USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c
+    - xhci: fix runtime PM imbalance in USB2 resume
+    - xhci: make xhci_handshake timeout for xhci_reset() adjustable
+    - xhci: fix uninitialized string returned by xhci_decode_ctrl_ctx()
+    - coresight: Fix TRCCONFIGR.QE sysfs interface
+    - iio: afe: rescale: use s64 for temporary scale calculations
+    - iio: inkern: apply consumer scale on IIO_VAL_INT cases
+    - iio: inkern: apply consumer scale when no channel scale is available
+    - iio: inkern: make a best effort on offset calculation
+    - greybus: svc: fix an error handling bug in gb_svc_hello()
+    - clk: uniphier: Fix fixed-rate initialization
+    - KEYS: fix length validation in keyctl_pkey_params_get_2()
+    - Documentation: add link to stable release candidate tree
+    - Documentation: update stable tree link
+    - HID: intel-ish-hid: Use dma_alloc_coherent for firmware update
+    - SUNRPC: avoid race between mod_timer() and del_timer_sync()
+    - NFSD: prevent underflow in nfssvc_decode_writeargs()
+    - NFSD: prevent integer overflow on 32 bit systems
+    - f2fs: fix to unlock page correctly in error path of is_alive()
+    - f2fs: quota: fix loop condition at f2fs_quota_sync()
+    - f2fs: fix to do sanity check on .cp_pack_total_block_count
+    - pinctrl: samsung: drop pin banks references on error paths
+    - spi: mxic: Fix the transmit path
+    - jffs2: fix use-after-free in jffs2_clear_xattr_subsystem
+    - jffs2: fix memory leak in jffs2_do_mount_fs
+    - jffs2: fix memory leak in jffs2_scan_medium
+    - mm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node
+    - mm: invalidate hwpoison page cache page in fault path
+    - mempolicy: mbind_range() set_policy() after vma_merge()
+    - scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands
+    - qed: display VF trust config
+    - qed: validate and restrict untrusted VFs vlan promisc mode
+    - riscv: Fix fill_callchain return value
+    - Revert "Input: clear BTN_RIGHT/MIDDLE on buttonpads"
+    - ALSA: cs4236: fix an incorrect NULL check on list iterator
+    - ALSA: hda/realtek: Fix audio regression on Mi Notebook Pro 2020
+    - mm,hwpoison: unmap poisoned page before invalidation
+    - mm/kmemleak: reset tag when compare object pointer
+    - drbd: fix potential silent data corruption
+    - powerpc/kvm: Fix kvm_use_magic_page
+    - udp: call udp_encap_enable for v6 sockets when enabling encap
+    - ACPI: properties: Consistently return -ENOENT if there are no more
+      references
+    - drivers: hamradio: 6pack: fix UAF bug caused by mod_timer()
+    - mailbox: tegra-hsp: Flush whole channel
+    - block: don't merge across cgroup boundaries if blkcg is enabled
+    - drm/edid: check basic audio support on CEA extension block
+    - video: fbdev: sm712fb: Fix crash in smtcfb_read()
+    - video: fbdev: atari: Atari 2 bpp (STe) palette bugfix
+    - ARM: dts: at91: sama5d2: Fix PMERRLOC resource size
+    - ARM: dts: exynos: fix UART3 pins configuration in Exynos5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5420
+    - carl9170: fix missing bit-wise or operator for tx_params
+    - thermal: int340x: Increase bitmap size
+    - lib/raid6/test: fix multiple definition linking error
+    - crypto: rsa-pkcs1pad - correctly get hash from source scatterlist
+    - crypto: rsa-pkcs1pad - restore signature length check
+    - crypto: rsa-pkcs1pad - fix buffer overread in pkcs1pad_verify_complete()
+    - DEC: Limit PMAX memory probing to R3k systems
+    - media: davinci: vpif: fix unbalanced runtime PM get
+    - xtensa: fix stop_machine_cpuslocked call in patch_text
+    - xtensa: fix xtensa_wsr always writing 0
+    - brcmfmac: firmware: Allocate space for default boardrev in nvram
+    - brcmfmac: pcie: Release firmwares in the brcmf_pcie_setup error path
+    - brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toio
+    - brcmfmac: pcie: Fix crashes due to early IRQs
+    - PCI: pciehp: Clear cmd_busy bit in polling mode
+    - regulator: qcom_smd: fix for_each_child.cocci warnings
+    - crypto: authenc - Fix sleep in atomic context in decrypt_tail
+    - crypto: mxs-dcp - Fix scatterlist processing
+    - spi: tegra114: Add missing IRQ check in tegra_spi_probe
+    - selftests/x86: Add validity check and allow field splitting
+    - audit: log AUDIT_TIME_* records only from rules
+    - crypto: ccree - don't attempt 0 len DMA mappings
+    - spi: pxa2xx-pci: Balance reference count for PCI DMA device
+    - hwmon: (pmbus) Add mutex to regulator ops
+    - hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNING
+    - block: don't delete queue kobject before its children
+    - PM: hibernate: fix __setup handler error handling
+    - PM: suspend: fix return value of __setup handler
+    - hwrng: atmel - disable trng on failure path
+    - crypto: vmx - add missing dependencies
+    - clocksource/drivers/timer-of: Check return value of of_iomap in
+      timer_of_base_init()
+    - ACPI: APEI: fix return value of __setup handlers
+    - crypto: ccp - ccp_dmaengine_unregister release dma channels
+    - hwmon: (pmbus) Add Vin unit off handling
+    - clocksource: acpi_pm: fix return value of __setup handler
+    - sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa
+    - perf/core: Fix address filter parser for multiple filters
+    - perf/x86/intel/pt: Fix address filter config for 32-bit kernel
+    - f2fs: fix missing free nid in f2fs_handle_failed_inode
+    - f2fs: fix to avoid potential deadlock
+    - media: bttv: fix WARNING regression on tunerless devices
+    - media: coda: Fix missing put_device() call in coda_get_vdoa_data
+    - media: hantro: Fix overfill bottom register field name
+    - media: aspeed: Correct value for h-total-pixels
+    - video: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe()
+    - video: fbdev: atmel_lcdfb: fix an error code in atmel_lcdfb_probe()
+    - video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name()
+    - ARM: dts: qcom: ipq4019: fix sleep clock
+    - soc: qcom: rpmpd: Check for null return of devm_kcalloc
+    - soc: qcom: aoss: remove spurious IRQF_ONESHOT flags
+    - arm64: dts: qcom: sm8150: Correct TCS configuration for apps rsc
+    - soc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe
+    - ARM: dts: imx: Add missing LVDS decoder on M53Menlo
+    - media: video/hdmi: handle short reads of hdmi info frame.
+    - media: em28xx: initialize refcount before kref_get
+    - media: usb: go7007: s2250-board: fix leak in probe()
+    - uaccess: fix nios2 and microblaze get_user_8()
+    - ASoC: rt5663: check the return value of devm_kzalloc() in rt5663_parse_dp()
+    - ASoC: ti: davinci-i2s: Add check for clk_enable()
+    - ALSA: spi: Add check for clk_enable()
+    - arm64: dts: ns2: Fix spi-cpol and spi-cpha property
+    - arm64: dts: broadcom: Fix sata nodename
+    - printk: fix return value of printk.devkmsg __setup handler
+    - ASoC: mxs-saif: Handle errors for clk_enable
+    - ASoC: atmel_ssc_dai: Handle errors for clk_enable
+    - ASoC: soc-compress: prevent the potentially use of null pointer
+    - memory: emif: Add check for setup_interrupts
+    - memory: emif: check the pointer temp in get_device_details()
+    - ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction
+    - arm64: dts: rockchip: Fix SDIO regulator supply properties on rk3399-firefly
+    - media: stk1160: If start stream fails, return buffers with
+      VB2_BUF_STATE_QUEUED
+    - ASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe
+    - ASoC: wm8350: Handle error for wm8350_register_irq
+    - ASoC: fsi: Add check for clk_enable
+    - video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of
+    - ivtv: fix incorrect device_caps for ivtvfb
+    - ASoC: dmaengine: do not use a NULL prepare_slave_config() callback
+    - ASoC: mxs: Fix error handling in mxs_sgtl5000_probe
+    - ASoC: imx-es8328: Fix error return code in imx_es8328_probe()
+    - ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in
+      msm8916_wcd_digital_probe
+    - mmc: davinci_mmc: Handle error for clk_enable
+    - ASoC: msm8916-wcd-analog: Fix error handling in pm8916_wcd_analog_spmi_probe
+    - drm/bridge: Fix free wrong object in sii8620_init_rcp_input_dev
+    - drm/bridge: Add missing pm_runtime_disable() in __dw_mipi_dsi_probe
+    - ath10k: fix memory overwrite of the WoWLAN wakeup packet pattern
+    - udmabuf: validate ubuf->pagecount
+    - Bluetooth: hci_serdev: call init_rwsem() before p->open()
+    - mtd: onenand: Check for error irq
+    - mtd: rawnand: gpmi: fix controller timings setting
+    - drm/edid: Don't clear formats if using deep color
+    - drm/amd/display: Fix a NULL pointer dereference in
+      amdgpu_dm_connector_add_common_modes()
+    - ath9k_htc: fix uninit value bugs
+    - KVM: PPC: Fix vmx/vsx mixup in mmio emulation
+    - i40e: don't reserve excessive XDP_PACKET_HEADROOM on XSK Rx to skb
+    - power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probe
+    - ray_cs: Check ioremap return value
+    - powerpc/perf: Don't use perf_hw_context for trace IMC PMU
+    - mt76: mt7603: check sta_rates pointer in mt7603_sta_rate_tbl_update
+    - mt76: mt7615: check sta_rates pointer in mt7615_sta_rate_tbl_update
+    - net: dsa: mv88e6xxx: Enable port policy support on 6097
+    - PCI: aardvark: Fix reading PCI_EXP_RTSTA_PME bit on emulated bridge
+    - power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_init
+    - HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports
+    - iommu/ipmmu-vmsa: Check for error num after setting mask
+    - drm/amd/display: Add affected crtcs to atomic state for dsc mst unplug
+    - IB/cma: Allow XRC INI QPs to set their local ACK timeout
+    - dax: make sure inodes are flushed before destroy cache
+    - iwlwifi: Fix -EIO error code that is never returned
+    - iwlwifi: mvm: Fix an error code in iwl_mvm_up()
+    - dm crypt: fix get_key_size compiler warning if !CONFIG_KEYS
+    - scsi: pm8001: Fix command initialization in pm80XX_send_read_log()
+    - scsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req()
+    - scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config()
+    - scsi: pm8001: Fix abort all task initialization
+    - drm/amd/display: Remove vupdate_int_entry definition
+    - TOMOYO: fix __setup handlers return values
+    - ext2: correct max file size computing
+    - drm/tegra: Fix reference leak in tegra_dsi_ganged_probe
+    - power: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false
+      return
+    - scsi: hisi_sas: Change permission of parameter prot_mask
+    - drm/bridge: cdns-dsi: Make sure to to create proper aliases for dt
+    - bpf, arm64: Call build_prologue() first in first JIT pass
+    - bpf, arm64: Feed byte-offset into bpf line info
+    - libbpf: Skip forward declaration when counting duplicated type names
+    - powerpc/Makefile: Don't pass -mcpu=powerpc64 when building 32-bit
+    - KVM: x86: Fix emulation in writing cr8
+    - KVM: x86/emulator: Defer not-present segment check in
+      __load_segment_descriptor()
+    - hv_balloon: rate-limit "Unhandled message" warning
+    - i2c: xiic: Make bus names unique
+    - power: supply: wm8350-power: Handle error for wm8350_register_irq
+    - power: supply: wm8350-power: Add missing free in free_charger_irq
+    - PCI: Reduce warnings on possible RW1C corruption
+    - mips: DEC: honor CONFIG_MIPS_FP_SUPPORT=n
+    - powerpc/sysdev: fix incorrect use to determine if list is empty
+    - mfd: mc13xxx: Add check for mc13xxx_irq_request
+    - selftests/bpf: Make test_lwt_ip_encap more stable and faster
+    - powerpc: 8xx: fix a return value error in mpc8xx_pic_init
+    - vxcan: enable local echo for sent CAN frames
+    - MIPS: RB532: fix return value of __setup handler
+    - mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init
+    - RDMA/mlx5: Fix memory leak in error flow for subscribe event routine
+    - bpf, sockmap: Fix memleak in tcp_bpf_sendmsg while sk msg is full
+    - bpf, sockmap: Fix more uncharged while msg has more_data
+    - bpf, sockmap: Fix double uncharge the mem of sk_msg
+    - USB: storage: ums-realtek: fix error code in rts51x_read_mem()
+    - Bluetooth: btmtksdio: Fix kernel oops in btmtksdio_interrupt
+    - af_netlink: Fix shift out of bounds in group mask calculation
+    - i2c: mux: demux-pinctrl: do not deactivate a master that is not active
+    - selftests/bpf/test_lirc_mode2.sh: Exit with proper code
+    - tcp: ensure PMTU updates are processed during fastopen
+    - openvswitch: always update flow key after nat
+    - tipc: fix the timer expires after interval 100ms
+    - mfd: asic3: Add missing iounmap() on error asic3_mfd_probe
+    - mxser: fix xmit_buf leak in activate when LSR == 0xff
+    - pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()
+    - misc: alcor_pci: Fix an error handling path
+    - staging:iio:adc:ad7280a: Fix handing of device address bit reversing.
+    - pinctrl: renesas: r8a77470: Reduce size for narrow VIN1 channel
+    - clk: qcom: ipq8074: Use floor ops for SDCC1 clock
+    - phy: dphy: Correct lpx parameter and its derivatives(ta_{get,go,sure})
+    - serial: 8250_mid: Balance reference count for PCI DMA device
+    - serial: 8250: Fix race condition in RTS-after-send handling
+    - iio: adc: Add check for devm_request_threaded_irq
+    - NFS: Return valid errors from nfs2/3_decode_dirent()
+    - dma-debug: fix return value of __setup handlers
+    - clk: imx7d: Remove audio_mclk_root_clk
+    - clk: qcom: clk-rcg2: Update logic to calculate D value for RCG
+    - clk: qcom: clk-rcg2: Update the frac table for pixel clock
+    - remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_region
+    - remoteproc: qcom_wcnss: Add missing of_node_put() in
+      wcnss_alloc_memory_region
+    - clk: actions: Terminate clk_div_table with sentinel element
+    - clk: loongson1: Terminate clk_div_table with sentinel element
+    - clk: clps711x: Terminate clk_div_table with sentinel element
+    - clk: tegra: tegra124-emc: Fix missing put_device() call in
+      emc_ensure_emc_driver
+    - NFS: remove unneeded check in decode_devicenotify_args()
+    - staging: mt7621-dts: fix LEDs and pinctrl on GB-PC1 devicetree
+    - pinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_init
+    - pinctrl: mediatek: paris: Fix "argument" argument type for mtk_pinconf_get()
+    - pinctrl: mediatek: paris: Fix pingroup pin config state readback
+    - pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe
+    - pinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe
+    - tty: hvc: fix return value of __setup handler
+    - kgdboc: fix return value of __setup handler
+    - kgdbts: fix return value of __setup handler
+    - firmware: google: Properly state IOMEM dependency
+    - driver core: dd: fix return value of __setup handler
+    - jfs: fix divide error in dbNextAG
+    - netfilter: nf_conntrack_tcp: preserve liberal flag in tcp options
+    - NFSv4.1: don't retry BIND_CONN_TO_SESSION on session error
+    - clk: qcom: gcc-msm8994: Fix gpll4 width
+    - clk: Initialize orphan req_rate
+    - xen: fix is_xen_pmu()
+    - net: phy: broadcom: Fix brcm_fet_config_init()
+    - selftests: test_vxlan_under_vrf: Fix broken test case
+    - qlcnic: dcb: default to returning -EOPNOTSUPP
+    - net/x25: Fix null-ptr-deref caused by x25_disconnect
+    - NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
+    - net: dsa: bcm_sf2_cfp: fix an incorrect NULL check on list iterator
+    - lib/test: use after free in register_test_dev_kmod()
+    - LSM: general protection fault in legacy_parse_param
+    - gcc-plugins/stackleak: Exactly match strings instead of prefixes
+    - pinctrl: npcm: Fix broken references to chip->parent_device
+    - block, bfq: don't move oom_bfqq
+    - selinux: use correct type for context length
+    - loop: use sysfs_emit() in the sysfs xxx show()
+    - Fix incorrect type in assignment of ipv6 port for audit
+    - irqchip/qcom-pdc: Fix broken locking
+    - irqchip/nvic: Release nvic_base upon failure
+    - bfq: fix use-after-free in bfq_dispatch_request
+    - ACPICA: Avoid walking the ACPI Namespace if it is not there
+    - lib/raid6/test/Makefile: Use $(pound) instead of \# for Make 4.3
+    - Revert "Revert "block, bfq: honor already-setup queue merges""
+    - ACPI/APEI: Limit printable size of BERT table data
+    - PM: core: keep irq flags in device_pm_check_callbacks()
+    - spi: tegra20: Use of_device_get_match_data()
+    - ext4: don't BUG if someone dirty pages without asking ext4 first
+    - ntfs: add sanity check on allocation size
+    - video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow
+    - video: fbdev: w100fb: Reset global state
+    - video: fbdev: cirrusfb: check pixclock to avoid divide by zero
+    - video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit
+    - ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960
+    - ARM: dts: bcm2837: Add the missing L1/L2 cache information
+    - ASoC: madera: Add dependencies on MFD
+    - video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf()
+    - video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of
+      snprintf()
+    - video: fbdev: udlfb: replace snprintf in show functions with sysfs_emit
+    - ASoC: soc-core: skip zero num_dai component in searching dai name
+    - media: cx88-mpeg: clear interrupt status register before streaming video
+    - ARM: tegra: tamonten: Fix I2C3 pad setting
+    - ARM: mmp: Fix failure to remove sram device
+    - video: fbdev: sm712fb: Fix crash in smtcfb_write()
+    - media: Revert "media: em28xx: add missing em28xx_close_extension"
+    - media: hdpvr: initialize dev->worker at hdpvr_register_videodev
+    - mmc: host: Return an error when ->enable_sdio_irq() ops is missing
+    - ALSA: hda/realtek: Add alc256-samsung-headphone fixup
+    - powerpc/lib/sstep: Fix 'sthcx' instruction
+    - powerpc/lib/sstep: Fix build errors with newer binutils
+    - powerpc: Fix build errors with newer binutils
+    - scsi: qla2xxx: Fix stuck session in gpdb
+    - scsi: qla2xxx: Fix wrong FDMI data for 64G adapter
+    - scsi: qla2xxx: Fix warning for missing error code
+    - scsi: qla2xxx: Fix device reconnect in loop topology
+    - scsi: qla2xxx: Add devids and conditionals for 28xx
+    - scsi: qla2xxx: Check for firmware dump already collected
+    - scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair()
+    - scsi: qla2xxx: Fix disk failure to rediscover
+    - scsi: qla2xxx: Fix incorrect reporting of task management failure
+    - scsi: qla2xxx: Fix hang due to session stuck
+    - scsi: qla2xxx: Fix missed DMA unmap for NVMe ls requests
+    - scsi: qla2xxx: Fix N2N inconsistent PLOGI
+    - scsi: qla2xxx: Reduce false trigger to login
+    - scsi: qla2xxx: Use correct feature type field during RFF_ID processing
+    - KVM: Prevent module exit until all VMs are freed
+    - KVM: x86: fix sending PV IPI
+    - ASoC: SOF: Intel: Fix NULL ptr dereference when ENOMEM
+    - ubifs: rename_whiteout: Fix double free for whiteout_ui->data
+    - ubifs: Fix deadlock in concurrent rename whiteout and inode writeback
+    - ubifs: Add missing iput if do_tmpfile() failed in rename whiteout
+    - ubifs: setflags: Make dirtied_ino_d 8 bytes aligned
+    - ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()
+    - ubifs: rename_whiteout: correct old_dir size computing
+    - XArray: Fix xas_create_range() when multi-order entry present
+    - can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path
+    - can: mcba_usb: properly check endpoint type
+    - XArray: Update the LRU list in xas_split()
+    - rtc: check if __rtc_read_time was successful
+    - gfs2: Make sure FITRIM minlen is rounded up to fs block size
+    - net: hns3: fix software vlan talbe of vlan 0 inconsistent with hardware
+    - pinctrl: pinconf-generic: Print arguments for bias-pull-*
+    - pinctrl: nuvoton: npcm7xx: Rename DS() macro to DSTR()
+    - pinctrl: nuvoton: npcm7xx: Use %zu printk format for ARRAY_SIZE()
+    - ASoC: mediatek: mt6358: add missing EXPORT_SYMBOLs
+    - ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
+    - ARM: iop32x: offset IRQ numbers by 1
+    - ACPI: CPPC: Avoid out of bounds access when parsing _CPC data
+    - powerpc/kasan: Fix early region not updated correctly
+    - ASoC: soc-compress: Change the check for codec_dai
+    - mm/mmap: return 1 from stack_guard_gap __setup() handler
+    - mm/memcontrol: return 1 from cgroup.memory __setup() handler
+    - mm/usercopy: return 1 from hardened_usercopy __setup() handler
+    - bpf: Fix comment for helper bpf_current_task_under_cgroup()
+    - dt-bindings: mtd: nand-controller: Fix the reg property description
+    - dt-bindings: mtd: nand-controller: Fix a comment in the examples
+    - dt-bindings: spi: mxic: The interrupt property is not mandatory
+    - ubi: fastmap: Return error code if memory allocation fails in add_aeb()
+    - ASoC: topology: Allow TLV control to be either read or write
+    - ARM: dts: spear1340: Update serial node properties
+    - ARM: dts: spear13xx: Update SPI dma properties
+    - um: Fix uml_mconsole stop/go
+    - openvswitch: Fixed nd target mask field in the flow dump.
+    - KVM: x86/mmu: do compare-and-exchange of gPTE via the user address
+    - KVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activated
+    - ubifs: Rectify space amount budget for mkdir/tmpfile operations
+    - rtc: wm8350: Handle error for wm8350_register_irq
+    - riscv module: remove (NOLOAD)
+    - ARM: 9187/1: JIVE: fix return value of __setup handler
+    - KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs
+    - drm: Add orientation quirk for GPD Win Max
+    - ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111
+    - drm/amd/amdgpu/amdgpu_cs: fix refcount leak of a dma_fence obj
+    - ptp: replace snprintf with sysfs_emit
+    - powerpc: dts: t104xrdb: fix phy type for FMAN 4/5
+    - bpf: Make dst_port field in struct bpf_sock 16-bit wide
+    - scsi: mvsas: Replace snprintf() with sysfs_emit()
+    - scsi: bfa: Replace snprintf() with sysfs_emit()
+    - power: supply: axp20x_battery: properly report current when discharging
+    - ipv6: make mc_forwarding atomic
+    - powerpc: Set crashkernel offset to mid of RMA region
+    - drm/amdgpu: Fix recursive locking warning
+    - PCI: aardvark: Fix support for MSI interrupts
+    - iommu/arm-smmu-v3: fix event handling soft lockup
+    - usb: ehci: add pci device support for Aspeed platforms
+    - PCI: pciehp: Add Qualcomm quirk for Command Completed erratum
+    - power: supply: axp288-charger: Set Vhold to 4.4V
+    - ipv4: Invalidate neighbour for broadcast address upon address addition
+    - dm ioctl: prevent potential spectre v1 gadget
+    - drm/amdkfd: make CRAT table missing message informational only
+    - scsi: pm8001: Fix pm8001_mpi_task_abort_resp()
+    - scsi: aha152x: Fix aha152x_setup() __setup handler return value
+    - net/smc: correct settings of RMB window update limit
+    - mips: ralink: fix a refcount leak in ill_acc_of_setup()
+    - macvtap: advertise link netns via netlink
+    - tuntap: add sanity checks about msg_controllen in sendmsg
+    - bnxt_en: Eliminate unintended link toggle during FW reset
+    - MIPS: fix fortify panic when copying asm exception handlers
+    - scsi: libfc: Fix use after free in fc_exch_abts_resp()
+    - usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evm
+    - xtensa: fix DTC warning unit_address_format
+    - Bluetooth: Fix use after free in hci_send_acl
+    - netlabel: fix out-of-bounds memory accesses
+    - init/main.c: return 1 from handled __setup() functions
+    - minix: fix bug when opening a file with O_DIRECT
+    - clk: si5341: fix reported clk_rate when output divider is 2
+    - w1: w1_therm: fixes w1_seq for ds28ea00 sensors
+    - NFSv4: Protect the state recovery thread against direct reclaim
+    - xen: delay xen_hvm_init_time_ops() if kdump is boot on vcpu>=32
+    - clk: Enforce that disjoints limits are invalid
+    - SUNRPC/call_alloc: async tasks mustn't block waiting for memory
+    - NFS: swap IO handling is slightly different for O_DIRECT IO
+    - NFS: swap-out must always use STABLE writes.
+    - serial: samsung_tty: do not unlock port->lock for uart_write_wakeup()
+    - virtio_console: eliminate anonymous module_init & module_exit
+    - jfs: prevent NULL deref in diFree
+    - SUNRPC: Fix socket waits for write buffer space
+    - parisc: Fix CPU affinity for Lasi, WAX and Dino chips
+    - parisc: Fix patch code locking and flushing
+    - mm: fix race between MADV_FREE reclaim and blkdev direct IO read
+    - KVM: arm64: Check arm64_get_bp_hardening_data() didn't return NULL
+    - drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire()
+    - Drivers: hv: vmbus: Fix potential crash on module unload
+    - scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one()
+    - net/tls: fix slab-out-of-bounds bug in decrypt_internal
+    - net: ipv4: fix route with nexthop object delete warning
+    - net: stmmac: Fix unset max_speed difference between DT and non-DT platforms
+    - drm/imx: Fix memory leak in imx_pd_connector_get_modes
+    - bnxt_en: reserve space inside receive page for skb_shared_info
+    - IB/rdmavt: add lock to call to rvt_error_qp to prevent a race condition
+    - dpaa2-ptp: Fix refcount leak in dpaa2_ptp_probe
+    - ipv6: Fix stats accounting in ip6_pkt_drop
+    - net: openvswitch: don't send internal clone attribute to the userspace.
+    - rxrpc: fix a race in rxrpc_exit_net()
+    - qede: confirm skb is allocated before using
+    - spi: bcm-qspi: fix MSPI only access with bcm_qspi_exec_mem_op()
+    - bpf: Support dual-stack sockets in bpf_tcp_check_syncookie
+    - drbd: Fix five use after free bugs in get_initial_state
+    - SUNRPC: Handle ENOMEM in call_transmit_status()
+    - SUNRPC: Handle low memory situations in call_status()
+    - perf tools: Fix perf's libperf_print callback
+    - perf session: Remap buf if there is no space for event
+    - Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"
+    - mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is
+      complete
+    - lz4: fix LZ4_decompress_safe_partial read out of bound
+    - mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0)
+    - mm/mempolicy: fix mpol_new leak in shared_policy_replace
+    - x86/pm: Save the MSR validity status at context setup
+    - x86/speculation: Restore speculation related MSRs during S3 resume
+    - btrfs: fix qgroup reserve overflow the qgroup limit
+    - arm64: patch_text: Fixup last cpu should be master
+    - ata: sata_dwc_460ex: Fix crash due to OOB write
+    - perf: qcom_l2_pmu: fix an incorrect NULL check on list iterator
+    - irqchip/gic-v3: Fix GICR_CTLR.RWP polling
+    - tools build: Filter out options and warnings not supported by clang
+    - tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts
+    - dmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error"
+    - mmc: mmci_sdmmc: Replace sg_dma_xxx macros
+    - mmc: mmci: stm32: correctly check all elements of sg list
+    - mm: don't skip swap entry even if zap_details specified
+    - arm64: module: remove (NOLOAD) from linker script
+    - mm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning
+    - drm/amdkfd: add missing void argument to function kgd2kfd_init
+    - drm/amdkfd: Fix -Wstrict-prototypes from
+      amdgpu_amdkfd_gfx_10_0_get_functions()
+    - cgroup: Use open-time credentials for process migraton perm checks
+    - cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv
+    - cgroup: Use open-time cgroup namespace for process migration perm checks
+    - selftests: cgroup: Make cg_create() use 0755 for permission instead of 0644
+    - selftests: cgroup: Test open-time credential usage for migration checks
+    - selftests: cgroup: Test open-time cgroup namespace usage for migration
+      checks
+    - cpuidle: PSCI: Move the `has_lpi` check to the beginning of the function
+    - ACPI: processor idle: Check for architectural support for LPI
+    - Linux 5.4.189
+
+  * Focal update: v5.4.188 upstream stable release (LP: #1971496)
+    - nfsd: cleanup nfsd_file_lru_dispose()
+    - nfsd: Containerise filecache laundrette
+    - net: ipv6: fix skb_over_panic in __ip6_append_data
+    - tpm: Fix error handling in async work
+    - staging: fbtft: fb_st7789v: reset display before initialization
+    - thermal: int340x: fix memory leak in int3400_notify()
+    - llc: fix netdevice reference leaks in llc_ui_bind()
+    - ALSA: pcm: Add stream lock during PCM reset ioctl operations
+    - ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB
+    - ALSA: cmipci: Restore aux vol on suspend/resume
+    - ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec
+    - drivers: net: xgene: Fix regression in CRC stripping
+    - ASoC: sti: Fix deadlock via snd_pcm_stop_xrun() call
+    - ALSA: oss: Fix PCM OSS buffer allocation overflow
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek: Add quirk for ASUS GA402
+    - ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
+    - ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
+    - ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU
+    - crypto: qat - disable registration of algorithms
+    - rcu: Don't deboost before reporting expedited quiescent state
+    - mac80211: fix potential double free on mesh join
+    - tpm: use try_get_ops() in tpm-space.c
+    - nds32: fix access_ok() checks in get/put_user
+    - llc: only change llc->dev when bind() succeeds
+    - Linux 5.4.188
+
+  * Focal update: v5.4.187 upstream stable release (LP: #1971493)
+    - crypto: qcom-rng - ensure buffer for generate is completely filled
+    - ocfs2: fix crash when initialize filecheck kobj fails
+    - efi: fix return value of __setup handlers
+    - net: phy: marvell: Fix invalid comparison in the resume and suspend
+      functions
+    - net/packet: fix slab-out-of-bounds access in packet_recvmsg()
+    - atm: eni: Add check for dma_map_single
+    - hv_netvsc: Add check for kvmalloc_array
+    - drm/panel: simple: Fix Innolux G070Y2-L01 BPP settings
+    - net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit()
+    - net: dsa: Add missing of_node_put() in dsa_port_parse_of
+    - arm64: fix clang warning about TRAMP_VALIAS
+    - usb: gadget: rndis: prevent integer overflow in rndis_set_response()
+    - usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
+    - usb: usbtmc: Fix bug in pipe direction for control transfers
+    - Input: aiptek - properly check endpoint type
+    - perf symbols: Fix symbol size calculation condition
+    - Linux 5.4.187
+
+  * Focal update: v5.4.186 upstream stable release (LP: #1969678)
+    - Revert "xfrm: state and policy should fail if XFRMA_IF_ID 0"
+    - sctp: fix the processing for INIT chunk
+    - xfrm: Check if_id in xfrm_migrate
+    - xfrm: Fix xfrm migrate issues when address family changes
+    - arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity
+    - arm64: dts: rockchip: reorder rk3399 hdmi clocks
+    - arm64: dts: agilex: use the compatible "intel,socfpga-agilex-hsotg"
+    - ARM: dts: rockchip: reorder rk322x hmdi clocks
+    - ARM: dts: rockchip: fix a typo on rk3288 crypto-controller
+    - mac80211: refuse aggregations sessions before authorized
+    - MIPS: smp: fill in sibling and core maps earlier
+    - ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE
+    - can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when
+      fully ready
+    - atm: firestream: check the return value of ioremap() in fs_init()
+    - iwlwifi: don't advertise TWT support
+    - drm/vrr: Set VRR capable prop only if it is attached to connector
+    - nl80211: Update bss channel on channel switch for P2P_CLIENT
+    - tcp: make tcp_read_sock() more robust
+    - sfc: extend the locking on mcdi->seqno
+    - kselftest/vm: fix tests build with old libc
+    - fixup for "arm64 entry: Add macro for reading symbol address from the
+      trampoline"
+    - Linux 5.4.186
+
+  * Focal update: v5.4.185 upstream stable release (LP: #1969672)
+    - clk: qcom: gdsc: Add support to update GDSC transition delay
+    - arm64: dts: armada-3720-turris-mox: Add missing ethernet0 alias
+    - virtio-blk: Don't use MAX_DISCARD_SEGMENTS if max_discard_seg is zero
+    - net: qlogic: check the return value of dma_alloc_coherent() in
+      qed_vf_hw_prepare()
+    - qed: return status of qed_iov_get_link
+    - drm/sun4i: mixer: Fix P010 and P210 format numbers
+    - ARM: dts: aspeed: Fix AST2600 quad spi group
+    - ethernet: Fix error handling in xemaclite_of_probe
+    - net: ethernet: ti: cpts: Handle error for clk_enable
+    - net: ethernet: lpc_eth: Handle error for clk_enable
+    - ax25: Fix NULL pointer dereference in ax25_kill_by_device
+    - net/mlx5: Fix size field in bufferx_reg struct
+    - net/mlx5: Fix a race on command flush flow
+    - NFC: port100: fix use-after-free in port100_send_complete
+    - selftests: pmtu.sh: Kill tcpdump processes launched by subshell.
+    - gpio: ts4900: Do not set DAT and OE together
+    - gianfar: ethtool: Fix refcount leak in gfar_get_ts_info
+    - net: phy: DP83822: clear MISR2 register to disable interrupts
+    - sctp: fix kernel-infoleak for SCTP sockets
+    - net: bcmgenet: Don't claim WOL when its not available
+    - net-sysfs: add check for netdevice being present to speed_show
+    - Revert "xen-netback: remove 'hotplug-status' once it has served its purpose"
+    - Revert "xen-netback: Check for hotplug-status existence before watching"
+    - ipv6: prevent a possible race condition with lifetimes
+    - tracing: Ensure trace buffer is at least 4096 bytes large
+    - selftest/vm: fix map_fixed_noreplace test failure
+    - selftests/memfd: clean up mapping in mfd_fail_write
+    - ARM: Spectre-BHB: provide empty stub for non-config
+    - fuse: fix pipe buffer lifetime for direct_io
+    - staging: gdm724x: fix use after free in gdm_lte_rx()
+    - net: macb: Fix lost RX packet wakeup race in NAPI receive
+    - mmc: meson: Fix usage of meson_mmc_post_req()
+    - riscv: Fix auipc+jalr relocation range checks
+    - arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0
+    - virtio: unexport virtio_finalize_features
+    - virtio: acknowledge all features before access
+    - ARM: fix Thumb2 regression with Spectre BHB
+    - ext4: add check to prevent attempting to resize an fs with sparse_super2
+    - x86/cpufeatures: Mark two free bits in word 3
+    - x86/cpu: Add hardware-enforced cache coherency as a CPUID feature
+    - x86/mm/pat: Don't flush cache if hardware enforces cache coherency across
+      encryption domnains
+    - KVM: SVM: Don't flush cache if hardware enforces cache coherency across
+      encryption domains
+    - Linux 5.4.185
+
+  * Focal update: v5.4.184 upstream stable release (LP: #1969242)
+    - arm/arm64: Provide a wrapper for SMCCC 1.1 calls
+    - arm/arm64: smccc/psci: add arm_smccc_1_1_get_conduit()
+    - ARM: report Spectre v2 status through sysfs
+    - ARM: early traps initialisation
+    - ARM: use LOADADDR() to get load address of sections
+    - [Config] updateconfigs for HARDEN_BRANCH_HISTORY
+    - ARM: Spectre-BHB workaround
+    - ARM: include unprivileged BPF status in Spectre V2 reporting
+    - ARM: fix build error when BPF_SYSCALL is disabled
+    - ARM: fix co-processor register typo
+    - ARM: Do not use NOCROSSREFS directive with ld.lld
+    - ARM: fix build warning in proc-v7-bugs.c
+    - xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
+    - xen/grant-table: add gnttab_try_end_foreign_access()
+    - xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/netfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/scsifront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/gntalloc: don't use gnttab_query_foreign_access()
+    - xen: remove gnttab_query_foreign_access()
+    - xen/9p: use alloc/free_pages_exact()
+    - xen/pvcalls: use alloc/free_pages_exact()
+    - xen/gnttab: fix gnttab_end_foreign_access() without page specified
+    - xen/netfront: react properly to failing gnttab_end_foreign_access_ref()
+    - Linux 5.4.184
+
+  * Focal update: v5.4.183 upstream stable release (LP: #1969239)
+    - mac80211_hwsim: report NOACK frames in tx_status
+    - mac80211_hwsim: initialize ieee80211_tx_info at hw_scan_work
+    - i2c: bcm2835: Avoid clock stretching timeouts
+    - ASoC: rt5668: do not block workqueue if card is unbound
+    - ASoC: rt5682: do not block workqueue if card is unbound
+    - Input: clear BTN_RIGHT/MIDDLE on buttonpads
+    - cifs: fix double free race when mount fails in cifs_get_root()
+    - dmaengine: shdma: Fix runtime PM imbalance on error
+    - i2c: cadence: allow COMPILE_TEST
+    - i2c: qup: allow COMPILE_TEST
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FN990
+    - usb: gadget: don't release an existing dev->buf
+    - usb: gadget: clear related members when goto fail
+    - ata: pata_hpt37x: fix PCI clock detection
+    - ALSA: intel_hdmi: Fix reference to PCM buffer address
+    - ASoC: ops: Shift tested values in snd_soc_put_volsw() by +min
+    - xfrm: fix MTU regression
+    - netfilter: fix use-after-free in __nf_register_net_hook()
+    - xfrm: enforce validity of offload input flags
+    - netfilter: nf_queue: don't assume sk is full socket
+    - netfilter: nf_queue: fix possible use-after-free
+    - batman-adv: Request iflink once in batadv-on-batadv check
+    - batman-adv: Request iflink once in batadv_get_real_netdevice
+    - batman-adv: Don't expect inter-netns unique iflink indices
+    - net: dcb: flush lingering app table entries for unregistered devices
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error generated by client
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error cause by server
+    - block: Fix fsync always failed if once failed
+    - xen/netfront: destroy queues before real_num_tx_queues is zeroed
+    - sched/topology: Make sched_init_numa() use a set for the deduplicating sort
+    - sched/topology: Fix sched_domain_topology_level alloc in sched_init_numa()
+    - ia64: ensure proper NUMA distance and possible map initialization
+    - mac80211: fix forwarded mesh frames AC & queue selection
+    - net: stmmac: fix return value of __setup handler
+    - iavf: Fix missing check for running netdev
+    - net: sxgbe: fix return value of __setup handler
+    - net: arcnet: com20020: Fix null-ptr-deref in com20020pci_probe()
+    - ixgbe: xsk: change !netif_carrier_ok() handling in ixgbe_xmit_zc()
+    - efivars: Respect "block" flag in efivar_entry_set_safe()
+    - firmware: arm_scmi: Remove space in MODULE_ALIAS name
+    - ASoC: cs4265: Fix the duplicated control name
+    - can: gs_usb: change active_channels's type from atomic_t to u8
+    - arm64: dts: rockchip: Switch RK3399-Gru DP to SPDIF output
+    - igc: igc_read_phy_reg_gpy: drop premature return
+    - ARM: Fix kgdb breakpoint for Thumb2
+    - ARM: 9182/1: mmu: fix returns from early_param() and __setup() functions
+    - igc: igc_write_phy_reg_gpy: drop premature return
+    - ibmvnic: free reset-work-item when flushing
+    - memfd: fix F_SEAL_WRITE after shmem huge page allocated
+    - soc: fsl: qe: Check of ioremap return value
+    - net: chelsio: cxgb3: check the return value of pci_find_capability()
+    - nl80211: Handle nla_memdup failures in handle_nan_filter
+    - Input: elan_i2c - move regulator_[en|dis]able() out of
+      elan_[en|dis]able_power()
+    - Input: elan_i2c - fix regulator enable count imbalance after suspend/resume
+    - HID: add mapping for KEY_DICTATE
+    - HID: add mapping for KEY_ALL_APPLICATIONS
+    - tracing/histogram: Fix sorting on old "cpu" value
+    - tracing: Fix return value of __setup handlers
+    - btrfs: fix lost prealloc extents beyond eof after full fsync
+    - btrfs: qgroup: fix deadlock between rescan worker and remove qgroup
+    - btrfs: add missing run of delayed items after unlink during log replay
+    - Revert "xfrm: xfrm_state_mtu should return at least 1280 for ipv6"
+    - net: dcb: disable softirqs in dcbnl_flush_dev()
+    - hamradio: fix macro redefine warning
+    - Linux 5.4.183
+
+  * Focal update: v5.4.182 upstream stable release (LP: #1969236)
+    - cgroup/cpuset: Fix a race between cpuset_attach() and cpu hotplug
+    - clk: jz4725b: fix mmc0 clock gating
+    - vhost/vsock: don't check owner in vhost_vsock_stop() while releasing
+    - parisc/unaligned: Fix fldd and fstd unaligned handlers on 32-bit kernel
+    - parisc/unaligned: Fix ldw() and stw() unalignment handlers
+    - drm/amdgpu: disable MMHUB PG for Picasso
+    - sr9700: sanity check for packet length
+    - USB: zaurus: support another broken Zaurus
+    - x86/fpu: Correct pkru/xstate inconsistency
+    - tee: export teedev_open() and teedev_close_context()
+    - optee: use driver internal tee_context for some rpc
+    - lan743x: fix deadlock in lan743x_phy_link_status_change()
+    - ping: remove pr_err from ping_lookup
+    - perf data: Fix double free in perf_session__delete()
+    - bpf: Do not try bpf_msg_push_data with len 0
+    - net: __pskb_pull_tail() & pskb_carve_frag_list() drop_monitor friends
+    - tipc: Fix end of loop tests for list_for_each_entry()
+    - gso: do not skip outer ip header in case of ipip and net_failover
+    - openvswitch: Fix setting ipv6 fields causing hw csum failure
+    - drm/edid: Always set RGB444
+    - net/mlx5e: Fix wrong return value on ioctl EEPROM query failure
+    - net: ll_temac: check the return value of devm_kmalloc()
+    - net: Force inlining of checksum functions in net/checksum.h
+    - nfp: flower: Fix a potential leak in nfp_tunnel_add_shared_mac()
+    - netfilter: nf_tables: fix memory leak during stateful obj update
+    - net/mlx5: Fix possible deadlock on rule deletion
+    - net/mlx5: Fix wrong limitation of metadata match on ecpf
+    - spi: spi-zynq-qspi: Fix a NULL pointer dereference in
+      zynq_qspi_exec_mem_op()
+    - configfs: fix a race in configfs_{,un}register_subsystem()
+    - RDMA/ib_srp: Fix a deadlock
+    - tracing: Have traceon and traceoff trigger honor the instance
+    - iio: adc: men_z188_adc: Fix a resource leak in an error handling path
+    - iio: adc: ad7124: fix mask used for setting AIN_BUFP & AIN_BUFM bits
+    - iio: Fix error handling for PM
+    - ata: pata_hpt37x: disable primary channel on HPT371
+    - Revert "USB: serial: ch341: add new Product ID for CH341A"
+    - usb: gadget: rndis: add spinlock for rndis response list
+    - tracefs: Set the group ownership in apply_options() not parse_options()
+    - USB: serial: option: add support for DW5829e
+    - USB: serial: option: add Telit LE910R1 compositions
+    - usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
+    - usb: dwc3: gadget: Let the interrupt handler disable bottom halves.
+    - xhci: re-initialize the HC during resume if HCE was set
+    - xhci: Prevent futile URB re-submissions due to incorrect return value.
+    - tty: n_gsm: fix encoding of control signal octet bit DV
+    - tty: n_gsm: fix proper link termination after failed open
+    - tty: n_gsm: fix NULL pointer access due to DLCI release
+    - gpio: tegra186: Fix chip_data type confusion
+    - Revert "drm/nouveau/pmu/gm200-: avoid touching PMU outside of
+      DEVINIT/PREOS/ACR"
+    - memblock: use kfree() to release kmalloced memblock regions
+    - fget: clarify and improve __fget_files() implementation
+    - Linux 5.4.182
+
+  * CVE-2022-28390
+    - can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 20 May 2022 15:31:22 +0200
+
+linux (5.4.0-113.127) focal; urgency=medium
+
+  * focal/linux: 5.4.0-113.127 -proposed tracker (LP: #1973980)
+
+  * CVE-2022-29581
+    - net/sched: cls_u32: fix netns refcount changes in u32_change()
+
+  * CVE-2022-1116
+    - io_uring: fix fs->users overflow
+
+  * ext4: limit length to bitmap_maxbytes (LP: #1972281)
+    - ext4: limit length to bitmap_maxbytes - blocksize in punch_hole
+
+  * 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
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 18 May 2022 16:07:54 +0200
+
+linux (5.4.0-110.124) focal; urgency=medium
+
+  * focal/linux: 5.4.0-110.124 -proposed tracker (LP: #1969053)
+
+  * net/mlx5e: Fix page DMA map/unmap attributes (LP: #1967292)
+    - net/mlx5e: Fix page DMA map/unmap attributes
+
+  * xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+    (LP: #1966803)
+    - xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+
+  * LRMv6: add multi-architecture support (LP: #1968774)
+    - [Packaging] resync dkms-build{,--nvidia-N}
+
+  * xfrm interface cannot be changed anymore (LP: #1968591)
+    - xfrm: fix the if_id check in changelink
+
+  * Use kernel-testing repo from launchpad for ADT tests (LP: #1968016)
+    - [Debian] Use kernel-testing repo from launchpad
+
+  * vmx_ldtr_test in ubuntu_kvm_unit_tests failed (FAIL: Expected 0 for L1 LDTR
+    selector (got 50)) (LP: #1956315)
+    - KVM: nVMX: Set LDTR to its architecturally defined value on nested VM-Exit
+
+  * [SRU][Regression] Revert "PM: ACPI: reboot: Use S5 for reboot" which causes
+    Bus Fatal Error when rebooting system with BCM5720 NIC (LP: #1917471)
+    - Revert "PM: ACPI: reboot: Use S5 for reboot"
+
+  * Focal update: v5.4.181 upstream stable release (LP: #1967582)
+    - Makefile.extrawarn: Move -Wunaligned-access to W=1
+    - HID:Add support for UGTABLET WP5540
+    - Revert "svm: Add warning message for AVIC IPI invalid target"
+    - serial: parisc: GSC: fix build when IOSAPIC is not set
+    - parisc: Drop __init from map_pages declaration
+    - parisc: Fix data TLB miss in sba_unmap_sg
+    - parisc: Fix sglist access in ccio-dma.c
+    - btrfs: send: in case of IO error log it
+    - platform/x86: ISST: Fix possible circular locking dependency detected
+    - selftests: rtc: Increase test timeout so that all tests run
+    - net: ieee802154: at86rf230: Stop leaking skb's
+    - selftests/zram: Skip max_comp_streams interface on newer kernel
+    - selftests/zram01.sh: Fix compression ratio calculation
+    - selftests/zram: Adapt the situation that /dev/zram0 is being used
+    - ax25: improve the incomplete fix to avoid UAF and NPD bugs
+    - vfs: make freeze_super abort when sync_filesystem returns error
+    - quota: make dquot_quota_sync return errors from ->sync_fs
+    - nvme: fix a possible use-after-free in controller reset during load
+    - nvme-tcp: fix possible use-after-free in transport error_recovery work
+    - nvme-rdma: fix possible use-after-free in transport error_recovery work
+    - drm/amdgpu: fix logic inversion in check
+    - Revert "module, async: async_synchronize_full() on module init iff async is
+      used"
+    - ftrace: add ftrace_init_nop()
+    - module/ftrace: handle patchable-function-entry
+    - arm64: module: rework special section handling
+    - arm64: module/ftrace: intialize PLT at load time
+    - iwlwifi: fix use-after-free
+    - drm/radeon: Fix backlight control on iMac 12,1
+    - ext4: check for out-of-order index extents in ext4_valid_extent_entries()
+    - ext4: check for inconsistent extents between index and leaf block
+    - ext4: prevent partial update of the extent blocks
+    - taskstats: Cleanup the use of task->exit_code
+    - dmaengine: at_xdmac: Start transfer for cyclic channels in issue_pending
+    - vsock: remove vsock from connected table when connect is interrupted by a
+      signal
+    - mmc: block: fix read single on recovery logic
+    - iwlwifi: pcie: fix locking when "HW not ready"
+    - iwlwifi: pcie: gen2: fix locking when "HW not ready"
+    - netfilter: nft_synproxy: unregister hooks on init error path
+    - net: dsa: lan9303: fix reset on probe
+    - net: ieee802154: ca8210: Fix lifs/sifs periods
+    - ping: fix the dif and sdif check in ping_lookup
+    - bonding: force carrier update when releasing slave
+    - drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit
+    - bonding: fix data-races around agg_select_timer
+    - libsubcmd: Fix use-after-free for realloc(..., 0)
+    - ALSA: hda: Fix regression on forced probe mask option
+    - ALSA: hda: Fix missing codec probe on Shenker Dock 15
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw()
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw_range()
+    - powerpc/lib/sstep: fix 'ptesync' build error
+    - mtd: rawnand: gpmi: don't leak PM reference in error path
+    - block/wbt: fix negative inflight counter when remove scsi device
+    - NFS: LOOKUP_DIRECTORY is also ok with symlinks
+    - NFS: Do not report writeback errors in nfs_getattr()
+    - mtd: rawnand: qcom: Fix clock sequencing in qcom_nandc_probe()
+    - mtd: rawnand: brcmnand: Fixed incorrect sub-page ECC status
+    - scsi: lpfc: Fix pt2pt NVMe PRLI reject LOGO loop
+    - EDAC: Fix calculation of returned address and next offset in
+      edac_align_ptr()
+    - net: sched: limit TC_ACT_REPEAT loops
+    - dmaengine: sh: rcar-dmac: Check for error num after setting mask
+    - copy_process(): Move fd_install() out of sighand->siglock critical section
+    - i2c: brcmstb: fix support for DSL and CM variants
+    - Drivers: hv: vmbus: Fix memory leak in vmbus_add_channel_kobj
+    - KVM: x86/pmu: Use AMD64_RAW_EVENT_MASK for PERF_TYPE_RAW
+    - ARM: OMAP2+: hwmod: Add of_node_put() before break
+    - ARM: OMAP2+: adjust the location of put_device() call in omapdss_init_of
+    - irqchip/sifive-plic: Add missing thead,c900-plic match string
+    - netfilter: conntrack: don't refresh sctp entries in closed state
+    - arm64: dts: meson-gx: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: drop BL32 region from SEI510/SEI610
+    - kconfig: let 'shell' return enough output for deep path names
+    - ata: libata-core: Disable TRIM on M88V29
+    - drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
+    - tracing: Fix tp_printk option related with tp_printk_stop_on_boot
+    - net: usb: qmi_wwan: Add support for Dell DW5829e
+    - net: macb: Align the dma and coherent dma masks
+    - kconfig: fix failing to generate auto.conf
+    - Linux 5.4.181
+
+  * Focal update: v5.4.180 upstream stable release (LP: #1966118)
+    - integrity: check the return value of audit_log_start()
+    - ima: Remove ima_policy file before directory
+    - ima: Allow template selection with ima_template[_fmt]= after ima_hash=
+    - ima: Do not print policy rule with inactive LSM labels
+    - mmc: sdhci-of-esdhc: Check for error num after setting mask
+    - net: phy: marvell: Fix RGMII Tx/Rx delays setting in 88e1121-compatible PHYs
+    - net: phy: marvell: Fix MDI-x polarity setting in 88e1118-compatible PHYs
+    - NFS: Fix initialisation of nfs_client cl_flags field
+    - NFSD: Clamp WRITE offsets
+    - NFSD: Fix offset type in I/O trace points
+    - NFSv4 only print the label when its queried
+    - nfs: nfs4clinet: check the return value of kstrdup()
+    - NFSv4.1: Fix uninitialised variable in devicenotify
+    - NFSv4 remove zero number of fs_locations entries error check
+    - NFSv4 expose nfs_parse_server_name function
+    - drm: panel-orientation-quirks: Add quirk for the 1Netbook OneXPlayer
+    - net: sched: Clarify error message when qdisc kind is unknown
+    - scsi: target: iscsi: Make sure the np under each tpg is unique
+    - scsi: qedf: Fix refcount issue when LOGO is received during TMF
+    - scsi: myrs: Fix crash in error case
+    - PM: hibernate: Remove register_nosave_region_late()
+    - usb: dwc2: gadget: don't try to disable ep0 in dwc2_hsotg_suspend
+    - net: stmmac: dwmac-sun8i: use return val of readl_poll_timeout()
+    - KVM: nVMX: eVMCS: Filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER
+    - riscv: fix build with binutils 2.38
+    - ARM: dts: imx23-evk: Remove MX23_PAD_SSP1_DETECT from hog group
+    - ARM: socfpga: fix missing RESET_CONTROLLER
+    - nvme-tcp: fix bogus request completion when failing to send AER
+    - ACPI/IORT: Check node revision for PMCG resources
+    - PM: s2idle: ACPI: Fix wakeup interrupts handling
+    - net: bridge: fix stale eth hdr pointer in br_dev_xmit
+    - perf probe: Fix ppc64 'perf probe add events failed' case
+    - ARM: dts: meson: Fix the UART compatible strings
+    - staging: fbtft: Fix error path in fbtft_driver_module_init()
+    - ARM: dts: imx6qdl-udoo: Properly describe the SD card detect
+    - usb: f_fs: Fix use-after-free for epfile
+    - misc: fastrpc: avoid double fput() on failed usercopy
+    - ixgbevf: Require large buffers for build_skb on 82599VF
+    - bonding: pair enable_port with slave_arr_updates
+    - ipmr,ip6mr: acquire RTNL before calling ip[6]mr_free_table() on failure path
+    - nfp: flower: fix ida_idx not being released
+    - net: do not keep the dst cache when uncloning an skb dst and its metadata
+    - net: fix a memleak when uncloning an skb dst and its metadata
+    - veth: fix races around rq->rx_notify_masked
+    - net: mdio: aspeed: Add missing MODULE_DEVICE_TABLE
+    - tipc: rate limit warning for received illegal binding update
+    - net: amd-xgbe: disable interrupts during pci removal
+    - vt_ioctl: fix array_index_nospec in vt_setactivate
+    - vt_ioctl: add array_index_nospec to VT_ACTIVATE
+    - n_tty: wake up poll(POLLRDNORM) on receiving data
+    - eeprom: ee1004: limit i2c reads to I2C_SMBUS_BLOCK_MAX
+    - net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
+    - usb: ulpi: Move of_node_put to ulpi_dev_release
+    - usb: ulpi: Call of_node_put correctly
+    - usb: dwc3: gadget: Prevent core from processing stale TRBs
+    - usb: gadget: udc: renesas_usb3: Fix host to USB_ROLE_NONE transition
+    - USB: gadget: validate interface OS descriptor requests
+    - usb: gadget: rndis: check size of RNDIS_MSG_SET command
+    - usb: gadget: f_uac2: Define specific wTerminalType
+    - USB: serial: ftdi_sio: add support for Brainboxes US-159/235/320
+    - USB: serial: option: add ZTE MF286D modem
+    - USB: serial: ch341: add support for GW Instek USB2.0-Serial devices
+    - USB: serial: cp210x: add NCR Retail IO box id
+    - USB: serial: cp210x: add CPI Bulk Coin Recycler id
+    - seccomp: Invalidate seccomp mode to catch death failures
+    - hwmon: (dell-smm) Speed up setting of fan speed
+    - scsi: lpfc: Remove NVMe support if kernel has NVME_FC disabled
+    - perf: Fix list corruption in perf_cgroup_switch()
+    - Linux 5.4.180
+
+  * Focal update: v5.4.179 upstream stable release (LP: #1965591)
+    - moxart: fix potential use-after-free on remove path
+    - Linux 5.4.179
+
+  * CVE-2020-27820
+    - drm/nouveau: Add a dedicated mutex for the clients list
+    - drm/nouveau: clean up all clients on device removal
+
+  * CVE-2022-1016
+    - netfilter: nf_tables: initialize registers in nft_do_chain()
+
+  * CVE-2022-27223
+    - USB: gadget: validate endpoint index for xilinx udc
+
+  * CVE-2022-26490
+    - nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
+
+  * CVE-2021-26401
+    - x86/speculation: Use generic retpoline by default on AMD
+    - x86/speculation: Update link to AMD speculation whitepaper
+    - x86/speculation: Warn about Spectre v2 LFENCE mitigation
+    - x86/speculation: Warn about eIBRS + LFENCE + Unprivileged eBPF + SMT
+
+  * CVE-2022-0001
+    - x86/speculation: Include unprivileged eBPF status in Spectre v2 mitigation
+      reporting
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 14 Apr 2022 14:19:29 +0200
+
+linux (5.4.0-109.123) focal; urgency=medium
+
+  * focal/linux: 5.4.0-109.123 -proposed tracker (LP: #1968290)
+
+  * USB devices not detected during boot on USB 3.0 hubs (LP: #1968210)
+    - SAUCE: Revert "Revert "xhci: Set HCD flag to defer primary roothub
+      registration""
+    - SAUCE: Revert "Revert "usb: core: hcd: Add support for deferring roothub
+      registration""
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 08 Apr 2022 10:44:46 +0200
+
+linux (5.4.0-108.122) focal; urgency=medium
+
+  * focal/linux: 5.4.0-108.122 -proposed tracker (LP: #1966740)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync dkms-build{,--nvidia-N} from LRMv5
+    - debian/dkms-versions -- update from kernel-versions (main/2022.03.21)
+
+  * Low RX performance for 40G Solarflare NICs (LP: #1964512)
+    - SAUCE: sfc: The size of the RX recycle ring should be more flexible
+
+  * [UBUNTU 20.04] KVM: Enable storage key checking for intercepted instruction
+    (LP: #1962831)
+    - selftests: kvm: add _vm_ioctl
+    - selftests: kvm: Introduce the TEST_FAIL macro
+    - KVM: selftests: Add GUEST_ASSERT variants to pass values to host
+    - KVM: s390: gaccess: Refactor gpa and length calculation
+    - KVM: s390: gaccess: Refactor access address range check
+    - KVM: s390: gaccess: Cleanup access to guest pages
+    - s390/uaccess: introduce bit field for OAC specifier
+    - s390/uaccess: fix compile error
+    - s390/uaccess: Add copy_from/to_user_key functions
+    - KVM: s390: Honor storage keys when accessing guest memory
+    - KVM: s390: handle_tprot: Honor storage keys
+    - KVM: s390: selftests: Test TEST PROTECTION emulation
+    - KVM: s390: Add optional storage key checking to MEMOP IOCTL
+    - KVM: s390: Add vm IOCTL for key checked guest absolute memory access
+    - KVM: s390: Rename existing vcpu memop functions
+    - KVM: s390: Add capability for storage key extension of MEM_OP IOCTL
+    - KVM: s390: Update api documentation for memop ioctl
+    - KVM: s390: Clarify key argument for MEM_OP in api docs
+    - KVM: s390: Add missing vm MEM_OP size check
+
+  * 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon/sec2 - Add workqueue for SEC driver.
+    - crypto: hisilicon/sec2 - update SEC initialization and reset
+
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117)
+    - crypto: hisilicon - Use one workqueue per qm instead of per qp
+
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117) // 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon - Unify hardware error init/uninit into QM
+
+  * [UBUNTU 20.04] Fix SIGP processing on KVM/s390 (LP: #1962578)
+    - KVM: s390: Simplify SIGP Set Arch handling
+    - KVM: s390: Add a routine for setting userspace CPU state
+
+  * Move virtual graphics drivers from linux-modules-extra to linux-modules
+    (LP: #1960633)
+    - [Packaging] Move VM DRM drivers into modules
+
+  * Focal update: v5.4.178 upstream stable release (LP: #1964634)
+    - audit: improve audit queue handling when "audit=1" on cmdline
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw_sx()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_xr_sx()
+    - ALSA: usb-audio: Simplify quirk entries with a macro
+    - ALSA: hda/realtek: Add quirk for ASUS GU603
+    - ALSA: hda/realtek: Add missing fixup-model entry for Gigabyte X570 ALC1220
+      quirks
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570S Aorus Master (newer
+      chipset)
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570 Aorus Xtreme after
+      reboot from Windows
+    - btrfs: fix deadlock between quota disable and qgroup rescan worker
+    - drm/nouveau: fix off by one in BIOS boundary checking
+    - mm/kmemleak: avoid scanning potential huge holes
+    - block: bio-integrity: Advance seed correctly for larger interval sizes
+    - memcg: charge fs_context and legacy_fs_context
+    - IB/rdmavt: Validate remote_addr during loopback atomic tests
+    - RDMA/siw: Fix broken RDMA Read Fence/Resume logic.
+    - RDMA/mlx4: Don't continue event handler after memory allocation failure
+    - iommu/vt-d: Fix potential memory leak in intel_setup_irq_remapping()
+    - iommu/amd: Fix loop timeout issue in iommu_ga_log_enable()
+    - spi: bcm-qspi: check for valid cs before applying chip select
+    - spi: mediatek: Avoid NULL pointer crash in interrupt
+    - spi: meson-spicc: add IRQ check in meson_spicc_probe
+    - net: ieee802154: hwsim: Ensure proper channel selection at probe time
+    - net: ieee802154: mcr20a: Fix lifs/sifs periods
+    - net: ieee802154: ca8210: Stop leaking skb's
+    - net: ieee802154: Return meaningful error codes from the netlink helpers
+    - net: macsec: Verify that send_sci is on when setting Tx sci explicitly
+    - net: stmmac: dump gmac4 DMA registers correctly
+    - net: stmmac: ensure PTP time register reads are consistent
+    - drm/i915/overlay: Prevent divide by zero bugs in scaling
+    - ASoC: fsl: Add missing error handling in pcm030_fabric_probe
+    - ASoC: xilinx: xlnx_formatter_pcm: Make buffer bytes multiple of period bytes
+    - ASoC: cpcap: Check for NULL pointer after calling of_get_child_by_name
+    - ASoC: max9759: fix underflow in speaker_gain_control_put()
+    - pinctrl: bcm2835: Fix a few error paths
+    - scsi: bnx2fc: Make bnx2fc_recv_frame() mp safe
+    - nfsd: nfsd4_setclientid_confirm mistakenly expires confirmed client.
+    - selftests: futex: Use variable MAKE instead of make
+    - rtc: cmos: Evaluate century appropriate
+    - EDAC/altera: Fix deferred probing
+    - EDAC/xgene: Fix deferred probing
+    - ext4: fix error handling in ext4_restore_inline_data()
+    - cgroup/cpuset: Fix "suspicious RCU usage" lockdep warning
+    - Linux 5.4.178
+
+  * Focal update: v5.4.177 upstream stable release (LP: #1964628)
+    - PCI: pciehp: Fix infinite loop in IRQ handler upon power fault
+    - psi: Fix uaf issue when psi trigger is destroyed while being polled
+    - ipheth: fix EOVERFLOW in ipheth_rcvbulk_callback
+    - net: amd-xgbe: ensure to reset the tx_timer_active flag
+    - net: amd-xgbe: Fix skb data length underflow
+    - rtnetlink: make sure to refresh master_dev/m_ops in __rtnl_newlink()
+    - cpuset: Fix the bug that subpart_cpus updated wrongly in update_cpumask()
+    - af_packet: fix data-race in packet_setsockopt / packet_setsockopt
+    - Linux 5.4.177
+
+  * Focal update: v5.4.176 upstream stable release (LP: #1962345)
+    - s390/hypfs: include z/VM guests with access control group set
+    - scsi: zfcp: Fix failed recovery on gone remote port with non-NPIV FCP
+      devices
+    - udf: Restore i_lenAlloc when inode expansion fails
+    - udf: Fix NULL ptr deref when converting from inline format
+    - PM: wakeup: simplify the output logic of pm_show_wakelocks()
+    - tracing/histogram: Fix a potential memory leak for kstrdup()
+    - tracing: Don't inc err_log entry count if entry allocation fails
+    - fsnotify: fix fsnotify hooks in pseudo filesystems
+    - drm/etnaviv: relax submit size limits
+    - arm64: errata: Fix exec handling in erratum 1418040 workaround
+    - netfilter: nft_payload: do not update layer 4 checksum when mangling
+      fragments
+    - serial: 8250: of: Fix mapped region size when using reg-offset property
+    - serial: stm32: fix software flow control transfer
+    - tty: n_gsm: fix SW flow control encoding/handling
+    - tty: Add support for Brainboxes UC cards.
+    - usb-storage: Add unusual-devs entry for VL817 USB-SATA bridge
+    - usb: common: ulpi: Fix crash in ulpi_match()
+    - usb: gadget: f_sourcesink: Fix isoc transfer for USB_SPEED_SUPER_PLUS
+    - USB: core: Fix hang in usb_kill_urb by adding memory barriers
+    - usb: typec: tcpm: Do not disconnect while receiving VBUS off
+    - ucsi_ccg: Check DEV_INT bit only when starting CCG4
+    - net: sfp: ignore disabled SFP node
+    - powerpc/32: Fix boot failure with GCC latent entropy plugin
+    - i40e: Increase delay to 1 s after global EMP reset
+    - i40e: Fix issue when maximum queues is exceeded
+    - i40e: Fix queues reservation for XDP
+    - i40e: fix unsigned stat widths
+    - rpmsg: char: Fix race between the release of rpmsg_ctrldev and cdev
+    - rpmsg: char: Fix race between the release of rpmsg_eptdev and cdev
+    - scsi: bnx2fc: Flush destroy_work queue before calling bnx2fc_interface_put()
+    - ipv6_tunnel: Rate limit warning messages
+    - net: fix information leakage in /proc/net/ptype
+    - hwmon: (lm90) Mark alert as broken for MAX6646/6647/6649
+    - hwmon: (lm90) Mark alert as broken for MAX6680
+    - ping: fix the sk_bound_dev_if match in ping_lookup
+    - ipv4: avoid using shared IP generator for connected sockets
+    - hwmon: (lm90) Reduce maximum conversion rate for G781
+    - NFSv4: Handle case where the lookup of a directory fails
+    - NFSv4: nfs_atomic_open() can race when looking up a non-regular file
+    - net-procfs: show net devices bound packet types
+    - drm/msm: Fix wrong size calculation
+    - drm/msm/dsi: Fix missing put_device() call in dsi_get_phy
+    - drm/msm/dsi: invalid parameter check in msm_dsi_phy_enable
+    - ipv6: annotate accesses to fn->fn_sernum
+    - NFS: Ensure the server has an up to date ctime before hardlinking
+    - NFS: Ensure the server has an up to date ctime before renaming
+    - netfilter: conntrack: don't increment invalid counter on NF_REPEAT
+    - net: phy: broadcom: hook up soft_reset for BCM54616S
+    - phylib: fix potential use-after-free
+    - rxrpc: Adjust retransmission backoff
+    - hwmon: (lm90) Mark alert as broken for MAX6654
+    - ibmvnic: init ->running_cap_crqs early
+    - ibmvnic: don't spin in tasklet
+    - drm/msm/hdmi: Fix missing put_device() call in msm_hdmi_get_phy
+    - yam: fix a memory leak in yam_siocdevprivate()
+    - net: hns3: handle empty unknown interrupt for VF
+    - ipv4: raw: lock the socket in raw_bind()
+    - ipv4: tcp: send zero IPID in SYNACK messages
+    - ipv4: remove sparse error in ip_neigh_gw4()
+    - dt-bindings: can: tcan4x5x: fix mram-cfg RX FIFO config
+    - fsnotify: invalidate dcache before IN_DELETE event
+    - block: Fix wrong offset in bio_truncate()
+    - mtd: rawnand: mpc5121: Remove unused variable in ads5121_select_chip()
+    - Linux 5.4.176
+
+  * Focal update: v5.4.175 upstream stable release (LP: #1962330)
+    - rcu: Tighten rcu_advance_cbs_nowake() checks
+    - pinctrl: bcm2835: Drop unused define
+    - pinctrl: bcm2835: Refactor platform data
+    - pinctrl: bcm2835: Add support for all GPIOs on BCM2711
+    - pinctrl: bcm2835: Match BCM7211 compatible string
+    - pinctrl: bcm2835: Add support for wake-up interrupts
+    - pinctrl: bcm2835: Change init order for gpio hogs
+    - ARM: dts: gpio-ranges property is now required
+    - mmc: sdhci-esdhc-imx: disable CMDQ support
+    - select: Fix indefinitely sleeping task in poll_schedule_timeout()
+    - Linux 5.4.175
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 29 Mar 2022 09:18:40 +0200
+
+linux (5.4.0-107.121) focal; urgency=medium
+
+  * focal/linux: 5.4.0-107.121 -proposed tracker (LP: #1966275)
+
+  * CVE-2022-27666
+    - esp: Fix possible buffer overflow in ESP transformation
+
+  * CVE-2022-1055
+    - net: sched: fix use-after-free in tc_new_tfilter()
+
+  * Pick fixup from v5.4.176 upstream stable release to address cert
+    failure with clock jitter test in NUC7i3DNHE (LP: #1964204)
+    - Bluetooth: refactor malicious adv data check
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 24 Mar 2022 16:48:48 +0100
+
+linux (5.4.0-105.119) focal; urgency=medium
+
+  * CVE-2022-0847
+    - lib/iov_iter: initialize "flags" in new pipe_buffer
+
+  * Broken network on some AWS instances with focal/impish kernels
+    (LP: #1961968)
+    - SAUCE: Revert "PCI/MSI: Mask MSI-X vectors only on success"
+
+  * [UBUNTU 20.04] kernel: Add support for CPU-MF counter second version 7
+    (LP: #1960182)
+    - s390/cpumf: Support for CPU Measurement Facility CSVN 7
+    - s390/cpumf: Support for CPU Measurement Sampling Facility LS bit
+
+  * Hipersocket page allocation failure on Ubuntu 20.04 based SSC environments
+    (LP: #1959529)
+    - s390/qeth: use memory reserves to back RX buffers
+
+  * CVE-2022-0516
+    - KVM: s390: Return error on SIDA memop on normal guest
+
+  * CVE-2022-0435
+    - tipc: improve size validations for received domain records
+
+  * CVE-2022-0492
+    - cgroup-v1: Require capabilities to set release_agent
+
+  * Recalled NFSv4 files delegations overwhelm server (LP: #1957986)
+    - NFSv4: Fix delegation handling in update_open_stateid()
+    - NFSv4: nfs4_callback_getattr() should ignore revoked delegations
+    - NFSv4: Delegation recalls should not find revoked delegations
+    - NFSv4: fail nfs4_refresh_delegation_stateid() when the delegation was
+      revoked
+    - NFS: Rename nfs_inode_return_delegation_noreclaim()
+    - NFSv4: Don't remove the delegation from the super_list more than once
+    - NFSv4: Hold the delegation spinlock when updating the seqid
+    - NFSv4: Clear the NFS_DELEGATION_REVOKED flag in
+      nfs_update_inplace_delegation()
+    - NFSv4: Update the stateid seqid in nfs_revoke_delegation()
+    - NFSv4: Revoke the delegation on success in nfs4_delegreturn_done()
+    - NFSv4: Ignore requests to return the delegation if it was revoked
+    - NFSv4: Don't reclaim delegations that have been returned or revoked
+    - NFSv4: nfs4_return_incompatible_delegation() should check delegation
+      validity
+    - NFSv4: Fix nfs4_inode_make_writeable()
+    - NFS: nfs_inode_find_state_and_recover() fix stateid matching
+    - NFSv4: Fix races between open and delegreturn
+    - NFSv4: Handle NFS4ERR_OLD_STATEID in delegreturn
+    - NFSv4: Don't retry the GETATTR on old stateid in nfs4_delegreturn_done()
+    - NFSv4: nfs_inode_evict_delegation() should set NFS_DELEGATION_RETURNING
+    - NFS: Clear NFS_DELEGATION_RETURN_IF_CLOSED when the delegation is returned
+    - NFSv4: Try to return the delegation immediately when marked for return on
+      close
+    - NFSv4: Add accounting for the number of active delegations held
+    - NFSv4: Limit the total number of cached delegations
+    - NFSv4: Ensure the delegation is pinned in nfs_do_return_delegation()
+    - NFSv4: Ensure the delegation cred is pinned when we call delegreturn
+
+  * Focal update: v5.4.174 upstream stable release (LP: #1960566)
+    - HID: uhid: Fix worker destroying device without any protection
+    - HID: wacom: Reset expected and received contact counts at the same time
+    - HID: wacom: Ignore the confidence flag when a touch is removed
+    - HID: wacom: Avoid using stale array indicies to read contact count
+    - f2fs: fix to do sanity check in is_alive()
+    - nfc: llcp: fix NULL error pointer dereference on sendmsg() after failed
+      bind()
+    - mtd: rawnand: gpmi: Add ERR007117 protection for nfc_apply_timings
+    - mtd: rawnand: gpmi: Remove explicit default gpmi clock setting for i.MX6
+    - x86/gpu: Reserve stolen memory for first integrated Intel GPU
+    - tools/nolibc: x86-64: Fix startup code bug
+    - tools/nolibc: i386: fix initial stack alignment
+    - tools/nolibc: fix incorrect truncation of exit code
+    - rtc: cmos: take rtc_lock while reading from CMOS
+    - media: v4l2-ioctl.c: readbuffers depends on V4L2_CAP_READWRITE
+    - media: flexcop-usb: fix control-message timeouts
+    - media: mceusb: fix control-message timeouts
+    - media: em28xx: fix control-message timeouts
+    - media: cpia2: fix control-message timeouts
+    - media: s2255: fix control-message timeouts
+    - media: dib0700: fix undefined behavior in tuner shutdown
+    - media: redrat3: fix control-message timeouts
+    - media: pvrusb2: fix control-message timeouts
+    - media: stk1160: fix control-message timeouts
+    - can: softing_cs: softingcs_probe(): fix memleak on registration failure
+    - lkdtm: Fix content of section containing lkdtm_rodata_do_nothing()
+    - iommu/io-pgtable-arm-v7s: Add error handle for page table allocation failure
+    - dma_fence_array: Fix PENDING_ERROR leak in dma_fence_array_signaled()
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9125 SATA controller
+    - mm_zone: add function to check if managed dma zone exists
+    - mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed
+      pages
+    - shmem: fix a race between shmem_unused_huge_shrink and shmem_evict_inode
+    - drm/rockchip: dsi: Hold pm-runtime across bind/unbind
+    - drm/rockchip: dsi: Reconfigure hardware on resume()
+    - drm/panel: kingdisplay-kd097d04: Delete panel on attach() failure
+    - drm/panel: innolux-p079zca: Delete panel on attach() failure
+    - drm/rockchip: dsi: Fix unbalanced clock on probe error
+    - Bluetooth: cmtp: fix possible panic when cmtp_init_sockets() fails
+    - clk: bcm-2835: Pick the closest clock rate
+    - clk: bcm-2835: Remove rounding up the dividers
+    - wcn36xx: Indicate beacon not connection loss on MISSED_BEACON_IND
+    - wcn36xx: Release DMA channel descriptor allocations
+    - media: videobuf2: Fix the size printk format
+    - media: aspeed: fix mode-detect always time out at 2nd run
+    - media: em28xx: fix memory leak in em28xx_init_dev
+    - media: aspeed: Update signal status immediately to ensure sane hw state
+    - arm64: dts: meson-gxbb-wetek: fix HDMI in early boot
+    - arm64: dts: meson-gxbb-wetek: fix missing GPIO binding
+    - Bluetooth: stop proccessing malicious adv data
+    - tee: fix put order in teedev_close_context()
+    - media: dmxdev: fix UAF when dvb_register_device() fails
+    - crypto: qce - fix uaf on qce_ahash_register_one
+    - arm64: dts: ti: k3-j721e: correct cache-sets info
+    - tty: serial: atmel: Check return code of dmaengine_submit()
+    - tty: serial: atmel: Call dma_async_issue_pending()
+    - media: rcar-csi2: Correct the selection of hsfreqrange
+    - media: imx-pxp: Initialize the spinlock prior to using it
+    - media: si470x-i2c: fix possible memory leak in si470x_i2c_probe()
+    - media: mtk-vcodec: call v4l2_m2m_ctx_release first when file is released
+    - media: venus: core: Fix a resource leak in the error handling path of
+      'venus_probe()'
+    - netfilter: bridge: add support for pppoe filtering
+    - arm64: dts: qcom: msm8916: fix MMC controller aliases
+    - ACPI: EC: Rework flushing of EC work while suspended to idle
+    - drm/amdgpu: Fix a NULL pointer dereference in
+      amdgpu_connector_lcd_native_mode()
+    - drm/radeon/radeon_kms: Fix a NULL pointer dereference in
+      radeon_driver_open_kms()
+    - arm64: dts: ti: k3-j721e: Fix the L2 cache sets
+    - tty: serial: uartlite: allow 64 bit address
+    - serial: amba-pl011: do not request memory region twice
+    - floppy: Fix hang in watchdog when disk is ejected
+    - staging: rtl8192e: return error code from rtllib_softmac_init()
+    - staging: rtl8192e: rtllib_module: fix error handle case in alloc_rtllib()
+    - Bluetooth: btmtksdio: fix resume failure
+    - media: dib8000: Fix a memleak in dib8000_init()
+    - media: saa7146: mxb: Fix a NULL pointer dereference in mxb_attach()
+    - media: si2157: Fix "warm" tuner state detection
+    - sched/rt: Try to restart rt period timer when rt runtime exceeded
+    - rcu/exp: Mark current CPU as exp-QS in IPI loop second pass
+    - mwifiex: Fix possible ABBA deadlock
+    - xfrm: fix a small bug in xfrm_sa_len()
+    - crypto: stm32/cryp - fix xts and race condition in crypto_engine requests
+    - crypto: stm32/cryp - fix double pm exit
+    - crypto: stm32/cryp - fix lrw chaining mode
+    - ARM: dts: gemini: NAS4220-B: fis-index-block with 128 KiB sectors
+    - media: dw2102: Fix use after free
+    - media: msi001: fix possible null-ptr-deref in msi001_probe()
+    - media: coda/imx-vdoa: Handle dma_set_coherent_mask error codes
+    - drm/msm/dpu: fix safe status debugfs file
+    - drm/bridge: ti-sn65dsi86: Set max register for regmap
+    - media: hantro: Fix probe func error path
+    - xfrm: interface with if_id 0 should return error
+    - xfrm: state and policy should fail if XFRMA_IF_ID 0
+    - ARM: 9159/1: decompressor: Avoid UNPREDICTABLE NOP encoding
+    - usb: ftdi-elan: fix memory leak on device disconnect
+    - ARM: dts: armada-38x: Add generic compatible to UART nodes
+    - mmc: meson-mx-sdio: add IRQ check
+    - selinux: fix potential memleak in selinux_add_opt()
+    - bpftool: Enable line buffering for stdout
+    - x86/mce/inject: Avoid out-of-bounds write when setting flags
+    - ACPI: scan: Create platform device for BCM4752 and LNV4752 ACPI nodes
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      __nonstatic_find_io_region()
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      nonstatic_find_mem_region()
+    - netfilter: ipt_CLUSTERIP: fix refcount leak in clusterip_tg_check()
+    - bpf: Fix SO_RCVBUF/SO_SNDBUF handling in _bpf_setsockopt().
+    - ppp: ensure minimum packet size in ppp_write()
+    - rocker: fix a sleeping in atomic bug
+    - staging: greybus: audio: Check null pointer
+    - fsl/fman: Check for null pointer after calling devm_ioremap
+    - Bluetooth: hci_bcm: Check for error irq
+    - HID: hid-uclogic-params: Invalid parameter check in uclogic_params_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_get_str_desc
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_huion_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_frame_init_v1_buttonpad
+    - debugfs: lockdown: Allow reading debugfs files that are not world readable
+    - net/mlx5e: Don't block routes with nexthop objects in SW
+    - Revert "net/mlx5e: Block offload of outer header csum for UDP tunnels"
+    - net/mlx5: Set command entry semaphore up once got index free
+    - spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe
+    - tpm: add request_locality before write TPM_INT_ENABLE
+    - can: softing: softing_startstop(): fix set but not used variable warning
+    - can: xilinx_can: xcan_probe(): check for error irq
+    - pcmcia: fix setting of kthread task states
+    - net: mcs7830: handle usb read errors properly
+    - ext4: avoid trim error on fs with small groups
+    - ALSA: jack: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: PCM: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: hda: Add missing rwsem around snd_ctl_remove() calls
+    - RDMA/hns: Validate the pkey index
+    - clk: imx8mn: Fix imx8mn_clko1_sels
+    - powerpc/prom_init: Fix improper check of prom_getprop()
+    - ASoC: uniphier: drop selecting non-existing SND_SOC_UNIPHIER_AIO_DMA
+    - ALSA: oss: fix compile error when OSS_DEBUG is enabled
+    - char/mwave: Adjust io port register size
+    - binder: fix handling of error during copy
+    - iommu/io-pgtable-arm: Fix table descriptor paddr formatting
+    - scsi: ufs: Fix race conditions related to driver data
+    - PCI/MSI: Fix pci_irq_vector()/pci_irq_get_affinity()
+    - powerpc/powermac: Add additional missing lockdep_register_key()
+    - RDMA/core: Let ib_find_gid() continue search even after empty entry
+    - RDMA/cma: Let cma_resolve_ib_dev() continue search even after empty entry
+    - ASoC: rt5663: Handle device_property_read_u32_array error codes
+    - clk: stm32: Fix ltdc's clock turn off by clk_disable_unused() after system
+      enter shell
+    - dmaengine: pxa/mmp: stop referencing config->slave_id
+    - iommu/iova: Fix race between FQ timeout and teardown
+    - phy: uniphier-usb3ss: fix unintended writing zeros to PHY register
+    - ASoC: samsung: idma: Check of ioremap return value
+    - misc: lattice-ecp3-config: Fix task hung when firmware load failed
+    - mips: lantiq: add support for clk_set_parent()
+    - mips: bcm63xx: add support for clk_set_parent()
+    - RDMA/cxgb4: Set queue pair state when being queried
+    - of: base: Fix phandle argument length mismatch error message
+    - Bluetooth: Fix debugfs entry leak in hci_register_dev()
+    - fs: dlm: filter user dlm messages for kernel locks
+    - drm/lima: fix warning when CONFIG_DEBUG_SG=y & CONFIG_DMA_API_DEBUG=y
+    - ar5523: Fix null-ptr-deref with unexpected WDCMSG_TARGET_START reply
+    - drm/nouveau/pmu/gm200-: avoid touching PMU outside of DEVINIT/PREOS/ACR
+    - ARM: shmobile: rcar-gen2: Add missing of_node_put()
+    - batman-adv: allow netlink usage in unprivileged containers
+    - usb: gadget: f_fs: Use stream_open() for endpoint files
+    - drm: panel-orientation-quirks: Add quirk for the Lenovo Yoga Book X91F/L
+    - HID: apple: Do not reset quirks when the Fn key is not found
+    - media: b2c2: Add missing check in flexcop_pci_isr:
+    - EDAC/synopsys: Use the quirk for version instead of ddr version
+    - mlxsw: pci: Add shutdown method in PCI driver
+    - drm/bridge: megachips: Ensure both bridges are probed before registration
+    - gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use
+    - HSI: core: Fix return freed object in hsi_new_client
+    - mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
+    - rsi: Fix use-after-free in rsi_rx_done_handler()
+    - rsi: Fix out-of-bounds read in rsi_read_pkt()
+    - usb: uhci: add aspeed ast2600 uhci support
+    - floppy: Add max size check for user space request
+    - x86/mm: Flush global TLB when switching to trampoline page-table
+    - media: uvcvideo: Increase UVC_CTRL_CONTROL_TIMEOUT to 5 seconds.
+    - media: saa7146: hexium_orion: Fix a NULL pointer dereference in
+      hexium_attach()
+    - media: m920x: don't use stack on USB reads
+    - iwlwifi: mvm: synchronize with FW after multicast commands
+    - ath10k: Fix tx hanging
+    - net-sysfs: update the queue counts in the unregistration path
+    - net: phy: prefer 1000baseT over 1000baseKX
+    - gpio: aspeed: Convert aspeed_gpio.lock to raw_spinlock
+    - x86/mce: Mark mce_panic() noinstr
+    - x86/mce: Mark mce_end() noinstr
+    - x86/mce: Mark mce_read_aux() noinstr
+    - net: bonding: debug: avoid printing debug logs when bond is not notifying
+      peers
+    - bpf: Do not WARN in bpf_warn_invalid_xdp_action()
+    - HID: quirks: Allow inverting the absolute X/Y values
+    - media: igorplugusb: receiver overflow should be reported
+    - media: saa7146: hexium_gemini: Fix a NULL pointer dereference in
+      hexium_attach()
+    - mmc: core: Fixup storing of OCR for MMC_QUIRK_NONSTD_SDIO
+    - audit: ensure userspace is penalized the same as the kernel when under
+      pressure
+    - arm64: dts: ls1028a-qds: move rtc node to the correct i2c bus
+    - arm64: tegra: Adjust length of CCPLEX cluster MMIO region
+    - cpufreq: Fix initialization of min and max frequency QoS requests
+    - usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0
+    - ath9k: Fix out-of-bound memcpy in ath9k_hif_usb_rx_stream
+    - iwlwifi: fix leaks/bad data after failed firmware load
+    - iwlwifi: remove module loading failure message
+    - iwlwifi: mvm: Fix calculation of frame length
+    - um: registers: Rename function names to avoid conflicts and build problems
+    - jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
+    - ACPICA: actypes.h: Expand the ACPI_ACCESS_ definitions
+    - ACPICA: Utilities: Avoid deleting the same object twice in a row
+    - ACPICA: Executer: Fix the REFCLASS_REFOF case in acpi_ex_opcode_1A_0T_1R()
+    - ACPICA: Fix wrong interpretation of PCC address
+    - ACPICA: Hardware: Do not flush CPU cache when entering S4 and S5
+    - drm/amdgpu: fixup bad vram size on gmc v8
+    - ACPI: battery: Add the ThinkPad "Not Charging" quirk
+    - btrfs: remove BUG_ON() in find_parent_nodes()
+    - btrfs: remove BUG_ON(!eie) in find_parent_nodes
+    - net: mdio: Demote probed message to debug print
+    - mac80211: allow non-standard VHT MCS-10/11
+    - dm btree: add a defensive bounds check to insert_at()
+    - dm space map common: add bounds check to sm_ll_lookup_bitmap()
+    - net: phy: marvell: configure RGMII delays for 88E1118
+    - net: gemini: allow any RGMII interface mode
+    - regulator: qcom_smd: Align probe function with rpmh-regulator
+    - serial: pl010: Drop CR register reset on set_termios
+    - serial: core: Keep mctrl register state and cached copy in sync
+    - random: do not throw away excess input to crng_fast_load
+    - parisc: Avoid calling faulthandler_disabled() twice
+    - powerpc/6xx: add missing of_node_put
+    - powerpc/powernv: add missing of_node_put
+    - powerpc/cell: add missing of_node_put
+    - powerpc/btext: add missing of_node_put
+    - powerpc/watchdog: Fix missed watchdog reset due to memory ordering race
+    - i2c: i801: Don't silently correct invalid transfer size
+    - powerpc/smp: Move setup_profiling_timer() under CONFIG_PROFILING
+    - i2c: mpc: Correct I2C reset procedure
+    - clk: meson: gxbb: Fix the SDM_EN bit for MPLL0 on GXBB
+    - powerpc/powermac: Add missing lockdep_register_key()
+    - KVM: PPC: Book3S: Suppress failed alloc warning in H_COPY_TOFROM_GUEST
+    - w1: Misuse of get_user()/put_user() reported by sparse
+    - scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup
+    - ALSA: seq: Set upper limit of processed events
+    - powerpc: handle kdump appropriately with crash_kexec_post_notifiers option
+    - MIPS: OCTEON: add put_device() after of_find_device_by_node()
+    - i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters
+    - MIPS: Octeon: Fix build errors using clang
+    - scsi: sr: Don't use GFP_DMA
+    - ASoC: mediatek: mt8173: fix device_node leak
+    - power: bq25890: Enable continuous conversion for ADC at charging
+    - rpmsg: core: Clean up resources on announce_create failure.
+    - crypto: omap-aes - Fix broken pm_runtime_and_get() usage
+    - crypto: stm32/crc32 - Fix kernel BUG triggered in probe()
+    - crypto: caam - replace this_cpu_ptr with raw_cpu_ptr
+    - ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
+    - fuse: Pass correct lend value to filemap_write_and_wait_range()
+    - serial: Fix incorrect rs485 polarity on uart open
+    - cputime, cpuacct: Include guest time in user time in cpuacct.stat
+    - tracing/kprobes: 'nmissed' not showed correctly for kretprobe
+    - iwlwifi: mvm: Increase the scan timeout guard to 30 seconds
+    - s390/mm: fix 2KB pgtable release race
+    - drm/etnaviv: limit submit sizes
+    - drm/nouveau/kms/nv04: use vzalloc for nv04_display
+    - drm/bridge: analogix_dp: Make PSR-exit block less
+    - PCI: pci-bridge-emul: Properly mark reserved PCIe bits in PCI config space
+    - PCI: pci-bridge-emul: Correctly set PCIe capabilities
+    - PCI: pci-bridge-emul: Set PCI_STATUS_CAP_LIST for PCIe device
+    - xfrm: fix policy lookup for ipv6 gre packets
+    - btrfs: fix deadlock between quota enable and other quota operations
+    - btrfs: check the root node for uptodate before returning it
+    - btrfs: respect the max size in the header when activating swap file
+    - ext4: make sure to reset inode lockdep class when quota enabling fails
+    - ext4: make sure quota gets properly shutdown on error
+    - ext4: set csum seed in tmp inode while migrating to extents
+    - ext4: Fix BUG_ON in ext4_bread when write quota data
+    - ext4: don't use the orphan list when migrating an inode
+    - drm/radeon: fix error handling in radeon_driver_open_kms
+    - of: base: Improve argument length mismatch error
+    - firmware: Update Kconfig help text for Google firmware
+    - media: rcar-csi2: Optimize the selection PHTW register
+    - Documentation: dmaengine: Correctly describe dmatest with channel unset
+    - Documentation: ACPI: Fix data node reference documentation
+    - Documentation: refer to config RANDOMIZE_BASE for kernel address-space
+      randomization
+    - Documentation: fix firewire.rst ABI file path error
+    - scsi: core: Show SCMD_LAST in text form
+    - RDMA/hns: Modify the mapping attribute of doorbell to device
+    - RDMA/rxe: Fix a typo in opcode name
+    - dmaengine: stm32-mdma: fix STM32_MDMA_CTBR_TSEL_MASK
+    - Revert "net/mlx5: Add retry mechanism to the command entry index allocation"
+    - powerpc/cell: Fix clang -Wimplicit-fallthrough warning
+    - powerpc/fsl/dts: Enable WA for erratum A-009885 on fman3l MDIO buses
+    - bpftool: Remove inclusion of utilities.mak from Makefiles
+    - ipv4: avoid quadratic behavior in netns dismantle
+    - net/fsl: xgmac_mdio: Fix incorrect iounmap when removing module
+    - parisc: pdc_stable: Fix memory leak in pdcs_register_pathentries
+    - f2fs: fix to reserve space for IO align feature
+    - af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
+    - clk: si5341: Fix clock HW provider cleanup
+    - net: axienet: limit minimum TX ring size
+    - net: axienet: fix number of TX ring slots for available check
+    - net: axienet: increase default TX ring size to 128
+    - rtc: pxa: fix null pointer dereference
+    - inet: frags: annotate races around fqdir->dead and fqdir->high_thresh
+    - netns: add schedule point in ops_exit_list()
+    - xfrm: Don't accidentally set RTO_ONLINK in decode_session4()
+    - gre: Don't accidentally set RTO_ONLINK in gre_fill_metadata_dst()
+    - libcxgb: Don't accidentally set RTO_ONLINK in cxgb_find_route()
+    - perf script: Fix hex dump character output
+    - dmaengine: at_xdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_xdmac: Print debug message after realeasing the lock
+    - dmaengine: at_xdmac: Fix concurrency over xfers_list
+    - dmaengine: at_xdmac: Fix lld view setting
+    - dmaengine: at_xdmac: Fix at_xdmac_lld struct definition
+    - arm64: dts: qcom: msm8996: drop not documented adreno properties
+    - net_sched: restore "mpu xxx" handling
+    - bcmgenet: add WOL IRQ check
+    - net: ethernet: mtk_eth_soc: fix error checking in mtk_mac_config()
+    - dt-bindings: display: meson-dw-hdmi: add missing sound-name-prefix property
+    - dt-bindings: display: meson-vpu: Add missing amlogic,canvas property
+    - scripts/dtc: dtx_diff: remove broken example from help text
+    - lib82596: Fix IRQ check in sni_82596_probe
+    - lib/test_meminit: destroy cache in kmem_cache_alloc_bulk() test
+    - mtd: nand: bbt: Fix corner case in bad block table handling
+    - Revert "ia64: kprobes: Use generic kretprobe trampoline handler"
+    - Linux 5.4.174
+
+  * Focal update: v5.4.173 upstream stable release (LP: #1959701)
+    - kbuild: Add $(KBUILD_HOSTLDFLAGS) to 'has_libelf' test
+    - devtmpfs regression fix: reconfigure on each mount
+    - orangefs: Fix the size of a memory allocation in orangefs_bufmap_alloc()
+    - perf: Protect perf_guest_cbs with RCU
+    - KVM: s390: Clarify SIGP orders versus STOP/RESTART
+    - media: uvcvideo: fix division by zero at stream start
+    - rtlwifi: rtl8192cu: Fix WARNING when calling local_irq_restore() with
+      interrupts enabled
+    - firmware: qemu_fw_cfg: fix sysfs information leak
+    - firmware: qemu_fw_cfg: fix NULL-pointer deref on duplicate entries
+    - firmware: qemu_fw_cfg: fix kobject leak in probe error path
+    - KVM: x86: remove PMU FIXED_CTR3 from msrs_to_save_all
+    - ALSA: hda/realtek - Fix silent output on Gigabyte X570 Aorus Master after
+      reboot from Windows
+    - mtd: fixup CFI on ixp4xx
+    - ARM: 9025/1: Kconfig: CPU_BIG_ENDIAN depends on !LD_IS_LLD
+    - Linux 5.4.173
+
+  * Focal update: v5.4.172 upstream stable release (LP: #1959698)
+    - workqueue: Fix unbind_workers() VS wq_worker_running() race
+    - Bluetooth: btusb: fix memory leak in btusb_mtk_submit_wmt_recv_urb()
+    - Bluetooth: bfusb: fix division by zero in send path
+    - USB: core: Fix bug in resuming hub's handling of wakeup requests
+    - USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
+    - mmc: sdhci-pci: Add PCI ID for Intel ADL
+    - veth: Do not record rx queue hint in veth_xmit
+    - mfd: intel-lpss: Fix too early PM enablement in the ACPI ->probe()
+    - drivers core: Use sysfs_emit and sysfs_emit_at for show(device *...)
+      functions
+    - can: gs_usb: fix use of uninitialized variable, detach device on reception
+      of invalid USB data
+    - can: gs_usb: gs_can_start_xmit(): zero-initialize hf->{flags,reserved}
+    - random: fix data race on crng_node_pool
+    - random: fix data race on crng init time
+    - random: fix crash on multiple early calls to add_bootloader_randomness()
+    - media: Revert "media: uvcvideo: Set unique vdev name based in type"
+    - staging: wlan-ng: Avoid bitwise vs logical OR warning in
+      hfa384x_usb_throttlefn()
+    - drm/i915: Avoid bitwise vs logical OR warning in snb_wm_latency_quirk()
+    - staging: greybus: fix stack size warning with UBSAN
+    - Linux 5.4.172
+
+  * Focal update: v5.4.171 upstream stable release (LP: #1959437)
+    - f2fs: quota: fix potential deadlock
+    - Input: touchscreen - Fix backport of
+      a02dcde595f7cbd240ccd64de96034ad91cffc40
+    - selftests: x86: fix [-Wstringop-overread] warn in test_process_vm_readv()
+    - tracing: Fix check for trace_percpu_buffer validity in get_trace_buf()
+    - tracing: Tag trace_percpu_buffer as a percpu pointer
+    - ieee802154: atusb: fix uninit value in atusb_set_extended_addr
+    - iavf: Fix limit of total number of queues to active queues of VF
+    - RDMA/core: Don't infoleak GRH fields
+    - RDMA/uverbs: Check for null return of kmalloc_array
+    - mac80211: initialize variable have_higher_than_11mbit
+    - i40e: fix use-after-free in i40e_sync_filters_subtask()
+    - i40e: Fix for displaying message regarding NVM version
+    - i40e: Fix incorrect netdev's real number of RX/TX queues
+    - ipv4: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv4: Check attribute length for RTA_FLOW in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY when deleting multipath route
+    - lwtunnel: Validate RTA_ENCAP_TYPE attribute length
+    - batman-adv: mcast: don't send link-local multicast to mcast routers
+    - sch_qfq: prevent shift-out-of-bounds in qfq_init_qdisc
+    - net: phy: micrel: set soft_reset callback to genphy_soft_reset for KSZ8081
+    - power: supply: core: Break capacity loop
+    - power: reset: ltc2952: Fix use of floating point literals
+    - rndis_host: support Hytera digital radios
+    - phonet: refcount leak in pep_sock_accep
+    - ipv6: Continue processing multipath route even if gateway attribute is
+      invalid
+    - ipv6: Do cleanup if attribute validation fails in multipath route
+    - usb: mtu3: fix interval value for intr and isoc
+    - scsi: libiscsi: Fix UAF in iscsi_conn_get_param()/iscsi_conn_teardown()
+    - ip6_vti: initialize __ip6_tnl_parm struct in vti6_siocdevprivate
+    - net: udp: fix alignment problem in udp4_seq_show()
+    - atlantic: Fix buff_ring OOB in aq_ring_rx_clean
+    - mISDN: change function names to avoid conflicts
+    - Linux 5.4.171
+
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898)
+    - tee: handle lookup of shm with reference count 0
+    - Input: i8042 - add deferred probe support
+    - Input: i8042 - enable deferred probe quirk for ASUS UM325UA
+    - tomoyo: Check exceeded quota early in tomoyo_domain_quota_is_ok().
+    - platform/x86: apple-gmux: use resource_size() with res
+    - memblock: fix memblock_phys_alloc() section mismatch error
+    - recordmcount.pl: fix typo in s390 mcount regex
+    - selinux: initialize proto variable in selinux_ip_postroute_compat()
+    - scsi: lpfc: Terminate string in lpfc_debugfs_nvmeio_trc_write()
+    - net/mlx5: DR, Fix NULL vs IS_ERR checking in dr_domain_init_resources
+    - sctp: use call_rcu to free endpoint
+    - net: usb: pegasus: Do not drop long Ethernet frames
+    - net: lantiq_xrx200: fix statistics of received bytes
+    - NFC: st21nfca: Fix memory leak in device probe and remove
+    - ionic: Initialize the 'lif->dbid_inuse' bitmap
+    - net/mlx5e: Fix wrong features assignment in case of error
+    - selftests/net: udpgso_bench_tx: fix dst ip argument
+    - net/ncsi: check for error return from call to nla_put_u32
+    - fsl/fman: Fix missing put_device() call in fman_port_probe
+    - i2c: validate user data in compat ioctl
+    - nfc: uapi: use kernel size_t to fix user-space builds
+    - uapi: fix linux/nfc.h userspace compilation errors
+    - xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.
+    - usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
+    - usb: mtu3: add memory barrier before set GPD's HWO
+    - usb: mtu3: fix list_head check warning
+    - usb: mtu3: set interval of FS intr and isoc endpoint
+    - binder: fix async_free_space accounting for empty parcels
+    - scsi: vmw_pvscsi: Set residual data length conditionally
+    - Input: appletouch - initialize work before device registration
+    - Input: spaceball - fix parsing of movement data packets
+    - net: fix use-after-free in tw_timer_handler
+    - perf script: Fix CPU filtering of a script's switch events
+    - Linux 5.4.170
+
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898) // HID_ASUS
+    should depend on USB_HID in stable v4.15 backports (LP: #1959762)
+    - HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option
+
+  * Focal update: v5.4.169 upstream stable release (LP: #1958557)
+    - net: usb: lan78xx: add Allied Telesis AT29M2-AF
+    - serial: 8250_fintek: Fix garbled text for console
+    - arm64: dts: allwinner: orangepi-zero-plus: fix PHY mode
+    - spi: change clk_disable_unprepare to clk_unprepare
+    - IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
+    - netfilter: fix regression in looped (broad|multi)cast's MAC handling
+    - qlcnic: potential dereference null pointer of rx_queue->page_ring
+    - net: accept UFOv6 packages in virtio_net_hdr_to_skb
+    - net: skip virtio_net_hdr_set_proto if protocol already set
+    - ipmi: Fix UAF when uninstall ipmi_si and ipmi_msghandler module
+    - bonding: fix ad_actor_system option setting to default
+    - fjes: Check for error irq
+    - drivers: net: smc911x: Check for error irq
+    - sfc: falcon: Check null pointer of rx_queue->page_ring
+    - Input: elantech - fix stack out of bound access in
+      elantech_change_report_id()
+    - hwmon: (lm90) Fix usage of CONFIG2 register in detect function
+    - hwmon: (lm90) Add max6654 support to lm90 driver
+    - hwmon: (lm90) Add basic support for TI TMP461
+    - hwmon: (lm90) Introduce flag indicating extended temperature support
+    - hwmon: (lm90) Drop critical attribute support for MAX6654
+    - ALSA: jack: Check the return value of kstrdup()
+    - ALSA: drivers: opl3: Fix incorrect use of vp->state
+    - ALSA: hda/realtek: Amp init fixup for HP ZBook 15 G6
+    - Input: atmel_mxt_ts - fix double free in mxt_read_info_block
+    - ipmi: bail out if init_srcu_struct fails
+    - ipmi: ssif: initialize ssif_info->client early
+    - ipmi: fix initialization when workqueue allocation fails
+    - parisc: Correct completer in lws start
+    - x86/pkey: Fix undefined behaviour with PKRU_WD_BIT
+    - pinctrl: stm32: consider the GPIO offset to expose all the GPIO lines
+    - mmc: sdhci-tegra: Fix switch to HS400ES mode
+    - mmc: core: Disable card detect during shutdown
+    - ARM: 9169/1: entry: fix Thumb2 bug in iWMMXt exception handling
+    - tee: optee: Fix incorrect page free bug
+    - f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr()
+    - usb: gadget: u_ether: fix race in setting MAC address in setup phase
+    - KVM: VMX: Fix stale docs for kvm-intel.emulate_invalid_guest_state
+    - mm: mempolicy: fix THP allocations escaping mempolicy restrictions
+    - pinctrl: mediatek: fix global-out-of-bounds issue
+    - hwmom: (lm90) Fix citical alarm status for MAX6680/MAX6681
+    - hwmon: (lm90) Do not report 'busy' status bit as alarm
+    - ax25: NPD bug when detaching AX25 device
+    - hamradio: defer ax25 kfree after unregister_netdev
+    - hamradio: improve the incomplete fix to avoid NPD
+    - phonet/pep: refuse to enable an unbound pipe
+    - Linux 5.4.169
+
+  * Focal update: v5.4.168 upstream stable release (LP: #1957991)
+    - KVM: selftests: Make sure kvm_create_max_vcpus test won't hit RLIMIT_NOFILE
+    - mac80211: mark TX-during-stop for TX in in_reconfig
+    - mac80211: send ADDBA requests using the tid/queue of the aggregation session
+    - firmware: arm_scpi: Fix string overflow in SCPI genpd driver
+    - virtio_ring: Fix querying of maximum DMA mapping size for virtio device
+    - recordmcount.pl: look for jgnop instruction as well as bcrl on s390
+    - dm btree remove: fix use after free in rebalance_children()
+    - audit: improve robustness of the audit queue handling
+    - iio: adc: stm32: fix a current leak by resetting pcsel before disabling vdda
+    - nfsd: fix use-after-free due to delegation race
+    - arm64: dts: rockchip: remove mmc-hs400-enhanced-strobe from rk3399-khadas-
+      edge
+    - arm64: dts: rockchip: fix rk3399-leez-p710 vcc3v3-lan supply
+    - arm64: dts: rockchip: fix audio-supply for Rock Pi 4
+    - mac80211: track only QoS data frames for admission control
+    - ARM: socfpga: dts: fix qspi node compatible
+    - clk: Don't parent clks until the parent is fully registered
+    - selftests: net: Correct ping6 expected rc from 2 to 1
+    - s390/kexec_file: fix error handling when applying relocations
+    - sch_cake: do not call cake_destroy() from cake_init()
+    - inet_diag: use jiffies_delta_to_msecs()
+    - inet_diag: fix kernel-infoleak for UDP sockets
+    - selftests: Fix raw socket bind tests with VRF
+    - selftests: Fix IPv6 address bind tests
+    - dmaengine: st_fdma: fix MODULE_ALIAS
+    - selftest/net/forwarding: declare NETIFS p9 p10
+    - mac80211: agg-tx: refactor sending addba
+    - mac80211: agg-tx: don't schedule_and_wake_txq() under sta->lock
+    - mac80211: accept aggregation sessions on 6 GHz
+    - mac80211: fix lookup when adding AddBA extension element
+    - net: sched: lock action when translating it to flow_action infra
+    - flow_offload: return EOPNOTSUPP for the unsupported mpls action type
+    - rds: memory leak in __rds_conn_create()
+    - soc/tegra: fuse: Fix bitwise vs. logical OR warning
+    - igb: Fix removal of unicast MAC filters of VFs
+    - igbvf: fix double free in `igbvf_probe`
+    - ixgbe: set X550 MDIO speed before talking to PHY
+    - netdevsim: Zero-initialize memory for new map's value in function
+      nsim_bpf_map_alloc
+    - net: Fix double 0x prefix print in SKB dump
+    - net/smc: Prevent smc_release() from long blocking
+    - net: systemport: Add global locking for descriptor lifecycle
+    - sit: do not call ipip6_dev_free() from sit_init_net()
+    - USB: NO_LPM quirk Lenovo USB-C to Ethernet Adapher(RTL8153-04)
+    - PCI/MSI: Clear PCI_MSIX_FLAGS_MASKALL on error
+    - PCI/MSI: Mask MSI-X vectors only on success
+    - usb: xhci: Extend support for runtime power management for AMD's Yellow
+      carp.
+    - USB: serial: cp210x: fix CP2105 GPIO registration
+    - USB: serial: option: add Telit FN990 compositions
+    - timekeeping: Really make sure wall_to_monotonic isn't positive
+    - libata: if T_LENGTH is zero, dma direction should be DMA_NONE
+    - drm/amdgpu: correct register access for RLC_JUMP_TABLE_RESTORE
+    - mac80211: validate extended element ID is present
+    - mwifiex: Remove unnecessary braces from HostCmd_SET_SEQ_NO_BSS_INFO
+    - Input: touchscreen - avoid bitwise vs logical OR warning
+    - ARM: dts: imx6ull-pinfunc: Fix CSI_DATA07__ESAI_TX0 pad name
+    - xsk: Do not sleep in poll() when need_wakeup set
+    - media: mxl111sf: change mutex_init() location
+    - fuse: annotate lock in fuse_reverse_inval_entry()
+    - ovl: fix warning in ovl_create_real()
+    - scsi: scsi_debug: Sanity check block descriptor length in resp_mode_select()
+    - rcu: Mark accesses to rcu_state.n_force_qs
+    - mac80211: fix regression in SSN handling of addba tx
+    - net: sched: Fix suspicious RCU usage while accessing tcf_tunnel_info
+    - Revert "xsk: Do not sleep in poll() when need_wakeup set"
+    - xen/blkfront: harden blkfront against event channel storms
+    - xen/netfront: harden netfront against event channel storms
+    - xen/console: harden hvc_xen against event channel storms
+    - xen/netback: fix rx queue stall detection
+    - xen/netback: don't queue unlimited number of packages
+    - Linux 5.4.168
+
+  * Focal update: v5.4.167 upstream stable release (LP: #1957987)
+    - nfc: fix segfault in nfc_genl_dump_devices_done
+    - drm/msm/dsi: set default num_data_lanes
+    - net/mlx4_en: Update reported link modes for 1/10G
+    - parisc/agp: Annotate parisc agp init functions with __init
+    - i2c: rk3x: Handle a spurious start completion interrupt flag
+    - net: netlink: af_netlink: Prevent empty skb by adding a check on len.
+    - drm/amd/display: Fix for the no Audio bug with Tiled Displays
+    - drm/amd/display: add connector type check for CRC source set
+    - tracing: Fix a kmemleak false positive in tracing_map
+    - KVM: x86: Ignore sparse banks size for an "all CPUs", non-sparse IPI req
+    - selinux: fix race condition when computing ocontext SIDs
+    - bpf: Fix integer overflow in argument calculation for bpf_map_area_alloc
+    - hwmon: (dell-smm) Fix warning on /proc/i8k creation error
+    - memblock: free_unused_memmap: use pageblock units instead of MAX_ORDER
+    - memblock: align freed memory map on pageblock boundaries with SPARSEMEM
+    - memblock: ensure there is no overflow in memblock_overlaps_region()
+    - arm: extend pfn_valid to take into account freed memory map alignment
+    - arm: ioremap: don't abuse pfn_valid() to check if pfn is in RAM
+    - Linux 5.4.167
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 07 Mar 2022 17:07:14 +0100
+
+linux (5.4.0-104.118) focal; urgency=medium
+
+  * CVE-2022-23960
+    - SAUCE: kvm: arm: fix build on 32-bit
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 02 Mar 2022 14:10:18 -0300
+
+linux (5.4.0-103.117) focal; urgency=medium
+
+  * CVE-2022-23960
+    - arm64: Add part number for Arm Cortex-A77
+    - arm64: Add Neoverse-N2, Cortex-A710 CPU part definition
+    - arm64: Add Cortex-X2 CPU part definition
+    - arm64: add ID_AA64ISAR2_EL1 sys register
+    - SAUCE: arm64: entry.S: Add ventry overflow sanity checks
+    - SAUCE: arm64: entry: Make the trampoline cleanup optional
+    - SAUCE: arm64: entry: Free up another register on kpti's tramp_exit path
+    - SAUCE: arm64: entry: Move the trampoline data page before the text page
+    - SAUCE: arm64: entry: Allow tramp_alias to access symbols after the 4K
+      boundary
+    - SAUCE: arm64: entry: Don't assume tramp_vectors is the start of the vectors
+    - SAUCE: arm64: entry: Move trampoline macros out of ifdef'd section
+    - SAUCE: arm64: entry: Make the kpti trampoline's kpti sequence optional
+    - SAUCE: arm64: entry: Allow the trampoline text to occupy multiple pages
+    - SAUCE: arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations
+    - SAUCE: arm64: entry: Add vectors that have the bhb mitigation sequences
+    - SAUCE: arm64: entry: Add macro for reading symbol addresses from the
+      trampoline
+    - SAUCE: arm64: Add percpu vectors for EL1
+    - SAUCE: arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of
+      Spectre-v2
+    - SAUCE: KVM: arm64: Add templates for BHB mitigation sequences
+    - SAUCE: arm64: Mitigate spectre style branch history side channels
+    - SAUCE: KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and
+      migrated
+    - SAUCE: arm64: Use the clearbhb instruction in mitigations
+    - [Config]: set CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+
+  * CVE-2022-25636
+    - netfilter: nf_tables_offload: incorrect flow offload action array size
+
+  * CVE-2022-0001
+    - 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
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 02 Mar 2022 05:33:12 -0300
+
+linux (5.4.0-100.113) focal; urgency=medium
+
+  * focal/linux: 5.4.0-100.113 -proposed tracker (LP: #1959900)
+
+  * CVE-2022-22942
+    - SAUCE: drm/vmwgfx: Fix stale file descriptors on failed usercopy
+
+  * CVE-2022-0330
+    - drm/i915: Flush TLBs before releasing backing store
+
+  * Focal update: v5.4.166 upstream stable release (LP: #1957008)
+    - netfilter: selftest: conntrack_vrf.sh: fix file permission
+    - Linux 5.4.166
+    - net/packet: rx_owner_map depends on pg_vec
+    - USB: gadget: bRequestType is a bitfield, not a enum
+    - HID: holtek: fix mouse probing
+    - udp: using datalen to cap ipv6 udp max gso segments
+    - selftests: Calculate udpgso segment count without header adjustment
+
+  * Focal update: v5.4.165 upstream stable release (LP: #1957007)
+    - serial: tegra: Change lower tolerance baud rate limit for tegra20 and
+      tegra30
+    - ntfs: fix ntfs_test_inode and ntfs_init_locked_inode function type
+    - HID: quirks: Add quirk for the Microsoft Surface 3 type-cover
+    - HID: google: add eel USB id
+    - HID: add hid_is_usb() function to make it simpler for USB detection
+    - HID: add USB_HID dependancy to hid-prodikeys
+    - HID: add USB_HID dependancy to hid-chicony
+    - HID: add USB_HID dependancy on some USB HID drivers
+    - HID: bigbenff: prevent null pointer dereference
+    - HID: wacom: fix problems when device is not a valid USB device
+    - HID: check for valid USB device for many HID drivers
+    - can: kvaser_usb: get CAN clock frequency from device
+    - can: kvaser_pciefd: kvaser_pciefd_rx_error_frame(): increase correct
+      stats->{rx,tx}_errors counter
+    - can: sja1000: fix use after free in ems_pcmcia_add_card()
+    - nfc: fix potential NULL pointer deref in nfc_genl_dump_ses_done
+    - selftests: netfilter: add a vrf+conntrack testcase
+    - vrf: don't run conntrack on vrf with !dflt qdisc
+    - bpf: Fix the off-by-two error in range markings
+    - ice: ignore dropped packets during init
+    - bonding: make tx_rebalance_counter an atomic
+    - nfp: Fix memory leak in nfp_cpp_area_cache_add()
+    - seg6: fix the iif in the IPv6 socket control block
+    - udp: using datalen to cap max gso segments
+    - iavf: restore MSI state on reset
+    - iavf: Fix reporting when setting descriptor count
+    - IB/hfi1: Correct guard on eager buffer deallocation
+    - mm: bdi: initialize bdi_min_ratio when bdi is unregistered
+    - ALSA: ctl: Fix copy of updated id with element read/write
+    - ALSA: hda/realtek - Add headset Mic support for Lenovo ALC897 platform
+    - ALSA: pcm: oss: Fix negative period/buffer sizes
+    - ALSA: pcm: oss: Limit the period size to 16MB
+    - ALSA: pcm: oss: Handle missing errors in snd_pcm_oss_change_params*()
+    - btrfs: clear extent buffer uptodate when we fail to write it
+    - btrfs: replace the BUG_ON in btrfs_del_root_ref with proper error handling
+    - nfsd: Fix nsfd startup race (again)
+    - tracefs: Have new files inherit the ownership of their parent
+    - clk: qcom: regmap-mux: fix parent clock lookup
+    - drm/syncobj: Deal with signalled fences in drm_syncobj_find_fence.
+    - can: pch_can: pch_can_rx_normal: fix use after free
+    - can: m_can: Disable and ignore ELO interrupt
+    - x86/sme: Explicitly map new EFI memmap table as encrypted
+    - libata: add horkage for ASMedia 1092
+    - wait: add wake_up_pollfree()
+    - SAUCE: binder: export __wake_up_pollfree for binder module
+    - binder: use wake_up_pollfree()
+    - signalfd: use wake_up_pollfree()
+    - aio: keep poll requests on waitqueue until completed
+    - aio: fix use-after-free due to missing POLLFREE handling
+    - tracefs: Set all files to the same group ownership as the mount option
+    - block: fix ioprio_get(IOPRIO_WHO_PGRP) vs setuid(2)
+    - qede: validate non LSO skb length
+    - ASoC: qdsp6: q6routing: Fix return value from msm_routing_put_audio_mixer
+    - i40e: Fix failed opcode appearing if handling messages from VF
+    - i40e: Fix pre-set max number of queues for VF
+    - mtd: rawnand: fsmc: Take instruction delay into account
+    - mtd: rawnand: fsmc: Fix timing computation
+    - dt-bindings: net: Reintroduce PHY no lane swap binding
+    - tools build: Remove needless libpython-version feature check that breaks
+      test-all fast path
+    - net: cdc_ncm: Allow for dwNtbOutMaxSize to be unset or zero
+    - net: altera: set a couple error code in probe()
+    - net: fec: only clear interrupt of handling queue in fec_enet_rx_queue()
+    - net, neigh: clear whole pneigh_entry at alloc time
+    - net/qla3xxx: fix an error code in ql_adapter_up()
+    - Revert "UBUNTU: SAUCE: selftests: fib_tests: assign address to dummy1 for
+      rp_filter tests"
+    - selftests/fib_tests: Rework fib_rp_filter_test()
+    - USB: gadget: detect too-big endpoint 0 requests
+    - USB: gadget: zero allocate endpoint 0 buffers
+    - usb: core: config: fix validation of wMaxPacketValue entries
+    - xhci: Remove CONFIG_USB_DEFAULT_PERSIST to prevent xHCI from runtime
+      suspending
+    - usb: core: config: using bit mask instead of individual bits
+    - xhci: avoid race between disable slot command and host runtime suspend
+    - iio: trigger: Fix reference counting
+    - iio: trigger: stm32-timer: fix MODULE_ALIAS
+    - iio: stk3310: Don't return error code in interrupt handler
+    - iio: mma8452: Fix trigger reference couting
+    - iio: ltr501: Don't return error code in trigger handler
+    - iio: kxsd9: Don't return error code in trigger handler
+    - iio: itg3200: Call iio_trigger_notify_done() on error
+    - iio: dln2-adc: Fix lockdep complaint
+    - iio: dln2: Check return value of devm_iio_trigger_register()
+    - iio: at91-sama5d2: Fix incorrect sign extension
+    - iio: adc: axp20x_adc: fix charging current reporting on AXP22x
+    - iio: ad7768-1: Call iio_trigger_notify_done() on error
+    - iio: accel: kxcjk-1013: Fix possible memory leak in probe and remove
+    - irqchip/armada-370-xp: Fix return value of armada_370_xp_msi_alloc()
+    - irqchip/armada-370-xp: Fix support for Multi-MSI interrupts
+    - irqchip/irq-gic-v3-its.c: Force synchronisation when issuing INVALL
+    - irqchip: nvic: Fix offset for Interrupt Priority Offsets
+    - misc: fastrpc: fix improper packet size calculation
+    - bpf: Add selftests to cover packet access corner cases
+    - Linux 5.4.165
+
+  * Focal update: v5.4.164 upstream stable release (LP: #1956381)
+    - NFSv42: Fix pagecache invalidation after COPY/CLONE
+    - of: clk: Make <linux/of_clk.h> self-contained
+    - arm64: dts: mcbin: support 2W SFP modules
+    - can: j1939: j1939_tp_cmd_recv(): check the dst address of TP.CM_BAM
+    - gfs2: Fix length of holes reported at end-of-file
+    - drm/sun4i: fix unmet dependency on RESET_CONTROLLER for PHY_SUN6I_MIPI_DPHY
+    - mac80211: do not access the IV when it was stripped
+    - net/smc: Transfer remaining wait queue entries during fallback
+    - atlantic: Fix OOB read and write in hw_atl_utils_fw_rpc_wait
+    - net: return correct error code
+    - platform/x86: thinkpad_acpi: Fix WWAN device disabled issue after S3 deep
+    - s390/setup: avoid using memblock_enforce_memory_limit
+    - btrfs: check-integrity: fix a warning on write caching disabled disk
+    - thermal: core: Reset previous low and high trip during thermal zone init
+    - scsi: iscsi: Unblock session then wake up error handler
+    - ata: ahci: Add Green Sardine vendor ID as board_ahci_mobile
+    - ethernet: hisilicon: hns: hns_dsaf_misc: fix a possible array overflow in
+      hns_dsaf_ge_srst_by_port()
+    - net: tulip: de4x5: fix the problem that the array 'lp->phy[8]' may be out of
+      bound
+    - net: ethernet: dec: tulip: de4x5: fix possible array overflows in
+      type3_infoblock()
+    - perf hist: Fix memory leak of a perf_hpp_fmt
+    - perf report: Fix memory leaks around perf_tip()
+    - net/smc: Avoid warning of possible recursive locking
+    - vrf: Reset IPCB/IP6CB when processing outbound pkts in vrf dev xmit
+    - kprobes: Limit max data_size of the kretprobe instances
+    - rt2x00: do not mark device gone on EPROTO errors during start
+    - cpufreq: Fix get_cpu_device() failure in add_cpu_dev_symlink()
+    - s390/pci: move pseudo-MMIO to prevent MIO overlap
+    - sata_fsl: fix UAF in sata_fsl_port_stop when rmmod sata_fsl
+    - sata_fsl: fix warning in remove_proc_entry when rmmod sata_fsl
+    - i2c: stm32f7: flush TX FIFO upon transfer errors
+    - i2c: stm32f7: recover the bus on access timeout
+    - i2c: stm32f7: stop dma transfer in case of NACK
+    - i2c: cbus-gpio: set atomic transfer callback
+    - natsemi: xtensa: fix section mismatch warnings
+    - net: qlogic: qlcnic: Fix a NULL pointer dereference in
+      qlcnic_83xx_add_rings()
+    - net: mpls: Fix notifications when deleting a device
+    - siphash: use _unaligned version by default
+    - net/mlx4_en: Fix an use-after-free bug in mlx4_en_try_alloc_resources()
+    - selftests: net: Correct case name
+    - rxrpc: Fix rxrpc_local leak in rxrpc_lookup_peer()
+    - net: usb: lan78xx: lan78xx_phy_init(): use PHY_POLL instead of "0" if no IRQ
+      is available
+    - net: marvell: mvpp2: Fix the computation of shared CPUs
+    - net: annotate data-races on txq->xmit_lock_owner
+    - ipv4: convert fib_num_tclassid_users to atomic_t
+    - net/rds: correct socket tunable error in rds_tcp_tune()
+    - net/smc: Keep smc_close_final rc during active close
+    - drm/msm: Do hw_init() before capturing GPU state
+    - ipv6: fix memory leak in fib6_rule_suppress
+    - KVM: x86/pmu: Fix reserved bits for AMD PerfEvtSeln register
+    - sched/uclamp: Fix rq->uclamp_max not set on first enqueue
+    - parisc: Fix KBUILD_IMAGE for self-extracting kernel
+    - parisc: Fix "make install" on newer debian releases
+    - vgacon: Propagate console boot parameters before calling `vc_resize'
+    - xhci: Fix commad ring abort, write all 64 bits to CRCR register.
+    - USB: NO_LPM quirk Lenovo Powered USB-C Travel Hub
+    - usb: typec: tcpm: Wait in SNK_DEBOUNCED until disconnect
+    - x86/tsc: Add a timer to make sure TSC_adjust is always checked
+    - x86/tsc: Disable clocksource watchdog for TSC on qualified platorms
+    - x86/64/mm: Map all kernel memory into trampoline_pgd
+    - tty: serial: msm_serial: Deactivate RX DMA for polling support
+    - serial: pl011: Add ACPI SBSA UART match id
+    - serial: core: fix transmit-buffer reset and memleak
+    - serial: 8250_pci: Fix ACCES entries in pci_serial_quirks array
+    - serial: 8250_pci: rewrite pericom_do_set_divisor()
+    - iwlwifi: mvm: retry init flow if failed
+    - parisc: Mark cr16 CPU clocksource unstable on all SMP machines
+    - net/tls: Fix authentication failure in CCM mode
+    - Linux 5.4.164
+
+  * Focal update: v5.4.163 upstream stable release (LP: #1956380)
+    - USB: serial: option: add Telit LE910S1 0x9200 composition
+    - USB: serial: option: add Fibocom FM101-GL variants
+    - usb: dwc2: gadget: Fix ISOC flow for elapsed frames
+    - usb: dwc2: hcd_queue: Fix use of floating point literal
+    - net: nexthop: fix null pointer dereference when IPv6 is not enabled
+    - usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts
+    - usb: hub: Fix usb enumeration issue due to address0 race
+    - usb: hub: Fix locking issues with address0_mutex
+    - binder: fix test regression due to sender_euid change
+    - ALSA: ctxfi: Fix out-of-range access
+    - media: cec: copy sequence field for the reply
+    - HID: wacom: Use "Confidence" flag to prevent reporting invalid contacts
+    - staging/fbtft: Fix backlight
+    - staging: rtl8192e: Fix use after free in _rtl92e_pci_disconnect()
+    - xen: don't continue xenstore initialization in case of errors
+    - xen: detect uninitialized xenbus in xenbus_init
+    - KVM: PPC: Book3S HV: Prevent POWER7/8 TLB flush flushing SLB
+    - tracing/uprobe: Fix uprobe_perf_open probes iteration
+    - tracing: Fix pid filtering when triggers are attached
+    - mmc: sdhci: Fix ADMA for PAGE_SIZE >= 64KiB
+    - mdio: aspeed: Fix "Link is Down" issue
+    - PCI: aardvark: Deduplicate code in advk_pcie_rd_conf()
+    - PCI: aardvark: Wait for endpoint to be ready before training link
+    - PCI: aardvark: Fix big endian support
+    - PCI: aardvark: Train link immediately after enabling training
+    - PCI: aardvark: Improve link training
+    - PCI: aardvark: Issue PERST via GPIO
+    - PCI: aardvark: Replace custom macros by standard linux/pci_regs.h macros
+    - PCI: aardvark: Don't touch PCIe registers if no card connected
+    - PCI: aardvark: Fix compilation on s390
+    - PCI: aardvark: Move PCIe reset card code to advk_pcie_train_link()
+    - PCI: aardvark: Update comment about disabling link training
+    - PCI: pci-bridge-emul: Fix array overruns, improve safety
+    - PCI: aardvark: Configure PCIe resources from 'ranges' DT property
+    - PCI: aardvark: Fix PCIe Max Payload Size setting
+    - PCI: aardvark: Implement re-issuing config requests on CRS response
+    - PCI: aardvark: Simplify initialization of rootcap on virtual bridge
+    - PCI: aardvark: Fix link training
+    - PCI: aardvark: Fix support for bus mastering and PCI_COMMAND on emulated
+      bridge
+    - PCI: aardvark: Set PCI Bridge Class Code to PCI Bridge
+    - PCI: aardvark: Fix support for PCI_BRIDGE_CTL_BUS_RESET on emulated bridge
+    - pinctrl: armada-37xx: Correct PWM pins definitions
+    - arm64: dts: marvell: armada-37xx: Set pcie_reset_pin to gpio function
+    - proc/vmcore: fix clearing user buffer by properly using clear_user()
+    - netfilter: ipvs: Fix reuse connection if RS weight is 0
+    - ARM: dts: BCM5301X: Fix I2C controller interrupt
+    - ARM: dts: BCM5301X: Add interrupt properties to GPIO node
+    - ASoC: qdsp6: q6routing: Conditionally reset FrontEnd Mixer
+    - ASoC: topology: Add missing rwsem around snd_ctl_remove() calls
+    - net: ieee802154: handle iftypes as u32
+    - firmware: arm_scmi: pm: Propagate return value to caller
+    - NFSv42: Don't fail clone() unless the OP_CLONE operation failed
+    - ARM: socfpga: Fix crash with CONFIG_FORTIRY_SOURCE
+    - scsi: mpt3sas: Fix kernel panic during drive powercycle test
+    - drm/vc4: fix error code in vc4_create_object()
+    - iavf: Prevent changing static ITR values if adaptive moderation is on
+    - ipv6: fix typos in __ip6_finish_output()
+    - nfp: checking parameter process for rx-usecs/tx-usecs is invalid
+    - net: ipv6: add fib6_nh_release_dsts stub
+    - net: nexthop: release IPv6 per-cpu dsts when replacing a nexthop group
+    - scsi: core: sysfs: Fix setting device state to SDEV_RUNNING
+    - net/smc: Ensure the active closing peer first closes clcsock
+    - nvmet-tcp: fix incomplete data digest send
+    - net/ncsi : Add payload to be 32-bit aligned to fix dropped packets
+    - PM: hibernate: use correct mode for swsusp_close()
+    - tcp_cubic: fix spurious Hystart ACK train detections for not-cwnd-limited
+      flows
+    - nvmet: use IOCB_NOWAIT only if the filesystem supports it
+    - igb: fix netpoll exit with traffic
+    - MIPS: use 3-level pgtable for 64KB page size on MIPS_VA_BITS_48
+    - net: vlan: fix underflow for the real_dev refcnt
+    - net/smc: Don't call clcsock shutdown twice when smc shutdown
+    - net: hns3: fix VF RSS failed problem after PF enable multi-TCs
+    - net: mscc: ocelot: don't downgrade timestamping RX filters in SIOCSHWTSTAMP
+    - net: mscc: ocelot: correctly report the timestamping RX filters in ethtool
+    - f2fs: set SBI_NEED_FSCK flag when inconsistent node block found
+    - smb3: do not error on fsync when readonly
+    - vhost/vsock: fix incorrect used length reported to the guest
+    - tracing: Check pid filtering when creating events
+    - s390/mm: validate VMA in PGSTE manipulation functions
+    - shm: extend forced shm destroy to support objects from several IPC nses
+    - NFC: add NCI_UNREG flag to eliminate the race
+    - fuse: release pipe buf after last use
+    - xen: sync include/xen/interface/io/ring.h with Xen's newest version
+    - xen/blkfront: read response from backend only once
+    - xen/blkfront: don't take local copy of a request from the ring page
+    - xen/blkfront: don't trust the backend response data blindly
+    - xen/netfront: read response from backend only once
+    - xen/netfront: don't read data from request on the ring page
+    - xen/netfront: disentangle tx_skb_freelist
+    - xen/netfront: don't trust the backend response data blindly
+    - tty: hvc: replace BUG_ON() with negative return value
+    - Linux 5.4.163
+
+  * net/mlx5e: EPERM on vlan 0 programming (LP: #1957753)
+    - net/mlx5e: Unblock setting vid 0 for VF in case PF isn't eswitch manager
+
+  * CVE-2021-4083
+    - fget: check that the fd still exists after getting a ref to it
+
+  * CVE-2021-4155
+    - xfs: map unwritten blocks in XFS_IOC_{ALLOC, FREE}SP just like fallocate
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 03 Feb 2022 19:16:55 +0100
+
+linux (5.4.0-99.112) focal; urgency=medium
+
+  * focal/linux: 5.4.0-99.112 -proposed tracker (LP: #1959817)
+
+  * linux-image-5.4.0-97.110 freezes by accessing cifs shares (LP: #1959665)
+    - Revert "cifs: To match file servers, make sure the server hostname matches"
+    - Revert "cifs: set a minimum of 120s for next dns resolution"
+    - Revert "cifs: use the expiry output of dns_query to schedule next
+      resolution"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 02 Feb 2022 17:21:18 +0100
+
+linux (5.4.0-97.110) focal; urgency=medium
+
+  * icmp_redirect from selftests fails on F/kvm (unary operator expected)
+    (LP: #1938964)
+    - selftests: icmp_redirect: pass xfail=0 to log_test()
+
+  * Focal: CIFS stable updates (LP: #1954926)
+    - cifs: use the expiry output of dns_query to schedule next resolution
+    - cifs: set a minimum of 120s for next dns resolution
+    - cifs: To match file servers, make sure the server hostname matches
+
+  * seccomp_bpf in seccomp from ubuntu_kernel_selftests failed to build on B-5.4
+    (LP: #1896420)
+    - SAUCE: selftests/seccomp: fix "storage size of 'md' isn't known" build issue
+    - SAUCE: selftests/seccomp: Fix s390x regs not defined issue
+
+  * system crash when removing ipmi_msghandler module (LP: #1950666)
+    - ipmi: Move remove_work to dedicated workqueue
+    - ipmi: msghandler: Make symbol 'remove_work_wq' static
+
+  * zcrypt DD: Toleration for new IBM Z Crypto Hardware - (Backport to Ubuntu
+    20.04) (LP: #1954680)
+    - s390/AP: support new dynamic AP bus size limit
+
+  * [UBUNTU 20.04] KVM hardware diagnose data improvements for guest kernel -
+    kernel part (LP: #1953334)
+    - s390/setup: diag 318: refactor struct
+    - s390/kvm: diagnose 0x318 sync and reset
+    - KVM: s390: remove diag318 reset code
+    - KVM: s390: add debug statement for diag 318 CPNC data
+
+  * Updates to ib_peer_memory requested by Nvidia (LP: #1947206)
+    - SAUCE: RDMA/core: Updated ib_peer_memory
+
+  * Include Infiniband Peer Memory interface (LP: #1923104)
+    - IB: Allow calls to ib_umem_get from kernel ULPs
+    - SAUCE: RDMA/core: Introduce peer memory interface
+
+  * Focal update: v5.4.162 upstream stable release (LP: #1954834)
+    - arm64: zynqmp: Do not duplicate flash partition label property
+    - arm64: zynqmp: Fix serial compatible string
+    - ARM: dts: NSP: Fix mpcore, mmc node names
+    - scsi: lpfc: Fix list_add() corruption in lpfc_drain_txq()
+    - arm64: dts: hisilicon: fix arm,sp805 compatible string
+    - RDMA/bnxt_re: Check if the vlan is valid before reporting
+    - usb: musb: tusb6010: check return value after calling
+      platform_get_resource()
+    - usb: typec: tipd: Remove WARN_ON in tps6598x_block_read
+    - arm64: dts: qcom: msm8998: Fix CPU/L2 idle state latency and residency
+    - arm64: dts: freescale: fix arm,sp805 compatible string
+    - ASoC: SOF: Intel: hda-dai: fix potential locking issue
+    - clk: imx: imx6ul: Move csi_sel mux to correct base register
+    - ASoC: nau8824: Add DMI quirk mechanism for active-high jack-detect
+    - scsi: advansys: Fix kernel pointer leak
+    - firmware_loader: fix pre-allocated buf built-in firmware use
+    - ARM: dts: omap: fix gpmc,mux-add-data type
+    - usb: host: ohci-tmio: check return value after calling
+      platform_get_resource()
+    - ARM: dts: ls1021a: move thermal-zones node out of soc/
+    - ARM: dts: ls1021a-tsn: use generic "jedec,spi-nor" compatible for flash
+    - ALSA: ISA: not for M68K
+    - tty: tty_buffer: Fix the softlockup issue in flush_to_ldisc
+    - MIPS: sni: Fix the build
+    - scsi: target: Fix ordered tag handling
+    - scsi: target: Fix alua_tg_pt_gps_count tracking
+    - iio: imu: st_lsm6dsx: Avoid potential array overflow in st_lsm6dsx_set_odr()
+    - powerpc/5200: dts: fix memory node unit name
+    - ALSA: gus: fix null pointer dereference on pointer block
+    - powerpc/dcr: Use cmplwi instead of 3-argument cmpli
+    - sh: check return code of request_irq
+    - maple: fix wrong return value of maple_bus_init().
+    - f2fs: fix up f2fs_lookup tracepoints
+    - sh: fix kconfig unmet dependency warning for FRAME_POINTER
+    - sh: math-emu: drop unused functions
+    - sh: define __BIG_ENDIAN for math-emu
+    - clk: ingenic: Fix bugs with divided dividers
+    - clk/ast2600: Fix soc revision for AHB
+    - clk: qcom: gcc-msm8996: Drop (again) gcc_aggre1_pnoc_ahb_clk
+    - mips: BCM63XX: ensure that CPU_SUPPORTS_32BIT_KERNEL is set
+    - sched/core: Mitigate race cpus_share_cache()/update_top_cache_domain()
+    - tracing: Save normal string variables
+    - tracing/histogram: Do not copy the fixed-size char array field over the
+      field size
+    - RDMA/netlink: Add __maybe_unused to static inline in C file
+    - perf bpf: Avoid memory leak from perf_env__insert_btf()
+    - perf bench futex: Fix memory leak of perf_cpu_map__new()
+    - perf tests: Remove bash construct from record+zstd_comp_decomp.sh
+    - net: bnx2x: fix variable dereferenced before check
+    - iavf: check for null in iavf_fix_features
+    - iavf: free q_vectors before queues in iavf_disable_vf
+    - iavf: Fix failure to exit out from last all-multicast mode
+    - iavf: prevent accidental free of filter structure
+    - iavf: validate pointers
+    - iavf: Fix for the false positive ASQ/ARQ errors while issuing VF reset
+    - MIPS: generic/yamon-dt: fix uninitialized variable error
+    - mips: bcm63xx: add support for clk_get_parent()
+    - mips: lantiq: add support for clk_get_parent()
+    - platform/x86: hp_accel: Fix an error handling path in 'lis3lv02d_probe()'
+    - scsi: core: sysfs: Fix hang when device state is set via sysfs
+    - net: sched: act_mirred: drop dst for the direction from egress to ingress
+    - net: dpaa2-eth: fix use-after-free in dpaa2_eth_remove
+    - net: virtio_net_hdr_to_skb: count transport header in UFO
+    - i40e: Fix correct max_pkt_size on VF RX queue
+    - i40e: Fix NULL ptr dereference on VSI filter sync
+    - i40e: Fix changing previously set num_queue_pairs for PFs
+    - i40e: Fix ping is lost after configuring ADq on VF
+    - i40e: Fix creation of first queue by omitting it if is not power of two
+    - i40e: Fix display error code in dmesg
+    - NFC: reorganize the functions in nci_request
+    - drm/nouveau: hdmigv100.c: fix corrupted HDMI Vendor InfoFrame
+    - NFC: reorder the logic in nfc_{un,}register_device
+    - KVM: PPC: Book3S HV: Use GLOBAL_TOC for kvmppc_h_set_dabr/xdabr()
+    - perf/x86/intel/uncore: Fix filter_tid mask for CHA events on Skylake Server
+    - perf/x86/intel/uncore: Fix IIO event constraints for Skylake Server
+    - s390/kexec: fix return code handling
+    - arm64: vdso32: suppress error message for 'make mrproper'
+    - tun: fix bonding active backup with arp monitoring
+    - hexagon: export raw I/O routines for modules
+    - ipc: WARN if trying to remove ipc object which is absent
+    - mm: kmemleak: slob: respect SLAB_NOLEAKTRACE flag
+    - x86/hyperv: Fix NULL deref in set_hv_tscchange_cb() if Hyper-V setup fails
+    - s390/kexec: fix memory leak of ipl report buffer
+    - udf: Fix crash after seekdir
+    - btrfs: fix memory ordering between normal and ordered work functions
+    - parisc/sticon: fix reverse colors
+    - cfg80211: call cfg80211_stop_ap when switch from P2P_GO type
+    - drm/udl: fix control-message timeout
+    - drm/nouveau: use drm_dev_unplug() during device removal
+    - drm/i915/dp: Ensure sink rate values are always valid
+    - drm/amdgpu: fix set scaling mode Full/Full aspect/Center not works on vga
+      and dvi connectors
+    - Revert "net: mvpp2: disable force link UP during port init procedure"
+    - perf/core: Avoid put_page() when GUP fails
+    - batman-adv: Consider fragmentation for needed_headroom
+    - batman-adv: Reserve needed_*room for fragments
+    - batman-adv: Don't always reallocate the fragmentation skb head
+    - ASoC: DAPM: Cover regression by kctl change notification fix
+    - usb: max-3421: Use driver data instead of maintaining a list of bound
+      devices
+    - ice: Delete always true check of PF pointer
+    - ALSA: hda: hdac_ext_stream: fix potential locking issues
+    - ALSA: hda: hdac_stream: fix potential locking issue in
+      snd_hdac_stream_assign()
+    - Linux 5.4.162
+
+  * Focal update: v5.4.161 upstream stable release (LP: #1954828)
+    - scsi: ufs: Fix interrupt error message for shared interrupts
+    - MIPS: Fix assembly error from MIPSr2 code used within MIPS_ISA_ARCH_LEVEL
+    - ext4: fix lazy initialization next schedule time computation in more
+      granular unit
+    - scsi: ufs: Fix tm request when non-fatal error happens
+    - fortify: Explicitly disable Clang support
+    - parisc/entry: fix trace test in syscall exit path
+    - PCI/MSI: Destroy sysfs before freeing entries
+    - PCI/MSI: Deal with devices lying about their MSI mask capability
+    - PCI: Add MSI masking quirk for Nvidia ION AHCI
+    - erofs: remove the occupied parameter from z_erofs_pagevec_enqueue()
+    - erofs: fix unsafe pagevec reuse of hooked pclusters
+    - Linux 5.4.161
+
+  * Focal update: v5.4.160 upstream stable release (LP: #1953387)
+    - xhci: Fix USB 3.1 enumeration issues by increasing roothub power-on-good
+      delay
+    - usb: xhci: Enable runtime-pm by default on AMD Yellow Carp platform
+    - binder: use euid from cred instead of using task
+    - binder: use cred instead of task for selinux checks
+    - binder: use cred instead of task for getsecid
+    - Input: iforce - fix control-message timeout
+    - Input: elantench - fix misreporting trackpoint coordinates
+    - Input: i8042 - Add quirk for Fujitsu Lifebook T725
+    - libata: fix read log timeout value
+    - ocfs2: fix data corruption on truncate
+    - scsi: qla2xxx: Fix kernel crash when accessing port_speed sysfs file
+    - scsi: qla2xxx: Fix use after free in eh_abort path
+    - mmc: dw_mmc: Dont wait for DRTO on Write RSP error
+    - parisc: Fix ptrace check on syscall return
+    - tpm: Check for integer overflow in tpm2_map_response_body()
+    - firmware/psci: fix application of sizeof to pointer
+    - crypto: s5p-sss - Add error handling in s5p_aes_probe()
+    - media: ite-cir: IR receiver stop working after receive overflow
+    - media: ir-kbd-i2c: improve responsiveness of hauppauge zilog receivers
+    - media: v4l2-ioctl: Fix check_ext_ctrls
+    - ALSA: hda/realtek: Add quirk for Clevo PC70HS
+    - ALSA: hda/realtek: Add a quirk for Acer Spin SP513-54N
+    - ALSA: hda/realtek: Add quirk for ASUS UX550VE
+    - ALSA: hda/realtek: Add quirk for HP EliteBook 840 G7 mute LED
+    - ALSA: ua101: fix division by zero at probe
+    - ALSA: 6fire: fix control and bulk message timeouts
+    - ALSA: line6: fix control and interrupt message timeouts
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 400
+    - ALSA: synth: missing check for possible NULL after the call to kstrdup
+    - ALSA: timer: Fix use-after-free problem
+    - ALSA: timer: Unconditionally unlink slave instances, too
+    - fuse: fix page stealing
+    - x86/sme: Use #define USE_EARLY_PGTABLE_L5 in mem_encrypt_identity.c
+    - x86/cpu: Fix migration safety with X86_BUG_NULL_SEL
+    - x86/irq: Ensure PI wakeup handler is unregistered before module unload
+    - cavium: Return negative value when pci_alloc_irq_vectors() fails
+    - scsi: qla2xxx: Return -ENOMEM if kzalloc() fails
+    - scsi: qla2xxx: Fix unmap of already freed sgl
+    - cavium: Fix return values of the probe function
+    - sfc: Don't use netif_info before net_device setup
+    - hyperv/vmbus: include linux/bitops.h
+    - ARM: dts: sun7i: A20-olinuxino-lime2: Fix ethernet phy-mode
+    - reset: socfpga: add empty driver allowing consumers to probe
+    - mmc: winbond: don't build on M68K
+    - drm: panel-orientation-quirks: Add quirk for Aya Neo 2021
+    - bpf: Define bpf_jit_alloc_exec_limit for arm64 JIT
+    - bpf: Prevent increasing bpf_jit_limit above max
+    - xen/netfront: stop tx queues during live migration
+    - nvmet-tcp: fix a memory leak when releasing a queue
+    - spi: spl022: fix Microwire full duplex mode
+    - net: multicast: calculate csum of looped-back and forwarded packets
+    - watchdog: Fix OMAP watchdog early handling
+    - drm: panel-orientation-quirks: Add quirk for GPD Win3
+    - nvmet-tcp: fix header digest verification
+    - r8169: Add device 10ec:8162 to driver r8169
+    - vmxnet3: do not stop tx queues after netif_device_detach()
+    - nfp: bpf: relax prog rejection for mtu check through max_pkt_offset
+    - net/smc: Correct spelling mistake to TCPF_SYN_RECV
+    - btrfs: clear MISSING device status bit in btrfs_close_one_device
+    - btrfs: fix lost error handling when replaying directory deletes
+    - btrfs: call btrfs_check_rw_degradable only if there is a missing device
+    - ia64: kprobes: Fix to pass correct trampoline address to the handler
+    - hwmon: (pmbus/lm25066) Add offset coefficients
+    - regulator: s5m8767: do not use reset value as DVS voltage if GPIO DVS is
+      disabled
+    - regulator: dt-bindings: samsung,s5m8767: correct s5m8767,pmic-buck-default-
+      dvs-idx property
+    - EDAC/sb_edac: Fix top-of-high-memory value for Broadwell/Haswell
+    - mwifiex: fix division by zero in fw download path
+    - ath6kl: fix division by zero in send path
+    - ath6kl: fix control-message timeout
+    - ath10k: fix control-message timeout
+    - ath10k: fix division by zero in send path
+    - PCI: Mark Atheros QCA6174 to avoid bus reset
+    - rtl8187: fix control-message timeouts
+    - evm: mark evm_fixmode as __ro_after_init
+    - wcn36xx: Fix HT40 capability for 2Ghz band
+    - mwifiex: Read a PCI register after writing the TX ring write pointer
+    - libata: fix checking of DMA state
+    - wcn36xx: handle connection loss indication
+    - rsi: fix occasional initialisation failure with BT coex
+    - rsi: fix key enabled check causing unwanted encryption for vap_id > 0
+    - rsi: fix rate mask set leading to P2P failure
+    - rsi: Fix module dev_oper_mode parameter description
+    - RDMA/qedr: Fix NULL deref for query_qp on the GSI QP
+    - signal: Remove the bogus sigkill_pending in ptrace_stop
+    - signal/mips: Update (_save|_restore)_fp_context to fail with -EFAULT
+    - power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
+    - power: supply: max17042_battery: use VFSOC for capacity when no rsns
+    - KVM: nVMX: Query current VMCS when determining if MSR bitmaps are in use
+    - can: j1939: j1939_tp_cmd_recv(): ignore abort message in the BAM transport
+    - can: j1939: j1939_can_recv(): ignore messages with invalid source address
+    - powerpc/85xx: Fix oops when mpc85xx_smp_guts_ids node cannot be found
+    - serial: core: Fix initializing and restoring termios speed
+    - ALSA: mixer: oss: Fix racy access to slots
+    - ALSA: mixer: fix deadlock in snd_mixer_oss_set_volume
+    - xen/balloon: add late_initcall_sync() for initial ballooning done
+    - PCI: pci-bridge-emul: Fix emulation of W1C bits
+    - PCI: aardvark: Do not clear status bits of masked interrupts
+    - PCI: aardvark: Fix checking for link up via LTSSM state
+    - PCI: aardvark: Do not unmask unused interrupts
+    - PCI: aardvark: Fix reporting Data Link Layer Link Active
+    - PCI: aardvark: Fix return value of MSI domain .alloc() method
+    - PCI: aardvark: Read all 16-bits from PCIE_MSI_PAYLOAD_REG
+    - quota: check block number when reading the block in quota file
+    - quota: correct error number in free_dqentry()
+    - pinctrl: core: fix possible memory leak in pinctrl_enable()
+    - iio: dac: ad5446: Fix ad5622_write() return value
+    - USB: serial: keyspan: fix memleak on probe errors
+    - USB: iowarrior: fix control-message timeouts
+    - USB: chipidea: fix interrupt deadlock
+    - dma-buf: WARN on dmabuf release with pending attachments
+    - drm: panel-orientation-quirks: Update the Lenovo Ideapad D330 quirk (v2)
+    - drm: panel-orientation-quirks: Add quirk for KD Kurio Smart C15200 2-in-1
+    - drm: panel-orientation-quirks: Add quirk for the Samsung Galaxy Book 10.6
+    - Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg()
+    - Bluetooth: fix use-after-free error in lock_sock_nested()
+    - drm/panel-orientation-quirks: add Valve Steam Deck
+    - platform/x86: wmi: do not fail if disabling fails
+    - MIPS: lantiq: dma: add small delay after reset
+    - MIPS: lantiq: dma: reset correct number of channel
+    - locking/lockdep: Avoid RCU-induced noinstr fail
+    - net: sched: update default qdisc visibility after Tx queue cnt changes
+    - smackfs: Fix use-after-free in netlbl_catmap_walk()
+    - x86: Increase exception stack sizes
+    - mwifiex: Run SET_BSS_MODE when changing from P2P to STATION vif-type
+    - mwifiex: Properly initialize private structure on interface type changes
+    - ath10k: high latency fixes for beacon buffer
+    - media: mt9p031: Fix corrupted frame after restarting stream
+    - media: netup_unidvb: handle interrupt properly according to the firmware
+    - media: stm32: Potential NULL pointer dereference in dcmi_irq_thread()
+    - media: uvcvideo: Set capability in s_param
+    - media: uvcvideo: Return -EIO for control errors
+    - media: uvcvideo: Set unique vdev name based in type
+    - media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe()
+    - media: s5p-mfc: Add checking to s5p_mfc_probe().
+    - media: imx: set a media_device bus_info string
+    - media: mceusb: return without resubmitting URB in case of -EPROTO error.
+    - ia64: don't do IA64_CMPXCHG_DEBUG without CONFIG_PRINTK
+    - brcmfmac: Add DMI nvram filename quirk for Cyberbook T116 tablet
+    - media: rcar-csi2: Add checking to rcsi2_start_receiver()
+    - ipmi: Disable some operations during a panic
+    - ACPICA: Avoid evaluating methods too early during system resume
+    - media: ipu3-imgu: imgu_fmt: Handle properly try
+    - media: ipu3-imgu: VIDIOC_QUERYCAP: Fix bus_info
+    - media: usb: dvd-usb: fix uninit-value bug in dibusb_read_eeprom_byte()
+    - net-sysfs: try not to restart the syscall if it will fail eventually
+    - tracefs: Have tracefs directories not set OTH permission bits by default
+    - ath: dfs_pattern_detector: Fix possible null-pointer dereference in
+      channel_detector_create()
+    - iov_iter: Fix iov_iter_get_pages{,_alloc} page fault return value
+    - ACPI: battery: Accept charges over the design capacity as full
+    - leaking_addresses: Always print a trailing newline
+    - memstick: r592: Fix a UAF bug when removing the driver
+    - lib/xz: Avoid overlapping memcpy() with invalid input with in-place
+      decompression
+    - lib/xz: Validate the value before assigning it to an enum variable
+    - workqueue: make sysfs of unbound kworker cpumask more clever
+    - tracing/cfi: Fix cmp_entries_* functions signature mismatch
+    - mwl8k: Fix use-after-free in mwl8k_fw_state_machine()
+    - block: remove inaccurate requeue check
+    - nvmet: fix use-after-free when a port is removed
+    - nvmet-tcp: fix use-after-free when a port is removed
+    - nvme: drop scan_lock and always kick requeue list when removing namespaces
+    - PM: hibernate: Get block device exclusively in swsusp_check()
+    - selftests: kvm: fix mismatched fclose() after popen()
+    - iwlwifi: mvm: disable RX-diversity in powersave
+    - smackfs: use __GFP_NOFAIL for smk_cipso_doi()
+    - ARM: clang: Do not rely on lr register for stacktrace
+    - gre/sit: Don't generate link-local addr if addr_gen_mode is
+      IN6_ADDR_GEN_MODE_NONE
+    - ARM: 9136/1: ARMv7-M uses BE-8, not BE-32
+    - vrf: run conntrack only in context of lower/physdev for locally generated
+      packets
+    - net: annotate data-race in neigh_output()
+    - btrfs: do not take the uuid_mutex in btrfs_rm_device
+    - spi: bcm-qspi: Fix missing clk_disable_unprepare() on error in
+      bcm_qspi_probe()
+    - x86/hyperv: Protect set_hv_tscchange_cb() against getting preempted
+    - parisc: fix warning in flush_tlb_all
+    - task_stack: Fix end_of_stack() for architectures with upwards-growing stack
+    - parisc/unwind: fix unwinder when CONFIG_64BIT is enabled
+    - parisc/kgdb: add kgdb_roundup() to make kgdb work with idle polling
+    - netfilter: conntrack: set on IPS_ASSURED if flows enters internal stream
+      state
+    - selftests/bpf: Fix strobemeta selftest regression
+    - Bluetooth: fix init and cleanup of sco_conn.timeout_work
+    - rcu: Fix existing exp request check in sync_sched_exp_online_cleanup()
+    - drm/v3d: fix wait for TMU write combiner flush
+    - virtio-gpu: fix possible memory allocation failure
+    - net: net_namespace: Fix undefined member in key_remove_domain()
+    - cgroup: Make rebind_subsystems() disable v2 controllers all at once
+    - wilc1000: fix possible memory leak in cfg_scan_result()
+    - Bluetooth: btmtkuart: fix a memleak in mtk_hci_wmt_sync
+    - crypto: caam - disable pkc for non-E SoCs
+    - rxrpc: Fix _usecs_to_jiffies() by using usecs_to_jiffies()
+    - net: dsa: rtl8366rb: Fix off-by-one bug
+    - ath10k: Fix missing frame timestamp for beacon/probe-resp
+    - drm/amdgpu: fix warning for overflow check
+    - media: em28xx: add missing em28xx_close_extension
+    - media: cxd2880-spi: Fix a null pointer dereference on error handling path
+    - media: dvb-usb: fix ununit-value in az6027_rc_query
+    - media: TDA1997x: handle short reads of hdmi info frame.
+    - media: mtk-vpu: Fix a resource leak in the error handling path of
+      'mtk_vpu_probe()'
+    - media: radio-wl1273: Avoid card name truncation
+    - media: si470x: Avoid card name truncation
+    - media: tm6000: Avoid card name truncation
+    - media: cx23885: Fix snd_card_free call on null card pointer
+    - kprobes: Do not use local variable when creating debugfs file
+    - crypto: ecc - fix CRYPTO_DEFAULT_RNG dependency
+    - cpuidle: Fix kobject memory leaks in error paths
+    - media: em28xx: Don't use ops->suspend if it is NULL
+    - ath9k: Fix potential interrupt storm on queue reset
+    - EDAC/amd64: Handle three rank interleaving mode
+    - netfilter: nft_dynset: relax superfluous check on set updates
+    - media: dvb-frontends: mn88443x: Handle errors of clk_prepare_enable()
+    - crypto: qat - detect PFVF collision after ACK
+    - crypto: qat - disregard spurious PFVF interrupts
+    - hwrng: mtk - Force runtime pm ops for sleep ops
+    - b43legacy: fix a lower bounds test
+    - b43: fix a lower bounds test
+    - mmc: sdhci-omap: Fix NULL pointer exception if regulator is not configured
+    - memstick: avoid out-of-range warning
+    - memstick: jmb38x_ms: use appropriate free function in jmb38x_ms_alloc_host()
+    - net, neigh: Fix NTF_EXT_LEARNED in combination with NTF_USE
+    - hwmon: Fix possible memleak in __hwmon_device_register()
+    - hwmon: (pmbus/lm25066) Let compiler determine outer dimension of
+      lm25066_coeff
+    - ath10k: fix max antenna gain unit
+    - drm/msm: uninitialized variable in msm_gem_import()
+    - net: stream: don't purge sk_error_queue in sk_stream_kill_queues()
+    - mmc: mxs-mmc: disable regulator on error and in the remove function
+    - block: ataflop: fix breakage introduced at blk-mq refactoring
+    - platform/x86: thinkpad_acpi: Fix bitwise vs. logical warning
+    - mt76: mt76x02: fix endianness warnings in mt76x02_mac.c
+    - rsi: stop thread firstly in rsi_91x_init() error handling
+    - mwifiex: Send DELBA requests according to spec
+    - phy: micrel: ksz8041nl: do not use power down mode
+    - nvme-rdma: fix error code in nvme_rdma_setup_ctrl
+    - PM: hibernate: fix sparse warnings
+    - clocksource/drivers/timer-ti-dm: Select TIMER_OF
+    - drm/msm: Fix potential NULL dereference in DPU SSPP
+    - smackfs: use netlbl_cfg_cipsov4_del() for deleting cipso_v4_doi
+    - libbpf: Fix BTF data layout checks and allow empty BTF
+    - s390/gmap: don't unconditionally call pte_unmap_unlock() in __gmap_zap()
+    - irq: mips: avoid nested irq_enter()
+    - tcp: don't free a FIN sk_buff in tcp_remove_empty_skb()
+    - samples/kretprobes: Fix return value if register_kretprobe() failed
+    - KVM: s390: Fix handle_sske page fault handling
+    - libertas_tf: Fix possible memory leak in probe and disconnect
+    - libertas: Fix possible memory leak in probe and disconnect
+    - wcn36xx: add proper DMA memory barriers in rx path
+    - drm/amdgpu/gmc6: fix DMA mask from 44 to 40 bits
+    - net: amd-xgbe: Toggle PLL settings during rate change
+    - net: phylink: avoid mvneta warning when setting pause parameters
+    - crypto: pcrypt - Delay write to padata->info
+    - selftests/bpf: Fix fclose/pclose mismatch in test_progs
+    - udp6: allow SO_MARK ctrl msg to affect routing
+    - ibmvnic: don't stop queue in xmit
+    - ibmvnic: Process crqs after enabling interrupts
+    - RDMA/rxe: Fix wrong port_cap_flags
+    - clk: mvebu: ap-cpu-clk: Fix a memory leak in error handling paths
+    - ARM: s3c: irq-s3c24xx: Fix return value check for s3c24xx_init_intc()
+    - arm64: dts: rockchip: Fix GPU register width for RK3328
+    - ARM: dts: qcom: msm8974: Add xo_board reference clock to DSI0 PHY
+    - RDMA/bnxt_re: Fix query SRQ failure
+    - arm64: dts: meson-g12a: Fix the pwm regulator supply properties
+    - ARM: dts: at91: tse850: the emac<->phy interface is rmii
+    - scsi: dc395: Fix error case unwinding
+    - MIPS: loongson64: make CPU_LOONGSON64 depends on MIPS_FP_SUPPORT
+    - JFS: fix memleak in jfs_mount
+    - ALSA: hda: Reduce udelay() at SKL+ position reporting
+    - arm: dts: omap3-gta04a4: accelerometer irq fix
+    - soc/tegra: Fix an error handling path in tegra_powergate_power_up()
+    - memory: fsl_ifc: fix leak of irq and nand_irq in fsl_ifc_ctrl_probe
+    - clk: at91: check pmc node status before registering syscore ops
+    - video: fbdev: chipsfb: use memset_io() instead of memset()
+    - serial: 8250_dw: Drop wrong use of ACPI_PTR()
+    - usb: gadget: hid: fix error code in do_config()
+    - power: supply: rt5033_battery: Change voltage values to µV
+    - scsi: csiostor: Uninitialized data in csio_ln_vnp_read_cbfn()
+    - RDMA/mlx4: Return missed an error if device doesn't support steering
+    - staging: ks7010: select CRYPTO_HASH/CRYPTO_MICHAEL_MIC
+    - ARM: dts: stm32: fix SAI sub nodes register range
+    - ASoC: cs42l42: Correct some register default values
+    - ASoC: cs42l42: Defer probe if request_threaded_irq() returns EPROBE_DEFER
+    - phy: qcom-qusb2: Fix a memory leak on probe
+    - serial: xilinx_uartps: Fix race condition causing stuck TX
+    - HID: u2fzero: clarify error check and length calculations
+    - HID: u2fzero: properly handle timeouts in usb_submit_urb
+    - powerpc/44x/fsp2: add missing of_node_put
+    - mips: cm: Convert to bitfield API to fix out-of-bounds access
+    - power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
+    - apparmor: fix error check
+    - rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined
+    - pnfs/flexfiles: Fix misplaced barrier in nfs4_ff_layout_prepare_ds
+    - drm/plane-helper: fix uninitialized variable reference
+    - PCI: aardvark: Don't spam about PIO Response Status
+    - PCI: aardvark: Fix preserving PCI_EXP_RTCTL_CRSSVE flag on emulated bridge
+    - opp: Fix return in _opp_add_static_v2()
+    - NFS: Fix deadlocks in nfs_scan_commit_list()
+    - fs: orangefs: fix error return code of orangefs_revalidate_lookup()
+    - mtd: spi-nor: hisi-sfc: Remove excessive clk_disable_unprepare()
+    - mtd: core: don't remove debugfs directory if device is in use
+    - dmaengine: at_xdmac: fix AT_XDMAC_CC_PERID() macro
+    - auxdisplay: img-ascii-lcd: Fix lock-up when displaying empty string
+    - auxdisplay: ht16k33: Connect backlight to fbdev
+    - auxdisplay: ht16k33: Fix frame buffer device blanking
+    - soc: fsl: dpaa2-console: free buffer before returning from
+      dpaa2_console_read
+    - netfilter: nfnetlink_queue: fix OOB when mac header was cleared
+    - dmaengine: dmaengine_desc_callback_valid(): Check for `callback_result`
+    - signal/sh: Use force_sig(SIGKILL) instead of do_group_exit(SIGKILL)
+    - m68k: set a default value for MEMORY_RESERVE
+    - watchdog: f71808e_wdt: fix inaccurate report in WDIOC_GETTIMEOUT
+    - ar7: fix kernel builds for compiler test
+    - scsi: qla2xxx: Fix gnl list corruption
+    - scsi: qla2xxx: Turn off target reset during issue_lip
+    - NFSv4: Fix a regression in nfs_set_open_stateid_locked()
+    - i2c: xlr: Fix a resource leak in the error handling path of
+      'xlr_i2c_probe()'
+    - xen-pciback: Fix return in pm_ctrl_init()
+    - net: davinci_emac: Fix interrupt pacing disable
+    - net: vlan: fix a UAF in vlan_dev_real_dev()
+    - ACPI: PMIC: Fix intel_pmic_regs_handler() read accesses
+    - bonding: Fix a use-after-free problem when bond_sysfs_slave_add() failed
+    - mm/zsmalloc.c: close race window between zs_pool_dec_isolated() and
+      zs_unregister_migration()
+    - zram: off by one in read_block_state()
+    - perf bpf: Add missing free to bpf_event__print_bpf_prog_info()
+    - llc: fix out-of-bound array index in llc_sk_dev_hash()
+    - nfc: pn533: Fix double free when pn533_fill_fragment_skbs() fails
+    - arm64: pgtable: make __pte_to_phys/__phys_to_pte_val inline functions
+    - bpf: sockmap, strparser, and tls are reusing qdisc_skb_cb and colliding
+    - net/sched: sch_taprio: fix undefined behavior in ktime_mono_to_any
+    - net: hns3: allow configure ETS bandwidth of all TCs
+    - vsock: prevent unnecessary refcnt inc for nonblocking connect
+    - net/smc: fix sk_refcnt underflow on linkdown and fallback
+    - cxgb4: fix eeprom len when diagnostics not implemented
+    - selftests/net: udpgso_bench_rx: fix port argument
+    - ARM: 9155/1: fix early early_iounmap()
+    - ARM: 9156/1: drop cc-option fallbacks for architecture selection
+    - parisc: Fix set_fixmap() on PA1.x CPUs
+    - irqchip/sifive-plic: Fixup EOI failed when masked
+    - f2fs: should use GFP_NOFS for directory inodes
+    - net, neigh: Enable state migration between NUD_PERMANENT and NTF_USE
+    - 9p/net: fix missing error check in p9_check_errors
+    - ovl: fix deadlock in splice write
+    - powerpc/lib: Add helper to check if offset is within conditional branch
+      range
+    - powerpc/bpf: Validate branch ranges
+    - powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
+    - powerpc/security: Add a helper to query stf_barrier type
+    - powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
+    - mm, oom: pagefault_out_of_memory: don't force global OOM for dying tasks
+    - mm, oom: do not trigger out_of_memory from the #PF
+    - video: backlight: Drop maximum brightness override for brightness zero
+    - s390/cio: check the subchannel validity for dev_busid
+    - s390/tape: fix timer initialization in tape_std_assign()
+    - s390/cio: make ccw_device_dma_* more robust
+    - powerpc/powernv/prd: Unregister OPAL_MSG_PRD2 notifier during module unload
+    - PCI: Add PCI_EXP_DEVCTL_PAYLOAD_* macros
+    - SUNRPC: Partial revert of commit 6f9f17287e78
+    - ath10k: fix invalid dma_addr_t token assignment
+    - selftests/bpf: Fix also no-alu32 strobemeta selftest
+    - Linux 5.4.160
+    - soc/tegra: pmc: Fix imbalanced clock disabling in error code path
+
+  * Focal update: v5.4.159 upstream stable release (LP: #1953071)
+    - Revert "x86/kvm: fix vcpu-id indexed array sizes"
+    - usb: ehci: handshake CMD_RUN instead of STS_HALT
+    - usb: gadget: Mark USB_FSL_QE broken on 64-bit
+    - usb: musb: Balance list entry in musb_gadget_queue
+    - usb-storage: Add compatibility quirk flags for iODD 2531/2541
+    - binder: don't detect sender/target during buffer cleanup
+    - printk/console: Allow to disable console output by using console="" or
+      console=null
+    - isofs: Fix out of bound access for corrupted isofs image
+    - comedi: dt9812: fix DMA buffers on stack
+    - comedi: ni_usb6501: fix NULL-deref in command paths
+    - comedi: vmk80xx: fix transfer-buffer overflows
+    - comedi: vmk80xx: fix bulk-buffer overflow
+    - comedi: vmk80xx: fix bulk and interrupt message timeouts
+    - staging: r8712u: fix control-message timeout
+    - staging: rtl8192u: fix control-message timeouts
+    - media: staging/intel-ipu3: css: Fix wrong size comparison imgu_css_fw_init
+    - rsi: fix control-message timeout
+    - Linux 5.4.159
+
+  * Focal update: v5.4.158 upstream stable release (LP: #1953066)
+    - scsi: core: Put LLD module refcnt after SCSI device is released
+    - vrf: Revert "Reset skb conntrack connection..."
+    - net: ethernet: microchip: lan743x: Fix skb allocation failure
+    - media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
+    - Revert "xhci: Set HCD flag to defer primary roothub registration"
+    - Revert "usb: core: hcd: Add support for deferring roothub registration"
+    - sfc: Fix reading non-legacy supported link modes
+    - ARM: 9120/1: Revert "amba: make use of -1 IRQs warn"
+    - Linux 5.4.158
+
+  * [Ubuntu 20.04] Problem leading IUCV service down (on s390x) (LP: #1913442)
+    - usercopy: mark dma-kmalloc caches as usercopy caches
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 13 Jan 2022 19:00:41 +0100
+
+linux (5.4.0-96.109) focal; urgency=medium
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - [Config]: add i386 to CONFIG_SYSTEM_REVOCATION_KEYS annotation
+
+  * CVE-2022-0185
+    - SAUCE: vfs: Out-of-bounds write of heap buffer in fs_context.c
+    - SAUCE: vfs: test that one given mount param is not larger than PAGE_SIZE
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 12 Jan 2022 12:16:43 -0300
+
+linux (5.4.0-94.106) focal; urgency=medium
+
+  * focal/linux: 5.4.0-94.106 -proposed tracker (LP: #1956628)
+
+  * [Regression] Focal kernel  5.4.0-92.103 fails to boot when Secure Encrypted
+    Virtualization(SEV) is enabled (LP: #1956575)
+    - x86/ioremap: Map EFI-reserved memory as encrypted for SEV
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Thu, 06 Jan 2022 16:56:46 -0500
+
+linux (5.4.0-92.103) focal; urgency=medium
+
+  * focal/linux: 5.4.0-92.103 -proposed tracker (LP: #1952316)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.29)
+
+  * CVE-2021-4002
+    - tlb: mmu_gather: add tlb_flush_*_range APIs
+    - hugetlbfs: flush TLBs correctly after huge_pmd_unshare
+
+  * Re-enable DEBUG_INFO_BTF where it was disabled (LP: #1945632)
+    - [Config] Enable CONFIG_DEBUG_INFO_BTF on all arches
+
+  * Focal linux-azure: Vm crash on Dv5/Ev5 (LP: #1950462)
+    - KVM: VMX: eVMCS: make evmcs_sanitize_exec_ctrls() work again
+    - jump_label: Fix usage in module __init
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - Revert "UBUNTU: SAUCE: (lockdown) Make get_cert_list() not complain about
+      cert lists that aren't present."
+    - integrity: Move import of MokListRT certs to a separate routine
+    - integrity: Load certs from the EFI MOK config table
+    - certs: Add ability to preload revocation certs
+    - integrity: Load mokx variables into the blacklist keyring
+    - certs: add 'x509_revocation_list' to gitignore
+    - SAUCE: Dump stack when X.509 certificates cannot be loaded
+    - [Packaging] build canonical-revoked-certs.pem from branch/arch certs
+    - [Packaging] Revoke 2012 UEFI signing certificate as built-in
+    - [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys
+
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679)
+    - efi: Support for MOK variable config table
+    - efi: mokvar-table: fix some issues in new code
+    - efi: mokvar: add missing include of asm/early_ioremap.h
+    - efi/mokvar: Reserve the table only if it is in boot services data
+    - SAUCE: integrity: add informational messages when revoking certs
+
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679) // CVE-2020-26541 when certificates are revoked via
+    MokListXRT.
+    - SAUCE: integrity: Load mokx certs from the EFI MOK config table
+
+  * Focal update: v5.4.157 upstream stable release (LP: #1951883)
+    - ARM: 9133/1: mm: proc-macros: ensure *_tlb_fns are 4B aligned
+    - ARM: 9134/1: remove duplicate memcpy() definition
+    - ARM: 9139/1: kprobes: fix arch_init_kprobes() prototype
+    - ARM: 9141/1: only warn about XIP address when not compile testing
+    - ipv6: use siphash in rt6_exception_hash()
+    - ipv4: use siphash instead of Jenkins in fnhe_hashfun()
+    - usbnet: sanity check for maxpacket
+    - usbnet: fix error return code in usbnet_probe()
+    - Revert "pinctrl: bcm: ns: support updated DT binding as syscon subnode"
+    - ata: sata_mv: Fix the error handling of mv_chip_id()
+    - nfc: port100: fix using -ERRNO as command type mask
+    - net/tls: Fix flipped sign in tls_err_abort() calls
+    - mmc: vub300: fix control-message timeouts
+    - mmc: cqhci: clear HALT state after CQE enable
+    - mmc: dw_mmc: exynos: fix the finding clock sample value
+    - mmc: sdhci: Map more voltage level to SDHCI_POWER_330
+    - mmc: sdhci-esdhc-imx: clear the buffer_read_ready to reset standard tuning
+      circuit
+    - cfg80211: scan: fix RCU in cfg80211_add_nontrans_list()
+    - net: lan78xx: fix division by zero in send path
+    - tcp_bpf: Fix one concurrency problem in the tcp_bpf_send_verdict function
+    - IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt fields
+    - IB/hfi1: Fix abba locking issue with sc_disable()
+    - nvmet-tcp: fix data digest pointer calculation
+    - nvme-tcp: fix data digest pointer calculation
+    - RDMA/mlx5: Set user priority for DCT
+    - arm64: dts: allwinner: h5: NanoPI Neo 2: Fix ethernet node
+    - regmap: Fix possible double-free in regcache_rbtree_exit()
+    - net: batman-adv: fix error handling
+    - net: Prevent infinite while loop in skb_tx_hash()
+    - RDMA/sa_query: Use strscpy_pad instead of memcpy to copy a string
+    - nios2: Make NIOS2_DTB_SOURCE_BOOL depend on !COMPILE_TEST
+    - net: ethernet: microchip: lan743x: Fix driver crash when lan743x_pm_resume
+      fails
+    - net: ethernet: microchip: lan743x: Fix dma allocation failure by using
+      dma_set_mask_and_coherent
+    - net: nxp: lpc_eth.c: avoid hang when bringing interface down
+    - net/tls: Fix flipped sign in async_wait.err assignment
+    - phy: phy_ethtool_ksettings_get: Lock the phy for consistency
+    - phy: phy_start_aneg: Add an unlocked version
+    - sctp: use init_tag from inithdr for ABORT 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
+    - net: use netif_is_bridge_port() to check for IFF_BRIDGE_PORT
+    - cfg80211: correct bridge/4addr mode check
+    - KVM: s390: clear kicked_mask before sleeping again
+    - KVM: s390: preserve deliverable_mask in __airqs_kick_single_vcpu
+    - perf script: Check session->header.env.arch before using it
+    - Linux 5.4.157
+
+  * keyboard not working on Medion notebook s17 series (LP: #1950536)
+    - ACPI: resources: Add one more Medion model in IRQ override quirk
+
+  * creat09 from ubuntu_ltp_syscalls and cve-2018-13405 from ubuntu_ltp/cve
+    failed with XFS (LP: #1950239)
+    - xfs: ensure that the inode uid/gid match values match the icdinode ones
+    - xfs: merge the projid fields in struct xfs_icdinode
+    - xfs: remove the icdinode di_uid/di_gid members
+    - xfs: fix up non-directory creation in SGID directories
+
+  * reuseport_bpf_numa in net from ubuntu_kernel_selftests fails on ppc64le
+    (LP: #1867570)
+    - selftests/net: Fix reuseport_bpf_numa by skipping unavailable nodes
+
+  * Focal update: v5.4.156 upstream stable release (LP: #1951295)
+    - parisc: math-emu: Fix fall-through warnings
+    - net: switchdev: do not propagate bridge updates across bridges
+    - tee: optee: Fix missing devices unregister during optee_remove
+    - ARM: dts: at91: sama5d2_som1_ek: disable ISC node by default
+    - xtensa: xtfpga: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: xtfpga: Try software restart before simulating CPU reset
+    - NFSD: Keep existing listeners on portlist error
+    - dma-debug: fix sg checks in debug_dma_map_sg()
+    - ASoC: wm8960: Fix clock configuration on slave mode
+    - netfilter: ipvs: make global sysctl readonly in non-init netns
+    - lan78xx: select CRC32
+    - net: dsa: lantiq_gswip: fix register definition
+    - NIOS2: irqflags: rename a redefined register name
+    - net: hns3: reset DWRR of unused tc to zero
+    - net: hns3: add limit ets dwrr bandwidth cannot be 0
+    - net: hns3: disable sriov before unload hclge layer
+    - net: stmmac: Fix E2E delay mechanism
+    - net: enetc: fix ethtool counter name for PM0_TERR
+    - can: rcar_can: fix suspend/resume
+    - can: peak_usb: pcan_usb_fd_decode_status(): fix back to ERROR_ACTIVE state
+      notification
+    - can: peak_pci: peak_pci_remove(): fix UAF
+    - can: j1939: j1939_tp_rxtimer(): fix errant alert in j1939_tp_rxtimer
+    - can: j1939: j1939_netdev_start(): fix UAF for rx_kref of j1939_priv
+    - can: j1939: j1939_xtp_rx_dat_one(): cancel session if receive TP.DT with
+      error length
+    - can: j1939: j1939_xtp_rx_rts_session_new(): abort TP less than 9 bytes
+    - ceph: fix handling of "meta" errors
+    - ocfs2: fix data corruption after conversion from inline format
+    - ocfs2: mount fails with buffer overflow in strlen
+    - elfcore: correct reference to CONFIG_UML
+    - ALSA: usb-audio: Provide quirk for Sennheiser GSP670 Headset
+    - ALSA: hda/realtek: Add quirk for Clevo PC50HS
+    - ASoC: DAPM: Fix missing kctl change notifications
+    - audit: fix possible null-pointer dereference in audit_filter_rules
+    - powerpc64/idle: Fix SP offsets when saving GPRs
+    - KVM: PPC: Book3S HV: Fix stack handling in idle_kvm_start_guest()
+    - KVM: PPC: Book3S HV: Make idle_kvm_start_guest() return 0 if it went to
+      guest
+    - powerpc/idle: Don't corrupt back chain when going idle
+    - mm, slub: fix mismatch between reconstructed freelist depth and cnt
+    - mm, slub: fix potential memoryleak in kmem_cache_open()
+    - nfc: nci: fix the UAF of rf_conn_info object
+    - isdn: cpai: check ctr->cnr to avoid array index out of bound
+    - netfilter: Kconfig: use 'default y' instead of 'm' for bool config option
+    - selftests: netfilter: remove stray bash debug line
+    - gcc-plugins/structleak: add makefile var for disabling structleak
+    - btrfs: deal with errors when checking if a dir entry exists during log
+      replay
+    - net: stmmac: add support for dwmac 3.40a
+    - ARM: dts: spear3xx: Fix gmac node
+    - isdn: mISDN: Fix sleeping function called from invalid context
+    - platform/x86: intel_scu_ipc: Update timeout value in comment
+    - ALSA: hda: avoid write to STATESTS if controller is in reset
+    - Input: snvs_pwrkey - add clk handling
+    - scsi: core: Fix shost->cmd_per_lun calculation in scsi_add_host_with_dma()
+    - tracing: Have all levels of checks prevent recursion
+    - ARM: 9122/1: select HAVE_FUTEX_CMPXCHG
+    - pinctrl: stm32: use valid pin identifier in stm32_pinctrl_resume()
+    - Linux 5.4.156
+
+  * ubuntu_ltp / finit_module02 fails on v4.15 and other kernels
+    (LP: #1950644) // Focal update: v5.4.156 upstream stable release
+    (LP: #1951295)
+    - vfs: check fd has read access in kernel_read_file_from_fd()
+
+  * Focal update: v5.4.155 upstream stable release (LP: #1951291)
+    - ovl: simplify file splice
+    - ALSA: usb-audio: Add quirk for VF0770
+    - ALSA: seq: Fix a potential UAF by wrong private_free call order
+    - ALSA: hda/realtek: Complete partial device name to avoid ambiguity
+    - ALSA: hda/realtek: Add quirk for Clevo X170KM-G
+    - ALSA: hda/realtek - ALC236 headset MIC recording issue
+    - ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
+    - nds32/ftrace: Fix Error: invalid operands (*UND* and *UND* sections) for `^'
+    - s390: fix strrchr() implementation
+    - csky: don't let sigreturn play with priveleged bits of status register
+    - csky: Fixup regs.sr broken in ptrace
+    - btrfs: unlock newly allocated extent buffer after error
+    - btrfs: deal with errors when replaying dir entry during log replay
+    - btrfs: deal with errors when adding inode reference during log replay
+    - btrfs: check for error when looking up inode during dir entry replay
+    - watchdog: orion: use 0 for unset heartbeat
+    - x86/resctrl: Free the ctrlval arrays when domain_setup_mon_state() fails
+    - mei: me: add Ice Lake-N device id.
+    - xhci: guard accesses to ep_state in xhci_endpoint_reset()
+    - xhci: Fix command ring pointer corruption while aborting a command
+    - xhci: Enable trust tx length quirk for Fresco FL11 USB controller
+    - cb710: avoid NULL pointer subtraction
+    - efi/cper: use stack buffer for error record decoding
+    - efi: Change down_interruptible() in virt_efi_reset_system() to
+      down_trylock()
+    - usb: musb: dsps: Fix the probe error path
+    - Input: xpad - add support for another USB ID of Nacon GC-100
+    - USB: serial: qcserial: add EM9191 QDL support
+    - USB: serial: option: add Quectel EC200S-CN module support
+    - USB: serial: option: add Telit LE910Cx composition 0x1204
+    - USB: serial: option: add prod. id for Quectel EG91
+    - EDAC/armada-xp: Fix output of uncorrectable error counter
+    - nvmem: Fix shift-out-of-bound (UBSAN) with byte size cells
+    - x86/Kconfig: Do not enable AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT automatically
+    - powerpc/xive: Discard disabled interrupts in get_irqchip_state()
+    - iio: adc: aspeed: set driver data when adc probe.
+    - iio: adc128s052: Fix the error handling path of 'adc128_probe()'
+    - iio: mtk-auxadc: fix case IIO_CHAN_INFO_PROCESSED
+    - iio: light: opt3001: Fixed timeout error when 0 lux
+    - iio: ssp_sensors: add more range checking in ssp_parse_dataframe()
+    - iio: ssp_sensors: fix error code in ssp_print_mcu_debug()
+    - iio: dac: ti-dac5571: fix an error code in probe()
+    - sctp: account stream padding length for reconf chunk
+    - gpio: pca953x: Improve bias setting
+    - net: arc: select CRC32
+    - net: korina: select CRC32
+    - net/mlx5e: Mutually exclude RX-FCS and RX-port-timestamp
+    - net: stmmac: fix get_hw_feature() on old hardware
+    - net: encx24j600: check error in devm_regmap_init_encx24j600
+    - ethernet: s2io: fix setting mac address during resume
+    - nfc: fix error handling of nfc_proto_register()
+    - NFC: digital: fix possible memory leak in digital_tg_listen_mdaa()
+    - NFC: digital: fix possible memory leak in digital_in_send_sdd_req()
+    - pata_legacy: fix a couple uninitialized variable bugs
+    - ata: ahci_platform: fix null-ptr-deref in ahci_platform_enable_regulators()
+    - mlxsw: thermal: Fix out-of-bounds memory accesses
+    - platform/mellanox: mlxreg-io: Fix argument base in kstrtou32() call
+    - drm/panel: olimex-lcd-olinuxino: select CRC32
+    - drm/msm: Fix null pointer dereference on pointer edp
+    - drm/msm/dsi: Fix an error code in msm_dsi_modeset_init()
+    - drm/msm/dsi: fix off by one in dsi_bus_clk_enable error handling
+    - acpi/arm64: fix next_platform_timer() section mismatch error
+    - mqprio: Correct stats in mqprio_dump_class_stats().
+    - qed: Fix missing error code in qed_slowpath_start()
+    - r8152: select CRC32 and CRYPTO/CRYPTO_HASH/CRYPTO_SHA256
+    - ionic: don't remove netdev->dev_addr when syncing uc list
+    - Linux 5.4.155
+
+  * [UBUNTU 20.04] kernel:  unable to read partitions on virtio-block dasd (kvm)
+    (LP: #1950144) // Focal update: v5.4.155 upstream stable release
+    (LP: #1951291)
+    - virtio: write back F_VERSION_1 before validate
+
+  * Focal update: v5.4.154 upstream stable release (LP: #1951288)
+    - net: phy: bcm7xxx: Fixed indirect MMD operations
+    - ext4: correct the error path of ext4_write_inline_data_end()
+    - HID: apple: Fix logical maximum and usage maximum of Magic Keyboard JIS
+    - netfilter: ip6_tables: zero-initialize fragment offset
+    - HID: wacom: Add new Intuos BT (CTL-4100WL/CTL-6100WL) device IDs
+    - netfilter: nf_nat_masquerade: make async masq_inet6_event handling generic
+    - netfilter: nf_nat_masquerade: defer conntrack walk to work queue
+    - mac80211: Drop frames from invalid MAC address in ad-hoc mode
+    - m68k: Handle arrivals of multiple signals correctly
+    - net: prevent user from passing illegal stab size
+    - mac80211: check return value of rhashtable_init
+    - net: sun: SUNVNET_COMMON should depend on INET
+    - drm/amdgpu: fix gart.bo pin_count leak
+    - scsi: ses: Fix unsigned comparison with less than zero
+    - scsi: virtio_scsi: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - sched: Always inline is_percpu_thread()
+    - Linux 5.4.154
+
+  * Focal update: v5.4.153 upstream stable release (LP: #1950014)
+    - Partially revert "usb: Kconfig: using select for USB_COMMON dependency"
+    - USB: cdc-acm: fix racy tty buffer accesses
+    - USB: cdc-acm: fix break reporting
+    - usb: typec: tcpm: handle SRC_STARTUP state if cc changes
+    - xen/privcmd: fix error handling in mmap-resource processing
+    - mmc: meson-gx: do not use memcpy_to/fromio for dram-access-quirk
+    - ovl: fix missing negative dentry check in ovl_rename()
+    - nfsd: fix error handling of register_pernet_subsys() in init_nfsd()
+    - nfsd4: Handle the NFSv4 READDIR 'dircount' hint being zero
+    - xen/balloon: fix cancelled balloon action
+    - ARM: dts: omap3430-sdp: Fix NAND device node
+    - ARM: dts: qcom: apq8064: use compatible which contains chipid
+    - MIPS: BPF: Restore MIPS32 cBPF JIT
+    - bpf, mips: Validate conditional branch offsets
+    - soc: qcom: socinfo: Fixed argument passed to platform_set_data()
+    - ARM: dts: qcom: apq8064: Use 27MHz PXO clock as DSI PLL reference
+    - soc: qcom: mdt_loader: Drop PT_LOAD check on hash segment
+    - ARM: dts: imx: Add missing pinctrl-names for panel on M53Menlo
+    - ARM: dts: imx: Fix USB host power regulator polarity on M53Menlo
+    - arm64: dts: qcom: pm8150: use qcom,pm8998-pon binding
+    - xtensa: move XCHAL_KIO_* definitions to kmem_layout.h
+    - xtensa: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: call irqchip_init only when CONFIG_USE_OF is selected
+    - bpf, arm: Fix register clobbering in div/mod implementation
+    - bpf: Fix integer overflow in prealloc_elems_and_freelist()
+    - phy: mdio: fix memory leak
+    - net_sched: fix NULL deref in fifo_set_limit()
+    - powerpc/fsl/dts: Fix phy-connection-type for fm1mac3
+    - ptp_pch: Load module automatically if ID matches
+    - arm64: dts: freescale: Fix SP805 clock-names
+    - arm64: dts: ls1028a: add missing CAN nodes
+    - ARM: imx6: disable the GIC CPU interface before calling stby-poweroff
+      sequence
+    - net: bridge: use nla_total_size_64bit() in br_get_linkxstats_size()
+    - net/sched: sch_taprio: properly cancel timer from taprio_destroy()
+    - net: sfp: Fix typo in state machine debug string
+    - netlink: annotate data races around nlk->bound
+    - bus: ti-sysc: Use CLKDM_NOAUTO for dra7 dcan1 for errata i893
+    - video: fbdev: gbefb: Only instantiate device when built for IP32
+    - drm/nouveau/debugfs: fix file release memory leak
+    - gve: Correct available tx qpl check
+    - rtnetlink: fix if_nlmsg_stats_size() under estimation
+    - gve: fix gve_get_stats()
+    - i40e: fix endless loop under rtnl
+    - i40e: Fix freeing of uninitialized misc IRQ vector
+    - net: prefer socket bound to interface when not in VRF
+    - i2c: acpi: fix resource leak in reconfiguration device addition
+    - bpf, s390: Fix potential memory leak about jit_data
+    - RISC-V: Include clone3() on rv32
+    - x86/platform/olpc: Correct ifdef symbol to intended CONFIG_OLPC_XO15_SCI
+    - x86/hpet: Use another crystalball to evaluate HPET usability
+    - x86/Kconfig: Correct reference to MWINCHIP3D
+    - Linux 5.4.153
+
+  * Focal update: v5.4.152 upstream stable release (LP: #1950009)
+    - net: mdio: introduce a shutdown method to mdio device drivers
+    - xen-netback: correct success/error reporting for the SKB-with-fraglist case
+    - sparc64: fix pci_iounmap() when CONFIG_PCI is not set
+    - ext2: fix sleeping in atomic bugs on error
+    - scsi: sd: Free scsi_disk device via put_device()
+    - usb: testusb: Fix for showing the connection speed
+    - usb: dwc2: check return value after calling platform_get_resource()
+    - selftests: be sure to make khdr before other targets
+    - selftests:kvm: fix get_warnings_count() ignoring fscanf() return warn
+    - scsi: ses: Retry failed Send/Receive Diagnostic commands
+    - tools/vm/page-types: remove dependency on opt_file for idle page tracking
+    - KVM: do not shrink halt_poll_ns below grow_start
+    - kvm: x86: Add AMD PMU MSRs to msrs_to_save_all[]
+    - perf/x86: Reset destroy callback on event init failure
+    - silence nfscache allocation warnings with kvzalloc
+    - libata: Add ATA_HORKAGE_NO_NCQ_ON_ATI for Samsung 860 and 870 SSD.
+    - Linux 5.4.152
+
+  * linux-aws: Fix backport of RDMA/efa: Expose maximum  TX doorbell batch
+    (LP: #1949882)
+    - SAUCE: aws: Fix backport of RDMA/efa: Expose maximum TX doorbell batch
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 26 Nov 2021 15:42:03 +0100
+
+linux (5.4.0-91.102) focal; urgency=medium
+
+  * focal/linux: 5.4.0-91.102 -proposed tracker (LP: #1949840)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.08)
+
+  * KVM emulation failure when booting into  VM crash kernel with multiple CPUs
+    (LP: #1948862)
+    - KVM: x86: Properly reset MMU context at vCPU RESET/INIT
+
+  * aufs: kernel bug with apparmor and fuseblk (LP: #1948470)
+    - SAUCE: aufs: bugfix, stop omitting path->mnt
+
+  * ebpf:  bpf_redirect fails with ip6 gre interfaces (LP: #1947164)
+    - net: handle ARPHRD_IP6GRE in dev_is_mac_header_xmit()
+
+  * require CAP_NET_ADMIN to attach N_HCI ldisc (LP: #1949516)
+    - Bluetooth: hci_ldisc: require CAP_NET_ADMIN to attach N_HCI ldisc
+
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161)
+    - ocfs2: fix remounting needed after setfacl command
+
+  * ppc64 BPF JIT mod by 1 will not return 0 (LP: #1948351)
+    - powerpc/bpf: Fix BPF_MOD when imm == 1
+
+  * Drop "UBUNTU: SAUCE: cachefiles: Page leaking in
+    cachefiles_read_backing_file while vmscan is active" (LP: #1947709)
+    - Revert "UBUNTU: SAUCE: cachefiles: Page leaking in
+      cachefiles_read_backing_file while vmscan is active"
+
+  * Reassign I/O Path of ConnectX-5 Port 1 before Port 2 causes NULL dereference
+    (LP: #1943464)
+    - s390/pci: fix leak of PCI device structure
+    - s390/pci: fix use after free of zpci_dev
+    - s390/pci: fix zpci_zdev_put() on reserve
+
+  * [SRU][F] USB: serial: pl2303: add support for PL2303HXN (LP: #1948377)
+    - USB: serial: pl2303: add support for PL2303HXN
+    - USB: serial: pl2303: fix line-speed handling on newer chips
+
+  * Focal update: v5.4.151 upstream stable release (LP: #1947888)
+    - tty: Fix out-of-bound vmalloc access in imageblit
+    - cpufreq: schedutil: Use kobject release() method to free sugov_tunables
+    - cpufreq: schedutil: Destroy mutex before kobject_put() frees the memory
+    - usb: cdns3: fix race condition before setting doorbell
+    - fs-verity: fix signed integer overflow with i_size near S64_MAX
+    - hwmon: (w83793) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83792d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83791d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - scsi: ufs: Fix illegal offset in UPIU event trace
+    - mac80211: fix use-after-free in CCMP/GCMP RX
+    - x86/kvmclock: Move this_cpu_pvti into kvmclock.h
+    - drm/amd/display: Pass PCI deviceid into DC
+    - ipvs: check that ip_vs_conn_tab_bits is between 8 and 20
+    - hwmon: (mlxreg-fan) Return non-zero value when fan current state is enforced
+      from sysfs
+    - mac80211: Fix ieee80211_amsdu_aggregate frag_tail bug
+    - mac80211: limit injected vht mcs/nss in ieee80211_parse_tx_radiotap
+    - mac80211: mesh: fix potentially unaligned access
+    - mac80211-hwsim: fix late beacon hrtimer handling
+    - sctp: break out if skb_header_pointer returns NULL in sctp_rcv_ootb
+    - hwmon: (tmp421) report /PVLD condition as fault
+    - hwmon: (tmp421) fix rounding for negative values
+    - net: ipv4: Fix rtnexthop len when RTA_FLOW is present
+    - e100: fix length calculation in e100_get_regs_len
+    - e100: fix buffer overrun in e100_get_regs
+    - selftests, bpf: test_lwt_ip_encap: Really disable rp_filter
+    - scsi: csiostor: Add module softdep on cxgb4
+    - net: hns3: do not allow call hns3_nic_net_open repeatedly
+    - net: sched: flower: protect fl_walk() with rcu
+    - af_unix: fix races in sk_peer_pid and sk_peer_cred accesses
+    - perf/x86/intel: Update event constraints for ICX
+    - elf: don't use MAP_FIXED_NOREPLACE for elf interpreter mappings
+    - debugfs: debugfs_create_file_size(): use IS_ERR to check for error
+    - ipack: ipoctal: fix stack information leak
+    - ipack: ipoctal: fix tty registration race
+    - ipack: ipoctal: fix tty-registration error handling
+    - ipack: ipoctal: fix missing allocation-failure check
+    - ipack: ipoctal: fix module reference leak
+    - ext4: fix loff_t overflow in ext4_max_bitmap_size()
+    - ext4: fix reserved space counter leakage
+    - ext4: fix potential infinite loop in ext4_dx_readdir()
+    - HID: u2fzero: ignore incomplete packets without data
+    - net: udp: annotate data race around udp_sk(sk)->corkflag
+    - net: stmmac: don't attach interface until resume finishes
+    - PCI: Fix pci_host_bridge struct device release/free handling
+    - libnvdimm/pmem: Fix crash triggered when I/O in-flight during unbind
+    - hso: fix bailout in error case of probe
+    - usb: hso: fix error handling code of hso_create_net_device
+    - usb: hso: remove the bailout parameter
+    - crypto: ccp - fix resource leaks in ccp_run_aes_gcm_cmd()
+    - HID: betop: fix slab-out-of-bounds Write in betop_probe
+    - netfilter: ipset: Fix oversized kvmalloc() calls
+    - HID: usbhid: free raw_report buffers in usbhid_stop
+    - Linux 5.4.151
+
+  * Focal update: v5.4.150 upstream stable release (LP: #1947886)
+    - usb: gadget: r8a66597: fix a loop in set_feature()
+    - usb: dwc2: gadget: Fix ISOC flow for BDMA and Slave
+    - usb: dwc2: gadget: Fix ISOC transfer complete handling for DDMA
+    - usb: musb: tusb6010: uninitialized data in tusb_fifo_write_unaligned()
+    - cifs: fix incorrect check for null pointer in header_assemble
+    - xen/x86: fix PV trap handling on secondary processors
+    - usb-storage: Add quirk for ScanLogic SL11R-IDE older than 2.6c
+    - USB: serial: cp210x: add ID for GW Instek GDM-834x Digital Multimeter
+    - USB: cdc-acm: fix minor-number release
+    - binder: make sure fd closes complete
+    - staging: greybus: uart: fix tty use after free
+    - Re-enable UAS for LaCie Rugged USB3-FW with fk quirk
+    - USB: serial: mos7840: remove duplicated 0xac24 device ID
+    - USB: serial: option: add Telit LN920 compositions
+    - USB: serial: option: remove duplicate USB device ID
+    - USB: serial: option: add device id for Foxconn T99W265
+    - mcb: fix error handling in mcb_alloc_bus()
+    - erofs: fix up erofs_lookup tracepoint
+    - btrfs: prevent __btrfs_dump_space_info() to underflow its free space
+    - serial: mvebu-uart: fix driver's tx_empty callback
+    - net: hso: fix muxed tty registration
+    - afs: Fix incorrect triggering of sillyrename on 3rd-party invalidation
+    - platform/x86/intel: punit_ipc: Drop wrong use of ACPI_PTR()
+    - enetc: Fix illegal access when reading affinity_hint
+    - bnxt_en: Fix TX timeout when TX ring size is set to the smallest
+    - net/smc: add missing error check in smc_clc_prfx_set()
+    - gpio: uniphier: Fix void functions to remove return value
+    - qed: rdma - don't wait for resources under hw error recovery flow
+    - net/mlx4_en: Don't allow aRFS for encapsulated packets
+    - scsi: iscsi: Adjust iface sysfs attr detection
+    - tty: synclink_gt, drop unneeded forward declarations
+    - tty: synclink_gt: rename a conflicting function name
+    - fpga: machxo2-spi: Return an error on failure
+    - fpga: machxo2-spi: Fix missing error code in machxo2_write_complete()
+    - thermal/core: Potential buffer overflow in thermal_build_list_of_policies()
+    - cifs: fix a sign extension bug
+    - scsi: qla2xxx: Restore initiator in dual mode
+    - scsi: lpfc: Use correct scnprintf() limit
+    - irqchip/goldfish-pic: Select GENERIC_IRQ_CHIP to fix build
+    - irqchip/gic-v3-its: Fix potential VPE leak on error
+    - md: fix a lock order reversal in md_alloc
+    - blktrace: Fix uaf in blk_trace access after removing by sysfs
+    - net: macb: fix use after free on rmmod
+    - net: stmmac: allow CSR clock of 300MHz
+    - m68k: Double cast io functions to unsigned long
+    - ipv6: delay fib6_sernum increase in fib6_add
+    - bpf: Add oversize check before call kvcalloc()
+    - xen/balloon: use a kernel thread instead a workqueue
+    - nvme-multipath: fix ANA state updates when a namespace is not present
+    - sparc32: page align size in arch_dma_alloc
+    - blk-cgroup: fix UAF by grabbing blkcg lock before destroying blkg pd
+    - compiler.h: Introduce absolute_pointer macro
+    - net: i825xx: Use absolute_pointer for memcpy from fixed memory location
+    - sparc: avoid stringop-overread errors
+    - qnx4: avoid stringop-overread errors
+    - parisc: Use absolute_pointer() to define PAGE0
+    - arm64: Mark __stack_chk_guard as __ro_after_init
+    - alpha: Declare virt_to_phys and virt_to_bus parameter as pointer to volatile
+    - net: 6pack: Fix tx timeout and slot time
+    - spi: Fix tegra20 build with CONFIG_PM=n
+    - EDAC/synopsys: Fix wrong value type assignment for edac_mode
+    - thermal/drivers/int340x: Do not set a wrong tcc offset on resume
+    - arm64: dts: marvell: armada-37xx: Extend PCIe MEM space
+    - xen/balloon: fix balloon kthread freezing
+    - qnx4: work around gcc false positive warning bug
+    - Linux 5.4.150
+
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161) // Focal update:
+    v5.4.150 upstream stable release (LP: #1947886)
+    - ocfs2: drop acl cache for directories too
+
+  * Focal update: v5.4.149 upstream stable release (LP: #1947885)
+    - PCI: pci-bridge-emul: Fix big-endian support
+    - PCI: aardvark: Indicate error in 'val' when config read fails
+    - PCI: pci-bridge-emul: Add PCIe Root Capabilities Register
+    - PCI: aardvark: Fix reporting CRS value
+    - PCI/ACPI: Add Ampere Altra SOC MCFG quirk
+    - KVM: remember position in kvm->vcpus array
+    - console: consume APC, DM, DCS
+    - s390/pci_mmio: fully validate the VMA before calling follow_pte()
+    - ARM: Qualify enabling of swiotlb_init()
+    - apparmor: remove duplicate macro list_entry_is_head()
+    - ARM: 9077/1: PLT: Move struct plt_entries definition to header
+    - ARM: 9078/1: Add warn suppress parameter to arm_gen_branch_link()
+    - ARM: 9079/1: ftrace: Add MODULE_PLTS support
+    - ARM: 9098/1: ftrace: MODULE_PLT: Fix build problem without DYNAMIC_FTRACE
+    - sctp: validate chunk size in __rcv_asconf_lookup
+    - sctp: add param size validation for SCTP_PARAM_SET_PRIMARY
+    - staging: rtl8192u: Fix bitwise vs logical operator in
+      TranslateRxSignalStuff819xUsb()
+    - um: virtio_uml: fix memory leak on init failures
+    - dmaengine: acpi: Avoid comparison GSI with Linux vIRQ
+    - thermal/drivers/exynos: Fix an error code in exynos_tmu_probe()
+    - 9p/trans_virtio: Remove sysfs file on probe failure
+    - prctl: allow to setup brk for et_dyn executables
+    - nilfs2: use refcount_dec_and_lock() to fix potential UAF
+    - profiling: fix shift-out-of-bounds bugs
+    - pwm: lpc32xx: Don't modify HW state in .probe() after the PWM chip was
+      registered
+    - phy: avoid unnecessary link-up delay in polling mode
+    - net: stmmac: reset Tx desc base address before restarting Tx
+    - Kconfig.debug: drop selecting non-existing HARDLOCKUP_DETECTOR_ARCH
+    - thermal/core: Fix thermal_cooling_device_register() prototype
+    - drivers: base: cacheinfo: Get rid of DEFINE_SMP_CALL_CACHE_FUNCTION()
+    - parisc: Move pci_dev_is_behind_card_dino to where it is used
+    - dmaengine: sprd: Add missing MODULE_DEVICE_TABLE
+    - dmaengine: ioat: depends on !UML
+    - dmaengine: xilinx_dma: Set DMA mask for coherent APIs
+    - ceph: request Fw caps before updating the mtime in ceph_write_iter
+    - ceph: lockdep annotations for try_nonblocking_invalidate
+    - btrfs: fix lockdep warning while mounting sprout fs
+    - nilfs2: fix memory leak in nilfs_sysfs_create_device_group
+    - nilfs2: fix NULL pointer in nilfs_##name##_attr_release
+    - nilfs2: fix memory leak in nilfs_sysfs_create_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_create_snapshot_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_snapshot_group
+    - pwm: img: Don't modify HW state in .remove() callback
+    - pwm: rockchip: Don't modify HW state in .remove() callback
+    - pwm: stm32-lp: Don't modify HW state in .remove() callback
+    - blk-throttle: fix UAF by deleteing timer in blk_throtl_exit()
+    - rtc: rx8010: select REGMAP_I2C
+    - drm/nouveau/nvkm: Replace -ENOSYS with -ENODEV
+    - Linux 5.4.149
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 05 Nov 2021 17:02:56 +0100
+
+linux (5.4.0-90.101) focal; urgency=medium
+
+  * focal/linux: 5.4.0-90.101 -proposed tracker (LP: #1947260)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.10.18)
+
+  * Add final-checks to check certificates (LP: #1947174)
+    - [Packaging] Add system trusted and revocation keys final check
+
+  * No sound on Lenovo laptop models Legion 15IMHG05, Yoga 7 14ITL5, and 13s
+    Gen2 (LP: #1939052)
+    - ALSA: hda/realtek: Quirks to enable speaker output for Lenovo Legion 7i
+      15IMHG05, Yoga 7i 14ITL5/15ITL5, and 13s Gen2 laptops.
+    - ALSA: hda/realtek: Fix for quirk to enable speaker output on the Lenovo 13s
+      Gen2
+
+  * CVE-2020-36385
+    - 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
+
+  * Focal update: v5.4.148 upstream stable release (LP: #1946802)
+    - rtc: tps65910: Correct driver module alias
+    - btrfs: wake up async_delalloc_pages waiters after submit
+    - btrfs: reset replace target device to allocation state on close
+    - blk-zoned: allow zone management send operations without CAP_SYS_ADMIN
+    - blk-zoned: allow BLKREPORTZONE without CAP_SYS_ADMIN
+    - PCI/MSI: Skip masking MSI-X on Xen PV
+    - powerpc/perf/hv-gpci: Fix counter value parsing
+    - xen: fix setting of max_pfn in shared_info
+    - include/linux/list.h: add a macro to test if entry is pointing to the head
+    - 9p/xen: Fix end of loop tests for list_for_each_entry
+    - tools/thermal/tmon: Add cross compiling support
+    - pinctrl: stmfx: Fix hazardous u8[] to unsigned long cast
+    - pinctrl: ingenic: Fix incorrect pull up/down info
+    - soc: qcom: aoss: Fix the out of bound usage of cooling_devs
+    - soc: aspeed: lpc-ctrl: Fix boundary check for mmap
+    - soc: aspeed: p2a-ctrl: Fix boundary check for mmap
+    - arm64: head: avoid over-mapping in map_memory
+    - crypto: public_key: fix overflow during implicit conversion
+    - block: bfq: fix bfq_set_next_ioprio_data()
+    - power: supply: max17042: handle fails of reading status register
+    - dm crypt: Avoid percpu_counter spinlock contention in crypt_page_alloc()
+    - VMCI: fix NULL pointer dereference when unmapping queue pair
+    - media: uvc: don't do DMA on stack
+    - media: rc-loopback: return number of emitters rather than error
+    - Revert "dmaengine: imx-sdma: refine to load context only once"
+    - dmaengine: imx-sdma: remove duplicated sdma_load_context
+    - libata: add ATA_HORKAGE_NO_NCQ_TRIM for Samsung 860 and 870 SSDs
+    - ARM: 9105/1: atags_to_fdt: don't warn about stack size
+    - PCI/portdrv: Enable Bandwidth Notification only if port supports it
+    - PCI: Restrict ASMedia ASM1062 SATA Max Payload Size Supported
+    - PCI: Return ~0 data on pciconfig_read() CAP_SYS_ADMIN failure
+    - PCI: xilinx-nwl: Enable the clock through CCF
+    - PCI: aardvark: Fix checking for PIO status
+    - PCI: aardvark: Increase polling delay to 1.5s while waiting for PIO response
+    - PCI: aardvark: Fix masking and unmasking legacy INTx interrupts
+    - HID: input: do not report stylus battery state as "full"
+    - f2fs: quota: fix potential deadlock
+    - scsi: bsg: Remove support for SCSI_IOCTL_SEND_COMMAND
+    - IB/hfi1: Adjust pkey entry in index 0
+    - RDMA/iwcm: Release resources if iw_cm module initialization fails
+    - docs: Fix infiniband uverbs minor number
+    - pinctrl: samsung: Fix pinctrl bank pin count
+    - vfio: Use config not menuconfig for VFIO_NOIOMMU
+    - powerpc/stacktrace: Include linux/delay.h
+    - RDMA/efa: Remove double QP type assignment
+    - f2fs: show f2fs instance in printk_ratelimited
+    - f2fs: reduce the scope of setting fsck tag when de->name_len is zero
+    - openrisc: don't printk() unconditionally
+    - dma-debug: fix debugfs initialization order
+    - SUNRPC: Fix potential memory corruption
+    - scsi: fdomain: Fix error return code in fdomain_probe()
+    - pinctrl: single: Fix error return code in pcs_parse_bits_in_pinctrl_entry()
+    - scsi: smartpqi: Fix an error code in pqi_get_raid_map()
+    - scsi: qedi: Fix error codes in qedi_alloc_global_queues()
+    - scsi: qedf: Fix error codes in qedf_alloc_global_queues()
+    - powerpc/config: Renable MTD_PHYSMAP_OF
+    - scsi: target: avoid per-loop XCOPY buffer allocations
+    - HID: i2c-hid: Fix Elan touchpad regression
+    - KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs
+      are live
+    - platform/x86: dell-smbios-wmi: Add missing kfree in error-exit from
+      run_smbios_call
+    - fscache: Fix cookie key hashing
+    - clk: at91: sam9x60: Don't use audio PLL
+    - clk: at91: clk-generated: pass the id of changeable parent at registration
+    - clk: at91: clk-generated: Limit the requested rate to our range
+    - KVM: PPC: Fix clearing never mapped TCEs in realmode
+    - f2fs: fix to account missing .skipped_gc_rwsem
+    - f2fs: fix unexpected ENOENT comes from f2fs_map_blocks()
+    - f2fs: fix to unmap pages from userspace process in punch_hole()
+    - MIPS: Malta: fix alignment of the devicetree buffer
+    - kbuild: Fix 'no symbols' warning when CONFIG_TRIM_UNUSD_KSYMS=y
+    - userfaultfd: prevent concurrent API initialization
+    - drm/amdgpu: Fix amdgpu_ras_eeprom_init()
+    - ASoC: atmel: ATMEL drivers don't need HAS_DMA
+    - media: dib8000: rewrite the init prbs logic
+    - crypto: mxs-dcp - Use sg_mapping_iter to copy data
+    - PCI: Use pci_update_current_state() in pci_enable_device_flags()
+    - tipc: keep the skb in rcv queue until the whole data is read
+    - iio: dac: ad5624r: Fix incorrect handling of an optional regulator.
+    - iavf: do not override the adapter state in the watchdog task
+    - iavf: fix locking of critical sections
+    - ARM: dts: qcom: apq8064: correct clock names
+    - video: fbdev: kyro: fix a DoS bug by restricting user input
+    - netlink: Deal with ESRCH error in nlmsg_notify()
+    - Smack: Fix wrong semantics in smk_access_entry()
+    - drm: avoid blocking in drm_clients_info's rcu section
+    - igc: Check if num of q_vectors is smaller than max before array access
+    - usb: host: fotg210: fix the endpoint's transactional opportunities
+      calculation
+    - usb: host: fotg210: fix the actual_length of an iso packet
+    - usb: gadget: u_ether: fix a potential null pointer dereference
+    - USB: EHCI: ehci-mv: improve error handling in mv_ehci_enable()
+    - usb: gadget: composite: Allow bMaxPower=0 if self-powered
+    - staging: board: Fix uninitialized spinlock when attaching genpd
+    - tty: serial: jsm: hold port lock when reporting modem line changes
+    - drm/amd/display: Fix timer_per_pixel unit error
+    - drm/amd/amdgpu: Update debugfs link_settings output link_rate field in hex
+    - bpf/tests: Fix copy-and-paste error in double word test
+    - bpf/tests: Do not PASS tests without actually testing the result
+    - video: fbdev: asiliantfb: Error out if 'pixclock' equals zero
+    - video: fbdev: kyro: Error out if 'pixclock' equals zero
+    - video: fbdev: riva: Error out if 'pixclock' equals zero
+    - ipv4: ip_output.c: Fix out-of-bounds warning in ip_copy_addrs()
+    - flow_dissector: Fix out-of-bounds warnings
+    - s390/jump_label: print real address in a case of a jump label bug
+    - s390: make PCI mio support a machine flag
+    - serial: 8250: Define RX trigger levels for OxSemi 950 devices
+    - xtensa: ISS: don't panic in rs_init
+    - hvsi: don't panic on tty_register_driver failure
+    - serial: 8250_pci: make setup_port() parameters explicitly unsigned
+    - staging: ks7010: Fix the initialization of the 'sleep_status' structure
+    - samples: bpf: Fix tracex7 error raised on the missing argument
+    - ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init()
+    - Bluetooth: skip invalid hci_sync_conn_complete_evt
+    - workqueue: Fix possible memory leaks in wq_numa_init()
+    - bonding: 3ad: fix the concurrency between __bond_release_one() and
+      bond_3ad_state_machine_handler()
+    - arm64: tegra: Fix Tegra194 PCIe EP compatible string
+    - ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the
+      matching in-/output
+    - media: imx258: Rectify mismatch of VTS value
+    - media: imx258: Limit the max analogue gain to 480
+    - media: v4l2-dv-timings.c: fix wrong condition in two for-loops
+    - media: TDA1997x: fix tda1997x_query_dv_timings() return value
+    - media: tegra-cec: Handle errors of clk_prepare_enable()
+    - ARM: dts: imx53-ppd: Fix ACHC entry
+    - arm64: dts: qcom: sdm660: use reg value for memory node
+    - net: ethernet: stmmac: Do not use unreachable() in ipq806x_gmac_probe()
+    - drm/msm: mdp4: drop vblank get/put from prepare/complete_commit
+    - selftests/bpf: Fix xdp_tx.c prog section name
+    - Bluetooth: schedule SCO timeouts with delayed_work
+    - Bluetooth: avoid circular locks in sco_sock_connect
+    - net/mlx5: Fix variable type to match 64bit
+    - gpu: drm: amd: amdgpu: amdgpu_i2c: fix possible uninitialized-variable
+      access in amdgpu_i2c_router_select_ddc_port()
+    - drm/display: fix possible null-pointer dereference in dcn10_set_clock()
+    - mac80211: Fix monitor MTU limit so that A-MSDUs get through
+    - ARM: tegra: tamonten: Fix UART pad setting
+    - arm64: tegra: Fix compatible string for Tegra132 CPUs
+    - arm64: dts: ls1046a: fix eeprom entries
+    - nvme-tcp: don't check blk_mq_tag_to_rq when receiving pdu data
+    - Bluetooth: Fix handling of LE Enhanced Connection Complete
+    - opp: Don't print an error if required-opps is missing
+    - serial: sh-sci: fix break handling for sysrq
+    - tcp: enable data-less, empty-cookie SYN with TFO_SERVER_COOKIE_NOT_REQD
+    - rpc: fix gss_svc_init cleanup on failure
+    - staging: rts5208: Fix get_ms_information() heap buffer size
+    - gfs2: Don't call dlm after protocol is unmounted
+    - usb: chipidea: host: fix port index underflow and UBSAN complains
+    - lockd: lockd server-side shouldn't set fl_ops
+    - drm/exynos: Always initialize mapping in exynos_drm_register_dma()
+    - m68knommu: only set CONFIG_ISA_DMA_API for ColdFire sub-arch
+    - btrfs: tree-log: check btrfs_lookup_data_extent return value
+    - ASoC: Intel: Skylake: Fix module configuration for KPB and MIXER
+    - ASoC: Intel: Skylake: Fix passing loadable flag for module
+    - of: Don't allow __of_attached_node_sysfs() without CONFIG_SYSFS
+    - mmc: sdhci-of-arasan: Check return value of non-void funtions
+    - mmc: rtsx_pci: Fix long reads when clock is prescaled
+    - selftests/bpf: Enlarge select() timeout for test_maps
+    - mmc: core: Return correct emmc response in case of ioctl error
+    - cifs: fix wrong release in sess_alloc_buffer() failed path
+    - Revert "USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST
+      quirk set"
+    - usb: musb: musb_dsps: request_irq() after initializing musb
+    - usbip: give back URBs for unsent unlink requests during cleanup
+    - usbip:vhci_hcd USB port can get stuck in the disabled state
+    - ASoC: rockchip: i2s: Fix regmap_ops hang
+    - ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B
+    - drm/amdkfd: Account for SH/SE count when setting up cu masks.
+    - iwlwifi: mvm: fix a memory leak in iwl_mvm_mac_ctxt_beacon_changed
+    - iwlwifi: mvm: avoid static queue number aliasing
+    - iwlwifi: mvm: fix access to BSS elements
+    - net/mlx5: DR, Enable QP retransmission
+    - parport: remove non-zero check on count
+    - ath9k: fix OOB read ar9300_eeprom_restore_internal
+    - ath9k: fix sleeping in atomic context
+    - net: fix NULL pointer reference in cipso_v4_doi_free
+    - fix array-index-out-of-bounds in taprio_change
+    - net: w5100: check return value after calling platform_get_resource()
+    - parisc: fix crash with signals and alloca
+    - ovl: fix BUG_ON() in may_delete() when called from ovl_cleanup()
+    - scsi: BusLogic: Fix missing pr_cont() use
+    - scsi: qla2xxx: Changes to support kdump kernel
+    - scsi: qla2xxx: Sync queue idx with queue_pair_map idx
+    - cpufreq: powernv: Fix init_chip_info initialization in numa=off
+    - s390/pv: fix the forcing of the swiotlb
+    - mm/hugetlb: initialize hugetlb_usage in mm_init
+    - mm,vmscan: fix divide by zero in get_scan_count
+    - memcg: enable accounting for pids in nested pid namespaces
+    - platform/chrome: cros_ec_proto: Send command again when timeout occurs
+    - lib/test_stackinit: Fix static initializer test
+    - net: dsa: lantiq_gswip: fix maximum frame length
+    - drm/msi/mdp4: populate priv->kms in mdp4_kms_init
+    - drm/amdgpu: Fix BUG_ON assert
+    - drm/panfrost: Simplify lock_region calculation
+    - drm/panfrost: Use u64 for size in lock_region
+    - drm/panfrost: Clamp lock region to Bifrost minimum
+    - btrfs: fix upper limit for max_inline for page size 64K
+    - xen: reset legacy rtc flag for PV domU
+    - bnx2x: Fix enabling network interfaces without VFs
+    - arm64/sve: Use correct size when reinitialising SVE state
+    - PM: base: power: don't try to use non-existing RTC for storing data
+    - PCI: Add AMD GPU multi-function power dependencies
+    - drm/amd/amdgpu: Increase HWIP_MAX_INSTANCE to 10
+    - drm/etnaviv: return context from etnaviv_iommu_context_get
+    - drm/etnaviv: put submit prev MMU context when it exists
+    - drm/etnaviv: stop abusing mmu_context as FE running marker
+    - drm/etnaviv: keep MMU context across runtime suspend/resume
+    - drm/etnaviv: exec and MMU state is lost when resetting the GPU
+    - drm/etnaviv: fix MMU context leak on GPU reset
+    - drm/etnaviv: reference MMU context when setting up hardware state
+    - drm/etnaviv: add missing MMU context put when reaping MMU mapping
+    - s390/sclp: fix Secure-IPL facility detection
+    - x86/mm: Fix kern_addr_valid() to cope with existing but not present entries
+    - tipc: fix an use-after-free issue in tipc_recvmsg
+    - net-caif: avoid user-triggerable WARN_ON(1)
+    - ptp: dp83640: don't define PAGE0
+    - net/l2tp: Fix reference count leak in l2tp_udp_recv_core
+    - r6040: Restore MDIO clock frequency after MAC reset
+    - tipc: increase timeout in tipc_sk_enqueue()
+    - perf machine: Initialize srcline string member in add_location struct
+    - net/mlx5: FWTrace, cancel work on alloc pd error flow
+    - net/mlx5: Fix potential sleeping in atomic context
+    - events: Reuse value read using READ_ONCE instead of re-reading it
+    - vhost_net: fix OoB on sendmsg() failure.
+    - net/af_unix: fix a data-race in unix_dgram_poll
+    - net: dsa: destroy the phylink instance on any error in dsa_slave_phy_setup
+    - tcp: fix tp->undo_retrans accounting in tcp_sacktag_one()
+    - qed: Handle management FW error
+    - dt-bindings: arm: Fix Toradex compatible typo
+    - ibmvnic: check failover_pending in login response
+    - KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing
+      registers
+    - net: hns3: pad the short tunnel frame before sending to hardware
+    - net: hns3: change affinity_mask to numa node range
+    - net: hns3: disable mac in flr process
+    - net: hns3: fix the timing issue of VF clearing interrupt sources
+    - mm/memory_hotplug: use "unsigned long" for PFN in zone_for_pfn_range()
+    - dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation
+    - mfd: db8500-prcmu: Adjust map to reality
+    - PCI: Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms
+    - fuse: fix use after free in fuse_read_interrupt()
+    - mfd: Don't use irq_create_mapping() to resolve a mapping
+    - tracing/probes: Reject events which have the same name of existing one
+    - PCI: Add ACS quirks for Cavium multi-function devices
+    - Set fc_nlinfo in nh_create_ipv4, nh_create_ipv6
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit LN920
+    - PCI: ibmphp: Fix double unmap of io_mem
+    - ethtool: Fix an error code in cxgb2.c
+    - NTB: Fix an error code in ntb_msit_probe()
+    - NTB: perf: Fix an error code in perf_setup_inbuf()
+    - mfd: axp20x: Update AXP288 volatile ranges
+    - PCI: Fix pci_dev_str_match_path() alloc while atomic bug
+    - mfd: tqmx86: Clear GPIO IRQ resource when no IRQ is set
+    - KVM: arm64: Handle PSCI resets before userspace touches vCPU state
+    - PCI: Sync __pci_register_driver() stub for CONFIG_PCI=n
+    - mtd: rawnand: cafe: Fix a resource leak in the error handling path of
+      'cafe_nand_probe()'
+    - ARC: export clear_user_page() for modules
+    - perf unwind: Do not overwrite FEATURE_CHECK_LDFLAGS-libunwind-{x86,aarch64}
+    - net: dsa: b53: Fix calculating number of switch ports
+    - netfilter: socket: icmp6: fix use-after-scope
+    - fq_codel: reject silly quantum parameters
+    - qlcnic: Remove redundant unlock in qlcnic_pinit_from_rom
+    - ip_gre: validate csum_start only on pull
+    - net: renesas: sh_eth: Fix freeing wrong tx descriptor
+    - Linux 5.4.148
+
+  * Focal update: v5.4.147 upstream stable release (LP: #1946795)
+    - Linux 5.4.147
+    - upstream stable to v5.4.147
+
+  * CVE-2021-3428
+    - ext4: save the error code which triggered an ext4_error() in the superblock
+    - ext4: simulate various I/O and checksum errors when reading metadata
+    - ext4: save all error info in save_error_info() and drop ext4_set_errno()
+    - ext4: check journal inode extents more carefully
+
+  * ip6gretap / erspan / ip6erspan in rtnetlink.sh from net of
+    ubuntu_kernel_selftests failed on B-5.4-aws / B-5.4-gke / B-5.4-oracle /
+    B-5.4-azure / B-5.4 (LP: #1896448)
+    - SAUCE: selftests: rtnetlink: fixes for older iproute2
+
+  * CVE-2019-19449
+    - f2fs: fix wrong total_sections check and fsmeta check
+    - f2fs: fix to do sanity check on segment/section count
+
+  * kernel bug found when disconnecting one fiber channel interface on Cisco
+    Chassis with fnic DRV_VERSION "1.6.0.47" (LP: #1944586)
+    - scsi: fnic: Do not call 'scsi_done()' for unhandled commands
+
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (unknown type
+    name ‘__u64’) (LP: #1944613)
+    - SAUCE: selftests/memfd: fix __u64 not defined build issue
+
+  * Medion Notebook Keyboard not working (LP: #1909814)
+    - ACPI: resources: Add DMI-based legacy IRQ override quirk
+
+  * vrf: fix refcnt leak with vxlan slaves (LP: #1945180)
+    - ipv4: Fix device used for dst_alloc with local routes
+
+  * Check for changes relevant for security certifications (LP: #1945989)
+    - [Packaging] Add a new fips-checks script
+    - [Packaging] Add fips-checks as part of finalchecks
+
+  * Fix cold plugged USB device on certain PCIe USB cards (LP: #1945211)
+    - Revert "UBUNTU: SAUCE: Revert "usb: core: reduce power-on-good delay time of
+      root hub""
+    - usb: core: hcd: Add support for deferring roothub registration
+    - xhci: Set HCD flag to defer primary roothub registration
+    - usb: core: hcd: Modularize HCD stop configuration in usb_stop_hcd()
+
+  * CVE-2021-3759
+    - memcg: enable accounting of ipc resources
+
+  * Focal update: v5.4.146 upstream stable release (LP: #1946024)
+    - locking/mutex: Fix HANDOFF condition
+    - regmap: fix the offset of register error log
+    - crypto: mxs-dcp - Check for DMA mapping errors
+    - sched/deadline: Fix reset_on_fork reporting of DL tasks
+    - power: supply: axp288_fuel_gauge: Report register-address on readb / writeb
+      errors
+    - crypto: omap-sham - clear dma flags only after omap_sham_update_dma_stop()
+    - sched/deadline: Fix missing clock update in migrate_task_rq_dl()
+    - rcu/tree: Handle VM stoppage in stall detection
+    - hrtimer: Avoid double reprogramming in __hrtimer_start_range_ns()
+    - hrtimer: Ensure timerfd notification for HIGHRES=n
+    - udf: Check LVID earlier
+    - udf: Fix iocharset=utf8 mount option
+    - isofs: joliet: Fix iocharset=utf8 mount option
+    - bcache: add proper error unwinding in bcache_device_init
+    - nvme-tcp: don't update queue count when failing to set io queues
+    - nvme-rdma: don't update queue count when failing to set io queues
+    - nvmet: pass back cntlid on successful completion
+    - power: supply: max17042_battery: fix typo in MAx17042_TOFF
+    - s390/cio: add dev_busid sysfs entry for each subchannel
+    - libata: fix ata_host_start()
+    - crypto: qat - do not ignore errors from enable_vf2pf_comms()
+    - crypto: qat - handle both source of interrupt in VF ISR
+    - crypto: qat - fix reuse of completion variable
+    - crypto: qat - fix naming for init/shutdown VF to PF notifications
+    - crypto: qat - do not export adf_iov_putmsg()
+    - fcntl: fix potential deadlock for &fasync_struct.fa_lock
+    - udf_get_extendedattr() had no boundary checks.
+    - s390/kasan: fix large PMD pages address alignment check
+    - s390/debug: fix debug area life cycle
+    - m68k: emu: Fix invalid free in nfeth_cleanup()
+    - sched: Fix UCLAMP_FLAG_IDLE setting
+    - spi: spi-fsl-dspi: Fix issue with uninitialized dma_slave_config
+    - spi: spi-pic32: Fix issue with uninitialized dma_slave_config
+    - genirq/timings: Fix error return code in irq_timings_test_irqs()
+    - lib/mpi: use kcalloc in mpi_resize
+    - clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock
+      source channel
+    - crypto: qat - use proper type for vf_mask
+    - certs: Trigger creation of RSA module signing key if it's not an RSA key
+    - regulator: vctrl: Use locked regulator_get_voltage in probe path
+    - regulator: vctrl: Avoid lockdep warning in enable/disable ops
+    - spi: sprd: Fix the wrong WDG_LOAD_VAL
+    - spi: spi-zynq-qspi: use wait_for_completion_timeout to make
+      zynq_qspi_exec_mem_op not interruptible
+    - EDAC/i10nm: Fix NVDIMM detection
+    - drm/panfrost: Fix missing clk_disable_unprepare() on error in
+      panfrost_clk_init()
+    - media: TDA1997x: enable EDID support
+    - soc: rockchip: ROCKCHIP_GRF should not default to y, unconditionally
+    - media: cxd2880-spi: Fix an error handling path
+    - bpf: Fix a typo of reuseport map in bpf.h.
+    - bpf: Fix potential memleak and UAF in the verifier.
+    - ARM: dts: aspeed-g6: Fix HVI3C function-group in pinctrl dtsi
+    - arm64: dts: renesas: r8a77995: draak: Remove bogus adv7511w properties
+    - soc: qcom: rpmhpd: Use corner in power_off
+    - media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init
+    - media: dvb-usb: fix uninit-value in vp702x_read_mac_addr
+    - media: dvb-usb: Fix error handling in dvb_usb_i2c_init
+    - media: go7007: remove redundant initialization
+    - media: coda: fix frame_mem_ctrl for YUV420 and YVU420 formats
+    - Bluetooth: sco: prevent information leak in sco_conn_defer_accept()
+    - 6lowpan: iphc: Fix an off-by-one check of array index
+    - netns: protect netns ID lookups with RCU
+    - tcp: seq_file: Avoid skipping sk during tcp_seek_last_pos
+    - ARM: dts: meson8: Use a higher default GPU clock frequency
+    - ARM: dts: meson8b: odroidc1: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: mxq: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: ec100: Fix the pwm regulator supply properties
+    - net/mlx5e: Prohibit inner indir TIRs in IPoIB
+    - cgroup/cpuset: Fix a partition bug with hotplug
+    - net: cipso: fix warnings in netlbl_cipsov4_add_std
+    - i2c: highlander: add IRQ check
+    - leds: lt3593: Put fwnode in any case during ->probe()
+    - leds: trigger: audio: Add an activate callback to ensure the initial
+      brightness is set
+    - media: em28xx-input: fix refcount bug in em28xx_usb_disconnect
+    - media: venus: venc: Fix potential null pointer dereference on pointer fmt
+    - PCI: PM: Avoid forcing PCI_D0 for wakeup reasons inconsistently
+    - PCI: PM: Enable PME if it can be signaled from D3cold
+    - soc: qcom: smsm: Fix missed interrupts if state changes while masked
+    - debugfs: Return error during {full/open}_proxy_open() on rmmod
+    - Bluetooth: increase BTNAMSIZ to 21 chars to fix potential buffer overflow
+    - PM: EM: Increase energy calculation precision
+    - drm/msm/dpu: make dpu_hw_ctl_clear_all_blendstages clear necessary LMs
+    - arm64: dts: exynos: correct GIC CPU interfaces address range on Exynos7
+    - counter: 104-quad-8: Return error when invalid mode during ceiling_write
+    - Bluetooth: fix repeated calls to sco_sock_kill
+    - drm/msm/dsi: Fix some reference counted resource leaks
+    - usb: gadget: udc: at91: add IRQ check
+    - usb: phy: fsl-usb: add IRQ check
+    - usb: phy: twl6030: add IRQ checks
+    - usb: gadget: udc: renesas_usb3: Fix soc_device_match() abuse
+    - usb: host: ohci-tmio: add IRQ check
+    - usb: phy: tahvo: add IRQ check
+    - mac80211: Fix insufficient headroom issue for AMSDU
+    - lockd: Fix invalid lockowner cast after vfs_test_lock
+    - nfsd4: Fix forced-expiry locking
+    - usb: gadget: mv_u3d: request_irq() after initializing UDC
+    - mm/swap: consider max pages in iomap_swapfile_add_extent
+    - Bluetooth: add timeout sanity check to hci_inquiry
+    - i2c: iop3xx: fix deferred probing
+    - i2c: s3c2410: fix IRQ check
+    - rsi: fix error code in rsi_load_9116_firmware()
+    - rsi: fix an error code in rsi_probe()
+    - ASoC: Intel: Skylake: Leave data as is when invoking TLV IPCs
+    - ASoC: Intel: Skylake: Fix module resource and format selection
+    - mmc: dw_mmc: Fix issue with uninitialized dma_slave_config
+    - mmc: moxart: Fix issue with uninitialized dma_slave_config
+    - bpf: Fix possible out of bound write in narrow load handling
+    - CIFS: Fix a potencially linear read overflow
+    - i2c: mt65xx: fix IRQ check
+    - usb: ehci-orion: Handle errors of clk_prepare_enable() in probe
+    - usb: bdc: Fix an error handling path in 'bdc_probe()' when no suitable DMA
+      config is available
+    - tty: serial: fsl_lpuart: fix the wrong mapbase value
+    - ASoC: wcd9335: Fix a double irq free in the remove function
+    - ASoC: wcd9335: Fix a memory leak in the error handling path of the probe
+      function
+    - ASoC: wcd9335: Disable irq on slave ports in the remove function
+    - ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point()
+    - bcma: Fix memory leak for internally-handled cores
+    - brcmfmac: pcie: fix oops on failure to resume and reprobe
+    - ipv6: make exception cache less predictible
+    - ipv4: make exception cache less predictible
+    - net: sched: Fix qdisc_rate_table refcount leak when get tcf_block failed
+    - net: qualcomm: fix QCA7000 checksum handling
+    - octeontx2-af: Fix loop in free and unmap counter
+    - ipv4: fix endianness issue in inet_rtm_getroute_build_skb()
+    - bpf: Introduce BPF nospec instruction for mitigating Spectre v4
+    - bpf: Fix leakage due to insufficient speculative store bypass mitigation
+    - bpf: verifier: Allocate idmap scratch in verifier env
+    - bpf: Fix pointer arithmetic mask tightening under state pruning
+    - tty: Fix data race between tiocsti() and flush_to_ldisc()
+    - perf/x86/amd/ibs: Extend PERF_PMU_CAP_NO_EXCLUDE to IBS Op
+    - x86/resctrl: Fix a maybe-uninitialized build warning treated as error
+    - KVM: s390: index kvm->arch.idle_mask by vcpu_idx
+    - KVM: x86: Update vCPU's hv_clock before back to guest when tsc_offset is
+      adjusted
+    - KVM: nVMX: Unconditionally clear nested.pi_pending on nested VM-Enter
+    - fuse: truncate pagecache on atomic_o_trunc
+    - fuse: flush extending writes
+    - IMA: remove -Wmissing-prototypes warning
+    - IMA: remove the dependency on CRYPTO_MD5
+    - fbmem: don't allow too huge resolutions
+    - backlight: pwm_bl: Improve bootloader/kernel device handover
+    - clk: kirkwood: Fix a clocking boot regression
+    - Linux 5.4.146
+
+  * AMD A8-7680 (amdgpu): broken Xorg acceleration and hibernation
+    (LP: #1920674) // Focal update: v5.4.146 upstream stable release
+    (LP: #1946024)
+    - drm/amdgpu/acp: Make PM domain really work
+
+  * Focal update: v5.4.145 upstream stable release (LP: #1945517)
+    - fscrypt: add fscrypt_symlink_getattr() for computing st_size
+    - ext4: report correct st_size for encrypted symlinks
+    - f2fs: report correct st_size for encrypted symlinks
+    - ubifs: report correct st_size for encrypted symlinks
+    - kthread: Fix PF_KTHREAD vs to_kthread() race
+    - xtensa: fix kconfig unmet dependency warning for HAVE_FUTEX_CMPXCHG
+    - gpu: ipu-v3: Fix i.MX IPU-v3 offset calculations for (semi)planar U/V
+      formats
+    - reset: reset-zynqmp: Fixed the argument data type
+    - qed: Fix the VF msix vectors flow
+    - net: macb: Add a NULL check on desc_ptp
+    - qede: Fix memset corruption
+    - perf/x86/intel/pt: Fix mask of num_address_ranges
+    - perf/x86/amd/ibs: Work around erratum #1197
+    - perf/x86/amd/power: Assign pmu.module
+    - cryptoloop: add a deprecation warning
+    - ARM: 8918/2: only build return_address() if needed
+    - ALSA: hda/realtek: Workaround for conflicting SSID on ASUS ROG Strix G17
+    - ALSA: pcm: fix divide error in snd_pcm_lib_ioctl
+    - ARC: wireup clone3 syscall
+    - media: stkwebcam: fix memory leak in stk_camera_probe
+    - igmp: Add ip_mc_list lock in ip_check_mc_rcu
+    - USB: serial: mos7720: improve OOM-handling in read_mos_reg()
+    - ipv4/icmp: l3mdev: Perform icmp error route lookup on source device routing
+      table (v2)
+    - powerpc/boot: Delete unneeded .globl _zimage_start
+    - net: ll_temac: Remove left-over debug message
+    - mm/page_alloc: speed up the iteration of max_order
+    - Revert "r8169: avoid link-up interrupt issue on RTL8106e if user enables
+      ASPM"
+    - x86/events/amd/iommu: Fix invalid Perf result due to IOMMU PMC power-gating
+    - Revert "btrfs: compression: don't try to compress if we don't have enough
+      pages"
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 800
+    - usb: host: xhci-rcar: Don't reload firmware after the completion
+    - usb: mtu3: use @mult for HS isoc or intr
+    - usb: mtu3: fix the wrong HS mult value
+    - xhci: fix unsafe memory usage in xhci tracing
+    - x86/reboot: Limit Dell Optiplex 990 quirk to early BIOS versions
+    - PCI: Call Max Payload Size-related fixup quirks early
+    - Linux 5.4.145
+
+  * Focal update: v5.4.144 upstream stable release (LP: #1944756)
+    - net: qrtr: fix another OOB Read in qrtr_endpoint_post
+    - ARC: Fix CONFIG_STACKDEPOT
+    - netfilter: conntrack: collect all entries in one cycle
+    - once: Fix panic when module unload
+    - ovl: fix uninitialized pointer read in ovl_lookup_real_one()
+    - mmc: sdhci-msm: Update the software timeout value for sdhc
+    - mm, oom: make the calculation of oom badness more accurate
+    - can: usb: esd_usb2: esd_usb2_rx_event(): fix the interchange of the CAN RX
+      and TX error counters
+    - Revert "USB: serial: ch341: fix character loss at high transfer rates"
+    - USB: serial: option: add new VID/PID to support Fibocom FG150
+    - usb: dwc3: gadget: Fix dwc3_calc_trbs_left()
+    - usb: dwc3: gadget: Stop EP0 transfers during pullup disable
+    - scsi: core: Fix hang of freezing queue between blocking and running device
+    - RDMA/bnxt_re: Add missing spin lock initialization
+    - IB/hfi1: Fix possible null-pointer dereference in _extend_sdma_tx_descs()
+    - e1000e: Fix the max snoop/no-snoop latency for 10M
+    - RDMA/efa: Free IRQ vectors on error flow
+    - ip_gre: add validation for csum_start
+    - xgene-v2: Fix a resource leak in the error handling path of 'xge_probe()'
+    - net: marvell: fix MVNETA_TX_IN_PRGRS bit number
+    - rtnetlink: Return correct error on changing device netns
+    - net: hns3: clear hardware resource when loading driver
+    - net: hns3: fix duplicate node in VLAN list
+    - net: hns3: fix get wrong pfc_en when query PFC configuration
+    - drm/i915: Fix syncmap memory leak
+    - usb: gadget: u_audio: fix race condition on endpoint stop
+    - perf/x86/intel/uncore: Fix integer overflow on 23 bit left shift of a u32
+    - opp: remove WARN when no valid OPPs remain
+    - virtio: Improve vq->broken access to avoid any compiler optimization
+    - virtio_pci: Support surprise removal of virtio pci device
+    - vringh: Use wiov->used to check for read/write desc order
+    - qed: qed ll2 race condition fixes
+    - qed: Fix null-pointer dereference in qed_rdma_create_qp()
+    - drm: Copy drm_wait_vblank to user before returning
+    - drm/nouveau/disp: power down unused DP links during init
+    - net/rds: dma_map_sg is entitled to merge entries
+    - btrfs: fix race between marking inode needs to be logged and log syncing
+    - vt_kdsetmode: extend console locking
+    - bpf: Track contents of read-only maps as scalars
+    - bpf: Fix cast to pointer from integer of different size warning
+    - net: dsa: mt7530: fix VLAN traffic leaks again
+    - KVM: x86/mmu: Treat NX as used (not reserved) for all !TDP shadow MMUs
+    - arm64: dts: qcom: msm8994-angler: Fix gpio-reserved-ranges 85-88
+    - btrfs: fix NULL pointer dereference when deleting device by invalid id
+    - Revert "floppy: reintroduce O_NDELAY fix"
+    - Revert "parisc: Add assembly implementations for memset, strlen, strcpy,
+      strncpy and strcat"
+    - net: don't unconditionally copy_from_user a struct ifreq for socket ioctls
+    - audit: move put_tree() to avoid trim_trees refcount underflow and UAF
+    - Linux 5.4.144
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Fri, 15 Oct 2021 11:56:24 -0600
+
+linux (5.4.0-89.100) focal; urgency=medium
+
+  * focal/linux: 5.4.0-89.100 -proposed tracker (LP: #1944901)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.27)
+
+  * ext4 journal recovery fails w/ data=journal + mmap (LP: #1847340)
+    - jbd2: introduce/export functions
+      jbd2_journal_submit|finish_inode_data_buffers()
+    - jbd2, ext4, ocfs2: introduce/use journal callbacks
+      j_submit|finish_inode_data_buffers()
+    - ext4: data=journal: fixes for ext4_page_mkwrite()
+    - ext4: data=journal: write-protect pages on j_submit_inode_data_buffers()
+    - ext4: fix mmap write protection for data=journal mode
+
+  * CVE-2021-40490
+    - ext4: fix race writing to an inline_data file while its xattrs are changing
+
+  * Obsolete patch "UBUNTU: SAUCE: ext4: fix directory index node split
+    corruption" (LP: #1942902)
+    - Revert "UBUNTU: SAUCE: ext4: fix directory index node split corruption"
+
+  * psock_snd.sh in net from ubuntu_kernel_selftests ADT failure with
+    focal/groovy/hirsute/impish (LP: #1892213)
+    - selftests/net: remove min gso test in packet_snd
+
+  * Focal update: v5.4.143 upstream stable release (LP: #1944212)
+    - ext4: fix EXT4_MAX_LOGICAL_BLOCK macro
+    - x86/fpu: Make init_fpstate correct with optimized XSAVE
+    - 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
+    - mtd: cfi_cmdset_0002: fix crash when erasing/writing AMD cards
+    - media: zr364xx: propagate errors from zr364xx_start_readpipe()
+    - media: zr364xx: fix memory leaks in probe()
+    - media: drivers/media/usb: fix memory leak in zr364xx_probe
+    - USB: core: Avoid WARNings for 0-length descriptor requests
+    - dmaengine: xilinx_dma: Fix read-after-free bug when terminating transfers
+    - dmaengine: usb-dmac: Fix PM reference leak in usb_dmac_probe()
+    - ARM: dts: am43x-epos-evm: Reduce i2c0 bus speed for tps65218
+    - dmaengine: of-dma: router_xlate to return -EPROBE_DEFER if controller is not
+      yet available
+    - scsi: megaraid_mm: Fix end of loop tests for list_for_each_entry()
+    - scsi: scsi_dh_rdac: Avoid crash during rdac_bus_attach()
+    - scsi: core: Avoid printing an error if target_alloc() returns -ENXIO
+    - scsi: core: Fix capacity set to zero after offlinining device
+    - ARM: dts: nomadik: Fix up interrupt controller node names
+    - net: usb: lan78xx: don't modify phy_device state concurrently
+    - drm/amd/display: Fix Dynamic bpp issue with 8K30 with Navi 1X
+    - Bluetooth: hidp: use correct wait queue when removing ctrl_wait
+    - iommu: Check if group is NULL before remove device
+    - cpufreq: armada-37xx: forbid cpufreq for 1.2 GHz variant
+    - dccp: add do-while-0 stubs for dccp_pr_debug macros
+    - virtio: Protect vqs list access
+    - vhost: Fix the calculation in vhost_overflow()
+    - bpf: Clear zext_dst of dead insns
+    - bnxt: don't lock the tx queue from napi poll
+    - bnxt: disable napi before canceling DIM
+    - net: 6pack: fix slab-out-of-bounds in decode_data
+    - ptp_pch: Restore dependency on PCI
+    - bnxt_en: Add missing DMA memory barriers
+    - vrf: Reset skb conntrack connection on VRF rcv
+    - virtio-net: support XDP when not more queues
+    - virtio-net: use NETIF_F_GRO_HW instead of NETIF_F_LRO
+    - net: qlcnic: add missed unlock in qlcnic_83xx_flash_read32
+    - net: mdio-mux: Don't ignore memory allocation errors
+    - net: mdio-mux: Handle -EPROBE_DEFER correctly
+    - ovs: clear skb->tstamp in forwarding path
+    - i40e: Fix ATR queue selection
+    - iavf: Fix ping is lost after untrusted VF had tried to change MAC
+    - ovl: add splice file read write helper
+    - mmc: dw_mmc: Fix hang on data CRC error
+    - ALSA: hda - fix the 'Capture Switch' value change notifications
+    - tracing / histogram: Fix NULL pointer dereference on strcmp() on NULL event
+      name
+    - slimbus: messaging: start transaction ids from 1 instead of zero
+    - slimbus: messaging: check for valid transaction id
+    - slimbus: ngd: reset dma setup during runtime pm
+    - ipack: tpci200: fix many double free issues in tpci200_pci_probe
+    - ipack: tpci200: fix memory leak in the tpci200_register
+    - btrfs: prevent rename2 from exchanging a subvol with a directory from
+      different parents
+    - PCI: Increase D3 delay for AMD Renoir/Cezanne XHCI
+    - ASoC: intel: atom: Fix breakage for PCM buffer address setup
+    - mm, memcg: avoid stale protection values when cgroup is above protection
+    - mm: memcontrol: fix occasional OOMs due to proportional memory.low reclaim
+    - fs: warn about impending deprecation of mandatory locks
+    - netfilter: nft_exthdr: fix endianness of tcp option cast
+    - Linux 5.4.143
+
+  * Focal update: v5.4.142 upstream stable release (LP: #1944202)
+    - iio: adc: ti-ads7950: Ensure CS is deasserted after reading channels
+    - iio: humidity: hdc100x: Add margin to the conversion time
+    - iio: adc: Fix incorrect exit of for-loop
+    - ASoC: xilinx: Fix reference to PCM buffer address
+    - ASoC: intel: atom: Fix reference to PCM buffer address
+    - i2c: dev: zero out array used for i2c reads from userspace
+    - ceph: reduce contention in ceph_check_delayed_caps()
+    - ACPI: NFIT: Fix support for virtual SPA ranges
+    - libnvdimm/region: Fix label activation vs errors
+    - ieee802154: hwsim: fix GPF in hwsim_set_edge_lqi
+    - ieee802154: hwsim: fix GPF in hwsim_new_edge_nl
+    - ASoC: cs42l42: Correct definition of ADC Volume control
+    - ASoC: cs42l42: Don't allow SND_SOC_DAIFMT_LEFT_J
+    - ASoC: cs42l42: Fix inversion of ADC Notch Switch control
+    - ASoC: cs42l42: Remove duplicate control for WNF filter frequency
+    - netfilter: nf_conntrack_bridge: Fix memory leak when error
+    - ASoC: cs42l42: Fix LRCLK frame start edge
+    - net: dsa: mt7530: add the missing RxUnicast MIB counter
+    - platform/x86: pcengines-apuv2: revert wiring up simswitch GPIO as LED
+    - platform/x86: pcengines-apuv2: Add missing terminating entries to gpio-
+      lookup tables
+    - net: phy: micrel: Fix link detection on ksz87xx switch"
+    - ppp: Fix generating ifname when empty IFLA_IFNAME is specified
+    - net: sched: act_mirred: Reset ct info when mirror/redirect skb
+    - iavf: Set RSS LUT and key in reset handle path
+    - psample: Add a fwd declaration for skbuff
+    - net/mlx5: Fix return value from tracer initialization
+    - drm/meson: fix colour distortion from HDR set during vendor u-boot
+    - net: dsa: microchip: Fix ksz_read64()
+    - net: Fix memory leak in ieee802154_raw_deliver
+    - net: igmp: fix data-race in igmp_ifc_timer_expire()
+    - net: dsa: lan9303: fix broken backpressure in .port_fdb_dump
+    - net: dsa: lantiq: fix broken backpressure in .port_fdb_dump
+    - net: dsa: sja1105: fix broken backpressure in .port_fdb_dump
+    - net: bridge: fix memleak in br_add_if()
+    - net: linkwatch: fix failure to restore device state across suspend/resume
+    - tcp_bbr: fix u32 wrap bug in round logic if bbr_init() called after 2B
+      packets
+    - net: igmp: increase size of mr_ifc_count
+    - xen/events: Fix race in set_evtchn_to_irq
+    - vsock/virtio: avoid potential deadlock when vsock device remove
+    - nbd: Aovid double completion of a request
+    - powerpc/kprobes: Fix kprobe Oops happens in booke
+    - x86/tools: Fix objdump version check again
+    - genirq: Provide IRQCHIP_AFFINITY_PRE_STARTUP
+    - x86/msi: Force affinity setup before startup
+    - x86/ioapic: Force affinity setup before startup
+    - x86/resctrl: Fix default monitoring groups reporting
+    - genirq/msi: Ensure deactivation on teardown
+    - genirq/timings: Prevent potential array overflow in __irq_timings_store()
+    - PCI/MSI: Enable and mask MSI-X early
+    - PCI/MSI: Mask all unused MSI-X entries
+    - PCI/MSI: Enforce that MSI-X table entry is masked for update
+    - PCI/MSI: Enforce MSI[X] entry updates to be visible
+    - PCI/MSI: Do not set invalid bits in MSI mask
+    - PCI/MSI: Correct misleading comments
+    - PCI/MSI: Use msi_mask_irq() in pci_msi_shutdown()
+    - PCI/MSI: Protect msi_desc::masked for multi-MSI
+    - KVM: VMX: Use current VMCS to query WAITPKG support for MSR emulation
+    - ceph: add some lockdep assertions around snaprealm handling
+    - ceph: clean up locking annotation for ceph_get_snap_realm and
+      __lookup_snap_realm
+    - ceph: take snap_empty_lock atomically with snaprealm refcount change
+    - vmlinux.lds.h: Handle clang's module.{c,d}tor sections
+    - iommu/vt-d: Fix agaw for a supported 48 bit guest address width
+    - Linux 5.4.142
+
+  * Focal update: v5.4.141 upstream stable release (LP: #1943484)
+    - KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB
+    - tee: Correct inappropriate usage of TEE_SHM_DMA_BUF flag
+    - media: v4l2-mem2mem: always consider OUTPUT queue during poll
+    - tracing: Reject string operand in the histogram expression
+    - usb: dwc3: Stop active transfers before halting the controller
+    - usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
+    - usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
+    - usb: dwc3: gadget: Prevent EP queuing while stopping transfers
+    - usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
+    - usb: dwc3: gadget: Disable gadget IRQ during pullup disable
+    - usb: dwc3: gadget: Avoid runtime resume if disabling pullup
+    - KVM: X86: MMU: Use the correct inherited permissions to get shadow page
+    - USB:ehci:fix Kunpeng920 ehci hardware problem
+    - ALSA: hda: Add quirk for ASUS Flow x13
+    - ppp: Fix generating ppp unit id when ifname is not specified
+    - ovl: prevent private clone if bind mount is not allowed
+    - btrfs: make qgroup_free_reserved_data take btrfs_inode
+    - btrfs: make btrfs_qgroup_reserve_data take btrfs_inode
+    - btrfs: qgroup: allow to unreserve range without releasing other ranges
+    - btrfs: qgroup: try to flush qgroup space when we get -EDQUOT
+    - btrfs: transaction: Cleanup unused TRANS_STATE_BLOCKED
+    - btrfs: qgroup: remove ASYNC_COMMIT mechanism in favor of reserve retry-
+      after-EDQUOT
+    - btrfs: fix lockdep splat when enabling and disabling qgroups
+    - net: xilinx_emaclite: Do not print real IOMEM pointer
+    - btrfs: qgroup: don't commit transaction when we already hold the handle
+    - btrfs: export and rename qgroup_reserve_meta
+    - btrfs: don't flush from btrfs_delayed_inode_reserve_metadata
+    - Linux 5.4.141
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 24 Sep 2021 15:50:10 +0200
+
+linux (5.4.0-88.99) focal; urgency=medium
+
+  * focal/linux: 5.4.0-88.99 -proposed tracker (LP: #1944747)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - Revert "UBUNTU: [Config] Disable virtualbox dkms build"
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Thu, 23 Sep 2021 10:40:49 -0600
+
+linux (5.4.0-87.98) focal; urgency=medium
+
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - [Config] Disable virtualbox dkms build
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+
+  *  LRMv5: switch primary version handling to kernel-versions data set
+    (LP: #1928921)
+    - [Packaging] switch to kernel-versions
+
+  * disable “CONFIG_HISI_DMA” config for ubuntu version (LP: #1936771)
+    - Disable CONFIG_HISI_DMA
+    - [Config] Record hisi_dma no longer built for arm64
+
+  * memory leaking when removing a profile (LP: #1939915)
+    - apparmor: Fix memory leak of profile proxy
+
+  * CryptoExpress EP11 cards are going offline (LP: #1939618)
+    - s390/zcrypt: Support for CCA protected key block version 2
+    - s390: Replace zero-length array with flexible-array member
+    - s390/zcrypt: Use scnprintf() for avoiding potential buffer overflow
+    - s390/zcrypt: replace snprintf/sprintf with scnprintf
+    - s390/ap: Remove ap device suspend and resume callbacks
+    - s390/zcrypt: use fallthrough;
+    - s390/zcrypt: use kvmalloc instead of kmalloc for 256k alloc
+    - s390/ap: remove power management code from ap bus and drivers
+    - s390/ap: introduce new ap function ap_get_qdev()
+    - s390/zcrypt: use kzalloc
+    - s390/zcrypt: fix smatch warnings
+    - s390/zcrypt: code beautification and struct field renames
+    - s390/zcrypt: split ioctl function into smaller code units
+    - s390/ap: rename and clarify ap state machine related stuff
+    - s390/zcrypt: provide cex4 cca sysfs attributes for cex3
+    - s390/ap: rework crypto config info and default domain code
+    - s390/zcrypt: simplify cca_findcard2 loop code
+    - s390/zcrypt: remove set_fs() invocation in zcrypt device driver
+    - s390/ap: remove unnecessary spin_lock_init()
+    - s390/zcrypt: Support for CCA APKA master keys
+    - s390/zcrypt: introduce msg tracking in zcrypt functions
+    - s390/ap: split ap queue state machine state from device state
+    - s390/ap: add error response code field for ap queue devices
+    - s390/ap: add card/queue deconfig state
+    - s390/sclp: Add support for SCLP AP adapter config/deconfig
+    - s390/ap: Support AP card SCLP config and deconfig operations
+    - s390/ap/zcrypt: revisit ap and zcrypt error handling
+    - s390/zcrypt: move ap_msg param one level up the call chain
+    - s390/zcrypt: Introduce Failure Injection feature
+    - s390/zcrypt: fix wrong format specifications
+    - s390/ap: fix ap devices reference counting
+    - s390/zcrypt: return EIO when msg retry limit reached
+    - s390/zcrypt: fix zcard and zqueue hot-unplug memleak
+    - s390/ap: Fix hanging ioctl caused by wrong msg counter
+
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (LP: #1926142)
+    - SAUCE: selftests/memfd: fix build when F_SEAL_FUTURE_WRITE is not defined
+
+  * [SRU] Ice driver causes the kernel to crash with Ubuntu 20.04.2 with ethtool
+    specific register commands (LP: #1939855)
+    - ice: Fix bad register reads
+
+  * ubunut_kernel_selftests: memory-hotplug: avoid spamming logs with
+    dump_page() (LP: #1941829)
+    - selftests: memory-hotplug: avoid spamming logs with dump_page(), ratio limit
+      hot-remove error test
+
+  * e1000e blocks the boot process when it tried to write checksum to its NVM
+    (LP: #1936998)
+    - e1000e: Do not take care about recovery NVM checksum
+
+  * Focal update: v5.4.140 upstream stable release (LP: #1941798)
+    - Revert "ACPICA: Fix memory leak caused by _CID repair function"
+    - ALSA: seq: Fix racy deletion of subscriber
+    - arm64: dts: ls1028a: fix node name for the sysclk
+    - ARM: imx: add missing iounmap()
+    - ARM: imx: add missing clk_disable_unprepare()
+    - ARM: dts: imx6qdl-sr-som: Increase the PHY reset duration to 10ms
+    - ARM: dts: colibri-imx6ull: limit SDIO clock to 25MHz
+    - ARM: imx: fix missing 3rd argument in macro imx_mmdc_perf_init
+    - ARM: dts: imx: Swap M53Menlo pinctrl_power_button/pinctrl_power_out pins
+    - arm64: dts: armada-3720-turris-mox: remove mrvl,i2c-fast-mode
+    - ALSA: usb-audio: fix incorrect clock source setting
+    - clk: stm32f4: fix post divisor setup for I2S/SAI PLLs
+    - ARM: dts: am437x-l4: fix typo in can@0 node
+    - omap5-board-common: remove not physically existing vdds_1v8_main fixed-
+      regulator
+    - spi: imx: mx51-ecspi: Reinstate low-speed CONFIGREG delay
+    - spi: imx: mx51-ecspi: Fix low-speed CONFIGREG delay calculation
+    - scsi: sr: Return correct event when media event code is 3
+    - media: videobuf2-core: dequeue if start_streaming fails
+    - dmaengine: imx-dma: configure the generic DMA type to make it work
+    - net, gro: Set inner transport header offset in tcp/udp GRO hook
+    - net: dsa: sja1105: overwrite dynamic FDB entries with static ones in
+      .port_fdb_add
+    - net: dsa: sja1105: invalidate dynamic FDB entries learned concurrently with
+      statically added ones
+    - net: phy: micrel: Fix detection of ksz87xx switch
+    - net: natsemi: Fix missing pci_disable_device() in probe and remove
+    - gpio: tqmx86: really make IRQ optional
+    - sctp: move the active_key update after sh_keys is added
+    - nfp: update ethtool reporting of pauseframe control
+    - net: ipv6: fix returned variable type in ip6_skb_dst_mtu
+    - mips: Fix non-POSIX regexp
+    - bnx2x: fix an error code in bnx2x_nic_load()
+    - net: pegasus: fix uninit-value in get_interrupt_interval
+    - net: fec: fix use-after-free in fec_drv_remove
+    - net: vxge: fix use-after-free in vxge_device_unregister
+    - blk-iolatency: error out if blk_get_queue() failed in iolatency_set_limit()
+    - Bluetooth: defer cleanup of resources in hci_unregister_dev()
+    - USB: usbtmc: Fix RCU stall warning
+    - USB: serial: option: add Telit FD980 composition 0x1056
+    - USB: serial: ch341: fix character loss at high transfer rates
+    - USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2
+    - firmware_loader: use -ETIMEDOUT instead of -EAGAIN in fw_load_sysfs_fallback
+    - firmware_loader: fix use-after-free in firmware_fallback_sysfs
+    - ALSA: hda/realtek: add mic quirk for Acer SF314-42
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 600
+    - usb: cdns3: Fixed incorrect gadget state
+    - usb: gadget: f_hid: added GET_IDLE and SET_IDLE handlers
+    - usb: gadget: f_hid: fixed NULL pointer dereference
+    - usb: gadget: f_hid: idle uses the highest byte for duration
+    - usb: otg-fsm: Fix hrtimer list corruption
+    - clk: fix leak on devm_clk_bulk_get_all() unwind
+    - scripts/tracing: fix the bug that can't parse raw_trace_func
+    - tracing / histogram: Give calculation hist_fields a size
+    - optee: Clear stale cache entries during initialization
+    - tee: add tee_shm_alloc_kernel_buf()
+    - optee: Fix memory leak when failing to register shm pages
+    - tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
+    - staging: rtl8723bs: Fix a resource leak in sd_int_dpc
+    - staging: rtl8712: get rid of flush_scheduled_work
+    - media: rtl28xxu: fix zero-length control request
+    - pipe: increase minimum default pipe size to 2 pages
+    - ext4: fix potential htree corruption when growing large_dir directories
+    - serial: tegra: Only print FIFO error message when an error occurs
+    - serial: 8250_mtk: fix uart corruption issue when rx power off
+    - serial: 8250: Mask out floating 16/32-bit bus bits
+    - MIPS: Malta: Do not byte-swap accesses to the CBUS UART
+    - serial: 8250_pci: Enumerate Elkhart Lake UARTs via dedicated driver
+    - serial: 8250_pci: Avoid irq sharing for MSI(-X) interrupts.
+    - timers: Move clearing of base::timer_running under base:: Lock
+    - pcmcia: i82092: fix a null pointer dereference bug
+    - md/raid10: properly indicate failure when ending a failed write request
+    - KVM: x86: accept userspace interrupt only if no event is injected
+    - KVM: Do not leak memory for duplicate debugfs directories
+    - KVM: x86/mmu: Fix per-cpu counter corruption on 32-bit builds
+    - arm64: vdso: Avoid ISB after reading from cntvct_el0
+    - soc: ixp4xx: fix printing resources
+    - spi: meson-spicc: fix memory leak in meson_spicc_remove
+    - soc: ixp4xx/qmgr: fix invalid __iomem access
+    - perf/x86/amd: Don't touch the AMD64_EVENTSEL_HOSTONLY bit inside the guest
+    - bpf, selftests: Adjust few selftest result_unpriv outcomes
+    - libata: fix ata_pio_sector for CONFIG_HIGHMEM
+    - reiserfs: add check for root_inode in reiserfs_fill_super
+    - reiserfs: check directory items on read from disk
+    - virt_wifi: fix error on connect
+    - alpha: Send stop IPI to send to online CPUs
+    - net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and
+      ql_adapter_reset
+    - arm64: fix compat syscall return truncation
+    - Linux 5.4.140
+
+  * Focal update: v5.4.139 upstream stable release (LP: #1941796)
+    - btrfs: delete duplicated words + other fixes in comments
+    - btrfs: do not commit logs and transactions during link and rename operations
+    - btrfs: fix race causing unnecessary inode logging during link and rename
+    - btrfs: fix lost inode on log replay after mix of fsync, rename and inode
+      eviction
+    - regulator: rt5033: Fix n_voltages settings for BUCK and LDO
+    - spi: stm32h7: fix full duplex irq handler handling
+    - ASoC: tlv320aic31xx: fix reversed bclk/wclk master bits
+    - r8152: Fix potential PM refcount imbalance
+    - qed: fix possible unpaired spin_{un}lock_bh in _qed_mcp_cmd_and_union()
+    - net: Fix zero-copy head len calculation.
+    - nvme: fix nvme_setup_command metadata trace event
+    - ACPI: fix NULL pointer dereference
+    - Revert "Bluetooth: Shutdown controller after workqueues are flushed or
+      cancelled"
+    - firmware: arm_scmi: Ensure drivers provide a probe function
+    - firmware: arm_scmi: Add delayed response status check
+    - bpf: Inherit expanded/patched seen count from old aux data
+    - bpf: Do not mark insn as seen under speculative path verification
+    - bpf: Fix leakage under speculation on mispredicted branches
+    - bpf: Test_verifier, add alu32 bounds tracking tests
+    - bpf, selftests: Add a verifier test for assigning 32bit reg states to 64bit
+      ones
+    - bpf, selftests: Adjust few selftest outcomes wrt unreachable code
+    - spi: mediatek: Fix fifo transfer
+    - Linux 5.4.139
+
+  * Focal update: v5.4.138 upstream stable release (LP: #1940559)
+    - net_sched: check error pointer in tcf_dump_walker()
+    - x86/asm: Ensure asm/proto.h can be included stand-alone
+    - btrfs: fix rw device counting in __btrfs_free_extra_devids
+    - btrfs: mark compressed range uptodate only if all bio succeed
+    - x86/kvm: fix vcpu-id indexed array sizes
+    - KVM: add missing compat KVM_CLEAR_DIRTY_LOG
+    - ocfs2: fix zero out valid data
+    - ocfs2: issue zeroout to EOF blocks
+    - can: j1939: j1939_xtp_rx_dat_one(): fix rxtimer value between consecutive
+      TP.DT to 750ms
+    - can: raw: raw_setsockopt(): fix raw_rcv panic for sock UAF
+    - can: mcba_usb_start(): add missing urb->transfer_dma initialization
+    - can: usb_8dev: fix memory leak
+    - can: ems_usb: fix memory leak
+    - can: esd_usb2: fix memory leak
+    - HID: wacom: Re-enable touch by default for Cintiq 24HDT / 27QHDT
+    - NIU: fix incorrect error return, missed in previous revert
+    - nfc: nfcsim: fix use after free during module unload
+    - cfg80211: Fix possible memory leak in function cfg80211_bss_update
+    - netfilter: conntrack: adjust stop timestamp to real expiry value
+    - netfilter: nft_nat: allow to specify layer 4 protocol NAT only
+    - i40e: Fix logic of disabling queues
+    - i40e: Fix firmware LLDP agent related warning
+    - i40e: Fix queue-to-TC mapping on Tx
+    - i40e: Fix log TC creation failure when max num of queues is exceeded
+    - tipc: fix sleeping in tipc accept routine
+    - net: Set true network header for ECN decapsulation
+    - mlx4: Fix missing error code in mlx4_load_one()
+    - net: llc: fix skb_over_panic
+    - net/mlx5: Fix flow table chaining
+    - net/mlx5e: Fix nullptr in mlx5e_hairpin_get_mdev()
+    - sctp: fix return value check in __sctp_rcv_asconf_lookup
+    - tulip: windbond-840: Fix missing pci_disable_device() in probe and remove
+    - sis900: Fix missing pci_disable_device() in probe and remove
+    - can: hi311x: fix a signedness bug in hi3110_cmd()
+    - PCI: mvebu: Setup BAR0 in order to fix MSI
+    - powerpc/pseries: Fix regression while building external modules
+    - i40e: Add additional info to PHY type error
+    - can: j1939: j1939_session_deactivate(): clarify lifetime of session object
+    - Linux 5.4.138
+
+  * Focal update: v5.4.137 upstream stable release (LP: #1940557)
+    - selftest: fix build error in tools/testing/selftests/vm/userfaultfd.c
+    - tools: Allow proper CC/CXX/... override with LLVM=1 in Makefile.include
+    - KVM: x86: determine if an exception has an error code only when injecting
+      it.
+    - af_unix: fix garbage collect vs MSG_PEEK
+    - workqueue: fix UAF in pwq_unbound_release_workfn()
+    - cgroup1: fix leaked context root causing sporadic NULL deref in LTP
+    - net/802/mrp: fix memleak in mrp_request_join()
+    - net/802/garp: fix memleak in garp_request_join()
+    - net: annotate data race around sk_ll_usec
+    - sctp: move 198 addresses from unusable to private scope
+    - ipv6: allocate enough headroom in ip6_finish_output2()
+    - hfs: add missing clean-up in hfs_fill_super
+    - hfs: fix high memory mapping in hfs_bnode_read
+    - hfs: add lock nesting notation to hfs_find_init
+    - firmware: arm_scmi: Fix possible scmi_linux_errmap buffer overflow
+    - firmware: arm_scmi: Fix range check for the maximum number of pending
+      messages
+    - cifs: fix the out of range assignment to bit fields in
+      parse_server_interfaces
+    - iomap: remove the length variable in iomap_seek_data
+    - iomap: remove the length variable in iomap_seek_hole
+    - ARM: dts: versatile: Fix up interrupt controller node names
+    - ipv6: ip6_finish_output2: set sk into newly allocated nskb
+    - Linux 5.4.137
+
+  * Focal update: v5.4.136 upstream stable release (LP: #1939899)
+    - igc: Fix use-after-free error during reset
+    - igb: Fix use-after-free error during reset
+    - igc: change default return of igc_read_phy_reg()
+    - ixgbe: Fix an error handling path in 'ixgbe_probe()'
+    - igc: Prefer to use the pci_release_mem_regions method
+    - igc: Fix an error handling path in 'igc_probe()'
+    - igb: Fix an error handling path in 'igb_probe()'
+    - fm10k: Fix an error handling path in 'fm10k_probe()'
+    - e1000e: Fix an error handling path in 'e1000_probe()'
+    - iavf: Fix an error handling path in 'iavf_probe()'
+    - igb: Check if num of q_vectors is smaller than max before array access
+    - igb: Fix position of assignment to *ring
+    - gve: Fix an error handling path in 'gve_probe()'
+    - ipv6: fix 'disable_policy' for fwd packets
+    - selftests: icmp_redirect: remove from checking for IPv6 route get
+    - selftests: icmp_redirect: IPv6 PMTU info should be cleared after redirect
+    - pwm: sprd: Ensure configuring period and duty_cycle isn't wrongly skipped
+    - cxgb4: fix IRQ free race during driver unload
+    - nvme-pci: do not call nvme_dev_remove_admin from nvme_remove
+    - perf probe: Fix dso->nsinfo refcounting
+    - perf env: Fix sibling_dies memory leak
+    - perf test session_topology: Delete session->evlist
+    - perf test event_update: Fix memory leak of evlist
+    - perf dso: Fix memory leak in dso__new_map()
+    - perf script: Fix memory 'threads' and 'cpus' leaks on exit
+    - perf lzma: Close lzma stream on exit
+    - perf probe-file: Delete namelist in del_events() on the error path
+    - perf data: Close all files in close_dir()
+    - spi: imx: add a check for speed_hz before calculating the clock
+    - spi: stm32: Use dma_request_chan() instead dma_request_slave_channel()
+    - spi: stm32: fixes pm_runtime calls in probe/remove
+    - regulator: hi6421: Use correct variable type for regmap api val argument
+    - regulator: hi6421: Fix getting wrong drvdata
+    - spi: mediatek: fix fifo rx mode
+    - ASoC: rt5631: Fix regcache sync errors on resume
+    - liquidio: Fix unintentional sign extension issue on left shift of u16
+    - s390/bpf: Perform r1 range checking before accessing jit->seen_reg[r1]
+    - bpf, sockmap, tcp: sk_prot needs inuse_idx set for proc stats
+    - bpftool: Check malloc return value in mount_bpffs_for_pin
+    - net: fix uninit-value in caif_seqpkt_sendmsg
+    - efi/tpm: Differentiate missing and invalid final event log table.
+    - net: decnet: Fix sleeping inside in af_decnet
+    - KVM: PPC: Book3S: Fix CONFIG_TRANSACTIONAL_MEM=n crash
+    - KVM: PPC: Fix kvm_arch_vcpu_ioctl vcpu_load leak
+    - net: sched: fix memory leak in tcindex_partial_destroy_work
+    - netrom: Decrease sock refcount when sock timers expire
+    - scsi: iscsi: Fix iface sysfs attr detection
+    - scsi: target: Fix protect handling in WRITE SAME(32)
+    - spi: cadence: Correct initialisation of runtime PM again
+    - bnxt_en: Improve bnxt_ulp_stop()/bnxt_ulp_start() call sequence.
+    - bnxt_en: Refresh RoCE capabilities in bnxt_ulp_probe()
+    - bnxt_en: Add missing check for BNXT_STATE_ABORT_ERR in bnxt_fw_rset_task()
+    - bnxt_en: Check abort error state in bnxt_half_open_nic()
+    - net: hisilicon: rename CACHE_LINE_MASK to avoid redefinition
+    - net/tcp_fastopen: fix data races around tfo_active_disable_stamp
+    - net: hns3: fix rx VLAN offload state inconsistent issue
+    - net/sched: act_skbmod: Skip non-Ethernet packets
+    - ipv6: fix another slab-out-of-bounds in fib6_nh_flush_exceptions
+    - nvme-pci: don't WARN_ON in nvme_reset_work if ctrl.state is not RESETTING
+    - Revert "USB: quirks: ignore remote wake-up on Fibocom L850-GL LTE modem"
+    - afs: Fix tracepoint string placement with built-in AFS
+    - r8169: Avoid duplicate sysfs entry creation error
+    - nvme: set the PRACT bit when using Write Zeroes with T10 PI
+    - sctp: update active_key for asoc when old key is being replaced
+    - net: sched: cls_api: Fix the the wrong parameter
+    - drm/panel: raspberrypi-touchscreen: Prevent double-free
+    - proc: Avoid mixing integer types in mem_rw()
+    - s390/ftrace: fix ftrace_update_ftrace_func implementation
+    - s390/boot: fix use of expolines in the DMA code
+    - ALSA: usb-audio: Add missing proc text entry for BESPOKEN type
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum headsets
+    - ALSA: sb: Fix potential ABBA deadlock in CSP driver
+    - ALSA: hdmi: Expose all pins on MSI MS-7C94 board
+    - xhci: Fix lost USB 2 remote wake
+    - KVM: PPC: Book3S: Fix H_RTAS rets buffer overflow
+    - KVM: PPC: Book3S HV Nested: Sanitise H_ENTER_NESTED TM state
+    - usb: hub: Disable USB 3 device initiated lpm if exit latency is too high
+    - usb: hub: Fix link power management max exit latency (MEL) calculations
+    - USB: usb-storage: Add LaCie Rugged USB3-FW to IGNORE_UAS
+    - usb: max-3421: Prevent corruption of freed memory
+    - usb: renesas_usbhs: Fix superfluous irqs happen after usb_pkt_pop()
+    - USB: serial: option: add support for u-blox LARA-R6 family
+    - USB: serial: cp210x: fix comments for GE CS1000
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - usb: dwc2: gadget: Fix sending zero length packet in DDMA mode.
+    - firmware/efi: Tell memblock about EFI iomem reservations
+    - tracing/histogram: Rename "cpu" to "common_cpu"
+    - tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
+    - btrfs: check for missing device in btrfs_trim_fs
+    - media: ngene: Fix out-of-bounds bug in ngene_command_config_free_buf()
+    - ixgbe: Fix packet corruption due to missing DMA sync
+    - selftest: use mmap instead of posix_memalign to allocate memory
+    - userfaultfd: do not untag user pointers
+    - hugetlbfs: fix mount mode command line processing
+    - rbd: don't hold lock_rwsem while running_list is being drained
+    - rbd: always kick acquire on "acquired" and "released" notifications
+    - nds32: fix up stack guard gap
+    - drm: Return -ENOTTY for non-drm ioctls
+    - net: dsa: mv88e6xxx: use correct .stats_set_histogram() on Topaz
+    - net: bcmgenet: ensure EXT_ENERGY_DET_MASK is clear
+    - iio: accel: bma180: Use explicit member assignment
+    - iio: accel: bma180: Fix BMA25x bandwidth register values
+    - btrfs: compression: don't try to compress if we don't have enough pages
+    - PCI: Mark AMD Navi14 GPU ATS as broken
+    - perf inject: Close inject.output on exit
+    - xhci: add xhci_get_virt_ep() helper
+    - Linux 5.4.136
+
+  * Focal update: v5.4.135 upstream stable release (LP: #1939442)
+    - ARM: dts: gemini: rename mdio to the right name
+    - ARM: dts: gemini: add device_type on pci
+    - ARM: dts: rockchip: fix pinctrl sleep nodename for rk3036-kylin and rk3288
+    - arm64: dts: rockchip: fix pinctrl sleep nodename for rk3399.dtsi
+    - ARM: dts: rockchip: Fix the timer clocks order
+    - ARM: dts: rockchip: Fix IOMMU nodes properties on rk322x
+    - ARM: dts: rockchip: Fix power-controller node names for rk3066a
+    - ARM: dts: rockchip: Fix power-controller node names for rk3188
+    - ARM: dts: rockchip: Fix power-controller node names for rk3288
+    - arm64: dts: rockchip: Fix power-controller node names for px30
+    - arm64: dts: rockchip: Fix power-controller node names for rk3328
+    - reset: ti-syscon: fix to_ti_syscon_reset_data macro
+    - ARM: brcmstb: dts: fix NAND nodes names
+    - ARM: Cygnus: dts: fix NAND nodes names
+    - ARM: NSP: dts: fix NAND nodes names
+    - ARM: dts: BCM63xx: Fix NAND nodes names
+    - ARM: dts: Hurricane 2: Fix NAND nodes names
+    - ARM: dts: imx6: phyFLEX: Fix UART hardware flow control
+    - ARM: imx: pm-imx5: Fix references to imx5_cpu_suspend_info
+    - rtc: mxc_v2: add missing MODULE_DEVICE_TABLE
+    - kbuild: sink stdout from cmd for silent build
+    - ARM: dts: am57xx-cl-som-am57x: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: am437x-gp-evm: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: stm32: fix gpio-keys node on STM32 MCU boards
+    - ARM: dts: stm32: fix RCC node name on stm32f429 MCU
+    - ARM: dts: stm32: fix timer nodes on STM32 MCU to prevent warnings
+    - arm64: dts: juno: Update SCPI nodes as per the YAML schema
+    - ARM: dts: rockchip: fix supply properties in io-domains nodes
+    - ARM: dts: stm32: fix i2c node name on stm32f746 to prevent warnings
+    - ARM: dts: stm32: move stmmac axi config in ethernet node on stm32mp15
+    - soc/tegra: fuse: Fix Tegra234-only builds
+    - firmware: tegra: bpmp: Fix Tegra234-only builds
+    - arm64: dts: ls208xa: remove bus-num from dspi node
+    - arm64: dts: imx8mq: assign PCIe clocks
+    - thermal/core: Correct function name thermal_zone_device_unregister()
+    - kbuild: mkcompile_h: consider timestamp if KBUILD_BUILD_TIMESTAMP is set
+    - rtc: max77686: Do not enforce (incorrect) interrupt trigger type
+    - scsi: aic7xxx: Fix unintentional sign extension issue on left shift of u8
+    - scsi: libsas: Add LUN number check in .slave_alloc callback
+    - scsi: libfc: Fix array index out of bound exception
+    - scsi: qedf: Add check to synchronize abort and flush
+    - sched/fair: Fix CFS bandwidth hrtimer expiry type
+    - s390: introduce proper type handling call_on_stack() macro
+    - cifs: prevent NULL deref in cifs_compose_mount_options()
+    - arm64: dts: armada-3720-turris-mox: add firmware node
+    - firmware: turris-mox-rwtm: add marvell,armada-3700-rwtm-firmware compatible
+      string
+    - arm64: dts: marvell: armada-37xx: move firmware node to generic dtsi file
+    - f2fs: Show casefolding support only when supported
+    - usb: cdns3: Enable TDL_CHK only for OUT ep
+    - Revert "UBUNTU: SAUCE: Revert "mm: memcg/slab: fix memory leak at non-root
+      kmem_cache destroy""
+    - mm: slab: fix kmem_cache_create failed when sysfs node not destroyed
+    - dm writecache: return the exact table values that were set
+    - net: dsa: mv88e6xxx: enable .port_set_policy() on Topaz
+    - net: dsa: mv88e6xxx: enable .rmu_disable() on Topaz
+    - net: ipv6: fix return value of ip6_skb_dst_mtu
+    - netfilter: ctnetlink: suspicious RCU usage in ctnetlink_dump_helpinfo
+    - net/sched: act_ct: fix err check for nf_conntrack_confirm
+    - net: bridge: sync fdb to new unicast-filtering ports
+    - net: bcmgenet: Ensure all TX/RX queues DMAs are disabled
+    - net: ip_tunnel: fix mtu calculation for ETHER tunnel devices
+    - net: moxa: fix UAF in moxart_mac_probe
+    - net: qcom/emac: fix UAF in emac_remove
+    - net: ti: fix UAF in tlan_remove_one
+    - net: send SYNACK packet with accepted fwmark
+    - net: validate lwtstate->data before returning from skb_tunnel_info()
+    - net: fddi: fix UAF in fza_probe
+    - dma-buf/sync_file: Don't leak fences on merge failure
+    - tcp: annotate data races around tp->mtu_info
+    - ipv6: tcp: drop silly ICMPv6 packet too big messages
+    - bpftool: Properly close va_list 'ap' by va_end() on error
+    - perf test bpf: Free obj_buf
+    - udp: annotate data races around unix_sk(sk)->gso_size
+    - Linux 5.4.135
+
+  * Focal update: v5.4.134 upstream stable release (LP: #1939440)
+    - KVM: mmio: Fix use-after-free Read in kvm_vm_ioctl_unregister_coalesced_mmio
+    - KVM: x86: Use guest MAXPHYADDR from CPUID.0x8000_0008 iff TDP is enabled
+    - KVM: X86: Disable hardware breakpoints unconditionally before kvm_x86->run()
+    - scsi: core: Fix bad pointer dereference when ehandler kthread is invalid
+    - tracing: Do not reference char * as a string in histograms
+    - cgroup: verify that source is a string
+    - fbmem: Do not delete the mode that is still in use
+    - net: moxa: Use devm_platform_get_and_ioremap_resource()
+    - dmaengine: fsl-qdma: check dma_set_mask return value
+    - srcu: Fix broken node geometry after early ssp init
+    - tty: serial: fsl_lpuart: fix the potential risk of division or modulo by
+      zero
+    - misc/libmasm/module: Fix two use after free in ibmasm_init_one
+    - misc: alcor_pci: fix null-ptr-deref when there is no PCI bridge
+    - iio: gyro: fxa21002c: Balance runtime pm + use pm_runtime_resume_and_get().
+    - iio: magn: bmc150: Balance runtime pm + use pm_runtime_resume_and_get()
+    - ALSA: usx2y: Don't call free_pages_exact() with NULL address
+    - Revert "ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro"
+    - w1: ds2438: fixing bug that would always get page0
+    - scsi: hisi_sas: Propagate errors in interrupt_init_v1_hw()
+    - scsi: lpfc: Fix "Unexpected timeout" error in direct attach topology
+    - scsi: lpfc: Fix crash when lpfc_sli4_hba_setup() fails to initialize the
+      SGLs
+    - scsi: core: Cap scsi_host cmd_per_lun at can_queue
+    - ALSA: ac97: fix PM reference leak in ac97_bus_remove()
+    - tty: serial: 8250: serial_cs: Fix a memory leak in error handling path
+    - scsi: scsi_dh_alua: Check for negative result value
+    - fs/jfs: Fix missing error code in lmLogInit()
+    - scsi: megaraid_sas: Fix resource leak in case of probe failure
+    - scsi: megaraid_sas: Early detection of VD deletion through RaidMap update
+    - scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs
+    - scsi: iscsi: Add iscsi_cls_conn refcount helpers
+    - scsi: iscsi: Fix conn use after free during resets
+    - scsi: iscsi: Fix shost->max_id use
+    - scsi: qedi: Fix null ref during abort handling
+    - mfd: da9052/stmpe: Add and modify MODULE_DEVICE_TABLE
+    - mfd: cpcap: Fix cpcap dmamask not set warnings
+    - ASoC: img: Fix PM reference leak in img_i2s_in_probe()
+    - serial: tty: uartlite: fix console setup
+    - s390/sclp_vt220: fix console name to match device
+    - ALSA: sb: Fix potential double-free of CSP mixer elements
+    - powerpc/ps3: Add dma_mask to ps3_dma_region
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak when arm_smmu_rpm_get
+      fails
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak in address translation
+    - gpio: zynq: Check return value of pm_runtime_get_sync
+    - ALSA: ppc: fix error return code in snd_pmac_probe()
+    - selftests/powerpc: Fix "no_handler" EBB selftest
+    - gpio: pca953x: Add support for the On Semi pca9655
+    - ASoC: soc-core: Fix the error return code in
+      snd_soc_of_parse_audio_routing()
+    - s390/processor: always inline stap() and __load_psw_mask()
+    - s390/ipl_parm: fix program check new psw handling
+    - s390/mem_detect: fix diag260() program check new psw handling
+    - s390/mem_detect: fix tprot() program check new psw handling
+    - Input: hideep - fix the uninitialized use in hideep_nvm_unlock()
+    - ALSA: bebob: add support for ToneWeal FW66
+    - ALSA: usb-audio: scarlett2: Fix 18i8 Gen 2 PCM Input count
+    - ALSA: usb-audio: scarlett2: Fix data_mutex lock
+    - ALSA: usb-audio: scarlett2: Fix scarlett2_*_ctl_put() return values
+    - usb: gadget: f_hid: fix endianness issue with descriptors
+    - usb: gadget: hid: fix error return code in hid_bind()
+    - powerpc/boot: Fixup device-tree on little endian
+    - ASoC: Intel: kbl_da7219_max98357a: shrink platform_id below 20 characters
+    - backlight: lm3630a: Fix return code of .update_status() callback
+    - ALSA: hda: Add IRQ check for platform_get_irq()
+    - ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions
+    - staging: rtl8723bs: fix macro value for 2.4Ghz only device
+    - intel_th: Wait until port is in reset before programming it
+    - i2c: core: Disable client irq on reboot/shutdown
+    - power: supply: sc27xx: Add missing MODULE_DEVICE_TABLE
+    - power: supply: sc2731_charger: Add missing MODULE_DEVICE_TABLE
+    - pwm: spear: Don't modify HW state in .remove callback
+    - power: supply: ab8500: Avoid NULL pointers
+    - power: supply: max17042: Do not enforce (incorrect) interrupt trigger type
+    - power: reset: gpio-poweroff: add missing MODULE_DEVICE_TABLE
+    - ARM: 9087/1: kprobes: test-thumb: fix for LLVM_IAS=1
+    - PCI/P2PDMA: Avoid pci_get_slot(), which may sleep
+    - watchdog: Fix possible use-after-free in wdt_startup()
+    - watchdog: sc520_wdt: Fix possible use-after-free in wdt_turnoff()
+    - watchdog: Fix possible use-after-free by calling del_timer_sync()
+    - watchdog: imx_sc_wdt: fix pretimeout
+    - x86/fpu: Return proper error codes from user access functions
+    - PCI: tegra: Add missing MODULE_DEVICE_TABLE
+    - orangefs: fix orangefs df output.
+    - ceph: remove bogus checks and WARN_ONs from ceph_set_page_dirty
+    - NFS: nfs_find_open_context() may only select open files
+    - power: supply: charger-manager: add missing MODULE_DEVICE_TABLE
+    - power: supply: ab8500: add missing MODULE_DEVICE_TABLE
+    - pwm: img: Fix PM reference leak in img_pwm_enable()
+    - pwm: tegra: Don't modify HW state in .remove callback
+    - ACPI: AMBA: Fix resource name in /proc/iomem
+    - ACPI: video: Add quirk for the Dell Vostro 3350
+    - virtio-blk: Fix memory leak among suspend/resume procedure
+    - virtio_net: Fix error handling in virtnet_restore()
+    - virtio_console: Assure used length from device is limited
+    - x86/signal: Detect and prevent an alternate signal stack overflow
+    - f2fs: add MODULE_SOFTDEP to ensure crc32 is included in the initramfs
+    - PCI/sysfs: Fix dsm_label_utf16s_to_utf8s() buffer overrun
+    - power: supply: rt5033_battery: Fix device tree enumeration
+    - NFSv4: Initialise connection to the server in nfs4_alloc_client()
+    - um: fix error return code in slip_open()
+    - um: fix error return code in winch_tramp()
+    - watchdog: aspeed: fix hardware timeout calculation
+    - nfs: fix acl memory leak of posix_acl_create()
+    - ubifs: Set/Clear I_LINKABLE under i_lock for whiteout inode
+    - PCI: iproc: Fix multi-MSI base vector number allocation
+    - PCI: iproc: Support multi-MSI only on uniprocessor kernel
+    - x86/fpu: Limit xstate copy size in xstateregs_set()
+    - pwm: imx1: Don't disable clocks at device remove time
+    - virtio_net: move tx vq operation under tx queue lock
+    - nvme-tcp: can't set sk_user_data without write_lock
+    - ALSA: isa: Fix error return code in snd_cmi8330_probe()
+    - NFSv4/pNFS: Don't call _nfs4_pnfs_v3_ds_connect multiple times
+    - hexagon: use common DISCARDS macro
+    - ARM: dts: gemini-rut1xx: remove duplicate ethernet node
+    - reset: a10sr: add missing of_match_table reference
+    - ARM: exynos: add missing of_node_put for loop iteration
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU/XU3
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid HC1
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU4
+    - memory: atmel-ebi: add missing of_node_put for loop iteration
+    - reset: brcmstb: Add missing MODULE_DEVICE_TABLE
+    - memory: pl353: Fix error return code in pl353_smc_probe()
+    - rtc: fix snprintf() checking in is_rtc_hctosys()
+    - arm64: dts: renesas: v3msk: Fix memory size
+    - ARM: dts: r8a7779, marzen: Fix DU clock names
+    - firmware: tegra: Fix error return code in tegra210_bpmp_init()
+    - firmware: arm_scmi: Reset Rx buffer to max size during async commands
+    - ARM: dts: BCM5301X: Fixup SPI binding
+    - reset: bail if try_module_get() fails
+    - memory: fsl_ifc: fix leak of IO mapping on probe failure
+    - memory: fsl_ifc: fix leak of private memory on probe failure
+    - ARM: dts: am335x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: am437x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: imx6q-dhcom: Fix ethernet reset time properties
+    - ARM: dts: imx6q-dhcom: Fix ethernet plugin detection problems
+    - ARM: dts: imx6q-dhcom: Add gpios pinctrl for i2c bus recovery
+    - thermal/drivers/rcar_gen3_thermal: Fix coefficient calculations
+    - firmware: turris-mox-rwtm: fix reply status decoding function
+    - firmware: turris-mox-rwtm: report failures better
+    - firmware: turris-mox-rwtm: fail probing when firmware does not support hwrng
+    - scsi: be2iscsi: Fix an error handling path in beiscsi_dev_probe()
+    - mips: always link byteswap helpers into decompressor
+    - mips: disable branch profiling in boot/decompress.o
+    - MIPS: vdso: Invalid GIC access through VDSO
+    - scsi: scsi_dh_alua: Fix signedness bug in alua_rtpg()
+    - misc: alcor_pci: fix inverted branch condition
+    - Linux 5.4.134
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 20 Sep 2021 21:38:19 +0200
+
+linux (5.4.0-86.97) focal; 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 15:35:09 -0300
+
+linux (5.4.0-84.94) focal; urgency=medium
+
+  * focal/linux: 5.4.0-84.94 -proposed tracker (LP: #1941767)
+
+  * Server boot failure after adding checks for ACPI IRQ override (LP: #1941657)
+    - Revert "ACPI: resources: Add checks for ACPI IRQ override"
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Thu, 26 Aug 2021 12:48:59 -0600
+
+linux (5.4.0-83.93) focal; urgency=medium
+
+  * focal/linux: 5.4.0-83.93 -proposed tracker (LP: #1940159)
+
+  * fails to launch linux L2 guests on AMD (LP: #1940134) // CVE-2021-3653
+    - KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+      (CVE-2021-3653)
+
+  * fails to launch linux L2 guests on AMD (LP: #1940134)
+    - SAUCE: Revert "UBUNTU: SAUCE: KVM: nSVM: avoid picking up unsupported bits
+      from L2 in int_ctl"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 17 Aug 2021 11:37:56 +0200
+
+linux (5.4.0-82.92) focal; urgency=medium
+
+  * focal/linux: 5.4.0-82.92 -proposed tracker (LP: #1939799)
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.08.16)
+
+  * CVE-2021-3656
+    - SAUCE: KVM: nSVM: always intercept VMLOAD/VMSAVE when nested
+
+  * CVE-2021-3653
+    - SAUCE: KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+
+  * [regression] USB device is not detected during boot (LP: #1939638)
+    - SAUCE: Revert "usb: core: reduce power-on-good delay time of root hub"
+
+  * dev_forward_skb: do not scrub skb mark within the same name space
+    (LP: #1935040)
+    - dev_forward_skb: do not scrub skb mark within the same name space
+
+  * XPS 9510 (TGL) Screen Brightness could not be changed (LP: #1933566)
+    - SAUCE: drm/i915: Force DPCD backlight mode for Dell XPS 9510(TGL)
+
+  * Acer Aspire 5 sound driver issues (LP: #1930188)
+    - ALSA: hda/realtek: headphone and mic don't work on an Acer laptop
+
+  * Sony Dualshock 4 usb dongle crashes the whole system (LP: #1935846)
+    - HID: sony: Workaround for DS4 dongle hotplug kernel crash.
+
+  * [21.10 FEAT] KVM: Provide a secure guest indication (LP: #1933173)
+    - s390/uv: add prot virt guest/host indication files
+    - s390/uv: fix prot virt host indication compilation
+
+  * Skip rtcpie test in kselftests/timers if the default RTC device does not
+    exist (LP: #1937991)
+    - selftests: timers: rtcpie: skip test if default RTC device does not exist
+
+  * Focal update: v5.4.133 upstream stable release (LP: #1938713)
+    - drm/mxsfb: Don't select DRM_KMS_FB_HELPER
+    - drm/zte: Don't select DRM_KMS_FB_HELPER
+    - drm/amd/amdgpu/sriov disable all ip hw status by default
+    - drm/vc4: fix argument ordering in vc4_crtc_get_margins()
+    - net: pch_gbe: Use proper accessors to BE data in pch_ptp_match()
+    - drm/amd/display: fix use_max_lb flag for 420 pixel formats
+    - hugetlb: clear huge pte during flush function on mips platform
+    - atm: iphase: fix possible use-after-free in ia_module_exit()
+    - mISDN: fix possible use-after-free in HFC_cleanup()
+    - atm: nicstar: Fix possible use-after-free in nicstar_cleanup()
+    - net: Treat __napi_schedule_irqoff() as __napi_schedule() on PREEMPT_RT
+    - drm/mediatek: Fix PM reference leak in mtk_crtc_ddp_hw_init()
+    - reiserfs: add check for invalid 1st journal block
+    - drm/virtio: Fix double free on probe failure
+    - drm/sched: Avoid data corruptions
+    - udf: Fix NULL pointer dereference in udf_symlink function
+    - e100: handle eeprom as little endian
+    - igb: handle vlan types with checker enabled
+    - drm/bridge: cdns: Fix PM reference leak in cdns_dsi_transfer()
+    - clk: renesas: r8a77995: Add ZA2 clock
+    - clk: tegra: Ensure that PLLU configuration is applied properly
+    - ipv6: use prandom_u32() for ID generation
+    - RDMA/cxgb4: Fix missing error code in create_qp()
+    - dm space maps: don't reset space map allocation cursor when committing
+    - pinctrl: mcp23s08: fix race condition in irq handler
+    - ice: set the value of global config lock timeout longer
+    - virtio_net: Remove BUG() to avoid machine dead
+    - net: bcmgenet: check return value after calling platform_get_resource()
+    - net: mvpp2: check return value after calling platform_get_resource()
+    - net: micrel: check return value after calling platform_get_resource()
+    - drm/amd/display: Update scaling settings on modeset
+    - drm/amd/display: Release MST resources on switch from MST to SST
+    - drm/amd/display: Set DISPCLK_MAX_ERRDET_CYCLES to 7
+    - drm/amdkfd: use allowed domain for vmbo validation
+    - fjes: check return value after calling platform_get_resource()
+    - selinux: use __GFP_NOWARN with GFP_NOWAIT in the AVC
+    - r8169: avoid link-up interrupt issue on RTL8106e if user enables ASPM
+    - drm/amd/display: Verify Gamma & Degamma LUT sizes in amdgpu_dm_atomic_check
+    - xfrm: Fix error reporting in xfrm_state_construct.
+    - wlcore/wl12xx: Fix wl12xx get_mac error if device is in ELP
+    - wl1251: Fix possible buffer overflow in wl1251_cmd_scan
+    - cw1200: add missing MODULE_DEVICE_TABLE
+    - bpf: Fix up register-based shifts in interpreter to silence KUBSAN
+    - mt76: mt7615: fix fixed-rate tx status reporting
+    - net: fix mistake path for netdev_features_strings
+    - net: sched: fix error return code in tcf_del_walker()
+    - drm/amdkfd: Walk through list with dqm lock hold
+    - rtl8xxxu: Fix device info for RTL8192EU devices
+    - atm: nicstar: use 'dma_free_coherent' instead of 'kfree'
+    - atm: nicstar: register the interrupt handler in the right place
+    - vsock: notify server to shutdown when client has pending signal
+    - RDMA/rxe: Don't overwrite errno from ib_umem_get()
+    - iwlwifi: mvm: don't change band on bound PHY contexts
+    - iwlwifi: pcie: free IML DMA memory allocation
+    - iwlwifi: pcie: fix context info freeing
+    - sfc: avoid double pci_remove of VFs
+    - sfc: error code if SRIOV cannot be disabled
+    - wireless: wext-spy: Fix out-of-bounds warning
+    - media, bpf: Do not copy more entries than user space requested
+    - net: ip: avoid OOM kills with large UDP sends over loopback
+    - RDMA/cma: Fix rdma_resolve_route() memory leak
+    - Bluetooth: btusb: Fixed too many in-token issue for Mediatek Chip.
+    - Bluetooth: Fix the HCI to MGMT status conversion table
+    - Bluetooth: Shutdown controller after workqueues are flushed or cancelled
+    - Bluetooth: btusb: fix bt fiwmare downloading failure issue for qca btsoc.
+    - sctp: validate from_addr_param return
+    - sctp: add size validation when walking chunks
+    - MIPS: loongsoon64: Reserve memory below starting pfn to prevent Oops
+    - MIPS: set mips32r5 for virt extensions
+    - fscrypt: don't ignore minor_hash when hash is 0
+    - crypto: ccp - Annotate SEV Firmware file names
+    - perf bench: Fix 2 memory sanitizer warnings
+    - powerpc/mm: Fix lockup on kernel exec fault
+    - powerpc/barrier: Avoid collision with clang's __lwsync macro
+    - drm/amdgpu: Update NV SIMD-per-CU to 2
+    - drm/radeon: Add the missed drm_gem_object_put() in
+      radeon_user_framebuffer_create()
+    - drm/rockchip: dsi: remove extra component_del() call
+    - drm/amd/display: fix incorrrect valid irq check
+    - pinctrl/amd: Add device HID for new AMD GPIO controller
+    - drm/tegra: Don't set allow_fb_modifiers explicitly
+    - drm/msm/mdp4: Fix modifier support enabling
+    - drm/arm/malidp: Always list modifiers
+    - mmc: sdhci: Fix warning message when accessing RPMB in HS400 mode
+    - mmc: core: clear flags before allowing to retune
+    - mmc: core: Allow UHS-I voltage switch for SDSC cards if supported
+    - ata: ahci_sunxi: Disable DIPM
+    - cpu/hotplug: Cure the cpusets trainwreck
+    - clocksource/arm_arch_timer: Improve Allwinner A64 timer workaround
+    - fpga: stratix10-soc: Add missing fpga_mgr_free() call
+    - MIPS: fix "mipsel-linux-ld: decompress.c:undefined reference to `memmove'"
+    - ASoC: tegra: Set driver_name=tegra for all machine drivers
+    - qemu_fw_cfg: Make fw_cfg_rev_attr a proper kobj_attribute
+    - ipmi/watchdog: Stop watchdog timer when the current action is 'none'
+    - thermal/drivers/int340x/processor_thermal: Fix tcc setting
+    - ubifs: Fix races between xattr_{set|get} and listxattr operations
+    - power: supply: ab8500: Fix an old bug
+    - nvmem: core: add a missing of_node_put
+    - extcon: intel-mrfld: Sync hardware and software state on init
+    - seq_buf: Fix overflow in seq_buf_putmem_hex()
+    - rq-qos: fix missed wake-ups in rq_qos_throttle try two
+    - tracing: Simplify & fix saved_tgids logic
+    - tracing: Resize tgid_map to pid_max, not PID_MAX_DEFAULT
+    - ipack/carriers/tpci200: Fix a double free in tpci200_pci_probe
+    - coresight: tmc-etf: Fix global-out-of-bounds in tmc_update_etf_buffer()
+    - dm btree remove: assign new_root only when removal succeeds
+    - PCI: Leave Apple Thunderbolt controllers on for s2idle or standby
+    - PCI: aardvark: Fix checking for PIO Non-posted Request
+    - PCI: aardvark: Implement workaround for the readback value of VEND_ID
+    - media: subdev: disallow ioctl for saa6588/davinci
+    - media: dtv5100: fix control-request directions
+    - media: zr364xx: fix memory leak in zr364xx_start_readpipe
+    - media: gspca/sq905: fix control-request direction
+    - media: gspca/sunplus: fix zero-length control requests
+    - pinctrl: mcp23s08: Fix missing unlock on error in mcp23s08_irq()
+    - jfs: fix GPF in diFree
+    - smackfs: restrict bytes count in smk_set_cipso()
+    - Linux 5.4.133
+
+  * Focal update: v5.4.132 upstream stable release (LP: #1938199)
+    - ALSA: usb-audio: fix rate on Ozone Z90 USB headset
+    - ALSA: usb-audio: Fix OOB access at proc output
+    - ALSA: usb-audio: scarlett2: Fix wrong resume call
+    - ALSA: intel8x0: Fix breakage at ac97 clock measurement
+    - ALSA: hda/realtek: Add another ALC236 variant support
+    - ALSA: hda/realtek: Improve fixup for HP Spectre x360 15-df0xxx
+    - ALSA: hda/realtek: Fix bass speaker DAC mapping for Asus UM431D
+    - ALSA: hda/realtek: Apply LED fixup for HP Dragonfly G1, too
+    - media: dvb-usb: fix wrong definition
+    - Input: usbtouchscreen - fix control-request directions
+    - net: can: ems_usb: fix use-after-free in ems_usb_disconnect()
+    - usb: gadget: eem: fix echo command packet response issue
+    - USB: cdc-acm: blacklist Heimann USB Appset device
+    - usb: dwc3: Fix debugfs creation flow
+    - usb: typec: Add the missed altmode_id_remove() in typec_register_altmode()
+    - xhci: solve a double free problem while doing s4
+    - ntfs: fix validity check for file name attribute
+    - copy_page_to_iter(): fix ITER_DISCARD case
+    - iov_iter_fault_in_readable() should do nothing in xarray case
+    - Input: joydev - prevent use of not validated data in JSIOCSBTNMAP ioctl
+    - arm_pmu: Fix write counter incorrect in ARMv7 big-endian mode
+    - ARM: dts: at91: sama5d4: fix pinctrl muxing
+    - btrfs: send: fix invalid path for unlink operations after parent
+      orphanization
+    - btrfs: clear defrag status of a root if starting transaction fails
+    - ext4: cleanup in-core orphan list if ext4_truncate() failed to get a
+      transaction handle
+    - ext4: fix kernel infoleak via ext4_extent_header
+    - ext4: return error code when ext4_fill_flex_info() fails
+    - ext4: correct the cache_nr in tracepoint ext4_es_shrink_exit
+    - ext4: remove check for zero nr_to_scan in ext4_es_scan()
+    - ext4: fix avefreec in find_group_orlov
+    - ext4: use ext4_grp_locked_error in mb_find_extent
+    - can: gw: synchronize rcu operations before removing gw job entry
+    - can: j1939: j1939_sk_init(): set SOCK_RCU_FREE to call sk_destruct() after
+      RCU is done
+    - can: peak_pciefd: pucan_handle_status(): fix a potential starvation issue in
+      TX path
+    - mac80211: remove iwlwifi specific workaround that broke sta NDP tx
+    - SUNRPC: Fix the batch tasks count wraparound.
+    - SUNRPC: Should wake up the privileged task firstly.
+    - perf/smmuv3: Don't trample existing events with global filter
+    - KVM: PPC: Book3S HV: Workaround high stack usage with clang
+    - s390/cio: dont call css_wait_for_slow_path() inside a lock
+    - rtc: stm32: Fix unbalanced clk_disable_unprepare() on probe error path
+    - iio: light: tcs3472: do not free unallocated IRQ
+    - iio: ltr501: mark register holding upper 8 bits of ALS_DATA{0,1} and PS_DATA
+      as volatile, too
+    - iio: ltr501: ltr559: fix initialization of LTR501_ALS_CONTR
+    - iio: ltr501: ltr501_read_ps(): add missing endianness conversion
+    - serial: mvebu-uart: fix calculation of clock divisor
+    - serial: sh-sci: Stop dmaengine transfer in sci_stop_tx()
+    - serial_cs: Add Option International GSM-Ready 56K/ISDN modem
+    - serial_cs: remove wrong GLOBETROTTER.cis entry
+    - ath9k: Fix kernel NULL pointer dereference during ath_reset_internal()
+    - ssb: sdio: Don't overwrite const buffer if block_write fails
+    - rsi: Assign beacon rate settings to the correct rate_info descriptor field
+    - rsi: fix AP mode with WPA failure due to encrypted EAPOL
+    - tracing/histograms: Fix parsing of "sym-offset" modifier
+    - tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing
+    - seq_buf: Make trace_seq_putmem_hex() support data longer than 8
+    - powerpc/stacktrace: Fix spurious "stale" traces in raise_backtrace_ipi()
+    - evm: Execute evm_inode_init_security() only when an HMAC key is loaded
+    - evm: Refuse EVM_ALLOW_METADATA_WRITES only if an HMAC key is loaded
+    - fuse: ignore PG_workingset after stealing
+    - fuse: check connected before queueing on fpq->io
+    - fuse: reject internal errno
+    - spi: Make of_register_spi_device also set the fwnode
+    - media: mdk-mdp: fix pm_runtime_get_sync() usage count
+    - media: s5p: fix pm_runtime_get_sync() usage count
+    - media: sh_vou: fix pm_runtime_get_sync() usage count
+    - media: mtk-vcodec: fix PM runtime get logic
+    - media: s5p-jpeg: fix pm_runtime_get_sync() usage count
+    - media: sti/bdisp: fix pm_runtime_get_sync() usage count
+    - media: exynos-gsc: fix pm_runtime_get_sync() usage count
+    - spi: spi-loopback-test: Fix 'tx_buf' might be 'rx_buf'
+    - spi: spi-topcliff-pch: Fix potential double free in
+      pch_spi_process_messages()
+    - spi: omap-100k: Fix the length judgment problem
+    - regulator: uniphier: Add missing MODULE_DEVICE_TABLE
+    - hwrng: exynos - Fix runtime PM imbalance on error
+    - crypto: nx - add missing MODULE_DEVICE_TABLE
+    - media: sti: fix obj-$(config) targets
+    - media: cpia2: fix memory leak in cpia2_usb_probe
+    - media: cobalt: fix race condition in setting HPD
+    - media: pvrusb2: fix warning in pvr2_i2c_core_done
+    - media: imx: imx7_mipi_csis: Fix logging of only error event counters
+    - crypto: qat - check return code of qat_hal_rd_rel_reg()
+    - crypto: qat - remove unused macro in FW loader
+    - sched/fair: Fix ascii art by relpacing tabs
+    - media: em28xx: Fix possible memory leak of em28xx struct
+    - media: v4l2-core: Avoid the dangling pointer in v4l2_fh_release
+    - media: bt8xx: Fix a missing check bug in bt878_probe
+    - media: st-hva: Fix potential NULL pointer dereferences
+    - Makefile: fix GDB warning with CONFIG_RELR
+    - media: dvd_usb: memory leak in cinergyt2_fe_attach
+    - memstick: rtsx_usb_ms: fix UAF
+    - mmc: sdhci-sprd: use sdhci_sprd_writew
+    - mmc: via-sdmmc: add a check against NULL pointer dereference
+    - crypto: shash - avoid comparing pointers to exported functions under CFI
+    - media: dvb_net: avoid speculation from net slot
+    - media: siano: fix device register error path
+    - media: imx-csi: Skip first few frames from a BT.656 source
+    - hwmon: (max31790) Report correct current pwm duty cycles
+    - hwmon: (max31790) Fix pwmX_enable attributes
+    - drivers/perf: fix the missed ida_simple_remove() in ddr_perf_probe()
+    - KVM: PPC: Book3S HV: Fix TLB management on SMT8 POWER9 and POWER10
+      processors
+    - btrfs: fix error handling in __btrfs_update_delayed_inode
+    - btrfs: abort transaction if we fail to update the delayed inode
+    - btrfs: disable build on platforms having page size 256K
+    - locking/lockdep: Fix the dep path printing for backwards BFS
+    - lockding/lockdep: Avoid to find wrong lock dep path in check_irq_usage()
+    - KVM: s390: get rid of register asm usage
+    - regulator: mt6358: Fix vdram2 .vsel_mask
+    - regulator: da9052: Ensure enough delay time for .set_voltage_time_sel
+    - media: Fix Media Controller API config checks
+    - HID: do not use down_interruptible() when unbinding devices
+    - EDAC/ti: Add missing MODULE_DEVICE_TABLE
+    - ACPI: processor idle: Fix up C-state latency if not ordered
+    - hv_utils: Fix passing zero to 'PTR_ERR' warning
+    - lib: vsprintf: Fix handling of number field widths in vsscanf
+    - ACPI: EC: Make more Asus laptops use ECDT _GPE
+    - block_dump: remove block_dump feature in mark_inode_dirty()
+    - fs: dlm: cancel work sync othercon
+    - random32: Fix implicit truncation warning in prandom_seed_state()
+    - fs: dlm: fix memory leak when fenced
+    - ACPICA: Fix memory leak caused by _CID repair function
+    - ACPI: bus: Call kobject_put() in acpi_init() error path
+    - block: fix race between adding/removing rq qos and normal IO
+    - platform/x86: toshiba_acpi: Fix missing error code in
+      toshiba_acpi_setup_keyboard()
+    - nvmet-fc: do not check for invalid target port in nvmet_fc_handle_fcp_rqst()
+    - EDAC/Intel: Do not load EDAC driver when running as a guest
+    - PCI: hv: Add check for hyperv_initialized in init_hv_pci_drv()
+    - clocksource: Retry clock read if long delays detected
+    - ACPI: tables: Add custom DSDT file as makefile prerequisite
+    - HID: wacom: Correct base usage for capacitive ExpressKey status bits
+    - cifs: fix missing spinlock around update to ses->status
+    - block: fix discard request merge
+    - kthread_worker: fix return value when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - ia64: mca_drv: fix incorrect array size calculation
+    - writeback, cgroup: increment isw_nr_in_flight before grabbing an inode
+    - media: s5p_cec: decrement usage count if disabled
+    - crypto: ixp4xx - dma_unmap the correct address
+    - crypto: ux500 - Fix error return code in hash_hw_final()
+    - sata_highbank: fix deferred probing
+    - pata_rb532_cf: fix deferred probing
+    - media: I2C: change 'RST' to "RSET" to fix multiple build errors
+    - sched/uclamp: Fix wrong implementation of cpu.uclamp.min
+    - sched/uclamp: Fix locking around cpu_util_update_eff()
+    - kbuild: run the checker after the compiler
+    - kbuild: Fix objtool dependency for 'OBJECT_FILES_NON_STANDARD_<obj> := n'
+    - pata_octeon_cf: avoid WARN_ON() in ata_host_activate()
+    - evm: fix writing <securityfs>/evm overflow
+    - crypto: ccp - Fix a resource leak in an error handling path
+    - media: rc: i2c: Fix an error message
+    - pata_ep93xx: fix deferred probing
+    - media: exynos4-is: Fix a use after free in isp_video_release
+    - media: au0828: fix a NULL vs IS_ERR() check
+    - media: tc358743: Fix error return code in tc358743_probe_of()
+    - media: gspca/gl860: fix zero-length control requests
+    - m68k: atari: Fix ATARI_KBD_CORE kconfig unmet dependency warning
+    - media: siano: Fix out-of-bounds warnings in smscore_load_firmware_family2()
+    - crypto: nitrox - fix unchecked variable in nitrox_register_interrupts
+    - crypto: omap-sham - Fix PM reference leak in omap sham ops
+    - mmc: usdhi6rol0: fix error return code in usdhi6_probe()
+    - arm64: consistently use reserved_pg_dir
+    - arm64/mm: Fix ttbr0 values stored in struct thread_info for software-pan
+    - media: s5p-g2d: Fix a memory leak on ctx->fh.m2m_ctx
+    - hwmon: (max31722) Remove non-standard ACPI device IDs
+    - hwmon: (max31790) Fix fan speed reporting for fan7..12
+    - KVM: nVMX: Ensure 64-bit shift when checking VMFUNC bitmap
+    - regulator: hi655x: Fix pass wrong pointer to config.driver_data
+    - btrfs: clear log tree recovering status if starting transaction fails
+    - sched/rt: Fix RT utilization tracking during policy change
+    - sched/rt: Fix Deadline utilization tracking during policy change
+    - sched/uclamp: Fix uclamp_tg_restrict()
+    - spi: spi-sun6i: Fix chipselect/clock bug
+    - crypto: nx - Fix RCU warning in nx842_OF_upd_status
+    - ACPI: sysfs: Fix a buffer overrun problem with description_show()
+    - extcon: extcon-max8997: Fix IRQ freeing at error path
+    - blk-wbt: introduce a new disable state to prevent false positive by
+      rwb_enabled()
+    - blk-wbt: make sure throttle is enabled properly
+    - ACPI: Use DEVICE_ATTR_<RW|RO|WO> macros
+    - ACPI: bgrt: Fix CFI violation
+    - cpufreq: Make cpufreq_online() call driver->offline() on errors
+    - ocfs2: fix snprintf() checking
+    - dax: fix ENOMEM handling in grab_mapping_entry()
+    - xfrm: xfrm_state_mtu should return at least 1280 for ipv6
+    - video: fbdev: imxfb: Fix an error message
+    - net: mvpp2: Put fwnode in error case during ->probe()
+    - net: pch_gbe: Propagate error from devm_gpio_request_one()
+    - pinctrl: renesas: r8a7796: Add missing bias for PRESET# pin
+    - pinctrl: renesas: r8a77990: JTAG pins do not have pull-down capabilities
+    - clk: meson: g12a: fix gp0 and hifi ranges
+    - net: ftgmac100: add missing error return code in ftgmac100_probe()
+    - drm/rockchip: cdn-dp-core: add missing clk_disable_unprepare() on error in
+      cdn_dp_grf_write()
+    - drm/rockchip: dsi: move all lane config except LCDC mux to bind()
+    - ehea: fix error return code in ehea_restart_qps()
+    - net/sched: act_vlan: Fix modify to allow 0
+    - RDMA/core: Sanitize WQ state received from the userspace
+    - RDMA/rxe: Fix failure during driver load
+    - drm: qxl: ensure surf.data is ininitialized
+    - tools/bpftool: Fix error return code in do_batch()
+    - ath10k: go to path err_unsupported when chip id is not supported
+    - ath10k: add missing error return code in ath10k_pci_probe()
+    - wireless: carl9170: fix LEDS build errors & warnings
+    - ieee802154: hwsim: Fix possible memory leak in hwsim_subscribe_all_others
+    - wcn36xx: Move hal_buf allocation to devm_kmalloc in probe
+    - ssb: Fix error return code in ssb_bus_scan()
+    - brcmfmac: fix setting of station info chains bitmask
+    - brcmfmac: correctly report average RSSI in station info
+    - brcmsmac: mac80211_if: Fix a resource leak in an error handling path
+    - ath10k: Fix an error code in ath10k_add_interface()
+    - netlabel: Fix memory leak in netlbl_mgmt_add_common
+    - RDMA/mlx5: Don't add slave port to unaffiliated list
+    - netfilter: nft_exthdr: check for IPv6 packet before further processing
+    - netfilter: nft_osf: check for TCP packet before further processing
+    - netfilter: nft_tproxy: restrict support to TCP and UDP transport protocols
+    - RDMA/rxe: Fix qp reference counting for atomic ops
+    - samples/bpf: Fix the error return code of xdp_redirect's main()
+    - net: ethernet: aeroflex: fix UAF in greth_of_remove
+    - net: ethernet: ezchip: fix UAF in nps_enet_remove
+    - net: ethernet: ezchip: fix error handling
+    - vrf: do not push non-ND strict packets with a source LLA through packet taps
+      again
+    - net: sched: add barrier to ensure correct ordering for lockless qdisc
+    - tls: prevent oversized sendfile() hangs by ignoring MSG_MORE
+    - pkt_sched: sch_qfq: fix qfq_change_class() error path
+    - vxlan: add missing rcu_read_lock() in neigh_reduce()
+    - net/ipv4: swap flow ports when validating source
+    - tc-testing: fix list handling
+    - ieee802154: hwsim: Fix memory leak in hwsim_add_one
+    - ieee802154: hwsim: avoid possible crash in hwsim_del_edge_nl()
+    - mac80211: remove iwlwifi specific workaround NDPs of null_response
+    - net: bcmgenet: Fix attaching to PYH failed on RPi 4B
+    - ipv6: exthdrs: do not blindly use init_net
+    - bpf: Do not change gso_size during bpf_skb_change_proto()
+    - i40e: Fix error handling in i40e_vsi_open
+    - i40e: Fix autoneg disabling for non-10GBaseT links
+    - Revert "ibmvnic: remove duplicate napi_schedule call in open function"
+    - ibmvnic: free tx_pool if tso_pool alloc fails
+    - ipv6: fix out-of-bound access in ip6_parse_tlv()
+    - e1000e: Check the PCIm state
+    - bpfilter: Specify the log level for the kmsg message
+    - gve: Fix swapped vars when fetching max queues
+    - Revert "be2net: disable bh with spin_lock in be_process_mcc"
+    - Bluetooth: mgmt: Fix slab-out-of-bounds in tlv_data_is_valid
+    - Bluetooth: Fix handling of HCI_LE_Advertising_Set_Terminated event
+    - clk: actions: Fix UART clock dividers on Owl S500 SoC
+    - clk: actions: Fix SD clocks factor table on Owl S500 SoC
+    - clk: actions: Fix bisp_factor_table based clocks on Owl S500 SoC
+    - clk: si5341: Avoid divide errors due to bogus register contents
+    - clk: si5341: Update initialization magic
+    - writeback: fix obtain a reference to a freeing memcg css
+    - net: lwtunnel: handle MTU calculation in forwading
+    - net: sched: fix warning in tcindex_alloc_perfect_hash
+    - RDMA/mlx5: Don't access NULL-cleared mpi pointer
+    - MIPS: Fix PKMAP with 32-bit MIPS huge page support
+    - staging: fbtft: Rectify GPIO handling
+    - rcu: Invoke rcu_spawn_core_kthreads() from rcu_spawn_gp_kthread()
+    - tty: nozomi: Fix a resource leak in an error handling function
+    - mwifiex: re-fix for unaligned accesses
+    - iio: adis_buffer: do not return ints in irq handlers
+    - iio: adis16400: do not return ints in irq handlers
+    - iio: accel: bma180: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: bma220: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: hid: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: kxcjk-1013: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio:accel:mxc4005: Drop unnecessary explicit casts in regmap_bulk_read calls
+    - iio: accel: mxc4005: Fix overread of data and alignment issue.
+    - iio: accel: stk8312: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: stk8ba50: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads1015: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: vf610: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: gyro: bmg160: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: humidity: am2315: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: srf08: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: pulsed-light: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: as3935: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: hmc5843: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: bmc150: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: isl29125: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3414: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3472: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: cros_ec_sensors: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: potentiostat: lmp91000: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: rk3328: fix missing clk_disable_unprepare() on error in
+      rk3328_platform_probe()
+    - ASoC: hisilicon: fix missing clk_disable_unprepare() on error in
+      hi6210_i2s_startup()
+    - backlight: lm3630a_bl: Put fwnode in error case during ->probe()
+    - ASoC: rsnd: tidyup loop on rsnd_adg_clk_query()
+    - Input: hil_kbd - fix error return code in hil_dev_connect()
+    - mtd: partitions: redboot: seek fis-index-block in the right node
+    - char: pcmcia: error out if 'num_bytes_read' is greater than 4 in
+      set_protocol()
+    - firmware: stratix10-svc: Fix a resource leak in an error handling path
+    - tty: nozomi: Fix the error handling path of 'nozomi_card_init()'
+    - leds: lm3532: select regmap I2C API
+    - leds: lm36274: cosmetic: rename lm36274_data to chip
+    - leds: lm3692x: Put fwnode in any case during ->probe()
+    - scsi: FlashPoint: Rename si_flags field
+    - fsi: core: Fix return of error values on failures
+    - fsi: scom: Reset the FSI2PIB engine for any error
+    - fsi: occ: Don't accept response from un-initialized OCC
+    - fsi/sbefifo: Clean up correct FIFO when receiving reset request from SBE
+    - fsi/sbefifo: Fix reset timeout
+    - visorbus: fix error return code in visorchipset_init()
+    - s390: appldata depends on PROC_SYSCTL
+    - iommu/dma: Fix IOVA reserve dma ranges
+    - ASoC: mediatek: mtk-btcvsd: Fix an error handling path in
+      'mtk_btcvsd_snd_probe()'
+    - usb: gadget: f_fs: Fix setting of device and driver data cross-references
+    - usb: dwc2: Don't reset the core after setting turnaround time
+    - eeprom: idt_89hpesx: Put fwnode in matching case during ->probe()
+    - eeprom: idt_89hpesx: Restore printing the unsupported fwnode name
+    - iio: at91-sama5d2_adc: remove usage of iio_priv_to_dev() helper
+    - iio: adc: at91-sama5d2: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: hx711: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: mxs-lradc: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads8688: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: rm3100: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - staging: gdm724x: check for buffer overflow in gdm_lte_multi_sdu_pkt()
+    - staging: gdm724x: check for overflow in gdm_lte_netif_rx()
+    - staging: rtl8712: remove redundant check in r871xu_drv_init
+    - staging: rtl8712: fix memory leak in rtl871x_load_fw_cb
+    - staging: mt7621-dts: fix pci address for PCI memory range
+    - serial: 8250: Actually allow UPF_MAGIC_MULTIPLIER baud rates
+    - iio: light: vcnl4035: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: isl29501: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: cs42l42: Correct definition of CS42L42_ADC_PDN_MASK
+    - of: Fix truncation of memory sizes on 32-bit platforms
+    - mtd: rawnand: marvell: add missing clk_disable_unprepare() on error in
+      marvell_nfc_resume()
+    - scsi: mpt3sas: Fix error return value in _scsih_expander_add()
+    - soundwire: stream: Fix test for DP prepare complete
+    - phy: uniphier-pcie: Fix updating phy parameters
+    - phy: ti: dm816x: Fix the error handling path in 'dm816x_usb_phy_probe()
+    - extcon: sm5502: Drop invalid register write in sm5502_reg_data
+    - extcon: max8997: Add missing modalias string
+    - ASoC: atmel-i2s: Fix usage of capture and playback at the same time
+    - configfs: fix memleak in configfs_release_bin_file
+    - leds: as3645a: Fix error return code in as3645a_parse_node()
+    - leds: ktd2692: Fix an error handling path
+    - powerpc: Offline CPU in stop_this_cpu()
+    - serial: mvebu-uart: do not allow changing baudrate when uartclk is not
+      available
+    - serial: mvebu-uart: correctly calculate minimal possible baudrate
+    - arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
+    - vfio/pci: Handle concurrent vma faults
+    - mm/huge_memory.c: don't discard hugepage if other processes are mapping it
+    - mm/z3fold: fix potential memory leak in z3fold_destroy_pool()
+    - selftests/vm/pkeys: fix alloc_random_pkey() to make it really, really random
+    - perf llvm: Return -ENOMEM when asprintf() fails
+    - scsi: target: cxgbit: Unmap DMA buffer before calling target_execute_cmd()
+    - mmc: block: Disable CMDQ on the ioctl path
+    - mmc: vub3000: fix control-request direction
+    - scsi: core: Retry I/O for Notify (Enable Spinup) Required error
+    - iommu/dma: Fix compile warning in 32-bit builds
+    - Linux 5.4.132
+
+  * Keyboard not working (LP: #1909814) // Focal update: v5.4.132 upstream
+    stable release (LP: #1938199)
+    - ACPI: resources: Add checks for ACPI IRQ override
+
+  * Focal update: v5.4.131 upstream stable release (LP: #1936245)
+    - KVM: SVM: Periodically schedule when unregistering regions on destroy
+    - s390/stack: fix possible register corruption with stack switch helper
+    - KVM: SVM: Call SEV Guest Decommission if ASID binding fails
+    - xen/events: reset active flag for lateeoi events later
+    - Linux 5.4.131
+
+  * Focal update: v5.4.130 upstream stable release (LP: #1936244)
+    - scsi: sr: Return appropriate error code when disk is ejected
+    - drm/nouveau: fix dma_address check for CPU/GPU sync
+    - gpio: AMD8111 and TQMX86 require HAS_IOPORT_MAP
+    - RDMA/mlx5: Block FDB rules when not in switchdev mode
+    - Linux 5.4.130
+
+  * Focal update: v5.4.129 upstream stable release (LP: #1936242)
+    - module: limit enabling module.sig_enforce
+    - drm/nouveau: wait for moving fence after pinning v2
+    - drm/radeon: wait for moving fence after pinning
+    - ARM: 9081/1: fix gcc-10 thumb2-kernel regression
+    - mmc: meson-gx: use memcpy_to/fromio for dram-access-quirk
+    - kbuild: add CONFIG_LD_IS_LLD
+    - arm64: link with -z norelro for LLD or aarch64-elf
+    - MIPS: generic: Update node names to avoid unit addresses
+    - spi: spi-nxp-fspi: move the register operation after the clock enable
+    - Revert "PCI: PM: Do not read power state in pci_enable_device_flags()"
+    - dmaengine: zynqmp_dma: Fix PM reference leak in
+      zynqmp_dma_alloc_chan_resourc()
+    - mac80211: remove warning in ieee80211_get_sband()
+    - mac80211_hwsim: drop pending frames on stop
+    - cfg80211: call cfg80211_leave_ocb when switching away from OCB
+    - dmaengine: rcar-dmac: Fix PM reference leak in rcar_dmac_probe()
+    - dmaengine: mediatek: free the proper desc in desc_free handler
+    - dmaengine: mediatek: do not issue a new desc if one is still current
+    - dmaengine: mediatek: use GFP_NOWAIT instead of GFP_ATOMIC in prep_dma
+    - net: ipv4: Remove unneed BUG() function
+    - mac80211: drop multicast fragments
+    - net: ethtool: clear heap allocations for ethtool function
+    - ping: Check return value of function 'ping_queue_rcv_skb'
+    - inet: annotate date races around sk->sk_txhash
+    - net: phy: dp83867: perform soft reset and retain established link
+    - net: caif: fix memory leak in ldisc_open
+    - net/packet: annotate accesses to po->bind
+    - net/packet: annotate accesses to po->ifindex
+    - r8152: Avoid memcpy() over-reading of ETH_SS_STATS
+    - sh_eth: Avoid memcpy() over-reading of ETH_SS_STATS
+    - r8169: Avoid memcpy() over-reading of ETH_SS_STATS
+    - KVM: selftests: Fix kvm_check_cap() assertion
+    - net: qed: Fix memcpy() overflow of qed_dcbx_params()
+    - recordmcount: Correct st_shndx handling
+    - PCI: Add AMD RS690 quirk to enable 64-bit DMA
+    - net: ll_temac: Add memory-barriers for TX BD access
+    - net: ll_temac: Avoid ndo_start_xmit returning NETDEV_TX_BUSY
+    - pinctrl: stm32: fix the reported number of GPIO lines per bank
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_device_group
+    - KVM: do not allow mapping valid but non-reference-counted pages
+    - i2c: robotfuzz-osif: fix control-request directions
+    - kthread_worker: split code for canceling the delayed work timer
+    - kthread: prevent deadlock when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - mm: add VM_WARN_ON_ONCE_PAGE() macro
+    - mm/rmap: remove unneeded semicolon in page_not_mapped()
+    - mm/rmap: use page_not_mapped in try_to_unmap()
+    - mm, thp: use head page in __migration_entry_wait()
+    - mm/thp: fix __split_huge_pmd_locked() on shmem migration entry
+    - mm/thp: make is_huge_zero_pmd() safe and quicker
+    - mm/thp: try_to_unmap() use TTU_SYNC for safe splitting
+    - mm/thp: fix vma_address() if virtual address below file offset
+    - mm/thp: fix page_address_in_vma() on file THP tails
+    - mm/thp: unmap_mapping_page() to fix THP truncate_cleanup_page()
+    - mm: thp: replace DEBUG_VM BUG with VM_WARN when unmap fails for split
+    - mm: page_vma_mapped_walk(): use page for pvmw->page
+    - mm: page_vma_mapped_walk(): settle PageHuge on entry
+    - mm: page_vma_mapped_walk(): use pmde for *pvmw->pmd
+    - mm: page_vma_mapped_walk(): prettify PVMW_MIGRATION block
+    - mm: page_vma_mapped_walk(): crossing page table boundary
+    - mm: page_vma_mapped_walk(): add a level of indentation
+    - mm: page_vma_mapped_walk(): use goto instead of while (1)
+    - mm: page_vma_mapped_walk(): get vma_address_end() earlier
+    - mm/thp: fix page_vma_mapped_walk() if THP mapped by ptes
+    - mm/thp: another PVMW_SYNC fix in page_vma_mapped_walk()
+    - mm, futex: fix shared futex pgoff on shmem huge page
+    - [Config] enable CONFIG_SYSTEM_REVOCATION_LIST
+    - certs: Add EFI_CERT_X509_GUID support for dbx entries
+    - certs: Move load_system_certificate_list to a common function
+    - Linux 5.4.129
+
+  * Patch To Fix Bug in the Linux Block Layer Responsible For  Merging BIOs
+    (LP: #1931497)
+    - block: return the correct bvec when checking for gaps
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 13 Aug 2021 11:58:48 +0200
+
+linux (5.4.0-81.91) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * large_dir in ext4 broken (LP: #1933074)
+    - SAUCE: ext4: fix directory index node split corruption
+
+  * Some test in kselftest/net on focal source tree were not tested at all
+    (LP: #1934282)
+    - selftests/net: add missing tests to Makefile
+
+  * curtin: install flash-kernel in arm64 UEFI unexpected (LP: #1918427)
+    - [Packaging] Allow grub-efi-arm* to satisfy recommends on ARM
+
+  * Add l2tp.sh in net from ubuntu_kernel_selftests back (LP: #1934293)
+    - Revert "UBUNTU: SAUCE: selftests/net -- disable l2tp.sh test"
+
+  * icmp_redirect.sh in net from ubuntu_kernel_selftests failed on F-OEM-5.6 /
+    F-OEM-5.10 / F-OEM-5.13 / F / G / H (LP: #1880645)
+    - selftests: icmp_redirect: support expected failures
+
+  * Focal update: v5.4.128 upstream stable release (LP: #1934179)
+    - dmaengine: ALTERA_MSGDMA depends on HAS_IOMEM
+    - dmaengine: QCOM_HIDMA_MGMT depends on HAS_IOMEM
+    - dmaengine: stedma40: add missing iounmap() on error in d40_probe()
+    - afs: Fix an IS_ERR() vs NULL check
+    - mm/memory-failure: make sure wait for page writeback in memory_failure
+    - kvm: LAPIC: Restore guard to prevent illegal APIC register access
+    - batman-adv: Avoid WARN_ON timing related checks
+    - net: ipv4: fix memory leak in netlbl_cipsov4_add_std
+    - vrf: fix maximum MTU
+    - net: rds: fix memory leak in rds_recvmsg
+    - net: lantiq: disable interrupt before sheduling NAPI
+    - udp: fix race between close() and udp_abort()
+    - rtnetlink: Fix regression in bridge VLAN configuration
+    - net/sched: act_ct: handle DNAT tuple collision
+    - net/mlx5e: Remove dependency in IPsec initialization flows
+    - net/mlx5e: Fix page reclaim for dead peer hairpin
+    - net/mlx5: Consider RoCE cap before init RDMA resources
+    - net/mlx5e: allow TSO on VXLAN over VLAN topologies
+    - net/mlx5e: Block offload of outer header csum for UDP tunnels
+    - netfilter: synproxy: Fix out of bounds when parsing TCP options
+    - sch_cake: Fix out of bounds when parsing TCP options and header
+    - alx: Fix an error handling path in 'alx_probe()'
+    - net: stmmac: dwmac1000: Fix extended MAC address registers definition
+    - net: make get_net_ns return error if NET_NS is disabled
+    - qlcnic: Fix an error handling path in 'qlcnic_probe()'
+    - netxen_nic: Fix an error handling path in 'netxen_nic_probe()'
+    - net: qrtr: fix OOB Read in qrtr_endpoint_post
+    - ptp: improve max_adj check against unreasonable values
+    - net: cdc_ncm: switch to eth%d interface naming
+    - lantiq: net: fix duplicated skb in rx descriptor ring
+    - net: usb: fix possible use-after-free in smsc75xx_bind
+    - net: fec_ptp: fix issue caused by refactor the fec_devtype
+    - net: ipv4: fix memory leak in ip_mc_add1_src
+    - net/af_unix: fix a data-race in unix_dgram_sendmsg / unix_release_sock
+    - be2net: Fix an error handling path in 'be_probe()'
+    - net: hamradio: fix memory leak in mkiss_close
+    - net: cdc_eem: fix tx fixup skb leak
+    - cxgb4: fix wrong shift.
+    - bnxt_en: Rediscover PHY capabilities after firmware reset
+    - bnxt_en: Call bnxt_ethtool_free() in bnxt_init_one() error path
+    - icmp: don't send out ICMP messages with a source address of 0.0.0.0
+    - net: ethernet: fix potential use-after-free in ec_bhf_remove
+    - regulator: bd70528: Fix off-by-one for buck123 .n_voltages setting
+    - ASoC: rt5659: Fix the lost powers for the HDA header
+    - spi: stm32-qspi: Always wait BUSY bit to be cleared in stm32_qspi_wait_cmd()
+    - pinctrl: ralink: rt2880: avoid to error in calls is pin is already enabled
+    - radeon: use memcpy_to/fromio for UVD fw upload
+    - hwmon: (scpi-hwmon) shows the negative temperature properly
+    - can: bcm: fix infoleak in struct bcm_msg_head
+    - can: bcm/raw/isotp: use per module netdevice notifier
+    - can: j1939: fix Use-after-Free, hold skb ref while in use
+    - can: mcba_usb: fix memory leak in mcba_usb
+    - usb: core: hub: Disable autosuspend for Cypress CY7C65632
+    - tracing: Do not stop recording cmdlines when tracing is off
+    - tracing: Do not stop recording comms if the trace file is being read
+    - tracing: Do no increment trace_clock_global() by one
+    - PCI: Mark TI C667X to avoid bus reset
+    - PCI: Mark some NVIDIA GPUs to avoid bus reset
+    - PCI: aardvark: Don't rely on jiffies while holding spinlock
+    - PCI: aardvark: Fix kernel panic during PIO transfer
+    - PCI: Add ACS quirk for Broadcom BCM57414 NIC
+    - PCI: Work around Huawei Intelligent NIC VF FLR erratum
+    - KVM: x86: Immediately reset the MMU context when the SMM flag is cleared
+    - ARCv2: save ABI registers across signal handling
+    - x86/process: Check PF_KTHREAD and not current->mm for kernel threads
+    - x86/pkru: Write hardware init value to PKRU when xstate is init
+    - x86/fpu: Reset state for all signal restore failures
+    - dmaengine: pl330: fix wrong usage of spinlock flags in dma_cyclc
+    - cfg80211: make certificate generation more robust
+    - cfg80211: avoid double free of PMSR request
+    - net: ll_temac: Make sure to free skb when it is completely used
+    - net: ll_temac: Fix TX BD buffer overwrite
+    - net: bridge: fix vlan tunnel dst null pointer dereference
+    - net: bridge: fix vlan tunnel dst refcnt when egressing
+    - mm/slub: clarify verification reporting
+    - mm/slub: fix redzoning for small allocations
+    - mm/slub.c: include swab.h
+    - net: stmmac: disable clocks in stmmac_remove_config_dt()
+    - net: fec_ptp: add clock rate zero check
+    - tools headers UAPI: Sync linux/in.h copy with the kernel sources
+    - KVM: arm/arm64: Fix KVM_VGIC_V3_ADDR_TYPE_REDIST read
+    - ARM: OMAP: replace setup_irq() by request_irq()
+    - clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support
+    - clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
+    - clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
+    - usb: dwc3: debugfs: Add and remove endpoint dirs dynamically
+    - usb: dwc3: core: fix kernel panic when do reboot
+    - Linux 5.4.128
+
+  * linux-azure CIFS DFS oops (LP: #1935833)
+    - cifs: get rid of unused parameter in reconn_setup_dfs_targets()
+    - cifs: handle empty list of targets in cifs_reconnect()
+
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: improve the test result processing
+
+  * cifs: On cifs_reconnect, resolve the hostname again (LP: #1929831)
+    - cifs: rename reconn_inval_dfs_target()
+    - cifs: Simplify reconnect code when dfs upcall is enabled
+    - cifs: Avoid error pointer dereference
+    - cifs: On cifs_reconnect, resolve the hostname again.
+
+  * Pixel format change broken for Elgato Cam Link 4K (LP: #1932367)
+    - (upstream) media: uvcvideo: Fix pixel format change for Elgato Cam Link 4K
+
+  * Focal update: v5.4.127 upstream stable release (LP: #1933851)
+    - net: ieee802154: fix null deref in parse dev addr
+    - HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for Saitek X65
+    - HID: hid-input: add mapping for emoji picker key
+    - HID: hid-sensor-hub: Return error for hid_set_field() failure
+    - HID: quirks: Add quirk for Lenovo optical mouse
+    - HID: multitouch: set Stylus suffix for Stylus-application devices, too
+    - HID: Add BUS_VIRTUAL to hid_connect logging
+    - HID: usbhid: fix info leak in hid_submit_ctrl
+    - drm/tegra: sor: Do not leak runtime PM reference
+    - ARM: OMAP2+: Fix build warning when mmc_omap is not built
+    - gfs2: Prevent direct-I/O write fallback errors from getting lost
+    - HID: gt683r: add missing MODULE_DEVICE_TABLE
+    - riscv: Use -mno-relax when using lld linker
+    - gfs2: Fix use-after-free in gfs2_glock_shrink_scan
+    - scsi: target: core: Fix warning on realtime kernels
+    - ethernet: myri10ge: Fix missing error code in myri10ge_probe()
+    - scsi: qedf: Do not put host in qedf_vport_create() unconditionally
+    - scsi: scsi_devinfo: Add blacklist entry for HPE OPEN-V
+    - nvme-loop: reset queue count to 1 in nvme_loop_destroy_io_queues()
+    - nvme-loop: clear NVME_LOOP_Q_LIVE when nvme_loop_configure_admin_queue()
+      fails
+    - nvme-loop: check for NVME_LOOP_Q_LIVE in nvme_loop_destroy_admin_queue()
+    - net: ipconfig: Don't override command-line hostnames or domains
+    - drm/amd/display: Allow bandwidth validation for 0 streams.
+    - rtnetlink: Fix missing error code in rtnl_bridge_notify()
+    - net/x25: Return the correct errno code
+    - net: Return the correct errno code
+    - fib: Return the correct errno code
+    - Linux 5.4.127
+
+  * Focal update: v5.4.126 upstream stable release (LP: #1933369)
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - proc: Track /proc/$pid/attr/ opener mm_struct
+    - ASoC: max98088: fix ni clock divider calculation
+    - spi: Fix spi device unregister flow
+    - net/nfc/rawsock.c: fix a permission check bug
+    - usb: cdns3: Fix runtime PM imbalance on error
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Glavey TM800A550L tablet
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Lenovo Miix 3-830 tablet
+    - vfio-ccw: Serialize FSM IDLE state with I/O completion
+    - ASoC: sti-sas: add missing MODULE_DEVICE_TABLE
+    - spi: sprd: Add missing MODULE_DEVICE_TABLE
+    - isdn: mISDN: netjet: Fix crash in nj_probe:
+    - bonding: init notify_work earlier to avoid uninitialized use
+    - netlink: disable IRQs for netlink_lock_table()
+    - net: mdiobus: get rid of a BUG_ON()
+    - cgroup: disable controllers at parse time
+    - wq: handle VM suspension in stall detection
+    - net/qla3xxx: fix schedule while atomic in ql_sem_spinlock
+    - RDS tcp loopback connection can hang
+    - scsi: bnx2fc: Return failure if io_req is already in ABTS processing
+    - scsi: vmw_pvscsi: Set correct residual data length
+    - scsi: hisi_sas: Drop free_irq() of devm_request_irq() allocated irq
+    - scsi: target: qla2xxx: Wait for stop_phase1 at WWN removal
+    - net: macb: ensure the device is available before accessing GEMGXL control
+      registers
+    - net: appletalk: cops: Fix data race in cops_probe1
+    - net: dsa: microchip: enable phy errata workaround on 9567
+    - nvme-fabrics: decode host pathing error for connect
+    - MIPS: Fix kernel hang under FUNCTION_GRAPH_TRACER and PREEMPT_TRACER
+    - dm verity: fix require_signatures module_param permissions
+    - bnx2x: Fix missing error code in bnx2x_iov_init_one()
+    - nvme-tcp: remove incorrect Kconfig dep in BLK_DEV_NVME
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P2041 i2c controllers
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P1010 i2c controllers
+    - spi: Don't have controller clean up spi device before driver unbind
+    - spi: Cleanup on failure of initial setup
+    - i2c: mpc: Make use of i2c_recover_bus()
+    - i2c: mpc: implement erratum A-004447 workaround
+    - x86/boot: Add .text.* to setup.ld
+    - spi: bcm2835: Fix out-of-bounds access with more than 4 slaves
+    - drm: Fix use-after-free read in drm_getunique()
+    - drm: Lock pointer access in drm_master_release()
+    - kvm: avoid speculation-based attacks from out-of-range memslot accesses
+    - staging: rtl8723bs: Fix uninitialized variables
+    - btrfs: return value from btrfs_mark_extent_written() in case of error
+    - btrfs: promote debugging asserts to full-fledged checks in validate_super
+    - cgroup1: don't allow '\n' in renaming
+    - USB: f_ncm: ncm_bitrate (speed) is unsigned
+    - usb: f_ncm: only first packet of aggregate needs to start timer
+    - usb: pd: Set PD_T_SINK_WAIT_CAP to 310ms
+    - usb: dwc3: ep0: fix NULL pointer exception
+    - usb: musb: fix MUSB_QUIRK_B_DISCONNECT_99 handling
+    - usb: typec: wcove: Use LE to CPU conversion when accessing msg->header
+    - usb: typec: ucsi: Clear PPM capability data in ucsi_init() error path
+    - usb: gadget: f_fs: Ensure io_completion_wq is idle during unbind
+    - USB: serial: ftdi_sio: add NovaTech OrionMX product ID
+    - USB: serial: omninet: add device id for Zyxel Omni 56K Plus
+    - USB: serial: quatech2: fix control-request directions
+    - USB: serial: cp210x: fix alternate function for CP2102N QFN20
+    - usb: gadget: eem: fix wrong eem header operation
+    - usb: fix various gadgets null ptr deref on 10gbps cabling.
+    - usb: fix various gadget panics on 10gbps cabling
+    - regulator: core: resolve supply for boot-on/always-on regulators
+    - regulator: max77620: Use device_set_of_node_from_dev()
+    - usb: typec: mux: Fix copy-paste mistake in typec_mux_match
+    - RDMA/ipoib: Fix warning caused by destroying non-initial netns
+    - RDMA/mlx4: Do not map the core_clock page to user space unless enabled
+    - vmlinux.lds.h: Avoid orphan section with !SMP
+    - perf: Fix data race between pin_count increment/decrement
+    - sched/fair: Make sure to update tg contrib for blocked load
+    - KVM: x86: Ensure liveliness of nested VM-Enter fail tracepoint message
+    - IB/mlx5: Fix initializing CQ fragments buffer
+    - NFS: Fix a potential NULL dereference in nfs_get_client()
+    - NFSv4: Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()
+    - perf session: Correct buffer copying when peeking events
+    - kvm: fix previous commit for 32-bit builds
+    - NFS: Fix use-after-free in nfs4_init_client()
+    - NFSv4: Fix second deadlock in nfs4_evict_inode()
+    - NFSv4: nfs4_proc_set_acl needs to restore NFS_CAP_UIDGID_NOMAP on error.
+    - scsi: core: Fix error handling of scsi_host_alloc()
+    - scsi: core: Fix failure handling of scsi_add_host_with_dma()
+    - scsi: core: Put .shost_dev in failure path if host state changes to RUNNING
+    - scsi: core: Only put parent device if host state differs from SHOST_CREATED
+    - ftrace: Do not blindly read the ip address in ftrace_bug()
+    - tracing: Correct the length check which causes memory corruption
+    - proc: only require mm_struct for writing
+    - Linux 5.4.126
+
+  * Focal update: v5.4.125 upstream stable release (LP: #1932957)
+    - btrfs: tree-checker: do not error out if extent ref hash doesn't match
+    - net: usb: cdc_ncm: don't spew notifications
+    - ALSA: usb: update old-style static const declaration
+    - nl80211: validate key indexes for cfg80211_registered_device
+    - hwmon: (dell-smm-hwmon) Fix index values
+    - netfilter: conntrack: unregister ipv4 sockopts on error unwind
+    - efi: Allow EFI_MEMORY_XP and EFI_MEMORY_RO both to be cleared
+    - efi: cper: fix snprintf() use in cper_dimm_err_location()
+    - vfio/pci: Fix error return code in vfio_ecap_init()
+    - vfio/pci: zap_vma_ptes() needs MMU
+    - samples: vfio-mdev: fix error handing in mdpy_fb_probe()
+    - vfio/platform: fix module_put call in error flow
+    - ipvs: ignore IP_VS_SVC_F_HASHED flag when adding service
+    - HID: pidff: fix error return code in hid_pidff_init()
+    - HID: i2c-hid: fix format string mismatch
+    - net/sched: act_ct: Fix ct template allocation for zone 0
+    - ACPICA: Clean up context mutex during object deletion
+    - netfilter: nft_ct: skip expectations for confirmed conntrack
+    - netfilter: nfnetlink_cthelper: hit EBUSY on updates if size mismatches
+    - ieee802154: fix error return code in ieee802154_add_iface()
+    - ieee802154: fix error return code in ieee802154_llsec_getparams()
+    - ixgbevf: add correct exception tracing for XDP
+    - ipv6: Fix KASAN: slab-out-of-bounds Read in fib6_nh_flush_exceptions
+    - ice: write register with correct offset
+    - ice: Fix VFR issues for AVF drivers that expect ATQLEN cleared
+    - ice: Allow all LLDP packets from PF to Tx
+    - i2c: qcom-geni: Add shutdown callback for i2c
+    - i40e: optimize for XDP_REDIRECT in xsk path
+    - i40e: add correct exception tracing for XDP
+    - arm64: dts: ls1028a: fix memory node
+    - arm64: dts: zii-ultra: fix 12V_MAIN voltage
+    - ARM: dts: imx7d-meerkat96: Fix the 'tuning-step' property
+    - ARM: dts: imx7d-pico: Fix the 'tuning-step' property
+    - ARM: dts: imx: emcon-avari: Fix nxp,pca8574 #gpio-cells
+    - bus: ti-sysc: Fix flakey idling of uarts and stop using swsup_sidle_act
+    - tipc: add extack messages for bearer/media failure
+    - tipc: fix unique bearer names sanity check
+    - Bluetooth: fix the erroneous flush_work() order
+    - Bluetooth: use correct lock to prevent UAF of hdev object
+    - net: caif: added cfserl_release function
+    - net: caif: add proper error handling
+    - net: caif: fix memory leak in caif_device_notify
+    - net: caif: fix memory leak in cfusbl_device_notify
+    - HID: i2c-hid: Skip ELAN power-on command after reset
+    - HID: magicmouse: fix NULL-deref on disconnect
+    - HID: multitouch: require Finger field to mark Win8 reports as MT
+    - ALSA: timer: Fix master timer notification
+    - ALSA: hda: Fix for mute key LED for HP Pavilion 15-CK0xx
+    - ARM: dts: imx6dl-yapp4: Fix RGMII connection to QCA8334 switch
+    - ARM: dts: imx6q-dhcom: Add PU,VDD1P1,VDD2P5 regulators
+    - ext4: fix bug on in ext4_es_cache_extent as ext4_split_extent_at failed
+    - usb: dwc2: Fix build in periphal-only mode
+    - pid: take a reference when initializing `cad_pid`
+    - ocfs2: fix data corruption by fallocate
+    - nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+    - drm/amdgpu: Don't query CE and UE errors
+    - drm/amdgpu: make sure we unpin the UVD BO
+    - x86/apic: Mark _all_ legacy interrupts when IO/APIC is missing
+    - btrfs: mark ordered extent and inode with error if we fail to finish
+    - btrfs: fix error handling in btrfs_del_csums
+    - btrfs: return errors from btrfs_del_csums in cleanup_ref_head
+    - btrfs: fixup error handling in fixup_inode_link_counts
+    - mm, hugetlb: fix simple resv_huge_pages underflow on UFFDIO_COPY
+    - bnxt_en: Remove the setting of dev_port.
+    - mm: add thp_order
+    - XArray: add xa_get_order
+    - XArray: add xas_split
+    - mm/filemap: fix storing to a THP shadow entry
+    - btrfs: fix unmountable seed device after fstrim
+    - KVM: SVM: Truncate GPR value for DR and CR accesses in !64-bit mode
+    - KVM: arm64: Fix debug register indexing
+    - lib/lz4: explicitly support in-place decompression
+    - xen-pciback: redo VF placement in the virtual topology
+    - i2c: qcom-geni: Suspend and resume the bus during SYSTEM_SLEEP_PM ops
+    - neighbour: allow NUD_NOARP entries to be forced GCed
+    - Linux 5.4.125
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 15 Jul 2021 20:01:02 +0200
+
+linux (5.4.0-80.90) focal; urgency=medium
+
+  * CVE-2021-33909
+    - SAUCE: seq_file: Disallow extremely large seq buffer allocations
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 09 Jul 2021 12:49:11 -0300
+
+linux (5.4.0-79.88) focal; urgency=medium
+
+  * focal/linux: 5.4.0-79.88 -proposed tracker (LP: #1934343)
+
+  * lxd exec fails (LP: #1934187)
+    - SAUCE: Revert "proc: Check /proc/$pid/attr/ writes against file opener"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 02 Jul 2021 10:27:49 +0200
+
+linux (5.4.0-78.87) focal; urgency=medium
+
+  * focal/linux: 5.4.0-78.87 -proposed tracker (LP: #1932478)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+    - update dkms package versions
+
+  * Disable hv-kvp-daemon.service on certain instance types (LP: #1932081)
+    - [Packaging]: Add kernel command line condition to hv-kvp-daemon service
+
+  * QLogic Direct-Connect host can't discover SCSI-FC or NVMe/FC devices
+    (LP: #1860724)
+    - scsi: qla2xxx: Serialize fc_port alloc in N2N
+    - scsi: qla2xxx: Set Nport ID for N2N
+    - scsi: qla2xxx: Fix point-to-point (N2N) device discovery issue
+    - scsi: qla2xxx: Fix N2N and NVMe connect retry failure
+
+  * [SRU] Add support for E810 NIC to Ice Driver in Focal (LP: #1912511)
+    - ice: add additional E810 device id
+
+  * Focal update: v5.4.124 upstream stable release (LP: #1931166)
+    - ALSA: hda/realtek: Headphone volume is controlled by Front mixer
+    - ALSA: usb-audio: scarlett2: Fix device hang with ehci-pci
+    - ALSA: usb-audio: scarlett2: Improve driver startup messages
+    - cifs: set server->cipher_type to AES-128-CCM for SMB3.0
+    - NFSv4: Fix a NULL pointer dereference in pnfs_mark_matching_lsegs_return()
+    - iommu/vt-d: Fix sysfs leak in alloc_iommu()
+    - perf intel-pt: Fix sample instruction bytes
+    - perf intel-pt: Fix transaction abort handling
+    - perf scripts python: exported-sql-viewer.py: Fix copy to clipboard from Top
+      Calls by elapsed Time report
+    - perf scripts python: exported-sql-viewer.py: Fix Array TypeError
+    - perf scripts python: exported-sql-viewer.py: Fix warning display
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - net: hso: fix control-request directions
+    - ath10k: Validate first subframe of A-MSDU before processing the list
+    - dm snapshot: properly fix a crash when an origin has no snapshots
+    - drm/amdgpu/vcn1: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.0: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.5: add cancel_delayed_work_sync before power gate
+    - selftests/gpio: Use TEST_GEN_PROGS_EXTENDED
+    - selftests/gpio: Move include of lib.mk up
+    - selftests/gpio: Fix build when source tree is read only
+    - kgdb: fix gcc-11 warnings harder
+    - Documentation: seccomp: Fix user notification documentation
+    - serial: core: fix suspicious security_locked_down() call
+    - misc/uss720: fix memory leak in uss720_probe
+    - thunderbolt: dma_port: Fix NVM read buffer bounds and offset issue
+    - mei: request autosuspend after sending rx flow control
+    - staging: iio: cdc: ad7746: avoid overwrite of num_channels
+    - iio: gyro: fxas21002c: balance runtime power in error path
+    - iio: adc: ad7768-1: Fix too small buffer passed to
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ad7124: Fix missbalanced regulator enable / disable on error.
+    - iio: adc: ad7124: Fix potential overflow due to non sequential channel
+      numbers
+    - iio: adc: ad7793: Add missing error code in ad7793_setup()
+    - serial: 8250_pci: Add support for new HPE serial device
+    - serial: 8250_pci: handle FL_NOIRQ board flag
+    - USB: trancevibrator: fix control-request direction
+    - USB: usbfs: Don't WARN about excessively large memory allocations
+    - serial: tegra: Fix a mask operation that is always true
+    - serial: sh-sci: Fix off-by-one error in FIFO threshold register setting
+    - serial: rp2: use 'request_firmware' instead of 'request_firmware_nowait'
+    - USB: serial: ti_usb_3410_5052: add startech.com device id
+    - USB: serial: option: add Telit LE910-S1 compositions 0x7010, 0x7011
+    - USB: serial: ftdi_sio: add IDs for IDS GmbH Products
+    - USB: serial: pl2303: add device id for ADLINK ND-6530 GC
+    - thermal/drivers/intel: Initialize RW trip to THERMAL_TEMP_INVALID
+    - usb: dwc3: gadget: Properly track pending and queued SG
+    - usb: gadget: udc: renesas_usb3: Fix a race in usb3_start_pipen()
+    - net: usb: fix memory leak in smsc75xx_bind
+    - spi: spi-geni-qcom: Fix use-after-free on unbind
+    - Bluetooth: cmtp: fix file refcount when cmtp_attach_device fails
+    - fs/nfs: Use fatal_signal_pending instead of signal_pending
+    - NFS: fix an incorrect limit in filelayout_decode_layout()
+    - NFS: Fix an Oopsable condition in __nfs_pageio_add_request()
+    - NFS: Don't corrupt the value of pg_bytes_written in nfs_do_recoalesce()
+    - NFSv4: Fix v4.0/v4.1 SEEK_DATA return -ENOTSUPP when set NFS_V4_2 config
+    - drm/meson: fix shutdown crash when component not probed
+    - net/mlx5e: Fix multipath lag activation
+    - net/mlx5e: Fix nullptr in add_vlan_push_action()
+    - net/mlx4: Fix EEPROM dump support
+    - Revert "net:tipc: Fix a double free in tipc_sk_mcast_rcv"
+    - tipc: wait and exit until all work queues are done
+    - tipc: skb_linearize the head skb when reassembling msgs
+    - spi: spi-fsl-dspi: Fix a resource leak in an error handling path
+    - net: dsa: mt7530: fix VLAN traffic leaks
+    - net: dsa: fix a crash if ->get_sset_count() fails
+    - net: dsa: sja1105: error out on unsupported PHY mode
+    - i2c: s3c2410: fix possible NULL pointer deref on read message after write
+    - i2c: i801: Don't generate an interrupt on bus reset
+    - i2c: sh_mobile: Use new clock calculation formulas for RZ/G2E
+    - perf jevents: Fix getting maximum number of fds
+    - platform/x86: hp_accel: Avoid invoking _INI to speed up resume
+    - gpio: cadence: Add missing MODULE_DEVICE_TABLE
+    - Revert "media: usb: gspca: add a missed check for goto_low_power"
+    - Revert "ALSA: sb: fix a missing check of snd_ctl_add"
+    - Revert "serial: max310x: pass return value of spi_register_driver"
+    - serial: max310x: unregister uart driver in case of failure and abort
+    - Revert "net: fujitsu: fix a potential NULL pointer dereference"
+    - net: fujitsu: fix potential null-ptr-deref
+    - Revert "net/smc: fix a NULL pointer dereference"
+    - net: caif: remove BUG_ON(dev == NULL) in caif_xmit
+    - Revert "char: hpet: fix a missing check of ioremap"
+    - char: hpet: add checks after calling ioremap
+    - Revert "ALSA: gus: add a check of the status of snd_ctl_add"
+    - Revert "ALSA: usx2y: Fix potential NULL pointer dereference"
+    - Revert "isdn: mISDNinfineon: fix potential NULL pointer dereference"
+    - isdn: mISDNinfineon: check/cleanup ioremap failure correctly in setup_io
+    - Revert "ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()"
+    - ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()
+    - Revert "isdn: mISDN: Fix potential NULL pointer dereference of kzalloc"
+    - isdn: mISDN: correctly handle ph_info allocation failure in hfcsusb_ph_info
+    - Revert "dmaengine: qcom_hidma: Check for driver register failure"
+    - dmaengine: qcom_hidma: comment platform_driver_register call
+    - Revert "libertas: add checks for the return value of sysfs_create_group"
+    - libertas: register sysfs groups properly
+    - Revert "ASoC: cs43130: fix a NULL pointer dereference"
+    - ASoC: cs43130: handle errors in cs43130_probe() properly
+    - Revert "media: dvb: Add check on sp8870_readreg"
+    - media: dvb: Add check on sp8870_readreg return
+    - Revert "media: gspca: mt9m111: Check write_bridge for timeout"
+    - media: gspca: mt9m111: Check write_bridge for timeout
+    - Revert "media: gspca: Check the return value of write_bridge for timeout"
+    - media: gspca: properly check for errors in po1030_probe()
+    - Revert "net: liquidio: fix a NULL pointer dereference"
+    - net: liquidio: Add missing null pointer checks
+    - Revert "brcmfmac: add a check for the status of usb_register"
+    - brcmfmac: properly check for bus register errors
+    - btrfs: return whole extents in fiemap
+    - scsi: BusLogic: Fix 64-bit system enumeration error for Buslogic
+    - openrisc: Define memory barrier mb
+    - btrfs: do not BUG_ON in link_to_fixup_dir
+    - platform/x86: hp-wireless: add AMD's hardware id to the supported list
+    - platform/x86: intel_punit_ipc: Append MODULE_DEVICE_TABLE for ACPI
+    - platform/x86: touchscreen_dmi: Add info for the Mediacom Winpad 7.0 W700
+      tablet
+    - SMB3: incorrect file id in requests compounded with open
+    - drm/amd/display: Disconnect non-DP with no EDID
+    - drm/amd/amdgpu: fix refcount leak
+    - drm/amdgpu: Fix a use-after-free
+    - drm/amd/amdgpu: fix a potential deadlock in gpu reset
+    - net: netcp: Fix an error message
+    - net: dsa: fix error code getting shifted with 4 in dsa_slave_get_sset_count
+    - ASoC: cs42l42: Regmap must use_single_read/write
+    - vfio-ccw: Check initialized flag in cp_init()
+    - net: really orphan skbs tied to closing sk
+    - net: fec: fix the potential memory leak in fec_enet_init()
+    - net: mdio: thunder: Fix a double free issue in the .remove function
+    - net: mdio: octeon: Fix some double free issues
+    - openvswitch: meter: fix race when getting now_ms.
+    - tls splice: check SPLICE_F_NONBLOCK instead of MSG_DONTWAIT
+    - net: sched: fix packet stuck problem for lockless qdisc
+    - net: sched: fix tx action rescheduling issue during deactivation
+    - net: sched: fix tx action reschedule issue with stopped queue
+    - net: hso: check for allocation failure in hso_create_bulk_serial_device()
+    - net: bnx2: Fix error return code in bnx2_init_board()
+    - bnxt_en: Include new P5 HV definition in VF check.
+    - mld: fix panic in mld_newpack()
+    - gve: Check TX QPL was actually assigned
+    - gve: Update mgmt_msix_idx if num_ntfy changes
+    - gve: Add NULL pointer checks when freeing irqs.
+    - gve: Upgrade memory barrier in poll routine
+    - gve: Correct SKB queue index validation.
+    - cxgb4: avoid accessing registers when clearing filters
+    - staging: emxx_udc: fix loop in _nbu2ss_nuke()
+    - ASoC: cs35l33: fix an error code in probe()
+    - bpf: Set mac_len in bpf_skb_change_head
+    - ixgbe: fix large MTU request from VF
+    - scsi: libsas: Use _safe() loop in sas_resume_port()
+    - net: lantiq: fix memory corruption in RX ring
+    - ipv6: record frag_max_size in atomic fragments in input path
+    - ALSA: usb-audio: scarlett2: snd_scarlett_gen2_controls_create() can be
+      static
+    - net: ethernet: mtk_eth_soc: Fix packet statistics support for MT7628/88
+    - sch_dsmark: fix a NULL deref in qdisc_reset()
+    - MIPS: alchemy: xxs1500: add gpio-au1000.h header file
+    - MIPS: ralink: export rt_sysc_membase for rt2880_wdt.c
+    - drm/i915/display: fix compiler warning about array overrun
+    - i915: fix build warning in intel_dp_get_link_status()
+    - drivers/net/ethernet: clean up unused assignments
+    - net: hns3: check the return of skb_checksum_help()
+    - Revert "Revert "ALSA: usx2y: Fix potential NULL pointer dereference""
+    - net: hso: bail out on interrupt URB allocation failure
+    - neighbour: Prevent Race condition in neighbour subsytem
+    - usb: core: reduce power-on-good delay time of root hub
+    - Linux 5.4.124
+
+  * Focal update: v5.4.123 upstream stable release (LP: #1931160)
+    - usb: dwc3: gadget: Enable suspend events
+    - perf unwind: Fix separate debug info files when using elfutils' libdw's
+      unwinder
+    - perf unwind: Set userdata for all __report_module() paths
+    - NFC: nci: fix memory leak in nci_allocate_device
+    - Linux 5.4.123
+
+  * Focal update: v5.4.122 upstream stable release (LP: #1931159)
+    - firmware: arm_scpi: Prevent the ternary sign expansion bug
+    - openrisc: Fix a memory leak
+    - RDMA/siw: Properly check send and receive CQ pointers
+    - RDMA/siw: Release xarray entry
+    - RDMA/rxe: Clear all QP fields if creation failed
+    - scsi: ufs: core: Increase the usable queue depth
+    - scsi: qla2xxx: Fix error return code in qla82xx_write_flash_dword()
+    - RDMA/mlx5: Recover from fatal event in dual port mode
+    - RDMA/core: Don't access cm_id after its destruction
+    - platform/mellanox: mlxbf-tmfifo: Fix a memory barrier issue
+    - platform/x86: dell-smbios-wmi: Fix oops on rmmod dell_smbios
+    - RDMA/uverbs: Fix a NULL vs IS_ERR() bug
+    - ptrace: make ptrace() fail if the tracee changed its pid unexpectedly
+    - nvmet: seset ns->file when open fails
+    - locking/mutex: clear MUTEX_FLAGS if wait_list is empty due to signal
+    - btrfs: avoid RCU stalls while running delayed iputs
+    - cifs: fix memory leak in smb2_copychunk_range
+    - ALSA: dice: fix stream format for TC Electronic Konnekt Live at high
+      sampling transfer frequency
+    - ALSA: intel8x0: Don't update period unless prepared
+    - ALSA: line6: Fix racy initialization of LINE6 MIDI
+    - ALSA: dice: fix stream format at middle sampling rate for Alesis iO 26
+    - ALSA: firewire-lib: fix calculation for size of IR context payload
+    - ALSA: usb-audio: Validate MS endpoint descriptors
+    - ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro
+    - ALSA: hda: fixup headset for ASUS GU502 laptop
+    - Revert "ALSA: sb8: add a check for request_region"
+    - ALSA: firewire-lib: fix check for the size of isochronous packet payload
+    - ALSA: hda/realtek: reset eapd coeff to default value for alc287
+    - ALSA: hda/realtek: Add some CLOVE SSIDs of ALC293
+    - ALSA: hda/realtek: Fix silent headphone output on ASUS UX430UA
+    - ALSA: hda/realtek: Add fixup for HP OMEN laptop
+    - ALSA: hda/realtek: Add fixup for HP Spectre x360 15-df0xxx
+    - uio_hv_generic: Fix a memory leak in error handling paths
+    - Revert "rapidio: fix a NULL pointer dereference when create_workqueue()
+      fails"
+    - rapidio: handle create_workqueue() failure
+    - Revert "serial: mvebu-uart: Fix to avoid a potential NULL pointer
+      dereference"
+    - drm/amdgpu: disable 3DCGCG on picasso/raven1 to avoid compute hang
+    - drm/amdgpu: update gc golden setting for Navi12
+    - drm/amdgpu: update sdma golden setting for Navi12
+    - mmc: sdhci-pci-gli: increase 1.8V regulator wait
+    - xen-pciback: reconfigure also from backend watch handler
+    - dm snapshot: fix crash with transient storage and zero chunk size
+    - Revert "video: hgafb: fix potential NULL pointer dereference"
+    - Revert "net: stmicro: fix a missing check of clk_prepare"
+    - Revert "leds: lp5523: fix a missing check of return value of lp55xx_read"
+    - Revert "hwmon: (lm80) fix a missing check of bus read in lm80 probe"
+    - Revert "video: imsttfb: fix potential NULL pointer dereferences"
+    - Revert "ecryptfs: replace BUG_ON with error handling code"
+    - Revert "scsi: ufs: fix a missing check of devm_reset_control_get"
+    - Revert "gdrom: fix a memory leak bug"
+    - cdrom: gdrom: deallocate struct gdrom_unit fields in remove_gdrom
+    - cdrom: gdrom: initialize global variable at init time
+    - Revert "media: rcar_drif: fix a memory disclosure"
+    - Revert "rtlwifi: fix a potential NULL pointer dereference"
+    - Revert "qlcnic: Avoid potential NULL pointer dereference"
+    - Revert "niu: fix missing checks of niu_pci_eeprom_read"
+    - ethernet: sun: niu: fix missing checks of niu_pci_eeprom_read()
+    - net: stmicro: handle clk_prepare() failure during init
+    - scsi: ufs: handle cleanup correctly on devm_reset_control_get error
+    - net: rtlwifi: properly check for alloc_workqueue() failure
+    - ics932s401: fix broken handling of errors when word reading fails
+    - leds: lp5523: check return value of lp5xx_read and jump to cleanup code
+    - qlcnic: Add null check after calling netdev_alloc_skb
+    - video: hgafb: fix potential NULL pointer dereference
+    - vgacon: Record video mode changes with VT_RESIZEX
+    - vt: Fix character height handling with VT_RESIZEX
+    - tty: vt: always invoke vc->vc_sw->con_resize callback
+    - nvme-multipath: fix double initialization of ANA state
+    - ext4: fix error handling in ext4_end_enable_verity()
+    - Bluetooth: L2CAP: Fix handling LE modes by L2CAP_OPTIONS
+    - nvmet: use new ana_log_size instead the old one
+    - video: hgafb: correctly handle card detect failure during probe
+    - Bluetooth: SMP: Fail if remote and local public keys are identical
+    - Linux 5.4.122
+
+  * Focal update: v5.4.121 upstream stable release (LP: #1931158)
+    - x86/msr: Fix wr/rdmsr_safe_regs_on_cpu() prototypes
+    - kgdb: fix gcc-11 warning on indentation
+    - usb: sl811-hcd: improve misleading indentation
+    - cxgb4: Fix the -Wmisleading-indentation warning
+    - isdn: capi: fix mismatched prototypes
+    - pinctrl: ingenic: Improve unreachable code generation
+    - xsk: Simplify detection of empty and full rings
+    - virtio_net: Do not pull payload in skb->head
+    - PCI: thunder: Fix compile testing
+    - dmaengine: dw-edma: Fix crash on loading/unloading driver
+    - ARM: 9066/1: ftrace: pause/unpause function graph tracer in cpu_suspend()
+    - ACPI / hotplug / PCI: Fix reference count leak in enable_slot()
+    - Input: elants_i2c - do not bind to i2c-hid compatible ACPI instantiated
+      devices
+    - Input: silead - add workaround for x86 BIOS-es which bring the chip up in a
+      stuck state
+    - um: Mark all kernel symbols as local
+    - um: Disable CONFIG_GCOV with MODULES
+    - ARM: 9075/1: kernel: Fix interrupted SMC calls
+    - scripts/recordmcount.pl: Fix RISC-V regex for clang
+    - riscv: Workaround mcount name prior to clang-13
+    - scsi: lpfc: Fix illegal memory access on Abort IOCBs
+    - ceph: fix fscache invalidation
+    - scsi: target: tcmu: Return from tcmu_handle_completions() if cmd_id not
+      found
+    - bridge: Fix possible races between assigning rx_handler_data and setting
+      IFF_BRIDGE_PORT bit
+    - drm/amd/display: Fix two cursor duplication when using overlay
+    - gpiolib: acpi: Add quirk to ignore EC wakeups on Dell Venue 10 Pro 5055
+    - ALSA: hda: generic: change the DAC ctl name for LO+SPK or LO+HP
+    - block: reexpand iov_iter after read/write
+    - lib: stackdepot: turn depot_lock spinlock to raw_spinlock
+    - net: stmmac: Do not enable RX FIFO overflow interrupts
+    - ip6_gre: proper dev_{hold|put} in ndo_[un]init methods
+    - sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ip6_tunnel: sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ipv6: remove extra dev_hold() for fallback tunnels
+    - KVM: arm64: Initialize VCPU mdcr_el2 before loading it
+    - tweewide: Fix most Shebang lines
+    - scripts: switch explicitly to Python 3
+    - Linux 5.4.121
+
+  * Focal update: v5.4.120 upstream stable release (LP: #1930474)
+    - tpm: fix error return code in tpm2_get_cc_attrs_tbl()
+    - tpm, tpm_tis: Extend locality handling to TPM2 in tpm_tis_gen_interrupt()
+    - tpm, tpm_tis: Reserve locality in tpm_tis_resume()
+    - KVM: x86/mmu: Remove the defunct update_pte() paging hook
+    - PM: runtime: Fix unpaired parent child_count for force_resume
+    - fs: dlm: fix debugfs dump
+    - tipc: convert dest node's address to network order
+    - ASoC: Intel: bytcr_rt5640: Enable jack-detect support on Asus T100TAF
+    - net: stmmac: Set FIFO sizes for ipq806x
+    - ASoC: rsnd: core: Check convert rate in rsnd_hw_params
+    - i2c: bail out early when RDWR parameters are wrong
+    - ALSA: hdsp: don't disable if not enabled
+    - ALSA: hdspm: don't disable if not enabled
+    - ALSA: rme9652: don't disable if not enabled
+    - ALSA: bebob: enable to deliver MIDI messages for multiple ports
+    - Bluetooth: Set CONF_NOT_COMPLETE as l2cap_chan default
+    - Bluetooth: initialize skb_queue_head at l2cap_chan_create()
+    - net: bridge: when suppression is enabled exclude RARP packets
+    - Bluetooth: check for zapped sk before connecting
+    - ip6_vti: proper dev_{hold|put} in ndo_[un]init methods
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Chuwi Hi8 tablet
+    - i2c: Add I2C_AQ_NO_REP_START adapter quirk
+    - mac80211: clear the beacon's CRC after channel switch
+    - pinctrl: samsung: use 'int' for register masks in Exynos
+    - mt76: mt76x0: disable GTK offloading
+    - cuse: prevent clone
+    - ASoC: rsnd: call rsnd_ssi_master_clk_start() from rsnd_ssi_init()
+    - Revert "iommu/amd: Fix performance counter initialization"
+    - iommu/amd: Remove performance counter pre-initialization test
+    - drm/amd/display: Force vsync flip when reconfiguring MPCC
+    - selftests: Set CC to clang in lib.mk if LLVM is set
+    - kconfig: nconf: stop endless search loops
+    - ALSA: hda/hdmi: fix race in handling acomp ELD notification at resume
+    - sctp: Fix out-of-bounds warning in sctp_process_asconf_param()
+    - flow_dissector: Fix out-of-bounds warning in __skb_flow_bpf_to_target()
+    - powerpc/smp: Set numa node before updating mask
+    - ASoC: rt286: Generalize support for ALC3263 codec
+    - ethtool: ioctl: Fix out-of-bounds warning in store_link_ksettings_for_user()
+    - net: sched: tapr: prevent cycle_time == 0 in parse_taprio_schedule
+    - samples/bpf: Fix broken tracex1 due to kprobe argument change
+    - powerpc/pseries: Stop calling printk in rtas_stop_self()
+    - drm/amd/display: fixed divide by zero kernel crash during dsc enablement
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_send_pkt
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_mgmt_join
+    - qtnfmac: Fix possible buffer overflow in qtnf_event_handle_external_auth
+    - powerpc/iommu: Annotate nested lock for lockdep
+    - iavf: remove duplicate free resources calls
+    - net: ethernet: mtk_eth_soc: fix RX VLAN offload
+    - bnxt_en: Add PCI IDs for Hyper-V VF devices.
+    - ia64: module: fix symbolizer crash on fdescr
+    - ASoC: rt286: Make RT286_SET_GPIO_* readable and writable
+    - thermal: thermal_of: Fix error return code of
+      thermal_of_populate_bind_params()
+    - f2fs: fix a redundant call to f2fs_balance_fs if an error occurs
+    - PCI: iproc: Fix return value of iproc_msi_irq_domain_alloc()
+    - PCI: Release OF node in pci_scan_device()'s error path
+    - ARM: 9064/1: hw_breakpoint: Do not directly check the event's
+      overflow_handler hook
+    - rpmsg: qcom_glink_native: fix error return code of qcom_glink_rx_data()
+    - NFSv4.2: Always flush out writes in nfs42_proc_fallocate()
+    - NFS: Deal correctly with attribute generation counter overflow
+    - PCI: endpoint: Fix missing destroy_workqueue()
+    - pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
+    - NFSv4.2 fix handling of sr_eof in SEEK's reply
+    - rtc: fsl-ftm-alarm: add MODULE_TABLE()
+    - ceph: fix inode leak on getattr error in __fh_to_dentry
+    - rtc: ds1307: Fix wday settings for rx8130
+    - net: hns3: fix incorrect configuration for igu_egu_hw_err
+    - net: hns3: initialize the message content in hclge_get_link_mode()
+    - net: hns3: add check for HNS3_NIC_STATE_INITED in
+      hns3_reset_notify_up_enet()
+    - net: hns3: fix for vxlan gpe tx checksum bug
+    - net: hns3: use netif_tx_disable to stop the transmit queue
+    - net: hns3: disable phy loopback setting in hclge_mac_start_phy
+    - sctp: do asoc update earlier in sctp_sf_do_dupcook_a
+    - RISC-V: Fix error code returned by riscv_hartid_to_cpuid()
+    - sunrpc: Fix misplaced barrier in call_decode
+    - ethernet:enic: Fix a use after free bug in enic_hard_start_xmit
+    - sctp: fix a SCTP_MIB_CURRESTAB leak in sctp_sf_do_dupcook_b
+    - netfilter: xt_SECMARK: add new revision to fix structure layout
+    - drm/radeon: Fix off-by-one power_state index heap overwrite
+    - drm/radeon: Avoid power table parsing memory leaks
+    - khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
+    - mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
+    - mm/migrate.c: fix potential indeterminate pte entry in
+      migrate_vma_insert_page()
+    - ksm: fix potential missing rmap_item for stable_node
+    - net: fix nla_strcmp to handle more then one trailing null character
+    - smc: disallow TCP_ULP in smc_setsockopt()
+    - netfilter: nfnetlink_osf: Fix a missing skb_header_pointer() NULL check
+    - can: m_can: m_can_tx_work_queue(): fix tx_skb race condition
+    - sched: Fix out-of-bound access in uclamp
+    - sched/fair: Fix unfairness caused by missing load decay
+    - kernel: kexec_file: fix error return code of kexec_calculate_store_digests()
+    - netfilter: nftables: avoid overflows in nft_hash_buckets()
+    - i40e: Fix use-after-free in i40e_client_subtask()
+    - i40e: fix the restart auto-negotiation after FEC modified
+    - i40e: Fix PHY type identifiers for 2.5G and 5G adapters
+    - ARC: entry: fix off-by-one error in syscall number validation
+    - ARC: mm: PAE: use 40-bit physical page mask
+    - powerpc/64s: Fix crashes when toggling stf barrier
+    - powerpc/64s: Fix crashes when toggling entry flush barrier
+    - hfsplus: prevent corruption in shrinking truncate
+    - squashfs: fix divide error in calculate_skip()
+    - userfaultfd: release page in error path to avoid BUG_ON
+    - mm/hugetlb: fix F_SEAL_FUTURE_WRITE
+    - drm/radeon/dpm: Disable sclk switching on Oland when two 4K 60Hz monitors
+      are connected
+    - drm/i915: Avoid div-by-zero on gen2
+    - iio: proximity: pulsedlight: Fix rumtime PM imbalance on error
+    - usb: fotg210-hcd: Fix an error message
+    - hwmon: (occ) Fix poll rate limiting
+    - ACPI: scan: Fix a memory leak in an error handling path
+    - kyber: fix out of bounds access when preempted
+    - nbd: Fix NULL pointer in flush_workqueue
+    - blk-mq: Swap two calls in blk_mq_exit_queue()
+    - iomap: fix sub-page uptodate handling
+    - usb: dwc3: omap: improve extcon initialization
+    - usb: dwc3: pci: Enable usb2-gadget-lpm-disable for Intel Merrifield
+    - usb: xhci: Increase timeout for HC halt
+    - usb: dwc2: Fix gadget DMA unmap direction
+    - usb: core: hub: fix race condition about TRSMRCY of resume
+    - usb: dwc3: gadget: Return success always for kick transfer in ep queue
+    - xhci: Do not use GFP_KERNEL in (potentially) atomic context
+    - xhci: Add reset resume quirk for AMD xhci controller.
+    - iio: gyro: mpu3050: Fix reported temperature value
+    - iio: tsl2583: Fix division by a zero lux_val
+    - cdc-wdm: untangle a circular dependency between callback and softint
+    - KVM: x86: Cancel pvclock_gtod_work on module removal
+    - mm: fix struct page layout on 32-bit systems
+    - FDDI: defxx: Make MMIO the configuration default except for EISA
+    - MIPS: Reinstate platform `__div64_32' handler
+    - MIPS: Avoid DIVU in `__div64_32' is result would be zero
+    - MIPS: Avoid handcoded DIVU in `__div64_32' altogether
+    - thermal/core/fair share: Lock the thermal zone while looping over instances
+    - f2fs: fix error handling in f2fs_end_enable_verity()
+    - ARM: 9011/1: centralize phys-to-virt conversion of DT/ATAGS address
+    - ARM: 9012/1: move device tree mapping out of linear region
+    - ARM: 9020/1: mm: use correct section size macro to describe the FDT virtual
+      address
+    - ARM: 9027/1: head.S: explicitly map DT even if it lives in the first
+      physical section
+    - usb: typec: tcpm: Fix error while calculating PPS out values
+    - kobject_uevent: remove warning in init_uevent_argv()
+    - netfilter: conntrack: Make global sysctls readonly in non-init netns
+    - clk: exynos7: Mark aclk_fsys1_200 as critical
+    - nvme: do not try to reconfigure APST when the controller is not live
+    - ASoC: rsnd: check all BUSIF status when error
+    - Linux 5.4.120
+
+  * scsi: storvsc: Parameterize number hardware queues (LP: #1930626)
+    - scsi: storvsc: Parameterize number hardware queues
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 18 Jun 2021 16:07:34 +0200
+
+linux (5.4.0-77.86) focal; urgency=medium
+
+  * UAF on CAN J1939 j1939_can_recv (LP: #1932209)
+    - SAUCE: can: j1939: delay release of j1939_priv after synchronize_rcu
+
+  * UAF on CAN BCM bcm_rx_handler (LP: #1931855)
+    - SAUCE: can: bcm: delay release of struct bcm_op after synchronize_rcu
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 16 Jun 2021 22:05:50 -0300
+
+linux (5.4.0-76.85) focal; urgency=medium
+
+  * focal/linux: 5.4.0-76.85 -proposed tracker (LP: #1932123)
+
+  * Upstream v5.9 introduced 'module' patches that removed exported symbols
+    (LP: #1932065)
+    - SAUCE: Revert "modules: inherit TAINT_PROPRIETARY_MODULE"
+    - SAUCE: Revert "modules: return licensing information from find_symbol"
+    - SAUCE: Revert "modules: rename the licence field in struct symsearch to
+      license"
+    - SAUCE: Revert "modules: unexport __module_address"
+    - SAUCE: Revert "modules: unexport __module_text_address"
+    - SAUCE: Revert "modules: mark each_symbol_section static"
+    - SAUCE: Revert "modules: mark find_symbol static"
+    - SAUCE: Revert "modules: mark ref_module static"
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 16 Jun 2021 10:37:49 +0200
+
+linux (5.4.0-75.84) focal; urgency=medium
+
+  * focal/linux: 5.4.0-75.84 -proposed tracker (LP: #1930032)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * CVE-2021-33200
+    - bpf: Wrap aux data inside bpf_sanitize_info container
+    - bpf: Fix mask direction swap upon off reg sign change
+    - bpf: No need to simulate speculative domain for immediates
+
+  * Realtek USB hubs in Dell WD19SC/DC/TB fail to work after exiting s2idle
+    (LP: #1928242)
+    - USB: Verify the port status when timeout happens during port suspend
+
+  * CVE-2020-26145
+    - ath10k: drop fragments with multicast DA for SDIO
+    - ath10k: add CCMP PN replay protection for fragmented frames for PCIe
+    - ath10k: drop fragments with multicast DA for PCIe
+
+  * CVE-2020-26141
+    - ath10k: Fix TKIP Michael MIC verification for PCIe
+
+  * CVE-2020-24588
+    - mac80211: properly handle A-MSDUs that start with an RFC 1042 header
+    - cfg80211: mitigate A-MSDU aggregation attacks
+    - mac80211: drop A-MSDUs on old ciphers
+    - ath10k: drop MPDU which has discard flag set by firmware for SDIO
+
+  * CVE-2020-26139
+    - mac80211: do not accept/forward invalid EAPOL frames
+
+  * CVE-2020-24586 // CVE-2020-24587 // CVE-2020-24587 for such cases.
+    - mac80211: extend protection against mixed key and fragment cache attacks
+
+  * CVE-2020-24586 // CVE-2020-24587
+    - mac80211: prevent mixed key and fragment cache attacks
+    - mac80211: add fragment cache to sta_info
+    - mac80211: check defrag PN against current frame
+    - mac80211: prevent attacks on TKIP/WEP as well
+
+  * CVE-2020-26147
+    - mac80211: assure all fragments are encrypted
+
+  * raid10: Block discard is very slow, causing severe delays for mkfs and
+    fstrim operations (LP: #1896578)
+    - md: add md_submit_discard_bio() for submitting discard bio
+    - md/raid10: extend r10bio devs to raid disks
+    - md/raid10: pull the code that wait for blocked dev into one function
+    - md/raid10: improve raid10 discard request
+    - md/raid10: improve discard request for far layout
+    - dm raid: remove unnecessary discard limits for raid0 and raid10
+
+  * [SRU] mpt3sas: only one vSES is handy even IOC has multi vSES (LP: #1926517)
+    - scsi: mpt3sas: Only one vSES is present even when IOC has multi vSES
+
+  * kvm: properly tear down PV features on hibernate (LP: #1920944)
+    - x86/kvm: Fix pr_info() for async PF setup/teardown
+    - x86/kvm: Teardown PV features on boot CPU as well
+    - x86/kvm: Disable kvmclock on all CPUs on shutdown
+    - x86/kvm: Disable all PV features on crash
+    - x86/kvm: Unify kvm_pv_guest_cpu_reboot() with kvm_guest_cpu_offline()
+
+  * Focal update: v5.4.119 upstream stable release (LP: #1929615)
+    - Bluetooth: verify AMP hci_chan before amp_destroy
+    - hsr: use netdev_err() instead of WARN_ONCE()
+    - bluetooth: eliminate the potential race condition when removing the HCI
+      controller
+    - net/nfc: fix use-after-free llcp_sock_bind/connect
+    - Revert "USB: cdc-acm: fix rounding error in TIOCSSERIAL"
+    - tty: moxa: fix TIOCSSERIAL jiffies conversions
+    - tty: amiserial: fix TIOCSSERIAL permission check
+    - USB: serial: usb_wwan: fix TIOCSSERIAL jiffies conversions
+    - staging: greybus: uart: fix TIOCSSERIAL jiffies conversions
+    - USB: serial: ti_usb_3410_5052: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL jiffies conversions
+    - tty: moxa: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL permission check
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for fixed supply
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for pps supply
+    - usb: typec: tcpm: update power supply once partner accepts
+    - usb: xhci-mtk: remove or operator for setting schedule parameters
+    - usb: xhci-mtk: improve bandwidth scheduling with TT
+    - ASoC: samsung: tm2_wm5110: check of of_parse return value
+    - ASoC: Intel: kbl_da7219_max98927: Fix kabylake_ssp_fixup function
+    - MIPS: pci-mt7620: fix PLL lock check
+    - MIPS: pci-rt2880: fix slot 0 configuration
+    - FDDI: defxx: Bail out gracefully with unassigned PCI resource for CSR
+    - PCI: Allow VPD access for QLogic ISP2722
+    - iio:accel:adis16201: Fix wrong axis assignment that prevents loading
+    - misc: lis3lv02d: Fix false-positive WARN on various HP models
+    - misc: vmw_vmci: explicitly initialize vmci_notify_bm_set_msg struct
+    - misc: vmw_vmci: explicitly initialize vmci_datagram payload
+    - md/bitmap: wait for external bitmap writes to complete during tear down
+    - md-cluster: fix use-after-free issue when removing rdev
+    - md: split mddev_find
+    - md: factor out a mddev_find_locked helper from mddev_find
+    - md: md_open returns -EBUSY when entering racing area
+    - md: Fix missing unused status line of /proc/mdstat
+    - ipw2x00: potential buffer overflow in libipw_wx_set_encodeext()
+    - cfg80211: scan: drop entry from hidden_list on overflow
+    - rtw88: Fix array overrun in rtw_get_tx_power_params()
+    - drm/panfrost: Clear MMU irqs before handling the fault
+    - drm/panfrost: Don't try to map pages that are already mapped
+    - drm/radeon: fix copy of uninitialized variable back to userspace
+    - drm/amd/display: Reject non-zero src_y and src_x for video planes
+    - ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Clevo quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 HP quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Dell quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 ASUS quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries
+    - ALSA: hda/realtek: Re-order remaining ALC269 quirk table entries
+    - ALSA: hda/realtek: Re-order ALC662 quirk table entries
+    - ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices
+    - ALSA: hda/realtek: ALC285 Thinkpad jack pin quirk is unreachable
+    - KVM: s390: split kvm_s390_logical_to_effective
+    - KVM: s390: fix guarded storage control register handling
+    - s390: fix detection of vector enhancements facility 1 vs. vector packed
+      decimal facility
+    - KVM: s390: split kvm_s390_real_to_abs
+    - KVM: nVMX: Truncate bits 63:32 of VMCS field on nested check in !64-bit
+    - KVM: Stop looking for coalesced MMIO zones if the bus is destroyed
+    - Revert "i3c master: fix missing destroy_workqueue() on error in
+      i3c_master_register"
+    - ovl: fix missing revert_creds() on error path
+    - usb: gadget: pch_udc: Revert d3cb25a12138 completely
+    - memory: gpmc: fix out of bounds read and dereference on gpmc_cs[]
+    - ARM: dts: exynos: correct fuel gauge interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct MUIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Odroid X/U3 family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on SMDK5250
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Snow
+    - serial: stm32: fix incorrect characters on console
+    - serial: stm32: fix tx_empty condition
+    - usb: typec: tcpci: Check ROLE_CONTROL while interpreting CC_STATUS
+    - regmap: set debugfs_name to NULL after it is freed
+    - mtd: rawnand: fsmc: Fix error code in fsmc_nand_probe()
+    - mtd: rawnand: brcmnand: fix OOB R/W with Hamming ECC
+    - mtd: Handle possible -EPROBE_DEFER from parse_mtd_partitions()
+    - mtd: rawnand: qcom: Return actual error code instead of -ENODEV
+    - arm64: dts: qcom: sm8150: fix number of pins in 'gpio-ranges'
+    - spi: stm32: drop devres version of spi_register_master
+    - arm64: dts: renesas: r8a77980: Fix vin4-7 endpoint binding
+    - x86/microcode: Check for offline CPUs before requesting new microcode
+    - usb: gadget: pch_udc: Replace cpu_to_le32() by lower_32_bits()
+    - usb: gadget: pch_udc: Check if driver is present before calling ->setup()
+    - usb: gadget: pch_udc: Check for DMA mapping error
+    - crypto: qat - don't release uninitialized resources
+    - crypto: qat - ADF_STATUS_PF_RUNNING should be set after adf_dev_init
+    - fotg210-udc: Fix DMA on EP0 for length > max packet size
+    - fotg210-udc: Fix EP0 IN requests bigger than two packets
+    - fotg210-udc: Remove a dubious condition leading to fotg210_done
+    - fotg210-udc: Mask GRP2 interrupts we don't handle
+    - fotg210-udc: Don't DMA more than the buffer can take
+    - fotg210-udc: Complete OUT requests on short packets
+    - mtd: require write permissions for locking and badblock ioctls
+    - bus: qcom: Put child node before return
+    - soundwire: bus: Fix device found flag correctly
+    - phy: marvell: ARMADA375_USBCLUSTER_PHY should not default to y,
+      unconditionally
+    - crypto: qat - fix error path in adf_isr_resource_alloc()
+    - usb: gadget: aspeed: fix dma map failure
+    - USB: gadget: udc: fix wrong pointer passed to IS_ERR() and PTR_ERR()
+    - memory: pl353: fix mask of ECC page_size config register
+    - soundwire: stream: fix memory leak in stream config error path
+    - m68k: mvme147,mvme16x: Don't wipe PCC timer config bits
+    - mtd: rawnand: gpmi: Fix a double free in gpmi_nand_init
+    - irqchip/gic-v3: Fix OF_BAD_ADDR error handling
+    - staging: rtl8192u: Fix potential infinite loop
+    - staging: greybus: uart: fix unprivileged TIOCCSERIAL
+    - PM / devfreq: Use more accurate returned new_freq as resume_freq
+    - spi: Fix use-after-free with devm_spi_alloc_*
+    - soc: qcom: mdt_loader: Validate that p_filesz < p_memsz
+    - soc: qcom: mdt_loader: Detect truncated read of segments
+    - ACPI: CPPC: Replace cppc_attr with kobj_attribute
+    - crypto: qat - Fix a double free in adf_create_ring
+    - cpufreq: armada-37xx: Fix setting TBG parent for load levels
+    - clk: mvebu: armada-37xx-periph: remove .set_parent method for CPU PM clock
+    - cpufreq: armada-37xx: Fix the AVS value for load L1
+    - clk: mvebu: armada-37xx-periph: Fix switching CPU freq from 250 Mhz to 1 GHz
+    - clk: mvebu: armada-37xx-periph: Fix workaround for switching from L1 to L0
+    - cpufreq: armada-37xx: Fix driver cleanup when registration failed
+    - cpufreq: armada-37xx: Fix determining base CPU frequency
+    - spi: fsl-lpspi: Fix PM reference leak in lpspi_prepare_xfer_hardware()
+    - usb: gadget: r8a66597: Add missing null check on return from
+      platform_get_resource
+    - USB: cdc-acm: fix unprivileged TIOCCSERIAL
+    - USB: cdc-acm: fix TIOCGSERIAL implementation
+    - tty: fix return value for unsupported ioctls
+    - serial: core: return early on unsupported ioctls
+    - firmware: qcom-scm: Fix QCOM_SCM configuration
+    - node: fix device cleanups in error handling code
+    - usbip: vudc: fix missing unlock on error in usbip_sockfd_store()
+    - platform/x86: pmc_atom: Match all Beckhoff Automation baytrail boards with
+      critclk_systems DMI table
+    - x86/platform/uv: Fix !KEXEC build failure
+    - usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
+    - usb: dwc2: Fix hibernation between host and device modes.
+    - ttyprintk: Add TTY hangup callback.
+    - xen-blkback: fix compatibility bug with single page rings
+    - soc: aspeed: fix a ternary sign expansion bug
+    - media: vivid: fix assignment of dev->fbuf_out_flags
+    - media: omap4iss: return error code when omap4iss_get() failed
+    - media: aspeed: fix clock handling logic
+    - media: platform: sunxi: sun6i-csi: fix error return code of
+      sun6i_video_start_streaming()
+    - media: m88rs6000t: avoid potential out-of-bounds reads on arrays
+    - drm/amdkfd: fix build error with AMD_IOMMU_V2=m
+    - x86/kprobes: Fix to check non boostable prefixes correctly
+    - pata_arasan_cf: fix IRQ check
+    - pata_ipx4xx_cf: fix IRQ check
+    - sata_mv: add IRQ checks
+    - ata: libahci_platform: fix IRQ check
+    - nvme-tcp: block BH in sk state_change sk callback
+    - nvmet-tcp: fix incorrect locking in state_change sk callback
+    - nvme: retrigger ANA log update if group descriptor isn't found
+    - media: v4l2-ctrls.c: fix race condition in hdl->requests list
+    - vfio/mdev: Do not allow a mdev_type to have a NULL parent pointer
+    - clk: zynqmp: move zynqmp_pll_set_mode out of round_rate callback
+    - clk: qcom: a53-pll: Add missing MODULE_DEVICE_TABLE
+    - clk: uniphier: Fix potential infinite loop
+    - scsi: hisi_sas: Fix IRQ checks
+    - scsi: jazz_esp: Add IRQ check
+    - scsi: sun3x_esp: Add IRQ check
+    - scsi: sni_53c710: Add IRQ check
+    - scsi: ibmvfc: Fix invalid state machine BUG_ON()
+    - mfd: stm32-timers: Avoid clearing auto reload register
+    - nvme-pci: don't simple map sgl when sgls are disabled
+    - HSI: core: fix resource leaks in hsi_add_client_from_dt()
+    - x86/events/amd/iommu: Fix sysfs type mismatch
+    - sched/debug: Fix cgroup_path[] serialization
+    - drivers/block/null_blk/main: Fix a double free in null_init.
+    - HID: plantronics: Workaround for double volume key presses
+    - perf symbols: Fix dso__fprintf_symbols_by_name() to return the number of
+      printed chars
+    - net: lapbether: Prevent racing when checking whether the netif is running
+    - powerpc/fadump: Mark fadump_calculate_reserve_size as __init
+    - powerpc/prom: Mark identical_pvr_fixup as __init
+    - inet: use bigger hash table for IP ID generation
+    - powerpc: Fix HAVE_HARDLOCKUP_DETECTOR_ARCH build configuration
+    - ALSA: core: remove redundant spin_lock pair in snd_card_disconnect
+    - bug: Remove redundant condition check in report_bug
+    - nfc: pn533: prevent potential memory corruption
+    - net: hns3: Limiting the scope of vector_ring_chain variable
+    - mips: bmips: fix syscon-reboot nodes
+    - ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls
+    - ASoC: simple-card: fix possible uninitialized single_cpu local variable
+    - liquidio: Fix unintented sign extension of a left shift of a u16
+    - powerpc/64s: Fix pte update for kernel memory on radix
+    - powerpc/perf: Fix PMU constraint check for EBB events
+    - powerpc: iommu: fix build when neither PCI or IBMVIO is set
+    - mac80211: bail out if cipher schemes are invalid
+    - mt7601u: fix always true expression
+    - KVM: PPC: Book3S HV P9: Restore host CTRL SPR after guest exit
+    - RDMA/qedr: Fix error return code in qedr_iw_connect()
+    - IB/hfi1: Fix error return code in parse_platform_config()
+    - cxgb4: Fix unintentional sign extension issues
+    - net: thunderx: Fix unintentional sign extension issue
+    - RDMA/srpt: Fix error return code in srpt_cm_req_recv()
+    - i2c: img-scb: fix reference leak when pm_runtime_get_sync fails
+    - i2c: imx-lpi2c: fix reference leak when pm_runtime_get_sync fails
+    - i2c: omap: fix reference leak when pm_runtime_get_sync fails
+    - i2c: sprd: fix reference leak when pm_runtime_get_sync fails
+    - i2c: cadence: add IRQ check
+    - i2c: emev2: add IRQ check
+    - i2c: jz4780: add IRQ check
+    - i2c: sh7760: add IRQ check
+    - powerpc/xive: Fix xmon command "dxi"
+    - ASoC: ak5558: correct reset polarity
+    - drm/i915/gvt: Fix error code in intel_gvt_init_device()
+    - perf beauty: Fix fsconfig generator
+    - MIPS: pci-legacy: stop using of_pci_range_to_resource
+    - powerpc/pseries: extract host bridge from pci_bus prior to bus removal
+    - rtlwifi: 8821ae: upgrade PHY and RF parameters
+    - i2c: sh7760: fix IRQ error path
+    - mwl8k: Fix a double Free in mwl8k_probe_hw
+    - vsock/vmci: log once the failed queue pair allocation
+    - gro: fix napi_gro_frags() Fast GRO breakage due to IP alignment check
+    - RDMA/cxgb4: add missing qpid increment
+    - RDMA/i40iw: Fix error unwinding when i40iw_hmc_sd_one fails
+    - ALSA: usb: midi: don't return -ENOMEM when usb_urb_ep_type_check fails
+    - net: davinci_emac: Fix incorrect masking of tx and rx error channel
+    - net: renesas: ravb: Fix a stuck issue when a lot of frames are received
+    - net: phy: intel-xway: enable integrated led functions
+    - ath9k: Fix error check in ath9k_hw_read_revisions() for PCI devices
+    - ath10k: Fix ath10k_wmi_tlv_op_pull_peer_stats_info() unlock without lock
+    - powerpc/52xx: Fix an invalid ASM expression ('addi' used instead of 'add')
+    - bnxt_en: fix ternary sign extension bug in bnxt_show_temp()
+    - ARM: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - arm64: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - net: geneve: modify IP header check in geneve6_xmit_skb and geneve_xmit_skb
+    - selftests: net: mirror_gre_vlan_bridge_1q: Make an FDB entry static
+    - bnxt_en: Fix RX consumer index logic in the error path.
+    - net:emac/emac-mac: Fix a use after free in emac_mac_tx_buf_send
+    - RDMA/siw: Fix a use after free in siw_alloc_mr
+    - RDMA/bnxt_re: Fix a double free in bnxt_qplib_alloc_res
+    - net: bridge: mcast: fix broken length + header check for MRDv6 Adv.
+    - net:nfc:digital: Fix a double free in digital_tg_recv_dep_req
+    - kfifo: fix ternary sign extension bugs
+    - mm/sparse: add the missing sparse_buffer_fini() in error branch
+    - mm/memory-failure: unnecessary amount of unmapping
+    - net: Only allow init netns to set default tcp cong to a restricted algo
+    - smp: Fix smp_call_function_single_async prototype
+    - Revert "net/sctp: fix race condition in sctp_destroy_sock"
+    - sctp: delay auto_asconf init until binding the first addr
+    - Revert "of/fdt: Make sure no-map does not remove already reserved regions"
+    - Revert "fdt: Properly handle "no-map" field in the memory region"
+    - Linux 5.4.119
+
+  * seccomp_bpf:syscall_faked from kselftests fail on s390x (LP: #1928522)
+    - selftests/seccomp: s390 shares the syscall and return value register
+
+  * Can't detect intel wifi 6235 (LP: #1920180)
+    - SAUCE: iwlwifi: add new pci id for 6235
+
+  * Mark kprobe_args_user.tc in kselftest/ftrace as unsupported (LP: #1929527)
+    - selftests/ftrace: Return unsupported for the unconfigured features
+
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: use $ksft_skip for skipped return code
+
+  * alsa/sof: make sof driver work in the case of without i915 (focal kernel)
+    (LP: #1927672)
+    - SAUCE: ASoC: SOF: Intel: hda: move the probe_bus ahead of creation of mach
+      device
+
+  * Fix kdump failures (LP: #1927518)
+    - video: hyperv_fb: Add ratelimit on error message
+    - Drivers: hv: vmbus: Increase wait time for VMbus unload
+    - Drivers: hv: vmbus: Initialize unload_event statically
+
+  * Ubuntu 20.04 - 'Support flow counters offset for bulk counters'
+    (LP: #1922494)
+    - IB/mlx5: Support flow counters offset for bulk counters
+
+  * Focal update: v5.4.118 upstream stable release (LP: #1928825)
+    - s390/disassembler: increase ebpf disasm buffer size
+    - ACPI: custom_method: fix potential use-after-free issue
+    - ACPI: custom_method: fix a possible memory leak
+    - ftrace: Handle commands when closing set_ftrace_filter file
+    - ARM: 9056/1: decompressor: fix BSS size calculation for LLVM ld.lld
+    - arm64: dts: marvell: armada-37xx: add syscon compatible to NB clk node
+    - arm64: dts: mt8173: fix property typo of 'phys' in dsi node
+    - ecryptfs: fix kernel panic with null dev_name
+    - mtd: spinand: core: add missing MODULE_DEVICE_TABLE()
+    - mtd: rawnand: atmel: Update ecc_stats.corrected counter
+    - erofs: add unsupported inode i_format check
+    - spi: spi-ti-qspi: Free DMA resources
+    - scsi: qla2xxx: Fix crash in qla2xxx_mqueuecommand()
+    - scsi: mpt3sas: Block PCI config access from userspace during reset
+    - mmc: uniphier-sd: Fix an error handling path in uniphier_sd_probe()
+    - mmc: uniphier-sd: Fix a resource leak in the remove function
+    - mmc: sdhci: Check for reset prior to DMA address unmap
+    - mmc: sdhci-pci: Fix initialization of some SD cards for Intel BYT-based
+      controllers
+    - mmc: block: Update ext_csd.cache_ctrl if it was written
+    - mmc: block: Issue a cache flush only when it's enabled
+    - mmc: core: Do a power cycle when the CMD11 fails
+    - mmc: core: Set read only for SD cards with permanent write protect bit
+    - mmc: core: Fix hanging on I/O during system suspend for removable cards
+    - modules: mark ref_module static
+    - modules: mark find_symbol static
+    - modules: mark each_symbol_section static
+    - modules: unexport __module_text_address
+    - modules: unexport __module_address
+    - modules: rename the licence field in struct symsearch to license
+    - modules: return licensing information from find_symbol
+    - modules: inherit TAINT_PROPRIETARY_MODULE
+    - irqchip/gic-v3: Do not enable irqs when handling spurious interrups
+    - cifs: Return correct error code from smb2_get_enc_key
+    - btrfs: fix metadata extent leak after failure to create subvolume
+    - intel_th: pci: Add Rocket Lake CPU support
+    - posix-timers: Preserve return value in clock_adjtime32()
+    - fbdev: zero-fill colormap in fbcmap.c
+    - bus: ti-sysc: Probe for l4_wkup and l4_cfg interconnect devices first
+    - staging: wimax/i2400m: fix byte-order issue
+    - spi: ath79: always call chipselect function
+    - spi: ath79: remove spi-master setup and cleanup assignment
+    - crypto: api - check for ERR pointers in crypto_destroy_tfm()
+    - crypto: qat - fix unmap invalid dma address
+    - usb: gadget: uvc: add bInterval checking for HS mode
+    - usb: webcam: Invalid size of Processing Unit Descriptor
+    - genirq/matrix: Prevent allocation counter corruption
+    - usb: gadget: f_uac2: validate input parameters
+    - usb: gadget: f_uac1: validate input parameters
+    - usb: dwc3: gadget: Ignore EP queue requests during bus reset
+    - usb: xhci: Fix port minor revision
+    - PCI: PM: Do not read power state in pci_enable_device_flags()
+    - x86/build: Propagate $(CLANG_FLAGS) to $(REALMODE_FLAGS)
+    - tee: optee: do not check memref size on return from Secure World
+    - perf/arm_pmu_platform: Fix error handling
+    - usb: xhci-mtk: support quirk to disable usb2 lpm
+    - xhci: check control context is valid before dereferencing it.
+    - xhci: fix potential array out of bounds with several interrupters
+    - spi: dln2: Fix reference leak to master
+    - spi: omap-100k: Fix reference leak to master
+    - spi: qup: fix PM reference leak in spi_qup_remove()
+    - usb: musb: fix PM reference leak in musb_irq_work()
+    - usb: core: hub: Fix PM reference leak in usb_port_resume()
+    - tty: n_gsm: check error while registering tty devices
+    - intel_th: Consistency and off-by-one fix
+    - phy: phy-twl4030-usb: Fix possible use-after-free in twl4030_usb_remove()
+    - crypto: stm32/hash - Fix PM reference leak on stm32-hash.c
+    - crypto: stm32/cryp - Fix PM reference leak on stm32-cryp.c
+    - crypto: omap-aes - Fix PM reference leak on omap-aes.c
+    - platform/x86: intel_pmc_core: Don't use global pmcdev in quirks
+    - btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s
+    - drm: Added orientation quirk for OneGX1 Pro
+    - drm/qxl: release shadow on shutdown
+    - drm/amd/display: Check for DSC support instead of ASIC revision
+    - drm/amd/display: Don't optimize bandwidth before disabling planes
+    - scsi: lpfc: Fix incorrect dbde assignment when building target abts wqe
+    - scsi: lpfc: Fix pt2pt connection does not recover after LOGO
+    - scsi: target: pscsi: Fix warning in pscsi_complete_cmd()
+    - media: ite-cir: check for receive overflow
+    - media: drivers: media: pci: sta2x11: fix Kconfig dependency on GPIOLIB
+    - media: imx: capture: Return -EPIPE from __capture_legacy_try_fmt()
+    - power: supply: bq27xxx: fix power_avg for newer ICs
+    - extcon: arizona: Fix some issues when HPDET IRQ fires after the jack has
+      been unplugged
+    - extcon: arizona: Fix various races on driver unbind
+    - media: media/saa7164: fix saa7164_encoder_register() memory leak bugs
+    - media: gspca/sq905.c: fix uninitialized variable
+    - power: supply: Use IRQF_ONESHOT
+    - drm/amdgpu: mask the xgmi number of hops reported from psp to kfd
+    - drm/amdkfd: Fix UBSAN shift-out-of-bounds warning
+    - drm/amdgpu : Fix asic reset regression issue introduce by 8f211fe8ac7c4f
+    - drm/amd/display: Fix UBSAN warning for not a valid value for type '_Bool'
+    - drm/amd/display: fix dml prefetch validation
+    - scsi: qla2xxx: Always check the return value of qla24xx_get_isp_stats()
+    - drm/vkms: fix misuse of WARN_ON
+    - scsi: qla2xxx: Fix use after free in bsg
+    - mmc: sdhci-pci: Add PCI IDs for Intel LKF
+    - ata: ahci: Disable SXS for Hisilicon Kunpeng920
+    - scsi: smartpqi: Correct request leakage during reset operations
+    - scsi: smartpqi: Add new PCI IDs
+    - scsi: scsi_dh_alua: Remove check for ASC 24h in alua_rtpg()
+    - media: em28xx: fix memory leak
+    - media: vivid: update EDID
+    - clk: socfpga: arria10: Fix memory leak of socfpga_clk on error return
+    - power: supply: generic-adc-battery: fix possible use-after-free in
+      gab_remove()
+    - power: supply: s3c_adc_battery: fix possible use-after-free in
+      s3c_adc_bat_remove()
+    - media: tc358743: fix possible use-after-free in tc358743_remove()
+    - media: adv7604: fix possible use-after-free in adv76xx_remove()
+    - media: i2c: adv7511-v4l2: fix possible use-after-free in adv7511_remove()
+    - media: i2c: tda1997: Fix possible use-after-free in tda1997x_remove()
+    - media: i2c: adv7842: fix possible use-after-free in adv7842_remove()
+    - media: platform: sti: Fix runtime PM imbalance in regs_show
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init
+    - media: gscpa/stv06xx: fix memory leak
+    - sched/fair: Ignore percpu threads for imbalance pulls
+    - drm/msm/mdp5: Configure PP_SYNC_HEIGHT to double the vtotal
+    - drm/msm/mdp5: Do not multiply vclk line count by 100
+    - drm/amdkfd: Fix cat debugfs hang_hws file causes system crash bug
+    - amdgpu: avoid incorrect %hu format string
+    - drm/amdgpu: fix NULL pointer dereference
+    - scsi: lpfc: Fix crash when a REG_RPI mailbox fails triggering a LOGO
+      response
+    - scsi: lpfc: Fix error handling for mailboxes completed in MBX_POLL mode
+    - scsi: lpfc: Remove unsupported mbox PORT_CAPABILITIES logic
+    - mfd: arizona: Fix rumtime PM imbalance on error
+    - scsi: libfc: Fix a format specifier
+    - s390/archrandom: add parameter check for s390_arch_random_generate
+    - ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer
+    - ALSA: hda/conexant: Re-order CX5066 quirk table entries
+    - ALSA: sb: Fix two use after free in snd_sb_qsound_build
+    - ALSA: usb-audio: Explicitly set up the clock selector
+    - ALSA: usb-audio: More constifications
+    - ALSA: usb-audio: Add dB range mapping for Sennheiser Communications Headset
+      PC 8
+    - ALSA: hda/realtek: GA503 use same quirks as GA401
+    - ALSA: hda/realtek: fix mic boost on Intel NUC 8
+    - ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops
+    - ALSA: hda/realtek: Add quirk for Intel Clevo PCx0Dx
+    - btrfs: fix race when picking most recent mod log operation for an old root
+    - arm64/vdso: Discard .note.gnu.property sections in vDSO
+    - Makefile: Move -Wno-unused-but-set-variable out of GCC only block
+    - virtiofs: fix memory leak in virtio_fs_probe()
+    - ubifs: Only check replay with inode type to judge if inode linked
+    - f2fs: fix to avoid out-of-bounds memory access
+    - mlxsw: spectrum_mr: Update egress RIF list before route's action
+    - openvswitch: fix stack OOB read while fragmenting IPv4 packets
+    - ACPI: GTDT: Don't corrupt interrupt mappings on watchdow probe failure
+    - NFS: Don't discard pNFS layout segments that are marked for return
+    - NFSv4: Don't discard segments marked for return in _pnfs_return_layout()
+    - Input: ili210x - add missing negation for touch indication on ili210x
+    - jffs2: Fix kasan slab-out-of-bounds problem
+    - powerpc/eeh: Fix EEH handling for hugepages in ioremap space.
+    - powerpc: fix EDEADLOCK redefinition error in uapi/asm/errno.h
+    - intel_th: pci: Add Alder Lake-M support
+    - tpm: efi: Use local variable for calculating final log size
+    - tpm: vtpm_proxy: Avoid reading host log when using a virtual device
+    - crypto: rng - fix crypto_rng_reset() refcounting when !CRYPTO_STATS
+    - md/raid1: properly indicate failure when ending a failed write request
+    - dm raid: fix inconclusive reshape layout on fast raid4/5/6 table reload
+      sequences
+    - fuse: fix write deadlock
+    - security: commoncap: fix -Wstringop-overread warning
+    - Fix misc new gcc warnings
+    - jffs2: check the validity of dstlen in jffs2_zlib_compress()
+    - Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
+    - x86/cpu: Initialize MSR_TSC_AUX if RDTSCP *or* RDPID is supported
+    - kbuild: update config_data.gz only when the content of .config is changed
+    - ext4: fix check to prevent false positive report of incorrect used inodes
+    - ext4: do not set SB_ACTIVE in ext4_orphan_cleanup()
+    - ext4: fix error code in ext4_commit_super
+    - media: dvbdev: Fix memory leak in dvb_media_device_free()
+    - media: dvb-usb: Fix use-after-free access
+    - media: dvb-usb: Fix memory leak at error in dvb_usb_device_init()
+    - media: staging/intel-ipu3: Fix memory leak in imu_fmt
+    - media: staging/intel-ipu3: Fix set_fmt error handling
+    - media: staging/intel-ipu3: Fix race condition during set_fmt
+    - usb: gadget: dummy_hcd: fix gpf in gadget_setup
+    - usb: gadget: Fix double free of device descriptor pointers
+    - usb: gadget/function/f_fs string table fix for multiple languages
+    - usb: dwc3: gadget: Fix START_TRANSFER link state check
+    - usb: dwc2: Fix session request interrupt handler
+    - tty: fix memory leak in vc_deallocate
+    - rsi: Use resume_noirq for SDIO
+    - tracing: Map all PIDs to command lines
+    - tracing: Restructure trace_clock_global() to never block
+    - dm persistent data: packed struct should have an aligned() attribute too
+    - dm space map common: fix division bug in sm_ll_find_free_block()
+    - dm integrity: fix missing goto in bitmap_flush_interval error handling
+    - dm rq: fix double free of blk_mq_tag_set in dev remove after table load
+      fails
+    - Linux 5.4.118
+
+  * Focal update: v5.4.117 upstream stable release (LP: #1928823)
+    - mips: Do not include hi and lo in clobber list for R6
+    - ACPI: tables: x86: Reserve memory occupied by ACPI tables
+    - ACPI: x86: Call acpi_boot_table_init() after acpi_table_upgrade()
+    - net: usb: ax88179_178a: initialize local variables before use
+    - igb: Enable RSS for Intel I211 Ethernet Controller
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_enqueue_hcmd()
+    - bpf: Fix masking negation logic upon negative dst register
+    - bpf: Fix leakage of uninitialized bpf stack under speculation
+    - avoid __memcat_p link failure
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_gen2_enqueue_hcmd()
+    - perf data: Fix error return code in perf_data__create_dir()
+    - perf ftrace: Fix access to pid in array when setting a pid filter
+    - ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX
+    - USB: Add reset-resume quirk for WD19's Realtek Hub
+    - platform/x86: thinkpad_acpi: Correct thermal sensor allocation
+    - scsi: ufs: Unlock on a couple error paths
+    - ovl: allow upperdir inside lowerdir
+    - perf/core: Fix unconditional security_locked_down() call
+    - vfio: Depend on MMU
+    - Linux 5.4.117
+
+  * r8152 tx status -71 (LP: #1922651) // Focal update: v5.4.117 upstream stable
+    release (LP: #1928823)
+    - USB: Add LPM quirk for Lenovo ThinkPad USB-C Dock Gen2 Ethernet
+
+  * Focal update: v5.4.116 upstream stable release (LP: #1928821)
+    - bpf: Move off_reg into sanitize_ptr_alu
+    - bpf: Ensure off_reg has no mixed signed bounds for all types
+    - bpf: Rework ptr_limit into alu_limit and add common error path
+    - bpf: Improve verifier error messages for users
+    - bpf: Refactor and streamline bounds check into helper
+    - bpf: Move sanitize_val_alu out of op switch
+    - bpf: Tighten speculative pointer arithmetic mask
+    - bpf: Update selftests to reflect new error states
+    - Linux 5.4.116
+
+  * Focal update: v5.4.115 upstream stable release (LP: #1927997)
+    - gpio: omap: Save and restore sysconfig
+    - pinctrl: lewisburg: Update number of pins in community
+    - arm64: dts: allwinner: Revert SD card CD GPIO for Pine64-LTS
+    - perf/x86/intel/uncore: Remove uncore extra PCI dev HSWEP_PCI_PCU_3
+    - perf/x86/kvm: Fix Broadwell Xeon stepping in isolation_ucodes[]
+    - perf auxtrace: Fix potential NULL pointer dereference
+    - HID: google: add don USB id
+    - HID: alps: fix error return code in alps_input_configured()
+    - HID: wacom: Assign boolean values to a bool variable
+    - ARM: dts: Fix swapped mmc order for omap3
+    - net: geneve: check skb is large enough for IPv4/IPv6 header
+    - s390/entry: save the caller of psw_idle
+    - xen-netback: Check for hotplug-status existence before watching
+    - cavium/liquidio: Fix duplicate argument
+    - csky: change a Kconfig symbol name to fix e1000 build error
+    - ia64: fix discontig.c section mismatches
+    - ia64: tools: remove duplicate definition of ia64_mf() on ia64
+    - x86/crash: Fix crash_setup_memmap_entries() out-of-bounds access
+    - net: hso: fix NULL-deref on disconnect regression
+    - USB: CDC-ACM: fix poison/unpoison imbalance
+    - Linux 5.4.115
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 28 May 2021 18:14:26 +0200
+
+linux (5.4.0-74.83) focal; urgency=medium
+
+  * focal/linux: 5.4.0-74.83 -proposed tracker (LP: #1927619)
+
+  * Introduce the 465 driver series, fabric-manager, and libnvidia-nscq
+    (LP: #1925522)
+    - debian/dkms-versions -- add NVIDIA 465 and migrate 450 to 460
+
+  * linux-image-5.0.0-35-generic breaks checkpointing of container
+    (LP: #1857257)
+    - SAUCE: overlayfs: fix incorrect mnt_id of files opened from map_files
+
+  * Enable CIFS GCM256 (LP: #1921916)
+    - smb3: add defines for new crypto algorithms
+    - smb3.1.1: add new module load parm require_gcm_256
+    - smb3.1.1: add new module load parm enable_gcm_256
+    - smb3.1.1: print warning if server does not support requested encryption type
+    - smb3.1.1: rename nonces used for GCM and CCM encryption
+    - smb3.1.1: set gcm256 when requested
+    - cifs: Adjust key sizes and key generation routines for AES256 encryption
+
+  * locking/qrwlock: Fix ordering in queued_write_lock_slowpath() (LP: #1926184)
+    - locking/qrwlock: Fix ordering in queued_write_lock_slowpath()
+
+  * [Ubuntu 21.04] net/mlx5: Fix HW spec violation configuring uplink
+    (LP: #1925452)
+    - net/mlx5: Fix HW spec violation configuring uplink
+
+  * Focal update: v5.4.114 upstream stable release (LP: #1926493)
+    - Revert "scsi: qla2xxx: Retry PLOGI on FC-NVMe PRLI failure"
+    - Revert "scsi: qla2xxx: Fix stuck login session using prli_pend_timer"
+    - scsi: qla2xxx: Dual FCP-NVMe target port support
+    - scsi: qla2xxx: Fix device connect issues in P2P configuration
+    - scsi: qla2xxx: Retry PLOGI on FC-NVMe PRLI failure
+    - scsi: qla2xxx: Add a shadow variable to hold disc_state history of fcport
+    - scsi: qla2xxx: Fix stuck login session using prli_pend_timer
+    - scsi: qla2xxx: Fix fabric scan hang
+    - net/sctp: fix race condition in sctp_destroy_sock
+    - Input: nspire-keypad - enable interrupts only when opened
+    - gpio: sysfs: Obey valid_mask
+    - dmaengine: dw: Make it dependent to HAS_IOMEM
+    - ARM: dts: Drop duplicate sha2md5_fck to fix clk_disable race
+    - ARM: dts: Fix moving mmc devices with aliases for omap4 & 5
+    - lockdep: Add a missing initialization hint to the "INFO: Trying to register
+      non-static key" message
+    - arc: kernel: Return -EFAULT if copy_to_user() fails
+    - ASoC: max98373: Added 30ms turn on/off time delay
+    - neighbour: Disregard DEAD dst in neigh_update
+    - ARM: keystone: fix integer overflow warning
+    - ARM: omap1: fix building with clang IAS
+    - drm/msm: Fix a5xx/a6xx timestamps
+    - ASoC: fsl_esai: Fix TDM slot setup for I2S mode
+    - scsi: scsi_transport_srp: Don't block target in SRP_PORT_LOST state
+    - net: ieee802154: stop dump llsec keys for monitors
+    - net: ieee802154: forbid monitor for add llsec key
+    - net: ieee802154: forbid monitor for del llsec key
+    - net: ieee802154: stop dump llsec devs for monitors
+    - net: ieee802154: forbid monitor for add llsec dev
+    - net: ieee802154: forbid monitor for del llsec dev
+    - net: ieee802154: stop dump llsec devkeys for monitors
+    - net: ieee802154: forbid monitor for add llsec devkey
+    - net: ieee802154: forbid monitor for del llsec devkey
+    - net: ieee802154: stop dump llsec seclevels for monitors
+    - net: ieee802154: forbid monitor for add llsec seclevel
+    - pcnet32: Use pci_resource_len to validate PCI resource
+    - mac80211: clear sta->fast_rx when STA removed from 4-addr VLAN
+    - virt_wifi: Return micros for BSS TSF values
+    - Input: s6sy761 - fix coordinate read bit shift
+    - Input: i8042 - fix Pegatron C15B ID entry
+    - HID: wacom: set EV_KEY and EV_ABS only for non-HID_GENERIC type of devices
+    - dm verity fec: fix misaligned RS roots IO
+    - readdir: make sure to verify directory entry for legacy interfaces too
+    - arm64: fix inline asm in load_unaligned_zeropad()
+    - arm64: alternatives: Move length validation in alternative_{insn, endif}
+    - vfio/pci: Add missing range check in vfio_pci_mmap
+    - riscv: Fix spelling mistake "SPARSEMEM" to "SPARSMEM"
+    - scsi: libsas: Reset num_scatter if libata marks qc as NODATA
+    - netfilter: conntrack: do not print icmpv6 as unknown via /proc
+    - libnvdimm/region: Fix nvdimm_has_flush() to handle ND_REGION_ASYNC
+    - netfilter: bridge: add pre_exit hooks for ebtable unregistration
+    - netfilter: arp_tables: add pre_exit hook for table unregister
+    - net: macb: fix the restore of cmp registers
+    - netfilter: nft_limit: avoid possible divide error in nft_limit_init
+    - net: davicom: Fix regulator not turned off on failed probe
+    - net: sit: Unregister catch-all devices
+    - net: ip6_tunnel: Unregister catch-all devices
+    - i40e: fix the panic when running bpf in xdpdrv mode
+    - ibmvnic: avoid calling napi_disable() twice
+    - ibmvnic: remove duplicate napi_schedule call in do_reset function
+    - ibmvnic: remove duplicate napi_schedule call in open function
+    - gro: ensure frag0 meets IP header alignment
+    - ARM: footbridge: fix PCI interrupt mapping
+    - arm64: dts: allwinner: Fix SD card CD GPIO for SOPine systems
+    - r8169: remove fiddling with the PCIe max read request size
+    - r8169: simplify setting PCI_EXP_DEVCTL_NOSNOOP_EN
+    - r8169: fix performance regression related to PCIe max read request size
+    - r8169: improve rtl_jumbo_config
+    - r8169: tweak max read request size for newer chips also in jumbo mtu mode
+    - r8169: don't advertise pause in jumbo mode
+    - ARM: 9071/1: uprobes: Don't hook on thumb instructions
+    - net: phy: marvell: fix detection of PHY on Topaz switches
+    - Linux 5.4.114
+
+  * Focal update: v5.4.113 upstream stable release (LP: #1926490)
+    - interconnect: core: fix error return code of icc_link_destroy()
+    - KVM: arm64: Hide system instruction access to Trace registers
+    - KVM: arm64: Disable guest access to trace filter controls
+    - drm/imx: imx-ldb: fix out of bounds array access warning
+    - gfs2: report "already frozen/thawed" errors
+    - drm/tegra: dc: Don't set PLL clock to 0Hz
+    - block: only update parent bi_status when bio fail
+    - radix tree test suite: Register the main thread with the RCU library
+    - idr test suite: Take RCU read lock in idr_find_test_1
+    - idr test suite: Create anchor before launching throbber
+    - riscv,entry: fix misaligned base for excp_vect_table
+    - block: don't ignore REQ_NOWAIT for direct IO
+    - netfilter: x_tables: fix compat match/target pad out-of-bound write
+    - driver core: Fix locking bug in deferred_probe_timeout_work_func()
+    - perf tools: Use %define api.pure full instead of %pure-parser
+    - perf tools: Use %zd for size_t printf formats on 32-bit
+    - perf map: Tighten snprintf() string precision to pass gcc check on some
+      32-bit arches
+    - xen/events: fix setting irq affinity
+    - Linux 5.4.113
+
+  * Focal update: v5.4.112 upstream stable release (LP: #1926489)
+    - counter: stm32-timer-cnt: fix ceiling miss-alignment with reload register
+    - ALSA: aloop: Fix initialization of controls
+    - ALSA: hda/realtek: Fix speaker amp setup on Acer Aspire E1
+    - ASoC: intel: atom: Stop advertising non working S24LE support
+    - nfc: fix refcount leak in llcp_sock_bind()
+    - nfc: fix refcount leak in llcp_sock_connect()
+    - nfc: fix memory leak in llcp_sock_connect()
+    - nfc: Avoid endless loops caused by repeated llcp_sock_connect()
+    - xen/evtchn: Change irq_info lock to raw_spinlock_t
+    - net: ipv6: check for validity before dereferencing cfg->fc_nlinfo.nlh
+    - net: dsa: lantiq_gswip: Let GSWIP automatically set the xMII clock
+    - drm/i915: Fix invalid access to ACPI _DSM objects
+    - gcov: re-fix clang-11+ support
+    - ia64: fix user_stack_pointer() for ptrace()
+    - nds32: flush_dcache_page: use page_mapping_file to avoid races with swapoff
+    - ocfs2: fix deadlock between setattr and dio_end_io_write
+    - fs: direct-io: fix missing sdio->boundary
+    - parisc: parisc-agp requires SBA IOMMU driver
+    - parisc: avoid a warning on u8 cast for cmpxchg on u8 pointers
+    - ARM: dts: turris-omnia: configure LED[2]/INTn pin as interrupt pin
+    - batman-adv: initialize "struct batadv_tvlv_tt_vlan_data"->reserved field
+    - ice: Increase control queue timeout
+    - ice: Fix for dereference of NULL pointer
+    - ice: Cleanup fltr list in case of allocation issues
+    - net: hso: fix null-ptr-deref during tty device unregistration
+    - ethernet/netronome/nfp: Fix a use after free in nfp_bpf_ctrl_msg_rx
+    - bpf, sockmap: Fix sk->prot unhash op reset
+    - net: ensure mac header is set in virtio_net_hdr_to_skb()
+    - i40e: Fix sparse warning: missing error code 'err'
+    - i40e: Fix sparse error: 'vsi->netdev' could be null
+    - net: sched: sch_teql: fix null-pointer dereference
+    - mac80211: fix TXQ AC confusion
+    - net: hsr: Reset MAC header for Tx path
+    - net-ipv6: bugfix - raw & sctp - switch to ipv6_can_nonlocal_bind()
+    - net: let skb_orphan_partial wake-up waiters.
+    - usbip: add sysfs_lock to synchronize sysfs code paths
+    - usbip: stub-dev synchronize sysfs code paths
+    - usbip: vudc synchronize sysfs code paths
+    - usbip: synchronize event handler with sysfs code paths
+    - i2c: turn recovery error on init to debug
+    - virtio_net: Add XDP meta data support
+    - net: dsa: lantiq_gswip: Don't use PHY auto polling
+    - net: dsa: lantiq_gswip: Configure all remaining GSWIP_MII_CFG bits
+    - xfrm: interface: fix ipv4 pmtu check to honor ip header df
+    - regulator: bd9571mwv: Fix AVS and DVFS voltage range
+    - net: xfrm: Localize sequence counter per network namespace
+    - esp: delete NETIF_F_SCTP_CRC bit from features for esp offload
+    - ASoC: SOF: Intel: hda: remove unnecessary parentheses
+    - ASoC: SOF: Intel: HDA: fix core status verification
+    - ASoC: wm8960: Fix wrong bclk and lrclk with pll enabled for some chips
+    - xfrm: Fix NULL pointer dereference on policy lookup
+    - i40e: Added Asym_Pause to supported link modes
+    - i40e: Fix kernel oops when i40e driver removes VF's
+    - hostfs: Use kasprintf() instead of fixed buffer formatting
+    - hostfs: fix memory handling in follow_link()
+    - amd-xgbe: Update DMA coherency values
+    - sch_red: fix off-by-one checks in red_check_params()
+    - arm64: dts: imx8mm/q: Fix pad control of SD1_DATA0
+    - can: bcm/raw: fix msg_namelen values depending on CAN_REQUIRED_SIZE
+    - gianfar: Handle error code at MAC address change
+    - cxgb4: avoid collecting SGE_QBASE regs during traffic
+    - net:tipc: Fix a double free in tipc_sk_mcast_rcv
+    - ARM: dts: imx6: pbab01: Set vmmc supply for both SD interfaces
+    - net/ncsi: Avoid channel_monitor hrtimer deadlock
+    - nfp: flower: ignore duplicate merge hints from FW
+    - net: phy: broadcom: Only advertise EEE for supported modes
+    - ASoC: sunxi: sun4i-codec: fill ASoC card owner
+    - net/mlx5e: Fix ethtool indication of connector type
+    - net/mlx5: Don't request more than supported EQs
+    - net/rds: Fix a use after free in rds_message_map_pages
+    - soc/fsl: qbman: fix conflicting alignment attributes
+    - i40e: Fix display statistics for veb_tc
+    - drm/msm: Set drvdata to NULL when msm_drm_init() fails
+    - net: udp: Add support for getsockopt(..., ..., UDP_GRO, ..., ...);
+    - scsi: ufs: Fix irq return code
+    - scsi: ufs: Avoid busy-waiting by eliminating tag conflicts
+    - scsi: ufs: Use blk_{get,put}_request() to allocate and free TMFs
+    - scsi: ufs: core: Fix task management request completion timeout
+    - scsi: ufs: core: Fix wrong Task Tag used in task management request UPIUs
+    - net: macb: restore cmp registers on resume path
+    - clk: fix invalid usage of list cursor in register
+    - clk: fix invalid usage of list cursor in unregister
+    - workqueue: Move the position of debug_work_activate() in __queue_work()
+    - s390/cpcmd: fix inline assembly register clobbering
+    - perf inject: Fix repipe usage
+    - net: openvswitch: conntrack: simplify the return expression of
+      ovs_ct_limit_get_default_limit()
+    - openvswitch: fix send of uninitialized stack memory in ct limit reply
+    - net: hns3: clear VF down state bit before request link status
+    - net/mlx5: Fix placement of log_max_flow_counter
+    - net/mlx5: Fix PBMC register mapping
+    - RDMA/cxgb4: check for ipv6 address properly while destroying listener
+    - RDMA/addr: Be strict with gid size
+    - RAS/CEC: Correct ce_add_elem()'s returned values
+    - clk: socfpga: fix iomem pointer cast on 64-bit
+    - dt-bindings: net: ethernet-controller: fix typo in NVMEM
+    - net: sched: bump refcount for new action in ACT replace mode
+    - cfg80211: remove WARN_ON() in cfg80211_sme_connect
+    - net: tun: set tun->dev->addr_len during TUNSETLINK processing
+    - drivers: net: fix memory leak in atusb_probe
+    - drivers: net: fix memory leak in peak_usb_create_dev
+    - net: mac802154: Fix general protection fault
+    - net: ieee802154: nl-mac: fix check on panid
+    - net: ieee802154: fix nl802154 del llsec key
+    - net: ieee802154: fix nl802154 del llsec dev
+    - net: ieee802154: fix nl802154 add llsec key
+    - net: ieee802154: fix nl802154 del llsec devkey
+    - net: ieee802154: forbid monitor for set llsec params
+    - net: ieee802154: forbid monitor for del llsec seclevel
+    - net: ieee802154: stop dump llsec params for monitors
+    - Linux 5.4.112
+
+  * crash utility fails on arm64 with  cannot determine VA_BITS_ACTUAL
+    (LP: #1919275)
+    - arm64/crash_core: Export TCR_EL1.T1SZ in vmcoreinfo
+
+  * Focal update: v5.4.111 upstream stable release (LP: #1923874)
+    - ARM: dts: am33xx: add aliases for mmc interfaces
+    - bus: ti-sysc: Fix warning on unbind if reset is not deasserted
+    - platform/x86: intel-hid: Support Lenovo ThinkPad X1 Tablet Gen 2
+    - bpf, x86: Use kvmalloc_array instead kmalloc_array in bpf_jit_comp
+    - net/mlx5e: Enforce minimum value check for ICOSQ size
+    - net: pxa168_eth: Fix a potential data race in pxa168_eth_remove
+    - mISDN: fix crash in fritzpci
+    - mac80211: choose first enabled channel for monitor
+    - drm/msm/adreno: a5xx_power: Don't apply A540 lm_setup to other GPUs
+    - drm/msm: Ratelimit invalid-fence message
+    - netfilter: conntrack: Fix gre tunneling over ipv6
+    - platform/x86: thinkpad_acpi: Allow the FnLock LED to change state
+    - x86/build: Turn off -fcf-protection for realmode targets
+    - scsi: target: pscsi: Clean up after failure in pscsi_map_sg()
+    - ia64: mca: allocate early mca with GFP_ATOMIC
+    - ia64: fix format strings for err_inject
+    - cifs: revalidate mapping when we open files for SMB1 POSIX
+    - cifs: Silently ignore unknown oplock break handle
+    - nvme-mpath: replace direct_make_request with generic_make_request
+    - init/Kconfig: make COMPILE_TEST depend on !S390
+    - init/Kconfig: make COMPILE_TEST depend on HAS_IOMEM
+    - Linux 5.4.111
+
+  * Focal update: v5.4.110 upstream stable release (LP: #1923869)
+    - selinux: vsock: Set SID for socket returned by accept()
+    - ipv6: weaken the v4mapped source check
+    - modsign: print module name along with error message
+    - module: merge repetitive strings in module_sig_check()
+    - module: avoid *goto*s in module_sig_check()
+    - module: harden ELF info handling
+    - ext4: shrink race window in ext4_should_retry_alloc()
+    - ext4: fix bh ref count on error paths
+    - fs: nfsd: fix kconfig dependency warning for NFSD_V4
+    - rpc: fix NULL dereference on kmalloc failure
+    - iomap: Fix negative assignment to unsigned sis->pages in
+      iomap_swapfile_activate
+    - ASoC: rt5640: Fix dac- and adc- vol-tlv values being off by a factor of 10
+    - ASoC: rt5651: Fix dac- and adc- vol-tlv values being off by a factor of 10
+    - ASoC: sgtl5000: set DAP_AVC_CTRL register to correct default value on probe
+    - ASoC: es8316: Simplify adc_pga_gain_tlv table
+    - ASoC: cs42l42: Fix Bitclock polarity inversion
+    - ASoC: cs42l42: Fix channel width support
+    - ASoC: cs42l42: Fix mixer volume control
+    - ASoC: cs42l42: Always wait at least 3ms after reset
+    - NFSD: fix error handling in NFSv4.0 callbacks
+    - powerpc: Force inlining of cpu_has_feature() to avoid build failure
+    - vhost: Fix vhost_vq_reset()
+    - scsi: st: Fix a use after free in st_open()
+    - scsi: qla2xxx: Fix broken #endif placement
+    - staging: comedi: cb_pcidas: fix request_irq() warn
+    - staging: comedi: cb_pcidas64: fix request_irq() warn
+    - ASoC: rt5659: Update MCLK rate in set_sysclk()
+    - thermal/core: Add NULL pointer check before using cooling device stats
+    - locking/ww_mutex: Simplify use_ww_ctx & ww_ctx handling
+    - ext4: do not iput inode under running transaction in ext4_rename()
+    - net: mvpp2: fix interrupt mask/unmask skip condition
+    - flow_dissector: fix TTL and TOS dissection on IPv4 fragments
+    - can: dev: move driver related infrastructure into separate subdir
+    - net: introduce CAN specific pointer in the struct net_device
+    - can: tcan4x5x: fix max register value
+    - brcmfmac: clear EAP/association status bits on linkdown events
+    - ath10k: hold RCU lock when calling ieee80211_find_sta_by_ifaddr()
+    - net: ethernet: aquantia: Handle error cleanup of start on open
+    - appletalk: Fix skb allocation size in loopback case
+    - net: wan/lmc: unregister device when no matching device is found
+    - bpf: Remove MTU check in __bpf_skb_max_len
+    - ALSA: usb-audio: Apply sample rate quirk to Logitech Connect
+    - ALSA: hda: Re-add dropped snd_poewr_change_state() calls
+    - ALSA: hda: Add missing sanity checks in PM prepare/complete callbacks
+    - ALSA: hda/realtek: fix a determine_headset_type issue for a Dell AIO
+    - ALSA: hda/realtek: call alc_update_headset_mode() in hp_automute_hook
+    - xtensa: move coprocessor_flush to the .text section
+    - PM: runtime: Fix race getting/putting suppliers at probe
+    - PM: runtime: Fix ordering in pm_runtime_get_suppliers()
+    - tracing: Fix stack trace event size
+    - mm: fix race by making init_zero_pfn() early_initcall
+    - drm/amdgpu: fix offset calculation in amdgpu_vm_bo_clear_mappings()
+    - drm/amdgpu: check alignment on CPU page for bo map
+    - reiserfs: update reiserfs_xattrs_initialized() condition
+    - vfio/nvlink: Add missing SPAPR_TCE_IOMMU depends
+    - pinctrl: rockchip: fix restore error in resume
+    - extcon: Add stubs for extcon_register_notifier_all() functions
+    - extcon: Fix error handling in extcon_dev_register
+    - firewire: nosy: Fix a use-after-free bug in nosy_ioctl()
+    - usbip: vhci_hcd fix shift out-of-bounds in vhci_hub_control()
+    - USB: quirks: ignore remote wake-up on Fibocom L850-GL LTE modem
+    - usb: musb: Fix suspend with devices connected for a64
+    - usb: xhci-mtk: fix broken streams issue on 0.96 xHCI
+    - cdc-acm: fix BREAK rx code path adding necessary calls
+    - USB: cdc-acm: untangle a circular dependency between callback and softint
+    - USB: cdc-acm: downgrade message to debug
+    - USB: cdc-acm: fix double free on probe failure
+    - USB: cdc-acm: fix use-after-free after probe failure
+    - usb: gadget: udc: amd5536udc_pci fix null-ptr-dereference
+    - usb: dwc2: Fix HPRT0.PrtSusp bit setting for HiKey 960 board.
+    - usb: dwc2: Prevent core suspend when port connection flag is 0
+    - staging: rtl8192e: Fix incorrect source in memcpy()
+    - staging: rtl8192e: Change state information from u16 to u8
+    - drivers: video: fbcon: fix NULL dereference in fbcon_cursor()
+    - Linux 5.4.110
+
+  * Focal update: v5.4.109 upstream stable release (LP: #1923220)
+    - hugetlbfs: hugetlb_fault_mutex_hash() cleanup
+    - net: fec: ptp: avoid register access when ipg clock is disabled
+    - powerpc/4xx: Fix build errors from mfdcr()
+    - atm: eni: dont release is never initialized
+    - atm: lanai: dont run lanai_dev_close if not open
+    - Revert "r8152: adjust the settings about MAC clock speed down for RTL8153"
+    - ALSA: hda: ignore invalid NHLT table
+    - ixgbe: Fix memleak in ixgbe_configure_clsu32
+    - net: tehuti: fix error return code in bdx_probe()
+    - net: intel: iavf: fix error return code of iavf_init_get_resources()
+    - sun/niu: fix wrong RXMAC_BC_FRM_CNT_COUNT count
+    - gianfar: fix jumbo packets+napi+rx overrun crash
+    - cifs: ask for more credit on async read/write code paths
+    - cpufreq: blacklist Arm Vexpress platforms in cpufreq-dt-platdev
+    - gpiolib: acpi: Add missing IRQF_ONESHOT
+    - nfs: fix PNFS_FLEXFILE_LAYOUT Kconfig default
+    - NFS: Correct size calculation for create reply length
+    - net: hisilicon: hns: fix error return code of hns_nic_clear_all_rx_fetch()
+    - net: wan: fix error return code of uhdlc_init()
+    - net: davicom: Use platform_get_irq_optional()
+    - atm: uPD98402: fix incorrect allocation
+    - atm: idt77252: fix null-ptr-dereference
+    - cifs: change noisy error message to FYI
+    - irqchip/ingenic: Add support for the JZ4760
+    - sparc64: Fix opcode filtering in handling of no fault loads
+    - habanalabs: Call put_pid() when releasing control device
+    - u64_stats,lockdep: Fix u64_stats_init() vs lockdep
+    - regulator: qcom-rpmh: Correct the pmic5_hfsmps515 buck
+    - drm/amd/display: Revert dram_clock_change_latency for DCN2.1
+    - drm/amdgpu: fb BO should be ttm_bo_type_device
+    - drm/radeon: fix AGP dependency
+    - nvme: add NVME_REQ_CANCELLED flag in nvme_cancel_request()
+    - nvme-fc: return NVME_SC_HOST_ABORTED_CMD when a command has been aborted
+    - nvme-pci: add the DISABLE_WRITE_ZEROES quirk for a Samsung PM1725a
+    - nfs: we don't support removing system.nfs4_acl
+    - block: Suppress uevent for hidden device when removed
+    - ia64: fix ia64_syscall_get_set_arguments() for break-based syscalls
+    - ia64: fix ptrace(PTRACE_SYSCALL_INFO_EXIT) sign
+    - netsec: restore phy power state after controller reset
+    - platform/x86: intel-vbtn: Stop reporting SW_DOCK events
+    - squashfs: fix inode lookup sanity checks
+    - squashfs: fix xattr id and id lookup sanity checks
+    - kasan: fix per-page tags for non-page_alloc pages
+    - gcov: fix clang-11+ support
+    - ACPI: video: Add missing callback back for Sony VPCEH3U1E
+    - arm64: dts: ls1046a: mark crypto engine dma coherent
+    - arm64: dts: ls1012a: mark crypto engine dma coherent
+    - arm64: dts: ls1043a: mark crypto engine dma coherent
+    - ARM: dts: at91-sama5d27_som1: fix phy address to 7
+    - integrity: double check iint_cache was initialized
+    - dm verity: fix DM_VERITY_OPTS_MAX value
+    - dm ioctl: fix out of bounds array access when no devices
+    - bus: omap_l3_noc: mark l3 irqs as IRQF_NO_THREAD
+    - veth: Store queue_mapping independently of XDP prog presence
+    - libbpf: Fix INSTALL flag order
+    - net/mlx5e: Don't match on Geneve options in case option masks are all zero
+    - ipv6: fix suspecious RCU usage warning
+    - macvlan: macvlan_count_rx() needs to be aware of preemption
+    - net: sched: validate stab values
+    - net: dsa: bcm_sf2: Qualify phydev->dev_flags based on port
+    - igc: Fix Pause Frame Advertising
+    - igc: Fix Supported Pause Frame Link Setting
+    - e1000e: add rtnl_lock() to e1000_reset_task
+    - e1000e: Fix error handling in e1000_set_d0_lplu_state_82571
+    - net/qlcnic: Fix a use after free in qlcnic_83xx_get_minidump_template
+    - ftgmac100: Restart MAC HW once
+    - selftests/bpf: Set gopt opt_class to 0 if get tunnel opt failed
+    - netfilter: ctnetlink: fix dump of the expect mask attribute
+    - tcp: relookup sock for RST+ACK packets handled by obsolete req sock
+    - can: peak_usb: add forgotten supported devices
+    - can: flexcan: flexcan_chip_freeze(): fix chip freeze for missing bitrate
+    - can: kvaser_pciefd: Always disable bus load reporting
+    - can: c_can_pci: c_can_pci_remove(): fix use-after-free
+    - can: c_can: move runtime PM enable/disable to c_can_platform
+    - can: m_can: m_can_do_rx_poll(): fix extraneous msg loss warning
+    - can: m_can: m_can_rx_peripheral(): fix RX being blocked by errors
+    - mac80211: fix rate mask reset
+    - nfp: flower: fix pre_tun mask id allocation
+    - libbpf: Use SOCK_CLOEXEC when opening the netlink socket
+    - octeontx2-af: Fix irq free in rvu teardown
+    - octeontx2-af: fix infinite loop in unmapping NPC counter
+    - net: cdc-phonet: fix data-interface release on probe failure
+    - r8152: limit the RX buffer size of RTL8153A for USB 2.0
+    - net: stmmac: dwmac-sun8i: Provide TX and RX fifo sizes
+    - selftests: forwarding: vxlan_bridge_1d: Fix vxlan ecn decapsulate value
+    - libbpf: Fix BTF dump of pointer-to-array-of-struct
+    - drm/msm: fix shutdown hook in case GPU components failed to bind
+    - arm64: kdump: update ppos when reading elfcorehdr
+    - PM: runtime: Defer suspending suppliers
+    - net/mlx5e: Fix error path for ethtool set-priv-flag
+    - PM: EM: postpone creating the debugfs dir till fs_initcall
+    - RDMA/cxgb4: Fix adapter LE hash errors while destroying ipv6 listening
+      server
+    - bpf: Don't do bpf_cgroup_storage_set() for kuprobe/tp programs
+    - ACPI: scan: Rearrange memory allocation in acpi_device_add()
+    - ACPI: scan: Use unique number for instance_no
+    - perf auxtrace: Fix auxtrace queue conflict
+    - block: recalculate segment count for multi-segment discards correctly
+    - scsi: Revert "qla2xxx: Make sure that aborted commands are freed"
+    - scsi: qedi: Fix error return code of qedi_alloc_global_queues()
+    - scsi: mpt3sas: Fix error return code of mpt3sas_base_attach()
+    - locking/mutex: Fix non debug version of mutex_lock_io_nested()
+    - x86/mem_encrypt: Correct physical address calculation in __set_clr_pte_enc()
+    - can: dev: Move device back to init netns on owning netns delete
+    - net: dsa: b53: VLAN filtering is global to all users
+    - net: qrtr: fix a kernel-infoleak in qrtr_recvmsg()
+    - mac80211: fix double free in ibss_leave
+    - ext4: add reclaim checks to xattr code
+    - can: peak_usb: Revert "can: peak_usb: add forgotten supported devices"
+    - xen-blkback: don't leak persistent grants from xen_blkbk_map()
+    - Linux 5.4.109
+
+  * Focal update: v5.4.108 upstream stable release (LP: #1923214)
+    - ASoC: ak4458: Add MODULE_DEVICE_TABLE
+    - ASoC: ak5558: Add MODULE_DEVICE_TABLE
+    - ALSA: dice: fix null pointer dereference when node is disconnected
+    - ALSA: hda/realtek: apply pin quirk for XiaomiNotebook Pro
+    - ALSA: hda: generic: Fix the micmute led init state
+    - ALSA: hda/realtek: Apply headset-mic quirks for Xiaomi Redmibook Air
+    - Revert "PM: runtime: Update device status before letting suppliers suspend"
+    - ARM: 9030/1: entry: omit FP emulation for UND exceptions taken in kernel
+      mode
+    - ARM: 9044/1: vfp: use undef hook for VFP support detection
+    - btrfs: fix race when cloning extent buffer during rewind of an old root
+    - btrfs: fix slab cache flags for free space tree bitmap
+    - ASoC: fsl_ssi: Fix TDM slot setup for I2S mode
+    - ASoC: SOF: Intel: unregister DMIC device on probe error
+    - ASoC: SOF: intel: fix wrong poll bits in dsp power down
+    - ASoC: simple-card-utils: Do not handle device clock
+    - afs: Stop listxattr() from listing "afs.*" attributes
+    - nvme: fix Write Zeroes limitations
+    - nvme-tcp: fix possible hang when failing to set io queues
+    - nvme-tcp: fix a NULL deref when receiving a 0-length r2t PDU
+    - nvmet: don't check iosqes,iocqes for discovery controllers
+    - nfsd: Don't keep looking up unhashed files in the nfsd file cache
+    - NFSD: Repair misuse of sv_lock in 5.10.16-rt30.
+    - svcrdma: disable timeouts on rdma backchannel
+    - vfio: IOMMU_API should be selected
+    - sunrpc: fix refcount leak for rpc auth modules
+    - net/qrtr: fix __netdev_alloc_skb call
+    - kbuild: Fix <linux/version.h> for empty SUBLEVEL or PATCHLEVEL again
+    - riscv: Correct SPARSEMEM configuration
+    - scsi: lpfc: Fix some error codes in debugfs
+    - scsi: myrs: Fix a double free in myrs_cleanup()
+    - counter: stm32-timer-cnt: Report count function when SLAVE_MODE_DISABLED
+    - nvme-rdma: fix possible hang when failing to set io queues
+    - usb-storage: Add quirk to defeat Kindle's automatic unload
+    - usbip: Fix incorrect double assignment to udc->ud.tcp_rx
+    - USB: replace hardcode maximum usb string length by definition
+    - usb: gadget: configfs: Fix KASAN use-after-free
+    - usb: typec: tcpm: Invoke power_supply_changed for tcpm-source-psy-
+    - iio:adc:stm32-adc: Add HAS_IOMEM dependency
+    - iio:adc:qcom-spmi-vadc: add default scale to LR_MUX2_BAT_ID channel
+    - iio: adis16400: Fix an error code in adis16400_initial_setup()
+    - iio: gyro: mpu3050: Fix error handling in mpu3050_trigger_handler
+    - iio: adc: ad7949: fix wrong ADC result due to incorrect bit mask
+    - iio: hid-sensor-humidity: Fix alignment issue of timestamp channel
+    - iio: hid-sensor-prox: Fix scale not correct issue
+    - iio: hid-sensor-temperature: Fix issues of timestamp channel
+    - counter: stm32-timer-cnt: fix ceiling write max value
+    - PCI: rpadlpar: Fix potential drc_name corruption in store functions
+    - perf/x86/intel: Fix a crash caused by zero PEBS status
+    - x86/ioapic: Ignore IRQ2 again
+    - kernel, fs: Introduce and use set_restart_fn() and arch_set_restart_data()
+    - x86: Move TS_COMPAT back to asm/thread_info.h
+    - x86: Introduce TS_COMPAT_RESTART to fix get_nr_restart_syscall()
+    - ext4: find old entry again if failed to rename whiteout
+    - ext4: do not try to set xattr into ea_inode if value is empty
+    - ext4: fix potential error in ext4_do_update_inode
+    - efi: use 32-bit alignment for efi_guid_t literals
+    - firmware/efi: Fix a use after bug in efi_mem_reserve_persistent
+    - genirq: Disable interrupts for force threaded handlers
+    - x86/apic/of: Fix CPU devicetree-node lookups
+    - cifs: Fix preauth hash corruption
+    - Linux 5.4.108
+
+  * Focal update: v5.4.107 upstream stable release (LP: #1923210)
+    - KVM: arm64: nvhe: Save the SPE context early
+    - btrfs: scrub: Don't check free space before marking a block group RO
+    - drm/i915/gvt: Set SNOOP for PAT3 on BXT/APL to workaround GPU BB hang
+    - drm/i915/gvt: Fix mmio handler break on BXT/APL.
+    - drm/i915/gvt: Fix virtual display setup for BXT/APL
+    - drm/i915/gvt: Fix port number for BDW on EDID region setup
+    - drm/i915/gvt: Fix vfio_edid issue for BXT/APL
+    - fuse: fix live lock in fuse_iget()
+    - crypto: x86 - Regularize glue function prototypes
+    - crypto: aesni - Use TEST %reg,%reg instead of CMP $0,%reg
+    - crypto: x86/aes-ni-xts - use direct calls to and 4-way stride
+    - net: dsa: tag_mtk: fix 802.1ad VLAN egress
+    - net: dsa: b53: Support setting learning on port
+    - Linux 5.4.107
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Fri, 07 May 2021 18:45:05 -0600
+
+linux (5.4.0-73.82) focal; urgency=medium
+
+  * focal/linux: 5.4.0-73.82 -proposed tracker (LP: #1923781)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * CIFS DFS entries not accessible with 5.4.0-71.74-generic (LP: #1923670)
+    - Revert "cifs: Set CIFS_MOUNT_USE_PREFIX_PATH flag on setting
+      cifs_sb->prepath."
+
+  * CVE-2021-29650
+    - Revert "netfilter: x_tables: Update remaining dereference to RCU"
+    - Revert "netfilter: x_tables: Switch synchronization to RCU"
+    - netfilter: x_tables: Use correct memory barriers.
+
+  * LRMv4: switch to signing nvidia modules via the Ubuntu Modules signing key
+    (LP: #1918134)
+    - [Packaging] dkms-build{,--nvidia-N} sync back from LRMv4
+
+  * 5.4 kernel: when iommu is on crashdump fails (LP: #1922738)
+    - iommu/vt-d: Refactor find_domain() helper
+    - iommu/vt-d: Add attach_deferred() helper
+    - iommu/vt-d: Move deferred device attachment into helper function
+    - iommu/vt-d: Do deferred attachment in iommu_need_mapping()
+    - iommu/vt-d: Remove deferred_attach_domain()
+    - iommu/vt-d: Simplify check in identity_mapping()
+
+  * Backport mlx5e fix for tunnel offload (LP: #1921769)
+    - net/mlx5e: Check tunnel offload is required before setting SWP
+
+  * Bcache bypasse writeback on caching device with fragmentation (LP: #1900438)
+    - bcache: consider the fragmentation when update the writeback rate
+
+  * Fix implicit declaration warnings for kselftests/memfd test on newer
+    releases (LP: #1910323)
+    - selftests/memfd: Fix implicit declaration warnings
+
+  * net/mlx5e: Add missing capability check for uplink follow (LP: #1921104)
+    - net/mlx5e: Add missing capability check for uplink follow
+
+  * [UBUNUT 21.04] s390/vtime: fix increased steal time accounting
+    (LP: #1921498)
+    - s390/vtime: fix increased steal time accounting
+
+  * Mute/Mic-mute LEDs are not work on HP 850/840/440 G8 Laptops (LP: #1920030)
+    - ALSA: hda/realtek: fix mute/micmute LEDs for HP 840 G8
+    - ALSA: hda/realtek: fix mute/micmute LEDs for HP 440 G8
+    - ALSA: hda/realtek: fix mute/micmute LEDs for HP 850 G8
+
+  * Focal update: v5.4.106 upstream stable release (LP: #1920246)
+    - uapi: nfnetlink_cthelper.h: fix userspace compilation error
+    - powerpc/pseries: Don't enforce MSI affinity with kdump
+    - ath9k: fix transmitting to stations in dynamic SMPS mode
+    - net: Fix gro aggregation for udp encaps with zero csum
+    - net: check if protocol extracted by virtio_net_hdr_set_proto is correct
+    - net: avoid infinite loop in mpls_gso_segment when mpls_hlen == 0
+    - sh_eth: fix TRSCER mask for SH771x
+    - 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
+    - can: flexcan: invoke flexcan_chip_freeze() to enter freeze mode
+    - can: tcan4x5x: tcan4x5x_init(): fix initialization - clear MRAM before
+      entering Normal Mode
+    - tcp: add sanity tests to TCP_QUEUE_SEQ
+    - netfilter: nf_nat: undo erroneous tcp edemux lookup
+    - netfilter: x_tables: gpf inside xt_find_revision()
+    - selftests/bpf: No need to drop the packet when there is no geneve opt
+    - selftests/bpf: Mask bpf_csum_diff() return value to 16 bits in test_verifier
+    - samples, bpf: Add missing munmap in xdpsock
+    - ibmvnic: always store valid MAC address
+    - mt76: dma: do not report truncated frames to mac80211
+    - powerpc/603: Fix protection of user pages mapped with PROT_NONE
+    - mount: fix mounting of detached mounts onto targets that reside on shared
+      mounts
+    - cifs: return proper error code in statfs(2)
+    - Revert "mm, slub: consider rest of partial list if acquire_slab() fails"
+    - net: enetc: don't overwrite the RSS indirection table when initializing
+    - net/mlx4_en: update moderation when config reset
+    - net: stmmac: fix incorrect DMA channel intr enable setting of EQoS v4.10
+    - nexthop: Do not flush blackhole nexthops when loopback goes down
+    - net: sched: avoid duplicates in classes dump
+    - net: usb: qmi_wwan: allow qmimux add/del with master up
+    - netdevsim: init u64 stats for 32bit hardware
+    - cipso,calipso: resolve a number of problems with the DOI refcounts
+    - 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
+    - net: qrtr: fix error return code of qrtr_sendmsg()
+    - ixgbe: fail to create xfrm offload of IPsec tunnel mode SA
+    - net: stmmac: stop each tx channel independently
+    - net: stmmac: fix watchdog timeout during suspend/resume stress test
+    - selftests: forwarding: Fix race condition in mirror installation
+    - perf traceevent: Ensure read cmdlines are null terminated.
+    - net: hns3: fix query vlan mask value error for flow director
+    - net: hns3: fix bug when calculating the TCAM table info
+    - s390/cio: return -EFAULT if copy_to_user() fails again
+    - bnxt_en: reliably allocate IRQ table on reset to avoid crash
+    - drm/compat: Clear bounce structures
+    - drm/shmem-helper: Check for purged buffers in fault handler
+    - drm/shmem-helper: Don't remove the offset in vm_area_struct pgoff
+    - drm: meson_drv add shutdown function
+    - s390/cio: return -EFAULT if copy_to_user() fails
+    - s390/crypto: return -EFAULT if copy_to_user() fails
+    - qxl: Fix uninitialised struct field head.surface_id
+    - sh_eth: fix TRSCER mask for R7S9210
+    - media: usbtv: Fix deadlock on suspend
+    - media: v4l: vsp1: Fix uif null pointer access
+    - media: v4l: vsp1: Fix bru null pointer access
+    - media: rc: compile rc-cec.c into rc-core
+    - [Config] update abi for rc-cec
+    - net: hns3: fix error mask definition of flow director
+    - net: enetc: initialize RFS/RSS memories for unused ports too
+    - net: phy: fix save wrong speed and duplex problem if autoneg is on
+    - i2c: rcar: faster irq code to minimize HW race condition
+    - i2c: rcar: optimize cacheline to minimize HW race condition
+    - udf: fix silent AED tagLocation corruption
+    - 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
+    - Platform: OLPC: Fix probe error handling
+    - powerpc/pci: Add ppc_md.discover_phbs()
+    - spi: stm32: make spurious and overrun interrupts visible
+    - powerpc: improve handling of unrecoverable system reset
+    - powerpc/perf: Record counter overflow always if SAMPLE_IP is unset
+    - HID: logitech-dj: add support for the new lightspeed connection iteration
+    - powerpc/64: Fix stack trace not displaying final frame
+    - iommu/amd: Fix performance counter initialization
+    - sparc32: Limit memblock allocation to low memory
+    - sparc64: Use arch_validate_flags() to validate ADI flag
+    - Input: applespi - don't wait for responses to commands indefinitely.
+    - PCI: xgene-msi: Fix race in installing chained irq handler
+    - PCI: mediatek: Add missing of_node_put() to fix reference leak
+    - kbuild: clamp SUBLEVEL to 255
+    - PCI: Fix pci_register_io_range() memory leak
+    - i40e: Fix memory leak in i40e_probe
+    - s390/smp: __smp_rescan_cpus() - move cpumask away from stack
+    - sysctl.c: fix underflow value setting risk in vm_table
+    - scsi: libiscsi: Fix iscsi_prep_scsi_cmd_pdu() error handling
+    - scsi: target: core: Add cmd length set before cmd complete
+    - scsi: target: core: Prevent underflow for service actions
+    - ALSA: usb: Add Plantronics C320-M USB ctrl msg delay quirk
+    - ALSA: hda/hdmi: Cancel pending works before suspend
+    - ALSA: hda/ca0132: Add Sound BlasterX AE-5 Plus support
+    - ALSA: hda: Drop the BATCH workaround for AMD controllers
+    - ALSA: hda: Flush pending unsolicited events 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
+    - ALSA: usb-audio: Apply the control quirk to Plantronics headsets
+    - Revert 95ebabde382c ("capabilities: Don't allow writing ambiguous v3 file
+      capabilities")
+    - arm64: kasan: fix page_alloc tagging with DEBUG_VIRTUAL
+    - s390/dasd: fix hanging DASD driver unbind
+    - s390/dasd: fix hanging IO request during DASD driver unbind
+    - software node: Fix node registration
+    - mmc: core: Fix partition switch time for eMMC
+    - mmc: cqhci: Fix random crash when remove mmc module/card
+    - Goodix Fingerprint device is not a modem
+    - USB: gadget: u_ether: Fix a configfs return code
+    - usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio
+      slot
+    - usb: gadget: f_uac1: stop playback on function disable
+    - usb: dwc3: qcom: Add missing DWC3 OF node refcount decrement
+    - usb: dwc3: qcom: Honor wakeup enabled/disabled state
+    - USB: usblp: fix a hang in poll() if disconnected
+    - usb: renesas_usbhs: Clear PIPECFG for re-enabling pipe with other EPNUM
+    - usb: xhci: do not perform Soft Retry for some xHCI hosts
+    - xhci: Improve detection of device initiated wake signal.
+    - usb: xhci: Fix ASMedia ASM1042A and ASM3242 DMA addressing
+    - xhci: Fix repeated xhci wake after suspend due to uncleared internal wake
+      state
+    - 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 vudc to check for stream socket
+    - usbip: fix stub_dev usbip_sockfd_store() races leading to gpf
+    - usbip: fix vhci_hcd attach_store() races leading to gpf
+    - usbip: fix vudc usbip_sockfd_store races leading to gpf
+    - misc/pvpanic: Export module FDT device table
+    - misc: fastrpc: restrict user apps from sending kernel RPC messages
+    - 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: ks7010: prevent buffer overflow in ks_wlan_set_scan()
+    - 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
+    - sh_eth: fix TRSCER mask for R7S72100
+    - arm64/mm: Fix pfn_valid() for ZONE_DEVICE based memory
+    - SUNRPC: Set memalloc_nofs_save() for sync tasks
+    - NFS: Don't revalidate the directory permissions on a lookup failure
+    - NFS: Don't gratuitously clear the inode cache when lookup failed
+    - NFSv4.2: fix return value of _nfs4_get_security_label()
+    - block: rsxx: fix error return code of rsxx_pci_probe()
+    - configfs: fix a use-after-free in __configfs_open_file
+    - arm64: mm: use a 48-bit ID map when possible on 52-bit VA builds
+    - hrtimer: Update softirq_expires_next correctly after
+      __hrtimer_get_next_event()
+    - stop_machine: mark helpers __always_inline
+    - include/linux/sched/mm.h: use rcu_dereference in in_vfork()
+    - zram: fix return value on writeback_store
+    - sched/membarrier: fix missing local execution of ipi_sync_rq_state()
+    - powerpc/64s: Fix instruction encoding for lis in ppc_function_entry()
+    - binfmt_misc: fix possible deadlock in bm_register_write
+    - x86/unwind/orc: Disable KASAN checking in the ORC unwinder, part 2
+    - KVM: arm64: Fix exclusive limit for IPA size
+    - nvme: unlink head after removing last namespace
+    - nvme: release namespace head reference on error
+    - KVM: arm64: Ensure I-cache isolation between vcpus of a same VM
+    - KVM: arm64: Reject VM creation when the default IPA size is unsupported
+    - 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 5.4.106
+
+  * Focal update: v5.4.105 upstream stable release (LP: #1920244)
+    - net: dsa: add GRO support via gro_cells
+    - dm table: fix iterate_devices based device capability checks
+    - dm table: fix DAX iterate_devices based device capability checks
+    - dm table: fix zoned iterate_devices based device capability checks
+    - ACPICA: Fix race in generic_serial_bus (I2C) and GPIO op_region parameter
+      handling
+    - iommu/amd: Fix sleeping in atomic in increase_address_space()
+    - mwifiex: pcie: skip cancel_work_sync() on reset failure path
+    - platform/x86: acer-wmi: Cleanup ACER_CAP_FOO defines
+    - platform/x86: acer-wmi: Cleanup accelerometer device handling
+    - platform/x86: acer-wmi: Add new force_caps module parameter
+    - platform/x86: acer-wmi: Add ACER_CAP_SET_FUNCTION_MODE capability flag
+    - platform/x86: acer-wmi: Add support for SW_TABLET_MODE on Switch devices
+    - platform/x86: acer-wmi: Add ACER_CAP_KBD_DOCK quirk for the Aspire Switch
+      10E SW3-016
+    - HID: mf: add support for 0079:1846 Mayflash/Dragonrise USB Gamecube Adapter
+    - media: cx23885: add more quirks for reset DMA on some AMD IOMMU
+    - ACPI: video: Add DMI quirk for GIGABYTE GB-BXBT-2807
+    - ASoC: Intel: bytcr_rt5640: Add quirk for ARCHOS Cesium 140
+    - PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller
+    - misc: eeprom_93xx46: Add quirk to support Microchip 93LC46B eeprom
+    - drm/msm/a5xx: Remove overwriting A5XX_PC_DBG_ECO_CNTL register
+    - mmc: sdhci-of-dwcmshc: set SDHCI_QUIRK2_PRESET_VALUE_BROKEN
+    - HID: i2c-hid: Add I2C_HID_QUIRK_NO_IRQ_AFTER_RESET for ITE8568 EC on Voyo
+      Winpad A15
+    - nvme-pci: mark Seagate Nytro XM1440 as QUIRK_NO_NS_DESC_LIST.
+    - nvme-pci: add quirks for Lexar 256GB SSD
+    - Linux 5.4.105
+
+  * Focal update: v5.4.104 upstream stable release (LP: #1920238)
+    - tpm, tpm_tis: Decorate tpm_tis_gen_interrupt() with request_locality()
+    - tpm, tpm_tis: Decorate tpm_get_timeouts() with request_locality()
+    - btrfs: raid56: simplify tracking of Q stripe presence
+    - btrfs: fix raid6 qstripe kmap
+    - btrfs: validate qgroup inherit for SNAP_CREATE_V2 ioctl
+    - btrfs: free correct amount of space in btrfs_delayed_inode_reserve_metadata
+    - btrfs: unlock extents in btrfs_zero_range in case of quota reservation
+      errors
+    - btrfs: fix warning when creating a directory with smack enabled
+    - PM: runtime: Update device status before letting suppliers suspend
+    - dm bufio: subtract the number of initial sectors in dm_bufio_get_device_size
+    - dm verity: fix FEC for RS roots unaligned to block size
+    - drm/amdgpu: fix parameter error of RREG32_PCIE() in amdgpu_regs_pcie
+    - arm64: ptrace: Fix seccomp of traced syscall -1 (NO_SYSCALL)
+    - crypto - shash: reduce minimum alignment of shash_desc structure
+    - usbip: tools: fix build error for multiple definition
+    - ALSA: ctxfi: cthw20k2: fix mask on conf to allow 4 bits
+    - RDMA/rxe: Fix missing kconfig dependency on CRYPTO
+    - IB/mlx5: Add missing error code
+    - ALSA: hda: intel-nhlt: verify config type
+    - ftrace: Have recordmcount use w8 to read relp->r_info in
+      arm64_is_fake_mcount
+    - rsxx: Return -EFAULT if copy_to_user() fails
+    - r8169: fix resuming from suspend on RTL8105e if machine runs on battery
+    - Linux 5.4.104
+
+  * Focal update: v5.4.103 upstream stable release (LP: #1920235)
+    - net: usb: qmi_wwan: support ZTE P685M modem
+    - nvme-pci: refactor nvme_unmap_data
+    - nvme-pci: fix error unwind in nvme_map_data
+    - arm64 module: set plt* section addresses to 0x0
+    - MIPS: VDSO: Use CLANG_FLAGS instead of filtering out '--target='
+    - JFS: more checks for invalid superblock
+    - udlfb: Fix memory leak in dlfb_usb_probe
+    - media: mceusb: sanity check for prescaler value
+    - erofs: fix shift-out-of-bounds of blkszbits
+    - media: v4l2-ctrls.c: fix shift-out-of-bounds in std_validate
+    - xfs: Fix assert failure in xfs_setattr_size()
+    - net/af_iucv: remove WARN_ONCE on malformed RX packets
+    - smackfs: restrict bytes count in smackfs write functions
+    - net: fix up truesize of cloned skb in skb_prepare_for_shift()
+    - nbd: handle device refs for DESTROY_ON_DISCONNECT properly
+    - mm/hugetlb.c: fix unnecessary address expansion of pmd sharing
+    - net: bridge: use switchdev for port flags set through sysfs too
+    - net: ag71xx: remove unnecessary MTU reservation
+    - net: fix dev_ifsioc_locked() race condition
+    - dt-bindings: ethernet-controller: fix fixed-link specification
+    - dt-bindings: net: btusb: DT fix s/interrupt-name/interrupt-names/
+    - MIPS: Drop 32-bit asm string functions
+    - drm/virtio: use kvmalloc for large allocations
+    - rsi: Fix TX EAPOL packet handling against iwlwifi AP
+    - rsi: Move card interrupt handling to RX thread
+    - 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
+    - Bluetooth: hci_h5: Set HCI_QUIRK_SIMULTANEOUS_DISCOVERY for btrtl
+    - 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
+    - staging: bcm2835-audio: Replace unsafe strcpy() with strscpy()
+    - brcmfmac: Add DMI nvram filename quirk for Predia Basic tablet
+    - brcmfmac: Add DMI nvram filename quirk for Voyo winpad A15 tablet
+    - drm/hisilicon: Fix use-after-free
+    - crypto: tcrypt - avoid signed overflow in byte count
+    - drm/amdgpu: Add check to prevent IH overflow
+    - PCI: Add a REBAR size quirk for Sapphire RX 5600 XT Pulse
+    - drm/amd/display: Guard against NULL pointer deref when get_i2c_info fails
+    - media: uvcvideo: Allow entities with no pads
+    - f2fs: handle unallocated section and zone on pinned/atgc
+    - f2fs: fix to set/clear I_LINKABLE under i_lock
+    - nvme-core: add cancel tagset helpers
+    - nvme-rdma: add clean action for failed reconnection
+    - nvme-tcp: add clean action for failed reconnection
+    - ASoC: Intel: Add DMI quirk table to soc_intel_is_byt_cr()
+    - btrfs: fix error handling in commit_fs_roots
+    - perf/x86/kvm: Add Cascade Lake Xeon steppings to isolation_ucodes[]
+    - parisc: Bump 64-bit IRQ stack size to 64 KB
+    - sched/features: Fix hrtick reprogramming
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Estar Beauty HD MID 7316R
+      tablet
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Voyo Winpad A15 tablet
+    - ASoC: Intel: bytcr_rt5651: Add quirk for the Jumper EZpad 7 tablet
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Acer One S1002 tablet
+    - 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
+    - ALSA: hda/realtek: Add quirk for Clevo NH55RZQ
+    - ALSA: hda/realtek: Add quirk for Intel NUC 10
+    - ALSA: hda/realtek: Apply dual codec quirks for MSI Godlike X570 board
+    - Linux 5.4.103
+
+  * Focal update: v5.4.102 upstream stable release (LP: #1918974)
+    - vmlinux.lds.h: add DWARF v5 sections
+    - kvm: x86: replace kvm_spec_ctrl_test_value with runtime test on the host
+    - debugfs: be more robust at handling improper input in debugfs_lookup()
+    - debugfs: do not attempt to create a new file before the filesystem is
+      initalized
+    - kdb: Make memory allocations more robust
+    - PCI: qcom: Use PHY_REFCLK_USE_PAD only for ipq8064
+    - PCI: Decline to resize resources if boot config must be preserved
+    - virt: vbox: Do not use wait_event_interruptible when called from kernel
+      context
+    - bfq: Avoid false bfq queue merging
+    - ALSA: usb-audio: Fix PCM buffer allocation in non-vmalloc mode
+    - MIPS: vmlinux.lds.S: add missing PAGE_ALIGNED_DATA() section
+    - random: fix the RNDRESEEDCRNG ioctl
+    - ath10k: Fix error handling in case of CE pipe init failure
+    - Bluetooth: btqcomsmd: Fix a resource leak in error handling paths in the
+      probe function
+    - Bluetooth: hci_uart: Fix a race for write_work scheduling
+    - Bluetooth: Fix initializing response id after clearing struct
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Artik 5
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Monk
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Rinato
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Spring
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Arndale Octa
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Odroid XU3 family
+    - arm64: dts: exynos: correct PMIC interrupt trigger level on TM2
+    - arm64: dts: exynos: correct PMIC interrupt trigger level on Espresso
+    - memory: mtk-smi: Fix PM usage counter unbalance in mtk_smi ops
+    - bpf: Add bpf_patch_call_args prototype to include/linux/bpf.h
+    - bpf: Avoid warning when re-casting __bpf_call_base into __bpf_call_base_args
+    - arm64: dts: allwinner: A64: properly connect USB PHY to port 0
+    - arm64: dts: allwinner: H6: properly connect USB PHY to port 0
+    - arm64: dts: allwinner: Drop non-removable from SoPine/LTS SD card
+    - arm64: dts: allwinner: H6: Allow up to 150 MHz MMC bus frequency
+    - arm64: dts: allwinner: A64: Limit MMC2 bus frequency to 150 MHz
+    - cpufreq: brcmstb-avs-cpufreq: Free resources in error path
+    - cpufreq: brcmstb-avs-cpufreq: Fix resource leaks in ->remove()
+    - ACPICA: Fix exception code class checks
+    - usb: gadget: u_audio: Free requests only after callback
+    - Bluetooth: drop HCI device reference before return
+    - Bluetooth: Put HCI device if inquiry procedure interrupts
+    - memory: ti-aemif: Drop child node when jumping out loop
+    - ARM: dts: Configure missing thermal interrupt for 4430
+    - usb: dwc2: Do not update data length if it is 0 on inbound transfers
+    - usb: dwc2: Abort transaction after errors with unknown reason
+    - usb: dwc2: Make "trimming xfer length" a debug message
+    - staging: rtl8723bs: wifi_regd.c: Fix incorrect number of regulatory rules
+    - ARM: dts: armada388-helios4: assign pinctrl to LEDs
+    - ARM: dts: armada388-helios4: assign pinctrl to each fan
+    - arm64: dts: armada-3720-turris-mox: rename u-boot mtd partition to
+      a53-firmware
+    - Bluetooth: btusb: Fix memory leak in btusb_mtk_wmt_recv
+    - arm64: dts: msm8916: Fix reserved and rfsa nodes unit address
+    - ARM: s3c: fix fiq for clang IAS
+    - soc: aspeed: snoop: Add clock control logic
+    - bpf_lru_list: Read double-checked variable once without lock
+    - ath9k: fix data bus crash when setting nf_override via debugfs
+    - ibmvnic: Set to CLOSED state even on error
+    - bnxt_en: reverse order of TX disable and carrier off
+    - xen/netback: fix spurious event detection for common event case
+    - mac80211: fix potential overflow when multiplying to u32 integers
+    - bpf: Fix bpf_fib_lookup helper MTU check for SKB ctx
+    - tcp: fix SO_RCVLOWAT related hangs under mem pressure
+    - net: axienet: Handle deferred probe on clock properly
+    - cxgb4/chtls/cxgbit: Keeping the max ofld immediate data size same in cxgb4
+      and ulds
+    - b43: N-PHY: Fix the update of coef for the PHY revision >= 3case
+    - ibmvnic: add memory barrier to protect long term buffer
+    - ibmvnic: skip send_request_unmap for timeout reset
+    - net: amd-xgbe: Reset the PHY rx data path when mailbox command timeout
+    - net: amd-xgbe: Fix NETDEV WATCHDOG transmit queue timeout warning
+    - net: amd-xgbe: Reset link when the link never comes back
+    - net: amd-xgbe: Fix network fluctuations when using 1G BELFUSE SFP
+    - net: mvneta: Remove per-cpu queue mapping for Armada 3700
+    - fbdev: aty: SPARC64 requires FB_ATY_CT
+    - drm/gma500: Fix error return code in psb_driver_load()
+    - gma500: clean up error handling in init
+    - drm/fb-helper: Add missed unlocks in setcmap_legacy()
+    - crypto: sun4i-ss - linearize buffers content must be kept
+    - crypto: sun4i-ss - fix kmap usage
+    - crypto: arm64/aes-ce - really hide slower algos when faster ones are enabled
+    - drm/amdgpu: Fix macro name _AMDGPU_TRACE_H_ in preprocessor if condition
+    - MIPS: c-r4k: Fix section mismatch for loongson2_sc_init
+    - MIPS: lantiq: Explicitly compare LTQ_EBU_PCC_ISTAT against 0
+    - media: i2c: ov5670: Fix PIXEL_RATE minimum value
+    - media: imx: Unregister csc/scaler only if registered
+    - media: imx: Fix csc/scaler unregister
+    - media: camss: missing error code in msm_video_register()
+    - media: vsp1: Fix an error handling path in the probe function
+    - media: em28xx: Fix use-after-free in em28xx_alloc_urbs
+    - media: media/pci: Fix memleak in empress_init
+    - media: tm6000: Fix memleak in tm6000_start_stream
+    - media: aspeed: fix error return code in aspeed_video_setup_video()
+    - ASoC: cs42l56: fix up error handling in probe
+    - evm: Fix memleak in init_desc
+    - crypto: bcm - Rename struct device_private to bcm_device_private
+    - drm/sun4i: tcon: fix inverted DCLK polarity
+    - MIPS: properly stop .eh_frame generation
+    - bsg: free the request before return error code
+    - drm/amd/display: Fix 10/12 bpc setup in DCE output bit depth reduction.
+    - drm/amd/display: Fix HDMI deep color output for DCE 6-11.
+    - media: software_node: Fix refcounts in software_node_get_next_child()
+    - media: lmedm04: Fix misuse of comma
+    - media: qm1d1c0042: fix error return code in qm1d1c0042_init()
+    - media: cx25821: Fix a bug when reallocating some dma memory
+    - media: pxa_camera: declare variable when DEBUG is defined
+    - media: uvcvideo: Accept invalid bFormatIndex and bFrameIndex values
+    - sched/eas: Don't update misfit status if the task is pinned
+    - mtd: parser: imagetag: fix error codes in
+      bcm963xx_parse_imagetag_partitions()
+    - crypto: talitos - Work around SEC6 ERRATA (AES-CTR mode data size error)
+    - drm/nouveau: bail out of nouveau_channel_new if channel init fails
+    - ata: ahci_brcm: Add back regulators management
+    - ASoC: cpcap: fix microphone timeslot mask
+    - mtd: parsers: afs: Fix freeing the part name memory in failure
+    - f2fs: fix to avoid inconsistent quota data
+    - drm/amdgpu: Prevent shift wrapping in amdgpu_read_mask()
+    - f2fs: fix a wrong condition in __submit_bio
+    - Drivers: hv: vmbus: Avoid use-after-free in vmbus_onoffer_rescind()
+    - ASoC: SOF: debug: Fix a potential issue on string buffer termination
+    - btrfs: clarify error returns values in __load_free_space_cache
+    - hwrng: timeriomem - Fix cooldown period calculation
+    - crypto: ecdh_helper - Ensure 'len >= secret.len' in decode_key()
+    - ima: Free IMA measurement buffer on error
+    - ima: Free IMA measurement buffer after kexec syscall
+    - ASoC: simple-card-utils: Fix device module clock
+    - fs/jfs: fix potential integer overflow on shift of a int
+    - jffs2: fix use after free in jffs2_sum_write_data()
+    - ubifs: Fix memleak in ubifs_init_authentication
+    - ubifs: Fix error return code in alloc_wbufs()
+    - capabilities: Don't allow writing ambiguous v3 file capabilities
+    - HSI: Fix PM usage counter unbalance in ssi_hw_init
+    - clk: meson: clk-pll: fix initializing the old rate (fallback) for a PLL
+    - clk: meson: clk-pll: make "ret" a signed integer
+    - clk: meson: clk-pll: propagate the error from meson_clk_pll_set_rate()
+    - quota: Fix memory leak when handling corrupted quota file
+    - i2c: iproc: handle only slave interrupts which are enabled
+    - i2c: iproc: update slave isr mask (ISR_MASK_SLAVE)
+    - i2c: iproc: handle master read request
+    - spi: cadence-quadspi: Abort read if dummy cycles required are too many
+    - clk: sunxi-ng: h6: Fix CEC clock
+    - HID: core: detect and skip invalid inputs to snto32()
+    - RDMA/siw: Fix handling of zero-sized Read and Receive Queues.
+    - 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
+    - dmaengine: owl-dma: Fix a resource leak in the remove function
+    - dmaengine: hsu: disable spurious interrupt
+    - mfd: bd9571mwv: Use devm_mfd_add_devices()
+    - fdt: Properly handle "no-map" field in the memory region
+    - of/fdt: Make sure no-map does not remove already reserved regions
+    - power: reset: at91-sama5d2_shdwc: fix wkupdbc mask
+    - rtc: s5m: select REGMAP_I2C
+    - clocksource/drivers/ixp4xx: Select TIMER_OF when needed
+    - clocksource/drivers/mxs_timer: Add missing semicolon when DEBUG is defined
+    - RDMA/mlx5: Use the correct obj_id upon DEVX TIR creation
+    - clk: sunxi-ng: h6: Fix clock divider range on some clocks
+    - regulator: axp20x: Fix reference cout leak
+    - certs: Fix blacklist flag type confusion
+    - regulator: s5m8767: Fix reference count leak
+    - spi: atmel: Put allocated master before return
+    - regulator: s5m8767: Drop regulators OF node reference
+    - regulator: core: Avoid debugfs: Directory ... already present! error
+    - isofs: release buffer head before return
+    - auxdisplay: ht16k33: Fix refresh rate handling
+    - objtool: Fix error handling for STD/CLD warnings
+    - objtool: Fix ".cold" section suffix check for newer versions of GCC
+    - IB/umad: Return EIO in case of when device disassociated
+    - IB/umad: Return EPOLLERR in case of when device disassociated
+    - KVM: PPC: Make the VMX instruction emulation routines static
+    - powerpc/47x: Disable 256k page size
+    - mmc: sdhci-sprd: Fix some resource leaks in the remove function
+    - mmc: usdhi6rol0: Fix a resource leak in the error handling path of the probe
+    - mmc: renesas_sdhi_internal_dmac: Fix DMA buffer alignment from 8 to
+      128-bytes
+    - ARM: 9046/1: decompressor: Do not clear SCTLR.nTLSMD for ARMv7+ cores
+    - i2c: qcom-geni: Store DMA mapping data in geni_i2c_dev struct
+    - amba: Fix resource leak for drivers without .remove
+    - IB/mlx5: Return appropriate error code instead of ENOMEM
+    - IB/cm: Avoid a loop when device has 255 ports
+    - tracepoint: Do not fail unregistering a probe due to memory failure
+    - perf tools: Fix DSO filtering when not finding a map for a sampled address
+    - perf vendor events arm64: Fix Ampere eMag event typo
+    - RDMA/rxe: Fix coding error in rxe_recv.c
+    - RDMA/rxe: Fix coding error in rxe_rcv_mcast_pkt
+    - RDMA/rxe: Correct skb on loopback path
+    - spi: stm32: properly handle 0 byte transfer
+    - mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq()
+    - powerpc/pseries/dlpar: handle ibm, configure-connector delay status
+    - powerpc/8xx: Fix software emulation interrupt
+    - clk: qcom: gcc-msm8998: Fix Alpha PLL type for all GPLLs
+    - RDMA/hns: Fixed wrong judgments in the goto branch
+    - RDMA/siw: Fix calculation of tx_valid_cpus size
+    - RDMA/hns: Fix type of sq_signal_bits
+    - spi: pxa2xx: Fix the controller numbering for Wildcat Point
+    - regulator: qcom-rpmh: fix pm8009 ldo7
+    - clk: aspeed: Fix APLL calculate formula from ast2600-A2
+    - nfsd: register pernet ops last, unregister first
+    - RDMA/hns: Fixes missing error code of CMDQ
+    - Input: sur40 - fix an error code in sur40_probe()
+    - perf intel-pt: Fix missing CYC processing in PSB
+    - perf intel-pt: Fix premature IPC
+    - 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
+    - phy: rockchip-emmc: emmc_phy_init() always return 0
+    - misc: eeprom_93xx46: Add module alias to avoid breaking support for non
+      device tree users
+    - soundwire: cadence: fix ACK/NAK handling
+    - pwm: rockchip: rockchip_pwm_probe(): Remove superfluous clk_unprepare()
+    - VMCI: Use set_page_dirty_lock() when unregistering guest memory
+    - PCI: Align checking of syscall user config accessors
+    - mei: hbm: call mei_set_devstate() on hbm stop response
+    - drm/msm/dsi: Correct io_start for MSM8994 (20nm PHY)
+    - drm/msm/mdp5: Fix wait-for-commit for cmd panels
+    - vfio/iommu_type1: Fix some sanity checks in detach group
+    - ext4: fix potential htree index checksum corruption
+    - nvmem: core: Fix a resource leak on error in nvmem_add_cells_from_of()
+    - nvmem: core: skip child nodes not matching binding
+    - regmap: sdw: use _no_pm functions in regmap_read/write
+    - i40e: Fix flow for IPv6 next header (extension header)
+    - i40e: Add zero-initialization of AQ command structures
+    - i40e: Fix overwriting flow control settings during driver loading
+    - i40e: Fix addition of RX filters after enabling FW LLDP agent
+    - i40e: Fix VFs not created
+    - i40e: Fix add TC filter for IPv6
+    - vfio/type1: Use follow_pte()
+    - net/mlx4_core: Add missed mlx4_free_cmd_mailbox()
+    - vxlan: move debug check after netdev unregister
+    - ocfs2: fix a use after free on error
+    - mm/memory.c: fix potential pte_unmap_unlock pte error
+    - mm/hugetlb: fix potential double free in hugetlb_register_node() error path
+    - mm/compaction: fix misbehaviors of fast_find_migrateblock()
+    - r8169: fix jumbo packet handling on RTL8168e
+    - arm64: Add missing ISB after invalidating TLB in __primary_switch
+    - i2c: brcmstb: Fix brcmstd_send_i2c_cmd condition
+    - mm/rmap: fix potential pte_unmap on an not mapped pte
+    - scsi: bnx2fc: Fix Kconfig warning & CNIC build errors
+    - blk-settings: align max_sectors on "logical_block_size" boundary
+    - ACPI: property: Fix fwnode string properties matching
+    - ACPI: configfs: add missing check after configfs_register_default_group()
+    - HID: logitech-dj: add support for keyboard events in eQUAD step 4 Gaming
+    - HID: wacom: Ignore attempts to overwrite the touch_max value from HID
+    - Input: raydium_ts_i2c - do not send zero length
+    - 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
+    - media: mceusb: Fix potential out-of-bounds shift
+    - USB: serial: option: update interface mapping for ZTE P685M
+    - usb: musb: Fix runtime PM race in musb_queue_resume_work
+    - usb: dwc3: gadget: Fix setting of DEPCFG.bInterval_m1
+    - usb: dwc3: gadget: Fix dep->interval for fullspeed interrupt
+    - USB: serial: ftdi_sio: fix FTX sub-integer prescaler
+    - USB: serial: mos7840: fix error code in mos7840_write()
+    - USB: serial: mos7720: fix error code in mos7720_write()
+    - ALSA: hda: Add another CometLake-H PCI ID
+    - ALSA: hda/realtek: modify EAPD in the ALC886
+    - Revert "bcache: Kill btree_io_wq"
+    - bcache: Give btree_io_wq correct semantics again
+    - bcache: Move journal work to new flush wq
+    - drm/amd/display: Add vupdate_no_lock interrupts for DCN2.1
+    - drm/amdgpu: Set reference clock to 100Mhz on Renoir (v2)
+    - drm/nouveau/kms: handle mDP connectors
+    - drm/sched: Cancel and flush all outstanding jobs before finish.
+    - erofs: initialized fields can only be observed after bit is set
+    - tpm_tis: Fix check_locality for correct locality acquisition
+    - tpm_tis: Clean up locality release
+    - KEYS: trusted: Fix migratable=1 failing
+    - btrfs: abort the transaction if we fail to inc ref in btrfs_copy_root
+    - btrfs: fix reloc root leak with 0 ref reloc roots on recovery
+    - btrfs: splice remaining dirty_bg's onto the transaction dirty bg list
+    - btrfs: fix extent buffer leak on failure to copy root
+    - crypto: arm64/sha - add missing module aliases
+    - crypto: aesni - prevent misaligned buffers on the stack
+    - crypto: sun4i-ss - checking sg length is not sufficient
+    - crypto: sun4i-ss - handle BigEndian for cipher
+    - crypto: sun4i-ss - initialize need_fallback
+    - seccomp: Add missing return in non-void function
+    - misc: rtsx: init of rts522a add OCP power off when no card is present
+    - drivers/misc/vmw_vmci: restrict too big queue size in qp_host_alloc_queue
+    - pstore: Fix typo in compression option name
+    - dts64: mt7622: fix slow sd card access
+    - staging/mt7621-dma: mtk-hsdma.c->hsdma-mt7621.c
+    - staging: gdm724x: Fix DMA from stack
+    - staging: rtl8188eu: Add Edimax EW-7811UN V2 to device table
+    - media: ipu3-cio2: Fix mbus_code processing in cio2_subdev_set_fmt()
+    - x86/virt: Eat faults on VMXOFF in reboot flows
+    - x86/reboot: Force all cpus to exit VMX root if VMX is supported
+    - powerpc/prom: Fix "ibm,arch-vec-5-platform-support" scan
+    - rcu: Pull deferred rcuog wake up to rcu_eqs_enter() callers
+    - rcu/nocb: Perform deferred wake up before last idle's need_resched() check
+    - floppy: reintroduce O_NDELAY fix
+    - arm64: kexec_file: fix memory leakage in create_dtb() when fdt_open_into()
+      fails
+    - arm64: uprobe: Return EOPNOTSUPP for AARCH32 instruction probing
+    - watchdog: qcom: Remove incorrect usage of QCOM_WDT_ENABLE_IRQ
+    - watchdog: mei_wdt: request stop on unregister
+    - mtd: spi-nor: sfdp: Fix last erase region marking
+    - mtd: spi-nor: sfdp: Fix wrong erase type bitmask for overlaid region
+    - mtd: spi-nor: core: Fix erase type discovery for overlaid region
+    - mtd: spi-nor: core: Add erase size check for erase command initialization
+    - mtd: spi-nor: hisi-sfc: Put child node np on error path
+    - fs/affs: release old buffer head on error path
+    - seq_file: document how per-entry resources are managed.
+    - x86: fix seq_file iteration for pat/memtype.c
+    - hugetlb: fix update_and_free_page contig page struct assumption
+    - hugetlb: fix copy_huge_page_from_user contig page struct assumption
+    - arm64: Extend workaround for erratum 1024718 to all versions of Cortex-A55
+    - media: smipcie: fix interrupt handling and IR timeout
+    - module: Ignore _GLOBAL_OFFSET_TABLE_ when warning for undefined symbols
+    - mmc: sdhci-esdhc-imx: fix kernel panic when remove module
+    - powerpc/32s: Add missing call to kuep_lock on syscall entry
+    - spmi: spmi-pmic-arb: Fix hw_irq overflow
+    - gpio: pcf857x: Fix missing first interrupt
+    - printk: fix deadlock when kernel panic
+    - cpufreq: intel_pstate: Get per-CPU max freq via MSR_HWP_CAPABILITIES if
+      available
+    - s390/vtime: fix inline assembly clobber list
+    - virtio/s390: implement virtio-ccw revision 2 correctly
+    - um: mm: check more comprehensively for stub changes
+    - f2fs: fix out-of-repair __setattr_copy()
+    - sparc32: fix a user-triggerable oops in clear_user()
+    - spi: spi-synquacer: fix set_cs handling
+    - gfs2: Don't skip dlm unlock if glock has an lvb
+    - gfs2: Recursive gfs2_quota_hold in gfs2_iomap_end
+    - dm: fix deadlock when swapping to encrypted device
+    - dm writecache: fix writing beyond end of underlying device when shrinking
+    - 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
+    - drm/i915: Reject 446-480MHz HDMI clock on GLK
+    - icmp: introduce helper for nat'd source address in network device context
+    - icmp: allow icmpv6_ndo_send to work with CONFIG_IPV6=n
+    - gtp: use icmp_ndo_send helper
+    - sunvnet: use icmp_ndo_send helper
+    - xfrm: interface: use icmp_ndo_send helper
+    - ipv6: icmp6: avoid indirect call for icmpv6_send()
+    - ipv6: silence compilation warning for non-IPV6 builds
+    - net: icmp: pass zeroed opts from icmp{,v6}_ndo_send before sending
+    - net: sched: fix police ext initialization
+    - dm era: Update in-core bitset after committing the metadata
+    - net: qrtr: Fix memory leak in qrtr_tun_open
+    - ARM: dts: aspeed: Add LCLK to lpc-snoop
+    - Linux 5.4.102
+
+  * eeh-basic.sh from powerpc in ubuntu_kernel_selftests failed with unexpected
+    operator on F-5.8 (LP: #1909428)
+    - selftests/powerpc: Make the test check in eeh-basic.sh posix compliant
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 14 Apr 2021 18:35:30 +0200
+
+linux (5.4.0-72.80) focal; urgency=medium
+
+  * overlayfs calls vfs_setxattr without cap_convert_nscap
+    - vfs: move cap_convert_nscap() call into vfs_setxattr()
+
+  * CVE-2021-3492
+    - SAUCE: shiftfs: free allocated memory in shiftfs_btrfs_ioctl_fd_replace()
+      error paths
+    - SAUCE: shiftfs: handle copy_to_user() return values correctly
+
+  * CVE-2021-29154
+    - SAUCE: bpf, x86: Validate computation of branch displacements for x86-64
+    - SAUCE: bpf, x86: Validate computation of branch displacements for x86-32
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 12 Apr 2021 17:12:08 +0200
+
+linux (5.4.0-71.79) focal; urgency=medium
+
+  * focal/linux: 5.4.0-71.79 -proposed tracker (LP: #1921040)
+
+  * selftests: bpf verifier fails after sanitize_ptr_alu fixes (LP: #1920995)
+    - bpf: Simplify alu_limit masking for pointer arithmetic
+    - bpf: Add sanity check for upper ptr_limit
+    - bpf, selftests: Fix up some test_verifier cases for unprivileged
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * Fix missing HDMI/DP audio on NVidia card after S3 (LP: #1918228)
+    - ALSA: hda/hdmi: Reduce hda_jack_tbl lookup at unsol event handling
+    - ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
+    - ALSA: hda/hdmi: Move runtime PM resume into hdmi_present_sense_via_verbs()
+    - ALSA: hda/hdmi: Move ELD parse and jack reporting into update_eld()
+
+  * Focal update: v5.4.101 upstream stable release (LP: #1918170)
+    - HID: make arrays usage and value to be the same
+    - USB: quirks: sort quirk entries
+    - usb: quirks: add quirk to start video capture on ELMO L-12F document camera
+      reliable
+    - ntfs: check for valid standard information attribute
+    - arm64: tegra: Add power-domain for Tegra210 HDA
+    - scripts: use pkg-config to locate libcrypto
+    - scripts: set proper OpenSSL include dir also for sign-file
+    - mm: unexport follow_pte_pmd
+    - mm: simplify follow_pte{,pmd}
+    - KVM: do not assume PTE is writable after follow_pfn
+    - mm: provide a saner PTE walking API for modules
+    - KVM: Use kvm_pfn_t for local PFN variable in hva_to_pfn_remapped()
+    - NET: usb: qmi_wwan: Adding support for Cinterion MV31
+    - cxgb4: Add new T6 PCI device id 0x6092
+    - cifs: Set CIFS_MOUNT_USE_PREFIX_PATH flag on setting cifs_sb->prepath.
+    - scripts/recordmcount.pl: support big endian for ARCH sh
+    - Linux 5.4.101
+
+  * Focal update: v5.4.100 upstream stable release (LP: #1918168)
+    - KVM: SEV: fix double locking due to incorrect backport
+    - net: qrtr: Fix port ID for control messages
+    - net: bridge: Fix a warning when del bridge sysfs
+    - 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()
+    - media: pwc: Use correct device for DMA
+    - btrfs: fix backport of 2175bf57dc952 in 5.4.95
+    - Linux 5.4.100
+
+  * Focal update: v5.4.99 upstream stable release (LP: #1918167)
+    - gpio: ep93xx: fix BUG_ON port F usage
+    - gpio: ep93xx: Fix single irqchip with multi gpiochips
+    - tracing: Do not count ftrace events in top level enable output
+    - tracing: Check length before giving out the filter buffer
+    - arm/xen: Don't probe xenbus as part of an early initcall
+    - cgroup: fix psi monitor for root cgroup
+    - arm64: dts: rockchip: Fix PCIe DT properties on rk3399
+    - arm64: dts: qcom: sdm845: Reserve LPASS clocks in gcc
+    - ARM: OMAP2+: Fix suspcious RCU usage splats for omap_enter_idle_coupled
+    - platform/x86: hp-wmi: Disable tablet-mode reporting by default
+    - ovl: perform vfs_getxattr() with mounter creds
+    - cap: fix conversions on getxattr
+    - ovl: skip getxattr of security labels
+    - nvme-pci: ignore the subsysem NQN on Phison E16
+    - drm/amd/display: Add more Clock Sources to DCN2.1
+    - drm/amd/display: Fix dc_sink kref count in emulated_link_detect
+    - drm/amd/display: Free atomic state after drm_atomic_commit
+    - drm/amd/display: Decrement refcount of dc_sink before reassignment
+    - riscv: virt_addr_valid must check the address belongs to linear mapping
+    - bfq-iosched: Revert "bfq: Fix computation of shallow depth"
+    - ARM: dts: lpc32xx: Revert set default clock rate of HCLK PLL
+    - ARM: ensure the signal page contains defined contents
+    - ARM: kexec: fix oops after TLB are invalidated
+    - vmlinux.lds.h: Create section for protection against instrumentation
+    - lkdtm: don't move ctors to .rodata
+    - mt76: dma: fix a possible memory leak in mt76_add_fragment()
+    - drm/vc4: hvs: Fix buffer overflow with the dlist handling
+    - bpf: Check for integer overflow when using roundup_pow_of_two()
+    - netfilter: xt_recent: Fix attempt to update deleted entry
+    - netfilter: nftables: fix possible UAF over chains from packet path in netns
+    - netfilter: flowtable: fix tcp and udp header checksum update
+    - xen/netback: avoid race in xenvif_rx_ring_slots_available()
+    - net: enetc: initialize the RFS and RSS memories
+    - selftests: txtimestamp: fix compilation issue
+    - net: stmmac: set TxQ mode back to DCB after disabling CBS
+    - ibmvnic: Clear failover_pending if unable to schedule
+    - netfilter: conntrack: skip identical origin tuple in same zone only
+    - x86/build: Disable CET instrumentation in the kernel for 32-bit too
+    - net: hns3: add a check for queue_id in hclge_reset_vf_queue()
+    - firmware_loader: align .builtin_fw to 8
+    - drm/sun4i: tcon: set sync polarity for tcon1 channel
+    - drm/sun4i: Fix H6 HDMI PHY configuration
+    - drm/sun4i: dw-hdmi: Fix max. frequency for H6
+    - clk: sunxi-ng: mp: fix parent rate change flag check
+    - i2c: stm32f7: fix configuration of the digital filter
+    - 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
+    - rxrpc: Fix clearance of Tx/Rx ring when releasing a call
+    - udp: fix skb_copy_and_csum_datagram with odd segment sizes
+    - net: dsa: call teardown method on probe failure
+    - net: gro: do not keep too many GRO packets in napi->rx_list
+    - net: fix iteration for sctp transport seq_files
+    - net/vmw_vsock: improve locking in vsock_connect_timeout()
+    - net: watchdog: hold device global xmit lock during tx disable
+    - vsock/virtio: update credit only if socket is not closed
+    - vsock: fix locking in vsock_shutdown()
+    - net/rds: restrict iovecs length for RDS_CMSG_RDMA_ARGS
+    - net/qrtr: restrict user-controlled length in qrtr_tun_write_iter()
+    - ovl: expand warning in ovl_d_real()
+    - Linux 5.4.99
+
+  * Focal update: v5.4.98 upstream stable release (LP: #1918158)
+    - tracing/kprobe: Fix to support kretprobe events on unloaded modules
+    - af_key: relax availability checks for skb size calculation
+    - regulator: core: avoid regulator_resolve_supply() race condition
+    - mac80211: 160MHz with extended NSS BW in CSA
+    - ASoC: Intel: Skylake: Zero snd_ctl_elem_value
+    - chtls: Fix potential resource leak
+    - pNFS/NFSv4: Try to return invalid layout in pnfs_layout_process()
+    - ASoC: ak4458: correct reset polarity
+    - iwlwifi: mvm: skip power command when unbinding vif during CSA
+    - iwlwifi: mvm: take mutex for calling iwl_mvm_get_sync_time()
+    - iwlwifi: pcie: add a NULL check in iwl_pcie_txq_unmap
+    - iwlwifi: pcie: fix context info memory leak
+    - iwlwifi: mvm: invalidate IDs of internal stations at mvm start
+    - 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
+    - i2c: mediatek: Move suspend and resume handling to NOIRQ phase
+    - blk-cgroup: Use cond_resched() when destroy blkgs
+    - regulator: Fix lockdep warning resolving supplies
+    - Fix unsynchronized access to sev members through svm_register_enc_region
+    - 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
+    - Linux 5.4.98
+
+  * Enforce CONFIG_DRM_BOCHS=m (LP: #1916290)
+    - [Config] Enforce CONFIG_DRM_BOCHS=m
+
+  * powerpc/eeh-basic.sh in kselftest make P8 node stopped working
+    (LP: #1916468)
+    - selftests/eeh: Skip ahci adapters
+
+  * Focal update: v5.4.97 upstream stable release (LP: #1916066)
+    - 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
+    - arm64: dts: qcom: c630: keep both touchpad devices enabled
+    - arm64: dts: amlogic: meson-g12: Set FL-adj property value
+    - arm64: dts: rockchip: fix vopl iommu irq on px30
+    - bpf, cgroup: Fix optlen WARN_ON_ONCE toctou
+    - bpf, cgroup: Fix problematic bounds check
+    - um: virtio: free vu_dev only with the contained struct device
+    - rxrpc: Fix deadlock around release of dst cached on udp tunnel
+    - arm64: dts: ls1046a: fix dcfg address range
+    - igc: set the default return value to -IGC_ERR_NVM in igc_write_nvm_srwr
+    - igc: check return value of ret_val in igc_config_fc_after_link_up
+    - i40e: Revert "i40e: don't report link up for a VF who hasn't enabled queues"
+    - net/mlx5: Fix leak upon failure of rule creation
+    - net: lapb: Copy the skb before sending a packet
+    - net: mvpp2: TCAM entry enable should be written after SRAM data
+    - r8169: fix WoL on shutdown if CONFIG_DEBUG_SHIRQ is set
+    - ARM: dts: sun7i: a20: bananapro: Fix ethernet phy-mode
+    - nvmet-tcp: fix out-of-bounds access when receiving multiple h2cdata PDUs
+    - memblock: do not start bottom-up allocations with kernel_end
+    - 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: renesas_usbhs: Clear pipe running flag in usbhs_pkt_pop()
+    - usb: dwc2: Fix endpoint direction check in ep_from_windex
+    - usb: dwc3: fix clock issue during resume in OTG mode
+    - usb: xhci-mtk: fix unreleased bandwidth data
+    - usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints
+    - usb: xhci-mtk: break loop when find the endpoint to drop
+    - usb: host: xhci-plat: add priv quirk for skip PHY initialization
+    - ovl: fix dentry leak in ovl_get_redirect
+    - mac80211: fix station rate table updates on assoc
+    - fgraph: Initialize tracing_graph_pause at task creation
+    - kretprobe: Avoid re-registration of the same kretprobe earlier
+    - libnvdimm/dimm: Avoid race between probe and available_slots_show()
+    - genirq/msi: Activate Multi-MSI early when MSI_FLAG_ACTIVATE_EARLY is set
+    - xhci: fix bounce buffer usage for non-sg list case
+    - cifs: report error instead of invalid when revalidating a dentry fails
+    - smb3: Fix out-of-bounds bug in SMB2_negotiate()
+    - smb3: fix crediting for compounding when only one request in flight
+    - mmc: core: Limit retries when analyse of SDIO tuples fails
+    - drm/amd/display: Revert "Fix EDID parsing after resume from suspend"
+    - nvme-pci: avoid the deepest sleep state on Kingston A2000 SSDs
+    - KVM: SVM: Treat SVM as unsupported when running as an SEV guest
+    - KVM: x86: Update emulator context mode if SYSENTER xfers to 64-bit mode
+    - ARM: footbridge: fix dc21285 PCI configuration accessors
+    - mm: hugetlbfs: fix cannot migrate the fallocated HugeTLB page
+    - mm: hugetlb: fix a race between freeing and dissolving the page
+    - mm: hugetlb: fix a race between isolating and freeing page
+    - mm: hugetlb: remove VM_BUG_ON_PAGE from page_huge_active
+    - mm, compaction: move high_pfn to the for loop scope
+    - mm: thp: fix MADV_REMOVE deadlock on shmem THP
+    - x86/build: Disable CET instrumentation in the kernel
+    - x86/apic: Add extra serialization for non-serializing MSRs
+    - iwlwifi: mvm: don't send RFH_QUEUE_CONFIG_CMD with no queues
+    - Input: xpad - sync supported devices with fork on GitHub
+    - iommu/vt-d: Do not use flush-queue when caching-mode is on
+    - md: Set prev_flush_start and flush_bio in an atomic way
+    - neighbour: Prevent a dead entry from updating gc_list
+    - net: ip_tunnel: fix mtu calculation
+    - net: dsa: mv88e6xxx: override existent unicast portvec in port_fdb_add
+    - net: sched: replaced invalid qdisc tree flush helper in qdisc_replace
+    - usb: host: xhci: mvebu: make USB 3.0 PHY optional for Armada 3720
+    - Linux 5.4.97
+
+  * Focal update: v5.4.96 upstream stable release (LP: #1916061)
+    - net: dsa: bcm_sf2: put device node before return
+    - net: switchdev: don't set port_obj_info->handled true when -EOPNOTSUPP
+    - ibmvnic: Ensure that CRQ entry read are correctly ordered
+    - Revert "Revert "block: end bio with BLK_STS_AGAIN in case of non-mq devs and
+      REQ_NOWAIT""
+    - ACPI: thermal: Do not call acpi_thermal_check() directly
+    - arm64: Fix kernel address detection of __is_lm_address()
+    - arm64: Do not pass tagged addresses to __is_lm_address()
+    - tcp: make TCP_USER_TIMEOUT accurate for zero window probes
+    - btrfs: backref, only collect file extent items matching backref offset
+    - btrfs: backref, don't add refs from shared block when resolving normal
+      backref
+    - btrfs: backref, only search backref entries from leaves of the same root
+    - btrfs: backref, use correct count to resolve normal data refs
+    - net_sched: gen_estimator: support large ewma log
+    - phy: cpcap-usb: Fix warning for missing regulator_disable
+    - platform/x86: touchscreen_dmi: Add swap-x-y quirk for Goodix touchscreen on
+      Estar Beauty HD tablet
+    - platform/x86: intel-vbtn: Support for tablet mode on Dell Inspiron 7352
+    - x86: __always_inline __{rd,wr}msr()
+    - scsi: scsi_transport_srp: Don't block target in failfast state
+    - scsi: libfc: Avoid invoking response handler twice if ep is already
+      completed
+    - scsi: fnic: Fix memleak in vnic_dev_init_devcmd2
+    - ASoC: SOF: Intel: hda: Resume codec to do jack detection
+    - mac80211: fix fast-rx encryption check
+    - scsi: ibmvfc: Set default timeout to avoid crash during migration
+    - udf: fix the problem that the disc content is not displayed
+    - nvme: check the PRINFO bit before deciding the host buffer length
+    - selftests/powerpc: Only test lwm/stmw on big endian
+    - drm/amd/display: Update dram_clock_change_latency for DCN2.1
+    - drm/amd/display: Change function decide_dp_link_settings to avoid infinite
+      looping
+    - objtool: Don't fail on missing symbol table
+    - kthread: Extract KTHREAD_IS_PER_CPU
+    - workqueue: Restrict affinity change to rescuer
+    - Linux 5.4.96
+
+  * Focal update: v5.4.95 upstream stable release (LP: #1916056)
+    - ICMPv6: Add ICMPv6 Parameter Problem, code 3 definition
+    - IPv6: reply ICMP error if the first fragment don't include all headers
+    - nbd: freeze the queue while we're adding connections
+    - ACPI: sysfs: Prefer "compatible" modalias
+    - kernel: kexec: remove the lock operation of system_transition_mutex
+    - ALSA: hda/realtek: Enable headset of ASUS B1400CEPE with ALC256
+    - ALSA: hda/via: Apply the workaround generically for Clevo machines
+    - media: rc: ensure that uevent can be read directly after rc device register
+    - ARM: dts: imx6qdl-gw52xx: fix duplicate regulator naming
+    - wext: fix NULL-ptr-dereference with cfg80211's lack of commit()
+    - net: usb: qmi_wwan: added support for Thales Cinterion PLSx3 modem family
+    - s390/vfio-ap: No need to disable IRQ after queue reset
+    - PM: hibernate: flush swap writer after marking
+    - drivers: soc: atmel: Avoid calling at91_soc_init on non AT91 SoCs
+    - drivers: soc: atmel: add null entry at the end of at91_soc_allowed_list[]
+    - btrfs: fix possible free space tree corruption with online conversion
+    - KVM: x86/pmu: Fix HW_REF_CPU_CYCLES event pseudo-encoding in
+      intel_arch_events[]
+    - KVM: x86/pmu: Fix UBSAN shift-out-of-bounds warning in intel_pmu_refresh()
+    - KVM: nVMX: Sync unsync'd vmcs02 state to vmcs12 on migration
+    - KVM: x86: get smi pending status correctly
+    - KVM: Forbid the use of tagged userspace addresses for memslots
+    - xen: Fix XenStore initialisation for XS_LOCAL
+    - leds: trigger: fix potential deadlock with libata
+    - arm64: dts: broadcom: Fix USB DMA address translation for Stingray
+    - mt7601u: fix kernel crash unplugging the device
+    - mt7601u: fix rx buffer refcounting
+    - drm/nouveau/svm: fail NOUVEAU_SVM_INIT ioctl on unsupported devices
+    - drm/i915: Check for all subplatform bits
+    - tee: optee: replace might_sleep with cond_resched
+    - xen-blkfront: allow discard-* nodes to be optional
+    - 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
+    - xfrm: fix disable_xfrm sysctl when used on xfrm interfaces
+    - selftests: xfrm: fix test return value override issue in xfrm_policy.sh
+    - xfrm: Fix wraparound in xfrm_policy_addr_delta()
+    - arm64: dts: ls1028a: fix the offset of the reset register
+    - ARM: dts: imx6qdl-kontron-samx6i: fix i2c_lcd/cam default status
+    - firmware: imx: select SOC_BUS to fix firmware build
+    - RDMA/cxgb4: Fix the reported max_recv_sge value
+    - ASoC: Intel: Skylake: skl-topology: Fix OOPs ib skl_tplg_complete
+    - pNFS/NFSv4: Fix a layout segment leak in pnfs_layout_process()
+    - iwlwifi: pcie: use jiffies for memory read spin time limit
+    - iwlwifi: pcie: reschedule in long-running memory reads
+    - mac80211: pause TX while changing interface type
+    - i40e: acquire VSI pointer only after VF is initialized
+    - igc: fix link speed advertising
+    - net/mlx5: Fix memory leak on flow table creation error flow
+    - net/mlx5e: E-switch, Fix rate calculation for overflow
+    - net/mlx5e: Reduce tc unsupported key print level
+    - can: dev: prevent potential information leak in can_fill_info()
+    - nvme-multipath: Early exit if no path is available
+    - selftests: forwarding: Specify interface when invoking mausezahn
+    - 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
+    - rxrpc: Fix memory leak in rxrpc_lookup_local
+    - NFC: fix resource leak when target index is invalid
+    - NFC: fix possible resource leak
+    - ASoC: topology: Fix memory corruption in soc_tplg_denum_create_values()
+    - team: protect features update by RCU to avoid deadlock
+    - tcp: fix TLP timer not set when CA_STATE changes from DISORDER to OPEN
+    - Linux 5.4.95
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Wed, 24 Mar 2021 11:25:50 +0100
+
+linux (5.4.0-70.78) focal; urgency=medium
+
+  * CVE-2020-27170
+    - bpf: Fix off-by-one for area size in creating mask to left
+
+  * CVE-2020-27171
+    - bpf: Prohibit alu ops for pointer types not defining ptr_limit
+
+  * binary assembly failures with CONFIG_MODVERSIONS present (LP: #1919315)
+    - [Packaging] quiet (nomially) benign errors in BUILD script
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 19 Mar 2021 12:57:03 +0100
+
+linux (5.4.0-69.77) focal; urgency=medium
+
+  * CVE-2021-3444
+    - bpf: Fix 32 bit src register truncation on div/mod
+    - bpf: Fix truncation handling for mod32 dst reg wrt zero
+
+  * CVE-2021-27365
+    - scsi: iscsi: Verify lengths on passthrough PDUs
+    - sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs output
+    - scsi: iscsi: Ensure sysfs attributes are limited to PAGE_SIZE
+
+  * CVE-2021-27363 // CVE-2021-27364
+    - scsi: iscsi: Restrict sessions and handles to admin capabilities
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 16 Mar 2021 12:29:06 +0100
+
+linux (5.4.0-67.75) focal; urgency=medium
+
+  * focal/linux: 5.4.0-67.75 -proposed tracker (LP: #1916169)
+
+  * Please trust Canonical Livepatch Service kmod signing key (LP: #1898716)
+    - [Config] enable CONFIG_MODVERSIONS=y
+    - [Packaging] build canonical-certs.pem from branch/arch certs
+    - [Config] add Canonical Livepatch Service key to SYSTEM_TRUSTED_KEYS
+    - [Config] add ubuntu-drivers key to SYSTEM_TRUSTED_KEYS
+    - [Config] Allow ASM_MODVERSIONS and MODULE_REL_CRCS
+
+  * geneve overlay network on vlan interface broken with offload enabled
+    (LP: #1914447)
+    - net/mlx5e: Fix SWP offsets when vlan inserted by driver
+
+  * Add support for selective build of special drivers (LP: #1912789)
+    - [Packaging] Fix ODM support in actual build
+
+  * devlink: don't do reporter recovery if the state is healthy (LP: #1915403)
+    - devlink: don't do reporter recovery if the state is healthy
+
+  * Missing device id for Intel TGL-H ISH [8086:43fc] in intel-ish-hid driver
+    (LP: #1914543)
+    - HID: intel-ish-hid: ipc: Add Tiger Lake H PCI device ID
+
+  * Focal update: v5.4.94 upstream stable release (LP: #1915200)
+    - gpio: mvebu: fix pwm .get_state period calculation
+    - futex: Ensure the correct return value from futex_lock_pi()
+    - 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
+    - HID: wacom: Correct NULL dereference on AES pen proximity
+    - io_uring: Fix current->fs handling in io_sq_wq_submit_work()
+    - tracing: Fix race in trace_open and buffer resize call
+    - arm64: mm: use single quantity to represent the PA to VA translation
+    - SMB3.1.1: do not log warning message if server doesn't populate salt
+    - tools: Factor HOSTCC, HOSTLD, HOSTAR definitions
+    - dm integrity: conditionally disable "recalculate" feature
+    - writeback: Drop I_DIRTY_TIME_EXPIRE
+    - fs: fix lazytime expiration handling in __writeback_single_inode()
+    - Linux 5.4.94
+
+  * Focal update: v5.4.93 upstream stable release (LP: #1915195)
+    - i2c: bpmp-tegra: Ignore unknown I2C_M flags
+    - platform/x86: ideapad-laptop: Disable touchpad_switch for ELAN0634
+    - 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
+    - btrfs: don't get an EINTR during drop_snapshot for reloc
+    - btrfs: fix lockdep splat in btrfs_recover_relocation
+    - btrfs: don't clear ret in btrfs_start_dirty_block_groups
+    - btrfs: send: fix invalid clone operations when cloning from the same file
+      and root
+    - mmc: core: don't initialize block size from ext_csd if not present
+    - mmc: sdhci-xenon: fix 1.8v regulator stabilization
+    - dm: avoid filesystem lookup in dm_get_dev_t()
+    - dm integrity: fix a crash if "recalculate" used without "internal_hash"
+    - drm/atomic: put state on error path
+    - drm/syncobj: Fix use-after-free
+    - drm/i915/gt: Prevent use of engine->wa_ctx after error
+    - ASoC: Intel: haswell: Add missing pm_ops
+    - dm integrity: select CRYPTO_SKCIPHER
+    - scsi: ufs: Correct the LUN used in eh_device_reset_handler() callback
+    - scsi: qedi: Correct max length of CHAP secret
+    - scsi: sd: Suppress spurious errors when WRITE SAME is being disabled
+    - riscv: Fix kernel time_init()
+    - riscv: Fix sifive serial driver
+    - HID: logitech-dj: add the G602 receiver
+    - HID: Ignore battery for Elan touchscreen on ASUS UX550
+    - clk: tegra30: Add hda clock default rates to clock driver
+    - arm64: make atomic helpers __always_inline
+    - xen: Fix event channel callback via INTX/GSI
+    - x86/xen: Add xen_no_vector_callback option to test PCI INTX delivery
+    - dts: phy: fix missing mdio device and probe failure of vsc8541-01 device
+    - riscv: defconfig: enable gpio support for HiFive Unleashed
+    - drm/amdgpu/psp: fix psp gfx ctrl cmds
+    - drm/amd/display: Fix to be able to stop crc calculation
+    - drm/nouveau/bios: fix issue shadowing expansion ROMs
+    - drm/nouveau/privring: ack interrupts the same way as RM
+    - drm/nouveau/i2c/gm200: increase width of aux semaphore owner fields
+    - drm/nouveau/mmu: fix vram heap sizing
+    - drm/nouveau/kms/nv50-: fix case where notifier buffer is at offset 0
+    - powerpc: Use the common INIT_DATA_SECTION macro in vmlinux.lds.S
+    - pinctrl: aspeed: g6: Fix PWMG0 pinctrl setting
+    - scsi: megaraid_sas: Fix MEGASAS_IOC_FIRMWARE regression
+    - powerpc: Fix alignment bug within the init sections
+    - i2c: octeon: check correct size of maximum RECV_LEN packet
+    - platform/x86: intel-vbtn: Drop HP Stream x360 Convertible PC 11 from allow-
+      list
+    - selftests: net: fib_tests: remove duplicate log test
+    - can: dev: can_restart: fix use after free bug
+    - can: vxcan: vxcan_xmit: fix use after free bug
+    - can: peak_usb: fix use after free bugs
+    - iio: ad5504: Fix setting power-down state
+    - cifs: do not fail __smb_send_rqst if non-fatal signals are pending
+    - irqchip/mips-cpu: Set IPI domain parent chip
+    - x86/fpu: Add kernel_fpu_begin_mask() to selectively initialize state
+    - x86/topology: Make __max_die_per_package available unconditionally
+    - x86/mmx: Use KFPU_387 for MMX string operations
+    - intel_th: pci: Add Alder Lake-P support
+    - stm class: Fix module init return on allocation failure
+    - serial: mvebu-uart: fix tx lost characters at power off
+    - ehci: fix EHCI host controller initialization sequence
+    - USB: ehci: fix an interrupt calltrace error
+    - usb: gadget: aspeed: fix stop dma register setting.
+    - usb: udc: core: Use lock when write to soft_connect
+    - [Config] updateconfigs for USB_BDC_PCI
+    - usb: bdc: Make bdc pci driver depend on BROKEN
+    - xhci: make sure TRB is fully written before giving it to the controller
+    - xhci: tegra: Delay for disabling LFPS detector
+    - driver core: Extend device_is_dependent()
+    - pinctrl: ingenic: Fix JZ4760 support
+    - x86/cpu/amd: Set __max_die_per_package on AMD
+    - netfilter: rpfilter: mask ecn bits before fib lookup
+    - sh: dma: fix kconfig dependency for G2_DMA
+    - net: dsa: mv88e6xxx: also read STU state in mv88e6250_g1_vtu_getnext
+    - sh_eth: Fix power down vs. is_opened flag ordering
+    - lightnvm: fix memory leak when submit fails
+    - skbuff: back tiny skbs with kmalloc() in __netdev_alloc_skb() too
+    - kasan: fix unaligned address is unhandled in kasan_remove_zero_shadow
+    - kasan: fix incorrect arguments passing in kasan_add_zero_shadow
+    - udp: mask TOS bits in udp_v4_early_demux()
+    - ipv6: create multicast route with RTPROT_KERNEL
+    - net_sched: avoid shift-out-of-bounds in tcindex_set_parms()
+    - net_sched: reject silly cell_log in qdisc_get_rtab()
+    - ipv6: set multicast flag on the multicast route
+    - net: mscc: ocelot: allow offloading of bridge on top of LAG
+    - net: Disable NETIF_F_HW_TLS_RX when RXCSUM is disabled
+    - net: dsa: b53: fix an off by one in checking "vlan->vid"
+    - tcp: do not mess with cloned skbs in tcp_add_backlog()
+    - tcp: fix TCP_USER_TIMEOUT with zero window
+    - Linux 5.4.93
+
+  * High load from process irq/65-i2c-INT3  - kernel module tps6598x
+    (LP: #1883511) // Focal update: v5.4.93 upstream stable release
+    (LP: #1915195)
+    - platform/x86: i2c-multi-instantiate: Don't create platform device for
+      INT3515 ACPI nodes
+
+  * Focal update: v5.4.92 upstream stable release (LP: #1915186)
+    - usb: ohci: Make distrust_firmware param default to false
+    - compiler.h: Raise minimum version of GCC to 5.1 for arm64
+    - xen/privcmd: allow fetching resource sizes
+    - elfcore: fix building with clang
+    - scsi: lpfc: Make lpfc_defer_acc_rsp static
+    - spi: npcm-fiu: simplify the return expression of npcm_fiu_probe()
+    - spi: npcm-fiu: Disable clock in probe error path
+    - nfsd4: readdirplus shouldn't return parent of export
+    - bpf: Don't leak memory in bpf getsockopt when optlen == 0
+    - bpf: Fix helper bpf_map_peek_elem_proto pointing to wrong callback
+    - udp: Prevent reuseport_select_sock from reading uninitialized socks
+    - netxen_nic: fix MSI/MSI-x interrupts
+    - net: introduce skb_list_walk_safe for skb segment walking
+    - net: skbuff: disambiguate argument and member for skb_list_walk_safe helper
+    - net: ipv6: Validate GSO SKB before finish IPv6 processing
+    - mlxsw: core: Add validation of transceiver temperature thresholds
+    - mlxsw: core: Increase critical threshold for ASIC thermal zone
+    - net: mvpp2: Remove Pause and Asym_Pause support
+    - rndis_host: set proper input size for OID_GEN_PHYSICAL_MEDIUM request
+    - esp: avoid unneeded kmap_atomic call
+    - net: dcb: Validate netlink message in DCB handler
+    - net: dcb: Accept RTM_GETDCB messages carrying set-like DCB commands
+    - rxrpc: Call state should be read with READ_ONCE() under some circumstances
+    - net: stmmac: Fixed mtu channged by cache aligned
+    - net: sit: unregister_netdevice on newlink's error path
+    - net: avoid 32 x truesize under-estimation for tiny skbs
+    - rxrpc: Fix handling of an unsupported token type in rxrpc_read()
+    - net, sctp, filter: remap copy_from_user failure error
+    - tipc: fix NULL deref in tipc_link_xmit()
+    - mac80211: do not drop tx nulldata packets on encrypted links
+    - mac80211: check if atf has been disabled in __ieee80211_schedule_txq
+    - spi: cadence: cache reference clock rate during probe
+    - Linux 5.4.92
+
+  * intel-hid is not loaded on new Intel platform (LP: #1907160)
+    - platform/x86: intel-hid: Add Tiger Lake ACPI device ID
+    - platform/x86: intel-hid: fix: Update Tiger Lake ACPI device ID
+    - platform/x86: intel-hid: Move MODULE_DEVICE_TABLE() closer to the table
+    - platform/x86: intel-hid: add Rocket Lake ACPI device ID
+
+  * Support Advantech UNO-420 platform (LP: #1902672)
+    - ODM: MAINTAINERS: Add Advantech AHC1EC0 embedded controller entry
+    - ODM: mfd: ahc1ec0: Add Advantech EC include file used by dt-bindings
+    - ODM: dt-bindings: mfd: ahc1ec0.yaml: Add Advantech embedded controller -
+      AHC1EC0
+    - ODM: mfd: ahc1ec0: Add support for Advantech embedded controller
+    - ODM: hwmon: ahc1ec0-hwmon: Add sub-device hwmon for Advantech embedded
+      controller
+    - ODM: watchdog: ahc1ec0-wdt: Add sub-device watchdog for Advantech embedded
+      controller
+    - ODM: [Config] update config for Advantech devices
+
+  * Remove scary stack trace from Realtek WiFi driver (LP: #1913263)
+    - rtw88: reduce the log level for failure of tx report
+
+  * Focal update: v5.4.91 upstream stable release (LP: #1914654)
+    - kbuild: enforce -Werror=return-type
+    - btrfs: prevent NULL pointer dereference in extent_io_tree_panic
+    - ASoC: dapm: remove widget from dirty list on free
+    - x86/hyperv: check cpu mask after interrupt has been disabled
+    - tracing/kprobes: Do the notrace functions check without kprobes on ftrace
+    - [Config] update annotations for KPROBE_EVENTS_ON_NOTRACE
+    - mips: fix Section mismatch in reference
+    - mips: lib: uncached: fix non-standard usage of variable 'sp'
+    - MIPS: boot: Fix unaligned access with CONFIG_MIPS_RAW_APPENDED_DTB
+    - MIPS: relocatable: fix possible boot hangup with KASLR enabled
+    - RDMA/ocrdma: Fix use after free in ocrdma_dealloc_ucontext_pd()
+    - ACPI: scan: Harden acpi_device_add() against device ID overflows
+    - mm/hugetlb: fix potential missing huge page size info
+    - dm raid: fix discard limits for raid1
+    - dm snapshot: flush merged data before committing metadata
+    - dm integrity: fix the maximum number of arguments
+    - r8152: Add Lenovo Powered USB-C Travel Hub
+    - btrfs: tree-checker: check if chunk item end overflows
+    - drm/i915/backlight: fix CPU mode backlight takeover on LPT
+    - ext4: fix bug for rename with RENAME_WHITEOUT
+    - ext4: don't leak old mountpoint samples
+    - cifs: fix interrupted close commands
+    - dm integrity: fix flush with external metadata device
+    - ARC: build: remove non-existing bootpImage from KBUILD_IMAGE
+    - ARC: build: add uImage.lzma to the top-level target
+    - ARC: build: add boot_targets to PHONY
+    - ARC: build: move symlink creation to arch/arc/Makefile to avoid race
+    - netfilter: ipset: fixes possible oops in mtype_resize
+    - btrfs: fix transaction leak and crash after RO remount caused by qgroup
+      rescan
+    - regulator: bd718x7: Add enable times
+    - ethernet: ucc_geth: fix definition and size of ucc_geth_tx_global_pram
+    - habanalabs: register to pci shutdown callback
+    - habanalabs: Fix memleak in hl_device_reset
+    - hwmon: (pwm-fan) Ensure that calculation doesn't discard big period values
+    - lib/raid6: Let $(UNROLL) rules work with macOS userland
+    - bfq: Fix computation of shallow depth
+    - 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
+    - nvme-pci: mark Samsung PM1725a as IGNORE_DEV_SUBNQN
+    - nvmet-rdma: Fix list_del corruption on queue establishment failure
+    - drm/amdgpu: fix a GPU hang issue when remove device
+    - usb: typec: Fix copy paste error for NVIDIA alt-mode description
+    - ACPI: scan: add stub acpi_create_platform_device() for !CONFIG_ACPI
+    - drm/msm: Call msm_init_vram before binding the gpu
+    - ARM: picoxcell: fix missing interrupt-parent properties
+    - perf intel-pt: Fix 'CPU too large' error
+    - dump_common_audit_data(): fix racy accesses to ->d_name
+    - ASoC: meson: axg-tdm-interface: fix loopback
+    - ASoC: meson: axg-tdmin: fix axg skew offset
+    - ASoC: Intel: fix error code cnl_set_dsp_D0()
+    - nvme-tcp: fix possible data corruption with bio merges
+    - NFS4: Fix use-after-free in trace_event_raw_event_nfs4_set_lock
+    - pNFS: We want return-on-close to complete when evicting the inode
+    - pNFS: Mark layout for return if return-on-close was not sent
+    - pNFS: Stricter ordering of layoutget and layoutreturn
+    - NFS/pNFS: Fix a leak of the layout 'plh_outstanding' counter
+    - NFS: nfs_igrab_and_active must first reference the superblock
+    - ext4: fix superblock checksum failure when setting password salt
+    - RDMA/restrack: Don't treat as an error allocation ID wrapping
+    - RDMA/usnic: Fix memleak in find_free_vf_and_create_qp_grp
+    - bnxt_en: Improve stats context resource accounting with RDMA driver loaded.
+    - RDMA/mlx5: Fix wrong free of blue flame register on error
+    - IB/mlx5: Fix error unwinding when set_has_smi_cap fails
+    - drm/i915/dsi: Use unconditional msleep for the panel_on_delay when there is
+      no reset-deassert MIPI-sequence
+    - mm, slub: consider rest of partial list if acquire_slab() fails
+    - iommu/vt-d: Fix unaligned addresses for intel_flush_svm_range_dev()
+    - net: sunrpc: interpret the return value of kstrtou32 correctly
+    - dm: eliminate potential source of excessive kernel log noise
+    - ALSA: fireface: Fix integer overflow in transmit_midi_msg()
+    - ALSA: firewire-tascam: Fix integer overflow in midi_port_work()
+    - netfilter: conntrack: fix reading nf_conntrack_buckets
+    - netfilter: nf_nat: Fix memleak in nf_nat_init
+    - netfilter: nft_compat: remove flush counter optimization
+    - Linux 5.4.91
+
+  * Focal update: v5.4.90 upstream stable release (LP: #1913487)
+    - x86/asm/32: Add ENDs to some functions and relabel with SYM_CODE_*
+    - vfio iommu: Add dma available capability
+    - net: cdc_ncm: correct overhead in delayed_ndp_size
+    - net: hns3: fix the number of queues actually used by ARQ
+    - net: hns3: fix a phy loopback fail issue
+    - net: stmmac: dwmac-sun8i: Balance internal PHY resource references
+    - net: stmmac: dwmac-sun8i: Balance internal PHY power
+    - net: vlan: avoid leaks on register_vlan_dev() failures
+    - net/sonic: Fix some resource leaks in error handling paths
+    - net: ipv6: fib: flush exceptions when purging route
+    - tools: selftests: add test for changing routes with PTMU exceptions
+    - net: fix pmtu check in nopmtudisc mode
+    - net: ip: always refragment ip defragmented packets
+    - octeontx2-af: fix memory leak of lmac and lmac->name
+    - nexthop: Fix off-by-one error in error path
+    - nexthop: Unlink nexthop group entry in error path
+    - s390/qeth: fix L2 header access in qeth_l3_osa_features_check()
+    - net: dsa: lantiq_gswip: Exclude RMII from modes that report 1 GbE
+    - net/mlx5: Use port_num 1 instead of 0 when delete a RoCE address
+    - net/mlx5e: ethtool, Fix restriction of autoneg with 56G
+    - chtls: Fix hardware tid leak
+    - chtls: Remove invalid set_tcb call
+    - chtls: Fix panic when route to peer not configured
+    - chtls: Replace skb_dequeue with skb_peek
+    - chtls: Added a check to avoid NULL pointer dereference
+    - chtls: Fix chtls resources release sequence
+    - x86/resctrl: Use an IPI instead of task_work_add() to update PQR_ASSOC MSR
+    - x86/resctrl: Don't move a task to the same resource group
+    - exfat: Month timestamp metadata accidentally incremented
+    - vmlinux.lds.h: Add PGO and AutoFDO input sections
+    - iio: imu: st_lsm6dsx: fix edge-trigger interrupts
+    - HID: wacom: Fix memory leakage caused by kfifo_alloc
+    - ARM: OMAP2+: omap_device: fix idling of devices during probe
+    - i2c: sprd: use a specific timeout to avoid system hang up issue
+    - dmaengine: dw-edma: Fix use after free in dw_edma_alloc_chunk()
+    - can: tcan4x5x: fix bittiming const, use common bittiming from m_can driver
+    - can: m_can: m_can_class_unregister(): remove erroneous m_can_clk_stop()
+    - can: kvaser_pciefd: select CONFIG_CRC32
+    - cpufreq: powernow-k8: pass policy rather than use cpufreq_cpu_get()
+    - spi: stm32: FIFO threshold level - fix align packet size
+    - i2c: i801: Fix the i2c-mux gpiod_lookup_table not being properly terminated
+    - dmaengine: mediatek: mtk-hsdma: Fix a resource leak in the error handling
+      path of the probe function
+    - dmaengine: xilinx_dma: check dma_async_device_register return value
+    - dmaengine: xilinx_dma: fix incompatible param warning in _child_probe()
+    - dmaengine: xilinx_dma: fix mixed_enum_type coverity warning
+    - qed: select CONFIG_CRC32
+    - wil6210: select CONFIG_CRC32
+    - block: rsxx: select CONFIG_CRC32
+    - lightnvm: select CONFIG_CRC32
+    - iommu/intel: Fix memleak in intel_irq_remapping_alloc
+    - bpftool: Fix compilation failure for net.o with older glibc
+    - net/mlx5e: Fix memleak in mlx5e_create_l2_table_groups
+    - net/mlx5e: Fix two double free cases
+    - regmap: debugfs: Fix a memory leak when calling regmap_attach_dev
+    - wan: ds26522: select CONFIG_BITREVERSE
+    - regulator: qcom-rpmh-regulator: correct hfsmps515 definition
+    - net: mvpp2: disable force link UP during port init procedure
+    - KVM: arm64: Don't access PMCR_EL0 when no PMU is available
+    - block: fix use-after-free in disk_part_iter_next
+    - net: drop bogus skb with CHECKSUM_PARTIAL and offset beyond end of trimmed
+      packet
+    - regmap: debugfs: Fix a reversed if statement in regmap_debugfs_init()
+    - Linux 5.4.90
+
+  * Focal update: v5.4.89 upstream stable release (LP: #1913486)
+    - workqueue: Kick a worker based on the actual activation of delayed works
+    - scsi: ufs: Fix wrong print message in dev_err()
+    - scsi: ufs-pci: Ensure UFS device is in PowerDown mode for suspend-to-disk
+      ->poweroff()
+    - scsi: ide: Do not set the RQF_PREEMPT flag for sense requests
+    - scsi: scsi_transport_spi: Set RQF_PM for domain validation commands
+    - lib/genalloc: fix the overflow when size is too big
+    - depmod: handle the case of /sbin/depmod without /sbin in PATH
+    - proc: change ->nlink under proc_subdir_lock
+    - proc: fix lookup in /proc/net subdirectories after setns(2)
+    - i40e: Fix Error I40E_AQ_RC_EINVAL when removing VFs
+    - iavf: fix double-release of rtnl_lock
+    - net: mvpp2: Add TCAM entry to drop flow control pause frames
+    - net: mvpp2: prs: fix PPPoE with ipv6 packet parse
+    - net: systemport: set dev->max_mtu to UMAC_MAX_MTU_SIZE
+    - ethernet: ucc_geth: fix use-after-free in ucc_geth_remove()
+    - ethernet: ucc_geth: set dev->max_mtu to 1518
+    - atm: idt77252: call pci_disable_device() on error path
+    - net: mvpp2: Fix GoP port 3 Networking Complex Control configurations
+    - ibmvnic: continue fatal error reset after passive init
+    - net: ethernet: mvneta: Fix error handling in mvneta_probe
+    - virtio_net: Fix recursive call to cpus_read_lock()
+    - net/ncsi: Use real net-device for response handler
+    - net: ethernet: Fix memleak in ethoc_probe
+    - net-sysfs: take the rtnl lock when storing xps_cpus
+    - net-sysfs: take the rtnl lock when accessing xps_cpus_map and num_tc
+    - net-sysfs: take the rtnl lock when storing xps_rxqs
+    - net-sysfs: take the rtnl lock when accessing xps_rxqs_map and num_tc
+    - net: ethernet: ti: cpts: fix ethtool output when no ptp_clock registered
+    - tun: fix return value when the number of iovs exceeds MAX_SKB_FRAGS
+    - net: mvpp2: fix pkt coalescing int-threshold configuration
+    - ipv4: Ignore ECN bits for fib lookups in fib_compute_spec_dst()
+    - net: sched: prevent invalid Scell_log shift count
+    - net: hns: fix return value check in __lb_other_process()
+    - erspan: fix version 1 check in gre_parse_header()
+    - net: hdlc_ppp: Fix issues when mod_timer is called while timer is running
+    - r8169: work around power-saving bug on some chip versions
+    - net: dsa: lantiq_gswip: Enable GSWIP_MII_CFG_EN also for internal PHYs
+    - net: dsa: lantiq_gswip: Fix GSWIP_MII_CFG(p) register access
+    - CDC-NCM: remove "connected" log message
+    - net: usb: qmi_wwan: add Quectel EM160R-GL
+    - vhost_net: fix ubuf refcount incorrectly when sendmsg fails
+    - ionic: account for vlan tag len in rx buffer len
+    - net/sched: sch_taprio: ensure to reset/destroy all child qdiscs
+    - kbuild: don't hardcode depmod path
+    - Bluetooth: revert: hci_h5: close serdev device and free hu in h5_close
+    - video: hyperv_fb: Fix the mmap() regression for v5.4.y and older
+    - crypto: ecdh - avoid buffer overflow in ecdh_set_secret()
+    - crypto: asym_tpm: correct zero out potential secrets
+    - powerpc: Handle .text.{hot,unlikely}.* in linker script
+    - staging: mt7621-dma: Fix a resource leak in an error handling path
+    - usb: gadget: enable super speed plus
+    - USB: cdc-acm: blacklist another IR Droid device
+    - USB: cdc-wdm: Fix use after free in service_outstanding_interrupt().
+    - usb: dwc3: ulpi: Use VStsDone to detect PHY regs access completion
+    - 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: usbip: vhci_hcd: protect shift size
+    - 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: serial: option: add Quectel EM160R-GL
+    - 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: u_ether: Fix MTU size mismatch with RX packet size
+    - 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: gadget: configfs: Fix use-after-free issue with udc_name
+    - USB: serial: keyspan_pda: remove unused variable
+    - x86/mm: Fix leak of pmd ptlock
+    - kvm: check tlbs_dirty directly
+    - ALSA: hda/via: Fix runtime PM for Clevo W35xSS
+    - ALSA: hda/conexant: add a new hda codec CX11970
+    - ALSA: hda/realtek - Fix speaker volume control on Lenovo C940
+    - ALSA: hda/realtek: Add two "Intel Reference board" SSID in the ALC256.
+    - btrfs: send: fix wrong file path when there is an inode with a pending rmdir
+    - Revert "device property: Keep secondary firmware node secondary by type"
+    - dmabuf: fix use-after-free of dmabuf's file->f_inode
+    - drm/i915: clear the gpu reloc batch
+    - netfilter: x_tables: Update remaining dereference to RCU
+    - netfilter: ipset: fix shift-out-of-bounds in htable_bits()
+    - netfilter: xt_RATEEST: reject non-null terminated string from userspace
+    - netfilter: nft_dynset: report EOPNOTSUPP on missing set feature
+    - x86/mtrr: Correct the range check before performing MTRR type lookups
+    - KVM: x86: fix shift out of bounds reported by UBSAN
+    - Linux 5.4.89
+
+  * Focal update: v5.4.88 upstream stable release (LP: #1913223)
+    - Revert "drm/amd/display: Fix memory leaks in S3 resume"
+    - Revert "mtd: spinand: Fix OOB read"
+    - dmaengine: at_hdmac: Substitute kzalloc with kmalloc
+    - dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()
+    - dmaengine: at_hdmac: add missing kfree() call in at_dma_xlate()
+    - kdev_t: always inline major/minor helper functions
+    - iio:imu:bmi160: Fix alignment and data leak issues
+    - fuse: fix bad inode
+    - perf: Break deadlock involving exec_update_mutex
+    - rwsem: Implement down_read_killable_nested
+    - rwsem: Implement down_read_interruptible
+    - exec: Transform exec_update_mutex into a rw_semaphore
+    - mwifiex: Fix possible buffer overflows in mwifiex_cmd_802_11_ad_hoc_start
+    - Linux 5.4.88
+
+  * Focal update: v5.4.87 upstream stable release (LP: #1912681)
+    - net/sched: sch_taprio: reset child qdiscs before freeing them
+    - md/raid10: initialize r10_bio->read_slot before use.
+    - thermal/drivers/cpufreq_cooling: Update cpufreq_state only if state has
+      changed
+    - ext4: prevent creating duplicate encrypted filenames
+    - ubifs: prevent creating duplicate encrypted filenames
+    - f2fs: prevent creating duplicate encrypted filenames
+    - fscrypt: add fscrypt_is_nokey_name()
+    - fscrypt: remove kernel-internal constants from UAPI header
+    - vfio/pci: Move dummy_resources_list init in vfio_pci_probe()
+    - btrfs: fix race when defragmenting leads to unnecessary IO
+    - ext4: don't remount read-only with errors=continue on reboot
+    - KVM: x86: avoid incorrect writes to host MSR_IA32_SPEC_CTRL
+    - KVM: SVM: relax conditions for allowing MSR_IA32_SPEC_CTRL accesses
+    - KVM: x86: reinstate vendor-agnostic check on SPEC_CTRL cpuid bits
+    - powerpc/bitops: Fix possible undefined behaviour with fls() and fls64()
+    - jffs2: Allow setting rp_size to zero during remounting
+    - jffs2: Fix NULL pointer dereference in rp_size fs option parsing
+    - scsi: block: Fix a race in the runtime power management code
+    - uapi: move constants from <linux/kernel.h> to <linux/const.h>
+    - tools headers UAPI: Sync linux/const.h with the kernel headers
+    - null_blk: Fix zone size initialization
+    - of: fix linker-section match-table corruption
+    - cgroup: Fix memory leak when parsing multiple source parameters
+    - scsi: cxgb4i: Fix TLS dependency
+    - Bluetooth: hci_h5: close serdev device and free hu in h5_close
+    - 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
+    - f2fs: fix shift-out-of-bounds in sanity_check_raw_super()
+    - ALSA: seq: Use bool for snd_seq_queue internal flags
+    - ALSA: rawmidi: Access runtime->avail always in spinlock
+    - bfs: don't use WARNING: string when it's just info.
+    - fcntl: Fix potential deadlock in send_sig{io, urg}()
+    - rtc: sun6i: Fix memleak in sun6i_rtc_clk_init
+    - module: set MODULE_STATE_GOING state when a module fails to load
+    - quota: Don't overflow quota file offsets
+    - rtc: pl031: fix resource leak in pl031_probe
+    - powerpc: sysdev: add missing iounmap() on error in mpic_msgr_probe()
+    - i3c master: fix missing destroy_workqueue() on error in i3c_master_register
+    - NFSv4: Fix a pNFS layout related use-after-free race when freeing the inode
+    - f2fs: avoid race condition for shrinker count
+    - module: delay kobject uevent until after module init call
+    - fs/namespace.c: WARN if mnt_count has become negative
+    - um: ubd: Submit all data segments atomically
+    - tick/sched: Remove bogus boot "safety" check
+    - ALSA: pcm: Clear the full allocated memory at hw_params
+    - dm verity: skip verity work if I/O error when system is shutting down
+    - Linux 5.4.87
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 19 Feb 2021 17:11:23 +0100
+
+linux (5.4.0-66.74) focal; urgency=medium
+
+  * focal/linux: 5.4.0-66.74 -proposed tracker (LP: #1913152)
+
+  * Add support for selective build of special drivers (LP: #1912789)
+    - [Packaging] Add support for ODM drivers
+    - [Packaging] Turn on ODM support for amd64
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+    - update dkms package versions
+
+  * Introduce the new NVIDIA 460-server series and update the 460 series
+    (LP: #1913200)
+    - [Config] dkms-versions -- drop NVIDIA 435 455 and 440-server
+    - [Config] dkms-versions -- add the 460-server nvidia driver
+
+  * Enable mute and micmute LED on HP EliteBook 850 G7 (LP: #1910102)
+    - ALSA: hda/realtek: Enable mute and micmute LED on HP EliteBook 850 G7
+
+  * SYNA30B4:00 06CB:CE09 Mouse  on HP EliteBook 850 G7 not working at all
+    (LP: #1908992)
+    - HID: multitouch: Enable multi-input for Synaptics pointstick/touchpad device
+
+  * HD Audio Device PCI ID for the Intel Cometlake-R platform (LP: #1912427)
+    - SAUCE: ALSA: hda: Add Cometlake-R PCI ID
+
+  * switch to an autogenerated nvidia series based core via dkms-versions
+    (LP: #1912803)
+    - [Packaging] nvidia -- use dkms-versions to define versions built
+    - [Packaging] update-version-dkms -- maintain flags fields
+    - [Config] dkms-versions -- add transitional/skip information for nvidia
+      packages
+
+  * udpgro.sh in net from ubuntu_kernel_selftests seems not reflecting sub-test
+    result (LP: #1908499)
+    - selftests: fix the return value for UDP GRO test
+
+  * qede: Kubernetes Internal DNS Failure due to QL41xxx NIC not supporting IPIP
+    tx csum offload (LP: #1909062)
+    - qede: fix offload for IPIP tunnel packets
+
+  * Use DCPD to control HP DreamColor panel (LP: #1911001)
+    - SAUCE: drm/dp: Another HP DreamColor panel brigntness fix
+
+  * kvm: Windows 2k19 with Hyper-v role gets stuck on pending hypervisor
+    requests on cascadelake based kvm hosts (LP: #1911848)
+    - KVM: x86: Set KVM_REQ_EVENT if run is canceled with req_immediate_exit set
+
+  * Ubuntu 20.10 four needed fixes to 'Add driver for Mellanox Connect-IB
+    adapters' (LP: #1905574)
+    - net/mlx5: Fix a race when moving command interface to polling mode
+
+  * Fix right sounds and mute/micmute LEDs for HP ZBook Fury 15/17 G7 Mobile
+    Workstation (LP: #1910561)
+    - ALSA: hda/realtek: fix right sounds and mute/micmute LEDs for HP machines
+
+  * Ubuntu 20.04 - multicast counter is not increased in ip -s (LP: #1901842)
+    - net/mlx5e: Fix multicast counter not up-to-date in "ip -s"
+
+  * eeh-basic.sh in powerpc from ubuntu_kernel_selftests timeout with 5.4 P8 /
+    P9 (LP: #1882503)
+    - selftests/powerpc/eeh: disable kselftest timeout setting for eeh-basic
+
+  * 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()
+
+  * update ENA driver, incl. new ethtool stats (LP: #1910291)
+    - net: ena: Change WARN_ON expression in ena_del_napi_in_range()
+    - net: ena: ethtool: convert stat_offset to 64 bit resolution
+    - net: ena: ethtool: Add new device statistics
+    - net: ena: ethtool: add stats printing to XDP queues
+    - net: ena: xdp: add queue counters for xdp actions
+    - net: ena: Change license into format to SPDX in all files
+    - net: ena: Change log message to netif/dev function
+    - net: ena: Capitalize all log strings and improve code readability
+    - net: ena: Remove redundant print of placement policy
+    - net: ena: Change RSS related macros and variables names
+    - net: ena: Fix all static chekers' warnings
+    - drivers/net/ethernet: remove incorrectly formatted doc
+    - net: ena: handle bad request id in ena_netdev
+    - net: ena: fix packet's addresses for rx_offset feature
+
+  * s390x broken with unknown syscall number on kernels < 5.8 (LP: #1895132)
+    - s390/ptrace: return -ENOSYS when invalid syscall is supplied
+
+  * Focal update: v5.4.86 upstream stable release (LP: #1910822)
+    - ARM: dts: sun7i: bananapi: Enable RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sun8i: r40: bananapi-m2-berry: Fix dcdc1 regulator
+    - ARM: dts: sun8i: v40: bananapi-m2-berry: Fix ethernet node
+    - pinctrl: merrifield: Set default bias in case no particular value given
+    - pinctrl: baytrail: Avoid clearing debounce value when turning it off
+    - ARM: dts: sun8i: v3s: fix GIC node memory range
+    - ARM: dts: sun7i: pcduino3-nano: enable RGMII RX/TX delay on PHY
+    - ARM: dts: imx6qdl-wandboard-revd1: Remove PAD_GPIO_6 from enetgrp
+    - ARM: dts: imx6qdl-kontron-samx6i: fix I2C_PM scl pin
+    - PM: runtime: Add pm_runtime_resume_and_get to deal with usage counter
+    - gpio: zynq: fix reference leak in zynq_gpio functions
+    - gpio: mvebu: fix potential user-after-free on probe
+    - scsi: bnx2i: Requires MMU
+    - xsk: Fix xsk_poll()'s return type
+    - xsk: Replace datagram_poll by sock_poll_wait
+    - can: softing: softing_netdev_open(): fix error handling
+    - clk: renesas: r9a06g032: Drop __packed for portability
+    - block: Simplify REQ_OP_ZONE_RESET_ALL handling
+    - block: factor out requeue handling from dispatch code
+    - blk-mq: In blk_mq_dispatch_rq_list() "no budget" is a reason to kick
+    - pinctrl: aspeed: Fix GPIO requests on pass-through banks
+    - netfilter: x_tables: Switch synchronization to RCU
+    - netfilter: nft_compat: make sure xtables destructors have run
+    - netfilter: nft_dynset: fix timeouts later than 23 days
+    - afs: Fix memory leak when mounting with multiple source parameters
+    - Revert "gpio: eic-sprd: Use devm_platform_ioremap_resource()"
+    - gpio: eic-sprd: break loop when getting NULL device resource
+    - netfilter: nft_ct: Remove confirmation check for NFT_CT_ID
+    - selftests/bpf/test_offload.py: Reset ethtool features after failed setting
+    - RDMA/cm: Fix an attempt to use non-valid pointer when cleaning timewait
+    - i40e: Refactor rx_bi accesses
+    - i40e: optimise prefetch page refcount
+    - i40e: avoid premature Rx buffer reuse
+    - ixgbe: avoid premature Rx buffer reuse
+    - selftests: fix poll error in udpgro.sh
+    - net: mvpp2: add mvpp2_phylink_to_port() helper
+    - drm/tegra: replace idr_init() by idr_init_base()
+    - kernel/cpu: add arch override for clear_tasks_mm_cpumask() mm handling
+    - drm/tegra: sor: Disable clocks on error in tegra_sor_init()
+    - habanalabs: put devices before driver removal
+    - arm64: syscall: exit userspace before unmasking exceptions
+    - vxlan: Add needed_headroom for lower device
+    - vxlan: Copy needed_tailroom from lowerdev
+    - scsi: mpt3sas: Increase IOCInit request timeout to 30s
+    - dm table: Remove BUG_ON(in_interrupt())
+    - iwlwifi: pcie: add one missing entry for AX210
+    - drm/amd/display: Init clock value by current vbios CLKs
+    - perf/x86/intel: Check PEBS status correctly
+    - kbuild: avoid split lines in .mod files
+    - soc/tegra: fuse: Fix index bug in get_process_id
+    - usb: mtu3: fix memory corruption in mtu3_debugfs_regset()
+    - USB: serial: option: add interface-number sanity check to flag handling
+    - USB: gadget: f_acm: add support for SuperSpeed Plus
+    - USB: gadget: f_midi: setup SuperSpeed Plus descriptors
+    - usb: gadget: f_fs: Re-use SS descriptors for SuperSpeedPlus
+    - USB: gadget: f_rndis: fix bitrate for SuperSpeed and above
+    - usb: chipidea: ci_hdrc_imx: Pass DISABLE_DEVICE_STREAMING flag to imx6ul
+    - ARM: dts: exynos: fix roles of USB 3.0 ports on Odroid XU
+    - ARM: dts: exynos: fix USB 3.0 VBUS control and over-current pins on
+      Exynos5410
+    - ARM: dts: exynos: fix USB 3.0 pins supply being turned off on Odroid XU
+    - coresight: tmc-etf: Fix NULL ptr dereference in tmc_enable_etf_sink_perf()
+    - coresight: tmc-etr: Check if page is valid before dma_map_page()
+    - coresight: tmc-etr: Fix barrier packet insertion for perf buffer
+    - coresight: etb10: Fix possible NULL ptr dereference in etb_enable_perf()
+    - scsi: megaraid_sas: Check user-provided offsets
+    - HID: i2c-hid: add Vero K147 to descriptor override
+    - serial_core: Check for port state when tty is in error state
+    - Bluetooth: Fix slab-out-of-bounds read in hci_le_direct_adv_report_evt()
+    - quota: Sanity-check quota file headers on load
+    - media: msi2500: assign SPI bus number dynamically
+    - crypto: af_alg - avoid undefined behavior accessing salg_name
+    - md: fix a warning caused by a race between concurrent md_ioctl()s
+    - drm/gma500: fix double free of gma_connector
+    - drm/aspeed: Fix Kconfig warning & subsequent build errors
+    - drm/mcde: Fix handling of platform_get_irq() error
+    - drm/tve200: Fix handling of platform_get_irq() error
+    - arm64: dts: renesas: hihope-rzg2-ex: Drop rxc-skew-ps from ethernet-phy node
+    - arm64: dts: renesas: cat875: Remove rxc-skew-ps from ethernet-phy node
+    - soc: renesas: rmobile-sysc: Fix some leaks in rmobile_init_pm_domains()
+    - soc: mediatek: Check if power domains can be powered on at boot time
+    - soc: qcom: geni: More properly switch to DMA mode
+    - Revert "i2c: i2c-qcom-geni: Fix DMA transfer race"
+    - RDMA/bnxt_re: Set queue pair state when being queried
+    - rtc: pcf2127: fix pcf2127_nvmem_read/write() returns
+    - selinux: fix error initialization in inode_doinit_with_dentry()
+    - ARM: dts: aspeed: s2600wf: Fix VGA memory region location
+    - RDMA/rxe: Compute PSN windows correctly
+    - x86/mm/ident_map: Check for errors from ident_pud_init()
+    - ARM: p2v: fix handling of LPAE translation in BE mode
+    - x86/apic: Fix x2apic enablement without interrupt remapping
+    - sched/deadline: Fix sched_dl_global_validate()
+    - sched: Reenable interrupts in do_sched_yield()
+    - drm/amdgpu: fix incorrect enum type
+    - crypto: talitos - Endianess in current_desc_hdr()
+    - crypto: talitos - Fix return type of current_desc_hdr()
+    - crypto: inside-secure - Fix sizeof() mismatch
+    - ASoC: sun4i-i2s: Fix lrck_period computation for I2S justified mode
+    - ARM: dts: aspeed: tiogapass: Remove vuart
+    - drm/amdgpu: fix build_coefficients() argument
+    - powerpc/64: Set up a kernel stack for secondaries before cpu_restore()
+    - spi: img-spfi: fix reference leak in img_spfi_resume
+    - f2fs: call f2fs_get_meta_page_retry for nat page
+    - drm/msm/dsi_pll_10nm: restore VCO rate during restore_state
+    - spi: spi-mem: fix reference leak in spi_mem_access_start
+    - ASoC: pcm: DRAIN support reactivation
+    - selinux: fix inode_doinit_with_dentry() LABEL_INVALID error handling
+    - spi: stm32: fix reference leak in stm32_spi_resume
+    - brcmfmac: Fix memory leak for unpaired brcmf_{alloc/free}
+    - arm64: dts: exynos: Include common syscon restart/poweroff for Exynos7
+    - arm64: dts: exynos: Correct psci compatible used on Exynos7
+    - Bluetooth: Fix null pointer dereference in hci_event_packet()
+    - Bluetooth: hci_h5: fix memory leak in h5_close
+    - spi: spi-ti-qspi: fix reference leak in ti_qspi_setup
+    - spi: mt7621: fix missing clk_disable_unprepare() on error in
+      mt7621_spi_probe
+    - 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
+    - spi: bcm63xx-hsspi: fix missing clk_disable_unprepare() on error in
+      bcm63xx_hsspi_resume
+    - mwifiex: fix mwifiex_shutdown_sw() causing sw reset failure
+    - selftest/bpf: Add missed ip6ip6 test back
+    - ASoC: wm8998: Fix PM disable depth imbalance on error
+    - spi: sprd: fix reference leak in sprd_spi_remove
+    - ASoC: arizona: Fix a wrong free in wm8997_probe
+    - RDMa/mthca: Work around -Wenum-conversion warning
+    - MIPS: BCM47XX: fix kconfig dependency bug for BCM47XX_BCMA
+    - crypto: qat - fix status check in qat_hal_put_rel_rd_xfer()
+    - staging: greybus: codecs: Fix reference counter leak in error handling
+    - staging: gasket: interrupt: fix the missed eventfd_ctx_put() in
+      gasket_interrupt.c
+    - media: tm6000: Fix sizeof() mismatches
+    - media: mtk-vcodec: add missing put_device() call in mtk_vcodec_init_dec_pm()
+    - media: mtk-vcodec: add missing put_device() call in
+      mtk_vcodec_release_dec_pm()
+    - media: mtk-vcodec: add missing put_device() call in mtk_vcodec_init_enc_pm()
+    - media: v4l2-fwnode: Return -EINVAL for invalid bus-type
+    - ASoC: meson: fix COMPILE_TEST error
+    - scsi: core: Fix VPD LUN ID designator priorities
+    - media: solo6x10: fix missing snd_card_free in error handling case
+    - video: fbdev: atmel_lcdfb: fix return error code in atmel_lcdfb_of_init()
+    - drm/omap: dmm_tiler: fix return error code in omap_dmm_probe()
+    - Input: ads7846 - fix race that causes missing releases
+    - Input: ads7846 - fix integer overflow on Rt calculation
+    - Input: ads7846 - fix unaligned access on 7845
+    - usb/max3421: fix return error code in max3421_probe()
+    - spi: mxs: fix reference leak in mxs_spi_probe
+    - selftests/bpf: Fix broken riscv build
+    - powerpc: Avoid broken GCC __attribute__((optimize))
+    - powerpc/feature: Fix CPU_FTRS_ALWAYS by removing CPU_FTRS_GENERIC_32
+    - EDAC/mce_amd: Use struct cpuinfo_x86.cpu_die_id for AMD NodeId
+    - crypto: crypto4xx - Replace bitwise OR with logical OR in crypto4xx_build_pd
+    - crypto: omap-aes - Fix PM disable depth imbalance in omap_aes_probe
+    - spi: fix resource leak for drivers without .remove callback
+    - 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
+    - Input: omap4-keypad - fix runtime PM error handling
+    - clk: meson: Kconfig: fix dependency for G12A
+    - RDMA/cxgb4: Validate the number of CQEs
+    - 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
+    - mmc: pxamci: Fix error return code in pxamci_probe
+    - orinoco: Move context allocation after processing the skb
+    - qtnfmac: fix error return code in qtnf_pcie_probe()
+    - rsi: fix error return code in rsi_reset_card()
+    - cw1200: fix missing destroy_workqueue() on error in cw1200_init_common
+    - dmaengine: mv_xor_v2: Fix error return code in mv_xor_v2_probe()
+    - arm64: tegra: Fix DT binding for IO High Voltage entry
+    - media: siano: fix memory leak of debugfs members in smsdvb_hotplug
+    - platform/x86: mlx-platform: Remove PSU EEPROM from default platform
+      configuration
+    - platform/x86: mlx-platform: Remove PSU EEPROM from MSN274x platform
+      configuration
+    - samples: bpf: Fix lwt_len_hist reusing previous BPF map
+    - media: imx214: Fix stop streaming
+    - mips: cdmm: fix use-after-free in mips_cdmm_bus_discover
+    - media: max2175: fix max2175_set_csm_mode() error code
+    - slimbus: qcom-ngd-ctrl: Avoid sending power requests without QMI
+    - HSI: omap_ssi: Don't jump to free ID in ssi_add_controller()
+    - ARM: dts: Remove non-existent i2c1 from 98dx3236
+    - arm64: dts: armada-3720-turris-mox: update ethernet-phy handle name
+    - arm64: dts: rockchip: Set dr_mode to "host" for OTG on rk3328-roc-cc
+    - power: supply: axp288_charger: Fix HP Pavilion x2 10 DMI matching
+    - power: supply: bq24190_charger: fix reference leak
+    - genirq/irqdomain: Don't try to free an interrupt that has no mapping
+    - arm64: dts: ls1028a: fix ENETC PTP clock input
+    - arm64: dts: qcom: c630: Polish i2c-hid devices
+    - PCI: Bounds-check command-line resource alignment requests
+    - PCI: Fix overflow in command-line resource alignment requests
+    - PCI: iproc: Fix out-of-bound array accesses
+    - arm64: dts: meson: fix spi-max-frequency on Khadas VIM2
+    - arm64: dts: meson-sm1: fix typo in opp table
+    - soc: amlogic: canvas: add missing put_device() call in meson_canvas_get()
+    - ARM: dts: at91: at91sam9rl: fix ADC triggers
+    - platform/x86: dell-smbios-base: Fix error return code in dell_smbios_init
+    - ath10k: Fix the parsing error in service available event
+    - ath10k: Fix an error handling path
+    - ath10k: Release some resources in an error handling path
+    - SUNRPC: rpc_wake_up() should wake up tasks in the correct order
+    - NFSv4.2: condition READDIR's mask for security label based on LSM state
+    - SUNRPC: xprt_load_transport() needs to support the netid "rdma6"
+    - NFSv4: Fix the alignment of page data in the getdeviceinfo reply
+    - net: sunrpc: Fix 'snprintf' return value check in 'do_xprt_debugfs'
+    - lockd: don't use interval-based rebinding over TCP
+    - NFS: switch nfsiod to be an UNBOUND workqueue.
+    - selftests/seccomp: Update kernel config
+    - vfio-pci: Use io_remap_pfn_range() for PCI IO memory
+    - hwmon: (ina3221) Fix PM usage counter unbalance in ina3221_write_enable
+    - media: saa7146: fix array overflow in vidioc_s_audio()
+    - powerpc/perf: Fix crash with is_sier_available when pmu is not set
+    - powerpc/64: Fix an EMIT_BUG_ENTRY in head_64.S
+    - clocksource/drivers/orion: Add missing clk_disable_unprepare() on error path
+    - clocksource/drivers/cadence_ttc: Fix memory leak in ttc_setup_clockevent()
+    - iio: hrtimer-trigger: Mark hrtimer to expire in hard interrupt context
+    - ARM: dts: at91: sama5d2: map securam as device
+    - bpf: Fix bpf_put_raw_tracepoint()'s use of __module_address()
+    - pinctrl: falcon: add missing put_device() call in pinctrl_falcon_probe()
+    - arm64: dts: rockchip: Fix UART pull-ups on rk3328
+    - memstick: r592: Fix error return in r592_probe()
+    - MIPS: Don't round up kernel sections size for memblock_add()
+    - net/mlx5: Properly convey driver version to firmware
+    - ASoC: jz4740-i2s: add missed checks for clk_get()
+    - dm ioctl: fix error return code in target_message
+    - phy: renesas: rcar-gen3-usb2: disable runtime pm in case of failure
+    - clocksource/drivers/arm_arch_timer: Use stable count reader in erratum sne
+    - clocksource/drivers/arm_arch_timer: Correct fault programming of
+      CNTKCTL_EL1.EVNTI
+    - cpufreq: ap806: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: highbank: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: mediatek: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: qcom: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: st: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: sun50i: Add missing MODULE_DEVICE_TABLE
+    - cpufreq: loongson1: Add missing MODULE_ALIAS
+    - cpufreq: scpi: Add missing MODULE_ALIAS
+    - Bluetooth: btusb: Add the missed release_firmware() in
+      btusb_mtk_setup_firmware()
+    - Bluetooth: btmtksdio: Add the missed release_firmware() in
+      mtk_setup_firmware()
+    - arm64: dts: meson: fix PHY deassert timing requirements
+    - ARM: dts: meson: fix PHY deassert timing requirements
+    - arm64: dts: meson: g12a: x96-max: fix PHY deassert timing requirements
+    - scsi: qedi: Fix missing destroy_workqueue() on error in __qedi_probe
+    - 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()
+    - platform/x86: mlx-platform: Fix item counter assignment for MSN2700, MSN24xx
+      systems
+    - powerpc/pseries/hibernation: drop pseries_suspend_begin() from suspend ops
+    - powerpc/pseries/hibernation: remove redundant cacheinfo update
+    - drm/mediatek: avoid dereferencing a null hdmi_phy on an error message
+    - ASoC: amd: change clk_get() to devm_clk_get() and add missed checks
+    - powerpc/mm: sanity_check_fault() should work for all, not only BOOK3S
+    - 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
+    - nfsd: Fix message level for normal termination
+    - nfs_common: need lock during iterate through the list
+    - x86/kprobes: Restore BTF if the single-stepping is cancelled
+    - platform/chrome: cros_ec_spi: Don't overwrite spi::mode
+    - bus: fsl-mc: fix error return code in fsl_mc_object_allocate()
+    - s390/cio: fix use-after-free in ccw_device_destroy_console
+    - iwlwifi: mvm: hook up missing RX handlers
+    - erofs: avoid using generic_block_bmap
+    - can: m_can: m_can_config_endisable(): remove double clearing of clock stop
+      request bit
+    - RDMA/core: Do not indicate device ready when device enablement fails
+    - remoteproc: q6v5-mss: fix error handling in q6v5_pds_enable
+    - remoteproc: qcom: fix reference leak in adsp_start
+    - remoteproc: qcom: Fix potential NULL dereference in adsp_init_mmio()
+    - clk: tegra: Fix duplicated SE clock entry
+    - mtd: rawnand: gpmi: fix reference count leak in gpmi ops
+    - mtd: rawnand: meson: Fix a resource leak in init
+    - mtd: rawnand: gpmi: Fix the random DMA timeout issue
+    - extcon: max77693: Fix modalias string
+    - crypto: atmel-i2c - select CONFIG_BITREVERSE
+    - mac80211: don't set set TDLS STA bandwidth wider than possible
+    - ASoC: wm_adsp: remove "ctl" from list on error in wm_adsp_create_control()
+    - irqchip/alpine-msi: Fix freeing of interrupts on allocation error path
+    - watchdog: armada_37xx: Add missing dependency on HAS_IOMEM
+    - watchdog: sirfsoc: Add missing dependency on HAS_IOMEM
+    - watchdog: sprd: remove watchdog disable from resume fail path
+    - watchdog: sprd: check busy bit before new loading rather than after that
+    - watchdog: Fix potential dereferencing of null pointer
+    - ubifs: Fix error return code in ubifs_init_authentication()
+    - um: Monitor error events in IRQ controller
+    - um: tty: Fix handling of close in tty lines
+    - um: chan_xterm: Fix fd leak
+    - sunrpc: fix xs_read_xdr_buf for partial pages receive
+    - RDMA/cma: Don't overwrite sgid_attr after device is released
+    - nfc: s3fwrn5: Release the nfc firmware
+    - powerpc/ps3: use dma_mapping_error()
+    - sparc: fix handling of page table constructor failure
+    - mm: don't wake kswapd prematurely when watermark boosting is disabled
+    - checkpatch: fix unescaped left brace
+    - lan743x: fix rx_napi_poll/interrupt ping-pong
+    - 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
+    - libnvdimm/label: Return -ENXIO for no slot in __blk_label_update
+    - watchdog: qcom: Avoid context switch in restart handler
+    - watchdog: coh901327: add COMMON_CLK dependency
+    - clk: ti: Fix memleak in ti_fapll_synth_setup
+    - pwm: zx: Add missing cleanup in error path
+    - pwm: lp3943: Dynamically allocate PWM chip base
+    - perf record: Fix memory leak when using '--user-regs=?' to list registers
+    - qlcnic: Fix error code in probe
+    - virtio_ring: Cut and paste bugs in vring_create_virtqueue_packed()
+    - virtio_net: Fix error code in probe()
+    - virtio_ring: Fix two use after free bugs
+    - clk: at91: sam9x60: remove atmel,osc-bypass support
+    - clk: s2mps11: Fix a resource leak in error handling paths in the probe
+      function
+    - clk: sunxi-ng: Make sure divider tables have sentinel
+    - kconfig: fix return value of do_error_if()
+    - perf probe: Fix memory leak when synthesizing SDT probes
+    - ARM: sunxi: Add machine match for the Allwinner V3 SoC
+    - cfg80211: initialize rekey_data
+    - fix namespaced fscaps when !CONFIG_SECURITY
+    - lwt: Disable BH too in run_lwt_bpf()
+    - drm/amd/display: Prevent bandwidth overflow
+    - drm/amdkfd: Fix leak in dmabuf import
+    - Input: cros_ec_keyb - send 'scancodes' in addition to key events
+    - initramfs: fix clang build failure
+    - Input: goodix - add upside-down quirk for Teclast X98 Pro tablet
+    - vfio/pci/nvlink2: Do not attempt NPU2 setup on POWER8NVL NPU
+    - 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
+    - media: ipu3-cio2: Remove traces of returned buffers
+    - media: ipu3-cio2: Return actual subdev format
+    - media: ipu3-cio2: Serialise access to pad format
+    - media: ipu3-cio2: Validate mbus format in setting subdev format
+    - media: ipu3-cio2: Make the field on subdev format V4L2_FIELD_NONE
+    - Input: cyapa_gen6 - fix out-of-bounds stack access
+    - ALSA: hda/ca0132 - Change Input Source enum strings.
+    - Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources
+      walks"
+    - ACPI: PNP: compare the string length in the matching_id()
+    - ALSA: hda: Fix regressions on clear and reconfig sysfs
+    - ALSA: hda/ca0132 - Fix AE-5 rear headphone pincfg.
+    - ALSA: hda/realtek: make bass spk volume adjustable on a yoga laptop
+    - ALSA: hda/realtek - Enable headset mic of ASUS X430UN with ALC256
+    - ALSA: hda/realtek - Enable headset mic of ASUS Q524UQK with ALC255
+    - ALSA: hda/realtek - Add supported for more Lenovo ALC285 Headset Button
+    - ALSA: pcm: oss: Fix a few more UBSAN fixes
+    - ALSA/hda: apply jack fixup for the Acer Veriton N4640G/N6640G/N2510G
+    - ALSA: hda/realtek: Add quirk for MSI-GP73
+    - ALSA: hda/realtek: Apply jack fixup for Quanta NL3
+    - ALSA: usb-audio: Add VID to support native DSD reproduction on FiiO devices
+    - ALSA: usb-audio: Disable sample read check if firmware doesn't give back
+    - ALSA: core: memalloc: add page alignment for iram
+    - s390/smp: perform initial CPU reset also for SMT siblings
+    - s390/kexec_file: fix diag308 subcode when loading crash kernel
+    - s390/dasd: fix hanging device offline processing
+    - s390/dasd: prevent inconsistent LCU device data
+    - s390/dasd: fix list corruption of pavgroup group list
+    - s390/dasd: fix list corruption of lcu list
+    - binder: add flag to clear buffer on txn complete
+    - ASoC: cx2072x: Fix doubly definitions of Playback and Capture streams
+    - staging: comedi: mf6x4: Fix AI end-of-conversion detection
+    - perf/x86/intel: Add event constraint for CYCLE_ACTIVITY.STALLS_MEM_ANY
+    - perf/x86/intel: Fix rtm_abort_event encoding on Ice Lake
+    - powerpc/perf: Exclude kernel samples while counting events in user space.
+    - crypto: ecdh - avoid unaligned accesses in ecdh_set_secret()
+    - crypto: arm/aes-ce - work around Cortex-A57/A72 silion errata
+    - EDAC/i10nm: Use readl() to access MMIO registers
+    - EDAC/amd64: Fix PCI component registration
+    - cpuset: fix race between hotplug work and later CPU offline
+    - USB: serial: mos7720: fix parallel-port state restore
+    - USB: serial: digi_acceleport: fix write-wakeup deadlocks
+    - 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: do not shorten unpin len for caching block groups
+    - ext4: fix a memory leak of ext4_free_data
+    - ext4: fix deadlock with fs freezing and EA inodes
+    - KVM: arm64: Introduce handling of AArch32 TTBCR2 traps
+    - ARM: dts: pandaboard: fix pinmux for gpio user button of Pandaboard ES
+    - ARM: dts: at91: sama5d2: fix CAN message ram offset and size
+    - xprtrdma: Fix XDRBUF_SPARSE_PAGES support
+    - powerpc: Fix incorrect stw{, ux, u, x} instructions in __set_pte_at
+    - powerpc/rtas: Fix typo of ibm,open-errinjct in RTAS filter
+    - powerpc/feature: Add CPU_FTR_NOEXECUTE to G2_LE
+    - powerpc/xmon: Change printk() to pr_cont()
+    - powerpc/8xx: Fix early debug when SMC1 is relocated
+    - powerpc/mm: Fix verification of MMU_FTR_TYPE_44x
+    - powerpc/powernv/npu: Do not attempt NPU2 setup on POWER8NVL NPU
+    - powerpc/powernv/memtrace: Don't leak kernel memory to user space
+    - powerpc/powernv/memtrace: Fix crashing the kernel when enabling concurrently
+    - ima: Don't modify file descriptor mode on the fly
+    - um: Remove use of asprinf in umid.c
+    - ceph: fix race in concurrent __ceph_remove_cap invocations
+    - SMB3: avoid confusing warning message on mount to Azure
+    - ubifs: wbuf: Don't leak kernel memory to flash
+    - jffs2: Fix GC exit abnormally
+    - jffs2: Fix ignoring mounting options problem during remounting
+    - jfs: Fix array index bounds check in dbAdjTree
+    - platform/x86: mlx-platform: remove an unused variable
+    - drm/amd/display: Fix memory leaks in S3 resume
+    - drm/dp_aux_dev: check aux_dev before use in drm_dp_aux_dev_get_by_minor()
+    - drm/i915: Fix mismatch between misplaced vma check and vma insert
+    - spi: pxa2xx: Fix use-after-free on unbind
+    - spi: spi-sh: Fix use-after-free on unbind
+    - spi: atmel-quadspi: Fix use-after-free on unbind
+    - spi: davinci: Fix use-after-free on unbind
+    - spi: fsl: fix use of spisel_boot signal on MPC8309
+    - spi: gpio: Don't leak SPI master in probe error path
+    - spi: mxic: Don't leak SPI master in probe error path
+    - spi: pic32: Don't leak DMA channels in probe error path
+    - spi: rb4xx: Don't leak SPI master in probe error path
+    - spi: sc18is602: Don't leak SPI master in probe error path
+    - spi: st-ssc4: Fix unbalanced pm_runtime_disable() in probe error path
+    - spi: synquacer: Disable clock in probe error path
+    - spi: mt7621: Disable clock in probe error path
+    - spi: mt7621: Don't leak SPI master in probe error path
+    - spi: atmel-quadspi: Disable clock in probe error path
+    - spi: atmel-quadspi: Fix AHB memory accesses
+    - soc: qcom: smp2p: Safely acquire spinlock without IRQs
+    - mtd: spinand: Fix OOB read
+    - mtd: parser: cmdline: Fix parsing of part-names with colons
+    - mtd: rawnand: qcom: Fix DMA sync on FLASH_STATUS register read
+    - mtd: rawnand: meson: fix meson_nfc_dma_buffer_release() arguments
+    - scsi: qla2xxx: Fix crash during driver load on big endian machines
+    - scsi: lpfc: Fix invalid sleeping context in lpfc_sli4_nvmet_alloc()
+    - scsi: lpfc: Re-fix use after free in lpfc_rq_buf_free()
+    - iio: buffer: Fix demux update
+    - iio: adc: rockchip_saradc: fix missing clk_disable_unprepare() on error in
+      rockchip_saradc_resume
+    - iio:light:rpr0521: Fix timestamp alignment and prevent data leak.
+    - iio:light:st_uvis25: Fix timestamp alignment and prevent data leak.
+    - iio:magnetometer:mag3110: Fix alignment and data leak issues.
+    - iio:pressure:mpl3115: Force alignment of buffer
+    - iio:imu:bmi160: Fix too large a buffer.
+    - iio:adc:ti-ads124s08: Fix buffer being too long.
+    - iio:adc:ti-ads124s08: Fix alignment and data leak issues.
+    - md/cluster: block reshape with remote resync job
+    - md/cluster: fix deadlock when node is doing resync job
+    - pinctrl: sunxi: Always call chained_irq_{enter, exit} in
+      sunxi_pinctrl_irq_handler
+    - clk: ingenic: Fix divider calculation with div tables
+    - clk: mvebu: a3700: fix the XTAL MODE pin to MPP1_9
+    - clk: tegra: Do not return 0 on failure
+    - device-dax/core: Fix memory leak when rmmod dax.ko
+    - dma-buf/dma-resv: Respect num_fences when initializing the shared fence
+      list.
+    - xen-blkback: set ring->xenblkd to NULL after kthread_stop()
+    - 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
+    - libnvdimm/namespace: Fix reaping of invalidated block-window-namespace
+      labels
+    - platform/x86: intel-vbtn: Allow switch events on Acer Switch Alpha 12
+    - PCI: Fix pci_slot_release() NULL pointer dereference
+    - regulator: axp20x: Fix DLDO2 voltage control register mask for AXP22x
+    - rtc: ep93xx: Fix NULL pointer dereference in ep93xx_rtc_read_time
+    - Revert: "ring-buffer: Remove HAVE_64BIT_ALIGNED_ACCESS"
+    - x86/CPU/AMD: Save AMD NodeId as cpu_die_id
+    - Linux 5.4.86
+
+  * Focal update: v5.4.85 upstream stable release (LP: #1910817)
+    - ptrace: Prevent kernel-infoleak in ptrace_get_syscall_info()
+    - ipv4: fix error return code in rtm_to_fib_config()
+    - mac80211: mesh: fix mesh_pathtbl_init() error path
+    - net: bridge: vlan: fix error return code in __vlan_add()
+    - vrf: packets with lladdr src needs dst at input with orig_iif when needs
+      strict
+    - net: hns3: remove a misused pragma packed
+    - udp: fix the proto value passed to ip_protocol_deliver_rcu for the segments
+    - enetc: Fix reporting of h/w packet counters
+    - bridge: Fix a deadlock when enabling multicast snooping
+    - net: stmmac: free tx skb buffer in stmmac_resume()
+    - tcp: select sane initial rcvq_space.space for big MSS
+    - tcp: fix cwnd-limited bug for TSO deferral where we send nothing
+    - net/mlx4_en: Avoid scheduling restart task if it is already running
+    - lan743x: fix for potential NULL pointer dereference with bare card
+    - net/mlx4_en: Handle TX error CQE
+    - net: ll_temac: Fix potential NULL dereference in temac_probe()
+    - net: stmmac: dwmac-meson8b: fix mask definition of the m250_sel mux
+    - net: stmmac: delete the eee_ctrl_timer after napi disabled
+    - ktest.pl: If size of log is too big to email, email error message
+    - 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
+    - xhci-pci: Allow host runtime PM as default for Intel Alpine Ridge LP
+    - USB: UAS: introduce a quirk to set no_write_same
+    - 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
+    - KVM: mmu: Fix SPTE encoding of MMIO generation upper half
+    - membarrier: Explicitly sync remote cores when SYNC_CORE is requested
+    - x86/resctrl: Remove unused struct mbm_state::chunks_bw
+    - x86/resctrl: Fix incorrect local bandwidth when mba_sc is enabled
+    - Linux 5.4.85
+
+  * Focal update: v5.4.84 upstream stable release (LP: #1910816)
+    - Kbuild: do not emit debug info for assembly with LLVM_IAS=1
+    - x86/lib: Change .weak to SYM_FUNC_START_WEAK for arch/x86/lib/mem*_64.S
+    - iwlwifi: pcie: limit memory read spin time
+    - arm64: dts: rockchip: Assign a fixed index to mmc devices on rk3399 boards.
+    - iwlwifi: pcie: set LTR to avoid completion timeout
+    - iwlwifi: mvm: fix kernel panic in case of assert during CSA
+    - powerpc: Drop -me200 addition to build flags
+    - arm64: dts: broadcom: clear the warnings caused by empty dma-ranges
+    - ARC: stack unwinding: don't assume non-current task is sleeping
+    - scsi: ufs: Make sure clk scaling happens only when HBA is runtime ACTIVE
+    - interconnect: qcom: qcs404: Remove GPU and display RPM IDs
+    - ibmvnic: skip tx timeout reset while in resetting
+    - irqchip/gic-v3-its: Unconditionally save/restore the ITS state on suspend
+    - spi: spi-nxp-fspi: fix fspi panic by unexpected interrupts
+    - soc: fsl: dpio: Get the cpumask through cpumask_of(cpu)
+    - arm64: tegra: Disable the ACONNECT for Jetson TX2
+    - platform/x86: thinkpad_acpi: Do not report SW_TABLET_MODE on Yoga 11e
+    - platform/x86: thinkpad_acpi: Add BAT1 is primary battery quirk for Thinkpad
+      Yoga 11e 4th gen
+    - platform/x86: acer-wmi: add automatic keyboard background light toggle key
+      as KEY_LIGHTS_TOGGLE
+    - platform/x86: intel-vbtn: Support for tablet mode on HP Pavilion 13 x360 PC
+    - platform/x86: touchscreen_dmi: Add info for the Irbis TW118 tablet
+    - can: m_can: m_can_dev_setup(): add support for bosch mcan version 3.3.0
+    - ktest.pl: Fix incorrect reboot for grub2bls
+    - Input: cm109 - do not stomp on control URB
+    - Input: i8042 - add Acer laptops to the i8042 reset list
+    - mmc: block: Fixup condition for CMD13 polling for RPMB requests
+    - drm/i915/display/dp: Compute the correct slice count for VDSC on DP
+    - kbuild: avoid static_assert for genksyms
+    - proc: use untagged_addr() for pagemap_read addresses
+    - scsi: be2iscsi: Revert "Fix a theoretical leak in beiscsi_create_eqs()"
+    - x86/mm/mem_encrypt: Fix definition of PMD_FLAGS_DEC_WP
+    - x86/membarrier: Get rid of a dubious optimization
+    - x86/apic/vector: Fix ordering in vector assignment
+    - mm/zsmalloc.c: drop ZSMALLOC_PGTABLE_MAPPING
+    - [Config] updateconfigs for PGTABLE_MAPPING
+    - compiler.h: fix barrier_data() on clang
+    - Linux 5.4.84
+
+  * MSFT Touchpad not working on Lenovo Legion-5 15ARH05 (LP: #1887190) // Focal
+    update: v5.4.84 upstream stable release (LP: #1910816)
+    - pinctrl: amd: remove debounce filter setting in IRQ type setting
+
+  * Focal update: v5.4.83 upstream stable release (LP: #1910784)
+    - pinctrl: baytrail: Replace WARN with dev_info_once when setting direct-irq
+      pin to output
+    - pinctrl: baytrail: Fix pin being driven low for a while on gpiod_get(...,
+      GPIOD_OUT_HIGH)
+    - 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
+    - USB: serial: option: fix Quectel BG96 matching
+    - tty: Fix ->pgrp locking in tiocspgrp()
+    - tty: Fix ->session locking
+    - ALSA: hda/realtek: Fix bass speaker DAC assignment on Asus Zephyrus G14
+    - ALSA: hda/realtek: Add mute LED quirk to yet another HP x360 model
+    - ALSA: hda/realtek: Enable headset of ASUS UX482EG & B9400CEA with ALC294
+    - ALSA: hda/realtek - Add new codec supported for ALC897
+    - ALSA: hda/generic: Add option to enforce preferred_dacs pairs
+    - ftrace: Fix updating FTRACE_FL_TRAMP
+    - cifs: allow syscalls to be restarted in __smb_send_rqst()
+    - cifs: fix potential use-after-free in cifs_echo_request()
+    - i2c: imx: Don't generate STOP condition if arbitration has been lost
+    - thunderbolt: Fix use-after-free in remove_unplugged_switch()
+    - drm/i915/gt: Program mocs:63 for cache eviction on gen9
+    - scsi: mpt3sas: Fix ioctl timeout
+    - dm writecache: fix the maximum number of arguments
+    - powerpc/64s/powernv: Fix memory corruption when saving SLB entries on MCE
+    - genirq/irqdomain: Add an irq_create_mapping_affinity() function
+    - powerpc/pseries: Pass MSI affinity to irq_create_mapping()
+    - dm: fix bug with RCU locking in dm_blk_report_zones
+    - dm: remove invalid sparse __acquires and __releases annotations
+    - x86/uprobes: Do not use prefixes.nbytes when looping over prefixes.bytes
+    - coredump: fix core_pattern parse error
+    - mm: list_lru: set shrinker map bit when child nr_items is not zero
+    - mm/swapfile: do not sleep with a spin lock held
+    - speakup: Reject setting the speakup line discipline outside of speakup
+    - i2c: imx: Fix reset of I2SR_IAL flag
+    - i2c: imx: Check for I2SR_IAL after every byte
+    - spi: bcm2835: Release the DMA channel if probe fails after dma_init
+    - iommu/amd: Set DTE[IntTabLen] to represent 512 IRTEs
+    - tracing: Fix userstacktrace option for instances
+    - lib/syscall: fix syscall registers retrieval on 32-bit platforms
+    - can: af_can: can_rx_unregister(): remove WARN() statement from list
+      operation sanity check
+    - gfs2: check for empty rgrp tree in gfs2_ri_update
+    - netfilter: ipset: prevent uninit-value in hash_ip6_add
+    - tipc: fix a deadlock when flushing scheduled work
+    - ASoC: wm_adsp: fix error return code in wm_adsp_load()
+    - rtw88: debug: Fix uninitialized memory in debugfs code
+    - i2c: qup: Fix error return code in qup_i2c_bam_schedule_desc()
+    - dm writecache: remove BUG() and fail gracefully instead
+    - Input: i8042 - fix error return code in i8042_setup_aux()
+    - netfilter: nf_tables: avoid false-postive lockdep splat
+    - netfilter: nftables_offload: set address type in control dissector
+    - x86/insn-eval: Use new for_each_insn_prefix() macro to loop over prefixes
+      bytes
+    - Linux 5.4.83
+
+  * dep-8 ubuntu-regression-suite tests are not run for all linux-hwe-* kernels
+    (LP: #1908529)
+    - [dep-8] Allow all hwe kernels
+
+  * failing ftrace self tests from 5.7+ onwards (LP: #1893024)
+    - SAUCE: Revert "selftests/ftrace: check for do_sys_openat2 in user-memory
+      test"
+
+  * selftests: test_vxlan_under_vrf: mute unnecessary error message
+    (LP: #1908342)
+    - selftests: test_vxlan_under_vrf: mute unnecessary error message
+
+  * Focal update: v5.4.82 upstream stable release (LP: #1908564)
+    - devlink: Hold rtnl lock while reading netdev attributes
+    - ipv6: addrlabel: fix possible memory leak in ip6addrlbl_net_init
+    - net/af_iucv: set correct sk_protocol for child sockets
+    - net/tls: missing received data after fast remote close
+    - net/tls: Protect from calling tls_dev_del for TLS RX twice
+    - rose: Fix Null pointer dereference in rose_send_frame()
+    - sock: set sk_err to ee_errno on dequeue from errq
+    - tcp: Set INET_ECN_xmit configuration in tcp_reinit_congestion_control
+    - tun: honor IOCB_NOWAIT flag
+    - usbnet: ipheth: fix connectivity with iOS 14
+    - bonding: wait for sysfs kobject destruction before freeing struct slave
+    - staging/octeon: fix up merge error
+    - ima: extend boot_aggregate with kernel measurements
+    - sched/fair: Fix unthrottle_cfs_rq() for leaf_cfs_rq list
+    - netfilter: bridge: reset skb->pkt_type after NF_INET_POST_ROUTING traversal
+    - ipv4: Fix tos mask in inet_rtm_getroute()
+    - dt-bindings: net: correct interrupt flags in examples
+    - chelsio/chtls: fix panic during unload reload chtls
+    - ibmvnic: Ensure that SCRQ entry reads are correctly ordered
+    - ibmvnic: Fix TX completion error handling
+    - inet_ecn: Fix endianness of checksum update when setting ECT(1)
+    - net: ip6_gre: set dev->hard_header_len when using header_ops
+    - 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()
+    - vxlan: fix error return code in __vxlan_dev_create()
+    - chelsio/chtls: fix a double free in chtls_setkey()
+    - net: mvpp2: Fix error return code in mvpp2_open()
+    - net: skbuff: ensure LSE is pullable before decrementing the MPLS ttl
+    - net: openvswitch: ensure LSE is pullable before reading it
+    - net/sched: act_mpls: ensure LSE is pullable before reading it
+    - net/mlx5: DR, Proper handling of unsupported Connect-X6DX SW steering
+    - net/mlx5: Fix wrong address reclaim when command interface is down
+    - ALSA: usb-audio: US16x08: fix value count for level meters
+    - Input: xpad - support Ardwiino Controllers
+    - tracing: Remove WARN_ON in start_thread()
+    - RDMA/i40iw: Address an mmap handler exploit in i40iw
+    - Linux 5.4.82
+
+  * Focal update: v5.4.81 upstream stable release (LP: #1908562)
+    - spi: bcm-qspi: Fix use-after-free on unbind
+    - spi: bcm2835: Fix use-after-free on unbind
+    - ipv4: use IS_ENABLED instead of ifdef
+    - netfilter: clear skb->next in NF_HOOK_LIST()
+    - btrfs: tree-checker: add missing return after error in root_item
+    - btrfs: tree-checker: add missing returns after data_ref alignment checks
+    - btrfs: don't access possibly stale fs_info data for printing duplicate
+      device
+    - btrfs: fix lockdep splat when reading qgroup config on mount
+    - wireless: Use linux/stddef.h instead of stddef.h
+    - smb3: Call cifs reconnect from demultiplex thread
+    - smb3: Avoid Mid pending list corruption
+    - smb3: Handle error case during offload read path
+    - cifs: fix a memleak with modefromsid
+    - KVM: PPC: Book3S HV: XIVE: Fix possible oops when accessing ESB page
+    - KVM: arm64: vgic-v3: Drop the reporting of GICR_TYPER.Last for userspace
+    - KVM: x86: handle !lapic_in_kernel case in kvm_cpu_*_extint
+    - KVM: x86: Fix split-irqchip vs interrupt injection window request
+    - trace: fix potenial dangerous pointer
+    - arm64: pgtable: Fix pte_accessible()
+    - arm64: pgtable: Ensure dirty bit is preserved across pte_wrprotect()
+    - HID: uclogic: Add ID for Trust Flex Design Tablet
+    - HID: ite: Replace ABS_MISC 120/121 events with touchpad on/off keypresses
+    - HID: cypress: Support Varmilo Keyboards' media hotkeys
+    - HID: add support for Sega Saturn
+    - Input: i8042 - allow insmod to succeed on devices without an i8042
+      controller
+    - HID: hid-sensor-hub: Fix issue with devices with no report ID
+    - staging: ralink-gdma: fix kconfig dependency bug for DMA_RALINK
+    - HID: add HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE for Gamevice devices
+    - dmaengine: xilinx_dma: use readl_poll_timeout_atomic variant
+    - x86/xen: don't unbind uninitialized lock_kicker_irq
+    - HID: logitech-hidpp: Add HIDPP_CONSUMER_VENDOR_KEYS quirk for the Dinovo
+      Edge
+    - HID: Add Logitech Dinovo Edge battery quirk
+    - proc: don't allow async path resolution of /proc/self components
+    - nvme: free sq/cq dbbuf pointers when dbbuf set fails
+    - vhost scsi: fix cmd completion race
+    - dmaengine: pl330: _prep_dma_memcpy: Fix wrong burst size
+    - scsi: libiscsi: Fix NOP race condition
+    - scsi: target: iscsi: Fix cmd abort fabric stop race
+    - perf/x86: fix sysfs type mismatches
+    - xtensa: uaccess: Add missing __user to strncpy_from_user() prototype
+    - net: dsa: mv88e6xxx: Wait for EEPROM done after HW reset
+    - bus: ti-sysc: Fix bogus resetdone warning on enable for cpsw
+    - ARM: OMAP2+: Manage MPU state properly for omap_enter_idle_coupled()
+    - phy: tegra: xusb: Fix dangling pointer on probe failure
+    - iwlwifi: mvm: write queue_sync_state only for sync
+    - batman-adv: set .owner to THIS_MODULE
+    - arch: pgtable: define MAX_POSSIBLE_PHYSMEM_BITS where needed
+    - ARM: dts: dra76x: m_can: fix order of clocks
+    - scsi: ufs: Fix race between shutdown and runtime resume flow
+    - bnxt_en: fix error return code in bnxt_init_one()
+    - 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.
+    - cxgb4: fix the panic caused by non smac rewrite
+    - s390/qeth: make af_iucv TX notification call more robust
+    - s390/qeth: fix af_iucv notification race
+    - s390/qeth: fix tear down of async TX buffers
+    - ibmvnic: fix call_netdevice_notifiers in do_reset
+    - ibmvnic: notify peers when failover and migration happen
+    - powerpc/64s: Fix allnoconfig build since uaccess flush
+    - IB/mthca: fix return value of error branch in mthca_init_cq()
+    - i40e: Fix removing driver while bare-metal VFs pass traffic
+    - nfc: s3fwrn5: use signed integer for parsing GPIO numbers
+    - net: ena: set initial DMA width to avoid intel iommu issue
+    - ibmvnic: fix NULL pointer dereference in reset_sub_crq_queues
+    - ibmvnic: fix NULL pointer dereference in ibmvic_reset_crq
+    - optee: add writeback to valid memory type
+    - arm64: tegra: Wrong AON HSP reg property size
+    - efivarfs: revert "fix memory leak in efivarfs_create()"
+    - efi: EFI_EARLYCON should depend on EFI
+    - can: gs_usb: fix endianess problem with candleLight firmware
+    - platform/x86: thinkpad_acpi: Send tablet mode switch at wakeup time
+    - platform/x86: toshiba_acpi: Fix the wrong variable assignment
+    - RDMA/hns: Fix retry_cnt and rnr_cnt when querying QP
+    - RDMA/hns: Bugfix for memory window mtpt configuration
+    - can: m_can: m_can_open(): remove IRQF_TRIGGER_FALLING from
+      request_threaded_irq()'s flags
+    - can: m_can: fix nominal bitiming tseg2 min for version >= 3.1
+    - perf stat: Use proper cpu for shadow stats
+    - perf probe: Fix to die_entrypc() returns error correctly
+    - spi: bcm2835aux: Restore err assignment in bcm2835aux_spi_probe
+    - USB: core: Change %pK for __user pointers to %px
+    - usb: gadget: f_midi: Fix memleak in f_midi_alloc
+    - USB: quirks: Add USB_QUIRK_DISCONNECT_SUSPEND quirk for Lenovo A630Z TIO
+      built-in usb-audio card
+    - usb: gadget: Fix memleak in gadgetfs_fill_super
+    - irqchip/exiu: Fix the index of fwspec for IRQ type
+    - x86/mce: Do not overwrite no_way_out if mce_end() fails
+    - x86/speculation: Fix prctl() when spectre_v2_user={seccomp,prctl},ibpb
+    - x86/resctrl: Remove superfluous kernfs_get() calls to prevent refcount leak
+    - x86/resctrl: Add necessary kernfs_put() calls to prevent refcount leak
+    - USB: core: Fix regression in Hercules audio card
+    - ASoC: Intel: Skylake: Remove superfluous chip initialization
+    - ASoC: Intel: Skylake: Select hda configuration permissively
+    - ASoC: Intel: Skylake: Enable codec wakeup during chip init
+    - ASoC: Intel: Skylake: Shield against no-NHLT configurations
+    - ASoC: Intel: Allow for ROM init retry on CNL platforms
+    - ASoC: Intel: Skylake: Await purge request ack on CNL
+    - ASoC: Intel: Multiple I/O PCM format support for pipe
+    - ASoC: Intel: Skylake: Automatic DMIC format configuration according to
+      information from NHLT
+    - Linux 5.4.81
+
+  * Focal update: v5.4.80 upstream stable release (LP: #1908561)
+    - ah6: fix error return code in ah6_input()
+    - atm: nicstar: Unmap DMA on send error
+    - bnxt_en: read EEPROM A2h address using page 0
+    - devlink: Add missing genlmsg_cancel() in devlink_nl_sb_port_pool_fill()
+    - Exempt multicast addresses from five-second neighbor lifetime
+    - inet_diag: Fix error path to cancel the meseage in inet_req_diag_fill()
+    - ipv6: Fix error path to cancel the meseage
+    - lan743x: fix issue causing intermittent kernel log warnings
+    - lan743x: prevent entire kernel HANG on open, for some platforms
+    - mlxsw: core: Use variable timeout for EMAD retries
+    - net: b44: fix error return code in b44_init_one()
+    - net: bridge: add missing counters to ndo_get_stats64 callback
+    - net: dsa: mv88e6xxx: Avoid VTU corruption on 6097
+    - net: ethernet: ti: cpsw: fix error return code in cpsw_probe()
+    - net: Have netpoll bring-up DSA management interface
+    - netlabel: fix our progress tracking in netlbl_unlabel_staticlist()
+    - netlabel: fix an uninitialized warning in netlbl_unlabel_staticlist()
+    - net: lantiq: Wait for the GPHY firmware to be ready
+    - net/mlx4_core: Fix init_hca fields offset
+    - net: qualcomm: rmnet: Fix incorrect receive packet handling during cleanup
+    - net/smc: fix direct access to ib_gid_addr->ndev in smc_ib_determine_gid()
+    - net/tls: fix corrupted data in recvmsg
+    - net: x25: Increase refcnt of "struct x25_neigh" in x25_rx_call_request
+    - page_frag: Recover from memory pressure
+    - qed: fix error return code in qed_iwarp_ll2_start()
+    - qlcnic: fix error return code in qlcnic_83xx_restart_hw()
+    - sctp: change to hold/put transport for proto_unreach_timer
+    - tcp: only postpone PROBE_RTT if RTT is < current min_rtt estimate
+    - net/mlx5: Add handling of port type in rule deletion
+    - net/mlx5: Disable QoS when min_rates on all VFs are zero
+    - net: usb: qmi_wwan: Set DTR quirk for MR400
+    - net/ncsi: Fix netlink registration
+    - net: ftgmac100: Fix crash when removing driver
+    - pinctrl: rockchip: enable gpio pclk for rockchip_gpio_to_irq
+    - scsi: ufs: Fix unbalanced scsi_block_reqs_cnt caused by ufshcd_hold()
+    - selftests: kvm: Fix the segment descriptor layout to match the actual layout
+    - ACPI: button: Add DMI quirk for Medion Akoya E2228T
+    - arm64: errata: Fix handling of 1418040 with late CPU onlining
+    - arm64: psci: Avoid printing in cpu_psci_cpu_die()
+    - arm64: smp: Tell RCU about CPUs that fail to come online
+    - vfs: remove lockdep bogosity in __sb_start_write
+    - gfs2: fix possible reference leak in gfs2_check_blk_type
+    - hwmon: (pwm-fan) Fix RPM calculation
+    - arm64: dts: allwinner: beelink-gs1: Enable both RGMII RX/TX delay
+    - arm64: dts: allwinner: Pine H64: Enable both RGMII RX/TX delay
+    - arm64: dts: allwinner: a64: OrangePi Win: Fix ethernet node
+    - arm64: dts: allwinner: a64: Pine64 Plus: Fix ethernet node
+    - arm64: dts: allwinner: h5: OrangePi PC2: Fix ethernet node
+    - ARM: dts: sun8i: r40: bananapi-m2-ultra: Fix ethernet node
+    - Revert "arm: sun8i: orangepi-pc-plus: Set EMAC activity LEDs to active high"
+    - ARM: dts: sun6i: a31-hummingbird: Enable RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sun7i: cubietruck: Enable RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sun7i: bananapi-m1-plus: Enable RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sun8i: h3: orangepi-plus2e: Enable RGMII RX/TX delay on Ethernet
+      PHY
+    - ARM: dts: sun8i: a83t: Enable both RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sun9i: Enable both RGMII RX/TX delay on Ethernet PHY
+    - ARM: dts: sunxi: bananapi-m2-plus: Enable RGMII RX/TX delay on Ethernet PHY
+    - arm64: dts: allwinner: a64: bananapi-m64: Enable RGMII RX/TX delay on PHY
+    - Input: adxl34x - clean up a data type in adxl34x_probe()
+    - MIPS: export has_transparent_hugepage() for modules
+    - arm64: dts: allwinner: h5: OrangePi Prime: Fix ethernet node
+    - arm64: dts imx8mn: Remove non-existent USB OTG2
+    - arm: dts: imx6qdl-udoo: fix rgmii phy-mode for ksz9031 phy
+    - swiotlb: using SIZE_MAX needs limits.h included
+    - arm64: dts: imx8mm: fix voltage for 1.6GHz CPU operating point
+    - ARM: dts: imx50-evk: Fix the chip select 1 IOMUX
+    - Input: resistive-adc-touch - fix kconfig dependency on IIO_BUFFER
+    - rfkill: Fix use-after-free in rfkill_resume()
+    - RDMA/pvrdma: Fix missing kfree() in pvrdma_register_device()
+    - [Config] updateconfigs for INFINIBAND_VIRT_DMA
+    - RMDA/sw: Don't allow drivers using dma_virt_ops on highmem configs
+    - perf lock: Don't free "lock_seq_stat" if read_count isn't zero
+    - tools, bpftool: Add missing close before bpftool net attach exit
+    - ip_tunnels: Set tunnel option flag when tunnel metadata is present
+    - can: af_can: prevent potential access of uninitialized member in can_rcv()
+    - can: af_can: prevent potential access of uninitialized member in canfd_rcv()
+    - can: dev: can_restart(): post buffer from the right context
+    - can: ti_hecc: Fix memleak in ti_hecc_probe
+    - can: mcba_usb: mcba_usb_start_xmit(): first fill skb, then pass to
+      can_put_echo_skb()
+    - can: peak_usb: fix potential integer overflow on shift of a int
+    - can: flexcan: fix failure handling of pm_runtime_get_sync()
+    - can: tcan4x5x: replace depends on REGMAP_SPI with depends on SPI
+    - can: tcan4x5x: tcan4x5x_can_probe(): add missing error checking for
+      devm_regmap_init()
+    - can: tcan4x5x: tcan4x5x_can_remove(): fix order of deregistration
+    - can: m_can: m_can_handle_state_change(): fix state change
+    - can: m_can: m_can_class_free_dev(): introduce new function
+    - can: m_can: m_can_stop(): set device to software init mode before closing
+    - ASoC: qcom: lpass-platform: Fix memory leak
+    - selftests/bpf: Fix error return code in run_getsockopt_test()
+    - MIPS: Alchemy: Fix memleak in alchemy_clk_setup_cpu
+    - drm/sun4i: dw-hdmi: fix error return code in sun8i_dw_hdmi_bind()
+    - net/mlx5: E-Switch, Fail mlx5_esw_modify_vport_rate if qos disabled
+    - bpf, sockmap: Fix partial copy_page_to_iter so progress can still be made
+    - bpf, sockmap: Ensure SO_RCVBUF memory is observed on ingress redirect
+    - can: kvaser_pciefd: Fix KCAN bittiming limits
+    - can: kvaser_usb: kvaser_usb_hydra: Fix KCAN bittiming limits
+    - iommu/vt-d: Move intel_iommu_gfx_mapped to Intel IOMMU header
+    - iommu/vt-d: Avoid panic if iommu init fails in tboot system
+    - can: flexcan: flexcan_chip_start(): fix erroneous
+      flexcan_transceiver_enable() during bus-off recovery
+    - can: m_can: process interrupt only when not runtime suspended
+    - xfs: fix the minrecs logic when dealing with inode root child blocks
+    - xfs: strengthen rmap record flags checking
+    - xfs: return corresponding errcode if xfs_initialize_perag() fail
+    - regulator: ti-abb: Fix array out of bound read access on the first
+      transition
+    - fail_function: Remove a redundant mutex unlock
+    - xfs: revert "xfs: fix rmap key and record comparison functions"
+    - bpf, sockmap: Skb verdict SK_PASS to self already checked rmem limits
+    - bpf, sockmap: On receive programs try to fast track SK_PASS ingress
+    - bpf, sockmap: Use truesize with sk_rmem_schedule()
+    - bpf, sockmap: Avoid returning unneeded EAGAIN when redirecting to self
+    - efi/x86: Free efi_pgd with free_pages()
+    - libfs: fix error cast of negative value in simple_attr_write()
+    - HID: logitech-hidpp: Add PID for MX Anywhere 2
+    - HID: logitech-dj: Handle quad/bluetooth keyboards with a builtin trackpad
+    - HID: logitech-dj: Fix Dinovo Mini when paired with a MX5x00 receiver
+    - speakup: Do not let the line discipline be used several times
+    - ALSA: firewire: Clean up a locking issue in copy_resp_to_buf()
+    - ALSA: usb-audio: Add delay quirk for all Logitech USB devices
+    - ALSA: ctl: fix error path at adding user-defined element set
+    - ALSA: mixart: Fix mutex deadlock
+    - ALSA: hda/realtek - Add supported for Lenovo ThinkPad Headset Button
+    - ALSA: hda/realtek: Add some Clove SSID in the ALC293(ALC1220)
+    - tty: serial: imx: fix potential deadlock
+    - tty: serial: imx: keep console clocks always on
+    - HID: logitech-dj: Fix an error in mse_bluetooth_descriptor
+    - efivarfs: fix memory leak in efivarfs_create()
+    - staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids
+    - iio: light: fix kconfig dependency bug for VCNL4035
+    - ext4: fix bogus warning in ext4_update_dx_flag()
+    - iio: accel: kxcjk1013: Replace is_smo8500_device with an acpi_type enum
+    - iio: accel: kxcjk1013: Add support for KIOX010A ACPI DSM for setting tablet-
+      mode
+    - iio: adc: mediatek: fix unset field
+    - spi: lpspi: Fix use-after-free on unbind
+    - spi: Introduce device-managed SPI controller allocation
+    - spi: npcm-fiu: Don't leak SPI master in probe error path
+    - spi: bcm2835aux: Fix use-after-free on unbind
+    - regulator: pfuze100: limit pfuze-support-disable-sw to pfuze{100,200}
+    - regulator: fix memory leak with repeated set_machine_constraints()
+    - regulator: avoid resolve_supply() infinite recursion
+    - regulator: workaround self-referent regulators
+    - xtensa: fix TLBTEMP area placement
+    - xtensa: disable preemption around cache alias management calls
+    - mac80211: minstrel: remove deferred sampling code
+    - mac80211: minstrel: fix tx status processing corner case
+    - mac80211: free sta in sta_info_insert_finish() on errors
+    - s390/cpum_sf.c: fix file permission for cpum_sfb_size
+    - s390/dasd: fix null pointer dereference for ERP requests
+    - Drivers: hv: vmbus: Allow cleanup of VMBUS_CONNECT_CPU if disconnected
+    - drm/amd/display: Add missing pflip irq for dcn2.0
+    - drm/i915: Handle max_bpc==16
+    - mmc: sdhci-pci: Prefer SDR25 timing for High Speed mode for BYT-based Intel
+      controllers
+    - ptrace: Set PF_SUPERPRIV when checking capability
+    - seccomp: Set PF_SUPERPRIV when checking capability
+    - x86/microcode/intel: Check patch signature before saving microcode for early
+      loading
+    - mm: memcg/slab: fix root memcg vmstats
+    - mm/userfaultfd: do not access vma->vm_mm after calling handle_userfault()
+    - mm, page_alloc: skip ->waternark_boost for atomic order-0 allocations
+    - sched/fair: Fix overutilized update in enqueue_task_fair()
+    - Linux 5.4.80
+
+  * [SRU][F/G/H/U/OEM-5.6] Fix i2c report error on elan trackpoint
+    (LP: #1908335)
+    - Input: elan_i2c - add support for high resolution reports
+    - Input: elan_i2c - add new trackpoint report type 0x5F
+    - Input: elantech - fix protocol errors for some trackpoints in SMBus mode
+
+  * rtwpci driver blocks the system to enter PC10, stuck at PC3 (LP: #1907200)
+    - SAUCE: rtw88: 8723de: let cpu enter c10
+
+  * [UBUNTU 21.04] s390/pci: vfio-pci mmio being disabled erroneously
+    (LP: #1907265)
+    - s390/pci: Mark all VFs as not implementing PCI_COMMAND_MEMORY
+
+  * Touchpad not detected on ByteSpeed C15B laptop (LP: #1906128)
+    - Input: i8042 - add ByteSpeed touchpad to noloop table
+
+  * Fix reading speed and duplex sysfs on igc device (LP: #1906851)
+    - SAUCE: igc: Report speed and duplex as unknown when device is runtime
+      suspended
+
+  * stack trace in kernel (LP: #1903596)
+    - net: napi: remove useless stack trace
+
+  * Refresh ACPI wakeup power to make Thunderbolt hotplug detection work
+    (LP: #1906229)
+    - PM: ACPI: PCI: Drop acpi_pm_set_bridge_wakeup()
+    - PM: ACPI: Refresh wakeup device power configuration every time
+
+  * CVE-2020-27777
+    - [Config]: Set CONFIG_PPC_RTAS_FILTER
+
+  * Add dpcd backlight control for 0x4c83 0x4f41 (LP: #1905663)
+    - SAUCE: drm/dp: Add dpcd backlight control for 0x4c83 0x4f41
+
+  * Focal update: v5.4.79 upstream stable release (LP: #1907151)
+    - powerpc: Only include kup-radix.h for 64-bit Book3S
+    - MIPS: PCI: Fix MIPS build
+    - powerpc/8xx: Always fault when _PAGE_ACCESSED is not set
+    - net: lantiq: Add locking for TX DMA channel
+    - Input: sunkbd - avoid use-after-free in teardown paths
+    - mac80211: always wind down STA state
+    - can: proc: can_remove_proc(): silence remove_proc_entry warning
+    - KVM: x86: clflushopt should be treated as a no-op by emulation
+    - ACPI: GED: fix -Wformat
+    - Linux 5.4.79
+
+ -- Ian May <ian.may@canonical.com>  Wed, 27 Jan 2021 15:44:24 -0600
+
+linux (5.4.0-65.73) focal; urgency=medium
+
+  * focal/linux: 5.4.0-65.73 -proposed tracker (LP: #1912220)
+
+  * initramfs unpacking failed (LP: #1835660)
+    - SAUCE: lib/decompress_unlz4.c: correctly handle zero-padding around initrds.
+
+  * overlay: permission regression in 5.4.0-51.56 due to patches related to
+    CVE-2020-16120 (LP: #1900141)
+    - ovl: do not fail because of O_NOATIME
+
+  * Focal update: v5.4.79 upstream stable release (LP: #1907151)
+    - net/mlx5: Use async EQ setup cleanup helpers for multiple EQs
+    - net/mlx5: poll cmd EQ in case of command timeout
+    - net/mlx5: Fix a race when moving command interface to events mode
+    - net/mlx5: Add retry mechanism to the command entry index allocation
+
+  * Kernel 5.4.0-56 Wi-Fi does not connect (LP: #1906770)
+    - mt76: fix fix ampdu locking
+
+  * [Ubuntu 21.04 FEAT] mpt3sas: Request to include the patch set which supports
+    topology where zoning is enabled in expander (LP: #1899802)
+    - scsi: mpt3sas: Define hba_port structure
+    - scsi: mpt3sas: Allocate memory for hba_port objects
+    - scsi: mpt3sas: Rearrange _scsih_mark_responding_sas_device()
+    - scsi: mpt3sas: Update hba_port's sas_address & phy_mask
+    - scsi: mpt3sas: Get device objects using sas_address & portID
+    - scsi: mpt3sas: Rename transport_del_phy_from_an_existing_port()
+    - scsi: mpt3sas: Get sas_device objects using device's rphy
+    - scsi: mpt3sas: Update hba_port objects after host reset
+    - scsi: mpt3sas: Set valid PhysicalPort in SMPPassThrough
+    - scsi: mpt3sas: Handling HBA vSES device
+    - scsi: mpt3sas: Add bypass_dirty_port_flag parameter
+    - scsi: mpt3sas: Handle vSES vphy object during HBA reset
+    - scsi: mpt3sas: Add module parameter multipath_on_hba
+    - scsi: mpt3sas: Bump driver version to 35.101.00.00
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 18 Jan 2021 17:31:23 +0100
+
+linux (5.4.0-64.72) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 15 Jan 2021 10:50:30 +0100
+
+linux (5.4.0-62.70) focal; urgency=medium
+
+  * focal/linux: 5.4.0-62.70 -proposed tracker (LP: #1911144)
+
+  * CVE-2020-28374
+    - SAUCE: target: fix XCOPY NAA identifier lookup
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Tue, 12 Jan 2021 13:00:40 +0100
+
+linux (5.4.0-60.67) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update variants
+    - update dkms package versions
+
+  * CVE-2021-1052 // CVE-2021-1053
+    - [Packaging] NVIDIA -- Add the NVIDIA 460 driver
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 05 Jan 2021 13:51:33 -0300
+
+linux (5.4.0-59.65) focal; urgency=medium
+
+  * focal/linux: 5.4.0-59.65 -proposed tracker (LP: #1907604)
+
+  * focal: selftests/bpf build broken: test_map_init.skel.h: No such file or
+    directory (LP: #1906866)
+    - SAUCE: Revert selftests/ "bpf: Zero-fill re-used per-cpu map element"
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * memory is leaked when tasks are moved to net_prio (LP: #1886859)
+    - netprio_cgroup: Fix unlimited memory leak of v2 cgroups
+
+  * Focal update: v5.4.78 upstream stable release (LP: #1905618)
+    - drm/i915/gem: Flush coherency domains on first set-domain-ioctl
+    - time: Prevent undefined behaviour in timespec64_to_ns()
+    - nbd: don't update block size after device is started
+    - KVM: arm64: Force PTE mapping on fault resulting in a device mapping
+    - PCI: qcom: Make sure PCIe is reset before init for rev 2.1.0
+    - usb: dwc3: gadget: Continue to process pending requests
+    - usb: dwc3: gadget: Reclaim extra TRBs after request completion
+    - btrfs: tracepoints: output proper root owner for trace_find_free_extent()
+    - btrfs: sysfs: init devices outside of the chunk_mutex
+    - btrfs: reschedule when cloning lots of extents
+    - ASoC: Intel: kbl_rt5663_max98927: Fix kabylake_ssp_fixup function
+    - genirq: Let GENERIC_IRQ_IPI select IRQ_DOMAIN_HIERARCHY
+    - hv_balloon: disable warning when floor reached
+    - net: xfrm: fix a race condition during allocing spi
+    - ASoC: codecs: wcd9335: Set digital gain range correctly
+    - xfs: set xefi_discard when creating a deferred agfl free log intent item
+    - netfilter: use actual socket sk rather than skb sk when routing harder
+    - netfilter: nf_tables: missing validation from the abort path
+    - netfilter: ipset: Update byte and packet counters regardless of whether they
+      match
+    - powerpc/eeh_cache: Fix a possible debugfs deadlock
+    - perf trace: Fix segfault when trying to trace events by cgroup
+    - perf tools: Add missing swap for ino_generation
+    - ALSA: hda: prevent undefined shift in snd_hdac_ext_bus_get_link()
+    - iommu/vt-d: Fix a bug for PDP check in prq_event_thread
+    - afs: Fix warning due to unadvanced marshalling pointer
+    - can: rx-offload: don't call kfree_skb() from IRQ context
+    - 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: j1939: swap addr and pgn in the send example
+    - can: j1939: j1939_sk_bind(): return failure if netdev is down
+    - can: ti_hecc: ti_hecc_probe(): add missed clk_disable_unprepare() in error
+      path
+    - can: xilinx_can: handle failure cases of pm_runtime_get_sync
+    - can: peak_usb: add range checking in decode operations
+    - can: peak_usb: peak_usb_get_ts_time(): fix timestamp wrapping
+    - can: peak_canfd: pucan_handle_can_rx(): fix echo management when loopback is
+      on
+    - can: flexcan: remove FLEXCAN_QUIRK_DISABLE_MECR quirk for LS1021A
+    - can: flexcan: flexcan_remove(): disable wakeup completely
+    - xfs: flush new eof page on truncate to avoid post-eof corruption
+    - xfs: fix scrub flagging rtinherit even if there is no rt device
+    - tpm: efi: Don't create binary_bios_measurements file for an empty log
+    - random32: make prandom_u32() output unpredictable
+    - KVM: arm64: ARM_SMCCC_ARCH_WORKAROUND_1 doesn't return
+      SMCCC_RET_NOT_REQUIRED
+    - KVM: x86: don't expose MSR_IA32_UMWAIT_CONTROL unconditionally
+    - ath9k_htc: Use appropriate rs_datalen type
+    - ASoC: qcom: sdm845: set driver name correctly
+    - ASoC: cs42l51: manage mclk shutdown delay
+    - usb: dwc3: pci: add support for the Intel Alder Lake-S
+    - opp: Reduce the size of critical section in _opp_table_kref_release()
+    - usb: gadget: goku_udc: fix potential crashes in probe
+    - selftests/ftrace: check for do_sys_openat2 in user-memory test
+    - selftests: pidfd: fix compilation errors due to wait.h
+    - ALSA: hda: Separate runtime and system suspend
+    - ALSA: hda: Reinstate runtime_allow() for all hda controllers
+    - gfs2: Free rd_bits later in gfs2_clear_rgrpd to fix use-after-free
+    - gfs2: Add missing truncate_inode_pages_final for sd_aspace
+    - gfs2: check for live vs. read-only file system in gfs2_fitrim
+    - scsi: hpsa: Fix memory leak in hpsa_init_one()
+    - drm/amdgpu: perform srbm soft reset always on SDMA resume
+    - drm/amd/pm: perform SMC reset on suspend/hibernation
+    - drm/amd/pm: do not use ixFEATURE_STATUS for checking smc running
+    - mac80211: fix use of skb payload instead of header
+    - cfg80211: initialize wdev data earlier
+    - cfg80211: regulatory: Fix inconsistent format argument
+    - tracing: Fix the checking of stackidx in __ftrace_trace_stack
+    - scsi: scsi_dh_alua: Avoid crash during alua_bus_detach()
+    - scsi: mpt3sas: Fix timeouts observed while reenabling IRQ
+    - nvme: introduce nvme_sync_io_queues
+    - nvme-rdma: avoid race between time out and tear down
+    - nvme-tcp: avoid race between time out and tear down
+    - nvme-rdma: avoid repeated request completion
+    - nvme-tcp: avoid repeated request completion
+    - iommu/amd: Increase interrupt remapping table limit to 512 entries
+    - s390/smp: move rcu_cpu_starting() earlier
+    - vfio: platform: fix reference leak in vfio_platform_open
+    - vfio/pci: Bypass IGD init in case of -ENODEV
+    - i2c: mediatek: move dma reset before i2c reset
+    - amd/amdgpu: Disable VCN DPG mode for Picasso
+    - selftests: proc: fix warning: _GNU_SOURCE redefined
+    - riscv: Set text_offset correctly for M-Mode
+    - i2c: sh_mobile: implement atomic transfers
+    - tpm_tis: Disable interrupts on ThinkPad T490s
+    - spi: bcm2835: remove use of uninitialized gpio flags variable
+    - tick/common: Touch watchdog in tick_unfreeze() on all CPUs
+    - mfd: sprd: Add wakeup capability for PMIC IRQ
+    - pinctrl: intel: Set default bias in case no particular value given
+    - ARM: 9019/1: kprobes: Avoid fortify_panic() when copying optprobe template
+    - bpf: Don't rely on GCC __attribute__((optimize)) to disable GCSE
+    - pinctrl: aspeed: Fix GPI only function problem.
+    - net/mlx5: Fix deletion of duplicate rules
+    - SUNRPC: Fix general protection fault in trace_rpc_xdr_overflow()
+    - bpf: Zero-fill re-used per-cpu map element
+    - nbd: fix a block_device refcount leak in nbd_release
+    - igc: Fix returning wrong statistics
+    - xfs: fix flags argument to rmap lookup when converting shared file rmaps
+    - xfs: set the unwritten bit in rmap lookup flags in xchk_bmap_get_rmapextents
+    - xfs: fix rmap key and record comparison functions
+    - xfs: fix brainos in the refcount scrubber's rmap fragment processor
+    - lan743x: fix "BUG: invalid wait context" when setting rx mode
+    - 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
+    - vrf: Fix fast path output packet handling with async Netfilter rules
+    - perf: Fix get_recursion_context()
+    - erofs: derive atime instead of leaving it empty
+    - ext4: correctly report "not supported" for {usr,grp}jquota when
+      !CONFIG_QUOTA
+    - ext4: unlock xattr_sem properly in ext4_inline_data_truncate()
+    - btrfs: ref-verify: fix memory leak in btrfs_ref_tree_mod
+    - btrfs: fix min reserved size calculation in merge_reloc_root
+    - btrfs: dev-replace: fail mount if we don't have replace item with target
+      device
+    - KVM: arm64: Don't hide ID registers from userspace
+    - thunderbolt: Fix memory leak if ida_simple_get() fails in
+      enumerate_services()
+    - thunderbolt: Add the missed ida_simple_remove() in ring_request_msix()
+    - uio: Fix use-after-free in uio_unregister_device()
+    - usb: cdc-acm: Add DISABLE_ECHO for Renesas USB Download mode
+    - xhci: hisilicon: fix refercence leak in xhci_histb_probe
+    - virtio: virtio_console: fix DMA memory allocation for rproc serial
+    - mei: protect mei_cl_mtu from null dereference
+    - futex: Don't enable IRQs unconditionally in put_pi_state()
+    - jbd2: fix up sparse warnings in checkpoint code
+    - mm/slub: fix panic in slab_alloc_node()
+    - Revert "kernel/reboot.c: convert simple_strtoul to kstrtoint"
+    - reboot: fix overflow parsing reboot cpu number
+    - ocfs2: initialize ip_next_orphan
+    - btrfs: fix potential overflow in cluster_pages_for_defrag on 32bit arch
+    - selinux: Fix error return code in sel_ib_pkey_sid_slow()
+    - gpio: pcie-idio-24: Fix irq mask when masking
+    - gpio: pcie-idio-24: Fix IRQ Enable Register value
+    - gpio: pcie-idio-24: Enable PEX8311 interrupts
+    - mmc: sdhci-of-esdhc: Handle pulse width detection erratum for more SoCs
+    - mmc: renesas_sdhi_core: Add missing tmio_mmc_host_free() at remove
+    - 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: udp: fix UDP header access on Fast/frag0 UDP GRO
+    - net: Update window_clamp if SOCK_RCVBUF is set
+    - net/x25: Fix null-ptr-deref in x25_connect
+    - tipc: fix memory leak in tipc_topsrv_start()
+    - r8169: fix potential skb double free in an error path
+    - drm/i915: Correctly set SFC capability for video engines
+    - powerpc/603: Always fault when _PAGE_ACCESSED is not set
+    - x86/speculation: Allow IBPB to be conditionally enabled on CPUs with always-
+      on STIBP
+    - perf scripting python: Avoid declaring function pointers with a visibility
+      attribute
+    - net: sch_generic: fix the missing new qdisc assignment bug
+    - Convert trailing spaces and periods in path components
+    - Linux 5.4.78
+
+  * Focal update: v5.4.77 upstream stable release (LP: #1905614)
+    - Linux 5.4.77
+
+  * Focal update: v5.4.76 upstream stable release (LP: #1905612)
+    - drm/i915: Break up error capture compression loops with cond_resched()
+    - drm/i915/gt: Delay execlist processing for tgl
+    - drm/i915: Drop runtime-pm assert from vgpu io accessors
+    - ASoC: Intel: Skylake: Add alternative topology binary name
+    - update dkms package versions
+    - linkage: Introduce new macros for assembler symbols
+    - arm64: asm: Add new-style position independent function annotations
+    - arm64: lib: Use modern annotations for assembly functions
+    - arm64: Change .weak to SYM_FUNC_START_WEAK_PI for arch/arm64/lib/mem*.S
+    - tipc: fix use-after-free in tipc_bcast_get_mode
+    - ptrace: fix task_join_group_stop() for the case when current is traced
+    - cadence: force nonlinear buffers to be cloned
+    - chelsio/chtls: fix memory leaks caused by a race
+    - chelsio/chtls: fix always leaking ctrl_skb
+    - gianfar: Replace skb_realloc_headroom with skb_cow_head for PTP
+    - gianfar: Account for Tx PTP timestamp in the skb headroom
+    - ionic: check port ptr before use
+    - ip_tunnel: fix over-mtu packet send fail without TUNNEL_DONT_FRAGMENT flags
+    - net: usb: qmi_wwan: add Telit LE910Cx 0x1230 composition
+    - powerpc/vnic: Extend "failover pending" window
+    - sctp: Fix COMM_LOST/CANT_STR_ASSOC err reporting on big-endian platforms
+    - sfp: Fix error handing in sfp_probe()
+    - Fonts: Replace discarded const qualifier
+    - ALSA: hda/realtek - Fixed HP headset Mic can't be detected
+    - ALSA: hda/realtek - Enable headphone for ASUS TM420
+    - ALSA: usb-audio: Add implicit feedback quirk for Zoom UAC-2
+    - ALSA: usb-audio: add usb vendor id as DSD-capable for Khadas devices
+    - ALSA: usb-audio: Add implicit feedback quirk for Qu-16
+    - ALSA: usb-audio: Add implicit feedback quirk for MODX
+    - mm: mempolicy: fix potential pte_unmap_unlock pte error
+    - lib/crc32test: remove extra local_irq_disable/enable
+    - kthread_worker: prevent queuing delayed work from timer_fn when it is being
+      canceled
+    - mm: always have io_remap_pfn_range() set pgprot_decrypted()
+    - gfs2: Wake up when sd_glock_disposal becomes zero
+    - ring-buffer: Fix recursion protection transitions between interrupt context
+    - mtd: spi-nor: Don't copy self-pointing struct around
+    - ftrace: Fix recursion check for NMI test
+    - ftrace: Handle tracing when switching between context
+    - regulator: defer probe when trying to get voltage from unresolved supply
+    - spi: bcm2835: fix gpio cs level inversion
+    - tracing: Fix out of bounds write in get_trace_buf
+    - futex: Handle transient "ownerless" rtmutex state correctly
+    - ARM: dts: sun4i-a10: fix cpu_alert temperature
+    - arm64: dts: meson: add missing g12 rng clock
+    - x86/kexec: Use up-to-dated screen_info copy to fill boot params
+    - of: Fix reserved-memory overlap detection
+    - drm/sun4i: frontend: Rework a bit the phase data
+    - drm/sun4i: frontend: Reuse the ch0 phase for RGB formats
+    - drm/sun4i: frontend: Fix the scaler phase on A33
+    - blk-cgroup: Fix memleak on error path
+    - blk-cgroup: Pre-allocate tree node on blkg_conf_prep
+    - scsi: core: Don't start concurrent async scan on same host
+    - drm/amdgpu: add DID for navi10 blockchain SKU
+    - scsi: ibmvscsi: Fix potential race after loss of transport
+    - vsock: use ns_capable_noaudit() on socket create
+    - nvme-rdma: handle unexpected nvme completion data length
+    - nvmet: fix a NULL pointer dereference when tracing the flush command
+    - drm/vc4: drv: Add error handding for bind
+    - ACPI: NFIT: Fix comparison to '-ENXIO'
+    - usb: cdns3: gadget: suspicious implicit sign extension
+    - drm/nouveau/nouveau: fix the start/end range for migration
+    - drm/nouveau/gem: fix "refcount_t: underflow; use-after-free"
+    - arm64/smp: Move rcu_cpu_starting() earlier
+    - vt: Disable KD_FONT_OP_COPY
+    - fork: fix copy_process(CLONE_PARENT) race with the exiting ->real_parent
+    - s390/pkey: fix paes selftest failure with paes and pkey static build
+    - 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 Quectel EC200T module support
+    - USB: serial: option: add LE910Cx compositions 0x1203, 0x1230, 0x1231
+    - USB: serial: option: add Telit FN980 composition 0x1055
+    - tty: serial: fsl_lpuart: add LS1028A support
+    - tty: serial: fsl_lpuart: LS1021A has a FIFO size of 16 words, like LS1028A
+    - usb: dwc3: ep0: Fix delay status handling
+    - USB: Add NO_LPM quirk for Kingston flash drive
+    - usb: mtu3: fix panic in mtu3_gadget_stop()
+    - drm/panfrost: Fix a deadlock between the shrinker and madvise path
+    - ARC: stack unwinding: avoid indefinite looping
+    - PM: runtime: Drop runtime PM references to supplier on link removal
+    - PM: runtime: Drop pm_runtime_clean_up_links()
+    - PM: runtime: Resume the device earlier in __device_release_driver()
+    - xfs: flush for older, xfs specific ioctls
+    - perf/core: Fix a memory leak in perf_event_parse_addr_filter()
+    - arm64: dts: marvell: espressobin: Add ethernet switch aliases
+    - Linux 5.4.76
+
+  * s390: dbginfo.sh triggers kernel panic, reading from
+    /sys/kernel/mm/page_idle/bitmap (LP: #1904884)
+    - mm/page_idle.c: skip offline pages
+
+  * Ask 8821C Bluetooth controller to drop old firmware (LP: #1904221)
+    - Bluetooth: btrtl: Ask 8821C to drop old firmware
+    - Bluetooth: btrtl: fix incorrect skb allocation failure check
+
+  * Use ACPI S5 for reboot (LP: #1904225)
+    - PM: ACPI: reboot: Use S5 for reboot
+
+  * Focal update: v5.4.75 upstream stable release (LP: #1904450)
+    - 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/pvcallsback: 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
+    - firmware: arm_scmi: Fix ARCH_COLD_RESET
+    - firmware: arm_scmi: Add missing Rx size re-initialisation
+    - x86/unwind/orc: Fix inactive tasks with stack pointer in %sp on GCC 10
+      compiled kernels
+    - mlxsw: core: Fix use-after-free in mlxsw_emad_trans_finish()
+    - RDMA/qedr: Fix memory leak in iWARP CM
+    - ata: sata_nv: Fix retrieving of active qcs
+    - futex: Fix incorrect should_fail_futex() handling
+    - powerpc/powernv/smp: Fix spurious DBG() warning
+    - [Config] update config for ARCH_WANT_IRQS_OFF_ACTIVATE_MM
+    - mm: fix exec activate_mm vs TLB shootdown and lazy tlb switching race
+    - powerpc: select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
+    - sparc64: remove mm_cpumask clearing to fix kthread_use_mm race
+    - f2fs: add trace exit in exception path
+    - f2fs: fix uninit-value in f2fs_lookup
+    - f2fs: fix to check segment boundary during SIT page readahead
+    - s390/startup: avoid save_area_sync overflow
+    - um: change sigio_spinlock to a mutex
+    - f2fs: handle errors of f2fs_get_meta_page_nofail
+    - ARM: 8997/2: hw_breakpoint: Handle inexact watchpoint addresses
+    - NFS4: Fix oops when copy_file_range is attempted with NFS4.0 source
+    - power: supply: bq27xxx: report "not charging" on all types
+    - xfs: fix realtime bitmap/summary file truncation when growing rt volume
+    - video: fbdev: pvr2fb: initialize variables
+    - ath10k: start recovery process when payload length exceeds max htc length
+      for sdio
+    - ath10k: fix VHT NSS calculation when STBC is enabled
+    - drm/brige/megachips: Add checking if ge_b850v3_lvds_init() is working
+      correctly
+    - selftests/x86/fsgsbase: Reap a forgotten child
+    - media: videodev2.h: RGB BT2020 and HSV are always full range
+    - media: platform: Improve queue set up flow for bug fixing
+    - usb: typec: tcpm: During PR_SWAP, source caps should be sent only after
+      tSwapSourceStart
+    - media: tw5864: check status of tw5864_frameinterval_get
+    - media: imx274: fix frame interval handling
+    - mmc: via-sdmmc: Fix data race bug
+    - drm/bridge/synopsys: dsi: add support for non-continuous HS clock
+    - arm64: topology: Stop using MPIDR for topology information
+    - printk: reduce LOG_BUF_SHIFT range for H8300
+    - ia64: kprobes: Use generic kretprobe trampoline handler
+    - kgdb: Make "kgdbcon" work properly with "kgdb_earlycon"
+    - bpf: Permit map_ptr arithmetic with opcode add and offset 0
+    - media: uvcvideo: Fix dereference of out-of-bound list iterator
+    - selftests/bpf: Define string const as global for test_sysctl_prog.c
+    - samples/bpf: Fix possible deadlock in xdpsock
+    - riscv: Define AT_VECTOR_SIZE_ARCH for ARCH_DLINFO
+    - cpufreq: sti-cpufreq: add stih418 support
+    - USB: adutux: fix debugging
+    - uio: free uio id after uio file node is freed
+    - usb: xhci: omit duplicate actions when suspending a runtime suspended host.
+    - SUNRPC: Mitigate cond_resched() in xprt_transmit()
+    - arm64/mm: return cpu_all_mask when node is NUMA_NO_NODE
+    - can: flexcan: disable clocks during stop mode
+    - xfs: don't free rt blocks when we're doing a REMAP bunmapi call
+    - ACPI: Add out of bounds and numa_off protections to pxm_to_node()
+    - brcmfmac: Fix warning message after dongle setup failed
+    - drivers/net/wan/hdlc_fr: Correctly handle special skb->protocol values
+    - bus/fsl_mc: Do not rely on caller to provide non NULL mc_io
+    - ACPI: HMAT: Fix handling of changes from ACPI 6.2 to ACPI 6.3
+    - power: supply: test_power: add missing newlines when printing parameters by
+      sysfs
+    - drm/amd/display: HDMI remote sink need mode validation for Linux
+    - ARC: [dts] fix the errors detected by dtbs_check
+    - btrfs: fix replace of seed device
+    - md/bitmap: md_bitmap_get_counter returns wrong blocks
+    - bnxt_en: Log unknown link speed appropriately.
+    - rpmsg: glink: Use complete_all for open states
+    - 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
+    - KVM: PPC: Book3S HV: Do not allocate HPT for a nested guest
+    - gfs2: use-after-free in sysfs deregistration
+    - gfs2: add validation checks for size of superblock
+    - cifs: handle -EINTR in cifs_setattr
+    - arm64: dts: renesas: ulcb: add full-pwr-cycle-in-suspend into eMMC nodes
+    - ARM: dts: omap4: Fix sgx clock rate for 4430
+    - memory: emif: Remove bogus debugfs error handling
+    - ARM: dts: s5pv210: remove DMA controller bus node name to fix dtschema
+      warnings
+    - ARM: dts: s5pv210: move fixed clocks under root node
+    - ARM: dts: s5pv210: move PMU node out of clock controller
+    - ARM: dts: s5pv210: remove dedicated 'audio-subsystem' node
+    - nbd: make the config put is called before the notifying the waiter
+    - sgl_alloc_order: fix memory leak
+    - nvme-rdma: fix crash when connect rejected
+    - md/raid5: fix oops during stripe resizing
+    - mmc: sdhci: Add LTR support for some Intel BYT based controllers
+    - mmc: sdhci-acpi: AMDI0040: Set SDHCI_QUIRK2_PRESET_VALUE_BROKEN
+    - seccomp: Make duplicate listener detection non-racy
+    - selftests/x86/fsgsbase: Test PTRACE_PEEKUSER for GSBASE with invalid LDT GS
+    - perf/x86/intel: Fix Ice Lake event constraint table
+    - perf/x86/amd/ibs: Don't include randomized bits in get_ibs_op_count()
+    - perf/x86/amd/ibs: Fix raw sample data accumulation
+    - spi: sprd: Release DMA channel also on probe deferral
+    - extcon: ptn5150: Fix usage of atomic GPIO with sleeping GPIO chips
+    - leds: bcm6328, bcm6358: use devres LED registering function
+    - media: uvcvideo: Fix uvc_ctrl_fixup_xu_info() not having any effect
+    - fs: Don't invalidate page buffers in block_write_full_page()
+    - NFS: fix nfs_path in case of a rename retry
+    - ACPI: button: fix handling lid state changes when input device closed
+    - ACPI / extlog: Check for RDMSR failure
+    - ACPI: debug: don't allow debugging when ACPI is disabled
+    - PCI/ACPI: Whitelist hotplug ports for D3 if power managed by ACPI
+    - ACPI: EC: PM: Flush EC work unconditionally after wakeup
+    - ACPI: EC: PM: Drop ec_no_wakeup check from acpi_ec_dispatch_gpe()
+    - 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()
+    - scsi: qla2xxx: Fix crash on session cleanup with unload
+    - PM: runtime: Remove link state checks in rpm_get/put_supplier()
+    - btrfs: qgroup: fix wrong qgroup metadata reserve for delayed inode
+    - btrfs: improve device scanning messages
+    - btrfs: reschedule if necessary when logging directory items
+    - btrfs: send, orphanize first all conflicting inodes when processing
+      references
+    - btrfs: send, recompute reference path after orphanization of a directory
+    - btrfs: use kvzalloc() to allocate clone_roots in btrfs_ioctl_send()
+    - btrfs: tree-checker: fix false alert caused by legacy btrfs root item
+    - btrfs: cleanup cow block on error
+    - btrfs: tree-checker: validate number of chunk stripes and parity
+    - btrfs: fix use-after-free on readahead extent after failure to create it
+    - btrfs: fix readahead hang and use-after-free after removing a device
+    - Revert "UBUNTU: SAUCE: xhci: workaround for S3 issue on AMD SNPS 3.0 xHC"
+    - usb: xhci: Workaround for S3 issue on AMD SNPS 3.0 xHC
+    - usb: dwc3: pci: Allow Elkhart Lake to utilize DSM method for PM
+      functionality
+    - usb: dwc3: ep0: Fix ZLP for OUT ep0 requests
+    - usb: dwc3: gadget: Check MPS of the request length
+    - usb: dwc3: core: add phy cleanup for probe error handling
+    - usb: dwc3: core: don't trigger runtime pm when remove driver
+    - usb: dwc3: gadget: Resume pending requests after CLEAR_STALL
+    - usb: dwc3: gadget: END_TRANSFER before CLEAR_STALL command
+    - usb: cdc-acm: fix cooldown mechanism
+    - usb: typec: tcpm: reset hard_reset_count for any disconnect
+    - usb: host: fsl-mph-dr-of: check return of dma_set_mask()
+    - drm/i915: Force VT'd workarounds when running as a guest OS
+    - vt: keyboard, simplify vt_kdgkbsent
+    - vt: keyboard, extend func_buf_lock to readers
+    - HID: wacom: Avoid entering wacom_wac_pen_report for pad / battery
+    - udf: Fix memory leak when mounting
+    - dmaengine: dma-jz4780: Fix race in jz4780_dma_tx_status
+    - iio:light:si1145: Fix timestamp alignment and prevent data leak.
+    - iio: adc: gyroadc: fix leak of device node iterator
+    - iio:adc:ti-adc0832 Fix alignment issue with timestamp
+    - iio:adc:ti-adc12138 Fix alignment issue with timestamp
+    - iio:gyro:itg3200: Fix timestamp alignment and prevent data leak.
+    - powerpc/drmem: Make lmb_size 64 bit
+    - MIPS: DEC: Restore bootmem reservation for firmware working memory area
+    - s390/stp: add locking to sysfs functions
+    - [Config] update config for PPC_RTAS_FILTER
+    - powerpc/rtas: Restrict RTAS requests from userspace
+    - powerpc: Warn about use of smt_snooze_delay
+    - powerpc/memhotplug: Make lmb size 64bit
+    - powerpc/powernv/elog: Fix race while processing OPAL error log event.
+    - powerpc/powermac: Fix low_sleep_handler with KUAP and KUEP
+    - NFSv4: Wait for stateid updates after CLOSE/OPEN_DOWNGRADE
+    - NFSv4.2: support EXCHGID4_FLAG_SUPP_FENCE_OPS 4.2 EXCHANGE_ID flag
+    - NFSD: Add missing NFSv2 .pc_func methods
+    - ubifs: dent: Fix some potential memory leaks while iterating entries
+    - ubifs: xattr: Fix some potential memory leaks while iterating entries
+    - ubifs: journal: Make sure to not dirty twice for auth nodes
+    - ubifs: Fix a memleak after dumping authentication mount options
+    - ubifs: Don't parse authentication mount options in remount process
+    - ubifs: mount_ubifs: Release authentication resource in error handling path
+    - perf python scripting: Fix printable strings in python3 scripts
+    - ARC: perf: redo the pct irq missing in device-tree handling
+    - ubi: check kthread_should_stop() after the setting of task state
+    - ia64: fix build error with !COREDUMP
+    - rtc: rx8010: don't modify the global rtc ops
+    - i2c: imx: Fix external abort on interrupt in exit paths
+    - drm/amdgpu: don't map BO in reserved region
+    - drm/amd/display: Increase timeout for DP Disable
+    - drm/amdgpu: correct the gpu reset handling for job != NULL case
+    - drm/amdkfd: Use same SQ prefetch setting as amdgpu
+    - drm/amd/display: Avoid MST manager resource leak.
+    - drm/amdgpu: increase the reserved VM size to 2MB
+    - drm/amd/display: Don't invoke kgdb_breakpoint() unconditionally
+    - drm/amd/display: Fix kernel panic by dal_gpio_open() error
+    - 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
+    - ext4: fix leaking sysfs kobject after failed mount
+    - ext4: fix error handling code in add_new_gdb
+    - ext4: fix invalid inode checksum
+    - drm/ttm: fix eviction valuable range check.
+    - mmc: sdhci-of-esdhc: set timeout to max before tuning
+    - mmc: sdhci: Use Auto CMD Auto Select only when v4_mode is true
+    - drm/amd/pm: increase mclk switch threshold to 200 us
+    - tty: make FONTX ioctl use the tty pointer they were actually passed
+    - arm64: berlin: Select DW_APB_TIMER_OF
+    - [Config] update annotations for DW_APB_TIMER
+    - cachefiles: Handle readpage error correctly
+    - hil/parisc: Disable HIL driver when it gets stuck
+    - arm: dts: mt7623: add missing pause for switchport
+    - 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
+    - KVM: arm64: Fix AArch32 handling of DBGD{CCINT,SCRext} and DBGVCR
+    - staging: fieldbus: anybuss: jump to correct label in an error path
+    - staging: comedi: cb_pcidas: Allow 2-channel commands for AO subdevice
+    - staging: octeon: repair "fixed-link" support
+    - staging: octeon: Drop on uncorrectable alignment or FCS error
+    - Linux 5.4.75
+
+  * [HP 635] Radeon 6310 brightness control does not work (LP: #1894667) //
+    Focal update: v5.4.75 upstream stable release (LP: #1904450)
+    - ACPI: video: use ACPI backlight for HP 635 Notebook
+
+  * Focal update: v5.4.74 upstream stable release (LP: #1904445)
+    - netfilter: nftables_offload: KASAN slab-out-of-bounds Read in
+      nft_flow_rule_create
+    - socket: don't clear SOCK_TSTAMP_NEW when SO_TIMESTAMPNS is disabled
+    - objtool: Support Clang non-section symbols in ORC generation
+    - scripts/setlocalversion: make git describe output more reliable
+    - arm64: Run ARCH_WORKAROUND_1 enabling code on all CPUs
+    - arm64: Run ARCH_WORKAROUND_2 enabling code on all CPUs
+    - arm64: link with -z norelro regardless of CONFIG_RELOCATABLE
+    - x86/PCI: Fix intel_mid_pci.c build error when ACPI is not enabled
+    - bnxt_en: Check abort error state in bnxt_open_nic().
+    - bnxt_en: Send HWRM_FUNC_RESET fw command unconditionally.
+    - chelsio/chtls: fix deadlock issue
+    - chelsio/chtls: fix memory leaks in CPL handlers
+    - chelsio/chtls: fix tls record info to user
+    - cxgb4: set up filter action after rewrites
+    - gtp: fix an use-before-init in gtp_newlink()
+    - ibmvnic: fix ibmvnic_set_mac
+    - mlxsw: core: Fix memory leak on module removal
+    - netem: fix zero division in tabledist
+    - net/sched: act_mpls: Add softdep on mpls_gso.ko
+    - r8169: fix issue with forced threading in combination with shared interrupts
+    - ravb: Fix bit fields checking in ravb_hwtstamp_get()
+    - tcp: Prevent low rmem stalls with SO_RCVLOWAT.
+    - tipc: fix memory leak caused by tipc_buf_append()
+    - net: hns3: Clear the CMDQ registers before unmapping BAR region
+    - bnxt_en: Re-write PCI BARs after PCI fatal error.
+    - bnxt_en: Fix regression in workqueue cleanup logic in bnxt_remove_one().
+    - bnxt_en: Invoke cancel_delayed_work_sync() for PFs also.
+    - erofs: avoid duplicated permission check for "trusted." xattrs
+    - arch/x86/amd/ibs: Fix re-arming IBS Fetch
+    - x86/xen: disable Firmware First mode for correctable memory errors
+    - ata: ahci: mvebu: Make SATA PHY optional for Armada 3720
+    - fuse: fix page dereference after free
+    - bpf: Fix comment for helper bpf_current_task_under_cgroup()
+    - evm: Check size of security.evm before using it
+    - p54: avoid accessing the data mapped to streaming DMA
+    - cxl: Rework error message for incompatible slots
+    - RDMA/addr: Fix race with netevent_callback()/rdma_addr_cancel()
+    - mtd: lpddr: Fix bad logic in print_drs_error
+    - serial: qcom_geni_serial: To correct QUP Version detection logic
+    - serial: pl011: Fix lockdep splat when handling magic-sysrq interrupt
+    - PM: runtime: Fix timer_expires data type on 32-bit arches
+    - ata: sata_rcar: Fix DMA boundary mask
+    - xen/gntdev.c: Mark pages as dirty
+    - crypto: x86/crc32c - fix building with clang ias
+    - openrisc: Fix issue with get_user for 64-bit values
+    - misc: rtsx: do not setting OC_POWER_DOWN reg in rtsx_pci_init_ocp()
+    - phy: marvell: comphy: Convert internal SMCC firmware return codes to errno
+    - Linux 5.4.74
+
+  * Bionic: btrfs: kernel BUG at /build/linux-
+    eTBZpZ/linux-4.15.0/fs/btrfs/ctree.c:3233! (LP: #1902254)
+    - btrfs: tree-checker: fix incorrect printk format
+
+  * NULL pointer dereference when configuring multi-function with devfn != 0
+    before devfn == 0 (LP: #1903682)
+    - s390/pci: fix hot-plug of PCI function missing bus
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 10 Dec 2020 12:37:45 +0100
+
+linux (5.4.0-58.64) focal; urgency=medium
+
+  * focal/linux: 5.4.0-58.64 -proposed tracker (LP: #1907390)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * raid10: discard leads to corrupted file system (LP: #1907262)
+    - Revert "dm raid: remove unnecessary discard limits for raid10"
+    - Revert "dm raid: fix discard limits for raid1 and raid10"
+    - Revert "md/raid10: improve discard request for far layout"
+    - Revert "md/raid10: improve raid10 discard request"
+    - Revert "md/raid10: pull codes that wait for blocked dev into one function"
+    - Revert "md/raid10: extend r10bio devs to raid disks"
+    - Revert "md: add md_submit_discard_bio() for submitting discard bio"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Wed, 09 Dec 2020 02:10:30 -0500
+
+linux (5.4.0-56.62) focal; urgency=medium
+
+  * focal/linux: 5.4.0-56.62 -proposed tracker (LP: #1905300)
+
+  * CVE-2020-4788
+    - selftests/powerpc: rfi_flush: disable entry flush if present
+    - powerpc/64s: flush L1D on kernel entry
+    - powerpc/64s: flush L1D after user accesses
+    - selftests/powerpc: entry flush test
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 23 Nov 2020 15:06:56 -0300
+
+linux (5.4.0-55.61) focal; urgency=medium
+
+  * focal/linux: 5.4.0-55.61 -proposed tracker (LP: #1903175)
+
+  * 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
+
+  * raid10: Block discard is very slow, causing severe delays for mkfs and
+    fstrim operations (LP: #1896578)
+    - md: add md_submit_discard_bio() for submitting discard bio
+    - md/raid10: extend r10bio devs to raid disks
+    - md/raid10: pull codes that wait for blocked dev into one function
+    - md/raid10: improve raid10 discard request
+    - md/raid10: improve discard request for far layout
+    - dm raid: fix discard limits for raid1 and raid10
+    - dm raid: remove unnecessary discard limits for raid10
+
+  * Bionic: btrfs: kernel BUG at /build/linux-
+    eTBZpZ/linux-4.15.0/fs/btrfs/ctree.c:3233! (LP: #1902254)
+    - btrfs: drop unnecessary offset_in_page in extent buffer helpers
+    - btrfs: extent_io: do extra check for extent buffer read write functions
+    - btrfs: extent-tree: kill BUG_ON() in __btrfs_free_extent()
+    - btrfs: extent-tree: kill the BUG_ON() in insert_inline_extent_backref()
+    - btrfs: ctree: check key order before merging tree blocks
+
+  * Ethernet no link lights after reboot (Intel i225-v 2.5G) (LP: #1902578)
+    - igc: Add PHY power management control
+
+  * Undetected Data corruption in MPI workloads that use VSX for reductions on
+    POWER9 DD2.1 systems (LP: #1902694)
+    - powerpc: Fix undetected data corruption with P9N DD2.1 VSX CI load emulation
+    - selftests/powerpc: Make alignment handler test P9N DD2.1 vector CI load
+      workaround
+
+  * [20.04 FEAT] Support/enhancement of NVMe IPL (LP: #1902179)
+    - s390: nvme ipl
+    - s390: nvme reipl
+    - s390/ipl: support NVMe IPL kernel parameters
+
+  * uvcvideo: add mapping for HEVC payloads (LP: #1895803)
+    - media: uvcvideo: Add mapping for HEVC payloads
+
+  * Focal update: v5.4.73 upstream stable release (LP: #1902115)
+    - ibmveth: Switch order of ibmveth_helper calls.
+    - ibmveth: Identify ingress large send packets.
+    - ipv4: Restore flowi4_oif update before call to xfrm_lookup_route
+    - mlx4: handle non-napi callers to napi_poll
+    - net: fec: Fix phy_device lookup for phy_reset_after_clk_enable()
+    - net: fec: Fix PHY init after phy_reset_after_clk_enable()
+    - net: fix pos incrementment in ipv6_route_seq_next
+    - net/smc: fix valid DMBE buffer sizes
+    - net/tls: sendfile fails with ktls offload
+    - net: usb: qmi_wwan: add Cellient MPL200 card
+    - tipc: fix the skb_unshare() in tipc_buf_append()
+    - socket: fix option SO_TIMESTAMPING_NEW
+    - can: m_can_platform: don't call m_can_class_suspend in runtime suspend
+    - can: j1935: j1939_tp_tx_dat_new(): fix missing initialization of skbcnt
+    - net: j1939: j1939_session_fresh_new(): fix missing initialization of skbcnt
+    - net/ipv4: always honour route mtu during forwarding
+    - net_sched: remove a redundant goto chain check
+    - r8169: fix data corruption issue on RTL8402
+    - cxgb4: handle 4-tuple PEDIT to NAT mode translation
+    - binder: fix UAF when releasing todo list
+    - ALSA: bebob: potential info leak in hwdep_read()
+    - ALSA: hda/hdmi: fix incorrect locking in hdmi_pcm_close
+    - nvme-pci: disable the write zeros command for Intel 600P/P3100
+    - chelsio/chtls: fix socket lock
+    - chelsio/chtls: correct netdevice for vlan interface
+    - chelsio/chtls: correct function return and return type
+    - ibmvnic: save changed mac address to adapter->mac_addr
+    - net: ftgmac100: Fix Aspeed ast2600 TX hang issue
+    - 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
+    - net: Properly typecast int values to set sk_max_pacing_rate
+    - net/sched: act_tunnel_key: fix OOB write in case of IPv6 ERSPAN tunnels
+    - nexthop: Fix performance regression in nexthop deletion
+    - nfc: Ensure presence of NFC_ATTR_FIRMWARE_NAME attribute in
+      nfc_genl_fw_download()
+    - r8169: fix operation under forced interrupt threading
+    - selftests: forwarding: Add missing 'rp_filter' configuration
+    - tcp: fix to update snd_wl1 in bulk receiver fast path
+    - icmp: randomize the global rate limiter
+    - ALSA: hda/realtek - set mic to auto detect on a HP AIO machine
+    - ALSA: hda/realtek - Add mute Led support for HP Elitebook 845 G7
+    - ALSA: hda/realtek: Enable audio jacks of ASUS D700SA with ALC887
+    - cifs: remove bogus debug code
+    - cifs: Return the error from crypt_message when enc/dec key not found.
+    - SMB3: Resolve data corruption of TCP server info fields
+    - KVM: nVMX: Reset the segment cache when stuffing guest segs
+    - KVM: nVMX: Reload vmcs01 if getting vmcs12's pages fails
+    - KVM: x86/mmu: Commit zap of remaining invalid pages when recovering lpages
+    - KVM: SVM: Initialize prev_ga_tag before use
+    - ima: Don't ignore errors from crypto_shash_update()
+    - crypto: algif_aead - Do not set MAY_BACKLOG on the async path
+    - crypto: caam/qi - add fallback for XTS with more than 8B IV
+    - EDAC/i5100: Fix error handling order in i5100_init_one()
+    - EDAC/aspeed: Fix handling of platform_get_irq() error
+    - EDAC/ti: Fix handling of platform_get_irq() error
+    - perf/x86/intel/ds: Fix x86_pmu_stop warning for large PEBS
+    - x86/fpu: Allow multiple bits in clearcpuid= parameter
+    - drivers/perf: xgene_pmu: Fix uninitialized resource struct
+    - drivers/perf: thunderx2_pmu: Fix memory resource error handling
+    - sched/fair: Fix wrong cpu selecting from isolated domain
+    - perf/x86/intel/uncore: Update Ice Lake uncore units
+    - perf/x86/intel/uncore: Reduce the number of CBOX counters
+    - x86/nmi: Fix nmi_handle() duration miscalculation
+    - x86/events/amd/iommu: Fix sizeof mismatch
+    - crypto: algif_skcipher - EBUSY on aio should be an error
+    - crypto: mediatek - Fix wrong return value in mtk_desc_ring_alloc()
+    - crypto: ixp4xx - Fix the size used in a 'dma_free_coherent()' call
+    - crypto: picoxcell - Fix potential race condition bug
+    - media: tuner-simple: fix regression in simple_set_radio_freq
+    - media: Revert "media: exynos4-is: Add missed check for
+      pinctrl_lookup_state()"
+    - media: ov5640: Correct Bit Div register in clock tree diagram
+    - media: m5mols: Check function pointer in m5mols_sensor_power
+    - media: uvcvideo: Set media controller entity functions
+    - media: uvcvideo: Silence shift-out-of-bounds warning
+    - media: staging/intel-ipu3: css: Correctly reset some memory
+    - media: omap3isp: Fix memleak in isp_probe
+    - media: i2c: ov5640: Remain in power down for DVP mode unless streaming
+    - media: i2c: ov5640: Separate out mipi configuration from s_power
+    - media: i2c: ov5640: Enable data pins on poweron for DVP mode
+    - media: rcar_drif: Fix fwnode reference leak when parsing DT
+    - media: rcar_drif: Allocate v4l2_async_subdev dynamically
+    - media: rcar-csi2: Allocate v4l2_async_subdev dynamically
+    - crypto: omap-sham - fix digcnt register handling with export/import
+    - hwmon: (pmbus/max34440) Fix status register reads for MAX344{51,60,61}
+    - cypto: mediatek - fix leaks in mtk_desc_ring_alloc
+    - media: mx2_emmaprp: Fix memleak in emmaprp_probe
+    - media: tc358743: initialize variable
+    - media: tc358743: cleanup tc358743_cec_isr
+    - media: rcar-vin: Fix a reference count leak.
+    - media: rockchip/rga: Fix a reference count leak.
+    - media: platform: fcp: Fix a reference count leak.
+    - media: camss: Fix a reference count leak.
+    - media: s5p-mfc: Fix a reference count leak
+    - media: stm32-dcmi: Fix a reference count leak
+    - media: ti-vpe: Fix a missing check and reference count leak
+    - regulator: resolve supply after creating regulator
+    - pinctrl: bcm: fix kconfig dependency warning when !GPIOLIB
+    - spi: spi-s3c64xx: swap s3c64xx_spi_set_cs() and s3c64xx_enable_datapath()
+    - spi: spi-s3c64xx: Check return values
+    - blk-mq: move cancel of hctx->run_work to the front of blk_exit_queue
+    - ath10k: provide survey info as accumulated data
+    - drm/vkms: fix xrgb on compute crc
+    - Bluetooth: hci_uart: Cancel init work before unregistering
+    - drm/amd/display: Fix wrong return value in dm_update_plane_state()
+    - drm: panel: Fix bus format for OrtusTech COM43H4M85ULC panel
+    - ath6kl: prevent potential array overflow in ath6kl_add_new_sta()
+    - ath9k: Fix potential out of bounds in ath9k_htc_txcompletion_cb()
+    - ath10k: Fix the size used in a 'dma_free_coherent()' call in an error
+      handling path
+    - wcn36xx: Fix reported 802.11n rx_highest rate wcn3660/wcn3680
+    - ASoC: qcom: lpass-platform: fix memory leak
+    - ASoC: qcom: lpass-cpu: fix concurrency issue
+    - brcmfmac: check ndev pointer
+    - mwifiex: Do not use GFP_KERNEL in atomic context
+    - staging: rtl8192u: 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: qla2xxx: Fix wrong return value in qlt_chk_unresolv_exchg()
+    - scsi: qla2xxx: Fix wrong return value in qla_nvme_register_hba()
+    - scsi: csiostor: Fix wrong return value in csio_hw_prep_fw()
+    - backlight: sky81452-backlight: Fix refcount imbalance on error
+    - staging: emxx_udc: Fix passing of NULL to dma_alloc_coherent()
+    - VMCI: check return value of get_user_pages_fast() for errors
+    - mm/error_inject: Fix allow_error_inject function signatures.
+    - drm: panel: Fix bpc for OrtusTech COM43H4M85ULC panel
+    - drm/crc-debugfs: Fix memleak in crc_control_write
+    - binder: Remove bogus warning on failed same-process transaction
+    - tty: serial: earlycon dependency
+    - pty: do tty_flip_buffer_push without port->lock in pty_write
+    - pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()
+    - pwm: lpss: Add range limit check for the base_unit register value
+    - 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
+    - video: fbdev: radeon: Fix memleak in radeonfb_pci_register
+    - ASoC: fsl: imx-es8328: add missing put_device() call in imx_es8328_probe()
+    - HID: roccat: add bounds checking in kone_sysfs_write_settings()
+    - drm/msm: Avoid div-by-zero in dpu_crtc_atomic_check()
+    - drm/panfrost: Ensure GPU quirks are always initialised
+    - iomap: Clear page error before beginning a write
+    - pinctrl: mcp23s08: Fix mcp23x17_regmap initialiser
+    - pinctrl: mcp23s08: Fix mcp23x17 precious range
+    - net/mlx5: Don't call timecounter cyc2time directly from 1PPS flow
+    - scsi: mpt3sas: Fix sync irqs
+    - net: stmmac: use netif_tx_start|stop_all_queues() function
+    - cpufreq: armada-37xx: Add missing MODULE_DEVICE_TABLE
+    - drm: mxsfb: check framebuffer pitch
+    - coresight: etm4x: Handle unreachable sink in perf mode
+    - xhci: don't create endpoint debugfs entry before ring buffer is set.
+    - net: dsa: rtl8366: Check validity of passed VLANs
+    - net: dsa: rtl8366: Refactor VLAN/PVID init
+    - net: dsa: rtl8366: Skip PVID setting if not requested
+    - net: wilc1000: clean up resource in error path of init mon interface
+    - ASoC: tlv320aic32x4: Fix bdiv clock rate derivation
+    - net: dsa: rtl8366rb: Support all 4096 VLANs
+    - spi: omap2-mcspi: Improve performance waiting for CHSTAT
+    - ath6kl: wmi: prevent a shift wrapping bug in ath6kl_wmi_delete_pstream_cmd()
+    - dmaengine: dmatest: Check list for emptiness before access its last entry
+    - misc: mic: scif: Fix error handling path
+    - ALSA: seq: oss: Avoid mutex lock for a long-time ioctl
+    - usb: dwc2: Fix parameter type in function pointer prototype
+    - quota: clear padding in v2r1_mem2diskdqb()
+    - slimbus: core: check get_addr before removing laddr ida
+    - slimbus: core: do not enter to clock pause mode in core
+    - slimbus: qcom-ngd-ctrl: disable ngd in qmi server down callback
+    - ASoC: fsl_sai: Instantiate snd_soc_dai_driver
+    - HID: hid-input: fix stylus battery reporting
+    - nvmem: core: fix possibly memleak when use nvmem_cell_info_to_nvmem_cell()
+    - nl80211: fix OBSS PD min and max offset validation
+    - coresight: etm: perf: Fix warning caused by etm_setup_aux failure
+    - ibmvnic: set up 200GBPS speed
+    - qtnfmac: fix resource leaks on unsupported iftype error return path
+    - iio: adc: stm32-adc: fix runtime autosuspend delay when slow polling
+    - net: enic: Cure the enic api locking trainwreck
+    - mfd: sm501: Fix leaks in probe()
+    - iwlwifi: mvm: split a print to avoid a WARNING in ROC
+    - usb: gadget: f_ncm: fix ncm_bitrate for SuperSpeed and above.
+    - usb: gadget: u_ether: enable qmult on SuperSpeed Plus as well
+    - nl80211: fix non-split wiphy information
+    - usb: dwc2: Fix INTR OUT transfers in DDMA mode.
+    - scsi: target: tcmu: Fix warning: 'page' may be used uninitialized
+    - scsi: be2iscsi: Fix a theoretical leak in beiscsi_create_eqs()
+    - ipmi_si: Fix wrong return value in try_smi_init()
+    - platform/x86: mlx-platform: Remove PSU EEPROM configuration
+    - mwifiex: fix double free
+    - ipvs: clear skb->tstamp in forwarding path
+    - net: korina: fix kfree of rx/tx descriptor array
+    - netfilter: nf_log: missing vlan offload tag and proto
+    - mm/swapfile.c: fix potential memory leak in sys_swapon
+    - mm/memcg: fix device private memcg accounting
+    - mm, oom_adj: don't loop through tasks in __set_oom_adj when not necessary
+    - fs: fix NULL dereference due to data race in prepend_path()
+    - selftests/ftrace: Change synthetic event name for inter-event-combined test
+    - i3c: master add i3c_master_attach_boardinfo to preserve boardinfo
+    - IB/mlx4: Fix starvation in paravirt mux/demux
+    - 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
+    - RDMA/ucma: Fix locking for ctx->events_reported
+    - RDMA/ucma: Add missing locking around rdma_leave_multicast()
+    - mtd: lpddr: fix excessive stack usage with clang
+    - RDMA/hns: Add a check for current state before modifying QP
+    - RDMA/umem: Fix signature of stub ib_umem_find_best_pgsz()
+    - powerpc/pseries: explicitly reschedule during drmem_lmb list traversal
+    - pseries/drmem: don't cache node id in drmem_lmb struct
+    - RDMA/mlx5: Fix potential race between destroy and CQE poll
+    - mtd: mtdoops: Don't write panic data twice
+    - ARM: 9007/1: l2c: fix prefetch bits init in L2X0_AUX_CTRL using DT values
+    - arc: plat-hsdk: fix kconfig dependency warning when !RESET_CONTROLLER
+    - ida: Free allocated bitmap in error path
+    - xfs: limit entries returned when counting fsmap records
+    - xfs: fix deadlock and streamline xfs_getfsmap performance
+    - xfs: fix high key handling in the rt allocator's query_range function
+    - RDMA/umem: Fix ib_umem_find_best_pgsz() for mappings that cross a page
+      boundary
+    - RDMA/umem: Prevent small pages from being returned by
+      ib_umem_find_best_pgsz()
+    - RDMA/qedr: Fix qp structure memory leak
+    - RDMA/qedr: Fix use of uninitialized field
+    - RDMA/qedr: Fix return code if accept is called on a destroyed qp
+    - RDMA/qedr: Fix inline size returned for iWARP
+    - powerpc/book3s64/hash/4k: Support large linear mapping range with 4K
+    - powerpc/tau: Use appropriate temperature sample interval
+    - powerpc/tau: Convert from timer to workqueue
+    - powerpc/tau: Remove duplicated set_thresholds() call
+    - powerpc/tau: Check processor type before enabling TAU interrupt
+    - powerpc/tau: Disable TAU between measurements
+    - powerpc/64s/radix: Fix mm_cpumask trimming race vs kthread_use_mm
+    - RDMA/cma: Remove dead code for kernel rdmacm multicast
+    - RDMA/cma: Consolidate the destruction of a cma_multicast in one place
+    - perf intel-pt: Fix "context_switch event has no tid" error
+    - RDMA/hns: Set the unsupported wr opcode
+    - RDMA/mlx5: Disable IB_DEVICE_MEM_MGT_EXTENSIONS if IB_WR_REG_MR can't work
+    - i40iw: Add support to make destroy QP synchronous
+    - perf stat: Skip duration_time in setup_system_wide
+    - RDMA/hns: Fix the wrong value of rnr_retry when querying qp
+    - RDMA/hns: Fix missing sq_sig_type when querying QP
+    - mtd: rawnand: vf610: disable clk on error handling path in probe
+    - mtd: spinand: gigadevice: Only one dummy byte in QUADIO
+    - mtd: spinand: gigadevice: Add QE Bit
+    - kdb: Fix pager search for multi-line strings
+    - overflow: Include header file with SIZE_MAX declaration
+    - RDMA/ipoib: Set rtnl_link_ops for ipoib interfaces
+    - powerpc/perf: Exclude pmc5/6 from the irrelevant PMU group constraints
+    - powerpc/perf/hv-gpci: Fix starting index value
+    - i3c: master: Fix error return in cdns_i3c_master_probe()
+    - cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier
+    - IB/rdmavt: Fix sizeof mismatch
+    - RDMA/rxe: Fix skb lifetime in rxe_rcv_mcast_pkt()
+    - maiblox: mediatek: Fix handling of platform_get_irq() error
+    - selftests/powerpc: Fix eeh-basic.sh exit codes
+    - f2fs: wait for sysfs kobject removal before freeing f2fs_sb_info
+    - RDMA/rxe: Handle skb_clone() failure in rxe_recv.c
+    - mm/page_owner: change split_page_owner to take a count
+    - lib/crc32.c: fix trivial typo in preprocessor condition
+    - ramfs: fix nommu mmap with gaps in the page cache
+    - rapidio: fix error handling path
+    - rapidio: fix the missed put_device() for rio_mport_add_riodev
+    - mailbox: avoid timer start from callback
+    - i2c: rcar: Auto select RESET_CONTROLLER
+    - clk: meson: g12a: mark fclk_div2 as critical
+    - PCI: aardvark: Check for errors from pci_bridge_emul_init() call
+    - PCI: iproc: Set affinity mask on MSI interrupts
+    - rpmsg: smd: Fix a kobj leak in in qcom_smd_parse_edge()
+    - PCI/IOV: Mark VFs as not implementing PCI_COMMAND_MEMORY
+    - vfio/pci: Decouple PCI_COMMAND_MEMORY bit checks from is_virtfn
+    - clk: qcom: gcc-sdm660: Fix wrong parent_map
+    - clk: keystone: sci-clk: fix parsing assigned-clock data during probe
+    - pwm: img: Fix null pointer access in probe
+    - clk: rockchip: Initialize hw to error to avoid undefined behavior
+    - clk: mediatek: add UART0 clock support
+    - module: statically initialize init section freeing data
+    - clk: at91: clk-main: update key before writing AT91_CKGR_MOR
+    - clk: bcm2835: add missing release if devm_clk_hw_register fails
+    - watchdog: Fix memleak in watchdog_cdev_register
+    - watchdog: Use put_device on error
+    - watchdog: sp5100: Fix definition of EFCH_PM_DECODEEN3
+    - svcrdma: fix bounce buffers for unaligned offsets and multiple pages
+    - ext4: limit entries returned when counting fsmap records
+    - vfio/pci: Clear token on bypass registration failure
+    - vfio iommu type1: Fix memory leak in vfio_iommu_type1_pin_pages
+    - clk: imx8mq: Fix usdhc parents order
+    - SUNRPC: fix copying of multiple pages in gss_read_proxy_verf()
+    - Input: imx6ul_tsc - clean up some errors in imx6ul_tsc_resume()
+    - Input: stmfts - fix a & vs && typo
+    - Input: ep93xx_keypad - fix handling of platform_get_irq() error
+    - Input: omap4-keypad - fix handling of platform_get_irq() error
+    - Input: twl4030_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
+    - scsi: bfa: Fix error return in bfad_pci_init()
+    - netfilter: conntrack: connection timeout after re-register
+    - netfilter: ebtables: Fixes dropping of small packets in bridge nat
+    - netfilter: nf_fwd_netdev: clear timestamp in forwarding path
+    - arm64: dts: meson: vim3: correct led polarity
+    - ARM: dts: imx6sl: fix rng node
+    - ARM: at91: pm: of_node_put() after its usage
+    - ARM: s3c24xx: fix mmc gpio lookup tables
+    - ARM: dts: sun8i: r40: bananapi-m2-ultra: Fix dcdc1 regulator
+    - arm64: dts: allwinner: h5: remove Mali GPU PMU module
+    - memory: omap-gpmc: Fix a couple off by ones
+    - memory: omap-gpmc: Fix build error without CONFIG_OF
+    - memory: fsl-corenet-cf: Fix handling of platform_get_irq() error
+    - arm64: dts: imx8mq: Add missing interrupts to GPC
+    - arm64: dts: qcom: msm8916: Remove one more thermal trip point unit name
+    - arm64: dts: qcom: pm8916: Remove invalid reg size from wcd_codec
+    - arm64: dts: qcom: msm8916: Fix MDP/DSI interrupts
+    - arm64: dts: renesas: r8a77990: Fix MSIOF1 DMA channels
+    - arm64: dts: renesas: r8a774c0: Fix MSIOF1 DMA channels
+    - arm64: dts: actions: limit address range for pinctrl node
+    - ARM: dts: owl-s500: Fix incorrect PPI interrupt specifiers
+    - soc: fsl: qbman: Fix return value on success
+    - ARM: OMAP2+: Restore MPU power domain if cpu_cluster_pm_enter() fails
+    - arm64: dts: zynqmp: Remove additional compatible string for i2c IPs
+    - ARM: dts: meson8: remove two invalid interrupt lines from the GPU node
+    - lightnvm: fix out-of-bounds write to array devices->info[]
+    - powerpc/powernv/dump: Fix race while processing OPAL dump
+    - powerpc/pseries: Avoid using addr_to_pfn in real mode
+    - nvmet: fix uninitialized work for zero kato
+    - NTB: hw: amd: fix an issue about leak system resources
+    - sched/features: Fix !CONFIG_JUMP_LABEL case
+    - perf: correct SNOOPX field offset
+    - i2c: core: Restore acpi_walk_dep_device_list() getting called after
+      registering the ACPI i2c devs
+    - md/bitmap: fix memory leak of temporary bitmap
+    - block: ratelimit handle_bad_sector() message
+    - crypto: ccp - fix error handling
+    - x86/asm: Replace __force_order with a memory clobber
+    - x86/mce: Add Skylake quirk for patrol scrub reported errors
+    - media: firewire: fix memory leak
+    - media: ati_remote: sanity check for both endpoints
+    - media: st-delta: Fix reference count leak in delta_run_work
+    - media: sti: Fix reference count leaks
+    - 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: vsp1: Fix runtime PM imbalance on error
+    - media: platform: s3c-camif: Fix runtime PM imbalance on error
+    - media: platform: sti: hva: Fix runtime PM imbalance on error
+    - media: bdisp: Fix runtime PM imbalance on error
+    - media: media/pci: prevent memory leak in bttv_probe
+    - x86/mce: Make mce_rdmsrl() panic on an inaccessible MSR
+    - 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
+    - media: venus: fixes for list corruption
+    - fs: dlm: fix configfs memory leak
+    - media: venus: core: Fix runtime PM imbalance in venus_probe
+    - ntfs: add check for mft record size in superblock
+    - ip_gre: set dev->hard_header_len and dev->needed_headroom properly
+    - mac80211: handle lack of sband->bitrates in rates
+    - 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
+    - mic: vop: copy data to kernel space then write to io memory
+    - misc: vop: add round_up(x,4) for vring_size to avoid kernel panic
+    - usb: dwc3: Add splitdisable quirk for Hisilicon Kirin Soc
+    - 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
+    - rtw88: increse the size of rx buffer size
+    - USB: cdc-acm: handle broken union descriptors
+    - usb: dwc3: simple: add support for Hikey 970
+    - can: flexcan: flexcan_chip_stop(): add error handling and propagate error
+      value
+    - ath9k: hif_usb: fix race condition between usb_get_urb() and
+      usb_kill_anchored_urbs()
+    - drm/panfrost: add amlogic reset quirk callback
+    - bpf: Limit caller's stack depth 256 for subprogs with tailcalls
+    - misc: rtsx: Fix memory leak in rtsx_pci_probe
+    - reiserfs: only call unlock_new_inode() if I_NEW
+    - opp: Prevent memory leak in dev_pm_opp_attach_genpd()
+    - 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
+    - drm/msm/a6xx: fix a potential overflow issue
+    - iomap: fix WARN_ON_ONCE() from unprivileged users
+    - scsi: ibmvfc: Fix error return in ibmvfc_probe()
+    - scsi: qla2xxx: Warn if done() or free() are called on an already freed srb
+    - selftests/bpf: Fix test_sysctl_loop{1, 2} failure due to clang change
+    - brcmsmac: fix memory leak in wlc_phy_attach_lcnphy
+    - rtl8xxxu: prevent potential memory leak
+    - Fix use after free in get_capset_info callback.
+    - HID: ite: Add USB id match for Acer One S1003 keyboard dock
+    - scsi: qedf: Return SUCCESS if stale rport is encountered
+    - scsi: qedi: Protect active command list to avoid list corruption
+    - scsi: qedi: Fix list_del corruption while removing active I/O
+    - fbmem: add margin check to fb_check_caps()
+    - tty: ipwireless: fix error handling
+    - Bluetooth: btusb: Fix memleak in btusb_mtk_submit_wmt_recv_urb
+    - ipvs: Fix uninit-value in do_ip_vs_set_ctl()
+    - reiserfs: Fix memory leak in reiserfs_parse_options()
+    - mwifiex: don't call del_timer_sync() on uninitialized timer
+    - ALSA: hda/ca0132 - Add AE-7 microphone selection commands.
+    - ALSA: hda/ca0132 - Add new quirk ID for SoundBlaster AE-7.
+    - scsi: smartpqi: Avoid crashing kernel for controller issues
+    - brcm80211: fix possible memleak in brcmf_proto_msgbuf_attach
+    - usb: core: Solve race condition in anchor cleanup functions
+    - scsi: ufs: ufs-qcom: Fix race conditions caused by ufs_qcom_testbus_config()
+    - dmaengine: dw: Add DMA-channels mask cell support
+    - dmaengine: dw: Activate FIFO-mode for memory peripherals only
+    - ath10k: check idx validity in __ath10k_htt_rx_ring_fill_n()
+    - net: korina: cast KSEG0 address to pointer in kfree
+    - s390/qeth: don't let HW override the configured port role
+    - tty: serial: lpuart: fix lpuart32_write usage
+    - tty: serial: fsl_lpuart: fix lpuart32_poll_get_char
+    - usb: cdc-acm: add quirk to blacklist ETAS ES58X devices
+    - USB: cdc-wdm: Make wdm_flush() interruptible and add wdm_fsync().
+    - usb: cdns3: gadget: free interrupt after gadget has deleted
+    - eeprom: at25: set minimum read/write access stride to 1
+    - usb: gadget: f_ncm: allow using NCM in SuperSpeed Plus gadgets.
+    - Linux 5.4.73
+
+  * Focal update: v5.4.72 upstream stable release (LP: #1902111)
+    - perf cs-etm: Move definition of 'traceid_list' global variable from header
+      file
+    - btrfs: don't pass system_chunk into can_overcommit
+    - btrfs: take overcommit into account in inc_block_group_ro
+    - ARM: 8939/1: kbuild: use correct nm executable
+    - ACPI: Always build evged in
+    - 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
+    - xen/events: don't use chip_data for legacy IRQs
+    - crypto: bcm - Verify GCM/CCM key length in setkey
+    - crypto: qat - check cipher length for aead AES-CBC-HMAC-SHA
+    - Linux 5.4.72
+
+  * Focal update: v5.4.71 upstream stable release (LP: #1902110)
+    - fbdev, newport_con: Move FONT_EXTRA_WORDS macros into linux/font.h
+    - Fonts: Support FONT_EXTRA_WORDS macros for built-in fonts
+    - fbcon: Fix global-out-of-bounds read in fbcon_get_font()
+    - Revert "ravb: Fixed to be able to unload modules"
+    - io_uring: Fix resource leaking when kill the process
+    - io_uring: Fix missing smp_mb() in io_cancel_async_work()
+    - io_uring: Fix remove irrelevant req from the task_list
+    - io_uring: Fix double list add in io_queue_async_work()
+    - net: wireless: nl80211: fix out-of-bounds access in nl80211_del_key()
+    - drm/nouveau/mem: guard against NULL pointer access in mem_del
+    - vhost: Don't call access_ok() when using IOTLB
+    - vhost: Use vhost_get_used_size() in vhost_vring_set_addr()
+    - usermodehelper: reset umask to default before executing user process
+    - Platform: OLPC: Fix memleak in olpc_ec_probe
+    - platform/x86: intel-vbtn: Fix SW_TABLET_MODE always reporting 1 on the HP
+      Pavilion 11 x360
+    - platform/x86: thinkpad_acpi: initialize tp_nvram_state variable
+    - bpf: Fix sysfs export of empty BTF section
+    - bpf: Prevent .BTF section elimination
+    - platform/x86: intel-vbtn: Switch to an allow-list for SW_TABLET_MODE
+      reporting
+    - platform/x86: thinkpad_acpi: re-initialize ACPI buffer size when reuse
+    - driver core: Fix probe_count imbalance in really_probe()
+    - perf test session topology: Fix data path
+    - perf top: Fix stdio interface input handling with glibc 2.28+
+    - i2c: i801: Exclude device from suspend direct complete optimization
+    - arm64: dts: stratix10: add status to qspi dts node
+    - Btrfs: send, allow clone operations within the same file
+    - Btrfs: send, fix emission of invalid clone operations within the same file
+    - btrfs: volumes: Use more straightforward way to calculate map length
+    - btrfs: Ensure we trim ranges across block group boundary
+    - btrfs: fix RWF_NOWAIT write not failling when we need to cow
+    - btrfs: allow btrfs_truncate_block() to fallback to nocow for data space
+      reservation
+    - nvme-core: put ctrl ref when module ref get fail
+    - macsec: avoid use-after-free in macsec_handle_frame()
+    - mm/khugepaged: fix filemap page_to_pgoff(page) != offset
+    - net: introduce helper sendpage_ok() in include/linux/net.h
+    - tcp: use sendpage_ok() to detect misused .sendpage
+    - nvme-tcp: check page by sendpage_ok() before calling kernel_sendpage()
+    - xfrmi: drop ignore_df check before updating pmtu
+    - cifs: Fix incomplete memory allocation on setxattr path
+    - i2c: meson: fix clock setting overwrite
+    - i2c: meson: fixup rate calculation with filter delay
+    - i2c: owl: Clear NACK and BUS error bits
+    - 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
+    - openvswitch: handle DNAT tuple collision
+    - drm/amdgpu: prevent double kfree ttm->sg
+    - iommu/vt-d: Fix lockdep splat in iommu_flush_dev_iotlb()
+    - xfrm: clone XFRMA_SET_MARK in xfrm_do_migrate
+    - xfrm: clone XFRMA_REPLAY_ESN_VAL in xfrm_do_migrate
+    - xfrm: clone XFRMA_SEC_CTX in xfrm_do_migrate
+    - xfrm: clone whole liftime_cur structure in xfrm_do_migrate
+    - net: stmmac: removed enabling eee in EEE set callback
+    - platform/x86: fix kconfig dependency warning for FUJITSU_LAPTOP
+    - xfrm: Use correct address family in xfrm_state_find
+    - iavf: use generic power management
+    - iavf: Fix incorrect adapter get in iavf_resume
+    - net: ethernet: cavium: octeon_mgmt: use phy_start and phy_stop
+    - bonding: set dev->needed_headroom in bond_setup_by_slave()
+    - mdio: fix mdio-thunder.c dependency & build error
+    - mlxsw: spectrum_acl: Fix mlxsw_sp_acl_tcam_group_add()'s error path
+    - r8169: fix RTL8168f/RTL8411 EPHY config
+    - net: usb: ax88179_178a: fix missing stop entry in driver_info
+    - virtio-net: don't disable guest csum when disable LRO
+    - net/mlx5: Avoid possible free of command entry while timeout comp handler
+    - net/mlx5: Fix request_irqs error flow
+    - net/mlx5e: Add resiliency in Striding RQ mode for packets larger than MTU
+    - net/mlx5e: Fix VLAN cleanup flow
+    - net/mlx5e: Fix VLAN create flow
+    - rxrpc: Fix rxkad token xdr encoding
+    - rxrpc: Downgrade the BUG() for unsupported token type in rxrpc_read()
+    - rxrpc: Fix some missing _bh annotations on locking conn->state_lock
+    - rxrpc: The server keyring isn't network-namespaced
+    - rxrpc: Fix server keyring leak
+    - perf: Fix task_function_call() error handling
+    - mmc: core: don't set limits.discard_granularity as 0
+    - mm: khugepaged: recalculate min_free_kbytes after memory hotplug as expected
+      by khugepaged
+    - tcp: fix receive window update in tcp_add_backlog()
+    - net/core: check length before updating Ethertype in skb_mpls_{push,pop}
+    - net/tls: race causes kernel panic
+    - net/mlx5e: Fix driver's declaration to support GRE offload
+    - Input: ati_remote2 - add missing newlines when printing module parameters
+    - net: usb: rtl8150: set random MAC address when set_ethernet_addr() fails
+    - net_sched: defer tcf_idr_insert() in tcf_action_init_1()
+    - net_sched: commit action insertions together
+    - Linux 5.4.71
+
+  * kci_test_encap_fou() in rtnetlink.sh from kselftests/net failed with "FAIL:
+    can't add fou port 7777, skipping test" (LP: #1891421)
+    - selftests: rtnetlink: load fou module for kci_test_encap_fou() test
+
+  * alsa/hda/realtek - The front Mic on a HP machine doesn't work (LP: #1899508)
+    - ALSA: hda/realtek - The front Mic on a HP machine doesn't work
+
+  * Enable brightness control on HP DreamColor panel (LP: #1898865)
+    - drm/i915/dpcd_bl: Unbreak enable_dpcd_backlight modparam
+    - SAUCE: drm/i915/dpcd_bl: Skip testing control capability with force DPCD
+      quirk
+    - SAUCE: drm/dp: HP DreamColor panel brigntness fix
+
+  * Fix non-working Intel NVMe after S3 (LP: #1900847)
+    - SAUCE: PCI: Enable ACS quirk on all CML root ports
+
+  * bcache: Issues with large IO wait in bch_mca_scan() when shrinker is enabled
+    (LP: #1898786)
+    - bcache: remove member accessed from struct btree
+    - bcache: reap c->btree_cache_freeable from the tail in bch_mca_scan()
+    - bcache: reap from tail of c->btree_cache in bch_mca_scan()
+
+  * Improve descriptions for XFAIL cases in kselftests/net/psock_snd
+    (LP: #1900088)
+    - selftests/net: improve descriptions for XFAIL cases in psock_snd.sh
+
+  * ceph: fix inode number handling on arches with 32-bit ino_t (LP: #1899582)
+    - ceph: fix inode number handling on arches with 32-bit ino_t
+
+  * Fix system reboot when disconnecting WiFi (LP: #1899726)
+    - iwlwifi: msix: limit max RX queues for 9000 family
+
+  * Fix broken MSI interrupt after HDA controller was suspended (LP: #1899586)
+    - ALSA: hda: fix jack detection with Realtek codecs when in D3
+
+  * Focal update: v5.4.70 upstream stable release (LP: #1900632)
+    - btrfs: fix filesystem corruption after a device replace
+    - mmc: sdhci: Workaround broken command queuing on Intel GLK based IRBIS
+      models
+    - USB: gadget: f_ncm: Fix NDP16 datagram validation
+    - gpio: siox: explicitly support only threaded irqs
+    - gpio: mockup: fix resource leak in error path
+    - gpio: tc35894: fix up tc35894 interrupt configuration
+    - clk: socfpga: stratix10: fix the divider for the emac_ptp_free_clk
+    - vsock/virtio: add transport parameter to the
+      virtio_transport_reset_no_sock()
+    - net: virtio_vsock: Enhance connection semantics
+    - xfs: trim IO to found COW extent limit
+    - Input: i8042 - add nopnp quirk for Acer Aspire 5 A515
+    - iio: adc: qcom-spmi-adc5: fix driver name
+    - ftrace: Move RCU is watching check after recursion check
+    - memstick: Skip allocating card when removing host
+    - drm/amdgpu: restore proper ref count in amdgpu_display_crtc_set_config
+    - clocksource/drivers/timer-gx6605s: Fixup counter reload
+    - libbpf: Remove arch-specific include path in Makefile
+    - drivers/net/wan/hdlc_fr: Add needed_headroom for PVC devices
+    - drm/sun4i: mixer: Extend regmap max_register
+    - net: dec: de2104x: Increase receive ring size for Tulip
+    - rndis_host: increase sleep time in the query-response loop
+    - nvme-core: get/put ctrl and transport module in nvme_dev_open/release()
+    - fuse: fix the ->direct_IO() treatment of iov_iter
+    - drivers/net/wan/lapbether: Make skb->protocol consistent with the header
+    - drivers/net/wan/hdlc: Set skb->protocol before transmitting
+    - mac80211: Fix radiotap header channel flag for 6GHz band
+    - mac80211: do not allow bigger VHT MPDUs than the hardware supports
+    - tracing: Make the space reserved for the pid wider
+    - tools/io_uring: fix compile breakage
+    - spi: fsl-espi: Only process interrupts for expected events
+    - nvme-pci: fix NULL req in completion handler
+    - nvme-fc: fail new connections to a deleted host or remote port
+    - gpio: sprd: Clear interrupt when setting the type as edge
+    - phy: ti: am654: Fix a leak in serdes_am654_probe()
+    - pinctrl: mvebu: Fix i2c sda definition for 98DX3236
+    - nfs: Fix security label length not being reset
+    - clk: tegra: Always program PLL_E when enabled
+    - clk: samsung: exynos4: mark 'chipid' clock as CLK_IGNORE_UNUSED
+    - iommu/exynos: add missing put_device() call in exynos_iommu_of_xlate()
+    - gpio/aspeed-sgpio: enable access to all 80 input & output sgpios
+    - gpio/aspeed-sgpio: don't enable all interrupts by default
+    - gpio: aspeed: fix ast2600 bank properties
+    - i2c: cpm: Fix i2c_ram structure
+    - Input: trackpoint - enable Synaptics trackpoints
+    - scripts/dtc: only append to HOST_EXTRACFLAGS instead of overwriting
+    - random32: Restore __latent_entropy attribute on net_rand_state
+    - block/diskstats: more accurate approximation of io_ticks for slow disks
+    - mm: replace memmap_context by meminit_context
+    - mm: don't rely on system state to detect hot-plug operations
+    - nvme: Cleanup and rename nvme_block_nr()
+    - nvme: Introduce nvme_lba_to_sect()
+    - nvme: consolidate chunk_sectors settings
+    - 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
+    - Linux 5.4.70
+
+  * Focal update: v5.4.69 upstream stable release (LP: #1900624)
+    - kernel/sysctl-test: Add null pointer test for sysctl.c:proc_dointvec()
+    - selinux: allow labeling before policy is loaded
+    - media: mc-device.c: fix memleak in media_device_register_entity
+    - drm/amd/display: Do not double-buffer DTO adjustments
+    - drm/amdkfd: Fix race in gfx10 context restore handler
+    - dma-fence: Serialise signal enabling (dma_fence_enable_sw_signaling)
+    - scsi: qla2xxx: Add error handling for PLOGI ELS passthrough
+    - ath10k: fix array out-of-bounds access
+    - ath10k: fix memory leak for tpc_stats_final
+    - PCI/IOV: Serialize sysfs sriov_numvfs reads vs writes
+    - mm: fix double page fault on arm64 if PTE_AF is cleared
+    - scsi: aacraid: fix illegal IO beyond last LBA
+    - m68k: q40: Fix info-leak in rtc_ioctl
+    - xfs: fix inode fork extent count overflow
+    - gma/gma500: fix a memory disclosure bug due to uninitialized bytes
+    - ASoC: kirkwood: fix IRQ error handling
+    - soundwire: intel/cadence: fix startup sequence
+    - media: smiapp: Fix error handling at NVM reading
+    - drm/amd/display: Free gamma after calculating legacy transfer function
+    - xfs: properly serialise fallocate against AIO+DIO
+    - leds: mlxreg: Fix possible buffer overflow
+    - dm table: do not allow request-based DM to stack on partitions
+    - PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out
+    - scsi: fnic: fix use after free
+    - powerpc/64s: Always disable branch profiling for prom_init.o
+    - net: silence data-races on sk_backlog.tail
+    - dax: Fix alloc_dax_region() compile warning
+    - iomap: Fix overflow in iomap_page_mkwrite
+    - f2fs: avoid kernel panic on corruption test
+    - clk/ti/adpll: allocate room for terminating null
+    - drm/amdgpu/powerplay: fix AVFS handling with custom powerplay table
+    - ice: Fix to change Rx/Tx ring descriptor size via ethtool with DCBx
+    - 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
+    - drm/amdgpu/powerplay/smu7: fix AVFS handling with custom powerplay table
+    - tpm_crb: fix fTPM on AMD Zen+ CPUs
+    - tracing: Verify if trace array exists before destroying it.
+    - tracing: Adding NULL checks for trace_array descriptor pointer
+    - bcache: fix a lost wake-up problem caused by mca_cannibalize_lock
+    - dmaengine: mediatek: hsdma_probe: fixed a memory leak when devm_request_irq
+      fails
+    - x86/kdump: Always reserve the low 1M when the crashkernel option is
+      specified
+    - RDMA/qedr: Fix potential use after free
+    - RDMA/i40iw: Fix potential use after free
+    - PCI: Avoid double hpmemsize MMIO window assignment
+    - fix dget_parent() fastpath race
+    - xfs: fix attr leaf header freemap.size underflow
+    - RDMA/iw_cgxb4: Fix an error handling path in 'c4iw_connect()'
+    - ubi: Fix producing anchor PEBs
+    - mmc: core: Fix size overflow for mmc partitions
+    - gfs2: clean up iopen glock mess in gfs2_create_inode
+    - scsi: pm80xx: Cleanup command when a reset times out
+    - mt76: do not use devm API for led classdev
+    - mt76: add missing locking around ampdu action
+    - debugfs: Fix !DEBUG_FS debugfs_create_automount
+    - SUNRPC: Capture completion of all RPC tasks
+    - CIFS: Use common error handling code in smb2_ioctl_query_info()
+    - CIFS: Properly process SMB3 lease breaks
+    - f2fs: stop GC when the victim becomes fully valid
+    - ASoC: max98090: remove msleep in PLL unlocked workaround
+    - xtensa: fix system_call interaction with ptrace
+    - s390: avoid misusing CALL_ON_STACK for task stack setup
+    - xfs: fix realtime file data space leak
+    - drm/amdgpu: fix calltrace during kmd unload(v3)
+    - arm64: insn: consistently handle exit text
+    - selftests/bpf: De-flake test_tcpbpf
+    - kernel/notifier.c: intercept duplicate registrations to avoid infinite loops
+    - kernel/sys.c: avoid copying possible padding bytes in copy_to_user
+    - KVM: arm/arm64: vgic: Fix potential double free dist->spis in
+      __kvm_vgic_destroy()
+    - module: Remove accidental change of module_enable_x()
+    - xfs: fix log reservation overflows when allocating large rt extents
+    - ALSA: hda: enable regmap internal locking
+    - tipc: fix link overflow issue at socket shutdown
+    - vcc_seq_next should increase position index
+    - neigh_stat_seq_next() should increase position index
+    - rt_cpu_seq_next should increase position index
+    - ipv6_route_seq_next should increase position index
+    - drm/mcde: Handle pending vblank while disabling display
+    - seqlock: Require WRITE_ONCE surrounding raw_seqcount_barrier
+    - drm/scheduler: Avoid accessing freed bad job.
+    - media: ti-vpe: cal: Restrict DMA to avoid memory corruption
+    - opp: Replace list_kref with a local counter
+    - scsi: qla2xxx: Fix stuck session in GNL
+    - sctp: move trace_sctp_probe_path into sctp_outq_sack
+    - ACPI: EC: Reference count query handlers under lock
+    - scsi: ufs: Make ufshcd_add_command_trace() easier to read
+    - scsi: ufs: Fix a race condition in the tracing code
+    - drm/amd/display: Initialize DSC PPS variables to 0
+    - i2c: tegra: Prevent interrupt triggering after transfer timeout
+    - btrfs: tree-checker: Check leaf chunk item size
+    - dmaengine: zynqmp_dma: fix burst length configuration
+    - s390/cpum_sf: Use kzalloc and minor changes
+    - nfsd: Fix a soft lockup race in nfsd_file_mark_find_or_create()
+    - powerpc/eeh: Only dump stack once if an MMIO loop is detected
+    - Bluetooth: btrtl: Use kvmalloc for FW allocations
+    - tracing: Set kernel_stack's caller size properly
+    - ARM: 8948/1: Prevent OOB access in stacktrace
+    - ar5523: Add USB ID of SMCWUSBT-G2 wireless adapter
+    - ceph: ensure we have a new cap before continuing in fill_inode
+    - selftests/ftrace: fix glob selftest
+    - tools/power/x86/intel_pstate_tracer: changes for python 3 compatibility
+    - Bluetooth: Fix refcount use-after-free issue
+    - mm/swapfile.c: swap_next should increase position index
+    - mm: pagewalk: fix termination condition in walk_pte_range()
+    - Bluetooth: prefetch channel before killing sock
+    - ALSA: hda: Clear RIRB status before reading WP
+    - skbuff: fix a data race in skb_queue_len()
+    - nfsd: Fix a perf warning
+    - drm/amd/display: fix workaround for incorrect double buffer register for DLG
+      ADL and TTU
+    - audit: CONFIG_CHANGE don't log internal bookkeeping as an event
+    - selinux: sel_avc_get_stat_idx should increase position index
+    - drm/omap: fix possible object reference leak
+    - locking/lockdep: Decrement IRQ context counters when removing lock chain
+    - clk: stratix10: use do_div() for 64-bit calculation
+    - crypto: chelsio - This fixes the kernel panic which occurs during a libkcapi
+      test
+    - mt76: clear skb pointers from rx aggregation reorder buffer during cleanup
+    - mt76: fix handling full tx queues in mt76_dma_tx_queue_skb_raw
+    - ALSA: usb-audio: Don't create a mixer element with bogus volume range
+    - perf test: Fix test trace+probe_vfs_getname.sh on s390
+    - RDMA/rxe: Fix configuration of atomic queue pair attributes
+    - KVM: x86: fix incorrect comparison in trace event
+    - KVM: nVMX: Hold KVM's srcu lock when syncing vmcs12->shadow
+    - dmaengine: stm32-mdma: use vchan_terminate_vdesc() in .terminate_all
+    - media: staging/imx: Missing assignment in
+      imx_media_capture_device_register()
+    - x86/pkeys: Add check for pkey "overflow"
+    - bpf: Remove recursion prevention from rcu free callback
+    - dmaengine: stm32-dma: use vchan_terminate_vdesc() in .terminate_all
+    - dmaengine: tegra-apb: Prevent race conditions on channel's freeing
+    - soundwire: bus: disable pm_runtime in sdw_slave_delete
+    - drm/amd/display: dal_ddc_i2c_payloads_create can fail causing panic
+    - drm/omap: dss: Cleanup DSS ports on initialisation failure
+    - iavf: use tc_cls_can_offload_and_chain0() instead of chain check
+    - firmware: arm_sdei: Use cpus_read_lock() to avoid races with cpuhp
+    - random: fix data races at timer_rand_state
+    - bus: hisi_lpc: Fixup IO ports addresses to avoid use-after-free in host
+      removal
+    - ASoC: SOF: ipc: check ipc return value before data copy
+    - media: go7007: Fix URB type for interrupt handling
+    - Bluetooth: guard against controllers sending zero'd events
+    - timekeeping: Prevent 32bit truncation in scale64_check_overflow()
+    - powerpc/book3s64: Fix error handling in mm_iommu_do_alloc()
+    - drm/amd/display: fix image corruption with ODM 2:1 DSC 2 slice
+    - ext4: fix a data race at inode->i_disksize
+    - perf jevents: Fix leak of mapfile memory
+    - mm: avoid data corruption on CoW fault into PFN-mapped VMA
+    - drm/amdgpu: increase atombios cmd timeout
+    - ARM: OMAP2+: Handle errors for cpu_pm
+    - clk: imx: Fix division by zero warning on pfdv2
+    - cpu-topology: Fix the potential data corruption
+    - s390/irq: replace setup_irq() by request_irq()
+    - perf cs-etm: Swap packets for instruction samples
+    - perf cs-etm: Correct synthesizing instruction samples
+    - ath10k: use kzalloc to read for ath10k_sdio_hif_diag_read
+    - scsi: aacraid: Disabling TM path and only processing IOP reset
+    - Bluetooth: L2CAP: handle l2cap config request during open state
+    - media: tda10071: fix unsigned sign extension overflow
+    - tty: sifive: Finish transmission before changing the clock
+    - xfs: don't ever return a stale pointer from __xfs_dir3_free_read
+    - xfs: mark dir corrupt when lookup-by-hash fails
+    - ext4: mark block bitmap corrupted when found instead of BUGON
+    - tpm: ibmvtpm: Wait for buffer to be set before proceeding
+    - rtc: sa1100: fix possible race condition
+    - rtc: ds1374: fix possible race condition
+    - nfsd: Don't add locks to closed or closing open stateids
+    - RDMA/cm: Remove a race freeing timewait_info
+    - intel_th: Disallow multi mode on devices where it's broken
+    - KVM: PPC: Book3S HV: Treat TM-related invalid form instructions on P9 like
+      the valid ones
+    - drm/msm: fix leaks if initialization fails
+    - drm/msm/a5xx: Always set an OPP supported hardware value
+    - tracing: Use address-of operator on section symbols
+    - thermal: rcar_thermal: Handle probe error gracefully
+    - KVM: LAPIC: Mark hrtimer for period or oneshot mode to expire in hard
+      interrupt context
+    - perf parse-events: Fix 3 use after frees found with clang ASAN
+    - btrfs: do not init a reloc root if we aren't relocating
+    - btrfs: free the reloc_control in a consistent way
+    - r8169: improve RTL8168b FIFO overflow workaround
+    - serial: 8250_port: Don't service RX FIFO if throttled
+    - serial: 8250_omap: Fix sleeping function called from invalid context during
+      probe
+    - serial: 8250: 8250_omap: Terminate DMA before pushing data on RX timeout
+    - perf cpumap: Fix snprintf overflow check
+    - net: axienet: Convert DMA error handler to a work queue
+    - net: axienet: Propagate failure of DMA descriptor setup
+    - cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_work_fn
+    - tools: gpio-hammer: Avoid potential overflow in main
+    - exec: Add exec_update_mutex to replace cred_guard_mutex
+    - exec: Fix a deadlock in strace
+    - selftests/ptrace: add test cases for dead-locks
+    - kernel/kcmp.c: Use new infrastructure to fix deadlocks in execve
+    - proc: Use new infrastructure to fix deadlocks in execve
+    - proc: io_accounting: Use new infrastructure to fix deadlocks in execve
+    - perf: Use new infrastructure to fix deadlocks in execve
+    - nvme-multipath: do not reset on unknown status
+    - nvme: Fix ctrl use-after-free during sysfs deletion
+    - nvme: Fix controller creation races with teardown flow
+    - brcmfmac: Fix double freeing in the fmac usb data path
+    - xfs: prohibit fs freezing when using empty transactions
+    - RDMA/rxe: Set sys_image_guid to be aligned with HW IB devices
+    - IB/iser: Always check sig MR before putting it to the free pool
+    - scsi: hpsa: correct race condition in offload enabled
+    - SUNRPC: Fix a potential buffer overflow in 'svc_print_xprts()'
+    - svcrdma: Fix leak of transport addresses
+    - netfilter: nf_tables: silence a RCU-list warning in nft_table_lookup()
+    - PCI: Use ioremap(), not phys_to_virt() for platform ROM
+    - ubifs: ubifs_jnl_write_inode: Fix a memory leak bug
+    - ubifs: ubifs_add_orphan: Fix a memory leak bug
+    - 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
+    - PCI: pciehp: Fix MSI interrupt race
+    - NFS: Fix races nfs_page_group_destroy() vs
+      nfs_destroy_unlinked_subrequests()
+    - drm/amdgpu/vcn2.0: stall DPG when WPTR/RPTR reset
+    - powerpc/perf: Implement a global lock to avoid races between trace, core and
+      thread imc events.
+    - mm/kmemleak.c: use address-of operator on section symbols
+    - mm/filemap.c: clear page error before actual read
+    - mm/swapfile: fix data races in try_to_unuse()
+    - mm/vmscan.c: fix data races using kswapd_classzone_idx
+    - SUNRPC: Don't start a timer on an already queued rpc task
+    - nvmet-rdma: fix double free of rdma queue
+    - workqueue: Remove the warning in wq_worker_sleeping()
+    - drm/amdgpu/sriov add amdgpu_amdkfd_pre_reset in gpu reset
+    - mm/mmap.c: initialize align_offset explicitly for vm_unmapped_area
+    - ALSA: hda: Skip controller resume if not needed
+    - scsi: qedi: Fix termination timeouts in session logout
+    - serial: uartps: Wait for tx_empty in console setup
+    - btrfs: fix setting last_trans for reloc roots
+    - KVM: Remove CREATE_IRQCHIP/SET_PIT2 race
+    - perf stat: Force error in fallback on :k events
+    - bdev: Reduce time holding bd_mutex in sync in blkdev_close()
+    - drivers: char: tlclk.c: Avoid data race between init and interrupt handler
+    - KVM: arm64: vgic-v3: Retire all pending LPIs on vcpu destroy
+    - KVM: arm64: vgic-its: Fix memory leak on the error path of vgic_add_lpi()
+    - net: openvswitch: use u64 for meter bucket
+    - scsi: aacraid: Fix error handling paths in aac_probe_one()
+    - staging:r8188eu: avoid skb_clone for amsdu to msdu conversion
+    - sparc64: vcc: Fix error return code in vcc_probe()
+    - arm64: cpufeature: Relax checks for AArch32 support at EL[0-2]
+    - sched/fair: Eliminate bandwidth race between throttling and distribution
+    - dpaa2-eth: fix error return code in setup_dpni()
+    - dt-bindings: sound: wm8994: Correct required supplies based on actual
+      implementaion
+    - devlink: Fix reporter's recovery condition
+    - atm: fix a memory leak of vcc->user_back
+    - media: venus: vdec: Init registered list unconditionally
+    - perf mem2node: Avoid double free related to realloc
+    - mm/slub: fix incorrect interpretation of s->offset
+    - i2c: tegra: Restore pinmux on system resume
+    - power: supply: max17040: Correct voltage reading
+    - 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()
+    - KVM: x86: handle wrap around 32-bit address space
+    - tipc: fix memory leak in service subscripting
+    - tty: serial: samsung: Correct clock selection logic
+    - ALSA: hda: Fix potential race in unsol event handler
+    - drm/exynos: dsi: Remove bridge node reference in error handling path in
+      probe function
+    - ipmi:bt-bmc: Fix error handling and status check
+    - powerpc/traps: Make unrecoverable NMIs die instead of panic
+    - svcrdma: Fix backchannel return code
+    - fuse: don't check refcount after stealing page
+    - fuse: update attr_version counter on fuse_notify_inval_inode()
+    - USB: EHCI: ehci-mv: fix less than zero comparison of an unsigned int
+    - coresight: etm4x: Fix use-after-free of per-cpu etm drvdata
+    - arm64: acpi: Make apei_claim_sea() synchronise with APEI's irq work
+    - scsi: cxlflash: Fix error return code in cxlflash_probe()
+    - arm64/cpufeature: Drop TraceFilt feature exposure from ID_DFR0 register
+    - drm/amdkfd: fix restore worker race condition
+    - e1000: Do not perform reset in reset_task if we are already down
+    - drm/nouveau/debugfs: fix runtime pm imbalance on error
+    - drm/nouveau: fix runtime pm imbalance on error
+    - drm/nouveau/dispnv50: fix runtime pm imbalance on error
+    - printk: handle blank console arguments passed in.
+    - usb: dwc3: Increase timeout for CmdAct cleared by device controller
+    - btrfs: don't force read-only after error in drop snapshot
+    - btrfs: fix double __endio_write_update_ordered in direct I/O
+    - gpio: rcar: Fix runtime PM imbalance on error
+    - vfio/pci: fix memory leaks of eventfd ctx
+    - KVM: PPC: Book3S HV: Close race with page faults around memslot flushes
+    - perf evsel: Fix 2 memory leaks
+    - perf trace: Fix the selection for architectures to generate the errno name
+      tables
+    - perf stat: Fix duration_time value for higher intervals
+    - perf util: Fix memory leak of prefix_if_not_in
+    - perf metricgroup: Free metric_events on error
+    - perf kcore_copy: Fix module map when there are no modules loaded
+    - PCI: tegra194: Fix runtime PM imbalance on error
+    - ASoC: img-i2s-out: Fix runtime PM imbalance on error
+    - wlcore: fix runtime pm imbalance in wl1271_tx_work
+    - wlcore: fix runtime pm imbalance in wlcore_regdomain_config
+    - mtd: rawnand: gpmi: Fix runtime PM imbalance on error
+    - mtd: rawnand: omap_elm: Fix runtime PM imbalance on error
+    - PCI: tegra: Fix runtime PM imbalance on error
+    - ceph: fix potential race in ceph_check_caps
+    - mm/swap_state: fix a data race in swapin_nr_pages
+    - mm: memcontrol: fix stat-corrupting race in charge moving
+    - rapidio: avoid data race between file operation callbacks and
+      mport_cdev_add().
+    - mtd: parser: cmdline: Support MTD names containing one or more colons
+    - x86/speculation/mds: Mark mds_user_clear_cpu_buffers() __always_inline
+    - NFS: nfs_xdr_status should record the procedure name
+    - vfio/pci: Clear error and request eventfd ctx after releasing
+    - cifs: Fix double add page to memcg when cifs_readpages
+    - nvme: fix possible deadlock when I/O is blocked
+    - mac80211: skip mpath lookup also for control port tx
+    - scsi: libfc: Handling of extra kref
+    - scsi: libfc: Skip additional kref updating work event
+    - selftests/x86/syscall_nt: Clear weird flags after each test
+    - vfio/pci: fix racy on error and request eventfd ctx
+    - btrfs: qgroup: fix data leak caused by race between writeback and truncate
+    - perf tests: Fix test 68 zstd compression for s390
+    - scsi: qla2xxx: Retry PLOGI on FC-NVMe PRLI failure
+    - ubi: fastmap: Free unused fastmap anchor peb during detach
+    - mt76: fix LED link time failure
+    - opp: Increase parsed_static_opps in _of_add_opp_table_v1()
+    - perf parse-events: Use strcmp() to compare the PMU name
+    - ALSA: hda: Always use jackpoll helper for jack update after resume
+    - ALSA: hda: Workaround for spurious wakeups on some Intel platforms
+    - net: openvswitch: use div_u64() for 64-by-32 divisions
+    - nvme: explicitly update mpath disk capacity on revalidation
+    - device_cgroup: Fix RCU list debugging warning
+    - ASoC: pcm3168a: ignore 0 Hz settings
+    - ASoC: wm8994: Skip setting of the WM8994_MICBIAS register for WM1811
+    - ASoC: wm8994: Ensure the device is resumed in wm89xx_mic_detect functions
+    - ASoC: Intel: bytcr_rt5640: Add quirk for MPMAN Converter9 2-in-1
+    - RISC-V: Take text_mutex in ftrace_init_nop()
+    - i2c: aspeed: Mask IRQ status to relevant bits
+    - s390/init: add missing __init annotations
+    - lockdep: fix order in trace_hardirqs_off_caller()
+    - EDAC/ghes: Check whether the driver is on the safe list correctly
+    - drm/amdkfd: fix a memory leak issue
+    - drm/amd/display: update nv1x stutter latencies
+    - drm/amdgpu/dc: Require primary plane to be enabled whenever the CRTC is
+    - objtool: Fix noreturn detection for ignored functions
+    - ieee802154: fix one possible memleak in ca8210_dev_com_init
+    - ieee802154/adf7242: check status of adf7242_read_reg
+    - clocksource/drivers/h8300_timer8: Fix wrong return value in
+      h8300_8timer_init()
+    - 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
+    - netfilter: conntrack: nf_conncount_init is failing with IPv6 disabled
+    - mac802154: tx: fix use-after-free
+    - bpf: Fix clobbering of r2 in bpf_gen_ld_abs
+    - drm/vc4/vc4_hdmi: fill ASoC card owner
+    - net: qed: Disable aRFS for NPAR and 100G
+    - net: qede: Disable aRFS for NPAR and 100G
+    - net: qed: RDMA personality shouldn't fail VF load
+    - drm/sun4i: sun8i-csc: Secondary CSC register correction
+    - batman-adv: Add missing include for in_interrupt()
+    - nvme-tcp: fix kconfig dependency warning when !CRYPTO
+    - batman-adv: mcast: fix duplicate mcast packets in BLA backbone from LAN
+    - batman-adv: mcast: fix duplicate mcast packets in BLA backbone from mesh
+    - batman-adv: mcast: fix duplicate mcast packets from BLA backbone to mesh
+    - bpf: Fix a rcu warning for bpffs map pretty-print
+    - lib80211: fix unmet direct dependendices config warning when !CRYPTO
+    - ALSA: asihpi: fix iounmap in error handler
+    - regmap: fix page selection for noinc reads
+    - regmap: fix page selection for noinc writes
+    - MIPS: Add the missing 'CPU_1074K' into __get_cpu_type()
+    - regulator: axp20x: fix LDO2/4 description
+    - KVM: x86: Reset MMU context if guest toggles CR4.SMAP or CR4.PKE
+    - KVM: SVM: Add a dedicated INVD intercept routine
+    - mm: validate pmd after splitting
+    - arch/x86/lib/usercopy_64.c: fix __copy_user_flushcache() cache writeback
+    - x86/ioapic: Unbreak check_timer()
+    - scsi: lpfc: Fix initial FLOGI failure due to BBSCN not supported
+    - ALSA: usb-audio: Add delay quirk for H570e USB headsets
+    - ALSA: hda/realtek - Couldn't detect Mic if booting with headset plugged
+    - ALSA: hda/realtek: Enable front panel headset LED on Lenovo ThinkStation
+      P520
+    - lib/string.c: implement stpcpy
+    - tracing: fix double free
+    - s390/dasd: Fix zero write for FBA devices
+    - kprobes: Fix to check probe enabled before disarm_kprobe_ftrace()
+    - kprobes: tracing/kprobes: Fix to kill kprobes on initmem after boot
+    - btrfs: fix overflow when copying corrupt csums for a message
+    - dmabuf: fix NULL pointer dereference in dma_buf_release()
+    - mm, THP, swap: fix allocating cluster for swapfile by mistake
+    - mm/gup: fix gup_fast with dynamic page table folding
+    - s390/zcrypt: Fix ZCRYPT_PERDEV_REQCNT ioctl
+    - KVM: arm64: Assume write fault on S1PTW permission fault on instruction
+      fetch
+    - dm: fix bio splitting and its bio completion order for regular IO
+    - ata: define AC_ERR_OK
+    - ata: make qc_prep return ata_completion_errors
+    - ata: sata_mv, avoid trigerrable BUG_ON
+    - Linux 5.4.69
+
+  * Focal update: v5.4.68 upstream stable release (LP: #1899511)
+    - af_key: pfkey_dump needs parameter validation
+    - ibmvnic fix NULL tx_pools and rx_tools issue at do_reset
+    - ibmvnic: add missing parenthesis in do_reset()
+    - kprobes: fix kill kprobe which has been marked as gone
+    - mm/thp: fix __split_huge_pmd_locked() for migration PMD
+    - act_ife: load meta modules before tcf_idr_check_alloc()
+    - bnxt_en: Avoid sending firmware messages when AER error is detected.
+    - bnxt_en: Fix NULL ptr dereference crash in bnxt_fw_reset_task()
+    - cxgb4: fix memory leak during module unload
+    - cxgb4: Fix offset when clearing filter byte counters
+    - geneve: add transport ports in route lookup for geneve
+    - hdlc_ppp: add range checks in ppp_cp_parse_cr()
+    - ip: fix tos reflection in ack and reset packets
+    - ipv4: Initialize flowi4_multipath_hash in data path
+    - ipv4: Update exception handling for multipath routes via same device
+    - ipv6: avoid lockdep issue in fib6_del()
+    - net: bridge: br_vlan_get_pvid_rcu() should dereference the VLAN group under
+      RCU
+    - net: DCB: Validate DCB_ATTR_DCB_BUFFER argument
+    - net: dsa: rtl8366: Properly clear member config
+    - net: Fix bridge enslavement failure
+    - net: ipv6: fix kconfig dependency warning for IPV6_SEG6_HMAC
+    - net/mlx5: Fix FTE cleanup
+    - net: sch_generic: aviod concurrent reset and enqueue op for lockless qdisc
+    - net: sctp: Fix IPv6 ancestor_size calc in sctp_copy_descendant
+    - nfp: use correct define to return NONE fec
+    - taprio: Fix allowing too small intervals
+    - tipc: Fix memory leak in tipc_group_create_member()
+    - tipc: fix shutdown() of connection oriented socket
+    - tipc: use skb_unshare() instead in tipc_buf_append()
+    - net/mlx5e: Enable adding peer miss rules only if merged eswitch is supported
+    - net/mlx5e: TLS, Do not expose FPGA TLS counter if not supported
+    - bnxt_en: return proper error codes in bnxt_show_temp
+    - bnxt_en: Protect bnxt_set_eee() and bnxt_set_pauseparam() with mutex.
+    - net: lantiq: Wake TX queue again
+    - net: lantiq: use netif_tx_napi_add() for TX NAPI
+    - net: lantiq: Use napi_complete_done()
+    - net: lantiq: Disable IRQs only if NAPI gets scheduled
+    - net: phy: Avoid NPD upon phy_detach() when driver is unbound
+    - net: phy: Do not warn in phy_stop() on PHY_DOWN
+    - net: qrtr: check skb_put_padto() return value
+    - net: add __must_check to skb_put_padto()
+    - mm: memcg: fix memcg reclaim soft lockup
+    - iommu/amd: Use cmpxchg_double() when updating 128-bit IRTE
+    - Linux 5.4.68
+
+  * *-tools-common packages descriptions have typo "PGKVER" (LP: #1898903)
+    - [Packaging] Fix typo in -tools template s/PGKVER/PKGVER/
+
+  * tc/ebpf: unable to use BPF_FUNC_skb_change_head (LP: #1896504)
+    - net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
+
+  * HP Zbook Studio G7 boots into corrupted screen with PSR featured panel
+    (LP: #1897501)
+    - SAUCE: drm/i915/psr: allow overriding PSR disable param by quirk
+    - SAUCE: drm/dp: add DP_QUIRK_FORCE_PSR_CHIP_DEFAULT quirk to CMN prod-ID
+      19-15
+
+  * Fix broken e1000e device after S3 (LP: #1897755)
+    - SAUCE: e1000e: Increase polling timeout on MDIC ready bit
+
+  * debian/rules editconfigs does not work on s390x to change s390x only configs
+    (LP: #1863116)
+    - [Packaging] kernelconfig -- only update/edit configurations on architectures
+      we have compiler support
+
+  * acpi event detection crashes (LP: #1896482)
+    - ACPI: EC: tweak naming in preparation for GpioInt support
+    - ACPI: EC: add support for hardware-reduced systems
+    - ACPI: EC: Avoid passing redundant argument to functions
+    - ACPI: EC: Consolidate event handler installation code
+
+  * mwifiex stops working after kernel upgrade (LP: #1897299)
+    - mwifiex: Increase AES key storage size to 256 bits
+
+  * Remove NVMe suspend-to-idle workaround (LP: #1897227)
+    - Revert "UBUTU: SAUCE: pci: prevent Intel NVMe SSDPEKKF from entering D3"
+    - Revert "UBUNTU: SAUCE: pci: prevent sk hynix nvme from entering D3"
+
+  * Request for CIFS patches to be available in 5.4 kernel (LP: #1896642)
+    - smb3: remove unused flag passed into close functions
+    - smb3: query attributes on file close
+
+  * Lenovo ThinkBook 14-IML Touchpad not showing up in /proc/bus/input/devices
+    (LP: #1853277)
+    - i2c: core: Call i2c_acpi_install_space_handler() before
+      i2c_acpi_register_devices()
+
+  * [Ubuntu 20.10] zPCI DMA tables and bitmap leak on hard unplug (PCI Event
+    0x0304) (LP: #1896216)
+    - s390/pci: fix leak of DMA tables on hard unplug
+
+  * Thunderbolt3 daisy chain sometimes doesn't work (LP: #1895606)
+    - thunderbolt: Retry DROM read once if parsing fails
+
+  * btrfs: trimming a btrfs device which has been shrunk previously fails and
+    fills root disk with garbage data (LP: #1896154)
+    - btrfs: trim: fix underflow in trim length to prevent access beyond device
+      boundary
+
+  * EFA: add support for 0xefa1 devices (LP: #1896791)
+    - RDMA/efa: Expose maximum TX doorbell batch
+    - RDMA/efa: Expose minimum SQ size
+    - RDMA/efa: User/kernel compatibility handshake mechanism
+    - RDMA/efa: Add EFA 0xefa1 PCI ID
+
+  * Focal update: v5.4.67 upstream stable release (LP: #1896828)
+    - gfs2: initialize transaction tr_ailX_lists earlier
+    - RDMA/bnxt_re: Restrict the max_gids to 256
+    - dsa: Allow forwarding of redirected IGMP traffic
+    - net: handle the return value of pskb_carve_frag_list() correctly
+    - hv_netvsc: Remove "unlikely" from netvsc_select_queue
+    - firmware_loader: fix memory leak for paged buffer
+    - NFSv4.1 handle ERR_DELAY error reclaiming locking state on delegation recall
+    - scsi: pm8001: Fix memleak in pm8001_exec_internal_task_abort
+    - scsi: libfc: Fix for double free()
+    - scsi: lpfc: Fix FLOGI/PLOGI receive race condition in pt2pt discovery
+    - regulator: pwm: Fix machine constraints application
+    - spi: spi-loopback-test: Fix out-of-bounds read
+    - NFS: Zero-stateid SETATTR should first return delegation
+    - SUNRPC: stop printk reading past end of string
+    - rapidio: Replace 'select' DMAENGINES 'with depends on'
+    - cifs: fix DFS mount with cifsacl/modefromsid
+    - openrisc: Fix cache API compile issue when not inlining
+    - nvme-fc: cancel async events before freeing event struct
+    - nvme-rdma: cancel async events before freeing event struct
+    - nvme-tcp: cancel async events before freeing event struct
+    - block: only call sched requeue_request() for scheduled requests
+    - f2fs: fix indefinite loop scanning for free nid
+    - f2fs: Return EOF on unaligned end of file DIO read
+    - i2c: algo: pca: Reapply i2c bus settings after reset
+    - spi: Fix memory leak on splited transfers
+    - KVM: MIPS: Change the definition of kvm type
+    - clk: davinci: Use the correct size when allocating memory
+    - clk: rockchip: Fix initialization of mux_pll_src_4plls_p
+    - ASoC: qcom: Set card->owner to avoid warnings
+    - ASoC: qcom: common: Fix refcount imbalance on error
+    - powerpc/book3s64/radix: Fix boot failure with large amount of guest memory
+    - ASoC: meson: axg-toddr: fix channel order on g12 platforms
+    - Drivers: hv: vmbus: hibernation: do not hang forever in vmbus_bus_resume()
+    - scsi: libsas: Fix error path in sas_notify_lldd_dev_found()
+    - arm64: Allow CPUs unffected by ARM erratum 1418040 to come in late
+    - Drivers: hv: vmbus: Add timeout to vmbus_wait_for_unload
+    - perf test: Fix the "signal" test inline assembly
+    - MIPS: SNI: Fix MIPS_L1_CACHE_SHIFT
+    - perf evlist: Fix cpu/thread map leak
+    - perf parse-event: Fix memory leak in evsel->unit
+    - perf test: Free formats for perf pmu parse test
+    - fbcon: Fix user font detection test at fbcon_resize().
+    - MIPS: SNI: Fix spurious interrupts
+    - drm/mediatek: Add exception handing in mtk_drm_probe() if component init
+      fail
+    - drm/mediatek: Add missing put_device() call in mtk_hdmi_dt_parse_pdata()
+    - arm64: bpf: Fix branch offset in JIT
+    - iommu/amd: Fix potential @entry null deref
+    - i2c: mxs: use MXS_DMA_CTRL_WAIT4END instead of DMA_CTRL_ACK
+    - riscv: Add sfence.vma after early page table changes
+    - drm/i915: Filter wake_flags passed to default_wake_function
+    - 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()
+    - i2c: i801: Fix resume bug
+    - Revert "ALSA: hda - Fix silent audio output and corrupted input on MSI
+      X570-A PRO"
+    - ALSA: hda: fixup headset for ASUS GX502 laptop
+    - ALSA: hda/realtek - The Mic on a RedmiBook doesn't work
+    - percpu: fix first chunk size calculation for populated bitmap
+    - Input: trackpoint - add new trackpoint variant IDs
+    - Input: i8042 - add Entroware Proteus EL07R4 to nomux and reset lists
+    - serial: 8250_pci: Add Realtek 816a and 816b
+    - x86/boot/compressed: Disable relocation relaxation
+    - s390/zcrypt: fix kmalloc 256k failure
+    - ehci-hcd: Move include to keep CRC stable
+    - powerpc/dma: Fix dma_map_ops::get_required_mask
+    - selftests/vm: fix display of page size in map_hugetlb
+    - dm/dax: Fix table reference counts
+    - mm/memory_hotplug: drain per-cpu pages again during memory offline
+    - dm: Call proper helper to determine dax support
+    - dax: Fix compilation for CONFIG_DAX && !CONFIG_FS_DAX
+    - Linux 5.4.67
+
+  * Focal update: v5.4.67 upstream stable release (LP: #1896828) // Cherry Pick
+    needed for Critical upstream patch for Kernel null pointer dereference -
+    usb-c altmode (LP: #1897963)
+    - usb: typec: ucsi: Prevent mode overrun
+
+  * Focal update: v5.4.66 upstream stable release (LP: #1896824)
+    - ARM: dts: logicpd-torpedo-baseboard: Fix broken audio
+    - ARM: dts: logicpd-som-lv-baseboard: Fix broken audio
+    - ARM: dts: logicpd-som-lv-baseboard: Fix missing video
+    - regulator: push allocation in regulator_ena_gpio_request() out of lock
+    - regulator: remove superfluous lock in regulator_resolve_coupling()
+    - ARM: dts: socfpga: fix register entry for timer3 on Arria10
+    - ARM: dts: ls1021a: fix QuadSPI-memory reg range
+    - ARM: dts: imx7ulp: Correct gpio ranges
+    - RDMA/rxe: Fix memleak in rxe_mem_init_user
+    - RDMA/rxe: Drop pointless checks in rxe_init_ports
+    - RDMA/rxe: Fix panic when calling kmem_cache_create()
+    - RDMA/bnxt_re: Do not report transparent vlan from QP1
+    - drm/sun4i: add missing put_device() call in sun8i_r40_tcon_tv_set_mux()
+    - arm64: dts: imx8mq: Fix TMU interrupt property
+    - drm/sun4i: Fix dsi dcs long write function
+    - iio: adc: mcp3422: fix locking on error path
+    - iio: adc: mcp3422: fix locking scope
+    - scsi: libsas: Set data_dir as DMA_NONE if libata marks qc as NODATA
+    - RDMA/core: Fix reported speed and width
+    - scsi: megaraid_sas: Don't call disable_irq from process IRQ poll
+    - scsi: mpt3sas: Don't call disable_irq from IRQ poll handler
+    - soundwire: fix double free of dangling pointer
+    - drm/sun4i: backend: Support alpha property on lowest plane
+    - drm/sun4i: backend: Disable alpha on the lowest plane on the A20
+    - mmc: sdhci-acpi: Clear amd_sdhci_host on reset
+    - mmc: sdhci-msm: Add retries when all tuning phases are found valid
+    - spi: stm32: Rate-limit the 'Communication suspended' message
+    - nvme-fabrics: allow to queue requests for live queues
+    - spi: stm32: fix pm_runtime_get_sync() error checking
+    - block: Set same_page to false in __bio_try_merge_page if ret is false
+    - IB/isert: Fix unaligned immediate-data handling
+    - ARM: dts: bcm: HR2: Fixed QSPI compatible string
+    - ARM: dts: NSP: Fixed QSPI compatible string
+    - ARM: dts: BCM5301X: Fixed QSPI compatible string
+    - arm64: dts: ns2: Fixed QSPI compatible string
+    - ARC: HSDK: wireup perf irq
+    - dmaengine: acpi: Put the CSRT table after using it
+    - netfilter: conntrack: allow sctp hearbeat after connection re-use
+    - drivers/net/wan/lapbether: Added needed_tailroom
+    - NFC: st95hf: Fix memleak in st95hf_in_send_cmd
+    - firestream: Fix memleak in fs_open
+    - ALSA: hda: Fix 2 channel swapping for Tegra
+    - ALSA: hda/tegra: Program WAKEEN register for Tegra
+    - drivers/dma/dma-jz4780: Fix race condition between probe and irq handler
+    - net: hns3: Fix for geneve tx checksum bug
+    - xfs: fix off-by-one in inode alloc block reservation calculation
+    - drivers/net/wan/lapbether: Set network_header before transmitting
+    - cfg80211: Adjust 6 GHz frequency to channel conversion
+    - xfs: initialize the shortform attr header padding entry
+    - irqchip/eznps: Fix build error for !ARC700 builds
+    - nvmet-tcp: Fix NULL dereference when a connect data comes in h2cdata pdu
+    - nvme-fabrics: don't check state NVME_CTRL_NEW for request acceptance
+    - nvme: have nvme_wait_freeze_timeout return if it timed out
+    - nvme-tcp: serialize controller teardown sequences
+    - nvme-tcp: fix timeout handler
+    - nvme-tcp: fix reset hang if controller died in the middle of a reset
+    - nvme-rdma: serialize controller teardown sequences
+    - nvme-rdma: fix timeout handler
+    - nvme-rdma: fix reset hang if controller died in the middle of a reset
+    - nvme-pci: cancel nvme device request before disabling
+    - HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for all Saitek X52 devices
+    - HID: microsoft: Add rumble support for the 8bitdo SN30 Pro+ controller
+    - drivers/net/wan/hdlc_cisco: Add hard_header_len
+    - HID: elan: Fix memleak in elan_input_configured
+    - ARC: [plat-hsdk]: Switch ethernet phy-mode to rgmii-id
+    - cpufreq: intel_pstate: Refuse to turn off with HWP enabled
+    - cpufreq: intel_pstate: Fix intel_pstate_get_hwp_max() for turbo disabled
+    - arm64/module: set trampoline section flags regardless of
+      CONFIG_DYNAMIC_FTRACE
+    - ALSA: hda: hdmi - add Rocketlake support
+    - ALSA: hda: fix a runtime pm issue in SOF when integrated GPU is disabled
+    - drm/amdgpu: Fix bug in reporting voltage for CIK
+    - iommu/amd: Do not use IOMMUv2 functionality when SME is active
+    - gcov: Disable gcov build with GCC 10
+    - iio: adc: ti-ads1015: fix conversion when CONFIG_PM is not set
+    - iio: cros_ec: Set Gyroscope default frequency to 25Hz
+    - iio:light:ltr501 Fix timestamp alignment issue.
+    - iio:proximity:mb1232: Fix timestamp alignment and prevent data leak.
+    - iio:accel:bmc150-accel: Fix timestamp alignment and prevent data leak.
+    - iio:adc:ti-adc084s021 Fix alignment and data leak issues.
+    - iio:adc:ina2xx Fix timestamp alignment issue.
+    - iio:adc:max1118 Fix alignment of timestamp and data leak issues
+    - iio:adc:ti-adc081c Fix alignment and data leak issues
+    - iio:magnetometer:ak8975 Fix alignment and data leak issues.
+    - iio:light:max44000 Fix timestamp alignment and prevent data leak.
+    - iio:chemical:ccs811: Fix timestamp alignment and prevent data leak.
+    - iio: accel: kxsd9: Fix alignment of local buffer.
+    - iio:accel:mma7455: Fix timestamp alignment and prevent data leak.
+    - iio:accel:mma8452: Fix timestamp alignment and prevent data leak.
+    - staging: wlan-ng: fix out of bounds read in prism2sta_probe_usb()
+    - btrfs: require only sector size alignment for parent eb bytenr
+    - btrfs: fix lockdep splat in add_missing_dev
+    - btrfs: fix wrong address when faulting in pages in the search ioctl
+    - kobject: Restore old behaviour of kobject_del(NULL)
+    - regulator: push allocation in regulator_init_coupling() outside of lock
+    - regulator: push allocations in create_regulator() outside of lock
+    - regulator: push allocation in set_consumer_device_supply() out of lock
+    - regulator: plug of_node leak in regulator_register()'s error path
+    - regulator: core: Fix slab-out-of-bounds in regulator_unlock_recursive()
+    - scsi: target: iscsi: Fix data digest calculation
+    - scsi: target: iscsi: Fix hang in iscsit_access_np() when getting
+      tpg->np_login_sem
+    - drm/i915/gvt: do not check len & max_len for lri
+    - drm/tve200: Stabilize enable/disable
+    - drm/msm: Disable preemption on all 5xx targets
+    - mmc: sdio: Use mmc_pre_req() / mmc_post_req()
+    - mmc: sdhci-of-esdhc: Don't walk device-tree on every interrupt
+    - rbd: require global CAP_SYS_ADMIN for mapping and unmapping
+    - RDMA/rxe: Fix the parent sysfs read when the interface has 15 chars
+    - RDMA/mlx4: Read pkey table length instead of hardcoded value
+    - 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
+    - KVM: arm64: Do not try to map PUDs when they are folded into PMD
+    - KVM: fix memory leak in kvm_io_bus_unregister_dev()
+    - debugfs: Fix module state check condition
+    - ARM: dts: vfxxx: Add syscon compatible with OCOTP
+    - video: fbdev: fix OOB read in vga_8planes_imageblit()
+    - staging: greybus: audio: fix uninitialized value issue
+    - phy: qcom-qmp: Use correct values for ipq8074 PCIe Gen2 PHY init
+    - usb: core: fix slab-out-of-bounds Read in read_descriptors
+    - USB: serial: ftdi_sio: add IDs for Xsens Mti USB converter
+    - USB: serial: option: support dynamic Quectel USB compositions
+    - USB: serial: option: add support for SIM7070/SIM7080/SIM7090 modules
+    - usb: Fix out of sync data toggle if a configured device is reconfigured
+    - usb: typec: ucsi: acpi: Check the _DEP dependencies
+    - drm/msm/gpu: make ringbuffer readonly
+    - drm/msm: Disable the RPTR shadow
+    - gcov: add support for GCC 10.1
+    - Linux 5.4.66
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Mon, 09 Nov 2020 14:56:24 +0100
+
+linux (5.4.0-54.60) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * Introduce the new NVIDIA 455 series (LP: #1902093)
+    - [Packaging] NVIDIA -- Add the NVIDIA 455 driver
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 05 Nov 2020 18:03:49 +0100
+
+linux (5.4.0-53.59) focal; 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:00:29 +0200
+
+linux (5.4.0-52.57) focal; urgency=medium
+
+  * focal/linux: 5.4.0-52.57 -proposed tracker (LP: #1899920)
+
+  * CVE-2020-12351 // CVE-2020-12352 // CVE-2020-24490
+    - Bluetooth: Disable High Speed by default
+    - Bluetooth: MGMT: Fix not checking if BT_HS is enabled
+    - [Config] Disable BlueZ highspeed support
+
+  * CVE-2020-12351
+    - Bluetooth: L2CAP: Fix calling sk_filter on non-socket based channel
+
+  * CVE-2020-12352
+    - Bluetooth: A2MP: Fix not initializing all members
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 15 Oct 2020 12:28:28 +0200
+
+linux (5.4.0-51.56) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 05 Oct 2020 15:34:26 +0200
+
+linux (5.4.0-50.55) focal; urgency=medium
+
+  * CVE-2020-16119
+    - SAUCE: dccp: avoid double free of ccid on child socket
+
+  * CVE-2020-16120
+    - Revert "UBUNTU: SAUCE: overlayfs: ensure mounter privileges when reading
+      directories"
+    - ovl: pass correct flags for opening real directory
+    - ovl: switch to mounter creds in readdir
+    - ovl: verify permissions in ovl_path_open()
+    - ovl: call secutiry hook in ovl_real_ioctl()
+    - ovl: check permission to open real file
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 30 Sep 2020 10:04:48 -0300
+
+linux (5.4.0-49.53) focal; urgency=medium
+
+  * focal/linux: 5.4.0-49.53 -proposed tracker (LP: #1896007)
+
+  * Comet Lake PCH-H RAID not support on Ubuntu20.04 (LP: #1892288)
+    - ahci: Add Intel Comet Lake PCH-H PCI ID
+
+  * Novalink (mkvterm command failure) (LP: #1892546)
+    - tty: hvcs: Don't NULL tty->driver_data until hvcs_cleanup()
+
+  * Oops and hang when starting LVM snapshots on 5.4.0-47 (LP: #1894780)
+    - SAUCE: Revert "mm: memcg/slab: fix memory leak at non-root kmem_cache
+      destroy"
+
+  * Intel x710 LOMs do not work on Focal (LP: #1893956)
+    - i40e: Fix LED blinking flow for X710T*L devices
+    - i40e: enable X710 support
+
+  * Add/Backport EPYC-v3 and EPYC-Rome CPU model (LP: #1887490)
+    - kvm: svm: Update svm_xsaves_supported
+
+  * Fix non-working NVMe after S3 (LP: #1895718)
+    - SAUCE: PCI: Enable ACS quirk on CML root port
+
+  * Focal update: v5.4.65 upstream stable release (LP: #1895881)
+    - ipv4: Silence suspicious RCU usage warning
+    - ipv6: Fix sysctl max for fib_multipath_hash_policy
+    - netlabel: fix problems with mapping removal
+    - net: usb: dm9601: Add USB ID of Keenetic Plus DSL
+    - sctp: not disable bh in the whole sctp_get_port_local()
+    - taprio: Fix using wrong queues in gate mask
+    - tipc: fix shutdown() of connectionless socket
+    - net: disable netpoll on fresh napis
+    - Linux 5.4.65
+
+  * Focal update: v5.4.64 upstream stable release (LP: #1895880)
+    - HID: quirks: Always poll three more Lenovo PixArt mice
+    - drm/msm/dpu: Fix scale params in plane validation
+    - tty: serial: qcom_geni_serial: Drop __init from qcom_geni_console_setup
+    - drm/msm: add shutdown support for display platform_driver
+    - hwmon: (applesmc) check status earlier.
+    - nvmet: Disable keep-alive timer when kato is cleared to 0h
+    - drm/msm: enable vblank during atomic commits
+    - habanalabs: validate FW file size
+    - habanalabs: check correct vmalloc return code
+    - drm/msm/a6xx: fix gmu start on newer firmware
+    - ceph: don't allow setlease on cephfs
+    - drm/omap: fix incorrect lock state
+    - cpuidle: Fixup IRQ state
+    - nbd: restore default timeout when setting it to zero
+    - s390: don't trace preemption in percpu macros
+    - drm/amd/display: Reject overlay plane configurations in multi-display
+      scenarios
+    - drivers: gpu: amd: Initialize amdgpu_dm_backlight_caps object to 0 in
+      amdgpu_dm_update_backlight_caps
+    - drm/amd/display: Retry AUX write when fail occurs
+    - drm/amd/display: Fix memleak in amdgpu_dm_mode_config_init
+    - xen/xenbus: Fix granting of vmalloc'd memory
+    - fsldma: fix very broken 32-bit ppc ioread64 functionality
+    - dmaengine: of-dma: Fix of_dma_router_xlate's of_dma_xlate handling
+    - batman-adv: Avoid uninitialized chaddr when handling DHCP
+    - batman-adv: Fix own OGM check in aggregated OGMs
+    - 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()
+    - rxrpc: Keep the ACK serial in a var in rxrpc_input_ack()
+    - rxrpc: Make rxrpc_kernel_get_srtt() indicate validity
+    - MIPS: mm: BMIPS5000 has inclusive physical caches
+    - MIPS: BMIPS: Also call bmips_cpu_setup() for secondary cores
+    - mmc: sdhci-acpi: Fix HS400 tuning for AMDI0040
+    - netfilter: nf_tables: add NFTA_SET_USERDATA if not null
+    - netfilter: nf_tables: incorrect enum nft_list_attributes definition
+    - netfilter: nf_tables: fix destination register zeroing
+    - net: hns: Fix memleak in hns_nic_dev_probe
+    - net: systemport: Fix memleak in bcm_sysport_probe
+    - ravb: Fixed to be able to unload modules
+    - net: arc_emac: Fix memleak in arc_mdio_probe
+    - dmaengine: pl330: Fix burst length if burst size is smaller than bus width
+    - gtp: add GTPA_LINK info to msg sent to userspace
+    - net: ethernet: ti: cpsw: fix clean up of vlan mc entries for host port
+    - bnxt_en: Don't query FW when netif_running() is false.
+    - bnxt_en: Check for zero dir entries in NVRAM.
+    - bnxt_en: Fix PCI AER error recovery flow
+    - bnxt_en: Fix possible crash in bnxt_fw_reset_task().
+    - bnxt_en: fix HWRM error when querying VF temperature
+    - xfs: fix boundary test in xfs_attr_shortform_verify
+    - bnxt: don't enable NAPI until rings are ready
+    - media: vicodec: add missing v4l2_ctrl_request_hdl_put()
+    - media: cedrus: Add missing v4l2_ctrl_request_hdl_put()
+    - selftests/bpf: Fix massive output from test_maps
+    - net: dsa: mt7530: fix advertising unsupported 1000baseT_Half
+    - netfilter: nfnetlink: nfnetlink_unicast() reports EAGAIN instead of ENOBUFS
+    - nvmet-fc: Fix a missed _irqsave version of spin_lock in
+      'nvmet_fc_fod_op_done()'
+    - nvme: fix controller instance leak
+    - cxgb4: fix thermal zone device registration
+    - perf tools: Correct SNOOPX field offset
+    - net: ethernet: mlx4: Fix memory allocation in mlx4_buddy_init()
+    - fix regression in "epoll: Keep a reference on files added to the check list"
+    - net: gemini: Fix another missing clk_disable_unprepare() in probe
+    - MIPS: add missing MSACSR and upper MSA initialization
+    - xfs: fix xfs_bmap_validate_extent_raw when checking attr fork of rt files
+    - perf jevents: Fix suspicious code in fixregex()
+    - tg3: Fix soft lockup when tg3_reset_task() fails.
+    - x86, fakenuma: Fix invalid starting node ID
+    - iommu/vt-d: Serialize IOMMU GCMD register modifications
+    - thermal: ti-soc-thermal: Fix bogus thermal shutdowns for omap4430
+    - thermal: qcom-spmi-temp-alarm: Don't suppress negative temp
+    - iommu/amd: Restore IRTE.RemapEn bit after programming IRTE
+    - include/linux/log2.h: add missing () around n in roundup_pow_of_two()
+    - iommu/vt-d: Handle 36bit addressing for x86-32
+    - tracing/kprobes, x86/ptrace: Fix regs argument order for i386
+    - ext2: don't update mtime on COW faults
+    - xfs: don't update mtime on COW faults
+    - ARC: perf: don't bail setup if pct irq missing in device-tree
+    - btrfs: drop path before adding new uuid tree entry
+    - btrfs: allocate scrub workqueues outside of locks
+    - btrfs: set the correct lockdep class for new nodes
+    - btrfs: set the lockdep class for log tree extent buffers
+    - btrfs: tree-checker: fix the error message for transid error
+    - net: core: use listified Rx for GRO_NORMAL in napi_gro_receive()
+    - btrfs: fix potential deadlock in the search ioctl
+    - ALSA: ca0106: fix error code handling
+    - ALSA: usb-audio: Add implicit feedback quirk for UR22C
+    - ALSA: pcm: oss: Remove superfluous WARN_ON() for mulaw sanity check
+    - ALSA: hda/hdmi: always check pin power status in i915 pin fixup
+    - ALSA: firewire-digi00x: exclude Avid Adrenaline from detection
+    - ALSA: hda - Fix silent audio output and corrupted input on MSI X570-A PRO
+    - ALSA; firewire-tascam: exclude Tascam FE-8 from detection
+    - ALSA: hda/realtek: Add quirk for Samsung Galaxy Book Ion NT950XCJ-X716A
+    - ALSA: hda/realtek - Improved routing for Thinkpad X1 7th/8th Gen
+    - arm64: dts: mt7622: add reset node for mmc device
+    - mmc: mediatek: add optional module reset property
+    - mmc: dt-bindings: Add resets/reset-names for Mediatek MMC bindings
+    - mmc: cqhci: Add cqhci_deactivate()
+    - mmc: sdhci-pci: Fix SDHCI_RESET_ALL for CQHCI for Intel GLK-based
+      controllers
+    - media: rc: do not access device via sysfs after rc_unregister_device()
+    - media: rc: uevent sysfs file races with rc_unregister_device()
+    - affs: fix basic permission bits to actually work
+    - block: allow for_each_bvec to support zero len bvec
+    - block: ensure bdi->io_pages is always initialized
+    - libata: implement ATA_HORKAGE_MAX_TRIM_128M and apply to Sandisks
+    - blk-iocost: ioc_pd_free() shouldn't assume irq disabled
+    - dmaengine: dw-edma: Fix scatter-gather address calculation
+    - drm/amd/pm: avoid false alarm due to confusing softwareshutdowntemp setting
+    - dm writecache: handle DAX to partitions on persistent memory correctly
+    - dm mpath: fix racey management of PG initialization
+    - dm integrity: fix error reporting in bitmap mode after creation
+    - dm crypt: Initialize crypto wait structures
+    - dm cache metadata: Avoid returning cmd->bm wild pointer on error
+    - dm thin metadata: Avoid returning cmd->bm wild pointer on error
+    - dm thin metadata: Fix use-after-free in dm_bm_set_read_only
+    - mm: slub: fix conversion of freelist_corrupted()
+    - mm: madvise: fix vma user-after-free
+    - vfio/pci: Fix SR-IOV VF handling with MMIO blocking
+    - perf record: Correct the help info of option "--no-bpf-event"
+    - sdhci: tegra: Add missing TMCLK for data timeout
+    - checkpatch: fix the usage of capture group ( ... )
+    - mm/hugetlb: fix a race between hugetlb sysctl handlers
+    - mm/khugepaged.c: fix khugepaged's request size in collapse_file
+    - cfg80211: regulatory: reject invalid hints
+    - net: usb: Fix uninit-was-stored issue in asix_read_phy_addr()
+    - Linux 5.4.64
+
+  * Focal update: v5.4.63 upstream stable release (LP: #1895879)
+    - 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
+    - drm/sched: Fix passing zero to 'PTR_ERR' warning v2
+    - drm/etnaviv: fix TS cache flushing on GPUs with BLT engine
+    - KVM: arm64: Add kvm_extable for vaxorcism code
+    - KVM: arm64: Survive synchronous exceptions caused by AT instructions
+    - KVM: arm64: Set HCR_EL2.PTW to prevent AT taking synchronous exception
+    - dt-bindings: mmc: tegra: Add tmclk for Tegra210 and later
+    - arm64: tegra: Add missing timeout clock to Tegra194 SDMMC nodes
+    - arm64: tegra: Add missing timeout clock to Tegra186 SDMMC nodes
+    - arm64: tegra: Add missing timeout clock to Tegra210 SDMMC
+    - sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra210
+    - sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra186
+    - scsi: target: tcmu: Fix size in calls to tcmu_flush_dcache_range
+    - scsi: target: tcmu: Optimize use of flush_dcache_page
+    - Linux 5.4.63
+
+  * Focal update: v5.4.62 upstream stable release (LP: #1895174)
+    - binfmt_flat: revert "binfmt_flat: don't offset the data start"
+    - gre6: Fix reception with IP6_TNL_F_RCV_DSCP_COPY
+    - net: Fix potential wrong skb->protocol in skb_vlan_untag()
+    - net: nexthop: don't allow empty NHA_GROUP
+    - net: qrtr: fix usage of idr in port assignment to socket
+    - net: sctp: Fix negotiation of the number of data streams.
+    - net/smc: Prevent kernel-infoleak in __smc_diag_dump()
+    - tipc: fix uninit skb->data in tipc_nl_compat_dumpit()
+    - net: ena: Make missed_tx stat incremental
+    - net/sched: act_ct: Fix skb double-free in tcf_ct_handle_fragments() error
+      flow
+    - ipvlan: fix device features
+    - ALSA: pci: delete repeated words in comments
+    - ASoC: img: Fix a reference count leak in img_i2s_in_set_fmt
+    - ASoC: img-parallel-out: Fix a reference count leak
+    - ASoC: tegra: Fix reference count leaks.
+    - mfd: intel-lpss: Add Intel Emmitsburg PCH PCI IDs
+    - arm64: dts: qcom: msm8916: Pull down PDM GPIOs during sleep
+    - powerpc/xive: Ignore kmemleak false positives
+    - media: pci: ttpci: av7110: fix possible buffer overflow caused by bad DMA
+      value in debiirq()
+    - blktrace: ensure our debugfs dir exists
+    - scsi: target: tcmu: Fix crash on ARM during cmd completion
+    - mfd: intel-lpss: Add Intel Tiger Lake PCH-H PCI IDs
+    - iommu/iova: Don't BUG on invalid PFNs
+    - 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
+    - xfs: Don't allow logging of XFS_ISTALE inodes
+    - scsi: target: Fix xcopy sess release leak
+    - selftests/powerpc: Purge extra count_pmc() calls of ebb selftests
+    - f2fs: fix error path in do_recover_data()
+    - omapfb: fix multiple reference count leaks due to pm_runtime_get_sync
+    - PCI: Fix pci_create_slot() reference count leak
+    - ARM: dts: ls1021a: output PPS signal on FIPER2
+    - rtlwifi: rtl8192cu: Prevent leaking urb
+    - mips/vdso: Fix resource leaks in genvdso.c
+    - cec-api: prevent leaking memory through hole in structure
+    - HID: quirks: add NOGET quirk for Logitech GROUP
+    - f2fs: fix use-after-free issue
+    - drm/nouveau/drm/noveau: fix reference count leak in nouveau_fbcon_open
+    - drm/nouveau: fix reference count leak in nv50_disp_atomic_commit
+    - drm/nouveau: Fix reference count leak in nouveau_connector_detect
+    - locking/lockdep: Fix overflow in presentation of average lock-time
+    - btrfs: file: reserve qgroup space after the hole punch range is locked
+    - btrfs: make btrfs_qgroup_check_reserved_leak take btrfs_inode
+    - scsi: iscsi: Do not put host in iscsi_set_flashnode_param()
+    - ceph: fix potential mdsc use-after-free crash
+    - ceph: do not access the kiocb after aio requests
+    - scsi: fcoe: Memory leak fix in fcoe_sysfs_fcf_del()
+    - EDAC/ie31200: Fallback if host bridge device is already initialized
+    - hugetlbfs: prevent filesystem stacking of hugetlbfs
+    - media: davinci: vpif_capture: fix potential double free
+    - KVM: arm64: Fix symbol dependency in __hyp_call_panic_nvhe
+    - powerpc/spufs: add CONFIG_COREDUMP dependency
+    - USB: sisusbvga: Fix a potential UB casued by left shifting a negative value
+    - brcmfmac: Set timeout value when configuring power save
+    - efi: provide empty efi_enter_virtual_mode implementation
+    - arm64: Fix __cpu_logical_map undefined issue
+    - Revert "ath10k: fix DMA related firmware crashes on multiple devices"
+    - sched/uclamp: Protect uclamp fast path code with static key
+    - sched/uclamp: Fix a deadlock when enabling uclamp static key
+    - usb: cdns3: gadget: always zeroed TRB buffer when enable endpoint
+    - PM / devfreq: rk3399_dmc: Add missing of_node_put()
+    - PM / devfreq: rk3399_dmc: Disable devfreq-event device when fails
+    - PM / devfreq: rk3399_dmc: Fix kernel oops when rockchip,pmu is absent
+    - drm/xen: fix passing zero to 'PTR_ERR' warning
+    - drm/xen-front: Fix misused IS_ERR_OR_NULL checks
+    - s390/numa: set node distance to LOCAL_DISTANCE
+    - btrfs: factor out inode items copy loop from btrfs_log_inode()
+    - btrfs: only commit the delayed inode when doing a full fsync
+    - btrfs: only commit delayed items at fsync if we are logging a directory
+    - mm/shuffle: don't move pages between zones and don't read garbage memmaps
+    - mm: fix kthread_use_mm() vs TLB invalidate
+    - mm/cma.c: switch to bitmap_zalloc() for cma bitmap allocation
+    - cma: don't quit at first error when activating reserved areas
+    - gpu/drm: ingenic: Use the plane's src_[x,y] to configure DMA length
+    - drm/ingenic: Fix incorrect assumption about plane->index
+    - drm/amd/display: Trigger modesets on MST DSC connectors
+    - drm/amd/display: Add additional config guards for DCN
+    - drm/amd/display: Fix dmesg warning from setting abm level
+    - mm/vunmap: add cond_resched() in vunmap_pmd_range
+    - EDAC: sb_edac: get rid of unused vars
+    - EDAC: skx_common: get rid of unused type var
+    - EDAC/{i7core,sb,pnd2,skx}: Fix error event severity
+    - PCI: qcom: Add missing ipq806x clocks in PCIe driver
+    - PCI: qcom: Change duplicate PCI reset to phy reset
+    - PCI: qcom: Add missing reset for ipq806x
+    - cpufreq: intel_pstate: Fix EPP setting via sysfs in active mode
+    - ALSA: usb-audio: Add capture support for Saffire 6 (USB 1.1)
+    - media: gpio-ir-tx: improve precision of transmitted signal due to scheduling
+    - block: respect queue limit of max discard segment
+    - block: virtio_blk: fix handling single range discard request
+    - drm/msm/adreno: fix updating ring fence
+    - block: Fix page_is_mergeable() for compound pages
+    - bfq: fix blkio cgroup leakage v4
+    - hwmon: (nct7904) Correct divide by 0
+    - blk-mq: insert request not through ->queue_rq into sw/scheduler queue
+    - blkcg: fix memleak for iolatency
+    - nvme-fc: Fix wrong return value in __nvme_fc_init_request()
+    - nvme: multipath: round-robin: fix single non-optimized path case
+    - null_blk: fix passing of REQ_FUA flag in null_handle_rq
+    - i2c: core: Don't fail PRP0001 enumeration when no ID table exist
+    - i2c: rcar: in slave mode, clear NACK earlier
+    - usb: gadget: f_tcm: Fix some resource leaks in some error paths
+    - spi: stm32: clear only asserted irq flags on interrupt
+    - jbd2: make sure jh have b_transaction set in refile/unfile_buffer
+    - ext4: don't BUG on inconsistent journal feature
+    - ext4: handle read only external journal device
+    - jbd2: abort journal if free a async write error metadata buffer
+    - ext4: handle option set by mount flags correctly
+    - ext4: handle error of ext4_setup_system_zone() on remount
+    - ext4: correctly restore system zone info when remount fails
+    - fs: prevent BUG_ON in submit_bh_wbc()
+    - spi: stm32h7: fix race condition at end of transfer
+    - spi: stm32: fix fifo threshold level in case of short transfer
+    - spi: stm32: fix stm32_spi_prepare_mbr in case of odd clk_rate
+    - spi: stm32: always perform registers configuration prior to transfer
+    - drm/amd/powerplay: correct Vega20 cached smu feature state
+    - drm/amd/powerplay: correct UVD/VCE PG state on custom pptable uploading
+    - drm/amd/display: Switch to immediate mode for updating infopackets
+    - netfilter: avoid ipv6 -> nf_defrag_ipv6 module dependency
+    - can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to detect
+      corruptions
+    - ALSA: hda/realtek: Add model alc298-samsung-headphone
+    - s390/cio: add cond_resched() in the slow_eval_known_fn() loop
+    - ASoC: wm8994: Avoid attempts to read unreadable registers
+    - selftests: disable rp_filter for icmp_redirect.sh
+    - scsi: fcoe: Fix I/O path allocation
+    - scsi: ufs: Fix possible infinite loop in ufshcd_hold
+    - scsi: ufs: Improve interrupt handling for shared interrupts
+    - scsi: ufs: Clean up completed request without interrupt notification
+    - scsi: qla2xxx: Fix login timeout
+    - scsi: qla2xxx: Check if FW supports MQ before enabling
+    - scsi: qla2xxx: Fix null pointer access during disconnect from subsystem
+    - Revert "scsi: qla2xxx: Fix crash on qla2x00_mailbox_command"
+    - macvlan: validate setting of multiple remote source MAC addresses
+    - net: gianfar: Add of_node_put() before goto statement
+    - powerpc/perf: Fix soft lockups due to missed interrupt accounting
+    - arm64: Move handling of erratum 1418040 into C code
+    - arm64: Allow booting of late CPUs affected by erratum 1418040
+    - block: fix get_max_io_size()
+    - block: loop: set discard granularity and alignment for block device backed
+      loop
+    - HID: i2c-hid: Always sleep 60ms after I2C_HID_PWR_ON commands
+    - blk-mq: order adding requests to hctx->dispatch and checking SCHED_RESTART
+    - btrfs: reset compression level for lzo on remount
+    - btrfs: check the right error variable in btrfs_del_dir_entries_in_log
+    - btrfs: fix space cache memory leak after transaction abort
+    - btrfs: detect nocow for swap after snapshot delete
+    - 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: Fix oops on -EPROBE_DEFER
+    - serial: pl011: Don't leak amba_ports entry on driver register error
+    - serial: stm32: avoid kernel warning on absence of optional IRQ
+    - serial: 8250_exar: Fix number of ports for Commtech PCIe cards
+    - 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.
+    - usb: host: xhci: fix ep context print mismatch in debugfs
+    - xhci: Do warm-reset when both CAS and XDEV_RESUME are set
+    - xhci: Always restore EP_SOFT_CLEAR_TOGGLE even if ep reset failed
+    - ARM64: vdso32: Install vdso32 from vdso_install
+    - arm64: vdso32: make vdso32 install conditional
+    - PM: sleep: core: Fix the handling of pending runtime resume requests
+    - powerpc/perf: Fix crashes with generic_compat_pmu & BHRB
+    - device property: Fix the secondary firmware node handling in
+      set_primary_fwnode()
+    - crypto: af_alg - Work around empty control messages without MSG_MORE
+    - genirq/matrix: Deal with the sillyness of for_each_cpu() on UP
+    - irqchip/stm32-exti: Avoid losing interrupts due to clearing pending bits by
+      mistake
+    - x86/hotplug: Silence APIC only after all interrupts are migrated
+    - drm/amdgpu: Fix buffer overflow in INFO ioctl
+    - drm/amdgpu/gfx10: refine mgcg setting
+    - drm/amd/powerplay: Fix hardmins not being sent to SMU for RV
+    - drm/amd/pm: correct Vega10 swctf limit setting
+    - drm/amd/pm: correct Vega12 swctf limit setting
+    - drm/amd/pm: correct Vega20 swctf limit setting
+    - drm/amd/pm: correct the thermal alert temperature limit settings
+    - USB: yurex: Fix bad gfp argument
+    - usb: uas: Add quirk for PNY Pro Elite
+    - USB: quirks: Ignore duplicate endpoint on Sound Devices MixPre-D
+    - USB: Ignore UAS for JMicron JMS567 ATA/ATAPI Bridge
+    - usb: host: ohci-exynos: Fix error handling in exynos_ohci_probe()
+    - USB: gadget: u_f: add overflow checks to VLA macros
+    - USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()
+    - USB: gadget: u_f: Unbreak offset calculation in VLAs
+    - USB: cdc-acm: rework notification_buffer resizing
+    - usb: storage: Add unusual_uas entry for Sony PSZ drives
+    - drm/i915: Fix cmd parser desc matching with masks
+    - usb: dwc3: gadget: Don't setup more than requested
+    - usb: dwc3: gadget: Fix handling ZLP
+    - usb: dwc3: gadget: Handle ZLP for sg requests
+    - fbmem: pull fbcon_update_vcs() out of fb_set_var()
+    - kheaders: remove unneeded 'cat' command piped to 'head' / 'tail'
+    - kheaders: optimize md5sum calculation for in-tree builds
+    - kheaders: optimize header copy for in-tree builds
+    - kheaders: remove the last bashism to allow sh to run it
+    - kheaders: explain why include/config/autoconf.h is excluded from md5sum
+    - kbuild: add variables for compression tools
+    - kbuild: fix broken builds because of GZIP,BZIP2,LZOP variables
+    - HID: hiddev: Fix slab-out-of-bounds write in hiddev_ioctl_usage()
+    - ALSA: usb-audio: Update documentation comment for MS2109 quirk
+    - io_uring: Fix NULL pointer dereference in io_sq_wq_submit_work()
+    - Linux 5.4.62
+
+  * DELL LATITUDE 5491 touchscreen doesn't work (LP: #1889446) // Focal update:
+    v5.4.62 upstream stable release (LP: #1895174)
+    - USB: quirks: Add no-lpm quirk for another Raydium touchscreen
+
+  * [NUC8CCHK][HDA-Intel - HDA Intel PCH, playback] No sound at all
+    (LP: #1875199) // Focal update: v5.4.62 upstream stable release
+    (LP: #1895174)
+    - ALSA: hda/realtek: Fix pin default on Intel NUC 8 Rugged
+
+  * Focal update: v5.4.61 upstream stable release (LP: #1893115)
+    - Documentation/llvm: add documentation on building w/ Clang/LLVM
+    - Documentation/llvm: fix the name of llvm-size
+    - net: wan: wanxl: use allow to pass CROSS_COMPILE_M68k for rebuilding
+      firmware
+    - net: wan: wanxl: use $(M68KCC) instead of $(M68KAS) for rebuilding firmware
+    - x86/boot: kbuild: allow readelf executable to be specified
+    - kbuild: remove PYTHON2 variable
+    - kbuild: remove AS variable
+    - kbuild: replace AS=clang with LLVM_IAS=1
+    - kbuild: support LLVM=1 to switch the default tools to Clang/LLVM
+    - drm/vgem: Replace opencoded version of drm_gem_dumb_map_offset()
+    - gfs2: Improve mmap write vs. punch_hole consistency
+    - gfs2: Never call gfs2_block_zero_range with an open transaction
+    - perf probe: Fix memory leakage when the probe point is not found
+    - khugepaged: khugepaged_test_exit() check mmget_still_valid()
+    - khugepaged: adjust VM_BUG_ON_MM() in __khugepaged_enter()
+    - bcache: avoid nr_stripes overflow in bcache_device_init()
+    - btrfs: export helpers for subvolume name/id resolution
+    - btrfs: don't show full path of bind mounts in subvol=
+    - btrfs: return EROFS for BTRFS_FS_STATE_ERROR cases
+    - btrfs: add wrapper for transaction abort predicate
+    - ALSA: hda/realtek: Add quirk for Samsung Galaxy Flex Book
+    - ALSA: hda/realtek: Add quirk for Samsung Galaxy Book Ion
+    - can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in
+      j1939_tp_txtimer()
+    - can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated
+    - [Config] update config for SPI_DYNAMIC
+    - spi: Prevent adding devices below an unregistering controller
+    - romfs: fix uninitialized memory leak in romfs_dev_read()
+    - kernel/relay.c: fix memleak on destroy relay channel
+    - uprobes: __replace_page() avoid BUG in munlock_vma_page()
+    - mm: include CMA pages in lowmem_reserve at boot
+    - mm, page_alloc: fix core hung in free_pcppages_bulk()
+    - RDMA/hfi1: Correct an interlock issue for TID RDMA WRITE request
+    - ext4: fix checking of directory entry validity for inline directories
+    - jbd2: add the missing unlock_buffer() in the error path of
+      jbd2_write_superblock()
+    - scsi: zfcp: Fix use-after-free in request timeout handlers
+    - drm/amdgpu/display: use GFP_ATOMIC in dcn20_validate_bandwidth_internal
+    - drm/amd/display: Fix EDID parsing after resume from suspend
+    - drm/amd/display: fix pow() crashing when given base 0
+    - kthread: Do not preempt current task if it is going to call schedule()
+    - opp: Enable resources again if they were disabled earlier
+    - scsi: ufs: Add DELAY_BEFORE_LPM quirk for Micron devices
+    - scsi: target: tcmu: Fix crash in tcmu_flush_dcache_range on ARM
+    - media: budget-core: Improve exception handling in budget_register()
+    - rtc: goldfish: Enable interrupt in set_alarm() when necessary
+    - media: vpss: clean up resources in init
+    - Input: psmouse - add a newline when printing 'proto' by sysfs
+    - MIPS: Fix unable to reserve memory for Crash kernel
+    - m68knommu: fix overwriting of bits in ColdFire V3 cache control
+    - svcrdma: Fix another Receive buffer leak
+    - xfs: fix inode quota reservation checks
+    - drm/ttm: fix offset in VMAs with a pg_offs in ttm_bo_vm_access
+    - jffs2: fix UAF problem
+    - ceph: fix use-after-free for fsc->mdsc
+    - swiotlb-xen: use vmalloc_to_page on vmalloc virt addresses
+    - cpufreq: intel_pstate: Fix cpuinfo_max_freq when MSR_TURBO_RATIO_LIMIT is 0
+    - scsi: libfc: Free skb in fc_disc_gpn_id_resp() for valid cases
+    - virtio_ring: Avoid loop when vq is broken in virtqueue_poll
+    - media: camss: fix memory leaks on error handling paths in probe
+    - tools/testing/selftests/cgroup/cgroup_util.c: cg_read_strcmp: fix null
+      pointer dereference
+    - xfs: Fix UBSAN null-ptr-deref in xfs_sysfs_init
+    - alpha: fix annotation of io{read,write}{16,32}be()
+    - fs/signalfd.c: fix inconsistent return codes for signalfd4
+    - ext4: fix potential negative array index in do_split()
+    - ext4: don't allow overlapping system zones
+    - netfilter: nf_tables: nft_exthdr: the presence return value should be
+      little-endian
+    - spi: stm32: fixes suspend/resume management
+    - ASoC: q6afe-dai: mark all widgets registers as SND_SOC_NOPM
+    - ASoC: q6routing: add dummy register read/write function
+    - bpf: sock_ops sk access may stomp registers when dst_reg = src_reg
+    - can: j1939: fix kernel-infoleak in j1939_sk_sock2sockaddr_can()
+    - can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send
+      not by J1939 stack
+    - can: j1939: transport: add j1939_session_skb_find_by_offset() function
+    - i40e: Set RX_ONLY mode for unicast promiscuous on VLAN
+    - i40e: Fix crash during removing i40e driver
+    - net: fec: correct the error path for regulator disable in probe
+    - bonding: show saner speed for broadcast mode
+    - can: j1939: fix support for multipacket broadcast message
+    - can: j1939: cancel rxtimer on multipacket broadcast session complete
+    - can: j1939: abort multipacket broadcast session when timeout occurs
+    - can: j1939: add rxtimer for multipacket broadcast session
+    - bonding: fix a potential double-unregister
+    - s390/runtime_instrumentation: fix storage key handling
+    - s390/ptrace: fix storage key handling
+    - ASoC: msm8916-wcd-analog: fix register Interrupt offset
+    - ASoC: intel: Fix memleak in sst_media_open
+    - vfio/type1: Add proper error unwind for vfio_iommu_replay()
+    - kvm: x86: Toggling CR4.SMAP does not load PDPTEs in PAE mode
+    - kvm: x86: Toggling CR4.PKE does not load PDPTEs in PAE mode
+    - Revert "scsi: qla2xxx: Disable T10-DIF feature with FC-NVMe during probe"
+    - kconfig: qconf: do not limit the pop-up menu to the first row
+    - kconfig: qconf: fix signal connection to invalid slots
+    - efi: avoid error message when booting under Xen
+    - Fix build error when CONFIG_ACPI is not set/enabled:
+    - RDMA/bnxt_re: Do not add user qps to flushlist
+    - afs: Fix NULL deref in afs_dynroot_depopulate()
+    - bonding: fix active-backup failover for current ARP slave
+    - net: ena: Prevent reset after device destruction
+    - net: gemini: Fix missing free_netdev() in error path of
+      gemini_ethernet_port_probe()
+    - hv_netvsc: Fix the queue_mapping in netvsc_vf_xmit()
+    - net: dsa: b53: check for timeout
+    - powerpc/pseries: Do not initiate shutdown when system is running on UPS
+    - efi: add missed destroy_workqueue when efisubsys_init fails
+    - 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
+    - KVM: Pass MMU notifier range flags to kvm_unmap_hva_range()
+    - KVM: arm64: Only reschedule if MMU_NOTIFIER_RANGE_BLOCKABLE is not set
+    - Linux 5.4.61
+
+  * [UBUNTU 20.04] zPCI device hot-plug during boot may result in unusable
+    device (LP: #1893778)
+    - s390/pci: ignore stale configuration request event
+
+  * [SRU] [Focal/OEM-5.6/Groovy]Fix AMD usb host controller lost after stress S3
+    (LP: #1893914)
+    - SAUCE: xhci: workaround for S3 issue on AMD SNPS 3.0 xHC
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 18 Sep 2020 10:17:00 +0200
+
+linux (5.4.0-48.52) focal; urgency=medium
+
+  * focal/linux: 5.4.0-48.52 -proposed tracker (LP: #1894654)
+
+  * mm/slub kernel oops on focal kernel 5.4.0-45 (LP: #1895109)
+    - SAUCE: Revert "mm/slub: fix a memory leak in sysfs_slab_add()"
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+    - update dkms package versions
+
+  * Introduce the new NVIDIA 450-server and the 450 UDA series (LP: #1887674)
+    - [packaging] add signed modules for nvidia 450 and 450-server
+
+  * [UBUNTU 20.04] zPCI attach/detach issues with PF/VF linking support
+    (LP: #1892849)
+    - s390/pci: fix zpci_bus_link_virtfn()
+    - s390/pci: re-introduce zpci_remove_device()
+    - s390/pci: fix PF/VF linking on hot plug
+
+  * [UBUNTU 20.04] kernel: s390/cpum_cf,perf: changeDFLT_CCERROR counter name
+    (LP: #1891454)
+    - s390/cpum_cf, perf: change DFLT_CCERROR counter name
+
+  * [UBUNTU 20.04] zPCI: Enabling of a reserved PCI function regression
+    introduced by multi-function support (LP: #1891437)
+    - s390/pci: fix enabling a reserved PCI function
+
+  * 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
+
+  *  [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
+
+  * alsa/hdmi: support nvidia mst hdmi/dp audio (LP: #1867704)
+    - ALSA: hda - Rename snd_hda_pin_sense to snd_hda_jack_pin_sense
+    - ALSA: hda - Add DP-MST jack support
+    - ALSA: hda - Add DP-MST support for non-acomp codecs
+    - ALSA: hda - Add DP-MST support for NVIDIA codecs
+    - ALSA: hda: hdmi - fix regression in connect list handling
+    - ALSA: hda: hdmi - fix kernel oops caused by invalid PCM idx
+    - ALSA: hda: hdmi - preserve non-MST PCM routing for Intel platforms
+    - ALSA: hda: hdmi - Keep old slot assignment behavior for Intel platforms
+    - ALSA: hda - Fix DP-MST support for NVIDIA codecs
+
+  * Focal update: v5.4.60 upstream stable release (LP: #1892899)
+    - smb3: warn on confusing error scenario with sec=krb5
+    - genirq/affinity: Make affinity setting if activated opt-in
+    - genirq/PM: Always unlock IRQ descriptor in rearm_wake_irq()
+    - PCI: hotplug: ACPI: Fix context refcounting in acpiphp_grab_context()
+    - PCI: Add device even if driver attach failed
+    - PCI: qcom: Define some PARF params needed for ipq8064 SoC
+    - PCI: qcom: Add support for tx term offset for rev 2.1.0
+    - btrfs: allow use of global block reserve for balance item deletion
+    - btrfs: free anon block device right after subvolume deletion
+    - btrfs: don't allocate anonymous block device for user invisible roots
+    - btrfs: ref-verify: fix memory leak in add_block_entry
+    - btrfs: stop incremening log_batch for the log root tree when syncing log
+    - btrfs: remove no longer needed use of log_writers for the log root tree
+    - btrfs: don't traverse into the seed devices in show_devname
+    - btrfs: open device without device_list_mutex
+    - btrfs: move the chunk_mutex in btrfs_read_chunk_tree
+    - btrfs: relocation: review the call sites which can be interrupted by signal
+    - btrfs: add missing check for nocow and compression inode flags
+    - btrfs: avoid possible signal interruption of btrfs_drop_snapshot() on
+      relocation tree
+    - btrfs: sysfs: use NOFS for device creation
+    - btrfs: don't WARN if we abort a transaction with EROFS
+    - btrfs: fix race between page release and a fast fsync
+    - btrfs: fix messages after changing compression level by remount
+    - btrfs: only search for left_info if there is no right_info in
+      try_merge_free_space
+    - btrfs: inode: fix NULL pointer dereference if inode doesn't need compression
+    - btrfs: fix memory leaks after failure to lookup checksums during inode
+      logging
+    - btrfs: make sure SB_I_VERSION doesn't get unset by remount
+    - btrfs: fix return value mixup in btrfs_get_extent
+    - arm64: perf: Correct the event index in sysfs
+    - dt-bindings: iio: io-channel-mux: Fix compatible string in example code
+    - iio: dac: ad5592r: fix unbalanced mutex unlocks in ad5592r_read_raw()
+    - xtensa: add missing exclusive access state management
+    - xtensa: fix xtensa_pmu_setup prototype
+    - cifs: Fix leak when handling lease break for cached root fid
+    - powerpc/ptdump: Fix build failure in hashpagetable.c
+    - powerpc: Allow 4224 bytes of stack expansion for the signal frame
+    - powerpc: Fix circular dependency between percpu.h and mmu.h
+    - pinctrl: ingenic: Enhance support for IRQ_TYPE_EDGE_BOTH
+    - media: vsp1: dl: Fix NULL pointer dereference on unbind
+    - net: ethernet: stmmac: Disable hardware multicast filter
+    - net: stmmac: dwmac1000: provide multicast filter fallback
+    - net/compat: Add missing sock updates for SCM_RIGHTS
+    - md/raid5: Fix Force reconstruct-write io stuck in degraded raid5
+    - bcache: allocate meta data pages as compound pages
+    - bcache: fix overflow in offset_to_stripe()
+    - mac80211: fix misplaced while instead of if
+    - driver core: Avoid binding drivers to dead devices
+    - MIPS: CPU#0 is not hotpluggable
+    - MIPS: qi_lb60: Fix routing to audio amplifier
+    - ext2: fix missing percpu_counter_inc
+    - khugepaged: collapse_pte_mapped_thp() flush the right range
+    - khugepaged: collapse_pte_mapped_thp() protect the pmd lock
+    - ocfs2: change slot number type s16 to u16
+    - mm/page_counter.c: fix protection usage propagation
+    - mm/memory_hotplug: fix unpaired mem_hotplug_begin/done
+    - ftrace: Setup correct FTRACE_FL_REGS flags for module
+    - kprobes: Fix NULL pointer dereference at kprobe_ftrace_handler
+    - tracing/hwlat: Honor the tracing_cpumask
+    - tracing: Use trace_sched_process_free() instead of exit() for pid tracing
+    - tracing: Move pipe reference to trace array instead of current_tracer
+    - watchdog: f71808e_wdt: indicate WDIOF_CARDRESET support in
+      watchdog_info.options
+    - watchdog: f71808e_wdt: remove use of wrong watchdog_info option
+    - watchdog: f71808e_wdt: clear watchdog timeout occurred flag
+    - ceph: set sec_context xattr on symlink creation
+    - ceph: handle zero-length feature mask in session messages
+    - pseries: Fix 64 bit logical memory block panic
+    - module: Correctly truncate sysfs sections output
+    - perf intel-pt: Fix FUP packet state
+    - perf intel-pt: Fix duplicate branch after CBR
+    - remoteproc: qcom: q6v5: Update running state before requesting stop
+    - remoteproc: qcom_q6v5_mss: Validate MBA firmware size before load
+    - remoteproc: qcom_q6v5_mss: Validate modem blob firmware size before load
+    - drm/imx: imx-ldb: Disable both channels for split mode in enc->disable()
+    - orangefs: get rid of knob code...
+    - pinctrl: ingenic: Properly detect GPIO direction when configured for IRQ
+    - crypto: algif_aead - Only wake up when ctx->more is zero
+    - mfd: arizona: Ensure 32k clock is put on driver unbind and error
+    - octeontx2-af: change (struct qmem)->entry_sz from u8 to u16
+    - mtd: rawnand: fsl_upm: Remove unused mtd var
+    - platform/chrome: cros_ec_ishtp: Fix a double-unlock issue
+    - RDMA/ipoib: Return void from ipoib_ib_dev_stop()
+    - RDMA/ipoib: Fix ABBA deadlock with ipoib_reap_ah()
+    - media: rockchip: rga: Introduce color fmt macros and refactor CSC mode logic
+    - media: rockchip: rga: Only set output CSC mode for RGB input
+    - IB/uverbs: Set IOVA on IB MR in uverbs layer
+    - selftests/bpf: Test_progs indicate to shell on non-actions
+    - selftests/bpf: test_progs use another shell exit on non-actions
+    - USB: serial: ftdi_sio: make process-packet buffer unsigned
+    - USB: serial: ftdi_sio: clean up receive processing
+    - crypto: af_alg - Fix regression on empty requests
+    - devres: keep both device name and resource name in pretty name
+    - RDMA/counter: Only bind user QPs in auto mode
+    - RDMA/counter: Allow manually bind QPs with different pids to same counter
+    - mmc: renesas_sdhi_internal_dmac: clean up the code for dma complete
+    - crypto: caam - Remove broken arc4 support
+    - gpu: ipu-v3: image-convert: Combine rotate/no-rotate irq handlers
+    - gpu: ipu-v3: image-convert: Wait for all EOFs before completing a tile
+    - dm rq: don't call blk_mq_queue_stopped() in dm_stop_queue()
+    - clk: actions: Fix h_clk for Actions S500 SoC
+    - selftests/powerpc: ptrace-pkey: Rename variables to make it easier to follow
+      code
+    - selftests/powerpc: ptrace-pkey: Update the test to mark an invalid pkey
+      correctly
+    - selftests/powerpc: ptrace-pkey: Don't update expected UAMOR value
+    - iommu/omap: Check for failure of a call to omap_iommu_dump_ctx
+    - clk: qcom: gcc: fix sm8150 GPU and NPU clocks
+    - clk: qcom: clk-alpha-pll: remove unused/incorrect PLL_CAL_VAL
+    - iommu/vt-d: Enforce PASID devTLB field mask
+    - i2c: rcar: slave: only send STOP event when we have been addressed
+    - clk: qcom: gcc-sdm660: Fix up gcc_mss_mnoc_bimc_axi_clk
+    - clk: clk-atlas6: fix return value check in atlas6_clk_init()
+    - pwm: bcm-iproc: handle clk_get_rate() return
+    - tools build feature: Use CC and CXX from parent
+    - i2c: rcar: avoid race when unregistering slave
+    - nfs: ensure correct writeback errors are returned on close()
+    - ubifs: Fix wrong orphan node deletion in ubifs_jnl_update|rename
+    - clk: bcm2835: Do not use prediv with bcm2711's PLLs
+    - libnvdimm/security: fix a typo
+    - libnvdimm/security: ensure sysfs poll thread woke up and fetch updated attr
+    - openrisc: Fix oops caused when dumping stack
+    - scsi: lpfc: nvmet: Avoid hang / use-after-free again when destroying
+      targetport
+    - nfs: nfs_file_write() should check for writeback errors
+    - watchdog: initialize device before misc_register
+    - md-cluster: Fix potential error pointer dereference in resize_bitmaps()
+    - x86/tsr: Fix tsc frequency enumeration bug on Lightning Mountain SoC
+    - Input: sentelic - fix error return when fsp_reg_write fails
+    - recordmcount: Fix build failure on non arm64
+    - drm/vmwgfx: Use correct vmw_legacy_display_unit pointer
+    - drm/vmwgfx: Fix two list_for_each loop exit tests
+    - net: qcom/emac: add missed clk_disable_unprepare in error path of
+      emac_clks_phase1_init
+    - nfs: Fix getxattr kernel panic and memory overflow
+    - fs/minix: set s_maxbytes correctly
+    - fs/minix: fix block limit check for V1 filesystems
+    - fs/minix: remove expected error message in block_to_path()
+    - fs/ufs: avoid potential u32 multiplication overflow
+    - test_kmod: avoid potential double free in trigger_config_run_type()
+    - i2c: iproc: fix race between client unreg and isr
+    - mfd: dln2: Run event handler loop under spinlock
+    - crypto: algif_aead - fix uninitialized ctx->init
+    - ALSA: echoaudio: Fix potential Oops in snd_echo_resume()
+    - perf bench mem: Always memset source before memcpy
+    - tools build feature: Quote CC and CXX for their arguments
+    - perf/x86/rapl: Fix missing psys sysfs attributes
+    - sh: landisk: Add missing initialization of sh_io_port_base
+    - khugepaged: retract_page_tables() remember to test exit
+    - arm64: dts: marvell: espressobin: add ethernet alias
+    - drm/panfrost: Use kvfree() to free bo->sgts
+    - drm: Added orientation quirk for ASUS tablet model T103HAF
+    - drm: fix drm_dp_mst_port refcount leaks in drm_dp_mst_allocate_vcpi
+    - drm/amdgpu: Fix bug where DPM is not enabled after hibernate and resume
+    - drm/amd/display: dchubbub p-state warning during surface planes switch
+    - Linux 5.4.60
+    - kprobes: Fix compiler warning for !CONFIG_KPROBES_ON_FTRACE
+
+  * Focal update: v5.4.59 upstream stable release (LP: #1892417)
+    - tracepoint: Mark __tracepoint_string's __used
+    - HID: input: Fix devices that return multiple bytes in battery report
+    - nvme: add a Identify Namespace Identification Descriptor list quirk
+    - fs/io_uring.c: Fix uninitialized variable is referenced in io_submit_sqe
+    - clk: qcom: clk-rpmh: Wait for completion when enabling clocks
+    - x86/mce/inject: Fix a wrong assignment of i_mce.status
+    - sched/fair: Fix NOHZ next idle balance
+    - sched: correct SD_flags returned by tl->sd_flags()
+    - arm64: dts: rockchip: fix rk3368-lion gmac reset gpio
+    - arm64: dts: rockchip: fix rk3399-puma vcc5v0-host gpio
+    - arm64: dts: rockchip: fix rk3399-puma gmac reset gpio
+    - EDAC: Fix reference count leaks
+    - crc-t10dif: Fix potential crypto notify dead-lock
+    - arm64: dts: qcom: msm8916: Replace invalid bias-pull-none property
+    - crypto: ccree - fix resource leak on error path
+    - ARM: exynos: MCPM: Restore big.LITTLE cpuidle support
+    - firmware: arm_scmi: Fix SCMI genpd domain probing
+    - arm64: dts: exynos: Fix silent hang after boot on Espresso
+    - sched/uclamp: Fix initialization of struct uclamp_rq
+    - clk: scmi: Fix min and max rate when registering clocks with discrete rates
+    - m68k: mac: Don't send IOP message until channel is idle
+    - m68k: mac: Fix IOP status/control register writes
+    - platform/x86: intel-hid: Fix return value check in check_acpi_dev()
+    - platform/x86: intel-vbtn: Fix return value check in check_acpi_dev()
+    - ARM: dts: gose: Fix ports node name for adv7180
+    - ARM: dts: gose: Fix ports node name for adv7612
+    - ARM: at91: pm: add missing put_device() call in at91_pm_sram_init()
+    - ARM: dts: sunxi: bananapi-m2-plus-v1.2: Add regulator supply to all CPU
+      cores
+    - ARM: dts: sunxi: bananapi-m2-plus-v1.2: Fix CPU supply voltages
+    - spi: lantiq: fix: Rx overflow error in full duplex mode
+    - tpm: Require that all digests are present in TCG_PCR_EVENT2 structures
+    - recordmcount: only record relocation of type R_AARCH64_CALL26 on arm64.
+    - regulator: fix memory leak on error path of regulator_register()
+    - io_uring: fix sq array offset calculation
+    - spi: rockchip: Fix error in SPI slave pio read
+    - ARM: socfpga: PM: add missing put_device() call in
+      socfpga_setup_ocram_self_refresh()
+    - iocost: Fix check condition of iocg abs_vdebt
+    - irqchip/ti-sci-inta: Fix return value about devm_ioremap_resource()
+    - seccomp: Fix ioctl number for SECCOMP_IOCTL_NOTIF_ID_VALID
+    - md: raid0/linear: fix dereference before null check on pointer mddev
+    - nvme-tcp: fix controller reset hang during traffic
+    - nvme-rdma: fix controller reset hang during traffic
+    - nvme-multipath: fix logic for non-optimized paths
+    - nvme-multipath: do not fall back to __nvme_find_path() for non-optimized
+      paths
+    - drm/tilcdc: fix leak & null ref in panel_connector_get_modes
+    - soc: qcom: rpmh-rsc: Set suppress_bind_attrs flag
+    - Bluetooth: add a mutex lock to avoid UAF in do_enale_set
+    - loop: be paranoid on exit and prevent new additions / removals
+    - fs/btrfs: Add cond_resched() for try_release_extent_mapping() stalls
+    - drm/amdgpu: avoid dereferencing a NULL pointer
+    - drm/radeon: Fix reference count leaks caused by pm_runtime_get_sync
+    - crypto: aesni - Fix build with LLVM_IAS=1
+    - video: fbdev: savage: fix memory leak on error handling path in probe
+    - video: fbdev: neofb: fix memory leak in neo_scan_monitor()
+    - bus: ti-sysc: Add missing quirk flags for usb_host_hs
+    - md-cluster: fix wild pointer of unlock_all_bitmaps()
+    - drm/nouveau/kms/nv50-: Fix disabling dithering
+    - arm64: dts: hisilicon: hikey: fixes to comply with adi, adv7533 DT binding
+    - drm/etnaviv: fix ref count leak via pm_runtime_get_sync
+    - drm/nouveau: fix reference count leak in nouveau_debugfs_strap_peek
+    - drm/nouveau: fix multiple instances of reference count leaks
+    - mmc: sdhci-cadence: do not use hardware tuning for SD mode
+    - btrfs: fix lockdep splat from btrfs_dump_space_info
+    - usb: mtu3: clear dual mode of u3port when disable device
+    - drm: msm: a6xx: fix gpu failure after system resume
+    - drm/msm: Fix a null pointer access in msm_gem_shrinker_count()
+    - drm/debugfs: fix plain echo to connector "force" attribute
+    - drm/radeon: disable AGP by default
+    - irqchip/irq-mtk-sysirq: Replace spinlock with raw_spinlock
+    - mm/mmap.c: Add cond_resched() for exit_mmap() CPU stalls
+    - drm/amdgpu/display bail early in dm_pp_get_static_clocks
+    - drm/amd/powerplay: fix compile error with ARCH=arc
+    - bpf: Fix fds_example SIGSEGV error
+    - brcmfmac: keep SDIO watchdog running when console_interval is non-zero
+    - brcmfmac: To fix Bss Info flag definition Bug
+    - brcmfmac: set state of hanger slot to FREE when flushing PSQ
+    - platform/x86: asus-nb-wmi: add support for ASUS ROG Zephyrus G14 and G15
+    - iwlegacy: Check the return value of pcie_capability_read_*()
+    - gpu: host1x: debug: Fix multiple channels emitting messages simultaneously
+    - ionic: update eid test for overflow
+    - mmc: sdhci-pci-o2micro: Bug fix for O2 host controller Seabird1
+    - usb: gadget: net2280: fix memory leak on probe error handling paths
+    - bdc: Fix bug causing crash after multiple disconnects
+    - usb: bdc: Halt controller on suspend
+    - 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
+    - drm/msm: ratelimit crtc event overflow error
+    - drm/gem: Fix a leak in drm_gem_objects_lookup()
+    - drm/bridge: ti-sn65dsi86: Clear old error bits before AUX transfers
+    - agp/intel: Fix a memory leak on module initialisation failure
+    - mwifiex: Fix firmware filename for sd8977 chipset
+    - mwifiex: Fix firmware filename for sd8997 chipset
+    - btmrvl: Fix firmware filename for sd8977 chipset
+    - btmrvl: Fix firmware filename for sd8997 chipset
+    - video: fbdev: sm712fb: fix an issue about iounmap for a wrong address
+    - console: newport_con: fix an issue about leak related system resources
+    - video: pxafb: Fix the function used to balance a 'dma_alloc_coherent()' call
+    - ath10k: Acquire tx_lock in tx error paths
+    - iio: improve IIO_CONCENTRATION channel type description
+    - drm/etnaviv: Fix error path on failure to enable bus clk
+    - drm/arm: fix unintentional integer overflow on left shift
+    - clk: bcm63xx-gate: fix last clock availability
+    - leds: lm355x: avoid enum conversion warning
+    - Bluetooth: btusb: fix up firmware download sequence
+    - Bluetooth: btmtksdio: fix up firmware download sequence
+    - media: cxusb-analog: fix V4L2 dependency
+    - media: marvell-ccic: Add missed v4l2_async_notifier_cleanup()
+    - media: omap3isp: Add missed v4l2_ctrl_handler_free() for
+      preview_init_entities()
+    - ASoC: SOF: nocodec: add missing .owner field
+    - ASoC: Intel: bxt_rt298: add missing .owner field
+    - scsi: cumana_2: Fix different dev_id between request_irq() and free_irq()
+    - drm/mipi: use dcs write for mipi_dsi_dcs_set_tear_scanline
+    - cxl: Fix kobject memleak
+    - drm/radeon: fix array out-of-bounds read and write issues
+    - staging: vchiq_arm: Add a matching unregister call
+    - iavf: fix error return code in iavf_init_get_resources()
+    - iavf: Fix updating statistics
+    - RDMA/core: Fix bogus WARN_ON during ib_unregister_device_queued()
+    - scsi: powertec: Fix different dev_id between request_irq() and free_irq()
+    - scsi: eesox: Fix different dev_id between request_irq() and free_irq()
+    - ipvs: allow connection reuse for unconfirmed conntrack
+    - media: firewire: Using uninitialized values in node_probe()
+    - media: exynos4-is: Add missed check for pinctrl_lookup_state()
+    - media: cros-ec-cec: do not bail on device_init_wakeup failure
+    - xfs: don't eat an EIO/ENOSPC writeback error when scrubbing data fork
+    - xfs: fix reflink quota reservation accounting error
+    - RDMA/rxe: Skip dgid check in loopback mode
+    - PCI: Fix pci_cfg_wait queue locking problem
+    - drm/stm: repair runtime power management
+    - kobject: Avoid premature parent object freeing in kobject_cleanup()
+    - leds: core: Flush scheduled work for system suspend
+    - drm: panel: simple: Fix bpc for LG LB070WV8 panel
+    - phy: exynos5-usbdrd: Calibrating makes sense only for USB2.0 PHY
+    - drm/bridge: sil_sii8620: initialize return of sii8620_readb
+    - scsi: scsi_debug: Add check for sdebug_max_queue during module init
+    - mwifiex: Prevent memory corruption handling keys
+    - kernfs: do not call fsnotify() with name without a parent
+    - powerpc/rtas: don't online CPUs for partition suspend
+    - powerpc/vdso: Fix vdso cpu truncation
+    - RDMA/qedr: SRQ's bug fixes
+    - RDMA/rxe: Prevent access to wr->next ptr afrer wr is posted to send queue
+    - ima: Have the LSM free its audit rule
+    - staging: rtl8192u: fix a dubious looking mask before a shift
+    - ASoC: meson: fixes the missed kfree() for axg_card_add_tdm_loopback
+    - PCI/ASPM: Add missing newline in sysfs 'policy'
+    - phy: renesas: rcar-gen3-usb2: move irq registration to init
+    - powerpc/book3s64/pkeys: Use PVR check instead of cpu feature
+    - drm/imx: fix use after free
+    - drm/imx: tve: fix regulator_disable error path
+    - gpu: ipu-v3: Restore RGB32, BGR32
+    - spi: lantiq-ssc: Fix warning by using WQ_MEM_RECLAIM
+    - USB: serial: iuu_phoenix: fix led-activity helpers
+    - usb: core: fix quirks_param_set() writing to a const pointer
+    - thermal: ti-soc-thermal: Fix reversed condition in
+      ti_thermal_expose_sensor()
+    - coresight: tmc: Fix TMC mode read in tmc_read_unprepare_etb()
+    - powerpc/perf: Fix missing is_sier_aviable() during build
+    - mt76: mt7615: fix potential memory leak in mcu message handler
+    - phy: armada-38x: fix NETA lockup when repeatedly switching speeds
+    - MIPS: OCTEON: add missing put_device() call in dwc3_octeon_device_init()
+    - usb: dwc2: Fix error path in gadget registration
+    - usb: gadget: f_uac2: fix AC Interface Header Descriptor wTotalLength
+    - scsi: megaraid_sas: Clear affinity hint
+    - scsi: mesh: Fix panic after host or bus reset
+    - net: dsa: mv88e6xxx: MV88E6097 does not support jumbo configuration
+    - macintosh/via-macii: Access autopoll_devs when inside lock
+    - PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
+    - RDMA/core: Fix return error value in _ib_modify_qp() to negative
+    - 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
+    - Bluetooth: hci_h5: Set HCI_UART_RESET_ON_INIT to correct flags
+    - Bluetooth: hci_serdev: Only unregister device if it was registered
+    - net: dsa: rtl8366: Fix VLAN semantics
+    - net: dsa: rtl8366: Fix VLAN set-up
+    - xfs: fix inode allocation block res calculation precedence
+    - selftests/powerpc: Squash spurious errors due to device removal
+    - powerpc/32s: Fix CONFIG_BOOK3S_601 uses
+    - powerpc/boot: Fix CONFIG_PPC_MPC52XX references
+    - selftests/powerpc: Fix CPU affinity for child process
+    - RDMA/netlink: Remove CAP_NET_RAW check when dump a raw QP
+    - PCI: Release IVRS table in AMD ACS quirk
+    - [Config] update config for ARMADA_AP_CPU_CLK
+    - cpufreq: ap806: fix cpufreq driver needs ap cpu clk
+    - selftests/powerpc: Fix online CPU selection
+    - ASoC: meson: axg-tdm-interface: fix link fmt setup
+    - ASoC: meson: axg-tdmin: fix g12a skew
+    - ASoC: meson: axg-tdm-formatters: fix sclk inversion
+    - ASoC: fsl_sai: Fix value of FSL_SAI_CR1_RFW_MASK
+    - s390/qeth: don't process empty bridge port events
+    - ice: Graceful error handling in HW table calloc failure
+    - rtw88: fix LDPC field for RA info
+    - rtw88: fix short GI capability based on current bandwidth
+    - rtw88: coex: only skip coex triggered by BT info
+    - wl1251: fix always return 0 error
+    - tools, build: Propagate build failures from tools/build/Makefile.build
+    - tools, bpftool: Fix wrong return value in do_dump()
+    - net/mlx5: DR, Change push vlan action sequence
+    - net/mlx5: Delete extra dump stack that gives nothing
+    - net: ethernet: aquantia: Fix wrong return value
+    - liquidio: Fix wrong return value in cn23xx_get_pf_num()
+    - net: spider_net: Fix the size used in a 'dma_free_coherent()' call
+    - fsl/fman: use 32-bit unsigned integer
+    - fsl/fman: fix dereference null return value
+    - fsl/fman: fix unreachable code
+    - fsl/fman: check dereferencing null pointer
+    - fsl/fman: fix eth hash table allocation
+    - net: thunderx: initialize VF's mailbox mutex before first usage
+    - dlm: Fix kobject memleak
+    - ocfs2: fix unbalanced locking
+    - pinctrl-single: fix pcs_parse_pinconf() return value
+    - svcrdma: Fix page leak in svc_rdma_recv_read_chunk()
+    - x86/fsgsbase/64: Fix NULL deref in 86_fsgsbase_read_task
+    - crypto: aesni - add compatibility with IAS
+    - af_packet: TPACKET_V3: fix fill status rwlock imbalance
+    - drivers/net/wan/lapbether: Added needed_headroom and a skb->len check
+    - net: Fix potential memory leak in proto_register()
+    - net/nfc/rawsock.c: add CAP_NET_RAW check.
+    - net: phy: fix memory leak in device-create error path
+    - net: Set fput_needed iff FDPUT_FPUT is set
+    - net/tls: Fix kmap usage
+    - vmxnet3: use correct tcp hdr length when packet is encapsulated
+    - net: refactor bind_bucket fastreuse into helper
+    - net: initialize fastreuse on inet_inherit_port
+    - USB: serial: cp210x: re-enable auto-RTS on open
+    - USB: serial: cp210x: enable usb generic throttle/unthrottle
+    - ALSA: hda - fix the micmute led status for Lenovo ThinkCentre AIO
+    - 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: work around streaming quirk for MacroSilicon MS2109
+    - 9p: Fix memory leak in v9fs_mount
+    - media: media-request: Fix crash if memory allocation fails
+    - drm/ttm/nouveau: don't call tt destroy callback on alloc failure.
+    - io_uring: set ctx sq/cq entry count earlier
+    - NFS: Don't move layouts to plh_return_segs list while in use
+    - NFS: Don't return layout segments that are in use
+    - cpufreq: Fix locking issues with governors
+    - cpufreq: dt: fix oops on armada37xx
+    - include/asm-generic/vmlinux.lds.h: align ro_after_init
+    - spi: spidev: Align buffers for DMA
+    - mtd: rawnand: qcom: avoid write to unavailable register
+    - erofs: fix extended inode could cross boundary
+    - Revert "parisc: Drop LDCW barrier in CAS code when running UP"
+    - Revert "parisc: Use ldcw instruction for SMP spinlock release barrier"
+    - Revert "parisc: Revert "Release spinlocks using ordered store""
+    - parisc: Do not use an ordered store in pa_tlb_lock()
+    - parisc: Implement __smp_store_release and __smp_load_acquire barriers
+    - parisc: mask out enable and reserved bits from sba imask
+    - ARM: 8992/1: Fix unwind_frame for clang-built kernels
+    - irqdomain/treewide: Free firmware node after domain removal
+    - ALSA: usb-audio: add quirk for Pioneer DDJ-RB
+    - tpm: Unify the mismatching TPM space buffer sizes
+    - pstore: Fix linking when crypto API disabled
+    - crypto: hisilicon - don't sleep of CRYPTO_TFM_REQ_MAY_SLEEP was not
+      specified
+    - crypto: qat - fix double free in qat_uclo_create_batch_init_list
+    - crypto: ccp - Fix use of merged scatterlists
+    - crypto: cpt - don't sleep of CRYPTO_TFM_REQ_MAY_SLEEP was not specified
+    - bitfield.h: don't compile-time validate _val in FIELD_FIT
+    - fs/minix: check return value of sb_getblk()
+    - fs/minix: don't allow getting deleted inodes
+    - fs/minix: reject too-large maximum file size
+    - xen/balloon: fix accounting in alloc_xenballooned_pages error path
+    - xen/balloon: make the balloon wait interruptible
+    - xen/gntdev: Fix dmabuf import with non-zero sgt offset
+    - s390/dasd: fix inability to use DASD with DIAG driver
+    - s390/gmap: improve THP splitting
+    - io_uring: Fix NULL pointer dereference in loop_rw_iter()
+    - Linux 5.4.59
+
+  * Regression on NFS: unable to handle page fault in mempool_alloc_slab
+    (LP: #1886277) // Focal update: v5.4.59 upstream stable release
+    (LP: #1892417)
+    - SUNRPC: Fix ("SUNRPC: Add "@len" parameter to gss_unwrap()")
+
+  * Focal update: v5.4.59 upstream stable release (LP: #1892417) //
+    CVE-2019-19770 which shows this issue is not a core debugfs issue, but
+    - blktrace: fix debugfs use after free
+
+  * update ENA driver for LLQ acceleration mode, new hw support (LP: #1890845)
+    - net: ena: change num_queues to num_io_queues for clarity and consistency
+    - net: ena: multiple queue creation related cleanups
+    - net: ena: ethtool: get_channels: use combined only
+    - net: ena: make ethtool -l show correct max number of queues
+    - net: ena: remove redundant print of number of queues
+    - net: ena: ethtool: support set_channels callback
+    - net: ena: implement XDP drop support
+    - net: ena: Implement XDP_TX action
+    - net: ena: Add first_interrupt field to napi struct
+    - net: ena: fix default tx interrupt moderation interval
+    - net: ena: remove set but not used variable 'rx_ring'
+    - net: ena: remove set but not used variable 'hash_key'
+    - net: ena: ethtool: remove redundant non-zero check on rc
+    - net/amazon: Ensure that driver version is aligned to the linux kernel
+    - net: ena: fix broken interface between ENA driver and FW
+    - net: ena: ethtool: clean up minor indentation issue
+    - net: ena: fix incorrect setting of the number of msix vectors
+    - net: ena: fix request of incorrect number of IRQ vectors
+    - net: ena: avoid memory access violation by validating req_id properly
+    - net: ena: fix continuous keep-alive resets
+    - net: ena: Make some functions static
+    - net: ena: avoid unnecessary admin command when RSS function set fails
+    - net: ena: allow setting the hash function without changing the key
+    - net: ena: change default RSS hash function to Toeplitz
+    - net: ena: changes to RSS hash key allocation
+    - net: ena: remove code that does nothing
+    - net: ena: add unmask interrupts statistics to ethtool
+    - net: ena: add support for reporting of packet drops
+    - net: ena: drop superfluous prototype
+    - net: ena: use SHUTDOWN as reset reason when closing interface
+    - net: ena: cosmetic: remove unnecessary spaces and tabs in ena_com.h macros
+    - net: ena: cosmetic: extract code to ena_indirection_table_set()
+    - net: ena: add support for the rx offset feature
+    - net: ena: rename ena_com_free_desc to make API more uniform
+    - net: ena: use explicit variable size for clarity
+    - net: ena: fix ena_com_comp_status_to_errno() return value
+    - net: ena: simplify ena_com_update_intr_delay_resolution()
+    - net: ena: cosmetic: set queue sizes to u32 for consistency
+    - net: ena: cosmetic: fix spelling and grammar mistakes in comments
+    - net: ena: cosmetic: fix line break issues
+    - net: ena: cosmetic: remove unnecessary code
+    - net: ena: cosmetic: code reorderings
+    - net: ena: cosmetic: fix spacing issues
+    - net: ena: cosmetic: minor code changes
+    - net: ena: reduce driver load time
+    - net: ena: xdp: XDP_TX: fix memory leak
+    - net: ena: xdp: update napi budget for DROP and ABORTED
+    - ena_netdev: use generic power management
+    - net: ena: Fix using plain integer as NULL pointer in ena_init_napi_in_range
+    - net: ena: avoid unnecessary rearming of interrupt vector when busy-polling
+    - net: ena: add reserved PCI device ID
+    - net: ena: cosmetic: satisfy gcc warning
+    - net: ena: cosmetic: change ena_com_stats_admin stats to u64
+    - net: ena: add support for traffic mirroring
+    - net: ena: enable support of rss hash key and function changes
+    - net: ena: move llq configuration from ena_probe to ena_device_init()
+    - net: ena: support new LLQ acceleration mode
+
+  * [SRU] Fix acpi backlight issue on some thinkpads (LP: #1892010)
+    - platform/x86: thinkpad_acpi: not loading brightness_init when _BCL invalid
+
+  * [SRU][F/OEM-5.6] add a new OLED panel support for brightness control
+    (LP: #1887909)
+    - drm/dp: Lenovo X13 Yoga OLED panel brightness fix
+
+  * Realtek [10ec:c82f] Subsystem [17aa:c02f] Wifi adapter not found
+    (LP: #1886247)
+    - SAUCE: rtw88: 8822ce: add support for device ID 0xc82f
+
+  * KVM: Fix zero_page reference counter overflow when using KSM on KVM compute
+    host (LP: #1837810)
+    - KVM: fix overflow of zero page refcount with ksm running
+
+  * Fix missing HDMI Audio on another HP Desktop (LP: #1891617)
+    - ALSA: hda/hdmi: Use force connectivity quirk on another HP desktop
+
+  * alsa/sof: support 1 and 3 dmics (LP: #1891585)
+    - SAUCE: ASoC: SOF: intel: hda: support also devices with 1 and 3 dmics
+
+  * tcp_fastopen_backup_key.sh from net in ubuntu_kernel_selftests failed on
+    Eoan LPAR (LP: #1869134)
+    - tcp: correct read of TFO keys on big endian systems
+
+  * Fix false-negative return value for rtnetlink.sh in kselftests/net
+    (LP: #1890136)
+    - selftests: rtnetlink: correct the final return value for the test
+    - selftests: rtnetlink: make kci_test_encap() return sub-test result
+
+  * Focal update: v5.4.58 upstream stable release (LP: #1891387)
+    - USB: serial: qcserial: add EM7305 QDL product ID
+    - perf/core: Fix endless multiplex timer
+    - USB: iowarrior: fix up report size handling for some devices
+    - usb: xhci: define IDs for various ASMedia host controllers
+    - usb: xhci: Fix ASMedia ASM1142 DMA addressing
+    - io_uring: prevent re-read of sqe->opcode
+    - io_uring: Fix use-after-free in io_sq_wq_submit_work()
+    - Revert "ALSA: hda: call runtime_allow() for all hda controllers"
+    - ALSA: hda/realtek: Add alc269/alc662 pin-tables for Loongson-3 laptops
+    - ALSA: hda/ca0132 - Add new quirk ID for Recon3D.
+    - ALSA: hda/ca0132 - Fix ZxR Headphone gain control get value.
+    - ALSA: hda/ca0132 - Fix AE-5 microphone selection commands.
+    - ALSA: seq: oss: Serialize ioctls
+    - staging: android: ashmem: Fix lockdep warning for write operation
+    - staging: rtl8712: handle firmware load failure
+    - Staging: rtl8188eu: rtw_mlme: Fix uninitialized variable authmode
+    - 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()
+    - omapfb: dss: Fix max fclk divider for omap36xx
+    - binder: Prevent context manager from incrementing ref 0
+    - Smack: fix use-after-free in smk_write_relabel_self()
+    - scripts: add dummy report mode to add_namespace.cocci
+    - vgacon: Fix for missing check in scrollback handling
+    - mtd: properly check all write ioctls for permissions
+    - leds: wm831x-status: fix use-after-free on unbind
+    - leds: lm36274: fix use-after-free on unbind
+    - leds: da903x: fix use-after-free on unbind
+    - leds: lm3533: fix use-after-free on unbind
+    - leds: 88pm860x: fix use-after-free on unbind
+    - net/9p: validate fds in p9_fd_open
+    - drm/nouveau/fbcon: fix module unload when fbcon init has failed for some
+      reason
+    - drm/nouveau/fbcon: zero-initialise the mode_cmd2 structure
+    - drm/drm_fb_helper: fix fbdev with sparc64
+    - i2c: slave: improve sanity check when registering
+    - i2c: slave: add sanity check when unregistering
+    - usb: hso: check for return value in hso_serial_common_create()
+    - net: ethernet: mtk_eth_soc: Always call mtk_gmac0_rgmii_adjust() for mt7623
+    - ALSA: hda: fix NULL pointer dereference during suspend
+    - firmware: Fix a reference count leak.
+    - 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
+    - Drivers: hv: vmbus: Ignore CHANNELMSG_TL_CONNECT_RESULT(23)
+    - xattr: break delegations in {set,remove}xattr
+    - Revert "powerpc/kasan: Fix shadow pages allocation failure"
+    - PCI: tegra: Revert tegra124 raw_violation_fixup
+    - ipv4: Silence suspicious RCU usage warning
+    - ipv6: fix memory leaks on IPV6_ADDRFORM path
+    - ipv6: Fix nexthop refcnt leak when creating ipv6 route info
+    - net: ethernet: mtk_eth_soc: fix MTU warnings
+    - rxrpc: Fix race between recvmsg and sendmsg on immediate call failure
+    - vxlan: Ensure FDB dump is performed under RCU
+    - net: lan78xx: replace bogus endpoint lookup
+    - appletalk: Fix atalk_proc_init() return path
+    - dpaa2-eth: Fix passing zero to 'PTR_ERR' warning
+    - hv_netvsc: do not use VF device if link is down
+    - net: gre: recompute gre csum for sctp over gre tunnels
+    - net: thunderx: use spin_lock_bh in nicvf_set_rx_mode_task()
+    - openvswitch: Prevent kernel-infoleak in ovs_ct_put_key()
+    - Revert "vxlan: fix tos value before xmit"
+    - tcp: apply a floor of 1 for RTT samples from TCP timestamps
+    - ima: move APPRAISE_BOOTPARAM dependency on ARCH_POLICY to runtime
+    - [Config] update annotations for IMA_APPRAISE_BOOTPARAM
+    - nfsd: Fix NFSv4 READ on RDMA when using readv
+    - Linux 5.4.58
+
+  * Focal update: v5.4.57 upstream stable release (LP: #1891064)
+    - 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
+    - arm64: Workaround circular dependency in pointer_auth.h
+    - ext4: fix direct I/O read error
+    - selftests: bpf: Fix detach from sockmap tests
+    - bpf: sockmap: Require attach_bpf_fd when detaching a program
+    - Linux 5.4.57
+
+  * Focal update: v5.4.56 upstream stable release (LP: #1891063)
+    - crypto: ccp - Release all allocated memory if sha type is invalid
+    - media: rc: prevent memory leak in cx23888_ir_probe
+    - sunrpc: check that domain table is empty at module unload.
+    - ath10k: enable transmit data ack RSSI for QCA9884
+    - PCI/ASPM: Disable ASPM on ASMedia ASM1083/1085 PCIe-to-PCI bridge
+    - mm/filemap.c: don't bother dropping mmap_sem for zero size readahead
+    - ALSA: usb-audio: Add implicit feedback quirk for SSL2
+    - ALSA: hda/realtek: enable headset mic of ASUS ROG Zephyrus G15(GA502) series
+      with ALC289
+    - ALSA: hda/realtek: typo_fix: enable headset mic of ASUS ROG Zephyrus
+      G14(GA401) series with ALC289
+    - ALSA: hda/realtek: Fix add a "ultra_low_power" function for intel reference
+      board (alc256)
+    - ALSA: hda/hdmi: Fix keep_power assignment for non-component devices
+    - IB/rdmavt: Fix RQ counting issues causing use of an invalid RWQE
+    - vhost/scsi: fix up req type endian-ness
+    - 9p/trans_fd: Fix concurrency del of req_list in p9_fd_cancelled/p9_read_work
+    - wireless: Use offsetof instead of custom macro.
+    - ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess
+      watchpoints
+    - ARM: dts: imx6sx-sabreauto: Fix the phy-mode on fec2
+    - ARM: dts: imx6sx-sdb: Fix the phy-mode on fec2
+    - ARM: dts: imx6qdl-icore: Fix OTG_ID pin and sdcard detect
+    - virtio_balloon: fix up endian-ness for free cmd id
+    - Revert "drm/amdgpu: Fix NULL dereference in dpm sysfs handlers"
+    - drm/amd/display: Clear dm_state for fast updates
+    - drm/amdgpu: Prevent kernel-infoleak in amdgpu_info_ioctl()
+    - drm/dbi: Fix SPI Type 1 (9-bit) transfer
+    - drm: hold gem reference until object is no longer accessed
+    - rds: Prevent kernel-infoleak in rds_notify_queue_get()
+    - libtraceevent: Fix build with binutils 2.35
+    - net/x25: Fix x25_neigh refcnt leak when x25 disconnect
+    - net/x25: Fix null-ptr-deref in x25_disconnect
+    - ARM: dts sunxi: Relax a bit the CMA pool allocation range
+    - xfrm: Fix crash when the hold queue is used.
+    - ARM: dts: armada-38x: fix NETA lockup when repeatedly switching speeds
+    - nvme-tcp: fix possible hang waiting for icresp response
+    - selftests/net: rxtimestamp: fix clang issues for target arch PowerPC
+    - selftests/net: psock_fanout: fix clang issues for target arch PowerPC
+    - selftests/net: so_txtime: fix clang issues for target arch PowerPC
+    - sh/tlb: Fix PGTABLE_LEVELS > 2
+    - sh: Fix validation of system call number
+    - net: hns3: fix a TX timeout issue
+    - net: hns3: fix aRFS FD rules leftover after add a user FD rule
+    - net/mlx5: E-switch, Destroy TSAR when fail to enable the mode
+    - net/mlx5e: Fix error path of device attach
+    - net/mlx5: Verify Hardware supports requested ptp function on a given pin
+    - net/mlx5e: Modify uplink state on interface up/down
+    - net/mlx5e: Fix kernel crash when setting vf VLANID on a VF dev
+    - net: lan78xx: add missing endpoint sanity check
+    - net: lan78xx: fix transfer-buffer memory leak
+    - rhashtable: Fix unprotected RCU dereference in __rht_ptr
+    - mlx4: disable device on shutdown
+    - mlxsw: core: Increase scope of RCU read-side critical section
+    - mlxsw: core: Free EMAD transactions using kfree_rcu()
+    - ibmvnic: Fix IRQ mapping disposal in error path
+    - bpf: Fix map leak in HASH_OF_MAPS map
+    - mac80211: mesh: Free ie data when leaving mesh
+    - mac80211: mesh: Free pending skb when destroying a mpath
+    - arm64/alternatives: move length validation inside the subsection
+    - arm64: csum: Fix handling of bad packets
+    - Bluetooth: fix kernel oops in store_pending_adv_report
+    - net: nixge: fix potential memory leak in nixge_probe()
+    - net: gemini: Fix missing clk_disable_unprepare() in error path of
+      gemini_ethernet_port_probe()
+    - net/mlx5e: fix bpf_prog reference count leaks in mlx5e_alloc_rq
+    - perf tools: Fix record failure when mixed with ARM SPE event
+    - vxlan: fix memleak of fdb
+    - usb: hso: Fix debug compile warning on sparc32
+    - selftests: fib_nexthop_multiprefix: fix cleanup() netns deletion
+    - qed: Disable "MFW indication via attention" SPAM every 5 minutes
+    - selftests: net: ip_defrag: modprobe missing nf_defrag_ipv6 support
+    - nfc: s3fwrn5: add missing release on skb in s3fwrn5_recv_frame
+    - scsi: core: Run queue in case of I/O resource contention failure
+    - parisc: add support for cmpxchg on u8 pointers
+    - net: ethernet: ravb: exit if re-initialization fails in tx timeout
+    - Revert "i2c: cadence: Fix the hold bit setting"
+    - x86/unwind/orc: Fix ORC for newly forked tasks
+    - x86/stacktrace: Fix reliable check for empty user task stacks
+    - cxgb4: add missing release on skb in uld_send()
+    - xen-netfront: fix potential deadlock in xennet_remove()
+    - RISC-V: Set maximum number of mapped pages correctly
+    - drivers/net/wan: lapb: Corrected the usage of skb_cow
+    - KVM: arm64: Don't inherit exec permission across page-table levels
+    - KVM: LAPIC: Prevent setting the tscdeadline timer if the lapic is hw
+      disabled
+    - x86/i8259: Use printk_deferred() to prevent deadlock
+    - perf tests bp_account: Make global variable static
+    - perf env: Do not return pointers to local variables
+    - perf bench: Share some global variables to fix build with gcc 10
+    - Linux 5.4.56
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 10 Sep 2020 12:12:09 +0200
+
+linux (5.4.0-47.51) focal; urgency=medium
+
+  * focal/linux: 5.4.0-47.51 -proposed tracker (LP: #1894315)
+
+  * CVE-2020-14386
+    - SAUCE: net/packet: fix overflow in tpacket_rcv
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 04 Sep 2020 16:08:25 -0300
+
+linux (5.4.0-45.49) focal; urgency=medium
+
+  * focal/linux: 5.4.0-45.49 -proposed tracker (LP: #1893050)
+
+  * [Potential Regression] dscr_inherit_exec_test from powerpc in
+    ubuntu_kernel_selftests failed on B/E/F (LP: #1888332)
+    - powerpc/64s: Don't init FSCR_DSCR in __init_FSCR()
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 26 Aug 2020 15:15:45 +0200
+
+linux (5.4.0-44.48) focal; urgency=medium
+
+  * focal/linux: 5.4.0-44.48 -proposed tracker (LP: #1891049)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * ipsec: policy priority management is broken (LP: #1890796)
+    - xfrm: policy: match with both mark and mask on user interfaces
+
+ -- Kelsey Skunberg <kelsey.skunberg@canonical.com>  Mon, 10 Aug 2020 14:57:15 -0600
+
+linux (5.4.0-43.47) focal; urgency=medium
+
+  * focal/linux: 5.4.0-43.47 -proposed tracker (LP: #1890746)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * Devlink -  add RoCE disable kernel support  (LP: #1877270)
+    - devlink: Add new "enable_roce" generic device param
+    - net/mlx5: Document flow_steering_mode devlink param
+    - net/mlx5: Handle "enable_roce" devlink param
+    - IB/mlx5: Rename profile and init methods
+    - IB/mlx5: Load profile according to RoCE enablement state
+    - net/mlx5: Remove unneeded variable in mlx5_unload_one
+    - net/mlx5: Add devlink reload
+    - IB/mlx5: Do reverse sequence during device removal
+
+  * msg_zerocopy.sh in net from ubuntu_kernel_selftests failed (LP: #1812620)
+    - selftests/net: relax cpu affinity requirement in msg_zerocopy test
+
+  * Enlarge hisi_sec2 capability (LP: #1890222)
+    - Revert "UBUNTU: [Config] Disable hisi_sec2 temporarily"
+    - crypto: hisilicon - update SEC driver module parameter
+
+  * Fix missing HDMI/DP Audio on an HP Desktop (LP: #1890441)
+    - ALSA: hda/hdmi: Add quirk to force connectivity
+
+  * Fix IOMMU error on AMD Radeon Pro W5700 (LP: #1890306)
+    - PCI: Mark AMD Navi10 GPU rev 0x00 ATS as broken
+
+  * ASoC:amd:renoir:  the dmic can't record sound after suspend and resume
+    (LP: #1890220)
+    - SAUCE: ASoC: amd: renoir: restore two more registers during resume
+
+  * No sound, Dummy output on Acer Swift 3 SF314-57G with Ice Lake core-i7  CPU
+    (LP: #1877757)
+    - ASoC: SOF: Intel: hda: fix generic hda codec support
+
+  * Fix right speaker of HP laptop (LP: #1889375)
+    - SAUCE: hda/realtek: Fix right speaker of HP laptop
+
+  * blk_update_request error when mount nvme partition (LP: #1872383)
+    - SAUCE: nvme-pci: prevent SK hynix PC400 from using Write Zeroes command
+
+  * soc/amd/renoir: detect dmic from acpi table (LP: #1887734)
+    - ASoC: amd: add logic to check dmic hardware runtime
+    - ASoC: amd: add ACPI dependency check
+    - ASoC: amd: fixed kernel warnings
+
+  * soc/amd/renoir: change the module name to make it work with ucm3
+    (LP: #1888166)
+    - AsoC: amd: add missing snd- module prefix to the acp3x-rn driver kernel
+      module
+    - SAUCE: remove a kernel module since its name is changed
+
+  * Focal update: v5.4.55 upstream stable release (LP: #1890343)
+    - AX.25: Fix out-of-bounds read in ax25_connect()
+    - AX.25: Prevent out-of-bounds read in ax25_sendmsg()
+    - dev: Defer free of skbs in flush_backlog
+    - drivers/net/wan/x25_asy: Fix to make it work
+    - ip6_gre: fix null-ptr-deref in ip6gre_init_net()
+    - net-sysfs: add a newline when printing 'tx_timeout' by sysfs
+    - net: udp: Fix wrong clean up for IS_UDPLITE macro
+    - qrtr: orphan socket in qrtr_release()
+    - rtnetlink: Fix memory(net_device) leak when ->newlink fails
+    - rxrpc: Fix sendmsg() returning EPIPE due to recvmsg() returning ENODATA
+    - tcp: allow at most one TLP probe per flight
+    - AX.25: Prevent integer overflows in connect and sendmsg
+    - sctp: shrink stream outq only when new outcnt < old outcnt
+    - sctp: shrink stream outq when fails to do addstream reconf
+    - udp: Copy has_conns in reuseport_grow().
+    - udp: Improve load balancing for SO_REUSEPORT.
+    - regmap: debugfs: check count when read regmap file
+    - PM: wakeup: Show statistics for deleted wakeup sources again
+    - Revert "dpaa_eth: fix usage as DSA master, try 3"
+    - Linux 5.4.55
+
+  * Add support for Atlantic NIC firmware v4 (LP: #1886908)
+    - net: atlantic: simplify hw_get_fw_version() usage
+    - net: atlantic: align return value of ver_match function with function name
+    - net: atlantic: add support for FW 4.x
+
+  * perf vendor events s390: Add new deflate counters for IBM z15 (LP: #1888551)
+    - perf vendor events s390: Add new deflate counters for IBM z15
+
+  * Focal update: v5.4.54 upstream stable release (LP: #1889669)
+    - soc: qcom: rpmh: Dirt can only make you dirtier, not cleaner
+    - gpio: arizona: handle pm_runtime_get_sync failure case
+    - gpio: arizona: put pm_runtime in case of failure
+    - 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
+    - scsi: mpt3sas: Fix unlock imbalance
+    - drivers/net/wan/lapbether: Fixed the value of hard_header_len
+    - ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
+    - net: sky2: initialize return of gm_phy_read
+    - drm/nouveau/i2c/g94-: increase NV_PMGR_DP_AUXCTL_TRANSACTREQ timeout
+    - scsi: mpt3sas: Fix error returns in BRM_status_show
+    - scsi: dh: Add Fujitsu device to devinfo and dh lists
+    - dm: use bio_uninit instead of bio_disassociate_blkg
+    - drivers/firmware/psci: Fix memory leakage in alloc_init_cpu_groups()
+    - fuse: fix weird page warning
+    - irqdomain/treewide: Keep firmware node unconditionally allocated
+    - ARM: dts: imx6qdl-gw551x: Do not use 'simple-audio-card,dai-link'
+    - ARM: dts: imx6qdl-gw551x: fix audio SSI
+    - dmabuf: use spinlock to access dmabuf->name
+    - drm/amd/display: Check DMCU Exists Before Loading
+    - SUNRPC reverting d03727b248d0 ("NFSv4 fix CLOSE not waiting for direct IO
+      compeletion")
+    - btrfs: reloc: fix reloc root leak and NULL pointer dereference
+    - btrfs: reloc: clear DEAD_RELOC_TREE bit for orphan roots to prevent runaway
+      balance
+    - uprobes: Change handle_swbp() to send SIGTRAP with si_code=SI_KERNEL, to fix
+      GDB regression
+    - ALSA: hda/realtek: Fixed ALC298 sound bug by adding quirk for Samsung
+      Notebook Pen S
+    - 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
+    - btrfs: fix mount failure caused by race with umount
+    - btrfs: fix page leaks after failure to lock page for delalloc
+    - bnxt_en: Fix race when modifying pause settings.
+    - bnxt_en: Fix completion ring sizing with TPA enabled.
+    - fpga: dfl: pci: reduce the scope of variable 'ret'
+    - fpga: dfl: fix bug in port reset handshake
+    - hippi: Fix a size used in a 'pci_free_consistent()' in an error handling
+      path
+    - vsock/virtio: annotate 'the_virtio_vsock' RCU pointer
+    - ax88172a: fix ax88172a_unbind() failures
+    - RDMA/mlx5: Use xa_lock_irq when access to SRQ table
+    - ASoC: Intel: bytcht_es8316: Add missed put_device()
+    - net: dp83640: fix SIOCSHWTSTAMP to update the struct with actual
+      configuration
+    - ieee802154: fix one possible memleak in adf7242_probe
+    - drm: sun4i: hdmi: Fix inverted HPD result
+    - net: smc91x: Fix possible memory leak in smc_drv_probe()
+    - bonding: check error value of register_netdevice() immediately
+    - mlxsw: destroy workqueue when trap_register in mlxsw_emad_init
+    - ionic: use offset for ethtool regs data
+    - ionic: fix up filter locks and debug msgs
+    - net: ag71xx: add missed clk_disable_unprepare in error path of probe
+    - net: hns3: fix error handling for desc filling
+    - net: dsa: microchip: call phy_remove_link_mode during probe
+    - netdevsim: fix unbalaced locking in nsim_create()
+    - qed: suppress "don't support RoCE & iWARP" flooding on HW init
+    - qed: suppress false-positives interrupt error messages on HW init
+    - ipvs: fix the connection sync failed in some cases
+    - net: ethernet: ave: Fix error returns in ave_init
+    - Revert "PCI/PM: Assume ports without DLL Link Active train links in 100 ms"
+    - nfsd4: fix NULL dereference in nfsd/clients display code
+    - enetc: Remove the mdio bus on PF probe bailout
+    - i2c: rcar: always clear ICSAR to avoid side effects
+    - i2c: i2c-qcom-geni: Fix DMA transfer race
+    - bonding: check return value of register_netdevice() in bond_newlink()
+    - geneve: fix an uninitialized value in geneve_changelink()
+    - serial: exar: Fix GPIO configuration for Sealevel cards based on XR17V35X
+    - scripts/decode_stacktrace: strip basepath from all paths
+    - scripts/gdb: fix lx-symbols 'gdb.error' while loading modules
+    - HID: i2c-hid: add Mediacom FlexBook edge13 to descriptor override
+    - HID: alps: support devices with report id 2
+    - HID: steam: fixes race in handling device list.
+    - HID: apple: Disable Fn-key key-re-mapping on clone keyboards
+    - dmaengine: tegra210-adma: Fix runtime PM imbalance on error
+    - Input: add `SW_MACHINE_COVER`
+    - ARM: dts: n900: remove mmc1 card detect gpio
+    - spi: mediatek: use correct SPI_CFG2_REG MACRO
+    - regmap: dev_get_regmap_match(): fix string comparison
+    - hwmon: (aspeed-pwm-tacho) Avoid possible buffer overflow
+    - dmaengine: fsl-edma: fix wrong tcd endianness for big-endian cpu
+    - dmaengine: ioat setting ioat timeout as module parameter
+    - Input: synaptics - enable InterTouch for ThinkPad X1E 1st gen
+    - Input: elan_i2c - only increment wakeup count on touch
+    - usb: dwc3: pci: add support for the Intel Tiger Lake PCH -H variant
+    - usb: dwc3: pci: add support for the Intel Jasper Lake
+    - usb: gadget: udc: gr_udc: fix memleak on error handling path in gr_ep_init()
+    - usb: cdns3: ep0: fix some endian issues
+    - usb: cdns3: trace: fix some endian issues
+    - hwmon: (adm1275) Make sure we are reading enough data for different chips
+    - drm/amdgpu/gfx10: fix race condition for kiq
+    - drm/amdgpu: fix preemption unit test
+    - hwmon: (nct6775) Accept PECI Calibration as temperature source for NCT6798D
+    - platform/x86: ISST: Add new PCI device ids
+    - platform/x86: asus-wmi: allow BAT1 battery name
+    - hwmon: (scmi) Fix potential buffer overflow in scmi_hwmon_probe()
+    - ALSA: hda/realtek - fixup for yet another Intel reference board
+    - drivers/perf: Fix kernel panic when rmmod PMU modules during perf sampling
+    - arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP
+    - x86: math-emu: Fix up 'cmp' insn for clang ias
+    - asm-generic/mmiowb: Allow mmiowb_set_pending() when preemptible()
+    - drivers/perf: Prevent forced unbinding of PMU drivers
+    - RISC-V: Upgrade smp_mb__after_spinlock() to iorw,iorw
+    - binder: Don't use mmput() from shrinker function.
+    - usb: xhci-mtk: fix the failure of bandwidth allocation
+    - usb: xhci: Fix ASM2142/ASM3142 DMA addressing
+    - Revert "cifs: Fix the target file was deleted when rename failed."
+    - iwlwifi: mvm: don't call iwl_mvm_free_inactive_queue() under RCU
+    - tty: xilinx_uartps: Really fix id assignment
+    - 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: tegra: fix CREAD handling for PIO
+    - serial: 8250: fix null-ptr-deref in serial8250_start_tx()
+    - serial: 8250_mtk: Fix high-speed baud rates clamping
+    - /dev/mem: Add missing memory barriers for devmem_inode
+    - fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
+    - vt: Reject zero-sized screen buffer size.
+    - Makefile: Fix GCC_TOOLCHAIN_DIR prefix for Clang cross compilation
+    - mm/mmap.c: close race between munmap() and expand_upwards()/downwards()
+    - mm/memcg: fix refcount error while moving and swapping
+    - mm: memcg/slab: fix memory leak at non-root kmem_cache destroy
+    - khugepaged: fix null-pointer dereference due to race
+    - io-mapping: indicate mapping failure
+    - mmc: sdhci-of-aspeed: Fix clock divider calculation
+    - drm/amdgpu: Fix NULL dereference in dpm sysfs handlers
+    - drm/amd/powerplay: fix a crash when overclocking Vega M
+    - parisc: Add atomic64_set_release() define to avoid CPU soft lockups
+    - x86, vmlinux.lds: Page-align end of ..page_aligned sections
+    - ASoC: rt5670: Add new gpio1_is_ext_spk_en quirk and enable it on the Lenovo
+      Miix 2 10
+    - ASoC: qcom: Drop HAS_DMA dependency to fix link failure
+    - ASoC: topology: fix kernel oops on route addition error
+    - ASoC: topology: fix tlvs in error handling for widget_dmixer
+    - dm integrity: fix integrity recalculation that is improperly skipped
+    - ath9k: Fix regression with Atheros 9271
+    - Linux 5.4.54
+
+  * Focal update: v5.4.53 upstream stable release (LP: #1888560)
+    - crypto: atmel - Fix selection of CRYPTO_AUTHENC
+    - crypto: atmel - Fix build error of CRYPTO_AUTHENC
+    - net: atlantic: fix ip dst and ipv6 address filters
+    - net: rmnet: fix lower interface leak
+    - bridge: mcast: Fix MLD2 Report IPv6 payload length check
+    - genetlink: remove genl_bind
+    - ipv4: fill fl4_icmp_{type,code} in ping_v4_sendmsg
+    - ipv6: fib6_select_path can not use out path for nexthop objects
+    - ipv6: Fix use of anycast address with loopback
+    - 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
+    - net_sched: fix a memory leak in atm_tc_init()
+    - sched: consistently handle layer3 header accesses in the presence of VLANs
+    - tcp: fix SO_RCVLOWAT possible hangs under high mem pressure
+    - 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: do not send silly options in SYNCOOKIES
+    - vlan: consolidate VLAN parsing code and limit max parsing depth
+    - tcp: md5: refine tcp_md5_do_add()/tcp_md5_hash_key() barriers
+    - tcp: md5: allow changing MD5 keys in all socket states
+    - cgroup: fix cgroup_sk_alloc() for sk_clone_lock()
+    - cgroup: Fix sock_cgroup_data on big-endian.
+    - ip: Fix SO_MARK in RST, ACK and ICMP packets
+    - arm64: Introduce a way to disable the 32bit vdso
+    - arm64: arch_timer: Allow an workaround descriptor to disable compat vdso
+    - arm64: arch_timer: Disable the compat vdso for cores affected by
+      ARM64_WORKAROUND_1418040
+    - drm/msm: fix potential memleak in error branch
+    - drm/msm/dpu: allow initialization of encoder locks during encoder init
+    - drm/exynos: Properly propagate return value in drm_iommu_attach_device()
+    - drm/exynos: fix ref count leak in mic_pre_enable
+    - x86/fpu: Reset MXCSR to default in kernel_fpu_begin()
+    - thermal/drivers: imx: Fix missing of_node_put() at probe time
+    - blk-mq-debugfs: update blk_queue_flag_name[] accordingly for new flags
+    - m68k: nommu: register start of the memory with memblock
+    - m68k: mm: fix node memblock init
+    - dt-bindings: mailbox: zynqmp_ipi: fix unit address
+    - cifs: prevent truncation from long to int in wait_for_free_credits
+    - arm64/alternatives: use subsections for replacement sequences
+    - tpm_tis: extra chip->ops check on error path in tpm_tis_core_init
+    - gfs2: read-only mounts should grab the sd_freeze_gl glock
+    - i2c: eg20t: Load module automatically if ID matches
+    - arm64/alternatives: don't patch up internal branches
+    - iio:magnetometer:ak8974: Fix alignment and data leak issues
+    - iio:humidity:hdc100x Fix alignment and data leak issues
+    - iio: magnetometer: ak8974: Fix runtime PM imbalance on error
+    - iio: core: add missing IIO_MOD_H2/ETHANOL string identifiers
+    - iio: mma8452: Add missed iio_device_unregister() call in mma8452_probe()
+    - iio: pressure: zpa2326: handle pm_runtime_get_sync failure
+    - iio:humidity:hts221 Fix alignment and data leak issues
+    - iio:pressure:ms5611 Fix buffer element alignment
+    - iio:health:afe4403 Fix timestamp alignment and prevent data leak.
+    - spi: spi-fsl-dspi: Fix lockup if device is shutdown during SPI transfer
+    - net: dsa: bcm_sf2: Fix node reference count
+    - of: of_mdio: Correct loop scanning logic
+    - net: macb: call pm_runtime_put_sync on failure path
+    - net: ethernet: mvneta: Do not error out in non serdes modes
+    - net: ethernet: mvneta: Add back interface mode validation
+    - Revert "usb/ohci-platform: Fix a warning when hibernating"
+    - Revert "usb/ehci-platform: Set PM runtime as active on resume"
+    - Revert "usb/xhci-plat: Set PM runtime as active on resume"
+    - net: sfp: add support for module quirks
+    - net: sfp: add some quirks for GPON modules
+    - ARM: OMAP4+: remove pdata quirks for omap4+ iommus
+    - ARM: OMAP2+: Add workaround for DRA7 DSP MStandby errata i879
+    - ARM: OMAP2+: use separate IOMMU pdata to fix DRA7 IPU1 boot
+    - mmc: mmci: Support any block sizes for ux500v2 and qcom variant
+    - HID: quirks: Remove ITE 8595 entry from hid_have_special_driver
+    - ARM: at91: pm: add quirk for sam9x60's ulp1
+    - drm/sun4i: tcon: Separate quirks for tcon0 and tcon1 on A20
+    - scsi: sr: remove references to BLK_DEV_SR_VENDOR, leave it enabled
+    - [Config] updateconfigs for BLK_DEV_SR_VENDOR
+    - bus: ti-sysc: Rename clk related quirks to pre_reset and post_reset quirks
+    - bus: ti-sysc: Consider non-existing registers too when matching quirks
+    - bus: ti-sysc: Handle module unlock quirk needed for some RTC
+    - bus: ti-sysc: Detect display subsystem related devices
+    - arm64: dts: g12-common: add parkmode_disable_ss_quirk on DWC3 controller
+    - bus: ti-sysc: Detect EDMA and set quirk flags for tptc
+    - ALSA: usb-audio: Add support for MOTU MicroBook IIc
+    - Input: goodix - fix touch coordinates on Cube I15-TC
+    - ALSA: usb-audio: Create a registration quirk for Kingston HyperX Amp
+      (0951:16d8)
+    - doc: dt: bindings: usb: dwc3: Update entries for disabling SS instances in
+      park mode
+    - mmc: sdhci: do not enable card detect interrupt for gpio cd type
+    - ALSA: usb-audio: Rewrite registration quirk handling
+    - ACPI: video: Use native backlight on Acer Aspire 5783z
+    - ALSA: usb-audio: Add registration quirk for Kingston HyperX Cloud Alpha S
+    - ALSA: usb-audio: Add quirk for Focusrite Scarlett 2i2
+    - Input: mms114 - add extra compatible for mms345l
+    - ACPI: video: Use native backlight on Acer TravelMate 5735Z
+    - bus: ti-sysc: Use optional clocks on for enable and wait for softreset bit
+    - ALSA: usb-audio: Add registration quirk for Kingston HyperX Cloud Flight S
+    - iio:health:afe4404 Fix timestamp alignment and prevent data leak.
+    - soundwire: intel: fix memory leak with devm_kasprintf
+    - dmaengine: sh: usb-dmac: set tx_result parameters
+    - phy: sun4i-usb: fix dereference of pointer phy0 before it is null checked
+    - arm64: dts: meson: add missing gxl rng clock
+    - arm64: dts: meson-gxl-s805x: reduce initial Mali450 core frequency
+    - bus: ti-sysc: Fix wakeirq sleeping function called from invalid context
+    - bus: ti-sysc: Fix sleeping function called from invalid context for RTC
+      quirk
+    - bus: ti-sysc: Do not disable on suspend for no-idle
+    - iio: adc: ad7780: Fix a resource handling path in 'ad7780_probe()'
+    - dmaengine: dw: Initialize channel before each transfer
+    - dmaengine: dmatest: stop completed threads when running without set channel
+    - spi: spi-sun6i: sun6i_spi_transfer_one(): fix setting of clock rate
+    - usb: gadget: udc: atmel: fix uninitialized read in debug printk
+    - staging: comedi: verify array index is correct before using it
+    - clk: mvebu: ARMADA_AP_CPU_CLK needs to select ARMADA_AP_CP_HELPER
+    - clk: AST2600: Add mux for EMMC clock
+    - NFS: Fix interrupted slots by sending a solo SEQUENCE operation
+    - fuse: don't ignore errors from fuse_writepages_fill()
+    - ARM: dts: Fix dcan driver probe failed on am437x platform
+    - Revert "thermal: mediatek: fix register index error"
+    - xprtrdma: fix incorrect header size calculations
+    - ARM: dts: socfpga: Align L2 cache-controller nodename with dtschema
+    - arm64: dts: spcfpga: Align GIC, NAND and UART nodenames with dtschema
+    - keys: asymmetric: fix error return code in software_key_query()
+    - regmap: debugfs: Don't sleep while atomic for fast_io regmaps
+    - copy_xstate_to_kernel: Fix typo which caused GDB regression
+    - arm: dts: mt7623: add phy-mode property for gmac2
+    - soc: qcom: socinfo: add missing soc_id sysfs entry
+    - habanalabs: Align protection bits configuration of all TPCs
+    - PCI/PM: Call .bridge_d3() hook only if non-NULL
+    - perf stat: Zero all the 'ena' and 'run' array slot stats for interval mode
+    - soc: qcom: rpmh: Update dirty flag only when data changes
+    - soc: qcom: rpmh: Invalidate SLEEP and WAKE TCSes before flushing new data
+    - soc: qcom: rpmh-rsc: Clear active mode configuration for wake TCS
+    - soc: qcom: rpmh-rsc: Allow using free WAKE TCS for active request
+    - RDMA/mlx5: Verify that QP is created with RQ or SQ
+    - mtd: rawnand: marvell: Fix the condition on a return code
+    - mtd: rawnand: marvell: Use nand_cleanup() when the device is not yet
+      registered
+    - mtd: rawnand: marvell: Fix probe error path
+    - mtd: rawnand: timings: Fix default tR_max and tCCS_min timings
+    - mtd: rawnand: brcmnand: correctly verify erased pages
+    - mtd: rawnand: brcmnand: fix CS0 layout
+    - mtd: rawnand: oxnas: Keep track of registered devices
+    - mtd: rawnand: oxnas: Unregister all devices on error
+    - mtd: rawnand: oxnas: Release all devices in the _remove() path
+    - clk: qcom: gcc: Add GPU and NPU clocks for SM8150
+    - clk: qcom: gcc: Add missing UFS clocks for SM8150
+    - slimbus: core: Fix mismatch in of_node_get/put
+    - HID: logitech-hidpp: avoid repeated "multiplier = " log messages
+    - HID: magicmouse: do not set up autorepeat
+    - HID: quirks: Always poll Obins Anne Pro 2 keyboard
+    - HID: quirks: Ignore Simply Automated UPB PIM
+    - ALSA: line6: Perform sanity check for each URB creation
+    - ALSA: line6: Sync the pending work cancel at disconnection
+    - ALSA: usb-audio: Fix race against the error recovery URB submission
+    - ALSA: hda/realtek - change to suitable link model for ASUS platform
+    - ALSA: hda/realtek: enable headset mic of ASUS ROG Zephyrus G14(G401) series
+      with ALC289
+    - ALSA: hda/realtek: Enable headset mic of Acer TravelMate B311R-31 with
+      ALC256
+    - ALSA: hda/realtek - Enable Speaker for ASUS UX533 and UX534
+    - ALSA: hda/realtek - Enable Speaker for ASUS UX563
+    - USB: c67x00: fix use after free in c67x00_giveback_urb
+    - usb: dwc2: Fix shutdown callback in platform
+    - 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
+    - virt: vbox: Fix VBGL_IOCTL_VMMDEV_REQUEST_BIG and _LOG req numbers to match
+      upstream
+    - virt: vbox: Fix guest capabilities mask check
+    - Revert "tty: xilinx_uartps: Fix missing id assignment to the console"
+    - virtio: virtio_console: add missing MODULE_DEVICE_TABLE() for rproc serial
+    - serial: mxs-auart: add missed iounmap() in probe failure and remove
+    - ovl: fix regression with re-formatted lower squashfs
+    - ovl: inode reference leak in ovl_is_inuse true case.
+    - ovl: relax WARN_ON() when decoding lower directory file handle
+    - ovl: fix unneeded call to ovl_change_flags()
+    - fuse: ignore 'data' argument of mount(..., MS_REMOUNT)
+    - fuse: use ->reconfigure() instead of ->remount_fs()
+    - fuse: Fix parameter for FS_IOC_{GET,SET}FLAGS
+    - Revert "zram: convert remaining CLASS_ATTR() to CLASS_ATTR_RO()"
+    - mei: bus: don't clean driver pointer
+    - Input: i8042 - add Lenovo XiaoXin Air 12 to i8042 nomux list
+    - uio_pdrv_genirq: Remove warning when irq is not specified
+    - uio_pdrv_genirq: fix use without device tree and no interrupt
+    - scsi: megaraid_sas: Remove undefined ENABLE_IRQ_POLL macro
+    - timer: Prevent base->clk from moving backward
+    - timer: Fix wheel index calculation on last level
+    - riscv: use 16KB kernel stack on 64-bit
+    - hwmon: (emc2103) fix unable to change fan pwm1_enable attribute
+    - powerpc/book3s64/pkeys: Fix pkey_access_permitted() for execute disable pkey
+    - powerpc/pseries/svm: Fix incorrect check for shared_lppaca_size
+    - intel_th: pci: Add Jasper Lake CPU support
+    - intel_th: pci: Add Tiger Lake PCH-H support
+    - intel_th: pci: Add Emmitsburg PCH support
+    - intel_th: Fix a NULL dereference when hub driver is not loaded
+    - dmaengine: fsl-edma: Fix NULL pointer exception in fsl_edma_tx_handler
+    - dmaengine: mcf-edma: Fix NULL pointer exception in mcf_edma_tx_handler
+    - dmaengine: fsl-edma-common: correct DSIZE_32BYTE
+    - misc: atmel-ssc: lock with mutex instead of spinlock
+    - thermal: int3403_thermal: Downgrade error message
+    - thermal/drivers/cpufreq_cooling: Fix wrong frequency converted from power
+    - arm64: ptrace: Override SPSR.SS when single-stepping is enabled
+    - arm64: ptrace: Consistently use pseudo-singlestep exceptions
+    - arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return
+    - sched: Fix unreliable rseq cpu_id for new tasks
+    - sched/fair: handle case of task_h_load() returning 0
+    - genirq/affinity: Handle affinity setting on inactive interrupts correctly
+    - drm/amdgpu/sdma5: fix wptr overwritten in ->get_wptr()
+    - drm/i915/gt: Ignore irq enabling on the virtual engines
+    - block: fix splitting segments on boundary masks
+    - block: fix get_max_segment_size() overflow on 32bit arch
+    - libceph: don't omit recovery_deletes in target_copy()
+    - rxrpc: Fix trace string
+    - spi: sprd: switch the sequence of setting WDG_LOAD_LOW and _HIGH
+    - ionic: export features for vlans to use
+    - iommu/vt-d: Make Intel SVM code 64-bit only
+    - drm/i915/gvt: Fix two CFL MMIO handling caused by regression.
+    - gpio: pca953x: disable regmap locking for automatic address incrementing
+    - Linux 5.4.53
+
+  * linux-libc-dev broken for crossbuilding, Multi-Arch:same violation
+    (LP: #1886188)
+    - [Packaging] Produce linux-libc-dev package for riscv64
+    - [Debian] Disallow building linux-libc-dev from linux-riscv
+
+  * [UBUNTU 20.04] DIF and DIX support in zfcp (s390x) is broken and the kernel
+    crashes unconditionally (LP: #1887124)
+    - scsi: zfcp: signal incomplete or error for sync exchange config/port data
+    - scsi: zfcp: diagnostics buffer caching and use for exchange port data
+    - scsi: zfcp: add diagnostics buffer for exchange config data
+    - scsi: zfcp: support retrieval of SFP Data via Exchange Port Data
+    - scsi: zfcp: introduce sysfs interface for diagnostics of local SFP
+      transceiver
+    - scsi: zfcp: implicitly refresh port-data diagnostics when reading sysfs
+    - scsi: zfcp: introduce sysfs interface to read the local B2B-Credit
+    - scsi: zfcp: implicitly refresh config-data diagnostics when reading sysfs
+    - scsi: zfcp: move maximum age of diagnostic buffers into a per-adapter
+      variable
+    - scsi: zfcp: proper indentation to reduce confusion in zfcp_erp_required_act
+    - scsi: zfcp: fix wrong data and display format of SFP+ temperature
+    - scsi: zfcp: expose fabric name as common fc_host sysfs attribute
+    - scsi: zfcp: wire previously driver-specific sysfs attributes also to fc_host
+    - scsi: zfcp: fix fc_host attributes that should be unknown on local link down
+    - scsi: zfcp: auto variables for dereferenced structs in open port handler
+    - scsi: zfcp: report FC Endpoint Security in sysfs
+    - scsi: zfcp: log FC Endpoint Security of connections
+    - scsi: zfcp: trace FC Endpoint Security of FCP devices and connections
+    - scsi: zfcp: enhance handling of FC Endpoint Security errors
+    - scsi: zfcp: log FC Endpoint Security errors
+    - scsi: zfcp: use fallthrough;
+    - scsi: zfcp: Move shost modification after QDIO (re-)open into fenced
+      function
+    - scsi: zfcp: Move shost updates during xconfig data handling into fenced
+      function
+    - scsi: zfcp: Move fc_host updates during xport data handling into fenced
+      function
+    - scsi: zfcp: Fence fc_host updates during link-down handling
+    - scsi: zfcp: Move p-t-p port allocation to after xport data
+    - scsi: zfcp: Fence adapter status propagation for common statuses
+    - scsi: zfcp: Fence early sysfs interfaces for accesses of shost objects
+    - scsi: zfcp: Move allocation of the shost object to after xconf- and xport-
+      data
+
+  * Enable Quectel EG95 LTE modem [2c7c:0195]  (LP: #1886744)
+    - net: usb: qmi_wwan: add support for Quectel EG95 LTE modem
+    - USB: serial: option: add Quectel EG95 LTE modem
+
+  * Kernel Regression between 5.4.0-26 and 5.4.0-40 causes laptop internal audio
+    devices to fail to load w/o unacceptable workaround (Lenovo IdeaPad 5
+    15IIL05) (LP: #1886341)
+    - ASoC: SOF: intel: hda: Modify signature for hda_codec_probe_bus()
+    - ASoC: SOF: Intel: drop HDA codec upon probe failure
+    - ASoC: SOF: Intel: hda: move i915 init earlier
+
+  * [UBUNTU 20.04] smc: SMC connections hang with later-level implementations
+    (LP: #1882088)
+    - net/smc: tolerate future SMCD versions
+
+  * zfs: backport AES-GCM performance accelleration (LP: #1881107)
+    - debian/dkms-versions: update ZFS dkms package version (LP: #1881107)
+
+  * Regression in kernel 4.15.0-91 causes kernel panic with Bcache
+    (LP: #1867916)
+    - bcache: check and adjust logical block size for backing devices
+
+  * [SRU][OEM-5.6/U] Fix r8117 firmware base issue (LP: #1885072)
+    - r8169: add helper r8168g_phy_param
+    - r8169: add support for RTL8117
+    - r8169: load firmware for RTL8168fp/RTL8117
+    - r8169: fix OCP access on RTL8117
+    - r8169: fix firmware not resetting tp->ocp_base
+
+  * [UBUNTU 20.04] Deflate counters reported by lscpumf are not valid or
+    available with perf (LP: #1881096)
+    - s390/cpum_cf: Add new extended counters for IBM z15
+
+  * shiftfs: O_TMPFILE reports ESTALE (LP: #1872757)
+    - SAUCE: shiftfs: prevent ESTALE for LOOKUP_JUMP lookups
+
+  * shiftfs: fix btrfs regression (LP: #1884767)
+    - SAUCE: Revert "UBUNTU: SAUCE: shiftfs: fix dentry revalidation"
+
+  * Focal update: v5.4.52 upstream stable release (LP: #1887853)
+    - KVM: s390: reduce number of IO pins to 1
+    - spi: spi-fsl-dspi: Adding shutdown hook
+    - spi: spi-fsl-dspi: Fix lockup if device is removed during SPI transfer
+    - regmap: fix alignment issue
+    - perf/x86/rapl: Move RAPL support to common x86 code
+    - perf/x86/rapl: Fix RAPL config variable bug
+    - [Packaging] module intel-rapl-perf rename
+    - ARM: dts: omap4-droid4: Fix spi configuration and increase rate
+    - drm/ttm: Fix dma_fence refcnt leak when adding move fence
+    - drm/tegra: hub: Do not enable orphaned window group
+    - gpu: host1x: Detach driver on unregister
+    - drm: mcde: Fix display initialization problem
+    - ASoC: SOF: Intel: add PCI ID for CometLake-S
+    - ALSA: hda: Intel: add missing PCI IDs for ICL-H, TGL-H and EKL
+    - spi: spidev: fix a race between spidev_release and spidev_remove
+    - spi: spidev: fix a potential use-after-free in spidev_release()
+    - net: ethernet: mvneta: Fix Serdes configuration for SoCs without comphy
+    - net: ethernet: mvneta: Add 2500BaseX support for SoCs without comphy
+    - ixgbe: protect ring accesses with READ- and WRITE_ONCE
+    - i40e: protect ring accesses with READ- and WRITE_ONCE
+    - ibmvnic: continue to init in CRQ reset returns H_CLOSED
+    - powerpc/kvm/book3s64: Fix kernel crash with nested kvm & DEBUG_VIRTUAL
+    - iommu/vt-d: Don't apply gfx quirks to untrusted devices
+    - drm: panel-orientation-quirks: Add quirk for Asus T101HA panel
+    - drm: panel-orientation-quirks: Use generic orientation-data for Acer S1003
+    - s390/kasan: fix early pgm check handler execution
+    - cifs: update ctime and mtime during truncate
+    - ARM: imx6: add missing put_device() call in imx6q_suspend_init()
+    - scsi: mptscsih: Fix read sense data size
+    - usb: dwc3: pci: Fix reference count leak in dwc3_pci_resume_work
+    - block: release bip in a right way in error path
+    - nvme-rdma: assign completion vector correctly
+    - x86/entry: Increase entry_stack size to a full page
+    - sched/core: Check cpus_mask, not cpus_ptr in __set_cpus_allowed_ptr(), to
+      fix mask corruption
+    - net: qrtr: Fix an out of bounds read qrtr_endpoint_post()
+    - gpio: pca953x: Override IRQ for one of the expanders on Galileo Gen 2
+    - gpio: pca953x: Fix GPIO resource leak on Intel Galileo Gen 2
+    - nl80211: don't return err unconditionally in nl80211_start_ap()
+    - drm/mediatek: Check plane visibility in atomic_update
+    - bpf, sockmap: RCU splat with redirect and strparser error or TLS
+    - bpf, sockmap: RCU dereferenced psock may be used outside RCU block
+    - netfilter: ipset: call ip_set_free() instead of kfree()
+    - net: mvneta: fix use of state->speed
+    - net: cxgb4: fix return error value in t4_prep_fw
+    - IB/sa: Resolv use-after-free in ib_nl_make_request()
+    - net: dsa: microchip: set the correct number of ports
+    - netfilter: conntrack: refetch conntrack after nf_conntrack_update()
+    - perf report TUI: Fix segmentation fault in perf_evsel__hists_browse()
+    - perf intel-pt: Fix recording PEBS-via-PT with registers
+    - perf intel-pt: Fix PEBS sample for XMM registers
+    - smsc95xx: check return value of smsc95xx_reset
+    - smsc95xx: avoid memory leak in smsc95xx_bind
+    - net: hns3: add a missing uninit debugfs when unload driver
+    - net: hns3: fix use-after-free when doing self test
+    - ALSA: compress: fix partial_drain completion state
+    - RDMA/siw: Fix reporting vendor_part_id
+    - arm64: kgdb: Fix single-step exception handling oops
+    - nbd: Fix memory leak in nbd_add_socket
+    - cxgb4: fix all-mask IP address comparison
+    - IB/mlx5: Fix 50G per lane indication
+    - qed: Populate nvm-file attributes while reading nvm config partition.
+    - net/mlx5: Fix eeprom support for SFP module
+    - net/mlx5e: Fix 50G per lane indication
+    - bnxt_en: fix NULL dereference in case SR-IOV configuration fails
+    - net: macb: fix wakeup test in runtime suspend/resume routines
+    - net: macb: mark device wake capable when "magic-packet" property present
+    - net: macb: fix call to pm_runtime in the suspend/resume functions
+    - mlxsw: spectrum_router: Remove inappropriate usage of WARN_ON()
+    - mlxsw: pci: Fix use-after-free in case of failed devlink reload
+    - IB/hfi1: Do not destroy hfi1_wq when the device is shut down
+    - IB/hfi1: Do not destroy link_wq when the device is shut down
+    - 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
+    - ALSA: usb-audio: Add implicit feedback quirk for RTX6001
+    - ALSA: hda/realtek - Fix Lenovo Thinkpad X1 Carbon 7th quirk subdevice id
+    - ALSA: hda/realtek - Enable audio jacks of Acer vCopperbox with ALC269VC
+    - ALSA: hda/realtek: Enable headset mic of Acer C20-820 with ALC269VC
+    - ALSA: hda/realtek: Enable headset mic of Acer Veriton N4660G with ALC269VC
+    - KVM: arm64: Fix definition of PAGE_HYP_DEVICE
+    - KVM: arm64: Stop clobbering x0 for HVC_SOFT_RESTART
+    - KVM: arm64: Annotate hyp NMI-related functions as __always_inline
+    - KVM: x86: bit 8 of non-leaf PDPEs is not reserved
+    - KVM: x86: Inject #GP if guest attempts to toggle CR4.LA57 in 64-bit mode
+    - KVM: x86: Mark CR4.TSD as being possibly owned by the guest
+    - KVM: arm64: Fix kvm_reset_vcpu() return code being incorrect with SVE
+    - kallsyms: Refactor kallsyms_show_value() to take cred
+    - module: Refactor section attr into bin attribute
+    - module: Do not expose section addresses to non-CAP_SYSLOG
+    - kprobes: Do not expose probe addresses to non-CAP_SYSLOG
+    - bpf: Check correct cred for CAP_SYSLOG in bpf_dump_raw_ok()
+    - btrfs: fix fatal extent_buffer readahead vs releasepage race
+    - btrfs: fix double put of block group with nocow
+    - drm/radeon: fix double free
+    - drm/amdgpu: don't do soft recovery if gpu_recovery=0
+    - dm: use noio when sending kobject event
+    - mmc: meson-gx: limit segments to 1 when dram-access-quirk is needed
+    - ARC: entry: fix potential EFA clobber when TIF_SYSCALL_TRACE
+    - ARC: elf: use right ELF_ARCH
+    - s390/setup: init jump labels before command line parsing
+    - s390/mm: fix huge pte soft dirty copying
+    - blk-mq: consider non-idle request as "inflight" in blk_mq_rq_inflight()
+    - dm writecache: reject asynchronous pmem devices
+    - perf scripts python: export-to-postgresql.py: Fix struct.pack() int argument
+    - perf scripts python: exported-sql-viewer.py: Fix zero id in call graph
+      'Find' result
+    - perf scripts python: exported-sql-viewer.py: Fix zero id in call tree 'Find'
+      result
+    - perf scripts python: exported-sql-viewer.py: Fix unexpanded 'Find' result
+    - pwm: jz4740: Fix build failure
+    - s390: Change s390_kernel_write() return type to match memcpy()
+    - s390/maccess: add no DAT mode to kernel_write
+    - Linux 5.4.52
+
+  * Focal update: v5.4.45 upstream stable release (LP: #1882802) // Focal
+    update: v5.4.52 upstream stable release (LP: #1887853)
+    - Revert "cgroup: Add memory barriers to plug cgroup_rstat_updated() race
+      window"
+
+  * Focal update: v5.4.51 upstream stable release (LP: #1886995)
+    - io_uring: make sure async workqueue is canceled on exit
+    - mm: fix swap cache node allocation mask
+    - EDAC/amd64: Read back the scrub rate PCI register on F15h
+    - usbnet: smsc95xx: Fix use-after-free after removal
+    - sched/debug: Make sd->flags sysctl read-only
+    - mm/slub.c: fix corrupted freechain in deactivate_slab()
+    - mm/slub: fix stack overruns with SLUB_STATS
+    - rxrpc: Fix race between incoming ACK parser and retransmitter
+    - usb: usbtest: fix missing kfree(dev->buf) in usbtest_disconnect
+    - tools lib traceevent: Add append() function helper for appending strings
+    - tools lib traceevent: Handle __attribute__((user)) in field names
+    - s390/debug: avoid kernel warning on too large number of pages
+    - nvme-multipath: set bdi capabilities once
+    - nvme-multipath: fix deadlock between ana_work and scan_work
+    - nvme-multipath: fix deadlock due to head->lock
+    - nvme-multipath: fix bogus request queue reference put
+    - kgdb: Avoid suspicious RCU usage warning
+    - selftests: tpm: Use /bin/sh instead of /bin/bash
+    - crypto: af_alg - fix use-after-free in af_alg_accept() due to bh_lock_sock()
+    - drm/msm/dpu: fix error return code in dpu_encoder_init
+    - rxrpc: Fix afs large storage transmission performance drop
+    - RDMA/counter: Query a counter before release
+    - cxgb4: use unaligned conversion for fetching timestamp
+    - cxgb4: parse TC-U32 key values and masks natively
+    - cxgb4: fix endian conversions for L4 ports in filters
+    - cxgb4: use correct type for all-mask IP address comparison
+    - cxgb4: fix SGE queue dump destination buffer context
+    - hwmon: (max6697) Make sure the OVERT mask is set correctly
+    - hwmon: (acpi_power_meter) Fix potential memory leak in
+      acpi_power_meter_add()
+    - thermal/drivers/mediatek: Fix bank number settings on mt8183
+    - thermal/drivers/rcar_gen3: Fix undefined temperature if negative
+    - nfsd4: fix nfsdfs reference count loop
+    - nfsd: fix nfsdfs inode reference count leak
+    - drm: sun4i: hdmi: Remove extra HPD polling
+    - virtio-blk: free vblk-vqs in error path of virtblk_probe()
+    - SMB3: Honor 'posix' flag for multiuser mounts
+    - nvme: fix identify error status silent ignore
+    - nvme: fix a crash in nvme_mpath_add_disk
+    - samples/vfs: avoid warning in statx override
+    - i2c: algo-pca: Add 0x78 as SCL stuck low status for PCA9665
+    - i2c: mlxcpld: check correct size of maximum RECV_LEN packet
+    - spi: spi-fsl-dspi: Fix external abort on interrupt in resume or exit paths
+    - nfsd: apply umask on fs without ACL support
+    - Revert "ALSA: usb-audio: Improve frames size computation"
+    - SMB3: Honor 'seal' flag for multiuser mounts
+    - SMB3: Honor persistent/resilient handle flags for multiuser mounts
+    - SMB3: Honor lease disabling for multiuser mounts
+    - SMB3: Honor 'handletimeout' flag for multiuser mounts
+    - cifs: Fix the target file was deleted when rename failed.
+    - MIPS: lantiq: xway: sysctrl: fix the GPHY clock alias names
+    - MIPS: Add missing EHB in mtc0 -> mfc0 sequence for DSPen
+    - drm/amd/display: Only revalidate bandwidth on medium and fast updates
+    - drm/amdgpu: use %u rather than %d for sclk/mclk
+    - drm/amdgpu/atomfirmware: fix vram_info fetching for renoir
+    - dma-buf: Move dma_buf_release() from fops to dentry_ops
+    - irqchip/gic: Atomically update affinity
+    - mm, compaction: fully assume capture is not NULL in compact_zone_order()
+    - mm, compaction: make capture control handling safe wrt interrupts
+    - x86/resctrl: Fix memory bandwidth counter width for AMD
+    - dm zoned: assign max_io_len correctly
+    - [Config] updateconfigs for EFI_CUSTOM_SSDT_OVERLAYS
+    - efi: Make it possible to disable efivar_ssdt entirely
+    - Linux 5.4.51
+
+  * Focal update: v5.4.50 upstream stable release (LP: #1885942)
+    - block/bio-integrity: don't free 'buf' if bio_integrity_add_page() failed
+    - enetc: Fix tx rings bitmap iteration range, irq handling
+    - geneve: allow changing DF behavior after creation
+    - ibmveth: Fix max MTU limit
+    - mld: fix memory leak in ipv6_mc_destroy_dev()
+    - mvpp2: ethtool rxtx stats fix
+    - net: bridge: enfore alignment for ethernet address
+    - net: core: reduce recursion limit value
+    - net: Do not clear the sock TX queue in sk_set_socket()
+    - net: fix memleak in register_netdevice()
+    - net: Fix the arp error in some cases
+    - net: increment xmit_recursion level in dev_direct_xmit()
+    - net: usb: ax88179_178a: fix packet alignment padding
+    - openvswitch: take into account de-fragmentation/gso_size in
+      execute_check_pkt_len
+    - rocker: fix incorrect error handling in dma_rings_init
+    - rxrpc: Fix notification call on completion of discarded calls
+    - sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
+    - tcp: don't ignore ECN CWR on pure ACK
+    - tcp: grow window for OOO packets only for SACK flows
+    - tg3: driver sleeps indefinitely when EEH errors exceed eeh_max_freezes
+    - ip6_gre: fix use-after-free in ip6gre_tunnel_lookup()
+    - net: phy: Check harder for errors in get_phy_id()
+    - ip_tunnel: fix use-after-free in ip_tunnel_lookup()
+    - sch_cake: don't try to reallocate or unshare skb unconditionally
+    - sch_cake: don't call diffserv parsing code when it is not needed
+    - sch_cake: fix a few style nits
+    - tcp_cubic: fix spurious HYSTART_DELAY exit upon drop in min RTT
+    - Revert "i2c: tegra: Fix suspending in active runtime PM state"
+    - btrfs: fix a block group ref counter leak after failure to remove block
+      group
+    - net: sched: export __netdev_watchdog_up()
+    - fix a braino in "sparc32: fix register window handling in
+      genregs32_[gs]et()"
+    - ALSA: usb-audio: Fix potential use-after-free of streams
+    - binder: fix null deref of proc->context
+    - 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
+    - USB: ehci: reopen solution for Synopsys HC bug
+    - usb: host: xhci-mtk: avoid runtime suspend when removing hcd
+    - xhci: Poll for U0 after disabling USB2 LPM
+    - usb: host: ehci-exynos: Fix error check in exynos_ehci_probe()
+    - usb: typec: tcpci_rt1711h: avoid screaming irq causing boot hangs
+    - ALSA: usb-audio: Add implicit feedback quirk for SSL2+.
+    - ALSA: usb-audio: add quirk for Denon DCD-1500RE
+    - ALSA: usb-audio: add quirk for Samsung USBC Headset (AKG)
+    - ALSA: usb-audio: Fix OOB access of mixer element list
+    - usb: cdns3: trace: using correct dir value
+    - usb: cdns3: ep0: fix the test mode set incorrectly
+    - usb: cdns3: ep0: add spinlock for cdns3_check_new_setup
+    - scsi: qla2xxx: Keep initiator ports after RSCN
+    - scsi: zfcp: Fix panic on ERP timeout for previously dismissed ERP action
+    - cifs: Fix cached_fid refcnt leak in open_shroot
+    - cifs/smb3: Fix data inconsistent when punch hole
+    - cifs/smb3: Fix data inconsistent when zero file range
+    - xhci: Fix incorrect EP_STATE_MASK
+    - xhci: Fix enumeration issue when setting max packet size for FS devices.
+    - xhci: Return if xHCI doesn't support LPM
+    - cdc-acm: Add DISABLE_ECHO quirk for Microchip/SMSC chip
+    - loop: replace kill_bdev with invalidate_bdev
+    - IB/mad: Fix use after free when destroying MAD agent
+    - IB/hfi1: Fix module use count flaw due to leftover module put calls
+    - bus: ti-sysc: Flush posted write on enable and disable
+    - bus: ti-sysc: Ignore clockactivity unless specified as a quirk
+    - ARM: OMAP2+: Fix legacy mode dss_reset
+    - xfrm: Fix double ESP trailer insertion in IPsec crypto offload.
+    - ASoC: q6asm: handle EOS correctly
+    - efi/tpm: Verify event log header before parsing
+    - efi/esrt: Fix reference count leak in esre_create_sysfs_entry.
+    - ASoc: q6afe: add support to get port direction
+    - ASoC: qcom: common: set correct directions for dailinks
+    - regualtor: pfuze100: correct sw1a/sw2 on pfuze3000
+    - RDMA/siw: Fix pointer-to-int-cast warning in siw_rx_pbl()
+    - ASoC: fsl_ssi: Fix bclk calculation for mono channel
+    - samples/bpf: xdp_redirect_cpu: Set MAX_CPUS according to NR_CPUS
+    - bpf, xdp, samples: Fix null pointer dereference in *_user code
+    - ARM: dts: am335x-pocketbeagle: Fix mmc0 Write Protect
+    - ARM: dts: Fix duovero smsc interrupt for suspend
+    - x86/resctrl: Fix a NULL vs IS_ERR() static checker warning in
+      rdt_cdp_peer_get()
+    - regmap: Fix memory leak from regmap_register_patch
+    - devmap: Use bpf_map_area_alloc() for allocating hash buckets
+    - bpf: Don't return EINVAL from {get,set}sockopt when optlen > PAGE_SIZE
+    - ARM: dts: NSP: Correct FA2 mailbox node
+    - rxrpc: Fix handling of rwind from an ACK packet
+    - RDMA/rvt: Fix potential memory leak caused by rvt_alloc_rq
+    - RDMA/qedr: Fix KASAN: use-after-free in ucma_event_handler+0x532
+    - RDMA/cma: Protect bind_list and listen_list while finding matching cm id
+    - ASoC: rockchip: Fix a reference count leak.
+    - s390/qeth: fix error handling for isolation mode cmds
+    - RDMA/mad: Fix possible memory leak in ib_mad_post_receive_mads()
+    - selftests/net: report etf errors correctly
+    - iommu/vt-d: Enable PCI ACS for platform opt in hint
+    - iommu/vt-d: Update scalable mode paging structure coherency
+    - net: qed: fix left elements count calculation
+    - net: qed: fix async event callbacks unregistering
+    - net: qede: stop adding events on an already destroyed workqueue
+    - net: qed: fix NVMe login fails over VFs
+    - net: qed: fix excessive QM ILT lines consumption
+    - net: qede: fix PTP initialization on recovery
+    - net: qede: fix use-after-free on recovery and AER handling
+    - cxgb4: move handling L2T ARP failures to caller
+    - ARM: imx5: add missing put_device() call in imx_suspend_alloc_ocram()
+    - scsi: lpfc: Avoid another null dereference in lpfc_sli4_hba_unset()
+    - usb: gadget: udc: Potential Oops in error handling code
+    - usb: renesas_usbhs: getting residue from callback_result
+    - nvme: don't protect ns mutation with ns->head->lock
+    - netfilter: ipset: fix unaligned atomic access
+    - net: bcmgenet: use hardware padding of runt frames
+    - clk: sifive: allocate sufficient memory for struct __prci_data
+    - i2c: fsi: Fix the port number field in status register
+    - i2c: core: check returned size of emulated smbus block read
+    - afs: Fix storage of cell names
+    - sched/deadline: Initialize ->dl_boosted
+    - sched/core: Fix PI boosting between RT and DEADLINE tasks
+    - sata_rcar: handle pm_runtime_get_sync failure cases
+    - ata/libata: Fix usage of page address by page_address in
+      ata_scsi_mode_select_xlat function
+    - drm/amd/display: Use kfree() to free rgb_user in
+      calculate_user_regamma_ramp()
+    - riscv/atomic: Fix sign extension for RV64I
+    - hwrng: ks-sa - Fix runtime PM imbalance on error
+    - ibmvnic: Harden device login requests
+    - net: alx: fix race condition in alx_remove
+    - test_objagg: Fix potential memory leak in error handling
+    - pinctrl: qcom: spmi-gpio: fix warning about irq chip reusage
+    - pinctrl: tegra: Use noirq suspend/resume callbacks
+    - s390/ptrace: pass invalid syscall numbers to tracing
+    - s390/ptrace: fix setting syscall number
+    - s390/vdso: Use $(LD) instead of $(CC) to link vDSO
+    - s390/vdso: fix vDSO clock_getres()
+    - arm64: sve: Fix build failure when ARM64_SVE=y and SYSCTL=n
+    - kbuild: improve cc-option to clean up all temporary files
+    - recordmcount: support >64k sections
+    - kprobes: Suppress the suspicious RCU warning on kprobes
+    - blktrace: break out of blktrace setup on concurrent calls
+    - block: update hctx map when use multiple maps
+    - RISC-V: Don't allow write+exec only page mapping request in mmap
+    - ALSA: hda: Add NVIDIA codec IDs 9a & 9d through a0 to patch table
+    - ALSA: hda/realtek - Add quirk for MSI GE63 laptop
+    - ACPI: sysfs: Fix pm_profile_attr type
+    - erofs: fix partially uninitialized misuse in z_erofs_onlinepage_fixup
+    - KVM: X86: Fix MSR range of APIC registers in X2APIC mode
+    - KVM: nVMX: Plumb L2 GPA through to PML emulation
+    - KVM: VMX: Stop context switching MSR_IA32_UMWAIT_CONTROL
+    - x86/cpu: Use pinning mask for CR4 bits needing to be 0
+    - x86/asm/64: Align start of __clear_user() loop to 16-bytes
+    - btrfs: fix bytes_may_use underflow when running balance and scrub in
+      parallel
+    - btrfs: fix data block group relocation failure due to concurrent scrub
+    - btrfs: check if a log root exists before locking the log_mutex on unlink
+    - btrfs: fix failure of RWF_NOWAIT write into prealloc extent beyond eof
+    - mm/slab: use memzero_explicit() in kzfree()
+    - ocfs2: avoid inode removal while nfsd is accessing it
+    - ocfs2: load global_inode_alloc
+    - ocfs2: fix value of OCFS2_INVALID_SLOT
+    - ocfs2: fix panic on nfs server over ocfs2
+    - mm/memcontrol.c: add missed css_put()
+    - arm64: perf: Report the PC value in REGS_ABI_32 mode
+    - arm64: dts: imx8mm-evk: correct ldo1/ldo2 voltage range
+    - arm64: dts: imx8mn-ddr4-evk: correct ldo1/ldo2 voltage range
+    - tracing: Fix event trigger to accept redundant spaces
+    - ring-buffer: Zero out time extend if it is nested and not absolute
+    - drm/amd: fix potential memleak in err branch
+    - drm: rcar-du: Fix build error
+    - drm/radeon: fix fb_div check in ni_init_smc_spll_table()
+    - drm/amdgpu: add fw release for sdma v5_0
+    - Staging: rtl8723bs: prevent buffer overflow in update_sta_support_rate()
+    - 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
+    - xprtrdma: Fix handling of RDMA_ERROR replies
+    - dm writecache: correct uncommitted_block when discarding uncommitted entry
+    - dm writecache: add cond_resched to loop in persistent_memory_claim()
+    - xfs: add agf freeblocks verify in xfs_agf_verify
+    - Revert "tty: hvc: Fix data abort due to race in hvc_open"
+    - Linux 5.4.50
+
+  * Focal update: v5.4.49 upstream stable release (LP: #1885322)
+    - power: supply: bq24257_charger: Replace depends on REGMAP_I2C with select
+    - clk: sunxi: Fix incorrect usage of round_down()
+    - ASoC: tegra: tegra_wm8903: Support nvidia, headset property
+    - i2c: piix4: Detect secondary SMBus controller on AMD AM4 chipsets
+    - ASoC: SOF: imx8: Fix randbuild error
+    - iio: pressure: bmp280: Tolerate IRQ before registering
+    - remoteproc: Fix IDR initialisation in rproc_alloc()
+    - clk: qcom: msm8916: Fix the address location of pll->config_reg
+    - ASoC: fsl_esai: Disable exception interrupt before scheduling tasklet
+    - backlight: lp855x: Ensure regulators are disabled on probe failure
+    - ARM: dts: renesas: Fix IOMMU device node names
+    - ASoC: davinci-mcasp: Fix dma_chan refcnt leak when getting dma type
+    - ARM: integrator: Add some Kconfig selections
+    - ARM: dts: stm32: Add missing ethernet PHY reset on AV96
+    - scsi: core: free sgtables in case command setup fails
+    - scsi: qedi: Check for buffer overflow in qedi_set_path()
+    - arm64: dts: meson: fixup SCP sram nodes
+    - ALSA: isa/wavefront: prevent out of bounds write in ioctl
+    - PCI: Allow pci_resize_resource() for devices on root bus
+    - scsi: qla2xxx: Fix issue with adapter's stopping state
+    - Input: edt-ft5x06 - fix get_default register write access
+    - powerpc/kasan: Fix stack overflow by increasing THREAD_SHIFT
+    - rtc: mc13xxx: fix a double-unlock issue
+    - iio: bmp280: fix compensation of humidity
+    - f2fs: report delalloc reserve as non-free in statfs for project quota
+    - i2c: pxa: clear all master action bits in i2c_pxa_stop_message()
+    - remoteproc: qcom_q6v5_mss: map/unmap mpss segments before/after use
+    - clk: samsung: Mark top ISP and CAM clocks on Exynos542x as critical
+    - usblp: poison URBs upon disconnect
+    - serial: 8250: Fix max baud limit in generic 8250 port
+    - misc: fastrpc: Fix an incomplete memory release in fastrpc_rpmsg_probe()
+    - misc: fastrpc: fix potential fastrpc_invoke_ctx leak
+    - dm mpath: switch paths in dm_blk_ioctl() code path
+    - arm64: dts: armada-3720-turris-mox: forbid SDR104 on SDIO for FCC purposes
+    - arm64: dts: armada-3720-turris-mox: fix SFP binding
+    - arm64: dts: juno: Fix GIC child nodes
+    - pinctrl: ocelot: Fix GPIO interrupt decoding on Jaguar2
+    - clk: renesas: cpg-mssr: Fix STBCR suspend/resume handling
+    - ASoC: SOF: Do nothing when DSP PM callbacks are not set
+    - arm64: dts: fvp: Fix GIC child nodes
+    - PCI: aardvark: Don't blindly enable ASPM L0s and don't write to read-only
+      register
+    - ps3disk: use the default segment boundary
+    - arm64: dts: fvp/juno: Fix node address fields
+    - vfio/pci: fix memory leaks in alloc_perm_bits()
+    - coresight: tmc: Fix TMC mode read in tmc_read_prepare_etb()
+    - RDMA/mlx5: Add init2init as a modify command
+    - scsi: hisi_sas: Do not reset phy timer to wait for stray phy up
+    - PCI: pci-bridge-emul: Fix PCIe bit conflicts
+    - m68k/PCI: Fix a memory leak in an error handling path
+    - gpio: dwapb: Call acpi_gpiochip_free_interrupts() on GPIO chip de-
+      registration
+    - usb: gadget: core: sync interrupt before unbind the udc
+    - powerpc/ptdump: Add _PAGE_COHERENT flag
+    - mfd: wm8994: Fix driver operation if loaded as modules
+    - scsi: cxgb3i: Fix some leaks in init_act_open()
+    - clk: zynqmp: fix memory leak in zynqmp_register_clocks
+    - scsi: lpfc: Fix lpfc_nodelist leak when processing unsolicited event
+    - scsi: vhost: Notify TCM about the maximum sg entries supported per command
+    - clk: clk-flexgen: fix clock-critical handling
+    - IB/mlx5: Fix DEVX support for MLX5_CMD_OP_INIT2INIT_QP command
+    - powerpc/perf/hv-24x7: Fix inconsistent output values incase multiple hv-24x7
+      events run
+    - nfsd: Fix svc_xprt refcnt leak when setup callback client failed
+    - PCI: vmd: Filter resource type bits from shadow register
+    - RDMA/core: Fix several reference count leaks.
+    - cifs: set up next DFS target before generic_ip_connect()
+    - ASoC: qcom: q6asm-dai: kCFI fix
+    - powerpc/crashkernel: Take "mem=" option into account
+    - pwm: img: Call pm_runtime_put() in pm_runtime_get_sync() failed case
+    - sparc32: mm: Don't try to free page-table pages if ctor() fails
+    - yam: fix possible memory leak in yam_init_driver
+    - NTB: ntb_pingpong: Choose doorbells based on port number
+    - NTB: Fix the default port and peer numbers for legacy drivers
+    - mksysmap: Fix the mismatch of '.L' symbols in System.map
+    - apparmor: fix introspection of of task mode for unconfined tasks
+    - net: dsa: lantiq_gswip: fix and improve the unsupported interface error
+    - f2fs: handle readonly filesystem in f2fs_ioc_shutdown()
+    - ASoC: meson: add missing free_irq() in error path
+    - bpf, sockhash: Fix memory leak when unlinking sockets in sock_hash_free
+    - scsi: sr: Fix sr_probe() missing deallocate of device minor
+    - scsi: ibmvscsi: Don't send host info in adapter info MAD after LPM
+    - x86/purgatory: Disable various profiling and sanitizing options
+    - staging: greybus: fix a missing-check bug in gb_lights_light_config()
+    - arm64: dts: mt8173: fix unit name warnings
+    - scsi: qedi: Do not flush offload work if ARP not resolved
+    - arm64: dts: qcom: msm8916: remove unit name for thermal trip points
+    - ARM: dts: sun8i-h2-plus-bananapi-m2-zero: Fix led polarity
+    - RDMA/mlx5: Fix udata response upon SRQ creation
+    - gpio: dwapb: Append MODULE_ALIAS for platform driver
+    - scsi: qedf: Fix crash when MFW calls for protocol stats while function is
+      still probing
+    - pinctrl: rza1: Fix wrong array assignment of rza1l_swio_entries
+    - virtiofs: schedule blocking async replies in separate worker
+    - arm64: dts: qcom: fix pm8150 gpio interrupts
+    - firmware: qcom_scm: fix bogous abuse of dma-direct internals
+    - staging: gasket: Fix mapping refcnt leak when put attribute fails
+    - staging: gasket: Fix mapping refcnt leak when register/store fails
+    - ALSA: usb-audio: Improve frames size computation
+    - ALSA: usb-audio: Fix racy list management in output queue
+    - s390/qdio: put thinint indicator after early error
+    - tty: hvc: Fix data abort due to race in hvc_open
+    - slimbus: ngd: get drvdata from correct device
+    - clk: meson: meson8b: Fix the first parent of vid_pll_in_sel
+    - clk: meson: meson8b: Fix the polarity of the RESET_N lines
+    - clk: meson: meson8b: Fix the vclk_div{1, 2, 4, 6, 12}_en gate bits
+    - gpio: pca953x: fix handling of automatic address incrementing
+    - thermal/drivers/ti-soc-thermal: Avoid dereferencing ERR_PTR
+    - clk: meson: meson8b: Don't rely on u-boot to init all GP_PLL registers
+    - ASoC: max98373: reorder max98373_reset() in resume
+    - soundwire: slave: don't init debugfs on device registration error
+    - HID: intel-ish-hid: avoid bogus uninitialized-variable warning
+    - usb: dwc3: gadget: Properly handle ClearFeature(halt)
+    - usb: dwc3: gadget: Properly handle failed kick_transfer
+    - staging: wilc1000: Increase the size of wid_list array
+    - staging: sm750fb: add missing case while setting FB_VISUAL
+    - PCI: v3-semi: Fix a memory leak in v3_pci_probe() error handling paths
+    - 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: rcar: Fix incorrect programming of OB windows
+    - PCI/ASPM: Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges
+    - scsi: qla2xxx: Fix warning after FC target reset
+    - ALSA: firewire-lib: fix invalid assignment to union data for directional
+      parameter
+    - power: supply: lp8788: Fix an error handling path in
+      'lp8788_charger_probe()'
+    - power: supply: smb347-charger: IRQSTAT_D is volatile
+    - ASoC: SOF: core: fix error return code in sof_probe_continue()
+    - arm64: dts: msm8996: Fix CSI IRQ types
+    - scsi: target: loopback: Fix READ with data and sensebytes
+    - scsi: mpt3sas: Fix double free warnings
+    - SoC: rsnd: add interrupt support for SSI BUSIF buffer
+    - ASoC: ux500: mop500: Fix some refcounted resources issues
+    - ASoC: ti: omap-mcbsp: Fix an error handling path in 'asoc_mcbsp_probe()'
+    - pinctrl: rockchip: fix memleak in rockchip_dt_node_to_map
+    - dlm: remove BUG() before panic()
+    - USB: ohci-sm501: fix error return code in ohci_hcd_sm501_drv_probe()
+    - clk: ti: composite: fix memory leak
+    - PCI: Fix pci_register_host_bridge() device_register() error handling
+    - powerpc/64: Don't initialise init_task->thread.regs
+    - tty: n_gsm: Fix SOF skipping
+    - tty: n_gsm: Fix waking up upper tty layer when room available
+    - ALSA: usb-audio: Add duplex sound support for USB devices using implicit
+      feedback
+    - HID: Add quirks for Trust Panora Graphic Tablet
+    - PCI/PM: Assume ports without DLL Link Active train links in 100 ms
+    - habanalabs: increase timeout during reset
+    - ipmi: use vzalloc instead of kmalloc for user creation
+    - powerpc/64s/exception: Fix machine check no-loss idle wakeup
+    - powerpc/pseries/ras: Fix FWNMI_VALID off by one
+    - drivers: phy: sr-usb: do not use internal fsm for USB2 phy init
+    - powerpc/ps3: Fix kexec shutdown hang
+    - vfio-pci: Mask cap zero
+    - usb/ohci-platform: Fix a warning when hibernating
+    - drm/msm/mdp5: Fix mdp5_init error path for failed mdp5_kms allocation
+    - ASoC: Intel: bytcr_rt5640: Add quirk for Toshiba Encore WT8-A tablet
+    - USB: host: ehci-mxc: Add error handling in ehci_mxc_drv_probe()
+    - tty: n_gsm: Fix bogus i++ in gsm_data_kick
+    - fpga: dfl: afu: Corrected error handling levels
+    - clk: samsung: exynos5433: Add IGNORE_UNUSED flag to sclk_i2s1
+    - RDMA/hns: Bugfix for querying qkey
+    - RDMA/hns: Fix cmdq parameter of querying pf timer resource
+    - scsi: target: tcmu: Userspace must not complete queued commands
+    - firmware: imx: scu: Fix possible memory leak in imx_scu_probe()
+    - fuse: fix copy_file_range cache issues
+    - fuse: copy_file_range should truncate cache
+    - arm64: tegra: Fix ethernet phy-mode for Jetson Xavier
+    - arm64: tegra: Fix flag for 64-bit resources in 'ranges' property
+    - powerpc/64s/pgtable: fix an undefined behaviour
+    - dm zoned: return NULL if dmz_get_zone_for_reclaim() fails to find a zone
+    - PCI/PTM: Inherit Switch Downstream Port PTM settings from Upstream Port
+    - PCI: dwc: Fix inner MSI IRQ domain registration
+    - PCI: amlogic: meson: Don't use FAST_LINK_MODE to set up link
+    - IB/cma: Fix ports memory leak in cma_configfs
+    - 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.
+    - usb: gadget: Fix issue with config_ep_by_speed function
+    - scripts: headers_install: Exit with error on config leak
+    - RDMA/iw_cxgb4: cleanup device debugfs entries on ULD remove
+    - x86/apic: Make TSC deadline timer detection message visible
+    - mfd: stmfx: Reset chip on resume as supply was disabled
+    - mfd: stmfx: Fix stmfx_irq_init error path
+    - mfd: stmfx: Disable IRQ in suspend to avoid spurious interrupt
+    - powerpc/32s: Don't warn when mapping RO data ROX.
+    - ASoC: fix incomplete error-handling in img_i2s_in_probe.
+    - scsi: target: tcmu: Fix a use after free in tcmu_check_expired_queue_cmd()
+    - clk: bcm2835: Fix return type of bcm2835_register_gate
+    - scsi: ufs-qcom: Fix scheduling while atomic issue
+    - KVM: PPC: Book3S HV: Ignore kmemleak false positives
+    - KVM: PPC: Book3S: Fix some RCU-list locks
+    - clk: sprd: return correct type of value for _sprd_pll_recalc_rate
+    - clk: ast2600: Fix AHB clock divider for A1
+    - misc: xilinx-sdfec: improve get_user_pages_fast() error handling
+    - /dev/mem: Revoke mappings when a driver claims the region
+    - net: sunrpc: Fix off-by-one issues in 'rpc_ntop6'
+    - NFSv4.1 fix rpc_call_done assignment for BIND_CONN_TO_SESSION
+    - of: Fix a refcounting bug in __of_attach_node_sysfs()
+    - input: i8042 - Remove special PowerPC handling
+    - powerpc/4xx: Don't unmap NULL mbase
+    - extcon: adc-jack: Fix an error handling path in 'adc_jack_probe()'
+    - ASoC: fsl_asrc_dma: Fix dma_chan leak when config DMA channel failed
+    - vfio/mdev: Fix reference count leak in add_mdev_supported_type
+    - rtc: rv3028: Add missed check for devm_regmap_init_i2c()
+    - mailbox: zynqmp-ipi: Fix NULL vs IS_ERR() check in zynqmp_ipi_mbox_probe()
+    - rxrpc: Adjust /proc/net/rxrpc/calls to display call->debug_id not user_ID
+    - openrisc: Fix issue with argument clobbering for clone/fork
+    - drm/nouveau/disp/gm200-: fix NV_PDISP_SOR_HDMI2_CTRL(n) selection
+    - ceph: don't return -ESTALE if there's still an open file
+    - nfsd4: make drc_slab global, not per-net
+    - gfs2: Allow lock_nolock mount to specify jid=X
+    - scsi: iscsi: Fix reference count leak in iscsi_boot_create_kobj
+    - scsi: ufs: Don't update urgent bkops level when toggling auto bkops
+    - pinctrl: imxl: Fix an error handling path in 'imx1_pinctrl_core_probe()'
+    - pinctrl: freescale: imx: Fix an error handling path in 'imx_pinctrl_probe()'
+    - nfsd: safer handling of corrupted c_type
+    - drm/amd/display: Revalidate bandwidth before commiting DC updates
+    - crypto: omap-sham - add proper load balancing support for multicore
+    - geneve: change from tx_error to tx_dropped on missing metadata
+    - lib/zlib: remove outdated and incorrect pre-increment optimization
+    - include/linux/bitops.h: avoid clang shift-count-overflow warnings
+    - selftests/vm/pkeys: fix alloc_random_pkey() to make it really random
+    - blktrace: use errno instead of bi_status
+    - blktrace: fix endianness in get_pdu_int()
+    - blktrace: fix endianness for blk_log_remap()
+    - gfs2: fix use-after-free on transaction ail lists
+    - net: marvell: Fix OF_MDIO config check
+    - ntb_perf: pass correct struct device to dma_alloc_coherent
+    - ntb_tool: pass correct struct device to dma_alloc_coherent
+    - NTB: ntb_tool: reading the link file should not end in a NULL byte
+    - NTB: Revert the change to use the NTB device dev for DMA allocations
+    - NTB: perf: Don't require one more memory window than number of peers
+    - NTB: perf: Fix support for hardware that doesn't have port numbers
+    - NTB: perf: Fix race condition when run with ntb_test
+    - NTB: ntb_test: Fix bug when counting remote files
+    - i2c: icy: Fix build with CONFIG_AMIGA_PCMCIA=n
+    - drivers/perf: hisi: Fix wrong value for all counters enable
+    - selftests/net: in timestamping, strncpy needs to preserve null byte
+    - f2fs: don't return vmalloc() memory from f2fs_kmalloc()
+    - afs: Fix memory leak in afs_put_sysnames()
+    - ASoC: core: only convert non DPCM link to DPCM link
+    - ASoC: SOF: nocodec: conditionally set dpcm_capture/dpcm_playback flags
+    - ASoC: Intel: bytcr_rt5640: Add quirk for Toshiba Encore WT10-A tablet
+    - ASoC: rt5645: Add platform-data for Asus T101HA
+    - bpf/sockmap: Fix kernel panic at __tcp_bpf_recvmsg
+    - bpf, sockhash: Synchronize delete from bucket list on map free
+    - tracing/probe: Fix bpf_task_fd_query() for kprobes and uprobes
+    - drm/sun4i: hdmi ddc clk: Fix size of m divider
+    - libbpf: Handle GCC noreturn-turned-volatile quirk
+    - scsi: acornscsi: Fix an error handling path in acornscsi_probe()
+    - x86/idt: Keep spurious entries unset in system_vectors
+    - net/filter: Permit reading NET in load_bytes_relative when MAC not set
+    - nvme-pci: use simple suspend when a HMB is enabled
+    - nfs: set invalid blocks after NFSv4 writes
+    - xdp: Fix xsk_generic_xmit errno
+    - iavf: fix speed reporting over virtchnl
+    - bpf: Fix memlock accounting for sock_hash
+    - usb/xhci-plat: Set PM runtime as active on resume
+    - usb: host: ehci-platform: add a quirk to avoid stuck
+    - usb/ehci-platform: Set PM runtime as active on resume
+    - perf report: Fix NULL pointer dereference in
+      hists__fprintf_nr_sample_events()
+    - perf stat: Fix NULL pointer dereference
+    - ext4: stop overwrite the errcode in ext4_setup_super
+    - bcache: fix potential deadlock problem in btree_gc_coalesce
+    - powerpc: Fix kernel crash in show_instructions() w/DEBUG_VIRTUAL
+    - afs: Fix non-setting of mtime when writing into mmap
+    - afs: afs_write_end() should change i_size under the right lock
+    - afs: Fix EOF corruption
+    - afs: Always include dir in bulk status fetch from afs_do_lookup()
+    - afs: Set error flag rather than return error from file status decode
+    - afs: Fix the mapping of the UAEOVERFLOW abort code
+    - bnxt_en: Return from timer if interface is not in open state.
+    - scsi: ufs-bsg: Fix runtime PM imbalance on error
+    - block: Fix use-after-free in blkdev_get()
+    - mvpp2: remove module bugfix
+    - arm64: hw_breakpoint: Don't invoke overflow handler on uaccess watchpoints
+    - drm: encoder_slave: fix refcouting error for modules
+    - ext4: fix partial cluster initialization when splitting extent
+    - ext4: avoid utf8_strncasecmp() with unstable name
+    - drm/dp_mst: Reformat drm_dp_check_act_status() a bit
+    - drm/qxl: Use correct notify port address when creating cursor ring
+    - drm/amdgpu: Replace invalid device ID with a valid device ID
+    - selinux: fix double free
+    - jbd2: clean __jbd2_journal_abort_hard() and __journal_abort_soft()
+    - ext4: avoid race conditions when remounting with options that change dax
+    - drm/dp_mst: Increase ACT retry timeout to 3s
+    - drm/amd/display: Use swap() where appropriate
+    - x86/boot/compressed: Relax sed symbol type regex for LLVM ld.lld
+    - block: nr_sects_write(): Disable preemption on seqcount write
+    - net/mlx5: DR, Fix freeing in dr_create_rc_qp()
+    - f2fs: split f2fs_d_compare() from f2fs_match_name()
+    - f2fs: avoid utf8_strncasecmp() with unstable name
+    - s390: fix syscall_get_error for compat processes
+    - drm/i915: Fix AUX power domain toggling across TypeC mode resets
+    - drm/msm: Check for powered down HW in the devfreq callbacks
+    - drm/i915/gem: Avoid iterating an empty list
+    - drm/i915: Whitelist context-local timestamp in the gen9 cmdparser
+    - drm/connector: notify userspace on hotplug after register complete
+    - drm/amd/display: Use kvfree() to free coeff in build_regamma()
+    - drm/i915/icl+: Fix hotplug interrupt disabling after storm detection
+    - Revert "drm/amd/display: disable dcn20 abm feature for bring up"
+    - crypto: algif_skcipher - Cap recv SG list at ctx->used
+    - crypto: algboss - don't wait during notifier callback
+    - tracing/probe: Fix memleak in fetch_op_data operations
+    - kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
+    - kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
+    - e1000e: Do not wake up the system via WOL if device wakeup is disabled
+    - net: octeon: mgmt: Repair filling of RX ring
+    - pwm: jz4740: Enhance precision in calculation of duty cycle
+    - sched/rt, net: Use CONFIG_PREEMPTION.patch
+    - net: core: device_rename: Use rwsem instead of a seqcount
+    - Linux 5.4.49
+
+  * Computer is frozen after suspend (LP: #1867983) // Focal update: v5.4.49
+    upstream stable release (LP: #1885322)
+    - libata: Use per port sync for detach
+
+  * Focal update: v5.4.48 upstream stable release (LP: #1885023)
+    - ACPI: GED: use correct trigger type field in _Exx / _Lxx handling
+    - drm/amdgpu: fix and cleanup amdgpu_gem_object_close v4
+    - ath10k: Fix the race condition in firmware dump work queue
+    - drm: bridge: adv7511: Extend list of audio sample rates
+    - media: staging: imgu: do not hold spinlock during freeing mmu page table
+    - media: imx: imx7-mipi-csis: Cleanup and fix subdev pad format handling
+    - crypto: ccp -- don't "select" CONFIG_DMADEVICES
+    - media: vicodec: Fix error codes in probe function
+    - media: si2157: Better check for running tuner in init
+    - objtool: Ignore empty alternatives
+    - spi: spi-mem: Fix Dual/Quad modes on Octal-capable devices
+    - drm/amdgpu: Init data to avoid oops while reading pp_num_states.
+    - arm64/kernel: Fix range on invalidating dcache for boot page tables
+    - libbpf: Fix memory leak and possible double-free in hashmap__clear
+    - spi: pxa2xx: Apply CS clk quirk to BXT
+    - x86,smap: Fix smap_{save,restore}() alternatives
+    - sched/fair: Refill bandwidth before scaling
+    - net: atlantic: make hw_get_regs optional
+    - net: ena: fix error returning in ena_com_get_hash_function()
+    - efi/libstub/x86: Work around LLVM ELF quirk build regression
+    - ath10k: remove the max_sched_scan_reqs value
+    - arm64: cacheflush: Fix KGDB trap detection
+    - media: staging: ipu3: Fix stale list entries on parameter queue failure
+    - rtw88: fix an issue about leak system resources
+    - spi: dw: Zero DMA Tx and Rx configurations on stack
+    - ACPICA: Dispatcher: add status checks
+    - block: alloc map and request for new hardware queue
+    - arm64: insn: Fix two bugs in encoding 32-bit logical immediates
+    - block: reset mapping if failed to update hardware queue count
+    - drm: rcar-du: Set primary plane zpos immutably at initializing
+    - lockdown: Allow unprivileged users to see lockdown status
+    - ixgbe: Fix XDP redirect on archs with PAGE_SIZE above 4K
+    - platform/x86: dell-laptop: don't register micmute LED if there is no token
+    - MIPS: Loongson: Build ATI Radeon GPU driver as module
+    - Bluetooth: Add SCO fallback for invalid LMP parameters error
+    - kgdb: Disable WARN_CONSOLE_UNLOCKED for all kgdb
+    - kgdb: Prevent infinite recursive entries to the debugger
+    - pmu/smmuv3: Clear IRQ affinity hint on device removal
+    - ACPI/IORT: Fix PMCG node single ID mapping handling
+    - mips: Fix cpu_has_mips64r1/2 activation for MIPS32 CPUs
+    - spi: dw: Enable interrupts in accordance with DMA xfer mode
+    - clocksource: dw_apb_timer: Make CPU-affiliation being optional
+    - clocksource: dw_apb_timer_of: Fix missing clockevent timers
+    - media: dvbdev: Fix tuner->demod media controller link
+    - btrfs: account for trans_block_rsv in may_commit_transaction
+    - btrfs: do not ignore error from btrfs_next_leaf() when inserting checksums
+    - ARM: 8978/1: mm: make act_mm() respect THREAD_SIZE
+    - batman-adv: Revert "disable ethtool link speed detection when auto
+      negotiation off"
+    - ice: Fix memory leak
+    - ice: Fix for memory leaks and modify ICE_FREE_CQ_BUFS
+    - mmc: meson-mx-sdio: trigger a soft reset after a timeout or CRC error
+    - Bluetooth: btmtkuart: Improve exception handling in btmtuart_probe()
+    - spi: dw: Fix Rx-only DMA transfers
+    - x86/kvm/hyper-v: Explicitly align hcall param for kvm_hyperv_exit
+    - net: vmxnet3: fix possible buffer overflow caused by bad DMA value in
+      vmxnet3_get_rss()
+    - x86: fix vmap arguments in map_irq_stack
+    - staging: android: ion: use vmap instead of vm_map_ram
+    - ath10k: fix kernel null pointer dereference
+    - media: staging/intel-ipu3: Implement lock for stream on/off operations
+    - spi: Respect DataBitLength field of SpiSerialBusV2() ACPI resource
+    - brcmfmac: fix wrong location to get firmware feature
+    - regulator: qcom-rpmh: Fix typos in pm8150 and pm8150l
+    - tools api fs: Make xxx__mountpoint() more scalable
+    - e1000: Distribute switch variables for initialization
+    - dt-bindings: display: mediatek: control dpi pins mode to avoid leakage
+    - drm/mediatek: set dpi pin mode to gpio low to avoid leakage current
+    - audit: fix a net reference leak in audit_send_reply()
+    - media: dvb: return -EREMOTEIO on i2c transfer failure.
+    - media: platform: fcp: Set appropriate DMA parameters
+    - MIPS: Make sparse_init() using top-down allocation
+    - ath10k: add flush tx packets for SDIO chip
+    - Bluetooth: btbcm: Add 2 missing models to subver tables
+    - audit: fix a net reference leak in audit_list_rules_send()
+    - Drivers: hv: vmbus: Always handle the VMBus messages on CPU0
+    - dpaa2-eth: fix return codes used in ndo_setup_tc
+    - netfilter: nft_nat: return EOPNOTSUPP if type or flags are not supported
+    - selftests/bpf: Fix memory leak in extract_build_id()
+    - net: bcmgenet: set Rx mode before starting netif
+    - net: bcmgenet: Fix WoL with password after deep sleep
+    - lib/mpi: Fix 64-bit MIPS build with Clang
+    - exit: Move preemption fixup up, move blocking operations down
+    - sched/core: Fix illegal RCU from offline CPUs
+    - drivers/perf: hisi: Fix typo in events attribute array
+    - iocost_monitor: drop string wrap around numbers when outputting json
+    - net: lpc-enet: fix error return code in lpc_mii_init()
+    - selinux: fix error return code in policydb_read()
+    - drivers: net: davinci_mdio: fix potential NULL dereference in
+      davinci_mdio_probe()
+    - media: cec: silence shift wrapping warning in __cec_s_log_addrs()
+    - net: allwinner: Fix use correct return type for ndo_start_xmit()
+    - powerpc/spufs: fix copy_to_user while atomic
+    - libertas_tf: avoid a null dereference in pointer priv
+    - xfs: clean up the error handling in xfs_swap_extents
+    - Crypto/chcr: fix for ccm(aes) failed test
+    - MIPS: Truncate link address into 32bit for 32bit kernel
+    - mips: cm: Fix an invalid error code of INTVN_*_ERR
+    - kgdb: Fix spurious true from in_dbg_master()
+    - xfs: reset buffer write failure state on successful completion
+    - xfs: fix duplicate verification from xfs_qm_dqflush()
+    - platform/x86: intel-vbtn: Use acpi_evaluate_integer()
+    - platform/x86: intel-vbtn: Split keymap into buttons and switches parts
+    - platform/x86: intel-vbtn: Do not advertise switches to userspace if they are
+      not there
+    - platform/x86: intel-vbtn: Also handle tablet-mode switch on "Detachable" and
+      "Portable" chassis-types
+    - iwlwifi: avoid debug max amsdu config overwriting itself
+    - nvme: refine the Qemu Identify CNS quirk
+    - nvme-pci: align io queue count with allocted nvme_queue in nvme_probe
+    - nvme-tcp: use bh_lock in data_ready
+    - ath10k: Remove msdu from idr when management pkt send fails
+    - wcn36xx: Fix error handling path in 'wcn36xx_probe()'
+    - net: qed*: Reduce RX and TX default ring count when running inside kdump
+      kernel
+    - drm/mcde: dsi: Fix return value check in mcde_dsi_bind()
+    - mt76: avoid rx reorder buffer overflow
+    - md: don't flush workqueue unconditionally in md_open
+    - raid5: remove gfp flags from scribble_alloc()
+    - iocost: don't let vrate run wild while there's no saturation signal
+    - veth: Adjust hard_start offset on redirect XDP frames
+    - net/mlx5e: IPoIB, Drop multicast packets that this interface sent
+    - rtlwifi: Fix a double free in _rtl_usb_tx_urb_setup()
+    - mwifiex: Fix memory corruption in dump_station
+    - kgdboc: Use a platform device to handle tty drivers showing up late
+    - x86/boot: Correct relocation destination on old linkers
+    - sched: Defend cfs and rt bandwidth quota against overflow
+    - mips: MAAR: Use more precise address mask
+    - mips: Add udelay lpj numbers adjustment
+    - crypto: stm32/crc32 - fix ext4 chksum BUG_ON()
+    - crypto: stm32/crc32 - fix run-time self test issue.
+    - crypto: stm32/crc32 - fix multi-instance
+    - drm/amd/powerpay: Disable gfxoff when setting manual mode on picasso and
+      raven
+    - drm/amdgpu: Sync with VM root BO when switching VM to CPU update mode
+    - selftests/bpf: CONFIG_IPV6_SEG6_BPF required for test_seg6_loop.o
+    - x86/mm: Stop printing BRK addresses
+    - MIPS: tools: Fix resource leak in elf-entry.c
+    - m68k: mac: Don't call via_flush_cache() on Mac IIfx
+    - btrfs: improve global reserve stealing logic
+    - btrfs: qgroup: mark qgroup inconsistent if we're inherting snapshot to a new
+      qgroup
+    - 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()
+    - bcache: fix refcount underflow in bcache_device_free()
+    - mmc: sdhci-msm: Set SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 quirk
+    - staging: greybus: sdio: Respect the cmd->busy_timeout from the mmc core
+    - mmc: via-sdmmc: Respect the cmd->busy_timeout from the mmc core
+    - ice: fix potential double free in probe unrolling
+    - ixgbe: fix signed-integer-overflow warning
+    - iwlwifi: mvm: fix aux station leak
+    - mmc: sdhci-esdhc-imx: fix the mask for tuning start point
+    - spi: dw: Return any value retrieved from the dma_transfer callback
+    - cpuidle: Fix three reference count leaks
+    - platform/x86: hp-wmi: Convert simple_strtoul() to kstrtou32()
+    - platform/x86: intel-hid: Add a quirk to support HP Spectre X2 (2015)
+    - platform/x86: intel-vbtn: Only blacklist SW_TABLET_MODE on the 9 / "Laptop"
+      chasis-type
+    - platform/x86: asus_wmi: Reserve more space for struct bias_args
+    - libbpf: Fix perf_buffer__free() API for sparse allocs
+    - bpf: Fix map permissions check
+    - bpf: Refactor sockmap redirect code so its easy to reuse
+    - bpf: Fix running sk_skb program types with ktls
+    - selftests/bpf, flow_dissector: Close TAP device FD after the test
+    - kasan: stop tests being eliminated as dead code with FORTIFY_SOURCE
+    - string.h: fix incompatibility between FORTIFY_SOURCE and KASAN
+    - btrfs: free alien device after device add
+    - btrfs: include non-missing as a qualifier for the latest_bdev
+    - btrfs: send: emit file capabilities after chown
+    - btrfs: force chunk allocation if our global rsv is larger than metadata
+    - btrfs: fix error handling when submitting direct I/O bio
+    - btrfs: fix wrong file range cleanup after an error filling dealloc range
+    - btrfs: fix space_info bytes_may_use underflow after nocow buffered write
+    - btrfs: fix space_info bytes_may_use underflow during space cache writeout
+    - powerpc/mm: Fix conditions to perform MMU specific management by blocks on
+      PPC32.
+    - mm: thp: make the THP mapcount atomic against __split_huge_pmd_locked()
+    - mm: initialize deferred pages with interrupts enabled
+    - mm/pagealloc.c: call touch_nmi_watchdog() on max order boundaries in
+      deferred init
+    - mm: call cond_resched() from deferred_init_memmap()
+    - ima: Fix ima digest hash table key calculation
+    - ima: Switch to ima_hash_algo for boot aggregate
+    - ima: Evaluate error in init_ima()
+    - ima: Directly assign the ima_default_policy pointer to ima_rules
+    - ima: Call ima_calc_boot_aggregate() in ima_eventdigest_init()
+    - ima: Remove __init annotation from ima_pcrread()
+    - evm: Fix possible memory leak in evm_calc_hmac_or_hash()
+    - ext4: fix EXT_MAX_EXTENT/INDEX to check for zeroed eh_max
+    - ext4: fix error pointer dereference
+    - ext4: fix race between ext4_sync_parent() and rename()
+    - PCI: Add ACS quirk for Intel Root Complex Integrated Endpoints
+    - PCI: Add Loongson vendor ID
+    - x86/amd_nb: Add AMD family 17h model 60h PCI IDs
+    - ima: Remove redundant policy rule set in add_rules()
+    - ima: Set again build_ima_appraise variable
+    - 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
+    - media: cedrus: Program output format during each run
+    - serial: 8250: Avoid error message on reprobe
+    - Bluetooth: hci_bcm: fix freeing not-requested IRQ
+    - b43legacy: Fix case where channel status is corrupted
+    - b43: Fix connection problem with WPA3
+    - b43_legacy: Fix connection problem with WPA3
+    - media: ov5640: fix use of destroyed mutex
+    - clk: mediatek: assign the initial value to clk_init_data of mtk_mux
+    - hwmon: (k10temp) Add AMD family 17h model 60h PCI match
+    - EDAC/amd64: Add AMD family 17h model 60h PCI IDs
+    - power: vexpress: add suppress_bind_attrs to true
+    - power: supply: core: fix HWMON temperature labels
+    - power: supply: core: fix memory leak in HWMON error path
+    - pinctrl: samsung: Correct setting of eint wakeup mask on s5pv210
+    - pinctrl: samsung: Save/restore eint_mask over suspend for EINT_TYPE GPIOs
+    - gnss: sirf: fix error return code in sirf_probe()
+    - sparc32: fix register window handling in genregs32_[gs]et()
+    - sparc64: fix misuses of access_process_vm() in genregs32_[sg]et()
+    - dm crypt: avoid truncating the logical block size
+    - alpha: fix memory barriers so that they conform to the specification
+    - powerpc/fadump: use static allocation for reserved memory ranges
+    - powerpc/fadump: consider reserved ranges while reserving memory
+    - powerpc/fadump: Account for memory_limit while reserving memory
+    - kernel/cpu_pm: Fix uninitted local in cpu_pm
+    - ARM: tegra: Correct PL310 Auxiliary Control Register initialization
+    - soc/tegra: pmc: Select GENERIC_PINCONF
+    - ARM: dts: exynos: Fix GPIO polarity for thr GalaxyS3 CM36651 sensor's bus
+    - ARM: dts: at91: sama5d2_ptc_ek: fix vbus pin
+    - ARM: dts: s5pv210: Set keep-power-in-suspend for SDHCI1 on Aries
+    - drivers/macintosh: Fix memleak in windfarm_pm112 driver
+    - powerpc/32s: Fix another build failure with CONFIG_PPC_KUAP_DEBUG
+    - powerpc/kasan: Fix issues by lowering KASAN_SHADOW_END
+    - powerpc/kasan: Fix shadow pages allocation failure
+    - powerpc/32: Disable KASAN with pages bigger than 16k
+    - powerpc/64s: Don't let DT CPU features set FSCR_DSCR
+    - powerpc/64s: Save FSCR to init_task.thread.fscr after feature init
+    - 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()
+    - mtd: rawnand: Fix nand_gpio_waitrdy()
+    - mtd: rawnand: onfi: Fix redundancy detection check
+    - mtd: rawnand: brcmnand: fix hamming oob layout
+    - mtd: rawnand: diskonchip: Fix the probe error path
+    - mtd: rawnand: sharpsl: Fix the probe error path
+    - mtd: rawnand: ingenic: Fix the probe error path
+    - mtd: rawnand: xway: Fix the probe error path
+    - mtd: rawnand: orion: Fix the probe error path
+    - mtd: rawnand: socrates: Fix the probe error path
+    - mtd: rawnand: oxnas: Fix the probe error path
+    - mtd: rawnand: sunxi: Fix the probe error path
+    - mtd: rawnand: plat_nand: Fix the probe error path
+    - mtd: rawnand: pasemi: Fix the probe error path
+    - mtd: rawnand: mtk: Fix the probe error path
+    - mtd: rawnand: tmio: Fix the probe error path
+    - w1: omap-hdq: cleanup to add missing newline for some dev_dbg
+    - f2fs: fix checkpoint=disable:%u%%
+    - perf probe: Do not show the skipped events
+    - perf probe: Fix to check blacklist address correctly
+    - perf probe: Check address correctness by map instead of _etext
+    - perf symbols: Fix debuginfo search for Ubuntu
+    - perf symbols: Fix kernel maps for kcore and eBPF
+    - Linux 5.4.48
+
+  * The thread level parallelism would be a bottleneck when searching for the
+    shared pmd by using hugetlbfs (LP: #1882039)
+    - hugetlbfs: take read_lock on i_mmap for PMD sharing
+
+  * Support Audio Mute LED for two new HP laptops (LP: #1884251)
+    - ALSA: hda/realtek: Add mute LED and micmute LED support for HP systems
+
+  * Focal update: v5.4.47 upstream stable release (LP: #1884089)
+    - ipv6: fix IPV6_ADDRFORM operation logic
+    - mlxsw: core: Use different get_trend() callbacks for different thermal zones
+    - net_failover: fixed rollback in net_failover_open()
+    - tun: correct header offsets in napi frags mode
+    - bridge: Avoid infinite loop when suppressing NS messages with invalid
+      options
+    - vxlan: Avoid infinite loop when suppressing NS messages with invalid options
+    - bpf: Support llvm-objcopy for vmlinux BTF
+    - elfnote: mark all .note sections SHF_ALLOC
+    - Input: mms114 - fix handling of mms345l
+    - ARM: 8977/1: ptrace: Fix mask for thumb breakpoint hook
+    - sched/fair: Don't NUMA balance for kthreads
+    - Input: synaptics - add a second working PNP_ID for Lenovo T470s
+    - csky: Fixup abiv2 syscall_trace break a4 & a5
+    - gfs2: Even more gfs2_find_jhead fixes
+    - drivers/net/ibmvnic: Update VNIC protocol version reporting
+    - powerpc/xive: Clear the page tables for the ESB IO mapping
+    - spi: dw: Fix native CS being unset
+    - ath9k_htc: Silence undersized packet warnings
+    - smack: avoid unused 'sip' variable warning
+    - RDMA/uverbs: Make the event_queue fds return POLLERR when disassociated
+    - padata: add separate cpuhp node for CPUHP_PADATA_DEAD
+    - s390/pci: Log new handle in clp_disable_fh()
+    - x86/cpu/amd: Make erratum #1054 a legacy erratum
+    - KVM: x86: only do L1TF workaround on affected processors
+    - PCI/PM: Adjust pcie_wait_for_link_delay() for caller delay
+    - perf probe: Accept the instance number of kretprobe event
+    - mm: add kvfree_sensitive() for freeing sensitive data objects
+    - selftests: fix flower parent qdisc
+    - fanotify: fix ignore mask logic for events on child and on dir
+    - aio: fix async fsync creds
+    - ipv4: fix a RCU-list lock in fib_triestat_seq_show
+    - iwlwifi: mvm: fix NVM check for 3168 devices
+    - sctp: fix possibly using a bad saddr with a given dst
+    - sctp: fix refcount bug in sctp_wfree
+    - x86_64: Fix jiffies ODR violation
+    - x86/PCI: Mark Intel C620 MROMs as having non-compliant BARs
+    - x86/speculation: Prevent rogue cross-process SSBD shutdown
+    - x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced
+      IBRS.
+    - x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches.
+    - x86/reboot/quirks: Add MacBook6,1 reboot quirk
+    - perf/x86/intel: Add more available bits for OFFCORE_RESPONSE of Intel
+      Tremont
+    - KVM: x86/mmu: Set mmio_value to '0' if reserved #PF can't be generated
+    - KVM: x86: respect singlestep when emulating instruction
+    - KVM: x86: Fix APIC page invalidation race
+    - powerpc/ptdump: Properly handle non standard page size
+    - ASoC: max9867: fix volume controls
+    - io_uring: use kvfree() in io_sqe_buffer_register()
+    - efi/efivars: Add missing kobject_put() in sysfs entry creation error path
+    - smb3: fix incorrect number of credits when ioctl MaxOutputResponse > 64K
+    - smb3: add indatalen that can be a non-zero value to calculation of credit
+      charge in smb2 ioctl
+    - watchdog: imx_sc_wdt: Fix reboot on crash
+    - ALSA: es1688: Add the missed snd_card_free()
+    - ALSA: fireface: fix configuration error for nominal sampling transfer
+      frequency
+    - ALSA: hda/realtek - add a pintbl quirk for several Lenovo machines
+    - ALSA: pcm: disallow linking stream to itself
+    - ALSA: pcm: fix snd_pcm_link() lockdep splat
+    - ALSA: usb-audio: Fix inconsistent card PM state after resume
+    - ALSA: usb-audio: Add vendor, product and profile name for HP Thunderbolt
+      Dock
+    - ACPI: sysfs: Fix reference count leak in acpi_sysfs_add_hotplug_profile()
+    - ACPI: CPPC: Fix reference count leak in acpi_cppc_processor_probe()
+    - ACPI: GED: add support for _Exx / _Lxx handler methods
+    - ACPI: PM: Avoid using power resources if there are none for D0
+    - arm64: acpi: fix UBSAN warning
+    - lib/lzo: fix ambiguous encoding bug in lzo-rle
+    - nilfs2: fix null pointer dereference at nilfs_segctor_do_construct()
+    - spi: dw: Fix controller unregister order
+    - spi: Fix controller unregister order
+    - spi: pxa2xx: Fix controller unregister order
+    - spi: pxa2xx: Fix runtime PM ref imbalance on probe error
+    - spi: bcm2835: Fix controller unregister order
+    - spi: bcm2835aux: Fix controller unregister order
+    - spi: bcm-qspi: Handle clock probe deferral
+    - spi: bcm-qspi: when tx/rx buffer is NULL set to 0
+    - PM: runtime: clk: Fix clk_pm_runtime_get() error path
+    - gup: document and work around "COW can break either way" issue
+    - crypto: cavium/nitrox - Fix 'nitrox_get_first_device()' when ndevlist is
+      fully iterated
+    - crypto: algapi - Avoid spurious modprobe on LOADED
+    - crypto: drbg - fix error return code in drbg_alloc_state()
+    - x86/{mce,mm}: Unmap the entire page if the whole page is affected and
+      poisoned
+    - firmware: imx: warn on unexpected RX
+    - firmware: imx-scu: Support one TX and one RX
+    - firmware: imx: scu: Fix corruption of header
+    - crypto: virtio: Fix use-after-free in virtio_crypto_skcipher_finalize_req()
+    - crypto: virtio: Fix src/dst scatterlist calculation in
+      __virtio_crypto_skcipher_do_req()
+    - crypto: virtio: Fix dest length calculation in
+      __virtio_crypto_skcipher_do_req()
+    - dccp: Fix possible memleak in dccp_init and dccp_fini
+    - selftests/net: in rxtimestamp getopt_long needs terminating null entry
+    - net/mlx5: drain health workqueue in case of driver load error
+    - net/mlx5: Fix fatal error handling during device load
+    - net/mlx5e: Fix repeated XSK usage on one channel
+    - ovl: initialize error in ovl_copy_xattr
+    - proc: Use new_inode not new_inode_pseudo
+    - remoteproc: Fall back to using parent memory pool if no dedicated available
+    - remoteproc: Fix and restore the parenting hierarchy for vdev
+    - cpufreq: Fix up cpufreq_boost_set_sw()
+    - EDAC/skx: Use the mcmtr register to retrieve close_pg/bank_xor_enable
+    - video: vt8500lcdfb: fix fallthrough warning
+    - video: fbdev: w100fb: Fix a potential double free.
+    - KVM: nVMX: Skip IBPB when switching between vmcs01 and vmcs02
+    - KVM: nSVM: fix condition for filtering async PF
+    - KVM: nSVM: leave ASID aside in copy_vmcb_control_area
+    - KVM: nVMX: Consult only the "basic" exit reason when routing nested exit
+    - KVM: MIPS: Define KVM_ENTRYHI_ASID to cpu_asid_mask(&boot_cpu_data)
+    - KVM: MIPS: Fix VPN2_MASK definition for variable cpu_vmbits
+    - KVM: arm64: Stop writing aarch32's CSSELR into ACTLR
+    - KVM: arm64: Make vcpu_cp1x() work on Big Endian hosts
+    - scsi: megaraid_sas: TM command refire leads to controller firmware crash
+    - scsi: lpfc: Fix negation of else clause in lpfc_prep_node_fc4type
+    - selftests/ftrace: Return unsupported if no error_log file
+    - ath9k: Fix use-after-free Read in htc_connect_service
+    - 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
+    - drm/vkms: Hold gem object while still in-use
+    - mm/slub: fix a memory leak in sysfs_slab_add()
+    - fat: don't allow to mount if the FAT length == 0
+    - perf: Add cond_resched() to task_function_call()
+    - agp/intel: Reinforce the barrier after GTT updates
+    - mmc: sdhci-msm: Clear tuning done flag while hs400 tuning
+    - mmc: mmci_sdmmc: fix DMA API warning overlapping mappings
+    - mmc: tmio: Further fixup runtime PM management at remove
+    - mmc: uniphier-sd: call devm_request_irq() after tmio_mmc_host_probe()
+    - ARM: dts: at91: sama5d2_ptc_ek: fix sdmmc0 node description
+    - mmc: sdio: Fix potential NULL pointer error in mmc_sdio_init_card()
+    - mmc: sdio: Fix several potential memory leaks in mmc_sdio_init_card()
+    - block/floppy: fix contended case in floppy_queue_rq()
+    - xen/pvcalls-back: test for errors when calling backend_connect()
+    - KVM: arm64: Synchronize sysreg state on injecting an AArch32 exception
+    - KVM: arm64: Save the host's PtrAuth keys in non-preemptible context
+    - Linux 5.4.47
+
+  * apparmor reference leak causes refcount_t overflow with af_alg_accept()
+    (LP: #1883962)
+    - apparmor: check/put label on apparmor_sk_clone_security()
+
+  * Focal update: v5.4.46 upstream stable release (LP: #1883184)
+    - devinet: fix memleak in inetdev_init()
+    - l2tp: add sk_family checks to l2tp_validate_socket
+    - l2tp: do not use inet_hash()/inet_unhash()
+    - net/mlx5: Fix crash upon suspend/resume
+    - net: stmmac: enable timestamp snapshot for required PTP packets in dwmac
+      v5.10a
+    - net: usb: qmi_wwan: add Telit LE910C1-EUX composition
+    - NFC: st21nfca: add missed kfree_skb() in an error path
+    - nfp: flower: fix used time of merge flow statistics
+    - vsock: fix timeout in vsock_accept()
+    - net: check untrusted gso_size at kernel entry
+    - net: be more gentle about silly gso requests coming from user
+    - 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
+    - USB: serial: ch341: add basis for quirk detection
+    - iio:chemical:sps30: Fix timestamp alignment
+    - iio: vcnl4000: Fix i2c swapped word reading.
+    - iio:chemical:pms7003: Fix timestamp alignment and prevent data leak.
+    - iio: adc: stm32-adc: fix a wrong error message when probing interrupts
+    - usb: musb: start session in resume for host port
+    - usb: musb: Fix runtime PM imbalance on error
+    - vt: keyboard: avoid signed integer overflow in k_ascii
+    - tty: hvc_console, fix crashes on parallel open/close
+    - staging: rtl8712: Fix IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK
+    - CDC-ACM: heed quirk also in error handling
+    - nvmem: qfprom: remove incorrect write support
+    - uprobes: ensure that uprobe->offset and ->ref_ctr_offset are properly
+      aligned
+    - Revert "net/mlx5: Annotate mutex destroy for root ns"
+    - Linux 5.4.46
+
+  * Focal update: v5.4.45 upstream stable release (LP: #1882802)
+    - mm: Fix mremap not considering huge pmd devmap
+    - HID: sony: Fix for broken buttons on DS3 USB dongles
+    - HID: multitouch: enable multi-input as a quirk for some devices
+    - HID: i2c-hid: add Schneider SCL142ALM to descriptor override
+    - p54usb: add AirVasT USB stick device-id
+    - mt76: mt76x02u: Add support for newer versions of the XBox One wifi adapter
+    - mmc: fix compilation of user API
+    - media: Revert "staging: imgu: Address a compiler warning on alignment"
+    - media: staging: ipu3-imgu: Move alignment attribute to field
+    - scsi: ufs: Release clock if DMA map fails
+    - net: dsa: mt7530: set CPU port to fallback mode
+    - airo: Fix read overflows sending packets
+    - RDMA/qedr: Fix qpids xarray api used
+    - RDMA/qedr: Fix synchronization methods and memory leaks in qedr
+    - ARC: Fix ICCM & DCCM runtime size checks
+    - ARC: [plat-eznps]: Restrict to CONFIG_ISA_ARCOMPACT
+    - evm: Fix RCU list related warnings
+    - scsi: pm: Balance pm_only counter of request queue during system resume
+    - i2c: altera: Fix race between xfer_msg and isr thread
+    - io_uring: initialize ctx->sqo_wait earlier
+    - x86/mmiotrace: Use cpumask_available() for cpumask_var_t variables
+    - net: bmac: Fix read of MAC address from ROM
+    - drm/edid: Add Oculus Rift S to non-desktop list
+    - s390/mm: fix set_huge_pte_at() for empty ptes
+    - null_blk: return error for invalid zone size
+    - net/ethernet/freescale: rework quiesce/activate for ucc_geth
+    - net: ethernet: stmmac: Enable interface clocks on probe for IPQ806x
+    - selftests: mlxsw: qos_mc_aware: Specify arping timeout as an integer
+    - net: smsc911x: Fix runtime PM imbalance on error
+    - Linux 5.4.45
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Sat, 08 Aug 2020 02:05:56 -0400
+
+linux (5.4.0-42.46) focal; urgency=medium
+
+  * focal/linux: 5.4.0-42.46 -proposed tracker (LP: #1887069)
+
+  * linux 4.15.0-109-generic network DoS regression vs -108 (LP: #1886668)
+    - SAUCE: Revert "netprio_cgroup: Fix unlimited memory leak of v2 cgroups"
+
+ -- Khalid Elmously <khalid.elmously@canonical.com>  Thu, 09 Jul 2020 19:50:26 -0400
+
+linux (5.4.0-41.45) focal; urgency=medium
+
+  * focal/linux: 5.4.0-41.45 -proposed tracker (LP: #1885855)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * CVE-2019-19642
+    - kernel/relay.c: handle alloc_percpu returning NULL in relay_open
+
+  * CVE-2019-16089
+    - SAUCE: nbd_genl_status: null check for nla_nest_start
+
+  * CVE-2020-11935
+    - aufs: do not call i_readcount_inc()
+
+  * ip_defrag.sh in net from ubuntu_kernel_selftests failed with 5.0 / 5.3 / 5.4
+    kernel (LP: #1826848)
+    - selftests: net: ip_defrag: ignore EPERM
+
+  * Update lockdown patches (LP: #1884159)
+    - SAUCE: acpi: disallow loading configfs acpi tables when locked down
+
+  * seccomp_bpf fails on powerpc (LP: #1885757)
+    - SAUCE: selftests/seccomp: fix ptrace tests on powerpc
+
+  * Introduce the new NVIDIA 418-server and 440-server series, and update the
+    current NVIDIA drivers (LP: #1881137)
+    - [packaging] add signed modules for the 418-server and the 440-server
+      flavours
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 03 Jul 2020 10:32:54 +0200
+
+linux (5.4.0-40.44) focal; urgency=medium
+
+  * linux-oem-5.6-tools-common and -tools-host should be dropped (LP: #1881120)
+    - [Packaging] Add Conflicts/Replaces to remove linux-oem-5.6-tools-common and
+      -tools-host
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Slow send speed with Intel I219-V on Ubuntu 18.04.1 (LP: #1802691)
+    - e1000e: Disable TSO for buffer overrun workaround
+
+  * CVE-2020-0543
+    - UBUNTU/SAUCE: x86/speculation/srbds: do not try to turn mitigation off when
+      not supported
+
+  * Realtek 8723DE [10ec:d723] subsystem [10ec:d738]  disconnects unsolicitedly
+    when Bluetooth is paired: Reason: 23=IEEE8021X_FAILED (LP: #1878147)
+    - SAUCE: Revert "UBUNTU: SAUCE: rtw88: Move driver IQK to set channel before
+      association for 11N chip"
+    - SAUCE: Revert "UBUNTU: SAUCE: rtw88: fix rate for a while after being
+      connected"
+    - SAUCE: Revert "UBUNTU: SAUCE: rtw88: No retry and report for auth and assoc"
+    - SAUCE: Revert "UBUNTU: SAUCE: rtw88: 8723d: Add coex support"
+    - rtw88: add a debugfs entry to dump coex's info
+    - rtw88: add a debugfs entry to enable/disable coex mechanism
+    - rtw88: 8723d: Add coex support
+    - SAUCE: rtw88: coex: 8723d: set antanna control owner
+    - SAUCE: rtw88: coex: 8723d: handle BT inquiry cases
+    - SAUCE: rtw88: fix EAPOL 4-way failure by finish IQK earlier
+
+  * CPU stress test fails with focal kernel (LP: #1867900)
+    - [Config] Disable hisi_sec2 temporarily
+
+  * Enforce all config annotations (LP: #1879327)
+    - [Config]: do not enforce CONFIG_VERSION_SIGNATURE
+    - [Config]: prepare to enforce all
+    - [Config]: enforce all config options
+
+  * Focal update: v5.4.44 upstream stable release (LP: #1881927)
+    - ax25: fix setsockopt(SO_BINDTODEVICE)
+    - dpaa_eth: fix usage as DSA master, try 3
+    - net: don't return invalid table id error when we fall back to PF_UNSPEC
+    - net: dsa: mt7530: fix roaming from DSA user ports
+    - net: ethernet: ti: cpsw: fix ASSERT_RTNL() warning during suspend
+    - __netif_receive_skb_core: pass skb by reference
+    - net: inet_csk: Fix so_reuseport bind-address cache in tb->fast*
+    - net: ipip: fix wrong address family in init error path
+    - net/mlx5: Add command entry handling completion
+    - net: mvpp2: fix RX hashing for non-10G ports
+    - net: nlmsg_cancel() if put fails for nhmsg
+    - net: qrtr: Fix passing invalid reference to qrtr_local_enqueue()
+    - net: revert "net: get rid of an signed integer overflow in
+      ip_idents_reserve()"
+    - net sched: fix reporting the first-time use timestamp
+    - net/tls: fix race condition causing kernel panic
+    - nexthop: Fix attribute checking for groups
+    - r8152: support additional Microsoft Surface Ethernet Adapter variant
+    - sctp: Don't add the shutdown timer if its already been added
+    - sctp: Start shutdown on association restart if in SHUTDOWN-SENT state and
+      socket is closed
+    - tipc: block BH before using dst_cache
+    - net/mlx5e: kTLS, Destroy key object after destroying the TIS
+    - net/mlx5e: Fix inner tirs handling
+    - net/mlx5: Fix memory leak in mlx5_events_init
+    - net/mlx5e: Update netdev txq on completions during closure
+    - net/mlx5: Fix error flow in case of function_setup failure
+    - net/mlx5: Annotate mutex destroy for root ns
+    - net/tls: fix encryption error checking
+    - net/tls: free record only on encryption error
+    - net: sun: fix missing release regions in cas_init_one().
+    - net/mlx4_core: fix a memory leak bug.
+    - mlxsw: spectrum: Fix use-after-free of split/unsplit/type_set in case reload
+      fails
+    - ARM: dts: rockchip: fix phy nodename for rk3228-evb
+    - ARM: dts: rockchip: fix phy nodename for rk3229-xms6
+    - arm64: dts: rockchip: fix status for &gmac2phy in rk3328-evb.dts
+    - arm64: dts: rockchip: swap interrupts interrupt-names rk3399 gpu node
+    - ARM: dts: rockchip: swap clock-names of gpu nodes
+    - ARM: dts: rockchip: fix pinctrl sub nodename for spi in rk322x.dtsi
+    - gpio: tegra: mask GPIO IRQs during IRQ shutdown
+    - ALSA: usb-audio: add mapping for ASRock TRX40 Creator
+    - net: microchip: encx24j600: add missed kthread_stop
+    - gfs2: move privileged user check to gfs2_quota_lock_check
+    - gfs2: Grab glock reference sooner in gfs2_add_revoke
+    - drm/amdgpu: drop unnecessary cancel_delayed_work_sync on PG ungate
+    - drm/amd/powerplay: perform PG ungate prior to CG ungate
+    - drm/amdgpu: Use GEM obj reference for KFD BOs
+    - cachefiles: Fix race between read_waiter and read_copier involving op->to_do
+    - usb: dwc3: pci: Enable extcon driver for Intel Merrifield
+    - usb: phy: twl6030-usb: Fix a resource leak in an error handling path in
+      'twl6030_usb_probe()'
+    - usb: gadget: legacy: fix redundant initialization warnings
+    - net: freescale: select CONFIG_FIXED_PHY where needed
+    - IB/i40iw: Remove bogus call to netdev_master_upper_dev_get()
+    - riscv: stacktrace: Fix undefined reference to `walk_stackframe'
+    - clk: ti: am33xx: fix RTC clock parent
+    - csky: Fixup msa highest 3 bits mask
+    - csky: Fixup perf callchain unwind
+    - csky: Fixup remove duplicate irq_disable
+    - hwmon: (nct7904) Fix incorrect range of temperature limit registers
+    - cifs: Fix null pointer check in cifs_read
+    - csky: Fixup raw_copy_from_user()
+    - samples: bpf: Fix build error
+    - drivers: net: hamradio: Fix suspicious RCU usage warning in bpqether.c
+    - 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: dlink-dir685-touchkeys - fix a typo in driver name
+    - Input: i8042 - add ThinkPad S230u to i8042 reset list
+    - Input: synaptics-rmi4 - really fix attn_data use-after-free
+    - Input: synaptics-rmi4 - fix error return code in rmi_driver_probe()
+    - ARM: 8970/1: decompressor: increase tag size
+    - ARM: uaccess: consolidate uaccess asm to asm/uaccess-asm.h
+    - ARM: uaccess: integrate uaccess_save and uaccess_restore
+    - ARM: uaccess: fix DACR mismatch with nested exceptions
+    - gpio: exar: Fix bad handling for ida_simple_get error path
+    - arm64: dts: mt8173: fix vcodec-enc clock
+    - soc: mediatek: cmdq: return send msg error code
+    - gpu/drm: Ingenic: Fix opaque pointer casted to wrong type
+    - IB/qib: Call kobject_put() when kobject_init_and_add() fails
+    - ARM: dts/imx6q-bx50v3: Set display interface clock parents
+    - ARM: dts: bcm2835-rpi-zero-w: Fix led polarity
+    - ARM: dts: bcm: HR2: Fix PPI interrupt types
+    - mmc: block: Fix use-after-free issue for rpmb
+    - gpio: pxa: Fix return value of pxa_gpio_probe()
+    - gpio: bcm-kona: Fix return value of bcm_kona_gpio_probe()
+    - RDMA/pvrdma: Fix missing pci disable in pvrdma_pci_probe()
+    - ALSA: hwdep: fix a left shifting 1 by 31 UB bug
+    - ALSA: hda/realtek - Add a model for Thinkpad T570 without DAC workaround
+    - ALSA: usb-audio: mixer: volume quirk for ESS Technology Asus USB DAC
+    - exec: Always set cap_ambient in cap_bprm_set_creds
+    - clk: qcom: gcc: Fix parent for gpll0_out_even
+    - ALSA: usb-audio: Quirks for Gigabyte TRX40 Aorus Master onboard audio
+    - ALSA: hda/realtek - Add new codec supported for ALC287
+    - libceph: ignore pool overlay and cache logic on redirects
+    - ceph: flush release queue when handling caps for unknown inode
+    - RDMA/core: Fix double destruction of uobject
+    - drm/amd/display: drop cursor position check in atomic test
+    - IB/ipoib: Fix double free of skb in case of multicast traffic in CM mode
+    - mm,thp: stop leaking unreleased file pages
+    - mm: remove VM_BUG_ON(PageSlab()) from page_mapcount()
+    - fs/binfmt_elf.c: allocate initialized memory in fill_thread_core_info()
+    - include/asm-generic/topology.h: guard cpumask_of_node() macro argument
+    - Revert "block: end bio with BLK_STS_AGAIN in case of non-mq devs and
+      REQ_NOWAIT"
+    - gpio: fix locking open drain IRQ lines
+    - iommu: Fix reference count leak in iommu_group_alloc.
+    - parisc: Fix kernel panic in mem_init()
+    - cfg80211: fix debugfs rename crash
+    - x86/syscalls: Revert "x86/syscalls: Make __X32_SYSCALL_BIT be unsigned long"
+    - mac80211: mesh: fix discovery timer re-arming issue / crash
+    - x86/dma: Fix max PFN arithmetic overflow on 32 bit systems
+    - copy_xstate_to_kernel(): don't leave parts of destination uninitialized
+    - xfrm: allow to accept packets with ipv6 NEXTHDR_HOP in xfrm_input
+    - xfrm: do pskb_pull properly in __xfrm_transport_prep
+    - xfrm: remove the xfrm_state_put call becofe going to out_reset
+    - xfrm: call xfrm_output_gso when inner_protocol is set in xfrm_output
+    - xfrm interface: fix oops when deleting a x-netns interface
+    - xfrm: fix a warning in xfrm_policy_insert_list
+    - xfrm: fix a NULL-ptr deref in xfrm_local_error
+    - xfrm: fix error in comment
+    - 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: conntrack: make conntrack userspace helpers work again
+    - netfilter: nfnetlink_cthelper: unbreak userspace helper support
+    - netfilter: nf_conntrack_pptp: prevent buffer overflows in debug code
+    - esp6: get the right proto for transport mode in esp6_gso_encap
+    - bnxt_en: Fix accumulation of bp->net_stats_prev.
+    - ieee80211: Fix incorrect mask for default PE duration
+    - xsk: Add overflow check for u64 division, stored into u32
+    - qlcnic: fix missing release in qlcnic_83xx_interrupt_test.
+    - crypto: chelsio/chtls: properly set tp->lsndtime
+    - nexthops: Move code from remove_nexthop_from_groups to remove_nh_grp_entry
+    - nexthops: don't modify published nexthop groups
+    - nexthop: Expand nexthop_is_multipath in a few places
+    - ipv4: nexthop version of fib_info_nh_uses_dev
+    - net: dsa: declare lockless TX feature for slave ports
+    - bonding: Fix reference count leak in bond_sysfs_slave_add.
+    - netfilter: conntrack: comparison of unsigned in cthelper confirmation
+    - netfilter: conntrack: Pass value of ctinfo to __nf_conntrack_update
+    - netfilter: nf_conntrack_pptp: fix compilation warning with W=1 build
+    - perf: Make perf able to build with latest libbfd
+    - Linux 5.4.44
+
+  * Focal update: v5.4.43 upstream stable release (LP: #1881178)
+    - i2c: dev: Fix the race between the release of i2c_dev and cdev
+    - KVM: SVM: Fix potential memory leak in svm_cpu_init()
+    - ima: Set file->f_mode instead of file->f_flags in ima_calc_file_hash()
+    - evm: Check also if *tfm is an error pointer in init_desc()
+    - ima: Fix return value of ima_write_policy()
+    - ubifs: fix wrong use of crypto_shash_descsize()
+    - ACPI: EC: PM: Avoid flushing EC work when EC GPE is inactive
+    - mtd: spinand: Propagate ECC information to the MTD structure
+    - fix multiplication overflow in copy_fdtable()
+    - ubifs: remove broken lazytime support
+    - i2c: fix missing pm_runtime_put_sync in i2c_device_probe
+    - iommu/amd: Fix over-read of ACPI UID from IVRS table
+    - evm: Fix a small race in init_desc()
+    - i2c: mux: demux-pinctrl: Fix an error handling path in
+      'i2c_demux_pinctrl_probe()'
+    - ubi: Fix seq_file usage in detailed_erase_block_info debugfs file
+    - afs: Don't unlock fetched data pages until the op completes successfully
+    - mtd: Fix mtd not registered due to nvmem name collision
+    - kbuild: avoid concurrency issue in parallel building dtbs and dtbs_check
+    - net: drop_monitor: use IS_REACHABLE() to guard net_dm_hw_report()
+    - gcc-common.h: Update for GCC 10
+    - HID: multitouch: add eGalaxTouch P80H84 support
+    - HID: alps: Add AUI1657 device ID
+    - HID: alps: ALPS_1657 is too specific; use U1_UNICORN_LEGACY instead
+    - scsi: qla2xxx: Fix hang when issuing nvme disconnect-all in NPIV
+    - scsi: qla2xxx: Delete all sessions before unregister local nvme port
+    - configfs: fix config_item refcnt leak in configfs_rmdir()
+    - vhost/vsock: fix packet delivery order to monitoring devices
+    - aquantia: Fix the media type of AQC100 ethernet controller in the driver
+    - component: Silence bind error on -EPROBE_DEFER
+    - net/ena: Fix build warning in ena_xdp_set()
+    - scsi: ibmvscsi: Fix WARN_ON during event pool release
+    - HID: i2c-hid: reset Synaptics SYNA2393 on resume
+    - x86/mm/cpa: Flush direct map alias during cpa
+    - ibmvnic: Skip fatal error reset after passive init
+    - x86/apic: Move TSC deadline timer debug printk
+    - gtp: set NLM_F_MULTI flag in gtp_genl_dump_pdp()
+    - HID: quirks: Add HID_QUIRK_NO_INIT_REPORTS quirk for Dell K12A keyboard-dock
+    - ceph: fix double unlock in handle_cap_export()
+    - stmmac: fix pointer check after utilization in stmmac_interrupt
+    - USB: core: Fix misleading driver bug report
+    - platform/x86: asus-nb-wmi: Do not load on Asus T100TA and T200TA
+    - iommu/amd: Call domain_flush_complete() in update_domain()
+    - drm/amd/display: Prevent dpcd reads with passive dongles
+    - KVM: selftests: Fix build for evmcs.h
+    - ARM: futex: Address build warning
+    - scripts/gdb: repair rb_first() and rb_last()
+    - ALSA: hda - constify and cleanup static NodeID tables
+    - ALSA: hda: patch_realtek: fix empty macro usage in if block
+    - ALSA: hda: Manage concurrent reg access more properly
+    - ALSA: hda/realtek - Add supported new mute Led for HP
+    - ALSA: hda/realtek - Add HP new mute led supported for ALC236
+    - ALSA: hda/realtek: Add quirk for Samsung Notebook
+    - ALSA: hda/realtek - Enable headset mic of ASUS GL503VM with ALC295
+    - ALSA: hda/realtek - Enable headset mic of ASUS UX550GE with ALC295
+    - ALSA: hda/realtek: Enable headset mic of ASUS UX581LV with ALC295
+    - KVM: x86: Fix pkru save/restore when guest CR4.PKE=0, move it to x86.c
+    - ALSA: iec1712: Initialize STDSP24 properly when using the model=staudio
+      option
+    - ALSA: pcm: fix incorrect hw_base increase
+    - ALSA: hda/realtek - Fix silent output on Gigabyte X570 Aorus Xtreme
+    - ALSA: hda/realtek - Add more fixup entries for Clevo machines
+    - scsi: qla2xxx: Do not log message when reading port speed via sysfs
+    - scsi: target: Put lun_ref at end of tmr processing
+    - arm64: Fix PTRACE_SYSEMU semantics
+    - drm/etnaviv: fix perfmon domain interation
+    - apparmor: Fix aa_label refcnt leak in policy_update
+    - dmaengine: tegra210-adma: Fix an error handling path in 'tegra_adma_probe()'
+    - drm/etnaviv: Fix a leak in submit_pin_objects()
+    - dmaengine: dmatest: Restore default for channel
+    - dmaengine: owl: Use correct lock in owl_dma_get_pchan()
+    - vsprintf: don't obfuscate NULL and error pointers
+    - drm/i915/gvt: Init DPLL/DDI vreg for virtual display instead of inheritance.
+    - drm/i915: Propagate error from completed fences
+    - powerpc: Remove STRICT_KERNEL_RWX incompatibility with RELOCATABLE
+    - powerpc/64s: Disable STRICT_KERNEL_RWX
+    - bpf: Avoid setting bpf insns pages read-only when prog is jited
+    - kbuild: Remove debug info from kallsyms linking
+    - Revert "gfs2: Don't demote a glock until its revokes are written"
+    - media: fdp1: Fix R-Car M3-N naming in debug message
+    - staging: iio: ad2s1210: Fix SPI reading
+    - staging: kpc2000: fix error return code in kp2000_pcie_probe()
+    - staging: greybus: Fix uninitialized scalar variable
+    - iio: sca3000: Remove an erroneous 'get_device()'
+    - iio: dac: vf610: Fix an error handling path in 'vf610_dac_probe()'
+    - iio: adc: ti-ads8344: Fix channel selection
+    - misc: rtsx: Add short delay after exit from ASPM
+    - tty: serial: add missing spin_lock_init for SiFive serial console
+    - mei: release me_cl object reference
+    - ipack: tpci200: fix error return code in tpci200_register()
+    - s390/kaslr: add support for R_390_JMP_SLOT relocation type
+    - device-dax: don't leak kernel memory to user space after unloading kmem
+    - rapidio: fix an error in get_user_pages_fast() error handling
+    - kasan: disable branch tracing for core runtime
+    - rxrpc: Fix the excessive initial retransmission timeout
+    - rxrpc: Fix a memory leak in rxkad_verify_response()
+    - s390/kexec_file: fix initrd location for kdump kernel
+    - flow_dissector: Drop BPF flow dissector prog ref on netns cleanup
+    - x86/unwind/orc: Fix unwind_get_return_address_ptr() for inactive tasks
+    - iio: adc: stm32-adc: Use dma_request_chan() instead
+      dma_request_slave_channel()
+    - iio: adc: stm32-adc: fix device used to request dma
+    - iio: adc: stm32-dfsdm: Use dma_request_chan() instead
+      dma_request_slave_channel()
+    - iio: adc: stm32-dfsdm: fix device used to request dma
+    - rxrpc: Trace discarded ACKs
+    - rxrpc: Fix ack discard
+    - tpm: check event log version before reading final events
+    - sched/fair: Reorder enqueue/dequeue_task_fair path
+    - sched/fair: Fix reordering of enqueue/dequeue_task_fair()
+    - sched/fair: Fix enqueue_task_fair() warning some more
+    - Linux 5.4.43
+
+  * Focal update: v5.4.42 upstream stable release (LP: #1879759)
+    - net: dsa: Do not make user port errors fatal
+    - shmem: fix possible deadlocks on shmlock_user_lock
+    - net: phy: microchip_t1: add lan87xx_phy_init to initialize the lan87xx phy.
+    - KVM: arm: vgic: Synchronize the whole guest on GIC{D,R}_I{S,C}ACTIVER read
+    - gpio: pca953x: Fix pca953x_gpio_set_config
+    - SUNRPC: Add "@len" parameter to gss_unwrap()
+    - SUNRPC: Fix GSS privacy computation of auth->au_ralign
+    - net/sonic: Fix a resource leak in an error handling path in
+      'jazz_sonic_probe()'
+    - net: moxa: Fix a potential double 'free_irq()'
+    - ftrace/selftests: workaround cgroup RT scheduling issues
+    - drop_monitor: work around gcc-10 stringop-overflow warning
+    - virtio-blk: handle block_device_operations callbacks after hot unplug
+    - sun6i: dsi: fix gcc-4.8
+    - net_sched: fix tcm_parent in tc filter dump
+    - scsi: sg: add sg_remove_request in sg_write
+    - mmc: sdhci-acpi: Add SDHCI_QUIRK2_BROKEN_64_BIT_DMA for AMDI0040
+    - dpaa2-eth: properly handle buffer size restrictions
+    - net: fix a potential recursive NETDEV_FEAT_CHANGE
+    - netlabel: cope with NULL catmap
+    - net: phy: fix aneg restart in phy_ethtool_set_eee
+    - net: stmmac: fix num_por initialization
+    - pppoe: only process PADT targeted at local interfaces
+    - Revert "ipv6: add mtu lock check in __ip6_rt_update_pmtu"
+    - tcp: fix error recovery in tcp_zerocopy_receive()
+    - tcp: fix SO_RCVLOWAT hangs with fat skbs
+    - virtio_net: fix lockdep warning on 32 bit
+    - dpaa2-eth: prevent array underflow in update_cls_rule()
+    - hinic: fix a bug of ndo_stop
+    - net: dsa: loop: Add module soft dependency
+    - net: ipv4: really enforce backoff for redirects
+    - netprio_cgroup: Fix unlimited memory leak of v2 cgroups
+    - net: tcp: fix rx timestamp behavior for tcp_recvmsg
+    - nfp: abm: fix error return code in nfp_abm_vnic_alloc()
+    - r8169: re-establish support for RTL8401 chip version
+    - umh: fix memory leak on execve failure
+    - riscv: fix vdso build with lld
+    - dmaengine: pch_dma.c: Avoid data race between probe and irq handler
+    - dmaengine: mmp_tdma: Do not ignore slave config validation errors
+    - dmaengine: mmp_tdma: Reset channel error on release
+    - selftests/ftrace: Check the first record for kprobe_args_type.tc
+    - cpufreq: intel_pstate: Only mention the BIOS disabling turbo mode once
+    - ALSA: hda/hdmi: fix race in monitor detection during probe
+    - drm/amd/powerplay: avoid using pm_en before it is initialized revised
+    - drm/amd/display: check if REFCLK_CNTL register is present
+    - drm/amd/display: Update downspread percent to match spreadsheet for DCN2.1
+    - drm/qxl: lost qxl_bo_kunmap_atomic_page in qxl_image_init_helper()
+    - drm/amdgpu: simplify padding calculations (v2)
+    - drm/amdgpu: invalidate L2 before SDMA IBs (v2)
+    - ipc/util.c: sysvipc_find_ipc() incorrectly updates position index
+    - gfs2: Another gfs2_walk_metadata fix
+    - mmc: sdhci-pci-gli: Fix no irq handler from suspend
+    - IB/hfi1: Fix another case where pq is left on waitlist
+    - ACPI: EC: PM: Avoid premature returns from acpi_s2idle_wake()
+    - pinctrl: sunrisepoint: Fix PAD lock register offset for SPT-H
+    - pinctrl: baytrail: Enable pin configuration setting for GPIO chip
+    - pinctrl: qcom: fix wrong write in update_dual_edge
+    - pinctrl: cherryview: Add missing spinlock usage in chv_gpio_irq_handler
+    - bpf: Fix error return code in map_lookup_and_delete_elem()
+    - ALSA: firewire-lib: fix 'function sizeof not defined' error of tracepoints
+      format
+    - i40iw: Fix error handling in i40iw_manage_arp_cache()
+    - drm/i915: Don't enable WaIncreaseLatencyIPCEnabled when IPC is disabled
+    - bpf, sockmap: msg_pop_data can incorrecty set an sge length
+    - bpf, sockmap: bpf_tcp_ingress needs to subtract bytes from sg.size
+    - mmc: alcor: Fix a resource leak in the error path for ->probe()
+    - mmc: sdhci-pci-gli: Fix can not access GL9750 after reboot from Windows 10
+    - mmc: core: Check request type before completing the request
+    - mmc: core: Fix recursive locking issue in CQE recovery path
+    - mmc: block: Fix request completion in the CQE timeout path
+    - gfs2: More gfs2_find_jhead fixes
+    - fork: prevent accidental access to clone3 features
+    - drm/amdgpu: force fbdev into vram
+    - NFS: Fix fscache super_cookie index_key from changing after umount
+    - nfs: fscache: use timespec64 in inode auxdata
+    - NFSv4: Fix fscache cookie aux_data to ensure change_attr is included
+    - netfilter: conntrack: avoid gcc-10 zero-length-bounds warning
+    - drm/i915/gvt: Fix kernel oops for 3-level ppgtt guest
+    - arm64: fix the flush_icache_range arguments in machine_kexec
+    - nfs: fix NULL deference in nfs4_get_valid_delegation
+    - SUNRPC: Signalled ASYNC tasks need to exit
+    - netfilter: nft_set_rbtree: Introduce and use nft_rbtree_interval_start()
+    - netfilter: nft_set_rbtree: Add missing expired checks
+    - RDMA/rxe: Always return ERR_PTR from rxe_create_mmap_info()
+    - IB/mlx4: Test return value of calls to ib_get_cached_pkey
+    - IB/core: Fix potential NULL pointer dereference in pkey cache
+    - RDMA/core: Fix double put of resource
+    - RDMA/iw_cxgb4: Fix incorrect function parameters
+    - hwmon: (da9052) Synchronize access with mfd
+    - s390/ism: fix error return code in ism_probe()
+    - mm, memcg: fix inconsistent oom event behavior
+    - NFSv3: fix rpc receive buffer size for MOUNT call
+    - pnp: Use list_for_each_entry() instead of open coding
+    - net/rds: Use ERR_PTR for rds_message_alloc_sgs()
+    - Stop the ad-hoc games with -Wno-maybe-initialized
+    - [Config] updateconfigs for CC_HAS_WARN_MAYBE_UNINITIALIZED
+    - 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
+    - gcc-10 warnings: fix low-hanging fruit
+    - gcc-10: mark more functions __init to avoid section mismatch warnings
+    - gcc-10: avoid shadowing standard library 'free()' in crypto
+    - usb: usbfs: correct kernel->user page attribute mismatch
+    - USB: usbfs: fix mmap dma mismatch
+    - ALSA: hda/realtek - Limit int mic boost for Thinkpad T530
+    - ALSA: hda/realtek - Add COEF workaround for ASUS ZenBook UX431DA
+    - ALSA: rawmidi: Fix racy buffer resize under concurrent accesses
+    - ALSA: usb-audio: Add control message quirk delay for Kingston HyperX headset
+    - usb: core: hub: limit HUB_QUIRK_DISABLE_AUTOSUSPEND to USB5534B
+    - usb: host: xhci-plat: keep runtime active when removing host
+    - usb: cdns3: gadget: prev_req->trb is NULL for ep0
+    - usb: xhci: Fix NULL pointer dereference when enqueuing trbs from urb sg list
+    - Make the "Reducing compressed framebufer size" message be DRM_INFO_ONCE()
+    - ARM: dts: dra7: Fix bus_dma_limit for PCIe
+    - ARM: dts: imx27-phytec-phycard-s-rdk: Fix the I2C1 pinctrl entries
+    - ARM: dts: imx6dl-yapp4: Fix Ursa board Ethernet connection
+    - drm/amd/display: add basic atomic check for cursor plane
+    - powerpc/32s: Fix build failure with CONFIG_PPC_KUAP_DEBUG
+    - cifs: fix leaked reference on requeued write
+    - x86: Fix early boot crash on gcc-10, third try
+    - x86/unwind/orc: Fix error handling in __unwind_start()
+    - exec: Move would_dump into flush_old_exec
+    - clk: rockchip: fix incorrect configuration of rk3228 aclk_gpu* clocks
+    - dwc3: Remove check for HWO flag in dwc3_gadget_ep_reclaim_trb_sg()
+    - fanotify: fix merging marks masks with FAN_ONDIR
+    - 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()
+    - clk: Unlink clock if failed to prepare or enable
+    - arm64: dts: meson-g12b-khadas-vim3: add missing frddr_a status property
+    - arm64: dts: meson-g12-common: fix dwc2 clock names
+    - arm64: dts: rockchip: Replace RK805 PMIC node name with "pmic" on rk3328
+      boards
+    - arm64: dts: rockchip: Rename dwc3 device nodes on rk3399 to make dtc happy
+    - arm64: dts: imx8mn: Change SDMA1 ahb clock for imx8mn
+    - ARM: dts: r8a73a4: Add missing CMT1 interrupts
+    - arm64: dts: renesas: r8a77980: Fix IPMMU VIP[01] nodes
+    - ARM: dts: r8a7740: Add missing extal2 to CPG node
+    - SUNRPC: Revert 241b1f419f0e ("SUNRPC: Remove xdr_buf_trim()")
+    - bpf: Fix sk_psock refcnt leak when receiving message
+    - KVM: x86: Fix off-by-one error in kvm_vcpu_ioctl_x86_setup_mce
+    - Makefile: disallow data races on gcc-10 as well
+    - Linux 5.4.42
+
+  * upgrading to 4.15.0-99-generic breaks the sound and the trackpad
+    (LP: #1875916) // Focal update: v5.4.42 upstream stable release
+    (LP: #1879759)
+    - Revert "ALSA: hda/realtek: Fix pop noise on ALC225"
+
+  * Pop sound from build-in speaker during cold boot and resume from S3
+    (LP: #1866357) // Focal update: v5.4.42 upstream stable release
+    (LP: #1879759)
+    - ALSA: hda/realtek - Fix S3 pop noise on Dell Wyse
+
+  * tpm: fix TIS locality timeout problems (LP: #1881710)
+    - SAUCE: tpm: fix TIS locality timeout problems
+
+  * [UBUNTU 20.04] s390x/pci: fix linking between PF and VF for multifunction
+    devices (LP: #1879704)
+    - PCI/IOV: Introduce pci_iov_sysfs_link() function
+    - s390/pci: create links between PFs and VFs
+
+  * Performing function level reset of AMD onboard USB and audio devices causes
+    system lockup (LP: #1865988)
+    - SAUCE: PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0
+    - SAUCE: PCI: Avoid FLR for AMD Starship USB 3.0
+
+  * seccomp_benchmark times out on eoan (LP: #1881576)
+    - SAUCE: selftests/seccomp: use 90s as timeout
+
+  * ASoC/amd: add audio driver for amd renoir (LP: #1881046)
+    - ASoC: amd: add Renoir ACP3x IP register header
+    - ASoC: amd: add Renoir ACP PCI driver
+    - ASoC: amd: add acp init/de-init functions
+    - ASoC: amd: create acp3x pdm platform device
+    - ASoC: amd: add ACP3x PDM platform driver
+    - ASoC: amd: irq handler changes for ACP3x PDM dma driver
+    - ASoC: amd: add acp3x pdm driver dma ops
+    - ASoC: amd: add ACP PDM DMA driver dai ops
+    - ASoC: amd: add Renoir ACP PCI driver PM ops
+    - ASoC: amd: add ACP PDM DMA driver pm ops
+    - ASoC: amd: enable Renoir acp3x drivers build
+    - ASoC: amd: create platform devices for Renoir
+    - ASoC: amd: RN machine driver using dmic
+    - ASoC: amd: enable build for RN machine driver
+    - ASoC: amd: fix kernel warning
+    - ASoC: amd: refactoring dai_hw_params() callback
+    - ASoC: amd: return error when acp de-init fails
+    - [Config]: enable amd renoir ASoC audio
+
+  * Fix for secure boot rules in IMA arch policy on powerpc (LP: #1877955)
+    - powerpc/ima: Fix secure boot rules in ima arch policy
+
+  * [UBUNTU 20.04] s390x/pci: s390_pci_mmio_write/read fail when MIO
+    instructions are available (LP: #1874055)
+    - s390/pci: Fix s390_mmio_read/write with MIO
+
+  * security: lockdown: remove trailing semicolon before function body
+    (LP: #1880660)
+    - SAUCE: (lockdown) security: lockdown: remove trailing semicolon before
+      function body
+
+  * Fix incorrect speed/duplex when I210 device is runtime suspended
+    (LP: #1880656)
+    - igb: Report speed and duplex as unknown when device is runtime suspended
+
+  * [OMEN by HP Laptop 15-dh0xxx, Realtek ALC285, Black Mic, Left] Recording
+    problem (LP: #1874698)
+    - ASoC: SOF: Intel: hda: allow operation without i915 gfx
+    - ASoC: intel/skl/hda - add no-HDMI cases to generic HDA driver
+
+  * CVE-2020-13143
+    - USB: gadget: fix illegal array access in binding with UDC
+
+  * rtl8723bu wifi issue after being turned off (LP: #1878296)
+    - rtl8xxxu: Improve TX performance of RTL8723BU on rtl8xxxu driver
+    - rtl8xxxu: add bluetooth co-existence support for single antenna
+    - rtl8xxxu: remove set but not used variable 'rate_mask'
+    - rtl8xxxu: Remove set but not used variable 'vif', 'dev', 'len'
+
+  * Fix Pericom USB controller OHCI/EHCI PME# defect (LP: #1879321)
+    - serial: 8250_pci: Move Pericom IDs to pci_ids.h
+    - PCI: Avoid Pericom USB controller OHCI/EHCI PME# defect
+
+  * shiftfs: fix btrfs snapshot deletion (LP: #1879688)
+    - SAUCE: shiftfs: let userns root destroy subvolumes from other users
+
+  * [UBUNTU 20.04] s390x/pci: enumerate pci functions per physical adapter
+    (LP: #1874056)
+    - s390/pci: Improve handling of unset UID
+    - s390/pci: embedding hotplug_slot in zdev
+    - s390/pci: Expose new port attribute for PCIe functions
+    - s390/pci: adaptation of iommu to multifunction
+    - s390/pci: define kernel parameters for PCI multifunction
+    - s390/pci: define RID and RID available
+    - s390/pci: create zPCI bus
+    - s390/pci: adapt events for zbus
+    - s390/pci: Handling multifunctions
+    - s390/pci: Do not disable PF when VFs exist
+    - s390/pci: Documentation for zPCI
+    - s390/pci: removes wrong PCI multifunction assignment
+
+  * update-initramfs complains of missing amdgpu firmware files (LP: #1873325)
+    - SAUCE: drm/amdgpu: Remove unreleased arcturus and navi12 firmware from
+      modinfo
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Mon, 22 Jun 2020 17:59:17 -0300
+
+linux (5.4.0-39.43) focal; urgency=medium
+
+  * dkms-build: downloads fail in private PPAs (LP: #1883874)
+    - dkms-build: apt-cache policy elides username:password information
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Fri, 19 Jun 2020 11:56:47 +0200
+
+linux (5.4.0-37.41) focal; urgency=medium
+
+  * CVE-2020-0543
+    - SAUCE: x86/speculation/spectre_v2: Exclude Zhaoxin CPUs from SPECTRE_V2
+    - 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
+
+ -- Marcelo Henrique Cerri <marcelo.cerri@canonical.com>  Wed, 03 Jun 2020 11:24:23 -0300
+
+linux (5.4.0-34.38) focal; urgency=medium
+
+  * focal/linux: 5.4.0-34.38 -proposed tracker (LP: #1880118)
+
+  * debian/scripts/file-downloader does not handle positive failures correctly
+    (LP: #1878897)
+    - [Packaging] file-downloader not handling positive failures correctly
+
+  * Focal update: v5.4.41 upstream stable release (LP: #1878649)
+    - USB: serial: qcserial: Add DW5816e support
+    - nvme: refactor nvme_identify_ns_descs error handling
+    - nvme: fix possible hang when ns scanning fails during error recovery
+    - tracing/kprobes: Fix a double initialization typo
+    - net: macb: Fix runtime PM refcounting
+    - drm/amdgpu: move kfd suspend after ip_suspend_phase1
+    - drm/amdgpu: drop redundant cg/pg ungate on runpm enter
+    - vt: fix unicode console freeing with a common interface
+    - tty: xilinx_uartps: Fix missing id assignment to the console
+    - devlink: fix return value after hitting end in region read
+    - dp83640: reverse arguments to list_add_tail
+    - fq_codel: fix TCA_FQ_CODEL_DROP_BATCH_SIZE sanity checks
+    - ipv6: Use global sernum for dst validation with nexthop objects
+    - mlxsw: spectrum_acl_tcam: Position vchunk in a vregion list properly
+    - neigh: send protocol value in neighbor create notification
+    - net: dsa: Do not leave DSA master with NULL netdev_ops
+    - net: macb: fix an issue about leak related system resources
+    - net: macsec: preserve ingress frame ordering
+    - net/mlx4_core: Fix use of ENOSPC around mlx4_counter_alloc()
+    - net_sched: sch_skbprio: add message validation to skbprio_change()
+    - net: stricter validation of untrusted gso packets
+    - net: tc35815: Fix phydev supported/advertising mask
+    - net/tls: Fix sk_psock refcnt leak in bpf_exec_tx_verdict()
+    - net/tls: Fix sk_psock refcnt leak when in tls_data_ready()
+    - net: usb: qmi_wwan: add support for DW5816e
+    - nfp: abm: fix a memory leak bug
+    - sch_choke: avoid potential panic in choke_reset()
+    - sch_sfq: validate silly quantum values
+    - tipc: fix partial topology connection closure
+    - tunnel: Propagate ECT(1) when decapsulating as recommended by RFC6040
+    - bnxt_en: Fix VF anti-spoof filter setup.
+    - bnxt_en: Reduce BNXT_MSIX_VEC_MAX value to supported CQs per PF.
+    - bnxt_en: Improve AER slot reset.
+    - bnxt_en: Return error when allocating zero size context memory.
+    - bnxt_en: Fix VLAN acceleration handling in bnxt_fix_features().
+    - net/mlx5: DR, On creation set CQ's arm_db member to right value
+    - net/mlx5: Fix forced completion access non initialized command entry
+    - net/mlx5: Fix command entry leak in Internal Error State
+    - net: mvpp2: prevent buffer overflow in mvpp22_rss_ctx()
+    - net: mvpp2: cls: Prevent buffer overflow in mvpp2_ethtool_cls_rule_del()
+    - HID: wacom: Read HID_DG_CONTACTMAX directly for non-generic devices
+    - sctp: Fix bundling of SHUTDOWN with COOKIE-ACK
+    - Revert "HID: wacom: generic: read the number of expected touches on a per
+      collection basis"
+    - HID: usbhid: Fix race between usbhid_close() and usbhid_stop()
+    - HID: wacom: Report 2nd-gen Intuos Pro S center button status over BT
+    - USB: uas: add quirk for LaCie 2Big Quadra
+    - usb: chipidea: msm: Ensure proper controller reset using role switch API
+    - USB: serial: garmin_gps: add sanity checking for data length
+    - tracing: Add a vmalloc_sync_mappings() for safe measure
+    - crypto: arch/nhpoly1305 - process in explicit 4k chunks
+    - KVM: s390: Remove false WARN_ON_ONCE for the PQAP instruction
+    - KVM: VMX: Explicitly clear RFLAGS.CF and RFLAGS.ZF in VM-Exit RSB path
+    - KVM: arm: vgic: Fix limit condition when writing to GICD_I[CS]ACTIVER
+    - KVM: arm64: Fix 32bit PC wrap-around
+    - arm64: hugetlb: avoid potential NULL dereference
+    - drm: ingenic-drm: add MODULE_DEVICE_TABLE
+    - ipc/mqueue.c: change __do_notify() to bypass check_kill_permission()
+    - epoll: atomically remove wait entry on wake up
+    - eventpoll: fix missing wakeup for ovflist in ep_poll_callback
+    - mm/page_alloc: fix watchdog soft lockups during set_zone_contiguous()
+    - mm: limit boost_watermark on small zones
+    - ceph: demote quotarealm lookup warning to a debug message
+    - staging: gasket: Check the return value of gasket_get_bar_index()
+    - coredump: fix crash when umh is disabled
+    - iocost: protect iocg->abs_vdebt with iocg->waitq.lock
+    - batman-adv: fix batadv_nc_random_weight_tq
+    - batman-adv: Fix refcnt leak in batadv_show_throughput_override
+    - batman-adv: Fix refcnt leak in batadv_store_throughput_override
+    - batman-adv: Fix refcnt leak in batadv_v_ogm_process
+    - x86/entry/64: Fix unwind hints in register clearing code
+    - x86/entry/64: Fix unwind hints in kernel exit path
+    - x86/entry/64: Fix unwind hints in rewind_stack_do_exit()
+    - x86/unwind/orc: Don't skip the first frame for inactive tasks
+    - x86/unwind/orc: Prevent unwinding before ORC initialization
+    - x86/unwind/orc: Fix error path for bad ORC entry type
+    - x86/unwind/orc: Fix premature unwind stoppage due to IRET frames
+    - KVM: x86: Fixes posted interrupt check for IRQs delivery modes
+    - arch/x86/kvm/svm/sev.c: change flag passed to GUP fast in sev_pin_memory()
+    - netfilter: nat: never update the UDP checksum when it's 0
+    - netfilter: nf_osf: avoid passing pointer to local var
+    - objtool: Fix stack offset tracking for indirect CFAs
+    - iommu/virtio: Reverse arguments to list_add
+    - scripts/decodecode: fix trapping instruction formatting
+    - mm, memcg: fix error return value of mem_cgroup_css_alloc()
+    - bdi: move bdi_dev_name out of line
+    - bdi: add a ->dev_name field to struct backing_dev_info
+    - fsnotify: replace inode pointer with an object id
+    - fanotify: merge duplicate events on parent and child
+    - Linux 5.4.41
+
+  * Intel GPU Hangs : random screen freezing w/ Ubuntu 20.04 (Linux 5.4)
+    i915_active_acquire (LP: #1868551)
+    - drm/i915: Hold reference to intel_frontbuffer as we track activity
+    - drm/i915: fix uninitialized pointer reads on pointers to and from
+
+  * Kernel panic due to NULL ringbuffer vaddr dereference in i915 (LP: #1877394)
+    - Revert "UBUNTU: SAUCE: drm/i915: Synchronize active and retire callbacks"
+    - drm/i915/gt: Make intel_ring_unpin() safe for concurrent pint
+
+  * add 16-bit width registers support for EEPROM at24 device (LP: #1876699)
+    - regmap-i2c: add 16-bit width registers support
+
+  * [UBUNTU 20.04] PSI generates overhead on s390x (LP: #1876044)
+    - Ubuntu: [Config] Set CONFIG_PSI_DEFAULT_DISABLED=y on s390x
+
+  * Focal update: v5.4.40 upstream stable release (LP: #1878040)
+    - vhost: vsock: kick send_pkt worker once device is started
+    - drm/bridge: analogix_dp: Split bind() into probe() and real bind()
+    - ASoC: topology: Check return value of soc_tplg_create_tlv
+    - ASoC: topology: Check return value of soc_tplg_*_create
+    - ASoC: topology: Check soc_tplg_add_route return value
+    - ASoC: topology: Check return value of pcm_new_ver
+    - ASoC: topology: Check return value of soc_tplg_dai_config
+    - selftests/ipc: Fix test failure seen after initial test run
+    - ASoC: sgtl5000: Fix VAG power-on handling
+    - ASoC: topology: Fix endianness issue
+    - usb: dwc3: gadget: Properly set maxpacket limit
+    - ASoC: rsnd: Fix parent SSI start/stop in multi-SSI mode
+    - ASoC: rsnd: Fix HDMI channel mapping for multi-SSI mode
+    - ASoC: codecs: hdac_hdmi: Fix incorrect use of list_for_each_entry
+    - remoteproc: qcom_q6v5_mss: fix a bug in q6v5_probe()
+    - drm/amdgpu: Correctly initialize thermal controller for GPUs with Powerplay
+      table v0 (e.g Hawaii)
+    - wimax/i2400m: Fix potential urb refcnt leak
+    - net: stmmac: fix enabling socfpga's ptp_ref_clock
+    - net: stmmac: Fix sub-second increment
+    - ASoC: rsnd: Don't treat master SSI in multi SSI setup as parent
+    - ASoC: rsnd: Fix "status check failed" spam for multi-SSI
+    - cifs: protect updating server->dstaddr with a spinlock
+    - scripts/config: allow colons in option strings for sed
+    - cifs: do not share tcons with DFS
+    - tracing: Fix memory leaks in trace_events_hist.c
+    - lib/mpi: Fix building for powerpc with clang
+    - mac80211: sta_info: Add lockdep condition for RCU list usage
+    - net: bcmgenet: suppress warnings on failed Rx SKB allocations
+    - net: systemport: suppress warnings on failed Rx SKB allocations
+    - drm/i915: Extend WaDisableDARBFClkGating to icl,ehl,tgl
+    - sctp: Fix SHUTDOWN CTSN Ack in the peer restart case
+    - Revert "software node: Simplify software_node_release() function"
+    - hexagon: clean up ioremap
+    - hexagon: define ioremap_uc
+    - ALSA: hda: Match both PCI ID and SSID for driver blacklist
+    - x86/kvm: fix a missing-prototypes "vmread_error"
+    - platform/x86: GPD pocket fan: Fix error message when temp-limits are out of
+      range
+    - ACPI: PM: s2idle: Fix comment in acpi_s2idle_prepare_late()
+    - mac80211: add ieee80211_is_any_nullfunc()
+    - cgroup, netclassid: remove double cond_resched
+    - libbpf: Fix readelf output parsing for Fedora
+    - mm/mremap: Add comment explaining the untagging behaviour of mremap()
+    - Revert "drm/amd/display: setting the DIG_MODE to the correct value."
+    - tools headers UAPI: Sync copy of arm64's asm/unistd.h with the kernel
+      sources
+    - udp: document udp_rcv_segment special case for looped packets
+    - PM / devfreq: Add missing locking while setting suspend_freq
+    - Linux 5.4.40
+
+  * Focal update: v5.4.39 upstream stable release (LP: #1877592)
+    - dma-buf: Fix SET_NAME ioctl uapi
+    - drm/edid: Fix off-by-one in DispID DTD pixel clock
+    - drm/amd/display: Fix green screen issue after suspend
+    - drm/qxl: qxl_release leak in qxl_draw_dirty_fb()
+    - drm/qxl: qxl_release leak in qxl_hw_surface_alloc()
+    - drm/qxl: qxl_release use after free
+    - NFSv4.1: fix handling of backchannel binding in BIND_CONN_TO_SESSION
+    - btrfs: fix transaction leak in btrfs_recover_relocation
+    - btrfs: fix block group leak when removing fails
+    - btrfs: fix partial loss of prealloc extent past i_size after fsync
+    - btrfs: transaction: Avoid deadlock due to bad initialization timing of
+      fs_info::journal_info
+    - mmc: cqhci: Avoid false "cqhci: CQE stuck on" by not open-coding timeout
+      loop
+    - mmc: sdhci-xenon: fix annoying 1.8V regulator warning
+    - mmc: sdhci-pci: Fix eMMC driver strength for BYT-based controllers
+    - mmc: sdhci-msm: Enable host capabilities pertains to R1b response
+    - mmc: meson-mx-sdio: Set MMC_CAP_WAIT_WHILE_BUSY
+    - mmc: meson-mx-sdio: remove the broken ->card_busy() op
+    - crypto: caam - fix the address of the last entry of S/G
+    - ALSA: hda/realtek - Two front mics on a Lenovo ThinkCenter
+    - ALSA: usb-audio: Correct a typo of NuPrime DAC-10 USB ID
+    - ALSA: hda/hdmi: fix without unlocked before return
+    - ALSA: line6: Fix POD HD500 audio playback
+    - ALSA: pcm: oss: Place the plugin buffer overflow checks correctly
+    - i2c: amd-mp2-pci: Fix Oops in amd_mp2_pci_init() error handling
+    - Drivers: hv: vmbus: Fix Suspend-to-Idle for Generation-2 VM
+    - dlmfs_file_write(): fix the bogosity in handling non-zero *ppos
+    - IB/rdmavt: Always return ERR_PTR from rvt_create_mmap_info()
+    - PM: ACPI: Output correct message on target power state
+    - PM: hibernate: Freeze kernel threads in software_resume()
+    - dm verity fec: fix hash block number in verity_fec_decode
+    - dm writecache: fix data corruption when reloading the target
+    - dm multipath: use updated MPATHF_QUEUE_IO on mapping for bio-based mpath
+    - ARM: dts: imx6qdl-sr-som-ti: indicate powering off wifi is safe
+    - scsi: qla2xxx: set UNLOADING before waiting for session deletion
+    - scsi: qla2xxx: check UNLOADING before posting async work
+    - RDMA/mlx5: Set GRH fields in query QP on RoCE
+    - RDMA/mlx4: Initialize ib_spec on the stack
+    - RDMA/siw: Fix potential siw_mem refcnt leak in siw_fastreg_mr()
+    - RDMA/core: Prevent mixed use of FDs between shared ufiles
+    - RDMA/core: Fix race between destroy and release FD object
+    - RDMA/cm: Fix ordering of xa_alloc_cyclic() in ib_create_cm_id()
+    - RDMA/cm: Fix an error check in cm_alloc_id_priv()
+    - i2c: iproc: generate stop event for slave writes
+    - vfio: avoid possible overflow in vfio_iommu_type1_pin_pages
+    - vfio/type1: Fix VA->PA translation for PFNMAP VMAs in vaddr_get_pfn()
+    - iommu/qcom: Fix local_base status check
+    - scsi: target/iblock: fix WRITE SAME zeroing
+    - iommu/amd: Fix legacy interrupt remapping for x2APIC-enabled system
+    - i2c: aspeed: Avoid i2c interrupt status clear race condition.
+    - ALSA: opti9xx: shut up gcc-10 range warning
+    - Fix use after free in get_tree_bdev()
+    - nvme: prevent double free in nvme_alloc_ns() error handling
+    - nfs: Fix potential posix_acl refcnt leak in nfs3_set_acl
+    - dmaengine: dmatest: Fix iteration non-stop logic
+    - dmaengine: dmatest: Fix process hang when reading 'wait' parameter
+    - arm64: vdso: Add -fasynchronous-unwind-tables to cflags
+    - selinux: properly handle multiple messages in selinux_netlink_send()
+    - Linux 5.4.39
+
+  * Focal update: v5.4.38 upstream stable release (LP: #1876767)
+    - Linux 5.4.38
+
+  * Focal update: v5.4.37 upstream stable release (LP: #1876765)
+    - remoteproc: Fix wrong rvring index computation
+    - ubifs: Fix ubifs_tnc_lookup() usage in do_kill_orphans()
+    - printk: queue wake_up_klogd irq_work only if per-CPU areas are ready
+    - ASoC: stm32: sai: fix sai probe
+    - usb: dwc3: gadget: Do link recovery for SS and SSP
+    - kbuild: fix DT binding schema rule again to avoid needless rebuilds
+    - usb: gadget: udc: bdc: Remove unnecessary NULL checks in bdc_req_complete
+    - usb: gadget: udc: atmel: Fix vbus disconnect handling
+    - afs: Make record checking use TASK_UNINTERRUPTIBLE when appropriate
+    - afs: Fix to actually set AFS_SERVER_FL_HAVE_EPOCH
+    - iio:ad7797: Use correct attribute_group
+    - propagate_one(): mnt_set_mountpoint() needs mount_lock
+    - counter: 104-quad-8: Add lock guards - generic interface
+    - s390/ftrace: fix potential crashes when switching tracers
+    - ASoC: q6dsp6: q6afe-dai: add missing channels to MI2S DAIs
+    - ASoC: tas571x: disable regulators on failed probe
+    - ASoC: wm8960: Fix wrong clock after suspend & resume
+    - drivers: soc: xilinx: fix firmware driver Kconfig dependency
+    - nfsd: memory corruption in nfsd4_lock()
+    - bpf: Forbid XADD on spilled pointers for unprivileged users
+    - i2c: altera: use proper variable to hold errno
+    - rxrpc: Fix DATA Tx to disable nofrag for UDP on AF_INET6 socket
+    - net/cxgb4: Check the return from t4_query_params properly
+    - xfs: acquire superblock freeze protection on eofblocks scans
+    - svcrdma: Fix trace point use-after-free race
+    - svcrdma: Fix leak of svc_rdma_recv_ctxt objects
+    - net/mlx5e: Don't trigger IRQ multiple times on XSK wakeup to avoid WQ
+      overruns
+    - net/mlx5e: Get the latest values from counters in switchdev mode
+    - PCI: Add ACS quirk for Zhaoxin multi-function devices
+    - PCI: Make ACS quirk implementations more uniform
+    - PCI: Unify ACS quirk desired vs provided checking
+    - PCI: Add Zhaoxin Vendor ID
+    - PCI: Add ACS quirk for Zhaoxin Root/Downstream Ports
+    - PCI: Move Apex Edge TPU class quirk to fix BAR assignment
+    - ARM: dts: bcm283x: Disable dsi0 node
+    - cpumap: Avoid warning when CONFIG_DEBUG_PER_CPU_MAPS is enabled
+    - s390/pci: do not set affinity for floating irqs
+    - net/mlx5: Fix failing fw tracer allocation on s390
+    - sched/core: Fix reset-on-fork from RT with uclamp
+    - perf/core: fix parent pid/tid in task exit events
+    - netfilter: nat: fix error handling upon registering inet hook
+    - PM: sleep: core: Switch back to async_schedule_dev()
+    - blk-iocost: Fix error on iocost_ioc_vrate_adj
+    - um: ensure `make ARCH=um mrproper` removes
+      arch/$(SUBARCH)/include/generated/
+    - bpf, x86_32: Fix incorrect encoding in BPF_LDX zero-extension
+    - bpf, x86_32: Fix clobbering of dst for BPF_JSET
+    - bpf, x86_32: Fix logic error in BPF_LDX zero-extension
+    - mm: shmem: disable interrupt when acquiring info->lock in userfaultfd_copy
+      path
+    - xfs: clear PF_MEMALLOC before exiting xfsaild thread
+    - bpf, x86: Fix encoding for lower 8-bit registers in BPF_STX BPF_B
+    - libbpf: Initialize *nl_pid so gcc 10 is happy
+    - net: fec: set GPR bit on suspend by DT configuration.
+    - x86: hyperv: report value of misc_features
+    - signal: check sig before setting info in kill_pid_usb_asyncio
+    - afs: Fix length of dump of bad YFSFetchStatus record
+    - xfs: fix partially uninitialized structure in xfs_reflink_remap_extent
+    - ALSA: hda: Release resources at error in delayed probe
+    - ALSA: hda: Keep the controller initialization even if no codecs found
+    - ALSA: hda: Explicitly permit using autosuspend if runtime PM is supported
+    - scsi: target: fix PR IN / READ FULL STATUS for FC
+    - scsi: target: tcmu: reset_ring should reset TCMU_DEV_BIT_BROKEN
+    - objtool: Fix CONFIG_UBSAN_TRAP unreachable warnings
+    - objtool: Support Clang non-section symbols in ORC dump
+    - xen/xenbus: ensure xenbus_map_ring_valloc() returns proper grant status
+    - ALSA: hda: call runtime_allow() for all hda controllers
+    - net: stmmac: socfpga: Allow all RGMII modes
+    - mac80211: fix channel switch trigger from unknown mesh peer
+    - arm64: Delete the space separator in __emit_inst
+    - ext4: use matching invalidatepage in ext4_writepage
+    - ext4: increase wait time needed before reuse of deleted inode numbers
+    - ext4: convert BUG_ON's to WARN_ON's in mballoc.c
+    - blk-mq: Put driver tag in blk_mq_dispatch_rq_list() when no budget
+    - hwmon: (jc42) Fix name to have no illegal characters
+    - taprio: do not use BIT() in TCA_TAPRIO_ATTR_FLAG_* definitions
+    - qed: Fix race condition between scheduling and destroying the slowpath
+      workqueue
+    - Crypto: chelsio - Fixes a hang issue during driver registration
+    - net: use indirect call wrappers for skb_copy_datagram_iter()
+    - qed: Fix use after free in qed_chain_free
+    - ext4: check for non-zero journal inum in ext4_calculate_overhead
+    - ASoC: soc-core: disable route checks for legacy devices
+    - ASoC: stm32: spdifrx: fix regmap status check
+    - Linux 5.4.37
+
+  * Focal update: v5.4.36 upstream stable release (LP: #1876361)
+    - ext4: fix extent_status fragmentation for plain files
+    - f2fs: fix to avoid memory leakage in f2fs_listxattr
+    - net, ip_tunnel: fix interface lookup with no key
+    - [Config] updateconfigs for ARM64_ERRATUM_1542419
+    - arm64: errata: Hide CTR_EL0.DIC on systems affected by Neoverse-N1 #1542419
+    - arm64: Fake the IminLine size on systems affected by Neoverse-N1 #1542419
+    - arm64: compat: Workaround Neoverse-N1 #1542419 for compat user-space
+    - arm64: Silence clang warning on mismatched value/register sizes
+    - tools/testing/nvdimm: Fix compilation failure without
+      CONFIG_DEV_DAX_PMEM_COMPAT
+    - watchdog: reset last_hw_keepalive time at start
+    - scsi: lpfc: Fix kasan slab-out-of-bounds error in lpfc_unreg_login
+    - scsi: lpfc: Fix crash after handling a pci error
+    - scsi: lpfc: Fix crash in target side cable pulls hitting WAIT_FOR_UNREG
+    - scsi: libfc: If PRLI rejected, move rport to PLOGI state
+    - 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
+    - nvme-tcp: fix possible crash in write_zeroes processing
+    - scsi: iscsi: Report unbind session event when the target has been removed
+    - tools/test/nvdimm: Fix out of tree build
+    - ASoC: Intel: atom: Take the drv->lock mutex before calling
+      sst_send_slot_map()
+    - nvme: fix deadlock caused by ANA update wrong locking
+    - drm/amd/display: Update stream adjust in dc_stream_adjust_vmin_vmax
+    - dma-direct: fix data truncation in dma_direct_get_required_mask()
+    - kernel/gcov/fs.c: gcov_seq_next() should increase position index
+    - selftests: kmod: fix handling test numbers above 9
+    - ipc/util.c: sysvipc_find_ipc() should increase position index
+    - kconfig: qconf: Fix a few alignment issues
+    - lib/raid6/test: fix build on distros whose /bin/sh is not bash
+    - s390/cio: generate delayed uevent for vfio-ccw subchannels
+    - s390/cio: avoid duplicated 'ADD' uevents
+    - loop: Better discard support for block devices
+    - Revert "powerpc/64: irq_work avoid interrupt when called with hardware irqs
+      enabled"
+    - powerpc/pseries: Fix MCE handling on pseries
+    - nvme: fix compat address handling in several ioctls
+    - pwm: renesas-tpu: Fix late Runtime PM enablement
+    - pwm: bcm2835: Dynamically allocate base
+    - perf/core: Disable page faults when getting phys address
+    - drm/amd/display: Calculate scaling ratios on every medium/full update
+    - ASoC: Intel: bytcr_rt5640: Add quirk for MPMAN MPWIN895CL tablet
+    - ALSA: usb-audio: Add Pioneer DJ DJM-250MK2 quirk
+    - drm/amd/display: Not doing optimize bandwidth if flip pending.
+    - cxgb4: fix adapter crash due to wrong MC size
+    - cxgb4: fix large delays in PTP synchronization
+    - ipv4: Update fib_select_default to handle nexthop objects
+    - ipv6: fix restrict IPV6_ADDRFORM operation
+    - macsec: avoid to set wrong mtu
+    - macvlan: fix null dereference in macvlan_device_event()
+    - mlxsw: Fix some IS_ERR() vs NULL bugs
+    - net: bcmgenet: correct per TX/RX ring statistics
+    - net/mlx4_en: avoid indirect call in TX completion
+    - net: netrom: Fix potential nr_neigh refcnt leak in nr_add_node
+    - net: openvswitch: ovs_ct_exit to be done under ovs_lock
+    - net: stmmac: dwmac-meson8b: Add missing boundary to RGMII TX clock array
+    - net/x25: Fix x25_neigh refcnt leak when receiving frame
+    - sched: etf: do not assume all sockets are full blown
+    - selftests: Fix suppress test in fib_tests.sh
+    - tcp: cache line align MAX_TCP_HEADER
+    - team: fix hang in team_mode_get()
+    - vrf: Fix IPv6 with qdisc and xfrm
+    - net: dsa: b53: Lookup VID in ARL searches when VLAN is enabled
+    - net: dsa: b53: Fix valid setting for MDB entries
+    - net: dsa: b53: Fix ARL register definitions
+    - net: dsa: b53: Rework ARL bin logic
+    - net: dsa: b53: b53_arl_rw_op() needs to select IVL or SVL
+    - vxlan: use the correct nlattr array in NL_SET_ERR_MSG_ATTR
+    - geneve: use the correct nlattr array in NL_SET_ERR_MSG_ATTR
+    - xfrm: Always set XFRM_TRANSFORMED in xfrm{4,6}_output_finish
+    - vrf: Check skb for XFRM_TRANSFORMED flag
+    - KEYS: Avoid false positive ENOMEM error on key read
+    - ALSA: hda: Remove ASUS ROG Zenith from the blacklist
+    - ALSA: usb-audio: Add static mapping table for ALC1220-VB-based mobos
+    - ALSA: usb-audio: Add connector notifier delegation
+    - iio: core: remove extra semi-colon from devm_iio_device_register() macro
+    - iio: st_sensors: rely on odr mask to know if odr can be set
+    - iio: adc: stm32-adc: fix sleep in atomic context
+    - iio: adc: ti-ads8344: properly byte swap value
+    - 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
+    - iio: xilinx-xadc: Make sure not exceed maximum samplerate
+    - 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
+    - USB: early: Handle AMD's spec-compliant identifiers, too
+    - USB: core: Fix free-while-in-use bug in the USB S-Glibrary
+    - USB: hub: Fix handling of connect changes during sleep
+    - USB: hub: Revert commit bd0e6c9614b9 ("usb: hub: try old enumeration scheme
+      first for high speed devices")
+    - tty: serial: owl: add "much needed" clk_prepare_enable()
+    - vmalloc: fix remap_vmalloc_range() bounds checks
+    - staging: gasket: Fix incongruency in handling of sysfs entries creation
+    - coredump: fix null pointer dereference on coredump
+    - mm/hugetlb: fix a addressing exception caused by huge_pte_offset
+    - mm/ksm: fix NULL pointer dereference when KSM zero page is enabled
+    - tools/vm: fix cross-compile build
+    - ALSA: usx2y: Fix potential NULL dereference
+    - ALSA: hda/realtek - Fix unexpected init_amp override
+    - ALSA: hda/realtek - Add new codec supported for ALC245
+    - ALSA: hda/hdmi: Add module option to disable audio component binding
+    - ALSA: usb-audio: Fix usb audio refcnt leak when getting spdif
+    - ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices
+    - tpm/tpm_tis: Free IRQ if probing fails
+    - tpm: fix wrong return value in tpm_pcr_extend
+    - tpm: ibmvtpm: retry on H_CLOSED in tpm_ibmvtpm_send()
+    - KVM: s390: Return last valid slot if approx index is out-of-bounds
+    - 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
+    - signal: Avoid corrupting si_pid and si_uid in do_notify_parent
+    - audit: check the length of userspace generated audit records
+    - ASoC: dapm: fixup dapm kcontrol widget
+    - mac80211: populate debugfs only after cfg80211 init
+    - SUNRPC: Fix backchannel RPC soft lockups
+    - iwlwifi: pcie: actually release queue memory in TVQM
+    - iwlwifi: mvm: beacon statistics shouldn't go backwards
+    - iwlwifi: mvm: limit maximum queue appropriately
+    - iwlwifi: mvm: Do not declare support for ACK Enabled Aggregation
+    - iwlwifi: mvm: fix inactive TID removal return value usage
+    - cifs: fix uninitialised lease_key in open_shroot()
+    - ARM: imx: provide v7_cpu_resume() only on ARM_CPU_SUSPEND=y
+    - powerpc/setup_64: Set cache-line-size based on cache-block-size
+    - staging: comedi: dt2815: fix writing hi byte of analog output
+    - staging: comedi: Fix comedi_device refcnt leak in comedi_open
+    - vt: don't hardcode the mem allocation upper bound
+    - vt: don't use kmalloc() for the unicode screen buffer
+    - staging: vt6656: Don't set RCR_MULTICAST or RCR_BROADCAST by default.
+    - staging: vt6656: Fix calling conditions of vnt_set_bss_mode
+    - staging: vt6656: Fix drivers TBTT timing counter.
+    - staging: vt6656: Fix pairwise key entry save.
+    - staging: vt6656: Power save stop wake_up_count wrap around.
+    - cdc-acm: close race betrween suspend() and acm_softint
+    - cdc-acm: introduce a cool down
+    - UAS: no use logging any details in case of ENODEV
+    - UAS: fix deadlock in error handling and PM flushing work
+    - fpga: dfl: pci: fix return value of cci_pci_sriov_configure
+    - usb: dwc3: gadget: Fix request completion check
+    - usb: f_fs: Clear OS Extended descriptor counts to zero in ffs_data_reset()
+    - usb: typec: tcpm: Ignore CC and vbus changes in PORT_RESET change
+    - usb: typec: altmode: Fix typec_altmode_get_partner sometimes returning an
+      invalid pointer
+    - xhci: Fix handling halted endpoint even if endpoint ring appears empty
+    - xhci: prevent bus suspend if a roothub port detected a over-current
+      condition
+    - xhci: Don't clear hub TT buffer on ep0 protocol stall
+    - serial: sh-sci: Make sure status register SCxSR is read in correct sequence
+    - Revert "serial: uartps: Fix uartps_major handling"
+    - Revert "serial: uartps: Use the same dynamic major number for all ports"
+    - Revert "serial: uartps: Fix error path when alloc failed"
+    - Revert "serial: uartps: Do not allow use aliases >= MAX_UART_INSTANCES"
+    - Revert "serial: uartps: Change uart ID port allocation"
+    - Revert "serial: uartps: Move Port ID to device data structure"
+    - Revert "serial: uartps: Register own uart console and driver structures"
+    - powerpc/kuap: PPC_KUAP_DEBUG should depend on PPC_KUAP
+    - powerpc/mm: Fix CONFIG_PPC_KUAP_DEBUG on PPC32
+    - compat: ARM64: always include asm-generic/compat.h
+    - Linux 5.4.36
+
+  * Focal update: v5.4.35 upstream stable release (LP: #1875660)
+    - ext4: use non-movable memory for superblock readahead
+    - watchdog: sp805: fix restart handler
+    - xsk: Fix out of boundary write in __xsk_rcv_memcpy
+    - arm, bpf: Fix bugs with ALU64 {RSH, ARSH} BPF_K shift by 0
+    - arm, bpf: Fix offset overflow for BPF_MEM BPF_DW
+    - objtool: Fix switch table detection in .text.unlikely
+    - scsi: sg: add sg_remove_request in sg_common_write
+    - ALSA: hda: Honor PM disablement in PM freeze and thaw_noirq ops
+    - ARM: dts: imx6: Use gpc for FEC interrupt controller to fix wake on LAN.
+    - kbuild, btf: Fix dependencies for DEBUG_INFO_BTF
+    - netfilter: nf_tables: report EOPNOTSUPP on unsupported flags/object type
+    - irqchip/mbigen: Free msi_desc on device teardown
+    - ALSA: hda: Don't release card at firmware loading error
+    - xsk: Add missing check on user supplied headroom size
+    - of: unittest: kmemleak on changeset destroy
+    - of: unittest: kmemleak in of_unittest_platform_populate()
+    - of: unittest: kmemleak in of_unittest_overlay_high_level()
+    - of: overlay: kmemleak in dup_and_fixup_symbol_prop()
+    - x86/Hyper-V: Unload vmbus channel in hv panic callback
+    - x86/Hyper-V: Trigger crash enlightenment only once during system crash.
+    - x86/Hyper-V: Report crash register data or kmsg before running crash kernel
+    - x86/Hyper-V: Report crash register data when sysctl_record_panic_msg is not
+      set
+    - x86/Hyper-V: Report crash data in die() when panic_on_oops is set
+    - afs: Fix missing XDR advance in xdr_decode_{AFS,YFS}FSFetchStatus()
+    - afs: Fix decoding of inline abort codes from version 1 status records
+    - afs: Fix rename operation status delivery
+    - afs: Fix afs_d_validate() to set the right directory version
+    - afs: Fix race between post-modification dir edit and readdir/d_revalidate
+    - block, bfq: turn put_queue into release_process_ref in
+      __bfq_bic_change_cgroup
+    - block, bfq: make reparent_leaf_entity actually work only on leaf entities
+    - block, bfq: invoke flush_idle_tree after reparent_active_queues in
+      pd_offline
+    - rbd: avoid a deadlock on header_rwsem when flushing notifies
+    - rbd: call rbd_dev_unprobe() after unwatching and flushing notifies
+    - x86/Hyper-V: Free hv_panic_page when fail to register kmsg dump
+    - drm/ttm: flush the fence on the bo after we individualize the reservation
+      object
+    - clk: Don't cache errors from clk_ops::get_phase()
+    - clk: at91: usb: continue if clk_hw_round_rate() return zero
+    - net/mlx5e: Enforce setting of a single FEC mode
+    - f2fs: fix the panic in do_checkpoint()
+    - ARM: dts: rockchip: fix vqmmc-supply property name for rk3188-bqedison2qc
+    - arm64: dts: allwinner: a64: Fix display clock register range
+    - power: supply: bq27xxx_battery: Silence deferred-probe error
+    - clk: tegra: Fix Tegra PMC clock out parents
+    - arm64: tegra: Add PCIe endpoint controllers nodes for Tegra194
+    - arm64: tegra: Fix Tegra194 PCIe compatible string
+    - arm64: dts: clearfog-gt-8k: set gigabit PHY reset deassert delay
+    - soc: imx: gpc: fix power up sequencing
+    - dma-coherent: fix integer overflow in the reserved-memory dma allocation
+    - rtc: 88pm860x: fix possible race condition
+    - NFS: alloc_nfs_open_context() must use the file cred when available
+    - NFSv4/pnfs: Return valid stateids in nfs_layout_find_inode_by_stateid()
+    - NFSv4.2: error out when relink swapfile
+    - ARM: dts: rockchip: fix lvds-encoder ports subnode for rk3188-bqedison2qc
+    - KVM: PPC: Book3S HV: Fix H_CEDE return code for nested guests
+    - f2fs: fix to show norecovery mount option
+    - phy: uniphier-usb3ss: Add Pro5 support
+    - NFS: direct.c: Fix memory leak of dreq when nfs_get_lock_context fails
+    - f2fs: Fix mount failure due to SPO after a successful online resize FS
+    - f2fs: Add a new CP flag to help fsck fix resize SPO issues
+    - s390/cpuinfo: fix wrong output when CPU0 is offline
+    - hibernate: Allow uswsusp to write to swap
+    - btrfs: add RCU locks around block group initialization
+    - powerpc/prom_init: Pass the "os-term" message to hypervisor
+    - powerpc/maple: Fix declaration made after definition
+    - s390/cpum_sf: Fix wrong page count in error message
+    - ext4: do not commit super on read-only bdev
+    - um: ubd: Prevent buffer overrun on command completion
+    - cifs: Allocate encryption header through kmalloc
+    - mm/hugetlb: fix build failure with HUGETLB_PAGE but not HUGEBTLBFS
+    - drm/nouveau/svm: check for SVM initialized before migrating
+    - drm/nouveau/svm: fix vma range check for migration
+    - include/linux/swapops.h: correct guards for non_swap_entry()
+    - percpu_counter: fix a data race at vm_committed_as
+    - compiler.h: fix error in BUILD_BUG_ON() reporting
+    - KVM: s390: vsie: Fix possible race when shadowing region 3 tables
+    - drm/nouveau: workaround runpm fail by disabling PCI power management on
+      certain intel bridges
+    - leds: core: Fix warning message when init_data
+    - x86: ACPI: fix CPU hotplug deadlock
+    - csky: Fixup cpu speculative execution to IO area
+    - drm/amdkfd: kfree the wrong pointer
+    - NFS: Fix memory leaks in nfs_pageio_stop_mirroring()
+    - csky: Fixup get wrong psr value from phyical reg
+    - f2fs: fix NULL pointer dereference in f2fs_write_begin()
+    - ACPICA: Fixes for acpiExec namespace init file
+    - um: falloc.h needs to be directly included for older libc
+    - drm/vc4: Fix HDMI mode validation
+    - iommu/virtio: Fix freeing of incomplete domains
+    - iommu/vt-d: Fix mm reference leak
+    - ext2: fix empty body warnings when -Wextra is used
+    - iommu/vt-d: Silence RCU-list debugging warning in dmar_find_atsr()
+    - iommu/vt-d: Fix page request descriptor size
+    - ext2: fix debug reference to ext2_xattr_cache
+    - sunrpc: Fix gss_unwrap_resp_integ() again
+    - csky: Fixup init_fpu compile warning with __init
+    - power: supply: axp288_fuel_gauge: Broaden vendor check for Intel Compute
+      Sticks.
+    - libnvdimm: Out of bounds read in __nd_ioctl()
+    - iommu/amd: Fix the configuration of GCR3 table root pointer
+    - f2fs: fix to wait all node page writeback
+    - drm/nouveau/gr/gp107,gp108: implement workaround for HW hanging during init
+    - net: dsa: bcm_sf2: Fix overflow checks
+    - dma-debug: fix displaying of dma allocation type
+    - fbdev: potential information leak in do_fb_ioctl()
+    - ARM: dts: sunxi: Fix DE2 clocks register range
+    - iio: si1133: read 24-bit signed integer for measurement
+    - fbmem: Adjust indentation in fb_prepare_logo and fb_blank
+    - tty: evh_bytechan: Fix out of bounds accesses
+    - locktorture: Print ratio of acquisitions, not failures
+    - mtd: rawnand: free the nand_device object
+    - mtd: spinand: Explicitly use MTD_OPS_RAW to write the bad block marker to
+      OOB
+    - docs: Fix path to MTD command line partition parser
+    - mtd: lpddr: Fix a double free in probe()
+    - mtd: phram: fix a double free issue in error path
+    - KEYS: Don't write out to userspace while holding key semaphore
+    - bpf: fix buggy r0 retval refinement for tracing helpers
+    - bpf: Test_verifier, bpf_get_stack return value add <0
+    - bpf: Test_progs, add test to catch retval refine error handling
+    - SAUCE: bpf: Test_progs, fix test_get_stack_rawtp_err.c build
+    - bpf, test_verifier: switch bpf_get_stack's 0 s> r8 test
+    - Linux 5.4.35
+
+  * Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW),
+    REV=0x354 [8086:a0f0] subsystem id [1a56:1651] wireless adapter not found
+    due to firmware crash (LP: #1874685)
+    - iwlwifi: pcie: handle QuZ configs with killer NICs as well
+
+  * Support DMIC micmute LED on HP platforms (LP: #1876859)
+    - ALSA: hda/realtek - Introduce polarity for micmute LED GPIO
+    - ALSA: hda/realtek - Enable micmute LED on and HP system
+    - ALSA: hda/realtek - Add LED class support for micmute LED
+    - ALSA: hda/realtek - Fix unused variable warning w/o
+      CONFIG_LEDS_TRIGGER_AUDIO
+    - ASoC: SOF: Update correct LED status at the first time usage of
+      update_mute_led()
+
+  * linux: riscv: set max_pfn to the PFN of the last page (LP: #1876885)
+    - riscv: set max_pfn to the PFN of the last page
+
+  * Dell XPS 13 9300 mirror mode doesn't work sometimes with WD19TB
+    (LP: #1877013)
+    - drm/i915/perf: Do not clear pollin for small user read buffers
+
+  * [UBUNTU 20.04] s390x/pci: do not allow to create more pci functions than
+    configured via CONFIG_PCI_NR_FUNCTIONS (LP: #1874057)
+    - s390/pci: Fix zpci_alloc_domain() over allocation
+
+  * [Ubuntu 20.04] net/mlx5e: Fix endianness handling in pedit mask
+    (LP: #1872726)
+    - net/mlx5e: Fix endianness handling in pedit mask
+
+  * rtkit-daemon[*]: Failed to make ourselves RT: Operation not permitted after
+    upgrade to 20.04 (LP: #1875665)
+    - [Config] Turn off CONFIG_RT_GROUP_SCHED everywhere
+
+  * ceph -- Unable to mount ceph volume on s390x (LP: #1875863)
+    - ceph: fix endianness bug when handling MDS session feature bits
+
+  * 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
+
+  * Add support for Ambiq micro AM1805 RTC chip (LP: #1876667)
+    - SAUCE: rtc: add am-1805 RTC driver
+
+  * alsa/sof: kernel oops on the machine without Intel hdmi audio codec (a
+    regression in the  asoc machine driver) (LP: #1874359)
+    - SAUCE: ASoC: intel/skl/hda - fix oops on systems without i915 audio codec
+
+  * 'Elan touchpad' not detected on 'Lenovo ThinkBook 15 IIL' (LP: #1861610)
+    - SAUCE: Input: elan_i2c - add more hardware ID for Lenovo laptop
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Mon, 25 May 2020 17:05:37 +0200
+
+linux (5.4.0-33.37) focal; urgency=medium
+
+  * focal/linux: 5.4.0-33.37 -proposed tracker (LP: #1879926)
+
+  * Docker registry doesn't stay up and keeps restarting (LP: #1879690)
+    - Revert "UBUNTU: SAUCE: overlayfs: fix shitfs special-casing"
+    - Revert "UBUNTU: SAUCE: overlayfs: use shiftfs hacks only with shiftfs as
+      underlay"
+
+ -- Kleber Sacilotto de Souza <kleber.souza@canonical.com>  Thu, 21 May 2020 14:34:26 +0200
+
+linux (5.4.0-31.35) focal; urgency=medium
+
+  * focal/linux: 5.4.0-31.35 -proposed tracker (LP: #1877253)
+
+  * Intermittent display blackouts on event (LP: #1875254)
+    - drm/i915: Limit audio CDCLK>=2*BCLK constraint back to GLK only
+
+  * Unable to handle kernel pointer dereference in virtual kernel address space
+    on Eoan (LP: #1876645)
+    - SAUCE: overlayfs: fix shitfs special-casing
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Thu, 07 May 2020 11:05:18 +0200
+
+linux (5.4.0-30.34) focal; urgency=medium
+
+  * focal/linux: 5.4.0-30.34 -proposed tracker (LP: #1875385)
+
+  * ubuntu/focal64 fails to mount Vagrant shared folders  (LP: #1873506)
+    - [Packaging] Move virtualbox modules to linux-modules
+    - [Packaging] Remove vbox and zfs modules from generic.inclusion-list
+
+  * linux-image-5.0.0-35-generic breaks checkpointing of container
+    (LP: #1857257)
+    - SAUCE: overlayfs: use shiftfs hacks only with shiftfs as underlay
+
+  * shiftfs: broken shiftfs nesting (LP: #1872094)
+    - SAUCE: shiftfs: record correct creator credentials
+
+  * Add debian/rules targets to compile/run kernel selftests (LP: #1874286)
+    - [Packaging] add support to compile/run selftests
+
+  * shiftfs: O_TMPFILE reports ESTALE (LP: #1872757)
+    - SAUCE: shiftfs: fix dentry revalidation
+
+  * LIO hanging in iscsit_free_session and iscsit_stop_session (LP: #1871688)
+    - scsi: target: iscsi: calling iscsit_stop_session() inside
+      iscsit_close_session() has no effect
+
+  * [ICL] TC port in legacy/static mode can't be detected due TCCOLD
+    (LP: #1868936)
+    - SAUCE: drm/i915: Align power domain names with port names
+    - SAUCE: drm/i915/display: Move out code to return the digital_port of the aux
+      ch
+    - SAUCE: drm/i915/display: Add intel_legacy_aux_to_power_domain()
+    - SAUCE: drm/i915/display: Split hsw_power_well_enable() into two
+    - SAUCE: drm/i915/tc/icl: Implement TC cold sequences
+    - SAUCE: drm/i915/tc: Skip ref held check for TC legacy aux power wells
+    - SAUCE: drm/i915/tc/tgl: Implement TC cold sequences
+    - SAUCE: drm/i915/tc: Catch TC users accessing FIA registers without enable
+      aux
+    - SAUCE: drm/i915/tc: Do not warn when aux power well of static TC ports
+      timeout
+
+  * alsa/sof: external mic can't be deteced on Lenovo and HP laptops
+    (LP: #1872569)
+    - SAUCE: ASoC: intel/skl/hda - set autosuspend timeout for hda codecs
+
+  * amdgpu kernel errors in Linux 5.4 (LP: #1871248)
+    - drm/amd/display: Stop if retimer is not available
+
+  * Focal update: v5.4.34 upstream stable release (LP: #1874111)
+    - amd-xgbe: Use __napi_schedule() in BH context
+    - hsr: check protocol version in hsr_newlink()
+    - l2tp: Allow management of tunnels and session in user namespace
+    - net: dsa: mt7530: fix tagged frames pass-through in VLAN-unaware mode
+    - net: ipv4: devinet: Fix crash when add/del multicast IP with autojoin
+    - net: ipv6: do not consider routes via gateways for anycast address check
+    - net: phy: micrel: use genphy_read_status for KSZ9131
+    - net: qrtr: send msgs from local of same id as broadcast
+    - net: revert default NAPI poll timeout to 2 jiffies
+    - net: tun: record RX queue in skb before do_xdp_generic()
+    - net: dsa: mt7530: move mt7623 settings out off the mt7530
+    - net: ethernet: mediatek: move mt7623 settings out off the mt7530
+    - net/mlx5: Fix frequent ioread PCI access during recovery
+    - net/mlx5e: Add missing release firmware call
+    - net/mlx5e: Fix nest_level for vlan pop action
+    - net/mlx5e: Fix pfnum in devlink port attribute
+    - net: stmmac: dwmac-sunxi: Provide TX and RX fifo sizes
+    - ovl: fix value of i_ino for lower hardlink corner case
+    - scsi: ufs: Fix ufshcd_hold() caused scheduling while atomic
+    - platform/chrome: cros_ec_rpmsg: Fix race with host event
+    - jbd2: improve comments about freeing data buffers whose page mapping is NULL
+    - acpi/nfit: improve bounds checking for 'func'
+    - perf report: Fix no branch type statistics report issue
+    - pwm: pca9685: Fix PWM/GPIO inter-operation
+    - ext4: fix incorrect group count in ext4_fill_super error message
+    - ext4: fix incorrect inodes per group in error message
+    - clk: at91: sam9x60: fix usb clock parents
+    - clk: at91: usb: use proper usbs_mask
+    - ARM: dts: imx7-colibri: fix muxing of usbc_det pin
+    - arm64: dts: librem5-devkit: add a vbus supply to usb0
+    - usb: dwc3: gadget: Don't clear flags before transfer ended
+    - ASoC: Intel: mrfld: fix incorrect check on p->sink
+    - ASoC: Intel: mrfld: return error codes when an error occurs
+    - ALSA: hda/realtek - Enable the headset mic on Asus FX505DT
+    - ALSA: usb-audio: Filter error from connector kctl ops, too
+    - ALSA: usb-audio: Don't override ignore_ctl_error value from the map
+    - ALSA: usb-audio: Don't create jack controls for PCM terminals
+    - ALSA: usb-audio: Check mapping at creating connector controls, too
+    - arm64: vdso: don't free unallocated pages
+    - keys: Fix proc_keys_next to increase position index
+    - tracing: Fix the race between registering 'snapshot' event trigger and
+      triggering 'snapshot' operation
+    - btrfs: check commit root generation in should_ignore_root
+    - nl80211: fix NL80211_ATTR_FTM_RESPONDER policy
+    - mac80211: fix race in ieee80211_register_hw()
+    - mac80211_hwsim: Use kstrndup() in place of kasprintf()
+    - net/mlx5e: Encapsulate updating netdev queues into a function
+    - net/mlx5e: Rename hw_modify to preactivate
+    - net/mlx5e: Use preactivate hook to set the indirection table
+    - drm/amd/powerplay: force the trim of the mclk dpm_levels if OD is enabled
+    - drm/amdgpu: fix the hw hang during perform system reboot and reset
+    - i2c: designware: platdrv: Remove DPM_FLAG_SMART_SUSPEND flag on BYT and CHT
+    - ext4: do not zeroout extents beyond i_disksize
+    - irqchip/ti-sci-inta: Fix processing of masked irqs
+    - x86/resctrl: Preserve CDP enable over CPU hotplug
+    - x86/resctrl: Fix invalid attempt at removing the default resource group
+    - scsi: target: remove boilerplate code
+    - scsi: target: fix hang when multiple threads try to destroy the same iscsi
+      session
+    - x86/microcode/AMD: Increase microcode PATCH_MAX_SIZE
+    - Linux 5.4.34
+
+  * Focal update: v5.4.33 upstream stable release (LP: #1873481)
+    - ARM: dts: sun8i-a83t-tbs-a711: HM5065 doesn't like such a high voltage
+    - bus: sunxi-rsb: Return correct data when mixing 16-bit and 8-bit reads
+    - ARM: dts: Fix dm814x Ethernet by changing to use rgmii-id mode
+    - bpf: Fix deadlock with rq_lock in bpf_send_signal()
+    - iwlwifi: mvm: Fix rate scale NSS configuration
+    - Input: tm2-touchkey - add support for Coreriver TC360 variant
+    - soc: fsl: dpio: register dpio irq handlers after dpio create
+    - rxrpc: Abstract out the calculation of whether there's Tx space
+    - rxrpc: Fix call interruptibility handling
+    - net: stmmac: platform: Fix misleading interrupt error msg
+    - net: vxge: fix wrong __VA_ARGS__ usage
+    - hinic: fix a bug of waitting for IO stopped
+    - hinic: fix the bug of clearing event queue
+    - hinic: fix out-of-order excution in arm cpu
+    - hinic: fix wrong para of wait_for_completion_timeout
+    - hinic: fix wrong value of MIN_SKB_LEN
+    - selftests/net: add definition for SOL_DCCP to fix compilation errors for old
+      libc
+    - cxgb4/ptp: pass the sign of offset delta in FW CMD
+    - drm/scheduler: fix rare NULL ptr race
+    - cfg80211: Do not warn on same channel at the end of CSA
+    - qlcnic: Fix bad kzalloc null test
+    - i2c: st: fix missing struct parameter description
+    - i2c: pca-platform: Use platform_irq_get_optional
+    - media: rc: add keymap for Videostrong KII Pro
+    - cpufreq: imx6q: Fixes unwanted cpu overclocking on i.MX6ULL
+    - staging: wilc1000: avoid double unlocking of 'wilc->hif_cs' mutex
+    - media: venus: hfi_parser: Ignore HEVC encoding for V1
+    - firmware: arm_sdei: fix double-lock on hibernate with shared events
+    - null_blk: Fix the null_add_dev() error path
+    - null_blk: Handle null_add_dev() failures properly
+    - null_blk: fix spurious IO errors after failed past-wp access
+    - media: imx: imx7_mipi_csis: Power off the source when stopping streaming
+    - media: imx: imx7-media-csi: Fix video field handling
+    - xhci: bail out early if driver can't accress host in resume
+    - x86: Don't let pgprot_modify() change the page encryption bit
+    - dma-mapping: Fix dma_pgprot() for unencrypted coherent pages
+    - block: keep bdi->io_pages in sync with max_sectors_kb for stacked devices
+    - debugfs: Check module state before warning in {full/open}_proxy_open()
+    - irqchip/versatile-fpga: Handle chained IRQs properly
+    - time/sched_clock: Expire timer in hardirq context
+    - media: allegro: fix type of gop_length in channel_create message
+    - sched: Avoid scale real weight down to zero
+    - selftests/x86/ptrace_syscall_32: Fix no-vDSO segfault
+    - PCI/switchtec: Fix init_completion race condition with poll_wait()
+    - block, bfq: move forward the getting of an extra ref in bfq_bfqq_move
+    - media: i2c: video-i2c: fix build errors due to 'imply hwmon'
+    - libata: Remove extra scsi_host_put() in ata_scsi_add_hosts()
+    - pstore/platform: fix potential mem leak if pstore_init_fs failed
+    - gfs2: Do log_flush in gfs2_ail_empty_gl even if ail list is empty
+    - gfs2: Don't demote a glock until its revokes are written
+    - cpufreq: imx6q: fix error handling
+    - x86/boot: Use unsigned comparison for addresses
+    - efi/x86: Ignore the memory attributes table on i386
+    - genirq/irqdomain: Check pointer in irq_domain_alloc_irqs_hierarchy()
+    - block: Fix use-after-free issue accessing struct io_cq
+    - media: i2c: ov5695: Fix power on and off sequences
+    - usb: dwc3: core: add support for disabling SS instances in park mode
+    - irqchip/gic-v4: Provide irq_retrigger to avoid circular locking dependency
+    - md: check arrays is suspended in mddev_detach before call quiesce operations
+    - firmware: fix a double abort case with fw_load_sysfs_fallback
+    - spi: spi-fsl-dspi: Replace interruptible wait queue with a simple completion
+    - locking/lockdep: Avoid recursion in lockdep_count_{for,back}ward_deps()
+    - block, bfq: fix use-after-free in bfq_idle_slice_timer_body
+    - btrfs: qgroup: ensure qgroup_rescan_running is only set when the worker is
+      at least queued
+    - btrfs: remove a BUG_ON() from merge_reloc_roots()
+    - btrfs: restart relocate_tree_blocks properly
+    - btrfs: track reloc roots based on their commit root bytenr
+    - 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
+    - ALSA: hda/realtek - a fake key event is triggered by running shutup
+    - ALSA: doc: Document PC Beep Hidden Register on Realtek ALC256
+    - ALSA: hda/realtek - Set principled PC Beep configuration for ALC256
+    - ALSA: hda/realtek - Remove now-unnecessary XPS 13 headphone noise fixups
+    - ALSA: hda/realtek - Add quirk for Lenovo Carbon X1 8th gen
+    - ALSA: hda/realtek - Add quirk for MSI GL63
+    - media: venus: firmware: Ignore secure call error on first resume
+    - media: hantro: Read be32 words starting at every fourth byte
+    - media: ti-vpe: cal: fix disable_irqs to only the intended target
+    - media: ti-vpe: cal: fix a kernel oops when unloading module
+    - seccomp: Add missing compat_ioctl for notify
+    - acpi/x86: ignore unspecified bit positions in the ACPI global lock field
+    - ACPICA: Allow acpi_any_gpe_status_set() to skip one GPE
+    - ACPI: PM: s2idle: Refine active GPEs check
+    - thermal: devfreq_cooling: inline all stubs for CONFIG_DEVFREQ_THERMAL=n
+    - nvmet-tcp: fix maxh2cdata icresp parameter
+    - efi/x86: Add TPM related EFI tables to unencrypted mapping checks
+    - PCI: pciehp: Fix indefinite wait on sysfs requests
+    - PCI/ASPM: Clear the correct bits when enabling L1 substates
+    - PCI: Add boot interrupt quirk mechanism for Xeon chipsets
+    - PCI: qcom: Fix the fixup of PCI_VENDOR_ID_QCOM
+    - PCI: endpoint: Fix for concurrent memory allocation in OB address region
+    - sched/fair: Fix enqueue_task_fair warning
+    - tpm: Don't make log failures fatal
+    - tpm: tpm1_bios_measurements_next should increase position index
+    - tpm: tpm2_bios_measurements_next should increase position index
+    - cpu/hotplug: Ignore pm_wakeup_pending() for disable_nonboot_cpus()
+    - genirq/debugfs: Add missing sanity checks to interrupt injection
+    - irqchip/versatile-fpga: Apply clear-mask earlier
+    - io_uring: remove bogus RLIMIT_NOFILE check in file registration
+    - pstore: pstore_ftrace_seq_next should increase position index
+    - MIPS/tlbex: Fix LDDIR usage in setup_pw() for Loongson-3
+    - MIPS: OCTEON: irq: Fix potential NULL pointer dereference
+    - PM / Domains: Allow no domain-idle-states DT property in genpd when parsing
+    - PM: sleep: wakeup: Skip wakeup_source_sysfs_remove() if device is not there
+    - ath9k: Handle txpower changes even when TPC is disabled
+    - signal: Extend exec_id to 64bits
+    - x86/tsc_msr: Use named struct initializers
+    - x86/tsc_msr: Fix MSR_FSB_FREQ mask for Cherry Trail devices
+    - x86/tsc_msr: Make MSR derived TSC frequency more accurate
+    - x86/entry/32: Add missing ASM_CLAC to general_protection entry
+    - platform/x86: asus-wmi: Support laptops where the first battery is named
+      BATT
+    - KVM: nVMX: Properly handle userspace interrupt window request
+    - KVM: s390: vsie: Fix region 1 ASCE sanity shadow address checks
+    - KVM: s390: vsie: Fix delivery of addressing exceptions
+    - KVM: x86: Allocate new rmap and large page tracking when moving memslot
+    - KVM: VMX: Always VMCLEAR in-use VMCSes during crash with kexec support
+    - KVM: x86: Gracefully handle __vmalloc() failure during VM allocation
+    - KVM: VMX: Add a trampoline to fix VMREAD error handling
+    - KVM: VMX: fix crash cleanup when KVM wasn't used
+    - smb3: fix performance regression with setting mtime
+    - CIFS: Fix bug which the return value by asynchronous read is error
+    - mtd: spinand: Stop using spinand->oobbuf for buffering bad block markers
+    - mtd: spinand: Do not erase the block before writing a bad block marker
+    - btrfs: Don't submit any btree write bio if the fs has errors
+    - Btrfs: fix crash during unmount due to race with delayed inode workers
+    - btrfs: reloc: clean dirty subvols if we fail to start a transaction
+    - btrfs: set update the uuid generation as soon as possible
+    - btrfs: drop block from cache on error in relocation
+    - btrfs: fix missing file extent item for hole after ranged fsync
+    - btrfs: unset reloc control if we fail to recover
+    - btrfs: fix missing semaphore unlock in btrfs_sync_file
+    - btrfs: use nofs allocations for running delayed items
+    - remoteproc: qcom_q6v5_mss: Don't reassign mpss region on shutdown
+    - remoteproc: qcom_q6v5_mss: Reload the mba region on coredump
+    - remoteproc: Fix NULL pointer dereference in rproc_virtio_notify
+    - crypto: rng - Fix a refcounting bug in crypto_rng_reset()
+    - crypto: mxs-dcp - fix scatterlist linearization for hash
+    - erofs: correct the remaining shrink objects
+    - io_uring: honor original task RLIMIT_FSIZE
+    - mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions
+    - powerpc/pseries: Drop pointless static qualifier in vpa_debugfs_init()
+    - tools: gpio: Fix out-of-tree build regression
+    - net: qualcomm: rmnet: Allow configuration updates to existing devices
+    - arm64: dts: allwinner: h6: Fix PMU compatible
+    - sched/core: Remove duplicate assignment in sched_tick_remote()
+    - arm64: dts: allwinner: h5: Fix PMU compatible
+    - mm, memcg: do not high throttle allocators based on wraparound
+    - dm writecache: add cond_resched to avoid CPU hangs
+    - dm integrity: fix a crash with unusually large tag size
+    - dm verity fec: fix memory leak in verity_fec_dtr
+    - dm clone: Add overflow check for number of regions
+    - dm clone metadata: Fix return type of dm_clone_nr_of_hydrated_regions()
+    - XArray: Fix xas_pause for large multi-index entries
+    - xarray: Fix early termination of xas_for_each_marked
+    - crypto: caam/qi2 - fix chacha20 data size error
+    - crypto: caam - update xts sector size for large input length
+    - crypto: ccree - protect against empty or NULL scatterlists
+    - crypto: ccree - only try to map auth tag if needed
+    - crypto: ccree - dec auth tag size from cryptlen map
+    - scsi: zfcp: fix missing erp_lock in port recovery trigger for point-to-point
+    - scsi: ufs: fix Auto-Hibern8 error detection
+    - ARM: dts: exynos: Fix polarity of the LCD SPI bus on UniversalC210 board
+    - arm64: dts: ti: k3-am65: Add clocks to dwc3 nodes
+    - arm64: armv8_deprecated: Fix undef_hook mask for thumb setend
+    - selftests: vm: drop dependencies on page flags from mlock2 tests
+    - selftests/vm: fix map_hugetlb length used for testing read and write
+    - selftests/powerpc: Add tlbie_test in .gitignore
+    - vfio: platform: Switch to platform_get_irq_optional()
+    - drm/i915/gem: Flush all the reloc_gpu batch
+    - drm/etnaviv: rework perfmon query infrastructure
+    - drm: Remove PageReserved manipulation from drm_pci_alloc
+    - drm/amdgpu/powerplay: using the FCLK DPM table to set the MCLK
+    - drm/amdgpu: unify fw_write_wait for new gfx9 asics
+    - powerpc/pseries: Avoid NULL pointer dereference when drmem is unavailable
+    - nfsd: fsnotify on rmdir under nfsd/clients/
+    - NFS: Fix use-after-free issues in nfs_pageio_add_request()
+    - NFS: Fix a page leak in nfs_destroy_unlinked_subrequests()
+    - ext4: fix a data race at inode->i_blocks
+    - fs/filesystems.c: downgrade user-reachable WARN_ONCE() to pr_warn_once()
+    - ocfs2: no need try to truncate file beyond i_size
+    - perf tools: Support Python 3.8+ in Makefile
+    - s390/diag: fix display of diagnose call statistics
+    - Input: i8042 - add Acer Aspire 5738z to nomux list
+    - ftrace/kprobe: Show the maxactive number on kprobe_events
+    - clk: ingenic/jz4770: Exit with error if CGU init failed
+    - clk: ingenic/TCU: Fix round_rate returning error
+    - kmod: make request_module() return an error when autoloading is disabled
+    - cpufreq: powernv: Fix use-after-free
+    - hfsplus: fix crash and filesystem corruption when deleting files
+    - ipmi: fix hung processes in __get_guid()
+    - xen/blkfront: fix memory allocation flags in blkfront_setup_indirect()
+    - powerpc/64/tm: Don't let userspace set regs->trap via sigreturn
+    - powerpc/fsl_booke: Avoid creating duplicate tlb1 entry
+    - powerpc/hash64/devmap: Use H_PAGE_THP_HUGE when setting up huge devmap PTE
+      entries
+    - powerpc/xive: Use XIVE_BAD_IRQ instead of zero to catch non configured IPIs
+    - powerpc/64: Setup a paca before parsing device tree etc.
+    - powerpc/xive: Fix xmon support on the PowerNV platform
+    - powerpc/kprobes: Ignore traps that happened in real mode
+    - powerpc/64: Prevent stack protection in early boot
+    - scsi: mpt3sas: Fix kernel panic observed on soft HBA unplug
+    - powerpc: Make setjmp/longjmp signature standard
+    - arm64: Always force a branch protection mode when the compiler has one
+    - dm zoned: remove duplicate nr_rnd_zones increase in dmz_init_zone()
+    - dm clone: replace spin_lock_irqsave with spin_lock_irq
+    - dm clone: Fix handling of partial region discards
+    - dm clone: Add missing casts to prevent overflows and data corruption
+    - Revert "drm/dp_mst: Remove VCPI while disabling topology mgr"
+    - drm/dp_mst: Fix clearing payload state on topology disable
+    - drm/amdgpu: fix gfx hang during suspend with video playback (v2)
+    - drm/i915/icl+: Don't enable DDI IO power on a TypeC port in TBT mode
+    - powerpc/kasan: Fix kasan_remap_early_shadow_ro()
+    - mmc: sdhci: Convert sdhci_set_timeout_irq() to non-static
+    - mmc: sdhci: Refactor sdhci_set_timeout()
+    - bpf: Fix tnum constraints for 32-bit comparisons
+    - mfd: dln2: Fix sanity checking for endpoints
+    - efi/x86: Fix the deletion of variables in mixed mode
+    - ASoC: stm32: sai: Add missing cleanup
+    - Linux 5.4.33
+    - SUNRPC: fix krb5p mount to provide large enough buffer in rq_rcvsize
+
+  * Panic on suspend/resume Kernel panic - not syncing: stack-protector: Kernel
+    stack is corrupted in: sata_pmp_eh_recover+0xa2b/0xa40 (LP: #1821434) //
+    Focal update: v5.4.33 upstream stable release (LP: #1873481)
+    - libata: Return correct status in sata_pmp_eh_recover_pm() when
+      ATA_DFLAG_DETACH is set
+
+  * Focal update: v5.4.32 upstream stable release (LP: #1873292)
+    - cxgb4: fix MPS index overwrite when setting MAC address
+    - ipv6: don't auto-add link-local address to lag ports
+    - net: dsa: bcm_sf2: Do not register slave MDIO bus with OF
+    - net: dsa: bcm_sf2: Ensure correct sub-node is parsed
+    - net: dsa: mt7530: fix null pointer dereferencing in port5 setup
+    - net: phy: micrel: kszphy_resume(): add delay after genphy_resume() before
+      accessing PHY registers
+    - net_sched: add a temporary refcnt for struct tcindex_data
+    - net_sched: fix a missing refcnt in tcindex_init()
+    - net: stmmac: dwmac1000: fix out-of-bounds mac address reg setting
+    - tun: Don't put_page() for all negative return values from XDP program
+    - mlxsw: spectrum_flower: Do not stop at FLOW_ACTION_VLAN_MANGLE
+    - r8169: change back SG and TSO to be disabled by default
+    - s390: prevent leaking kernel address in BEAR
+    - random: always use batched entropy for get_random_u{32,64}
+    - usb: dwc3: gadget: Wrap around when skip TRBs
+    - uapi: rename ext2_swab() to swab() and share globally in swab.h
+    - slub: improve bit diffusion for freelist ptr obfuscation
+    - tools/accounting/getdelays.c: fix netlink attribute length
+    - hwrng: imx-rngc - fix an error path
+    - ACPI: PM: Add acpi_[un]register_wakeup_handler()
+    - platform/x86: intel_int0002_vgpio: Use acpi_register_wakeup_handler()
+    - ASoC: jz4740-i2s: Fix divider written at incorrect offset in register
+    - IB/hfi1: Call kobject_put() when kobject_init_and_add() fails
+    - IB/hfi1: Fix memory leaks in sysfs registration and unregistration
+    - IB/mlx5: Replace tunnel mpls capability bits for tunnel_offloads
+    - ARM: imx: Enable ARM_ERRATA_814220 for i.MX6UL and i.MX7D
+    - ARM: imx: only select ARM_ERRATA_814220 for ARMv7-A
+    - ceph: remove the extra slashes in the server path
+    - ceph: canonicalize server path in place
+    - include/uapi/linux/swab.h: fix userspace breakage, use __BITS_PER_LONG for
+      swap
+    - RDMA/ucma: Put a lock around every call to the rdma_cm layer
+    - RDMA/cma: Teach lockdep about the order of rtnl and lock
+    - RDMA/siw: Fix passive connection establishment
+    - Bluetooth: RFCOMM: fix ODEBUG bug in rfcomm_dev_ioctl
+    - RDMA/cm: Update num_paths in cma_resolve_iboe_route error flow
+    - blk-mq: Keep set->nr_hw_queues and set->map[].nr_queues in sync
+    - fbcon: fix null-ptr-deref in fbcon_switch
+    - iommu/vt-d: Allow devices with RMRRs to use identity domain
+    - Linux 5.4.32
+
+  * Focal update: v5.4.31 upstream stable release (LP: #1871651)
+    - nvme-rdma: Avoid double freeing of async event data
+    - kconfig: introduce m32-flag and m64-flag
+    - drm/amd/display: Add link_rate quirk for Apple 15" MBP 2017
+    - drm/bochs: downgrade pci_request_region failure from error to warning
+    - initramfs: restore default compression behavior
+    - drm/amdgpu: fix typo for vcn1 idle check
+    - [Packaging] add libcap-dev dependency
+    - tools/power turbostat: Fix gcc build warnings
+    - tools/power turbostat: Fix missing SYS_LPI counter on some Chromebooks
+    - tools/power turbostat: Fix 32-bit capabilities warning
+    - net/mlx5e: kTLS, Fix TCP seq off-by-1 issue in TX resync flow
+    - XArray: Fix xa_find_next for large multi-index entries
+    - padata: fix uninitialized return value in padata_replace()
+    - brcmfmac: abort and release host after error
+    - misc: rtsx: set correct pcr_ops for rts522A
+    - misc: pci_endpoint_test: Fix to support > 10 pci-endpoint-test devices
+    - misc: pci_endpoint_test: Avoid using module parameter to determine irqtype
+    - PCI: sysfs: Revert "rescan" file renames
+    - coresight: do not use the BIT() macro in the UAPI header
+    - mei: me: add cedar fork device ids
+    - nvmem: check for NULL reg_read and reg_write before dereferencing
+    - extcon: axp288: Add wakeup support
+    - power: supply: axp288_charger: Add special handling for HP Pavilion x2 10
+    - Revert "dm: always call blk_queue_split() in dm_process_bio()"
+    - ALSA: hda/ca0132 - Add Recon3Di quirk to handle integrated sound on EVGA X99
+      Classified motherboard
+    - soc: mediatek: knows_txdone needs to be set in Mediatek CMDQ helper
+    - net/mlx5e: kTLS, Fix wrong value in record tracker enum
+    - iwlwifi: consider HE capability when setting LDPC
+    - iwlwifi: yoyo: don't add TLV offset when reading FIFOs
+    - iwlwifi: dbg: don't abort if sending DBGC_SUSPEND_RESUME fails
+    - rxrpc: Fix sendmsg(MSG_WAITALL) handling
+    - IB/hfi1: Ensure pq is not left on waitlist
+    - tcp: fix TFO SYNACK undo to avoid double-timestamp-undo
+    - watchdog: iTCO_wdt: Export vendorsupport
+    - watchdog: iTCO_wdt: Make ICH_RES_IO_SMI optional
+    - i2c: i801: Do not add ICH_RES_IO_SMI for the iTCO_wdt device
+    - net: Fix Tx hash bound checking
+    - padata: always acquire cpu_hotplug_lock before pinst->lock
+    - mm: mempolicy: require at least one nodeid for MPOL_PREFERRED
+    - Linux 5.4.31
+
+  * Add hw timestamps to received skbs in peak_canfd (LP: #1874124)
+    - can: peak_canfd: provide hw timestamps in rx skbs
+
+  * kselftest: seccomp kill_after_ptrace() timeout (LP: #1872047)
+    - SAUCE: kselftest/runner: allow to properly deliver signals to tests
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Tue, 05 May 2020 12:36:10 +0200
+
+linux (5.4.0-29.33) focal; urgency=medium
+
+  * focal/linux: 5.4.0-29.33 -proposed tracker (LP: #1875858)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * Add signed modules for the 435 NVIDIA driver (LP: #1875888)
+    - [Packaging] NVIDIA -- add signed modules for the 435 NVIDIA driver
+
+  * built-using constraints preventing uploads (LP: #1875601)
+    - temporarily drop Built-Using data
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Wed, 29 Apr 2020 15:34:16 +0200
+
+linux (5.4.0-28.32) focal; urgency=medium
+
+  * CVE-2020-11884
+    - SAUCE: s390/mm: fix page table upgrade vs 2ndary address mode accesses
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Wed, 22 Apr 2020 11:08:40 -0300
+
+linux (5.4.0-26.30) focal; urgency=medium
+
+  * focal/linux: 5.4.0-26.30 -proposed tracker (LP: #1873882)
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+
+  * swap storms kills interactive use (LP: #1861359)
+    - SAUCE: drm/i915: prevent direct writeback from the shrinker
+
+  * 5.4.0-24.28 does not seem to apply rtprio, whereas -21 does. (LP: #1873315)
+    - [Config] lowlatency: turn off RT_GROUP_SCHED
+
+  * [RTL810xE] No ethernet connection (LP: #1871182)
+    - net: phy: realtek: fix handling of RTL8105e-integrated PHY
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 20 Apr 2020 18:33:49 +0200
+
+linux (5.4.0-25.29) focal; urgency=medium
+
+  * focal/linux: 5.4.0-25.29 -proposed tracker (LP: #1873459)
+
+  * [TGL] VMD support in TGL (LP: #1855954)
+    - PCI: vmd: Add bus 224-255 restriction decode
+    - PCI: vmd: Add device id for VMD device 8086:9A0B
+
+  * Can not see the storage with Intel RAID On mode enabled on Intel Comet Lake
+    (LP: #1871812)
+    - ahci: Add Intel Comet Lake PCH RAID PCI ID
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 17 Apr 2020 08:41:16 -0500
+
+linux (5.4.0-24.28) focal; urgency=medium
+
+  * focal/linux: 5.4.0-24.28 -proposed tracker (LP: #1871939)
+
+  * getitimer returns it_value=0 erroneously (LP: #1349028)
+    - [Config] CONTEXT_TRACKING_FORCE policy should be unset
+
+  * 12d1:1038 Dual-Role OTG device on non-HNP port - unable to enumerate USB
+    device on port 1 (LP: #1047527)
+    - [Config] USB_OTG_FSM policy not needed
+
+  * Add DCPD backlight support for HP CML system (LP: #1871589)
+    - SAUCE: drm/i915: Force DPCD backlight mode for HP CML 2020 system
+
+  * Backlight brightness cannot be adjusted using keys (LP: #1860303)
+    - SAUCE drm/i915: Force DPCD backlight mode for HP Spectre x360 Convertible
+      13t-aw100
+
+  * CVE-2020-11494
+    - slcan: Don't transmit uninitialized stack data in padding
+
+  * Ubuntu Kernel Support for OpenPOWER NV Secure & Trusted Boot (LP: #1866909)
+    - powerpc: Detect the secure boot mode of the system
+    - powerpc/ima: Add support to initialize ima policy rules
+    - powerpc: Detect the trusted boot state of the system
+    - powerpc/ima: Define trusted boot policy
+    - ima: Make process_buffer_measurement() generic
+    - certs: Add wrapper function to check blacklisted binary hash
+    - ima: Check against blacklisted hashes for files with modsig
+    - powerpc/ima: Update ima arch policy to check for blacklist
+    - powerpc/ima: Indicate kernel modules appended signatures are enforced
+    - powerpc/powernv: Add OPAL API interface to access secure variable
+    - powerpc: expose secure variables to userspace via sysfs
+    - x86/efi: move common keyring handler functions to new file
+    - powerpc: Load firmware trusted keys/hashes into kernel keyring
+    - x86/efi: remove unused variables
+
+  * [roce-0227]sync mainline kernel 5.6rc3  roce patchset into ubuntu HWE kernel
+    branch (LP: #1864950)
+    - RDMA/hns: Cleanups of magic numbers
+    - RDMA/hns: Optimize eqe buffer allocation flow
+    - RDMA/hns: Add the workqueue framework for flush cqe handler
+    - RDMA/hns: Delayed flush cqe process with workqueue
+    - RDMA/hns: fix spelling mistake: "attatch" -> "attach"
+    - RDMA/hns: Initialize all fields of doorbells to zero
+    - RDMA/hns: Treat revision HIP08_A as a special case
+    - RDMA/hns: Use flush framework for the case in aeq
+    - RDMA/hns: Stop doorbell update while qp state error
+    - RDMA/hns: Optimize qp destroy flow
+    - RDMA/hns: Optimize qp context create and destroy flow
+    - RDMA/hns: Optimize qp number assign flow
+    - RDMA/hns: Optimize qp buffer allocation flow
+    - RDMA/hns: Optimize qp param setup flow
+    - RDMA/hns: Optimize kernel qp wrid allocation flow
+    - RDMA/hns: Optimize qp doorbell allocation flow
+    - RDMA/hns: Check if depth of qp is 0 before configure
+
+  * [hns3-0316]sync mainline kernel 5.6rc4  hns3 patchset into ubuntu HWE kernel
+    branch (LP: #1867586)
+    - net: hns3: modify an unsuitable print when setting unknown duplex to fibre
+    - net: hns3: add enabled TC numbers and DWRR weight info in debugfs
+    - net: hns3: add support for dump MAC ID and loopback status in debugfs
+    - net: hns3: add missing help info for QS shaper in debugfs
+    - net: hns3: fix some mixed type assignment
+    - net: hns3: rename macro HCLGE_MAX_NCL_CONFIG_LENGTH
+    - net: hns3: remove an unnecessary resetting check in
+      hclge_handle_hw_ras_error()
+    - net: hns3: delete some reduandant code
+    - net: hns3: add a check before PF inform VF to reset
+    - net: hns3: print out status register when VF receives unknown source
+      interrupt
+    - net: hns3: print out command code when dump fails in debugfs
+    - net: hns3: synchronize some print relating to reset issue
+    - net: hns3: delete unnecessary logs after kzalloc fails
+
+  * [SRU][F/U/OEM-5.6] UBUNTU: SAUCE: Fix amdgpu hang during acpi event
+    (LP: #1871316)
+    - SAUCE: drm/amdgpu: Fix oops when pp_funcs is unset in ACPI event
+
+  * alsa: make the dmic detection align to the mainline kernel-5.6
+    (LP: #1871284)
+    - ALSA: hda: add Intel DSP configuration / probe code
+    - ALSA: hda: fix intel DSP config
+    - ALSA: hda: Allow non-Intel device probe gracefully
+    - ALSA: hda: More constifications
+    - ALSA: hda: Rename back to dmic_detect option
+    - [Config] SND_INTEL_DSP_CONFIG=m
+
+  * add_key05 from ubuntu_ltp_syscalls failed (LP: #1869644)
+    - KEYS: reaching the keys quotas correctly
+
+  * Fix authentication fail on Realtek WiFi 8723de (LP: #1871300)
+    - SAUCE: rtw88: No retry and report for auth and assoc
+    - SAUCE: rtw88: fix rate for a while after being connected
+    - SAUCE: rtw88: Move driver IQK to set channel before association for 11N chip
+
+  * Add Mute LED support for an HP laptop (LP: #1871090)
+    - ALSA: hda/realtek: Enable mute LED on an HP system
+
+  * dscr_sysfs_test / futex_bench / tm-unavailable  in powerpc from
+    ubuntu_kernel_selftests timeout on PowerPC nodes with B-5.3 (LP: #1864642)
+    - Revert "UBUNTU: SAUCE: selftests/powerpc -- Disable timeout for benchmark
+      and tm tests"
+    - selftests/powerpc: Turn off timeout setting for benchmarks, dscr, signal, tm
+
+  * Update 20.0.4 NVMe Core, NVMe FC Transport and nvme-cli for Broadcom Emulex
+    lpfc driver 12.6.0.x dependencies (LP: #1856340)
+    - nvme-fc: Sync nvme-fc header to FC-NVME-2
+    - nvme-fc and nvmet-fc: sync with FC-NVME-2 header changes
+    - nvme-fc: Set new cmd set indicator in nvme-fc cmnd iu
+    - nvme-fc: clarify error messages
+    - nvme-fc: ensure association_id is cleared regardless of a Disconnect LS
+    - nvme: resync include/linux/nvme.h with nvmecli
+    - nvme: Fix parsing of ANA log page
+
+  * Update Broadcom Emulex lpfc driver in 5.4 to 12.6.0.x from 5.5
+    (LP: #1855303)
+    - scsi: lpfc: Fix pt2pt discovery on SLI3 HBAs
+    - scsi: lpfc: Fix premature re-enabling of interrupts in lpfc_sli_host_down
+    - scsi: lpfc: Fix miss of register read failure check
+    - scsi: lpfc: Fix NVME io abort failures causing hangs
+    - scsi: lpfc: Fix device recovery errors after PLOGI failures
+    - scsi: lpfc: Fix GPF on scsi command completion
+    - scsi: lpfc: Fix NVMe ABTS in response to receiving an ABTS
+    - scsi: lpfc: Fix coverity errors on NULL pointer checks
+    - scsi: lpfc: Fix host hang at boot or slow boot
+    - scsi: lpfc: Update async event logging
+    - scsi: lpfc: Complete removal of FCoE T10 PI support on SLI-4 adapters
+    - scsi: lpfc: cleanup: remove unused fcp_txcmlpq_cnt
+    - scsi: lpfc: Update lpfc version to 12.4.0.1
+    - scsi: lpfc: Make function lpfc_defer_pt2pt_acc static
+    - scsi: lpfc: fix lpfc_nvmet_mrq to be bound by hdw queue count
+    - scsi: lpfc: Fix reporting of read-only fw error errors
+    - scsi: lpfc: Fix lockdep errors in sli_ringtx_put
+    - scsi: lpfc: fix coverity error of dereference after null check
+    - scsi: lpfc: Slight fast-path performance optimizations
+    - scsi: lpfc: Remove lock contention target write path
+    - scsi: lpfc: Revise interrupt coalescing for missing scenarios
+    - scsi: lpfc: Make FW logging dynamically configurable
+    - scsi: lpfc: Add log macros to allow print by serverity or verbosity setting
+    - scsi: lpfc: Add FA-WWN Async Event reporting
+    - scsi: lpfc: Add FC-AL support to lpe32000 models
+    - scsi: lpfc: Add additional discovery log messages
+    - scsi: lpfc: Update lpfc version to 12.6.0.0
+    - scsi: lpfc: lpfc_attr: Fix Use plain integer as NULL pointer
+    - scsi: lpfc: lpfc_nvmet: Fix Use plain integer as NULL pointer
+    - scsi: lpfc: fix build error of lpfc_debugfs.c for vfree/vmalloc
+    - scsi: lpfc: fix spelling error in MAGIC_NUMER_xxx
+    - scsi: lpfc: Fix NULL check before mempool_destroy is not needed
+    - scsi: lpfc: Make lpfc_debugfs_ras_log_data static
+    - scsi: lpfc: Fix configuration of BB credit recovery in service parameters
+    - scsi: lpfc: Fix kernel crash at lpfc_nvme_info_show during remote port
+      bounce
+    - scsi: lpfc: Fix dynamic fw log enablement check
+    - scsi: lpfc: Sync with FC-NVMe-2 SLER change to require Conf with SLER
+    - scsi: lpfc: Clarify FAWNN error message
+    - scsi: lpfc: Add registration for CPU Offline/Online events
+    - scsi: lpfc: Change default IRQ model on AMD architectures
+    - scsi: lpfc: Add enablement of multiple adapter dumps
+    - scsi: lpfc: Update lpfc version to 12.6.0.1
+    - scsi: lpfc: Fix a kernel warning triggered by lpfc_sli4_enable_intr()
+    - scsi: lpfc: Fix lpfc_cpumask_of_node_init()
+    - scsi: lpfc: fix inlining of lpfc_sli4_cleanup_poll_list()
+    - scsi: lpfc: Initialize cpu_map for not present cpus
+    - scsi: lpfc: revise nvme max queues to be hdwq count
+    - scsi: lpfc: Update lpfc version to 12.6.0.2
+    - scsi: lpfc: size cpu map by last cpu id set
+    - scsi: lpfc: Fix incomplete NVME discovery when target
+    - scsi: lpfc: Fix missing check for CSF in Write Object Mbox Rsp
+    - scsi: lpfc: Fix Fabric hostname registration if system hostname changes
+    - scsi: lpfc: Fix ras_log via debugfs
+    - scsi: lpfc: Fix disablement of FC-AL on lpe35000 models
+    - scsi: lpfc: Fix unmap of dpp bars affecting next driver load
+    - scsi: lpfc: Fix MDS Latency Diagnostics Err-drop rates
+    - scsi: lpfc: Fix improper flag check for IO type
+    - scsi: lpfc: Update lpfc version to 12.6.0.3
+    - scsi: lpfc: Fix RQ buffer leakage when no IOCBs available
+    - scsi: lpfc: Fix lpfc_io_buf resource leak in lpfc_get_scsi_buf_s4 error path
+    - scsi: lpfc: Fix broken Credit Recovery after driver load
+    - scsi: lpfc: Fix registration of ELS type support in fdmi
+    - scsi: lpfc: Fix release of hwq to clear the eq relationship
+    - scsi: lpfc: Fix compiler warning on frame size
+    - scsi: lpfc: Fix coverity errors in fmdi attribute handling
+    - scsi: lpfc: Remove handler for obsolete ELS - Read Port Status (RPS)
+    - scsi: lpfc: Clean up hba max_lun_queue_depth checks
+    - scsi: lpfc: Update lpfc version to 12.6.0.4
+    - scsi: lpfc: Copyright updates for 12.6.0.4 patches
+    - scsi: fc: Update Descriptor definition and add RDF and Link Integrity FPINs
+    - scsi: lpfc: add RDF registration and Link Integrity FPIN logging
+
+  * lockdown on power (LP: #1855668) // Ubuntu Kernel Support for OpenPOWER NV
+    Secure & Trusted Boot (LP: #1866909)
+    - [Config] Enable configs for OpenPOWER NV Secure & Trusted Boot
+
+  * lockdown on power (LP: #1855668)
+    - SAUCE: (lockdown) powerpc: lock down kernel in secure boot mode
+
+  * Focal update: v5.4.30 upstream stable release (LP: #1870571)
+    - mac80211: Check port authorization in the ieee80211_tx_dequeue() case
+    - mac80211: fix authentication with iwlwifi/mvm
+    - serial: sprd: Fix a dereference warning
+    - 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
+    - vt: vt_ioctl: fix use-after-free in vt_in_use()
+    - platform/x86: pmc_atom: Add Lex 2I385SW to critclk_systems DMI table
+    - bpf: Explicitly memset the bpf_attr structure
+    - bpf: Explicitly memset some bpf info structures declared on the stack
+    - gpiolib: acpi: Add quirk to ignore EC wakeups on HP x2 10 CHT + AXP288 model
+    - net: ks8851-ml: Fix IO operations, again
+    - clk: imx: Align imx sc clock msg structs to 4
+    - clk: imx: Align imx sc clock parent msg structs to 4
+    - clk: ti: am43xx: Fix clock parent for RTC clock
+    - libceph: fix alloc_msg_with_page_vector() memory leaks
+    - arm64: alternative: fix build with clang integrated assembler
+    - perf map: Fix off by one in strncpy() size argument
+    - ARM: dts: oxnas: Fix clear-mask property
+    - ARM: bcm2835-rpi-zero-w: Add missing pinctrl name
+    - ARM: dts: imx6: phycore-som: fix arm and soc minimum voltage
+    - ARM: dts: N900: fix onenand timings
+    - ARM: dts: sun8i: r40: Move AHCI device node based on address order
+    - arm64: dts: ls1043a-rdb: correct RGMII delay mode to rgmii-id
+    - arm64: dts: ls1046ardb: set RGMII interfaces to RGMII_ID mode
+    - Linux 5.4.30
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_RT_GROUP_SCHED=y
+    - SAUCE: powerpc/ima: require IMA module signatures only if MODULE_SIG is not
+      enabled
+    - SAUCE: Update aufs to 5.4.3 20200302
+    - SAUCE: drm/amdgpu: Remove missing firmware files from modinfo
+    - SAUCE: drm/i915: Fix ref->mutex deadlock in i915_active_wait()
+    - SAUCE: drm/i915: Synchronize active and retire callbacks
+    - SAUCE: apparmor: add a valid state flags check
+    - SAUCE: aapparmor: add consistency check between state and dfa diff encode
+      flags
+    - SAUCE: aapparmor: remove useless aafs_create_symlink
+    - SAUCE: aapparmor: fail unpack if profile mode is unknown
+    - SAUCE: apparmor: ensure that dfa state tables have entries
+    - SAUCE: apparmor: fix potential label refcnt leak in aa_change_profile
+    - SAUCE: security/apparmor/label.c: Clean code by removing redundant
+      instructions
+    - [Config] Remove PCIEASPM_DEBUG from annotations
+    - [Config] Remove HEADER_TEST from annotations
+    - SAUCE: selftests/seccomp: allow clock_nanosleep instead of nanosleep
+    - [Debian] Allow building linux-libc-dev from linux-riscv
+    - [Packaging] Remove riscv64 packaging from master kernel
+    - [Config] Remove CONFIG_SND_HDA_INTEL_DETECT_DMIC from annotations
+
+  * Miscellaneous upstream changes
+    - net/bpfilter: remove superfluous testing message
+    - apparmor: increase left match history buffer size
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 09 Apr 2020 16:49:54 -0500
+
+linux (5.4.0-23.27) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Enable riscv64 build
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sat, 04 Apr 2020 14:03:47 -0500
+
+linux (5.4.0-22.26) focal; urgency=medium
+
+  * focal/linux: 5.4.0-22.26 -proposed tracker (LP: #1870502)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update variants
+    - [Packaging] update helper scripts
+    - update dkms package versions
+
+  * [SFC-0316]sync mainline kernel 5.7rc1 SFC patchset into ubuntu HWE kernel
+    branch (LP: #1867588)
+    - spi: Allow SPI controller override device buswidth
+    - spi: HiSilicon v3xx: Properly set CMD_CONFIG for Dual/Quad modes
+    - spi: HiSilicon v3xx: Use DMI quirk to set controller buswidth override bits
+
+  * [hns3-0316]sync mainline kernel 5.6rc4  hns3 patchset into ubuntu HWE kernel
+    branch (LP: #1867586)
+    - net: hns3: fix VF VLAN table entries inconsistent issue
+    - net: hns3: fix RMW issue for VLAN filter switch
+    - net: hns3: clear port base VLAN when unload PF
+
+  * [sas-0316]sync mainline kernel 5.6rc1 roce patchset into ubuntu HWE kernel
+    branch (LP: #1867587)
+    - scsi: hisi_sas: use threaded irq to process CQ interrupts
+    - scsi: hisi_sas: replace spin_lock_irqsave/spin_unlock_restore with
+      spin_lock/spin_unlock
+    - scsi: hisi_sas: Replace magic number when handle channel interrupt
+    - scsi: hisi_sas: Modify the file permissions of trigger_dump to write only
+    - scsi: hisi_sas: Add prints for v3 hw interrupt converge and automatic
+      affinity
+    - scsi: hisi_sas: Rename hisi_sas_cq.pci_irq_mask
+
+  * Revert "nvme_fc: add module to ops template to allow module references"
+    (LP: #1869947)
+    - SAUCE: Revert "nvme_fc: add module to ops template to allow module
+      references"
+
+  * suspend only works once on ThinkPad X1 Carbon gen 7 (LP: #1865570)
+    - Revert "UBUNTU: SAUCE: e1000e: Disable s0ix flow for X1 Carbon 7th"
+    - SAUCE: e1000e: bump up timeout to wait when ME un-configure ULP mode
+
+  * Focal update: v5.4.29 upstream stable release (LP: #1870142)
+    - mmc: core: Allow host controllers to require R1B for CMD6
+    - mmc: core: Respect MMC_CAP_NEED_RSP_BUSY for erase/trim/discard
+    - mmc: core: Respect MMC_CAP_NEED_RSP_BUSY for eMMC sleep command
+    - mmc: sdhci-omap: Fix busy detection by enabling MMC_CAP_NEED_RSP_BUSY
+    - mmc: sdhci-tegra: Fix busy detection by enabling MMC_CAP_NEED_RSP_BUSY
+    - ACPI: PM: s2idle: Rework ACPI events synchronization
+    - cxgb4: fix throughput drop during Tx backpressure
+    - cxgb4: fix Txq restart check during backpressure
+    - geneve: move debug check after netdev unregister
+    - hsr: fix general protection fault in hsr_addr_is_self()
+    - ipv4: fix a RCU-list lock in inet_dump_fib()
+    - macsec: restrict to ethernet devices
+    - mlxsw: pci: Only issue reset when system is ready
+    - mlxsw: spectrum_mr: Fix list iteration in error path
+    - net/bpfilter: fix dprintf usage for /dev/kmsg
+    - net: cbs: Fix software cbs to consider packet sending time
+    - net: dsa: Fix duplicate frames flooded by learning
+    - net: dsa: mt7530: Change the LINK bit to reflect the link status
+    - net: dsa: tag_8021q: replace dsa_8021q_remove_header with __skb_vlan_pop
+    - net: ena: Add PCI shutdown handler to allow safe kexec
+    - net: mvneta: Fix the case where the last poll did not process all rx
+    - net/packet: tpacket_rcv: avoid a producer race condition
+    - net: phy: dp83867: w/a for fld detect threshold bootstrapping issue
+    - net: phy: mdio-bcm-unimac: Fix clock handling
+    - net: phy: mdio-mux-bcm-iproc: check clk_prepare_enable() return value
+    - net: qmi_wwan: add support for ASKEY WWHC050
+    - net/sched: act_ct: Fix leak of ct zone template on replace
+    - net_sched: cls_route: remove the right filter from hashtable
+    - net_sched: hold rtnl lock in tcindex_partial_destroy_work()
+    - net_sched: keep alloc_hash updated after hash allocation
+    - net: stmmac: dwmac-rk: fix error path in rk_gmac_probe
+    - NFC: fdp: Fix a signedness bug in fdp_nci_send_patch()
+    - r8169: re-enable MSI on RTL8168c
+    - slcan: not call free_netdev before rtnl_unlock in slcan_open
+    - tcp: also NULL skb->dev when copy was needed
+    - tcp: ensure skb->dev is NULL before leaving TCP stack
+    - tcp: repair: fix TCP_QUEUE_SEQ implementation
+    - vxlan: check return value of gro_cells_init()
+    - bnxt_en: Fix Priority Bytes and Packets counters in ethtool -S.
+    - bnxt_en: fix memory leaks in bnxt_dcbnl_ieee_getets()
+    - bnxt_en: Return error if bnxt_alloc_ctx_mem() fails.
+    - bnxt_en: Free context memory after disabling PCI in probe error path.
+    - bnxt_en: Reset rings if ring reservation fails during open()
+    - net: ip_gre: Separate ERSPAN newlink / changelink callbacks
+    - net: ip_gre: Accept IFLA_INFO_DATA-less configuration
+    - hsr: use rcu_read_lock() in hsr_get_node_{list/status}()
+    - hsr: add restart routine into hsr_get_node_list()
+    - hsr: set .netnsok flag
+    - net/mlx5: DR, Fix postsend actions write length
+    - net/mlx5e: Enhance ICOSQ WQE info fields
+    - net/mlx5e: Fix missing reset of SW metadata in Striding RQ reset
+    - net/mlx5e: Fix ICOSQ recovery flow with Striding RQ
+    - net/mlx5e: Do not recover from a non-fatal syndrome
+    - cgroup-v1: cgroup_pidlist_next should update position index
+    - nfs: add minor version to nfs_server_key for fscache
+    - cpupower: avoid multiple definition with gcc -fno-common
+    - drivers/of/of_mdio.c:fix of_mdiobus_register()
+    - cgroup1: don't call release_agent when it is ""
+    - [Config] updateconfigs for DPAA_ERRATUM_A050385
+    - dt-bindings: net: FMan erratum A050385
+    - arm64: dts: ls1043a: FMan erratum A050385
+    - fsl/fman: detect FMan erratum A050385
+    - drm/amd/display: update soc bb for nv14
+    - drm/amdgpu: correct ROM_INDEX/DATA offset for VEGA20
+    - drm/exynos: Fix cleanup of IOMMU related objects
+    - iommu/vt-d: Silence RCU-list debugging warnings
+    - s390/qeth: don't reset default_out_queue
+    - s390/qeth: handle error when backing RX buffer
+    - scsi: ipr: Fix softlockup when rescanning devices in petitboot
+    - mac80211: Do not send mesh HWMP PREQ if HWMP is disabled
+    - dpaa_eth: Remove unnecessary boolean expression in dpaa_get_headroom
+    - sxgbe: Fix off by one in samsung driver strncpy size arg
+    - net: hns3: fix "tc qdisc del" failed issue
+    - iommu/vt-d: Fix debugfs register reads
+    - iommu/vt-d: Populate debugfs if IOMMUs are detected
+    - iwlwifi: mvm: fix non-ACPI function
+    - i2c: hix5hd2: add missed clk_disable_unprepare in remove
+    - Input: raydium_i2c_ts - fix error codes in raydium_i2c_boot_trigger()
+    - Input: fix stale timestamp on key autorepeat events
+    - Input: synaptics - enable RMI on HP Envy 13-ad105ng
+    - Input: avoid BIT() macro usage in the serio.h UAPI header
+    - IB/rdmavt: Free kernel completion queue when done
+    - RDMA/core: Fix missing error check on dev_set_name()
+    - gpiolib: Fix irq_disable() semantics
+    - RDMA/nl: Do not permit empty devices names during RDMA_NLDEV_CMD_NEWLINK/SET
+    - RDMA/mad: Do not crash if the rdma device does not have a umad interface
+    - ceph: check POOL_FLAG_FULL/NEARFULL in addition to OSDMAP_FULL/NEARFULL
+    - ceph: fix memory leak in ceph_cleanup_snapid_map()
+    - ARM: dts: dra7: Add bus_dma_limit for L3 bus
+    - ARM: dts: omap5: Add bus_dma_limit for L3 bus
+    - x86/ioremap: Fix CONFIG_EFI=n build
+    - perf probe: Fix to delete multiple probe event
+    - perf probe: Do not depend on dwfl_module_addrsym()
+    - rtlwifi: rtl8188ee: Fix regression due to commit d1d1a96bdb44
+    - tools: Let O= makes handle a relative path with -C option
+    - scripts/dtc: Remove redundant YYLOC global declaration
+    - scsi: sd: Fix optimal I/O size for devices that change reported values
+    - nl80211: fix NL80211_ATTR_CHANNEL_WIDTH attribute type
+    - mac80211: drop data frames without key on encrypted links
+    - mac80211: mark station unauthorized before key removal
+    - mm/swapfile.c: move inode_lock out of claim_swapfile
+    - drivers/base/memory.c: indicate all memory blocks as removable
+    - mm/sparse: fix kernel crash with pfn_section_valid check
+    - mm: fork: fix kernel_stack memcg stats for various stack implementations
+    - gpiolib: acpi: Correct comment for HP x2 10 honor_wakeup quirk
+    - gpiolib: acpi: Rework honor_wakeup option into an ignore_wake option
+    - gpiolib: acpi: Add quirk to ignore EC wakeups on HP x2 10 BYT + AXP288 model
+    - bpf: Fix cgroup ref leak in cgroup_bpf_inherit on out-of-memory
+    - RDMA/core: Ensure security pkey modify is not lost
+    - afs: Fix handling of an abort from a service handler
+    - genirq: Fix reference leaks on irq affinity notifiers
+    - xfrm: handle NETDEV_UNREGISTER for xfrm device
+    - vti[6]: fix packet tx through bpf_redirect() in XinY cases
+    - RDMA/mlx5: Fix the number of hwcounters of a dynamic counter
+    - RDMA/mlx5: Fix access to wrong pointer while performing flush due to error
+    - RDMA/mlx5: Block delay drop to unprivileged users
+    - 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
+    - afs: Fix client call Rx-phase signal handling
+    - afs: Fix some tracing details
+    - afs: Fix unpinned address list during probing
+    - ieee80211: fix HE SPR size calculation
+    - mac80211: set IEEE80211_TX_CTRL_PORT_CTRL_PROTO for nl80211 TX
+    - netfilter: flowtable: reload ip{v6}h in nf_flow_tuple_ip{v6}
+    - netfilter: nft_fwd_netdev: validate family and chain type
+    - netfilter: nft_fwd_netdev: allow to redirect to ifb via ingress
+    - i2c: nvidia-gpu: Handle timeout correctly in gpu_i2c_check_status()
+    - bpf, x32: Fix bug with JMP32 JSET BPF_X checking upper bits
+    - bpf: Initialize storage pointers to NULL to prevent freeing garbage pointer
+    - bpf/btf: Fix BTF verification of enum members in struct/union
+    - bpf, sockmap: Remove bucket->lock from sock_{hash|map}_free
+    - ARM: dts: sun8i-a83t-tbs-a711: Fix USB OTG mode detection
+    - vti6: Fix memory leak of skb if input policy check fails
+    - r8169: fix PHY driver check on platforms w/o module softdeps
+    - clocksource/drivers/hyper-v: Untangle stimers and timesync from clocksources
+    - 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: kpc2000: prevent underflow in cpld_reconfigure()
+    - staging: rtl8188eu: Add ASUS USB-N10 Nano B1 to device table
+    - staging: wlan-ng: fix ODEBUG bug in prism2sta_disconnect_usb
+    - staging: wlan-ng: fix use-after-free Read in hfa384x_usbin_callback
+    - ahci: Add Intel Comet Lake H RAID PCI ID
+    - 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
+    - media: v4l2-core: fix a use-after-free bug of sd->devnode
+    - update wireguard dkms package version
+    - [Config] updateconfigs for NET_REDIRECT
+    - net: Fix CONFIG_NET_CLS_ACT=n and CONFIG_NFT_FWD_NETDEV={y, m} build
+    - Linux 5.4.29
+
+  * Restore kernel control of PCIe DPC via option (LP: #1869423)
+    - PCI/DPC: Add "pcie_ports=dpc-native" to allow DPC without AER control
+
+  * swap storms kills interactive use (LP: #1861359)
+    - SAUCE: mm/page_alloc.c: disable memory reclaim watermark boosting by default
+
+  * sysfs: incorrect network device permissions on network namespace change
+    (LP: #1865359)
+    - sysfs: add sysfs_file_change_owner()
+    - sysfs: add sysfs_link_change_owner()
+    - sysfs: add sysfs_group{s}_change_owner()
+    - sysfs: add sysfs_change_owner()
+    - device: add device_change_owner()
+    - drivers/base/power: add dpm_sysfs_change_owner()
+    - net-sysfs: add netdev_change_owner()
+    - net-sysfs: add queue_change_owner()
+    - net: fix sysfs permssions when device changes network namespace
+    - sysfs: fix static inline declaration of sysfs_groups_change_owner()
+
+  * Kernel Oops - general protection fault: 0000 [#1] SMP PTI after
+    disconnecting thunderbolt docking station (LP: #1864754)
+    - SAUCE: ptp: free ptp clock properly
+
+  * [Selftests] Apply various fixes and improvements (LP: #1870543)
+    - SAUCE: selftests: net: ip_defrag: limit packet to 1000 fragments
+    - SAUCE: kselftest/runner: avoid using timeout if timeout is disabled
+    - SAUCE: selftests/seccomp -- Disable timeout for seccomp tests
+
+  * Focal update: v5.4.28 upstream stable release (LP: #1869061)
+    - locks: fix a potential use-after-free problem when wakeup a waiter
+    - locks: reinstate locks_delete_block optimization
+    - spi: spi-omap2-mcspi: Support probe deferral for DMA channels
+    - drm/mediatek: Find the cursor plane instead of hard coding it
+    - phy: ti: gmii-sel: fix set of copy-paste errors
+    - phy: ti: gmii-sel: do not fail in case of gmii
+    - ARM: dts: dra7-l4: mark timer13-16 as pwm capable
+    - spi: qup: call spi_qup_pm_resume_runtime before suspending
+    - powerpc: Include .BTF section
+    - cifs: fix potential mismatch of UNC paths
+    - cifs: add missing mount option to /proc/mounts
+    - ARM: dts: dra7: Add "dma-ranges" property to PCIe RC DT nodes
+    - spi: pxa2xx: Add CS control clock quirk
+    - 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
+    - drm/exynos: hdmi: don't leak enable HDMI_EN regulator if probe fails
+    - drivers/perf: fsl_imx8_ddr: Correct the CLEAR bit definition
+    - drivers/perf: arm_pmu_acpi: Fix incorrect checking of gicc pointer
+    - altera-stapl: altera_get_note: prevent write beyond end of 'key'
+    - dm bio record: save/restore bi_end_io and bi_integrity
+    - dm integrity: use dm_bio_record and dm_bio_restore
+    - riscv: avoid the PIC offset of static percpu data in module beyond 2G limits
+    - ASoC: stm32: sai: manage rebind issue
+    - spi: spi_register_controller(): free bus id on error paths
+    - riscv: Force flat memory model with no-mmu
+    - riscv: Fix range looking for kernel image memblock
+    - drm/amdgpu: clean wptr on wb when gpu recovery
+    - drm/amd/display: Clear link settings on MST disable connector
+    - drm/amd/display: fix dcc swath size calculations on dcn1
+    - xenbus: req->body should be updated before req->state
+    - xenbus: req->err should be updated before req->state
+    - block, bfq: fix overwrite of bfq_group pointer in bfq_find_set_group()
+    - parse-maintainers: Mark as executable
+    - binderfs: use refcount for binder control devices too
+    - Revert "drm/fbdev: Fallback to non tiled mode if all tiles not present"
+    - 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
+    - usb: xhci: apply XHCI_SUSPEND_DELAY to AMD XHCI controller 1022:145c
+    - usb: typec: ucsi: displayport: Fix NULL pointer dereference
+    - usb: typec: ucsi: displayport: Fix a potential race during registration
+    - USB: cdc-acm: fix close_delay and closing_wait units in TIOCSSERIAL
+    - USB: cdc-acm: fix rounding error in TIOCSSERIAL
+    - ALSA: line6: Fix endless MIDI read loop
+    - ALSA: hda/realtek - Enable headset mic of Acer X2660G with ALC662
+    - ALSA: hda/realtek - Enable the headset of Acer N50-600 with ALC662
+    - 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
+    - tty: fix compat TIOCGSERIAL leaking uninitialized memory
+    - tty: fix compat TIOCGSERIAL checking wrong function ptr
+    - iio: chemical: sps30: fix missing triggered buffer dependency
+    - iio: st_sensors: remap SMO8840 to LIS2DH12
+    - iio: trigger: stm32-timer: disable master mode when stopping
+    - iio: accel: adxl372: Set iio_chan BE
+    - iio: magnetometer: ak8974: Fix negative raw values in sysfs
+    - iio: adc: stm32-dfsdm: fix sleep in atomic context
+    - iio: adc: at91-sama5d2_adc: fix differential channels in triggered mode
+    - iio: light: vcnl4000: update sampling periods for vcnl4200
+    - iio: light: vcnl4000: update sampling periods for vcnl4040
+    - mmc: rtsx_pci: Fix support for speed-modes that relies on tuning
+    - mmc: sdhci-of-at91: fix cd-gpios for SAMA5D2
+    - mmc: sdhci-cadence: set SDHCI_QUIRK2_PRESET_VALUE_BROKEN for UniPhier
+    - CIFS: fiemap: do not return EINVAL if get nothing
+    - kbuild: Disable -Wpointer-to-enum-cast
+    - staging: rtl8188eu: Add device id for MERCUSYS MW150US v2
+    - staging: greybus: loopback_test: fix poll-mask build breakage
+    - staging/speakup: fix get_word non-space look-ahead
+    - intel_th: msu: Fix the unexpected state warning
+    - intel_th: Fix user-visible error codes
+    - intel_th: pci: Add Elkhart Lake CPU support
+    - modpost: move the namespace field in Module.symvers last
+    - rtc: max8907: add missing select REGMAP_IRQ
+    - arm64: compat: Fix syscall number of compat_clock_getres
+    - xhci: Do not open code __print_symbolic() in xhci trace events
+    - btrfs: fix log context list corruption after rename whiteout error
+    - drm/amd/amdgpu: Fix GPR read from debugfs (v2)
+    - drm/lease: fix WARNING in idr_destroy
+    - stm class: sys-t: Fix the use of time_after()
+    - memcg: fix NULL pointer dereference in __mem_cgroup_usage_unregister_event
+    - mm, memcg: fix corruption on 64-bit divisor in memory.high throttling
+    - mm, memcg: throttle allocators based on ancestral memory.high
+    - mm/hotplug: fix hot remove failure in SPARSEMEM|!VMEMMAP case
+    - mm: do not allow MADV_PAGEOUT for CoW pages
+    - epoll: fix possible lost wakeup on epoll_ctl() path
+    - mm: slub: be more careful about the double cmpxchg of freelist
+    - mm, slub: prevent kmalloc_node crashes and memory leaks
+    - page-flags: fix a crash at SetPageError(THP_SWAP)
+    - x86/mm: split vmalloc_sync_all()
+    - futex: Fix inode life-time issue
+    - futex: Unbreak futex hashing
+    - arm64: smp: fix smp_send_stop() behaviour
+    - arm64: smp: fix crash_smp_send_stop() behaviour
+    - nvmet-tcp: set MSG_MORE only if we actually have more to send
+    - drm/bridge: dw-hdmi: fix AVI frame colorimetry
+    - staging: greybus: loopback_test: fix potential path truncation
+    - staging: greybus: loopback_test: fix potential path truncations
+    - Linux 5.4.28
+
+  * Pop sound from build-in speaker during cold boot and resume from S3
+    (LP: #1866357) // Focal update: v5.4.28 upstream stable release
+    (LP: #1869061)
+    - ALSA: hda/realtek: Fix pop noise on ALC225
+
+  * Focal update: v5.4.28 upstream stable release (LP: #1869061)
+    - perf/x86/amd: Add support for Large Increment per Cycle Events
+    - EDAC/amd64: Add family ops for Family 19h Models 00h-0Fh
+    - x86/MCE/AMD, EDAC/mce_amd: Add new Load Store unit McaType
+    - EDAC/mce_amd: Always load on SMCA systems
+    - x86/amd_nb: Add Family 19h PCI IDs
+    - EDAC/amd64: Drop some family checks for newer systems
+
+  * Update mpt3sas Driver to 33.100.00.00 for Ubuntu 20.04 (LP: #1863574)
+    - scsi: mpt3sas: Register trace buffer based on NVDATA settings
+    - scsi: mpt3sas: Display message before releasing diag buffer
+    - scsi: mpt3sas: Free diag buffer without any status check
+    - scsi: mpt3sas: Maintain owner of buffer through UniqueID
+    - scsi: mpt3sas: clear release bit when buffer reregistered
+    - scsi: mpt3sas: Reuse diag buffer allocated at load time
+    - scsi: mpt3sas: Add app owned flag support for diag buffer
+    - scsi: mpt3sas: Fail release cmnd if diag buffer is released
+    - scsi: mpt3sas: Use Component img header to get Package ver
+    - scsi: mpt3sas: Fix module parameter max_msix_vectors
+    - scsi: mpt3sas: Bump mpt3sas driver version to 32.100.00.00
+    - scsi: mpt3sas: Clean up some indenting
+    - scsi: mpt3sas: change allocation option
+    - scsi: mpt3sas: Update MPI Headers to v02.00.57
+    - scsi: mpt3sas: Add support for NVMe shutdown
+    - scsi: mpt3sas: renamed _base_after_reset_handler function
+    - scsi: mpt3sas: Add support IOCs new state named COREDUMP
+    - scsi: mpt3sas: Handle CoreDump state from watchdog thread
+    - scsi: mpt3sas: print in which path firmware fault occurred
+    - scsi: mpt3sas: Optimize mpt3sas driver logging
+    - scsi: mpt3sas: Print function name in which cmd timed out
+    - scsi: mpt3sas: Remove usage of device_busy counter
+    - scsi: mpt3sas: Update drive version to 33.100.00.00
+
+  * Ubuntu 20.04: megaraid_sas driver update to version 07.713.01.00-rc1
+    (LP: #1863581)
+    - scsi: megaraid_sas: Unique names for MSI-X vectors
+    - scsi: megaraid_sas: remove unused variables 'debugBlk','fusion'
+    - compat_ioctl: use correct compat_ptr() translation in drivers
+    - scsi: megaraid_sas: Make poll_aen_lock static
+    - scsi: megaraid_sas: Reset adapter if FW is not in READY state after device
+      resume
+    - scsi: megaraid_sas: Set no_write_same only for Virtual Disk
+    - scsi: megaraid_sas: Update optimal queue depth for SAS and NVMe devices
+    - scsi: megaraid_sas: Do not kill host bus adapter, if adapter is already dead
+    - scsi: megaraid_sas: Do not kill HBA if JBOD Seqence map or RAID map is
+      disabled
+    - scsi: megaraid_sas: Do not set HBA Operational if FW is not in operational
+      state
+    - scsi: megaraid_sas: Re-Define enum DCMD_RETURN_STATUS
+    - scsi: megaraid_sas: Limit the number of retries for the IOCTLs causing
+      firmware fault
+    - scsi: megaraid_sas: Use Block layer API to check SCSI device in-flight IO
+      requests
+    - scsi: megaraid_sas: Update driver version to 07.713.01.00-rc1
+    - scsi: megaraid_sas: fixup MSIx interrupt setup during resume
+
+ -- Stefan Bader <stefan.bader@canonical.com>  Fri, 03 Apr 2020 16:28:40 +0200
+
+linux (5.4.0-21.25) focal; urgency=medium
+
+  * CVE-2020-8835
+    - SAUCE: bpf: undo incorrect __reg_bound_offset32 handling
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 26 Mar 2020 17:51:28 -0300
+
+linux (5.4.0-20.24) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (lockdown) Reduce lockdown level to INTEGRITY for secure boot
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 23 Mar 2020 14:54:04 -0500
+
+linux (5.4.0-19.23) focal; urgency=medium
+
+  * focal/linux: 5.4.0-19.23 -proposed tracker (LP: #1868347)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - update dkms package versions
+
+  * Focal update: v5.4.27 upstream stable release (LP: #1868538)
+    - netfilter: hashlimit: do not use indirect calls during gc
+    - netfilter: xt_hashlimit: unregister proc file before releasing mutex
+    - drm/amdgpu: Fix TLB invalidation request when using semaphore
+    - ACPI: watchdog: Allow disabling WDAT at boot
+    - HID: apple: Add support for recent firmware on Magic Keyboards
+    - ACPI: watchdog: Set default timeout in probe
+    - HID: hid-bigbenff: fix general protection fault caused by double kfree
+    - HID: hid-bigbenff: call hid_hw_stop() in case of error
+    - HID: hid-bigbenff: fix race condition for scheduled work during removal
+    - selftests/rseq: Fix out-of-tree compilation
+    - tracing: Fix number printing bug in print_synth_event()
+    - cfg80211: check reg_rule for NULL in handle_channel_custom()
+    - scsi: libfc: free response frame from GPN_ID
+    - net: usb: qmi_wwan: restore mtu min/max values after raw_ip switch
+    - net: ks8851-ml: Fix IRQ handling and locking
+    - mac80211: rx: avoid RCU list traversal under mutex
+    - net: ll_temac: Fix race condition causing TX hang
+    - net: ll_temac: Add more error handling of dma_map_single() calls
+    - net: ll_temac: Fix RX buffer descriptor handling on GFP_ATOMIC pressure
+    - net: ll_temac: Handle DMA halt condition caused by buffer underrun
+    - blk-mq: insert passthrough request into hctx->dispatch directly
+    - drm/amdgpu: fix memory leak during TDR test(v2)
+    - kbuild: add dtbs_check to PHONY
+    - kbuild: add dt_binding_check to PHONY in a correct place
+    - signal: avoid double atomic counter increments for user accounting
+    - slip: not call free_netdev before rtnl_unlock in slip_open
+    - net: phy: mscc: fix firmware paths
+    - hinic: fix a irq affinity bug
+    - hinic: fix a bug of setting hw_ioctxt
+    - hinic: fix a bug of rss configuration
+    - net: rmnet: fix NULL pointer dereference in rmnet_newlink()
+    - net: rmnet: fix NULL pointer dereference in rmnet_changelink()
+    - net: rmnet: fix suspicious RCU usage
+    - net: rmnet: remove rcu_read_lock in rmnet_force_unassociate_device()
+    - net: rmnet: do not allow to change mux id if mux id is duplicated
+    - net: rmnet: use upper/lower device infrastructure
+    - net: rmnet: fix bridge mode bugs
+    - net: rmnet: fix packet forwarding in rmnet bridge mode
+    - sfc: fix timestamp reconstruction at 16-bit rollover points
+    - jbd2: fix data races at struct journal_head
+    - blk-mq: insert flush request to the front of dispatch queue
+    - net: qrtr: fix len of skb_put_padto in qrtr_node_enqueue
+    - 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()
+    - HID: google: add moonball USB id
+    - HID: add ALWAYS_POLL quirk to lenovo pixart mouse
+    - ARM: 8961/2: Fix Kbuild issue caused by per-task stack protector GCC plugin
+    - ipv4: ensure rcu_read_lock() in cipso_v4_error()
+    - Linux 5.4.27
+
+  * This laptop contains a touchpadwhich is not recognized. (LP: #1858299) //
+    Focal update: v5.4.27 upstream stable release (LP: #1868538)
+    - HID: i2c-hid: add Trekstor Surfbook E11B to descriptor override
+
+  * suspend only works once on ThinkPad X1 Carbon gen 7 (LP: #1865570)
+    - SAUCE: e1000e: Disable s0ix flow for X1 Carbon 7th
+
+  *  Make Dell WD19 dock more reliable after suspend (LP: #1868217)
+    - xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3
+    - xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0
+    - xhci: Finetune host initiated USB3 rootport link suspend and resume
+    - USB: Disable LPM on WD19's Realtek Hub
+
+  * update-version-dkms doesn't add a BugLink (LP: #1867790)
+    - [Packaging] Add BugLink to update-version-dkms commit
+
+  * enable realtek ethernet device ASPM function (LP: #1836030)
+    - PCI/ASPM: Add L1 PM substate support to pci_disable_link_state()
+    - PCI/ASPM: Allow re-enabling Clock PM
+    - PCI/ASPM: Remove pcie_aspm_enabled() unnecessary locking
+    - PCI/ASPM: Add pcie_aspm_get_link()
+    - PCI/ASPM: Add sysfs attributes for controlling ASPM link states
+
+  * Update SmartPQI driver in Focal to 1.2.10-025 (LP: #1864484)
+    - scsi: smartpqi: clean up indentation of a statement
+    - scsi: smartpqi: remove set but not used variable 'ctrl_info'
+    - scsi: smartpqi: clean up an indentation issue
+    - scsi: smartpqi: fix controller lockup observed during force reboot
+    - scsi: smartpqi: fix call trace in device discovery
+    - scsi: smartpqi: add inquiry timeouts
+    - scsi: smartpqi: fix LUN reset when fw bkgnd thread is hung
+    - scsi: smartpqi: change TMF timeout from 60 to 30 seconds
+    - scsi: smartpqi: correct syntax issue
+    - scsi: smartpqi: fix problem with unique ID for physical device
+    - scsi: smartpqi: remove unused manifest constants
+    - scsi: smartpqi: Align driver syntax with oob
+    - scsi: smartpqi: bump version
+
+  * [roce-0111]sync mainline kernel 5.5rc6 roce patchset into ubuntu HWE kernel
+    branch (LP: #1859269)
+    - RDMA/hns: Modify variable/field name from vlan to vlan_id
+    - RDMA/hns: Fix a spelling mistake in a macro
+    - RDMA/hns: Delete BITS_PER_BYTE redefinition
+    - RDMA/core: Move core content from ib_uverbs to ib_core
+    - RDMA/core: Create mmap database and cookie helper functions
+    - RDMA: Connect between the mmap entry and the umap_priv structure
+    - RDMA/hns: Remove unsupported modify_port callback
+    - RDMA/hns: Delete unnecessary variable max_post
+    - RDMA/hns: Remove unnecessary structure hns_roce_sqp
+    - RDMA/hns: Delete unnecessary uar from hns_roce_cq
+    - RDMA/hns: Modify fields of struct hns_roce_srq
+    - RDMA/hns: Replace not intuitive function/macro names
+    - RDMA/hns: Simplify doorbell initialization code
+    - RDMA/hns: Modify hns_roce_hw_v2_get_cfg to simplify the code
+    - RDMA/hns: Fix non-standard error codes
+    - RDMA/hns: Modify appropriate printings
+    - dma-mapping: remove the DMA_ATTR_WRITE_BARRIER flag
+    - IB/umem: remove the dmasync argument to ib_umem_get
+    - RDMA/hns: Redefine interfaces used in creating cq
+    - RDMA/hns: Redefine the member of hns_roce_cq struct
+    - RDMA/hns: Rename the functions used inside creating cq
+    - RDMA/hns: Delete unnecessary callback functions for cq
+    - RDMA/hns: Remove unused function hns_roce_init_eq_table()
+    - RDMA/hns: Update the value of qp type
+    - RDMA/hns: Delete unnessary parameters in hns_roce_v2_qp_modify()
+    - RDMA/hns: Remove redundant print information
+    - RDMA/hns: Replace custom macros HNS_ROCE_ALIGN_UP
+    - RDMA/hns: Fix coding style issues
+    - RDMA/hns: Add support for reporting wc as software mode
+    - RDMA/hns: Remove some redundant variables related to capabilities
+    - RDMA/hns: Add interfaces to get pf capabilities from firmware
+    - RDMA/hns: Get pf capabilities from firmware
+    - RDMA/hns: Add support for extended atomic in userspace
+
+  * dmaengine: hisilicon: Add Kunpeng DMA engine support (LP: #1864442)
+    - dmaengine: hisilicon: Add Kunpeng DMA engine support
+    - [Config] CONFIG_HISI_DMA=m
+
+  * Add support for Realtek 8723DE wireless adapter (LP: #1780590)
+    - rtw88: 8822c: fix boolreturn.cocci warnings
+    - rtw88: remove redundant flag check helper function
+    - rtw88: pci: reset H2C queue indexes in a single write
+    - rtw88: not to enter or leave PS under IRQ
+    - rtw88: not to control LPS by each vif
+    - rtw88: remove unused lps state check helper
+    - rtw88: LPS enter/leave should be protected by lock
+    - rtw88: leave PS state for dynamic mechanism
+    - rtw88: add deep power save support
+    - rtw88: not to enter LPS by coex strategy
+    - rtw88: select deep PS mode when module is inserted
+    - rtw88: add deep PS PG mode for 8822c
+    - rtw88: remove misleading module parameter rtw_fw_support_lps
+    - mac80211: simplify TX aggregation start
+    - rtw88: check firmware leave lps successfully
+    - rtw88: allows to set RTS in TX descriptor
+    - rtw88: add driver TX queue support
+    - rtw88: take over rate control from mac80211
+    - rtw88: report tx rate to mac80211 stack
+    - rtw88: add TX-AMSDU support
+    - rtw88: flush hardware tx queues
+    - rtw88: Don't set RX_FLAG_DECRYPTED if packet has no encryption
+    - rtw88: configure TX queue EDCA parameters
+    - rtw88: raise firmware version debug level
+    - rtw88: use struct rtw_fw_hdr to access firmware header
+    - rtw88: Fix an error message
+    - rtw88: config 8822c multicast address in MAC init flow
+    - rtw88: add NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 support
+    - rtw88: Use rtw_write8_set to set SYS_FUNC
+    - rtw88: pci: config phy after chip info is setup
+    - rtw88: use a for loop in rtw_power_mode_change(), not goto
+    - rtw88: include interrupt.h for tasklet_struct
+    - rtw88: mark rtw_fw_hdr __packed
+    - rtw88: use macro to check the current band
+    - rtw88: add power tracking support
+    - rtw88: Enable 802.11ac beamformee support
+    - rtw88: add set_bitrate_mask support
+    - rtw88: add phy_info debugfs to show Tx/Rx physical status
+    - rtw88: fix GENMASK_ULL for u64
+    - rtw88: fix sparse warnings for DPK
+    - rtw88: fix sparse warnings for power tracking
+    - rtw88: 8822b: add RFE type 3 support
+    - rtw88: use rtw_phy_pg_cfg_pair struct, not arrays
+    - rtw88: rearrange if..else statements for rx rate indexes
+    - rtw88: avoid FW info flood
+    - rtw88: remove redundant null pointer check on arrays
+    - rtw88: raise LPS threshold to 50, for less power consumption
+    - rtw88: fix potential NULL pointer access for firmware
+    - rtw88: signal completion even on firmware-request failure
+    - rtw88: remove duplicated include from ps.c
+    - rtw88: pci: use macros to access PCI DBI/MDIO registers
+    - rtw88: pci: use for loop instead of while loop for DBI/MDIO
+    - rtw88: pci: enable CLKREQ function if host supports it
+    - rtw88: allows to enable/disable HCI link PS mechanism
+    - rtw88: pci: reset ring index when release skbs in tx ring
+    - rtw88: pci: reset dma when reset pci trx ring
+    - rtw88: add interface config for 8822c
+    - rtw88: load wowlan firmware if wowlan is supported
+    - rtw88: support wowlan feature for 8822c
+    - rtw88: Add wowlan pattern match support
+    - rtw88: Add wowlan net-detect support
+    - rtw88: fix TX secondary channel offset of 40M if current bw is 20M or 40M
+    - rtw88: 8822c: update power sequence to v15
+    - rtw88: remove unused spinlock
+    - rtw88: remove unused variable 'in_lps'
+    - rtw88: remove unused vif pointer in struct rtw_vif
+    - rtw88: use rtw_hci_stop() instead of rtwdev->hci.ops->stop()
+    - rtw88: assign NULL to skb after being kfree()'ed
+    - rtw88: change max_num_of_tx_queue() definition to inline in pci.h
+    - rtw88: use true,false for bool variable
+    - rtw88: use shorter delay time to poll PS state
+    - rtw88: Fix return value of rtw_wow_check_fw_status
+    - SAUCE: rtw88: add regulatory process strategy for different chipset
+    - SAUCE: rtw88: support dynamic user regulatory setting
+    - SAUCE: rtw88: Use secondary channel offset enumeration
+    - SAUCE: rtw88: 8822c: modify rf protection setting
+    - SAUCE: rtw88: disable TX-AMSDU on 2.4G band
+    - SAUCE: Revert "rtw88: disable TX-AMSDU on 2.4G band"
+    - SAUCE: rtw88: disable TX-AMSDU on 2.4G band
+    - SAUCE: rtw88: remove unused parameter vif in rtw_lps_pg_info_get()
+    - SAUCE: rtw88: add rtw_read8_mask and rtw_read16_mask
+    - SAUCE: rtw88: pci: 8822c should set clock delay to zero
+    - SAUCE: rtw88: move rtw_enter_ips() to the last when config
+    - SAUCE: rtw88: avoid holding mutex for cancel_delayed_work_sync()
+    - SAUCE: rtw88: add ciphers to suppress error message
+    - SAUCE: rtw88: 8822c: update power sequence to v16
+    - SAUCE: rtw88: Fix incorrect beamformee role setting
+    - SAUCE: rtw88: don't hold all IRQs disabled for PS operations
+    - SAUCE: rtw88: extract alloc rsvd_page and h2c skb routines
+    - SAUCE: rtw88: associate reserved pages with each vif
+    - SAUCE: rtw88: add adaptivity support for EU/JP regulatory
+    - SAUCE: rtw88: 8723d: Add basic chip capabilities
+    - SAUCE: rtw88: 8723d: add beamform wrapper functions
+    - SAUCE: rtw88: 8723d: Add power sequence
+    - SAUCE: rtw88: 8723d: Add RF read/write ops
+    - SAUCE: rtw88: 8723d: Add mac/bb/rf/agc/power_limit tables
+    - SAUCE: rtw88: 8723d: Add cfg_ldo25 to control LDO25
+    - SAUCE: rtw88: 8723d: Add new chip op efuse_grant() to control efuse access
+    - SAUCE: rtw88: 8723d: Add read_efuse to recognize efuse info from map
+    - SAUCE: rtw88: add legacy firmware download for 8723D devices
+    - SAUCE: rtw88: no need to send additional information to legacy firmware
+    - SAUCE: rtw88: 8723d: Add mac power-on/-off function
+    - SAUCE: rtw88: decompose while(1) loop of power sequence polling command
+    - SAUCE: rtw88: 8723d: 11N chips don't support H2C queue
+    - SAUCE: rtw88: 8723d: implement set_tx_power_index ops
+    - SAUCE: rtw88: 8723d: Organize chip TX/RX FIFO
+    - SAUCE: rtw88: 8723d: initialize mac/bb/rf basic functions
+    - SAUCE: rtw88: 8723d: Add DIG parameter
+    - SAUCE: rtw88: 8723d: Add query_rx_desc
+    - SAUCE: rtw88: 8723d: Add set_channel
+    - SAUCE: rtw88: handle C2H_CCX_TX_RPT to know if packet TX'ed successfully
+    - SAUCE: rtw88: 8723d: 11N chips don't support LDPC
+    - SAUCE: rtw88: set default port to firmware
+    - SAUCE: rtw88: update tx descriptor of mgmt and rsvd page packets
+    - SAUCE: rtw88: sar: add SAR of TX power limit
+    - SAUCE: rtw88: sar: Load static SAR table from ACPI WRDS method
+    - SAUCE: rtw88: sar: Load dynamic SAR table from ACPI methods
+    - SAUCE: rtw88: sar: apply dynamic SAR table to tx power limit
+    - SAUCE: rtw88: sar: add sar_work to poll if dynamic SAR table is changed
+    - SAUCE: rtw88: sar: dump sar information via debugfs
+    - SAUCE: rtw88: 8723d: Add chip_ops::false_alarm_statistics
+    - SAUCE: rtw88: 8723d: Set IG register for CCK rate
+    - SAUCE: rtw88: 8723d: add interface configurations table
+    - SAUCE: rtw88: 8723d: Add LC calibration
+    - SAUCE: rtw88: 8723d: add IQ calibration
+    - SAUCE: rtw88: 8723d: Add power tracking
+    - SAUCE: rtw88: 8723d: Add shutdown callback to disable BT USB suspend
+    - SAUCE: rtw88: 8723d: implement flush queue
+    - SAUCE: rtw88: 8723d: set ltecoex register address in chip_info
+    - SAUCE: rtw88: 8723d: Add coex support
+    - SAUCE: rtw88: fill zeros to words 0x06 and 0x07 of security cam entry
+    - SAUCE: rtw88: 8723d: Add 8723DE to Kconfig and Makefile
+    - [Config] CONFIG_RTW88_8723DE=y
+
+  * [Ubuntu 20.04] Unset HIBERNATION and PM kernel config options for focal
+    (LP: #1867753)
+    - [Config] CONFIG_HIBERNATION=n and CONFIG_PM=n for s390x
+
+  * [20.04 FEAT] Base KVM setup for secure guests - kernel part (LP: #1835531)
+    - KVM: s390: Cleanup kvm_arch_init error path
+    - KVM: s390: Cleanup initial cpu reset
+    - KVM: s390: Add new reset vcpu API
+    - s390/protvirt: introduce host side setup
+    - s390/protvirt: add ultravisor initialization
+    - s390/mm: provide memory management functions for protected KVM guests
+    - s390/mm: add (non)secure page access exceptions handlers
+    - s390/protvirt: Add sysfs firmware interface for Ultravisor information
+    - KVM: s390/interrupt: do not pin adapter interrupt pages
+    - KVM: s390: protvirt: Add UV debug trace
+    - KVM: s390: add new variants of UV CALL
+    - KVM: s390: protvirt: Add initial vm and cpu lifecycle handling
+    - KVM: s390: protvirt: Secure memory is not mergeable
+    - KVM: s390/mm: Make pages accessible before destroying the guest
+    - KVM: s390: protvirt: Handle SE notification interceptions
+    - KVM: s390: protvirt: Instruction emulation
+    - KVM: s390: protvirt: Implement interrupt injection
+    - KVM: s390: protvirt: Add SCLP interrupt handling
+    - KVM: s390: protvirt: Handle spec exception loops
+    - KVM: s390: protvirt: Add new gprs location handling
+    - KVM: S390: protvirt: Introduce instruction data area bounce buffer
+    - KVM: s390: protvirt: handle secure guest prefix pages
+    - KVM: s390/mm: handle guest unpin events
+    - KVM: s390: protvirt: Write sthyi data to instruction data area
+    - KVM: s390: protvirt: STSI handling
+    - KVM: s390: protvirt: disallow one_reg
+    - KVM: s390: protvirt: Do only reset registers that are accessible
+    - KVM: s390: protvirt: Only sync fmt4 registers
+    - KVM: s390: protvirt: Add program exception injection
+    - KVM: s390: protvirt: UV calls in support of diag308 0, 1
+    - KVM: s390: protvirt: Report CPU state to Ultravisor
+    - KVM: s390: protvirt: Support cmd 5 operation state
+    - KVM: s390: protvirt: Mask PSW interrupt bits for interception 104 and 112
+    - KVM: s390: protvirt: do not inject interrupts after start
+    - KVM: s390: protvirt: Add UV cpu reset calls
+    - DOCUMENTATION: Protected virtual machine introduction and IPL
+    - KVM: s390: protvirt: introduce and enable KVM_CAP_S390_PROTECTED
+    - KVM: s390: protvirt: Add KVM api documentation
+    - mm/gup/writeback: add callbacks for inaccessible pages
+
+  * Sys oopsed with sysfs test in ubuntu_stress_smoke_test on X-hwe ARM64
+    (LP: #1866772)
+    - ACPI: sysfs: copy ACPI data using io memory copying
+
+  * Focal update: v5.4.26 upstream stable release (LP: #1867903)
+    - virtio_balloon: Adjust label in virtballoon_probe
+    - ALSA: hda/realtek - More constifications
+    - cgroup, netclassid: periodically release file_lock on classid updating
+    - gre: fix uninit-value in __iptunnel_pull_header
+    - inet_diag: return classid for all socket types
+    - ipv6/addrconf: call ipv6_mc_up() for non-Ethernet interface
+    - ipvlan: add cond_resched_rcu() while processing muticast backlog
+    - ipvlan: do not add hardware address of master to its unicast filter list
+    - 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: dsa: fix phylink_start()/phylink_stop() calls
+    - net: dsa: mv88e6xxx: fix lockup on warm boot
+    - net: fec: validate the new settings in fec_enet_set_coalesce()
+    - net: hns3: fix a not link up issue when fibre port supports autoneg
+    - net/ipv6: use configured metric when add peer route
+    - netlink: Use netlink header as base to calculate bad attribute offset
+    - net: macsec: update SCI upon MAC address change.
+    - net: nfc: fix bounds checking bugs on "pipe"
+    - net/packet: tpacket_rcv: do not increment ring index on drop
+    - net: phy: bcm63xx: fix OOPS due to missing driver name
+    - net: stmmac: dwmac1000: Disable ACS if enhanced descs are not used
+    - net: systemport: fix index check to avoid an array out of bounds access
+    - sfc: detach from cb_page in efx_copy_channel()
+    - slip: make slhc_compress() more robust against malicious packets
+    - taprio: Fix sending packets without dequeueing them
+    - bonding/alb: make sure arp header is pulled before accessing it
+    - bnxt_en: reinitialize IRQs when MTU is modified
+    - bnxt_en: fix error handling when flashing from file
+    - cgroup: memcg: net: do not associate sock with unrelated cgroup
+    - net: memcg: late association of sock to memcg
+    - net: memcg: fix lockdep splat in inet_csk_accept()
+    - devlink: validate length of param values
+    - devlink: validate length of region addr/len
+    - fib: add missing attribute validation for tun_id
+    - nl802154: add missing attribute validation
+    - nl802154: add missing attribute validation for dev_type
+    - can: add missing attribute validation for termination
+    - macsec: add missing attribute validation for port
+    - net: fq: add missing attribute validation for orphan mask
+    - net: taprio: add missing attribute validation for txtime delay
+    - team: add missing attribute validation for port ifindex
+    - team: add missing attribute validation for array index
+    - tipc: add missing attribute validation for MTU property
+    - nfc: add missing attribute validation for SE API
+    - nfc: add missing attribute validation for deactivate target
+    - nfc: add missing attribute validation for vendor subcommand
+    - net: phy: avoid clearing PHY interrupts twice in irq handler
+    - net: phy: fix MDIO bus PM PHY resuming
+    - net/ipv6: need update peer route when modify metric
+    - net/ipv6: remove the old peer route if change it to a new one
+    - selftests/net/fib_tests: update addr_metric_test for peer route testing
+    - net: dsa: Don't instantiate phylink for CPU/DSA ports unless needed
+    - net: phy: Avoid multiple suspends
+    - cgroup: cgroup_procs_next should increase position index
+    - cgroup: Iterate tasks that did not finish do_exit()
+    - netfilter: nf_tables: fix infinite loop when expr is not available
+    - iwlwifi: mvm: Do not require PHY_SKU NVM section for 3168 devices
+    - iommu/vt-d: quirk_ioat_snb_local_iommu: replace WARN_TAINT with pr_warn +
+      add_taint
+    - netfilter: nf_conntrack: ct_cpu_seq_next should increase position index
+    - netfilter: synproxy: synproxy_cpu_seq_next should increase position index
+    - netfilter: xt_recent: recent_seq_next should increase position index
+    - netfilter: x_tables: xt_mttg_seq_next should increase position index
+    - workqueue: don't use wq_select_unbound_cpu() for bound works
+    - drm/amd/display: remove duplicated assignment to grph_obj_type
+    - drm/i915: be more solid in checking the alignment
+    - drm/i915: Defer semaphore priority bumping to a workqueue
+    - mmc: sdhci-pci-gli: Enable MSI interrupt for GL975x
+    - pinctrl: falcon: fix syntax error
+    - ktest: Add timeout for ssh sync testing
+    - cifs_atomic_open(): fix double-put on late allocation failure
+    - gfs2_atomic_open(): fix O_EXCL|O_CREAT handling on cold dcache
+    - KVM: x86: clear stale x86_emulate_ctxt->intercept value
+    - KVM: nVMX: avoid NULL pointer dereference with incorrect EVMCS GPAs
+    - ARC: define __ALIGN_STR and __ALIGN symbols for ARC
+    - fuse: fix stack use after return
+    - s390/dasd: fix data corruption for thin provisioned devices
+    - ipmi_si: Avoid spurious errors for optional IRQs
+    - blk-iocost: fix incorrect vtime comparison in iocg_is_idle()
+    - fscrypt: don't evict dirty inodes after removing key
+    - macintosh: windfarm: fix MODINFO regression
+    - x86/ioremap: Map EFI runtime services data as encrypted for SEV
+    - efi: Fix a race and a buffer overflow while reading efivars via sysfs
+    - efi: Add a sanity check to efivar_store_raw()
+    - i2c: designware-pci: Fix BUG_ON during device removal
+    - mt76: fix array overflow on receiving too many fragments for a packet
+    - perf/amd/uncore: Replace manual sampling check with CAP_NO_INTERRUPT flag
+    - x86/mce: Fix logic and comments around MSR_PPIN_CTL
+    - iommu/dma: Fix MSI reservation allocation
+    - iommu/vt-d: dmar: replace WARN_TAINT with pr_warn + add_taint
+    - iommu/vt-d: Fix RCU list debugging warnings
+    - iommu/vt-d: Fix a bug in intel_iommu_iova_to_phys() for huge page
+    - batman-adv: Don't schedule OGM for disabled interface
+    - clk: imx8mn: Fix incorrect clock defines
+    - pinctrl: meson-gxl: fix GPIOX sdio pins
+    - pinctrl: imx: scu: Align imx sc msg structs to 4
+    - virtio_ring: Fix mem leak with vring_new_virtqueue()
+    - drm/i915/gvt: Fix dma-buf display blur issue on CFL
+    - pinctrl: core: Remove extra kref_get which blocks hogs being freed
+    - drm/i915/gvt: Fix unnecessary schedule timer when no vGPU exits
+    - driver code: clarify and fix platform device DMA mask allocation
+    - iommu/vt-d: Fix RCU-list bugs in intel_iommu_init()
+    - i2c: gpio: suppress error on probe defer
+    - nl80211: add missing attribute validation for critical protocol indication
+    - nl80211: add missing attribute validation for beacon report scanning
+    - nl80211: add missing attribute validation for channel switch
+    - perf bench futex-wake: Restore thread count default to online CPU count
+    - netfilter: cthelper: add missing attribute validation for cthelper
+    - netfilter: nft_payload: add missing attribute validation for payload csum
+      flags
+    - netfilter: nft_tunnel: add missing attribute validation for tunnels
+    - netfilter: nf_tables: dump NFTA_CHAIN_FLAGS attribute
+    - netfilter: nft_chain_nat: inet family is missing module ownership
+    - iommu/vt-d: Fix the wrong printing in RHSA parsing
+    - iommu/vt-d: Ignore devices with out-of-spec domain number
+    - i2c: acpi: put device when verifying client fails
+    - iommu/amd: Fix IOMMU AVIC not properly update the is_run bit in IRTE
+    - ipv6: restrict IPV6_ADDRFORM operation
+    - net/smc: check for valid ib_client_data
+    - net/smc: cancel event worker during device removal
+    - Linux 5.4.26
+
+  * please help enable CONFIG_EROFS_FS_ZIP (LP: #1867099)
+    - [Config] CONFIG_EROFS_FS_ZIP=y
+    - [Config] CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT=1
+
+  * All PS/2 ports on PS/2 Serial add-in bracket are not working after S3
+    (LP: #1866734)
+    - SAUCE: Input: i8042 - fix the selftest retry logic
+
+  * [UBUNTU 20.04] virtio-blk disks can go dissfunctional when swiotlb fills up
+    (LP: #1867109)
+    - virtio-blk: fix hw_queue stopped on arbitrary error
+    - virtio-blk: improve virtqueue error to BLK_STS
+
+  * Focal update: v5.4.25 upstream stable release (LP: #1867178)
+    - block, bfq: get extra ref to prevent a queue from being freed during a group
+      move
+    - block, bfq: do not insert oom queue into position tree
+    - net: dsa: bcm_sf2: Forcibly configure IMP port for 1Gb/sec
+    - net: stmmac: fix notifier registration
+    - dm thin metadata: fix lockdep complaint
+    - RDMA/core: Fix pkey and port assignment in get_new_pps
+    - RDMA/core: Fix use of logical OR in get_new_pps
+    - kbuild: fix 'No such file or directory' warning when cleaning
+    - kprobes: Fix optimize_kprobe()/unoptimize_kprobe() cancellation logic
+    - blktrace: fix dereference after null check
+    - ALSA: hda: do not override bus codec_mask in link_get()
+    - serial: ar933x_uart: set UART_CS_{RX,TX}_READY_ORIDE
+    - selftests: fix too long argument
+    - usb: gadget: composite: Support more than 500mA MaxPower
+    - usb: gadget: ffs: ffs_aio_cancel(): Save/restore IRQ flags
+    - usb: gadget: serial: fix Tx stall after buffer overflow
+    - habanalabs: halt the engines before hard-reset
+    - habanalabs: do not halt CoreSight during hard reset
+    - habanalabs: patched cb equals user cb in device memset
+    - drm/msm/mdp5: rate limit pp done timeout warnings
+    - drm: msm: Fix return type of dsi_mgr_connector_mode_valid for kCFI
+    - drm/modes: Make sure to parse valid rotation value from cmdline
+    - drm/modes: Allow DRM_MODE_ROTATE_0 when applying video mode parameters
+    - scsi: megaraid_sas: silence a warning
+    - drm/msm/dsi: save pll state before dsi host is powered off
+    - drm/msm/dsi/pll: call vco set rate explicitly
+    - selftests: forwarding: use proto icmp for {gretap, ip6gretap}_mac testing
+    - selftests: forwarding: vxlan_bridge_1d: fix tos value
+    - net: atlantic: check rpc result and wait for rpc address
+    - net: ks8851-ml: Remove 8-bit bus accessors
+    - net: ks8851-ml: Fix 16-bit data access
+    - net: ks8851-ml: Fix 16-bit IO operation
+    - net: ethernet: dm9000: Handle -EPROBE_DEFER in dm9000_parse_dt()
+    - watchdog: da9062: do not ping the hw during stop()
+    - s390/cio: cio_ignore_proc_seq_next should increase position index
+    - s390: make 'install' not depend on vmlinux
+    - efi: Only print errors about failing to get certs if EFI vars are found
+    - net/mlx5: DR, Fix matching on vport gvmi
+    - nvme/pci: Add sleep quirk for Samsung and Toshiba drives
+    - nvme-pci: Use single IRQ vector for old Apple models
+    - x86/boot/compressed: Don't declare __force_order in kaslr_64.c
+    - s390/qdio: fill SL with absolute addresses
+    - nvme: Fix uninitialized-variable warning
+    - ice: Don't tell the OS that link is going down
+    - x86/xen: Distribute switch variables for initialization
+    - net: thunderx: workaround BGX TX Underflow issue
+    - csky/mm: Fixup export invalid_pte_table symbol
+    - csky: Set regs->usp to kernel sp, when the exception is from kernel
+    - csky/smp: Fixup boot failed when CONFIG_SMP
+    - csky: Fixup ftrace modify panic
+    - csky: Fixup compile warning for three unimplemented syscalls
+    - arch/csky: fix some Kconfig typos
+    - selftests: forwarding: vxlan_bridge_1d: use more proper tos value
+    - firmware: imx: scu: Ensure sequential TX
+    - binder: prevent UAF for binderfs devices
+    - binder: prevent UAF for binderfs devices II
+    - ALSA: hda/realtek - Add Headset Mic supported
+    - ALSA: hda/realtek - Add Headset Button supported for ThinkPad X1
+    - ALSA: hda/realtek - Fix silent output on Gigabyte X570 Aorus Master
+    - ALSA: hda/realtek - Enable the headset of ASUS B9450FA with ALC294
+    - cifs: don't leak -EAGAIN for stat() during reconnect
+    - cifs: fix rename() by ensuring source handle opened with DELETE bit
+    - usb: storage: Add quirk for Samsung Fit flash
+    - usb: quirks: add NO_LPM quirk for Logitech Screen Share
+    - usb: dwc3: gadget: Update chain bit correctly when using sg list
+    - usb: cdns3: gadget: link trb should point to next request
+    - usb: cdns3: gadget: toggle cycle bit before reset endpoint
+    - usb: core: hub: fix unhandled return by employing a void function
+    - 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
+    - mm, numa: fix bad pmd by atomically check for pmd_trans_huge when marking
+      page tables prot_numa
+    - mm: fix possible PMD dirty bit lost in set_pmd_migration_entry()
+    - mm, hotplug: fix page online with DEBUG_PAGEALLOC compiled but not enabled
+    - fat: fix uninit-memory access for partial initialized inode
+    - btrfs: fix RAID direct I/O reads with alternate csums
+    - arm64: dts: socfpga: agilex: Fix gmac compatible
+    - arm: dts: dra76x: Fix mmc3 max-frequency
+    - tty:serial:mvebu-uart:fix a wrong return
+    - tty: serial: fsl_lpuart: free IDs allocated by IDA
+    - serial: 8250_exar: add support for ACCES cards
+    - vt: selection, close sel_buffer race
+    - vt: selection, push console lock down
+    - vt: selection, push sel_lock up
+    - media: hantro: Fix broken media controller links
+    - media: mc-entity.c: use & to check pad flags, not ==
+    - media: vicodec: process all 4 components for RGB32 formats
+    - media: v4l2-mem2mem.c: fix broken links
+    - perf intel-pt: Fix endless record after being terminated
+    - perf intel-bts: Fix endless record after being terminated
+    - perf cs-etm: Fix endless record after being terminated
+    - perf arm-spe: Fix endless record after being terminated
+    - spi: spidev: Fix CS polarity if GPIO descriptors are used
+    - x86/pkeys: Manually set X86_FEATURE_OSPKE to preserve existing changes
+    - s390/pci: Fix unexpected write combine on resource
+    - s390/mm: fix panic in gup_fast on large pud
+    - dmaengine: imx-sdma: fix context cache
+    - dmaengine: imx-sdma: Fix the event id check to include RX event for UART6
+    - dmaengine: tegra-apb: Fix use-after-free
+    - dmaengine: tegra-apb: Prevent race conditions of tasklet vs free list
+    - dm integrity: fix recalculation when moving from journal mode to bitmap mode
+    - dm integrity: fix a deadlock due to offloading to an incorrect workqueue
+    - dm integrity: fix invalid table returned due to argument count mismatch
+    - dm cache: fix a crash due to incorrect work item cancelling
+    - dm: report suspended device during destroy
+    - dm writecache: verify watermark during resume
+    - dm zoned: Fix reference counter initial value of chunk works
+    - dm: fix congested_fn for request-based device
+    - arm64: dts: meson-sm1-sei610: add missing interrupt-names
+    - ARM: dts: ls1021a: Restore MDIO compatible to gianfar
+    - spi: bcm63xx-hsspi: Really keep pll clk enabled
+    - drm/virtio: make resource id workaround runtime switchable.
+    - drm/virtio: fix resource id creation race
+    - ASoC: topology: Fix memleak in soc_tplg_link_elems_load()
+    - ASoC: topology: Fix memleak in soc_tplg_manifest_load()
+    - ASoC: SOF: Fix snd_sof_ipc_stream_posn()
+    - ASoC: intel: skl: Fix pin debug prints
+    - ASoC: intel: skl: Fix possible buffer overflow in debug outputs
+    - powerpc: define helpers to get L1 icache sizes
+    - powerpc: Convert flush_icache_range & friends to C
+    - powerpc/mm: Fix missing KUAP disable in flush_coherent_icache()
+    - ASoC: pcm: Fix possible buffer overflow in dpcm state sysfs output
+    - ASoC: pcm512x: Fix unbalanced regulator enable call in probe error path
+    - ASoC: Intel: Skylake: Fix available clock counter incrementation
+    - ASoC: dapm: Correct DAPM handling of active widgets during shutdown
+    - spi: atmel-quadspi: fix possible MMIO window size overrun
+    - drm/panfrost: Don't try to map on error faults
+    - drm: kirin: Revert "Fix for hikey620 display offset problem"
+    - drm/sun4i: Add separate DE3 VI layer formats
+    - drm/sun4i: Fix DE2 VI layer format support
+    - drm/sun4i: de2/de3: Remove unsupported VI layer formats
+    - drm/i915: Program MBUS with rmw during initialization
+    - drm/i915/selftests: Fix return in assert_mmap_offset()
+    - phy: mapphone-mdm6600: Fix timeouts by adding wake-up handling
+    - phy: mapphone-mdm6600: Fix write timeouts with shorter GPIO toggle interval
+    - ARM: dts: imx6: phycore-som: fix emmc supply
+    - arm64: dts: imx8qxp-mek: Remove unexisting Ethernet PHY
+    - firmware: imx: misc: Align imx sc msg structs to 4
+    - firmware: imx: scu-pd: Align imx sc msg structs to 4
+    - firmware: imx: Align imx_sc_msg_req_cpu_start to 4
+    - soc: imx-scu: Align imx sc msg structs to 4
+    - Revert "RDMA/cma: Simplify rdma_resolve_addr() error flow"
+    - RDMA/rw: Fix error flow during RDMA context initialization
+    - RDMA/nldev: Fix crash when set a QP to a new counter but QPN is missing
+    - RDMA/siw: Fix failure handling during device creation
+    - RDMA/iwcm: Fix iwcm work deallocation
+    - RDMA/core: Fix protection fault in ib_mr_pool_destroy
+    - regulator: stm32-vrefbuf: fix a possible overshoot when re-enabling
+    - RMDA/cm: Fix missing ib_cm_destroy_id() in ib_cm_insert_listen()
+    - IB/hfi1, qib: Ensure RCU is locked when accessing list
+    - ARM: imx: build v7_cpu_resume() unconditionally
+    - ARM: dts: am437x-idk-evm: Fix incorrect OPP node names
+    - ARM: dts: dra7xx-clocks: Fixup IPU1 mux clock parent source
+    - ARM: dts: imx7-colibri: Fix frequency for sd/mmc
+    - hwmon: (adt7462) Fix an error return in ADT7462_REG_VOLT()
+    - dma-buf: free dmabuf->name in dma_buf_release()
+    - dmaengine: coh901318: Fix a double lock bug in dma_tc_handle()
+    - arm64: dts: meson: fix gxm-khadas-vim2 wifi
+    - bus: ti-sysc: Fix 1-wire reset quirk
+    - EDAC/synopsys: Do not print an error with back-to-back snprintf() calls
+    - powerpc: fix hardware PMU exception bug on PowerVM compatibility mode
+      systems
+    - efi/x86: Align GUIDs to their size in the mixed mode runtime wrapper
+    - efi/x86: Handle by-ref arguments covering multiple pages in mixed mode
+    - efi: READ_ONCE rng seed size before munmap
+    - block, bfq: get a ref to a group when adding it to a service tree
+    - block, bfq: remove ifdefs from around gets/puts of bfq groups
+    - csky: Implement copy_thread_tls
+    - drm/virtio: module_param_named() requires linux/moduleparam.h
+    - Linux 5.4.25
+
+  * Miscellaneous Ubuntu changes
+    - hio -- remove duplicated MODULE_DEVICE_TABLE declaration
+    - [Config] Add initial riscv64 config
+    - [Config] Bring riscv64 in line with other arches
+    - [Packaging] Add riscv64 arch support
+    - [Packaging] Add initial riscv64 abi
+    - [Config] updateconfigs for riscv64
+    - [Config] Update annotations for riscv64
+    - SAUCE: r8169: disable ASPM L1.1
+    - update wireguard dkms package version
+    - [Config] garbage collect PCIEASPM_DEBUG
+    - [Config] gcc version updateconfigs
+
+  * Miscellaneous upstream changes
+    - Revert "UBUNTU: SAUCE: platform/x86: dell-uart-backlight: move retry block"
+    - RISC-V: Do not invoke SBI call if cpumask is empty
+    - RISC-V: Issue a local tlbflush if possible.
+    - RISC-V: Issue a tlb page flush if possible
+    - riscv: add support for SECCOMP and SECCOMP_FILTER
+    - riscv: reject invalid syscalls below -1
+    - mtd: spi-nor: Add support for is25wp256
+    - PCI/ASPM: Remove PCIEASPM_DEBUG Kconfig option and related code
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 23 Mar 2020 13:03:48 +0100
+
+linux (5.4.0-18.22) focal; urgency=medium
+
+  * focal/linux: 5.4.0-18.22 -proposed tracker (LP: #1866488)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * Add sysfs attribute to show remapped NVMe (LP: #1863621)
+    - SAUCE: ata: ahci: Add sysfs attribute to show remapped NVMe device count
+
+  * [20.04 FEAT] Compression improvements in Linux kernel (LP: #1830208)
+    - lib/zlib: add s390 hardware support for kernel zlib_deflate
+    - s390/boot: rename HEAP_SIZE due to name collision
+    - lib/zlib: add s390 hardware support for kernel zlib_inflate
+    - s390/boot: add dfltcc= kernel command line parameter
+    - lib/zlib: add zlib_deflate_dfltcc_enabled() function
+    - btrfs: use larger zlib buffer for s390 hardware compression
+    - [Config] Introducing s390x specific kernel config option CONFIG_ZLIB_DFLTCC
+
+  * [UBUNTU 20.04] s390x/pci: increase CONFIG_PCI_NR_FUNCTIONS to 512 in kernel
+    config (LP: #1866056)
+    - [Config] Increase CONFIG_PCI_NR_FUNCTIONS from 64 to 512 starting with focal
+      on s390x
+
+  * CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set (LP: #1865332)
+    - [Config] CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+
+  * Dell XPS 13 9300 Intel 1650S wifi [34f0:1651] fails to load firmware
+    (LP: #1865962)
+    - iwlwifi: remove IWL_DEVICE_22560/IWL_DEVICE_FAMILY_22560
+    - iwlwifi: 22000: fix some indentation
+    - iwlwifi: pcie: rx: use rxq queue_size instead of constant
+    - iwlwifi: allocate more receive buffers for HE devices
+    - iwlwifi: remove some outdated iwl22000 configurations
+    - iwlwifi: assume the driver_data is a trans_cfg, but allow full cfg
+
+  * [FOCAL][REGRESSION] Intel Gen 9 brightness cannot be controlled
+    (LP: #1861521)
+    - Revert "USUNTU: SAUCE: drm/i915: Force DPCD backlight mode on Dell Precision
+      4K sku"
+    - Revert "UBUNTU: SAUCE: drm/i915: Force DPCD backlight mode on X1 Extreme 2nd
+      Gen 4K AMOLED panel"
+    - SAUCE: drm/dp: Introduce EDID-based quirks
+    - SAUCE: drm/i915: Force DPCD backlight mode on X1 Extreme 2nd Gen 4K AMOLED
+      panel
+    - SAUCE: drm/i915: Force DPCD backlight mode for some Dell CML 2020 panels
+
+  * [20.04 FEAT] Enable proper kprobes on ftrace support (LP: #1865858)
+    - s390/ftrace: save traced function caller
+    - s390: support KPROBES_ON_FTRACE
+
+  * alsa/sof: load different firmware on different platforms (LP: #1857409)
+    - ASoC: SOF: Intel: hda: use fallback for firmware name
+    - ASoC: Intel: acpi-match: split CNL tables in three
+    - ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names.
+
+  * [UBUNTU 20.04] Enable CONFIG_NET_SWITCHDEV in kernel config for s390x
+    starting with focal (LP: #1865452)
+    - [Config] Enable CONFIG_NET_SWITCHDEV in kernel config for s390x starting
+      with focal
+
+  * Focal update: v5.4.24 upstream stable release (LP: #1866333)
+    - io_uring: grab ->fs as part of async offload
+    - EDAC: skx_common: downgrade message importance on missing PCI device
+    - net: dsa: b53: Ensure the default VID is untagged
+    - net: fib_rules: Correctly set table field when table number exceeds 8 bits
+    - net: macb: ensure interface is not suspended on at91rm9200
+    - net: mscc: fix in frame extraction
+    - net: phy: restore mdio regs in the iproc mdio driver
+    - net: sched: correct flower port blocking
+    - net/tls: Fix to avoid gettig invalid tls record
+    - nfc: pn544: Fix occasional HW initialization failure
+    - qede: Fix race between rdma destroy workqueue and link change event
+    - Revert "net: dev: introduce support for sch BYPASS for lockless qdisc"
+    - udp: rehash on disconnect
+    - sctp: move the format error check out of __sctp_sf_do_9_1_abort
+    - bnxt_en: Improve device shutdown method.
+    - bnxt_en: Issue PCIe FLR in kdump kernel to cleanup pending DMAs.
+    - bonding: add missing netdev_update_lockdep_key()
+    - net: export netdev_next_lower_dev_rcu()
+    - bonding: fix lockdep warning in bond_get_stats()
+    - ipv6: Fix route replacement with dev-only route
+    - ipv6: Fix nlmsg_flags when splitting a multipath route
+    - ipmi:ssif: Handle a possible NULL pointer reference
+    - drm/msm: Set dma maximum segment size for mdss
+    - sched/core: Don't skip remote tick for idle CPUs
+    - timers/nohz: Update NOHZ load in remote tick
+    - sched/fair: Prevent unlimited runtime on throttled group
+    - dax: pass NOWAIT flag to iomap_apply
+    - mac80211: consider more elements in parsing CRC
+    - cfg80211: check wiphy driver existence for drvinfo report
+    - s390/zcrypt: fix card and queue total counter wrap
+    - qmi_wwan: re-add DW5821e pre-production variant
+    - qmi_wwan: unconditionally reject 2 ep interfaces
+    - NFSv4: Fix races between open and dentry revalidation
+    - perf/smmuv3: Use platform_get_irq_optional() for wired interrupt
+    - perf/x86/intel: Add Elkhart Lake support
+    - perf/x86/cstate: Add Tremont support
+    - perf/x86/msr: Add Tremont support
+    - ceph: do not execute direct write in parallel if O_APPEND is specified
+    - ARM: dts: sti: fixup sound frame-inversion for stihxxx-b2120.dtsi
+    - drm/amd/display: Do not set optimized_require to false after plane disable
+    - RDMA/siw: Remove unwanted WARN_ON in siw_cm_llp_data_ready()
+    - drm/amd/display: Check engine is not NULL before acquiring
+    - drm/amd/display: Limit minimum DPPCLK to 100MHz.
+    - drm/amd/display: Add initialitions for PLL2 clock source
+    - amdgpu: Prevent build errors regarding soft/hard-float FP ABI tags
+    - soc/tegra: fuse: Fix build with Tegra194 configuration
+    - i40e: Fix the conditional for i40e_vc_validate_vqs_bitmaps
+    - net: ena: fix potential crash when rxfh key is NULL
+    - net: ena: fix uses of round_jiffies()
+    - net: ena: add missing ethtool TX timestamping indication
+    - net: ena: fix incorrect default RSS key
+    - net: ena: rss: do not allocate key when not supported
+    - net: ena: rss: fix failure to get indirection table
+    - net: ena: rss: store hash function as values and not bits
+    - net: ena: fix incorrectly saving queue numbers when setting RSS indirection
+      table
+    - net: ena: fix corruption of dev_idx_to_host_tbl
+    - net: ena: ethtool: use correct value for crc32 hash
+    - net: ena: ena-com.c: prevent NULL pointer dereference
+    - ice: update Unit Load Status bitmask to check after reset
+    - cifs: Fix mode output in debugging statements
+    - cfg80211: add missing policy for NL80211_ATTR_STATUS_CODE
+    - mac80211: fix wrong 160/80+80 MHz setting
+    - nvme/tcp: fix bug on double requeue when send fails
+    - nvme: prevent warning triggered by nvme_stop_keep_alive
+    - nvme/pci: move cqe check after device shutdown
+    - ext4: potential crash on allocation error in ext4_alloc_flex_bg_array()
+    - audit: fix error handling in audit_data_to_entry()
+    - audit: always check the netlink payload length in audit_receive_msg()
+    - ACPICA: Introduce ACPI_ACCESS_BYTE_WIDTH() macro
+    - ACPI: watchdog: Fix gas->access_width usage
+    - KVM: VMX: check descriptor table exits on instruction emulation
+    - HID: ite: Only bind to keyboard USB interface on Acer SW5-012 keyboard dock
+    - HID: core: fix off-by-one memset in hid_report_raw_event()
+    - HID: core: increase HID report buffer size to 8KiB
+    - drm/amdgpu: Drop DRIVER_USE_AGP
+    - drm/radeon: Inline drm_get_pci_dev
+    - macintosh: therm_windtunnel: fix regression when instantiating devices
+    - tracing: Disable trace_printk() on post poned tests
+    - Revert "PM / devfreq: Modify the device name as devfreq(X) for sysfs"
+    - amdgpu/gmc_v9: save/restore sdpif regs during S3
+    - cpufreq: Fix policy initialization for internal governor drivers
+    - io_uring: fix 32-bit compatability with sendmsg/recvmsg
+    - netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports
+    - net/smc: transfer fasync_list in case of fallback
+    - vhost: Check docket sk_family instead of call getname
+    - netfilter: ipset: Fix forceadd evaluation path
+    - netfilter: xt_hashlimit: reduce hashlimit_mutex scope for htable_put()
+    - HID: alps: Fix an error handling path in 'alps_input_configured()'
+    - HID: hiddev: Fix race in in hiddev_disconnect()
+    - MIPS: VPE: Fix a double free and a memory leak in 'release_vpe()'
+    - i2c: altera: Fix potential integer overflow
+    - i2c: jz4780: silence log flood on txabrt
+    - drm/i915/gvt: Fix orphan vgpu dmabuf_objs' lifetime
+    - drm/i915/gvt: Separate display reset from ALL_ENGINES reset
+    - nl80211: fix potential leak in AP start
+    - mac80211: Remove a redundant mutex unlock
+    - kbuild: fix DT binding schema rule to detect command line changes
+    - hv_netvsc: Fix unwanted wakeup in netvsc_attach()
+    - usb: charger: assign specific number for enum value
+    - nvme-pci: Hold cq_poll_lock while completing CQEs
+    - s390/qeth: vnicc Fix EOPNOTSUPP precedence
+    - net: netlink: cap max groups which will be considered in netlink_bind()
+    - net: atlantic: fix use after free kasan warn
+    - net: atlantic: fix potential error handling
+    - net: atlantic: fix out of range usage of active_vlans array
+    - net/smc: no peer ID in CLC decline for SMCD
+    - net: ena: make ena rxfh support ETH_RSS_HASH_NO_CHANGE
+    - selftests: Install settings files to fix TIMEOUT failures
+    - kbuild: remove header compile test
+    - kbuild: move headers_check rule to usr/include/Makefile
+    - kbuild: remove unneeded variable, single-all
+    - kbuild: make single target builds even faster
+    - namei: only return -ECHILD from follow_dotdot_rcu()
+    - mwifiex: drop most magic numbers from mwifiex_process_tdls_action_frame()
+    - mwifiex: delete unused mwifiex_get_intf_num()
+    - KVM: SVM: Override default MMIO mask if memory encryption is enabled
+    - KVM: Check for a bad hva before dropping into the ghc slow path
+    - sched/fair: Optimize select_idle_cpu
+    - f2fs: fix to add swap extent correctly
+    - RDMA/hns: Simplify the calculation and usage of wqe idx for post verbs
+    - RDMA/hns: Bugfix for posting a wqe with sge
+    - drivers: net: xgene: Fix the order of the arguments of
+      'alloc_etherdev_mqs()'
+    - ima: ima/lsm policy rule loading logic bug fixes
+    - kprobes: Set unoptimized flag after unoptimizing code
+    - lib/vdso: Make __arch_update_vdso_data() logic understandable
+    - lib/vdso: Update coarse timekeeper unconditionally
+    - pwm: omap-dmtimer: put_device() after of_find_device_by_node()
+    - perf hists browser: Restore ESC as "Zoom out" of DSO/thread/etc
+    - perf ui gtk: Add missing zalloc object
+    - x86/resctrl: Check monitoring static key in the MBM overflow handler
+    - KVM: x86: Remove spurious kvm_mmu_unload() from vcpu destruction path
+    - KVM: x86: Remove spurious clearing of async #PF MSR
+    - rcu: Allow only one expedited GP to run concurrently with wakeups
+    - ubifs: Fix ino_t format warnings in orphan_delete()
+    - thermal: db8500: Depromote debug print
+    - thermal: brcmstb_thermal: Do not use DT coefficients
+    - netfilter: nft_tunnel: no need to call htons() when dumping ports
+    - netfilter: nf_flowtable: fix documentation
+    - bus: tegra-aconnect: Remove PM_CLK dependency
+    - xfs: clear kernel only flags in XFS_IOC_ATTRMULTI_BY_HANDLE
+    - locking/lockdep: Fix lockdep_stats indentation problem
+    - mm/debug.c: always print flags in dump_page()
+    - mm/gup: allow FOLL_FORCE for get_user_pages_fast()
+    - mm/huge_memory.c: use head to check huge zero page
+    - mm, thp: fix defrag setting if newline is not used
+    - kvm: nVMX: VMWRITE checks VMCS-link pointer before VMCS field
+    - kvm: nVMX: VMWRITE checks unsupported field before read-only field
+    - blktrace: Protect q->blk_trace with RCU
+    - Linux 5.4.24
+
+  * Focal update: v5.4.23 upstream stable release (LP: #1866165)
+    - iommu/qcom: Fix bogus detach logic
+    - ALSA: hda: Use scnprintf() for printing texts for sysfs/procfs
+    - ALSA: hda/realtek - Apply quirk for MSI GP63, too
+    - ALSA: hda/realtek - Apply quirk for yet another MSI laptop
+    - ASoC: codec2codec: avoid invalid/double-free of pcm runtime
+    - ASoC: sun8i-codec: Fix setting DAI data format
+    - tpm: Initialize crypto_id of allocated_banks to HASH_ALGO__LAST
+    - ecryptfs: fix a memory leak bug in parse_tag_1_packet()
+    - ecryptfs: fix a memory leak bug in ecryptfs_init_messaging()
+    - btrfs: handle logged extent failure properly
+    - thunderbolt: Prevent crash if non-active NVMem file is read
+    - USB: misc: iowarrior: add support for 2 OEMed devices
+    - USB: misc: iowarrior: add support for the 28 and 28L devices
+    - USB: misc: iowarrior: add support for the 100 device
+    - e1000e: Use rtnl_lock to prevent race conditions between net and pci/pm
+    - floppy: check FDC index for errors before assigning it
+    - vt: fix scrollback flushing on background consoles
+    - vt: selection, handle pending signals in paste_selection
+    - vt: vt_ioctl: fix race in VT_RESIZEX
+    - staging: android: ashmem: Disallow ashmem memory from being remapped
+    - staging: vt6656: fix sign of rx_dbm to bb_pre_ed_rssi.
+    - xhci: Force Maximum Packet size for Full-speed bulk devices to valid range.
+    - xhci: fix runtime pm enabling for quirky Intel hosts
+    - xhci: apply XHCI_PME_STUCK_QUIRK to Intel Comet Lake platforms
+    - xhci: Fix memory leak when caching protocol extended capability PSI tables -
+      take 2
+    - usb: host: xhci: update event ring dequeue pointer on purpose
+    - USB: core: add endpoint-blacklist quirk
+    - USB: quirks: blacklist duplicate ep on Sound Devices USBPre2
+    - 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
+    - USB: hub: Fix the broken detection of USB3 device in SMSC hub
+    - usb: dwc2: Fix SET/CLEAR_FEATURE and GET_STATUS flows
+    - usb: dwc3: gadget: Check for IOC/LST bit in TRB->ctrl fields
+    - usb: dwc3: debug: fix string position formatting mixup with ret and len
+    - scsi: Revert "target/core: Inline transport_lun_remove_cmd()"
+    - staging: rtl8188eu: Fix potential security hole
+    - staging: rtl8188eu: Fix potential overuse of kernel memory
+    - staging: rtl8723bs: Fix potential security hole
+    - staging: rtl8723bs: Fix potential overuse of kernel memory
+    - drm/panfrost: perfcnt: Reserve/use the AS attached to the perfcnt MMU
+      context
+    - powerpc/8xx: Fix clearing of bits 20-23 in ITLB miss
+    - powerpc/eeh: Fix deadlock handling dead PHB
+    - powerpc/tm: Fix clearing MSR[TS] in current when reclaiming on signal
+      delivery
+    - powerpc/entry: Fix an #if which should be an #ifdef in entry_32.S
+    - powerpc/hugetlb: Fix 512k hugepages on 8xx with 16k page size
+    - powerpc/hugetlb: Fix 8M hugepages on 8xx
+    - arm64: memory: Add missing brackets to untagged_addr() macro
+    - jbd2: fix ocfs2 corrupt when clearing block group bits
+    - x86/ima: use correct identifier for SetupMode variable
+    - x86/mce/amd: Publish the bank pointer only after setup has succeeded
+    - x86/mce/amd: Fix kobject lifetime
+    - x86/cpu/amd: Enable the fixed Instructions Retired counter IRPERF
+    - serial: 8250: Check UPF_IRQ_SHARED in advance
+    - tty/serial: atmel: manage shutdown in case of RS485 or ISO7816 mode
+    - tty: serial: imx: setup the correct sg entry for tx dma
+    - tty: serial: qcom_geni_serial: Fix RX cancel command failure
+    - serdev: ttyport: restore client ops on deregistration
+    - MAINTAINERS: Update drm/i915 bug filing URL
+    - ACPI: PM: s2idle: Check fixed wakeup events in acpi_s2idle_wake()
+    - mm/memcontrol.c: lost css_put in memcg_expand_shrinker_maps()
+    - nvme-multipath: Fix memory leak with ana_log_buf
+    - genirq/irqdomain: Make sure all irq domain flags are distinct
+    - mm/vmscan.c: don't round up scan size for online memory cgroup
+    - mm/sparsemem: pfn_to_page is not valid yet on SPARSEMEM
+    - lib/stackdepot.c: fix global out-of-bounds in stack_slabs
+    - mm: Avoid creating virtual address aliases in brk()/mmap()/mremap()
+    - drm/amdgpu/soc15: fix xclk for raven
+    - drm/amdgpu/gfx9: disable gfxoff when reading rlc clock
+    - drm/amdgpu/gfx10: disable gfxoff when reading rlc clock
+    - drm/nouveau/kms/gv100-: Re-set LUT after clearing for modesets
+    - drm/i915: Wean off drm_pci_alloc/drm_pci_free
+    - drm/i915: Update drm/i915 bug filing URL
+    - sched/psi: Fix OOB write when writing 0 bytes to PSI files
+    - KVM: nVMX: Don't emulate instructions in guest mode
+    - KVM: x86: don't notify userspace IOAPIC on edge-triggered interrupt EOI
+    - ext4: fix a data race in EXT4_I(inode)->i_disksize
+    - ext4: add cond_resched() to __ext4_find_entry()
+    - ext4: fix potential race between online resizing and write operations
+    - ext4: fix potential race between s_group_info online resizing and access
+    - ext4: fix potential race between s_flex_groups online resizing and access
+    - ext4: fix mount failure with quota configured as module
+    - ext4: rename s_journal_flag_rwsem to s_writepages_rwsem
+    - ext4: fix race between writepages and enabling EXT4_EXTENTS_FL
+    - KVM: nVMX: Refactor IO bitmap checks into helper function
+    - KVM: nVMX: Check IO instruction VM-exit conditions
+    - KVM: nVMX: clear PIN_BASED_POSTED_INTR from nested pinbased_ctls only when
+      apicv is globally disabled
+    - KVM: nVMX: handle nested posted interrupts when apicv is disabled for L1
+    - KVM: apic: avoid calculating pending eoi from an uninitialized val
+    - btrfs: destroy qgroup extent records on transaction abort
+    - btrfs: fix bytes_may_use underflow in prealloc error condtition
+    - btrfs: reset fs_root to NULL on error in open_ctree
+    - btrfs: do not check delayed items are empty for single transaction cleanup
+    - Btrfs: fix btrfs_wait_ordered_range() so that it waits for all ordered
+      extents
+    - Btrfs: fix race between shrinking truncate and fiemap
+    - btrfs: don't set path->leave_spinning for truncate
+    - Btrfs: fix deadlock during fast fsync when logging prealloc extents beyond
+      eof
+    - Revert "dmaengine: imx-sdma: Fix memory leak"
+    - drm/i915/gvt: more locking for ppgtt mm LRU list
+    - drm/bridge: tc358767: fix poll timeouts
+    - drm/i915/gt: Protect defer_request() from new waiters
+    - drm/msm/dpu: fix BGR565 vs RGB565 confusion
+    - 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"
+    - usb: gadget: composite: Fix bMaxPower for SuperSpeedPlus
+    - usb: dwc2: Fix in ISOC request length checking
+    - staging: rtl8723bs: fix copy of overlapping memory
+    - staging: greybus: use after free in gb_audio_manager_remove_all()
+    - ASoC: atmel: fix atmel_ssc_set_audio link failure
+    - ASoC: fsl_sai: Fix exiting path on probing failure
+    - ecryptfs: replace BUG_ON with error handling code
+    - iommu/vt-d: Fix compile warning from intel-svm.h
+    - crypto: rename sm3-256 to sm3 in hash_algo_name
+    - genirq/proc: Reject invalid affinity masks (again)
+    - bpf, offload: Replace bitwise AND by logical AND in
+      bpf_prog_offload_info_fill
+    - arm64: lse: Fix LSE atomics with LLVM
+    - io_uring: fix __io_iopoll_check deadlock in io_sq_thread
+    - 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
+    - netfilter: xt_hashlimit: limit the max size of hashtable
+    - rxrpc: Fix call RCU cleanup using non-bh-safe locks
+    - io_uring: prevent sq_thread from spinning when it should stop
+    - ata: ahci: Add shutdown to freeze hardware resources of ahci
+    - xen: Enable interrupts when calling _cond_resched()
+    - net/mlx5e: Reset RQ doorbell counter before moving RQ state from RST to RDY
+    - net/mlx5: Fix sleep while atomic in mlx5_eswitch_get_vepa
+    - net/mlx5e: Fix crash in recovery flow without devlink reporter
+    - s390/kaslr: Fix casts in get_random
+    - s390/mm: Explicitly compare PAGE_DEFAULT_KEY against zero in
+      storage_key_init_range
+    - bpf: Selftests build error in sockmap_basic.c
+    - ASoC: SOF: Intel: hda: Add iDisp4 DAI
+    - Linux 5.4.23
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/net -- disable timeout
+    - SAUCE: selftests/net -- disable l2tp.sh test
+    - SAUCE: selftests/ftrace: Use printf instead of echo in kprobe syntax error
+      tests
+    - SAUCE: selftests/powerpc -- Disable timeout for benchmark and tm tests
+    - SAUCE: selftests/ftrace: Escape additional strings in kprobe syntax error
+      tests
+    - SAUCE: Revert "UBUNTU: SAUCE: blk/core: Gracefully handle unset
+      make_request_fn"
+    - [Packaging] prevent duplicated entries in modules.ignore
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sat, 07 Mar 2020 10:23:40 -0600
+
+linux (5.4.0-17.21) focal; urgency=medium
+
+  * focal/linux: 5.4.0-17.20 -proposed tracker (LP: #1865025)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: drm/i915/execlists: fix off by one in execlists_update_context()
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Thu, 27 Feb 2020 14:29:02 +0100
+
+linux (5.4.0-16.19) focal; urgency=medium
+
+  * focal/linux: 5.4.0-16.19 -proposed tracker (LP: #1864889)
+
+  * system hang: i915 Resetting rcs0 for hang on rcs0 (LP: #1861395)
+    - drm/i915/execlists: Always force a context reload when rewinding RING_TAIL
+
+  * nsleep-lat / set-timer-lat / inconsistency-check / raw_skew from timer in
+    ubuntu_kernel_selftests timeout on 5.3 / 5.4 (LP: #1864626)
+    - selftests/timers: Turn off timeout setting
+
+  * [sfc-0121]enable the HiSilicon v3xx SFC driver (LP: #1860401)
+    - spi: Add HiSilicon v3xx SPI NOR flash controller driver
+    - MAINTAINERS: Add a maintainer for the HiSilicon v3xx SFC driver
+    - [Config] CONFIG_SPI_HISI_SFC_V3XX=m
+
+  * [hns3-0217]sync mainline kernel 5.6rc1 hns3 patchset into ubuntu HWE kernel
+    branch (LP: #1863575)
+    - net: hns3: add management table after IMP reset
+    - net: hns3: fix VF bandwidth does not take effect in some case
+    - net: hns3: fix a copying IPv6 address error in hclge_fd_get_flow_tuples()
+
+  * [hns3-0111]sync mainline kernel 5.5rc6 hns3 patchset into ubuntu HWE kernel
+    branch Edit (LP: #1859261)
+    - net: hns3: schedule hclgevf_service by using delayed workqueue
+    - net: hns3: remove mailbox and reset work in hclge_main
+    - net: hns3: remove unnecessary work in hclgevf_main
+    - net: hns3: allocate WQ with WQ_MEM_RECLAIM flag
+    - net: hns3: do not schedule the periodic task when reset fail
+    - net: hns3: check FE bit before calling hns3_add_frag()
+    - net: hns3: remove useless mutex vport_cfg_mutex in the struct hclge_dev
+    - net: hns3: optimization for CMDQ uninitialization
+    - net: hns3: get FD rules location before dump in debugfs
+    - net: hns3: implement ndo_features_check ops for hns3 driver
+    - net: hns3: add some VF VLAN information for command "ip link show"
+    - net: hns3: add a log for getting chain failure in
+      hns3_nic_uninit_vector_data()
+    - net: hns3: only print misc interrupt status when handling fails
+    - net: hns3: add trace event support for HNS3 driver
+    - net: hns3: re-organize vector handle
+    - net: hns3: modify the IRQ name of TQP vector
+    - net: hns3: modify an unsuitable log in hclge_map_ring_to_vector()
+    - net: hns3: modify the IRQ name of misc vectors
+    - net: hns3: add protection when get SFP speed as 0
+    - net: hns3: replace an unsuitable variable type in
+      hclge_inform_reset_assert_to_vf()
+    - net: hns3: modify an unsuitable reset level for hardware error
+    - net: hns3: split hclge_reset() into preparing and rebuilding part
+    - net: hns3: split hclgevf_reset() into preparing and rebuilding part
+    - net: hns3: refactor the precedure of PF FLR
+    - net: hns3: refactor the procedure of VF FLR
+    - net: hns3: enlarge HCLGE_RESET_WAIT_CNT
+    - net: hns3: modify hclge_func_reset_sync_vf()'s return type to void
+    - net: hns3: refactor the notification scheme of PF reset
+
+  * alsa/hda/realtek: fix a mute led regression on Lenovo X1 Carbon
+    (LP: #1864576)
+    - SAUCE: ALSA: hda/realtek - Fix a regression for mute led on Lenovo Carbon X1
+
+  * ipc/sem.c : process loops infinitely in exit_sem() (LP: #1858834)
+    - Revert "ipc, sem: remove uneeded sem_undo_list lock usage in exit_sem()"
+
+  * r8152 init may take up to 40 seconds at initialization with Dell WD19/WD19DC
+    during hotplug (LP: #1864284)
+    - UBUNTU SAUCE: r8151: check disconnect status after long sleep
+
+  * Update kernel options CONFIG_NR_CPUS and CONFIG_NUMA_EMU for focal
+    (LP: #1864198)
+    - Ubuntu: [Config] Update kernel options CONFIG_NR_CPUS and CONFIG_NUMA_EMU
+
+  * ftrace test in ubuntu_kernel_selftests will timeout randomly (LP: #1864172)
+    - tracing/selftests: Turn off timeout setting
+
+  * Another Dell AIO backlight issue (LP: #1863880)
+    - SAUCE: platform/x86: dell-uart-backlight: move retry block
+
+  * Backport GetFB2 ioctl (LP: #1863874)
+    - SAUCE: drm: Add getfb2 ioctl
+
+  * [20.04] Allow to reset an opencapi adapter (LP: #1862121)
+    - powerpc/powernv/ioda: Fix ref count for devices with their own PE
+    - powerpc/powernv/ioda: Protect PE list
+    - powerpc/powernv/ioda: set up PE on opencapi device when enabling
+    - powerpc/powernv/ioda: Release opencapi device
+    - powerpc/powernv/ioda: Find opencapi slot for a device node
+    - pci/hotplug/pnv-php: Remove erroneous warning
+    - pci/hotplug/pnv-php: Improve error msg on power state change failure
+    - pci/hotplug/pnv-php: Register opencapi slots
+    - pci/hotplug/pnv-php: Relax check when disabling slot
+    - pci/hotplug/pnv-php: Wrap warnings in macro
+    - ocxl: Add PCI hotplug dependency to Kconfig
+
+  * alsa/asoc: export the number of dmic to userspace to work with the latest
+    ucm2 (focal) (LP: #1864400)
+    - ASoC: add control components management
+    - ASoC: intel/skl/hda - export number of digital microphones via control
+      components
+
+  * alsa/sof: let sof driver work with topology with volume and led control
+    (focal) (LP: #1864398)
+    - ASoC: SOF: enable dual control for pga
+    - AsoC: SOF: refactor control load code
+    - ASoC: SOF: acpi led support for switch controls
+    - ASoC: SOF: topology: check errors when parsing LED tokens
+
+  * machine doesn't come up after suspend and re-opening the lid (LP: #1861837)
+    - ASoC: SOF: trace: fix unconditional free in trace release
+
+  * 5.3.0-23-generic causes fans to spin when idle (LP: #1853044)
+    - drm/i915/gt: Close race between engine_park and intel_gt_retire_requests
+    - drm/i915/gt: Adapt engine_park synchronisation rules for engine_retire
+    - drm/i915/gt: Schedule request retirement when timeline idles
+
+  * Focal update: 5.4.22 upstream stable release (LP: #1864488)
+    - core: Don't skip generic XDP program execution for cloned SKBs
+    - enic: prevent waking up stopped tx queues over watchdog reset
+    - net/smc: fix leak of kernel memory to user space
+    - net: dsa: tag_qca: Make sure there is headroom for tag
+    - net/sched: matchall: add missing validation of TCA_MATCHALL_FLAGS
+    - net/sched: flower: add missing validation of TCA_FLOWER_FLAGS
+    - drm/gma500: Fixup fbdev stolen size usage evaluation
+    - ath10k: Fix qmi init error handling
+    - wil6210: fix break that is never reached because of zero'ing of a retry
+      counter
+    - drm/qxl: Complete exception handling in qxl_device_init()
+    - rcu/nocb: Fix dump_tree hierarchy print always active
+    - rcu: Fix missed wakeup of exp_wq waiters
+    - rcu: Fix data-race due to atomic_t copy-by-value
+    - f2fs: preallocate DIO blocks when forcing buffered_io
+    - f2fs: call f2fs_balance_fs outside of locked page
+    - media: meson: add missing allocation failure check on new_buf
+    - clk: meson: pll: Fix by 0 division in __pll_params_to_rate()
+    - cpu/hotplug, stop_machine: Fix stop_machine vs hotplug order
+    - brcmfmac: Fix memory leak in brcmf_p2p_create_p2pdev()
+    - brcmfmac: Fix use after free in brcmf_sdio_readframes()
+    - PCI: Fix pci_add_dma_alias() bitmask size
+    - drm/amd/display: Map ODM memory correctly when doing ODM combine
+    - leds: pca963x: Fix open-drain initialization
+    - ext4: fix ext4_dax_read/write inode locking sequence for IOCB_NOWAIT
+    - ALSA: ctl: allow TLV read operation for callback type of element in locked
+      case
+    - gianfar: Fix TX timestamping with a stacked DSA driver
+    - pinctrl: sh-pfc: sh7264: Fix CAN function GPIOs
+    - printk: fix exclusive_console replaying
+    - drm/mipi_dbi: Fix off-by-one bugs in mipi_dbi_blank()
+    - drm/msm/adreno: fix zap vs no-zap handling
+    - pxa168fb: Fix the function used to release some memory in an error handling
+      path
+    - media: ov5640: Fix check for PLL1 exceeding max allowed rate
+    - media: i2c: mt9v032: fix enum mbus codes and frame sizes
+    - media: sun4i-csi: Deal with DRAM offset
+    - media: sun4i-csi: Fix data sampling polarity handling
+    - media: sun4i-csi: Fix [HV]sync polarity handling
+    - clk: at91: sam9x60: fix programmable clock prescaler
+    - powerpc/powernv/iov: Ensure the pdn for VFs always contains a valid PE
+      number
+    - clk: meson: meson8b: make the CCF use the glitch-free mali mux
+    - gpio: gpio-grgpio: fix possible sleep-in-atomic-context bugs in
+      grgpio_irq_map/unmap()
+    - iommu/vt-d: Fix off-by-one in PASID allocation
+    - x86/fpu: Deactivate FPU state after failure during state load
+    - char/random: silence a lockdep splat with printk()
+    - media: sti: bdisp: fix a possible sleep-in-atomic-context bug in
+      bdisp_device_run()
+    - kernel/module: Fix memleak in module_add_modinfo_attrs()
+    - IB/core: Let IB core distribute cache update events
+    - pinctrl: baytrail: Do not clear IRQ flags on direct-irq enabled pins
+    - efi/x86: Map the entire EFI vendor string before copying it
+    - MIPS: Loongson: Fix potential NULL dereference in loongson3_platform_init()
+    - sparc: Add .exit.data section.
+    - net: ethernet: ixp4xx: Standard module init
+    - raid6/test: fix a compilation error
+    - uio: fix a sleep-in-atomic-context bug in uio_dmem_genirq_irqcontrol()
+    - drm/amdgpu/sriov: workaround on rev_id for Navi12 under sriov
+    - spi: fsl-lpspi: fix only one cs-gpio working
+    - drm/nouveau/nouveau: fix incorrect sizeof on args.src an args.dst
+    - usb: gadget: udc: fix possible sleep-in-atomic-context bugs in gr_probe()
+    - usb: dwc2: Fix IN FIFO allocation
+    - clocksource/drivers/bcm2835_timer: Fix memory leak of timer
+    - drm/amd/display: Clear state after exiting fixed active VRR state
+    - kselftest: Minimise dependency of get_size on C library interfaces
+    - jbd2: clear JBD2_ABORT flag before journal_reset to update log tail info
+      when load journal
+    - ext4: fix deadlock allocating bio_post_read_ctx from mempool
+    - clk: ti: dra7: fix parent for gmac_clkctrl
+    - x86/sysfb: Fix check for bad VRAM size
+    - pwm: omap-dmtimer: Simplify error handling
+    - udf: Allow writing to 'Rewritable' partitions
+    - dmaengine: fsl-qdma: fix duplicated argument to &&
+    - wan/hdlc_x25: fix skb handling
+    - powerpc/iov: Move VF pdev fixup into pcibios_fixup_iov()
+    - tracing: Fix tracing_stat return values in error handling paths
+    - tracing: Fix very unlikely race of registering two stat tracers
+    - ARM: 8952/1: Disable kmemleak on XIP kernels
+    - ext4, jbd2: ensure panic when aborting with zero errno
+    - ath10k: Correct the DMA direction for management tx buffers
+    - rtw88: fix rate mask for 1SS chip
+    - brcmfmac: sdio: Fix OOB interrupt initialization on brcm43362
+    - selftests: settings: tests can be in subsubdirs
+    - rtc: i2c/spi: Avoid inclusion of REGMAP support when not needed
+    - drm/amd/display: Retrain dongles when SINK_COUNT becomes non-zero
+    - tracing: Simplify assignment parsing for hist triggers
+    - nbd: add a flush_workqueue in nbd_start_device
+    - KVM: s390: ENOTSUPP -> EOPNOTSUPP fixups
+    - Btrfs: keep pages dirty when using btrfs_writepage_fixup_worker
+    - drivers/block/zram/zram_drv.c: fix error return codes not being returned in
+      writeback_store
+    - block, bfq: do not plug I/O for bfq_queues with no proc refs
+    - kconfig: fix broken dependency in randconfig-generated .config
+    - clk: qcom: Don't overwrite 'cfg' in clk_rcg2_dfs_populate_freq()
+    - clk: qcom: rcg2: Don't crash if our parent can't be found; return an error
+    - drm/amdkfd: Fix a bug in SDMA RLC queue counting under HWS mode
+    - bpf, sockhash: Synchronize_rcu before free'ing map
+    - drm/amdgpu: remove 4 set but not used variable in
+      amdgpu_atombios_get_connector_info_from_object_table
+    - ath10k: correct the tlv len of ath10k_wmi_tlv_op_gen_config_pno_start
+    - drm/amdgpu: Ensure ret is always initialized when using SOC15_WAIT_ON_RREG
+    - drm/panel: simple: Add Logic PD Type 28 display support
+    - arm64: dts: rockchip: Fix NanoPC-T4 cooling maps
+    - modules: lockdep: Suppress suspicious RCU usage warning
+    - ASoC: intel: sof_rt5682: Add quirk for number of HDMI DAI's
+    - ASoC: intel: sof_rt5682: Add support for tgl-max98357a-rt5682
+    - regulator: rk808: Lower log level on optional GPIOs being not available
+    - net/wan/fsl_ucc_hdlc: reject muram offsets above 64K
+    - NFC: port100: Convert cpu_to_le16(le16_to_cpu(E1) + E2) to use
+      le16_add_cpu().
+    - arm64: dts: allwinner: H6: Add PMU mode
+    - arm64: dts: allwinner: H5: Add PMU node
+    - arm: dts: allwinner: H3: Add PMU node
+    - opp: Free static OPPs on errors while adding them
+    - selinux: ensure we cleanup the internal AVC counters on error in
+      avc_insert()
+    - arm64: dts: qcom: msm8996: Disable USB2 PHY suspend by core
+    - padata: validate cpumask without removed CPU during offline
+    - clk: imx: Add correct failure handling for clk based helpers
+    - ARM: exynos_defconfig: Bring back explicitly wanted options
+    - ARM: dts: imx6: rdu2: Disable WP for USDHC2 and USDHC3
+    - ARM: dts: imx6: rdu2: Limit USBH1 to Full Speed
+    - bus: ti-sysc: Implement quirk handling for CLKDM_NOAUTO
+    - PCI: iproc: Apply quirk_paxc_bridge() for module as well as built-in
+    - media: cx23885: Add support for AVerMedia CE310B
+    - PCI: Add generic quirk for increasing D3hot delay
+    - PCI: Increase D3 delay for AMD Ryzen5/7 XHCI controllers
+    - gpu/drm: ingenic: Avoid null pointer deference in plane atomic update
+    - selftests/net: make so_txtime more robust to timer variance
+    - media: v4l2-device.h: Explicitly compare grp{id,mask} to zero in v4l2_device
+      macros
+    - reiserfs: Fix spurious unlock in reiserfs_fill_super() error handling
+    - samples/bpf: Set -fno-stack-protector when building BPF programs
+    - r8169: check that Realtek PHY driver module is loaded
+    - fore200e: Fix incorrect checks of NULL pointer dereference
+    - netfilter: nft_tunnel: add the missing ERSPAN_VERSION nla_policy
+    - ALSA: usx2y: Adjust indentation in snd_usX2Y_hwdep_dsp_status
+    - PCI: Add nr_devfns parameter to pci_add_dma_alias()
+    - PCI: Add DMA alias quirk for PLX PEX NTB
+    - 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
+    - drm/amdgpu: fix KIQ ring test fail in TDR of SRIOV
+    - clk: qcom: smd: Add missing bimc clock
+    - ACPICA: Disassembler: create buffer fields in ACPI_PARSE_LOAD_PASS1
+    - nfsd: Clone should commit src file metadata too
+    - scsi: ufs: Complete pending requests in host reset and restore path
+    - scsi: aic7xxx: Adjust indentation in ahc_find_syncrate
+    - crypto: inside-secure - add unspecified HAS_IOMEM dependency
+    - drm/mediatek: handle events when enabling/disabling crtc
+    - clk: renesas: rcar-gen3: Allow changing the RPC[D2] clocks
+    - ARM: dts: r8a7779: Add device node for ARM global timer
+    - selinux: ensure we cleanup the internal AVC counters on error in
+      avc_update()
+    - scsi: lpfc: Fix: Rework setting of fdmi symbolic node name registration
+    - arm64: dts: qcom: db845c: Enable ath10k 8bit host-cap quirk
+    - iommu/amd: Check feature support bit before accessing MSI capability
+      registers
+    - iommu/amd: Only support x2APIC with IVHD type 11h/40h
+    - iommu/iova: Silence warnings under memory pressure
+    - clk: actually call the clock init before any other callback of the clock
+    - dmaengine: Store module owner in dma_device struct
+    - dmaengine: imx-sdma: Fix memory leak
+    - bpf: Print error message for bpftool cgroup show
+    - net: phy: realtek: add logging for the RGMII TX delay configuration
+    - crypto: chtls - Fixed memory leak
+    - x86/vdso: Provide missing include file
+    - PM / devfreq: exynos-ppmu: Fix excessive stack usage
+    - PM / devfreq: rk3399_dmc: Add COMPILE_TEST and HAVE_ARM_SMCCC dependency
+    - drm/fbdev: Fallback to non tiled mode if all tiles not present
+    - pinctrl: sh-pfc: sh7269: Fix CAN function GPIOs
+    - reset: uniphier: Add SCSSI reset control for each channel
+    - ASoC: soc-topology: fix endianness issues
+    - fbdev: fix numbering of fbcon options
+    - RDMA/rxe: Fix error type of mmap_offset
+    - clk: sunxi-ng: add mux and pll notifiers for A64 CPU clock
+    - ALSA: sh: Fix unused variable warnings
+    - clk: Use parent node pointer during registration if necessary
+    - clk: uniphier: Add SCSSI clock gate for each channel
+    - ALSA: hda/realtek - Apply mic mute LED quirk for Dell E7xx laptops, too
+    - ALSA: sh: Fix compile warning wrt const
+    - net: phy: fixed_phy: fix use-after-free when checking link GPIO
+    - tools lib api fs: Fix gcc9 stringop-truncation compilation error
+    - vfio/spapr/nvlink2: Skip unpinning pages on error exit
+    - ASoC: Intel: sof_rt5682: Ignore the speaker amp when there isn't one.
+    - ACPI: button: Add DMI quirk for Razer Blade Stealth 13 late 2019 lid switch
+    - iommu/vt-d: Match CPU and IOMMU paging mode
+    - iommu/vt-d: Avoid sending invalid page response
+    - drm/amdkfd: Fix permissions of hang_hws
+    - mlx5: work around high stack usage with gcc
+    - RDMA/hns: Avoid printing address of mtt page
+    - drm: remove the newline for CRC source name.
+    - usb: dwc3: use proper initializers for property entries
+    - ARM: dts: stm32: Add power-supply for DSI panel on stm32f469-disco
+    - usbip: Fix unsafe unaligned pointer usage
+    - udf: Fix free space reporting for metadata and virtual partitions
+    - drm/mediatek: Add gamma property according to hardware capability
+    - staging: rtl8188: avoid excessive stack usage
+    - IB/hfi1: Add software counter for ctxt0 seq drop
+    - IB/hfi1: Add RcvShortLengthErrCnt to hfi1stats
+    - soc/tegra: fuse: Correct straps' address for older Tegra124 device trees
+    - efi/x86: Don't panic or BUG() on non-critical error conditions
+    - rcu: Use WRITE_ONCE() for assignments to ->pprev for hlist_nulls
+    - Input: edt-ft5x06 - work around first register access error
+    - bnxt: Detach page from page pool before sending up the stack
+    - x86/nmi: Remove irq_work from the long duration NMI handler
+    - wan: ixp4xx_hss: fix compile-testing on 64-bit
+    - clocksource: davinci: only enable clockevents once tim34 is initialized
+    - arm64: dts: rockchip: fix dwmmc clock name for px30
+    - arm64: dts: rockchip: add reg property to brcmf sub-nodes
+    - ARM: dts: rockchip: add reg property to brcmf sub node for
+      rk3188-bqedison2qc
+    - ALSA: usb-audio: Add boot quirk for MOTU M Series
+    - ASoC: atmel: fix build error with CONFIG_SND_ATMEL_SOC_DMA=m
+    - raid6/test: fix a compilation warning
+    - tty: synclinkmp: Adjust indentation in several functions
+    - tty: synclink_gt: Adjust indentation in several functions
+    - misc: xilinx_sdfec: fix xsdfec_poll()'s return type
+    - visorbus: fix uninitialized variable access
+    - driver core: platform: Prevent resouce overflow from causing infinite loops
+    - driver core: Print device when resources present in really_probe()
+    - ASoC: SOF: Intel: hda-dai: fix compilation warning in pcm_prepare
+    - bpf: Return -EBADRQC for invalid map type in __bpf_tx_xdp_map
+    - vme: bridges: reduce stack usage
+    - drm/nouveau/secboot/gm20b: initialize pointer in gm20b_secboot_new()
+    - drm/nouveau/gr/gk20a,gm200-: add terminators to method lists read from fw
+    - drm/nouveau: Fix copy-paste error in nouveau_fence_wait_uevent_handler
+    - drm/nouveau/drm/ttm: Remove set but not used variable 'mem'
+    - drm/nouveau/fault/gv100-: fix memory leak on module unload
+    - dm thin: don't allow changing data device during thin-pool reload
+    - gpiolib: Set lockdep class for hierarchical irq domains
+    - drm/vmwgfx: prevent memory leak in vmw_cmdbuf_res_add
+    - perf/imx_ddr: Fix cpu hotplug state cleanup
+    - usb: musb: omap2430: Get rid of musb .set_vbus for omap2430 glue
+    - kbuild: remove *.tmp file when filechk fails
+    - iommu/arm-smmu-v3: Use WRITE_ONCE() when changing validity of an STE
+    - ALSA: usb-audio: unlock on error in probe
+    - f2fs: set I_LINKABLE early to avoid wrong access by vfs
+    - f2fs: free sysfs kobject
+    - scsi: ufs: pass device information to apply_dev_quirks
+    - scsi: ufs-mediatek: add apply_dev_quirks variant operation
+    - scsi: iscsi: Don't destroy session if there are outstanding connections
+    - crypto: essiv - fix AEAD capitalization and preposition use in help text
+    - ALSA: usb-audio: add implicit fb quirk for MOTU M Series
+    - RDMA/mlx5: Don't fake udata for kernel path
+    - arm64: lse: fix LSE atomics with LLVM's integrated assembler
+    - arm64: fix alternatives with LLVM's integrated assembler
+    - drm/amd/display: fixup DML dependencies
+    - EDAC/sifive: Fix return value check in ecc_register()
+    - KVM: PPC: Remove set but not used variable 'ra', 'rs', 'rt'
+    - arm64: dts: ti: k3-j721e-main: Add missing power-domains for smmu
+    - sched/core: Fix size of rq::uclamp initialization
+    - sched/topology: Assert non-NUMA topology masks don't (partially) overlap
+    - perf/x86/amd: Constrain Large Increment per Cycle events
+    - watchdog/softlockup: Enforce that timestamp is valid on boot
+    - debugobjects: Fix various data races
+    - ASoC: SOF: Intel: hda: Fix SKL dai count
+    - regulator: vctrl-regulator: Avoid deadlock getting and setting the voltage
+    - f2fs: fix memleak of kobject
+    - x86/mm: Fix NX bit clearing issue in kernel_map_pages_in_pgd
+    - pwm: omap-dmtimer: Remove PWM chip in .remove before making it unfunctional
+    - cmd64x: potential buffer overflow in cmd64x_program_timings()
+    - ide: serverworks: potential overflow in svwks_set_pio_mode()
+    - pwm: Remove set but not set variable 'pwm'
+    - btrfs: fix possible NULL-pointer dereference in integrity checks
+    - btrfs: safely advance counter when looking up bio csums
+    - btrfs: device stats, log when stats are zeroed
+    - module: avoid setting info->name early in case we can fall back to
+      info->mod->name
+    - remoteproc: Initialize rproc_class before use
+    - regulator: core: Fix exported symbols to the exported GPL version
+    - irqchip/mbigen: Set driver .suppress_bind_attrs to avoid remove problems
+    - ALSA: hda/hdmi - add retry logic to parse_intel_hdmi()
+    - spi: spi-fsl-qspi: Ensure width is respected in spi-mem operations
+    - kbuild: use -S instead of -E for precise cc-option test in Kconfig
+    - objtool: Fix ARCH=x86_64 build error
+    - x86/decoder: Add TEST opcode to Group3-2
+    - s390: adjust -mpacked-stack support check for clang 10
+    - s390/ftrace: generate traced function stack frame
+    - driver core: platform: fix u32 greater or equal to zero comparison
+    - bpf, btf: Always output invariant hit in pahole DWARF to BTF transform
+    - ALSA: hda - Add docking station support for Lenovo Thinkpad T420s
+    - sunrpc: Fix potential leaks in sunrpc_cache_unhash()
+    - drm/nouveau/mmu: fix comptag memory leak
+    - powerpc/sriov: Remove VF eeh_dev state when disabling SR-IOV
+    - media: uvcvideo: Add a quirk to force GEO GC6500 Camera bits-per-pixel value
+    - btrfs: separate definition of assertion failure handlers
+    - btrfs: Fix split-brain handling when changing FSID to metadata uuid
+    - bcache: cached_dev_free needs to put the sb page
+    - bcache: rework error unwinding in register_bcache
+    - bcache: fix use-after-free in register_bcache()
+    - iommu/vt-d: Remove unnecessary WARN_ON_ONCE()
+    - alarmtimer: Make alarmtimer platform device child of RTC device
+    - selftests: bpf: Reset global state between reuseport test runs
+    - jbd2: switch to use jbd2_journal_abort() when failed to submit the commit
+      record
+    - jbd2: make sure ESHUTDOWN to be recorded in the journal superblock
+    - powerpc/pseries/lparcfg: Fix display of Maximum Memory
+    - selftests/eeh: Bump EEH wait time to 60s
+    - ARM: 8951/1: Fix Kexec compilation issue.
+    - ALSA: usb-audio: add quirks for Line6 Helix devices fw>=2.82
+    - hostap: Adjust indentation in prism2_hostapd_add_sta
+    - rtw88: fix potential NULL skb access in TX ISR
+    - iwlegacy: ensure loop counter addr does not wrap and cause an infinite loop
+    - cifs: fix unitialized variable poential problem with network I/O cache lock
+      patch
+    - cifs: Fix mount options set in automount
+    - cifs: fix NULL dereference in match_prepath
+    - bpf: map_seq_next should always increase position index
+    - powerpc/mm: Don't log user reads to 0xffffffff
+    - ceph: check availability of mds cluster on mount after wait timeout
+    - rbd: work around -Wuninitialized warning
+    - drm/amd/display: do not allocate display_mode_lib unnecessarily
+    - irqchip/gic-v3: Only provision redistributors that are enabled in ACPI
+    - drm/nouveau/disp/nv50-: prevent oops when no channel method map provided
+    - char: hpet: Fix out-of-bounds read bug
+    - ftrace: fpid_next() should increase position index
+    - trigger_next should increase position index
+    - radeon: insert 10ms sleep in dce5_crtc_load_lut
+    - powerpc: Do not consider weak unresolved symbol relocations as bad
+    - btrfs: do not do delalloc reservation under page lock
+    - ocfs2: make local header paths relative to C files
+    - 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: fix memory corruption in bch_cache_accounting_clear()
+    - bcache: explicity type cast in bset_bkey_last()
+    - bcache: fix incorrect data type usage in btree_flush_write()
+    - irqchip/gic-v3-its: Reference to its_invall_cmd descriptor when building
+      INVALL
+    - nvmet: Pass lockdep expression to RCU lists
+    - nvme-pci: remove nvmeq->tags
+    - iwlwifi: mvm: Fix thermal zone registration
+    - iwlwifi: mvm: Check the sta is not NULL in iwl_mvm_cfg_he_sta()
+    - asm-generic/tlb: add missing CONFIG symbol
+    - microblaze: Prevent the overflow of the start
+    - brd: check and limit max_part par
+    - drm/amdgpu/smu10: fix smu10_get_clock_by_type_with_latency
+    - drm/amdgpu/smu10: fix smu10_get_clock_by_type_with_voltage
+    - NFS: Fix memory leaks
+    - help_next should increase position index
+    - i40e: Relax i40e_xsk_wakeup's return value when PF is busy
+    - cifs: log warning message (once) if out of disk space
+    - virtio_balloon: prevent pfn array overflow
+    - fuse: don't overflow LLONG_MAX with end offset
+    - mlxsw: spectrum_dpipe: Add missing error path
+    - drm/amdgpu/display: handle multiple numbers of fclks in dcn_calcs.c (v2)
+    - bcache: properly initialize 'path' and 'err' in register_bcache()
+    - rtc: Kconfig: select REGMAP_I2C when necessary
+    - Linux 5.4.22
+
+  * Focal update: 5.4.22 upstream stable release (LP: #1864488) //
+    CVE-2019-19076.
+    - Revert "nfp: abm: fix memory leak in nfp_abm_u32_knode_replace"
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Revert "UBUNTU: [Debian] Update linux source package name in
+      debian/tests/*"
+    - SAUCE: selftests: fix undefined lable cleanup build error
+    - SAUCE: selftests: fix undefined macro RET_IF() build error
+    - [Packaging] Include modules.builtin.modinfo in linux-modules
+    - update dkms package versions
+    - Revert "UBUNTU: [Debian] Update package name in getabis repo list"
+
+  * Miscellaneous upstream changes
+    - libbpf: Extract and generalize CPU mask parsing logic
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 26 Feb 2020 12:22:51 -0600
+
+linux (5.4.0-15.18) focal; urgency=medium
+
+  * focal/linux: 5.4.0-15.18 -proposed tracker (LP: #1864085)
+
+  * Focal update: v5.4.21 upstream stable release (LP: #1864046)
+    - Input: synaptics - switch T470s to RMI4 by default
+    - Input: synaptics - enable SMBus on ThinkPad L470
+    - Input: synaptics - remove the LEN0049 dmi id from topbuttonpad list
+    - ALSA: usb-audio: Fix UAC2/3 effect unit parsing
+    - ALSA: hda/realtek - Add more codec supported Headset Button
+    - ALSA: hda/realtek - Fix silent output on MSI-GL73
+    - ALSA: usb-audio: Apply sample rate quirk for Audioengine D1
+    - ACPI: EC: Fix flushing of pending work
+    - ACPI: PM: s2idle: Avoid possible race related to the EC GPE
+    - ACPICA: Introduce acpi_any_gpe_status_set()
+    - ACPI: PM: s2idle: Prevent spurious SCIs from waking up the system
+    - ALSA: usb-audio: sound: usb: usb true/false for bool return type
+    - ALSA: usb-audio: Add clock validity quirk for Denon MC7000/MCX8000
+    - ext4: don't assume that mmp_nodename/bdevname have NUL
+    - ext4: fix support for inode sizes > 1024 bytes
+    - ext4: fix checksum errors with indexed dirs
+    - ext4: add cond_resched() to ext4_protect_reserved_inode
+    - ext4: improve explanation of a mount failure caused by a misconfigured
+      kernel
+    - Btrfs: fix race between using extent maps and merging them
+    - btrfs: ref-verify: fix memory leaks
+    - btrfs: print message when tree-log replay starts
+    - btrfs: log message when rw remount is attempted with unclean tree-log
+    - ARM: npcm: Bring back GPIOLIB support
+    - gpio: xilinx: Fix bug where the wrong GPIO register is written to
+    - arm64: ssbs: Fix context-switch when SSBS is present on all CPUs
+    - xprtrdma: Fix DMA scatter-gather list mapping imbalance
+    - cifs: make sure we do not overflow the max EA buffer size
+    - EDAC/sysfs: Remove csrow objects on errors
+    - EDAC/mc: Fix use-after-free and memleaks during device removal
+    - KVM: nVMX: Use correct root level for nested EPT shadow page tables
+    - perf/x86/amd: Add missing L2 misses event spec to AMD Family 17h's event map
+    - s390/pkey: fix missing length of protected key on return
+    - s390/uv: Fix handling of length extensions
+    - drm/vgem: Close use-after-free race in vgem_gem_create
+    - drm/panfrost: Make sure the shrinker does not reclaim referenced BOs
+    - bus: moxtet: fix potential stack buffer overflow
+    - nvme: fix the parameter order for nvme_get_log in nvme_get_fw_slot_info
+    - drivers: ipmi: fix off-by-one bounds check that leads to a out-of-bounds
+      write
+    - IB/mlx5: Return failure when rts2rts_qp_counters_set_id is not supported
+    - IB/hfi1: Acquire lock to release TID entries when user file is closed
+    - IB/hfi1: Close window for pq and request coliding
+    - IB/rdmavt: Reset all QPs when the device is shut down
+    - IB/umad: Fix kernel crash while unloading ib_umad
+    - RDMA/core: Fix invalid memory access in spec_filter_size
+    - RDMA/iw_cxgb4: initiate CLOSE when entering TERM
+    - RDMA/hfi1: Fix memory leak in _dev_comp_vect_mappings_create
+    - RDMA/rxe: Fix soft lockup problem due to using tasklets in softirq
+    - RDMA/core: Fix protection fault in get_pkey_idx_qp_list
+    - s390/time: Fix clk type in get_tod_clock
+    - sched/uclamp: Reject negative values in cpu_uclamp_write()
+    - spmi: pmic-arb: Set lockdep class for hierarchical irq domains
+    - perf/x86/intel: Fix inaccurate period in context switch for auto-reload
+    - hwmon: (pmbus/ltc2978) Fix PMBus polling of MFR_COMMON definitions.
+    - mac80211: fix quiet mode activation in action frames
+    - cifs: fix mount option display for sec=krb5i
+    - arm64: dts: fast models: Fix FVP PCI interrupt-map property
+    - KVM: x86: Mask off reserved bit from #DB exception payload
+    - perf stat: Don't report a null stalled cycles per insn metric
+    - NFSv4.1 make cachethis=no for writes
+    - Revert "drm/sun4i: drv: Allow framebuffer modifiers in mode config"
+    - 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
+    - ext4: choose hardlimit when softlimit is larger than hardlimit in
+      ext4_statfs_project()
+    - KVM: x86/mmu: Fix struct guest_walker arrays for 5-level paging
+    - gpio: add gpiod_toggle_active_low()
+    - mmc: core: Rework wp-gpio handling
+    - Linux 5.4.21
+
+  * Fix AMD Stoney Ridge screen flickering under 4K resolution (LP: #1864005)
+    - iommu/amd: Disable IOMMU on Stoney Ridge systems
+
+  * Focal Fossa (20.04) feature request - Enable CONFIG_X86_UV (LP: #1863810)
+    - [Config] CONFIG_X86_UV=y
+
+  * [UBUNTU 20.04] Enable proper reset/recovery of s390x/pci functions in error
+    state (LP: #1863768)
+    - s390/pci: Recover handle in clp_set_pci_fn()
+    - s390/pci: Fix possible deadlock in recover_store()
+
+  * [20.04 FEAT] Enhanced handling of secure keys and protected keys
+    (LP: #1853303)
+    - s390/zcrypt: enable card/domain autoselect on ep11 cprbs
+    - s390/zcrypt: ep11 structs rework, export zcrypt_send_ep11_cprb
+    - s390/zcrypt: add new low level ep11 functions support file
+    - s390/zcrypt: extend EP11 card and queue sysfs attributes
+    - s390/pkey/zcrypt: Support EP11 AES secure keys
+
+  * [20.04 FEAT] paes self test (LP: #1854948)
+    - s390/pkey: use memdup_user() to simplify code
+    - s390/pkey: Add support for key blob with clear key value
+    - s390/crypto: Rework on paes implementation
+    - s390/crypto: enable clear key values for paes ciphers
+    - crypto/testmgr: enable selftests for paes-s390 ciphers
+
+  * Sometimes can't adjust brightness on Dell AIO (LP: #1862885)
+    - SAUCE: platform/x86: dell-uart-backlight: increase retry times
+
+  * change the ASoC card name and card longname to meet the requirement of alsa-
+    lib-1.2.1 (Focal) (LP: #1862712)
+    - ASoC: improve the DMI long card code in asoc-core
+    - ASoC: DMI long name - avoid to add board name if matches with product name
+    - ASoC: intel - fix the card names
+
+  * Support Headset Mic on HP cPC (LP: #1862313)
+    - ALSA: hda/realtek - Add Headset Mic supported for HP cPC
+    - ALSA: hda/realtek - Fixed one of HP ALC671 platform Headset Mic supported
+
+  * [hns3-0205]sync mainline kernel 5.5rc7 hns3 patchset into ubuntu HWE kernel
+    branch (LP: #1861972)
+    - net: hns3: replace snprintf with scnprintf in hns3_dbg_cmd_read
+    - net: hns3: replace snprintf with scnprintf in hns3_update_strings
+    - net: hns3: limit the error logging in the hns3_clean_tx_ring()
+    - net: hns3: do not reuse pfmemalloc pages
+    - net: hns3: set VF's default reset_type to HNAE3_NONE_RESET
+    - net: hns3: move duplicated macro definition into header
+    - net: hns3: refine the input parameter 'size' for snprintf()
+    - net: hns3: rewrite a log in hclge_put_vector()
+    - net: hns3: delete unnecessary blank line and space for cleanup
+    - net: hns3: remove redundant print on ENOMEM
+
+  * [acc-0205]sync mainline kernel 5.5rc6 acc patchset into ubuntu HWE kernel
+    branch (LP: #1861976)
+    - crypto: hisilicon/sec2 - Use atomics instead of __sync
+    - crypto: hisilicon - still no need to check return value of debugfs_create
+      functions
+    - crypto: hisilicon - Update debugfs usage of SEC V2
+    - crypto: hisilicon - fix print/comment of SEC V2
+    - crypto: hisilicon - Update some names on SEC V2
+    - crypto: hisilicon - Update QP resources of SEC V2
+    - crypto: hisilicon - Adjust some inner logic
+    - crypto: hisilicon - Add callback error check
+    - crypto: hisilicon - Add branch prediction macro
+    - crypto: hisilicon - redefine skcipher initiation
+    - crypto: hisilicon - Add aead support on SEC2
+    - crypto: hisilicon - Bugfixed tfm leak
+    - crypto: hisilicon - Fixed some tiny bugs of HPRE
+    - crypto: hisilicon - adjust hpre_crt_para_get
+    - crypto: hisilicon - add branch prediction macro
+    - crypto: hisilicon - fix spelling mistake "disgest" -> "digest"
+
+  * [spi-0115]spi: dw: use "smp_mb()" to avoid sending spi data error
+    (LP: #1859744)
+    - spi: dw: use "smp_mb()" to avoid sending spi data error
+
+  * [tpm-0115]EFI/stub: tpm: enable tpm eventlog function for ARM64 platform
+    (LP: #1859743)
+    - efi: libstub/tpm: enable tpm eventlog function for ARM platforms
+
+  * Restrict xmon to read-only-mode if kernel is locked down (LP: #1863562)
+    - powerpc/xmon: Restrict when kernel is locked down
+
+  * [CML-H] Add intel_thermal_pch driver support Comet Lake -H (LP: #1853219)
+    - thermal: intel: intel_pch_thermal: Add Comet Lake (CML) platform support
+
+  * Root can lift kernel lockdown via USB/IP (LP: #1861238)
+    - Revert "UBUNTU: SAUCE: (lockdown) Add a SysRq option to lift kernel
+      lockdown"
+
+  * Dell XPS 13 (7390) Display Flickering - 19.10  (LP: #1849947)
+    - SAUCE: drm/i915: Disable PSR by default on all platforms
+
+  * Focal update: v5.4.20 upstream stable release (LP: #1863589)
+    - ASoC: pcm: update FE/BE trigger order based on the command
+    - hv_sock: Remove the accept port restriction
+    - IB/mlx4: Fix memory leak in add_gid error flow
+    - IB/srp: Never use immediate data if it is disabled by a user
+    - IB/mlx4: Fix leak in id_map_find_del
+    - RDMA/netlink: Do not always generate an ACK for some netlink operations
+    - RDMA/i40iw: fix a potential NULL pointer dereference
+    - RDMA/core: Fix locking in ib_uverbs_event_read
+    - RDMA/uverbs: Verify MR access flags
+    - RDMA/cma: Fix unbalanced cm_id reference count during address resolve
+    - RDMA/umem: Fix ib_umem_find_best_pgsz()
+    - scsi: ufs: Fix ufshcd_probe_hba() reture value in case
+      ufshcd_scsi_add_wlus() fails
+    - PCI/IOV: Fix memory leak in pci_iov_add_virtfn()
+    - ath10k: pci: Only dump ATH10K_MEM_REGION_TYPE_IOREG when safe
+    - PCI/switchtec: Use dma_set_mask_and_coherent()
+    - PCI/switchtec: Fix vep_vector_number ioread width
+    - PCI: tegra: Fix afi_pex2_ctrl reg offset for Tegra30
+    - PCI: Don't disable bridge BARs when assigning bus resources
+    - PCI/AER: Initialize aer_fifo
+    - iwlwifi: mvm: avoid use after free for pmsr request
+    - bpftool: Don't crash on missing xlated program instructions
+    - bpf, sockmap: Don't sleep while holding RCU lock on tear-down
+    - bpf, sockhash: Synchronize_rcu before free'ing map
+    - selftests/bpf: Test freeing sockmap/sockhash with a socket in it
+    - bpf: Improve bucket_log calculation logic
+    - bpf, sockmap: Check update requirements after locking
+    - nfs: NFS_SWAP should depend on SWAP
+    - NFS: Revalidate the file size on a fatal write error
+    - NFS/pnfs: Fix pnfs_generic_prepare_to_resend_writes()
+    - NFS: Fix fix of show_nfs_errors
+    - NFSv4: pnfs_roc() must use cred_fscmp() to compare creds
+    - NFSv4: try lease recovery on NFS4ERR_EXPIRED
+    - NFSv4.0: nfs4_do_fsinfo() should not do implicit lease renewals
+    - x86/boot: Handle malformed SRAT tables during early ACPI parsing
+    - rtc: hym8563: Return -EINVAL if the time is known to be invalid
+    - rtc: cmos: Stop using shared IRQ
+    - watchdog: qcom: Use platform_get_irq_optional() for bark irq
+    - ARC: [plat-axs10x]: Add missing multicast filter number to GMAC node
+    - platform/x86: intel_mid_powerbtn: Take a copy of ddata
+    - arm64: dts: qcom: msm8998: Fix tcsr syscon size
+    - arm64: dts: uDPU: fix broken ethernet
+    - ARM: dts: at91: Reenable UART TX pull-ups
+    - ARM: dts: am43xx: add support for clkout1 clock
+    - arm64: dts: renesas: r8a77990: ebisu: Remove clkout-lr-synchronous from
+      sound
+    - arm64: dts: marvell: clearfog-gt-8k: fix switch cpu port node
+    - ARM: dts: meson8: use the actual frequency for the GPU's 182.1MHz OPP
+    - ARM: dts: meson8b: use the actual frequency for the GPU's 364MHz OPP
+    - ARM: dts: at91: sama5d3: fix maximum peripheral clock rates
+    - ARM: dts: at91: sama5d3: define clock rate range for tcb1
+    - tools/power/acpi: fix compilation error
+    - soc: qcom: rpmhpd: Set 'active_only' for active only power domains
+    - Revert "powerpc/pseries/iommu: Don't use dma_iommu_ops on secure guests"
+    - powerpc/ptdump: Fix W+X verification call in mark_rodata_ro()
+    - powerpc/ptdump: Only enable PPC_CHECK_WX with STRICT_KERNEL_RWX
+    - powerpc/papr_scm: Fix leaking 'bus_desc.provider_name' in some paths
+    - powerpc/pseries/vio: Fix iommu_table use-after-free refcount warning
+    - powerpc/pseries: Allow not having ibm, hypertas-functions::hcall-multi-tce
+      for DDW
+    - iommu/arm-smmu-v3: Populate VMID field for CMDQ_OP_TLBI_NH_VA
+    - ARM: at91: pm: use SAM9X60 PMC's compatible
+    - ARM: at91: pm: use of_device_id array to find the proper shdwc node
+    - KVM: arm/arm64: vgic-its: Fix restoration of unmapped collections
+    - ARM: 8949/1: mm: mark free_memmap as __init
+    - sched/uclamp: Fix a bug in propagating uclamp value in new cgroups
+    - arm64: cpufeature: Fix the type of no FP/SIMD capability
+    - arm64: cpufeature: Set the FP/SIMD compat HWCAP bits properly
+    - arm64: ptrace: nofpsimd: Fail FP/SIMD regset operations
+    - KVM: arm/arm64: Fix young bit from mmu notifier
+    - KVM: arm: Fix DFSR setting for non-LPAE aarch32 guests
+    - KVM: arm: Make inject_abt32() inject an external abort instead
+    - KVM: arm64: pmu: Don't increment SW_INCR if PMCR.E is unset
+    - KVM: arm64: pmu: Fix chained SW_INCR counters
+    - KVM: arm64: Treat emulated TVAL TimerValue as a signed 32-bit integer
+    - arm64: nofpsmid: Handle TIF_FOREIGN_FPSTATE flag cleanly
+    - mtd: onenand_base: Adjust indentation in onenand_read_ops_nolock
+    - mtd: sharpslpart: Fix unsigned comparison to zero
+    - crypto: testmgr - don't try to decrypt uninitialized buffers
+    - crypto: artpec6 - return correct error code for failed setkey()
+    - crypto: atmel-sha - fix error handling when setting hmac key
+    - crypto: caam/qi2 - fix typo in algorithm's driver name
+    - drivers: watchdog: stm32_iwdg: set WDOG_HW_RUNNING at probe
+    - media: i2c: adv748x: Fix unsafe macros
+    - dt-bindings: iio: adc: ad7606: Fix wrong maxItems value
+    - bcache: avoid unnecessary btree nodes flushing in btree_flush_write()
+    - selinux: revert "stop passing MAY_NOT_BLOCK to the AVC upon follow_link"
+    - selinux: fix regression introduced by move_mount(2) syscall
+    - pinctrl: sh-pfc: r8a77965: Fix DU_DOTCLKIN3 drive/bias control
+    - pinctrl: sh-pfc: r8a7778: Fix duplicate SDSELF_B and SD1_CLK_B
+    - regmap: fix writes to non incrementing registers
+    - mfd: max77650: Select REGMAP_IRQ in Kconfig
+    - clk: meson: g12a: fix missing uart2 in regmap table
+    - dmaengine: axi-dmac: add a check for devm_regmap_init_mmio
+    - 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
+    - selinux: fall back to ref-walk if audit is required
+    - Linux 5.4.20
+
+  * Focal update: v5.4.19 upstream stable release (LP: #1863588)
+    - sparc32: fix struct ipc64_perm type definition
+    - bnxt_en: Move devlink_register before registering netdev
+    - cls_rsvp: fix rsvp_policy
+    - gtp: use __GFP_NOWARN to avoid memalloc warning
+    - l2tp: Allow duplicate session creation with UDP
+    - net: hsr: fix possible NULL deref in hsr_handle_frame()
+    - net_sched: fix an OOB access in cls_tcindex
+    - net: stmmac: Delete txtimer in suspend()
+    - bnxt_en: Fix TC queue mapping.
+    - rxrpc: Fix use-after-free in rxrpc_put_local()
+    - rxrpc: Fix insufficient receive notification generation
+    - rxrpc: Fix missing active use pinning of rxrpc_local object
+    - rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect
+    - tcp: clear tp->total_retrans in tcp_disconnect()
+    - tcp: clear tp->delivered in tcp_disconnect()
+    - tcp: clear tp->data_segs{in|out} in tcp_disconnect()
+    - tcp: clear tp->segs_{in|out} in tcp_disconnect()
+    - ionic: fix rxq comp packet type mask
+    - MAINTAINERS: correct entries for ISDN/mISDN section
+    - netdevsim: fix stack-out-of-bounds in nsim_dev_debugfs_init()
+    - bnxt_en: Fix logic that disables Bus Master during firmware reset.
+    - media: uvcvideo: Avoid cyclic entity chains due to malformed USB descriptors
+    - mfd: dln2: More sanity checking for endpoints
+    - netfilter: ipset: fix suspicious RCU usage in find_set_and_id
+    - ipc/msg.c: consolidate all xxxctl_down() functions
+    - tracing/kprobes: Have uname use __get_str() in print_fmt
+    - tracing: Fix sched switch start/stop refcount racy updates
+    - rcu: Use *_ONCE() to protect lockless ->expmask accesses
+    - rcu: Avoid data-race in rcu_gp_fqs_check_wake()
+    - srcu: Apply *_ONCE() to ->srcu_last_gp_end
+    - rcu: Use READ_ONCE() for ->expmask in rcu_read_unlock_special()
+    - nvmet: Fix error print message at nvmet_install_queue function
+    - nvmet: Fix controller use after free
+    - Bluetooth: btusb: fix memory leak on fw
+    - Bluetooth: btusb: Disable runtime suspend on Realtek devices
+    - brcmfmac: Fix memory leak in brcmf_usbdev_qinit
+    - usb: dwc3: gadget: Check END_TRANSFER completion
+    - usb: dwc3: gadget: Delay starting transfer
+    - usb: typec: tcpci: mask event interrupts when remove driver
+    - objtool: Silence build output
+    - usb: gadget: f_fs: set req->num_sgs as 0 for non-sg transfer
+    - 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: usb-audio: Fix endianess in descriptor validation
+    - ALSA: usb-audio: Annotate endianess in Scarlett gen2 quirk
+    - ALSA: dummy: Fix PCM format loop in proc output
+    - memcg: fix a crash in wb_workfn when a device disappears
+    - mm/sparse.c: reset section's mem_map when fully deactivated
+    - mmc: sdhci-pci: Make function amd_sdhci_reset static
+    - utimes: Clamp the timestamps in notify_change()
+    - mm/memory_hotplug: fix remove_memory() lockdep splat
+    - mm: thp: don't need care deferred split queue in memcg charge move path
+    - mm: move_pages: report the number of non-attempted pages
+    - media/v4l2-core: set pages dirty upon releasing DMA buffers
+    - media: v4l2-core: compat: ignore native command codes
+    - media: v4l2-rect.h: fix v4l2_rect_map_inside() top/left adjustments
+    - lib/test_kasan.c: fix memory leak in kmalloc_oob_krealloc_more()
+    - irqdomain: Fix a memory leak in irq_domain_push_irq()
+    - x86/cpu: Update cached HLE state on write to TSX_CTRL_CPUID_CLEAR
+    - platform/x86: intel_scu_ipc: Fix interrupt support
+    - ALSA: hda: Apply aligned MMIO access only conditionally
+    - ALSA: hda: Add Clevo W65_67SB the power_save blacklist
+    - ALSA: hda: Add JasperLake PCI ID and codec vid
+    - arm64: acpi: fix DAIF manipulation with pNMI
+    - KVM: arm64: Correct PSTATE on exception entry
+    - KVM: arm/arm64: Correct CPSR on exception entry
+    - KVM: arm/arm64: Correct AArch32 SPSR on exception entry
+    - KVM: arm64: Only sign-extend MMIO up to register width
+    - MIPS: syscalls: fix indentation of the 'SYSNR' message
+    - MIPS: fix indentation of the 'RELOCS' message
+    - MIPS: boot: fix typo in 'vmlinux.lzma.its' target
+    - s390/mm: fix dynamic pagetable upgrade for hugetlbfs
+    - powerpc/mmu_gather: enable RCU_TABLE_FREE even for !SMP case
+    - powerpc/ptdump: Fix W+X verification
+    - powerpc/xmon: don't access ASDR in VMs
+    - powerpc/pseries: Advance pfn if section is not present in lmb_is_removable()
+    - powerpc/32s: Fix bad_kuap_fault()
+    - powerpc/32s: Fix CPU wake-up from sleep mode
+    - tracing: Fix now invalid var_ref_vals assumption in trace action
+    - PCI: tegra: Fix return value check of pm_runtime_get_sync()
+    - PCI: keystone: Fix outbound region mapping
+    - PCI: keystone: Fix link training retries initiation
+    - PCI: keystone: Fix error handling when "num-viewport" DT property is not
+      populated
+    - mmc: spi: Toggle SPI polarity, do not hardcode it
+    - ACPI: video: Do not export a non working backlight interface on MSI MS-7721
+      boards
+    - ACPI / battery: Deal with design or full capacity being reported as -1
+    - ACPI / battery: Use design-cap for capacity calculations if full-cap is not
+      available
+    - ACPI / battery: Deal better with neither design nor full capacity not being
+      reported
+    - alarmtimer: Unregister wakeup source when module get fails
+    - fscrypt: don't print name of busy file when removing key
+    - ubifs: don't trigger assertion on invalid no-key filename
+    - ubifs: Fix wrong memory allocation
+    - ubifs: Fix FS_IOC_SETFLAGS unexpectedly clearing encrypt flag
+    - ubifs: Fix deadlock in concurrent bulk-read and writepage
+    - mmc: sdhci-of-at91: fix memleak on clk_get failure
+    - ASoC: SOF: core: free trace on errors
+    - hv_balloon: Balloon up according to request page number
+    - mfd: axp20x: Mark AXP20X_VBUS_IPSOUT_MGMT as volatile
+    - nvmem: core: fix memory abort in cleanup path
+    - crypto: api - Check spawn->alg under lock in crypto_drop_spawn
+    - crypto: ccree - fix backlog memory leak
+    - crypto: ccree - fix AEAD decrypt auth fail
+    - crypto: ccree - fix pm wrongful error reporting
+    - crypto: ccree - fix FDE descriptor sequence
+    - crypto: ccree - fix PM race condition
+    - padata: Remove broken queue flushing
+    - fs: allow deduplication of eof block into the end of the destination file
+    - scripts/find-unused-docs: Fix massive false positives
+    - erofs: fix out-of-bound read for shifted uncompressed block
+    - scsi: megaraid_sas: Do not initiate OCR if controller is not in ready state
+    - scsi: qla2xxx: Fix mtcp dump collection failure
+    - cpupower: Revert library ABI changes from commit ae2917093fb60bdc1ed3e
+    - power: supply: axp20x_ac_power: Fix reporting online status
+    - power: supply: ltc2941-battery-gauge: fix use-after-free
+    - ovl: fix wrong WARN_ON() in ovl_cache_update_ino()
+    - ovl: fix lseek overflow on 32bit
+    - f2fs: choose hardlimit when softlimit is larger than hardlimit in
+      f2fs_statfs_project()
+    - f2fs: fix miscounted block limit in f2fs_statfs_project()
+    - f2fs: code cleanup for f2fs_statfs_project()
+    - f2fs: fix dcache lookup of !casefolded directories
+    - f2fs: fix race conditions in ->d_compare() and ->d_hash()
+    - PM: core: Fix handling of devices deleted during system-wide resume
+    - cpufreq: Avoid creating excessively large stack frames
+    - of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
+    - ARM: dma-api: fix max_pfn off-by-one error in __dma_supported()
+    - dm zoned: support zone sizes smaller than 128MiB
+    - dm space map common: fix to ensure new block isn't already in use
+    - dm writecache: fix incorrect flush sequence when doing SSD mode commit
+    - dm crypt: fix GFP flags passed to skcipher_request_alloc()
+    - dm crypt: fix benbi IV constructor crash if used in authenticated mode
+    - dm thin metadata: use pool locking at end of dm_pool_metadata_close
+    - scsi: qla2xxx: Fix stuck login session using prli_pend_timer
+    - ASoC: SOF: Introduce state machine for FW boot
+    - ASoC: SOF: core: release resources on errors in probe_continue
+    - tracing: Annotate ftrace_graph_hash pointer with __rcu
+    - tracing: Annotate ftrace_graph_notrace_hash pointer with __rcu
+    - ftrace: Add comment to why rcu_dereference_sched() is open coded
+    - ftrace: Protect ftrace_graph_hash with ftrace_sync
+    - crypto: pcrypt - Avoid deadlock by using per-instance padata queues
+    - btrfs: fix improper setting of scanned for range cyclic write cache pages
+    - btrfs: Handle another split brain scenario with metadata uuid feature
+    - riscv, bpf: Fix broken BPF tail calls
+    - selftests/bpf: Fix perf_buffer test on systems w/ offline CPUs
+    - bpf, devmap: Pass lockdep expression to RCU lists
+    - libbpf: Fix realloc usage in bpf_core_find_cands
+    - tc-testing: fix eBPF tests failure on linux fresh clones
+    - samples/bpf: Don't try to remove user's homedir on clean
+    - samples/bpf: Xdp_redirect_cpu fix missing tracepoint attach
+    - selftests/bpf: Fix test_attach_probe
+    - selftests/bpf: Skip perf hw events test if the setup disabled it
+    - selftests: bpf: Use a temporary file in test_sockmap
+    - selftests: bpf: Ignore FIN packets for reuseport tests
+    - crypto: api - fix unexpectedly getting generic implementation
+    - crypto: hisilicon - Use the offset fields in sqe to avoid need to split
+      scatterlists
+    - crypto: ccp - set max RSA modulus size for v3 platform devices as well
+    - crypto: arm64/ghash-neon - bump priority to 150
+    - crypto: pcrypt - Do not clear MAY_SLEEP flag in original request
+    - crypto: atmel-aes - Fix counter overflow in CTR mode
+    - crypto: api - Fix race condition in crypto_spawn_alg
+    - crypto: picoxcell - adjust the position of tasklet_init and fix missed
+      tasklet_kill
+    - powerpc/futex: Fix incorrect user access blocking
+    - scsi: qla2xxx: Fix unbound NVME response length
+    - NFS: Fix memory leaks and corruption in readdir
+    - NFS: Directory page cache pages need to be locked when read
+    - nfsd: fix filecache lookup
+    - jbd2_seq_info_next should increase position index
+    - ext4: fix deadlock allocating crypto bounce page from mempool
+    - ext4: fix race conditions in ->d_compare() and ->d_hash()
+    - Btrfs: fix missing hole after hole punching and fsync when using NO_HOLES
+    - Btrfs: make deduplication with range including the last block work
+    - Btrfs: fix infinite loop during fsync after rename operations
+    - btrfs: set trans->drity in btrfs_commit_transaction
+    - btrfs: drop log root for dropped roots
+    - Btrfs: fix race between adding and putting tree mod seq elements and nodes
+    - btrfs: flush write bio if we loop in extent_write_cache_pages
+    - btrfs: Correctly handle empty trees in find_first_clear_extent_bit
+    - ARM: tegra: Enable PLLP bypass during Tegra124 LP1
+    - iwlwifi: don't throw error when trying to remove IGTK
+    - mwifiex: fix unbalanced locking in mwifiex_process_country_ie()
+    - sunrpc: expiry_time should be seconds not timeval
+    - gfs2: fix gfs2_find_jhead that returns uninitialized jhead with seq 0
+    - gfs2: move setting current->backing_dev_info
+    - gfs2: fix O_SYNC write handling
+    - drm: atmel-hlcdc: use double rate for pixel clock only if supported
+    - drm: atmel-hlcdc: enable clock before configuring timing engine
+    - drm: atmel-hlcdc: prefer a lower pixel-clock than requested
+    - drm/rect: Avoid division by zero
+    - media: iguanair: fix endpoint sanity check
+    - media: rc: ensure lirc is initialized before registering input device
+    - tools/kvm_stat: Fix kvm_exit filter name
+    - xen/balloon: Support xend-based toolstack take two
+    - watchdog: fix UAF in reboot notifier handling in watchdog core code
+    - bcache: add readahead cache policy options via sysfs interface
+    - eventfd: track eventfd_signal() recursion depth
+    - aio: prevent potential eventfd recursion on poll
+    - KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Refactor prefix decoding to prevent Spectre-v1/L1TF attacks
+    - KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks
+    - KVM: x86: Protect kvm_lapic_reg_write() 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: x86: Fix potential put_fpu() w/o load_fpu() on MPX platform
+    - KVM: PPC: Book3S HV: Uninit vCPU if vcore creation fails
+    - KVM: PPC: Book3S PR: Free shared page if mmu initialization fails
+    - kvm/svm: PKU not currently supported
+    - KVM: VMX: Add non-canonical check on writes to RTIT address MSRs
+    - KVM: x86: Don't let userspace set host-reserved cr4 bits
+    - KVM: x86: Free wbinvd_dirty_mask if vCPU creation fails
+    - KVM: x86: Handle TIF_NEED_FPU_LOAD in kvm_{load,put}_guest_fpu()
+    - KVM: x86: Ensure guest's FPU state is loaded when accessing for emulation
+    - KVM: x86: Revert "KVM: X86: Fix fpu state crash in kvm guest"
+    - KVM: s390: do not clobber registers during guest reset/store status
+    - ocfs2: fix oops when writing cloned file
+    - mm/page_alloc.c: fix uninitialized memmaps on a partially populated last
+      section
+    - arm64: dts: qcom: qcs404-evb: Set vdd_apc regulator in high power mode
+    - mm/mmu_gather: invalidate TLB correctly on batch allocation failure and
+      flush
+    - clk: tegra: Mark fuse clock as critical
+    - drm/amd/dm/mst: Ignore payload update failures
+    - virtio-balloon: initialize all vq callbacks
+    - virtio-pci: check name when counting MSI-X vectors
+    - fix up iter on short count in fuse_direct_io()
+    - broken ping to ipv6 linklocal addresses on debian buster
+    - percpu: Separate decrypted varaibles anytime encryption can be enabled
+    - ASoC: meson: axg-fifo: fix fifo threshold setup
+    - 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
+    - scsi: ufs: Recheck bkops level if bkops is disabled
+    - mtd: spi-nor: Split mt25qu512a (n25q512a) entry into two
+    - phy: qualcomm: Adjust indentation in read_poll_timeout
+    - ext2: Adjust indentation in ext2_fill_super
+    - powerpc/44x: Adjust indentation in ibm4xx_denali_fixup_memsize
+    - drm: msm: mdp4: Adjust indentation in mdp4_dsi_encoder_enable
+    - 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
+    - IB/mlx5: Fix outstanding_pi index for GSI qps
+    - IB/core: Fix ODP get user pages flow
+    - nfsd: fix delay timer on 32-bit architectures
+    - nfsd: fix jiffies/time_t mixup in LRU list
+    - nfsd: Return the correct number of bytes written to the file
+    - virtio-balloon: Fix memory leak when unloading while hinting is in progress
+    - virtio_balloon: Fix memory leaks on errors in virtballoon_probe()
+    - ubi: fastmap: Fix inverted logic in seen selfcheck
+    - ubi: Fix an error pointer dereference in error handling code
+    - ubifs: Fix memory leak from c->sup_node
+    - regulator: core: Add regulator_is_equal() helper
+    - ASoC: sgtl5000: Fix VDDA and VDDIO comparison
+    - bonding/alb: properly access headers in bond_alb_xmit()
+    - devlink: report 0 after hitting end in region read
+    - dpaa_eth: support all modes with rate adapting PHYs
+    - net: dsa: b53: Always use dev->vlan_enabled in b53_configure_vlan()
+    - net: dsa: bcm_sf2: Only 7278 supports 2Gb/sec IMP port
+    - net: dsa: microchip: enable module autoprobe
+    - net: mvneta: move rx_dropped and rx_errors in per-cpu stats
+    - net_sched: fix a resource leak in tcindex_set_parms()
+    - net: stmmac: fix a possible endless loop
+    - net: systemport: Avoid RBUF stuck in Wake-on-LAN mode
+    - net/mlx5: IPsec, Fix esp modify function attribute
+    - net/mlx5: IPsec, fix memory leak at mlx5_fpga_ipsec_delete_sa_ctx
+    - net: macb: Remove unnecessary alignment check for TSO
+    - net: macb: Limit maximum GEM TX length in TSO
+    - taprio: Fix enabling offload with wrong number of traffic classes
+    - taprio: Fix still allowing changing the flags during runtime
+    - taprio: Add missing policy validation for flags
+    - taprio: Use taprio_reset_tc() to reset Traffic Classes configuration
+    - taprio: Fix dropping packets when using taprio + ETF offloading
+    - ipv6/addrconf: fix potential NULL deref in inet6_set_link_af()
+    - qed: Fix timestamping issue for L2 unicast ptp packets.
+    - drop_monitor: Do not cancel uninitialized work item
+    - net/mlx5: Fix deadlock in fs_core
+    - net/mlx5: Deprecate usage of generic TLS HW capability bit
+    - ASoC: Intel: skl_hda_dsp_common: Fix global-out-of-bounds bug
+    - mfd: da9062: Fix watchdog compatible string
+    - mfd: rn5t618: Mark ADC control register volatile
+    - mfd: bd70528: Fix hour register mask
+    - x86/timer: Don't skip PIT setup when APIC is disabled or in legacy mode
+    - btrfs: use bool argument in free_root_pointers()
+    - btrfs: free block groups after free'ing fs trees
+    - drm/dp_mst: Remove VCPI while disabling topology mgr
+    - KVM: x86/mmu: Apply max PA check for MMIO sptes to 32-bit KVM
+    - KVM: x86: use CPUID to locate host page table reserved bits
+    - KVM: x86: Use gpa_t for cr2/gpa to fix TDP support on 32-bit KVM
+    - KVM: x86: fix overlap between SPTE_MMIO_MASK and generation
+    - KVM: nVMX: vmread should not set rflags to specify success in case of #PF
+    - KVM: Use vcpu-specific gva->hva translation when querying host page size
+    - KVM: Play nice with read-only memslots when querying host page size
+    - cifs: fail i/o on soft mounts if sessionsetup errors out
+    - x86/apic/msi: Plug non-maskable MSI affinity race
+    - clocksource: Prevent double add_timer_on() for watchdog_timer
+    - perf/core: Fix mlock accounting in perf_mmap()
+    - rxrpc: Fix service call disconnection
+    - regulator fix for "regulator: core: Add regulator_is_equal() helper"
+    - powerpc/kuap: Fix set direction in allow/prevent_user_access()
+    - Linux 5.4.19
+    - [Config] updateconfigs following v5.4.19 stable update
+
+  * 5.4.0-11 crash on cryptsetup open (LP: #1860231) // Focal update: v5.4.19
+    upstream stable release (LP: #1863588)
+    - dm: fix potential for q->make_request_fn NULL pointer
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [debian] ignore missing wireguard module
+    - debian: remove snapdragon config, rules and flavour
+    - [Config] updateconfigs following snapdragon removal
+    - remove snapdragon abi files
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 20 Feb 2020 11:42:30 -0600
+
+linux (5.4.0-14.17) focal; urgency=medium
+
+  * Empty entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 19 Feb 2020 11:46:35 -0600
+
+linux-5.4 (5.4.0-14.17) focal; urgency=medium
+
+  * focal/linux-5.4: 5.4.0-14.17 -proposed tracker (LP: #1862255)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Boot log is swamped with "debugfs: Directory 'imc' with parent 'powerpc'
+    already present" messages on kernel 5.4 (LP: #1861379)
+    - powerpc/powernv: Avoid re-registration of imc debugfs directory
+
+  * CVE-2019-3016
+    - SAUCE: x86/kvm: Be careful not to clear KVM_VCPU_FLUSH_TLB bit
+    - SAUCE: x86/kvm: Introduce kvm_(un)map_gfn()
+    - SAUCE: x86/kvm: Cache gfn to pfn translation
+    - SAUCE: x86/KVM: Make sure KVM_VCPU_FLUSH_TLB flag is not missed
+    - SAUCE: x86/KVM: Clean up host's steal time structure
+
+  * installing linux-modules-nvidia does not remove nvidia-dkms, and the kernel
+    prioritizes the wrong version of the module from disk (LP: #1856414)
+    - Revert "UBUNTU: [Packaging] dkms -- switch basic provides to *-modules"
+    - Revert "UBUNTU: [Packaging] dkms -- add Provides: specifiers for existing
+      zfs/nvidia/vbox"
+    - Revert "UBUNTU: [packaging] dkms-build -- include versioned provides"
+    - [Packaging] wireguard -- drop provides
+
+  * Focal update: v5.4.18 upstream stable release (LP: #1862203)
+    - vfs: fix do_last() regression
+    - cifs: fix soft mounts hanging in the reconnect code
+    - x86/resctrl: Fix a deadlock due to inaccurate reference
+    - x86/resctrl: Fix use-after-free when deleting resource groups
+    - x86/resctrl: Fix use-after-free due to inaccurate refcount of rdtgroup
+    - e1000e: Drop unnecessary __E1000_DOWN bit twiddling
+    - e1000e: Revert "e1000e: Make watchdog use delayed work"
+    - gfs2: Another gfs2_find_jhead fix
+    - perf c2c: Fix return type for histogram sorting comparision functions
+    - PM / devfreq: Add new name attribute for sysfs
+    - tools lib: Fix builds when glibc contains strlcpy()
+    - 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: af9005: uninitialized variable printked
+    - media: vp7045: do not read uninitialized values if usb transfer fails
+    - media: gspca: zero usb_buf
+    - media: dvb-usb/dvb-usb-urb.c: initialize actlen to 0
+    - tomoyo: Use atomic_t for statistics counter
+    - ttyprintk: fix a potential deadlock in interrupt context issue
+    - Bluetooth: Fix race condition in hci_release_sock()
+    - cgroup: Prevent double killing of css when enabling threaded cgroup
+    - clk: sunxi-ng: v3s: Fix incorrect number of hw_clks.
+    - arm64: dts: meson-sm1-sei610: add gpio bluetooth interrupt
+    - ARM: dts: sun8i: a83t: Correct USB3503 GPIOs polarity
+    - ARM: dts: am57xx-beagle-x15/am57xx-idk: Remove "gpios" for endpoint dt nodes
+    - ARM: dts: beagle-x15-common: Model 5V0 regulator
+    - soc: ti: wkup_m3_ipc: Fix race condition with rproc_boot
+    - tools lib traceevent: Fix memory leakage in filter_event
+    - rseq: Unregister rseq for clone CLONE_VM
+    - clk: sunxi-ng: sun8i-r: Fix divider on APB0 clock
+    - clk: sunxi-ng: h6-r: Fix AR100/R_APB2 parent order
+    - mac80211: mesh: restrict airtime metric to peered established plinks
+    - clk: mmp2: Fix the order of timer mux parents
+    - ASoC: rt5640: Fix NULL dereference on module unload
+    - s390/zcrypt: move ap device reset from bus to driver code
+    - i40e: Fix virtchnl_queue_select bitmap validation
+    - ixgbevf: Remove limit of 10 entries for unicast filter list
+    - ixgbe: Fix calculation of queue with VFs and flow director on interface flap
+    - igb: Fix SGMII SFP module discovery for 100FX/LX.
+    - iavf: remove current MAC address filter on VF reset
+    - platform/x86: GPD pocket fan: Allow somewhat lower/higher temperature limits
+    - platform/x86: intel_pmc_core: update Comet Lake platform driver
+    - ASoC: hdac_hda: Fix error in driver removal after failed probe
+    - ASoC: sti: fix possible sleep-in-atomic
+    - qmi_wwan: Add support for Quectel RM500Q
+    - parisc: Use proper printk format for resource_size_t
+    - lkdtm/bugs: fix build error in lkdtm_UNSET_SMEP
+    - wireless: fix enabling channel 12 for custom regulatory domain
+    - cfg80211: Fix radar event during another phy CAC
+    - mac80211: Fix TKIP replay protection immediately after key setup
+    - wireless: wext: avoid gcc -O3 warning
+    - perf/x86/intel/uncore: Add PCI ID of IMC for Xeon E3 V5 Family
+    - perf/x86/intel/uncore: Remove PCIe3 unit for SNR
+    - riscv: delete temporary files
+    - XArray: Fix xas_pause at ULONG_MAX
+    - iwlwifi: pcie: allocate smaller dev_cmd for TX headers
+    - iwlwifi: Don't ignore the cap field upon mcc update
+    - iwlwifi: dbg: force stop the debug monitor HW
+    - Input: evdev - convert kzalloc()/vzalloc() to kvzalloc()
+    - ARM: dts: am335x-boneblack-common: fix memory size
+    - xfrm: interface: do not confirm neighbor when do pmtu update
+    - Input: max77650-onkey - add of_match table
+    - scsi: fnic: do not queue commands during fwreset
+    - ARM: 8955/1: virt: Relax arch timer version check during early boot
+    - led: max77650: add of_match table
+    - tee: optee: Fix compilation issue with nommu
+    - r8152: get default setting of WOL before initializing
+    - r8152: disable U2P3 for RTL8153B
+    - r8152: Disable PLA MCU clock speed down
+    - r8152: disable test IO for RTL8153B
+    - r8152: avoid the MCU to clear the lanwake
+    - r8152: disable DelayPhyPwrChg
+    - ARM: dts: am43x-epos-evm: set data pin directions for spi0 and spi1
+    - qlcnic: Fix CPU soft lockup while collecting firmware dump
+    - powerpc/fsl/dts: add fsl,erratum-a011043
+    - net/fsl: treat fsl,erratum-a011043
+    - net: fsl/fman: rename IF_MODE_XGMII to IF_MODE_10G
+    - seq_tab_next() should increase position index
+    - l2t_seq_next should increase position index
+    - netfilter: conntrack: sctp: use distinct states for new SCTP connections
+    - netfilter: nf_tables_offload: fix check the chain offload flag
+    - net: Fix skb->csum update in inet_proto_csum_replace16().
+    - btrfs: do not zero f_bavail if we have available space
+    - cpuidle: teo: Avoid using "early hits" incorrectly
+    - flow_dissector: Fix to use new variables for port ranges in bpf hook
+    - dm thin: fix use-after-free in metadata_pre_commit_callback
+    - perf report: Fix no libunwind compiled warning break s390 issue
+    - mm/migrate.c: also overwrite error when it is bigger than zero
+    - ASoC: topology: fix soc_tplg_fe_link_create() - link->dobj initialization
+      order
+    - Revert "rsi: fix potential null dereference in rsi_probe()"
+    - tracing/uprobe: Fix to make trace_uprobe_filter alignment safe
+    - Linux 5.4.18
+
+  *  Integrate Intel SGX driver into linux-azure (LP: #1844245)
+    - [Packaging] Add systemd service to load intel_sgx
+
+  * Focal update: v5.4.17 upstream stable release (LP: #1861784)
+    - Bluetooth: btusb: fix non-atomic allocation in completion handler
+    - orinoco_usb: fix interface sanity check
+    - rsi_91x_usb: fix interface sanity check
+    - usb: dwc3: pci: add ID for the Intel Comet Lake -V variant
+    - usb: host: xhci-tegra: set MODULE_FIRMWARE for tegra186
+    - USB: serial: ir-usb: add missing endpoint sanity check
+    - USB: serial: ir-usb: fix link-speed handling
+    - USB: serial: ir-usb: fix IrLAP framing
+    - usb: dwc3: turn off VBUS when leaving host mode
+    - usb: typec: wcove: fix "op-sink-microwatt" default that was in mW
+    - usb: typec: fusb302: fix "op-sink-microwatt" default that was in mW
+    - 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.
+    - serial: 8250_bcm2835aux: Fix line mismatch on driver unbind
+    - serial: imx: fix a race condition in receive path
+    - debugfs: Return -EPERM when locked down
+    - component: do not dereference opaque pointer in debugfs
+    - binder: fix log spam for existing debugfs file creation.
+    - mei: hdcp: bind only with i915 on the same PCH
+    - mei: me: add comet point (lake) H device ids
+    - iio: adc: stm32-dfsdm: fix single conversion
+    - iio: st_gyro: Correct data for LSM9DS0 gyro
+    - driver core: Fix test_async_driver_probe if NUMA is disabled
+    - crypto: chelsio - fix writing tfm flags to wrong place
+    - CIFS: Fix task struct use-after-free on reconnect
+    - cifs: set correct max-buffer-size for smb2_ioctl_init()
+    - cifs: Fix memory allocation in __smb2_handle_cancelled_cmd()
+    - ath9k: fix storage endpoint lookup
+    - brcmfmac: fix interface sanity check
+    - rtl8xxxu: fix interface sanity check
+    - zd1211rw: fix storage endpoint lookup
+    - net_sched: ematch: reject invalid TCF_EM_SIMPLE
+    - net_sched: fix ops->bind_class() implementations
+    - net_sched: walk through all child classes in tc_bind_tclass()
+    - net: socionext: fix possible user-after-free in netsec_process_rx
+    - net: socionext: fix xdp_result initialization in netsec_process_rx
+    - udp: segment looped gso packets correctly
+    - mlxsw: minimal: Fix an error handling path in 'mlxsw_m_port_create()'
+    - net: include struct nhmsg size in nh nlmsg size
+    - rxrpc: Fix use-after-free in rxrpc_receive_data()
+    - arc: eznps: fix allmodconfig kconfig warning
+    - HID: Add quirk for Xin-Mo Dual Controller
+    - HID: ite: Add USB id match for Acer SW5-012 keyboard dock
+    - HID: asus: Ignore Asus vendor-page usage-code 0xff events
+    - HID: Add quirk for incorrect input length on Lenovo Y720
+    - HID: intel-ish-hid: ipc: add CMP device id
+    - HID: wacom: Recognize new MobileStudio Pro PID
+    - ASoC: SOF: fix fault at driver unload after failed probe
+    - ASoC: SOF: Intel: hda: hda-dai: fix oops on hda_link .hw_free
+    - drivers/hid/hid-multitouch.c: fix a possible null pointer access.
+    - phy: qcom-qmp: Increase PHY ready timeout
+    - ASoC: fsl_audmix: add missed pm_runtime_disable
+    - ASoC: topology: Prevent use-after-free in snd_soc_get_pcm_runtime()
+    - phy: cpcap-usb: Prevent USB line glitches from waking up modem
+    - HID: intel-ish-hid: ipc: Add Tiger Lake PCI device ID
+    - watchdog: max77620_wdt: fix potential build errors
+    - watchdog: rn5t618_wdt: fix module aliases
+    - watchdog: orion: fix platform_get_irq() complaints
+    - usb: musb: jz4740: Silence error if code is -EPROBE_DEFER
+    - can: tcan4x5x: tcan4x5x_parse_config(): reset device before register access
+    - spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
+    - net: Google gve: Remove dma_wmb() before ringing doorbell
+    - drivers/net/b44: Change to non-atomic bit operations on pwol_mask
+    - net: wan: sdla: Fix cast from pointer to integer of different size
+    - gpio: max77620: Add missing dependency on GPIOLIB_IRQCHIP
+    - iommu/dma: fix variable 'cookie' set but not used
+    - drm/amd/display: Reduce HDMI pixel encoding if max clock is exceeded
+    - stmmac: debugfs entry name is not be changed when udev rename device name.
+    - atm: eni: fix uninitialized variable warning
+    - HID: steam: Fix input device disappearing
+    - extcon-intel-cht-wc: Don't reset USB data connection at probe
+    - ASoC: Intel: cht_bsw_rt5645: Add quirk for boards using pmc_plt_clk_0
+    - drm/amdgpu/SRIOV: add navi12 pci id for SRIOV (v2)
+    - libbpf: Fix BTF-defined map's __type macro handling of arrays
+    - staging: mt7621-pci: add quirks for 'E2' revision using
+      'soc_device_attribute'
+    - platform/x86: dell-laptop: disable kbd backlight on Inspiron 10xx
+    - PCI: Add DMA alias quirk for Intel VCA NTB
+    - media: dvbsky: add support for eyeTV Geniatech T2 lite
+    - bus: ti-sysc: Handle mstandby quirk and use it for musb
+    - bus: ti-sysc: Use swsup quirks also for am335x musb
+    - spi: pxa2xx: Add support for Intel Comet Lake-H
+    - iommu/amd: Support multiple PCI DMA aliases in device table
+    - iommu/amd: Support multiple PCI DMA aliases in IRQ Remapping
+    - perf/imx_ddr: Add enhanced AXI ID filter support
+    - ARM: config: aspeed-g5: Enable 8250_DW quirks
+    - ARM: OMAP2+: SmartReflex: add omap_sr_pdata definition
+    - mmc: sdhci-pci: Quirk for AMD SDHC Device 0x7906
+    - mmc: sdhci-pci: Add support for Intel JSL
+    - bus: ti-sysc: Add module enable quirk for audio AESS
+    - usb-storage: Disable UAS on JMicron SATA enclosure
+    - ALSA: hda/realtek - Move some alc236 pintbls to fallback table
+    - Bluetooth: Allow combination of BDADDR_PROPERTY and INVALID_BDADDR quirks
+    - Bluetooth: btbcm: Use the BDADDR_PROPERTY quirk
+    - bus: ti-sysc: Fix missing force mstandby quirk handling
+    - rsi: fix use-after-free on failed probe and unbind
+    - rsi: fix use-after-free on probe errors
+    - rsi: fix memory leak on failed URB submission
+    - rsi: fix non-atomic allocation in completion handler
+    - crypto: af_alg - Use bh_lock_sock in sk_destruct
+    - crypto: vmx - reject xts inputs that are too short
+    - crypto: caam - do not reset pointer size from MCFGR register
+    - crypto: pcrypt - Fix user-after-free on module unload
+    - KVM: arm64: Write arch.mdcr_el2 changes since last vcpu_load on VHE
+    - Revert "um: Enable CONFIG_CONSTRUCTORS"
+    - power/supply: ingenic-battery: Don't change scale if there's only one
+    - Linux 5.4.17
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] dkms -- switch basic provides to *-modules
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 06 Feb 2020 16:30:48 -0600
+
+linux-5.4 (5.4.0-13.16) focal; urgency=medium
+
+  * focal/linux-5.4: 5.4.0-13.16 -proposed tracker (LP: #1861352)
+
+  * system hang: i915 Resetting rcs0 for hang on rcs0 (LP: #1861395)
+    - drm/i915/gt: Detect if we miss WaIdleLiteRestore
+
+  * Focal update: v5.4.16 upstream stable release (LP: #1861385)
+    - can, slip: Protect tty->disc_data in write_wakeup and close with RCU
+    - firestream: fix memory leaks
+    - gtp: make sure only SOCK_DGRAM UDP sockets are accepted
+    - ipv6: sr: remove SKB_GSO_IPXIP6 on End.D* actions
+    - net: bcmgenet: Use netif_tx_napi_add() for TX NAPI
+    - net: cxgb3_main: Add CAP_NET_ADMIN check to CHELSIO_GET_MEM
+    - net: ip6_gre: fix moving ip6gre between namespaces
+    - net, ip6_tunnel: fix namespaces move
+    - net, ip_tunnel: fix namespaces move
+    - net: rtnetlink: validate IFLA_MTU attribute in rtnl_create_link()
+    - net_sched: fix datalen for ematch
+    - net_sched: use validated TCA_KIND attribute in tc_new_tfilter()
+    - net-sysfs: Fix reference count leak
+    - net: usb: lan78xx: Add .ndo_features_check
+    - Revert "udp: do rmem bulk free even if the rx sk queue is empty"
+    - tcp_bbr: improve arithmetic division in bbr_update_bw()
+    - tcp: do not leave dangling pointers in tp->highest_sack
+    - tun: add mutex_unlock() call and napi.skb clearing in tun_get_user()
+    - airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE
+    - mlxsw: spectrum_acl: Fix use-after-free during reload
+    - fou: Fix IPv6 netlink policy
+    - net: Fix packet reordering caused by GRO and listified RX cooperation
+    - net/mlx5: Fix lowest FDB pool size
+    - net/mlx5: Update the list of the PCI supported devices
+    - net/mlx5: DR, Enable counter on non-fwd-dest objects
+    - net/mlx5: E-Switch, Prevent ingress rate configuration of uplink rep
+    - net/mlx5: DR, use non preemptible call to get the current cpu number
+    - net/mlx5e: kTLS, Fix corner-case checks in TX resync flow
+    - net/mlx5e: kTLS, Remove redundant posts in TX resync flow
+    - net/mlx5e: kTLS, Do not send decrypted-marked SKBs via non-accel path
+    - ipv4: Detect rollover in specific fib table dump
+    - Revert "io_uring: only allow submit from owning task"
+    - afs: Fix characters allowed into cell names
+    - hwmon: (adt7475) Make volt2reg return same reg as reg2volt input
+    - hwmon: (core) Do not use device managed functions for memory allocations
+    - ceph: hold extra reference to r_parent over life of request
+    - PCI: Mark AMD Navi14 GPU rev 0xc5 ATS as broken
+    - drm/panfrost: Add the panfrost_gem_mapping concept
+    - drm/i915: Align engine->uabi_class/instance with i915_drm.h
+    - PM: hibernate: fix crashes with init_on_free=1
+    - tracing: trigger: Replace unneeded RCU-list traversals
+    - tracing/uprobe: Fix double perf_event linking on multiprobe uprobe
+    - tracing: Do not set trace clock if tracefs lockdown is in effect
+    - tracing: Fix histogram code when expression has same var as value
+    - powerpc/mm/hash: Fix sharing context ids between kernel & userspace
+    - powerpc/xive: Discard ESB load value when interrupt is invalid
+    - Revert "iwlwifi: mvm: fix scan config command size"
+    - iwlwifi: mvm: don't send the IWL_MVM_RXQ_NSSN_SYNC notif to Rx queues
+    - XArray: Fix infinite loop with entry at ULONG_MAX
+    - XArray: Fix xa_find_after with multi-index entries
+    - XArray: Fix xas_find returning too many entries
+    - pinctrl: sunrisepoint: Add missing Interrupt Status register offset
+    - iommu/vt-d: Call __dmar_remove_one_dev_info with valid pointer
+    - Input: keyspan-remote - fix control-message timeouts
+    - Revert "Input: synaptics-rmi4 - don't increment rmiaddr for SMBus transfers"
+    - ARM: 8950/1: ftrace/recordmcount: filter relocation types
+    - mmc: tegra: fix SDR50 tuning override
+    - mmc: sdhci: fix minimum clock rate for v3 controller
+    - mmc: sdhci_am654: Remove Inverted Write Protect flag
+    - mmc: sdhci_am654: Reset Command and Data line after tuning
+    - mlxsw: switchx2: Do not modify cloned SKBs during xmit
+    - net/tls: fix async operation
+    - Input: pm8xxx-vib - fix handling of separate enable register
+    - Input: sur40 - fix interface sanity checks
+    - Input: gtco - fix endpoint sanity check
+    - Input: aiptek - fix endpoint sanity check
+    - Input: pegasus_notetaker - fix endpoint sanity check
+    - Input: sun4i-ts - add a check for devm_thermal_zone_of_sensor_register
+    - netfilter: nft_osf: add missing check for DREG attribute
+    - lib: Reduce user_access_begin() boundaries in strncpy_from_user() and
+      strnlen_user()
+    - iommu/amd: Fix IOMMU perf counter clobbering during init
+    - readdir: make user_access_begin() use the real access range
+    - leds: gpio: Fix uninitialized gpio label for fwnode based probe
+    - hsr: Fix a compilation error
+    - hwmon: (nct7802) Fix voltage limits to wrong registers
+    - hwmon: (nct7802) Fix non-working alarm on voltages
+    - scsi: RDMA/isert: Fix a recently introduced regression related to logout
+    - tracing: xen: Ordered comparison of function pointers
+    - iwlwifi: mvm: fix SKB leak on invalid queue
+    - iwlwifi: mvm: fix potential SKB leak on TXQ TX
+    - drm/i915/userptr: fix size calculation
+    - xfrm: support output_mark for offload ESP packets
+    - net, sk_msg: Don't check if sock is locked when tearing down psock
+    - do_last(): fetch directory ->i_mode and ->i_uid before it's too late
+    - readdir: be more conservative with directory entry names
+    - net/sonic: Add mutual exclusion for accessing shared state
+    - net/sonic: Clear interrupt flags immediately
+    - net/sonic: Use MMIO accessors
+    - net/sonic: Fix interface error stats collection
+    - net/sonic: Fix receive buffer handling
+    - net/sonic: Avoid needless receive descriptor EOL flag updates
+    - net/sonic: Improve receive descriptor status flag check
+    - net/sonic: Fix receive buffer replenishment
+    - net/sonic: Quiesce SONIC before re-initializing descriptor memory
+    - net/sonic: Fix command register usage
+    - net/sonic: Fix CAM initialization
+    - net/sonic: Prevent tx watchdog timeout
+    - media: v4l2-ioctl.c: zero reserved fields for S/TRY_FMT
+    - netfilter: ipset: use bitmap infrastructure completely
+    - netfilter: nf_tables: add __nft_chain_type_get()
+    - netfilter: nf_tables: autoload modules from the abort path
+    - net/x25: fix nonblocking connect
+    - Linux 5.4.16
+
+  * Build and ship a signed wireguard.ko (LP: #1861284)
+    - [Packaging] wireguard -- add support for building signed .ko
+    - [Config] wireguard -- enable on all architectures
+
+  * installing linux-modules-nvidia does not remove nvidia-dkms, and the kernel
+    prioritizes the wrong version of the module from disk (LP: #1856414)
+    - [packaging] dkms-build -- include versioned provides
+    - [Packaging] dkms -- add Provides: specifiers for existing zfs/nvidia/vbox
+
+  * dkms artifacts may expire from the pool (LP: #1850958)
+    - [Packaging] autoreconstruct -- manage executable debian files
+    - [packaging] handle downloads from the librarian better
+
+  * QAT drivers for C3XXX and C62X not included as modules (LP: #1845959)
+    - [Config] CRYPTO_DEV_QAT_C3XXX=m, CRYPTO_DEV_QAT_C62X=m and
+      CRYPTO_DEV_QAT_DH895xCC=m
+
+  * 5.4.0-11 crash on cryptsetup open (LP: #1860231)
+    - SAUCE: blk/core: Gracefully handle unset make_request_fn
+
+  * multi-zone raid0 corruption (LP: #1850540)
+    - SAUCE: md/raid0: Use kernel specific layout
+
+  * ipsec interfaces: fix sending with bpf_redirect() / AF_PACKET sockets
+    (LP: #1860969)
+    - vti[6]: fix packet tx through bpf_redirect()
+    - xfrm interface: fix packet tx through bpf_redirect()
+
+  * Focal update: v5.4.15 upstream stable release (LP: #1861091)
+    - drm/i915: Fix pid leak with banned clients
+    - libbpf: Fix compatibility for kernels without need_wakeup
+    - libbpf: Fix memory leak/double free issue
+    - libbpf: Fix potential overflow issue
+    - libbpf: Fix another potential overflow issue in bpf_prog_linfo
+    - libbpf: Make btf__resolve_size logic always check size error condition
+    - bpf: Force .BTF section start to zero when dumping from vmlinux
+    - samples: bpf: update map definition to new syntax BTF-defined map
+    - samples/bpf: Fix broken xdp_rxq_info due to map order assumptions
+    - ARM: dts: logicpd-torpedo-37xx-devkit-28: Reference new DRM panel
+    - ARM: OMAP2+: Add missing put_device() call in omapdss_init_of()
+    - xfs: Sanity check flags of Q_XQUOTARM call
+    - i2c: stm32f7: rework slave_id allocation
+    - i2c: i2c-stm32f7: fix 10-bits check in slave free id search loop
+    - mfd: intel-lpss: Add default I2C device properties for Gemini Lake
+    - SUNRPC: Fix svcauth_gss_proxy_init()
+    - SUNRPC: Fix backchannel latency metrics
+    - powerpc/security: Fix debugfs data leak on 32-bit
+    - powerpc/pseries: Enable support for ibm,drc-info property
+    - powerpc/kasan: Fix boot failure with RELOCATABLE && FSL_BOOKE
+    - powerpc/archrandom: fix arch_get_random_seed_int()
+    - tipc: reduce sensitive to retransmit failures
+    - tipc: update mon's self addr when node addr generated
+    - tipc: fix potential memory leak in __tipc_sendmsg()
+    - tipc: fix wrong socket reference counter after tipc_sk_timeout() returns
+    - tipc: fix wrong timeout input for tipc_wait_for_cond()
+    - net/mlx5e: Fix free peer_flow when refcount is 0
+    - phy: lantiq: vrx200-pcie: fix error return code in
+      ltq_vrx200_pcie_phy_power_on()
+    - net: phy: broadcom: Fix RGMII delays configuration for BCM54210E
+    - phy: ti: gmii-sel: fix mac tx internal delay for rgmii-rxid
+    - mt76: mt76u: fix endpoint definition order
+    - mt7601u: fix bbp version check in mt7601u_wait_bbp_ready
+    - ice: fix stack leakage
+    - s390/pkey: fix memory leak within _copy_apqns_from_user()
+    - nfsd: depend on CRYPTO_MD5 for legacy client tracking
+    - crypto: amcc - restore CRYPTO_AES dependency
+    - crypto: sun4i-ss - fix big endian issues
+    - perf map: No need to adjust the long name of modules
+    - leds: tlc591xx: update the maximum brightness
+    - soc/tegra: pmc: Fix crashes for hierarchical interrupts
+    - soc: qcom: llcc: Name regmaps to avoid collisions
+    - soc: renesas: Add missing check for non-zero product register address
+    - soc: aspeed: Fix snoop_file_poll()'s return type
+    - watchdog: sprd: Fix the incorrect pointer getting from driver data
+    - ipmi: Fix memory leak in __ipmi_bmc_register
+    - sched/core: Further clarify sched_class::set_next_task()
+    - gpiolib: No need to call gpiochip_remove_pin_ranges() twice
+    - rtw88: fix beaconing mode rsvd_page memory violation issue
+    - rtw88: fix error handling when setup efuse info
+    - drm/panfrost: Add missing check for pfdev->regulator
+    - drm: panel-lvds: Potential Oops in probe error handling
+    - drm/amdgpu: remove excess function parameter description
+    - hwrng: omap3-rom - Fix missing clock by probing with device tree
+    - dpaa2-eth: Fix minor bug in ethtool stats reporting
+    - drm/rockchip: Round up _before_ giving to the clock framework
+    - software node: Get reference to parent swnode in get_parent op
+    - PCI: mobiveil: Fix csr_read()/write() build issue
+    - drm: rcar_lvds: Fix color mismatches on R-Car H2 ES2.0 and later
+    - net: netsec: Correct dma sync for XDP_TX frames
+    - ACPI: platform: Unregister stale platform devices
+    - pwm: sun4i: Fix incorrect calculation of duty_cycle/period
+    - regulator: bd70528: Add MODULE_ALIAS to allow module auto loading
+    - drm/amdgpu/vi: silence an uninitialized variable warning
+    - power: supply: bd70528: Add MODULE_ALIAS to allow module auto loading
+    - firmware: imx: Remove call to devm_of_platform_populate
+    - libbpf: Don't use kernel-side u32 type in xsk.c
+    - rcu: Fix uninitialized variable in nocb_gp_wait()
+    - dpaa_eth: perform DMA unmapping before read
+    - dpaa_eth: avoid timestamp read on error paths
+    - scsi: ufs: delete redundant function ufshcd_def_desc_sizes()
+    - net: openvswitch: don't unlock mutex when changing the user_features fails
+    - hv_netvsc: flag software created hash value
+    - rt2800: remove errornous duplicate condition
+    - net: neigh: use long type to store jiffies delta
+    - net: axienet: Fix error return code in axienet_probe()
+    - selftests: gen_kselftest_tar.sh: Do not clobber kselftest/
+    - rtc: bd70528: fix module alias to autoload module
+    - packet: fix data-race in fanout_flow_is_huge()
+    - i2c: stm32f7: report dma error during probe
+    - kselftests: cgroup: Avoid the reuse of fd after it is deallocated
+    - firmware: arm_scmi: Fix doorbell ring logic for !CONFIG_64BIT
+    - mmc: sdio: fix wl1251 vendor id
+    - mmc: core: fix wl1251 sdio quirks
+    - tee: optee: Fix dynamic shm pool allocations
+    - tee: optee: fix device enumeration error handling
+    - workqueue: Add RCU annotation for pwq list walk
+    - SUNRPC: Fix another issue with MIC buffer space
+    - sched/cpufreq: Move the cfs_rq_util_change() call to cpufreq_update_util()
+    - mt76: mt76u: rely on usb_interface instead of usb_dev
+    - dma-direct: don't check swiotlb=force in dma_direct_map_resource
+    - afs: Remove set but not used variables 'before', 'after'
+    - dmaengine: ti: edma: fix missed failure handling
+    - drm/radeon: fix bad DMA from INTERRUPT_CNTL2
+    - xdp: Fix cleanup on map free for devmap_hash map type
+    - platform/chrome: wilco_ec: fix use after free issue
+    - block: fix memleak of bio integrity data
+    - s390/qeth: fix dangling IO buffers after halt/clear
+    - net-sysfs: Call dev_hold always in netdev_queue_add_kobject
+    - gpio: aspeed: avoid return type warning
+    - phy/rockchip: inno-hdmi: round clock rate down to closest 1000 Hz
+    - optee: Fix multi page dynamic shm pool alloc
+    - Linux 5.4.15
+
+  * Focal update: v5.4.14 upstream stable release (LP: #1861090)
+    - ARM: dts: meson8: fix the size of the PMU registers
+    - clk: qcom: gcc-sdm845: Add missing flag to votable GDSCs
+    - soc: amlogic: meson-ee-pwrc: propagate PD provider registration errors
+    - soc: amlogic: meson-ee-pwrc: propagate errors from pm_genpd_init()
+    - dt-bindings: reset: meson8b: fix duplicate reset IDs
+    - ARM: dts: imx6q-dhcom: fix rtc compatible
+    - arm64: dts: ls1028a: fix endian setting for dcfg
+    - arm64: dts: imx8mm: Change SDMA1 ahb clock for imx8mm
+    - bus: ti-sysc: Fix iterating over clocks
+    - clk: Don't try to enable critical clocks if prepare failed
+    - Revert "gpio: thunderx: Switch to GPIOLIB_IRQCHIP"
+    - arm64: dts: imx8mq-librem5-devkit: use correct interrupt for the
+      magnetometer
+    - ASoC: msm8916-wcd-digital: Reset RX interpolation path after use
+    - ASoC: stm32: sai: fix possible circular locking
+    - ASoC: stm32: dfsdm: fix 16 bits record
+    - ASoC: msm8916-wcd-analog: Fix selected events for MIC BIAS External1
+    - ASoC: msm8916-wcd-analog: Fix MIC BIAS Internal1
+    - ARM: OMAP2+: Fix ti_sysc_find_one_clockdomain to check for to_clk_hw_omap
+    - ARM: dts: imx7ulp: fix reg of cpu node
+    - ARM: dts: imx6q-dhcom: Fix SGTL5000 VDDIO regulator connection
+    - ASoC: Intel: bytcht_es8316: Fix Irbis NB41 netbook quirk
+    - ALSA: dice: fix fallback from protocol extension into limited functionality
+    - ALSA: seq: Fix racy access for queue timer in proc read
+    - ALSA: firewire-tascam: fix corruption due to spin lock without restoration
+      in SoftIRQ context
+    - ALSA: usb-audio: fix sync-ep altsetting sanity check
+    - arm64: dts: allwinner: a64: olinuxino: Fix SDIO supply regulator
+    - arm64: dts: allwinner: a64: olinuxino: Fix eMMC supply regulator
+    - arm64: dts: agilex/stratix10: fix pmu interrupt numbers
+    - Fix built-in early-load Intel microcode alignment
+    - clk: sunxi-ng: r40: Allow setting parent rate for external clock outputs
+    - block: fix an integer overflow in logical block size
+    - fuse: fix fuse_send_readpages() in the syncronous read case
+    - io_uring: only allow submit from owning task
+    - cpuidle: teo: Fix intervals[] array indexing bug
+    - ARM: dts: am571x-idk: Fix gpios property to have the correct gpio number
+    - ARM: davinci: select CONFIG_RESET_CONTROLLER
+    - perf: Correctly handle failed perf_get_aux_event()
+    - iio: adc: ad7124: Fix DT channel configuration
+    - iio: imu: st_lsm6dsx: Fix selection of ST_LSM6DS3_ID
+    - iio: light: vcnl4000: Fix scale for vcnl4040
+    - iio: chemical: pms7003: fix unmet triggered buffer dependency
+    - iio: buffer: align the size of scan bytes to size of the largest element
+    - USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx
+    - USB: serial: option: Add support for Quectel RM500Q
+    - USB: serial: opticon: fix control-message timeouts
+    - USB: serial: option: add support for Quectel RM500Q in QDL mode
+    - USB: serial: suppress driver bind attributes
+    - USB: serial: ch341: handle unbound port at reset_resume
+    - USB: serial: io_edgeport: handle unbound ports on URB completion
+    - USB: serial: io_edgeport: add missing active-port sanity check
+    - USB: serial: keyspan: handle unbound ports
+    - USB: serial: quatech2: handle unbound ports
+    - staging: comedi: ni_routes: fix null dereference in ni_find_route_source()
+    - staging: comedi: ni_routes: allow partial routing information
+    - scsi: fnic: fix invalid stack access
+    - scsi: mptfusion: Fix double fetch bug in ioctl
+    - ptrace: reintroduce usage of subjective credentials in ptrace_has_cap()
+    - mtd: rawnand: gpmi: Fix suspend/resume problem
+    - mtd: rawnand: gpmi: Restore nfc timing setup after suspend/resume
+    - usb: core: hub: Improved device recognition on remote wakeup
+    - cpu/SMT: Fix x86 link error without CONFIG_SYSFS
+    - x86/resctrl: Fix an imbalance in domain_remove_cpu()
+    - x86/CPU/AMD: Ensure clearing of SME/SEV features is maintained
+    - locking/rwsem: Fix kernel crash when spinning on RWSEM_OWNER_UNKNOWN
+    - perf/x86/intel/uncore: Fix missing marker for
+      snr_uncore_imc_freerunning_events
+    - x86/efistub: Disable paging at mixed mode entry
+    - s390/zcrypt: Fix CCA cipher key gen with clear key value function
+    - scsi: storvsc: Correctly set number of hardware queues for IDE disk
+    - mtd: spi-nor: Fix selection of 4-byte addressing opcodes on Spansion
+    - drm/i915: Add missing include file <linux/math64.h>
+    - x86/resctrl: Fix potential memory leak
+    - efi/earlycon: Fix write-combine mapping on x86
+    - s390/setup: Fix secure ipl message
+    - clk: samsung: exynos5420: Keep top G3D clocks enabled
+    - perf hists: Fix variable name's inconsistency in hists__for_each() macro
+    - locking/lockdep: Fix buffer overrun problem in stack_trace[]
+    - perf report: Fix incorrectly added dimensions as switch perf data file
+    - mm/shmem.c: thp, shmem: fix conflict of above-47bit hint address and PMD
+      alignment
+    - mm/huge_memory.c: thp: fix conflict of above-47bit hint address and PMD
+      alignment
+    - mm: memcg/slab: fix percpu slab vmstats flushing
+    - mm: memcg/slab: call flush_memcg_workqueue() only if memcg workqueue is
+      valid
+    - mm, debug_pagealloc: don't rely on static keys too early
+    - btrfs: rework arguments of btrfs_unlink_subvol
+    - btrfs: fix invalid removal of root ref
+    - btrfs: do not delete mismatched root refs
+    - btrfs: relocation: fix reloc_root lifespan and access
+    - btrfs: fix memory leak in qgroup accounting
+    - btrfs: check rw_devices, not num_devices for balance
+    - Btrfs: always copy scrub arguments back to user space
+    - mm/memory_hotplug: don't free usage map when removing a re-added early
+      section
+    - mm/page-writeback.c: avoid potential division by zero in wb_min_max_ratio()
+    - mm: khugepaged: add trace status description for SCAN_PAGE_HAS_PRIVATE
+    - ARM: dts: imx6qdl-sabresd: Remove incorrect power supply assignment
+    - ARM: dts: imx6sx-sdb: Remove incorrect power supply assignment
+    - ARM: dts: imx6sl-evk: Remove incorrect power supply assignment
+    - ARM: dts: imx6sll-evk: Remove incorrect power supply assignment
+    - ARM: dts: imx6q-icore-mipi: Use 1.5 version of i.Core MX6DL
+    - ARM: dts: imx7: Fix Toradex Colibri iMX7S 256MB NAND flash support
+    - net: stmmac: 16KB buffer must be 16 byte aligned
+    - net: stmmac: Enable 16KB buffer size
+    - reset: Fix {of,devm}_reset_control_array_get kerneldoc return types
+    - tipc: fix potential hanging after b/rcast changing
+    - tipc: fix retrans failure due to wrong destination
+    - net: fix kernel-doc warning in <linux/netdevice.h>
+    - block: Fix the type of 'sts' in bsg_queue_rq()
+    - drm/amd/display: Reorder detect_edp_sink_caps before link settings read.
+    - bpf: Fix incorrect verifier simulation of ARSH under ALU32
+    - bpf: Sockmap/tls, during free we may call tcp_bpf_unhash() in loop
+    - bpf: Sockmap, ensure sock lock held during tear down
+    - bpf: Sockmap/tls, push write_space updates through ulp updates
+    - bpf: Sockmap, skmsg helper overestimates push, pull, and pop bounds
+    - bpf: Sockmap/tls, msg_push_data may leave end mark in place
+    - bpf: Sockmap/tls, tls_sw can create a plaintext buf > encrypt buf
+    - bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining
+    - bpf: Sockmap/tls, fix pop data with SK_DROP return code
+    - i2c: tegra: Fix suspending in active runtime PM state
+    - i2c: tegra: Properly disable runtime PM on driver's probe error
+    - cfg80211: fix deadlocks in autodisconnect work
+    - cfg80211: fix memory leak in nl80211_probe_mesh_link
+    - cfg80211: fix memory leak in cfg80211_cqm_rssi_update
+    - cfg80211: fix page refcount issue in A-MSDU decap
+    - bpf/sockmap: Read psock ingress_msg before sk_receive_queue
+    - i2c: iop3xx: Fix memory leak in probe error path
+    - netfilter: fix a use-after-free in mtype_destroy()
+    - netfilter: arp_tables: init netns pointer in xt_tgdtor_param struct
+    - netfilter: nat: fix ICMP header corruption on ICMP errors
+    - netfilter: nft_tunnel: fix null-attribute check
+    - netfilter: nft_tunnel: ERSPAN_VERSION must not be null
+    - netfilter: nf_tables: remove WARN and add NLA_STRING upper limits
+    - netfilter: nf_tables: store transaction list locally while requesting module
+    - netfilter: nf_tables: fix flowtable list del corruption
+    - NFC: pn533: fix bulk-message timeout
+    - net: bpf: Don't leak time wait and request sockets
+    - bpftool: Fix printing incorrect pointer in btf_dump_ptr
+    - batman-adv: Fix DAT candidate selection on little endian systems
+    - macvlan: use skb_reset_mac_header() in macvlan_queue_xmit()
+    - hv_netvsc: Fix memory leak when removing rndis device
+    - net: avoid updating qdisc_xmit_lock_key in netdev_update_lockdep_key()
+    - net: dsa: tag_qca: fix doubled Tx statistics
+    - net: hns3: pad the short frame before sending to the hardware
+    - net: hns: fix soft lockup when there is not enough memory
+    - net: phy: dp83867: Set FORCE_LINK_GOOD to default after reset
+    - net/sched: act_ife: initalize ife->metalist earlier
+    - net: usb: lan78xx: limit size of local TSO packets
+    - net/wan/fsl_ucc_hdlc: fix out of bounds write on array utdm_info
+    - ptp: free ptp device pin descriptors properly
+    - r8152: add missing endpoint sanity check
+    - tcp: fix marked lost packets not being retransmitted
+    - bnxt_en: Fix NTUPLE firmware command failures.
+    - bnxt_en: Fix ipv6 RFS filter matching logic.
+    - bnxt_en: Do not treat DSN (Digital Serial Number) read failure as fatal.
+    - net: ethernet: ave: Avoid lockdep warning
+    - net: systemport: Fixed queue mapping in internal ring map
+    - net: dsa: sja1105: Don't error out on disabled ports with no phy-mode
+    - net: dsa: tag_gswip: fix typo in tagger name
+    - net: sched: act_ctinfo: fix memory leak
+    - net: dsa: bcm_sf2: Configure IMP port for 2Gb/sec
+    - i40e: prevent memory leak in i40e_setup_macvlans
+    - drm/amdgpu: allow direct upload save restore list for raven2
+    - sh_eth: check sh_eth_cpu_data::dual_port when dumping registers
+    - mlxsw: spectrum: Do not modify cloned SKBs during xmit
+    - mlxsw: spectrum: Wipe xstats.backlog of down ports
+    - mlxsw: spectrum_qdisc: Include MC TCs in Qdisc counters
+    - net: stmmac: selftests: Make it work in Synopsys AXS101 boards
+    - net: stmmac: selftests: Mark as fail when received VLAN ID != expected
+    - selftests: mlxsw: qos_mc_aware: Fix mausezahn invocation
+    - net: stmmac: selftests: Update status when disabling RSS
+    - net: stmmac: tc: Do not setup flower filtering if RSS is enabled
+    - devlink: Wait longer before warning about unset port type
+    - xen/blkfront: Adjust indentation in xlvbd_alloc_gendisk
+    - dt-bindings: Add missing 'properties' keyword enclosing 'snps,tso'
+    - tcp: refine rule to allow EPOLLOUT generation under mem pressure
+    - irqchip: Place CONFIG_SIFIVE_PLIC into the menu
+    - arm64: dts: qcom: msm8998: Disable coresight by default
+    - cw1200: Fix a signedness bug in cw1200_load_firmware()
+    - arm64: dts: meson: axg: fix audio fifo reg size
+    - arm64: dts: meson: g12: fix audio fifo reg size
+    - arm64: dts: meson-gxl-s905x-khadas-vim: fix gpio-keys-polled node
+    - arm64: dts: renesas: r8a77970: Fix PWM3
+    - arm64: dts: marvell: Add AP806-dual missing CPU clocks
+    - cfg80211: check for set_wiphy_params
+    - tick/sched: Annotate lockless access to last_jiffies_update
+    - arm64: dts: marvell: Fix CP110 NAND controller node multi-line comment
+      alignment
+    - arm64: dts: renesas: r8a774a1: Remove audio port node
+    - arm64: dts: imx8mm-evk: Assigned clocks for audio plls
+    - arm64: dts: qcom: sdm845-cheza: delete zap-shader
+    - ARM: dts: imx6ul-kontron-n6310-s: Disable the snvs-poweroff driver
+    - arm64: dts: allwinner: a64: Re-add PMU node
+    - ARM: dts: dra7: fix cpsw mdio fck clock
+    - arm64: dts: juno: Fix UART frequency
+    - ARM: dts: Fix sgx sysconfig register for omap4
+    - Revert "arm64: dts: juno: add dma-ranges property"
+    - mtd: devices: fix mchp23k256 read and write
+    - mtd: cfi_cmdset_0002: only check errors when ready in cfi_check_err_status()
+    - mtd: cfi_cmdset_0002: fix delayed error detection on HyperFlash
+    - um: Don't trace irqflags during shutdown
+    - um: virtio_uml: Disallow modular build
+    - reiserfs: fix handling of -EOPNOTSUPP in reiserfs_for_each_xattr
+    - 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: lpfc: fix: Coverity: lpfc_get_scsi_buf_s3(): Null pointer dereferences
+    - scsi: qla2xxx: Fix qla2x00_request_irqs() for MSI
+    - scsi: qla2xxx: fix rports not being mark as lost in sync fabric scan
+    - scsi: core: scsi_trace: Use get_unaligned_be*()
+    - scsi: lpfc: Fix list corruption detected in lpfc_put_sgl_per_hdwq
+    - scsi: lpfc: Fix hdwq sgl locks and irq handling
+    - scsi: lpfc: Fix a kernel warning triggered by lpfc_get_sgl_per_hdwq()
+    - rtw88: fix potential read outside array boundary
+    - perf probe: Fix wrong address verification
+    - perf script: Allow --time with --reltime
+    - clk: sprd: Use IS_ERR() to validate the return value of
+      syscon_regmap_lookup_by_phandle()
+    - clk: imx7ulp: Correct system clock source option #7
+    - clk: imx7ulp: Correct DDR clock mux options
+    - regulator: ab8500: Remove SYSCLKREQ from enum ab8505_regulator_id
+    - hwmon: (pmbus/ibm-cffps) Switch LEDs to blocking brightness call
+    - hwmon: (pmbus/ibm-cffps) Fix LED blink behavior
+    - perf script: Fix --reltime with --time
+    - scsi: lpfc: use hdwq assigned cpu for allocation
+    - Linux 5.4.14
+
+  * Focal update: v5.4.13 upstream stable release (LP: #1861085)
+    - HID: hidraw, uhid: Always report EPOLLOUT
+    - rtc: mt6397: fix alarm register overwrite
+    - phy: mapphone-mdm6600: Fix uninitialized status value regression
+    - RDMA/bnxt_re: Avoid freeing MR resources if dereg fails
+    - RDMA/bnxt_re: Fix Send Work Entry state check while polling completions
+    - IB/hfi1: Don't cancel unused work item
+    - mtd: rawnand: stm32_fmc2: avoid to lock the CPU bus
+    - i2c: bcm2835: Store pointer to bus clock
+    - ASoC: SOF: imx8: fix memory allocation failure check on priv->pd_dev
+    - ASoC: soc-core: Set dpcm_playback / dpcm_capture
+    - ASoC: stm32: spdifrx: fix inconsistent lock state
+    - ASoC: stm32: spdifrx: fix race condition in irq handler
+    - ASoC: stm32: spdifrx: fix input pin state management
+    - pinctrl: lochnagar: select GPIOLIB
+    - netfilter: nft_flow_offload: fix underflow in flowtable reference counter
+    - ASoC: SOF: imx8: Fix dsp_box offset
+    - mtd: onenand: omap2: Pass correct flags for prep_dma_memcpy
+    - gpio: zynq: Fix for bug in zynq_gpio_restore_context API
+    - pinctrl: meson: Fix wrong shift value when get drive-strength
+    - selftests: loopback.sh: skip this test if the driver does not support
+    - iommu/vt-d: Unlink device if failed to add to group
+    - iommu: Remove device link to group on failure
+    - bpf: cgroup: prevent out-of-order release of cgroup bpf
+    - fs: move guard_bio_eod() after bio_set_op_attrs
+    - scsi: mpt3sas: Fix double free in attach error handling
+    - gpio: Fix error message on out-of-range GPIO in lookup table
+    - PM / devfreq: tegra: Add COMMON_CLK dependency
+    - PCI: amlogic: Fix probed clock names
+    - drm/tegra: Fix ordering of cleanup code
+    - hsr: add hsr root debugfs directory
+    - hsr: rename debugfs file when interface name is changed
+    - hsr: reset network header when supervision frame is created
+    - s390/qeth: fix qdio teardown after early init error
+    - s390/qeth: fix false reporting of VNIC CHAR config failure
+    - s390/qeth: Fix vnicc_is_in_use if rx_bcast not set
+    - s390/qeth: vnicc Fix init to default
+    - s390/qeth: fix initialization on old HW
+    - cifs: Adjust indentation in smb2_open_file
+    - scsi: smartpqi: Update attribute name to `driver_version`
+    - MAINTAINERS: Append missed file to the database
+    - ath9k: use iowrite32 over __raw_writel
+    - can: j1939: fix address claim code example
+    - dt-bindings: reset: Fix brcmstb-reset example
+    - reset: brcmstb: Remove resource checks
+    - afs: Fix missing cell comparison in afs_test_super()
+    - perf vendor events s390: Remove name from L1D_RO_EXCL_WRITES description
+    - syscalls/x86: Wire up COMPAT_SYSCALL_DEFINE0
+    - syscalls/x86: Use COMPAT_SYSCALL_DEFINE0 for IA32 (rt_)sigreturn
+    - syscalls/x86: Use the correct function type for sys_ni_syscall
+    - syscalls/x86: Fix function types in COND_SYSCALL
+    - hsr: fix slab-out-of-bounds Read in hsr_debugfs_rename()
+    - btrfs: simplify inode locking for RWF_NOWAIT
+    - netfilter: nf_tables_offload: release flow_rule on error from commit path
+    - netfilter: nft_meta: use 64-bit time arithmetic
+    - ASoC: dt-bindings: mt8183: add missing update
+    - ASoC: simple_card_utils.h: Add missing include
+    - ASoC: fsl_esai: Add spin lock to protect reset, stop and start
+    - ASoC: core: Fix compile warning with CONFIG_DEBUG_FS=n
+    - ASoC: rsnd: fix DALIGN register for SSIU
+    - RDMA/hns: Prevent undefined behavior in hns_roce_set_user_sq_size()
+    - RDMA/hns: remove a redundant le16_to_cpu
+    - RDMA/hns: Modify return value of restrack functions
+    - RDMA/counter: Prevent QP counter manual binding in auto mode
+    - RDMA/siw: Fix port number endianness in a debug message
+    - RDMA/hns: Fix build error again
+    - RDMA/hns: Release qp resources when failed to destroy qp
+    - xprtrdma: Add unique trace points for posting Local Invalidate WRs
+    - xprtrdma: Connection becomes unstable after a reconnect
+    - xprtrdma: Fix MR list handling
+    - xprtrdma: Close window between waking RPC senders and posting Receives
+    - RDMA/hns: Fix to support 64K page for srq
+    - RDMA/hns: Bugfix for qpc/cqc timer configuration
+    - rdma: Remove nes ABI header
+    - RDMA/mlx5: Return proper error value
+    - RDMA/srpt: Report the SCSI residual to the initiator
+    - uaccess: Add non-pagefault user-space write function
+    - bpf: Make use of probe_user_write in probe write helper
+    - bpf: skmsg, fix potential psock NULL pointer dereference
+    - bpf: Support pre-2.25-binutils objcopy for vmlinux BTF
+    - libbpf: Fix Makefile' libbpf symbol mismatch diagnostic
+    - afs: Fix use-after-loss-of-ref
+    - afs: Fix afs_lookup() to not clobber the version on a new dentry
+    - keys: Fix request_key() cache
+    - scsi: enclosure: Fix stale device oops with hot replug
+    - scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI
+    - platform/mellanox: fix potential deadlock in the tmfifo driver
+    - platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0
+    - platform/x86: GPD pocket fan: Use default values when wrong modparams are
+      given
+    - asm-generic/nds32: don't redefine cacheflush primitives
+    - Documentation/ABI: Fix documentation inconsistency for mlxreg-io sysfs
+      interfaces
+    - Documentation/ABI: Add missed attribute for mlxreg-io sysfs interfaces
+    - xprtrdma: Fix create_qp crash on device unload
+    - xprtrdma: Fix completion wait during device removal
+    - xprtrdma: Fix oops in Receive handler after device removal
+    - dm: add dm-clone to the documentation index
+    - scsi: ufs: Give an unique ID to each ufs-bsg
+    - crypto: cavium/nitrox - fix firmware assignment to AE cores
+    - crypto: hisilicon - select NEED_SG_DMA_LENGTH in qm Kconfig
+    - crypto: arm64/aes-neonbs - add return value of skcipher_walk_done() in
+      __xts_crypt()
+    - crypto: virtio - implement missing support for output IVs
+    - crypto: algif_skcipher - Use chunksize instead of blocksize
+    - crypto: geode-aes - convert to skcipher API and make thread-safe
+    - NFSv2: Fix a typo in encode_sattr()
+    - nfsd: Fix cld_net->cn_tfm initialization
+    - nfsd: v4 support requires CRYPTO_SHA256
+    - NFSv4.x: Handle bad/dead sessions correctly in nfs41_sequence_process()
+    - NFSv4.x: Drop the slot if nfs4_delegreturn_prepare waits for layoutreturn
+    - iio: imu: st_lsm6dsx: fix gyro gain definitions for LSM9DS1
+    - iio: imu: adis16480: assign bias value only if operation succeeded
+    - mei: fix modalias documentation
+    - clk: meson: axg-audio: fix regmap last register
+    - clk: samsung: exynos5420: Preserve CPU clocks configuration during
+      suspend/resume
+    - clk: Fix memory leak in clk_unregister()
+    - dmaengine: dw: platform: Mark 'hclk' clock optional
+    - clk: imx: pll14xx: Fix quick switch of S/K parameter
+    - rsi: fix potential null dereference in rsi_probe()
+    - affs: fix a memory leak in affs_remount
+    - pinctl: ti: iodelay: fix error checking on pinctrl_count_index_with_args
+      call
+    - pinctrl: sh-pfc: Fix PINMUX_IPSR_PHYS() to set GPSR
+    - pinctrl: sh-pfc: Do not use platform_get_irq() to count interrupts
+    - pinctrl: lewisburg: Update pin list according to v1.1v6
+    - Revert "drm/virtio: switch virtio_gpu_wait_ioctl() to gem helper."
+    - drm/amdgpu: cleanup creating BOs at fixed location (v2)
+    - drm/amdgpu/discovery: reserve discovery data at the top of VRAM
+    - scsi: sd: enable compat ioctls for sed-opal
+    - arm64: dts: apq8096-db820c: Increase load on l21 for SDCARD
+    - af_unix: add compat_ioctl support
+    - compat_ioctl: handle SIOCOUTQNSD
+    - PCI: aardvark: Use LTSSM state to build link training flag
+    - PCI: aardvark: Fix PCI_EXP_RTCTL register configuration
+    - PCI: dwc: Fix find_next_bit() usage
+    - PCI: Fix missing bridge dma_ranges resource list cleanup
+    - PCI/PM: Clear PCIe PME Status even for legacy power management
+    - tools: PCI: Fix fd leakage
+    - PCI/PTM: Remove spurious "d" from granularity message
+    - powerpc/powernv: Disable native PCIe port management
+    - MIPS: PCI: remember nasid changed by set interrupt affinity
+    - MIPS: Loongson: Fix return value of loongson_hwmon_init
+    - MIPS: SGI-IP27: Fix crash, when CPUs are disabled via nr_cpus parameter
+    - tty: serial: imx: use the sg count from dma_map_sg
+    - tty: serial: pch_uart: correct usage of dma_unmap_sg
+    - ARM: 8943/1: Fix topology setup in case of CPU hotplug for CONFIG_SCHED_MC
+    - 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
+    - media: ov6650: Fix default format not applied on device probe
+    - media: rcar-vin: Fix incorrect return statement in rvin_try_format()
+    - media: hantro: h264: Fix the frame_num wraparound case
+    - media: v4l: cadence: Fix how unsued lanes are handled in 'csi2rx_start()'
+    - media: exynos4-is: Fix recursive locking in isp_video_release()
+    - media: coda: fix deadlock between decoder picture run and start command
+    - media: cedrus: Use correct H264 8x8 scaling list
+    - media: hantro: Do not reorder H264 scaling list
+    - media: aspeed-video: Fix memory leaks in aspeed_video_probe
+    - media: hantro: Set H264 FIELDPIC_FLAG_E flag correctly
+    - iommu/mediatek: Correct the flush_iotlb_all callback
+    - iommu/mediatek: Add a new tlb_lock for tlb_flush
+    - memory: mtk-smi: Add PM suspend and resume ops
+    - Revert "ubifs: Fix memory leak bug in alloc_ubifs_info() error path"
+    - ubifs: Fixed missed le64_to_cpu() in journal
+    - ubifs: do_kill_orphans: Fix a memory leak bug
+    - spi: sprd: Fix the incorrect SPI register
+    - mtd: spi-nor: fix silent truncation in spi_nor_read()
+    - mtd: spi-nor: fix silent truncation in spi_nor_read_raw()
+    - spi: pxa2xx: Set controller->max_transfer_size in dma mode
+    - spi: atmel: fix handling of cs_change set on non-last xfer
+    - spi: rspi: Use platform_get_irq_byname_optional() for optional irqs
+    - spi: lpspi: fix memory leak in fsl_lpspi_probe
+    - iwlwifi: mvm: consider ieee80211 station max amsdu value
+    - rtlwifi: Remove unnecessary NULL check in rtl_regd_init
+    - iwlwifi: mvm: fix support for single antenna diversity
+    - sch_cake: Add missing NLA policy entry TCA_CAKE_SPLIT_GSO
+    - f2fs: fix potential overflow
+    - NFSD fixing possible null pointer derefering in copy offload
+    - rtc: msm6242: Fix reading of 10-hour digit
+    - rtc: brcmstb-waketimer: add missed clk_disable_unprepare
+    - rtc: bd70528: Add MODULE ALIAS to autoload module
+    - gpio: mpc8xxx: Add platform device to gpiochip->parent
+    - scsi: libcxgbi: fix NULL pointer dereference in cxgbi_device_destroy()
+    - scsi: target/iblock: Fix protection error with blocks greater than 512B
+    - selftests: firmware: Fix it to do root uid check and skip
+    - rseq/selftests: Turn off timeout setting
+    - riscv: export flush_icache_all to modules
+    - mips: cacheinfo: report shared CPU map
+    - mips: Fix gettimeofday() in the vdso library
+    - tomoyo: Suppress RCU warning at list_for_each_entry_rcu().
+    - MIPS: Prevent link failure with kcov instrumentation
+    - drm/arm/mali: make malidp_mw_connector_helper_funcs static
+    - rxrpc: Unlock new call in rxrpc_new_incoming_call() rather than the caller
+    - rxrpc: Don't take call->user_mutex in rxrpc_new_incoming_call()
+    - rxrpc: Fix missing security check on incoming calls
+    - dmaengine: k3dma: Avoid null pointer traversal
+    - s390/qeth: lock the card while changing its hsuid
+    - ioat: ioat_alloc_ring() failure handling.
+    - drm/amdgpu: enable gfxoff for raven1 refresh
+    - media: intel-ipu3: Align struct ipu3_uapi_awb_fr_config_s to 32 bytes
+    - kbuild/deb-pkg: annotate libelf-dev dependency as :native
+    - hexagon: parenthesize registers in asm predicates
+    - hexagon: work around compiler crash
+    - ocfs2: call journal flush to mark journal as empty after journal recovery
+      when mount
+    - Linux 5.4.13
+    - [Config] updateconfigs following v5.4.13 stable update
+
+  * [hns3-0111]sync mainline kernel 5.5rc6 hns3 patchset into ubuntu HWE kernel
+    branch Edit (LP: #1859261)
+    - net: hns3: make array tick_array static, makes object smaller
+    - net: hns3: add support for setting VF link status on the host
+    - net: hns3: add support for spoof check setting
+    - net: hns3: add support for setting VF trust
+    - net: hns3: add support for configuring bandwidth of VF on the host
+    - net: hns3: add support for configuring VF MAC from the host
+    - net: hns3: support tx-scatter-gather-fraglist feature
+    - net: hns3: remove struct hns3_nic_ring_data in hns3_enet module
+    - net: hns3: optimized MAC address in management table.
+    - net: hns3: minor optimization for barrier in IO path
+    - net: hns3: introduce ring_to_netdev() in enet module
+    - net: hns3: make struct hns3_enet_ring cacheline aligned
+    - net: hns3: minor cleanup for hns3_handle_rx_bd()
+    - net: hns3: do not allocate linear data for fraglist skb
+    - net: hns3: dump some debug information when reset fail
+    - net: hns3: cleanup some magic numbers
+    - net: hns3: cleanup some coding style issues
+    - net: hns3: cleanup a format-truncation warning
+    - net: hns3: optimize local variable initialization
+    - net: hns3: add or modify some comments
+    - net: hns3: cleanup some print format warning
+    - net: hns3: cleanup byte order issues when printed
+    - net: hns3: remove unused macros
+    - net: hns3: fix for TX queue not restarted problem
+    - net: hns3: fix a use after free problem in hns3_nic_maybe_stop_tx()
+    - net: hns3: fix VF ID issue for setting VF VLAN
+
+  * [Dell Vostro 5490] proposed linux-oem-osp1 suspend resume fails
+    (LP: #1860642)
+    - Revert "ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names."
+    - Revert "ASoC: Intel: acpi-match: split CNL tables in three"
+    - Revert "ASoC: SOF: Intel: hda: use fallback for firmware name"
+
+  * shiftfs: prevent lower dentries from going negative during unlink
+    (LP: #1860041)
+    - SAUCE: shiftfs: prevent lower dentries from going negative during unlink
+
+  * [SRU][B/OEM-B/OEM-OSP1/D/E/Unstable] UBUNTU: SAUCE: Use native backlight on
+    Lenovo E41-25/45 (LP: #1859561)
+    - SAUCE: ACPI: video: Use native backlight on Lenovo E41-25/45
+
+  * Dell AIO can't adjust brightness (LP: #1858761)
+    - SAUCE: platform/x86: dell-uart-backlight: add retry for get scalar status
+
+  * [20.04 FEAT] qeth: Support for HiperSockets Multi-Write (LP: #1853292)
+    - s390/qdio: implement IQD Multi-Write
+    - s390/qeth: use IQD Multi-Write
+
+  * debian/tests/corosync: gfs2_jadd fails with ENOTTY for i386 package on amd64
+    kernel (LP: #1859827)
+    - gfs2: add compat_ioctl support
+
+  * Reduce s2idle power consumption when ethernet cable is connected on e1000e
+    (LP: #1859126)
+    - e1000e: Add support for S0ix
+
+  * USB key cannot be detected by hotplug on Sunix USB Type-A 3.1 Gen 2 card
+    [1b21:2142]  (LP: #1858988)
+    - SAUCE: PCI: Avoid ASMedia XHCI USB PME# from D0 defect
+
+  * [scsi-1130]scsi: scsi_transport_sas: Fix memory leak when removing devices
+    (LP: #1854550)
+    - scsi: scsi_transport_sas: Fix memory leak when removing devices
+
+  * Focal update: v5.4.12 upstream stable release (LP: #1860131)
+    - chardev: Avoid potential use-after-free in 'chrdev_open()'
+    - i2c: fix bus recovery stop mode timing
+    - powercap: intel_rapl: add NULL pointer check to rapl_mmio_cpu_online()
+    - usb: chipidea: host: Disable port power only if previously enabled
+    - ALSA: usb-audio: Apply the sample rate quirk for Bose Companion 5
+    - ALSA: hda/realtek - Add new codec supported for ALCS1200A
+    - ALSA: hda/realtek - Set EAPD control to default for ALC222
+    - ALSA: hda/realtek - Add quirk for the bass speaker on Lenovo Yoga X1 7th gen
+    - tpm: Revert "tpm_tis: reserve chip for duration of tpm_tis_core_init"
+    - tpm: Revert "tpm_tis_core: Set TPM_CHIP_FLAG_IRQ before probing for
+      interrupts"
+    - tpm: Revert "tpm_tis_core: Turn on the TPM before probing IRQ's"
+    - tpm: Handle negative priv->response_len in tpm_common_read()
+    - rtc: sun6i: Add support for RTC clocks on R40
+    - 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
+    - tracing: Change offset type to s32 in preempt/irq tracepoints
+    - HID: Fix slab-out-of-bounds read in hid_field_extract
+    - HID: uhid: Fix returning EPOLLOUT from uhid_char_poll
+    - HID: hidraw: Fix returning EPOLLOUT from hidraw_poll
+    - HID: hid-input: clear unmapped usages
+    - Input: add safety guards to input_set_keycode()
+    - Input: input_event - fix struct padding on sparc64
+    - drm/i915: Add Wa_1408615072 and Wa_1407596294 to icl,ehl
+    - Revert "drm/amdgpu: Set no-retry as default."
+    - drm/sun4i: tcon: Set RGB DCLK min. divider based on hardware model
+    - drm/fb-helper: Round up bits_per_pixel if possible
+    - drm/dp_mst: correct the shifting in DP_REMOTE_I2C_READ
+    - drm/i915: Add Wa_1407352427:icl,ehl
+    - drm/i915/gt: Mark up virtual engine uabi_instance
+    - IB/hfi1: Adjust flow PSN with the correct resync_psn
+    - can: kvaser_usb: fix interface sanity check
+    - can: gs_usb: gs_usb_probe(): use descriptors of current altsetting
+    - can: tcan4x5x: tcan4x5x_can_probe(): get the device out of standby before
+      register access
+    - 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
+    - gpiolib: acpi: Turn dmi_system_id table into a generic quirk table
+    - gpiolib: acpi: Add honor_wakeup module-option + quirk mechanism
+    - pstore/ram: Regularize prz label allocation lifetime
+    - staging: vt6656: set usb_set_intfdata on driver fail.
+    - staging: vt6656: Fix non zero logical return of, usb_control_msg
+    - usb: cdns3: should not use the same dev_id for shared interrupt handler
+    - usb: ohci-da8xx: ensure error return on variable error is set
+    - USB-PD tcpm: bad warning+size, PPS adapters
+    - USB: serial: option: add ZLP support for 0x1bc7/0x9010
+    - usb: musb: fix idling for suspend after disconnect interrupt
+    - usb: musb: Disable pullup at init
+    - usb: musb: dma: Correct parameter passed to IRQ handler
+    - staging: comedi: adv_pci1710: fix AI channels 16-31 for PCI-1713
+    - staging: vt6656: correct return of vnt_init_registers.
+    - staging: vt6656: limit reg output to block size
+    - staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21
+    - serdev: Don't claim unsupported ACPI serial devices
+    - iommu/vt-d: Fix adding non-PCI devices to Intel IOMMU
+    - tty: link tty and port before configuring it as console
+    - tty: always relink the port
+    - arm64: Move __ARCH_WANT_SYS_CLONE3 definition to uapi headers
+    - arm64: Implement copy_thread_tls
+    - arm: Implement copy_thread_tls
+    - parisc: Implement copy_thread_tls
+    - riscv: Implement copy_thread_tls
+    - xtensa: Implement copy_thread_tls
+    - clone3: ensure copy_thread_tls is implemented
+    - um: Implement copy_thread_tls
+    - staging: vt6656: remove bool from vnt_radio_power_on ret
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_alloc_cmdrsp_buf
+    - rpmsg: char: release allocated memory
+    - scsi: bfa: release allocated memory in case of error
+    - rtl8xxxu: prevent leaking urb
+    - HID: hiddev: fix mess in hiddev_open()
+    - USB: Fix: Don't skip endpoint descriptors with maxpacket=0
+    - phy: cpcap-usb: Fix error path when no host driver is loaded
+    - phy: cpcap-usb: Fix flakey host idling and enumerating of devices
+    - netfilter: arp_tables: init netns pointer in xt_tgchk_param struct
+    - netfilter: conntrack: dccp, sctp: handle null timeout argument
+    - netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present
+    - drm/i915/gen9: Clear residual context state on context switch
+    - Linux 5.4.12
+
+  * Focal update: v5.4.11 upstream stable release (LP: #1860130)
+    - USB: dummy-hcd: use usb_urb_dir_in instead of usb_pipein
+    - bpf: Fix passing modified ctx to ld/abs/ind instruction
+    - ASoC: rt5682: fix i2c arbitration lost issue
+    - spi: pxa2xx: Add support for Intel Jasper Lake
+    - regulator: fix use after free issue
+    - ASoC: max98090: fix possible race conditions
+    - spi: fsl: Fix GPIO descriptor support
+    - gpio: Handle counting of Freescale chipselects
+    - spi: fsl: Handle the single hardwired chipselect case
+    - locking/spinlock/debug: Fix various data races
+    - netfilter: ctnetlink: netns exit must wait for callbacks
+    - netfilter: nf_tables_offload: Check for the NETDEV_UNREGISTER event
+    - libtraceevent: Fix lib installation with O=
+    - libtraceevent: Copy pkg-config file to output folder when using O=
+    - regulator: core: fix regulator_register() error paths to properly release
+      rdev
+    - x86/efi: Update e820 with reserved EFI boot services data to fix kexec
+      breakage
+    - ASoC: Intel: bytcr_rt5640: Update quirk for Teclast X89
+    - selftests: netfilter: use randomized netns names
+    - efi/gop: Return EFI_NOT_FOUND if there are no usable GOPs
+    - efi/gop: Return EFI_SUCCESS if a usable GOP was found
+    - efi/gop: Fix memory leak in __gop_query32/64()
+    - efi/earlycon: Remap entire framebuffer after page initialization
+    - ARM: dts: imx6ul: imx6ul-14x14-evk.dtsi: Fix SPI NOR probing
+    - ARM: vexpress: Set-up shared OPP table instead of individual for each CPU
+    - netfilter: uapi: Avoid undefined left-shift in xt_sctp.h
+    - netfilter: nft_set_rbtree: bogus lookup/get on consecutive elements in named
+      sets
+    - netfilter: nf_tables: validate NFT_SET_ELEM_INTERVAL_END
+    - netfilter: nf_tables: validate NFT_DATA_VALUE after nft_data_init()
+    - netfilter: nf_tables: skip module reference count bump on object updates
+    - netfilter: nf_tables_offload: return EOPNOTSUPP if rule specifies no actions
+    - ARM: dts: BCM5301X: Fix MDIO node address/size cells
+    - selftests/ftrace: Fix to check the existence of set_ftrace_filter
+    - selftests/ftrace: Fix ftrace test cases to check unsupported
+    - selftests/ftrace: Do not to use absolute debugfs path
+    - selftests/ftrace: Fix multiple kprobe testcase
+    - selftests: safesetid: Move link library to LDLIBS
+    - selftests: safesetid: Check the return value of setuid/setgid
+    - selftests: safesetid: Fix Makefile to set correct test program
+    - ARM: exynos_defconfig: Restore debugfs support
+    - ARM: dts: Cygnus: Fix MDIO node address/size cells
+    - spi: spi-cavium-thunderx: Add missing pci_release_regions()
+    - reset: Do not register resource data for missing resets
+    - ASoC: topology: Check return value for snd_soc_add_dai_link()
+    - ASoC: topology: Check return value for soc_tplg_pcm_create()
+    - ASoC: SOF: loader: snd_sof_fw_parse_ext_data log warning on unknown header
+    - ASoC: SOF: Intel: split cht and byt debug window sizes
+    - ARM: dts: am335x-sancloud-bbe: fix phy mode
+    - ARM: omap2plus_defconfig: Add back DEBUG_FS
+    - ARM: dts: bcm283x: Fix critical trip point
+    - arm64: dts: ls1028a: fix typo in TMU calibration data
+    - bpf, riscv: Limit to 33 tail calls
+    - bpf, mips: Limit to 33 tail calls
+    - bpftool: Don't crash on missing jited insns or ksyms
+    - perf metricgroup: Fix printing event names of metric group with multiple
+      events
+    - perf header: Fix false warning when there are no duplicate cache entries
+    - spi: spi-ti-qspi: Fix a bug when accessing non default CS
+    - ARM: dts: am437x-gp/epos-evm: fix panel compatible
+    - kselftest/runner: Print new line in print of timeout log
+    - kselftest: Support old perl versions
+    - samples: bpf: Replace symbol compare of trace_event
+    - samples: bpf: fix syscall_tp due to unused syscall
+    - arm64: dts: ls1028a: fix reboot node
+    - ARM: imx_v6_v7_defconfig: Explicitly restore CONFIG_DEBUG_FS
+    - pinctrl: aspeed-g6: Fix LPC/eSPI mux configuration
+    - bus: ti-sysc: Fix missing reset delay handling
+    - clk: walk orphan list on clock provider registration
+    - mac80211: fix TID field in monitor mode transmit
+    - cfg80211: fix double-free after changing network namespace
+    - pinctrl: pinmux: fix a possible null pointer in pinmux_can_be_used_for_gpio
+    - powerpc: Ensure that swiotlb buffer is allocated from low memory
+    - btrfs: Fix error messages in qgroup_rescan_init
+    - Btrfs: fix cloning range with a hole when using the NO_HOLES feature
+    - powerpc/vcpu: Assume dedicated processors as non-preempt
+    - powerpc/spinlocks: Include correct header for static key
+    - btrfs: handle error in btrfs_cache_block_group
+    - Btrfs: fix hole extent items with a zero size after range cloning
+    - ocxl: Fix potential memory leak on context creation
+    - bpf: Clear skb->tstamp in bpf_redirect when necessary
+    - habanalabs: rate limit error msg on waiting for CS
+    - habanalabs: remove variable 'val' set but not used
+    - bnx2x: Do not handle requests from VFs after parity
+    - bnx2x: Fix logic to get total no. of PFs per engine
+    - cxgb4: Fix kernel panic while accessing sge_info
+    - net: usb: lan78xx: Fix error message format specifier
+    - parisc: fix compilation when KEXEC=n and KEXEC_FILE=y
+    - parisc: add missing __init annotation
+    - rfkill: Fix incorrect check to avoid NULL pointer dereference
+    - ASoC: wm8962: fix lambda value
+    - regulator: rn5t618: fix module aliases
+    - spi: nxp-fspi: Ensure width is respected in spi-mem operations
+    - clk: at91: fix possible deadlock
+    - staging: axis-fifo: add unspecified HAS_IOMEM dependency
+    - iommu/iova: Init the struct iova to fix the possible memleak
+    - kconfig: don't crash on NULL expressions in expr_eq()
+    - scripts: package: mkdebian: add missing rsync dependency
+    - perf/x86: Fix potential out-of-bounds access
+    - perf/x86/intel: Fix PT PMI handling
+    - sched/psi: Fix sampling error and rare div0 crashes with cgroups and high
+      uptime
+    - psi: Fix a division error in psi poll()
+    - usb: typec: fusb302: Fix an undefined reference to 'extcon_get_state'
+    - block: end bio with BLK_STS_AGAIN in case of non-mq devs and REQ_NOWAIT
+    - fs: avoid softlockups in s_inodes iterators
+    - fs: call fsnotify_sb_delete after evict_inodes
+    - perf/smmuv3: Remove the leftover put_cpu() in error path
+    - iommu/dma: Relax locking in iommu_dma_prepare_msi()
+    - io_uring: don't wait when under-submitting
+    - clk: Move clk_core_reparent_orphans() under CONFIG_OF
+    - net: stmmac: selftests: Needs to check the number of Multicast regs
+    - net: stmmac: Determine earlier the size of RX buffer
+    - net: stmmac: Do not accept invalid MTU values
+    - net: stmmac: xgmac: Clear previous RX buffer size
+    - net: stmmac: RX buffer size must be 16 byte aligned
+    - net: stmmac: Always arm TX Timer at end of transmission start
+    - s390/purgatory: do not build purgatory with kcov, kasan and friends
+    - drm/exynos: gsc: add missed component_del
+    - tpm/tpm_ftpm_tee: add shutdown call back
+    - xsk: Add rcu_read_lock around the XSK wakeup
+    - net/mlx5e: Fix concurrency issues between config flow and XSK
+    - net/i40e: Fix concurrency issues between config flow and XSK
+    - net/ixgbe: Fix concurrency issues between config flow and XSK
+    - platform/x86: pcengines-apuv2: fix simswap GPIO assignment
+    - arm64: cpu_errata: Add Hisilicon TSV110 to spectre-v2 safe list
+    - block: Fix a lockdep complaint triggered by request queue flushing
+    - s390/dasd/cio: Interpret ccw_device_get_mdc return value correctly
+    - s390/dasd: fix memleak in path handling error case
+    - block: fix memleak when __blk_rq_map_user_iov() is failed
+    - parisc: Fix compiler warnings in debug_core.c
+    - sbitmap: only queue kyber's wait callback if not already active
+    - s390/qeth: handle error due to unsupported transport mode
+    - s390/qeth: fix promiscuous mode after reset
+    - s390/qeth: don't return -ENOTSUPP to userspace
+    - llc2: Fix return statement of llc_stat_ev_rx_null_dsap_xid_c (and _test_c)
+    - hv_netvsc: Fix unwanted rx_table reset
+    - selftests: pmtu: fix init mtu value in description
+    - tracing: Do not create directories if lockdown is in affect
+    - gtp: fix bad unlock balance in gtp_encap_enable_socket
+    - macvlan: do not assume mac_header is set in macvlan_broadcast()
+    - net: dsa: mv88e6xxx: Preserve priority when setting CPU port.
+    - net: freescale: fec: Fix ethtool -d runtime PM
+    - net: stmmac: dwmac-sun8i: Allow all RGMII modes
+    - net: stmmac: dwmac-sunxi: Allow all RGMII modes
+    - net: stmmac: Fixed link does not need MDIO Bus
+    - net: usb: lan78xx: fix possible skb leak
+    - pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM
+    - sch_cake: avoid possible divide by zero in cake_enqueue()
+    - 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
+    - vxlan: fix tos value before xmit
+    - mlxsw: spectrum_qdisc: Ignore grafting of invisible FIFO
+    - net: sch_prio: When ungrafting, replace with FIFO
+    - vlan: fix memory leak in vlan_dev_set_egress_priority
+    - vlan: vlan_changelink() should propagate errors
+    - macb: Don't unregister clks unconditionally
+    - net/mlx5: Move devlink registration before interfaces load
+    - net: dsa: mv88e6xxx: force cmode write on 6141/6341
+    - net/mlx5e: Always print health reporter message to dmesg
+    - net/mlx5: DR, No need for atomic refcount for internal SW steering resources
+    - net/mlx5e: Fix hairpin RSS table size
+    - net/mlx5: DR, Init lists that are used in rule's member
+    - usb: dwc3: gadget: Fix request complete check
+    - USB: core: fix check for duplicate endpoints
+    - USB: serial: option: add Telit ME910G1 0x110a composition
+    - usb: missing parentheses in USE_NEW_SCHEME
+    - Linux 5.4.11
+
+  * Focal update: v5.4.10 upstream stable release (LP: #1860127)
+    - powerpc/pmem: Fix kernel crash due to wrong range value usage in
+      flush_dcache_range
+    - Linux 5.4.10
+
+  * Focal update: v5.4.9 upstream stable release (LP: #1860125)
+    - drm/mcde: dsi: Fix invalid pointer dereference if panel cannot be found
+    - nvme_fc: add module to ops template to allow module references
+    - nvme-fc: fix double-free scenarios on hw queues
+    - drm/amdgpu: add check before enabling/disabling broadcast mode
+    - drm/amdgpu: add header line for power profile on Arcturus
+    - drm/amdgpu: add cache flush workaround to gfx8 emit_fence
+    - drm/amd/display: Map DSC resources 1-to-1 if numbers of OPPs and DSCs are
+      equal
+    - drm/amd/display: Fixed kernel panic when booting with DP-to-HDMI dongle
+    - drm/amd/display: Change the delay time before enabling FEC
+    - drm/amd/display: Reset steer fifo before unblanking the stream
+    - drm/amd/display: update dispclk and dppclk vco frequency
+    - nvme/pci: Fix write and poll queue types
+    - nvme/pci: Fix read queue count
+    - iio: st_accel: Fix unused variable warning
+    - iio: adc: max9611: Fix too short conversion time delay
+    - PM / devfreq: Fix devfreq_notifier_call returning errno
+    - PM / devfreq: Set scaling_max_freq to max on OPP notifier error
+    - PM / devfreq: Don't fail devfreq_dev_release if not in list
+    - afs: Fix afs_find_server lookups for ipv4 peers
+    - afs: Fix SELinux setting security label on /afs
+    - RDMA/cma: add missed unregister_pernet_subsys in init failure
+    - rxe: correctly calculate iCRC for unaligned payloads
+    - scsi: lpfc: Fix memory leak on lpfc_bsg_write_ebuf_set func
+    - scsi: qla2xxx: Use explicit LOGO in target mode
+    - scsi: qla2xxx: Drop superfluous INIT_WORK of del_work
+    - scsi: qla2xxx: Don't call qlt_async_event twice
+    - scsi: qla2xxx: Fix PLOGI payload and ELS IOCB dump length
+    - scsi: qla2xxx: Configure local loop for N2N target
+    - scsi: qla2xxx: Send Notify ACK after N2N PLOGI
+    - scsi: qla2xxx: Don't defer relogin unconditonally
+    - scsi: qla2xxx: Ignore PORT UPDATE after N2N PLOGI
+    - scsi: iscsi: qla4xxx: fix double free in probe
+    - scsi: libsas: stop discovering if oob mode is disconnected
+    - scsi: iscsi: Avoid potential deadlock in iscsi_if_rx func
+    - staging/wlan-ng: add CRC32 dependency in Kconfig
+    - drm/nouveau: Move the declaration of struct nouveau_conn_atom up a bit
+    - drm/nouveau: Fix drm-core using atomic code-paths on pre-nv50 hardware
+    - drm/nouveau/kms/nv50-: fix panel scaling
+    - usb: gadget: fix wrong endpoint desc
+    - net: make socket read/write_iter() honor IOCB_NOWAIT
+    - afs: Fix mountpoint parsing
+    - afs: Fix creation calls in the dynamic root to fail with EOPNOTSUPP
+    - raid5: need to set STRIPE_HANDLE for batch head
+    - 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
+    - RDMA/counter: Prevent auto-binding a QP which are not tracked with res
+    - IB/mlx4: Follow mirror sequence of device add during device removal
+    - IB/mlx5: Fix steering rule of drop and count
+    - xen-blkback: prevent premature module unload
+    - xen/balloon: fix ballooned page accounting without hotplug enabled
+    - ALSA: hda/realtek - Add Bass Speaker and fixed dac for bass speaker
+    - ALSA: hda/realtek - Enable the bass speaker of ASUS UX431FLC
+    - ALSA: hda - fixup for the bass speaker on Lenovo Carbon X1 7th gen
+    - tcp: fix data-race in tcp_recvmsg()
+    - shmem: pin the file in shmem_fault() if mmap_sem is dropped
+    - taskstats: fix data-race
+    - ALSA: hda - Downgrade error message for single-cmd fallback
+    - netfilter: nft_tproxy: Fix port selector on Big Endian
+    - block: add bio_truncate to fix guard_bio_eod
+    - mm: drop mmap_sem before calling balance_dirty_pages() in write fault
+    - ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code
+    - ALSA: usb-audio: fix set_format altsetting sanity check
+    - ALSA: hda - Apply sync-write workaround to old Intel platforms, too
+    - ALSA: hda/realtek - Add headset Mic no shutup for ALC283
+    - drm/sun4i: hdmi: Remove duplicate cleanup calls
+    - drm/amdgpu/smu: add metrics table lock
+    - drm/amdgpu/smu: add metrics table lock for arcturus (v2)
+    - drm/amdgpu/smu: add metrics table lock for navi (v2)
+    - drm/amdgpu/smu: add metrics table lock for vega20 (v2)
+    - MIPS: BPF: Disable MIPS32 eBPF JIT
+    - MIPS: BPF: eBPF JIT: check for MIPS ISA compliance in Kconfig
+    - MIPS: Avoid VDSO ABI breakage due to global register variable
+    - media: pulse8-cec: fix lost cec_transmit_attempt_done() call
+    - media: cec: CEC 2.0-only bcast messages were ignored
+    - media: cec: avoid decrementing transmit_queue_sz if it is 0
+    - media: cec: check 'transmit_in_progress', not 'transmitting'
+    - mm/memory_hotplug: shrink zones when offlining memory
+    - mm/zsmalloc.c: fix the migrated zspage statistics.
+    - memcg: account security cred as well to kmemcg
+    - mm: move_pages: return valid node id in status if the page is already on the
+      target node
+    - mm/oom: fix pgtables units mismatch in Killed process message
+    - ocfs2: fix the crash due to call ocfs2_get_dlm_debug once less
+    - pstore/ram: Write new dumps to start of recycled zones
+    - pstore/ram: Fix error-path memory leak in persistent_ram_new() callers
+    - gcc-plugins: make it possible to disable CONFIG_GCC_PLUGINS again
+    - locks: print unsigned ino in /proc/locks
+    - selftests/seccomp: Zero out seccomp_notif
+    - seccomp: Check that seccomp_notif is zeroed out by the user
+    - samples/seccomp: Zero out members based on seccomp_notif_sizes
+    - selftests/seccomp: Catch garbage on SECCOMP_IOCTL_NOTIF_RECV
+    - dmaengine: Fix access to uninitialized dma_slave_caps
+    - dmaengine: dma-jz4780: Also break descriptor chains on JZ4725B
+    - Btrfs: fix infinite loop during nocow writeback due to race
+    - compat_ioctl: block: handle Persistent Reservations
+    - compat_ioctl: block: handle BLKREPORTZONE/BLKRESETZONE
+    - compat_ioctl: block: handle BLKGETZONESZ/BLKGETNRZONES
+    - bpf: Fix precision tracking for unbounded scalars
+    - ata: libahci_platform: Export again ahci_platform_<en/dis>able_phys()
+    - ata: ahci_brcm: Fix AHCI resources management
+    - ata: ahci_brcm: Add missing clock management during recovery
+    - ata: ahci_brcm: BCM7425 AHCI requires AHCI_HFLAG_DELAY_ENGINE
+    - libata: Fix retrieving of active qcs
+    - gpio: xtensa: fix driver build
+    - gpiolib: fix up emulated open drain outputs
+    - clocksource: riscv: add notrace to riscv_sched_clock
+    - riscv: ftrace: correct the condition logic in function graph tracer
+    - rseq/selftests: Fix: Namespace gettid() for compatibility with glibc 2.30
+    - tracing: Fix lock inversion in trace_event_enable_tgid_record()
+    - tracing: Avoid memory leak in process_system_preds()
+    - tracing: Have the histogram compare functions convert to u64 first
+    - tracing: Fix endianness bug in histogram trigger
+    - samples/trace_printk: Wait for IRQ work to finish
+    - io_uring: use current task creds instead of allocating a new one
+    - mm/gup: fix memory leak in __gup_benchmark_ioctl
+    - apparmor: fix aa_xattrs_match() may sleep while holding a RCU lock
+    - dmaengine: virt-dma: Fix access after free in vchan_complete()
+    - gen_initramfs_list.sh: fix 'bad variable name' error
+    - ALSA: cs4236: fix error return comparison of an unsigned integer
+    - ALSA: pcm: Yet another missing check of non-cached buffer type
+    - ALSA: firewire-motu: Correct a typo in the clock proc string
+    - scsi: lpfc: Fix rpi release when deleting vport
+    - exit: panic before exit_mm() on global init exit
+    - ftrace: Avoid potential division by zero in function profiler
+    - spi: spi-fsl-dspi: Fix 16-bit word order in 32-bit XSPI mode
+    - drm/msm: include linux/sched/task.h
+    - PM / devfreq: Check NULL governor in available_governors_show
+    - sunrpc: fix crash when cache_head become valid before update
+    - arm64: dts: qcom: msm8998-clamshell: Remove retention idle state
+    - nfsd4: fix up replay_matches_cache()
+    - powerpc: Chunk calls to flush_dcache_range in arch_*_memory
+    - HID: i2c-hid: Reset ALPS touchpads on resume
+    - net/sched: annotate lockless accesses to qdisc->empty
+    - kernel/module.c: wakeup processes in module_wq on module unload
+    - ACPI: sysfs: Change ACPI_MASKABLE_GPE_MAX to 0x100
+    - perf callchain: Fix segfault in thread__resolve_callchain_sample()
+    - iommu/vt-d: Remove incorrect PSI capability check
+    - of: overlay: add_changeset_property() memory leak
+    - cifs: Fix potential softlockups while refreshing DFS cache
+    - firmware: arm_scmi: Avoid double free in error flow
+    - xfs: don't check for AG deadlock for realtime files in bunmapi
+    - platform/x86: pmc_atom: Add Siemens CONNECT X300 to critclk_systems DMI
+      table
+    - netfilter: nf_queue: enqueue skbs with NULL dst
+    - net, sysctl: Fix compiler warning when only cBPF is present
+    - watchdog: tqmx86_wdt: Fix build error
+    - regulator: axp20x: Fix axp20x_set_ramp_delay
+    - regulator: bd70528: Remove .set_ramp_delay for bd70528_ldo_ops
+    - spi: uniphier: Fix FIFO threshold
+    - regulator: axp20x: Fix AXP22x ELDO2 regulator enable bitmask
+    - powerpc/mm: Mark get_slice_psize() & slice_addr_is_low() as notrace
+    - Bluetooth: btusb: fix PM leak in error case of setup
+    - Bluetooth: delete a stray unlock
+    - Bluetooth: Fix memory leak in hci_connect_le_scan
+    - arm64: dts: meson-gxl-s905x-khadas-vim: fix uart_A bluetooth node
+    - arm64: dts: meson-gxm-khadas-vim2: fix uart_A bluetooth node
+    - media: flexcop-usb: ensure -EIO is returned on error condition
+    - regulator: ab8500: Remove AB8505 USB regulator
+    - media: usb: fix memory leak in af9005_identify_state
+    - dt-bindings: clock: renesas: rcar-usb2-clock-sel: Fix typo in example
+    - arm64: dts: meson: odroid-c2: Disable usb_otg bus to avoid power failed
+      warning
+    - phy: renesas: rcar-gen3-usb2: Use platform_get_irq_optional() for optional
+      irq
+    - tty: serial: msm_serial: Fix lockup for sysrq and oops
+    - cifs: Fix lookup of root ses in DFS referral cache
+    - fs: cifs: Fix atime update check vs mtime
+    - fix compat handling of FICLONERANGE, FIDEDUPERANGE and FS_IOC_FIEMAP
+    - ath9k_htc: Modify byte order for an error message
+    - ath9k_htc: Discard undersized packets
+    - drm/i915/execlists: Fix annotation for decoupling virtual request
+    - xfs: periodically yield scrub threads to the scheduler
+    - net: add annotations on hh->hh_len lockless accesses
+    - ubifs: ubifs_tnc_start_commit: Fix OOB in layout_in_gaps
+    - btrfs: get rid of unique workqueue helper functions
+    - Btrfs: only associate the locked page with one async_chunk struct
+    - s390/smp: fix physical to logical CPU map for SMT
+    - mm/sparse.c: mark populate_section_memmap as __meminit
+    - xen/blkback: Avoid unmapping unmapped grant pages
+    - lib/ubsan: don't serialize UBSAN report
+    - efi: Don't attempt to map RCI2 config table if it doesn't exist
+    - perf/x86/intel/bts: Fix the use of page_private()
+    - net: annotate lockless accesses to sk->sk_pacing_shift
+    - hsr: avoid debugfs warning message when module is remove
+    - hsr: fix error handling routine in hsr_dev_finalize()
+    - hsr: fix a race condition in node list insertion and deletion
+    - mm/hugetlb: defer freeing of huge pages if in non-task context
+    - Linux 5.4.9
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Update package name in getabis repo list
+    - [Packaging] Fix ubuntu-regression-suite python dependency for hwe kernel
+    - [Config] Fix typo in annotations file
+    - [Packaging] move linux-doc and linux-libc-dev stubs to debian.master
+    - update dkms package versions
+
+  * Miscellaneous upstream changes
+    - ASoC: SOF: Intel: fix HDA codec driver probe with multiple controllers
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Thu, 30 Jan 2020 16:34:17 +0100
+
+linux-5.4 (5.4.0-12.15) focal; urgency=medium
+
+  * No change, rebuild to use new binutils
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Tue, 21 Jan 2020 14:43:14 +0100
+
+linux-5.4 (5.4.0-11.14) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Update ubuntu-regression-suite dependency to python2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 09 Jan 2020 09:35:50 -0600
+
+linux-5.4 (5.4.0-10.13) focal; urgency=medium
+
+  * focal/linux-5.4: 5.4.0-10.13 -proposed tracker (LP: #1858880)
+
+  * PAN is broken for execute-only user mappings on ARMv8 (LP: #1858815)
+    - arm64: Revert support for execute-only user mappings
+
+  * linux build and autopkg tests need to use python2 instead of python
+    (LP: #1858487)
+    - [Packaging] Remove python-dev build dependency
+
+  * Support ath10k hardware rfkill (LP: #1858166)
+    - ath10k: add support for hardware rfkill
+
+  * [SRU][B/OEM-B/OEM-OSP1/D/E/F] Add LG I2C touchscreen multitouch support
+    (LP: #1857541)
+    - SAUCE: HID: multitouch: Add LG MELF0410 I2C touchscreen support
+
+  * usb-audio: the mic can't record any sound after resume on Dell Dock WD19
+    (LP: #1857496)
+    - ALSA: usb-audio: set the interface format after resume on Dell WD19
+
+  * alsa/sof: load different firmware on different platforms (LP: #1857409)
+    - ASoC: SOF: Intel: hda: use fallback for firmware name
+    - ASoC: Intel: acpi-match: split CNL tables in three
+    - ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names.
+
+  * Make vfio-pci built-in or xhci_hcd optional (LP: #1770845)
+    - [Config]: built-in VFIO_PCI for amd64
+
+  * multi-zone raid0 corruption (LP: #1850540)
+    - SAUCE: md/raid0: Link to wiki with guidance on multi-zone RAID0 layout
+      migration
+
+  * [hpre-1017]sync mainline kernel 5.4rc3 hpre patchset into ubuntu HWE kernel
+    branch (LP: #1850117) // [acc-1130]sync mainline kernel 5.5rc1 acc  patchset
+    into ubuntu HWE kernel branch (LP: #1854549)
+    - [Config] Enable HISI crypto drivers and update previous module
+
+  * [hpre-1017]sync mainline kernel 5.4rc3 hpre patchset into ubuntu HWE kernel
+    branch (LP: #1850117)
+    - crypto: hisilicon - add HiSilicon HPRE accelerator
+    - crypto: hisilicon - add SRIOV support for HPRE
+    - crypto: hisilicon - Add debugfs for HPRE
+    - MAINTAINERS: Add maintainer for HiSilicon HPRE driver
+    - Documentation: Add debugfs doc for hisi_hpre
+
+  * [acc-1130]sync mainline kernel 5.5rc1 acc  patchset into ubuntu HWE kernel
+    branch (LP: #1854549)
+    - crypto: hisilicon - allow compile-testing on x86
+    - crypto: hisilicon - merge sgl support to hisi_qm module
+    - crypto: hisilicon - add sgl_sge_nr module param for zip
+    - crypto: hisilicon - fix large sgl memory allocation problem when disable
+      smmu
+    - crypto: hisilicon - misc fix about sgl
+    - crypto: hisilicon - select NEED_SG_DMA_LENGTH in qm Kconfig
+    - crypto: hisilicon: Fix misuse of GENMASK macro
+    - crypto: hisilicon - tiny fix about QM/ZIP error callback print
+    - crypto: hisilicon - Fix using plain integer as NULL pointer
+    - crypto: hisilicon - fix param should be static when not external.
+    - crypto: hisilicon - fix endianness verification problem of QM
+    - crypto: hisilicon - use sgl API to get sgl dma addr and len
+    - crypto: hisilicon - fix to return sub-optimal device when best device has no
+      qps
+    - crypto: hisilicon - replace #ifdef with IS_ENABLED for CONFIG_NUMA
+    - crypto: hisilicon - add vfs_num module param for zip
+    - crypto: hisilicon - no need to check return value of debugfs_create
+      functions
+    - crypto: hisilicon - add HiSilicon SEC V2 driver
+    - crypto: hisilicon - add SRIOV for HiSilicon SEC
+    - crypto: hisilicon - add DebugFS for HiSilicon SEC
+    - crypto: hisilicon - fix a NULL vs IS_ERR() bug in sec_create_qp_ctx()
+    - hwrng: hisi - add HiSilicon TRNG driver support
+    - MAINTAINERS: Add maintainer for HiSilicon TRNG V2 driver
+    - MAINTAINERS: Add maintainer for HiSilicon SEC V2 driver
+    - Documentation: add DebugFS doc for HiSilicon SEC
+
+  * [sas-1130]enable sas DFX Function for 1620 soc (LP: #1854548)
+    - scsi: hisi_sas: Don't create debugfs dump folder twice
+    - scsi: hisi_sas: Set the BIST init value before enabling BIST
+    - scsi: hisi_sas: Add timestamp for a debugfs dump
+    - scsi: hisi_sas: Add debugfs file structure for CQ
+    - scsi: hisi_sas: Add debugfs file structure for DQ
+    - scsi: hisi_sas: Add debugfs file structure for registers
+    - scsi: hisi_sas: Add debugfs file structure for port
+    - scsi: hisi_sas: Add debugfs file structure for IOST
+    - scsi: hisi_sas: Add debugfs file structure for ITCT
+    - scsi: hisi_sas: Add debugfs file structure for IOST cache
+    - scsi: hisi_sas: Add debugfs file structure for ITCT cache
+    - scsi: hisi_sas: Allocate memory for multiple dumps of debugfs
+    - scsi: hisi_sas: Add module parameter for debugfs dump count
+    - scsi: hisi_sas: Add ability to have multiple debugfs dumps
+    - scsi: hisi_sas: Record the phy down event in debugfs
+    - scsi: hisi_sas: Relocate call to hisi_sas_debugfs_exit()
+
+  * scsi: hisi_sas: Return directly if init hardware failed (LP: #1855958)
+    - scsi: hisi_sas: Return directly if init hardware failed
+
+  * [sas-1126]scsi: hisi_sas: use wait_for_completion_timeout() when clearing
+    ITCT (LP: #1853999)
+    - scsi: hisi_sas: use wait_for_completion_timeout() when clearing ITCT
+
+  * Focal update: v5.4.8 upstream stable release (LP: #1858429)
+    - Revert "MIPS: futex: Restore \n after sync instructions"
+    - Revert "MIPS: futex: Emit Loongson3 sync workarounds within asm"
+    - scsi: lpfc: Fix spinlock_irq issues in lpfc_els_flush_cmd()
+    - scsi: lpfc: Fix discovery failures when target device connectivity bounces
+    - scsi: mpt3sas: Fix clear pending bit in ioctl status
+    - scsi: lpfc: Fix locking on mailbox command completion
+    - scsi: mpt3sas: Reject NVMe Encap cmnds to unsupported HBA
+    - gpio: mxc: Only get the second IRQ when there is more than one IRQ
+    - scsi: lpfc: Fix list corruption in lpfc_sli_get_iocbq
+    - Input: atmel_mxt_ts - disable IRQ across suspend
+    - f2fs: fix to update time in lazytime mode
+    - powerpc/papr_scm: Fix an off-by-one check in papr_scm_meta_{get, set}
+    - tools/power/x86/intel-speed-select: Remove warning for unused result
+    - platform/x86: peaq-wmi: switch to using polled mode of input devices
+    - iommu: rockchip: Free domain on .domain_free
+    - iommu/tegra-smmu: Fix page tables in > 4 GiB memory
+    - dmaengine: xilinx_dma: Clear desc_pendingcount in xilinx_dma_reset
+    - scsi: target: compare full CHAP_A Algorithm strings
+    - scsi: lpfc: Fix hardlockup in lpfc_abort_handler
+    - scsi: lpfc: Fix SLI3 hba in loop mode not discovering devices
+    - scsi: csiostor: Don't enable IRQs too early
+    - scsi: hisi_sas: Replace in_softirq() check in hisi_sas_task_exec()
+    - scsi: hisi_sas: Delete the debugfs folder of hisi_sas when the probe fails
+    - powerpc/pseries: Mark accumulate_stolen_time() as notrace
+    - powerpc/pseries: Don't fail hash page table insert for bolted mapping
+    - Input: st1232 - do not reset the chip too early
+    - selftests/powerpc: Fixup clobbers for TM tests
+    - powerpc/tools: Don't quote $objdump in scripts
+    - dma-debug: add a schedule point in debug_dma_dump_mappings()
+    - dma-mapping: Add vmap checks to dma_map_single()
+    - dma-mapping: fix handling of dma-ranges for reserved memory (again)
+    - dmaengine: fsl-qdma: Handle invalid qdma-queue0 IRQ
+    - leds: lm3692x: Handle failure to probe the regulator
+    - leds: an30259a: add a check for devm_regmap_init_i2c
+    - leds: trigger: netdev: fix handling on interface rename
+    - clocksource/drivers/asm9260: Add a check for of_clk_get
+    - clocksource/drivers/timer-of: Use unique device name instead of timer
+    - dtc: Use pkg-config to locate libyaml
+    - selftests/powerpc: Skip tm-signal-sigreturn-nt if TM not available
+    - powerpc/security/book3s64: Report L1TF status in sysfs
+    - powerpc/book3s64/hash: Add cond_resched to avoid soft lockup warning
+    - ext4: update direct I/O read lock pattern for IOCB_NOWAIT
+    - ext4: iomap that extends beyond EOF should be marked dirty
+    - 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 unexpected error messages during RSCN handling
+    - scsi: lpfc: Fix duplicate unreg_rpi error in port offline flow
+    - f2fs: fix to update dir's i_pino during cross_rename
+    - clk: qcom: smd: Add missing pnoc clock
+    - clk: qcom: Allow constant ratio freq tables for rcg
+    - clk: clk-gpio: propagate rate change to parent
+    - irqchip/irq-bcm7038-l1: Enable parent IRQ if necessary
+    - irqchip: ingenic: Error out if IRQ domain creation failed
+    - dma-direct: check for overflows on 32 bit DMA addresses
+    - fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long
+    - iommu/arm-smmu-v3: Don't display an error when IRQ lines are missing
+    - i2c: stm32f7: fix & reorder remove & probe error handling
+    - iomap: fix return value of iomap_dio_bio_actor on 32bit systems
+    - Input: ili210x - handle errors from input_mt_init_slots()
+    - scsi: lpfc: fix: Coverity: lpfc_cmpl_els_rsp(): Null pointer dereferences
+    - scsi: zorro_esp: Limit DMA transfers to 65536 bytes (except on Fastlane)
+    - PCI: rpaphp: Fix up pointer to first drc-info entry
+    - scsi: ufs: fix potential bug which ends in system hang
+    - powerpc/pseries/cmm: Implement release() function for sysfs device
+    - PCI: rpaphp: Don't rely on firmware feature to imply drc-info support
+    - PCI: rpaphp: Annotate and correctly byte swap DRC properties
+    - PCI: rpaphp: Correctly match ibm, my-drc-index to drc-name when using drc-
+      info
+    - powerpc/security: Fix wrong message when RFI Flush is disable
+    - powerpc/eeh: differentiate duplicate detection message
+    - powerpc/book3s/mm: Update Oops message to print the correct translation in
+      use
+    - scsi: atari_scsi: sun3_scsi: Set sg_tablesize to 1 instead of SG_NONE
+    - clk: pxa: fix one of the pxa RTC clocks
+    - bcache: at least try to shrink 1 node in bch_mca_scan()
+    - HID: quirks: Add quirk for HP MSU1465 PIXART OEM mouse
+    - dt-bindings: Improve validation build error handling
+    - HID: logitech-hidpp: Silence intermittent get_battery_capacity errors
+    - ARM: 8937/1: spectre-v2: remove Brahma-B53 from hardening
+    - libnvdimm/btt: fix variable 'rc' set but not used
+    - HID: Improve Windows Precision Touchpad detection.
+    - HID: rmi: Check that the RMI_STARTED bit is set before unregistering the RMI
+      transport device
+    - watchdog: imx7ulp: Fix reboot hang
+    - watchdog: prevent deferral of watchdogd wakeup on RT
+    - watchdog: Fix the race between the release of watchdog_core_data and cdev
+    - powerpc/fixmap: Use __fix_to_virt() instead of fix_to_virt()
+    - scsi: pm80xx: Fix for SATA device discovery
+    - scsi: ufs: Fix error handing during hibern8 enter
+    - scsi: scsi_debug: num_tgts must be >= 0
+    - scsi: NCR5380: Add disconnect_mask module parameter
+    - scsi: target: core: Release SPC-2 reservations when closing a session
+    - scsi: ufs: Fix up auto hibern8 enablement
+    - scsi: iscsi: Don't send data to unbound connection
+    - scsi: target: iscsi: Wait for all commands to finish before freeing a
+      session
+    - f2fs: Fix deadlock in f2fs_gc() context during atomic files handling
+    - habanalabs: skip VA block list update in reset flow
+    - gpio/mpc8xxx: fix qoriq GPIO reading
+    - platform/x86: intel_pmc_core: Fix the SoC naming inconsistency
+    - gpio: mpc8xxx: Don't overwrite default irq_set_type callback
+    - gpio: lynxpoint: Setup correct IRQ handlers
+    - tools/power/x86/intel-speed-select: Ignore missing config level
+    - Drivers: hv: vmbus: Fix crash handler reset of Hyper-V synic
+    - apparmor: fix unsigned len comparison with less than zero
+    - drm/amdgpu: Call find_vma under mmap_sem
+    - scripts/kallsyms: fix definitely-lost memory leak
+    - powerpc: Don't add -mabi= flags when building with Clang
+    - cifs: Fix use-after-free bug in cifs_reconnect()
+    - um: virtio: Keep reading on -EAGAIN
+    - io_uring: io_allocate_scq_urings() should return a sane state
+    - of: unittest: fix memory leak in attach_node_and_children
+    - cdrom: respect device capabilities during opening action
+    - cifs: move cifsFileInfo_put logic into a work-queue
+    - perf script: Fix brstackinsn for AUXTRACE
+    - perf regs: Make perf_reg_name() return "unknown" instead of NULL
+    - s390/zcrypt: handle new reply code FILTERED_BY_HYPERVISOR
+    - mailbox: imx: Clear the right interrupts at shutdown
+    - libfdt: define INT32_MAX and UINT32_MAX in libfdt_env.h
+    - s390/unwind: filter out unreliable bogus %r14
+    - s390/cpum_sf: Check for SDBT and SDB consistency
+    - ocfs2: fix passing zero to 'PTR_ERR' warning
+    - mailbox: imx: Fix Tx doorbell shutdown path
+    - s390: disable preemption when switching to nodat stack with CALL_ON_STACK
+    - selftests: vm: add fragment CONFIG_TEST_VMALLOC
+    - mm/hugetlbfs: fix error handling when setting up mounts
+    - kernel: sysctl: make drop_caches write-only
+    - userfaultfd: require CAP_SYS_PTRACE for UFFD_FEATURE_EVENT_FORK
+    - Revert "powerpc/vcpu: Assume dedicated processors as non-preempt"
+    - sctp: fix err handling of stream initialization
+    - md: make sure desc_nr less than MD_SB_DISKS
+    - Revert "iwlwifi: assign directly to iwl_trans->cfg in QuZ detection"
+    - netfilter: ebtables: compat: reject all padding in matches/watchers
+    - 6pack,mkiss: fix possible deadlock
+    - powerpc: Fix __clear_user() with KUAP enabled
+    - net/smc: add fallback check to connect()
+    - netfilter: bridge: make sure to pull arp header in br_nf_forward_arp()
+    - inetpeer: fix data-race in inet_putpeer / inet_putpeer
+    - net: add a READ_ONCE() in skb_peek_tail()
+    - net: icmp: fix data-race in cmp_global_allow()
+    - hrtimer: Annotate lockless access to timer->state
+    - tomoyo: Don't use nifty names on sockets.
+    - uaccess: disallow > INT_MAX copy sizes
+    - drm: limit to INT_MAX in create_blob ioctl
+    - xfs: fix mount failure crash on invalid iclog memory access
+    - cxgb4/cxgb4vf: fix flow control display for auto negotiation
+    - net: dsa: bcm_sf2: Fix IP fragment location and behavior
+    - net/mlxfw: Fix out-of-memory error in mfa2 flash burning
+    - net: phy: aquantia: add suspend / resume ops for AQR105
+    - net/sched: act_mirred: Pull mac prior redir to non mac_header_xmit device
+    - net/sched: add delete_empty() to filters and use it in cls_flower
+    - net_sched: sch_fq: properly set sk->sk_pacing_status
+    - net: stmmac: dwmac-meson8b: Fix the RGMII TX delay on Meson8b/8m2 SoCs
+    - ptp: fix the race between the release of ptp_clock and cdev
+    - tcp: Fix highest_sack and highest_sack_seq
+    - udp: fix integer overflow while computing available space in sk_rcvbuf
+    - bnxt_en: Fix MSIX request logic for RDMA driver.
+    - bnxt_en: Free context memory in the open path if firmware has been reset.
+    - bnxt_en: Return error if FW returns more data than dump length
+    - bnxt_en: Fix bp->fw_health allocation and free logic.
+    - bnxt_en: Remove unnecessary NULL checks for fw_health
+    - bnxt_en: Fix the logic that creates the health reporters.
+    - bnxt_en: Add missing devlink health reporters for VFs.
+    - mlxsw: spectrum_router: Skip loopback RIFs during MAC validation
+    - mlxsw: spectrum: Use dedicated policer for VRRP packets
+    - net: add bool confirm_neigh parameter for dst_ops.update_pmtu
+    - ip6_gre: do not confirm neighbor when do pmtu update
+    - gtp: do not confirm neighbor when do pmtu update
+    - net/dst: add new function skb_dst_update_pmtu_no_confirm
+    - tunnel: do not confirm neighbor when do pmtu update
+    - vti: do not confirm neighbor when do pmtu update
+    - sit: do not confirm neighbor when do pmtu update
+    - net/dst: do not confirm neighbor for vxlan and geneve pmtu update
+    - net: dsa: sja1105: Reconcile the meaning of TPID and TPID2 for E/T and
+      P/Q/R/S
+    - net: marvell: mvpp2: phylink requires the link interrupt
+    - gtp: fix wrong condition in gtp_genl_dump_pdp()
+    - gtp: avoid zero size hashtable
+    - bonding: fix active-backup transition after link failure
+    - tcp: do not send empty skb from tcp_write_xmit()
+    - tcp/dccp: fix possible race __inet_lookup_established()
+    - hv_netvsc: Fix tx_table init in rndis_set_subchannel()
+    - gtp: fix an use-after-free in ipv4_pdp_find()
+    - gtp: do not allow adding duplicate tid and ms_addr pdp context
+    - bnxt: apply computed clamp value for coalece parameter
+    - ipv6/addrconf: only check invalid header values when NETLINK_F_STRICT_CHK is
+      set
+    - net: phylink: fix interface passed to mac_link_up
+    - net: ena: fix napi handler misbehavior when the napi budget is zero
+    - vhost/vsock: accept only packets with the right dst_cid
+    - mmc: sdhci-of-esdhc: fix up erratum A-008171 workaround
+    - mmc: sdhci-of-esdhc: re-implement erratum A-009204 workaround
+    - mm/hugetlbfs: fix for_each_hstate() loop in init_hugetlbfs_fs()
+    - Linux 5.4.8
+
+  * Focal update: v5.4.7 upstream stable release (LP: #1858428) // Focal update:
+    v5.4.8 upstream stable release (LP: #1858429)
+    - [Config] updateconfigs following v5.4.7 stable update
+
+  * Focal update: v5.4.7 upstream stable release (LP: #1858428)
+    - af_packet: set defaule value for tmo
+    - fjes: fix missed check in fjes_acpi_add
+    - mod_devicetable: fix PHY module format
+    - net: dst: Force 4-byte alignment of dst_metrics
+    - net: gemini: Fix memory leak in gmac_setup_txqs
+    - 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: phy: ensure that phy IDs are correctly typed
+    - net: qlogic: Fix error paths in ql_alloc_large_buffers()
+    - net-sysfs: Call dev_hold always in rx_queue_add_kobject
+    - net: usb: lan78xx: Fix suspend/resume PHY register access error
+    - nfp: flower: fix stats id allocation
+    - qede: Disable hardware gro when xdp prog is installed
+    - qede: Fix multicast mac configuration
+    - sctp: fix memleak on err handling of stream initialization
+    - sctp: fully initialize v4 addr in some functions
+    - selftests: forwarding: Delete IPv6 address at the end
+    - neighbour: remove neigh_cleanup() method
+    - bonding: fix bond_neigh_init()
+    - dpaa2-ptp: fix double free of the ptp_qoriq IRQ
+    - mlxsw: spectrum_router: Remove unlikely user-triggerable warning
+    - net: ethernet: ti: davinci_cpdma: fix warning "device driver frees DMA
+      memory with different size"
+    - net: stmmac: platform: Fix MDIO init for platforms without PHY
+    - net: dsa: b53: Fix egress flooding settings
+    - NFC: nxp-nci: Fix probing without ACPI
+    - btrfs: don't double lock the subvol_sem for rename exchange
+    - btrfs: do not call synchronize_srcu() in inode_tree_del
+    - Btrfs: make tree checker detect checksum items with overlapping ranges
+    - btrfs: return error pointer from alloc_test_extent_buffer
+    - Btrfs: fix missing data checksums after replaying a log tree
+    - btrfs: send: remove WARN_ON for readonly mount
+    - btrfs: abort transaction after failed inode updates in create_subvol
+    - btrfs: skip log replay on orphaned roots
+    - btrfs: do not leak reloc root if we fail to read the fs root
+    - btrfs: handle ENOENT in btrfs_uuid_tree_iterate
+    - 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
+    - ALSA: hda/ca0132 - Keep power on during processing DSP response
+    - ALSA: hda/ca0132 - Avoid endless loop
+    - ALSA: hda/ca0132 - Fix work handling in delayed HP detection
+    - drm/vc4/vc4_hdmi: fill in connector info
+    - drm/virtio: switch virtio_gpu_wait_ioctl() to gem helper.
+    - drm: mst: Fix query_payload ack reply struct
+    - drm/mipi-dbi: fix a loop in debugfs code
+    - drm/panel: Add missing drm_panel_init() in panel drivers
+    - drm: exynos: exynos_hdmi: use cec_notifier_conn_(un)register
+    - drm: Use EOPNOTSUPP, not ENOTSUPP
+    - drm/amd/display: verify stream link before link test
+    - drm/bridge: analogix-anx78xx: silence -EPROBE_DEFER warnings
+    - drm/amd/display: OTC underflow fix
+    - iio: max31856: add missing of_node and parent references to iio_dev
+    - iio: light: bh1750: Resolve compiler warning and make code more readable
+    - drm/amdgpu/sriov: add ring_stop before ring_create in psp v11 code
+    - drm/amdgpu: grab the id mgr lock while accessing passid_mapping
+    - drm/ttm: return -EBUSY on pipelining with no_gpu_wait (v2)
+    - drm/amd/display: Rebuild mapped resources after pipe split
+    - ath10k: add cleanup in ath10k_sta_state()
+    - drm/amd/display: Handle virtual signal type in disable_link()
+    - ath10k: Check if station exists before forwarding tx airtime report
+    - spi: Add call to spi_slave_abort() function when spidev driver is released
+    - drm/meson: vclk: use the correct G12A frac max value
+    - staging: rtl8192u: fix multiple memory leaks on error path
+    - staging: rtl8188eu: fix possible null dereference
+    - rtlwifi: prevent memory leak in rtl_usb_probe
+    - libertas: fix a potential NULL pointer dereference
+    - Revert "pinctrl: sh-pfc: r8a77990: Fix MOD_SEL1 bit30 when using SSI_SCK2
+      and SSI_WS2"
+    - Revert "pinctrl: sh-pfc: r8a77990: Fix MOD_SEL1 bit31 when using SIM0_D"
+    - ath10k: fix backtrace on coredump
+    - IB/iser: bound protection_sg size by data_sg size
+    - drm/komeda: Workaround for broken FLIP_COMPLETE timestamps
+    - spi: gpio: prevent memory leak in spi_gpio_probe
+    - media: am437x-vpfe: Setting STD to current value is not an error
+    - media: cedrus: fill in bus_info for media device
+    - media: seco-cec: Add a missing 'release_region()' in an error handling path
+    - media: vim2m: Fix abort issue
+    - media: vim2m: Fix BUG_ON in vim2m_device_release()
+    - media: max2175: Fix build error without CONFIG_REGMAP_I2C
+    - media: ov6650: Fix control handler not freed on init error
+    - media: i2c: ov2659: fix s_stream return value
+    - media: ov6650: Fix crop rectangle alignment not passed back
+    - media: i2c: ov2659: Fix missing 720p register config
+    - media: ov6650: Fix stored frame format not in sync with hardware
+    - media: ov6650: Fix stored crop rectangle not in sync with hardware
+    - tools/power/cpupower: Fix initializer override in hsw_ext_cstates
+    - media: venus: core: Fix msm8996 frequency table
+    - ath10k: fix offchannel tx failure when no ath10k_mac_tx_frm_has_freq
+    - media: vimc: Fix gpf in rmmod path when stream is active
+    - drm/amd/display: Set number of pipes to 1 if the second pipe was disabled
+    - pinctrl: devicetree: Avoid taking direct reference to device name string
+    - drm/sun4i: dsi: Fix TCON DRQ set bits
+    - drm/amdkfd: fix a potential NULL pointer dereference (v2)
+    - x86/math-emu: Check __copy_from_user() result
+    - drm/amd/powerplay: A workaround to GPU RESET on APU
+    - selftests/bpf: Correct path to include msg + path
+    - drm/amd/display: set minimum abm backlight level
+    - media: venus: Fix occasionally failures to suspend
+    - rtw88: fix NSS of hw_cap
+    - drm/amd/display: fix struct init in update_bounding_box
+    - usb: renesas_usbhs: add suspend event support in gadget mode
+    - crypto: aegis128-neon - use Clang compatible cflags for ARM
+    - 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()
+    - tools/memory-model: Fix data race detection for unordered store and load
+    - media: flexcop-usb: fix NULL-ptr deref in flexcop_usb_transfer_init()
+    - media: cec-funcs.h: add status_req checks
+    - media: meson/ao-cec: move cec_notifier_cec_adap_register after hw setup
+    - drm/bridge: dw-hdmi: Refuse DDC/CI transfers on the internal I2C controller
+    - samples: pktgen: fix proc_cmd command result check logic
+    - block: Fix writeback throttling W=1 compiler warnings
+    - drm/amdkfd: Fix MQD size calculation
+    - MIPS: futex: Emit Loongson3 sync workarounds within asm
+    - mwifiex: pcie: Fix memory leak in mwifiex_pcie_init_evt_ring
+    - drm/drm_vblank: Change EINVAL by the correct errno
+    - selftests/bpf: Fix btf_dump padding test case
+    - libbpf: Fix struct end padding in btf_dump
+    - libbpf: Fix passing uninitialized bytes to setsockopt
+    - net/smc: increase device refcount for added link group
+    - team: call RCU read lock when walking the port_list
+    - media: cx88: Fix some error handling path in 'cx8800_initdev()'
+    - crypto: inside-secure - Fix a maybe-uninitialized warning
+    - crypto: aegis128/simd - build 32-bit ARM for v8 architecture explicitly
+    - misc: fastrpc: fix memory leak from miscdev->name
+    - media: ti-vpe: vpe: Fix Motion Vector vpdma stride
+    - 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
+    - media: ti-vpe: vpe: fix a v4l2-compliance failure causing a kernel panic
+    - media: ti-vpe: vpe: ensure buffers are cleaned up properly in abort cases
+    - drm/amd/display: Properly round nominal frequency for SPD
+    - drm/amd/display: wait for set pipe mcp command completion
+    - media: ti-vpe: vpe: fix a v4l2-compliance failure about invalid sizeimage
+    - drm/amd/display: add new active dongle to existent w/a
+    - syscalls/x86: Use the correct function type in SYSCALL_DEFINE0
+    - drm/amd/display: Fix dongle_caps containing stale information.
+    - extcon: sm5502: Reset registers during initialization
+    - drm/amd/display: Program DWB watermarks from correct state
+    - x86/mm: Use the correct function type for native_set_fixmap()
+    - ath10k: Correct error handling of dma_map_single()
+    - rtw88: coex: Set 4 slot mode for A2DP
+    - drm/bridge: dw-hdmi: Restore audio when setting a mode
+    - perf test: Report failure for mmap events
+    - perf report: Add warning when libunwind not compiled in
+    - perf test: Avoid infinite loop for task exit case
+    - perf vendor events arm64: Fix Hisi hip08 DDRC PMU eventname
+    - usb: usbfs: Suppress problematic bind and unbind uevents.
+    - drm/amd/powerplay: avoid disabling ECC if RAS is enabled for VEGA20
+    - iio: adc: max1027: Reset the device at probe time
+    - Bluetooth: btusb: avoid unused function warning
+    - Bluetooth: missed cpu_to_le16 conversion in hci_init4_req
+    - Bluetooth: Workaround directed advertising bug in Broadcom controllers
+    - Bluetooth: hci_core: fix init for HCI_USER_CHANNEL
+    - bpf/stackmap: Fix deadlock with rq_lock in bpf_get_stack()
+    - x86/mce: Lower throttling MCE messages' priority to warning
+    - drm/amd/display: enable hostvm based on roimmu active for dcn2.1
+    - drm/amd/display: fix header for RN clk mgr
+    - drm/amdgpu: fix amdgpu trace event print string format error
+    - staging: iio: ad9834: add a check for devm_clk_get
+    - power: supply: cpcap-battery: Check voltage before orderly_poweroff
+    - perf tests: Disable bp_signal testing for arm64
+    - selftests/bpf: Make a copy of subtest name
+    - net: hns3: log and clear hardware error after reset complete
+    - RDMA/hns: Fix wrong parameters when initial mtt of srq->idx_que
+    - drm/gma500: fix memory disclosures due to uninitialized bytes
+    - ASoC: soc-pcm: fixup dpcm_prune_paths() loop continue
+    - rtl8xxxu: fix RTL8723BU connection failure issue after warm reboot
+    - RDMA/siw: Fix SQ/RQ drain logic
+    - ipmi: Don't allow device module unload when in use
+    - x86/ioapic: Prevent inconsistent state when moving an interrupt
+    - media: cedrus: Fix undefined shift with a SHIFT_AND_MASK_BITS macro
+    - media: aspeed: set hsync and vsync polarities to normal before starting mode
+      detection
+    - drm/nouveau: Don't grab runtime PM refs for HPD IRQs
+    - media: ov6650: Fix stored frame interval not in sync with hardware
+    - media: ad5820: Define entity function
+    - media: ov5640: Make 2592x1944 mode only available at 15 fps
+    - media: st-mipid02: add a check for devm_gpiod_get_optional
+    - media: imx7-mipi-csis: Add a check for devm_regulator_get
+    - media: aspeed: clear garbage interrupts
+    - media: smiapp: Register sensor after enabling runtime PM on the device
+    - md: no longer compare spare disk superblock events in super_load
+    - staging: wilc1000: potential corruption in wilc_parse_join_bss_param()
+    - md/bitmap: avoid race window between md_bitmap_resize and
+      bitmap_file_clear_bit
+    - drm: Don't free jobs in wait_event_interruptible()
+    - EDAC/amd64: Set grain per DIMM
+    - arm64: psci: Reduce the waiting time for cpu_psci_cpu_kill()
+    - drm/amd/display: setting the DIG_MODE to the correct value.
+    - i40e: initialize ITRN registers with correct values
+    - drm/amd/display: correctly populate dpp refclk in fpga
+    - i40e: Wrong 'Advertised FEC modes' after set FEC to AUTO
+    - net: phy: dp83867: enable robust auto-mdix
+    - drm/tegra: sor: Use correct SOR index on Tegra210
+    - regulator: core: Release coupled_rdevs on regulator_init_coupling() error
+    - ubsan, x86: Annotate and allow __ubsan_handle_shift_out_of_bounds() in
+      uaccess regions
+    - spi: sprd: adi: Add missing lock protection when rebooting
+    - ACPI: button: Add DMI quirk for Medion Akoya E2215T
+    - RDMA/qedr: Fix memory leak in user qp and mr
+    - RDMA/hns: Fix memory leak on 'context' on error return path
+    - RDMA/qedr: Fix srqs xarray initialization
+    - RDMA/core: Set DMA parameters correctly
+    - staging: wilc1000: check if device is initialzied before changing vif
+    - gpu: host1x: Allocate gather copy for host1x
+    - net: dsa: LAN9303: select REGMAP when LAN9303 enable
+    - phy: renesas: phy-rcar-gen2: Fix the array off by one warning
+    - phy: qcom-usb-hs: Fix extcon double register after power cycle
+    - s390/time: ensure get_clock_monotonic() returns monotonic values
+    - s390: add error handling to perf_callchain_kernel
+    - s390/mm: add mm_pxd_folded() checks to pxd_free()
+    - net: hns3: add struct netdev_queue debug info for TX timeout
+    - libata: Ensure ata_port probe has completed before detach
+    - loop: fix no-unmap write-zeroes request behavior
+    - net/mlx5e: Verify that rule has at least one fwd/drop action
+    - pinctrl: sh-pfc: sh7734: Fix duplicate TCLK1_B
+    - ALSA: bebob: expand sleep just after breaking connections for protocol
+      version 1
+    - iio: dln2-adc: fix iio_triggered_buffer_postenable() position
+    - libbpf: Fix error handling in bpf_map__reuse_fd()
+    - Bluetooth: Fix advertising duplicated flags
+    - ALSA: pcm: Fix missing check of the new non-cached buffer type
+    - spi: sifive: disable clk when probe fails and remove
+    - ASoC: SOF: imx: fix reverse CONFIG_SND_SOC_SOF_OF dependency
+    - pinctrl: qcom: sc7180: Add missing tile info in SDC_QDSD_PINGROUP/UFS_RESET
+    - pinctrl: amd: fix __iomem annotation in amd_gpio_irq_handler()
+    - ixgbe: protect TX timestamping from API misuse
+    - cpufreq: sun50i: Fix CPU speed bin detection
+    - media: rcar_drif: fix a memory disclosure
+    - media: v4l2-core: fix touch support in v4l_g_fmt
+    - nvme: introduce "Command Aborted By host" status code
+    - media: staging/imx: Use a shorter name for driver
+    - nvmem: imx-ocotp: reset error status on probe
+    - nvmem: core: fix nvmem_cell_write inline function
+    - ASoC: SOF: topology: set trigger order for FE DAI link
+    - media: vivid: media_device_cleanup was called too early
+    - spi: dw: Fix Designware SPI loopback
+    - bnx2x: Fix PF-VF communication over multi-cos queues.
+    - spi: img-spfi: fix potential double release
+    - ALSA: timer: Limit max amount of slave instances
+    - RDMA/core: Fix return code when modify_port isn't supported
+    - drm: msm: a6xx: fix debug bus register configuration
+    - rtlwifi: fix memory leak in rtl92c_set_fw_rsvdpagepkt()
+    - perf probe: Fix to find range-only function instance
+    - perf cs-etm: Fix definition of macro TO_CS_QUEUE_NR
+    - perf probe: Fix to list probe event with correct line number
+    - perf jevents: Fix resource leak in process_mapfile() and main()
+    - 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
+    - libsubcmd: Use -O0 with DEBUG=1
+    - perf probe: Fix to probe a function which has no entry pc
+    - perf tools: Fix cross compile for ARM64
+    - perf tools: Splice events onto evlist even on error
+    - drm/amdgpu: disallow direct upload save restore list from gfx driver
+    - drm/amd/powerplay: fix struct init in renoir_print_clk_levels
+    - drm/amdgpu: fix potential double drop fence reference
+    - ice: Check for null pointer dereference when setting rings
+    - xen/gntdev: Use select for DMA_SHARED_BUFFER
+    - perf parse: If pmu configuration fails free terms
+    - perf probe: Skip overlapped location on searching variables
+    - net: avoid potential false sharing in neighbor related code
+    - 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
+    - libbpf: Fix negative FD close() in xsk_setup_xdp_prog()
+    - s390/bpf: Use kvcalloc for addrs array
+    - cgroup: freezer: don't change task and cgroups status unnecessarily
+    - selftests: proc: Make va_max 1MB
+    - drm/amdgpu: Avoid accidental thread reactivation.
+    - media: exynos4-is: fix wrong mdev and v4l2 dev order in error path
+    - ath10k: fix get invalid tx rate for Mesh metric
+    - fsi: core: Fix small accesses and unaligned offsets via sysfs
+    - selftests: net: Fix printf format warnings on arm
+    - media: pvrusb2: Fix oops on tear-down when radio support is not present
+    - soundwire: intel: fix PDI/stream mapping for Bulk
+    - crypto: atmel - Fix authenc support when it is set to m
+    - ice: delay less
+    - media: si470x-i2c: add missed operations in remove
+    - media: cedrus: Use helpers to access capture queue
+    - media: v4l2-ctrl: Lock main_hdl on operations of requests_queued.
+    - iio: cros_ec_baro: set info_mask_shared_by_all_available field
+    - EDAC/ghes: Fix grain calculation
+    - media: vicodec: media_device_cleanup was called too early
+    - media: vim2m: media_device_cleanup was called too early
+    - spi: pxa2xx: Add missed security checks
+    - ASoC: rt5677: Mark reg RT5677_PWR_ANLG2 as volatile
+    - iio: dac: ad5446: Add support for new AD5600 DAC
+    - bpf, testing: Workaround a verifier failure for test_progs
+    - ASoC: Intel: kbl_rt5663_rt5514_max98927: Add dmic format constraint
+    - net: dsa: sja1105: Disallow management xmit during switch reset
+    - r8169: respect EEE user setting when restarting network
+    - s390/disassembler: don't hide instruction addresses
+    - net: ethernet: ti: Add dependency for TI_DAVINCI_EMAC
+    - nvme: Discard workaround for non-conformant devices
+    - parport: load lowlevel driver if ports not found
+    - bcache: fix static checker warning in bcache_device_free()
+    - cpufreq: Register drivers only after CPU devices have been registered
+    - qtnfmac: fix debugfs support for multiple cards
+    - qtnfmac: fix invalid channel information output
+    - x86/crash: Add a forward declaration of struct kimage
+    - qtnfmac: fix using skb after free
+    - RDMA/efa: Clear the admin command buffer prior to its submission
+    - tracing: use kvcalloc for tgid_map array allocation
+    - MIPS: ralink: enable PCI support only if driver for mt7621 SoC is selected
+    - tracing/kprobe: Check whether the non-suffixed symbol is notrace
+    - iwlwifi: mvm: fix unaligned read of rx_pkt_status
+    - ASoC: wm8904: fix regcache handling
+    - regulator: core: Let boot-on regulators be powered off
+    - spi: tegra20-slink: add missed clk_unprepare
+    - tun: fix data-race in gro_normal_list()
+    - xhci-pci: Allow host runtime PM as default also for Intel Ice Lake xHCI
+    - crypto: virtio - deal with unsupported input sizes
+    - mmc: tmio: Add MMC_CAP_ERASE to allow erase/discard/trim requests
+    - btrfs: don't prematurely free work in end_workqueue_fn()
+    - btrfs: don't prematurely free work in run_ordered_work()
+    - sched/uclamp: Fix overzealous type replacement
+    - ASoC: wm2200: add missed operations in remove and probe failure
+    - spi: st-ssc4: add missed pm_runtime_disable
+    - ASoC: wm5100: add missed pm_runtime_disable
+    - perf/core: Fix the mlock accounting, again
+    - selftests, bpf: Fix test_tc_tunnel hanging
+    - selftests, bpf: Workaround an alu32 sub-register spilling issue
+    - bnxt_en: Return proper error code for non-existent NVM variable
+    - net: phy: avoid matching all-ones clause 45 PHY IDs
+    - firmware_loader: Fix labels with comma for builtin firmware
+    - ASoC: Intel: bytcr_rt5640: Update quirk for Acer Switch 10 SW5-012 2-in-1
+    - x86/insn: Add some Intel instructions to the opcode map
+    - net-af_xdp: Use correct number of channels from ethtool
+    - brcmfmac: remove monitor interface when detaching
+    - perf session: Fix decompression of PERF_RECORD_COMPRESSED records
+    - perf probe: Fix to show function entry line as probe-able
+    - s390/crypto: Fix unsigned variable compared with zero
+    - s390/kasan: support memcpy_real with TRACE_IRQFLAGS
+    - bnxt_en: Improve RX buffer error handling.
+    - iwlwifi: check kasprintf() return value
+    - fbtft: Make sure string is NULL terminated
+    - ASoC: soc-pcm: check symmetry before hw_params
+    - net: ethernet: ti: ale: clean ale tbl on init and intf restart
+    - mt76: fix possible out-of-bound access in mt7615_fill_txs/mt7603_fill_txs
+    - s390/cpumf: Adjust registration of s390 PMU device drivers
+    - crypto: sun4i-ss - Fix 64-bit size_t warnings
+    - crypto: sun4i-ss - Fix 64-bit size_t warnings on sun4i-ss-hash.c
+    - mac80211: consider QoS Null frames for STA_NULLFUNC_ACKED
+    - crypto: vmx - Avoid weird build failures
+    - libtraceevent: Fix memory leakage in copy_filter_type
+    - mips: fix build when "48 bits virtual memory" is enabled
+    - drm/amdgpu: fix bad DMA from INTERRUPT_CNTL2
+    - ice: Only disable VF state when freeing each VF resources
+    - ice: Fix setting coalesce to handle DCB configuration
+    - net: phy: initialise phydev speed and duplex sanely
+    - tools, bpf: Fix build for 'make -s tools/bpf O=<dir>'
+    - RDMA/bnxt_re: Fix missing le16_to_cpu
+    - RDMA/bnxt_re: Fix stat push into dma buffer on gen p5 devices
+    - bpf: Provide better register bounds after jmp32 instructions
+    - RDMA/bnxt_re: Fix chip number validation Broadcom's Gen P5 series
+    - ibmvnic: Fix completion structure initialization
+    - net: wireless: intel: iwlwifi: fix GRO_NORMAL packet stalling
+    - MIPS: futex: Restore \n after sync instructions
+    - btrfs: don't prematurely free work in reada_start_machine_worker()
+    - btrfs: don't prematurely free work in scrub_missing_raid56_worker()
+    - Revert "mmc: sdhci: Fix incorrect switch to HS mode"
+    - mmc: mediatek: fix CMD_TA to 2 for MT8173 HS200/HS400 mode
+    - tpm_tis: reserve chip for duration of tpm_tis_core_init
+    - tpm: fix invalid locking in NONBLOCKING mode
+    - iommu: fix KASAN use-after-free in iommu_insert_resv_region
+    - iommu: set group default domain before creating direct mappings
+    - iommu/vt-d: Fix dmar pte read access not set error
+    - iommu/vt-d: Set ISA bridge reserved region as relaxable
+    - iommu/vt-d: Allocate reserved region for ISA with correct permission
+    - can: xilinx_can: Fix missing Rx can packets on CANFD2.0
+    - can: m_can: tcan4x5x: add required delay after reset
+    - can: j1939: j1939_sk_bind(): take priv after lock is held
+    - can: flexcan: fix possible deadlock and out-of-order reception after wakeup
+    - can: flexcan: poll MCR_LPM_ACK instead of GPR ACK for stop mode
+      acknowledgment
+    - can: kvaser_usb: kvaser_usb_leaf: Fix some info-leaks to USB devices
+    - spi: dw: Correct handling of native chipselect
+    - spi: cadence: Correct handling of native chipselect
+    - usb: xhci: Fix build warning seen with CONFIG_PM=n
+    - drm/amdgpu: fix uninitialized variable pasid_mapping_needed
+    - ath10k: Revert "ath10k: add cleanup in ath10k_sta_state()"
+    - RDMA/siw: Fix post_recv QP state locking
+    - md: avoid invalid memory access for array sb->dev_roles
+    - s390/ftrace: fix endless recursion in function_graph tracer
+    - ARM: dts: Fix vcsi regulator to be always-on for droid4 to prevent hangs
+    - can: flexcan: add low power enter/exit acknowledgment helper
+    - usbip: Fix receive error in vhci-hcd when using scatter-gather
+    - usbip: Fix error path of vhci_recv_ret_submit()
+    - spi: fsl: don't map irq during probe
+    - spi: fsl: use platform_get_irq() instead of of_irq_to_resource()
+    - efi/memreserve: Register reservations as 'reserved' in /proc/iomem
+    - cpufreq: Avoid leaving stale IRQ work items during CPU offline
+    - KEYS: asymmetric: return ENOMEM if akcipher_request_alloc() fails
+    - mm: vmscan: protect shrinker idr replace with CONFIG_MEMCG
+    - USB: EHCI: Do not return -EPIPE when hub is disconnected
+    - intel_th: pci: Add Comet Lake PCH-V support
+    - intel_th: pci: Add Elkhart Lake SOC support
+    - intel_th: Fix freeing IRQs
+    - intel_th: msu: Fix window switching without windows
+    - platform/x86: hp-wmi: Make buffer for HPWMI_FEATURE2_QUERY 128 bytes
+    - staging: comedi: gsc_hpdi: check dma_alloc_coherent() return value
+    - tty/serial: atmel: fix out of range clock divider handling
+    - serial: sprd: Add clearing break interrupt operation
+    - pinctrl: baytrail: Really serialize all register accesses
+    - clk: imx: clk-imx7ulp: Add missing sentinel of ulp_div_table
+    - clk: imx: clk-composite-8m: add lock to gate/mux
+    - clk: imx: pll14xx: fix clk_pll14xx_wait_lock
+    - ext4: fix ext4_empty_dir() for directories with holes
+    - ext4: check for directory entries too close to block end
+    - ext4: unlock on error in ext4_expand_extra_isize()
+    - ext4: validate the debug_want_extra_isize mount option at parse time
+    - iocost: over-budget forced IOs should schedule async delay
+    - KVM: PPC: Book3S HV: Fix regression on big endian hosts
+    - kvm: x86: Host feature SSBD doesn't imply guest feature SPEC_CTRL_SSBD
+    - kvm: x86: Host feature SSBD doesn't imply guest feature AMD_SSBD
+    - KVM: arm/arm64: Properly handle faulting of device mappings
+    - KVM: arm64: Ensure 'params' is initialised when looking up sys register
+    - x86/MCE/AMD: Do not use rdmsr_safe_on_cpu() in smca_configure()
+    - x86/MCE/AMD: Allow Reserved types to be overwritten in smca_banks[]
+    - x86/mce: Fix possibly incorrect severity calculation on AMD
+    - powerpc/vcpu: Assume dedicated processors as non-preempt
+    - powerpc/irq: fix stack overflow verification
+    - ocxl: Fix concurrent AFU open and device removal
+    - mmc: sdhci-msm: Correct the offset and value for DDR_CONFIG register
+    - mmc: sdhci-of-esdhc: Revert "mmc: sdhci-of-esdhc: add erratum A-009204
+      support"
+    - mmc: sdhci: Update the tuning failed messages to pr_debug level
+    - mmc: sdhci-of-esdhc: fix P2020 errata handling
+    - mmc: sdhci: Workaround broken command queuing on Intel GLK
+    - mmc: sdhci: Add a quirk for broken command queuing
+    - nbd: fix shutdown and recv work deadlock v2
+    - iwlwifi: pcie: move power gating workaround earlier in the flow
+    - Linux 5.4.7
+
+  * Focal update: v5.4.6 upstream stable release (LP: #1858427)
+    - Revert "UBUNTU: SAUCE: drm/i915/fbc: disable framebuffer compression on
+      IceLake"
+    - USB: Fix incorrect DMA allocations for local memory pool drivers
+    - mmc: block: Make card_busy_detect() a bit more generic
+    - mmc: block: Add CMD13 polling for MMC IOCTLS with R1B response
+    - mmc: core: Drop check for mmc_card_is_removable() in mmc_rescan()
+    - mmc: core: Re-work HW reset for SDIO cards
+    - PCI/switchtec: Read all 64 bits of part_event_bitmap
+    - PCI/PM: Always return devices to D0 when thawing
+    - PCI: pciehp: Avoid returning prematurely from sysfs requests
+    - PCI: Fix Intel ACS quirk UPDCR register address
+    - PCI/MSI: Fix incorrect MSI-X masking on resume
+    - PCI: Do not use bus number zero from EA capability
+    - PCI: rcar: Fix missing MACCTLR register setting in initialization sequence
+    - PCI: Apply Cavium ACS quirk to ThunderX2 and ThunderX3
+    - PM / QoS: Redefine FREQ_QOS_MAX_DEFAULT_VALUE to S32_MAX
+    - block: fix "check bi_size overflow before merge"
+    - xtensa: use MEMBLOCK_ALLOC_ANYWHERE for KASAN shadow map
+    - gfs2: Multi-block allocations in gfs2_page_mkwrite
+    - gfs2: fix glock reference problem in gfs2_trans_remove_revoke
+    - xtensa: fix TLB sanity checker
+    - xtensa: fix syscall_set_return_value
+    - rpmsg: glink: Set tail pointer to 0 at end of FIFO
+    - rpmsg: glink: Fix reuse intents memory leak issue
+    - rpmsg: glink: Fix use after free in open_ack TIMEOUT case
+    - rpmsg: glink: Put an extra reference during cleanup
+    - rpmsg: glink: Fix rpmsg_register_device err handling
+    - rpmsg: glink: Don't send pending rx_done during remove
+    - rpmsg: glink: Free pending deferred work on remove
+    - cifs: smbd: Return -EAGAIN when transport is reconnecting
+    - cifs: smbd: Only queue work for error recovery on memory registration
+    - cifs: smbd: Add messages on RDMA session destroy and reconnection
+    - cifs: smbd: Return -EINVAL when the number of iovs exceeds SMBDIRECT_MAX_SGE
+    - cifs: smbd: Return -ECONNABORTED when trasnport is not in connected state
+    - cifs: Don't display RDMA transport on reconnect
+    - CIFS: Respect O_SYNC and O_DIRECT flags during reconnect
+    - CIFS: Close open handle after interrupted close
+    - CIFS: Do not miss cancelled OPEN responses
+    - CIFS: Fix NULL pointer dereference in mid callback
+    - 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
+    - dma-buf: Fix memory leak in sync_file_merge()
+    - drm/panfrost: Fix a race in panfrost_ioctl_madvise()
+    - drm/panfrost: Fix a BO leak in panfrost_ioctl_mmap_bo()
+    - drm/panfrost: Fix a race in panfrost_gem_free_object()
+    - drm/mgag200: Extract device type from flags
+    - drm/mgag200: Store flags from PCI driver data in device structure
+    - drm/mgag200: Add workaround for HW that does not support 'startadd'
+    - drm/mgag200: Flag all G200 SE A machines as broken wrt <startadd>
+    - drm: meson: venc: cvbs: fix CVBS mode matching
+    - dm mpath: remove harmful bio-based optimization
+    - dm btree: increase rebalance threshold in __rebalance2()
+    - dm clone metadata: Track exact changes per transaction
+    - dm clone metadata: Use a two phase commit
+    - dm clone: Flush destination device before committing metadata
+    - dm thin metadata: Add support for a pre-commit callback
+    - dm thin: Flush data device before committing metadata
+    - scsi: ufs: Disable autohibern8 feature in Cadence UFS
+    - scsi: iscsi: Fix a potential deadlock in the timeout handler
+    - scsi: qla2xxx: Ignore NULL pointer in tcm_qla2xxx_free_mcmd
+    - scsi: qla2xxx: Initialize free_work before flushing it
+    - scsi: qla2xxx: Added support for MPI and PEP regions for ISP28XX
+    - scsi: qla2xxx: Change discovery state before PLOGI
+    - scsi: qla2xxx: Correctly retrieve and interpret active flash region
+    - scsi: qla2xxx: Fix incorrect SFUB length used for Secure Flash Update MB Cmd
+    - drm/nouveau/kms/nv50-: Call outp_atomic_check_view() before handling PBN
+    - drm/nouveau/kms/nv50-: Store the bpc we're using in nv50_head_atom
+    - drm/nouveau/kms/nv50-: Limit MST BPC to 8
+    - drm/i915/fbc: Disable fbc by default on all glk+
+    - drm/radeon: fix r1xx/r2xx register checker for POT textures
+    - drm/dp_mst: Correct the bug in drm_dp_update_payload_part1()
+    - drm/amd/display: re-enable wait in pipelock, but add timeout
+    - drm/amd/display: add default clocks if not able to fetch them
+    - drm/amdgpu: initialize vm_inv_eng0_sem for gfxhub and mmhub
+    - drm/amdgpu: invalidate mmhub semaphore workaround in gmc9/gmc10
+    - drm/amdgpu/gfx10: explicitly wait for cp idle after halt/unhalt
+    - drm/amdgpu/gfx10: re-init clear state buffer after gpu reset
+    - drm/i915/gvt: Fix cmd length check for MI_ATOMIC
+    - drm/amdgpu: avoid using invalidate semaphore for picasso
+    - drm/amdgpu: add invalidate semaphore limit for SRIOV and picasso in gmc9
+    - ALSA: hda: Fix regression by strip mask fix
+    - Linux 5.4.6
+
+  * Focal update: v5.4.5 upstream stable release (LP: #1858426)
+    - inet: protect against too small mtu values.
+    - mqprio: Fix out-of-bounds access in mqprio_dump
+    - net: bridge: deny dev_set_mac_address() when unregistering
+    - net: dsa: fix flow dissection on Tx path
+    - net: ethernet: ti: cpsw: fix extra rx interrupt
+    - net: sched: fix dump qlen for sch_mq/sch_mqprio with NOLOCK subqueues
+    - net_sched: validate TCA_KIND attribute in tc_chain_tmplt_add()
+    - net: thunderx: start phy before starting autonegotiation
+    - net/tls: Fix return values to avoid ENOTSUPP
+    - openvswitch: support asymmetric conntrack
+    - tcp: md5: fix potential overestimation of TCP option space
+    - tipc: fix ordering of tipc module init and exit routine
+    - net/mlx5e: Query global pause state before setting prio2buffer
+    - net: ipv6: add net argument to ip6_dst_lookup_flow
+    - net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup
+    - 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: core: rename indirect block ingress cb function
+    - net: sched: allow indirect blocks to bind to clsact in TC
+    - cls_flower: Fix the behavior using port ranges with hw-offload
+    - gre: refetch erspan header from skb->data after pskb_may_pull()
+    - Fixed updating of ethertype in function skb_mpls_pop
+    - hsr: fix a NULL pointer dereference in hsr_dev_xmit()
+    - net: Fixed updating of ethertype in skb_mpls_push()
+    - net/mlx5e: Fix TXQ indices to be sequential
+    - act_ct: support asymmetric conntrack
+    - net/mlx5e: Fix SFF 8472 eeprom length
+    - net/mlx5e: Fix freeing flow with kfree() and not kvfree()
+    - net/mlx5e: Fix translation of link mode into speed
+    - net/mlx5e: ethtool, Fix analysis of speed setting
+    - page_pool: do not release pool until inflight == 0.
+    - xdp: obtain the mem_id mutex before trying to remove an entry.
+    - ionic: keep users rss hash across lif reset
+    - net: mscc: ocelot: unregister the PTP clock on deinit
+    - r8169: add missing RX enabling for WoL on RTL8125
+    - Linux 5.4.5
+
+  * Focal update: v5.4.4 upstream stable release (LP: #1858424)
+    - usb: gadget: configfs: Fix missing spin_lock_init()
+    - usb: gadget: pch_udc: fix use after free
+    - nvme: Namepace identification descriptor list is optional
+    - Revert "nvme: Add quirk for Kingston NVME SSD running FW E8FK11.T"
+    - scsi: lpfc: Fix bad ndlp ptr in xri aborted handling
+    - scsi: zfcp: trace channel log even for FCP command responses
+    - scsi: qla2xxx: Do command completion on abort timeout
+    - scsi: qla2xxx: Fix driver unload hang
+    - scsi: qla2xxx: Fix double scsi_done for abort path
+    - scsi: qla2xxx: Fix memory leak when sending I/O fails
+    - compat_ioctl: add compat_ptr_ioctl()
+    - ceph: fix compat_ioctl for ceph_dir_operations
+    - media: venus: remove invalid compat_ioctl32 handler
+    - USB: uas: honor flag to avoid CAPACITY16
+    - USB: uas: heed CAPACITY_HEURISTICS
+    - USB: documentation: flags on usb-storage versus UAS
+    - usb: Allow USB device to be warm reset in suspended state
+    - usb: host: xhci-tegra: Correct phy enable sequence
+    - binder: fix incorrect calculation for num_valid
+    - staging: exfat: fix multiple definition error of `rename_file'
+    - staging: rtl8188eu: fix interface sanity check
+    - staging: rtl8712: fix interface sanity check
+    - staging: vchiq: call unregister_chrdev_region() when driver registration
+      fails
+    - staging: gigaset: fix general protection fault on probe
+    - staging: gigaset: fix illegal free on probe errors
+    - staging: gigaset: add endpoint-type sanity check
+    - usb: xhci: only set D3hot for pci device
+    - xhci: Fix memory leak in xhci_add_in_port()
+    - xhci: fix USB3 device initiated resume race with roothub autosuspend
+    - xhci: Increase STS_HALT timeout in xhci_suspend()
+    - xhci: handle some XHCI_TRUST_TX_LENGTH quirks cases as default behaviour.
+    - xhci: make sure interrupts are restored to correct state
+    - interconnect: qcom: sdm845: Walk the list safely on node removal
+    - interconnect: qcom: qcs404: Walk the list safely on node removal
+    - usb: common: usb-conn-gpio: Don't log an error on probe deferral
+    - ARM: dts: pandora-common: define wl1251 as child node of mmc3
+    - iio: adis16480: Add debugfs_reg_access entry
+    - iio: imu: st_lsm6dsx: fix ODR check in st_lsm6dsx_write_raw
+    - iio: adis16480: Fix scales factors
+    - iio: humidity: hdc100x: fix IIO_HUMIDITYRELATIVE channel reporting
+    - iio: imu: inv_mpu6050: fix temperature reporting using bad unit
+    - iio: adc: ad7606: fix reading unnecessary data from device
+    - iio: adc: ad7124: Enable internal reference
+    - USB: atm: ueagle-atm: add missing endpoint check
+    - USB: idmouse: fix interface sanity checks
+    - USB: serial: io_edgeport: fix epic endpoint lookup
+    - usb: roles: fix a potential use after free
+    - 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
+    - tpm: add check after commands attribs tab allocation
+    - tpm: Switch to platform_get_irq_optional()
+    - EDAC/altera: Use fast register IO for S10 IRQs
+    - brcmfmac: disable PCIe interrupts before bus reset
+    - mtd: spear_smi: Fix Write Burst mode
+    - mtd: rawnand: Change calculating of position page containing BBM
+    - virt_wifi: fix use-after-free in virt_wifi_newlink()
+    - virtio-balloon: fix managed page counts when migrating pages between zones
+    - usb: dwc3: pci: add ID for the Intel Comet Lake -H variant
+    - usb: dwc3: gadget: Fix logical condition
+    - usb: dwc3: gadget: Clear started flag for non-IOC
+    - usb: dwc3: ep0: Clear started flag on completion
+    - phy: renesas: rcar-gen3-usb2: Fix sysfs interface of "role"
+    - usb: typec: fix use after free in typec_register_port()
+    - iwlwifi: pcie: fix support for transmitting SKBs with fraglist
+    - btrfs: check page->mapping when loading free space cache
+    - btrfs: use btrfs_block_group_cache_done in update_block_group
+    - btrfs: use refcount_inc_not_zero in kill_all_nodes
+    - Btrfs: fix metadata space leak on fixup worker failure to set range as
+      delalloc
+    - Btrfs: fix negative subv_writers counter and data space leak after buffered
+      write
+    - btrfs: Avoid getting stuck during cyclic writebacks
+    - btrfs: Remove btrfs_bio::flags member
+    - Btrfs: send, skip backreference walking for extents with many references
+    - btrfs: record all roots for rename exchange on a subvol
+    - 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
+    - ovl: fix corner case of non-unique st_dev;st_ino
+    - ovl: relax WARN_ON() on rename to self
+    - hwrng: omap - Fix RNG wait loop timeout
+    - dm writecache: handle REQ_FUA
+    - dm zoned: reduce overhead of backing device checks
+    - workqueue: Fix spurious sanity check failures in destroy_workqueue()
+    - workqueue: Fix pwq ref leak in rescuer_thread()
+    - ASoC: rt5645: Fixed buddy jack support.
+    - ASoC: rt5645: Fixed typo for buddy jack support.
+    - ASoC: Jack: Fix NULL pointer dereference in snd_soc_jack_report
+    - ASoC: fsl_audmix: Add spin lock to protect tdms
+    - md: improve handling of bio with REQ_PREFLUSH in md_flush_request()
+    - blk-mq: avoid sysfs buffer overflow with too many CPU cores
+    - cgroup: pids: use atomic64_t for pids->limit
+    - wil6210: check len before memcpy() calls
+    - ar5523: check NULL before memcpy() in ar5523_cmd()
+    - s390/mm: properly clear _PAGE_NOEXEC bit when it is not supported
+    - media: hantro: Fix s_fmt for dynamic resolution changes
+    - media: hantro: Fix motion vectors usage condition
+    - media: hantro: Fix picture order count table enable
+    - media: vimc: sen: remove unused kthread_sen field
+    - media: bdisp: fix memleak on release
+    - media: radio: wl1273: fix interrupt masking on release
+    - media: cec.h: CEC_OP_REC_FLAG_ values were swapped
+    - cpuidle: Do not unset the driver if it is there already
+    - cpuidle: teo: Ignore disabled idle states that are too deep
+    - cpuidle: teo: Rename local variable in teo_select()
+    - cpuidle: teo: Consider hits and misses metrics of disabled states
+    - cpuidle: teo: Fix "early hits" handling for disabled idle states
+    - cpuidle: use first valid target residency as poll time
+    - erofs: zero out when listxattr is called with no xattr
+    - perf tests: Fix out of bounds memory access
+    - drm/panfrost: Open/close the perfcnt BO
+    - powerpc/perf: Disable trace_imc pmu
+    - intel_th: Fix a double put_device() in error path
+    - intel_th: pci: Add Ice Lake CPU support
+    - intel_th: pci: Add Tiger Lake CPU support
+    - PM / devfreq: Lock devfreq in trans_stat_show
+    - cpufreq: powernv: fix stack bloat and hard limit on number of CPUs
+    - ALSA: fireface: fix return value in error path of isochronous resources
+      reservation
+    - ALSA: oxfw: fix return value in error path of isochronous resources
+      reservation
+    - ACPI / utils: Move acpi_dev_get_first_match_dev() under CONFIG_ACPI
+    - ACPI: LPSS: Add LNXVIDEO -> BYT I2C7 to lpss_device_links
+    - ACPI: LPSS: Add LNXVIDEO -> BYT I2C1 to lpss_device_links
+    - ACPI: LPSS: Add dmi quirk for skipping _DEP check for some device-links
+    - ACPI / hotplug / PCI: Allocate resources directly under the non-hotplug
+      bridge
+    - ACPI: OSL: only free map once in osl.c
+    - ACPI: bus: Fix NULL pointer check in acpi_bus_get_private_data()
+    - ACPI: EC: Rework flushing of pending work
+    - ACPI: PM: Avoid attaching ACPI PM domain to certain devices
+    - pinctrl: rza2: Fix gpio name typos
+    - pinctrl: armada-37xx: Fix irq mask access in armada_37xx_irq_set_type()
+    - pinctrl: samsung: Add of_node_put() before return in error path
+    - pinctrl: samsung: Fix device node refcount leaks in Exynos wakeup controller
+      init
+    - pinctrl: samsung: Fix device node refcount leaks in S3C24xx wakeup
+      controller init
+    - pinctrl: samsung: Fix device node refcount leaks in init code
+    - pinctrl: samsung: Fix device node refcount leaks in S3C64xx wakeup
+      controller init
+    - mmc: host: omap_hsmmc: add code for special init of wl1251 to get rid of
+      pandora_wl1251_init_card
+    - ARM: dts: omap3-tao3530: Fix incorrect MMC card detection GPIO polarity
+    - RDMA/core: Fix ib_dma_max_seg_size()
+    - ppdev: fix PPGETTIME/PPSETTIME ioctls
+    - stm class: Lose the protocol driver when dropping its reference
+    - coresight: Serialize enabling/disabling a link device.
+    - powerpc: Allow 64bit VDSO __kernel_sync_dicache to work across ranges >4GB
+    - powerpc/xive: Prevent page fault issues in the machine crash handler
+    - powerpc: Allow flush_icache_range to work across ranges >4GB
+    - powerpc/xive: Skip ioremap() of ESB pages for LSI interrupts
+    - video/hdmi: Fix AVI bar unpack
+    - quota: Check that quota is not dirty before release
+    - ext2: check err when partial != NULL
+    - quota: fix livelock in dquot_writeback_dquots
+    - ext4: Fix credit estimate for final inode freeing
+    - reiserfs: fix extended attributes on the root directory
+    - scsi: qla2xxx: Fix SRB leak on switch command timeout
+    - scsi: qla2xxx: Fix a dma_pool_free() call
+    - Revert "scsi: qla2xxx: Fix memory leak when sending I/O fails"
+    - iio: ad7949: kill pointless "readback"-handling code
+    - iio: ad7949: fix channels mixups
+    - omap: pdata-quirks: revert pandora specific gpiod additions
+    - omap: pdata-quirks: remove openpandora quirks for mmc3 and wl1251
+    - powerpc: Avoid clang warnings around setjmp and longjmp
+    - powerpc: Fix vDSO clock_getres()
+    - mm, memfd: fix COW issue on MAP_PRIVATE and F_SEAL_FUTURE_WRITE mappings
+    - mm: memcg/slab: wait for !root kmem_cache refcnt killing on root kmem_cache
+      destruction
+    - ext4: work around deleting a file with i_nlink == 0 safely
+    - firmware: qcom: scm: Ensure 'a0' status code is treated as signed
+    - s390/smp,vdso: fix ASCE handling
+    - s390/kaslr: store KASLR offset for early dumps
+    - mm/shmem.c: cast the type of unmap_start to u64
+    - powerpc: Define arch_is_kernel_initmem_freed() for lockdep
+    - USB: dummy-hcd: increase max number of devices to 32
+    - rtc: disable uie before setting time and enable after
+    - splice: only read in as much information as there is pipe buffer space
+    - ext4: fix a bug in ext4_wait_for_tail_page_commit
+    - ext4: fix leak of quota reservations
+    - blk-mq: make sure that line break can be printed
+    - workqueue: Fix missing kfree(rescuer) in destroy_workqueue()
+    - r8169: fix rtl_hw_jumbo_disable for RTL8168evl
+    - EDAC/ghes: Do not warn when incrementing refcount on 0
+    - Linux 5.4.4
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update variants
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Change source package to linux-5.4
+    - [Packaging] Don't use SRCPKGNAME for linux-libc-dev
+    - [Packaging] Remove linux-source-3 Provides: from linux-source
+    - [Packaging] Fix linux-doc in linux-image Suggests:
+    - [Debian] Read variants list into a variable
+    - [Packaging] Generate linux-libc-dev package only for primary variant
+    - [Packaging] Generate linux-doc for only the primary variant
+    - [Debian] Update linux source package name in debian/tests/*
+    - [Config] update annotations to match config changes
+    - [Config] disable PCI_MESON
+    - SAUCE: tools: hv: Update shebang to use python3 instead of python
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 08 Jan 2020 15:00:54 -0600
+
+linux-5.4 (5.4.0-9.12) focal; urgency=medium
+
+  * Empty entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 17 Dec 2019 07:09:13 -0600
+
+linux (5.4.0-9.12) focal; urgency=medium
+
+  * alsa/hda/realtek: the line-out jack doens't work on a dell AIO
+    (LP: #1855999)
+    - SAUCE: ALSA: hda/realtek - Line-out jack doesn't work on a Dell AIO
+
+  * scsi: hisi_sas: Check sas_port before using it (LP: #1855952)
+    - scsi: hisi_sas: Check sas_port before using it
+
+  * CVE-2019-19078
+    - ath10k: fix memory leak
+
+  * cifs: DFS Caching feature causing problems traversing multi-tier DFS setups
+    (LP: #1854887)
+    - cifs: Fix retrieval of DFS referrals in cifs_mount()
+
+  * Support DPCD aux brightness control (LP: #1856134)
+    - SAUCE: drm/i915: Fix eDP DPCD aux max backlight calculations
+    - SAUCE: drm/i915: Assume 100% brightness when not in DPCD control mode
+    - SAUCE: drm/i915: Fix DPCD register order in intel_dp_aux_enable_backlight()
+    - SAUCE: drm/i915: Auto detect DPCD backlight support by default
+    - SAUCE: drm/i915: Force DPCD backlight mode on X1 Extreme 2nd Gen 4K AMOLED
+      panel
+    - USUNTU: SAUCE: drm/i915: Force DPCD backlight mode on Dell Precision 4K sku
+
+  * The system cannot resume from S3 if user unplugs the TB16 during suspend
+    state (LP: #1849269)
+    - PCI: pciehp: Do not disable interrupt twice on suspend
+    - PCI: pciehp: Prevent deadlock on disconnect
+
+  * change kconfig of the soundwire bus driver from y to m (LP: #1855685)
+    - [Config]: SOUNDWIRE=m
+
+  * alsa/sof: change to use hda hdmi codec driver to make hdmi audio on the
+    docking station work (LP: #1855666)
+    - ALSA: hda/hdmi - implement mst_no_extra_pcms flag
+    - ASoC: hdac_hda: add support for HDMI/DP as a HDA codec
+    - ASoC: Intel: skl-hda-dsp-generic: use snd-hda-codec-hdmi
+    - ASoC: Intel: skl-hda-dsp-generic: fix include guard name
+    - ASoC: SOF: Intel: add support for snd-hda-codec-hdmi
+    - ASoC: Intel: bxt-da7219-max98357a: common hdmi codec support
+    - ASoC: Intel: glk_rt5682_max98357a: common hdmi codec support
+    - ASoC: intel: sof_rt5682: common hdmi codec support
+    - ASoC: Intel: bxt_rt298: common hdmi codec support
+    - ASoC: SOF: enable sync_write in hdac_bus
+    - [config]: SND_SOC_SOF_HDA_COMMON_HDMI_CODEC=y
+
+  * Fix unusable USB hub on Dell TB16 after S3 (LP: #1855312)
+    - SAUCE: USB: core: Make port power cycle a seperate helper function
+    - SAUCE: USB: core: Attempt power cycle port when it's in eSS.Disabled state
+
+  * Focal update: v5.4.3 upstream stable release (LP: #1856583)
+    - rsi: release skb if rsi_prepare_beacon fails
+    - arm64: tegra: Fix 'active-low' warning for Jetson TX1 regulator
+    - arm64: tegra: Fix 'active-low' warning for Jetson Xavier regulator
+    - perf scripts python: exported-sql-viewer.py: Fix use of TRUE with SQLite
+    - sparc64: implement ioremap_uc
+    - lp: fix sparc64 LPSETTIMEOUT ioctl
+    - time: Zero the upper 32-bits in __kernel_timespec on 32-bit
+    - mailbox: tegra: Fix superfluous IRQ error message
+    - staging/octeon: Use stubs for MIPS && !CAVIUM_OCTEON_SOC
+    - usb: gadget: u_serial: add missing port entry locking
+    - serial: 8250-mtk: Use platform_get_irq_optional() for optional irq
+    - tty: serial: fsl_lpuart: use the sg count from dma_map_sg
+    - tty: serial: msm_serial: Fix flow control
+    - serial: pl011: Fix DMA ->flush_buffer()
+    - serial: serial_core: Perform NULL checks for break_ctl ops
+    - serial: stm32: fix clearing interrupt error flags
+    - serial: 8250_dw: Avoid double error messaging when IRQ absent
+    - serial: ifx6x60: add missed pm_runtime_disable
+    - mwifiex: Re-work support for SDIO HW reset
+    - io_uring: fix dead-hung for non-iter fixed rw
+    - io_uring: transform send/recvmsg() -ERESTARTSYS to -EINTR
+    - fuse: fix leak of fuse_io_priv
+    - fuse: verify nlink
+    - fuse: verify write return
+    - fuse: verify attributes
+    - io_uring: fix missing kmap() declaration on powerpc
+    - io_uring: ensure req->submit is copied when req is deferred
+    - SUNRPC: Avoid RPC delays when exiting suspend
+    - ALSA: hda/realtek - Enable internal speaker of ASUS UX431FLC
+    - ALSA: hda/realtek - Fix inverted bass GPIO pin on Acer 8951G
+    - ALSA: pcm: oss: Avoid potential buffer overflows
+    - ALSA: hda - Add mute led support for HP ProBook 645 G4
+    - ALSA: hda: Modify stream stripe mask only when needed
+    - soc: mediatek: cmdq: fixup wrong input order of write api
+    - Input: synaptics - switch another X1 Carbon 6 to RMI/SMbus
+    - Input: synaptics-rmi4 - re-enable IRQs in f34v7_do_reflash
+    - Input: synaptics-rmi4 - don't increment rmiaddr for SMBus transfers
+    - Input: goodix - add upside-down quirk for Teclast X89 tablet
+    - coresight: etm4x: Fix input validation for sysfs.
+    - Input: Fix memory leak in psxpad_spi_probe
+    - media: rc: mark input device as pointing stick
+    - x86/mm/32: Sync only to VMALLOC_END in vmalloc_sync_all()
+    - CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks
+    - CIFS: Fix SMB2 oplock break processing
+    - tty: vt: keyboard: reject invalid keycodes
+    - can: slcan: Fix use-after-free Read in slcan_open
+    - nfsd: Ensure CLONE persists data and metadata changes to the target file
+    - nfsd: restore NFSv3 ACL support
+    - kernfs: fix ino wrap-around detection
+    - jbd2: Fix possible overflow in jbd2_log_space_left()
+    - drm/msm: fix memleak on release
+    - drm: damage_helper: Fix race checking plane->state->fb
+    - drm/i810: Prevent underflow in ioctl
+    - arm64: Validate tagged addresses in access_ok() called from kernel threads
+    - arm64: dts: exynos: Revert "Remove unneeded address space mapping for soc
+      node"
+    - KVM: PPC: Book3S HV: XIVE: Free previous EQ page when setting up a new one
+    - KVM: PPC: Book3S HV: XIVE: Fix potential page leak on error path
+    - KVM: PPC: Book3S HV: XIVE: Set kvm->arch.xive when VPs are allocated
+    - KVM: nVMX: Always write vmcs02.GUEST_CR3 during nested VM-Enter
+    - KVM: arm/arm64: vgic: Don't rely on the wrong pending table
+    - KVM: x86: do not modify masked bits of shared MSRs
+    - KVM: x86: fix presentation of TSX feature in ARCH_CAPABILITIES
+    - KVM: x86: Remove a spurious export of a static function
+    - KVM: x86: Grab KVM's srcu lock when setting nested state
+    - crypto: crypto4xx - fix double-free in crypto4xx_destroy_sdr
+    - crypto: atmel-aes - Fix IV handling when req->nbytes < ivsize
+    - crypto: af_alg - cast ki_complete ternary op to int
+    - crypto: geode-aes - switch to skcipher for cbc(aes) fallback
+    - crypto: ccp - fix uninitialized list head
+    - crypto: ecdh - fix big endian bug in ECC library
+    - crypto: user - fix memory leak in crypto_report
+    - spi: spi-fsl-qspi: Clear TDH bits in FLSHCR register
+    - spi: stm32-qspi: Fix kernel oops when unbinding driver
+    - spi: atmel: Fix CS high support
+    - spi: Fix SPI_CS_HIGH setting when using native and GPIO CS
+    - spi: Fix NULL pointer when setting SPI_CS_HIGH for GPIO CS
+    - can: ucan: fix non-atomic allocation in completion handler
+    - RDMA/qib: Validate ->show()/store() callbacks before calling them
+    - rfkill: allocate static minor
+    - bdev: Factor out bdev revalidation into a common helper
+    - bdev: Refresh bdev size for disks without partitioning
+    - iomap: Fix pipe page leakage during splicing
+    - thermal: Fix deadlock in thermal thermal_zone_device_check
+    - vcs: prevent write access to vcsu devices
+    - Revert "serial/8250: Add support for NI-Serial PXI/PXIe+485 devices"
+    - binder: Fix race between mmap() and binder_alloc_print_pages()
+    - binder: Prevent repeated use of ->mmap() via NULL mapping
+    - binder: Handle start==NULL in binder_update_page_range()
+    - KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
+    - ALSA: hda - Fix pending unsol events at shutdown
+    - cpufreq: imx-cpufreq-dt: Correct i.MX8MN's default speed grade value
+    - md/raid0: Fix an error message in raid0_make_request()
+    - drm/mcde: Fix an error handling path in 'mcde_probe()'
+    - watchdog: aspeed: Fix clock behaviour for ast2600
+    - EDAC/ghes: Fix locking and memory barrier issues
+    - perf script: Fix invalid LBR/binary mismatch error
+    - kselftest: Fix NULL INSTALL_PATH for TARGETS runlist
+    - Linux 5.4.3
+
+  * Realtek ALC256M with DTS Audio Processing internal microphone doesn't work
+    on Redmi Book 14 2019 (LP: #1846148) // Focal update: v5.4.3 upstream stable
+    release (LP: #1856583)
+    - ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] add python depends to ubuntu-regression-suite
+    - SAUCE: selftests: net: tls: remove recv_rcvbuf test
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 16 Dec 2019 14:54:19 -0600
+
+linux (5.4.0-8.11) focal; urgency=medium
+
+  * focal/linux: 5.4.0-8.9 -proposed tracker (LP: #1855448)
+
+  * update ENA driver for DIMLIB dynamic interrupt moderation (LP: #1853180)
+    - SAUCE: net: ena: fix issues in setting interrupt moderation params in
+      ethtool
+    - SAUCE: net: ena: fix too long default tx interrupt moderation interval
+
+  * Kernel build log filled with "/bin/bash: line 5: warning: command
+    substitution: ignored null byte in input" (LP: #1853843)
+    - [Debian] Fix warnings when checking for modules signatures
+
+  * hwe-edge kernel 5.3.0-23.25 kernel does not boot on Precision 5720 AIO
+    (LP: #1852581)
+    - [Packaging] Fix module signing with older modinfo
+
+  * Fix MST support on Ice Lake (LP: #1854432)
+    - drm/i915: fix port checks for MST support on gen >= 11
+
+  * headphone has noise as not mute on dell machines with alc236/256
+    (LP: #1854401)
+    - SAUCE: ALSA: hda/realtek - Dell headphone has noise on unmute for ALC236
+
+  * [CML-S62] Need enable intel_pmc_core driver patch for Comet lake- S 6+2
+    (LP: #1847450)
+    - SAUCE: platform/x86: intel_pmc_core: Add Comet Lake (CML) platform support
+      to intel_pmc_core driver
+
+  * 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()
+
+  * [CML-S62] Need enable intel_rapl patch support for Comet lake- S 6+2
+    (LP: #1847454)
+    - powercap/intel_rapl: add support for CometLake Mobile
+    - powercap/intel_rapl: add support for Cometlake desktop
+
+  * External microphone can't work on some dell machines with the codec alc256
+    or alc236 (LP: #1853791)
+    - SAUCE: ALSA: hda/realtek - Move some alc256 pintbls to fallback table
+    - SAUCE: ALSA: hda/realtek - Move some alc236 pintbls to fallback table
+
+  * remount of multilower moved pivoted-root overlayfs root, results in I/O
+    errors on some modified files (LP: #1824407)
+    - SAUCE: ovl: fix lookup failure on multi lower squashfs
+
+  * [CML-S62] Need enable turbostat patch support for Comet lake- S 6+2
+    (LP: #1847451)
+    - SAUCE: tools/power turbostat: Add Cometlake support
+
+  * CONFIG_ARCH_ROCKCHIP is not set in ubuntu 18.04 aarch64,arm64 (LP: #1825222)
+    - [Config] Enable ROCKCHIP support for arm64
+
+  * [broadwell-rt286, playback] Since Linux 5.2rc2 audio playback no longer
+    works on Dell Venue 11 Pro 7140 (LP: #1846539)
+    - SAUCE: ASoC: SOF: Intel: Broadwell: clarify mutual exclusion with legacy
+      driver
+
+  * i40e: general protection fault in i40e_config_vf_promiscuous_mode
+    (LP: #1852663)
+    - SAUCE: i40e Fix GPF when deleting VMs
+
+  * libbpf check_abi fails on ppc64el (LP: #1854974)
+    - libbpf: Fix readelf output parsing on powerpc with recent binutils
+
+  * CVE-2019-19050
+    - crypto: user - fix memory leak in crypto_reportstat
+
+  * Make hotplugging docking station to Thunderbolt port more reliable
+    (LP: #1853991)
+    - PCI/PM: Add pcie_wait_for_link_delay()
+    - PCI/PM: Add missing link delays required by the PCIe spec
+
+  * i915: Display flickers (monitor loses signal briefly) during "flickerfree"
+    boot, while showing the BIOS logo on a black background (LP: #1836858)
+    - [Config] FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y
+
+  * [CML] New device id's for CMP-H (LP: #1846335)
+    - i2c: i801: Add support for Intel Comet Lake PCH-H
+    - mtd: spi-nor: intel-spi: Add support for Intel Comet Lake-H SPI serial flash
+    - mfd: intel-lpss: Add Intel Comet Lake PCH-H PCI IDs
+
+  * Focal update: v5.4.2 upstream stable release (LP: #1855326)
+    - io_uring: async workers should inherit the user creds
+    - net: separate out the msghdr copy from ___sys_{send,recv}msg()
+    - net: disallow ancillary data for __sys_{send,recv}msg_file()
+    - crypto: inside-secure - Fix stability issue with Macchiatobin
+    - driver core: platform: use the correct callback type for bus_find_device
+    - usb: dwc2: use a longer core rest timeout in dwc2_core_reset()
+    - staging: wilc1000: fix illegal memory access in wilc_parse_join_bss_param()
+    - staging: rtl8192e: fix potential use after free
+    - staging: rtl8723bs: Drop ACPI device ids
+    - staging: rtl8723bs: Add 024c:0525 to the list of SDIO device-ids
+    - USB: serial: ftdi_sio: add device IDs for U-Blox C099-F9P
+    - mei: bus: prefix device names on bus with the bus name
+    - mei: me: add comet point V device id
+    - thunderbolt: Power cycle the router if NVM authentication fails
+    - x86/fpu: Don't cache access to fpu_fpregs_owner_ctx
+    - gve: Fix the queue page list allocated pages count
+    - macvlan: schedule bc_work even if error
+    - mdio_bus: don't use managed reset-controller
+    - net: dsa: sja1105: fix sja1105_parse_rgmii_delays()
+    - net: macb: add missed tasklet_kill
+    - net: psample: fix skb_over_panic
+    - net: sched: fix `tc -s class show` no bstats on class with nolock subqueues
+    - openvswitch: fix flow command message size
+    - sctp: Fix memory leak in sctp_sf_do_5_2_4_dupcook
+    - slip: Fix use-after-free Read in slip_open
+    - sctp: cache netns in sctp_ep_common
+    - openvswitch: drop unneeded BUG_ON() in ovs_flow_cmd_build_info()
+    - openvswitch: remove another BUG_ON()
+    - net/tls: take into account that bpf_exec_tx_verdict() may free the record
+    - net/tls: free the record on encryption error
+    - net: skmsg: fix TLS 1.3 crash with full sk_msg
+    - selftests/tls: add a test for fragmented messages
+    - net/tls: remove the dead inplace_crypto code
+    - net/tls: use sg_next() to walk sg entries
+    - selftests: bpf: test_sockmap: handle file creation failures gracefully
+    - selftests: bpf: correct perror strings
+    - tipc: fix link name length check
+    - selftests: pmtu: use -oneline for ip route list cache
+    - r8169: fix jumbo configuration for RTL8168evl
+    - r8169: fix resume on cable plug-in
+    - ext4: add more paranoia checking in ext4_expand_extra_isize handling
+    - Revert "jffs2: Fix possible null-pointer dereferences in
+      jffs2_add_frag_to_fragtree()"
+    - crypto: talitos - Fix build error by selecting LIB_DES
+    - HID: core: check whether Usage Page item is after Usage ID items
+    - platform/x86: hp-wmi: Fix ACPI errors caused by too small buffer
+    - platform/x86: hp-wmi: Fix ACPI errors caused by passing 0 as input size
+    - Linux 5.4.2
+
+  * no HDMI video output since GDM greeter after linux-oem-osp1 version
+    5.0.0-1026 (LP: #1852386)
+    - drm/i915: Add new CNL PCH ID seen on a CML platform
+    - SAUCE: drm/i915: Fix detection for a CMP-V PCH
+
+  * Please add patch fixing RK818 ID detection (LP: #1853192)
+    - SAUCE: mfd: rk808: Fix RK818 ID template
+
+  * Raydium Touchscreen on ThinkPad L390 does not work (LP: #1849721)
+    - HID: i2c-hid: fix no irq after reset on raydium 3118
+
+  * Touchpad doesn't work on Dell Inspiron 7000 2-in-1 (LP: #1851901)
+    - Revert "UBUNTU: SAUCE: mfd: intel-lpss: add quirk for Dell XPS 13 7390
+      2-in-1"
+    - lib: devres: add a helper function for ioremap_uc
+    - mfd: intel-lpss: Use devm_ioremap_uc for MMIO
+
+  * Lenovo dock MAC Address pass through doesn't work in Ubuntu  (LP: #1827961)
+    - r8152: Add macpassthru support for ThinkPad Thunderbolt 3 Dock Gen 2
+
+  * Disable unreliable HPET on CFL-H system (LP: #1852216)
+    - SAUCE: x86/intel: Disable HPET on Intel Coffe Lake H platforms
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Config] Enable virtualbox dkms build
+    - [Config] update annotations to match current configs
+    - SAUCE: Add exfat module to signature inclusion list
+
+  * Miscellaneous upstream changes
+    - Bluetooth: Fix invalid-free in bcsp_close()
+    - ath9k_hw: fix uninitialized variable data
+    - ath10k: Fix a NULL-ptr-deref bug in ath10k_usb_alloc_urb_from_pipe
+    - ath10k: Fix HOST capability QMI incompatibility
+    - ath10k: restore QCA9880-AR1A (v1) detection
+    - Revert "Bluetooth: hci_ll: set operational frequency earlier"
+    - Revert "dm crypt: use WQ_HIGHPRI for the IO and crypt workqueues"
+    - md/raid10: prevent access of uninitialized resync_pages offset
+    - x86/insn: Fix awk regexp warnings
+    - x86/speculation: Fix incorrect MDS/TAA mitigation status
+    - x86/speculation: Fix redundant MDS mitigation message
+    - nbd: prevent memory leak
+    - x86/stackframe/32: Repair 32-bit Xen PV
+    - x86/xen/32: Make xen_iret_crit_fixup() independent of frame layout
+    - x86/xen/32: Simplify ring check in xen_iret_crit_fixup()
+    - x86/doublefault/32: Fix stack canaries in the double fault handler
+    - x86/pti/32: Size initial_page_table correctly
+    - x86/cpu_entry_area: Add guard page for entry stack on 32bit
+    - x86/entry/32: Fix IRET exception
+    - x86/entry/32: Use %ss segment where required
+    - x86/entry/32: Move FIXUP_FRAME after pushing %fs in SAVE_ALL
+    - x86/entry/32: Unwind the ESPFIX stack earlier on exception entry
+    - x86/entry/32: Fix NMI vs ESPFIX
+    - selftests/x86/mov_ss_trap: Fix the SYSENTER test
+    - selftests/x86/sigreturn/32: Invalidate DS and ES when abusing the kernel
+    - x86/pti/32: Calculate the various PTI cpu_entry_area sizes correctly, make
+      the CPU_ENTRY_AREA_PAGES assert precise
+    - x86/entry/32: Fix FIXUP_ESPFIX_STACK with user CR3
+    - futex: Prevent robust futex exit race
+    - ALSA: usb-audio: Fix NULL dereference at parsing BADD
+    - ALSA: usb-audio: Fix Scarlett 6i6 Gen 2 port data
+    - media: vivid: Set vid_cap_streaming and vid_out_streaming to true
+    - media: vivid: Fix wrong locking that causes race conditions on streaming
+      stop
+    - media: usbvision: Fix invalid accesses after device disconnect
+    - media: usbvision: Fix races among open, close, and disconnect
+    - cpufreq: Add NULL checks to show() and store() methods of cpufreq
+    - 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
+    - media: uvcvideo: Fix error path in control parsing failure
+    - media: b2c2-flexcop-usb: add sanity checking
+    - media: cxusb: detect cxusb_ctrl_msg error in query
+    - media: imon: invalid dereference in imon_touch_event
+    - media: mceusb: fix out of bounds read in MCE receiver buffer
+    - ALSA: hda - Disable audio component for legacy Nvidia HDMI codecs
+    - USBIP: add config dependency for SGL_ALLOC
+    - usbip: tools: fix fd leakage in the function of read_attr_usbip_status
+    - usbip: Fix uninitialized symbol 'nents' in stub_recv_cmd_submit()
+    - usb-serial: cp201x: support Mark-10 digital force gauge
+    - USB: chaoskey: fix error case of a timeout
+    - 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
+    - powerpc/book3s64: Fix link stack flush on context switch
+    - KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
+    - Linux 5.4.1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 06 Dec 2019 15:53:53 -0600
+
+linux (5.4.0-7.8) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/bpf: Comment out BPF_CORE_READ's which cause clang to
+      segfault
+    - Update nvidia-430 to nvidia-440
+    - [Config] Enable nvidia dkms build
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 25 Nov 2019 15:02:30 +0100
+
+linux (5.4.0-6.7) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Config] updateconfigs after rebase to 5.4-rc8
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc7
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 18 Nov 2019 12:08:01 +0100
+
+linux (5.4.0-5.6) focal; urgency=medium
+
+  * refcount underflow and type confusion in shiftfs (LP: #1850867) //
+    CVE-2019-15793
+    - SAUCE: shiftfs: Correct id translation for lower fs operations
+
+  * refcount underflow and type confusion in shiftfs (LP: #1850867) //
+    CVE-2019-15792
+    - SAUCE: shiftfs: prevent type confusion
+
+  * refcount underflow and type confusion in shiftfs (LP: #1850867) //
+    CVE-2019-15791
+    - SAUCE: shiftfs: Fix refcount underflow in btrfs ioctl handling
+
+  * Some EFI systems fail to boot in efi_init() when booted via maas
+    (LP: #1851810)
+    - SAUCE: efi: efi_get_memory_map -- increase map headroom
+
+  * seccomp: fix SECCOMP_USER_NOTIF_FLAG_CONTINUE test (LP: #1849281)
+    - SAUCE: seccomp: rework define for SECCOMP_USER_NOTIF_FLAG_CONTINUE
+    - SAUCE: seccomp: avoid overflow in implicit constant conversion
+
+  * dkms artifacts may expire from the pool (LP: #1850958)
+    - [Packaging] dkms -- try launchpad librarian for pool downloads
+    - [Packaging] dkms -- dkms-build quieten wget verbiage
+
+  * tsc marked unstable after entered PC10 on Intel CoffeeLake (LP: #1840239)
+    - SAUCE: x86/intel: Disable HPET on Intel Coffe Lake platforms
+    - SAUCE: x86/intel: Disable HPET on Intel Ice Lake platforms
+
+  * shiftfs: prevent exceeding project quotas (LP: #1849483)
+    - SAUCE: shiftfs: drop CAP_SYS_RESOURCE from effective capabilities
+
+  * shiftfs: fix fallocate() (LP: #1849482)
+    - SAUCE: shiftfs: setup correct s_maxbytes limit
+
+  * The alsa hda driver is not loaded due to the missing of PCIID for Comet
+    Lake-S [8086:a3f0] (LP: #1852070)
+    - SAUCE: ALSA: hda: Add Cometlake-S PCI ID
+
+  * Can't adjust brightness on DELL UHD dGPU AIO (LP: #1813877)
+    - SAUCE: platform/x86: dell-uart-backlight: add missing status command
+    - SAUCE: platform/x86: dell-uart-backlight: load driver by scalar status
+    - SAUCE: platform/x86: dell-uart-backlight: add force parameter
+    - SAUCE: platform/x86: dell-uart-backlight: add quirk for old platforms
+
+  * s_iflags overlap prevents unprivileged overlayfs mounts (LP: #1851677)
+    - SAUCE: fs: Move SB_I_NOSUID to the top of s_iflags
+
+  * ubuntu-aufs-modified mmap_region() breaks refcounting in overlayfs/shiftfs
+    error path (LP: #1850994) // CVE-2019-15794
+    - SAUCE: shiftfs: Restore vm_file value when lower fs mmap fails
+    - SAUCE: ovl: Restore vm_file value when lower fs mmap fails
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Convert update-aufs.sh to use aufs5
+    - SAUCE: import aufs driver
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 13 Nov 2019 11:56:35 -0800
+
+linux (5.4.0-4.5) focal; urgency=medium
+
+  * High power consumption using 5.0.0-25-generic (LP: #1840835)
+    - PCI: Add a helper to check Power Resource Requirements _PR3 existence
+    - ALSA: hda: Allow HDA to be runtime suspended when dGPU is not bound to a
+      driver
+    - PCI: Fix missing inline for pci_pr3_present()
+
+  * Fix signing of staging modules in eoan (LP: #1850234)
+    - [Packaging] Leave unsigned modules unsigned after adding .gnu_debuglink
+
+  * [20.04 FEAT] Set Architecture Level (ALS) to z13 (LP: #1837525)
+    - [Config] s390x bump march to z13, with tune to z15
+
+  * Miscellaneous Ubuntu changes
+    - [Debian]: do not skip tests for linux-hwe-edge
+    - update dkms package versions
+    - [Config] re-enable zfs
+    - [Config] rename module virtio_fs to virtiofs
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc6
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 04 Nov 2019 15:12:02 +0100
+
+linux (5.4.0-3.4) focal; urgency=medium
+
+  * seccomp: fix SECCOMP_USER_NOTIF_FLAG_CONTINUE test (LP: #1849281)
+    - SAUCE: seccomp: fix SECCOMP_USER_NOTIF_FLAG_CONTINUE test
+
+  * cloudimg: no iavf/i40evf module so no network available with SR-IOV enabled
+    cloud (LP: #1848481)
+    - [Packaging] include iavf/i40evf in generic
+
+  * CVE-2019-17666
+    - SAUCE: rtlwifi: Fix potential overflow on P2P code
+
+  * Change Config Option CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE for s390x from yes
+    to no (LP: #1848492)
+    - [Config] Change Config Option CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE for s390x
+      from yes to no
+
+  * Add Intel Comet Lake ethernet support (LP: #1848555)
+    - SAUCE: e1000e: Add support for Comet Lake
+
+  * seccomp: add SECCOMP_USER_NOTIF_FLAG_CONTINUE    (LP: #1847744)
+    - SAUCE: seccomp: add SECCOMP_USER_NOTIF_FLAG_CONTINUE
+    - SAUCE: seccomp: test SECCOMP_USER_NOTIF_FLAG_CONTINUE
+
+  * drm/i915: Fix the issue of "azx_get_response timeout" for hdmi audio on ICL
+    platforms (LP: #1847192)
+    - SAUCE: drm/i915: Fix audio power up sequence for gen10+ display
+    - SAUCE: drm/i915: extend audio CDCLK>=2*BCLK constraint to more platforms
+
+  * PM / hibernate: fix potential memory corruption (LP: #1847118)
+    - SAUCE: PM / hibernate: memory_bm_find_bit -- tighten node optimisation
+
+  * [regression] NoNewPrivileges incompatible with Apparmor (LP: #1844186)
+    - SAUCE: apparmor: fix nnp subset test for unconfined
+
+  * overlayfs: allow with shiftfs as underlay (LP: #1846272)
+    - SAUCE: overlayfs: allow with shiftfs as underlay
+
+  * eoan: alsa/sof: Enable SOF_HDA link and codec (LP: #1848490)
+    - [Config] Fix SOF Kconfig options
+
+  * linux won't build when new virtualbox version is present on the archive
+    (LP: #1848788)
+    - [Packaging]: download virtualbox from sources
+
+  * Miscellaneous Ubuntu changes
+    - [Config] update annotations from configs
+    - [Config] updateconfigs after rebase to 5.4-rc5
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 29 Oct 2019 12:01:27 -0500
+
+linux (5.4.0-2.3) eoan; urgency=medium
+
+  * Add installer support for iwlmvm adapters (LP: #1848236)
+    - d-i: Add iwlmvm to nic-modules
+
+  * shiftfs: rework how shiftfs opens files (LP: #1846265)
+    - SAUCE: shiftfs: rework how shiftfs opens files
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Config] updateconfigs after rebase to 5.4-rc4
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc4
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 21 Oct 2019 17:31:26 +0200
+
+linux (5.4.0-1.2) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Config] updateconfigs after rebase to 5.4-rc3
+    - [Config] add flexfb, fbtft_device and rio500 to modules.ignore
+    - [Config] amd64: ignore fbtft and all dependent modules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc3
+
+ -- Andrea Righi <andrea.righi@canonical.com>  Mon, 14 Oct 2019 19:48:52 +0200
+
+linux (5.4.0-0.1) eoan; urgency=medium
+
+  * Enable the Dragonboards out of Eoan/master arm64 kernel (LP: #1846704)
+    - [Packaging] arm64: snapdragon: introduce a snapdragon flavour
+    - [Packaging] arm64: snapdragon: switch kernel format to Image
+    - [Config] arm64: snapdragon: CONFIG_PINCTRL_MSM8916=y
+    - [Config] arm64: snapdragon: CONFIG_PINCTRL_MSM8994=y
+    - [Config] arm64: snapdragon: CONFIG_PINCTRL_MSM8996=y
+    - [Config] arm64: snapdragon: CONFIG_PINCTRL_MSM8998=y
+    - [Config] arm64: snapdragon: CONFIG_REGULATOR_QCOM_RPMH=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_BAM_DMA=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_HIDMA_MGMT=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_HIDMA=y
+    - [Config] arm64: snapdragon: CONFIG_COMMON_CLK_QCOM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_CLK_RPMH=y
+    - [Config] arm64: snapdragon: CONFIG_MSM_GCC_8916=y
+    - [Config] arm64: snapdragon: CONFIG_MSM_GCC_8994=y
+    - [Config] arm64: snapdragon: CONFIG_MSM_MMCC_8996=y
+    - [Config] arm64: snapdragon: CONFIG_MSM_GCC_8998=y
+    - [Config] arm64: snapdragon: CONFIG_HWSPINLOCK_QCOM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_APCS_IPC=y
+    - [Config] arm64: snapdragon: CONFIG_RPMSG_QCOM_GLINK_RPM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_GENI_SE=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_SMEM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_SMD_RPM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_SMP2P=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_SMSM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_QFPROM=y
+    - [Config] arm64: snapdragon: CONFIG_SERIAL_QCOM_GENI=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_TSENS=y
+    - [Config] arm64: snapdragon: CONFIG_REGULATOR_QCOM_SMD_RPM=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_CLK_SMD_RPM=y
+    - [Config] arm64: snapdragon: CONFIG_RPMSG_QCOM_SMD=y
+    - [Config] arm64: snapdragon: CONFIG_MFD_QCOM_RPM=y
+    - [Config] arm64: snapdragon: CONFIG_SCSI_UFSHCD=y
+    - [Config] arm64: snapdragon: CONFIG_SCSI_UFSHCD_PLATFORM=y
+    - [Config] arm64: snapdragon: CONFIG_SCSI_UFS_HISI=y
+    - [Config] arm64: snapdragon: CONFIG_MMC_SDHCI=y
+    - [Config] arm64: snapdragon: CONFIG_MMC_SDHCI_PLTFM=y
+    - [Config] arm64: snapdragon: CONFIG_MMC_SDHCI_MSM=y
+    - [Config] arm64: snapdragon: CONFIG_REGULATOR_QCOM_SPMI=y
+    - [Config] arm64: snapdragon: CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+    - [Config] arm64: snapdragon: CONFIG_PHY_QCOM_USB_HS=y
+    - [Config] arm64: snapdragon: CONFIG_PHY_QCOM_QMP=y
+    - [Config] arm64: snapdragon: CONFIG_PHY_QCOM_UFS=y
+    - [Config] arm64: snapdragon: CONFIG_PHY_QCOM_USB_HSIC=y
+    - [Config] arm64: snapdragon: CONFIG_USB_CHIPIDEA_OF=y
+    - [Config] arm64: snapdragon: CONFIG_USB_EHCI_HCD_PLATFORM=y
+    - [Config] arm64: snapdragon: CONFIG_EXTCON_USB_GPIO=y
+    - [Config] arm64: snapdragon: CONFIG_REGULATOR_FIXED_VOLTAGE=y
+    - [Config] arm64: snapdragon: CONFIG_LEDS_GPIO=y
+    - [Config] arm64: snapdragon: CONFIG_USB_HSIC_USB3503=y
+    - [Config] arm64: snapdragon: CONFIG_USB_NET_DRIVERS=y
+    - [Config] arm64: snapdragon: CONFIG_USB_OTG=y
+    - [Config] arm64: snapdragon: CONFIG_USB_XHCI_PLATFORM=y
+    - [Config] arm64: snapdragon: CONFIG_USB_OHCI_HCD_PLATFORM=y
+    - [Config] arm64: snapdragon: CONFIG_USB_MUSB_HDRC=y
+    - [Config] arm64: snapdragon: CONFIG_USB_DWC3=y
+    - [Config] arm64: snapdragon: CONFIG_USB_DWC3_PCI=y
+    - [Config] arm64: snapdragon: CONFIG_USB_DWC3_OF_SIMPLE=y
+    - [Config] arm64: snapdragon: CONFIG_USB_DWC3_QCOM=y
+    - [Config] arm64: snapdragon: CONFIG_LEDS_PWM=y
+    - [Config] arm64: snapdragon: CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+    - [Config] arm64: snapdragon: CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_A53PLL=y
+    - [Config] arm64: snapdragon: CONFIG_QCOM_CLK_APCS_MSM8916=y
+    - [Config] arm64: snapdragon: CONFIG_NLS_ISO8859_1=y
+    - [Config] arm64: snapdragon: CONFIG_USB_USBNET=y
+    - [Config] arm64: snapdragon: CONFIG_CRYPTO_DEV_QCOM_RNG=y
+    - [Config] arm64: snapdragon: CONFIG_POWER_RESET_QCOM_PON=y
+    - [Config] arm64: snapdragon: CONFIG_INPUT_PM8941_PWRKEY=y
+    - [Config] arm64: snapdragon: CONFIG_KEYBOARD_GPIO=y
+    - [Config] arm64: snapdragon: CONFIG_RTC_DRV_PM8XXX=y
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updateconfigs after rebase to 5.4-rc2
+    - SAUCE: (lockdown) Make get_cert_list() not complain about cert lists that
+      aren't present.
+    - SAUCE: (lockdown) Add efi_status_to_str() and rework efi_status_to_err().
+    - SAUCE: (lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (lockdown) security: lockdown: expose a hook to lock the kernel down
+    - SAUCE: (lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure boot
+      mode
+    - SAUCE: (lockdown) efi: Lock down the kernel if booted in secure boot mode
+    - SAUCE: (lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (lockdown) KEYS: Make use of platform keyring for module signature
+      verify
+    - SAUCE: (lockdown) arm64: Allow locking down the kernel under EFI secure boot
+    - SAUCE: (lockdown) security: lockdown: Make
+      CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT more generic
+    - SAUCE: (lockdown) s390/ipl: lockdown kernel when booted secure
+    - [Config] Enable lockdown under secure boot
+    - SAUCE: import aufs driver
+    - SAUCE: aufs: rwsem owner changed to atmoic_long_t in 5.3
+    - SAUCE: aufs: add "WITH Linux-syscall-note" to SPDX tag of uapi headers
+    - [Config] enable aufs
+    - update dkms package versions
+    - [Config] disable zfs
+    - [Config] disable nvidia dkms build
+    - [Config] disable virtualbox dkms build
+    - [Debian] Generate stub reconstruct for -rc kernels
+    - Revert "UBUNTU: SAUCE: (namespace) block_dev: Forbid unprivileged mounting
+      when device is opened for writing"
+    - Revert "UBUNTU: SAUCE: (namespace) ext4: Add module parameter to enable user
+      namespace mounts"
+    - Revert "UBUNTU: SAUCE: (namespace) ext4: Add support for unprivileged mounts
+      from user namespaces"
+    - Revert "UBUNTU: SAUCE: (namespace) mtd: Check permissions towards mtd block
+      device inode when mounting"
+    - Revert "UBUNTU: SAUCE: (namespace) block_dev: Check permissions towards
+      block device inode when mounting"
+    - Revert "UBUNTU: SAUCE: (namespace) block_dev: Support checking inode
+      permissions in lookup_bdev()"
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.4-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 11 Oct 2019 16:42:41 -0500
+
+linux (5.4.0-0.0) eoan; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 08 Oct 2019 09:59:00 -0500
+
+linux (5.3.0-17.18) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-17.18 -proposed tracker (LP: #1846641)
+
+  * 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()
+
+  * xHCI on AMD Stoney Ridge cannot detect USB 2.0 or 1.1 devices.
+    (LP: #1846470)
+    - x86/PCI: Avoid AMD FCH XHCI USB PME# from D0 defect
+
+  * Re-enable linux-libc-dev build on i386 (LP: #1846508)
+    - [Packaging] Build only linux-libc-dev for i386
+    - [Debian] final-checks -- ignore archtictures with no binaries
+
+  * arm64: loop on boot after installing linux-generic-hwe-18.04-edge/bionic-
+    proposed (LP: #1845820)
+    - [Config] Disable CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT
+
+  * Revert ESE DASD discard support (LP: #1846219)
+    - SAUCE: Revert "s390/dasd: Add discard support for ESE volumes"
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 03 Oct 2019 16:57:05 -0500
+
+linux (5.3.0-16.17) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-16.17 -proposed tracker (LP: #1846204)
+
+  * zfs fails to build on s390x  with debug symbols enabled (LP: #1846143)
+    - SAUCE: s390: Mark atomic const ops always inline
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 01 Oct 2019 07:46:43 -0500
+
+linux (5.3.0-15.16) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-15.16 -proposed tracker (LP: #1845987)
+
+  * Drop i386 build for 19.10 (LP: #1845714)
+    - [Packaging] Remove x32 arch references from control files
+    - [Debian] final-checks -- Get arch list from debian/control
+
+  * ZFS kernel modules lack debug symbols (LP: #1840704)
+    - [Debian] Fix conditional for setting zfs debug package path
+
+  * Use pyhon3-sphinx instead of python-sphinx for building html docs
+    (LP: #1845808)
+    - [Packaging] Update sphinx build dependencies to python3 packages
+
+  * Kernel panic with 19.10 beta image (LP: #1845454)
+    - efi/tpm: Don't access event->count when it isn't mapped.
+    - efi/tpm: don't traverse an event log with no events
+    - efi/tpm: only set efi_tpm_final_log_size after successful event log parsing
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 30 Sep 2019 11:57:20 -0500
+
+linux (5.3.0-14.15) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-14.15 -proposed tracker (LP: #1845728)
+
+  * Drop i386 build for 19.10 (LP: #1845714)
+    - [Debian] Remove support for producing i386 kernels
+    - [Debian] Don't use CROSS_COMPILE for i386 configs
+
+  * udevadm trigger will fail when trying to add /sys/devices/vio/
+    (LP: #1845572)
+    - SAUCE: powerpc/vio: drop bus_type from parent device
+
+  * Trying to online dasd drive results in invalid input/output from the kernel
+    on z/VM (LP: #1845323)
+    - SAUCE: s390/dasd: Fix error handling during online processing
+
+  * intel-lpss driver conflicts with write-combining MTRR region (LP: #1845584)
+    - SAUCE: mfd: intel-lpss: add quirk for Dell XPS 13 7390 2-in-1
+
+  * Support Hi1620 zip hw accelerator (LP: #1845355)
+    - [Config] Enable HiSilicon QM/ZIP as modules
+    - crypto: hisilicon - add queue management driver for HiSilicon QM module
+    - crypto: hisilicon - add hardware SGL support
+    - crypto: hisilicon - add HiSilicon ZIP accelerator support
+    - crypto: hisilicon - add SRIOV support for ZIP
+    - Documentation: Add debugfs doc for hisi_zip
+    - crypto: hisilicon - add debugfs for ZIP and QM
+    - MAINTAINERS: add maintainer for HiSilicon QM and ZIP controller driver
+    - crypto: hisilicon - fix kbuild warnings
+    - crypto: hisilicon - add dependency for CRYPTO_DEV_HISI_ZIP
+    - crypto: hisilicon - init curr_sgl_dma to fix compile warning
+    - crypto: hisilicon - add missing single_release
+    - crypto: hisilicon - fix error handle in hisi_zip_create_req_q
+    - crypto: hisilicon - Fix warning on printing %p with dma_addr_t
+    - crypto: hisilicon - Fix return value check in hisi_zip_acompress()
+    - crypto: hisilicon - avoid unused function warning
+
+  * SafeSetID LSM should be built but disabled by default (LP: #1845391)
+    - LSM: SafeSetID: Stop releasing uninitialized ruleset
+    - [Config] Build SafeSetID LSM but don't enable it by default
+
+  * CONFIG_LSM should not specify loadpin since it is not built (LP: #1845383)
+    - [Config] loadpin shouldn't be in CONFIG_LSM
+
+  * Add new pci-id's for CML-S, ICL (LP: #1845317)
+    - drm/i915/icl: Add missing device ID
+    - drm/i915/cml: Add Missing PCI IDs
+
+  * Thunderbolt support for ICL (LP: #1844680)
+    - thunderbolt: Correct path indices for PCIe tunnel
+    - thunderbolt: Move NVM upgrade support flag to struct icm
+    - thunderbolt: Use 32-bit writes when writing ring producer/consumer
+    - thunderbolt: Do not fail adding switch if some port is not implemented
+    - thunderbolt: Hide switch attributes that are not set
+    - thunderbolt: Expose active parts of NVM even if upgrade is not supported
+    - thunderbolt: Add support for Intel Ice Lake
+    - ACPI / property: Add two new Thunderbolt property GUIDs to the list
+
+  * Ubuntu 19.10 -  Additional PCI patch and fix (LP: #1844668)
+    - s390/pci: fix MSI message data
+
+  * Enhanced Hardware Support - Finalize Naming (LP: #1842774)
+    - s390: add support for IBM z15 machines
+    - [Config] CONFIG_MARCH_Z15=n, CONFIG_TUNE_Z15=n
+
+  * Eoan update: v5.3.1 upstream stable release (LP: #1845642)
+    - USB: usbcore: Fix slab-out-of-bounds bug during device reset
+    - media: tm6000: double free if usb disconnect while streaming
+    - phy: renesas: rcar-gen3-usb2: Disable clearing VBUS in over-current
+    - ip6_gre: fix a dst leak in ip6erspan_tunnel_xmit
+    - net/sched: fix race between deactivation and dequeue for NOLOCK qdisc
+    - net_sched: let qdisc_put() accept NULL pointer
+    - udp: correct reuseport selection with connected sockets
+    - xen-netfront: do not assume sk_buff_head list is empty in error handling
+    - net: dsa: Fix load order between DSA drivers and taggers
+    - net: stmmac: Hold rtnl lock in suspend/resume callbacks
+    - KVM: coalesced_mmio: add bounds checking
+    - Documentation: sphinx: Add missing comma to list of strings
+    - firmware: google: check if size is valid when decoding VPD data
+    - serial: sprd: correct the wrong sequence of arguments
+    - tty/serial: atmel: reschedule TX after RX was started
+    - nl80211: Fix possible Spectre-v1 for CQM RSSI thresholds
+    - Revert "arm64: Remove unnecessary ISBs from set_{pte,pmd,pud}"
+    - ovl: fix regression caused by overlapping layers detection
+    - phy: qcom-qmp: Correct ready status, again
+    - floppy: fix usercopy direction
+    - media: technisat-usb2: break out of loop at end of buffer
+    - Linux 5.3.1
+
+  * ZFS kernel modules lack debug symbols (LP: #1840704)
+    - [Debian]: Remove hardcoded $(pkgdir) in debug symbols handling
+    - [Debian]: Handle debug symbols for modules in extras too
+    - [Debian]: Check/link modules with debug symbols after DKMS modules
+    - [Debian]: Warn about modules without debug symbols
+    - [Debian]: dkms-build: new parameter for debug package directory
+    - [Debian]: dkms-build: zfs: support for debug symbols
+    - [Debian]: dkms-build: Avoid executing post-processor scripts twice
+    - [Debian]: dkms-build: Move zfs special-casing into configure script
+
+  * /proc/self/maps paths missing on live session (was vlc won't start; eoan
+    19.10 & bionic 18.04 ubuntu/lubuntu/kubuntu/xubuntu/ubuntu-mate dailies)
+    (LP: #1842382)
+    - SAUCE: Revert "UBUNTU: SAUCE: shiftfs: enable overlayfs on shiftfs"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 27 Sep 2019 16:08:06 -0500
+
+linux (5.3.0-13.14) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-13.14 -proposed tracker (LP: #1845105)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Remove binutils-dev build dependency
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 23 Sep 2019 19:26:43 -0500
+
+linux (5.3.0-12.13) eoan; urgency=medium
+
+  * Change kernel compression method to improve boot speed (LP: #1840934)
+    - [Packaging] Add lz4 build dependency for s390x
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Remove spl and zfs source
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 17 Sep 2019 13:36:26 +0200
+
+linux (5.3.0-11.12) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-11.12 -proposed tracker (LP: #1844144)
+
+  *  Suspend to RAM(S3) does not wake up for latest megaraid and mpt3sas
+    adapters(SAS3.5 onwards) (LP: #1838751)
+    - PCI: Restore Resizable BAR size bits correctly for 1MB BARs
+
+  * s390/setup: Actually init kernel lock down (LP: #1843961)
+    - SAUCE: (lockdown) s390/setup: Actually init kernel lock down
+
+  * cherrypick has_sipl fix (LP: #1843960)
+    - SAUCE: s390/sclp: Fix bit checked for has_sipl
+
+  * Change kernel compression method to improve boot speed (LP: #1840934)
+    - [Config]: Switch kernel compression from LZO to LZ4 on s390x
+
+  * Installation fails on eoan/PowerVM : missing /dev/nvram (LP: #1837726)
+    - [Config] CONFIG_NVRAM=y for ppc64el
+
+  * Miscellaneous Ubuntu changes
+    - [Config]: remove nvram from ppc64el modules ABI
+    - [Config] Update annotations for recent config changes
+    - SAUCE: sched: Add __ASSEMBLY__ guards around struct clone_args
+    - SAUCE: i2c: qcom-geni: Disable DMA processing on the Lenovo Yoga C630
+    - SAUCE: arm64: dts: qcom: Add Lenovo Yoga C630
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 16 Sep 2019 16:18:27 +0200
+
+linux (5.3.0-10.11) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-10.11 -proposed tracker (LP: #1843232)
+
+  * No sound inputs from the external microphone and headset on a Dell machine
+    (LP: #1842265)
+    - SAUCE: ALSA: hda - Expand pin_match function to match upcoming new tbls
+    - SAUCE: ALSA: hda - Define a fallback_pin_fixup_tbl for alc269 family
+
+  * Horizontal corrupted line at top of screen caused by framebuffer compression
+    (LP: #1840236)
+    - SAUCE: drm/i915/fbc: disable framebuffer compression on IceLake
+
+  * Add bpftool to linux-tools-common (LP: #1774815)
+    - [Debian] package bpftool in linux-tools-common
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc8
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 09 Sep 2019 10:00:41 +0200
+
+linux (5.3.0-9.10) eoan; urgency=medium
+
+  * eoan/linux: 5.3.0-9.10 -proposed tracker (LP: #1842393)
+
+  * shiftfs: mark kmem_cache as reclaimable (LP: #1842059)
+    - SAUCE: shiftfs: mark slab objects SLAB_RECLAIM_ACCOUNT
+
+  * shiftfs: drop entries from cache on unlink (LP: #1841977)
+    - SAUCE: shiftfs: fix buggy unlink logic
+
+  * Fix touchpad IRQ storm after S3 (LP: #1841396)
+    - pinctrl: intel: remap the pin number to gpio offset for irq enabled pin
+
+  * Please include DTBs for arm64 laptops (LP: #1842050)
+    - arm64: dts: qcom: Add Lenovo Miix 630
+    - arm64: dts: qcom: Add HP Envy x2
+    - arm64: dts: qcom: Add Asus NovaGo TP370QL
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: import aufs driver
+    - [Packaging]: ignore vbox modules when vbox is disabled
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc7
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Tue, 03 Sep 2019 10:27:33 +0200
+
+linux (5.3.0-8.9) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  * Change kernel compression method to improve boot speed (LP: #1840934)
+    - [Config] change kernel compression method to improve boot speed
+    - [Packaging] add build dependencies for compression algorithms
+
+  * realtek r8822be kernel module fails after update to linux kernel-headers
+    5.0.0-21 (LP: #1838133)
+    - rtw88: Fix misuse of GENMASK macro
+    - rtw88: pci: Rearrange the memory usage for skb in RX ISR
+    - rtw88: pci: Use DMA sync instead of remapping in RX ISR
+    - rtw88: debug: dump tx power indexes in use
+    - rtw88: use txpwr_lmt_cfg_pair struct, not arrays
+    - rtw88: pci: remove set but not used variable 'ip_sel'
+    - rtw88: allow c2h operation in irq context
+    - rtw88: enclose c2h cmd handle with mutex
+    - rtw88: add BT co-existence support
+    - SAUCE: rtw88: pci: enable MSI interrupt
+
+  * VIMC module not available (CONFIG_VIDEO_VIMC not set) (LP: #1831482)
+    - [Config] Enable VIMC module
+
+  * Goodix touchpad may drop first input event (LP: #1840075)
+    - Revert "UBUNTU: SAUCE: i2c: designware: add G3 3590 into i2c quirk"
+    - Revert "UBUNTU: SAUCE: i2c: designware: add Inpiron 7591 into i2c quirk"
+    - Revert "UBUNTU: SAUCE: i2c: designware: add Inpiron/Vostro 7590 into i2c
+      quirk"
+    - Revert "UBUNTU: SAUCE: i2c: designware: Add disable runtime pm quirk"
+    - mfd: intel-lpss: Remove D3cold delay
+
+  * Include Sunix serial/parallel driver (LP: #1826716)
+    - serial: 8250_pci: Add support for Sunix serial boards
+    - parport: parport_serial: Add support for Sunix Multi I/O boards
+
+  * enable lockdown on s390x when Secure IPL is performed (LP: #1839622)
+    - SAUCE: (lockdown) s390/ipl: lockdown kernel when booted secure
+    - Ubuntu: [Config] Enable CONFIG_LOCK_DOWN_KERNEL on s390x.
+
+  * UBUNTU: SAUCE: shiftfs: pass correct point down (LP: #1837231)
+    - SAUCE: shiftfs: pass correct point down
+
+  * shiftfs: add O_DIRECT support (LP: #1837223)
+    - SAUCE: shiftfs: add O_DIRECT support
+
+  * Miscellaneous Ubuntu changes
+    - [Config] enable secureboot signing on s390x
+    - [Config] CONFIG_TEST_BLACKHOLE_DEV=m
+    - SAUCE: selftests: fib_tests: assign address to dummy1 for rp_filter tests
+    - [Debian] disable dkms builds for autopktest rebuilds
+    - update dkms package versions
+    - [Config] updateconfigs after v5.3-rc6 rebase
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc5
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 26 Aug 2019 10:09:42 +0200
+
+linux (5.3.0-7.8) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  * Miscellaneous Ubuntu changes
+    - [Config] updateconfigs after v5.3-rc5 rebase
+    - remove missing module after updateconfigs
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc5
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 19 Aug 2019 15:31:24 +0200
+
+linux (5.3.0-6.7) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/bpf: prevent headers to be compiled as C code
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 14 Aug 2019 13:25:01 -0500
+
+linux (5.3.0-5.6) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Config] enable zfs build
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 13 Aug 2019 09:16:06 -0500
+
+linux (5.3.0-4.5) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+
+  * 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
+
+  * shiftfs: allow overlayfs (LP: #1838677)
+    - SAUCE: shiftfs: enable overlayfs on shiftfs
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Revert "kbuild: modpost: do not parse unnecessary rules for vmlinux
+      modpost"
+    - update dkms package versions
+    - enable nvidia dkms build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 12 Aug 2019 10:41:27 -0500
+
+linux (5.3.0-3.4) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - SAUCE: aufs: add "WITH Linux-syscall-note" to SPDX tag of uapi headers
+    - [Config] add mux-* to modules.ignore
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc3
+
+ -- Paolo Pisati <paolo.pisati@canonical.com>  Mon, 05 Aug 2019 18:17:09 +0200
+
+linux (5.3.0-2.3) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] add build dependincy on fontconfig
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 29 Jul 2019 12:18:46 -0400
+
+linux (5.3.0-1.2) eoan; urgency=medium
+
+  * System does not auto detect disconnection of external monitor (LP: #1835001)
+    - SAUCE: drm/i915: Add support for retrying hotplug
+    - SAUCE: drm/i915: Enable hotplug retry
+
+  * Please enable CONFIG_SCSI_UFS_QCOM as a module on arm64 (LP: #1837332)
+    - [Config] Enable CONFIG_SCSI_UFS_QCOM as a module on arm64.
+
+  * Add arm64 CONFIG_ARCH_MESON=y and related configs Edit (LP: #1820530)
+    - [Config] enable ARCH_MESON
+    - remove missing module
+    - [Config] update annotations after enabling ARCH_MESON for arm64
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: KVM: PPC: comment implicit fallthrough
+    - update dkms package versions
+    - [Config] enable vbox dkms build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 28 Jul 2019 23:10:16 -0400
+
+linux (5.3.0-0.1) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) kexec_file: split KEXEC_VERIFY_SIG into KEXEC_SIG and
+      KEXEC_SIG_FORCE
+    - SAUCE: (efi-lockdown) kexec_file: Restrict at runtime if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) lockdown: Print current->comm in restriction messages
+    - SAUCE: (efi-lockdown) kexec: Allow kexec_file() with appropriate IMA policy
+      when locked down
+    - SAUCE: (efi-lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (efi-lockdown) debugfs: avoid EPERM when no open file operation
+      defined
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) KEYS: Make use of platform keyring for module
+      signature verify
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) furter KEXEC_VERIFY_SIG -> KEXEC_SIG updates
+    - SAUCE: (efi-lockdown) arm64: add kernel config option to lock down when in
+      Secure Boot mode
+    - SAUCE: import aufs driver
+    - SAUCE: aufs: rwsem owner changed to atmoic_long_t in 5.3
+    - [Config] disable zfs dkms build
+    - [Config] disable nvidia dkms build
+    - [Config] disable vbox dkms build
+    - SAUCE: perf diff: use llabs for s64 vaules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.3-rc1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 23 Jul 2019 21:45:44 -0500
+
+linux (5.3.0-0.0) eoan; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 22 Jul 2019 10:19:04 -0500
+
+linux (5.2.0-9.10) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * input/mouse: alps trackpoint-only device doesn't work (LP: #1836752)
+    - SAUCE: Input: alps - don't handle ALPS cs19 trackpoint-only device
+    - SAUCE: Input: alps - fix a mismatch between a condition check and its
+      comment
+
+  * System does not auto detect disconnection of external monitor (LP: #1835001)
+    - SAUCE: drm/i915: Add support for retrying hotplug
+    - SAUCE: drm/i915: Enable hotplug retry
+
+  * alsa/hdmi: add icelake hdmi audio support for a Dell machine (LP: #1836916)
+    - SAUCE: ALSA: hda/hdmi - Remove duplicated define
+    - SAUCE: ALSA: hda/hdmi - Fix i915 reverse port/pin mapping
+
+  * First click on Goodix touchpad doesn't be recognized after runtime suspended
+    (LP: #1836836)
+    - SAUCE: i2c: designware: add G3 3590 into i2c quirk
+
+  * 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
+
+  * Doing multiple squashfs (and other loop?) mounts in parallel breaks
+    (LP: #1836914)
+    - SAUCE: Revert "loop: Don't change loop device under exclusive opener"
+
+  * hibmc-drm Causes Unreadable Display for Huawei amd64 Servers (LP: #1762940)
+    - SAUCE: Make CONFIG_DRM_HISI_HIBMC depend on ARM64
+    - [Config] Set CONFIG_DRM_HISI_HIBMC to arm64 only
+    - [Config] add hibmc-drm to modules.ignore
+
+  * hda/realtek: can't detect external mic on a Dell machine (LP: #1836755)
+    - ALSA: hda/realtek: apply ALC891 headset fixup to one Dell machine
+
+  * Enable Armada SOCs and MVPP2 NIC driver for disco/generic arm64
+    (LP: #1835054)
+    - [Config] Enable Armada SOCs and MVPP2 NIC driver for disco/generic arm64
+
+  * Unhide Nvidia HDA audio controller (LP: #1836308)
+    - PCI: Enable NVIDIA HDA controllers
+
+  * Intel ethernet I219 may wrongly detect connection speed as 10Mbps
+    (LP: #1836177)
+    - e1000e: Make watchdog use delayed work
+
+  * Sometimes touchpad(goodix) can't use tap function (LP: #1836020)
+    - SAUCE: i2c: designware: add Inpiron/Vostro 7590 into i2c quirk
+    - SAUCE: i2c: designware: add Inpiron 7591 into i2c quirk
+
+  * Intel ethernet I219 has slow RX speed (LP: #1836152)
+    - e1000e: add workaround for possible stalled packet
+    - e1000e: disable force K1-off feature
+
+  * bcache: risk of data loss on I/O errors in backing or caching devices
+    (LP: #1829563)
+    - Revert "bcache: set CACHE_SET_IO_DISABLE in bch_cached_dev_error()"
+
+  * bnx2x driver causes 100% CPU load (LP: #1832082)
+    - bnx2x: Prevent ptp_task to be rescheduled indefinitely
+
+  * fcf-protection=none patch with new version
+    - Revert "UBUNTU: SAUCE: kbuild: add -fcf-protection=none to retpoline flags"
+    - SAUCE: kbuild: add -fcf-protection=none when using retpoline flags
+
+  * CVE-2019-12614
+    - powerpc/pseries/dlpar: Fix a missing check in dlpar_parse_cc_property()
+
+  * Eoan update: v5.2.1 upstream stable release (LP: #1836622)
+    - crypto: lrw - use correct alignmask
+    - crypto: talitos - rename alternative AEAD algos.
+    - fscrypt: don't set policy for a dead directory
+    - udf: Fix incorrect final NOT_ALLOCATED (hole) extent length
+    - media: stv0297: fix frequency range limit
+    - ALSA: usb-audio: Fix parse of UAC2 Extension Units
+    - ALSA: hda/realtek - Headphone Mic can't record after S3
+    - tpm: Actually fail on TPM errors during "get random"
+    - tpm: Fix TPM 1.2 Shutdown sequence to prevent future TPM operations
+    - block: fix .bi_size overflow
+    - block, bfq: NULL out the bic when it's no longer valid
+    - perf intel-pt: Fix itrace defaults for perf script
+    - perf auxtrace: Fix itrace defaults for perf script
+    - perf intel-pt: Fix itrace defaults for perf script intel-pt documentation
+    - perf pmu: Fix uncore PMU alias list for ARM64
+    - perf thread-stack: Fix thread stack return from kernel for kernel-only case
+    - perf header: Assign proper ff->ph in perf_event__synthesize_features()
+    - x86/ptrace: Fix possible spectre-v1 in ptrace_get_debugreg()
+    - x86/tls: Fix possible spectre-v1 in do_get_thread_area()
+    - Documentation: Add section about CPU vulnerabilities for Spectre
+    - Documentation/admin: Remove the vsyscall=native documentation
+    - 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
+    - Revert "serial: 8250: Don't service RX FIFO if interrupts are disabled"
+    - p54usb: Fix race between disconnect and firmware loading
+    - usb: gadget: f_fs: data_len used before properly set
+    - usb: gadget: ether: Fix race between gether_disconnect and rx_submit
+    - usb: dwc2: use a longer AHB idle timeout in dwc2_core_reset()
+    - usb: renesas_usbhs: add a workaround for a race condition of workqueue
+    - drivers/usb/typec/tps6598x.c: fix portinfo width
+    - drivers/usb/typec/tps6598x.c: fix 4CC cmd write
+    - p54: fix crash during initialization
+    - staging: comedi: dt282x: fix a null pointer deref on interrupt
+    - staging: wilc1000: fix error path cleanup in wilc_wlan_initialize()
+    - staging: bcm2835-camera: Restore return behavior of ctrl_set_bitrate()
+    - staging: comedi: amplc_pci230: fix null pointer deref on interrupt
+    - staging: mt7621-pci: fix PCIE_FTS_NUM_LO macro
+    - HID: Add another Primax PIXART OEM mouse quirk
+    - lkdtm: support llvm-objcopy
+    - binder: fix memory leak in error path
+    - binder: return errors from buffer copy functions
+    - iio: adc: stm32-adc: add missing vdda-supply
+    - coresight: Potential uninitialized variable in probe()
+    - coresight: etb10: Do not call smp_processor_id from preemptible
+    - coresight: tmc-etr: Do not call smp_processor_id() from preemptible
+    - coresight: tmc-etr: alloc_perf_buf: Do not call smp_processor_id from
+      preemptible
+    - coresight: tmc-etf: Do not call smp_processor_id from preemptible
+    - carl9170: fix misuse of device driver API
+    - Revert "x86/build: Move _etext to actual end of .text"
+    - VMCI: Fix integer overflow in VMCI handle arrays
+    - staging: vchiq_2835_arm: revert "quit using custom down_interruptible()"
+    - staging: vchiq: make wait events interruptible
+    - staging: vchiq: revert "switch to wait_for_completion_killable"
+    - staging: fsl-dpaa2/ethsw: fix memory leak of switchdev_work
+    - staging: bcm2835-camera: Replace spinlock protecting context_map with mutex
+    - staging: bcm2835-camera: Ensure all buffers are returned on disable
+    - staging: bcm2835-camera: Remove check of the number of buffers supplied
+    - staging: bcm2835-camera: Handle empty EOS buffers whilst streaming
+    - staging: rtl8712: reduce stack usage, again
+    - Linux 5.2.1
+    - [Config] updateconfigs after v5.2.1 stable update
+
+  * fcf-protection=none patch with upstream version
+    - Revert "UBUNTU: SAUCE: add -fcf-protection=none to retpoline flags"
+    - SAUCE: kbuild: add -fcf-protection=none to retpoline flags
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/ftrace: avoid failure when trying to probe a notrace
+      function
+    - SAUCE: selftests/powerpc/ptrace: fix build failure
+    - update dkms package versions
+    - [Packaging] add zlua to zfs-modules.ignore
+    - update dkms package versions
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 19 Jul 2019 15:04:45 -0500
+
+linux (5.2.0-8.9) eoan; urgency=medium
+
+  * linux: 5.2.0-8.9 -proposed tracker (LP: #1835700)
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] replace zfs and spl build with zfs 0.8.1-1ubuntu1
+    - SAUCE: test_bpf: remove expected fail for Ctx heavy transformations test on
+      s390
+    - SAUCE: add -fcf-protection=none to retpoline flags
+    - SAUCE: usbip: ensure strings copied using strncpy are null-terminated
+    - SAUCE: usbip: add -Wno-address-of-packed-member to EXTRA_CFLAGS
+    - SAUCE: perf jvmti: ensure strncpy result is null-terminated
+    - update dkms package versions
+    - add removed zfs modules to modules.ignore
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 08 Jul 2019 07:13:41 -0500
+
+linux (5.2.0-7.8) eoan; urgency=medium
+
+  * Kernel panic upon resetting ixgbe SR-IOV VFIO virtual function using 5.0
+    kernel (LP: #1829652)
+    - SAUCE: ixgbe: Avoid NULL pointer dereference with VF on non-IPsec hw
+
+  * Hi1620 driver updates from upstream 5.2 merge window (LP: #1830815)
+    - net: hns3: initialize CPU reverse mapping
+    - net: hns3: refine the flow director handle
+    - net: hns3: add aRFS support for PF
+    - net: hns3: fix for FEC configuration
+    - RDMA/hns: Remove unnecessary print message in aeq
+    - RDMA/hns: Update CQE specifications
+    - RDMA/hns: Move spin_lock_irqsave to the correct place
+    - RDMA/hns: Remove jiffies operation in disable interrupt context
+    - RDMA/hns: Replace magic numbers with #defines
+    - net: hns3: fix compile warning without CONFIG_RFS_ACCEL
+    - net: hns3: fix for HNS3_RXD_GRO_SIZE_M macro
+    - net: hns3: add support for dump firmware statistics by debugfs
+    - net: hns3: use HCLGE_STATE_NIC_REGISTERED to indicate PF NIC client has
+      registered
+    - net: hns3: use HCLGE_STATE_ROCE_REGISTERED to indicate PF ROCE client has
+      registered
+    - net: hns3: use HCLGEVF_STATE_NIC_REGISTERED to indicate VF NIC client has
+      registered
+    - net: hns3: modify hclge_init_client_instance()
+    - net: hns3: modify hclgevf_init_client_instance()
+    - net: hns3: add handshake with hardware while doing reset
+    - net: hns3: stop schedule reset service while unloading driver
+    - net: hns3: adjust hns3_uninit_phy()'s location in the hns3_client_uninit()
+    - net: hns3: fix a memory leak issue for hclge_map_unmap_ring_to_vf_vector
+    - RDMA/hns: Bugfix for posting multiple srq work request
+    - net: hns3: remove redundant core reset
+    - net: hns3: don't configure new VLAN ID into VF VLAN table when it's full
+    - net: hns3: fix VLAN filter restore issue after reset
+    - net: hns3: set the port shaper according to MAC speed
+    - net: hns3: add a check to pointer in error_detected and slot_reset
+    - net: hns3: set ops to null when unregister ad_dev
+    - net: hns3: add handling of two bits in MAC tunnel interrupts
+    - net: hns3: remove setting bit of reset_requests when handling mac tunnel
+      interrupts
+    - net: hns3: add opcode about query and clear RAS & MSI-X to special opcode
+    - net: hns3: delay and separate enabling of NIC and ROCE HW errors
+    - RDMA/hns: fix inverted logic of readl read and shift
+    - RDMA/hns: Bugfix for filling the sge of srq
+    - net: hns3: log detail error info of ROCEE ECC and AXI errors
+    - net: hns3: fix wrong size of mailbox responding data
+    - net: hns3: make HW GRO handling compliant with SW GRO
+    - net: hns3: replace numa_node_id with numa_mem_id for buffer reusing
+    - net: hns3: refactor hns3_get_new_int_gl function
+    - net: hns3: trigger VF reset if a VF has an over_8bd_nfe_err
+    - net: hns3: delete the redundant user NIC codes
+    - net: hns3: small changes for magic numbers
+    - net: hns3: use macros instead of magic numbers
+    - net: hns3: refactor PF/VF RSS hash key configuration
+    - net: hns3: some modifications to simplify and optimize code
+    - net: hns3: fix some coding style issues
+    - net: hns3: delay setting of reset level for hw errors until slot_reset is
+      called
+    - net: hns3: fix avoid unnecessary resetting for the H/W errors which do not
+      require reset
+    - net: hns3: process H/W errors occurred before HNS dev initialization
+    - net: hns3: add recovery for the H/W errors occurred before the HNS dev
+      initialization
+    - net: hns3: some changes of MSI-X bits in PPU(RCB)
+    - net: hns3: extract handling of mpf/pf msi-x errors into functions
+    - net: hns3: clear restting state when initializing HW device
+    - net: hns3: free irq when exit from abnormal branch
+    - net: hns3: fix for dereferencing before null checking
+    - net: hns3: fix for skb leak when doing selftest
+    - net: hns3: delay ring buffer clearing during reset
+    - net: hns3: some variable modification
+    - net: hns3: fix dereference of ae_dev before it is null checked
+    - scsi: hisi_sas: Delete PHY timers when rmmod or probe failed
+    - scsi: hisi_sas: Fix the issue of argument mismatch of printing ecc errors
+    - scsi: hisi_sas: Reduce HISI_SAS_SGE_PAGE_CNT in size
+    - scsi: hisi_sas: Change the type of some numbers to unsigned
+    - scsi: hisi_sas: Ignore the error code between phy down to phy up
+    - scsi: hisi_sas: Disable stash for v3 hw
+    - net: hns3: Add missing newline at end of file
+    - RDMa/hns: Don't stuck in endless timeout loop
+
+  * Sometimes touchpad automatically trigger double click (LP: #1833484)
+    - SAUCE: i2c: designware: Add disable runtime pm quirk
+
+  * Add pointstick support on HP ZBook 17 G5 (LP: #1833387)
+    - Revert "HID: multitouch: Support ALPS PTP stick with pid 0x120A"
+
+  * depmod may prefer unsigned l-r-m nvidia modules to signed modules
+    (LP: #1834479)
+    - [Packaging] dkms-build--nvidia-N -- clean up unsigned ko files
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/powerpc: disable signal_fuzzer test
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 01 Jul 2019 07:22:18 -0500
+
+linux (5.2.0-6.7) eoan; urgency=medium
+
+  * hinic: fix oops due to race in set_rx_mode (LP: #1832048)
+    - hinic: fix a bug in set rx mode
+
+  * Miscellaneous Ubuntu changes
+    - rebase to v5.2-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 23 Jun 2019 23:36:11 -0500
+
+linux (5.2.0-5.6) eoan; urgency=medium
+
+  * QCA9377 isn't being recognized sometimes (LP: #1757218)
+    - SAUCE: USB: Disable USB2 LPM at shutdown
+
+  * shiftfs: allow changing ro/rw for subvolumes (LP: #1832316)
+    - SAUCE: shiftfs: allow changing ro/rw for subvolumes
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - [Packaging] replace nvidia-418 dkms build with nvidia-430
+    - SAUCE: import aufs driver
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 17 Jun 2019 15:04:12 -0500
+
+linux (5.2.0-4.5) eoan; urgency=medium
+
+  * arm64: cma_alloc errors at boot (LP: #1823753)
+    - [Config] Bump CMA_SIZE_MBYTES to 32 on arm64
+    - dma-contiguous: add dma_{alloc,free}_contiguous() helpers
+    - dma-contiguous: use fallback alloc_pages for single pages
+    - dma-contiguous: fix !CONFIG_DMA_CMA version of dma_{alloc,
+      free}_contiguous()
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_MFD_TQMX86=n for s390x
+    - [Config] CONFIG_GPIO_AMD_FCH=n for s390x
+    - [Config] CONFIG_BACKLIGHT_CLASS_DEVICE=n on s390x
+    - [Config] CONFIG_LCD_CLASS_DEVICE=n for s390x
+    - [Config] CONFIG_DRM_ETNAVIV=m for armhf generic-lpae
+    - [Config] CONFIG_DRM_NOUVEAU_SVM=n
+    - [Config] CONFIG_HWMON=n for s390x
+    - [Config] CONFIG_NEW_LEDS=n for s390x
+    - [Config] CONFIG_MTD_NAND_OMAP2=y for armhf
+    - [Config] CONFIG_VOP_BUS=n for non-amd64 arches
+    - [Config] CONFIG_TI_CPSW_PHY_SEL=n
+    - [Config] CONFIG_INTERCONNECT=n for s390x
+    - [Config] CONFIG_SCSI_GDTH=n for s390x
+    - [Config] CONFIG_PACKING=n for s390x
+    - [Config] CONFIG_ARCH_MILBEAUT=y for armhf
+    - [Config] update annotations following config review
+    - update dkms package versions
+    - [Config] enable nvidia dkms build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 10 Jun 2019 07:00:11 -0500
+
+linux (5.2.0-3.4) eoan; urgency=medium
+
+  * [18.04/18.10] File libperf-jvmti.so is missing in linux-tools-common deb on
+    Ubuntu (LP: #1761379)
+    - [Packaging] Support building libperf-jvmti.so
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Revert "bpf, selftest: test global data/bss/rodata sections"
+    - update dkms package versions
+    - [Config] enable zfs
+    - rebase to v5.2-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 02 Jun 2019 21:48:50 -0500
+
+linux (5.2.0-2.3) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: perf arm64: Fix mksyscalltbl when system kernel headers are ahead of
+      the kernel
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 28 May 2019 07:12:39 -0500
+
+linux (5.2.0-1.2) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_INTEGRITY_PLATFORM_KEYRING=y
+    - update dkms package versions
+    - [Config] enable vbox dkms build
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 27 May 2019 21:11:27 -0500
+
+linux (5.2.0-0.1) eoan; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: import aufs driver
+    - [Packaging] disable ZFS
+    - [Packaging] disable nvidia
+    - [Packaging] dkms-build -- expand paths searched for make.log files
+    - add virtualbox-guest-dkms dkms package build
+    - enable vbox dkms build for amd64 and i386
+    - update dkms package versions
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) kexec_file: split KEXEC_VERIFY_SIG into KEXEC_SIG and
+      KEXEC_SIG_FORCE
+    - SAUCE: (efi-lockdown) kexec_file: Restrict at runtime if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) lockdown: Print current->comm in restriction messages
+    - SAUCE: (efi-lockdown) kexec: Allow kexec_file() with appropriate IMA policy
+      when locked down
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) KEYS: Make use of platform keyring for module
+      signature verify
+    - SAUCE: (efi-lockdown) debugfs: avoid EPERM when no open file operation
+      defined
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) furter KEXEC_VERIFY_SIG -> KEXEC_SIG updates
+    - SAUCE: (efi-lockdown) arm64: add kernel config option to lock down when in
+      Secure Boot mode
+    - update dkms package versions
+    - [Config] disable vbox build
+    - SAUCE: s390: mark __cpacf_check_opcode() and cpacf_query_func() as
+      __always_inline
+    - SAUCE: IB/mlx5: use size_t instead of u64 when dividing
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.2-rc1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 21 May 2019 11:18:43 -0500
+
+linux (5.2.0-0.0) eoan; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 21 May 2019 07:34:43 -0500
+
+linux (5.1.0-2.2) eoan; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+
+  * Eoan update: v5.1.2 upstream stable release (LP: #1829050)
+    - 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()
+    - 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
+    - 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
+    - cpu/speculation: Add 'mitigations=' cmdline option
+    - x86/speculation: Support 'mitigations=' cmdline option
+    - powerpc/speculation: Support 'mitigations=' cmdline option
+    - s390/speculation: Support 'mitigations=' cmdline option
+    - x86/speculation/mds: Add 'mitigations=' support for MDS
+    - x86/mds: Add MDSUM variant to the MDS documentation
+    - Documentation: Correct the possible MDS sysfs values
+    - x86/speculation/mds: Fix documentation typo
+    - Linux 5.1.2
+
+  * Eoan update: v5.1.1 upstream stable release (LP: #1829046)
+    - Drivers: hv: vmbus: Remove the undesired put_cpu_ptr() in hv_synic_cleanup()
+    - ubsan: Fix nasty -Wbuiltin-declaration-mismatch GCC-9 warnings
+    - staging: greybus: power_supply: fix prop-descriptor request size
+    - staging: wilc1000: Avoid GFP_KERNEL allocation from atomic context.
+    - staging: most: cdev: fix chrdev_region leak in mod_exit
+    - staging: most: sound: pass correct device when creating a sound card
+    - usb: dwc3: Allow building USB_DWC3_QCOM without EXTCON
+    - usb: dwc3: Fix default lpm_nyet_threshold value
+    - USB: serial: f81232: fix interrupt worker not stop
+    - USB: cdc-acm: fix unthrottle races
+    - usb-storage: Set virt_boundary_mask to avoid SG overflows
+    - genirq: Prevent use-after-free and work list corruption
+    - intel_th: pci: Add Comet Lake support
+    - iio: adc: qcom-spmi-adc5: Fix of-based module autoloading
+    - cpufreq: armada-37xx: fix frequency calculation for opp
+    - ACPI / LPSS: Use acpi_lpss_* instead of acpi_subsys_* functions for
+      hibernate
+    - soc: sunxi: Fix missing dependency on REGMAP_MMIO
+    - scsi: lpfc: change snprintf to scnprintf for possible overflow
+    - scsi: qla2xxx: Fix incorrect region-size setting in optrom SYSFS routines
+    - scsi: qla2xxx: Set remote port devloss timeout to 0
+    - scsi: qla2xxx: Fix device staying in blocked state
+    - Bluetooth: hidp: fix buffer overflow
+    - Bluetooth: Align minimum encryption key size for LE and BR/EDR connections
+    - Bluetooth: Fix not initializing L2CAP tx_credits
+    - Bluetooth: hci_bcm: Fix empty regulator supplies for Intel Macs
+    - UAS: fix alignment of scatter/gather segments
+    - ASoC: Intel: avoid Oops if DMA setup fails
+    - i3c: Fix a shift wrap bug in i3c_bus_set_addr_slot_status()
+    - locking/futex: Allow low-level atomic operations to return -EAGAIN
+    - arm64: futex: Bound number of LDXR/STXR loops in FUTEX_WAKE_OP
+    - Linux 5.1.1
+
+  * shiftfs: lock security sensitive superblock flags (LP: #1827122)
+    - SAUCE: shiftfs: lock down certain superblock flags
+
+  * Please package libbpf (which is done out of the kernel src) in Debian [for
+    19.10] (LP: #1826410)
+    - SAUCE: tools -- fix add ability to disable libbfd
+
+  * ratelimit cma_alloc messages (LP: #1828092)
+    - SAUCE: cma: ratelimit cma_alloc error messages
+
+  * Headphone jack switch sense is inverted: plugging in headphones disables
+    headphone output (LP: #1824259)
+    - ASoC: rt5645: Headphone Jack sense inverts on the LattePanda board
+
+  * There are 4 HDMI/Displayport audio output listed in sound setting without
+    attach any HDMI/DP monitor (LP: #1827967)
+    - ALSA: hda/hdmi - Read the pin sense from register when repolling
+    - ALSA: hda/hdmi - Consider eld_valid when reporting jack event
+
+  * CONFIG_LOG_BUF_SHIFT set to 14 is too low on arm64 (LP: #1824864)
+    - [Config] CONFIG_LOG_BUF_SHIFT=18 on all 64bit arches
+
+  * CTAUTO:DevOps:860.50:devops4fp1:Error occurred during LINUX Dmesg error
+    Checking for all LINUX clients for devops4p10 (LP: #1766201)
+    - SAUCE: integrity: downgrade error to warning
+
+  * linux-buildinfo: pull out ABI information into its own package
+    (LP: #1806380)
+    - [Packaging] autoreconstruct -- base tag is always primary mainline version
+
+  * [SRU] Please sync vbox modules from virtualbox 6.0.6 on next kernel update
+    (LP: #1825210)
+    - vbox-update: updates for renamed makefiles
+    - ubuntu: vbox -- update to 6.0.6-dfsg-1
+
+  * autofs kernel module missing (LP: #1824333)
+    - [Config] Update autofs4 path in inclusion list
+
+  * The Realtek card reader does not enter PCIe 1.1/1.2 (LP: #1825487)
+    - SAUCE: misc: rtsx: Fixed rts5260 power saving parameter and sd glitch
+
+  * CVE-2019-3874
+    - sctp: implement memory accounting on tx path
+    - sctp: implement memory accounting on rx path
+
+  * apparmor does not start in Disco LXD containers (LP: #1824812)
+    - SAUCE: shiftfs: use separate llseek method for directories
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] autoreconstruct -- remove for -rc kernels
+    - SAUCE: (efi-lockdown) debugfs: avoid EPERM when no open file operation
+      defined
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) furter KEXEC_VERIFY_SIG -> KEXEC_SIG updates
+    - [Config] (efi-lockdown): update configs after efi lockdown patch refresh
+    - [Packaging] don't delete efi_parser.c
+    - vbox-update -- do not fix up KERN_DIR or KBUILD_EXTMOD
+    - ubuntu: vbox -- update to 6.0.6-dfsg-2
+    - add nvidia-418 dkms build
+    - remove virtualbox guest drivers
+    - [Packaging] dkms-build -- expand paths searched for make.log files
+    - add virtualbox-guest-dkms dkms package build
+    - enable vbox dkms build for amd64 and i386
+    - [Config] update configs for v5.1(-rc7)? rebase
+    - update dkms package versions
+    - Add the ability to lock down access to the running kernel image
+    - Enforce module signatures if the kernel is locked down
+    - Restrict /dev/{mem,kmem,port} when the kernel is locked down
+    - kexec_load: Disable at runtime if the kernel is locked down
+    - Copy secure_boot flag in boot params across kexec reboot
+    - kexec_file: split KEXEC_VERIFY_SIG into KEXEC_SIG and KEXEC_SIG_FORCE
+    - kexec_file: Restrict at runtime if the kernel is locked down
+    - hibernate: Disable when the kernel is locked down
+    - uswsusp: Disable when the kernel is locked down
+    - PCI: Lock down BAR access when the kernel is locked down
+    - x86: Lock down IO port access when the kernel is locked down
+    - x86/msr: Restrict MSR access when the kernel is locked down
+    - ACPI: Limit access to custom_method when the kernel is locked down
+    - acpi: Ignore acpi_rsdp kernel param when the kernel has been locked down
+    - acpi: Disable ACPI table override if the kernel is locked down
+    - acpi: Disable APEI error injection if the kernel is locked down
+    - Prohibit PCMCIA CIS storage when the kernel is locked down
+    - Lock down TIOCSSERIAL
+    - Lock down module params that specify hardware parameters (eg. ioport)
+    - x86/mmiotrace: Lock down the testmmiotrace module
+    - Lock down /proc/kcore
+    - Lock down kprobes
+    - bpf: Restrict kernel image access functions when the kernel is locked down
+    - Lock down perf
+    - debugfs: Restrict debugfs when the kernel is locked down
+    - lockdown: Print current->comm in restriction messages
+    - kexec: Allow kexec_file() with appropriate IMA policy when locked down
+    - Make get_cert_list() not complain about cert lists that aren't present.
+    - Add efi_status_to_str() and rework efi_status_to_err().
+    - Make get_cert_list() use efi_status_to_str() to print error messages.
+    - efi: Add an EFI_SECURE_BOOT flag to indicate secure boot mode
+    - efi: Lock down the kernel if booted in secure boot mode
+    - KEYS: Make use of platform keyring for module signature verify
+
+  * Miscellaneous upstream changes
+    - ALSA: hdea/realtek - Headset fixup for System76 Gazelle (gaze14)
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 14 May 2019 12:32:56 -0500
+
+linux (5.1.0-1.1) eoan; urgency=medium
+
+  * bionic: fork out linux-snapdragon into its own topic kernel (LP: #1820868)
+    - [Packaging]: really drop snapdragon
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: fix vbox use of MAP_SHARED
+    - SAUCE: fix vbox use of vm_fault_t
+    - [Packaging] disable ZFS
+    - [Packaging] disable nvidia
+    - SAUCE: perf annotate: Fix build on 32 bit for BPF annotation
+    - [Config]: updateconfig after rebase to v5.1-rc
+    - [Config]: build ETNAVIV only on arm platforms
+    - [Config]: Disable CMA on non-arm platforms
+    - [Config]: MMC_CQHCI is needed by some built-in drivers
+    - [Config]: a.out support has been deprecated
+    - [Config]: R3964 was marked as BROKEN
+    - [Config]: Add SENSIRION_SGP30 module
+
+  * Miscellaneous upstream changes
+    - Revert "UBUNTU: SAUCE: tools: lib/bpf -- add generated headers to search
+      path"
+    - Revert "UBUNTU: SAUCE: btqcomsmd: introduce BT_QCOMSMD_HACK"
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 25 Apr 2019 10:03:25 -0300
+
+linux (5.1.0-0.0) eoan; urgency=medium
+
+  * Dummy entry.
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Thu, 25 Apr 2019 09:49:47 -0300
+
+linux (5.0.0-13.14) disco; urgency=medium
+
+  * linux: 5.0.0-13.14 -proposed tracker (LP: #1824819)
+
+  * Display only has 640x480 (LP: #1824677)
+    - Revert "UBUNTU: SAUCE: drm/nouveau: Disable nouveau driver by default"
+
+  * shiftfs: use after free when checking mount options (LP: #1824735)
+    - SAUCE: shiftfs: prevent use-after-free when verifying mount options
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 15 Apr 2019 09:11:23 -0500
+
+linux (5.0.0-12.13) disco; urgency=medium
+
+  * linux: 5.0.0-12.13 -proposed tracker (LP: #1824726)
+
+  * Linux 5.0 black screen on boot, display flickers (i915 regression with
+    certain laptop panels) (LP: #1824216)
+    - drm/i915/dp: revert back to max link rate and lane count on eDP
+
+  * kernel BUG at fs/attr.c:287 when using shiftfs (LP: #1824717)
+    - SAUCE: shiftfs: fix passing of attrs to underaly for setattr
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 14 Apr 2019 13:38:05 -0500
+
+linux (5.0.0-11.12) disco; urgency=medium
+
+  * linux: 5.0.0-11.12 -proposed tracker (LP: #1824383)
+
+  * hns3: PPU_PF_ABNORMAL_INT_ST over_8bd_no_fe found [error status=0x1]
+    (LP: #1824194)
+    - net: hns3: fix for not calculating tx bd num correctly
+
+  * disco: unable to use iptables/enable ufw under -virtual kernel
+    (LP: #1823862)
+    - [Packaging] add bpfilter to linux-modules
+
+  * Make shiftfs a module rather than built-in (LP: #1824354)
+    - [Config] CONFIG_SHIFT_FS=m
+
+  * shiftfs: chown sets untranslated ids in lower fs (LP: #1824350)
+    - SAUCE: shiftfs: use translated ids when chaning lower fs attrs
+
+  * [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
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 11 Apr 2019 10:17:19 -0500
+
+linux (5.0.0-10.11) disco; urgency=medium
+
+  * linux: 5.0.0-10.11 -proposed tracker (LP: #1823936)
+
+  * Apparmor enforcement failure in lxc selftests (LP: #1823379)
+    - SAUCE: apparmor: Restore Y/N in /sys for apparmor's "enabled"
+
+  * systemd cause kernel trace "BUG: unable to handle kernel paging request at
+    6db23a14" on Cosmic i386 (LP: #1813244)
+    - openvswitch: fix flow actions reallocation
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 09 Apr 2019 08:30:38 -0500
+
+linux (5.0.0-9.10) disco; urgency=medium
+
+  * linux: 5.0.0-9.10 -proposed tracker (LP: #1823228)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] update helper scripts
+    - [Packaging] resync retpoline extraction
+
+  * Huawei Hi1822 NIC has poor performance (LP: #1820187)
+    - net-next/hinic: replace disable_irq_nosync/enable_irq
+
+  * Add uid shifting overlay filesystem (shiftfs) (LP: #1823186)
+    - shiftfs: uid/gid shifting bind mount
+    - shiftfs: rework and extend
+    - shiftfs: support some btrfs ioctls
+    - [Config] enable shiftfs
+
+  * Cannot boot or install - have to use nomodeset (LP: #1821820)
+    - Revert "drm/i915/fbdev: Actually configure untiled displays"
+
+  * Disco update: v5.0.6 upstream stable release (LP: #1823060)
+    - netfilter: nf_tables: fix set double-free in abort path
+    - dccp: do not use ipv6 header for ipv4 flow
+    - genetlink: Fix a memory leak on error path
+    - gtp: change NET_UDP_TUNNEL dependency to select
+    - ipv6: make ip6_create_rt_rcu return ip6_null_entry instead of NULL
+    - mac8390: Fix mmio access size probe
+    - mISDN: hfcpci: Test both vendor & device ID for Digium HFC4S
+    - net: aquantia: fix rx checksum offload for UDP/TCP over IPv6
+    - net: datagram: fix unbounded loop in __skb_try_recv_datagram()
+    - net/packet: Set __GFP_NOWARN upon allocation in alloc_pg_vec
+    - net: phy: meson-gxl: fix interrupt support
+    - net: rose: fix a possible stack overflow
+    - net: stmmac: fix memory corruption with large MTUs
+    - net-sysfs: call dev_hold if kobject_init_and_add success
+    - net: usb: aqc111: Extend HWID table by QNAP device
+    - packets: Always register packet sk in the same order
+    - rhashtable: Still do rehash when we get EEXIST
+    - sctp: get sctphdr by offset in sctp_compute_cksum
+    - sctp: use memdup_user instead of vmemdup_user
+    - tcp: do not use ipv6 header for ipv4 flow
+    - tipc: allow service ranges to be connect()'ed on RDM/DGRAM
+    - tipc: change to check tipc_own_id to return in tipc_net_stop
+    - tipc: fix cancellation of topology subscriptions
+    - tun: properly test for IFF_UP
+    - vrf: prevent adding upper devices
+    - vxlan: Don't call gro_cells_destroy() before device is unregistered
+    - thunderx: enable page recycling for non-XDP case
+    - thunderx: eliminate extra calls to put_page() for pages held for recycling
+    - net: dsa: mv88e6xxx: fix few issues in mv88e6390x_port_set_cmode
+    - net: mii: Fix PAUSE cap advertisement from linkmode_adv_to_lcl_adv_t()
+      helper
+    - net: phy: don't clear BMCR in genphy_soft_reset
+    - r8169: fix cable re-plugging issue
+    - ila: Fix rhashtable walker list corruption
+    - tun: add a missing rcu_read_unlock() in error path
+    - powerpc/fsl: Fix the flush of branch predictor.
+    - Btrfs: fix incorrect file size after shrinking truncate and fsync
+    - btrfs: remove WARN_ON in log_dir_items
+    - btrfs: don't report readahead errors and don't update statistics
+    - btrfs: Fix bound checking in qgroup_trace_new_subtree_blocks
+    - btrfs: Avoid possible qgroup_rsv_size overflow in
+      btrfs_calculate_inode_block_rsv_size
+    - Btrfs: fix assertion failure on fsync with NO_HOLES enabled
+    - locks: wake any locks blocked on request before deadlock check
+    - tracing: initialize variable in create_dyn_event()
+    - ARM: imx6q: cpuidle: fix bug that CPU might not wake up at expected time
+    - powerpc: bpf: Fix generation of load/store DW instructions
+    - vfio: ccw: only free cp on final interrupt
+    - NFS: Fix nfs4_lock_state refcounting in nfs4_alloc_{lock,unlock}data()
+    - NFS: fix mount/umount race in nlmclnt.
+    - NFSv4.1 don't free interrupted slot on open
+    - net: dsa: qca8k: remove leftover phy accessors
+    - ALSA: rawmidi: Fix potential Spectre v1 vulnerability
+    - ALSA: seq: oss: Fix Spectre v1 vulnerability
+    - ALSA: pcm: Fix possible OOB access in PCM oss plugins
+    - ALSA: pcm: Don't suspend stream in unrecoverable PCM state
+    - ALSA: hda/realtek - Fixed Headset Mic JD not stable
+    - ALSA: hda/realtek: merge alc_fixup_headset_jack to alc295_fixup_chromebook
+    - ALSA: hda/realtek - Add support headset mode for DELL WYSE AIO
+    - ALSA: hda/realtek - Add support headset mode for New DELL WYSE NB
+    - ALSA: hda/realtek: Enable headset MIC of Acer AIO with ALC286
+    - ALSA: hda/realtek: Enable headset MIC of Acer Aspire Z24-890 with ALC286
+    - ALSA: hda/realtek - Add support for Acer Aspire E5-523G/ES1-432 headset mic
+    - ALSA: hda/realtek: Enable ASUS X441MB and X705FD headset MIC with ALC256
+    - ALSA: hda/realtek: Enable headset mic of ASUS P5440FF with ALC256
+    - ALSA: hda/realtek: Enable headset MIC of ASUS X430UN and X512DK with ALC256
+    - ALSA: hda/realtek - Fix speakers on Acer Predator Helios 500 Ryzen laptops
+    - kbuild: modversions: Fix relative CRC byte order interpretation
+    - fs/open.c: allow opening only regular files during execve()
+    - ocfs2: fix inode bh swapping mixup in ocfs2_reflink_inodes_lock
+    - scsi: sd: Fix a race between closing an sd device and sd I/O
+    - scsi: sd: Quiesce warning if device does not report optimal I/O size
+    - 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
+    - drm/rockchip: vop: reset scale mode when win is disabled
+    - tty/serial: atmel: Add is_half_duplex helper
+    - tty/serial: atmel: RS485 HD w/DMA: enable RX after TX is stopped
+    - tty: mxs-auart: fix a potential NULL pointer dereference
+    - tty: atmel_serial: fix a potential NULL pointer dereference
+    - tty: serial: qcom_geni_serial: Initialize baud in qcom_geni_console_setup
+    - staging: comedi: ni_mio_common: Fix divide-by-zero for DIO cmdtest
+    - staging: olpc_dcon_xo_1: add missing 'const' qualifier
+    - staging: speakup_soft: Fix alternate speech with other synths
+    - staging: vt6655: Remove vif check from vnt_interrupt
+    - staging: vt6655: Fix interrupt race condition on device start up.
+    - staging: erofs: fix to handle error path of erofs_vmap()
+    - staging: erofs: fix error handling when failed to read compresssed data
+    - staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()
+    - serial: max310x: Fix to avoid potential NULL pointer dereference
+    - serial: mvebu-uart: Fix to avoid a 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 support for Quectel EM12
+    - USB: serial: option: add Olicard 600
+    - ACPI / CPPC: Fix guaranteed performance handling
+    - Disable kgdboc failed by echo space to /sys/module/kgdboc/parameters/kgdboc
+    - fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links
+    - drivers/block/zram/zram_drv.c: fix idle/writeback string compare
+    - blk-mq: fix sbitmap ws_active for shared tags
+    - cpufreq: intel_pstate: Also use CPPC nominal_perf for base_frequency
+    - cpufreq: scpi: Fix use after free
+    - drm/vgem: fix use-after-free when drm_gem_handle_create() fails
+    - drm/vkms: fix use-after-free when drm_gem_handle_create() fails
+    - drm/i915: Mark AML 0x87CA as ULX
+    - drm/i915/gvt: Fix MI_FLUSH_DW parsing with correct index check
+    - drm/i915/icl: Fix the TRANS_DDI_FUNC_CTL2 bitfield macro
+    - gpio: exar: add a check for the return value of ida_simple_get fails
+    - gpio: adnp: Fix testing wrong value in adnp_gpio_direction_input
+    - phy: sun4i-usb: Support set_mode to USB_HOST for non-OTG PHYs
+    - usb: mtu3: fix EXTCON dependency
+    - USB: gadget: f_hid: fix deadlock in f_hidg_write()
+    - usb: common: Consider only available nodes for dr_mode
+    - mm/memory.c: fix modifying of page protection by insert_pfn()
+    - usb: host: xhci-rcar: Add XHCI_TRUST_TX_LENGTH quirk
+    - xhci: Fix port resume done detection for SS ports with LPM enabled
+    - usb: xhci: dbc: Don't free all memory with spinlock held
+    - xhci: Don't let USB3 ports stuck in polling state prevent suspend
+    - usb: cdc-acm: fix race during wakeup blocking TX traffic
+    - usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
+    - usb: typec: Fix unchecked return value
+    - mm/hotplug: fix offline undo_isolate_page_range()
+    - mm: add support for kmem caches in DMA32 zone
+    - iommu/io-pgtable-arm-v7s: request DMA32 memory, and improve debugging
+    - mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified
+    - mm/debug.c: fix __dump_page when mapping->host is not set
+    - mm/memory_hotplug.c: fix notification in offline error path
+    - mm/page_isolation.c: fix a wrong flag in set_migratetype_isolate()
+    - mm/migrate.c: add missing flush_dcache_page for non-mapped page migrate
+    - perf pmu: Fix parser error for uncore event alias
+    - perf intel-pt: Fix TSC slip
+    - objtool: Query pkg-config for libelf location
+    - powerpc/pseries/energy: Use OF accessor functions to read ibm,drc-indexes
+    - powerpc/64: Fix memcmp reading past the end of src/dest
+    - powerpc/pseries/mce: Fix misleading print for TLB mutlihit
+    - watchdog: Respect watchdog cpumask on CPU hotplug
+    - cpu/hotplug: Prevent crash when CPU bringup fails on CONFIG_HOTPLUG_CPU=n
+    - x86/smp: Enforce CONFIG_HOTPLUG_CPU when SMP=y
+    - KVM: Reject device ioctls from processes other than the VM's creator
+    - KVM: x86: Emulate MSR_IA32_ARCH_CAPABILITIES on AMD hosts
+    - KVM: x86: update %rip after emulating IO
+    - bpf: do not restore dst_reg when cur_state is freed
+    - mt76x02u: use usb_bulk_msg to upload firmware
+    - Linux 5.0.6
+
+  * RDMA/hns updates for disco (LP: #1822897)
+    - RDMA/hns: Fix the bug with updating rq head pointer when flush cqe
+    - RDMA/hns: Bugfix for the scene without receiver queue
+    - RDMA/hns: Add constraint on the setting of local ACK timeout
+    - RDMA/hns: Modify the pbl ba page size for hip08
+    - RDMA/hns: RDMA/hns: Assign rq head pointer when enable rq record db
+    - RDMA/hns: Add the process of AEQ overflow for hip08
+    - RDMA/hns: Add SCC context allocation support for hip08
+    - RDMA/hns: Add SCC context clr support for hip08
+    - RDMA/hns: Add timer allocation support for hip08
+    - RDMA/hns: Remove set but not used variable 'rst'
+    - RDMA/hns: Make some function static
+    - RDMA/hns: Fix the Oops during rmmod or insmod ko when reset occurs
+    - RDMA/hns: Fix the chip hanging caused by sending mailbox&CMQ during reset
+    - RDMA/hns: Fix the chip hanging caused by sending doorbell during reset
+    - RDMA/hns: Limit minimum ROCE CQ depth to 64
+    - RDMA/hns: Fix the state of rereg mr
+    - RDMA/hns: Set allocated memory to zero for wrid
+    - RDMA/hns: Delete useful prints for aeq subtype event
+    - RDMA/hns: Configure capacity of hns device
+    - RDMA/hns: Modify qp&cq&pd specification according to UM
+    - RDMA/hns: Bugfix for set hem of SCC
+    - RDMA/hns: Use GFP_ATOMIC in hns_roce_v2_modify_qp
+
+  * autopkgtests run too often, too much and don't skip enough (LP: #1823056)
+    - Set +x on rebuild testcase.
+    - Skip rebuild test, for regression-suite deps.
+    - Make ubuntu-regression-suite skippable on unbootable kernels.
+    - make rebuild use skippable error codes when skipping.
+    - Only run regression-suite, if requested to.
+
+  * touchpad not working on lenovo yoga 530 (LP: #1787775)
+    - Revert "UBUNTU: SAUCE: i2c:amd Depends on ACPI"
+    - Revert "UBUNTU: SAUCE: i2c:amd move out pointer in union i2c_event_base"
+    - i2c: add extra check to safe DMA buffer helper
+    - i2c: Add drivers for the AMD PCIe MP2 I2C controller
+    - [Config] Update config for AMD MP2 I2C driver
+
+  * Detect SMP PHY control command errors (LP: #1822680)
+    - scsi: libsas: Check SMP PHY control function result
+
+  * disable a.out support (LP: #1818552)
+    - [Config] Disable a.out support
+    - [Config] remove binfmt_aout from abi for i386 lowlatency
+
+  * bionic: fork out linux-snapdragon into its own topic kernel (LP: #1820868)
+    - [Packaging] remove snapdragon flavour support
+    - Revert "UBUNTU: SAUCE: (snapdragon) drm/msm/adv7511: wrap hacks under
+      CONFIG_ADV7511_SNAPDRAGON_HACKS #ifdefs"
+    - Revert "UBUNTU: SAUCE: (snapdragon) media: ov5645: skip address change if dt
+      addr == default addr"
+    - Revert "UBUNTU: SAUCE: (snapdragon) DT: leds: Add Qualcomm Light Pulse
+      Generator binding"
+    - Revert "UBUNTU: SAUCE: (snapdragon) MAINTAINERS: Add Qualcomm Camera Control
+      Interface driver"
+    - Revert "UBUNTU: SAUCE: (snapdragon) dt-bindings: media: Binding document for
+      Qualcomm Camera Control Interface driver"
+    - Revert "UBUNTU: SAUCE: (snapdragon) leds: Add driver for Qualcomm LPG"
+    - Revert "UBUNTU: SAUCE: (snapdragon) HACK: drm/msm/adv7511: Don't rely on
+      interrupts for EDID parsing"
+    - Revert "UBUNTU: SAUCE: (snapdragon) drm/bridge/adv7511: Delay clearing of
+      HPD interrupt status"
+    - Revert "UBUNTU: SAUCE: (snapdragon) media: ov5645: Fix I2C address"
+    - Revert "UBUNTU: SAUCE: (snapdragon) i2c-qcom-cci: Fix I2C address bug"
+    - Revert "UBUNTU: SAUCE: (snapdragon) i2c-qcom-cci: Fix run queue completion
+      timeout"
+    - Revert "UBUNTU: SAUCE: (snapdragon) camss: Do not register if no cameras are
+      present"
+    - Revert "UBUNTU: SAUCE: (snapdragon) i2c: Add Qualcomm Camera Control
+      Interface driver"
+    - Revert "UBUNTU: SAUCE: (snapdragon) ov5645: I2C address change"
+    - Revert "UBUNTU: SAUCE: (snapdragon) regulator: smd: Allow
+      REGULATOR_QCOM_SMD_RPM=m"
+    - Revert "UBUNTU: SAUCE: (snapdragon) cpufreq: Add apq8016 to cpufreq-dt-
+      platdev blacklist"
+    - Revert "UBUNTU: SAUCE: (snapdragon) PM / OPP: Add a helper to get an opp
+      regulator for device"
+    - Revert "UBUNTU: SAUCE: (snapdragon) PM / OPP: HACK: Allow to set regulator
+      without opp_list"
+    - Revert "UBUNTU: SAUCE: (snapdragon) PM / OPP: Drop RCU usage in
+      dev_pm_opp_adjust_voltage()"
+    - Revert "UBUNTU: SAUCE: (snapdragon) PM / OPP: Support adjusting OPP voltages
+      at runtime"
+    - Revert "UBUNTU: SAUCE: (snapdragon) regulator: smd: Add floor and corner
+      operations"
+    - Revert "UBUNTU: SAUCE: (snapdragon) power: avs: cpr: Register with cpufreq-
+      dt"
+    - Revert "UBUNTU: SAUCE: (snapdragon) power: avs: cpr: fix with new
+      reg_sequence structures"
+    - Revert "UBUNTU: SAUCE: (snapdragon) power: avs: cpr: Use raw mem access for
+      qfprom"
+    - Revert "UBUNTU: SAUCE: (snapdragon) power: avs: Add support for CPR (Core
+      Power Reduction)"
+    - Revert "UBUNTU: SAUCE: (snapdragon) HACK: drm/msm/iommu: Remove runtime_put
+      calls in map/unmap"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: enable LEDS_QCOM_LPG"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: distro.config: enable 'BBR' TCP
+      congestion algorithm"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: distro.config: enable 'fq' and
+      'fq_codel' qdiscs"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: distro.config: enable
+      'schedutil' CPUfreq governor"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: configs: set USB_CONFIG_F_FS in
+      distro.config"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: enable
+      CONFIG_USB_CONFIGFS_F_FS by default"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: configs: add freq stat to sysfs"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: configs: Enable camera drivers"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: disable ANALOG_TV and
+      DIGITAL_TV"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: configs: add more USB net
+      drivers"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: configs: enable BT_QCOMSMD"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: enable
+      CFG80211_DEFAULT_PS by default"
+    - Revert "UBUNTU: SAUCE: (snapdragon) Force the SMD regulator driver to be
+      compiled-in"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: configs: enable dm_mod and
+      dm_crypt"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: Enable a53/apcs and
+      avs"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: configs: enable QCOM Venus"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: distro.config: enable debug
+      friendly USB network adpater"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: configs: enable WCN36xx"
+    - Revert "UBUNTU: SAUCE: (snapdragon) kernel: configs; add distro.config"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: enable QCOM audio
+      drivers for APQ8016 and DB410c"
+    - Revert "UBUNTU: SAUCE: (snapdragon) arm64: defconfig: enable REMOTEPROC"
+    - [Config] fix abi for remove i2c-qcom-cci module
+    - [Config] update annotations
+    - [Config] update configs following snapdragon removal
+
+  * Disco update: v5.0.5 upstream stable release (LP: #1822671)
+    - Revert "ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec"
+    - ALSA: hda - add Lenovo IdeaCentre B550 to the power_save_blacklist
+    - ALSA: firewire-motu: use 'version' field of unit directory to identify model
+    - mmc: pxamci: fix enum type confusion
+    - mmc: alcor: fix DMA reads
+    - mmc: mxcmmc: "Revert mmc: mxcmmc: handle highmem pages"
+    - mmc: renesas_sdhi: limit block count to 16 bit for old revisions
+    - drm/amdgpu: fix invalid use of change_bit
+    - drm/vmwgfx: Don't double-free the mode stored in par->set_mode
+    - drm/vmwgfx: Return 0 when gmrid::get_node runs out of ID's
+    - iommu/amd: fix sg->dma_address for sg->offset bigger than PAGE_SIZE
+    - iommu/iova: Fix tracking of recently failed iova address
+    - libceph: wait for latest osdmap in ceph_monc_blacklist_add()
+    - udf: Fix crash on IO error during truncate
+    - mips: loongson64: lemote-2f: Add IRQF_NO_SUSPEND to "cascade" irqaction.
+    - MIPS: Ensure ELF appended dtb is relocated
+    - MIPS: Fix kernel crash for R6 in jump label branch function
+    - powerpc/vdso64: Fix CLOCK_MONOTONIC inconsistencies across Y2038
+    - powerpc/security: Fix spectre_v2 reporting
+    - net/mlx5: Fix DCT creation bad flow
+    - scsi: core: Avoid that a kernel warning appears during system resume
+    - scsi: qla2xxx: Fix FC-AL connection target discovery
+    - scsi: ibmvscsi: Protect ibmvscsi_head from concurrent modificaiton
+    - scsi: ibmvscsi: Fix empty event pool access during host removal
+    - futex: Ensure that futex address is aligned in handle_futex_death()
+    - perf probe: Fix getting the kernel map
+    - objtool: Move objtool_file struct off the stack
+    - irqchip/gic-v3-its: Fix comparison logic in lpi_range_cmp
+    - clocksource/drivers/riscv: Fix clocksource mask
+    - ALSA: ac97: Fix of-node refcount unbalance
+    - 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()
+    - media: v4l2-ctrls.c/uvc: zero v4l2_event
+    - Bluetooth: hci_uart: Check if socket buffer is ERR_PTR in h4_recv_buf()
+    - Bluetooth: Fix decrementing reference count twice in releasing socket
+    - Bluetooth: hci_ldisc: Initialize hci_dev before open()
+    - Bluetooth: hci_ldisc: Postpone HCI_UART_PROTO_READY bit set in
+      hci_uart_set_proto()
+    - drm/vkms: Fix flush_work() without INIT_WORK().
+    - RDMA/cma: Rollback source IP address if failing to acquire device
+    - f2fs: fix to avoid deadlock of atomic file operations
+    - aio: simplify - and fix - fget/fput for io_submit()
+    - netfilter: ebtables: remove BUGPRINT messages
+    - loop: access lo_backing_file only when the loop device is Lo_bound
+    - x86/unwind: Handle NULL pointer calls better in frame unwinder
+    - x86/unwind: Add hardcoded ORC entry for NULL
+    - 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
+    - Linux 5.0.5
+
+  * hisi_sas updates for disco (LP: #1822385)
+    - scsi: hisi_sas: send primitive NOTIFY to SSP situation only
+    - scsi: hisi_sas: shutdown axi bus to avoid exception CQ returned
+    - scsi: hisi_sas: remove the check of sas_dev status in
+      hisi_sas_I_T_nexus_reset()
+    - scsi: hisi_sas: Remove unused parameter of function hisi_sas_alloc()
+    - scsi: hisi_sas: Reject setting programmed minimum linkrate > 1.5G
+    - scsi: hisi_sas: Fix losing directly attached disk when hot-plug
+    - scsi: hisi_sas: Correct memory allocation size for DQ debugfs
+    - scsi: hisi_sas: Some misc tidy-up
+    - scsi: hisi_sas: Fix to only call scsi_get_prot_op() for non-NULL scsi_cmnd
+    - scsi: hisi_sas: Add missing seq_printf() call in hisi_sas_show_row_32()
+    - scsi: hisi_sas: Add support for DIX feature for v3 hw
+    - scsi: hisi_sas: Add manual trigger for debugfs dump
+    - scsi: hisi_sas: change queue depth from 512 to 4096
+    - scsi: hisi_sas: Issue internal abort on all relevant queues
+    - scsi: hisi_sas: Use pci_irq_get_affinity() for v3 hw as experimental
+    - scsi: hisi_sas: Do some more tidy-up
+    - scsi: hisi_sas: Change return variable type in phy_up_v3_hw()
+    - scsi: hisi_sas: Fix a timeout race of driver internal and SMP IO
+    - scsi: hisi_sas: print PHY RX errors count for later revision of v3 hw
+    - scsi: hisi_sas: Set PHY linkrate when disconnected
+    - scsi: hisi_sas: Send HARD RESET to clear the previous affiliation of STP
+      target port
+    - scsi: hisi_sas: Change SERDES_CFG init value to increase reliability of
+      HiLink
+    - scsi: hisi_sas: Add softreset in hisi_sas_I_T_nexus_reset()
+
+  * [Patch][Raven 2] kernel 5.0.0 cannot boot because of psp response
+    (LP: #1822267)
+    - drm/amdgpu/psp: Fix can't detect psp INVOKE command failed
+    - drm/amdgpu/psp: ignore psp response status
+
+  * 3b080b2564287be91605bfd1d5ee985696e61d3c in ubuntu_btrfs_kernel_fixes
+    triggers system hang on i386 (LP: #1812845)
+    - btrfs: raid56: properly unmap parity page in finish_parity_scrub()
+
+  * enable CONFIG_DRM_BOCHS (LP: #1795857)
+    - [Config] Reenable DRM_BOCHS as module
+
+  * [Dell Precision 7530/5530 with Nvidia Quadro P1000] Live USB freezes or
+    cannot complete install when nouveau driver is loaded (crashing in GP100
+    code) (LP: #1822026)
+    - SAUCE: drm/nouveau: Disable nouveau driver by default
+
+  * Need to add Intel CML related pci-id's (LP: #1821863)
+    - drm/i915/cml: Add CML PCI IDS
+    - drm/i915/cml: Introduce Comet Lake PCH
+
+  * ARM: Add support for the SDEI interface (LP: #1822005)
+    - ACPI / APEI: Don't wait to serialise with oops messages when panic()ing
+    - ACPI / APEI: Remove silent flag from ghes_read_estatus()
+    - ACPI / APEI: Switch estatus pool to use vmalloc memory
+    - ACPI / APEI: Make hest.c manage the estatus memory pool
+    - ACPI / APEI: Make estatus pool allocation a static size
+    - ACPI / APEI: Don't store CPER records physical address in struct ghes
+    - ACPI / APEI: Remove spurious GHES_TO_CLEAR check
+    - ACPI / APEI: Don't update struct ghes' flags in read/clear estatus
+    - ACPI / APEI: Generalise the estatus queue's notify code
+    - ACPI / APEI: Don't allow ghes_ack_error() to mask earlier errors
+    - ACPI / APEI: Move NOTIFY_SEA between the estatus-queue and NOTIFY_NMI
+    - ACPI / APEI: Switch NOTIFY_SEA to use the estatus queue
+    - KVM: arm/arm64: Add kvm_ras.h to collect kvm specific RAS plumbing
+    - arm64: KVM/mm: Move SEA handling behind a single 'claim' interface
+    - ACPI / APEI: Move locking to the notification helper
+    - ACPI / APEI: Let the notification helper specify the fixmap slot
+    - ACPI / APEI: Pass ghes and estatus separately to avoid a later copy
+    - ACPI / APEI: Make GHES estatus header validation more user friendly
+    - ACPI / APEI: Split ghes_read_estatus() to allow a peek at the CPER length
+    - ACPI / APEI: Only use queued estatus entry during in_nmi_queue_one_entry()
+    - ACPI / APEI: Use separate fixmap pages for arm64 NMI-like notifications
+    - firmware: arm_sdei: Add ACPI GHES registration helper
+    - ACPI / APEI: Add support for the SDEI GHES Notification type
+
+  * CVE-2019-9857
+    - inotify: Fix fsnotify_mark refcount leak in inotify_update_existing_watch()
+
+  * scsi: libsas: Support SATA PHY connection rate unmatch fixing during
+    discovery (LP: #1821408)
+    - scsi: libsas: Support SATA PHY connection rate unmatch fixing during
+      discovery
+
+  * Qualcomm Atheros QCA9377 wireless does not work (LP: #1818204)
+    - platform/x86: ideapad-laptop: Add Ideapad 530S-14ARR to no_hw_rfkill list
+
+  * Lenovo ideapad 330-15ICH Wifi rfkill hard blocked (LP: #1811815)
+    - platform/x86: ideapad: Add ideapad 330-15ICH to no_hw_rfkill
+
+  * hid-sensor-hub spamming dmesg in 4.20 (LP: #1818547)
+    - HID: Increase maximum report size allowed by hid_field_extract()
+
+  * [disco] [5.0.0-7.8] can't mount guest cifs share (LP: #1821053)
+    - cifs: allow guest mounts to work for smb3.11
+    - SMB3: Fix SMB3.1.1 guest mounts to Samba
+
+  * Add HiSilicon SoC quirk for cpufreq (LP: #1821620)
+    - ACPI / CPPC: Add a helper to get desired performance
+    - cpufreq / cppc: Work around for Hisilicon CPPC cpufreq
+
+  * Disco update: v5.0.4 upstream stable release (LP: #1821607)
+    - 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
+    - ASoC: codecs: pcm186x: fix wrong usage of DECLARE_TLV_DB_SCALE()
+    - ASoC: codecs: pcm186x: Fix energysense SLEEP bit
+    - iio: adc: exynos-adc: Fix NULL pointer exception on unbind
+    - iio: adc: exynos-adc: Use proper number of channels for Exynos4x12
+    - mei: hbm: clean the feature flags on link reset
+    - mei: bus: move hw module get/put to probe/release
+    - stm class: Prevent division by zero
+    - stm class: Fix an endless loop in channel allocation
+    - crypto: caam - fix hash context DMA unmap size
+    - crypto: ccree - fix missing break in switch statement
+    - crypto: caam - fixed handling of sg list
+    - crypto: caam - fix DMA mapping of stack memory
+    - crypto: ccree - fix free of unallocated mlli buffer
+    - crypto: ccree - unmap buffer before copying IV
+    - crypto: ccree - don't copy zero size ciphertext
+    - crypto: cfb - add missing 'chunksize' property
+    - crypto: cfb - remove bogus memcpy() with src == dest
+    - crypto: ofb - fix handling partial blocks and make thread-safe
+    - crypto: ahash - fix another early termination in hash walk
+    - crypto: rockchip - fix scatterlist nents error
+    - crypto: rockchip - update new iv to device in multiple operations
+    - dax: Flush partial PMDs correctly
+    - nfit: Fix nfit_intel_shutdown_status() command submission
+    - nfit: acpi_nfit_ctl(): Check out_obj->type in the right place
+    - acpi/nfit: Fix bus command validation
+    - nfit/ars: Attempt a short-ARS whenever the ARS state is idle at boot
+    - nfit/ars: Attempt short-ARS even in the no_init_ars case
+    - libnvdimm/label: Clear 'updating' flag after label-set update
+    - libnvdimm, pfn: Fix over-trim in trim_pfn_device()
+    - libnvdimm/pmem: Honor force_raw for legacy pmem regions
+    - libnvdimm: Fix altmap reservation size calculation
+    - fix cgroup_do_mount() handling of failure exits
+    - crypto: aead - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
+    - crypto: aegis - fix handling chunked inputs
+    - crypto: arm/crct10dif - revert to C code for short inputs
+    - crypto: arm64/aes-neonbs - fix returning final keystream block
+    - crypto: arm64/crct10dif - revert to C code for short inputs
+    - crypto: hash - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
+    - crypto: morus - fix handling chunked inputs
+    - crypto: pcbc - remove bogus memcpy()s with src == dest
+    - crypto: skcipher - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
+    - crypto: testmgr - skip crc32c context test for ahash algorithms
+    - crypto: x86/aegis - fix handling chunked inputs and MAY_SLEEP
+    - crypto: x86/aesni-gcm - fix crash on empty plaintext
+    - crypto: x86/morus - fix handling chunked inputs and MAY_SLEEP
+    - crypto: arm64/aes-ccm - fix logical bug in AAD MAC handling
+    - crypto: arm64/aes-ccm - fix bugs in non-NEON fallback routine
+    - CIFS: Fix leaking locked VFS cache pages in writeback retry
+    - CIFS: Do not reset lease state to NONE on lease break
+    - CIFS: Do not skip SMB2 message IDs on send failures
+    - CIFS: Fix read after write for files with read caching
+    - smb3: make default i/o size for smb3 mounts larger
+    - tracing: Use strncpy instead of memcpy for string keys in hist triggers
+    - tracing: Do not free iter->trace in fail path of tracing_open_pipe()
+    - tracing/perf: Use strndup_user() instead of buggy open-coded version
+    - vmw_balloon: release lock on error in vmballoon_reset()
+    - xen: fix dom0 boot on huge systems
+    - ACPI / device_sysfs: Avoid OF modalias creation for removed device
+    - mmc: sdhci-esdhc-imx: fix HS400 timing issue
+    - mmc: renesas_sdhi: Fix card initialization failure in high speed mode
+    - mmc:fix a bug when max_discard is 0
+    - spi: ti-qspi: Fix mmap read when more than one CS in use
+    - spi: pxa2xx: Setup maximum supported DMA transfer length
+    - spi: omap2-mcspi: Fix DMA and FIFO event trigger size mismatch
+    - spi: spi-gpio: fix SPI_CS_HIGH capability
+    - regulator: s2mps11: Fix steps for buck7, buck8 and LDO35
+    - regulator: max77620: Initialize values for DT properties
+    - regulator: s2mpa01: Fix step values for some LDOs
+    - mt76: fix corrupted software generated tx CCMP PN
+    - clocksource/drivers/exynos_mct: Move one-shot check from tick clear to ISR
+    - clocksource/drivers/exynos_mct: Clear timer interrupt when shutdown
+    - clocksource/drivers/arch_timer: Workaround for Allwinner A64 timer
+      instability
+    - s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem
+    - s390/setup: fix early warning messages
+    - s390/virtio: handle find on invalid queue gracefully
+    - scsi: virtio_scsi: don't send sc payload with tmfs
+    - scsi: aacraid: Fix performance issue on logical drives
+    - scsi: sd: Optimal I/O size should be a multiple of physical block size
+    - scsi: target/iscsi: Avoid iscsit_release_commands_from_conn() deadlock
+    - scsi: qla2xxx: Fix LUN discovery if loop id is not assigned yet by firmware
+    - scsi: qla2xxx: Avoid PCI IRQ affinity mapping when multiqueue is not
+      supported
+    - scsi: qla2xxx: Use complete switch scan for RSCN events
+    - fs/devpts: always delete dcache dentry-s in dput()
+    - splice: don't merge into linked buffers
+    - ovl: During copy up, first copy up data and then xattrs
+    - ovl: Do not lose security.capability xattr over metadata file copy-up
+    - m68k: Add -ffreestanding to CFLAGS
+    - Btrfs: setup a nofs context for memory allocation at btrfs_create_tree()
+    - Btrfs: setup a nofs context for memory allocation at __btrfs_set_acl
+    - btrfs: scrub: fix circular locking dependency warning
+    - btrfs: drop the lock on error in btrfs_dev_replace_cancel
+    - btrfs: ensure that a DUP or RAID1 block group has exactly two stripes
+    - btrfs: init csum_list before possible free
+    - Btrfs: fix corruption reading shared and compressed extents after hole
+      punching
+    - Btrfs: fix deadlock between clone/dedupe and rename
+    - soc: qcom: rpmh: Avoid accessing freed memory from batch API
+    - libertas_tf: don't set URB_ZERO_PACKET on IN USB transfer
+    - irqchip/gic-v3-its: Avoid parsing _indirect_ twice for Device table
+    - irqchip/brcmstb-l2: Use _irqsave locking variants in non-interrupt code
+    - x86/kprobes: Prohibit probing on optprobe template code
+    - cpufreq: kryo: Release OPP tables on module removal
+    - cpufreq: tegra124: add missing of_node_put()
+    - cpufreq: pxa2xx: remove incorrect __init annotation
+    - ext4: fix check of inode in swap_inode_boot_loader
+    - ext4: cleanup pagecache before swap i_data
+    - mm: hwpoison: fix thp split handing in soft_offline_in_use_page()
+    - mm/vmalloc: fix size check for remap_vmalloc_range_partial()
+    - mm/memory.c: do_fault: avoid usage of stale vm_area_struct
+    - kernel/sysctl.c: add missing range check in do_proc_dointvec_minmax_conv
+    - nvmem: core: don't check the return value of notifier chain call
+    - device property: Fix the length used in PROPERTY_ENTRY_STRING()
+    - 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
+    - i2c: tegra: update maximum transfer size
+    - media: i2c: ov5640: Fix post-reset delay
+    - gpio: pca953x: Fix dereference of irq data in shutdown
+    - ext4: update quota information while swapping boot loader inode
+    - ext4: add mask of ext4 flags to swap
+    - ext4: fix crash during online resizing
+    - dma: Introduce dma_max_mapping_size()
+    - swiotlb: Introduce swiotlb_max_mapping_size()
+    - swiotlb: Add is_swiotlb_active() function
+    - PCI/ASPM: Use LTR if already enabled by platform
+    - PCI/DPC: Fix print AER status in DPC event handling
+    - PCI: qcom: Don't deassert reset GPIO during probe
+    - PCI: dwc: skip MSI init if MSIs have been explicitly disabled
+    - PCI: pci-bridge-emul: Create per-bridge copy of register behavior
+    - PCI: pci-bridge-emul: Extend pci_bridge_emul_init() with flags
+    - IB/hfi1: Close race condition on user context disable and close
+    - IB/rdmavt: Fix loopback send with invalidate ordering
+    - IB/rdmavt: Fix concurrency panics in QP post_send and modify to error
+    - cxl: Wrap iterations over afu slices inside 'afu_list_lock'
+    - ext2: Fix underflow in ext2_max_size()
+    - clk: uniphier: Fix update register for CPU-gear
+    - clk: clk-twl6040: Fix imprecise external abort for pdmclk
+    - clk: samsung: exynos5: Fix possible NULL pointer exception on
+      platform_device_alloc() failure
+    - clk: samsung: exynos5: Fix kfree() of const memory on setting
+      driver_override
+    - clk: ingenic: Fix round_rate misbehaving with non-integer dividers
+    - clk: ingenic: Fix doc of ingenic_cgu_div_info
+    - usb: chipidea: tegra: Fix missed ci_hdrc_remove_device()
+    - usb: typec: tps6598x: handle block writes separately with plain-I2C adapters
+    - dmaengine: usb-dmac: Make DMAC system sleep callbacks explicit
+    - serial: uartps: Fix stuck ISR if RX disabled with non-empty FIFO
+    - serial: 8250_of: assume reg-shift of 2 for mrvl,mmp-uart
+    - 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
+    - selinux: add the missing walk_size + len check in selinux_sctp_bind_connect
+    - security/selinux: fix SECURITY_LSM_NATIVE_LABELS on reused superblock
+    - 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
+    - powerpc/kvm: Save and restore host AMR/IAMR/UAMOR
+    - powerpc/powernv: Don't reprogram SLW image on every KVM guest entry/exit
+    - powerpc/64s/hash: Fix assert_slb_presence() use of the slbfee. instruction
+    - powerpc: Fix 32-bit KVM-PR lockup and host crash with MacOS guest
+    - powerpc/ptrace: Simplify vr_get/set() to avoid GCC warning
+    - powerpc/hugetlb: Don't do runtime allocation of 16G pages in LPAR
+      configuration
+    - powerpc/smp: Fix NMI IPI timeout
+    - powerpc/smp: Fix NMI IPI xmon timeout
+    - powerpc/traps: fix recoverability of machine check handling on book3s/32
+    - powerpc/traps: Fix the message printed when stack overflows
+    - ARM: s3c24xx: Fix boolean expressions in osiris_dvs_notify
+    - arm64: Fix HCR.TGE status for NMI contexts
+    - arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals
+    - arm64: debug: Ensure debug handlers check triggering exception level
+    - arm64: KVM: Fix architecturally invalid reset value for FPEXC32_EL2
+    - Revert "KVM/MMU: Flush tlb directly in the kvm_zap_gfn_range()"
+    - ipmi_si: Fix crash when using hard-coded device
+    - ipmi_si: fix use-after-free of resource->name
+    - dm: fix to_sector() for 32bit
+    - dm integrity: limit the rate of error messages
+    - media: cx25840: mark pad sig_types to fix cx231xx init
+    - mfd: sm501: Fix potential NULL pointer dereference
+    - cpcap-charger: generate events for userspace
+    - cpuidle: governor: Add new governors to cpuidle_governors again
+    - NFS: Fix I/O request leakages
+    - NFS: Fix an I/O request leakage in nfs_do_recoalesce
+    - NFS: Don't recoalesce on error in nfs_pageio_complete_mirror()
+    - nfsd: fix performance-limiting session calculation
+    - nfsd: fix memory corruption caused by readdir
+    - nfsd: fix wrong check in write_v4_end_grace()
+    - NFSv4.1: Reinitialise sequence results before retransmitting a request
+    - svcrpc: fix UDP on servers with lots of threads
+    - PM / wakeup: Rework wakeup source timer cancellation
+    - PM / OPP: Update performance state when freq == old_freq
+    - bcache: treat stale && dirty keys as bad keys
+    - bcache: use (REQ_META|REQ_PRIO) to indicate bio for metadata
+    - stable-kernel-rules.rst: add link to networking patch queue
+    - vt: perform safe console erase in the right order
+    - x86/unwind/orc: Fix ORC unwind table alignment
+    - perf intel-pt: Fix CYC timestamp calculation after OVF
+    - perf tools: Fix split_kallsyms_for_kcore() for trampoline symbols
+    - perf auxtrace: Define auxtrace record alignment
+    - perf intel-pt: Fix overlap calculation for padding
+    - perf/x86/intel/uncore: Fix client IMC events return huge result
+    - perf intel-pt: Fix divide by zero when TSC is not available
+    - md: Fix failed allocation of md_register_thread
+    - x86/kvmclock: set offset for kvm unstable clock
+    - x86/ftrace: Fix warning and considate ftrace_jmp_replace() and
+      ftrace_call_replace()
+    - tpm/tpm_crb: Avoid unaligned reads in crb_recv()
+    - tpm: Unify the send callback behaviour
+    - rcu: Do RCU GP kthread self-wakeup from softirq and interrupt
+    - media: imx: prpencvf: Stop upstream before disabling IDMA channel
+    - media: lgdt330x: fix lock status reporting
+    - media: sun6i: Fix CSI regmap's max_register
+    - media: uvcvideo: Avoid NULL pointer dereference at the end of streaming
+    - media: vimc: Add vimc-streamer for stream control
+    - media: imx-csi: Input connections to CSI should be optional
+    - media: imx: csi: Disable CSI immediately after last EOF
+    - media: imx: csi: Stop upstream before disabling IDMA channel
+    - drm/fb-helper: generic: Fix drm_fbdev_client_restore()
+    - drm/radeon/evergreen_cs: fix missing break in switch statement
+    - drm/amd/powerplay: correct power reading on fiji
+    - drm/amd/display: don't call dm_pp_ function from an fpu block
+    - KVM: Call kvm_arch_memslots_updated() before updating memslots
+    - KVM: VMX: Compare only a single byte for VMCS' "launched" in vCPU-run
+    - KVM: VMX: Zero out *all* general purpose registers after VM-Exit
+    - KVM: x86/mmu: Detect MMIO generation wrap in any address space
+    - KVM: x86/mmu: Do not cache MMIO accesses while memslots are in flux
+    - KVM: nVMX: Sign extend displacements of VMX instr's mem operands
+    - KVM: nVMX: Apply addr size mask to effective address for VMX instructions
+    - KVM: nVMX: Ignore limit checks on VMX instructions using flat segments
+    - KVM: nVMX: Check a single byte for VMCS "launched" in nested early checks
+    - net: dsa: lantiq_gswip: fix use-after-free on failed probe
+    - net: dsa: lantiq_gswip: fix OF child-node lookups
+    - s390/setup: fix boot crash for machine without EDAT-1
+    - SUNRPC: Prevent thundering herd when the socket is not connected
+    - SUNRPC: Fix up RPC back channel transmission
+    - SUNRPC: Respect RPC call timeouts when retrying transmission
+    - Linux 5.0.4
+    - [Config] update configs for 5.0.4 stable update
+
+  * New Intel Wireless-AC 9260 [8086:2526] card not correctly probed in Ubuntu
+    system (LP: #1821271)
+    - iwlwifi: add new card for 9260 series
+
+  * [CONFIG] please enable highdpi font FONT_TER16x32 (LP: #1819881)
+    - [Config]: enable highdpi Terminus 16x32 font support
+
+  * [SRU][B/B-OEM/C/D] Fix AMD IOMMU NULL dereference (LP: #1820990)
+    - iommu/amd: Fix NULL dereference bug in match_hid_uid
+
+  * some codecs stop working after S3 (LP: #1820930)
+    - ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec
+    - ALSA: hda - Don't trigger jackpoll_work in azx_resume
+
+  * tcm_loop.ko: move from modules-extra into main modules package
+    (LP: #1817786)
+    - [Packaging] move tcm_loop.lo to main linux-modules package
+
+  * C++ demangling support missing from perf (LP: #1396654)
+    - [Packaging] fix a mistype
+
+  * r8169 doesn't get woken up by ethernet cable plugging, no PME generated
+    (LP: #1817676)
+    - PCI: pciehp: Disable Data Link Layer State Changed event on suspend
+
+  * Disco update: v5.0.3 upstream stable release (LP: #1821074)
+    - connector: fix unsafe usage of ->real_parent
+    - fou, fou6: avoid uninit-value in gue_err() and gue6_err()
+    - gro_cells: make sure device is up in gro_cells_receive()
+    - ipv4/route: fail early when inet dev is missing
+    - l2tp: fix infoleak in l2tp_ip6_recvmsg()
+    - lan743x: Fix RX Kernel Panic
+    - lan743x: Fix TX Stall Issue
+    - net: hsr: fix memory leak in hsr_dev_finalize()
+    - net/hsr: fix possible crash in add_timer()
+    - 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
+    - rxrpc: Fix client call queueing, waiting for channel
+    - sctp: remove sched init from sctp_stream_init
+    - tcp: do not report TCP_CM_INQ of 0 for closed connections
+    - tcp: Don't access TCP_SKB_CB before initializing it
+    - tcp: handle inet_csk_reqsk_queue_add() failures
+    - vxlan: Fix GRO cells race condition between receive and link delete
+    - vxlan: test dev->flags & IFF_UP before calling gro_cells_receive()
+    - net/mlx4_core: Fix reset flow when in command polling mode
+    - net/mlx4_core: Fix locking in SRIOV mode when switching between events and
+      polling
+    - net/mlx4_core: Fix qp mtt size calculation
+    - net: dsa: mv88e6xxx: Set correct interface mode for CPU/DSA ports
+    - vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
+    - net: sched: flower: insert new filter to idr after setting its mask
+    - f2fs: wait on atomic writes to count F2FS_CP_WB_DATA
+    - perf/x86: Fixup typo in stub functions
+    - ALSA: bebob: use more identical mod_alias for Saffire Pro 10 I/O against
+      Liquid Saffire 56
+    - ALSA: firewire-motu: fix construction of PCM frame for capture direction
+    - ALSA: hda: Extend i915 component bind timeout
+    - ALSA: hda - add more quirks for HP Z2 G4 and HP Z240
+    - ALSA: hda/realtek: Enable audio jacks of ASUS UX362FA with ALC294
+    - ALSA: hda/realtek - Reduce click noise on Dell Precision 5820 headphone
+    - ALSA: hda/realtek: Enable headset MIC of Acer TravelMate X514-51T with
+      ALC255
+    - perf/x86/intel: Fix memory corruption
+    - perf/x86/intel: Make dev_attr_allow_tsx_force_abort static
+    - It's wrong to add len to sector_nr in raid10 reshape twice
+    - drm: Block fb changes for async plane updates
+    - Linux 5.0.3
+
+  * Disco update: v5.0.2 upstream stable release (LP: #1820318)
+    - media: uvcvideo: Fix 'type' check leading to overflow
+    - 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
+    - scsi: aacraid: Fix missing break in switch statement
+    - x86/PCI: Fixup RTIT_BAR of Intel Denverton Trace Hub
+    - arm64: dts: zcu100-revC: Give wifi some time after power-on
+    - arm64: dts: hikey: Give wifi some time after power-on
+    - arm64: dts: hikey: Revert "Enable HS200 mode on eMMC"
+    - ARM: dts: exynos: Fix pinctrl definition for eMMC RTSN line on Odroid X2/U3
+    - ARM: dts: exynos: Add minimal clkout parameters to Exynos3250 PMU
+    - ARM: dts: exynos: Fix max voltage for buck8 regulator on Odroid XU3/XU4
+    - drm: disable uncached DMA optimization for ARM and arm64
+    - media: Revert "media: rc: some events are dropped by userspace"
+    - Revert "PCI/PME: Implement runtime PM callbacks"
+    - bpf: Stop the psock parser before canceling its work
+    - gfs2: Fix missed wakeups in find_insert_glock
+    - staging: erofs: keep corrupted fs from crashing kernel in erofs_namei()
+    - staging: erofs: compressed_pages should not be accessed again after freed
+    - scripts/gdb: replace flags (MS_xyz -> SB_xyz)
+    - ath9k: Avoid OF no-EEPROM quirks without qca,no-eeprom
+    - perf/x86/intel: Make cpuc allocations consistent
+    - perf/x86/intel: Generalize dynamic constraint creation
+    - x86: Add TSX Force Abort CPUID/MSR
+    - perf/x86/intel: Implement support for TSX Force Abort
+    - Linux 5.0.2
+
+  * Linux security module stacking support
+    - LSM: Introduce LSM_FLAG_LEGACY_MAJOR
+    - LSM: Provide separate ordered initialization
+    - LSM: Plumb visibility into optional "enabled" state
+    - LSM: Lift LSM selection out of individual LSMs
+    - LSM: Build ordered list of LSMs to initialize
+    - LSM: Introduce CONFIG_LSM
+    - LSM: Introduce "lsm=" for boottime LSM selection
+    - LSM: Tie enabling logic to presence in ordered list
+    - LSM: Prepare for reorganizing "security=" logic
+    - LSM: Refactor "security=" in terms of enable/disable
+    - LSM: Separate idea of "major" LSM from "exclusive" LSM
+    - apparmor: Remove SECURITY_APPARMOR_BOOTPARAM_VALUE
+    - selinux: Remove SECURITY_SELINUX_BOOTPARAM_VALUE
+    - LSM: Add all exclusive LSMs to ordered initialization
+    - LSM: Split LSM preparation from initialization
+    - LoadPin: Initialize as ordered LSM
+    - Yama: Initialize as ordered LSM
+    - LSM: Introduce enum lsm_order
+    - capability: Initialize as LSM_ORDER_FIRST
+    - procfs: add smack subdir to attrs
+    - Smack: Abstract use of cred security blob
+    - SELinux: Abstract use of cred security blob
+    - SELinux: Remove cred security blob poisoning
+    - SELinux: Remove unused selinux_is_enabled
+    - AppArmor: Abstract use of cred security blob
+    - TOMOYO: Abstract use of cred security blob
+    - Infrastructure management of the cred security blob
+    - SELinux: Abstract use of file security blob
+    - Smack: Abstract use of file security blob
+    - LSM: Infrastructure management of the file security
+    - SELinux: Abstract use of inode security blob
+    - Smack: Abstract use of inode security blob
+    - LSM: Infrastructure management of the inode security
+    - LSM: Infrastructure management of the task security
+    - SELinux: Abstract use of ipc security blobs
+    - Smack: Abstract use of ipc security blobs
+    - LSM: Infrastructure management of the ipc security blob
+    - TOMOYO: Update LSM flags to no longer be exclusive
+    - LSM: generalize flag passing to security_capable
+    - LSM: Make lsm_early_cred() and lsm_early_task() local functions.
+    - LSM: Make some functions static
+    - apparmor: Adjust offset when accessing task blob.
+    - LSM: Ignore "security=" when "lsm=" is specified
+    - LSM: Update list of SECURITYFS users in Kconfig
+    - apparmor: delete the dentry in aafs_remove() to avoid a leak
+    - apparmor: fix double free when unpack of secmark rules fails
+    - SAUCE: LSM: Infrastructure management of the sock security
+    - SAUCE: LSM: Limit calls to certain module hooks
+    - SAUCE: LSM: Special handling for secctx lsm hooks
+    - SAUCE: LSM: Specify which LSM to display with /proc/self/attr/display
+    - SAUCE: Fix-up af_unix mediation for sock infrastructure management
+    - SAUCE: Revert "apparmor: Fix warning about unused function
+      apparmor_ipv6_postroute"
+    - SAUCE: Revert "apparmor: fix checkpatch error in Parse secmark policy"
+    - SAUCE: Revert "apparmor: add #ifdef checks for secmark filtering"
+    - SAUCE: Revert "apparmor: Allow filtering based on secmark policy"
+    - SAUCE: Revert "apparmor: Parse secmark policy"
+    - SAUCE: Revert "apparmor: Add a wildcard secid"
+    - SAUCE: Revert "apparmor: fix bad debug check in apparmor_secid_to_secctx()"
+    - SAUCE: Revert "apparmor: fixup secid map conversion to using IDR"
+    - SAUCE: Revert "apparmor: Use an IDR to allocate apparmor secids"
+    - SAUCE: Revert "apparmor: Fix memory leak of rule on error exit path"
+    - SAUCE: Revert "apparmor: modify audit rule support to support profile
+      stacks"
+    - SAUCE: Revert "apparmor: Add support for audit rule filtering"
+    - SAUCE: Revert "apparmor: add the ability to get a task's secid"
+    - SAUCE: Revert "apparmor: add support for mapping secids and using secctxes"
+    - SAUCE: apparmor: add proc subdir to attrs
+    - SAUCE: apparmor: add an apparmorfs entry to access current attrs
+    - SAUCE: apparmor: update flags to no longer be exclusive
+    - SAUCE: update configs and annotations for LSM stacking
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_EARLY_PRINTK_USB_XDBC=y
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - [Config] CONFIG_RANDOM_TRUST_CPU=y
+    - [Config] refresh annotations for recent config changes
+    - ubuntu: vbox -- update to 6.0.4-dfsg-7
+    - Revert "UBUNTU: SAUCE: i2c:amd I2C Driver based on PCI Interface for
+      upcoming platform"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 04 Apr 2019 14:49:59 -0500
+
+linux (5.0.0-8.9) disco; urgency=medium
+
+  * linux: 5.0.0-8.9 -proposed tracker (LP: #1819759)
+
+  * hisi_sas: add debugfs support (LP: #1819500)
+    - scsi: hisi_sas: Create root and device debugfs directories
+    - scsi: hisi_sas: Alloc debugfs snapshot buffer memory for all registers
+    - scsi: hisi_sas: Take debugfs snapshot for all regs
+    - scsi: hisi_sas: Debugfs global register create file and add file operations
+    - scsi: hisi_sas: Add debugfs for port registers
+    - scsi: hisi_sas: Add debugfs CQ file and add file operations
+    - scsi: hisi_sas: Add debugfs DQ file and add file operations
+    - scsi: hisi_sas: Add debugfs IOST file and add file operations
+    - scsi: hisi_sas: No need to check return value of debugfs_create functions
+    - scsi: hisi_sas: Fix type casting and missing static qualifier in debugfs
+      code
+    - scsi: hisi_sas: Add debugfs ITCT file and add file operations
+
+  * [disco] hns driver updates from 5.1 merge window (LP: #1819535)
+    - net: hns: Use struct_size() in devm_kzalloc()
+    - net: hns3: modify enet reinitialization interface
+    - net: hns3: remove unused member in struct hns3_enet_ring
+    - net: hns3: remove unnecessary hns3_adjust_tqps_num
+    - net: hns3: reuse reinitialization interface in the hns3_set_channels
+    - net: hns3: add interface hclge_tm_bp_setup
+    - net: hns3: modify parameter checks in the hns3_set_channels
+    - net: hns3: remove redundant codes in hclge_knic_setup
+    - net: hns3: fix user configuration loss for ethtool -L
+    - net: hns3: adjust the use of alloc_tqps and num_tqps
+    - net: hns3: fix wrong combined count returned by ethtool -l
+    - net: hns3: do reinitialization while ETS configuration changed
+    - net: hns3: add HNAE3_RESTORE_CLIENT interface in enet module
+    - net: hns3: add calling roce callback function when link status change
+    - net: hns3: add rx multicast packets statistic
+    - net: hns3: refactor the statistics updating for netdev
+    - net: hns3: fix rss configuration lost problem when setting channel
+    - net: hns3: fix for shaper not setting when TC num changes
+    - net: hns3: fix bug of ethtool_ops.get_channels for VF
+    - net: hns3: clear param in ring when free ring
+    - net: hns3: Change fw error code NOT_EXEC to NOT_SUPPORTED
+    - net: hns3: do not return GE PFC setting err when initializing
+    - net: hns3: add ETS TC weight setting in SSU module
+    - net: hns3: add statistics for PFC frames and MAC control frames
+    - net: hns3: fix PFC not setting problem for DCB module
+    - net: hns3: don't update packet statistics for packets dropped by hardware
+    - net: hns3: clear pci private data when unload hns3 driver
+    - net: hns3: add error handling in hclge_ieee_setets
+    - net: hns3: fix return value handle issue for hclge_set_loopback()
+    - net: hns3: fix broadcast promisc issue for revision 0x20
+    - net: hns3: After setting the loopback, add the status of getting MAC
+    - net: hns3: do reinitialization while mqprio configuration changed
+    - net: hns3: remove dcb_ops->map_update in hclge_dcb
+    - net: hns3: call hns3_nic_set_real_num_queue with netdev down
+    - net: hns3: add 8 BD limit for tx flow
+    - net: hns3: add initialization for nic state
+    - net: hns3: don't allow vf to enable promisc mode
+    - net: hns3: reuse the definition of l3 and l4 header info union
+    - net: hns3: fix VF dump register issue
+    - net: hns3: use the correct interface to stop|open port
+    - net: hns3: change hnae3_register_ae_dev() to int
+    - net: hns3: only support tc 0 for VF
+    - net: hns3: Fix NULL deref when unloading driver
+    - net: hns3: fix netif_napi_del() not do problem when unloading
+    - net: hns3: fix for rss result nonuniform
+    - net: hns3: fix improper error handling in the hclge_init_ae_dev()
+    - net: hns3: fix an issue for hclgevf_ae_get_hdev
+    - net: hns3: stop sending keep alive msg to PF when VF is resetting
+    - net: hns3: keep flow director state unchanged when reset
+    - net: hns3: Check for allocation failure
+    - net: hns3: fix a code style issue for hns3_update_new_int_gl()
+    - net: hns3: fix an issue for hns3_update_new_int_gl
+    - net: hns3: Modify parameter type from int to bool in set_gro_en
+    - net: hns3: code optimization for hclge_rx_buffer_calc
+    - net: hns3: add hclge_cmd_check_retval() to parse comman's return value
+    - net: hns3: move some set_bit statement into hclge_prepare_mac_addr
+    - net: hns3: fix a wrong checking in the hclge_tx_buffer_calc()
+    - net: hns3: fix the problem that the supported port is empty
+    - net: hns3: optimize the maximum TC macro
+    - net: hns3: don't allow user to change vlan filter state
+    - net: hns3: modify the upper limit judgment condition
+    - net: hns3: MAC table entry count function increases operation 0 value
+      protection measures
+    - net: hns3: make function hclge_set_all_vf_rst() static
+    - net: hns3: add pointer checking at the beginning of the exported functions.
+    - net: hns3: Check variable is valid before assigning it to another
+    - net: hns3: convert mac advertize and supported from u32 to link mode
+    - net: hns3: fix port info query issue for copper port
+    - net: hns3: modify print message of ssu common ecc errors
+    - net: hns3: some bugfix of ppu(rcb) ras errors
+    - net: hns3: enable 8~11th bit of mac common msi-x error
+    - net: hns3: fix 6th bit of ppp mpf abnormal errors
+    - net: hns3: Record VF unicast and multicast tables
+    - net: hns3: Record VF vlan tables
+    - net: hns3: uninitialize command queue while unloading PF driver
+    - net: hns3: clear command queue's registers when unloading VF driver
+    - net: hns3: add xps setting support for hns3 driver
+    - net: hns3: avoid mult + div op in critical data path
+    - net: hns3: limit some variable scope in critical data path
+    - net: hns3: remove some ops in struct hns3_nic_ops
+    - net: hns3: add unlikely for error handling in data path
+    - net: hns3: replace hnae3_set_bit and hnae3_set_field in data path
+    - net: hns3: remove hnae3_get_bit in data path
+    - net: hns3: add support to config depth for tx|rx ring separately
+    - net: hns3: enable VF VLAN filter for each VF when initializing
+    - net: hns3: fix get VF RSS issue
+    - net: hns3: fix setting of the hns reset_type for rdma hw errors
+    - net: hns3: fix improper error handling for hns3_client_start
+    - net: hns: use struct_size() in devm_kzalloc()
+    - net: hns3: Fix a logical vs bitwise typo
+    - net: hns3: add dma_rmb() for rx description
+    - net: hns3: fix to stop multiple HNS reset due to the AER changes
+
+  * Build Nvidia drivers in conjunction with kernel (LP: #1764792)
+    - [Packaging] dkms-build -- support building against packages in PPAs
+    - [Packaging] dkms-build: do not redownload files on subsequent passes
+    - [Packaging] dkms-build -- elide partial Built-Using information
+    - [Packaging] dkms-build -- remove retpoline data from final binary packages
+    - [Packaging] dkms-build--nvidia* -- check gcc version against primary build
+    - [Packaging] dkms-build -- add support for unversioned overrides
+    - [Packaging] dkms-build--nvidia-* -- convert to generic -N form
+    - [Packaging] fix-filenames -- handle exact string removal
+    - [Packaging] dkms-build--nvidia-N -- remove GCC versions
+
+  * Disco update: v5.0.1 upstream stable release (LP: #1819515)
+    - cpufreq: Use struct kobj_attribute instead of struct global_attr
+    - staging: erofs: fix mis-acted TAIL merging behavior
+    - binder: create node flag to request sender's security context
+    - 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
+    - driver core: Postpone DMA tear-down until after devres release
+    - staging: erofs: fix fast symlink w/o xattr when fs xattr is on
+    - staging: erofs: fix memleak of inode's shared xattr array
+    - staging: erofs: fix race of initializing xattrs of a inode at the same time
+    - staging: erofs: fix illegal address access under memory pressure
+    - staging: comedi: ni_660x: fix missing break in switch statement
+    - staging: wilc1000: fix to set correct value for 'vif_num'
+    - staging: android: ion: fix sys heap pool's gfp_flags
+    - staging: android: ashmem: Don't call fallocate() with ashmem_mutex held.
+    - staging: android: ashmem: Avoid range_alloc() allocation with ashmem_mutex
+      held.
+    - ip6mr: Do not call __IP6_INC_STATS() from preemptible context
+    - net: dsa: mv88e6xxx: add call to mv88e6xxx_ports_cmode_init to probe for new
+      DSA framework
+    - net: dsa: mv88e6xxx: handle unknown duplex modes gracefully in
+      mv88e6xxx_port_set_duplex
+    - net: dsa: mv8e6xxx: fix number of internal PHYs for 88E6x90 family
+    - net: mscc: Enable all ports in QSGMII
+    - net: sched: put back q.qlen into a single location
+    - net-sysfs: Fix mem leak in netdev_register_kobject
+    - qmi_wwan: Add support for Quectel EG12/EM12
+    - sctp: call iov_iter_revert() after sending ABORT
+    - team: Free BPF filter when unregistering netdev
+    - tipc: fix RDM/DGRAM connect() regression
+    - x86/CPU/AMD: Set the CPB bit unconditionally on F17h
+    - x86/boot/compressed/64: Do not read legacy ROM on EFI system
+    - tracing: Fix event filters and triggers to handle negative numbers
+    - xhci: tegra: Prevent error pointer dereference
+    - usb: xhci: Fix for Enabling USB ROLE SWITCH QUIRK on
+      INTEL_SUNRISEPOINT_LP_XHCI
+    - applicom: Fix potential Spectre v1 vulnerabilities
+    - alpha: wire up io_pgetevents system call
+    - MIPS: irq: Allocate accurate order pages for irq stack
+    - aio: Fix locking in aio_poll()
+    - xtensa: fix get_wchan
+    - gnss: sirf: fix premature wakeup interrupt enable
+    - USB: serial: cp210x: fix GPIO in autosuspend
+    - Revert "selftests: firmware: add CONFIG_FW_LOADER_USER_HELPER_FALLBACK to
+      config"
+    - Revert "selftests: firmware: remove use of non-standard diff -Z option"
+    - selftests: firmware: fix verify_reqs() return value
+    - Bluetooth: btrtl: Restore old logic to assume firmware is already loaded
+    - Bluetooth: Fix locking in bt_accept_enqueue() for BH context
+    - Linux 5.0.1
+
+  * sky2 ethernet card doesn't work after returning from suspend
+    (LP: #1807259) // sky2 ethernet card link not up after suspend
+    (LP: #1809843) // Disco update: v5.0.1 upstream stable release
+    (LP: #1819515)
+    - sky2: Disable MSI on Dell Inspiron 1545 and Gateway P-79
+
+  * tls selftest failures/hangs on i386 (LP: #1813607)
+    - [Config] CONFIG_TLS=n for i386
+
+  * CVE-2019-8980
+    - exec: Fix mem leak in kernel_read_file
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests: net: Use 'ipproto ipv6-icmp' to match ICMPv6 headers
+    - [Config] enable nvidia build
+    - [Config] update gcc version to 8.3
+
+  * Miscellaneous upstream changes
+    - Revert "UBUNTU: SAUCE: selftests: pmtu: disable accept_dad for tests"
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 12 Mar 2019 16:15:44 -0300
+
+linux (5.0.0-7.8) disco; urgency=medium
+
+  * linux: 5.0.0-7.8 -proposed tracker (LP: #1818519)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * unnecessary request_queue freeze (LP: #1815733)
+    - block: avoid setting nr_requests to current value
+    - block: avoid setting none scheduler if it's already none
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests: net: Don't fail test_vxlan_under_vrf on xfail
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 04 Mar 2019 08:46:10 -0600
+
+linux (5.0.0-6.7) disco; urgency=medium
+
+  * linux: 5.0.0-6.7 -proposed tracker (LP: #1817585)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] resync getabis
+
+  * installer does not support iSCSI iBFT (LP: #1817321)
+    - d-i: add iscsi_ibft to scsi-modules
+
+  * Silent "Unknown key" message when pressing keyboard backlight hotkey
+    (LP: #1817063)
+    - platform/x86: dell-wmi: Ignore new keyboard backlight change event
+
+  * Fix I219 doesn't get woken up after plugging ethernet cable (LP: #1817058)
+    - e1000e: Disable runtime PM on CNP+
+
+  * efi/arm/arm64: Allow SetVirtualAddressMap() to be omitted (LP: #1814982)
+    - efi/arm/arm64: Allow SetVirtualAddressMap() to be omitted
+
+  * CVE-2019-3460
+    - Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt
+
+  * CVE-2019-3459
+    - Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer
+
+  * kernel net tls selftest fails on 5.0 (LP: #1816716)
+    - SAUCE: Revert "selftests/tls: Add test for recv(PEEK) spanning across
+      multiple records"
+
+  * Please enable CONFIG_DMA_CMA=y on arm64 (LP: #1803206)
+    - [Config] annotations -- enforce CONFIG_DMA_CMA and update notes
+
+  * [19.04 FEAT] [LS1801] PCI Virtual function enablement (LP: #1814684)
+    - s390/pci: map IOV resources
+    - s390/pci: improve bar check
+
+  * glibc 2.28-0ubuntu1 ADT test failure with linux 5.0.0-1.2 (LP: #1813060)
+    - SAUCE: prevent a glibc test failure when looking for obsolete types on
+      headers
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Enforce CONFIG_ZCRYPT_MULTIDEVNODES in annotations
+    - SAUCE: selftests: pmtu: disable accept_dad for tests
+    - SAUCE: arm64: add kernel config option to lock down when in Secure Boot mode
+    - SAUCE: selftests: net: Make test for VXLAN underlay in non-default VRF an
+      expected failure
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc8
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 25 Feb 2019 09:37:36 -0600
+
+linux (5.0.0-5.6) disco; urgency=medium
+
+  * [ALSA] [PATCH] System76 darp5 and oryp5 fixups (LP: #1815831)
+    - ALSA: hda/realtek - Headset microphone and internal speaker support for
+      System76 oryp5
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Fix aufs menus in annotations file
+    - [Config] CONFIG_SAMPLE_TRACE_PRINTK=m
+    - [Config] Update annotations based on configs
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 18 Feb 2019 10:04:11 +0100
+
+linux (5.0.0-4.5) disco; urgency=medium
+
+  * linux-buildinfo: pull out ABI information into its own package
+    (LP: #1806380)
+    - [Packaging] autoreconstruct -- base tag is always primary mainline version
+
+  * [Packaging] Allow overlay of config annotations (LP: #1752072)
+    - [Packaging] config-check: Add an include directive
+
+  * Miscellaneous Ubuntu changes
+    - hio -- stub out BIOVEC_PHYS_MERGEABLE for 4.20+
+    - hio -- replace use of do_gettimeofday()
+    - hio -- part_round_stats() removed in 5.0
+    - hio -- device_add_disk() grew a 'groups' argument in 4.20
+    - enable hio build
+    - Revert "UBUNTU: [Packaging] autoreconstruct -- base tag is always primary
+      mainline version"
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 12 Feb 2019 08:15:32 -0600
+
+linux (5.0.0-3.4) disco; urgency=medium
+
+  * CONFIG_TEST_BPF is disabled (LP: #1813955)
+    - [Config]: Reenable TEST_BPF
+
+  * Ignore "incomplete report" from Elan touchpanels (LP: #1813733)
+    - HID: i2c-hid: Ignore input report if there's no data present on Elan
+      touchpanels
+
+  * SecureBoot support for arm64 (LP: #1804481)
+    - Build signed kernels for arm64
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests: net: fix "from" match test in fib_rule_tests.sh
+    - [Config] CONFIG_PCMCIA=n for arm64 and s390x
+    - [Config] CONFIG_SERIAL_SC16IS7XX=n for s390x
+    - [Config] disable I2C TPM drivers for s390x
+    - [Config] CONFIG_RAPIDIO=n for s390x
+    - [Config] CONFIG_DMADEVICES=n for s390x
+    - [Config] disable gpio drivers for s390x
+    - [Config] CONFIG_SENSORS_OCC_P8_I2C=m for ppc64el
+    - [Config] disable I2C hardware drivers for s390x
+    - [Config] CONFIG_I3C=n for s390x
+    - [Config] CONFIG_SERIO=n for s390x
+    - [Config] disable misc drivers for s390x
+    - [Config] disable EEPROM drivers for s390x
+    - [Config] disable MFD drivers for s390x
+    - [Config] CONFIG_NVMEM=n for s390x
+    - [Config] CONFIG_MLXSW_I2C=n for s390x
+    - [Config] CONFIG_NET_VENDOR_MICROCHIP=n for s390x
+    - [Config] CONFIG_PPP=n for s390x
+    - [Config] CONFIG_PCCARD=n for s390x
+    - [Config] CONFIG_PCI_MESON=y
+    - [Config] CONFIG_SCSI_MYRB=n for s390x
+    - [Config] CONFIG_REGULATOR=n for s390x
+    - [Config] CONFIG_ZIIRAVE_WATCHDOG=n for s390x
+    - [Config] CONFIG_NCSI_OEM_CMD_GET_MAC=y
+    - [Config] update annotations following config review
+    - [Packaging] remove handoff check for uefi signing
+    - [Packaging] decompress gzipped efi images in signing tarball
+    - vbox-update: allow leading whitespace when fixing up KERN_DIR
+    - ubuntu: vbox -- update to 6.0.4-dfsg-3
+    - vbox: remove remount check in sf_read_super_aux()
+    - enable vbox build
+    - [Config] CONFIG_ANDROID_BINDER_DEVICES=""
+    - SAUCE: import aufs driver
+    - [Config]: Enable aufs
+    - [Config] relocate aufs annotations to menu
+    - [Config] remove unmatched configs from annotations
+    - [Config] fix up abi for removed modules
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) module: remove support for having IMA validate modules
+    - SAUCE: (efi-lockdown) Move EFI signature blob parser to shared location
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable to be suppressed
+    - [Config] (efi-lockdown) enable importing of efi certificates for module sig
+      verification
+
+  * Miscellaneous upstream changes
+    - binder: fix CONFIG_ANDROID_BINDER_DEVICES
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 05 Feb 2019 14:26:12 -0600
+
+linux (5.0.0-2.3) disco; urgency=medium
+
+  * kernel oops in bcache module (LP: #1793901)
+    - SAUCE: bcache: never writeback a discard operation
+
+  * Enable sound card power saving by default (LP: #1804265)
+    - [Config] CONFIG_SND_HDA_POWER_SAVE_DEFAULT=1
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: selftests: disable some failing networking tests"
+    - SAUCE: ashmem: turn into module
+    - SAUCE: binder: turn into module
+    - SAUCE: binder: give binder_alloc its own debug mask file
+    - [Config] enable binder and ashmem as modules
+    - SAUCE: selftests: net: replace AF_MAX with INT_MAX in socket.c
+    - SAUCE: selftests/ftrace: Fix tab expansion in trace_marker snapshot trigger
+      test
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 29 Jan 2019 06:57:32 -0600
+
+linux (5.0.0-1.2) disco; urgency=medium
+
+  * Fix non-working QCA Rome Bluetooth after S3 (LP: #1812812)
+    - USB: Add new USB LPM helpers
+    - USB: Consolidate LPM checks to avoid enabling LPM twice
+
+  * bluetooth controller not detected with 4.15 kernel (LP: #1810797)
+    - SAUCE: btqcomsmd: introduce BT_QCOMSMD_HACK
+    - [Config] arm64: snapdragon: BT_QCOMSMD_HACK=y
+
+  * [19.04 FEAT| Enable virtio-gpu for s390x (LP: #1799467)
+    - [Config] enable virtio-gpu for s390x
+
+  * Crash on "ip link add foo type ipip" (LP: #1811803)
+    - SAUCE: fan: Fix NULL pointer dereference
+
+  * Fix not working Goodix touchpad (LP: #1811929)
+    - HID: i2c-hid: Disable runtime PM on Goodix touchpad
+
+  * Miscellaneous Ubuntu changes
+    - update dkms package versions
+    - enable zfs build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 22 Jan 2019 13:56:17 -0600
+
+linux (5.0.0-0.1) disco; urgency=medium
+
+  * Build Nvidia drivers in conjunction with kernel (LP: #1764792)
+    - [Packaging] dkms -- add per package post-process step
+    - [Packaging] dkms -- switch to a consistent build prefix length and strip
+    - [Packaging] nvidia -- build and sign nvidia packages and ship signatures
+    - [Packaging] nvidia -- make nvidia package version explicit
+
+  * Add support for ALC3277 codec on new Dell edge gateways (LP: #1807334)
+    - [Config] CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH=m
+
+  * RTL8822BE WiFi Disabled in Kernel 4.18.0-12 (LP: #1806472)
+    - [Config] CONFIG_RTLWIFI_DEBUG_ST=n
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu -- disable vbox build
+    - ubuntu -- disable hio build
+    - Disable zfs build
+    - SAUCE: import aufs driver
+    - update dkms package versions
+    - [Config] disable aufs config options
+    - [Config] disable nvidia build
+    - update dropped.txt
+    - [Packaging] disable nvidia dkms builds for mainline
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) debugfs: avoid EPERM when no open file operation
+      defined
+    - SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time addition of keys to
+      secondary keyring
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - [Config] set config options for efi lockdown
+    - Revert "UBUNTU: SAUCE: import aufs driver"
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v5.0-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 17 Jan 2019 12:31:29 -0600
+
+linux (5.0.0-0.0) disco; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 16 Jan 2019 14:48:05 -0600
+
+linux (4.20.0-2.3) disco; urgency=medium
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.20
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 03 Jan 2019 12:11:43 -0600
+
+linux (4.20.0-1.2) disco; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * Power leakage at S5 with Qualcomm Atheros QCA9377 802.11ac Wireless Network
+    Adapter (LP: #1805607)
+    - SAUCE: ath10k: provide reset function for QCA9377 chip
+
+  * zfs/spl build in conjunction with the kernel from DKMS source (LP: #1807378)
+    - [Packaging] dkms -- dkms package build packaging support
+    - [Packaging] dkms -- save build objects artifacts for validation
+    - [Packaging] dkms -- add general Built-Using: support
+    - [Packaging] simplify Provides comma handling
+    - [Packaging] zfs/spl -- remove packaging support for incorporated source
+    - [Packaging] zfs/spl -- remove incorporated source
+    - [Packaging] zfs/spl -- build via dkms
+    - [Packaging] zfs/spl -- make zfs package version explicit
+    - [Packaging] update-version-dkms -- sync archive versions to package
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] update-version-dkms -- fix getting distrbution from changelog
+    - update dkms package versions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.20-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 11 Dec 2018 11:33:08 -0600
+
+linux (4.20.0-0.1) disco; urgency=medium
+
+  * Overlayfs in user namespace leaks directory content of inaccessible
+    directories (LP: #1793458) // CVE-2018-6559
+    - Revert "ovl: relax permission checking on underlying layers"
+    - SAUCE: overlayfs: ensure mounter privileges when reading directories
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time addition of keys to
+      secondary keyring
+    - SAUCE: (efi-lockdown) efi: Add EFI signature data types
+    - SAUCE: (efi-lockdown) efi: Add an EFI signature blob parser
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable to be suppressed
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) Fix for module sig verification
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: Import aufs driver
+    - ubuntu: vbox -- update to 5.2.22-dfsg-2
+    - ubuntu -- disable vbox build
+    - ubuntu -- disable hio build
+    - Disable zfs build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.20-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 07 Dec 2018 07:13:42 -0600
+
+linux (4.20.0-0.0) disco; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 06 Dec 2018 10:20:19 -0600
+
+linux (4.19.0-8.9) disco; urgency=medium
+
+  * linux: 4.19.0-8.9 -proposed tracker (LP: #1806952)
+
+  * Workaround CSS timeout on AMD SNPS 3.0 xHC (LP: #1806838)
+    - xhci: workaround CSS timeout on AMD SNPS 3.0 xHC
+
+  * 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
+
+  * The line-out on the Dell Dock station can't work (LP: #1806532)
+    - ALSA: usb-audio: Add vendor and product name for Dell WD19 Dock
+
+  * CVE-2018-19407
+    - KVM: X86: Fix scan ioapic use-before-initialization
+
+  * PC SN720 NVMe WDC 256GB consumes more power in S2Idle than during long idle
+    (LP: #1805775)
+    - SAUCE: pci/nvme: prevent WDC PC SN720 NVMe from entering D3 and being
+      disabled
+
+  * Disco update: 4.19.6 upstream stable release (LP: #1806909)
+    - HID: steam: remove input device when a hid client is running.
+    - efi/libstub: arm: support building with clang
+    - usb: core: Fix hub port connection events lost
+    - usb: dwc3: gadget: fix ISOC TRB type on unaligned transfers
+    - usb: dwc3: gadget: Properly check last unaligned/zero chain TRB
+    - usb: dwc3: core: Clean up ULPI device
+    - usb: dwc3: Fix NULL pointer exception in dwc3_pci_remove()
+    - xhci: Fix leaking USB3 shared_hcd at xhci removal
+    - xhci: handle port status events for removed USB3 hcd
+    - xhci: Add check for invalid byte size error when UAS devices are connected.
+    - usb: xhci: fix uninitialized completion when USB3 port got wrong status
+    - usb: xhci: fix timeout for transition from RExit to U0
+    - xhci: Add quirk to workaround the errata seen on Cavium Thunder-X2 Soc
+    - usb: xhci: Prevent bus suspend if a port connect change or polling state is
+      detected
+    - ALSA: oss: Use kvzalloc() for local buffer allocations
+    - MAINTAINERS: Add Sasha as a stable branch maintainer
+    - Documentation/security-bugs: Clarify treatment of embargoed information
+    - Documentation/security-bugs: Postpone fix publication in exceptional cases
+    - mmc: sdhci-pci: Try "cd" for card-detect lookup before using NULL
+    - mmc: sdhci-pci: Workaround GLK firmware failing to restore the tuning value
+    - gpio: don't free unallocated ida on gpiochip_add_data_with_key() error path
+    - iwlwifi: fix wrong WGDS_WIFI_DATA_SIZE
+    - iwlwifi: mvm: support sta_statistics() even on older firmware
+    - iwlwifi: mvm: fix regulatory domain update when the firmware starts
+    - iwlwifi: mvm: don't use SAR Geo if basic SAR is not used
+    - brcmfmac: fix reporting support for 160 MHz channels
+    - opp: ti-opp-supply: Dynamically update u_volt_min
+    - opp: ti-opp-supply: Correct the supply in _get_optimal_vdd_voltage call
+    - tools/power/cpupower: fix compilation with STATIC=true
+    - v9fs_dir_readdir: fix double-free on p9stat_read error
+    - selinux: Add __GFP_NOWARN to allocation at str_read()
+    - Input: synaptics - avoid using uninitialized variable when probing
+    - 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()
+    - mm: don't warn about large allocations for slab
+    - mm/memory.c: recheck page table entry with page table lock held
+    - tcp: do not release socket ownership in tcp_close()
+    - drm/fb-helper: Blacklist writeback when adding connectors to fbdev
+    - drm/amdgpu: Add missing firmware entry for HAINAN
+    - drm/vc4: Set ->legacy_cursor_update to false when doing non-async updates
+    - drm/amdgpu: Fix oops when pp_funcs->switch_power_profile is unset
+    - drm/i915: Disable LP3 watermarks on all SNB machines
+    - drm/ast: change resolution may cause screen blurred
+    - drm/ast: fixed cursor may disappear sometimes
+    - drm/ast: Remove existing framebuffers before loading driver
+    - can: flexcan: Unlock the MB unconditionally
+    - 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
+    - can: rx-offload: introduce can_rx_offload_get_echo_skb() and
+      can_rx_offload_queue_sorted() functions
+    - can: rx-offload: rename can_rx_offload_irq_queue_err_skb() to
+      can_rx_offload_queue_tail()
+    - can: flexcan: use can_rx_offload_queue_sorted() for flexcan_irq_bus_*()
+    - can: flexcan: handle tx-complete CAN frames via rx-offload infrastructure
+    - can: raw: check for CAN FD capable netdev in raw_sendmsg()
+    - can: hi311x: Use level-triggered interrupt
+    - can: flexcan: Always use last mailbox for TX
+    - can: flexcan: remove not needed struct flexcan_priv::tx_mb and struct
+      flexcan_priv::tx_mb_idx
+    - ACPICA: AML interpreter: add region addresses in global list during
+      initialization
+    - IB/hfi1: Eliminate races in the SDMA send error path
+    - fsnotify: generalize handling of extra event flags
+    - fanotify: fix handling of events on child sub-directory
+    - pinctrl: meson: fix pinconf bias disable
+    - pinctrl: meson: fix gxbb ao pull register bits
+    - pinctrl: meson: fix gxl ao pull register bits
+    - pinctrl: meson: fix meson8 ao pull register bits
+    - pinctrl: meson: fix meson8b ao pull register bits
+    - tools/testing/nvdimm: Fix the array size for dimm devices.
+    - scsi: lpfc: fix remoteport access
+    - scsi: hisi_sas: Remove set but not used variable 'dq_list'
+    - KVM: PPC: Move and undef TRACE_INCLUDE_PATH/FILE
+    - cpufreq: imx6q: add return value check for voltage scale
+    - rtc: cmos: Do not export alarm rtc_ops when we do not support alarms
+    - rtc: pcf2127: fix a kmemleak caused in pcf2127_i2c_gather_write
+    - crypto: simd - correctly take reqsize of wrapped skcipher into account
+    - floppy: fix race condition in __floppy_read_block_0()
+    - powerpc/io: Fix the IO workarounds code to work with Radix
+    - sched/fair: Fix cpu_util_wake() for 'execl' type workloads
+    - perf/x86/intel/uncore: Add more IMC PCI IDs for KabyLake and CoffeeLake CPUs
+    - block: copy ioprio in __bio_clone_fast() and bounce
+    - SUNRPC: Fix a bogus get/put in generic_key_to_expire()
+    - riscv: add missing vdso_install target
+    - RISC-V: Silence some module warnings on 32-bit
+    - drm/amdgpu: fix bug with IH ring setup
+    - kdb: Use strscpy with destination buffer size
+    - NFSv4: Fix an Oops during delegation callbacks
+    - powerpc/numa: Suppress "VPHN is not supported" messages
+    - efi/arm: Revert deferred unmap of early memmap mapping
+    - z3fold: fix possible reclaim races
+    - mm, memory_hotplug: check zone_movable in has_unmovable_pages
+    - tmpfs: make lseek(SEEK_DATA/SEK_HOLE) return ENXIO with a negative offset
+    - mm, page_alloc: check for max order in hot path
+    - dax: Avoid losing wakeup in dax_lock_mapping_entry
+    - include/linux/pfn_t.h: force '~' to be parsed as an unary operator
+    - tty: wipe buffer.
+    - tty: wipe buffer if not echoing data
+    - gfs2: Fix iomap buffer head reference counting bug
+    - rcu: Make need_resched() respond to urgent RCU-QS needs
+    - media: ov5640: Re-work MIPI startup sequence
+    - media: ov5640: Fix timings setup code
+    - media: ov5640: fix exposure regression
+    - media: ov5640: fix auto gain & exposure when changing mode
+    - media: ov5640: fix wrong binning value in exposure calculation
+    - media: ov5640: fix auto controls values when switching to manual mode
+    - Linux 4.19.6
+
+  * 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
+    - [Packaging] getabis -- handle all known package combinations
+    - [Packaging] getabis -- support parsing a simple version
+
+  * linux packages should own /usr/lib/linux/triggers (LP: #1770256)
+    - [Packaging] own /usr/lib/linux/triggers
+
+  * Miscellaneous upstream changes
+    - blk-mq: fix corruption with direct issue
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 05 Dec 2018 09:18:30 -0600
+
+linux (4.19.0-7.8) disco; urgency=medium
+
+  * linux: 4.19.0-7.8 -proposed tracker (LP: #1805465)
+
+  * Fix and issue that LG I2C touchscreen stops working after reboot
+    (LP: #1805085)
+    - HID: i2c-hid: Disable runtime PM for LG touchscreen
+
+  * click/pop noise in the headphone on several lenovo laptops (LP: #1805079) //
+    click/pop noise in the headphone on several lenovo laptops (LP: #1805079)
+    - ALSA: hda/realtek - fix the pop noise on headphone for lenovo laptops
+
+  * Regression: hinic performance degrades over time (LP: #1805248)
+    - Revert "net-next/hinic: add checksum offload and TSO support"
+
+  * Disco update: 4.19.5 upstream stable release (LP: #1805461)
+    - drm/i915: Replace some PAGE_SIZE with I915_GTT_PAGE_SIZE
+    - cifs: don't dereference smb_file_target before null check
+    - cifs: fix return value for cifs_listxattr
+    - arm64: kprobe: make page to RO mode when allocate it
+    - block: brd: associate with queue until adding disk
+    - net: hns3: bugfix for rtnl_lock's range in the hclgevf_reset()
+    - net: hns3: bugfix for rtnl_lock's range in the hclge_reset()
+    - net: hns3: bugfix for handling mailbox while the command queue reinitialized
+    - net: hns3: bugfix for the initialization of command queue's spin lock
+    - ixgbe: fix MAC anti-spoofing filter after VFLR
+    - reiserfs: propagate errors from fill_with_dentries() properly
+    - hfs: prevent btree data loss on root split
+    - hfsplus: prevent btree data loss on root split
+    - perf unwind: Take pgoff into account when reporting elf to libdwfl
+    - um: Give start_idle_thread() a return code
+    - drm/edid: Add 6 bpc quirk for BOE panel.
+    - afs: Handle EIO from delivery function
+    - platform/x86: intel_telemetry: report debugfs failure
+    - clk: fixed-rate: fix of_node_get-put imbalance
+    - perf symbols: Set PLT entry/header sizes properly on Sparc
+    - fs/exofs: fix potential memory leak in mount option parsing
+    - clk: samsung: exynos5420: Enable PERIS clocks for suspend
+    - apparmor: Fix uninitialized value in aa_split_fqname
+    - x86/earlyprintk: Add a force option for pciserial device
+    - platform/x86: acerhdf: Add BIOS entry for Gateway LT31 v1.3307
+    - clk: meson-axg: pcie: drop the mpll3 clock parent
+    - arm64: percpu: Initialize ret in the default case
+    - clk: meson: clk-pll: drop CLK_GET_RATE_NOCACHE where unnecessary
+    - clk: renesas: r9a06g032: Fix UART34567 clock rate
+    - clk: ti: fix OF child-node lookup
+    - serial: sh-sci: Fix receive on SCIFA/SCIFB variants with DMA
+    - netfilter: ipv6: fix oops when defragmenting locally generated fragments
+    - netfilter: bridge: define INT_MIN & INT_MAX in userspace
+    - s390/decompressor: add missing FORCE to build targets
+    - s390/vdso: add missing FORCE to build targets
+    - HID: i2c-hid: Add a small delay after sleep command for Raydium touchpanel
+    - Revert "HID: add NOGET quirk for Eaton Ellipse MAX UPS"
+    - HID: alps: allow incoming reports when only the trackstick is opened
+    - Revert "netfilter: nft_numgen: add map lookups for numgen random operations"
+    - netfilter: ipset: list:set: Decrease refcount synchronously on deletion and
+      replace
+    - netfilter: ipset: actually allow allowable CIDR 0 in hash:net,port,net
+    - netfilter: ipset: fix ip_set_list allocation failure
+    - s390/mm: fix mis-accounting of pgtable_bytes
+    - s390/mm: Fix ERROR: "__node_distance" undefined!
+    - bpf: fix bpf_prog_get_info_by_fd to return 0 func_lens for unpriv
+    - netfilter: ipset: Correct rcu_dereference() call in ip_set_put_comment()
+    - netfilter: xt_IDLETIMER: add sysfs filename checking routine
+    - netfilter: ipset: Fix calling ip_set() macro at dumping
+    - netfilter: nft_compat: ebtables 'nat' table is normal chain type
+    - s390/qeth: fix HiperSockets sniffer
+    - s390/qeth: unregister netdevice only when registered
+    - net: hns3: Fix for out-of-bounds access when setting pfc back pressure
+    - hwmon: (ibmpowernv) Remove bogus __init annotations
+    - ARM: dts: imx6sll: fix typo for fsl,imx6sll-i2c node
+    - ARM: dts: fsl: Fix improperly quoted stdout-path values
+    - Revert "drm/exynos/decon5433: implement frame counter"
+    - arm64: dts: renesas: r8a7795: add missing dma-names on hscif2
+    - arm64: dts: renesas: condor: switch from EtherAVB to GEther
+    - xen/grant-table: Fix incorrect gnttab_dma_free_pages() pr_debug message
+    - clk: fixed-factor: fix of_node_get-put imbalance
+    - mtd: nand: Fix nanddev_pos_next_page() kernel-doc header
+    - lib/raid6: Fix arm64 test build
+    - drm/amd/display: Stop leaking planes
+    - block: Clear kernel memory before copying to user
+    - drm/amd/display: Drop reusing drm connector for MST
+    - drm/amd/amdgpu/dm: Fix dm_dp_create_fake_mst_encoder()
+    - s390/perf: Change CPUM_CF return code in event init function
+    - ceph: quota: fix null pointer dereference in quota check
+    - of/device: Really only set bus DMA mask when appropriate
+    - nvme: make sure ns head inherits underlying device limits
+    - i2c: omap: Enable for ARCH_K3
+    - i2c: qcom-geni: Fix runtime PM mismatch with child devices
+    - sched/core: Take the hotplug lock in sched_init_smp()
+    - perf tools: Fix undefined symbol scnprintf in libperf-jvmti.so
+    - perf tools: Do not zero sample_id_all for group members
+    - ice: Fix dead device link issue with flow control
+    - ice: Fix the bytecount sent to netdev_tx_sent_queue
+    - ice: Change req_speeds to be u16
+    - i40e: restore NETIF_F_GSO_IPXIP[46] to netdev features
+    - qed: Fix memory/entry leak in qed_init_sp_request()
+    - qed: Fix blocking/unlimited SPQ entries leak
+    - qed: Fix SPQ entries not returned to pool in error flows
+    - qed: Fix potential memory corruption
+    - net: stmmac: Fix RX packet size > 8191
+    - net: aquantia: fix potential IOMMU fault after driver unbind
+    - net: aquantia: fixed enable unicast on 32 macvlan
+    - net: aquantia: invalid checksumm offload implementation
+    - kbuild: deb-pkg: fix too low build version number
+    - Revert "scripts/setlocalversion: git: Make -dirty check more robust"
+    - SUNRPC: drop pointless static qualifier in xdr_get_next_encode_buffer()
+    - x86/mm: Move LDT remap out of KASLR region on 5-level paging
+    - x86/ldt: Unmap PTEs for the slot before freeing LDT pages
+    - x86/ldt: Remove unused variable in map_ldt_struct()
+    - media: v4l: event: Add subscription to list before calling "add" operation
+    - MIPS: OCTEON: cavium_octeon_defconfig: re-enable OCTEON USB driver
+    - RISC-V: Fix raw_copy_{to,from}_user()
+    - uio: Fix an Oops on load
+    - ALSA: hda/realtek - Add quirk entry for HP Pavilion 15
+    - ALSA: hda/ca0132 - Call pci_iounmap() instead of iounmap()
+    - can: kvaser_usb: Fix accessing freed memory in kvaser_usb_start_xmit()
+    - can: kvaser_usb: Fix potential uninitialized variable use
+    - usb: cdc-acm: add entry for Hiro (Conexant) modem
+    - USB: Wait for extra delay time after USB_PORT_FEAT_RESET for quirky hub
+    - 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
+    - gnss: serial: fix synchronous write timeout
+    - gnss: sirf: fix synchronous write timeout
+    - mtd: rawnand: atmel: fix OF child-node lookup
+    - drivers/misc/sgi-gru: fix Spectre v1 vulnerability
+    - ACPI / platform: Add SMB0001 HID to forbidden_id_list
+    - HID: uhid: forbid UHID_CREATE under KERNEL_DS or elevated privileges
+    - HID: Add quirk for Primax PIXART OEM mice
+    - HID: Add quirk for Microsoft PIXART OEM mouse
+    - libceph: fall back to sendmsg for slab pages
+    - mt76x0: run vco calibration for each channel configuration
+    - Linux 4.19.5
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: Build signed kernels for arm64"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 27 Nov 2018 10:38:34 -0600
+
+linux (4.19.0-6.7) disco; urgency=medium
+
+  * linux: 4.19.0-6.7 -proposed tracker (LP: #1805195)
+
+  * SecureBoot support for arm64 (LP: #1804481)
+    - Build signed kernels for arm64
+
+  * Add pointstick support for Cirque Touchpad (LP: #1805081)
+    - HID: multitouch: Add pointstick support for Cirque Touchpad
+
+  * Power consumption during s2idle is higher than long idle (Intel SSDPEKKF)
+    (LP: #1804588)
+    - SAUCE: pci: prevent Intel NVMe SSDPEKKF from entering D3
+    - SAUCE: nvme: add quirk to not call disable function when suspending
+
+  * Disco update: 4.19.4 upstream stable release (LP: #1805159)
+    - flow_dissector: do not dissect l4 ports for fragments
+    - ibmvnic: fix accelerated VLAN handling
+    - ip_tunnel: don't force DF when MTU is locked
+    - ipv6: fix a dst leak when removing its exception
+    - ipv6: Fix PMTU updates for UDP/raw sockets in presence of VRF
+    - net: bcmgenet: protect stop from timeout
+    - net-gro: reset skb->pkt_type in napi_reuse_skb()
+    - sctp: not allow to set asoc prsctp_enable by sockopt
+    - tcp: Fix SOF_TIMESTAMPING_RX_HARDWARE to use the latest timestamp during TCP
+      coalescing
+    - tg3: Add PHY reset for 5717/5719/5720 in change ring and flow control paths
+    - tipc: don't assume linear buffer when reading ancillary data
+    - tipc: fix lockdep warning when reinitilaizing sockets
+    - tuntap: fix multiqueue rx
+    - net: systemport: Protect stop from timeout
+    - net/sched: act_pedit: fix memory leak when IDR allocation fails
+    - net: sched: cls_flower: validate nested enc_opts_policy to avoid warning
+    - tipc: fix link re-establish failure
+    - net/mlx5e: Don't match on vlan non-existence if ethertype is wildcarded
+    - net/mlx5e: Claim TC hw offloads support only under a proper build config
+    - net/mlx5e: Adjust to max number of channles when re-attaching
+    - net/mlx5e: RX, verify received packet size in Linear Striding RQ
+    - Revert "sctp: remove sctp_transport_pmtu_check"
+    - net/mlx5e: Always use the match level enum when parsing TC rule match
+    - net/mlx5e: Fix selftest for small MTUs
+    - net/mlx5e: Removed unnecessary warnings in FEC caps query
+    - inet: frags: better deal with smp races
+    - l2tp: fix a sock refcnt leak in l2tp_tunnel_register
+    - net/mlx5: IPSec, Fix the SA context hash key
+    - net/mlx5e: IPoIB, Reset QP after channels are closed
+    - net: dsa: mv88e6xxx: Fix clearing of stats counters
+    - net: phy: realtek: fix RTL8201F sysfs name
+    - sctp: define SCTP_SS_DEFAULT for Stream schedulers
+    - net: qualcomm: rmnet: Fix incorrect assignment of real_dev
+    - net: dsa: microchip: initialize mutex before use
+    - sctp: fix strchange_flags name for Stream Change Event
+    - net: phy: mdio-gpio: Fix working over slow can_sleep GPIOs
+    - sctp: not increase stream's incnt before sending addstrm_in request
+    - mlxsw: spectrum: Fix IP2ME CPU policer configuration
+    - net: smsc95xx: Fix MTU range
+    - rxrpc: Fix lockup due to no error backoff after ack transmit error
+    - usbnet: smsc95xx: disable carrier check while suspending
+    - Revert "x86/speculation: Enable cross-hyperthread spectre v2 STIBP
+      mitigation"
+    - Linux 4.19.4
+
+  * Disco update: 4.19.3 upstream stable release (LP: #1805158)
+    - powerpc/traps: restore recoverability of machine_check interrupts
+    - powerpc/64/module: REL32 relocation range check
+    - powerpc/mm: Fix page table dump to work on Radix
+    - powerpc/mm: fix always true/false warning in slice.c
+    - drm/amd/display: fix bug of accessing invalid memory
+    - Input: wm97xx-ts - fix exit path
+    - powerpc/Makefile: Fix PPC_BOOK3S_64 ASFLAGS
+    - powerpc/eeh: Fix possible null deref in eeh_dump_dev_log()
+    - tty: check name length in tty_find_polling_driver()
+    - tracing/kprobes: Check the probe on unloaded module correctly
+    - drm/nouveau/secboot/acr: fix memory leak
+    - drm/amdgpu/powerplay: fix missing break in switch statements
+    - ARM: imx_v6_v7_defconfig: Select CONFIG_TMPFS_POSIX_ACL
+    - powerpc/nohash: fix undefined behaviour when testing page size support
+    - drm/msm/gpu: fix parameters in function msm_gpu_crashstate_capture
+    - drm/msm/disp/dpu: Use proper define for drm_encoder_init() 'encoder_type'
+    - drm/msm: dpu: Allow planes to extend past active display
+    - powerpc/mm: Don't report hugepage tables as memory leaks when using kmemleak
+    - drm/omap: fix memory barrier bug in DMM driver
+    - drm/amd/display: Raise dispclk value for dce120 by 15%
+    - drm/amd/display: fix gamma not being applied
+    - drm/hisilicon: hibmc: Do not carry error code in HiBMC framebuffer pointer
+    - media: pci: cx23885: handle adding to list failure
+    - media: coda: don't overwrite h.264 profile_idc on decoder instance
+    - MIPS: kexec: Mark CPU offline before disabling local IRQ
+    - powerpc/boot: Ensure _zimage_start is a weak symbol
+    - powerpc/memtrace: Remove memory in chunks
+    - MIPS/PCI: Call pcie_bus_configure_settings() to set MPS/MRRS
+    - staging: erofs: fix a missing endian conversion
+    - serial: 8250_of: Fix for lack of interrupt support
+    - sc16is7xx: Fix for multi-channel stall
+    - media: tvp5150: fix width alignment during set_selection()
+    - powerpc/selftests: Wait all threads to join
+    - staging:iio:ad7606: fix voltage scales
+    - drm: rcar-du: Update Gen3 output limitations
+    - drm/amdgpu: Fix SDMA TO after GPU reset v3
+    - staging: most: video: fix registration of an empty comp core_component
+    - 9p locks: fix glock.client_id leak in do_lock
+    - udf: Prevent write-unsupported filesystem to be remounted read-write
+    - ARM: dts: imx6ull: keep IMX6UL_ prefix for signals on both i.MX6UL and
+      i.MX6ULL
+    - media: ov5640: fix mode change regression
+    - 9p: clear dangling pointers in p9stat_free
+    - drm/amdgpu: fix integer overflow test in amdgpu_bo_list_create()
+    - media: ov5640: fix restore of last mode set
+    - cdrom: fix improper type cast, which can leat to information leak.
+    - ovl: fix error handling in ovl_verify_set_fh()
+    - ovl: fix recursive oi->lock in ovl_link()
+    - ovl: check whiteout in ovl_create_over_whiteout()
+    - ovl: automatically enable redirect_dir on metacopy=on
+    - serial: sh-sci: Fix could not remove dev_attr_rx_fifo_timeout
+    - scsi: qla2xxx: Fix incorrect port speed being set for FC adapters
+    - scsi: qla2xxx: Fix process response queue for ISP26XX and above
+    - scsi: qla2xxx: Remove stale debug trace message from tcm_qla2xxx
+    - scsi: qla2xxx: Fix early srb free on abort
+    - scsi: qla2xxx: shutdown chip if reset fail
+    - scsi: qla2xxx: Reject bsg request if chip is down.
+    - scsi: qla2xxx: Fix re-using LoopID when handle is in use
+    - scsi: qla2xxx: Fix for double free of SRB structure
+    - scsi: qla2xxx: Fix NVMe session hang on unload
+    - scsi: qla2xxx: Fix NVMe Target discovery
+    - scsi: qla2xxx: Fix duplicate switch database entries
+    - scsi: qla2xxx: Fix driver hang when FC-NVMe LUNs are configured
+    - vfs: fix FIGETBSZ ioctl on an overlayfs file
+    - 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
+    - drm/msm: fix OF child-node lookup
+    - arm64: dts: stratix10: Support Ethernet Jumbo frame
+    - arm64: dts: stratix10: fix multicast filtering
+    - clk: meson-gxbb: set fclk_div3 as CLK_IS_CRITICAL
+    - clk: meson: axg: mark fdiv2 and fdiv3 as critical
+    - zram: close udev startup race condition as default groups
+    - 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
+    - um: Drop own definition of PTRACE_SYSEMU/_SINGLESTEP
+    - clk: s2mps11: Fix matching when built as module and DT node contains
+      compatible
+    - clk: at91: Fix division by zero in PLL recalc_rate()
+    - clk: sunxi-ng: h6: fix bus clocks' divider position
+    - clk: rockchip: fix wrong mmc sample phase shift for rk3328
+    - clk: rockchip: Fix static checker warning in rockchip_ddrclk_get_parent call
+    - libceph: bump CEPH_MSG_MAX_DATA_LEN
+    - Revert "ceph: fix dentry leak in splice_dentry()"
+    - thermal: core: Fix use-after-free in thermal_cooling_device_destroy_sysfs
+    - mach64: fix display corruption on big endian machines
+    - mach64: fix image corruption due to reading accelerator registers
+    - acpi/nfit, x86/mce: Handle only uncorrectable machine checks
+    - acpi/nfit, x86/mce: Validate a MCE's address before using it
+    - acpi, nfit: Fix ARS overflow continuation
+    - reset: hisilicon: fix potential NULL pointer dereference
+    - crypto: hisilicon - Fix NULL dereference for same dst and src
+    - crypto: hisilicon - Fix reference after free of memories on error path
+    - vhost/scsi: truncate T10 PI iov_iter to prot_bytes
+    - scsi: qla2xxx: Initialize port speed to avoid setting lower speed
+    - SCSI: fix queue cleanup race before queue initialization is done
+    - Revert "powerpc/8xx: Use L1 entry APG to handle _PAGE_ACCESSED for
+      CONFIG_SWAP"
+    - soc: ti: QMSS: Fix usage of irq_set_affinity_hint
+    - ocfs2: fix a misuse a of brelse after failing ocfs2_check_dir_entry
+    - ocfs2: free up write context when direct IO failed
+    - mm: thp: relax __GFP_THISNODE for MADV_HUGEPAGE mappings
+    - memory_hotplug: cond_resched in __remove_pages
+    - netfilter: conntrack: fix calculation of next bucket number in early_drop
+    - ARM: 8809/1: proc-v7: fix Thumb annotation of cpu_v7_hvc_switch_mm
+    - bonding/802.3ad: fix link_failure_count tracking
+    - mtd: spi-nor: cadence-quadspi: Return error code in
+      cqspi_direct_read_execute()
+    - mtd: nand: Fix nanddev_neraseblocks()
+    - mtd: docg3: don't set conflicting BCH_CONST_PARAMS option
+    - hwmon: (core) Fix double-free in __hwmon_device_register()
+    - perf cs-etm: Correct CPU mode for samples
+    - perf stat: Handle different PMU names with common prefix
+    - perf callchain: Honour the ordering of PERF_CONTEXT_{USER,KERNEL,etc}
+    - perf intel-pt/bts: Calculate cpumode for synthesized samples
+    - perf intel-pt: Insert callchain context into synthesized callchains
+    - of, numa: Validate some distance map rules
+    - x86/cpu/vmware: Do not trace vmware_sched_clock()
+    - x86/hyper-v: Enable PIT shutdown quirk
+    - termios, tty/tty_baudrate.c: fix buffer overrun
+    - arch/alpha, termios: implement BOTHER, IBSHIFT and termios2
+    - watchdog/core: Add missing prototypes for weak functions
+    - btrfs: fix pinned underflow after transaction aborted
+    - Btrfs: fix missing data checksums after a ranged fsync (msync)
+    - Btrfs: fix cur_offset in the error case for nocow
+    - Btrfs: fix infinite loop on inode eviction after deduplication of eof block
+    - Btrfs: fix data corruption due to cloning of eof block
+    - btrfs: tree-checker: Fix misleading group system information
+    - 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: missing !bh check in ext4_xattr_inode_write()
+    - ext4: fix possible inode leak in the retry loop of ext4_resize_fs()
+    - ext4: avoid buffer leak on shutdown in ext4_mark_iloc_dirty()
+    - 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: fix possible leak of s_journal_flag_rwsem in error path
+    - ext4: fix buffer leak in ext4_xattr_get_block() on 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_expand_extra_isize_ea() on error path
+    - ext4: fix buffer leak in __ext4_read_dirblock() on error path
+    - mount: Prevent MNT_DETACH from disconnecting locked mounts
+    - mnt: fix __detach_mounts infinite loop
+    - uapi: fix linux/kfd_ioctl.h userspace compilation errors
+    - ARM: cpuidle: Don't register the driver when back-end init returns -ENXIO
+    - kdb: use correct pointer when 'btc' calls 'btt'
+    - kdb: print real address of pointers instead of hashed addresses
+    - sunrpc: correct the computation for page_ptr when truncating
+    - NFSv4: Don't exit the state manager without clearing
+      NFS4CLNT_MANAGER_RUNNING
+    - nfsd: COPY and CLONE operations require the saved filehandle to be set
+    - rtc: hctosys: Add missing range error reporting
+    - fuse: fix use-after-free in fuse_direct_IO()
+    - fuse: fix leaked notify reply
+    - fuse: fix possibly missed wake-up after abort
+    - selinux: check length properly in SCTP bind hook
+    - gfs2: Put bitmap buffers in put_super
+    - gfs2: Fix metadata read-ahead during truncate (2)
+    - libata: blacklist SAMSUNG MZ7TD256HAFV-000L9 SSD
+    - crypto: user - fix leaking uninitialized memory to userspace
+    - lib/ubsan.c: don't mark __ubsan_handle_builtin_unreachable as noreturn
+    - hugetlbfs: fix kernel BUG at fs/hugetlbfs/inode.c:444!
+    - mm/swapfile.c: use kvzalloc for swap_info_struct allocation
+    - efi/arm/libstub: Pack FDT after populating it
+    - mm: don't reclaim inodes with many attached pages
+    - scripts/spdxcheck.py: make python3 compliant
+    - drm/rockchip: Allow driver to be shutdown on reboot/kexec
+    - drm/amdgpu: Fix typo in amdgpu_vmid_mgr_init
+    - drm/amdgpu: add missing CHIP_HAINAN in amdgpu_ucode_get_load_type
+    - drm/amdgpu: Suppress keypresses from ACPI_VIDEO events
+    - drm/nouveau: Check backlight IDs are >= 0, not > 0
+    - drm/nouveau: Fix nv50_mstc->best_encoder()
+    - drm/amd/powerplay: Enable/Disable NBPSTATE on On/OFF of UVD
+    - drm/etnaviv: fix bogus fence complete check in timeout handler
+    - drm/dp_mst: Check if primary mstb is null
+    - drm: panel-orientation-quirks: Add quirk for Acer One 10 (S1003)
+    - drm/i915/dp: Link train Fallback on eDP only if fallback link BW can fit
+      panel's native mode
+    - drm/i915: Use the correct crtc when sanitizing plane mapping
+    - drm/i915: Restore vblank interrupts earlier
+    - drm/i915: Don't unset intel_connector->mst_port
+    - drm/i915: Skip vcpi allocation for MSTB ports that are gone
+    - drm/i915: Large page offsets for pread/pwrite
+    - drm/i915/dp: Fix link retraining comment in intel_dp_long_pulse()
+    - drm/i915/dp: Restrict link retrain workaround to external monitors
+    - drm/i915/icl: Fix the macros for DFLEXDPMLE register bits
+    - drm/i915/hdmi: Add HDMI 2.0 audio clock recovery N values
+    - drm/i915: Mark up GTT sizes as u64
+    - drm/i915: Fix error handling for the NV12 fb dimensions check
+    - drm/i915: Fix ilk+ watermarks when disabling pipes
+    - drm/i915: Compare user's 64b GTT offset even on 32b
+    - drm/i915: Don't oops during modeset shutdown after lpe audio deinit
+    - drm/i915: Mark pin flags as u64
+    - drm/i915/ringbuffer: Delay after EMIT_INVALIDATE for gen4/gen5
+    - drm/i915/execlists: Force write serialisation into context image vs
+      execution
+    - drm/i915: Fix possible race in intel_dp_add_mst_connector()
+    - drm/i915: Fix NULL deref when re-enabling HPD IRQs on systems with MST
+    - drm/i915: Fix hpd handling for pins with two encoders
+    - CONFIG_XEN_PV breaks xen_create_contiguous_region on ARM
+    - Revert "ACPICA: AML interpreter: add region addresses in global list during
+      initialization"
+    - Linux 4.19.3
+
+  * glibc 2.28-0ubuntu1 ADT test failure with linux 4.19.0-5.6 (LP: #1805154)
+    - SAUCE: Revert "x86: vdso: Use $LD instead of $CC to link"
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.12-1ubuntu1, zfs to 0.7.12-1ubuntu1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 26 Nov 2018 11:44:00 -0600
+
+linux (4.19.0-5.6) disco; urgency=medium
+
+  * crash in ENA driver on removing an interface (LP: #1802341)
+    - SAUCE: net: ena: fix crash during ena_remove()
+
+  * Ubuntu 18.04.1 - [s390x] Kernel panic while stressing network bonding
+    (LP: #1797367)
+    - s390/qeth: sanitize strings in debug messages
+
+  * Disco update: 4.19.2 upstream stable release (LP: #1803410)
+    - bpf: fix partial copy of map_ptr when dst is scalar
+    - MIPS: VDSO: Reduce VDSO_RANDOMIZE_SIZE to 64MB for 64bit
+    - gpio: mxs: Get rid of external API call
+    - mtd: rawnand: marvell: fix the IRQ handler complete() condition
+    - mtd: maps: gpio-addr-flash: Fix ioremapped size
+    - mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
+    - mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash
+    - mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus
+    - spi: spi-mem: Adjust op len based on message/transfer size limitations
+    - spi: bcm-qspi: switch back to reading flash using smaller chunks
+    - spi: bcm-qspi: fix calculation of address length
+    - bcache: trace missed reading by cache_missed
+    - bcache: fix ioctl in flash device
+    - bcache: correct dirty data statistics
+    - bcache: fix miss key refill->end in writeback
+    - hwmon: (pmbus) Fix page count auto-detection.
+    - jffs2: free jffs2_sb_info through jffs2_kill_sb()
+    - block: setup bounce bio_sets properly
+    - block: make sure discard bio is aligned with logical block size
+    - block: make sure writesame bio is aligned with logical block size
+    - cpufreq: conservative: Take limits changes into account properly
+    - dma-mapping: fix panic caused by passing empty cma command line argument
+    - pcmcia: Implement CLKRUN protocol disabling for Ricoh bridges
+    - ACPI / OSL: Use 'jiffies' as the time bassis for acpi_os_get_timer()
+    - ACPICA: AML interpreter: add region addresses in global list during
+      initialization
+    - ACPICA: AML Parser: fix parse loop to correctly skip erroneous extended
+      opcodes
+    - acpi, nfit: Fix Address Range Scrub completion tracking
+    - kprobes/x86: Use preempt_enable() in optimized_callback()
+    - mailbox: PCC: handle parse error
+    - parisc: Fix address in HPMC IVA
+    - parisc: Fix map_pages() to not overwrite existing pte entries
+    - parisc: Fix exported address of os_hpmc handler
+    - ALSA: hda - Add quirk for ASUS G751 laptop
+    - ALSA: hda - Fix headphone pin config for ASUS G751
+    - ALSA: hda - Add mic quirk for the Lenovo G50-30 (17aa:3905)
+    - ALSA: hda: Add 2 more models to the power_save blacklist
+    - ALSA: ca0106: Disable IZD on SB0570 DAC to fix audio pops
+    - ALSA: hda - Fix incorrect clearance of thinkpad_acpi hooks
+    - x86/speculation: Enable cross-hyperthread spectre v2 STIBP mitigation
+    - x86/xen: Fix boot loader version reported for PVH guests
+    - x86/corruption-check: Fix panic in memory_corruption_check() when boot
+      option without value is provided
+    - x86/kvm/nVMX: allow bare VMXON state migration
+    - x86/mm/pat: Disable preemption around __flush_tlb_all()
+    - x86/numa_emulation: Fix uniform-split numa emulation
+    - ARM: dts: exynos: Disable pull control for MAX8997 interrupts on Origen
+    - net: socionext: Reset tx queue in ndo_stop
+    - net: loopback: clear skb->tstamp before netif_rx()
+    - locking/lockdep: Fix debug_locks off performance problem
+    - netfilter: xt_nat: fix DNAT target for shifted portmap ranges
+    - ataflop: fix error handling during setup
+    - swim: fix cleanup on setup error
+    - arm64: cpufeature: ctr: Fix cpu capability check for late CPUs
+    - hv_netvsc: fix vf serial matching with pci slot info
+    - nfp: devlink port split support for 1x100G CXP NIC
+    - tun: Consistently configure generic netdev params via rtnetlink
+    - s390/sthyi: Fix machine name validity indication
+    - hwmon: (pwm-fan) Set fan speed to 0 on suspend
+    - lightnvm: pblk: fix race on sysfs line state
+    - lightnvm: pblk: fix two sleep-in-atomic-context bugs
+    - lightnvm: pblk: fix race condition on metadata I/O
+    - spi: spi-ep93xx: Use dma_data_direction for ep93xx_spi_dma_{finish,prepare}
+    - perf tools: Free temporary 'sys' string in read_event_files()
+    - perf tools: Cleanup trace-event-info 'tdata' leak
+    - perf tools: Free 'printk' string in parse_ftrace_printk()
+    - perf strbuf: Match va_{add,copy} with va_end
+    - cpupower: Fix coredump on VMWare
+    - bcache: Populate writeback_rate_minimum attribute
+    - mmc: sdhci-pci-o2micro: Add quirk for O2 Micro dev 0x8620 rev 0x01
+    - sdhci: acpi: add free_slot callback
+    - mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset
+    - iwlwifi: pcie: avoid empty free RB queue
+    - iwlwifi: mvm: clear HW_RESTART_REQUESTED when stopping the interface
+    - iwlwifi: mvm: check for n_profiles validity in EWRD ACPI
+    - x86/olpc: Indicate that legacy PC XO-1 platform should not register RTC
+    - wlcore: Fix BUG with clear completion on timeout
+    - ACPI/PPTT: Handle architecturally unknown cache types
+    - ACPI / PM: LPIT: Register sysfs attributes based on FADT
+    - ACPI / processor: Fix the return value of acpi_processor_ids_walk()
+    - cpufreq: dt: Try freeing static OPPs only if we have added them
+    - x86/intel_rdt: Show missing resctrl mount options
+    - mtd: rawnand: atmel: Fix potential NULL pointer dereference
+    - nvme: call nvme_complete_rq when nvmf_check_ready fails for mpath I/O
+    - ath10k: fix tx status flag setting for management frames
+    - signal: Introduce COMPAT_SIGMINSTKSZ for use in compat_sys_sigaltstack
+    - ice: fix changing of ring descriptor size (ethtool -G)
+    - ice: update fw version check logic
+    - net: hns3: Fix for packet buffer setting bug
+    - Bluetooth: btbcm: Add entry for BCM4335C0 UART bluetooth
+    - Bluetooth: hci_qca: Remove hdev dereference in qca_close().
+    - x86: boot: Fix EFI stub alignment
+    - net: hns3: Add nic state check before calling netif_tx_wake_queue
+    - net: hns3: Fix ets validate issue
+    - pinctrl: sunxi: fix 'pctrl->functions' allocation in
+      sunxi_pinctrl_build_state
+    - pinctrl: qcom: spmi-mpp: Fix err handling of pmic_mpp_set_mux
+    - brcmfmac: fix for proper support of 160MHz bandwidth
+    - net: hns3: Check hdev state when getting link status
+    - net: hns3: Set STATE_DOWN bit of hdev state when stopping net
+    - net: phy: phylink: ensure the carrier is off when starting phylink
+    - block, bfq: correctly charge and reset entity service in all cases
+    - arm64: entry: Allow handling of undefined instructions from EL1
+    - kprobes: Return error if we fail to reuse kprobe instead of BUG_ON()
+    - spi: gpio: No MISO does not imply no RX
+    - ACPI / LPSS: Add alternative ACPI HIDs for Cherry Trail DMA controllers
+    - pinctrl: qcom: spmi-mpp: Fix drive strength setting
+    - bpf/verifier: fix verifier instability
+    - failover: Add missing check to validate 'slave_dev' in
+      net_failover_slave_unregister
+    - perf tests: Fix record+probe_libc_inet_pton.sh without ping's debuginfo
+    - pinctrl: spmi-mpp: Fix pmic_mpp_config_get() to be compliant
+    - pinctrl: ssbi-gpio: Fix pm8xxx_pin_config_get() to be compliant
+    - net: hns3: Preserve vlan 0 in hardware table
+    - net: hns3: Fix ping exited problem when doing lp selftest
+    - net: hns3: Fix for vf vlan delete failed problem
+    - net: dsa: mv88e6xxx: Fix writing to a PHY page.
+    - mt76x2u: run device cleanup routine if resume fails
+    - rsi: fix memory alignment issue in ARM32 platforms
+    - libertas_tf: prevent underflow in process_cmdrequest()
+    - iwlwifi: mvm: fix BAR seq ctrl reporting
+    - gpio: brcmstb: allow 0 width GPIO banks
+    - ixgbe: disallow IPsec Tx offload when in SR-IOV mode
+    - ixgbevf: VF2VF TCP RSS
+    - wil6210: fix RX buffers release and unmap
+    - ath10k: schedule hardware restart if WMI command times out
+    - libata: Apply NOLPM quirk for SAMSUNG MZ7TD256HAFV-000L9
+    - thermal: rcar_thermal: Prevent doing work after unbind
+    - thermal: da9062/61: Prevent hardware access during system suspend
+    - cifs: fix a credits leak for compund commands
+    - cgroup, netclassid: add a preemption point to write_classid
+    - net: stmmac: dwmac-sun8i: fix OF child-node lookup
+    - f2fs: fix to account IO correctly for cgroup writeback
+    - MD: Memory leak when flush bio size is zero
+    - md: fix memleak for mempool
+    - of: Add missing exports of node name compare functions
+    - scsi: esp_scsi: Track residual for PIO transfers
+    - scsi: ufs: Schedule clk gating work on correct queue
+    - UAPI: ndctl: Fix g++-unsupported initialisation in headers
+    - KVM: nVMX: Clear reserved bits of #DB exit qualification
+    - scsi: megaraid_sas: fix a missing-check bug
+    - RDMA/core: Do not expose unsupported counters
+    - RDMA/cm: Respect returned status of cm_init_av_by_path
+    - IB/ipoib: Clear IPCB before icmp_send
+    - RDMA/bnxt_re: Avoid accessing nq->bar_reg_iomem in failure case
+    - RDMA/bnxt_re: Fix recursive lock warning in debug kernel
+    - usb: host: ohci-at91: fix request of irq for optional gpio
+    - PCI: mediatek: Fix mtk_pcie_find_port() endpoint/port matching logic
+    - PCI: cadence: Use AXI region 0 to signal interrupts from EP
+    - usb: typec: tcpm: Report back negotiated PPS voltage and current
+    - tpm: suppress transmit cmd error logs when TPM 1.2 is disabled/deactivated
+    - f2fs: clear PageError on the read path
+    - Drivers: hv: vmbus: Use cpumask_var_t for on-stack cpu mask
+    - VMCI: Resource wildcard match fixed
+    - PCI / ACPI: Enable wake automatically for power managed bridges
+    - xprtrdma: Reset credit grant properly after a disconnect
+    - irqchip/pdc: Setup all edge interrupts as rising edge at GIC
+    - usb: dwc2: fix call to vbus supply exit routine, call it unlocked
+    - usb: dwc2: fix a race with external vbus supply
+    - usb: gadget: udc: atmel: handle at91sam9rl PMC
+    - ext4: fix argument checking in EXT4_IOC_MOVE_EXT
+    - MD: fix invalid stored role for a disk
+    - PCI: cadence: Correct probe behaviour when failing to get PHY
+    - nvmem: check the return value of nvmem_add_cells()
+    - xhci: Avoid USB autosuspend when resuming USB2 ports.
+    - scsi: qla2xxx: Fix recursive mailbox timeout
+    - f2fs: fix to recover inode's crtime during POR
+    - f2fs: fix to recover inode's i_flags during POR
+    - PCI/MSI: Warn and return error if driver enables MSI/MSI-X twice
+    - coresight: etb10: Fix handling of perf mode
+    - PCI: dwc: pci-dra7xx: Enable errata i870 for both EP and RC mode
+    - crypto: caam - fix implicit casts in endianness helpers
+    - usb: chipidea: Prevent unbalanced IRQ disable
+    - Smack: ptrace capability use fixes
+    - driver/dma/ioat: Call del_timer_sync() without holding prep_lock
+    - ASoC: AMD: Fix capture unstable in beginning for some runs
+    - firmware: coreboot: Unmap ioregion after device population
+    - IB/ipoib: Use dev_port to expose network interface port numbers
+    - IB/mlx5: Allow transition of DCI QP to reset
+    - uio: ensure class is registered before devices
+    - scsi: lpfc: Correct soft lockup when running mds diagnostics
+    - scsi: lpfc: Correct race with abort on completion path
+    - f2fs: avoid sleeping under spin_lock
+    - f2fs: report error if quota off error during umount
+    - signal: Always deliver the kernel's SIGKILL and SIGSTOP to a pid namespace
+      init
+    - f2fs: fix to flush all dirty inodes recovered in readonly fs
+    - mfd: menelaus: Fix possible race condition and leak
+    - dmaengine: dma-jz4780: Return error if not probed from DT
+    - IB/rxe: fix for duplicate request processing and ack psns
+    - ALSA: hda: Check the non-cached stream buffers more explicitly
+    - cpupower: Fix AMD Family 0x17 msr_pstate size
+    - Revert "f2fs: fix to clear PG_checked flag in set_page_dirty()"
+    - f2fs: fix missing up_read
+    - f2fs: fix to recover cold bit of inode block during POR
+    - f2fs: fix to account IO correctly
+    - OPP: Free OPP table properly on performance state irregularities
+    - ARM: dts: exynos: Convert exynos5250.dtsi to opp-v2 bindings
+    - ARM: dts: exynos: Mark 1 GHz CPU OPP as suspend OPP on Exynos5250
+    - xen-swiotlb: use actually allocated size on check physical continuous
+    - tpm: Restore functionality to xen vtpm driver.
+    - xen/blkfront: avoid NULL blkfront_info dereference on device removal
+    - xen/balloon: Support xend-based toolstack
+    - xen: fix race in xen_qlock_wait()
+    - xen: make xen_qlock_wait() nestable
+    - xen/pvh: increase early stack size
+    - xen/pvh: don't try to unplug emulated devices
+    - libertas: don't set URB_ZERO_PACKET on IN USB transfer
+    - usbip:vudc: BUG kmalloc-2048 (Not tainted): Poison overwritten
+    - usb: typec: tcpm: Fix APDO PPS order checking to be based on voltage
+    - usb: gadget: udc: renesas_usb3: Fix b-device mode for "workaround"
+    - mt76: mt76x2: fix multi-interface beacon configuration
+    - iwlwifi: mvm: check return value of rs_rate_from_ucode_rate()
+    - net/ipv4: defensive cipso option parsing
+    - dmaengine: ppc4xx: fix off-by-one build failure
+    - scsi: sched/wait: Add wait_event_lock_irq_timeout for TASK_UNINTERRUPTIBLE
+      usage
+    - scsi: target: Fix target_wait_for_sess_cmds breakage with active signals
+    - libnvdimm: Hold reference on parent while scheduling async init
+    - libnvdimm, region: Fail badblocks listing for inactive regions
+    - libnvdimm, pmem: Fix badblocks population for 'raw' namespaces
+    - ASoC: intel: skylake: Add missing break in skl_tplg_get_token()
+    - ASoC: sta32x: set ->component pointer in private struct
+    - IB/mlx5: Fix MR cache initialization
+    - IB/rxe: Revise the ib_wr_opcode enum
+    - jbd2: fix use after free in jbd2_log_do_checkpoint()
+    - gfs2_meta: ->mount() can get NULL dev_name
+    - ext4: fix EXT4_IOC_SWAP_BOOT
+    - ext4: initialize retries variable in ext4_da_write_inline_data_begin()
+    - ext4: fix setattr project check in fssetxattr ioctl
+    - ext4: propagate error from dquot_initialize() in EXT4_IOC_FSSETXATTR
+    - ext4: fix use-after-free race in ext4_remount()'s error path
+    - selinux: fix mounting of cgroup2 under older policies
+    - HID: wacom: Work around HID descriptor bug in DTK-2451 and DTH-2452
+    - HID: hiddev: fix potential Spectre v1
+    - EDAC, amd64: Add Family 17h, models 10h-2fh support
+    - EDAC, {i7core,sb,skx}_edac: Fix uncorrected error counting
+    - EDAC, skx_edac: Fix logical channel intermediate decoding
+    - ARM: dts: dra7: Fix up unaligned access setting for PCIe EP
+    - PCI/ASPM: Fix link_state teardown on device removal
+    - PCI: Add Device IDs for Intel GPU "spurious interrupt" quirk
+    - signal/GenWQE: Fix sending of SIGKILL
+    - signal: Guard against negative signal numbers in copy_siginfo_from_user32
+    - crypto: lrw - Fix out-of bounds access on counter overflow
+    - crypto: tcrypt - fix ghash-generic speed test
+    - crypto: aesni - don't use GFP_ATOMIC allocation if the request doesn't cross
+      a page in gcm
+    - crypto: morus/generic - fix for big endian systems
+    - crypto: aegis/generic - fix for big endian systems
+    - crypto: speck - remove Speck
+    - mm: /proc/pid/smaps_rollup: fix NULL pointer deref in smaps_pte_range()
+    - userfaultfd: disable irqs when taking the waitqueue lock
+    - ima: fix showing large 'violations' or 'runtime_measurements_count'
+    - ima: open a new file instance if no read permissions
+    - hugetlbfs: dirty pages as they are added to pagecache
+    - mm/rmap: map_pte() was not handling private ZONE_DEVICE page properly
+    - mm/hmm: fix race between hmm_mirror_unregister() and mmu_notifier callback
+    - KVM: arm/arm64: Ensure only THP is candidate for adjustment
+    - KVM: arm64: Fix caching of host MDCR_EL2 value
+    - kbuild: fix kernel/bounds.c 'W=1' warning
+    - iio: ad5064: Fix regulator handling
+    - iio: adc: imx25-gcq: Fix leak of device_node in mx25_gcq_setup_cfgs()
+    - 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
+    - tpm: fix response size validation in tpm_get_random()
+    - NFC: nfcmrvl_uart: fix OF child-node lookup
+    - NFSv4.1: Fix the r/wsize checking
+    - nfs: Fix a missed page unlock after pg_doio()
+    - nfsd: correctly decrement odstate refcount in error path
+    - 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
+    - dm zoned: fix metadata block ref counting
+    - dm zoned: fix various dmz_get_mblock() issues
+    - media: ov7670: make "xclk" clock optional
+    - fsnotify: Fix busy inodes during unmount
+    - powerpc64/module elfv1: Set opd addresses after module relocation
+    - powerpc/msi: Fix compile error on mpc83xx
+    - powerpc/tm: Fix HFSCR bit for no suspend case
+    - powerpc/64s/hash: Do not use PPC_INVALIDATE_ERAT on CPUs before POWER9
+    - MIPS: OCTEON: fix out of bounds array access on CN68XX
+    - rtc: ds1307: fix ds1339 wakealarm support
+    - rtc: cmos: Fix non-ACPI undefined reference to `hpet_rtc_interrupt'
+    - rtc: cmos: Remove the `use_acpi_alarm' module parameter for !ACPI
+    - power: supply: twl4030-charger: fix OF sibling-node lookup
+    - ocxl: Fix access to the AFU Descriptor Data
+    - iommu/arm-smmu: Ensure that page-table updates are visible before TLBI
+    - TC: Set DMA masks for devices
+    - net: bcmgenet: fix OF child-node lookup
+    - media: v4l2-tpg: fix kernel oops when enabling HFLIP and OSD
+    - Revert "media: dvbsky: use just one mutex for serializing device R/W ops"
+    - kgdboc: Passing ekgdboc to command line causes panic
+    - remoteproc: qcom: q6v5: Propagate EPROBE_DEFER
+    - media: cec: make cec_get_edid_spa_location() an inline function
+    - media: cec: integrate cec_validate_phys_addr() in cec-api.c
+    - xen: fix xen_qlock_wait()
+    - xen: remove size limit of privcmd-buf mapping interface
+    - xen-blkfront: fix kernel panic with negotiate_mq error path
+    - media: cec: add new tx/rx status bits to detect aborts/timeouts
+    - media: cec: fix the Signal Free Time calculation
+    - media: cec: forgot to cancel delayed work
+    - media: em28xx: use a default format if TRY_FMT fails
+    - media: tvp5150: avoid going past array on v4l2_querymenu()
+    - media: em28xx: fix input name for Terratec AV 350
+    - media: em28xx: make v4l2-compliance happier by starting sequence on zero
+    - media: em28xx: fix handler for vidioc_s_input()
+    - media: adv7604: when the EDID is cleared, unconfigure CEC as well
+    - media: adv7842: when the EDID is cleared, unconfigure CEC as well
+    - drm/mediatek: fix OF sibling-node lookup
+    - media: media colorspaces*.rst: rename AdobeRGB to opRGB
+    - media: replace ADOBERGB by OPRGB
+    - media: hdmi.h: rename ADOBE_RGB to OPRGB and ADOBE_YCC to OPYCC
+    - arm64: lse: remove -fcall-used-x0 flag
+    - rpmsg: smd: fix memory leak on channel create
+    - Cramfs: fix abad comparison when wrap-arounds occur
+    - ARM: dts: socfpga: Fix SDRAM node address for Arria10
+    - arm64: dts: stratix10: Correct System Manager register size
+    - soc: qcom: rmtfs-mem: Validate that scm is available
+    - soc/tegra: pmc: Fix child-node lookup
+    - selftests/ftrace: Fix synthetic event test to delete event correctly
+    - selftests/powerpc: Fix ptrace tm failure
+    - tracing: Return -ENOENT if there is no target synthetic event
+    - btrfs: qgroup: Avoid calling qgroup functions if qgroup is not enabled
+    - btrfs: Handle owner mismatch gracefully when walking up tree
+    - btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock
+    - btrfs: fix error handling in free_log_tree
+    - btrfs: fix error handling in btrfs_dev_replace_start
+    - btrfs: Enhance btrfs_trim_fs function to handle error better
+    - btrfs: Ensure btrfs_trim_fs can trim the whole filesystem
+    - 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: keep trim from interfering with transaction commits
+    - btrfs: wait on caching when putting the bg cache
+    - Btrfs: don't clean dirty pages during buffered writes
+    - btrfs: release metadata before running delayed refs
+    - btrfs: protect space cache inode alloc with GFP_NOFS
+    - btrfs: reset max_extent_size on clear in a bitmap
+    - btrfs: make sure we create all new block groups
+    - Btrfs: fix warning when replaying log after fsync of a tmpfile
+    - 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: fix assertion on fsync of regular file when using no-holes feature
+    - Btrfs: fix deadlock when writing out free space caches
+    - btrfs: reset max_extent_size properly
+    - btrfs: set max_extent_size properly
+    - btrfs: don't use ctl->free_space for max_extent_size
+    - btrfs: only free reserved extent if we didn't insert it
+    - btrfs: fix insert_reserved error handling
+    - btrfs: don't run delayed_iputs in commit
+    - btrfs: move the dio_sem higher up the callchain
+    - Btrfs: fix use-after-free during inode eviction
+    - Btrfs: fix use-after-free when dumping free space
+    - net: sched: Remove TCA_OPTIONS from policy
+    - vt: fix broken display when running aptitude
+    - bpf: wait for running BPF programs when updating map-in-map
+    - vga_switcheroo: Fix missing gpu_bound call at audio client registration
+    - MD: fix invalid stored role for a disk - try2
+    - Linux 4.19.2
+
+  * [FEAT] Guest-dedicated Crypto Adapters (LP: #1787405)
+    - KVM: s390: vsie: simulate VCPU SIE entry/exit
+    - KVM: s390: introduce and use KVM_REQ_VSIE_RESTART
+    - KVM: s390: refactor crypto initialization
+    - s390: vfio-ap: base implementation of VFIO AP device driver
+    - s390: vfio-ap: register matrix device with VFIO mdev framework
+    - s390: vfio-ap: sysfs interfaces to configure adapters
+    - s390: vfio-ap: sysfs interfaces to configure domains
+    - s390: vfio-ap: sysfs interfaces to configure control domains
+    - s390: vfio-ap: sysfs interface to view matrix mdev matrix
+    - KVM: s390: interface to clear CRYCB masks
+    - s390: vfio-ap: implement mediated device open callback
+    - s390: vfio-ap: implement VFIO_DEVICE_GET_INFO ioctl
+    - s390: vfio-ap: zeroize the AP queues
+    - s390: vfio-ap: implement VFIO_DEVICE_RESET ioctl
+    - KVM: s390: Clear Crypto Control Block when using vSIE
+    - KVM: s390: vsie: Do the CRYCB validation first
+    - KVM: s390: vsie: Make use of CRYCB FORMAT2 clear
+    - KVM: s390: vsie: Allow CRYCB FORMAT-2
+    - KVM: s390: vsie: allow CRYCB FORMAT-1
+    - KVM: s390: vsie: allow CRYCB FORMAT-0
+    - KVM: s390: vsie: allow guest FORMAT-0 CRYCB on host FORMAT-1
+    - KVM: s390: vsie: allow guest FORMAT-1 CRYCB on host FORMAT-2
+    - KVM: s390: vsie: allow guest FORMAT-0 CRYCB on host FORMAT-2
+    - KVM: s390: device attrs to enable/disable AP interpretation
+    - KVM: s390: CPU model support for AP virtualization
+    - s390: doc: detailed specifications for AP virtualization
+    - KVM: s390: fix locking for crypto setting error path
+    - KVM: s390: Tracing APCB changes
+    - s390: vfio-ap: setup APCB mask using KVM dedicated function
+    - [Config:] Enable CONFIG_S390_AP_IOMMU and set CONFIG_VFIO_AP to module.
+
+  * 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
+
+  *  CVE-2018-18955: nested user namespaces with more than five extents
+    incorrectly grant privileges over inode (LP: #1801924) // CVE-2018-18955
+    - userns: also map extents in the reverse map to kernel IDs
+
+  * 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
+
+  * Disable LPM for Raydium Touchscreens (LP: #1802248)
+    - USB: quirks: Add no-lpm quirk for Raydium touchscreens
+
+  * Power consumption during s2idle is higher than long idle(sk hynix)
+    (LP: #1801875)
+    - SAUCE: pci: prevent sk hynix nvme from entering D3
+    - SAUCE: nvme: add quirk to not call disable function when suspending
+
+  * Disco update: v4.19.1 upstream stable release (LP: #1801739)
+    - bridge: do not add port to router list when receives query with source
+      0.0.0.0
+    - ipv6/ndisc: Preserve IPv6 control buffer if protocol error handlers are
+      called
+    - net/mlx5e: fix csum adjustments caused by RXFCS
+    - net: sched: gred: pass the right attribute to gred_change_table_def()
+    - net: stmmac: Fix stmmac_mdio_reset() when building stmmac as modules
+    - net: udp: fix handling of CHECKSUM_COMPLETE packets
+    - Revert "net: simplify sock_poll_wait"
+    - rtnetlink: Disallow FDB configuration for non-Ethernet device
+    - vhost: Fix Spectre V1 vulnerability
+    - bonding: fix length of actor system
+    - openvswitch: Fix push/pop ethernet validation
+    - net/ipv6: Allow onlink routes to have a device mismatch if it is the default
+      route
+    - net/smc: fix smc_buf_unuse to use the lgr pointer
+    - mlxsw: spectrum_switchdev: Don't ignore deletions of learned MACs
+    - mlxsw: core: Fix devlink unregister flow
+    - net: drop skb on failure in ip_check_defrag()
+    - net: Properly unlink GRO packets on overflow.
+    - r8169: fix broken Wake-on-LAN from S5 (poweroff)
+    - Revert "be2net: remove desc field from be_eq_obj"
+    - sctp: check policy more carefully when getting pr status
+    - sparc64: Export __node_distance.
+    - sparc64: Make corrupted user stacks more debuggable.
+    - sparc64: Wire up compat getpeername and getsockname.
+    - net: bridge: remove ipv6 zero address check in mcast queries
+    - Linux 4.19.1
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.11-1ubuntu1, zfs to 0.7.11-3ubuntu1
+    - [Config] updateconfigs after 4.19.2 stable update
+    - [Config] Disable unneded options for s390
+    - [Config] Update annotations for 4.19
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 15 Nov 2018 09:55:37 -0800
+
+linux (4.19.0-4.5) disco; urgency=medium
+
+  * Add checksum offload and TSO support for HiNIC adapters (LP: #1800664)
+    - net-next/hinic: add checksum offload and TSO support
+
+  * [Bionic][Cosmic] Fix to ipmi to support vendor specific messages greater
+    than 255 bytes (LP: #1799794)
+    - ipmi:ssif: Add support for multi-part transmit messages > 2 parts
+
+  * Packaging resync (LP: #1786013)
+    - [Package] add support for specifying the primary makefile
+
+  * Update ENA driver to version 2.0.1K (LP: #1798182)
+    - 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
+
+  * [Bionic][Cosmic]  ipmi: Fix timer race with module unload (LP: #1799281)
+    - ipmi: Fix timer race with module unload
+
+  * Overlayfs in user namespace leaks directory content of inaccessible
+    directories (LP: #1793458) // CVE-2018-6559
+    - SAUCE: overlayfs: ensure mounter privileges when reading directories
+
+  * not able to unwind the stack from within __kernel_clock_gettime in the Linux
+    vDSO (LP: #1797963)
+    - powerpc/vdso: Correct call frame information
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Don't print secure boot state
+      from the efi stub"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Make get_cert_list() use
+      efi_status_to_str() to print error messages."
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err()."
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Make get_cert_list() not complain
+      about cert lists that aren't present."
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable
+      to be suppressed"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI
+      Secure Boot"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Add an EFI signature blob parser"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Add EFI signature data types"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time
+      addition of keys to secondary keyring"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in
+      secure boot mode"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to
+      indicate secure boot mode"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Copy secure_boot flag in boot params
+      across kexec reboot"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Lock down perf"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) bpf: Restrict kernel image access
+      functions when the kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Lock down kprobes"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Lock down /proc/kcore"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the
+      testmmiotrace module"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Lock down module params that specify
+      hardware parameters (eg. ioport)"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Lock down TIOCSSERIAL"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) acpi: Disable APEI error injection if
+      the kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) acpi: Disable ACPI table override if
+      the kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param
+      when the kernel has been locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) ACPI: Limit access to custom_method
+      when the kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) x86: Lock down IO port access when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) PCI: Lock down BAR access when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is
+      locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) hibernate: Disable when the kernel is
+      locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Enforce module signatures if the
+      kernel is locked down"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Add a SysRq option to lift kernel
+      lockdown"
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) Add the ability to lock down access to
+      the running kernel image"
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time addition of keys to
+      secondary keyring
+    - SAUCE: (efi-lockdown) efi: Add EFI signature data types
+    - SAUCE: (efi-lockdown) efi: Add an EFI signature blob parser
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable to be suppressed
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) efi/x86: Call efi_parse_options() from efi_main()
+    - SAUCE: (efi-lockdown) Fix for module sig verification
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) module: remove support for having IMA validate modules
+    - [Packaging] generate Vcs-Git url from changelog
+    - [Config] CONFIG_SCSI_MQ_DEFAULT=y
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 02 Nov 2018 14:22:55 -0500
+
+linux (4.19.0-3.4) cosmic; urgency=medium
+
+  * Support Edge Gateway's Bluetooth LED (LP: #1798332)
+    - SAUCE: Bluetooth: Support for LED on Edge Gateways
+
+  * Support Edge Gateway's WIFI LED (LP: #1798330)
+    - SAUCE: mwifiex: Switch WiFi LED state according to the device status
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.19
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 22 Oct 2018 09:13:39 -0500
+
+linux (4.19.0-2.3) cosmic; urgency=medium
+
+  * fscache: bad refcounting in fscache_op_complete leads to OOPS (LP: #1797314)
+    - SAUCE: fscache: Fix race in decrementing refcount of op->npages
+
+  * Provide mode where all vCPUs on a core must be the same VM (LP: #1792957)
+    - KVM: PPC: Book3S HV: Provide mode where all vCPUs on a core must be the same
+      VM
+
+  * The front MIC can't work on the Lenovo M715 (LP: #1797292)
+    - ALSA: hda/realtek - Fix the problem of the front MIC on the Lenovo M715
+
+  * arm64: snapdragon: WARNING: CPU: 0 PID: 1 at drivers/irqchip/irq-gic.c:1016
+    gic_irq_domain_translate (LP: #1797143)
+    - SAUCE: arm64: dts: msm8916: camms: fix gic_irq_domain_translate warnings
+
+  * Dell new AIO requires a new uart backlight driver (LP: #1727235)
+    - SAUCE: platform/x86: dell-uart-backlight: new backlight driver for DELL AIO
+    - updateconfigs for Dell UART backlight driver
+
+  * Please make CONFIG_PWM_LPSS_PCI and CONFIG_PWM_LPSS_PLATFORM built in to
+    make brightness adjustment working on various BayTrail/CherryTrail-based
+    devices (LP: #1783964)
+    - [Config]: Make PWM_LPSS_* built-in
+
+  * check and fix zkey required kernel modules locations in debs, udebs, and
+    initramfs (LP: #1794346)
+    - [Config] add s390 crypto modules to crypt-modules udeb
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_VBOXGUEST=n
+    - ubuntu: vbox -- update to 5.2.18-dfsg-2
+    - ubuntu: enable vbox build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.19-rc8
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 15 Oct 2018 10:52:04 -0500
+
+linux (4.19.0-1.2) cosmic; urgency=medium
+
+  * 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
+
+  * SRU: Enable middle button of touchpad on ThinkPad P72 (LP: #1793463)
+    - Input: elantech - enable middle button of touchpad on ThinkPad P72
+
+  * Improvements to the kernel source package preparation (LP: #1793461)
+    - [Packaging] startnewrelease: add support for backport kernels
+
+  * Fix unusable NVIDIA GPU after S3 (LP: #1793338)
+    - SAUCE: PCI: Reprogram bridge prefetch registers on resume
+
+  * Error reported when creating ZFS pool with "-t" option, despite successful
+    pool creation (LP: #1769937)
+    - SAUCE: (noup) Update zfs to 0.7.9-3ubuntu6
+
+  * device hotplug of vfio devices can lead to deadlock in vfio_pci_release
+    (LP: #1792099)
+    - SAUCE: vfio -- release device lock before userspace requests
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] retpoline -- fix temporary filenaming
+    - CONFIG_BCH_CONST_PARAMS=n
+    - Packaging: final-checks: remove trailing backport suffix
+    - SAUCE: import aufs driver
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.19-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 25 Sep 2018 16:32:24 -0500
+
+linux (4.19.0-0.1) cosmic; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu -- disable vbox build
+    - Disable zfs build
+    - SAUCE: Import aufs driver
+    - Update dropped.txt
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.19-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 13 Sep 2018 07:54:47 -0500
+
+linux (4.19.0-0.0) cosmic; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 13 Sep 2018 06:44:09 -0500
+
+linux (4.18.0-8.9) cosmic; urgency=medium
+
+  * linux: 4.18.0-8.9 -proposed tracker (LP: #1791663)
+
+  * Cosmic update to v4.18.7 stable release (LP: #1791660)
+    - rcu: Make expedited GPs handle CPU 0 being offline
+    - 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
+    - spi: davinci: fix a NULL pointer dereference
+    - spi: pxa2xx: Add support for Intel Ice Lake
+    - spi: spi-fsl-dspi: Fix imprecise abort on VF500 during probe
+    - spi: cadence: Change usleep_range() to udelay(), for atomic context
+    - mmc: block: Fix unsupported parallel dispatch of requests
+    - mmc: renesas_sdhi_internal_dmac: mask DMAC interrupts
+    - mmc: renesas_sdhi_internal_dmac: fix #define RST_RESERVED_BITS
+    - readahead: stricter check for bdi io_pages
+    - block: fix infinite loop if the device loses discard capability
+    - block: blk_init_allocated_queue() set q->fq as NULL in the fail case
+    - block: really disable runtime-pm for blk-mq
+    - blkcg: Introduce blkg_root_lookup()
+    - block: Introduce blk_exit_queue()
+    - block: Ensure that a request queue is dissociated from the cgroup controller
+    - apparmor: fix bad debug check in apparmor_secid_to_secctx()
+    - dma-buf: Move BUG_ON from _add_shared_fence to _add_shared_inplace
+    - libertas: fix suspend and resume for SDIO connected cards
+    - media: Revert "[media] tvp5150: fix pad format frame height"
+    - mailbox: xgene-slimpro: Fix potential NULL pointer dereference
+    - Replace magic for trusting the secondary keyring with #define
+    - Fix kexec forbidding kernels signed with keys in the secondary keyring to
+      boot
+    - powerpc/fadump: handle crash memory ranges array index overflow
+    - powerpc/64s: Fix page table fragment refcount race vs speculative references
+    - powerpc/pseries: Fix endianness while restoring of r3 in MCE handler.
+    - powerpc/pkeys: Give all threads control of their key permissions
+    - powerpc/pkeys: Deny read/write/execute by default
+    - powerpc/pkeys: key allocation/deallocation must not change pkey registers
+    - powerpc/pkeys: Save the pkey registers before fork
+    - powerpc/pkeys: Fix calculation of total pkeys.
+    - powerpc/pkeys: Preallocate execute-only key
+    - powerpc/nohash: fix pte_access_permitted()
+    - powerpc64/ftrace: Include ftrace.h needed for enable/disable calls
+    - powerpc/powernv/pci: Work around races in PCI bridge enabling
+    - cxl: Fix wrong comparison in cxl_adapter_context_get()
+    - IB/mlx5: Honor cnt_set_id_valid flag instead of set_id
+    - IB/mlx5: Fix leaking stack memory to userspace
+    - IB/srpt: Fix srpt_cm_req_recv() error path (1/2)
+    - IB/srpt: Fix srpt_cm_req_recv() error path (2/2)
+    - IB/srpt: Support HCAs with more than two ports
+    - overflow.h: Add arithmetic shift helper
+    - RDMA/mlx5: Fix shift overflow in mlx5_ib_create_wq
+    - ib_srpt: Fix a use-after-free in srpt_close_ch()
+    - ib_srpt: Fix a use-after-free in __srpt_close_all_ch()
+    - RDMA/rxe: Set wqe->status correctly if an unexpected response is received
+    - 9p: fix multiple NULL-pointer-dereferences
+    - 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 integrity: change 'suspending' variable from bool to int
+    - dm thin: stop no_space_timeout worker when switching to write-mode
+    - dm cache metadata: save in-core policy_hint_size to on-disk superblock
+    - dm cache metadata: set dirty on all cache blocks after a crash
+    - dm crypt: don't decrease device limits
+    - dm writecache: fix a crash due to reading past end of dirty_bitmap
+    - uart: fix race between uart_put_char() and uart_shutdown()
+    - Drivers: hv: vmbus: Fix the offer_in_progress in vmbus_process_offer()
+    - Drivers: hv: vmbus: Reset the channel callback in vmbus_onoffer_rescind()
+    - iio: sca3000: Fix missing return in switch
+    - iio: ad9523: Fix displayed phase
+    - iio: ad9523: Fix return value for ad952x_store()
+    - extcon: Release locking when sending the notification of connector state
+    - eventpoll.h: wrap casts in () properly
+    - 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
+    - rtc: omap: fix resource leak in registration error path
+    - rtc: omap: fix potential crash on power off
+    - tracing: Do not call start/stop() functions when tracing_on does not change
+    - tracing/blktrace: Fix to allow setting same value
+    - printk/tracing: Do not trace printk_nmi_enter()
+    - livepatch: Validate module/old func name length
+    - uprobes: Use synchronize_rcu() not synchronize_sched()
+    - mfd: hi655x: Fix regmap area declared size for hi655x
+    - ovl: fix wrong use of impure dir cache in ovl_iterate()
+    - ACPICA: AML Parser: skip opcodes that open a scope upon parse failure
+    - ACPICA: Clear status of all events when entering sleep states
+    - drivers/block/zram/zram_drv.c: fix bug storing backing_dev
+    - sched: idle: Avoid retaining the tick when it has been stopped
+    - cpuidle: menu: Handle stopped tick more aggressively
+    - cpufreq: governor: Avoid accessing invalid governor_data
+    - PM / sleep: wakeup: Fix build error caused by missing SRCU support
+    - ALSA: ac97: fix device initialization in the compat layer
+    - ALSA: ac97: fix check of pm_runtime_get_sync failure
+    - ALSA: ac97: fix unbalanced pm_runtime_enable
+    - i2c: designware: Re-init controllers with pm_disabled set on resume
+    - KVM: VMX: fixes for vmentry_l1d_flush module parameter
+    - KVM: PPC: Book3S: Fix guest DMA when guest partially backed by THP pages
+    - xtensa: limit offsets in __loop_cache_{all,page}
+    - xtensa: increase ranges in ___invalidate_{i,d}cache_all
+    - block, bfq: return nbytes and not zero from struct cftype .write() method
+    - pnfs/blocklayout: off by one in bl_map_stripe()
+    - nfsd: fix leaked file lock with nfs exported overlayfs
+    - NFSv4 client live hangs after live data migration recovery
+    - NFSv4: Fix locking in pnfs_generic_recover_commit_reqs
+    - NFSv4: Fix a sleep in atomic context in nfs4_callback_sequence()
+    - ARM: tegra: Fix Tegra30 Cardhu PCA954x reset
+    - ARM: dts: am57xx-idk: Enable dual role for USB2 port
+    - pwm: omap-dmtimer: Return -EPROBE_DEFER if no dmtimer platform data
+    - mm/tlb: Remove tlb_remove_table() non-concurrent condition
+    - iommu/ipmmu-vmsa: Don't register as BUS IOMMU if machine doesn't have IPMMU-
+      VMSA
+    - iommu/vt-d: Add definitions for PFSID
+    - iommu/vt-d: Fix dev iotlb pfsid use
+    - 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: xattr: Don't operate on deleted inodes
+    - ubifs: Fix directory size calculation for symlinks
+    - ubifs: Fix synced_i_size calculation for xattr inodes
+    - pwm: tiehrpwm: Don't use emulation mode bits to control PWM output
+    - pwm: tiehrpwm: Fix disabling of output of PWMs
+    - fb: fix lost console when the user unplugs a USB adapter
+    - udlfb: fix semaphore value leak
+    - udlfb: fix display corruption of the last line
+    - udlfb: don't switch if we are switching to the same videomode
+    - udlfb: set optimal write delay
+    - udlfb: make a local copy of fb_ops
+    - udlfb: handle allocation failure
+    - udlfb: set line_length in dlfb_ops_set_par
+    - getxattr: use correct xattr length
+    - libnvdimm: Use max contiguous area for namespace size
+    - libnvdimm: fix ars_status output length calculation
+    - bcache: release dc->writeback_lock properly in bch_writeback_thread()
+    - kconfig: fix "Can't open ..." in parallel build
+    - perf auxtrace: Fix queue resize
+    - crypto: vmx - Fix sleep-in-atomic bugs
+    - crypto: aesni - Use unaligned loads from gcm_context_data
+    - crypto: arm64/sm4-ce - check for the right CPU feature bit
+    - crypto: caam - fix DMA mapping direction for RSA forms 2 & 3
+    - crypto: caam/jr - fix descriptor DMA unmapping
+    - crypto: caam/qi - fix error path in xts setkey
+    - fs/quota: Fix spectre gadget in do_quotactl
+    - udf: Fix mounting of Win7 created UDF filesystems
+    - cpuidle: menu: Retain tick when shallow state is selected
+    - arm64: mm: always enable CONFIG_HOLES_IN_ZONE
+    - Linux 4.18.7
+
+  * CVE-2017-5715
+    - s390: detect etoken facility
+    - KVM: s390: add etoken support for guests
+
+  * Missing Intel GPU pci-id's (LP: #1789924)
+    - drm/i915/whl: Introducing Whiskey Lake platform
+    - drm/i915/aml: Introducing Amber Lake platform
+    - drm/i915/cfl: Add a new CFL PCI ID.
+
+  * [18.10 FEAT] Add kernel config options for SMC-R/D (LP: #1789934)
+    - s390/ism: add device driver for internal shared memory
+    - CONFIG_ISM=y for s390
+
+  * Cosmic update to v4.18.6 stable release (LP: #1791105)
+    - PATCH scripts/kernel-doc
+    - scripts/kernel-doc: Escape all literal braces in regexes
+    - scsi: libsas: dynamically allocate and free ata host
+    - xprtrdma: Fix disconnect regression
+    - mei: don't update offset in write
+    - cifs: add missing support for ACLs in SMB 3.11
+    - CIFS: fix uninitialized ptr deref in smb2 signing
+    - cifs: add missing debug entries for kconfig options
+    - cifs: use a refcount to protect open/closing the cached file handle
+    - cifs: check kmalloc before use
+    - smb3: enumerating snapshots was leaving part of the data off end
+    - smb3: Do not send SMB3 SET_INFO if nothing changed
+    - smb3: don't request leases in symlink creation and query
+    - smb3: fill in statfs fsid and correct namelen
+    - btrfs: use correct compare function of dirty_metadata_bytes
+    - btrfs: don't leak ret from do_chunk_alloc
+    - Btrfs: fix mount failure after fsync due to hard link recreation
+    - Btrfs: fix btrfs_write_inode vs delayed iput deadlock
+    - Btrfs: fix send failure when root has deleted files still open
+    - Btrfs: send, fix incorrect file layout after hole punching beyond eof
+    - hwmon: (k10temp) 27C Offset needed for Threadripper2
+    - bpf, arm32: fix stack var offset in jit
+    - regulator: arizona-ldo1: Use correct device to get enable GPIO
+    - iommu/arm-smmu: Error out only if not enough context interrupts
+    - printk: Split the code for storing a message into the log buffer
+    - printk: Create helper function to queue deferred console handling
+    - printk/nmi: Prevent deadlock when accessing the main log buffer in NMI
+    - kprobes/arm64: Fix %p uses in error messages
+    - arm64: Fix mismatched cache line size detection
+    - arm64: Handle mismatched cache type
+    - arm64: mm: check for upper PAGE_SHIFT bits in pfn_valid()
+    - arm64: dts: rockchip: corrected uart1 clock-names for rk3328
+    - KVM: arm/arm64: Fix potential loss of ptimer interrupts
+    - KVM: arm/arm64: Fix lost IRQs from emulated physcial timer when blocked
+    - KVM: arm/arm64: Skip updating PMD entry if no change
+    - KVM: arm/arm64: Skip updating PTE entry if no change
+    - s390/kvm: fix deadlock when killed by oom
+    - perf kvm: Fix subcommands on s390
+    - stop_machine: Reflow cpu_stop_queue_two_works()
+    - stop_machine: Atomically queue and wake stopper threads
+    - ext4: check for NUL characters in extended attribute's name
+    - ext4: use ext4_warning() for sb_getblk failure
+    - ext4: sysfs: print ext4_super_block fields as little-endian
+    - ext4: reset error code in ext4_find_entry in fallback
+    - ext4: fix race when setting the bitmap corrupted flag
+    - x86/gpu: reserve ICL's graphics stolen memory
+    - platform/x86: wmi: Do not mix pages and kmalloc
+    - platform/x86: ideapad-laptop: Apply no_hw_rfkill to Y20-15IKBM, too
+    - mm: move tlb_table_flush to tlb_flush_mmu_free
+    - mm/tlb, x86/mm: Support invalidating TLB caches for RCU_TABLE_FREE
+    - 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: Suggest what to do on systems with too much RAM
+    - x86/vdso: Fix vDSO build if a retpoline is emitted
+    - x86/process: Re-export start_thread()
+    - KVM: x86: ensure all MSRs can always be KVM_GET/SET_MSR'd
+    - KVM: x86: SVM: Call x86_spec_ctrl_set_guest/host() with interrupts disabled
+    - fuse: Don't access pipe->buffers without pipe_lock()
+    - fuse: fix initial parallel dirops
+    - 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()
+    - lib/vsprintf: Do not handle %pO[^F] as %px
+    - udl-kms: change down_interruptible to down
+    - udl-kms: handle allocation failure
+    - udl-kms: fix crash due to uninitialized memory
+    - udl-kms: avoid division
+    - b43legacy/leds: Ensure NUL-termination of LED name string
+    - b43/leds: Ensure NUL-termination of LED name string
+    - ASoC: dpcm: don't merge format from invalid codec dai
+    - ASoC: zte: Fix incorrect PCM format bit usages
+    - ASoC: sirf: Fix potential NULL pointer dereference
+    - ASoC: wm_adsp: Correct DSP pointer for preloader control
+    - soc: qcom: rmtfs-mem: fix memleak in probe error paths
+    - pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show()
+    - scsi: qla2xxx: Fix stalled relogin
+    - x86/vdso: Fix lsl operand order
+    - x86/nmi: Fix NMI uaccess race against CR3 switching
+    - x86/irqflags: Mark native_restore_fl extern inline
+    - x86/spectre: Add missing family 6 check to microcode check
+    - x86/speculation/l1tf: Increase l1tf memory limit for Nehalem+
+    - hwmon: (nct6775) Fix potential Spectre v1
+    - x86/entry/64: Wipe KASAN stack shadow before rewind_stack_do_exit()
+    - x86: Allow generating user-space headers without a compiler
+    - s390/mm: fix addressing exception after suspend/resume
+    - s390/lib: use expoline for all bcr instructions
+    - s390: fix br_r1_trampoline for machines without exrl
+    - s390/qdio: reset old sbal_state flags
+    - s390/numa: move initial setup of node_to_cpumask_map
+    - s390/purgatory: Fix crash with expoline enabled
+    - s390/purgatory: Add missing FORCE to Makefile targets
+    - kprobes: Show blacklist addresses as same as kallsyms does
+    - kprobes: Replace %p with other pointer types
+    - kprobes/arm: Fix %p uses in error messages
+    - kprobes: Make list and blacklist root user read only
+    - MIPS: Correct the 64-bit DSP accumulator register size
+    - MIPS: memset.S: Fix byte_fixup for MIPSr6
+    - MIPS: Always use -march=<arch>, not -<arch> shortcuts
+    - MIPS: Change definition of cpu_relax() for Loongson-3
+    - MIPS: lib: Provide MIPS64r6 __multi3() for GCC < 7
+    - tpm: Return the actual size when receiving an unsupported command
+    - tpm: separate cmd_ready/go_idle from runtime_pm
+    - scsi: mpt3sas: Fix calltrace observed while running IO & reset
+    - scsi: mpt3sas: Fix _transport_smp_handler() error path
+    - 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
+    - mtd: rawnand: hynix: Use ->exec_op() in hynix_nand_reg_write_op()
+    - mtd: rawnand: fsmc: Stop using chip->read_buf()
+    - mtd: rawnand: marvell: add suspend and resume hooks
+    - mtd: rawnand: qcom: wait for desc completion in all BAM channels
+    - clk: rockchip: fix clk_i2sout parent selection bits on rk3399
+    - clk: npcm7xx: fix memory allocation
+    - PM / clk: signedness bug in of_pm_clk_add_clks()
+    - power: generic-adc-battery: fix out-of-bounds write when copying channel
+      properties
+    - power: generic-adc-battery: check for duplicate properties copied from iio
+      channels
+    - watchdog: Mark watchdog touch functions as notrace
+    - cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status
+    - x86/dumpstack: Don't dump kernel memory based on usermode RIP
+    - Linux 4.18.6
+    - updateconfigs after v4.18.6 stable update
+
+  * random oopses on s390 systems using NVMe devices (LP: #1790480)
+    - s390/pci: fix out of bounds access during irq setup
+
+  * [18.10 FEAT] zcrypt DD: introduce APQN tags to support deterministic driver
+    binding (LP: #1784331)
+    - s390/zcrypt: code beautify
+    - s390/zcrypt: AP bus support for alternate driver(s)
+    - s390/zcrypt: hex string mask improvements for apmask and aqmask.
+
+  * performance drop with ATS enabled (LP: #1788097)
+    - powerpc/powernv: Fix concurrency issue with npu->mmio_atsd_usage
+
+  * Fix MCE handling for user access of poisoned device-dax mapping
+    (LP: #1774366)
+    - device-dax: Convert to vmf_insert_mixed and vm_fault_t
+    - device-dax: Enable page_mapping()
+    - device-dax: Set page->index
+    - filesystem-dax: Set page->index
+    - mm, madvise_inject_error: Disable MADV_SOFT_OFFLINE for ZONE_DEVICE pages
+    - mm, dev_pagemap: Do not clear ->mapping on final put
+    - mm, madvise_inject_error: Let memory_failure() optionally take a page
+      reference
+    - mm, memory_failure: Collect mapping size in collect_procs()
+    - filesystem-dax: Introduce dax_lock_mapping_entry()
+    - mm, memory_failure: Teach memory_failure() about dev_pagemap pages
+    - x86/mm/pat: Prepare {reserve, free}_memtype() for "decoy" addresses
+    - x86/memory_failure: Introduce {set, clear}_mce_nospec()
+    - libnvdimm, pmem: Restore page attributes when clearing errors
+
+  * Reconcile hns3 SAUCE patches with upstream (LP: #1787477)
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix comments for
+      hclge_get_ring_chain_from_mbx"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for using wrong mask and
+      shift in hclge_get_ring_chain_from_mbx"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for reset_level default
+      assignment probelm"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove unnecessary ring
+      configuration operation while resetting"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix return value error in
+      hns3_reset_notify_down_enet"
+    - Revert "UBUNTU: SAUCE: net: hns3: Fix for phy link issue when using marvell
+      phy driver"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: separate roce from nic when
+      resetting"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: correct reset event status
+      register"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: prevent to request reset
+      frequently"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: reset net device with rtnl_lock"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: modify the order of initializeing
+      command queue register"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: prevent sending command during
+      global or core reset"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: Use roce handle when calling roce
+      callback function"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove the warning when clear
+      reset cause"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix get_vector ops in
+      hclgevf_main module"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix warning bug when doing lp
+      selftest"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: Add configure for mac minimal
+      frame size"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for mailbox message truncated
+      problem"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for l4 checksum offload bug"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for waterline not setting
+      correctly"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix for mac pause not disable in
+      pfc mode"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix tc setup when netdev is first
+      up"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: Add calling roce callback
+      function when link status change"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: optimize the process of notifying
+      roce client"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: Add pf reset for hip08 RoCE"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: Add SPDX tags to hns3 driver"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove unused struct member and
+      definition"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix mislead parameter name"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: modify inconsistent bit mask
+      macros"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: use decimal for bit offset
+      macros"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: fix unreasonable code comments"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove extra space and brackets"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: standardize the handle of return
+      value"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove some redundant
+      assignments"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: modify hnae_ to hnae3_"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: use dma_zalloc_coherent instead
+      of kzalloc/dma_map_single"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: give default option while
+      dependency HNS3 set"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove some unused members of
+      some structures"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove a redundant
+      hclge_cmd_csq_done"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: using modulo for cyclic counters
+      in hclge_cmd_send"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: simplify hclge_cmd_csq_clean"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove some redundant
+      assignments"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove useless code in
+      hclge_cmd_send"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove unused
+      hclge_ring_to_dma_dir"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: use lower_32_bits and
+      upper_32_bits"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove back in struct hclge_hw"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: add unlikely for error check"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove the Redundant put_vector
+      in hns3_client_uninit"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: print the ret value in error
+      information"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: extraction an interface for state
+      state init|uninit"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove unused head file in
+      hnae3.c"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: add l4_type check for both ipv4
+      and ipv6"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: add vector status check before
+      free vector"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: rename the interface for
+      init_client_instance and uninit_client_instance"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: remove hclge_get_vector_index
+      from hclge_bind_ring_with_vector"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: RX BD information valid only in
+      last BD except VLD bit and buffer size"
+    - Revert "UBUNTU: SAUCE: {topost} net: hns3: add support for serdes loopback
+      selftest"
+    - net: hns3: Updates RX packet info fetch in case of multi BD
+    - net: hns3: remove hclge_get_vector_index from hclge_bind_ring_with_vector
+    - net: hns3: rename the interface for init_client_instance and
+      uninit_client_instance
+    - net: hns3: add vector status check before free vector
+    - net: hns3: add l4_type check for both ipv4 and ipv6
+    - net: hns3: add unlikely for error check
+    - net: hns3: remove unused head file in hnae3.c
+    - net: hns3: extraction an interface for state init|uninit
+    - net: hns3: print the ret value in error information
+    - net: hns3: remove the Redundant put_vector in hns3_client_uninit
+    - net: hns3: remove back in struct hclge_hw
+    - net: hns3: use lower_32_bits and upper_32_bits
+    - net: hns3: remove unused hclge_ring_to_dma_dir
+    - net: hns3: remove useless code in hclge_cmd_send
+    - net: hns3: remove some redundant assignments
+    - net: hns3: simplify hclge_cmd_csq_clean
+    - net: hns3: remove a redundant hclge_cmd_csq_done
+    - net: hns3: remove some unused members of some structures
+    - net: hns3: give default option while dependency HNS3 set
+    - net: hns3: use dma_zalloc_coherent instead of kzalloc/dma_map_single
+    - net: hns3: modify hnae_ to hnae3_
+    - net: hns3: Fix tc setup when netdev is first up
+    - net: hns3: Fix for mac pause not disable in pfc mode
+    - net: hns3: Fix for waterline not setting correctly
+    - net: hns3: Fix for l4 checksum offload bug
+    - net: hns3: Fix for mailbox message truncated problem
+    - net: hns3: Add configure for mac minimal frame size
+    - net: hns3: Fix warning bug when doing lp selftest
+    - net: hns3: Fix get_vector ops in hclgevf_main module
+    - net: hns3: Remove the warning when clear reset cause
+    - net: hns3: Prevent sending command during global or core reset
+    - net: hns3: Modify the order of initializing command queue register
+    - net: hns3: Reset net device with rtnl_lock
+    - net: hns3: Prevent to request reset frequently
+    - net: hns3: Correct reset event status register
+    - net: hns3: Fix return value error in hns3_reset_notify_down_enet
+    - net: hns3: remove unnecessary ring configuration operation while resetting
+    - net: hns3: Fix for reset_level default assignment probelm
+    - net: hns3: Fix for using wrong mask and shift in
+      hclge_get_ring_chain_from_mbx
+    - net: hns3: Fix comments for hclge_get_ring_chain_from_mbx
+    - net: hns3: Remove some redundant assignments
+    - net: hns3: Standardize the handle of return value
+    - net: hns3: Remove extra space and brackets
+    - net: hns3: Correct unreasonable code comments
+    - net: hns3: Use decimal for bit offset macros
+    - net: hns3: Modify inconsistent bit mask macros
+    - net: hns3: Fix misleading parameter name
+    - net: hns3: Remove unused struct member and definition
+    - net: hns3: Add SPDX tags to HNS3 PF driver
+    - net: hns3: Add support for serdes loopback selftest
+    - net: hns3: Fix for phy link issue when using marvell phy driver
+
+  * [Regression] kernel crashdump fails on arm64 (LP: #1786878)
+    - arm64: export memblock_reserve()d regions via /proc/iomem
+    - drivers: acpi: add dependency of EFI for arm64
+    - efi/arm: preserve early mapping of UEFI memory map longer for BGRT
+    - efi/arm: map UEFI memory map even w/o runtime services enabled
+    - arm64: acpi: fix alignment fault in accessing ACPI
+    - [Config] CONFIG_ARCH_SUPPORTS_ACPI=y
+    - arm64: fix ACPI dependencies
+    - ACPI: fix menuconfig presentation of ACPI submenu
+
+  * TB 16 issue on Dell Lattitude 7490 with large amount of data (LP: #1785780)
+    - r8152: disable RX aggregation on new Dell TB16 dock
+
+  * Support Power Management for Thunderbolt Controller  (LP: #1789358)
+    - thunderbolt: Use 64-bit DMA mask if supported by the platform
+    - thunderbolt: Do not unnecessarily call ICM get route
+    - thunderbolt: No need to take tb->lock in domain suspend/complete
+    - thunderbolt: Use correct ICM commands in system suspend
+    - thunderbolt: Add support for runtime PM
+
+  * Enable AMD PCIe MP2 for AMDI0011 (LP: #1773940)
+    - SAUCE: i2c:amd I2C Driver based on PCI Interface for upcoming platform
+    - SAUCE: i2c:amd move out pointer in union i2c_event_base
+    - SAUCE: i2c:amd Depends on ACPI
+    - [Config] i2c: CONFIG_I2C_AMD_MP2=y on x86
+
+  * Microphone cannot be detected with front panel audio combo jack on HP Z8-G4
+    machine (LP: #1789145)
+    - ALSA: hda/realtek - Fix HP Headset Mic can't record
+
+  * Please enable CONFIG_PAGE_POISONING (LP: #1783651)
+    - [Config] Enable CONFIG_PAGE_POISONING configs
+
+  * Tango platform uses __initcall without further checks (LP: #1787945)
+    - [Config] disable ARCH_TANGO
+
+  * [18.10 FEAT] SMC-Direct (LP: #1786902)
+    - net/smc: determine port attributes independent from pnet table
+    - net/smc: add pnetid support
+    - net/smc: add base infrastructure for SMC-D and ISM
+    - net/smc: add pnetid support for SMC-D and ISM
+    - net/smc: add SMC-D support in CLC messages
+    - net/smc: add SMC-D support in data transfer
+    - net/smc: add SMC-D support in af_smc
+    - net/smc: add SMC-D diag support
+    - net/smc: provide smc mode in smc_diag.c
+    - net/smc: eliminate cursor read and write calls
+    - net/smc: add function to get link group from link
+    - net/smc: use DECLARE_BITMAP for rtokens_used_mask
+    - net/smc: remove local variable page in smc_rx_splice()
+    - net/smc: Remove a WARN_ON() statement
+    - net/smc: Simplify ib_post_(send|recv|srq_recv)() calls
+    - net/smc: fewer parameters for smc_llc_send_confirm_link()
+    - net/smc: use correct vlan gid of RoCE device
+    - net/smc: provide fallback reason code
+    - net/smc: improve delete link processing
+    - net: simplify sock_poll_wait
+    - net/smc: send response to test link signal
+
+  * Miscellaneous Ubuntu changes
+    - [Config] update annotations for CONFIG_CRYPTO_SPECK_NEON
+    - [Config] fix up annotatios for CONFIG_CRYPTO_SPECK
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 10 Sep 2018 07:08:38 -0500
+
+linux (4.18.0-7.8) cosmic; urgency=medium
+
+  * linux: 4.18.0-7.8 -proposed tracker (LP: #1789459)
+
+  * pmtu.sh fails on 4.18 kernel (LP: #1789436)
+    - SAUCE: Revert "vti6: fix PMTU caching and reporting on xmit"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 28 Aug 2018 11:08:51 -0500
+
+linux (4.18.0-6.7) cosmic; urgency=medium
+
+  * linux: 4.18.0-6.7 -proposed tracker (LP: #1788881)
+
+  * systemd 237-3ubuntu10 ADT test failure with linux 4.18.0-5.6 (LP: #1787440)
+    - Config: Disable BPF_JIT_ALWAYS_ON on i386
+
+  * execveat03 in ubuntu_ltp_syscalls failed on X/B (LP: #1786729)
+    - cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
+
+  * Cosmic update to v4.18.5 stable release (LP: #1788874)
+    - EDAC: Add missing MEM_LRDDR4 entry in edac_mem_types[]
+    - pty: fix O_CLOEXEC for TIOCGPTPEER
+    - mm: Allow non-direct-map arguments to free_reserved_area()
+    - x86/mm/init: Pass unconverted symbol addresses to free_init_pages()
+    - x86/mm/init: Add helper for freeing kernel image pages
+    - x86/mm/init: Remove freed kernel image areas from alias mapping
+    - powerpc64s: Show ori31 availability in spectre_v1 sysfs file not v2
+    - ext4: fix spectre gadget in ext4_mb_regular_allocator()
+    - drm/i915/kvmgt: Fix potential Spectre v1
+    - drm/amdgpu/pm: Fix potential Spectre v1
+    - parisc: Remove unnecessary barriers from spinlock.h
+    - parisc: Remove ordered stores from syscall.S
+    - PCI: Restore resized BAR state on resume
+    - PCI / ACPI / PM: Resume all bridges on suspend-to-RAM
+    - PCI: hotplug: Don't leak pci_slot on registration failure
+    - PCI: aardvark: Size bridges before resources allocation
+    - PCI: Skip MPS logic for Virtual Functions (VFs)
+    - PCI: pciehp: Fix use-after-free on unplug
+    - PCI: pciehp: Fix unprotected list iteration in IRQ handler
+    - i2c: core: ACPI: Properly set status byte to 0 for multi-byte writes
+    - i2c: imx: Fix race condition in dma read
+    - reiserfs: fix broken xattr handling (heap corruption, bad retval)
+    - Linux 4.18.5
+
+  * [18.10 FEAT] Add kernel config option "CONFIG_SCLP_OFB" (LP: #1787898)
+    - [Config] CONFIG_SCLP_OFB=y for s390x
+
+  * 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
+
+  * Apply NVMe bugfix from Google that bjf asked for (LP: #1787635)
+    - nvme-pci: add a memory barrier to nvme_dbbuf_update_and_check_event
+
+  * ThinkPad systems have no HDMI sound when using the nvidia GPU (LP: #1787058)
+    - ACPI / OSI: Add OEM _OSI string to enable NVidia HDMI audio
+
+  * Cosmic update to v4.18.4 stable release (LP: #1788454)
+    - l2tp: use sk_dst_check() to avoid race on sk->sk_dst_cache
+    - net_sched: fix NULL pointer dereference when delete tcindex filter
+    - net_sched: Fix missing res info when create new tc_index filter
+    - r8169: don't use MSI-X on RTL8168g
+    - 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: dice: fix wrong copy to rx parameters for Alesis iO26
+    - 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
+    - ALSA: seq: Fix poll() error return
+    - media: gl861: fix probe of dvb_usb_gl861
+    - USB: serial: sierra: fix potential deadlock at close
+    - USB: serial: pl2303: add a new device id for ATEN
+    - USB: option: add support for DW5821e
+    - ACPI / PM: save NVS memory for ASUS 1025C laptop
+    - tty: serial: 8250: Revert NXP SC16C2552 workaround
+    - serial: 8250_exar: Read INT0 from slave device, too
+    - serial: 8250_dw: always set baud rate in dw8250_set_termios
+    - serial: 8250_dw: Add ACPI support for uart on Broadcom SoC
+    - uio: fix wrong return value from uio_mmap()
+    - misc: sram: fix resource leaks in probe error path
+    - Revert "uio: use request_threaded_irq instead"
+    - Bluetooth: avoid killing an already killed socket
+    - isdn: Disable IIOCDBGVAR
+    - net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
+    - hv/netvsc: Fix NULL dereference at single queue mode fallback
+    - r8169: don't use MSI-X on RTL8106e
+    - ip_vti: fix a null pointer deferrence when create vti fallback tunnel
+    - net: ethernet: mvneta: Fix napi structure mixup on armada 3700
+    - net: mvneta: fix mvneta_config_rss on armada 3700
+    - cls_matchall: fix tcf_unbind_filter missing
+    - Linux 4.18.4
+
+  * Cosmic update to v4.18.3 stable release (LP: #1788453)
+    - x86/speculation/l1tf: Exempt zeroed PTEs from inversion
+    - Linux 4.18.3
+
+  * Cosmic update to v4.18.2 stable release (LP: #1788452)
+    - x86/l1tf: Fix build error seen if CONFIG_KVM_INTEL is disabled
+    - x86: i8259: Add missing include file
+    - x86/hyper-v: Check for VP_INVAL in hyperv_flush_tlb_others()
+    - x86/platform/UV: Mark memblock related init code and data correctly
+    - x86/mm/pti: Clear Global bit more aggressively
+    - xen/pv: Call get_cpu_address_sizes to set x86_virt/phys_bits
+    - x86/mm: Disable ioremap free page handling on x86-PAE
+    - kbuild: verify that $DEPMOD is installed
+    - crypto: ccree - fix finup
+    - crypto: ccree - fix iv handling
+    - crypto: ccp - Check for NULL PSP pointer at module unload
+    - crypto: ccp - Fix command completion detection race
+    - crypto: x86/sha256-mb - fix digest copy in sha256_mb_mgr_get_comp_job_avx2()
+    - 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
+    - crypto: skcipher - fix aligning block size in skcipher_copy_iv()
+    - crypto: skcipher - fix crash flushing dcache in error path
+    - ioremap: Update pgtable free interfaces with addr
+    - x86/mm: Add TLB purge to free pmd/pte page interfaces
+    - Linux 4.18.2
+
+  * Cosmic update to v4.18.2 stable release (LP: #1788452) // CVE-2018-9363
+    - Bluetooth: hidp: buffer overflow in hidp_process_report
+
+  * 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
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: ipvs: remove nbsp characters from Kconfig
+    - [Config] CONFIG_MPROFILE_KERNEL=y for ppc64el
+    - [Config] CONFIG_DRM_RCAR_LVDS=m for snapdragon
+    - [Config] CONFIG_MDIO_MSCC_MIIM=n for s390x
+    - [Config] CONFIG_NET_VENDOR_MICROSEMI=n, CONFIG_NET_VENDOR_NI=n for s390x
+    - [Config] update annotations following config review
+    - [Debian] set CROSS_COMPILE when generating kernel configs
+    - [Config] Disable the Speck cipher
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 24 Aug 2018 14:18:15 -0500
+
+linux (4.18.0-5.6) cosmic; urgency=medium
+
+  * Cosmic update to v4.18.1 stable release (LP: #1787264)
+    - x86/paravirt: Fix spectre-v2 mitigations for paravirt guests
+    - x86/speculation: Protect against userspace-userspace spectreRSB
+    - kprobes/x86: Fix %p uses in error messages
+    - x86/irqflags: Provide a declaration for native_save_fl
+    - 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/speculation/l1tf: Protect PROT_NONE PTEs against speculation
+    - x86/speculation/l1tf: Make sure the first page is always reserved
+    - 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/bugs: Move the l1tf function and define pr_fmt properly
+    - sched/smt: Update sched_smt_present at runtime
+    - x86/smp: Provide topology_is_primary_thread()
+    - x86/topology: Provide topology_smt_supported()
+    - cpu/hotplug: Make bringup/teardown of smp threads symmetric
+    - cpu/hotplug: Split do_cpu_down()
+    - cpu/hotplug: Provide knobs to control SMT
+    - 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: Do not check CPUID max ext level before parsing SMP info
+    - 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/cpufeatures: Add detection of L1D cache flush support.
+    - x86/CPU/AMD: Move TOPOEXT reenablement before reading smp_num_siblings
+    - 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"
+    - cpu/hotplug: Boot HT siblings at least once
+    - 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: Separate 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/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: 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: Make set_memory_np() L1TF safe
+    - x86/mm/kmmio: Make the tracer robust against L1TF
+    - tools headers: Synchronise x86 cpufeatures.h for L1TF additions
+    - x86/microcode: Allow late microcode loading with SMT disabled
+    - x86/smp: fix non-SMP broken build due to redefinition of
+      apic_id_is_primary_thread
+    - cpu/hotplug: Non-SMP machines do not make use of booted_once
+    - x86/init: fix build with CONFIG_SWAP=n
+    - Linux 4.18.1
+    - [Config] updateconfigs after v4.18.1 stable update
+
+  * Consider enabling CONFIG_NETWORK_PHY_TIMESTAMPING (LP: #1785816)
+    - [Config] Enable timestamping in network PHY devices
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_SYSCTL_SYSCALL=n
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 15 Aug 2018 14:20:59 -0500
+
+linux (4.18.0-4.5) cosmic; urgency=medium
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18-rc8
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 06 Aug 2018 13:54:02 -0500
+
+linux (4.18.0-3.4) cosmic; urgency=medium
+
+  * Suspend fails in Ubuntu and Kubuntu 18.04 but works fine in Ubuntu and
+    Kubuntu 17.10 (and on Kubuntu 18.04 using kernel 4.14.47) (LP: #1774950)
+    - ACPI / LPSS: Avoid PM quirks on suspend and resume from hibernation
+
+  * hinic interfaces aren't getting predictable names (LP: #1783138)
+    - hinic: Link the logical network device to the pci device in sysfs
+
+  * libvirtd is unable to configure bridge devices inside of LXD containers
+    (LP: #1784501)
+    - kernfs: allow creating kernfs objects with arbitrary uid/gid
+    - sysfs, kobject: allow creating kobject belonging to arbitrary users
+    - kobject: kset_create_and_add() - fetch ownership info from parent
+    - driver core: set up ownership of class devices in sysfs
+    - net-sysfs: require net admin in the init ns for setting tx_maxrate
+    - net-sysfs: make sure objects belong to container's owner
+    - net: create reusable function for getting ownership info of sysfs inodes
+    - bridge: make sure objects belong to container's owner
+    - sysfs: Fix regression when adding a file to an existing group
+
+  * locking sockets broken due to missing AppArmor socket mediation patches
+    (LP: #1780227)
+    - UBUNTU SAUCE: apparmor: fix apparmor mediating locking non-fs, unix sockets
+
+  * Update2 for ocxl driver (LP: #1781436)
+    - ocxl: Fix page fault handler in case of fault on dying process
+
+  * HDMI/DP audio can't work on the laptop of Dell Latitude 5495 (LP: #1782689)
+    - ALSA: hda: use PCI_BASE_CLASS_DISPLAY to replace PCI_CLASS_DISPLAY_VGA
+    - vga_switcheroo: set audio client id according to bound GPU id
+
+  * Allow Raven Ridge's audio controller to be runtime suspended (LP: #1782540)
+    - ALSA: hda: Add AZX_DCAPS_PM_RUNTIME for AMD Raven Ridge
+
+  * Invoking obsolete 'firmware_install' target breaks snap build (LP: #1782166)
+    - snapcraft.yaml: stop invoking the obsolete (and non-existing)
+      'firmware_install' target
+
+  * snapcraft.yaml: missing ubuntu-retpoline-extract-one script breaks the build
+    (LP: #1782116)
+    - snapcraft.yaml: copy retpoline-extract-one to scripts before build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 01 Aug 2018 08:49:40 -0500
+
+linux (4.18.0-2.3) cosmic; urgency=medium
+
+  * Kernel error "task zfs:pid blocked for more than 120 seconds" (LP: #1781364)
+    - SAUCE: (noup) zfs to 0.7.9-3ubuntu4
+
+  * [Regression] EXT4-fs error (device sda1): ext4_validate_inode_bitmap:99:
+    comm stress-ng: Corrupt inode bitmap (LP: #1780137)
+    - SAUCE: ext4: fix ext4_validate_inode_bitmap: comm stress-ng: Corrupt inode
+      bitmap
+
+  * Cloud-init causes potentially huge boot delays with 4.15 kernels
+    (LP: #1780062)
+    - random: Make getrandom() ready earlier
+
+  * hisi_sas_v3_hw: internal task abort: timeout and not done. (LP: #1777736)
+    - scsi: hisi_sas: Update a couple of register settings for v3 hw
+
+  * hisi_sas: Add missing PHY spinlock init (LP: #1777734)
+    - scsi: hisi_sas: Add missing PHY spinlock init
+
+  * hisi_sas: improve read performance by pre-allocating slot DMA buffers
+    (LP: #1777727)
+    - scsi: hisi_sas: Use dmam_alloc_coherent()
+    - scsi: hisi_sas: Pre-allocate slot DMA buffers
+
+  * hisi_sas: Failures during host reset (LP: #1777696)
+    - scsi: hisi_sas: Only process broadcast change in phy_bcast_v3_hw()
+    - scsi: hisi_sas: Fix the conflict between dev gone and host reset
+    - scsi: hisi_sas: Adjust task reject period during host reset
+    - scsi: hisi_sas: Add a flag to filter PHY events during reset
+    - scsi: hisi_sas: Release all remaining resources in clear nexus ha
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.9-3ubuntu2, zfs to 0.7.9-3ubuntu3
+    - SAUCE: mm: Fix exports that inadvertently make put_page() EXPORT_SYMBOL_GPL
+    - Enable zfs build
+    - SAUCE: Import aufs driver
+    - Revert "UBUNTU: [Config]: set CONFIG_EDAC_DEBUG=y for ARM64"
+    - [Config] retpoline -- review and accept retpoline changes
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18-rc5
+  * Rebase to v4.18-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 24 Jul 2018 08:41:22 -0500
+
+linux (4.18.0-1.2) cosmic; urgency=medium
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 09 Jul 2018 07:36:31 -0500
+
+linux (4.18.0-0.1) cosmic; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu -- disable vbox build
+    - Disable zfs build
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) Add a SysRq option to lift kernel lockdown
+    - SAUCE: (efi-lockdown) ima: require secure_boot rules in lockdown mode
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/{mem,kmem,port} when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) kexec_load: Disable at runtime if the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86/msr: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Lock down module params that specify hardware
+      parameters (eg. ioport)
+    - SAUCE: (efi-lockdown) x86/mmiotrace: Lock down the testmmiotrace module
+    - SAUCE: (efi-lockdown) Lock down /proc/kcore
+    - SAUCE: (efi-lockdown) Lock down kprobes
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - SAUCE: (efi-lockdown) Lock down perf
+    - SAUCE: (efi-lockdown) debugfs: Restrict debugfs when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time addition of keys to
+      secondary keyring
+    - SAUCE: (efi-lockdown) efi: Add EFI signature data types
+    - SAUCE: (efi-lockdown) efi: Add an EFI signature blob parser
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable to be suppressed
+    - SAUCE: (efi-lockdown) Make get_cert_list() not complain about cert lists
+      that aren't present.
+    - SAUCE: (efi-lockdown) Add efi_status_to_str() and rework
+      efi_status_to_err().
+    - SAUCE: (efi-lockdown) Make get_cert_list() use efi_status_to_str() to print
+      error messages.
+    - SAUCE: (efi-lockdown) lockdown: fix coordination of kernel module signature
+      verification
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) efi: Don't print secure boot state from the efi stub
+    - SAUCE: (namespace) block_dev: Support checking inode permissions in
+      lookup_bdev()
+    - SAUCE: (namespace) block_dev: Check permissions towards block device inode
+      when mounting
+    - SAUCE: (namespace) mtd: Check permissions towards mtd block device inode
+      when mounting
+    - SAUCE: (namespace) ext4: Add support for unprivileged mounts from user
+      namespaces
+    - SAUCE: (namespace) ext4: Add module parameter to enable user namespace
+      mounts
+    - SAUCE: (namespace) block_dev: Forbid unprivileged mounting when device is
+      opened for writing
+    - SAUCE: Import aufs driver
+    - Update dropped.txt
+    - [Config] updateconfigs after 4.18-rc3 rebase
+    - SAUCE: (no-up): ASoC: Intel: bytcr-rt5660: Remove snd_soc_codec use for 4.18
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.18-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 06 Jul 2018 10:46:37 -0500
+
+linux (4.18.0-0.0) cosmic; urgency=medium
+
+  * Dummy entry.
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 03 Jul 2018 11:10:33 -0500
+
+linux (4.17.0-4.5) cosmic; urgency=medium
+
+  * linux: 4.17.0-4.5 -proposed tracker (LP: #1779399)
+
+  * Update to ocxl driver for 18.04.1 (LP: #1775786)
+    - powerpc: Add TIDR CPU feature for POWER9
+    - powerpc: Use TIDR CPU feature to control TIDR allocation
+    - powerpc: use task_pid_nr() for TID allocation
+    - ocxl: Rename pnv_ocxl_spa_remove_pe to clarify it's action
+    - ocxl: Expose the thread_id needed for wait on POWER9
+    - ocxl: Add an IOCTL so userspace knows what OCXL features are available
+    - ocxl: Document new OCXL IOCTLs
+    - ocxl: Fix missing unlock on error in afu_ioctl_enable_p9_wait()
+
+  * Please include ax88179_178a and r8152 modules in d-i udeb (LP: #1771823)
+    - [Config:] d-i: Add ax88179_178a and r8152 to nic-modules
+
+  * glibc pkeys test fail on powerpc (LP: #1776967)
+    - [Config] Temporarily disable CONFIG_PPC_MEM_KEYS
+
+  * After update to 4.13-43 Intel Graphics are Laggy (LP: #1773520)
+    - Revert "drm/i915/edp: Allow alternate fixed mode for eDP if available."
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.9-3ubuntu1, zfs to 0.7.9-3ubuntu1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 29 Jun 2018 13:37:52 -0500
+
+linux (4.17.0-3.4) cosmic; urgency=medium
+
+  * linux: 4.17.0-3.4 -proposed tracker (LP: #1779124)
+
+  * Cosmic update to v4.17.3 stable release (LP: #1778997)
+    - net: aquantia: fix unsigned numvecs comparison with less than zero
+    - bonding: re-evaluate force_primary when the primary slave name changes
+    - cdc_ncm: avoid padding beyond end of skb
+    - ipv6: allow PMTU exceptions to local routes
+    - net: dsa: add error handling for pskb_trim_rcsum
+    - net: phy: dp83822: use BMCR_ANENABLE instead of BMSR_ANEGCAPABLE for DP83620
+    - net/sched: act_simple: fix parsing of TCA_DEF_DATA
+    - tcp: verify the checksum of the first data segment in a new connection
+    - tls: fix use-after-free in tls_push_record
+    - tls: fix waitall behavior in tls_sw_recvmsg
+    - socket: close race condition between sock_close() and sockfs_setattr()
+    - udp: fix rx queue len reported by diag and proc interface
+    - net: in virtio_net_hdr only add VLAN_HLEN to csum_start if payload holds
+      vlan
+    - hv_netvsc: Fix a network regression after ifdown/ifup
+    - ACPICA: AML parser: attempt to continue loading table after error
+    - ext4: fix hole length detection in ext4_ind_map_blocks()
+    - ext4: update mtime in ext4_punch_hole even if no blocks are released
+    - ext4: do not allow external inodes for inline data
+    - ext4: bubble errors from ext4_find_inline_data_nolock() up to ext4_iget()
+    - ext4: correctly handle a zero-length xattr with a non-zero e_value_offs
+    - ext4: fix fencepost error in check for inode count overflow during resize
+    - driver core: Don't ignore class_dir_create_and_add() failure.
+    - Btrfs: allow empty subvol= again
+    - Btrfs: fix clone vs chattr NODATASUM race
+    - Btrfs: fix memory and mount leak in btrfs_ioctl_rm_dev_v2()
+    - btrfs: return error value if create_io_em failed in cow_file_range
+    - btrfs: scrub: Don't use inode pages for device replace
+    - ALSA: usb-audio: Disable the quirk for Nura headset
+    - ALSA: hda/conexant - Add fixup for HP Z2 G4 workstation
+    - 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
+    - x86/MCE: Fix stack out-of-bounds write in mce-inject.c: Flags_read()
+    - smb3: fix various xid leaks
+    - smb3: on reconnect set PreviousSessionId field
+    - CIFS: 511c54a2f69195b28afb9dd119f03787b1625bb4 adds a check for session
+      expiry
+    - cifs: For SMB2 security informaion query, check for minimum sized security
+      descriptor instead of sizeof FileAllInformation class
+    - nbd: fix nbd device deletion
+    - nbd: update size when connected
+    - nbd: use bd_set_size when updating disk size
+    - blk-mq: reinit q->tag_set_list entry only after grace period
+    - bdi: Move cgroup bdi_writeback to a dedicated low concurrency workqueue
+    - cpufreq: Fix new policy initialization during limits updates via sysfs
+    - cpufreq: ti-cpufreq: Fix an incorrect error return value
+    - cpufreq: governors: Fix long idle detection logic in load calculation
+    - libata: zpodd: small read overflow in eject_tray()
+    - libata: Drop SanDisk SD7UB3Q*G1001 NOLPM quirk
+    - nvme/pci: Sync controller reset for AER slot_reset
+    - w1: mxc_w1: Enable clock before calling clk_get_rate() on it
+    - x86/vector: Fix the args of vector_alloc tracepoint
+    - x86/apic/vector: Prevent hlist corruption and leaks
+    - x86/apic: Provide apic_ack_irq()
+    - x86/ioapic: Use apic_ack_irq()
+    - x86/platform/uv: Use apic_ack_irq()
+    - irq_remapping: Use apic_ack_irq()
+    - genirq/generic_pending: Do not lose pending affinity update
+    - genirq/affinity: Defer affinity setting if irq chip is busy
+    - genirq/migration: Avoid out of line call if pending is not set
+    - x86/intel_rdt: Enable CMT and MBM on new Skylake stepping
+    - media: uvcvideo: Prevent setting unavailable flags
+    - media: rc: ensure input/lirc device can be opened after register
+    - iwlwifi: fw: harden page loading code
+    - orangefs: set i_size on new symlink
+    - orangefs: report attributes_mask and attributes for statx
+    - HID: intel_ish-hid: ipc: register more pm callbacks to support hibernation
+    - HID: wacom: Correct logical maximum Y for 2nd-gen Intuos Pro large
+    - vhost: fix info leak due to uninitialized memory
+    - mm, page_alloc: do not break __GFP_THISNODE by zonelist reset
+    - Linux 4.17.3
+
+  * Use-after-free in sk_peer_label (LP: #1778646)
+    - SAUCE: apparmor: fix use after free in sk_peer_label
+
+  * kernel: Fix memory leak on CCA and EP11 CPRB processing. (LP: #1775390)
+    - s390/zcrypt: Fix CCA and EP11 CPRB processing failure memory leak.
+
+  * Various fixes for CXL kernel module (LP: #1774471)
+    - cxl: Configure PSL to not use APC virtual machines
+    - cxl: Disable prefault_mode in Radix mode
+
+  * Bluetooth not working (LP: #1764645)
+    - Bluetooth: btusb: Apply QCA Rome patches for some ATH3012 models
+
+  * Fake SAS addresses for SATA disks on HiSilicon D05 are non-unique
+    (LP: #1776750)
+    - scsi: hisi_sas: make SAS address of SATA disks unique
+
+  * linux-snapdragon: wcn36xx: mac address generation on boot (LP: #1776491)
+    - [Config] arm64: snapdragon: WCN36XX_SNAPDRAGON_HACKS=y
+    - SAUCE: wcn36xx: read MAC from file or randomly generate one
+
+  * Lenovo V330 needs patch in ideapad_laptop module for rfkill (LP: #1774636)
+    - SAUCE: Add Lenovo V330 to the ideapad_laptop rfkill blacklist
+
+  * register on binfmt_misc may overflow and crash the system (LP: #1775856)
+    - fs/binfmt_misc.c: do not allow offset overflow
+
+  * Network installs fail on SocioNext board (LP: #1775884)
+    - net: socionext: reset hardware in ndo_stop
+    - net: netsec: enable tx-irq during open callback
+
+  * Fix several bugs in RDMA/hns driver (LP: #1770974)
+    - RDMA/hns: Drop local zgid in favor of core defined variable
+    - RDMA/hns: Add 64KB page size support for hip08
+    - RDMA/hns: Rename the idx field of db
+    - RDMA/hns: Modify uar allocation algorithm to avoid bitmap exhaust
+    - RDMA/hns: Increase checking CMQ status timeout value
+    - RDMA/hns: Add reset process for RoCE in hip08
+    - RDMA/hns: Fix the illegal memory operation when cross page
+    - RDMA/hns: Implement the disassociate_ucontext API
+
+  * powerpc/livepatch: Implement reliable stack tracing for the consistency
+    model (LP: #1771844)
+    - powerpc/livepatch: Implement reliable stack tracing for the consistency
+      model
+
+  * Adding back alx WoL feature (LP: #1772610)
+    - SAUCE: Revert "alx: remove WoL support"
+    - SAUCE: alx: add enable_wol paramenter
+
+  * Lancer A0 Asic HBA's won't boot with 18.04 (LP: #1768103)
+    - scsi: lpfc: Fix WQ/CQ creation for older asic's.
+    - scsi: lpfc: Fix 16gb hbas failing cq create.
+
+  * [LTCTest][OPAL][OP920] cpupower idle-info is not listing stop4 and stop5
+    idle states when all CORES are guarded (LP: #1771780)
+    - powerpc/powernv/cpuidle: Init all present cpus for deep states
+
+  * Huawei 25G/100G Network Adapters Unsupported (LP: #1770970)
+    - net-next/hinic: add pci device ids for 25ge and 100ge card
+
+  * Expose arm64 CPU topology to userspace (LP: #1770231)
+    - drivers: base: cacheinfo: move cache_setup_of_node()
+    - drivers: base: cacheinfo: setup DT cache properties early
+    - cacheinfo: rename of_node to fw_token
+    - arm64/acpi: Create arch specific cpu to acpi id helper
+    - ACPI/PPTT: Add Processor Properties Topology Table parsing
+    - [Config] CONFIG_ACPI_PPTT=y
+    - ACPI: Enable PPTT support on ARM64
+    - drivers: base cacheinfo: Add support for ACPI based firmware tables
+    - arm64: Add support for ACPI based firmware tables
+    - arm64: topology: rename cluster_id
+    - arm64: topology: enable ACPI/PPTT based CPU topology
+    - ACPI: Add PPTT to injectable table list
+    - arm64: topology: divorce MC scheduling domain from core_siblings
+
+  * Vcs-Git header on bionic linux source package points to zesty git tree
+    (LP: #1766055)
+    - [Packaging]: Update Vcs-Git
+
+  * Request to revert SAUCE patches in the 18.04 SRU and update with upstream
+    version (LP: #1768431)
+    - scsi: cxlflash: Handle spurious interrupts
+    - scsi: cxlflash: Remove commmands from pending list on timeout
+    - scsi: cxlflash: Synchronize reset and remove ops
+    - SAUCE: (no-up) cxlflash: OCXL diff between v2 and v3
+
+  * hisi_sas robustness fixes (LP: #1774466)
+    - scsi: hisi_sas: delete timer when removing hisi_sas driver
+    - scsi: hisi_sas: print device id for errors
+    - scsi: hisi_sas: Add some checks to avoid free'ing a sas_task twice
+    - scsi: hisi_sas: check host frozen before calling "done" function
+    - scsi: hisi_sas: check sas_dev gone earlier in hisi_sas_abort_task()
+    - scsi: hisi_sas: stop controller timer for reset
+    - scsi: hisi_sas: update PHY linkrate after a controller reset
+    - scsi: hisi_sas: change slot index allocation mode
+    - scsi: hisi_sas: Change common allocation mode of device id
+    - scsi: hisi_sas: Reset disks when discovered
+    - scsi: hisi_sas: Create a scsi_host_template per HW module
+    - scsi: hisi_sas: Init disks after controller reset
+    - scsi: hisi_sas: Try wait commands before before controller reset
+    - scsi: hisi_sas: Include TMF elements in struct hisi_sas_slot
+    - scsi: hisi_sas: Add v2 hw force PHY function for internal ATA command
+    - scsi: hisi_sas: Terminate STP reject quickly for v2 hw
+    - scsi: hisi_sas: Fix return value when get_free_slot() failed
+    - scsi: hisi_sas: Mark PHY as in reset for nexus reset
+
+  * hisi_sas: Support newer v3 hardware (LP: #1774467)
+    - scsi: hisi_sas: update RAS feature for later revision of v3 HW
+    - scsi: hisi_sas: check IPTT is valid before using it for v3 hw
+    - scsi: hisi_sas: fix PI memory size
+    - scsi: hisi_sas: config ATA de-reset as an constrained command for v3 hw
+    - scsi: hisi_sas: remove redundant handling to event95 for v3
+    - scsi: hisi_sas: add readl poll timeout helper wrappers
+    - scsi: hisi_sas: workaround a v3 hw hilink bug
+    - scsi: hisi_sas: Add LED feature for v3 hw
+
+  * hisi_sas: improve performance by optimizing DQ locking (LP: #1774472)
+    - scsi: hisi_sas: optimise the usage of DQ locking
+    - scsi: hisi_sas: relocate smp sg map
+    - scsi: hisi_sas: make return type of prep functions void
+    - scsi: hisi_sas: allocate slot buffer earlier
+    - scsi: hisi_sas: Don't lock DQ for complete task sending
+    - scsi: hisi_sas: Use device lock to protect slot alloc/free
+    - scsi: hisi_sas: add check of device in hisi_sas_task_exec()
+    - scsi: hisi_sas: fix a typo in hisi_sas_task_prep()
+
+  * FS-Cache: Assertion failed: FS-Cache: 6 == 5 is false (LP: #1774336)
+    - SAUCE: CacheFiles: fix a read_waiter/read_copier race
+
+  * enable mic-mute hotkey and led on Lenovo M820z and M920z (LP: #1774306)
+    - ALSA: hda/realtek - Enable mic-mute hotkey for several Lenovo AIOs
+
+  * hns3 driver updates (LP: #1768670)
+    - net: hns3: Remove error log when getting pfc stats fails
+    - net: hns3: fix to correctly fetch l4 protocol outer header
+    - net: hns3: Fixes the out of bounds access in hclge_map_tqp
+    - net: hns3: Fixes the error legs in hclge_init_ae_dev function
+    - net: hns3: fix for phy_addr error in hclge_mac_mdio_config
+    - net: hns3: Fix to support autoneg only for port attached with phy
+    - net: hns3: fix a dead loop in hclge_cmd_csq_clean
+    - net: hns3: Fix for packet loss due wrong filter config in VLAN tbls
+    - net: hns3: Remove packet statistics in the range of 8192~12287
+    - net: hns3: Add support of hardware rx-vlan-offload to HNS3 VF driver
+    - net: hns3: Fix for setting mac address when resetting
+    - net: hns3: remove add/del_tunnel_udp in hns3_enet module
+    - net: hns3: fix for cleaning ring problem
+    - net: hns3: refactor the loopback related function
+    - net: hns3: Fix for deadlock problem occurring when unregistering ae_algo
+    - net: hns3: Fix for the null pointer problem occurring when initializing
+      ae_dev failed
+    - net: hns3: Add a check for client instance init state
+    - net: hns3: Change return type of hnae3_register_ae_dev
+    - net: hns3: Change return type of hnae3_register_ae_algo
+    - net: hns3: Change return value in hnae3_register_client
+    - net: hns3: Fixes the back pressure setting when sriov is enabled
+    - net: hns3: Fix for fiber link up problem
+    - net: hns3: Add support of .sriov_configure in HNS3 driver
+    - net: hns3: Fixes the missing PCI iounmap for various legs
+    - net: hns3: Fixes error reported by Kbuild and internal review
+    - net: hns3: Fixes API to fetch ethernet header length with kernel default
+    - net: hns3: cleanup of return values in hclge_init_client_instance()
+    - net: hns3: Fix the missing client list node initialization
+    - net: hns3: Fix for hns3 module is loaded multiple times problem
+    - net: hns3: Use enums instead of magic number in hclge_is_special_opcode
+    - net: hns3: Fix for netdev not running problem after calling net_stop and
+      net_open
+    - net: hns3: Fixes kernel panic issue during rmmod hns3 driver
+    - net: hns3: Fix for CMDQ and Misc. interrupt init order problem
+    - net: hns3: Updates RX packet info fetch in case of multi BD
+    - net: hns3: Add support for tx_accept_tag2 and tx_accept_untag2 config
+    - net: hns3: Add STRP_TAGP field support for hardware revision 0x21
+    - net: hns3: Add support to enable TX/RX promisc mode for H/W rev(0x21)
+    - net: hns3: Fix for PF mailbox receving unknown message
+    - net: hns3: Fixes the state to indicate client-type initialization
+    - net: hns3: Fixes the init of the VALID BD info in the descriptor
+    - net: hns3: Removes unnecessary check when clearing TX/RX rings
+    - net: hns3: Clear TX/RX rings when stopping port & un-initializing client
+    - net: hns3: Remove unused led control code
+    - net: hns3: Adds support for led locate command for copper port
+    - net: hns3: Fixes initalization of RoCE handle and makes it conditional
+    - net: hns3: Disable vf vlan filter when vf vlan table is full
+    - net: hns3: Add support for IFF_ALLMULTI flag
+    - net: hns3: Add repeat address checking for setting mac address
+    - net: hns3: Fix setting mac address error
+    - net: hns3: Fix for service_task not running problem after resetting
+    - net: hns3: Fix for hclge_reset running repeatly problem
+    - net: hns3: Fix for phy not link up problem after resetting
+    - net: hns3: Add missing break in misc_irq_handle
+    - net: hns3: Fix for vxlan tx checksum bug
+    - net: hns3: Optimize the PF's process of updating multicast MAC
+    - net: hns3: Optimize the VF's process of updating multicast MAC
+    - SAUCE: {topost} net: hns3: add support for serdes loopback selftest
+    - SAUCE: {topost} net: hns3: RX BD information valid only in last BD except
+      VLD bit and buffer size
+    - SAUCE: {topost} net: hns3: remove hclge_get_vector_index from
+      hclge_bind_ring_with_vector
+    - SAUCE: {topost} net: hns3: rename the interface for init_client_instance and
+      uninit_client_instance
+    - SAUCE: {topost} net: hns3: add vector status check before free vector
+    - SAUCE: {topost} net: hns3: add l4_type check for both ipv4 and ipv6
+    - SAUCE: {topost} net: hns3: remove unused head file in hnae3.c
+    - SAUCE: {topost} net: hns3: extraction an interface for state state
+      init|uninit
+    - SAUCE: {topost} net: hns3: print the ret value in error information
+    - SAUCE: {topost} net: hns3: remove the Redundant put_vector in
+      hns3_client_uninit
+    - SAUCE: {topost} net: hns3: add unlikely for error check
+    - SAUCE: {topost} net: hns3: remove back in struct hclge_hw
+    - SAUCE: {topost} net: hns3: use lower_32_bits and upper_32_bits
+    - SAUCE: {topost} net: hns3: remove unused hclge_ring_to_dma_dir
+    - SAUCE: {topost} net: hns3: remove useless code in hclge_cmd_send
+    - SAUCE: {topost} net: hns3: remove some redundant assignments
+    - SAUCE: {topost} net: hns3: simplify hclge_cmd_csq_clean
+    - SAUCE: {topost} net: hns3: using modulo for cyclic counters in
+      hclge_cmd_send
+    - SAUCE: {topost} net: hns3: remove a redundant hclge_cmd_csq_done
+    - SAUCE: {topost} net: hns3: remove some unused members of some structures
+    - SAUCE: {topost} net: hns3: give default option while dependency HNS3 set
+    - SAUCE: {topost} net: hns3: use dma_zalloc_coherent instead of
+      kzalloc/dma_map_single
+    - SAUCE: {topost} net: hns3: modify hnae_ to hnae3_
+    - SAUCE: {topost} net: hns3: fix unused function warning in VF driver
+    - SAUCE: {topost} net: hns3: remove some redundant assignments
+    - SAUCE: {topost} net: hns3: standardize the handle of return value
+    - SAUCE: {topost} net: hns3: remove extra space and brackets
+    - SAUCE: {topost} net: hns3: fix unreasonable code comments
+    - SAUCE: {topost} net: hns3: use decimal for bit offset macros
+    - SAUCE: {topost} net: hns3: modify inconsistent bit mask macros
+    - SAUCE: {topost} net: hns3: fix mislead parameter name
+    - SAUCE: {topost} net: hns3: remove unused struct member and definition
+    - SAUCE: {topost} net: hns3: Add SPDX tags to hns3 driver
+    - SAUCE: {topost} net: hns3: Add pf reset for hip08 RoCE
+    - SAUCE: {topost} net: hns3: optimize the process of notifying roce client
+    - SAUCE: {topost} net: hns3: Add calling roce callback function when link
+      status change
+    - SAUCE: {topost} net: hns3: fix tc setup when netdev is first up
+    - SAUCE: {topost} net: hns3: fix for mac pause not disable in pfc mode
+    - SAUCE: {topost} net: hns3: fix for waterline not setting correctly
+    - SAUCE: {topost} net: hns3: fix for l4 checksum offload bug
+    - SAUCE: {topost} net: hns3: fix for mailbox message truncated problem
+    - SAUCE: {topost} net: hns3: Add configure for mac minimal frame size
+    - SAUCE: {topost} net: hns3: fix warning bug when doing lp selftest
+    - SAUCE: {topost} net: hns3: fix get_vector ops in hclgevf_main module
+    - SAUCE: {topost} net: hns3: remove the warning when clear reset cause
+    - SAUCE: {topost} net: hns3: Use roce handle when calling roce callback
+      function
+    - SAUCE: {topost} net: hns3: prevent sending command during global or core
+      reset
+    - SAUCE: {topost} net: hns3: modify the order of initializeing command queue
+      register
+    - SAUCE: {topost} net: hns3: reset net device with rtnl_lock
+    - SAUCE: {topost} net: hns3: prevent to request reset frequently
+    - SAUCE: {topost} net: hns3: correct reset event status register
+    - SAUCE: {topost} net: hns3: separate roce from nic when resetting
+    - SAUCE: net: hns3: Fix for phy link issue when using marvell phy driver
+    - SAUCE: {topost} net: hns3: fix return value error in
+      hns3_reset_notify_down_enet
+    - SAUCE: {topost} net: hns3: remove unnecessary ring configuration operation
+      while resetting
+    - SAUCE: {topost} net: hns3: fix for reset_level default assignment probelm
+    - SAUCE: {topost} net: hns3: fix for using wrong mask and shift in
+      hclge_get_ring_chain_from_mbx
+    - SAUCE: {topost} net: hns3: fix comments for hclge_get_ring_chain_from_mbx
+    - SAUCE: net: hns3: Fix for VF mailbox cannot receiving PF response
+    - SAUCE: net: hns3: Fix for VF mailbox receiving unknown message
+    - SAUCE: net: hns3: Optimize PF CMDQ interrupt switching process
+
+  * CVE-2018-7755
+    - SAUCE: floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl
+
+  * Incorrect blacklist of bcm2835_wdt (LP: #1766052)
+    - [Packaging] Fix missing watchdog for Raspberry Pi
+
+  * kernel: Fix arch random implementation (LP: #1775391)
+    - s390/archrandom: Rework arch random implementation.
+
+  * [Ubuntu 1804][boston][ixgbe] EEH causes kernel BUG at /build/linux-
+    jWa1Fv/linux-4.15.0/drivers/pci/msi.c:352 (i2S) (LP: #1776389)
+    - ixgbe/ixgbevf: Free IRQ when PCI error recovery removes the device
+
+  * Cosmic update to v4.17.2 stable release (LP: #1779117)
+    - crypto: chelsio - request to HW should wrap
+    - blkdev_report_zones_ioctl(): Use vmalloc() to allocate large buffers
+    - KVM: X86: Fix reserved bits check for MOV to CR3
+    - KVM: x86: introduce linear_{read,write}_system
+    - kvm: fix typo in flag name
+    - kvm: nVMX: Enforce cpl=0 for VMX instructions
+    - 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
+    - staging: android: ion: Switch to pr_warn_once in ion_buffer_destroy
+    - NFC: pn533: don't send USB data off of the stack
+    - usbip: vhci_sysfs: fix potential Spectre v1
+    - usb-storage: Add support for FL_ALWAYS_SYNC flag in the UAS driver
+    - usb-storage: Add compatibility quirk flags for G-Technologies G-Drive
+    - Input: xpad - add GPD Win 2 Controller USB IDs
+    - phy: qcom-qusb2: Fix crash if nvmem cell not specified
+    - usb: core: message: remove extra endianness conversion in
+      usb_set_isoch_delay
+    - usb: typec: wcove: Remove dependency on HW FSM
+    - usb: gadget: function: printer: avoid wrong list handling in printer_write()
+    - usb: gadget: udc: renesas_usb3: fix double phy_put()
+    - usb: gadget: udc: renesas_usb3: should remove debugfs
+    - usb: gadget: udc: renesas_usb3: should call pm_runtime_enable() before add
+      udc
+    - usb: gadget: udc: renesas_usb3: should call devm_phy_get() before add udc
+    - usb: gadget: udc: renesas_usb3: should fail if devm_phy_get() returns error
+    - usb: gadget: udc: renesas_usb3: disable the controller's irqs for
+      reconnecting
+    - serial: sh-sci: Stop using printk format %pCr
+    - tty/serial: atmel: use port->name as name in request_irq()
+    - serial: samsung: fix maxburst parameter for DMA transactions
+    - serial: 8250: omap: Fix idling of clocks for unused uarts
+    - vmw_balloon: fixing double free when batching mode is off
+    - doc: fix sysfs ABI documentation
+    - arm64: defconfig: Enable CONFIG_PINCTRL_MT7622 by default
+    - tty: pl011: Avoid spuriously stuck-off interrupts
+    - crypto: ccree - correct host regs offset
+    - Input: goodix - add new ACPI id for GPD Win 2 touch screen
+    - Input: elan_i2c - add ELAN0612 (Lenovo v330 14IKB) ACPI ID
+    - crypto: caam - strip input zeros from RSA input buffer
+    - crypto: caam - fix DMA mapping dir for generated IV
+    - crypto: caam - fix IV DMA mapping and updating
+    - crypto: caam/qi - fix IV DMA mapping and updating
+    - crypto: caam - fix size of RSA prime factor q
+    - crypto: cavium - Fix fallout from CONFIG_VMAP_STACK
+    - crypto: cavium - Limit result reading attempts
+    - crypto: vmx - Remove overly verbose printk from AES init routines
+    - crypto: vmx - Remove overly verbose printk from AES XTS init
+    - crypto: omap-sham - fix memleak
+    - Linux 4.17.2
+
+  * Cosmic update to v4.17.1 stable release (LP: #1779116)
+    - netfilter: nf_flow_table: attach dst to skbs
+    - bnx2x: use the right constant
+    - ip6mr: only set ip6mr_table from setsockopt when ip6mr_new_table succeeds
+    - ipv6: omit traffic class when calculating flow hash
+    - l2tp: fix refcount leakage on PPPoL2TP sockets
+    - netdev-FAQ: clarify DaveM's position for stable backports
+    - net: metrics: add proper netlink validation
+    - net/packet: refine check for priv area size
+    - rtnetlink: validate attributes in do_setlink()
+    - sctp: not allow transport timeout value less than HZ/5 for hb_timer
+    - team: use netdev_features_t instead of u32
+    - vrf: check the original netdevice for generating redirect
+    - net: dsa: b53: Fix for brcm tag issue in Cygnus SoC
+    - ipmr: fix error path when ipmr_new_table fails
+    - PCI: hv: Do not wait forever on a device that has disappeared
+    - Linux 4.17.1
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: crypto: thunderx_zip: Fix fallout from
+      CONFIG_VMAP_STACK"
+    - Revert "UBUNTU: SAUCE: cred: Add clone_cred() interface"
+    - SAUCE: apparmor: userspace queries
+    - SAUCE: apparmor: patch to provide compatibility with v2.x net rules
+    - SAUCE: apparmor: af_unix mediation
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 28 Jun 2018 08:03:32 -0500
+
+linux (4.17.0-2.3) cosmic; urgency=medium
+
+  * linux: 4.17.0-2.3 -proposed tracker (LP: #1776276)
+
+  * Miscellaneous Ubuntu changes
+    - Config: remove IrDA from annotations
+    - Config: remove scsi drivers from annotations
+    - Config: remove BT_HCIBTUART from annotations
+    - Config: pstore zlib support was renamed
+    - Config: disable NVRAM for armhf on annotations
+    - Config: Disable VT on s390x
+    - Config: Update SSB and B43/B44 options
+    - Config: some options not supported on some arches anymore
+    - Config: renamed and removed options
+    - Config: TCG_CRB is required for IMA on ACPI systems
+    - Config: EXTCON_AXP288 depends on X86
+    - Config: CONFIG_FSI depends on OF
+    - Config: DRM_RCAR_LVDS now depends on DRM
+    - CONFIG: Allow CONFIG_LEDS_MLXCPLD for i386
+    - Config: Enable HINIC on arm64
+    - Config: Set PPS and PTP_1588_CLOCK as y
+    - Config: Some NF_TABLES options are built-in now
+    - Config: GENERIC_CPU for ppc64el
+    - Config: KEXEC_FILE=n for s390x
+    - Config: CRYPTO_DEFLATE is needed by PSTORE_DEFLATE_COMPRESS
+    - Config: Disable STM32 support
+    - Config: Enable FORTIFY_SOURCE for armhf
+    - Config: use STRONG instead of AUTO for CC_STACKPROTECTOR
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.17
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Mon, 11 Jun 2018 15:22:10 -0300
+
+linux (4.17.0-1.2) cosmic; urgency=medium
+
+  [ Seth Forshee ]
+  * [Config] enable EDAC_DEBUG on ARM64 (LP: #1772516)
+    - [Config]: set CONFIG_EDAC_DEBUG=y for ARM64
+
+  * Ubuntu 18.04 kernel crashed while in degraded mode (LP: #1770849)
+    - SAUCE: powerpc/perf: Fix memory allocation for core-imc based on
+      num_possible_cpus()
+
+  * 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
+
+  * Switch Build-Depends: transfig to fig2dev (LP: #1770770)
+    - [Config] update Build-Depends: transfig to fig2dev
+
+  * update-initramfs not adding i915 GuC firmware for Kaby Lake, firmware fails
+    to load (LP: #1728238)
+    - Revert "UBUNTU: SAUCE: (no-up) i915: Remove MODULE_FIRMWARE statements for
+      unreleased firmware"
+
+  * No driver for Huawei network adapters on arm64 (LP: #1769899)
+    - net-next/hinic: add arm64 support
+
+  * linux-snapdragon: reduce EPROBEDEFER noise during boot (LP: #1768761)
+    - [Config] snapdragon: DRM_I2C_ADV7511=y
+
+  * Add d-i support for Huawei NICs (LP: #1767490)
+    - d-i: add hinic to nic-modules udeb
+
+  * Acer Swift sf314-52 power button not managed  (LP: #1766054)
+    - SAUCE: platform/x86: acer-wmi: add another KEY_POWER keycode
+
+  * Include nfp driver in linux-modules (LP: #1768526)
+    - [Config] Add nfp.ko to generic inclusion list
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Import aufs driver
+    - [Config] Enable AUFS config options
+    - SAUCE: (efi-lockdown) Fix for module sig verification
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) efi: Add an EFI_SECURE_BOOT flag to indicate secure
+      boot mode
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) efi: Don't print secure boot state from the efi stub
+    - [Config] CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT=y
+    - SAUCE: (efi-lockdown) really lock down kernel under EFI secure boot
+    - SAUCE: (noup) Update spl to 0.7.5-1ubuntu3, zfs to 0.7.5-1ubuntu17
+    - enable zfs build
+
+  * Miscellaneous upstream changes
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) ima: require secure_boot rules in
+      lockdown mode"
+    - Rebased to v4.17-rc6
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 22 May 2018 14:48:13 -0300
+
+linux (4.17.0-0.1) bionic; urgency=medium
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.17-rc4
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Tue, 08 May 2018 16:38:51 -0300
+
+linux (4.17.0-0.0) bionic; urgency=medium
+
+  * Dummy entry.
+
+ -- Thadeu Lima de Souza Cascardo <cascardo@canonical.com>  Fri, 27 Apr 2018 11:01:13 -0300
+
+linux (4.16.0-4.5) bionic; urgency=medium
+
+  * [18.04 FEAT] Add kvm_stat from kernel tree (LP: #1734130)
+    - tools/kvm_stat: Fix python3 syntax
+    - tools/kvm_stat: Don't use deprecated file()
+    - tools/kvm_stat: Remove unused function
+    - [Packaging] Add linux-tools-host package for VM host tools
+    - [Config] do_tools_host=true for amd64
+
+  * [Featire] CNL: Enable RAPL support (LP: #1685712)
+    - powercap: RAPL: Add support for Cannon Lake
+
+  * Bionic update to v4.16.2 stable release (LP: #1763388)
+    - sparc64: Oracle DAX driver depends on SPARC64
+    - arp: fix arp_filter on l3slave devices
+    - net: dsa: Discard frames from unused ports
+    - net/ipv6: Increment OUTxxx counters after netfilter hook
+    - 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
+    - vlan: also check phy_driver ts_info for vlan's real device
+    - 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
+    - net_sched: fix a missing idr_remove() in u32_delete_key()
+    - nfp: use full 40 bits of the NSP buffer address
+    - Linux 4.16.2
+
+  * sky2 gigabit ethernet driver sometimes stops working after lid-open resume
+    from sleep (88E8055) (LP: #1758507) // Bionic update to v4.16.2 stable
+    release (LP: #1763388)
+    - sky2: Increase D3 delay to sky2 stops working after suspend
+
+  * Merge the linux-snapdragon kernel into bionic master/snapdragon
+    (LP: #1763040)
+    - arm64: defconfig: enable REMOTEPROC
+    - arm64: defconfig: enable QCOM audio drivers for APQ8016 and DB410c
+    - kernel: configs; add distro.config
+    - arm64: configs: enable WCN36xx
+    - kernel: distro.config: enable debug friendly USB network adpater
+    - arm64: configs: enable QCOM Venus
+    - arm64: defconfig: Enable a53/apcs and avs
+    - arm64: defconfig: enable ondemand governor as default
+    - arm64: defconfig: enable QCOM_TSENS
+    - kernel: configs: enable dm_mod and dm_crypt
+    - Force the SMD regulator driver to be compiled-in
+    - arm64: defconfig: enable CFG80211_DEFAULT_PS by default
+    - arm64: configs: enable BT_QCOMSMD
+    - kernel: configs: add more USB net drivers
+    - arm64: defconfig: disable ANALOG_TV and DIGITAL_TV
+    - arm64: configs: Enable camera drivers
+    - kernel: configs: add freq stat to sysfs
+    - arm64: defconfig: enable CONFIG_USB_CONFIGFS_F_FS by default
+    - arm64: defconfig: Enable QRTR features
+    - kernel: configs: set USB_CONFIG_F_FS in distro.config
+    - kernel: distro.config: enable 'schedutil' CPUfreq governor
+    - kernel: distro.config: enable 'fq' and 'fq_codel' qdiscs
+    - kernel: distro.config: enable 'BBR' TCP congestion algorithm
+    - arm64: defconfig: enable LEDS_QCOM_LPG
+    - HACK: drm/msm/iommu: Remove runtime_put calls in map/unmap
+    - power: avs: Add support for CPR (Core Power Reduction)
+    - power: avs: cpr: Use raw mem access for qfprom
+    - power: avs: cpr: fix with new reg_sequence structures
+    - power: avs: cpr: Register with cpufreq-dt
+    - regulator: smd: Add floor and corner operations
+    - PM / OPP: Support adjusting OPP voltages at runtime
+    - PM / OPP: Drop RCU usage in dev_pm_opp_adjust_voltage()
+    - PM / OPP: HACK: Allow to set regulator without opp_list
+    - PM / OPP: Add a helper to get an opp regulator for device
+    - cpufreq: Add apq8016 to cpufreq-dt-platdev blacklist
+    - regulator: smd: Allow REGULATOR_QCOM_SMD_RPM=m
+    - ov5645: I2C address change
+    - i2c: Add Qualcomm Camera Control Interface driver
+    - camss: vfe: Skip first four frames from sensor
+    - camss: Do not register if no cameras are present
+    - i2c-qcom-cci: Fix run queue completion timeout
+    - i2c-qcom-cci: Fix I2C address bug
+    - media: ov5645: Fix I2C address
+    - drm/bridge/adv7511: Delay clearing of HPD interrupt status
+    - HACK: drm/msm/adv7511: Don't rely on interrupts for EDID parsing
+    - leds: Add driver for Qualcomm LPG
+    - wcn36xx: Fix warning due to duplicate scan_completed notification
+    - arm64: dts: Add CPR DT node for msm8916
+    - arm64: dts: add spmi-regulator nodes
+    - arm64: dts: msm8916: Add cpufreq support
+    - arm64: dts: msm8916: Add a shared CPU opp table
+    - arm64: dts: msm8916: Add cpu cooling maps
+    - arm64: dts: pm8916: Mark the s2 regulator as always-on
+    - arm64: dts: qcom: msm8916: Add msm8916 A53 PLL DT node
+    - arm64: dts: qcom: msm8916: Use the new APCS mailbox driver
+    - arm64: dts: qcom: msm8916: Add clock properties to the APCS node
+    - dt-bindings: media: Binding document for Qualcomm Camera Control Interface
+      driver
+    - MAINTAINERS: Add Qualcomm Camera Control Interface driver
+    - DT: leds: Add Qualcomm Light Pulse Generator binding
+    - arm64: dts: qcom: msm8996: Add mpp and lpg blocks
+    - arm64: dts: qcom: Add pwm node for pm8916
+    - arm64: dts: qcom: Add user LEDs on db820c
+    - arm64: dts: qcom: Add WiFI/BT LEDs on db820c
+    - ARM: dts: qcom: Add LPG node to pm8941
+    - ARM: dts: qcom: honami: Add LPG node and RGB LED
+    - arm64: dts: qcom: Add Camera Control Interface support
+    - arm64: dts: qcom: Add apps_iommu vfe child node
+    - arm64: dts: qcom: Add camss device node
+    - arm64: dts: qcom: Add ov5645 device nodes
+    - arm64: dts: msm8916: Fix camera sensors I2C addresses
+    - arm: dts: qcom: db410c: Enable PWM signal on MPP4
+    - packaging: arm64: add a uboot flavour - part1
+    - packaging: arm64: add a uboot flavour - part2
+    - packaging: arm64: add a uboot flavour - part3
+    - packaging: arm64: add a uboot flavour - part4
+    - packaging: arm64: add a uboot flavour - part5
+    - packaging: arm64: rename uboot flavour to snapdragon
+    - [Config] updateconfigs after qcomlt import
+    - [Config] arm64: snapdragon: COMMON_CLK_QCOM=y
+    - [Config] arm64: snapdragon: MSM_GCC_8916=y
+    - [Config] arm64: snapdragon: REGULATOR_FIXED_VOLTAGE=y
+    - [Config] arm64: snapdragon: PINCTRL_MSM8916=y
+    - [Config] arm64: snapdragon: HWSPINLOCK_QCOM=y
+    - [Config] arm64: snapdragon: SPMI=y, SPMI_MSM_PMIC_ARB=y
+    - [Config] arm64: snapdragon: REGMAP_SPMI=y, PINCTRL_QCOM_SPMI_PMIC=y
+    - [Config] arm64: snapdragon: REGULATOR_QCOM_SPMI=y
+    - [Config] arm64: snapdragon: MFD_SPMI_PMIC=y
+    - [Config] arm64: snapdragon: QCOM_SMEM=y
+    - [Config] arm64: snapdragon: RPMSG=y, RPMSG_QCOM_SMD=y
+    - [Config] arm64: snapdragon: QCOM_SMD_RPM=y, REGULATOR_QCOM_SMD_RPM=y
+    - [Config] arm64: snapdragon: QCOM_CLK_SMD_RPM=y
+    - [Config] arm64: snapdragon: QCOM_BAM_DMA=y
+    - [Config] arm64: snapdragon: QCOM_HIDMA=y, QCOM_HIDMA_MGMT=y
+    - [Config] arm64: snapdragon: QCOM_CPR=y
+    - [Config] arm64: snapdragon: QCOM_QFPROM=y, QCOM_TSENS=y
+    - [Config] arm64: snapdragon: MMC_SDHCI=y, MMC_SDHCI_PLTFM=y, MMC_SDHCI_MSM=y
+    - [Config] turn off DRM_MSM_REGISTER_LOGGING
+    - [Config] arm64: snapdragon: I2C_QUP=y
+    - [Config] arm64: snapdragon: SPI_QUP=y
+    - [Config] arm64: snapdragon: USB_ULPI_BUS=y, PHY_QCOM_USB_HS=y
+    - [Config] arm64: snapdragon: QCOM_APCS_IPC=y
+    - [Config] arm64: snapdragon: QCOM_WCNSS_CTRL=y
+    - [Config] arm64: snapdragon: QCOM_SMSM=y
+    - [Config] arm64: snapdragon: QCOM_SMP2P=y
+    - [Config] arm64: snapdragon: DRM_MSM=y
+    - [Config] arm64: snapdragon: SND_SOC=y
+    - [Config] arm64: snapdragon: QCOM_WCNSS_PIL=m
+    - [Config] arm64: snapdragon: INPUT_PM8941_PWRKEY=y
+    - [Config] arm64: snapdragon: MEDIA_SUBDRV_AUTOSELECT=y, VIDEO_OV5645=m
+    - [Config] arm64: snapdragon: SND_SOC_APQ8016_SBC=y, SND_SOC_LPASS_APQ8016=y
+    - [Config] arm64: snapdragon: SND_SOC_MSM8916_WCD_ANALOG=y,
+      SND_SOC_MSM8916_WCD_DIGITAL=y
+    - SAUCE: media: ov5645: skip address change if dt addr == default addr
+    - SAUCE: drm/msm/adv7511: wrap hacks under CONFIG_ADV7511_SNAPDRAGON_HACKS
+      #ifdefs
+    - [Config] arm64: snapdragon: ADV7511_SNAPDRAGON_HACKS=y
+    - [Packaging] fix up snapdragon abi paths
+
+  * LSM stacking patches for bionic (LP: #1763062)
+    - SAUCE: LSM stacking: procfs: add smack subdir to attrs
+    - SAUCE: LSM stacking: LSM: Manage credential security blobs
+    - SAUCE: LSM stacking: LSM: Manage file security blobs
+    - SAUCE: LSM stacking: LSM: Manage task security blobs
+    - SAUCE: LSM stacking: LSM: Manage remaining security blobs
+    - SAUCE: LSM stacking: LSM: General stacking
+    - SAUCE: LSM stacking: fixup initialize task->security
+    - SAUCE: LSM stacking: fixup: alloc_task_ctx is dead code
+    - SAUCE: LSM stacking: add support for stacking getpeersec_stream
+    - SAUCE: LSM stacking: add stacking support to apparmor network hooks
+    - SAUCE: LSM stacking: fixup apparmor stacking enablement
+    - SAUCE: LSM stacking: fixup stacking kconfig
+    - SAUCE: LSM stacking: allow selecting multiple LSMs using kernel boot params
+    - SAUCE: LSM stacking: provide prctl interface for setting context
+    - SAUCE: LSM stacking: inherit current display LSM
+    - SAUCE: LSM stacking: keep an index for each registered LSM
+    - SAUCE: LSM stacking: verify display LSM
+    - SAUCE: LSM stacking: provide a way to specify the default display lsm
+    - SAUCE: LSM stacking: make sure LSM blob align on 64 bit boundaries
+    - SAUCE: LSM stacking: add /proc/<pid>/attr/display_lsm
+    - SAUCE: LSM stacking: add Kconfig to set default display LSM
+    - SAUCE: LSM stacking: add configs for LSM stacking
+    - SAUCE: LSM stacking: add apparmor and selinux proc dirs
+    - SAUCE: LSM stacking: remove procfs context interface
+
+  * linux 4.13.0-13.14 ADT test failure with linux 4.13.0-13.14
+    (LP: #1720779) // LSM stacking patches for bionic (LP: #1763062)
+    - SAUCE: LSM stacking: check for invalid zero sized writes
+
+  * Support cq/rq record doorbell for RDMA on HSilicon hip08 systems
+    (LP: #1762755)
+    - RDMA/hns: Support rq record doorbell for the user space
+    - RDMA/hns: Support cq record doorbell for the user space
+    - RDMA/hns: Support rq record doorbell for kernel space
+    - RDMA/hns: Support cq record doorbell for kernel space
+    - RDMA/hns: Fix cqn type and init resp
+    - RDMA/hns: Fix init resp when alloc ucontext
+    - RDMA/hns: Fix cq record doorbell enable in kernel
+
+  * Replace LPC patchset with upstream version (LP: #1762758)
+    - Revert "UBUNTU: SAUCE: MAINTAINERS: Add maintainer for HiSilicon LPC driver"
+    - Revert "UBUNTU: SAUCE: HISI LPC: Add ACPI support"
+    - Revert "UBUNTU: SAUCE: ACPI / scan: do not enumerate Indirect IO host
+      children"
+    - Revert "UBUNTU: SAUCE: HISI LPC: Support the LPC host on Hip06/Hip07 with DT
+      bindings"
+    - Revert "UBUNTU: SAUCE: OF: Add missing I/O range exception for indirect-IO
+      devices"
+    - Revert "UBUNTU: SAUCE: PCI: Apply the new generic I/O management on PCI IO
+      hosts"
+    - Revert "UBUNTU: SAUCE: PCI: Add fwnode handler as input param of
+      pci_register_io_range()"
+    - Revert "UBUNTU: SAUCE: PCI: Remove unused __weak attribute in
+      pci_register_io_range()"
+    - Revert "UBUNTU: SAUCE: LIB: Introduce a generic PIO mapping method"
+    - lib: Add generic PIO mapping method
+    - PCI: Remove __weak tag from pci_register_io_range()
+    - PCI: Add fwnode handler as input param of pci_register_io_range()
+    - PCI: Apply the new generic I/O management on PCI IO hosts
+    - of: Add missing I/O range exception for indirect-IO devices
+    - HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings
+    - ACPI / scan: Rename acpi_is_serial_bus_slave() for more general use
+    - ACPI / scan: Do not enumerate Indirect IO host children
+    - HISI LPC: Add ACPI support
+    - MAINTAINERS: Add John Garry as maintainer for HiSilicon LPC driver
+
+  * Enable Tunneled Operations on POWER9 (LP: #1762448)
+    - powerpc/powernv: Enable tunneled operations
+    - cxl: read PHB indications from the device tree
+
+  * PSL traces reset after PERST for debug AFU image (LP: #1762462)
+    - cxl: Enable NORST bit in PSL_DEBUG register for PSL9
+
+  * NFS + sec=krb5 is broken (LP: #1759791)
+    - sunrpc: remove incorrect HMAC request initialization
+
+  * Raspberry Pi 3 microSD support missing from the installer (LP: #1729128)
+    - d-i: add bcm2835 to block-modules
+
+  * Backport USB core quirks (LP: #1762695)
+    - usb: core: Add "quirks" parameter for usbcore
+    - usb: core: Copy parameter string correctly and remove superfluous null check
+    - usb: core: Add USB_QUIRK_DELAY_CTRL_MSG to usbcore quirks
+
+  * [Ubuntu 18.04] cryptsetup: 'device-mapper: reload ioctl on  failed' when
+    setting up a second end-to-end encrypted disk (LP: #1762353)
+    - SAUCE: s390/crypto: Adjust s390 aes and paes cipher
+
+  * System Z {kernel} UBUNTU18.04 wrong kernel config (LP: #1762719)
+    - s390: move nobp parameter functions to nospec-branch.c
+    - s390: add automatic detection of the spectre defense
+    - s390: report spectre mitigation via syslog
+    - s390: add sysfs attributes for spectre
+    - [Config] CONFIG_EXPOLINE_AUTO=y, CONFIG_KERNEL_NOBP=n for s390
+    - s390: correct nospec auto detection init order
+
+  * Additional spectre and meltdown patches (LP: #1760099) // CVE-2017-5715
+    - powerpc/64s: Wire up cpu_show_spectre_v2()
+
+  * Additional spectre and meltdown patches (LP: #1760099) // CVE-2017-5753
+    - powerpc/64s: Wire up cpu_show_spectre_v1()
+
+  * Additional spectre and meltdown patches (LP: #1760099) // CVE-2017-5754
+    - 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/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()
+
+  * Additional spectre and meltdown patches (LP: #1760099) // CVE-2017-5715 //
+    CVE-2017-5753 // CVE-2017-5754
+    - 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
+
+  * Hisilicon network subsystem 3 support (LP: #1761610)
+    - net: hns3: export pci table of hclge and hclgevf to userspace
+    - d-i: Add hns3 drivers to nic-modules
+
+  * "ip a" command on a guest VM shows UNKNOWN status (LP: #1761534)
+    - virtio-net: Fix operstate for virtio when no VIRTIO_NET_F_STATUS
+
+  * perf vendor events arm64: Enable JSON events for ThunderX2 B0 (LP: #1760712)
+    - perf vendor events: Drop incomplete multiple mapfile support
+    - perf vendor events: Fix error code in json_events()
+    - perf vendor events: Drop support for unused topic directories
+    - perf vendor events: Add support for pmu events vendor subdirectory
+    - perf vendor events arm64: Relocate ThunderX2 JSON to cavium subdirectory
+    - perf vendor events arm64: Relocate Cortex A53 JSONs to arm subdirectory
+    - perf vendor events: Add support for arch standard events
+    - perf vendor events arm64: Add armv8-recommended.json
+    - perf vendor events arm64: Fixup ThunderX2 to use recommended events
+    - perf vendor events arm64: fixup A53 to use recommended events
+    - perf vendor events arm64: add HiSilicon hip08 JSON file
+    - perf vendor events arm64: Enable JSON events for ThunderX2 B0
+
+  * Warning "cache flush timed out!" seen when unloading the cxl driver
+    (LP: #1762367)
+    - cxl: Check if PSL data-cache is available before issue flush request
+
+  * Bionic update to v4.16.1 stable release (LP: #1763170)
+    - bitmap: fix memset optimization on big-endian systems
+    - 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
+    - serial: 8250: Add Nuvoton NPCM UART
+    - mei: remove dev_err message on an unsupported ioctl
+    - /dev/mem: Avoid overwriting "err" in read_mem()
+    - media: usbtv: prevent double free in error case
+    - parport_pc: Add support for WCH CH382L PCI-E single parallel port card.
+    - crypto: lrw - Free rctx->ext with kzfree
+    - crypto: ccp - Fill the result buffer only on digest, finup, and final ops
+    - crypto: talitos - don't persistently map req_ctx->hw_context and
+      req_ctx->buf
+    - crypto: inside-secure - fix clock management
+    - crypto: testmgr - Fix incorrect values in PKCS#1 test vector
+    - crypto: talitos - fix IPsec cipher in length
+    - crypto: ahash - Fix early termination in hash walk
+    - crypto: caam - Fix null dereference at error path
+    - crypto: ccp - return an actual key size from RSA max_size callback
+    - crypto: arm,arm64 - Fix random regeneration of S_shipped
+    - crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one
+    - Bluetooth: hci_bcm: Add 6 new ACPI HIDs
+    - Btrfs: fix unexpected cow in run_delalloc_nocow
+    - siox: fix possible buffer overflow in device_add_store
+    - staging: comedi: ni_mio_common: ack ai fifo error interrupts.
+    - Revert "base: arch_topology: fix section mismatch build warnings"
+    - Input: ALPS - fix TrackStick detection on Thinkpad L570 and Latitude 7370
+    - 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
+    - Fix slab name "biovec-(1<<(21-12))"
+    - signal: Correct the offset of si_pkey and si_lower in struct siginfo on m68k
+    - Linux 4.16.1
+
+  * [18.04][config] regression: nvme and nvme_core couldn't be built as modules
+    starting 4.15-rc2 (LP: #1759893)
+    - SAUCE: Revert "lightnvm: include NVM Express driver if OCSSD is selected for
+      build"
+    - [Config] CONFIG_BLK_DEV_NMVE=m
+
+  * FFe: Enable configuring resume offset via sysfs (LP: #1760106)
+    - PM / hibernate: Make passing hibernate offsets more friendly
+
+  * Ubuntu18.04:POWER9:DD2.2 - Unable to start a KVM guest with default machine
+    type(pseries-bionic) complaining "KVM implementation does not support
+    Transactional Memory, try cap-htm=off" (kvm) (LP: #1752026)
+    - powerpc: Use feature bit for RTC presence rather than timebase presence
+    - powerpc: Book E: Remove unused CPU_FTR_L2CSR bit
+    - powerpc: Free up CPU feature bits on 64-bit machines
+    - powerpc: Add CPU feature bits for TM bug workarounds on POWER9 v2.2
+    - powerpc/powernv: Provide a way to force a core into SMT4 mode
+    - KVM: PPC: Book3S HV: Work around transactional memory bugs in POWER9
+    - KVM: PPC: Book3S HV: Work around XER[SO] bug in fake suspend mode
+    - KVM: PPC: Book3S HV: Work around TEXASR bug in fake suspend state
+
+  * [Feature][CFL][ICL] [CNL]Thunderbolt support (Titan Ridge) (LP: #1730775)
+    - thunderbolt: Resume control channel after hibernation image is created
+    - thunderbolt: Serialize PCIe tunnel creation with PCI rescan
+    - thunderbolt: Handle connecting device in place of host properly
+    - thunderbolt: Do not overwrite error code when domain adding fails
+    - thunderbolt: Wait a bit longer for root switch config space
+    - thunderbolt: Wait a bit longer for ICM to authenticate the active NVM
+    - thunderbolt: Handle rejected Thunderbolt devices
+    - thunderbolt: Factor common ICM add and update operations out
+    - thunderbolt: Correct function name in kernel-doc comment
+    - thunderbolt: Add tb_switch_get()
+    - thunderbolt: Add tb_switch_find_by_route()
+    - thunderbolt: Add tb_xdomain_find_by_route()
+    - thunderbolt: Add constant for approval timeout
+    - thunderbolt: Move driver ready handling to struct icm
+    - thunderbolt: Add 'boot' attribute for devices
+    - thunderbolt: Add support for preboot ACL
+    - thunderbolt: Introduce USB only (SL4) security level
+    - thunderbolt: Add support for Intel Titan Ridge
+
+  * QCA9377 requires more IRAM banks for its new firmware (LP: #1748345)
+    - ath10k: update the IRAM bank number for QCA9377
+
+  * Fix an issue that when system in S3, USB keyboard can't wake up the system.
+    (LP: #1759511)
+    - ACPI / PM: Allow deeper wakeup power states with no _SxD nor _SxW
+
+  * cxl: Fix timebase synchronization status on POWER9 missing (CAPI)
+    (LP: #1757228)
+    - cxl: Fix timebase synchronization status on P9
+
+  * [Feature]Update Ubuntu 18.04 lpfc FC driver with 32/64GB HBA support and bug
+    fixes (LP: #1752182)
+    - scsi: lpfc: Fix frequency of Release WQE CQEs
+    - scsi: lpfc: Increase CQ and WQ sizes for SCSI
+    - scsi: lpfc: move placement of target destroy on driver detach
+    - scsi: lpfc: correct debug counters for abort
+    - scsi: lpfc: Add WQ Full Logic for NVME Target
+    - scsi: lpfc: Fix PRLI handling when topology type changes
+    - scsi: lpfc: Fix IO failure during hba reset testing with nvme io.
+    - scsi: lpfc: Fix RQ empty firmware trap
+    - scsi: lpfc: Allow set of maximum outstanding SCSI cmd limit for a target
+    - scsi: lpfc: Fix soft lockup in lpfc worker thread during LIP testing
+    - scsi: lpfc: Fix issue_lip if link is disabled
+    - scsi: lpfc: Indicate CONF support in NVMe PRLI
+    - scsi: lpfc: Fix SCSI io host reset causing kernel crash
+    - scsi: lpfc: Validate adapter support for SRIU option
+    - scsi: lpfc: Fix header inclusion in lpfc_nvmet
+    - scsi: lpfc: Treat SCSI Write operation Underruns as an error
+    - scsi: lpfc: Fix nonrecovery of NVME controller after cable swap.
+    - scsi: lpfc: update driver version to 11.4.0.7
+    - scsi: lpfc: Update 11.4.0.7 modified files for 2018 Copyright
+    - scsi: lpfc: Rework lpfc to allow different sli4 cq and eq handlers
+    - scsi: lpfc: Rework sli4 doorbell infrastructure
+    - scsi: lpfc: Add SLI-4 if_type=6 support to the code base
+    - scsi: lpfc: Add push-to-adapter support to sli4
+    - scsi: lpfc: Add PCI Ids for if_type=6 hardware
+    - scsi: lpfc: Add 64G link speed support
+    - scsi: lpfc: Add if_type=6 support for cycling valid bits
+    - scsi: lpfc: Enable fw download on if_type=6 devices
+    - scsi: lpfc: Add embedded data pointers for enhanced performance
+    - scsi: lpfc: Fix nvme embedded io length on new hardware
+    - scsi: lpfc: Work around NVME cmd iu SGL type
+    - scsi: lpfc: update driver version to 12.0.0.0
+    - scsi: lpfc: Change Copyright of 12.0.0.0 modified files to 2018
+    - scsi: lpfc: use __raw_writeX on DPP copies
+    - scsi: lpfc: Add missing unlock in WQ full logic
+
+  * /dev/bcache/by-uuid links not created after reboot (LP: #1729145)
+    - SAUCE: (no-up) bcache: decouple emitting a cached_dev CHANGE uevent
+
+  * 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
+
+  * Use med_with_dipm SATA LPM to save more power for mobile platforms
+    (LP: #1759547)
+    - [Config] CONFIG_SATA_MOBILE_LPM_POLICY=3
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Only install cloud init files when do_tools_common=true
+    - SAUCE: Import aufs driver
+    - [Config] Enable AUFS config options
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 12 Apr 2018 09:30:56 -0500
+
+linux (4.16.0-3.4) bionic; urgency=medium
+
+  * Allow multiple mounts of zfs datasets (LP: #1759848)
+    - SAUCE: Allow mounting datasets more than once (LP: #1759848)
+
+  * zfs system process hung on container stop/delete (LP: #1754584)
+    - SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)
+    - Revert "UBUNTU: SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)"
+    - SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)
+
+  * ubuntu_zram_smoke test will cause soft lockup on Artful ThunderX ARM64
+    (LP: #1755073)
+    - SAUCE: crypto: thunderx_zip: Fix fallout from CONFIG_VMAP_STACK
+
+  * CAPI Flash (cxlflash) update (LP: #1752672)
+    - SAUCE: cxlflash: Preserve number of interrupts for master contexts
+    - SAUCE: cxlflash: Avoid clobbering context control register value
+    - SAUCE: cxlflash: Add argument identifier names
+    - SAUCE: cxlflash: Introduce OCXL backend
+    - SAUCE: cxlflash: Hardware AFU for OCXL
+    - SAUCE: cxlflash: Read host function configuration
+    - SAUCE: cxlflash: Setup function acTag range
+    - SAUCE: cxlflash: Read host AFU configuration
+    - SAUCE: cxlflash: Setup AFU acTag range
+    - SAUCE: cxlflash: Setup AFU PASID
+    - SAUCE: cxlflash: Adapter context support for OCXL
+    - SAUCE: cxlflash: Use IDR to manage adapter contexts
+    - SAUCE: cxlflash: Support adapter file descriptors for OCXL
+    - SAUCE: cxlflash: Support adapter context discovery
+    - SAUCE: cxlflash: Support image reload policy modification
+    - SAUCE: cxlflash: MMIO map the AFU
+    - SAUCE: cxlflash: Support starting an adapter context
+    - SAUCE: cxlflash: Support process specific mappings
+    - SAUCE: cxlflash: Support AFU state toggling
+    - SAUCE: cxlflash: Support reading adapter VPD data
+    - SAUCE: cxlflash: Setup function OCXL link
+    - SAUCE: cxlflash: Setup OCXL transaction layer
+    - SAUCE: cxlflash: Support process element lifecycle
+    - SAUCE: cxlflash: Support AFU interrupt management
+    - SAUCE: cxlflash: Support AFU interrupt mapping and registration
+    - SAUCE: cxlflash: Support starting user contexts
+    - SAUCE: cxlflash: Support adapter context polling
+    - SAUCE: cxlflash: Support adapter context reading
+    - SAUCE: cxlflash: Support adapter context mmap and release
+    - SAUCE: cxlflash: Support file descriptor mapping
+    - SAUCE: cxlflash: Introduce object handle fop
+    - SAUCE: cxlflash: Setup LISNs for user contexts
+    - SAUCE: cxlflash: Setup LISNs for master contexts
+    - SAUCE: cxlflash: Update synchronous interrupt status bits
+    - SAUCE: cxlflash: Introduce OCXL context state machine
+    - SAUCE: cxlflash: Register for translation errors
+    - SAUCE: cxlflash: Support AFU reset
+    - SAUCE: cxlflash: Enable OCXL operations
+
+  * [Artful][Wyse 3040] System hang when trying to enable an offlined CPU core
+    (LP: #1736393)
+    - SAUCE: drm/i915:Don't set chip specific data
+    - SAUCE: drm/i915: make previous commit affects Wyse 3040 only
+
+  * zed process consuming 100% cpu (LP: #1751796)
+    - SAUCE: Fix ioctl loop-spin in zed (LP: #1751796)
+
+  * Ubuntu18.04:PowerPC - Set Transparent Huge Pages (THP) by default to
+    "always" (LP: #1753708)
+    - Config: Set TRANSPARENT_HUGEPAGE_ALWAYS=y on ppc64el
+
+  * retpoline hints: primary infrastructure and initial hints (LP: #1758856)
+    - [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: apm -- annotate indirect calls within
+      firmware_restrict_branch_speculation_{start,end}
+    - SAUCE: EFI -- annotate indirect calls within
+      firmware_restrict_branch_speculation_{start,end}
+    - SAUCE: early/late -- annotate indirect calls in early/late initialisation
+      code
+    - SAUCE: vga_set_mode -- avoid jump tables
+    - [Config] retpoine -- switch to new format
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] final-checks -- remove check for empty retpoline files
+    - [Packaging] skip cloud tools packaging when not building package
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.16
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 02 Apr 2018 16:15:36 -0500
+
+linux (4.16.0-2.3) bionic; urgency=medium
+
+  * devpts: handle bind-mounts (LP: #1755857)
+    - SAUCE: devpts: hoist out check for DEVPTS_SUPER_MAGIC
+    - SAUCE: devpts: resolve devpts bind-mounts
+    - SAUCE: devpts: comment devpts_mntget()
+    - SAUCE: selftests: add devpts selftests
+
+  * [bionic][arm64] d-i: add hisi_sas_v3_hw to scsi-modules (LP: #1756103)
+    - d-i: add hisi_sas_v3_hw to scsi-modules
+
+  * [Bionic][ARM64] PCI and SAS driver patches for hip08 SoCs (LP: #1756094)
+    - SAUCE: scsi: hisi_sas: config for hip08 ES
+    - SAUCE: scsi: hisi_sas: export device table of v3 hw to userspace
+
+  * s390/crypto: Fix kernel crash on aes_s390 module remove (LP: #1753424)
+    - SAUCE: s390/crypto: Fix kernel crash on aes_s390 module remove.
+
+  * Fix ARC hit rate (LP: #1755158)
+    - SAUCE: Fix ARC hit rate (LP: #1755158)
+
+  * ZFS setgid broken on 0.7 (LP: #1753288)
+    - SAUCE: Fix ZFS setgid
+
+  * CONFIG_EFI=y on armhf (LP: #1726362)
+    - [Config] CONFIG_EFI=y on armhf, reconcile secureboot EFI settings
+
+  * [Feature] Add xHCI debug device support in the driver (LP: #1730832)
+    - [Config] CONFIG_USB_XHCI_DBGCAP=y
+
+  * retpoline: ignore %cs:0xNNN constant indirections (LP: #1752655)
+    - [Packaging] retpoline -- elide %cs:0xNNNN constants on i386
+    - [Config] retpoline -- clean up i386 retpoline files
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] retpoline-extract: flag *0xNNN(%reg) branches
+    - [Config] fix up retpoline abi files
+    - [Config] fix up retpoline abi files
+    - d-i: Add netsec to nic-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.16-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 19 Mar 2018 14:09:49 -0500
+
+linux (4.16.0-1.2) bionic; urgency=medium
+
+  * Driver not found in Ubuntu kernel does not detect interface (LP: #1745927)
+    - d-i: add cxgb4 to nic-modules
+
+  * Support low-pin-count devices on Hisilicon SoCs (LP: #1677319)
+    - [Config] CONFIG_INDIRECT_PIO=y
+    - SAUCE: LIB: Introduce a generic PIO mapping method
+    - SAUCE: PCI: Remove unused __weak attribute in pci_register_io_range()
+    - SAUCE: PCI: Add fwnode handler as input param of pci_register_io_range()
+    - SAUCE: PCI: Apply the new generic I/O management on PCI IO hosts
+    - SAUCE: OF: Add missing I/O range exception for indirect-IO devices
+    - [Config] CONFIG_HISILICON_LPC=y
+    - SAUCE: HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings
+    - SAUCE: ACPI / scan: do not enumerate Indirect IO host children
+    - SAUCE: HISI LPC: Add ACPI support
+    - SAUCE: MAINTAINERS: Add maintainer for HiSilicon LPC driver
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: tools: use CC for linking acpi tools
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.16-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 28 Feb 2018 10:17:23 -0600
+
+linux (4.16.0-0.1) bionic; urgency=medium
+
+  * 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
+
+  * Miscellaneous upstream changes
+    - disable vbox build
+    - Disable zfs build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.16-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 22 Feb 2018 08:58:57 -0600
+
+linux (4.16.0-0.0) bionic; urgency=medium
+
+  * Dummy entry
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 21 Feb 2018 14:33:13 -0600
+
+linux (4.15.0-10.11) bionic; urgency=medium
+
+  * linux: 4.15.0-10.11 -proposed tracker (LP: #1749250)
+
+  * "swiotlb: coherent allocation failed" dmesg spam with linux 4.15.0-9.10
+    (LP: #1749202)
+    - swiotlb: suppress warning when __GFP_NOWARN is set
+    - drm/ttm: specify DMA_ATTR_NO_WARN for huge page pools
+
+  * linux-tools: perf incorrectly linking libbfd (LP: #1748922)
+    - SAUCE: tools -- add ability to disable libbfd
+    - [Packaging] correct disablement of libbfd
+
+  * [Artful] Realtek ALC225: 2 secs noise when a headset plugged in
+    (LP: #1744058)
+    - ALSA: hda/realtek - update ALC225 depop optimize
+
+  * [Artful] Support headset mode for DELL WYSE (LP: #1723913)
+    - SAUCE: ALSA: hda/realtek - Add support headset mode for DELL WYSE
+
+  * headset mic can't be detected on two Dell machines (LP: #1748807)
+    - ALSA: hda/realtek - Support headset mode for ALC215/ALC285/ALC289
+    - ALSA: hda - Fix headset mic detection problem for two Dell machines
+
+  * Bionic update to v4.15.3 stable release (LP: #1749191)
+    - ip6mr: fix stale iterator
+    - net: igmp: add a missing rcu locking section
+    - qlcnic: fix deadlock bug
+    - qmi_wwan: Add support for Quectel EP06
+    - 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
+    - ipv6: addrconf: break critical section in addrconf_verify_rtnl()
+    - ipv6: change route cache aging logic
+    - Revert "defer call to mem_cgroup_sk_alloc()"
+    - net: ipv6: send unsolicited NA after DAD
+    - rocker: fix possible null pointer dereference in
+      rocker_router_fib_event_work
+    - tcp_bbr: fix pacing_gain to always be unity when using lt_bw
+    - cls_u32: add missing RCU annotation.
+    - ipv6: Fix SO_REUSEPORT UDP socket with implicit sk_ipv6only
+    - soreuseport: fix mem leak in reuseport_add_sock()
+    - net_sched: get rid of rcu_barrier() in tcf_block_put_ext()
+    - net: sched: fix use-after-free in tcf_block_put_ext
+    - media: mtk-vcodec: add missing MODULE_LICENSE/DESCRIPTION
+    - media: soc_camera: soc_scale_crop: add missing
+      MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - media: tegra-cec: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - gpio: uniphier: fix mismatch between license text and MODULE_LICENSE
+    - crypto: tcrypt - fix S/G table for test_aead_speed()
+    - Linux 4.15.3
+
+  * 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
+
+  * ethtool -p fails to light NIC LED on HiSilicon D05 systems (LP: #1748567)
+    - net: hns: add ACPI mode support for ethtool -p
+
+  * CVE-2017-5715 (Spectre v2 Intel)
+    - [Packaging] retpoline files must be sorted
+    - [Packaging] pull in retpoline files
+
+  * [Feature] PXE boot with Intel Omni-Path (LP: #1712031)
+    - d-i: Add hfi1 to nic-modules
+
+  * CVE-2017-5715 (Spectre v2 retpoline)
+    - [Packaging] retpoline -- add call site validation
+    - [Config] disable retpoline checks for first upload
+
+  * Do not duplicate changelog entries assigned to more than one bug or CVE
+    (LP: #1743383)
+    - [Packaging] git-ubuntu-log -- handle multiple bugs/cves better
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 13 Feb 2018 11:33:58 -0600
+
+linux (4.15.0-9.10) bionic; urgency=medium
+
+  * linux: 4.15.0-9.10 -proposed tracker (LP: #1748244)
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] tests -- remove gcc-multilib dependency for arm64
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 08 Feb 2018 11:25:04 -0600
+
+linux (4.15.0-8.9) bionic; urgency=medium
+
+  * linux: 4.15.0-8.9 -proposed tracker (LP: #1748075)
+
+  * Bionic update to v4.15.2 stable release (LP: #1748072)
+    - KVM: x86: Make indirect calls in emulator speculation safe
+    - KVM: VMX: Make indirect call speculation safe
+    - module/retpoline: Warn about missing retpoline in module
+    - x86/cpufeatures: Add CPUID_7_EDX CPUID leaf
+    - x86/cpufeatures: Add Intel feature bits for Speculation Control
+    - x86/cpufeatures: Add AMD feature bits for Speculation Control
+    - x86/msr: Add definitions for new speculation control MSRs
+    - 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/alternative: Print unadorned pointers
+    - x86/nospec: Fix header guards names
+    - x86/bugs: Drop one "mitigation" from dmesg
+    - x86/cpu/bugs: Make retpoline module warning conditional
+    - x86/cpufeatures: Clean up Spectre v2 related CPUID flags
+    - x86/retpoline: Simplify vmexit_fill_RSB()
+    - x86/speculation: Simplify indirect_branch_prediction_barrier()
+    - auxdisplay: img-ascii-lcd: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - iio: adc/accel: Fix up module licenses
+    - pinctrl: pxa: pxa2xx: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - ASoC: pcm512x: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE
+    - KVM: nVMX: Eliminate vmcs02 pool
+    - KVM: VMX: introduce alloc_loaded_vmcs
+    - objtool: Improve retpoline alternative handling
+    - objtool: Add support for alternatives at the end of a section
+    - objtool: Warn on stripped section symbol
+    - x86/mm: Fix overlap of i386 CPU_ENTRY_AREA with FIX_BTMAP
+    - x86/spectre: Check CONFIG_RETPOLINE in command line parser
+    - x86/entry/64: Remove the SYSCALL64 fast path
+    - x86/entry/64: Push extra regs right away
+    - x86/asm: Move 'status' from thread_struct to thread_info
+    - Documentation: Document array_index_nospec
+    - array_index_nospec: Sanitize speculative array de-references
+    - x86: Implement array_index_mask_nospec
+    - x86: Introduce barrier_nospec
+    - 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
+    - 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/spectre: Fix spelling mistake: "vunerable"-> "vulnerable"
+    - x86/cpuid: Fix up "virtual" IBRS/IBPB/STIBP feature bits on Intel
+    - x86/speculation: Use Indirect Branch Prediction Barrier in context switch
+    - x86/paravirt: Remove 'noreplace-paravirt' cmdline option
+    - KVM: VMX: make MSR bitmaps per-VCPU
+    - x86/kvm: Update spectre-v1 mitigation
+    - x86/retpoline: Avoid retpolines for built-in __init functions
+    - x86/spectre: Simplify spectre_v2 command line parsing
+    - x86/pti: Mark constant arrays as __initconst
+    - x86/speculation: Fix typo IBRS_ATT, which should be IBRS_ALL
+    - KVM/x86: Update the reverse_cpuid list to include CPUID_7_EDX
+    - KVM/x86: Add IBPB support
+    - KVM/VMX: Emulate MSR_IA32_ARCH_CAPABILITIES
+    - KVM/VMX: Allow direct access to MSR_IA32_SPEC_CTRL
+    - KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
+    - serial: core: mark port as initialized after successful IRQ change
+    - fpga: region: release of_parse_phandle nodes after use
+    - Linux 4.15.2
+
+  * Add support for the NIC on SynQuacer E-Series boards (LP: #1747792)
+    - net: phy: core: remove now uneeded disabling of interrupts
+    - [Config] CONFIG_NET_VENDOR_SOCIONEXT=y & CONFIG_SNI_NETSEC=m
+    - net: socionext: Add Synquacer NetSec driver
+    - net: socionext: include linux/io.h to fix build
+    - net: socionext: Fix error return code in netsec_netdev_open()
+
+  * [Artful/Bionic] [Config] enable EDAC_GHES for ARM64 (LP: #1747746)
+    - [Config] CONFIG_EDAC_GHES=y
+
+  * support thunderx2 vendor pmu events (LP: #1747523)
+    - perf pmu: Pass pmu as a parameter to get_cpuid_str()
+    - perf tools arm64: Add support for get_cpuid_str function.
+    - perf pmu: Add helper function is_pmu_core to detect PMU CORE devices
+    - perf vendor events arm64: Add ThunderX2 implementation defined pmu core
+      events
+    - perf pmu: Add check for valid cpuid in perf_pmu__find_map()
+
+  * linux 4.14.0-7.9 ADT test failure with linux 4.14.0-7.9 (LP: #1732463)
+    - SAUCE: mm: disable vma based swap readahead by default
+    - SAUCE: mm: fix memory hotplug in ZONE_HIGHMEM
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Fix CONFIG_PROFILE_ALL_BRANCHES annotations
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 07 Feb 2018 21:13:27 -0600
+
+linux (4.15.0-7.8) bionic; urgency=medium
+
+  * Bionic update to v4.15.1 stable release (LP: #1747169)
+    - Bluetooth: hci_serdev: Init hci_uart proto_lock to avoid oops
+    - tools/gpio: Fix build error with musl libc
+    - gpio: stmpe: i2c transfer are forbiden in atomic context
+    - gpio: Fix kernel stack leak to userspace
+    - ALSA: hda - Reduce the suspend time consumption for ALC256
+    - crypto: ecdh - fix typo in KPP dependency of CRYPTO_ECDH
+    - crypto: aesni - handle zero length dst buffer
+    - crypto: aesni - fix typo in generic_gcmaes_decrypt
+    - crypto: aesni - add wrapper for generic gcm(aes)
+    - crypto: aesni - Fix out-of-bounds access of the data buffer in generic-gcm-
+      aesni
+    - crypto: aesni - Fix out-of-bounds access of the AAD buffer in generic-gcm-
+      aesni
+    - crypto: inside-secure - fix hash when length is a multiple of a block
+    - crypto: inside-secure - avoid unmapping DMA memory that was not mapped
+    - crypto: sha3-generic - fixes for alignment and big endian operation
+    - crypto: af_alg - whitelist mask and type
+    - HID: wacom: EKR: ensure devres groups at higher indexes are released
+    - HID: wacom: Fix reporting of touch toggle (WACOM_HID_WD_MUTE_DEVICE) events
+    - 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
+    - ima/policy: fix parsing of fsuuid
+    - scsi: aacraid: Fix udev inquiry race condition
+    - scsi: aacraid: Fix hang in kdump
+    - scsi: storvsc: missing error code in storvsc_probe()
+    - staging: lustre: separate a connection destroy from free struct kib_conn
+    - staging: ccree: NULLify backup_info when unused
+    - staging: ccree: fix fips event irq handling build
+    - tty: fix data race between tty_init_dev and flush of buf
+    - 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
+    - usb/gadget: Fix "high bandwidth" check in usb_gadget_ep_match_desc()
+    - ANDROID: binder: remove waitqueue when thread exits.
+    - android: binder: use VM_ALLOC to get vm area
+    - mei: me: allow runtime pm for platform with D0i3
+    - serial: 8250_of: fix return code when probe function fails to get reset
+    - serial: 8250_uniphier: fix error return code in uniphier_uart_probe()
+    - serial: 8250_dw: Revert "Improve clock rate setting"
+    - serial: imx: Only wakeup via RTSDEN bit if the system has RTS/CTS
+    - spi: imx: do not access registers while clocks disabled
+    - iio: adc: stm32: fix scan of multiple channels with DMA
+    - iio: chemical: ccs811: Fix output of IIO_CONCENTRATION channels
+    - test_firmware: fix missing unlock on error in config_num_requests_store()
+    - Input: synaptics-rmi4 - unmask F03 interrupts when port is opened
+    - Input: synaptics-rmi4 - do not delete interrupt memory too early
+    - x86/efi: Clarify that reset attack mitigation needs appropriate userspace
+    - Linux 4.15.1
+
+  * Dell XPS 13 9360 bluetooth (Atheros) won't connect after resume
+    (LP: #1744712)
+    - Revert "Bluetooth: btusb: fix QCA Rome suspend/resume"
+    - Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten"
+      version
+
+  * apparmor profile load in stacked policy container fails (LP: #1746463)
+    - SAUCE: apparmor: fix display of .ns_name for containers
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 04 Feb 2018 11:56:32 +0100
+
+linux (4.15.0-6.7) bionic; urgency=low
+
+  * upload urgency should be medium by default (LP: #1745338)
+    - [Packaging] update urgency to medium by default
+
+  * Shutdown hang on 16.04 with iscsi targets (LP: #1569925)
+    - scsi: libiscsi: Allow sd_shutdown on bad transport
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.5-1ubuntu1, zfs to 0.7.5-1ubuntu1
+    - Revert "UBUNTU: SAUCE: mm: fix memory hotplug in ZONE_HIGHMEM"
+    - Revert "UBUNTU: SAUCE: mm: disable vma based swap readahead by default"
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 29 Jan 2018 08:47:07 -0600
+
+linux (4.15.0-5.6) bionic; urgency=low
+
+  * $(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
+
+  * Missing install-time driver for QLogic QED 25/40/100Gb Ethernet NIC
+    (LP: #1743638)
+    - [d-i] Add qede to nic-modules udeb
+
+  * boot failure on AMD Raven + WesternXT (LP: #1742759)
+    - SAUCE: drm/amdgpu: add atpx quirk handling (v2)
+
+  * Unable to handle kernel NULL pointer dereference at isci_task_abort_task
+    (LP: #1726519)
+    - SAUCE: Revert "scsi: libsas: allow async aborts"
+
+  * Update Ubuntu-4.15.0 config to support Intel Atom devices (LP: #1739939)
+    - [Config] CONFIG_SERIAL_DEV_BUS=y, CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
+
+  * Miscellaneous Ubuntu changes
+    - Rebase to v4.15-rc7
+    - [Config] CONFIG_CPU_ISOLATION=y
+    - [Config] Update annotations following config review
+    - Revert "UBUNTU: SAUCE: Import aufs driver"
+    - SAUCE: Import aufs driver
+    - ubuntu: vbox -- update to 5.2.6-dfsg-1
+    - ubuntu: vbox: build fixes for 4.15
+    - ubuntu: vbox -- update to 5.2.6-dfsg-2
+    - hio: updates for timer api changes in 4.15
+    - enable hio build
+    - Rebase to v4.15-rc9
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc9
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 22 Jan 2018 10:16:05 -0600
+
+linux (4.15.0-4.5) bionic; urgency=low
+
+  * [0cf3:e010] QCA6174A XR failed to pair with bt 4.0 device  (LP: #1741166)
+    - SAUCE: Bluetooth: btusb: Add support for 0cf3:e010
+
+  * External HDMI monitor failed to show screen on Lenovo X1 series
+    (LP: #1738523)
+    - SAUCE: drm/i915: Disable writing of TMDS_OE on Lenovo ThinkPad X1 series
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] autoreconstruct - add resoration of execute permissions
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 10 Jan 2018 10:24:22 -0600
+
+linux (4.15.0-3.4) bionic; urgency=low
+
+  * ubuntu/xr-usb-serial didn't get built in zesty and artful (LP: #1733281)
+    - SAUCE: make sure ubuntu/xr-usb-serial builds for x86
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 03 Jan 2018 20:20:43 -0600
+
+linux (4.15.0-2.3) bionic; urgency=low
+
+  * nvidia-graphics-drivers-384 384.90-0ubuntu6 ADT test failure with linux
+    4.15.0-1.2 (LP: #1737752)
+    - x86/mm: Unbreak modules that use the DMA API
+
+  * Ubuntu 17.10 corrupting BIOS - many LENOVO laptops models (LP: #1734147)
+    - [Config] CONFIG_SPI_INTEL_SPI_*=n
+
+  * power: commonise configs IBMVETH/IBMVSCSI and ensure both are in linux-image
+    and udebs (LP: #1521712)
+    - [Config] Include ibmvnic in nic-modules
+
+  * Enable arm64 emulation of removed ARMv7 instructions (LP: #1545542)
+    - [Config] Enable support for emulation of deprecated ARMv8 instructions
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl with 4.15 compat fix (LP:#1737761)
+    - Enable zfs build
+    - [Debian] add icp to zfs-modules.ignore
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 18 Dec 2017 09:27:13 -0600
+
+linux (4.15.0-1.2) bionic; urgency=low
+
+  * Disabling zfs does not always disable module checks for the zfs modules
+    (LP: #1737176)
+    - [Packaging] disable zfs module checks when zfs is disabled
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_UNWINDER_FRAME_POINTER=y for amd64
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 10 Dec 2017 22:07:19 -0600
+
+linux (4.15.0-0.1) bionic; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu: vbox -- update to 5.2.2-dfsg-2
+    - ubuntu: vbox: build fixes for 4.15
+    - disable hio build
+    - [Config] Update kernel lockdown options to fix build errors
+    - Disable zfs build
+    - SAUCE: Import aufs driver
+    - [Config] Enable AUFS config options
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.15-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 08 Dec 2017 13:55:42 -0600
+
+linux (4.14.0-11.13) bionic; urgency=low
+
+  * linux: 4.14.0-11.13 -proposed tracker (LP: #1736168)
+
+  * CVE-2017-1000405
+    - mm, thp: Do not make page table dirty unconditionally in touch_p[mu]d()
+
+  * linux 4.14.0-7.9 ADT test failure with linux 4.14.0-7.9 (LP: #1732463)
+    - SAUCE: mm: disable vma based swap readahead by default
+    - SAUCE: mm: fix memory hotplug in ZONE_HIGHMEM
+
+  * Bionic update to v4.14.3 stable release (LP: #1735843)
+    - s390: fix transactional execution control register handling
+    - s390/noexec: execute kexec datamover without DAT
+    - s390/runtime instrumention: fix possible memory corruption
+    - s390/guarded storage: fix possible memory corruption
+    - s390/disassembler: add missing end marker for e7 table
+    - s390/disassembler: increase show_code buffer size
+    - ACPI / PM: Fix acpi_pm_notifier_lock vs flush_workqueue() deadlock
+    - ACPI / EC: Fix regression related to triggering source of EC event handling
+    - cpufreq: schedutil: Reset cached_raw_freq when not in sync with next_freq
+    - serdev: fix registration of second slave
+    - sched: Make resched_cpu() unconditional
+    - lib/mpi: call cond_resched() from mpi_powm() loop
+    - x86/boot: Fix boot failure when SMP MP-table is based at 0
+    - x86/decoder: Add new TEST instruction pattern
+    - x86/entry/64: Fix entry_SYSCALL_64_after_hwframe() IRQ tracing
+    - x86/entry/64: Add missing irqflags tracing to native_load_gs_index()
+    - perf/x86/intel: Hide TSX events when RTM is not supported
+    - arm64: Implement arch-specific pte_access_permitted()
+    - ARM: 8722/1: mm: make STRICT_KERNEL_RWX effective for LPAE
+    - ARM: 8721/1: mm: dump: check hardware RO bit for LPAE
+    - uapi: fix linux/tls.h userspace compilation error
+    - uapi: fix linux/rxrpc.h userspace compilation errors
+    - MIPS: cmpxchg64() and HAVE_VIRT_CPU_ACCOUNTING_GEN don't work for 32-bit SMP
+    - MIPS: ralink: Fix MT7628 pinmux
+    - MIPS: ralink: Fix typo in mt7628 pinmux function
+    - net: mvneta: fix handling of the Tx descriptor counter
+    - nbd: wait uninterruptible for the dead timeout
+    - nbd: don't start req until after the dead connection logic
+    - PM / OPP: Add missing of_node_put(np)
+    - PCI/ASPM: Account for downstream device's Port Common_Mode_Restore_Time
+    - PCI/ASPM: Use correct capability pointer to program LTR_L1.2_THRESHOLD
+    - PCI: hv: Use effective affinity mask
+    - PCI: Set Cavium ACS capability quirk flags to assert RR/CR/SV/UF
+    - PCI: Apply Cavium ThunderX ACS quirk to more Root Ports
+    - ALSA: hda: Add Raven PCI ID
+    - dm integrity: allow unaligned bv_offset
+    - dm cache: fix race condition in the writeback mode overwrite_bio
+      optimisation
+    - dm crypt: allow unaligned bv_offset
+    - dm zoned: ignore last smaller runt zone
+    - dm mpath: remove annoying message of 'blk_get_request() returned -11'
+    - dm bufio: fix integer overflow when limiting maximum cache size
+    - ovl: Put upperdentry if ovl_check_origin() fails
+    - dm: allocate struct mapped_device with kvzalloc
+    - sched/rt: Simplify the IPI based RT balancing logic
+    - MIPS: pci: Remove KERN_WARN instance inside the mt7620 driver
+    - dm: fix race between dm_get_from_kobject() and __dm_destroy()
+    - dm: discard support requires all targets in a table support discards
+    - MIPS: Fix odd fp register warnings with MIPS64r2
+    - MIPS: Fix MIPS64 FP save/restore on 32-bit kernels
+    - MIPS: dts: remove bogus bcm96358nb4ser.dtb from dtb-y entry
+    - MIPS: Fix an n32 core file generation regset support regression
+    - MIPS: BCM47XX: Fix LED inversion for WRT54GSv1
+    - MIPS: math-emu: Fix final emulation phase for certain instructions
+    - rt2x00usb: mark device removed when get ENOENT usb error
+    - mm/z3fold.c: use kref to prevent page free/compact race
+    - autofs: don't fail mount for transient error
+    - nilfs2: fix race condition that causes file system corruption
+    - fscrypt: lock mutex before checking for bounce page pool
+    - eCryptfs: use after free in ecryptfs_release_messaging()
+    - libceph: don't WARN() if user tries to add invalid key
+    - bcache: check ca->alloc_thread initialized before wake up it
+    - fs: guard_bio_eod() needs to consider partitions
+    - fanotify: fix fsnotify_prepare_user_wait() failure
+    - isofs: fix timestamps beyond 2027
+    - btrfs: change how we decide to commit transactions during flushing
+    - f2fs: expose some sectors to user in inline data or dentry case
+    - NFS: Fix typo in nomigration mount option
+    - NFS: Revert "NFS: Move the flock open mode check into nfs_flock()"
+    - nfs: Fix ugly referral attributes
+    - NFS: Avoid RCU usage in tracepoints
+    - NFS: revalidate "." etc correctly on "open".
+    - nfsd: deal with revoked delegations appropriately
+    - rtlwifi: rtl8192ee: Fix memory leak when loading firmware
+    - rtlwifi: fix uninitialized rtlhal->last_suspend_sec time
+    - iwlwifi: fix firmware names for 9000 and A000 series hw
+    - md: fix deadlock error in recent patch.
+    - md: don't check MD_SB_CHANGE_CLEAN in md_allow_write
+    - Bluetooth: btqcomsmd: Add support for BD address setup
+    - md/bitmap: revert a patch
+    - fsnotify: clean up fsnotify_prepare/finish_user_wait()
+    - fsnotify: pin both inode and vfsmount mark
+    - fsnotify: fix pinning group in fsnotify_prepare_user_wait()
+    - ata: fixes kernel crash while tracing ata_eh_link_autopsy event
+    - ext4: fix interaction between i_size, fallocate, and delalloc after a crash
+    - ext4: prevent data corruption with inline data + DAX
+    - ext4: prevent data corruption with journaling + DAX
+    - 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 ALC275 no sound issue
+    - ALSA: hda: Fix too short HDMI/DP chmap reporting
+    - ALSA: hda - Fix yet remaining issue with vmaster 0dB initialization
+    - ALSA: hda/realtek - Fix ALC700 family no sound issue
+    - ASoC: sun8i-codec: Invert Master / Slave condition
+    - ASoC: sun8i-codec: Fix left and right channels inversion
+    - ASoC: sun8i-codec: Set the BCLK divider
+    - mfd: lpc_ich: Avoton/Rangeley uses SPI_BYT method
+    - fix a page leak in vhost_scsi_iov_to_sgl() error recovery
+    - 9p: Fix missing commas in mount options
+    - fs/9p: Compare qid.path in v9fs_test_inode
+    - net/9p: Switch to wait_event_killable()
+    - scsi: qla2xxx: Suppress a kernel complaint in qla_init_base_qpair()
+    - scsi: sd_zbc: Fix sd_zbc_read_zoned_characteristics()
+    - scsi: lpfc: fix pci hot plug crash in timer management routines
+    - scsi: lpfc: fix pci hot plug crash in list_add call
+    - scsi: lpfc: Fix crash receiving ELS while detaching driver
+    - scsi: lpfc: Fix FCP hba_wqidx assignment
+    - scsi: lpfc: Fix oops if nvmet_fc_register_targetport fails
+    - iscsi-target: Make TASK_REASSIGN use proper se_cmd->cmd_kref
+    - iscsi-target: Fix non-immediate TMR reference leak
+    - target: fix null pointer regression in core_tmr_drain_tmr_list
+    - target: fix buffer offset in core_scsi3_pri_read_full_status
+    - target: Fix QUEUE_FULL + SCSI task attribute handling
+    - target: Fix caw_sem leak in transport_generic_request_failure
+    - target: Fix quiese during transport_write_pending_qf endless loop
+    - target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK
+    - mtd: Avoid probe failures when mtd->dbg.dfs_dir is invalid
+    - mtd: nand: Export nand_reset() symbol
+    - mtd: nand: atmel: Actually use the PM ops
+    - mtd: nand: omap2: Fix subpage write
+    - mtd: nand: Fix writing mtdoops to nand flash.
+    - mtd: nand: mtk: fix infinite ECC decode IRQ issue
+    - mailbox: bcm-flexrm-mailbox: Fix FlexRM ring flush sequence
+    - p54: don't unregister leds when they are not initialized
+    - block: Fix a race between blk_cleanup_queue() and timeout handling
+    - raid1: prevent freeze_array/wait_all_barriers deadlock
+    - genirq: Track whether the trigger type has been set
+    - irqchip/gic-v3: Fix ppi-partitions lookup
+    - lockd: double unregister of inetaddr notifiers
+    - KVM: PPC: Book3S HV: Don't call real-mode XICS hypercall handlers if not
+      enabled
+    - KVM: nVMX: set IDTR and GDTR limits when loading L1 host state
+    - KVM: SVM: obey guest PAT
+    - kvm: vmx: Reinstate support for CPUs without virtual NMI
+    - dax: fix PMD faults on zero-length files
+    - dax: fix general protection fault in dax_alloc_inode
+    - SUNRPC: Fix tracepoint storage issues with svc_recv and svc_rqst_status
+    - clk: ti: dra7-atl-clock: fix child-node lookups
+    - libnvdimm, dimm: clear 'locked' status on successful DIMM enable
+    - libnvdimm, pfn: make 'resource' attribute only readable by root
+    - libnvdimm, namespace: fix label initialization to use valid seq numbers
+    - libnvdimm, region : make 'resource' attribute only readable by root
+    - libnvdimm, namespace: make 'resource' attribute only readable by root
+    - svcrdma: Preserve CB send buffer across retransmits
+    - IB/srpt: Do not accept invalid initiator port names
+    - IB/cm: Fix memory corruption in handling CM request
+    - IB/hfi1: Fix incorrect available receive user context count
+    - IB/srp: Avoid that a cable pull can trigger a kernel crash
+    - IB/core: Avoid crash on pkey enforcement failed in received MADs
+    - IB/core: Only maintain real QPs in the security lists
+    - NFC: fix device-allocation error return
+    - spi-nor: intel-spi: Fix broken software sequencing codes
+    - 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: Fix boot on BOOK3S_32 with CONFIG_STRICT_KERNEL_RWX
+    - powerpc/mm/radix: Fix crashes on Power9 DD1 with radix MMU and STRICT_RWX
+    - powerpc/perf/imc: Use cpu_to_node() not topology_physical_package_id()
+    - powerpc/signal: Properly handle return value from uprobe_deny_signal()
+    - powerpc/64s: Fix masking of SRR1 bits on instruction fault
+    - powerpc/64s/radix: Fix 128TB-512TB virtual address boundary case allocation
+    - powerpc/64s/hash: Fix 512T hint detection to use >= 128T
+    - powerpc/64s/hash: Fix 128TB-512TB virtual address boundary case allocation
+    - powerpc/64s/hash: Fix fork() with 512TB process address space
+    - powerpc/64s/hash: Allow MAP_FIXED allocations to cross 128TB boundary
+    - media: Don't do DMA on stack for firmware upload in the AS102 driver
+    - media: rc: check for integer overflow
+    - media: rc: nec decoder should not send both repeat and keycode
+    - cx231xx-cards: fix NULL-deref on missing association descriptor
+    - media: v4l2-ctrl: Fix flags field on Control events
+    - media: venus: fix wrong size on dma_free
+    - media: venus: venc: fix bytesused v4l2_plane field
+    - media: venus: reimplement decoder stop command
+    - ARM64: dts: meson-gxl: Add alternate ARM Trusted Firmware reserved memory
+      zone
+    - iwlwifi: fix wrong struct for a000 device
+    - iwlwifi: add a new a000 device
+    - iwlwifi: pcie: sort IDs for the 9000 series for easier comparisons
+    - iwlwifi: add new cards for a000 series
+    - iwlwifi: add new cards for 8265 series
+    - iwlwifi: add new cards for 8260 series
+    - iwlwifi: fix PCI IDs and configuration mapping for 9000 series
+    - iwlwifi: mvm: support version 7 of the SCAN_REQ_UMAC FW command
+    - e1000e: Fix error path in link detection
+    - e1000e: Fix return value test
+    - e1000e: Separate signaling for link check/link up
+    - e1000e: Avoid receiver overrun interrupt bursts
+    - e1000e: fix buffer overrun while the I219 is processing DMA transactions
+    - Linux 4.14.3
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: s390/topology: don't inline cpu_to_node
+    - SAUCE: (noup) Update spl to 0.7.3-1ubuntu1, zfs to 0.7.3-1ubuntu1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 04 Dec 2017 09:08:07 -0600
+
+linux (4.14.0-10.12) bionic; urgency=low
+
+  * linux: 4.14.0-10.12 -proposed tracker (LP: #1734901)
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Enable the ACPI kernel debugger and acpidbg tool
+    - [Packaging] Include arch/arm64/kernel/ftrace-mod.o in headers package
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 28 Nov 2017 08:46:49 -0600
+
+linux (4.14.0-9.11) bionic; urgency=low
+
+  * linux: 4.14.0-9.11 -proposed tracker (LP: #1734728)
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: (noup) Update spl to 0.7.3-1ubuntu1, zfs to
+      0.7.3-1ubuntu1"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 27 Nov 2017 12:44:48 -0600
+
+linux (4.14.0-8.10) bionic; urgency=low
+
+  * linux: 4.14.0-8.10 -proposed tracker (LP: #1734695)
+
+  * Bionic update to v4.14.2 stable release (LP: #1734694)
+    - bio: ensure __bio_clone_fast copies bi_partno
+    - af_netlink: ensure that NLMSG_DONE never fails in dumps
+    - vxlan: fix the issue that neigh proxy blocks all icmpv6 packets
+    - net: cdc_ncm: GetNtbFormat endian fix
+    - 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
+    - serial: 8250_fintek: Fix finding base_port with activated SuperIO
+    - tpm-dev-common: Reject too short writes
+    - rcu: Fix up pending cbs check in rcu_prepare_for_idle
+    - mm/pagewalk.c: report holes in hugetlb ranges
+    - ocfs2: fix cluster hang after a node dies
+    - ocfs2: should wait dio before inode lock in ocfs2_setattr()
+    - ipmi: fix unsigned long underflow
+    - mm/page_alloc.c: broken deferred calculation
+    - mm/page_ext.c: check if page_ext is not prepared
+    - coda: fix 'kernel memory exposure attempt' in fsync
+    - ipmi: Prefer ACPI system interfaces over SMBIOS ones
+    - Linux 4.14.2
+
+  * Bionic update to v4.14.1 stable release (LP: #1734693)
+    - EDAC, sb_edac: Don't create a second memory controller if HA1 is not present
+    - dmaengine: dmatest: warn user when dma test times out
+    - media: imon: Fix null-ptr-deref in imon_probe
+    - media: dib0700: fix invalid dvb_detach argument
+    - crypto: dh - Fix double free of ctx->p
+    - crypto: dh - Don't permit 'p' to be 0
+    - crypto: dh - Don't permit 'key' or 'g' size longer than 'p'
+    - crypto: brcm - Explicity ACK mailbox message
+    - USB: early: Use new USB product ID and strings for DbC device
+    - USB: usbfs: compute urb->actual_length for isochronous
+    - USB: Add delay-init quirk for Corsair K70 LUX keyboards
+    - usb: gadget: f_fs: Fix use-after-free in ffs_free_inst
+    - USB: serial: metro-usb: stop I/O after failed open
+    - USB: serial: Change DbC debug device binding ID
+    - 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
+    - selftests/x86/protection_keys: Fix syscall NR redefinition warnings
+    - x86/MCE/AMD: Always give panic severity for UC errors in kernel context
+    - platform/x86: peaq-wmi: Add DMI check before binding to the WMI interface
+    - platform/x86: peaq_wmi: Fix missing terminating entry for peaq_dmi_table
+    - HID: cp2112: add HIDRAW dependency
+    - HID: wacom: generic: Recognize WACOM_HID_WD_PEN as a type of pen collection
+    - rpmsg: glink: Add missing MODULE_LICENSE
+    - staging: wilc1000: Fix bssid buffer offset in Txq
+    - staging: sm750fb: Fix parameter mistake in poke32
+    - staging: ccree: fix 64 bit scatter/gather DMA ops
+    - staging: greybus: spilib: fix use-after-free after deregistration
+    - staging: rtl8188eu: Revert 4 commits breaking ARP
+    - spi: fix use-after-free at controller deregistration
+    - sparc32: Add cmpxchg64().
+    - sparc64: mmu_context: Add missing include files
+    - sparc64: Fix page table walk for PUD hugepages
+    - Linux 4.14.1
+
+  * Set PANIC_TIMEOUT=10 on Power Systems (LP: #1730660)
+    - [Config]: Set PANIC_TIMEOUT=10 on ppc64el
+
+  * enable CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH easily confuse users
+    (LP: #1732627)
+    - [Config] CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH=n
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.7.3-1ubuntu1, zfs to 0.7.3-1ubuntu1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 27 Nov 2017 07:43:44 -0600
+
+linux (4.14.0-7.9) bionic; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: apparmor: add base infastructure for socket mediation
+    - SAUCE: apparmor: af_unix mediation
+    - SAUCE: LSM stacking: procfs: add smack subdir to attrs
+    - SAUCE: LSM stacking: LSM: manage credential security blobs
+    - SAUCE: LSM stacking: LSM: Manage file security blobs
+    - SAUCE: LSM stacking: LSM: manage task security blobs
+    - SAUCE: LSM stacking: LSM: Infrastructure management of the remaining blobs
+    - SAUCE: LSM stacking: LSM: general but not extreme module stacking
+    - SAUCE: LSM stacking: LSM: Complete task_alloc hook
+    - SAUCE: LSM stacking: fixup procsfs: add smack subdir to attrs
+    - SAUCE: LSM stacking: fixup initialize task->security
+    - SAUCE: LSM stacking: fixup: alloc_task_ctx is dead code
+    - SAUCE: LSM stacking: add support for stacking getpeersec_stream
+    - SAUCE: LSM stacking: add stacking support to apparmor network hooks
+    - SAUCE: LSM stacking: fixup apparmor stacking enablement
+    - SAUCE: LSM stacking: fixup stacking kconfig
+    - SAUCE: LSM stacking: allow selecting multiple LSMs using kernel boot params
+    - SAUCE: LSM stacking: provide prctl interface for setting context
+    - SAUCE: LSM stacking: inherit current display LSM
+    - SAUCE: LSM stacking: keep an index for each registered LSM
+    - SAUCE: LSM stacking: verify display LSM
+    - SAUCE: LSM stacking: provide a way to specify the default display lsm
+    - SAUCE: LSM stacking: make sure LSM blob align on 64 bit boundaries
+    - SAUCE: LSM stacking: add /proc/<pid>/attr/display_lsm
+    - SAUCE: LSM stacking: add Kconfig to set default display LSM
+    - SAUCE: LSM stacking: add configs for LSM stacking
+    - SAUCE: LSM stacking: check for invalid zero sized writes
+    - [Config] Run updateconfigs after merging LSM stacking
+    - [Config] CONFIG_AMD_MEM_ENCRYPT=y
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 13 Nov 2017 08:12:08 -0600
+
+linux (4.14.0-6.8) bionic; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: add workarounds to enable ZFS for 4.14
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc8
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 06 Nov 2017 11:39:00 -0600
+
+linux (4.14.0-5.7) bionic; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Fix invocation of dh_prep for dbgsym packages
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 31 Oct 2017 07:07:23 -0500
+
+linux (4.14.0-4.5) bionic; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] virtualbox -- reduce in kernel module versions
+    - vbox-update: Fix up KERN_DIR definitions
+    - ubuntu: vbox -- update to 5.2.0-dfsg-2
+    - [Config] CONFIG_AMD_MEM_ENCRYPT=n
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 30 Oct 2017 13:29:20 -0500
+
+linux (4.14.0-3.4) artful; urgency=low
+
+  * Touchpad and TrackPoint Dose Not Work on Lenovo X1C6 and X280 (LP: #1723986)
+    - SAUCE: Input: synaptics-rmi4 - RMI4 can also use SMBUS version 3
+    - SAUCE: Input: synaptics - Lenovo X1 Carbon 5 should use SMBUS/RMI
+    - SAUCE: Input: synaptics - add Intertouch support on X1 Carbon 6th and X280
+
+  * powerpc/64s: Add workaround for P9 vector CI load issuenext (LP: #1721070)
+    - powerpc/64s: Add workaround for P9 vector CI load issue
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: staging: vboxvideo: Fix reporting invalid suggested-offset-properties
+    - [Config] CONFIG_DRM_VBOXVIDEO=m
+    - SAUCE: Import aufs driver
+    - [Config] Enable aufs
+    - [Config] Reorder annotations file after enabling aufs
+    - vbox-update: Disable imported vboxvideo module
+    - ubuntu: vbox -- update to 5.1.30-dfsg-1
+    - Enable vbox
+    - hio: Use correct sizes when initializing ssd_index_bits* arrays
+    - hio: Update io stat accounting for 4.14
+    - Enable hio
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc5
+  * Rebase to v4.14-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 23 Oct 2017 13:53:52 -0500
+
+linux (4.14.0-2.3) artful; urgency=low
+
+  * [Bug] USB controller failed to respond on Denverton after loading
+    intel_th_pci module (LP: #1715833)
+    - SAUCE: PCI: Disable broken RTIT_BAR of Intel TH
+
+  * CONFIG_DEBUG_FS is not enabled by "make zfcpdump_defconfig" with Ubuntu
+    17.10 (kernel 4.13) (LP: #1719290)
+    - SAUCE: s390: update zfcpdump_defconfig
+
+  * Add installer support for Broadcom BCM573xx network drivers. (LP: #1720466)
+    - d-i: Add bnxt_en to nic-modules.
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Update annotations for 4.14-rc2
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc3
+  * Rebase to v4.14-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 11 Oct 2017 16:04:27 -0500
+
+linux (4.14.0-1.2) artful; urgency=low
+
+  * [Bug] USB 3.1 Gen2 works as 5Gbps (LP: #1720045)
+    - xhci: set missing SuperSpeedPlus Link Protocol bit in roothub descriptor
+
+  * Please make linux-libc-dev Provide: aufs-dev (LP: #1716091)
+    - [Packaging] Add aufs-dev to the Provides: for linux-libc-dev
+
+  * Upgrade to 4.13.0-11.12 in artful amd64 VM breaks display on wayland
+    (LP: #1718679)
+    - [Config] CONFIG_DRM_VBOXVIDEO=n
+
+  * ipmmu-vmsa driver breaks arm64 boots (LP: #1718734)
+    - [Config] Disable CONFIG_IPMMU_VMSA on arm64
+
+  * autopkgtest profile fails to build on armhf (LP: #1717920)
+    - [Packaging] autopkgtest -- disable d-i when dropping flavours
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_I2C_XLP9XX=m
+    - [Packaging] Use SRCPKGNAME rather than hard-coding the source package name
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 29 Sep 2017 09:09:11 -0400
+
+linux (4.14.0-0.1) artful; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - Disable vbox build
+    - Disable hio build
+    - Disable zfs build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.14-rc1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 19 Sep 2017 20:22:29 -0500
+
+linux (4.13.0-11.12) artful; urgency=low
+
+  * linux: 4.13.0-11.12 -proposed tracker (LP: #1716699)
+
+  * kernel panic -not syncing: Fatal exception: panic_on_oops (LP: #1708399)
+    - s390/mm: fix local TLB flushing vs. detach of an mm address space
+    - s390/mm: fix race on mm->context.flush_mm
+
+  * CVE-2017-1000251
+    - Bluetooth: Properly check L2CAP config option output buffer length
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 12 Sep 2017 10:18:38 -0500
+
+linux (4.13.0-10.11) artful; urgency=low
+
+  * linux: 4.13.0-10.11 -proposed tracker (LP: #1716287)
+
+  * please add aufs-dkms to the Provides: for the kernel packages (LP: #1716093)
+    - [Packaging] Add aufs-dkms to the Provides: for kernel packages
+
+  * Artful update to v4.13.1 stable release (LP: #1716284)
+    - 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: musb: fix external abort on suspend
+    - ANDROID: binder: add padding to binder_fd_array_object.
+    - ANDROID: binder: add hwbinder,vndbinder to BINDER_DEVICES.
+    - USB: core: Avoid race of async_completed() w/ usbdev_release()
+    - staging/rts5208: fix incorrect shift to extract upper nybble
+    - staging: ccree: save ciphertext for CTS IV
+    - staging: fsl-dpaa2/eth: fix off-by-one FD ctrl bitmaks
+    - iio: adc: ti-ads1015: fix incorrect data rate setting update
+    - iio: adc: ti-ads1015: fix scale information for ADS1115
+    - iio: adc: ti-ads1015: enable conversion when CONFIG_PM is not set
+    - iio: adc: ti-ads1015: avoid getting stale result after runtime resume
+    - iio: adc: ti-ads1015: don't return invalid value from buffer setup callbacks
+    - iio: adc: ti-ads1015: add adequate wait time to get correct conversion
+    - driver core: bus: Fix a potential double free
+    - HID: wacom: Do not completely map WACOM_HID_WD_TOUCHRINGSTATUS usage
+    - binder: free memory on error
+    - crypto: caam/qi - fix compilation with CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+    - crypto: caam/qi - fix compilation with DEBUG enabled
+    - thunderbolt: Fix reset response_type
+    - fpga: altera-hps2fpga: fix multiple init of l3_remap_lock
+    - 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
+    - drm/vgem: Pin our pages for dmabuf exports
+    - drm/ttm: Fix accounting error when fail to get pages for pool
+    - drm/dp/mst: Handle errors from drm_atomic_get_private_obj_state() correctly
+    - rtlwifi: rtl_pci_probe: Fix fail path of _rtl_pci_find_adapter
+    - Bluetooth: Add support of 13d3:3494 RTL8723BE device
+    - iwlwifi: pci: add new PCI ID for 7265D
+    - dlm: avoid double-free on error path in dlm_device_{register,unregister}
+    - mwifiex: correct channel stat buffer overflows
+    - MCB: add support for SC31 to mcb-lpc
+    - s390/mm: avoid empty zero pages for KVM guests to avoid postcopy hangs
+    - drm/nouveau/pci/msi: disable MSI on big-endian platforms by default
+    - drm/nouveau: Fix error handling in nv50_disp_atomic_commit
+    - workqueue: Fix flag collision
+    - ahci: don't use MSI for devices with the silly Intel NVMe remapping scheme
+    - 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
+    - of/device: Prevent buffer overflow in of_device_modalias()
+    - rtlwifi: Fix memory leak when firmware request fails
+    - rtlwifi: Fix fallback firmware loading
+    - Linux 4.13.1
+
+  * Kernel has trouble recognizing Corsair Strafe RGB keyboard (LP: #1678477)
+    - usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
+
+  * SRIOV: warning if unload VFs (LP: #1715073)
+    - PCI: Disable VF decoding before pcibios_sriov_disable() updates resources
+
+  * [Patch] network-i40e:NVM bug fixes (cherrypick from 4.14) (LP: #1715578)
+    - i40e: avoid NVM acquire deadlock during NVM update
+    - i40e: point wb_desc at the nvm_wb_desc during i40e_read_nvm_aq
+
+  * [P9,POwer NV] Perf PMU event : pm_br_2path and pm_ld_miss_l1 is counted
+    twice when perf stat is done (perf:) (LP: #1714571)
+    - perf vendor events powerpc: Remove duplicate events
+
+  * Unable to install Ubuntu on the NVMe disk under VMD PCI domain
+    (LP: #1703339)
+    - [Config] Include vmd in storage-core-modules udeb
+
+  * 17.10 fails to boot on POWER9 DD2.0 with Deep stop states (LP: #1715064)
+    - powerpc/powernv: Save/Restore additional SPRs for stop4 cpuidle
+    - powerpc/powernv: Clear PECE1 in LPCR via stop-api only on Hotplug
+    - SAUCE: powerpc/powernv: Clear LPCR[PECE1] via stop-api only for deep state
+      offline
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: selftests/seccomp: Support glibc 2.26 siginfo_t.h
+    - Revert "UBUNTU: SAUCE: Import aufs driver"
+    - SAUCE: Import aufs driver
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 10 Sep 2017 17:48:59 -0500
+
+linux (4.13.0-9.10) artful; urgency=low
+
+  * linux: 4.13.0-9.10 -proposed tracker (LP: #1715145)
+
+  * EDAC sbridge: Failed to register device with error -22. (LP: #1714112)
+    - [Config] CONFIG_EDAC_GHES=n
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu: vbox -- update to 5.1.26-dfsg-2
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 05 Sep 2017 07:51:19 -0500
+
+linux (4.13.0-8.9) artful; urgency=low
+
+  * snapd 2.27.3+17.10 ADT test failure with linux 4.13.0-6.7 (LP: #1713103)
+    - SAUCE: apparmor: fix apparmorfs DAC access, permissions
+
+  * enable ARCH_SUNXI (and friends) in arm64 kernel .config (LP: #1701137)
+    - [Config] Enable CONFIG_ARCH_SUNXI and related options for arm64
+
+  * [Bug] Harrisonville: pnd2_edac always fail to load on B1 stepping
+    Harrisonville SDP (LP: #1709257)
+    - EDAC, pnd2: Build in a minimal sideband driver for Apollo Lake
+    - EDAC, pnd2: Mask off the lower four bits of a BAR
+    - EDAC, pnd2: Conditionally unhide/hide the P2SB PCI device to read BAR
+    - EDAC, pnd2: Properly toggle hidden state for P2SB PCI device
+    - SAUCE: i2c: i801: Restore the presence state of P2SB PCI device after
+      reading BAR
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: Import aufs driver"
+    - SAUCE: Import aufs driver
+    - SAUCE: selftests/powerpc: Disable some ptrace selftests
+    - [Config] CONFIG_CRYPTO_DEV_NITROX_CNN55XX=n for s390x
+    - [Config] CONFIG_I2C_SLAVE=n for amd64, i386, ppc64el
+    - [Config] Disable CONFIG_MDIO_* options for s390x
+    - [Config] CONFIG_SCSI_MQ_DEFAULT=n for s390x
+    - [Config] Update annotations for 4.13
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 31 Aug 2017 14:27:09 -0500
+
+linux (4.13.0-7.8) artful; urgency=low
+
+  * linux 4.12.0-11.12 ADT test failure with linux 4.12.0-11.12 (LP: #1710904)
+    - SAUCE: selftests/powerpc: Use snprintf to construct DSCR sysfs interface
+      paths
+
+  * Miscellaneous Ubuntu changes
+    - Revert "UBUNTU: SAUCE: seccomp: log actions even when audit is disabled"
+
+  * Miscellaneous upstream changes
+    - 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
+    - seccomp: Action to log before allowing
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 28 Aug 2017 08:12:24 -0500
+
+linux (4.13.0-6.7) artful; urgency=low
+
+  * HID: multitouch: Support ALPS PTP Stick and Touchpad devices (LP: #1712481)
+    - SAUCE: HID: multitouch: Support ALPS PTP stick with pid 0x120A
+
+  * sort ABI files with C.UTF-8 locale (LP: #1712345)
+    - [Packaging] sort ABI files with C.UTF-8 locale
+
+  * igb: Support using Broadcom 54616 as PHY (LP: #1712024)
+    - SAUCE: igb: add support for using Broadcom 54616 as PHY
+
+  * RPT related fixes missing in Ubuntu 16.04.3 (LP: #1709220)
+    - powerpc/mm/radix: Improve _tlbiel_pid to be usable for PWC flushes
+    - powerpc/mm/radix: Improve TLB/PWC flushes
+    - powerpc/mm/radix: Avoid flushing the PWC on every flush_tlb_range
+
+  * Linux 4.12 refuses to load self-signed modules under Secure Boot with
+    properly enrolled keys (LP: #1712168)
+    - SAUCE: (efi-lockdown) MODSIGN: Fix module signature verification
+
+  * [17.10 FEAT] Enable NVMe driver - kernel (LP: #1708432)
+    - [Config] CONFIG_BLK_DEV_NVME=m for s390
+
+  * Artful: 4.12.0-11.12: Boot panic in vlv2_plat_configure_clock+0x3b/0xa0
+    (LP: #1711298)
+    - [Config] CONFIG_INTEL_ATOMISP=n
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: apparmor: af_unix mediation
+
+  * Miscellaneous upstream changes
+    - apparmor: Fix shadowed local variable in unpack_trans_table()
+    - apparmor: Fix logical error in verify_header()
+    - apparmor: Fix an error code in aafs_create()
+    - apparmor: Redundant condition: prev_ns. in [label.c:1498]
+    - apparmor: add the ability to mediate signals
+    - apparmor: add mount mediation
+    - apparmor: cleanup conditional check for label in label_print
+    - apparmor: add support for absolute root view based labels
+    - apparmor: make policy_unpack able to audit different info messages
+    - apparmor: add more debug asserts to apparmorfs
+    - apparmor: add base infastructure for socket mediation
+    - apparmor: move new_null_profile to after profile lookup fns()
+    - apparmor: fix race condition in null profile creation
+    - apparmor: ensure unconfined profiles have dfas initialized
+    - apparmor: fix incorrect type assignment when freeing proxies
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 23 Aug 2017 08:10:38 -0500
+
+linux (4.13.0-5.6) artful; urgency=low
+
+  * Ubuntu17.10 - perf: Update Power9 PMU event JSON files (LP: #1708630)
+    - perf pmu-events: Support additional POWER8+ PVR in mapfile
+    - perf vendor events: Add POWER9 PMU events
+    - perf vendor events: Add POWER9 PVRs to mapfile
+    - SAUCE: perf vendor events powerpc: remove suffix in mapfile
+    - SAUCE: perf vendor events powerpc: Update POWER9 events
+
+  * Disable CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE (LP: #1709171)
+    - [Config] CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=n for ppc64el
+
+  * 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
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Import aufs driver
+    - SAUCE: aufs -- Add missing argument to loop_switch() call
+    - [Config] Enable aufs
+    - SAUCE: (noup) Update spl to 0.6.5.11-ubuntu1, zfs to 0.6.5.11-1ubuntu3
+    - Enable zfs build
+    - SAUCE: powerpc: Always initialize input array when calling epapr_hypercall()
+    - [Packaging] switch up to debhelper 9
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 15 Aug 2017 09:24:16 -0500
+
+linux (4.13.0-4.5) artful; urgency=low
+
+  * Lenovo Yoga 910 Sensors (LP: #1708120)
+    - SAUCE: (no-up) HID: Add quirk for Lenovo Yoga 910 with ITE Chips
+
+  * Unable to install Ubuntu on the NVMe disk under VMD PCI domain
+    (LP: #1703339)
+    - [Config] Add vmd driver to generic inclusion list
+
+  * Set CONFIG_SATA_HIGHBANK=y on armhf (LP: #1703430)
+    - [Config] CONFIG_SATA_HIGHBANK=y
+
+  * Miscellaneous Ubuntu changes
+    - ubuntu: vbox -- update to 5.1.26-dfsg-1
+    - SAUCE: hio: Build fixes for 4.13
+    - Enable hio build
+    - SAUCE: (noup) Update spl to 0.6.5.11-1, zfs to 0.6.5.11-1ubuntu1
+    - [debian] use all rather than amd64 dkms debs for sync
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc4
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 08 Aug 2017 11:31:48 -0500
+
+linux (4.13.0-3.4) artful; urgency=low
+
+  * Adt tests of src:linux time out often on armhf lxc containers (LP: #1705495)
+    - [Packaging] tests -- reduce rebuild test to one flavour
+    - [Packaging] tests -- reduce rebuild test to one flavour -- use filter
+
+  * snapd 2.26.8+17.10 ADT test failure with linux 4.12.0-6.7 (LP: #1704158)
+    - SAUCE: virtio_net: Revert mergeable buffer handling rework
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 31 Jul 2017 10:08:16 -0500
+
+linux (4.13.0-2.3) artful; urgency=low
+
+  * Change CONFIG_IBMVETH to module (LP: #1704479)
+    - [Config] CONFIG_IBMVETH=m
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 24 Jul 2017 13:58:08 -0500
+
+linux (4.13.0-1.2) artful; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Support sphinx-based kernel documentation
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Thu, 20 Jul 2017 09:18:33 -0500
+
+linux (4.13.0-0.1) artful; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - Disable hio
+    - Disable zfs build
+    - ubuntu: vbox -- update to 5.1.24-dfsg-1
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.13-rc1
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 19 Jul 2017 15:09:31 -0500
+
+linux (4.12.0-7.8) artful; urgency=low
+
+  * ThunderX: soft lockup on 4.8+ kernels when running qemu-efi with vhost=on
+    (LP: #1673564)
+    - arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
+    - KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
+    - KVM: arm64: Make kvm_condition_valid32() accessible from EL2
+    - KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2
+    - KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
+    - KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
+    - KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
+    - KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
+    - KVM: arm64: vgic-v3: Add misc Group-0 handlers
+    - KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
+    - KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
+    - arm64: Add MIDR values for Cavium cn83XX SoCs
+    - arm64: Add workaround for Cavium Thunder erratum 30115
+    - KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
+    - KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
+    - KVM: arm64: Enable GICv3 common sysreg trapping via command-line
+    - KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
+    - KVM: arm64: Log an error if trapping a read-from-write-only GICv3 access
+    - KVM: arm64: Log an error if trapping a write-to-read-only GICv3 access
+
+  * hns: under heavy load, NIC may fail and require reboot (LP: #1704146)
+    - net: hns: Bugfix for Tx timeout handling in hns driver
+
+  * New ACPI identifiers for ThunderX SMMU (LP: #1703437)
+    - iommu/arm-smmu: Plumb in new ACPI identifiers
+
+  * Transparent hugepages should default to enabled=madvise (LP: #1703742)
+    - SAUCE: use CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y as default
+
+  * Artful update to v4.12.1 stable release (LP: #1703858)
+    - driver core: platform: fix race condition with driver_override
+    - RDMA/uverbs: Check port number supplied by user verbs cmds
+    - usb: dwc3: replace %p with %pK
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - usb: usbip: set buffer pointers to NULL after free
+    - Add USB quirk for HVR-950q to avoid intermittent device resets
+    - usb: Fix typo in the definition of Endpoint[out]Request
+    - USB: core: fix device node leak
+    - USB: serial: option: add two Longcheer device ids
+    - USB: serial: qcserial: new Sierra Wireless EM7305 device ID
+    - xhci: Limit USB2 port wake support for AMD Promontory hosts
+    - gfs2: Fix glock rhashtable rcu bug
+    - Add "shutdown" to "struct class".
+    - tpm: Issue a TPM2_Shutdown for TPM2 devices.
+    - tpm: fix a kernel memory leak in tpm-sysfs.c
+    - powerpc/powernv: Fix CPU_HOTPLUG=n idle.c compile error
+    - x86/uaccess: Optimize copy_user_enhanced_fast_string() for short strings
+    - sched/fair, cpumask: Export for_each_cpu_wrap()
+    - sched/core: Implement new approach to scale select_idle_cpu()
+    - sched/numa: Use down_read_trylock() for the mmap_sem
+    - sched/numa: Override part of migrate_degrades_locality() when idle balancing
+    - sched/fair: Simplify wake_affine() for the single socket case
+    - sched/numa: Implement NUMA node level wake_affine()
+    - sched/fair: Remove effective_load()
+    - sched/numa: Hide numa_wake_affine() from UP build
+    - xen: avoid deadlock in xenbus driver
+    - crypto: drbg - Fixes panic in wait_for_completion call
+    - Linux 4.12.1
+
+  * cxlflash update request in the Xenial SRU stream (LP: #1702521)
+    - scsi: cxlflash: Combine the send queue locks
+    - scsi: cxlflash: Update cxlflash_afu_sync() to return errno
+    - scsi: cxlflash: Reset hardware queue context via specified register
+    - scsi: cxlflash: Schedule asynchronous reset of the host
+    - scsi: cxlflash: Handle AFU sync failures
+    - scsi: cxlflash: Track pending scsi commands in each hardware queue
+    - scsi: cxlflash: Flush pending commands in cleanup path
+    - scsi: cxlflash: Add scsi command abort handler
+    - scsi: cxlflash: Create character device to provide host management interface
+    - scsi: cxlflash: Separate AFU internal command handling from AFU sync
+      specifics
+    - scsi: cxlflash: Introduce host ioctl support
+    - scsi: cxlflash: Refactor AFU capability checking
+    - scsi: cxlflash: Support LUN provisioning
+    - scsi: cxlflash: Support AFU debug
+    - scsi: cxlflash: Support WS16 unmap
+    - scsi: cxlflash: Remove zeroing of private command data
+    - scsi: cxlflash: Update TMF command processing
+    - scsi: cxlflash: Avoid double free of character device
+    - scsi: cxlflash: Update send_tmf() parameters
+    - scsi: cxlflash: Update debug prints in reset handlers
+
+  * make snap-pkg support (LP: #1700747)
+    - make snap-pkg support
+
+  * Quirk for non-compliant PCI bridge on HiSilicon D05 board (LP: #1698706)
+    - SAUCE: PCI: Support hibmc VGA cards behind a misbehaving HiSilicon bridge
+
+  * arm64: fix crash reading /proc/kcore (LP: #1702749)
+    - fs/proc: kcore: use kcore_list type to check for vmalloc/module address
+    - arm64: mm: select CONFIG_ARCH_PROC_KCORE_TEXT
+
+  * Opal and POWER9 DD2 (LP: #1702159)
+    - SAUCE: powerpc/powernv: Tell OPAL about our MMU mode on POWER9
+
+  * Data corruption with hio driver  (LP: #1701316)
+    - SAUCE: hio: Fix incorrect use of enum req_opf values
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.6.5.10-1, zfs to 0.6.5.10-1ubuntu2
+    - snapcraft.yaml: Sync with xenial
+    - [Config] CONFIG_CAVIUM_ERRATUM_30115=y
+
+  * Miscellaneous upstream changes
+    - Revert "UBUNTU: SAUCE: (efi-lockdown) efi: Add sysctls for secureboot and
+      MokSBState"
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 14 Jul 2017 15:25:41 -0500
+
+linux (4.12.0-6.7) artful; urgency=low
+
+  * update ENA driver to 1.2.0k from net-next (LP: #1701575)
+    - 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: allow the driver to work with small number of msix vectors
+    - 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
+
+  * APST gets enabled against explicit kernel option (LP: #1699004)
+    - nvme: explicitly disable APST on quirked devices
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: hio: Update to Huawei ES3000_V2 (2.1.0.40)
+    - SAUCE: hio updates for 4.12
+    - SAUCE: Enable hio build
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 05 Jul 2017 14:23:20 -0500
+
+linux (4.12.0-5.6) artful; urgency=low
+
+  * ERAT invalidate on context switch removal (LP: #1700819)
+    - powerpc: Only do ERAT invalidate on radix context switch on P9 DD1
+
+  * powerpc: Invalidate ERAT on powersave wakeup for POWER9 (LP: #1700521)
+    - SAUCE: powerpc: Invalidate ERAT on powersave wakeup for POWER9
+
+  * Miscellaneous Ubuntu changes
+    - d-i: Move qcom-emac from arm64 to shared nic-modules
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 03 Jul 2017 07:52:02 -0500
+
+linux (4.12.0-4.5) artful; urgency=low
+
+  * aacraid driver may return uninitialized stack data to userspace
+    (LP: #1700077)
+    - SAUCE: scsi: aacraid: Don't copy uninitialized stack memory to userspace
+
+  * KILLER1435-S[0489:e0a2] BT cannot search BT 4.0 device (LP: #1699651)
+    - Bluetooth: btusb: Add support for 0489:e0a2 QCA_ROME device
+
+  * AACRAID for power9 platform (LP: #1689980)
+    - scsi: aacraid: Remove __GFP_DMA for raw srb memory
+    - scsi: aacraid: Fix DMAR issues with iommu=pt
+    - scsi: aacraid: Added 32 and 64 queue depth for arc natives
+    - scsi: aacraid: Set correct Queue Depth for HBA1000 RAW disks
+    - scsi: aacraid: Remove reset support from check_health
+    - scsi: aacraid: Change wait time for fib completion
+    - scsi: aacraid: Log count info of scsi cmds before reset
+    - scsi: aacraid: Print ctrl status before eh reset
+    - scsi: aacraid: Using single reset mask for IOP reset
+    - scsi: aacraid: Rework IOP reset
+    - scsi: aacraid: Add periodic checks to see IOP reset status
+    - scsi: aacraid: Rework SOFT reset code
+    - scsi: aacraid: Rework aac_src_restart
+    - scsi: aacraid: Use correct function to get ctrl health
+    - scsi: aacraid: Make sure ioctl returns on controller reset
+    - scsi: aacraid: Enable ctrl reset for both hba and arc
+    - scsi: aacraid: Add reset debugging statements
+    - scsi: aacraid: Remove reference to Series-9
+    - scsi: aacraid: Update driver version to 50834
+
+  * hibmc driver does not include "pci:" prefix in bus ID (LP: #1698700)
+    - SAUCE: drm: hibmc: Use set_busid function from drm core
+
+  * HiSilicon D05: installer doesn't appear on VGA (LP: #1698954)
+    - d-i: Add hibmc-drm to kernel-image udeb
+
+  * Fix /proc/cpuinfo revision for POWER9 DD2 (LP: #1698844)
+    - SAUCE: powerpc: Fix /proc/cpuinfo revision for POWER9 DD2
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_SATA_MV=n and CONFIG_GENERIC_PHY=n for s390x
+    - [Config] CONFIG_ATA=n for s390x
+    - [Config] Update annotations for 4.12
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 26 Jun 2017 11:27:29 -0500
+
+linux (4.12.0-3.4) artful; urgency=low
+
+  * Miscellaneous upstream changes
+    - ufs: fix the logics for tail relocation
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12-rc6
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 19 Jun 2017 14:50:39 -0500
+
+linux (4.12.0-2.3) artful; urgency=low
+
+  * CVE-2014-9900
+    - SAUCE: (no-up) net: Zeroing the structure ethtool_wolinfo in
+      ethtool_get_wol()
+
+  * System doesn't boot properly on Gigabyte AM4 motherboards (AMD Ryzen)
+    (LP: #1671360)
+    - pinctrl/amd: Use regular interrupt instead of chained
+
+  * extend-diff-ignore should use exact matches (LP: #1693504)
+    - [Packaging] exact extend-diff-ignore matches
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: efi: Don't print secure boot state from the efi stub
+    - ubuntu: vbox -- Update to 5.1.22-dfsg-1
+    - SAUCE: vbox fixes for 4.12
+    - Re-enable virtualbox build
+    - [Config] CONFIG_ORANGEFS_FS=m
+    - SAUCE: (noup) Update spl to 0.6.5.9-1ubuntu2, zfs to 0.6.5.9-5ubuntu7
+    - Enable zfs build
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12-rc4
+  * Rebase to v4.12-rc5
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 11 Jun 2017 22:25:13 -0500
+
+linux (4.12.0-1.2) artful; urgency=low
+
+  * Enable Matrox driver for Ubuntu 16.04.3 (LP: #1693337)
+    - [Config] Enable CONFIG_DRM_MGAG200 as module
+
+  * Support low-pin-count devices on Hisilicon SoCs (LP: #1677319)
+    - [Config] CONFIG_LIBIO=y on arm64 only
+    - SAUCE: LIBIO: Introduce a generic PIO mapping method
+    - SAUCE: OF: Add missing I/O range exception for indirect-IO devices
+    - [Config] CONFIG_HISILICON_LPC=y
+    - SAUCE: LPC: Support the device-tree LPC host on Hip06/Hip07
+    - SAUCE: LIBIO: Support the dynamically logical PIO registration of ACPI host
+      I/O
+    - SAUCE: LPC: Add the ACPI LPC support
+    - SAUCE: PCI: Apply the new generic I/O management on PCI IO hosts
+    - SAUCE: PCI: Restore codepath for !CONFIG_LIBIO
+
+  * POWER9: Additional patches for TTY and CPU_IDLE (LP: #1674325)
+    - SAUCE: tty: Fix ldisc crash on reopened tty
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Add build-dep on libnuma-dev to enable 'perf bench numa'
+    - Rebase to v4.12-rc3
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12-rc3
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Mon, 29 May 2017 20:56:29 -0500
+
+linux (4.12.0-0.1) artful; urgency=low
+
+  * please enable CONFIG_ARM64_LSE_ATOMICS (LP: #1691614)
+    - [Config] CONFIG_ARM64_LSE_ATOMICS=y
+
+  * [Regression] NUMA_BALANCING disabled on arm64 (LP: #1690914)
+    - [Config] CONFIG_NUMA_BALANCING{,_DEFAULT_ENABLED}=y on arm64
+
+  * 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
+
+  * Miscellaneous Ubuntu changes
+    - Update find-missing-sauce.sh to compare to artful
+    - Update dropped.txt
+    - SAUCE: (efi-lockdown) efi: Add EFI_SECURE_BOOT bit
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/mem and /dev/kmem when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Add a sysrq option to exit secure boot mode
+    - SAUCE: (efi-lockdown) kexec: Disable at runtime if the kernel is locked down
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) kexec_file: Disable at runtime if securelevel has been
+      set
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) asus-wmi: Restrict debugfs interface when the kernel
+      is locked down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Enable cold boot attack mitigation
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - SAUCE: (efi-lockdown) scsi: Lock down the eata driver
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) KEYS: Allow unrestricted boot-time addition of keys to
+      secondary keyring
+    - SAUCE: (efi-lockdown) efi: Add EFI signature data types
+    - SAUCE: (efi-lockdown) efi: Add an EFI signature blob parser
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Allow the "db" UEFI variable to be suppressed
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) efi: Add secure_boot state and status bit for
+      MokSBState
+    - SAUCE: (efi-lockdown) efi: Add sysctls for secureboot and MokSBState
+    - [Config] Set values for UEFI secure boot lockdown options
+    - Disable virtualbox build
+    - Disable hio build
+    - SAUCE: securityfs: Replace CURRENT_TIME with current_time()
+    - Disable zfs build
+    - [Debian] Work out upstream tag for use with gen-auto-reconstruct
+    - SAUCE: Import aufs driver
+    - SAUCE: aufs -- Include linux/mm.h in fs/aufs/file.h
+    - [Config] Enable aufs
+    - SAUCE: perf callchain: Include errno.h on x86 unconditinally
+
+  [ Upstream Kernel Changes ]
+
+  * Rebase to v4.12-rc2
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Sun, 21 May 2017 23:44:44 -0500
+
+linux (4.11.0-3.8) artful; urgency=low
+
+  [ Seth Forshee ]
+
+  * Release Tracking Bug
+    - LP: #1690999
+
+  * 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
+
+  * libvirt profile is blocking global setrlimit despite having no rlimit rule
+    (LP: #1679704)
+    - SAUCE: apparmor: fix complain mode failure for rlimit mediation
+    - apparmor: update auditing of rlimit check to provide capability information
+
+  * apparmor: does not provide a way to detect policy updataes (LP: #1678032)
+    - SAUCE: apparmor: add policy revision file interface
+
+  * apparmor does not make support of query data visible (LP: #1678023)
+    - SAUCE: apparmor: add label data availability to the feature set
+
+  * apparmor query interface does not make supported query info available
+    (LP: #1678030)
+    - SAUCE: apparmor: add information about the query inteface to the feature set
+
+  * change_profile incorrect when using namespaces with a compound stack
+    (LP: #1677959)
+    - SAUCE: apparmor: fix label parse for stacked labels
+
+  * Regression in 4.4.0-65-generic causes very frequent system crashes
+    (LP: #1669611)
+    - apparmor: sync of apparmor 3.6+ (17.04)
+
+  * Artful update to 4.11.1 stable release (LP: #1690814)
+    - dm ioctl: prevent stack leak in dm ioctl call
+    - drm/sti: fix GDP size to support up to UHD resolution
+    - power: supply: lp8788: prevent out of bounds array access
+    - brcmfmac: Ensure pointer correctly set if skb data location changes
+    - brcmfmac: Make skb header writable before use
+    - sparc64: fix fault handling in NGbzero.S and GENbzero.S
+    - refcount: change EXPORT_SYMBOL markings
+    - net: macb: fix phy interrupt parsing
+    - tcp: fix access to sk->sk_state in tcp_poll()
+    - geneve: fix incorrect setting of UDP checksum flag
+    - bpf: enhance verifier to understand stack pointer arithmetic
+    - bpf, arm64: fix jit branch offset related to ldimm64
+    - tcp: fix wraparound issue in tcp_lp
+    - net: ipv6: Do not duplicate DAD on link up
+    - net: usb: qmi_wwan: add Telit ME910 support
+    - 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
+    - tcp: randomize timestamps on syncookies
+    - bnxt_en: allocate enough space for ->ntp_fltr_bmap
+    - bpf: don't let ldimm64 leak map addresses on unprivileged
+    - net: mdio-mux: bcm-iproc: call mdiobus_free() in error path
+    - f2fs: sanity check segment count
+    - xen/arm,arm64: fix xen_dma_ops after 815dd18 "Consolidate get_dma_ops..."
+    - xen: Revert commits da72ff5bfcb0 and 72a9b186292d
+    - block: get rid of blk_integrity_revalidate()
+    - Linux 4.11.1
+
+  * Module signing exclusion for staging drivers does not work properly
+    (LP: #1690908)
+    - SAUCE: Fix module signing exclusion in package builds
+
+  * perf: qcom: Add L3 cache PMU driver (LP: #1689856)
+    - [Config] CONFIG_QCOM_L3_PMU=y
+    - perf: qcom: Add L3 cache PMU driver
+
+  * No PMU support for ACPI-based arm64 systems (LP: #1689661)
+    - drivers/perf: arm_pmu: rework per-cpu allocation
+    - drivers/perf: arm_pmu: manage interrupts per-cpu
+    - drivers/perf: arm_pmu: split irq request from enable
+    - drivers/perf: arm_pmu: remove pointless PMU disabling
+    - drivers/perf: arm_pmu: define armpmu_init_fn
+    - drivers/perf: arm_pmu: fold init into alloc
+    - drivers/perf: arm_pmu: factor out pmu registration
+    - drivers/perf: arm_pmu: simplify cpu_pmu_request_irqs()
+    - drivers/perf: arm_pmu: handle no platform_device
+    - drivers/perf: arm_pmu: rename irq request/free functions
+    - drivers/perf: arm_pmu: split cpu-local irq request/free
+    - drivers/perf: arm_pmu: move irq request/free into probe
+    - drivers/perf: arm_pmu: split out platform device probe logic
+    - arm64: add function to get a cpu's MADT GICC table
+    - [Config] CONFIG_ARM_PMU_ACPI=y
+    - drivers/perf: arm_pmu: add ACPI framework
+    - arm64: pmuv3: handle !PMUv3 when probing
+    - arm64: pmuv3: use arm_pmu ACPI framework
+
+  * Fix NVLINK2 TCE route (LP: #1690155)
+    - powerpc/powernv: Fix TCE kill on NVLink2
+
+  * CVE-2017-0605
+    - tracing: Use strlcpy() instead of strcpy() in __trace_find_cmdline()
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Restore powerpc arch to annotations file
+    - [Config] Disable runtime testing modules
+    - [Config] Disable drivers not needed on s390x
+    - [Config] Update annotations for 4.11
+    - [Config] updateconfigs after apparmor updates
+
+  * Miscellaneous upstream changes
+    - apparmor: use SHASH_DESC_ON_STACK
+    - apparmor: fix invalid reference to index variable of iterator line 836
+    - apparmor: fix parameters so that the permission test is bypassed at boot
+    - apparmor: Make path_max parameter readonly
+    - apparmorfs: Combine two function calls into one in aa_fs_seq_raw_abi_show()
+    - apparmorfs: Use seq_putc() in two functions
+    - apparmor: provide information about path buffer size at boot
+    - apparmor: add/use fns to print hash string hex value
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 16 May 2017 00:39:13 -0500
+
+linux (4.11.0-2.7) artful; urgency=low
+
+  * kernel-wedge fails in artful due to leftover squashfs-modules d-i files
+    (LP: #1688259)
+    - Remove squashfs-modules files from d-i
+    - [Config] as squashfs-modules is builtin kernel-image must Provides: it
+
+  * [Zesty] d-i: replace msm_emac with qcom_emac (LP: #1677297)
+    - Revert "UBUNTU: d-i: initrd needs msm_emac on amberwing platform."
+    - d-i: initrd needs qcom_emac on amberwing platform.
+
+  * update for V3 kernel bits and improved multiple fan slice support
+    (LP: #1470091)
+    - SAUCE: fan: tunnel multiple mapping mode (v3)
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: (noup) Update spl to 0.6.5.9-1ubuntu1, zfs to 0.6.5.9-5ubuntu5
+    - Enable zfs
+    - SAUCE: fan: add VXLAN implementation
+    - SAUCE: (efi-lockdown) efi: Add EFI_SECURE_BOOT bit
+    - SAUCE: (efi-lockdown) Add the ability to lock down access to the running
+      kernel image
+    - SAUCE: (efi-lockdown) efi: Lock down the kernel if booted in secure boot
+      mode
+    - SAUCE: (efi-lockdown) Enforce module signatures if the kernel is locked down
+    - SAUCE: (efi-lockdown) Restrict /dev/mem and /dev/kmem when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Add a sysrq option to exit secure boot mode
+    - SAUCE: (efi-lockdown) kexec: Disable at runtime if the kernel is locked down
+    - SAUCE: (efi-lockdown) Copy secure_boot flag in boot params across kexec
+      reboot
+    - SAUCE: (efi-lockdown) kexec_file: Disable at runtime if securelevel has been
+      set
+    - SAUCE: (efi-lockdown) hibernate: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) uswsusp: Disable when the kernel is locked down
+    - SAUCE: (efi-lockdown) PCI: Lock down BAR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) x86: Lock down IO port access when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) x86: Restrict MSR access when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) asus-wmi: Restrict debugfs interface when the kernel
+      is locked down
+    - SAUCE: (efi-lockdown) ACPI: Limit access to custom_method when the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Ignore acpi_rsdp kernel param when the kernel
+      has been locked down
+    - SAUCE: (efi-lockdown) acpi: Disable ACPI table override if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) acpi: Disable APEI error injection if the kernel is
+      locked down
+    - SAUCE: (efi-lockdown) Enable cold boot attack mitigation
+    - SAUCE: (efi-lockdown) bpf: Restrict kernel image access functions when the
+      kernel is locked down
+    - SAUCE: (efi-lockdown) scsi: Lock down the eata driver
+    - SAUCE: (efi-lockdown) Prohibit PCMCIA CIS storage when the kernel is locked
+      down
+    - SAUCE: (efi-lockdown) Lock down TIOCSSERIAL
+    - SAUCE: (efi-lockdown) Add EFI signature data types
+    - SAUCE: (efi-lockdown) Add an EFI signature blob parser and key loader.
+    - SAUCE: (efi-lockdown) KEYS: Add a system blacklist keyring
+    - SAUCE: (efi-lockdown) MODSIGN: Import certificates from UEFI Secure Boot
+    - SAUCE: (efi-lockdown) MODSIGN: Support not importing certs from db
+    - SAUCE: (efi-lockdown) MODSIGN: Don't try secure boot if EFI runtime is
+      disabled
+    - SAUCE: (efi-lockdown) efi: Sanitize boot_params in efi stub
+    - SAUCE: (efi-lockdown) efi: Add secure_boot state and status bit for
+      MokSBState
+    - SAUCE: (efi-lockdown) efi: Add sysctls for secureboot and MokSBState
+    - [Config] Set values for UEFI secure boot lockdown options
+    - Update dropped.txt
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Fri, 05 May 2017 07:43:14 -0500
+
+linux (4.11.0-1.6) artful; urgency=low
+
+  * Miscellaneous Ubuntu changes
+    - [Debian] Use default compression for all packages
+    - SAUCE: (namespace) block_dev: Support checking inode permissions in
+      lookup_bdev()
+    - SAUCE: (namespace) block_dev: Check permissions towards block device inode
+      when mounting
+    - SAUCE: (namespace) mtd: Check permissions towards mtd block device inode
+      when mounting
+    - SAUCE: (namespace) fs: Allow superblock owner to change ownership of inodes
+    - SAUCE: (namespace) fs: Don't remove suid for CAP_FSETID for userns root
+    - SAUCE: (namespace) fs: Allow superblock owner to access do_remount_sb()
+    - SAUCE: (namespace) capabilities: Allow privileged user in s_user_ns to set
+      security.* xattrs
+    - SAUCE: (namespace) fs: Allow CAP_SYS_ADMIN in s_user_ns to freeze and thaw
+      filesystems
+    - SAUCE: (namespace) fuse: Add support for pid namespaces
+    - SAUCE: (namespace) fuse: Support fuse filesystems outside of init_user_ns
+    - SAUCE: (namespace) fuse: Restrict allow_other to the superblock's namespace
+      or a descendant
+    - SAUCE: (namespace) fuse: Allow user namespace mounts
+    - SAUCE: (namespace) ext4: Add support for unprivileged mounts from user
+      namespaces
+    - SAUCE: (namespace) evm: Don't update hmacs in user ns mounts
+    - SAUCE: (namespace) ext4: Add module parameter to enable user namespace
+      mounts
+    - SAUCE: (namespace) block_dev: Forbid unprivileged mounting when device is
+      opened for writing
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Wed, 26 Apr 2017 10:08:29 -0500
+
+linux (4.11.0-0.5) artful; urgency=low
+
+  * [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
+
+  * [Hyper-V] Ubuntu 14.04.2 LTS Generation 2 SCSI Errors on VSS Based Backups
+    (LP: #1470250)
+    - SAUCE: Tools: hv: vss: Thaw the filesystem and continue after freeze fails
+
+  * Enable virtual scsi server driver for Power (LP: #1615665)
+    - SAUCE: Return TCMU-generated sense data to fabric module
+
+  * include/linux/security.h header syntax error with !CONFIG_SECURITYFS
+    (LP: #1630990)
+    - SAUCE: (no-up) include/linux/security.h -- fix syntax error with
+      CONFIG_SECURITYFS=n
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: Import aufs driver
+    - [Config] Enable aufs
+    - [Debian] Add script to update virtualbox
+    - ubuntu: vbox -- Update to 5.1.20-dfsg-2
+    - Enable vbox
+    - SAUCE: aufs -- Include linux/mm.h in fs/aufs/file.h
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11-rc8
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 25 Apr 2017 13:42:54 -0500
+
+linux (4.11.0-0.4) zesty; urgency=low
+
+  * POWER9: Improve performance on memory management (LP: #1681429)
+    - SAUCE: powerpc/mm/radix: Don't do page walk cache flush when doing full mm
+      flush
+    - SAUCE: powerpc/mm/radix: Remove unnecessary ptesync
+
+  * Miscellaneous Ubuntu changes
+    - find-missing-sauce.sh
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11-rc7
+
+ -- Seth Forshee <seth.forshee@canonical.com>  Tue, 18 Apr 2017 08:19:43 -0500
+
+linux (4.11.0-0.3) zesty; urgency=low
+
+  * Disable CONFIG_HVC_UDBG on ppc64el (LP: #1680888)
+    - [Config] Disable CONFIG_HVC_UDBG on ppc64el
+
+  * smartpqi driver needed in initram disk and installer (LP: #1680156)
+    - [Config] Add smartpqi to d-i
+
+  * Disable CONFIG_SECURITY_SELINUX_DISABLE (LP: #1680315)
+    - [Config] CONFIG_SECURITY_SELINUX_DISABLE=n
+
+  * Miscellaneous Ubuntu changes
+    - [Config] flash-kernel should be a Breaks
+    - [Config] drop the info directory
+    - [Config] drop NOTES as obsolete
+    - [Config] drop changelog.historical as obsolete
+    - rebase to v4.11-rc6
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11-rc6
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Tue, 11 Apr 2017 07:16:52 -0600
+
+linux (4.11.0-0.2) zesty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11-rc5
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 03 Apr 2017 08:26:07 +0100
+
+linux (4.11.0-0.1) zesty; urgency=low
+
+  [ Upstream Kernel Changes ]
+
+  * rebase to v4.11-rc4
+    - LP: #1591053
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 20 Mar 2017 05:15:32 -0600
+
+linux (4.11.0-0.0) zesty; urgency=low
+
+  * dummy entry
+
+ -- Tim Gardner <tim.gardner@canonical.com>  Mon, 20 Mar 2017 05:15:32 -0600
--- linux-ein-5.4.0.orig/debian.master/config/README.rst
+++ linux-ein-5.4.0/debian.master/config/README.rst
@@ -0,0 +1,185 @@
+==================
+Config Annotations
+==================
+
+:Author: Andrea Righi
+
+Overview
+========
+
+Each Ubuntu kernel needs to maintain its own .config for each supported
+architecture and each flavour.
+
+Every time a new patch is applied or a kernel is rebased on top of a new
+one, we need to update the .config's accordingly (config options can be
+added, removed and also renamed).
+
+So, we need to make sure that some critical config options are always
+matching the desired value in order to have a functional kernel.
+
+State of the art
+================
+
+At the moment configs are maintained as a set of Kconfig chunks (inside
+`debian.<kernel>/config/`): a global one, plus per-arch / per-flavour
+chunks.
+
+In addition to that, we need to maintain also a file called
+'annotations'; the purpose of this file is to make sure that some
+critical config options are not silently removed or changed when the
+real .config is re-generated (for example after a rebase or after
+applying a new set of patches).
+
+The main problem with this approach is that, often, we have duplicate
+information that is stored both in the Kconfig chunks *and* in the
+annotations files and, at the same time, the whole .config's information
+is distributed between Kconfig chunks and annotations, making it hard to
+maintain, review and manage in general.
+
+Proposed solution
+=================
+
+The proposed solution is to store all the config information into the
+"annotations" format and get rid of the config chunks (basically the
+real .config's can be produced "compiling" annotations).
+
+Implementation
+==============
+
+To help the management of the annotations an helper script is provided
+(`debian/scripts/misc/annotations`):
+
+```
+usage: annotations [-h] [--version] [--file FILE] [--arch ARCH] [--flavour FLAVOUR] [--config CONFIG]
+                   (--query | --export | --import FILE | --update FILE | --check FILE)
+
+Manage Ubuntu kernel .config and annotations
+
+options:
+  -h, --help            show this help message and exit
+  --version, -v         show program's version number and exit
+  --file FILE, -f FILE  Pass annotations or .config file to be parsed
+  --arch ARCH, -a ARCH  Select architecture
+  --flavour FLAVOUR, -l FLAVOUR
+                        Select flavour (default is "generic")
+  --config CONFIG, -c CONFIG
+                        Select a specific config option
+
+Action:
+  --query, -q           Query annotations
+  --export, -e          Convert annotations to .config format
+  --import FILE, -i FILE
+                        Import a full .config for a specific arch and flavour into annotations
+  --update FILE, -u FILE
+                        Import a partial .config into annotations (only resync configs specified in FILE)
+  --check FILE, -k FILE
+                        Validate kernel .config with annotations
+```
+
+This script allows to query config settings (per arch/flavour/config),
+export them into the Kconfig format (generating the real .config files)
+and check if the final .config matches the rules defined in the
+annotations.
+
+Examples (annotations is defined as an alias to `debian/scripts/annotations`):
+
+ - Show settings for `CONFIG_DEBUG_INFO_BTF` for master kernel across all the
+   supported architectures and flavours:
+
+```
+$ annotations --query --config CONFIG_DEBUG_INFO_BTF
+{
+    "policy": {
+        "amd64": "y",
+        "arm64": "y",
+        "armhf": "n",
+        "ppc64el": "y",
+        "riscv64": "y",
+        "s390x": "y"
+    },
+    "note": "'Needs newer pahole for armhf'"
+}
+```
+
+ - Dump kernel .config for arm64 and flavour generic-64k:
+
+```
+$ annotations --arch arm64 --flavour generic-64k --export
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_COMPAT=y
+...
+```
+
+ - Update annotations file with a new kernel .config for amd64 flavour
+   generic:
+
+```
+$ annotations --arch amd64 --flavour generic --import build/.config
+```
+
+Moreover, an additional kernelconfig commands are provided
+(via debian/rules targets):
+ - `migrateconfigs`: automatically merge all the previous configs into
+   annotations (local changes still need to be committed)
+
+Annotations headers
+===================
+
+The main annotations file should contain a header to define the architectures
+and flavours that are supported.
+
+Here is the format of the header for the generic kernel:
+```
+# Menu: HEADER
+# FORMAT: 4
+# ARCH: amd64 arm64 armhf ppc64el riscv64 s390x
+# FLAVOUR: amd64-generic arm64-generic arm64-generic-64k armhf-generic armhf-generic-lpae ppc64el-generic riscv64-generic s390x-generic
+
+```
+
+Example header of a derivative (linux-aws):
+```
+# Menu: HEADER
+# FORMAT: 4
+# ARCH: amd64 arm64
+# FLAVOUR: amd64-aws arm64-aws
+# FLAVOUR_DEP: {'amd64-aws': 'amd64-generic', 'arm64-aws': 'arm64-generic'}
+
+include "../../debian.master/config/annotations"
+
+# Below you can define only the specific linux-aws configs that differ from linux generic
+
+```
+
+Pros and Cons
+=============
+
+ Pros:
+  - avoid duplicate information in .config's and annotations
+  - allow to easily define groups of config settings (for a specific
+    environment or feature, such as annotations.clouds, annotations.ubuntu,
+    annotations.snapd, etc.)
+  - config options are more accessible, easy to change and review
+  - we can easily document how config options are managed (and external
+    contributors won't be discouraged anymore when they need to to change a
+    config option)
+
+ Cons:
+  - potential regressions: the new tool/scripts can have potential bugs,
+    so we could experience regressions due to some missed config changes
+  - kernel team need to understand the new process (even if everything
+    is transparent, kernel cranking process is the same, there might be
+    corner cases that need to be addressed and resolved manually)
+
+TODO
+====
+
+ - Migrate all flavour and arch definitions into annotations (rather
+   than having this information defined in multiple places inside
+   debian/scripts); right now this information is "partially" migrated,
+   meaning that we need to define arches and flavours in the headers
+   section of annotations (so that the annotations tool can figure out
+   the list of supported arches and flavours), but arches and flavours
+   are still defined elsewhere, ideally we would like to have arches and
+   flavours defined only in one place: annotations.
--- linux-ein-5.4.0.orig/debian.master/config/annotations
+++ linux-ein-5.4.0/debian.master/config/annotations
@@ -0,0 +1,12858 @@
+# Menu: HEADER
+# FORMAT: 4
+# ARCH: amd64 arm64 armhf i386 ppc64el s390x
+# FLAVOUR: amd64-generic amd64-lowlatency arm64-generic armhf-generic armhf-generic-lpae i386-generic i386-lowlatency ppc64el-generic s390x-generic
+
+CONFIG_ACPI_CUSTOM_DSDT_FILE                    policy<{'amd64': '""', 'i386': '""'}>
+CONFIG_ACPI_CUSTOM_DSDT_FILE                    note<'might allow hardware damage'>
+
+CONFIG_ACPI_CUSTOM_METHOD                       policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_CUSTOM_METHOD                       note<'SECURITY: allows arbitrary execution'>
+
+CONFIG_AGP                                      policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AGP                                      note<'not autoloadable'>
+
+CONFIG_ARCH_ROCKCHIP                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_ROCKCHIP                            note<'LP:1566283 / LP:1825222'>
+
+CONFIG_ARCH_TANGO                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_TANGO                               note<'LP:1787945'>
+
+CONFIG_ARCH_ZX                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARCH_ZX                                  note<'LP:1628503'>
+
+CONFIG_ARM64_ERRATUM_843419                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_843419                     note<'LP:1647793'>
+
+CONFIG_ARM64_ERRATUM_858921                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_858921                     note<'LP#1675509'>
+
+CONFIG_ARM64_LSE_ATOMICS                        policy<{'arm64': 'y'}>
+CONFIG_ARM64_LSE_ATOMICS                        note<'LP:1691614'>
+
+CONFIG_ARM64_VA_BITS_48                         policy<{'arm64': 'y'}>
+CONFIG_ARM64_VA_BITS_48                         note<'Cavium ThunderX 2-socket needs a minimum of 41 bits of VA'>
+
+CONFIG_ARMV8_DEPRECATED                         policy<{'arm64': 'y'}>
+CONFIG_ARMV8_DEPRECATED                         note<'LP:1545542'>
+
+CONFIG_ARM_HIGHBANK_CPUIDLE                     policy<{'armhf-generic': 'n', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARM_HIGHBANK_CPUIDLE                     note<'broken on ecx-1000'>
+
+CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT       policy<{'arm64': 'n'}>
+CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT       note<'LP:1845820'>
+
+CONFIG_ASYMMETRIC_KEY_TYPE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASYMMETRIC_KEY_TYPE                      note<'module signing'>
+
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE            note<'module signing'>
+
+CONFIG_ATA_PIIX                                 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_ATA_PIIX                                 note<'LP:1627324'>
+
+CONFIG_AUFS_EXPORT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_EXPORT                              note<'LP:1121699'>
+
+CONFIG_BINFMT_SCRIPT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BINFMT_SCRIPT                            note<'required if init is a shell script such as in initramfs-tools'>
+
+CONFIG_BLK_DEV_DM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_DM                               note<'LP:#560717'>
+
+CONFIG_BLK_DEV_NVME                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_NVME                             note<'LP:#1759893'>
+
+CONFIG_BLK_DEV_RAM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_RAM                              note<'LP #1593293'>
+
+CONFIG_BLK_DEV_RAM_SIZE                         policy<{'amd64': '65536', 'arm64': '65536', 'armhf': '65536', 'i386': '65536', 'ppc64el': '65536', 's390x': '65536'}>
+CONFIG_BLK_DEV_RAM_SIZE                         note<'Ramdisk size should be a minimum of 64M'>
+
+CONFIG_BLK_DEV_SD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_SD                               note<'LP:1627330'>
+
+CONFIG_BLK_DEV_SR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_SR                               note<'LP:1627330'>
+
+CONFIG_BLK_DEV_THROTTLING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_THROTTLING                       note<'CGROUP disk consumption control'>
+
+CONFIG_BLK_DEV_UMEM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_UMEM                             note<'experimental NVRAM disk driver -- opt-in'>
+
+CONFIG_BT_HS                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BT_HS                                    note<'https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00435.html'>
+
+CONFIG_CHR_DEV_SG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CHR_DEV_SG                               note<'not autoloadable'>
+
+CONFIG_CMA_SIZE_MBYTES                          policy<{'arm64': '32', 'armhf': '32'}>
+CONFIG_CMA_SIZE_MBYTES                          note<'LP:1823753'>
+
+CONFIG_COMPAT_BRK                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_COMPAT_BRK                               note<'disables brk ASLR'>
+
+CONFIG_CP15_BARRIER_EMULATION                   policy<{'arm64': 'y'}>
+CONFIG_CP15_BARRIER_EMULATION                   note<'LP:1545542'>
+
+CONFIG_CPUFREQ_DT                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CPUFREQ_DT                               note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE         note<'for bootspeed'>
+
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE                note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_ONDEMAND                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_ONDEMAND                    note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_PERFORMANCE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_PERFORMANCE                 note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_POWERSAVE                   note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_GOV_USERSPACE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_USERSPACE                   note<'not autoloadable'>
+
+CONFIG_CPU_FREQ_STAT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_STAT                            note<'dependancy of boot essential'>
+
+CONFIG_CRASH_DUMP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRASH_DUMP                               note<'LP:1363180'>
+
+CONFIG_CRYPTO_SHA512                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SHA512                            note<'module signing'>
+
+CONFIG_CS5535_MFGPT                             policy<{'i386': 'n'}>
+CONFIG_CS5535_MFGPT                             note<'should be disabled by default'>
+
+CONFIG_DEBUG_FS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_FS                                 note<'required debug option'>
+
+CONFIG_DEBUG_INFO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_INFO                               note<'required for debug packages'>
+
+CONFIG_DEBUG_INFO_SPLIT                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_INFO_SPLIT                         note<'LP:1413646 and LP:1413664'>
+
+CONFIG_DEBUG_KERNEL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_KERNEL                             note<'required debug option'>
+
+CONFIG_DEFAULT_MMAP_MIN_ADDR                    policy<{'amd64': '65536', 'arm64': '32768', 'armhf': '32768', 'i386': '65536', 'ppc64el': '65536', 's390x': '65536'}>
+CONFIG_DEFAULT_MMAP_MIN_ADDR                    note<'LP:1418140 LP:1531327'>
+
+CONFIG_DEVKMEM                                  policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEVKMEM                                  note<'/dev/kmem is a large attack vector'>
+
+CONFIG_DEVTMPFS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVTMPFS                                 note<'upstart requirement'>
+
+CONFIG_DEVTMPFS_MOUNT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVTMPFS_MOUNT                           note<'upstart requirement'>
+
+CONFIG_DMA_CMA                                  policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 's390x': 'n'}>
+CONFIG_DMA_CMA                                  note<'LP:1803206'>
+
+CONFIG_DRM_AMDGPU_CIK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMDGPU_CIK                           note<'LP:1661887 for zesty'>
+
+CONFIG_DRM_BOCHS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_BOCHS                                note<'LP#1916290'>
+
+CONFIG_DRM_HISI_HIBMC                           policy<{'arm64': 'm'}>
+CONFIG_DRM_HISI_HIBMC                           note<'LP:1762940'>
+
+CONFIG_DRM_LEGACY                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DRM_LEGACY                               note<'Consider re-enabling but not signing the modules'>
+
+CONFIG_DRM_MGAG200                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_MGAG200                              note<'LP#1693337'>
+
+CONFIG_DRM_STI                                  policy<{'armhf': 'n'}>
+CONFIG_DRM_STI                                  note<'LP#1398458'>
+
+CONFIG_DRM_VBOXVIDEO                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_VBOXVIDEO                            note<'LP:1718679'>
+
+CONFIG_DVB_DUMMY_FE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DUMMY_FE                             note<'expert use only'>
+
+CONFIG_ECRYPT_FS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ECRYPT_FS                                note<'not autoloadable'>
+
+CONFIG_EFIVAR_FS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFIVAR_FS                                note<'needed for variable EFI update'>
+
+CONFIG_EFI_VARS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFI_VARS                                 note<'EFI boot requirement (d-i) LP:#837332'>
+
+CONFIG_EVM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM                                      note<'LP:1643652'>
+
+CONFIG_EVM_ATTR_FSUUID                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM_ATTR_FSUUID                          note<'LP:1643652'>
+
+CONFIG_EVM_LOAD_X509                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EVM_LOAD_X509                            note<'LP:1643652'>
+
+CONFIG_EVM_X509_PATH                            policy<{'ppc64el': '"/etc/keys/x509_evm.der"'}>
+CONFIG_EVM_X509_PATH                            note<'LP:1643652'>
+
+CONFIG_EXT2_FS                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EXT2_FS                                  note<'ext4 handling via EXT4_USE_FOR_EXT23'>
+
+CONFIG_EXT3_FS                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EXT3_FS                                  note<'ext4 handling via EXT4_USE_FOR_EXT23'>
+
+CONFIG_FA_DUMP                                  policy<{'ppc64el': 'y'}>
+CONFIG_FA_DUMP                                  note<'LP:1415562'>
+
+CONFIG_FHANDLE                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FHANDLE                                  note<'LP:1412543'>
+
+CONFIG_FUSE_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUSE_FS                                  note<'not autoloadable'>
+
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK           note<'LP#1398458'>
+
+CONFIG_GPIO_EM                                  policy<{'armhf': 'n'}>
+CONFIG_GPIO_EM                                  note<'h/w not encounted'>
+
+CONFIG_GPIO_TWL4030                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TWL4030                             note<'LP:#921934'>
+
+CONFIG_HIBERNATION                              policy<{'amd64': 'y', 'arm64': 'n', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HIBERNATION                              note<'LP:1867753'>
+
+CONFIG_HIO                                      policy<{'amd64': 'm', 'arm64': 'n', 'armhf': 'n', 'i386': 'm', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HIO                                      note<'LP:1635594'>
+
+CONFIG_HIPPI                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HIPPI                                    note<'DEPRECATED'>
+
+CONFIG_HOTPLUG_PCI_PCIE                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI_PCIE                         note<'LP#1374440'>
+
+CONFIG_HOTPLUG_PCI_SHPC                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HOTPLUG_PCI_SHPC                         note<'LP#1374440'>
+
+CONFIG_HVC_UDBG                                 policy<{'ppc64el': 'n'}>
+CONFIG_HVC_UDBG                                 note<'LP#1680888'>
+
+CONFIG_I2C_CHARDEV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_I2C_CHARDEV                              note<'LP:1417032'>
+
+CONFIG_IBMVNIC                                  policy<{'ppc64el': 'm'}>
+CONFIG_IBMVNIC                                  note<'LP:#1628187'>
+
+CONFIG_IDLE_PAGE_TRACKING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IDLE_PAGE_TRACKING                       note<'is there a cost associated with this?'>
+
+CONFIG_IIO_SIMPLE_DUMMY_BUFFER                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IIO_SIMPLE_DUMMY_BUFFER                  note<'dummy driver'>
+
+CONFIG_IIO_SIMPLE_DUMMY_EVENTS                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IIO_SIMPLE_DUMMY_EVENTS                  note<'dummy driver'>
+
+CONFIG_IMA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA                                      note<'LP:1643652'>
+
+CONFIG_IMA_APPRAISE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_APPRAISE                             note<'LP:1643652'>
+
+CONFIG_IMA_ARCH_POLICY                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_IMA_ARCH_POLICY                          note<'LP:1866909'>
+
+CONFIG_IMA_DEFAULT_HASH_SHA256                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_IMA_DEFAULT_HASH_SHA256                  note<'LP:1643652'>
+
+CONFIG_IMA_KEXEC                                policy<{'ppc64el': 'y'}>
+CONFIG_IMA_KEXEC                                note<'LP:1643652'>
+
+CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY note<'LP:1667490'>
+
+CONFIG_IMA_READ_POLICY                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_IMA_READ_POLICY                          note<'LP:1866909'>
+
+CONFIG_IMA_SIG_TEMPLATE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_IMA_SIG_TEMPLATE                         note<'LP:1643652'>
+
+CONFIG_IMA_WRITE_POLICY                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_WRITE_POLICY                         note<'LP:1667490'>
+
+CONFIG_INPUT_UINPUT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_UINPUT                             note<'LP:584812'>
+
+CONFIG_INTEGRITY_PLATFORM_KEYRING               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_PLATFORM_KEYRING               note<'Required for lockdown'>
+
+CONFIG_INTEL_IOMMU_DEFAULT_ON                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_INTEL_IOMMU_DEFAULT_ON                   note<'the IOMMU can trigger boot failures'>
+
+CONFIG_IOMMU_DEBUGFS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IOMMU_DEBUGFS                            note<'Should not be enabled in production, LP #1861057'>
+
+CONFIG_IPDDP                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IPDDP                                    note<'LP:1559772'>
+
+CONFIG_IPMMU_VMSA                               policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_IPMMU_VMSA                               note<'LP:1718734'>
+
+CONFIG_IPV6                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6                                     note<'if this is a module we get a module load for every ipv6 packet'>
+
+CONFIG_IP_PNP                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_PNP                                   note<'LP:1259861'>
+
+CONFIG_ISM                                      policy<{'s390x': 'm'}>
+CONFIG_ISM                                      note<'LP:1789934'>
+
+CONFIG_KEXEC_BZIMAGE_VERIFY_SIG                 policy<{'amd64': 'y'}>
+CONFIG_KEXEC_BZIMAGE_VERIFY_SIG                 note<'Q: check this is in sync with the kexec/kdump userspace'>
+
+CONFIG_KGDB_SERIAL_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KGDB_SERIAL_CONSOLE                      note<'early debugging support'>
+
+CONFIG_KVM                                      policy<{'amd64': 'm', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'm', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KVM                                      note<'LP:1532886'>
+
+CONFIG_LATENCYTOP                               policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LATENCYTOP                               note<'https://lists.ubuntu.com/archives/kernel-team/2014-July/045006.html, LP#1655986'>
+
+CONFIG_LOAD_PPC_KEYS                            policy<{'ppc64el': 'y'}>
+CONFIG_LOAD_PPC_KEYS                            note<'LP:1866909'>
+
+CONFIG_LOCALVERSION_AUTO                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCALVERSION_AUTO                        note<'triggers packaging failures'>
+
+CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE            note<'LP:1709171 LP:1848492'>
+
+CONFIG_MFD_SM501                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_SM501                                note<'boot essential on OMAP4'>
+
+CONFIG_MFD_TPS65217                             policy<{'arm64': 'm', 'armhf': 'y', 'ppc64el': 'n'}>
+CONFIG_MFD_TPS65217                             note<'boot essential on AM335x'>
+
+CONFIG_MMC_BLOCK                                policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_BLOCK                                note<'boot essential on armhf/arm64'>
+
+CONFIG_MMC_OMAP_HS                              policy<{'armhf': 'y'}>
+CONFIG_MMC_OMAP_HS                              note<'boot essential on arm'>
+
+CONFIG_MMC_SDHCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI                                note<'installation essential on omap/highbank'>
+
+CONFIG_MMC_SDHCI_PLTFM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_PLTFM                          note<'boot essential on highbank'>
+
+CONFIG_MODIFY_LDT_SYSCALL                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MODIFY_LDT_SYSCALL                       note<'Q: check this with security'>
+
+CONFIG_MODVERSIONS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODVERSIONS                              note<'LP:1898716 -- required as we have a livepatch/drivers modules signing key'>
+
+CONFIG_MOUSE_INPORT                             policy<{'i386': 'n'}>
+CONFIG_MOUSE_INPORT                             note<'very old ISA based mouse support'>
+
+CONFIG_MTD                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MTD                                      note<'boot essential on arm'>
+
+CONFIG_MTD_BLOCK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK                                note<'boot essential on arm'>
+
+CONFIG_MTD_DOCG3                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_DOCG3                                note<'LP:1792205'>
+
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE             note<'can be enabled at runtime'>
+
+CONFIG_MTD_NAND_OMAP2                           policy<{'armhf': 'y'}>
+CONFIG_MTD_NAND_OMAP2                           note<'boot essential on arm'>
+
+CONFIG_MTD_NAND_OMAP_BCH                        policy<{'armhf': 'y'}>
+CONFIG_MTD_NAND_OMAP_BCH                        note<'boot essential on arm'>
+
+CONFIG_MTD_OF_PARTS                             policy<{'arm64': 'm', 'armhf': 'y', 'ppc64el': 'm'}>
+CONFIG_MTD_OF_PARTS                             note<'boot essential on arm'>
+
+CONFIG_MTD_ONENAND_VERIFY_WRITE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_ONENAND_VERIFY_WRITE                 note<'writes here are not checked in full without'>
+
+CONFIG_MTD_RAW_NAND                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_RAW_NAND                             note<'boot essential on arm'>
+
+CONFIG_NETWORK_PHY_TIMESTAMPING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETWORK_PHY_TIMESTAMPING                 note<'LP:1785816'>
+
+CONFIG_NET_9P                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P                                   note<'LP:1557994'>
+
+CONFIG_NET_DROP_MONITOR                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_DROP_MONITOR                         note<'LP #1660634'>
+
+CONFIG_NET_SWITCHDEV                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SWITCHDEV                            note<'LP: #1865452, updated to y for s390x starting with focal'>
+
+CONFIG_NET_VENDOR_EMULEX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_EMULEX                        note<'LP:1543165'>
+
+CONFIG_NLS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLS                                      note<'dependancy of boot essential'>
+
+CONFIG_NOP_USB_XCEIV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NOP_USB_XCEIV                            note<'boot essential on omap/highbank'>
+
+CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT               note<'Selects CONFIG_DRM_LEGACY which is not wanted'>
+
+CONFIG_NO_HZ_IDLE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NO_HZ_IDLE                               note<'LP:1413968'>
+
+CONFIG_NR_CPUS                                  policy<{'amd64': '8192', 'arm64': '256', 'armhf': '4', 'i386': '8', 'ppc64el': '2048', 's390x': '512'}>
+CONFIG_NR_CPUS                                  note<'LP:1864198'>
+
+CONFIG_NUMA                                     policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NUMA                                     note<'LP:1543165 LP:1557690'>
+
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED           note<'LP:1557690'>
+
+CONFIG_NUMA_EMU                                 policy<{'amd64': 'n', 's390x': 'n'}>
+CONFIG_NUMA_EMU                                 note<'LP:1864198'>
+
+CONFIG_NVMEM                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NVMEM                                    note<'Q: is this appropriate for s390x LP:1543165'>
+
+CONFIG_NVRAM                                    policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'y'}>
+CONFIG_NVRAM                                    note<'LP#1837726'>
+
+CONFIG_N_GSM                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_N_GSM                                    note<'LP#1404670'>
+
+CONFIG_PAGE_POISONING                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_POISONING                           note<'LP:1783651'>
+
+CONFIG_PAGE_POISONING_NO_SANITY                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_POISONING_NO_SANITY                 note<'LP:1783651'>
+
+CONFIG_PAGE_POISONING_ZERO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_POISONING_ZERO                      note<'LP:1783651'>
+
+CONFIG_PANIC_ON_OOPS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PANIC_ON_OOPS                            note<'keep working if at all possible'>
+
+CONFIG_PATA_HPT3X3_DMA                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PATA_HPT3X3_DMA                          note<'DMA mode is documented problematic'>
+
+CONFIG_PCIEASPM_DEFAULT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_PCIEASPM_DEFAULT                         note<'LP#1398544'>
+
+CONFIG_PCIEPORTBUS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PCIEPORTBUS                              note<'LP#1665404'>
+
+CONFIG_PCI_NR_FUNCTIONS                         policy<{'s390x': '512'}>
+CONFIG_PCI_NR_FUNCTIONS                         note<'LP:1866056'>
+
+CONFIG_PINCTRL_CHERRYVIEW                       policy<{'amd64': 'y', 'i386': 'm'}>
+CONFIG_PINCTRL_CHERRYVIEW                       note<'LP #1630238'>
+
+CONFIG_PM                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PM                                       note<'LP:1867753'>
+
+CONFIG_PPC_MEM_KEYS                             policy<{'ppc64el': 'n'}>
+CONFIG_PPC_MEM_KEYS                             note<'LP:1776967'>
+
+CONFIG_PPC_RTAS_FILTER                          policy<{'ppc64el': 'y'}>
+CONFIG_PPC_RTAS_FILTER                          note<'CVE-2020-27777'>
+
+CONFIG_PPC_SECURE_BOOT                          policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SECURE_BOOT                          note<'LP:1855668'>
+
+CONFIG_PPC_SECVAR_SYSFS                         policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SECVAR_SYSFS                         note<'LP:1866909'>
+
+CONFIG_PREEMPT_NONE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PREEMPT_NONE                             note<'LP:1543165'>
+
+CONFIG_PSI_DEFAULT_DISABLED                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_PSI_DEFAULT_DISABLED                     note<'LP: #1876044'>
+
+CONFIG_QCOM_QDF2400_ERRATUM_0065                policy<{'arm64': 'y'}>
+CONFIG_QCOM_QDF2400_ERRATUM_0065                note<'LP:1672486'>
+
+CONFIG_REGULATOR_FIXED_VOLTAGE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_FIXED_VOLTAGE                  note<'boot essential on arm'>
+
+CONFIG_REGULATOR_TPS65217                       policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_REGULATOR_TPS65217                       note<'boot essential on AM335x'>
+
+CONFIG_REGULATOR_TWL4030                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TWL4030                        note<'boot requisite for omap4'>
+
+CONFIG_RTC_DRV_CMOS                             policy<{'amd64': 'y', 'armhf': 'm', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_CMOS                             note<'boot essential on i386/amd64'>
+
+CONFIG_RTC_DRV_EFI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RTC_DRV_EFI                              note<'LP:#1583738'>
+
+CONFIG_RTC_DRV_TWL4030                          policy<{'arm64': 'm', 'armhf': 'y', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TWL4030                          note<'boot essential on OMAP3/OMAP4'>
+
+CONFIG_RT_GROUP_SCHED                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RT_GROUP_SCHED                           note<'LP#1875665'>
+
+CONFIG_SAMPLE_TRACE_PRINTK                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SAMPLE_TRACE_PRINTK                      note<'Required for ftrace selftests'>
+
+CONFIG_SATA_AHCI_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_AHCI_PLATFORM                       note<'boot essential on highbank'>
+
+CONFIG_SATA_HIGHBANK                            policy<{'armhf': 'y'}>
+CONFIG_SATA_HIGHBANK                            note<'LP:1703430'>
+
+CONFIG_SCLP_OFB                                 policy<{'s390x': 'y'}>
+CONFIG_SCLP_OFB                                 note<'LP:1787898'>
+
+CONFIG_SCSI_IPR_DUMP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_IPR_DUMP                            note<'LP:1343109'>
+
+CONFIG_SCSI_IPR_TRACE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_IPR_TRACE                           note<'LP:1343109'>
+
+CONFIG_SCSI_VIRTIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_VIRTIO                              note<'tech preview of new feature'>
+
+CONFIG_SECURITY_SAFESETID                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SAFESETID                       note<'LP:#1845391'>
+
+CONFIG_SECURITY_SELINUX_DISABLE                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_SELINUX_DISABLE                 note<'LP#1680315'>
+
+CONFIG_SERIAL_DEV_BUS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SERIAL_DEV_BUS                           note<'LP:1739939'>
+
+CONFIG_SERIAL_DEV_CTRL_TTYPORT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SERIAL_DEV_CTRL_TTYPORT                  note<'LP:1739939'>
+
+CONFIG_SERIAL_SH_SCI                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_SH_SCI                            note<'LP: #2022361'>
+
+CONFIG_SERIAL_SH_SCI_CONSOLE                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_SH_SCI_CONSOLE                    note<'LP: #2022361'>
+
+CONFIG_SERIAL_SH_SCI_EARLYCON                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_SH_SCI_EARLYCON                   note<'LP: #2022361'>
+
+CONFIG_SETEND_EMULATION                         policy<{'arm64': 'y'}>
+CONFIG_SETEND_EMULATION                         note<'LP:1545542'>
+
+CONFIG_SMC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SMC                                      note<'LP:1789934'>
+
+CONFIG_SMC_DIAG                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SMC_DIAG                                 note<'LP:1789934'>
+
+CONFIG_SND                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND                                      note<'not autoloadable on omap'>
+
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT               policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1'}>
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT               note<'LP:1804265'>
+
+CONFIG_SND_HDA_RECONFIG                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_RECONFIG                         note<'allows fixes to be tested live'>
+
+CONFIG_SND_PCM_OSS                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_PCM_OSS                              note<'deprecated in favour of pulseaudio emulation'>
+
+CONFIG_SND_SOC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC                                  note<'not autoloadable on omap'>
+
+CONFIG_SND_SOC_AMD_RENOIR                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_AMD_RENOIR                       note<'LP:1881046'>
+
+CONFIG_SND_SOC_AMD_RENOIR_MACH                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_AMD_RENOIR_MACH                  note<'LP:1881046'>
+
+CONFIG_SND_SOC_INTEL_CFL                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_CFL                        note<'deprecated'>
+
+CONFIG_SND_SOC_INTEL_CML_H                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_CML_H                      note<'deprecated'>
+
+CONFIG_SND_SOC_INTEL_CML_LP                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_CML_LP                     note<'deprecated'>
+
+CONFIG_SND_SOC_INTEL_CNL                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_CNL                        note<'deprecated'>
+
+CONFIG_SND_SOC_INTEL_SKYLAKE                    policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_SKYLAKE                    note<'deprecated'>
+
+CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC      note<'deprecated'>
+
+CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC              note<'LP:1848490'>
+
+CONFIG_SND_SOC_SOF_HDA_COMMON_HDMI_CODEC        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_HDA_COMMON_HDMI_CODEC        note<'LP:#1855666'>
+
+CONFIG_SND_SOC_SOF_HDA_LINK                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_HDA_LINK                     note<'LP:1848490'>
+
+CONFIG_SND_SOC_SOF_NOCODEC_SUPPORT              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_SOC_SOF_NOCODEC_SUPPORT              note<'LP:1848490'>
+
+CONFIG_SOUND                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SOUND                                    note<'not autoloadable on omap'>
+
+CONFIG_SOUNDWIRE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SOUNDWIRE                                note<'LP:1855685'>
+
+CONFIG_SOUND_OSS_CORE_PRECLAIM                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SOUND_OSS_CORE_PRECLAIM                  note<'LP#1105230 LP#1385510'>
+
+CONFIG_SPI_INTEL_SPI_PCI                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SPI_INTEL_SPI_PCI                        note<'LP:1734147'>
+
+CONFIG_SPI_INTEL_SPI_PLATFORM                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SPI_INTEL_SPI_PLATFORM                   note<'LP:1734147'>
+
+CONFIG_SQUASHFS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS                                 note<'LP#1593134'>
+
+CONFIG_SQUASHFS_4K_DEVBLK_SIZE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_4K_DEVBLK_SIZE                  note<'non-default block size'>
+
+CONFIG_STACK_VALIDATION                         policy<{'amd64': 'y'}>
+CONFIG_STACK_VALIDATION                         note<'needed for livepatch'>
+
+CONFIG_SWP_EMULATION                            policy<{'arm64': 'y'}>
+CONFIG_SWP_EMULATION                            note<'LP:1545542'>
+
+CONFIG_SYSFS_DEPRECATED                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SYSFS_DEPRECATED                         note<'ensure nothing is using these deprecated interfaces'>
+
+CONFIG_TCG_TIS_I2C_ATMEL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TCG_TIS_I2C_ATMEL                        note<'LP:1643652'>
+
+CONFIG_TCG_TIS_I2C_INFINEON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TCG_TIS_I2C_INFINEON                     note<'LP:1643652'>
+
+CONFIG_TCG_TIS_I2C_NUVOTON                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TCG_TIS_I2C_NUVOTON                      note<'LP:1643652'>
+
+CONFIG_TCG_TPM                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCG_TPM                                  note<'needed for early validation'>
+
+CONFIG_TEST_BLACKHOLE_DEV                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_BLACKHOLE_DEV                       note<'Used by net selftests'>
+
+CONFIG_TMPFS_POSIX_ACL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMPFS_POSIX_ACL                          note<'some /dev nodes require POSIX ACLs, like /dev/dsp'>
+
+CONFIG_TOUCHSCREEN_ELAN                         policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ELAN                         note<'LP #1630238'>
+
+CONFIG_UNWINDER_FRAME_POINTER                   policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_UNWINDER_FRAME_POINTER                   note<'needed for livepatch'>
+
+CONFIG_USB_EHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_HCD                             note<'ensures USB 2.0/1.1 probe ordering'>
+
+CONFIG_USB_EHCI_HCD_PLATFORM                    policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'n', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_USB_EHCI_HCD_PLATFORM                    note<'Dont use the generic ehci/ohci code on omap, it doesnt work'>
+
+CONFIG_USB_HCD_BCMA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'n', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HCD_BCMA                             note<'USB_{O,E}HCI_HCD_PLATFORM must be off on omap'>
+
+CONFIG_USB_HCD_SSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'n', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HCD_SSB                              note<'USB_{O,E}HCI_HCD_PLATFORM must be off on omap'>
+
+CONFIG_USB_M66592                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_M66592                               note<'gadget device'>
+
+CONFIG_USB_MUSB_HDRC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MUSB_HDRC                            note<'not autoloadable on omap'>
+
+CONFIG_USB_OHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_OHCI_HCD                             note<'ensures USB 2.0/1.1 probe ordering'>
+
+CONFIG_USB_OTG                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG                                  note<'triggers breakage on x86 LP:1047527, LP:1411295'>
+
+CONFIG_USB_OTG_BLACKLIST_HUB                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG_BLACKLIST_HUB                    note<'OTG white/blacklists are disabled'>
+
+CONFIG_USB_OTG_WHITELIST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_OTG_WHITELIST                        note<'OTG white/blacklists are disabled'>
+
+CONFIG_USB_SERIAL_DEBUG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_DEBUG                         note<'not actually debug'>
+
+CONFIG_USB_UHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_UHCI_HCD                             note<'ensures USB 2.0/1.1 probe ordering'>
+
+CONFIG_USB_XHCI_DBGCAP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_XHCI_DBGCAP                          note<'LP:1730832'>
+
+CONFIG_USB_XHCI_HCD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_XHCI_HCD                             note<'ensures USB 2.0/1.1 probe ordering'>
+
+CONFIG_VBOXGUEST                                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_VBOXGUEST                                note<'LP:1796647'>
+
+CONFIG_VFAT_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VFAT_FS                                  note<'needed on arm to ensure we can write the kernel when replacing'>
+
+CONFIG_VFIO                                     policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_VFIO                                     note<'LP#1636733'>
+
+CONFIG_VFIO_PCI                                 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_VFIO_PCI                                 note<'LP#1636733'>
+
+CONFIG_VIDEO_VIMC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIMC                               note<'LP#1831482'>
+
+CONFIG_VIRTIO_BLK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_BLK                               note<'KVM paravirt support -- not autoloadable'>
+
+CONFIG_VIRTIO_MMIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VIRTIO_MMIO                              note<'LP:1557689'>
+
+CONFIG_VIRTIO_NET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_NET                               note<'KVM paravirt support -- not autoloadable'>
+
+CONFIG_X509_CERTIFICATE_PARSER                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_X509_CERTIFICATE_PARSER                  note<'module signing'>
+
+CONFIG_X86_ACPI_CPUFREQ                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_ACPI_CPUFREQ                         note<'not autoloadable'>
+
+CONFIG_X86_CPUFREQ_NFORCE2                      policy<{'i386': 'y'}>
+CONFIG_X86_CPUFREQ_NFORCE2                      note<'not autoloadable'>
+
+CONFIG_X86_LEGACY_VM86                          policy<{'i386': 'y'}>
+CONFIG_X86_LEGACY_VM86                          note<'LP:1499089'>
+
+CONFIG_X86_PCC_CPUFREQ                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PCC_CPUFREQ                          note<'not autoloadable'>
+
+CONFIG_X86_POWERNOW_K8                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_POWERNOW_K8                          note<'not autoloadable'>
+
+CONFIG_X86_SPEEDSTEP_CENTRINO                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_CENTRINO                   note<'not autoloadable'>
+
+CONFIG_X86_SPEEDSTEP_ICH                        policy<{'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_ICH                        note<'not autoloadable'>
+
+CONFIG_X86_SPEEDSTEP_SMI                        policy<{'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_SMI                        note<'not autoloadable'>
+
+CONFIG_X86_UV                                   policy<{'amd64': 'y'}>
+CONFIG_X86_UV                                   note<'LP:1863810'>
+
+CONFIG_XEN_512GB                                policy<{'amd64': 'y'}>
+CONFIG_XEN_512GB                                note<'Q: is this related to the utlemming questions on memory size?'>
+
+CONFIG_XEN_ACPI_PROCESSOR                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_ACPI_PROCESSOR                       note<'boot essential on XEN host'>
+
+CONFIG_XEN_BLKDEV_FRONTEND                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BLKDEV_FRONTEND                      note<'not autoloadable -- XEN paravirt support'>
+
+CONFIG_XEN_NETDEV_FRONTEND                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_NETDEV_FRONTEND                      note<'not autoloadable -- XEN paravirt support'>
+
+CONFIG_XZ_DEC                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XZ_DEC                                   note<'boot essential -- initramfs decompressor'>
+
+CONFIG_ZCRYPT_MULTIDEVNODES                     policy<{'s390x': 'y'}>
+CONFIG_ZCRYPT_MULTIDEVNODES                     note<'LP:1805429'>
+
+CONFIG_ZLIB_DFLTCC                              policy<{'s390x': 'y'}>
+CONFIG_ZLIB_DFLTCC                              note<'LP:1830208'>
+
+CONFIG_ZONE_DMA                                 policy<{'amd64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ZONE_DMA                                 note<'LP:1628523'>
+
+
+# ---- Annotations without notes ----
+
+CONFIG_104_QUAD_8                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_3C515                                    policy<{'i386': 'm'}>
+CONFIG_60XX_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_64BIT                                    policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_64BIT_TIME                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_6LOWPAN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_6LOWPAN_DEBUGFS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_ICMPV6                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_GHC_UDP                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_6LOWPAN_NHC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_DEST                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_FRAGMENT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_HOP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_IPV6                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_MOBILITY                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_ROUTING                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6LOWPAN_NHC_UDP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_6PACK                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_8139CP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_8139TOO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_8139TOO_8129                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_8139TOO_PIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_8139TOO_TUNE_TWISTER                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_8139_OLD_RX_RESET                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_842_COMPRESS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_842_DECOMPRESS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_88EU_AP_MODE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_9P_FS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_9P_FSCACHE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_9P_FS_POSIX_ACL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_9P_FS_SECURITY                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AB3100_CORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AB3100_OTP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ABP060MG                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ABX500_CORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AC97_BUS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ACCESSIBILITY                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ACENIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ACENIC_OMIT_TIGON_I                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ACERHDF                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACER_WIRELESS                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACER_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACORN_PARTITION                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ACPI                                     policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_AC                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_ADXL                                policy<{'amd64': 'y'}>
+CONFIG_ACPI_ALS                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_APEI                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_EINJ                           policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_APEI_ERST_DEBUG                     policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_APEI_GHES                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_MEMORY_FAILURE                 policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ACPI_APEI_PCIEAER                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_APEI_SEA                            policy<{'arm64': 'y'}>
+CONFIG_ACPI_BATTERY                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_BGRT                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_BUTTON                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_CCA_REQUIRED                        policy<{'arm64': 'y'}>
+CONFIG_ACPI_CMPC                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_CONFIGFS                            policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_CONTAINER                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_CPPC_CPUFREQ                        policy<{'arm64': 'm'}>
+CONFIG_ACPI_CPPC_LIB                            policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ACPI_CPU_FREQ_PSS                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_DEBUG                               policy<{'amd64': 'y', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_DEBUGGER                            policy<{'amd64': 'y', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_DEBUGGER_USER                       policy<{'amd64': 'y'}>
+CONFIG_ACPI_DOCK                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_EC_DEBUGFS                          policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_EXTLOG                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_FAN                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_GENERIC_GSI                         policy<{'arm64': 'y'}>
+CONFIG_ACPI_GTDT                                policy<{'arm64': 'y'}>
+CONFIG_ACPI_HED                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_HMAT                                policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ACPI_HOTPLUG_CPU                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_HOTPLUG_IOAPIC                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_HOTPLUG_MEMORY                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_I2C_OPREGION                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_IORT                                policy<{'arm64': 'y'}>
+CONFIG_ACPI_IPMI                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_LPIT                                policy<{'amd64': 'y'}>
+CONFIG_ACPI_MCFG                                policy<{'arm64': 'y'}>
+CONFIG_ACPI_NFIT                                policy<{'amd64': 'm', 'arm64': 'm'}>
+CONFIG_ACPI_NUMA                                policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ACPI_PCI_SLOT                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_PPTT                                policy<{'arm64': 'y'}>
+CONFIG_ACPI_PROCESSOR                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_PROCESSOR_AGGREGATOR                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_PROCESSOR_CSTATE                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_PROCESSOR_IDLE                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_PROCFS_POWER                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ACPI_REDUCED_HARDWARE_ONLY               policy<{'amd64': 'n', 'arm64': 'y', 'i386': 'n'}>
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_SBS                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_SLEEP                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_SPCR_TABLE                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_TABLE_UPGRADE                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_TAD                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_THERMAL                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_THERMAL_REL                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_TOSHIBA                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_VIDEO                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACPI_WATCHDOG                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ACPI_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACQUIRE_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ACRN_GUEST                               policy<{'amd64': 'y'}>
+CONFIG_AD2S1200                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD2S1210                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD2S90                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5064                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD525X_DPOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AD525X_DPOT_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD525X_DPOT_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5272                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5360                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5380                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5421                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5446                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5449                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5504                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5592R                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5592R_BASE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5593R                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5624R_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5686                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5686_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5696_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5755                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5758                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5761                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5764                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5791                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD5933                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7124                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7150                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7192                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7266                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7280                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7291                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7298                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7303                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7476                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7606                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7606_IFACE_PARALLEL                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7606_IFACE_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7746                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7766                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7768_1                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7780                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7791                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7793                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7816                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7887                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7923                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD7949                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD799X                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD8366                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD8801                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD9523                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD9832                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD9834                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADAPTEC_STARFIRE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADE7854_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADF4350                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADF4371                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ADFS_FS_RW                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ADIN_PHY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ADIS16080                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16130                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16136                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16201                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16203                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16209                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16240                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16260                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16400                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16460                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADIS16480                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADJD_S311                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADM8211                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADT7316                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADT7316_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADT7316_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADVANTECH_WDT                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ADVISE_SYSCALLS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ADXL372                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADXL372_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADXL372_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ADXRS450                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AD_SIGMA_DELTA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AEABI                                    policy<{'armhf': 'y'}>
+CONFIG_AFE4403                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AFE4404                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AFFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AFIUCV                                   policy<{'s390x': 'm'}>
+CONFIG_AFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AFS_DEBUG_CURSOR                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AFS_FSCACHE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AF_KCM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AF_RXRPC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AF_RXRPC_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AF_RXRPC_INJECT_LOSS                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AF_RXRPC_IPV6                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AGP_ALI                                  policy<{'i386': 'm'}>
+CONFIG_AGP_AMD                                  policy<{'i386': 'y'}>
+CONFIG_AGP_AMD64                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AGP_ATI                                  policy<{'i386': 'm'}>
+CONFIG_AGP_EFFICEON                             policy<{'i386': 'm'}>
+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_AHC1EC0_WDT                              policy<{'amd64': 'm'}>
+CONFIG_AHCI_BRCM                                policy<{'arm64': 'm'}>
+CONFIG_AHCI_CEVA                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_AHCI_DM816                               policy<{'armhf': 'm'}>
+CONFIG_AHCI_IMX                                 policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_AHCI_MTK                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_AHCI_MVEBU                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_AHCI_QORIQ                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_AHCI_SUNXI                               policy<{'arm64': 'n'}>
+CONFIG_AHCI_TEGRA                               policy<{'armhf-generic': 'm'}>
+CONFIG_AHCI_XGENE                               policy<{'arm64': 'm'}>
+CONFIG_AIC79XX_CMDS_PER_DEVICE                  policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32'}>
+CONFIG_AIC79XX_DEBUG_ENABLE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_AIC79XX_DEBUG_MASK                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_AIC79XX_REG_PRETTY_PRINT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AIC79XX_RESET_DELAY_MS                   policy<{'amd64': '5000', 'arm64': '5000', 'armhf': '5000', 'i386': '5000', 'ppc64el': '5000'}>
+CONFIG_AIC7XXX_CMDS_PER_DEVICE                  policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_AIC7XXX_DEBUG_ENABLE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_AIC7XXX_DEBUG_MASK                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_AIC7XXX_REG_PRETTY_PRINT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AIC7XXX_RESET_DELAY_MS                   policy<{'amd64': '5000', 'arm64': '5000', 'armhf': '5000', 'i386': '5000', 'ppc64el': '5000'}>
+CONFIG_AIC94XX_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_AIO                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AIRO                                     policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AIRO_CS                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_AIX_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AK09911                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AK8974                                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_AK8975                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AL3320A                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ALIENWARE_WMI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ALIGNMENT_TRAP                           policy<{'armhf': 'y'}>
+CONFIG_ALIM1535_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ALIM7101_WDT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ALIX                                     policy<{'i386': 'y'}>
+CONFIG_ALLOW_DEV_COREDUMP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ALPINE_MSI                               policy<{'armhf': 'y'}>
+CONFIG_ALTERA_FREEZE_BRIDGE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ALTERA_MBOX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ALTERA_MSGDMA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ALTERA_PR_IP_CORE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ALTERA_PR_IP_CORE_PLAT                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_ALTERA_STAPL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ALTERA_TSE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ALTIVEC                                  policy<{'ppc64el': 'y'}>
+CONFIG_ALX                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AL_FIC                                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_AM2315                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AM335X_CONTROL_USB                       policy<{'armhf': 'm'}>
+CONFIG_AM335X_PHY_USB                           policy<{'armhf': 'm'}>
+CONFIG_AMBA_PL08X                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_AMD8111_ETH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AMD_IOMMU                                policy<{'amd64': 'y'}>
+CONFIG_AMD_IOMMU_V2                             policy<{'amd64': 'm'}>
+CONFIG_AMD_MEM_ENCRYPT                          policy<{'amd64': 'y'}>
+CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT        policy<{'amd64': 'n'}>
+CONFIG_AMD_NB                                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AMD_NUMA                                 policy<{'amd64': 'y'}>
+CONFIG_AMD_PHY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AMD_XGBE                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_AMD_XGBE_DCB                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_AMD_XGBE_HAVE_ECC                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_AMIGA_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AMILO_RFKILL                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ANDROID                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ANDROID_BINDERFS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ANDROID_BINDER_DEVICES                   policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""'}>
+CONFIG_ANDROID_BINDER_IPC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ANDROID_BINDER_IPC_SELFTEST              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ANDROID_VSOC                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_APB_TIMER                                policy<{'i386': 'y'}>
+CONFIG_APDS9300                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_APDS9802ALS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_APDS9960                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_APM                                      policy<{'i386': 'm'}>
+CONFIG_APM_ALLOW_INTS                           policy<{'i386': 'n'}>
+CONFIG_APM_CPU_IDLE                             policy<{'i386': 'n'}>
+CONFIG_APM_DISPLAY_BLANK                        policy<{'i386': 'n'}>
+CONFIG_APM_DO_ENABLE                            policy<{'i386': 'n'}>
+CONFIG_APM_EMULATION                            policy<{'armhf': 'n'}>
+CONFIG_APM_IGNORE_USER_SUSPEND                  policy<{'i386': 'n'}>
+CONFIG_APPLDATA_BASE                            policy<{'s390x': 'y'}>
+CONFIG_APPLDATA_MEM                             policy<{'s390x': 'm'}>
+CONFIG_APPLDATA_NET_SUM                         policy<{'s390x': 'm'}>
+CONFIG_APPLDATA_OS                              policy<{'s390x': 'm'}>
+CONFIG_APPLE_GMUX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_APPLE_PROPERTIES                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_APPLICOM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_APQ_GCC_8084                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_APQ_MMCC_8084                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_AQTION                                   policy<{'amd64': 'm', 'arm64': 'm'}>
+CONFIG_AQUANTIA_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AR5523                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCH_32BIT_OFF_T                         policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_ARCH_ACTIONS                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_AGILEX                              policy<{'arm64': 'y'}>
+CONFIG_ARCH_ALPINE                              policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_ARCH_ARTPEC                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_ASPEED                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_AT91                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_AXXIA                               policy<{'armhf-generic-lpae': 'y'}>
+CONFIG_ARCH_BCM                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_BCM2835                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_BCM_IPROC                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_BERLIN                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_BINFMT_ELF_STATE                    policy<{'s390x': 'y'}>
+CONFIG_ARCH_BITMAIN                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_BRCMSTB                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_CLOCKSOURCE_DATA                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_ARCH_CLOCKSOURCE_INIT                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_CPUIDLE_HALTPOLL                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_CPU_PROBE_RELEASE                   policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_DEFCONFIG                           policy<{'amd64': '"arch/x86/configs/x86_64_defconfig"', 'i386': '"arch/x86/configs/i386_defconfig"'}>
+CONFIG_ARCH_DIGICOLOR                           policy<{'armhf': 'n'}>
+CONFIG_ARCH_DMA_ADDR_T_64BIT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_DOVE                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_EBSA110                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_EMEV2                               policy<{'armhf': 'y'}>
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE             policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_ENABLE_THP_MIGRATION                policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_EP93XX                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_EXYNOS                              policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_ARCH_EXYNOS3                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_EXYNOS4                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_EXYNOS5                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_FLATMEM_ENABLE                      policy<{'i386': 'y'}>
+CONFIG_ARCH_FOOTBRIDGE                          policy<{'armhf': 'n'}>
+CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_ADD_PAGES                       policy<{'amd64': 'y'}>
+CONFIG_ARCH_HAS_BANDGAP                         policy<{'armhf': 'y'}>
+CONFIG_ARCH_HAS_BINFMT_FLAT                     policy<{'armhf': 'y'}>
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_CPU_FINALIZE_INIT               policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_CPU_RELAX                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_DEBUG_VIRTUAL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN             policy<{'arm64': 'y', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARCH_HAS_DMA_PREP_COHERENT               policy<{'arm64': 'y'}>
+CONFIG_ARCH_HAS_ELF_RANDOMIZE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_FAST_MULTIPLIER                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_FILTER_PGPROT                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED           policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_FORTIFY_SOURCE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_GIGANTIC_PAGE                   policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_HUGEPD                          policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_KCOV                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_KEEPINITRD                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HAS_KEXEC_PURGATORY                 policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_MEMBARRIER_CALLBACKS            policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_MEM_ENCRYPT                     policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_MMIOWB                          policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_PHYS_TO_DMA                     policy<{'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_PKEYS                           policy<{'amd64': 'y'}>
+CONFIG_ARCH_HAS_PMEM_API                        policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_PTE_DEVMAP                      policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_PTE_SPECIAL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_RELR                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_HAS_RESET_CONTROLLER                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HAS_SCALED_CPUTIME                  policy<{'s390x': 'y'}>
+CONFIG_ARCH_HAS_SETUP_DMA_OPS                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HAS_SET_DIRECT_MAP                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_SET_MEMORY                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_STRICT_KERNEL_RWX               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_STRICT_MODULE_RWX               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU                policy<{'arm64': 'y', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE             policy<{'arm64': 'y', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARCH_HAS_SYSCALL_WRAPPER                 policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HAS_TICK_BROADCAST                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE              policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_UACCESS_MCSAFE                  policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H                  policy<{'armhf': 'y'}>
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HI3xxx                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_HIBERNATION_HEADER                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_HIBERNATION_POSSIBLE                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_HIGHBANK                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_HIP01                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_HIP04                               policy<{'armhf': 'y'}>
+CONFIG_ARCH_HISI                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_HIX5HD2                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_INLINE_READ_LOCK                    policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_LOCK_BH                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_LOCK_IRQ                policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE            policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_TRYLOCK                 policy<{'s390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK                  policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_BH               policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ              policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE       policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK                    policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_BH                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ                policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE            policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH              policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK                  policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH               policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ              policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE       policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK                   policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_BH                policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ               policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE           policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_TRYLOCK                policy<{'s390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH              policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ             policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE      policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_ARCH_IOP32X                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_IXP4XX                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_K3                                  policy<{'arm64': 'y'}>
+CONFIG_ARCH_K3_AM6_SOC                          policy<{'arm64': 'y'}>
+CONFIG_ARCH_K3_J721E_SOC                        policy<{'arm64': 'y'}>
+CONFIG_ARCH_KEEP_MEMBLOCK                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_KEYSTONE                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_LAYERSCAPE                          policy<{'arm64': 'y'}>
+CONFIG_ARCH_LG1K                                policy<{'arm64': 'y'}>
+CONFIG_ARCH_MAY_HAVE_PC_FDC                     policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_MDM9615                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MEDIATEK                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_MEMORY_PROBE                        policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_MESON                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT               policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO                 policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_MILBEAUT                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_MILBEAUT_M10V                       policy<{'armhf': 'y'}>
+CONFIG_ARCH_MMAP_RND_BITS                       policy<{'amd64': '28', 'arm64': '18', 'armhf': '8', 'i386': '8', 'ppc64el': '28'}>
+CONFIG_ARCH_MMAP_RND_BITS_MAX                   policy<{'amd64': '32', 'arm64': '33', 'armhf': '16', 'i386': '16', 'ppc64el': '29'}>
+CONFIG_ARCH_MMAP_RND_BITS_MIN                   policy<{'amd64': '28', 'arm64': '18', 'armhf': '8', 'i386': '8', 'ppc64el': '14'}>
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS                policy<{'amd64': '8', 'arm64': '11', 'ppc64el': '8'}>
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX            policy<{'amd64': '16', 'arm64': '16', 'i386': '16', 'ppc64el': '13'}>
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN            policy<{'amd64': '8', 'arm64': '11', 'i386': '8', 'ppc64el': '7'}>
+CONFIG_ARCH_MMP                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_MSM8960                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MSM8974                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MSM8X60                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_MULTIPLATFORM                       policy<{'armhf': 'y'}>
+CONFIG_ARCH_MULTI_V6                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_MULTI_V6_V7                         policy<{'armhf': 'y'}>
+CONFIG_ARCH_MULTI_V7                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_MVEBU                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_MXC                                 policy<{'arm64': 'y', 'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED              policy<{'armhf': 'y'}>
+CONFIG_ARCH_NPCM                                policy<{'armhf': 'y'}>
+CONFIG_ARCH_NPCM7XX                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_NR_GPIO                             policy<{'armhf': '1024'}>
+CONFIG_ARCH_OMAP                                policy<{'armhf': 'y'}>
+CONFIG_ARCH_OMAP1                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_OMAP2PLUS                           policy<{'armhf': 'y'}>
+CONFIG_ARCH_OMAP2PLUS_TYPICAL                   policy<{'armhf': 'y'}>
+CONFIG_ARCH_OMAP3                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_OMAP4                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX                 policy<{'armhf': 'y'}>
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT         policy<{'armhf': 'y'}>
+CONFIG_ARCH_PROC_KCORE_TEXT                     policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ARCH_PXA                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_QCOM                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_R7S72100                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_R7S9210                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A73A4                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_R8A7740                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7743                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7744                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7745                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A77470                            policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A774A1                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A774C0                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A7778                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7779                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7790                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7791                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7792                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7793                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7794                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_R8A7795                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A7796                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A77965                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A77970                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A77980                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A77990                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R8A77995                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_R9A06G032                           policy<{'armhf': 'y'}>
+CONFIG_ARCH_RANDOM                              policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_RCAR_GEN1                           policy<{'armhf': 'y'}>
+CONFIG_ARCH_RCAR_GEN2                           policy<{'armhf': 'y'}>
+CONFIG_ARCH_RCAR_GEN3                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_RDA                                 policy<{'armhf': 'y'}>
+CONFIG_ARCH_REALTEK                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_REALVIEW                            policy<{'armhf': 'n'}>
+CONFIG_ARCH_RENESAS                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_RMOBILE                             policy<{'armhf': 'y'}>
+CONFIG_ARCH_RPC                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_RZN1                                policy<{'armhf': 'y'}>
+CONFIG_ARCH_S3C24XX                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_S5PV210                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_SA1100                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_SEATTLE                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_SELECT_MEMORY_MODEL                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_SH73A0                              policy<{'armhf': 'y'}>
+CONFIG_ARCH_SIRF                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_SOCFPGA                             policy<{'armhf': 'n'}>
+CONFIG_ARCH_SPARSEMEM_DEFAULT                   policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SPARSEMEM_ENABLE                    policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SPRD                                policy<{'arm64': 'y'}>
+CONFIG_ARCH_STACKWALK                           policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ARCH_STI                                 policy<{'armhf': 'n'}>
+CONFIG_ARCH_STM32                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_STRATIX10                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_SUNXI                               policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_ARCH_SUPPORTS_ACPI                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN                 policy<{'armhf': 'y'}>
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SUPPORTS_INT128                     policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE             policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING             policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SUPPORTS_UPROBES                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_SUSPEND_NONZERO_CPU                 policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_SUSPEND_POSSIBLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ARCH_SYNQUACER                           policy<{'arm64': 'y'}>
+CONFIG_ARCH_TEGRA                               policy<{'arm64': 'n', 'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARCH_TEGRA_114_SOC                       policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_124_SOC                       policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_2x_SOC                        policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_TEGRA_3x_SOC                        policy<{'armhf-generic': 'y'}>
+CONFIG_ARCH_THUNDER                             policy<{'arm64': 'y'}>
+CONFIG_ARCH_THUNDER2                            policy<{'arm64': 'y'}>
+CONFIG_ARCH_U8500                               policy<{'armhf': 'n'}>
+CONFIG_ARCH_UNIPHIER                            policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_ARCH_USES_HIGH_VMA_FLAGS                 policy<{'amd64': 'y'}>
+CONFIG_ARCH_USES_PG_UNCACHED                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_USE_BUILTIN_BSWAP                   policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_USE_MEMREMAP_PROT                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_USE_QUEUED_RWLOCKS                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_VEXPRESS                            policy<{'arm64': 'y', 'armhf': 'y'}>
+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'}>
+CONFIG_ARCH_VIRT                                policy<{'armhf': 'y'}>
+CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT           policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_ARCH_WANTS_THP_SWAP                      policy<{'amd64': 'y'}>
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION       policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_WANT_FRAME_POINTERS                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARCH_WANT_GENERAL_HUGETLB                policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION              policy<{'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM           policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_WANT_OLD_COMPAT_IPC                 policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ARCH_WEAK_RELEASE_ACQUIRE                policy<{'ppc64el': 'y'}>
+CONFIG_ARCH_WM8850                              policy<{'armhf': 'n'}>
+CONFIG_ARCH_XGENE                               policy<{'arm64': 'y'}>
+CONFIG_ARCH_ZYNQ                                policy<{'armhf': 'n'}>
+CONFIG_ARCH_ZYNQMP                              policy<{'arm64': 'y'}>
+CONFIG_ARCNET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ARCNET_1051                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_1201                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_CAP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM20020                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM20020_CS                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ARCNET_COM20020_ISA                      policy<{'i386': 'm'}>
+CONFIG_ARCNET_COM20020_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM90xx                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_COM90xxIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_RAW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCNET_RIM_I                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ARCX_ANYBUS_CONTROLLER                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_ARC_EMAC_CORE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM                                      policy<{'armhf': 'y'}>
+CONFIG_ARM64                                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_16K_PAGES                          policy<{'arm64': 'n'}>
+CONFIG_ARM64_4K_PAGES                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_64K_PAGES                          policy<{'arm64': 'n'}>
+CONFIG_ARM64_ACPI_PARKING_PROTOCOL              policy<{'arm64': 'y'}>
+CONFIG_ARM64_CNP                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_CONT_SHIFT                         policy<{'arm64': '4'}>
+CONFIG_ARM64_CRYPTO                             policy<{'arm64': 'y'}>
+CONFIG_ARM64_DEBUG_PRIORITY_MASKING             policy<{'arm64': 'n'}>
+CONFIG_ARM64_ERRATUM_1024718                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1165522                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1286807                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1418040                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1463225                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1542419                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_1742098                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_819472                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_824069                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_826319                     policy<{'arm64': 'y'}>
+CONFIG_ARM64_ERRATUM_827319                     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_HW_AFDBM                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_MODULE_PLTS                        policy<{'arm64': 'y'}>
+CONFIG_ARM64_PAGE_SHIFT                         policy<{'arm64': '12'}>
+CONFIG_ARM64_PAN                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_PA_BITS                            policy<{'arm64': '48'}>
+CONFIG_ARM64_PA_BITS_48                         policy<{'arm64': 'y'}>
+CONFIG_ARM64_PMEM                               policy<{'arm64': 'y'}>
+CONFIG_ARM64_PSEUDO_NMI                         policy<{'arm64': 'y'}>
+CONFIG_ARM64_PTDUMP_CORE                        policy<{'arm64': 'y'}>
+CONFIG_ARM64_PTDUMP_DEBUGFS                     policy<{'arm64': 'n'}>
+CONFIG_ARM64_PTR_AUTH                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET              policy<{'arm64': 'n'}>
+CONFIG_ARM64_RAS_EXTN                           policy<{'arm64': 'y'}>
+CONFIG_ARM64_RELOC_TEST                         policy<{'arm64': 'n'}>
+CONFIG_ARM64_SSBD                               policy<{'arm64': 'y'}>
+CONFIG_ARM64_SVE                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_SW_TTBR0_PAN                       policy<{'arm64': 'y'}>
+CONFIG_ARM64_TAGGED_ADDR_ABI                    policy<{'arm64': 'y'}>
+CONFIG_ARM64_UAO                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_VA_BITS                            policy<{'arm64': '48'}>
+CONFIG_ARM64_VA_BITS_39                         policy<{'arm64': 'n'}>
+CONFIG_ARM64_VHE                                policy<{'arm64': 'y'}>
+CONFIG_ARM64_WORKAROUND_CLEAN_CACHE             policy<{'arm64': 'y'}>
+CONFIG_ARM64_WORKAROUND_REPEAT_TLBI             policy<{'arm64': 'y'}>
+CONFIG_ARMADA375_USBCLUSTER_PHY                 policy<{'armhf': 'y'}>
+CONFIG_ARMADA_370_CLK                           policy<{'armhf': 'y'}>
+CONFIG_ARMADA_370_XP_IRQ                        policy<{'armhf': 'y'}>
+CONFIG_ARMADA_370_XP_TIMER                      policy<{'armhf': 'y'}>
+CONFIG_ARMADA_375_CLK                           policy<{'armhf': 'y'}>
+CONFIG_ARMADA_37XX_CLK                          policy<{'arm64': 'y'}>
+CONFIG_ARMADA_37XX_RWTM_MBOX                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARMADA_37XX_WATCHDOG                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARMADA_38X_CLK                           policy<{'armhf': 'y'}>
+CONFIG_ARMADA_39X_CLK                           policy<{'armhf': 'y'}>
+CONFIG_ARMADA_AP806_SYSCON                      policy<{'arm64': 'y'}>
+CONFIG_ARMADA_AP_CPU_CLK                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARMADA_AP_CP_HELPER                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARMADA_CP110_SYSCON                      policy<{'arm64': 'y'}>
+CONFIG_ARMADA_THERMAL                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARMADA_XP_CLK                            policy<{'armhf': 'y'}>
+CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM       policy<{'arm64': 'm'}>
+CONFIG_ARM_AMBA                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_APPENDED_DTB                         policy<{'armhf': 'y'}>
+CONFIG_ARM_ARCH_TIMER                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND            policy<{'arm64': 'y'}>
+CONFIG_ARM_ARMADA_37XX_CPUFREQ                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_ARMADA_8K_CPUFREQ                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_ATAG_DTB_COMPAT                      policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND       policy<{'armhf-generic': 'y'}>
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER policy<{'armhf-generic': 'n'}>
+CONFIG_ARM_BIG_LITTLE_CPUFREQ                   policy<{'armhf': 'm'}>
+CONFIG_ARM_BIG_LITTLE_CPUIDLE                   policy<{'armhf': 'y'}>
+CONFIG_ARM_BRCMSTB_AVS_CPUFREQ                  policy<{'arm64': 'm'}>
+CONFIG_ARM_CCI                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCI400_COMMON                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCI400_PMU                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCI400_PORT_CTRL                     policy<{'armhf': 'y'}>
+CONFIG_ARM_CCI5xx_PMU                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCI_PMU                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CCN                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CHARLCD                              policy<{'armhf': 'y'}>
+CONFIG_ARM_CPUIDLE                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_CPU_SUSPEND                          policy<{'armhf': 'y'}>
+CONFIG_ARM_CPU_TOPOLOGY                         policy<{'armhf': 'y'}>
+CONFIG_ARM_CRYPTO                               policy<{'armhf': 'y'}>
+CONFIG_ARM_DMA_IOMMU_ALIGNMENT                  policy<{'armhf': '8'}>
+CONFIG_ARM_DMA_MEM_BUFFERABLE                   policy<{'armhf': 'y'}>
+CONFIG_ARM_DMA_USE_IOMMU                        policy<{'armhf': 'y'}>
+CONFIG_ARM_DSU_PMU                              policy<{'arm64': 'm'}>
+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_773022                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_775420                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_798181                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_814220                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_818325_852422                 policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_821420                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_825619                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_852421                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_852423                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_857271                        policy<{'armhf': 'y'}>
+CONFIG_ARM_ERRATA_857272                        policy<{'armhf': 'y'}>
+CONFIG_ARM_EXYNOS_BUS_DEVFREQ                   policy<{'armhf': 'y'}>
+CONFIG_ARM_EXYNOS_CPUIDLE                       policy<{'armhf': 'y'}>
+CONFIG_ARM_GIC                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_GIC_MAX_NR                           policy<{'arm64': '1', 'armhf': '1'}>
+CONFIG_ARM_GIC_V2M                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_GIC_V3                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_GIC_V3_ITS                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_GIC_V3_ITS_FSL_MC                    policy<{'arm64': 'y'}>
+CONFIG_ARM_GIC_V3_ITS_PCI                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_GLOBAL_TIMER                         policy<{'armhf': 'y'}>
+CONFIG_ARM_HAS_SG_CHAIN                         policy<{'armhf': 'y'}>
+CONFIG_ARM_HEAVY_MB                             policy<{'armhf': 'y'}>
+CONFIG_ARM_HIGHBANK_CPUFREQ                     policy<{'armhf': 'm'}>
+CONFIG_ARM_IMX6Q_CPUFREQ                        policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_ARM_IMX_CPUFREQ_DT                       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_ARM_KPROBES_TEST                         policy<{'armhf': 'm'}>
+CONFIG_ARM_L1_CACHE_SHIFT                       policy<{'armhf': '7'}>
+CONFIG_ARM_L1_CACHE_SHIFT_6                     policy<{'armhf': 'y'}>
+CONFIG_ARM_L1_CACHE_SHIFT_7                     policy<{'armhf': 'y'}>
+CONFIG_ARM_LPAE                                 policy<{'armhf-generic': 'n', 'armhf-generic-lpae': 'y'}>
+CONFIG_ARM_MEDIATEK_CPUFREQ                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_MHU                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_MODULE_PLTS                          policy<{'armhf': 'n'}>
+CONFIG_ARM_MVEBU_V7_CPUIDLE                     policy<{'armhf': 'y'}>
+CONFIG_ARM_OMAP2PLUS_CPUFREQ                    policy<{'armhf': 'y'}>
+CONFIG_ARM_PATCH_IDIV                           policy<{'armhf': 'y'}>
+CONFIG_ARM_PATCH_PHYS_VIRT                      policy<{'armhf': 'y'}>
+CONFIG_ARM_PL172_MPMC                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_PMU                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_PMU_ACPI                             policy<{'arm64': 'y'}>
+CONFIG_ARM_PSCI                                 policy<{'armhf': 'y'}>
+CONFIG_ARM_PSCI_CHECKER                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_ARM_PSCI_CPUIDLE                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_PSCI_FW                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_PTDUMP_CORE                          policy<{'armhf': 'y'}>
+CONFIG_ARM_PTDUMP_DEBUGFS                       policy<{'armhf': 'n'}>
+CONFIG_ARM_QCOM_CPUFREQ_HW                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_QCOM_CPUFREQ_NVMEM                   policy<{'arm64': 'm'}>
+CONFIG_ARM_RASPBERRYPI_CPUFREQ                  policy<{'arm64': 'm'}>
+CONFIG_ARM_RK3399_DMC_DEVFREQ                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SBSA_WATCHDOG                        policy<{'arm64': 'm'}>
+CONFIG_ARM_SCMI_CPUFREQ                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SCMI_POWER_DOMAIN                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SCMI_PROTOCOL                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_SCPI_CPUFREQ                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SCPI_POWER_DOMAIN                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SCPI_PROTOCOL                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SDE_INTERFACE                        policy<{'arm64': 'y'}>
+CONFIG_ARM_SMMU                                 policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_ARM_SMMU_V3                              policy<{'arm64': 'y'}>
+CONFIG_ARM_SMMU_V3_PMU                          policy<{'arm64': 'm'}>
+CONFIG_ARM_SP805_WATCHDOG                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ARM_SPE_PMU                              policy<{'arm64': 'm'}>
+CONFIG_ARM_TEGRA124_CPUFREQ                     policy<{'armhf-generic': 'y'}>
+CONFIG_ARM_TEGRA186_CPUFREQ                     policy<{'armhf-generic': 'm'}>
+CONFIG_ARM_TEGRA20_CPUFREQ                      policy<{'armhf-generic': 'y'}>
+CONFIG_ARM_TEGRA20_DEVFREQ                      policy<{'armhf-generic': 'm'}>
+CONFIG_ARM_TEGRA_DEVFREQ                        policy<{'armhf-generic': 'm'}>
+CONFIG_ARM_THUMB                                policy<{'armhf': 'y'}>
+CONFIG_ARM_THUMBEE                              policy<{'armhf': 'y'}>
+CONFIG_ARM_TIMER_SP804                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ARM_TI_CPUFREQ                           policy<{'armhf': 'y'}>
+CONFIG_ARM_VEXPRESS_SPC_CPUFREQ                 policy<{'armhf': 'm'}>
+CONFIG_ARM_VIRT_EXT                             policy<{'armhf': 'y'}>
+CONFIG_AS3935                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ASHMEM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ASM_MODVERSIONS                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASN1                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASPEED_ADC                               policy<{'armhf': 'm'}>
+CONFIG_ASPEED_BT_IPMI_BMC                       policy<{'armhf': 'm'}>
+CONFIG_ASPEED_KCS_IPMI_BMC                      policy<{'armhf': 'm'}>
+CONFIG_ASPEED_LPC_CTRL                          policy<{'armhf': 'm'}>
+CONFIG_ASPEED_LPC_SNOOP                         policy<{'armhf': 'm'}>
+CONFIG_ASPEED_P2A_CTRL                          policy<{'armhf': 'm'}>
+CONFIG_ASPEED_WATCHDOG                          policy<{'armhf': 'y'}>
+CONFIG_ASSOCIATIVE_ARRAY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ASUS_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_NB_WMI                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_WIRELESS                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASUS_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ASYNC_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ASYNC_MEMCPY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ASYNC_PQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ASYNC_RAID6_RECOV                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ASYNC_RAID6_TEST                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA              policy<{'arm64': 'y'}>
+CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA             policy<{'arm64': 'y'}>
+CONFIG_ASYNC_TX_DMA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ASYNC_XOR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AT76C50X_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AT803X_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ATA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ATAGS                                    policy<{'armhf': 'y'}>
+CONFIG_ATAGS_PROC                               policy<{'armhf': 'y'}>
+CONFIG_ATALK                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ATARI_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_ATA_ACPI                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_ATA_BMDMA                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATA_GENERIC                              policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_ATA_OVER_ETH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ATA_SFF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATA_VERBOSE_ERROR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH10K_AHB                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_CE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH10K_DEBUGFS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH10K_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH10K_SNOC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ATH10K_SPECTRAL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_TRACING                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH10K_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH5K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH5K_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH5K_PCI                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH5K_TRACER                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH6KL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH6KL_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH6KL_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH6KL_TRACING                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH6KL_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_AHB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_BTCOEX_SUPPORT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_CHANNEL_CONTEXT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_COMMON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_COMMON_DEBUG                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_COMMON_SPECTRAL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_DEBUGFS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_DYNACK                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATH9K_HTC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_HTC_DEBUGFS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_HW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_HWRNG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_PCI                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_PCI_NO_EEPROM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH9K_PCOEM                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_RFKILL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_STATION_STATISTICS                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH9K_WOW                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATH_COMMON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATH_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATL1                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL1C                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL1E                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATL2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATLAS_PH_SENSOR                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ATMEL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_AMBASSADOR                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ATM_AMBASSADOR_DEBUG                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ATM_BR2684                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_BR2684_IPFILTER                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_CLIP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_CLIP_NO_ICMP                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_DRIVERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATM_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_ENI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_ENI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_ENI_TUNE_BURST                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_FIRESTREAM                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ATM_FORE200E                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_FORE200E_DEBUG                       policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_ATM_FORE200E_TX_RETRY                    policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'ppc64el': '16'}>
+CONFIG_ATM_FORE200E_USE_TASKLET                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_HE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_HE_USE_SUNI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATM_HORIZON                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ATM_HORIZON_DEBUG                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ATM_IA                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_IA_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_IDT77252                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_IDT77252_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_IDT77252_RCV_ALL                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_IDT77252_USE_SUNI                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ATM_LANAI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_LANE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_MPOA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_NICSTAR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_NICSTAR_USE_IDT77105                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_NICSTAR_USE_SUNI                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ATM_SOLOS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_TCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ATM_ZATM                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ATM_ZATM_DEBUG                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_ATOMIC64_SELFTEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ATP                                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_AUDIT                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUDITSYSCALL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUDIT_ARCH                               policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC                policy<{'arm64': 'y'}>
+CONFIG_AUDIT_COMPAT_GENERIC                     policy<{'arm64': 'y'}>
+CONFIG_AUDIT_GENERIC                            policy<{'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_AUFS_BDEV_LOOP                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_BRANCH_MAX_1023                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BRANCH_MAX_127                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_BRANCH_MAX_32767                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BRANCH_MAX_511                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BR_FUSE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_BR_HFSPLUS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AUFS_BR_RAMFS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_DIRREN                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_FHSM                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AUFS_HNOTIFY                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_INO_T_64                            policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_AUFS_RDU                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_SBILIST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AUFS_SHWH                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_AUFS_XATTR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_AURORA_NB8800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_AUTOFS4_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_AUTOFS_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_AUTO_ZRELADDR                            policy<{'armhf': 'y'}>
+CONFIG_AUXDISPLAY                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_AX25                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AX25_DAMA_SLAVE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_AX88796                                  policy<{'armhf': 'm'}>
+CONFIG_AX88796B_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_AX88796_93CX6                            policy<{'armhf': 'n'}>
+CONFIG_AXI_DMAC                                 policy<{'arm64': 'm'}>
+CONFIG_AXP20X_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP20X_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP288_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_AXP288_CHARGER                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_AXP288_FUEL_GAUGE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B43                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B43LEGACY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B43LEGACY_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43LEGACY_DMA                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_DMA_MODE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43LEGACY_HWRNG                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_LEDS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_PCICORE_AUTOSELECT             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_PCI_AUTOSELECT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_PIO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43LEGACY_PIO_MODE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_BCMA                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_BCMA_PIO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_BUSES_BCMA                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_BUSES_BCMA_AND_SSB                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_BUSES_SSB                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_HWRNG                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_LEDS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PCICORE_AUTOSELECT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PCI_AUTOSELECT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_G                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_HT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_LP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PHY_N                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_PIO                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B43_SDIO                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_B43_SSB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B44                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B44_PCI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B44_PCICORE_AUTOSELECT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B44_PCI_AUTOSELECT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_B53                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B53_MDIO_DRIVER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B53_MMAP_DRIVER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B53_SERDES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B53_SPI_DRIVER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_B53_SRAB_DRIVER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_88PM860X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_AAT2870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP5520                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP8860                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_ADP8870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_APPLE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_ARCXCNN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_AS3711                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_BD6107                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_CARILLO_RANCH                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_CLASS_DEVICE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_BACKLIGHT_DA903X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_DA9052                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_GENERIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3533                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3630A                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LM3639                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LP855X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LP8788                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_LV5207LP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_MAX8925                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PANDORA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PCF50633                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PM8941_WLED                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_PWM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_RAVE_SP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_SAHARA                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BACKLIGHT_SKY81452                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKLIGHT_TPS65217                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_BACKLIGHT_WM831X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BACKTRACE_SELF_TEST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BALLOON_COMPACTION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BASE_FULL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BASE_SMALL                               policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_BATMAN_ADV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BATMAN_ADV_BATMAN_V                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BATMAN_ADV_BLA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_DAT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BATMAN_ADV_DEBUGFS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BATMAN_ADV_MCAST                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_NC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_SYSFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BATMAN_ADV_TRACING                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BATTERY_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_ACT8945A                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_AXP20X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_BQ27XXX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BATTERY_BQ27XXX_HDQ                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_BQ27XXX_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_CPCAP                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DA9030                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DA9052                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DA9150                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2760                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2780                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2781                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_DS2782                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_GAUGE_LTC2941                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_LEGO_EV3                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_MAX17040                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_MAX17042                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_MAX1721X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_RT5033                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_RX51                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_SBS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BATTERY_TWL4030_MADC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_EPP                               policy<{'armhf': 'm', 'i386': 'm'}>
+CONFIG_BAYCOM_PAR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_SER_FDX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BAYCOM_SER_HDX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BCACHE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCACHE_CLOSURES_DEBUG                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BCACHE_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BCH                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BCM2835_MBOX                             policy<{'arm64': 'y'}>
+CONFIG_BCM2835_POWER                            policy<{'arm64': 'y'}>
+CONFIG_BCM2835_THERMAL                          policy<{'arm64': 'm'}>
+CONFIG_BCM2835_VCHIQ                            policy<{'arm64': 'm'}>
+CONFIG_BCM2835_WDT                              policy<{'arm64': 'm'}>
+CONFIG_BCM7038_L1_IRQ                           policy<{'arm64': 'y'}>
+CONFIG_BCM7038_WDT                              policy<{'arm64': 'm'}>
+CONFIG_BCM7XXX_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCM87XX_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCMA                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BCMA_BLOCKIO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BCMA_DRIVER_GMAC_CMN                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DRIVER_GPIO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_DRIVER_PCI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_HOST_PCI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_HOST_PCI_POSSIBLE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_HOST_SOC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMA_POSSIBLE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BCMA_SFLASH                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BCMGENET                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BCM_FLEXRM_MBOX                          policy<{'arm64': 'm'}>
+CONFIG_BCM_IPROC_ADC                            policy<{'arm64': 'm'}>
+CONFIG_BCM_KONA_USB2_PHY                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BCM_NET_PHYLIB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BCM_NS_THERMAL                           policy<{'arm64': 'm'}>
+CONFIG_BCM_PDC_MBOX                             policy<{'arm64': 'm'}>
+CONFIG_BCM_SBA_RAID                             policy<{'arm64': 'm'}>
+CONFIG_BCM_SR_THERMAL                           policy<{'arm64': 'm'}>
+CONFIG_BCM_VIDEOCORE                            policy<{'arm64': 'm'}>
+CONFIG_BD70528_WATCHDOG                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_BE2ISCSI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BE2NET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BE2NET_BE2                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BE2NET_BE3                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BE2NET_HWMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BE2NET_LANCER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BE2NET_SKYHAWK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BEFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BEFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BERLIN2_ADC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_BFQ_CGROUP_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BFQ_GROUP_IOSCHED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BGMAC                                    policy<{'arm64': 'y'}>
+CONFIG_BGMAC_PLATFORM                           policy<{'arm64': 'y'}>
+CONFIG_BH1750                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BH1780                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BIG_KEYS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BIG_LITTLE                               policy<{'armhf': 'y'}>
+CONFIG_BINARY_PRINTF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BINFMT_ELF                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BINFMT_ELF_FDPIC                         policy<{'armhf': 'y'}>
+CONFIG_BINFMT_FLAT                              policy<{'armhf': 'y'}>
+CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK          policy<{'armhf': 'y'}>
+CONFIG_BINFMT_FLAT_OLD                          policy<{'armhf': 'y'}>
+CONFIG_BINFMT_MISC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BINFMT_SHARED_FLAT                       policy<{'armhf': 'y'}>
+CONFIG_BINFMT_ZFLAT                             policy<{'armhf': 'y'}>
+CONFIG_BITREVERSE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CGROUP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CGROUP_IOCOST                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_CGROUP_IOLATENCY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BLK_CMDLINE_PARSER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEBUG_FS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEBUG_FS_ZONED                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_3W_XXXX_RAID                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_BSG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_BSGLIB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_CRYPTOLOOP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_DM_BUILTIN                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_DRBD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_FD                               policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BLK_DEV_FD_RAWCMD                        policy<{'amd64': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BLK_DEV_INITRD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_INTEGRITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_IO_TRACE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_LOOP                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_LOOP_MIN_COUNT                   policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8', 's390x': '8'}>
+CONFIG_BLK_DEV_MD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_DEV_NBD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_NULL_BLK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_PMEM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BLK_DEV_RAM_COUNT                        policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'ppc64el': '16', 's390x': '16'}>
+CONFIG_BLK_DEV_RBD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BLK_DEV_RSXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_SKD                              policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_BLK_DEV_THROTTLING_LOW                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BLK_DEV_XPRAM                            policy<{'s390x': 'n'}>
+CONFIG_BLK_DEV_ZONED                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_MQ_PCI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_MQ_RDMA                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_MQ_VIRTIO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_PM                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BLK_RQ_ALLOC_TIME                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_SCSI_REQUEST                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_SED_OPAL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_WBT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLK_WBT_MQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLOCK                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BLOCK_COMPAT                             policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BL_SWITCHER                              policy<{'armhf': 'y'}>
+CONFIG_BL_SWITCHER_DUMMY_IF                     policy<{'armhf': 'm'}>
+CONFIG_BMA180                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMA220                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_ACCEL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_ACCEL_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_ACCEL_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_MAGN                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_MAGN_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMC150_MAGN_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BME680                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BME680_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BME680_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMG160                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMG160_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMG160_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMI160                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMI160_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMI160_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMP280                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMP280_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BMP280_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BNA                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BNX2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BNX2X                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BNX2X_SRIOV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BNXT                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BNXT_DCB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BNXT_FLOWER_OFFLOAD                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BNXT_HWMON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BNXT_SRIOV                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BOARD_TPCI200                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BONDING                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC               policy<{'amd64': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE         policy<{'amd64': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_BOOTPARAM_HOTPLUG_CPU0                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE          policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE         policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_BOOTX_TEXT                               policy<{'ppc64el': 'n'}>
+CONFIG_BOOT_PRINTK_DELAY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_BOUNCE                                   policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'n'}>
+CONFIG_BPF                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPFILTER                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPFILTER_UMH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BPF_EVENTS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_JIT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_JIT_ALWAYS_ON                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_KPROBE_OVERRIDE                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BPF_STREAM_PARSER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_SYSCALL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPF_UNPRIV_DEFAULT_OFF                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BPQETHER                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BQL                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BRANCH_PROFILE_NONE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BRCMDBG                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BRCMFMAC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BRCMFMAC_PCIE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_PROTO_BCDC                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_PROTO_MSGBUF                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_SDIO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMFMAC_USB                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRCMSMAC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BRCMSTB_GISB_ARB                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_BRCMSTB_L2_IRQ                           policy<{'arm64': 'y'}>
+CONFIG_BRCMSTB_PM                               policy<{'arm64': 'y'}>
+CONFIG_BRCMSTB_THERMAL                          policy<{'arm64': 'm'}>
+CONFIG_BRCMUTIL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BRCM_TRACING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BRIDGE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_802_3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_AMONG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_ARP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_ARPREPLY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_BROUTE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_DNAT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_IP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_IP6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_LIMIT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_LOG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_MARK                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_MARK_T                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_NFLOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_PKTTYPE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_REDIRECT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_SNAT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_STP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_T_FILTER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_T_NAT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_EBT_VLAN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_IGMP_SNOOPING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BRIDGE_NETFILTER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_NF_EBTABLES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BRIDGE_VLAN_FILTERING                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BROADCOM_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BSD_DISKLABEL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_BSD_PROCESS_ACCT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BSD_PROCESS_ACCT_V3                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BT                                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BTREE                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BTRFS_ASSERT                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_BTRFS_FS_CHECK_INTEGRITY                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BTRFS_FS_REF_VERIFY                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTRFS_FS_RUN_SANITY_TESTS                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BTT                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_6LOWPAN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_ATH3K                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_BCM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_BNEP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_BNEP_MC_FILTER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_BNEP_PROTO_FILTER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_BREDR                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_CMTP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_DEBUGFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIBCM203X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBFUSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBLUECARD                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BT_HCIBPA10X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBT3C                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BT_HCIBTSDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBTUSB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIBTUSB_AUTOSUSPEND                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIBTUSB_BCM                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIBTUSB_MTK                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIBTUSB_RTL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIDTL1                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_BT_HCIRSI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIUART                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIUART_3WIRE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_AG6XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_ATH3K                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_BCM                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_BCSP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_H4                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_INTEL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_LL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_MRVL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_NOKIA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HCIUART_QCA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIUART_RTL                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_BT_HCIUART_SERDEV                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_HCIVHCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_HIDP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_INTEL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_LE                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_LEDS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_MRVL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_MRVL_SDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_MTKSDIO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_MTKUART                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_QCA                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_QCOMSMD                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_BT_RFCOMM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_RFCOMM_TTY                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_BT_RTL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BT_SELFTEST                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_BT_WILINK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_BUG                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BUG_ON_DATA_CORRUPTION                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_BUILDTIME_EXTABLE_SORT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BUILD_BIN2C                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_BUILD_SALT                               policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_C101                                     policy<{'i386': 'm'}>
+CONFIG_C2PORT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_C2PORT_DURAMAR_2150                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CACHEFILES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CACHEFILES_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CACHEFILES_HISTOGRAM                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CACHE_FEROCEON_L2                        policy<{'armhf': 'y'}>
+CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH           policy<{'armhf': 'n'}>
+CONFIG_CACHE_L2X0                               policy<{'armhf': 'y'}>
+CONFIG_CACHE_L2X0_PMU                           policy<{'armhf': 'y'}>
+CONFIG_CACHE_TAUROS2                            policy<{'armhf': 'y'}>
+CONFIG_CACHE_UNIPHIER                           policy<{'armhf': 'y'}>
+CONFIG_CADENCE_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CAIF                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CAIF_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CAIF_HSI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_NETDEV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_SPI_SLAVE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_SPI_SYNC                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CAIF_TTY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_USB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAIF_VIRTIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CALGARY_IOMMU                            policy<{'amd64': 'y'}>
+CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT         policy<{'amd64': 'y'}>
+CONFIG_CAN                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CAN_8DEV_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_BCM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CALC_BITTIMING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_CC770                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CC770_ISA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_CC770_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_C_CAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_C_CAN_PCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_C_CAN_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_DEBUG_DEVICES                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CAN_DEV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_EMS_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_EMS_PCMCIA                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CAN_EMS_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_ESD_USB2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_F81601                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_FLEXCAN                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_GRCAN                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_GS_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_GW                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_HI311X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_IFI_CANFD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_J1939                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_JANZ_ICAN3                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_KVASER_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_KVASER_PCIEFD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_KVASER_USB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_MCBA_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_MCP251X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_MSCAN                                policy<{'ppc64el': 'm'}>
+CONFIG_CAN_M_CAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_M_CAN_PLATFORM                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_M_CAN_TCAN4X5X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_PCIEC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CAN_PEAK_PCIEFD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PEAK_PCMCIA                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CAN_PEAK_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_PLX_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_RAW                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_RCAR                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CAN_RCAR_CANFD                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CAN_SJA1000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SJA1000_ISA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SJA1000_PLATFORM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SLCAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SOFTING                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_SOFTING_CS                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CAN_TI_HECC                              policy<{'armhf': 'm'}>
+CONFIG_CAN_TSCAN1                               policy<{'i386': 'm'}>
+CONFIG_CAN_UCAN                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_VCAN                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_VXCAN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAN_XILINXCAN                            policy<{'arm64': 'm'}>
+CONFIG_CAPI_AVM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CAPI_TRACE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CARDBUS                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_CARDMAN_4000                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CARDMAN_4040                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CARL9170                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CARL9170_DEBUGFS                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CARL9170_HWRNG                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CARL9170_LEDS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CARL9170_WPC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CARMINE_DRAM_CUSTOM                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CASSINI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CAVIUM_CPT                               policy<{'arm64': 'm'}>
+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'}>
+CONFIG_CAVIUM_ERRATUM_30115                     policy<{'arm64': 'y'}>
+CONFIG_CAVIUM_PTP                               policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_CAVIUM_TX2_ERRATUM_219                   policy<{'arm64': 'y'}>
+CONFIG_CB710_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CB710_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CB710_DEBUG_ASSUMPTIONS                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CC10001_ADC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CCS811                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CCW                                      policy<{'s390x': 'y'}>
+CONFIG_CCWGROUP                                 policy<{'s390x': 'm'}>
+CONFIG_CCW_CONSOLE                              policy<{'s390x': 'y'}>
+CONFIG_CC_CAN_LINK                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAS_ASM_GOTO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAS_ASM_INLINE                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAS_KASAN_GENERIC                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAS_SANCOV_TRACE_PC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAS_SANE_STACKPROTECTOR               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CC_HAS_STACKPROTECTOR_NONE               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG            policy<{'arm64': 'y'}>
+CONFIG_CC_IS_GCC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CC_OPTIMIZE_FOR_SIZE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CDNS_I3C_MASTER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CDROM                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CDROM_PKTCDVD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CDROM_PKTCDVD_BUFFERS                    policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_CDROM_PKTCDVD_WCACHE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CEC_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CEC_GPIO                                 policy<{'amd64-lowlatency': 'm', 'i386-lowlatency': 'm'}>
+CONFIG_CEC_NOTIFIER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CEC_PIN                                  policy<{'amd64-lowlatency': 'y', 'arm64': 'y', 'i386-lowlatency': 'y'}>
+CONFIG_CEC_PIN_ERROR_INJ                        policy<{'amd64-lowlatency': 'n', 'arm64': 'n', 'i386-lowlatency': 'n'}>
+CONFIG_CEC_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CEPH_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_FSCACHE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CEPH_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CEPH_FS_SECURITY_LABEL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CEPH_LIB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CEPH_LIB_PRETTYDEBUG                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CEPH_LIB_USE_DNS_RESOLVER                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CFAG12864B                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CFAG12864B_RATE                          policy<{'amd64': '20', 'i386': '20'}>
+CONFIG_CFG80211                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CFG80211_CERTIFICATION_ONUS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_CRDA_SUPPORT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_DEFAULT_PS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_DEVELOPER_WARNINGS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CFG80211_REQUIRE_SIGNED_REGDB            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_WEXT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFG80211_WEXT_EXPORT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CFS_BANDWIDTH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUPS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_BPF                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_CPUACCT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CGROUP_DEVICE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_FREEZER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_HUGETLB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_NET_CLASSID                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_NET_PRIO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_PERF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_PIDS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_RDMA                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_SCHED                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CGROUP_WRITEBACK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CHARGER_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_ADP5061                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_AXP20X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BD70528                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ2415X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24190                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24257                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ24735                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_BQ25890                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_CPCAP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CHARGER_CROS_USBPD                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CHARGER_DA9150                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_DETECTOR_MAX14656                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_GPIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_ISP1704                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_LP8727                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_LP8788                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_LT3651                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MANAGER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHARGER_MAX14577                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX77650                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX77693                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8903                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8997                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_MAX8998                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_PCF50633                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_QCOM_SMBB                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CHARGER_RT9455                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_SBS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_SC2731                           policy<{'arm64': 'm'}>
+CONFIG_CHARGER_SMB347                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_TPS65090                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_TPS65217                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CHARGER_TWL4030                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_UCS1002                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARGER_WILCO                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CHARLCD                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHARLCD_BL_FLASH                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHARLCD_BL_OFF                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CHARLCD_BL_ON                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CHECKPOINT_RESTORE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CHECK_SIGNATURE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_IPSEC_INLINE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_LIB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T1                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T1_1G                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_T3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T4VF                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CHELSIO_T4_DCB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHELSIO_T4_FCOE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CHROMEOS_LAPTOP                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CHROMEOS_PSTORE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CHROMEOS_TBMC                            policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CHROME_PLATFORMS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_CHR_DEV_SCH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CHR_DEV_ST                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CHSC_SCH                                 policy<{'s390x': 'm'}>
+CONFIG_CICADA_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CIFS                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CIFS_ALLOW_INSECURE_LEGACY               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_DEBUG2                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_DEBUG_DUMP_KEYS                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_DFS_UPCALL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_FSCACHE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_POSIX                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_SMB_DIRECT                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_STATS2                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CIFS_UPCALL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_WEAK_PW_HASH                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIFS_XATTR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CIO_DAC                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CLANG_VERSION                            policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_CLEANCACHE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CLKBLD_I8253                             policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CLKDEV_LOOKUP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_CLKEVT_I8253                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK      policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_EXYNOS_MCT                        policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_I8253                             policy<{'i386': 'y'}>
+CONFIG_CLKSRC_IMX_GPT                           policy<{'armhf-generic': 'y'}>
+CONFIG_CLKSRC_IMX_TPM                           policy<{'armhf-generic': 'y'}>
+CONFIG_CLKSRC_MMIO                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLKSRC_QCOM                              policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_TI_32K                            policy<{'armhf': 'y'}>
+CONFIG_CLKSRC_VERSATILE                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_ACTIONS                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_BCM2835                              policy<{'arm64': 'y'}>
+CONFIG_CLK_BCM_NS2                              policy<{'arm64': 'y'}>
+CONFIG_CLK_BCM_SR                               policy<{'arm64': 'y'}>
+CONFIG_CLK_EMEV2                                policy<{'armhf': 'y'}>
+CONFIG_CLK_HSDK                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_IMX8MM                               policy<{'arm64': 'y'}>
+CONFIG_CLK_IMX8MN                               policy<{'arm64': 'y'}>
+CONFIG_CLK_IMX8MQ                               policy<{'arm64': 'y'}>
+CONFIG_CLK_IMX8QXP                              policy<{'arm64': 'y'}>
+CONFIG_CLK_OWL_S500                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_OWL_S700                             policy<{'arm64': 'y'}>
+CONFIG_CLK_OWL_S900                             policy<{'arm64': 'y'}>
+CONFIG_CLK_QORIQ                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_R7S9210                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7740                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7743                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7745                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A77470                             policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A774A1                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A774C0                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A7778                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7779                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7790                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7791                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7792                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7794                              policy<{'armhf': 'y'}>
+CONFIG_CLK_R8A7795                              policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A7796                              policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A77965                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A77970                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A77980                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A77990                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R8A77995                             policy<{'arm64': 'y'}>
+CONFIG_CLK_R9A06G032                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_RASPBERRYPI                          policy<{'arm64': 'm'}>
+CONFIG_CLK_RCAR_GEN2                            policy<{'armhf': 'y'}>
+CONFIG_CLK_RCAR_GEN2_CPG                        policy<{'armhf': 'y'}>
+CONFIG_CLK_RCAR_GEN3_CPG                        policy<{'arm64': 'y'}>
+CONFIG_CLK_RCAR_USB2_CLOCK_SEL                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_RENESAS                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_RENESAS_CPG_MSSR                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_RENESAS_CPG_MSTP                     policy<{'armhf': 'y'}>
+CONFIG_CLK_RENESAS_DIV6                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_RENESAS_LEGACY                       policy<{'armhf': 'y'}>
+CONFIG_CLK_RZA1                                 policy<{'armhf': 'y'}>
+CONFIG_CLK_SH73A0                               policy<{'armhf': 'y'}>
+CONFIG_CLK_SP810                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLK_SUNXI                                policy<{'arm64': 'y'}>
+CONFIG_CLK_SUNXI_CLOCKS                         policy<{'arm64': 'y'}>
+CONFIG_CLK_SUNXI_PRCM_SUN6I                     policy<{'arm64': 'y'}>
+CONFIG_CLK_SUNXI_PRCM_SUN8I                     policy<{'arm64': 'y'}>
+CONFIG_CLK_SUNXI_PRCM_SUN9I                     policy<{'arm64': 'y'}>
+CONFIG_CLK_TEGRA_BPMP                           policy<{'armhf-generic': 'y'}>
+CONFIG_CLK_TWL6040                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CLK_UNIPHIER                             policy<{'armhf': 'y'}>
+CONFIG_CLK_VEXPRESS_OSC                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CLOCKSOURCE_WATCHDOG                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CLOCK_THERMAL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_CLONE_BACKWARDS                          policy<{'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CLONE_BACKWARDS2                         policy<{'s390x': 'y'}>
+CONFIG_CLS_U32_MARK                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CLS_U32_PERF                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CLZ_TAB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CM32181                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CM3232                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CM3323                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CM3605                                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CM36651                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CMA                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CMA_ALIGNMENT                            policy<{'arm64': '8', 'armhf': '8'}>
+CONFIG_CMA_AREAS                                policy<{'amd64': '7', 'arm64': '7', 'armhf': '7', 'i386': '7', 'ppc64el': '7', 's390x': '7'}>
+CONFIG_CMA_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CMA_DEBUGFS                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CMA_SIZE_SEL_MAX                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CMA_SIZE_SEL_MBYTES                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CMA_SIZE_SEL_MIN                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CMA_SIZE_SEL_PERCENTAGE                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CMDLINE                                  policy<{'arm64': '"console=ttyAMA0"', 'armhf': '""', 'ppc64el': '""'}>
+CONFIG_CMDLINE_BOOL                             policy<{'amd64': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CMDLINE_FORCE                            policy<{'arm64': 'n'}>
+CONFIG_CMDLINE_PARTITION                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_CMM                                      policy<{'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_CMM_IUCV                                 policy<{'s390x': 'y'}>
+CONFIG_CMT_SPEECH                               policy<{'armhf-generic': 'm'}>
+CONFIG_CNIC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CODA_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CODE_PATCHING_SELFTEST                   policy<{'ppc64el': 'n'}>
+CONFIG_COMEDI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_8254                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_8255                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_8255_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_8255_SA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1032                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1500                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1516                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_1564                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_16XX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_2032                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_2200                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3120                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3501                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_APCI_3XXX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADDI_WATCHDOG                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI6208                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI7X3X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI8164                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI9111                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADL_PCI9118                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADQ12B                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1710                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1720                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1723                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1724                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI1760                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ADV_PCI_DIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AIO_AIO12_8                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AIO_IIRO_16                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_DIO200                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_DIO200_ISA                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_DIO200_PCI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC236                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC236_ISA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC236_PCI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC263_ISA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PC263_PCI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PCI224                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_AMPLC_PCI230                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_BOND                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_C6XDIGIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_DAS16_CS                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_CB_PCIDAS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIDAS64                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIDDA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIMDAS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CB_PCIMDDA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_CONTEC_PCI_DIO                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAC02                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAQBOARD2000                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS08                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS08_CS                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_DAS08_ISA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS08_PCI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS16                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS16M1                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS1800                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS6402                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DAS800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB            policy<{'amd64': '20480', 'arm64': '20480', 'armhf': '20480', 'i386': '20480', 'ppc64el': '20480'}>
+CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB               policy<{'amd64': '2048', 'arm64': '2048', 'armhf': '2048', 'i386': '2048', 'ppc64el': '2048'}>
+CONFIG_COMEDI_DMM32AT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2801                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2811                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2814                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2815                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT2817                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT282X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT3000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DT9812                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_DYNA_PCI10XX                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_FL512                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_GSC_HPDI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ICP_MULTI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_II_PCI20KC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ISADMA                            policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ISA_DRIVERS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_COMEDI_JR3_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_KCOMEDILIB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_KE_COUNTER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ME4000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_ME_DAQ                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MF6X4                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MISC_DRIVERS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_COMEDI_MITE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MPC624                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_MULTIQ3                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_6527                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_65XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_660X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_670X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_ATMIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_ATMIO16D                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_AT_A2150                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_AT_AO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_DAQ_700_CS                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_NI_DAQ_DIO24_CS                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_NI_LABPC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_LABPC_CS                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_NI_LABPC_ISA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_LABPC_ISADMA                   policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_LABPC_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_MIO_CS                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_NI_PCIDIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_PCIMIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_ROUTING                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_TIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_TIOCMD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_NI_USB6501                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PARPORT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCI_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL711                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL724                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL726                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL730                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL812                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL816                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCL818                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCM3724                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMAD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMCIA_DRIVERS                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_PCMDA12                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMMIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_PCMUIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_QUATECH_DAQP_CS                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMEDI_RTD520                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_RTI800                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_RTI802                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_S526                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_S626                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_SSV_DNP                           policy<{'i386': 'm'}>
+CONFIG_COMEDI_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUXFAST                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USBDUXSIGMA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_USB_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMEDI_VMK80XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_COMMON_CLK                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_COMMON_CLK_ASPEED                        policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_AXG                           policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_AXG_AUDIO                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_BD718XX                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_CDCE706                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_CDCE925                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_CS2000_CP                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_FIXED_MMIO                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_G12A                          policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_GXBB                          policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_HI3516CV300                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_HI3519                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_HI3660                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_HI3670                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_HI3798CV200                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_HI6220                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_HI655X                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_IPROC                         policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_LOCHNAGAR                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_MAX77686                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_MAX9485                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_MEDIATEK                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MESON8B                       policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_MESON_AO_CLKC                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MESON_CPU_DYNDIV              policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MESON_DUALDIV                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MESON_EE_CLKC                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MESON_MPLL                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MESON_PHASE                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_MESON_PLL                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MESON_REGMAP                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MESON_SCLK_DIV                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_MESON_VID_PLL_DIV             policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2701                        policy<{'armhf': 'n'}>
+CONFIG_COMMON_CLK_MT2712                        policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_BDPSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_IMGSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_JPGDECSYS              policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_MFGCFG                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_MMSYS                  policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_VDECSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT2712_VENCSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779                        policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_AUDSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_CAMSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_IMGSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_IPESYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_MFGCFG                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_MMSYS                  policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_VDECSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6779_VENCSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6797                        policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6797_IMGSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6797_MMSYS                  policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6797_VDECSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT6797_VENCSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT7622                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7622_AUDSYS                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7622_ETHSYS                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7622_HIFSYS                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7629                        policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7629_ETHSYS                 policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT7629_HIFSYS                 policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT8135                        policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT8173                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT8183                        policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_AUDIOSYS               policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_CAMSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_IMGSYS                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_IPU_ADL                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CONN               policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CORE0              policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_IPU_CORE1              policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_MFGCFG                 policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_MMSYS                  policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_VDECSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8183_VENCSYS                policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_MT8516                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_MT8516_AUDSYS                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_PALMAS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_PWM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_QCOM                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_RK808                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_S2MPS11                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_SAMSUNG                       policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_SCMI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SCPI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI514                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_SI5341                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_SI5351                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_SI544                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_SI570                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_TI_ADPLL                      policy<{'armhf': 'y'}>
+CONFIG_COMMON_CLK_VC5                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_CLK_VERSATILE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_COMMON_CLK_WM831X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_COMMON_CLK_XGENE                         policy<{'arm64': 'y'}>
+CONFIG_COMMON_CLK_XLNX_CLKWZRD                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_COMMON_CLK_ZYNQMP                        policy<{'arm64': 'y'}>
+CONFIG_COMMON_RESET_HI3660                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMMON_RESET_HI6220                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_COMPACTION                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAL_LAPTOP                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COMPAT                                   policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAT_32                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_COMPAT_32BIT_TIME                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAT_BINFMT_ELF                        policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAT_FOR_U64_ALIGNMENT                 policy<{'amd64': 'y'}>
+CONFIG_COMPAT_NETLINK_MESSAGES                  policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_COMPAT_OLD_SIGACTION                     policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COMPAT_VDSO                              policy<{'amd64': 'n', 'i386': 'n', 's390x': 'y'}>
+CONFIG_COMPILE_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CONFIGFS_FS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CONNECTOR                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT                 policy<{'amd64': '7', 'arm64': '7', 'armhf': '7', 'i386': '7', 'ppc64el': '7', 's390x': '7'}>
+CONFIG_CONSOLE_LOGLEVEL_QUIET                   policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'ppc64el': '4', 's390x': '4'}>
+CONFIG_CONSOLE_POLL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CONSOLE_TRANSLATIONS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CONTEXT_SWITCH_TRACER                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CONTIG_ALLOC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_COPS                                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_COPS_DAYNA                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_COPS_TANGENT                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CORDIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_COREDUMP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CORESIGHT                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CORTINA_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_COSA                                     policy<{'i386': 'm'}>
+CONFIG_COUNTER                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CPA_DEBUG                                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_CPCAP_ADC                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CPU5_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CPUFREQ_DT_PLATDEV                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CPUMASK_OFFSTACK                         policy<{'amd64': 'y'}>
+CONFIG_CPUSETS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CPU_32v6K                                policy<{'armhf': 'y'}>
+CONFIG_CPU_32v7                                 policy<{'armhf': 'y'}>
+CONFIG_CPU_ABRT_EV7                             policy<{'armhf': 'y'}>
+CONFIG_CPU_BIG_ENDIAN                           policy<{'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_CPU_BPREDICT_DISABLE                     policy<{'armhf': 'n'}>
+CONFIG_CPU_CACHE_V7                             policy<{'armhf': 'y'}>
+CONFIG_CPU_CACHE_VIPT                           policy<{'armhf': 'y'}>
+CONFIG_CPU_COPY_V6                              policy<{'armhf': 'y'}>
+CONFIG_CPU_CP15                                 policy<{'armhf': 'y'}>
+CONFIG_CPU_CP15_MMU                             policy<{'armhf': 'y'}>
+CONFIG_CPU_FREQ                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_CPU_FREQ_GOV_ATTR_SET                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_COMMON                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_HAS_ASID                             policy<{'armhf': 'y'}>
+CONFIG_CPU_HOTPLUG_STATE_CONTROL                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CPU_ICACHE_DISABLE                       policy<{'armhf': 'n'}>
+CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND           policy<{'armhf': 'y'}>
+CONFIG_CPU_IDLE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_HALTPOLL                    policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_LADDER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_MENU                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_GOV_TEO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_IDLE_MULTIPLE_DRIVERS                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CPU_ISOLATION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CPU_LITTLE_ENDIAN                        policy<{'ppc64el': 'y'}>
+CONFIG_CPU_PABRT_V7                             policy<{'armhf': 'y'}>
+CONFIG_CPU_PJ4                                  policy<{'armhf': 'y'}>
+CONFIG_CPU_PJ4B                                 policy<{'armhf': 'y'}>
+CONFIG_CPU_PM                                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CPU_RMAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CPU_SPECTRE                              policy<{'armhf': 'y'}>
+CONFIG_CPU_SUP_AMD                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_CENTAUR                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_CYRIX_32                         policy<{'i386': 'y'}>
+CONFIG_CPU_SUP_HYGON                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_INTEL                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SUP_TRANSMETA_32                     policy<{'i386': 'y'}>
+CONFIG_CPU_SUP_UMC_32                           policy<{'i386': 'y'}>
+CONFIG_CPU_SUP_ZHAOXIN                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CPU_SW_DOMAIN_PAN                        policy<{'armhf-generic': 'y'}>
+CONFIG_CPU_THERMAL                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_CPU_THUMB_CAPABLE                        policy<{'armhf': 'y'}>
+CONFIG_CPU_TLB_V7                               policy<{'armhf': 'y'}>
+CONFIG_CPU_V7                                   policy<{'armhf': 'y'}>
+CONFIG_CRAMFS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CRAMFS_BLOCKDEV                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CRAMFS_MTD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_CRASH_CORE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC16                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC32                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC32_BIT                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_SARWATE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_SELFTEST                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_SLICEBY4                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_CRC32_SLICEBY8                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC4                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC64                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC7                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC8                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC_CCITT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRC_ITU_T                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRC_T10DIF                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CROSS_MEMORY_ATTACH                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CROS_EC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_CHARDEV                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_DEBUGFS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_ISHTP                            policy<{'amd64': 'm'}>
+CONFIG_CROS_EC_LIGHTBAR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_LPC                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_PROTO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_CROS_EC_RPMSG                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CROS_EC_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_SYSFS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CROS_EC_VBC                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CROS_KBD_LED_BACKLIGHT                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CROS_USBPD_LOGGER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_842                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ACOMP2                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ADIANTUM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_AEAD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_AEAD2                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_AEGIS128                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_AEGIS128_AESNI_SSE2               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_AEGIS128_SIMD                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_CRYPTO_AES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_AES_ARM                           policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_ARM64                         policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_BS                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE_BLK                  policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_CE_CCM                  policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK                policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_AES_ARM_BS                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_ARM_CE                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_AES_NI_INTEL                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_AES_S390                          policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_AES_TI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_AKCIPHER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_AKCIPHER2                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ALGAPI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ALGAPI2                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ANSI_CPRNG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ANUBIS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ARC4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_AUTHENC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_BLKCIPHER                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_BLKCIPHER2                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_BLOWFISH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_BLOWFISH_COMMON                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64        policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64         policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAMELLIA_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAST5                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CAST6_AVX_X86_64                  policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CAST_COMMON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CBC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CCM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CFB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CHACHA20                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CHACHA20POLY1305                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CHACHA20_NEON                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_CHACHA20_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CMAC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CRC32                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CRC32C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CRC32C_INTEL                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_CRC32C_VPMSUM                     policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_CRC32_ARM_CE                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_CRC32_PCLMUL                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_CRC32_S390                        policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_CRCT10DIF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CRCT10DIF_ARM64_CE                policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_CRCT10DIF_ARM_CE                  policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_CRCT10DIF_PCLMUL                  policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_CRCT10DIF_VPMSUM                  policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_CRYPTD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_CTR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_CTS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DEFLATE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_CRYPTO_DES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_DES3_EDE_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_DES_S390                          policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_DEV_ARTPEC6                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_ATMEL_ECC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CRYPTO_DEV_ATMEL_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_ATMEL_SHA204A                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CRYPTO_DEV_BCM_SPU                       policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_CAVIUM_ZIP                    policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_CCP                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_DEV_CCP_CRYPTO                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_CCP_DD                        policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_CCP_DEBUGFS                   policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_CRYPTO_DEV_CCREE                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_CHELSIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_CHELSIO_TLS                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_CPT                           policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_EXYNOS_RNG                    policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM                      policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API            policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON               policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API           policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC      policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI        policy<{'arm64': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG                policy<{'arm64': 'n', 'armhf-generic': 'n'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC                 policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD      policy<{'arm64': '255', 'armhf-generic': '255'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD       policy<{'arm64': '2048', 'armhf-generic': '2048'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_JR                   policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API              policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE             policy<{'arm64': '9', 'armhf-generic': '9'}>
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API              policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM                policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_GEODE                         policy<{'i386': 'm'}>
+CONFIG_CRYPTO_DEV_HIFN_795X                     policy<{'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG                 policy<{'armhf-generic': 'y'}>
+CONFIG_CRYPTO_DEV_HISI_HPRE                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_HISI_QM                       policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_HISI_SEC                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_HISI_SEC2                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_HISI_ZIP                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_DEV_MARVELL_CESA                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_MEDIATEK                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_MXS_DCP                       policy<{'arm64': 'n', 'armhf-generic': 'n'}>
+CONFIG_CRYPTO_DEV_NITROX                        policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_NITROX_CNN55XX                policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CRYPTO_DEV_NX                            policy<{'ppc64el': 'y'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS                   policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV           policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES           policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP                          policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP_AES                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP_DES                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_OMAP_SHAM                     policy<{'armhf': 'm'}>
+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_QAT                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_C3XXX                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_C3XXXVF                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_C62X                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_DEV_QAT_C62XVF                    policy<{'amd64': 'm', 'i386': '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_QCOM_RNG                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_ROCKCHIP                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_S5P                           policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_DEV_SAFEXCEL                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_CRYPTO_DEV_SAHARA                        policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_CRYPTO_DEV_SP_CCP                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_CRYPTO_DEV_SP_PSP                        policy<{'amd64': 'y'}>
+CONFIG_CRYPTO_DEV_VIRTIO                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_DEV_VMX                           policy<{'ppc64el': 'y'}>
+CONFIG_CRYPTO_DEV_VMX_ENCRYPT                   policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_DH                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG_CTR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG_HASH                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG_HMAC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_DRBG_MENU                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ECB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_ECC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ECDH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ECHAINIV                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ECRDSA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ENGINE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ESSIV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_FCRYPT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_GCM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_GF128MUL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_GHASH                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_GHASH_ARM64_CE                    policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_GHASH_ARM_CE                      policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL              policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_GHASH_S390                        policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_GLUE_HELPER_X86                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_HASH                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_HASH2                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_HASH_INFO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_HMAC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_HW                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_JITTERENTROPY                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_KEYWRAP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_KHAZAD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_KPP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_KPP2                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_LIB_AES                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_LIB_ARC4                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LIB_DES                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LIB_SHA256                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_LRW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZ4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZ4HC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_LZO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MANAGER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MANAGER2                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MD4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_MD5                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_MD5_PPC                           policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_MICHAEL_MIC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_NHPOLY1305                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_NHPOLY1305_AVX2                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_NHPOLY1305_NEON                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_CRYPTO_NHPOLY1305_SSE2                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_NULL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_NULL2                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_OFB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_PAES_S390                         policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_PCBC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_PCRYPT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_POLY1305                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_POLY1305_X86_64                   policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_RMD128                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD160                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD256                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RMD320                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_RNG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_RNG2                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_RNG_DEFAULT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_RSA                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SALSA20                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SEED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SEQIV                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SERPENT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SERPENT_AVX2_X86_64               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SERPENT_AVX_X86_64                policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SERPENT_SSE2_586                  policy<{'i386': 'm'}>
+CONFIG_CRYPTO_SERPENT_SSE2_X86_64               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SHA1_ARM                          policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA1_ARM64_CE                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA1_ARM_CE                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA1_ARM_NEON                     policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA1_PPC                          policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_SHA1_S390                         policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA1_SSSE3                        policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA256                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_SHA256_ARM                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA256_ARM64                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA256_S390                       policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA256_SSSE3                      policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SHA2_ARM64_CE                     policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA2_ARM_CE                       policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SHA3_256_S390                     policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA3_512_S390                     policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA3_ARM64                        policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA512_ARM                        policy<{'armhf': 'm'}>
+CONFIG_CRYPTO_SHA512_ARM64                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA512_ARM64_CE                   policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SHA512_S390                       policy<{'s390x': 'm'}>
+CONFIG_CRYPTO_SHA512_SSSE3                      policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_SIMD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CRYPTO_SM3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SM3_ARM64_CE                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_SM4                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_SM4_ARM64_CE                      policy<{'arm64': 'm'}>
+CONFIG_CRYPTO_STATS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_STREEBOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TEA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TGR192                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TWOFISH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TWOFISH_586                       policy<{'i386': 'm'}>
+CONFIG_CRYPTO_TWOFISH_AVX_X86_64                policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_TWOFISH_COMMON                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_TWOFISH_X86_64                    policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_TWOFISH_X86_64_3WAY               policy<{'amd64': 'm'}>
+CONFIG_CRYPTO_USER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_AEAD                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_HASH                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_RNG                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_USER_API_SKCIPHER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_VMAC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_VPMSUM_TESTER                     policy<{'ppc64el': 'm'}>
+CONFIG_CRYPTO_WP512                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_XCBC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_XTS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_CRYPTO_XXHASH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CRYPTO_ZSTD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CS89x0                                   policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_CS89x0_PLATFORM                          policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_CTCM                                     policy<{'s390x': 'm'}>
+CONFIG_CUSE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_CW1200                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CW1200_WLAN_SDIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CW1200_WLAN_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CXD2880_SPI_DRV                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CXL                                      policy<{'ppc64el': 'm'}>
+CONFIG_CXLFLASH                                 policy<{'ppc64el': 'm'}>
+CONFIG_CXL_AFU_DRIVER_OPS                       policy<{'ppc64el': 'y'}>
+CONFIG_CXL_BASE                                 policy<{'ppc64el': 'y'}>
+CONFIG_CXL_LIB                                  policy<{'ppc64el': 'y'}>
+CONFIG_CX_ECAT                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_CYCLADES                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CYPRESS_FIRMWARE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_CYZ_INTR                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DA280                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA311                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9052_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9055_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9062_THERMAL                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9062_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9063_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DA9150_GPADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DASD                                     policy<{'s390x': 'm'}>
+CONFIG_DASD_DIAG                                policy<{'s390x': 'm'}>
+CONFIG_DASD_ECKD                                policy<{'s390x': 'm'}>
+CONFIG_DASD_EER                                 policy<{'s390x': 'y'}>
+CONFIG_DASD_FBA                                 policy<{'s390x': 'm'}>
+CONFIG_DASD_PROFILE                             policy<{'s390x': 'y'}>
+CONFIG_DATA_SHIFT                               policy<{'ppc64el': '16'}>
+CONFIG_DAVICOM_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DAX                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DAX_DRIVER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DCA                                      policy<{'amd64': 'm'}>
+CONFIG_DCACHE_WORD_ACCESS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DCB                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DCDBAS                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DCSSBLK                                  policy<{'s390x': 'm'}>
+CONFIG_DDR                                      policy<{'armhf': 'y'}>
+CONFIG_DE2104X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DE2104X_DSL                              policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_DE4X5                                    policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DEBUGGER                                 policy<{'ppc64el': 'y'}>
+CONFIG_DEBUG_ALIGN_RODATA                       policy<{'arm64': 'n', 'armhf': 'y'}>
+CONFIG_DEBUG_ATOMIC_SLEEP                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_BLOCK_EXT_DEVT                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_BOOT_PARAMS                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_BUGVERBOSE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_CREDENTIALS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_DEVRES                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_DRIVER                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_EFI                                policy<{'arm64': 'n'}>
+CONFIG_DEBUG_ENTRY                              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_GPIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_HIGHMEM                            policy<{'armhf': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_HOTPLUG_CPU0                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_INFO_BTF                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_INFO_DWARF4                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_INFO_REDUCED                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_KERNEL_DC                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DEBUG_KMEMLEAK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_KOBJECT                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_LIST                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_LL                                 policy<{'armhf': 'n'}>
+CONFIG_DEBUG_LL_INCLUDE                         policy<{'armhf': '"mach/debug-macro.S"'}>
+CONFIG_DEBUG_LOCKING_API_SELFTESTS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_LOCK_ALLOC                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_MEMORY_INIT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_MISC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEBUG_MUTEXES                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_NMI_SELFTEST                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_NOTIFIERS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_OBJECTS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PAGEALLOC                          policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PAGE_REF                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PERF_USE_VMALLOC                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PER_CPU_MAPS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PINCTRL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DEBUG_PLIST                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_PREEMPT                            policy<{'amd64-lowlatency': 'n', 'i386-lowlatency': 'n'}>
+CONFIG_DEBUG_RODATA_TEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_RSEQ                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_RT_MUTEXES                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_RWSEMS                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SECTION_MISMATCH                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SHIRQ                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_SPINLOCK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_STACKOVERFLOW                      policy<{'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DEBUG_STACK_USAGE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_TEST_DRIVER_REMOVE                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_TIMEKEEPING                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_TLBFLUSH                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DEBUG_USER                               policy<{'armhf': 'n'}>
+CONFIG_DEBUG_VF_UART_PORT                       policy<{'armhf-generic': '1'}>
+CONFIG_DEBUG_VIRTUAL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DEBUG_VM                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_WQ_FORCE_RR_CPU                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_WW_MUTEX_SLOWPATH                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEBUG_WX                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DECOMPRESS_BZIP2                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECOMPRESS_GZIP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECOMPRESS_LZ4                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECOMPRESS_LZMA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECOMPRESS_LZO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DECOMPRESS_XZ                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_CUBIC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_HOSTNAME                         policy<{'amd64': '"(none)"', 'arm64': '"(none)"', 'armhf': '"(none)"', 'i386': '"(none)"', 'ppc64el': '"(none)"', 's390x': '"(none)"'}>
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT                policy<{'amd64': '120', 'arm64': '120', 'armhf': '120', 'i386': '120', 'ppc64el': '120', 's390x': '120'}>
+CONFIG_DEFAULT_RENO                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_APPARMOR                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEFAULT_SECURITY_DAC                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_SELINUX                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_SMACK                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_SECURITY_TOMOYO                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFAULT_TCP_CONG                         policy<{'amd64': '"cubic"', 'arm64': '"cubic"', 'armhf': '"cubic"', 'i386': '"cubic"', 'ppc64el': '"cubic"', 's390x': '"cubic"'}>
+CONFIG_DEFERRED_STRUCT_PAGE_INIT                policy<{'amd64': 'n', 'arm64': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DEFXX                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DEFXX_MMIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DELL_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_RBTN                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_RBU                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_SMBIOS                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_SMBIOS_SMM                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DELL_SMBIOS_WMI                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DELL_SMO8800                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_UART_BACKLIGHT                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI_AIO                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI_DESCRIPTOR                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DELL_WMI_LED                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DEPRECATED_PARAM_STRUCT                  policy<{'armhf': 'n'}>
+CONFIG_DETECT_HUNG_TASK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP                policy<{'armhf': 'y'}>
+CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU                policy<{'armhf': 'y'}>
+CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DEVFREQ_GOV_PASSIVE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_PERFORMANCE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_POWERSAVE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_GOV_USERSPACE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVFREQ_THERMAL                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVICE_PRIVATE                           policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_DEVMEM                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEVPORT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DEV_APPLETALK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DEV_COREDUMP                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DEV_DAX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DEV_DAX_KMEM                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DEV_DAX_PMEM                             policy<{'amd64': 'm', 'ppc64el': 'm'}>
+CONFIG_DEV_DAX_PMEM_COMPAT                      policy<{'amd64': 'm', 'ppc64el': 'm'}>
+CONFIG_DEV_PAGEMAP_OPS                          policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_DHT11                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DIAG288_WATCHDOG                         policy<{'s390x': 'm'}>
+CONFIG_DIMLIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DL2K                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DLCI                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DLCI_MAX                                 policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_DLM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DLM_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DLN2_ADC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DM9000                                   policy<{'armhf': 'm'}>
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL             policy<{'armhf': 'n'}>
+CONFIG_DM9102                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DMABUF_SELFTESTS                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DMADEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DMADEVICES_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DMARD06                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DMARD09                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DMARD10                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DMAR_TABLE                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DMATEST                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DMA_ACPI                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_DMA_API_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DMA_BCM2835                              policy<{'arm64': 'y'}>
+CONFIG_DMA_DECLARE_COHERENT                     policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DMA_DIRECT_REMAP                         policy<{'arm64': 'y'}>
+CONFIG_DMA_ENGINE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DMA_ENGINE_RAID                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DMA_FENCE_TRACE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DMA_OF                                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DMA_OMAP                                 policy<{'armhf': 'y'}>
+CONFIG_DMA_REMAP                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DMA_SHARED_BUFFER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DMA_SUN6I                                policy<{'arm64': 'm'}>
+CONFIG_DMA_VIRTUAL_CHANNELS                     policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DMA_VIRT_OPS                             policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DMI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DMIID                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DMI_SYSFS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_DM_BIO_PRISON                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_BUFIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CACHE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CACHE_SMQ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CLONE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_CRYPT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_DEBUG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DM_DELAY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_DUST                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DM_ERA                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_FLAKEY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_INIT                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DM_INTEGRITY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_LOG_USERSPACE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_LOG_WRITES                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MIRROR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH_QL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_MULTIPATH_ST                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_PERSISTENT_DATA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_RAID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_SNAPSHOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_SWITCH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_THIN_PROVISIONING                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_UEVENT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DM_UNSTRIPED                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_VERITY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_VERITY_FEC                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DM_WRITECACHE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_ZERO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DM_ZONED                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DNET                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DNOTIFY                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DNS_RESOLVER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DOUBLEFAULT                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DOVE_CLK                                 policy<{'armhf': 'y'}>
+CONFIG_DOVE_THERMAL                             policy<{'armhf': 'm'}>
+CONFIG_DP83640_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83822_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83848_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83867_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DP83TC811_PHY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DPAA2_CONSOLE                            policy<{'arm64': 'm'}>
+CONFIG_DPAA_ERRATUM_A050385                     policy<{'arm64': 'y'}>
+CONFIG_DPM_WATCHDOG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DPOT_DAC                                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DPS310                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DPTF_POWER                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DQL                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRA752_THERMAL                           policy<{'armhf': 'y'}>
+CONFIG_DRAGONRISE_FF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRBD_FAULT_INJECTION                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DRM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_AMDGPU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_AMDGPU_GART_DEBUGFS                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_AMDGPU_SI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMDGPU_USERPTR                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMD_ACP                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMD_DC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_AMD_DC_DCN1_0                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_AMD_DC_DCN2_0                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_AMD_DC_DCN2_1                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_AMD_DC_DSC_SUPPORT                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_ANALOGIX_ANX78XX                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_ANALOGIX_DP                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_ARCPGU                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_ARMADA                               policy<{'armhf': 'm'}>
+CONFIG_DRM_ASPEED_GFX                           policy<{'armhf': 'm'}>
+CONFIG_DRM_AST                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_ATMEL_HLCDC                          policy<{'armhf': 'm'}>
+CONFIG_DRM_BRIDGE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_CDNS_DSI                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_CIRRUS_QEMU                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_DEBUG_SELFTEST                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DRM_DP_AUX_CHARDEV                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DRM_DP_CEC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_DRM_DUMB_VGA_DAC                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_DW_HDMI                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_DW_HDMI_AHB_AUDIO                    policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_DW_HDMI_CEC                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_DW_HDMI_I2S_AUDIO                    policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_DW_MIPI_DSI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_ETNAVIV                              policy<{'amd64': 'n', 'arm64': 'm', 'armhf': 'm', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DRM_ETNAVIV_THERMAL                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_EXYNOS                               policy<{'armhf': 'm'}>
+CONFIG_DRM_EXYNOS5433_DECON                     policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS7_DECON                        policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS_DSI                           policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_FIMC                          policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_FIMD                          policy<{'armhf': 'n'}>
+CONFIG_DRM_EXYNOS_HDMI                          policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_IPP                           policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_MIC                           policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_MIXER                         policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_ROTATOR                       policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_SCALER                        policy<{'armhf': 'y'}>
+CONFIG_DRM_EXYNOS_VIDI                          policy<{'armhf': 'n'}>
+CONFIG_DRM_FBDEV_EMULATION                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_DRM_FBDEV_OVERALLOC                      policy<{'amd64': '100', 'arm64': '100', 'armhf': '100', 'i386': '100', 'ppc64el': '100', 's390x': '100'}>
+CONFIG_DRM_FSL_DCU                              policy<{'armhf': 'm'}>
+CONFIG_DRM_GEM_CMA_HELPER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_GEM_SHMEM_HELPER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_GM12U320                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_GMA3600                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_GMA500                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_GMA600                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_HDLCD                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_HDLCD_SHOW_UNDERRUN                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_HISI_KIRIN                           policy<{'arm64': 'm'}>
+CONFIG_DRM_I2C_ADV7511                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_I2C_ADV7511_AUDIO                    policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_I2C_ADV7511_CEC                      policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_I2C_ADV7533                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_I2C_CH7006                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_I2C_NXP_TDA9950                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_I2C_NXP_TDA998X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_I2C_SIL164                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_I915                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_I915_ALPHA_SUPPORT                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_CAPTURE_ERROR                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_I915_COMPRESS_ERROR                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_I915_DEBUG                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_DEBUG_GUC                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_DEBUG_MMIO                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_DEBUG_RUNTIME_PM                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_DEBUG_VBLANK_EVADE              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_FORCE_PROBE                     policy<{'amd64': '""', 'i386': '""'}>
+CONFIG_DRM_I915_GVT                             policy<{'amd64': 'y'}>
+CONFIG_DRM_I915_GVT_KVMGT                       policy<{'amd64': 'm'}>
+CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_SELFTEST                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_SPIN_REQUEST                    policy<{'amd64': '5', 'i386': '5'}>
+CONFIG_DRM_I915_SW_FENCE_CHECK_DAG              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND           policy<{'amd64': '250', 'i386': '250'}>
+CONFIG_DRM_I915_USERPTR                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_I915_WERROR                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_DRM_IMX                                  policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_HDMI                             policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_LDB                              policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_PARALLEL_DISPLAY                 policy<{'armhf': 'm'}>
+CONFIG_DRM_IMX_TVE                              policy<{'armhf': 'm'}>
+CONFIG_DRM_KMS_CMA_HELPER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_KMS_FB_HELPER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_KMS_HELPER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_KOMEDA                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_LIMA                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_LOAD_EDID_FIRMWARE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_LVDS_ENCODER                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_MALI_DISPLAY                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MCDE                                 policy<{'armhf': 'm'}>
+CONFIG_DRM_MEDFIELD                             policy<{'i386': 'y'}>
+CONFIG_DRM_MEDIATEK                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MEDIATEK_HDMI                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_MESON                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MESON_DW_HDMI                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MIPI_DBI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_MIPI_DSI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_MSM                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_MSM_DSI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_10NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_14NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_20NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_28NM_8960_PHY                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_28NM_PHY                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_DSI_PLL                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_GPU_STATE                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_GPU_SUDO                         policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_MSM_HDMI_HDCP                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_MSM_REGISTER_LOGGING                 policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_DRM_MXS                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_DRM_MXSFB                                policy<{'arm64': 'm', 'armhf-generic': 'm', 'armhf-generic-lpae': '-'}>
+CONFIG_DRM_NOUVEAU                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_NOUVEAU_BACKLIGHT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DRM_NOUVEAU_SVM                          policy<{'amd64': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_NXP_PTN3460                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_OMAP                                 policy<{'armhf': 'n'}>
+CONFIG_DRM_PANEL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_PANEL_ARM_VERSATILE                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_BRIDGE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_ILITEK_IL9322                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_ILITEK_ILI9881C                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_INNOLUX_P079ZCA                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_JDI_LT070ME05000               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_LG_LB035Q02                    policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_LG_LG4573                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_LVDS                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_NEC_NL8048HL11                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_NOVATEK_NT39016                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_ORIENTATION_QUIRKS             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_PANEL_ORISETECH_OTM8009A             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_RAYDIUM_RM67191                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_RAYDIUM_RM68200                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_ROCKTECH_JH057N00900           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_RONBO_RB070D30                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_LD9040                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6D16D0                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E63M0                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SEIKO_43WVF1G                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SHARP_LQ101R1SX01              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SHARP_LS037V7DW01              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SHARP_LS043T1LE01              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SIMPLE                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SITRONIX_ST7701                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SITRONIX_ST7789V               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_SONY_ACX565AKM                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_TPO_TD028TTEC1                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_TPO_TD043MTEA1                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_TPO_TPG110                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PANFROST                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_PARADE_PS8622                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_PL111                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_QXL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_RADEON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_RADEON_USERPTR                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DRM_RCAR_DU                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_RCAR_DW_HDMI                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_RCAR_LVDS                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'n'}>
+CONFIG_DRM_RCAR_VSP                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DRM_RCAR_WRITEBACK                       policy<{'arm64': 'y'}>
+CONFIG_DRM_ROCKCHIP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DRM_SCHED                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_SII902X                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_SII9234                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_SIL_SII8620                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_STM                                  policy<{'armhf': 'm'}>
+CONFIG_DRM_STM_DSI                              policy<{'armhf': 'm'}>
+CONFIG_DRM_SUN4I                                policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN4I_BACKEND                        policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN4I_HDMI                           policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN4I_HDMI_CEC                       policy<{'arm64': 'y'}>
+CONFIG_DRM_SUN6I_DSI                            policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN8I_DW_HDMI                        policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN8I_MIXER                          policy<{'arm64': 'm'}>
+CONFIG_DRM_SUN8I_TCON_TOP                       policy<{'arm64': 'm'}>
+CONFIG_DRM_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_DRM_TEGRA_DEBUG                          policy<{'armhf-generic': 'n'}>
+CONFIG_DRM_TEGRA_STAGING                        policy<{'armhf-generic': 'y'}>
+CONFIG_DRM_THINE_THC63LVD1024                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_TILCDC                               policy<{'armhf': 'm'}>
+CONFIG_DRM_TI_SN65DSI86                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_TI_TFP410                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_TOSHIBA_TC358764                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_TOSHIBA_TC358767                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_TTM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_TVE200                               policy<{'armhf': 'm'}>
+CONFIG_DRM_UDL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DRM_VC4                                  policy<{'arm64': 'm'}>
+CONFIG_DRM_VC4_HDMI_CEC                         policy<{'arm64': 'y'}>
+CONFIG_DRM_VGEM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_VIRTIO_GPU                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_VKMS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DRM_VMWGFX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_DRM_VMWGFX_FBCON                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_DRM_VRAM_HELPER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DRM_XEN                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_DRM_XEN_FRONTEND                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_DS1682                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DS1803                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DS4424                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DST_CACHE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DTC                                      policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_DTL                                      policy<{'ppc64el': 'y'}>
+CONFIG_DTLK                                     policy<{'i386': 'm'}>
+CONFIG_DT_IDLE_STATES                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DUMMY                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DUMMY_CONSOLE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DUMMY_CONSOLE_COLUMNS                    policy<{'amd64': '80', 'arm64': '80', 'i386': '80', 'ppc64el': '80', 's390x': '80'}>
+CONFIG_DUMMY_CONSOLE_ROWS                       policy<{'amd64': '25', 'arm64': '25', 'i386': '25', 'ppc64el': '25', 's390x': '25'}>
+CONFIG_DUMMY_IRQ                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DVB_A8293                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AF9013                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AF9033                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AS102                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AS102_FE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ASCOT2E                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ATBM8830                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AU8522                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AU8522_DTV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AU8522_V4L                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AV7110                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_AV7110_IR                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_AV7110_OSD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_B2C2_FLEXCOP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_BCM3510                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BT8XX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_AV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_CI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_BUDGET_PATCH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_C8SECTPFE                            policy<{'armhf': 'n'}>
+CONFIG_DVB_CORE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX22700                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX22702                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24110                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24116                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24117                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24120                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CX24123                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2099                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2820R                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2841ER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_CXD2880                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DDBRIDGE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DDBRIDGE_MSIENABLE                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_DEMUX_SECTION_LOSS_LOG               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_DIB3000MB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB3000MC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB7000M                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB7000P                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB8000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DIB9000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DM1105                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRX39XYJ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRXD                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DRXK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DS3000                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_EC100                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_FIREDTV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_FIREDTV_INPUT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_GP8PSK_FE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_HELENE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_HOPPER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_HORUS3A                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6405                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6421                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ISL6423                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_IX2505V                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_L64781                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LG2160                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT3305                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT3306A                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGDT330X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGS8GL5                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LGS8GXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBH25                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBH29                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBP21                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_LNBP22                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_M88DS3103                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_M88RS2000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MANTIS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MAX_ADAPTERS                         policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_DVB_MB86A16                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MB86A20S                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MMAP                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_MN88443X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MN88472                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MN88473                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MT312                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MT352                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_MXL5XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NET                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_NETUP_UNIDVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NGENE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NXT200X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_NXT6000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_OR51132                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_OR51211                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_PLL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PLUTO2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PT1                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_PT3                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2830                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2832                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_RTL2832_SDR                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1409                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1411                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1420                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S5H1432                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_S921                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI2165                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI2168                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SI21XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SMIPCIE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP8870                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_SP887X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STB0899                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STB6000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STB6100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0288                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0297                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0299                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0367                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0900                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV090x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV0910                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV6110                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV6110x                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_STV6111                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TC90522                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10021                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10023                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10048                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA1004X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10071                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA10086                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA18271C2DD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA665x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA8083                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA8261                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TDA826X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TS2020                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TTUSB_BUDGET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TTUSB_DEC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUA6100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_CX24113                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_DIB0070                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_DIB0090                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_TUNER_ITD1000                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ULE_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_A800                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9005                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9005_REMOTE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9015                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AF9035                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_ANYSEE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AU6610                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AZ6007                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_AZ6027                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CE6230                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CINERGY_T2                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CXUSB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_CXUSB_ANALOG                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_DVB_USB_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_USB_DIB0700                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIB3000MC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_DVB_USB_DIBUSB_MC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DIGITV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DTT200U                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DTV5100                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DVBSKY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_DW2102                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_EC168                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_GL861                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_GP8PSK                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_LME2510                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_M920X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_MXL111SF                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_NOVA_T_USB2                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_OPERA1                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_PCTV452E                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_RTL28XXU                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_TECHNISAT_USB2                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_TTUSB2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_UMT_010                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_V2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_VP702X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_VP7045                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_USB_ZD1301                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_VES1820                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_VES1X93                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZD1301_DEMOD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10036                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10039                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DVB_ZL10353                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DWC_XLGMAC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DWC_XLGMAC_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_DWMAC_DWC_QOS_ETH                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_GENERIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DWMAC_IPQ806X                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DWMAC_MEDIATEK                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DWMAC_MESON                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DWMAC_QCOM_ETHQOS                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DWMAC_ROCKCHIP                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_DWMAC_SOCFPGA                            policy<{'arm64': 'm'}>
+CONFIG_DWMAC_SUN8I                              policy<{'arm64': 'm'}>
+CONFIG_DWMAC_SUNXI                              policy<{'arm64': 'n'}>
+CONFIG_DW_APB_ICTL                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DW_APB_TIMER                             policy<{'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_DW_APB_TIMER_OF                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_DW_AXI_DMAC                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_DMAC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_DMAC_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_DMAC_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_EDMA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_EDMA_PCIE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_I3C_MASTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_DW_WATCHDOG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_DYNAMIC_DEBUG                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DYNAMIC_EVENTS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DYNAMIC_FTRACE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DYNAMIC_FTRACE_WITH_REGS                 policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_DYNAMIC_MEMORY_LAYOUT                    policy<{'amd64': 'y'}>
+CONFIG_DYNAMIC_PHYSICAL_MASK                    policy<{'amd64': 'y'}>
+CONFIG_E100                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000E                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_E1000E_HWTS                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EADM_SCH                                 policy<{'s390x': 'm'}>
+CONFIG_EARLY_PRINTK                             policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EARLY_PRINTK_DBGP                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EARLY_PRINTK_USB                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EARLY_PRINTK_USB_XDBC                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EBC_C384_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ECHO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ECRYPT_FS_MESSAGING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EDAC                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_EDAC_ALTERA                              policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_ETHERNET                     policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_NAND                         policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_OCRAM                        policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_QSPI                         policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_SDMMC                        policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_SDRAM                        policy<{'arm64': 'y'}>
+CONFIG_EDAC_ALTERA_USB                          policy<{'arm64': 'y'}>
+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_ARMADA_XP                           policy<{'armhf': 'y'}>
+CONFIG_EDAC_ATOMIC_SCRUB                        policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_EDAC_BLUEFIELD                           policy<{'arm64': 'm'}>
+CONFIG_EDAC_CPC925                              policy<{'ppc64el': 'm'}>
+CONFIG_EDAC_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_EDAC_DECODE_MCE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_E752X                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_E7XXX                               policy<{'i386': 'm'}>
+CONFIG_EDAC_GHES                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_EDAC_HIGHBANK_L2                         policy<{'armhf': 'm'}>
+CONFIG_EDAC_HIGHBANK_MC                         policy<{'armhf': 'm'}>
+CONFIG_EDAC_I10NM                               policy<{'amd64': 'm'}>
+CONFIG_EDAC_I3000                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I3200                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I5000                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I5100                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I5400                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I7300                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I7CORE                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_I82860                              policy<{'i386': 'm'}>
+CONFIG_EDAC_I82875P                             policy<{'i386': 'm'}>
+CONFIG_EDAC_I82975X                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_IE31200                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_LAYERSCAPE                          policy<{'arm64': 'm'}>
+CONFIG_EDAC_LEGACY_SYSFS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_EDAC_PND2                                policy<{'amd64': 'm'}>
+CONFIG_EDAC_QCOM                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_EDAC_R82600                              policy<{'i386': 'm'}>
+CONFIG_EDAC_SBRIDGE                             policy<{'amd64': 'm'}>
+CONFIG_EDAC_SKX                                 policy<{'amd64': 'm'}>
+CONFIG_EDAC_SUPPORT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_EDAC_SYNOPSYS                            policy<{'arm64': 'm'}>
+CONFIG_EDAC_THUNDERX                            policy<{'arm64': 'm'}>
+CONFIG_EDAC_TI                                  policy<{'armhf': 'm'}>
+CONFIG_EDAC_X38                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EDAC_XGENE                               policy<{'arm64': 'm'}>
+CONFIG_EDD                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EDD_OFF                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EEEPC_LAPTOP                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EEEPC_WMI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EEH                                      policy<{'ppc64el': 'y'}>
+CONFIG_EEPROM_93CX6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_93XX46                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_AT24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_AT25                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EEPROM_EE1004                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_IDT_89HPESX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_LEGACY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EEPROM_MAX6875                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EFI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFI_ARMSTUB                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EFI_ARMSTUB_DTB_LOADER                   policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_EFI_BOOTLOADER_CONTROL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_EFI_CAPSULE_LOADER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'y'}>
+CONFIG_EFI_CAPSULE_QUIRK_QUARK_CSH              policy<{'i386': 'y'}>
+CONFIG_EFI_CUSTOM_SSDT_OVERLAYS                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_EFI_DEV_PATH_PARSER                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EFI_EARLYCON                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_EFI_ESRT                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFI_FAKE_MEMMAP                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EFI_MIXED                                policy<{'amd64': 'y'}>
+CONFIG_EFI_PARAMS_FROM_FDT                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EFI_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EFI_PGT_DUMP                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_EFI_RCI2_TABLE                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EFI_RUNTIME_MAP                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EFI_RUNTIME_WRAPPERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFI_STUB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_EFI_TEST                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_EFI_VARS_PSTORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_EFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EINT_MTK                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_EISA                                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EISA_NAMES                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EISA_PCI_EISA                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EISA_VIRTUAL_ROOT                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EISA_VLB_PRIMING                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_EL3                                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ELFCORE                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ELF_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EMAC_ROCKCHIP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_EMBEDDED                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EM_TIMER_STI                             policy<{'armhf': 'y'}>
+CONFIG_ENABLE_MUST_CHECK                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ENA_ETHERNET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ENC28J60                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ENC28J60_WRITEVERIFY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ENCLOSURE_SERVICES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ENCRYPTED_KEYS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ENCX24J600                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ENERGY_MODEL                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ENIC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ENVELOPE_DETECTOR                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_EPAPR_BOOT                               policy<{'ppc64el': 'y'}>
+CONFIG_EPAPR_PARAVIRT                           policy<{'ppc64el': 'y'}>
+CONFIG_EPIC100                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EPOLL                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EQUALIZER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_EROFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT              policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_EROFS_FS_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EROFS_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EROFS_FS_SECURITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EROFS_FS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EROFS_FS_ZIP                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ET131X                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ETEXT_SHIFT                              policy<{'ppc64el': '16'}>
+CONFIG_ETHERNET                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ETHOC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_EUROTECH_WDT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EVENTFD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVENT_TRACING                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM_ADD_XATTRS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EVM_EXTRA_SMACK_XATTRS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXFAT_DEBUG_MSG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_EXFAT_DEFAULT_CODEPAGE                   policy<{'amd64': '437', 'arm64': '437', 'armhf': '437', 'i386': '437', 'ppc64el': '437'}>
+CONFIG_EXFAT_DEFAULT_IOCHARSET                  policy<{'amd64': '"utf8"', 'arm64': '"utf8"', 'armhf': '"utf8"', 'i386': '"utf8"', 'ppc64el': '"utf8"'}>
+CONFIG_EXFAT_DELAYED_SYNC                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_EXFAT_DISCARD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_EXFAT_DONT_MOUNT_VFAT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_EXFAT_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXFAT_KERNEL_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_EXPERT                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXPOLINE                                 policy<{'s390x': 'y'}>
+CONFIG_EXPOLINE_AUTO                            policy<{'s390x': 'y'}>
+CONFIG_EXPOLINE_FULL                            policy<{'s390x': 'n'}>
+CONFIG_EXPOLINE_OFF                             policy<{'s390x': 'n'}>
+CONFIG_EXPORTFS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXPORTFS_BLOCK_OPS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_EXT4_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_FS_SECURITY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXT4_USE_FOR_EXT2                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_EXTCON                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_EXTCON_ADC_JACK                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_ARIZONA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_AXP288                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EXTCON_FSA9480                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_GPIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_INTEL_CHT_WC                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EXTCON_INTEL_INT3496                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_EXTCON_INTEL_MRFLD                       policy<{'i386': 'm'}>
+CONFIG_EXTCON_MAX14577                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX3355                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX77693                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX77843                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_MAX8997                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_PALMAS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_PTN5150                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_QCOM_SPMI_MISC                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_EXTCON_RT8973A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_SM5502                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTCON_USBC_CROS_EC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_EXTCON_USB_GPIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_EXTRA_FIRMWARE                           policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_EXTRA_TARGETS                            policy<{'ppc64el': '""'}>
+CONFIG_EXYNOS_ADC                               policy<{'armhf': 'm'}>
+CONFIG_EXYNOS_AUDSS_CLK_CON                     policy<{'armhf': 'm'}>
+CONFIG_EXYNOS_CHIPID                            policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_CPU_SUSPEND                       policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_IOMMU                             policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_IOMMU_DEBUG                       policy<{'armhf': 'n'}>
+CONFIG_EXYNOS_MCPM                              policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_PMU                               policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_PMU_ARM_DRIVERS                   policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_PM_DOMAINS                        policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_SROM                              policy<{'armhf': 'y'}>
+CONFIG_EXYNOS_THERMAL                           policy<{'armhf': 'y'}>
+CONFIG_EZCHIP_NPS_MANAGEMENT_ENET               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_EZX_PCAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_CHECK_FS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_F2FS_FAULT_INJECTION                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_F2FS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_F2FS_FS_POSIX_ACL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_FS_SECURITY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_FS_XATTR                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_F2FS_IO_TRACE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_F2FS_STAT_FS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_F71808E_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FAILOVER                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FAIR_GROUP_SCHED                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FANOTIFY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FARSYNC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FAT_DEFAULT_CODEPAGE                     policy<{'amd64': '437', 'arm64': '437', 'armhf': '437', 'i386': '437', 'ppc64el': '437', 's390x': '437'}>
+CONFIG_FAT_DEFAULT_IOCHARSET                    policy<{'amd64': '"iso8859-1"', 'arm64': '"iso8859-1"', 'armhf': '"iso8859-1"', 'i386': '"iso8859-1"', 'ppc64el': '"iso8859-1"', 's390x': '"iso8859-1"'}>
+CONFIG_FAT_DEFAULT_UTF8                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FAT_FS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FAULT_INJECTION                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FB                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FB_3DFX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_3DFX_ACCEL                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_3DFX_I2C                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_ARC                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_ARK                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_ARMCLCD                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_FB_ASILIANT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FB_ATY                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_ATY128                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_ATY128_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ATY_BACKLIGHT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ATY_CT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_ATY_GENERIC_LCD                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_ATY_GX                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_BACKLIGHT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_BOOT_VESA_SUPPORT                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_CARILLO_RANCH                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_CARMINE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_CARMINE_DRAM_EVAL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_CFB_COPYAREA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_FB_CFB_FILLRECT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_FB_CFB_IMAGEBLIT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_FB_CFB_REV_PIXELS_IN_BYTE                policy<{'armhf-generic': 'y'}>
+CONFIG_FB_CIRRUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_CMDLINE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FB_CYBER2000                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_CYBER2000_DDC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_DA8XX                                 policy<{'armhf-generic': 'm'}>
+CONFIG_FB_DDC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_DEFERRED_IO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FB_EFI                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_FB_FOREIGN_ENDIAN                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FB_GEODE                                 policy<{'i386': 'y'}>
+CONFIG_FB_GEODE_GX                              policy<{'i386': 'm'}>
+CONFIG_FB_GEODE_GX1                             policy<{'i386': 'm'}>
+CONFIG_FB_GEODE_LX                              policy<{'i386': 'm'}>
+CONFIG_FB_HECUBA                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_HGA                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_HYPERV                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_I740                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_I810                                  policy<{'i386': 'm'}>
+CONFIG_FB_I810_GTF                              policy<{'i386': 'n'}>
+CONFIG_FB_IBM_GXT4500                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FB_IMSTT                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FB_IMX                                   policy<{'arm64': 'm', 'armhf-generic': '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_KYRO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_LE80578                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_MACMODES                              policy<{'ppc64el': 'y'}>
+CONFIG_FB_MATROX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_MATROX_G                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MATROX_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MATROX_MAVEN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_MATROX_MILLENIUM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MATROX_MYSTIQUE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MB862XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_MB862XX_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_MB862XX_LIME                          policy<{'ppc64el': 'n'}>
+CONFIG_FB_MB862XX_PCI_GDC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_METRONOME                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_MODE_HELPERS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FB_MX3                                   policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_FB_N411                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FB_NEOMAGIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_NOTIFY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FB_NVIDIA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_NVIDIA_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_NVIDIA_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_NVIDIA_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_OF                                    policy<{'ppc64el': 'y'}>
+CONFIG_FB_OMAP2                                 policy<{'armhf': 'm'}>
+CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV             policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_CONNECTOR_DVI                   policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_CONNECTOR_HDMI                  policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DEBUG_SUPPORT                   policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DSS                             policy<{'armhf': 'm'}>
+CONFIG_FB_OMAP2_DSS_DEBUG                       policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DSS_DEBUGFS                     policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DSS_DPI                         policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP2_DSS_DSI                         policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DSS_HDMI_COMMON                 policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP2_DSS_INIT                        policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP2_DSS_MIN_FCK_PER_PCK             policy<{'armhf': '0'}>
+CONFIG_FB_OMAP2_DSS_SDI                         policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET      policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP2_DSS_VENC                        policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP2_ENCODER_OPA362                  policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_ENCODER_TFP410                  policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_ENCODER_TPD12S015               policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_NUM_FBS                         policy<{'armhf': '3'}>
+CONFIG_FB_OMAP2_PANEL_DPI                       policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_PANEL_DSI_CM                    policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02        policy<{'armhf': 'n'}>
+CONFIG_FB_OMAP4_DSS_HDMI                        policy<{'armhf': 'y'}>
+CONFIG_FB_OMAP5_DSS_HDMI                        policy<{'armhf': 'n'}>
+CONFIG_FB_OPENCORES                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_PM2                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_PM2_FIFO_DISCONNECT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_PM3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA          policy<{'armhf': 'y'}>
+CONFIG_FB_RADEON                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_RADEON_BACKLIGHT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RADEON_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_RADEON_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RIVA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_RIVA_BACKLIGHT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_RIVA_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_RIVA_I2C                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_S1D13XXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_S3                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_S3_DDC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SAVAGE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_SAVAGE_ACCEL                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_FB_SAVAGE_I2C                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SH_MOBILE_LCDC                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FB_SIMPLE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FB_SIS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_SIS_300                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SIS_315                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FB_SM501                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SM712                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_SM750                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SMSCUFX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SSD1307                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SVGALIB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_SYS_COPYAREA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FB_SYS_FILLRECT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FB_SYS_FOPS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FB_SYS_IMAGEBLIT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FB_TFT                                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_AGM1264K_FL                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_BD663474                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8340BN                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8347D                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8353D                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_HX8357D                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9163                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9320                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9325                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9340                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9341                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9481                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ILI9486                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_PCD8544                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_RA8875                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_S6D02A1                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_S6D1121                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SH1106                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1289                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1305                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1306                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1331                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_SSD1351                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ST7735R                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_ST7789V                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_TINYLCD                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_TLS8204                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UC1611                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UC1701                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_UPD161704                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TFT_WATTEROTT                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_TILEBLITTING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FB_TMIO                                  policy<{'armhf': 'm'}>
+CONFIG_FB_TMIO_ACCELL                           policy<{'armhf': 'y'}>
+CONFIG_FB_TRIDENT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_UDL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FB_UVESA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_VESA                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_FB_VGA16                                 policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+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_VIRTUAL                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FB_VOODOO1                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_VT8623                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FB_XILINX                                policy<{'arm64': 'm'}>
+CONFIG_FCOE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FCOE_FNIC                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FDDI                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FEALNX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FEC                                      policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_FIB_RULES                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FIELDBUS_DEV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FILE_LOCKING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FIND_BIT_BENCHMARK                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FIQ                                      policy<{'armhf-generic': 'y'}>
+CONFIG_FIREWIRE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FIREWIRE_NET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_NOSY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FIREWIRE_OHCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_SBP2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FIREWIRE_SERIAL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FIRMWARE_EDID                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FIRMWARE_MEMMAP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_FIXED_PHY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_FIX_EARLYCON_MEM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_FLATMEM                                  policy<{'armhf': 'y'}>
+CONFIG_FLATMEM_MANUAL                           policy<{'i386': 'n'}>
+CONFIG_FLAT_NODE_MEM_MAP                        policy<{'armhf': 'y'}>
+CONFIG_FM10K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FONTS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_10x18                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_6x10                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_6x11                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_7x14                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_8x16                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_8x8                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_ACORN_8x8                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_MINI_4x6                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_PEARL_8x8                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_SUN12x22                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_SUN8x16                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FONT_SUPPORT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FONT_TER16x32                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FORCEDETH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FORCE_DYNAMIC_FTRACE                     policy<{'i386': 'y'}>
+CONFIG_FORCE_MAX_ZONEORDER                      policy<{'arm64': '13', 'armhf-generic': '12', 'armhf-generic-lpae': '11', 'ppc64el': '9', 's390x': '9'}>
+CONFIG_FORCE_PCI                                policy<{'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_FORCE_SMP                                policy<{'ppc64el': 'y'}>
+CONFIG_FORTIFY_SOURCE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FPGA                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FPGA_BRIDGE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FPGA_DFL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_FPGA_DFL_AFU                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_DFL_FME                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_DFL_FME_BRIDGE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_DFL_FME_MGR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_DFL_FME_REGION                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_DFL_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_MGR_ALTERA_CVP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FPGA_MGR_ALTERA_PS_SPI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_MGR_ICE40_SPI                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_MGR_MACHXO2_SPI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_MGR_STRATIX10_SOC                   policy<{'arm64': 'm'}>
+CONFIG_FPGA_MGR_XILINX_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FPGA_MGR_ZYNQMP_FPGA                     policy<{'arm64': 'm'}>
+CONFIG_FPGA_REGION                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FRAMEBUFFER_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRAME_POINTER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_FRAME_VECTOR                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FRAME_WARN                               policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'ppc64el': '2048', 's390x': '1024'}>
+CONFIG_FREEZER                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FRONTSWAP                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FSCACHE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_FSCACHE_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FSCACHE_HISTOGRAM                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FSCACHE_OBJECT_LIST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FSCACHE_STATS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FSI                                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSI_MASTER_AST_CF                        policy<{'armhf': 'm'}>
+CONFIG_FSI_MASTER_GPIO                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSI_MASTER_HUB                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSI_NEW_DEV_NODE                         policy<{'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n'}>
+CONFIG_FSI_OCC                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSI_SBEFIFO                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSI_SCOM                                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSL_BMAN_TEST                            policy<{'arm64': 'm'}>
+CONFIG_FSL_BMAN_TEST_API                        policy<{'arm64': 'n'}>
+CONFIG_FSL_DPAA                                 policy<{'arm64': 'y'}>
+CONFIG_FSL_DPAA2                                policy<{'arm64': 'y'}>
+CONFIG_FSL_DPAA2_ETH                            policy<{'arm64': 'm'}>
+CONFIG_FSL_DPAA2_ETHSW                          policy<{'arm64': 'm'}>
+CONFIG_FSL_DPAA2_PTP_CLOCK                      policy<{'arm64': 'm'}>
+CONFIG_FSL_DPAA_CHECKING                        policy<{'arm64': 'y'}>
+CONFIG_FSL_DPAA_ETH                             policy<{'arm64': 'm'}>
+CONFIG_FSL_EDMA                                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FSL_ENETC                                policy<{'arm64': 'm'}>
+CONFIG_FSL_ENETC_HW_TIMESTAMPING                policy<{'arm64': 'y'}>
+CONFIG_FSL_ENETC_MDIO                           policy<{'arm64': 'm'}>
+CONFIG_FSL_ENETC_PTP_CLOCK                      policy<{'arm64': 'm'}>
+CONFIG_FSL_ENETC_VF                             policy<{'arm64': 'm'}>
+CONFIG_FSL_ERRATUM_A008585                      policy<{'arm64': 'y'}>
+CONFIG_FSL_FMAN                                 policy<{'arm64': 'y'}>
+CONFIG_FSL_GUTS                                 policy<{'arm64': 'y', 'armhf-generic': 'y', 'ppc64el': 'y'}>
+CONFIG_FSL_IFC                                  policy<{'arm64': 'y'}>
+CONFIG_FSL_IMX8_DDR_PMU                         policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_FSL_LBC                                  policy<{'ppc64el': 'y'}>
+CONFIG_FSL_MC_BUS                               policy<{'arm64': 'y'}>
+CONFIG_FSL_MC_DPIO                              policy<{'arm64': 'm'}>
+CONFIG_FSL_PQ_MDIO                              policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_FSL_QDMA                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_FSL_QMAN_TEST                            policy<{'arm64': 'n'}>
+CONFIG_FSL_XGMAC_MDIO                           policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_FSNOTIFY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_DAX                                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_DAX_LIMITED                           policy<{'s390x': 'y'}>
+CONFIG_FS_DAX_PMD                               policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_FS_ENCRYPTION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_IOMAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_MBCACHE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_POSIX_ACL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_VERITY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_VERITY_BUILTIN_SIGNATURES             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FS_VERITY_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FTGMAC100                                policy<{'armhf': 'm'}>
+CONFIG_FTL                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FTMAC100                                 policy<{'armhf': 'm'}>
+CONFIG_FTM_QUADDEC                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_FTRACE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FTRACE_MCOUNT_RECORD                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FTRACE_STARTUP_TEST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_FTRACE_SYSCALLS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FTR_FIXUP_SELFTEST                       policy<{'ppc64el': 'n'}>
+CONFIG_FTWDT010_WATCHDOG                        policy<{'armhf': 'm'}>
+CONFIG_FUEL_GAUGE_SC27XX                        policy<{'arm64': 'm'}>
+CONFIG_FUJITSU_ERRATUM_010001                   policy<{'arm64': 'y'}>
+CONFIG_FUJITSU_ES                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_FUJITSU_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FUJITSU_TABLET                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_FUNCTION_ERROR_INJECTION                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FUNCTION_GRAPH_TRACER                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUNCTION_PROFILER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUNCTION_TRACER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUSION                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_FUSION_CTL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_FC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_LAN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_LOGGING                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_FUSION_MAX_SGE                           policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128'}>
+CONFIG_FUSION_SAS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FUSION_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FUTEX                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FUTEX_PI                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FWTTY_MAX_CARD_PORTS                     policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32'}>
+CONFIG_FWTTY_MAX_TOTAL_PORTS                    policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'ppc64el': '64'}>
+CONFIG_FW_CFG_SYSFS                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_FW_CFG_SYSFS_CMDLINE                     policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_FW_LOADER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FW_LOADER_COMPRESS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FW_LOADER_PAGED_BUF                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FW_LOADER_USER_HELPER                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_FXAS21002C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FXAS21002C_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_FXAS21002C_SPI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GACT_PROB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GADGET_UAC1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GADGET_UAC1_LEGACY                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_GAMEPORT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GAMEPORT_EMU10K1                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_FM801                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_L4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GAMEPORT_NS558                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GARP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GART_IOMMU                               policy<{'amd64': 'y'}>
+CONFIG_GCC_VERSION                              policy<{'amd64': '90400', 'arm64': '90400', 'armhf': '90400', 'i386': '90400', 'ppc64el': '90400', 's390x': '90400'}>
+CONFIG_GCOV_KERNEL                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GDB_SCRIPTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GDS_FORCE_MITIGATION                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_GEMINI_ETHERNET                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GENERIC_ADC_BATTERY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GENERIC_ADC_THERMAL                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GENERIC_ALLOCATOR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_ARCH_TOPOLOGY                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GENERIC_BUG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS            policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_CALIBRATE_DELAY                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_CLOCKEVENTS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_CMOS_UPDATE                      policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_CPU                              policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_CPU_AUTOPROBE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_CPU_VULNERABILITIES              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_CSUM                             policy<{'arm64': 'y'}>
+CONFIG_GENERIC_EARLY_IOREMAP                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_FIND_FIRST_BIT                   policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_GETTIMEOFDAY                     policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_HWEIGHT                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_IDLE_POLL_SETUP                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GENERIC_IOMAP                            policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_IRQ_CHIP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_IRQ_DEBUGFS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_IRQ_MIGRATION                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_IRQ_MULTI_HANDLER                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GENERIC_IRQ_PROBE                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_IRQ_RESERVATION_MODE             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_IRQ_SHOW                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_IRQ_SHOW_LEVEL                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_ISA_DMA                          policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_MSI_IRQ                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_MSI_IRQ_DOMAIN                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_NET_UTILS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_PCI_IOMAP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_PENDING_IRQ                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GENERIC_PHY                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_GENERIC_PHY_MIPI_DPHY                    policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_PINCONF                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_PINCTRL_GROUPS                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_PINMUX_FUNCTIONS                 policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_SCHED_CLOCK                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GENERIC_SMP_IDLE_THREAD                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_STRNCPY_FROM_USER                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_STRNLEN_USER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GENERIC_TIME_VSYSCALL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_TRACER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GENERIC_VDSO_32                          policy<{'i386': 'y'}>
+CONFIG_GENEVE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GENWQE                                   policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY           policy<{'amd64': '0', 'arm64': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_GEN_RTC                                  policy<{'ppc64el': 'y'}>
+CONFIG_GEOS                                     policy<{'i386': 'y'}>
+CONFIG_GFS2_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GFS2_FS_LOCKING_DLM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GIANFAR                                  policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_GIGASET_BASE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_CAPI                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_GIGASET_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_GIGASET_M101                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GIGASET_M105                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GLOB                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GLOB_SELFTEST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GNSS                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GNSS_MTK_SERIAL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GNSS_SERIAL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GNSS_SIRF_SERIAL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GNSS_UBX_SERIAL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GOLDFISH                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_GOOGLE_FIRMWARE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_GP2AP020A00F                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPD_POCKET_FAN                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIOLIB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GPIOLIB_FASTPATH_LIMIT                   policy<{'amd64': '512', 'arm64': '512', 'armhf': '512', 'i386': '512', 'ppc64el': '512', 's390x': '512'}>
+CONFIG_GPIOLIB_IRQCHIP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GPIO_104_DIO_48E                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_104_IDIO_16                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_104_IDI_48                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_74X164                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_74XX_MMIO                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ACPI                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_GPIO_ADNP                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ADP5520                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ADP5588                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_ALTERA                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_AMD8111                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_AMDPT                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_AMD_FCH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_ARIZONA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ASPEED                              policy<{'armhf': 'm'}>
+CONFIG_GPIO_BD70528                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_BD9571MWV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_BRCMSTB                             policy<{'arm64': 'm'}>
+CONFIG_GPIO_BT8XX                               policy<{'s390x': 'm'}>
+CONFIG_GPIO_CADENCE                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_CRYSTAL_COVE                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_CS5535                              policy<{'i386': 'm'}>
+CONFIG_GPIO_DA9052                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_DA9055                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_DAVINCI                             policy<{'arm64': 'y'}>
+CONFIG_GPIO_DLN2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_DWAPB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_EIC_SPRD                            policy<{'arm64': 'm'}>
+CONFIG_GPIO_EXAR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_F7188X                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_FTGPIO010                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_GENERIC                             policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_GPIO_GENERIC_PLATFORM                    policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GPIO_GPIO_MM                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_GRGPIO                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_GW_PLD                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_HLWD                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ICH                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_INTEL_MID                           policy<{'i386': 'y'}>
+CONFIG_GPIO_IT87                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_JANZ_TTL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_KEMPLD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_LP3943                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_LP873X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_LP87565                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_LYNXPOINT                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_GPIO_MADERA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX3191X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX7300                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_MAX7301                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX730X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX732X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_MAX77620                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MAX77650                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MB86S7X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_MC33880                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MENZ127                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MERRIFIELD                          policy<{'i386': 'n'}>
+CONFIG_GPIO_MLXBF                               policy<{'arm64': 'm'}>
+CONFIG_GPIO_ML_IOH                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_MOCKUP                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GPIO_MOXTET                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_MPC8XXX                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_MSIC                                policy<{'i386': 'y'}>
+CONFIG_GPIO_MVEBU                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_MXC                                 policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_GPIO_OMAP                                policy<{'armhf': 'y'}>
+CONFIG_GPIO_PALMAS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_PCA953X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_PCF857X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_PCH                                 policy<{'i386': 'm'}>
+CONFIG_GPIO_PCIE_IDIO_24                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GPIO_PCI_IDIO_16                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GPIO_PISOSR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_PL061                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_GPIO_PMIC_EIC_SPRD                       policy<{'arm64': 'm'}>
+CONFIG_GPIO_RASPBERRYPI_EXP                     policy<{'arm64': 'm'}>
+CONFIG_GPIO_RC5T583                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_RCAR                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_GPIO_RDC321X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GPIO_SAMA5D2_PIOBU                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_SCH                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_SCH311X                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_SIOX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_SPRD                                policy<{'arm64': 'm'}>
+CONFIG_GPIO_STMPE                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_SYSCON                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_SYSFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GPIO_TC3589X                             policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TEGRA                               policy<{'armhf-generic': 'y'}>
+CONFIG_GPIO_THUNDERX                            policy<{'arm64': 'm'}>
+CONFIG_GPIO_TIMBERDALE                          policy<{'i386': 'y'}>
+CONFIG_GPIO_TPIC2810                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GPIO_TPS65086                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TPS65218                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TPS6586X                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TPS65910                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GPIO_TPS65912                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TPS68470                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_GPIO_TQMX86                              policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_TS4800                              policy<{'armhf-generic': 'm'}>
+CONFIG_GPIO_TS4900                              policy<{'armhf-generic': 'm'}>
+CONFIG_GPIO_TWL6040                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_UCB1400                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_UNIPHIER                            policy<{'armhf': 'm'}>
+CONFIG_GPIO_VF610                               policy<{'armhf-generic': 'y'}>
+CONFIG_GPIO_VIPERBOARD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_VX855                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_WATCHDOG                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WHISKEY_COVE                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_WINBOND                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_WM831X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WM8350                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WM8994                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_WS16C48                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_GPIO_XGENE                               policy<{'arm64': 'y'}>
+CONFIG_GPIO_XGENE_SB                            policy<{'arm64': 'm'}>
+CONFIG_GPIO_XILINX                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_GPIO_XLP                                 policy<{'arm64': 'm'}>
+CONFIG_GPIO_XRA1403                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GPIO_ZEVIO                               policy<{'armhf': 'y'}>
+CONFIG_GPIO_ZYNQ                                policy<{'arm64': 'm'}>
+CONFIG_GRACE_PERIOD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GREENASIA_FF                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_GREYBUS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_GREYBUS_AUDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_BOOTROM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_BRIDGED_PHY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_ES2                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_FIRMWARE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_GPIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_HID                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_LIGHT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_LOG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_LOOPBACK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_POWER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_PWM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_RAW                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_SDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_UART                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GREYBUS_VIBRATOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GRO_CELLS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_GS_FPGABOOT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_GTP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_GUP_BENCHMARK                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_GUP_GET_PTE_LOW_HIGH                     policy<{'i386': 'y'}>
+CONFIG_GVE                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HABANA_AI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HALTPOLL_CPUIDLE                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HAMACHI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HAMRADIO                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HANDLE_DOMAIN_IRQ                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HANGCHECK_TIMER                          policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_HAPPYMEAL                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HARDENED_USERCOPY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HARDENED_USERCOPY_FALLBACK               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HARDENED_USERCOPY_PAGESPAN               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HARDEN_BRANCH_HISTORY                    policy<{'armhf': 'y'}>
+CONFIG_HARDEN_BRANCH_PREDICTOR                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HARDEN_EL2_VECTORS                       policy<{'arm64': 'y'}>
+CONFIG_HARDIRQS_SW_RESEND                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_HARDLOCKUP_CHECK_TIMESTAMP               policy<{'amd64': 'y'}>
+CONFIG_HARDLOCKUP_DETECTOR                      policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HARDLOCKUP_DETECTOR_PERF                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAS_DMA                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAS_IOMEM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAS_IOPORT_MAP                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_ACPI_APEI                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ACPI_APEI_NMI                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_AUDITSYSCALL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_BITREVERSE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES              policy<{'amd64': 'y'}>
+CONFIG_HAVE_ARCH_HUGE_VMAP                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_ARCH_JUMP_LABEL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_KASAN                          policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_KASAN_SW_TAGS                  policy<{'arm64': 'y'}>
+CONFIG_HAVE_ARCH_KGDB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_ARCH_MMAP_RND_BITS                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_ARCH_NVRAM_OPS                      policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_ARCH_PFN_VALID                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_ARCH_PREL32_RELOCATIONS             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ARCH_SECCOMP_FILTER                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_SOFT_DIRTY                     policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_STACKLEAK                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ARCH_TRACEHOOK                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE           policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD       policy<{'amd64': 'y'}>
+CONFIG_HAVE_ARCH_VMAP_STACK                     policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_ARM_ARCH_TIMER                      policy<{'armhf': 'y'}>
+CONFIG_HAVE_ARM_SCU                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_ARM_SMCCC                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_ARM_TWD                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_ASM_MODVERSIONS                     policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_ATOMIC_IOMAP                        policy<{'i386': 'y'}>
+CONFIG_HAVE_BOOTMEM_INFO_NODE                   policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_CLK                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HAVE_CLK_PREPARE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HAVE_CMPXCHG_DOUBLE                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_CMPXCHG_LOCAL                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_CONTEXT_TRACKING                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_COPY_THREAD_TLS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_C_RECORDMCOUNT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_DEBUG_BUGVERBOSE                    policy<{'arm64': 'y'}>
+CONFIG_HAVE_DEBUG_KMEMLEAK                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_DEBUG_STACKOVERFLOW                 policy<{'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_DMA_CONTIGUOUS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_DYNAMIC_FTRACE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS            policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_EBPF_JIT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_EISA                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_EXIT_THREAD                         policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HAVE_FAST_GUP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_FENTRY                              policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_FUNCTION_ARG_ACCESS_API             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_FUNCTION_ERROR_INJECTION            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_FUNCTION_TRACER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_FUTEX_CMPXCHG                       policy<{'armhf': 'y', 's390x': 'y'}>
+CONFIG_HAVE_GCC_PLUGINS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_GENERIC_VDSO                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_HARDLOCKUP_DETECTOR_ARCH            policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_HW_BREAKPOINT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_IDE                                 policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_IMA_KEXEC                           policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_IMX_ANATOP                          policy<{'armhf-generic': 'y'}>
+CONFIG_HAVE_IMX_GPC                             policy<{'armhf-generic': 'y'}>
+CONFIG_HAVE_IMX_MMDC                            policy<{'armhf-generic': 'y'}>
+CONFIG_HAVE_IMX_SRC                             policy<{'armhf-generic': 'y'}>
+CONFIG_HAVE_INTEL_TXT                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_IOREMAP_PROT                        policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK               policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_KERNEL_BZIP2                        policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KERNEL_GZIP                         policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KERNEL_LZ4                          policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KERNEL_LZMA                         policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KERNEL_LZO                          policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KERNEL_UNCOMPRESSED                 policy<{'s390x': 'y'}>
+CONFIG_HAVE_KERNEL_XZ                           policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KPROBES                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KPROBES_ON_FTRACE                   policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KRETPROBES                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM                                 policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL              policy<{'arm64': 'y', 'armhf-generic-lpae': 'y'}>
+CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_EVENTFD                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_INVALID_WAKEUPS                 policy<{'s390x': 'y'}>
+CONFIG_HAVE_KVM_IRQCHIP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_IRQFD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_IRQ_BYPASS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_KVM_IRQ_ROUTING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_MSI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y'}>
+CONFIG_HAVE_KVM_NO_POLL                         policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL                policy<{'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE             policy<{'arm64': 'y'}>
+CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION       policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_LIVEPATCH                           policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_MARCH_Z10_FEATURES                  policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_Z13_FEATURES                  policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_Z196_FEATURES                 policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_Z900_FEATURES                 policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_Z990_FEATURES                 policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_Z9_109_FEATURES               policy<{'s390x': 'y'}>
+CONFIG_HAVE_MARCH_ZEC12_FEATURES                policy<{'s390x': 'y'}>
+CONFIG_HAVE_MEMBLOCK_NODE_MAP                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_MEMBLOCK_PHYS_MAP                   policy<{'s390x': 'y'}>
+CONFIG_HAVE_MEMORYLESS_NODES                    policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_MEMORY_PRESENT                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_MMIOTRACE_SUPPORT                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_MMU_GATHER_NO_GATHER                policy<{'s390x': 'y'}>
+CONFIG_HAVE_MMU_GATHER_PAGE_SIZE                policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_MOD_ARCH_SPECIFIC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_MOVE_PMD                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_NET_DSA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_NMI                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_NMI_WATCHDOG                        policy<{'ppc64el': 'y'}>
+CONFIG_HAVE_NOP_MCOUNT                          policy<{'s390x': 'y'}>
+CONFIG_HAVE_OPROFILE                            policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_OPTPROBES                           policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_PATA_PLATFORM                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HAVE_PCI                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_PCSPKR_PLATFORM                     policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_PERF_EVENTS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_PERF_EVENTS_NMI                     policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_PERF_REGS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_PERF_USER_STACK_DUMP                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_PNETID                              policy<{'s390x': 'm'}>
+CONFIG_HAVE_PROC_CPU                            policy<{'armhf': 'y'}>
+CONFIG_HAVE_RCU_TABLE_FREE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_RELIABLE_STACKTRACE                 policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_RSEQ                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_S3C2410_I2C                         policy<{'armhf': 'y'}>
+CONFIG_HAVE_S3C2410_WATCHDOG                    policy<{'armhf': 'y'}>
+CONFIG_HAVE_S3C_RTC                             policy<{'armhf': 'y'}>
+CONFIG_HAVE_SETUP_PER_CPU_AREA                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_SMP                                 policy<{'armhf': 'y'}>
+CONFIG_HAVE_STACKPROTECTOR                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HAVE_STACK_VALIDATION                    policy<{'amd64': 'y'}>
+CONFIG_HAVE_SYSCALL_TRACEPOINTS                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_UID16                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_USER_RETURN_NOTIFIER                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING                 policy<{'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HBMC_AM654                               policy<{'arm64': 'm'}>
+CONFIG_HCALL_STATS                              policy<{'ppc64el': 'n'}>
+CONFIG_HD44780                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDC100X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_CISCO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_FR                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_PPP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_RAW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_RAW_ETH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDLC_X25                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HDMI                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HDMI_LPE_AUDIO                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HDQ_MASTER_OMAP                          policy<{'armhf': 'm'}>
+CONFIG_HEADERS_INSTALL                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HERMES                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HERMES_CACHE_FW_ON_INIT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HERMES_PRISM                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_HFI1_DEBUG_SDMA_ORDER                    policy<{'amd64': 'n'}>
+CONFIG_HFSPLUS_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HI13X1_GMAC                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HI3660_MBOX                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HI6220_MBOX                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HI8435                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HIBERNATE_CALLBACKS                      policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_HID                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HIDRAW                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_A4TECH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ACCUTOUCH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ACRUX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ACRUX_FF                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_ALPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_APPLE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_APPLEIR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ASUS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_AUREAL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BATTERY_STRENGTH                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_BELKIN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BETOP_FF                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_BIGBEN_FF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CHERRY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CHICONY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CMEDIA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CORSAIR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_COUGAR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CP2112                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CREATIVE_SB0540                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_CYPRESS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_DRAGONRISE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ELAN                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ELECOM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ELO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_EMS_FF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_EZKEY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GEMBIRD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GENERIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GFRM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GOOGLE_HAMMER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_HID_GREENASIA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GT683R                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_GYRATION                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_HOLTEK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_HYPERV_MOUSE                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HID_ICADE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ITE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_JABRA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KENSINGTON                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KEYTOUCH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_KYE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LCPOWER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LED                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LENOVO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LOGITECH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LOGITECH_DJ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_LOGITECH_HIDPP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MACALLY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MAGICMOUSE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MALTRON                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MAYFLASH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MICROSOFT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MONTEREY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_MULTITOUCH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_NTI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_NTRIG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ORTEK                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PANTHERLORD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PENMOUNT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PETALYNX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PICOLCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PICOLCD_BACKLIGHT                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_CIR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_FB                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_LCD                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PICOLCD_LEDS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PID                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HID_PLANTRONICS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PRIMAX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_PRODIKEYS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_REDRAGON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_RETRODE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_RMI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ROCCAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SAITEK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SAMSUNG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_ACCEL_3D                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_ALS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_CUSTOM_SENSOR                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_DEVICE_ROTATION               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_GYRO_3D                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_HUB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_HUMIDITY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_IIO_COMMON                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_IIO_TRIGGER                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_INCLINOMETER_3D               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_MAGNETOMETER_3D               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_PRESS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_PROX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SENSOR_TEMP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SMARTJOYPLUS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SONY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SPEEDLINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_STEAM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_STEELSERIES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_SUNPLUS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_THINGM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_THRUSTMASTER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_TIVO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_TOPSEED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_TWINHAN                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_U2FZERO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_UCLOGIC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_UDRAW_PS3                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_VIEWSONIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_WACOM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_WALTOP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_WIIMOTE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_XINMO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ZEROPLUS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HID_ZYDACRON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HIGHMEM                                  policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_HIGHMEM4G                                policy<{'i386': 'n'}>
+CONFIG_HIGHMEM64G                               policy<{'i386': 'y'}>
+CONFIG_HIGHPTE                                  policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_HIGH_RES_TIMERS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HINIC                                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_HIP04_ETH                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HISILICON_ERRATUM_161010101              policy<{'arm64': 'y'}>
+CONFIG_HISILICON_ERRATUM_161600802              policy<{'arm64': 'y'}>
+CONFIG_HISILICON_IRQ_MBIGEN                     policy<{'arm64': 'y'}>
+CONFIG_HISILICON_LPC                            policy<{'arm64': 'y'}>
+CONFIG_HISI_DMA                                 policy<{'arm64': 'n'}>
+CONFIG_HISI_FEMAC                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HISI_PMU                                 policy<{'arm64': 'm'}>
+CONFIG_HISI_THERMAL                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HIST_TRIGGERS                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HIX5HD2_GMAC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HMC6352                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HMC_DRV                                  policy<{'s390x': 'm'}>
+CONFIG_HMEM_REPORTING                           policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_HMM_MIRROR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HMS_ANYBUSS_BUS                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_HMS_PROFINET                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_HNS                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS3                                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS3_DCB                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HNS3_ENET                                policy<{'arm64': 'm'}>
+CONFIG_HNS3_HCLGE                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS3_HCLGEVF                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS_DSAF                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS_ENET                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HNS_MDIO                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HOLES_IN_ZONE                            policy<{'arm64': 'y'}>
+CONFIG_HOLTEK_FF                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HOSTAP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTAP_CS                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HOSTAP_FIRMWARE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HOSTAP_FIRMWARE_NVRAM                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HOSTAP_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTAP_PLX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HOSTESS_SV11                             policy<{'i386': 'm'}>
+CONFIG_HOTPLUG_CPU                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+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_COMPAQ                       policy<{'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM                 policy<{'i386': 'y'}>
+CONFIG_HOTPLUG_PCI_CPCI                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HOTPLUG_PCI_CPCI_GENERIC                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_CPCI_ZT5550                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_IBM                          policy<{'i386': 'm'}>
+CONFIG_HOTPLUG_PCI_POWERNV                      policy<{'ppc64el': 'm'}>
+CONFIG_HOTPLUG_PCI_RPA                          policy<{'ppc64el': 'm'}>
+CONFIG_HOTPLUG_PCI_RPA_DLPAR                    policy<{'ppc64el': 'm'}>
+CONFIG_HOTPLUG_PCI_S390                         policy<{'s390x': 'y'}>
+CONFIG_HOTPLUG_SMT                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HP03                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HP100                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HP206C                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HPET                                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPET_EMULATE_RTC                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPET_MMAP                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPET_MMAP_DEFAULT                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPET_TIMER                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HPFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HPWDT_NMI_DECODING                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HP_ACCEL                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_ILO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HP_WATCHDOG                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_WIRELESS                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HP_WMI                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HSA_AMD                                  policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_HSI                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HSI_BOARDINFO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HSI_CHAR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HSR                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HSU_DMA                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HSU_DMA_PCI                              policy<{'i386': 'm'}>
+CONFIG_HT16K33                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_HTC_EGPIO                                policy<{'armhf': 'y'}>
+CONFIG_HTC_I2CPLD                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HTC_PASIC3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HTS221                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HTS221_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HTS221_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HTU21                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HUAWEI_WMI                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HUGETLBFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HUGETLB_PAGE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HUGETLB_PAGE_SIZE_VARIABLE               policy<{'ppc64el': 'y'}>
+CONFIG_HVCS                                     policy<{'ppc64el': 'm'}>
+CONFIG_HVC_CONSOLE                              policy<{'ppc64el': 'y'}>
+CONFIG_HVC_DCC                                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_HVC_DRIVER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HVC_IRQ                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HVC_IUCV                                 policy<{'s390x': 'y'}>
+CONFIG_HVC_OLD_HVSI                             policy<{'ppc64el': 'y'}>
+CONFIG_HVC_OPAL                                 policy<{'ppc64el': 'y'}>
+CONFIG_HVC_RTAS                                 policy<{'ppc64el': 'y'}>
+CONFIG_HVC_XEN                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HVC_XEN_FRONTEND                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_HV_PERF_CTRS                             policy<{'ppc64el': 'y'}>
+CONFIG_HWLAT_TRACER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HWMON                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HWMON_DEBUG_CHIP                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_HWMON_VID                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HWPOISON_INJECT                          policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_HWSPINLOCK                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HWSPINLOCK_OMAP                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HWSPINLOCK_QCOM                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HWSPINLOCK_SPRD                          policy<{'arm64': 'm'}>
+CONFIG_HW_CONSOLE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HW_PERF_EVENTS                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_HW_RANDOM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HW_RANDOM_AMD                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HW_RANDOM_BCM2835                        policy<{'arm64': 'm'}>
+CONFIG_HW_RANDOM_CAVIUM                         policy<{'arm64': 'm'}>
+CONFIG_HW_RANDOM_EXYNOS                         policy<{'armhf': 'm'}>
+CONFIG_HW_RANDOM_GEODE                          policy<{'i386': 'm'}>
+CONFIG_HW_RANDOM_HISI                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_HISI_V2                        policy<{'arm64': 'm'}>
+CONFIG_HW_RANDOM_IMX_RNGC                       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_HW_RANDOM_INTEL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HW_RANDOM_IPROC_RNG200                   policy<{'arm64': 'm'}>
+CONFIG_HW_RANDOM_MESON                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_MTK                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_OMAP                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_OMAP3_ROM                      policy<{'armhf-generic': 'm'}>
+CONFIG_HW_RANDOM_OPTEE                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_HW_RANDOM_POWERNV                        policy<{'ppc64el': 'm'}>
+CONFIG_HW_RANDOM_PSERIES                        policy<{'ppc64el': 'm'}>
+CONFIG_HW_RANDOM_S390                           policy<{'s390x': 'm'}>
+CONFIG_HW_RANDOM_TIMERIOMEM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_HW_RANDOM_TPM                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_HW_RANDOM_VIA                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HW_RANDOM_VIRTIO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_HW_RANDOM_XGENE                          policy<{'arm64': 'm'}>
+CONFIG_HX711                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HYPERV                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERVISOR_GUEST                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HYPERV_BALLOON                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_IOMMU                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HYPERV_KEYBOARD                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_NET                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_STORAGE                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_TIMER                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_HYPERV_UTILS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYPERV_VSOCKETS                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_HYSDN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_HYSDN_CAPI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_HZ                                       policy<{'amd64-generic': '250', 'amd64-lowlatency': '1000', 'arm64': '250', 'armhf': '250', 'i386-generic': '250', 'i386-lowlatency': '1000', 'ppc64el': '250', 's390x': '100'}>
+CONFIG_HZ_100                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_HZ_1000                                  policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HZ_200                                   policy<{'armhf': 'n'}>
+CONFIG_HZ_250                                   policy<{'amd64-generic': 'y', 'amd64-lowlatency': 'n', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'i386-lowlatency': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_HZ_300                                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_HZ_500                                   policy<{'armhf': 'n'}>
+CONFIG_HZ_FIXED                                 policy<{'armhf': '0'}>
+CONFIG_HZ_PERIODIC                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_I2C                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_I2C_ALGOBIT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_I2C_ALGOPCA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ALI1535                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_ALI1563                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_ALI15X3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_AMD756                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_AMD756_S4882                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_AMD8111                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_AMD_MP2                              policy<{'amd64': 'm', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_I2C_ARB_GPIO_CHALLENGE                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_ASPEED                               policy<{'armhf': 'm'}>
+CONFIG_I2C_AXXIA                                policy<{'armhf-generic-lpae': 'm'}>
+CONFIG_I2C_BCM2835                              policy<{'arm64': 'm'}>
+CONFIG_I2C_BCM_IPROC                            policy<{'arm64': 'm'}>
+CONFIG_I2C_BOARDINFO                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_I2C_BRCMSTB                              policy<{'arm64': 'm'}>
+CONFIG_I2C_CADENCE                              policy<{'arm64': 'n'}>
+CONFIG_I2C_CBUS_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_CHT_WC                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_COMPAT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_I2C_CROS_EC_TUNNEL                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_I2C_DEBUG_ALGO                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_I2C_DEBUG_BUS                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_I2C_DEBUG_CORE                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_I2C_DEMUX_PINCTRL                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_DESIGNWARE_BAYTRAIL                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_I2C_DESIGNWARE_CORE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_I2C_DESIGNWARE_PCI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_DESIGNWARE_PLATFORM                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_I2C_DESIGNWARE_SLAVE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_I2C_DIOLAN_U2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_EG20T                                policy<{'i386': 'm'}>
+CONFIG_I2C_EMEV2                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'm', 'i386': 'n'}>
+CONFIG_I2C_EXYNOS5                              policy<{'armhf': 'm'}>
+CONFIG_I2C_FSI                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_GPIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_GPIO_FAULT_INJECTOR                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_I2C_HELPER_AUTO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_I2C_HID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_HIX5HD2                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_I801                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_IMX                                  policy<{'arm64': 'm', 'armhf-generic': 'y'}>
+CONFIG_I2C_IMX_LPI2C                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_I2C_ISCH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_ISMT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_KEMPLD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MESON                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_MLXCPLD                              policy<{'amd64': 'm'}>
+CONFIG_I2C_MPC                                  policy<{'ppc64el': 'm'}>
+CONFIG_I2C_MT65XX                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_MULTI_INSTANTIATE                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_MUX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_I2C_MUX_GPIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MUX_GPMUX                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_LTC4306                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MUX_MLXCPLD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MUX_PCA9541                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MUX_PCA954x                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MUX_PINCTRL                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_MUX_REG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_MV64XXX                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_NFORCE2                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_NFORCE2_S4985                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I2C_NOMADIK                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_NVIDIA_GPU                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_OCORES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_OMAP                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_I2C_OPAL                                 policy<{'ppc64el': 'y'}>
+CONFIG_I2C_OWL                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_PARPORT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_PARPORT_LIGHT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_PCA_ISA                              policy<{'i386': 'm'}>
+CONFIG_I2C_PCA_PLATFORM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_PIIX4                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_PXA                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_PXA_SLAVE                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_I2C_QCOM_GENI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_QUP                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_RCAR                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_RIIC                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_RK3X                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_ROBOTFUZZ_OSIF                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_S3C2410                              policy<{'armhf': 'y'}>
+CONFIG_I2C_SCMI                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_I2C_SH_MOBILE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_SI470X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SI4713                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SIMTEC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_SIS5595                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_SIS630                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_SIS96X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_SLAVE                                policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_I2C_SLAVE_EEPROM                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_SMBUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_SPRD                                 policy<{'arm64': 'y'}>
+CONFIG_I2C_STUB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_I2C_SYNQUACER                            policy<{'arm64': 'm'}>
+CONFIG_I2C_TAOS_EVM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_I2C_TEGRA_BPMP                           policy<{'armhf-generic': 'm'}>
+CONFIG_I2C_THUNDERX                             policy<{'arm64': 'm'}>
+CONFIG_I2C_TINY_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_UNIPHIER                             policy<{'armhf': 'n'}>
+CONFIG_I2C_UNIPHIER_F                           policy<{'armhf': 'n'}>
+CONFIG_I2C_VERSATILE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_I2C_VIA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_VIAPRO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_VIPERBOARD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I2C_XGENE_SLIMPRO                        policy<{'arm64': 'm'}>
+CONFIG_I2C_XILINX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I2C_XLP9XX                               policy<{'arm64': 'm'}>
+CONFIG_I3C                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I40E                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I40EVF                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_I40E_DCB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_I6300ESB_WDT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_I82092                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_I82365                                   policy<{'i386': 'm'}>
+CONFIG_I8253_LOCK                               policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_I8K                                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IA32_EMULATION                           policy<{'amd64': 'y'}>
+CONFIG_IAQCORE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IAVF                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IB700_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IBMASR                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IBMVETH                                  policy<{'ppc64el': 'm'}>
+CONFIG_IBMVIO                                   policy<{'ppc64el': 'y'}>
+CONFIG_IBMVMC                                   policy<{'ppc64el': 'm'}>
+CONFIG_IBM_ASM                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IBM_BSR                                  policy<{'ppc64el': 'm'}>
+CONFIG_IBM_PARTITION                            policy<{'s390x': 'y'}>
+CONFIG_IBM_RTL                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ICE                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ICPLUS_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ICS932S401                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ICST                                     policy<{'armhf': 'y'}>
+CONFIG_IDE                                      policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IDEAPAD_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IDLE_INJECT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IE6XX_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IEEE802154                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IEEE802154_6LOWPAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_ADF7242                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_AT86RF230                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_AT86RF230_DEBUGFS             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IEEE802154_ATUSB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_CA8210                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IEEE802154_CA8210_DEBUGFS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_IEEE802154_CC2520                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_DRIVERS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_FAKELB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_HWSIM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_MCR20A                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_MRF24J40                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IEEE802154_NL802154_EXPERIMENTAL         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IEEE802154_SOCKET                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IFB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IGB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IGBVF                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IGB_DCA                                  policy<{'amd64': 'y'}>
+CONFIG_IGB_HWMON                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IGC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IIO_ADIS_LIB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ADIS_LIB_BUFFER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IIO_BUFFER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IIO_BUFFER_CB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_BUFFER_HW_CONSUMER                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_CONFIGFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_CONSUMERS_PER_TRIGGER                policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'ppc64el': '2'}>
+CONFIG_IIO_CROS_EC_ACCEL_LEGACY                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_CROS_EC_BARO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_CROS_EC_LIGHT_PROX                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_CROS_EC_SENSORS                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_CROS_EC_SENSORS_CORE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_IIO_HRTIMER_TRIGGER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_INTERRUPT_TRIGGER                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_KFIFO_BUF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_MS_SENSORS_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_MUX                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_RESCALE                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SIMPLE_DUMMY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SSP_SENSORHUB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SSP_SENSORS_COMMONS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_ACCEL_3AXIS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_ACCEL_I2C_3AXIS                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_ACCEL_SPI_3AXIS                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_GYRO_3AXIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_GYRO_I2C_3AXIS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_GYRO_SPI_3AXIS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_LSM6DSX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_LSM6DSX_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_LSM6DSX_I3C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_LSM6DSX_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_MAGN_3AXIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_MAGN_I2C_3AXIS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_MAGN_SPI_3AXIS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_PRESS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_PRESS_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_PRESS_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_SENSORS_CORE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_SENSORS_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_ST_SENSORS_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SW_DEVICE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SW_TRIGGER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_SYSFS_TRIGGER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_TIGHTLOOP_TRIGGER                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_TRIGGER                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IIO_TRIGGERED_BUFFER                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IIO_TRIGGERED_EVENT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IKCONFIG                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IKHEADERS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ILLEGAL_POINTER_VALUE                    policy<{'amd64': '0xdead000000000000', 'arm64': '0xdead000000000000', 'i386': '0', 'ppc64el': '0x5deadbeef0000000'}>
+CONFIG_IMA_APPRAISE_BOOTPARAM                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_APPRAISE_BUILD_POLICY                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_APPRAISE_MODSIG                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_BLACKLIST_KEYRING                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_DEFAULT_HASH                         policy<{'amd64': '"sha1"', 'arm64': '"sha1"', 'armhf': '"sha1"', 'i386': '"sha1"', 'ppc64el': '"sha256"', 's390x': '"sha1"'}>
+CONFIG_IMA_DEFAULT_HASH_SHA1                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_IMA_DEFAULT_HASH_SHA512                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_DEFAULT_TEMPLATE                     policy<{'amd64': '"ima-ng"', 'arm64': '"ima-ng"', 'armhf': '"ima-ng"', 'i386': '"ima-ng"', 'ppc64el': '"ima-sig"', 's390x': '"ima-ng"'}>
+CONFIG_IMA_LOAD_X509                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IMA_LSM_RULES                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IMA_MEASURE_PCR_IDX                      policy<{'amd64': '10', 'arm64': '10', 'armhf': '10', 'i386': '10', 'ppc64el': '10', 's390x': '10'}>
+CONFIG_IMA_NG_TEMPLATE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_IMG_ASCII_LCD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IMX2_WDT                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX7D_ADC                                policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX7ULP_WDT                              policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_DMA                                  policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_DSP                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_GPCV2                                policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_GPCV2_PM_DOMAINS                     policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_IPUV3_CORE                           policy<{'armhf': 'm'}>
+CONFIG_IMX_IRQSTEER                             policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_MBOX                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_REMOTEPROC                           policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_SCU                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_SCU_PD                               policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_SCU_SOC                              policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_IMX_SC_WDT                               policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_SDMA                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_THERMAL                              policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_IMX_WEIM                                 policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_INA2XX_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INDIRECT_PIO                             policy<{'arm64': 'y'}>
+CONFIG_INET                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INET6_AH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_ESP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_ESP_OFFLOAD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_IPCOMP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_TUNNEL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET6_XFRM_TUNNEL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_AH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_DCCP_DIAG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_DIAG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_DIAG_DESTROY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INET_ESP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_ESP_OFFLOAD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_IPCOMP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_RAW_DIAG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_SCTP_DIAG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_TABLE_PERTURB_ORDER                 policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'ppc64el': '16', 's390x': '16'}>
+CONFIG_INET_TCP_DIAG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_TUNNEL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_UDP_DIAG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INET_XFRM_TUNNEL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_ADDR_TRANS                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_BNXT_RE                       policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INFINIBAND_CXGB3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_CXGB4                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_EFA                           policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_EXP_LEGACY_VERBS_NEW_UAPI     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INFINIBAND_HFI1                          policy<{'amd64': 'm'}>
+CONFIG_INFINIBAND_HNS                           policy<{'arm64': 'm'}>
+CONFIG_INFINIBAND_HNS_HIP06                     policy<{'arm64': 'y'}>
+CONFIG_INFINIBAND_HNS_HIP08                     policy<{'arm64': 'y'}>
+CONFIG_INFINIBAND_I40IW                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_IPOIB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_IPOIB_CM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_IPOIB_DEBUG                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INFINIBAND_ISER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_ISERT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_MTHCA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_MTHCA_DEBUG                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INFINIBAND_OCRDMA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INFINIBAND_ON_DEMAND_PAGING              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_OPA_VNIC                      policy<{'amd64': 'm'}>
+CONFIG_INFINIBAND_QEDR                          policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_INFINIBAND_QIB                           policy<{'amd64': 'm'}>
+CONFIG_INFINIBAND_QIB_DCA                       policy<{'amd64': 'y'}>
+CONFIG_INFINIBAND_RDMAVT                        policy<{'amd64': 'm'}>
+CONFIG_INFINIBAND_SRP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_SRPT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_USER_ACCESS                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_USER_MAD                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INFINIBAND_USER_MEM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_USNIC                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INFINIBAND_VIRT_DMA                      policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INFINIBAND_VMWARE_PVRDMA                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_INFTL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INITRAMFS_SOURCE                         policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_INIT_ENV_ARG_LIMIT                       policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32', 's390x': '32'}>
+CONFIG_INIT_ON_ALLOC_DEFAULT_ON                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INIT_ON_FREE_DEFAULT_ON                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INIT_STACK_NONE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_LOCK                         policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_LOCK_BH                      policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_LOCK_IRQ                     policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_LOCK_IRQSAVE                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_TRYLOCK                      policy<{'s390x': 'y'}>
+CONFIG_INLINE_READ_UNLOCK                       policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_UNLOCK_BH                    policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_UNLOCK_IRQ                   policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_READ_UNLOCK_IRQRESTORE            policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_LOCK                         policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_LOCK_BH                      policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_LOCK_IRQ                     policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_LOCK_IRQSAVE                 policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_TRYLOCK                      policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_TRYLOCK_BH                   policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_UNLOCK_BH                    policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_UNLOCK_IRQ                   policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE            policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_LOCK                        policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_LOCK_BH                     policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_LOCK_IRQ                    policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_LOCK_IRQSAVE                policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_TRYLOCK                     policy<{'s390x': 'y'}>
+CONFIG_INLINE_WRITE_UNLOCK                      policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_UNLOCK_BH                   policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_UNLOCK_IRQ                  policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE           policy<{'arm64': 'y', 's390x': 'y'}>
+CONFIG_INOTIFY_USER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INPUT                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INPUT_88PM80X_ONKEY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_88PM860X_ONKEY                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AD714X_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ADXL34X_SPI                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_APANEL                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_ARIZONA_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ATI_REMOTE2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_ATLAS_BTNS                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_ATMEL_CAPTOUCH                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_AXP20X_PEK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_BMA150                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CM109                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CMA3000                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CMA3000_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_CPCAP_PWRBUTTON                    policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9052_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9055_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DA9063_ONKEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV260X_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV2665_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_DRV2667_HAPTICS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_E3X0_BUTTON                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_EVBUG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_EVDEV                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INPUT_FF_MEMLESS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_GP2A                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_BEEPER                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_DECODER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_ROTARY_ENCODER                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_GPIO_VIBRA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_HISI_POWERKEY                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INPUT_IDEAPAD_SLIDEBAR                   policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_IMS_PCU                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_JOYDEV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_JOYSTICK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_KEYBOARD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_KEYSPAN_REMOTE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_KXTJ9                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_KXTJ9_POLLED_MODE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_INPUT_LEDS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MATRIXKMAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_MAX77650_ONKEY                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MAX77693_HAPTIC                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MAX8925_ONKEY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MAX8997_HAPTIC                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MC13783_PWRBUTTON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MISC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_MMA8450                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_MOUSE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_MOUSEDEV                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_MOUSEDEV_PSAUX                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_INPUT_MOUSEDEV_SCREEN_X                  policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'ppc64el': '1024'}>
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y                  policy<{'amd64': '768', 'arm64': '768', 'armhf': '768', 'i386': '768', 'ppc64el': '768'}>
+CONFIG_INPUT_MSM_VIBRATOR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PALMAS_PWRBUTTON                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCAP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCF50633_PMU                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCF8574                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PCSPKR                             policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PM8941_PWRKEY                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INPUT_PM8XXX_VIBRATOR                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INPUT_PMIC8XXX_PWRKEY                    policy<{'armhf': 'm'}>
+CONFIG_INPUT_POLLDEV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_POWERMATE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PWM_BEEPER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_PWM_VIBRA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_RAVE_SP_PWRBUTTON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_REGULATOR_HAPTIC                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_RETU_PWRBUTTON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_RK805_PWRKEY                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_SC27XX_VIBRA                       policy<{'arm64': 'm'}>
+CONFIG_INPUT_SOC_BUTTON_ARRAY                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_SPARSEKMAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INPUT_STPMIC1_ONKEY                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TABLET                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_TOUCHSCREEN                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_INPUT_TPS65218_PWRBUTTON                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL4030_PWRBUTTON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL4030_VIBRA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_TWL6040_VIBRA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_WISTRON_BTNS                       policy<{'i386': 'm'}>
+CONFIG_INPUT_WM831X_ON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_INPUT_YEALINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INSTRUCTION_DECODER                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INT3406_THERMAL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INT340X_THERMAL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEGRITY                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_AUDIT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_SIGNATURE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEGRITY_TRUSTED_KEYRING                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTEL_ATOMISP2_PM                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_BXTWC_PMIC_TMU                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_BXT_PMIC_THERMAL                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_CHTDC_TI_PWRBTN                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_CHT_INT33FE                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_GTT                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_HID_EVENT                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_IDLE                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IDMA64                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INTEL_INT0002_VGPIO                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_IOATDMA                            policy<{'amd64': 'm'}>
+CONFIG_INTEL_IOMMU                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IOMMU_FLOPPY_WA                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_IOMMU_SVM                          policy<{'amd64': 'y', 'i386': '-'}>
+CONFIG_INTEL_IPS                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER            policy<{'amd64': 'm'}>
+CONFIG_INTEL_ISH_HID                            policy<{'amd64': 'm'}>
+CONFIG_INTEL_MEI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_HDCP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_ME                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_TXE                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MEI_WDT                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MENLOW                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_MFLD_THERMAL                       policy<{'i386': 'm'}>
+CONFIG_INTEL_MIC_BUS                            policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_CARD                           policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_HOST                           policy<{'amd64': 'm'}>
+CONFIG_INTEL_MIC_X100_DMA                       policy<{'amd64': 'm'}>
+CONFIG_INTEL_MID_POWER_BUTTON                   policy<{'i386': 'm'}>
+CONFIG_INTEL_MID_PTI                            policy<{'i386': 'm'}>
+CONFIG_INTEL_MID_WATCHDOG                       policy<{'i386': 'm'}>
+CONFIG_INTEL_MRFLD_PWRBTN                       policy<{'i386': 'm'}>
+CONFIG_INTEL_OAKTRAIL                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PCH_THERMAL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PMC_CORE                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_PMC_IPC                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_POWERCLAMP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_PUNIT_IPC                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_RAPL                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_RAPL_CORE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_RST                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SCU_IPC                            policy<{'i386': 'y'}>
+CONFIG_INTEL_SCU_IPC_UTIL                       policy<{'i386': 'm'}>
+CONFIG_INTEL_SCU_WATCHDOG                       policy<{'i386': 'y'}>
+CONFIG_INTEL_SMARTCONNECT                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_DTS_IOSF_CORE                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_DTS_THERMAL                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_PMIC                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_SOC_PMIC_BXTWC                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_PMIC_CHTDC_TI                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_SOC_PMIC_CHTWC                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_SOC_PMIC_MRFLD                     policy<{'i386': 'm'}>
+CONFIG_INTEL_SPEED_SELECT_INTERFACE             policy<{'amd64': 'm'}>
+CONFIG_INTEL_STRATIX10_RSU                      policy<{'arm64': 'm'}>
+CONFIG_INTEL_STRATIX10_SERVICE                  policy<{'arm64': 'm'}>
+CONFIG_INTEL_TELEMETRY                          policy<{'amd64': 'm'}>
+CONFIG_INTEL_TH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_ACPI                            policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_TH_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INTEL_TH_GTH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_MSU                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_PTI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TH_STH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTEL_TURBO_MAX_3                        policy<{'amd64': 'y'}>
+CONFIG_INTEL_TXT                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_INTEL_VBTN                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_WMI_THUNDERBOLT                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_INTEL_XWAY_PHY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_INTERCONNECT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_INTERCONNECT_QCOM                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_INTERCONNECT_QCOM_QCS404                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INTERCONNECT_QCOM_SDM845                 policy<{'arm64': 'm'}>
+CONFIG_INTERCONNECT_QCOM_SMD_RPM                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_INTERVAL_TREE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_INTERVAL_TREE_TEST                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_INV_MPU6050_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INV_MPU6050_IIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_INV_MPU6050_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IOMMU_API                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IOMMU_DEBUG                              policy<{'amd64': 'n'}>
+CONFIG_IOMMU_DEFAULT_PASSTHROUGH                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IOMMU_DMA                                policy<{'arm64': 'y'}>
+CONFIG_IOMMU_HELPER                             policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IOMMU_IOVA                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic': 'm', 'i386': 'y'}>
+CONFIG_IOMMU_IO_PGTABLE                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IOMMU_IO_PGTABLE_ARMV7S                  policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IOMMU_IO_PGTABLE_LPAE                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_IOMMU_SUPPORT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ION                                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IONIC                                    policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_IOSCHED_BFQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IOSF_MBI                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IOSF_MBI_DEBUG                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IO_DELAY_0X80                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IO_DELAY_0XED                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_IO_DELAY_NONE                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IO_DELAY_UDELAY                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_IO_EVENT_IRQ                             policy<{'ppc64el': 'y'}>
+CONFIG_IO_STRICT_DEVMEM                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IO_URING                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP6_NF_FILTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_IPTABLES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MANGLE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_AH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_EUI64                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_FRAG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_HL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_IPV6HEADER                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_MH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_OPTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_RPFILTER                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_RT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_MATCH_SRH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_NAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_RAW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_SECURITY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_HL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_MASQUERADE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_NPT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_REJECT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP6_NF_TARGET_SYNPROXY                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPACK_BUS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IPC_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPMB_DEVICE_INTERFACE                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPMI_DEVICE_INTERFACE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_DMI_DECODE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_IPMI_HANDLER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_IPMI_KCS_BMC                             policy<{'armhf': 'm'}>
+CONFIG_IPMI_PANIC_EVENT                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IPMI_PLAT_DATA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPMI_POWERNV                             policy<{'ppc64el': 'm'}>
+CONFIG_IPMI_POWEROFF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_SI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_SSIF                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPMI_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPQ_GCC_4019                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPQ_GCC_806X                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPQ_GCC_8074                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPQ_LCC_806X                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IPV6_FOU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_FOU_TUNNEL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_GRE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_ILA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_MIP6                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_MROUTE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_MULTIPLE_TABLES                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_NDISC_NODETYPE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_OPTIMISTIC_DAD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IPV6_PIMSM_V2                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_ROUTER_PREF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_ROUTE_INFO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SEG6_BPF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SEG6_HMAC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SEG6_LWTUNNEL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SIT                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_SIT_6RD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_SUBTREES                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPV6_TUNNEL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPV6_VTI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPVLAN                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPVLAN_L3S                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IPVTAP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IPW2100                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPW2100_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IPW2100_MONITOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IPW2200_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IPW2200_MONITOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_PROMISCUOUS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_QOS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPW2200_RADIOTAP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IPWIRELESS                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IP_ADVANCED_ROUTER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_DCCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_DCCP_CCID2_DEBUG                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_DCCP_CCID3                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_IP_DCCP_CCID3_DEBUG                      policy<{'s390x': 'n'}>
+CONFIG_IP_DCCP_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_DCCP_TFRC_LIB                         policy<{'s390x': 'y'}>
+CONFIG_IP_FIB_TRIE_STATS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MROUTE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MROUTE_COMMON                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MROUTE_MULTIPLE_TABLES                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MULTICAST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_MULTIPLE_TABLES                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_NF_ARPFILTER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_ARPTABLES                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_ARP_MANGLE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_FILTER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_IPTABLES                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MANGLE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_AH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_ECN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_RPFILTER                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_MATCH_TTL                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_NAT                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_RAW                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_SECURITY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_CLUSTERIP                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_ECN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_MASQUERADE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_NETMAP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_REDIRECT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_REJECT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_SYNPROXY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_NF_TARGET_TTL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_PIMSM_V1                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_PIMSM_V2                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_ROUTE_CLASSID                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_ROUTE_MULTIPATH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_ROUTE_VERBOSE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_SCTP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_BITMAP_IP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_BITMAP_IPMAC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_BITMAP_PORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPMAC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPMARK                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORTIP                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_IPPORTNET                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_MAC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETIFACE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETNET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETPORT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_HASH_NETPORTNET                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_LIST_SET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_SET_MAX                               policy<{'amd64': '256', 'arm64': '256', 'armhf': '256', 'i386': '256', 'ppc64el': '256', 's390x': '256'}>
+CONFIG_IP_VS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IP_VS_DH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_FO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_FTP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_IPV6                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_LBLC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_LBLCR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_LC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_MH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_MH_TAB_INDEX                       policy<{'amd64': '12', 'arm64': '12', 'armhf': '12', 'i386': '12', 'ppc64el': '12', 's390x': '12'}>
+CONFIG_IP_VS_NFCT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_NQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_OVF                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_PE_SIP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_PROTO_AH                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_AH_ESP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_ESP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_SCTP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_TCP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_PROTO_UDP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IP_VS_RR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SED                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_SH_TAB_BITS                        policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8', 's390x': '8'}>
+CONFIG_IP_VS_TAB_BITS                           policy<{'amd64': '12', 'arm64': '12', 'armhf': '12', 'i386': '12', 'ppc64el': '12', 's390x': '12'}>
+CONFIG_IP_VS_WLC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IP_VS_WRR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IRQCHIP                                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_IRQSOFF_TRACER                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_IRQ_ALL_CPUS                             policy<{'ppc64el': 'y'}>
+CONFIG_IRQ_BYPASS_MANAGER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic': 'm', 'armhf-generic-lpae': 'y', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_IRQ_CROSSBAR                             policy<{'armhf': 'y'}>
+CONFIG_IRQ_DOMAIN                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IRQ_DOMAIN_HIERARCHY                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS           policy<{'arm64': 'y'}>
+CONFIG_IRQ_FORCED_THREADING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IRQ_FORCED_THREADING_DEFAULT             policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'ppc64el': 'n'}>
+CONFIG_IRQ_MSI_IOMMU                            policy<{'arm64': 'y'}>
+CONFIG_IRQ_POLL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IRQ_REMAP                                policy<{'amd64': 'y'}>
+CONFIG_IRQ_TIME_ACCOUNTING                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IRQ_UNIPHIER_AIDET                       policy<{'armhf': 'y'}>
+CONFIG_IRQ_WORK                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_IR_ENE                                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_FINTEK                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_GPIO_CIR                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_GPIO_TX                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_HIX5HD2                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IGORPLUGUSB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IGUANA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IMON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IMON_DECODER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_IMON_RAW                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_ITE_CIR                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_JVC_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_MCEUSB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_MCE_KBD_DECODER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_MESON                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IR_MTK                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_IR_NEC_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_NUVOTON                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_IR_PWM_TX                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RC5_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RC6_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RCMM_DECODER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_REDRAT3                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_RX51                                  policy<{'armhf': 'm'}>
+CONFIG_IR_SANYO_DECODER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SERIAL                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SERIAL_TRANSMITTER                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IR_SHARP_DECODER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SIR                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SONY_DECODER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SPI                                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_STREAMZAP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_SUNXI                                 policy<{'arm64': 'm'}>
+CONFIG_IR_TTUSBIR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IR_WINBOND_CIR                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IR_XMP_DECODER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISA                                      policy<{'i386': 'y'}>
+CONFIG_ISAPNP                                   policy<{'i386': 'y'}>
+CONFIG_ISA_BUS                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ISA_BUS_API                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ISA_DMA_API                              policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ISCSI_BOOT_SYSFS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ISCSI_IBFT                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_ISCSI_IBFT_FIND                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ISCSI_TARGET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ISCSI_TARGET_CXGB4                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISCSI_TCP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ISDN                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_CAPI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_CAPI_CAPI20                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_CAPI_MIDDLEWARE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DRV_AVMB1_AVM_CS                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1ISA                     policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ISDN_DRV_AVMB1_B1PCMCIA                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_C4                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_T1ISA                     policy<{'i386': 'm'}>
+CONFIG_ISDN_DRV_AVMB1_T1PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISDN_DRV_GIGASET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISI                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISL29003                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ISL29020                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ISL29125                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISL29501                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ISO9660_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_IT8712F_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_IT87_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ITCO_VENDOR_SUPPORT                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_ITCO_WDT                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ITG3200                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IUCV                                     policy<{'s390x': 'y'}>
+CONFIG_IWL3945                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWL4965                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLDVM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLEGACY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLEGACY_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLEGACY_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IWLMVM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLWIFI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IWLWIFI_BCAST_FILTERING                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLWIFI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_IWLWIFI_DEBUGFS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IWLWIFI_DEVICE_TRACING                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IWLWIFI_LEDS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IWLWIFI_OPMODE_MODULAR                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IWMMXT                                   policy<{'armhf': 'y'}>
+CONFIG_IXGB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGBE                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGBEVF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_IXGBEVF_IPSEC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IXGBE_DCA                                policy<{'amd64': 'y'}>
+CONFIG_IXGBE_DCB                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IXGBE_HWMON                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_IXGBE_IPSEC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JAILHOUSE_GUEST                          policy<{'amd64': 'y'}>
+CONFIG_JBD2                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_JBD2_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_JFFS2_CMODE_FAVOURLZO                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_CMODE_NONE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_CMODE_PRIORITY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_CMODE_SIZE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_COMPRESSION_OPTIONS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JFFS2_FS_DEBUG                           policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_JFFS2_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_SECURITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_WBUF_VERIFY                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_FS_WRITEBUFFER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_FS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_LZO                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_RTIME                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFFS2_RUBIN                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_SUMMARY                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFFS2_ZLIB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_JFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_JFS_POSIX_ACL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFS_SECURITY                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JFS_STATISTICS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JME                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_JOLIET                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_JOYSTICK_A3D                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_ADI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_ANALOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_AS5011                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_COBRA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_DB9                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_FSIA6B                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GAMECON                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GF2K                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GRIP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GRIP_MP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_GUILLEMOT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_IFORCE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_IFORCE_232                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_IFORCE_USB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_INTERACT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_JOYDUMP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_MAGELLAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_PSXPAD_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_PSXPAD_SPI_FF                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_PXRC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SIDEWINDER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SPACEBALL                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_SPACEORB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_STINGER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TMDC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TURBOGRAFX                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_TWIDJOY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_WALKERA0701                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_WARRIOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_XPAD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JOYSTICK_XPAD_FF                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_XPAD_LEDS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_JOYSTICK_ZHENHUA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JSA1212                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_JUMP_LABEL                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_JUMP_LABEL_FEATURE_CHECKS                policy<{'ppc64el': 'y'}>
+CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG           policy<{'ppc64el': 'n'}>
+CONFIG_K3_DMA                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_KALLSYMS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KALLSYMS_ABSOLUTE_PERCPU                 policy<{'amd64': 'y'}>
+CONFIG_KALLSYMS_ALL                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KALLSYMS_BASE_RELATIVE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KARMA_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KASAN                                    policy<{'amd64': 'n', 'arm64': 'n', 's390x': 'n'}>
+CONFIG_KASAN_STACK                              policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_KCOV                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_KDB_CONTINUE_CATASTROPHIC                policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_KDB_DEFAULT_ENABLE                       policy<{'amd64': '0x1', 'arm64': '0x1', 'armhf': '0x1', 'i386': '0x1', 'ppc64el': '0x1'}>
+CONFIG_KDB_KEYBOARD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KEMPLD_WDT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KERNEL_BZIP2                             policy<{'amd64': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_GZIP                              policy<{'amd64': 'n', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KERNEL_LZ4                               policy<{'amd64': 'y', 'armhf': 'n', 'i386': 'y', 's390x': 'y'}>
+CONFIG_KERNEL_LZMA                              policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_LZO                               policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_KERNEL_MODE_NEON                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_KERNEL_NOBP                              policy<{'s390x': 'n'}>
+CONFIG_KERNEL_START                             policy<{'ppc64el': '0xc000000000000000'}>
+CONFIG_KERNEL_UNCOMPRESSED                      policy<{'s390x': 'n'}>
+CONFIG_KERNEL_XZ                                policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_KERNFS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEXEC                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEXEC_CORE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEXEC_ELF                                policy<{'ppc64el': 'y'}>
+CONFIG_KEXEC_FILE                               policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_KEXEC_IMAGE_VERIFY_SIG                   policy<{'arm64': 'n'}>
+CONFIG_KEXEC_JUMP                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KEXEC_SIG                                policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_KEXEC_SIG_FORCE                          policy<{'amd64': 'n'}>
+CONFIG_KEYBOARD_ADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ADP5520                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ADP5588                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_ADP5589                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_APPLESPI                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KEYBOARD_ATKBD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KEYBOARD_BCM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_KEYBOARD_CAP11XX                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_CROS_EC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_KEYBOARD_DLINK_DIR685                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_GPIO_POLLED                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_IMX                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_LKKBD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_LM8323                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_LM8333                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MATRIX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MAX7359                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MCS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MPR121                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_MTK_PMIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_NEWTON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_NVEC                            policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_OMAP4                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_OPENCORES                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_PMIC8XXX                        policy<{'armhf': 'm'}>
+CONFIG_KEYBOARD_QT1050                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_QT1070                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_QT2160                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_SAMSUNG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_KEYBOARD_SNVS_PWRKEY                     policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_STMPE                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_STOWAWAY                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_SUN4I_LRADC                     policy<{'arm64': 'n'}>
+CONFIG_KEYBOARD_SUNKBD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TC3589X                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TCA6416                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TCA8418                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_KEYBOARD_TM2_TOUCHKEY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_TWL4030                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYBOARD_XTKBD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KEYS                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEYS_COMPAT                              policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEYS_REQUEST_CACHE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KEY_DH_OPERATIONS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KGDB                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KGDB_KDB                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KGDB_LOW_LEVEL_TRAP                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KGDB_TESTS                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_KMSG_IDS                                 policy<{'s390x': 'y'}>
+CONFIG_KMX61                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KPC2000                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KPC2000_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KPC2000_DMA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KPC2000_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KPC2000_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KPROBES                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KPROBES_ON_FTRACE                        policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KPROBES_SANITY_TEST                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_KPROBE_EVENTS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KPROBE_EVENTS_ON_NOTRACE                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_KPSS_XCC                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_KRAITCC                                  policy<{'armhf': 'm'}>
+CONFIG_KRAIT_CLOCKS                             policy<{'armhf': 'y'}>
+CONFIG_KRAIT_L2_ACCESSORS                       policy<{'armhf': 'y'}>
+CONFIG_KRETPROBES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KS0108                                   policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KS0108_DELAY                             policy<{'amd64': '2', 'armhf': '2', 'i386': '2', 'ppc64el': '2'}>
+CONFIG_KS0108_PORT                              policy<{'amd64': '0x378', 'armhf': '0x378', 'i386': '0x378', 'ppc64el': '0x378'}>
+CONFIG_KS7010                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KS8842                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KS8851                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KS8851_MLL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KSM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KSZ884X_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KUSER_HELPERS                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_KVM_AMD                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KVM_AMD_SEV                              policy<{'amd64': 'y'}>
+CONFIG_KVM_ARM_HOST                             policy<{'arm64': 'y', 'armhf-generic-lpae': 'y'}>
+CONFIG_KVM_ARM_PMU                              policy<{'arm64': 'y'}>
+CONFIG_KVM_ASYNC_PF                             policy<{'amd64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_KVM_ASYNC_PF_SYNC                        policy<{'s390x': 'y'}>
+CONFIG_KVM_BOOK3S_64                            policy<{'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_64_HANDLER                    policy<{'ppc64el': 'y'}>
+CONFIG_KVM_BOOK3S_64_HV                         policy<{'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_64_PR                         policy<{'ppc64el': 'm'}>
+CONFIG_KVM_BOOK3S_HANDLER                       policy<{'ppc64el': 'y'}>
+CONFIG_KVM_BOOK3S_HV_EXIT_TIMING                policy<{'ppc64el': 'n'}>
+CONFIG_KVM_BOOK3S_HV_POSSIBLE                   policy<{'ppc64el': 'y'}>
+CONFIG_KVM_BOOK3S_PR_POSSIBLE                   policy<{'ppc64el': 'y'}>
+CONFIG_KVM_COMPAT                               policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_KVM_DEBUG_FS                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT        policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y'}>
+CONFIG_KVM_GUEST                                policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KVM_INDIRECT_VECTORS                     policy<{'arm64': 'y'}>
+CONFIG_KVM_INTEL                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_KVM_MMIO                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_KVM_MMU_AUDIT                            policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_KVM_S390_UCONTROL                        policy<{'s390x': 'n'}>
+CONFIG_KVM_VFIO                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_KVM_XICS                                 policy<{'ppc64el': 'y'}>
+CONFIG_KVM_XIVE                                 policy<{'ppc64el': 'y'}>
+CONFIG_KXCJK1013                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KXSD9                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KXSD9_I2C                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_KXSD9_SPI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_L2TP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_DEBUGFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_ETH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_IP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_L2TP_V3                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LAN743X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LANCE                                    policy<{'i386': 'm'}>
+CONFIG_LANMEDIA                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LAPB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LAPBETHER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LATTICE_ECP3_CONFIG                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_AMS369FG06                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_CLASS_DEVICE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LCD_HX8357                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_ILI922X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_ILI9320                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_L4F00242T03                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LMS283GF05                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LMS501KF03                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_LTV350QV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_OTM3225A                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_PLATFORM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_TDO24M                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCD_VGG2432A4                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LCS                                      policy<{'s390x': 'm'}>
+CONFIG_LDISC_AUTOLOAD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LDM_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LDM_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_LD_DEAD_CODE_DATA_ELIMINATION            policy<{'ppc64el': 'n'}>
+CONFIG_LD_HEAD_STUB_CATCH                       policy<{'ppc64el': 'n'}>
+CONFIG_LEDS_88PM860X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_AAT1290                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_ADP5520                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_AN30259A                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_APU                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_AS3645A                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_ASIC3                               policy<{'armhf': 'y'}>
+CONFIG_LEDS_BCM6328                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BCM6358                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BD2802                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BLINKM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_CLASS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_CLASS_FLASH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_CLEVO_MAIL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_CPCAP                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_CR0014114                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DA903X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DA9052                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_DAC124S085                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_GPIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_INTEL_SS4200                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_IS31FL319X                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_IS31FL32XX                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_KTD2692                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3530                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3532                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3533                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM355x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3601X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM36274                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3642                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3692X                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LM3697                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP3944                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP3952                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5521                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5523                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP5562                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP55XX_COMMON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8501                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8788                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LP8860                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_LT3593                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MAX77650                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MAX77693                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MAX8997                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MC13783                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MENF21BMC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MLXCPLD                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_MLXREG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_MT6323                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_NET48XX                             policy<{'i386': 'm'}>
+CONFIG_LEDS_NIC78BX                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LEDS_NS2                                 policy<{'armhf': 'm'}>
+CONFIG_LEDS_OT200                               policy<{'i386': 'm'}>
+CONFIG_LEDS_PCA9532                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PCA9532_GPIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_PCA955X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PCA955X_GPIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_PCA963X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_PM8058                              policy<{'armhf': 'm'}>
+CONFIG_LEDS_POWERNV                             policy<{'ppc64el': 'm'}>
+CONFIG_LEDS_PWM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_REGULATOR                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_SC27XX_BLTC                         policy<{'arm64': 'm'}>
+CONFIG_LEDS_SPI_BYTE                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_SYSCON                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TCA6507                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TI_LMU_COMMON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TLC591XX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGERS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_ACTIVITY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_AUDIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_BACKLIGHT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_CAMERA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_CPU                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_DEFAULT_ON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_DISK                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_GPIO                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_HEARTBEAT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_MTD                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_NETDEV                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_ONESHOT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_PANIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEDS_TRIGGER_PATTERN                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_TIMER                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_TRIGGER_TRANSIENT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_USER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_WM831X_STATUS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_WM8350                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LEDS_WRAP                                policy<{'i386': 'm'}>
+CONFIG_LED_TRIGGER_PHY                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LEGACY_PTYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LEGACY_PTY_COUNT                         policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_LEGACY_VSYSCALL_EMULATE                  policy<{'amd64': 'n'}>
+CONFIG_LEGACY_VSYSCALL_NONE                     policy<{'amd64': 'n'}>
+CONFIG_LEGACY_VSYSCALL_XONLY                    policy<{'amd64': 'y'}>
+CONFIG_LG_LAPTOP                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LIB80211                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIB80211_CRYPT_CCMP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIB80211_CRYPT_TKIP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIB80211_CRYPT_WEP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIB80211_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBCRC32C                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LIBERTAS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_CS                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LIBERTAS_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBERTAS_MESH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LIBERTAS_SDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_SPI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_THINFIRM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_THINFIRM_DEBUG                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBERTAS_THINFIRM_USB                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBERTAS_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBFC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LIBFCOE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LIBFDT                                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_LIBIPW                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIBIPW_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LIBNVDIMM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_LIDAR_LITE_V2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LIQUIDIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_LIQUIDIO_VF                              policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_LIRC                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LIVEPATCH                                policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LKDTM                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LLC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LLC2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LMP91000                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LOAD_IPL_KEYS                            policy<{'s390x': 'y'}>
+CONFIG_LOAD_UEFI_KEYS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_LOCALVERSION                             policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_LOCKD                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LOCKDEP_SUPPORT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCKD_V4                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCKUP_DETECTOR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LOCK_DEBUGGING_SUPPORT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCK_DOWN_IN_SECURE_BOOT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCK_EVENT_COUNTS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_SPIN_ON_OWNER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LOCK_STAT                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOCK_TORTURE_TEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOGIG940_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGIRUMBLEPAD2_FF                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGITECH_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGIWHEELS_FF                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_LOGO                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_LOG_BUF_SHIFT                            policy<{'amd64': '18', 'arm64': '18', 'armhf': '17', 'i386': '17', 'ppc64el': '18', 's390x': '18'}>
+CONFIG_LOG_CPU_MAX_BUF_SHIFT                    policy<{'amd64': '12', 'arm64': '12', 'armhf': '12', 'i386': '12', 'ppc64el': '12', 's390x': '12'}>
+CONFIG_LOOPBACK_TARGET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LP8788_ADC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LPARCFG                                  policy<{'ppc64el': 'y'}>
+CONFIG_LPC_ICH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LPC_SCH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_LP_CONSOLE                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_LRU_CACHE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LSI_ET1011C_PHY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LSM                                      policy<{'amd64': '"lockdown,yama,integrity,apparmor"', 'arm64': '"lockdown,yama,integrity,apparmor"', 'armhf': '"lockdown,yama,integrity,apparmor"', 'i386': '"lockdown,yama,integrity,apparmor"', 'ppc64el': '"lockdown,yama,integrity,apparmor"', 's390x': '"lockdown,yama,integrity,apparmor"'}>
+CONFIG_LSM_MMAP_MIN_ADDR                        policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_LS_SCFG_MSI                              policy<{'arm64': 'y'}>
+CONFIG_LTC1660                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTC2471                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTC2485                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTC2497                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTC2632                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTE_GDM724X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LTPC                                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_LTR501                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LV0104CS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_LWTUNNEL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LWTUNNEL_BPF                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LXT_PHY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LZ4HC_COMPRESS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LZ4_COMPRESS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_LZ4_DECOMPRESS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LZO_COMPRESS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_LZO_DECOMPRESS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_M486                                     policy<{'i386': 'n'}>
+CONFIG_M586                                     policy<{'i386': 'n'}>
+CONFIG_M586MMX                                  policy<{'i386': 'n'}>
+CONFIG_M586TSC                                  policy<{'i386': 'n'}>
+CONFIG_M62332                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_M686                                     policy<{'i386': 'y'}>
+CONFIG_MAC80211                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC80211_DEBUGFS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_DEBUG_MENU                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MAC80211_HAS_RC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_HWSIM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC80211_LEDS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_MESH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_MESSAGE_TRACING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_RC_DEFAULT                      policy<{'amd64': '"minstrel_ht"', 'arm64': '"minstrel_ht"', 'armhf': '"minstrel_ht"', 'i386': '"minstrel_ht"', 'ppc64el': '"minstrel_ht"'}>
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_RC_MINSTREL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MAC80211_STA_HASH_MAX_SIZE               policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_MAC802154                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MACB                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MACB_PCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MACB_USE_HWSTAMP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_MACHZ_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+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_ARTPEC6                             policy<{'armhf': 'n'}>
+CONFIG_MACH_ASPEED_G6                           policy<{'armhf': 'y'}>
+CONFIG_MACH_BERLIN_BG2                          policy<{'armhf': 'y'}>
+CONFIG_MACH_BERLIN_BG2CD                        policy<{'armhf': 'y'}>
+CONFIG_MACH_BERLIN_BG2Q                         policy<{'armhf': 'y'}>
+CONFIG_MACH_DOVE                                policy<{'armhf': 'y'}>
+CONFIG_MACH_MESON6                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MESON8                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT2701                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT6589                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT6592                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT7623                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT7629                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT8127                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MT8135                              policy<{'armhf': 'y'}>
+CONFIG_MACH_MVEBU_ANY                           policy<{'armhf': 'y'}>
+CONFIG_MACH_MVEBU_V7                            policy<{'armhf': 'y'}>
+CONFIG_MACH_OMAP3517EVM                         policy<{'armhf-generic': 'n'}>
+CONFIG_MACH_OMAP3_PANDORA                       policy<{'armhf-generic': 'y'}>
+CONFIG_MACH_OMAP_GENERIC                        policy<{'armhf': 'y'}>
+CONFIG_MACINTOSH_DRIVERS                        policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MACSEC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MACVLAN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MACVTAP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MAC_EMUMOUSEBTN                          policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAC_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MADERA_IRQ                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAG3110                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAGIC_SYSRQ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE               policy<{'amd64': '0x01b6', 'arm64': '0x01b6', 'armhf': '0x01b6', 'i386': '0x01b6', 'ppc64el': '0x01b6', 's390x': '0x01b6'}>
+CONFIG_MAGIC_SYSRQ_SERIAL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MAILBOX                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MAILBOX_TEST                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MANAGER_SBS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MANDATORY_FILE_LOCKING                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MANTIS_CORE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MARCH_Z10                                policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z13                                policy<{'s390x': 'y'}>
+CONFIG_MARCH_Z14                                policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z15                                policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z15_TUNE                           policy<{'s390x': 'y'}>
+CONFIG_MARCH_Z196                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z900                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z990                               policy<{'s390x': 'n'}>
+CONFIG_MARCH_Z9_109                             policy<{'s390x': 'n'}>
+CONFIG_MARCH_ZEC12                              policy<{'s390x': 'n'}>
+CONFIG_MARVELL_10G_PHY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MARVELL_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MATH_EMULATION                           policy<{'i386': 'n'}>
+CONFIG_MATOM                                    policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MAX1027                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX11100                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX1118                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX1363                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX30100                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX30102                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX31856                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX44000                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX44009                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX517                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX5432                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX5481                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX5487                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX5821                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX63XX_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MAX77620_THERMAL                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX77620_WATCHDOG                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX8925_POWER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAX9611                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAXIM_THERMOCOUPLE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MAXSMP                                   policy<{'amd64': 'y'}>
+CONFIG_MAX_PHYSMEM_BITS                         policy<{'s390x': '46'}>
+CONFIG_MAX_RAW_DEVS                             policy<{'amd64': '256', 'arm64': '256', 'armhf': '256', 'i386': '256', 'ppc64el': '256'}>
+CONFIG_MB1232                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MC3230                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MCB_LPC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCB_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCORE2                                   policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MCP320X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP3422                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP3911                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4018                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP41010                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4131                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4531                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4725                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCP4922                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MCPM                                     policy<{'armhf': 'y'}>
+CONFIG_MCPM_QUAD_CLUSTER                        policy<{'armhf': 'y'}>
+CONFIG_MCRUSOE                                  policy<{'i386': 'n'}>
+CONFIG_MCYRIXIII                                policy<{'i386': 'n'}>
+CONFIG_MD                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MDA_CONSOLE                              policy<{'i386': 'm'}>
+CONFIG_MDIO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_ASPEED                              policy<{'armhf': 'm'}>
+CONFIG_MDIO_BCM_IPROC                           policy<{'arm64': 'n'}>
+CONFIG_MDIO_BCM_UNIMAC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MDIO_BITBANG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MDIO_BUS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_MDIO_BUS_MUX                             policy<{'arm64': 'y', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_BUS_MUX_BCM_IPROC                   policy<{'arm64': 'y'}>
+CONFIG_MDIO_BUS_MUX_GPIO                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_BUS_MUX_MESON_G12A                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MDIO_BUS_MUX_MMIOREG                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_BUS_MUX_MULTIPLEXER                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_CAVIUM                              policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_DEVICE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MDIO_GPIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_HISI_FEMAC                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_I2C                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_MSCC_MIIM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MDIO_OCTEON                              policy<{'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_MDIO_SUN4I                               policy<{'arm64': 'n'}>
+CONFIG_MDIO_THUNDER                             policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MDIO_XGENE                               policy<{'arm64': 'm'}>
+CONFIG_MDM_GCC_9615                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MDM_LCC_9615                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MD_AUTODETECT                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MD_CLUSTER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_FAULTY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_LINEAR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_MULTIPATH                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'y'}>
+CONFIG_MD_RAID0                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID1                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID10                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MD_RAID456                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MEDIATEK_MT6577_AUXADC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MEDIATEK_WATCHDOG                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MEDIA_ALTERA_CI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_ANALOG_TV_SUPPORT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_ATTACH                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CAMERA_SUPPORT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CEC_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_COMMON_OPTIONS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CONTROLLER                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CONTROLLER_DVB                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_CONTROLLER_REQUEST_API             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_PCI_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_RADIO_SUPPORT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_SDR_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_SUBDRV_AUTOSELECT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEDIA_SUPPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEDIA_TUNER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_E4000                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0011                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0012                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC0013                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_FC2580                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_IT913X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_M88RS6000T                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MAX2165                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MC44S803                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MSI001                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2060                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2063                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT20XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2131                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MT2266                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL301RF                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL5005S                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_MXL5007T                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_QM1D1B0004                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_QM1D1C0042                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_QT1010                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_R820T                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_SI2157                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_SIMPLE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18212                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18218                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18250                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA18271                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA827X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA8290                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TDA9887                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5761                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TEA5767                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_TUA9001                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC2028                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC4000                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_TUNER_XC5000                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEDIA_USB_SUPPORT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MEFFICEON                                policy<{'i386': 'n'}>
+CONFIG_MEGARAID_LEGACY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEGARAID_MAILBOX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEGARAID_MM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEGARAID_NEWGEN                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MEGARAID_SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MELAN                                    policy<{'i386': 'n'}>
+CONFIG_MELLANOX_PLATFORM                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_MEMBARRIER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG_KMEM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG_SWAP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMCG_SWAP_ENABLED                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MEMFD_CREATE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MEMORY_BALLOON                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_FAILURE                           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_MEMORY_HOTPLUG                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_HOTPLUG_SPARSE                    policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_HOTREMOVE                         policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_ISOLATION                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEMORY_NOTIFIER_ERROR_INJECT             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MEMSTICK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MEMSTICK_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MEMSTICK_JMICRON_38X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_R592                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_REALTEK_PCI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_REALTEK_USB                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_TIFM_MS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEMSTICK_UNSAFE_RESUME                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MEMTEST                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MEM_SOFT_DIRTY                           policy<{'amd64': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_MENF21BMC_WATCHDOG                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MENZ069_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MEN_A21_WDT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MEN_Z188_ADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MESON6_TIMER                             policy<{'armhf': 'y'}>
+CONFIG_MESON_CANVAS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_CLK_MEASURE                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_EE_PM_DOMAINS                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_EFUSE                              policy<{'arm64': 'm'}>
+CONFIG_MESON_GXBB_WATCHDOG                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_GXL_PHY                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_GX_PM_DOMAINS                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_GX_SOCINFO                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_IRQ_GPIO                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_MX_EFUSE                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_MX_SOCINFO                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MESON_SARADC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESON_SM                                 policy<{'arm64': 'y'}>
+CONFIG_MESON_WATCHDOG                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT                 policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'ppc64el': '4', 's390x': '4'}>
+CONFIG_MFD_88PM800                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_88PM805                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_88PM860X                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_AAT2870_CORE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_AC100                                policy<{'arm64': 'n'}>
+CONFIG_MFD_ACT8945A                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_AHC1EC0                              policy<{'amd64': 'm'}>
+CONFIG_MFD_ALTERA_SYSMGR                        policy<{'arm64': 'y'}>
+CONFIG_MFD_ARIZONA                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_ARIZONA_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_ARIZONA_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_AS3711                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_AS3722                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_ASIC3                                policy<{'armhf': 'y'}>
+CONFIG_MFD_ATMEL_FLEXCOM                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_ATMEL_HLCDC                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_AXP20X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_AXP20X_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_AXP20X_RSB                           policy<{'arm64': 'm'}>
+CONFIG_MFD_BCM590XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_BD9571MWV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_MFD_CPCAP                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_CROS_EC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MFD_CROS_EC_DEV                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MFD_CS47L15                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS47L24                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS47L35                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS47L85                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS47L90                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS47L92                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_CS5535                               policy<{'i386': 'm'}>
+CONFIG_MFD_DA9052_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9052_SPI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9055                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_DA9062                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_DA9063                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_DA9150                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_EXYNOS_LPASS                         policy<{'armhf': 'm'}>
+CONFIG_MFD_HI6421_PMIC                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_HI655X_PMIC                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_INTEL_LPSS                           policy<{'amd64': 'm', 'i386': 'm'}>
+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_INTEL_QUARK_I2C_GPIO                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MFD_JANZ_CMODIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_KEMPLD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_LM3533                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_LOCHNAGAR                            policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_LP3943                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_LP8788                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MADERA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_MADERA_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MADERA_SPI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MAX14577                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_MAX77620                             policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX77650                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MAX77686                             policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX77693                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_MAX77843                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8907                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_MAX8925                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8997                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MAX8998                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_MC13XXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MC13XXX_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_MC13XXX_SPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_MENF21BMC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_MT6397                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_NVEC                                 policy<{'armhf-generic': 'm'}>
+CONFIG_MFD_OMAP_USB_HOST                        policy<{'armhf': 'y'}>
+CONFIG_MFD_PALMAS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_PCF50633                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_PM8XXX                               policy<{'armhf': 'm'}>
+CONFIG_MFD_QCOM_RPM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_RC5T583                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_RDC321X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MFD_RETU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_RK808                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RN5T618                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_ROHM_BD70528                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_ROHM_BD718XX                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_RT5033                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_SC27XX_PMIC                          policy<{'arm64': 'm'}>
+CONFIG_MFD_SEC_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SI476X_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_SKY81452                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_SM501_GPIO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SMSC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_SPMI_PMIC                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MFD_STMFX                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_STMPE                                policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_STPMIC1                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_SUN4I_GPADC                          policy<{'arm64': 'm'}>
+CONFIG_MFD_SUN6I_PRCM                           policy<{'arm64': 'y'}>
+CONFIG_MFD_SYSCON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_T7L66XB                              policy<{'armhf': 'y'}>
+CONFIG_MFD_TC3589X                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TC6387XB                             policy<{'armhf': 'y'}>
+CONFIG_MFD_TC6393XB                             policy<{'armhf': 'y'}>
+CONFIG_MFD_TIMBERDALE                           policy<{'i386': 'm'}>
+CONFIG_MFD_TI_AM335X_TSCADC                     policy<{'amd64': '-', 'arm64': 'm', 'armhf': 'm', 'i386': '-', 'ppc64el': '-', 's390x': '-'}>
+CONFIG_MFD_TI_LMU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_TI_LP873X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_TI_LP87565                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_TMIO                                 policy<{'armhf': 'y'}>
+CONFIG_MFD_TPS65086                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_TPS65090                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65218                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_TPS6586X                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65910                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65912                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS65912_I2C                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MFD_TPS65912_SPI                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TPS68470                             policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_MFD_TPS80031                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_TQMX86                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_TWL4030_AUDIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_VEXPRESS_SYSREG                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MFD_VIPERBOARD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MFD_VX855                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MFD_WL1273_CORE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_WM5102                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM5110                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM831X                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM831X_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM831X_SPI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8350                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8350_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8400                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8994                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MFD_WM8997                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MFD_WM8998                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MGEODEGX1                                policy<{'i386': 'n'}>
+CONFIG_MGEODE_LX                                policy<{'i386': 'n'}>
+CONFIG_MICREL_KS8995MA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MICREL_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MICROCHIP_PHY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MICROCHIP_T1_PHY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MICROCODE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROCODE_AMD                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROCODE_INTEL                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROCODE_OLD_INTERFACE                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MICROSEMI_PHY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MIC_COSM                                 policy<{'amd64': 'm'}>
+CONFIG_MIGHT_HAVE_CACHE_L2X0                    policy<{'armhf': 'y'}>
+CONFIG_MIGRATION                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MII                                      policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MILBEAUT_TIMER                           policy<{'armhf': 'y'}>
+CONFIG_MINIX_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MINIX_SUBPARTITION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MISC_ALCOR_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MISC_FILESYSTEMS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MISC_RTSX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISC_RTSX_PCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MISC_RTSX_USB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_AVMFRITZ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_DSP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HDLC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCMULTI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCPCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_HFCUSB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_INFINEON                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_IPAC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_ISAR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_L1OIP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_NETJET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_SPEEDFAX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MISDN_W6692                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY          policy<{'arm64': 'y'}>
+CONFIG_MIXCOMWD                                 policy<{'i386': 'm'}>
+CONFIG_MK6                                      policy<{'i386': 'n'}>
+CONFIG_MK7                                      policy<{'i386': 'n'}>
+CONFIG_MK8                                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MKISS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MLX4_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX4_CORE_GEN2                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_EN                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX4_EN_DCB                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX4_INFINIBAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX5_ACCEL                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX5_CORE_EN                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_CORE_EN_DCB                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_CORE_IPOIB                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_EN_ARFS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_EN_IPSEC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_EN_RXNFC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_EN_TLS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_ESWITCH                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_FPGA                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_FPGA_IPSEC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_FPGA_TLS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_INFINIBAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX5_MPFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_SW_STEERING                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX5_TLS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLX90614                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MLX90632                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MLXBF_TMFIFO                             policy<{'arm64': 'm'}>
+CONFIG_MLXFW                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXREG_HOTPLUG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MLXREG_IO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MLXSW_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXSW_CORE_HWMON                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MLXSW_CORE_THERMAL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MLXSW_I2C                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_MLXSW_MINIMAL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MLXSW_PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXSW_SPECTRUM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXSW_SPECTRUM_DCB                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MLXSW_SWITCHIB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLXSW_SWITCHX2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MLX_PLATFORM                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MLX_WDT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_MMA7455                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA7455_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA7455_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA7660                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA8452                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA9551                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA9551_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMA9553                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_MMC35240                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMCONF_FAM10H                            policy<{'amd64': 'y'}>
+CONFIG_MMC_ALCOR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_ARMMMCI                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_BCM2835                              policy<{'arm64': 'm'}>
+CONFIG_MMC_BLOCK_MINORS                         policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_MMC_CAVIUM_THUNDERX                      policy<{'arm64': 'm'}>
+CONFIG_MMC_CB710                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_CQHCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MMC_DW                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_BLUEFIELD                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_EXYNOS                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_HI3798CV200                       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_PLTFM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_DW_ROCKCHIP                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_MESON_GX                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_MESON_MX_SDIO                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_MTK                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_MVSDIO                               policy<{'armhf': 'm'}>
+CONFIG_MMC_MXC                                  policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_MMC_OMAP                                 policy<{'armhf': 'm'}>
+CONFIG_MMC_QCOM_DML                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_REALTEK_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_REALTEK_USB                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_RICOH_MMC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MMC_SDHCI_ACPI                           policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_MMC_SDHCI_AM654                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER  policy<{'ppc64el': 'y'}>
+CONFIG_MMC_SDHCI_BRCMSTB                        policy<{'arm64': 'm'}>
+CONFIG_MMC_SDHCI_CADENCE                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_DOVE                           policy<{'armhf': 'm'}>
+CONFIG_MMC_SDHCI_ESDHC_IMX                      policy<{'arm64': 'm', 'armhf-generic': 'y'}>
+CONFIG_MMC_SDHCI_F_SDH30                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_IO_ACCESSORS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MMC_SDHCI_IPROC                          policy<{'arm64': 'm'}>
+CONFIG_MMC_SDHCI_MSM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_OF_ARASAN                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_OF_ASPEED                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_AT91                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_DWCMSHC                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_OF_ESDHC                       policy<{'arm64': 'm', 'armhf-generic': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OF_HLWD                        policy<{'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_OMAP                           policy<{'arm64': '-', 'armhf': 'm', 'ppc64el': '-'}>
+CONFIG_MMC_SDHCI_PCI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHCI_PXAV3                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHCI_S3C                            policy<{'armhf': 'm'}>
+CONFIG_MMC_SDHCI_S3C_DMA                        policy<{'armhf': 'y'}>
+CONFIG_MMC_SDHCI_SPRD                           policy<{'arm64': 'm'}>
+CONFIG_MMC_SDHCI_TEGRA                          policy<{'armhf-generic': 'm'}>
+CONFIG_MMC_SDHCI_XENON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_SDHI                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHI_INTERNAL_DMAC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDHI_SYS_DMAC                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SDRICOH_CS                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MMC_SH_MMCIF                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_SPI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_STM32_SDMMC                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MMC_SUNXI                                policy<{'arm64': 'm'}>
+CONFIG_MMC_TEST                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MMC_TIFM_SD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_TMIO                                 policy<{'armhf': 'm'}>
+CONFIG_MMC_TMIO_CORE                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MMC_TOSHIBA_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_UNIPHIER                             policy<{'armhf': 'm'}>
+CONFIG_MMC_USDHI6ROL0                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_USHC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_VIA_SDMMC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_VUB300                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMC_WBSD                                 policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MMIOTRACE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MMIOTRACE_TEST                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MMIOWB                                   policy<{'ppc64el': 'y'}>
+CONFIG_MMU                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MMU_NOTIFIER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULES                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULES_TREE_LOOKUP                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULES_USE_ELF_REL                      policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_MODULES_USE_ELF_RELA                     policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_COMPRESS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_FORCE_LOAD                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_FORCE_UNLOAD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_REL_CRCS                          policy<{'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG_ALL                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG_FORCE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_FORMAT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SIG_HASH                          policy<{'amd64': '"sha512"', 'arm64': '"sha512"', 'armhf': '"sha512"', 'i386': '"sha512"', 'ppc64el': '"sha512"', 's390x': '"sha512"'}>
+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"', 'ppc64el': '"certs/signing_key.pem"', 's390x': '"certs/signing_key.pem"'}>
+CONFIG_MODULE_SIG_SHA1                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA224                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA256                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA384                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_MODULE_SIG_SHA512                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_SRCVERSION_ALL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MODULE_UNLOAD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MONREADER                                policy<{'s390x': 'm'}>
+CONFIG_MONWRITER                                policy<{'s390x': 'm'}>
+CONFIG_MOST                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_CDEV                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_DIM2                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_I2C                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_NET                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_SOUND                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_USB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOST_VIDEO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_APPLETOUCH                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_BCM5974                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_CYAPA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_ELAN_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_ELAN_I2C_I2C                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_ELAN_I2C_SMBUS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_GPIO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_LOGIBM                             policy<{'i386': 'm'}>
+CONFIG_MOUSE_PC110PAD                           policy<{'i386': 'm'}>
+CONFIG_MOUSE_PS2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_PS2_ALPS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_BYD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_CYPRESS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_ELANTECH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_ELANTECH_SMBUS                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_FOCALTECH                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_LIFEBOOK                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MOUSE_PS2_LOGIPS2PP                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SENTELIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SMBUS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SYNAPTICS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_TOUCHKIT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_TRACKPOINT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MOUSE_PS2_VMMOUSE                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_MOUSE_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_SYNAPTICS_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_SYNAPTICS_USB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOUSE_VSXXXAA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOXA_INTELLIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOXA_SMARTIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MOXTET                                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MPENTIUM4                                policy<{'i386': 'n'}>
+CONFIG_MPENTIUMII                               policy<{'i386': 'n'}>
+CONFIG_MPENTIUMIII                              policy<{'i386': 'n'}>
+CONFIG_MPENTIUMM                                policy<{'i386': 'n'}>
+CONFIG_MPIC                                     policy<{'ppc64el': 'y'}>
+CONFIG_MPIC_MSGR                                policy<{'ppc64el': 'n'}>
+CONFIG_MPILIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MPL115                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MPL115_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MPL115_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MPL3115                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MPLS                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MPLS_IPTUNNEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MPLS_ROUTING                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MPROFILE_KERNEL                          policy<{'ppc64el': 'y'}>
+CONFIG_MPSC                                     policy<{'amd64': 'n'}>
+CONFIG_MPU3050                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MPU3050_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MQ_IOSCHED_DEADLINE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MQ_IOSCHED_KYBER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MRP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MS5611                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5611_I2C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5611_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MS5637                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MSCC_OCELOT_SWITCH                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MSCC_OCELOT_SWITCH_OCELOT                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MSDOS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_MSDOS_PARTITION                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MSI_BITMAP_SELFTEST                      policy<{'ppc64el': 'n'}>
+CONFIG_MSI_LAPTOP                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MSI_WMI                                  policy<{'amd64': 'm', 'i386': '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_GCC_8974                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8994                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8996                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_GCC_8998                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_IOMMU                                policy<{'armhf': 'n'}>
+CONFIG_MSM_LCC_8960                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_MMCC_8960                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_MMCC_8974                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSM_MMCC_8996                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MSPRO_BLOCK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MS_BLOCK                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT7601U                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT7603E                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT7615E                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76_LEDS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MT76_USB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x02_LIB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x02_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x0E                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x0U                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x0_COMMON                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x2E                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x2U                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MT76x2_COMMON                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTDRAM_ERASE_SIZE                        policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128'}>
+CONFIG_MTDRAM_TOTAL_SIZE                        policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'ppc64el': '4096'}>
+CONFIG_MTD_ABSENT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_AFS_PARTS                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_AMD76XROM                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_AR7_PARTS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BCM47XXSFLASH                        policy<{'armhf': 'm'}>
+CONFIG_MTD_BLKDEVS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK2MTD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_BLOCK_RO                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_ADV_OPTIONS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_CFI_AMDSTD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_I1                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_CFI_I2                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_CFI_INTELEXT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_STAA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CFI_UTIL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_CK804XROM                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_CMDLINE_PARTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_COMPLEX_MAPPINGS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_DATAFLASH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_DATAFLASH_OTP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_DATAFLASH_WRITE_VERIFY               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_ESB2ROM                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_GEN_PROBE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_HYPERBUS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ICHXROM                              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', 'ppc64el': 'm'}>
+CONFIG_MTD_JEDECPROBE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_L440GX                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_LPDDR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_LPDDR2_NVM                           policy<{'armhf': 'm'}>
+CONFIG_MTD_MAP_BANK_WIDTH_1                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MAP_BANK_WIDTH_2                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MAP_BANK_WIDTH_4                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_MCHP23K256                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_MTDRAM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_BRCMNAND                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_CAFE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_CORE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_CS553X                          policy<{'i386': 'm'}>
+CONFIG_MTD_NAND_DENALI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DENALI_DT                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_DENALI_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DISKONCHIP                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS        policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_ECC_SW_BCH                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_NAND_ECC_SW_HAMMING                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_NAND_FSL_IFC                         policy<{'arm64': 'm'}>
+CONFIG_MTD_NAND_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_GPMI_NAND                       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_HISI504                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_MARVELL                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_MESON                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_MTK                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_MXC                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_MXIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_NANDSIM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_OMAP_BCH_BUILD                  policy<{'armhf': 'y'}>
+CONFIG_MTD_NAND_ORION                           policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_PLATFORM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_QCOM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTD_NAND_RICOH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_NAND_SUNXI                           policy<{'arm64': 'n'}>
+CONFIG_MTD_NAND_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_NAND_TMIO                            policy<{'armhf': 'm'}>
+CONFIG_MTD_NAND_VF610_NFC                       policy<{'armhf-generic': 'n'}>
+CONFIG_MTD_NETtel                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_ONENAND                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ONENAND_2X_PROGRAM                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_ONENAND_GENERIC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_ONENAND_OMAP2                        policy<{'armhf-generic': 'm'}>
+CONFIG_MTD_ONENAND_OTP                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_OOPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PARTITIONED_MASTER                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PCMCIA                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_PCMCIA_ANONYMOUS                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_MTD_PHRAM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PHYSMAP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PHYSMAP_COMPAT                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_PHYSMAP_GEMINI                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'n'}>
+CONFIG_MTD_PHYSMAP_GPIO_ADDR                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_PHYSMAP_OF                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_PHYSMAP_VERSATILE                    policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'n'}>
+CONFIG_MTD_PLATRAM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PMC551                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_PMC551_BUGFIX                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_PMC551_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_POWERNV_FLASH                        policy<{'ppc64el': 'm'}>
+CONFIG_MTD_QINFO_PROBE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_RAM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK              policy<{'amd64': '-1', 'arm64': '-1', 'armhf': '-1', 'i386': '-1', 'ppc64el': '-1'}>
+CONFIG_MTD_REDBOOT_PARTS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_REDBOOT_PARTS_READONLY               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_ROM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SBC_GXX                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_SCB2_FLASH                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MTD_SCx200_DOCFLASH                      policy<{'i386': 'm'}>
+CONFIG_MTD_SHARPSL_PARTS                        policy<{'armhf': 'm'}>
+CONFIG_MTD_SLRAM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SM_COMMON                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SPI_NAND                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SPI_NOR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_SST25L                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_SWAP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_TESTS                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_MTD_UBI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_UBI_BEB_LIMIT                        policy<{'amd64': '20', 'arm64': '20', 'armhf': '20', 'i386': '20', 'ppc64el': '20'}>
+CONFIG_MTD_UBI_BLOCK                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_UBI_FASTMAP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MTD_UBI_GLUEBI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MTD_UBI_WL_THRESHOLD                     policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'ppc64el': '4096'}>
+CONFIG_MTK_CMDQ                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_CMDQ_MBOX                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_CQDMA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_EFUSE                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTK_HSDMA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_INFRACFG                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_IOMMU                                policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_MTK_IOMMU_V1                             policy<{'armhf': 'n'}>
+CONFIG_MTK_PMIC_WRAP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_SCPSYS                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_SMI                                  policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_THERMAL                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MTK_TIMER                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MTK_UART_APDMA                           policy<{'arm64': 'm', 'armhf': 'm'}>
+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_MULTIPLEXER                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MULTIUSER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MUSB_PIO_ONLY                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_MUTEX_SPIN_ON_OWNER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_MUX_ADG792A                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MUX_ADGS1408                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MUX_GPIO                                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MUX_MMIO                                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_MV643XX_ETH                              policy<{'armhf': 'm'}>
+CONFIG_MVEBU_CLK_COMMON                         policy<{'armhf': 'y'}>
+CONFIG_MVEBU_CLK_COREDIV                        policy<{'armhf': 'y'}>
+CONFIG_MVEBU_CLK_CPU                            policy<{'armhf': 'y'}>
+CONFIG_MVEBU_DEVBUS                             policy<{'armhf': 'y'}>
+CONFIG_MVEBU_GICP                               policy<{'arm64': 'y'}>
+CONFIG_MVEBU_ICU                                policy<{'arm64': 'y'}>
+CONFIG_MVEBU_MBUS                               policy<{'armhf': 'y'}>
+CONFIG_MVEBU_ODMI                               policy<{'arm64': 'y'}>
+CONFIG_MVEBU_PIC                                policy<{'arm64': 'y'}>
+CONFIG_MVEBU_SEI                                policy<{'arm64': 'y'}>
+CONFIG_MVIAC3_2                                 policy<{'i386': 'n'}>
+CONFIG_MVIAC7                                   policy<{'i386': 'n'}>
+CONFIG_MVMDIO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MVNETA                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MVNETA_BM_ENABLE                         policy<{'armhf': 'n'}>
+CONFIG_MVPP2                                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_MV_XOR                                   policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_MV_XOR_V2                                policy<{'arm64': 'y'}>
+CONFIG_MWAVE                                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MWIFIEX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_PCIE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_SDIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MWIFIEX_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MWINCHIP3D                               policy<{'i386': 'n'}>
+CONFIG_MWINCHIPC6                               policy<{'i386': 'n'}>
+CONFIG_MWL8K                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MX3_IPU                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_MX3_IPU_IRQS                             policy<{'arm64': '4', 'armhf-generic': '4'}>
+CONFIG_MXC4005                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MXC6255                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MXC_CLK                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_MXC_CLK_SCU                              policy<{'arm64': 'y'}>
+CONFIG_MXC_TZIC                                 policy<{'armhf-generic': 'y'}>
+CONFIG_MXM_WMI                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_MXS_DMA                                  policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_MYRI10GE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_MYRI10GE_DCA                             policy<{'amd64': 'y'}>
+CONFIG_N2                                       policy<{'i386': 'm'}>
+CONFIG_NAMESPACES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NATIONAL_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NATSEMI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NAU7802                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NBPFAXI_DMA                              policy<{'armhf': 'm'}>
+CONFIG_NCSI_OEM_CMD_GET_MAC                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ND_BLK                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ND_BTT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ND_CLAIM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ND_PFN                                   policy<{'amd64': 'm', 'ppc64el': 'm'}>
+CONFIG_NE2000                                   policy<{'i386': 'm'}>
+CONFIG_NE2K_PCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NEED_DMA_MAP_STATE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NEED_MULTIPLE_NODES                      policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_NEED_SG_DMA_LENGTH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NEON                                     policy<{'armhf': 'y'}>
+CONFIG_NET                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET5501                                  policy<{'i386': 'y'}>
+CONFIG_NETCONSOLE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETCONSOLE_DYNAMIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETDEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETDEVSIM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETDEV_NOTIFIER_ERROR_INJECT             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NETFILTER                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_ADVANCED                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_CONNCOUNT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_FAMILY_ARP                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_FAMILY_BRIDGE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_INGRESS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_NETLINK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_ACCT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_GLUE_CT                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETFILTER_NETLINK_LOG                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_OSF                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_NETLINK_QUEUE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_SYNPROXY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XTABLES                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_CONNMARK                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MARK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_BPF                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CGROUP                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CLUSTER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_COMMENT               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNMARK              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_CPU                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DCCP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_DSCP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ECN                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_ESP                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HELPER                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_HL                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPCOMP                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPRANGE               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_IPVS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_L2TP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_LENGTH                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_LIMIT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MAC                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MARK                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_NFACCT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_OSF                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_OWNER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_POLICY                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_QUOTA                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_RATEEST               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_REALM                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_RECENT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_SCTP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_SOCKET                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STATE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STATISTIC             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_STRING                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_TCPMSS                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_TIME                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_MATCH_U32                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_NAT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_SET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_AUDIT                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CONNMARK             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_CT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_DSCP                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_HL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_HMARK                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_LED                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_LOG                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_MARK                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_MASQUERADE           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NETMAP               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NFLOG                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_NOTRACK              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NETFILTER_XT_TARGET_RATEEST              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_REDIRECT             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_SECMARK              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TCPMSS               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TEE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TPROXY               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETFILTER_XT_TARGET_TRACE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETIUCV                                  policy<{'s390x': 'm'}>
+CONFIG_NETLABEL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETLINK_DIAG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NETPOLL                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETROM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NETWORK_FILESYSTEMS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETWORK_SECMARK                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NETXEN_NIC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_9P_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_9P_RDMA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P_VIRTIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_9P_XEN                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_NET_ACT_BPF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CONNMARK                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CSUM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_CTINFO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_GACT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_IFE                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_ACT_IPT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_MIRRED                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_MPLS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_NAT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_PEDIT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_POLICE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SAMPLE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SIMP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SKBEDIT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_SKBMOD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_TUNNEL_KEY                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_ACT_VLAN                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CALXEDA_XGMAC                        policy<{'armhf': 'm'}>
+CONFIG_NET_CLS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_CLS_ACT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_CLS_BASIC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_BPF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_CGROUP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FLOW                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FLOWER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_FW                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_MATCHALL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_ROUTE4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CLS_U32                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_CORE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_DEVLINK                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_DSA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_BCM_SF2                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_LANTIQ_GSWIP                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_LOOP                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ8795                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ9477                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MT7530                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MV88E6060                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MV88E6XXX                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_MV88E6XXX_GLOBAL2                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_DSA_MV88E6XXX_PTP                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_DSA_QCA8K                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_REALTEK_SMI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_SJA1105                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_SJA1105_PTP                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_DSA_SJA1105_TAS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_DSA_SMSC_LAN9303                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_SMSC_LAN9303_I2C                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_SMSC_LAN9303_MDIO                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_8021Q                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_BRCM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_BRCM_COMMON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_BRCM_PREPEND                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_DSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_EDSA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_GSWIP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_KSZ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_LAN9303                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_MTK                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_QCA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_SJA1105                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_TAG_TRAILER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_VITESSE_VSC73XX                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_DSA_VITESSE_VSC73XX_SPI              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_EGRESS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_EMATCH                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_EMATCH_CANID                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NET_EMATCH_CMP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_IPSET                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_IPT                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_META                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_NBYTE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_STACK                         policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32', 's390x': '32'}>
+CONFIG_NET_EMATCH_TEXT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_EMATCH_U32                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FAILOVER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FC                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_FLOW_LIMIT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_FOU                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_FOU_IP_TUNNELS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_IFE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_INGRESS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_IPGRE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPGRE_BROADCAST                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_IPGRE_DEMUX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPIP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IPVTI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_IP_TUNNEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_KEY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_KEY_MIGRATE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_L3_MASTER_DEV                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_MPLS_GSO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_NCSI                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_NSH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_PKTGEN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_POLL_CONTROLLER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_PTP_CLASSIFY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_REDIRECT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_RX_BUSY_POLL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SB1000                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_NET_SCHED                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SCH_CAKE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_CBS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_CHOKE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_CODEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_DEFAULT                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NET_SCH_DRR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_ETF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_FIFO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_SCH_FQ                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_FQ_CODEL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_GRED                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HFSC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HHF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_HTB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_INGRESS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_MQPRIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_MULTIQ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_NETEM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_PIE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_PLUG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_PRIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_QFQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_RED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_SFB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_SFQ                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_SKBPRIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_TAPRIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_TBF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SCH_TEQL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_SOCK_MSG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_TC_SKB_EXT                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_TEAM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_BROADCAST                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_LOADBALANCE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_RANDOM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TEAM_MODE_ROUNDROBIN                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_TULIP                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_UDP_TUNNEL                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_VENDOR_3COM                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_8390                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_VENDOR_ADAPTEC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_AGERE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_ALACRITECH                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_ALLWINNER                     policy<{'arm64': 'y'}>
+CONFIG_NET_VENDOR_ALTEON                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_AMAZON                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_AMD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_AQUANTIA                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_ARC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_ATHEROS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_AURORA                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_BROADCOM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_BROCADE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_CADENCE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_CAVIUM                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_CHELSIO                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_CIRRUS                        policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_NET_VENDOR_CISCO                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_CORTINA                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_DEC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_DLINK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_EZCHIP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_FARADAY                       policy<{'armhf': 'y'}>
+CONFIG_NET_VENDOR_FREESCALE                     policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_NET_VENDOR_FUJITSU                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_NET_VENDOR_GOOGLE                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_HISILICON                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_NET_VENDOR_HP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_HUAWEI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_I825XX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_VENDOR_IBM                           policy<{'ppc64el': 'y'}>
+CONFIG_NET_VENDOR_INTEL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MARVELL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MEDIATEK                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_NET_VENDOR_MELLANOX                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_MICREL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MICROCHIP                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MICROSEMI                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_MYRI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_NATSEMI                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_NETERION                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_NETRONOME                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_NI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_NVIDIA                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_OKI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_PACKET_ENGINES                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_PENSANDO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_QLOGIC                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_QUALCOMM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_RDC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_REALTEK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_RENESAS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_ROCKER                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SAMSUNG                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SEEQ                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SILAN                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SIS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SMSC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SOCIONEXT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_SOLARFLARE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_STMICRO                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SUN                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_SYNOPSYS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NET_VENDOR_TEHUTI                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_TI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_VIA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_WIZNET                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NET_VENDOR_XILINX                        policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NET_VENDOR_XIRCOM                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_NET_VRF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NET_XGENE                                policy<{'arm64': 'm'}>
+CONFIG_NET_XGENE_V2                             policy<{'arm64': 'm'}>
+CONFIG_NEW_LEDS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_NFC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NFC_DIGITAL                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_FDP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_FDP_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_HCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MEI_PHY                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_MICROREAD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MICROREAD_I2C                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MICROREAD_MEI                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_MRVL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_I2C                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_SPI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_UART                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_MRVL_USB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NCI_UART                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NXP_NCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_NXP_NCI_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN533                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN533_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN533_USB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN544                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN544_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_PN544_MEI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NFC_PORT100                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_S3FWRN5                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_S3FWRN5_I2C                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_SHDLC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NFC_SIM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST21NFCA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST21NFCA_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST95HF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI_I2C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_ST_NCI_SPI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFC_TRF7970A                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFIT_SECURITY_DEBUG                      policy<{'amd64': 'n', 'arm64': 'n'}>
+CONFIG_NFP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NFP_APP_ABM_NIC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NFP_APP_FLOWER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NFP_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NFSD                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFSD_BLOCKLAYOUT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_FLEXFILELAYOUT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_PNFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_SCSILAYOUT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V2_ACL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V3                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V3_ACL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V4                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFSD_V4_SECURITY_LABEL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_ACL_SUPPORT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_COMMON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_DEBUG                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_FSCACHE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_SWAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_USE_KERNEL_DNS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_USE_LEGACY_DNS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NFS_V2                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V3_ACL                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFS_V4_1                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': '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"', 'ppc64el': '"kernel.org"', 's390x': '"kernel.org"'}>
+CONFIG_NFS_V4_1_MIGRATION                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4_2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFS_V4_SECURITY_LABEL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NFTL                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NFTL_RW                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NFT_BRIDGE_META                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_BRIDGE_REJECT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_COMPAT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CONNLIMIT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_COUNTER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_CT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_DUP_IPV4                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_DUP_IPV6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_DUP_NETDEV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FIB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FIB_INET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FIB_IPV4                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FIB_IPV6                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FIB_NETDEV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FLOW_OFFLOAD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_FWD_NETDEV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_HASH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_LIMIT                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_LOG                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_MASQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_NAT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_NUMGEN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_OBJREF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_OSF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_QUEUE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_QUOTA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REDIR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REJECT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REJECT_INET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REJECT_IPV4                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_REJECT_IPV6                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_SOCKET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_SYNPROXY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_TPROXY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_TUNNEL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NFT_XFRM                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_AMANDA                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_BRIDGE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_BROADCAST                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_EVENTS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_FTP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_H323                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_IRC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_LABELS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_MARK                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_NETBIOS_NS                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_PPTP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_PROCFS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NF_CONNTRACK_SANE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_SECMARK                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_SIP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_SNMP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_TFTP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CONNTRACK_TIMEOUT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_TIMESTAMP                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CONNTRACK_ZONES                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CT_NETLINK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_NETLINK_HELPER                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_NETLINK_TIMEOUT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_CT_PROTO_DCCP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CT_PROTO_GRE                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CT_PROTO_SCTP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_CT_PROTO_UDPLITE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_DEFRAG_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DEFRAG_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DUP_IPV4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DUP_IPV6                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_DUP_NETDEV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_FLOW_TABLE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_FLOW_TABLE_INET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_FLOW_TABLE_IPV4                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_FLOW_TABLE_IPV6                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_ARP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_BRIDGE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_COMMON                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_IPV4                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_IPV6                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_LOG_NETDEV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_AMANDA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_FTP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_H323                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_IRC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_MASQUERADE                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_NAT_PPTP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_REDIRECT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_NAT_SIP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_SNMP_BASIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_NAT_TFTP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_REJECT_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_REJECT_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_SOCKET_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_SOCKET_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_ARP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_TABLES_BRIDGE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TABLES_INET                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_TABLES_IPV4                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_TABLES_IPV6                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_TABLES_NETDEV                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NF_TABLES_SET                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TPROXY_IPV4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NF_TPROXY_IPV6                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NI65                                     policy<{'i386': 'm'}>
+CONFIG_NI903X_WDT                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NIC7018_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NILFS2_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NIU                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NI_XGE_MANAGEMENT_ENET                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NL80211_TESTMODE                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NLATTR                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLMON                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ASCII                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_1250                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_1251                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_437                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NLS_CODEPAGE_737                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_775                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_850                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_852                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_855                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_857                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_860                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_861                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_862                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_863                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_864                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_865                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_866                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_869                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_874                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_932                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_936                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_949                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_CODEPAGE_950                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_DEFAULT                              policy<{'amd64': '"utf8"', 'arm64': '"utf8"', 'armhf': '"utf8"', 'i386': '"utf8"', 'ppc64el': '"utf8"', 's390x': '"utf8"'}>
+CONFIG_NLS_ISO8859_1                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_13                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_14                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_15                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_3                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_4                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_5                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_6                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_7                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_8                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_ISO8859_9                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_KOI8_R                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_KOI8_U                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CELTIC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CENTEURO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CROATIAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_CYRILLIC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_GAELIC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_GREEK                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ICELAND                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_INUIT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ROMAN                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_ROMANIAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_MAC_TURKISH                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NLS_UTF8                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NMI_IPI                                  policy<{'ppc64el': 'y'}>
+CONFIG_NOA1305                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NODES_SHIFT                              policy<{'amd64': '10', 'arm64': '6', 'ppc64el': '8', 's390x': '4'}>
+CONFIG_NODES_SPAN_OTHER_NODES                   policy<{'amd64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NOHIGHMEM                                policy<{'i386': 'n'}>
+CONFIG_NOKIA_MODEM                              policy<{'armhf-generic': 'm'}>
+CONFIG_NONSTATIC_KERNEL                         policy<{'ppc64el': 'y'}>
+CONFIG_NOP_TRACER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NORTEL_HERMES                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NOTIFIER_ERROR_INJECTION                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NOUVEAU_DEBUG                            policy<{'amd64': '5', 'arm64': '5', 'armhf': '5', 'i386': '5', 'ppc64el': '5'}>
+CONFIG_NOUVEAU_DEBUG_DEFAULT                    policy<{'amd64': '3', 'arm64': '3', 'armhf': '3', 'i386': '3', 'ppc64el': '3'}>
+CONFIG_NOUVEAU_DEBUG_MMU                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NOUVEAU_PLATFORM_DRIVER                  policy<{'armhf-generic': 'y'}>
+CONFIG_NOZOMI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NO_HZ                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NO_HZ_COMMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NO_HZ_FULL                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n'}>
+CONFIG_NO_IOPORT_MAP                            policy<{'armhf': 'y', 's390x': 'y'}>
+CONFIG_NPCM7XX_KCS_IPMI_BMC                     policy<{'armhf': 'm'}>
+CONFIG_NPCM7XX_TIMER                            policy<{'armhf': 'y'}>
+CONFIG_NPCM7XX_WATCHDOG                         policy<{'armhf': 'y'}>
+CONFIG_NPCM_ADC                                 policy<{'armhf': 'm'}>
+CONFIG_NR_CPUS_DEFAULT                          policy<{'amd64': '8192', 'i386': '8'}>
+CONFIG_NR_CPUS_RANGE_BEGIN                      policy<{'amd64': '8192', 'i386': '2'}>
+CONFIG_NR_CPUS_RANGE_END                        policy<{'amd64': '8192', 'i386': '8'}>
+CONFIG_NR_IRQS                                  policy<{'ppc64el': '512'}>
+CONFIG_NS83820                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NSC_GPIO                                 policy<{'i386': 'm'}>
+CONFIG_NTB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_NTB_AMD                                  policy<{'amd64': 'n'}>
+CONFIG_NTB_IDT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_INTEL                                policy<{'amd64': 'm'}>
+CONFIG_NTB_MSI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NTB_MSI_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_NTB_NETDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_PERF                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_PINGPONG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_SWITCHTEC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_TOOL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTB_TRANSPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_NTFS_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NTFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NTFS_RW                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_NULL_TTY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NUMA_BALANCING                           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NVDIMM_DAX                               policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_NVDIMM_KEYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NVDIMM_PFN                               policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_NVEC_PAZ00                               policy<{'armhf-generic': 'm'}>
+CONFIG_NVEC_POWER                               policy<{'armhf-generic': 'm'}>
+CONFIG_NVMEM_BCM_OCOTP                          policy<{'arm64': 'm'}>
+CONFIG_NVMEM_IMX_IIM                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_NVMEM_IMX_OCOTP                          policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_NVMEM_IMX_OCOTP_SCU                      policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_NVMEM_REBOOT_MODE                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_NVMEM_SNVS_LPGPR                         policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_NVMEM_SUNXI_SID                          policy<{'arm64': 'm'}>
+CONFIG_NVMEM_SYSFS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_NVMEM_VF610_OCOTP                        policy<{'armhf-generic': 'n'}>
+CONFIG_NVMEM_ZYNQMP                             policy<{'arm64': 'y'}>
+CONFIG_NVME_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_FABRICS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_FC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_MULTIPATH                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_NVME_RDMA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TARGET                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TARGET_FC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TARGET_FCLOOP                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_NVME_TARGET_LOOP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TARGET_RDMA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TARGET_TCP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NVME_TCP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_NV_TCO                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_NXP_TJA11XX_PHY                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_N_HDLC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_OABI_COMPAT                              policy<{'armhf': 'n'}>
+CONFIG_OBJAGG                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_DEBUG_FS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_OCFS2_DEBUG_MASKLOG                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OCFS2_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_FS_O2CB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCFS2_FS_STATS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OCTEONTX2_AF                             policy<{'arm64': 'm'}>
+CONFIG_OCTEONTX2_MBOX                           policy<{'arm64': 'm'}>
+CONFIG_OCXL                                     policy<{'ppc64el': 'm'}>
+CONFIG_OCXL_BASE                                policy<{'ppc64el': 'y'}>
+CONFIG_OF                                       policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_OF_ADDRESS                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_DMA_DEFAULT_COHERENT                  policy<{'ppc64el': 'y'}>
+CONFIG_OF_DYNAMIC                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_EARLY_FLATTREE                        policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_FLATTREE                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_FPGA_REGION                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_OF_GPIO                                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_IOMMU                                 policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_IRQ                                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_KOBJ                                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_MDIO                                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_NET                                   policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_NUMA                                  policy<{'arm64': 'y'}>
+CONFIG_OF_OVERLAY                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_PMEM                                  policy<{'arm64': 'm', 'armhf-generic-lpae': 'm', 'ppc64el': 'm'}>
+CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT        policy<{'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n'}>
+CONFIG_OF_RESERVED_MEM                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_RESOLVE                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_OF_UNITTEST                              policy<{'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n'}>
+CONFIG_OID_REGISTRY                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OLD_SIGACTION                            policy<{'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_OLD_SIGSUSPEND                           policy<{'ppc64el': 'y'}>
+CONFIG_OLD_SIGSUSPEND3                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_OMAP2PLUS_MBOX                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_OMAP2_VRFB                               policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE         policy<{'armhf-generic': 'n'}>
+CONFIG_OMAP3_SDRC_AC_TIMING                     policy<{'armhf-generic': 'n'}>
+CONFIG_OMAP3_THERMAL                            policy<{'armhf-generic': 'n'}>
+CONFIG_OMAP4_THERMAL                            policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP5_ERRATA_801819                      policy<{'armhf': 'y'}>
+CONFIG_OMAP_32K_TIMER                           policy<{'armhf': 'y'}>
+CONFIG_OMAP_CONTROL_PHY                         policy<{'armhf': 'm'}>
+CONFIG_OMAP_DM_TIMER                            policy<{'armhf': 'y'}>
+CONFIG_OMAP_GPMC                                policy<{'armhf': 'y'}>
+CONFIG_OMAP_GPMC_DEBUG                          policy<{'armhf': 'n'}>
+CONFIG_OMAP_INTERCONNECT                        policy<{'armhf': 'y'}>
+CONFIG_OMAP_INTERCONNECT_BARRIER                policy<{'armhf': 'y'}>
+CONFIG_OMAP_IOMMU                               policy<{'armhf': 'y'}>
+CONFIG_OMAP_IOMMU_DEBUG                         policy<{'armhf': 'n'}>
+CONFIG_OMAP_IRQCHIP                             policy<{'armhf': 'y'}>
+CONFIG_OMAP_MBOX_KFIFO_SIZE                     policy<{'arm64': '256', 'armhf': '256'}>
+CONFIG_OMAP_OCP2SCP                             policy<{'armhf': 'm'}>
+CONFIG_OMAP_PACKAGE_CBB                         policy<{'armhf-generic': 'y'}>
+CONFIG_OMAP_REMOTEPROC                          policy<{'armhf-generic': 'm'}>
+CONFIG_OMAP_RESET_CLOCKS                        policy<{'armhf': 'y'}>
+CONFIG_OMAP_SSI                                 policy<{'armhf-generic': 'm'}>
+CONFIG_OMAP_USB2                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_OMAP_WATCHDOG                            policy<{'armhf': 'm'}>
+CONFIG_OMFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_OPAL_CORE                                policy<{'ppc64el': 'n'}>
+CONFIG_OPAL_PRD                                 policy<{'ppc64el': 'm'}>
+CONFIG_OPENVSWITCH                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_GENEVE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_GRE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPENVSWITCH_VXLAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPROFILE                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OPROFILE_EVENT_MULTIPLEX                 policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_OPROFILE_NMI_TIMER                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_OPT3001                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_OPTEE                                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_OPTEE_SHM_NUM_PRIV_PAGES                 policy<{'arm64': '1', 'armhf': '1'}>
+CONFIG_OPTIMIZE_INLINING                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OPTPROBES                                policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ORANGEFS_FS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ORINOCO_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ORION_IRQCHIP                            policy<{'armhf': 'y'}>
+CONFIG_ORION_TIMER                              policy<{'armhf': 'y'}>
+CONFIG_ORION_WATCHDOG                           policy<{'armhf': 'm'}>
+CONFIG_OSF_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_OUTER_CACHE                              policy<{'armhf': 'y'}>
+CONFIG_OUTER_CACHE_SYNC                         policy<{'armhf': 'y'}>
+CONFIG_OUTPUT_FORMAT                            policy<{'amd64': '"elf64-x86-64"', 'i386': '"elf32-i386"'}>
+CONFIG_OVERLAY_FS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_OVERLAY_FS_INDEX                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_OVERLAY_FS_METACOPY                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OVERLAY_FS_REDIRECT_DIR                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_OVERLAY_FS_XINO_AUTO                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_OWL_DMA                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_OWL_PM_DOMAINS                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_OWL_PM_DOMAINS_HELPER                    policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_OWL_TIMER                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_P54_COMMON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_LEDS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_P54_PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_SPI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_P54_SPI_DEFAULT_EEPROM                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_P54_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PA12203001                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PACKET                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PACKET_DIAG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PACKING                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PACK_STACK                               policy<{'s390x': 'y'}>
+CONFIG_PADATA                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_COUNTER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_EXTENSION                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PAGE_OFFSET                              policy<{'armhf': '0xC0000000', 'i386': '0xC0000000', 'ppc64el': '0xc000000000000000'}>
+CONFIG_PAGE_OWNER                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PAGE_POOL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PAGE_TABLE_ISOLATION                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PALMAS_GPADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PANASONIC_LAPTOP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PANEL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PANEL_CHANGE_MESSAGE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PANEL_PARPORT                            policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_PANEL_PROFILE                            policy<{'amd64': '5', 'arm64': '5', 'armhf': '5', 'i386': '5', 'ppc64el': '5'}>
+CONFIG_PANIC_ON_OOPS_VALUE                      policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_PANIC_TIMEOUT                            policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '10', 's390x': '0'}>
+CONFIG_PANTHERLORD_FF                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PAPR_SCM                                 policy<{'ppc64el': 'm'}>
+CONFIG_PARAVIRT                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y'}>
+CONFIG_PARAVIRT_CLOCK                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PARAVIRT_DEBUG                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_PARAVIRT_SPINLOCKS                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PARAVIRT_TIME_ACCOUNTING                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_PARAVIRT_XXL                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PARIDE                                   policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ATEN                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_BPCK                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_BPCK6                             policy<{'armhf': 'm', 'i386': 'm'}>
+CONFIG_PARIDE_COMM                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_DSTR                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_EPAT                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_EPATC8                            policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PARIDE_EPIA                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FIT2                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FIT3                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FRIQ                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_FRPW                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_KBIC                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_KTTI                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ON20                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_ON26                              policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PCD                               policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PD                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PF                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PG                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARIDE_PT                                policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARMAN                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PARPORT                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PARPORT_1284                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PARPORT_AX88796                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_NOT_PC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PARPORT_PANEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_PC                               policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARPORT_PC_FIFO                          policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PARPORT_PC_PCMCIA                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PARPORT_PC_SUPERIO                       policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PARPORT_SERIAL                           policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PARTITION_ADVANCED                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PARTITION_PERCPU                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PATA_ACPI                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_PATA_ALI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_AMD                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ARTOP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ATIIXP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_ATP867X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_CMD640_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_CMD64X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_PATA_EFAR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT366                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT37X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT3X2N                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_HPT3X3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_IMX                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_PATA_ISAPNP                              policy<{'i386': 'm'}>
+CONFIG_PATA_IT8213                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_IT821X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_JMICRON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_LEGACY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_MARVELL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_MPIIX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NETCELL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NINJA32                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NS87410                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_NS87415                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OF_PLATFORM                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OLDPIIX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OPTI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_OPTIDMA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PCMCIA                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PATA_PDC2027X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PDC_OLD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_PLATFORM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_QDI                                 policy<{'i386': 'm'}>
+CONFIG_PATA_RADISYS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_RDC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_RZ1000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SC1200                              policy<{'i386': 'm'}>
+CONFIG_PATA_SCH                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SERVERWORKS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SIL680                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_SIS                                 policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_PATA_TOSHIBA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_TRIFLEX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_VIA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_WINBOND                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PATA_WINBOND_VLB                         policy<{'i386': 'm'}>
+CONFIG_PC104                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PC300TOO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PC8736x_GPIO                             policy<{'i386': 'm'}>
+CONFIG_PC87413_WDT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCC                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PCCARD                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'n', 'i386': 'm', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCCARD_NONSTATIC                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCENGINES_APU2                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCF50633_ADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PCF50633_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PCH_CAN                                  policy<{'i386': 'm'}>
+CONFIG_PCH_DMA                                  policy<{'i386': 'm'}>
+CONFIG_PCH_GBE                                  policy<{'i386': 'm'}>
+CONFIG_PCH_PHUB                                 policy<{'i386': 'm'}>
+CONFIG_PCI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI200SYN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PCIEAER                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_PCIEAER_INJECT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIEASPM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_PCIEASPM_PERFORMANCE                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIEASPM_POWERSAVE                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIEASPM_POWER_SUPERSAVE                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIE_AL                                  policy<{'arm64': 'y'}>
+CONFIG_PCIE_ALTERA                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_ALTERA_MSI                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_ARMADA_8K                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_BW                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIE_CADENCE                             policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCIE_CADENCE_EP                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCIE_CADENCE_HOST                        policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCIE_DPC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_PCIE_DW                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_DW_EP                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_DW_HOST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_DW_PLAT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_DW_PLAT_EP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_DW_PLAT_HOST                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_ECRC                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 's390x': 'n'}>
+CONFIG_PCIE_HISI_STB                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_IPROC                               policy<{'arm64': 'm'}>
+CONFIG_PCIE_IPROC_MSI                           policy<{'arm64': 'y'}>
+CONFIG_PCIE_IPROC_PLATFORM                      policy<{'arm64': 'm'}>
+CONFIG_PCIE_KIRIN                               policy<{'arm64': 'y'}>
+CONFIG_PCIE_MEDIATEK                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_MOBIVEIL                            policy<{'arm64': 'y'}>
+CONFIG_PCIE_PME                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCIE_PTM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_PCIE_QCOM                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_RCAR                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_ROCKCHIP                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_ROCKCHIP_EP                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCIE_ROCKCHIP_HOST                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PCIE_UNIPHIER                            policy<{'armhf': 'y'}>
+CONFIG_PCIE_XILINX                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCIE_XILINX_NWL                          policy<{'arm64': 'y'}>
+CONFIG_PCIPCWATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PCI_AARDVARK                             policy<{'arm64': 'y'}>
+CONFIG_PCI_ATMEL                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PCI_ATS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_BIOS                                 policy<{'i386': 'y'}>
+CONFIG_PCI_BRIDGE_EMUL                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCI_CNB20LE_QUIRK                        policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_PCI_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCI_DIRECT                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_DOMAINS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_DOMAINS_GENERIC                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCI_DRA7XX                               policy<{'armhf': 'y'}>
+CONFIG_PCI_DRA7XX_EP                            policy<{'armhf': 'y'}>
+CONFIG_PCI_DRA7XX_HOST                          policy<{'armhf': 'y'}>
+CONFIG_PCI_ECAM                                 policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCI_ENDPOINT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_ENDPOINT_CONFIGFS                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_ENDPOINT_TEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCI_EPF_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PCI_FTPCI100                             policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCI_GOANY                                policy<{'i386': 'y'}>
+CONFIG_PCI_GOBIOS                               policy<{'i386': 'n'}>
+CONFIG_PCI_GODIRECT                             policy<{'i386': 'n'}>
+CONFIG_PCI_GOMMCONFIG                           policy<{'i386': 'n'}>
+CONFIG_PCI_HISI                                 policy<{'arm64': 'y'}>
+CONFIG_PCI_HOST_COMMON                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCI_HOST_GENERIC                         policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCI_HOST_THUNDER_ECAM                    policy<{'arm64': 'y'}>
+CONFIG_PCI_HOST_THUNDER_PEM                     policy<{'arm64': 'y'}>
+CONFIG_PCI_HYPERV                               policy<{'amd64': 'm'}>
+CONFIG_PCI_HYPERV_INTERFACE                     policy<{'amd64': 'm'}>
+CONFIG_PCI_IMX6                                 policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_PCI_IOV                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_KEYSTONE                             policy<{'arm64': 'y'}>
+CONFIG_PCI_KEYSTONE_EP                          policy<{'arm64': 'y'}>
+CONFIG_PCI_KEYSTONE_HOST                        policy<{'arm64': 'y'}>
+CONFIG_PCI_LABEL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCI_LAYERSCAPE                           policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_PCI_LAYERSCAPE_EP                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PCI_LOCKLESS_CONFIG                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_MESON                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n'}>
+CONFIG_PCI_MMCONFIG                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_MSI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_MSI_IRQ_DOMAIN                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PCI_MVEBU                                policy<{'armhf': 'y'}>
+CONFIG_PCI_P2PDMA                               policy<{'amd64': 'n', 'ppc64el': 'n'}>
+CONFIG_PCI_PASID                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCI_PF_STUB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PCI_PRI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCI_QUIRKS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PCI_RCAR_GEN2                            policy<{'armhf': 'y'}>
+CONFIG_PCI_REALLOC_ENABLE_AUTO                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PCI_STUB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PCI_SW_SWITCHTEC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PCI_SYSCALL                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PCI_TEGRA                                policy<{'armhf-generic': 'y'}>
+CONFIG_PCI_V3_SEMI                              policy<{'armhf': 'y'}>
+CONFIG_PCI_XEN                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCI_XGENE                                policy<{'arm64': 'y'}>
+CONFIG_PCI_XGENE_MSI                            policy<{'arm64': 'y'}>
+CONFIG_PCMCIA                                   policy<{'amd64': 'm', 'arm64': 'n', 'i386': 'm'}>
+CONFIG_PCMCIA_3C574                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_3C589                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_AHA152X                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_ATMEL                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_AXNET                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_FDOMAIN                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_FMVJ18X                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_HERMES                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_LOAD_CIS                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PCMCIA_NINJA_SCSI                        policy<{'i386': 'm'}>
+CONFIG_PCMCIA_NMCLAN                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_PCNET                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_PROBE                             policy<{'i386': 'y'}>
+CONFIG_PCMCIA_QLOGIC                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_RAYCS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_SMC91C92                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_SPECTRUM                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_SYM53C500                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_WL3501                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_XIRC2PS                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PCMCIA_XIRCOM                            policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_PCNET32                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PCSPKR_PLATFORM                          policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PCWATCHDOG                               policy<{'i386': 'm'}>
+CONFIG_PD6729                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PDA_POWER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PDC_ADMA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PEAQ_WMI                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PERCPU_STATS                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PERCPU_TEST                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PERF_EVENTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PERF_EVENTS_AMD_POWER                    policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_PERF_EVENTS_INTEL_CSTATE                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PERF_EVENTS_INTEL_RAPL                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PERF_EVENTS_INTEL_UNCORE                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PERF_USE_VMALLOC                         policy<{'armhf': 'y'}>
+CONFIG_PERSISTENT_KEYRINGS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PFAULT                                   policy<{'s390x': 'y'}>
+CONFIG_PGSTE                                    policy<{'s390x': 'y'}>
+CONFIG_PGTABLE_LEVELS                           policy<{'amd64': '4', 'arm64': '4', 'armhf-generic': '2', 'armhf-generic-lpae': '3', 'i386': '3', 'ppc64el': '4', 's390x': '5'}>
+CONFIG_PHANTOM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHONET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHYLIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_PHYLINK                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHYSICAL_ALIGN                           policy<{'amd64': '0x200000', 'i386': '0x1000000'}>
+CONFIG_PHYSICAL_START                           policy<{'amd64': '0x1000000', 'i386': '0x1000000', 'ppc64el': '0x00000000'}>
+CONFIG_PHYS_ADDR_T_64BIT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PHY_AM654_SERDES                         policy<{'arm64': 'm'}>
+CONFIG_PHY_BCM_NS_USB2                          policy<{'arm64': 'm'}>
+CONFIG_PHY_BCM_NS_USB3                          policy<{'arm64': 'm'}>
+CONFIG_PHY_BCM_SR_PCIE                          policy<{'arm64': 'm'}>
+CONFIG_PHY_BCM_SR_USB                           policy<{'arm64': 'm'}>
+CONFIG_PHY_BERLIN_SATA                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_BERLIN_USB                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_BRCM_SATA                            policy<{'arm64': 'y'}>
+CONFIG_PHY_BRCM_USB                             policy<{'arm64': 'm'}>
+CONFIG_PHY_CADENCE_DP                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_CADENCE_DPHY                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_CADENCE_SIERRA                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_CPCAP_USB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_DM816X_USB                           policy<{'armhf': 'm'}>
+CONFIG_PHY_EXYNOS5250_SATA                      policy<{'armhf': 'y'}>
+CONFIG_PHY_EXYNOS5250_USB2                      policy<{'armhf': 'y'}>
+CONFIG_PHY_EXYNOS5_USBDRD                       policy<{'armhf': 'm'}>
+CONFIG_PHY_EXYNOS_DP_VIDEO                      policy<{'armhf': 'y'}>
+CONFIG_PHY_EXYNOS_MIPI_VIDEO                    policy<{'armhf': 'y'}>
+CONFIG_PHY_EXYNOS_PCIE                          policy<{'armhf': 'y'}>
+CONFIG_PHY_FSL_IMX8MQ_USB                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_HI3660_USB                           policy<{'arm64': 'm'}>
+CONFIG_PHY_HI6220_USB                           policy<{'arm64': 'm'}>
+CONFIG_PHY_HISI_INNO_USB2                       policy<{'arm64': 'm'}>
+CONFIG_PHY_HISTB_COMBPHY                        policy<{'arm64': 'm'}>
+CONFIG_PHY_HIX5HD2_SATA                         policy<{'armhf': 'm'}>
+CONFIG_PHY_MAPPHONE_MDM6600                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_MESON8B_USB2                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MESON_G12A_USB2                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MESON_G12A_USB3_PCIE                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MESON_GXL_USB2                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MESON_GXL_USB3                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MIXEL_MIPI_DPHY                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_MTK_TPHY                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MTK_UFS                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MTK_XSPHY                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MVEBU_A3700_COMPHY                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MVEBU_A3700_UTMI                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MVEBU_A38X_COMPHY                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MVEBU_CP110_COMPHY                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_MVEBU_SATA                           policy<{'armhf': 'y'}>
+CONFIG_PHY_NS2_PCIE                             policy<{'arm64': 'y'}>
+CONFIG_PHY_NS2_USB_DRD                          policy<{'arm64': 'm'}>
+CONFIG_PHY_OCELOT_SERDES                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_PXA_28NM_HSIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHY_PXA_28NM_USB2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PHY_QCOM_APQ8064_SATA                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_IPQ806X_SATA                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_PCIE2                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_QMP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_QUSB2                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_UFS                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_UFS_14NM                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_QCOM_USB_HS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_QCOM_USB_HSIC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_RCAR_GEN2                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_RCAR_GEN3_PCIE                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_RCAR_GEN3_USB2                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_RCAR_GEN3_USB3                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_DP                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_EMMC                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_INNO_HDMI                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_INNO_USB2                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_PCIE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_TYPEC                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_ROCKCHIP_USB                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PHY_SAMSUNG_USB2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_SUN4I_USB                            policy<{'arm64': 'm'}>
+CONFIG_PHY_SUN6I_MIPI_DPHY                      policy<{'arm64': 'm'}>
+CONFIG_PHY_SUN9I_USB                            policy<{'arm64': 'n'}>
+CONFIG_PHY_TEGRA_XUSB                           policy<{'armhf-generic': 'm'}>
+CONFIG_PHY_TI_GMII_SEL                          policy<{'armhf': 'y'}>
+CONFIG_PHY_TUSB1210                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PHY_UNIPHIER_PCIE                        policy<{'armhf': 'm'}>
+CONFIG_PHY_UNIPHIER_USB2                        policy<{'armhf': 'm'}>
+CONFIG_PHY_UNIPHIER_USB3                        policy<{'armhf': 'm'}>
+CONFIG_PHY_XGENE                                policy<{'arm64': 'y'}>
+CONFIG_PI433                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PID_IN_CONTEXTIDR                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_PID_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PINCONF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PINCTRL_AMD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_APQ8064                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_APQ8084                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_ARMADA_370                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_ARMADA_375                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_ARMADA_37XX                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_ARMADA_38X                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_ARMADA_39X                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_ARMADA_AP806                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_ARMADA_CP110                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_ARMADA_XP                        policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_AS370                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_AS3722                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_ASPEED                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_ASPEED_G6                        policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_AXP209                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_BAYTRAIL                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PINCTRL_BCM2835                          policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_BERLIN                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_BERLIN_BG2                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_BERLIN_BG2CD                     policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_BERLIN_BG2Q                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_BERLIN_BG4CT                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_BM1880                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_BROXTON                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_CANNONLAKE                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_CEDARFORK                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_CS47L15                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_CS47L35                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_CS47L85                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_CS47L90                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_CS47L92                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_DENVERTON                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_DOVE                             policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_EXYNOS                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_EXYNOS_ARM                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_GEMINILAKE                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_ICELAKE                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_IMX                              policy<{'arm64': 'y', 'armhf-generic': '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_IMX6SLL                          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_IMX7ULP                          policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_IMX8MM                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_IMX8MN                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_IMX8MQ                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_IMX8QM                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_IMX8QXP                          policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_IMX_SCU                          policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_INTEL                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_IPQ4019                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_IPQ8064                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_IPQ8074                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_IPROC_GPIO                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_LEWISBURG                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_LOCHNAGAR                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_MADERA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_MAX77620                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_MCP23S08                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_MDM9615                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MERRIFIELD                       policy<{'i386': 'n'}>
+CONFIG_PINCTRL_MESON                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MESON8                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MESON8B                          policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MESON8_PMX                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MESON_AXG                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MESON_AXG_PMX                    policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MESON_G12A                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MESON_GXBB                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MESON_GXL                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MSM                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MSM8660                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8916                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8960                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8994                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8996                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8998                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MSM8X74                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_MT2701                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MT2712                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT6397                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MT6765                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT6797                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT7622                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT7623                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MT7629                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MT8127                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MT8135                           policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_MT8173                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT8183                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MT8516                           policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MTK                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MTK_MOORE                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_MTK_PARIS                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_MVEBU                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_NPCM7XX                          policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_NS2_MUX                          policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_OCELOT                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_OWL                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_PALMAS                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_PFC_EMEV2                        policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7740                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7743                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7744                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7745                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77470                     policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A774A1                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A774C0                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7778                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7779                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7790                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7791                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7792                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7793                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7794                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7795                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A7796                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77965                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77970                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77980                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77990                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_R8A77995                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_PFC_SH73A0                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_QCOM_SPMI_PMIC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_QCOM_SSBI_PMIC                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_QCS404                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_QDF2XXX                          policy<{'arm64': 'm'}>
+CONFIG_PINCTRL_RK805                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_ROCKCHIP                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_RZA1                             policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_RZA2                             policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_RZN1                             policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_S700                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_S900                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_SAMSUNG                          policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_SC7180                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_SDM660                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_SDM845                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_SH_PFC                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PINCTRL_SH_PFC_GPIO                      policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_SINGLE                           policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_SM8150                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PINCTRL_SPRD                             policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SPRD_SC9860                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_STMFX                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PINCTRL_SUN4I_A10                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN50I_A64                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN50I_A64_R                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN50I_H5                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN50I_H6                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN50I_H6_R                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN5I                            policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN6I_A31                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN6I_A31_R                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_A23                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_A23_R                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_A33                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_A83T                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_A83T_R                     policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_H3                         policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_H3_R                       policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN8I_V3S                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN9I_A80                        policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUN9I_A80_R                      policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SUNRISEPOINT                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PINCTRL_SUNXI                            policy<{'arm64': 'y'}>
+CONFIG_PINCTRL_SX150X                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PINCTRL_TEGRA                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TEGRA114                         policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TEGRA124                         policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TEGRA20                          policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TEGRA30                          policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TEGRA_XUSB                       policy<{'armhf-generic': 'y'}>
+CONFIG_PINCTRL_TI_IODELAY                       policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER                         policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_LD11                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_LD20                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_LD4                     policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_LD6B                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_PRO4                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_PRO5                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_PXS2                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_PXS3                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_UNIPHIER_SLD8                    policy<{'armhf': 'y'}>
+CONFIG_PINCTRL_VF610                            policy<{'armhf-generic': 'y'}>
+CONFIG_PINMUX                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PJ4B_ERRATA_4742                         policy<{'armhf': 'y'}>
+CONFIG_PKCS7_MESSAGE_PARSER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PKCS7_TEST_KEY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PKCS8_PRIVATE_KEY_PARSER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PKEY                                     policy<{'s390x': 'm'}>
+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'}>
+CONFIG_PL320_MBOX                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_PL330_DMA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PL353_SMC                                policy<{'armhf': 'm'}>
+CONFIG_PLATFORM_MHU                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PLATFORM_SI4713                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PLAT_ORION                               policy<{'armhf': 'y'}>
+CONFIG_PLAT_SAMSUNG                             policy<{'armhf': 'y'}>
+CONFIG_PLAT_SPEAR                               policy<{'armhf': 'n'}>
+CONFIG_PLAT_VERSATILE                           policy<{'armhf': 'y'}>
+CONFIG_PLIP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PLUGIN_HOSTCC                            policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_PLX_HERMES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PM8916_WATCHDOG                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PMBUS                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PMC_ATOM                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PMIC_ADP5520                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PMIC_DA903X                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PMIC_DA9052                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PMIC_OPREGION                            policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_PMS7003                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PM_ADVANCED_DEBUG                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_AUTOSLEEP                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PM_CLK                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_PM_DEBUG                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_DEVFREQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PM_DEVFREQ_EVENT                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_GENERIC_DOMAINS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_GENERIC_DOMAINS_OF                    policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_GENERIC_DOMAINS_SLEEP                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_NOTIFIER_ERROR_INJECT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PM_OPP                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_SLEEP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_SLEEP_DEBUG                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_SLEEP_SMP                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_SLEEP_SMP_NONZERO_CPU                 policy<{'ppc64el': 'y'}>
+CONFIG_PM_STD_PARTITION                         policy<{'amd64': '""', 'armhf': '""', 'i386': '""'}>
+CONFIG_PM_TEST_SUSPEND                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PM_TRACE                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PM_TRACE_RTC                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PM_WAKELOCKS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_WAKELOCKS_GC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PM_WAKELOCKS_LIMIT                       policy<{'amd64': '100', 'arm64': '100', 'armhf': '100', 'i386': '100', 'ppc64el': '100'}>
+CONFIG_PNFS_BLOCK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PNFS_FILE_LAYOUT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PNFS_FLEXFILE_LAYOUT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PNP                                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PNPACPI                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_PNPBIOS                                  policy<{'i386': 'y'}>
+CONFIG_PNPBIOS_PROC_FS                          policy<{'i386': 'y'}>
+CONFIG_PNP_DEBUG_MESSAGES                       policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_POSIX_MQUEUE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POSIX_MQUEUE_SYSCTL                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POSIX_TIMERS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POWER7_CPU                               policy<{'ppc64el': 'n'}>
+CONFIG_POWER8_CPU                               policy<{'ppc64el': 'n'}>
+CONFIG_POWER9_CPU                               policy<{'ppc64el': 'n'}>
+CONFIG_POWERCAP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_POWERNV_CPUFREQ                          policy<{'ppc64el': 'y'}>
+CONFIG_POWERNV_CPUIDLE                          policy<{'ppc64el': 'y'}>
+CONFIG_POWERNV_OP_PANEL                         policy<{'ppc64el': 'm'}>
+CONFIG_POWER_AVS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_POWER_AVS_OMAP                           policy<{'armhf-generic': 'y'}>
+CONFIG_POWER_AVS_OMAP_CLASS3                    policy<{'armhf-generic': 'y'}>
+CONFIG_POWER_RESET                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POWER_RESET_AS3722                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_AXXIA                        policy<{'armhf-generic-lpae': 'y'}>
+CONFIG_POWER_RESET_BRCMKONA                     policy<{'armhf': 'y'}>
+CONFIG_POWER_RESET_BRCMSTB                      policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_POWER_RESET_GPIO                         policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_GPIO_RESTART                 policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_HISI                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_POWER_RESET_LTC2952                      policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_MSM                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_POWER_RESET_QCOM_PON                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_POWER_RESET_QNAP                         policy<{'armhf': 'n'}>
+CONFIG_POWER_RESET_RESTART                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_POWER_RESET_RMOBILE                      policy<{'armhf': 'm'}>
+CONFIG_POWER_RESET_SC27XX                       policy<{'arm64': 'y'}>
+CONFIG_POWER_RESET_SYSCON                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_POWER_RESET_SYSCON_POWEROFF              policy<{'arm64': 'y', 'armhf': '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_SUPPLY                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_POWER_SUPPLY_DEBUG                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_POWER_SUPPLY_HWMON                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PPC                                      policy<{'ppc64el': 'y'}>
+CONFIG_PPC64                                    policy<{'ppc64el': 'y'}>
+CONFIG_PPC64_BOOT_WRAPPER                       policy<{'ppc64el': 'y'}>
+CONFIG_PPC64_SUPPORTS_MEMORY_FAILURE            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_4K_PAGES                             policy<{'ppc64el': 'n'}>
+CONFIG_PPC_64K_PAGES                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_BARRIER_NOSPEC                       policy<{'ppc64el': 'y'}>
+CONFIG_PPC_BOOK3E_64                            policy<{'ppc64el': 'n'}>
+CONFIG_PPC_BOOK3S                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_BOOK3S_64                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_COPRO_BASE                           policy<{'ppc64el': 'y'}>
+CONFIG_PPC_DAWR                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_DENORMALISATION                      policy<{'ppc64el': 'y'}>
+CONFIG_PPC_DISABLE_WERROR                       policy<{'ppc64el': 'n'}>
+CONFIG_PPC_DOORBELL                             policy<{'ppc64el': 'y'}>
+CONFIG_PPC_DT_CPU_FTRS                          policy<{'ppc64el': 'y'}>
+CONFIG_PPC_EARLY_DEBUG                          policy<{'ppc64el': 'n'}>
+CONFIG_PPC_EMULATED_STATS                       policy<{'ppc64el': 'n'}>
+CONFIG_PPC_EPAPR_HV_BYTECHAN                    policy<{'ppc64el': 'n'}>
+CONFIG_PPC_FAST_ENDIAN_SWITCH                   policy<{'ppc64el': 'n'}>
+CONFIG_PPC_FPU                                  policy<{'ppc64el': 'y'}>
+CONFIG_PPC_HAVE_KUAP                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_HAVE_KUEP                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_HAVE_PMU_SUPPORT                     policy<{'ppc64el': 'y'}>
+CONFIG_PPC_I8259                                policy<{'ppc64el': 'y'}>
+CONFIG_PPC_ICP_HV                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_ICP_NATIVE                           policy<{'ppc64el': 'y'}>
+CONFIG_PPC_ICS_RTAS                             policy<{'ppc64el': 'y'}>
+CONFIG_PPC_INDIRECT_PIO                         policy<{'ppc64el': 'y'}>
+CONFIG_PPC_IRQ_SOFT_MASK_DEBUG                  policy<{'ppc64el': 'n'}>
+CONFIG_PPC_KUAP                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_KUAP_DEBUG                           policy<{'ppc64el': 'n'}>
+CONFIG_PPC_KUEP                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_MEMTRACE                             policy<{'ppc64el': 'y'}>
+CONFIG_PPC_MM_SLICES                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_MSI_BITMAP                           policy<{'ppc64el': 'y'}>
+CONFIG_PPC_NATIVE                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_OF_BOOT_TRAMPOLINE                   policy<{'ppc64el': 'y'}>
+CONFIG_PPC_P7_NAP                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_PAGE_SHIFT                           policy<{'ppc64el': '16'}>
+CONFIG_PPC_PERF_CTRS                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_POWERNV                              policy<{'ppc64el': 'y'}>
+CONFIG_PPC_PSERIES                              policy<{'ppc64el': 'y'}>
+CONFIG_PPC_PTDUMP                               policy<{'ppc64el': 'n'}>
+CONFIG_PPC_RADIX_MMU                            policy<{'ppc64el': 'y'}>
+CONFIG_PPC_RADIX_MMU_DEFAULT                    policy<{'ppc64el': 'y'}>
+CONFIG_PPC_RTAS                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_RTAS_DAEMON                          policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SMLPAR                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SMP_MUXED_IPI                        policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SPLPAR                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SUBPAGE_PROT                         policy<{'ppc64el': 'y'}>
+CONFIG_PPC_SVM                                  policy<{'ppc64el': 'y'}>
+CONFIG_PPC_TRANSACTIONAL_MEM                    policy<{'ppc64el': 'y'}>
+CONFIG_PPC_UDBG_16550                           policy<{'ppc64el': 'y'}>
+CONFIG_PPC_VAS                                  policy<{'ppc64el': 'y'}>
+CONFIG_PPC_WATCHDOG                             policy<{'ppc64el': 'y'}>
+CONFIG_PPC_WERROR                               policy<{'ppc64el': 'y'}>
+CONFIG_PPC_XICS                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_XIVE                                 policy<{'ppc64el': 'y'}>
+CONFIG_PPC_XIVE_NATIVE                          policy<{'ppc64el': 'y'}>
+CONFIG_PPC_XIVE_SPAPR                           policy<{'ppc64el': 'y'}>
+CONFIG_PPDEV                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PPPOATM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPPOE                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPPOL2TP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_ASYNC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_BSDCOMP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_DEFLATE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_FILTER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PPP_MPPE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPP_MULTILINK                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PPP_SYNC_TTY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_PPS_CLIENT_GPIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_KTIMER                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_LDISC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_PPS_CLIENT_PARPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PPS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PPTP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PREEMPT                                  policy<{'amd64-generic': 'n', 'amd64-lowlatency': 'y', 'arm64': 'n', 'armhf': 'n', 'i386-generic': 'n', 'i386-lowlatency': 'y', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PREEMPTION                               policy<{'amd64-lowlatency': 'y', 'i386-lowlatency': 'y'}>
+CONFIG_PREEMPTIRQ_DELAY_TEST                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PREEMPTIRQ_EVENTS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PREEMPT_COUNT                            policy<{'amd64-lowlatency': 'y', 'i386-lowlatency': 'y'}>
+CONFIG_PREEMPT_NOTIFIERS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PREEMPT_RCU                              policy<{'amd64-lowlatency': 'y', 'i386-lowlatency': 'y'}>
+CONFIG_PREEMPT_TRACER                           policy<{'amd64-lowlatency': 'n', 'i386-lowlatency': 'n'}>
+CONFIG_PREEMPT_VOLUNTARY                        policy<{'amd64-generic': 'y', 'amd64-lowlatency': 'n', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'i386-lowlatency': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PREVENT_FIRMWARE_BUILD                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINTER                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PRINTK                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINTK_CALLER                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PRINTK_NMI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT                policy<{'amd64': '13', 'arm64': '13', 'armhf': '13', 'i386': '13', 'ppc64el': '13', 's390x': '13'}>
+CONFIG_PRINTK_TIME                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PRINT_QUOTA_WARNING                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PRINT_STACK_DEPTH                        policy<{'ppc64el': '64'}>
+CONFIG_PRISM2_USB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PRISM54                                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PROBE_EVENTS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROCESSOR_SELECT                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PROC_CHILDREN                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_EVENTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_FS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_KCORE                               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_PAGE_MONITOR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_PID_ARCH_STATUS                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PROC_PID_CPUSET                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_SYSCTL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_THERMAL_MMIO_RAPL                   policy<{'amd64': 'y'}>
+CONFIG_PROC_VMCORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROC_VMCORE_DEVICE_DUMP                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROFILE_ANNOTATED_BRANCHES               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PROFILING                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PROTECTED_VIRTUALIZATION_GUEST           policy<{'s390x': 'y'}>
+CONFIG_PROVE_LOCKING                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_PROVIDE_OHCI1394_DMA_INIT                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_PSAMPLE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_PSERIES_CPUIDLE                          policy<{'ppc64el': 'y'}>
+CONFIG_PSERIES_ENERGY                           policy<{'ppc64el': 'm'}>
+CONFIG_PSI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_PSTORE                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PSTORE_842_COMPRESS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_COMPRESS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PSTORE_COMPRESS_DEFAULT                  policy<{'amd64': '"deflate"', 'arm64': '"deflate"', 'armhf': '"deflate"', 'i386': '"deflate"', 'ppc64el': '"deflate"'}>
+CONFIG_PSTORE_CONSOLE                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_DEFLATE_COMPRESS                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PSTORE_FTRACE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_LZ4HC_COMPRESS                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_LZ4_COMPRESS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_LZO_COMPRESS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_PMSG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PSTORE_RAM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PSTORE_ZSTD_COMPRESS                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_PTP_1588_CLOCK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_PTP_1588_CLOCK_DTE                       policy<{'arm64': 'm'}>
+CONFIG_PTP_1588_CLOCK_KVM                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PTP_1588_CLOCK_PCH                       policy<{'i386': 'm'}>
+CONFIG_PTP_1588_CLOCK_QORIQ                     policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_PUNIT_ATOM_DEBUG                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_PVH                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PVPANIC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_PWM_ATMEL_HLCDC_PWM                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_BCM2835                              policy<{'arm64': 'm'}>
+CONFIG_PWM_BCM_IPROC                            policy<{'arm64': 'm'}>
+CONFIG_PWM_BERLIN                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_BRCMSTB                              policy<{'arm64': 'm'}>
+CONFIG_PWM_CRC                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PWM_CROS_EC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_PWM_FSL_FTM                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_HIBVT                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_IMX1                                 policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_PWM_IMX27                                policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_PWM_IMX_TPM                              policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_PWM_LP3943                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_LPSS                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PWM_LPSS_PCI                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PWM_LPSS_PLATFORM                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_PWM_MEDIATEK                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_MESON                                policy<{'arm64': 'm', 'armhf': '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', 'ppc64el': 'm'}>
+CONFIG_PWM_RCAR                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_RENESAS_TPU                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_ROCKCHIP                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_PWM_SAMSUNG                              policy<{'armhf': 'm'}>
+CONFIG_PWM_SPRD                                 policy<{'arm64': 'm'}>
+CONFIG_PWM_STMPE                                policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_PWM_SUN4I                                policy<{'arm64': 'm'}>
+CONFIG_PWM_SYSFS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_PWM_TEGRA                                policy<{'armhf-generic': 'm'}>
+CONFIG_PWM_TIECAP                               policy<{'arm64': 'm', 'armhf-generic': 'm', 'armhf-generic-lpae': 'n'}>
+CONFIG_PWM_TIEHRPWM                             policy<{'arm64': 'm', 'armhf-generic': 'm', 'armhf-generic-lpae': 'n'}>
+CONFIG_PWM_TIPWMSS                              policy<{'armhf-generic': 'y'}>
+CONFIG_PWM_TWL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PWM_TWL_LED                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_PWRSEQ_EMMC                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PWRSEQ_SD8787                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PWRSEQ_SIMPLE                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_PXA168_ETH                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCA7000                                  policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_QCA7000_SPI                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_QCA7000_UART                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_A53PLL                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_AOSS_QMP                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_APCS_IPC                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_APR                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_BAM_DMA                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_CLK_APCS_MSM8916                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_CLK_RPM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_CLK_RPMH                            policy<{'arm64': 'm'}>
+CONFIG_QCOM_CLK_SMD_RPM                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_COINCELL                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_COMMAND_DB                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_EBI2                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_EMAC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_FALKOR_ERRATUM_1003                 policy<{'arm64': 'y'}>
+CONFIG_QCOM_FALKOR_ERRATUM_1009                 policy<{'arm64': 'y'}>
+CONFIG_QCOM_FALKOR_ERRATUM_E1041                policy<{'arm64': 'y'}>
+CONFIG_QCOM_FASTRPC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_GDSC                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_GENI_SE                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_GLINK_SSR                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_GSBI                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_HFPLL                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_HIDMA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_HIDMA_MGMT                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_IOMMU                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_IRQ_COMBINER                        policy<{'arm64': 'y'}>
+CONFIG_QCOM_L2_PMU                              policy<{'arm64': 'y'}>
+CONFIG_QCOM_L3_PMU                              policy<{'arm64': 'y'}>
+CONFIG_QCOM_LLCC                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_MDT_LOADER                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_PDC                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_PM                                  policy<{'armhf': 'y'}>
+CONFIG_QCOM_PM8XXX_XOADC                        policy<{'armhf': 'm'}>
+CONFIG_QCOM_Q6V5_ADSP                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_Q6V5_COMMON                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_Q6V5_MSS                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_Q6V5_PAS                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_Q6V5_WCSS                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_QFPROM                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_QMI_HELPERS                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_RMTFS_MEM                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_RPMCC                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_RPMH                                policy<{'arm64': 'y'}>
+CONFIG_QCOM_RPMHPD                              policy<{'arm64': 'y'}>
+CONFIG_QCOM_RPROC_COMMON                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SCM                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_SCM_32                              policy<{'armhf': 'y'}>
+CONFIG_QCOM_SCM_64                              policy<{'arm64': 'y'}>
+CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QCOM_SMD_RPM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SMEM                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SMEM_STATE                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_QCOM_SMP2P                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SMSM                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SOCINFO                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SPMI_ADC5                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_SPMI_IADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_SPMI_TEMP_ALARM                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_SPMI_VADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_SYSMON                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_TSENS                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_VADC_COMMON                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QCOM_WCNSS_CTRL                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCOM_WCNSS_PIL                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_QCOM_WDT                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCS_GCC_404                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QCS_TURING_404                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QDIO                                     policy<{'s390x': 'm'}>
+CONFIG_QED                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QEDE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QEDF                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QEDI                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QED_FCOE                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QED_ISCSI                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QED_LL2                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QED_OOO                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QED_RDMA                                 policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_QED_SRIOV                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QETH                                     policy<{'s390x': 'm'}>
+CONFIG_QETH_L2                                  policy<{'s390x': 'm'}>
+CONFIG_QETH_L3                                  policy<{'s390x': 'm'}>
+CONFIG_QFMT_V1                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_QFMT_V2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_QLA3XXX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QLCNIC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QLCNIC_DCB                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QLCNIC_HWMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QLCNIC_SRIOV                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_QLGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QNX4FS_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QNX6FS_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_QNX6FS_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_QORIQ_CPUFREQ                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QORIQ_THERMAL                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_QRTR                                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QRTR_SMD                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QRTR_TUN                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_QSEMI_PHY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_QTNFMAC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QTNFMAC_PCIE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_QUEUED_RWLOCKS                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_QUEUED_SPINLOCKS                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_QUOTA                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_QUOTACTL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_QUOTACTL_COMPAT                          policy<{'amd64': 'y'}>
+CONFIG_QUOTA_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_QUOTA_NETLINK_INTERFACE                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_QUOTA_TREE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_R6040                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_R8169                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_R8188EU                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_R8712U                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_ADAPTERS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RADIO_AZTECH                             policy<{'i386': 'm'}>
+CONFIG_RADIO_CADET                              policy<{'i386': 'm'}>
+CONFIG_RADIO_GEMTEK                             policy<{'i386': 'm'}>
+CONFIG_RADIO_ISA                                policy<{'i386': 'm'}>
+CONFIG_RADIO_MAXIRADIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_MIROPCM20                          policy<{'i386': 'm'}>
+CONFIG_RADIO_RTRACK                             policy<{'i386': 'm'}>
+CONFIG_RADIO_RTRACK2                            policy<{'i386': 'm'}>
+CONFIG_RADIO_SAA7706H                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SF16FMI                            policy<{'i386': 'm'}>
+CONFIG_RADIO_SF16FMR2                           policy<{'i386': 'm'}>
+CONFIG_RADIO_SHARK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SHARK2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SI470X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SI4713                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_SI476X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TEA575X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TEA5764                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TEF6862                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_TERRATEC                           policy<{'i386': 'm'}>
+CONFIG_RADIO_TIMBERDALE                         policy<{'i386': 'm'}>
+CONFIG_RADIO_TRUST                              policy<{'i386': 'm'}>
+CONFIG_RADIO_TYPHOON                            policy<{'i386': 'm'}>
+CONFIG_RADIO_WL1273                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_WL128X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RADIO_ZOLTRIX                            policy<{'i386': 'm'}>
+CONFIG_RAID6_PQ                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RAID6_PQ_BENCHMARK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RAID_ATTRS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RANDOM32_SELFTEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RANDOMIZE_BASE                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_RANDOMIZE_MEMORY                         policy<{'amd64': 'y'}>
+CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING        policy<{'amd64': '0xa'}>
+CONFIG_RANDOMIZE_MODULE_REGION_FULL             policy<{'arm64': 'y'}>
+CONFIG_RANDOM_TRUST_BOOTLOADER                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RANDOM_TRUST_CPU                         policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RAPIDIO                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_RAPIDIO_CHMAN                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_CPS_GEN2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_CPS_XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RAPIDIO_DISC_TIMEOUT                     policy<{'amd64': '30', 'arm64': '30', 'armhf': '30', 'i386': '30', 'ppc64el': '30'}>
+CONFIG_RAPIDIO_DMA_ENGINE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RAPIDIO_ENUM_BASIC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_MPORT_CDEV                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_RXS_GEN3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_TSI568                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_TSI57X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAPIDIO_TSI721                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_RAS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RASPBERRYPI_FIRMWARE                     policy<{'arm64': 'y'}>
+CONFIG_RASPBERRYPI_POWER                        policy<{'arm64': 'y'}>
+CONFIG_RAS_CEC                                  policy<{'amd64': 'y'}>
+CONFIG_RAS_CEC_DEBUG                            policy<{'amd64': 'n'}>
+CONFIG_RATIONAL                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RAVB                                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RAVE_SP_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_RAVE_SP_EEPROM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAVE_SP_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RAW_DRIVER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_RBTREE_TEST                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCAR_DMAC                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RCAR_GEN3_THERMAL                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RCAR_GYRO_ADC                            policy<{'armhf': 'm'}>
+CONFIG_RCAR_THERMAL                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RCU_CPU_STALL_TIMEOUT                    policy<{'amd64': '60', 'arm64': '60', 'armhf': '60', 'i386': '60', 'ppc64el': '21', 's390x': '21'}>
+CONFIG_RCU_EQS_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_EXPERT                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_NEED_SEGCBLIST                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RCU_PERF_TEST                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RCU_STALL_COMMON                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RCU_TORTURE_TEST                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RCU_TRACE                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RC_ATI_REMOTE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RC_CORE                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_RC_DECODERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RC_DEVICES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RC_LOOPBACK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RC_MAP                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RC_XBOX_DVD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RDA_INTC                                 policy<{'armhf': 'y'}>
+CONFIG_RDA_TIMER                                policy<{'armhf': 'y'}>
+CONFIG_RDMA_RXE                                 policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDMA_SIW                                 policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RDS_RDMA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RDS_TCP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RD_BZIP2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_GZIP                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZ4                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZMA                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_LZO                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RD_XZ                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_READABLE_ASM                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_READ_ONLY_THP_FOR_FS                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf-generic-lpae': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_REALTEK_AUTOPM                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REALTEK_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_REBOOT_MODE                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REED_SOLOMON                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REED_SOLOMON_DEC16                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REED_SOLOMON_DEC8                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REED_SOLOMON_ENC8                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REED_SOLOMON_TEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_REGMAP                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REGMAP_AC97                              policy<{'armhf-generic': 'm'}>
+CONFIG_REGMAP_I2C                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REGMAP_I3C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGMAP_IRQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REGMAP_MMIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REGMAP_SCCB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGMAP_SLIMBUS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGMAP_SPI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REGMAP_SPMI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGMAP_W1                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_REGULATOR_88PG86X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_88PM800                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_88PM8607                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AAT2870                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AB3100                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ACT8865                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ACT8945A                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AD5398                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ANATOP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ARIZONA_LDO1                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ARIZONA_MICSUPP                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AS3711                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AS3722                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_AXP20X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_BCM590XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_BD70528                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_BD718XX                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_BD9571MWV                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_CPCAP                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA903X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9052                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9055                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9062                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9063                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9210                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DA9211                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_REGULATOR_FAN53555                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_HI6421                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_HI6421V530                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_HI655X                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_ISL6271A                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_ISL9305                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LM363X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LOCHNAGAR                      policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP3971                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP3972                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP872X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP873X                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP8755                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP87565                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LP8788                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LTC3589                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_LTC3676                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX14577                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX1586                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77620                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77650                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77686                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77693                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX77802                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8649                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8660                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8907                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8925                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8952                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8973                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8997                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MAX8998                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MC13783                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MC13892                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MC13XXX_CORE                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MCP16502                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MT6311                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MT6323                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_MT6380                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_MT6397                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PALMAS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PBIAS                          policy<{'armhf': 'm'}>
+CONFIG_REGULATOR_PCAP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PCF50633                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PFUZE100                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PV88060                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PV88080                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PV88090                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_PWM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_QCOM_RPM                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_QCOM_RPMH                      policy<{'arm64': 'm'}>
+CONFIG_REGULATOR_QCOM_SMD_RPM                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_QCOM_SPMI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RC5T583                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RK808                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RN5T618                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_RT5033                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S2MPA01                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S2MPS11                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_S5M8767                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_SC2731                         policy<{'arm64': 'm'}>
+CONFIG_REGULATOR_SKY81452                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_SLG51000                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_STPMIC1                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_SY8106A                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_SY8824X                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TI_ABB                         policy<{'armhf': 'y'}>
+CONFIG_REGULATOR_TPS51632                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6105X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS62360                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65023                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6507X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65086                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65090                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65132                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65218                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6524X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS6586X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65910                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS65912                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_TPS80031                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_UNIPHIER                       policy<{'armhf': 'm'}>
+CONFIG_REGULATOR_USERSPACE_CONSUMER             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_VCTRL                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_VEXPRESS                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_REGULATOR_VIRTUAL_CONSUMER               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM831X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8350                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8400                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REGULATOR_WM8994                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_REISERFS_CHECK                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_REISERFS_FS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_REISERFS_FS_POSIX_ACL                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REISERFS_FS_SECURITY                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REISERFS_FS_XATTR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_REISERFS_PROC_INFO                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RELAY                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RELOCATABLE                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RELOCATABLE_TEST                         policy<{'ppc64el': 'n'}>
+CONFIG_REMOTEPROC                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_RENESAS_DMA                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RENESAS_INTC_IRQPIN                      policy<{'armhf': 'y'}>
+CONFIG_RENESAS_IRQC                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RENESAS_OSTM                             policy<{'armhf': 'y'}>
+CONFIG_RENESAS_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RENESAS_RZA1_IRQC                        policy<{'armhf': 'y'}>
+CONFIG_RENESAS_RZAWDT                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RENESAS_USB_DMAC                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RENESAS_WDT                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RESET_ATTACK_MITIGATION                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_RESET_BERLIN                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_BRCMSTB                            policy<{'arm64': 'm'}>
+CONFIG_RESET_CONTROLLER                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_RESET_HISI                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_IMX7                               policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_RESET_MESON                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_MESON_AUDIO_ARB                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RESET_QCOM_AOSS                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_QCOM_PDC                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RESET_SCMI                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RESET_SIMPLE                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RESET_SUNXI                              policy<{'arm64': 'y'}>
+CONFIG_RESET_TEGRA_BPMP                         policy<{'armhf-generic': 'y'}>
+CONFIG_RESET_TI_SCI                             policy<{'arm64': 'm'}>
+CONFIG_RESET_TI_SYSCON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RESET_UNIPHIER                           policy<{'armhf': 'm'}>
+CONFIG_RESET_UNIPHIER_GLUE                      policy<{'armhf': 'm'}>
+CONFIG_RETPOLINE                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_RETU_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RFD77402                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RFD_FTL                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RFKILL                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_RFKILL_GPIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RFKILL_INPUT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RFKILL_LEDS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RFS_ACCEL                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RING_BUFFER                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RING_BUFFER_ALLOW_SWAP                   policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RING_BUFFER_BENCHMARK                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RING_BUFFER_STARTUP_TEST                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_RIONET                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RIONET_RX_SIZE                           policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128'}>
+CONFIG_RIONET_TX_SIZE                           policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128'}>
+CONFIG_RMI4_2D_SENSOR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_RMI4_F03                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F03_SERIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RMI4_F11                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F12                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F30                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F34                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F54                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_F55                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RMI4_I2C                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RMI4_SMB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RMI4_SPI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RMNET                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RN5T618_WATCHDOG                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_ROCKCHIP_ANALOGIX_DP                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_CDN_DP                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_DW_HDMI                         policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_DW_MIPI_DSI                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_EFUSE                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_GRF                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_INNO_HDMI                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_IODOMAIN                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_IOMMU                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_LVDS                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_MBOX                            policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_PHY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ROCKCHIP_PM_DOMAINS                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_RGB                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_RK3066_HDMI                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKCHIP_SARADC                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_THERMAL                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_ROCKCHIP_TIMER                           policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_ROCKER                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ROCKETPORT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RODATA_FULL_DEFAULT_ENABLED              policy<{'arm64': 'y'}>
+CONFIG_ROMFS_BACKED_BY_BLOCK                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ROMFS_BACKED_BY_BOTH                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ROMFS_BACKED_BY_MTD                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ROMFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ROMFS_ON_BLOCK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ROSE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPCSEC_GSS_KRB5                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_RPMSG                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPMSG_CHAR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPMSG_QCOM_GLINK_NATIVE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPMSG_QCOM_GLINK_RPM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPMSG_QCOM_GLINK_SMEM                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RPMSG_QCOM_SMD                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RPMSG_VIRTIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_RPR0521                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RPS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RSEQ                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RSI_91X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RSI_COEX                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RSI_DEBUGFS                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RSI_SDIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RSI_USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RST_RCAR                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RT2400PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2500PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2500USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800PCI_RT3290                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT33XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT35XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800PCI_RT53XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800USB_RT33XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT3573                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT35XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT53XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_RT55XX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800USB_UNKNOWN                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2800_LIB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2800_LIB_MMIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00_DEBUG                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RT2X00_LIB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00_LIB_CRYPTO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2X00_LIB_DEBUGFS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RT2X00_LIB_FIRMWARE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2X00_LIB_LEDS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RT2X00_LIB_MMIO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00_LIB_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT2X00_LIB_USB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT61PCI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RT73USB                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTAS_ERROR_LOGGING                       policy<{'ppc64el': 'y'}>
+CONFIG_RTAS_FLASH                               policy<{'ppc64el': 'm'}>
+CONFIG_RTAS_PROC                                policy<{'ppc64el': 'y'}>
+CONFIG_RTC_CLASS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_88PM80X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_88PM860X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_AB3100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ABB5ZES3                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ABEOZ9                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ABX80X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_AM1805                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ARMADA38X                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_AS3722                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ASPEED                           policy<{'armhf': 'm'}>
+CONFIG_RTC_DRV_BD70528                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_BQ32K                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_BQ4802                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_BRCMSTB                          policy<{'arm64': 'm'}>
+CONFIG_RTC_DRV_CADENCE                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_CPCAP                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_CROS_EC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_RTC_DRV_DA9052                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DA9055                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DA9063                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1286                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1302                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1305                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1307                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1307_CENTURY                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_DS1343                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1347                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1374                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1374_WDT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_DS1390                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1511                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1553                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1672                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1685                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_DS1685_FAMILY                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS1689                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS17285                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS1742                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS17485                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS17885                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_DS2404                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS3232                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_DS3232_HWMON                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_EM3027                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_FM3130                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_FSL_FTM_ALARM                    policy<{'arm64': 'm'}>
+CONFIG_RTC_DRV_FTRTC010                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_GENERIC                          policy<{'ppc64el': 'y'}>
+CONFIG_RTC_DRV_HID_SENSOR_TIME                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_HYM8563                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_IMXDI                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_IMX_SC                           policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_ISL12022                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ISL12026                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_ISL1208                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_LP8788                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T80                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T80_WDT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_M41T93                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M41T94                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T35                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T59                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_M48T86                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX6900                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX6902                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX6916                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX77686                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8907                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8925                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8997                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MAX8998                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MC13XXX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MCP795                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MESON                            policy<{'armhf': 'm'}>
+CONFIG_RTC_DRV_MESON_VRTC                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_MSM6242                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MT6397                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_MT7622                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_MV                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_RTC_DRV_MXC                              policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_MXC_V2                           policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_OMAP                             policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_OPAL                             policy<{'ppc64el': 'y'}>
+CONFIG_RTC_DRV_PALMAS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCAP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF2123                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF2127                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF50633                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF85063                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8523                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF85363                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8563                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PCF8583                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_PL030                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_PL031                            policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_RTC_DRV_PM8XXX                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_R7301                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_R9701                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RC5T583                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RK808                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RP5C01                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RS5C348                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RS5C372                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RTD119X                          policy<{'arm64': 'y'}>
+CONFIG_RTC_DRV_RV3028                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RV3029C2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RV3029_HWMON                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_DRV_RV8803                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX4581                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX6110                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX8010                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX8025                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_RX8581                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_S35390A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_S3C                              policy<{'armhf': 'y'}>
+CONFIG_RTC_DRV_S5M                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_SC27XX                           policy<{'arm64': 'm'}>
+CONFIG_RTC_DRV_SD3078                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_SH                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_RTC_DRV_SNVS                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_STK17TA8                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_SUN6I                            policy<{'arm64': 'y'}>
+CONFIG_RTC_DRV_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_RTC_DRV_TEST                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_DRV_TPS6586X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TPS65910                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_TPS80031                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_V3020                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_VRTC                             policy<{'i386': 'm'}>
+CONFIG_RTC_DRV_WILCO_EC                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_RTC_DRV_WM831X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_WM8350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_X1205                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_DRV_XGENE                            policy<{'arm64': 'y'}>
+CONFIG_RTC_DRV_ZYNQMP                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_RTC_HCTOSYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_HCTOSYS_DEVICE                       policy<{'amd64': '"rtc0"', 'arm64': '"rtc0"', 'armhf': '"rtc0"', 'i386': '"rtc0"', 'ppc64el': '"rtc0"'}>
+CONFIG_RTC_I2C_AND_SPI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_DEV                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_DEV_UIE_EMUL                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTC_INTF_PROC                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_INTF_SYSFS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_LIB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_MC146818_LIB                         policy<{'amd64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_NVMEM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_SYSTOHC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTC_SYSTOHC_DEVICE                       policy<{'amd64': '"rtc0"', 'arm64': '"rtc0"', 'armhf': '"rtc0"', 'i386': '"rtc0"', 'ppc64el': '"rtc0"'}>
+CONFIG_RTD119X_WATCHDOG                         policy<{'arm64': 'y'}>
+CONFIG_RTL8180                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8187                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8187_LEDS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTL8188EE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192CE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192CU                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192C_COMMON                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192DE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192E                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192EE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192SE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8192U                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723AE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723BE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723BS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8723_COMMON                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8821AE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8XXXU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL8XXXU_UNTESTED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTLBTCOEXIST                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_CCMP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_TKIP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLLIB_CRYPTO_WEP                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLWIFI                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLWIFI_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RTLWIFI_PCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTLWIFI_USB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTL_CARDS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTS5208                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTW88                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTW88_8723DE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTW88_8822BE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTW88_8822CE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTW88_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTW88_DEBUG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTW88_DEBUGFS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_RTW88_PCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_RTW88_REGD_USER_REG_HINTS                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_RT_MUTEXES                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RUNTIME_TESTING_MENU                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RWSEM_SPIN_ON_OWNER                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_RXKAD                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_S2IO                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_S390                                     policy<{'s390x': 'y'}>
+CONFIG_S390_AP_IOMMU                            policy<{'s390x': 'y'}>
+CONFIG_S390_CCW_IOMMU                           policy<{'s390x': 'y'}>
+CONFIG_S390_GUEST                               policy<{'s390x': 'y'}>
+CONFIG_S390_HYPFS_FS                            policy<{'s390x': 'y'}>
+CONFIG_S390_IOMMU                               policy<{'s390x': 'y'}>
+CONFIG_S390_PRNG                                policy<{'s390x': 'm'}>
+CONFIG_S390_PTDUMP                              policy<{'s390x': 'y'}>
+CONFIG_S390_TAPE                                policy<{'s390x': 'm'}>
+CONFIG_S390_TAPE_34XX                           policy<{'s390x': 'm'}>
+CONFIG_S390_TAPE_3590                           policy<{'s390x': 'm'}>
+CONFIG_S390_VMUR                                policy<{'s390x': 'm'}>
+CONFIG_S3C2410_WATCHDOG                         policy<{'armhf': 'm'}>
+CONFIG_S5P_DEV_MFC                              policy<{'armhf': 'y'}>
+CONFIG_SAMPLES                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SAMPLE_CONFIGFS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_HW_BREAKPOINT                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SAMPLE_KDB                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SAMPLE_KFIFO                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_KOBJECT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_KPROBES                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_LIVEPATCH                         policy<{'amd64': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_QMI_CLIENT                        policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SAMPLE_RPMSG_CLIENT                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SAMPLE_TRACE_EVENTS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_VFIO_MDEV_MBOCHS                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_VFIO_MDEV_MDPY                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMPLE_VFIO_MDEV_MTTY                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SAMSUNG_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SAMSUNG_MC                               policy<{'armhf': 'y'}>
+CONFIG_SAMSUNG_Q10                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SATA_ACARD_AHCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_AHCI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_AHCI_SEATTLE                        policy<{'arm64': 'm'}>
+CONFIG_SATA_DWC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_DWC_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SATA_DWC_OLD_DMA                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SATA_INIC162X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_MOBILE_LPM_POLICY                   policy<{'amd64': '3', 'arm64': '3', 'armhf': '3', 'i386': '3', 'ppc64el': '3'}>
+CONFIG_SATA_MV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_NV                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_PMP                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SATA_PROMISE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_QSTOR                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_RCAR                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SATA_SIL                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SIL24                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SIS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SVW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_SX4                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_ULI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_VIA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_VITESSE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SATA_ZPODD                               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SBC7240_WDT                              policy<{'i386': 'm'}>
+CONFIG_SBC8360_WDT                              policy<{'i386': 'm'}>
+CONFIG_SBC_EPX_C3_WATCHDOG                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBC_FITPC2_WATCHDOG                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBITMAP                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SBNI                                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SBNI_MULTILINE                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SBP_TARGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SC1200_WDT                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SC27XX_ADC                               policy<{'arm64': 'm'}>
+CONFIG_SC27XX_EFUSE                             policy<{'arm64': 'm'}>
+CONFIG_SC92031                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCA3000                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCANLOG                                  policy<{'ppc64el': 'm'}>
+CONFIG_SCC                                      policy<{'i386': 'm'}>
+CONFIG_SCC_DELAY                                policy<{'i386': 'n'}>
+CONFIG_SCC_TRXECHO                              policy<{'i386': 'n'}>
+CONFIG_SCHEDSTATS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_AUTOGROUP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_BOOK                               policy<{'s390x': 'y'}>
+CONFIG_SCHED_DEBUG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_DRAWER                             policy<{'s390x': 'y'}>
+CONFIG_SCHED_HRTICK                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_INFO                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_MC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_SCHED_MC_PRIO                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SCHED_OMIT_FRAME_POINTER                 policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_SMT                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_STACK_END_CHECK                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCHED_TOPOLOGY                           policy<{'s390x': 'y'}>
+CONFIG_SCHED_TRACER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCIF                                     policy<{'amd64': 'm'}>
+CONFIG_SCIF_BUS                                 policy<{'amd64': 'm'}>
+CONFIG_SCLP_CONSOLE                             policy<{'s390x': 'y'}>
+CONFIG_SCLP_TTY                                 policy<{'s390x': 'y'}>
+CONFIG_SCLP_VT220_CONSOLE                       policy<{'s390x': 'y'}>
+CONFIG_SCLP_VT220_TTY                           policy<{'s390x': 'y'}>
+CONFIG_SCM_BLOCK                                policy<{'s390x': 'm'}>
+CONFIG_SCM_BUS                                  policy<{'s390x': 'y'}>
+CONFIG_SCOM_DEBUGFS                             policy<{'ppc64el': 'y'}>
+CONFIG_SCR24X                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_3W_9XXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_3W_SAS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AACRAID                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ACARD                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ADVANSYS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AHA152X                             policy<{'i386': 'm'}>
+CONFIG_SCSI_AHA1542                             policy<{'i386': 'm'}>
+CONFIG_SCSI_AHA1740                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_AIC79XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AIC7XXX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AIC94XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_AM53C974                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ARCMSR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BFA_FC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BNX2X_FCOE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BNX2_ISCSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_BUSLOGIC                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_CHELSIO_FCOE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_CONSTANTS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_CXGB3_ISCSI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_CXGB4_ISCSI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DC395x                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DEBUG                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_DH_ALUA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_EMC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_HP_SW                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DH_RDAC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_DMA                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_DMX3191D                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_DPT_I2O                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_ENCLOSURE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_ESAS2R                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_FC_ATTRS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_FDOMAIN                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_FDOMAIN_ISA                         policy<{'i386': 'm'}>
+CONFIG_SCSI_FDOMAIN_PCI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_FLASHPOINT                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SCSI_GDTH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_GENERIC_NCR5380                     policy<{'i386': 'm'}>
+CONFIG_SCSI_HISI_SAS                            policy<{'arm64': 'm'}>
+CONFIG_SCSI_HISI_SAS_PCI                        policy<{'arm64': 'm'}>
+CONFIG_SCSI_HPSA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_HPTIOP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_IBMVFC                              policy<{'ppc64el': 'm'}>
+CONFIG_SCSI_IBMVFC_TRACE                        policy<{'ppc64el': 'y'}>
+CONFIG_SCSI_IBMVSCSI                            policy<{'ppc64el': 'm'}>
+CONFIG_SCSI_IBMVSCSIS                           policy<{'ppc64el': 'm'}>
+CONFIG_SCSI_IMM                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_INIA100                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_INITIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_IPR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_IPS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_ISCI                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_ISCSI_ATTRS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_IZIP_EPP16                          policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_IZIP_SLOW_CTR                       policy<{'amd64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_LOGGING                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_LOWLEVEL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_LOWLEVEL_PCMCIA                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SCSI_LPFC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_LPFC_DEBUG_FS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MOD                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_MPT2SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_MPT2SAS_MAX_SGE                     policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128', 's390x': '128'}>
+CONFIG_SCSI_MPT3SAS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_MPT3SAS_MAX_SGE                     policy<{'amd64': '128', 'arm64': '128', 'armhf': '128', 'i386': '128', 'ppc64el': '128', 's390x': '128'}>
+CONFIG_SCSI_MVSAS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_MVSAS_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MVSAS_TASKLET                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_MVUMI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_MYRB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_MYRS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_NETLINK                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_NSP32                               policy<{'armhf': 'm', 'i386': 'm'}>
+CONFIG_SCSI_PM8001                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_PMCRAID                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_PPA                                 policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_PROC_FS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_QLA_FC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_QLA_ISCSI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_QLOGIC_1280                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_QLOGIC_FAS                          policy<{'i386': 'm'}>
+CONFIG_SCSI_SAS_ATA                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_SAS_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SAS_HOST_SMP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_SAS_LIBSAS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SCAN_ASYNC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCSI_SIM710                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SCSI_SMARTPQI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_SNIC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_SNIC_DEBUG_FS                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SCSI_SPI_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SCSI_SRP_ATTRS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_SCSI_STEX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_SYM53C8XX_2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS              policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'ppc64el': '16'}>
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE       policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1'}>
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS                  policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'ppc64el': '64'}>
+CONFIG_SCSI_SYM53C8XX_MMIO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_UFSHCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCSI_UFSHCD_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFSHCD_PLATFORM                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFS_BSG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SCSI_UFS_CDNS_PLATFORM                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFS_DWC_TC_PCI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFS_DWC_TC_PLATFORM                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SCSI_UFS_HISI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SCSI_UFS_MEDIATEK                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SCSI_UFS_QCOM                            policy<{'arm64': 'm', 'armhf': 'n'}>
+CONFIG_SCSI_WD719X                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SCTP_COOKIE_HMAC_MD5                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCTP_COOKIE_HMAC_SHA1                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCTP_DBG_OBJCNT                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SCx200                                   policy<{'i386': 'm'}>
+CONFIG_SCx200HR_TIMER                           policy<{'i386': 'm'}>
+CONFIG_SCx200_ACB                               policy<{'i386': 'm'}>
+CONFIG_SCx200_GPIO                              policy<{'i386': 'm'}>
+CONFIG_SCx200_WDT                               policy<{'i386': 'm'}>
+CONFIG_SDIO_UART                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SDLA                                     policy<{'i386': 'm'}>
+CONFIG_SDMA_VERBOSITY                           policy<{'amd64': 'n'}>
+CONFIG_SDM_CAMCC_845                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_DISPCC_845                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_GCC_660                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_GCC_845                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_GPUCC_845                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_LPASSCC_845                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDM_VIDEOCC_845                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SDR_MAX2175                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SDR_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SD_ADC_MODULATOR                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SEALEVEL_4021                            policy<{'i386': 'm'}>
+CONFIG_SECCOMP                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECCOMP_FILTER                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECONDARY_TRUSTED_KEYRING                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECTION_MISMATCH_WARN_ONLY               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITYFS                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR_DEBUG                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_APPARMOR_HASH                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_APPARMOR_HASH_DEFAULT           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_DMESG_RESTRICT                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_INFINIBAND                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_LOADPIN                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_LOCKDOWN_LSM                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_LOCKDOWN_LSM_EARLY              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_NETWORK                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_NETWORK_XFRM                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_PATH                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX_AVC_STATS               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SELINUX_BOOTPARAM               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE      policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_SECURITY_SELINUX_DEVELOP                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SMACK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SMACK_APPEND_SIGNALS            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_SMACK_BRINGUP                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_SMACK_NETFILTER                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_TOMOYO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER       policy<{'amd64': '"/sbin/init"', 'arm64': '"/sbin/init"', 'armhf': '"/sbin/init"', 'i386': '"/sbin/init"', 'ppc64el': '"/sbin/init"', 's390x': '"/sbin/init"'}>
+CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY         policy<{'amd64': '2048', 'arm64': '2048', 'armhf': '2048', 'i386': '2048', 'ppc64el': '2048', 's390x': '2048'}>
+CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG            policy<{'amd64': '1024', 'arm64': '1024', 'armhf': '1024', 'i386': '1024', 'ppc64el': '1024', 's390x': '1024'}>
+CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': '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"', 'ppc64el': '"/sbin/tomoyo-init"', 's390x': '"/sbin/tomoyo-init"'}>
+CONFIG_SECURITY_YAMA                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SELECT_MEMORY_MODEL                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SENSIRION_SGP30                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ABITUGURU                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ABITUGURU3                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ACPI_POWER                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_AD7314                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AD7414                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AD7418                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADC128D818                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADCXX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1021                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1025                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1026                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1029                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1031                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM1275                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADM9240                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADS7828                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADS7871                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7310                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7410                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7411                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7462                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7470                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7475                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ADT7X10                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_AHC1EC0_HWMON                    policy<{'amd64': 'm'}>
+CONFIG_SENSORS_AMC6821                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_APDS990X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SENSORS_APPLESMC                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ARM_SCMI                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_ARM_SCPI                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_AS370                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ASB100                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ASC7621                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ASPEED                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ATK0110                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ATXP1                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_BH1770                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SENSORS_CORETEMP                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_DA9052_ADC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DA9055                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DELL_SMM                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_DME1737                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_DS1621                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_DS620                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_EMC1403                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_EMC2103                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_EMC6W201                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_SENSORS_FAM15H_POWER                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_FSCHMD                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_FTSTEUTATES                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_G760A                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_G762                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_GL518SM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_GL520SM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_GPIO_FAN                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HDAPS                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_HIH6130                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HMC5843                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HMC5843_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_HMC5843_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_I5500                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_I5K_AMB                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMAEM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMPEX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IBMPOWERNV                       policy<{'ppc64el': 'm'}>
+CONFIG_SENSORS_IBM_CFFPS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IIO_HWMON                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INA209                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INA2XX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INA3221                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_INSPUR_IPSPS                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IR35221                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IR38064                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_IRPS5401                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ISL29018                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ISL29028                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_ISL68137                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': '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', 'ppc64el': 'm'}>
+CONFIG_SENSORS_K10TEMP                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_K8TEMP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_LINEAGE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LIS3LV02D                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LIS3_I2C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SENSORS_LIS3_SPI                         policy<{'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM25066                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM3533                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM63                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM70                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM73                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM75                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM77                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM78                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM80                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM83                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM85                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM87                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM90                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM92                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM93                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95234                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95241                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LM95245                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LOCHNAGAR                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2945                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2978                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC2978_REGULATOR                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SENSORS_LTC2990                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC3815                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4151                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4215                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4222                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4245                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4260                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_LTC4261                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1111                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX16064                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX16065                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1619                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX1668                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX197                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX20751                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX31722                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX31785                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX31790                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX34440                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6621                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6639                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6642                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6650                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX6697                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MAX8688                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MC13783_ADC                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MCP3021                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MENF21BMC_HWMON                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_MLXREG_FAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_SENSORS_NCT7904                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_NPCM7XX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_NTC_THERMISTOR                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_OCC_P8_I2C                       policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SENSORS_OCC_P9_SBE                       policy<{'arm64': 'n', 'armhf': 'n'}>
+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_PCF8591                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PMBUS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_POWR1220                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PWM_FAN                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_PXE1610                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_RASPBERRYPI_HWMON                policy<{'arm64': 'm'}>
+CONFIG_SENSORS_RM3100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_RM3100_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_RM3100_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': '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_SCH56XX_COMMON                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_SHT15                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHT21                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHT3x                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SHTC1                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SIS5595                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SMM665                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_SMSC47B397                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_SENSORS_STTS751                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TC654                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TC74                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_THMC50                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP102                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP103                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP108                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP401                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TMP421                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TPS40422                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TPS53679                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_TSL2550                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SENSORS_TSL2563                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_UCD9000                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_UCD9200                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_VEXPRESS                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SENSORS_VIA686A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_VIA_CPUTEMP                      policy<{'amd64': 'm', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83627EHF                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_W83627HF                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_W83773G                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83781D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83791D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83792D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83793                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83795                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83795_FANCTRL                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SENSORS_W83L785TS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_W83L786NG                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_WM831X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_WM8350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SENSORS_XGENE                            policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SENSORS_ZL6100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_ACCENT                       policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_ASPEED_VUART                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250_BCM2835AUX                   policy<{'arm64': 'n'}>
+CONFIG_SERIAL_8250_BOCA                         policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_CS                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_8250_DETECT_IRQ                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_8250_DMA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_DW                           policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250_DWLIB                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_EM                           policy<{'armhf': 'n'}>
+CONFIG_SERIAL_8250_EXAR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250_EXAR_ST16C554                policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_EXTENDED                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_FINTEK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y', 'ppc64el': 'n'}>
+CONFIG_SERIAL_8250_FOURPORT                     policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_FSL                          policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_HUB6                         policy<{'i386': 'm'}>
+CONFIG_SERIAL_8250_LPSS                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SERIAL_8250_MANY_PORTS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_MEN_MCB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_8250_MID                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SERIAL_8250_MT6577                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_8250_NR_UARTS                     policy<{'amd64': '48', 'arm64': '48', 'armhf': '48', 'i386': '48', 'ppc64el': '48'}>
+CONFIG_SERIAL_8250_OMAP                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIAL_8250_PCI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_PNP                          policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SERIAL_8250_RSA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_RT288X                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_RUNTIME_UARTS                policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32'}>
+CONFIG_SERIAL_8250_SHARE_IRQ                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_8250_UNIPHIER                     policy<{'armhf': 'm'}>
+CONFIG_SERIAL_ALTERA_JTAGUART                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ALTERA_UART                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ALTERA_UART_BAUDRATE              policy<{'amd64': '115200', 'arm64': '115200', 'armhf': '115200', 'i386': '115200', 'ppc64el': '115200'}>
+CONFIG_SERIAL_ALTERA_UART_MAXPORTS              policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'ppc64el': '4'}>
+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_ARC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ARC_NR_PORTS                      policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1'}>
+CONFIG_SERIAL_BCM63XX                           policy<{'armhf': 'm'}>
+CONFIG_SERIAL_CONEXANT_DIGICOLOR                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_CORE                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_SERIAL_CORE_CONSOLE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_EARLYCON                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_FSL_LINFLEXUART                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_FSL_LPUART                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_ICOM                              policy<{'ppc64el': 'm'}>
+CONFIG_SERIAL_IFX6X60                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SERIAL_IMX                               policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_SERIAL_IMX_CONSOLE                       policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_SERIAL_IPOCTAL                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_JSM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_KGDB_NMI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_MAX3100                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_MAX310X                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_MCTRL_GPIO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_MEN_Z135                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_MESON                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MESON_CONSOLE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MILBEAUT_USIO                     policy<{'armhf': 'm'}>
+CONFIG_SERIAL_MILBEAUT_USIO_PORTS               policy<{'armhf': '4'}>
+CONFIG_SERIAL_MSM                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MSM_CONSOLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MVEBU_CONSOLE                     policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_MVEBU_UART                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_NONSTANDARD                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIAL_OF_PLATFORM                       policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_OMAP                              policy<{'armhf': 'y'}>
+CONFIG_SERIAL_OMAP_CONSOLE                      policy<{'armhf': 'y'}>
+CONFIG_SERIAL_OWL                               policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_OWL_CONSOLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_PCH_UART                          policy<{'i386': 'm'}>
+CONFIG_SERIAL_QCOM_GENI                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIAL_RDA                               policy<{'armhf': 'y'}>
+CONFIG_SERIAL_RDA_CONSOLE                       policy<{'armhf': 'y'}>
+CONFIG_SERIAL_RP2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_RP2_NR_UARTS                      policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32'}>
+CONFIG_SERIAL_SAMSUNG                           policy<{'armhf': 'm'}>
+CONFIG_SERIAL_SAMSUNG_UARTS                     policy<{'armhf': '4'}>
+CONFIG_SERIAL_SAMSUNG_UARTS_4                   policy<{'armhf': 'y'}>
+CONFIG_SERIAL_SC16IS7XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SERIAL_SC16IS7XX_CORE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_SC16IS7XX_I2C                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_SC16IS7XX_SPI                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_SCCNXP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIAL_SCCNXP_CONSOLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIAL_SH_SCI_DMA                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SERIAL_SH_SCI_NR_UARTS                   policy<{'arm64': '2', 'armhf': '2'}>
+CONFIG_SERIAL_SIFIVE                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIAL_SPRD                              policy<{'arm64': 'm'}>
+CONFIG_SERIAL_ST_ASC                            policy<{'armhf': 'm'}>
+CONFIG_SERIAL_TEGRA                             policy<{'armhf-generic': 'm'}>
+CONFIG_SERIAL_TEGRA_TCU                         policy<{'armhf-generic': 'm'}>
+CONFIG_SERIAL_TIMBERDALE                        policy<{'i386': 'm'}>
+CONFIG_SERIAL_UARTLITE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SERIAL_UARTLITE_NR_UARTS                 policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1', 's390x': '1'}>
+CONFIG_SERIAL_XILINX_PS_UART                    policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SERIO_ALTERA_PS2                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_AMBAKMI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SERIO_APBPS2                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_ARC_PS2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_CT82C710                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SERIO_GPIO_PS2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_I8042                              policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIO_LIBPS2                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SERIO_NVEC_PS2                           policy<{'armhf-generic': 'm'}>
+CONFIG_SERIO_PARKBD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_PCIPS2                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_PS2MULT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_RAW                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_SERPORT                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SERIO_SUN4I_PS2                          policy<{'arm64': 'n'}>
+CONFIG_SERIO_XILINX_XPS_PS2                     policy<{'ppc64el': 'm'}>
+CONFIG_SFC                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SFC_FALCON                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SFC_FALCON_MTD                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_MCDI_LOGGING                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_MCDI_MON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_MTD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SFC_SRIOV                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SFI                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SFP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SGETMASK_SYSCALL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SGI_GRU                                  policy<{'amd64': 'm'}>
+CONFIG_SGI_GRU_DEBUG                            policy<{'amd64': 'n'}>
+CONFIG_SGI_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SGI_XP                                   policy<{'amd64': 'm'}>
+CONFIG_SGL_ALLOC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SG_POOL                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SG_SPLIT                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SHIFT_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SHIFT_FS_POSIX_ACL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SHMEM                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SHUFFLE_PAGE_ALLOCATOR                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SH_ETH                                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SH_TIMER_CMT                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SH_TIMER_MTU2                            policy<{'armhf': 'y'}>
+CONFIG_SH_TIMER_TMU                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SI1133                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SI1145                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SI7005                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SI7020                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SIGNALFD                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SIGNATURE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SIGNED_PE_FILE_VERIFICATION              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SIMPLE_GPIO                              policy<{'ppc64el': 'n'}>
+CONFIG_SIMPLE_PM_BUS                            policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SIOX                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SIOX_BUS_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SIS190                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SIS900                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SKB_EXTENSIONS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SKFP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SKGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SKGE_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SKGE_GENESIS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SKY2                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SKY2_DEBUG                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SLAB                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLAB_FREELIST_HARDENED                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLAB_FREELIST_RANDOM                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLAB_MERGE_DEFAULT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLHC                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SLICOSS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SLIC_DS26522                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SLIMBUS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SLIM_QCOM_CTRL                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SLIM_QCOM_NGD_CTRL                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SLIP                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SLIP_COMPRESSED                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SLIP_MODE_SLIP6                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SLIP_SMART                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SLOB                                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLUB_CPU_PARTIAL                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLUB_DEBUG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLUB_DEBUG_ON                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SLUB_MEMCG_SYSFS_ON                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SLUB_STATS                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SMARTJOYPLUS_FF                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SMC911X                                  policy<{'armhf': 'm'}>
+CONFIG_SMC9194                                  policy<{'i386': 'm'}>
+CONFIG_SMC91X                                   policy<{'arm64': 'y', 'armhf': 'm'}>
+CONFIG_SMP                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SMP_ON_UP                                policy<{'armhf': 'y'}>
+CONFIG_SMSC37B787_WDT                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SMSC911X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SMSC9420                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SMSC_PHY                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SMSC_SCH311X_WDT                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SMSGIUCV                                 policy<{'s390x': 'y'}>
+CONFIG_SMSGIUCV_EVENT                           policy<{'s390x': 'm'}>
+CONFIG_SMS_SDIO_DRV                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SMS_SIANO_DEBUGFS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SMS_SIANO_MDTV                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SMS_SIANO_RC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SMS_USB_DRV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SM_FTL                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SM_GCC_8150                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_AC97_CODEC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AC97_POWER_SAVE                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT              policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_SND_AD1816A                              policy<{'i386': 'm'}>
+CONFIG_SND_AD1848                               policy<{'i386': 'm'}>
+CONFIG_SND_AD1889                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ADLIB                                policy<{'i386': 'm'}>
+CONFIG_SND_ALI5451                              policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ALOOP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ALS100                               policy<{'i386': 'm'}>
+CONFIG_SND_ALS300                               policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ALS4000                              policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ARM                                  policy<{'armhf': 'y'}>
+CONFIG_SND_ARMAACI                              policy<{'armhf': 'm'}>
+CONFIG_SND_ASIHPI                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_ATIIXP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ATIIXP_MODEM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ATMEL_SOC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8810                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8820                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AU8830                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AUDIO_GRAPH_CARD                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AW2                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_AZT1605                              policy<{'i386': 'm'}>
+CONFIG_SND_AZT2316                              policy<{'i386': 'm'}>
+CONFIG_SND_AZT2320                              policy<{'i386': 'm'}>
+CONFIG_SND_AZT3328                              policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_BCD2000                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BCM2835                              policy<{'arm64': 'm'}>
+CONFIG_SND_BCM2835_SOC_I2S                      policy<{'arm64': 'm'}>
+CONFIG_SND_BEBOB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BT87X                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_BT87X_OVERCLOCK                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_CA0106                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CMI8328                              policy<{'i386': 'm'}>
+CONFIG_SND_CMI8330                              policy<{'i386': 'm'}>
+CONFIG_SND_CMIPCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_COMPRESS_OFFLOAD                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm'}>
+CONFIG_SND_CS4231                               policy<{'i386': 'm'}>
+CONFIG_SND_CS4236                               policy<{'i386': 'm'}>
+CONFIG_SND_CS4281                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CS46XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_CS46XX_NEW_DSP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': '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', 'ppc64el': 'm'}>
+CONFIG_SND_DARLA20                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DARLA24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_DESIGNWARE_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_DESIGNWARE_PCM                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_SND_DICE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DMAENGINE_PCM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DMA_SGBUF                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_DRIVERS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_ECHO3G                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_EMU10K1                              policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_EMU10K1X                             policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_EMU10K1_SEQ                          policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ENS1370                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ENS1371                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ES1688                               policy<{'i386': 'm'}>
+CONFIG_SND_ES18XX                               policy<{'i386': 'm'}>
+CONFIG_SND_ES1938                               policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ES1968                               policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ES1968_INPUT                         policy<{'amd64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y'}>
+CONFIG_SND_ES1968_RADIO                         policy<{'amd64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y'}>
+CONFIG_SND_FIREFACE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_FIREWIRE_DIGI00X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE_LIB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE_MOTU                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWIRE_TASCAM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FIREWORKS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FM801                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_FM801_TEA575X_BOOL                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_GINA20                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_GINA24                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_GUSCLASSIC                           policy<{'i386': 'm'}>
+CONFIG_SND_GUSEXTREME                           policy<{'i386': 'm'}>
+CONFIG_SND_GUSMAX                               policy<{'i386': 'm'}>
+CONFIG_SND_HDA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_ALIGNED_MMIO                     policy<{'armhf-generic': 'y'}>
+CONFIG_SND_HDA_CODEC_ANALOG                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0110                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0132                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CA0132_DSP                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_CODEC_CIRRUS                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CMEDIA                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_CONEXANT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_HDMI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_REALTEK                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_SI3054                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_SIGMATEL                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_CODEC_VIA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_COMPONENT                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_DSP_LOADER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_EXT_CORE                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_HDA_GENERIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_HWDEP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_I915                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_HDA_INPUT_BEEP                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_INPUT_BEEP_MODE                  policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_SND_HDA_INTEL                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDA_PATCH_LOADER                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_HDA_PREALLOC_SIZE                    policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'ppc64el': '64'}>
+CONFIG_SND_HDA_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_SND_HDSP                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HDSPM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HRTIMER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_HWDEP                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_I2S_HI6210_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_ICE1712                              policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_ICE1724                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_IMX_SOC                              policy<{'arm64': 'm', 'armhf-generic': 'y'}>
+CONFIG_SND_INDIGO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGODJ                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGODJX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGOIO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INDIGOIOX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL8X0                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL8X0M                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL_DSP_CONFIG                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_INTEL_NHLT                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SND_INTERWAVE                            policy<{'i386': 'm'}>
+CONFIG_SND_INTERWAVE_STB                        policy<{'i386': 'm'}>
+CONFIG_SND_ISA                                  policy<{'i386': 'y'}>
+CONFIG_SND_ISIGHT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_JACK                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_JACK_INPUT_DEV                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_JAZZ16                               policy<{'i386': 'm'}>
+CONFIG_SND_KIRKWOOD_SOC                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_KORG1212                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LAYLA20                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LAYLA24                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LOLA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_LX6464ES                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MAESTRO3                             policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_MAESTRO3_INPUT                       policy<{'amd64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y'}>
+CONFIG_SND_MAX_CARDS                            policy<{'amd64': '32', 'arm64': '32', 'armhf': '32', 'i386': '32', 'ppc64el': '32'}>
+CONFIG_SND_MESON_AXG_FIFO                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_FRDDR                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_PDM                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_SOUND_CARD                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_SPDIFIN                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_SPDIFOUT                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_TDMIN                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_TDMOUT                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_TDM_FORMATTER              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_TDM_INTERFACE              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_AXG_TODDR                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_CODEC_GLUE                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MESON_G12A_TOHDMITX                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_MIA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MIRO                                 policy<{'i386': 'm'}>
+CONFIG_SND_MIXART                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MIXER_OSS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MONA                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MPU401                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MPU401_UART                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MSND_CLASSIC                         policy<{'i386': 'm'}>
+CONFIG_SND_MSND_PINNACLE                        policy<{'i386': 'm'}>
+CONFIG_SND_MTPAV                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_MTS64                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_NM256                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OPL3SA2                              policy<{'i386': 'm'}>
+CONFIG_SND_OPL3_LIB                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OPL3_LIB_SEQ                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OPL4_LIB                             policy<{'i386': 'm'}>
+CONFIG_SND_OPL4_LIB_SEQ                         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_OSSEMUL                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_OXFW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OXYGEN                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_OXYGEN_LIB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PCI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PCMCIA                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_PCM_ELD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCM_IEC958                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCM_TIMER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_PCSP                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_PCXHR                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PDAUDIOCF                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_PORTMAN2X4                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_PPC                                  policy<{'ppc64el': 'y'}>
+CONFIG_SND_PROC_FS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_RAWMIDI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RIPTIDE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME32                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME96                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_RME9652                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SAMSUNG_I2S                          policy<{'armhf': 'm'}>
+CONFIG_SND_SAMSUNG_PCM                          policy<{'armhf': 'm'}>
+CONFIG_SND_SAMSUNG_SPDIF                        policy<{'armhf': 'm'}>
+CONFIG_SND_SB16                                 policy<{'i386': 'm'}>
+CONFIG_SND_SB16_CSP                             policy<{'i386': 'y'}>
+CONFIG_SND_SB16_DSP                             policy<{'i386': 'm'}>
+CONFIG_SND_SB8                                  policy<{'i386': 'm'}>
+CONFIG_SND_SB8_DSP                              policy<{'i386': 'm'}>
+CONFIG_SND_SBAWE                                policy<{'i386': 'm'}>
+CONFIG_SND_SBAWE_SEQ                            policy<{'i386': 'm'}>
+CONFIG_SND_SB_COMMON                            policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SC6000                               policy<{'i386': 'm'}>
+CONFIG_SND_SEQUENCER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQUENCER_OSS                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_SEQ_DEVICE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_DUMMY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_HRTIMER_DEFAULT                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SEQ_MIDI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_MIDI_EMUL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_MIDI_EVENT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SEQ_VIRMIDI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SERIAL_U16550                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SIMPLE_CARD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SIMPLE_CARD_UTILS                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SIS7019                              policy<{'i386': 'm'}>
+CONFIG_SND_SOC_AC97_BUS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SOC_AC97_CODEC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ACPI                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_ACPI_INTEL_MATCH                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_ADAU1701                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU1761                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU1761_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU1761_SPI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU17X1                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU7002                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ADAU_UTILS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4104                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4118                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4458                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4554                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4613                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK4642                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK5386                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AK5558                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ALC5623                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ALC5632                          policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_AMD_ACP                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AMD_ACP3x                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_AMD_CZ_RT5645_MACH               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_APQ8016_SBC                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ARIZONA                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631           policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_BD28623                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_BT_SCO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_COMPRESS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_CPCAP                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CROS_EC_CODEC                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_CS35L32                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS35L33                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS35L34                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS35L35                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS35L36                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4265                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4270                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4271                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4271_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4271_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L42                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L51                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L51_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L52                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L56                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42L73                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42XX8                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS42XX8_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS43130                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4341                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS4349                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CS53L30                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_CX2072X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_DA7213                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_DA7219                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_DAVINCI_MCASP                    policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_DMIC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES7134                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES7241                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES8316                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES8328                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES8328_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ES8328_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_EUKREA_TLV320                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_FSL_ASOC_CARD                    policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SND_SOC_FSL_ASRC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_AUDMIX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_ESAI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_MICFIL                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SAI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SPDIF                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_SSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_FSL_UTILS                        policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SOC_GTM601                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_HDAC_HDA                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_HDAC_HDMI                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_HDMI_CODEC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_I2C_AND_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SOC_IMG_I2S_IN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG_I2S_OUT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG_PARALLEL_OUT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG_SPDIF_IN                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMG_SPDIF_OUT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMX_AUDMIX                       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_AUDMUX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_IMX_ES8328                       policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_MC13783                      policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_PCM_DMA                      policy<{'arm64': 'm', 'armhf-generic': 'y'}>
+CONFIG_SND_SOC_IMX_PCM_FIQ                      policy<{'armhf-generic': 'y'}>
+CONFIG_SND_SOC_IMX_SGTL5000                     policy<{'arm64': 'm', 'armhf-generic': 'y'}>
+CONFIG_SND_SOC_IMX_SPDIF                        policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SND_SOC_IMX_SSI                          policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_INNO_RK3036                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_INTEL_APL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BROADWELL_MACH             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BXT_RT298_MACH             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_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_RT5672_MACH        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_DA7219_MAX98357A_GENERIC   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_GLK                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_HASWELL                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_HASWELL_MACH               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_MACH                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_INTEL_SKL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKL_RT286_MACH             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKYLAKE_FAMILY             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SST                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SST_ACPI                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SST_FIRMWARE               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_INTEL_SST_TOPLEVEL               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_LOCHNAGAR_SC                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_LPASS_APQ8016                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_LPASS_CPU                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_LPASS_IPQ806X                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_LPASS_PLATFORM                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MAX9759                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX98088                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX98090                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_MAX98095                         policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_MAX98357A                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX98373                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX98504                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX9860                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX9867                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MAX98927                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MC13783                          policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_MEDIATEK                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MIKROE_PROTO                     policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MSM8916_WCD_ANALOG               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MSM8916_WCD_DIGITAL              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MSM8996                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT2701                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_MT6351                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MT6358                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_MT6797                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT6797_MT6351                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT8173                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_SND_SOC_MT8183                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT8183_DA7219_MAX98357A          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_MTK_BTCVSD                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_NAU8540                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_NAU8810                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_NAU8822                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_NAU8824                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_NAU8825                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_NOKIA_RX51                       policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_ODROID                           policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_OMAP3_PANDORA                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_OMAP3_TWL4030                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_OMAP_ABE_TWL6040                 policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_OMAP_DMIC                        policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_OMAP_MCBSP                       policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_OMAP_MCPDM                       policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_PCM1681                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM1789                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM1789_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM179X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM179X_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM179X_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM186X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM186X_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM186X_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3060                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3060_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3060_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3168A                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3168A_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM3168A_SPI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM512x                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM512x_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_PCM512x_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_QCOM                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QCOM_COMMON                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_ADM                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_AFE                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_AFE_DAI                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_ASM                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_ASM_DAI                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_COMMON                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_CORE                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_QDSP6_ROUTING                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_RCAR                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_RK3288_HDMI_ANALOG               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_RK3328                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RK3399_GRU_SOUND                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_RL6231                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RL6347A                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_I2S                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_MAX98090                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_PDM                     policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_RT5645                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_ROCKCHIP_SPDIF                   policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_RT286                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT298                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5514                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5514_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5616                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RT5631                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RT5640                           policy<{'amd64': 'm', 'armhf-generic': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5645                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_RT5651                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5660                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5663                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5670                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5677                           policy<{'amd64': 'm', 'armhf-generic': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5677_SPI                       policy<{'amd64': 'm', 'armhf-generic': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_RT5682                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SAMSUNG                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF               policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994              policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SAMSUNG_TM2_WM5110               policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SDM845                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_SGTL5000                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic': 'y', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SH4_FSI                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_SI476X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIGMADSP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIGMADSP_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIGMADSP_REGMAP                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIMPLE_AMPLIFIER                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SIRF_AUDIO_CODEC                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SMDK_WM8994_PCM                  policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SNOW                             policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_SOF                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SOF_ACPI                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_APOLLOLAKE                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_APOLLOLAKE_SUPPORT           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_BAYTRAIL                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_BAYTRAIL_SUPPORT             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_CANNONLAKE                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_CANNONLAKE_SUPPORT           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_COFFEELAKE                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_COFFEELAKE_SUPPORT           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_COMETLAKE_H                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_COMETLAKE_H_SUPPORT          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_COMETLAKE_LP                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_COMETLAKE_LP_SUPPORT         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_DEBUG                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_SOC_SOF_ELKHARTLAKE                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_ELKHARTLAKE_SUPPORT          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_GEMINILAKE                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_GEMINILAKE_SUPPORT           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_HDA                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_HDA_COMMON                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_HDA_LINK_BASELINE            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_ICELAKE                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_ICELAKE_SUPPORT              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_IMX8                         policy<{'arm64': 'm'}>
+CONFIG_SND_SOC_SOF_IMX8_SUPPORT                 policy<{'arm64': 'y'}>
+CONFIG_SND_SOC_SOF_IMX_TOPLEVEL                 policy<{'arm64': 'y'}>
+CONFIG_SND_SOC_SOF_INTEL_ACPI                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_INTEL_COMMON                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_INTEL_PCI                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_MERRIFIELD                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_MERRIFIELD_SUPPORT           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_OF                           policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SOF_OPTIONS                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SOF_PCI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_SOC_SOF_TIGERLAKE                    policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SOF_TIGERLAKE_SUPPORT            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_SOC_SOF_TOPLEVEL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SOC_SOF_XTENSA                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_SPDIF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SPRD                             policy<{'arm64': 'm'}>
+CONFIG_SND_SOC_SPRD_MCDT                        policy<{'arm64': 'y'}>
+CONFIG_SND_SOC_SSM2305                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM2602                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM2602_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM2602_SPI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_SSM4567                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STA32X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STA350                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STI_SAS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_STORM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SND_SOC_TAS2552                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS5086                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS571X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS5720                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TAS6424                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TDA7419                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TEGRA                            policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA20_AC97                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA20_DAS                      policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA20_I2S                      policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA20_SPDIF                    policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA30_AHUB                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA30_I2S                      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_RT5640                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_RT5677                     policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_SGTL5000                   policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TEGRA_TRIMSLICE                  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_TFA9879                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TI_EDMA_PCM                      policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_TI_SDMA_PCM                      policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC23_SPI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC31XX                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4_I2C                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_TLV320AIC32X4_SPI                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SND_SOC_TLV320AIC3X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TOPOLOGY                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SOC_TPA6130A2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TS3A227E                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TSCS42XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TSCS454                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_TWL4030                          policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_TWL6040                          policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_UDA1334                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_UNIPHIER                         policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_UNIPHIER_AIO                     policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC              policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_UNIPHIER_LD11                    policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_UNIPHIER_PXS2                    policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_WCD9335                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM5110                           policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_WM8510                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8523                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8524                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8580                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8711                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8728                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8731                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8737                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8741                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8750                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8753                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8770                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8776                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8782                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8804                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8804_I2C                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8804_SPI                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8903                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8904                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8960                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8962                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8974                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8978                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8985                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_WM8994                           policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_WM9712                           policy<{'armhf-generic': 'm'}>
+CONFIG_SND_SOC_WM_ADSP                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_WM_HUBS                          policy<{'armhf': 'm'}>
+CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_XILINX_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_XILINX_SPDIF                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_XTFPGA_I2S                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SOC_ZX_AUD96P22                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_SONICVIBES                           policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_SPI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SSCAPE                               policy<{'i386': 'm'}>
+CONFIG_SND_SST_ATOM_HIFI2_PLATFORM              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SST_IPC                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SST_IPC_ACPI                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SST_IPC_PCI                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_SUN4I_CODEC                          policy<{'arm64': 'n'}>
+CONFIG_SND_SUN4I_I2S                            policy<{'arm64': 'n'}>
+CONFIG_SND_SUN4I_SPDIF                          policy<{'arm64': 'n'}>
+CONFIG_SND_SUN50I_CODEC_ANALOG                  policy<{'arm64': 'm'}>
+CONFIG_SND_SUN8I_ADDA_PR_REGMAP                 policy<{'arm64': 'm'}>
+CONFIG_SND_SUN8I_CODEC                          policy<{'arm64': 'm'}>
+CONFIG_SND_SUN8I_CODEC_ANALOG                   policy<{'arm64': 'm'}>
+CONFIG_SND_SUPPORT_OLD_API                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_SYNTH_EMUX                           policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_TIMER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_TRIDENT                              policy<{'amd64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm'}>
+CONFIG_SND_USB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_USB_6FIRE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_AUDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_USB_CAIAQ                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_CAIAQ_INPUT                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_USB_HIFACE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_LINE6                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_POD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_PODHD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_TONEPORT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_UA101                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_US122L                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_USB_USX2Y                            policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_USB_VARIAX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VERBOSE_PRINTK                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SND_VERBOSE_PROCFS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_VIA82XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIA82XX_MODEM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIRMIDI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VIRTUOSO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VMASTER                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SND_VX222                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_VXPOCKET                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SND_VX_LIB                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SND_WAVEFRONT                            policy<{'i386': 'm'}>
+CONFIG_SND_WSS_LIB                              policy<{'i386': 'm'}>
+CONFIG_SND_X86                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SND_XEN_FRONTEND                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_SND_YMFPCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SNI_AVE                                  policy<{'armhf': 'm'}>
+CONFIG_SNI_NETSEC                               policy<{'arm64': 'm'}>
+CONFIG_SOCIONEXT_SYNQUACER_PREITS               policy<{'arm64': 'y'}>
+CONFIG_SOCK_CGROUP_DATA                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SOCK_VALIDATE_XMIT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SOC_AM33XX                               policy<{'armhf-generic': 'y', 'armhf-generic-lpae': 'n'}>
+CONFIG_SOC_AM43XX                               policy<{'armhf': 'n'}>
+CONFIG_SOC_ASPEED                               policy<{'armhf': 'y'}>
+CONFIG_SOC_BRCMSTB                              policy<{'arm64': 'y', 'armhf': 'n'}>
+CONFIG_SOC_BUS                                  policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SOC_DRA7XX                               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_EXYNOS5800                           policy<{'armhf': 'y'}>
+CONFIG_SOC_HAS_OMAP2_SDRC                       policy<{'armhf': 'y'}>
+CONFIG_SOC_HAS_REALTIME_COUNTER                 policy<{'armhf': 'y'}>
+CONFIG_SOC_IMX5                                 policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX50                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX51                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX53                                policy<{'armhf-generic': 'n'}>
+CONFIG_SOC_IMX6                                 policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6Q                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6SL                               policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX6SLL                              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_IMX7D_CA7                            policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_IMX7ULP                              policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_LS1021A                              policy<{'armhf-generic': 'n'}>
+CONFIG_SOC_OMAP3430                             policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_OMAP5                                policy<{'armhf': 'n'}>
+CONFIG_SOC_RENESAS                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SOC_SAMSUNG                              policy<{'armhf': 'y'}>
+CONFIG_SOC_TEGRA_FLOWCTRL                       policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_TEGRA_FUSE                           policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_TEGRA_PMC                            policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_TEGRA_POWERGATE_BPMP                 policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_TI                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SOC_TI81XX                               policy<{'armhf-generic': 'y'}>
+CONFIG_SOC_VF610                                policy<{'armhf-generic': 'y'}>
+CONFIG_SOFTLOCKUP_DETECTOR                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SOFT_WATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SOFT_WATCHDOG_PRETIMEOUT                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SOLARIS_X86_PARTITION                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SONYPI                                   policy<{'i386': 'm'}>
+CONFIG_SONYPI_COMPAT                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SONY_FF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SONY_LAPTOP                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SOUNDWIRE_CADENCE                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SOUNDWIRE_INTEL                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SOUND_OSS_CORE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SP5100_TCO                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SPAPR_TCE_IOMMU                          policy<{'ppc64el': 'y'}>
+CONFIG_SPARSEMEM                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SPARSEMEM_EXTREME                        policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SPARSEMEM_MANUAL                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPARSEMEM_STATIC                         policy<{'i386': 'y'}>
+CONFIG_SPARSEMEM_VMEMMAP                        policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE                 policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SPARSE_IRQ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SPEAKUP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_ACNTPC                     policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_ACNTSA                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_APOLLO                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_AUDPTR                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_BNS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECEXT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECPC                      policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DECTLK                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DTLK                       policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_DUMMY                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_KEYPC                      policy<{'i386': 'm'}>
+CONFIG_SPEAKUP_SYNTH_LTLK                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_SOFT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_SPKOUT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPEAKUP_SYNTH_TXPRT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPECTRE_BHI_AUTO                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SPECTRE_BHI_OFF                          policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SPECTRE_BHI_ON                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SPI                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SPI_ALTERA                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_ARMADA_3700                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_ASPEED_SMC                           policy<{'armhf': 'm'}>
+CONFIG_SPI_AXI_SPI_ENGINE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_BCM2835                              policy<{'arm64': 'm'}>
+CONFIG_SPI_BCM2835AUX                           policy<{'arm64': 'm'}>
+CONFIG_SPI_BCM_QSPI                             policy<{'arm64': 'm'}>
+CONFIG_SPI_BITBANG                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_BUTTERFLY                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_CADENCE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_CADENCE_QUADSPI                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SPI_DESIGNWARE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DLN2                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DW_MID_DMA                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_DW_MMIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DW_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_DYNAMIC                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_FSL_DSPI                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SPI_FSL_LIB                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_FSL_LPSPI                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SPI_FSL_QUADSPI                          policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SPI_FSL_SPI                              policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_GPIO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_HISI_SFC                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_HISI_SFC_V3XX                        policy<{'arm64': 'm'}>
+CONFIG_SPI_IMX                                  policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_SPI_LM70_LLP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_LOOPBACK_TEST                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_MASTER                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_MEM                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_MESON_SPICC                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_MESON_SPIFC                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_MT65XX                               policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_MTK_QUADSPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_MXIC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_NPCM_FIU                             policy<{'armhf': 'm'}>
+CONFIG_SPI_NPCM_PSPI                            policy<{'armhf': 'm'}>
+CONFIG_SPI_NXP_FLEXSPI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_OC_TINY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_OMAP24XX                             policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SPI_ORION                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_PL022                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_PXA2XX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_PXA2XX_PCI                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_SPI_QCOM_GENI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_QCOM_QSPI                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_QUP                                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_ROCKCHIP                             policy<{'amd64': 'n', 'arm64': 'm', 'armhf': 'm', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SPI_RSPI                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_S3C64XX                              policy<{'armhf': 'm'}>
+CONFIG_SPI_SC18IS602                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SH_HSPI                              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_SH_MSIOF                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_SIFIVE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SLAVE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SPI_SLAVE_MT27XX                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPI_SLAVE_SYSTEM_CONTROL                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SLAVE_TIME                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SPIDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_SPRD                                 policy<{'arm64': 'm'}>
+CONFIG_SPI_SPRD_ADI                             policy<{'arm64': 'm'}>
+CONFIG_SPI_SUN4I                                policy<{'arm64': 'n'}>
+CONFIG_SPI_SUN6I                                policy<{'arm64': 'm'}>
+CONFIG_SPI_SYNQUACER                            policy<{'arm64': '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_THUNDERX                             policy<{'arm64': 'm'}>
+CONFIG_SPI_TI_QSPI                              policy<{'armhf': 'm'}>
+CONFIG_SPI_TLE62X0                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_TOPCLIFF_PCH                         policy<{'i386': 'm'}>
+CONFIG_SPI_UNIPHIER                             policy<{'armhf': 'm'}>
+CONFIG_SPI_XCOMM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPI_XILINX                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SPI_XLP                                  policy<{'arm64': 'm'}>
+CONFIG_SPI_ZYNQMP_GQSPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SPLIT_PTLOCK_CPUS                        policy<{'amd64': '4', 'arm64': '4', 'armhf': '4', 'i386': '4', 'ppc64el': '4', 's390x': '4'}>
+CONFIG_SPMI                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SPMI_MSM_PMIC_ARB                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPMI_PMIC_CLKDIV                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_SPRD_COMMON_CLK                          policy<{'arm64': 'm'}>
+CONFIG_SPRD_DMA                                 policy<{'arm64': 'm'}>
+CONFIG_SPRD_SC9860_CLK                          policy<{'arm64': 'm'}>
+CONFIG_SPRD_TIMER                               policy<{'arm64': 'y'}>
+CONFIG_SPRD_WATCHDOG                            policy<{'arm64': 'm'}>
+CONFIG_SPS30                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SQUASHFS_DECOMP_MULTI                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_DECOMP_SINGLE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_EMBEDDED                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_FILE_CACHE                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SQUASHFS_FILE_DIRECT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE             policy<{'amd64': '3', 'arm64': '3', 'armhf': '3', 'i386': '3', 'ppc64el': '3', 's390x': '3'}>
+CONFIG_SQUASHFS_LZ4                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_LZO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_XZ                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_ZLIB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SQUASHFS_ZSTD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SRAM                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SRAM_EXEC                                policy<{'armhf': 'y'}>
+CONFIG_SRCU                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SRF04                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SRF08                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SSB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SSB_B43_PCI_BRIDGE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_BLOCKIO                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_DRIVER_GPIO                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_DRIVER_PCICORE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_PCIHOST                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_PCIHOST_POSSIBLE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_PCMCIAHOST                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_SSB_PCMCIAHOST_POSSIBLE                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_SSB_POSSIBLE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SSB_SDIOHOST                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_SDIOHOST_POSSIBLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSB_SPROM                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SSFDC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SSI_PROTOCOL                             policy<{'armhf-generic': 'm'}>
+CONFIG_STACKPROTECTOR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_STACKPROTECTOR_PER_TASK                  policy<{'arm64': 'y'}>
+CONFIG_STACKPROTECTOR_STRONG                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_STACKTRACE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STACKTRACE_SUPPORT                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STACK_TRACER                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STAGING                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_STAGING_APEX_DRIVER                      policy<{'amd64': 'm', 'arm64': 'm'}>
+CONFIG_STAGING_BOARD                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_STAGING_GASKET_FRAMEWORK                 policy<{'amd64': 'm', 'arm64': 'm'}>
+CONFIG_STAGING_MEDIA                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_STANDALONE                               policy<{'amd64': 'n', 'arm64': 'y', 'armhf': 'y', 'i386': 'n', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STATIC_KEYS_SELFTEST                     policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STATIC_USERMODEHELPER                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STE10XP                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STK3310                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_STK8312                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_STK8BA50                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_STM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STMMAC_ETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_STMMAC_PCI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_STMMAC_PLATFORM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_STMMAC_SELFTESTS                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_STMPE_ADC                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_STMPE_I2C                                policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_STMPE_SPI                                policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_STMP_DEVICE                              policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_STM_DUMMY                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_PROTO_BASIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_PROTO_SYS_T                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_SOURCE_CONSOLE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_SOURCE_FTRACE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STM_SOURCE_HEARTBEAT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_STPMIC1_WATCHDOG                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_STREAM_PARSER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STRICT_DEVMEM                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_STRICT_KERNEL_RWX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_STRICT_MODULE_RWX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_STRING_SELFTEST                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STRIP_ASM_SYMS                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_STUB_CLK_HI3660                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_STUB_CLK_HI6220                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_STX104                                   policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_ST_UVIS25                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ST_UVIS25_I2C                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ST_UVIS25_SPI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SUN4I_EMAC                               policy<{'arm64': 'n'}>
+CONFIG_SUN4I_GPADC                              policy<{'arm64': 'n'}>
+CONFIG_SUN50I_A64_CCU                           policy<{'arm64': 'y'}>
+CONFIG_SUN50I_DE2_BUS                           policy<{'arm64': 'y'}>
+CONFIG_SUN50I_ERRATUM_UNKNOWN1                  policy<{'arm64': 'y'}>
+CONFIG_SUN50I_H6_CCU                            policy<{'arm64': 'y'}>
+CONFIG_SUN50I_H6_R_CCU                          policy<{'arm64': 'y'}>
+CONFIG_SUN8I_A83T_CCU                           policy<{'arm64': 'y'}>
+CONFIG_SUN8I_DE2_CCU                            policy<{'arm64': 'y'}>
+CONFIG_SUN8I_H3_CCU                             policy<{'arm64': 'y'}>
+CONFIG_SUN8I_R_CCU                              policy<{'arm64': 'y'}>
+CONFIG_SUNDANCE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNDANCE_MMIO                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SUNGEM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNGEM_PHY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SUNRPC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SUNRPC_BACKCHANNEL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SUNRPC_DEBUG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SUNRPC_GSS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SUNRPC_SWAP                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SUNRPC_XPRT_RDMA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_SUNXI_CCU                                policy<{'arm64': 'y'}>
+CONFIG_SUNXI_RSB                                policy<{'arm64': 'm'}>
+CONFIG_SUNXI_SRAM                               policy<{'arm64': 'y'}>
+CONFIG_SUNXI_WATCHDOG                           policy<{'arm64': 'm'}>
+CONFIG_SUN_PARTITION                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SURFACE3_WMI                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SURFACE_3_BUTTON                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SURFACE_PRO3_BUTTON                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SUSPEND                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SUSPEND_FREEZER                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_SUSPEND_SKIP_SYNC                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_SWAP                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SWIOTLB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SWIOTLB_XEN                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_SWPHY                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SWP_EMULATE                              policy<{'armhf': 'y'}>
+CONFIG_SW_SYNC                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SX9500                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SXGBE_ETH                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINK                                 policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINKMP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNCLINK_CS                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_SYNCLINK_GT                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SYNC_FILE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYN_COOKIES                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSCON_REBOOT_MODE                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_SYSCTL                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSCTL_EXCEPTION_TRACE                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSCTL_SYSCALL                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_SYSC_R8A7743                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7745                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A77470                            policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A774A1                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A774C0                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A7779                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7790                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7791                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7792                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7794                             policy<{'armhf': 'y'}>
+CONFIG_SYSC_R8A7795                             policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A7796                             policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A77965                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A77970                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A77980                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A77990                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_R8A77995                            policy<{'arm64': 'y'}>
+CONFIG_SYSC_RCAR                                policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SYSC_RMOBILE                             policy<{'armhf': 'y'}>
+CONFIG_SYSFS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSFS_SYSCALL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEMPORT                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_SYSTEM_BLACKLIST_HASH_LIST               policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_SYSTEM_BLACKLIST_KEYRING                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_DATA_VERIFICATION                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_EXTRA_CERTIFICATE                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE            policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'i386': '4096', 'ppc64el': '4096', 's390x': '4096'}>
+CONFIG_SYSTEM_REVOCATION_KEYS                   policy<{'amd64': '"debian/canonical-revoked-certs.pem"', 'arm64': '"debian/canonical-revoked-certs.pem"', 'armhf': '"debian/canonical-revoked-certs.pem"', 'i386': '"debian/canonical-revoked-certs.pem"', 'ppc64el': '"debian/canonical-revoked-certs.pem"', 's390x': '"debian/canonical-revoked-certs.pem"'}>
+CONFIG_SYSTEM_REVOCATION_LIST                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_TRUSTED_KEYRING                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSTEM_TRUSTED_KEYS                      policy<{'amd64': '"debian/canonical-certs.pem"', 'arm64': '"debian/canonical-certs.pem"', 'armhf': '"debian/canonical-certs.pem"', 'i386': '"debian/canonical-certs.pem"', 'ppc64el': '"debian/canonical-certs.pem"', 's390x': '"debian/canonical-certs.pem"'}>
+CONFIG_SYSV68_PARTITION                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_SYSVIPC                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSVIPC_COMPAT                           policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSVIPC_SYSCTL                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_SYSV_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_SYS_HYPERVISOR                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_SYS_SUPPORTS_APM_EMULATION               policy<{'armhf': 'y'}>
+CONFIG_SYS_SUPPORTS_EM_STI                      policy<{'armhf': 'y'}>
+CONFIG_SYS_SUPPORTS_HUGETLBFS                   policy<{'arm64': 'y', 'armhf-generic-lpae': 'y', 'ppc64el': 'y'}>
+CONFIG_SYS_SUPPORTS_SH_CMT                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_SYS_SUPPORTS_SH_MTU2                     policy<{'armhf': 'y'}>
+CONFIG_SYS_SUPPORTS_SH_TMU                      policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_T5403                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_SERIAL_WACOM4                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_ACECAD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_AIPTEK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_GTCO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_HANWANG                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_KBTAB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TABLET_USB_PEGASUS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TAHVO_USB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TAHVO_USB_HOST_BY_DEFAULT                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TAP                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TARGET_CORE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TASKSTATS                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASKS_RCU                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_DELAY_ACCT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_IO_ACCOUNTING                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TASK_XACCT                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TC1100_WMI                               policy<{'i386': 'm'}>
+CONFIG_TCG_ATMEL                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_CRB                                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_TCG_FTPM_TEE                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TCG_IBMVTPM                              policy<{'ppc64el': 'y'}>
+CONFIG_TCG_INFINEON                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_TCG_NSC                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TCG_TIS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TCG_TIS_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TCG_TIS_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_ST33ZP24                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_TIS_ST33ZP24_I2C                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TCG_TIS_ST33ZP24_SPI                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCG_VTPM_PROXY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCG_XEN                                  policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_TCIC                                     policy<{'i386': 'm'}>
+CONFIG_TCM_FC                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_FILEIO                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_IBLOCK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_PSCSI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCM_QLA2XXX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCM_QLA2XXX_DEBUG                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_TCM_USER2                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_ADVANCED                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCP_CONG_BBR                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_BIC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_CDG                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_CUBIC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCP_CONG_DCTCP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HSTCP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HTCP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_HYBLA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_ILLINOIS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_LP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_NV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_SCALABLE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_VEGAS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_VENO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_WESTWOOD                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_CONG_YEAH                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TCP_MD5SIG                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TCS3414                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TCS3472                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TEE                                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TEGRA124_EMC                             policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA20_APB_DMA                          policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA20_EMC                              policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_AHB                                policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_BPMP                               policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_BPMP_THERMAL                       policy<{'armhf-generic': 'm'}>
+CONFIG_TEGRA_CLK_DFLL                           policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_CLK_EMC                            policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_GMI                                policy<{'armhf-generic': 'm'}>
+CONFIG_TEGRA_HOST1X                             policy<{'armhf-generic': 'm'}>
+CONFIG_TEGRA_HOST1X_FIREWALL                    policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_HSP_MBOX                           policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_IOMMU_GART                         policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_IOMMU_SMMU                         policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_IVC                                policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_MC                                 policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_SOCTHERM                           policy<{'armhf-generic': 'n'}>
+CONFIG_TEGRA_TIMER                              policy<{'armhf-generic': 'y'}>
+CONFIG_TEGRA_VDE                                policy<{'armhf-generic': 'm'}>
+CONFIG_TEGRA_WATCHDOG                           policy<{'armhf-generic': 'm'}>
+CONFIG_TEHUTI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TELCLOCK                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TERANETICS_PHY                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_ASYNC_DRIVER_PROBE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_BITFIELD                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_BITMAP                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_BPF                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEST_FIRMWARE                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_HASH                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_HEXDUMP                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_IDA                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_KMOD                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_KSTRTOX                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_LIST_SORT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_LIVEPATCH                           policy<{'amd64': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_LKM                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_MEMCAT_P                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_MEMINIT                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_OBJAGG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_OVERFLOW                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_PARMAN                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_POWER                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TEST_PRINTF                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_RHASHTABLE                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_SORT                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_STACKINIT                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_STATIC_KEYS                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_STRING_HELPERS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_STRSCPY                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_SYSCTL                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_UDELAY                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_USER_COPY                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_UUID                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_VMALLOC                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEST_XARRAY                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TEXTSEARCH                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TEXTSEARCH_BM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEXTSEARCH_FSM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TEXTSEARCH_KMP                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_THERMAL                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS      policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0'}>
+CONFIG_THERMAL_EMULATION                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_BANG_BANG                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_FAIR_SHARE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_STEP_WISE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_GOV_USER_SPACE                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_HWMON                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_MMIO                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_THERMAL_OF                               policy<{'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_STATISTICS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THERMAL_WRITABLE_TRIPS                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THINKPAD_ACPI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_THINKPAD_ACPI_ALSA_SUPPORT               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_DEBUG                      policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_THINKPAD_ACPI_DEBUGFACILITIES            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_HOTKEY_POLL                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THINKPAD_ACPI_UNSAFE_LEDS                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_THINKPAD_ACPI_VIDEO                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_THP_SWAP                                 policy<{'amd64': 'y'}>
+CONFIG_THREAD_INFO_IN_TASK                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_THREAD_SHIFT                             policy<{'ppc64el': '14'}>
+CONFIG_THRUSTMASTER_FF                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_THUMB2_KERNEL                            policy<{'armhf': 'n'}>
+CONFIG_THUNDERBOLT                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_THUNDERBOLT_NET                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_THUNDERX2_PMU                            policy<{'arm64': 'm'}>
+CONFIG_THUNDER_NIC_BGX                          policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_THUNDER_NIC_PF                           policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_THUNDER_NIC_RGX                          policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_THUNDER_NIC_VF                           policy<{'amd64': 'm', 'arm64': 'm', 'ppc64el': 'm'}>
+CONFIG_TICK_CPU_ACCOUNTING                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TICK_ONESHOT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TIFM_7XX1                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TIFM_CORE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TIGON3                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TIGON3_HWMON                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TIMB_DMA                                 policy<{'i386': 'm'}>
+CONFIG_TIMERFD                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TIMER_ACPI                               policy<{'arm64': 'y'}>
+CONFIG_TIMER_IMX_SYS_CTR                        policy<{'arm64': 'y'}>
+CONFIG_TIMER_OF                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_TIMER_PROBE                              policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_TINYDRM_HX8357D                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_ILI9225                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_ILI9341                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_MI0283QT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_REPAPER                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_ST7586                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TINYDRM_ST7735R                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TIPC                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TIPC_DIAG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TIPC_MEDIA_IB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TIPC_MEDIA_UDP                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TI_ADC081C                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC0832                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC084S021                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC108S102                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC12138                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC128S052                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADC161S626                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADS1015                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADS124S08                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADS7950                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADS8344                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_ADS8688                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_AM335X_ADC                            policy<{'amd64': '-', 'arm64': 'm', 'armhf': 'm', 'i386': '-', 'ppc64el': '-'}>
+CONFIG_TI_CPPI41                                policy<{'armhf': 'm'}>
+CONFIG_TI_CPSW                                  policy<{'armhf': 'y'}>
+CONFIG_TI_CPSW_PHY_SEL                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_TI_CPTS                                  policy<{'armhf': 'y'}>
+CONFIG_TI_CPTS_MOD                              policy<{'armhf': 'y'}>
+CONFIG_TI_DAC082S085                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_DAC5571                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_DAC7311                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_DAC7612                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TI_DAVINCI_EMAC                          policy<{'armhf-generic': 'm'}>
+CONFIG_TI_DAVINCI_MDIO                          policy<{'armhf': 'y'}>
+CONFIG_TI_DMA_CROSSBAR                          policy<{'armhf': 'y'}>
+CONFIG_TI_EDMA                                  policy<{'armhf': 'y'}>
+CONFIG_TI_EMIF                                  policy<{'armhf': 'm'}>
+CONFIG_TI_EMIF_SRAM                             policy<{'armhf-generic': 'm'}>
+CONFIG_TI_MESSAGE_MANAGER                       policy<{'arm64': 'y'}>
+CONFIG_TI_PIPE3                                 policy<{'armhf': 'm'}>
+CONFIG_TI_SCI_CLK                               policy<{'arm64': 'm'}>
+CONFIG_TI_SCI_CLK_PROBE_FROM_FW                 policy<{'arm64': 'n'}>
+CONFIG_TI_SCI_INTA_IRQCHIP                      policy<{'arm64': 'y'}>
+CONFIG_TI_SCI_INTA_MSI_DOMAIN                   policy<{'arm64': 'y'}>
+CONFIG_TI_SCI_INTR_IRQCHIP                      policy<{'arm64': 'y'}>
+CONFIG_TI_SCI_PM_DOMAINS                        policy<{'arm64': 'm'}>
+CONFIG_TI_SCI_PROTOCOL                          policy<{'arm64': 'y'}>
+CONFIG_TI_SOC_THERMAL                           policy<{'armhf': 'm'}>
+CONFIG_TI_ST                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TI_SYSC                                  policy<{'armhf': 'y'}>
+CONFIG_TI_THERMAL                               policy<{'armhf': 'y'}>
+CONFIG_TI_TLC4541                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TLAN                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TLS                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'n', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TLS_DEVICE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMD_HERMES                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TMP006                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TMP007                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TMPFS                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TMPFS_XATTR                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TN3215                                   policy<{'s390x': 'y'}>
+CONFIG_TN3215_CONSOLE                           policy<{'s390x': 'y'}>
+CONFIG_TN3270                                   policy<{'s390x': 'y'}>
+CONFIG_TN3270_CONSOLE                           policy<{'s390x': 'y'}>
+CONFIG_TN3270_FS                                policy<{'s390x': 'm'}>
+CONFIG_TN3270_TTY                               policy<{'s390x': 'y'}>
+CONFIG_TOPSTAR_LAPTOP                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TORTURE_TEST                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TOSHIBA                                  policy<{'i386': 'n'}>
+CONFIG_TOSHIBA_BT_RFKILL                        policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOSHIBA_HAPS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TOSHIBA_WMI                              policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_TOUCHSCREEN_88PM860X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7877                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879_I2C                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AD7879_SPI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ADC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ADS7846                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_AR1021_I2C                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ATMEL_MXT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ATMEL_MXT_T37                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_AUO_PIXCIR                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_BU21013                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_BU21029                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8318              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8505              policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_TOUCHSCREEN_COLIBRI_VF50                 policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CY8CTMG110                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_CORE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP4_SPI                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_CORE                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_I2C                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_CYTTSP_SPI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DA9034                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DA9052                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_DMI                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_TOUCHSCREEN_DYNAPRO                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EDT_FT5X06                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EETI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EGALAX                       policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EGALAX_SERIAL                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EKTF2127                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ELO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_EXC3000                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_FUJITSU                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_GOODIX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_GUNZE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_HAMPSHIRE                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_HIDEEP                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_HTCPEN                       policy<{'i386': 'm'}>
+CONFIG_TOUCHSCREEN_ILI210X                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_IMX6UL_TSC                   policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_INEXIO                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_IPROC                        policy<{'arm64': 'm'}>
+CONFIG_TOUCHSCREEN_IQS5XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MAX11801                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MC13783                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MCS5000                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MELFAS_MIP4                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MK712                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MMS114                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_MTOUCH                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PCAP                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PENMOUNT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PIXCIR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_PROPERTIES                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_RASPBERRYPI_FW               policy<{'arm64': 'm'}>
+CONFIG_TOUCHSCREEN_RM_TS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ROHM_BU21023                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_S6SY761                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SILEAD                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SIS_I2C                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ST1232                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_STMFTS                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_STMPE                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SUN4I                        policy<{'arm64': 'n'}>
+CONFIG_TOUCHSCREEN_SUR40                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SURFACE3_SPI                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_SX8654                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TI_AM335X_TSC                policy<{'amd64': '-', 'arm64': 'm', 'armhf': 'm', 'i386': '-', 'ppc64el': '-'}>
+CONFIG_TOUCHSCREEN_TOUCHIT213                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TOUCHRIGHT                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TOUCHWIN                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TPS6507X                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TS4800                       policy<{'armhf-generic': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2004                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2005                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2007                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC2007_IIO                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_TSC200X_CORE                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_TSC_SERIO                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_UCB1400                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_USB_3M                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_COMPOSITE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_USB_DMC_TSC10                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_E2I                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_EASYTOUCH                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_EGALAX                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ELO                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ETT_TC45USB              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ETURBO                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GOTOP                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_GUNZE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_IDEALTEK                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_IRTOUCH                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ITM                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_JASTEC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_NEXIO                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_PANJIT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_USB_ZYTRONIC                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WACOM_I2C                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WACOM_W8001                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WDT87XX_I2C                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WM831X                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_WM9705                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WM9712                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WM9713                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TOUCHSCREEN_WM97XX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ZET6223                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TOUCHSCREEN_ZFORCE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TPL0102                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TPM_KEY_PARSER                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_TPS6105X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TPS65010                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TPS6507X                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TPS68470_PMIC_OPREGION                   policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_TQMX86_WDT                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_TRACEPOINTS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACEPOINT_BENCHMARK                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRACER_MAX_TRACE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACER_SNAPSHOT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRACE_CLOCK                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACE_EVAL_MAP_FILE                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TRACE_IRQFLAGS_SUPPORT                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACE_ROUTER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TRACE_SINK                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_TRACING                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACING_MAP                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRACING_SUPPORT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRANSPARENT_HUGEPAGE                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS              policy<{'amd64': 'n', 'arm64': 'n', 'armhf-generic-lpae': 'n', 'i386': 'n', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_TRANSPARENT_HUGE_PAGECACHE               policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TREE_RCU                                 policy<{'amd64-generic': 'y', 'arm64': 'y', 'armhf': 'y', 'i386-generic': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TREE_SRCU                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TRUSTED_FOUNDATIONS                      policy<{'armhf': 'y'}>
+CONFIG_TRUSTED_KEYS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TS4800_IRQ                               policy<{'armhf-generic': 'm'}>
+CONFIG_TS4800_WATCHDOG                          policy<{'armhf-generic': 'm'}>
+CONFIG_TSL2583                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TSL2772                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TSL4531                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TSYS01                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TSYS02D                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TTPCI_EEPROM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TTY                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TTY_PRINTK                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_TTY_PRINTK_LEVEL                         policy<{'amd64': '6', 'arm64': '6', 'armhf': '6', 'i386': '6', 'ppc64el': '6'}>
+CONFIG_TULIP                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TULIP_MMIO                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_TULIP_MWI                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_TULIP_NAPI                               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_TUN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_TUNE_DEFAULT                             policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z10                                 policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z13                                 policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z14                                 policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z15                                 policy<{'s390x': 'y'}>
+CONFIG_TUNE_Z196                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z900                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z990                                policy<{'s390x': 'n'}>
+CONFIG_TUNE_Z9_109                              policy<{'s390x': 'n'}>
+CONFIG_TUNE_ZEC12                               policy<{'s390x': 'n'}>
+CONFIG_TUN_VNET_CROSS_LE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_TURRIS_MOX_RWTM                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_TWL4030_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TWL4030_MADC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL4030_POWER                            policy<{'armhf': 'y'}>
+CONFIG_TWL4030_USB                              policy<{'armhf': 'm'}>
+CONFIG_TWL4030_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL6030_GPADC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TWL6030_USB                              policy<{'armhf': 'm'}>
+CONFIG_TWL6040_CORE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_TYPEC                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_DP_ALTMODE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_FUSB302                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_MUX_PI3USB30532                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_NVIDIA_ALTMODE                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_RT1711H                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_TCPCI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_TCPM                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_TPS6598X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPEC_UCSI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_TYPHOON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UACCESS_WITH_MEMCPY                      policy<{'armhf': 'n'}>
+CONFIG_UBIFS_ATIME_SUPPORT                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_UBIFS_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UBIFS_FS_ADVANCED_COMPR                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_UBIFS_FS_AUTHENTICATION                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_LZO                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_SECURITY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_XATTR                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_ZLIB                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBIFS_FS_ZSTD                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UBSAN                                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_UBSAN_ALIGNMENT                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UBUNTU_ODM_DRIVERS                       policy<{'amd64': 'y'}>
+CONFIG_UCB1400_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UCLAMP_BUCKETS_COUNT                     policy<{'amd64': '5', 'arm64': '5', 'armhf': '5', 'i386': '5', 'ppc64el': '5'}>
+CONFIG_UCLAMP_TASK                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UCLAMP_TASK_GROUP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UCS2_STRING                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y'}>
+CONFIG_UCSI_ACPI                                policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_UCSI_CCG                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UDBG_RTAS_CONSOLE                        policy<{'ppc64el': 'n'}>
+CONFIG_UDF_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_UDMABUF                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UEFI_CPER                                policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_UEFI_CPER_ARM                            policy<{'arm64': 'y'}>
+CONFIG_UEFI_CPER_X86                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_UEVENT_HELPER                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UEVENT_HELPER_PATH                       policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_UFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_UFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UFS_FS_WRITE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_UHID                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UID16                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 's390x': 'y'}>
+CONFIG_UIO                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_UIO_AEC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_CIF                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_DMEM_GENIRQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_FSL_ELBC_GPCM                        policy<{'ppc64el': 'm'}>
+CONFIG_UIO_FSL_ELBC_GPCM_NETX5152               policy<{'ppc64el': 'n'}>
+CONFIG_UIO_HV_GENERIC                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_UIO_MF624                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_NETX                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_PCI_GENERIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_PDRV_GENIRQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_PRUSS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_UIO_SERCOS3                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ULI526X                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ULTRA                                    policy<{'i386': 'm'}>
+CONFIG_ULTRIX_PARTITION                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_UNCOMPRESS_INCLUDE                       policy<{'armhf': '"debug/uncompress.h"'}>
+CONFIG_UNICODE                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNICODE_NORMALIZATION_SELFTEST           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_UNINLINE_SPIN_UNLOCK                     policy<{'amd64-lowlatency': 'y', 'i386-lowlatency': 'y'}>
+CONFIG_UNIPHIER_EFUSE                           policy<{'armhf': 'm'}>
+CONFIG_UNIPHIER_MDMAC                           policy<{'armhf': 'm'}>
+CONFIG_UNIPHIER_SYSTEM_BUS                      policy<{'armhf': 'y'}>
+CONFIG_UNIPHIER_THERMAL                         policy<{'armhf': 'm'}>
+CONFIG_UNIPHIER_WATCHDOG                        policy<{'armhf': 'm'}>
+CONFIG_UNISYSSPAR                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_UNISYS_VISORBUS                          policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORHBA                          policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORINPUT                        policy<{'amd64': 'm'}>
+CONFIG_UNISYS_VISORNIC                          policy<{'amd64': 'm'}>
+CONFIG_UNIX                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNIX98_PTYS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNIXWARE_DISKLABEL                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_UNIX_DIAG                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_UNIX_SCM                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNMAP_KERNEL_AT_EL0                      policy<{'arm64': 'y'}>
+CONFIG_UNUSED_SYMBOLS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UNWINDER_GUESS                           policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_UNWINDER_ORC                             policy<{'amd64': 'n'}>
+CONFIG_UPROBES                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UPROBE_EVENTS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_US5182D                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USBIP_CORE                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_DEBUG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USBIP_HOST                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_VHCI_HCD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USBIP_VHCI_HC_PORTS                      policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_USBIP_VHCI_NR_HCS                        policy<{'amd64': '1', 'arm64': '1', 'armhf': '1', 'i386': '1', 'ppc64el': '1'}>
+CONFIG_USBIP_VUDC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USBPCWATCHDOG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ACM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ADUTUX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AIRSPY                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ALI_M5632                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_AMD5536UDC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AN2720                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ANNOUNCE_NEW_DEVICES                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_APPLEDISPLAY                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ARCH_HAS_HCD                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ARMLINUX                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ASPEED_VHUB                          policy<{'armhf': 'm'}>
+CONFIG_USB_ATM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AUDIO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_AUTOSUSPEND_DELAY                    policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'ppc64el': '2'}>
+CONFIG_USB_BDC_UDC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_BELKIN                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_C67X00_HCD                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CATC                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CDC_COMPOSITE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CDC_PHONET                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CDNS3                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CDNS3_GADGET                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CDNS3_HOST                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CDNS3_PCI_WRAP                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_USB_CHAOSKEY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHIPIDEA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHIPIDEA_HOST                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CHIPIDEA_OF                          policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHIPIDEA_PCI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CHIPIDEA_UDC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_COMMON                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CONFIGFS_ACM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_ECM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_ECM_SUBSET                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_EEM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_FS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_HID                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_LB_SS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_MIDI                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_PRINTER                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_TCM                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UAC1                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UAC1_LEGACY               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UAC2                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_F_UVC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_MASS_STORAGE                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_NCM                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_OBEX                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_PHONET                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_RNDIS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONFIGFS_SERIAL                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_CONN_GPIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CXACRU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CYPRESS_CY7C63                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_CYTHERM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DEFAULT_PERSIST                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DSBR                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DUMMY_HCD                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC2                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC2_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC2_DUAL_ROLE                       policy<{'armhf': 'n'}>
+CONFIG_USB_DWC2_HOST                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC2_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DWC2_PERIPHERAL                      policy<{'armhf': 'n'}>
+CONFIG_USB_DWC2_TRACK_MISSED_SOFS               policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC3                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DWC3_DUAL_ROLE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DWC3_EXYNOS                          policy<{'armhf': 'm'}>
+CONFIG_USB_DWC3_GADGET                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC3_HAPS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_DWC3_HOST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_DWC3_KEYSTONE                        policy<{'arm64': 'm'}>
+CONFIG_USB_DWC3_MESON_G12A                      policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_DWC3_OF_SIMPLE                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_DWC3_OMAP                            policy<{'armhf': 'm'}>
+CONFIG_USB_DWC3_PCI                             policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_USB_DWC3_QCOM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_DWC3_ULPI                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_DYNAMIC_MINORS                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EG20T                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EHCI_EXYNOS                          policy<{'armhf': 'y'}>
+CONFIG_USB_EHCI_FSL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EHCI_HCD_NPCM7XX                     policy<{'armhf': 'm'}>
+CONFIG_USB_EHCI_HCD_OMAP                        policy<{'armhf': 'm'}>
+CONFIG_USB_EHCI_HCD_ORION                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_EHCI_HCD_PPC_OF                      policy<{'ppc64el': 'y'}>
+CONFIG_USB_EHCI_MXC                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_USB_EHCI_PCI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_ROOT_HUB_TT                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHCI_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_USB_EHCI_TT_NEWSCHED                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EHSET_TEST_FIXTURE                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMI26                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMI62                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_EMXX                                 policy<{'arm64': 'm', 'armhf': 'y'}>
+CONFIG_USB_EPSON2888                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ETH                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ETH_EEM                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ETH_RNDIS                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_EZUSB_FX2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FOTG210_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FOTG210_UDC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FSL_USB2                             policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_USB_FTDI_ELAN                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FUNCTIONFS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_FUNCTIONFS_ETH                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_FUNCTIONFS_GENERIC                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_FUNCTIONFS_RNDIS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_FUSB300                              policy<{'armhf-generic': 'm'}>
+CONFIG_USB_F_ACM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_ECM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_EEM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_FS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_HID                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_MASS_STORAGE                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_MIDI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_NCM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_OBEX                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_PHONET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_PRINTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_RNDIS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_SS_LB                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_SUBSET                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_TCM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_UAC1                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_UAC1_LEGACY                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_UAC2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_F_UVC                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGETFS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET_DEBUG                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_DEBUG_FILES                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_DEBUG_FS                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS           policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'ppc64el': '2'}>
+CONFIG_USB_GADGET_TARGET                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GADGET_VBUS_DRAW                     policy<{'amd64': '2', 'arm64': '2', 'armhf': '2', 'i386': '2', 'ppc64el': '2'}>
+CONFIG_USB_GADGET_XILINX                        policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GL860                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GOKU                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GPIO_VBUS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GR_UDC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_BENQ                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_CONEX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_CPIA1                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_DTCS033                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_ETOMS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_FINEPIX                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_JEILINJ                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_JL2005BCD                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_KINECT                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_KONICA                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_MARS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_MR97310A                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_NW80X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV519                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV534                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_OV534_9                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC207                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC7302                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_PAC7311                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SE401                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SN9C2028                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SN9C20X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SONIXB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SONIXJ                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA1528                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA500                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA501                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA505                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA506                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA508                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SPCA561                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ905                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ905C                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SQ930X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STK014                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STK1135                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_STV0680                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_SUNPLUS                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_T613                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TOPRO                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TOUPTEK                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_TV8532                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_VC032X                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_VICAM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_XIRLINK_CIT                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_GSPCA_ZC3XX                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_ACM_MS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_DBGP                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_DBGP_PRINTK                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_G_DBGP_SERIAL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_G_HID                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_MULTI                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'm', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_G_MULTI_CDC                          policy<{'armhf': 'y'}>
+CONFIG_USB_G_MULTI_RNDIS                        policy<{'armhf': 'y'}>
+CONFIG_USB_G_NCM                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_NOKIA                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_PRINTER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_G_WEBCAM                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HACKRF                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HCD_TEST_MODE                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_HID                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HIDDEV                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_HSIC_USB3503                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HSIC_USB4604                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HSO                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HUB_USB251XB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_HWA_HCD                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IDMOUSE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IMX21_HCD                            policy<{'armhf-generic': 'm'}>
+CONFIG_USB_IOWARRIOR                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_IPHETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISIGHTFW                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP116X_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP1301                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP1760                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ISP1760_DUAL_ROLE                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ISP1760_GADGET_ROLE                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ISP1760_HCD                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_ISP1760_HOST_ROLE                    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_ISP1761_UDC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_KAWETH                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_KBD                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_KC2190                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_KEENE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LAN78XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LCD                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LD                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LEDS_TRIGGER_USBPORT                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LED_TRIG                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_LEGOTOWER                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LIBCOMPOSITE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_LINK_LAYER_TEST                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_M5602                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MA901                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MASS_STORAGE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MAX3421_HCD                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MDC800                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MICROTEK                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MIDI_GADGET                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MON                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MOUSE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MR800                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MSI2500                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MTU3                                 policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_MTU3_DEBUG                           policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_MTU3_DUAL_ROLE                       policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_MTU3_GADGET                          policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_MTU3_HOST                            policy<{'arm64': 'n', 'armhf': 'n'}>
+CONFIG_USB_MUSB_AM335X_CHILD                    policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_AM35X                           policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_DSPS                            policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_DUAL_ROLE                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_MUSB_GADGET                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_MUSB_HOST                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_MUSB_OMAP2PLUS                       policy<{'armhf': 'm'}>
+CONFIG_USB_MUSB_SUNXI                           policy<{'arm64': 'm'}>
+CONFIG_USB_MUSB_TUSB6010                        policy<{'armhf': 'm'}>
+CONFIG_USB_MV_U3D                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MV_UDC                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_MXS_PHY                              policy<{'arm64': 'y', 'armhf-generic': 'y'}>
+CONFIG_USB_NET2272                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET2272_DMA                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_NET2280                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_AQC111                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_AX88179_178A                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_AX8817X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDCETHER                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_EEM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_MBIM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_NCM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_SUBSET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CDC_SUBSET_ENABLE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CH9200                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_CX82310_ETH                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_DM9601                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_DRIVERS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_GL620A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_HUAWEI_CDC_NCM                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_INT51X1                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_KALMIA                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_MCS7830                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_NET1080                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_PLUSB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_QMI_WWAN                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_RNDIS_HOST                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_RNDIS_WLAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SMSC75XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SMSC95XX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SR9700                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_SR9800                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_NET_ZAURUS                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_OHCI_EXYNOS                          policy<{'armhf': 'y'}>
+CONFIG_USB_OHCI_HCD_OMAP3                       policy<{'armhf-generic': 'm'}>
+CONFIG_USB_OHCI_HCD_PCI                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_OHCI_HCD_PLATFORM                    policy<{'amd64': 'y', 'arm64': 'm', 'armhf-generic': 'm', 'armhf-generic-lpae': 'n', 'i386': 'y', 'ppc64el': 'm'}>
+CONFIG_USB_OHCI_HCD_PPC_OF_BE                   policy<{'ppc64el': 'n'}>
+CONFIG_USB_OHCI_HCD_PPC_OF_LE                   policy<{'ppc64el': 'n'}>
+CONFIG_USB_OHCI_LITTLE_ENDIAN                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USB_OXU210HP_HCD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PCI                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_PEGASUS                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PHY                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_PRINTER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PULSE8_CEC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PWC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_PWC_DEBUG                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_PWC_INPUT_EVDEV                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_PXA27X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_R8A66597                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_R8A66597_HCD                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RAINSHADOW_CEC                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RAREMONO                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RENESAS_USB3                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_RENESAS_USBHS                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_RENESAS_USBHS_HCD                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_RENESAS_USBHS_UDC                    policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_ROLES_INTEL_XHCI                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_USB_ROLE_SWITCH                          policy<{'amd64': 'm', 'arm64': 'y', 'armhf': 'y', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RTL8150                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_RTL8152                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_S2255                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_AIRCABLE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_ARK3116                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_BELKIN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CH341                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CP210X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CYBERJACK                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_CYPRESS_M8                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EDGEPORT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EDGEPORT_TI                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_EMPEG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_F81232                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_F8153X                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_FTDI_SIO                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_GARMIN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_GENERIC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_IPAQ                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IPW                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IR                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_IUU                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KEYSPAN                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KEYSPAN_PDA                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KLSI                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_KOBIL_SCT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MCT_U232                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_METRO                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MOS7715_PARPORT               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SERIAL_MOS7720                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MOS7840                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_MXUPORT                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_NAVMAN                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OMNINET                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OPTICON                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OPTION                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_OTI6858                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_PL2303                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QCAUX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QT2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_QUALCOMM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SAFE                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SAFE_PADDED                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_SERIAL_SIERRAWIRELESS                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SIMPLE                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SPCP8X5                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SSU100                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_SYMBOL                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_TI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_UPD78F0730                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_VISOR                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_WHITEHEAT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_WISHBONE                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_WWAN                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_XIRCOM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SERIAL_XSENS_MT                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SEVSEG                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SI470X                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SI4713                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SIERRA_NET                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SISUSBVGA                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SL811_CS                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_USB_SL811_HCD                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SL811_HCD_ISO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_SNP_CORE                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SNP_UDC_PLAT                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SPEEDTOUCH                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STKWEBCAM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ALAUDA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_CYPRESS_ATACB                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_DATAFAB                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_DEBUG                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_STORAGE_ENE_UB6250                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_FREECOM                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ISD200                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_JUMPSHOT                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_KARMA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_ONETOUCH                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_REALTEK                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_SDDR09                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_SDDR55                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STORAGE_USBAT                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_STV06XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_SUPPORT                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_USB_TEGRA_PHY                            policy<{'armhf-generic': 'm'}>
+CONFIG_USB_TEST                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_TMC                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_TRANCEVIBRATOR                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_U132_HCD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UAS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UEAGLEATM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_UHCI_ASPEED                          policy<{'armhf': 'y'}>
+CONFIG_USB_UHCI_PLATFORM                        policy<{'armhf': 'y'}>
+CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC              policy<{'armhf': 'y'}>
+CONFIG_USB_ULPI                                 policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_ULPI_BUS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ULPI_VIEWPORT                        policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_USB_USBNET                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_USS720                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_U_AUDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_U_ETHER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_U_SERIAL                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_VIDEO_CLASS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_VL600                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WDM                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WHCI_HCD                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB_CBAF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_WUSB_CBAF_DEBUG                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_USB_XHCI_HISTB                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_XHCI_MTK                             policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_XHCI_MVEBU                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_XHCI_PCI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_USB_XHCI_PLATFORM                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_XHCI_RCAR                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_USB_XHCI_TEGRA                           policy<{'armhf-generic': 'm'}>
+CONFIG_USB_XUSBATM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_YUREX                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ZD1201                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ZERO                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USB_ZR364XX                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USELIB                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USERFAULTFD                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USERIO                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_USER_NS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_USER_RETURN_NOTIFIER                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_USER_STACKTRACE_SUPPORT                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_USE_OF                                   policy<{'armhf': 'y'}>
+CONFIG_USE_PERCPU_NUMA_NODE_ID                  policy<{'amd64': 'y', 'arm64': 'y', 'ppc64el': 'y'}>
+CONFIG_UTS_NS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_UV_MMTIMER                               policy<{'amd64': 'm'}>
+CONFIG_UWB                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UWB_HWA                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UWB_I1480U                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_UWB_WHCI                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_U_SERIAL_CONSOLE                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_V4L2_FLASH_LED_CLASS                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_V4L2_FWNODE                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_V4L2_MEM2MEM_DEV                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_V4L_MEM2MEM_DRIVERS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_V4L_PLATFORM_DRIVERS                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_V4L_RADIO_ISA_DRIVERS                    policy<{'i386': 'y'}>
+CONFIG_V4L_TEST_DRIVERS                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VALIDATE_FS_PARSER                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VCNL4000                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VCNL4035                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VDSO                                     policy<{'armhf': 'y'}>
+CONFIG_VEML6070                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VERSION_SIGNATURE                        policy<{'amd64': '""', 'arm64': '""', 'armhf': '""', 'i386': '""', 'ppc64el': '""', 's390x': '""'}>
+CONFIG_VETH                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VEXPRESS_CONFIG                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_VEXPRESS_SYSCFG                          policy<{'arm64': 'y', 'armhf': 'y'}>
+CONFIG_VF610_ADC                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VF610_DAC                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VFIO_AMBA                                policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_AP                                  policy<{'s390x': 'm'}>
+CONFIG_VFIO_CCW                                 policy<{'s390x': 'm'}>
+CONFIG_VFIO_IOMMU_SPAPR_TCE                     policy<{'ppc64el': 'y'}>
+CONFIG_VFIO_IOMMU_TYPE1                         policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 's390x': 'm'}>
+CONFIG_VFIO_MDEV                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VFIO_MDEV_DEVICE                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VFIO_NOIOMMU                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VFIO_PCI_IGD                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VFIO_PCI_INTX                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VFIO_PCI_MMAP                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VFIO_PCI_NVLINK2                         policy<{'ppc64el': 'y'}>
+CONFIG_VFIO_PCI_VGA                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VFIO_PLATFORM                            policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_PLATFORM_AMDXGBE_RESET              policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_PLATFORM_BCMFLEXRM_RESET            policy<{'arm64': 'm'}>
+CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VFIO_SPAPR_EEH                           policy<{'ppc64el': 'y'}>
+CONFIG_VFIO_VIRQFD                              policy<{'amd64': 'y', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_VFP                                      policy<{'armhf': 'y'}>
+CONFIG_VFPv3                                    policy<{'armhf': 'y'}>
+CONFIG_VF_USE_ARM_GLOBAL_TIMER                  policy<{'armhf-generic': 'y'}>
+CONFIG_VF_USE_PIT_TIMER                         policy<{'armhf-generic': 'n'}>
+CONFIG_VGASTATE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VGA_ARB                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VGA_ARB_MAX_GPUS                         policy<{'amd64': '16', 'arm64': '16', 'armhf': '16', 'i386': '16', 'ppc64el': '16'}>
+CONFIG_VGA_CONSOLE                              policy<{'amd64': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VGA_SWITCHEROO                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VHOST                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VHOST_CROSS_ENDIAN_LEGACY                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_VHOST_NET                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VHOST_RING                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VHOST_SCSI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VHOST_VSOCK                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIA_RHINE                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIA_RHINE_MMIO                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIA_VELOCITY                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIA_WDT                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEOBUF2_CORE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_DMA_CONTIG                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_DMA_SG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_DVB                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_MEMOPS                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_V4L2                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF2_VMALLOC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF_DMA_SG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF_GEN                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOBUF_VMALLOC                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEOMODE_HELPERS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_AD5820                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AD9389B                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADP1653                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7170                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7175                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7180                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7183                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7343                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7393                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV748X                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7511                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_ADV7511_CEC                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VIDEO_ADV7604                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7604_CEC                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_ADV7842                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ADV7842_CEC                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_ADV_DEBUG                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_AK7375                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AK881X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ALLEGRO_DVT                        policy<{'arm64': 'm'}>
+CONFIG_VIDEO_APTINA_PLL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ASPEED                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AU0828                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_AU0828_RC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_AU0828_V4L2                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_BCM2835                            policy<{'arm64': 'm'}>
+CONFIG_VIDEO_BT819                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_BT848                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_BT856                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_BT866                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CADENCE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CADENCE_CSI2RX                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CADENCE_CSI2TX                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CAFE_CCIC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_COBALT                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_CODA                               policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_VIDEO_CPIA2                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CROS_EC_CEC                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_CS3308                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CS5345                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CS53L32A                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX18                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX18_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX_DVB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX231XX_RC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CX2341X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX23885                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25821                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25821_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX25840                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_BLACKBIRD                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_DVB                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_ENABLE_VP3054                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_CX88_MPEG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_CX88_VP3054                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_DEV                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_DT3155                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_DW9714                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_DW9807_VCM                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_ALSA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_DVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_RC                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_EM28XX_V4L2                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ET8EK8                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_FB_IVTV                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_FB_IVTV_FORCE_PAT                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VIDEO_FIXED_MINOR_RANGES                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_GO7007                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_LOADER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_USB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_GS1662                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_HDPVR                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_HEXIUM_GEMINI                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_HEXIUM_ORION                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_I2C                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX214                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX258                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX274                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX319                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX355                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IMX7_CSI                           policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_IMX_CSI                            policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_IMX_MEDIA                          policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_IMX_PXP                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_VIDEO_IMX_VDOA                           policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_IPU3_CIO2                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_IPU3_IMGU                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_IR_I2C                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IVTV                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IVTV_ALSA                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_KS0127                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_LM3560                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_LM3646                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_M52790                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_M5MOLS                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MEDIATEK_VPU                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MEM2MEM_DEINTERLACE                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MESON_AO_CEC                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MESON_G12A_AO_CEC                  policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MESON_VDEC                         policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_MEYE                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_ML86V7667                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MSP3400                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9M001                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9M032                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9M111                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9P031                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9T001                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9T112                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9V011                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9V032                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MT9V111                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MUX                                policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_MXB                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_NOON010PC30                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OMAP2_VOUT                         policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_OMAP2_VOUT_VRFB                    policy<{'armhf-generic': 'y'}>
+CONFIG_VIDEO_OMAP3                              policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_OMAP3_DEBUG                        policy<{'armhf-generic': 'n'}>
+CONFIG_VIDEO_OMAP4                              policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_OV13858                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV2640                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV2659                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV2680                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV2685                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5640                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5645                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5647                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5670                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5675                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV5695                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV6650                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7251                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7640                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7670                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV772X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV7740                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV8856                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV9640                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_OV9650                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_PCI_SKELETON                       policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_PVRUSB2                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_PVRUSB2_DEBUGIFC                   policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VIDEO_PVRUSB2_DVB                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_PVRUSB2_SYSFS                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_QCOM_CAMSS                         policy<{'arm64': 'm'}>
+CONFIG_VIDEO_QCOM_VENUS                         policy<{'arm64': 'm'}>
+CONFIG_VIDEO_RCAR_CSI2                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RCAR_DRIF                          policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RCAR_VIN                           policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_CEU                        policy<{'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_FCP                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_FDP1                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_JPU                        policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RENESAS_VSP1                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_RJ54N1                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ROCKCHIP_RGA                       policy<{'arm64': 'm', 'armhf': 'm'}>
+CONFIG_VIDEO_S5C73M3                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_S5K4ECGX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_S5K5BAF                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_S5K6A3                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_S5K6AA                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA6588                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA6752HS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7110                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA711X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7127                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_ALSA                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_DVB                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_GO7007                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7134_RC                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_SAA7146                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7146_VV                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7164                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA717X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAA7185                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS                 policy<{'armhf': 'n'}>
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC                 policy<{'armhf': 'm'}>
+CONFIG_VIDEO_SAMSUNG_S5P_CEC                    policy<{'armhf': '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_SECO_CEC                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_SECO_RC                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VIDEO_SH_VEU                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SMIAPP                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_SMIAPP_PLL                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_SOLO6X10                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SONY_BTF_MPX                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SR030PC30                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_STK1160                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_STK1160_COMMON                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_ST_MIPID02                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_SUN4I_CSI                          policy<{'arm64': 'm'}>
+CONFIG_VIDEO_SUN6I_CSI                          policy<{'arm64': 'm'}>
+CONFIG_VIDEO_SUNXI                              policy<{'arm64': 'y'}>
+CONFIG_VIDEO_TC358743                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TC358743_CEC                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_TDA1997X                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TDA7432                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TDA9840                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TEA6415C                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TEA6420                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TEGRA_HDMI_CEC                     policy<{'armhf-generic': 'm'}>
+CONFIG_VIDEO_THS7303                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_THS8200                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TI_CAL                             policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_CSC                             policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_SC                              policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_VPDMA                           policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_VPE                             policy<{'armhf': 'm'}>
+CONFIG_VIDEO_TI_VPE_DEBUG                       policy<{'armhf': 'n'}>
+CONFIG_VIDEO_TLV320AIC23B                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TM6000                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TM6000_ALSA                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TM6000_DVB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TUNER                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVAUDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVEEPROM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVP514X                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVP5150                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TVP7002                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW2804                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW5864                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW68                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW686X                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW9903                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW9906                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_TW9910                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UDA1342                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UPD64031A                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_UPD64083                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_USBTV                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_USBVISION                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_V4L2                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_V4L2_I2C                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_V4L2_SUBDEV_API                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_V4L2_TPG                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIA_CAMERA                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VIDEO_VICODEC                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIM2M                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIVID                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VIVID_CEC                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIDEO_VIVID_MAX_DEVS                     policy<{'amd64': '64', 'arm64': '64', 'armhf': '64', 'i386': '64', 'ppc64el': '64'}>
+CONFIG_VIDEO_VP27SMPX                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VPX3220                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_VS6624                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_WM8739                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_WM8775                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_XILINX                             policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_XILINX_TPG                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIDEO_XILINX_VTC                         policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_VIPERBOARD_ADC                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIRTIO                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_BALLOON                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_BLK_SCSI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_CONSOLE                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_FS                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_INPUT                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_IOMMU                             policy<{'arm64': 'y'}>
+CONFIG_VIRTIO_MENU                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VIRTIO_PCI                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_PCI_LEGACY                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRTIO_PMEM                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf-generic-lpae': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VIRTIO_VSOCKETS                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTIO_VSOCKETS_COMMON                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VIRTUALIZATION                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRT_CPU_ACCOUNTING                      policy<{'s390x': 'y'}>
+CONFIG_VIRT_CPU_ACCOUNTING_GEN                  policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'ppc64el': 'n'}>
+CONFIG_VIRT_CPU_ACCOUNTING_NATIVE               policy<{'ppc64el': 'n', 's390x': 'y'}>
+CONFIG_VIRT_DRIVERS                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VIRT_TO_BUS                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_VIRT_WIFI                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VITESSE_PHY                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VL53L0X_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VL6180                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VLAN_8021Q                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VLAN_8021Q_GVRP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VLAN_8021Q_MVRP                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VM86                                     policy<{'i386': 'y'}>
+CONFIG_VMAP_STACK                               policy<{'amd64': 'y', 'arm64': 'y', 's390x': 'y'}>
+CONFIG_VMCP                                     policy<{'s390x': 'y'}>
+CONFIG_VMCP_CMA_SIZE                            policy<{'s390x': '4'}>
+CONFIG_VMD                                      policy<{'amd64': 'm'}>
+CONFIG_VME_BUS                                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_VME_CA91CX42                             policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VME_FAKE                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VME_TSI148                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VME_USER                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VMIVME_7805                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VMLOGRDR                                 policy<{'s390x': 'm'}>
+CONFIG_VMSPLIT_1G                               policy<{'armhf': 'n', 'i386': 'n'}>
+CONFIG_VMSPLIT_2G                               policy<{'armhf': 'n', 'i386': 'n'}>
+CONFIG_VMSPLIT_3G                               policy<{'armhf': 'y', 'i386': 'y'}>
+CONFIG_VMSPLIT_3G_OPT                           policy<{'armhf-generic': 'n'}>
+CONFIG_VMWARE_BALLOON                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VMWARE_PVSCSI                            policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VMWARE_VMCI                              policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VMWARE_VMCI_VSOCKETS                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_VMXNET3                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 's390x': 'n'}>
+CONFIG_VM_EVENT_COUNTERS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VOP                                      policy<{'amd64': 'm'}>
+CONFIG_VOP_BUS                                  policy<{'amd64': 'm', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_VORTEX                                   policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VSOCKETS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VSOCKETS_DIAG                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VSOCKMON                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VSX                                      policy<{'ppc64el': 'y'}>
+CONFIG_VT                                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VT6655                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VT6656                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_VT_CONSOLE                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VT_CONSOLE_SLEEP                         policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_VT_HW_CONSOLE_BINDING                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_VXFS_FS                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_VXGE                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_VXGE_DEBUG_TRACE_ALL                     policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_VXLAN                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_VZ89X                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1                                       policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_W1_CON                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_W1_MASTER_DS1WM                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_DS2482                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_DS2490                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_GPIO                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_MATROX                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_MASTER_MXC                            policy<{'arm64': 'm', 'armhf-generic': 'm'}>
+CONFIG_W1_MASTER_SGI                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2405                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2406                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2408                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2408_READBACK                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_W1_SLAVE_DS2413                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2423                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2431                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2433                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2433_CRC                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_W1_SLAVE_DS2438                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS250X                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2780                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2781                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS2805                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS28E04                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_DS28E17                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_SMEM                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_W1_SLAVE_THERM                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': '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_WAFER_WDT                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WAN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_WANT_DEV_COREDUMP                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WANXL                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WARN_ALL_UNSEEDED_RANDOM                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_WARN_DYNAMIC_STACK                       policy<{'s390x': 'n'}>
+CONFIG_WATCHDOG                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_CORE                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_NOWAYOUT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_WATCHDOG_OPEN_TIMEOUT                    policy<{'amd64': '0', 'arm64': '0', 'armhf': '0', 'i386': '0', 'ppc64el': '0', 's390x': '0'}>
+CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC    policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_WATCHDOG_PRETIMEOUT_GOV                  policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_WATCHDOG_RTAS                            policy<{'ppc64el': 'm'}>
+CONFIG_WATCHDOG_SYSFS                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_WCN36XX                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WCN36XX_DEBUGFS                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_WCN36XX_SNAPDRAGON_HACKS                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_WD80x3                                   policy<{'i386': 'm'}>
+CONFIG_WDAT_WDT                                 policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_WDT                                      policy<{'i386': 'm'}>
+CONFIG_WDTPCI                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_WEXT_CORE                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WEXT_PRIV                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WEXT_PROC                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WEXT_SPY                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIL6210                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WIL6210_DEBUGFS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIL6210_ISR_COR                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIL6210_TRACING                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WILC1000                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WILC1000_HW_OOB_INTR                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WILC1000_SDIO                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WILC1000_SPI                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WILCO_EC                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WILCO_EC_DEBUGFS                         policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WILCO_EC_EVENTS                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WILCO_EC_TELEMETRY                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WILINK_PLATFORM_DATA                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIMAX                                    policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_WIMAX_DEBUG_LEVEL                        policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_WIMAX_I2400M                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL                 policy<{'amd64': '8', 'arm64': '8', 'armhf': '8', 'i386': '8', 'ppc64el': '8'}>
+CONFIG_WIMAX_I2400M_USB                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WINBOND_840                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WINDFARM                                 policy<{'ppc64el': 'm'}>
+CONFIG_WIRELESS                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIRELESS_EXT                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIRELESS_WDS                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_WIZNET_BUS_ANY                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WIZNET_BUS_DIRECT                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_WIZNET_BUS_INDIRECT                      policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_WIZNET_W5100                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WIZNET_W5100_SPI                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WIZNET_W5300                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WKUP_M3_IPC                              policy<{'armhf-generic': 'n'}>
+CONFIG_WKUP_M3_RPROC                            policy<{'armhf-generic': 'm'}>
+CONFIG_WL1251                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WL1251_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WL1251_SPI                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WL12XX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WL18XX                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WLAN                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_ADMTEK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_ATH                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_ATMEL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_BROADCOM                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_CISCO                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_INTEL                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_INTERSIL                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_MARVELL                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_MEDIATEK                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_QUANTENNA                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_RALINK                       policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_REALTEK                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_RSI                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_ST                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_TI                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLAN_VENDOR_ZYDAS                        policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WLCORE                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WLCORE_SDIO                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WLCORE_SPI                               policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_BACKUP                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WM831X_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WM8350_POWER                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WM8350_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_WMI_BMOF                                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_WQ_WATCHDOG                              policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_WW_MUTEX_SELFTEST                        policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_X25                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_X25_ASY                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_X86                                      policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_16BIT                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_32                                   policy<{'i386': 'y'}>
+CONFIG_X86_32_IRIS                              policy<{'i386': 'm'}>
+CONFIG_X86_32_NON_STANDARD                      policy<{'i386': 'n'}>
+CONFIG_X86_32_SMP                               policy<{'i386': 'y'}>
+CONFIG_X86_5LEVEL                               policy<{'amd64': 'n'}>
+CONFIG_X86_64                                   policy<{'amd64': 'y'}>
+CONFIG_X86_64_ACPI_NUMA                         policy<{'amd64': 'y'}>
+CONFIG_X86_64_SMP                               policy<{'amd64': 'y'}>
+CONFIG_X86_ACPI_CPUFREQ_CPB                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_AMD_FREQ_SENSITIVITY                 policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_AMD_PLATFORM_DEVICE                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_ANCIENT_MCE                          policy<{'i386': 'n'}>
+CONFIG_X86_APM_BOOT                             policy<{'i386': 'y'}>
+CONFIG_X86_BIGSMP                               policy<{'i386': 'n'}>
+CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_CHECK_BIOS_CORRUPTION                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_CMOV                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_CMPXCHG64                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_CPA_STATISTICS                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_CPUID                                policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_CPU_RESCTRL                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_DEBUGCTLMSR                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_DEBUG_FPU                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_DECODER_SELFTEST                     policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_DEV_DMA_OPS                          policy<{'amd64': 'y'}>
+CONFIG_X86_DIRECT_GBPAGES                       policy<{'amd64': 'y'}>
+CONFIG_X86_ESPFIX32                             policy<{'i386': 'y'}>
+CONFIG_X86_ESPFIX64                             policy<{'amd64': 'y'}>
+CONFIG_X86_EXTENDED_PLATFORM                    policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_E_POWERSAVER                         policy<{'i386': 'n'}>
+CONFIG_X86_FEATURE_NAMES                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_GENERIC                              policy<{'i386': 'y'}>
+CONFIG_X86_GOLDFISH                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_GX_SUSPMOD                           policy<{'i386': 'm'}>
+CONFIG_X86_HV_CALLBACK_VECTOR                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_LPSS                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS         policy<{'amd64': 'y'}>
+CONFIG_X86_INTEL_MID                            policy<{'amd64': 'n', 'i386': 'y'}>
+CONFIG_X86_INTEL_MPX                            policy<{'amd64': 'y'}>
+CONFIG_X86_INTEL_PSTATE                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_QUARK                          policy<{'i386': 'n'}>
+CONFIG_X86_INTEL_TSX_MODE_AUTO                  policy<{'amd64': 'n', 'i386': 'n'}>
+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_UMIP                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_INTEL_USERCOPY                       policy<{'i386': 'y'}>
+CONFIG_X86_INTERNODE_CACHE_SHIFT                policy<{'amd64': '6', 'i386': '6'}>
+CONFIG_X86_IO_APIC                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_L1_CACHE_SHIFT                       policy<{'amd64': '6', 'i386': '6'}>
+CONFIG_X86_LOCAL_APIC                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_LONGHAUL                             policy<{'i386': 'm'}>
+CONFIG_X86_LONGRUN                              policy<{'i386': 'm'}>
+CONFIG_X86_MCE                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCELOG_LEGACY                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCE_AMD                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCE_INJECT                           policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_MCE_INTEL                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MCE_THRESHOLD                        policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MINIMUM_CPU_FAMILY                   policy<{'amd64': '64', 'i386': '6'}>
+CONFIG_X86_MPPARSE                              policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_MSR                                  policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_NEED_RELOCS                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_NUMACHIP                             policy<{'amd64': 'y'}>
+CONFIG_X86_P4_CLOCKMOD                          policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_PAE                                  policy<{'i386': 'y'}>
+CONFIG_X86_PAT                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PKG_TEMP_THERMAL                     policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_X86_PLATFORM_DEVICES                     policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PMEM_LEGACY                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PMEM_LEGACY_DEVICE                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_PM_TIMER                             policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_POWERNOW_K6                          policy<{'i386': 'm'}>
+CONFIG_X86_POWERNOW_K7                          policy<{'i386': 'm'}>
+CONFIG_X86_POWERNOW_K7_ACPI                     policy<{'i386': 'y'}>
+CONFIG_X86_PTDUMP                               policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_PTDUMP_CORE                          policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_RDC321X                              policy<{'i386': 'n'}>
+CONFIG_X86_REBOOTFIXUPS                         policy<{'i386': 'y'}>
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_RESERVE_LOW                          policy<{'amd64': '64', 'i386': '64'}>
+CONFIG_X86_SFI_CPUFREQ                          policy<{'i386': 'm'}>
+CONFIG_X86_SMAP                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE             policy<{'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_LIB                        policy<{'amd64': 'm', 'i386': 'y'}>
+CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK          policy<{'i386': 'y'}>
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE              policy<{'amd64': 'y'}>
+CONFIG_X86_SYSFB                                policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_THERMAL_VECTOR                       policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_TSC                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_X86_USE_PPRO_CHECKSUM                    policy<{'i386': 'y'}>
+CONFIG_X86_VERBOSE_BOOTUP                       policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_X86_VSMP                                 policy<{'amd64': 'n'}>
+CONFIG_X86_VSYSCALL_EMULATION                   policy<{'amd64': 'y'}>
+CONFIG_X86_X2APIC                               policy<{'amd64': 'y'}>
+CONFIG_X86_X32                                  policy<{'amd64': 'y'}>
+CONFIG_XARRAY_MULTI                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf-generic-lpae': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XDP_SOCKETS                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XDP_SOCKETS_DIAG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XEN                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'n', 'i386': 'y'}>
+CONFIG_XENFS                                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_ACPI                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_AUTO_XLATE                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BACKEND                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BALLOON                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG               policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT         policy<{'amd64': '512', 'i386': '4'}>
+CONFIG_XEN_BLKDEV_BACKEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_COMPAT_XENFS                         policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_DEBUG_FS                             policy<{'amd64': 'n', 'i386': 'n'}>
+CONFIG_XEN_DEV_EVTCHN                           policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_DOM0                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_EFI                                  policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_XEN_FBDEV_FRONTEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_FRONT_PGDIR_SHBUF                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_GNTDEV                               policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_GNTDEV_DMABUF                        policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_GRANT_DEV_ALLOC                      policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_GRANT_DMA_ALLOC                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_HAVE_PVMMU                           policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_HAVE_VPMU                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_MCE_LOG                              policy<{'amd64': 'y'}>
+CONFIG_XEN_NETDEV_BACKEND                       policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PCIDEV_BACKEND                       policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PCIDEV_FRONTEND                      policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PRIVCMD                              policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PV                                   policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_PVCALLS_BACKEND                      policy<{'amd64': 'n', 'arm64': 'n', 'i386': 'n'}>
+CONFIG_XEN_PVCALLS_FRONTEND                     policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_PVH                                  policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_PVHVM                                policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_PVHVM_SMP                            policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_PV_SMP                               policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SAVE_RESTORE                         policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SCRUB_PAGES_DEFAULT                  policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SCSI_BACKEND                         policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_SCSI_FRONTEND                        policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_SYMS                                 policy<{'amd64': 'y', 'i386': 'y'}>
+CONFIG_XEN_SYS_HYPERVISOR                       policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XEN_WDT                                  policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_XEN_XENBUS_FRONTEND                      policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_XFRM                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFRM_ALGO                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFRM_INTERFACE                           policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFRM_IPCOMP                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFRM_MIGRATE                             policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFRM_OFFLOAD                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFRM_STATISTICS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFRM_SUB_POLICY                          policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFRM_USER                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFS_DEBUG                                policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFS_FS                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XFS_ONLINE_SCRUB                         policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XFS_POSIX_ACL                            policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_QUOTA                                policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_RT                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XFS_WARN                                 policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_XGENE_DMA                                policy<{'arm64': 'm'}>
+CONFIG_XGENE_PMU                                policy<{'arm64': 'y'}>
+CONFIG_XGENE_SLIMPRO_MBOX                       policy<{'arm64': 'm'}>
+CONFIG_XIAOMI_WMI                               policy<{'amd64': 'm', 'i386': 'm'}>
+CONFIG_XILINX_AXI_EMAC                          policy<{'amd64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_XILINX_DMA                               policy<{'arm64': 'm'}>
+CONFIG_XILINX_GMII2RGMII                        policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XILINX_LL_TEMAC                          policy<{'amd64': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_XILINX_PR_DECOUPLER                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_XILINX_SDFEC                             policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_XILINX_VCU                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XILINX_WATCHDOG                          policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_XILINX_XADC                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_XILINX_ZYNQMP_DMA                        policy<{'arm64': 'm'}>
+CONFIG_XILLYBUS                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_XILLYBUS_OF                              policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_XILLYBUS_PCIE                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_XIL_AXIS_FIFO                            policy<{'arm64': 'm', 'armhf': 'm', 'ppc64el': 'm'}>
+CONFIG_XMON                                     policy<{'ppc64el': 'y'}>
+CONFIG_XMON_DEFAULT                             policy<{'ppc64el': 'n'}>
+CONFIG_XMON_DEFAULT_RO_MODE                     policy<{'ppc64el': 'y'}>
+CONFIG_XMON_DISASSEMBLY                         policy<{'ppc64el': 'y'}>
+CONFIG_XOR_BLOCKS                               policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_XPS                                      policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XXHASH                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_XZ_DEC_ARM                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_ARMTHUMB                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_BCJ                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_XZ_DEC_IA64                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_POWERPC                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_SPARC                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_XZ_DEC_TEST                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_XZ_DEC_X86                               policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'n'}>
+CONFIG_YAM                                      policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_YELLOWFIN                                policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_YENTA                                    policy<{'amd64': 'm', 'arm64': 'm', 'i386': 'm'}>
+CONFIG_YENTA_ENE_TUNE                           policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_YENTA_O2                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_YENTA_RICOH                              policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_YENTA_TI                                 policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_YENTA_TOSHIBA                            policy<{'amd64': 'y', 'arm64': 'y', 'i386': 'y'}>
+CONFIG_Z3FOLD                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ZBOOT_ROM_BSS                            policy<{'armhf': '0x0'}>
+CONFIG_ZBOOT_ROM_TEXT                           policy<{'armhf': '0x0'}>
+CONFIG_ZBUD                                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZCRYPT                                   policy<{'s390x': 'm'}>
+CONFIG_ZD1211RW                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ZD1211RW_DEBUG                           policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n'}>
+CONFIG_ZEROPLUS_FF                              policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y'}>
+CONFIG_ZFCP                                     policy<{'s390x': 'm'}>
+CONFIG_ZIIRAVE_WATCHDOG                         policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'n'}>
+CONFIG_ZISOFS                                   policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZLIB_DEFLATE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'm'}>
+CONFIG_ZLIB_INFLATE                             policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZONE_DEVICE                              policy<{'amd64': 'y', 'ppc64el': 'y'}>
+CONFIG_ZONE_DMA32                               policy<{'amd64': 'y', 'arm64': 'y'}>
+CONFIG_ZOPT2201                                 policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ZPA2326                                  policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ZPA2326_I2C                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ZPA2326_SPI                              policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm'}>
+CONFIG_ZPOOL                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZRAM                                     policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ZRAM_MEMORY_TRACKING                     policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZRAM_WRITEBACK                           policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZSMALLOC                                 policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZSMALLOC_STAT                            policy<{'amd64': 'n', 'arm64': 'n', 'armhf': 'n', 'i386': 'n', 'ppc64el': 'n', 's390x': 'n'}>
+CONFIG_ZSTD_COMPRESS                            policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm', 'ppc64el': 'm', 's390x': 'm'}>
+CONFIG_ZSTD_DECOMPRESS                          policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZSWAP                                    policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'i386': 'y', 'ppc64el': 'y', 's390x': 'y'}>
+CONFIG_ZX_TDM                                   policy<{'amd64': 'm', 'arm64': 'm', 'armhf': 'm', 'i386': 'm'}>
+CONFIG_ZYNQMP_FIRMWARE                          policy<{'arm64': 'y'}>
+CONFIG_ZYNQMP_FIRMWARE_DEBUG                    policy<{'arm64': 'n'}>
+CONFIG_ZYNQMP_IPI_MBOX                          policy<{'arm64': 'y'}>
+CONFIG_ZYNQMP_PM_DOMAINS                        policy<{'arm64': 'y'}>
+CONFIG_ZYNQMP_POWER                             policy<{'arm64': 'y'}>
--- linux-ein-5.4.0.orig/debian.master/control.d/flavour-control.stub
+++ linux-ein-5.4.0/debian.master/control.d/flavour-control.stub
@@ -0,0 +1,152 @@
+# 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, aufs-dkms, =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
+Breaks: flash-kernel (<< 3.90ubuntu2) [arm64 armhf], s390-tools (<< 2.3.0-0ubuntu3) [s390x]
+Conflicts: linux-image=SIGN-PEER-PKG=-PKGVER-ABINUM-FLAVOUR
+Suggests: fdutils, linux-doc | 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}
+Built-Using: ${linux:BuiltUsing}
+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-ein-5.4.0.orig/debian.master/control.d/generic.inclusion-list
+++ linux-ein-5.4.0/debian.master/control.d/generic.inclusion-list
@@ -0,0 +1,258 @@
+arch/*/{crypto,kernel,oprofile}
+arch/*/kvm/kvm.ko
+arch/powerpc/kvm/kvm-hv.ko
+arch/powerpc/kvm/kvm-pr.ko
+arch/powerpc/kvm/vfio.ko
+arch/powerpc/platforms/powernv/opal-prd.ko
+arch/s390/*
+arch/x86/kvm/kvm-amd.ko
+arch/x86/kvm/kvm-intel.ko
+crypto/*
+drivers/acpi/*
+drivers/ata/acard-ahci.ko
+drivers/ata/ahci.ko
+drivers/ata/ahci_platform.ko
+drivers/ata/ata_generic.ko
+drivers/ata/libahci.ko
+drivers/ata/libahci_platform.ko
+drivers/block/brd.ko
+drivers/block/cryptoloop.ko
+drivers/block/floppy.ko
+drivers/block/loop.ko
+drivers/block/nbd.ko
+drivers/block/rbd.ko
+drivers/block/virtio_blk.ko
+drivers/block/xen-blkfront.ko
+drivers/char/hangcheck-timer.ko
+drivers/char/hw_random/powernv-rng.ko
+drivers/char/hw_random/virtio-rng.ko
+drivers/char/ipmi/*
+drivers/char/ipmi/ipmi_msghandler.ko
+drivers/char/lp.ko
+drivers/char/nvram.ko
+drivers/char/ppdev.ko
+drivers/char/raw.ko
+drivers/char/virtio_console.ko
+drivers/crypto/nx/*
+drivers/crypto/vmx/vmx-crypto.ko
+drivers/firmware/efi/*
+drivers/firmware/iscsi_ibft.ko
+drivers/gpu/drm/ast/ast.ko
+drivers/gpu/drm/bochs/bochs-drm.ko
+drivers/gpu/drm/cirrus/cirrus.ko
+drivers/gpu/drm/drm_kms_helper.ko
+drivers/gpu/drm/drm.ko
+drivers/gpu/drm/ttm/ttm.ko
+drivers/gpu/drm/vboxvideo/vboxvideo.ko
+drivers/gpu/drm/virtio/virtio-gpu.ko
+drivers/gpu/drm/vmwgfx/vmwgfx.ko
+drivers/gpu/drm/xen/drm_xen_front.ko
+drivers/hid/hid-generic.ko
+drivers/hid/hid-hyperv.ko
+drivers/hid/hid.ko
+drivers/hid/usbhid/usbhid.ko
+drivers/hv/*
+drivers/hwmon/ibmpowernv.ko
+drivers/infiniband/core/ib_addr.ko
+drivers/infiniband/core/ib_cm.ko
+drivers/infiniband/core/ib_core.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/joydev.ko
+drivers/input/misc/xen-kbdfront.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/touchscreen/usbtouchscreen.ko
+drivers/leds/leds-powernv.ko
+drivers/md/*
+drivers/message/fusion*
+drivers/misc/cxl/*
+drivers/misc/eeprom/at24.ko
+drivers/misc/vmw_balloon.ko
+drivers/misc/vmw_vmci/vmw_vmci.ko
+drivers/mtd/cmdlinepart.ko
+drivers/mtd/devices/powernv_flash.ko
+drivers/mtd/ofpart.ko
+drivers/net/appletalk/ipddp.ko
+drivers/net/bonding/bonding.ko
+drivers/net/caif/caif_virtio.ko
+drivers/net/dummy.ko
+drivers/net/eql.ko
+drivers/net/ethernet/8390/8390.ko
+drivers/net/ethernet/8390/ne2k-pci.ko
+drivers/net/ethernet/amazon/ena/ena.ko
+drivers/net/ethernet/amd/pcnet32.ko
+drivers/net/ethernet/broadcom/bnx2x/*
+drivers/net/ethernet/broadcom/tg3.ko
+drivers/net/ethernet/dec/tulip/*
+drivers/net/ethernet/emulex/benet/*
+drivers/net/ethernet/ibm/*
+drivers/net/ethernet/intel/e1000/e1000.ko
+drivers/net/ethernet/intel/e1000e/e1000e.ko
+drivers/net/ethernet/intel/i40e/*
+drivers/net/ethernet/intel/iavf/iavf.ko
+drivers/net/ethernet/intel/igb/*
+drivers/net/ethernet/intel/igbvf/igbvf.ko
+drivers/net/ethernet/intel/ixgbe/*
+drivers/net/ethernet/intel/ixgbevf/ixgbevf.ko
+drivers/net/ethernet/mellanox/*
+drivers/net/ethernet/netronome/nfp/nfp.ko
+drivers/net/ethernet/realtek/8139cp.ko
+drivers/net/ethernet/realtek/8139too.ko
+drivers/net/fddi/*
+drivers/net/geneve.ko
+drivers/net/hyperv/hv_netvsc.ko
+drivers/net/ifb.ko
+drivers/net/ipvlan/*
+drivers/net/macvlan.ko
+drivers/net/macvtap.ko
+drivers/net/mii.ko
+drivers/net/netconsole.ko
+drivers/net/ppp/*
+drivers/net/ppp/bsd_comp.ko
+drivers/net/slip/*
+drivers/net/veth.ko
+drivers/net/virtio_net.ko
+drivers/net/vmxnet3/vmxnet3.ko
+drivers/net/vxlan.ko
+drivers/net/xen-netback/*
+drivers/net/xen-netfront.ko
+drivers/nvme/host/nvme.ko
+drivers/nvmem/nvmem_core.ko
+drivers/parport/parport.ko
+drivers/parport/parport_pc.ko
+drivers/pci/host/vmd.ko
+drivers/platform/x86/pvpanic.ko
+drivers/pps/pps_core.ko
+drivers/ptp/ptp.ko
+drivers/s390/*
+drivers/s390/block/xpram.ko
+drivers/scsi/aacraid/*
+drivers/scsi/BusLogic.ko
+drivers/scsi/cxlflash/*
+drivers/scsi/device_handler/scsi_dh_alua.ko
+drivers/scsi/device_handler/scsi_dh_emc.ko
+drivers/scsi/device_handler/scsi_dh_hp_sw.ko
+drivers/scsi/device_handler/scsi_dh_rdac.ko
+drivers/scsi/hv_storvsc.ko
+drivers/scsi/ibmvscsi/*
+drivers/scsi/ipr.ko
+drivers/scsi/iscsi_boot_sysfs.ko
+drivers/scsi/iscsi_tcp.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/libosd.ko
+drivers/scsi/osd/osd.ko
+drivers/scsi/qla1280.ko
+drivers/scsi/qla2xxx/*
+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/scsi_transport_spi.ko
+drivers/scsi/sd_mod.ko
+drivers/scsi/sr_mod.ko
+drivers/scsi/virtio_scsi.ko
+drivers/scsi/vmw_pvscsi.ko
+drivers/target/target_core*.ko
+drivers/target/loopback/tcm_loop.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/*
+drivers/video/vgastate.ko
+drivers/virtio/*
+drivers/watchdog/softdog.ko
+drivers/xen/*
+! find sound/core -name oss -prune -o -name *.ko -print
+fs/9p/*
+fs/aufs/aufs.ko
+fs/autofs/autofs4.ko
+fs/binfmt_misc.ko
+fs/btrfs/*
+fs/cachefiles/cachefiles.ko
+fs/ceph/*
+fs/cifs/*
+fs/configfs/*
+fs/dlm/dlm.ko
+fs/ecryptfs/*
+fs/efivarfs/*
+fs/exofs/libore.ko
+fs/ext4/*
+fs/fat/*
+fs/fscache/*
+fs/fuse/*
+fs/isofs/*
+fs/lockd/*
+fs/nfs/*
+fs/nfs_common/*
+fs/nfsd/*
+fs/nls/nls_cp437.ko
+fs/nls/nls_iso8859-1.ko
+fs/overlayfs/*
+fs/shiftfs.ko
+fs/squashfs/*
+fs/udf/*
+fs/ufs/*
+fs/xfs/*
+lib/*
+net/6lowpan/*
+net/802/*
+net/8021q/*
+net/9p/*
+net/appletalk/*
+net/atm/*
+net/ax25/*
+net/bpfilter/*
+net/bridge/*
+net/can/*
+net/ceph/libceph.ko
+net/core/*
+net/dccp/*
+net/decnet/*
+net/ieee802154/*
+net/ipv4/*
+net/ipv6/*
+net/ipx/*
+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/sunrpc/auth_gss/auth_rpcgss.ko
+net/sunrpc/auth_gss/rpcsec_gss_krb5.ko
+net/sunrpc/sunrpc.ko
+net/tipc/*
+net/unix/unix_diag.ko
+net/vmw_vsock/*
+net/x25/*
+net/xfrm/*
+sound/drivers/pcsp/snd-pcsp.ko
+sound/pci/snd-ens1370.ko
+sound/soundcore.ko
--- linux-ein-5.4.0.orig/debian.master/control.d/linux-doc.stub
+++ linux-ein-5.4.0/debian.master/control.d/linux-doc.stub
@@ -0,0 +1,12 @@
+Package: linux-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.
--- linux-ein-5.4.0.orig/debian.master/control.d/linux-libc-dev.stub
+++ linux-ein-5.4.0/debian.master/control.d/linux-libc-dev.stub
@@ -0,0 +1,12 @@
+Package: linux-libc-dev
+Architecture: amd64 armhf arm64 i386 ppc64el riscv64 s390x
+Depends: ${misc:Depends}
+Conflicts: linux-kernel-headers
+Replaces: linux-kernel-headers
+Provides: linux-kernel-headers, aufs-dev
+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.
--- linux-ein-5.4.0.orig/debian.master/control.d/vars.generic
+++ linux-ein-5.4.0/debian.master/control.d/vars.generic
@@ -0,0 +1,6 @@
+arch="amd64 armhf arm64 ppc64el s390x"
+supported="Generic"
+target="Geared toward desktop and server systems."
+desc="=HUMAN= SMP"
+bootloader="grub-pc [amd64] | grub-efi-amd64 [amd64] | grub-efi-ia32 [amd64] | grub [amd64] | lilo [amd64] | flash-kernel [armhf arm64] | grub-efi-arm64 [arm64] | grub-efi-arm [armhf] | grub-ieee1275 [ppc64el]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [amd64]"
--- linux-ein-5.4.0.orig/debian.master/control.d/vars.generic-lpae
+++ linux-ein-5.4.0/debian.master/control.d/vars.generic-lpae
@@ -0,0 +1,6 @@
+arch="armhf"
+supported="Generic LPAE"
+target="Geared toward desktop and server systems."
+desc="=HUMAN= SMP"
+bootloader="flash-kernel [armhf] | grub-efi-arm [armhf]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules"
--- linux-ein-5.4.0.orig/debian.master/control.d/vars.lowlatency
+++ linux-ein-5.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 [amd64] | grub-efi-amd64 [amd64] | grub-efi-ia32 [amd64] | grub [amd64] | lilo [amd64] | flash-kernel [armhf arm64] | grub-efi-arm64 [arm64] | grub-efi-arm [armhf]"
+provides="kvm-api-4, redhat-cluster-modules, ivtv-modules, virtualbox-guest-modules [amd64]"
--- linux-ein-5.4.0.orig/debian.master/control.stub.in
+++ linux-ein-5.4.0/debian.master/control.stub.in
@@ -0,0 +1,155 @@
+Source: SRCPKGNAME
+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] <!stage1>,
+ libcap-dev <!stage1>,
+ libelf-dev <!stage1>,
+ libnewt-dev <!stage1>,
+ libiberty-dev <!stage1>,
+ default-jdk-headless <!stage1>,
+ java-common <!stage1>,
+ rsync <!stage1>,
+ libdw-dev <!stage1>,
+ libpci-dev <!stage1>,
+ pkg-config <!stage1>,
+ flex <!stage1>,
+ bison <!stage1>,
+ libunwind8-dev [amd64 arm64 armhf ppc64el] <!stage1>,
+ liblzma-dev <!stage1>,
+ openssl <!stage1>,
+ libssl-dev <!stage1>,
+ libaudit-dev <!stage1>,
+ bc <!stage1>,
+ gawk <!stage1>,
+ libudev-dev <!stage1>,
+ autoconf <!stage1>,
+ automake <!stage1>,
+ libtool <!stage1>,
+ uuid-dev <!stage1>,
+ libnuma-dev [amd64 arm64 ppc64el s390x] <!stage1>,
+ dkms <!stage1>,
+ curl <!stage1>,
+ lz4 [amd64 s390x] <!stage1>,
+ dwarves [amd64 arm64 armhf ppc64el s390x] <!stage1>,
+Build-Depends-Indep:
+ xmlto <!stage1>,
+ docbook-utils <!stage1>,
+ ghostscript <!stage1>,
+ fig2dev <!stage1>,
+ bzip2 <!stage1>,
+ sharutils <!stage1>,
+ asciidoc <!stage1>,
+ python3-sphinx <!stage1>,
+ python3-sphinx-rtd-theme <!stage1>,
+ fontconfig <!stage1>,
+ python3-docutils <!stage1>,
+Vcs-Git: git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/=SERIES=
+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
+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-headers-PKGVER-ABINUM
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, coreutils
+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-tools-common
+Build-Profiles: <!stage1>
+Architecture: all
+Multi-Arch: foreign
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, lsb-release
+Conflicts: linux-oem-5.6-tools-common
+Replaces: linux-oem-5.6-tools-common
+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 armhf arm64 ppc64el s390x
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-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
+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 armhf
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-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
+Conflicts: linux-oem-5.6-tools-host
+Replaces: linux-oem-5.6-tools-host
+Description: Linux kernel VM host tools
+ This package provides kernel tools useful for VM hosts.
+
--- linux-ein-5.4.0.orig/debian.master/copyright
+++ linux-ein-5.4.0/debian.master/copyright
@@ -0,0 +1,29 @@
+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'.
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/README.txt
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/firmware/amd64/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/amd64/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/amd64/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/amd64/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/amd64/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/amd64/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/arm64/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/arm64/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/arm64/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/arm64/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/arm64/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/arm64/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/armhf/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/armhf/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/i386/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/i386/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/i386/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/i386/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/i386/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/i386/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/nic-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/firmware/powerpc/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/powerpc/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/powerpc/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/powerpc/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/powerpc/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/powerpc/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/ppc64el/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/ppc64el/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/ppc64el/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/ppc64el/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/ppc64el/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/ppc64el/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/s390x/README.txt
+++ linux-ein-5.4.0/debian.master/d-i/firmware/s390x/README.txt
@@ -0,0 +1,4 @@
+#
+# Place the names of udeb modules into this directory that require
+# runtime firmware.
+#
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/s390x/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/s390x/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/s390x/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/s390x/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/firmware/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/firmware/scsi-modules
@@ -0,0 +1,3 @@
+qlogic/1040.bin ?
+qlogic/12160.bin ?
+qlogic/1280.bin ?
--- linux-ein-5.4.0.orig/debian.master/d-i/kernel-versions
+++ linux-ein-5.4.0/debian.master/d-i/kernel-versions
@@ -0,0 +1,16 @@
+# arch	version		flavour		installedname			suffix	bdep
+amd64	-		generic		-				-	-
+
+i386	-		generic		-				-	-
+
+armhf	-		generic		-				-	-
+armhf	-		generic-lpae	-				-	-
+
+arm64	-		generic		-				-	-
+
+ppc64el	-		generic		-				-	-
+
+s390x	-		generic		-				-	-
+
+# Ports
+# arch	version		flavour		installedname			suffix	bdep
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/fb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/fb-modules
@@ -0,0 +1 @@
+#include <fb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/floppy-modules
@@ -0,0 +1 @@
+#include <floppy-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/serial-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/serial-modules
@@ -0,0 +1 @@
+#include <serial-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64-virtual/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64-virtual/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/fb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/fb-modules
@@ -0,0 +1 @@
+#include <fb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/firewire-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/firewire-core-modules
@@ -0,0 +1 @@
+#include <firewire-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/floppy-modules
@@ -0,0 +1 @@
+#include <floppy-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/input-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/input-modules
@@ -0,0 +1 @@
+#include <input-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/ipmi-modules
@@ -0,0 +1 @@
+#include <ipmi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/nic-pcmcia-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/nic-pcmcia-modules
@@ -0,0 +1 @@
+#include <nic-pcmcia-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/nic-usb-modules
@@ -0,0 +1 @@
+#include <nic-usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/pata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/pata-modules
@@ -0,0 +1 @@
+#include <pata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/pcmcia-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/pcmcia-modules
@@ -0,0 +1 @@
+#include <pcmcia-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/pcmcia-storage-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/pcmcia-storage-modules
@@ -0,0 +1 @@
+#include <pcmcia-storage-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/plip-modules
@@ -0,0 +1 @@
+#include <plip-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/ppp-modules
@@ -0,0 +1 @@
+#include <ppp-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/sata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/sata-modules
@@ -0,0 +1 @@
+#include <sata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/serial-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/serial-modules
@@ -0,0 +1 @@
+#include <serial-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/speakup-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/speakup-modules
@@ -0,0 +1 @@
+#include <speakup-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/usb-modules
@@ -0,0 +1 @@
+#include <usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/amd64/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/amd64/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/input-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/input-modules
@@ -0,0 +1 @@
+#include <input-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/ipmi-modules
@@ -0,0 +1 @@
+#include <ipmi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/nic-usb-modules
@@ -0,0 +1 @@
+#include <nic-usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/plip-modules
@@ -0,0 +1 @@
+#include <plip-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/ppp-modules
@@ -0,0 +1 @@
+#include <ppp-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/sata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/sata-modules
@@ -0,0 +1 @@
+#include <sata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/speakup-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/speakup-modules
@@ -0,0 +1 @@
+#include <speakup-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/usb-modules
@@ -0,0 +1 @@
+#include <usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/arm64/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/arm64/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/input-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/input-modules
@@ -0,0 +1 @@
+#include <input-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/ipmi-modules
@@ -0,0 +1 @@
+#include <ipmi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/nic-usb-modules
@@ -0,0 +1 @@
+#include <nic-usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/plip-modules
@@ -0,0 +1 @@
+#include <plip-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/ppp-modules
@@ -0,0 +1 @@
+#include <ppp-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/sata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/sata-modules
@@ -0,0 +1 @@
+#include <sata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/speakup-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/speakup-modules
@@ -0,0 +1 @@
+#include <speakup-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/usb-modules
@@ -0,0 +1 @@
+#include <usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/armhf/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/armhf/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/block-modules
@@ -0,0 +1,43 @@
+aoe ?
+aten ?
+bcm2835 ?
+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-ein-5.4.0.orig/debian.master/d-i/modules/block-modules.powerpc
+++ linux-ein-5.4.0/debian.master/d-i/modules/block-modules.powerpc
@@ -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-ein-5.4.0.orig/debian.master/d-i/modules/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/crypto-modules
@@ -0,0 +1,78 @@
+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 ?
+crc32_generic ?
+crc32c_generic ?
+crc32-vx_s390 ?
+cryptd ?
+cryptoloop ?
+crypto_null ?
+crypto_user ?
+ctr ?
+cts ?
+des_generic ?
+fcrypt ?
+gcm ?
+gf128mul ?
+ghash-clmulni-intel ?
+ghash-generic ?
+khazad ?
+lrw ?
+lzo ?
+md4 ?
+michael_mic ?
+padlock-aes ?
+padlock-sha ?
+paes_s390 ?
+pcbc ?
+pcrypt ?
+pkey ?
+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 ?
+zcrypt ?
+zcrypt_cex2a ?
+zcrypt_cex4 ?
+zcrypt_pcixcc ?
+zlib ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/dasd-extra-modules.s390x
+++ linux-ein-5.4.0/debian.master/d-i/modules/dasd-extra-modules.s390x
@@ -0,0 +1 @@
+dasd_diag_mod ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/dasd-modules.s390x
+++ linux-ein-5.4.0/debian.master/d-i/modules/dasd-modules.s390x
@@ -0,0 +1,3 @@
+dasd_mod ?
+dasd_fba_mod ?
+dasd_eckd_mod ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/fat-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/fb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/fb-modules
@@ -0,0 +1,3 @@
+fbcon ?
+vesafb ?
+vga16fb ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/firewire-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/firewire-core-modules
@@ -0,0 +1,4 @@
+firewire-core ?
+firewire-ohci ?
+firewire-sbp2 ?
+firewire-net ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/floppy-modules
@@ -0,0 +1 @@
+floppy ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/fs-core-modules
@@ -0,0 +1,6 @@
+ext2 ?
+ext4 ?
+jfs ?
+reiserfs ?
+xfs ?
+zfs ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/fs-secondary-modules
@@ -0,0 +1,5 @@
+btrfs ?
+fuse ?
+ntfs ?
+hfs ?
+hfsplus ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/fb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/fb-modules
@@ -0,0 +1 @@
+#include <fb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/floppy-modules
@@ -0,0 +1 @@
+#include <floppy-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/serial-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/serial-modules
@@ -0,0 +1 @@
+#include <serial-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386-virtual/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386-virtual/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/fb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/fb-modules
@@ -0,0 +1 @@
+#include <fb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/firewire-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/firewire-core-modules
@@ -0,0 +1 @@
+#include <firewire-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/floppy-modules
@@ -0,0 +1 @@
+#include <floppy-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/input-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/input-modules
@@ -0,0 +1 @@
+#include <input-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/ipmi-modules
@@ -0,0 +1 @@
+#include <ipmi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/mouse-modules
@@ -0,0 +1 @@
+#include <mouse-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/nic-pcmcia-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/nic-pcmcia-modules
@@ -0,0 +1 @@
+#include <nic-pcmcia-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/nic-usb-modules
@@ -0,0 +1 @@
+#include <nic-usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/pata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/pata-modules
@@ -0,0 +1 @@
+#include <pata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/pcmcia-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/pcmcia-modules
@@ -0,0 +1 @@
+#include <pcmcia-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/pcmcia-storage-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/pcmcia-storage-modules
@@ -0,0 +1 @@
+#include <pcmcia-storage-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/plip-modules
@@ -0,0 +1 @@
+#include <plip-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/ppp-modules
@@ -0,0 +1 @@
+#include <ppp-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/sata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/sata-modules
@@ -0,0 +1 @@
+#include <sata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/serial-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/serial-modules
@@ -0,0 +1 @@
+#include <serial-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/speakup-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/speakup-modules
@@ -0,0 +1 @@
+#include <speakup-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/usb-modules
@@ -0,0 +1 @@
+#include <usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/i386/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/i386/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/input-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ipmi-modules
@@ -0,0 +1,5 @@
+ipmi_devintf ?
+ipmi_msghandler ?
+ipmi_poweroff ?
+ipmi_si ?
+ipmi_watchdog ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/kernel-image
@@ -0,0 +1,31 @@
+ast ?
+gpio-pca953x ?
+gpio-regulator ?
+hibmc-drm ?
+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-ein-5.4.0.orig/debian.master/d-i/modules/md-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/message-modules
@@ -0,0 +1,9 @@
+mptbase ?
+mptctl ?
+mptfc ?
+mptlan ?
+mptsas ?
+mpt2sas ?
+mpt3sas ?
+mptscsih ?
+mptspi ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/message-modules.powerpc
+++ linux-ein-5.4.0/debian.master/d-i/modules/message-modules.powerpc
@@ -0,0 +1,7 @@
+mptbase
+mptctl
+mptfc
+mptlan
+mptsas
+mptscsih
+mptspi
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/mouse-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/mouse-modules
@@ -0,0 +1,2 @@
+psmouse ?
+usbmouse ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/multipath-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/nfs-modules
@@ -0,0 +1,6 @@
+nfs ?
+nfs_acl ?
+nfsv3 ?
+lockd ?
+sunrpc ?
+cifs ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/nic-modules
@@ -0,0 +1,209 @@
+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 ?
+bonding ?
+brcmfmac ?
+brcmsmac ?
+broadcom ?
+xgmac ?
+cassini ?
+ccwgroup ?
+com20020 ?
+com20020-pci ?
+com90io ?
+com90xx ?
+cs89x0 ?
+ctcm ?
+cxgb4 ?
+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 ?
+ibmvnic ?
+igb ?
+ps3_gelic ?
+hamachi ?
+hclge ?
+hermes ?
+hfi1 ?
+hinic ?
+hns_dsaf ?
+hns_enet_drv ?
+hns_mdio ?
+hns3 ?
+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 ?
+netsec ?
+netxen_nic ?
+ni5010 ?
+ni52 ?
+ni65 ?
+nicpf ?
+nicvf ?
+niu ?
+ns83820 ?
+olympic ?
+orinoco ?
+orinoco_pci ?
+orinoco_plx ?
+orinoco_tmd ?
+pcnet32 ?
+qcom-emac ?
+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-ein-5.4.0.orig/debian.master/d-i/modules/nic-modules.powerpc
+++ linux-ein-5.4.0/debian.master/d-i/modules/nic-modules.powerpc
@@ -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-ein-5.4.0.orig/debian.master/d-i/modules/nic-pcmcia-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/nic-shared-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/nic-usb-modules
@@ -0,0 +1,34 @@
+ax88179_178a ?
+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 ?
+r8152 ?
+smsc95xx ?
+zaurus ?
+carl9170 ?
+smsc75xx ?
+smsc95xx ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/parport-modules
@@ -0,0 +1,2 @@
+parport ?
+parport_pc ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/pata-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/pcmcia-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/pcmcia-storage-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/plip-modules
@@ -0,0 +1 @@
+plip ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/crypto-modules
@@ -0,0 +1 @@
+#include <crypto-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/floppy-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/floppy-modules
@@ -0,0 +1 @@
+#include <floppy-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/input-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/input-modules
@@ -0,0 +1 @@
+#include <input-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/ipmi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/ipmi-modules
@@ -0,0 +1 @@
+#include <ipmi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/message-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/message-modules
@@ -0,0 +1 @@
+#include <message-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/nic-usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/nic-usb-modules
@@ -0,0 +1 @@
+#include <nic-usb-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/parport-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/parport-modules
@@ -0,0 +1 @@
+#include <parport-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/plip-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/plip-modules
@@ -0,0 +1 @@
+#include <plip-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/ppp-modules
@@ -0,0 +1 @@
+#include <ppp-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/sata-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/sata-modules
@@ -0,0 +1 @@
+#include <sata-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/scsi-modules
@@ -0,0 +1 @@
+#include <scsi-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/storage-core-modules
@@ -0,0 +1,2 @@
+#include <storage-core-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppc64el/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppc64el/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/ppp-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/ppp-modules
@@ -0,0 +1,6 @@
+ppp_async ?
+ppp_deflate ?
+ppp_mppe ?
+pppoe ?
+pppox ?
+ppp_synctty ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/block-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/block-modules
@@ -0,0 +1 @@
+#include <block-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/crypto-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/crypto-modules
@@ -0,0 +1,2 @@
+#include <crypto-modules>
+deflate ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/dasd-extra-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/dasd-extra-modules
@@ -0,0 +1 @@
+#include <dasd-extra-modules.s390x>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/dasd-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/dasd-modules
@@ -0,0 +1 @@
+#include <dasd-modules.s390x>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/fat-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/fat-modules
@@ -0,0 +1 @@
+#include <fat-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/fs-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/fs-core-modules
@@ -0,0 +1 @@
+#include <fs-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/fs-secondary-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/fs-secondary-modules
@@ -0,0 +1 @@
+#include <fs-secondary-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/kernel-image
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/kernel-image
@@ -0,0 +1 @@
+#include <kernel-image>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/md-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/md-modules
@@ -0,0 +1 @@
+#include <md-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/multipath-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/multipath-modules
@@ -0,0 +1 @@
+#include <multipath-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/nfs-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/nfs-modules
@@ -0,0 +1 @@
+#include <nfs-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/nic-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/nic-modules
@@ -0,0 +1 @@
+#include <nic-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/nic-shared-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/nic-shared-modules
@@ -0,0 +1 @@
+#include <nic-shared-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/scsi-modules
@@ -0,0 +1,2 @@
+#include <scsi-modules>
+ipr ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/storage-core-modules
@@ -0,0 +1 @@
+#include <storage-core-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/virtio-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/virtio-modules
@@ -0,0 +1 @@
+#include <virtio-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/s390x/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/s390x/vlan-modules
@@ -0,0 +1 @@
+#include <vlan-modules>
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/sata-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/scsi-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/scsi-modules
@@ -0,0 +1,137 @@
+# SCSI
+raid_class ?
+scsi_transport_spi ?
+scsi_transport_fc ?
+scsi_transport_iscsi ?
+scsi_transport_sas ?
+sr_mod ?
+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 ?
+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 ?
+sd_mod ?
+hisi_sas_v2_hw ?
+hisi_sas_v3_hw ?
+iscsi_ibft ?
+
+# device handlers
+scsi_dh_alua ?
+scsi_dh_emc ?
+scsi_dh_rdac ?
+scsi_dh_hp_sw ?
+
+smartpqi ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/scsi-modules.powerpc
+++ linux-ein-5.4.0/debian.master/d-i/modules/scsi-modules.powerpc
@@ -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-ein-5.4.0.orig/debian.master/d-i/modules/serial-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/serial-modules
@@ -0,0 +1,4 @@
+generic_serial ?
+serial_cs ?
+synclink_cs ?
+hyperv-keyboard ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/speakup-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/storage-core-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/storage-core-modules
@@ -0,0 +1,15 @@
+# Core stacks
+usb-storage ?
+
+# Block level
+ata_piix ?
+ata_generic ?
+
+# Loop modules
+cryptoloop ?
+
+# Needs to be here for better cdrom initrd layout
+isofs ?
+
+# Needed for NVMe disks under VMD PCIe domains
+vmd ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/storage-core-modules.powerpc
+++ linux-ein-5.4.0/debian.master/d-i/modules/storage-core-modules.powerpc
@@ -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-ein-5.4.0.orig/debian.master/d-i/modules/usb-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/usb-modules
@@ -0,0 +1,15 @@
+ehci-hcd ?
+isp116x-hcd ?
+isp1760 ?
+ohci-hcd ?
+r8a66597-hcd ?
+sl811_cs ?
+sl811-hcd ?
+u132-hcd ?
+uhci-hcd ?
+xhci-hcd ?
+xhci-plat-hcd ?
+ehci-tegra ?
+ehci-msm ?
+ehci-platform ?
+uas ?
--- linux-ein-5.4.0.orig/debian.master/d-i/modules/virtio-modules
+++ linux-ein-5.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-ein-5.4.0.orig/debian.master/d-i/modules/vlan-modules
+++ linux-ein-5.4.0/debian.master/d-i/modules/vlan-modules
@@ -0,0 +1,3 @@
+slp ?
+garp ?
+8021q ?
--- linux-ein-5.4.0.orig/debian.master/d-i/package-list
+++ linux-ein-5.4.0/debian.master/d-i/package-list
@@ -0,0 +1,203 @@
+Package: kernel-image
+Provides: ext3-modules, ext4-modules, squashfs-modules
+Provides_amd64: efi-modules, ext3-modules, ext4-modules, squashfs-modules
+Provides_i386: efi-modules, ext3-modules, ext4-modules, squashfs-modules
+Provides_ppc64el: ext3-modules, ext4-modules, fat-modules, squashfs-modules
+Provides_s390x: ext3-modules, ext4-modules, ppp-modules, squashfs-modules
+Description: kernel image and system map
+
+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: 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-ein-5.4.0.orig/debian.master/dkms-versions
+++ linux-ein-5.4.0/debian.master/dkms-versions
@@ -0,0 +1,3 @@
+zfs-linux 0.8.3-1ubuntu12.17
+virtualbox 6.1.50-dfsg-1~ubuntu1.20.04.1
+wireguard-linux-compat 1.0.20201112-1~20.04.1
--- linux-ein-5.4.0.orig/debian.master/etc/kernelconfig
+++ linux-ein-5.4.0/debian.master/etc/kernelconfig
@@ -0,0 +1,7 @@
+if [ "$variant" = "ports" ]; then
+	archs=""
+	family='ports'
+else
+	archs="amd64 i386 armhf arm64 ppc64el s390x"
+	family='ubuntu'
+fi
--- linux-ein-5.4.0.orig/debian.master/modprobe.d/common.conf
+++ linux-ein-5.4.0/debian.master/modprobe.d/common.conf
@@ -0,0 +1,3 @@
+# LP:1434842 -- disable OSS drivers by default to allow pulseaudio to emulate
+blacklist snd-mixer-oss
+blacklist snd-pcm-oss
--- linux-ein-5.4.0.orig/debian.master/reconstruct
+++ linux-ein-5.4.0/debian.master/reconstruct
@@ -0,0 +1,122 @@
+# Recreate any symlinks created since the orig.
+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/config-check'
+chmod +x 'debian/scripts/control-create'
+chmod +x 'debian/scripts/dkms-build'
+chmod +x 'debian/scripts/dkms-build--nvidia-N'
+chmod +x 'debian/scripts/dkms-build--virtualbox-guest'
+chmod +x 'debian/scripts/dkms-build-configure--zfs'
+chmod +x 'debian/scripts/file-downloader'
+chmod +x 'debian/scripts/link-headers'
+chmod +x 'debian/scripts/misc/annotations'
+chmod +x 'debian/scripts/misc/arch-has-odm-enabled.sh'
+chmod +x 'debian/scripts/misc/final-checks'
+chmod +x 'debian/scripts/misc/find-missing-sauce.sh'
+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/kernel-wedge-arch.pl'
+chmod +x 'debian/scripts/misc/kernelconfig'
+chmod +x 'debian/scripts/misc/migrate-annotations'
+chmod +x 'debian/scripts/misc/retag'
+chmod +x 'debian/scripts/misc/splitconfig.pl'
+chmod +x 'debian/scripts/misc/tristate.sh'
+chmod +x 'debian/scripts/misc/update-aufs.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 'samples/bpf/lwt_len_hist.sh'
+chmod +x 'samples/bpf/test_lwt_bpf.sh'
+chmod +x 'scripts/kmsg-doc'
+chmod +x 'scripts/parse-maintainers.pl'
+chmod +x 'tools/testing/selftests/net/fib_nexthop_nongw.sh'
+chmod +x 'tools/testing/selftests/netfilter/conntrack_vrf.sh'
+# Remove any files deleted from the orig.
+rm -f 'Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml'
+rm -f 'Documentation/networking/decnet.txt'
+rm -f 'arch/alpha/include/asm/bugs.h'
+rm -f 'arch/ia64/include/asm/bugs.h'
+rm -f 'arch/m68k/include/asm/bugs.h'
+rm -f 'arch/parisc/include/asm/bugs.h'
+rm -f 'arch/parisc/kernel/module.lds'
+rm -f 'arch/parisc/lib/string.S'
+rm -f 'arch/powerpc/include/asm/bugs.h'
+rm -f 'arch/powerpc/include/uapi/asm/bpf_perf_event.h'
+rm -f 'arch/sh/include/asm/bugs.h'
+rm -f 'arch/sparc/include/asm/bugs.h'
+rm -f 'arch/um/include/asm/bugs.h'
+rm -f 'arch/um/kernel/gmon_syms.c'
+rm -f 'arch/x86/events/intel/rapl.c'
+rm -f 'arch/x86/include/asm/refcount.h'
+rm -f 'arch/xtensa/include/asm/bugs.h'
+rm -f 'drivers/block/sx8.c'
+rm -f 'drivers/crypto/hisilicon/sgl.h'
+rm -f 'drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h'
+rm -f 'drivers/iio/adc/stx104.c'
+rm -f 'drivers/input/serio/i8042-ppcio.h'
+rm -f 'drivers/net/can/dev.c'
+rm -f 'drivers/net/can/rx-offload.c'
+rm -f 'drivers/net/phy/mdio-i2c.h'
+rm -f 'drivers/net/phy/mdio-xgene.h'
+rm -f 'drivers/soc/qcom/llcc-sdm845.c'
+rm -f 'drivers/soc/qcom/llcc-slice.c'
+rm -f 'drivers/staging/mt7621-dma/mtk-hsdma.c'
+rm -f 'include/Kbuild'
+rm -f 'include/asm-generic/bugs.h'
+rm -f 'include/linux/kd.h'
+rm -f 'include/net/dn.h'
+rm -f 'include/net/dn_dev.h'
+rm -f 'include/net/dn_fib.h'
+rm -f 'include/net/dn_neigh.h'
+rm -f 'include/net/dn_nsp.h'
+rm -f 'include/net/dn_route.h'
+rm -f 'include/trace/events/random.h'
+rm -f 'include/uapi/linux/dn.h'
+rm -f 'include/uapi/linux/netfilter_decnet.h'
+rm -f 'include/uapi/rdma/nes-abi.h'
+rm -f 'kernel/elfcore.c'
+rm -f 'net/decnet/Kconfig'
+rm -f 'net/decnet/Makefile'
+rm -f 'net/decnet/README'
+rm -f 'net/decnet/af_decnet.c'
+rm -f 'net/decnet/dn_dev.c'
+rm -f 'net/decnet/dn_fib.c'
+rm -f 'net/decnet/dn_neigh.c'
+rm -f 'net/decnet/dn_nsp_in.c'
+rm -f 'net/decnet/dn_nsp_out.c'
+rm -f 'net/decnet/dn_route.c'
+rm -f 'net/decnet/dn_rules.c'
+rm -f 'net/decnet/dn_table.c'
+rm -f 'net/decnet/dn_timer.c'
+rm -f 'net/decnet/netfilter/Kconfig'
+rm -f 'net/decnet/netfilter/Makefile'
+rm -f 'net/decnet/netfilter/dn_rtmsg.c'
+rm -f 'net/decnet/sysctl_net_decnet.c'
+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 'net/sched/sch_atm.c'
+rm -f 'net/sched/sch_cbq.c'
+rm -f 'net/sched/sch_dsmark.c'
+rm -f 'net/xfrm/xfrm_interface.c'
+rm -f 'tools/build/feature/test-libpython-version.c'
+exit 0
--- linux-ein-5.4.0.orig/debian.master/rules.d/amd64.mk
+++ linux-ein-5.4.0/debian.master/rules.d/amd64.mk
@@ -0,0 +1,27 @@
+human_arch	= 64 bit x86
+build_arch	= x86
+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_perf_jvmti = true
+do_tools_bpftool = true
+do_tools_x86	= true
+do_tools_hyperv	= true
+do_tools_host = true
+do_extras_package = true
+do_tools_common = true
+do_tools_acpidbg = true
+do_zfs		= true
+do_dkms_vbox    = true
+do_dkms_wireguard = true
+do_odm_drivers    = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/arm64.mk
+++ linux-ein-5.4.0/debian.master/rules.d/arm64.mk
@@ -0,0 +1,24 @@
+human_arch	= ARMv8
+build_arch	= arm64
+header_arch	= arm64
+defconfig	= defconfig
+flavours	= generic
+build_image_generic	= Image.gz
+kernel_file_generic	= arch/$(build_arch)/boot/Image.gz
+install_file	= vmlinuz
+no_dumpfile = true
+uefi_signed     = true
+
+loader		= grub
+vdso		= vdso_install
+
+do_extras_package = true
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf   = true
+do_tools_perf_jvmti = true
+do_tools_bpftool = true
+
+do_dtbs		= true
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/armhf.mk
+++ linux-ein-5.4.0/debian.master/rules.d/armhf.mk
@@ -0,0 +1,21 @@
+human_arch	= ARM (hard float)
+build_arch	= arm
+header_arch	= arm
+defconfig	= defconfig
+flavours	= generic generic-lpae
+build_image	= zImage
+kernel_file	= arch/$(build_arch)/boot/zImage
+install_file	= vmlinuz
+no_dumpfile	= true
+
+loader		= grub
+
+do_tools_usbip  = true
+do_tools_cpupower = true
+do_tools_perf	= true
+do_tools_perf_jvmti = true
+do_tools_bpftool = true
+
+do_dtbs		= true
+
+do_dkms_wireguard = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/hooks.mk
+++ linux-ein-5.4.0/debian.master/rules.d/hooks.mk
@@ -0,0 +1 @@
+do_enforce_all = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/i386.mk
+++ linux-ein-5.4.0/debian.master/rules.d/i386.mk
@@ -0,0 +1,19 @@
+human_arch	= 32 bit x86
+build_arch	= i386
+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
+do_flavour_image_package = false
+do_tools	= false
+do_tools_common	= false
+do_extras_package = false
+do_source_package = false
+do_doc_package	= false
+do_flavour_header_package = false
+do_common_headers_indep = false
--- linux-ein-5.4.0.orig/debian.master/rules.d/ppc64el.mk
+++ linux-ein-5.4.0/debian.master/rules.d/ppc64el.mk
@@ -0,0 +1,22 @@
+human_arch	= PowerPC 64el
+build_arch	= powerpc
+header_arch	= $(build_arch)
+defconfig	= pseries_le_defconfig
+flavours	= generic
+build_image	= vmlinux.strip
+kernel_file     = arch/powerpc/boot/vmlinux.strip
+install_file	= vmlinux
+no_dumpfile	= true
+vdso		= vdso_install
+loader		= grub
+do_extras_package = true
+opal_signed       = true
+do_tools_usbip    = true
+do_tools_cpupower = true
+do_tools_perf	  = true
+do_tools_perf_jvmti = true
+do_tools_bpftool  = true
+
+#do_flavour_image_package = false
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/riscv64.mk
+++ linux-ein-5.4.0/debian.master/rules.d/riscv64.mk
@@ -0,0 +1,21 @@
+human_arch	= RISC-V
+build_arch	= riscv
+header_arch	= $(build_arch)
+defconfig	= defconfig
+flavours        = generic
+build_image	= Image
+kernel_file	= arch/$(build_arch)/boot/Image
+install_file	= vmlinuz
+
+loader		= grub
+vdso		= vdso_install
+no_dumpfile	= true
+
+do_flavour_image_package = false
+do_tools	= false
+do_tools_common	= false
+do_extras_package = false
+do_source_package = false
+do_doc_package	= false
+do_flavour_header_package = false
+do_common_headers_indep = false
--- linux-ein-5.4.0.orig/debian.master/rules.d/s390x.mk
+++ linux-ein-5.4.0/debian.master/rules.d/s390x.mk
@@ -0,0 +1,22 @@
+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
+sipl_signed       = true
+do_tools_usbip    = true
+do_tools_cpupower = true
+do_tools_perf     = true
+do_tools_perf_jvmti = true
+do_tools_bpftool  = true
+
+do_zfs		= true
+do_dkms_wireguard = true
--- linux-ein-5.4.0.orig/debian.master/rules.d/x32.mk
+++ linux-ein-5.4.0/debian.master/rules.d/x32.mk
@@ -0,0 +1,14 @@
+human_arch	= 64 bit x86 (32 bit userspace)
+build_arch	= x86
+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-ein-5.4.0.orig/debian.master/tracking-bug
+++ linux-ein-5.4.0/debian.master/tracking-bug
@@ -0,0 +1 @@
+2068291 s2024.04.29-1
--- linux-ein-5.4.0.orig/debian.master/upstream-stable
+++ linux-ein-5.4.0/debian.master/upstream-stable
@@ -0,0 +1,3 @@
+# The following upstream stable releases have been ported:
+[upstream-stable]
+    linux-5.4.y = v5.4.271
--- linux-ein-5.4.0.orig/debian/canonical-certs.pem
+++ linux-ein-5.4.0/debian/canonical-certs.pem
@@ -0,0 +1,246 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            c7:7e:51:6a:1c:25:cd:40
+        Signature Algorithm: sha512WithRSAEncryption
+        Issuer: CN = Canonical Ltd. Live Patch Signing
+        Validity
+            Not Before: Jul 18 23:41:27 2016 GMT
+            Not After : Jul 16 23:41:27 2026 GMT
+        Subject: CN = Canonical Ltd. Live Patch Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (4096 bit)
+                Modulus:
+                    00:bd:74:ee:72:b3:4a:ab:e6:31:e8:29:24:c2:bd:
+                    46:98:32:c0:39:ee:a3:fb:8a:ad:fe:ab:1a:5b:a3:
+                    2e:a1:80:db:79:61:9e:47:79:2c:75:57:a2:21:f0:
+                    93:f6:87:f2:9b:4b:9d:2f:b3:58:61:28:3c:41:70:
+                    13:16:a1:72:90:c9:d5:16:71:7c:e0:30:f9:28:5e:
+                    48:20:36:00:69:b7:59:9f:a3:ec:a8:eb:55:41:9f:
+                    38:1e:22:4a:57:20:f4:83:59:49:c5:00:93:d3:33:
+                    02:92:d1:fc:f0:84:3b:4a:5b:8f:b6:73:9a:89:fa:
+                    30:1e:e6:2a:68:f2:91:ef:59:57:3d:dc:1c:52:6f:
+                    5e:e6:9b:b5:b8:7c:98:c9:13:d1:39:68:01:67:91:
+                    e0:d3:67:72:16:0a:5e:16:83:45:31:4f:b5:2b:b3:
+                    f6:40:86:89:3a:84:6e:6f:16:61:bc:70:84:be:5a:
+                    13:36:7b:82:ea:07:19:fc:18:c1:16:c6:32:0b:7d:
+                    2c:6b:c4:21:b9:38:6b:31:dc:d9:0c:ad:56:40:68:
+                    7c:e3:c6:64:8e:bf:1c:e0:72:3e:6c:db:d2:73:79:
+                    da:d7:c5:2f:5d:04:7d:b0:07:1e:95:dd:2a:47:5e:
+                    bf:3e:3a:c8:66:f6:67:0f:d4:2a:f1:e2:71:59:d2:
+                    6c:7b:a0:37:ac:e6:97:80:30:13:97:48:d5:74:fc:
+                    38:68:e4:57:cb:99:69:5a:84:27:ac:98:51:e4:64:
+                    bd:91:62:e8:58:27:06:2a:b9:0b:b8:08:e5:e5:b4:
+                    51:a7:a2:10:df:4e:07:6c:a0:3b:96:f2:6e:df:75:
+                    8c:97:1e:64:a0:9a:86:9b:98:26:f9:d8:b7:de:5b:
+                    21:b7:af:89:01:a3:f7:98:6b:da:19:ba:86:ef:ef:
+                    f1:ce:bb:2f:89:ed:c0:b6:1b:e5:5b:f8:90:11:9a:
+                    52:93:e9:be:f7:35:b9:08:cb:ba:c3:ed:2f:73:af:
+                    cc:96:07:55:b5:de:f6:03:f6:f1:89:f9:21:40:76:
+                    c1:69:f2:61:cc:9a:94:df:9c:ec:6a:65:38:be:d1:
+                    4e:2a:87:c7:2f:3e:53:ae:8b:9f:54:a1:09:59:64:
+                    25:aa:a9:d8:44:a9:a8:a0:71:e1:32:aa:4c:32:fd:
+                    44:28:cc:9c:6f:8e:db:81:7e:6f:fa:00:56:c5:e5:
+                    03:46:63:fb:8e:71:8d:e3:13:91:9f:ac:60:3e:64:
+                    f3:df:25:34:09:fa:2d:96:9f:16:05:ea:93:f5:e6:
+                    00:08:27:32:7b:3c:bd:ee:70:24:6c:3b:55:e9:db:
+                    f4:10:2d:20:06:b4:ca:e9:29:65:55:ad:f6:52:54:
+                    5f:e5:a3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+            X509v3 Subject Key Identifier: 
+                14:DF:34:D1:A8:7C:F3:76:25:AB:EC:03:9E:F2:BF:52:12:49:B9:69
+            X509v3 Authority Key Identifier: 
+                keyid:14:DF:34:D1:A8:7C:F3:76:25:AB:EC:03:9E:F2:BF:52:12:49:B9:69
+
+    Signature Algorithm: sha512WithRSAEncryption
+         30:e7:48:02:37:e9:28:cf:04:a2:4d:5c:fa:d8:4e:c9:76:c7:
+         14:3f:bd:2c:51:3d:33:f0:1a:bc:49:f1:47:95:8f:69:d8:a9:
+         54:14:44:6c:4d:9f:55:82:08:1e:c6:5b:d5:91:d9:bc:2e:b0:
+         af:d6:25:65:74:96:aa:36:de:ae:31:a8:11:f2:a4:2c:5a:e1:
+         4f:73:f8:4a:c3:35:b0:76:96:71:f2:b5:7d:4b:75:ee:5d:bf:
+         86:a5:ba:0b:a9:52:cb:ec:ab:e5:23:4b:f2:74:55:28:17:1e:
+         b3:ac:27:ad:45:13:6e:69:b3:5a:be:42:36:29:48:db:e7:5c:
+         22:58:a0:90:82:2c:2a:21:2b:db:f4:64:b7:91:5d:1f:2c:48:
+         a4:1a:85:e3:86:a5:aa:19:cd:19:e8:a5:fb:a3:7b:94:77:48:
+         25:a4:cf:a0:cf:71:82:5c:6f:71:22:7c:d6:97:a0:53:bb:ec:
+         30:f6:cb:16:fb:7b:fd:16:94:7a:53:6e:bd:04:64:a2:01:10:
+         9f:f0:5b:b5:a6:73:41:9d:5f:6f:45:73:0d:05:f7:30:6d:39:
+         90:b6:7d:55:7d:4c:2f:ae:5f:38:56:2f:8b:df:f4:bf:12:06:
+         93:6e:0d:02:23:bf:71:91:57:88:e8:bd:62:72:99:00:40:29:
+         1e:c9:13:11:da:7e:8e:e1:d2:a5:0d:bf:f7:d6:ec:01:0d:89:
+         41:cd:d5:dc:d2:f7:5f:33:0d:4c:2f:85:b7:85:b7:81:e4:17:
+         29:f0:74:cf:0e:15:8c:1a:50:0b:08:63:1a:91:4f:e7:76:97:
+         f1:d4:3b:7e:72:d4:c5:45:58:0c:6a:e9:0d:f2:85:d8:91:1e:
+         37:bd:78:e3:39:4d:2e:fd:85:31:c1:a6:3b:6a:cc:2c:53:72:
+         1d:8e:7b:f0:e6:76:86:09:6f:1a:f3:e4:a1:e2:dd:76:5f:b0:
+         8c:e2:2a:54:5d:c1:88:49:90:10:15:42:7d:05:24:53:8c:54:
+         ff:48:18:1a:36:e3:31:d3:54:32:78:0d:fe:f2:3d:aa:0d:37:
+         15:84:b4:36:47:31:e8:85:6e:0b:58:38:ff:21:91:09:c9:a8:
+         43:a3:ea:60:cb:7e:ed:f7:41:6f:4e:91:c1:fd:77:46:e7:d4:
+         e7:86:c0:1b:fd:50:6c:aa:be:00:b3:63:02:ff:4e:c7:a5:57:
+         6e:29:64:e9:54:d5:30:63:38:5f:2d:5a:db:49:5f:14:14:22:
+         d2:81:1f:61:9e:ee:ee:16:66:d6:bc:bd:ac:1b:5c:fb:38:31:
+         95:33:2e:84:6e:7a:de:ee:b9:fc:97:17:06:13:bf:70:1c:6e:
+         76:ed:66:38:e2:70:08:00
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIJAMd+UWocJc1AMA0GCSqGSIb3DQEBDQUAMCwxKjAoBgNV
+BAMMIUNhbm9uaWNhbCBMdGQuIExpdmUgUGF0Y2ggU2lnbmluZzAeFw0xNjA3MTgy
+MzQxMjdaFw0yNjA3MTYyMzQxMjdaMCwxKjAoBgNVBAMMIUNhbm9uaWNhbCBMdGQu
+IExpdmUgUGF0Y2ggU2lnbmluZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAL107nKzSqvmMegpJMK9RpgywDnuo/uKrf6rGlujLqGA23lhnkd5LHVXoiHw
+k/aH8ptLnS+zWGEoPEFwExahcpDJ1RZxfOAw+SheSCA2AGm3WZ+j7KjrVUGfOB4i
+Slcg9INZScUAk9MzApLR/PCEO0pbj7Zzmon6MB7mKmjyke9ZVz3cHFJvXuabtbh8
+mMkT0TloAWeR4NNnchYKXhaDRTFPtSuz9kCGiTqEbm8WYbxwhL5aEzZ7guoHGfwY
+wRbGMgt9LGvEIbk4azHc2QytVkBofOPGZI6/HOByPmzb0nN52tfFL10EfbAHHpXd
+Kkdevz46yGb2Zw/UKvHicVnSbHugN6zml4AwE5dI1XT8OGjkV8uZaVqEJ6yYUeRk
+vZFi6FgnBiq5C7gI5eW0UaeiEN9OB2ygO5bybt91jJceZKCahpuYJvnYt95bIbev
+iQGj95hr2hm6hu/v8c67L4ntwLYb5Vv4kBGaUpPpvvc1uQjLusPtL3OvzJYHVbXe
+9gP28Yn5IUB2wWnyYcyalN+c7GplOL7RTiqHxy8+U66Ln1ShCVlkJaqp2ESpqKBx
+4TKqTDL9RCjMnG+O24F+b/oAVsXlA0Zj+45xjeMTkZ+sYD5k898lNAn6LZafFgXq
+k/XmAAgnMns8ve5wJGw7Venb9BAtIAa0yukpZVWt9lJUX+WjAgMBAAGjXTBbMAwG
+A1UdEwEB/wQCMAAwCwYDVR0PBAQDAgeAMB0GA1UdDgQWBBQU3zTRqHzzdiWr7AOe
+8r9SEkm5aTAfBgNVHSMEGDAWgBQU3zTRqHzzdiWr7AOe8r9SEkm5aTANBgkqhkiG
+9w0BAQ0FAAOCAgEAMOdIAjfpKM8Eok1c+thOyXbHFD+9LFE9M/AavEnxR5WPadip
+VBREbE2fVYIIHsZb1ZHZvC6wr9YlZXSWqjberjGoEfKkLFrhT3P4SsM1sHaWcfK1
+fUt17l2/hqW6C6lSy+yr5SNL8nRVKBces6wnrUUTbmmzWr5CNilI2+dcIligkIIs
+KiEr2/Rkt5FdHyxIpBqF44alqhnNGeil+6N7lHdIJaTPoM9xglxvcSJ81pegU7vs
+MPbLFvt7/RaUelNuvQRkogEQn/BbtaZzQZ1fb0VzDQX3MG05kLZ9VX1ML65fOFYv
+i9/0vxIGk24NAiO/cZFXiOi9YnKZAEApHskTEdp+juHSpQ2/99bsAQ2JQc3V3NL3
+XzMNTC+Ft4W3geQXKfB0zw4VjBpQCwhjGpFP53aX8dQ7fnLUxUVYDGrpDfKF2JEe
+N7144zlNLv2FMcGmO2rMLFNyHY578OZ2hglvGvPkoeLddl+wjOIqVF3BiEmQEBVC
+fQUkU4xU/0gYGjbjMdNUMngN/vI9qg03FYS0Nkcx6IVuC1g4/yGRCcmoQ6PqYMt+
+7fdBb06Rwf13RufU54bAG/1QbKq+ALNjAv9Ox6VXbilk6VTVMGM4Xy1a20lfFBQi
+0oEfYZ7u7hZm1ry9rBtc+zgxlTMuhG563u65/JcXBhO/cBxudu1mOOJwCAA=
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            e9:df:13:0f:92:92:a9:b7
+        Signature Algorithm: sha512WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Kernel Module Signing
+        Validity
+            Not Before: May 31 16:06:09 2016 GMT
+            Not After : May 29 16:06:09 2026 GMT
+        Subject: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Kernel Module Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (4096 bit)
+                Modulus:
+                    00:b3:b0:4f:c6:0a:77:8b:f9:d1:53:33:34:d2:80:
+                    b5:63:6f:e1:f6:a2:83:99:d5:b6:b1:e4:99:91:fa:
+                    6c:19:c6:d0:91:2a:b9:7d:b5:98:a6:0d:28:01:b8:
+                    7c:8e:aa:38:ec:51:37:33:96:f0:b0:9b:8d:86:5f:
+                    67:23:69:2f:d7:c2:f3:fb:c5:d7:f9:04:ff:f2:e5:
+                    61:68:b7:29:b9:c6:8e:4b:4d:2d:8f:92:0c:00:b3:
+                    a3:d2:5a:08:64:cd:f2:09:0b:a5:0e:e6:64:75:d5:
+                    41:f4:4d:49:3a:0d:dc:b9:27:8e:c4:d6:b1:df:8f:
+                    6c:f0:e4:f7:31:cb:a9:04:a1:f9:a7:aa:15:da:59:
+                    03:4d:46:14:d0:dd:bf:e0:f5:9e:f0:71:0c:70:78:
+                    2b:08:fb:e0:b6:68:a4:74:12:9d:f7:f2:64:88:17:
+                    2a:8a:ed:1a:91:b5:6c:13:bd:4c:10:0a:0b:72:0b:
+                    90:db:7d:f3:78:44:4c:d2:a5:41:f7:1c:77:7d:5a:
+                    8a:54:bc:8f:fe:b7:ee:e1:bc:59:37:c4:d4:e8:14:
+                    d0:5b:42:9b:04:00:8e:6d:83:8a:25:21:5b:08:c4:
+                    7b:b2:d9:99:52:c9:5e:59:6d:c4:aa:52:59:e2:e4:
+                    2f:7e:7e:ac:05:01:99:bf:13:72:b7:45:c5:17:da:
+                    8a:d5:3e:71:73:2e:d8:aa:e6:eb:5a:d0:9a:c4:93:
+                    f3:be:eb:d2:47:25:34:16:29:fa:dd:9a:2f:b1:20:
+                    e5:41:4e:ed:ea:51:7c:23:80:ba:3d:b5:3a:0b:8c:
+                    9c:85:48:6c:3c:8b:29:2f:2f:12:c7:52:34:02:ea:
+                    0f:ac:53:23:3c:f8:3e:40:1b:30:63:e9:2d:e6:f6:
+                    58:cc:51:f9:eb:08:4a:b4:c7:16:80:d1:8b:c2:64:
+                    6a:71:a9:70:31:a4:a7:3a:c0:93:99:1b:0e:42:c1:
+                    00:6d:43:27:99:6c:e5:fd:23:16:c1:8e:b5:66:17:
+                    2b:4c:53:5a:6d:1e:96:16:13:6a:c6:d4:85:5b:74:
+                    2e:ce:7c:45:2f:ad:cb:75:9e:5e:91:bd:9a:6a:86:
+                    1a:06:bd:39:be:a3:50:56:ea:e1:f6:e3:95:69:d7:
+                    31:e4:66:f7:36:b5:51:c2:22:b4:9c:74:9c:44:0b:
+                    0e:16:5f:53:f0:23:c6:b9:40:bd:d6:b8:7d:1b:f6:
+                    73:f6:27:e7:c0:e3:65:a0:58:ab:5c:59:b7:80:8c:
+                    8c:04:b4:a9:ae:a0:51:40:10:3b:63:59:49:87:d1:
+                    9b:df:a3:8c:c4:2e:eb:70:c1:0a:18:1f:cb:22:c2:
+                    f2:4a:65:0d:e5:81:74:d8:ce:72:c6:35:be:ba:63:
+                    72:c4:f9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+            X509v3 Subject Key Identifier: 
+                88:F7:52:E5:60:A1:E0:73:7E:31:16:3A:46:6A:D7:B7:0A:85:0C:19
+            X509v3 Authority Key Identifier: 
+                keyid:88:F7:52:E5:60:A1:E0:73:7E:31:16:3A:46:6A:D7:B7:0A:85:0C:19
+
+    Signature Algorithm: sha512WithRSAEncryption
+         04:85:16:27:58:ba:71:28:57:86:7b:c2:83:db:e5:72:6f:1e:
+         b2:1c:63:b0:db:ad:c0:42:96:c0:4f:65:f6:35:4d:c0:07:0d:
+         46:be:d3:1e:ec:f1:22:18:2a:18:5d:bb:69:a6:a6:d4:0d:c3:
+         57:03:b9:e7:45:49:28:ca:6d:98:17:68:97:cb:7b:36:81:0a:
+         37:9e:34:79:f3:e1:0e:5b:77:43:bb:5a:a5:45:b7:16:50:86:
+         fd:12:a4:96:0f:15:19:09:1c:e1:fa:80:a5:80:09:be:bb:c8:
+         26:0b:3e:de:03:d2:c2:18:a4:8d:0d:de:c5:32:82:0b:fb:75:
+         55:66:1a:2a:bb:e4:bd:25:91:20:15:d4:be:b8:3f:53:e3:fb:
+         a8:c3:55:e3:d5:e7:82:18:95:df:39:09:a7:fc:89:6e:b4:1c:
+         aa:2d:e8:67:c2:0d:34:34:3e:f9:fa:0b:ce:81:92:11:ae:12:
+         0a:fe:35:63:ce:46:29:c4:2b:4f:cb:4e:05:0a:a1:11:e2:35:
+         f6:5a:5d:b5:e8:d2:6f:4c:fc:3d:24:a6:03:4b:dd:98:6b:f2:
+         71:58:16:1d:a5:25:ef:d9:06:7c:e8:db:7b:88:6a:89:5c:59:
+         01:92:64:db:44:08:63:6c:7c:32:d6:55:98:63:09:26:61:67:
+         0a:fe:5d:ee:fd:23:59:b3:4d:91:c1:4d:41:8b:cd:20:58:fa:
+         2d:45:e5:bd:1d:69:5c:03:a0:49:a6:97:54:13:b6:c9:e0:f8:
+         56:83:a1:2a:c3:f4:6c:fd:ab:20:ca:3d:9c:95:c0:cf:04:bb:
+         46:39:cf:34:81:65:45:27:64:01:7d:62:b3:b8:72:ea:10:d5:
+         0f:53:7d:39:88:25:09:6f:8c:bc:e0:49:bb:39:e2:0e:8d:cf:
+         56:4d:c1:82:6d:87:d2:e7:fc:c0:9f:a7:65:60:d2:6c:65:18:
+         59:38:6e:d0:9c:d7:c3:81:9a:9a:29:8f:83:84:c3:b5:44:ff:
+         28:ac:13:17:64:f2:26:13:d9:55:06:b7:69:68:7c:bf:ec:d1:
+         8c:ef:b7:da:76:e1:07:73:c6:31:62:31:cb:b6:e1:e7:7f:0c:
+         c3:f7:4c:52:be:25:36:8e:a1:bb:60:02:c3:cb:3e:6f:29:fc:
+         7f:6a:fa:f8:ec:0a:df:49:e2:57:0e:bc:bd:93:c3:1b:d5:36:
+         8a:ff:d8:1b:17:c7:1f:cb:69:00:d2:54:9e:ad:61:89:92:95:
+         11:f8:ea:17:83:9f:9b:09:7d:b8:94:a4:ea:f5:ae:ea:dc:dd:
+         62:b9:9e:68:9c:18:ec:19:c4:13:08:c8:b1:62:ab:8e:84:69:
+         11:3c:da:ea:0d:b7:22:bd
+-----BEGIN CERTIFICATE-----
+MIIF2jCCA8KgAwIBAgIJAOnfEw+Skqm3MA0GCSqGSIb3DQEBDQUAMH0xCzAJBgNV
+BAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEQMA4GA1UEBwwHRG91Z2xhczEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xLTArBgNVBAMMJENhbm9uaWNhbCBMdGQu
+IEtlcm5lbCBNb2R1bGUgU2lnbmluZzAeFw0xNjA1MzExNjA2MDlaFw0yNjA1Mjkx
+NjA2MDlaMH0xCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEQMA4G
+A1UEBwwHRG91Z2xhczEXMBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xLTArBgNVBAMM
+JENhbm9uaWNhbCBMdGQuIEtlcm5lbCBNb2R1bGUgU2lnbmluZzCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBALOwT8YKd4v50VMzNNKAtWNv4faig5nVtrHk
+mZH6bBnG0JEquX21mKYNKAG4fI6qOOxRNzOW8LCbjYZfZyNpL9fC8/vF1/kE//Ll
+YWi3KbnGjktNLY+SDACzo9JaCGTN8gkLpQ7mZHXVQfRNSToN3LknjsTWsd+PbPDk
+9zHLqQSh+aeqFdpZA01GFNDdv+D1nvBxDHB4Kwj74LZopHQSnffyZIgXKortGpG1
+bBO9TBAKC3ILkNt983hETNKlQfccd31ailS8j/637uG8WTfE1OgU0FtCmwQAjm2D
+iiUhWwjEe7LZmVLJXlltxKpSWeLkL35+rAUBmb8TcrdFxRfaitU+cXMu2Krm61rQ
+msST877r0kclNBYp+t2aL7Eg5UFO7epRfCOAuj21OguMnIVIbDyLKS8vEsdSNALq
+D6xTIzz4PkAbMGPpLeb2WMxR+esISrTHFoDRi8JkanGpcDGkpzrAk5kbDkLBAG1D
+J5ls5f0jFsGOtWYXK0xTWm0elhYTasbUhVt0Ls58RS+ty3WeXpG9mmqGGga9Ob6j
+UFbq4fbjlWnXMeRm9za1UcIitJx0nEQLDhZfU/AjxrlAvda4fRv2c/Yn58DjZaBY
+q1xZt4CMjAS0qa6gUUAQO2NZSYfRm9+jjMQu63DBChgfyyLC8kplDeWBdNjOcsY1
+vrpjcsT5AgMBAAGjXTBbMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgeAMB0GA1Ud
+DgQWBBSI91LlYKHgc34xFjpGate3CoUMGTAfBgNVHSMEGDAWgBSI91LlYKHgc34x
+FjpGate3CoUMGTANBgkqhkiG9w0BAQ0FAAOCAgEABIUWJ1i6cShXhnvCg9vlcm8e
+shxjsNutwEKWwE9l9jVNwAcNRr7THuzxIhgqGF27aaam1A3DVwO550VJKMptmBdo
+l8t7NoEKN540efPhDlt3Q7tapUW3FlCG/RKklg8VGQkc4fqApYAJvrvIJgs+3gPS
+whikjQ3exTKCC/t1VWYaKrvkvSWRIBXUvrg/U+P7qMNV49XnghiV3zkJp/yJbrQc
+qi3oZ8INNDQ++foLzoGSEa4SCv41Y85GKcQrT8tOBQqhEeI19lpdtejSb0z8PSSm
+A0vdmGvycVgWHaUl79kGfOjbe4hqiVxZAZJk20QIY2x8MtZVmGMJJmFnCv5d7v0j
+WbNNkcFNQYvNIFj6LUXlvR1pXAOgSaaXVBO2yeD4VoOhKsP0bP2rIMo9nJXAzwS7
+RjnPNIFlRSdkAX1is7hy6hDVD1N9OYglCW+MvOBJuzniDo3PVk3Bgm2H0uf8wJ+n
+ZWDSbGUYWThu0JzXw4GamimPg4TDtUT/KKwTF2TyJhPZVQa3aWh8v+zRjO+32nbh
+B3PGMWIxy7bh538Mw/dMUr4lNo6hu2ACw8s+byn8f2r6+OwK30niVw68vZPDG9U2
+iv/YGxfHH8tpANJUnq1hiZKVEfjqF4Ofmwl9uJSk6vWu6tzdYrmeaJwY7BnEEwjI
+sWKrjoRpETza6g23Ir0=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/canonical-revoked-certs.pem
+++ linux-ein-5.4.0/debian/canonical-revoked-certs.pem
@@ -0,0 +1,688 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Apr 12 11:39:08 2012 GMT
+            Not After : Apr 11 11:39:08 2042 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c9:5f:9b:62:8f:0b:b0:64:82:ac:be:c9:e2:62:
+                    e3:4b:d2:9f:1e:8a:d5:61:1a:2b:5d:38:f4:b7:ce:
+                    b9:9a:b8:43:b8:43:97:77:ab:4f:7f:0c:70:46:0b:
+                    fc:7f:6d:c6:6d:ea:80:5e:01:d2:b7:66:1e:87:de:
+                    0d:6d:d0:41:97:a8:a5:af:0c:63:4f:f7:7c:c2:52:
+                    cc:a0:31:a9:bb:89:5d:99:1e:46:6f:55:73:b9:76:
+                    69:ec:d7:c1:fc:21:d6:c6:07:e7:4f:bd:22:de:e4:
+                    a8:5b:2d:db:95:34:19:97:d6:28:4b:21:4c:ca:bb:
+                    1d:79:a6:17:7f:5a:f9:67:e6:5c:78:45:3d:10:6d:
+                    b0:17:59:26:11:c5:57:e3:7f:4e:82:ba:f6:2c:4e:
+                    c8:37:4d:ff:85:15:84:47:e0:ed:3b:7c:7f:bc:af:
+                    e9:01:05:a7:0c:6f:c3:e9:8d:a3:ce:be:a6:e3:cd:
+                    3c:b5:58:2c:9e:c2:03:1c:60:22:37:39:ff:41:02:
+                    c1:29:a4:65:51:ff:33:34:aa:42:15:f9:95:78:fc:
+                    2d:f5:da:8a:85:7c:82:9d:fb:37:2c:6b:a5:a8:df:
+                    7c:55:0b:80:2e:3c:b0:63:e1:cd:38:48:89:e8:14:
+                    06:0b:82:bc:fd:d4:07:68:1b:0f:3e:d9:15:dd:94:
+                    11:1b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                61:48:2A:A2:83:0D:0A:B2:AD:5A:F1:0B:72:50:DA:90:33:DD:CE:F0
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        8f:8a:a1:06:1f:29:b7:0a:4a:d5:c5:fd:81:ab:25:ea:c0:7d:
+        e2:fc:6a:96:a0:79:93:67:ee:05:0e:25:12:25:e4:5a:f6:aa:
+        1a:f1:12:f3:05:8d:87:5e:f1:5a:5c:cb:8d:23:73:65:1d:15:
+        b9:de:22:6b:d6:49:67:c9:a3:c6:d7:62:4e:5c:b5:f9:03:83:
+        40:81:dc:87:9c:3c:3f:1c:0d:51:9f:94:65:0a:84:48:67:e4:
+        a2:f8:a6:4a:f0:e7:cd:cd:bd:94:e3:09:d2:5d:2d:16:1b:05:
+        15:0b:cb:44:b4:3e:61:42:22:c4:2a:5c:4e:c5:1d:a3:e2:e0:
+        52:b2:eb:f4:8b:2b:dc:38:39:5d:fb:88:a1:56:65:5f:2b:4f:
+        26:ff:06:78:10:12:eb:8c:5d:32:e3:c6:45:af:25:9b:a0:ff:
+        8e:ef:47:09:a3:e9:8b:37:92:92:69:76:7e:34:3b:92:05:67:
+        4e:b0:25:ed:bc:5e:5f:8f:b4:d6:ca:40:ff:e4:e2:31:23:0c:
+        85:25:ae:0c:55:01:ec:e5:47:5e:df:5b:bc:14:33:e3:c6:f5:
+        18:b6:d9:f7:dd:b3:b4:a1:31:d3:5a:5c:5d:7d:3e:bf:0a:e4:
+        e4:e8:b4:59:7d:3b:b4:8c:a3:1b:b5:20:a3:b9:3e:84:6f:8c:
+        21:00:c3:39
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIBATANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xMjA0MTIxMTM5MDhaFw00MjA0MTEx
+MTM5MDhaMH8xCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEXMBUG
+A1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MSswKQYD
+VQQDDCJDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyV+bYo8LsGSCrL7J4mLjS9KfHorVYRor
+XTj0t865mrhDuEOXd6tPfwxwRgv8f23GbeqAXgHSt2Yeh94NbdBBl6ilrwxjT/d8
+wlLMoDGpu4ldmR5Gb1VzuXZp7NfB/CHWxgfnT70i3uSoWy3blTQZl9YoSyFMyrsd
+eaYXf1r5Z+ZceEU9EG2wF1kmEcVX439Ogrr2LE7IN03/hRWER+DtO3x/vK/pAQWn
+DG/D6Y2jzr6m4808tVgsnsIDHGAiNzn/QQLBKaRlUf8zNKpCFfmVePwt9dqKhXyC
+nfs3LGulqN98VQuALjywY+HNOEiJ6BQGC4K8/dQHaBsPPtkV3ZQRGwIDAQABo4Gg
+MIGdMAwGA1UdEwEB/wQCMAAwHwYDVR0lBBgwFgYIKwYBBQUHAwMGCisGAQQBgjcK
+AwYwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl
+MB0GA1UdDgQWBBRhSCqigw0Ksq1a8QtyUNqQM93O8DAfBgNVHSMEGDAWgBStkZkL
+wiqx9RcEjCO2ZVomjjRaYzANBgkqhkiG9w0BAQsFAAOCAQEAj4qhBh8ptwpK1cX9
+gasl6sB94vxqlqB5k2fuBQ4lEiXkWvaqGvES8wWNh17xWlzLjSNzZR0Vud4ia9ZJ
+Z8mjxtdiTly1+QODQIHch5w8PxwNUZ+UZQqESGfkovimSvDnzc29lOMJ0l0tFhsF
+FQvLRLQ+YUIixCpcTsUdo+LgUrLr9Isr3Dg5XfuIoVZlXytPJv8GeBAS64xdMuPG
+Ra8lm6D/ju9HCaPpizeSkml2fjQ7kgVnTrAl7bxeX4+01spA/+TiMSMMhSWuDFUB
+7OVHXt9bvBQz48b1GLbZ992ztKEx01pcXX0+vwrk5Oi0WX07tIyjG7Ugo7k+hG+M
+IQDDOQ==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 26 21:52:11 2017 GMT
+            Not After : Sep 25 21:52:11 2047 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2017)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ef:9f:fa:9f:19:3a:9d:38:23:91:cc:c4:f9:42:
+                    e0:f8:54:12:82:dc:97:2c:d6:5b:c1:35:eb:ff:4a:
+                    74:06:b5:9d:32:aa:7b:f3:fc:31:5a:34:3e:a1:a4:
+                    44:db:7b:6d:16:af:35:76:e0:9b:99:ad:21:11:c6:
+                    12:4b:ae:24:8f:bb:d3:b2:00:fe:c5:1d:9b:3a:1a:
+                    4a:6c:ca:fa:16:37:85:22:f9:ff:22:fc:40:e0:58:
+                    35:c1:39:27:b4:c6:42:1a:96:d8:a5:c5:95:2e:f7:
+                    c5:1e:21:6e:36:84:f7:a9:a1:e1:f1:03:08:96:65:
+                    71:f8:eb:83:cf:82:f7:9a:44:58:72:00:14:39:29:
+                    4b:e9:78:2f:65:20:b3:80:76:3b:ba:0d:2d:46:f6:
+                    37:05:e7:05:fe:bd:6c:c7:a2:65:b5:06:6e:07:24:
+                    99:a1:c1:cf:e1:0e:5e:49:41:71:17:a8:50:e7:38:
+                    99:e5:6e:b6:db:9f:63:db:56:f4:9c:7d:89:f6:d2:
+                    03:6c:99:83:e0:99:23:39:36:bd:cb:b5:26:7c:7d:
+                    b0:c6:fe:82:7c:52:ed:f9:2c:8f:79:71:3d:a9:2f:
+                    b5:aa:7e:77:a0:fd:69:f9:97:10:a8:b2:c6:7d:88:
+                    9e:a2:19:bd:31:b8:02:2d:34:4d:9d:98:60:82:ad:
+                    04:ff
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                24:2A:DE:75:AC:4A:15:E5:0D:50:C8:4B:0D:45:FF:3E:AE:70:7A:03
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        00:b2:b7:57:b5:2b:5d:16:d3:04:88:6a:d7:77:d5:0d:89:f1:
+        d2:6e:11:d1:8e:f5:62:05:c4:6a:57:df:eb:d2:86:68:f2:fd:
+        a7:37:11:3c:f4:ce:5d:fe:32:5f:31:a2:6b:3a:da:28:c2:88:
+        fa:7f:70:b5:25:99:ea:27:9a:56:6a:9d:b2:0f:14:99:e2:b7:
+        c6:39:1e:8e:a7:76:31:d9:ed:c5:05:8d:48:ae:1b:68:18:14:
+        51:a1:7d:f6:c7:df:cb:9d:eb:a4:3b:0b:ff:c2:07:c5:42:bc:
+        0d:b2:11:fa:37:17:2b:1c:b5:84:48:2d:f9:31:4a:57:49:8e:
+        61:a6:82:11:06:4c:34:ea:9c:2a:47:4d:eb:e0:26:af:da:d2:
+        c2:08:a0:37:35:7b:73:71:de:0b:c4:ba:c8:34:de:20:04:03:
+        6f:46:26:0d:b9:91:02:5b:71:76:cc:45:e4:08:d0:a6:dd:a4:
+        50:d3:d9:04:91:2b:d9:5c:34:88:fc:c2:37:fd:c6:d4:3e:57:
+        f7:6b:ba:7b:d7:02:7a:84:0c:c8:c1:19:cc:bc:fa:52:d5:7f:
+        b3:35:c4:53:5d:70:0a:f6:44:60:8d:a9:11:7a:1b:7d:ae:7b:
+        20:5a:4c:8d:44:f6:c1:a9:61:cb:dc:cb:90:37:d5:28:24:73:
+        87:d0:e0:d8
+-----BEGIN CERTIFICATE-----
+MIIEKDCCAxCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA5MjYyMTUyMTFaFw00NzA5MjUy
+MTUyMTFaMIGGMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDEyMDAG
+A1UEAwwpQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoMjAxNykw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvn/qfGTqdOCORzMT5QuD4
+VBKC3Jcs1lvBNev/SnQGtZ0yqnvz/DFaND6hpETbe20WrzV24JuZrSERxhJLriSP
+u9OyAP7FHZs6GkpsyvoWN4Ui+f8i/EDgWDXBOSe0xkIaltilxZUu98UeIW42hPep
+oeHxAwiWZXH464PPgveaRFhyABQ5KUvpeC9lILOAdju6DS1G9jcF5wX+vWzHomW1
+Bm4HJJmhwc/hDl5JQXEXqFDnOJnlbrbbn2PbVvScfYn20gNsmYPgmSM5Nr3LtSZ8
+fbDG/oJ8Uu35LI95cT2pL7Wqfneg/Wn5lxCossZ9iJ6iGb0xuAItNE2dmGCCrQT/
+AgMBAAGjgaAwgZ0wDAYDVR0TAQH/BAIwADAfBgNVHSUEGDAWBggrBgEFBQcDAwYK
+KwYBBAGCNwoDBjAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFCQq3nWsShXlDVDISw1F/z6ucHoDMB8GA1UdIwQY
+MBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA0GCSqGSIb3DQEBCwUAA4IBAQAAsrdX
+tStdFtMEiGrXd9UNifHSbhHRjvViBcRqV9/r0oZo8v2nNxE89M5d/jJfMaJrOtoo
+woj6f3C1JZnqJ5pWap2yDxSZ4rfGOR6Op3Yx2e3FBY1IrhtoGBRRoX32x9/Lneuk
+Owv/wgfFQrwNshH6NxcrHLWESC35MUpXSY5hpoIRBkw06pwqR03r4Cav2tLCCKA3
+NXtzcd4LxLrINN4gBANvRiYNuZECW3F2zEXkCNCm3aRQ09kEkSvZXDSI/MI3/cbU
+Plf3a7p71wJ6hAzIwRnMvPpS1X+zNcRTXXAK9kRgjakReht9rnsgWkyNRPbBqWHL
+3MuQN9UoJHOH0ODY
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Oct 26 18:31:14 2018 GMT
+            Not After : Oct 24 18:31:14 2048 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (ESM 2018)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:bf:6a:e5:6d:55:7a:ec:7a:11:37:45:9c:4c:8f:
+                    6b:2d:56:d3:74:2b:32:ac:84:2d:ba:cb:cc:ec:8d:
+                    92:22:69:48:a5:d4:f6:75:11:66:2f:cb:b2:fd:9e:
+                    56:ab:e6:f1:52:8e:75:3e:50:bd:25:b3:50:fc:ef:
+                    3d:76:f3:3f:7f:03:f6:e2:a1:25:69:5c:14:98:54:
+                    bd:11:bf:e9:a5:ac:46:91:4b:1d:de:b7:18:2b:c8:
+                    22:83:15:a7:4a:00:8d:9d:e4:c0:da:f7:41:02:fd:
+                    9f:5f:79:93:56:cc:86:e1:b5:e0:39:0e:3c:a2:5b:
+                    fe:c0:56:f0:92:50:5a:2b:67:67:93:56:d7:7a:75:
+                    99:6a:25:b4:63:a8:5f:69:7e:3a:49:58:2a:a7:80:
+                    f6:5a:b4:be:b2:be:a8:8c:45:41:c9:f2:fc:76:a8:
+                    65:ef:99:29:0d:c9:9c:54:6b:0a:f0:4a:0e:61:0d:
+                    ed:99:32:af:12:e2:12:7b:9f:7b:ec:05:c4:e0:b6:
+                    d5:c3:71:28:ae:dd:0b:ba:97:ad:68:0b:76:e9:bf:
+                    e7:01:7e:64:54:39:23:85:36:c8:9d:dd:27:a1:ff:
+                    df:46:36:14:7e:cb:cc:a1:cd:49:0b:6d:c2:0c:45:
+                    99:56:58:7c:87:0d:59:9a:dc:4a:39:3b:1d:d9:15:
+                    2e:b5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                36:51:88:C1:D3:74:D6:B0:7C:3C:8F:24:0F:8E:F7:22:43:3D:6A:8B
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        4c:0f:cd:77:60:b4:6f:53:87:f3:3c:4f:e6:81:5f:a7:1c:cc:
+        60:29:b6:34:6c:4d:08:9b:e2:d2:bd:f6:17:1a:62:79:b8:17:
+        bc:a2:60:59:fd:03:51:c3:b7:6b:de:73:b3:48:95:f5:0b:aa:
+        b6:3c:b4:34:dc:1d:0b:c4:97:62:87:e7:48:d5:8f:c9:ea:e8:
+        91:8f:2a:40:cd:b7:b3:ee:b2:98:9e:fb:37:31:29:e6:8e:2f:
+        0a:39:99:1e:c6:aa:b8:05:62:85:d3:a8:3e:60:38:98:0f:f0:
+        fe:c7:ab:01:a5:6a:a5:7f:70:a6:26:94:76:23:2f:08:89:74:
+        97:c2:2a:ca:22:3e:7a:ea:22:22:08:07:f4:bb:f6:bc:69:9c:
+        4e:44:33:e2:8e:70:17:b0:9b:cb:33:94:66:6d:ff:9a:7d:e9:
+        50:b2:e8:90:14:e4:2b:91:cb:a0:c5:2e:0e:cf:19:ef:44:ef:
+        84:f0:bd:57:9e:26:c2:63:3d:df:fc:a1:84:de:5c:d7:5f:3b:
+        fb:94:61:f0:93:89:1f:cf:c3:b2:d1:90:97:35:7d:b9:8a:ad:
+        e6:05:f0:e8:3b:a1:7c:af:2b:c4:af:18:33:2e:5e:87:db:9d:
+        80:b5:04:fd:00:d0:60:ab:ff:85:77:0f:cb:47:22:c9:b2:85:
+        a8:48:16:e2
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xODEwMjYxODMxMTRaFw00ODEwMjQx
+ODMxMTRaMIGKMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDE2MDQG
+A1UEAwwtQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoRVNNIDIw
+MTgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2rlbVV67HoRN0Wc
+TI9rLVbTdCsyrIQtusvM7I2SImlIpdT2dRFmL8uy/Z5Wq+bxUo51PlC9JbNQ/O89
+dvM/fwP24qElaVwUmFS9Eb/ppaxGkUsd3rcYK8gigxWnSgCNneTA2vdBAv2fX3mT
+VsyG4bXgOQ48olv+wFbwklBaK2dnk1bXenWZaiW0Y6hfaX46SVgqp4D2WrS+sr6o
+jEVByfL8dqhl75kpDcmcVGsK8EoOYQ3tmTKvEuISe5977AXE4LbVw3Eort0Lupet
+aAt26b/nAX5kVDkjhTbInd0nof/fRjYUfsvMoc1JC23CDEWZVlh8hw1ZmtxKOTsd
+2RUutQIDAQABo4GgMIGdMAwGA1UdEwEB/wQCMAAwHwYDVR0lBBgwFgYIKwYBBQUH
+AwMGCisGAQQBgjcKAwYwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk
+IENlcnRpZmljYXRlMB0GA1UdDgQWBBQ2UYjB03TWsHw8jyQPjvciQz1qizAfBgNV
+HSMEGDAWgBStkZkLwiqx9RcEjCO2ZVomjjRaYzANBgkqhkiG9w0BAQsFAAOCAQEA
+TA/Nd2C0b1OH8zxP5oFfpxzMYCm2NGxNCJvi0r32FxpiebgXvKJgWf0DUcO3a95z
+s0iV9Quqtjy0NNwdC8SXYofnSNWPyerokY8qQM23s+6ymJ77NzEp5o4vCjmZHsaq
+uAVihdOoPmA4mA/w/serAaVqpX9wpiaUdiMvCIl0l8IqyiI+euoiIggH9Lv2vGmc
+TkQz4o5wF7CbyzOUZm3/mn3pULLokBTkK5HLoMUuDs8Z70TvhPC9V54mwmM93/yh
+hN5c1187+5Rh8JOJH8/DstGQlzV9uYqt5gXw6DuhfK8rxK8YMy5eh9udgLUE/QDQ
+YKv/hXcPy0ciybKFqEgW4g==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 18 16:10:17 2019 GMT
+            Not After : Sep 16 16:10:17 2049 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2019)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e6:47:d8:75:e5:87:59:26:87:83:7d:5b:7a:b8:
+                    58:3d:7c:ef:36:f8:a0:7a:b7:14:56:58:7d:01:f1:
+                    1c:3b:8c:e6:5b:03:77:7d:a0:ed:47:0a:45:e6:75:
+                    5c:de:95:38:0d:38:fa:41:79:89:56:31:87:e7:a3:
+                    9a:36:70:b6:cf:24:2f:99:26:89:08:39:0e:14:c3:
+                    35:be:02:8b:52:e1:8e:7b:0c:a6:9d:78:ff:01:60:
+                    d7:f5:c3:d5:f0:5e:dc:e4:23:09:59:72:93:d3:b5:
+                    22:af:7c:cd:e0:84:0f:af:11:2d:bc:c6:72:42:af:
+                    ea:67:63:c4:10:41:78:02:80:62:0d:43:74:b4:1c:
+                    ed:50:d7:94:f1:b0:bb:f9:57:80:e4:69:0f:83:4b:
+                    a2:e6:2c:4a:9a:e1:7d:7c:62:19:29:27:97:1f:4c:
+                    f1:85:f0:39:f5:31:9f:3a:39:0e:d4:4d:07:3a:40:
+                    55:4b:a6:6c:9d:04:89:51:2d:7c:b0:ef:40:b5:42:
+                    29:16:cc:65:73:38:62:21:f6:e3:2c:17:50:9d:74:
+                    34:4e:df:7c:4a:33:a4:bb:40:cf:d5:e5:ed:05:07:
+                    cd:4c:f9:af:7f:a6:5c:b9:f7:c5:16:45:4e:44:40:
+                    d7:85:32:de:ac:e5:75:ad:9b:d7:c0:26:33:1f:77:
+                    a5:37
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                C0:74:6F:D6:C5:DA:3A:E8:27:86:46:51:AD:66:AE:47:FE:24:B3:E8
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        aa:12:6c:d1:9d:6a:da:f0:ec:7c:17:46:3b:57:b8:d6:76:5f:
+        24:e6:06:a2:0a:55:1f:2f:d3:5e:8f:de:cf:02:f2:ff:e0:dd:
+        d3:c7:bd:75:59:aa:cd:34:f3:28:80:73:cc:28:69:e7:a2:70:
+        88:a2:c7:dc:66:f0:92:0e:ff:64:bf:30:04:54:01:1b:96:ad:
+        15:c5:61:fd:32:61:d7:5e:b5:ba:91:fd:31:fc:6b:15:df:ee:
+        22:d9:e4:1f:f3:cc:8b:0c:9f:f5:e8:f7:e2:62:3f:40:52:c9:
+        f0:f1:1c:63:fc:6c:90:e1:5b:74:03:b9:df:d1:3e:a8:ec:db:
+        2b:6e:83:6f:9f:7f:ba:b4:79:fc:3d:e7:12:2f:4a:e7:17:8c:
+        2b:77:a5:90:74:3c:bd:cf:75:83:0d:1a:95:d5:56:ef:07:9b:
+        a6:b3:31:e3:8c:97:ce:68:11:b5:7b:25:03:72:1c:ea:67:e9:
+        7c:3e:73:c7:7c:3e:fc:f5:ae:8a:b2:07:0d:15:6a:66:09:d7:
+        23:b9:5d:80:7a:26:d6:b6:22:30:aa:84:af:c0:42:e9:75:c3:
+        59:ab:a3:84:87:6b:0c:b7:ab:4e:92:69:ae:2c:82:6f:ab:01:
+        24:ab:ff:78:6d:59:85:c2:3b:23:c0:bd:0d:d8:6e:3a:29:82:
+        e1:c4:5f:db
+-----BEGIN CERTIFICATE-----
+MIIEKDCCAxCgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTA5MTgxNjEwMTdaFw00OTA5MTYx
+NjEwMTdaMIGGMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDEyMDAG
+A1UEAwwpQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoMjAxOSkw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDmR9h15YdZJoeDfVt6uFg9
+fO82+KB6txRWWH0B8Rw7jOZbA3d9oO1HCkXmdVzelTgNOPpBeYlWMYfno5o2cLbP
+JC+ZJokIOQ4UwzW+AotS4Y57DKadeP8BYNf1w9XwXtzkIwlZcpPTtSKvfM3ghA+v
+ES28xnJCr+pnY8QQQXgCgGINQ3S0HO1Q15TxsLv5V4DkaQ+DS6LmLEqa4X18Yhkp
+J5cfTPGF8Dn1MZ86OQ7UTQc6QFVLpmydBIlRLXyw70C1QikWzGVzOGIh9uMsF1Cd
+dDRO33xKM6S7QM/V5e0FB81M+a9/ply598UWRU5EQNeFMt6s5XWtm9fAJjMfd6U3
+AgMBAAGjgaAwgZ0wDAYDVR0TAQH/BAIwADAfBgNVHSUEGDAWBggrBgEFBQcDAwYK
+KwYBBAGCNwoDBjAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFMB0b9bF2jroJ4ZGUa1mrkf+JLPoMB8GA1UdIwQY
+MBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA0GCSqGSIb3DQEBCwUAA4IBAQCqEmzR
+nWra8Ox8F0Y7V7jWdl8k5gaiClUfL9Nej97PAvL/4N3Tx711WarNNPMogHPMKGnn
+onCIosfcZvCSDv9kvzAEVAEblq0VxWH9MmHXXrW6kf0x/GsV3+4i2eQf88yLDJ/1
+6PfiYj9AUsnw8Rxj/GyQ4Vt0A7nf0T6o7NsrboNvn3+6tHn8PecSL0rnF4wrd6WQ
+dDy9z3WDDRqV1VbvB5umszHjjJfOaBG1eyUDchzqZ+l8PnPHfD789a6KsgcNFWpm
+CdcjuV2AeibWtiIwqoSvwELpdcNZq6OEh2sMt6tOkmmuLIJvqwEkq/94bVmFwjsj
+wL0N2G46KYLhxF/b
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 6 (0x6)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:29:32 2021 GMT
+            Not After : Sep 22 19:29:32 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v1)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:aa:b8:34:5b:b6:ae:44:bf:41:e1:78:11:b9:7a:
+                    c8:88:b3:b0:26:50:10:9c:98:d1:f3:98:9f:23:50:
+                    64:f6:39:dd:50:3a:23:44:53:65:fc:f3:9f:f5:a5:
+                    8b:ae:8b:df:47:9f:e9:d5:a0:92:19:f1:21:ea:cc:
+                    59:3a:74:df:45:71:bc:de:64:15:a5:f6:db:ca:71:
+                    fa:19:d4:44:0d:12:ec:47:3a:43:e2:f2:dd:8b:fe:
+                    0d:7b:dc:4d:db:53:06:22:61:e5:8b:35:49:b6:33:
+                    c4:0a:69:5f:5b:81:09:84:6b:42:33:18:09:9d:a0:
+                    35:f7:9c:1e:de:6e:de:90:69:1a:e8:32:e4:49:ad:
+                    c3:31:e9:f8:4a:a2:28:1d:db:0d:29:b6:48:0a:44:
+                    93:86:41:62:8f:73:97:60:10:8a:74:46:66:55:fe:
+                    a0:95:35:9e:ef:9f:af:11:fa:5b:a3:7c:c2:35:64:
+                    11:67:28:1e:14:0a:7d:68:61:9c:cd:c7:46:39:30:
+                    31:79:94:56:b3:45:16:9a:b5:77:66:fe:41:43:0f:
+                    00:48:6e:99:dd:0c:d4:47:2c:86:8c:50:04:61:20:
+                    dd:aa:8e:73:4f:21:b4:ee:09:4d:d3:40:01:d0:f2:
+                    a7:5b:7d:05:3d:c1:e7:65:26:aa:8c:9a:58:5a:7c:
+                    6d:6f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                A8:D5:4B:BB:38:25:CF:B9:4F:A1:3C:9F:8A:59:4A:19:5C:10:7B:8D
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        24:25:25:7e:01:a5:c8:3d:54:8c:1b:05:73:d1:06:d8:db:d4:
+        3a:71:d5:19:9d:97:1c:85:3c:ca:38:5a:0c:25:25:39:1a:67:
+        bc:6c:9d:98:6c:f3:7d:5f:b7:40:f9:73:a0:f5:7b:40:a8:66:
+        a5:f1:53:b1:78:80:24:3f:19:50:2f:02:09:ec:a1:8a:e6:0d:
+        df:c4:ae:24:9e:69:0d:5c:dc:44:4c:38:3a:53:4e:4b:a1:4b:
+        92:9f:43:a4:9d:1e:76:33:18:1b:bf:62:e5:f5:bc:93:3c:4e:
+        21:d5:5b:20:69:11:28:c1:c5:93:b5:8e:96:1d:1b:ca:72:79:
+        24:de:67:2a:50:9d:ce:8b:41:dd:3e:82:dd:a5:04:75:54:fb:
+        35:70:98:87:b4:f3:ea:41:23:23:80:0e:99:d7:03:16:ee:7e:
+        11:e2:c8:29:ab:73:c5:6d:5c:a8:2f:32:03:9f:8e:66:d6:cb:
+        54:84:55:75:ab:9a:dd:95:fd:05:1e:11:85:37:1e:63:d2:f4:
+        7f:34:64:32:a1:63:91:91:50:39:14:1a:ea:54:78:e6:0d:04:
+        23:c7:83:51:c5:25:27:07:6c:f8:65:b7:da:95:89:76:83:cc:
+        f3:7e:06:74:d3:6c:ef:e9:17:de:29:1e:ab:5c:d7:ec:df:f1:
+        98:b8:e9:66
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTI5MzJaGA8yMDUxMDky
+MjE5MjkzMlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYxKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKq4NFu2rkS/QeF4
+Ebl6yIizsCZQEJyY0fOYnyNQZPY53VA6I0RTZfzzn/Wli66L30ef6dWgkhnxIerM
+WTp030VxvN5kFaX228px+hnURA0S7Ec6Q+Ly3Yv+DXvcTdtTBiJh5Ys1SbYzxApp
+X1uBCYRrQjMYCZ2gNfecHt5u3pBpGugy5EmtwzHp+EqiKB3bDSm2SApEk4ZBYo9z
+l2AQinRGZlX+oJU1nu+frxH6W6N8wjVkEWcoHhQKfWhhnM3HRjkwMXmUVrNFFpq1
+d2b+QUMPAEhumd0M1EcshoxQBGEg3aqOc08htO4JTdNAAdDyp1t9BT3B52Umqoya
+WFp8bW8CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUqNVLuzglz7lPoTyfillKGVwQe40wHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+ACQlJX4Bpcg9VIwbBXPRBtjb1Dpx1RmdlxyFPMo4WgwlJTkaZ7xsnZhs831ft0D5
+c6D1e0CoZqXxU7F4gCQ/GVAvAgnsoYrmDd/EriSeaQ1c3ERMODpTTkuhS5KfQ6Sd
+HnYzGBu/YuX1vJM8TiHVWyBpESjBxZO1jpYdG8pyeSTeZypQnc6LQd0+gt2lBHVU
++zVwmIe08+pBIyOADpnXAxbufhHiyCmrc8VtXKgvMgOfjmbWy1SEVXWrmt2V/QUe
+EYU3HmPS9H80ZDKhY5GRUDkUGupUeOYNBCPHg1HFJScHbPhlt9qViXaDzPN+BnTT
+bO/pF94pHqtc1+zf8Zi46WY=
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 7 (0x7)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:29:42 2021 GMT
+            Not After : Sep 22 19:29:42 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v2)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ba:06:8b:ee:58:b7:8b:49:7b:53:7a:d1:df:02:
+                    e3:f2:d8:b0:8c:03:5c:f4:2d:0b:d8:18:3b:23:fa:
+                    68:b0:e8:e9:9d:dc:a2:eb:5e:d3:06:a9:28:d4:9f:
+                    14:b6:1e:1c:1d:ef:69:0e:7f:44:f2:cc:4a:f1:b1:
+                    d0:71:30:6a:50:1e:b0:d3:f8:a4:19:d0:4a:f1:e3:
+                    eb:7a:e5:57:4c:a1:fb:d1:87:b9:48:e0:55:37:52:
+                    f9:de:99:2e:95:85:36:ce:d3:1d:67:2f:14:cb:7f:
+                    05:82:75:21:b6:aa:a5:14:ac:da:4a:f4:fe:fa:5c:
+                    33:49:3d:6f:de:fd:9d:75:ba:e2:c4:02:38:b5:69:
+                    f5:ff:a8:67:4b:3a:e0:34:f6:3b:07:03:a5:7e:59:
+                    6f:3a:d2:28:a4:2f:25:ac:d8:a9:1f:59:52:5d:24:
+                    36:58:51:b5:f0:12:a8:d3:78:56:57:b1:e0:a9:df:
+                    14:05:65:7c:b5:a5:00:f0:88:39:14:44:18:85:2d:
+                    0c:28:69:7b:b9:b4:1c:47:6f:43:66:4c:22:ad:f7:
+                    f6:19:75:e1:14:2c:0d:33:3f:c1:3f:fc:73:56:b2:
+                    68:05:b5:92:03:9b:65:6b:81:80:92:35:03:9b:66:
+                    68:58:c5:66:11:b6:8c:7f:05:09:9a:45:a6:0e:5e:
+                    5f:bf
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                4C:F0:46:89:2D:6F:D3:C9:A5:B0:3F:98:D8:45:F9:08:51:DC:6A:8C
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        93:9d:49:7d:9f:3e:3e:27:79:97:d9:c2:fc:0b:f7:30:b7:f4:
+        78:b2:c9:e4:5e:42:d3:27:26:70:cf:88:96:d1:f2:ea:a0:75:
+        7e:3c:f6:b7:d2:e7:95:30:e3:a6:67:a7:ee:b9:53:8f:fd:b2:
+        cb:db:e1:98:32:be:98:79:09:46:c6:63:6a:57:87:4d:b2:26:
+        46:f6:34:5e:18:75:ca:82:80:8e:33:c2:1d:c7:76:d7:14:57:
+        ef:2e:0e:9e:58:5c:81:8e:ed:53:2c:07:46:0a:8a:fc:2f:f5:
+        b2:c8:58:f5:fa:fa:bb:f9:7d:47:13:39:f0:f2:1c:15:9c:75:
+        90:40:bd:08:04:b3:6a:de:c2:cd:34:21:7e:ba:31:48:bc:a1:
+        23:bc:ee:93:b2:62:96:27:30:86:c2:d4:f7:b4:e6:3c:71:47:
+        37:84:ff:3d:0c:1e:ec:f3:0e:da:6b:dc:64:7a:b8:c0:7e:45:
+        13:09:bf:02:b3:b7:5b:6d:09:2d:6a:4e:0b:93:94:29:4c:a6:
+        c3:c7:05:fa:69:08:04:53:3c:4c:64:c0:7e:89:00:91:1b:a6:
+        c2:d7:ea:c4:db:86:38:fe:66:03:85:7b:fc:39:24:99:4c:2a:
+        3e:10:8b:91:c3:6e:20:9d:0c:ee:51:70:b5:98:58:f3:5c:ac:
+        16:98:7b:ce
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTI5NDJaGA8yMDUxMDky
+MjE5Mjk0MlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYyKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALoGi+5Yt4tJe1N6
+0d8C4/LYsIwDXPQtC9gYOyP6aLDo6Z3coute0wapKNSfFLYeHB3vaQ5/RPLMSvGx
+0HEwalAesNP4pBnQSvHj63rlV0yh+9GHuUjgVTdS+d6ZLpWFNs7THWcvFMt/BYJ1
+IbaqpRSs2kr0/vpcM0k9b979nXW64sQCOLVp9f+oZ0s64DT2OwcDpX5ZbzrSKKQv
+JazYqR9ZUl0kNlhRtfASqNN4Vlex4KnfFAVlfLWlAPCIORREGIUtDChpe7m0HEdv
+Q2ZMIq339hl14RQsDTM/wT/8c1ayaAW1kgObZWuBgJI1A5tmaFjFZhG2jH8FCZpF
+pg5eX78CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTPBGiS1v08mlsD+Y2EX5CFHcaowwHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+AJOdSX2fPj4neZfZwvwL9zC39HiyyeReQtMnJnDPiJbR8uqgdX489rfS55Uw46Zn
+p+65U4/9ssvb4Zgyvph5CUbGY2pXh02yJkb2NF4YdcqCgI4zwh3HdtcUV+8uDp5Y
+XIGO7VMsB0YKivwv9bLIWPX6+rv5fUcTOfDyHBWcdZBAvQgEs2rews00IX66MUi8
+oSO87pOyYpYnMIbC1Pe05jxxRzeE/z0MHuzzDtpr3GR6uMB+RRMJvwKzt1ttCS1q
+TguTlClMpsPHBfppCARTPExkwH6JAJEbpsLX6sTbhjj+ZgOFe/w5JJlMKj4Qi5HD
+biCdDO5RcLWYWPNcrBaYe84=
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 8 (0x8)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:30:02 2021 GMT
+            Not After : Sep 22 19:30:02 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v3)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:d6:29:96:87:ae:07:42:45:bb:65:09:b2:9b:de:
+                    5d:8e:78:61:10:d5:6d:ae:ae:26:08:6a:06:ec:4a:
+                    dd:2b:e7:1a:a9:ad:78:e3:fc:cf:8f:d1:47:bd:1e:
+                    33:d8:7a:e3:66:9b:e9:73:c1:5f:42:e2:fe:bc:c3:
+                    41:f7:cd:d7:85:d7:42:c9:ea:31:e5:47:b1:93:5b:
+                    43:2b:07:51:b8:75:08:ad:0f:e7:0d:81:38:5a:21:
+                    df:b1:43:5b:db:37:c5:ac:aa:14:3a:33:19:6a:26:
+                    e0:05:fe:cd:41:31:af:5d:a8:ab:31:77:44:fc:da:
+                    00:e2:7a:44:33:c3:a7:ed:13:54:9f:19:5d:c9:98:
+                    a2:3b:af:4d:0d:87:29:9c:90:9e:42:9e:9a:06:6a:
+                    70:27:c5:aa:f7:a2:f2:88:e0:b9:66:9a:72:a0:f6:
+                    61:7e:30:8f:14:9f:44:0d:dd:54:ae:47:c8:82:ba:
+                    d2:b2:db:6f:24:c1:f4:0a:81:07:90:47:49:5f:57:
+                    d6:3f:bf:2a:73:98:f2:f6:24:1a:74:03:d7:35:f0:
+                    42:d8:14:c5:94:27:5d:3c:49:0c:b0:f0:7a:61:1b:
+                    d7:5a:e3:a3:40:57:e9:a4:07:ee:02:a3:32:27:94:
+                    bb:f3:36:c5:5f:ef:d3:07:04:3a:80:4c:9c:0a:b7:
+                    88:9f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                10:04:37:BB:6D:E6:E4:69:B5:81:E6:1C:D6:6B:CE:3E:F4:ED:53:AF
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        3b:37:d6:a8:8d:cd:d2:df:13:35:ac:8c:92:d6:b0:ac:d1:38:
+        a8:00:97:47:59:b8:4a:84:8c:80:a5:1d:c7:29:bf:00:66:e5:
+        10:40:26:2e:31:f5:e1:13:c0:1b:29:f3:0b:7e:2d:71:d8:db:
+        e1:32:8f:79:8e:e3:97:0c:40:a9:a0:12:c1:fc:c2:50:88:72:
+        44:c5:bc:8b:45:6e:28:fd:d2:37:d6:db:17:cf:4e:61:33:08:
+        5a:5d:08:94:73:44:e2:76:00:44:1b:b8:00:a1:86:00:64:8a:
+        f1:42:32:3c:28:11:67:7c:8b:aa:06:34:74:58:e8:b3:3a:36:
+        8d:f6:04:5d:37:f5:66:52:c9:48:b0:a7:6f:34:09:dd:60:2a:
+        86:b9:14:f1:09:f6:06:16:56:e0:51:b1:e8:75:7f:fa:37:dc:
+        e0:98:a7:69:ae:7b:1a:73:89:0d:06:67:cc:01:ef:80:31:45:
+        9e:bb:03:2a:eb:89:70:d6:19:b2:c7:ce:bc:81:df:da:c8:6f:
+        a9:4b:2d:d7:a7:e1:af:c6:e8:fb:f0:61:c9:cd:d2:91:cd:8b:
+        c2:6c:ef:e0:b6:7f:f1:c4:81:f9:bb:76:9c:26:e3:fa:a1:a0:
+        cd:5e:05:de:ee:f9:1b:5b:50:0a:8b:0f:47:e3:90:32:ac:2a:
+        e7:65:02:80
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTMwMDJaGA8yMDUxMDky
+MjE5MzAwMlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYzKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANYploeuB0JFu2UJ
+spveXY54YRDVba6uJghqBuxK3SvnGqmteOP8z4/RR70eM9h642ab6XPBX0Li/rzD
+QffN14XXQsnqMeVHsZNbQysHUbh1CK0P5w2BOFoh37FDW9s3xayqFDozGWom4AX+
+zUExr12oqzF3RPzaAOJ6RDPDp+0TVJ8ZXcmYojuvTQ2HKZyQnkKemgZqcCfFqvei
+8ojguWaacqD2YX4wjxSfRA3dVK5HyIK60rLbbyTB9AqBB5BHSV9X1j+/KnOY8vYk
+GnQD1zXwQtgUxZQnXTxJDLDwemEb11rjo0BX6aQH7gKjMieUu/M2xV/v0wcEOoBM
+nAq3iJ8CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUEAQ3u23m5Gm1geYc1mvOPvTtU68wHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+ADs31qiNzdLfEzWsjJLWsKzROKgAl0dZuEqEjIClHccpvwBm5RBAJi4x9eETwBsp
+8wt+LXHY2+Eyj3mO45cMQKmgEsH8wlCIckTFvItFbij90jfW2xfPTmEzCFpdCJRz
+ROJ2AEQbuAChhgBkivFCMjwoEWd8i6oGNHRY6LM6No32BF039WZSyUiwp280Cd1g
+Koa5FPEJ9gYWVuBRseh1f/o33OCYp2muexpziQ0GZ8wB74AxRZ67AyrriXDWGbLH
+zryB39rIb6lLLden4a/G6PvwYcnN0pHNi8Js7+C2f/HEgfm7dpwm4/qhoM1eBd7u
++RtbUAqLD0fjkDKsKudlAoA=
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Mar  4 10:27:14 2020 GMT
+            Not After : Mar  3 10:27:14 2050 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (Ubuntu Core 2019)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b9:10:47:2e:75:5d:f3:10:23:bb:a0:75:d2:fa:
+                    02:2d:ff:22:df:c1:e6:cd:38:7c:36:0f:ae:74:15:
+                    6e:a5:34:52:2b:c3:a4:3a:60:d7:06:ee:1d:99:93:
+                    ff:66:91:a3:18:52:2c:8c:58:e6:b4:2f:4b:c5:fb:
+                    83:e6:f3:19:bd:1b:ca:23:ec:97:1f:d8:f1:9a:f1:
+                    04:da:da:10:04:53:4b:ec:1d:b6:26:47:7c:bb:8f:
+                    a7:0a:6e:2e:e8:91:e6:c4:bb:64:34:78:3c:fa:09:
+                    15:1c:8f:9e:eb:04:99:36:22:c6:8d:07:15:0f:b9:
+                    69:08:fa:ff:4b:45:bd:ba:2b:cd:01:0e:e7:01:23:
+                    c9:e5:7a:39:3b:91:b0:45:3c:d5:77:ba:ca:f9:29:
+                    3d:11:3f:1c:6b:5b:8e:6c:4b:3f:c9:29:05:cb:59:
+                    d6:b1:c1:c0:2d:56:88:70:27:fa:73:05:5c:c2:11:
+                    d4:27:11:f7:0b:c2:d5:68:d3:1a:cd:ed:d0:e4:10:
+                    ff:34:cb:b7:45:70:34:2c:23:53:b6:9c:30:70:b4:
+                    5c:d1:e2:64:18:82:8f:62:b1:5e:aa:0b:d4:89:f2:
+                    1c:53:c4:32:7d:ef:53:ee:9b:6e:02:ab:78:bd:25:
+                    67:8b:39:36:d8:84:3b:06:99:02:d6:75:73:4e:f2:
+                    f6:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                C1:D5:7B:8F:6B:74:3F:23:EE:41:F4:F7:EE:29:2F:06:EE:CA:DF:B9
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        2d:b5:11:a8:d2:a0:af:81:a0:18:22:18:2c:08:d0:f4:63:e8:
+        8f:9a:f4:f5:20:dd:eb:22:77:19:9a:1a:09:3d:7f:aa:7d:c9:
+        81:bc:26:98:65:94:46:30:4b:c2:51:7c:f7:21:41:63:87:31:
+        fc:a4:c9:41:28:c7:2e:2a:2e:d8:a8:75:7a:72:77:3b:1b:9f:
+        72:15:0d:0c:96:8d:8b:51:f3:ce:37:b6:ca:9f:ca:59:40:4a:
+        fc:73:7a:94:12:99:aa:c2:8d:52:ce:91:19:2e:b4:da:ff:e5:
+        2c:67:74:d9:58:47:38:2f:61:88:c5:cf:a7:48:e1:08:ba:bc:
+        ec:d5:3a:47:d9:8c:dc:c3:bc:cb:98:2b:79:7a:02:46:ef:85:
+        19:2f:03:4b:05:84:eb:56:98:5f:6d:cf:a5:8b:a2:b6:e5:50:
+        51:7c:33:44:bd:7a:94:2e:0d:90:39:39:3e:62:60:ae:3a:e2:
+        f5:17:fa:f1:94:06:1d:ae:a3:f8:19:20:7f:4b:4c:07:c4:e6:
+        2d:0d:e5:94:84:51:6d:6f:0f:c4:c6:79:1d:f0:e8:0e:23:9e:
+        fd:f9:46:2c:b9:ec:97:38:56:7e:b8:13:f6:d2:e1:8e:a5:93:
+        02:7b:6e:dd:33:9a:bf:10:a8:1b:3d:fa:c4:f2:15:f0:27:73:
+        26:a6:94:d1
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMDAzMDQxMDI3MTRaGA8yMDUwMDMw
+MzEwMjcxNFowgZIxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MT4w
+PAYDVQQDDDVDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nIChVYnVu
+dHUgQ29yZSAyMDE5KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkQ
+Ry51XfMQI7ugddL6Ai3/It/B5s04fDYPrnQVbqU0UivDpDpg1wbuHZmT/2aRoxhS
+LIxY5rQvS8X7g+bzGb0byiPslx/Y8ZrxBNraEARTS+wdtiZHfLuPpwpuLuiR5sS7
+ZDR4PPoJFRyPnusEmTYixo0HFQ+5aQj6/0tFvborzQEO5wEjyeV6OTuRsEU81Xe6
+yvkpPRE/HGtbjmxLP8kpBctZ1rHBwC1WiHAn+nMFXMIR1CcR9wvC1WjTGs3t0OQQ
+/zTLt0VwNCwjU7acMHC0XNHiZBiCj2KxXqoL1InyHFPEMn3vU+6bbgKreL0lZ4s5
+NtiEOwaZAtZ1c07y9rkCAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQY
+MBYGCCsGAQUFBwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
+IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUwdV7j2t0PyPuQfT37ikv
+Bu7K37kwHwYDVR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcN
+AQELBQADggEBAC21EajSoK+BoBgiGCwI0PRj6I+a9PUg3esidxmaGgk9f6p9yYG8
+JphllEYwS8JRfPchQWOHMfykyUEoxy4qLtiodXpydzsbn3IVDQyWjYtR8843tsqf
+yllASvxzepQSmarCjVLOkRkutNr/5SxndNlYRzgvYYjFz6dI4Qi6vOzVOkfZjNzD
+vMuYK3l6AkbvhRkvA0sFhOtWmF9tz6WLorblUFF8M0S9epQuDZA5OT5iYK464vUX
++vGUBh2uo/gZIH9LTAfE5i0N5ZSEUW1vD8TGeR3w6A4jnv35Riy57Jc4Vn64E/bS
+4Y6lkwJ7bt0zmr8QqBs9+sTyFfAncyamlNE=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/certs/canonical-livepatch-all.pem
+++ linux-ein-5.4.0/debian/certs/canonical-livepatch-all.pem
@@ -0,0 +1,121 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            c7:7e:51:6a:1c:25:cd:40
+        Signature Algorithm: sha512WithRSAEncryption
+        Issuer: CN = Canonical Ltd. Live Patch Signing
+        Validity
+            Not Before: Jul 18 23:41:27 2016 GMT
+            Not After : Jul 16 23:41:27 2026 GMT
+        Subject: CN = Canonical Ltd. Live Patch Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (4096 bit)
+                Modulus:
+                    00:bd:74:ee:72:b3:4a:ab:e6:31:e8:29:24:c2:bd:
+                    46:98:32:c0:39:ee:a3:fb:8a:ad:fe:ab:1a:5b:a3:
+                    2e:a1:80:db:79:61:9e:47:79:2c:75:57:a2:21:f0:
+                    93:f6:87:f2:9b:4b:9d:2f:b3:58:61:28:3c:41:70:
+                    13:16:a1:72:90:c9:d5:16:71:7c:e0:30:f9:28:5e:
+                    48:20:36:00:69:b7:59:9f:a3:ec:a8:eb:55:41:9f:
+                    38:1e:22:4a:57:20:f4:83:59:49:c5:00:93:d3:33:
+                    02:92:d1:fc:f0:84:3b:4a:5b:8f:b6:73:9a:89:fa:
+                    30:1e:e6:2a:68:f2:91:ef:59:57:3d:dc:1c:52:6f:
+                    5e:e6:9b:b5:b8:7c:98:c9:13:d1:39:68:01:67:91:
+                    e0:d3:67:72:16:0a:5e:16:83:45:31:4f:b5:2b:b3:
+                    f6:40:86:89:3a:84:6e:6f:16:61:bc:70:84:be:5a:
+                    13:36:7b:82:ea:07:19:fc:18:c1:16:c6:32:0b:7d:
+                    2c:6b:c4:21:b9:38:6b:31:dc:d9:0c:ad:56:40:68:
+                    7c:e3:c6:64:8e:bf:1c:e0:72:3e:6c:db:d2:73:79:
+                    da:d7:c5:2f:5d:04:7d:b0:07:1e:95:dd:2a:47:5e:
+                    bf:3e:3a:c8:66:f6:67:0f:d4:2a:f1:e2:71:59:d2:
+                    6c:7b:a0:37:ac:e6:97:80:30:13:97:48:d5:74:fc:
+                    38:68:e4:57:cb:99:69:5a:84:27:ac:98:51:e4:64:
+                    bd:91:62:e8:58:27:06:2a:b9:0b:b8:08:e5:e5:b4:
+                    51:a7:a2:10:df:4e:07:6c:a0:3b:96:f2:6e:df:75:
+                    8c:97:1e:64:a0:9a:86:9b:98:26:f9:d8:b7:de:5b:
+                    21:b7:af:89:01:a3:f7:98:6b:da:19:ba:86:ef:ef:
+                    f1:ce:bb:2f:89:ed:c0:b6:1b:e5:5b:f8:90:11:9a:
+                    52:93:e9:be:f7:35:b9:08:cb:ba:c3:ed:2f:73:af:
+                    cc:96:07:55:b5:de:f6:03:f6:f1:89:f9:21:40:76:
+                    c1:69:f2:61:cc:9a:94:df:9c:ec:6a:65:38:be:d1:
+                    4e:2a:87:c7:2f:3e:53:ae:8b:9f:54:a1:09:59:64:
+                    25:aa:a9:d8:44:a9:a8:a0:71:e1:32:aa:4c:32:fd:
+                    44:28:cc:9c:6f:8e:db:81:7e:6f:fa:00:56:c5:e5:
+                    03:46:63:fb:8e:71:8d:e3:13:91:9f:ac:60:3e:64:
+                    f3:df:25:34:09:fa:2d:96:9f:16:05:ea:93:f5:e6:
+                    00:08:27:32:7b:3c:bd:ee:70:24:6c:3b:55:e9:db:
+                    f4:10:2d:20:06:b4:ca:e9:29:65:55:ad:f6:52:54:
+                    5f:e5:a3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+            X509v3 Subject Key Identifier: 
+                14:DF:34:D1:A8:7C:F3:76:25:AB:EC:03:9E:F2:BF:52:12:49:B9:69
+            X509v3 Authority Key Identifier: 
+                keyid:14:DF:34:D1:A8:7C:F3:76:25:AB:EC:03:9E:F2:BF:52:12:49:B9:69
+
+    Signature Algorithm: sha512WithRSAEncryption
+         30:e7:48:02:37:e9:28:cf:04:a2:4d:5c:fa:d8:4e:c9:76:c7:
+         14:3f:bd:2c:51:3d:33:f0:1a:bc:49:f1:47:95:8f:69:d8:a9:
+         54:14:44:6c:4d:9f:55:82:08:1e:c6:5b:d5:91:d9:bc:2e:b0:
+         af:d6:25:65:74:96:aa:36:de:ae:31:a8:11:f2:a4:2c:5a:e1:
+         4f:73:f8:4a:c3:35:b0:76:96:71:f2:b5:7d:4b:75:ee:5d:bf:
+         86:a5:ba:0b:a9:52:cb:ec:ab:e5:23:4b:f2:74:55:28:17:1e:
+         b3:ac:27:ad:45:13:6e:69:b3:5a:be:42:36:29:48:db:e7:5c:
+         22:58:a0:90:82:2c:2a:21:2b:db:f4:64:b7:91:5d:1f:2c:48:
+         a4:1a:85:e3:86:a5:aa:19:cd:19:e8:a5:fb:a3:7b:94:77:48:
+         25:a4:cf:a0:cf:71:82:5c:6f:71:22:7c:d6:97:a0:53:bb:ec:
+         30:f6:cb:16:fb:7b:fd:16:94:7a:53:6e:bd:04:64:a2:01:10:
+         9f:f0:5b:b5:a6:73:41:9d:5f:6f:45:73:0d:05:f7:30:6d:39:
+         90:b6:7d:55:7d:4c:2f:ae:5f:38:56:2f:8b:df:f4:bf:12:06:
+         93:6e:0d:02:23:bf:71:91:57:88:e8:bd:62:72:99:00:40:29:
+         1e:c9:13:11:da:7e:8e:e1:d2:a5:0d:bf:f7:d6:ec:01:0d:89:
+         41:cd:d5:dc:d2:f7:5f:33:0d:4c:2f:85:b7:85:b7:81:e4:17:
+         29:f0:74:cf:0e:15:8c:1a:50:0b:08:63:1a:91:4f:e7:76:97:
+         f1:d4:3b:7e:72:d4:c5:45:58:0c:6a:e9:0d:f2:85:d8:91:1e:
+         37:bd:78:e3:39:4d:2e:fd:85:31:c1:a6:3b:6a:cc:2c:53:72:
+         1d:8e:7b:f0:e6:76:86:09:6f:1a:f3:e4:a1:e2:dd:76:5f:b0:
+         8c:e2:2a:54:5d:c1:88:49:90:10:15:42:7d:05:24:53:8c:54:
+         ff:48:18:1a:36:e3:31:d3:54:32:78:0d:fe:f2:3d:aa:0d:37:
+         15:84:b4:36:47:31:e8:85:6e:0b:58:38:ff:21:91:09:c9:a8:
+         43:a3:ea:60:cb:7e:ed:f7:41:6f:4e:91:c1:fd:77:46:e7:d4:
+         e7:86:c0:1b:fd:50:6c:aa:be:00:b3:63:02:ff:4e:c7:a5:57:
+         6e:29:64:e9:54:d5:30:63:38:5f:2d:5a:db:49:5f:14:14:22:
+         d2:81:1f:61:9e:ee:ee:16:66:d6:bc:bd:ac:1b:5c:fb:38:31:
+         95:33:2e:84:6e:7a:de:ee:b9:fc:97:17:06:13:bf:70:1c:6e:
+         76:ed:66:38:e2:70:08:00
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIJAMd+UWocJc1AMA0GCSqGSIb3DQEBDQUAMCwxKjAoBgNV
+BAMMIUNhbm9uaWNhbCBMdGQuIExpdmUgUGF0Y2ggU2lnbmluZzAeFw0xNjA3MTgy
+MzQxMjdaFw0yNjA3MTYyMzQxMjdaMCwxKjAoBgNVBAMMIUNhbm9uaWNhbCBMdGQu
+IExpdmUgUGF0Y2ggU2lnbmluZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAL107nKzSqvmMegpJMK9RpgywDnuo/uKrf6rGlujLqGA23lhnkd5LHVXoiHw
+k/aH8ptLnS+zWGEoPEFwExahcpDJ1RZxfOAw+SheSCA2AGm3WZ+j7KjrVUGfOB4i
+Slcg9INZScUAk9MzApLR/PCEO0pbj7Zzmon6MB7mKmjyke9ZVz3cHFJvXuabtbh8
+mMkT0TloAWeR4NNnchYKXhaDRTFPtSuz9kCGiTqEbm8WYbxwhL5aEzZ7guoHGfwY
+wRbGMgt9LGvEIbk4azHc2QytVkBofOPGZI6/HOByPmzb0nN52tfFL10EfbAHHpXd
+Kkdevz46yGb2Zw/UKvHicVnSbHugN6zml4AwE5dI1XT8OGjkV8uZaVqEJ6yYUeRk
+vZFi6FgnBiq5C7gI5eW0UaeiEN9OB2ygO5bybt91jJceZKCahpuYJvnYt95bIbev
+iQGj95hr2hm6hu/v8c67L4ntwLYb5Vv4kBGaUpPpvvc1uQjLusPtL3OvzJYHVbXe
+9gP28Yn5IUB2wWnyYcyalN+c7GplOL7RTiqHxy8+U66Ln1ShCVlkJaqp2ESpqKBx
+4TKqTDL9RCjMnG+O24F+b/oAVsXlA0Zj+45xjeMTkZ+sYD5k898lNAn6LZafFgXq
+k/XmAAgnMns8ve5wJGw7Venb9BAtIAa0yukpZVWt9lJUX+WjAgMBAAGjXTBbMAwG
+A1UdEwEB/wQCMAAwCwYDVR0PBAQDAgeAMB0GA1UdDgQWBBQU3zTRqHzzdiWr7AOe
+8r9SEkm5aTAfBgNVHSMEGDAWgBQU3zTRqHzzdiWr7AOe8r9SEkm5aTANBgkqhkiG
+9w0BAQ0FAAOCAgEAMOdIAjfpKM8Eok1c+thOyXbHFD+9LFE9M/AavEnxR5WPadip
+VBREbE2fVYIIHsZb1ZHZvC6wr9YlZXSWqjberjGoEfKkLFrhT3P4SsM1sHaWcfK1
+fUt17l2/hqW6C6lSy+yr5SNL8nRVKBces6wnrUUTbmmzWr5CNilI2+dcIligkIIs
+KiEr2/Rkt5FdHyxIpBqF44alqhnNGeil+6N7lHdIJaTPoM9xglxvcSJ81pegU7vs
+MPbLFvt7/RaUelNuvQRkogEQn/BbtaZzQZ1fb0VzDQX3MG05kLZ9VX1ML65fOFYv
+i9/0vxIGk24NAiO/cZFXiOi9YnKZAEApHskTEdp+juHSpQ2/99bsAQ2JQc3V3NL3
+XzMNTC+Ft4W3geQXKfB0zw4VjBpQCwhjGpFP53aX8dQ7fnLUxUVYDGrpDfKF2JEe
+N7144zlNLv2FMcGmO2rMLFNyHY578OZ2hglvGvPkoeLddl+wjOIqVF3BiEmQEBVC
+fQUkU4xU/0gYGjbjMdNUMngN/vI9qg03FYS0Nkcx6IVuC1g4/yGRCcmoQ6PqYMt+
+7fdBb06Rwf13RufU54bAG/1QbKq+ALNjAv9Ox6VXbilk6VTVMGM4Xy1a20lfFBQi
+0oEfYZ7u7hZm1ry9rBtc+zgxlTMuhG563u65/JcXBhO/cBxudu1mOOJwCAA=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/certs/ubuntu-drivers-all.pem
+++ linux-ein-5.4.0/debian/certs/ubuntu-drivers-all.pem
@@ -0,0 +1,125 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            e9:df:13:0f:92:92:a9:b7
+        Signature Algorithm: sha512WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Kernel Module Signing
+        Validity
+            Not Before: May 31 16:06:09 2016 GMT
+            Not After : May 29 16:06:09 2026 GMT
+        Subject: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Kernel Module Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (4096 bit)
+                Modulus:
+                    00:b3:b0:4f:c6:0a:77:8b:f9:d1:53:33:34:d2:80:
+                    b5:63:6f:e1:f6:a2:83:99:d5:b6:b1:e4:99:91:fa:
+                    6c:19:c6:d0:91:2a:b9:7d:b5:98:a6:0d:28:01:b8:
+                    7c:8e:aa:38:ec:51:37:33:96:f0:b0:9b:8d:86:5f:
+                    67:23:69:2f:d7:c2:f3:fb:c5:d7:f9:04:ff:f2:e5:
+                    61:68:b7:29:b9:c6:8e:4b:4d:2d:8f:92:0c:00:b3:
+                    a3:d2:5a:08:64:cd:f2:09:0b:a5:0e:e6:64:75:d5:
+                    41:f4:4d:49:3a:0d:dc:b9:27:8e:c4:d6:b1:df:8f:
+                    6c:f0:e4:f7:31:cb:a9:04:a1:f9:a7:aa:15:da:59:
+                    03:4d:46:14:d0:dd:bf:e0:f5:9e:f0:71:0c:70:78:
+                    2b:08:fb:e0:b6:68:a4:74:12:9d:f7:f2:64:88:17:
+                    2a:8a:ed:1a:91:b5:6c:13:bd:4c:10:0a:0b:72:0b:
+                    90:db:7d:f3:78:44:4c:d2:a5:41:f7:1c:77:7d:5a:
+                    8a:54:bc:8f:fe:b7:ee:e1:bc:59:37:c4:d4:e8:14:
+                    d0:5b:42:9b:04:00:8e:6d:83:8a:25:21:5b:08:c4:
+                    7b:b2:d9:99:52:c9:5e:59:6d:c4:aa:52:59:e2:e4:
+                    2f:7e:7e:ac:05:01:99:bf:13:72:b7:45:c5:17:da:
+                    8a:d5:3e:71:73:2e:d8:aa:e6:eb:5a:d0:9a:c4:93:
+                    f3:be:eb:d2:47:25:34:16:29:fa:dd:9a:2f:b1:20:
+                    e5:41:4e:ed:ea:51:7c:23:80:ba:3d:b5:3a:0b:8c:
+                    9c:85:48:6c:3c:8b:29:2f:2f:12:c7:52:34:02:ea:
+                    0f:ac:53:23:3c:f8:3e:40:1b:30:63:e9:2d:e6:f6:
+                    58:cc:51:f9:eb:08:4a:b4:c7:16:80:d1:8b:c2:64:
+                    6a:71:a9:70:31:a4:a7:3a:c0:93:99:1b:0e:42:c1:
+                    00:6d:43:27:99:6c:e5:fd:23:16:c1:8e:b5:66:17:
+                    2b:4c:53:5a:6d:1e:96:16:13:6a:c6:d4:85:5b:74:
+                    2e:ce:7c:45:2f:ad:cb:75:9e:5e:91:bd:9a:6a:86:
+                    1a:06:bd:39:be:a3:50:56:ea:e1:f6:e3:95:69:d7:
+                    31:e4:66:f7:36:b5:51:c2:22:b4:9c:74:9c:44:0b:
+                    0e:16:5f:53:f0:23:c6:b9:40:bd:d6:b8:7d:1b:f6:
+                    73:f6:27:e7:c0:e3:65:a0:58:ab:5c:59:b7:80:8c:
+                    8c:04:b4:a9:ae:a0:51:40:10:3b:63:59:49:87:d1:
+                    9b:df:a3:8c:c4:2e:eb:70:c1:0a:18:1f:cb:22:c2:
+                    f2:4a:65:0d:e5:81:74:d8:ce:72:c6:35:be:ba:63:
+                    72:c4:f9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+            X509v3 Subject Key Identifier: 
+                88:F7:52:E5:60:A1:E0:73:7E:31:16:3A:46:6A:D7:B7:0A:85:0C:19
+            X509v3 Authority Key Identifier: 
+                keyid:88:F7:52:E5:60:A1:E0:73:7E:31:16:3A:46:6A:D7:B7:0A:85:0C:19
+
+    Signature Algorithm: sha512WithRSAEncryption
+         04:85:16:27:58:ba:71:28:57:86:7b:c2:83:db:e5:72:6f:1e:
+         b2:1c:63:b0:db:ad:c0:42:96:c0:4f:65:f6:35:4d:c0:07:0d:
+         46:be:d3:1e:ec:f1:22:18:2a:18:5d:bb:69:a6:a6:d4:0d:c3:
+         57:03:b9:e7:45:49:28:ca:6d:98:17:68:97:cb:7b:36:81:0a:
+         37:9e:34:79:f3:e1:0e:5b:77:43:bb:5a:a5:45:b7:16:50:86:
+         fd:12:a4:96:0f:15:19:09:1c:e1:fa:80:a5:80:09:be:bb:c8:
+         26:0b:3e:de:03:d2:c2:18:a4:8d:0d:de:c5:32:82:0b:fb:75:
+         55:66:1a:2a:bb:e4:bd:25:91:20:15:d4:be:b8:3f:53:e3:fb:
+         a8:c3:55:e3:d5:e7:82:18:95:df:39:09:a7:fc:89:6e:b4:1c:
+         aa:2d:e8:67:c2:0d:34:34:3e:f9:fa:0b:ce:81:92:11:ae:12:
+         0a:fe:35:63:ce:46:29:c4:2b:4f:cb:4e:05:0a:a1:11:e2:35:
+         f6:5a:5d:b5:e8:d2:6f:4c:fc:3d:24:a6:03:4b:dd:98:6b:f2:
+         71:58:16:1d:a5:25:ef:d9:06:7c:e8:db:7b:88:6a:89:5c:59:
+         01:92:64:db:44:08:63:6c:7c:32:d6:55:98:63:09:26:61:67:
+         0a:fe:5d:ee:fd:23:59:b3:4d:91:c1:4d:41:8b:cd:20:58:fa:
+         2d:45:e5:bd:1d:69:5c:03:a0:49:a6:97:54:13:b6:c9:e0:f8:
+         56:83:a1:2a:c3:f4:6c:fd:ab:20:ca:3d:9c:95:c0:cf:04:bb:
+         46:39:cf:34:81:65:45:27:64:01:7d:62:b3:b8:72:ea:10:d5:
+         0f:53:7d:39:88:25:09:6f:8c:bc:e0:49:bb:39:e2:0e:8d:cf:
+         56:4d:c1:82:6d:87:d2:e7:fc:c0:9f:a7:65:60:d2:6c:65:18:
+         59:38:6e:d0:9c:d7:c3:81:9a:9a:29:8f:83:84:c3:b5:44:ff:
+         28:ac:13:17:64:f2:26:13:d9:55:06:b7:69:68:7c:bf:ec:d1:
+         8c:ef:b7:da:76:e1:07:73:c6:31:62:31:cb:b6:e1:e7:7f:0c:
+         c3:f7:4c:52:be:25:36:8e:a1:bb:60:02:c3:cb:3e:6f:29:fc:
+         7f:6a:fa:f8:ec:0a:df:49:e2:57:0e:bc:bd:93:c3:1b:d5:36:
+         8a:ff:d8:1b:17:c7:1f:cb:69:00:d2:54:9e:ad:61:89:92:95:
+         11:f8:ea:17:83:9f:9b:09:7d:b8:94:a4:ea:f5:ae:ea:dc:dd:
+         62:b9:9e:68:9c:18:ec:19:c4:13:08:c8:b1:62:ab:8e:84:69:
+         11:3c:da:ea:0d:b7:22:bd
+-----BEGIN CERTIFICATE-----
+MIIF2jCCA8KgAwIBAgIJAOnfEw+Skqm3MA0GCSqGSIb3DQEBDQUAMH0xCzAJBgNV
+BAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEQMA4GA1UEBwwHRG91Z2xhczEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xLTArBgNVBAMMJENhbm9uaWNhbCBMdGQu
+IEtlcm5lbCBNb2R1bGUgU2lnbmluZzAeFw0xNjA1MzExNjA2MDlaFw0yNjA1Mjkx
+NjA2MDlaMH0xCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEQMA4G
+A1UEBwwHRG91Z2xhczEXMBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xLTArBgNVBAMM
+JENhbm9uaWNhbCBMdGQuIEtlcm5lbCBNb2R1bGUgU2lnbmluZzCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBALOwT8YKd4v50VMzNNKAtWNv4faig5nVtrHk
+mZH6bBnG0JEquX21mKYNKAG4fI6qOOxRNzOW8LCbjYZfZyNpL9fC8/vF1/kE//Ll
+YWi3KbnGjktNLY+SDACzo9JaCGTN8gkLpQ7mZHXVQfRNSToN3LknjsTWsd+PbPDk
+9zHLqQSh+aeqFdpZA01GFNDdv+D1nvBxDHB4Kwj74LZopHQSnffyZIgXKortGpG1
+bBO9TBAKC3ILkNt983hETNKlQfccd31ailS8j/637uG8WTfE1OgU0FtCmwQAjm2D
+iiUhWwjEe7LZmVLJXlltxKpSWeLkL35+rAUBmb8TcrdFxRfaitU+cXMu2Krm61rQ
+msST877r0kclNBYp+t2aL7Eg5UFO7epRfCOAuj21OguMnIVIbDyLKS8vEsdSNALq
+D6xTIzz4PkAbMGPpLeb2WMxR+esISrTHFoDRi8JkanGpcDGkpzrAk5kbDkLBAG1D
+J5ls5f0jFsGOtWYXK0xTWm0elhYTasbUhVt0Ls58RS+ty3WeXpG9mmqGGga9Ob6j
+UFbq4fbjlWnXMeRm9za1UcIitJx0nEQLDhZfU/AjxrlAvda4fRv2c/Yn58DjZaBY
+q1xZt4CMjAS0qa6gUUAQO2NZSYfRm9+jjMQu63DBChgfyyLC8kplDeWBdNjOcsY1
+vrpjcsT5AgMBAAGjXTBbMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgeAMB0GA1Ud
+DgQWBBSI91LlYKHgc34xFjpGate3CoUMGTAfBgNVHSMEGDAWgBSI91LlYKHgc34x
+FjpGate3CoUMGTANBgkqhkiG9w0BAQ0FAAOCAgEABIUWJ1i6cShXhnvCg9vlcm8e
+shxjsNutwEKWwE9l9jVNwAcNRr7THuzxIhgqGF27aaam1A3DVwO550VJKMptmBdo
+l8t7NoEKN540efPhDlt3Q7tapUW3FlCG/RKklg8VGQkc4fqApYAJvrvIJgs+3gPS
+whikjQ3exTKCC/t1VWYaKrvkvSWRIBXUvrg/U+P7qMNV49XnghiV3zkJp/yJbrQc
+qi3oZ8INNDQ++foLzoGSEa4SCv41Y85GKcQrT8tOBQqhEeI19lpdtejSb0z8PSSm
+A0vdmGvycVgWHaUl79kGfOjbe4hqiVxZAZJk20QIY2x8MtZVmGMJJmFnCv5d7v0j
+WbNNkcFNQYvNIFj6LUXlvR1pXAOgSaaXVBO2yeD4VoOhKsP0bP2rIMo9nJXAzwS7
+RjnPNIFlRSdkAX1is7hy6hDVD1N9OYglCW+MvOBJuzniDo3PVk3Bgm2H0uf8wJ+n
+ZWDSbGUYWThu0JzXw4GamimPg4TDtUT/KKwTF2TyJhPZVQa3aWh8v+zRjO+32nbh
+B3PGMWIxy7bh538Mw/dMUr4lNo6hu2ACw8s+byn8f2r6+OwK30niVw68vZPDG9U2
+iv/YGxfHH8tpANJUnq1hiZKVEfjqF4Ofmwl9uJSk6vWu6tzdYrmeaJwY7BnEEwjI
+sWKrjoRpETza6g23Ir0=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/changelog
+++ linux-ein-5.4.0/debian/changelog
@@ -0,0 +1,19272 @@
+linux-ein (5.4.0-1056.64) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1056.64 -proposed tracker (LP: #2068265)
+
+  [ Ubuntu: 5.4.0-187.207 ]
+
+  * focal/linux: 5.4.0-187.207 -proposed tracker (LP: #2068291)
+  * CVE-2024-26925
+    - netfilter: Cleanup nft_net->module_list from nf_tables_exit_net()
+    - netfilter: nf_tables: release batch on table validation from abort path
+    - netfilter: nf_tables: release mutex after nft_gc_seq_end from abort path
+  * CVE-2024-26643
+    - netfilter: nf_tables: mark set as dead when unbinding anonymous set with
+      timeout
+  * 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|ON|OFF}
+    - 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
+
+ -- Aaron Jauregui <aaron.jauregui@canonical.com>  Thu, 20 Jun 2024 16:15:48 +1000
+
+linux-ein (5.4.0-1055.63) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1055.63 -proposed tracker (LP: #2063785)
+
+  [ Ubuntu: 5.4.0-186.206 ]
+
+  * focal/linux: 5.4.0-186.206 -proposed tracker (LP: #2063812)
+  * Mount CIFS fails with Permission denied (LP: #2061986)
+    - cifs: fix ntlmssp auth when there is no key exchange
+  * USB stick can't be detected (LP: #2040948)
+    - usb: Disable USB3 LPM at shutdown
+  * CVE-2024-26733
+    - net: dev: Convert sa_data to flexible array in struct sockaddr
+    - arp: Prevent overflow in arp_req_get().
+    - stddef: Introduce DECLARE_FLEX_ARRAY() helper
+  * CVE-2024-26712
+    - powerpc/kasan: Fix addr error caused by page alignment
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+  * CVE-2021-47063
+    - drm: bridge/panel: Cleanup connector on bridge detach
+  * [Ubuntu 22.04.4/linux-image-6.5.0-26-generic] Kernel output "UBSAN: array-
+    index-out-of-bounds in /build/linux-hwe-6.5-34pCLi/linux-
+    hwe-6.5-6.5.0/drivers/net/hyperv/netvsc.c:1445:41" multiple times,
+    especially during boot. (LP: #2058477)
+    - hv: hyperv.h: Replace one-element array with flexible-array member
+  * CVE-2024-26614
+    - tcp: make sure init the accept_queue's spinlocks once
+    - ipv6: init the accept_queue's spinlocks in inet6_create
+  * Focal update: v5.4.271 upstream stable release (LP: #2060216)
+    - netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+    - net: ip_tunnel: prevent perpetual headroom growth
+    - tun: Fix xdp_rxq_info's queue_index when detaching
+    - ipv6: fix potential "struct net" leak in inet6_rtm_getaddr()
+    - lan78xx: enable auto speed configuration for LAN7850 if no EEPROM is
+      detected
+    - net: usb: dm9601: fix wrong return value in dm9601_mdio_read
+    - Bluetooth: Avoid potential use-after-free in hci_error_reset
+    - Bluetooth: hci_event: Fix handling of HCI_EV_IO_CAPA_REQUEST
+    - Bluetooth: Enforce validation on max value of connection interval
+    - netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
+    - rtnetlink: fix error logic of IFLA_BRIDGE_FLAGS writing back
+    - efi/capsule-loader: fix incorrect allocation size
+    - power: supply: bq27xxx-i2c: Do not free non existing IRQ
+    - ALSA: Drop leftover snd-rtctimer stuff from Makefile
+    - afs: Fix endless loop in directory parsing
+    - gtp: fix use-after-free and null-ptr-deref in gtp_newlink()
+    - wifi: nl80211: reject iftype change with mesh ID change
+    - btrfs: dev-replace: properly validate device names
+    - dmaengine: fsl-qdma: fix SoC may hang on 16 byte unaligned read
+    - dmaengine: fsl-qdma: init irq after reg initialization
+    - mmc: core: Fix eMMC initialization with 1-bit bus connection
+    - x86/cpu/intel: Detect TME keyid bits before setting MTRR mask registers
+    - cachefiles: fix memory leak in cachefiles_add_cache()
+    - fs,hugetlb: fix NULL pointer dereference in hugetlbs_fill_super
+    - gpio: 74x164: Enable output pins after registers are reset
+    - Linux 5.4.271
+  * Focal update: v5.4.270 upstream stable release (LP: #2060019)
+    - KVM: arm64: vgic-its: Test for valid IRQ in its_sync_lpi_pending_table()
+    - KVM: arm64: vgic-its: Test for valid IRQ in MOVALL handler
+    - net/sched: Retire CBQ qdisc
+    - [Config] updateconfigs for NET_SCH_CBQ
+    - net/sched: Retire ATM qdisc
+    - [Config] updateconfigs for NET_SCH_ATM
+    - net/sched: Retire dsmark qdisc
+    - [Config] updateconfigs for NET_SCH_DSMARK
+    - sched/rt: sysctl_sched_rr_timeslice show default timeslice after reset
+    - memcg: add refcnt for pcpu stock to avoid UAF problem in drain_all_stock()
+    - nilfs2: replace WARN_ONs for invalid DAT metadata block requests
+    - userfaultfd: fix mmap_changing checking in mfill_atomic_hugetlb
+    - sched/rt: Fix sysctl_sched_rr_timeslice intial value
+    - sched/rt: Disallow writing invalid values to sched_rt_period_us
+    - scsi: target: core: Add TMF to tmr_list handling
+    - dmaengine: shdma: increase size of 'dev_id'
+    - dmaengine: fsl-qdma: increase size of 'irq_name'
+    - wifi: cfg80211: fix missing interfaces when dumping
+    - wifi: mac80211: fix race condition on enabling fast-xmit
+    - fbdev: savage: Error out if pixclock equals zero
+    - fbdev: sis: Error out if pixclock equals zero
+    - ahci: asm1166: correct count of reported ports
+    - ahci: add 43-bit DMA address quirk for ASMedia ASM1061 controllers
+    - ext4: avoid allocating blocks from corrupted group in
+      ext4_mb_try_best_found()
+    - ext4: avoid allocating blocks from corrupted group in ext4_mb_find_by_goal()
+    - regulator: pwm-regulator: Add validity checks in continuous .get_voltage
+    - nvmet-tcp: fix nvme tcp ida memory leak
+    - ASoC: sunxi: sun4i-spdif: Add support for Allwinner H616
+    - netfilter: conntrack: check SCTP_CID_SHUTDOWN_ACK for vtag setting in
+      sctp_new
+    - nvmet-fc: abort command when there is no binding
+    - hwmon: (coretemp) Enlarge per package core count limit
+    - scsi: lpfc: Use unsigned type for num_sge
+    - firewire: core: send bus reset promptly on gap count error
+    - virtio-blk: Ensure no requests in virtqueues before deleting vqs.
+    - s390/qeth: Fix potential loss of L3-IP@ in case of network issues
+    - pmdomain: renesas: r8a77980-sysc: CR7 must be always on
+    - tcp: factor out __tcp_close() helper
+    - tcp: return EPOLLOUT from tcp_poll only when notsent_bytes is half the limit
+    - tcp: add annotations around sk->sk_shutdown accesses
+    - pinctrl: pinctrl-rockchip: Fix a bunch of kerneldoc misdemeanours
+    - pinctrl: rockchip: Fix refcount leak in rockchip_pinctrl_parse_groups
+    - spi: mt7621: Fix an error message in mt7621_spi_probe()
+    - net: bridge: clear bridge's private skb space on xmit
+    - selftests/bpf: Avoid running unprivileged tests with alignment requirements
+    - Revert "drm/sun4i: dsi: Change the start delay calculation"
+    - drm/amdgpu: Check for valid number of registers to read
+    - x86/alternatives: Disable KASAN in apply_alternatives()
+    - dm-integrity: don't modify bio's immutable bio_vec in integrity_metadata()
+    - iomap: Set all uptodate bits for an Uptodate page
+    - drm/amdgpu: Fix type of second parameter in trans_msg() callback
+    - arm64: dts: qcom: msm8916: Fix typo in pronto remoteproc node
+    - PCI: tegra: Fix reporting GPIO error value
+    - PCI: tegra: Fix OF node reference leak
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one error
+    - dm-crypt: don't modify the data when using authenticated encryption
+    - gtp: fix use-after-free and null-ptr-deref in gtp_genl_dump_pdp()
+    - PCI/MSI: Prevent MSI hardware interrupt number truncation
+    - l2tp: pass correct message length to ip6_append_data
+    - ARM: ep93xx: Add terminator to gpiod_lookup_table
+    - usb: cdns3: fixed memory use after free at cdns3_gadget_ep_disable()
+    - usb: cdns3: fix memory double free when handle zero packet
+    - usb: gadget: ncm: Avoid dropping datagrams of properly parsed NTBs
+    - usb: roles: don't get/set_role() when usb_role_switch is unregistered
+    - IB/hfi1: Fix a memleak in init_credit_return
+    - RDMA/bnxt_re: Return error for SRQ resize
+    - RDMA/srpt: Make debug output more detailed
+    - RDMA/srpt: fix function pointer cast warnings
+    - scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions
+    - bpf, scripts: Correct GPL license name
+    - scsi: jazz_esp: Only build if SCSI core is builtin
+    - nouveau: fix function cast warnings
+    - ipv4: properly combine dev_base_seq and ipv4.dev_addr_genid
+    - ipv6: properly combine dev_base_seq and ipv6.dev_addr_genid
+    - afs: Increase buffer size in afs_update_volume_status()
+    - ipv6: sr: fix possible use-after-free and null-ptr-deref
+    - packet: move from strlcpy with unused retval to strscpy
+    - s390: use the correct count for __iowrite64_copy()
+    - tls: rx: jump to a more appropriate label
+    - tls: rx: drop pointless else after goto
+    - tls: stop recv() if initial process_rx_list gave us non-DATA
+    - netfilter: nf_tables: set dormant flag on hook register failure
+    - drm/syncobj: make lockdep complain on WAIT_FOR_SUBMIT v3
+    - drm/syncobj: call drm_syncobj_fence_add_wait when WAIT_AVAILABLE flag is set
+    - fs/aio: Restrict kiocb_set_cancel_fn() to I/O submitted via libaio
+    - scripts/bpf: Fix xdp_md forward declaration typo
+    - Linux 5.4.270
+  * CVE-2023-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+  * CVE-2021-47070
+    - uio: uio_hv_generic: use devm_kzalloc() for private data alloc
+    - uio_hv_generic: Fix another memory leak in error handling paths
+  * CVE-2024-26622
+    - tomoyo: fix UAF write bug in tomoyo_write_control()
+
+ -- Portia Stephens <portia.stephens@canonical.com>  Mon, 27 May 2024 11:13:00 +1000
+
+linux-ein (5.4.0-1054.62) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1054.62 -proposed tracker (LP: #2063658)
+
+  [ Ubuntu: 5.4.0-182.202 ]
+
+  * focal/linux: 5.4.0-182.202 -proposed tracker (LP: #2063685)
+  * CVE-2023-52530
+    - wifi: mac80211: fix potential key use-after-free
+  * 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-47233
+    - wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 08 May 2024 23:15:07 +0800
+
+linux-ein (5.4.0-1053.61) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1053.61 -proposed tracker (LP: #2063868)
+
+  * system hang after updating kernel (LP#2063553)
+    - SAUCE: crypto: arm64: use simd_skcipher_create() when registering aes
+      internal algs
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 02 May 2024 17:57:37 +0800
+
+linux-ein (5.4.0-1052.60) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1052.60 -proposed tracker (LP: #2059523)
+
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948)
+    - [Config] ein: updateconfigs for MFD_TI_AM335X_TSCADC
+
+  [ Ubuntu: 5.4.0-181.201 ]
+
+  * focal/linux: 5.4.0-181.201 -proposed tracker (LP: #2059549)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+  * Drop fips-checks script from trees (LP: #2055083)
+    - [Packaging] Remove fips-checks script
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948)
+    - PCI: mediatek: Clear interrupt status before dispatching handler
+    - include/linux/units.h: add helpers for kelvin to/from Celsius conversion
+    - units: Add Watt units
+    - units: change from 'L' to 'UL'
+    - units: add the HZ macros
+    - serial: sc16is7xx: set safe default SPI clock frequency
+    - spi: introduce SPI_MODE_X_MASK macro
+    - serial: sc16is7xx: add check for unsupported SPI modes during probe
+    - ext4: allow for the last group to be marked as trimmed
+    - crypto: api - Disallow identical driver names
+    - PM: hibernate: Enforce ordering during image compression/decompression
+    - hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+    - rpmsg: virtio: Free driver_override when rpmsg_remove()
+    - parisc/firmware: Fix F-extend for PDC addresses
+    - arm64: dts: qcom: sdm845: fix USB wakeup interrupt types
+    - mmc: core: Use mrq.sbc in close-ended ffu
+    - nouveau/vmm: don't set addr on the fail path to avoid warning
+    - ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
+    - rename(): fix the locking of subdirectories
+    - block: Remove special-casing of compound pages
+    - mtd: spinand: macronix: Fix MX35LFxGE4AD page size
+    - fs: add mode_strip_sgid() helper
+    - fs: move S_ISGID stripping into the vfs_*() helpers
+    - powerpc: Use always instead of always-y in for crtsavres.o
+    - x86/CPU/AMD: Fix disabling XSAVES on AMD family 0x17 due to erratum
+    - net/smc: fix illegal rmb_desc access in SMC-D connection dump
+    - vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
+    - llc: make llc_ui_sendmsg() more robust against bonding changes
+    - llc: Drop support for ETH_P_TR_802_2.
+    - net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
+    - tracing: Ensure visibility when inserting an element into tracing_map
+    - afs: Hide silly-rename files from userspace
+    - tcp: Add memory barrier to tcp_push()
+    - netlink: fix potential sleeping issue in mqueue_flush_file
+    - net/mlx5: DR, Use the right GVMI number for drop action
+    - net/mlx5: Use kfree(ft->g) in arfs_create_groups()
+    - net/mlx5e: fix a double-free in arfs_create_groups
+    - netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
+    - netfilter: nf_tables: validate NFPROTO_* family
+    - fjes: fix memleaks in fjes_hw_setup
+    - net: fec: fix the unhandled context fault from smmu
+    - btrfs: ref-verify: free ref cache before clearing mount opt
+    - btrfs: tree-checker: fix inline ref size in error messages
+    - btrfs: don't warn if discard range is not aligned to sector
+    - btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
+    - rbd: don't move requests to the running list on errors
+    - gpiolib: acpi: Ignore touchpad wakeup on GPD G1619-04
+    - drm: Don't unref the same fb many times by mistake due to deadlock handling
+    - drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking
+    - drm/bridge: nxp-ptn3460: simplify some error checking
+    - drm/exynos: fix accidental on-stack copy of exynos_drm_plane
+    - drm/exynos: gsc: minor fix for loop iteration in gsc_runtime_resume
+    - gpio: eic-sprd: Clear interrupt after set the interrupt type
+    - spi: bcm-qspi: fix SFDP BFPT read by usig mspi read
+    - mips: Call lose_fpu(0) before initializing fcr31 in mips_set_personality_nan
+    - tick/sched: Preserve number of idle sleeps across CPU hotplug events
+    - x86/entry/ia32: Ensure s32 is sign extended to s64
+    - powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+    - powerpc: Fix build error due to is_valid_bugaddr()
+    - powerpc/mm: Fix build failures due to arch_reserved_kernel_pages()
+    - powerpc: pmd_move_must_withdraw() is only needed for
+      CONFIG_TRANSPARENT_HUGEPAGE
+    - powerpc/lib: Validate size for vector operations
+    - x86/mce: Mark fatal MCE's page as poison to avoid panic in the kdump kernel
+    - perf/core: Fix narrow startup race when creating the perf nr_addr_filters
+      sysfs file
+    - regulator: core: Only increment use_count when enable_count changes
+    - audit: Send netlink ACK before setting connection in auditd_set
+    - ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
+    - PNP: ACPI: fix fortify warning
+    - ACPI: extlog: fix NULL pointer dereference check
+    - FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+    - jfs: fix slab-out-of-bounds Read in dtSearch
+    - jfs: fix array-index-out-of-bounds in dbAdjTree
+    - pstore/ram: Fix crash when setting number of cpus to an odd number
+    - crypto: stm32/crc32 - fix parsing list of devices
+    - afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
+    - rxrpc_find_service_conn_rcu: fix the usage of read_seqbegin_or_lock()
+    - jfs: fix array-index-out-of-bounds in diNewExt
+    - s390/ptrace: handle setting of fpc register correctly
+    - KVM: s390: fix setting of fpc register
+    - SUNRPC: Fix a suspicious RCU usage warning
+    - ecryptfs: Reject casefold directory inodes
+    - ext4: fix inconsistent between segment fstrim and full fstrim
+    - ext4: unify the type of flexbg_size to unsigned int
+    - ext4: remove unnecessary check from alloc_flex_gd()
+    - ext4: avoid online resizing failures due to oversized flex bg
+    - wifi: rt2x00: restart beacon queue when hardware reset
+    - selftests/bpf: satisfy compiler by having explicit return in btf test
+    - selftests/bpf: Fix pyperf180 compilation failure with clang18
+    - scsi: lpfc: Fix possible file string name overflow when updating firmware
+    - PCI: Add no PM reset quirk for NVIDIA Spectrum devices
+    - bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk
+    - ARM: dts: imx7d: Fix coresight funnel ports
+    - ARM: dts: imx7s: Fix lcdif compatible
+    - ARM: dts: imx7s: Fix nand-controller #size-cells
+    - wifi: ath9k: Fix potential array-index-out-of-bounds read in
+      ath9k_htc_txstatus()
+    - bpf: Add map and need_defer parameters to .map_fd_put_ptr()
+    - scsi: libfc: Don't schedule abort twice
+    - scsi: libfc: Fix up timeout error in fc_fcp_rec_error()
+    - ARM: dts: rockchip: fix rk3036 hdmi ports node
+    - ARM: dts: imx25/27-eukrea: Fix RTC node name
+    - ARM: dts: imx: Use flash@0,0 pattern
+    - ARM: dts: imx27: Fix sram node
+    - ARM: dts: imx1: Fix sram node
+    - ARM: dts: imx25/27: Pass timing0
+    - ARM: dts: imx27-apf27dev: Fix LED name
+    - ARM: dts: imx23-sansa: Use preferred i2c-gpios properties
+    - ARM: dts: imx23/28: Fix the DMA controller node name
+    - block: prevent an integer overflow in bvec_try_merge_hw_page
+    - md: Whenassemble the array, consult the superblock of the freshest device
+    - arm64: dts: qcom: msm8996: Fix 'in-ports' is a required property
+    - arm64: dts: qcom: msm8998: Fix 'out-ports' is a required property
+    - wifi: rtl8xxxu: Add additional USB IDs for RTL8192EU devices
+    - wifi: rtlwifi: rtl8723{be,ae}: using calculate_bit_shift()
+    - wifi: cfg80211: free beacon_ies when overridden from hidden BSS
+    - f2fs: fix to check return value of f2fs_reserve_new_block()
+    - ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument
+    - fast_dput(): handle underflows gracefully
+    - RDMA/IPoIB: Fix error code return in ipoib_mcast_join
+    - drm/drm_file: fix use of uninitialized variable
+    - drm/framebuffer: Fix use of uninitialized variable
+    - drm/mipi-dsi: Fix detach call without attach
+    - media: stk1160: Fixed high volume of stk1160_dbg messages
+    - media: rockchip: rga: fix swizzling for RGB formats
+    - PCI: add INTEL_HDA_ARL to pci_ids.h
+    - ALSA: hda: Intel: add HDA_ARL PCI ID support
+    - drm/exynos: Call drm_atomic_helper_shutdown() at shutdown/unbind time
+    - IB/ipoib: Fix mcast list locking
+    - media: ddbridge: fix an error code problem in ddb_probe
+    - drm/msm/dpu: Ratelimit framedone timeout msgs
+    - clk: hi3620: Fix memory leak in hi3620_mmc_clk_init()
+    - clk: mmp: pxa168: Fix memory leak in pxa168_clk_init()
+    - drm/amdgpu: Let KFD sync with VM fences
+    - drm/amdgpu: Drop 'fence' check in 'to_amdgpu_amdkfd_fence()'
+    - leds: trigger: panic: Don't register panic notifier if creating the trigger
+      failed
+    - um: Fix naming clash between UML and scheduler
+    - um: Don't use vfprintf() for os_info()
+    - um: net: Fix return type of uml_net_start_xmit()
+    - i3c: master: cdns: Update maximum prescaler value for i2c clock
+    - mfd: ti_am335x_tscadc: Fix TI SoC dependencies
+    - [Config] updateconfigs for MFD_TI_AM335X_TSCADC
+    - PCI: Only override AMD USB controller if required
+    - PCI: switchtec: Fix stdev_release() crash after surprise hot remove
+    - usb: hub: Replace hardcoded quirk value with BIT() macro
+    - fs/kernfs/dir: obey S_ISGID
+    - PCI/AER: Decode Requester ID when no error info found
+    - libsubcmd: Fix memory leak in uniq()
+    - virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region
+      of size 10" warnings
+    - blk-mq: fix IO hang from sbitmap wakeup race
+    - ceph: fix deadlock or deadcode of misusing dget()
+    - drm/amdgpu: Release 'adev->pm.fw' before return in
+      'amdgpu_device_need_post()'
+    - perf: Fix the nr_addr_filters fix
+    - wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
+    - scsi: isci: Fix an error code problem in isci_io_request_build()
+    - net: remove unneeded break
+    - ixgbe: Remove non-inclusive language
+    - ixgbe: Refactor returning internal error codes
+    - ixgbe: Refactor overtemp event handling
+    - ixgbe: Fix an error handling path in ixgbe_read_iosf_sb_reg_x550()
+    - ipv6: Ensure natural alignment of const ipv6 loopback and router addresses
+    - llc: call sock_orphan() at release time
+    - netfilter: nf_log: replace BUG_ON by WARN_ON_ONCE when putting logger
+    - netfilter: nft_ct: sanitize layer 3 and 4 protocol number in custom
+      expectations
+    - net: ipv4: fix a memleak in ip_setup_cork
+    - af_unix: fix lockdep positive in sk_diag_dump_icons()
+    - SAUCE: Sync apparmor copy of af_unix.c
+    - net: sysfs: Fix /sys/class/net/<iface> path
+    - HID: apple: Add support for the 2021 Magic Keyboard
+    - HID: apple: Swap the Fn and Left Control keys on Apple keyboards
+    - HID: apple: Add 2021 magic keyboard FN key mapping
+    - bonding: remove print in bond_verify_device_path
+    - dmaengine: fsl-qdma: Fix a memory leak related to the status queue DMA
+    - dmaengine: fsl-qdma: Fix a memory leak related to the queue command DMA
+    - phy: renesas: rcar-gen3-usb2: Fix returning wrong error code
+    - dmaengine: fix is_slave_direction() return false when DMA_DEV_TO_DEV
+    - phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+    - net: stmmac: xgmac: fix handling of DPP safety error for DMA channels
+    - selftests: net: avoid just another constant wait
+    - atm: idt77252: fix a memleak in open_card_ubr0
+    - hwmon: (aspeed-pwm-tacho) mutex for tach reading
+    - hwmon: (coretemp) Fix out-of-bounds memory access
+    - hwmon: (coretemp) Fix bogus core_id to attr name mapping
+    - inet: read sk->sk_family once in inet_recv_error()
+    - rxrpc: Fix response to PING RESPONSE ACKs to a dead call
+    - tipc: Check the bearer type before calling tipc_udp_nl_bearer_add()
+    - ppp_async: limit MRU to 64K
+    - netfilter: nft_compat: reject unused compat flag
+    - netfilter: nft_compat: restrict match/target protocol to u16
+    - netfilter: nft_ct: reject direction for ct id
+    - net/af_iucv: clean up a try_then_request_module()
+    - USB: serial: qcserial: add new usb-id for Dell Wireless DW5826e
+    - USB: serial: option: add Fibocom FM101-GL variant
+    - USB: serial: cp210x: add ID for IMST iM871A-USB
+    - hrtimer: Report offline hrtimer enqueue
+    - Input: atkbd - skip ATKBD_CMD_SETLEDS when skipping ATKBD_CMD_GETID
+    - net: stmmac: xgmac: use #define for string constants
+    - net: stmmac: xgmac: fix a typo of register name in DPP safety handling
+    - btrfs: forbid creating subvol qgroups
+    - btrfs: forbid deleting live subvol qgroup
+    - btrfs: send: return EOPNOTSUPP on unknown flags
+    - of: unittest: add overlay gpio test to catch gpio hog problem
+    - of: unittest: Fix compile in the non-dynamic case
+    - spi: ppc4xx: Drop write-only variable
+    - ASoC: rt5645: Fix deadlock in rt5645_jack_detect_work()
+    - MIPS: Add 'memory' clobber to csum_ipv6_magic() inline assembler
+    - i40e: Fix waiting for queues of all VSIs to be disabled
+    - tracing/trigger: Fix to return error if failed to alloc snapshot
+    - mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+    - HID: wacom: generic: Avoid reporting a serial of '0' to userspace
+    - HID: wacom: Do not register input devices until after hid_hw_start
+    - USB: hub: check for alternate port before enabling A_ALT_HNP_SUPPORT
+    - usb: f_mass_storage: forbid async queue when shutdown happen
+    - i2c: i801: Remove i801_set_block_buffer_mode
+    - i2c: i801: Fix block process call transactions
+    - scsi: Revert "scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock"
+    - firewire: core: correct documentation of fw_csr_string() kernel API
+    - kbuild: Fix changing ELF file type for output of gen_btf for big endian
+    - nfc: nci: free rx_data_reassembly skb on NCI device cleanup
+    - xen-netback: properly sync TX responses
+    - ALSA: hda/realtek: Enable headset mic on Vaio VJFE-ADL
+    - binder: signal epoll threads of self-work
+    - misc: fastrpc: Mark all sessions as invalid in cb_remove
+    - ext4: fix double-free of blocks due to wrong extents moved_len
+    - tracing: Fix wasted memory in saved_cmdlines logic
+    - staging: iio: ad5933: fix type mismatch regression
+    - iio: magnetometer: rm3100: add boundary check for the value read from
+      RM3100_REG_TMRC
+    - ring-buffer: Clean ring_buffer_poll_wait() error return
+    - serial: max310x: set default value when reading clock ready bit
+    - serial: max310x: improve crystal stable clock detection
+    - x86/Kconfig: Transmeta Crusoe is CPU family 5, not 6
+    - x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
+    - mmc: slot-gpio: Allow non-sleeping GPIO ro
+    - ALSA: hda/conexant: Add quirk for SWS JS201D
+    - nilfs2: fix data corruption in dsync block recovery for small block sizes
+    - nilfs2: fix hang in nilfs_lookup_dirty_data_buffers()
+    - nfp: use correct macro for LengthSelect in BAR config
+    - nfp: flower: prevent re-adding mac index for bonded port
+    - irqchip/irq-brcmstb-l2: Add write memory barrier before exit
+    - can: j1939: Fix UAF in j1939_sk_match_filter during
+      setsockopt(SO_J1939_FILTER)
+    - pmdomain: core: Move the unused cleanup to a _sync initcall
+    - tracing: Inform kmemleak of saved_cmdlines allocation
+    - Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d"
+    - bus: moxtet: Add spi device table
+    - arch, mm: remove stale mentions of DISCONIGMEM
+    - mips: Fix max_mapnr being uninitialized on early stages
+    - KVM: arm64: vgic-its: Avoid potential UAF in LPI translation cache
+    - netfilter: ipset: fix performance regression in swap operation
+    - netfilter: ipset: Missing gc cancellations fixed
+    - net: prevent mss overflow in skb_segment()
+    - sched/membarrier: reduce the ability to hammer on sys_membarrier
+    - nilfs2: fix potential bug in end_buffer_async_write
+    - PM: runtime: add devm_pm_runtime_enable helper
+    - PM: runtime: Have devm_pm_runtime_enable() handle
+      pm_runtime_dont_use_autosuspend()
+    - drm/msm/dsi: Enable runtime PM
+    - lsm: new security_file_ioctl_compat() hook
+    - Revert "Revert "mtd: rawnand: gpmi: Fix setting busy timeout setting""
+    - net: bcmgenet: Fix EEE implementation
+    - of: unittest: fix EXPECT text for gpio hog errors
+    - of: gpio unittest kfree() wrong object
+    - Linux 5.4.269
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948) //
+    CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+  * CVE-2023-52600
+    - jfs: fix uaf in jfs_evict_inode
+  * CVE-2023-24023
+    - Bluetooth: Add more enc key size check
+  * CVE-2024-26581
+    - netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
+    - netfilter: nft_set_rbtree: skip end interval element from gc
+  * CVE-2024-26589
+    - bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 19 Apr 2024 18:42:55 +0800
+
+linux-ein (5.4.0-1051.59) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1051.59 -proposed tracker (LP: #2059607)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+
+  [ Ubuntu: 5.4.0-177.197 ]
+
+  * focal/linux: 5.4.0-177.197 -proposed tracker (LP: #2059633)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop getabis data
+  * Remove getabis scripts (LP: #2059143)
+    - [Packaging] Remove getabis
+  * CVE-2023-24023
+    - Bluetooth: Add more enc key size check
+  * CVE-2023-52600
+    - jfs: fix uaf in jfs_evict_inode
+  * Focal update: v5.4.269 upstream stable release (LP: #2058948) //
+    CVE-2023-52603
+    - UBSAN: array-index-out-of-bounds in dtSplitRoot
+  * CVE-2024-26581
+    - netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
+    - netfilter: nft_set_rbtree: skip end interval element from gc
+  * CVE-2024-26589
+    - bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+
+  [ Ubuntu: 5.4.0-176.196 ]
+
+  * focal/linux: 5.4.0-176.196 -proposed tracker (LP: #2058756)
+  * Problems with HVCS and hotplugging (LP: #2056373)
+    - powerpc/pseries: Fix bad drc_index_start value parsing of drc-info entry
+    - powerpc/pseries: Fix of_read_drc_info_cell() to point at next record
+    - hvcs: Fix hvcs port reference counting
+    - hvcs: Use dev_groups to manage hvcs device attributes
+    - hvcs: Use driver groups to manage driver attributes
+    - hvcs: Get reference to tty in remove
+    - hvcs: Use vhangup in hotplug remove
+    - hvcs: Synchronize hotplug remove with port free
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 11 Apr 2024 21:42:07 +0800
+
+linux-ein (5.4.0-1050.58) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1050.58 -proposed tracker (LP: #2055658)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+    - debian.ein/dkms-versions -- update from kernel-versions (main/2024.03.04)
+
+  * Focal update: v5.4.268 upstream stable release (LP: #2055075)
+    - [Config] ein: Update annotations for CONFIG_MMC_SDHCI_OMAP
+
+  * Focal update: v5.4.267 upstream stable release (LP: #2054406)
+    - [Config] ein: Update annotations for CONFIG_SND_MESON_CODEC_GLUE
+
+  [ Ubuntu: 5.4.0-175.195 ]
+
+  * focal/linux: 5.4.0-175.195 -proposed tracker (LP: #2055684)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] drop ABI data
+    - [Packaging] update annotations scripts
+    - debian.master/dkms-versions -- update from kernel-versions (main/2024.03.04)
+  * 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
+  * Cranky update-dkms-versions rollout (LP: #2055685)
+    - [Packaging] remove update-dkms-versions
+    - Move debian/dkms-versions to debian.master/dkms-versions
+    - [Packaging] Replace debian/dkms-versions with $(DEBIAN)/dkms-versions
+    - [Packaging] remove update-version-dkms
+  * linux-tools-common: man page of usbip[d] is misplaced (LP: #2054094)
+    - [Packaging] rules: Put usbip manpages in the correct directory
+  * CVE-2024-23851
+    - dm ioctl: log an error if the ioctl structure is corrupted
+    - dm: limit the number of targets and parameter size area
+  * Focal update: v5.4.268 upstream stable release (LP: #2055075)
+    - f2fs: explicitly null-terminate the xattr list
+    - pinctrl: lochnagar: Don't build on MIPS
+    - ALSA: hda - Fix speaker and headset mic pin config for CHUWI CoreBook XPro
+    - ASoC: Intel: Skylake: Fix mem leak in few functions
+    - ASoC: nau8822: Fix incorrect type in assignment and cast to restricted
+      __be16
+    - ASoC: Intel: Skylake: mem leak in skl register function
+    - ASoC: cs43130: Fix the position of const qualifier
+    - ASoC: cs43130: Fix incorrect frame delay configuration
+    - ASoC: rt5650: add mutex to avoid the jack detection failure
+    - nouveau/tu102: flush all pdbs on vmm flush
+    - net/tg3: fix race condition in tg3_reset_task()
+    - ASoC: da7219: Support low DC impedance headset
+    - nvme: introduce helper function to get ctrl state
+    - drm/exynos: fix a potential error pointer dereference
+    - drm/exynos: fix a wrong error checking
+    - clk: rockchip: rk3128: Fix HCLK_OTG gate register
+    - jbd2: correct the printing of write_flags in jbd2_write_superblock()
+    - drm/crtc: Fix uninit-value bug in drm_mode_setcrtc
+    - neighbour: Don't let neigh_forced_gc() disable preemption for long
+    - tracing: Have large events show up as '[LINE TOO BIG]' instead of nothing
+    - tracing: Add size check when printing trace_marker output
+    - ring-buffer: Do not record in NMI if the arch does not support cmpxchg in
+      NMI
+    - reset: hisilicon: hi6220: fix Wvoid-pointer-to-enum-cast warning
+    - Input: atkbd - skip ATKBD_CMD_GETID in translated mode
+    - Input: i8042 - add nomux quirk for Acer P459-G2-M
+    - s390/scm: fix virtual vs physical address confusion
+    - ARC: fix spare error
+    - Input: xpad - add Razer Wolverine V2 support
+    - ARM: sun9i: smp: fix return code check of of_property_match_string
+    - drm/crtc: fix uninitialized variable use
+    - ACPI: resource: Add another DMI match for the TongFang GMxXGxx
+    - binder: use EPOLLERR from eventpoll.h
+    - binder: fix trivial typo of binder_free_buf_locked()
+    - binder: fix comment on binder_alloc_new_buf() return value
+    - uio: Fix use-after-free in uio_open
+    - parport: parport_serial: Add Brainboxes BAR details
+    - parport: parport_serial: Add Brainboxes device IDs and geometry
+    - coresight: etm4x: Fix width of CCITMIN field
+    - x86/lib: Fix overflow when counting digits
+    - EDAC/thunderx: Fix possible out-of-bounds string access
+    - powerpc: add crtsavres.o to always-y instead of extra-y
+    - powerpc/44x: select I2C for CURRITUCK
+    - powerpc/pseries/memhotplug: Quieten some DLPAR operations
+    - powerpc/pseries/memhp: Fix access beyond end of drmem array
+    - selftests/powerpc: Fix error handling in FPU/VMX preemption tests
+    - powerpc/powernv: Add a null pointer check to scom_debug_init_one()
+    - powerpc/powernv: Add a null pointer check in opal_event_init()
+    - powerpc/powernv: Add a null pointer check in opal_powercap_init()
+    - powerpc/imc-pmu: Add a null pointer check in update_events_in_group()
+    - mtd: rawnand: Increment IFC_TIMEOUT_MSECS for nand controller response
+    - ACPI: video: check for error while searching for backlight device parent
+    - ACPI: LPIT: Avoid u32 multiplication overflow
+    - net: netlabel: Fix kerneldoc warnings
+    - netlabel: remove unused parameter in netlbl_netlink_auditinfo()
+    - calipso: fix memory leak in netlbl_calipso_add_pass()
+    - spi: sh-msiof: Enforce fixed DTDL for R-Car H3
+    - mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+    - selinux: Fix error priority for bind with AF_UNSPEC on PF_INET6 socket
+    - crypto: virtio - Handle dataq logic with tasklet
+    - crypto: virtio - don't use 'default m'
+    - virtio_crypto: Introduce VIRTIO_CRYPTO_NOSPC
+    - crypto: ccp - fix memleak in ccp_init_dm_workarea
+    - crypto: af_alg - Disallow multiple in-flight AIO requests
+    - crypto: sahara - remove FLAGS_NEW_KEY logic
+    - crypto: sahara - fix ahash selftest failure
+    - crypto: sahara - fix processing requests with cryptlen < sg->length
+    - crypto: sahara - fix error handling in sahara_hw_descriptor_create()
+    - pstore: ram_core: fix possible overflow in persistent_ram_init_ecc()
+    - gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
+    - crypto: virtio - Wait for tasklet to complete on device remove
+    - crypto: sahara - fix ahash reqsize
+    - crypto: sahara - fix wait_for_completion_timeout() error handling
+    - crypto: sahara - improve error handling in sahara_sha_process()
+    - crypto: sahara - fix processing hash requests with req->nbytes < sg->length
+    - crypto: sahara - do not resize req->src when doing hash operations
+    - crypto: scomp - fix req->dst buffer overflow
+    - blocklayoutdriver: Fix reference leak of pnfs_device_node
+    - NFSv4.1/pnfs: Ensure we handle the error NFS4ERR_RETURNCONFLICT
+    - wifi: rtw88: fix RX filter in FIF_ALLMULTI flag
+    - bpf, lpm: Fix check prefixlen before walking trie
+    - wifi: libertas: stop selecting wext
+    - ARM: dts: qcom: apq8064: correct XOADC register address
+    - ncsi: internal.h: Fix a spello
+    - net/ncsi: Fix netlink major/minor version numbers
+    - firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create()
+    - rtlwifi: Use ffs in <foo>_phy_calculate_bit_shift
+    - wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior
+    - scsi: fnic: Return error if vmalloc() failed
+    - arm64: dts: qcom: sdm845-db845c: correct LED panic indicator
+    - scsi: hisi_sas: Replace with standard error code return value
+    - selftests/net: fix grep checking for fib_nexthop_multiprefix
+    - virtio/vsock: fix logic which reduces credit update messages
+    - dma-mapping: clear dev->dma_mem to NULL after freeing it
+    - wifi: rtlwifi: add calculate_bit_shift()
+    - wifi: rtlwifi: rtl8188ee: phy: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192c: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192cu: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ce: using calculate_bit_shift()
+    - rtlwifi: rtl8192de: make arrays static const, makes object smaller
+    - wifi: rtlwifi: rtl8192de: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192ee: using calculate_bit_shift()
+    - wifi: rtlwifi: rtl8192se: using calculate_bit_shift()
+    - netfilter: nf_tables: mark newset as dead on transaction abort
+    - Bluetooth: Fix bogus check for re-auth no supported with non-ssp
+    - Bluetooth: btmtkuart: fix recv_buf() return value
+    - ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+    - ARM: davinci: always select CONFIG_CPU_ARM926T
+    - RDMA/usnic: Silence uninitialized symbol smatch warnings
+    - media: pvrusb2: fix use after free on context disconnection
+    - drm/bridge: Fix typo in post_disable() description
+    - f2fs: fix to avoid dirent corruption
+    - drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg()
+    - drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check()
+    - drm/radeon: check return value of radeon_ring_lock()
+    - ASoC: cs35l33: Fix GPIO name and drop legacy include
+    - ASoC: cs35l34: Fix GPIO name and drop legacy include
+    - drm/msm/mdp4: flush vblank event on disable
+    - drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks
+    - drm/drv: propagate errors from drm_modeset_register_all()
+    - drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+    - drm/radeon/dpm: fix a memleak in sumo_parse_power_table
+    - drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table
+    - drm/bridge: tc358767: Fix return value on error case
+    - media: cx231xx: fix a memleak in cx231xx_init_isoc
+    - media: dvbdev: drop refcount on error path in dvb_device_open()
+    - drm/amdgpu/debugfs: fix error code when smc register accessors are NULL
+    - drm/amd/pm: fix a double-free in si_dpm_init
+    - drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+    - gpu/drm/radeon: fix two memleaks in radeon_vm_init
+    - drivers: clk: zynqmp: calculate closest mux rate
+    - watchdog: set cdev owner before adding
+    - watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO
+    - watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling
+    - clk: si5341: fix an error code problem in si5341_output_clk_set_rate
+    - mmc: sdhci_omap: Fix TI SoC dependencies
+    - [Config] update annotations for CONFIG_MMC_SDHCI_OMAP
+    - [Config] remove sdhci-omap module for arm64/ppc64el
+    - of: Fix double free in of_parse_phandle_with_args_map
+    - of: unittest: Fix of_count_phandle_with_args() expected value message
+    - binder: fix async space check for 0-sized buffers
+    - binder: fix use-after-free in shinker's callback
+    - Input: atkbd - use ab83 as id when skipping the getid command
+    - Revert "ASoC: atmel: Remove system clock tree configuration for
+      at91sam9g20ek"
+    - binder: fix race between mmput() and do_exit()
+    - binder: fix unused alloc->free_async_space
+    - tick-sched: Fix idle and iowait sleeptime accounting vs CPU hotplug
+    - usb: phy: mxs: remove CONFIG_USB_OTG condition for mxs_phy_is_otg_host()
+    - usb: dwc: ep0: Update request status in dwc3_ep0_stall_restart
+    - Revert "usb: dwc3: Soft reset phy on probe for host"
+    - Revert "usb: dwc3: don't reset device side if dwc3 was configured as host-
+      only"
+    - usb: chipidea: wait controller resume finished for wakeup irq
+    - Revert "usb: typec: class: fix typec_altmode_put_partner to put plugs"
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - usb: mon: Fix atomicity violation in mon_bin_vma_fault
+    - ALSA: oxygen: Fix right channel of capture volume mixer
+    - fbdev: flush deferred work in fb_deferred_io_fsync()
+    - rootfs: Fix support for rootfstype= when root= is given
+    - wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code
+    - wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors
+    - wifi: mwifiex: configure BSSID consistently when starting AP
+    - x86/kvm: Do not try to disable kvmclock if it was not enabled
+    - HID: wacom: Correct behavior when processing some confidence == false
+      touches
+    - mips: Fix incorrect max_low_pfn adjustment
+    - MIPS: Alchemy: Fix an out-of-bound access in db1200_dev_setup()
+    - MIPS: Alchemy: Fix an out-of-bound access in db1550_dev_setup()
+    - serial: 8250: omap: Don't skip resource freeing if
+      pm_runtime_resume_and_get() failed
+    - acpi: property: Let args be NULL in __acpi_node_get_property_reference
+    - software node: Let args be NULL in software_node_get_reference_args
+    - perf genelf: Set ELF program header addresses properly
+    - nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length
+    - nvmet-tcp: fix a crash in nvmet_req_complete()
+    - perf env: Add perf_env__numa_node()
+    - perf record: Move sb_evlist to 'struct record'
+    - perf top: Move sb_evlist to 'struct perf_top'
+    - perf bpf: Decouple creating the evlist from adding the SB event
+    - perf env: Avoid recursively taking env->bpf_progs.lock
+    - apparmor: avoid crash when parsed profile name is empty
+    - serial: imx: Correct clock error message in function probe()
+    - nvmet-tcp: Fix the H2C expected PDU len calculation
+    - PCI: keystone: Fix race condition when initializing PHYs
+    - s390/pci: fix max size calculation in zpci_memcpy_toio()
+    - net: qualcomm: rmnet: fix global oob in rmnet_policy
+    - net: phy: micrel: populate .soft_reset for KSZ9131
+    - net: ravb: Fix dma_addr_t truncation in error case
+    - net: dsa: vsc73xx: Add null pointer check to vsc73xx_gpio_probe
+    - netfilter: nf_tables: skip dead set elements in netlink dump
+    - ipvs: avoid stat macros calls from preemptible context
+    - kdb: Censor attempts to set PROMPT without ENABLE_MEM_READ
+    - kdb: Fix a potential buffer overflow in kdb_local()
+    - mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure
+    - i2c: s3c24xx: fix read transfers in polling mode
+    - i2c: s3c24xx: fix transferring more than one message in polling mode
+    - perf top: Skip side-band event setup if HAVE_LIBBPF_SUPPORT is not set
+    - arm64: dts: armada-3720-turris-mox: set irq type for RTC
+    - Linux 5.4.268
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+  * Focal update: v5.4.267 upstream stable release (LP: #2054406)
+    - nfc: llcp_core: Hold a ref to llcp_local->dev when holding a ref to
+      llcp_local
+    - i40e: Fix filter input checks to prevent config with invalid values
+    - net: sched: em_text: fix possible memory leak in em_text_destroy()
+    - can: raw: add support for SO_TXTIME/SCM_TXTIME
+    - can: raw: add support for SO_MARK
+    - net-timestamp: extend SOF_TIMESTAMPING_OPT_ID to HW timestamps
+    - ARM: sun9i: smp: Fix array-index-out-of-bounds read in sunxi_mc_smp_init
+    - net: bcmgenet: Fix FCS generation for fragmented skbuffs
+    - net: Save and restore msg_namelen in sock_sendmsg
+    - i40e: fix use-after-free in i40e_aqc_add_filters()
+    - ASoC: meson: g12a: extract codec-to-codec utils
+    - [Config] Update annotations for CONFIG_SND_MESON_CODEC_GLUE
+    - ASoC: meson: g12a-tohdmitx: Validate written enum values
+    - ASoC: meson: g12a-tohdmitx: Fix event generation for S/PDIF mux
+    - i40e: Restore VF MSI-X state during PCI reset
+    - net/qla3xxx: switch from 'pci_' to 'dma_' API
+    - net/qla3xxx: fix potential memleak in ql_alloc_buffer_queues
+    - asix: Add check for usbnet_get_endpoints
+    - bnxt_en: Remove mis-applied code from bnxt_cfg_ntp_filters()
+    - net: Implement missing SO_TIMESTAMPING_NEW cmsg support
+    - mm/memory-failure: check the mapcount of the precise page
+    - firewire: ohci: suppress unexpected system reboot in AMD Ryzen machines and
+      ASM108x/VT630x PCIe cards
+    - i2c: core: Fix atomic xfer check for non-preempt config
+    - mm: fix unmap_mapping_range high bits shift bug
+    - mmc: rpmb: fixes pause retune on all RPMB partitions.
+    - mmc: core: Cancel delayed work before releasing host
+    - mmc: sdhci-sprd: Fix eMMC init failure after hw reset
+    - ath10k: Wait until copy complete is actually done before completing
+    - ath10k: Add interrupt summary based CE processing
+    - ath10k: Keep track of which interrupts fired, don't poll them
+    - ath10k: Get rid of "per_ce_irq" hw param
+    - PCI: Extract ATS disabling to a helper function
+    - PCI: Disable ATS for specific Intel IPU E2000 devices
+    - net/dst: use a smaller percpu_counter batch for dst entries accounting
+    - ipv6: make ip6_rt_gc_expire an atomic_t
+    - ipv6: remove max_size check inline with ipv4
+    - ASoC: meson: codec-glue: fix pcm format cast warning
+    - Linux 5.4.267
+  * CVE-2023-23000
+    - phy: tegra: xusb: Fix return value of tegra_xusb_find_port_node function
+  * CVE-2023-23004
+    - malidp: Fix NULL vs IS_ERR() checking
+  * CVE-2023-46838
+    - xen-netback: don't produce zero-size SKB frags
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+  * Focal update: v5.4.266 upstream stable release (LP: #2051655)
+    - ALSA: hda/realtek: Enable headset on Lenovo M90 Gen5
+    - ksmbd: fix wrong name of SMB2_CREATE_ALLOCATION_SIZE
+    - ARM: OMAP2+: Fix null pointer dereference and memory leak in
+      omap_soc_device_init
+    - reset: Fix crash when freeing non-existent optional resets
+    - s390/vx: fix save/restore of fpu kernel context
+    - wifi: mac80211: mesh_plink: fix matches_local logic
+    - net/mlx5: improve some comments
+    - net/mlx5: Fix fw tracer first block check
+    - net/mlx5e: Correct snprintf truncation handling for fw_version buffer used
+      by representors
+    - net: sched: ife: fix potential use-after-free
+    - ethernet: atheros: fix a memleak in atl1e_setup_ring_resources
+    - net/rose: fix races in rose_kill_by_device()
+    - net: check vlan filter feature in vlan_vids_add_by_dev() and
+      vlan_vids_del_by_dev()
+    - afs: Fix the dynamic root's d_delete to always delete unused dentries
+    - afs: Fix dynamic root lookup DNS check
+    - net: warn if gso_type isn't set for a GSO SKB
+    - net: check dev->gso_max_size in gso_features_check()
+    - afs: Fix overwriting of result of DNS query
+    - i2c: aspeed: Handle the coalesced stop conditions with the start conditions.
+    - pinctrl: at91-pio4: use dedicated lock class for IRQ
+    - ALSA: hda/hdmi: Add quirk to force pin connectivity on NUC10
+    - ALSA: hda/hdmi: add force-connect quirk for NUC5CPYB
+    - smb: client: fix NULL deref in asn1_ber_decoder()
+    - btrfs: do not allow non subvolume root targets for snapshot
+    - interconnect: Treat xlate() returning NULL node as an error
+    - iio: imu: inv_mpu6050: fix an error code problem in inv_mpu6050_read_raw
+    - Input: ipaq-micro-keys - add error handling for devm_kmemdup
+    - scsi: bnx2fc: Fix skb double free in bnx2fc_rcv()
+    - iio: common: ms_sensors: ms_sensors_i2c: fix humidity conversion time table
+    - iio: adc: ti_am335x_adc: Fix return value check of tiadc_request_dma()
+    - wifi: cfg80211: Add my certificate
+    - wifi: cfg80211: fix certs build to not depend on file order
+    - USB: serial: ftdi_sio: update Actisense PIDs constant names
+    - USB: serial: option: add Quectel EG912Y module support
+    - USB: serial: option: add Foxconn T99W265 with new baseline
+    - USB: serial: option: add Quectel RM500Q R13 firmware support
+    - Bluetooth: hci_event: Fix not checking if HCI_OP_INQUIRY has been sent
+    - net: 9p: avoid freeing uninit memory in p9pdu_vreadf
+    - net: rfkill: gpio: set GPIO direction
+    - x86/alternatives: Sync core before enabling interrupts
+    - usb: fotg210-hcd: delete an incorrect bounds test
+    - ring-buffer: Fix wake ups when buffer_percent is set to 100
+    - block: Don't invalidate pagecache for invalid falloc modes
+    - Linux 5.4.266
+  * CVE-2024-0607
+    - netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 21 Mar 2024 17:59:35 +0800
+
+linux-ein (5.4.0-1049.56) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1049.56 -proposed tracker (LP: #2055951)
+
+  [ Ubuntu: 5.4.0-174.193 ]
+
+  * focal/linux: 5.4.0-174.193 -proposed tracker (LP: #2055978)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update annotations scripts
+    - debian/dkms-versions -- update from kernel-versions (main/s2024.02.05)
+  * CVE-2024-24855
+    - scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan()
+  * CVE-2024-1086
+    - netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+  * CVE-2023-23004
+    - malidp: Fix NULL vs IS_ERR() checking
+  * CVE-2023-23000
+    - phy: tegra: xusb: Fix return value of tegra_xusb_find_port_node function
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 14 Mar 2024 13:34:43 +0800
+
+linux-ein (5.4.0-1048.55) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1048.55 -proposed tracker (LP: #2052109)
+
+  * Focal update: v5.4.261 upstream stable release (LP: #2049049)
+    - [Config] ein: remove CONFIG_QCOM_SDM845_LLCC
+
+  * Focal update: v5.4.260 upstream stable release (LP: #2049024)
+    - [Config] ein: cleanup after removing CONFIG_BLK_DEV_SX8
+
+  [ Ubuntu: 5.4.0-173.191 ]
+
+  * focal/linux: 5.4.0-173.191 -proposed tracker (LP: #2052135)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2024.02.05)
+  * CVE-2023-0340
+    - vhost: use kzalloc() instead of kmalloc() followed by memset()
+  * CVE-2023-6915
+    - ida: Fix crash in ida_free when the bitmap is empty
+  * Focal update: v5.4.265 upstream stable release (LP: #2051644)
+    - afs: Fix refcount underflow from error handling race
+    - net: ipv6: support reporting otherwise unknown prefix flags in RTM_NEWPREFIX
+    - qca_debug: Prevent crash on TX ring changes
+    - qca_debug: Fix ethtool -G iface tx behavior
+    - qca_spi: Fix reset behavior
+    - atm: solos-pci: Fix potential deadlock on &cli_queue_lock
+    - atm: solos-pci: Fix potential deadlock on &tx_queue_lock
+    - atm: Fix Use-After-Free in do_vcc_ioctl
+    - qed: Fix a potential use-after-free in qed_cxt_tables_alloc
+    - net: Remove acked SYN flag from packet in the transmit queue correctly
+    - sign-file: Fix incorrect return values check
+    - vsock/virtio: Fix unsigned integer wrap around in
+      virtio_transport_has_space()
+    - net: stmmac: use dev_err_probe() for reporting mdio bus registration failure
+    - net: stmmac: Handle disabled MDIO busses from devicetree
+    - cred: switch to using atomic_long_t
+    - ALSA: hda/hdmi: add force-connect quirks for ASUSTeK Z170 variants
+    - usb: aqc111: check packet for fixup for true limit
+    - blk-throttle: fix lockdep warning of "cgroup_mutex or RCU read lock
+      required!"
+    - bcache: avoid oversize memory allocation by small stripe_size
+    - bcache: add code comments for bch_btree_node_get() and
+      __bch_btree_node_alloc()
+    - bcache: avoid NULL checking to c->root in run_cache_set()
+    - platform/x86: intel_telemetry: Fix kernel doc descriptions
+    - HID: add ALWAYS_POLL quirk for Apple kb
+    - HID: hid-asus: reset the backlight brightness level on resume
+    - HID: multitouch: Add quirk for HONOR GLO-GXXX touchpad
+    - asm-generic: qspinlock: fix queued_spin_value_unlocked() implementation
+    - net: usb: qmi_wwan: claim interface 4 for ZTE MF290
+    - HID: hid-asus: add const to read-only outgoing usb buffer
+    - soundwire: stream: fix NULL pointer dereference for multi_link
+    - ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS
+    - arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify
+    - team: Fix use-after-free when an option instance allocation fails
+    - ring-buffer: Fix memory leak of free page
+    - mmc: block: Be sure to wait while busy in CQE error recovery
+    - powerpc/ftrace: Create a dummy stackframe to fix stack unwind
+    - powerpc/ftrace: Fix stack teardown in ftrace_no_trace
+    - Linux 5.4.265
+  * Focal update: v5.4.264 upstream stable release (LP: #2049935)
+    - hrtimers: Push pending hrtimers away from outgoing CPU earlier
+    - netfilter: ipset: fix race condition between swap/destroy and kernel side
+      add/del/test
+    - tg3: Move the [rt]x_dropped counters to tg3_napi
+    - tg3: Increment tx_dropped in tg3_tso_bug()
+    - kconfig: fix memory leak from range properties
+    - drm/amdgpu: correct chunk_ptr to a pointer to chunk.
+    - of: base: Add of_get_cpu_state_node() to get idle states for a CPU node
+    - ACPI/IORT: Make iort_get_device_domain IRQ domain agnostic
+    - ACPI/IORT: Make iort_msi_map_rid() PCI agnostic
+    - of/iommu: Make of_map_rid() PCI agnostic
+    - of/irq: make of_msi_map_get_device_domain() bus agnostic
+    - of/irq: Make of_msi_map_rid() PCI bus agnostic
+    - of: base: Fix some formatting issues and provide missing descriptions
+    - of: Fix kerneldoc output formatting
+    - of: Add missing 'Return' section in kerneldoc comments
+    - of: dynamic: Fix of_reconfig_get_state_change() return value documentation
+    - ipv6: fix potential NULL deref in fib6_add()
+    - hv_netvsc: rndis_filter needs to select NLS
+    - net: arcnet: Fix RESET flag handling
+    - net: arcnet: com20020 fix error handling
+    - arcnet: restoring support for multiple Sohard Arcnet cards
+    - ipv4: ip_gre: Avoid skb_pull() failure in ipgre_xmit()
+    - net: hns: fix fake link up on xge port
+    - netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
+    - tcp: do not accept ACK of bytes we never sent
+    - bpf: sockmap, updating the sg structure should also update curr
+    - RDMA/bnxt_re: Correct module description string
+    - hwmon: (acpi_power_meter) Fix 4.29 MW bug
+    - ASoC: wm_adsp: fix memleak in wm_adsp_buffer_populate
+    - tracing: Fix a warning when allocating buffered events fails
+    - scsi: be2iscsi: Fix a memleak in beiscsi_init_wrb_handle()
+    - ARM: imx: Check return value of devm_kasprintf in imx_mmdc_perf_init
+    - ARM: dts: imx: make gpt node name generic
+    - ARM: dts: imx7: Declare timers compatible with fsl,imx6dl-gpt
+    - ALSA: pcm: fix out-of-bounds in snd_pcm_state_names
+    - nilfs2: prevent WARNING in nilfs_sufile_set_segment_usage()
+    - tracing: Always update snapshot buffer size
+    - tracing: Fix incomplete locking when disabling buffered events
+    - tracing: Fix a possible race when disabling buffered events
+    - packet: Move reference count in packet_sock to atomic_long_t
+    - arm64: dts: mediatek: mt7622: fix memory node warning check
+    - arm64: dts: mediatek: mt8173-evb: Fix regulator-fixed node names
+    - gpiolib: sysfs: Fix error handling on failed export
+    - mmc: core: add helpers mmc_regulator_enable/disable_vqmmc
+    - mmc: sdhci-sprd: Fix vqmmc not shutting down after the card was pulled
+    - usb: gadget: f_hid: fix report descriptor allocation
+    - parport: Add support for Brainboxes IX/UC/PX parallel cards
+    - usb: typec: class: fix typec_altmode_put_partner to put plugs
+    - ARM: PL011: Fix DMA support
+    - serial: sc16is7xx: address RX timeout interrupt errata
+    - serial: 8250_omap: Add earlycon support for the AM654 UART controller
+    - x86/CPU/AMD: Check vendor in the AMD microcode callback
+    - KVM: s390/mm: Properly reset no-dat
+    - nilfs2: fix missing error check for sb_set_blocksize call
+    - io_uring/af_unix: disable sending io_uring over sockets
+    - netlink: don't call ->netlink_bind with table lock held
+    - genetlink: add CAP_NET_ADMIN test for multicast bind
+    - psample: Require 'CAP_NET_ADMIN' when joining "packets" group
+    - drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group
+    - tools headers UAPI: Sync linux/perf_event.h with the kernel sources
+    - cifs: Fix non-availability of dedup breaking generic/304
+    - smb: client: fix potential NULL deref in parse_dfs_referrals()
+    - devcoredump : Serialize devcd_del work
+    - devcoredump: Send uevent once devcd is ready
+    - Linux 5.4.264
+  * CVE-2024-0646
+    - net: tls, update curr on splice as well
+  * CVE-2024-0565
+    - smb: client: fix OOB in receive_encrypted_standard()
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+  * CVE-2023-51782
+    - net/rose: Fix Use-After-Free in rose_ioctl
+  * Focal update: v5.4.263 upstream stable release (LP: #2049084)
+    - driver core: Release all resources during unbind before updating device
+      links
+    - RDMA/irdma: Prevent zero-length STAG registration
+    - PCI: keystone: Drop __init from ks_pcie_add_pcie_{ep,port}()
+    - afs: Make error on cell lookup failure consistent with OpenAFS
+    - drm/panel: simple: Fix Innolux G101ICE-L01 bus flags
+    - drm/panel: simple: Fix Innolux G101ICE-L01 timings
+    - ata: pata_isapnp: Add missing error check for devm_ioport_map()
+    - drm/rockchip: vop: Fix color for RGB888/BGR888 format on VOP full
+    - HID: core: store the unique system identifier in hid_device
+    - HID: fix HID device resource race between HID core and debugging support
+    - ipv4: Correct/silence an endian warning in __ip_do_redirect
+    - net: usb: ax88179_178a: fix failed operations during ax88179_reset
+    - arm/xen: fix xen_vcpu_info allocation alignment
+    - amd-xgbe: handle corner-case during sfp hotplug
+    - amd-xgbe: handle the corner-case during tx completion
+    - amd-xgbe: propagate the correct speed and duplex status
+    - net: axienet: Fix check for partial TX checksum
+    - afs: Return ENOENT if no cell DNS record can be found
+    - afs: Fix file locking on R/O volumes to operate in local mode
+    - nvmet: remove unnecessary ctrl parameter
+    - nvmet: nul-terminate the NQNs passed in the connect command
+    - MIPS: KVM: Fix a build warning about variable set but not used
+    - ext4: add a new helper to check if es must be kept
+    - ext4: factor out __es_alloc_extent() and __es_free_extent()
+    - ext4: use pre-allocated es in __es_insert_extent()
+    - ext4: use pre-allocated es in __es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_remove_extent()
+    - ext4: using nofail preallocation in ext4_es_insert_delayed_block()
+    - ext4: using nofail preallocation in ext4_es_insert_extent()
+    - ext4: fix slab-use-after-free in ext4_es_insert_extent()
+    - ext4: make sure allocate pending entry not fail
+    - arm64: cpufeature: Extract capped perfmon fields
+    - KVM: arm64: limit PMU version to PMUv3 for ARMv8.1
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA
+    - bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in
+      btree_gc_coalesce()
+    - s390/dasd: protect device queue against concurrent access
+    - USB: serial: option: add Luat Air72*U series products
+    - hv_netvsc: Fix race of register_netdevice_notifier and VF register
+    - hv_netvsc: Mark VF as slave before exposing it to user-mode
+    - dm-delay: fix a race between delay_presuspend and delay_bio
+    - bcache: check return value from btree_node_alloc_replacement()
+    - bcache: prevent potential division by zero error
+    - USB: serial: option: add Fibocom L7xx modules
+    - USB: serial: option: fix FM101R-GL defines
+    - USB: serial: option: don't claim interface 4 for ZTE MF290
+    - USB: dwc2: write HCINT with INTMASK applied
+    - usb: dwc3: set the dma max_seg_size
+    - USB: dwc3: qcom: fix resource leaks on probe deferral
+    - USB: dwc3: qcom: fix wakeup after probe deferral
+    - io_uring: fix off-by one bvec index
+    - pinctrl: avoid reload of p state in list iteration
+    - firewire: core: fix possible memory leak in create_units()
+    - mmc: block: Do not lose cache flush during CQE error recovery
+    - ALSA: hda: Disable power-save on KONTRON SinglePC
+    - ALSA: hda/realtek: Headset Mic VREF to 100%
+    - ALSA: hda/realtek: Add supported ALC257 for ChromeOS
+    - dm-verity: align struct dm_verity_fec_io properly
+    - dm verity: don't perform FEC for failed readahead IO
+    - bcache: revert replacing IS_ERR_OR_NULL with IS_ERR
+    - powerpc: Don't clobber f0/vs0 during fp|altivec register save
+    - btrfs: fix off-by-one when checking chunk map includes logical address
+    - btrfs: send: ensure send_fd is writable
+    - btrfs: make error messages more clear when getting a chunk map
+    - Input: xpad - add HyperX Clutch Gladiate Support
+    - net: stmmac: xgmac: Disable FPE MMC interrupts
+    - ravb: Fix races between ravb_tx_timeout_work() and net related ops
+    - net: ravb: Use pm_runtime_resume_and_get()
+    - net: ravb: Start TX queues after HW initialization succeeded
+    - smb3: fix touch -h of symlink
+    - s390/mm: fix phys vs virt confusion in mark_kernel_pXd() functions family
+    - s390/cmma: fix detection of DAT pages
+    - mtd: cfi_cmdset_0001: Support the absence of protection registers
+    - mtd: cfi_cmdset_0001: Byte swap OTP info
+    - fbdev: stifb: Make the STI next font pointer a 32-bit signed offset
+    - ima: annotate iint mutex to avoid lockdep false positive warnings
+    - ovl: skip overlayfs superblocks at global sync
+    - ima: detect changes to the backing overlay file
+    - scsi: qla2xxx: Simplify the code for aborting SCSI commands
+    - scsi: core: Introduce the scsi_cmd_to_rq() function
+    - scsi: qla2xxx: Use scsi_cmd_to_rq() instead of scsi_cmnd.request
+    - scsi: qla2xxx: Fix system crash due to bad pointer access
+    - cpufreq: imx6q: don't warn for disabling a non-existing frequency
+    - cpufreq: imx6q: Don't disable 792 Mhz OPP unnecessarily
+    - mmc: cqhci: Increase recovery halt timeout
+    - mmc: cqhci: Warn of halt or task clear failure
+    - mmc: cqhci: Fix task clearing in CQE error recovery
+    - mmc: core: convert comma to semicolon
+    - mmc: block: Retry commands in CQE error recovery
+    - Linux 5.4.263
+  * Focal update: v5.4.262 upstream stable release (LP: #2049069)
+    - locking/ww_mutex/test: Fix potential workqueue corruption
+    - perf/core: Bail out early if the request AUX area is out of bound
+    - clocksource/drivers/timer-imx-gpt: Fix potential memory leak
+    - clocksource/drivers/timer-atmel-tcb: Fix initialization on SAM9 hardware
+    - x86/mm: Drop the 4 MB restriction on minimal NUMA node memory size
+    - wifi: mac80211_hwsim: fix clang-specific fortify warning
+    - wifi: mac80211: don't return unset power in ieee80211_get_tx_power()
+    - wifi: ath9k: fix clang-specific fortify warnings
+    - wifi: ath10k: fix clang-specific fortify warning
+    - net: annotate data-races around sk->sk_tx_queue_mapping
+    - net: annotate data-races around sk->sk_dst_pending_confirm
+    - wifi: ath10k: Don't touch the CE interrupt registers after power up
+    - Bluetooth: Fix double free in hci_conn_cleanup
+    - platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e
+    - drm/komeda: drop all currently held locks if deadlock happens
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+    - drm/amd: Fix UBSAN array-index-out-of-bounds for Polaris and Tonga
+    - drm/amdgpu: Fix a null pointer access when the smc_rreg pointer is NULL
+    - selftests/efivarfs: create-read: fix a resource leak
+    - crypto: pcrypt - Fix hungtask for PADATA_RESET
+    - RDMA/hfi1: Use FIELD_GET() to extract Link Width
+    - fs/jfs: Add check for negative db_l2nbperpage
+    - fs/jfs: Add validity check for db_maxag and db_agpref
+    - jfs: fix array-index-out-of-bounds in dbFindLeaf
+    - jfs: fix array-index-out-of-bounds in diAlloc
+    - ARM: 9320/1: fix stack depot IRQ stack filter
+    - ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+    - PCI: tegra194: Use FIELD_GET()/FIELD_PREP() with Link Width fields
+    - atm: iphase: Do PCI error checks on own line
+    - scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+    - HID: Add quirk for Dell Pro Wireless Keyboard and Mouse KM5221W
+    - tty: vcc: Add check for kstrdup() in vcc_probe()
+    - usb: gadget: f_ncm: Always set current gadget in ncm_bind()
+    - i2c: sun6i-p2wi: Prevent potential division by zero
+    - media: gspca: cpia1: shift-out-of-bounds in set_flicker
+    - media: vivid: avoid integer overflow
+    - gfs2: ignore negated quota changes
+    - media: cobalt: Use FIELD_GET() to extract Link Width
+    - drm/amd/display: Avoid NULL dereference of timing generator
+    - kgdb: Flush console before entering kgdb on panic
+    - ASoC: ti: omap-mcbsp: Fix runtime PM underflow warnings
+    - pwm: Fix double shift bug
+    - wifi: iwlwifi: Use FW rate for non-data frames
+    - NFSv4.1: fix SP4_MACH_CRED protection for pnfs IO
+    - ipvlan: add ipvlan_route_v6_outbound() helper
+    - tty: Fix uninit-value access in ppp_sync_receive()
+    - net: hns3: fix variable may not initialized problem in hns3_init_mac_addr()
+    - tipc: Fix kernel-infoleak due to uninitialized TLV value
+    - ppp: limit MRU to 64K
+    - xen/events: fix delayed eoi list handling
+    - ptp: annotate data-race around q->head and q->tail
+    - bonding: stop the device in bond_setup_by_slave()
+    - net: ethernet: cortina: Fix max RX frame define
+    - net: ethernet: cortina: Handle large frames
+    - net: ethernet: cortina: Fix MTU max setting
+    - netfilter: nf_conntrack_bridge: initialize err to 0
+    - net: stmmac: Rework stmmac_rx()
+    - net: stmmac: fix rx budget limit check
+    - net/mlx5_core: Clean driver version and name
+    - net/mlx5e: Check return value of snprintf writing to fw_version buffer for
+      representors
+    - macvlan: Don't propagate promisc change to lower dev in passthru
+    - tools/power/turbostat: Fix a knl bug
+    - cifs: spnego: add ';' in HOST_KEY_LEN
+    - media: venus: hfi: add checks to perform sanity on queue pointers
+    - randstruct: Fix gcc-plugin performance mode to stay in group
+    - bpf: Fix precision tracking for BPF_ALU | BPF_TO_BE | BPF_END
+    - scsi: megaraid_sas: Increase register read retry rount from 3 to 30 for
+      selected registers
+    - x86/cpu/hygon: Fix the CPU topology evaluation for real
+    - KVM: x86: hyper-v: Don't auto-enable stimer on write from user-space
+    - KVM: x86: Ignore MSR_AMD64_TW_CFG access
+    - audit: don't take task_lock() in audit_exe_compare() code path
+    - audit: don't WARN_ON_ONCE(!current->mm) in audit_exe_compare()
+    - hvc/xen: fix error path in xen_hvc_init() to always register frontend driver
+    - PCI/sysfs: Protect driver's D3cold preference from user space
+    - ACPI: resource: Do IRQ override on TongFang GMxXGxx
+    - mmc: meson-gx: Remove setting of CMD_CFG_ERROR
+    - genirq/generic_chip: Make irq_remove_generic_chip() irqdomain aware
+    - PCI: keystone: Don't discard .remove() callback
+    - PCI: keystone: Don't discard .probe() callback
+    - parisc/pdc: Add width field to struct pdc_model
+    - clk: qcom: ipq8074: drop the CLK_SET_RATE_PARENT flag from PLL clocks
+    - mmc: vub300: fix an error code
+    - PM: hibernate: Use __get_safe_page() rather than touching the list
+    - PM: hibernate: Clean up sync_read handling in snapshot_write_next()
+    - btrfs: don't arbitrarily slow down delalloc if we're committing
+    - jbd2: fix potential data lost in recovering journal raced with synchronizing
+      fs bdev
+    - quota: explicitly forbid quota files from being encrypted
+    - kernel/reboot: emergency_restart: Set correct system_state
+    - i2c: core: Run atomic i2c xfer when !preemptible
+    - mcb: fix error handling for different scenarios when parsing
+    - dmaengine: stm32-mdma: correct desc prep when channel running
+    - mm/cma: use nth_page() in place of direct struct page manipulation
+    - i3c: master: cdns: Fix reading status register
+    - parisc: Prevent booting 64-bit kernels on PA1.x machines
+    - parisc/pgtable: Do not drop upper 5 address bits of physical address
+    - ALSA: info: Fix potential deadlock at disconnection
+    - ALSA: hda/realtek - Enable internal speaker of ASUS K6500ZC
+    - serial: meson: remove redundant initialization of variable id
+    - tty: serial: meson: retrieve port FIFO size from DT
+    - serial: meson: Use platform_get_irq() to get the interrupt
+    - tty: serial: meson: fix hard LOCKUP on crtscts mode
+    - Bluetooth: btusb: add Realtek 8822CE to usb_device_id table
+    - Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x0cb8:0xc559
+    - bluetooth: Add device 0bda:887b to device tables
+    - bluetooth: Add device 13d3:3571 to device tables
+    - Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables
+    - Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE
+    - Revert ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - net: dsa: lan9303: consequently nested-lock physical MDIO
+    - i2c: i801: fix potential race in i801_block_transaction_byte_by_byte
+    - media: lirc: drop trailing space from scancode transmit
+    - media: sharp: fix sharp encoding
+    - media: venus: hfi_parser: Add check to keep the number of codecs within
+      range
+    - media: venus: hfi: fix the check to handle session buffer requirement
+    - media: venus: hfi: add checks to handle capabilities from firmware
+    - nfsd: fix file memleak on client_opens_release
+    - ext4: apply umask if ACL support is disabled
+    - ext4: correct offset of gdb backup in non meta_bg group to update_backups
+    - ext4: correct return value of ext4_convert_meta_bg
+    - ext4: correct the start block of counting reserved clusters
+    - ext4: remove gdb backup copy for meta bg in setup_new_flex_group_blocks
+    - drm/amdgpu: fix error handling in amdgpu_bo_list_get()
+    - tracing: Have trace_event_file have ref counters
+    - netfilter: nf_tables: pass context to nft_set_destroy()
+    - netfilter: nftables: rename set element data activation/deactivation
+      functions
+    - netfilter: nf_tables: drop map element references from preparation phase
+    - netfilter: nft_set_rbtree: Switch to node list walk for overlap detection
+    - netfilter: nft_set_rbtree: fix null deref on element insertion
+    - netfilter: nft_set_rbtree: fix overlap expiration walk
+    - netfilter: nf_tables: don't skip expired elements during walk
+    - netfilter: nf_tables: GC transaction API to avoid race with control plane
+    - netfilter: nf_tables: adapt set backend to use GC transaction API
+    - netfilter: nft_set_hash: mark set element as dead when deleting from packet
+      path
+    - netfilter: nf_tables: remove busy mark and gc batch API
+    - netfilter: nf_tables: fix GC transaction races with netns and netlink event
+      exit path
+    - netfilter: nf_tables: GC transaction race with netns dismantle
+    - netfilter: nf_tables: GC transaction race with abort path
+    - netfilter: nf_tables: use correct lock to protect gc_list
+    - netfilter: nf_tables: defer gc run if previous batch is still pending
+    - netfilter: nft_set_rbtree: skip sync GC for new elements in this transaction
+    - netfilter: nft_set_rbtree: use read spinlock to avoid datapath contention
+    - netfilter: nft_set_hash: try later when GC hits EAGAIN on iteration
+    - netfilter: nf_tables: fix memleak when more than 255 elements expired
+    - netfilter: nf_tables: unregister flowtable hooks on netns exit
+    - netfilter: nf_tables: double hook unregistration in netns path
+    - netfilter: nftables: update table flags from the commit phase
+    - netfilter: nf_tables: fix table flag updates
+    - netfilter: nf_tables: disable toggling dormant table state more than once
+    - netfilter: nf_tables: bogus EBUSY when deleting flowtable after flush (for
+      5.4)
+    - Linux 5.4.262
+  * Focal update: v5.4.261 upstream stable release (LP: #2049049)
+    - vfs: fix readahead(2) on block devices
+    - genirq/matrix: Exclude managed interrupts in irq_matrix_allocated()
+    - i40e: fix potential memory leaks in i40e_remove()
+    - tcp: call tcp_try_undo_recovery when an RTOd TFO SYNACK is ACKed
+    - wifi: rtw88: debug: Fix the NULL vs IS_ERR() bug for debugfs_create_file()
+    - wifi: mt76: mt7603: rework/fix rx pse hang check
+    - tcp_metrics: add missing barriers on delete
+    - tcp_metrics: properly set tp->snd_ssthresh in tcp_init_metrics()
+    - tcp_metrics: do not create an entry from tcp_init_metrics()
+    - wifi: rtlwifi: fix EDCA limit set by BT coexistence
+    - can: dev: can_restart(): don't crash kernel if carrier is OK
+    - can: dev: can_restart(): fix race condition between controller restart and
+      netif_carrier_on()
+    - thermal: core: prevent potential string overflow
+    - r8169: use tp_to_dev instead of open code
+    - r8169: fix rare issue with broken rx after link-down on RTL8125
+    - chtls: fix tp->rcv_tstamp initialization
+    - tcp: Remove one extra ktime_get_ns() from cookie_init_timestamp
+    - tcp: fix cookie_init_timestamp() overflows
+    - ACPI: sysfs: Fix create_pnp_modalias() and create_of_modalias()
+    - ipv6: avoid atomic fragment on GSO packets
+    - net: add DEV_STATS_READ() helper
+    - ipvlan: properly track tx_errors
+    - regmap: debugfs: Fix a erroneous check after snprintf()
+    - clk: qcom: clk-rcg2: Fix clock rate overflow for high parent frequencies
+    - clk: qcom: gcc-sm8150: use ARRAY_SIZE instead of specifying num_parents
+    - clk: qcom: gcc-sm8150: Fix gcc_sdcc2_apps_clk_src
+    - clk: imx: Select MXC_CLK for CLK_IMX8QXP
+    - clk: keystone: pll: fix a couple NULL vs IS_ERR() checks
+    - clk: npcm7xx: Fix incorrect kfree
+    - clk: mediatek: clk-mt6779: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt6797: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629-eth: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt7629: Add check for mtk_alloc_clk_data
+    - clk: mediatek: clk-mt2701: Add check for mtk_alloc_clk_data
+    - platform/x86: wmi: Fix probe failure when failing to register WMI devices
+    - platform/x86: wmi: remove unnecessary initializations
+    - platform/x86: wmi: Fix opening of char device
+    - hwmon: (coretemp) Fix potentially truncated sysfs attribute name
+    - drm/rockchip: vop: Fix reset of state in duplicate state crtc funcs
+    - drm/rockchip: vop: Fix call to crtc reset helper
+    - drm/radeon: possible buffer overflow
+    - drm/rockchip: cdn-dp: Fix some error handling paths in cdn_dp_probe()
+    - arm64: dts: qcom: sdm845-mtp: fix WiFi configuration
+    - ARM: dts: qcom: mdm9615: populate vsdcc fixed regulator
+    - soc: qcom: llcc cleanup to get rid of sdm845 specific driver file
+    - [Config] remove CONFIG_QCOM_SDM845_LLCC
+    - soc: qcom: Rename llcc-slice to llcc-qcom
+    - [Config] remove llcc-slice module
+    - soc: qcom: llcc: Handle a second device without data corruption
+    - firmware: ti_sci: Replace HTTP links with HTTPS ones
+    - firmware: ti_sci: Mark driver as non removable
+    - clk: scmi: Free scmi_clk allocated when the clocks with invalid info are
+      skipped
+    - hwrng: geode - fix accessing registers
+    - libnvdimm/of_pmem: Use devm_kstrdup instead of kstrdup and check its return
+      value
+    - sched/rt: Provide migrate_disable/enable() inlines
+    - nd_btt: Make BTT lanes preemptible
+    - crypto: caam/qi2 - fix Chacha20 + Poly1305 self test failure
+    - crypto: caam/jr - fix Chacha20 + Poly1305 self test failure
+    - HID: cp2112: Use irqchip template
+    - hid: cp2112: Fix duplicate workqueue initialization
+    - ARM: 9321/1: memset: cast the constant byte to unsigned char
+    - ext4: move 'ix' sanity check to corrent position
+    - scsi: ufs: core: Leave space for '\0' in utf8 desc string
+    - RDMA/hfi1: Workaround truncation compilation error
+    - sh: bios: Revive earlyprintk support
+    - ASoC: Intel: Skylake: Fix mem leak when parsing UUIDs fails
+    - ASoC: ams-delta.c: use component after check
+    - mfd: dln2: Fix double put in dln2_probe
+    - leds: pwm: simplify if condition
+    - leds: pwm: convert to atomic PWM API
+    - leds: pwm: Don't disable the PWM when the LED should be off
+    - ledtrig-cpu: Limit to 8 CPUs
+    - leds: trigger: ledtrig-cpu:: Fix 'output may be truncated' issue for 'cpu'
+    - tty: tty_jobctrl: fix pid memleak in disassociate_ctty()
+    - usb: dwc2: fix possible NULL pointer dereference caused by driver
+      concurrency
+    - dmaengine: ti: edma: handle irq_of_parse_and_map() errors
+    - misc: st_core: Do not call kfree_skb() under spin_lock_irqsave()
+    - tools: iio: privatize globals and functions in iio_generic_buffer.c file
+    - tools: iio: iio_generic_buffer: Fix some integer type and calculation
+    - tools: iio: iio_generic_buffer ensure alignment
+    - USB: usbip: fix stub_dev hub disconnect
+    - dmaengine: pxa_dma: Remove an erroneous BUG_ON() in pxad_free_desc()
+    - f2fs: fix to initialize map.m_pblk in f2fs_precache_extents()
+    - modpost: fix tee MODULE_DEVICE_TABLE built on big-endian host
+    - powerpc/xive: Fix endian conversion size
+    - powerpc/imc-pmu: Use the correct spinlock initializer.
+    - powerpc/pseries: fix potential memory leak in init_cpu_associativity()
+    - i3c: Fix potential refcount leak in i3c_master_register_new_i3c_devs
+    - rtc: pcf85363: fix wrong mask/val parameters in regmap_update_bits call
+    - pcmcia: cs: fix possible hung task and memory leak pccardd()
+    - pcmcia: ds: fix refcount leak in pcmcia_device_add()
+    - pcmcia: ds: fix possible name leak in error path in pcmcia_device_add()
+    - media: bttv: fix use after free error due to btv->timeout timer
+    - media: s3c-camif: Avoid inappropriate kfree()
+    - media: dvb-usb-v2: af9035: fix missing unlock
+    - regmap: prevent noinc writes from clobbering cache
+    - pwm: sti: Avoid conditional gotos
+    - pwm: sti: Reduce number of allocations and drop usage of chip_data
+    - pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume
+    - Input: synaptics-rmi4 - fix use after free in rmi_unregister_function()
+    - llc: verify mac len before reading mac header
+    - tipc: Change nla_policy for bearer-related names to NLA_NUL_STRING
+    - inet: shrink struct flowi_common
+    - dccp: Call security_inet_conn_request() after setting IPv4 addresses.
+    - dccp/tcp: Call security_inet_conn_request() after setting IPv6 addresses.
+    - Fix termination state for idr_for_each_entry_ul()
+    - net: stmmac: xgmac: Enable support for multiple Flexible PPS outputs
+    - net/smc: fix dangling sock under state SMC_APPFINCLOSEWAIT
+    - tg3: power down device only on SYSTEM_POWER_OFF
+    - r8169: respect userspace disabling IFF_MULTICAST
+    - netfilter: xt_recent: fix (increase) ipv6 literal buffer length
+    - netfilter: nft_redir: use `struct nf_nat_range2` throughout and deduplicate
+      eval call-backs
+    - netfilter: nat: fix ipv6 nat redirect with mapped and scoped addresses
+    - drm/syncobj: fix DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
+    - spi: spi-zynq-qspi: add spi-mem to driver kconfig dependencies
+    - fbdev: imsttfb: Fix error path of imsttfb_probe()
+    - fbdev: imsttfb: fix a resource leak in probe
+    - fbdev: fsl-diu-fb: mark wr_reg_wa() static
+    - Revert "mmc: core: Capture correct oemid-bits for eMMC cards"
+    - btrfs: use u64 for buffer sizes in the tree search ioctls
+    - Linux 5.4.261
+  * Focal update: v5.4.260 upstream stable release (LP: #2049024)
+    - mtd: rawnand: marvell: Ensure program page operations are successful
+    - selftests/ftrace: Add new test case which checks non unique symbol
+    - mcb: Return actual parsed size when reading chameleon table
+    - mcb-lpc: Reallocate memory region to avoid memory overlapping
+    - virtio_balloon: Fix endless deflation and inflation on arm64
+    - virtio-mmio: fix memory leak of vm_dev
+    - r8169: fix the KCSAN reported data-race in rtl_tx while reading
+      TxDescArray[entry].opts1
+    - r8169: fix the KCSAN reported data race in rtl_rx while reading desc->opts1
+    - treewide: Spelling fix in comment
+    - igb: Fix potential memory leak in igb_add_ethtool_nfc_entry
+    - neighbour: fix various data-races
+    - igc: Fix ambiguity in the ethtool advertising
+    - net: ieee802154: adf7242: Fix some potential buffer overflow in
+      adf7242_stats_show()
+    - r8152: Increase USB control msg timeout to 5000ms as per spec
+    - r8152: Run the unload routine if we have errors during probe
+    - r8152: Cancel hw_phy_work if we have an error in probe
+    - tcp: fix wrong RTO timeout when received SACK reneging
+    - gtp: uapi: fix GTPA_MAX
+    - gtp: fix fragmentation needed check with gso
+    - iio: exynos-adc: request second interupt only when touchscreen mode is used
+    - i2c: muxes: i2c-mux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-mux-gpmux: Use of_get_i2c_adapter_by_node()
+    - i2c: muxes: i2c-demux-pinctrl: Use of_get_i2c_adapter_by_node()
+    - i2c: stm32f7: Fix PEC handling in case of SMBUS transfers
+    - i2c: aspeed: Fix i2c bus hang in slave read
+    - nvmem: imx: correct nregs for i.MX6ULL
+    - nvmem: imx: correct nregs for i.MX6SLL
+    - nvmem: imx: correct nregs for i.MX6UL
+    - perf/core: Fix potential NULL deref
+    - clk: Sanitize possible_parent_show to Handle Return Value of
+      of_clk_get_parent_name
+    - i40e: Fix wrong check for I40E_TXR_FLAGS_WB_ON_ITR
+    - x86/i8259: Skip probing when ACPI/MADT advertises PCAT compatibility
+    - drm/dp_mst: Fix NULL deref in get_mst_branch_device_by_guid_helper()
+    - arm64: fix a concurrency issue in emulation_proc_handler()
+    - smbdirect: missing rc checks while waiting for rdma events
+    - f2fs: fix to do sanity check on inode type during garbage collection
+    - nfsd: lock_rename() needs both directories to live on the same fs
+    - x86/mm: Simplify RESERVE_BRK()
+    - x86/mm: Fix RESERVE_BRK() for older binutils
+    - ext4: add two helper functions extent_logical_end() and pa_logical_end()
+    - ext4: avoid overlapping preallocations due to overflow
+    - ext4: fix BUG in ext4_mb_new_inode_pa() due to overflow
+    - driver: platform: Add helper for safer setting of driver_override
+    - rpmsg: Constify local variable in field store macro
+    - rpmsg: Fix kfree() of static memory on setting driver_override
+    - rpmsg: Fix calling device_lock() on non-initialized device
+    - rpmsg: glink: Release driver_override
+    - rpmsg: Fix possible refcount leak in rpmsg_register_device_override()
+    - x86: Fix .brk attribute in linker script
+    - Input: i8042 - add Fujitsu Lifebook E5411 to i8042 quirk table
+    - irqchip/stm32-exti: add missing DT IRQ flag translation
+    - dmaengine: ste_dma40: Fix PM disable depth imbalance in d40_probe
+    - Input: synaptics-rmi4 - handle reset delay when using SMBus trsnsport
+    - fbdev: atyfb: only use ioremap_uc() on i386 and ia64
+    - spi: npcm-fiu: Fix UMA reads when dummy.nbytes == 0
+    - netfilter: nfnetlink_log: silence bogus compiler warning
+    - ASoC: rt5650: fix the wrong result of key button
+    - fbdev: uvesafb: Call cn_del_callback() at the end of uvesafb_exit()
+    - scsi: mpt3sas: Fix in error path
+    - platform/x86: asus-wmi: Change ASUS_WMI_BRN_DOWN code from 0x20 to 0x2e
+    - platform/mellanox: mlxbf-tmfifo: Fix a warning message
+    - net: chelsio: cxgb4: add an error code check in t4_load_phy_fw
+    - ata: ahci: fix enum constants for gcc-13
+    - remove the sx8 block driver
+    - [Config] remove CONFIG_BLK_DEV_SX8
+    - Revert "ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver"
+    - PCI: Prevent xHCI driver from claiming AMD VanGogh USB3 DRD device
+    - usb: storage: set 1.50 as the lower bcdDevice for older "Super Top"
+      compatibility
+    - tty: 8250: Remove UC-257 and UC-431
+    - tty: 8250: Add support for additional Brainboxes UC cards
+    - tty: 8250: Add support for Brainboxes UP cards
+    - tty: 8250: Add support for Intashield IS-100
+    - Linux 5.4.260
+  * CVE-2023-51779
+    - Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+  * CVE-2023-22995
+    - usb: dwc3: dwc3-qcom: Add missing platform_device_put() in
+      dwc3_qcom_acpi_register_core
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 20 Feb 2024 19:23:08 +0800
+
+linux-ein (5.4.0-1047.54) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1047.54 -proposed tracker (LP: #2052194)
+
+  [ Ubuntu: 5.4.0-172.190 ]
+
+  * focal/linux: 5.4.0-172.190 -proposed tracker (LP: #2052220)
+  * CVE-2023-51781
+    - appletalk: Fix Use-After-Free in atalk_ioctl
+  * CVE-2023-6915
+    - ida: Fix crash in ida_free when the bitmap is empty
+  * CVE-2024-0565
+    - smb: client: fix OOB in receive_encrypted_standard()
+  * CVE-2024-0646
+    - net: tls, update curr on splice as well
+
+ -- Nathan Sweetman <nathan.sweetman@canonical.com>  Fri, 09 Feb 2024 14:33:18 +1030
+
+linux-ein (5.4.0-1046.53) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1046.53 -proposed tracker (LP: #2048256)
+
+  * [PE100A/PCIE] Incorrect PCIE Supply Configuration (LP:#2047889)
+    - dt-bindings: imx6q-pcie: Add "vph-supply" for PHY supply voltage
+    - arm64: dts: imx8mq-evk: add one regulator used to power up pcie phy
+    - PCI: imx6: Enable PHY internal regulator when supplied >3V
+    - SAUCE: arm64/dts: pe100a: add a dummy vph for pcie
+
+  * Audio device disappear after playing audio without setting (LP: #2047884)
+    - ASoC: fsl_sai: Don't disable bitclock for i.MX8MP
+
+  [ Ubuntu: 5.4.0-171.189 ]
+
+  * focal/linux: 5.4.0-171.189 -proposed tracker (LP: #2048282)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+    - [Packaging] update annotations scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2024.01.08)
+  * Page fault in RDMA ODP triggers BUG_ON during MMU notifier registration
+    (LP: #2046534)
+    - RDMA/odp: Ensure the mm is still alive before creating an implicit child
+  * Hotplugging SCSI disk in QEMU VM fails (LP: #2047382)
+    - Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
+  * CVE-2023-6040
+    - netfilter: nf_tables: Reject tables of unsupported family
+  * kernel_selftests failures on kernel-P10d-LPAR10.ppc64el.10
+    (LP: #2032641)
+    - selftests: Skip TM tests on synthetic TM implementations
+  * [Debian] autoreconstruct - Do not generate chmod -x for deleted  files
+    (LP: #2045562)
+    - [Debian] autoreconstruct - Do not generate chmod -x for deleted files
+  * CVE-2023-6931
+    - perf/core: Add a new read format to get a number of lost samples
+    - perf: Fix perf_event_validate_size()
+    - perf: Fix perf_event_validate_size() lockdep splat
+  * CVE-2023-6932
+    - ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+  * CVE-2023-6606
+    - smb: client: fix OOB in smbCalcSize()
+  * CVE-2023-45863
+    - kobject: Fix slab-out-of-bounds in fill_kobj_path()
+  * Focal update: v5.4.259 upstream stable release (LP: #2043724)
+    - RDMA/cxgb4: Check skb value for failure to allocate
+    - lib/test_meminit: fix off-by-one error in test_pages()
+    - pwm: hibvt: Explicitly set .polarity in .get_state()
+    - HID: logitech-hidpp: Fix kernel crash on receiver USB disconnect
+    - quota: Fix slow quotaoff
+    - net: prevent address rewrite in kernel_bind()
+    - drm: etvnaviv: fix bad backport leading to warning
+    - drm/msm/dsi: skip the wait for video mode done if not applicable
+    - ravb: Fix up dma_free_coherent() call in ravb_remove()
+    - ieee802154: ca8210: Fix a potential UAF in ca8210_probe
+    - mlxsw: fix mlxsw_sp2_nve_vxlan_learning_set() return type
+    - xen-netback: use default TX queue size for vifs
+    - drm/vmwgfx: fix typo of sizeof argument
+    - ixgbe: fix crash with empty VF macvlan list
+    - net: nfc: fix races in nfc_llcp_sock_get() and nfc_llcp_sock_get_sn()
+    - nfc: nci: assert requested protocol is valid
+    - workqueue: Override implicit ordered attribute in
+      workqueue_apply_unbound_cpumask()
+    - dmaengine: stm32-mdma: abort resume if no ongoing transfer
+    - usb: xhci: xhci-ring: Use sysdev for mapping bounce buffer
+    - net: usb: dm9601: fix uninitialized variable use in dm9601_mdio_read
+    - usb: dwc3: Soft reset phy on probe for host
+    - usb: musb: Get the musb_qh poniter after musb_giveback
+    - usb: musb: Modify the "HWVers" register address
+    - iio: pressure: bmp280: Fix NULL pointer exception
+    - iio: pressure: dps310: Adjust Timeout Settings
+    - iio: pressure: ms5611: ms5611_prom_is_valid false negative bug
+    - mcb: remove is_added flag from mcb_device struct
+    - libceph: use kernel_connect()
+    - ceph: fix incorrect revoked caps assert in ceph_fill_file_size()
+    - Input: powermate - fix use-after-free in powermate_config_complete
+    - Input: psmouse - fix fast_reconnect function for PS/2 mode
+    - Input: xpad - add PXN V900 support
+    - cgroup: Remove duplicates in cgroup v1 tasks file
+    - pinctrl: avoid unsafe code pattern in find_pinctrl()
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call
+    - x86/cpu: Fix AMD erratum #1485 on Zen4-based CPUs
+    - dmaengine: mediatek: Fix deadlock caused by synchronize_irq()
+    - powerpc/8xx: Fix pte_access_permitted() for PAGE_NONE
+    - powerpc/64e: Fix wrong test in __ptep_test_and_clear_young()
+    - ravb: Fix use-after-free issue in ravb_tx_timeout_work()
+    - Documentation: sysctl: align cells in second content column
+    - usb: hub: Guard against accesses to uninitialized BOS descriptors
+    - Bluetooth: hci_event: Ignore NULL link key
+    - Bluetooth: Reject connection with the device which has same BD_ADDR
+    - Bluetooth: Fix a refcnt underflow problem for hci_conn
+    - Bluetooth: vhci: Fix race when opening vhci device
+    - Bluetooth: hci_event: Fix coding style
+    - Bluetooth: avoid memcmp() out of bounds warning
+    - ice: fix over-shifted variable
+    - nfc: nci: fix possible NULL pointer dereference in send_acknowledge()
+    - regmap: fix NULL deref on lookup
+    - KVM: x86: Mask LVTPC when handling a PMI
+    - netfilter: nft_payload: fix wrong mac header matching
+    - qed: fix LL2 RX buffer allocation
+    - xfrm: fix a data-race in xfrm_gen_index()
+    - xfrm: interface: use DEV_STATS_INC()
+    - net: ipv4: fix return value check in esp_remove_trailer
+    - net: ipv6: fix return value check in esp_remove_trailer
+    - net: rfkill: gpio: prevent value glitch during probe
+    - tcp: fix excessive TLP and RACK timeouts from HZ rounding
+    - tcp: tsq: relax tcp_small_queue_check() when rtx queue contains a single skb
+    - tun: prevent negative ifindex
+    - ipv4: fib: annotate races around nh->nh_saddr_genid and nh->nh_saddr
+    - net: usb: smsc95xx: Fix an error code in smsc95xx_reset()
+    - i40e: prevent crash on probe if hw registers have invalid values
+    - net/sched: sch_hfsc: upgrade 'rt' to 'sc' when it becomes a inner curve
+    - neighbor: tracing: Move pin6 inside CONFIG_IPV6=y section
+    - netfilter: nft_set_rbtree: .deactivate fails if element has expired
+    - net: pktgen: Fix interface flags printing
+    - resource: Add irqresource_disabled()
+    - ACPI: Drop acpi_dev_irqresource_disabled()
+    - ACPI: resource: Skip IRQ override on Asus Vivobook S5602ZA
+    - ACPI: resource: Add Asus ExpertBook B2502 to Asus quirks
+    - ACPI: resource: Skip IRQ override on Asus Expertbook B2402CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1502CBA
+    - ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CBA
+    - ARM: dts: ti: omap: Fix noisy serial with overrun-throttle-ms for mapphone
+    - btrfs: return -EUCLEAN for delayed tree ref with a ref count not equals to 1
+    - btrfs: initialize start_slot in btrfs_log_prealloc_extents
+    - i2c: mux: Avoid potential false error message in i2c_mux_add_adapter
+    - overlayfs: set ctime when setting mtime and atime
+    - gpio: timberdale: Fix potential deadlock on &tgpio->lock
+    - ata: libata-eh: Fix compilation warning in ata_eh_link_report()
+    - tracing: relax trace_event_eval_update() execution with cond_resched()
+    - HID: holtek: fix slab-out-of-bounds Write in holtek_kbd_input_event
+    - Bluetooth: Avoid redundant authentication
+    - Bluetooth: hci_core: Fix build warnings
+    - wifi: mac80211: allow transmitting EAPOL frames with tainted key
+    - wifi: cfg80211: avoid leaking stack data into trace
+    - regulator/core: Revert "fix kobject release warning and memory leak in
+      regulator_register()"
+    - sky2: Make sure there is at least one frag_addr available
+    - drm: panel-orientation-quirks: Add quirk for One Mix 2S
+    - btrfs: fix some -Wmaybe-uninitialized warnings in ioctl.c
+    - HID: multitouch: Add required quirk for Synaptics 0xcd7e device
+    - Bluetooth: hci_event: Fix using memcmp when comparing keys
+    - mtd: rawnand: qcom: Unmap the right resource upon probe failure
+    - mtd: spinand: micron: correct bitmask for ecc status
+    - mtd: physmap-core: Restore map_rom fallback
+    - mmc: core: sdio: hold retuning if sdio in 1-bit mode
+    - mmc: core: Capture correct oemid-bits for eMMC cards
+    - Revert "pinctrl: avoid unsafe code pattern in find_pinctrl()"
+    - ACPI: irq: Fix incorrect return value in acpi_register_gsi()
+    - USB: serial: option: add Telit LE910C4-WWX 0x1035 composition
+    - USB: serial: option: add entry for Sierra EM9191 with new firmware
+    - USB: serial: option: add Fibocom to DELL custom modem FM101R-GL
+    - s390/pci: fix iommu bitmap allocation
+    - gpio: vf610: set value before the direction to avoid a glitch
+    - ASoC: pxa: fix a memory leak in probe()
+    - phy: mapphone-mdm6600: Fix runtime disable on probe
+    - phy: mapphone-mdm6600: Fix runtime PM for remove
+    - phy: mapphone-mdm6600: Fix pinctrl_pm handling for sleep pins
+    - Bluetooth: hci_sock: fix slab oob read in create_monitor_event
+    - Bluetooth: hci_sock: Correctly bounds check and pad HCI_MON_NEW_INDEX name
+    - xfrm6: fix inet6_dev refcount underflow problem
+    - Linux 5.4.259
+  * Focal update: v5.4.258 upstream stable release (LP: #2042107)
+    - NFS/pNFS: Report EINVAL errors from connect() to the server
+    - SUNRPC: Mark the cred for revalidation if the server rejects it
+    - tracing: Increase trace array ref count on enable and filter files
+    - ata: libahci: clear pending interrupt status
+    - ext4: remove the 'group' parameter of ext4_trim_extent
+    - ext4: add new helper interface ext4_try_to_trim_range()
+    - ext4: scope ret locally in ext4_try_to_trim_range()
+    - ext4: change s_last_trim_minblks type to unsigned long
+    - ext4: mark group as trimmed only if it was fully scanned
+    - ext4: replace the traditional ternary conditional operator with with
+      max()/min()
+    - ext4: move setting of trimmed bit into ext4_try_to_trim_range()
+    - ext4: do not let fstrim block system suspend
+    - ASoC: meson: spdifin: start hw on dai probe
+    - netfilter: nf_tables: disallow element removal on anonymous sets
+    - bpf: Avoid deadlock when using queue and stack maps from NMI
+    - selftests/tls: Add {} to avoid static checker warning
+    - selftests: tls: swap the TX and RX sockets in some tests
+    - ASoC: imx-audmix: Fix return error with devm_clk_get()
+    - i40e: Fix for persistent lldp support
+    - SAUCE: Revert "UBUNTU: SAUCE: i40e Fix GPF when deleting VMs"
+    - i40e: Remove scheduling while atomic possibility
+    - i40e: Fix warning message and call stack during rmmod i40e driver
+    - i40e: Fix VF VLAN offloading when port VLAN is configured
+    - powerpc/perf/hv-24x7: Update domain value check
+    - dccp: fix dccp_v4_err()/dccp_v6_err() again
+    - net: hns3: add 5ms delay before clear firmware reset irq source
+    - net: bridge: use DEV_STATS_INC()
+    - team: fix null-ptr-deref when team device type is changed
+    - net: rds: Fix possible NULL-pointer dereference
+    - gpio: tb10x: Fix an error handling path in tb10x_gpio_probe()
+    - i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()
+    - Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN
+    - scsi: qla2xxx: Fix update_fcport for current_topology
+    - scsi: qla2xxx: Fix deletion race condition
+    - drm/amd/display: Reinstate LFC optimization
+    - drm/amd/display: Fix LFC multiplier changing erratically
+    - drm/amd/display: prevent potential division by zero errors
+    - ata: libata: disallow dev-initiated LPM transitions to unsupported states
+    - MIPS: Alchemy: only build mmc support helpers if au1xmmc is enabled
+    - clk: tegra: fix error return case for recalc_rate
+    - ARM: dts: ti: omap: motorola-mapphone: Fix abe_clkctrl warning on boot
+    - bus: ti-sysc: Fix SYSC_QUIRK_SWSUP_SIDLE_ACT handling for uart wake-up
+    - xtensa: add default definition for XCHAL_HAVE_DIV32
+    - xtensa: iss/network: make functions static
+    - xtensa: boot: don't add include-dirs
+    - xtensa: boot/lib: fix function prototypes
+    - gpio: pmic-eic-sprd: Add can_sleep flag for PMIC EIC chip
+    - parisc: sba: Fix compile warning wrt list of SBA devices
+    - parisc: iosapic.c: Fix sparse warnings
+    - parisc: drivers: Fix sparse warning
+    - parisc: irq: Make irq_stack_union static to avoid sparse warning
+    - selftests/ftrace: Correctly enable event in instance-event.tc
+    - ring-buffer: Avoid softlockup in ring_buffer_resize()
+    - ata: libata-eh: do not clear ATA_PFLAG_EH_PENDING in ata_eh_reset()
+    - spi: nxp-fspi: reset the FLSHxCR1 registers
+    - bpf: Clarify error expectations from bpf_clone_redirect
+    - powerpc/watchpoints: Annotate atomic context in more places
+    - ncsi: Propagate carrier gain/loss events to the NCSI controller
+    - fbdev/sh7760fb: Depend on FB=y
+    - nvme-pci: do not set the NUMA node of device if it has none
+    - watchdog: iTCO_wdt: No need to stop the timer in probe
+    - watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
+    - i40e: improve locking of mac_filter_hash
+    - i40e: always propagate error value in i40e_set_vsi_promisc()
+    - i40e: fix return of uninitialized aq_ret in i40e_set_vsi_promisc
+    - smack: Record transmuting in smk_transmuted
+    - smack: Retrieve transmuting information in smack_inode_getsecurity()
+    - Smack:- Use overlay inode label in smack_inode_copy_up()
+    - serial: 8250_port: Check IRQ data before use
+    - nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
+    - ALSA: hda: Disable power save for solving pop issue on Lenovo ThinkCentre
+      M70q
+    - ata: libata-scsi: ignore reserved bits for REPORT SUPPORTED OPERATION CODES
+    - i2c: i801: unregister tco_pdev in i801_probe() error path
+    - ring-buffer: Update "shortest_full" in polling
+    - btrfs: properly report 0 avail for very full file systems
+    - net: thunderbolt: Fix TCPv6 GSO checksum calculation
+    - ata: libata-core: Fix ata_port_request_pm() locking
+    - ata: libata-core: Fix port and device removal
+    - ata: libata-core: Do not register PM operations for SAS ports
+    - ata: libata-sata: increase PMP SRST timeout to 10s
+    - fs: binfmt_elf_efpic: fix personality for ELF-FDPIC
+    - rbd: move rbd_dev_refresh() definition
+    - rbd: decouple header read-in from updating rbd_dev->header
+    - rbd: decouple parent info read-in from updating rbd_dev
+    - rbd: take header_rwsem in rbd_dev_refresh() only when updating
+    - Revert "PCI: qcom: Disable write access to read only registers for IP
+      v2.3.3"
+    - scsi: zfcp: Fix a double put in zfcp_port_enqueue()
+    - qed/red_ll2: Fix undefined behavior bug in struct qed_ll2_info
+    - wifi: mwifiex: Fix tlv_buf_left calculation
+    - net: replace calls to sock->ops->connect() with kernel_connect()
+    - net: prevent rewrite of msg_name in sock_sendmsg()
+    - wifi: iwlwifi: dbg_ini: fix structure packing
+    - wifi: mwifiex: Fix oob check condition in mwifiex_process_rx_packet
+    - drivers/net: process the result of hdlc_open() and add call of hdlc_close()
+      in uhdlc_close()
+    - wifi: mt76: mt76x02: fix MT76x0 external LNA gain handling
+    - regmap: rbtree: Fix wrong register marked as in-cache when creating new node
+    - ima: Finish deprecation of IMA_TRUSTED_KEYRING Kconfig
+    - scsi: target: core: Fix deadlock due to recursive locking
+    - NFS4: Trace state recovery operation
+    - NFS: Add a helper nfs_client_for_each_server()
+    - NFSv4: Fix a nfs4_state_manager() race
+    - modpost: add missing else to the "of" check
+    - net: fix possible store tearing in neigh_periodic_work()
+    - ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
+    - net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent
+    - net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
+    - net: nfc: llcp: Add lock when modifying device list
+    - netfilter: handle the connecting collision properly in
+      nf_conntrack_proto_sctp
+    - net: stmmac: dwmac-stm32: fix resume on STM32 MCU
+    - tcp: fix quick-ack counting to count actual ACKs of new data
+    - tcp: fix delayed ACKs for MSS boundary condition
+    - sctp: update transport state when processing a dupcook packet
+    - sctp: update hb timer immediately after users change hb_interval
+    - cpupower: add Makefile dependencies for install targets
+    - RDMA/core: Require admin capabilities to set system parameters
+    - IB/mlx4: Fix the size of a buffer in add_port_entries()
+    - gpio: aspeed: fix the GPIO number passed to pinctrl_gpio_set_config()
+    - gpio: pxa: disable pinctrl calls for MMP_GPIO
+    - RDMA/cma: Fix truncation compilation warning in make_cma_ports
+    - RDMA/uverbs: Fix typo of sizeof argument
+    - RDMA/siw: Fix connection failure handling
+    - RDMA/mlx5: Fix NULL string error
+    - parisc: Restore __ldcw_align for PA-RISC 2.0 processors
+    - NFS: Fix a race in __nfs_list_for_each_server()
+    - ima: rework CONFIG_IMA dependency block
+    - [Config] Update IMA_BLACKLIST_KEYRING and IMA_LOAD_X509
+    - xen/events: replace evtchn_rwlock with RCU
+    - Linux 5.4.258
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 19 Jan 2024 17:10:04 +0800
+
+linux-ein (5.4.0-1045.52) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1045.52 -proposed tracker (LP: #2046958)
+
+  * While playing videos screen goes black and after some period of time it will
+    be restored (LP: #2043226)
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Add media bus format
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Add proper delay after resetting
+      display
+    - SAUCE: drm/panel: avd-tt101wx-cn-101-a: Fix timing when entering/exiting
+      sleep
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 21 Dec 2023 18:41:13 +0800
+
+linux-ein (5.4.0-1044.51) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1044.51 -proposed tracker (LP: #2046115)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] remove helper scripts
+
+  [ Ubuntu: 5.4.0-169.187 ]
+
+  * focal/linux: 5.4.0-169.187 -proposed tracker (LP: #2044375)
+  * USB bus error after upgrading to proposed kernel on lunar, jammy and focal
+    (LP: #2043197)
+    - USB: core: Fix oversight in SuperSpeed initialization
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] update annotations scripts
+
+  [ Ubuntu: 5.4.0-168.186 ]
+
+  * focal/linux: 5.4.0-168.186 -proposed tracker (LP: #2041652)
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284)
+    - erofs: ensure that the post-EOF tails are all zeroed
+    - ARM: pxa: remove use of symbol_get()
+    - mmc: au1xmmc: force non-modular build and remove symbol_get usage
+    - net: enetc: use EXPORT_SYMBOL_GPL for enetc_phc_index
+    - rtc: ds1685: use EXPORT_SYMBOL_GPL for ds1685_rtc_poweroff
+    - modules: only allow symbol_get of EXPORT_SYMBOL_GPL modules
+    - USB: serial: option: add Quectel EM05G variant (0x030e)
+    - USB: serial: option: add FOXCONN T99W368/T99W373 product
+    - HID: wacom: remove the battery when the EKR is off
+    - staging: rtl8712: fix race condition
+    - Bluetooth: btsdio: fix use after free bug in btsdio_remove due to race
+      condition
+    - serial: sc16is7xx: fix bug when first setting GPIO direction
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - fsi: master-ast-cf: Add MODULE_FIRMWARE macro
+    - nilfs2: fix general protection fault in nilfs_lookup_dirty_data_buffers()
+    - nilfs2: fix WARNING in mark_buffer_dirty due to discarded buffer reuse
+    - pinctrl: amd: Don't show `Invalid config param` errors
+    - 9p: virtio: make sure 'offs' is initialized in zc_request
+    - ASoC: da7219: Flush pending AAD IRQ when suspending
+    - ASoC: da7219: Check for failure reading AAD IRQ events
+    - ethernet: atheros: fix return value check in atl1c_tso_csum()
+    - vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
+    - m68k: Fix invalid .section syntax
+    - s390/dasd: use correct number of retries for ERP requests
+    - s390/dasd: fix hanging device after request requeue
+    - fs/nls: make load_nls() take a const parameter
+    - ASoc: codecs: ES8316: Fix DMIC config
+    - ASoC: atmel: Fix the 8K sample parameter in I2SC master
+    - platform/x86: intel: hid: Always call BTNL ACPI method
+    - platform/x86: huawei-wmi: Silence ambient light sensor
+    - security: keys: perform capable check only on privileged operations
+    - clk: fixed-mmio: make COMMON_CLK_FIXED_MMIO depend on HAS_IOMEM
+    - net: usb: qmi_wwan: add Quectel EM05GV2
+    - idmaengine: make FSL_EDMA and INTEL_IDMA64 depends on HAS_IOMEM
+    - scsi: qedi: Fix potential deadlock on &qedi_percpu->p_work_lock
+    - netlabel: fix shift wrapping bug in netlbl_catmap_setlong()
+    - bnx2x: fix page fault following EEH recovery
+    - sctp: handle invalid error codes without calling BUG()
+    - cifs: add a warning when the in-flight count goes negative
+    - scsi: storvsc: Always set no_report_opcodes
+    - ALSA: seq: oss: Fix racy open/close of MIDI devices
+    - platform/mellanox: Fix mlxbf-tmfifo not handling all virtio CONSOLE
+      notifications
+    - powerpc/32s: Fix assembler warning about r0
+    - udf: Check consistency of Space Bitmap Descriptor
+    - udf: Handle error when adding extent to a file
+    - Revert "net: macsec: preserve ingress frame ordering"
+    - reiserfs: Check the return value from __getblk()
+    - eventfd: Export eventfd_ctx_do_read()
+    - eventfd: prevent underflow for eventfd semaphores
+    - new helper: lookup_positive_unlocked()
+    - fs: Fix error checking for d_hash_and_lookup()
+    - tmpfs: verify {g,u}id mount options correctly
+    - OPP: Fix passing 0 to PTR_ERR in _opp_attach_genpd()
+    - x86/asm: Make more symbols local
+    - x86/boot: Annotate local functions
+    - x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved
+    - perf/imx_ddr: don't enable counter0 if none of 4 counters are used
+    - cpufreq: powernow-k8: Use related_cpus instead of cpus in driver.exit()
+    - bpf: Clear the probe_addr for uprobe
+    - tcp: tcp_enter_quickack_mode() should be static
+    - regmap: rbtree: Use alloc_flags for memory allocations
+    - spi: tegra20-sflash: fix to check return value of platform_get_irq() in
+      tegra_sflash_probe()
+    - can: gs_usb: gs_usb_receive_bulk_callback(): count RX overflow errors also
+      in case of OOM
+    - wifi: mwifiex: Fix OOB and integer underflow when rx packets
+    - mwifiex: switch from 'pci_' to 'dma_' API
+    - wifi: mwifiex: fix error recovery in PCIE buffer descriptor management
+    - crypto: stm32 - Properly handle pm_runtime_get failing
+    - Bluetooth: nokia: fix value check in nokia_bluetooth_serdev_probe()
+    - crypto: caam - fix unchecked return value error
+    - hwrng: iproc-rng200 - use semicolons rather than commas to separate
+      statements
+    - hwrng: iproc-rng200 - Implement suspend and resume calls
+    - lwt: Fix return values of BPF xmit ops
+    - lwt: Check LWTUNNEL_XMIT_CONTINUE strictly
+    - fs: ocfs2: namei: check return value of ocfs2_add_entry()
+    - wifi: mwifiex: fix memory leak in mwifiex_histogram_read()
+    - wifi: mwifiex: Fix missed return in oob checks failed path
+    - wifi: ath9k: fix races between ath9k_wmi_cmd and ath9k_wmi_ctrl_rx
+    - wifi: ath9k: protect WMI command response buffer replacement with a lock
+    - wifi: mwifiex: avoid possible NULL skb pointer dereference
+    - wifi: ath9k: use IS_ERR() with debugfs_create_dir()
+    - net: arcnet: Do not call kfree_skb() under local_irq_disable()
+    - mlxsw: i2c: Fix chunk size setting in output mailbox buffer
+    - mlxsw: i2c: Limit single transaction buffer size
+    - netrom: Deny concurrent connect().
+    - drm/bridge: tc358764: Fix debug print parameter order
+    - quota: avoid increasing DQST_LOOKUPS when iterating over dirty/inuse list
+    - quota: factor out dquot_write_dquot()
+    - quota: rename dquot_active() to inode_quota_active()
+    - quota: add new helper dquot_active()
+    - quota: fix dqput() to follow the guarantees dquot_srcu should provide
+    - drm/amdgpu: avoid integer overflow warning in amdgpu_device_resize_fb_bar()
+    - ARM: dts: BCM53573: Drop nonexistent "default-off" LED trigger
+    - ARM: dts: BCM53573: Add cells sizes to PCIe node
+    - ARM: dts: BCM53573: Use updated "spi-gpio" binding properties
+    - drm/etnaviv: fix dumping of active MMU context
+    - ARM: dts: s3c6410: move fixed clocks under root node in Mini6410
+    - ARM: dts: s3c6410: align node SROM bus node name with dtschema in Mini6410
+    - ARM: dts: s3c64xx: align pinctrl with dtschema
+    - ARM: dts: samsung: s3c6410-mini6410: correct ethernet reg addresses (split)
+    - ARM: dts: s5pv210: add RTC 32 KHz clock in SMDKV210
+    - ARM: dts: s5pv210: use defines for IRQ flags in SMDKV210
+    - ARM: dts: s5pv210: correct ethernet unit address in SMDKV210
+    - ARM: dts: s5pv210: add dummy 5V regulator for backlight on SMDKv210
+    - ARM: dts: samsung: s5pv210-smdkv210: correct ethernet reg addresses (split)
+    - drm: adv7511: Fix low refresh rate register for ADV7533/5
+    - ARM: dts: BCM53573: Fix Ethernet info for Luxul devices
+    - arm64: dts: qcom: sdm845: Add missing RPMh power domain to GCC
+    - drm/amdgpu: Update min() to min_t() in 'amdgpu_info_ioctl'
+    - md/bitmap: don't set max_write_behind if there is no write mostly device
+    - md/md-bitmap: hold 'reconfig_mutex' in backlog_store()
+    - drm/tegra: Remove superfluous error messages around platform_get_irq()
+    - drm/tegra: dpaux: Fix incorrect return value of platform_get_irq
+    - of: unittest: fix null pointer dereferencing in
+      of_unittest_find_node_by_name()
+    - drm/armada: Fix off-by-one error in armada_overlay_get_property()
+    - drm/panel: simple: Add missing connector type and pixel format for AUO
+      T215HVN01
+    - ima: Remove deprecated IMA_TRUSTED_KEYRING Kconfig
+    - [Config] Update annotations after CONFIG_IMA_TRUSTED_KEYRING removal
+    - drm/msm/mdp5: Don't leak some plane state
+    - smackfs: Prevent underflow in smk_set_cipso()
+    - audit: fix possible soft lockup in __audit_inode_child()
+    - drm/mediatek: Fix potential memory leak if vmap() fail
+    - of: unittest: Fix overlay type in apply/revert check
+    - ALSA: ac97: Fix possible error value of *rac97
+    - ipmi:ssif: Add check for kstrdup
+    - ipmi:ssif: Fix a memory leak when scanning for an adapter
+    - drivers: clk: keystone: Fix parameter judgment in _of_pll_clk_init()
+    - clk: sunxi-ng: Modify mismatched function name
+    - PCI: Mark NVIDIA T4 GPUs to avoid bus reset
+    - PCI: pciehp: Use RMW accessors for changing LNKCTL
+    - PCI/ASPM: Use RMW accessors for changing LNKCTL
+    - clk: imx: composite-8m: fix clock pauses when set_rate would be a no-op
+    - powerpc/fadump: reset dump area size if fadump memory reserve fails
+    - PCI: Add #defines for Enter Compliance, Transmit Margin
+    - drm/amdgpu: Correct Transmit Margin masks
+    - drm/amdgpu: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/amdgpu: Prefer pcie_capability_read_word()
+    - drm/amdgpu: Use RMW accessors for changing LNKCTL
+    - drm/radeon: Correct Transmit Margin masks
+    - drm/radeon: Replace numbers with PCI_EXP_LNKCTL2 definitions
+    - drm/radeon: Prefer pcie_capability_read_word()
+    - drm/radeon: Use RMW accessors for changing LNKCTL
+    - wifi: ath10k: Use RMW accessors for changing LNKCTL
+    - nfs/blocklayout: Use the passed in gfp flags
+    - powerpc/iommu: Fix notifiers being shared by PCI and VIO buses
+    - jfs: validate max amount of blocks before allocation.
+    - fs: lockd: avoid possible wrong NULL parameter
+    - NFSD: da_addr_body field missing in some GETDEVICEINFO replies
+    - NFS: Guard against READDIR loop when entry names exceed MAXNAMELEN
+    - media: v4l2-fwnode: fix v4l2_fwnode_parse_link handling
+    - media: v4l2-fwnode: simplify v4l2_fwnode_parse_link
+    - media: v4l2-core: Fix a potential resource leak in v4l2_fwnode_parse_link()
+    - drivers: usb: smsusb: fix error handling code in smsusb_init_device
+    - media: dib7000p: Fix potential division by zero
+    - media: dvb-usb: m920x: Fix a potential memory leak in m920x_i2c_xfer()
+    - media: cx24120: Add retval check for cx24120_message_send()
+    - media: mediatek: vcodec: Return NULL if no vdec_fb is found
+    - usb: phy: mxs: fix getting wrong state with mxs_phy_is_otg_host()
+    - scsi: iscsi: Add strlen() check in iscsi_if_set{_host}_param()
+    - scsi: be2iscsi: Add length check when parsing nlattrs
+    - scsi: qla4xxx: Add length check when parsing nlattrs
+    - serial: sprd: getting port index via serial aliases only
+    - serial: sprd: remove redundant sprd_port cleanup
+    - serial: sprd: Assign sprd_port after initialized to avoid wrong access
+    - serial: sprd: Fix DMA buffer leak issue
+    - x86/APM: drop the duplicate APM_MINOR_DEV macro
+    - scsi: qedf: Do not touch __user pointer in
+      qedf_dbg_stop_io_on_error_cmd_read() directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_debug_cmd_read()
+      directly
+    - scsi: qedf: Do not touch __user pointer in qedf_dbg_fp_int_cmd_read()
+      directly
+    - coresight: tmc: Explicit type conversions to prevent integer overflow
+    - dma-buf/sync_file: Fix docs syntax
+    - driver core: test_async: fix an error code
+    - IB/uverbs: Fix an potential error pointer dereference
+    - iommu/vt-d: Fix to flush cache of PASID directory table
+    - media: go7007: Remove redundant if statement
+    - USB: gadget: f_mass_storage: Fix unused variable warning
+    - media: i2c: ov5640: Configure HVP lines in s_power callback
+    - media: ov5640: Enable MIPI interface in ov5640_set_power_mipi()
+    - media: i2c: ov2680: Set V4L2_CTRL_FLAG_MODIFY_LAYOUT on flips
+    - media: ov2680: Remove auto-gain and auto-exposure controls
+    - media: ov2680: Fix ov2680_bayer_order()
+    - media: ov2680: Fix vflip / hflip set functions
+    - media: ov2680: Fix regulators being left enabled on ov2680_power_on() errors
+    - scsi: core: Use 32-bit hostnum in scsi_host_lookup()
+    - scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
+    - serial: tegra: handle clk prepare error in tegra_uart_hw_init()
+    - amba: bus: fix refcount leak
+    - Revert "IB/isert: Fix incorrect release of isert connection"
+    - RDMA/siw: Balance the reference of cep->kref in the error path
+    - RDMA/siw: Correct wrong debug message
+    - HID: logitech-dj: Fix error handling in logi_dj_recv_switch_to_dj_mode()
+    - HID: multitouch: Correct devm device reference for hidinput input_dev name
+    - x86/speculation: Mark all Skylake CPUs as vulnerable to GDS
+    - tracing: Fix race issue between cpu buffer write and swap
+    - phy/rockchip: inno-hdmi: use correct vco_div_5 macro on rk3328
+    - phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 recalc_rate
+    - phy/rockchip: inno-hdmi: do not power on rk3328 post pll on reg write
+    - rpmsg: glink: Add check for kstrdup
+    - mtd: rawnand: fsmc: handle clk prepare error in fsmc_nand_resume()
+    - um: Fix hostaudio build errors
+    - dmaengine: ste_dma40: Add missing IRQ check in d40_probe
+    - cpufreq: Fix the race condition while updating the transition_task of policy
+    - virtio_ring: fix avail_wrap_counter in virtqueue_add_packed
+    - skbuff: skb_segment, Call zero copy functions before using skbuff frags
+    - PM / devfreq: Fix leak in devfreq_dev_release()
+    - ALSA: pcm: Fix missing fixup call in compat hw_refine ioctl
+    - ipmi_si: fix a memleak in try_smi_init()
+    - ARM: OMAP2+: Fix -Warray-bounds warning in _pwrdm_state_switch()
+    - backlight/gpio_backlight: Compare against struct fb_info.device
+    - backlight/bd6107: Compare against struct fb_info.device
+    - backlight/lv5207lp: Compare against struct fb_info.device
+    - xtensa: PMU: fix base address for the newer hardware
+    - media: dvb: symbol fixup for dvb_attach()
+    - ntb: Drop packets when qp link is down
+    - ntb: Clean up tx tail index on link down
+    - ntb: Fix calculation ntb_transport_tx_free_entry()
+    - Revert "PCI: Mark NVIDIA T4 GPUs to avoid bus reset"
+    - procfs: block chmod on /proc/thread-self/comm
+    - parisc: Fix /proc/cpuinfo output for lscpu
+    - dlm: fix plock lookup when using multiple lockspaces
+    - dccp: Fix out of bounds access in DCCP error handler
+    - X.509: if signature is unsupported skip validation
+    - net: handle ARPHRD_PPP in dev_is_mac_header_xmit()
+    - fsverity: skip PKCS#7 parser when keyring is empty
+    - pstore/ram: Check start of empty przs during init
+    - s390/ipl: add missing secure/has_secure file to ipl type 'unknown'
+    - crypto: stm32 - fix loop iterating through scatterlist for DMA
+    - cpufreq: brcmstb-avs-cpufreq: Fix -Warray-bounds bug
+    - sc16is7xx: Set iobase to device index
+    - serial: sc16is7xx: fix broken port 0 uart init
+    - usb: typec: tcpci: clear the fault status bit
+    - udf: initialize newblock to 0
+    - drm: fix double free for gbo in drm_gem_vram_init and drm_gem_vram_create
+    - net/ipv6: SKB symmetric hash should incorporate transport ports
+    - scsi: qla2xxx: fix inconsistent TMF timeout
+    - scsi: qla2xxx: Fix erroneous link up failure
+    - scsi: qla2xxx: Turn off noisy message log
+    - scsi: qla2xxx: Remove unsupported ql2xenabledif option
+    - fbdev/ep93xx-fb: Do not assign to struct fb_info.dev
+    - drm/ast: Fix DRAM init on AST2200
+    - lib/test_meminit: allocate pages up to order MAX_ORDER
+    - parisc: led: Fix LAN receive and transmit LEDs
+    - parisc: led: Reduce CPU overhead for disk & lan LED computation
+    - clk: qcom: gcc-mdm9615: use proper parent for pll0_vote clock
+    - soc: qcom: qmi_encdec: Restrict string length in decode
+    - NFSv4/pnfs: minor fix for cleanup path in nfs4_get_device_info
+    - kconfig: fix possible buffer overflow
+    - perf annotate bpf: Don't enclose non-debug code with an assert()
+    - x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm()
+    - perf top: Don't pass an ERR_PTR() directly to perf_session__delete()
+    - watchdog: intel-mid_wdt: add MODULE_ALIAS() to allow auto-load
+    - pwm: lpc32xx: Remove handling of PWM channels
+    - sctp: annotate data-races around sk->sk_wmem_queued
+    - ipv4: annotate data-races around fi->fib_dead
+    - net: read sk->sk_family once in sk_mc_loop()
+    - igb: disable virtualization features on 82580
+    - veth: Fixing transmit return status for dropped packets
+    - net: ipv6/addrconf: avoid integer underflow in ipv6_create_tempaddr
+    - af_unix: Fix data-races around user->unix_inflight.
+    - af_unix: Fix data-race around unix_tot_inflight.
+    - af_unix: Fix data-races around sk->sk_shutdown.
+    - af_unix: Fix data race around sk->sk_err.
+    - kcm: Destroy mutex in kcm_exit_net()
+    - igc: Change IGC_MIN to allow set rx/tx value between 64 and 80
+    - igbvf: Change IGBVF_MIN to allow set rx/tx value between 64 and 80
+    - igb: Change IGB_MIN to allow set rx/tx value between 64 and 80
+    - s390/zcrypt: don't leak memory if dev_set_name() fails
+    - idr: fix param name in idr_alloc_cyclic() doc
+    - ip_tunnels: use DEV_STATS_INC()
+    - net: hns3: fix the port information display when sfp is absent
+    - sh: boards: Fix CEU buffer size passed to dma_declare_coherent_memory()
+    - ata: sata_gemini: Add missing MODULE_DESCRIPTION
+    - ata: pata_ftide010: Add missing MODULE_DESCRIPTION
+    - fuse: nlookup missing decrement in fuse_direntplus_link
+    - btrfs: don't start transaction when joining with TRANS_JOIN_NOSTART
+    - btrfs: use the correct superblock to compare fsid in btrfs_validate_super
+    - mtd: rawnand: brcmnand: Fix crash during the panic_write
+    - mtd: rawnand: brcmnand: Fix potential out-of-bounds access in oob write
+    - mtd: rawnand: brcmnand: Fix potential false time out warning
+    - perf hists browser: Fix hierarchy mode header
+    - perf tools: Handle old data in PERF_RECORD_ATTR
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request payload handling
+    - usb: typec: tcpm: Refactor tcpm_handle_vdm_request
+    - usb: typec: bus: verify partner exists in typec_altmode_attention
+    - ARM: dts: BCM5301X: Extend RAM to full 256MB for Linksys EA6500 V2
+    - clk: imx8mm: Move 1443X/1416X PLL clock structure to common place
+    - net: ipv4: fix one memleak in __inet_del_ifa()
+    - net: ethernet: mvpp2_main: fix possible OOB write in
+      mvpp2_ethtool_get_rxnfc()
+    - net: ethernet: mtk_eth_soc: fix possible NULL pointer dereference in
+      mtk_hwlro_get_fdir_all()
+    - r8152: check budget for r8152_poll()
+    - kcm: Fix memory leak in error path of kcm_sendmsg()
+    - platform/mellanox: mlxbf-tmfifo: Drop the Rx packet if no more descriptors
+    - mlxbf-tmfifo: sparse tags for config access
+    - platform/mellanox: mlxbf-tmfifo: Drop jumbo frames
+    - net/tls: do not free tls_rec on async operation in bpf_exec_tx_verdict()
+    - ixgbe: fix timestamp configuration code
+    - kcm: Fix error handling for SOCK_DGRAM in kcm_sendmsg().
+    - drm/amd/display: Fix a bug when searching for insert_above_mpcc
+    - parisc: Drop loops_per_jiffy from per_cpu struct
+    - autofs: fix memory leak of waitqueues in autofs_catatonic_mode
+    - btrfs: output extra debug info if we failed to find an inline backref
+    - locks: fix KASAN: use-after-free in trace_event_raw_event_filelock_lock
+    - ACPICA: Add AML_NO_OPERAND_RESOLVE flag to Timer
+    - kernel/fork: beware of __put_task_struct() calling context
+    - ACPI: video: Add backlight=native DMI quirk for Lenovo Ideapad Z470
+    - perf/smmuv3: Enable HiSilicon Erratum 162001900 quirk for HIP08/09
+    - hw_breakpoint: fix single-stepping when using bpf_overflow_handler
+    - devlink: remove reload failed checks in params get/set callbacks
+    - wifi: ath9k: fix printk specifier
+    - wifi: mwifiex: fix fortify warning
+    - crypto: lib/mpi - avoid null pointer deref in mpi_cmp_ui()
+    - tpm_tis: Resend command to recover from data transfer errors
+    - mmc: sdhci-esdhc-imx: improve ESDHC_FLAG_ERR010450
+    - alx: fix OOB-read compiler warning
+    - wifi: mac80211_hwsim: drop short frames
+    - drm/exynos: fix a possible null-pointer dereference due to data race in
+      exynos_drm_crtc_atomic_disable()
+    - bus: ti-sysc: Configure uart quirks for k3 SoC
+    - md: raid1: fix potential OOB in raid1_remove_disk()
+    - ext2: fix datatype of block number in ext2_xattr_set2()
+    - fs/jfs: prevent double-free in dbUnmount() after failed jfs_remount()
+    - jfs: fix invalid free of JFS_IP(ipimap)->i_imap in diUnmount
+    - powerpc/pseries: fix possible memory leak in ibmebus_bus_init()
+    - media: dvb-usb-v2: af9035: Fix null-ptr-deref in af9035_i2c_master_xfer
+    - media: dw2102: Fix null-ptr-deref in dw2102_i2c_transfer()
+    - media: af9005: Fix null-ptr-deref in af9005_i2c_xfer
+    - media: anysee: fix null-ptr-deref in anysee_master_xfer
+    - media: az6007: Fix null-ptr-deref in az6007_i2c_xfer()
+    - media: tuners: qt1010: replace BUG_ON with a regular error
+    - media: pci: cx23885: replace BUG with error return
+    - usb: gadget: fsl_qe_udc: validate endpoint index for ch9 udc
+    - scsi: target: iscsi: Fix buffer overflow in lio_target_nacl_info_show()
+    - serial: cpm_uart: Avoid suspicious locking
+    - media: pci: ipu3-cio2: Initialise timing struct to avoid a compiler warning
+    - kobject: Add sanity check for kset->kobj.ktype in kset_register()
+    - tools features: Add feature test to check if libbfd has buildid support
+    - perf jevents: Make build dependency on test JSONs
+    - perf tools: Add an option to build without libbfd
+    - btrfs: move btrfs_pinned_by_swapfile prototype into volumes.h
+    - btrfs: add a helper to read the superblock metadata_uuid
+    - btrfs: compare the correct fsid/metadata_uuid in btrfs_validate_super
+    - selftests: tracing: Fix to unmount tracefs for recovering environment
+    - md/raid1: fix error: ISO C90 forbids mixed declarations
+    - attr: block mode changes of symlinks
+    - btrfs: fix lockdep splat and potential deadlock after failure running
+      delayed items
+    - tracing: Have current_trace inc the trace array ref count
+    - tracing: Have option files inc the trace array ref count
+    - nfsd: fix change_info in NFSv4 RENAME replies
+    - tracefs: Add missing lockdown check to tracefs_create_dir()
+    - i2c: aspeed: Reset the i2c controller when timeout occurs
+    - scsi: megaraid_sas: Fix deadlock on firmware crashdump
+    - ext4: fix rec_len verify error
+    - mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
+    - drm/amdgpu: fix amdgpu_cs_p1_user_fence
+    - Linux 5.4.257
+  * Focal update: v5.4.257 upstream stable release (LP: #2040284) //
+    CVE-2023-39189
+    - netfilter: nfnetlink_osf: avoid OOB read
+  * CVE-2023-45871
+    - igb: set max size RX buffer when store bad packet is enabled
+  * CVE-2023-39193
+    - netfilter: xt_sctp: validate the flag_info count
+  * CVE-2023-39192
+    - netfilter: xt_u32: validate user space input
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+  * CVE-2023-5717
+    - perf: Disallow mis-matched inherited group reads
+  * CVE-2023-5178
+    - nvmet-tcp: move send/recv error handling in the send/recv methods instead of
+      call-sites
+    - nvmet-tcp: Fix a possible UAF in queue intialization setup
+  * CVE-2023-42754
+    - ipv4: fix null-deref in ipv4_link_failure
+  * Focal update: v5.4.256 upstream stable release (LP: #2039446)
+    - powerpc/pmac/smp: Avoid unused-variable warnings
+    - powerpc/pmac/smp: Drop unnecessary volatile qualifier
+    - Revert "MIPS: Alchemy: fix dbdma2"
+    - Linux 5.4.256
+  * Focal update: v5.4.255 upstream stable release (LP: #2039440)
+    - mmc: sdhci_f_sdh30: convert to devm_platform_ioremap_resource
+    - mmc: sdhci-f-sdh30: Replace with sdhci_pltfm
+    - selftests: forwarding: tc_flower: Relax success criterion
+    - macsec: Fix traffic counters/statistics
+    - macsec: use DEV_STATS_INC()
+    - drm/radeon: Fix integer overflow in radeon_cs_parser_init
+    - ALSA: emu10k1: roll up loops in DSP setup code for Audigy
+    - quota: Properly disable quotas when add_dquot_ref() fails
+    - quota: fix warning in dqgrab()
+    - HID: add quirk for 03f0:464a HP Elite Presenter Mouse
+    - ovl: check type and offset of struct vfsmount in ovl_entry
+    - udf: Fix uninitialized array access for some pathnames
+    - fs: jfs: Fix UBSAN: array-index-out-of-bounds in dbAllocDmapLev
+    - MIPS: dec: prom: Address -Warray-bounds warning
+    - FS: JFS: Fix null-ptr-deref Read in txBegin
+    - FS: JFS: Check for read-only mounted filesystem in txBegin
+    - media: v4l2-mem2mem: add lock to protect parameter num_rdy
+    - media: platform: mediatek: vpu: fix NULL ptr dereference
+    - usb: chipidea: imx: don't request QoS for imx8ulp
+    - gfs2: Fix possible data races in gfs2_show_options()
+    - pcmcia: rsrc_nonstatic: Fix memory leak in nonstatic_release_resource_db()
+    - Bluetooth: L2CAP: Fix use-after-free
+    - drm/amdgpu: Fix potential fence use-after-free v2
+    - ALSA: hda/realtek: Add quirks for Unis H3C Desktop B760 & Q760
+    - ALSA: hda: fix a possible null-pointer dereference due to data race in
+      snd_hdac_regmap_sync()
+    - powerpc/kasan: Disable KCOV in KASAN code
+    - IMA: allow/fix UML builds
+    - iio: add addac subdirectory
+    - iio: adc: stx104: Utilize iomap interface
+    - iio: adc: stx104: Implement and utilize register structures
+    - iio: stx104: Move to addac subdirectory
+    - iio: addac: stx104: Fix race condition for stx104_write_raw()
+    - iio: addac: stx104: Fix race condition when converting analog-to-digital
+    - iommu/amd: Fix "Guest Virtual APIC Table Root Pointer" configuration in IRTE
+    - PM-runtime: add tracepoints for usage_count changes
+    - PM: runtime: Add pm_runtime_get_if_active()
+    - ALSA: hda: Fix unhandled register update during auto-suspend period
+    - irqchip/mips-gic: Get rid of the reliance on irq_cpu_online()
+    - irqchip/mips-gic: Use raw spinlock for gic_lock
+    - interconnect: Move internal structs into a separate file
+    - interconnect: Add helpers for enabling/disabling a path
+    - usb: dwc3: qcom: Add helper functions to enable,disable wake irqs
+    - USB: dwc3: qcom: fix NULL-deref on suspend
+    - mmc: bcm2835: fix deferred probing
+    - mmc: sunxi: fix deferred probing
+    - leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on dev rename
+    - tracing/probes: Have process_fetch_insn() take a void * instead of pt_regs
+    - tracing/probes: Fix to update dynamic data counter if fetcharg uses it
+    - net/ncsi: Fix gma flag setting after response
+    - nfsd4: kill warnings on testing stateids with mismatched clientids
+    - nfsd: Remove incorrect check in nfsd4_validate_stateid
+    - virtio-mmio: convert to devm_platform_ioremap_resource
+    - virtio-mmio: Use to_virtio_mmio_device() to simply code
+    - virtio-mmio: don't break lifecycle of vm_dev
+    - i2c: bcm-iproc: Fix bcm_iproc_i2c_isr deadlock issue
+    - fbdev: mmp: fix value check in mmphw_probe()
+    - powerpc/rtas_flash: allow user copy to flash block cache objects
+    - tty: serial: fsl_lpuart: Clear the error flags by writing 1 for lpuart32
+      platforms
+    - btrfs: fix BUG_ON condition in btrfs_cancel_balance
+    - net: xfrm: Fix xfrm_address_filter OOB read
+    - net: af_key: fix sadb_x_filter validation
+    - xfrm: interface: rename xfrm_interface.c to xfrm_interface_core.c
+    - xfrm: fix slab-use-after-free in decode_session6
+    - ip6_vti: fix slab-use-after-free in decode_session6
+    - ip_vti: fix potential slab-use-after-free in decode_session6
+    - selftests: mirror_gre_changes: Tighten up the TTL test match
+    - ipvs: fix racy memcpy in proc_do_sync_threshold
+    - netfilter: nft_dynset: disallow object maps
+    - team: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - i40e: fix misleading debug logs
+    - net: dsa: mv88e6xxx: Wait for EEPROM done before HW reset
+    - sock: Fix misuse of sk_under_memory_pressure()
+    - net: do not allow gso_size to be set to GSO_BY_FRAGS
+    - bus: ti-sysc: Improve reset to work with modules with no sysconfig
+    - bus: ti-sysc: Flush posted write on enable before reset
+    - ARM: dts: imx7s: Drop dma-apb interrupt-names
+    - ARM: dts: imx: Adjust dma-apbh node name
+    - ARM: dts: imx: Set default tuning step for imx7d usdhc
+    - ARM: dts: imx: Set default tuning step for imx6sx usdhc
+    - ASoC: rt5665: add missed regulator_bulk_disable
+    - ASoC: meson: axg-tdm-formatter: fix channel slot allocation
+    - serial: 8250: Fix oops for port->pm on uart_change_pm()
+    - ALSA: usb-audio: Add support for Mythware XA001AU capture and playback
+      interfaces.
+    - cifs: Release folio lock on fscache read hit.
+    - mmc: wbsd: fix double mmc_free_host() in wbsd_init()
+    - mmc: block: Fix in_flight[issue_type] value error
+    - netfilter: set default timeout to 3 secs for sctp shutdown send and recv
+      state
+    - virtio-net: set queues after driver_ok
+    - net: fix the RTO timer retransmitting skb every 1ms if linear option is
+      enabled
+    - net: xfrm: Amend XFRMA_SEC_CTX nla_policy structure
+    - mmc: f-sdh30: fix order of function calls in sdhci_f_sdh30_remove
+    - net: phy: broadcom: stub c45 read/write for 54810
+    - PCI: acpiphp: Reassign resources on bridge if necessary
+    - dlm: improve plock logging if interrupted
+    - dlm: replace usage of found with dedicated list iterator variable
+    - fs: dlm: add pid to debug log
+    - fs: dlm: change plock interrupted message to debug again
+    - fs: dlm: use dlm_plock_info for do_unlock_close
+    - fs: dlm: fix mismatch of plock results from userspace
+    - MIPS: cpu-features: Enable octeon_cache by cpu_type
+    - MIPS: cpu-features: Use boot_cpu_type for CPU type based features
+    - fbdev: Improve performance of sys_imageblit()
+    - fbdev: Fix sys_imageblit() for arbitrary image widths
+    - fbdev: fix potential OOB read in fast_imageblit()
+    - dm integrity: increase RECALC_SECTORS to improve recalculate speed
+    - dm integrity: reduce vmalloc space footprint on 32-bit architectures
+    - ALSA: pcm: Set per-card upper limit of PCM buffer allocations
+    - ALSA: pcm: Use SG-buffer only when direct DMA is available
+    - ALSA: pcm: Fix potential data race at PCM memory allocation helpers
+    - regmap: Account for register length in SMBus I/O limits
+    - ASoC: fsl_sai: Refine enable/disable TE/RE sequence in trigger()
+    - ASoC: fsl_sai: Add new added registers and new bit definition
+    - ASoC: fsl_sai: Disable bit clock with transmitter
+    - drm/amd/display: do not wait for mpc idle if tg is disabled
+    - drm/amd/display: check TG is non-null before checking if enabled
+    - tracing: Fix memleak due to race between current_tracer and trace
+    - octeontx2-af: SDP: fix receive link config
+    - sock: annotate data-races around prot->memory_pressure
+    - dccp: annotate data-races in dccp_poll()
+    - ipvlan: Fix a reference count leak warning in ipvlan_ns_exit()
+    - net: bgmac: Fix return value check for fixed_phy_register()
+    - net: bcmgenet: Fix return value check for fixed_phy_register()
+    - net: validate veth and vxcan peer ifindexes
+    - igb: Avoid starting unnecessary workqueues
+    - net/sched: fix a qdisc modification with ambiguous command request
+    - net: remove bond_slave_has_mac_rcu()
+    - bonding: fix macvlan over alb bond support
+    - ibmveth: Use dcbf rather than dcbfl
+    - NFSv4: Fix dropped lock for racing OPEN and delegation return
+    - clk: Fix slab-out-of-bounds error in devm_clk_release()
+    - nfsd: Fix race to FREE_STATEID and cl_revoked
+    - batman-adv: Trigger events for auto adjusted MTU
+    - batman-adv: Don't increase MTU when set by user
+    - batman-adv: Do not get eth header before batadv_check_management_packet
+    - batman-adv: Fix TT global entry leak when client roamed back
+    - batman-adv: Fix batadv_v_ogm_aggr_send memory leak
+    - batman-adv: Hold rtnl lock during MTU update via netlink
+    - lib/clz_ctz.c: Fix __clzdi2() and __ctzdi2() for 32-bit kernels
+    - radix tree: remove unused variable
+    - media: vcodec: Fix potential array out-of-bounds in encoder queue_setup
+    - PCI: acpiphp: Use pci_assign_unassigned_bridge_resources() only for non-root
+      bus
+    - drm/display/dp: Fix the DP DSC Receiver cap size
+    - mm: allow a controlled amount of unfairness in the page lock
+    - rtnetlink: Reject negative ifindexes in RTM_NEWLINK
+    - ALSA: pcm: Fix build error on m68k and others
+    - Revert "ALSA: pcm: Use SG-buffer only when direct DMA is available"
+    - interconnect: Do not skip aggregation for disabled paths
+    - ALSA: pcm: Check for null pointer of pointer substream before dereferencing
+      it
+    - Documentation/sysctl: document page_lock_unfairness
+    - irqchip/mips-gic: Don't touch vl_map if a local interrupt is not routable
+    - scsi: snic: Fix double free in snic_tgt_create()
+    - scsi: core: raid_class: Remove raid_component_add()
+    - clk: Fix undefined reference to `clk_rate_exclusive_{get,put}'
+    - pinctrl: renesas: rza2: Add lock around
+      pinctrl_generic{{add,remove}_group,{add,remove}_function}
+    - dma-buf/sw_sync: Avoid recursive lock during fence signal
+    - Linux 5.4.255
+  * Focal update: v5.4.254 upstream stable release (LP: #2039291)
+    - mmc: moxart: read scr register without changing byte order
+    - ipv6: adjust ndisc_is_useropt() to also return true for PIO
+    - dmaengine: pl330: Return DMA_PAUSED when transaction is paused
+    - drm/nouveau/gr: enable memory loads on helper invocation on all channels
+    - radix tree test suite: fix incorrect allocation size for pthreads
+    - nilfs2: fix use-after-free of nilfs_root in dirtying inodes via iput
+    - iio: cros_ec: Fix the allocation size for cros_ec_command
+    - binder: fix memory leak in binder_init()
+    - usb-storage: alauda: Fix uninit-value in alauda_check_media()
+    - usb: dwc3: Properly handle processing of pending events
+    - usb: common: usb-conn-gpio: Prevent bailing out if initial role is none
+    - x86/cpu/amd: Enable Zenbleed fix for AMD Custom APU 0405
+    - x86/mm: Fix VDSO and VVAR placement on 5-level paging machines
+    - x86: Move gds_ucode_mitigated() declaration to header
+    - drm/nouveau/disp: Revert a NULL check inside nouveau_connector_get_modes
+    - selftests/rseq: Fix build with undefined __weak
+    - mISDN: Update parameter type of dsp_cmx_send()
+    - net/packet: annotate data-races around tp->status
+    - bonding: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
+    - dccp: fix data-race around dp->dccps_mss_cache
+    - drivers: net: prevent tun_build_skb() to exceed the packet size limit
+    - IB/hfi1: Fix possible panic during hotplug remove
+    - wifi: cfg80211: fix sband iftype data lookup for AP_VLAN
+    - dmaengine: mcf-edma: Fix a potential un-allocated memory access
+    - net/mlx5: Allow 0 for total host VFs
+    - ibmvnic: Handle DMA unmapping of login buffs in release functions
+    - btrfs: don't stop integrity writeback too early
+    - btrfs: set cache_block_group_error if we find an error
+    - nvme-tcp: fix potential unbalanced freeze & unfreeze
+    - nvme-rdma: fix potential unbalanced freeze & unfreeze
+    - netfilter: nf_tables: report use refcount overflow
+    - scsi: core: Fix legacy /proc parsing buffer overflow
+    - scsi: storvsc: Fix handling of virtual Fibre Channel timeouts
+    - scsi: 53c700: Check that command slot is not NULL
+    - scsi: snic: Fix possible memory leak if device_add() fails
+    - scsi: core: Fix possible memory leak if device_add() fails
+    - alpha: remove __init annotation from exported page_is_ram()
+    - sch_netem: fix issues in netem_change() vs get_dist_table()
+    - Linux 5.4.254
+  * Focal update: v5.4.253 upstream stable release (LP: #2038652)
+    - jbd2: fix incorrect code style
+    - jbd2: fix kernel-doc markups
+    - jbd2: remove redundant buffer io error checks
+    - jbd2: recheck chechpointing non-dirty buffer
+    - jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint
+    - gpio: tps68470: Make tps68470_gpio_output() always set the initial value
+    - bcache: remove 'int n' from parameter list of bch_bucket_alloc_set()
+    - bcache: Fix __bch_btree_node_alloc to make the failure behavior consistent
+    - btrfs: qgroup: catch reserved space leaks at unmount time
+    - btrfs: fix race between quota disable and relocation
+    - btrfs: fix extent buffer leak after tree mod log failure at split_node()
+    - ext4: rename journal_dev to s_journal_dev inside ext4_sb_info
+    - ext4: Fix reusing stale buffer heads from last failed mounting
+    - PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+    - PCI/ASPM: Factor out pcie_wait_for_retrain()
+    - PCI/ASPM: Avoid link retraining race
+    - dlm: cleanup plock_op vs plock_xop
+    - dlm: rearrange async condition return
+    - fs: dlm: interrupt posix locks only when process is killed
+    - ftrace: Add information on number of page groups allocated
+    - ftrace: Check if pages were allocated before calling free_pages()
+    - ftrace: Store the order of pages allocated in ftrace_page
+    - ftrace: Fix possible warning on checking all pages used in
+      ftrace_process_locs()
+    - pwm: meson: Remove redundant assignment to variable fin_freq
+    - pwm: meson: Simplify duplicated per-channel tracking
+    - pwm: meson: fix handling of period/duty if greater than UINT_MAX
+    - scsi: qla2xxx: Fix inconsistent format argument type in qla_os.c
+    - scsi: qla2xxx: Array index may go out of bound
+    - uapi: General notification queue definitions
+    - keys: Fix linking a duplicate key to a keyring's assoc_array
+    - ext4: fix to check return value of freeze_bdev() in ext4_shutdown()
+    - i40e: Fix an NULL vs IS_ERR() bug for debugfs_create_dir()
+    - vxlan: calculate correct header length for GPE
+    - phy: hisilicon: Fix an out of bounds check in hisi_inno_phy_probe()
+    - ethernet: atheros: fix return value check in atl1e_tso_csum()
+    - ipv6 addrconf: fix bug where deleting a mngtmpaddr can create a new
+      temporary address
+    - bonding: reset bond's flags when down link is P2P device
+    - team: reset team's flags when down link is P2P device
+    - platform/x86: msi-laptop: Fix rfkill out-of-sync on MSI Wind U100
+    - net/sched: mqprio: refactor nlattr parsing to a separate function
+    - net/sched: mqprio: add extack to mqprio_parse_nlattr()
+    - net/sched: mqprio: Add length check for TCA_MQPRIO_{MAX/MIN}_RATE64
+    - benet: fix return value check in be_lancer_xmit_workarounds()
+    - RDMA/mlx4: Make check for invalid flags stricter
+    - drm/msm/dpu: drop enum dpu_core_perf_data_bus_id
+    - drm/msm/adreno: Fix snapshot BINDLESS_DATA size
+    - drm/msm: Fix IS_ERR_OR_NULL() vs NULL check in a5xx_submit_in_rb()
+    - ASoC: fsl_spdif: Silence output on stop
+    - block: Fix a source code comment in include/uapi/linux/blkzoned.h
+    - dm raid: fix missing reconfig_mutex unlock in raid_ctr() error paths
+    - ata: pata_ns87415: mark ns87560_tf_read static
+    - ring-buffer: Fix wrong stat of cpu_buffer->read
+    - tracing: Fix warning in trace_buffered_event_disable()
+    - serial: 8250_dw: Preserve original value of DLF register
+    - serial: sifive: Fix sifive_serial_console_setup() section
+    - USB: serial: option: support Quectel EM060K_128
+    - USB: serial: option: add Quectel EC200A module support
+    - USB: serial: simple: add Kaufmann RKS+CAN VCP
+    - USB: serial: simple: sort driver entries
+    - can: gs_usb: gs_can_close(): add missing set of CAN state to
+      CAN_STATE_STOPPED
+    - Revert "usb: dwc3: core: Enable AutoRetry feature in the controller"
+    - usb: dwc3: pci: skip BYT GPIO lookup table for hardwired phy
+    - usb: dwc3: don't reset device side if dwc3 was configured as host-only
+    - usb: ohci-at91: Fix the unhandle interrupt when resume
+    - USB: quirks: add quirk for Focusrite Scarlett
+    - usb: xhci-mtk: set the dma max_seg_size
+    - Revert "usb: xhci: tegra: Fix error check"
+    - Documentation: security-bugs.rst: update preferences when dealing with the
+      linux-distros group
+    - Documentation: security-bugs.rst: clarify CVE handling
+    - staging: ks7010: potential buffer overflow in ks_wlan_set_encode_ext()
+    - hwmon: (nct7802) Fix for temp6 (PECI1) processed even if PECI1 disabled
+    - btrfs: check for commit error at btrfs_attach_transaction_barrier()
+    - tpm_tis: Explicitly check for error code
+    - irq-bcm6345-l1: Do not assume a fixed block to cpu mapping
+    - btrfs: check if the transaction was aborted at btrfs_wait_for_commit()
+    - virtio-net: fix race between set queues and probe
+    - s390/dasd: fix hanging device after quiesce/resume
+    - ASoC: wm8904: Fill the cache for WM8904_ADC_TEST_0 register
+    - dm cache policy smq: ensure IO doesn't prevent cleaner policy progress
+    - ACPI: processor: perflib: Use the "no limit" frequency QoS
+    - ACPI: processor: perflib: Avoid updating frequency QoS unnecessarily
+    - cpufreq: intel_pstate: Drop ACPI _PSS states table patching
+    - btrfs: qgroup: remove one-time use variables for quota_root checks
+    - btrfs: qgroup: return ENOTCONN instead of EINVAL when quotas are not enabled
+    - ASoC: cs42l51: fix driver to properly autoload with automatic module loading
+    - arm64: Add AMPERE1 to the Spectre-BHB affected list
+    - arm64: Fix bit-shifting UB in the MIDR_CPU_MODEL() macro
+    - perf: Fix function pointer case
+    - loop: Select I/O scheduler 'none' from inside add_disk()
+    - word-at-a-time: use the same return type for has_zero regardless of
+      endianness
+    - KVM: s390: fix sthyi error handling
+    - net/mlx5: DR, fix memory leak in mlx5dr_cmd_create_reformat_ctx
+    - net/mlx5e: fix return value check in mlx5e_ipsec_remove_trailer()
+    - rtnetlink: let rtnl_bridge_setlink checks IFLA_BRIDGE_MODE length
+    - perf test uprobe_from_different_cu: Skip if there is no gcc
+    - net: sched: cls_u32: Fix match key mis-addressing
+    - mISDN: hfcpci: Fix potential deadlock on &hc->lock
+    - net: annotate data-races around sk->sk_max_pacing_rate
+    - net: add missing READ_ONCE(sk->sk_rcvlowat) annotation
+    - net: add missing READ_ONCE(sk->sk_sndbuf) annotation
+    - net: add missing READ_ONCE(sk->sk_rcvbuf) annotation
+    - net: add missing data-race annotations around sk->sk_peek_off
+    - net: add missing data-race annotation for sk_ll_usec
+    - bpf: sockmap: Remove preempt_disable in sock_map_sk_acquire
+    - driver core: add device probe log helper
+    - net: ll_temac: Switch to use dev_err_probe() helper
+    - net: ll_temac: fix error checking of irq_of_parse_and_map()
+    - net: dcb: choose correct policy to parse DCB_ATTR_BCN
+    - ip6mr: Fix skb_under_panic in ip6mr_cache_report()
+    - tcp_metrics: fix addr_same() helper
+    - tcp_metrics: annotate data-races around tm->tcpm_stamp
+    - tcp_metrics: annotate data-races around tm->tcpm_lock
+    - tcp_metrics: annotate data-races around tm->tcpm_vals[]
+    - tcp_metrics: annotate data-races around tm->tcpm_net
+    - tcp_metrics: fix data-race in tcpm_suck_dst() vs fastopen
+    - scsi: zfcp: Defer fc_rport blocking until after ADISC response
+    - libceph: fix potential hang in ceph_osdc_notify()
+    - USB: zaurus: Add ID for A-300/B-500/C-700
+    - mtd: spinand: toshiba: Fix ecc_get_status
+    - mtd: rawnand: meson: fix OOB available bytes for ECC
+    - fs/sysv: Null check to prevent null-ptr-deref bug
+    - net: usbnet: Fix WARNING in usbnet_start_xmit/usb_submit_urb
+    - fs: Protect reconfiguration of sb read-write from racing writes
+    - ext2: Drop fragment support
+    - test_firmware: prevent race conditions by a correct implementation of
+      locking
+    - test_firmware: return ENOMEM instead of ENOSPC on failed memory allocation
+    - mtd: rawnand: omap_elm: Fix incorrect type in assignment
+    - powerpc/mm/altmap: Fix altmap boundary check
+    - selftests/rseq: check if libc rseq support is registered
+    - selftests/rseq: Play nice with binaries statically linked against glibc
+      2.35+
+    - PM / wakeirq: support enabling wake-up irq after runtime_suspend called
+    - PM: sleep: wakeirq: fix wake irq arming
+    - ceph: show tasks waiting on caps in debugfs caps file
+    - ceph: use kill_anon_super helper
+    - ceph: defer stopping mdsc delayed_work
+    - arm64: dts: stratix10: fix incorrect I2C property for SCL signal
+    - ARM: dts: imx6sll: Make ssi node name same as other platforms
+    - ARM: dts: imx: Align L2 cache-controller nodename with dtschema
+    - ARM: dts: imx: add usb alias
+    - ARM: dts: imx6sll: fixup of operating points
+    - ARM: dts: nxp/imx6sll: fix wrong property name in usbphy node
+    - driver core: Annotate dev_err_probe() with __must_check
+    - driver code: print symbolic error code
+    - drivers: core: fix kernel-doc markup for dev_err_probe()
+    - Revert "driver core: Annotate dev_err_probe() with __must_check"
+    - Linux 5.4.253
+    - Upstream stable to v5.4.253
+  * CVE-2023-37453
+    - USB: hub: Clean up use of port initialization schemes and retries
+    - USB: hub: Add Kconfig option to reduce number of port initialization retries
+    - USB: core: Unite old scheme and new scheme descriptor reads
+    - usb: hub: Check device descriptor before resusciation
+    - USB: core: Change usb_get_device_descriptor() API
+    - USB: core: Fix race by not overwriting udev->descriptor in hub_port_init()
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 11 Dec 2023 17:06:03 +0800
+
+linux-ein (5.4.0-1043.50) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1043.50 -proposed tracker (LP: #2044653)
+
+  * Amgis-V5][UC20] Cortex A7 Core 1 Bare metal application conflicts with
+    OPTEE/Linux (LP#2023563)
+    - SAUCE: irq-gic: Allow device tree to exclude irqs
+    - SAUCE: amgis: dts: Exclude A7 Core 1 irqs
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 26 Nov 2023 23:57:27 +0800
+
+linux-ein (5.4.0-1042.49) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1042.49 -proposed tracker (LP: #2044059)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync update-dkms-versions helper
+
+  * Amgis v6 hardware (LP: #2043011)
+    - SAUCE: dts: Add Amgis v6 device tree
+
+  * Miscellaneous Ubuntu changes
+    - snap: medina: Adapt to the new config model
+
+  [ Ubuntu: 5.4.0-167.184 ]
+
+  * focal/linux: 5.4.0-167.184 -proposed tracker (LP: #2041988)
+  * CVE-2023-45871
+    - igb: set max size RX buffer when store bad packet is enabled
+  * CVE-2023-31085
+    - ubi: Refuse attaching if mtd's erasesize is 0
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 21 Nov 2023 13:00:44 +0800
+
+linux-ein (5.4.0-1041.48) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1041.48 -proposed tracker (LP: #2040956)
+
+  * Focal update: v5.4.251 upstream stable release (LP: #2034918)
+    - SAUCE: drm/panel: AVD101WX-CN: Update drm_panel_init() call
+
+  * Use new annotations model (LP: #2019000)
+    - [Config] ein: sanitize annotations
+    - [Config] ein: Migrate to the new annotations model
+    - [Config] ein: Migrate to the new annotations model
+
+  * CVE-2023-42755
+    - [Config] ein: remove NET_CLS_RSVP and NET_CLS_RSVP6
+
+  * Focal update: v5.4.248 upstream stable release (LP: #2031121)
+    - [Config] ein: updateconfigs for DECNET
+
+  * [Amgis-V5][UC20] LPM Suspend to Mem vs Standby (LP: #2038441)
+    - Revert "UBUNTU: SAUCE: imx7: Suspend/Resume updates"
+    - Revert "UBUNTU: SAUCE: ARM: imx7: Fix memory mapping for iram_tlb_io_desc by
+      removing the executable flag, resulting in a pagetable warning."
+
+  * Missing Marvell firmware (LP: #2037448)
+    - snap: medina: remove Marvell firmwares except sdsd8997_combo_v4.bin
+
+  * Miscellaneous Ubuntu changes
+    - [Config] ein: Change CONFIG_BLK_DEV_LOOP_MIN_COUNT to 8
+    - snap: medina: Remove pahole from build-packages
+
+  [ Ubuntu: 5.4.0-166.183 ]
+
+  * focal/linux: 5.4.0-166.183 -proposed tracker (LP: #2038010)
+  * Use new annotations model (LP: #2019000)
+    - [Packaging] new annotations model infrastructure
+    - [Packaging] config-check: Handle new annotations format 4
+    - [Packaging] rules: Use old-kernelconfig for old configs
+    - [Config] sanitize annotations
+    - [Config] import generated configs into annotation file
+    - [Packaging] kernelconfig: add i386 as supported arch
+    - [Config] Remove all old configs files
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - [Packaging] update annotations scripts
+  * fix typo in config-checks invocation (LP: #2020413)
+    - [Packaging] fix typo when calling the old config-check
+    - [Packaging] fix typo in 4-checks.mk
+  * support python < 3.9 with annotations (LP: #2020531)
+    - [Packaging] kconfig/annotations.py: support older way of merging dicts
+  * CVE-2023-42756
+    - netfilter: ipset: Fix race between IPSET_CMD_CREATE and IPSET_CMD_SWAP
+  * CVE-2023-4623
+    - net/sched: sch_hfsc: Ensure inner classes have fsc curve
+  * Focal update: v5.4.252 upstream stable release (LP: #2036240)
+    - ia64/cpu: Switch to arch_cpu_finalize_init()
+    - m68k/cpu: Switch to arch_cpu_finalize_init()
+    - mips/cpu: Switch to arch_cpu_finalize_init()
+    - sh/cpu: Switch to arch_cpu_finalize_init()
+    - x86/cpufeatures: Add SEV-ES CPU feature
+    - x86/cpu: Add VM page flush MSR availablility as a CPUID feature
+    - x86/cpufeatures: Assign dedicated feature word for CPUID_0x8000001F[EAX]
+    - tools headers cpufeatures: Sync with the kernel sources
+    - x86/cpu, kvm: Add support for CPUID_80000021_EAX
+    - Linux 5.4.252
+    - Upstream stable to v5.4.252
+  * CVE-2023-42755
+    - net/sched: Retire rsvp classifier
+    - [Config] remove NET_CLS_RSVP and NET_CLS_RSVP6
+  * CVE-2023-42753
+    - netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for
+      ip_set_hash_netportnet.c
+  * CVE-2023-34319
+    - xen/netback: Fix buffer overrun triggered by unusual packet
+  * CVE-2023-4921
+    - net: sched: sch_qfq: Fix UAF in qfq_dequeue()
+  * CVE-2023-42752
+    - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU
+  * Avoid address overwrite in kernel_connect (LP: #2035163)
+    - net: Avoid address overwrite in kernel_connect
+  * [regression] Unable to initialize SGX enclaves with XFRM other than 3
+    (LP: #2034745)
+    - x86/fpu: Set X86_FEATURE_OSXSAVE feature after enabling OSXSAVE in CR4
+  * 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().
+  * Focal update: v5.4.251 upstream stable release (LP: #2034918)
+    - x86/smp: Use dedicated cache-line for mwait_play_dead()
+    - video: imsttfb: check for ioremap() failures
+    - fbdev: imsttfb: Fix use after free bug in imsttfb_probe
+    - HID: wacom: Use ktime_t rather than int when dealing with timestamps
+    - drm/i915: Initialise outparam for error return from wait_for_register
+    - scripts/tags.sh: Resolve gtags empty index generation
+    - drm/amdgpu: Validate VM ioctl flags.
+    - bgmac: fix *initial* chip reset to support BCM5358
+    - x86/resctrl: Use is_closid_match() in more places
+    - x86/resctrl: Only show tasks' pid in current pid namespace
+    - md/raid10: check slab-out-of-bounds in md_bitmap_get_counter
+    - md/raid10: fix overflow of md/safe_mode_delay
+    - md/raid10: fix wrong setting of max_corr_read_errors
+    - md/raid10: fix null-ptr-deref of mreplace in raid10_sync_request
+    - md/raid10: fix io loss while replacement replace rdev
+    - irqchip/jcore-aic: Kill use of irq_create_strict_mappings()
+    - irqchip/jcore-aic: Fix missing allocation of IRQ descriptors
+    - tracing/timer: Add missing hrtimer modes to decode_hrtimer_mode().
+    - clocksource/drivers/cadence-ttc: Use ttc driver as platform driver
+    - clocksource/drivers/cadence-ttc: Fix memory leak in ttc_timer_probe
+    - PM: domains: fix integer overflow issues in genpd_parse_state()
+    - powercap: RAPL: Fix CONFIG_IOSF_MBI dependency
+    - ARM: 9303/1: kprobes: avoid missing-declaration warnings
+    - evm: Complete description of evm_inode_setattr()
+    - pstore/ram: Add check for kstrdup
+    - ima: Fix build warnings
+    - wifi: ath9k: fix AR9003 mac hardware hang check register offset calculation
+    - wifi: ath9k: avoid referencing uninit memory in ath9k_wmi_ctrl_rx
+    - samples/bpf: Fix buffer overflow in tcp_basertt
+    - spi: spi-geni-qcom: Correct CS_TOGGLE bit in SPI_TRANS_CFG
+    - wifi: mwifiex: Fix the size of a memory allocation in
+      mwifiex_ret_802_11_scan()
+    - nfc: constify several pointers to u8, char and sk_buff
+    - nfc: llcp: fix possible use of uninitialized variable in
+      nfc_llcp_send_connect()
+    - regulator: core: Fix more error checking for debugfs_create_dir()
+    - regulator: core: Streamline debugfs operations
+    - wifi: orinoco: Fix an error handling path in spectrum_cs_probe()
+    - wifi: orinoco: Fix an error handling path in orinoco_cs_probe()
+    - wifi: atmel: Fix an error handling path in atmel_probe()
+    - wl3501_cs: Fix a bunch of formatting issues related to function docs
+    - wl3501_cs: Remove unnecessary NULL check
+    - wl3501_cs: Fix misspelling and provide missing documentation
+    - net: create netdev->dev_addr assignment helpers
+    - wl3501_cs: use eth_hw_addr_set()
+    - wifi: wl3501_cs: Fix an error handling path in wl3501_probe()
+    - wifi: ray_cs: Utilize strnlen() in parse_addr()
+    - wifi: ray_cs: Drop useless status variable in parse_addr()
+    - wifi: ray_cs: Fix an error handling path in ray_probe()
+    - wifi: ath9k: don't allow to overwrite ENDPOINT0 attributes
+    - wifi: rsi: Do not set MMC_PM_KEEP_POWER in shutdown
+    - watchdog/perf: define dummy watchdog_update_hrtimer_threshold() on correct
+      config
+    - watchdog/perf: more properly prevent false positives with turbo modes
+    - kexec: fix a memory leak in crash_shrink_memory()
+    - memstick r592: make memstick_debug_get_tpc_name() static
+    - wifi: ath9k: Fix possible stall on ath9k_txq_list_has_key()
+    - rtnetlink: extend RTEXT_FILTER_SKIP_STATS to IFLA_VF_INFO
+    - wifi: iwlwifi: pull from TXQs with softirqs disabled
+    - wifi: cfg80211: rewrite merging of inherited elements
+    - wifi: ath9k: convert msecs to jiffies where needed
+    - netlink: fix potential deadlock in netlink_set_err()
+    - netlink: do not hard code device address lenth in fdb dumps
+    - selftests: rtnetlink: remove netdevsim device after ipsec offload test
+    - gtp: Fix use-after-free in __gtp_encap_destroy().
+    - lib/ts_bm: reset initial match offset for every block of text
+    - netfilter: conntrack: dccp: copy entire header to stack buffer, not just
+      basic one
+    - netfilter: nf_conntrack_sip: fix the ct_sip_parse_numerical_param() return
+      value.
+    - ipvlan: Fix return value of ipvlan_queue_xmit()
+    - netlink: Add __sock_i_ino() for __netlink_diag_dump().
+    - radeon: avoid double free in ci_dpm_init()
+    - Input: drv260x - sleep between polling GO bit
+    - ARM: dts: BCM5301X: Drop "clock-names" from the SPI node
+    - Input: adxl34x - do not hardcode interrupt trigger type
+    - drm: sun4i_tcon: use devm_clk_get_enabled in `sun4i_tcon_init_clocks`
+    - RDMA/bnxt_re: Fix to remove an unnecessary log
+    - ARM: dts: gta04: Move model property out of pinctrl node
+    - arm64: dts: qcom: msm8916: correct camss unit address
+    - drm/panel: simple: fix active size for Ampire AM-480272H3TMQW-T01H
+    - ARM: ep93xx: fix missing-prototype warnings
+    - memory: brcmstb_dpfe: fix testing array offset after use
+    - ASoC: es8316: Increment max value for ALC Capture Target Volume control
+    - ASoC: es8316: Do not set rate constraints for unsupported MCLKs
+    - soc/fsl/qe: fix usb.c build errors
+    - IB/hfi1: Fix sdma.h tx->num_descs off-by-one errors
+    - arm64: dts: renesas: ulcb-kf: Remove flow control for SCIF1
+    - fbdev: omapfb: lcd_mipid: Fix an error handling path in mipid_spi_probe()
+    - drm/amdkfd: Fix potential deallocation of previously deallocated memory.
+    - drm/radeon: fix possible division-by-zero errors
+    - clk: tegra: tegra124-emc: Fix potential memory leak
+    - ALSA: ac97: Fix possible NULL dereference in snd_ac97_mixer
+    - clk: cdce925: check return value of kasprintf()
+    - clk: keystone: sci-clk: check return value of kasprintf()
+    - ASoC: imx-audmix: check return value of devm_kasprintf()
+    - scsi: qedf: Fix NULL dereference in error handling
+    - PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free
+    - scsi: 3w-xxxx: Add error handling for initialization failure in tw_probe()
+    - PCI: pciehp: Cancel bringup sequence if card is not present
+    - PCI: ftpci100: Release the clock resources
+    - PCI: Add pci_clear_master() stub for non-CONFIG_PCI
+    - pinctrl: cherryview: Return correct value if pin in push-pull mode
+    - perf dwarf-aux: Fix off-by-one in die_get_varname()
+    - pinctrl: at91-pio4: check return value of devm_kasprintf()
+    - powerpc/mm/dax: Fix the condition when checking if altmap vmemap can cross-
+      boundary
+    - hwrng: virtio - add an internal buffer
+    - hwrng: virtio - don't wait on cleanup
+    - hwrng: virtio - don't waste entropy
+    - hwrng: virtio - always add a pending request
+    - hwrng: virtio - Fix race on data_avail and actual data
+    - crypto: nx - fix build warnings when DEBUG_FS is not enabled
+    - modpost: fix section mismatch message for R_ARM_ABS32
+    - modpost: fix section mismatch message for R_ARM_{PC24,CALL,JUMP24}
+    - crypto: marvell/cesa - Fix type mismatch warning
+    - modpost: fix off by one in is_executable_section()
+    - ARC: define ASM_NL and __ALIGN(_STR) outside #ifdef __ASSEMBLY__ guard
+    - NFSv4.1: freeze the session table upon receiving NFS4ERR_BADSESSION
+    - hwrng: st - Fix W=1 unused variable warning
+    - hwrng: st - keep clock enabled while hwrng is registered
+    - USB: serial: option: add LARA-R6 01B PIDs
+    - usb: dwc3: gadget: Propagate core init errors to UDC during pullup
+    - block: fix signed int overflow in Amiga partition support
+    - block: change all __u32 annotations to __be32 in affs_hardblocks.h
+    - w1: fix loop in w1_fini()
+    - sh: j2: Use ioremap() to translate device tree address into kernel memory
+    - media: usb: Check az6007_read() return value
+    - media: videodev2.h: Fix struct v4l2_input tuner index comment
+    - usb: dwc3: qcom: Fix potential memory leak
+    - extcon: Fix kernel doc of property fields to avoid warnings
+    - extcon: Fix kernel doc of property capability fields to avoid warnings
+    - usb: phy: phy-tahvo: fix memory leak in tahvo_usb_probe()
+    - usb: hide unused usbfs_notify_suspend/resume functions
+    - mfd: rt5033: Drop rt5033-battery sub-device
+    - KVM: s390: fix KVM_S390_GET_CMMA_BITS for GFNs in memslot holes
+    - usb: dwc3: qcom: Release the correct resources in dwc3_qcom_remove()
+    - mfd: intel-lpss: Add missing check for platform_get_resource
+    - serial: 8250_omap: Use force_suspend and resume for system suspend
+    - mfd: stmfx: Fix error path in stmfx_chip_init
+    - KVM: s390: vsie: fix the length of APCB bitmap
+    - mfd: stmpe: Only disable the regulators if they are enabled
+    - pwm: imx-tpm: force 'real_period' to be zero in suspend
+    - pwm: sysfs: Do not apply state to already disabled PWMs
+    - rtc: st-lpc: Release some resources in st_rtc_probe() in case of error
+    - sctp: fix potential deadlock on &net->sctp.addr_wq_lock
+    - Add MODULE_FIRMWARE() for FIRMWARE_TG357766.
+    - spi: bcm-qspi: return error if neither hif_mspi nor mspi is available
+    - mailbox: ti-msgmgr: Fill non-message tx data fields with 0x0
+    - f2fs: fix error path handling in truncate_dnode()
+    - powerpc: allow PPC_EARLY_DEBUG_CPM only when SERIAL_CPM=y
+    - net: bridge: keep ports without IFF_UNICAST_FLT in BR_PROMISC mode
+    - tcp: annotate data races in __tcp_oow_rate_limited()
+    - xsk: Improve documentation for AF_XDP
+    - xsk: Honor SO_BINDTODEVICE on bind
+    - net/sched: act_pedit: Add size check for TCA_PEDIT_PARMS_EX
+    - net: dsa: tag_sja1105: fix MAC DA patching from meta frames
+    - sh: dma: Fix DMA channel offset calculation
+    - i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in xiic_process()
+    - i2c: xiic: Don't try to handle more interrupt events after error
+    - ALSA: jack: Fix mutex call in snd_jack_report()
+    - NFSD: add encoding of op_recall flag for write delegation
+    - mmc: core: disable TRIM on Kingston EMMC04G-M627
+    - mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
+    - mmc: sdhci: fix DMA configure compatibility issue when 64bit DMA mode is
+      used.
+    - bcache: Remove unnecessary NULL point check in node allocations
+    - integrity: Fix possible multiple allocation in integrity_inode_get()
+    - jffs2: reduce stack usage in jffs2_build_xattr_subsystem()
+    - fs: avoid empty option when generating legacy mount string
+    - ext4: Remove ext4 locking of moved directory
+    - Revert "f2fs: fix potential corruption when moving a directory"
+    - fs: Establish locking order for unrelated directories
+    - fs: Lock moved directories
+    - btrfs: fix race when deleting quota root from the dirty cow roots list
+    - ARM: orion5x: fix d2net gpio initialization
+    - fs: no need to check source
+    - fanotify: disallow mount/sb marks on kernel internal pseudo fs
+    - block: add overflow checks for Amiga partition support
+    - netfilter: nf_tables: fix nat hook table deletion
+    - netfilter: nftables: add helper function to set the base sequence number
+    - netfilter: add helper function to set up the nfnetlink header and use it
+    - netfilter: nf_tables: use net_generic infra for transaction data
+    - netfilter: nf_tables: add rescheduling points during loop detection walks
+    - netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound
+      set/chain
+    - netfilter: nf_tables: reject unbound anonymous set before commit phase
+    - netfilter: nf_tables: unbind non-anonymous set if rule construction fails
+    - netfilter: nf_tables: fix scheduling-while-atomic splat
+    - netfilter: conntrack: Avoid nf_ct_helper_hash uses after free
+    - tty: serial: fsl_lpuart: add earlycon for imx8ulp platform
+    - block/partition: fix signedness issue for Amiga partitions
+    - net: lan743x: Don't sleep in atomic context
+    - workqueue: clean up WORK_* constant types, clarify masking
+    - drm/panel: Initialise panel dev and funcs through drm_panel_init()
+    - drm/panel: Add and fill drm_panel type field
+    - drm/panel: simple: Add connector_type for innolux_at043tn24
+    - igc: Remove delay during TX ring configuration
+    - igc: set TP bit in 'supported' and 'advertising' fields of
+      ethtool_link_ksettings
+    - scsi: qla2xxx: Fix error code in qla2x00_start_sp()
+    - net: mvneta: fix txq_map in case of txq_number==1
+    - ionic: improve irq numa locality
+    - ionic: clean irq affinity on queue deinit
+    - ionic: move irq request to qcq alloc
+    - ionic: ionic_intr_free parameter change
+    - ionic: remove WARN_ON to prevent panic_on_warn
+    - icmp6: Fix null-ptr-deref of ip6_null_entry->rt6i_idev in icmp6_dev().
+    - udp6: fix udp6_ehashfn() typo
+    - ntb: idt: Fix error handling in idt_pci_driver_init()
+    - NTB: amd: Fix error handling in amd_ntb_pci_driver_init()
+    - ntb: intel: Fix error handling in intel_ntb_pci_driver_init()
+    - NTB: ntb_transport: fix possible memory leak while device_register() fails
+    - NTB: ntb_tool: Add check for devm_kcalloc
+    - ipv6/addrconf: fix a potential refcount underflow for idev
+    - platform/x86: wmi: Replace UUID redefinitions by their originals
+    - platform/x86: wmi: Fix indentation in some cases
+    - platform/x86: wmi: remove unnecessary argument
+    - platform/x86: wmi: use guid_t and guid_equal()
+    - platform/x86: wmi: move variables
+    - platform/x86: wmi: Break possible infinite loop when parsing GUID
+    - erofs: avoid infinite loop in z_erofs_do_read_page() when reading beyond EOF
+    - wifi: airo: avoid uninitialized warning in airo_get_rate()
+    - cls_flower: Add extack support for src and dst port range options
+    - net/sched: flower: Ensure both minimum and maximum ports are specified
+    - net/sched: make psched_mtu() RTNL-less safe
+    - pinctrl: amd: Fix mistake in handling clearing pins at startup
+    - pinctrl: amd: Detect internal GPIO0 debounce handling
+    - pinctrl: amd: Only use special debounce behavior for GPIO 0
+    - tpm: tpm_vtpm_proxy: fix a race condition in /dev/vtpmx creation
+    - mtd: rawnand: meson: fix unaligned DMA buffers handling
+    - net: bcmgenet: Ensure MDIO unregistration has clocks enabled
+    - powerpc: Fail build if using recordmcount with binutils v2.37
+    - misc: fastrpc: Create fastrpc scalar with correct buffer count
+    - SUNRPC: Fix UAF in svc_tcp_listen_data_ready()
+    - erofs: fix compact 4B support for 16k block size
+    - ext4: fix wrong unit use in ext4_mb_clear_bb
+    - ext4: only update i_reserved_data_blocks on successful block allocation
+    - jfs: jfs_dmap: Validate db_l2nbperpage while mounting
+    - PCI/PM: Avoid putting EloPOS E2/S2/H2 PCIe Ports in D3cold
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9235
+    - PCI: qcom: Disable write access to read only registers for IP v2.3.3
+    - PCI: rockchip: Assert PCI Configuration Enable bit after probe
+    - PCI: rockchip: Write PCI Device ID to correct register
+    - PCI: rockchip: Add poll and timeout to wait for PHY PLLs to be locked
+    - PCI: rockchip: Fix legacy IRQ generation for RK3399 PCIe endpoint core
+    - PCI: rockchip: Use u32 variable to access 32-bit registers
+    - PCI: rockchip: Set address alignment for endpoint mode
+    - misc: pci_endpoint_test: Free IRQs before removing the device
+    - misc: pci_endpoint_test: Re-init completion for every test
+    - md/raid0: add discard support for the 'original' layout
+    - fs: dlm: return positive pid value for F_GETLK
+    - drm/atomic: Allow vblank-enabled + self-refresh "disable"
+    - drm/rockchip: vop: Leave vblank enabled in self-refresh
+    - serial: atmel: don't enable IRQs prematurely
+    - firmware: stratix10-svc: Fix a potential resource leak in
+      svc_create_memory_pool()
+    - hwrng: imx-rngc - fix the timeout for init and self check
+    - ceph: don't let check_caps skip sending responses for revoke msgs
+    - meson saradc: fix clock divider mask length
+    - Revert "8250: add support for ASIX devices with a FIFO bug"
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in
+      case of error
+    - tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() when
+      iterating clk
+    - tracing/histograms: Add histograms to hist_vars if they have referenced
+      variables
+    - ring-buffer: Fix deadloop issue on reading trace_pipe
+    - xtensa: ISS: fix call to split_if_spec
+    - tracing: Fix null pointer dereference in tracing_err_log_open()
+    - tracing/probes: Fix not to count error code to total length
+    - scsi: qla2xxx: Wait for io return on terminate rport
+    - scsi: qla2xxx: Fix potential NULL pointer dereference
+    - scsi: qla2xxx: Check valid rport returned by fc_bsg_to_rport()
+    - scsi: qla2xxx: Correct the index of array
+    - scsi: qla2xxx: Pointer may be dereferenced
+    - scsi: qla2xxx: Remove unused nvme_ls_waitq wait queue
+    - drm/atomic: Fix potential use-after-free in nonblocking commits
+    - perf probe: Add test for regression introduced by switch to
+      die_get_decl_file()
+    - btrfs: fix warning when putting transaction with qgroups enabled after abort
+    - fuse: revalidate: don't invalidate if interrupted
+    - selftests: tc: set timeout to 15 minutes
+    - can: bcm: Fix UAF in bcm_proc_show()
+    - drm/client: Fix memory leak in drm_client_target_cloned
+    - drm/client: Fix memory leak in drm_client_modeset_probe
+    - ext4: correct inline offset when handling xattrs in inode body
+    - debugobjects: Recheck debug_objects_enabled before reporting
+    - nbd: Add the maximum limit of allocated index in nbd_dev_add
+    - md: fix data corruption for raid456 when reshape restart while grow up
+    - md/raid10: prevent soft lockup while flush writes
+    - posix-timers: Ensure timer ID search-loop limit is valid
+    - arm64: mm: fix VA-range sanity check
+    - sched/fair: Don't balance task to its current running CPU
+    - bpf: Address KCSAN report on bpf_lru_list
+    - devlink: report devlink_port_type_warn source device
+    - wifi: wext-core: Fix -Wstringop-overflow warning in
+      ioctl_standard_iw_point()
+    - wifi: iwlwifi: mvm: avoid baid size integer overflow
+    - igb: Fix igb_down hung on surprise removal
+    - spi: bcm63xx: fix max prepend length
+    - fbdev: imxfb: warn about invalid left/right margin
+    - pinctrl: amd: Use amd_pinconf_set() for all config options
+    - net: ethernet: ti: cpsw_ale: Fix cpsw_ale_get_field()/cpsw_ale_set_field()
+    - iavf: Fix use-after-free in free_netdev
+    - net:ipv6: check return value of pskb_trim()
+    - Revert "tcp: avoid the lookup process failing to get sk in ehash table"
+    - fbdev: au1200fb: Fix missing IRQ check in au1200fb_drv_probe
+    - llc: Don't drop packet from non-root netns.
+    - netfilter: nf_tables: fix spurious set element insertion failure
+    - netfilter: nf_tables: can't schedule in nft_chain_validate
+    - tcp: annotate data-races around tp->tcp_tx_delay
+    - net: Replace the limit of TCP_LINGER2 with TCP_FIN_TIMEOUT_MAX
+    - tcp: annotate data-races around tp->linger2
+    - tcp: annotate data-races around rskq_defer_accept
+    - tcp: annotate data-races around tp->notsent_lowat
+    - tcp: annotate data-races around fastopenq.max_qlen
+    - tracing/histograms: Return an error if we fail to add histogram to hist_vars
+      list
+    - Linux 5.4.251
+  * Focal update: v5.4.250 upstream stable release (LP: #2033297)
+    - x86/microcode/AMD: Load late on both threads too
+    - Linux 5.4.250
+  * Focal update: v5.4.249 upstream stable release (LP: #2033278)
+    - nilfs2: reject devices with insufficient block count
+    - mm: rewrite wait_on_page_bit_common() logic
+    - list: add "list_del_init_careful()" to go with "list_empty_careful()"
+    - epoll: ep_autoremove_wake_function should use list_del_init_careful
+    - tracing: Add tracing_reset_all_online_cpus_unlocked() function
+    - x86/purgatory: remove PGO flags
+    - tick/common: Align tick period during sched_timer setup
+    - media: dvbdev: Fix memleak in dvb_register_device
+    - media: dvbdev: fix error logic at dvb_register_device()
+    - media: dvb-core: Fix use-after-free due to race at dvb_register_device()
+    - nilfs2: fix buffer corruption due to concurrent device reads
+    - Drivers: hv: vmbus: Fix vmbus_wait_for_unload() to scan present CPUs
+    - PCI: hv: Fix a race condition bug in hv_pci_query_relations()
+    - cgroup: Do not corrupt task iteration when rebinding subsystem
+    - mmc: meson-gx: remove redundant mmc_request_done() call from irq context
+    - ip_tunnels: allow VXLAN/GENEVE to inherit TOS/TTL from VLAN
+    - writeback: fix dereferencing NULL mapping->host on writeback_page_template
+    - nilfs2: prevent general protection fault in nilfs_clear_dirty_page()
+    - cifs: Clean up DFS referral cache
+    - cifs: Get rid of kstrdup_const()'d paths
+    - cifs: Introduce helpers for finding TCP connection
+    - cifs: Merge is_path_valid() into get_normalized_path()
+    - cifs: Fix potential deadlock when updating vol in cifs_reconnect()
+    - x86/mm: Avoid using set_pgd() outside of real PGD pages
+    - ieee802154: hwsim: Fix possible memory leaks
+    - xfrm: Linearize the skb after offloading if needed.
+    - net: qca_spi: Avoid high load if QCA7000 is not available
+    - mmc: mtk-sd: fix deferred probing
+    - mmc: mvsdio: convert to devm_platform_ioremap_resource
+    - mmc: mvsdio: fix deferred probing
+    - mmc: omap: fix deferred probing
+    - mmc: omap_hsmmc: fix deferred probing
+    - mmc: sdhci-acpi: fix deferred probing
+    - mmc: sh_mmcif: fix deferred probing
+    - mmc: usdhi60rol0: fix deferred probing
+    - ipvs: align inner_mac_header for encapsulation
+    - net: dsa: mt7530: fix trapping frames on non-MT7621 SoC MT7530 switch
+    - be2net: Extend xmit workaround to BE3 chip
+    - netfilter: nf_tables: disallow element updates of bound anonymous sets
+    - netfilter: nfnetlink_osf: fix module autoload
+    - Revert "net: phy: dp83867: perform soft reset and retain established link"
+    - sch_netem: acquire qdisc lock in netem_change()
+    - scsi: target: iscsi: Prevent login threads from racing between each other
+    - HID: wacom: Add error check to wacom_parse_and_register()
+    - arm64: Add missing Set/Way CMO encodings
+    - media: cec: core: don't set last_initiator if tx in progress
+    - nfcsim.c: Fix error checking for debugfs_create_dir
+    - usb: gadget: udc: fix NULL dereference in remove()
+    - s390/cio: unregister device when the only path is gone
+    - ASoC: nau8824: Add quirk to active-high jack-detect
+    - ARM: dts: Fix erroneous ADS touchscreen polarities
+    - drm/exynos: vidi: fix a wrong error return
+    - drm/exynos: fix race condition UAF in exynos_g2d_exec_ioctl
+    - drm/radeon: fix race condition UAF in radeon_gem_set_domain_ioctl
+    - x86/apic: Fix kernel panic when booting with intremap=off and x2apic_phys
+    - i2c: imx-lpi2c: fix type char overflow issue when calculating the clock
+      cycle
+    - mm: fix VM_BUG_ON(PageTail) and BUG_ON(PageWriteback)
+    - mm: make wait_on_page_writeback() wait for multiple pending writebacks
+    - Linux 5.4.249
+  * allow io_uring to be disabled in runtime (LP: #2035116)
+    - io_uring: add a sysctl to disable io_uring system-wide
+  * CVE-2023-31083
+    - Bluetooth: hci_ldisc: check HCI_UART_PROTO_READY flag in HCIUARTGETPROTO
+  * CVE-2023-4132
+    - media: usb: siano: Fix warning due to null work_func_t function pointer
+  * CVE-2023-3772
+    - xfrm: add NULL check in xfrm_update_ae_params
+  * CVE-2023-0597
+    - random32: add noise from network and scheduling activity
+    - x86/kasan: Map shadow for percpu pages on demand
+    - x86/mm: Randomize per-cpu entry area
+    - x86/mm: Recompute physical address for every page of per-CPU CEA mapping
+    - x86/mm: Populate KASAN shadow for entire per-CPU range of CPU entry area
+    - x86/mm: Do not shuffle CPU entry areas without KASLR
+
+  [ Ubuntu: 5.4.0-164.181 ]
+
+  * focal/linux: 5.4.0-164.181 -proposed tracker (LP: #2033867)
+  * Please enable Renesas RZ platform serial installer (LP: #2022361)
+    - [Config] enable hihope RZ/G2M serial console
+  * Azure: hv_netvsc: add support for vlans in AF_PACKET mode (LP: #2030872)
+    - hv_netvsc: add support for vlans in AF_PACKET mode
+  * systemd mount units fail during boot, while file system is correctly mounted
+    (LP: #1837227)
+    - list: introduce list_for_each_continue()
+    - proc/mounts: add cursor
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+  * 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
+  * CVE-2023-4194
+    - net: tun_chr_open(): set sk_uid from current_fsuid()
+    - net: tap_open(): set sk_uid from current_fsuid()
+  * CVE-2023-1206
+    - tcp: Reduce chance of collisions in inet6_hashfn().
+  * CVE-2021-4001
+    - bpf: Fix toctou on read-only map's constant scalar tracking
+  * Focal update: v5.4.248 upstream stable release (LP: #2031121)
+    - test_firmware: fix a memory leak with reqs buffer
+    - KEYS: asymmetric: Copy sig and digest in public_key_verify_signature()
+    - dasd: refactor dasd_ioctl_information
+    - s390/dasd: Use correct lock while counting channel queue length
+    - power: supply: ab8500: Fix external_power_changed race
+    - power: supply: sc27xx: Fix external_power_changed race
+    - power: supply: bq27xxx: Use mod_delayed_work() instead of cancel() +
+      schedule()
+    - ARM: dts: vexpress: add missing cache properties
+    - power: supply: Ratelimit no data debug output
+    - platform/x86: asus-wmi: Ignore WMI events with codes 0x7B, 0xC0
+    - regulator: Fix error checking for debugfs_create_dir
+    - irqchip/meson-gpio: Mark OF related data as maybe unused
+    - power: supply: Fix logic checking if system is running from battery
+    - btrfs: handle memory allocation failure in btrfs_csum_one_bio
+    - parisc: Improve cache flushing for PCXL in arch_sync_dma_for_cpu()
+    - parisc: Flush gatt writes and adjust gatt mask in parisc_agp_mask_memory()
+    - MIPS: Alchemy: fix dbdma2
+    - mips: Move initrd_start check after initrd address sanitisation.
+    - xen/blkfront: Only check REQ_FUA for writes
+    - drm:amd:amdgpu: Fix missing buffer object unlock in failure path
+    - ocfs2: fix use-after-free when unmounting read-only filesystem
+    - ocfs2: check new file size on fallocate call
+    - nios2: dts: Fix tse_mac "max-frame-size" property
+    - nilfs2: fix incomplete buffer cleanup in nilfs_btnode_abort_change_key()
+    - nilfs2: fix possible out-of-bounds segment allocation in resize ioctl
+    - kexec: support purgatories with .text.hot sections
+    - powerpc/purgatory: remove PGO flags
+    - nouveau: fix client work fence deletion race
+    - RDMA/uverbs: Restrict usage of privileged QKEYs
+    - net: usb: qmi_wwan: add support for Compal RXM-G1
+    - ALSA: hda/realtek: Add a quirk for Compaq N14JP6
+    - Remove DECnet support from kernel
+    - [Config] updateconfigs for DECNET
+    - USB: serial: option: add Quectel EM061KGL series
+    - serial: lantiq: add missing interrupt ack
+    - usb: dwc3: gadget: Reset num TRBs before giving back the request
+    - spi: spi-fsl-dspi: Remove unused chip->void_write_data
+    - spi: fsl-dspi: avoid SCK glitches with continuous transfers
+    - netfilter: nfnetlink: skip error delivery on batch in case of ENOMEM
+    - ping6: Fix send to link-local addresses with VRF.
+    - RDMA/rxe: Remove the unused variable obj
+    - RDMA/rxe: Removed unused name from rxe_task struct
+    - RDMA/rxe: Fix the use-before-initialization error of resp_pkts
+    - iavf: remove mask from iavf_irq_enable_queues()
+    - IB/uverbs: Fix to consider event queue closing also upon non-blocking mode
+    - IB/isert: Fix dead lock in ib_isert
+    - IB/isert: Fix possible list corruption in CMA handler
+    - IB/isert: Fix incorrect release of isert connection
+    - ipvlan: fix bound dev checking for IPv6 l3s mode
+    - sctp: fix an error code in sctp_sf_eat_auth()
+    - igb: fix nvm.ops.read() error handling
+    - drm/nouveau/dp: check for NULL nv_connector->native_mode
+    - drm/nouveau/kms: Don't change EDID when it hasn't actually changed
+    - drm/nouveau: add nv_encoder pointer check for NULL
+    - net/sched: cls_api: Fix lockup on flushing explicitly created chain
+    - net: lapbether: only support ethernet devices
+    - net: tipc: resize nlattr array to correct size
+    - selftests/ptp: Fix timestamp printf format for PTP_SYS_OFFSET
+    - afs: Fix vlserver probe RTT handling
+    - neighbour: Remove unused inline function neigh_key_eq16()
+    - net: Remove unused inline function dst_hold_and_use()
+    - neighbour: delete neigh_lookup_nodev as not used
+    - drm/nouveau/kms: Fix NULL pointer dereference in
+      nouveau_connector_detect_depth
+    - mmc: block: ensure error propagation for non-blk
+    - Linux 5.4.248
+  * Focal update: v5.4.247 upstream stable release (LP: #2030818)
+    - blk-iocost: avoid 64-bit division in ioc_timer_fn
+    - block/blk-iocost (gcc13): keep large values in a new enum
+    - i40iw: fix build warning in i40iw_manage_apbvt()
+    - i40e: fix build warnings in i40e_alloc.h
+    - spi: qup: Request DMA before enabling clocks
+    - neighbour: Replace zero-length array with flexible-array member
+    - neighbour: fix unaligned access to pneigh_entry
+    - net: dsa: lan9303: allow vid != 0 in port_fdb_{add|del} methods
+    - Bluetooth: Fix l2cap_disconnect_req deadlock
+    - Bluetooth: L2CAP: Add missing checks for invalid DCID
+    - netfilter: conntrack: fix NULL pointer dereference in nf_confirm_cthelper
+    - netfilter: ipset: Add schedule point in call_ad().
+    - rfs: annotate lockless accesses to sk->sk_rxhash
+    - rfs: annotate lockless accesses to RFS sock flow table
+    - net: sched: move rtm_tca_policy declaration to include file
+    - net: sched: fix possible refcount leak in tc_chain_tmplt_add()
+    - lib: cpu_rmap: Fix potential use-after-free in irq_cpu_rmap_release()
+    - bnxt_en: Query default VLAN before VNIC setup on a VF
+    - batman-adv: Broken sync while rescheduling delayed work
+    - Input: xpad - delete a Razer DeathAdder mouse VID/PID entry
+    - Input: psmouse - fix OOB access in Elantech protocol
+    - ALSA: hda/realtek: Add a quirk for HP Slim Desktop S01
+    - ALSA: hda/realtek: Add Lenovo P3 Tower platform
+    - drm/amdgpu: fix xclk freq on CHIP_STONEY
+    - can: j1939: j1939_sk_send_loop_abort(): improved error queue handling in
+      J1939 Socket
+    - can: j1939: change j1939_netdev_lock type to mutex
+    - can: j1939: avoid possible use-after-free when j1939_can_rx_register fails
+    - ceph: fix use-after-free bug for inodes when flushing capsnaps
+    - Bluetooth: Fix use-after-free in hci_remove_ltk/hci_remove_irk
+    - rbd: move RBD_OBJ_FLAG_COPYUP_ENABLED flag setting
+    - pinctrl: meson-axg: add missing GPIOA_18 gpio group
+    - usb: usbfs: Enforce page requirements for mmap
+    - usb: usbfs: Use consistent mmap functions
+    - bonding (gcc13): synchronize bond_{a,t}lb_xmit() types
+    - i2c: sprd: Delete i2c adapter in .remove's error path
+    - eeprom: at24: also select REGMAP
+    - ext4: only check dquot_initialize_needed() when debugging
+    - drm/atomic: Don't pollute crtc_state->mode_blob with error pointers
+    - rbd: get snapshot context after exclusive lock is ensured to be held
+    - mtd: spinand: macronix: Add support for MX35LFxGE4AD
+    - Linux 5.4.247
+  * 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-3863
+    - nfc: llcp: simplify llcp_sock_connect() error paths
+    - net: nfc: Fix use-after-free caused by nfc_llcp_find_local
+  * CVE-2023-3212
+    - gfs2: Don't deref jdesc in evict
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 26 Oct 2023 23:43:23 +0800
+
+linux-ein (5.4.0-1040.47) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1040.47 -proposed tracker (LP: #2037063)
+
+  * [K4500-NXP][UC20] Enable VPU For HW Accelerated Video Decoding (LP:
+    #2029414)
+    - [Config] ein: Enable Hantro VPU decoder for IMX8mm devices
+
+  * Miscellaneous Ubuntu changes
+    - snap: Import snapcraft.yaml for Medina
+
+  [ Ubuntu: 5.4.0-163.180 ]
+
+  * focal/linux: 5.4.0-163.180 -proposed tracker (LP: #2034247)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+  * CVE-2023-40283
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb
+  * 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
+  * 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
+
+  [ Ubuntu: 5.4.0-162.179 ]
+
+  * focal/linux: 5.4.0-162.179 -proposed tracker (LP: #2031128)
+  * libgnutls report "trap invalid opcode" when trying to install packages over
+    https (LP: #2031093)
+    - [Config]: disable CONFIG_GDS_FORCE_MITIGATION
+
+  [ Ubuntu: 5.4.0-160.177 ]
+
+  * focal/linux: 5.4.0-160.177 -proposed tracker (LP: #2031017)
+  * Fix boot test warning for log_check "CPU: 0 PID: 0 at
+    arch/x86/kernel/fpu/xstate.c:878 get_xsave_addr+0x98/0xb0" (LP: #2031022)
+    - x86/pkeys: Revert a5eff7259790 ("x86/pkeys: Add PKRU value to init_fpstate")
+
+  [ Ubuntu: 5.4.0-158.175 ]
+
+  * focal/linux: 5.4.0-158.175 -proposed tracker (LP: #2030466)
+  * CVE-2022-40982
+    - x86/mm: Initialize text poking earlier
+    - x86/mm: fix poking_init() for Xen PV guests
+    - x86/mm: Use mm_alloc() in poking_init()
+    - mm: Move mm_cachep initialization to mm_init()
+    - init: Provide arch_cpu_finalize_init()
+    - x86/cpu: Switch to arch_cpu_finalize_init()
+    - ARM: cpu: Switch to arch_cpu_finalize_init()
+    - sparc/cpu: Switch to arch_cpu_finalize_init()
+    - um/cpu: Switch to arch_cpu_finalize_init()
+    - init: Remove check_bugs() leftovers
+    - init: Invoke arch_cpu_finalize_init() earlier
+    - init, x86: Move mem_encrypt_init() into arch_cpu_finalize_init()
+    - x86/fpu: Remove cpuinfo argument from init functions
+    - x86/fpu: Mark init functions __init
+    - x86/fpu: Move FPU initialization into arch_cpu_finalize_init()
+    - x86/xen: Fix secondary processors' FPU initialization
+    - x86/speculation: Add Gather Data Sampling mitigation
+    - x86/speculation: Add force option to GDS mitigation
+    - x86/speculation: Add Kconfig option for GDS
+    - KVM: Add GDS_NO support to KVM
+    - Documentation/x86: Fix backwards on/off logic about YMM support
+    - [Config]: Enable CONFIG_ARCH_HAS_CPU_FINALIZE_INIT and
+      CONFIG_GDS_FORCE_MITIGATION
+  * CVE-2023-3609
+    - net/sched: cls_u32: Fix reference counter leak leading to overflow
+  * CVE-2023-20593
+    - x86/cpu/amd: Move the errata checking functionality up
+    - x86/cpu/amd: Add a Zenbleed fix
+  * CVE-2023-3611
+    - net/sched: sch_qfq: account for stab overhead in qfq_enqueue
+  * stacked overlay file system mounts that have chroot() called against them
+    appear to be getting locked (by the kernel most likely?) (LP: #2016398)
+    - SAUCE: overlayfs: fix reference count mismatch
+  * Focal update: v5.4.246 upstream stable release (LP: #2028981)
+    - RDMA/efa: Fix unsupported page sizes in device
+    - RDMA/bnxt_re: Enable SRIOV VF support on Broadcom's 57500 adapter series
+    - RDMA/bnxt_re: Refactor queue pair creation code
+    - RDMA/bnxt_re: Fix return value of bnxt_re_process_raw_qp_pkt_rx
+    - iommu/rockchip: Fix unwind goto issue
+    - iommu/amd: Don't block updates to GATag if guest mode is on
+    - dmaengine: pl330: rename _start to prevent build error
+    - net/mlx5: fw_tracer, Fix event handling
+    - netrom: fix info-leak in nr_write_internal()
+    - af_packet: Fix data-races of pkt_sk(sk)->num.
+    - amd-xgbe: fix the false linkup in xgbe_phy_status
+    - mtd: rawnand: ingenic: fix empty stub helper definitions
+    - af_packet: do not use READ_ONCE() in packet_bind()
+    - tcp: deny tcp_disconnect() when threads are waiting
+    - tcp: Return user_mss for TCP_MAXSEG in CLOSE/LISTEN state if user_mss set
+    - net/sched: sch_ingress: Only create under TC_H_INGRESS
+    - net/sched: sch_clsact: Only create under TC_H_CLSACT
+    - net/sched: Reserve TC_H_INGRESS (TC_H_CLSACT) for ingress (clsact) Qdiscs
+    - net/sched: Prohibit regrafting ingress or clsact Qdiscs
+    - net: sched: fix NULL pointer dereference in mq_attach
+    - ocfs2/dlm: move BITS_TO_BYTES() to bitops.h for wider use
+    - net/netlink: fix NETLINK_LIST_MEMBERSHIPS length report
+    - udp6: Fix race condition in udp6_sendmsg & connect
+    - net: dsa: mv88e6xxx: Increase wait after reset deactivation
+    - mtd: rawnand: marvell: ensure timing values are written
+    - mtd: rawnand: marvell: don't set the NAND frequency select
+    - watchdog: menz069_wdt: fix watchdog initialisation
+    - mailbox: mailbox-test: Fix potential double-free in
+      mbox_test_message_write()
+    - ARM: 9295/1: unwind:fix unwind abort for uleb128 case
+    - media: rcar-vin: Select correct interrupt mode for V4L2_FIELD_ALTERNATE
+    - fbdev: modedb: Add 1920x1080 at 60 Hz video mode
+    - fbdev: stifb: Fix info entry in sti_struct on error path
+    - nbd: Fix debugfs_create_dir error checking
+    - ASoC: dwc: limit the number of overrun messages
+    - xfrm: Check if_id in inbound policy/secpath match
+    - ASoC: ssm2602: Add workaround for playback distortions
+    - media: dvb_demux: fix a bug for the continuity counter
+    - media: dvb-usb: az6027: fix three null-ptr-deref in az6027_i2c_xfer()
+    - media: dvb-usb-v2: ec168: fix null-ptr-deref in ec168_i2c_xfer()
+    - media: dvb-usb-v2: ce6230: fix null-ptr-deref in ce6230_i2c_master_xfer()
+    - media: dvb-usb-v2: rtl28xxu: fix null-ptr-deref in rtl28xxu_i2c_xfer
+    - media: dvb-usb: digitv: fix null-ptr-deref in digitv_i2c_xfer()
+    - media: dvb-usb: dw2102: fix uninit-value in su3000_read_mac_address
+    - media: netup_unidvb: fix irq init by register it at the end of probe
+    - media: dvb_ca_en50221: fix a size write bug
+    - media: ttusb-dec: fix memory leak in ttusb_dec_exit_dvb()
+    - media: mn88443x: fix !CONFIG_OF error by drop of_match_ptr from ID table
+    - media: dvb-core: Fix use-after-free due on race condition at dvb_net
+    - media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221
+    - wifi: rtl8xxxu: fix authentication timeout due to incorrect RCR value
+    - ARM: dts: stm32: add pin map for CAN controller on stm32f7
+    - arm64/mm: mark private VM_FAULT_X defines as vm_fault_t
+    - scsi: core: Decrease scsi_device's iorequest_cnt if dispatch failed
+    - wifi: b43: fix incorrect __packed annotation
+    - netfilter: conntrack: define variables exp_nat_nla_policy and any_addr with
+      CONFIG_NF_NAT
+    - ALSA: oss: avoid missing-prototype warnings
+    - atm: hide unused procfs functions
+    - mailbox: mailbox-test: fix a locking issue in mbox_test_message_write()
+    - iio: adc: mxs-lradc: fix the order of two cleanup operations
+    - HID: google: add jewel USB id
+    - HID: wacom: avoid integer overflow in wacom_intuos_inout()
+    - iio: light: vcnl4035: fixed chip ID check
+    - iio: dac: mcp4725: Fix i2c_master_send() return value handling
+    - iio: dac: build ad5758 driver when AD5758 is selected
+    - net: usb: qmi_wwan: Set DTR quirk for BroadMobi BM818
+    - usb: gadget: f_fs: Add unbind event before functionfs_unbind
+    - misc: fastrpc: return -EPIPE to invocations on device removal
+    - misc: fastrpc: reject new invocations during device removal
+    - scsi: stex: Fix gcc 13 warnings
+    - ata: libata-scsi: Use correct device no in ata_find_dev()
+    - flow_dissector: work around stack frame size warning
+    - x86/boot: Wrap literal addresses in absolute_pointer()
+    - ACPI: thermal: drop an always true check
+    - gcc-12: disable '-Wdangling-pointer' warning for now
+    - eth: sun: cassini: remove dead code
+    - kernel/extable.c: use address-of operator on section symbols
+    - treewide: Remove uninitialized_var() usage
+    - lib/dynamic_debug.c: use address-of operator on section symbols
+    - wifi: rtlwifi: remove always-true condition pointed out by GCC 12
+    - mmc: vub300: fix invalid response handling
+    - tty: serial: fsl_lpuart: use UARTCTRL_TXINV to send break instead of
+      UARTCTRL_SBK
+    - selinux: don't use make's grouped targets feature yet
+    - tracing/probe: trace_probe_primary_from_call(): checked list_first_entry
+    - ext4: add EA_INODE checking to ext4_iget()
+    - ext4: set lockdep subclass for the ea_inode in ext4_xattr_inode_cache_find()
+    - ext4: disallow ea_inodes with extended attributes
+    - ext4: add lockdep annotations for i_data_sem for ea_inode's
+    - fbcon: Fix null-ptr-deref in soft_cursor
+    - test_firmware: fix the memory leak of the allocated firmware buffer
+    - regmap: Account for register length when chunking
+    - scsi: dpt_i2o: Remove broken pass-through ioctl (I2OUSERCMD)
+    - scsi: dpt_i2o: Do not process completions with invalid addresses
+    - [Config] updateconfigs for SCSI_DPT_I2O
+    - RDMA/bnxt_re: Remove set but not used variable 'dev_attr'
+    - RDMA/bnxt_re: Remove the qp from list only if the qp destroy succeeds
+    - drm/edid: Fix uninitialized variable in drm_cvt_modes()
+    - wifi: rtlwifi: 8192de: correct checking of IQK reload
+    - drm/edid: fix objtool warning in drm_cvt_modes()
+    - Linux 5.4.246
+  * Focal update: v5.4.245 upstream stable release (LP: #2028980)
+    - cdc_ncm: Implement the 32-bit version of NCM Transfer Block
+    - net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize
+    - power: supply: bq27xxx: After charger plug in/out wait 0.5s for things to
+      stabilize
+    - power: supply: core: Refactor
+      power_supply_set_input_current_limit_from_supplier()
+    - power: supply: bq24190: Call power_supply_changed() after updating input
+      current
+    - fs: fix undefined behavior in bit shift for SB_NOUSER
+    - net/mlx5: devcom only supports 2 ports
+    - net/mlx5: Devcom, serialize devcom registration
+    - cdc_ncm: Fix the build warning
+    - io_uring: always grab lock in io_cancel_async_work()
+    - io_uring: don't drop completion lock before timer is fully initialized
+    - io_uring: have io_kill_timeout() honor the request references
+    - bluetooth: Add cmd validity checks at the start of hci_sock_ioctl()
+    - binder: fix UAF caused by faulty buffer cleanup
+    - ipv{4,6}/raw: fix output xfrm lookup wrt protocol
+    - netfilter: ctnetlink: Support offloaded conntrack entry deletion
+    - Linux 5.4.245
+  * Focal update: v5.4.244 upstream stable release (LP: #2028697)
+    - driver core: add a helper to setup both the of_node and fwnode of a device
+    - drm/mipi-dsi: Set the fwnode for mipi_dsi_device
+    - ARM: 9296/1: HP Jornada 7XX: fix kernel-doc warnings
+    - linux/dim: Do nothing if no time delta between samples
+    - net: Fix load-tearing on sk->sk_stamp in sock_recv_cmsgs().
+    - netfilter: conntrack: fix possible bug_on with enable_hooks=1
+    - netlink: annotate accesses to nlk->cb_running
+    - net: annotate sk->sk_err write from do_recvmmsg()
+    - net: tap: check vlan with eth_type_vlan() method
+    - net: add vlan_get_protocol_and_depth() helper
+    - net: datagram: fix data-races in datagram_poll()
+    - af_unix: Fix a data race of sk->sk_receive_queue->qlen.
+    - af_unix: Fix data races around sk->sk_shutdown.
+    - fs: hfsplus: remove WARN_ON() from hfsplus_cat_{read,write}_inode()
+    - drm/amd/display: Use DC_LOG_DC in the trasform pixel function
+    - regmap: cache: Return error in cache sync operations for REGCACHE_NONE
+    - firmware: arm_sdei: Fix sleep from invalid context BUG
+    - ACPI: EC: Fix oops when removing custom query handlers
+    - drm/tegra: Avoid potential 32-bit integer overflow
+    - ACPICA: Avoid undefined behavior: applying zero offset to null pointer
+    - ACPICA: ACPICA: check null return of ACPI_ALLOCATE_ZEROED in
+      acpi_db_display_objects
+    - wifi: brcmfmac: cfg80211: Pass the PMK in binary instead of hex
+    - ext2: Check block size validity during mount
+    - scsi: lpfc: Prevent lpfc_debugfs_lockstat_write() buffer overflow
+    - net: pasemi: Fix return type of pasemi_mac_start_tx()
+    - net: Catch invalid index in XPS mapping
+    - scsi: target: iscsit: Free cmds before session free
+    - lib: cpu_rmap: Avoid use after free on rmap->obj array entries
+    - scsi: message: mptlan: Fix use after free bug in mptlan_remove() due to race
+      condition
+    - gfs2: Fix inode height consistency check
+    - ext4: set goal start correctly in ext4_mb_normalize_request
+    - ext4: Fix best extent lstart adjustment logic in ext4_mb_new_inode_pa()
+    - f2fs: fix to drop all dirty pages during umount() if cp_error is set
+    - samples/bpf: Fix fout leak in hbm's run_bpf_prog
+    - wifi: iwlwifi: pcie: fix possible NULL pointer dereference
+    - wifi: iwlwifi: pcie: Fix integer overflow in iwl_write_to_user_buf
+    - wifi: iwlwifi: dvm: Fix memcpy: detected field-spanning write backtrace
+    - Bluetooth: L2CAP: fix "bad unlock balance" in l2cap_disconnect_rsp
+    - HID: logitech-hidpp: Don't use the USB serial for USB devices
+    - HID: logitech-hidpp: Reconcile USB and Unifying serials
+    - spi: spi-imx: fix MX51_ECSPI_* macros when cs > 3
+    - HID: wacom: generic: Set battery quirk only when we see battery data
+    - usb: typec: tcpm: fix multiple times discover svids error
+    - serial: 8250: Reinit port->pm on port specific driver unbind
+    - mcb-pci: Reallocate memory region to avoid memory overlapping
+    - sched: Fix KCSAN noinstr violation
+    - recordmcount: Fix memory leaks in the uwrite function
+    - RDMA/core: Fix multiple -Warray-bounds warnings
+    - clk: tegra20: fix gcc-7 constant overflow warning
+    - iommu/arm-smmu-v3: Acknowledge pri/event queue overflow if any
+    - Input: xpad - add constants for GIP interface numbers
+    - phy: st: miphy28lp: use _poll_timeout functions for waits
+    - mfd: dln2: Fix memory leak in dln2_probe()
+    - btrfs: replace calls to btrfs_find_free_ino with btrfs_find_free_objectid
+    - btrfs: fix space cache inconsistency after error loading it from disk
+    - ASoC: fsl_micfil: register platform component before registering cpu dai
+    - cpupower: Make TSC read per CPU for Mperf monitor
+    - af_key: Reject optional tunnel/BEET mode templates in outbound policies
+    - net: fec: Better handle pm_runtime_get() failing in .remove()
+    - ALSA: firewire-digi00x: prevent potential use after free
+    - vsock: avoid to close connected socket after the timeout
+    - serial: arc_uart: fix of_iomap leak in `arc_serial_probe`
+    - ip6_gre: Fix skb_under_panic in __gre6_xmit()
+    - ip6_gre: Make o_seqno start from 0 in native mode
+    - ip_gre, ip6_gre: Fix race condition on o_seqno in collect_md mode
+    - erspan: get the proto with the md version for collect_md
+    - net: hns3: fix sending pfc frames after reset issue
+    - net: hns3: fix reset delay time to avoid configuration timeout
+    - media: netup_unidvb: fix use-after-free at del_timer()
+    - drm/exynos: fix g2d_open/close helper function definitions
+    - net: nsh: Use correct mac_offset to unwind gso skb in nsh_gso_segment()
+    - net: bcmgenet: Remove phy_stop() from bcmgenet_netif_stop()
+    - net: bcmgenet: Restore phy_stop() depending upon suspend/close
+    - wifi: iwlwifi: mvm: don't trust firmware n_channels
+    - cassini: Fix a memory leak in the error handling path of cas_init_one()
+    - igb: fix bit_shift to be in [1..8] range
+    - vlan: fix a potential uninit-value in vlan_dev_hard_start_xmit()
+    - USB: usbtmc: Fix direction for 0-length ioctl control messages
+    - usb-storage: fix deadlock when a scsi command timeouts more than once
+    - USB: UHCI: adjust zhaoxin UHCI controllers OverCurrent bit value
+    - usb: dwc3: debugfs: Resume dwc3 before accessing registers
+    - usb: typec: altmodes/displayport: fix pin_assignment_show
+    - ALSA: hda: Fix Oops by 9.1 surround channel names
+    - ALSA: hda: Add NVIDIA codec IDs a3 through a7 to patch table
+    - ALSA: hda/realtek: Add a quirk for HP EliteDesk 805
+    - ALSA: hda/realtek: Add quirk for 2nd ASUS GU603
+    - can: j1939: recvmsg(): allow MSG_CMSG_COMPAT flag
+    - can: kvaser_pciefd: Set CAN_STATE_STOPPED in kvaser_pciefd_stop()
+    - can: kvaser_pciefd: Call request_irq() before enabling interrupts
+    - can: kvaser_pciefd: Empty SRB buffer in probe
+    - can: kvaser_pciefd: Clear listen-only bit if not explicitly requested
+    - can: kvaser_pciefd: Do not send EFLUSH command on TFD interrupt
+    - can: kvaser_pciefd: Disable interrupts in probe error path
+    - KVM: x86: do not report a vCPU as preempted outside instruction boundaries
+    - statfs: enforce statfs[64] structure initialization
+    - serial: Add support for Advantech PCI-1611U card
+    - ceph: force updating the msg pointer in non-split case
+    - tpm/tpm_tis: Disable interrupts for more Lenovo devices
+    - powerpc/64s/radix: Fix soft dirty tracking
+    - nilfs2: fix use-after-free bug of nilfs_root in nilfs_evict_inode()
+    - netfilter: nftables: add nft_parse_register_load() and use it
+    - netfilter: nftables: add nft_parse_register_store() and use it
+    - netfilter: nftables: statify nft_parse_register()
+    - netfilter: nf_tables: validate registers coming from userspace.
+    - netfilter: nf_tables: add nft_setelem_parse_key()
+    - netfilter: nf_tables: allow up to 64 bytes in the set element data area
+    - netfilter: nf_tables: stricter validation of element data
+    - netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on NFT_SET_OBJECT
+      flag
+    - netfilter: nf_tables: hold mutex on netns pre_exit path
+    - HID: wacom: Force pen out of prox if no events have been received in a while
+    - HID: wacom: Add new Intuos Pro Small (PTH-460) device IDs
+    - HID: wacom: add three styli to wacom_intuos_get_tool_type
+    - lib/string_helpers: Introduce string_upper() and string_lower() helpers
+    - usb: gadget: u_ether: Convert prints to device prints
+    - usb: gadget: u_ether: Fix host MAC address case
+    - vc_screen: rewrite vcs_size to accept vc, not inode
+    - vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF
+    - s390/qdio: get rid of register asm
+    - s390/qdio: fix do_sqbs() inline assembly constraint
+    - watchdog: sp5100_tco: Immediately trigger upon starting.
+    - spi: fsl-spi: Re-organise transfer bits_per_word adaptation
+    - spi: fsl-cpm: Use 16 bit mode for large transfers with even size
+    - mt76: mt7615: Fix build with older compilers
+    - ALSA: hda/ca0132: add quirk for EVGA X299 DARK
+    - ALSA: hda/realtek: Enable headset onLenovo M70/M90
+    - m68k: Move signal frame following exception on 68020/030
+    - parisc: Handle kgdb breakpoints only in kernel context
+    - parisc: Allow to reboot machine after system halt
+    - gpio: mockup: Fix mode of debugfs files
+    - btrfs: use nofs when cleaning up aborted transactions
+    - selftests/memfd: Fix unknown type name build failure
+    - parisc: Fix flush_dcache_page() for usage from irq context
+    - x86/topology: Fix erroneous smp_num_siblings on Intel Hybrid platforms
+    - debugobjects: Don't wake up kswapd from fill_pool()
+    - fbdev: udlfb: Fix endpoint check
+    - net: fix stack overflow when LRO is disabled for virtual interfaces
+    - udplite: Fix NULL pointer dereference in __sk_mem_raise_allocated().
+    - USB: core: Add routines for endpoint checks in old drivers
+    - USB: sisusbvga: Add endpoint checks
+    - media: radio-shark: Add endpoint checks
+    - net: fix skb leak in __skb_tstamp_tx()
+    - selftests: fib_tests: mute cleanup error message
+    - bpf: Fix mask generation for 32-bit narrow loads of 64-bit fields
+    - ipv6: Fix out-of-bounds access in ipv6_find_tlv()
+    - power: supply: leds: Fix blink to LED on transition
+    - power: supply: bq27xxx: Fix bq27xxx_battery_update() race condition
+    - power: supply: bq27xxx: Fix I2C IRQ race on remove
+    - power: supply: bq27xxx: Fix poll_interval handling and races on remove
+    - power: supply: sbs-charger: Fix INHIBITED bit for Status reg
+    - coresight: Fix signedness bug in tmc_etr_buf_insert_barrier_packet()
+    - xen/pvcalls-back: fix double frees with pvcalls_new_active_socket()
+    - x86/show_trace_log_lvl: Ensure stack pointer is aligned, again
+    - ASoC: Intel: Skylake: Fix declaration of enum skl_ch_cfg
+    - forcedeth: Fix an error handling path in nv_probe()
+    - net/mlx5: Fix error message when failing to allocate device memory
+    - net/mlx5: Devcom, fix error flow in mlx5_devcom_register_device
+    - 3c589_cs: Fix an error handling path in tc589_probe()
+    - Linux 5.4.244
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387)
+    - counter: 104-quad-8: Fix race condition between FLAG and CNTR reads
+    - drm/fb-helper: set x/yres_virtual in drm_fb_helper_check_var
+    - bluetooth: Perform careful capability checks in hci_sock_ioctl()
+    - USB: serial: option: add UNISOC vendor and TOZED LT70C product
+    - iio: adc: palmas_gpadc: fix NULL dereference on rmmod
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Acer Iconia One 7 B1-750
+    - asm-generic/io.h: suppress endianness warnings for readq() and writeq()
+    - USB: dwc3: fix runtime pm imbalance on probe errors
+    - USB: dwc3: fix runtime pm imbalance on unbind
+    - perf sched: Cast PTHREAD_STACK_MIN to int as it may turn into
+      sysconf(__SC_THREAD_STACK_MIN_VALUE)
+    - staging: iio: resolver: ads1210: fix config mode
+    - debugfs: regset32: Add Runtime PM support
+    - xhci: fix debugfs register accesses while suspended
+    - MIPS: fw: Allow firmware to pass a empty env
+    - ipmi:ssif: Add send_retries increment
+    - ipmi: fix SSIF not responding under certain cond.
+    - kheaders: Use array declaration instead of char
+    - pwm: meson: Fix axg ao mux parents
+    - pwm: meson: Fix g12a ao clk81 name
+    - ring-buffer: Sync IRQ works before buffer destruction
+    - reiserfs: Add security prefix to xattr name in reiserfs_security_write()
+    - KVM: nVMX: Emulate NOPs in L2, and PAUSE if it's not intercepted
+    - i2c: omap: Fix standard mode false ACK readings
+    - Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path"
+    - ubifs: Fix memleak when insert_old_idx() failed
+    - ubi: Fix return value overwrite issue in try_write_vid_and_data()
+    - ubifs: Free memory for tmpfile name
+    - selinux: fix Makefile dependencies of flask.h
+    - selinux: ensure av_permissions.h is built when needed
+    - tpm, tpm_tis: Do not skip reset of original interrupt vector
+    - erofs: stop parsing non-compact HEAD index if clusterofs is invalid
+    - erofs: fix potential overflow calculating xattr_isize
+    - drm/rockchip: Drop unbalanced obj unref
+    - drm/vgem: add missing mutex_destroy
+    - drm/probe-helper: Cancel previous job before starting new one
+    - arm64: dts: renesas: r8a77990: Remove bogus voltages from OPP table
+    - arm64: dts: renesas: r8a774c0: Remove bogus voltages from OPP table
+    - EDAC/skx: Fix overflows on the DRAM row address mapping arrays
+    - ARM: dts: qcom: ipq4019: Fix the PCI I/O port range
+    - ARM: dts: qcom: ipq8064: reduce pci IO size to 64K
+    - ARM: dts: qcom: ipq8064: Fix the PCI I/O port range
+    - media: bdisp: Add missing check for create_workqueue
+    - media: uapi: add MEDIA_BUS_FMT_METADATA_FIXED media bus format.
+    - media: av7110: prevent underflow in write_ts_to_decoder()
+    - firmware: qcom_scm: Clear download bit during reboot
+    - drm/msm: fix unbalanced pm_runtime_enable in adreno_gpu_{init, cleanup}
+    - drm/msm/adreno: Defer enabling runpm until hw_init()
+    - drm/msm/adreno: drop bogus pm_runtime_set_active()
+    - mmc: sdhci-of-esdhc: fix quirk to ignore command inhibit for data
+    - drm/lima/lima_drv: Add missing unwind goto in lima_pdev_probe()
+    - regulator: core: Consistently set mutex_owner when using
+      ww_mutex_lock_slow()
+    - regulator: core: Avoid lockdep reports when resolving supplies
+    - x86/apic: Fix atomic update of offset in reserve_eilvt_offset()
+    - media: dm1105: Fix use after free bug in dm1105_remove due to race condition
+    - media: saa7134: fix use after free bug in saa7134_finidev due to race
+      condition
+    - media: rcar_fdp1: simplify error check logic at fdp_open()
+    - media: rcar_fdp1: fix pm_runtime_get_sync() usage count
+    - media: rcar_fdp1: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - media: rcar_fdp1: Fix the correct variable assignments
+    - media: rcar_fdp1: Fix refcount leak in probe and remove function
+    - media: rc: gpio-ir-recv: Fix support for wake-up
+    - regulator: stm32-pwr: fix of_iomap leak
+    - x86/ioapic: Don't return 0 from arch_dynirq_lower_bound()
+    - arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step
+    - debugobject: Prevent init race with static objects
+    - timekeeping: Split jiffies seqlock
+    - tick/sched: Use tick_next_period for lockless quick check
+    - tick/sched: Reduce seqcount held scope in tick_do_update_jiffies64()
+    - tick/sched: Optimize tick_do_update_jiffies64() further
+    - tick: Get rid of tick_period
+    - tick/common: Align tick period with the HZ tick.
+    - wifi: ath6kl: minor fix for allocation size
+    - wifi: ath9k: hif_usb: fix memory leak of remain_skbs
+    - wifi: ath5k: fix an off by one check in ath5k_eeprom_read_freq_list()
+    - wifi: ath6kl: reduce WARN to dev_dbg() in callback
+    - tools: bpftool: Remove invalid \' json escape
+    - wifi: rtw88: mac: Return the original error from rtw_pwr_seq_parser()
+    - wifi: rtw88: mac: Return the original error from rtw_mac_power_switch()
+    - scm: fix MSG_CTRUNC setting condition for SO_PASSSEC
+    - vlan: partially enable SIOCSHWTSTAMP in container
+    - net/packet: annotate accesses to po->xmit
+    - net/packet: convert po->origdev to an atomic flag
+    - net/packet: convert po->auxdata to an atomic flag
+    - scsi: target: iscsit: Fix TAS handling during conn cleanup
+    - scsi: megaraid: Fix mega_cmd_done() CMDID_INT_CMDS
+    - f2fs: handle dqget error in f2fs_transfer_project_quota()
+    - rtlwifi: Start changing RT_TRACE into rtl_dbg
+    - rtlwifi: Replace RT_TRACE with rtl_dbg
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_rfreg()
+    - wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_reg()
+    - bpftool: Fix bug for long instructions in program CFG dumps
+    - crypto: drbg - make drbg_prepare_hrng() handle jent instantiation errors
+    - crypto: drbg - Only fail when jent is unavailable in FIPS mode
+    - scsi: lpfc: Fix ioremap issues in lpfc_sli4_pci_mem_setup()
+    - bpf, sockmap: fix deadlocks in the sockhash and sockmap
+    - nvme: handle the persistent internal error AER
+    - nvme: fix async event trace event
+    - nvme-fcloop: fix "inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage"
+    - bpf, sockmap: Revert buggy deadlock fix in the sockhash and sockmap
+    - md/raid10: fix leak of 'r10bio->remaining' for recovery
+    - md/raid10: fix memleak for 'conf->bio_split'
+    - md: update the optimal I/O size on reshape
+    - md/raid10: fix memleak of md thread
+    - wifi: iwlwifi: make the loop for card preparation effective
+    - wifi: iwlwifi: mvm: check firmware response size
+    - ixgbe: Allow flow hash to be set via ethtool
+    - ixgbe: Enable setting RSS table to default values
+    - bpf: Don't EFAULT for getsockopt with optval=NULL
+    - netfilter: nf_tables: don't write table validation state without mutex
+    - ipv4: Fix potential uninit variable access bug in __ip_make_skb()
+    - netlink: Use copy_to_user() for optval in netlink_getsockopt().
+    - net: amd: Fix link leak when verifying config failed
+    - tcp/udp: Fix memleaks of sk and zerocopy skbs with TX timestamp.
+    - pstore: Revert pmsg_lock back to a normal mutex
+    - usb: host: xhci-rcar: remove leftover quirk handling
+    - fpga: bridge: fix kernel-doc parameter description
+    - iio: light: max44009: add missing OF device matching
+    - usb: gadget: udc: renesas_usb3: Fix use after free bug in
+      renesas_usb3_remove due to race condition
+    - PCI: imx6: Install the fault handler only on compatible match
+    - genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
+    - ASoC: es8316: Use IRQF_NO_AUTOEN when requesting the IRQ
+    - ASoC: es8316: Handle optional IRQ assignment
+    - linux/vt_buffer.h: allow either builtin or modular for macros
+    - spi: qup: Don't skip cleanup in remove's error path
+    - spi: fsl-spi: Fix CPM/QE mode Litte Endian
+    - vmci_host: fix a race condition in vmci_host_poll() causing GPF
+    - of: Fix modalias string generation
+    - ia64: mm/contig: fix section mismatch warning/error
+    - ia64: salinfo: placate defined-but-not-used warning
+    - scripts/gdb: bail early if there are no clocks
+    - PM: domains: Fix up terminology with parent/child
+    - scripts/gdb: bail early if there are no generic PD
+    - mtd: spi-nor: cadence-quadspi: Make driver independent of flash geometry
+    - mtd: spi-nor: cadence-quadspi: Provide a way to disable DAC mode
+    - mtd: spi-nor: cadence-quadspi: Don't initialize rx_dma_complete on failure
+    - mtd: spi-nor: cadence-quadspi: Handle probe deferral while requesting DMA
+      channel
+    - spi: cadence-quadspi: fix suspend-resume implementations
+    - uapi/linux/const.h: prefer ISO-friendly __typeof__
+    - sh: sq: Fix incorrect element size for allocating bitmap buffer
+    - usb: chipidea: fix missing goto in `ci_hdrc_probe`
+    - usb: mtu3: fix kernel panic at qmu transfer done irq handler
+    - firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe
+    - tty: serial: fsl_lpuart: adjust buffer length to the intended size
+    - serial: 8250: Add missing wakeup event reporting
+    - staging: rtl8192e: Fix W_DISABLE# does not work after stop/start
+    - spmi: Add a check for remove callback when removing a SPMI driver
+    - macintosh/windfarm_smu_sat: Add missing of_node_put()
+    - powerpc/mpc512x: fix resource printk format warning
+    - powerpc/wii: fix resource printk format warnings
+    - powerpc/sysdev/tsi108: fix resource printk format warnings
+    - macintosh: via-pmu-led: requires ATA to be set
+    - powerpc/rtas: use memmove for potentially overlapping buffer copy
+    - perf/core: Fix hardlockup failure caused by perf throttle
+    - RDMA/siw: Fix potential page_array out of range access
+    - RDMA/rdmavt: Delete unnecessary NULL check
+    - rtc: omap: include header for omap_rtc_power_off_program prototype
+    - RDMA/mlx4: Prevent shift wrapping in set_user_sq_size()
+    - rtc: meson-vrtc: Use ktime_get_real_ts64() to get the current time
+    - power: supply: generic-adc-battery: fix unit scaling
+    - clk: add missing of_node_put() in "assigned-clocks" property parsing
+    - RDMA/siw: Remove namespace check from siw_netdev_event()
+    - IB/hfi1: Fix SDMA mmu_rb_node not being evicted in LRU order
+    - NFSv4.1: Always send a RECLAIM_COMPLETE after establishing lease
+    - firmware: raspberrypi: Keep count of all consumers
+    - firmware: raspberrypi: Introduce devm_rpi_firmware_get()
+    - input: raspberrypi-ts: Release firmware handle when not needed
+    - Input: raspberrypi-ts - fix refcount leak in rpi_ts_probe
+    - SUNRPC: remove the maximum number of retries in call_bind_status
+    - RDMA/mlx5: Use correct device num_ports when modify DC
+    - clocksource/drivers/davinci: Avoid trailing '\n' hidden in pr_fmt()
+    - clocksource: davinci: axe a pointless __GFP_NOFAIL
+    - clocksource/drivers/davinci: Fix memory leak in davinci_timer_register when
+      init fails
+    - openrisc: Properly store r31 to pt_regs on unhandled exceptions
+    - ext4: fix use-after-free read in ext4_find_extent for bigalloc + inline
+    - leds: TI_LMU_COMMON: select REGMAP instead of depending on it
+    - dmaengine: mv_xor_v2: Fix an error code.
+    - pwm: mtk-disp: Don't check the return code of pwmchip_remove()
+    - pwm: mtk-disp: Adjust the clocks to avoid them mismatch
+    - pwm: mtk-disp: Disable shadow registers before setting backlight values
+    - phy: tegra: xusb: Add missing tegra_xusb_port_unregister for usb2_port and
+      ulpi_port
+    - dmaengine: dw-edma: Fix to change for continuous transfer
+    - dmaengine: dw-edma: Fix to enable to issue dma request on DMA processing
+    - dmaengine: at_xdmac: do not enable all cyclic channels
+    - afs: Fix updating of i_size with dv jump from server
+    - parisc: Fix argument pointer in real64_call_asm()
+    - nilfs2: do not write dirty data after degenerating to read-only
+    - nilfs2: fix infinite loop in nilfs_mdt_get_block()
+    - md/raid10: fix null-ptr-deref in raid10_sync_request
+    - mailbox: zynqmp: Fix IPI isr handling
+    - mailbox: zynqmp: Fix typo in IPI documentation
+    - wifi: rtl8xxxu: RTL8192EU always needs full init
+    - clk: rockchip: rk3399: allow clk_cifout to force clk_cifout_src to reparent
+    - scripts/gdb: fix lx-timerlist for Python3
+    - btrfs: scrub: reject unsupported scrub flags
+    - s390/dasd: fix hanging blockdevice after request requeue
+    - dm clone: call kmem_cache_destroy() in dm_clone_init() error path
+    - dm integrity: call kmem_cache_destroy() in dm_integrity_init() error path
+    - dm flakey: fix a crash with invalid table line
+    - perf auxtrace: Fix address filter entire kernel size
+    - perf intel-pt: Fix CYC timestamps after standalone CBR
+    - debugobject: Ensure pool refill (again)
+    - nohz: Add TICK_DEP_BIT_RCU
+    - tick/nohz: Fix cpu_is_hotpluggable() by checking with nohz subsystem
+    - mailbox: zynq: Switch to flexible array to simplify code
+    - mailbox: zynqmp: Fix counts of child nodes
+    - dm verity: skip redundant verity_handle_err() on I/O errors
+    - dm verity: fix error handling for check_at_most_once on FEC
+    - crypto: inside-secure - irq balance
+    - crypto: safexcel - Cleanup ring IRQ workqueues on load failure
+    - net/ncsi: clear Tx enable mode when handling a Config required AEN
+    - net/sched: cls_api: remove block_cb from driver_list before freeing
+    - sit: update dev->needed_headroom in ipip6_tunnel_bind_dev()
+    - net: dsa: mv88e6xxx: add mv88e6321 rsvd2cpu
+    - writeback: fix call of incorrect macro
+    - net/sched: act_mirred: Add carrier check
+    - rxrpc: Fix hard call timeout units
+    - ionic: remove noise from ethtool rxnfc error msg
+    - af_packet: Don't send zero-byte data in packet_sendmsg_spkt().
+    - drm/amdgpu: add a missing lock for AMDGPU_SCHED
+    - ALSA: caiaq: input: Add error handling for unsupported input methods in
+      `snd_usb_caiaq_input_init`
+    - net: dsa: mt7530: fix corrupt frames using trgmii on 40 MHz XTAL MT7621
+    - virtio_net: split free_unused_bufs()
+    - virtio_net: suppress cpu stall when free_unused_bufs
+    - perf vendor events power9: Remove UTF-8 characters from JSON files
+    - perf map: Delete two variable initialisations before null pointer checks in
+      sort__sym_from_cmp()
+    - perf symbols: Fix return incorrect build_id size in elf_read_build_id()
+    - btrfs: fix btrfs_prev_leaf() to not return the same key twice
+    - btrfs: don't free qgroup space unless specified
+    - btrfs: print-tree: parent bytenr must be aligned to sector size
+    - cifs: fix pcchunk length type in smb2_copychunk_range
+    - platform/x86: touchscreen_dmi: Add info for the Dexp Ursus KX210i
+    - inotify: Avoid reporting event with invalid wd
+    - sh: math-emu: fix macro redefined warning
+    - sh: init: use OF_EARLY_FLATTREE for early init
+    - sh: nmi_debug: fix return value of __setup handler
+    - remoteproc: stm32: Call of_node_put() on iteration error
+    - remoteproc: st: Call of_node_put() on iteration error
+    - ARM: dts: exynos: fix WM8960 clock name in Itop Elite
+    - ARM: dts: s5pv210: correct MIPI CSIS clock name
+    - f2fs: fix potential corruption when moving a directory
+    - drm/panel: otm8009a: Set backlight parent to panel device
+    - drm/amdgpu: fix an amdgpu_irq_put() issue in gmc_v9_0_hw_fini()
+    - drm/amdgpu/gfx: disable gfx9 cp_ecc_error_irq only when enabling legacy gfx
+      ras
+    - drm/amdgpu: disable sdma ecc irq only when sdma RAS is enabled in suspend
+    - HID: wacom: Set a default resolution for older tablets
+    - HID: wacom: insert timestamp to packed Bluetooth (BT) events
+    - ext4: fix WARNING in mb_find_extent
+    - ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum
+    - ext4: fix data races when using cached status extents
+    - ext4: improve error recovery code paths in __ext4_remount()
+    - ext4: fix deadlock when converting an inline directory in nojournal mode
+    - ext4: add bounds checking in get_max_inline_xattr_value_size()
+    - ext4: bail out of ext4_xattr_ibody_get() fails for any reason
+    - ext4: remove a BUG_ON in ext4_mb_release_group_pa()
+    - ext4: fix invalid free tracking in ext4_xattr_move_to_block()
+    - tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH
+    - serial: 8250: Fix serial8250_tx_empty() race with DMA Tx
+    - drbd: correctly submit flush bio on barrier
+    - PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors
+    - PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock
+    - printk: declare printk_deferred_{enter,safe}() in include/linux/printk.h
+    - PM: domains: Restore comment indentation for generic_pm_domain.child_links
+    - drm/msm: Fix double pm_runtime_disable() call
+    - firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
+    - drm/msm/adreno: Fix null ptr access in adreno_gpu_cleanup()
+    - drm/exynos: move to use request_irq by IRQF_NO_AUTOEN flag
+    - mm/page_alloc: fix potential deadlock on zonelist_update_seq seqlock
+    - drm/amd/display: Fix hang when skipping modeset
+    - Linux 5.4.243
+    - Upstream stable to v5.4.243
+  * Focal update: v5.4.243 upstream stable release (LP: #2025387) //
+    CVE-2023-2269
+    - dm ioctl: fix nested locking in table_clear() to remove deadlock concern
+  * Focal update: v5.4.242 upstream stable release (LP: #2025094)
+    - ARM: dts: rockchip: fix a typo error for rk3288 spdif node
+    - arm64: dts: meson-g12-common: specify full DMC range
+    - netfilter: br_netfilter: fix recent physdev match breakage
+    - regulator: fan53555: Explicitly include bits header
+    - virtio_net: bugfix overflow inside xdp_linearize_page()
+    - netfilter: nf_tables: fix ifdef to also consider nf_tables=m
+    - i40e: fix accessing vsi->active_filters without holding lock
+    - i40e: fix i40e_setup_misc_vector() error handling
+    - mlxfw: fix null-ptr-deref in mlxfw_mfa2_tlv_next()
+    - bpf: Fix incorrect verifier pruning due to missing register precision taints
+    - e1000e: Disable TSO on i219-LM card to increase speed
+    - f2fs: Fix f2fs_truncate_partial_nodes ftrace event
+    - Input: i8042 - add quirk for Fujitsu Lifebook A574/H
+    - selftests: sigaltstack: fix -Wuninitialized
+    - scsi: megaraid_sas: Fix fw_crash_buffer_show()
+    - scsi: core: Improve scsi_vpd_inquiry() checks
+    - net: dsa: b53: mmap: add phy ops
+    - s390/ptrace: fix PTRACE_GET_LAST_BREAK error handling
+    - nvme-tcp: fix a possible UAF when failing to allocate an io queue
+    - xen/netback: use same error messages for same errors
+    - iio: light: tsl2772: fix reading proximity-diodes from device tree
+    - nilfs2: initialize unused bytes in segment summary blocks
+    - memstick: fix memory leak if card device is never registered
+    - mmc: sdhci_am654: Set HIGH_SPEED_ENA for SDR12 and SDR25
+    - MIPS: Define RUNTIME_DISCARD_EXIT in LD script
+    - x86/purgatory: Don't generate debug info for purgatory.ro
+    - Revert "ext4: fix use-after-free in ext4_xattr_set_entry"
+    - ext4: remove duplicate definition of ext4_xattr_ibody_inline_set()
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM).
+    - tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
+    - inet6: Remove inet6_destroy_sock() in sk->sk_prot->destroy().
+    - dccp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - sctp: Call inet6_destroy_sock() via sk->sk_destruct().
+    - xfs: fix forkoff miscalculation related to XFS_LITINO(mp)
+    - pwm: meson: Explicitly set .polarity in .get_state()
+    - iio: adc: at91-sama5d2_adc: fix an error code in at91_adc_allocate_trigger()
+    - ASN.1: Fix check for strdup() success
+    - Linux 5.4.242
+    - Upstream stable to v5.4.242
+  * 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-3268
+    - kernel/relay.c: fix read_pos error when multiple readers
+    - relayfs: fix out-of-bounds access in relay_file_read
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-156.173 ]
+
+  * focal/linux: 5.4.0-156.173 -proposed tracker (LP: #2026585)
+  * CVE-2023-3390
+    - netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+  * Focal update: v5.4.241 upstream stable release (LP: #2023930)
+    - scsi: ses: Handle enclosure with just a primary component gracefully
+    - x86/PCI: Add quirk for AMD XHCI controller that loses MSI-X state in D3hot
+    - cgroup/cpuset: Wake up cpuset_attach_wq tasks in cpuset_cancel_attach()
+    - treewide: Replace DECLARE_TASKLET() with DECLARE_TASKLET_OLD()
+    - smb3: fix problem with null cifs super block with previous patch
+    - pinctrl: amd: Use irqchip template
+    - pinctrl: amd: disable and mask interrupts on probe
+    - pinctrl: amd: Disable and mask interrupts on resume
+    - pwm: cros-ec: Explicitly set .polarity in .get_state()
+    - pwm: sprd: Explicitly set .polarity in .get_state()
+    - wifi: mac80211: fix invalid drv_sta_pre_rcu_remove calls for non-uploaded
+      sta
+    - icmp: guard against too small mtu
+    - net: don't let netpoll invoke NAPI if in xmit context
+    - sctp: check send stream number after wait_for_sndbuf
+    - ipv6: Fix an uninit variable access bug in __ip6_make_skb()
+    - gpio: davinci: Add irq chip flag to skip set wake
+    - sunrpc: only free unix grouplist after RCU settles
+    - NFSD: callback request does not use correct credential for AUTH_SYS
+    - xhci: also avoid the XHCI_ZERO_64B_REGS quirk with a passthrough iommu
+    - USB: serial: cp210x: add Silicon Labs IFS-USB-DATACABLE IDs
+    - usb: typec: altmodes/displayport: Fix configure initial pin assignment
+    - USB: serial: option: add Telit FE990 compositions
+    - USB: serial: option: add Quectel RM500U-CN modem
+    - iio: adc: ti-ads7950: Set `can_sleep` flag for GPIO chip
+    - iio: dac: cio-dac: Fix max DAC write value check for 12-bit
+    - tty: serial: sh-sci: Fix transmit end interrupt handler
+    - tty: serial: sh-sci: Fix Rx on RZ/G2L SCI
+    - tty: serial: fsl_lpuart: avoid checking for transfer complete when
+      UARTCTRL_SBK is asserted in lpuart32_tx_empty
+    - nilfs2: fix potential UAF of struct nilfs_sc_info in nilfs_segctor_thread()
+    - nilfs2: fix sysfs interface lifetime
+    - ALSA: hda/realtek: Add quirk for Clevo X370SNW
+    - perf/core: Fix the same task check in perf_event_set_output
+    - ftrace: Mark get_lock_parent_ip() __always_inline
+    - can: j1939: j1939_tp_tx_dat_new(): fix out-of-bounds memory access
+    - tracing: Free error logs of tracing instances
+    - net_sched: prevent NULL dereference if default qdisc setup failed
+    - drm/panfrost: Fix the panfrost_mmu_map_fault_addr() error path
+    - ring-buffer: Fix race while reader and writer are on the same page
+    - mm/swap: fix swap_info_struct race between swapoff and get_swap_pages()
+    - irqdomain: Look for existing mapping only once
+    - irqdomain: Refactor __irq_domain_alloc_irqs()
+    - irqdomain: Fix mapping-creation race
+    - Revert "pinctrl: amd: Disable and mask interrupts on resume"
+    - ALSA: emu10k1: fix capture interrupt handler unlinking
+    - ALSA: hda/sigmatel: add pin overrides for Intel DP45SG motherboard
+    - ALSA: i2c/cs8427: fix iec958 mixer control deactivation
+    - ALSA: firewire-tascam: add missing unwind goto in
+      snd_tscm_stream_start_duplex()
+    - ALSA: hda/sigmatel: fix S/PDIF out on Intel D*45* motherboards
+    - Bluetooth: L2CAP: Fix use-after-free in l2cap_disconnect_{req,rsp}
+    - Bluetooth: Fix race condition in hidp_session_thread
+    - btrfs: print checksum type and implementation at mount time
+    - btrfs: fix fast csum implementation detection
+    - mtdblock: tolerate corrected bit-flips
+    - mtd: rawnand: meson: fix bitmask for length in command word
+    - mtd: rawnand: stm32_fmc2: remove unsupported EDO mode
+    - niu: Fix missing unwind goto in niu_alloc_channels()
+    - qlcnic: check pci_reset_function result
+    - sctp: fix a potential overflow in sctp_ifwdtsn_skip
+    - RDMA/core: Fix GID entry ref leak when create_ah fails
+    - udp6: fix potential access to stale information
+    - net: macb: fix a memory corruption in extended buffer descriptor mode
+    - power: supply: cros_usbpd: reclassify "default case!" as debug
+    - i2c: imx-lpi2c: clean rx/tx buffers upon new message
+    - efi: sysfb_efi: Add quirk for Lenovo Yoga Book X91F/L
+    - drm: panel-orientation-quirks: Add quirk for Lenovo Yoga Book X90F
+    - verify_pefile: relax wrapper length check
+    - asymmetric_keys: log on fatal failures in PE/pkcs7
+    - ubi: Fix failure attaching when vid_hdr offset equals to (sub)page size
+    - mtd: ubi: wl: Fix a couple of kernel-doc issues
+    - ubi: Fix deadlock caused by recursively holding work_sem
+    - i2c: ocores: generate stop condition after timeout in polling mode
+    - watchdog: sbsa_wdog: Make sure the timeout programming is within the limits
+    - coresight-etm4: Fix for() loop drvdata->nr_addr_cmp range bug
+    - xfs: show the proper user quota options
+    - xfs: remove the kuid/kgid conversion wrappers
+    - xfs: add a new xfs_sb_version_has_v3inode helper
+    - xfs: only check the superblock version for dinode size calculation
+    - xfs: simplify di_flags2 inheritance in xfs_ialloc
+    - xfs: simplify a check in xfs_ioctl_setattr_check_cowextsize
+    - xfs: remove the di_version field from struct icdinode
+    - xfs: set inode size after creating symlink
+    - xfs: report corruption only as a regular error
+    - xfs: shut down the filesystem if we screw up quota reservation
+    - xfs: consider shutdown in bmapbt cursor delete assert
+    - xfs: don't reuse busy extents on extent trim
+    - xfs: force log and push AIL to clear pinned inodes when aborting mount
+    - Linux 5.4.241
+  * [UBUNTU 20.04] [HPS] Kernel panic with "refcount_t: underflow" in mlx5
+    driver (LP: #2019011)
+    - net/mlx5: cmdif, Avoid skipping reclaim pages if FW is not accessible
+    - net/mlx5: Fix handling of entry refcount when command is not issued to FW
+  * Disable hv-kvp-daemon if /dev/vmbus/hv_kvp is not present (LP: #2024900)
+    - [Packaging] disable hv-kvp-daemon if needed
+  * CVE-2023-35001
+    - netfilter: nf_tables: prevent OOB access in nft_byteorder_eval
+  * CVE-2023-32629
+    - ovl: adhere to the vfs_ vs. ovl_do_ conventions for xattrs
+  * CVE-2023-3141
+    - memstick: r592: Fix UAF bug in r592_remove due to race condition
+  * CVE-2023-3111
+    - btrfs: check return value of btrfs_commit_transaction in relocation
+    - btrfs: unset reloc control if transaction commit fails in
+      prepare_to_relocate()
+  * 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-2022-0168
+    - cifs: move some variables off the stack in smb2_ioctl_query_info
+    - cifs: prevent bad output lengths in smb2_ioctl_query_info()
+    - cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
+  * CVE-2022-27672
+    - x86/speculation: Identify processors vulnerable to SMT RSB predictions
+    - KVM: x86: Mitigate the cross-thread return address predictions bug
+    - Documentation/hw-vuln: Add documentation for Cross-Thread Return Predictions
+  * Severe NFS performance degradation after LP #2003053 (LP: #2022098)
+    - SAUCE: Make NFS file-access stale cache behaviour opt-in
+  * Encountering an issue with memcpy_fromio causing failed boot of SEV-enabled
+    guest (LP: #2020319)
+    - x86/sev: Unroll string mmio with CC_ATTR_GUEST_UNROLL_STRING_IO
+  * Focal update: v5.4.240 upstream stable release (LP: #2023601)
+    - net: tls: fix possible race condition between do_tls_getsockopt_conf() and
+      do_tls_setsockopt_conf()
+    - power: supply: da9150: Fix use after free bug in da9150_charger_remove due
+      to race condition
+    - iavf: fix inverted Rx hash condition leading to disabled hash
+    - iavf: fix non-tunneled IPv6 UDP packet type and hashing
+    - intel/igbvf: free irq on the error path in igbvf_request_msix()
+    - igbvf: Regard vf reset nack as success
+    - i2c: imx-lpi2c: check only for enabled interrupt flags
+    - scsi: scsi_dh_alua: Fix memleak for 'qdata' in alua_activate()
+    - net: usb: smsc95xx: Limit packet length to skb->len
+    - qed/qed_sriov: guard against NULL derefs from qed_iov_get_vf_info
+    - net: qcom/emac: Fix use after free bug in emac_remove due to race condition
+    - net/ps3_gelic_net: Fix RX sk_buff length
+    - net/ps3_gelic_net: Use dma_mapping_error
+    - keys: Do not cache key in task struct if key is requested from kernel thread
+    - bpf: Adjust insufficient default bpf_jit_limit
+    - net/mlx5: Read the TC mapping of all priorities on ETS query
+    - atm: idt77252: fix kmemleak when rmmod idt77252
+    - erspan: do not use skb_mac_header() in ndo_start_xmit()
+    - net/sonic: use dma_mapping_error() for error check
+    - nvme-tcp: fix nvme_tcp_term_pdu to match spec
+    - hvc/xen: prevent concurrent accesses to the shared ring
+    - net: mdio: thunder: Add missing fwnode_handle_put()
+    - Bluetooth: btqcomsmd: Fix command timeout after setting BD address
+    - platform/chrome: cros_ec_chardev: fix kernel data leak from ioctl
+    - hwmon (it87): Fix voltage scaling for chips with 10.9mV ADCs
+    - scsi: qla2xxx: Perform lockless command completion in abort path
+    - uas: Add US_FL_NO_REPORT_OPCODES for JMicron JMS583Gen 2
+    - thunderbolt: Use const qualifier for `ring_interrupt_index`
+    - riscv: Bump COMMAND_LINE_SIZE value to 1024
+    - ca8210: fix mac_len negative array access
+    - m68k: Only force 030 bus error if PC not in exception table
+    - selftests/bpf: check that modifier resolves after pointer
+    - scsi: target: iscsi: Fix an error message in iscsi_check_key()
+    - scsi: ufs: core: Add soft dependency on governor_simpleondemand
+    - scsi: lpfc: Avoid usage of list iterator variable after loop
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FE990
+    - net: usb: qmi_wwan: add Telit 0x1080 composition
+    - sh: sanitize the flags on sigreturn
+    - cifs: empty interface list when server doesn't support query interfaces
+    - scsi: core: Add BLIST_SKIP_VPD_PAGES for SKhynix H28U74301AMR
+    - usb: gadget: u_audio: don't let userspace block driver unbind
+    - fsverity: Remove WQ_UNBOUND from fsverity read workqueue
+    - igb: revert rtnl_lock() that causes deadlock
+    - dm thin: fix deadlock when swapping to thin device
+    - usb: cdns3: Fix issue with using incorrect PCI device function
+    - usb: chipdea: core: fix return -EINVAL if request role is the same with
+      current role
+    - usb: chipidea: core: fix possible concurrent when switch role
+    - wifi: mac80211: fix qos on mesh interfaces
+    - nilfs2: fix kernel-infoleak in nilfs_ioctl_wrap_copy()
+    - i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer()
+    - dm stats: check for and propagate alloc_percpu failure
+    - dm crypt: add cond_resched() to dmcrypt_write()
+    - sched/fair: sanitize vruntime of entity being placed
+    - sched/fair: Sanitize vruntime of entity being migrated
+    - tun: avoid double free in tun_free_netdev
+    - ocfs2: fix data corruption after failed write
+    - fsverity: don't drop pagecache at end of FS_IOC_ENABLE_VERITY
+    - bus: imx-weim: fix branch condition evaluates to a garbage value
+    - md: avoid signed overflow in slot_store()
+    - ALSA: asihpi: check pao in control_message()
+    - ALSA: hda/ca0132: fixup buffer overrun at tuning_ctl_set()
+    - fbdev: tgafb: Fix potential divide by zero
+    - sched_getaffinity: don't assume 'cpumask_size()' is fully initialized
+    - fbdev: nvidia: Fix potential divide by zero
+    - fbdev: intelfb: Fix potential divide by zero
+    - fbdev: lxfb: Fix potential divide by zero
+    - fbdev: au1200fb: Fix potential divide by zero
+    - ca8210: Fix unsigned mac_len comparison with zero in ca8210_skb_tx()
+    - dma-mapping: drop the dev argument to arch_sync_dma_for_*
+    - mips: bmips: BCM6358: disable RAC flush for TP1
+    - mtd: rawnand: meson: invalidate cache on polling ECC bit
+    - scsi: megaraid_sas: Fix crash after a double completion
+    - ptp_qoriq: fix memory leak in probe()
+    - regulator: fix spelling mistake "Cant" -> "Can't"
+    - regulator: Handle deferred clk
+    - net/net_failover: fix txq exceeding warning
+    - can: bcm: bcm_tx_setup(): fix KMSAN uninit-value in vfs_write
+    - s390/vfio-ap: fix memory leak in vfio_ap device driver
+    - i40e: fix registers dump after run ethtool adapter self test
+    - bnxt_en: Fix typo in PCI id to device description string mapping
+    - net: dsa: mv88e6xxx: Enable IGMP snooping on user ports only
+    - net: mvneta: make tx buffer array agnostic
+    - pinctrl: ocelot: Fix alt mode for ocelot
+    - Input: alps - fix compatibility with -funsigned-char
+    - Input: focaltech - use explicitly signed char type
+    - cifs: prevent infinite recursion in CIFSGetDFSRefer()
+    - cifs: fix DFS traversal oops without CONFIG_CIFS_DFS_UPCALL
+    - Input: goodix - add Lenovo Yoga Book X90F to nine_bytes_report DMI table
+    - xen/netback: don't do grant copy across page boundary
+    - pinctrl: at91-pio4: fix domain name assignment
+    - NFSv4: Fix hangs when recovering open state after a server reboot
+    - ALSA: hda/conexant: Partial revert of a quirk for Lenovo
+    - ALSA: usb-audio: Fix regression on detection of Roland VS-100
+    - drm/etnaviv: fix reference leak when mmaping imported buffer
+    - btrfs: scan device in non-exclusive mode
+    - ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+    - net_sched: add __rcu annotation to netdev->qdisc
+    - net: sched: fix race condition in qdisc_graft()
+    - firmware: arm_scmi: Fix device node validation for mailbox transport
+    - gfs2: Always check inode size of inline inodes
+    - Linux 5.4.240
+  * Focal update: v5.4.239 upstream stable release (LP: #2023600)
+    - Linux 5.4.239
+  * CVE-2023-2124
+    - xfs: verify buffer contents when we skip log replay
+  * CVE-2020-36691
+    - netlink: limit recursion depth in policy validation
+  * CVE-2022-1184
+    - ext4: check if directory block is within i_size
+    - ext4: fix check for block being out of directory size
+  * CVE-2022-4269
+    - net: sched: extract qstats update code into functions
+    - net: sched: don't expose action qstats to skb_tc_reinsert()
+    - net/sched: act_mirred: refactor the handle of xmit
+    - net: sched: remove unused tcf_result extension
+    - net/sched: act_mirred: better wording on protection against excessive stack
+      growth
+    - act_mirred: use the backlog for nested calls to mirred ingress
+  * Focal update: v5.4.238 upstream stable release (LP: #2023427)
+    - ext4: fix cgroup writeback accounting with fs-layer encryption
+    - xfrm: Allow transport-mode states with AF_UNSPEC selector
+    - drm/panfrost: Don't sync rpm suspension after mmu flushing
+    - cifs: Move the in_send statistic to __smb_send_rqst()
+    - drm/meson: fix 1px pink line on GXM when scaling video overlay
+    - clk: HI655X: select REGMAP instead of depending on it
+    - docs: Correct missing "d_" prefix for dentry_operations member
+      d_weak_revalidate
+    - scsi: mpt3sas: Fix NULL pointer access in mpt3sas_transport_port_add()
+    - ALSA: hda - add Intel DG1 PCI and HDMI ids
+    - ALSA: hda - controller is in GPU on the DG1
+    - ALSA: hda: Add Alderlake-S PCI ID and HDMI codec vid
+    - ALSA: hda: Add Intel DG2 PCI ID and HDMI codec vid
+    - ALSA: hda: Match only Intel devices with CONTROLLER_IN_GPU()
+    - netfilter: nft_redir: correct value of inet type `.maxattrs`
+    - scsi: core: Fix a comment in function scsi_host_dev_release()
+    - scsi: core: Fix a procfs host directory removal regression
+    - tcp: tcp_make_synack() can be called from process context
+    - nfc: pn533: initialize struct pn533_out_arg properly
+    - ipvlan: Make skb->skb_iif track skb->dev for l3s mode
+    - i40e: Fix kernel crash during reboot when adapter is in recovery mode
+    - qed/qed_dev: guard against a possible division by zero
+    - net: tunnels: annotate lockless accesses to dev->needed_headroom
+    - net: phy: smsc: bail out in lan87xx_read_status if genphy_read_status fails
+    - nfc: st-nci: Fix use after free bug in ndlc_remove due to race condition
+    - net: usb: smsc75xx: Limit packet length to skb->len
+    - nvmet: avoid potential UAF in nvmet_req_complete()
+    - block: sunvdc: add check for mdesc_grab() returning NULL
+    - ipv4: Fix incorrect table ID in IOCTL path
+    - net: usb: smsc75xx: Move packet length check to prevent kernel panic in
+      skb_pull
+    - net/iucv: Fix size of interrupt data
+    - ethernet: sun: add check for the mdesc_grab()
+    - hwmon: (adt7475) Display smoothing attributes in correct order
+    - hwmon: (adt7475) Fix masking of hysteresis registers
+    - hwmon: (xgene) Fix use after free bug in xgene_hwmon_remove due to race
+      condition
+    - hwmon: (ina3221) return prober error code
+    - media: m5mols: fix off-by-one loop termination error
+    - mmc: atmel-mci: fix race between stop command and start of next command
+    - jffs2: correct logic when creating a hole in jffs2_write_begin
+    - ext4: fail ext4_iget if special inode unallocated
+    - ext4: fix task hung in ext4_xattr_delete_inode
+    - drm/amdkfd: Fix an illegal memory access
+    - sh: intc: Avoid spurious sizeof-pointer-div warning
+    - ext4: fix possible double unlock when moving a directory
+    - tty: serial: fsl_lpuart: skip waiting for transmission complete when
+      UARTCTRL_SBK is asserted
+    - interconnect: fix mem leak when freeing nodes
+    - tracing: Check field value in hist_field_name()
+    - tracing: Make tracepoint lockdep check actually test something
+    - ftrace: Fix invalid address access in lookup_rec() when index is 0
+    - fbdev: stifb: Provide valid pixelclock and add fb_check_var() checks
+    - x86/mm: Fix use of uninitialized buffer in sme_enable()
+    - drm/i915: Don't use stolen memory for ring buffers with LLC
+    - serial: 8250_em: Fix UART port type
+    - s390/ipl: add missing intersection check to ipl_report handling
+    - PCI: Unify delay handling for reset and resume
+    - HID: core: Provide new max_buffer_size attribute to over-ride the default
+    - HID: uhid: Over-ride the default maximum data buffer value with our own
+    - Linux 5.4.238
+  * Focal update: v5.4.237 upstream stable release (LP: #2023420)
+    - fs: prevent out-of-bounds array speculation when closing a file descriptor
+    - x86/CPU/AMD: Disable XSAVES on AMD family 0x17
+    - drm/connector: print max_requested_bpc in state debugfs
+    - ext4: fix RENAME_WHITEOUT handling for inline directories
+    - ext4: fix another off-by-one fsmap error on 1k block filesystems
+    - ext4: move where set the MAY_INLINE_DATA flag is set
+    - ext4: fix WARNING in ext4_update_inline_data
+    - ext4: zero i_disksize when initializing the bootloader inode
+    - nfc: change order inside nfc_se_io error path
+    - iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands
+    - iommu/amd: Fix ill-formed ivrs_ioapic, ivrs_hpet and ivrs_acpihid options
+    - iommu/amd: Add a length limitation for the ivrs_acpihid command-line
+      parameter
+    - ipmi:ssif: make ssif_i2c_send() void
+    - ipmi:ssif: resend_msg() cannot fail
+    - ipmi:ssif: Remove rtc_us_timer
+    - ipmi:ssif: Increase the message retry time
+    - ipmi:ssif: Add a timer between request retries
+    - irqdomain: Change the type of 'size' in __irq_domain_add() to be consistent
+    - irqdomain: Fix domain registration race
+    - iommu/vt-d: Fix PASID directory pointer coherency
+    - SMB3: Backup intent flag missing from some more ops
+    - cifs: Fix uninitialized memory read in smb3_qfs_tcon()
+    - scsi: core: Remove the /proc/scsi/${proc_name} directory earlier
+    - ext4: Fix possible corruption when moving a directory
+    - drm/msm/a5xx: fix setting of the CP_PREEMPT_ENABLE_LOCAL register
+    - nfc: fdp: add null check of devm_kmalloc_array in
+      fdp_nci_i2c_read_device_properties
+    - ila: do not generate empty messages in ila_xlat_nl_cmd_get_mapping()
+    - selftests: nft_nat: ensuring the listening side is up before starting the
+      client
+    - net: usb: lan78xx: Remove lots of set but unused 'ret' variables
+    - net: lan78xx: fix accessing the LAN7800's internal phy specific registers
+      from the MAC driver
+    - net: caif: Fix use-after-free in cfusbl_device_notify()
+    - bnxt_en: Avoid order-5 memory allocation for TPA data
+    - netfilter: tproxy: fix deadlock due to missing BH disable
+    - btf: fix resolving BTF_KIND_VAR after ARRAY, STRUCT, UNION, PTR
+    - scsi: megaraid_sas: Update max supported LD IDs to 240
+    - net/smc: fix fallback failed while sendmsg with fastopen
+    - riscv: Use READ_ONCE_NOCHECK in imprecise unwinding stack mode
+    - ext4: Fix deadlock during directory rename
+    - MIPS: Fix a compilation issue
+    - alpha: fix R_ALPHA_LITERAL reloc for large modules
+    - macintosh: windfarm: Use unsigned type for 1-bit bitfields
+    - PCI: Add SolidRun vendor ID
+    - media: ov5640: Fix analogue gain control
+    - ipmi/watchdog: replace atomic_add() and atomic_sub()
+    - ipmi:watchdog: Set panic count to proper value on a panic
+    - drm/i915: Don't use BAR mappings for ring buffers with LLC
+    - x86, vmlinux.lds: Add RUNTIME_DISCARD_EXIT to generic DISCARDS
+    - arch: fix broken BuildID for arm64 and riscv
+    - powerpc/vmlinux.lds: Define RUNTIME_DISCARD_EXIT
+    - powerpc/vmlinux.lds: Don't discard .rela* for relocatable builds
+    - s390: define RUNTIME_DISCARD_EXIT to fix link error with GNU ld < 2.36
+    - sh: define RUNTIME_DISCARD_EXIT
+    - UML: define RUNTIME_DISCARD_EXIT
+    - s390/dasd: add missing discipline function
+    - Linux 5.4.237
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - staging: rtl8192e: Remove function ..dm_check_ac_dc_power calling a script
+    - staging: rtl8192e: Remove call_usermodehelper starting RadioPower.sh
+    - Linux 5.4.236
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 22 Sep 2023 18:38:25 +0800
+
+linux-ein (5.4.0-1039.46) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1039.46 -proposed tracker (LP: #2029267)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - [Packaging] resync getabis
+
+  * [K4500-NXP][UC20] CPU-Freq Interface Not Available On NXP Hardware
+    (LP#2008278)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Enable cpufreq support
+
+  * WIFI/Bluetooth module is not fully reset/initialized at Linux boot Edit
+    (LP#2019041)
+    - SAUCE: amgis: dts: Add MMC simple HW reset driver node
+
+  * Miscellaneous Ubuntu changes
+    - snap: reading: Set grade to devel instead of stable
+    - snap: reading: Remove package-repositories
+
+  [ Ubuntu: 5.4.0-153.170 ]
+
+  * focal/linux: 5.4.0-153.170 -proposed tracker (LP: #2024108)
+  * cls_flower: off-by-one in fl_set_geneve_opt (LP: #2023577)
+    - net/sched: flower: fix possible OOB write in fl_set_geneve_opt()
+  * Some INVLPG implementations can leave Global translations unflushed when
+    PCIDs are enabled (LP: #2023220)
+    - x86/mm: Avoid incomplete Global INVLPG flushes
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 01 Aug 2023 23:03:05 +0800
+
+linux-ein (5.4.0-1038.45) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1038.45 -proposed tracker (LP: #2024158)
+
+  * CVE-2023-1829
+    - [Config] ein: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+  * Request a change to EMMC access rate, to DDR52 (LP#2012080)
+    - SAUCE: mmc: Add device tree quirks2 property
+    - SAUCE: mmc: Allow device tree to disable HS400
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Disable HS200 and HS400
+
+  [ Ubuntu: 5.4.0-152.169 ]
+
+  * focal/linux: 5.4.0-152.169 -proposed tracker (LP: #2023070)
+  * Focal update: v5.4.236 upstream stable release (LP: #2020390)
+    - wifi: cfg80211: Partial revert "wifi: cfg80211: Fix use after free for wext"
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync git-ubuntu-log
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-151.168 ]
+
+  * focal/linux: 5.4.0-151.168 -proposed tracker (LP: #2019375)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+    - debian/dkms-versions -- update from kernel-versions (main/2023.05.15)
+  * CVE-2023-32233
+    - netfilter: nf_tables: deactivate anonymous set from preparation phase
+  * CVE-2023-2612
+    - SAUCE: shiftfs: prevent lock unbalance in shiftfs_create_object()
+  * 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()
+  * Focal update: Focal update: v5.4.235 upstream stable release (LP: #2017706)
+    - HID: asus: Remove check for same LED brightness on set
+    - HID: asus: use spinlock to protect concurrent accesses
+    - HID: asus: use spinlock to safely schedule workers
+    - ARM: OMAP2+: Fix memory leak in realtime_counter_init()
+    - arm64: dts: qcom: qcs404: use symbol names for PCIe resets
+    - ARM: zynq: Fix refcount leak in zynq_early_slcr_init
+    - arm64: dts: meson-gx: Fix Ethernet MAC address unit name
+    - arm64: dts: meson-g12a: Fix internal Ethernet PHY unit name
+    - arm64: dts: meson-gx: Fix the SCPI DVFS node name and unit address
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12A boards
+    - ARM: OMAP1: call platform_device_put() in error case in
+      omap1_dm_timer_init()
+    - ARM: dts: exynos: correct wr-active property in Exynos3250 Rinato
+    - ARM: imx: Call ida_simple_remove() for ida_simple_get
+    - arm64: dts: amlogic: meson-gx: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-axg: fix SCPI clock dvfs node name
+    - arm64: dts: amlogic: meson-gx: add missing SCPI sensors compatible
+    - arm64: dts: amlogic: meson-gx: add missing unit address to rng node name
+    - arm64: dts: amlogic: meson-gxl: add missing unit address to eth-phy-mux node
+      name
+    - arm64: dts: amlogic: meson-gxl-s905d-phicomm-n1: fix led node name
+    - ARM: dts: imx7s: correct iomuxc gpr mux controller cells
+    - arm64: dts: mediatek: mt7622: Add missing pwm-cells to pwm node
+    - Revert "scsi: core: run queue if SCSI device queue isn't ready and queue is
+      idle"
+    - block: Limit number of items taken from the I/O scheduler in one go
+    - blk-mq: remove stale comment for blk_mq_sched_mark_restart_hctx
+    - blk-mq: wait on correct sbitmap_queue in blk_mq_mark_tag_wait
+    - blk-mq: correct stale comment of .get_budget
+    - s390/dasd: Prepare for additional path event handling
+    - s390/dasd: Fix potential memleak in dasd_eckd_init()
+    - sched/deadline,rt: Remove unused parameter from pick_next_[rt|dl]_entity()
+    - sched/rt: pick_next_rt_entity(): check list_entry
+    - block: bio-integrity: Copy flags when bio_integrity_payload is cloned
+    - wifi: rsi: Fix memory leak in rsi_coex_attach()
+    - net/wireless: Delete unnecessary checks before the macro call
+      “dev_kfree_skb”
+    - wifi: iwlegacy: common: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: fix memory leak in lbs_init_adapter()
+    - wifi: rtl8xxxu: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - rtlwifi: fix -Wpointer-sign warning
+    - wifi: rtlwifi: Fix global-out-of-bounds bug in
+      _rtl8812ae_phy_set_txpower_limit()
+    - ipw2x00: switch from 'pci_' to 'dma_' API
+    - wifi: ipw2x00: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - wifi: ipw2200: fix memory leak in ipw_wdev_init()
+    - wilc1000: let wilc_mac_xmit() return NETDEV_TX_OK
+    - wifi: wilc1000: fix potential memory leak in wilc_mac_xmit()
+    - wifi: brcmfmac: fix potential memory leak in brcmf_netdev_start_xmit()
+    - wifi: brcmfmac: unmap dma buffer in brcmf_msgbuf_alloc_pktid()
+    - wifi: libertas_tf: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: if_usb: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: main: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: libertas: cmdresp: don't call kfree_skb() under spin_lock_irqsave()
+    - wifi: wl3501_cs: don't call kfree_skb() under spin_lock_irqsave()
+    - crypto: x86/ghash - fix unaligned access in ghash_setkey()
+    - ACPICA: Drop port I/O validation for some regions
+    - genirq: Fix the return type of kstat_cpu_irqs_sum()
+    - lib/mpi: Fix buffer overrun when SG is too long
+    - ACPICA: nsrepair: handle cases without a return value correctly
+    - wifi: orinoco: check return value of hermes_write_wordrec()
+    - wifi: ath9k: htc_hst: free skb in ath9k_htc_rx_msg() if there is no callback
+      function
+    - ath9k: hif_usb: simplify if-if to if-else
+    - ath9k: htc: clean up statistics macros
+    - wifi: ath9k: hif_usb: clean up skbs if ath9k_hif_usb_rx_stream() fails
+    - wifi: ath9k: Fix potential stack-out-of-bounds write in
+      ath9k_wmi_rsp_callback()
+    - ACPI: battery: Fix missing NUL-termination with large strings
+    - crypto: ccp - Failure on re-initialization due to duplicate sysfs filename
+    - crypto: essiv - remove redundant null pointer check before kfree
+    - crypto: essiv - Handle EBUSY correctly
+    - crypto: seqiv - Handle EBUSY correctly
+    - powercap: fix possible name leak in powercap_register_zone()
+    - net/mlx5: Enhance debug print in page allocation failure
+    - irqchip/alpine-msi: Fix refcount leak in alpine_msix_init_domains
+    - irqchip/irq-mvebu-gicp: Fix refcount leak in mvebu_gicp_probe
+    - irqchip/ti-sci: Fix refcount leak in ti_sci_intr_irq_domain_probe
+    - mptcp: add sk_stop_timer_sync helper
+    - net: add sock_init_data_uid()
+    - tun: tun_chr_open(): correctly initialize socket uid
+    - tap: tap_open(): correctly initialize socket uid
+    - OPP: fix error checking in opp_migrate_dentry()
+    - Bluetooth: L2CAP: Fix potential user-after-free
+    - libbpf: Fix alen calculation in libbpf_nla_dump_errormsg()
+    - rds: rds_rm_zerocopy_callback() correct order for list_add_tail()
+    - crypto: rsa-pkcs1pad - Use akcipher_request_complete
+    - m68k: /proc/hardware should depend on PROC_FS
+    - RISC-V: time: initialize hrtimer based broadcast clock event device
+    - usb: gadget: udc: Avoid tasklet passing a global
+    - wifi: iwl3945: Add missing check for create_singlethread_workqueue
+    - wifi: iwl4965: Add missing check for create_singlethread_workqueue()
+    - wifi: mwifiex: fix loop iterator in mwifiex_update_ampdu_txwinsize()
+    - crypto: crypto4xx - Call dma_unmap_page when done
+    - wifi: mac80211: make rate u32 in sta_set_rate_info_rx()
+    - thermal/drivers/hisi: Drop second sensor hi3660
+    - can: esd_usb: Move mislocated storage of SJA1000_ECC_SEG bits in case of a
+      bus error
+    - irqchip/irq-brcmstb-l2: Set IRQ_LEVEL for level triggered interrupts
+    - irqchip/irq-bcm7120-l2: Set IRQ_LEVEL for level triggered interrupts
+    - selftests/net: Interpret UDP_GRO cmsg data as an int value
+    - drm/fourcc: Add missing big-endian XRGB1555 and RGB565 formats
+    - drm: mxsfb: DRM_MXSFB should depend on ARCH_MXS || ARCH_MXC
+    - drm/bridge: megachips: Fix error handling in i2c_register_driver()
+    - drm/vc4: dpi: Add option for inverting pixel clock and output enable
+    - drm/vc4: dpi: Fix format mapping for RGB565
+    - gpu: ipu-v3: common: Add of_node_put() for reference returned by
+      of_graph_get_port_by_id()
+    - drm/msm/hdmi: Add missing check for alloc_ordered_workqueue
+    - pinctrl: stm32: Fix refcount leak in stm32_pctrl_get_irq_domain
+    - ASoC: fsl_sai: initialize is_dsp_mode flag
+    - ALSA: hda/ca0132: minor fix for allocation size
+    - drm/mipi-dsi: Fix byte order of 16-bit DCS set/get brightness
+    - drm/msm: use strscpy instead of strncpy
+    - drm/msm/dpu: Add check for cstate
+    - drm/msm/dpu: Add check for pstates
+    - drm/exynos: Don't reset bridge->next
+    - drm/bridge: Rename bridge helpers targeting a bridge chain
+    - drm/bridge: Introduce drm_bridge_get_next_bridge()
+    - drm: Initialize struct drm_crtc_state.no_vblank from device settings
+    - drm/msm/mdp5: Add check for kzalloc
+    - gpu: host1x: Don't skip assigning syncpoints to channels
+    - drm/mediatek: remove cast to pointers passed to kfree
+    - drm/mediatek: Use NULL instead of 0 for NULL pointer
+    - drm/mediatek: Drop unbalanced obj unref
+    - drm/mediatek: Clean dangling pointer on bind error path
+    - ASoC: soc-compress.c: fixup private_data on snd_soc_new_compress()
+    - gpio: vf610: connect GPIO label to dev name
+    - hwmon: (ltc2945) Handle error case in ltc2945_value_store
+    - scsi: aic94xx: Add missing check for dma_map_single()
+    - spi: bcm63xx-hsspi: fix pm_runtime
+    - spi: bcm63xx-hsspi: Fix multi-bit mode setting
+    - hwmon: (mlxreg-fan) Return zero speed for broken fan
+    - dm: remove flush_scheduled_work() during local_exit()
+    - spi: synquacer: Fix timeout handling in synquacer_spi_transfer_one()
+    - ASoC: dapm: declare missing structure prototypes
+    - ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared
+    - HID: bigben: use spinlock to protect concurrent accesses
+    - HID: bigben_worker() remove unneeded check on report_field
+    - HID: bigben: use spinlock to safely schedule workers
+    - HID: asus: Only set EV_REP if we are adding a mapping
+    - HID: asus: Add report_size to struct asus_touchpad_info
+    - HID: asus: Add support for multi-touch touchpad on Medion Akoya E1239T
+    - HID: asus: Fix mute and touchpad-toggle keys on Medion Akoya E1239T
+    - hid: bigben_probe(): validate report count
+    - nfsd: fix race to check ls_layouts
+    - cifs: Fix lost destroy smbd connection when MR allocate failed
+    - cifs: Fix warning and UAF when destroy the MR list
+    - gfs2: jdata writepage fix
+    - perf llvm: Fix inadvertent file creation
+    - perf tools: Fix auto-complete on aarch64
+    - sparc: allow PM configs for sparc32 COMPILE_TEST
+    - mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read()
+    - clk: qcom: gcc-qcs404: disable gpll[04]_out_aux parents
+    - clk: qcom: gcc-qcs404: fix names of the DSI clocks used as parents
+    - mtd: rawnand: sunxi: Fix the size of the last OOB region
+    - clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed
+    - clk: renesas: cpg-mssr: Use enum clk_reg_layout instead of a boolean flag
+    - clk: renesas: cpg-mssr: Remove superfluous check in resume code
+    - Input: ads7846 - don't report pressure for ads7845
+    - Input: ads7846 - don't check penirq immediately for 7845
+    - clk: qcom: gpucc-sdm845: fix clk_dis_wait being programmed for CX GDSC
+    - powerpc/powernv/ioda: Skip unallocated resources when mapping to PE
+    - clk: Honor CLK_OPS_PARENT_ENABLE in clk_core_is_enabled()
+    - powerpc/pseries/lpar: add missing RTAS retry status handling
+    - powerpc/pseries/lparcfg: add missing RTAS retry status handling
+    - powerpc/rtas: make all exports GPL
+    - powerpc/rtas: ensure 4KB alignment for rtas_data_buf
+    - powerpc/eeh: Small refactor of eeh_handle_normal_event()
+    - powerpc/eeh: Set channel state after notifying the drivers
+    - MIPS: SMP-CPS: fix build error when HOTPLUG_CPU not set
+    - MIPS: vpe-mt: drop physical_memsize
+    - remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
+    - media: platform: ti: Add missing check for devm_regulator_get
+    - powerpc: Remove linker flag from KBUILD_AFLAGS
+    - media: ov5675: Fix memleak in ov5675_init_controls()
+    - media: i2c: ov772x: Fix memleak in ov772x_probe()
+    - media: i2c: ov7670: 0 instead of -EINVAL was returned
+    - media: usb: siano: Fix use after free bugs caused by do_submit_urb
+    - rpmsg: glink: Avoid infinite loop on intent for missing channel
+    - udf: Define EFSCORRUPTED error code
+    - ARM: dts: exynos: Use Exynos5420 compatible for the MIPI video phy
+    - blk-iocost: fix divide by 0 error in calc_lcoefs()
+    - wifi: brcmfmac: Fix potential stack-out-of-bounds in brcmf_c_preinit_dcmds()
+    - rcu: Suppress smp_processor_id() complaint in
+      synchronize_rcu_expedited_wait()
+    - thermal: intel: Fix unsigned comparison with less than zero
+    - timers: Prevent union confusion from unexpected restart_syscall()
+    - x86/bugs: Reset speculation control settings on init
+    - wifi: brcmfmac: ensure CLM version is null-terminated to prevent stack-out-
+      of-bounds
+    - wifi: mt7601u: fix an integer underflow
+    - inet: fix fast path in __inet_hash_connect()
+    - ice: add missing checks for PF vsi type
+    - ACPI: Don't build ACPICA with '-Os'
+    - net: bcmgenet: Add a check for oversized packets
+    - m68k: Check syscall_trace_enter() return code
+    - wifi: mt76: dma: free rx_head in mt76_dma_rx_cleanup
+    - ACPI: video: Fix Lenovo Ideapad Z570 DMI match
+    - net/mlx5: fw_tracer: Fix debug print
+    - coda: Avoid partial allocation of sig_inputArgs
+    - uaccess: Add minimum bounds check on kernel buffer size
+    - drm/amd/display: Fix potential null-deref in dm_resume
+    - drm/omap: dsi: Fix excessive stack usage
+    - HID: Add Mapping for System Microphone Mute
+    - drm/radeon: free iio for atombios when driver shutdown
+    - drm/msm/dsi: Add missing check for alloc_ordered_workqueue
+    - docs/scripts/gdb: add necessary make scripts_gdb step
+    - ASoC: kirkwood: Iterate over array indexes instead of using pointer math
+    - regulator: max77802: Bounds check regulator id against opmode
+    - regulator: s5m8767: Bounds check id indexing into arrays
+    - hwmon: (coretemp) Simplify platform device handling
+    - pinctrl: at91: use devm_kasprintf() to avoid potential leaks
+    - drm: panel-orientation-quirks: Add quirk for Lenovo IdeaPad Duet 3 10IGL5
+    - dm thin: add cond_resched() to various workqueue loops
+    - dm cache: add cond_resched() to various workqueue loops
+    - nfsd: zero out pointers after putting nfsd_files on COPY setup error
+    - wifi: rtl8xxxu: fixing transmisison failure for rtl8192eu
+    - firmware: coreboot: framebuffer: Ignore reserved pixel color bits
+    - rtc: pm8xxx: fix set-alarm race
+    - ipmi_ssif: Rename idle state and check
+    - s390: discard .interp section
+    - s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
+    - s390/kprobes: fix current_kprobe never cleared after kprobes reenter
+    - ARM: dts: exynos: correct HDMI phy compatible in Exynos4
+    - hfs: fix missing hfs_bnode_get() in __hfs_bnode_create
+    - fs: hfsplus: fix UAF issue in hfsplus_put_super
+    - f2fs: fix information leak in f2fs_move_inline_dirents()
+    - f2fs: fix cgroup writeback accounting with fs-layer encryption
+    - ocfs2: fix defrag path triggering jbd2 ASSERT
+    - ocfs2: fix non-auto defrag path not working issue
+    - udf: Truncate added extents on failed expansion
+    - udf: Do not bother merging very long extents
+    - udf: Do not update file length for failed writes to inline files
+    - udf: Preserve link count of system files
+    - udf: Detect system inodes linked into directory hierarchy
+    - udf: Fix file corruption when appending just after end of preallocated
+      extent
+    - KVM: Destroy target device if coalesced MMIO unregistration fails
+    - KVM: s390: disable migration mode when dirty tracking is disabled
+    - x86/virt: Force GIF=1 prior to disabling SVM (for reboot flows)
+    - x86/crash: Disable virt in core NMI crash handler to avoid double shootdown
+    - x86/reboot: Disable virtualization in an emergency if SVM is supported
+    - x86/reboot: Disable SVM, not just VMX, when stopping CPUs
+    - x86/kprobes: Fix __recover_optprobed_insn check optimizing logic
+    - x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe
+      range
+    - x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
+    - x86/microcode/AMD: Add a @cpu parameter to the reloading functions
+    - x86/microcode/AMD: Fix mixed steppings support
+    - x86/speculation: Allow enabling STIBP with legacy IBRS
+    - Documentation/hw-vuln: Document the interaction between IBRS and STIBP
+    - ima: Align ima_file_mmap() parameters with mmap_file LSM hook
+    - irqdomain: Fix association race
+    - irqdomain: Fix disassociation race
+    - irqdomain: Drop bogus fwspec-mapping error handling
+    - ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls()
+    - ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC
+    - ext4: optimize ea_inode block expansion
+    - ext4: refuse to create ea block when umounted
+    - wifi: rtl8xxxu: Use a longer retry limit of 48
+    - wifi: cfg80211: Fix use after free for wext
+    - thermal: intel: powerclamp: Fix cur_state for multi package system
+    - dm flakey: fix logic when corrupting a bio
+    - dm flakey: don't corrupt the zero page
+    - ARM: dts: exynos: correct TMU phandle in Exynos4
+    - ARM: dts: exynos: correct TMU phandle in Odroid XU
+    - rbd: avoid use-after-free in do_rbd_add() when rbd_dev_create() fails
+    - alpha: fix FEN fault handling
+    - mips: fix syscall_get_nr
+    - media: ipu3-cio2: Fix PM runtime usage_count in driver unbind
+    - mm: memcontrol: deprecate charge moving
+    - mm/thp: check and bail out if page in deferred queue already
+    - ktest.pl: Give back console on Ctrt^C on monitor
+    - ktest.pl: Fix missing "end_monitor" when machine check fails
+    - ktest.pl: Add RUN_TIMEOUT option with default unlimited
+    - scsi: qla2xxx: Fix link failure in NPIV environment
+    - scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests
+    - scsi: qla2xxx: Fix erroneous link down
+    - scsi: ses: Don't attach if enclosure has no components
+    - scsi: ses: Fix slab-out-of-bounds in ses_enclosure_data_process()
+    - scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix possible desc_ptr out-of-bounds accesses
+    - scsi: ses: Fix slab-out-of-bounds in ses_intf_remove()
+    - PCI/PM: Observe reset delay irrespective of bridge_d3
+    - PCI: hotplug: Allow marking devices as disconnected during bind/unbind
+    - PCI: Avoid FLR for AMD FCH AHCI adapters
+    - drm/i915/quirks: Add inverted backlight quirk for HP 14-r206nv
+    - drm/radeon: Fix eDP for single-display iMac11,2
+    - wifi: ath9k: use proper statements in conditionals
+    - kbuild: Port silent mode detection to future gnu make.
+    - fs/jfs: fix shift exponent db_agl2size negative
+    - pwm: sifive: Reduce time the controller lock is held
+    - pwm: sifive: Always let the first pwm_apply_state succeed
+    - pwm: stm32-lp: fix the check on arr and cmp registers update
+    - f2fs: use memcpy_{to,from}_page() where possible
+    - fs: f2fs: initialize fsdata in pagecache_write()
+    - um: vector: Fix memory leak in vector_config
+    - ubi: ensure that VID header offset + VID header size <= alloc, size
+    - ubifs: Fix build errors as symbol undefined
+    - ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted
+    - ubifs: Rectify space budget for ubifs_xrename()
+    - ubifs: Fix wrong dirty space budget for dirty inode
+    - ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1
+    - ubifs: Reserve one leb for each journal head while doing budget
+    - ubi: Fix use-after-free when volume resizing failed
+    - ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume()
+    - ubifs: Fix memory leak in alloc_wbufs()
+    - ubi: Fix possible null-ptr-deref in ubi_free_volume()
+    - ubifs: Re-statistic cleaned znode count if commit failed
+    - ubifs: dirty_cow_znode: Fix memleak in error handling path
+    - ubifs: ubifs_writepage: Mark page dirty after writing inode failed
+    - ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show()
+    - ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed
+    - x86: um: vdso: Add '%rcx' and '%r11' to the syscall clobber list
+    - watchdog: at91sam9_wdt: use devm_request_irq to avoid missing free_irq() in
+      error path
+    - watchdog: Fix kmemleak in watchdog_cdev_register
+    - watchdog: pcwd_usb: Fix attempting to access uninitialized memory
+    - netfilter: ctnetlink: fix possible refcount leak in
+      ctnetlink_create_conntrack()
+    - ipv6: Add lwtunnel encap size of all siblings in nexthop calculation
+    - sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop
+    - net: fix __dev_kfree_skb_any() vs drop monitor
+    - 9p/xen: fix version parsing
+    - 9p/xen: fix connection sequence
+    - 9p/rdma: unmap receive dma buffer in rdma_request()/post_recv()
+    - net/mlx5: Geneve, Fix handling of Geneve object id as error code
+    - nfc: fix memory leak of se_io context in nfc_genl_se_io
+    - net/sched: act_sample: fix action bind logic
+    - ARM: dts: spear320-hmi: correct STMPE GPIO compatible
+    - tcp: tcp_check_req() can be called from process context
+    - vc_screen: modify vcs_size() handling in vcs_read()
+    - rtc: sun6i: Make external 32k oscillator optional
+    - rtc: sun6i: Always export the internal oscillator
+    - scsi: ipr: Work around fortify-string warning
+    - thermal: intel: quark_dts: fix error pointer dereference
+    - thermal: intel: BXT_PMIC: select REGMAP instead of depending on it
+    - tracing: Add NULL checks for buffer in ring_buffer_free_read_page()
+    - firmware/efi sysfb_efi: Add quirk for Lenovo IdeaPad Duet 3
+    - mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak
+    - media: uvcvideo: Handle cameras with invalid descriptors
+    - media: uvcvideo: Handle errors from calls to usb_string
+    - media: uvcvideo: Quirk for autosuspend in Logitech B910 and C910
+    - media: uvcvideo: Silence memcpy() run-time false positive warnings
+    - staging: emxx_udc: Add checks for dma_alloc_coherent()
+    - tty: fix out-of-bounds access in tty_driver_lookup_tty()
+    - tty: serial: fsl_lpuart: disable the CTS when send break signal
+    - mei: bus-fixup:upon error print return values of send and receive
+    - tools/iio/iio_utils:fix memory leak
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_status_word()
+    - iio: accel: mma9551_core: Prevent uninitialized variable in
+      mma9551_read_config_word()
+    - usb: host: xhci: mvebu: Iterate over array indexes instead of using pointer
+      math
+    - USB: ene_usb6250: Allocate enough memory for full object
+    - usb: uvc: Enumerate valid values for color matching
+    - kernel/fail_function: fix memory leak with using debugfs_lookup()
+    - PCI: Add ACS quirk for Wangxun NICs
+    - phy: rockchip-typec: Fix unsigned comparison with less than zero
+    - net: tls: avoid hanging tasks on the tx_lock
+    - x86/resctrl: Apply READ_ONCE/WRITE_ONCE to task_struct.{rmid,closid}
+    - x86/resctl: fix scheduler confusion with 'current'
+    - Bluetooth: hci_sock: purge socket queues in the destruct() callback
+    - SAUCE: Revert "UBUNTU: SAUCE: Fix inet_csk_listen_start after CVE-2023-0461"
+    - tcp: Fix listen() regression in 5.4.229.
+    - media: uvcvideo: Provide sync and async uvc_ctrl_status_event
+    - media: uvcvideo: Fix race condition with usb_kill_urb
+    - dt-bindings: rtc: sun6i-a31-rtc: Loosen the requirements on the clocks
+    - Linux 5.4.235
+    - [Config] Drop mxsfb for armhf:generic-lpae
+  * Focal update: v5.4.234 upstream stable release (LP: #2017691)
+    - arm64: dts: rockchip: drop unused LED mode property from rk3328-roc-cc
+    - ARM: dts: rockchip: add power-domains property to dp node on rk3288
+    - ACPI: NFIT: fix a potential deadlock during NFIT teardown
+    - btrfs: send: limit number of clones and allocated memory size
+    - IB/hfi1: Assign npages earlier
+    - neigh: make sure used and confirmed times are valid
+    - HID: core: Fix deadloop in hid_apply_multiplier.
+    - bpf: bpf_fib_lookup should not return neigh in NUD_FAILED state
+    - net: Remove WARN_ON_ONCE(sk->sk_forward_alloc) from sk_stream_kill_queues().
+    - vc_screen: don't clobber return value in vcs_read
+    - dmaengine: sh: rcar-dmac: Check for error num after dma_set_max_seg_size
+    - USB: serial: option: add support for VW/Skoda "Carstick LTE"
+    - USB: core: Don't hold device lock while reading the "descriptors" sysfs file
+    - Linux 5.4.234
+  * CVE-2023-30456
+    - KVM: nVMX: add missing consistency checks for CR0 and CR4
+  * CVE-2023-1859
+    - 9p/xen : Fix use after free bug in xen_9pfs_front_remove due to race
+      condition
+  * CVE-2023-1670
+    - xirc2ps_cs: Fix use after free bug in xirc2ps_detach
+
+  [ Ubuntu: 5.4.0-149.166 ]
+
+  * focal/linux: 5.4.0-149.166 -proposed tracker (LP: #2016591)
+  * Focal update: v5.4.233 upstream stable release (LP: #2015909)
+    - dma-mapping: add generic helpers for mapping sgtable objects
+    - scatterlist: add generic wrappers for iterating over sgtable objects
+    - drm: etnaviv: fix common struct sg_table related issues
+    - drm/etnaviv: don't truncate physical page address
+    - wifi: rtl8xxxu: gen2: Turn on the rate control
+    - powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G
+    - random: always mix cycle counter in add_latent_entropy()
+    - KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception
+    - can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len
+    - powerpc: dts: t208x: Disable 10G on MAC1 and MAC2
+    - alarmtimer: Prevent starvation by small intervals and SIG_IGN
+    - drm/i915/gvt: fix double free bug in split_2MB_gtt_entry
+    - mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
+    - uaccess: Add speculation barrier to copy_from_user()
+    - wifi: mwifiex: Add missing compatible string for SD8787
+    - ext4: Fix function prototype mismatch for ext4_feat_ktype
+    - Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo
+      child qdiscs"
+    - bpf: add missing header file include
+    - Linux 5.4.233
+  *  selftest: fib_tests: Always cleanup before exit  (LP: #2015956)
+    - selftest: fib_tests: Always cleanup before exit
+  * fib_tests.sh in ubuntu_kernel_selftests was skipped silently on Focal
+    (LP: #2015440)
+    - selftests: Fix the executable permissions for fib_tests.sh
+  * Debian autoreconstruct Fix restoration of execute permissions (LP: #2015498)
+    - [Debian] autoreconstruct - fix restoration of execute permissions
+  * kernel: fix __clear_user() inline assembly constraints (LP: #2013088)
+    - s390/uaccess: add missing earlyclobber annotations to __clear_user()
+  * i/o error if next unused loop device is queried (LP: #1856871)
+    - loop: fix I/O error on fsync() in detached loop devices
+  * CVE-2023-1075
+    - net/tls: tls_is_tx_ready() checked list_entry
+  * Focal update: v5.4.232 upstream stable release (LP: #2011625)
+    - firewire: fix memory leak for payload of request subaction to IEC 61883-1
+      FCP region
+    - bus: sunxi-rsb: Fix error handling in sunxi_rsb_init()
+    - ASoC: Intel: bytcr_rt5651: Drop reference count of ACPI device after use
+    - ALSA: hda/via: Avoid potential array out-of-bound in add_secret_dac_path()
+    - arm64: dts: imx8mm: Fix pad control for UART1_DTE_RX
+    - scsi: Revert "scsi: core: map PQ=1, PDT=other values to
+      SCSI_SCAN_TARGET_PRESENT"
+    - WRITE is "data source", not destination...
+    - fix iov_iter_bvec() "direction" argument
+    - fix "direction" argument of iov_iter_kvec()
+    - netrom: Fix use-after-free caused by accept on already connected socket
+    - netfilter: br_netfilter: disable sabotage_in hook after first suppression
+    - squashfs: harden sanity check in squashfs_read_xattr_id_table
+    - net: phy: meson-gxl: Add generic dummy stubs for MMD register access
+    - can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
+    - ata: libata: Fix sata_down_spd_limit() when no link speed is reported
+    - selftests: net: udpgso_bench_rx: Fix 'used uninitialized' compiler warning
+    - selftests: net: udpgso_bench_rx/tx: Stop when wrong CLI args are provided
+    - selftests: net: udpgso_bench_tx: Cater for pending datagrams zerocopy
+      benchmarking
+    - virtio-net: Keep stop() to follow mirror sequence of open()
+    - net: openvswitch: fix flow memory leak in ovs_flow_cmd_new
+    - efi: fix potential NULL deref in efi_mem_reserve_persistent
+    - scsi: target: core: Fix warning on RT kernels
+    - scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
+    - i2c: rk3x: fix a bunch of kernel-doc warnings
+    - net/x25: Fix to not accept on connected socket
+    - iio: adc: stm32-dfsdm: fill module aliases
+    - usb: dwc3: dwc3-qcom: Fix typo in the dwc3 vbus override API
+    - usb: dwc3: qcom: enable vbus override when in OTG dr-mode
+    - usb: gadget: f_fs: Fix unbalanced spinlock in __ffs_ep0_queue_wait
+    - vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
+    - Input: i8042 - move __initconst to fix code styling warning
+    - Input: i8042 - merge quirk tables
+    - Input: i8042 - add TUXEDO devices to i8042 quirk tables
+    - Input: i8042 - add Clevo PCX0DX to i8042 quirk table
+    - fbcon: Check font dimension limits
+    - watchdog: diag288_wdt: do not use stack buffers for hardware data
+    - watchdog: diag288_wdt: fix __diag288() inline assembly
+    - efi: Accept version 2 of memory attributes table
+    - iio: hid: fix the retval in accel_3d_capture_sample
+    - iio: adc: berlin2-adc: Add missing of_node_put() in error path
+    - iio:adc:twl6030: Enable measurements of VUSB, VBAT and others
+    - parisc: Fix return code of pdc_iodc_print()
+    - parisc: Wire up PTRACE_GETREGS/PTRACE_SETREGS for compat case
+    - riscv: disable generation of unwind tables
+    - mm: hugetlb: proc: check for hugetlb shared PMD in /proc/PID/smaps
+    - fpga: stratix10-soc: Fix return value check in s10_ops_write_init()
+    - mm/swapfile: add cond_resched() in get_swap_pages()
+    - Squashfs: fix handling and sanity checking of xattr_ids count
+    - nvmem: core: fix cell removal on error
+    - mm: swap: properly update readahead statistics in unuse_pte_range()
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - serial: 8250_dma: Fix DMA Rx completion race
+    - serial: 8250_dma: Fix DMA Rx rearm race
+    - powerpc/imc-pmu: Revert nest_init_lock to being a mutex
+    - fbdev: smscufx: fix error handling code in ufx_usb_probe
+    - f2fs: fix to do sanity check on i_extra_isize in is_alive()
+    - wifi: brcmfmac: Check the count value of channel spec to prevent out-of-
+      bounds reads
+    - iio:adc:twl6030: Enable measurement of VAC
+    - btrfs: limit device extents to the device size
+    - btrfs: zlib: zero-initialize zlib workspace
+    - ALSA: emux: Avoid potential array out-of-bound in snd_emux_xg_control()
+    - tracing: Fix poll() and select() do not work on per_cpu trace_pipe and
+      trace_pipe_raw
+    - can: j1939: do not wait 250 ms if the same addr was already claimed
+    - IB/hfi1: Restore allocated resources on failed copyout
+    - IB/IPoIB: Fix legacy IPoIB due to wrong number of queues
+    - iommu: Add gfp parameter to iommu_ops::map
+    - RDMA/usnic: use iommu_map_atomic() under spin_lock()
+    - xfrm: fix bug with DSCP copy to v6 from v4 tunnel
+    - bonding: fix error checking in bond_debug_reregister()
+    - net: phy: meson-gxl: use MMD access dummy stubs for GXL, internal PHY
+    - ionic: clean interrupt before enabling queue to avoid credit race
+    - ice: Do not use WQ_MEM_RECLAIM flag for workqueue
+    - rds: rds_rm_zerocopy_callback() use list_first_entry()
+    - selftests: forwarding: lib: quote the sysctl values
+    - ALSA: pci: lx6464es: fix a debug loop
+    - pinctrl: aspeed: Fix confusing types in return value
+    - pinctrl: single: fix potential NULL dereference
+    - pinctrl: intel: Restore the pins that used to be in Direct IRQ mode
+    - net: USB: Fix wrong-direction WARNING in plusb.c
+    - usb: core: add quirk for Alcor Link AK9563 smartcard reader
+    - usb: typec: altmodes/displayport: Fix probe pin assign check
+    - ceph: flush cap releases when the session is flushed
+    - riscv: Fixup race condition on PG_dcache_clean in flush_icache_pte
+    - arm64: dts: meson-gx: Make mmc host controller interrupts level-sensitive
+    - arm64: dts: meson-g12-common: Make mmc host controller interrupts level-
+      sensitive
+    - arm64: dts: meson-axg: Make mmc host controller interrupts level-sensitive
+    - nvme-pci: Move enumeration by class to be last in the table
+    - bpf: Always return target ifindex in bpf_fib_lookup
+    - migrate: hugetlb: check for hugetlb shared PMD in node migration
+    - selftests/bpf: Verify copy_register_state() preserves parent/live fields
+    - ASoC: cs42l56: fix DT probe
+    - tools/virtio: fix the vringh test for virtio ring changes
+    - net/rose: Fix to not accept on connected socket
+    - net: stmmac: do not stop RX_CLK in Rx LPI state for qcs404 SoC
+    - net: sched: sch: Bounds check priority
+    - s390/decompressor: specify __decompress() buf len to avoid overflow
+    - nvme-fc: fix a missing queue put in nvmet_fc_ls_create_association
+    - aio: fix mremap after fork null-deref
+    - btrfs: free device in btrfs_close_devices for a single device filesystem
+    - netfilter: nft_tproxy: restrict to prerouting hook
+    - xfs: remove the xfs_efi_log_item_t typedef
+    - xfs: remove the xfs_efd_log_item_t typedef
+    - xfs: remove the xfs_inode_log_item_t typedef
+    - xfs: factor out a xfs_defer_create_intent helper
+    - xfs: merge the ->log_item defer op into ->create_intent
+    - xfs: merge the ->diff_items defer op into ->create_intent
+    - xfs: turn dfp_intent into a xfs_log_item
+    - xfs: refactor xfs_defer_finish_noroll
+    - xfs: log new intent items created as part of finishing recovered intent
+      items
+    - xfs: fix finobt btree block recovery ordering
+    - xfs: proper replay of deferred ops queued during log recovery
+    - xfs: xfs_defer_capture should absorb remaining block reservations
+    - xfs: xfs_defer_capture should absorb remaining transaction reservation
+    - xfs: clean up bmap intent item recovery checking
+    - xfs: clean up xfs_bui_item_recover iget/trans_alloc/ilock ordering
+    - xfs: fix an incore inode UAF in xfs_bui_recover
+    - xfs: change the order in which child and parent defer ops are finished
+    - xfs: periodically relog deferred intent items
+    - xfs: expose the log push threshold
+    - xfs: only relog deferred intent items if free space in the log gets low
+    - xfs: fix missing CoW blocks writeback conversion retry
+    - xfs: ensure inobt record walks always make forward progress
+    - xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks
+    - xfs: prevent UAF in xfs_log_item_in_current_chkpt
+    - xfs: sync lazy sb accounting on quiesce of read-only mounts
+    - Revert "ipv4: Fix incorrect route flushing when source address is deleted"
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - mmc: sdio: fix possible resource leaks in some error paths
+    - mmc: mmc_spi: fix error handling in mmc_spi_probe()
+    - ALSA: hda/conexant: add a new hda codec SN6180
+    - ALSA: hda/realtek - fixed wrong gpio assigned
+    - sched/psi: Fix use-after-free in ep_remove_wait_queue()
+    - hugetlb: check for undefined shift on 32 bit architectures
+    - Revert "mm: Always release pages to the buddy allocator in
+      memblock_free_late()."
+    - net: Fix unwanted sign extension in netdev_stats_to_stats64()
+    - revert "squashfs: harden sanity check in squashfs_read_xattr_id_table"
+    - ixgbe: allow to increase MTU to 3K with XDP enabled
+    - i40e: add double of VLAN header when computing the max MTU
+    - net: bgmac: fix BCM5358 support by setting correct flags
+    - sctp: sctp_sock_filter(): avoid list_entry() on possibly empty list
+    - dccp/tcp: Avoid negative sk_forward_alloc by ipv6_pinfo.pktoptions.
+    - net/usb: kalmia: Don't pass act_len in usb_bulk_msg error path
+    - net: stmmac: fix order of dwmac5 FlexPPS parametrization sequence
+    - bnxt_en: Fix mqprio and XDP ring checking logic
+    - net: stmmac: Restrict warning on disabling DMA store and fwd mode
+    - ixgbe: add double of VLAN header when computing the max MTU
+    - ipv6: Fix datagram socket connection with DSCP.
+    - ipv6: Fix tcp socket connection with DSCP.
+    - i40e: Add checking for null for nlmsg_find_attr()
+    - kvm: initialize all of the kvm_debugregs structure before sending it to
+      userspace
+    - nilfs2: fix underflow in second superblock position calculations
+    - ASoC: SOF: Intel: hda-dai: fix possible stream_tag leak
+    - net: sched: sch: Fix off by one in htb_activate_prios()
+    - iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()
+    - Linux 5.4.232
+  * CVE-2023-1118
+    - media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
+
+  [ Ubuntu: 5.4.0-148.165 ]
+
+  * focal/linux: 5.4.0-148.165 -proposed tracker (LP: #2016777)
+  * CVE-2023-1829
+    - net/sched: Retire tcindex classifier
+    - [Config]: Make sure CONFIG_NET_CLS_TCINDEX is not available
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 19 Jun 2023 13:05:12 +0800
+
+linux-ein (5.4.0-1037.43) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1037.43 -proposed tracker (LP: #2017272)
+
+  * [K4500-NXP][UC20] Unexpectedly reboot if using the kernel on 'master' branch
+    (LP: #2008068)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Load panel driver early
+
+  * Miscellaneous Ubuntu changes
+    - snap: Add snapcraft.yaml for Reading
+    - snap: reading: Add customized firmware
+    - snap: adopt trim-firmware
+
+  [ Ubuntu: 5.4.0-147.164 ]
+
+  * focal/linux: 5.4.0-147.164 -proposed tracker (LP: #2011959)
+  * CVE-2023-26545
+    - net: mpls: fix stale pointer if allocation fails during device rename
+  * CVE-2023-1281
+    - rcu: Upgrade rcu_swap_protected() to rcu_replace_pointer()
+    - net/sched: tcindex: update imperfect hash filters respecting rcu
+  * Focal update: v5.4.231 upstream stable release (LP: #2011226)
+    - clk: generalize devm_clk_get() a bit
+    - clk: Provide new devm_clk helpers for prepared and enabled clocks
+    - memory: atmel-sdramc: Fix missing clk_disable_unprepare in
+      atmel_ramc_probe()
+    - memory: mvebu-devbus: Fix missing clk_disable_unprepare in
+      mvebu_devbus_probe()
+    - ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts'
+    - ARM: imx27: Retrieve the SYSCTRL base address from devicetree
+    - ARM: imx31: Retrieve the IIM base address from devicetree
+    - ARM: imx35: Retrieve the IIM base address from devicetree
+    - ARM: imx: add missing of_node_put()
+    - HID: intel_ish-hid: Add check for ishtp_dma_tx_map
+    - EDAC/highbank: Fix memory leak in highbank_mc_probe()
+    - tomoyo: fix broken dependency on *.conf.default
+    - RDMA/core: Fix ib block iterator counter overflow
+    - IB/hfi1: Reject a zero-length user expected buffer
+    - IB/hfi1: Reserve user expected TIDs
+    - IB/hfi1: Fix expected receive setup error exit issues
+    - affs: initialize fsdata in affs_truncate()
+    - amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent
+    - amd-xgbe: Delay AN timeout during KR training
+    - bpf: Fix pointer-leak due to insufficient speculative store bypass
+      mitigation
+    - phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in
+      rockchip_usb2phy_power_on()
+    - net: nfc: Fix use-after-free in local_cleanup()
+    - net: wan: Add checks for NULL for utdm in undo_uhdlc_init and unmap_si_regs
+    - gpio: mxc: Always set GPIOs used as interrupt source to INPUT mode
+    - net/sched: sch_taprio: fix possible use-after-free
+    - net: fix a concurrency bug in l2tp_tunnel_register()
+    - l2tp: Serialize access to sk_user_data with sk_callback_lock
+    - l2tp: Don't sleep and disable BH under writer-side sk_callback_lock
+    - net: usb: sr9700: Handle negative len
+    - net: mdio: validate parameter addr in mdiobus_get_phy()
+    - HID: check empty report_list in hid_validate_values()
+    - HID: check empty report_list in bigben_probe()
+    - net: stmmac: fix invalid call to mdiobus_get_phy()
+    - HID: revert CHERRY_MOUSE_000C quirk
+    - usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
+    - usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
+    - net: mlx5: eliminate anonymous module_init & module_exit
+    - drm/panfrost: fix GENERIC_ATOMIC64 dependency
+    - dmaengine: Fix double increment of client_count in dma_chan_get()
+    - net: macb: fix PTP TX timestamp failure due to packet padding
+    - HID: betop: check shape of output reports
+    - dmaengine: xilinx_dma: use devm_platform_ioremap_resource()
+    - dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling
+    - dmaengine: xilinx_dma: call of_node_put() when breaking out of
+      for_each_child_of_node()
+    - tcp: avoid the lookup process failing to get sk in ehash table
+    - w1: fix deadloop in __w1_remove_master_device()
+    - w1: fix WARNING after calling w1_process()
+    - driver core: Fix test_async_probe_init saves device in wrong array
+    - net: dsa: microchip: ksz9477: port map correction in ALU table entry
+      register
+    - tcp: fix rate_app_limited to default to 1
+    - cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist
+    - ASoC: fsl_micfil: Correct the number of steps on SX controls
+    - drm: Add orientation quirk for Lenovo ideapad D330-10IGL
+    - s390/debug: add _ASM_S390_ prefix to header guard
+    - cpufreq: armada-37xx: stop using 0 as NULL pointer
+    - ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
+    - ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
+    - spi: spidev: remove debug messages that access spidev->spi without locking
+    - KVM: s390: interrupt: use READ_ONCE() before cmpxchg()
+    - scsi: hisi_sas: Set a port invalid only if there are no devices attached
+      when refreshing port id
+    - platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD
+    - platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK
+    - lockref: stop doing cpu_relax in the cmpxchg loop
+    - mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
+    - mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
+    - mmc: sdhci-esdhc-imx: correct the tuning start tap and step setting
+    - netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state
+    - fs: reiserfs: remove useless new_opts in reiserfs_remount
+    - Bluetooth: hci_sync: cancel cmd_timer if hci_open failed
+    - scsi: hpsa: Fix allocation size for scsi_host_alloc()
+    - module: Don't wait for GOING modules
+    - tracing: Make sure trace_printk() can output as soon as it can be used
+    - trace_events_hist: add check for return value of 'create_hist_field'
+    - ftrace/scripts: Update the instructions for ftrace-bisect.sh
+    - cifs: Fix oops due to uncleared server->smbd_conn in reconnect
+    - KVM: x86/vmx: Do not skip segment attributes if unusable bit is set
+    - thermal: intel: int340x: Protect trip temperature from concurrent updates
+    - ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment
+    - EDAC/device: Respect any driver-supplied workqueue polling value
+    - EDAC/qcom: Do not pass llcc_driv_data as edac_device_ctl_info's pvt_info
+    - netlink: prevent potential spectre v1 gadgets
+    - net: fix UaF in netns ops registration error path
+    - netfilter: nft_set_rbtree: skip elements in transaction from garbage
+      collection
+    - netlink: annotate data races around nlk->portid
+    - netlink: annotate data races around dst_portid and dst_group
+    - netlink: annotate data races around sk_state
+    - ipv4: prevent potential spectre v1 gadget in ip_metrics_convert()
+    - ipv4: prevent potential spectre v1 gadget in fib_metrics_match()
+    - netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE
+    - netrom: Fix use-after-free of a listening socket.
+    - net/sched: sch_taprio: do not schedule in taprio_reset()
+    - sctp: fail if no bound addresses can be used for a given scope
+    - net: ravb: Fix possible hang if RIS2_QFF1 happen
+    - thermal: intel: int340x: Add locking to int340x_thermal_get_trip_type()
+    - net/tg3: resolve deadlock in tg3_reset_task() during EEH
+    - net/phy/mdio-i2c: Move header file to include/linux/mdio
+    - net: xgene: Move shared header file into include/linux
+    - net: mdio-mux-meson-g12a: force internal PHY off on mux switch
+    - Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI
+      mode"
+    - nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted
+    - block: fix and cleanup bio_check_ro
+    - x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
+    - netfilter: conntrack: unify established states for SCTP paths
+    - perf/x86/amd: fix potential integer overflow on shift of a int
+    - clk: Fix pointer casting to prevent oops in devm_clk_release()
+    - x86/asm: Fix an assembler warning with current binutils
+    - ARM: dts: imx: Fix pca9547 i2c-mux node name
+    - bpf: Skip task with pid=1 in send_signal_common()
+    - blk-cgroup: fix missing pd_online_fn() while activating policy
+    - dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init
+    - sysctl: add a new register_sysctl_init() interface
+    - panic: unset panic_on_warn inside panic()
+    - mm: kasan: do not panic if both panic_on_warn and kasan_multishot set
+    - exit: Add and use make_task_dead.
+    - objtool: Add a missing comma to avoid string concatenation
+    - hexagon: Fix function name in die()
+    - h8300: Fix build errors from do_exit() to make_task_dead() transition
+    - csky: Fix function name in csky_alignment() and die()
+    - ia64: make IA64_MCA_RECOVERY bool instead of tristate
+    - exit: Put an upper limit on how often we can oops
+    - exit: Expose "oops_count" to sysfs
+    - exit: Allow oops_limit to be disabled
+    - panic: Consolidate open-coded panic_on_warn checks
+    - panic: Introduce warn_limit
+    - panic: Expose "warn_count" to sysfs
+    - docs: Fix path paste-o for /sys/kernel/warn_count
+    - exit: Use READ_ONCE() for all oops/warn limit reads
+    - ipv6: ensure sane device mtu in tunnels
+    - Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt
+    - usb: host: xhci-plat: add wakeup entry at sysfs
+    - Revert "xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()"
+    - Linux 5.4.231
+  * CVE-2022-3903
+    - USB: add usb_control_msg_send() and usb_control_msg_recv()
+    - USB: correct API of usb_control_msg_send/recv
+    - USB: move snd_usb_pipe_sanity_check into the USB core
+    - media: mceusb: Use new usb_control_msg_*() routines
+  * CVE-2022-3108
+    - drm/amdkfd: Check for null pointer after calling kmemdup
+  * Focal update: v5.4.230 upstream stable release (LP: #2008946)
+    - pNFS/filelayout: Fix coalescing test for single DS
+    - net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats
+    - RDMA/srp: Move large values to a new enum for gcc13
+    - f2fs: let's avoid panic if extent_tree is not created
+    - wifi: brcmfmac: fix regression for Broadcom PCIe wifi devices
+    - Add exception protection processing for vd in axi_chan_handle_err function
+    - nilfs2: fix general protection fault in nilfs_btree_insert()
+    - efi: fix userspace infinite retry read efivars after EFI runtime services
+      page fault
+    - drm/i915/gt: Reset twice
+    - ALSA: hda/realtek - Turn on power early
+    - xhci-pci: set the dma max_seg_size
+    - usb: xhci: Check endpoint is valid before dereferencing it
+    - xhci: Fix null pointer dereference when host dies
+    - xhci: Add update_hub_device override for PCI xHCI hosts
+    - xhci: Add a flag to disable USB3 lpm on a xhci root port level.
+    - usb: acpi: add helper to check port lpm capability using acpi _DSM
+    - xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
+    - prlimit: do_prlimit needs to have a speculation check
+    - USB: serial: option: add Quectel EM05-G (GR) modem
+    - USB: serial: option: add Quectel EM05-G (CS) modem
+    - USB: serial: option: add Quectel EM05-G (RS) modem
+    - USB: serial: option: add Quectel EC200U modem
+    - USB: serial: option: add Quectel EM05CN (SG) modem
+    - USB: serial: option: add Quectel EM05CN modem
+    - USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
+    - misc: fastrpc: Don't remove map on creater_process and device_release
+    - misc: fastrpc: Fix use-after-free race condition for maps
+    - usb: core: hub: disable autosuspend for TI TUSB8041
+    - comedi: adv_pci1760: Fix PWM instruction handling
+    - mmc: sunxi-mmc: Fix clock refcount imbalance during unbind
+    - btrfs: fix race between quota rescan and disable leading to NULL pointer
+      deref
+    - cifs: do not include page data when checking signature
+    - USB: serial: cp210x: add SCALANCE LPE-9000 device id
+    - usb: host: ehci-fsl: Fix module alias
+    - usb: typec: altmodes/displayport: Add pin assignment helper
+    - usb: typec: altmodes/displayport: Fix pin assignment calculation
+    - usb: gadget: g_webcam: Send color matching descriptor per frame
+    - usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
+    - usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210
+    - dt-bindings: phy: g12a-usb3-pcie-phy: fix compatible string documentation
+    - serial: pch_uart: Pass correct sg to dma_unmap_sg()
+    - dmaengine: tegra210-adma: fix global intr clear
+    - serial: atmel: fix incorrect baudrate setup
+    - gsmi: fix null-deref in gsmi_get_variable
+    - drm/i915: re-disable RC6p on Sandy Bridge
+    - drm/amd/display: Fix set scaling doesn's work
+    - drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix
+    - x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
+    - mm/khugepaged: fix collapse_pte_mapped_thp() to allow anon_vma
+    - Linux 5.4.230
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sat, 22 Apr 2023 18:48:58 +0800
+
+linux-ein (5.4.0-1036.42) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1036.42 -proposed tracker (LP: #2015677)
+
+  * [Amgis-v*] Update device trees for UIO platform driver (LP#2012101)
+    - SAUCE: amgis: dts: Add UIO node
+
+  * [imx8-all][oem-support] CAAM Driver is not loaded (LP: #2009583)
+    - MLKU-129-3 arm64: dts: imx8mp: add secure memory
+    - MLKU-25-4 arm64: dts: imx8m: add secure memory
+
+  * Miscellaneous Ubuntu changes
+    - [Config] ein: Enforce module signature check
+    - SAUCE: Add imx8 modules to signature inclusion list
+
+  [ Ubuntu: 5.4.0-146.163 ]
+
+  * focal/linux: 5.4.0-146.163 -proposed tracker (LP: #2012094)
+  * NFS deathlock with last Kernel 5.4.0-144.161 and 5.15.0-67.74 (LP: #2009325)
+    - NFS: Correct timing for assigning access cache timestamp
+
+  [ Ubuntu: 5.4.0-145.162 ]
+
+  * focal/linux: 5.4.0-145.162 -proposed tracker (LP: #2008389)
+  * [SRU]Update ice driver to support E823 devices (LP: #1986717)
+    - ice: Add device ids for E822 devices
+    - ice: add support for E823 devices
+  * btrfs/154: rename fails with EOVERFLOW when calculating item size during
+    item key collision (LP: #2004132)
+    - btrfs: correctly calculate item size used when item key collision happens
+  * rtcpie in timers from ubuntu_kernel_selftests randomly failing
+    (LP: #1814234)
+    - SAUCE: selftest: rtcpie: Force passing unreliable subtest
+  * [UBUNTU 20.04] KVM: s390: pv: don't allow userspace to set the clock under
+    PV - kernel part (LP: #1999882)
+    - KVM: s390x: fix SCK locking
+    - KVM: s390: pv: don't allow userspace to set the clock under PV
+  * CVE-2021-3669
+    - ipc: replace costly bailout check in sysvipc_find_ipc()
+  * net:fcnal-test.sh 'nettest' command not found on F/K (LP: #2006391)
+    - selftests/net: Find nettest in current directory
+  * xfs: Preallocated ioend transactions cause deadlock due to log buffer
+    exhaustion (LP: #2007219)
+    - xfs: drop submit side trans alloc for append ioends
+  * CVE-2022-4382
+    - USB: gadgetfs: Fix race between mounting and unmounting
+  * CVE-2022-2196
+    - KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
+  * ubuntu_kernel_selftests: net:udpgso_bench.sh failed (LP: #1951447)
+    - selftests: net: udpgso_bench: Fix racing bug between the rx/tx programs
+  * net:fcnal-test.sh didn't return a non-zero value even with some sub-tests
+    failed (LP: #2006692)
+    - selftests: net/fcnal-test.sh: add exit code
+  * Fix selftests/ftracetests/Meta-selftests in Focal (LP: #2006453)
+    - SAUCE: Fix ftrace/Meta-selftests bashism check
+  * CVE-2023-23559
+    - wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 09 Apr 2023 19:07:31 +0800
+
+linux-ein (5.4.0-1035.41) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1035.41 -proposed tracker (LP: #2011767)
+
+  * [UC20][Amgis-V5] Enabling OPTEE based FDE (LP#1995129)
+    - SAUCE: amgis: dts: Remove busfreq node
+    - SAUCE: amgis: dts: Fix OPTEE crash
+    - SAUCE: amgis: dts: Additional OCRAM node for OPTEE
+    - SAUCE: amgis: dts: Add secure memory
+
+  * [Amgis-V5][UC20] System reboot via RPMSG/M4 failed (LP#2009916)
+    - SAUCE: rpmsg: Change virtio bus name
+
+  * [PE100A] Fixes for LAN1 (LP: #1994123)
+    - SAUCE: net: fec: modify ethernet LED behavior for RTL8211E/RTL8211F
+    - net: phy: realtek: fix rtl8211e rx/tx delay config
+
+  * [PE100A] Fix PMIC Settings (LP: #1994118)
+    - SAUCE: arm64/dts: pe100a: modify dvs voltage of buck1~buck4.
+
+  * [PE100A] Add LTE modem support (LP: #1994089)
+    - SAUCE: net: Add support for more quectel modems
+
+  * Cadence MHDP HDMI CEC driver doesn't work when building as a module (LP:
+    #2011779)
+    - SAUCE: drm/cdns: Fix #if checks for CONFIG_DRM_CDNS_HDMI_CEC
+
+  * [PE100A] Wifi patch for WMX6219 module (LP: #1994116)
+    - [Config] CONFIG_RTW88_8822CE=y
+    - Revert "PCI: dwc: Use interrupt disabling instead of masking"
+    - PCI: dwc: Restore MSI Receiver mask during resume
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 17 Mar 2023 00:26:07 +0800
+
+linux-ein (5.4.0-1034.40) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1034.40 -proposed tracker (LP: #2009905)
+
+  * Focal update: v5.4.226 upstream stable release (LP: #2003896)
+    - [Config] updateconfigs for INET_TABLE_PERTURB_ORDER
+
+  * [K4500-NXP][UC20] HMI screen does not turn on at end of first boot process
+    or simple power cycle (LP#2002765)
+    - Revert "UBUNTU: SAUCE: drm: AVD101WX-CN: Assigned bus format to fix
+      warning:"
+
+  * [UC20] failed to bring up PLS63-W, fail rate ~10% (LP: #2008468)
+    - nvmem: core: fix registration vs use race
+
+  * Patch file for cascade-kernel (SF: #00347119)
+    - Revert "UBUNTU: SAUCE: dts: vesta-500: change pad setting to save power"
+
+  [ Ubuntu: 5.4.0-144.161 ]
+
+  * focal/linux: 5.4.0-144.161 -proposed tracker (LP: #2004653)
+  * CVE-2023-0461
+    - SAUCE: Fix inet_csk_listen_start after CVE-2023-0461
+
+  [ Ubuntu: 5.4.0-143.160 ]
+
+  * focal/linux: 5.4.0-143.160 -proposed tracker (LP: #2004385)
+  * NFS: client permission error after adding user to permissible group
+    (LP: #2003053)
+    - NFS: Clear the file access cache upon login
+    - NFS: Judge the file access cache's timestamp in rcu path
+    - NFS: Fix up a sparse warning
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914)
+    - tracing/ring-buffer: Only do full wait when cpu != RING_BUFFER_ALL_CPUS
+    - udf: Discard preallocation before extending file with a hole
+    - udf: Fix preallocation discarding at indirect extent boundary
+    - udf: Do not bother looking for prealloc extents if i_lenExtents matches
+      i_size
+    - udf: Fix extending file within last block
+    - usb: gadget: uvc: Prevent buffer overflow in setup handler
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: cp210x: add Kamstrup RF sniffer PIDs
+    - USB: serial: f81232: fix division by zero on line-speed change
+    - USB: serial: f81534: fix division by zero on line-speed change
+    - igb: Initialize mailbox message for VF reset
+    - xen-netback: move removal of "hotplug-status" to the right place
+    - HID: ite: Add support for Acer S1002 keyboard-dock
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch 10E
+    - HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch V 10
+    - HID: uclogic: Add HID_QUIRK_HIDINPUT_FORCE quirk
+    - net: loopback: use NET_NAME_PREDICTABLE for name_assign_type
+    - usb: musb: remove extra check in musb_gadget_vbus_draw
+    - ARM: dts: qcom: apq8064: fix coresight compatible
+    - arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
+    - drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
+    - arm: dts: spear600: Fix clcd interrupt
+    - soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of
+      pm_runtime_get_sync
+    - soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
+    - soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
+    - perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
+    - perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
+    - arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
+    - arm64: dts: mt2712e: Fix unit address for pinctrl node
+    - arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
+    - arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
+    - arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
+    - ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
+    - ARM: dts: turris-omnia: Add ethernet aliases
+    - ARM: dts: turris-omnia: Add switch port 6 node
+    - arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
+    - pstore/ram: Fix error return code in ramoops_probe()
+    - ARM: mmp: fix timer_read delay
+    - pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
+    - tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
+    - cpuidle: dt: Return the correct numbers of parsed idle states
+    - alpha: fix syscall entry in !AUDUT_SYSCALL case
+    - PM: hibernate: Fix mistake in kerneldoc comment
+    - fs: don't audit the capability check in simple_xattr_list()
+    - selftests/ftrace: event_triggers: wait longer for test_event_enable
+    - perf: Fix possible memleak in pmu_dev_alloc()
+    - timerqueue: Use rb_entry_safe() in timerqueue_getnext()
+    - proc: fixup uptime selftest
+    - lib/fonts: fix undefined behavior in bit shift for get_default_font
+    - ocfs2: fix memory leak in ocfs2_stack_glue_init()
+    - MIPS: vpe-mt: fix possible memory leak while module exiting
+    - MIPS: vpe-cmp: fix possible memory leak while module exiting
+    - selftests/efivarfs: Add checking of the test return value
+    - PNP: fix name memory leak in pnp_alloc_dev()
+    - perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
+    - irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
+    - EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
+    - nfsd: don't call nfsd_file_put from client states seqfile display
+    - genirq/irqdesc: Don't try to remove non-existing sysfs files
+    - cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
+    - libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
+    - lib/notifier-error-inject: fix error when writing -errno to debugfs file
+    - docs: fault-injection: fix non-working usage of negative values
+    - debugfs: fix error when writing negative value to atomic_t debugfs file
+    - ocfs2: ocfs2_mount_volume does cleanup job before return error
+    - ocfs2: rewrite error handling of ocfs2_fill_super
+    - ocfs2: fix memory leak in ocfs2_mount_volume()
+    - rapidio: fix possible name leaks when rio_add_device() fails
+    - rapidio: rio: fix possible name leak in rio_register_mport()
+    - clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
+    - ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
+    - uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
+    - xen/events: only register debug interrupt for 2-level events
+    - x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
+    - x86/xen: Fix memory leak in xen_init_lock_cpu()
+    - xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
+    - PM: runtime: Improve path in rpm_idle() when no callback
+    - PM: runtime: Do not call __rpm_callback() from rpm_idle()
+    - platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
+    - MIPS: BCM63xx: Add check for NULL for clk in clk_enable
+    - MIPS: OCTEON: warn only once if deprecated link status is being used
+    - fs: sysv: Fix sysv_nblocks() returns wrong value
+    - rapidio: fix possible UAF when kfifo_alloc() fails
+    - eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
+    - relay: fix type mismatch when allocating memory in relay_create_buf()
+    - hfs: Fix OOB Write in hfs_asc2mac
+    - rapidio: devices: fix missing put_device in mport_cdev_open
+    - wifi: ath9k: hif_usb: fix memory leak of urbs in
+      ath9k_hif_usb_dealloc_tx_urbs()
+    - wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
+    - wifi: rtl8xxxu: Fix reading the vendor of combo chips
+    - pata_ipx4xx_cf: Fix unsigned comparison with less than zero
+    - media: i2c: ad5820: Fix error path
+    - can: kvaser_usb: do not increase tx statistics when sending error message
+      frames
+    - can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
+    - can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to
+      {leaf,usbcan}_cmd_can_error_event
+    - can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
+    - can: kvaser_usb_leaf: Set Warning state even without bus errors
+    - can: kvaser_usb_leaf: Fix improved state not being reported
+    - can: kvaser_usb_leaf: Fix wrong CAN state after stopping
+    - can: kvaser_usb_leaf: Fix bogus restart events
+    - can: kvaser_usb: Add struct kvaser_usb_busparams
+    - can: kvaser_usb: Compare requested bittiming parameters with actual
+      parameters in do_set_{,data}_bittiming
+    - clk: renesas: r9a06g032: Repair grave increment error
+    - spi: Update reference to struct spi_controller
+    - drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
+    - ima: Rename internal filter rule functions
+    - ima: Fix fall-through warnings for Clang
+    - ima: Handle -ESTALE returned by ima_filter_rule_match()
+    - media: vivid: fix compose size exceed boundary
+    - bpf: propagate precision in ALU/ALU64 operations
+    - mtd: Fix device name leak when register device failed in add_mtd_device()
+    - wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
+    - media: camss: Clean up received buffers on failed start of streaming
+    - net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
+    - rxrpc: Fix ack.bufferSize to be 0 when generating an ack
+    - drm/radeon: Add the missed acpi_put_table() to fix memory leak
+    - drm/mediatek: Modify dpi power on/off sequence.
+    - ASoC: pxa: fix null-pointer dereference in filter()
+    - regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
+    - amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
+    - integrity: Fix memory leakage in keyring allocation error path
+    - ima: Fix misuse of dereference of pointer in template_desc_init_fields()
+    - wifi: ath10k: Fix return value in ath10k_pci_init()
+    - mtd: lpddr2_nvm: Fix possible null-ptr-deref
+    - Input: elants_i2c - properly handle the reset GPIO when power is off
+    - media: solo6x10: fix possible memory leak in solo_sysfs_init()
+    - media: platform: exynos4-is: Fix error handling in fimc_md_init()
+    - media: videobuf-dma-contig: use dma_mmap_coherent
+    - bpf: Move skb->len == 0 checks into __bpf_redirect
+    - HID: hid-sensor-custom: set fixed size for custom attributes
+    - ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
+    - ALSA: seq: fix undefined behavior in bit shift for
+      SNDRV_SEQ_FILTER_USE_EVENT
+    - regulator: core: use kfree_const() to free space conditionally
+    - clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
+    - bonding: Export skip slave logic to function
+    - bonding: Rename slave_arr to usable_slaves
+    - bonding: fix link recovery in mode 2 when updelay is nonzero
+    - mtd: maps: pxa2xx-flash: fix memory leak in probe
+    - media: imon: fix a race condition in send_packet()
+    - clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
+    - clk: imx: replace osc_hdmi with dummy
+    - pinctrl: pinconf-generic: add missing of_node_put()
+    - media: dvb-core: Fix ignored return value in dvb_register_frontend()
+    - media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
+    - media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
+    - drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
+    - ASoC: dt-bindings: wcd9335: fix reset line polarity in example
+    - ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
+    - NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
+    - NFSv4.2: Fix a memory stomp in decode_attr_security_label
+    - NFSv4.2: Fix initialisation of struct nfs4_label
+    - NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
+    - ALSA: asihpi: fix missing pci_disable_device()
+    - wifi: iwlwifi: mvm: fix double free on tx path.
+    - ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
+    - drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
+    - drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
+    - ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
+    - netfilter: conntrack: set icmpv6 redirects as RELATED
+    - bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
+    - bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
+    - bonding: uninitialized variable in bond_miimon_inspect()
+    - spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
+    - wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys()
+      fails
+    - regulator: core: fix module refcount leak in set_supply()
+    - clk: qcom: clk-krait: fix wrong div2 functions
+    - hsr: Avoid double remove of a node.
+    - configfs: fix possible memory leak in configfs_create_dir()
+    - regulator: core: fix resource leak in regulator_register()
+    - bpf, sockmap: fix race in sock_map_free()
+    - media: saa7164: fix missing pci_disable_device()
+    - ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
+    - xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
+    - SUNRPC: Fix missing release socket in rpc_sockname()
+    - NFSv4.x: Fail client initialisation if state manager thread can't run
+    - mmc: alcor: fix return value check of mmc_add_host()
+    - mmc: moxart: fix return value check of mmc_add_host()
+    - mmc: mxcmmc: fix return value check of mmc_add_host()
+    - mmc: pxamci: fix return value check of mmc_add_host()
+    - mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
+    - mmc: toshsd: fix return value check of mmc_add_host()
+    - mmc: vub300: fix return value check of mmc_add_host()
+    - mmc: wmt-sdmmc: fix return value check of mmc_add_host()
+    - mmc: atmel-mci: fix return value check of mmc_add_host()
+    - mmc: omap_hsmmc: fix return value check of mmc_add_host()
+    - mmc: meson-gx: fix return value check of mmc_add_host()
+    - mmc: via-sdmmc: fix return value check of mmc_add_host()
+    - mmc: wbsd: fix return value check of mmc_add_host()
+    - mmc: mmci: fix return value check of mmc_add_host()
+    - media: c8sectpfe: Add of_node_put() when breaking out of loop
+    - media: coda: Add check for dcoda_iram_alloc
+    - media: coda: Add check for kmalloc
+    - clk: samsung: Fix memory leak in _samsung_clk_register_pll()
+    - spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
+    - wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
+    - wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
+    - blktrace: Fix output non-blktrace event when blk_classic option enabled
+    - clk: socfpga: clk-pll: Remove unused variable 'rc'
+    - clk: socfpga: use clk_hw_register for a5/c5
+    - clk: socfpga: Fix memory leak in socfpga_gate_init()
+    - net: vmw_vsock: vmci: Check memcpy_from_msg()
+    - net: defxx: Fix missing err handling in dfx_init()
+    - net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
+    - drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
+    - of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry()
+      and find_dup_cset_prop()
+    - ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: farsync: Fix kmemleak when rmmods farsync
+    - net/tunnel: wait until all sk_user_data reader finish before releasing the
+      sock
+    - net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
+    - net: amd-xgbe: Fix logic around active and passive cables
+    - net: amd-xgbe: Check only the minimum speed for active/passive cables
+    - can: tcan4x5x: Remove invalid write in clear_interrupts
+    - net: lan9303: Fix read error execution path
+    - ntb_netdev: Use dev_kfree_skb_any() in interrupt context
+    - Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
+    - Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
+    - stmmac: fix potential division by 0
+    - apparmor: fix a memleak in multi_transaction_new()
+    - apparmor: fix lockdep warning when removing a namespace
+    - apparmor: Fix abi check to include v8 abi
+    - apparmor: Use pointer to struct aa_label for lbs_cred
+    - RDMA/core: Fix order of nldev_exit call
+    - f2fs: fix normal discard process
+    - RDMA/siw: Fix immediate work request flush to completion queue
+    - RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
+    - RDMA/siw: Set defined status for work completion with undefined status
+    - scsi: scsi_debug: Fix a warning in resp_write_scat()
+    - crypto: ccree - swap SHA384 and SHA512 larval hashes at build time
+    - crypto: ccree - Remove debugfs when platform_driver_register failed
+    - PCI: Check for alloc failure in pci_request_irq()
+    - RDMA/hfi: Decrease PCI device reference count in error path
+    - crypto: ccree - Make cc_debugfs_global_fini() available for module init
+      function
+    - RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create
+      failed
+    - scsi: hpsa: Fix possible memory leak in hpsa_init_one()
+    - crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
+    - scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
+    - scsi: hpsa: Fix error handling in hpsa_add_sas_host()
+    - scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
+    - scsi: fcoe: Fix possible name leak when device_register() fails
+    - scsi: ipr: Fix WARNING in ipr_init()
+    - scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
+    - scsi: snic: Fix possible UAF in snic_tgt_create()
+    - RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
+    - f2fs: avoid victim selection from previous victim section
+    - crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
+    - RDMA/hfi1: Fix error return code in parse_platform_config()
+    - orangefs: Fix sysfs not cleanup when dev init failed
+    - crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
+    - hwrng: amd - Fix PCI device refcount leak
+    - hwrng: geode - Fix PCI device refcount leak
+    - IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
+    - drivers: dio: fix possible memory leak in dio_init()
+    - tty: serial: tegra: Activate RX DMA transfer by request
+    - serial: tegra: Read DMA status before terminating
+    - class: fix possible memory leak in __class_register()
+    - vfio: platform: Do not pass return buffer to ACPI _RST method
+    - uio: uio_dmem_genirq: Fix missing unlock in irq configuration
+    - uio: uio_dmem_genirq: Fix deadlock between irq config and handling
+    - usb: fotg210-udc: Fix ages old endianness issues
+    - staging: vme_user: Fix possible UAF in tsi148_dma_list_add
+    - usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
+    - usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
+    - serial: amba-pl011: avoid SBSA UART accessing DMACR register
+    - serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
+    - serial: pch: Fix PCI device refcount leak in pch_request_dma()
+    - tty: serial: clean up stop-tx part in altera_uart_tx_chars()
+    - tty: serial: altera_uart_{r,t}x_chars() need only uart_port
+    - serial: altera_uart: fix locking in polling mode
+    - serial: sunsab: Fix error handling in sunsab_init()
+    - test_firmware: fix memory leak in test_firmware_init()
+    - misc: ocxl: fix possible name leak in ocxl_file_register_afu()
+    - misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
+    - misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault
+      and gru_handle_user_call_os
+    - cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
+    - cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
+    - counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
+    - usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
+    - usb: gadget: f_hid: optional SETUP/SET_REPORT mode
+    - usb: gadget: f_hid: fix f_hidg lifetime vs cdev
+    - usb: gadget: f_hid: fix refcount leak on error path
+    - drivers: mcb: fix resource leak in mcb_probe()
+    - mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
+    - chardev: fix error handling in cdev_device_add()
+    - i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
+    - staging: rtl8192u: Fix use after free in ieee80211_rx()
+    - staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
+    - vme: Fix error not catched in fake_init()
+    - i2c: ismt: Fix an out-of-bounds bug in ismt_access()
+    - usb: storage: Add check for kcalloc
+    - tracing/hist: Fix issue of losting command info in error_log
+    - samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
+    - fbdev: ssd1307fb: Drop optional dependency
+    - fbdev: pm2fb: fix missing pci_disable_device()
+    - fbdev: via: Fix error in via_core_init()
+    - fbdev: vermilion: decrease reference count in error path
+    - fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
+    - HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
+    - HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
+    - power: supply: fix residue sysfs file in error handle route of
+      __power_supply_register()
+    - perf trace: Return error if a system call doesn't exist
+    - perf trace: Separate 'struct syscall_fmt' definition from syscall_fmts
+      variable
+    - perf trace: Factor out the initialization of syscal_arg_fmt->scnprintf
+    - perf trace: Add the syscall_arg_fmt pointer to syscall_arg
+    - perf trace: Allow associating scnprintf routines with well known arg names
+    - perf trace: Add a strtoul() method to 'struct syscall_arg_fmt'
+    - perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
+    - perf trace: Handle failure when trace point folder is missed
+    - perf symbol: correction while adjusting symbol
+    - HSI: omap_ssi_core: Fix error handling in ssi_init()
+    - power: supply: fix null pointer dereferencing in
+      power_supply_get_battery_info
+    - RDMA/siw: Fix pointer cast warning
+    - include/uapi/linux/swab: Fix potentially missing __always_inline
+    - rtc: snvs: Allow a time difference on clock register read
+    - rtc: pcf85063: Fix reading alarm
+    - iommu/amd: Fix pci device refcount leak in ppr_notifier()
+    - iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
+    - macintosh: fix possible memory leak in macio_add_one_device()
+    - macintosh/macio-adb: check the return value of ioremap()
+    - powerpc/52xx: Fix a resource leak in an error handling path
+    - cxl: Fix refcount leak in cxl_calc_capp_routing
+    - powerpc/xive: add missing iounmap() in error path in
+      xive_spapr_populate_irq_data()
+    - powerpc/perf: callchain validate kernel stack pointer bounds
+    - powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in
+      of_fsl_spi_probe()
+    - powerpc/hv-gpci: Fix hv_gpci event list
+    - selftests/powerpc: Fix resource leaks
+    - pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
+    - remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
+    - remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in
+      adsp_alloc_memory_region()
+    - rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
+    - rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
+    - nfsd: Define the file access mode enum for tracing
+    - NFSD: Add tracepoints to NFSD's duplicate reply cache
+    - nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
+    - mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under
+      spin_lock_irqsave()
+    - nfc: pn533: Clear nfc_target before being used
+    - r6040: Fix kmemleak in probe and remove
+    - rtc: mxc_v2: Add missing clk_disable_unprepare()
+    - openvswitch: Fix flow lookup to use unmasked key
+    - skbuff: Account for tail adjustment during pull operations
+    - mailbox: zynq-ipi: fix error handling while device_register() fails
+    - net_sched: reject TCF_EM_SIMPLE case for complex ematch module
+    - rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
+    - myri10ge: Fix an error handling path in myri10ge_probe()
+    - net: stream: purge sk_error_queue in sk_stream_kill_queues()
+    - rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
+    - binfmt_misc: fix shift-out-of-bounds in check_special_flags
+    - fs: jfs: fix shift-out-of-bounds in dbAllocAG
+    - udf: Avoid double brelse() in udf_rename()
+    - fs: jfs: fix shift-out-of-bounds in dbDiscardAG
+    - ACPICA: Fix error code path in acpi_ds_call_control_method()
+    - nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
+    - acct: fix potential integer overflow in encode_comp_t()
+    - hfs: fix OOB Read in __hfs_brec_find
+    - drm/etnaviv: add missing quirks for GC300
+    - brcmfmac: return error when getting invalid max_flowrings from dongle
+    - wifi: ath9k: verify the expected usb_endpoints are present
+    - wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
+    - ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
+    - ipmi: fix memleak when unload ipmi driver
+    - bpf: make sure skb->len != 0 when redirecting to a tunneling device
+    - net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
+    - hamradio: baycom_epp: Fix return type of baycom_send_packet()
+    - wifi: brcmfmac: Fix potential shift-out-of-bounds in
+      brcmf_fw_alloc_request()
+    - igb: Do not free q_vector unless new one was allocated
+    - s390/ctcm: Fix return type of ctc{mp,}m_tx()
+    - s390/netiucv: Fix return type of netiucv_tx()
+    - s390/lcs: Fix return type of lcs_start_xmit()
+    - drm/rockchip: Use drm_mode_copy()
+    - drm/sti: Use drm_mode_copy()
+    - drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
+    - md/raid1: stop mdx_raid1 thread when raid1 array run failed
+    - net: add atomic_long_t to net_device_stats fields
+    - mrp: introduce active flags to prevent UAF when applicant uninit
+    - ppp: associate skb with a device at tx
+    - bpf: Prevent decl_tag from being referenced in func_proto arg
+    - media: dvb-frontends: fix leak of memory fw
+    - media: dvbdev: adopts refcnt to avoid UAF
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
+    - blk-mq: fix possible memleak when register 'hctx' failed
+    - regulator: core: fix use_count leakage when handling boot-on
+    - mmc: f-sdh30: Add quirks for broken timeout clock capability
+    - media: si470x: Fix use-after-free in si470x_int_in_callback()
+    - clk: st: Fix memory leak in st_of_quadfs_setup()
+    - hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
+    - drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
+    - drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
+    - orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
+    - orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
+    - ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
+    - ALSA: hda: add snd_hdac_stop_streams() helper
+    - ASoC: Intel: Skylake: Fix driver hang during shutdown
+    - ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in
+      mt8173_rt5650_rt5514_dev_probe()
+    - ASoC: audio-graph-card: fix refcount leak of cpu_ep in
+      __graph_for_each_link()
+    - ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in
+      rockchip_pdm_runtime_resume()
+    - ASoC: wm8994: Fix potential deadlock
+    - ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in
+      rk_spdif_runtime_resume()
+    - ASoC: rt5670: Remove unbalanced pm_runtime_put()
+    - pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
+    - pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
+    - ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
+    - ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
+    - usb: dwc3: core: defer probe on ulpi_read_id timeout
+    - HID: wacom: Ensure bootloader PID is usable in hidraw mode
+    - reiserfs: Add missing calls to reiserfs_security_free()
+    - iio: adc: ad_sigma_delta: do not use internal iio_dev lock
+    - iio: adc128s052: add proper .data members in adc128_of_match table
+    - regulator: core: fix deadlock on regulator enable
+    - gcov: add support for checksum field
+    - media: dvbdev: fix build warning due to comments
+    - media: dvbdev: fix refcnt bug
+    - cifs: fix oops during encryption
+    - nvme-pci: fix doorbell buffer value endianness
+    - ata: ahci: Fix PCS quirk application for suspend
+    - nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
+    - objtool: Fix SEGFAULT
+    - powerpc/rtas: avoid device tree lookups in rtas_os_term()
+    - powerpc/rtas: avoid scheduling in rtas_os_term()
+    - HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
+    - HID: plantronics: Additional PIDs for double volume key presses quirk
+    - hfsplus: fix bug causing custom uid and gid being unable to be assigned with
+      mount
+    - ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
+    - ALSA: line6: correct midi status byte when receiving data from podxt
+    - ALSA: line6: fix stack overflow in line6_midi_transmit
+    - pnode: terminate at peers of source
+    - md: fix a crash in mempool_free
+    - mm, compaction: fix fast_isolate_around() to stay within boundaries
+    - f2fs: should put a page when checking the summary info
+    - mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
+    - tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
+    - tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
+    - SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
+    - net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
+    - net/af_packet: make sure to pull mac header
+    - media: stv0288: use explicitly signed char
+    - soc: qcom: Select REMAP_MMIO for LLCC driver
+    - kest.pl: Fix grub2 menu handling for rebooting
+    - ktest.pl minconfig: Unset configs instead of just removing them
+    - mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
+    - btrfs: fix resolving backrefs for inline extent followed by prealloc
+    - ARM: ux500: do not directly dereference __iomem
+    - arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
+    - selftests: Use optional USERCFLAGS and USERLDFLAGS
+    - cpufreq: Init completion before kobject_init_and_add()
+    - binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf
+    - binfmt: Fix error return code in load_elf_fdpic_binary()
+    - dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
+    - dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
+    - dm thin: Use last transaction's pmd->root when commit failed
+    - dm thin: Fix UAF in run_timer_softirq()
+    - dm integrity: Fix UAF in dm_integrity_dtr()
+    - dm clone: Fix UAF in clone_dtr()
+    - dm cache: Fix UAF in destroy()
+    - dm cache: set needs_check flag after aborting metadata
+    - tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
+    - x86/microcode/intel: Do not retry microcode reloading on the APs
+    - tracing/hist: Fix wrong return value in parse_action_params()
+    - tracing: Fix infinite loop in tracing_read_pipe on overflowed
+      print_trace_line
+    - ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
+    - media: dvb-core: Fix double free in dvb_register_device()
+    - cifs: fix confusing debug message
+    - cifs: fix missing display of three mount options
+    - md/bitmap: Fix bitmap chunk size overflow issues
+    - efi: Add iMac Pro 2017 to uefi skip cert quirk
+    - ipmi: fix long wait in unload when IPMI disconnect
+    - mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
+    - ima: Fix a potential NULL pointer access in ima_restore_measurement_list
+    - ipmi: fix use after free in _ipmi_destroy_user()
+    - PCI: Fix pci_device_is_present() for VFs by checking PF
+    - PCI/sysfs: Fix double free in error path
+    - crypto: n2 - add missing hash statesize
+    - iommu/amd: Fix ivrs_acpihid cmdline parsing code
+    - parisc: led: Fix potential null-ptr-deref in start_task()
+    - device_cgroup: Roll back to original exceptions after copy failure
+    - drm/connector: send hotplug uevent on connector cleanup
+    - drm/vmwgfx: Validate the box size for the snooped cursor
+    - ext4: add inode table check in __ext4_get_inode_loc to aovid possible
+      infinite loop
+    - ext4: fix undefined behavior in bit shift for ext4_check_flag_values
+    - ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
+    - ext4: add helper to check quota inums
+    - ext4: fix reserved cluster accounting in __es_remove_extent()
+    - ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
+    - ext4: init quota for 'old.inode' in 'ext4_rename'
+    - ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
+    - ext4: fix corruption when online resizing a 1K bigalloc fs
+    - ext4: fix error code return to user-space in ext4_get_branch()
+    - ext4: avoid BUG_ON when creating xattrs
+    - ext4: fix inode leak in ext4_xattr_inode_create() on an error path
+    - ext4: initialize quota before expanding inode in setproject ioctl
+    - ext4: avoid unaccounted block allocation when expanding inode
+    - ext4: allocate extended attribute value in vmalloc area
+    - btrfs: replace strncpy() with strscpy()
+    - PM/devfreq: governor: Add a private governor_data for governor
+    - media: s5p-mfc: Fix to handle reference queue during finishing
+    - media: s5p-mfc: Clear workbit to handle error condition
+    - media: s5p-mfc: Fix in register read and write for H264
+    - dm thin: resume even if in FAIL mode
+    - perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
+    - perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged
+      data
+    - KVM: x86: optimize more exit handlers in vmx.c
+    - KVM: retpolines: x86: eliminate retpoline from vmx.c exit handlers
+    - KVM: VMX: Rename INTERRUPT_PENDING to INTERRUPT_WINDOW
+    - KVM: VMX: Rename NMI_PENDING to NMI_WINDOW
+    - KVM: VMX: Fix the spelling of CPU_BASED_USE_TSC_OFFSETTING
+    - KVM: nVMX: Properly expose ENABLE_USR_WAIT_PAUSE control to L1
+    - ravb: Fix "failed to switch device to config mode" message during unbind
+    - ext4: goto right label 'failed_mount3a'
+    - ext4: correct inconsistent error msg in nojournal mode
+    - mm/highmem: Lift memcpy_[to|from]_page to core
+    - ext4: use memcpy_to_page() in pagecache_write()
+    - fs: ext4: initialize fsdata in pagecache_write()
+    - ext4: use kmemdup() to replace kmalloc + memcpy
+    - mbcache: don't reclaim used entries
+    - mbcache: add functions to delete entry if unused
+    - ext4: remove EA inode entry from mbcache on inode eviction
+    - ext4: unindent codeblock in ext4_xattr_block_set()
+    - ext4: fix race when reusing xattr blocks
+    - mbcache: automatically delete entries from cache on freeing
+    - ext4: fix deadlock due to mbcache entry corruption
+    - SUNRPC: ensure the matching upcall is in-flight upon downcall
+    - bpf: pull before calling skb_postpull_rcsum()
+    - nfsd: shut down the NFSv4 state objects before the filecache
+    - net: hns3: add interrupts re-initialization while doing VF FLR
+    - net: sched: fix memory leak in tcindex_set_parms
+    - qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
+    - nfc: Fix potential resource leaks
+    - vhost: fix range used in translate_desc()
+    - net: amd-xgbe: add missed tasklet_kill
+    - net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
+    - RDMA/uverbs: Silence shiftTooManyBitsSigned warning
+    - RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
+    - net: sched: atm: dont intepret cls results when asked to drop
+    - net: sched: cbq: dont intepret cls results when asked to drop
+    - perf tools: Fix resources leak in perf_data__open_dir()
+    - drivers/net/bonding/bond_3ad: return when there's no aggregator
+    - usb: rndis_host: Secure rndis_query check against int overflow
+    - drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
+    - caif: fix memory leak in cfctrl_linkup_request()
+    - udf: Fix extension of the last extent in the file
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
+    - x86/bugs: Flush IBP in ib_prctl_set()
+    - nfsd: fix handling of readdir in v4root vs. mount upcall timeout
+    - riscv: uaccess: fix type of 0 variable on error in get_user()
+    - ext4: don't allow journal inode to have encrypt flag
+    - hfs/hfsplus: use WARN_ON for sanity check
+    - hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
+    - mbcache: Avoid nesting of cache->c_list_lock under bit locks
+    - parisc: Align parisc MADV_XXX constants with all other architectures
+    - selftests: Fix kselftest O=objdir build from cluttering top level objdir
+    - selftests: set the BUILD variable to absolute path
+    - driver core: Fix bus_type.match() error handling in __driver_attach()
+    - net: sched: disallow noqueue for qdisc classes
+    - KVM: arm64: Fix S1PTW handling on RO memslots
+    - efi: tpm: Avoid READ_ONCE() for accessing the event log
+    - docs: Fix the docs build with Sphinx 6.0
+    - perf auxtrace: Fix address filter duplicate symbol selection
+    - s390/kexec: fix ipl report address for kdump
+    - s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple()
+    - net/ulp: prevent ULP without clone op from entering the LISTEN status
+    - ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
+    - cifs: Fix uninitialized memory read for smb311 posix symlink create
+    - drm/msm/adreno: Make adreno quirks not overwrite each other
+    - platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during
+      probe
+    - ixgbe: fix pci device refcount leak
+    - ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
+    - wifi: wilc1000: sdio: fix module autoloading
+    - usb: ulpi: defer ulpi_register on ulpi_read_id timeout
+    - jbd2: use the correct print format
+    - quota: Factor out setup of quota inode
+    - ext4: fix bug_on in __es_tree_search caused by bad quota inode
+    - ext4: lost matching-pair of trace in ext4_truncate
+    - ext4: fix use-after-free in ext4_orphan_cleanup
+    - ext4: fix uninititialized value in 'ext4_evict_inode'
+    - netfilter: ipset: Fix overflow before widen in the bitmap_ip_create()
+      function.
+    - powerpc/imc-pmu: Fix use of mutex in IRQs disabled section
+    - x86/boot: Avoid using Intel mnemonics in AT&T syntax asm
+    - EDAC/device: Fix period calculation in edac_device_reset_delay_period()
+    - regulator: da9211: Use irq handler when ready
+    - tipc: improve throughput between nodes in netns
+    - tipc: eliminate checking netns if node established
+    - tipc: fix unexpected link reset due to discovery messages
+    - hvc/xen: lock console list traversal
+    - nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
+    - net/sched: act_mpls: Fix warning during failed attribute validation
+    - net/mlx5: Rename ptp clock info
+    - net/mlx5: Fix ptp max frequency adjustment range
+    - iommu/mediatek-v1: Add error handle for mtk_iommu_probe
+    - iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
+    - x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent
+      unnecessary IPI
+    - x86/resctrl: Fix task CLOSID/RMID update race
+    - drm/virtio: Fix GEM handle creation UAF
+    - arm64: atomics: format whitespace consistently
+    - arm64: atomics: remove LL/SC trampolines
+    - arm64: cmpxchg_double*: hazard against entire exchange variable
+    - efi: fix NULL-deref in init error path
+    - mm: Always release pages to the buddy allocator in memblock_free_late().
+    - Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout"
+    - tipc: fix use-after-free in tipc_disc_rcv()
+    - tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
+    - tipc: Add a missing case of TIPC_DIRECT_MSG type
+    - ocfs2: fix freeing uninitialized resource on ocfs2_dlm_shutdown
+    - tipc: call tipc_lxc_xmit without holding node_read_lock
+    - Linux 5.4.229
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2023-0266 was assigned for this issue.
+    - ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
+  * Focal update: v5.4.229 upstream stable release (LP: #2003914) //
+    CVE-2022-41218 is assigned to those bugs above.
+    - media: dvb-core: Fix UAF due to refcount races at releasing
+  * Focal update: v5.4.228 upstream stable release (LP: #2003904)
+    - x86/smpboot: Move rcu_cpu_starting() earlier
+    - mm/hugetlb: fix races when looking up a CONT-PTE/PMD size hugetlb page
+    - block: unhash blkdev part inode when the part is deleted
+    - ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx()
+    - pinctrl: meditatek: Startup with the IRQs disabled
+    - can: sja1000: fix size of OCR_MODE_MASK define
+    - can: mcba_usb: Fix termination command argument
+    - ASoC: ops: Correct bounds check for second channel on SX controls
+    - Linux 5.4.228
+  * Focal update: v5.4.227 upstream stable release (LP: #2003901)
+    - arm64: dts: rockchip: keep I2S1 disabled for GPIO function on ROCK Pi 4
+      series
+    - arm: dts: rockchip: fix node name for hym8563 rtc
+    - ARM: dts: rockchip: fix ir-receiver node names
+    - ARM: dts: rockchip: rk3188: fix lcdc1-rgb24 node name
+    - ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels
+    - ARM: 9266/1: mm: fix no-MMU ZERO_PAGE() implementation
+    - ARM: dts: rockchip: disable arm_global_timer on rk3066 and rk3188
+    - 9p/fd: Use P9_HDRSZ for header size
+    - regulator: slg51000: Wait after asserting CS pin
+    - ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
+    - btrfs: send: avoid unaligned encoded writes when attempting to clone range
+    - ASoC: soc-pcm: Add NULL check in BE reparenting
+    - regulator: twl6030: fix get status of twl6032 regulators
+    - fbcon: Use kzalloc() in fbcon_prepare_logo()
+    - 9p/xen: check logical size for buffer size
+    - net: usb: qmi_wwan: add u-blox 0x1342 composition
+    - mm/khugepaged: take the right locks for page table retraction
+    - mm/khugepaged: fix GUP-fast interaction by sending IPI
+    - mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths
+    - xen/netback: do some code cleanup
+    - xen/netback: don't call kfree_skb() with interrupts disabled
+    - Revert "net: dsa: b53: Fix valid setting for MDB entries"
+    - media: v4l2-dv-timings.c: fix too strict blanking sanity checks
+    - memcg: fix possible use-after-free in memcg_write_event_control()
+    - mm/gup: fix gup_pud_range() for dax
+    - KVM: s390: vsie: Fix the initialization of the epoch extension (epdx) field
+    - drm/shmem-helper: Remove errant put in error path
+    - HID: usbhid: Add ALWAYS_POLL quirk for some mice
+    - HID: hid-lg4ff: Add check for empty lbuf
+    - HID: core: fix shift-out-of-bounds in hid_report_raw_event
+    - can: af_can: fix NULL pointer dereference in can_rcv_filter
+    - ieee802154: cc2520: Fix error return code in cc2520_hw_init()
+    - ca8210: Fix crash by zero initializing data
+    - drm/bridge: ti-sn65dsi86: Fix output polarity setting bug
+    - gpio: amd8111: Fix PCI device reference count leak
+    - e1000e: Fix TX dispatch condition
+    - igb: Allocate MSI-X vector when testing
+    - af_unix: Get user_ns from in_skb in unix_diag_get_exact().
+    - Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn()
+    - Bluetooth: Fix not cleanup led when bt_init fails
+    - net: dsa: ksz: Check return value
+    - selftests: rtnetlink: correct xfrm policy rule in kci_test_ipsec_offload
+    - mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add()
+    - net: encx24j600: Add parentheses to fix precedence
+    - net: encx24j600: Fix invalid logic in reading of MISTAT register
+    - xen-netfront: Fix NULL sring after live migration
+    - net: mvneta: Prevent out of bounds read in mvneta_config_rss()
+    - i40e: Fix not setting default xps_cpus after reset
+    - i40e: Fix for VF MAC address 0
+    - i40e: Disallow ip4 and ip6 l4_4_bytes
+    - NFC: nci: Bounds check struct nfc_target arrays
+    - nvme initialize core quirks before calling nvme_init_subsystem
+    - net: stmmac: fix "snps,axi-config" node property parsing
+    - net: thunderx: Fix missing destroy_workqueue of nicvf_rx_mode_wq
+    - net: hisilicon: Fix potential use-after-free in hisi_femac_rx()
+    - net: hisilicon: Fix potential use-after-free in hix5hd2_rx()
+    - tipc: Fix potential OOB in tipc_link_proto_rcv()
+    - ipv4: Fix incorrect route flushing when source address is deleted
+    - ipv4: Fix incorrect route flushing when table ID 0 is used
+    - ethernet: aeroflex: fix potential skb leak in greth_init_rings()
+    - net: plip: don't call kfree_skb/dev_kfree_skb() under spin_lock_irq()
+    - ipv6: avoid use-after-free in ip6_fragment()
+    - net: mvneta: Fix an out of bounds check
+    - can: esd_usb: Allow REC and TEC to return to zero
+    - Linux 5.4.227
+  * 5.15.0-58.64 breaks xen bridge networking (pvh domU) (LP: #2002889) // Focal
+    update: v5.4.227 upstream stable release (LP: #2003901)
+    - xen/netback: fix build warning
+  * Focal update: v5.4.226 upstream stable release (LP: #2003896)
+    - wifi: mac80211: fix memory free error when registering wiphy fail
+    - wifi: mac80211_hwsim: fix debugfs attribute ps with rc table support
+    - audit: fix undefined behavior in bit shift for AUDIT_BIT
+    - wifi: mac80211: Fix ack frame idr leak when mesh has no route
+    - spi: stm32: fix stm32_spi_prepare_mbr() that halves spi clk for every run
+    - drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
+    - block, bfq: fix null pointer dereference in bfq_bio_bfqg()
+    - arm64/syscall: Include asm/ptrace.h in syscall_wrapper header.
+    - RISC-V: vdso: Do not add missing symbols to version section in linker script
+    - MIPS: pic32: treat port as signed integer
+    - af_key: Fix send_acquire race with pfkey_register
+    - ARM: dts: am335x-pcm-953: Define fixed regulators in root node
+    - ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove
+    - regulator: core: fix kobject release warning and memory leak in
+      regulator_register()
+    - regulator: core: fix UAF in destroy_regulator()
+    - bus: sunxi-rsb: Support atomic transfers
+    - tee: optee: fix possible memory leak in optee_register_device()
+    - ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl
+    - net: liquidio: simplify if expression
+    - nfc/nci: fix race with opening and closing
+    - net: pch_gbe: fix potential memleak in pch_gbe_tx_queue()
+    - 9p/fd: fix issue of list_del corruption in p9_fd_cancel()
+    - ARM: mxs: fix memory leak in mxs_machine_init()
+    - net/mlx4: Check retval of mlx4_bitmap_init
+    - net/qla3xxx: fix potential memleak in ql3xxx_send()
+    - net: pch_gbe: fix pci device refcount leak while module exiting
+    - nfp: add port from netdev validation for EEPROM access
+    - Drivers: hv: vmbus: fix double free in the error path of
+      vmbus_add_channel_work()
+    - Drivers: hv: vmbus: fix possible memory leak in vmbus_device_register()
+    - net/mlx5: Fix FW tracer timestamp calculation
+    - tipc: set con sock in tipc_conn_alloc
+    - tipc: add an extra conn_get in tipc_conn_alloc
+    - tipc: check skb_linearize() return value in tipc_disc_rcv()
+    - xfrm: Fix ignored return value in xfrm6_init()
+    - NFC: nci: fix memory leak in nci_rx_data_packet()
+    - regulator: twl6030: re-add TWL6032_SUBCLASS
+    - bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending()
+    - dccp/tcp: Reset saddr on failure after inet6?_hash_connect().
+    - s390/dasd: fix no record found for raw_track_access
+    - nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st-nci: fix memory leaks in EVT_TRANSACTION
+    - net: thunderx: Fix the ACPI memory leak
+    - s390/crashdump: fix TOD programmable field size
+    - lib/vdso: use "grep -E" instead of "egrep"
+    - usb: dwc3: exynos: Fix remove() function
+    - arm64: dts: rockchip: lower rk3399-puma-haikou SD controller clock frequency
+    - iio: light: apds9960: fix wrong register for gesture gain
+    - iio: core: Fix entry not deleted when iio_register_sw_trigger_type() fails
+    - init/Kconfig: fix CC_HAS_ASM_GOTO_TIED_OUTPUT test with dash
+    - nios2: add FORCE for vmlinuz.gz
+    - iio: ms5611: Simplify IO callback parameters
+    - iio: pressure: ms5611: fixed value compensation bug
+    - ceph: do not update snapshot context when there is no new snapshot
+    - ceph: avoid putting the realm twice when decoding snaps fails
+    - firmware: google: Release devices before unregistering the bus
+    - firmware: coreboot: Register bus in module init
+    - nilfs2: fix nilfs_sufile_mark_dirty() not set segment usage as dirty
+    - gcov: clang: fix the buffer overflow issue
+    - Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode
+    - ASoC: Intel: bytcht_es8316: Add quirk for the Nanote UMPC-01
+    - serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
+    - xen/platform-pci: add missing free_irq() in error path
+    - platform/x86: asus-wmi: add missing pci_dev_put() in asus_wmi_set_xusb2pr()
+    - platform/x86: acer-wmi: Enable SW_TABLET_MODE on Switch V 10 (SW5-017)
+    - platform/x86: hp-wmi: Ignore Smart Experience App event
+    - [Config] updateconfigs for INET_TABLE_PERTURB_ORDER
+    - tcp: configurable source port perturb table size
+    - net: usb: qmi_wwan: add Telit 0x103a composition
+    - dm integrity: flush the journal on suspend
+    - binder: avoid potential data leakage when copying txn
+    - binder: read pre-translated fds from sender buffer
+    - binder: defer copies of pre-patched txn data
+    - binder: fix pointer cast warning
+    - binder: Address corner cases in deferred copy and fixup
+    - binder: Gracefully handle BINDER_TYPE_FDA objects with num_fds=0
+    - btrfs: free btrfs_path before copying root refs to userspace
+    - btrfs: free btrfs_path before copying fspath to userspace
+    - btrfs: free btrfs_path before copying subvol info to userspace
+    - btrfs: sysfs: normalize the error handling branch in btrfs_init_sysfs()
+    - drm/amd/dc/dce120: Fix audio register mapping, stop triggering KASAN
+    - drm/amdgpu: always register an MMU notifier for userptr
+    - fuse: lock inode unconditionally in fuse_fallocate()
+    - btrfs: free btrfs_path before copying inodes to userspace
+    - spi: spi-imx: Fix spi_bus_clk if requested clock is higher than input clock
+    - btrfs: move QUOTA_ENABLED check to rescan_should_stop from
+      btrfs_qgroup_rescan_worker
+    - drm/amdgpu: update drm_display_info correctly when the edid is read
+    - drm/amdgpu: Partially revert "drm/amdgpu: update drm_display_info correctly
+      when the edid is read"
+    - btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit()
+    - iio: health: afe4403: Fix oob read in afe4403_read_raw
+    - iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
+    - iio: light: rpr0521: add missing Kconfig dependencies
+    - scripts/faddr2line: Fix regression in name resolution on ppc64le
+    - hwmon: (i5500_temp) fix missing pci_disable_device()
+    - hwmon: (ibmpex) Fix possible UAF when ibmpex_register_bmc() fails
+    - of: property: decrement node refcount in of_fwnode_get_reference_args()
+    - net/mlx5: Fix uninitialized variable bug in outlen_write()
+    - net/mlx5e: Fix use-after-free when reverting termination table
+    - can: sja1000_isa: sja1000_isa_probe(): add missing free_sja1000dev()
+    - can: cc770: cc770_isa_probe(): add missing free_cc770dev()
+    - qlcnic: fix sleep-in-atomic-context bugs caused by msleep
+    - wifi: cfg80211: fix buffer overflow in elem comparison
+    - net: phy: fix null-ptr-deref while probe() failed
+    - net: net_netdev: Fix error handling in ntb_netdev_init_module()
+    - net/9p: Fix a potential socket leak in p9_socket_open
+    - net: ethernet: nixge: fix NULL dereference
+    - dsa: lan9303: Correct stat name
+    - net: hsr: Fix potential use-after-free
+    - afs: Fix fileserver probe RTT handling
+    - net: tun: Fix use-after-free in tun_detach()
+    - packet: do not set TP_STATUS_CSUM_VALID on CHECKSUM_COMPLETE
+    - sctp: fix memory leak in sctp_stream_outq_migrate()
+    - net: ethernet: renesas: ravb: Fix promiscuous mode after system resumed
+    - hwmon: (coretemp) Check for null before removing sysfs attrs
+    - hwmon: (coretemp) fix pci device refcount leak in nv1a_ram_new()
+    - net/mlx5: DR, Fix uninitialized var warning
+    - error-injection: Add prompt for function error injection
+    - tools/vm/slabinfo-gnuplot: use "grep -E" instead of "egrep"
+    - nilfs2: fix NULL pointer dereference in nilfs_palloc_commit_free_entry()
+    - x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
+    - pinctrl: intel: Save and restore pins in "direct IRQ" mode
+    - mmc: mmc_test: Fix removal of debugfs file
+    - mmc: core: Fix ambiguous TRIM and DISCARD arg
+    - mmc: sdhci-esdhc-imx: correct CQHCI exit halt state check
+    - mmc: sdhci-sprd: Fix no reset data and command after voltage switch
+    - tracing: Free buffers when a used dynamic event is removed
+    - arm64: Fix panic() when Spectre-v2 causes Spectre-BHB to re-allocate KVM
+      vectors
+    - arm64: errata: Fix KVM Spectre-v2 mitigation selection for Cortex-A57/A72
+    - mm: Fix '.data.once' orphan section warning
+    - ASoC: ops: Fix bounds check for _sx controls
+    - pinctrl: single: Fix potential division by zero
+    - iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init()
+    - parisc: Increase size of gcc stack frame check
+    - xtensa: increase size of gcc stack frame check
+    - parisc: Increase FRAME_WARN to 2048 bytes on parisc
+    - Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is
+      enabled
+    - selftests: net: add delete nexthop route warning test
+    - selftests: net: fix nexthop warning cleanup double ip typo
+    - ipv4: Handle attempt to delete multipath route when fib_info contains an nh
+      reference
+    - ipv4: Fix route deletion when nexthop info is not specified
+    - tracing/ring-buffer: Have polling block on watermark
+    - nvme: restrict management ioctls to admin
+    - nvme: ensure subsystem reset is single threaded
+    - x86/tsx: Add a feature bit for TSX control MSR support
+    - x86/pm: Add enumeration check before spec MSRs save/restore setup
+    - x86/ioremap: Fix page aligned size calculation in __ioremap_caller()
+    - Revert "clocksource/drivers/riscv: Events are stopped during CPU suspend"
+    - char: tpm: Protect tpm_pm_suspend with locks
+    - mmc: sdhci: use FIELD_GET for preset value bit masks
+    - mmc: sdhci: Fix voltage switch delay
+    - proc: avoid integer type confusion in get_proc_long
+    - proc: proc_skip_spaces() shouldn't think it is working on C strings
+    - v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails
+    - ipc/sem: Fix dangling sem_array access in semtimedop race
+    - Linux 5.4.226
+  * CVE-2022-4139
+    - drm/i915: fix TLB invalidation for Gen12 video and compute engines
+  * Focal update: v5.4.225 upstream stable release (LP: #2002347)
+    - xfs: preserve rmapbt swapext block reservation from freed blocks
+    - xfs: rename xfs_bmap_is_real_extent to is_written_extent
+    - xfs: redesign the reflink remap loop to fix blkres depletion crash
+    - xfs: use MMAPLOCK around filemap_map_pages()
+    - xfs: preserve inode versioning across remounts
+    - xfs: drain the buf delwri queue before xfsaild idles
+    - phy: stm32: fix an error code in probe
+    - wifi: cfg80211: silence a sparse RCU warning
+    - wifi: cfg80211: fix memory leak in query_regdb_file()
+    - bpf, sockmap: Fix the sk->sk_forward_alloc warning of sk_stream_kill_queues
+    - HID: hyperv: fix possible memory leak in mousevsc_probe()
+    - net: gso: fix panic on frag_list with mixed head alloc types
+    - net: tun: Fix memory leaks of napi_get_frags
+    - bnxt_en: Fix possible crash in bnxt_hwrm_set_coal()
+    - bnxt_en: fix potentially incorrect return value for ndo_rx_flow_steer
+    - net: fman: Unregister ethernet device on removal
+    - capabilities: fix undefined behavior in bit shift for CAP_TO_MASK
+    - net: lapbether: fix issue of dev reference count leakage in
+      lapbeth_device_event()
+    - hamradio: fix issue of dev reference count leakage in bpq_device_event()
+    - drm/vc4: Fix missing platform_unregister_drivers() call in
+      vc4_drm_register()
+    - ipv6: addrlabel: fix infoleak when sending struct ifaddrlblmsg to network
+    - can: af_can: fix NULL pointer dereference in can_rx_register()
+    - tipc: fix the msg->req tlv len check in
+      tipc_nl_compat_name_table_dump_header
+    - dmaengine: pxa_dma: use platform_get_irq_optional
+    - dmaengine: mv_xor_v2: Fix a resource leak in mv_xor_v2_remove()
+    - drivers: net: xgene: disable napi when register irq failed in
+      xgene_enet_open()
+    - perf stat: Fix printing os->prefix in CSV metrics output
+    - net: nixge: disable napi when enable interrupts failed in nixge_open()
+    - net/mlx5: Allow async trigger completion execution on single CPU systems
+    - net: cpsw: disable napi in cpsw_ndo_open()
+    - net: cxgb3_main: disable napi when bind qsets failed in cxgb_up()
+    - cxgb4vf: shut down the adapter when t4vf_update_port_info() failed in
+      cxgb4vf_open()
+    - ethernet: s2io: disable napi when start nic failed in s2io_card_up()
+    - net: mv643xx_eth: disable napi when init rxq or txq failed in
+      mv643xx_eth_open()
+    - ethernet: tundra: free irq when alloc ring failed in tsi108_open()
+    - net: macvlan: fix memory leaks of macvlan_common_newlink
+    - riscv: process: fix kernel info leakage
+    - arm64: efi: Fix handling of misaligned runtime regions and drop warning
+    - MIPS: jump_label: Fix compat branch range check
+    - mmc: cqhci: Provide helper for resetting both SDHCI and CQHCI
+    - mmc: sdhci-of-arasan: Fix SDHCI_RESET_ALL for CQHCI
+    - mmc: sdhci-tegra: Fix SDHCI_RESET_ALL for CQHCI
+    - ALSA: hda/ca0132: add quirk for EVGA Z390 DARK
+    - ALSA: hda: fix potential memleak in 'add_widget_node'
+    - ALSA: usb-audio: Add quirk entry for M-Audio Micro
+    - ALSA: usb-audio: Add DSD support for Accuphase DAC-60
+    - vmlinux.lds.h: Fix placement of '.data..decrypted' section
+    - nilfs2: fix deadlock in nilfs_count_free_blocks()
+    - nilfs2: fix use-after-free bug of ns_writer on remount
+    - drm/i915/dmabuf: fix sg_table handling in map_dma_buf
+    - btrfs: selftests: fix wrong error check in btrfs_free_dummy_root()
+    - udf: Fix a slab-out-of-bounds write bug in udf_find_entry()
+    - can: j1939: j1939_send_one(): fix missing CAN header initialization
+    - cert host tools: Stop complaining about deprecated OpenSSL functions
+    - dmaengine: at_hdmac: Fix at_lli struct definition
+    - dmaengine: at_hdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
+    - dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
+    - dmaengine: at_hdmac: Fix impossible condition
+    - dmaengine: at_hdmac: Check return code of dma_async_device_register
+    - net: tun: call napi_schedule_prep() to ensure we own a napi
+    - x86/cpu: Restore AMD's DE_CFG MSR after resume
+    - ASoC: wm5102: Revert "ASoC: wm5102: Fix PM disable depth imbalance in
+      wm5102_probe"
+    - ASoC: wm5110: Revert "ASoC: wm5110: Fix PM disable depth imbalance in
+      wm5110_probe"
+    - ASoC: wm8997: Revert "ASoC: wm8997: Fix PM disable depth imbalance in
+      wm8997_probe"
+    - ASoC: wm8962: Add an event handler for TEMP_HP and TEMP_SPK
+    - spi: intel: Fix the offset to get the 64K erase opcode
+    - ASoC: codecs: jz4725b: add missed Line In power control bit
+    - ASoC: codecs: jz4725b: fix reported volume for Master ctl
+    - ASoC: codecs: jz4725b: use right control for Capture Volume
+    - ASoC: codecs: jz4725b: fix capture selector naming
+    - selftests/futex: fix build for clang
+    - selftests/intel_pstate: fix build for ARCH=x86_64
+    - NFSv4: Retry LOCK on OLD_STATEID during delegation return
+    - i2c: i801: add lis3lv02d's I2C address for Vostro 5568
+    - drm/imx: imx-tve: Fix return type of imx_tve_connector_mode_valid
+    - btrfs: remove pointless and double ulist frees in error paths of qgroup
+      tests
+    - ASoC: codecs: jz4725b: Fix spelling mistake "Sourc" -> "Source", "Routee" ->
+      "Route"
+    - spi: stm32: Print summary 'callbacks suppressed' message
+    - ASoC: core: Fix use-after-free in snd_soc_exit()
+    - serial: 8250_omap: remove wait loop from Errata i202 workaround
+    - serial: 8250: omap: Fix unpaired pm_runtime_put_sync() in omap8250_remove()
+    - serial: 8250: omap: Flush PM QOS work on remove
+    - serial: imx: Add missing .thaw_noirq hook
+    - tty: n_gsm: fix sleep-in-atomic-context bug in gsm_control_send
+    - ASoC: soc-utils: Remove __exit for snd_soc_util_exit()
+    - block: sed-opal: kmalloc the cmd/resp buffers
+    - siox: fix possible memory leak in siox_device_add()
+    - parport_pc: Avoid FIFO port location truncation
+    - pinctrl: devicetree: fix null pointer dereferencing in pinctrl_dt_to_map
+    - arm64: dts: imx8mm: Fix NAND controller size-cells
+    - arm64: dts: imx8mn: Fix NAND controller size-cells
+    - ata: libata-transport: fix double ata_host_put() in ata_tport_add()
+    - net: bgmac: Drop free_netdev() from bgmac_enet_remove()
+    - mISDN: fix possible memory leak in mISDN_dsp_element_register()
+    - net: liquidio: release resources when liquidio driver open failed
+    - mISDN: fix misuse of put_device() in mISDN_register_device()
+    - net: macvlan: Use built-in RCU list checking
+    - net: caif: fix double disconnect client in chnl_net_open()
+    - bnxt_en: Remove debugfs when pci_register_driver failed
+    - xen/pcpu: fix possible memory leak in register_pcpu()
+    - drbd: use after free in drbd_create_device()
+    - platform/x86/intel: pmc: Don't unconditionally attach Intel PMC when
+      virtualized
+    - net/x25: Fix skb leak in x25_lapb_receive_frame()
+    - cifs: Fix wrong return value checking when GETFLAGS
+    - net: thunderbolt: Fix error handling in tbnet_init()
+    - cifs: add check for returning value of SMB2_set_info_init
+    - ftrace: Fix the possible incorrect kernel message
+    - ftrace: Optimize the allocation for mcount entries
+    - ftrace: Fix null pointer dereference in ftrace_add_mod()
+    - ring_buffer: Do not deactivate non-existant pages
+    - ALSA: usb-audio: Drop snd_BUG_ON() from snd_usbmidi_output_open()
+    - Revert "usb: dwc3: disable USB core PHY management"
+    - slimbus: stream: correct presence rate frequencies
+    - speakup: fix a segfault caused by switching consoles
+    - USB: serial: option: add Sierra Wireless EM9191
+    - USB: serial: option: remove old LARA-R6 PID
+    - USB: serial: option: add u-blox LARA-R6 00B modem
+    - USB: serial: option: add u-blox LARA-L6 modem
+    - USB: serial: option: add Fibocom FM160 0x0111 composition
+    - usb: add NO_LPM quirk for Realforce 87U Keyboard
+    - usb: chipidea: fix deadlock in ci_otg_del_timer
+    - iio: adc: at91_adc: fix possible memory leak in at91_adc_allocate_trigger()
+    - iio: trigger: sysfs: fix possible memory leak in iio_sysfs_trig_init()
+    - iio: pressure: ms5611: changed hardcoded SPI speed to value limited
+    - dm ioctl: fix misbehavior if list_versions races with module loading
+    - serial: 8250: Fall back to non-DMA Rx if IIR_RDI occurs
+    - serial: 8250_lpss: Configure DMA also w/o DMA filter
+    - Input: iforce - invert valid length check when fetching device IDs
+    - scsi: zfcp: Fix double free of FSF request when qdio send fails
+    - mmc: core: properly select voltage range without power cycle
+    - mmc: sdhci-pci-o2micro: fix card detect fail issue caused by CD# debounce
+      timeout
+    - mmc: sdhci-pci: Fix possible memory leak caused by missing pci_dev_put()
+    - docs: update mediator contact information in CoC doc
+    - misc/vmw_vmci: fix an infoleak in vmci_host_do_receive_datagram()
+    - serial: 8250: Flush DMA Rx on RLSI
+    - ring-buffer: Include dropped pages in counting dirty patches
+    - scsi: target: tcm_loop: Fix possible name leak in tcm_loop_setup_hba_bus()
+    - kprobes: Skip clearing aggrprobe's post_handler in kprobe-on-ftrace case
+    - Input: i8042 - fix leaking of platform device on module removal
+    - macvlan: enforce a consistent minimal mtu
+    - tcp: cdg: allow tcp_cdg_release() to be called multiple times
+    - kcm: avoid potential race in kcm_tx_work
+    - bpf, test_run: Fix alignment problem in bpf_prog_test_run_skb()
+    - kcm: close race conditions on sk_receive_queue
+    - 9p: trans_fd/p9_conn_cancel: drop client lock earlier
+    - gfs2: Check sb_bsize_shift after reading superblock
+    - gfs2: Switch from strlcpy to strscpy
+    - 9p/trans_fd: always use O_NONBLOCK read/write
+    - mm: fs: initialize fsdata passed to write_begin/write_end interface
+    - ntfs: fix use-after-free in ntfs_attr_find()
+    - ntfs: fix out-of-bounds read in ntfs_attr_find()
+    - ntfs: check overflow when iterating ATTR_RECORDs
+    - Linux 5.4.225
+  * CVE-2022-47520
+    - wifi: wilc1000: validate pairwise and authentication suite offsets
+  * CVE-2022-3545
+    - nfp: fix use-after-free in area_cache_get()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Fri, 10 Mar 2023 12:24:57 +0800
+
+linux-ein (5.4.0-1033.39) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1033.39 -proposed tracker (LP: #2007484)
+
+  * Focal update: v5.4.221 upstream stable release (LP: #1997993)
+    - [Config] updateconfigs for ARM64_ERRATUM_1742098
+
+  * [UC20][Amgis-V5] AVR watchdog on reboot (LP#1999760)
+    - SAUCE: dts: amgis: Remove safe and v2 device tree files
+    - SAUCE: amgis: dts: Default to camera enable
+    - SAUCE: amgis: dts: v3 and v4 cleanup
+    - SAUCE: amgis: dts: v5 hardware GPIO configuration
+
+  * [UC20][Amgis-V5] Enabling OPTEE based FDE (LP #1995129)
+    - SAUCE: dts: amgis: Enable optee node
+
+  * [UC20][Amgis-V5] go standby mode and then resume pushing the power button
+    (LP #1995144)
+    - SAUCE: dts: amgis: Enable wake-up GPIO pin
+
+  * [UC20] Camera does not work after resume from suspend (LP #1999815)
+    - SAUCE: imx: gpcv2: Fix PGC CPU mapping after resume
+
+  [ Ubuntu: 5.4.0-139.156 ]
+
+  * focal/linux: 5.4.0-139.156 -proposed tracker (LP: #2003486)
+  * Revoke & rotate to new signing key (LP: #2002812)
+    - [Packaging] Revoke and rotate to new signing key
+
+  [ Ubuntu: 5.4.0-138.155 ]
+
+  * focal/linux: 5.4.0-138.155 -proposed tracker (LP: #2001845)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+  * Focal update: v5.4.224 upstream stable release (LP: #1999273)
+    - RDMA/cma: Use output interface for net_dev check
+    - IB/hfi1: Correctly move list in sc_disable()
+    - NFSv4.1: Handle RECLAIM_COMPLETE trunking errors
+    - NFSv4.1: We must always send RECLAIM_COMPLETE after a reboot
+    - nfs4: Fix kmemleak when allocate slot failed
+    - net: dsa: Fix possible memory leaks in dsa_loop_init()
+    - RDMA/core: Fix null-ptr-deref in ib_core_cleanup()
+    - RDMA/qedr: clean up work queue on failure in qedr_alloc_resources()
+    - nfc: s3fwrn5: Fix potential memory leak in s3fwrn5_nci_send()
+    - nfc: nfcmrvl: Fix potential memory leak in nfcmrvl_i2c_nci_send()
+    - net: fec: fix improper use of NETDEV_TX_BUSY
+    - ata: pata_legacy: fix pdc20230_set_piomode()
+    - net: sched: Fix use after free in red_enqueue()
+    - net: tun: fix bugs for oversize packet when napi frags enabled
+    - netfilter: nf_tables: release flow rule object from commit path
+    - ipvs: use explicitly signed chars
+    - ipvs: fix WARNING in __ip_vs_cleanup_batch()
+    - ipvs: fix WARNING in ip_vs_app_net_cleanup()
+    - rose: Fix NULL pointer dereference in rose_send_frame()
+    - mISDN: fix possible memory leak in mISDN_register_device()
+    - isdn: mISDN: netjet: fix wrong check of device registration
+    - btrfs: fix inode list leak during backref walking at resolve_indirect_refs()
+    - btrfs: fix inode list leak during backref walking at find_parent_nodes()
+    - btrfs: fix ulist leaks in error paths of qgroup self tests
+    - Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
+    - net: mdio: fix undefined behavior in bit shift for __mdiobus_register
+    - net, neigh: Fix null-ptr-deref in neigh_table_clear()
+    - ipv6: fix WARNING in ip6_route_net_exit_late()
+    - media: s5p_cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: cros-ec-cec: limit msg.len to CEC_MAX_MSG_SIZE
+    - media: dvb-frontends/drxk: initialize err to 0
+    - media: meson: vdec: fix possible refcount leak in vdec_probe()
+    - scsi: core: Restrict legal sdev_state transitions via sysfs
+    - HID: saitek: add madcatz variant of MMO7 mouse device ID
+    - i2c: xiic: Add platform module alias
+    - xfs: don't fail verifier on empty attr3 leaf block
+    - xfs: use ordered buffers to initialize dquot buffers during quotacheck
+    - xfs: gut error handling in xfs_trans_unreserve_and_mod_sb()
+    - xfs: group quota should return EDQUOT when prj quota enabled
+    - xfs: don't fail unwritten extent conversion on writeback due to edquot
+    - xfs: Add the missed xfs_perag_put() for xfs_ifree_cluster()
+    - Bluetooth: L2CAP: Fix attempting to access uninitialized memory
+    - block, bfq: protect 'bfqd->queued' by 'bfqd->lock'
+    - binder: fix UAF of alloc->vma in race with munmap()
+    - btrfs: fix type of parameter generation in btrfs_get_dentry
+    - tcp/udp: Make early_demux back namespacified.
+    - kprobe: reverse kp->flags when arm_kprobe failed
+    - tools/nolibc/string: Fix memcmp() implementation
+    - tracing/histogram: Update document for KEYS_MAX size
+    - capabilities: fix potential memleak on error path from vfs_getxattr_alloc()
+    - fuse: add file_modified() to fallocate
+    - efi: random: reduce seed size to 32 bytes
+    - perf/x86/intel: Fix pebs event constraints for ICL
+    - perf/x86/intel: Add Cooper Lake stepping to isolation_ucodes[]
+    - ALSA: usb-audio: Add quirks for MacroSilicon MS2100/MS2106 devices
+    - parisc: Make 8250_gsc driver dependend on CONFIG_PARISC
+    - parisc: Export iosapic_serial_irq() symbol for serial port driver
+    - parisc: Avoid printing the hardware path twice
+    - ext4: fix warning in 'ext4_da_release_space'
+    - ext4: fix BUG_ON() when directory entry has invalid rec_len
+    - KVM: x86: Mask off reserved bits in CPUID.8000001AH
+    - KVM: x86: Mask off reserved bits in CPUID.80000008H
+    - KVM: x86: emulator: em_sysexit should update ctxt->mode
+    - KVM: x86: emulator: introduce emulator_recalc_and_set_mode
+    - KVM: x86: emulator: update the emulation mode after CR0 write
+    - mtd: rawnand: gpmi: Set WAIT_FOR_READY timeout based on program/erase times
+    - drm/rockchip: dsi: Force synchronous probe
+    - drm/i915/sdvo: Filter out invalid outputs more sensibly
+    - drm/i915/sdvo: Setup DDC fully before output init
+    - wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
+    - ipc: remove memcg accounting for sops objects in do_semtimedop()
+    - Linux 5.4.224
+  * Focal update: v5.4.223 upstream stable release (LP: #1999179)
+    - can: j1939: transport: j1939_session_skb_drop_old():
+      spin_unlock_irqrestore() before kfree_skb()
+    - can: kvaser_usb: Fix possible completions during init_completion
+    - ALSA: Use del_timer_sync() before freeing timer
+    - ALSA: au88x0: use explicitly signed char
+    - USB: add RESET_RESUME quirk for NVIDIA Jetson devices in RCM
+    - usb: dwc3: gadget: Stop processing more requests on IMI
+    - usb: dwc3: gadget: Don't set IMI for no_interrupt
+    - usb: bdc: change state when port disconnected
+    - usb: xhci: add XHCI_SPURIOUS_SUCCESS to ASM1042 despite being a V0.96
+      controller
+    - mtd: rawnand: marvell: Use correct logic for nand-keep-config
+    - xhci: Remove device endpoints from bandwidth list when freeing the device
+    - tools: iio: iio_utils: fix digit calculation
+    - iio: light: tsl2583: Fix module unloading
+    - fbdev: smscufx: Fix several use-after-free bugs
+    - mac802154: Fix LQI recording
+    - drm/msm/dsi: fix memory corruption with too many bridges
+    - drm/msm/hdmi: fix memory corruption with too many bridges
+    - mmc: core: Fix kernel panic when remove non-standard SDIO card
+    - kernfs: fix use-after-free in __kernfs_remove
+    - perf auxtrace: Fix address filter symbol name match for modules
+    - s390/futex: add missing EX_TABLE entry to __futex_atomic_op()
+    - s390/pci: add missing EX_TABLE entries to
+      __pcistg_mio_inuser()/__pcilg_mio_inuser()
+    - xfs: finish dfops on every insert range shift iteration
+    - xfs: clear XFS_DQ_FREEING if we can't lock the dquot buffer to flush
+    - xfs: force the log after remapping a synchronous-writes file
+    - Xen/gntdev: don't ignore kernel unmapping error
+    - xen/gntdev: Prevent leaking grants
+    - mm,hugetlb: take hugetlb_lock before decrementing h->resv_huge_pages
+    - net: ieee802154: fix error return code in dgram_bind()
+    - media: v4l2: Fix v4l2_i2c_subdev_set_name function documentation
+    - drm/msm: Fix return type of mdp4_lvds_connector_mode_valid
+    - arc: iounmap() arg is volatile
+    - ALSA: ac97: fix possible memory leak in snd_ac97_dev_register()
+    - tipc: fix a null-ptr-deref in tipc_topsrv_accept
+    - net: netsec: fix error handling in netsec_register_mdio()
+    - x86/unwind/orc: Fix unreliable stack dump with gcov
+    - amd-xgbe: fix the SFP compliance codes check for DAC cables
+    - amd-xgbe: add the bit rate quirk for Molex cables
+    - kcm: annotate data-races around kcm->rx_psock
+    - kcm: annotate data-races around kcm->rx_wait
+    - net: fix UAF issue in nfqnl_nf_hook_drop() when ops_init() failed
+    - net: lantiq_etop: don't free skb when returning NETDEV_TX_BUSY
+    - tcp: fix indefinite deferral of RTO with SACK reneging
+    - can: mscan: mpc5xxx: mpc5xxx_can_probe(): add missing put_clock() in error
+      path
+    - PM: hibernate: Allow hybrid sleep to work with s2idle
+    - media: vivid: s_fbuf: add more sanity checks
+    - media: vivid: dev->bitmap_cap wasn't freed in all cases
+    - media: v4l2-dv-timings: add sanity checks for blanking values
+    - media: videodev2.h: V4L2_DV_BT_BLANKING_HEIGHT should check 'interlaced'
+    - i40e: Fix ethtool rx-flow-hash setting for X722
+    - i40e: Fix VF hang when reset is triggered on another VF
+    - i40e: Fix flow-type by setting GL_HASH_INSET registers
+    - net: ksz884x: fix missing pci_disable_device() on error in pcidev_init()
+    - PM: domains: Fix handling of unavailable/disabled idle states
+    - ALSA: aoa: i2sbus: fix possible memory leak in i2sbus_add_dev()
+    - ALSA: aoa: Fix I2S device accounting
+    - openvswitch: switch from WARN to pr_warn
+    - net: ehea: fix possible memory leak in ehea_register_port()
+    - nh: fix scope used to find saddr when adding non gw nh
+    - net/mlx5e: Do not increment ESN when updating IPsec ESN state
+    - net/mlx5: Fix possible use-after-free in async command interface
+    - net: enetc: survive memory pressure without crashing
+    - can: rcar_canfd: rcar_canfd_handle_global_receive(): fix IRQ storm on global
+      FIFO receive
+    - Linux 5.4.223
+  * Focal update: v5.4.222 upstream stable release (LP: #1997994)
+    - once: fix section mismatch on clang builds
+    - Linux 5.4.222
+  * Focal update: v5.4.221 upstream stable release (LP: #1997993)
+    - xfs: open code insert range extent split helper
+    - xfs: rework insert range into an atomic operation
+    - xfs: rework collapse range into an atomic operation
+    - xfs: add a function to deal with corrupt buffers post-verifiers
+    - xfs: xfs_buf_corruption_error should take __this_address
+    - xfs: fix buffer corruption reporting when xfs_dir3_free_header_check fails
+    - xfs: check owner of dir3 data blocks
+    - xfs: check owner of dir3 blocks
+    - xfs: Use scnprintf() for avoiding potential buffer overflow
+    - xfs: remove the xfs_disk_dquot_t and xfs_dquot_t
+    - xfs: remove the xfs_dq_logitem_t typedef
+    - xfs: remove the xfs_qoff_logitem_t typedef
+    - xfs: Replace function declaration by actual definition
+    - xfs: factor out quotaoff intent AIL removal and memory free
+    - xfs: fix unmount hang and memory leak on shutdown during quotaoff
+    - xfs: preserve default grace interval during quotacheck
+    - xfs: Lower CIL flush limit for large logs
+    - xfs: Throttle commits on delayed background CIL push
+    - xfs: factor common AIL item deletion code
+    - xfs: tail updates only need to occur when LSN changes
+    - xfs: don't write a corrupt unmount record to force summary counter recalc
+    - xfs: trylock underlying buffer on dquot flush
+    - xfs: factor out a new xfs_log_force_inode helper
+    - xfs: reflink should force the log out if mounted with wsync
+    - xfs: move inode flush to the sync workqueue
+    - xfs: fix use-after-free on CIL context on shutdown
+    - ocfs2: clear dinode links count in case of error
+    - ocfs2: fix BUG when iput after ocfs2_mknod fails
+    - x86/microcode/AMD: Apply the patch early on every logical thread
+    - hwmon/coretemp: Handle large core ID value
+    - ata: ahci-imx: Fix MODULE_ALIAS
+    - ata: ahci: Match EM_MAX_SLOTS with SATA_PMP_MAX_PORTS
+    - KVM: arm64: vgic: Fix exit condition in scan_its_table()
+    - media: venus: dec: Handle the case where find_format fails
+    - [Config] updateconfigs for ARM64_ERRATUM_1742098
+    - arm64: errata: Remove AES hwcap for COMPAT tasks
+    - r8152: add PID for the Lenovo OneLink+ Dock
+    - btrfs: fix processing of delayed data refs during backref walking
+    - btrfs: fix processing of delayed tree block refs during backref walking
+    - ACPI: extlog: Handle multiple records
+    - tipc: Fix recognition of trial period
+    - tipc: fix an information leak in tipc_topsrv_kern_subscr
+    - HID: magicmouse: Do not set BTN_MOUSE on double report
+    - net/atm: fix proc_mpc_write incorrect return value
+    - net: phy: dp83867: Extend RX strap quirk for SGMII mode
+    - net: sched: cake: fix null pointer access issue when cake_init() fails
+    - net: hns: fix possible memory leak in hnae_ae_register()
+    - iommu/vt-d: Clean up si_domain in the init_dmars() error path
+    - arm64: topology: move store_cpu_topology() to shared code
+    - riscv: topology: fix default topology reporting
+    - ACPI: video: Force backlight native for more TongFang devices
+    - Makefile.debug: re-enable debug info for .S files
+    - hv_netvsc: Fix race between VF offering and VF association message from host
+    - mm: /proc/pid/smaps_rollup: fix no vma's null-deref
+    - Linux 5.4.221
+  * Focal update: v5.4.220 upstream stable release (LP: #1996812)
+    - ALSA: oss: Fix potential deadlock at unregistration
+    - ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
+    - ALSA: usb-audio: Fix potential memory leaks
+    - ALSA: usb-audio: Fix NULL dererence at error path
+    - ALSA: hda/realtek: remove ALC289_FIXUP_DUAL_SPK for Dell 5530
+    - ALSA: hda/realtek: Correct pin configs for ASUS G533Z
+    - ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
+    - ALSA: hda/realtek: Add Intel Reference SSID to support headset keys
+    - mtd: rawnand: atmel: Unmap streaming DMA mappings
+    - cifs: destage dirty pages before re-reading them for cache=none
+    - cifs: Fix the error length of VALIDATE_NEGOTIATE_INFO message
+    - iio: dac: ad5593r: Fix i2c read protocol requirements
+    - iio: pressure: dps310: Refactor startup procedure
+    - iio: pressure: dps310: Reset chip after timeout
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - can: kvaser_usb: Fix use of uninitialized completion
+    - can: kvaser_usb_leaf: Fix overread with an invalid command
+    - can: kvaser_usb_leaf: Fix TX queue out of sync after restart
+    - can: kvaser_usb_leaf: Fix CAN state after restart
+    - mmc: sdhci-sprd: Fix minimum clock limit
+    - fs: dlm: fix race between test_bit() and queue_work()
+    - fs: dlm: handle -EBUSY first in lock arg validation
+    - HID: multitouch: Add memory barriers
+    - quota: Check next/prev free block number after reading from quota file
+    - ASoC: wcd9335: fix order of Slimbus unprepare/disable
+    - regulator: qcom_rpm: Fix circular deferral regression
+    - RISC-V: Make port I/O string accessors actually work
+    - parisc: fbdev/stifb: Align graphics memory size to 4MB
+    - riscv: Allow PROT_WRITE-only mmap()
+    - riscv: Pass -mno-relax only on lld < 15.0.0
+    - UM: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - PCI: Sanitise firmware BAR assignments behind a PCI-PCI bridge
+    - powerpc/boot: Explicitly disable usage of SPE instructions
+    - fbdev: smscufx: Fix use-after-free in ufx_ops_open()
+    - btrfs: fix race between quota enable and quota rescan ioctl
+    - f2fs: increase the limit for reserve_root
+    - f2fs: fix to do sanity check on destination blkaddr during recovery
+    - f2fs: fix to do sanity check on summary info
+    - nilfs2: fix use-after-free bug of struct nilfs_root
+    - jbd2: wake up journal waiters in FIFO order, not LIFO
+    - ext4: avoid crash when inline data creation follows DIO write
+    - ext4: fix null-ptr-deref in ext4_write_info
+    - ext4: make ext4_lazyinit_thread freezable
+    - ext4: place buffer head allocation before handle start
+    - livepatch: fix race between fork and KLP transition
+    - ftrace: Properly unset FTRACE_HASH_FL_MOD
+    - ring-buffer: Allow splice to read previous partially read pages
+    - ring-buffer: Have the shortest_full queue be the shortest not longest
+    - ring-buffer: Check pending waiters when doing wake ups as well
+    - ring-buffer: Fix race between reset page and reading page
+    - media: cedrus: Set the platform driver data earlier
+    - KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
+    - KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
+    - KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
+    - gcov: support GCC 12.1 and newer compilers
+    - drm/nouveau: fix a use-after-free in nouveau_gem_prime_import_sg_table()
+    - selinux: use "grep -E" instead of "egrep"
+    - tracing: Disable interrupt or preemption before acquiring arch_spinlock_t
+    - userfaultfd: open userfaultfds with O_RDONLY
+    - sh: machvec: Use char[] for section boundaries
+    - ARM: 9247/1: mm: set readonly for MT_MEMORY_RO with ARM_LPAE
+    - nfsd: Fix a memory leak in an error handling path
+    - wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
+    - wifi: mac80211: allow bw change during channel switch in mesh
+    - bpftool: Fix a wrong type cast in btf_dumper_int
+    - x86/resctrl: Fix to restore to original value when re-enabling hardware
+      prefetch register
+    - wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
+    - spi: qup: add missing clk_disable_unprepare on error in spi_qup_resume()
+    - spi: qup: add missing clk_disable_unprepare on error in
+      spi_qup_pm_resume_runtime()
+    - wifi: rtl8xxxu: Fix skb misuse in TX queue selection
+    - bpf: btf: fix truncated last_member_type_id in btf_struct_resolve
+    - wifi: rtl8xxxu: gen2: Fix mistake in path B IQ calibration
+    - net: fs_enet: Fix wrong check in do_pd_setup
+    - bpf: Ensure correct locking around vulnerable function find_vpid()
+    - x86/microcode/AMD: Track patch allocation size explicitly
+    - spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe
+    - netfilter: nft_fib: Fix for rpath check with VRF devices
+    - spi: s3c64xx: Fix large transfers with DMA
+    - vhost/vsock: Use kvmalloc/kvfree for larger packets.
+    - sctp: handle the error returned from sctp_auth_asoc_init_active_key
+    - tcp: fix tcp_cwnd_validate() to not forget is_cwnd_limited
+    - net: rds: don't hold sock lock when cancelling work from
+      rds_tcp_reset_callbacks()
+    - bnx2x: fix potential memory leak in bnx2x_tpa_stop()
+    - net/ieee802154: reject zero-sized raw_sendmsg()
+    - once: add DO_ONCE_SLOW() for sleepable contexts
+    - net: mvpp2: fix mvpp2 debugfs leak
+    - drm: bridge: adv7511: fix CEC power down control register offset
+    - drm/mipi-dsi: Detach devices when removing the host
+    - platform/chrome: fix double-free in chromeos_laptop_prepare()
+    - platform/chrome: fix memory corruption in ioctl
+    - platform/x86: msi-laptop: Fix old-ec check for backlight registering
+    - platform/x86: msi-laptop: Fix resource cleanup
+    - drm: fix drm_mipi_dbi build errors
+    - drm/bridge: megachips: Fix a null pointer dereference bug
+    - ASoC: rsnd: Add check for rsnd_mod_power_on
+    - ALSA: hda: beep: Simplify keep-power-at-enable behavior
+    - drm/omap: dss: Fix refcount leak bugs
+    - mmc: au1xmmc: Fix an error handling path in au1xmmc_probe()
+    - ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API
+    - drm/msm/dpu: index dpu_kms->hw_vbif using vbif_idx
+    - ALSA: dmaengine: increment buffer pointer atomically
+    - mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
+    - ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe
+    - ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe
+    - ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe
+    - ALSA: hda/hdmi: Don't skip notification handling during PM operation
+    - memory: pl353-smc: Fix refcount leak bug in pl353_smc_probe()
+    - memory: of: Fix refcount leak bug in of_get_ddr_timings()
+    - soc: qcom: smsm: Fix refcount leak bugs in qcom_smsm_probe()
+    - soc: qcom: smem_state: Add refcounting for the 'state->of_node'
+    - ARM: dts: turris-omnia: Fix mpp26 pin name and comment
+    - ARM: dts: kirkwood: lsxl: fix serial line
+    - ARM: dts: kirkwood: lsxl: remove first ethernet port
+    - ARM: dts: exynos: correct s5k6a3 reset polarity on Midas family
+    - ARM: Drop CMDLINE_* dependency on ATAGS
+    - ARM: dts: exynos: fix polarity of VBUS GPIO of Origen
+    - iio: adc: at91-sama5d2_adc: fix AT91_SAMA5D2_MR_TRACKTIM_MAX
+    - iio: adc: at91-sama5d2_adc: check return status for pressure and touch
+    - iio: adc: at91-sama5d2_adc: lock around oversampling and sample freq
+    - iio: inkern: only release the device node when done with it
+    - iio: ABI: Fix wrong format of differential capacitance channel ABI.
+    - clk: meson: Hold reference returned by of_get_parent()
+    - clk: oxnas: Hold reference returned by of_get_parent()
+    - clk: berlin: Add of_node_put() for of_get_parent()
+    - clk: tegra: Fix refcount leak in tegra210_clock_init
+    - clk: tegra: Fix refcount leak in tegra114_clock_init
+    - clk: tegra20: Fix refcount leak in tegra20_clock_init
+    - HSI: omap_ssi: Fix refcount leak in ssi_probe
+    - HSI: omap_ssi_port: Fix dma_map_sg error check
+    - media: exynos4-is: fimc-is: Add of_node_put() when breaking out of loop
+    - tty: xilinx_uartps: Fix the ignore_status
+    - media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
+    - RDMA/rxe: Fix "kernel NULL pointer dereference" error
+    - RDMA/rxe: Fix the error caused by qp->sk
+    - misc: ocxl: fix possible refcount leak in afu_ioctl()
+    - dyndbg: fix module.dyndbg handling
+    - dyndbg: let query-modname override actual module name
+    - mtd: devices: docg3: check the return value of devm_ioremap() in the probe
+    - RDMA/siw: Always consume all skbuf data in sk_data_ready() upcall.
+    - ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
+    - ata: fix ata_id_has_devslp()
+    - ata: fix ata_id_has_ncq_autosense()
+    - ata: fix ata_id_has_dipm()
+    - mtd: rawnand: meson: fix bit map use in meson_nfc_ecc_correct()
+    - md/raid5: Ensure stripe_fill happens on non-read IO with journal
+    - xhci: Don't show warning for reinit on known broken suspend
+    - usb: gadget: function: fix dangling pnp_string in f_printer.c
+    - drivers: serial: jsm: fix some leaks in probe
+    - tty: serial: fsl_lpuart: disable dma rx/tx use flags in lpuart_dma_shutdown
+    - phy: qualcomm: call clk_disable_unprepare in the error handling
+    - staging: vt6655: fix some erroneous memory clean-up loops
+    - firmware: google: Test spinlock on panic path to avoid lockups
+    - serial: 8250: Fix restoring termios speed after suspend
+    - scsi: libsas: Fix use-after-free bug in smp_execute_task_sg()
+    - fsi: core: Check error number after calling ida_simple_get
+    - mfd: intel_soc_pmic: Fix an error handling path in
+      intel_soc_pmic_i2c_probe()
+    - mfd: fsl-imx25: Fix an error handling path in mx25_tsadc_setup_irq()
+    - mfd: lp8788: Fix an error handling path in lp8788_probe()
+    - mfd: lp8788: Fix an error handling path in lp8788_irq_init() and
+      lp8788_irq_init()
+    - mfd: fsl-imx25: Fix check for platform_get_irq() errors
+    - mfd: sm501: Add check for platform_driver_register()
+    - clk: mediatek: mt8183: mfgcfg: Propagate rate changes to parent
+    - dmaengine: ioat: stop mod_timer from resurrecting deleted timer in
+      __cleanup()
+    - spmi: pmic-arb: correct duplicate APID to PPID mapping logic
+    - clk: bcm2835: fix bcm2835_clock_rate_from_divisor declaration
+    - clk: ti: dra7-atl: Fix reference leak in of_dra7_atl_clk_probe
+    - clk: ast2600: BCLK comes from EPLL
+    - mailbox: bcm-ferxrm-mailbox: Fix error check for dma_map_sg
+    - powerpc/math_emu/efp: Include module.h
+    - powerpc/sysdev/fsl_msi: Add missing of_node_put()
+    - powerpc/pci_dn: Add missing of_node_put()
+    - powerpc/powernv: add missing of_node_put() in opal_export_attrs()
+    - x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition
+    - powerpc/64s: Fix GENERIC_CPU build flags for PPC970 / G5
+    - powerpc: Fix SPE Power ISA properties for e500v1 platforms
+    - cgroup/cpuset: Enable update_tasks_cpumask() on top_cpuset
+    - iommu/omap: Fix buffer overflow in debugfs
+    - crypto: akcipher - default implementation for setting a private key
+    - crypto: ccp - Release dma channels before dmaengine unrgister
+    - iommu/iova: Fix module config properly
+    - kbuild: remove the target in signal traps when interrupted
+    - crypto: cavium - prevent integer overflow loading firmware
+    - f2fs: fix race condition on setting FI_NO_EXTENT flag
+    - ACPI: video: Add Toshiba Satellite/Portege Z830 quirk
+    - MIPS: BCM47XX: Cast memcmp() of function to (void *)
+    - powercap: intel_rapl: fix UBSAN shift-out-of-bounds issue
+    - thermal: intel_powerclamp: Use get_cpu() instead of smp_processor_id() to
+      avoid crash
+    - NFSD: Return nfserr_serverfault if splice_ok but buf->pages have data
+    - wifi: brcmfmac: fix invalid address access when enabling SCAN log level
+    - bpftool: Clear errno after libcap's checks
+    - openvswitch: Fix double reporting of drops in dropwatch
+    - openvswitch: Fix overreporting of drops in dropwatch
+    - tcp: annotate data-race around tcp_md5sig_pool_populated
+    - wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()
+    - xfrm: Update ipcomp_scratches with NULL when freed
+    - wifi: brcmfmac: fix use-after-free bug in brcmf_netdev_start_xmit()
+    - Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
+    - Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
+    - can: bcm: check the result of can_send() in bcm_can_tx()
+    - wifi: rt2x00: don't run Rt5592 IQ calibration on MT7620
+    - wifi: rt2x00: set correct TX_SW_CFG1 MAC register for MT7620
+    - wifi: rt2x00: set VGC gain for both chains of MT7620
+    - wifi: rt2x00: set SoC wmac clock register
+    - wifi: rt2x00: correctly set BBP register 86 for MT7620
+    - net: If sock is dead don't access sock's sk_wq in sk_stream_wait_memory
+    - Bluetooth: L2CAP: Fix user-after-free
+    - drm/nouveau/nouveau_bo: fix potential memory leak in nouveau_bo_alloc()
+    - drm: Use size_t type for len variable in drm_copy_field()
+    - drm: Prevent drm_copy_field() to attempt copying a NULL pointer
+    - drm/amd/display: fix overflow on MIN_I64 definition
+    - drm/vc4: vec: Fix timings for VEC modes
+    - drm: panel-orientation-quirks: Add quirk for Anbernic Win600
+    - platform/x86: msi-laptop: Change DMI match / alias strings to fix module
+      autoloading
+    - drm/amdgpu: fix initial connector audio value
+    - mmc: sdhci-msm: add compatible string check for sdm670
+    - ARM: dts: imx7d-sdb: config the max pressure for tsc2046
+    - ARM: dts: imx6q: add missing properties for sram
+    - ARM: dts: imx6dl: add missing properties for sram
+    - ARM: dts: imx6qp: add missing properties for sram
+    - ARM: dts: imx6sl: add missing properties for sram
+    - ARM: dts: imx6sll: add missing properties for sram
+    - ARM: dts: imx6sx: add missing properties for sram
+    - btrfs: scrub: try to fix super block errors
+    - clk: zynqmp: Fix stack-out-of-bounds in strncpy`
+    - media: cx88: Fix a null-ptr-deref bug in buffer_prepare()
+    - clk: zynqmp: pll: rectify rate rounding in zynqmp_pll_round_rate
+    - scsi: 3w-9xxx: Avoid disabling device if failing to enable it
+    - nbd: Fix hung when signal interrupts nbd_start_device_ioctl()
+    - power: supply: adp5061: fix out-of-bounds read in adp5061_get_chg_type()
+    - staging: vt6655: fix potential memory leak
+    - ata: libahci_platform: Sanity check the DT child nodes number
+    - bcache: fix set_at_max_writeback_rate() for multiple attached devices
+    - HID: roccat: Fix use-after-free in roccat_read()
+    - md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d
+    - usb: host: xhci: Fix potential memory leak in xhci_alloc_stream_info()
+    - usb: musb: Fix musb_gadget.c rxstate overflow bug
+    - Revert "usb: storage: Add quirk for Samsung Fit flash"
+    - staging: rtl8723bs: fix a potential memory leak in rtw_init_cmd_priv()
+    - nvme: copy firmware_rev on each init
+    - nvmet-tcp: add bounds check on Transfer Tag
+    - usb: idmouse: fix an uninit-value in idmouse_open
+    - clk: bcm2835: Make peripheral PLLC critical
+    - perf intel-pt: Fix segfault in intel_pt_print_info() with uClibc
+    - net: ieee802154: return -EINVAL for unknown addr type
+    - Revert "net/ieee802154: reject zero-sized raw_sendmsg()"
+    - net/ieee802154: don't warn zero-sized raw_sendmsg()
+    - ext4: continue to expand file system when the target size doesn't reach
+    - efi: libstub: drop pointless get_memory_map() call
+    - inet: fully convert sk->sk_rx_dst to RCU rules
+    - thermal: intel_powerclamp: Use first online CPU as control_cpu
+    - Linux 5.4.220
+  * Focal update: v5.4.219 upstream stable release (LP: #1996804)
+    - Linux 5.4.219
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 16 Feb 2023 23:33:02 +0800
+
+linux-ein (5.4.0-1032.38) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1032.38 -proposed tracker (LP: #2006609)
+
+  * [UC20][QCA-BT] The bluetooth interface is unstable (LP: #1999613)
+    - SAUCE: bluetooth: Add support for Qualcomm's HCI IBS protocol
+    - [Config] Enable HCI IBS protocol
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 09 Feb 2023 12:40:51 +0800
+
+linux-ein (5.4.0-1031.37) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1031.37 -proposed tracker (LP: #2002802)
+
+  * [K4500-NXP][B0+DV-2][UC20] Sometimes show kernel messages 'mmc2: cqhci:
+    timeout for tag 31' (LP: #2000621)
+    - mmc: sdhci-esdhc-imx: disable CMDQ support
+
+  [ Ubuntu: 5.4.0-137.154 ]
+
+  * focal/linux: 5.4.0-137.154 -proposed tracker (LP: #2001969)
+  * CVE-2022-3643
+    - 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
+  * CVE-2022-45934
+    - Bluetooth: L2CAP: Fix u8 overflow
+  * CVE-2022-42896
+    - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
+
+  [ Ubuntu: 5.4.0-136.153 ]
+
+  * focal/linux: 5.4.0-136.153 -proposed tracker (LP: #1997835)
+  * Expose built-in trusted and revoked certificates (LP: #1996892)
+    - [Packaging] Expose built-in trusted and revoked certificates
+  * [UBUNTU 20.04] KVM: PV: ext call delivered twice when receiver in PSW wait
+    (LP: #1995941)
+    - KVM: s390: pv: don't present the ecall interrupt twice
+  * [UBUNTU 20.04] boot: Add s390x secure boot trailer (LP: #1996071)
+    - s390/boot: add secure boot trailer
+  * Fix rfkill causing soft blocked wifi (LP: #1996198)
+    - platform/x86: hp_wmi: Fix rfkill causing soft blocked wifi
+  * md: Replace snprintf with scnprintf (LP: #1993315)
+    - md: Replace snprintf with scnprintf
+  * input/keyboard: the keyboard on some Asus laptops can't work (LP: #1992266)
+    - ACPI: resource: Skip IRQ override on Asus Vivobook K3402ZA/K3502ZA
+    - ACPI: resource: Add ASUS model S5402ZA to quirks
+  * Focal update: v5.4.218 upstream stable release (LP: #1995530)
+    - mm: pagewalk: Fix race between unmap and page walker
+    - perf tools: Fixup get_current_dir_name() compilation
+    - firmware: arm_scmi: Add SCMI PM driver remove routine
+    - dmaengine: xilinx_dma: cleanup for fetching xlnx,num-fstores property
+    - dmaengine: xilinx_dma: Report error in case of dma_set_mask_and_coherent API
+      failure
+    - ARM: dts: fix Moxa SDIO 'compatible', remove 'sdhci' misnomer
+    - scsi: qedf: Fix a UAF bug in __qedf_probe()
+    - net/ieee802154: fix uninit value bug in dgram_sendmsg
+    - um: Cleanup syscall_handler_t cast in syscalls_32.h
+    - um: Cleanup compiler warning in arch/x86/um/tls_32.c
+    - arch: um: Mark the stack non-executable to fix a binutils warning
+    - usb: mon: make mmapped memory read only
+    - USB: serial: ftdi_sio: fix 300 bps rate for SIO
+    - mmc: core: Replace with already defined values for readability
+    - mmc: core: Terminate infinite loop in SD-UHS voltage switch
+    - rpmsg: qcom: glink: replace strncpy() with strscpy_pad()
+    - nilfs2: fix leak of nilfs_root in case of writer thread creation failure
+    - nilfs2: replace WARN_ONs by nilfs_error for checkpoint acquisition failure
+    - ceph: don't truncate file in atomic_open
+    - random: clamp credited irq bits to maximum mixed
+    - ALSA: hda: Fix position reporting on Poulsbo
+    - efi: Correct Macmini DMI match in uefi cert quirk
+    - USB: serial: qcserial: add new usb-id for Dell branded EM7455
+    - random: restore O_NONBLOCK support
+    - random: avoid reading two cache lines on irq randomness
+    - random: use expired timer rather than wq for mixing fast pool
+    - Input: xpad - add supported devices as contributed on github
+    - Input: xpad - fix wireless 360 controller breaking after suspend
+    - Linux 5.4.218
+  * Focal update: v5.4.217 upstream stable release (LP: #1995528)
+    - xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag
+    - xfs: introduce XFS_MAX_FILEOFF
+    - xfs: truncate should remove all blocks, not just to the end of the page
+      cache
+    - xfs: fix s_maxbytes computation on 32-bit kernels
+    - xfs: fix IOCB_NOWAIT handling in xfs_file_dio_aio_read
+    - xfs: refactor remote attr value buffer invalidation
+    - xfs: fix memory corruption during remote attr value buffer invalidation
+    - xfs: move incore structures out of xfs_da_format.h
+    - xfs: streamline xfs_attr3_leaf_inactive
+    - xfs: fix uninitialized variable in xfs_attr3_leaf_inactive
+    - xfs: remove unused variable 'done'
+    - Makefile.extrawarn: Move -Wcast-function-type-strict to W=1
+    - docs: update mediator information in CoC docs
+    - Linux 5.4.217
+  * Focal update: v5.4.216 upstream stable release (LP: #1995526)
+    - uas: add no-uas quirk for Hiksemi usb_disk
+    - usb-storage: Add Hiksemi USB3-FW to IGNORE_UAS
+    - uas: ignore UAS for Thinkplus chips
+    - net: usb: qmi_wwan: Add new usb-id for Dell branded EM7455
+    - clk: ingenic-tcu: Properly enable registers before accessing timers
+    - ARM: dts: integrator: Tag PCI host with device_type
+    - ntfs: fix BUG_ON in ntfs_lookup_inode_by_name()
+    - libata: add ATA_HORKAGE_NOLPM for Pioneer BDR-207M and BDR-205
+    - mmc: moxart: fix 4-bit bus width and remove 8-bit bus width
+    - mm/page_alloc: fix race condition between build_all_zonelists and page
+      allocation
+    - mm: prevent page_frag_alloc() from corrupting the memory
+    - mm/migrate_device.c: flush TLB while holding PTL
+    - mm: fix madivse_pageout mishandling on non-LRU page
+    - media: dvb_vb2: fix possible out of bound access
+    - ARM: dts: Move am33xx and am43xx mmc nodes to sdhci-omap driver
+    - ARM: dts: am33xx: Fix MMCHS0 dma properties
+    - soc: sunxi: sram: Actually claim SRAM regions
+    - soc: sunxi: sram: Prevent the driver from being unbound
+    - soc: sunxi_sram: Make use of the helper function
+      devm_platform_ioremap_resource()
+    - soc: sunxi: sram: Fix probe function ordering issues
+    - soc: sunxi: sram: Fix debugfs info for A64 SRAM C
+    - Revert "drm: bridge: analogix/dp: add panel prepare/unprepare in
+      suspend/resume time"
+    - Input: melfas_mip4 - fix return value check in mip4_probe()
+    - usbnet: Fix memory leak in usbnet_disconnect()
+    - nvme: add new line after variable declatation
+    - nvme: Fix IOC_PR_CLEAR and IOC_PR_RELEASE ioctls for nvme devices
+    - selftests: Fix the if conditions of in test_extra_filter()
+    - clk: imx: imx6sx: remove the SET_RATE_PARENT flag for QSPI clocks
+    - clk: iproc: Do not rely on node name for correct PLL setup
+    - Linux 5.4.216
+  * Focal update: v5.4.215 upstream stable release (LP: #1993203)
+    - of: fdt: fix off-by-one error in unflatten_dt_nodes()
+    - NFSv4: Turn off open-by-filehandle and NFS re-export for NFSv4.0
+    - gpio: mpc8xxx: Fix support for IRQ_TYPE_LEVEL_LOW flow_type in mpc85xx
+    - drm/meson: Correct OSD1 global alpha value
+    - drm/meson: Fix OSD1 RGB to YCbCr coefficient
+    - parisc: ccio-dma: Add missing iounmap in error path in ccio_probe()
+    - ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC
+    - task_stack, x86/cea: Force-inline stack helpers
+    - tracing: hold caller_addr to hardirq_{enable,disable}_ip
+    - cifs: revalidate mapping when doing direct writes
+    - cifs: don't send down the destination address to sendmsg for a SOCK_STREAM
+    - MAINTAINERS: add Chandan as xfs maintainer for 5.4.y
+    - iomap: iomap that extends beyond EOF should be marked dirty
+    - ASoC: nau8824: Fix semaphore unbalance at error paths
+    - regulator: pfuze100: Fix the global-out-of-bounds access in
+      pfuze100_regulator_probe()
+    - rxrpc: Fix local destruction being repeated
+    - rxrpc: Fix calc of resend age
+    - ALSA: hda/sigmatel: Keep power up while beep is enabled
+    - ALSA: hda/tegra: Align BDL entry to 4KB boundary
+    - net: usb: qmi_wwan: add Quectel RM520N
+    - afs: Return -EAGAIN, not -EREMOTEIO, when a file already locked
+    - MIPS: OCTEON: irq: Fix octeon_irq_force_ciu_mapping()
+    - mksysmap: Fix the mismatch of 'L0' symbols in System.map
+    - video: fbdev: pxa3xx-gcu: Fix integer overflow in pxa3xx_gcu_write
+    - cgroup: Add missing cpus_read_lock() to cgroup_attach_task_all()
+    - ALSA: hda/sigmatel: Fix unused variable warning for beep power change
+    - usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind
+    - usb: dwc3: Issue core soft reset before enabling run/stop
+    - usb: dwc3: gadget: Prevent repeat pullup()
+    - usb: dwc3: gadget: Refactor pullup()
+    - usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup()
+    - usb: dwc3: gadget: Avoid duplicate requests to enable Run/Stop
+    - usb: xhci-mtk: get the microframe boundary for ESIT
+    - usb: xhci-mtk: add only one extra CS for FS/LS INTR
+    - usb: xhci-mtk: use @sch_tt to check whether need do TT schedule
+    - usb: xhci-mtk: add a function to (un)load bandwidth info
+    - usb: xhci-mtk: add some schedule error number
+    - usb: xhci-mtk: allow multiple Start-Split in a microframe
+    - usb: xhci-mtk: relax TT periodic bandwidth allocation
+    - wifi: mac80211: Fix UAF in ieee80211_scan_rx()
+    - tty/serial: atmel: RS485 & ISO7816: wait for TXRDY before sending data
+    - serial: atmel: remove redundant assignment in rs485_config
+    - tty: serial: atmel: Preserve previous USART mode if RS485 disabled
+    - usb: add quirks for Lenovo OneLink+ Dock
+    - usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+    - usb: cdns3: fix issue with rearming ISO OUT endpoint
+    - Revert "usb: add quirks for Lenovo OneLink+ Dock"
+    - Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio"
+    - USB: core: Fix RST error in hub.c
+    - USB: serial: option: add Quectel BG95 0x0203 composition
+    - USB: serial: option: add Quectel RM520N
+    - ALSA: hda/tegra: set depop delay for tegra
+    - ALSA: hda: add Intel 5 Series / 3400 PCI DID
+    - ALSA: hda/realtek: Add quirk for Huawei WRT-WX9
+    - ALSA: hda/realtek: Re-arrange quirk table entries
+    - ALSA: hda/realtek: Add pincfg for ASUS G513 HP jack
+    - ALSA: hda/realtek: Add pincfg for ASUS G533Z HP jack
+    - ALSA: hda/realtek: Add quirk for ASUS GA503R laptop
+    - ALSA: hda/realtek: Enable 4-speaker output Dell Precision 5530 laptop
+    - efi: libstub: check Shim mode using MokSBStateRT
+    - mm/slub: fix to return errno if kmalloc() fails
+    - arm64: dts: rockchip: Pull up wlan wake# on Gru-Bob
+    - arm64: dts: rockchip: Set RK3399-Gru PCLK_EDP to 24 MHz
+    - arm64: dts: rockchip: Remove 'enable-active-low' from rk3399-puma
+    - netfilter: nf_conntrack_sip: fix ct_sip_walk_headers
+    - netfilter: nf_conntrack_irc: Tighten matching on DCC message
+    - netfilter: nfnetlink_osf: fix possible bogus match in nf_osf_find()
+    - iavf: Fix cached head and tail value for iavf_get_tx_pending
+    - ipvlan: Fix out-of-bound bugs caused by unset skb->mac_header
+    - net: team: Unsync device addresses on ndo_stop
+    - MIPS: lantiq: export clk_get_io() for lantiq_wdt.ko
+    - MIPS: Loongson32: Fix PHY-mode being left unspecified
+    - iavf: Fix bad page state
+    - i40e: Fix set max_tx_rate when it is lower than 1 Mbps
+    - of: mdio: Add of_node_put() when breaking out of for_each_xx
+    - net/sched: taprio: avoid disabling offload when it was never enabled
+    - net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child
+      qdiscs
+    - netfilter: ebtables: fix memory leak when blob is malformed
+    - can: gs_usb: gs_can_open(): fix race dev->can.state condition
+    - perf jit: Include program header in ELF files
+    - perf kcore_copy: Do not check /proc/modules is unchanged
+    - net: sunhme: Fix packet reception for len < RX_COPY_THRESHOLD
+    - net: sched: fix possible refcount leak in tc_new_tfilter()
+    - serial: Create uart_xmit_advance()
+    - serial: tegra: Use uart_xmit_advance(), fixes icount.tx accounting
+    - serial: tegra-tcu: Use uart_xmit_advance(), fixes icount.tx accounting
+    - s390/dasd: fix Oops in dasd_alias_get_start_dev due to missing pavgroup
+    - usb: xhci-mtk: fix issue of out-of-bounds array access
+    - cifs: always initialize struct msghdr smb_msg completely
+    - Drivers: hv: Never allocate anything besides framebuffer from framebuffer
+      memory region
+    - drm/amd/display: Limit user regamma to a valid value
+    - drm/rockchip: Fix return type of cdn_dp_connector_mode_valid
+    - workqueue: don't skip lockdep work dependency in cancel_work_sync()
+    - ext4: fix bug in extents parsing when eh_entries == 0 and eh_depth > 0
+    - xfs: replace -EIO with -EFSCORRUPTED for corrupt metadata
+    - xfs: slightly tweak an assert in xfs_fs_map_blocks
+    - xfs: add missing assert in xfs_fsmap_owner_from_rmap
+    - xfs: range check ri_cnt when recovering log items
+    - xfs: attach dquots and reserve quota blocks during unwritten conversion
+    - xfs: convert EIO to EFSCORRUPTED when log contents are invalid
+    - xfs: constify the buffer pointer arguments to error functions
+    - xfs: always log corruption errors
+    - xfs: fix some memory leaks in log recovery
+    - xfs: stabilize insert range start boundary to avoid COW writeback race
+    - xfs: use bitops interface for buf log item AIL flag check
+    - xfs: refactor agfl length computation function
+    - xfs: split the sunit parameter update into two parts
+    - xfs: don't commit sunit/swidth updates to disk if that would cause repair
+      failures
+    - xfs: fix an ABBA deadlock in xfs_rename
+    - xfs: fix use-after-free when aborting corrupt attr inactivation
+    - ext4: make directory inode spreading reflect flexbg size
+    - Linux 5.4.215
+  * Focal update: v5.4.214 upstream stable release (LP: #1993196)
+    - drm/msm/rd: Fix FIFO-full deadlock
+    - HID: ishtp-hid-clientHID: ishtp-hid-client: Fix comment typo
+    - hid: intel-ish-hid: ishtp: Fix ishtp client sending disordered message
+    - tg3: Disable tg3 device on system reboot to avoid triggering AER
+    - ieee802154: cc2520: add rc code in cc2520_tx()
+    - Input: iforce - add support for Boeder Force Feedback Wheel
+    - nvmet-tcp: fix unhandled tcp states in nvmet_tcp_state_change()
+    - perf/arm_pmu_platform: fix tests for platform_get_irq() failure
+    - platform/x86: acer-wmi: Acer Aspire One AOD270/Packard Bell Dot keymap fixes
+    - usb: storage: Add ASUS <0x0b05:0x1932> to IGNORE_UAS
+    - mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()
+    - net: dp83822: disable rx error interrupt
+    - soc: fsl: select FSL_GUTS driver for DPIO
+    - tracefs: Only clobber mode/uid/gid on remount if asked
+    - Linux 5.4.214
+  * Focal update: v5.4.213 upstream stable release (LP: #1992211)
+    - efi: capsule-loader: Fix use-after-free in efi_capsule_write
+    - wifi: iwlegacy: 4965: corrected fix for potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - fs: only do a memory barrier for the first set_buffer_uptodate()
+    - Revert "mm: kmemleak: take a full lowmem check in kmemleak_*_phys()"
+    - net: dp83822: disable false carrier interrupt
+    - drm/msm/dsi: fix the inconsistent indenting
+    - drm/msm/dsi: Fix number of regulators for msm8996_dsi_cfg
+    - platform/x86: pmc_atom: Fix SLP_TYPx bitfield mask
+    - iio: adc: mcp3911: make use of the sign bit
+    - ieee802154/adf7242: defer destroy_workqueue call
+    - wifi: cfg80211: debugfs: fix return type in ht40allow_map_read()
+    - Revert "xhci: turn off port power in shutdown"
+    - net: sched: tbf: don't call qdisc_put() while holding tree lock
+    - ethernet: rocker: fix sleep in atomic context bug in neigh_timer_handler
+    - kcm: fix strp_init() order and cleanup
+    - sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb
+    - tcp: annotate data-race around challenge_timestamp
+    - Revert "sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb"
+    - net/smc: Remove redundant refcount increase
+    - serial: fsl_lpuart: RS485 RTS polariy is inverse
+    - staging: rtl8712: fix use after free bugs
+    - powerpc: align syscall table for ppc32
+    - vt: Clear selection before changing the font
+    - tty: serial: lpuart: disable flow control while waiting for the transmit
+      engine to complete
+    - Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flag
+    - iio: adc: mcp3911: use correct formula for AD conversion
+    - misc: fastrpc: fix memory corruption on probe
+    - misc: fastrpc: fix memory corruption on open
+    - USB: serial: ftdi_sio: add Omron CS1W-CIF31 device id
+    - binder: fix UAF of ref->proc caused by race condition
+    - usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup
+    - drm/i915/reg: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops
+    - Revert "clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops"
+    - clk: core: Fix runtime PM sequence in clk_core_unprepare()
+    - Input: rk805-pwrkey - fix module autoloading
+    - clk: bcm: rpi: Fix error handling of raspberrypi_fw_get_rate
+    - hwmon: (gpio-fan) Fix array out of bounds access
+    - gpio: pca953x: Add mutex_lock for regcache sync in PM
+    - thunderbolt: Use the actual buffer in tb_async_error()
+    - xhci: Add grace period after xHC start to prevent premature runtime suspend.
+    - USB: serial: cp210x: add Decagon UCA device id
+    - USB: serial: option: add support for OPPO R11 diag port
+    - USB: serial: option: add Quectel EM060K modem
+    - USB: serial: option: add support for Cinterion MV32-WA/WB RmNet mode
+    - usb: typec: altmodes/displayport: correct pin assignment for UFP receptacles
+    - usb: dwc2: fix wrong order of phy_power_on and phy_init
+    - USB: cdc-acm: Add Icom PMR F3400 support (0c26:0020)
+    - usb-storage: Add ignore-residue quirk for NXP PN7462AU
+    - s390/hugetlb: fix prepare_hugepage_range() check for 2 GB hugepages
+    - s390: fix nospec table alignments
+    - USB: core: Prevent nested device-reset calls
+    - usb: gadget: mass_storage: Fix cdrom data transfers on MAC-OS
+    - driver core: Don't probe devices after bus_type.match() probe deferral
+    - wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected
+    - net: mac802154: Fix a condition in the receive path
+    - ALSA: seq: oss: Fix data-race for max_midi_devs access
+    - ALSA: seq: Fix data-race at module auto-loading
+    - drm/i915/glk: ECS Liva Q2 needs GLK HDMI port timing quirk
+    - btrfs: harden identification of a stale device
+    - usb: dwc3: fix PHY disable sequence
+    - usb: dwc3: disable USB core PHY management
+    - USB: serial: ch341: fix lost character on LCR updates
+    - USB: serial: ch341: fix disabled rx timer on older devices
+    - scsi: megaraid_sas: Fix double kfree()
+    - drm/gem: Fix GEM handle release errors
+    - drm/amdgpu: Check num_gfx_rings for gfx v9_0 rb setup.
+    - drm/radeon: add a force flush to delay work when radeon
+    - parisc: ccio-dma: Handle kmalloc failure in ccio_init_resources()
+    - parisc: Add runtime check to prevent PA2.0 kernels on PA1.x machines
+    - arm64: cacheinfo: Fix incorrect assignment of signed error value to unsigned
+      fw_level
+    - fbdev: chipsfb: Add missing pci_disable_device() in chipsfb_pci_init()
+    - drm/amdgpu: mmVM_L2_CNTL3 register not initialized correctly
+    - ALSA: emu10k1: Fix out of bounds access in snd_emu10k1_pcm_channel_alloc()
+    - ALSA: aloop: Fix random zeros in capture data when using jiffies timer
+    - ALSA: usb-audio: Fix an out-of-bounds bug in
+      __snd_usb_parse_audio_interface()
+    - kprobes: Prohibit probes in gate area
+    - debugfs: add debugfs_lookup_and_remove()
+    - nvmet: fix a use-after-free
+    - scsi: mpt3sas: Fix use-after-free warning
+    - scsi: lpfc: Add missing destroy_workqueue() in error path
+    - cgroup: Optimize single thread migration
+    - cgroup: Elide write-locking threadgroup_rwsem when updating csses on an
+      empty subtree
+    - cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock
+    - smb3: missing inode locks in punch hole
+    - ARM: dts: imx6qdl-kontron-samx6i: remove duplicated node
+    - regulator: core: Clean up on enable failure
+    - RDMA/cma: Fix arguments order in net device validation
+    - soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugs
+    - RDMA/hns: Fix supported page size
+    - netfilter: br_netfilter: Drop dst references before setting.
+    - rxrpc: Fix an insufficiently large sglist in rxkad_verify_packet_2()
+    - afs: Use the operation issue time instead of the reply time for callbacks
+    - sch_sfb: Don't assume the skb is still around after enqueueing to child
+    - tipc: fix shift wrapping bug in map_get()
+    - i40e: Fix kernel crash during module removal
+    - RDMA/siw: Pass a pointer to virt_to_page()
+    - ipv6: sr: fix out-of-bounds read when setting HMAC data.
+    - RDMA/mlx5: Set local port to one when accessing counters
+    - nvme-tcp: fix UAF when detecting digest errors
+    - tcp: fix early ETIMEDOUT after spurious non-SACK RTO
+    - sch_sfb: Also store skb len before calling child enqueue
+    - x86/nospec: Fix i386 RSB stuffing
+    - MIPS: loongson32: ls1c: Fix hang during startup
+    - Linux 5.4.213
+  * CVE-2022-2663
+    - netfilter: nf_conntrack_irc: Fix forged IP logic
+  * CVE-2022-3061
+    - video: fbdev: i740fb: Error out if 'pixclock' equals zero
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sat, 14 Jan 2023 16:17:47 +0800
+
+linux-ein (5.4.0-1030.36) focal; urgency=medium
+
+  * focal/linux-ein: 5.4.0-1030.36 -proposed tracker (LP: #2001879)
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update helper scripts
+
+  * remove a space from model in the device tree (LP: #2001574)
+    - SAUCE: dts: vesta-500: drop the last space from model
+
+  * [UC20] Improper network interface name for wwan interface (LP: #1999616)
+    - net: usb: cdc_ether: added support for Thales Cinterion PLSx3 modem family.
+    - SAUCE: net: usb: cdc_ether: add pls62 modem ids
+
+  * Set LED Behavior for Hard Reboot (LP: #1991304)
+    - SAUCE: dts: vesta-500: Fix the led level and let them on
+
+  * [imx8-bms] Disable SDMA (LP: #1997367)
+    - dmaengine: imx-sdma: restart cyclic channel if needed
+    - dmaengine: imx-sdma: fix cyclic buffer race condition
+    - dmaengine: imx-sdma: only restart cyclic channel when enabled
+
+  * [imx8-bms] Fail to boot OS (LP: #1995467)
+    - SAUCE: serial: sc16is7xx: setup GPIO controller later in probe
+    - SAUCE: serial: sc16is7xx: Change error path order
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 05 Jan 2023 23:08:21 +0800
+
+linux-ein (5.4.0-1029.35) focal; urgency=medium
+
+  * [UC20] Failed to change wifi MAC (LP: #1998279)
+    - SAUCE: ath10k: Add macaddr kernel module parameter
+
+  * Read serial number and MAC address from fuses (device provisioning) (LP:
+    #1991298)
+    - SAUCE: ath10k: Getting macaddr from Uboot
+
+  * Patch file for cascade-kernel (SF: #00347119)
+    - SAUCE: dts: vesta-500: change pad setting to save power
+
+  * Tillamook: Wifi need additional binary file to work (LP: #1990944)
+    - ath10k: add QCA9377 sdio hw_param item
+    - ath10k: switch to ieee80211_tx_dequeue_ni
+    - SAUCE: ath10k: sdio: skip cal_data if without cal_firmware
+
+  * Tillamook: [UC20] Could not detect any USB device (LP: #1991203)
+    - MLK-14285-1 usb: phy: add usb mode for usb_phy
+    - MLK-14285-2 usb: chipidea: set mode for usb phy driver
+    - MLK-13308-2 usb: phy: phy-mxs-usb: handle USB PHY event
+    - MLK-14285-3 usb: phy: mxs: optimize disconnect line condition
+
+  * Tillamook: (image) Secure boot for UC20 (LP: #1991185)
+    - SAUCE: dts: vesta-500: add ocram definition for optee-os
+
+  * Tillamook: (image) Create classic20-x02 image (LP: #1991167)
+    - SAUNCE: dts: add vesta-500 dts and overlay dts
+    - SAUCE: scripts: add support for building dtbo
+    - kbuild: Silence unavoidable dtc overlay warnings
+    - SAUCE: vesta_overlay: support dt overlay for vesta
+    - [Config] enable vesta overlay manager
+
+  * [K4500-NXP] Failed to probe caam_jr device message is shown in dmesg (LP:
+    #1993138)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Disable job ring 2 node
+
+  [ Ubuntu: 5.4.0-135.152 ]
+
+  * focal/linux: 5.4.0-135.152 -proposed tracker (LP: #1997412)
+  * containerd sporadic timeouts (LP: #1996678)
+    - epoll: call final ep_events_available() check under the lock
+    - epoll: check for events when removing a timed out thread from the wait queue
+    - Revert "fs: check FMODE_LSEEK to control internal pipe splicing"
+  * CVE-2022-3621
+    - nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
+  * CVE-2022-3565
+    - mISDN: fix use-after-free bugs in l1oip timer handlers
+  * 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-3564
+    - 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-3594
+    - r8152: Rate limit overflow messages
+  * CVE-2022-42703
+    - mm/rmap.c: don't reuse anon_vma if we just want a copy
+
+  [ Ubuntu: 5.4.0-132.148 ]
+
+  * CVE-2022-42719
+    - mac80211: mlme: find auth challenge directly
+    - wifi: mac80211: don't parse mbssid in assoc response
+    - wifi: mac80211: fix MBSSID parsing use-after-free
+  * iavf: SR-IOV VFs error with no traffic flow when MTU greater than 1500
+    (LP: #1983656)
+    - iavf: Fix set max MTU size with port VLAN and jumbo frames
+    - i40e: Fix VF set max MTU size
+  * fib_nexthop_nongw.sh from ubuntu_kernel_selftests failed on B-5.4
+    (LP: #1990800)
+    - SAUCE: selftests/net: skipping tests for older ip command releases
+  * CVE-2022-29901
+    - Revert "x86/speculation: Add RSB VM Exit protections"
+    - Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
+    - 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/kvm/vmx: Make noinstr clean
+    - 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: Remove skip_r11rcx
+    - 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
+    - intel_idle: Disable IBRS during long idle
+    - x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
+    - 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: Use TEST %REG,%REG instead of CMP $0,%REG in vmenter.S
+    - KVM/nVMX: Use __vmx_vcpu_run in nested_vmx_check_vmentry_hw
+    - KVM: VMX: Flatten __vmx_vcpu_run()
+    - KVM: VMX: Convert launched argument to flags
+    - 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
+  * ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+    systems (LP: #1990985)
+    - ACPI: processor_idle: Skip dummy wait if kernel is in guest
+    - ACPI: processor idle: Practically limit "Dummy wait" workaround to old Intel
+      systems
+  * cgroup: all controllers mounted when using 'cgroup_no_v1=' (LP: #1988584)
+    - cgroup-v1: add disabled controller check in cgroup1_parse_param()
+  * Focal update: v5.4.212 upstream stable release (LP: #1991156)
+    - audit: fix potential double free on error path from fsnotify_add_inode_mark
+    - parisc: Fix exception handler for fldw and fstw instructions
+    - kernel/sys_ni: add compat entry for fadvise64_64
+    - usb: cdns3: Fix issue for clear halt endpoint
+    - pinctrl: amd: Don't save/restore interrupt status and wake status bits
+    - sched/deadline: Unthrottle PI boosted threads while enqueuing
+    - sched/deadline: Fix stale throttling on de-/boosted tasks
+    - sched/deadline: Fix priority inheritance with multiple scheduling classes
+    - kernel/sched: Remove dl_boosted flag comment
+    - xfrm: fix refcount leak in __xfrm_policy_check()
+    - SUNRPC: RPC level errors should set task->tk_rpc_status
+    - rose: check NULL rose_loopback_neigh->loopback
+    - net/mlx5e: Properly disable vlan strip on non-UL reps
+    - net: moxa: get rid of asymmetry in DMA mapping/unmapping
+    - bonding: 802.3ad: fix no transmission of LACPDUs
+    - net: ipvtap - add __init/__exit annotations to module init/exit funcs
+    - netfilter: ebtables: reject blobs that don't provide all entry points
+    - bnxt_en: fix NQ resource accounting during vf creation on 57500 chips
+    - netfilter: nft_payload: report ERANGE for too long offset and length
+    - netfilter: nft_payload: do not truncate csum_offset and csum_type
+    - netfilter: nft_osf: restrict osf to ipv4, ipv6 and inet families
+    - netfilter: nft_tunnel: restrict it to netdev family
+    - net: Fix data-races around weight_p and dev_weight_[rt]x_bias.
+    - net: Fix data-races around netdev_tstamp_prequeue.
+    - ratelimit: Fix data-races in ___ratelimit().
+    - net: Fix a data-race around sysctl_tstamp_allow_data.
+    - net: Fix a data-race around sysctl_net_busy_poll.
+    - net: Fix a data-race around sysctl_net_busy_read.
+    - net: Fix a data-race around netdev_budget.
+    - net: Fix a data-race around netdev_budget_usecs.
+    - net: Fix a data-race around sysctl_somaxconn.
+    - ixgbe: stop resetting SYSTIME in ixgbe_ptp_start_cyclecounter
+    - btrfs: fix silent failure when deleting root reference
+    - btrfs: replace: drop assert for suspended replace
+    - btrfs: add info when mount fails due to stale replace target
+    - btrfs: check if root is readonly while setting security xattr
+    - x86/unwind/orc: Unwind ftrace trampolines with correct ORC entry
+    - loop: Check for overflow while configuring loop
+    - asm-generic: sections: refactor memory_intersects
+    - s390: fix double free of GS and RI CBs on fork() failure
+    - ACPI: processor: Remove freq Qos request for all CPUs
+    - mm/hugetlb: fix hugetlb not supporting softdirty tracking
+    - md: call __md_stop_writes in md_stop
+    - perf/x86/intel/uncore: Fix broken read_counter() for SNB IMC PMU
+    - scsi: storvsc: Remove WQ_MEM_RECLAIM from storvsc_error_wq
+    - mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()
+    - s390/mm: do not trigger write fault when vma does not allow VM_WRITE
+    - x86/bugs: Add "unknown" reporting for MMIO Stale Data
+    - kbuild: Fix include path in scripts/Makefile.modpost
+    - Bluetooth: L2CAP: Fix build errors in some archs
+    - HID: steam: Prevent NULL pointer dereference in steam_{recv,send}_report
+    - udmabuf: Set the DMA mask for the udmabuf device (v2)
+    - media: pvrusb2: fix memory leak in pvr_probe
+    - HID: hidraw: fix memory leak in hidraw_release()
+    - fbdev: fb_pm2fb: Avoid potential divide by zero error
+    - ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is
+      dead
+    - bpf: Don't redirect packets with invalid pkt_len
+    - mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
+    - btrfs: introduce btrfs_lookup_match_dir
+    - btrfs: do not pin logs too early during renames
+    - btrfs: unify lookup return value when dir entry is missing
+    - drm/amd/display: Avoid MPC infinite loop
+    - drm/amd/display: clear optc underflow before turn off odm clock
+    - neigh: fix possible DoS due to net iface start/stop loop
+    - s390/hypfs: avoid error message under KVM
+    - drm/amd/display: Fix pixel clock programming
+    - netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to y
+    - btrfs: tree-checker: check for overlapping extent items
+    - lib/vdso: Let do_coarse() return 0 to simplify the callsite
+    - lib/vdso: Mark do_hres() and do_coarse() as __always_inline
+    - kprobes: don't call disarm_kprobe() for disabled kprobes
+    - net/af_packet: check len when min_header_len equals to 0
+    - net: neigh: don't call kfree_skb() under spin_lock_irqsave()
+    - Linux 5.4.212
+  * Focal update: v5.4.211 upstream stable release (LP: #1990190)
+    - Makefile: link with -z noexecstack --no-warn-rwx-segments
+    - x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments
+    - scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"
+    - ALSA: bcd2000: Fix a UAF bug on the error path of probing
+    - igc: Remove _I_PHY_ID checking
+    - wifi: mac80211_hwsim: fix race condition in pending packet
+    - wifi: mac80211_hwsim: add back erroneously removed cast
+    - wifi: mac80211_hwsim: use 32-bit skb cookie
+    - add barriers to buffer_uptodate and set_buffer_uptodate
+    - HID: wacom: Only report rotation for art pen
+    - HID: wacom: Don't register pad_input for touch switch
+    - KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case
+    - KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case
+    - KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0
+    - KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value
+    - KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks
+    - KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP
+    - mm/mremap: hold the rmap lock in write mode when moving page table entries.
+    - ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model
+    - ALSA: hda/cirrus - support for iMac 12,1 model
+    - ALSA: hda/realtek: Add quirk for another Asus K42JZ model
+    - tty: vt: initialize unicode screen buffer
+    - vfs: Check the truncate maximum size in inode_newsize_ok()
+    - fs: Add missing umask strip in vfs_tmpfile
+    - thermal: sysfs: Fix cooling_device_stats_setup() error code path
+    - fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters
+    - usbnet: Fix linkwatch use-after-free on disconnect
+    - ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()
+    - parisc: Fix device names in /proc/iomem
+    - parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat mode
+    - drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error
+    - drm/nouveau: fix another off-by-one in nvbios_addr
+    - drm/amdgpu: Check BO's requested pinning domains against its
+      preferred_domains
+    - iio: light: isl29028: Fix the warning in isl29028_remove()
+    - fuse: limit nsec
+    - serial: mvebu-uart: uart2 error bits clearing
+    - md-raid10: fix KASAN warning
+    - ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()
+    - PCI: Add defines for normal and subtractive PCI bridges
+    - powerpc/fsl-pci: Fix Class Code of PCIe Root Port
+    - powerpc/ptdump: Fix display of RW pages on FSL_BOOK3E
+    - powerpc/powernv: Avoid crashing if rng is NULL
+    - MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
+    - coresight: Clear the connection field properly
+    - USB: HCD: Fix URB giveback issue in tasklet function
+    - ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC
+    - arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC
+    - netfilter: nf_tables: fix null deref due to zeroed list head
+    - epoll: autoremove wakers even more aggressively
+    - x86: Handle idle=nomwait cmdline properly for x86_idle
+    - arm64: Do not forget syscall when starting a new thread.
+    - arm64: fix oops in concurrently setting insn_emulation sysctls
+    - ext2: Add more validity checks for inode counts
+    - genirq: Don't return error on missing optional irq_request_resources()
+    - wait: Fix __wait_event_hrtimeout for RT/DL tasks
+    - ARM: dts: imx6ul: add missing properties for sram
+    - ARM: dts: imx6ul: change operating-points to uint32-matrix
+    - ARM: dts: imx6ul: fix csi node compatible
+    - ARM: dts: imx6ul: fix lcdif node compatible
+    - ARM: dts: imx6ul: fix qspi node compatible
+    - spi: synquacer: Add missing clk_disable_unprepare()
+    - ARM: OMAP2+: display: Fix refcount leak bug
+    - ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks
+    - ACPI: PM: save NVS memory for Lenovo G40-45
+    - ACPI: LPSS: Fix missing check in register_device_clock()
+    - arm64: dts: qcom: ipq8074: fix NAND node name
+    - arm64: dts: allwinner: a64: orangepi-win: Fix LED node name
+    - ARM: shmobile: rcar-gen2: Increase refcount for new reference
+    - PM: hibernate: defer device probing when resuming from hibernation
+    - selinux: Add boundary check in put_entry()
+    - spi: spi-rspi: Fix PIO fallback on RZ platforms
+    - ARM: findbit: fix overflowing offset
+    - meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_init
+    - ARM: bcm: Fix refcount leak in bcm_kona_smc_init
+    - x86/pmem: Fix platform-device leak in error path
+    - ARM: dts: ast2500-evb: fix board compatible
+    - ARM: dts: ast2600-evb: fix board compatible
+    - soc: fsl: guts: machine variable might be unset
+    - ARM: dts: qcom: mdm9615: add missing PMIC GPIO reg
+    - ARM: OMAP2+: Fix refcount leak in omapdss_init_of
+    - ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init
+    - cpufreq: zynq: Fix refcount leak in zynq_get_revision
+    - soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register
+    - ARM: dts: qcom: pm8841: add required thermal-sensor-cells
+    - bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()
+    - arm64: dts: mt7622: fix BPI-R64 WPS button
+    - erofs: avoid consecutive detection for Highmem memory
+    - blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created
+    - regulator: of: Fix refcount leak bug in of_get_regulation_constraints()
+    - nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()
+    - thermal/tools/tmon: Include pthread and time headers in tmon.h
+    - dm: return early from dm_pr_call() if DM device is suspended
+    - ath10k: do not enforce interrupt trigger type
+    - wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()
+    - drm/mipi-dbi: align max_chunk to 2 in spi_transfer
+    - drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()
+    - drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff function
+    - drm: adv7511: override i2c address of cec before accessing it
+    - i2c: Fix a potential use after free
+    - media: tw686x: Register the irq at the end of probe
+    - wifi: iwlegacy: 4965: fix potential off-by-one overflow in
+      il4965_rs_fill_link_cmd()
+    - drm: bridge: adv7511: Add check for mipi_dsi_driver_register
+    - drm/mcde: Fix refcount leak in mcde_dsi_bind
+    - media: hdpvr: fix error value returns in hdpvr_read
+    - drm/vc4: plane: Remove subpixel positioning check
+    - drm/vc4: plane: Fix margin calculations for the right/bottom edges
+    - drm/vc4: dsi: Correct DSI divider calculations
+    - crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE
+    - drm/rockchip: vop: Don't crash for invalid duplicate_state()
+    - drm/rockchip: Fix an error handling path rockchip_dp_probe()
+    - drm/mediatek: dpi: Remove output format of YUV
+    - drm/mediatek: dpi: Only enable dpi after the bridge is enabled
+    - drm: bridge: sii8620: fix possible off-by-one
+    - drm/msm/mdp5: Fix global state lock backoff
+    - crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq
+    - media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment
+    - mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()
+    - drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.
+    - tcp: make retransmitted SKB fit into the send window
+    - libbpf: Fix the name of a reused map
+    - selftests: timers: valid-adjtimex: build fix for newer toolchains
+    - selftests: timers: clocksource-switch: fix passing errors from child
+    - fs: check FMODE_LSEEK to control internal pipe splicing
+    - wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()
+    - wifi: p54: Fix an error handling path in p54spi_probe()
+    - wifi: p54: add missing parentheses in p54_flush()
+    - selftests/bpf: fix a test for snprintf() overflow
+    - can: pch_can: do not report txerr and rxerr during bus-off
+    - can: rcar_can: do not report txerr and rxerr during bus-off
+    - can: sja1000: do not report txerr and rxerr during bus-off
+    - can: hi311x: do not report txerr and rxerr during bus-off
+    - can: sun4i_can: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_hydra: do not report txerr and rxerr during bus-off
+    - can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off
+    - can: usb_8dev: do not report txerr and rxerr during bus-off
+    - can: error: specify the values of data[5..7] of CAN error frames
+    - can: pch_can: pch_can_error(): initialize errc before using it
+    - Bluetooth: hci_intel: Add check for platform_driver_register
+    - i2c: cadence: Support PEC for SMBus block read
+    - i2c: mux-gpmux: Add of_node_put() when breaking out of loop
+    - wifi: wil6210: debugfs: fix uninitialized variable use in
+      `wil_write_file_wmi()`
+    - wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue
+    - wifi: libertas: Fix possible refcount leak in if_usb_probe()
+    - net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS
+    - crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for of
+    - iavf: Fix max_rate limiting
+    - netdevsim: Avoid allocation warnings triggered from user space
+    - net: rose: fix netdev reference changes
+    - dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock
+    - clk: renesas: r9a06g032: Fix UART clkgrp bitsel
+    - mtd: maps: Fix refcount leak in of_flash_probe_versatile
+    - mtd: maps: Fix refcount leak in ap_flash_init
+    - mtd: rawnand: meson: Fix a potential double free issue
+    - HID: cp2112: prevent a buffer overflow in cp2112_xfer()
+    - mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_release
+    - mtd: partitions: Fix refcount leak in parse_redboot_of
+    - mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path
+    - fpga: altera-pr-ip: fix unsigned comparison with less than zero
+    - usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe
+    - usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe
+    - usb: xhci: tegra: Fix error check
+    - clk: mediatek: reset: Fix written reset bit offset
+    - misc: rtsx: Fix an error handling path in rtsx_pci_probe()
+    - driver core: fix potential deadlock in __driver_attach
+    - clk: qcom: clk-krait: unlock spin after mux completion
+    - usb: host: xhci: use snprintf() in xhci_decode_trb()
+    - clk: qcom: ipq8074: fix NSS port frequency tables
+    - clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocks
+    - clk: qcom: camcc-sdm845: Fix topology around titan_top power domain
+    - soundwire: bus_type: fix remove and shutdown support
+    - intel_th: Fix a resource leak in an error handling path
+    - intel_th: msu-sink: Potential dereference of null pointer
+    - intel_th: msu: Fix vmalloced buffers
+    - staging: rtl8192u: Fix sleep in atomic context bug in
+      dm_fsync_timer_callback
+    - mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch
+    - memstick/ms_block: Fix some incorrect memory allocation
+    - memstick/ms_block: Fix a memory leak
+    - mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R
+    - scsi: smartpqi: Fix DMA direction for RAID requests
+    - usb: gadget: udc: amd5536 depends on HAS_DMA
+    - RDMA/hns: Fix incorrect clearing of interrupt status register
+    - RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event
+    - RDMA/hfi1: fix potential memory leak in setup_base_ctxt()
+    - gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()
+    - mmc: cavium-octeon: Add of_node_put() when breaking out of loop
+    - mmc: cavium-thunderx: Add of_node_put() when breaking out of loop
+    - HID: alps: Declare U1_UNICORN_LEGACY support
+    - PCI: tegra194: Fix Root Port interrupt handling
+    - PCI: tegra194: Fix link up retry sequence
+    - USB: serial: fix tty-port initialized comments
+    - platform/olpc: Fix uninitialized data in debugfs write
+    - mm/mmap.c: fix missing call to vm_unacct_memory in mmap_region
+    - RDMA/rxe: Fix error unwind in rxe_create_qp()
+    - null_blk: fix ida error handling in null_add_dev()
+    - jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()
+    - ext4: recover csum seed of tmp_inode after migrating to extents
+    - jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted
+    - opp: Fix error check in dev_pm_opp_attach_genpd()
+    - ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probe
+    - ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probe
+    - ASoC: codecs: da7210: add check for i2c_add_driver
+    - ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe
+    - serial: 8250_dw: Store LSR into lsr_saved_flags in dw8250_tx_wait_empty()
+    - ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV
+    - ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV
+    - profiling: fix shift too large makes kernel panic
+    - tty: n_gsm: fix non flow control frames during mux flow off
+    - tty: n_gsm: fix packet re-transmission without open control channel
+    - tty: n_gsm: fix race condition in gsmld_write()
+    - remoteproc: qcom: wcnss: Fix handling of IRQs
+    - vfio/ccw: Do not change FSM state in subchannel event
+    - tty: n_gsm: fix wrong T1 retry count handling
+    - tty: n_gsm: fix DM command
+    - tty: n_gsm: fix missing corner cases in gsmld_poll()
+    - iommu/exynos: Handle failed IOMMU device registration properly
+    - rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge
+    - kfifo: fix kfifo_to_user() return type
+    - mfd: t7l66xb: Drop platform disable callback
+    - mfd: max77620: Fix refcount leak in max77620_initialise_fps
+    - iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loop
+    - s390/zcore: fix race when reading from hardware system area
+    - ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()
+    - fuse: Remove the control interface for virtio-fs
+    - ASoC: audio-graph-card: Add of_node_put() in fail path
+    - watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in
+      armada_37xx_wdt_probe()
+    - video: fbdev: amba-clcd: Fix refcount leak bugs
+    - video: fbdev: sis: fix typos in SiS_GetModeID()
+    - powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC32
+    - powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and
+      alias
+    - powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader
+    - powerpc/xive: Fix refcount leak in xive_get_max_prio
+    - powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address
+    - perf symbol: Fail to read phdr workaround
+    - kprobes: Forbid probing on trampoline and BPF code areas
+    - powerpc/pci: Fix PHB numbering when using opal-phbid
+    - genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTO
+    - scripts/faddr2line: Fix vmlinux detection on arm64
+    - x86/numa: Use cpumask_available instead of hardcoded NULL check
+    - video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()
+    - tools/thermal: Fix possible path truncations
+    - video: fbdev: vt8623fb: Check the size of screen before memset_io()
+    - video: fbdev: arkfb: Check the size of screen before memset_io()
+    - video: fbdev: s3fb: Check the size of screen before memset_io()
+    - scsi: zfcp: Fix missing auto port scan and thus missing target ports
+    - scsi: qla2xxx: Fix discovery issues in FC-AL topology
+    - scsi: qla2xxx: Turn off multi-queue for 8G adapters
+    - scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection
+    - x86/olpc: fix 'logical not is only applied to the left hand side'
+    - spmi: trace: fix stack-out-of-bound access in SPMI tracing functions
+    - kexec, KEYS, s390: Make use of built-in and secondary keyring for signature
+      verification
+    - tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH
+    - btrfs: reset block group chunk force if we have to wait
+    - ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h
+    - ext4: make sure ext4_append() always allocates new block
+    - ext4: fix use-after-free in ext4_xattr_set_entry
+    - ext4: update s_overhead_clusters in the superblock during an on-line resize
+    - ext4: fix extent status tree race in writeback error recovery path
+    - ext4: correct max_inline_xattr_value_size computing
+    - ext4: correct the misjudgment in ext4_iget_extra_inode
+    - intel_th: pci: Add Raptor Lake-S CPU support
+    - intel_th: pci: Add Raptor Lake-S PCH support
+    - intel_th: pci: Add Meteor Lake-P support
+    - dm raid: fix address sanitizer warning in raid_resume
+    - dm raid: fix address sanitizer warning in raid_status
+    - dm thin: fix use-after-free crash in dm_sm_register_threshold_callback
+    - dm writecache: set a default MAX_WRITEBACK_JOBS
+    - ACPI: CPPC: Do not prevent CPPC from working in the future
+    - timekeeping: contribute wall clock to rng on time change
+    - firmware: arm_scpi: Ensure scpi_info is not assigned if the probe fails
+    - iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)
+    - btrfs: reject log replay if there is unsupported RO compat flag
+    - KVM: Add infrastructure and macro to mark VM as bugged
+    - KVM: x86: Check lapic_in_kernel() before attempting to set a SynIC irq
+    - KVM: x86: Avoid theoretical NULL pointer dereference in
+      kvm_irq_delivery_to_apic_fast()
+    - tcp: fix over estimation in sk_forced_mem_schedule()
+    - scsi: sg: Allow waiting for commands to complete on removed device
+    - Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regression
+    - net/9p: Initialize the iounit field during fid creation
+    - net_sched: cls_route: disallow handle of 0
+    - ALSA: info: Fix llseek return value when using callback
+    - rds: add missing barrier to release_refill
+    - ata: libata-eh: Add missing command name
+    - mmc: pxamci: Fix another error handling path in pxamci_probe()
+    - mmc: pxamci: Fix an error handling path in pxamci_probe()
+    - btrfs: fix lost error handling when looking up extended ref on log replay
+    - tracing: Have filter accept "common_cpu" to be consistent
+    - can: ems_usb: fix clang's -Wunaligned-access warning
+    - apparmor: fix quiet_denied for file rules
+    - apparmor: fix absroot causing audited secids to begin with =
+    - apparmor: Fix failed mount permission check error message
+    - apparmor: fix aa_label_asxprint return check
+    - apparmor: fix overlapping attachment computation
+    - apparmor: fix reference count leak in aa_pivotroot()
+    - apparmor: Fix memleak in aa_simple_write_to_buffer()
+    - Documentation: ACPI: EINJ: Fix obsolete example
+    - NFSv4.1: Don't decrease the value of seq_nr_highest_sent
+    - NFSv4.1: Handle NFS4ERR_DELAY replies to OP_SEQUENCE correctly
+    - NFSv4: Fix races in the legacy idmapper upcall
+    - NFSv4.1: RECLAIM_COMPLETE must handle EACCES
+    - NFSv4/pnfs: Fix a use-after-free bug in open
+    - can: mcp251x: Fix race condition on receive interrupt
+    - sunrpc: fix expiry of auth creds
+    - SUNRPC: Reinitialise the backchannel request buffers before reuse
+    - devlink: Fix use-after-free after a failed reload
+    - net: bgmac: Fix a BUG triggered by wrong bytes_compl
+    - pinctrl: nomadik: Fix refcount leak in nmk_pinctrl_dt_subnode_to_map
+    - pinctrl: qcom: msm8916: Allow CAMSS GP clocks to be muxed
+    - pinctrl: sunxi: Add I/O bias setting for H6 R-PIO
+    - ACPI: property: Return type of acpi_add_nondev_subnodes() should be bool
+    - geneve: do not use RT_TOS for IPv6 flowlabel
+    - plip: avoid rcu debug splat
+    - vsock: Fix memory leak in vsock_connect()
+    - vsock: Set socket state back to SS_UNCONNECTED in vsock_connect_timeout()
+    - dt-bindings: arm: qcom: fix MSM8916 MTP compatibles
+    - tools/vm/slabinfo: use alphabetic order when two values are equal
+    - tools build: Switch to new openssl API for test-libcrypto
+    - NTB: ntb_tool: uninitialized heap data in tool_fn_write()
+    - nfp: ethtool: fix the display error of `ethtool -m DEVNAME`
+    - xen/xenbus: fix return type in xenbus_file_read()
+    - atm: idt77252: fix use-after-free bugs caused by tst_timer
+    - dpaa2-eth: trace the allocated address instead of page struct
+    - tee: add overflow check in register_shm_helper()
+    - nios2: page fault et.al. are *not* restartable syscalls...
+    - nios2: don't leave NULLs in sys_call_table[]
+    - nios2: traced syscall does need to check the syscall number
+    - nios2: fix syscall restart checks
+    - nios2: restarts apply only to the first sigframe we build...
+    - nios2: add force_successful_syscall_return()
+    - iavf: Fix adminq error handling
+    - clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks
+    - netfilter: nf_tables: really skip inactive sets when allocating name
+    - powerpc/pci: Fix get_phb_number() locking
+    - net: dsa: mv88e6060: prevent crash on an unused port
+    - net: moxa: pass pdev instead of ndev to DMA functions
+    - net: dsa: microchip: ksz9477: fix fdb_dump last invalid entry
+    - ice: Ignore EEXIST when setting promisc mode
+    - i40e: Fix to stop tx_timeout recovery if GLOBR fails
+    - fec: Fix timer capture timing in `fec_ptp_enable_pps()`
+    - igb: Add lock to avoid data race
+    - gcc-plugins: Undefine LATENT_ENTROPY_PLUGIN when plugin disabled for a file
+    - locking/atomic: Make test_and_*_bit() ordered on failure
+    - drm/meson: Fix refcount bugs in meson_vpu_has_available_connectors()
+    - PCI: Add ACS quirk for Broadcom BCM5750x NICs
+    - usb: cdns3 fix use-after-free at workaround 2
+    - usb: gadget: uvc: call uvc uvcg_warn on completed status instead of
+      uvcg_info
+    - irqchip/tegra: Fix overflow implicit truncation warnings
+    - drm/meson: Fix overflow implicit truncation warnings
+    - usb: host: ohci-ppc-of: Fix refcount leak bug
+    - usb: renesas: Fix refcount leak bug
+    - vboxguest: Do not use devm for irq
+    - clk: qcom: ipq8074: dont disable gcc_sleep_clk_src
+    - scsi: lpfc: Prevent buffer overflow crashes in debugfs with malformed user
+      input
+    - gadgetfs: ep_io - wait until IRQ finishes
+    - cxl: Fix a memory leak in an error handling path
+    - PCI/ACPI: Guard ARM64-specific mcfg_quirks
+    - um: add "noreboot" command line option for PANIC_TIMEOUT=-1 setups
+    - selftests/kprobe: Do not test for GRP/ without event failures
+    - dmaengine: sprd: Cleanup in .remove() after pm_runtime_get_sync() failed
+    - nvmet-tcp: fix lockdep complaint on nvmet_tcp_wq flush during queue teardown
+    - drivers:md:fix a potential use-after-free bug
+    - ext4: avoid remove directory when directory is corrupted
+    - ext4: avoid resizing to a partial cluster size
+    - lib/list_debug.c: Detect uninitialized lists
+    - tty: serial: Fix refcount leak bug in ucc_uart.c
+    - vfio: Clear the caps->buf to NULL after free
+    - mips: cavium-octeon: Fix missing of_node_put() in octeon2_usb_clocks_start
+    - riscv: mmap with PROT_WRITE but no PROT_READ is invalid
+    - RISC-V: Add fast call path of crash_kexec()
+    - watchdog: export lockup_detector_reconfigure
+    - powerpc/32: Don't always pass -mcpu=powerpc to the compiler
+    - ALSA: core: Add async signal helpers
+    - ALSA: timer: Use deferred fasync helper
+    - f2fs: fix to avoid use f2fs_bug_on() in f2fs_new_node_page()
+    - smb3: check xattr value length earlier
+    - powerpc/64: Init jump labels before parse_early_param()
+    - video: fbdev: i740fb: Check the argument of i740_calc_vclk()
+    - MIPS: tlbex: Explicitly compare _PAGE_NO_EXEC against 0
+    - tracing/probes: Have kprobes and uprobes use $COMM too
+    - can: j1939: j1939_sk_queue_activate_next_locked(): replace WARN_ON_ONCE with
+      netdev_warn_once()
+    - can: j1939: j1939_session_destroy(): fix memory leak of skbs
+    - btrfs: only write the sectors in the vertical stripe which has data stripes
+    - btrfs: raid56: don't trust any cached sector in __raid56_parity_recover()
+    - Linux 5.4.211
+  * CVE-2022-3028
+    - af_key: Do not call xfrm_probe_algs in parallel
+  * CVE-2022-2978
+    - fs: fix UAF/GPF bug in nilfs_mdt_destroy
+  * CVE-2022-40768
+    - scsi: stex: Properly zero out the passthrough command structure
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 05 Dec 2022 19:40:05 +0800
+
+linux-ein (5.4.0-1028.34) focal; urgency=medium
+
+  * Dummy entry.
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 05 Dec 2022 14:25:56 +0800
+
+linux-imx (5.4.0-1028.34) focal; urgency=medium
+
+  * Focal update: v5.4.208 upstream stable release (LP: #1988225)
+    - [Config] updateconfigs for IMA_TEMPLATE
+    - [Config] updateconfigs for REFCOUNT_FULL
+
+  * [K4500-NXP][UC20] Integrate graphics driver needed for running QT
+    application (LP: #1990021)
+    - SAUCE: drm: AVD101WX-CN: Assigned bus format to fix warning:
+    - Revert "UBUNTU: SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove gpu node now at
+      the imx8mm.dtsi contains gpu nodes."
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove the 2d/3d GPU nodes that enable
+      the etnaviv driver.
+
+  * M4-RPMSG driver race condition (LP: #1991153)
+    - SAUCE: rpmsg: Fix race condition
+    - SAUCE: rpmsg: Use static prefix for globals
+    - SAUCE: rpmsg: Code clean-up
+
+  * [imx8-pdk] Fail to run perf (LP: #1987467)
+    - tools: perf: metricgroup: add metricgroup for each PMU
+    - perf vendor events: add JSON metrics for imx8 DDR Perf
+    - MLK-23195-4 tool: perf: imx8mp-ddr: correct the master ID
+    - MLK-23302-1 tools: perf: pmu-event: add socname for struct pmu_event
+    - MLK-23302-2 tools: perf: header: add support for checking socname
+    - MLK-23302-3 tools: perf: metricgroup: match metric with socname if needed
+    - MLK-23302-4 tools: perf: pmu-events: add SocName in DDR JSON file
+    - MLK-23724-1 tools: perf: fix metricgroup add metric events multiple times
+    - perf stat: Improve runtime stat for interval mode
+    - MLK-24053-2 perf vendor events: add ddr bandwidth usage metric for i.MX8MP
+    - perf/imx_ddr: Add driver for DDR PMU in i.MX8MPlus
+    - perf/imx_ddr: Dump AXI ID filter info to userspace
+    - perf/imx_ddr: Add stop event counters support for i.MX8MP
+    - MLK-23195-3 perf/imx_ddr: speed up overflow frequency of cycle counter
+    - bindings: perf: imx-ddr: Add new compatible string
+    - MLK-23417-1 perf/imx_ddr: Add AXI ID PORT CHANNEL filter support
+    - MLK-23417-3 perf/imx_ddr: Add driver support for i.MX8DXL DDR Perf
+    - MLK-23418-1 perf/imx_ddr: Extend driver for PMU in DRAM Block(DB)
+    - MLK-23418-3 perf/imx_ddr: Add clock support for Perf in DB
+    - MLK-23418-4 perf/imx_ddr: Add driver support for i.MX8DXL DB Perf
+
+  [ Ubuntu: 5.4.0-131.147 ]
+
+  * CVE-2022-2602
+    - SAUCE: io_uring/af_unix: defer registered files gc to io_uring release
+    - SAUCE: io_uring/af_unix: fix memleak during unix GC
+  * CVE-2022-41674
+    - SAUCE: wifi: cfg80211: fix u8 overflow in
+      cfg80211_update_notlisted_nontrans()
+    - SAUCE: wifi: cfg80211/mac80211: reject bad MBSSID elements
+    - SAUCE: wifi: cfg80211: ensure length byte is present before access
+    - SAUCE: wifi: mac80211_hwsim: avoid mac80211 warning on bad rate
+    - SAUCE: wifi: cfg80211: update hidden BSSes to avoid WARN_ON
+  * CVE-2022-42721
+    - SAUCE: wifi: cfg80211: avoid nontransmitted BSS list corruption
+  * CVE-2022-42720
+    - SAUCE: wifi: cfg80211: fix BSS refcounting bugs
+
+  [ Ubuntu: 5.4.0-128.144 ]
+
+  * focal/linux: 5.4.0-128.144 -proposed tracker (LP: #1990152)
+  * CVE-2022-3176
+    - io_uring: disable polling pollfree files
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809)
+    - selftests/net: test nexthop without gw
+  * ip/nexthop: fix default address selection for connected nexthop
+    (LP: #1988809) // icmp_redirect.sh in ubuntu_kernel_selftests failed on
+    Jammy 5.15.0-49.55 (LP: #1990124)
+    - ip: fix triggering of 'icmp redirect'
+
+  [ Ubuntu: 5.4.0-127.143 ]
+
+  * focal/linux: 5.4.0-127.143 -proposed tracker (LP: #1989892)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.09.19)
+  * [UBUNTU 20.04] mlx5 driver crashes on accessing device attributes during
+    recovery (LP: #1987287)
+    - net/mlx5: Avoid processing commands before cmdif is ready
+  * Focal update: v5.4.210 upstream stable release (LP: #1989230)
+    - thermal: Fix NULL pointer dereferences in of_thermal_ functions
+    - ACPI: video: Force backlight native for some TongFang devices
+    - ACPI: video: Shortening quirk list by identifying Clevo by board_name only
+    - ACPI: APEI: Better fix to avoid spamming the console with old error logs
+    - bpf: Verifer, adjust_scalar_min_max_vals to always call update_reg_bounds()
+    - selftests/bpf: Extend verifier and bpf_sock tests for dst_port loads
+    - bpf: Test_verifier, #70 error message updates for 32-bit right shift
+    - KVM: Don't null dereference ops->destroy
+    - selftests: KVM: Handle compiler optimizations in ucall
+    - media: v4l2-mem2mem: Apply DST_QUEUE_OFF_BASE on MMAP buffers across ioctls
+    - macintosh/adb: fix oob read in do_adb_query() function
+    - x86/speculation: Add RSB VM Exit protections
+    - x86/speculation: Add LFENCE to RSB fill sequence
+    - Linux 5.4.210
+  * Focal update: v5.4.209 upstream stable release (LP: #1989228)
+    - Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
+    - ntfs: fix use-after-free in ntfs_ucsncmp()
+    - s390/archrandom: prevent CPACF trng invocations in interrupt context
+    - tcp: Fix data-races around sysctl_tcp_dsack.
+    - tcp: Fix a data-race around sysctl_tcp_app_win.
+    - tcp: Fix a data-race around sysctl_tcp_adv_win_scale.
+    - tcp: Fix a data-race around sysctl_tcp_frto.
+    - tcp: Fix a data-race around sysctl_tcp_nometrics_save.
+    - ice: check (DD | EOF) bits on Rx descriptor rather than (EOP | RS)
+    - ice: do not setup vlan for loopback VSI
+    - scsi: ufs: host: Hold reference returned by of_parse_phandle()
+    - tcp: Fix a data-race around sysctl_tcp_limit_output_bytes.
+    - tcp: Fix a data-race around sysctl_tcp_challenge_ack_limit.
+    - net: ping6: Fix memleak in ipv6_renew_options().
+    - ipv6/addrconf: fix a null-ptr-deref bug for ip6_ptr
+    - igmp: Fix data-races around sysctl_igmp_qrv.
+    - net: sungem_phy: Add of_node_put() for reference returned by of_get_parent()
+    - tcp: Fix a data-race around sysctl_tcp_min_tso_segs.
+    - tcp: Fix a data-race around sysctl_tcp_min_rtt_wlen.
+    - tcp: Fix a data-race around sysctl_tcp_autocorking.
+    - tcp: Fix a data-race around sysctl_tcp_invalid_ratelimit.
+    - Documentation: fix sctp_wmem in ip-sysctl.rst
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_delay_ns.
+    - tcp: Fix a data-race around sysctl_tcp_comp_sack_nr.
+    - i40e: Fix interface init with MSI interrupts (no MSI-X)
+    - sctp: fix sleep in atomic context bug in timer handlers
+    - virtio-net: fix the race between refill work and close
+    - perf symbol: Correct address for bss symbols
+    - sfc: disable softirqs for ptp TX
+    - sctp: leave the err path free in sctp_stream_init to sctp_stream_free
+    - ARM: crypto: comment out gcc warning that breaks clang builds
+    - mt7601u: add USB device ID for some versions of XiaoDu WiFi Dongle.
+    - scsi: core: Fix race between handling STS_RESOURCE and completion
+    - Linux 5.4.209
+  * Focal update: v5.4.208 upstream stable release (LP: #1988225)
+    - pinctrl: stm32: fix optional IRQ support to gpios
+    - riscv: add as-options for modules with assembly compontents
+    - mlxsw: spectrum_router: Fix IPv4 nexthop gateway indication
+    - lockdown: Fix kexec lockdown bypass with ima policy
+    - xen/gntdev: Ignore failure to unmap INVALID_GRANT_HANDLE
+    - PCI: hv: Fix multi-MSI to allow more than one MSI vector
+    - PCI: hv: Fix hv_arch_irq_unmask() for multi-MSI
+    - PCI: hv: Reuse existing IRTE allocation in compose_msi_msg()
+    - PCI: hv: Fix interrupt mapping for multi-MSI
+    - serial: mvebu-uart: correctly report configured baudrate value
+    - xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in
+      xfrm_bundle_lookup()
+    - power/reset: arm-versatile: Fix refcount leak in versatile_reboot_probe
+    - pinctrl: ralink: Check for null return of devm_kcalloc
+    - perf/core: Fix data race between perf_event_set_output() and
+      perf_mmap_close()
+    - igc: Reinstate IGC_REMOVED logic and implement it properly
+    - ip: Fix data-races around sysctl_ip_no_pmtu_disc.
+    - ip: Fix data-races around sysctl_ip_fwd_use_pmtu.
+    - ip: Fix data-races around sysctl_ip_nonlocal_bind.
+    - ip: Fix a data-race around sysctl_fwmark_reflect.
+    - tcp/dccp: Fix a data-race around sysctl_tcp_fwmark_accept.
+    - tcp: Fix data-races around sysctl_tcp_mtu_probing.
+    - tcp: Fix data-races around sysctl_tcp_base_mss.
+    - tcp: Fix data-races around sysctl_tcp_min_snd_mss.
+    - tcp: Fix a data-race around sysctl_tcp_mtu_probe_floor.
+    - tcp: Fix a data-race around sysctl_tcp_probe_threshold.
+    - tcp: Fix a data-race around sysctl_tcp_probe_interval.
+    - i2c: cadence: Change large transfer count reset logic to be unconditional
+    - net: stmmac: fix dma queue left shift overflow issue
+    - net/tls: Fix race in TLS device down flow
+    - igmp: Fix data-races around sysctl_igmp_llm_reports.
+    - igmp: Fix a data-race around sysctl_igmp_max_memberships.
+    - tcp: Fix data-races around sysctl_tcp_syncookies.
+    - tcp: Fix data-races around sysctl_tcp_reordering.
+    - tcp: Fix data-races around some timeout sysctl knobs.
+    - tcp: Fix a data-race around sysctl_tcp_notsent_lowat.
+    - tcp: Fix a data-race around sysctl_tcp_tw_reuse.
+    - tcp: Fix data-races around sysctl_max_syn_backlog.
+    - tcp: Fix data-races around sysctl_tcp_fastopen.
+    - iavf: Fix handling of dummy receive descriptors
+    - i40e: Fix erroneous adapter reinitialization during recovery process
+    - ixgbe: Add locking to prevent panic when setting sriov_numvfs to zero
+    - gpio: pca953x: only use single read/write for No AI mode
+    - be2net: Fix buffer overflow in be_get_module_eeprom
+    - ipv4: Fix a data-race around sysctl_fib_multipath_use_neigh.
+    - udp: Fix a data-race around sysctl_udp_l3mdev_accept.
+    - tcp: Fix data-races around sysctl knobs related to SYN option.
+    - tcp: Fix a data-race around sysctl_tcp_early_retrans.
+    - tcp: Fix data-races around sysctl_tcp_recovery.
+    - tcp: Fix a data-race around sysctl_tcp_thin_linear_timeouts.
+    - tcp: Fix data-races around sysctl_tcp_slow_start_after_idle.
+    - tcp: Fix a data-race around sysctl_tcp_retrans_collapse.
+    - tcp: Fix a data-race around sysctl_tcp_stdurg.
+    - tcp: Fix a data-race around sysctl_tcp_rfc1337.
+    - tcp: Fix data-races around sysctl_tcp_max_reordering.
+    - spi: bcm2835: bcm2835_spi_handle_err(): fix NULL pointer deref for non DMA
+      transfers
+    - mm/mempolicy: fix uninit-value in mpol_rebind_policy()
+    - bpf: Make sure mac_header was set before using it
+    - dlm: fix pending remove if msg allocation fails
+    - ima: remove the IMA_TEMPLATE Kconfig option
+    - [Config] updateconfigs for IMA_TEMPLATE
+    - locking/refcount: Define constants for saturation and max refcount values
+    - locking/refcount: Ensure integer operands are treated as signed
+    - locking/refcount: Remove unused refcount_*_checked() variants
+    - locking/refcount: Move the bulk of the REFCOUNT_FULL implementation into the
+      <linux/refcount.h> header
+    - locking/refcount: Improve performance of generic REFCOUNT_FULL code
+    - locking/refcount: Move saturation warnings out of line
+    - locking/refcount: Consolidate REFCOUNT_{MAX,SATURATED} definitions
+    - locking/refcount: Consolidate implementations of refcount_t
+    - [Config] updateconfigs for REFCOUNT_FULL
+    - x86: get rid of small constant size cases in raw_copy_{to,from}_user()
+    - x86/uaccess: Implement macros for CMPXCHG on user addresses
+    - mmap locking API: initial implementation as rwsem wrappers
+    - x86/mce: Deduplicate exception handling
+    - bitfield.h: Fix "type of reg too small for mask" test
+    - ALSA: memalloc: Align buffer allocations in page size
+    - Bluetooth: Add bt_skb_sendmsg helper
+    - Bluetooth: Add bt_skb_sendmmsg helper
+    - Bluetooth: SCO: Replace use of memcpy_from_msg with bt_skb_sendmsg
+    - Bluetooth: RFCOMM: Replace use of memcpy_from_msg with bt_skb_sendmmsg
+    - Bluetooth: Fix passing NULL to PTR_ERR
+    - Bluetooth: SCO: Fix sco_send_frame returning skb->len
+    - Bluetooth: Fix bt_skb_sendmmsg not allocating partial chunks
+    - tty: drivers/tty/, stop using tty_schedule_flip()
+    - tty: the rest, stop using tty_schedule_flip()
+    - tty: drop tty_schedule_flip()
+    - tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
+    - tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
+    - x86: drop bogus "cc" clobber from __try_cmpxchg_user_asm()
+    - Linux 5.4.208
+  * Focal update: v5.4.207 upstream stable release (LP: #1988219)
+    - ALSA: hda - Add fixup for Dell Latitidue E5430
+    - ALSA: hda/conexant: Apply quirk for another HP ProDesk 600 G3 model
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc221
+    - ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop
+    - xen/netback: avoid entering xenvif_rx_next_skb() with an empty rx queue
+    - tracing/histograms: Fix memory leak problem
+    - net: sock: tracing: Fix sock_exceed_buf_limit not to dereference stale
+      pointer
+    - ip: fix dflt addr selection for connected nexthop
+    - ARM: 9213/1: Print message about disabled Spectre workarounds only once
+    - ARM: 9214/1: alignment: advance IT state after emulating Thumb instruction
+    - wifi: mac80211: fix queue selection for mesh/OCB interfaces
+    - cgroup: Use separate src/dst nodes when preloading css_sets for migration
+    - drm/panfrost: Fix shrinker list corruption by madvise IOCTL
+    - nilfs2: fix incorrect masking of permission flags for symlinks
+    - Revert "evm: Fix memleak in init_desc"
+    - sched/rt: Disable RT_RUNTIME_SHARE by default
+    - ext4: fix race condition between ext4_write and ext4_convert_inline_data
+    - ARM: dts: imx6qdl-ts7970: Fix ngpio typo and count
+    - ARM: 9209/1: Spectre-BHB: avoid pr_info() every time a CPU comes out of idle
+    - ARM: 9210/1: Mark the FDT_FIXED sections as shareable
+    - drm/i915: fix a possible refcount leak in intel_dp_add_mst_connector()
+    - ima: Fix a potential integer overflow in ima_appraise_measurement
+    - ASoC: sgtl5000: Fix noise on shutdown/remove
+    - net: stmmac: dwc-qos: Disable split header for Tegra194
+    - inetpeer: Fix data-races around sysctl.
+    - net: Fix data-races around sysctl_mem.
+    - cipso: Fix data-races around sysctl.
+    - icmp: Fix data-races around sysctl.
+    - ipv4: Fix a data-race around sysctl_fib_sync_mem.
+    - ARM: dts: at91: sama5d2: Fix typo in i2s1 node
+    - ARM: dts: sunxi: Fix SPI NOR campatible on Orange Pi Zero
+    - drm/i915/gt: Serialize TLB invalidates with GT resets
+    - icmp: Fix a data-race around sysctl_icmp_ratelimit.
+    - icmp: Fix a data-race around sysctl_icmp_ratemask.
+    - raw: Fix a data-race around sysctl_raw_l3mdev_accept.
+    - ipv4: Fix data-races around sysctl_ip_dynaddr.
+    - net: ftgmac100: Hold reference returned by of_get_child_by_name()
+    - sfc: fix use after free when disabling sriov
+    - seg6: fix skb checksum evaluation in SRH encapsulation/insertion
+    - seg6: fix skb checksum in SRv6 End.B6 and End.B6.Encaps behaviors
+    - seg6: bpf: fix skb checksum in bpf_push_seg6_encap()
+    - sfc: fix kernel panic when creating VF
+    - mm: sysctl: fix missing numa_stat when !CONFIG_HUGETLB_PAGE
+    - virtio_mmio: Add missing PM calls to freeze/restore
+    - virtio_mmio: Restore guest page size on resume
+    - netfilter: br_netfilter: do not skip all hooks with 0 priority
+    - cpufreq: pmac32-cpufreq: Fix refcount leak bug
+    - platform/x86: hp-wmi: Ignore Sanitization Mode event
+    - net: tipc: fix possible refcount leak in tipc_sk_create()
+    - NFC: nxp-nci: don't print header length mismatch on i2c error
+    - nvme: fix regression when disconnect a recovering ctrl
+    - net: sfp: fix memory leak in sfp_probe()
+    - ASoC: ops: Fix off by one in range control validation
+    - ASoC: wm5110: Fix DRE control
+    - ASoC: cs47l15: Fix event generation for low power mux control
+    - ASoC: madera: Fix event generation for OUT1 demux
+    - ASoC: madera: Fix event generation for rate controls
+    - irqchip: or1k-pic: Undefine mask_ack for level triggered hardware
+    - x86: Clear .brk area at early boot
+    - soc: ixp4xx/npe: Fix unused match warning
+    - ARM: dts: stm32: use the correct clock source for CEC on stm32mp151
+    - signal handling: don't use BUG_ON() for debugging
+    - USB: serial: ftdi_sio: add Belimo device ids
+    - usb: typec: add missing uevent when partner support PD
+    - usb: dwc3: gadget: Fix event pending check
+    - tty: serial: samsung_tty: set dma burst_size to 1
+    - serial: 8250: fix return error code in serial8250_request_std_resource()
+    - serial: stm32: Clear prev values before setting RTS delays
+    - serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle
+    - can: m_can: m_can_tx_handler(): fix use after free of skb
+    - Linux 5.4.207
+  * Focal update: v5.4.206 upstream stable release (LP: #1988215)
+    - Linux 5.4.206
+  * Focal update: v5.4.205 upstream stable release (LP: #1988214)
+    - esp: limit skb_page_frag_refill use to a single page
+    - mm/slub: add missing TID updates on slab deactivation
+    - can: bcm: use call_rcu() instead of costly synchronize_rcu()
+    - can: grcan: grcan_probe(): remove extra of_node_get()
+    - can: gs_usb: gs_usb_open/close(): fix memory leak
+    - usbnet: fix memory leak in error case
+    - net: rose: fix UAF bug caused by rose_t0timer_expiry
+    - iommu/vt-d: Fix PCI bus rescan device hot add
+    - fbdev: fbmem: Fix logo center image dx issue
+    - video: of_display_timing.h: include errno.h
+    - powerpc/powernv: delay rng platform device creation until later in boot
+    - can: kvaser_usb: replace run-time checks with struct kvaser_usb_driver_info
+    - can: kvaser_usb: kvaser_usb_leaf: fix CAN clock frequency regression
+    - can: kvaser_usb: kvaser_usb_leaf: fix bittiming limits
+    - xfs: remove incorrect ASSERT in xfs_rename
+    - ARM: meson: Fix refcount leak in meson_smp_prepare_cpus
+    - pinctrl: sunxi: a83t: Fix NAND function name for some pins
+    - pinctrl: sunxi: sunxi_pconf_set: use correct offset
+    - ARM: at91: pm: use proper compatible for sama5d2's rtc
+    - ARM: at91: pm: use proper compatibles for sam9x60's rtc and rtt
+    - ibmvnic: Properly dispose of all skbs during a failover.
+    - selftests: forwarding: fix flood_unicast_test when h2 supports
+      IFF_UNICAST_FLT
+    - selftests: forwarding: fix learning_test when h1 supports IFF_UNICAST_FLT
+    - selftests: forwarding: fix error message in learning_test
+    - i2c: cadence: Unregister the clk notifier in error path
+    - dmaengine: imx-sdma: Allow imx8m for imx7 FW revs
+    - misc: rtsx_usb: fix use of dma mapped buffer for usb bulk transfer
+    - misc: rtsx_usb: use separate command and response buffers
+    - misc: rtsx_usb: set return value in rsp_buf alloc err path
+    - dt-bindings: dma: allwinner,sun50i-a64-dma: Fix min/max typo
+    - ida: don't use BUG_ON() for debugging
+    - dmaengine: pl330: Fix lockdep warning about non-static key
+    - dmaengine: at_xdma: handle errors of at_xdmac_alloc_desc() correctly
+    - dmaengine: ti: Fix refcount leak in ti_dra7_xbar_route_allocate
+    - dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate
+    - Linux 5.4.205
+  * Focal update: v5.4.204 upstream stable release (LP: #1988212)
+    - ipv6: take care of disable_policy when restoring routes
+    - nvdimm: Fix badblocks clear off-by-one error
+    - powerpc/prom_init: Fix kernel config grep
+    - powerpc/bpf: Fix use of user_pt_regs in uapi
+    - dm raid: fix accesses beyond end of raid member array
+    - dm raid: fix KASAN warning in raid5_add_disks
+    - s390/archrandom: simplify back to earlier design and initialize earlier
+    - SUNRPC: Fix READ_PLUS crasher
+    - net: rose: fix UAF bugs caused by timer handler
+    - net: usb: ax88179_178a: Fix packet receiving
+    - virtio-net: fix race between ndo_open() and virtio_device_ready()
+    - selftests/net: pass ipv6_args to udpgso_bench's IPv6 TCP test
+    - net: tun: unlink NAPI from device on destruction
+    - net: tun: stop NAPI when detaching queues
+    - RDMA/qedr: Fix reporting QP timeout attribute
+    - linux/dim: Fix divide by 0 in RDMA DIM
+    - usbnet: fix memory allocation in helpers
+    - net: ipv6: unexport __init-annotated seg6_hmac_net_init()
+    - caif_virtio: fix race between virtio_device_ready() and ndo_open()
+    - PM / devfreq: exynos-ppmu: Fix refcount leak in of_get_devfreq_events
+    - s390: remove unneeded 'select BUILD_BIN2C'
+    - netfilter: nft_dynset: restore set element counter when failing to update
+    - net/sched: act_api: Notify user space if any actions were flushed before
+      error
+    - net: bonding: fix possible NULL deref in rlb code
+    - net: bonding: fix use-after-free after 802.3ad slave unbind
+    - nfc: nfcmrvl: Fix irq_of_parse_and_map() return value
+    - NFC: nxp-nci: Don't issue a zero length i2c_master_read()
+    - net: tun: avoid disabling NAPI twice
+    - xen/gntdev: Avoid blocking in unmap_grant_pages()
+    - hwmon: (ibmaem) don't call platform_device_del() if platform_device_add()
+      fails
+    - net: dsa: bcm_sf2: force pause link settings
+    - sit: use min
+    - ipv6/sit: fix ipip6_tunnel_get_prl return value
+    - rseq/selftests,x86_64: Add rseq_offset_deref_addv()
+    - selftests/rseq: remove ARRAY_SIZE define from individual tests
+    - selftests/rseq: introduce own copy of rseq uapi header
+    - selftests/rseq: Remove useless assignment to cpu variable
+    - selftests/rseq: Remove volatile from __rseq_abi
+    - selftests/rseq: Introduce rseq_get_abi() helper
+    - selftests/rseq: Introduce thread pointer getters
+    - selftests/rseq: Uplift rseq selftests for compatibility with glibc-2.35
+    - selftests/rseq: Fix ppc32: wrong rseq_cs 32-bit field pointer on big endian
+    - selftests/rseq: Fix ppc32 missing instruction selection "u" and "x" for
+      load/store
+    - selftests/rseq: Fix ppc32 offsets by using long rather than off_t
+    - selftests/rseq: Fix warnings about #if checks of undefined tokens
+    - selftests/rseq: Remove arm/mips asm goto compiler work-around
+    - selftests/rseq: Fix: work-around asm goto compiler bugs
+    - selftests/rseq: x86-64: use %fs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: x86-32: use %gs segment selector for accessing rseq thread
+      area
+    - selftests/rseq: Change type of rseq_offset to ptrdiff_t
+    - xen/blkfront: fix leaking data in shared pages
+    - xen/netfront: fix leaking data in shared pages
+    - xen/netfront: force data bouncing when backend is untrusted
+    - xen/blkfront: force data bouncing when backend is untrusted
+    - xen/arm: Fix race in RB-tree based P2M accounting
+    - net: usb: qmi_wwan: add Telit 0x1060 composition
+    - net: usb: qmi_wwan: add Telit 0x1070 composition
+    - clocksource/drivers/ixp4xx: remove EXPORT_SYMBOL_GPL from
+      ixp4xx_timer_setup()
+    - Linux 5.4.204
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 09 Nov 2022 19:19:19 +0800
+
+linux-imx (5.4.0-1027.33) focal; urgency=medium
+
+  * [K4500-NXP] Update the device tree to load Vivante graphics drivers (LP:
+    #1990021)
+    - arm64: dts: imx8mm: Add GPU nodes for 2D and 3D core
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Remove gpu node now at the imx8mm.dtsi
+      contains gpu nodes.
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 03 Oct 2022 18:15:38 +0800
+
+linux-imx (5.4.0-1026.32) focal; urgency=medium
+
+  * Focal update: v5.4.198 upstream stable release (LP: #1982409)
+    - PCI: imx6: Fix PERST# start-up sequence
+
+  * [US20.04[UC20] RPMSG driver support (LP: #1968362)
+    - SAUCE: ARM: imx: Add M4 rpmsg module that allows applications to send and
+      request data to and from the M4.
+    - [Config] Set CONFIG_RPMSG_AMGIS_M4_DEVICES=m for armhf
+
+  * [K4500-NXP][UC20] Snap for testing HSM chip (LP: #1984131)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Swap i2c-1 and i2c-2 buses for STSAFE
+      TPM compatibility with RPI platform.
+
+  * [K4500-NXP] Set GPIO defaults for WIFI_ENABLE and CELL_MODEM_RESET (LP:
+    #1990059)
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Set GPIO defaults for WIFI_ENABLE and
+      CELL_MODEM_RESET
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Delete user_gpio and tmp103 nodes to
+      disable kernel boot warnings
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Device tree cleanup and correction of
+      CMA size.
+
+  * Miscellaneous upstream changes
+    - LF-1235 clk: imx: Revert the changes for pll pfd gate clock
+
+  [ Ubuntu: 5.4.0-126.142 ]
+
+  * focal/linux: 5.4.0-126.142 -proposed tracker (LP: #1987819)
+  * [SRU] fnic driver on needs to be updated to 1.6.0.53 on Focal (LP: #1984011)
+    - scsi: fnic: Change shost_printk() to FNIC_FCS_DBG()
+    - scsi: fnic: Avoid looping in TRANS ETH on unload
+    - scsi: fnic: Change shost_printk() to FNIC_MAIN_DBG()
+    - scsi: fnic: Set scsi_set_resid() only for underflow
+    - scsi: fnic: Validate io_req before others
+  * Focal update: v5.4.203 upstream stable release (LP: #1986999)
+    - drm: remove drm_fb_helper_modinit
+    - powerpc/ftrace: Remove ftrace init tramp once kernel init is complete
+    - kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add]
+    - net: mscc: ocelot: allow unregistered IP multicast flooding
+    - ARM: 8989/1: use .fpu assembler directives instead of assembler arguments
+    - ARM: 8990/1: use VFP assembler mnemonics in register load/store macros
+    - ARM: 8971/1: replace the sole use of a symbol with its definition
+    - crypto: arm/sha256-neon - avoid ADRL pseudo instruction
+    - crypto: arm/sha512-neon - avoid ADRL pseudo instruction
+    - ARM: 8933/1: replace Sun/Solaris style flag on section directive
+    - ARM: 8929/1: use APSR_nzcv instead of r15 as mrc operand
+    - ARM: OMAP2+: drop unnecessary adrl
+    - ARM: 9029/1: Make iwmmxt.S support Clang's integrated assembler
+    - crypto: arm - use Kconfig based compiler checks for crypto opcodes
+    - crypto: arm/ghash-ce - define fpu before fpu registers are referenced
+    - Linux 5.4.203
+  * Focal update: v5.4.202 upstream stable release (LP: #1986995)
+    - random: schedule mix_interrupt_randomness() less often
+    - ALSA: hda/via: Fix missing beep setup
+    - ALSA: hda/conexant: Fix missing beep setup
+    - ALSA: hda/realtek - ALC897 headset MIC no sound
+    - ALSA: hda/realtek: Add quirk for Clevo PD70PNT
+    - net: openvswitch: fix parsing of nw_proto for IPv6 fragments
+    - mmc: sdhci-pci-o2micro: Fix card detect by dealing with debouncing
+    - ata: libata: add qc->flags in ata_qc_complete_template tracepoint
+    - dm era: commit metadata in postsuspend after worker stops
+    - dm mirror log: clear log bits up to BITS_PER_LONG boundary
+    - random: quiet urandom warning ratelimit suppression message
+    - USB: serial: option: add Telit LE910Cx 0x1250 composition
+    - USB: serial: option: add Quectel EM05-G modem
+    - USB: serial: option: add Quectel RM500K module support
+    - bpf: Fix request_sock leak in sk lookup helpers
+    - phy: aquantia: Fix AN when higher speeds than 1G are not advertised
+    - bonding: ARP monitor spams NETDEV_NOTIFY_PEERS notifiers
+    - net/sched: sch_netem: Fix arithmetic in netem_dump() for 32-bit platforms
+    - drm/msm/mdp4: Fix refcount leak in mdp4_modeset_init_intf
+    - erspan: do not assume transport header is always set
+    - net/tls: fix tls_sk_proto_close executed repeatedly
+    - udmabuf: add back sanity check
+    - x86/xen: Remove undefined behavior in setup_features()
+    - MIPS: Remove repetitive increase irq_err_count
+    - afs: Fix dynamic root getattr
+    - ice: ethtool: advertise 1000M speeds properly
+    - regmap-irq: Fix a bug in regmap_irq_enable() for type_in_mask chips
+    - igb: Make DMA faster when CPU is active on the PCIe link
+    - virtio_net: fix xdp_rxq_info bug after suspend/resume
+    - Revert "net/tls: fix tls_sk_proto_close executed repeatedly"
+    - gpio: winbond: Fix error code in winbond_gpio_get()
+    - s390/cpumf: Handle events cycles and instructions identical
+    - iio: adc: vf610: fix conversion mode sysfs node name
+    - xhci: turn off port power in shutdown
+    - usb: chipidea: udc: check request status before setting device address
+    - iio:chemical:ccs811: rearrange iio trigger get and register
+    - iio:accel:bma180: rearrange iio trigger get and register
+    - iio:accel:mxc4005: rearrange iio trigger get and register
+    - iio: accel: mma8452: ignore the return value of reset operation
+    - iio: gyro: mpu3050: Fix the error handling in mpu3050_power_up()
+    - iio: trigger: sysfs: fix use-after-free on remove
+    - iio: adc: stm32: fix maximum clock rate for stm32mp15x
+    - iio: adc: axp288: Override TS pin bias current for some models
+    - xtensa: xtfpga: Fix refcount leak bug in setup
+    - xtensa: Fix refcount leak bug in time.c
+    - parisc: Enable ARCH_HAS_STRICT_MODULE_RWX
+    - powerpc: Enable execve syscall exit tracepoint
+    - powerpc/rtas: Allow ibm,platform-dump RTAS call with null buffer address
+    - powerpc/powernv: wire up rng during setup_arch
+    - ARM: dts: imx6qdl: correct PU regulator ramp delay
+    - ARM: exynos: Fix refcount leak in exynos_map_pmu
+    - soc: bcm: brcmstb: pm: pm-arm: Fix refcount leak in brcmstb_pm_probe
+    - ARM: Fix refcount leak in axxia_boot_secondary
+    - ARM: cns3xxx: Fix refcount leak in cns3xxx_init
+    - modpost: fix section mismatch check for exported init/exit sections
+    - random: update comment from copy_to_user() -> copy_to_iter()
+    - kbuild: link vmlinux only once for CONFIG_TRIM_UNUSED_KSYMS (2nd attempt)
+    - powerpc/pseries: wire up rng during setup_arch()
+    - Linux 5.4.202
+  * Focal update: v5.4.201 upstream stable release (LP: #1986993)
+    - dm: remove special-casing of bio-based immutable singleton target on NVMe
+    - usb: gadget: u_ether: fix regression in setting fixed MAC address
+    - tcp: add some entropy in __inet_hash_connect()
+    - tcp: use different parts of the port_offset for index and offset
+    - tcp: add small random increments to the source port
+    - tcp: dynamically allocate the perturb table used by source ports
+    - tcp: increase source port perturb table to 2^16
+    - tcp: drop the hash_32() part from the index calculation
+    - arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer
+    - Linux 5.4.201
+  * Focal update: v5.4.200 upstream stable release (LP: #1983152)
+    - Revert "UBUNTU: SAUCE: random: Make getrandom() ready earlier"
+    - 9p: missing chunk of "fs/9p: Don't update file type when updating file
+      attributes"
+    - bpf: Fix incorrect memory charge cost calculation in stack_map_alloc()
+    - nfc: st21nfca: fix incorrect sizing calculations in EVT_TRANSACTION
+    - crypto: blake2s - generic C library implementation and selftest
+    - lib/crypto: blake2s: move hmac construction into wireguard
+    - lib/crypto: sha1: re-roll loops to reduce code size
+    - compat_ioctl: remove /dev/random commands
+    - random: don't forget compat_ioctl on urandom
+    - random: Don't wake crng_init_wait when crng_init == 1
+    - random: Add a urandom_read_nowait() for random APIs that don't warn
+    - random: add GRND_INSECURE to return best-effort non-cryptographic bytes
+    - random: ignore GRND_RANDOM in getentropy(2)
+    - random: make /dev/random be almost like /dev/urandom
+    - random: remove the blocking pool
+    - random: delete code to pull data into pools
+    - random: remove kernel.random.read_wakeup_threshold
+    - random: remove unnecessary unlikely()
+    - random: convert to ENTROPY_BITS for better code readability
+    - random: Add and use pr_fmt()
+    - random: fix typo in add_timer_randomness()
+    - random: remove some dead code of poolinfo
+    - random: split primary/secondary crng init paths
+    - random: avoid warnings for !CONFIG_NUMA builds
+    - x86: Remove arch_has_random, arch_has_random_seed
+    - powerpc: Remove arch_has_random, arch_has_random_seed
+    - s390: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Remove arch_has_random, arch_has_random_seed
+    - linux/random.h: Use false with bool
+    - linux/random.h: Mark CONFIG_ARCH_RANDOM functions __must_check
+    - powerpc: Use bool in archrandom.h
+    - random: add arch_get_random_*long_early()
+    - random: avoid arch_get_random_seed_long() when collecting IRQ randomness
+    - random: remove dead code left over from blocking pool
+    - MAINTAINERS: co-maintain random.c
+    - crypto: blake2s - include <linux/bug.h> instead of <asm/bug.h>
+    - crypto: blake2s - adjust include guard naming
+    - random: document add_hwgenerator_randomness() with other input functions
+    - random: remove unused irq_flags argument from add_interrupt_randomness()
+    - random: use BLAKE2s instead of SHA1 in extraction
+    - random: do not sign extend bytes for rotation when mixing
+    - random: do not re-init if crng_reseed completes before primary init
+    - random: mix bootloader randomness into pool
+    - random: harmonize "crng init done" messages
+    - random: use IS_ENABLED(CONFIG_NUMA) instead of ifdefs
+    - random: initialize ChaCha20 constants with correct endianness
+    - random: early initialization of ChaCha constants
+    - random: avoid superfluous call to RDRAND in CRNG extraction
+    - random: don't reset crng_init_cnt on urandom_read()
+    - random: fix typo in comments
+    - random: cleanup poolinfo abstraction
+    - random: cleanup integer types
+    - random: remove incomplete last_data logic
+    - random: remove unused extract_entropy() reserved argument
+    - random: rather than entropy_store abstraction, use global
+    - random: remove unused OUTPUT_POOL constants
+    - random: de-duplicate INPUT_POOL constants
+    - random: prepend remaining pool constants with POOL_
+    - random: cleanup fractional entropy shift constants
+    - random: access input_pool_data directly rather than through pointer
+    - random: selectively clang-format where it makes sense
+    - random: simplify arithmetic function flow in account()
+    - random: continually use hwgenerator randomness
+    - random: access primary_pool directly rather than through pointer
+    - random: only call crng_finalize_init() for primary_crng
+    - random: use computational hash for entropy extraction
+    - random: simplify entropy debiting
+    - random: use linear min-entropy accumulation crediting
+    - random: always wake up entropy writers after extraction
+    - random: make credit_entropy_bits() always safe
+    - random: remove use_input_pool parameter from crng_reseed()
+    - random: remove batched entropy locking
+    - random: fix locking in crng_fast_load()
+    - random: use RDSEED instead of RDRAND in entropy extraction
+    - random: get rid of secondary crngs
+    - random: inline leaves of rand_initialize()
+    - random: ensure early RDSEED goes through mixer on init
+    - random: do not xor RDRAND when writing into /dev/random
+    - random: absorb fast pool into input pool after fast load
+    - random: use simpler fast key erasure flow on per-cpu keys
+    - random: use hash function for crng_slow_load()
+    - random: make more consistent use of integer types
+    - random: remove outdated INT_MAX >> 6 check in urandom_read()
+    - random: zero buffer after reading entropy from userspace
+    - random: fix locking for crng_init in crng_reseed()
+    - random: tie batched entropy generation to base_crng generation
+    - random: remove ifdef'd out interrupt bench
+    - random: remove unused tracepoints
+    - random: add proper SPDX header
+    - random: deobfuscate irq u32/u64 contributions
+    - random: introduce drain_entropy() helper to declutter crng_reseed()
+    - random: remove useless header comment
+    - random: remove whitespace and reorder includes
+    - random: group initialization wait functions
+    - random: group crng functions
+    - random: group entropy extraction functions
+    - random: group entropy collection functions
+    - random: group userspace read/write functions
+    - random: group sysctl functions
+    - random: rewrite header introductory comment
+    - random: defer fast pool mixing to worker
+    - random: do not take pool spinlock at boot
+    - random: unify early init crng load accounting
+    - random: check for crng_init == 0 in add_device_randomness()
+    - random: pull add_hwgenerator_randomness() declaration into random.h
+    - random: clear fast pool, crng, and batches in cpuhp bring up
+    - random: round-robin registers as ulong, not u32
+    - random: only wake up writers after zap if threshold was passed
+    - random: cleanup UUID handling
+    - random: unify cycles_t and jiffies usage and types
+    - random: do crng pre-init loading in worker rather than irq
+    - random: give sysctl_random_min_urandom_seed a more sensible value
+    - random: don't let 644 read-only sysctls be written to
+    - random: replace custom notifier chain with standard one
+    - random: use SipHash as interrupt entropy accumulator
+    - random: make consistent usage of crng_ready()
+    - random: reseed more often immediately after booting
+    - random: check for signal and try earlier when generating entropy
+    - random: skip fast_init if hwrng provides large chunk of entropy
+    - random: treat bootloader trust toggle the same way as cpu trust toggle
+    - random: re-add removed comment about get_random_{u32,u64} reseeding
+    - random: mix build-time latent entropy into pool at init
+    - random: do not split fast init input in add_hwgenerator_randomness()
+    - random: do not allow user to keep crng key around on stack
+    - random: check for signal_pending() outside of need_resched() check
+    - random: check for signals every PAGE_SIZE chunk of /dev/[u]random
+    - random: allow partial reads if later user copies fail
+    - random: make random_get_entropy() return an unsigned long
+    - random: document crng_fast_key_erasure() destination possibility
+    - random: fix sysctl documentation nits
+    - init: call time_init() before rand_initialize()
+    - ia64: define get_cycles macro for arch-override
+    - s390: define get_cycles macro for arch-override
+    - parisc: define get_cycles macro for arch-override
+    - alpha: define get_cycles macro for arch-override
+    - powerpc: define get_cycles macro for arch-override
+    - timekeeping: Add raw clock fallback for random_get_entropy()
+    - m68k: use fallback for random_get_entropy() instead of zero
+    - mips: use fallback for random_get_entropy() instead of just c0 random
+    - arm: use fallback for random_get_entropy() instead of zero
+    - nios2: use fallback for random_get_entropy() instead of zero
+    - x86/tsc: Use fallback for random_get_entropy() instead of zero
+    - um: use fallback for random_get_entropy() instead of zero
+    - sparc: use fallback for random_get_entropy() instead of zero
+    - xtensa: use fallback for random_get_entropy() instead of zero
+    - random: insist on random_get_entropy() existing in order to simplify
+    - random: do not use batches when !crng_ready()
+    - random: use first 128 bits of input as fast init
+    - random: do not pretend to handle premature next security model
+    - random: order timer entropy functions below interrupt functions
+    - random: do not use input pool from hard IRQs
+    - random: help compiler out with fast_mix() by using simpler arguments
+    - siphash: use one source of truth for siphash permutations
+    - random: use symbolic constants for crng_init states
+    - random: avoid initializing twice in credit race
+    - random: move initialization out of reseeding hot path
+    - random: remove ratelimiting for in-kernel unseeded randomness
+    - random: use proper jiffies comparison macro
+    - random: handle latent entropy and command line from random_init()
+    - random: credit architectural init the exact amount
+    - random: use static branch for crng_ready()
+    - random: remove extern from functions in header
+    - random: use proper return types on get_random_{int,long}_wait()
+    - random: make consistent use of buf and len
+    - random: move initialization functions out of hot pages
+    - random: move randomize_page() into mm where it belongs
+    - random: unify batched entropy implementations
+    - random: convert to using fops->read_iter()
+    - random: convert to using fops->write_iter()
+    - random: wire up fops->splice_{read,write}_iter()
+    - random: check for signals after page of pool writes
+    - Revert "random: use static branch for crng_ready()"
+    - crypto: drbg - always seeded with SP800-90B compliant noise source
+    - crypto: drbg - prepare for more fine-grained tracking of seeding state
+    - crypto: drbg - track whether DRBG was seeded with !rng_is_initialized()
+    - crypto: drbg - move dynamic ->reseed_threshold adjustments to __drbg_seed()
+    - crypto: drbg - always try to free Jitter RNG instance
+    - crypto: drbg - make reseeding from get_random_bytes() synchronous
+    - random: avoid checking crng_ready() twice in random_init()
+    - random: mark bootloader randomness code as __init
+    - random: account for arch randomness in bits
+    - powerpc/kasan: Silence KASAN warnings in __get_wchan()
+    - ASoC: nau8822: Add operation for internal PLL off and on
+    - dma-debug: make things less spammy under memory pressure
+    - ASoC: cs42l52: Fix TLV scales for mixer controls
+    - ASoC: cs35l36: Update digital volume TLV
+    - ASoC: cs53l30: Correct number of volume levels on SX controls
+    - ASoC: cs42l52: Correct TLV for Bypass Volume
+    - ASoC: cs42l56: Correct typo in minimum level for SX volume controls
+    - ata: libata-core: fix NULL pointer deref in ata_host_alloc_pinfo()
+    - ASoC: wm8962: Fix suspend while playing music
+    - ASoC: es8328: Fix event generation for deemphasis control
+    - ASoC: wm_adsp: Fix event generation for wm_adsp_fw_put()
+    - scsi: vmw_pvscsi: Expand vcpuHint to 16 bits
+    - scsi: lpfc: Fix port stuck in bypassed state after LIP in PT2PT topology
+    - scsi: lpfc: Allow reduced polling rate for nvme_admin_async_event cmd
+      completion
+    - scsi: ipr: Fix missing/incorrect resource cleanup in error case
+    - scsi: pmcraid: Fix missing resource cleanup in error case
+    - ALSA: hda/realtek - Add HW8326 support
+    - virtio-mmio: fix missing put_device() when vm_cmdline_parent registration
+      failed
+    - nfc: nfcmrvl: Fix memory leak in nfcmrvl_play_deferred
+    - ipv6: Fix signed integer overflow in l2tp_ip6_sendmsg
+    - net: ethernet: mtk_eth_soc: fix misuse of mem alloc interface
+      netdev[napi]_alloc_frag
+    - random: credit cpu and bootloader seeds by default
+    - pNFS: Don't keep retrying if the server replied NFS4ERR_LAYOUTUNAVAILABLE
+    - clocksource: hyper-v: unexport __init-annotated hv_init_clocksource()
+    - i40e: Fix adding ADQ filter to TC0
+    - i40e: Fix calculating the number of queue pairs
+    - i40e: Fix call trace in setup_tx_descriptors
+    - tty: goldfish: Fix free_irq() on remove
+    - misc: atmel-ssc: Fix IRQ check in ssc_probe
+    - mlxsw: spectrum_cnt: Reorder counter pools
+    - net: bgmac: Fix an erroneous kfree() in bgmac_remove()
+    - arm64: ftrace: fix branch range checks
+    - certs/blacklist_hashes.c: fix const confusion in certs blacklist
+    - faddr2line: Fix overlapping text section failures, the sequel
+    - irqchip/gic/realview: Fix refcount leak in realview_gic_of_init
+    - irqchip/gic-v3: Fix error handling in gic_populate_ppi_partitions
+    - irqchip/gic-v3: Fix refcount leak in gic_populate_ppi_partitions
+    - i2c: designware: Use standard optional ref clock implementation
+    - comedi: vmk80xx: fix expression for tx buffer size
+    - USB: serial: option: add support for Cinterion MV31 with new baseline
+    - USB: serial: io_ti: add Agilent E5805A support
+    - usb: dwc2: Fix memory leak in dwc2_hcd_init
+    - usb: gadget: lpc32xx_udc: Fix refcount leak in lpc32xx_udc_probe
+    - serial: 8250: Store to lsr_save_flags after lsr read
+    - dm mirror log: round up region bitmap size to BITS_PER_LONG
+    - ext4: fix bug_on ext4_mb_use_inode_pa
+    - ext4: make variable "count" signed
+    - ext4: add reserved GDT blocks check
+    - ALSA: hda/realtek: fix right sounds and mute/micmute LEDs for HP machine
+    - virtio-pci: Remove wrong address verification in vp_del_vqs()
+    - net/sched: act_police: more accurate MTU policing
+    - net: openvswitch: fix leak of nested actions
+    - arm64: kprobes: Use BRK instead of single-step when executing instructions
+      out-of-line
+    - RISC-V: fix barrier() use in <vdso/processor.h>
+    - riscv: Less inefficient gcc tishift helpers (and export their symbols)
+    - powerpc/mm: Switch obsolete dssall to .long
+    - Linux 5.4.200
+  * Focal update: v5.4.199 upstream stable release (LP: #1983150)
+    - Linux 5.4.199
+  * Focal update: v5.4.198 upstream stable release (LP: #1982409)
+    - binfmt_flat: do not stop relocating GOT entries prematurely on riscv
+    - ALSA: hda/realtek - Fix microphone noise on ASUS TUF B550M-PLUS
+    - USB: serial: option: add Quectel BG95 modem
+    - USB: new quirk for Dell Gen 2 devices
+    - perf/x86/intel: Fix event constraints for ICL
+    - ptrace/um: Replace PT_DTRACE with TIF_SINGLESTEP
+    - ptrace/xtensa: Replace PT_SINGLESTEP with TIF_SINGLESTEP
+    - ptrace: Reimplement PTRACE_KILL by always sending SIGKILL
+    - btrfs: add "0x" prefix for unsupported optional features
+    - btrfs: repair super block num_devices automatically
+    - drm/virtio: fix NULL pointer dereference in virtio_gpu_conn_get_modes
+    - mwifiex: add mutex lock for call in mwifiex_dfs_chan_sw_work_queue
+    - b43legacy: Fix assigning negative value to unsigned variable
+    - b43: Fix assigning negative value to unsigned variable
+    - ipw2x00: Fix potential NULL dereference in libipw_xmit()
+    - ipv6: fix locking issues with loops over idev->addr_list
+    - fbcon: Consistently protect deferred_takeover with console_lock()
+    - ACPICA: Avoid cache flush inside virtual machines
+    - drm/komeda: return early if drm_universal_plane_init() fails.
+    - ALSA: jack: Access input_dev under mutex
+    - spi: spi-rspi: Remove setting {src,dst}_{addr,addr_width} based on DMA
+      direction
+    - tools/power turbostat: fix ICX DRAM power numbers
+    - drm/amd/pm: fix double free in si_parse_power_table()
+    - ath9k: fix QCA9561 PA bias level
+    - media: venus: hfi: avoid null dereference in deinit
+    - media: pci: cx23885: Fix the error handling in cx23885_initdev()
+    - media: cx25821: Fix the warning when removing the module
+    - md/bitmap: don't set sb values if can't pass sanity check
+    - mmc: jz4740: Apply DMA engine limits to maximum segment size
+    - scsi: megaraid: Fix error check return value of register_chrdev()
+    - drm/plane: Move range check for format_count earlier
+    - drm/amd/pm: fix the compile warning
+    - arm64: compat: Do not treat syscall number as ESR_ELx for a bad syscall
+    - drm: msm: fix error check return value of irq_of_parse_and_map()
+    - ipv6: Don't send rs packets to the interface of ARPHRD_TUNNEL
+    - net/mlx5: fs, delete the FTE when there are no rules attached to it
+    - ASoC: dapm: Don't fold register value changes into notifications
+    - mlxsw: spectrum_dcb: Do not warn about priority changes
+    - drm/amdgpu/ucode: Remove firmware load type check in amdgpu_ucode_free_bo
+    - HID: bigben: fix slab-out-of-bounds Write in bigben_probe
+    - ASoC: tscs454: Add endianness flag in snd_soc_component_driver
+    - s390/preempt: disable __preempt_count_add() optimization for
+      PROFILE_ALL_BRANCHES
+    - spi: stm32-qspi: Fix wait_cmd timeout in APM mode
+    - dma-debug: change allocation mode from GFP_NOWAIT to GFP_ATIOMIC
+    - ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default
+    - ipmi:ssif: Check for NULL msg when handling events and messages
+    - ipmi: Fix pr_fmt to avoid compilation issues
+    - rtlwifi: Use pr_warn instead of WARN_ONCE
+    - media: coda: limit frame interval enumeration to supported encoder frame
+      sizes
+    - media: cec-adap.c: fix is_configuring state
+    - openrisc: start CPU timer early in boot
+    - nvme-pci: fix a NULL pointer dereference in nvme_alloc_admin_tags
+    - ASoC: rt5645: Fix errorenous cleanup order
+    - nbd: Fix hung on disconnect request if socket is closed before
+    - net: phy: micrel: Allow probing without .driver_data
+    - media: exynos4-is: Fix compile warning
+    - ASoC: max98357a: remove dependency on GPIOLIB
+    - rxrpc: Return an error to sendmsg if call failed
+    - eth: tg3: silence the GCC 12 array-bounds warning
+    - selftests/bpf: fix btf_dump/btf_dump due to recent clang change
+    - IB/rdmavt: add missing locks in rvt_ruc_loopback
+    - ARM: dts: ox820: align interrupt controller node name with dtschema
+    - PM / devfreq: rk3399_dmc: Disable edev on remove()
+    - fs: jfs: fix possible NULL pointer dereference in dbFree()
+    - ARM: OMAP1: clock: Fix UART rate reporting algorithm
+    - powerpc/fadump: Fix fadump to work with a different endian capture kernel
+    - fat: add ratelimit to fat*_ent_bread()
+    - ARM: versatile: Add missing of_node_put in dcscb_init
+    - ARM: dts: exynos: add atmel,24c128 fallback to Samsung EEPROM
+    - ARM: hisi: Add missing of_node_put after of_find_compatible_node
+    - PCI: Avoid pci_dev_lock() AB/BA deadlock with sriov_numvfs_store()
+    - tracing: incorrect isolate_mote_t cast in mm_vmscan_lru_isolate
+    - powerpc/xics: fix refcount leak in icp_opal_init()
+    - powerpc/powernv: fix missing of_node_put in uv_init()
+    - macintosh/via-pmu: Fix build failure when CONFIG_INPUT is disabled
+    - powerpc/iommu: Add missing of_node_put in iommu_init_early_dart
+    - RDMA/hfi1: Prevent panic when SDMA is disabled
+    - drm: fix EDID struct for old ARM OABI format
+    - ath9k: fix ar9003_get_eepmisc
+    - drm/edid: fix invalid EDID extension block filtering
+    - drm/bridge: adv7511: clean up CEC adapter when probe fails
+    - ASoC: mediatek: Fix error handling in mt8173_max98090_dev_probe
+    - ASoC: mediatek: Fix missing of_node_put in mt2701_wm8960_machine_probe
+    - x86/delay: Fix the wrong asm constraint in delay_loop()
+    - drm/mediatek: Fix mtk_cec_mask()
+    - drm/vc4: txp: Don't set TXP_VSTART_AT_EOF
+    - drm/vc4: txp: Force alpha to be 0xff if it's disabled
+    - bpf: Fix excessive memory allocation in stack_map_alloc()
+    - nl80211: show SSID for P2P_GO interfaces
+    - drm/komeda: Fix an undefined behavior bug in komeda_plane_add()
+    - drm: mali-dp: potential dereference of null pointer
+    - spi: spi-ti-qspi: Fix return value handling of wait_for_completion_timeout
+    - NFC: NULL out the dev->rfkill to prevent UAF
+    - efi: Add missing prototype for efi_capsule_setup_info
+    - drbd: fix duplicate array initializer
+    - HID: hid-led: fix maximum brightness for Dream Cheeky
+    - HID: elan: Fix potential double free in elan_input_configured
+    - drm/bridge: Fix error handling in analogix_dp_probe
+    - sched/fair: Fix cfs_rq_clock_pelt() for throttled cfs_rq
+    - spi: img-spfi: Fix pm_runtime_get_sync() error checking
+    - cpufreq: Fix possible race in cpufreq online error path
+    - ath9k_htc: fix potential out of bounds access with invalid
+      rxstatus->rs_keyix
+    - inotify: show inotify mask flags in proc fdinfo
+    - fsnotify: fix wrong lockdep annotations
+    - of: overlay: do not break notify on NOTIFY_{OK|STOP}
+    - scsi: ufs: core: Exclude UECxx from SFR dump list
+    - x86/pm: Fix false positive kmemleak report in msr_build_context()
+    - x86/speculation: Add missing prototype for unpriv_ebpf_notify()
+    - ASoC: rk3328: fix disabling mclk on pclk probe failure
+    - perf tools: Add missing headers needed by util/data.h
+    - drm/msm/disp/dpu1: set vbif hw config to NULL to avoid use after memory free
+      during pm runtime resume
+    - drm/msm/dsi: fix error checks and return values for DSI xmit functions
+    - drm/msm/hdmi: check return value after calling
+      platform_get_resource_byname()
+    - drm/msm/hdmi: fix error check return value of irq_of_parse_and_map()
+    - drm/rockchip: vop: fix possible null-ptr-deref in vop_bind()
+    - virtio_blk: fix the discard_granularity and discard_alignment queue limits
+    - x86: Fix return value of __setup handlers
+    - irqchip/exiu: Fix acknowledgment of edge triggered interrupts
+    - irqchip/aspeed-i2c-ic: Fix irq_of_parse_and_map() return value
+    - x86/mm: Cleanup the control_va_addr_alignment() __setup handler
+    - regulator: core: Fix enable_count imbalance with EXCLUSIVE_GET
+    - drm/msm/mdp5: Return error code in mdp5_pipe_release when deadlock is
+      detected
+    - drm/msm/mdp5: Return error code in mdp5_mixer_release when deadlock is
+      detected
+    - drm/msm: return an error pointer in msm_gem_prime_get_sg_table()
+    - media: uvcvideo: Fix missing check to determine if element is found in list
+    - iomap: iomap_write_failed fix
+    - Revert "cpufreq: Fix possible race in cpufreq online error path"
+    - perf/amd/ibs: Use interrupt regs ip for stack unwinding
+    - ASoC: fsl: Fix refcount leak in imx_sgtl5000_probe
+    - ASoC: mxs-saif: Fix refcount leak in mxs_saif_probe
+    - regulator: pfuze100: Fix refcount leak in pfuze_parse_regulators_dt
+    - scripts/faddr2line: Fix overlapping text section failures
+    - media: aspeed: Fix an error handling path in aspeed_video_probe()
+    - media: st-delta: Fix PM disable depth imbalance in delta_probe
+    - media: exynos4-is: Change clk_disable to clk_disable_unprepare
+    - media: pvrusb2: fix array-index-out-of-bounds in pvr2_i2c_core_init
+    - media: vsp1: Fix offset calculation for plane cropping
+    - Bluetooth: fix dangling sco_conn and use-after-free in sco_sock_timeout
+    - m68k: math-emu: Fix dependencies of math emulation support
+    - sctp: read sk->sk_bound_dev_if once in sctp_rcv()
+    - media: ov7670: remove ov7670_power_off from ov7670_remove
+    - ext4: reject the 'commit' option on ext2 filesystems
+    - drm/msm/a6xx: Fix refcount leak in a6xx_gpu_init
+    - drm: msm: fix possible memory leak in mdp5_crtc_cursor_set()
+    - thermal/drivers/broadcom: Fix potential NULL dereference in sr_thermal_probe
+    - ASoC: wm2000: fix missing clk_disable_unprepare() on error in
+      wm2000_anc_transition()
+    - NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx
+    - rxrpc: Fix listen() setting the bar too high for the prealloc rings
+    - rxrpc: Don't try to resend the request if we're receiving the reply
+    - rxrpc: Fix overlapping ACK accounting
+    - rxrpc: Don't let ack.previousPacket regress
+    - rxrpc: Fix decision on when to generate an IDLE ACK
+    - net/smc: postpone sk_refcnt increment in connect()
+    - arm64: dts: rockchip: Move drive-impedance-ohm to emmc phy on rk3399
+    - ARM: dts: suniv: F1C100: fix watchdog compatible
+    - soc: qcom: smp2p: Fix missing of_node_put() in smp2p_parse_ipc
+    - soc: qcom: smsm: Fix missing of_node_put() in smsm_parse_ipc
+    - PCI: cadence: Fix find_first_zero_bit() limit
+    - PCI: rockchip: Fix find_first_zero_bit() limit
+    - KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry
+    - can: xilinx_can: mark bit timing constants as const
+    - ARM: dts: bcm2835-rpi-zero-w: Fix GPIO line name for Wifi/BT
+    - ARM: dts: bcm2837-rpi-cm3-io3: Fix GPIO line names for SMPS I2C
+    - ARM: dts: bcm2837-rpi-3-b-plus: Fix GPIO line name of power LED
+    - ARM: dts: bcm2835-rpi-b: Fix GPIO line names
+    - misc: ocxl: fix possible double free in ocxl_file_register_afu
+    - crypto: marvell/cesa - ECB does not IV
+    - arm: mediatek: select arch timer for mt7629
+    - powerpc/fadump: fix PT_LOAD segment for boot memory area
+    - mfd: ipaq-micro: Fix error check return value of platform_get_irq()
+    - scsi: fcoe: Fix Wstringop-overflow warnings in fcoe_wwn_from_mac()
+    - firmware: arm_scmi: Fix list protocols enumeration in the base protocol
+    - nvdimm: Allow overwrite in the presence of disabled dimms
+    - pinctrl: mvebu: Fix irq_of_parse_and_map() return value
+    - drivers/base/node.c: fix compaction sysfs file leak
+    - dax: fix cache flush on PMD-mapped pages
+    - powerpc/8xx: export 'cpm_setbrg' for modules
+    - powerpc/idle: Fix return value of __setup() handler
+    - powerpc/4xx/cpm: Fix return value of __setup() handler
+    - proc: fix dentry/inode overinstantiating under /proc/${pid}/net
+    - ipc/mqueue: use get_tree_nodev() in mqueue_get_tree()
+    - PCI: imx6: Fix PERST# start-up sequence
+    - tty: fix deadlock caused by calling printk() under tty_port->lock
+    - crypto: cryptd - Protect per-CPU resource by disabling BH.
+    - Input: sparcspkr - fix refcount leak in bbc_beep_probe
+    - powerpc/64: Only WARN if __pa()/__va() called with bad addresses
+    - powerpc/perf: Fix the threshold compare group constraint for power9
+    - macintosh: via-pmu and via-cuda need RTC_LIB
+    - powerpc/fsl_rio: Fix refcount leak in fsl_rio_setup
+    - mfd: davinci_voicecodec: Fix possible null-ptr-deref davinci_vc_probe()
+    - mailbox: forward the hrtimer if not queued and under a lock
+    - RDMA/hfi1: Prevent use of lock before it is initialized
+    - Input: stmfts - do not leave device disabled in stmfts_input_open
+    - f2fs: fix dereference of stale list iterator after loop body
+    - iommu/mediatek: Add list_del in mtk_iommu_remove
+    - i2c: at91: use dma safe buffers
+    - i2c: at91: Initialize dma_buf in at91_twi_xfer()
+    - NFS: Do not report EINTR/ERESTARTSYS as mapping errors
+    - NFS: Do not report flush errors in nfs_write_end()
+    - NFS: Don't report errors from nfs_pageio_complete() more than once
+    - NFSv4/pNFS: Do not fail I/O when we fail to allocate the pNFS layout
+    - video: fbdev: clcdfb: Fix refcount leak in clcdfb_of_vram_setup
+    - dmaengine: stm32-mdma: remove GISR1 register
+    - iommu/amd: Increase timeout waiting for GA log enablement
+    - perf c2c: Use stdio interface if slang is not supported
+    - perf jevents: Fix event syntax error caused by ExtSel
+    - f2fs: fix to avoid f2fs_bug_on() in dec_valid_node_count()
+    - f2fs: fix to do sanity check on block address in f2fs_do_zero_range()
+    - f2fs: fix to clear dirty inode in f2fs_evict_inode()
+    - f2fs: fix deadloop in foreground GC
+    - f2fs: don't need inode lock for system hidden quota
+    - f2fs: fix fallocate to use file_modified to update permissions consistently
+    - wifi: mac80211: fix use-after-free in chanctx code
+    - iwlwifi: mvm: fix assert 1F04 upon reconfig
+    - fs-writeback: writeback_sb_inodes：Recalculate 'wrote' according skipped
+      pages
+    - efi: Do not import certificates from UEFI Secure Boot for T2 Macs
+    - bfq: Split shared queues on move between cgroups
+    - bfq: Update cgroup information before merging bio
+    - bfq: Track whether bfq_group is still online
+    - ext4: fix use-after-free in ext4_rename_dir_prepare
+    - ext4: fix warning in ext4_handle_inode_extension
+    - ext4: fix bug_on in ext4_writepages
+    - ext4: verify dir block before splitting it
+    - ext4: avoid cycles in directory h-tree
+    - ACPI: property: Release subnode properties with data nodes
+    - tracing: Fix potential double free in create_var_ref()
+    - PCI/PM: Fix bridge_d3_blacklist[] Elo i2 overwrite of Gigabyte X299
+    - PCI: qcom: Fix runtime PM imbalance on probe errors
+    - PCI: qcom: Fix unbalanced PHY init on probe errors
+    - mm, compaction: fast_find_migrateblock() should return pfn in the target
+      zone
+    - dlm: fix plock invalid read
+    - dlm: fix missing lkb refcount handling
+    - ocfs2: dlmfs: fix error handling of user_dlm_destroy_lock
+    - scsi: dc395x: Fix a missing check on list iterator
+    - scsi: ufs: qcom: Add a readl() to make sure ref_clk gets enabled
+    - drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
+    - drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
+    - drm/nouveau/clk: Fix an incorrect NULL check on list iterator
+    - drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
+    - md: fix an incorrect NULL check in does_sb_need_changing
+    - md: fix an incorrect NULL check in md_reload_sb
+    - mtd: cfi_cmdset_0002: Move and rename
+      chip_check/chip_ready/chip_good_for_write
+    - media: coda: Fix reported H264 profile
+    - media: coda: Add more H264 levels for CODA960
+    - Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
+    - RDMA/hfi1: Fix potential integer multiplication overflow errors
+    - irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375,
+      A38x, A39x
+    - irqchip: irq-xtensa-mx: fix initial IRQ affinity
+    - mac80211: upgrade passive scan to active scan on DFS channels after beacon
+      rx
+    - um: chan_user: Fix winch_tramp() return value
+    - um: Fix out-of-bounds read in LDT setup
+    - iommu/msm: Fix an incorrect NULL check on list iterator
+    - nodemask.h: fix compilation error with GCC12
+    - hugetlb: fix huge_pmd_unshare address update
+    - rtl818x: Prevent using not initialized queues
+    - ASoC: rt5514: Fix event generation for "DSP Voice Wake Up" control
+    - carl9170: tx: fix an incorrect use of list iterator
+    - serial: pch: don't overwrite xmit->buf[0] by x_char
+    - tilcdc: tilcdc_external: fix an incorrect NULL check on list iterator
+    - gma500: fix an incorrect NULL check on list iterator
+    - arm64: dts: qcom: ipq8074: fix the sleep clock frequency
+    - phy: qcom-qmp: fix struct clk leak on probe errors
+    - ARM: pxa: maybe fix gpio lookup tables
+    - docs/conf.py: Cope with removal of language=None in Sphinx 5.0.0
+    - dt-bindings: gpio: altera: correct interrupt-cells
+    - blk-iolatency: Fix inflight count imbalances and IO hangs on offline
+    - phy: qcom-qmp: fix reset-controller leak on probe errors
+    - Kconfig: add config option for asm goto w/ outputs
+    - RDMA/rxe: Generate a completion for unsupported/invalid opcode
+    - MIPS: IP27: Remove incorrect `cpu_has_fpu' override
+    - bfq: Avoid merging queues with different parents
+    - bfq: Drop pointless unlock-lock pair
+    - bfq: Remove pointless bfq_init_rq() calls
+    - bfq: Get rid of __bio_blkcg() usage
+    - bfq: Make sure bfqg for which we are queueing requests is online
+    - block: fix bio_clone_blkg_association() to associate with proper blkcg_gq
+    - md: bcache: check the return value of kzalloc() in detached_dev_do_request()
+    - pcmcia: db1xxx_ss: restrict to MIPS_DB1XXX boards
+    - staging: greybus: codecs: fix type confusion of list iterator variable
+    - iio: adc: ad7124: Remove shift from scan_type
+    - tty: goldfish: Use tty_port_destroy() to destroy port
+    - tty: serial: owl: Fix missing clk_disable_unprepare() in owl_uart_probe
+    - tty: serial: fsl_lpuart: fix potential bug when using both of_alias_get_id
+      and ida_simple_get
+    - usb: usbip: fix a refcount leak in stub_probe()
+    - usb: usbip: add missing device lock on tweak configuration cmd
+    - USB: storage: karma: fix rio_karma_init return
+    - usb: musb: Fix missing of_node_put() in omap2430_probe
+    - staging: fieldbus: Fix the error handling path in
+      anybuss_host_common_probe()
+    - pwm: lp3943: Fix duty calculation in case period was clamped
+    - rpmsg: qcom_smd: Fix irq_of_parse_and_map() return value
+    - usb: dwc3: pci: Fix pm_runtime_get_sync() error checking
+    - firmware: stratix10-svc: fix a missing check on list iterator
+    - iio: adc: stmpe-adc: Fix wait_for_completion_timeout return value check
+    - iio: adc: sc27xx: fix read big scale voltage not right
+    - iio: adc: sc27xx: Fine tune the scale calibration values
+    - rpmsg: qcom_smd: Fix returning 0 if irq_of_parse_and_map() fails
+    - phy: qcom-qmp: fix pipe-clock imbalance on power-on failure
+    - serial: sifive: Report actual baud base rather than fixed 115200
+    - coresight: cpu-debug: Replace mutex with mutex_trylock on panic notifier
+    - soc: rockchip: Fix refcount leak in rockchip_grf_init
+    - clocksource/drivers/riscv: Events are stopped during CPU suspend
+    - rtc: mt6397: check return value after calling platform_get_resource()
+    - serial: meson: acquire port->lock in startup()
+    - serial: 8250_fintek: Check SER_RS485_RTS_* only with RS485
+    - serial: digicolor-usart: Don't allow CS5-6
+    - serial: rda-uart: Don't allow CS5-6
+    - serial: txx9: Don't allow CS5-6
+    - serial: sh-sci: Don't allow CS5-6
+    - serial: sifive: Sanitize CSIZE and c_iflag
+    - serial: st-asc: Sanitize CSIZE and correct PARENB for CS7
+    - serial: stm32-usart: Correct CSIZE, bits, and parity
+    - firmware: dmi-sysfs: Fix memory leak in dmi_sysfs_register_handle
+    - bus: ti-sysc: Fix warnings for unbind for serial
+    - driver: base: fix UAF when driver_attach failed
+    - driver core: fix deadlock in __device_attach
+    - watchdog: ts4800_wdt: Fix refcount leak in ts4800_wdt_probe
+    - ASoC: fsl_sai: Fix FSL_SAI_xDR/xFR definition
+    - clocksource/drivers/oxnas-rps: Fix irq_of_parse_and_map() return value
+    - s390/crypto: fix scatterwalk_unmap() callers in AES-GCM
+    - net: sched: fixed barrier to prevent skbuff sticking in qdisc backlog
+    - net: ethernet: mtk_eth_soc: out of bounds read in mtk_hwlro_get_fdir_entry()
+    - net: dsa: mv88e6xxx: Fix refcount leak in mv88e6xxx_mdios_register
+    - modpost: fix removing numeric suffixes
+    - jffs2: fix memory leak in jffs2_do_fill_super
+    - ubi: ubi_create_volume: Fix use-after-free when volume creation failed
+    - nfp: only report pause frame configuration for physical device
+    - net/mlx5: Don't use already freed action pointer
+    - net/mlx5e: Update netdev features after changing XDP state
+    - net: sched: add barrier to fix packet stuck problem for lockless qdisc
+    - tcp: tcp_rtx_synack() can be called from process context
+    - afs: Fix infinite loop found by xfstest generic/676
+    - tipc: check attribute length for bearer name
+    - perf c2c: Fix sorting in percent_rmt_hitm_cmp()
+    - mips: cpc: Fix refcount leak in mips_cpc_default_phys_base
+    - tracing: Fix sleeping function called from invalid context on RT kernel
+    - tracing: Avoid adding tracer option before update_tracer_options
+    - f2fs: remove WARN_ON in f2fs_is_valid_blkaddr
+    - i2c: cadence: Increase timeout per message if necessary
+    - m68knommu: set ZERO_PAGE() to the allocated zeroed page
+    - m68knommu: fix undefined reference to `_init_sp'
+    - dmaengine: zynqmp_dma: In struct zynqmp_dma_chan fix desc_size data type
+    - NFSv4: Don't hold the layoutget locks across multiple RPC calls
+    - video: fbdev: pxa3xx-gcu: release the resources correctly in
+      pxa3xx_gcu_probe/remove()
+    - xprtrdma: treat all calls not a bcall when bc_serv is NULL
+    - netfilter: nat: really support inet nat without l3 address
+    - ata: pata_octeon_cf: Fix refcount leak in octeon_cf_probe
+    - netfilter: nf_tables: memleak flow rule from commit path
+    - xen: unexport __init-annotated xen_xlate_map_ballooned_pages()
+    - af_unix: Fix a data-race in unix_dgram_peer_wake_me().
+    - bpf, arm64: Clear prog->jited_len along prog->jited
+    - net: dsa: lantiq_gswip: Fix refcount leak in gswip_gphy_fw_list
+    - net/mlx4_en: Fix wrong return value on ioctl EEPROM query failure
+    - SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
+    - net: mdio: unexport __init-annotated mdio_bus_init()
+    - net: xfrm: unexport __init-annotated xfrm4_protocol_init()
+    - net: ipv6: unexport __init-annotated seg6_hmac_init()
+    - net/mlx5: Rearm the FW tracer after each tracer event
+    - net/mlx5: fs, fail conflicting actions
+    - ip_gre: test csum_start instead of transport header
+    - net: altera: Fix refcount leak in altera_tse_mdio_create
+    - drm: imx: fix compiler warning with gcc-12
+    - iio: dummy: iio_simple_dummy: check the return value of kstrdup()
+    - iio: st_sensors: Add a local lock for protecting odr
+    - lkdtm/usercopy: Expand size of "out of frame" object
+    - tty: synclink_gt: Fix null-pointer-dereference in slgt_clean()
+    - tty: Fix a possible resource leak in icom_probe
+    - drivers: staging: rtl8192u: Fix deadlock in ieee80211_beacons_stop()
+    - drivers: staging: rtl8192e: Fix deadlock in rtllib_beacons_stop()
+    - USB: host: isp116x: check return value after calling platform_get_resource()
+    - drivers: tty: serial: Fix deadlock in sa1100_set_termios()
+    - drivers: usb: host: Fix deadlock in oxu_bus_suspend()
+    - USB: hcd-pci: Fully suspend across freeze/thaw cycle
+    - usb: dwc2: gadget: don't reset gadget's driver->bus
+    - misc: rtsx: set NULL intfdata when probe fails
+    - extcon: Modify extcon device to be created after driver data is set
+    - clocksource/drivers/sp804: Avoid error on multiple instances
+    - staging: rtl8712: fix uninit-value in usb_read8() and friends
+    - staging: rtl8712: fix uninit-value in r871xu_drv_init()
+    - serial: msm_serial: disable interrupts in __msm_console_write()
+    - kernfs: Separate kernfs_pr_cont_buf and rename_lock.
+    - watchdog: wdat_wdt: Stop watchdog when rebooting the system
+    - md: protect md_unregister_thread from reentrancy
+    - scsi: myrb: Fix up null pointer access on myrb_cleanup()
+    - ceph: allow ceph.dir.rctime xattr to be updatable
+    - drm/radeon: fix a possible null pointer dereference
+    - modpost: fix undefined behavior of is_arm_mapping_symbol()
+    - x86/cpu: Elide KCSAN for cpu_has() and friends
+    - nbd: call genl_unregister_family() first in nbd_cleanup()
+    - nbd: fix race between nbd_alloc_config() and module removal
+    - cifs: version operations for smb20 unneeded when legacy support disabled
+    - nodemask: Fix return values to be unsigned
+    - vringh: Fix loop descriptors check in the indirect cases
+    - scripts/gdb: change kernel config dumping method
+    - ALSA: hda/conexant - Fix loopback issue with CX20632
+    - cifs: return errors during session setup during reconnects
+    - ata: libata-transport: fix {dma|pio|xfer}_mode sysfs files
+    - mmc: block: Fix CQE recovery reset success
+    - nfc: st21nfca: fix incorrect validating logic in EVT_TRANSACTION
+    - nfc: st21nfca: fix memory leaks in EVT_TRANSACTION handling
+    - ixgbe: fix bcast packets Rx on VF after promisc removal
+    - ixgbe: fix unexpected VLAN Rx in promisc mode on VF
+    - Input: bcm5974 - set missing URB_NO_TRANSFER_DMA_MAP urb flag
+    - powerpc/32: Fix overread/overwrite of thread_struct via ptrace
+    - md/raid0: Ignore RAID0 layout if the second zone has only one device
+    - mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
+    - tcp: fix tcp_mtup_probe_success vs wrong snd_cwnd
+    - Linux 5.4.198
+  * Focal update: v5.4.197 upstream stable release (LP: #1981758)
+    - x86/pci/xen: Disable PCI/MSI[-X] masking for XEN_HVM guests
+    - staging: rtl8723bs: prevent ->Ssid overflow in rtw_wx_set_scan()
+    - Input: goodix - fix spurious key release events
+    - tcp: change source port randomizarion at connect() time
+    - secure_seq: use the 64 bits of the siphash for port offset calculation
+    - media: vim2m: Register video device after setting up internals
+    - media: vim2m: initialize the media device earlier
+    - ACPI: sysfs: Make sparse happy about address space in use
+    - ACPI: sysfs: Fix BERT error region memory mapping
+    - pinctrl: sunxi: fix f1c100s uart2 function
+    - net: af_key: check encryption module availability consistency
+    - net: ftgmac100: Disable hardware checksum on AST2600
+    - i2c: ismt: Provide a DMA buffer for Interrupt Cause Logging
+    - drivers: i2c: thunderx: Allow driver to work with ACPI defined TWSI
+      controllers
+    - assoc_array: Fix BUG_ON during garbage collect
+    - cfg80211: set custom regdomain after wiphy registration
+    - drm/i915: Fix -Wstringop-overflow warning in call to intel_read_wm_latency()
+    - exec: Force single empty string when argv is empty
+    - netfilter: conntrack: re-fetch conntrack after insertion
+    - crypto: ecrdsa - Fix incorrect use of vli_cmp
+    - zsmalloc: fix races between asynchronous zspage free and page migration
+    - dm integrity: fix error code in dm_integrity_ctr()
+    - dm crypt: make printing of the key constant-time
+    - dm stats: add cond_resched when looping over entries
+    - dm verity: set DM_TARGET_IMMUTABLE feature flag
+    - raid5: introduce MD_BROKEN
+    - HID: multitouch: Add support for Google Whiskers Touchpad
+    - tpm: Fix buffer access in tpm2_get_tpm_pt()
+    - tpm: ibmvtpm: Correct the return value in tpm_ibmvtpm_probe()
+    - docs: submitting-patches: Fix crossref to 'The canonical patch format'
+    - NFS: Memory allocation failures are not server fatal errors
+    - NFSD: Fix possible sleep during nfsd4_release_lockowner()
+    - bpf: Enlarge offset check value to INT_MAX in bpf_skb_{load,store}_bytes
+    - Linux 5.4.197
+  * Focal update: v5.4.196 upstream stable release (LP: #1981111)
+    - x86/xen: Make the boot CPU idle task reliable
+    - x86/xen: Make the secondary CPU idle tasks reliable
+    - rtc: fix use-after-free on device removal
+    - um: Cleanup syscall_handler_t definition/cast, fix warning
+    - Input: add bounds checking to input_set_capability()
+    - Input: stmfts - fix reference leak in stmfts_input_open
+    - crypto: stm32 - fix reference leak in stm32_crc_remove
+    - crypto: x86/chacha20 - Avoid spurious jumps to other functions
+    - ALSA: hda/realtek: Enable headset mic on Lenovo P360
+    - nvme-multipath: fix hang when disk goes live over reconnect
+    - rtc: mc146818-lib: Fix the AltCentury for AMD platforms
+    - MIPS: lantiq: check the return value of kzalloc()
+    - drbd: remove usage of list iterator variable after loop
+    - platform/chrome: cros_ec_debugfs: detach log reader wq from devm
+    - ARM: 9191/1: arm/stacktrace, kasan: Silence KASAN warnings in unwind_frame()
+    - nilfs2: fix lockdep warnings in page operations for btree nodes
+    - nilfs2: fix lockdep warnings during disk space reclamation
+    - mmc: core: Specify timeouts for BKOPS and CACHE_FLUSH for eMMC
+    - mmc: block: Use generic_cmd6_time when modifying INAND_CMD38_ARG_EXT_CSD
+    - mmc: core: Default to generic_cmd6_time as timeout in __mmc_switch()
+    - SUNRPC: Clean up scheduling of autoclose
+    - SUNRPC: Prevent immediate close+reconnect
+    - SUNRPC: Don't call connect() more than once on a TCP socket
+    - ALSA: wavefront: Proper check of get_user() error
+    - perf: Fix sys_perf_event_open() race against self
+    - Fix double fget() in vhost_net_set_backend()
+    - PCI/PM: Avoid putting Elo i2 PCIe Ports in D3cold
+    - KVM: x86/mmu: Update number of zapped pages even if page list is stable
+    - crypto: qcom-rng - fix infinite loop on requests not multiple of WORD_SZ
+    - drm/dp/mst: fix a possible memory leak in fetch_monitor_name()
+    - dma-buf: fix use of DMA_BUF_SET_NAME_{A,B} in userspace
+    - ARM: dts: aspeed-g6: remove FWQSPID group in pinctrl dtsi
+    - ARM: dts: aspeed-g6: fix SPI1/SPI2 quad pin group
+    - net: macb: Increment rx bd head after allocating skb and buffer
+    - net/sched: act_pedit: sanitize shift argument before usage
+    - net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()
+    - net: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()
+    - ice: fix possible under reporting of ethtool Tx and Rx statistics
+    - clk: at91: generated: consider range when calculating best rate
+    - net/qla3xxx: Fix a test in ql_reset_work()
+    - NFC: nci: fix sleep in atomic context bugs caused by nci_skb_alloc
+    - net/mlx5e: Properly block LRO when XDP is enabled
+    - ARM: 9196/1: spectre-bhb: enable for Cortex-A15
+    - ARM: 9197/1: spectre-bhb: fix loop8 sequence for Thumb2
+    - igb: skip phy status check where unavailable
+    - net: bridge: Clear offload_fwd_mark when passing frame up bridge interface.
+    - gpio: gpio-vf610: do not touch other bits when set the target bit
+    - gpio: mvebu/pwm: Refuse requests with inverted polarity
+    - perf bench numa: Address compiler error on s390
+    - scsi: qla2xxx: Fix missed DMA unmap for aborted commands
+    - mac80211: fix rx reordering with non explicit / psmp ack policy
+    - selftests: add ping test with ping_group_range tuned
+    - ethernet: tulip: fix missing pci_disable_device() on error in
+      tulip_init_one()
+    - net: stmmac: fix missing pci_disable_device() on error in stmmac_pci_probe()
+    - net: atlantic: verify hw_head_ lies within TX buffer ring
+    - Input: ili210x - fix reset timing
+    - block: return ELEVATOR_DISCARD_MERGE if possible
+    - net: stmmac: disable Split Header (SPH) for Intel platforms
+    - firmware_loader: use kernel credentials when reading firmware
+    - ARM: dts: imx7: Use audio_mclk_post_div instead audio_mclk_root_clk
+    - Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE""
+    - x86/xen: fix booting 32-bit pv guest
+    - x86/xen: Mark cpu_bringup_and_idle() as dead_end_function
+    - i2c: mt7621: fix missing clk_disable_unprepare() on error in mtk_i2c_probe()
+    - afs: Fix afs_getattr() to refetch file status if callback break occurred
+    - Linux 5.4.196
+  * 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()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Mon, 19 Sep 2022 00:41:11 +0800
+
+linux-imx (5.4.0-1025.31) focal; urgency=medium
+
+  * [X6MED][Feature] Bluetooth - no FW license & cannot initialise (LP:
+    #1933593)
+    - [Config] imx: armhf: CONFIG_IMX_SDMA=y
+
+  [ Ubuntu: 5.4.0-125.141 ]
+
+  * focal/linux: 5.4.0-125.141 -proposed tracker (LP: #1983947)
+  * nbd: requests can become stuck when disconnecting from server with qemu-nbd
+    (LP: #1896350)
+    - blk-mq: blk-mq: provide forced completion method
+    - blk-mq: move failure injection out of blk_mq_complete_request
+    - nbd: don't handle response without a corresponding request message
+    - nbd: make sure request completion won't concurrent
+    - nbd: don't clear 'NBD_CMD_INFLIGHT' flag if request is not completed
+    - nbd: fix io hung while disconnecting device
+  * CVE-2021-33656
+    - vt: drop old FONT ioctls
+  * CVE-2021-33061
+    - ixgbe: add the ability for the PF to disable VF link state
+    - ixgbe: add improvement for MDD response functionality
+    - ixgbevf: add disable link state
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 30 Aug 2022 18:28:39 +0800
+
+linux-imx (5.4.0-1024.29) focal; urgency=medium
+
+  * [Reading] Tracking bug for wireless support (LP: #1985008)
+    - SAUCE: net: wireless: brcmfmac: Add path for cypress firmware.
+    - SAUCE: net: wireless: brcmfmac: Support for CYW43439 SDIO
+    - brcmfmac: support 43439 Cypress Vendor and Device ID
+    - brcmfmac: add CYW43439 SR related changes
+
+  * [Reading] Tracking bug for kernel support (LP: #1985002)
+    - net: phy: dp83867: fix hfs boot in rgmii mode
+    - net: dp83867: Fix OF_MDIO config check
+    - SAUCE: arm64: dts: Support msc-sm2s-imx8mlc-mini.
+    - SAUCE: arm64: dts: msc-sm2-imx8m_mlc: Support Keurig.
+    - SAUCE: arm64: dts: imx8mlc_mini: build KDRP device tree
+    - SAUCE: arm64: dts: msc-sm2-imx8m_mlc: Added extcon entry for usb otg.
+    - arm64: dts: imx8mm: Remove incorrect fallback compatible for ocotp
+    - arm64: dts: imx8mm-evk: Assigned clocks for audio plls
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8mm-evk: Assigned clocks for audio plls
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8m: change ocotp node name on i.MX8M SoCs
+    - arm64: dts: imx8mm: add GPC node
+    - arm64: dts: imx8mm: Add the pcie support
+    - arm64: dts: imx8mm: Add the pcie phy support
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Correct pcie phy node.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Add enet wakeup support,
+      including the irq wakeup property.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Add dispmix-reset node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Define lcdif/dsi resets
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: Increase cma size
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add csi bridge and mipi csi
+      node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add fsl,dataline for SAI
+      node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add caam snvs and secvio
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add caam snvs clock
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add secure memory
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add the resets pcie
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add gpu device
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: add pcie ep support
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: use_dt_domains for pci node
+    - SAUCE: arm64: dts: msc-sm2s-imx8mlc-mini-module: assign osc_24m to dsi PHY
+      REF clock source
+    - arm64: dts: imx8m: add NVMEM provider and consumer to read soc unique ID
+    - SAUCE: arm64: dts: msc-sm2s-imx8mm_mlc: Added usb over current settings.
+    - SAUCE: drm: Add panel driver for AVD101WX-CN.
+    - SAUCE: drm: Updated panel driver for AVD101WX-CN.
+    - SAUCE: drm: Updated panel driver for AVD101WX-CN init sequence and timing.
+    - SAUCE: arm64: dts: msc-sm2s-imx8mm_mlc: Fixed USB0 otg support.
+    - SAUCE: drm: Fixed AVD101WX-CN display resolution.
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Changed GPIO10 to wifi enable.
+    - SAUCE: irqchip: imx: Corrected typo
+    - drm/panel: add backlight support
+    - MLK-14392-1 input: touch: add focaltech touch screen support
+    - LF-2653 drm/imx: lcdif: implement mode_valid() for CRTC
+    - reset: Kconfig: use 'ARCH_MXC' for reset dispmix
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm-04N0830E-module: add optee device node
+    - [Config] add AVD-TT101WX-CN touchscreen panel
+    - SAUCE: arm64: dts: kdp-sm2s-imx8mm: Use native RTS/CTS functionality of
+      uart2.
+    - drm/drm_panel: no error when no callback
+    - [Config] CONFIG_DRM_IMX_LCDIF=y
+
+  [ Ubuntu: 5.4.0-124.140 ]
+
+  * CVE-2022-2586
+    - SAUCE: netfilter: nf_tables: do not allow SET_ID to refer to another table
+    - SAUCE: netfilter: nf_tables: do not allow RULE_ID to refer to another chain
+  * CVE-2022-2588
+    - SAUCE: net_sched: cls_route: remove from list when handle is 0
+  * CVE-2022-34918
+    - netfilter: nf_tables: stricter validation of element data
+
+  [ Ubuntu: 5.4.0-123.139 ]
+
+  * focal/linux: 5.4.0-123.139 -proposed tracker (LP: #1981284)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.07.11)
+  * Hairpin traffic does not work with centralized NAT gw (LP: #1967856)
+    - net: openvswitch: fix misuse of the cached connection on tuple changes
+  * [UBUNTU 20.04] Include patches to avoid self-detected stall with Secure
+    Execution (LP: #1979296)
+    - KVM: s390: pv: add macros for UVC CC values
+    - KVM: s390: pv: avoid stalls when making pages secure
+    - KVM: s390: pv: avoid stalls for kvm_s390_pv_init_vm
+  * Focal update: v5.4.195 upstream stable release (LP: #1980407)
+    - batman-adv: Don't skb_split skbuffs with frag_list
+    - hwmon: (tmp401) Add OF device ID table
+    - mac80211: Reset MBSSID parameters upon connection
+    - net: Fix features skip in for_each_netdev_feature()
+    - ipv4: drop dst in multicast routing path
+    - drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name()
+    - netlink: do not reset transport header in netlink_recvmsg()
+    - mac80211_hwsim: call ieee80211_tx_prepare_skb under RCU protection
+    - dim: initialize all struct fields
+    - hwmon: (ltq-cputemp) restrict it to SOC_XWAY
+    - s390/ctcm: fix variable dereferenced before check
+    - s390/ctcm: fix potential memory leak
+    - s390/lcs: fix variable dereferenced before check
+    - net/sched: act_pedit: really ensure the skb is writable
+    - net/smc: non blocking recvmsg() return -EAGAIN when no data and
+      signal_pending
+    - net: sfc: ef10: fix memory leak in efx_ef10_mtd_probe()
+    - gfs2: Fix filesystem block deallocation for short writes
+    - hwmon: (f71882fg) Fix negative temperature
+    - ASoC: max98090: Reject invalid values in custom control put()
+    - ASoC: max98090: Generate notifications on changes for custom control
+    - ASoC: ops: Validate input values in snd_soc_put_volsw_range()
+    - s390: disable -Warray-bounds
+    - net: emaclite: Don't advertise 1000BASE-T and do auto negotiation
+    - tcp: resalt the secret every 10 seconds
+    - tty: n_gsm: fix mux activation issues in gsm_config()
+    - usb: cdc-wdm: fix reading stuck on device close
+    - usb: typec: tcpci: Don't skip cleanup in .remove() on error
+    - USB: serial: pl2303: add device id for HP LM930 Display
+    - USB: serial: qcserial: add support for Sierra Wireless EM7590
+    - USB: serial: option: add Fibocom L610 modem
+    - USB: serial: option: add Fibocom MA510 modem
+    - slimbus: qcom: Fix IRQ check in qcom_slim_probe
+    - serial: 8250_mtk: Fix UART_EFR register address
+    - serial: 8250_mtk: Fix register address for XON/XOFF character
+    - drm/nouveau/tegra: Stop using iommu_present()
+    - i40e: i40e_main: fix a missing check on list iterator
+    - cgroup/cpuset: Remove cpus_allowed/mems_allowed setup in cpuset_init_smp()
+    - drm/vmwgfx: Initialize drm_mode_fb_cmd2
+    - MIPS: fix build with gcc-12
+    - net: phy: Fix race condition on link status change
+    - arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map
+    - ping: fix address binding wrt vrf
+    - tty/serial: digicolor: fix possible null-ptr-deref in digicolor_uart_probe()
+    - Linux 5.4.195
+  * Focal update: v5.4.194 upstream stable release (LP: #1980399)
+    - MIPS: Use address-of operator on section symbols
+    - block: drbd: drbd_nl: Make conversion to 'enum drbd_ret_code' explicit
+    - drm/amd/display/dc/gpio/gpio_service: Pass around correct dce_{version,
+      environment} types
+    - drm/i915: Cast remain to unsigned long in eb_relocate_vma
+    - nfp: bpf: silence bitwise vs. logical OR warning
+    - can: grcan: grcan_probe(): fix broken system id check for errata workaround
+      needs
+    - can: grcan: only use the NAPI poll budget for RX
+    - arm: remove CONFIG_ARCH_HAS_HOLES_MEMORYMODEL
+    - [Config] updateconfigs for ARCH_HAS_HOLES_MEMORYMODEL
+    - KVM: x86/pmu: Refactoring find_arch_event() to pmc_perf_hw_id()
+    - x86/asm: Allow to pass macros to __ASM_FORM()
+    - x86: xen: kvm: Gather the definition of emulate prefixes
+    - x86: xen: insn: Decode Xen and KVM emulate-prefix signature
+    - x86: kprobes: Prohibit probing on instruction which has emulate prefix
+    - KVM: x86/svm: Account for family 17h event renumberings in
+      amd_pmc_perf_hw_id
+    - Bluetooth: Fix the creation of hdev->name
+    - mm: fix missing cache flush for all tail pages of compound page
+    - mm: hugetlb: fix missing cache flush in copy_huge_page_from_user()
+    - mm: userfaultfd: fix missing cache flush in mcopy_atomic_pte() and
+      __mcopy_atomic()
+    - Linux 5.4.194
+  * Focal update: v5.4.193 upstream stable release (LP: #1979566)
+    - MIPS: Fix CP0 counter erratum detection for R4k CPUs
+    - parisc: Merge model and model name into one line in /proc/cpuinfo
+    - ALSA: fireworks: fix wrong return count shorter than expected by 4 bytes
+    - gpiolib: of: fix bounds check for 'gpio-reserved-ranges'
+    - Revert "SUNRPC: attempt AF_LOCAL connect on setup"
+    - firewire: fix potential uaf in outbound_phy_packet_callback()
+    - firewire: remove check of list iterator against head past the loop body
+    - firewire: core: extend card->lock in fw_core_handle_bus_reset
+    - ACPICA: Always create namespace nodes using acpi_ns_create_node()
+    - genirq: Synchronize interrupt thread startup
+    - ASoC: da7219: Fix change notifications for tone generator frequency
+    - ASoC: wm8958: Fix change notifications for DSP controls
+    - ASoC: meson: Fix event generation for G12A tohdmi mux
+    - s390/dasd: fix data corruption for ESE devices
+    - s390/dasd: prevent double format of tracks for ESE devices
+    - s390/dasd: Fix read for ESE with blksize < 4k
+    - s390/dasd: Fix read inconsistency for ESE DASD devices
+    - can: grcan: grcan_close(): fix deadlock
+    - can: grcan: use ofdev->dev when allocating DMA memory
+    - nfc: replace improper check device_is_registered() in netlink related
+      functions
+    - NFC: netlink: fix sleep in atomic bug when firmware download timeout
+    - hwmon: (adt7470) Fix warning on module removal
+    - ASoC: dmaengine: Restore NULL prepare_slave_config() callback
+    - RDMA/siw: Fix a condition race issue in MPA request processing
+    - net: ethernet: mediatek: add missing of_node_put() in mtk_sgmii_init()
+    - net: stmmac: dwmac-sun8i: add missing of_node_put() in
+      sun8i_dwmac_register_mdio_mux()
+    - net: emaclite: Add error handling for of_address_to_resource()
+    - selftests: mirror_gre_bridge_1q: Avoid changing PVID while interface is
+      operational
+    - bnxt_en: Fix possible bnxt_open() failure caused by wrong RFS flag
+    - smsc911x: allow using IRQ0
+    - btrfs: always log symlinks in full mode
+    - net: igmp: respect RCU rules in ip_mc_source() and ip_mc_msfilter()
+    - drm/amdkfd: Use drm_priv to pass VM from KFD to amdgpu
+    - NFSv4: Don't invalidate inode attributes on delegation return
+    - kvm: x86/cpuid: Only provide CPUID leaf 0xA if host has architectural PMU
+    - x86/kvm: Preserve BSP MSR_KVM_POLL_CONTROL across suspend/resume
+    - KVM: LAPIC: Enable timer posted-interrupt only when mwait/hlt is advertised
+    - net: ipv6: ensure we call ipv6_mc_down() at most once
+    - block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kern
+    - mm: fix unexpected zeroed page mapping with zram swap
+    - ALSA: pcm: Fix races among concurrent hw_params and hw_free calls
+    - ALSA: pcm: Fix races among concurrent read/write and buffer changes
+    - ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls
+    - ALSA: pcm: Fix races among concurrent prealloc proc writes
+    - ALSA: pcm: Fix potential AB/BA lock with buffer_mutex and mmap_lock
+    - tcp: make sure treq->af_specific is initialized
+    - dm: fix mempool NULL pointer race when completing IO
+    - dm: interlock pending dm_io and dm_wait_for_bios_completion
+    - PCI: aardvark: Clear all MSIs at setup
+    - PCI: aardvark: Fix reading MSI interrupt number
+    - mmc: rtsx: add 74 Clocks in power on flow
+    - Linux 5.4.193
+  * CVE-2022-1679
+    - SAUCE: ath9k: fix use-after-free in ath9k_hif_usb_rx_cb
+  * CVE-2022-28893
+    - SUNRPC: Ensure we flush any closed sockets before xs_xprt_free()
+    - SUNRPC: Don't leak sockets in xs_local_connect()
+  * CVE-2022-1734
+    - nfc: nfcmrvl: main: reorder destructive operations in
+      nfcmrvl_nci_unregister_dev to avoid bugs
+  * CVE-2022-1652
+    - floppy: use a statically allocated error counter
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Sun, 14 Aug 2022 19:45:48 +0800
+
+linux-imx (5.4.0-1023.28) focal; urgency=medium
+
+  * Focal update: upstream stable patchset v5.4.192 (LP: #1979014)
+    - [Config] updateconfigs for NVM
+
+  * [uc20-x01] System can not wake up from suspend. (LP: #1976604)
+    - soc: imx: gpcv2: support system suspend/resume
+    - SAUCE: imx7: Suspend/Resume updates
+
+  * [PE100A][Core] The system shutdown because the critial temperature of
+    thermal should be config to 105'c not 90'c (LP: #1982989)
+    - SAUCE: imx/pe100a: dts: Set GPU/VPU crit temprature to 105
+
+  [ Ubuntu: 5.4.0-122.138 ]
+
+  * focal/linux: 5.4.0-122.138 -proposed tracker (LP: #1979489)
+  * Remove SAUCE patches from test_vxlan_under_vrf.sh in net of
+    ubuntu_kernel_selftests (LP: #1975691)
+    - Revert "UBUNTU: SAUCE: selftests: net: Don't fail test_vxlan_under_vrf on
+      xfail"
+    - Revert "UBUNTU: SAUCE: selftests: net: Make test for VXLAN underlay in non-
+      default VRF an expected failure"
+  * Enable Asus USB-BT500 Bluetooth dongle(0b05:190e) (LP: #1976613)
+    - Bluetooth: btusb: Add flag to define wideband speech capability
+    - Bluetooth: btrtl: Add support for RTL8761B
+    - Bluetooth: btusb: Add 0x0b05:0x190e Realtek 8761BU (ASUS BT500) device.
+  * [UBUNTU 20.04] rcu stalls with many storage key guests (LP: #1975582)
+    - s390/gmap: voluntarily schedule during key setting
+    - s390/mm: use non-quiescing sske for KVM switch to keyed guest
+  * Ubuntu 5.4.0-117.132-generic 5.4.189 has BUG: kernel NULL pointer
+    dereference, address: 0000000000000034 (LP: #1978719)
+    - mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()
+  * Focal update: upstream stable patchset v5.4.192 (LP: #1979014)
+    - floppy: disable FDRAWCMD by default
+    - [Config] updateconfigs for BLK_DEV_FD_RAWCMD
+    - hamradio: defer 6pack kfree after unregister_netdev
+    - hamradio: remove needs_free_netdev to avoid UAF
+    - lightnvm: disable the subsystem
+    - [Config] updateconfigs for NVM, NVM_PBLK
+    - usb: mtu3: fix USB 3.0 dual-role-switch from device to host
+    - USB: quirks: add a Realtek card reader
+    - USB: quirks: add STRING quirk for VCOM device
+    - USB: serial: whiteheat: fix heap overflow in WHITEHEAT_GET_DTR_RTS
+    - USB: serial: cp210x: add PIDs for Kamstrup USB Meter Reader
+    - USB: serial: option: add support for Cinterion MV32-WA/MV32-WB
+    - USB: serial: option: add Telit 0x1057, 0x1058, 0x1075 compositions
+    - xhci: stop polling roothubs after shutdown
+    - xhci: increase usb U3 -> U0 link resume timeout from 100ms to 500ms
+    - iio: dac: ad5592r: Fix the missing return value.
+    - iio: dac: ad5446: Fix read_raw not returning set value
+    - iio: magnetometer: ak8975: Fix the error handling in ak8975_power_on()
+    - usb: misc: fix improper handling of refcount in uss720_probe()
+    - usb: typec: ucsi: Fix role swapping
+    - usb: gadget: uvc: Fix crash when encoding data for usb request
+    - usb: gadget: configfs: clear deactivation flag in
+      configfs_composite_unbind()
+    - usb: dwc3: core: Fix tx/rx threshold settings
+    - usb: dwc3: gadget: Return proper request status
+    - serial: imx: fix overrun interrupts in DMA mode
+    - serial: 8250: Also set sticky MCR bits in console restoration
+    - serial: 8250: Correct the clock for EndRun PTP/1588 PCIe device
+    - arch_topology: Do not set llc_sibling if llc_id is invalid
+    - hex2bin: make the function hex_to_bin constant-time
+    - hex2bin: fix access beyond string end
+    - video: fbdev: udlfb: properly check endpoint type
+    - arm64: dts: meson: remove CPU opps below 1GHz for G12B boards
+    - arm64: dts: meson: remove CPU opps below 1GHz for SM1 boards
+    - mtd: rawnand: fix ecc parameters for mt7622
+    - USB: Fix xhci event ring dequeue pointer ERDP update issue
+    - ARM: dts: imx6qdl-apalis: Fix sgtl5000 detection issue
+    - phy: samsung: Fix missing of_node_put() in exynos_sata_phy_probe
+    - phy: samsung: exynos5250-sata: fix missing device put in probe error paths
+    - ARM: OMAP2+: Fix refcount leak in omap_gic_of_init
+    - phy: ti: omap-usb2: Fix error handling in omap_usb2_enable_clocks
+    - ARM: dts: at91: Map MCLK for wm8731 on at91sam9g20ek
+    - phy: mapphone-mdm6600: Fix PM error handling in phy_mdm6600_probe
+    - phy: ti: Add missing pm_runtime_disable() in serdes_am654_probe
+    - ARM: dts: Fix mmc order for omap3-gta04
+    - ARM: dts: am3517-evm: Fix misc pinmuxing
+    - ARM: dts: logicpd-som-lv: Fix wrong pinmuxing on OMAP35
+    - ipvs: correctly print the memory size of ip_vs_conn_tab
+    - mtd: rawnand: Fix return value check of wait_for_completion_timeout
+    - bpf, lwt: Fix crash when using bpf_skb_set_tunnel_key() from bpf_xmit lwt
+      hook
+    - tcp: md5: incorrect tcp_header_len for incoming connections
+    - tcp: ensure to use the most recently sent skb when filling the rate sample
+    - sctp: check asoc strreset_chunk in sctp_generate_reconf_event
+    - ARM: dts: imx6ull-colibri: fix vqmmc regulator
+    - arm64: dts: imx8mn-ddr4-evk: Describe the 32.768 kHz PMIC clock
+    - pinctrl: pistachio: fix use of irq_of_parse_and_map()
+    - cpufreq: fix memory leak in sun50i_cpufreq_nvmem_probe
+    - net: hns3: add validity check for message data length
+    - net/smc: sync err code when tcp connection was refused
+    - ip_gre: Make o_seqno start from 0 in native mode
+    - tcp: fix potential xmit stalls caused by TCP_NOTSENT_LOWAT
+    - bus: sunxi-rsb: Fix the return value of sunxi_rsb_device_create()
+    - clk: sunxi: sun9i-mmc: check return value after calling
+      platform_get_resource()
+    - net: bcmgenet: hide status block before TX timestamping
+    - net: dsa: lantiq_gswip: Don't set GSWIP_MII_CFG_RMII_CLK
+    - drm/amd/display: Fix memory leak in dcn21_clock_source_create
+    - tls: Skip tls_append_frag on zero copy size
+    - bnx2x: fix napi API usage sequence
+    - ixgbe: ensure IPsec VF<->PF compatibility
+    - tcp: fix F-RTO may not work correctly when receiving DSACK
+    - ASoC: wm8731: Disable the regulator when probing fails
+    - ip6_gre: Avoid updating tunnel->tun_hlen in __gre6_xmit()
+    - x86: __memcpy_flushcache: fix wrong alignment if size > 2^32
+    - cifs: destage any unwritten data to the server before calling
+      copychunk_write
+    - drivers: net: hippi: Fix deadlock in rr_close()
+    - net: ethernet: stmmac: fix write to sgmii_adapter_base
+    - x86/cpu: Load microcode during restore_processor_state()
+    - tty: n_gsm: fix wrong signal octet encoding in convergence layer type 2
+    - tty: n_gsm: fix malformed counter for out of frame data
+    - netfilter: nft_socket: only do sk lookups when indev is available
+    - tty: n_gsm: fix insufficient txframe size
+    - tty: n_gsm: fix missing explicit ldisc flush
+    - tty: n_gsm: fix wrong command retry handling
+    - tty: n_gsm: fix wrong command frame length field encoding
+    - tty: n_gsm: fix incorrect UA handling
+    - hugetlbfs: get unmapped area below TASK_UNMAPPED_BASE for hugetlbfs
+    - mm, hugetlb: allow for "high" userspace addresses
+    - Linux 5.4.192
+  * CVE-2022-1789
+    - KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID
+  * Focal update: v5.4.191 upstream stable release (LP: #1976116)
+    - etherdevice: Adjust ether_addr* prototypes to silence -Wstringop-overead
+    - mm: page_alloc: fix building error on -Werror=array-compare
+    - tracing: Dump stacktrace trigger to the corresponding instance
+    - gfs2: assign rgrp glock before compute_bitstructs
+    - tcp: fix race condition when creating child sockets from syncookies
+    - tcp: Fix potential use-after-free due to double kfree()
+    - ALSA: usb-audio: Clear MIDI port active flag after draining
+    - ASoC: atmel: Remove system clock tree configuration for at91sam9g20ek
+    - ASoC: msm8916-wcd-digital: Check failure for devm_snd_soc_register_component
+    - dmaengine: imx-sdma: Fix error checking in sdma_event_remap
+    - dmaengine: mediatek:Fix PM usage reference leak of
+      mtk_uart_apdma_alloc_chan_resources
+    - igc: Fix infinite loop in release_swfw_sync
+    - igc: Fix BUG: scheduling while atomic
+    - rxrpc: Restore removed timer deletion
+    - net/smc: Fix sock leak when release after smc_shutdown()
+    - net/packet: fix packet_sock xmit return value checking
+    - net/sched: cls_u32: fix possible leak in u32_init_knode()
+    - l3mdev: l3mdev_master_upper_ifindex_by_index_rcu should be using
+      netdev_master_upper_dev_get_rcu
+    - netlink: reset network and mac headers in netlink_dump()
+    - selftests: mlxsw: vxlan_flooding: Prevent flooding of unwanted packets
+    - ARM: vexpress/spc: Avoid negative array index when !SMP
+    - reset: tegra-bpmp: Restore Handle errors in BPMP response
+    - platform/x86: samsung-laptop: Fix an unsigned comparison which can never be
+      negative
+    - ALSA: usb-audio: Fix undefined behavior due to shift overflowing the
+      constant
+    - vxlan: fix error return code in vxlan_fdb_append
+    - cifs: Check the IOCB_DIRECT flag, not O_DIRECT
+    - mt76: Fix undefined behavior due to shift overflowing the constant
+    - brcmfmac: sdio: Fix undefined behavior due to shift overflowing the constant
+    - dpaa_eth: Fix missing of_node_put in dpaa_get_ts_info()
+    - drm/msm/mdp5: check the return of kzalloc()
+    - net: macb: Restart tx only if queue pointer is lagging
+    - scsi: qedi: Fix failed disconnect handling
+    - stat: fix inconsistency between struct stat and struct compat_stat
+    - EDAC/synopsys: Read the error count from the correct register
+    - oom_kill.c: futex: delay the OOM reaper to allow time for proper futex
+      cleanup
+    - ata: pata_marvell: Check the 'bmdma_addr' beforing reading
+    - dma: at_xdmac: fix a missing check on list iterator
+    - drm/panel/raspberrypi-touchscreen: Avoid NULL deref if not initialised
+    - drm/panel/raspberrypi-touchscreen: Initialise the bridge in prepare
+    - KVM: PPC: Fix TCE handling for VFIO
+    - drm/vc4: Use pm_runtime_resume_and_get to fix pm_runtime_get_sync() usage
+    - powerpc/perf: Fix power9 event alternatives
+    - xtensa: patch_text: Fixup last cpu should be master
+    - xtensa: fix a7 clobbering in coprocessor context load/store
+    - openvswitch: fix OOB access in reserve_sfa_size()
+    - ASoC: soc-dapm: fix two incorrect uses of list iterator
+    - e1000e: Fix possible overflow in LTR decoding
+    - ARC: entry: fix syscall_trace_exit argument
+    - arm_pmu: Validate single/group leader events
+    - ext4: fix symlink file size not match to file content
+    - ext4: fix use-after-free in ext4_search_dir
+    - ext4, doc: fix incorrect h_reserved size
+    - ext4: fix overhead calculation to account for the reserved gdt blocks
+    - ext4: force overhead calculation if the s_overhead_cluster makes no sense
+    - jbd2: fix a potential race while discarding reserved buffers after an abort
+    - spi: atmel-quadspi: Fix the buswidth adjustment between spi-mem and
+      controller
+    - staging: ion: Prevent incorrect reference counting behavour
+    - block/compat_ioctl: fix range check in BLKGETSIZE
+    - Linux 5.4.191
+  * Focal update: v5.4.190 upstream stable release (LP: #1973085)
+    - memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probe
+    - net/sched: flower: fix parsing of ethertype following VLAN header
+    - veth: Ensure eth header is in skb's linear part
+    - gpiolib: acpi: use correct format characters
+    - mlxsw: i2c: Fix initialization error flow
+    - net/sched: fix initialization order when updating chain 0 head
+    - net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link
+    - net/sched: taprio: Check if socket flags are valid
+    - cfg80211: hold bss_lock while updating nontrans_list
+    - drm/msm/dsi: Use connector directly in msm_dsi_manager_connector_init()
+    - net/smc: Fix NULL pointer dereference in smc_pnet_find_ib()
+    - sctp: Initialize daddr on peeled off socket
+    - testing/selftests/mqueue: Fix mq_perf_tests to free the allocated cpu set
+    - nfc: nci: add flush_workqueue to prevent uaf
+    - cifs: potential buffer overflow in handling symlinks
+    - drm/amd: Add USBC connector ID
+    - drm/amd/display: fix audio format not updated after edid updated
+    - drm/amd/display: Update VTEM Infopacket definition
+    - drm/amdkfd: Fix Incorrect VMIDs passed to HWS
+    - drm/amdkfd: Check for potential null return of kmalloc_array()
+    - Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
+    - scsi: target: tcmu: Fix possible page UAF
+    - scsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024
+    - ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs
+    - gpu: ipu-v3: Fix dev_dbg frequency output
+    - regulator: wm8994: Add an off-on delay for WM8994 variant
+    - arm64: alternatives: mark patch_alternative() as `noinstr`
+    - tlb: hugetlb: Add more sizes to tlb_remove_huge_tlb_entry
+    - net: usb: aqc111: Fix out-of-bounds accesses in RX fixup
+    - drm/amd/display: Fix allocate_mst_payload assert on resume
+    - powerpc: Fix virt_addr_valid() for 64-bit Book3E & 32-bit
+    - scsi: mvsas: Add PCI ID of RocketRaid 2640
+    - scsi: megaraid_sas: Target with invalid LUN ID is deleted during scan
+    - drivers: net: slip: fix NPD bug in sl_tx_timeout()
+    - perf/imx_ddr: Fix undefined behavior due to shift overflowing the constant
+    - mm, page_alloc: fix build_zonerefs_node()
+    - mm: kmemleak: take a full lowmem check in kmemleak_*_phys()
+    - gcc-plugins: latent_entropy: use /dev/urandom
+    - ath9k: Properly clear TX status area before reporting to mac80211
+    - ath9k: Fix usage of driver-private space in tx_info
+    - btrfs: remove unused variable in btrfs_{start,write}_dirty_block_groups()
+    - btrfs: mark resumed async balance as writing
+    - ALSA: hda/realtek: Add quirk for Clevo PD50PNT
+    - ALSA: pcm: Test for "silence" field in struct "pcm_format_data"
+    - ipv6: fix panic when forwarding a pkt with no in6 dev
+    - drm/amd/display: don't ignore alpha property on pre-multiplied mode
+    - genirq/affinity: Consider that CPUs on nodes can be unbalanced
+    - tick/nohz: Use WARN_ON_ONCE() to prevent console saturation
+    - ARM: davinci: da850-evm: Avoid NULL pointer dereference
+    - dm integrity: fix memory corruption when tag_size is less than digest size
+    - smp: Fix offline cpu check in flush_smp_call_function_queue()
+    - i2c: pasemi: Wait for write xfers to finish
+    - dma-direct: avoid redundant memory sync for swiotlb
+    - 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()
+    - ax25: fix NPD bug in ax25_disconnect
+    - ax25: Fix NULL pointer dereferences in ax25 timers
+    - ax25: Fix UAF bugs in ax25 timers
+    - Linux 5.4.190
+
+  [ Ubuntu: 5.4.0-121.137 ]
+
+  * focal/linux: 5.4.0-121.137 -proposed tracker (LP: #1978666)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.05.30)
+  * CVE-2022-28388
+    - can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error
+      path
+  * test_vxlan_under_vrf.sh in net from ubuntu_kernel_selftests failed (Check VM
+    connectivity through VXLAN (underlay in the default VRF) [FAIL])
+    (LP: #1871015)
+    - selftests: net: test_vxlan_under_vrf: fix HV connectivity test
+  * [UBUNTU 20.04] CPU-MF: add extended counter set definitions for new IBM z16
+    (LP: #1974433)
+    - s390/cpumf: add new extended counter set for IBM z16
+  * [UBUNTU 20.04] KVM nesting support leaks too much memory, might result in
+    stalls during cleanup (LP: #1974017)
+    - KVM: s390: vsie/gmap: reduce gmap_rmap overhead
+  * [UBUNTU 20.04] Null Pointer issue in nfs code running Ubuntu on IBM Z
+    (LP: #1968096)
+    - NFS: Fix up nfs_ctx_key_to_expire()
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 10 Aug 2022 14:53:21 +0800
+
+linux-imx (5.4.0-1022.26) focal; urgency=medium
+
+  * [pe100a] WWAN primary port is missing after resume from suspend (LP:
+    #1981540)
+    - SAUCE: pe100a: Pull platform reset pin low before suspend
+
+  * [PE100A] Custom setup required for LAN1 LED (LP: #1978043)
+    - SAUCE: net: fec: Set custom PHY LED config for PE100A
+
+  * [PE100A] Remove CAN debug messages (LP: #1965849)
+    - SAUCE: imx/pe100a: CAN: Remove debug messages
+
+  * [PE100A] Refine 0016-ethernet-Asus-LAN2-feature-porting.patch (LP: #1970770)
+    - SAUCE: Revert igb changes introduced by "Asus LAN2 feature porting"
+
+  * [PE100A] Syncing between two RTCs doesn't really work (LP: #1967267)
+    - SAUCE: rtc: isl1208: Mark UIE unsupported if there is no IRQ defined
+    - SAUCE: rtc: bq32k: Mark UIE unsupported if there is no IRQ defined
+    - SAUCE: imx/pe100a: dts: Add RTC aliases
+
+  * [PE100A] PCI bus doesn't work if platform-reset is not set as built-in (LP:
+    #1967293)
+    - SAUCE: pe100a: reset: Toggle reset pin on resume only
+    - [Config] CONFIG_RESET_ASUS_PE100A=m
+
+  * [PE100A] systemd does not turn-off device by power key pressed (LP:
+    #1965751)
+    - SAUCE: dts: pe100a: Add clock-names to snvs_pwrkey
+    - [Config] imx: arm64: CONFIG_KEYBOARD_SNVS_PWRKEY=m
+
+  * HDMI not worked after boot kernel (LP: #1965475)
+    - [Config] Enlarge CMA size for higher display resolution
+
+  * [PE100A] Add RTC bq32000 (LP: #1965851)
+    - SAUCE: imx/pe100a: dts: Add RTC bq32000
+
+  * Import eth0 pinctrl changes (LP: #1965852)
+    - SAUCE: pinctrl: modify RGMII TX&RX SRE to slow and other config.
+
+  * [pe100a][us2004]Intel I211 eth didn't bring up (LP: #1965485)
+    - [Config] Enable E100/E1000/E1000E and IGB
+    - [Config] CONFIG_RESET_ASUS_PE100A=y
+
+  * [PE100A]Internal eMMC is not working (LP: #1958199)
+    - [Config] Add driver for REGULATOR_BD718XX
+
+  * [pe100a][us2004]Wireless module not worked (LP: #1965481)
+    - [Config] Enable ath10k
+
+  * [pe100a][us2004]HDMI not worked after boot kernel (LP: #1965475)
+    - clk: imx8mq: add 27MHz PHY ref clock
+    - arm64: dts: imx8mq: add dcss, hdmi and create imx8mq-evk-hdmi.dts file
+    - dts: arm: imx: add imx8mq hdmi
+    - arm64: dts: imx8mq: add DCSS node
+    - arm64: dts: imx8mq: use the DCSS DTRC interrupts
+    - arm64: dts: imx8mq: add DCSS external oscillator support
+    - SAUCE: Fix HDMI output on PE100A
+    - [Config] CONFIG_FB_EFI=n
+
+  * [X6MED][UC20] WARNING: CPU: 0 PID: 1 at arch/arm/mm/dump.c (LP: #1951783)
+    - ARM: add __arm_iomem_set_ro() to write-protect ioremapped area
+    - ARM: imx6: mark OCRAM mapping read-only
+
+  * [imx8-bms] RS485 Send and receive test failed (LP: #1978514)
+    - MLK-21309: dma: engine: sdma: add uart rom script
+    - serial: core: Initialize rs485 RTS polarity already on probe
+
+  * [US20.04][UC20] Camera does not work (LP: #1966824)
+    - SAUCE: dts: amgis: Fix clock used by ov9281_mipi and clock used by clko1.
+    - [Config] Enable REGULATOR_ANATOP as a built-in driver for armhf.
+
+  * [uc20-x01] Can't find audio playback device (LP: #1976600)
+    - SAUCE: ASoC: topology: Avoid card NULL deref in
+      snd_soc_tplg_component_remove()
+
+  * [US20.04]Display not showing imagery (LP: #1970656)
+    - SAUCE: gpu: drm: panel: simple-panel: add DLC0430DCP10RF-2 support
+    - drm/mxsfb: Update mxsfb to support a bridge
+    - drm/mxsfb: Read bus flags from bridge if present
+    - drm/mxsfb: Add defines for the rest of registers
+    - drm/mxsfb: Reset vital registers for a proper initialization
+    - drm/mxsfb: Update register definitions using bit manipulation defines
+    - drm/mxsfb: Update mxsfb with additional pixel formats
+    - drm/mxsfb: Update mxsfb to support LCD reset
+    - drm/mxsfb: Clear OUTSTANDING_REQS bits
+    - MLK-24334-3: drm/mxsfb: Fix the LCD_RESET pin usage
+
+  * [US20.04] OV9281 camera sensor support (LP: #1966824)
+    - SAUCE: media: Add driver for OV9281
+    - SAUCE: media: Fix OV9281 module build and cleanup function names.
+    - SAUCE: media: capture: add grey pixel format used by ov9281 mipi driver.
+    - SAUCE: media: Fix OV9281 calls that search for regulators in the device
+      tree.
+    - SAUCE: dts: amgis: Fix pinctrl-0 for mipi-csi.
+    - [Config] Enable IMX_GPCV2_PM_DOMAINS for armhf.
+
+  * [US20.04] RPMSG driver support (LP: #1968362)
+    - rpmsg: imx: add the initial imx rpmsg support
+    - dt-binding: add imx rpmsg compatibility documentation
+    - rpmsg: imx: extend the rpmsg support for imx8qm and so on
+    - rpmsg: imx: bug fix and clean up the codes
+    - rpmsg: imx_rpmsg: add partition reset notify
+    - rpmsg: imx: enable the tx_block mechanism in the flow
+    - imx-mailbox: add state save and restore
+    - mailbox: imx: change to arch_init()
+    - mailbox: imx: add support for imx v1 mu
+    - SAUCE: ARM: imx: Define M4 related APIs in headers.
+    - clk: imx7d: add A7-M4 AMP power management support
+    - ARM: imx: add i.MX7D bus-freq support
+    - SAUCE: ARM: imx: Add type definition for LPDDR3.
+    - SAUCE: ARM: imx: add suspend/resume support needed for imx7 rpmsg
+      communication with the M4 core.
+    - ARM: imx: add i.MX7D power management support
+    - arm: arch: enable rpmsg for imx amp soc
+    - arm: imx: rename the compatible node of lpm mu driver
+    - MLK-23008 ARM: imx: Remove unused code on i.MX7D suspend driver
+    - LF-1011-26 arm: imx: pm-imx7: fix build break when calling of_flat_dt_match
+    - LF-1011-29 arm: imx: fix build break when calling of_flat_dt_match
+    - SAUCE: ARM: dts: Fix booting imx7 with added changes for
+      suspend/resume/power management.
+    - SAUCE: imx: Fix build error by including cpu type functions.
+    - SAUCE: dts: amgis: Enable rpmsg.
+    - [Config] Enable i.MX7D rpmsg support.
+    - SAUCE: dts: amgis: Fix booting without loading a bare metal m4 application.
+    - SAUCE: ARM: imx7: Use generic names per devicetree specification to fix
+      warnings from pm-imx7.
+    - SAUCE: ARM: imx7: Fix memory mapping for iram_tlb_io_desc by removing the
+      executable flag, resulting in a pagetable warning.
+
+  * [US20.04] Audio does not work (LP: #1966821)
+    - ASoC: tas2562: Introduce the TAS2562 amplifier
+    - ASoC: tas2562: Fix misuse of GENMASK macro
+    - ASoC: tas2562: Add support for digital volume control
+    - ASoC: tas2562: Fixed incorrect amp_level setting.
+    - ASoC: tas2562: Update shutdown GPIO property
+    - ASoC: tas2562: Update shutdown GPIO property
+    - ASoC: tas2562: Add the TAS2110 class-D amplifier
+    - [Config] CONFIG_SND_SOC_TAS2562=m on armhf
+
+  * Miscellaneous Ubuntu changes
+    - [Config] Enable i.MX7D
+    - SAUCE: arm: dts: add Amgis dts files
+    - SAUCE: dts: amgis: Device tree janitorial work
+    - SAUCE: dts: amgis: enable camera in device tree
+    - SAUCE: dts: amgis: use imx internal version of csi bridge/mipi csi node
+    - SAUCE: imx/pe100a: Add dts and defconfig for ASUS PE100A
+    - SAUCE: imx/pe100a: dts: Enable Rohm PMIC on ASUS PE100A
+    - SAUCE: imx/pe100a: dts: Updates for PE100A
+    - SAUCE: imx/pe100a: Add the platform-reset driver to control platform reset
+      gpio
+    - SAUCE: imx/pe100a: Rename the reset driver
+    - [Config] CONFIG_RESET_ASUS_PE100A=m
+    - SAUCE: imx/pe100a: HDMI: auto config physical address for cec
+    - SAUCE: imx/pe100a: hdmi-cec: Set pa only when a property is available
+    - SAUCE: imx/pe100a: HDMI: modify resolution upper limmit to 1920x1080 when
+      noEDID
+    - SAUCE: imx/pe100a: dts: Enable rtc-isl1208
+    - SAUCE: imx/pe100a: dts: Add cpu-alert/crit temperature
+    - SAUCE: imx/pe100a: defconfig: Import thermal config updates
+    - SAUCE: imx/pe100a: dts: Enable Wake-On-LAN
+    - SAUCE: imx/pe100a: extcon: it5201: add IT5201 Type-C CC logic chip
+    - [Config] imx/pe100a: CONFIG_EXTCON_IT5201=m
+    - SAUCE: imx/pe100a: ethernet: Asus LAN2 feature porting
+    - SAUCE: imx/pe100a: dts: EEPROM: support at24 eeprom
+    - SAUCE: imx/pe100a: dts: Audio: disable unavailable sound cards and SAI
+      configurations.
+    - SAUCE: imx/pe100a: defconfig: update defconfig for asus board
+    - SAUCE: imx/pe100a: Gpu: Change gpu shader frequency from 800MHz to 1GHz.
+    - SAUCE: imx/pe100a: CAN: Add MCP2515 support
+    - [Config] imx/pe100a: Enable CONFIG_CAN_MCP251X and CONFIG_CAN_DEBUG_DEVICES
+    - SAUCE: imx/pe100a: enable spi1 and add TCG_TIS_SPI support on 3.0
+    - SAUCE: imx/pe100a: defconfig: Add drivers for moby container engine
+    - SAUCE: imx/pe100a: Remove undefined labels
+    - SAUCE: imx/pe100a: extcon: Fix i2c_device_id array
+    - SAUCE: imx/pe100a: dts: Add usdhc clocks assignment
+    - SAUCE: reset-pe100a: Remove gpio_is_valid() check
+    - SAUCE: net: fec: Fix bit mask definitions
+    - SAUCE: imx/pe100a: Remove assigned PCI clock
+
+  * Miscellaneous upstream changes
+    - soc: imx: fix build error of missing imx_src_is_m4_enabled
+    - irqchip: irq-imx-gpcv2: Add workaround for i.MX8MQ ERR11171
+    - irqchip: irq-imx-gpcv2: Disable cpuidle if no GPC_CORE_WAKE in EL3
+    - irqchip: irq-imx-gpcv2: fix the suspend/resume on imx8mq
+    - MLK-21399 irqchip: Allow i.MX8MQ to call into TF-A
+    - LF-125 irqchip: irq-imx-gpcv2: Fix build error of nosmp
+    - irqchip: imx-gpcv2: Fix build error for imx_v6_v7_defconfig
+    - PCI: imx: add the l1ss feature on imx8m platforms
+    - PCI: imx: enable imx8 pcie pm support
+    - PCI: dwc: Use interrupt disabling instead of masking
+    - PCI: dwc: fix the msi failure after pm operations
+    - Revert "UBUNTU: SAUCE: net: fec: add imx8mq and imx8qm new versions support"
+    - net: fec: add imx8mq and imx8qm new versions support
+    - Revert "net: fec: fix system hang during suspend/resume"
+    - net: fec: add WoL support for i.MX8MQ
+    - net: fec: fix system hang during suspend/resume
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Wed, 13 Jul 2022 19:24:36 +0800
+
+linux-imx (5.4.0-1021.23) focal; urgency=medium
+
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2022.05.30)
+
+  * Focal update: v5.4.184 upstream stable release (LP: #1969242)
+    - [Config] updateconfigs for HARDEN_BRANCH_HISTORY
+
+  * [X6MED][UC20] CAAM crypto engine kernel panic (LP: #1967124)
+    - [Config] enable L2 cache L2X0 and its ERRATA for armhf
+
+  * [imx8-pdk][uc20-x03]Kernel panic while system go into suspend (LP: #1963629)
+    - net: fec: fix system hang during suspend/resume
+
+  * Need POSIX Calls Especially Message Queue (LP: #1944649)
+    - SAUCE: apparmor: move ptrace mediation to more logical task.{h,c}
+    - SAUCE: apparmor: fix setting unconfined mode on a loaded profile
+    - SAUCE: apparmor: fix overlapping attachment computation
+    - SAUCE: apparmor: allow label to carry debug flags
+    - SAUCE: apparmor: extend policydb permission set by making use of the xbits
+    - SAUCE: apparmor: Add fine grained mediation of posix mqueues
+
+  * Enable full-disk encryption (FDE) via OP-TEE (LP: #1953725)
+    - arm: imx: remove GPC low power mode switch
+
+  * [imx8-pdk][imx8-firecpu20][US20.04/UC20] RS-485 didn't worked (LP: #1934083)
+    - MLK-24708 spi: imx: handle EPROBE_DEFER when get cs-gpios number
+
+  * [imx8-pdk][Feature]M7 core (LP: #1935879)
+    - remoteproc: imx_rproc: parse fsl,auto-boot
+    - remoteproc: imx_rproc: initial support for mutilple start/stop method
+    - remoteproc: imx_rproc: make clk optional
+    - remoteproc: imx_rproc: support i.MX7ULP
+    - remoteproc: imx_rproc: support i.MX8MN/P
+    - remoteproc: imx_rproc: support i.MX8ULP
+    - remoteproc: imx_rproc: Fix TCM io memory type
+    - remoteproc: imx_rproc: Fix ignoring mapping vdev regions
+    - remoteproc: imx_rproc: Fix rsc-table name
+    - remoteproc: imx_rproc: Change to ioremap_wc for dram
+    - remoteproc: imx_rproc: Move common structure to header file
+    - remoteproc: imx_rproc: Fix a resource leak in the remove function
+    - remoteproc: imx_rproc: correct firmware reload
+    - MLK-23754-14 remoteproc: elf_loader: drop unneedded memset
+    - MLK-23754-19 remoteproc: add rproc_memcpy
+    - MLK-23754-21 remoteproc: imx_rproc: add imx memcpy functions
+    - SAUCE: remoteproc: imx_rproc: expand the clk array
+
+  * [imx8-pdk] USB port features and functions for OTG (LP: #1936038)
+    - SAUCE: extcon: fix the timer task timeout value
+    - SAUCE: usb: dwc3: add a switch to let drd use extcon on imx8mp
+
+  * [imx8-pdk][Feature]LVDS (LP: #1930804)
+    - MLK-23622-01 soc: imx: Add active wakeup flag for domain with active-wakeup
+      property
+    - MLK-23671-01 soc: imx: Add the rpm always on flag if necessary
+    - MLK-11293: gpio: pca953x: add device_reset() call
+    - gpio: pca953x: no need to do regcache sync without vcc regulator
+    - MLK-23602 gpio: pca953x: no need to show the warning of reg everytime
+
+  * [imx8-pdk] stress-ng cpu cache fail (LP: #1934105)
+    - arm64: dts: imx8m: add cache info
+
+  * [imx8-bms]MAC address not fixed after burned fuse (LP: #1942029)
+    - net: ethernet: add property "nvmem_macaddr_swap" to swap macaddr bytes order
+    - net: fec: add defer probe for of_get_mac_address
+
+  * imx8-pdk: emmc and sdhc index can't be fixed (LP: #1966163)
+    - mmc: add feature of setting slot index via devicetree alias
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: fix the clk for audio and gpu3d
+    - [Config] Enable AUDIOMIX and HDMIMIX reset
+    - SAUCE: clk: clk-imx8mp: Fix gpu2d clks
+    - [config] enable HDMI graphic and audio Kconfigs
+    - [Config] do not enforce reserved CMA sizes in kernel config
+    - [Config] update caam crypto configs
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC=y
+    - SAUCE: sdma: disable rt pm for imx8mp
+    - SAUCE: media: imx8: support to build as module
+
+  * Miscellaneous upstream changes
+    - mfd: Add audiomix support
+    - MA-17597-3 mfd: imx-audiomix: add license for module build
+    - MLK-23250-06: reset: Add hdmimix reset driver
+    - reset: imx: Add audiomix reset controller support
+    - MA-17913 reset: Allow reset-imx7/hdmimix/audiomix driver to be loadable as
+      module
+    - MLK-23159-4 clk: imx: Add i.MX8MP clock driver
+    - arm64: dts: imx8mp: Add clock and power domain to audiomix dts node
+    - MLK-23314-7: clk: imx: clk-audiomix: refine some muxes flags
+    - MLK-23680-1: clk: imx: clk-audiomix: remove sdma root clock
+    - MLK-23886-2: clk: imx: clk-audiomix: fix runtime PM
+    - clk: imx: clk-audiomix: Add SAI PLL frequencies
+    - clk: imx: clk-audiomix: fix PDM clocks
+    - MLK-24307-1 clk: imx: clk-audiomix: enable set parent rate for
+      IMX8MP_CLK_AUDIOMIX_PDM_SEL
+    - ASoC: fsl_sai: Add new added registers and new bit definition
+    - ASoC: fsl-asoc-card: Defer probe when fail to find codec device
+    - clk: imx: Remove the audio ipg clock from imx8mp
+    - MLK-16290 drm: Add drm_of_component_probe_with_match() helper
+    - drm/fourcc: add a 10bits fully packed variant of NV12
+    - drm/imx: Revert a patch which merges imx-drm-core and ipuv3-crtc in one
+      module
+    - drm/imx: Extract IPUv3 specific KMS functions to ipuv3-kms.c (part 1)
+    - drm/imx: Add DPU KMS support (part 2)
+    - MLK-22171 drm/imx: Avoid leaking dangling pointer dev->driver_data to PM ops
+    - MLK-18535-6 drm/imx: core: add LCDIF support
+    - gpu: imx: Add dpu common driver support
+    - drm/imx: Add DPU KMS support (part 1)
+    - MLK-21876-5 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-6 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-7 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-8 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-9 gpu: drm: dpu: fix build for next-20190524 upgrade
+    - MLK-21876-10 gpu: drm: dpu: fix headfile reference issue (part 1)
+    - gpu: imx: dpu: framegen: Use bypass clock when display encoder type is TMDS
+    - drm/imx: dpu: crtc: Specify encoder type for framegen_cfg_videomode()
+    - gpu: imx: dpu: framegen: add disp_lpcg clock
+    - MLK-15321-1 gpu: imx: dpu: Add dpu blit engine device
+    - gpu: imx: dpu: fetchunit: Add helper for TKT343664 to fixup burst size
+    - gpu: imx: dpu: fetchunit: Add helper for TKT339017 to fixup stride
+    - gpu: imx: dpu: fetchunit: Use TKT343664's fixup for ->set_burstlength()
+    - gpu: imx: dpu: fetchunit: Use TKT343664&TKT339017's fixups for
+      ->set_baseaddress()
+    - gpu: imx: dpu: fetchunit: Use TKT343664&TKT339017's fixups for
+      ->set_src_stride()
+    - gpu: imx: dpu: fetchunit: Add DPR support
+    - gpu: imx: dpu: Access regs in display engine units wo holding mutex
+    - drm/imx: dpu: crtc: Evade the first dumb frame for DPR/PRG errata
+    - drm/imx: dpu: kms: Add prefetch engine support
+    - drm/imx: dpu: kms: Return properly in case we fail to get plane state to
+      check
+    - drm/imx: dpu: kms: Ensure array idx k >= 0 before accessing sources[]
+    - drm/imx: dpu: crtc: Send vblank event after drm_crtc_vblank_off() in
+      ->atomic_disable()
+    - drm/imx: dpu: crtc: Do not send out bogus vblank event in ->atomic_disable()
+    - drm/imx: dpu: crtc: Remove WARN_ON(!crtc->state->event)
+    - drm/imx: dpu: crtc: Precisely send vbland event if CRTC is active
+    - gpu: imx: dpu: framegen: Add helpers to get/clear sec chan status
+    - drm/imx: dpu: crtc: Warn on FrameGen sec chan empty FIFO read request
+    - drm/imx: dpu: crtc: Wait for FrameGen secondary syncup in ->atomic_enable()
+    - drm/imx: dpu: kms: Support full screen CRTC background
+    - gpu: imx: dpu: Add helpers to peek at auxiliary display submodules
+    - gpu: imx: dpu: common: Add di_grp_id in display client pdev's data
+    - gpu: imx: dpu: common: Introduce master_stream_id in struct dpu_data
+    - gpu: imx: dpu: common: Add helper dpu_get_master_stream_id() support
+    - gpu: imx: dpu: framegen: Add framegen_is_master/slave() helper support
+    - gpu: imx: dpu: extdst: Add extdst_is_master() helper support
+    - gpu: imx: dpu: tcon: Add tcon_is_master/slave() helpers support
+    - gpu: imx: dpu: sc misc: Add helper dpu_pxlink_set_dc_sync_mode() support
+    - gpu: imx: dpu: framegen: Add side-by-side support
+    - gpu: imx: tcon: Add side-by-side support
+    - drm/imx: dpu: crtc: Set crtc group id
+    - drm/imx: dpu: crtc: Peek auxiliary CRTC resources
+    - gpu: imx: dpu: Add pixel combiner support
+    - gpu: imx: dpu: common: Set master stream id to be 1 for i.MX8QM DPU
+    - gpu: imx: dpu: common: Add store9 support for sync mode fixup
+    - gpu: imx: dpu: common: Provide store9 to client pdev via pdata
+    - gpu: imx: dpu: framegen: Add framegen_syncmode_fixup() helper
+    - gpu: imx: dpu: extdst: Add extdst_pixengcfg_syncmode_master() helper
+    - drm/imx: dpu: kms: Add pixel combiner support
+    - drm/imx: dpu: kms: Support proper default blend mode
+    - drm/imx: dpu: plane: Improve bailout path of dpu_plane_create()
+    - drm/imx: dpu: plane: Support full zpos range for planes
+    - drm/imx: dpu: plane: Support alpha in pixel for overlay planes
+    - drm/imx: dpu: plane: Support multiple pixel blend modes
+    - drm/imx: dpu: plane: Add color properties support
+    - gpu: imx: dpu: disengcfg: Do HW initialization in dpu_dec_init()
+    - gpu: imx: dpu: framegen: Cache encoder_type in struct dpu_framegen
+    - gpu: imx: dpu: common: Add flag has_dual_ldb in struct dpu_data
+    - gpu: imx: framegen: Don't enable/disable pixlnk when driving special encoder
+    - gpu: imx: dpu: sc misc: Rename dpu_sc_misc_init() to
+      dpu_sc_misc_get_handle()
+    - gpu: imx: dpu: sc misc: Rename dpu_pxlink_init() to dpu_sc_misc_init()
+    - LF-73 gpu: imx: dpu: sc misc: Initialze KACHUNK_CNT as needed by blit engine
+    - gpu: imx: dpu: common: Initialize SCU misc settings in dpu_resume()
+    - MLK-21378-1 gpu: imx: Add imx8_prg support
+    - MLK-21378-2 gpu: imx: Add imx8_dprc support
+    - gpu: imx: Add imx8 pixel combiner support
+    - drm/imx: ldb: Add i.MX8qm LDB support
+    - drm/imx: ldb: Add i.MX8qxp LDB support
+    - MLK-21876-23 drm/imx: ldb: fix incorrect color displayed for mx8qxp
+    - drm/imx: ldb: Add system power management support
+    - drm/imx: ldb: Add dual channel mode support for i.MX8QXP
+    - drm/imx: Extract IPUv3 specific KMS functions to ipuv3-kms.c (part 2)
+    - drm/imx: ipuv3-crtc: Rename some IPUv3 specific functions
+    - MLK-18535-3 gpu: imx: add LCDIF core driver
+    - MLK-18535-5 drm/imx: add LCDIF DRM/KMS driver
+    - gpu: imx: lcdif: break Kconfig recursive dependency
+    - MLK-18535-10 drm/imx: lcdif: limit the maximum resolution to '1920x1080'
+    - MLK-18560 drm/imx: lcdif: refine bus format sanity check for plane
+    - MLK-18605-14 drm/imx: lcdif: adjust 'max_height' for '1080x1920' mode
+    - MLK-19017-2 gpu: imx: add DISPMIX power domain support for LCDIF
+    - MLK-19017-3 gpu: imx: add system pm support for LCDIF
+    - MLK-19017-4 gpu: imx: lcdif: add rpm status check for suspend/resume
+    - MLK-19083 drm/imx: lcdif: remove untrue condition for pixel format set
+    - MLK-19112 gpu: imx: lcdif: change 'rpm_suspended' to be atomic counter
+    - MLK-19152-1 gpu: imx: lcdif: realize fb horizontal crop via Pigeon Mode
+    - MLK-19152-2 drm/imx: lcdif: force 'mode_changed' when fb width changed
+    - MLK-19152-3 drm/imx: lcdif: add horizontal crop support to plane update
+    - MLK-19199 drm/imx: lcdif: replace FB width usage for cropping
+    - MLK-19158-2 drm/imx: lcdif: improve output bus format config
+    - MLK-19158-3 gpu: imx: lcdif: fix output order for 16bpp BGR formats
+    - MLK-19158-4 drm/imx: lcdif: remove bus format check from PLANE's check
+    - MLK-19158-5 drm/imx: lcdif: add bus format check to CRTC's check
+    - MLK-19318 drm/imx: lcdif: avoid log print when no device attached
+    - MLK-19819-1 drm/imx: lcdif: bypass atomic check when CRTC will be disabled
+    - MLK-19819-2 Revert "MLK-19318 drm/imx: lcdif: avoid log print when no device
+      attached"
+    - MLK-20337 drm/imx: lcdif: block 'active CRTC with no plane' commit
+    - MLK-22158 drm/imx: lcdif: force 'mode_changed' for fb pix fmt change
+    - MLK-21876-10 gpu: drm: lcdif: fix headfile reference issue
+    - drm/imx: lcdif: change DISPMIX reset for IMX8MN
+    - gpu: imx: lcdif: fix build warnings if CONFIG_PM_SLEEP off
+    - drm/imx: Replace reset flow for LCDIF
+    - gpu: imx: lcdif: add imx8mn compatible support
+    - drm/bridge: Add ITE IT6263 LVDS to HDMI transmitter support
+    - MLK-18535-7 drm/bridge: sec-dsim: add bridge driver support
+    - MLK-19081 drm/bridge: sec-dsim: correct args of 'drm_bridge_attach' call
+    - MLK-18605-1 drm/bridge: sec-dsim: add cleanup when detach dsi client
+    - MLK-18605-2 drm/bridge: sec-dsim: allow same panel can be re-attached
+    - MLK-18605-3 drm/bridge: sec-dsim: refuse unknown dsi device attach
+    - MLK-18605-4 drm/bridge: sec-dsim: refine data lanes stop state check
+    - MLK-18605-5 drm/bridge: sec-dsim: correct 'DSIM_FIFOCTRL' offset
+    - MLK-18605-6 drm/bridge: sec-dsim: add fifo pointers initialization
+    - MLK-18605-7 drm/bridge: sec-dsim: correct a register macro misspelt
+    - MLK-18605-8 drm/bridge: sec-dsim: add non-continuous clock support
+    - MLK-18605-9 drm/bridge: sec-dsim: increase timeout values for BTA and LPRX
+    - MLK-18605-10 drm/bridge: sec-dsim: complete mipi panel support
+    - MLK-19017-5 drm/bridge: sec-dsim: add DISPMIX power domain support
+    - MLK-19082 drm/bridge: sec-dsim: wait 'ph_tx_done' for long packet send
+    - MLK-19252-1 drm/bridge: sec-dsim: move PLL check to DSIM Encoder
+    - MLK-19252-3 drm/bridge: sec-dsim: workaround 3 data lanes case
+    - MLK-19252-4 drm/bridge: sec-dsim: improve HT configs
+    - MLK-19252-5 drm/bridge: sec-dsim: improve PLL PMS configs
+    - MLK-19252-6 drm/bridge: sec-dsim: improve DPHY TIMING configs
+    - MLK-19252-7 drm/bridge: sec-dsim: workaround for 720p@60Hz on 4 lanes
+    - MLK-19317-2 drm/bridge: sec-dsim: fine tune for '720p@60Hz' mode on 2 lanes
+    - MLK-19400-1 drm/bridge: sec-dsim: correct one fail branching
+    - MLK-21150-1 drm/bridge: sec-dsim: change uint64_t clk fields to uint32_t
+    - MLK-21150-2 drm/bridge: sec-dsim: refine hblank word count compute
+    - MLK-18535-13 dt-bindings: display: bridge: add sec-dsim bindings
+    - MLK-21150-3 drm/bridge: sec-dsim: add a new property 'pref-rate'
+    - MLK-21150-4 drm/bridge: sec-dsim: a general way to compute PLL PMS
+    - MLK-21252 drm/bridge: sec-dsim: resolve OVERFLOW_BEFORE_WIDEN warns
+    - MLK-21383 drm/bridge: sec-dsim: fix maybe-uninitialized build warnings
+    - MLK-21880-1 drm/bridge: sec-dsim: correct DSIM version register access
+    - MLK-21911 drm/bridge: sec-dsim: free 'pll_pms' to avoid memory leak
+    - MLK-21274-3 drm/bridge: sec-dsim: add defer probe support
+    - MLK-21274-2 drm/bridge: sec-dsim: remove bridge assign for encoder
+    - MLK-20687 drm/bridge: sec-dsim: correct LPM config for Long Packet
+    - MLK-20438 drm/bridge: sec-dsim: remove 'FORCEBTA' for packet send
+    - MLK-17275-2: drm/bridge: it6263: Add support for OF_DYNAMIC
+    - MLK-18535-8 drm/imx: sec_mipi_dsim-imx: add DSIM host driver
+    - drm/imx: add DISPMIX power domain support for SEC DSIM
+    - MLK-19017-6 drm/imx: add system pm support for SEC DSIM
+    - MLK-19017-7 drm/imx: sec-dsim_imx: add rpm status check for suspend/resume
+    - MLK-19158-1 drm/imx: sec-dsim_imx: add bus format check for ENCODER
+    - MLK-19537-3 drm/imx: sec-dsim_imx: remove dphy slave reset
+    - drm/imx: sec-dsim_imx: move PLL check to DSIM Encoder
+    - drm/imx: sec-dsim_imx: improve DPHY TIMING configs
+    - MLK-19400-2 drm/imx: sec-dsim_imx: alter 'rpm_suspended' to a counter
+    - drm/imx: sec-dsim_imx: a general way to compute PLL PMS
+    - drm/imx: sec-dsim_imx: correct DSIM version register access
+    - drm/imx: dsim: change DISPMIX reset for IMX8MN
+    - MLK-22304-1 drm/imx: dsim: fix build warnings if CONFIG_PM_SLEEP off
+    - drm/imx: Replace reset flow for DSIM
+    - drm/imx: sec-dsim_imx: add resets put for probe failure
+    - drm/imx: sec_dsim-imx: add imx8mn compatible support
+    - drm/bridge: Add NWL MIPI DSI host controller support
+    - drm/bridge: nwl-dsi: Add support for video_pll
+    - drm/bridge: nwl-dsi: Add support for clock-drop-level
+    - drm/bridge: nwl-dsi: fix nwl-dsi when used as module
+    - drm/bridge/nwl-dsi: add support for DCSS
+    - drm: bridge: add Cadence MHDP HDMI/DP API
+    - drm: bridge: Add Cadence DP/HDMI core driver
+    - gpu: drm: Add imx8qm/mq DP/HDMI driver
+    - drm: bridge: cadence: Add new api functions
+    - drm: bridge: cadence: Add mhdp audio driver
+    - drm: bridge: cadence: Add CEC driver for cdns mhdp hdmi
+    - drm: bridge: cadence: move struct imx_mhdp_device to drm/imx
+    - drm: imx: add imx8mq hdmi support
+    - drm: bridge: cadence: Add power_on to __cdns_dp_probe
+    - drm: ls1028a: Add DP driver support for LS1028A
+    - drm: bridge: cadence: Add support for periodically poll the connector
+    - drm: imx: hdmi: support arc function
+    - drm: bridge: cadence: Fix return value for set log addr
+    - drm: bridge: cdns dp: Remove link rate/lanes set by device tree
+    - drm: imx: mhdp: add dual mode support for imx8qm
+    - drm: bridge: cdns cec: fix LA failed set issue
+    - DRM: mhdp: HDMI: skip scdc write return check
+    - drm: mhdp: add mutex lock to mhdp register access function
+    - drm: mhdp: reset video mode after hdmi/dp cable plugin
+    - drm: bridge: cadence: hdmi: remove video mode limition
+    - drm/imx/hdp: add hdr10 metadata property
+    - drm/imx/hdp: add colorspace property
+    - drm/imx/hdp: force a mode set when colorspace is changed
+    - drm/imx/hdp: handle the various deep-color settings
+    - MLK-15321-2 gpu: imx: dpu: Add dpu blit engine driver
+    - MLK-15321-3 drm/imx: dpu: Add render feature support
+    - MLK-15321-4 drm/imx: core: Add bliteng as component of imx-drm
+    - MLK-17311 gpu: imx: dpu-blit: enable prefetch feature
+    - MGS-4061 gpu: imx: dpu-blit: fix kernel panic in pm test
+    - MGS-3940 gpu: imx: dpu-blit: fix first frame handler
+    - MGS-4051 gpu: imx: dpu-blit: fix suspend resume issue
+    - MGS-3940 gpu: imx: dpu-blit: fix dpr hang for smaller size
+    - MGS-4265 gpu: imx: dpu-blit: fix video hang with g2d compositor
+    - gpu: imx: dpu-blit: Do not initialize STORE9_STATIC register
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: add busfreq support
+    - drm: imx: dcss: Fix for renaming reservation.h to dma-resv.h
+    - Revert "drm: imx: dcss: Fix for renaming reservation.h to dma-resv.h"
+    - Revert "drm/imx/dcss: add busfreq support"
+    - Revert "drm/imx: Add initial support for DCSS on iMX8MQ"
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: use the external 27MHz phy clock
+    - drm/imx/dcss: add busfreq support
+    - drm/imx/dcss: add support for DEC400D
+    - drm/imx/dcss: add support vor video overlays
+    - drm/imx/dcss: remove reference to P010
+    - drm/imx/dcss: add WRSCL/RDSRC support
+    - drm/imx/dcss: add support for NV12_10LE40 format
+    - drm/imx/dcss: eliminate unnecessary formats from planes
+    - drm/imx/dcss: add color management properties to video planes
+    - drm/imx/dcss: change HDR10 pipes config handling
+    - drm/imx/dcss: add support for tiled formats on overlay planes
+    - drm/imx/dcss: fix crash in DTRC exit routine
+    - drm/imx/dcss: Release DTRC IRQs in case of failure
+    - drm/bridge/nwl-dsi: fix attach flow of downstream bridge
+    - drm: imx: mhdp: Adjustment core rate of DP TX CTRL for LS1028A
+    - LF-46 drm/imx: sec-dsim: use late suspend
+    - drm/imx/hdp: fix issue with non-SCDC HDMI sinks
+    - drm/bridge: nwl-dsi: Add support for component framework
+    - drm/bridge: nwl-dsi: Add support for 8QM and 8QXP
+    - drm/bridge: nwl-dsi: Fix find_panel_or_bridge
+    - gpu: imx: framegen: Use crtc_clock instead of mode clock
+    - drm/bridge: nwl-dsi Correct the DSI init sequence
+    - Revert "drm/imx/hdp: fix issue with non-SCDC HDMI sinks"
+    - drm: hdmi: imx8: fix wrong hdmi type with non-SCDC HDMI sinks
+    - LF-94: drm: hdmi: imx: Add hdmi phy video mode valid function
+    - LF-283 gpu: imx: dpu: common: Get irq count properly
+    - LF-296: drm: mhdp: build mhdp sub-modules into one driver module
+    - LF-282 drm/imx: dpu: Kconfig: Add prompt string for DRM_IMX_DPU
+    - LF-335 drm/bridge: sec-dsim: solve fallthrough build warnings
+    - LF-95-4 drm/bridge: nwl-dsi: Correct register offsets for tx_ulps and
+      pxl2dpi
+    - LF-95-5 drm/imx: imx-ldb: Correct control register offset for i.MX8QM/QXP
+      LDB
+    - drm/bridge: nwl-dsi: Fix phy_ref clock ordering
+    - MLK-21231 gpu: imx: dpu: framegen: Wait for 100ms at most for secondary
+      syncup
+    - LF-323-1: drm/bridge/cdns: move link training to bridge enable function
+    - LF-323-2: drm/bridge/cdns: enhance link training stability
+    - LF-407-1: drm/imx/dcss: fix compilation issues after rebase
+    - LF-407-2: drm/imx/dcss: fix module insertion hang
+    - LF-407-3: drm/imx/dcss: remove unnecessary sleep
+    - LF-424 gpu/imx: lcdif: fix typo for imx_lcdif_dt_ids
+    - LF-425-2 drm/bridge: sec-dsim: use 'attach-bridge' for bridge attach
+    - LF-568-1: drm: bridge: cdns: dp: change bridge_enable/disable name
+    - LF-568-2: drm: gpu: bridge: cdns: Add force mode set flag
+    - MLK-23234-4 gpu: imx: add LCDIFv3 core driver
+    - MLK-23234-6 drm/imx: add LCDIFv3 DRM/KMS driver
+    - MLK-23234-7 drm/imx: core: add LCDIFv3 support
+    - MLK-23234-8 drm/imx: sec-dsim: add imx8mp compatible
+    - MLK-23234-9 drm/imx: sec-dsim: bypass mediamix resets on imx8mp
+    - MLK-23245 gpu: imx: lcdifv3: correct panic thresholds calculation
+    - MLK-23248 gpu: imx: lcdifv3: correct panic enable register typo
+    - MLK-23250-02: drm: lcdifv3: Change frame size limit to 4096
+    - MLK-23250-04: lcdifv3: Add hdmimix lcdifv3 support
+    - MLK-23250-09: drm: imx: pavi: Add PAVI driver for iMX8MP HDMI
+    - MLK-23250-10: drm: imx: hdmi: Add iMX8MP hdmi driver
+    - MLK-23287-3: drm: imx: hdmi: Add iMX8MP hdmi gp audio driver
+    - MLK-23218 gpu: imx: lcdifv3: Change burst size to 256B
+    - LF-900: drm/imx/dcss: Fix kernel panic during suspend
+    - MLK-23252-3 gpu: imx: lcdifv3: Support client specific pdev id
+    - MLK-23252-4 gpu: imx: lcdifv3: Add compatible string for LDB's LCDIFv3
+    - MLK-23252-8 drm/imx: imx-ldb: Rename flag is_imx8 to is_imx8q
+    - MLK-23252-9 drm/imx: imx-ldb: Add i.MX8mp LDB support
+    - LF-794 gpu: cdn: imx8qm: Add firmware loading support
+    - LF-794 gpu: cdn: mhdp-common: Increase the check alive timeout
+    - MLK-23328: drm: bridge: hdmi: Fix no vendor infoframe after resume
+    - MLK-23102-1 drm/imx: dpu: kms: Remove fetchunit pin-off mechanism
+    - MLK-23102-2 gpu: imx: dpu: fetchunit: Remove pin-off operations
+    - MLK-23109 drm/imx: dpu: plane: Always enable DPRC when prefetch is needed
+    - MLK-23107-1 gpu: imx: imx8_dprc: Add helper dprc_disable_repeat_en()
+    - MLK-23107-2 drm/imx: dpu: kms: Disable DPRC repeat_en in ->atomic_flush()
+      where necessary
+    - MLK-23187-1 gpu: imx: dpu: framegen: Increase timeout again when waiting for
+      moving
+    - MLK-23187-2 drm/imx: dpu: crtc: Disable DPRC repeat_en in ->atomic_disable()
+    - MLK-23221: drm/bridge: nwl-dsi: Call panel enable early
+    - LF-841: drm/bridge: nwl-dsi: Fix mode_set
+    - LF-842-1: drm/bridge: nwl-dsi: Change mipi clocks re-parenting
+    - LF-555: drm: mhdp: Improve the AUX channel signal for DP port
+    - MLK-23425-1 gpu/imx: lcdifv3: enable frame clear
+    - MLK-23425-2 gpu/imx: lcdifv3: add dma disable
+    - MLK-23428 drm/imx: sec-dsim: add bound check in runtime suspend/resume
+    - MLK-23522: drm/imx: lcdifv3: remove unsupported formats
+    - MLK-23544: drm: gpu: dw_hdmi: check imx8mp hdmi phy support clk rate
+    - MLK-23538-1: drm: gpu: dw_imx: add CEC enable bit set
+    - LF-452: gpu: drm: bridge: hdmi: Add CEA mode check
+    - MLK-23576 gpu/imx: lcdifv3: add system sleep PM ops
+    - MLK-23545-1: drm: bridge: hdp: Remove force_mode_set flag when cable plugin
+    - MLK-23545-2: drm: imx: mhdp: weston8 UI recovery after cable plugout/in
+    - LF-1189-2 gpu: imx: dpu: tcon: Add MEDIA_BUS_FMT_RGB565_1X30_PADLO support
+    - LF-1189-3 gpu: imx: dpu: framegen: Add DPI encoder support
+    - LF-1189-5 drm/imx: Add LCDIF mux display support
+    - MLK-23767 gpu: imx: dpu: common: avoid deattach multiple power domain
+    - MLK-20486 drm/imx: ldb: Cleanup enc&conn in ->unbind() if necessary
+    - LF-1256-1 drm/imx: imx-ldb: Allocate imx_ldb in ->probe() instead of
+      ->bind()
+    - LF-1256-2 drm/imx: lcdif-mux-display: Allocate lmuxd in ->probe() instead of
+      ->bind()
+    - LF-1256-3 drm/imx: dpu: crtc: Allocate dpu_crtc in ->probe() instead of
+      ->bind()
+    - MLK-23781-1 drm/imx: lcdifv3: move 'lcdifv3_crtc' alloc to probe
+    - MLK-23781-2 drm/imx: lcdifv3: remove 'lcdifv3_plane_deinit()'
+    - MLK-23781-3 drm/imx: sec-dsim: move 'dsim_dev' alloc to probe
+    - MLK-23781-4 drm/imx: sec-dsim: initialize 'rpm_suspended' in probe
+    - MLK-23694-6 drm/imx: ldb: remove PLL clock rate set for i.MX8M
+    - MLK-23694-9 drm/imx: sec-dsim: put resets in unbind() to fix memory leak
+    - MLK-23694-10 drm/imx: sec-dsim: NULL panel ptr when host detached
+    - MLK-23694-11 drm/imx: sec-dsim: allow bind for no display attached
+    - MLK-23817 gpu: imx: dpu: common: Enable power for dpu irq chip at probe
+      stage
+    - MLK-23642-1: drm: bridge: cadence: support HBR and 6 channel
+    - MLK-23885 drm/imx: ldb: Add mode fixup for i.MX8mp LDB in ->atomic_check()
+    - MLK-23903 drm/imx: imx-ldb: Disable both two channels for split mode in
+      enc->disable()
+    - MLK-23904 drm/imx: imx-ldb: Cache split mode status in struct imx_ldb
+    - MLK-23905-1 drm/bridge: Add fsl imx ldb support
+    - MLK-23905-2 drm/imx: imx-ldb: Use platform specific encoder drivers
+    - MLK-23942-6 drm/bridge: fsl-imx-ldb: Add runtime PM support
+    - MLK-23942-7 drm/imx: imx8mp-ldb: Add runtime PM support
+    - MLK-23942-8 drm/imx: imx8qm-ldb: Add runtime PM support
+    - MLK-23942-9 drm/imx: imx8qxp-ldb: Add runtime PM support
+    - LF-621: drm/imx/dcss: add back disabled formats
+    - MLK-24002-1 drm/imx: lcdifv3: enable shadow load for plane update
+    - MLK-24002-2 drm/imx: lcdifv3: put controller enable to CRTC
+    - MLK-24040: drm: imx: pavi: Combine pai and pvi powerup/down function
+    - MLK-24045 drm/imx: sec-dsim: let host unregister later than device
+    - MLK-24065-1: drm: bridge: cadence: fix dp_aux_transfer write return value
+    - MLK-24065-2: drm: bridge: cadence: print error when clock recovery fails
+    - MLK-24065-3: drm: bridge: cadence: use the lane mapping from dt when setting
+      host capabilities
+    - MLK-24072: drm: imx8: correct mhdp files copyright
+    - MLK-24076-2: drm: imx: hdmi: Add copyright
+    - LF-1043: drm/bridge: nwl-dsi: Assert mipi resets before enable
+    - LF-811-1: drm/bridge: Add driver for legacy Freescale Seiko 43WVFIG adapter
+    - MLK-24168 drm/imx: dpu: kms: Avoid -EDEADLK warning when getting crtc_state
+      in ->atomic_check
+    - MLK-24190: drm: imx: dw_hdmi: Add resume function
+    - MLK-24146 drm: dw_hdmi: cec: Add cec suspend/resume function
+    - LF-1444 gpu: imx: dpu: common: Check of_match_device() return value in
+      dpu_probe()
+    - LF-1442-1 drm/imx: sec-dsim: avoid dereference NULL ptr of of_id
+    - LF-1442-2 drm/imx: lcdif: avoid dereference NULL ptr of of_id
+    - LF-1442-3 drm/imx: lcdifv3: avoid dereference NULL ptr of of_id
+    - MLK-24293 gpu/imx: lcdifv3: use late system sleep pm ops
+    - LF-1510: gpu: drm: lcdifv3: null return value check for of_id
+    - LF-1510-2: gpu: drm: dw_hdmi: null return value check
+    - LF-1511: drm: cdn-cec: replace ++i with i++ in loop
+    - LF-1512: drm: cdns mhdp: avoid potentially overflowing
+    - LF-1514: drm: cdns-mhdp: check link rate index
+    - LF-1516: drm: cdns-mhdp: fix error check variable name for clk_pxl_link
+    - MLK-24335: drm: bridge: cdns: hdmi support work in DVI mode
+    - LF-1555: drm: bridge: nwl-dsi: Fix null-pointer dereference
+    - LF-1556: drm/bridge: nwl-dsi: Fix potential null-pointer dereference
+    - MLK-21509-1 gpu: imx: dpu: common: Add signature unit support
+    - MLK-21509-2 gpu: imx: dpu: disengcfg: Add signature select support
+    - MLK-21509-3 drm/imx: dpu: kms: Add auto control mode debugfs CRC support
+    - MLK-21509-4 drm/imx: dpu: crc: Add user-configurable CRC region(ROI) support
+    - LF-1750 gpu: imx: imx8_dprc: Get scu ipc handle in ->probe()
+    - LF-1485: drm: bridge: dw_hdmi: null pointer check
+    - LF-1526: drm/imx/dcss: Fix Coverity issue
+    - MLK-24427-1: drm: gpu: imx: Move cdns driver files to mhdp folder
+    - MLK-24427-2: drm: bridge: cdns: Move DP API functions to separate file
+    - MLK-24427-3: drm: mhdp: Backporting code change from linux-nxp
+    - LF-2011 gpu: imx: imx8_dprc: Check return value of SCU func call in
+      dprc_dpu_gpr_configure()
+    - LF-2010 gpu: imx: imx8_dprc: Check return value of SCU func call in
+      dprc_prg_sel_configure()
+    - MLK-24519 gpu: imx: Increase maximum single pipe width to 2560
+    - MLK-24520: drm: bridge: cdns: increase maximum width from 4096 to 5120.
+    - MLK-24521: drm: bridge: hdmi: Prevent the driver from rejecting VIC 0 modes
+    - MLK-24522: drm/imx: dpu: Increase iMX DRM CTRC size to 5120 x 4096
+    - drm: bridge: dw-hdmi: Report connector status using callback
+    - MLK-24611-1: drm: bridge: synopsys: Add callback function for plug/unplug
+      event
+    - MLK-24611-2: drm: bridge: cdns: Add callback function for plug/unplug event
+    - MLK-24601: drm: imx: mhdp: DP PHY support 1/2 lanes mode
+    - MLK-24608: drm/imx/dcss: disallow certain modes
+    - MLK-24770: drm: mhdp: Sync DPTX capability with Cadence sample code
+    - MLK-24900-1 drm/imx: lcdifv3: Use dts to config LCDIF panic threshold
+    - MLK-24916-1: drm: bridge: synopsys: fix eld length issue
+    - MLK-24916-3: drm: bridge: synopsys: Add HBR support for gp audio
+    - MLK-24998-4 drm/bridge: sec-dsim: use 12MHz for default PHY REF clock
+    - MLK-24998-7 drm/imx: lcdifv3: implement mode_valid() for CRTC
+    - MLK-25012 drm/imx: lcdif: move 'lcdif_crtc' alloc to probe()
+    - MLK-24911-3: drm: imx: sec-dsim: Adjust the LDO trim value
+    - MLK-25101: drm: imx: dw_hdmi: Keep hdmi phy in poweron status
+    - MLK-25228: drm: dw-hdmi: Pass CTS 7-30 Audio InfoFrame
+    - MLK-25156: drm: dw_hdmi: reset hdmi phy power
+    - MLK-24491: drm: bridge: cdns: Add support of i2c-over-aux
+    - MLK-25340-1: drm: imx: hdp: Added power off function
+    - MLK-25340-2: drm: imx: mhdp: Adding power off to driver remove
+    - drm/imx: ipuv3-kms: Move to a new ipuv3 folder
+    - MLK-21876-10 gpu: drm: ipu: fix headfile reference issue (part2)
+    - Revert "drm/imx: Use simple encoder"
+    - Revert "drm/imx: pd: Use bus format/flags provided by the bridge when
+      available"
+    - drm/fourcc: add modifier for vivante compressed tiled layout
+    - MLK-15110-1 drm/fourcc: Add Amphion tiled layout format modifier
+    - MLK-17368-1 drm: add fourcc codes for Verisilicon tiled formats
+    - dt-bindings: firmware: imx: add scu clock type IDs
+    - MLK-23329-01 dt-bindings: imx: update sc ctrl interfaces
+    - media: bus format: Add RGB888_1X30_PADLO support
+    - media: bus format: Add RGB666_1X30_PADLO support
+    - media: bus format: Add RGB101010_1X7X5_SPWG/JEIDA support
+    - LF-1189-1 media: bus format: Add RGB565_1X30_PADLO support
+    - reset: Add driver for dispmix reset
+    - reset: imx8m: Correct clock name for dispmix driver
+    - LF-218 reset: dispmix: remove dev when init mmio regmap
+    - MLK-23250-07: clk: imx: add imx8mp hdmimix clk driver
+    - MLK-23538-2: clk: hdmimix: set cec clock parent to 32k_clk
+    - MLK-23356: reset: Remove noc reset bit from hdmimix reset
+    - MLK-23250-08: phy: Add samsung hdmi phy driver
+    - MLK-23542: phy: support more pixel rates
+    - MLK-24041: phy: fsl: sync code change with LF branch
+    - MLK-24397 phy: samsung hdmi: support more clock rate
+    - MLK-23252-6 phy: freescale: Add i.MX8mp LVDS PHY support
+    - MLK-23616-3 phy: fsl-imx8mp-lvds: Enable/disable APB clock when necessary
+    - MLK-23942-3 phy: freescale: phy-fsl-imx8mp-lvds: Add runtime PM support
+    - irq: imx: irqsteer: add multi-pd support for irqsteer
+    - MLK-23250-05: irqchip: imx-irqsteer: Add reset function
+    - MLK-17290-01 irqchip: imx-irqsteer: add runtime pm support
+    - MLK-23750-1: irqchip: imx: fix ISI_0, CSI_0 can't enter lp when suspend
+    - MA-17912 irqchip: irqsteer: Allow IMX_IRQSTEER to be loadable as module
+    - MLK-23252-1 clk: imx8mp: Add DISP2 pixel clock
+    - MLK-23252-2 clk: imx8mp: Add LDB root clock
+    - MGS-4530-1 add 6.2.4.p4 gpu driver for L4.19
+    - MGS-4530-2 disable busfreq-imx to fix L4.19 dash build
+    - MGS-4530-3 [#imx-1314] include dma-direct.h to fix gpu build for L4.19
+    - gpu: fix access_ok build error
+    - gpu: fix do_gettimeofday build error
+    - gpu: fix totalram_pages build error
+    - gpu: more build fix
+    - gpu: imx: fix gpu boot hang by defer driver register time
+    - MLK-21876-11 gpu: fix build for next-20190524 upgrade
+    - gpu: Update SCU API and change the method to distinguish 8QM/8QXP from other
+      boards
+    - gpu:Integrate 6.4.0 kernel driver for Linux L5.x
+    - gpu: fix build break due to dma headfile include
+    - gpu:Remove dma.h to avoid Linux 5.x build problem
+    - gpu-viv: Fix writecombine/wc build error
+    - MGS-5252 Integrate Vivante 6.4.0.p1 GPU driver
+    - MGS-5176 [#imx-1744] Coverity issue of 6.4.0.p1.
+    - MGS-5176-2 [#imx-1744] Need free the pages if malloc memory failed
+    - MGS-4376 [#imx-1238] fix low performance with CMA allocator
+    - MGS-5283 [#imx-1238] fix GPU memory without CMA
+    - MGS-5283 [#imx-1784] fix GPU AXI bus error
+    - MGS-5284 [#imx-1786] fix GPU panic with vm_mmap failure
+    - MGS-5261 [#imx-1771] fix dummy draw hang for 8MM GPU
+    - QSDK-5959 [#ccc] update the platform driver to support layerscape soc
+    - MGS-5307 gpu: integrate 6.4.0.p2 driver
+    - MGS-5245 [#imx-1755] [8MN_EVK] VTK: fix the gpu dump when enable vProfile
+    - LF-84 [#imx-1834] remove gpu coherent_dma_mask setting
+    - Add Malone decoder and windsor encoder for QXP/QM
+    - Add directory driver/mxc and related scripts
+    - arm64: vpu: m850d: hantro
+    - arm64: vpu: m850d: hantro: mxc config
+    - vpu: hantro: fix build failure
+    - vpu: malone: fix build failure
+    - vpu: windsor: fix build failure
+    - vpu: windsor: remove deprecated using of s_crop/g_crop
+    - vpu: windsor: remove deprecated using of VB2_BUF_STATE_PREPARED
+    - vpu: windsor: fix build error
+    - vpu: malone decoder: porting from 4.19 rc3 release
+    - vpu: malone decoder: porting from 4.19 rc3 release
+    - vpu: windsor encoder: porting from 4.19 rc3 release
+    - vpu: windsor encoder: porting from 4.19 rc3 release
+    - MLK-21876-22 vpu: build for ARM64 only
+    - MLK-21985-2 vpu: malone: b0: fix build for next 20190607 upgrade
+    - MLK-21985-3 vpu: windsor: b0: fix build for next 20190607 upgrade
+    - media: vpu_malone: fix boot warning by intialize device_caps
+    - media: vpu_windsor: fix boot warning by intialize device_caps
+    - vpu: hantro: fix build error when enabling 'CONFIG_DEVICE_THERMAL'
+    - vpu: malone: encoder: add mu2 power domain for imx8qm
+    - vpu: hantro: add decoder for imx845
+    - vpu: hantro: add encoder for imx845 h1
+    - vpu: imx6: add decoder/encoder
+    - vpu: imx6: add decoder/encoder
+    - vpu: hantro_845_h1: fix compat_ptr building issue
+    - vpu: windsor encoder: add vpuenc2 power domain for imx8qm
+    - vpu: windsor encoder: enable mailbox and unify code
+    - vpu: malone decoder: enable mailbox and unify code
+    - vpu: windor encoder: malone decoder: fix kernel panic caused by MU_Init
+    - MLK-22913 vpu: windsor malone: fix kernel panic caused by directly read MU
+    - MLK-22920 vpu: windsor encoder: change the writeable flag synchronously
+    - vpu: hantro: Fix kconfig to depend on ARCH_MXC instead
+    - MLK-22951 mxc: vpu_malone: add missing semicolon
+    - MLK-22952 mxc: vpu_windsor: add missing semicolon
+    - vpu: hantro: Fix kconfig to depend on ARCH_MXC instead
+    - MLK-22945 mxc vpu_malone: disable decode ctx before release it.
+    - MLK-22963 mxc vpu_windsor: fix call vzalloc during spinlock
+    - MLK-22991 mxc: vpu_malone vpu_windsor: check is vpu poweroff when suspend
+    - MLK-22999 mxc: vpu_malone: release debugfs after open to avoid memory leak
+    - LF-80:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:clear eos flag when output streamoff
+    - MLK-10600-1: mxc: sim: Add SIM IP driver support on the i.MX7d-12x12-arm2
+      platform.
+    - MLK-10600-2: mxc: sim: add an option to enable SIM driver build
+    - MLK-10913-1: mxc: sim: Add the SIM driver support for i.MX6UL-EVK platform.
+    - MLK-10959: mxc: sim: Disable cwt timer when tx and enable in rx.
+    - MLK-10968: mxc: sim: Add the init delay detection function in the driver.
+    - MLK-10976: mxc: sim: Using timer interrupt to implement precise timing.
+    - MLK-11354 sim: imx: relapce devm_request_and_ioremap with
+      devm_ioremap_resource
+    - MLK-11777 sim: imx: remove useless code
+    - MLK-11472 sim: imx: set sim1 IOMUX to default state
+    - MLK-14642 imx: sim: fix segment fault caused by user address access
+    - MLK-13473: imx_sim: fix module device table name
+    - MLK-17319-1 imx8: sim: add driver to support EMVSIM module
+    - MLK-17416 imx8: sim: add usleep_range() before reading SPDP Bit
+    - MLK-18485 emvsim: enable CWT for ATR
+    - MLK-22210 mxc: emvsim: enable ICM mode
+    - MLK-22211 mxc: emvsim: should not clear PEF/FEF flag in irq handler
+    - MLK-22213 mxc: emvsim: read TS character before updating value of GPCNT1
+    - MLK-22214 mxc: emvsim: clean up the code in ATR stage
+    - MLK-22215 mxc: emvsim: correct irq mask and clear irq status before
+      receiving
+    - MLK-22216 mxc: emvsim: last character need be transmitted separately with no
+      guard time
+    - MLK-22217 mxc: emvsim: add value adjustment for cwt/bwt timer
+    - sim: emvsim: add multi power domain support
+    - MLK-11442 mlb: imx: add mlb support on imx_4.1.y
+    - imx: mlb: Replace ACCESS_ONCE with READ_ONCE
+    - MLK-11910 mxc: mlb: fix irq unsigned_compare issue
+    - MLK-12185 mlb: imx: fix the operation for mlb status in mlb_isr
+    - MLK-15987 imx: mlb: use dma pool when iram doesn't exist
+    - MLK-15988 imx: mlb: remove clk for mlb 6 pin mode
+    - MLK-15990 imx: mlb: change mlb clock name
+    - MLK-15995 imx: mlb: only use irq_ahb1 for imx6
+    - MLK-15999 imx: mlb: fix build warnings
+    - MLK-15992 imx: mlb: add ipg & hclk clocks for imx8 mlb
+    - MLK-22071-1 mxc: mlb: Fix clock config for imx8qxp platform
+    - mxc: mlb: fix interrupt rw lock dead lock
+    - mxc mlb: Allow compilation on imx8
+    - MLK-23000-1 mxc: mlb: fix kernel dump when use gen_pool_dma_alloc
+    - mxc: IPU3: Forward IPUv3 common driver from imx_4.19.y kernel
+    - mxc: IPU3: Fix not including uapi/linux/sched/types.h
+    - MLK-22399 mxc IPUv3: cpmem: Get 0 u/v_offset in __ipu_ch_offset_calc() for
+      some pfmts
+    - mxc: hdmi-cec: Add imx6 hdmi cec driver
+    - media: mipi csi: add IPU CSI driver
+    - MGS-5372 [#imx-1708] Fix the VX/CL apps hang for 865 GPU/VIP
+    - LF-365 [8QM_MEK/8QXP_MEK]mxc:vpu_malone: need skip tsm when skip not decoded
+      frame
+    - MGS-5326 [#imx-1803] 0058-align-gc_feature_database
+    - LF-503:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:check space of cmd buffer
+    - LF-521: mxc: hantro: [All]arch64 kernel default build using imx_v8_defconfig
+      has many Warnings.100%
+    - LF-561: [8QM_MEK/8QXP_MEK]mxc:vpu_malone:reinit completion before send
+      command
+    - MGS-5226 [#imx-1746] add REG_DisableVIP bit 1
+    - LF-628:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:export frame threshold of frame mode
+    - LF-629: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: donot set end_flag if scode type
+      is BUFFFLUSH in low-latency mode
+    - MGS-5064 [#imx-1868] 0003-CL244120-Prepare-for-NXP-backwards-compatible-
+      requir
+    - MGS-5064 [#imx-1868] 0006-CL244297-align-gc_feature_database
+    - MGS-5064 [#imx-1868] 0010-BUG25711-CL244484-Android-CTS-some-cases-fail-in-
+      gle
+    - MA-16168 [#imx-1903] Fix GPU driver build error and not work issue on 5.4
+      kernel
+    - LF-408-2 [#imx-1873] disable 1M page for dynamic mapping
+    - MGS-5458 [#imx-1708] fix GPU/VIP coreIndex issue
+    - LF-688:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:export fw log via debugfs
+    - LF-690:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:extends the range of frame rate
+      from integers to real numbers
+    - LF-711:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:stream may hang due to the event msg
+      hasn't process in time
+    - MLK-23211-1: arm64: imx8mp: vpu: add vc8000e driver
+    - MA-16211: imx8mp: vpu: Implement hantro vc8000e ioctl32
+    - LF-765 [8QM_MEK/8QXP_MEK]mxc:vpu_malone: add FRAME_SKIP status to record
+      skip-frame
+    - LF-765-2 [8QM_MEK/8QXP_MEK]mxc: vpu_malone: check buffer status before add
+      buffer to queue
+    - MGS-5472 [#ccc] fix gpu resolve alignment issue
+    - LF-165 [#imx-1870] gputop counter test failed
+    - LF-165 [#imx-1870] Fix the error when converting pointer to int for 32 bit
+      system
+    - MGS-5341 [#imx-1870] Fix the uninitialized variable in GPU driver.
+    - MGS-5485 [#imx-1870] fix memory database error
+    - MGS-5485-2 [#imx-1870] fix system out of memory in gpu database
+    - MLK-23263 mxc: vpu_malone: correct vpu decoder used bits of fuse
+    - LF-840-1:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-2:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-3:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-4:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-5:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-6:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-840-7:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:abort or stop cmd may timeout
+      after resume from suspend when run multi h264 instance
+    - LF-984:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:report error event when the
+      resolution beyond limit
+    - LF-994 mxc: vpu_malone vpu_windsor: cope with upstream y2038 changes
+    - MLK-23375: arm64: imx8mp: vc8000e: remove legacy ioremap_nocache interface
+    - MGS-5464 [#imx-1915] 0014-CL249917-DEC400-P010_LSB-I010-format
+    - MLK-23377: arm64: imx8mp: vc8000e: fix system hang in suspend/resume
+      operation
+    - MGS-5497-2 [#ccc] fix 6QP 2D MMU exception issue
+    - MA-16364 [#imx-1927] Set 4GB address limit flag on 8mm/8mn as 8mq
+    - MGS-5490 [#imx-1868] 0009-CL247796-Add-cores-in-order-3D-VIP-cores-2D-core-
+      VG-
+    - MGS-5534 [#imx-1960] Add copyright in gc_feature_database.h
+    - MGS-5536-1 [#imx-1962] add memory-region property support
+    - MGS-5536-2 [#imx-1962] fix MMU shift mapping for 4GB truncated mtlb
+    - MLK-23394-2: XUVI/PPM: driver initial version.
+    - MLK-23394-5: XUVI/PPM: add build for XUVI/PPM.
+    - LF-1090:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:synchronize the allocate and free
+      mbi buffer
+    - MGS-5453 [#imx-1895] update gc_feature_database.h file
+    - MLK-23394 XUVI/PPM: decrease the usage count when it isn't in using.
+    - MLK-23377-2: arm64: imx8mp: vc8000e: fix system hang in suspend/resume
+      operation
+    - MGS-5554 [#imx-1868] update gc_feature_database.h and gc_hal_enum.h file
+    - MLK-23394 XUVI/PPM: fix coverity issues
+    - MLK-23220:mxc:vpu_malone:kfifo_alloc failure in VPU driver when memory
+      fragment
+    - LF-1077:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:compatible with ffmpeg h264_v4l2m2m
+      decoder
+    - LF-1078:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:compatible with ffmpeg
+      h264_v4l2m2m encoder
+    - LF-1078-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:compatible with ffmpeg
+      h264_v4l2m2m encoder
+    - LF-1180:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:v4l2 buffer of output stream use
+      virtual memory instead of dma
+    - LF-1181 mxc: vpu_malone: Not send res_change event until dst done_list is
+      empty
+    - MGS-5581 [#imx-1868] integrate vsi patch base on 6.4.0.p2 from 20200306 to
+      20200320
+    - LF-1208:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor:instance may hang caused by stop
+      cmd is not sent in some case
+    - LF-1210:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: add LVL_FLOW debug log level to
+      help trace some key information
+    - LF-1091: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: request reasonable buffer size
+      for DCP instead of worst case
+    - LF-1212:[8QM_MEK/8QXP_MEK]mxc:vpu_malone:fix issue in timestamp manager not
+      correctly handle buffers with same timestamp
+    - LF-1211 mxc: vpu_malone: v4l2_poll directly return if firmware already
+      finished
+    - MGS-5607 [#imx-1868] integrate vsi patch base on 6.4.0.p2 from 20200320 to
+      20200408
+    - MLK-23793-1 mxc: emvsim: fix pm issue
+    - MLK-23793-2 mxc: emvsim: add runtime pm support
+    - LF-1220 mxc: vpu_malone: manage mailbox according to runtime PM
+    - LF-1220-2 mxc: vpu_windsor manage mailbox according to runtime PM
+    - MGS-5612 [#IMX-2018] fix weston build error
+    - LF-1236 mxc: vpu_malone: roundup allocated kfifo size to power-of-two
+    - MLK-23394-1 XUVI/PPM: fix coverity issues
+    - MLK-23791 XUVI/PPM: MU: enable runtime PM for MU3
+    - LF-1225: [8QM_MEK/8QXP_MEK]mxc:vpu_malone:fix hevc incorrect dcp buffer size
+    - mxc: gpu: remove use of ioremap_nocache()
+    - mxc: gpu-viv: Remove dma-buf map/unmap hooks
+    - mxc: gpu: cope with upstream y2038 changes
+    - MGS-5616-1 [#ccc] Update some Linux APIs for 5.5 kernel
+    - MGS-5616-2 [#ccc] Remove dma-buf map/unmap hooks for 5.5 kernel
+    - LF-1278:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: implement ctrl to set h264 aspect
+      ratio
+    - MLK-23723: arm64: imx8mp: vpu: fix g1/g2 timeout during suspend/resume
+    - MGS-5596 [#imx-2035] [1/2] PM QoS feature development
+    - MGS-5551 [#imx-1868] Update GPU database
+    - MGS-5653 [#imx-2041] modify clock prepare/unprepare along with power on/off
+    - MA-17115 mxc: vpu_malone: send error event when firmware exception
+    - mxc: vpu_malone: fix build issue as module
+    - mxc: vpu_maline: Fix Kconfig to depends on VIDEO_V4L2
+    - MLK-24009-1 arm64: imx8mp: vpu: vc8000e: fix build issue as module
+    - MLK-24009-2 arm64: imx8mp: vpu: g1/g2: fix build issue as module
+    - MLK-24009-3 arm64: imx8mm: vpu: h1: fix build issue as module
+    - MLK-24009-4 arm64: imx8mq: vpu: g1/g2: fix build issue as module
+    - MLK-24090 mxc: ipu3: ipu_device: Fix AB-BA deadlock between vdoa_lock and
+      ipu_ch_tbl.lock
+    - LF-1406-1:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support insmod separately
+    - LF-1406-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support insmod repeatly
+    - LF-1405-1: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: support insmod separately
+    - LF-1405-2:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: support insmod repeatly
+    - LF-1430-1 mxc: vpu_malone: refine insert scode for VC1 format
+    - LF-1430-2 mxc: vpu_malone: correct VP8 ivf frame header
+    - LF-1430-3 mxc: vpu_malone: unify set payload header
+    - LF-1430-4 mxc: vpu_malone: refine the operation of insert scode
+    - MGS-5060 [#imx-1868] 0021-Update-gc_feature_database.h-to-271754
+    - MGS-5709 [#imx-1439] fix gpu suspend/resume stuck
+    - MGS-5531 [#imx-1868] Fix VIP Hang isse with HW reet
+    - MGS-5768 [#imx-2132] fix android cts memory leak with
+      CL_MEM_USE_HOST_PHYSICAL_ADDR_VIV
+    - MLK-20236 mxc: sim/emvsim: useless call
+    - MGS-5787 [#imx-1868] 0003-CL275293-fix-flop-tp-reset-issue
+    - MGS-5787 [#imx-1868] 0004-CL275303-default-open-flopreset-with-TP
+    - MGS-5787 [#imx-1868] Update database for GPU/VIP
+    - MGS-5789 [#imx-2156] Fix Coverity issue in VIP PM HW workaround
+    - LF-1572 mxc: sim: Unchecked return value
+    - LF-1573 mxc: sim: Unchecked return value
+    - MLK-24363-1 mxc: emvsim: add error check when enable clk
+    - MLK-24363-2 mxc: emvsim: fix error report in probe stage
+    - MLK-24364 mxc: sim: add runtime pm support
+    - LF-1681: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: delete redundant data before
+      start code
+    - MA-17404 [#imx-2206] Kernel code copyright and license issue.
+    - MGS-5806 [#ccc] fix 8mm gpu hang due to dummy draw
+    - MLK-24404-1 mxc: vpu_malone: correct device power usage_count
+    - MLK-24404-2 mxc: vpu_windsor: correct device power usage_count
+    - MLK-24373-1 arm64: imx8mp: vpu: g1/g2: fix blocking issue in suspend
+    - MLK-24373-2 arm64: imx8mp: vpu: g1/g2: fix potential deadlock issue
+    - MLK-24477-2:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: enable color description in
+      vui
+    - MLK-24477-3:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: improve get/set color api
+    - MGS-5849 Integrate VSI GPU 6.4.3.p0 kernel driver
+    - LF-2138: mxc: vpu_malone: change typedef of 'valid_ts_received' to unsigned
+      int
+    - LF-2111: mxc: vpu_windsor: Avoid hide parameter
+    - MGS-5933-1 [#ccc] reenable m865s gpu TX clock gating
+    - MGS-5928-1 [#ccc] allocate auxiliary memory for cacheable map
+    - MGS-5928-2 [#ccc] support virtual memory in normal zone
+    - MLK-24477-4:[8QM_MEK/8QXP_MEK]mxc:vpu_malone: report color space by try_fmt
+    - MGS-5928-3 [#ccc] fix Android kernel crash problem
+    - MLK-24499: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: set low latency mode through
+      set bframe
+    - MGS-5943 [#imx-2089] 0079-CL290440-KERNEL-SPACE-6.4.x-Always-enable-
+      gcdIGNORE_
+    - MGS-5943 [#imx-2089] 0081-BUG27413-CL290463-KERNEL-SPACE-64x_234062-ocl-fix-
+      th
+    - MGS-5943 [#imx-2089] 0091-KERNEL-SPACE-Update-
+      gc_feature_database.h-to-290561
+    - MLK-24593:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: support change bitrate
+      dynamically
+    - MA-17341 [#imx-2211] Remove ts_address code to keep align with Linux
+    - MA-17341-2 [#imx-2211] Fix kernel panic when do stop on android
+    - MA-17683 [#imx-2302] Fix video playback "rcu stall" issue on 8mq
+    - MGS-5972 [#imx-2089] 0011-CL292878-KERNEL-SPACE-dev64x_234062-show-gpu-
+      video-m
+    - MGS-5972 [#imx-2089] 0038-KERNEL-SPACE-Update-
+      gc_feature_database.h-to-295136
+    - MA-18037 [#imx-2356] import vfs namespace to fix GPU module load errors
+    - MGS-6025: sync GPU kernel driver with 20201015 version
+    - MGS-6026 mxc/gpu-viv: integrate 6.4.3.p1 kernel
+    - MGS-6012-5 [#imx-2337] fix 6.4.3.p1 build break for L5.10
+    - MGS-6012-6 [#imx-2337] refine mmap_sem fix for L5.10 kernel
+    - MGS-6010 [#ccc] gpu: add GetSGT callback for reserved_mem
+    - LF-2118 [#ccc] fixed Coverity Issue:6124050
+    - LF-2118-2 [#ccc] fixed Coverity Issue:6124050
+    - MGS-5990-3 [#ccc] refine gpu memory bank configuration
+    - MGS-5990-4 [#ccc] fix the uninitialized variable
+    - MGS-6026-2 sync gpu database with formal 6.4.3.p1
+    - LF-2473 [#ccc] Coverity Issue:10281263
+    - LF-2466 [#ccc] fix the dereference issue
+    - LF-2461 [#ccc] use inline to fix multi-defination
+    - LF-2457 [#ccc] fix the Dereferencing null pointer
+    - LF-2478 [#ccc] fix the dereferencing null pointer
+    - LF-2480 [#ccc] rm DEBUG print as it print below like external mem
+    - LF-2492 [#ccc] check sscanf return value
+    - LF-2473 [#ccc] Coverity Issue:10281263
+    - MGS-4929 [#imx-2382] enable vivante drm for linux build
+    - MGS-6058 [#imx-2391] fix vivante drm build break for L5.10
+    - MGS-6060 gpu-viv: sync 20201116 patch release
+    - MGS-6060-2 gpu-viv: fix build break
+    - MLK-24959: [8QM_MEK/8QXP_MEK]mxc:vpu_windsor: move timestamp handler to
+      firmware
+    - MLK-24960: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: move timestamp manager to
+      firmware
+    - MGS-6108 [#imx-2416] fix GPU exception to access the freed MMU page
+    - MGS-6108-2 [#imx-2416] fix vg kernel panic for command unlock
+    - MGS-6108-3 [#imx-2416] fix gcdENABLE_VG logic issue
+    - MLK-21876-21 mxcfb: add uapi headfile for yocto build pass
+    - MLK-21876-17 mxc_v4l2: add uapi headfile for yocto build pass
+    - MLK-24874-3: include: uapi: mxc_v4l2: fix the UAPI_HEADER_TEST failure
+    - MLK-21876-19 pxp_dma: add uapi headfile for yocto build pass
+    - MLK-21876-13 ipu: add uapi headfile for yocto build pass
+    - MLK-24874-5: include: uapi: ipu: fix the UAPI_HEADER_TEST failure
+    - MLK-21876-12 vpu: add handro h1 headfile for Yocto build pass
+    - MA-11994 Add get phys address ioctl to dma-buf.
+    - MLK-16130-2: ASoC: fsl: add machine driver for cadence hdmi
+    - MLK-16159: ASoC: imx_cdnhdmi: refine the N value selection
+    - MLK-16538-2: hdmi api: Relocate hdmi api soure code
+    - MLK-13946-4: ASoC: imx-cdnhdmi: refine machine driver for api changes
+    - MLK-17344-1: ASoC: imx-cdnhdmi: get constraint rate from dts
+    - MLK-17620-2: ASoC: imx-cdnhdmi: switch to generic hdmi codec
+    - MLK-18368-2: ASoC: fsl: support hdmi rx in machine driver
+    - MLK-18833: ASoC: imx-cdnhdmi: fix no sound card issue
+    - MLK-20183-2: ASoC: imx-cdnhdmi: reconfigure the mclk for HDMI on imx8mq
+    - ASoC: imx-cdnhdmi: Fix compile error
+    - MLK-23642-3: ASoC: fsl: imx-cdnhdmi: support 6 channels
+    - MLK-24611-3: ASoC: imx-cdnhdmi: Add hdmi jack
+    - LF-2700: ASoC: fsl: imx-cdnhdmi: Fix error prompt
+    - MLK-23287-1: ASoC: fsl_aud2htx: Add aud2htx module driver
+    - MLK-23906-1: ASoC: fsl_aud2htx: Don't bind clock with regmap
+    - imx busfreq: Add API header file
+    - Add MU module for vpu dependence on QXP/QM
+    - MLK-9769-1 crypto: caam/jr - remove incorrect comment from job ring module
+    - MLK-20204 crypto: caam - remove deadcode on 32-bit platforms
+    - MLK-9769-9 crypto: caam - adjust RNG timing to support more devices
+    - MLK-9769-8 crypto: caam - add a test for the RNG
+    - MLKU-114-1 crypto: caam - reduce page 0 regs access to minimum
+    - MLKU-114-2 crypto: caam - SCU firmware support
+    - MLKU-114-3 crypto: caam - OP-TEE firmware support
+    - MLKU-38-3 crypto: caam - add SNVS / SECVIO support
+    - MLKU-25-3 crypto: caam - add Secure Memory support
+    - MLK-19801-1 crypto: caam - add tag functionality
+    - MLK-19801-2 crypto: caam - add support of tagged keys in caamalg
+    - MLK-10036 crypto: caam - add support for DSM with Mega/Fast mix on
+    - MLK-19449 crypto: caam - Change structure type representing DECO MID
+    - LFV-26 crypto: caam - fix Secure Memory driver init
+    - LF-63-1 crypto: caam - fix SM test init
+    - crypto: caam - fix snvs clk prepare+enable
+    - LF-838: crypto: caam - increase the domain of write memory barrier to full
+      system
+    - MLK-23774 crypto: caam - fix SNVS / SECVIO building as module
+    - MLK-21689 crypto: caam - make snvs clock optional
+    - MLK-23664-2 crypto: caam - allocate RNG instantiation descriptor with
+      GFP_DMA
+    - MLK-24420-1 crypto: caam - update tagged keys functionality and tk
+      transformations for skcipher
+    - MLK-24420-2 crypto: caam - add support for black keys and blobs
+    - MLK-24420-3 crypto: caam - add ioctl calls for black keys and blobs
+      generation
+    - MLK-24497 crypto: caam - update tagged object functionality by adding red
+      key length
+    - MLK-24496 crypto: caam - fix blob encapsulation/decapsulation
+    - MLK-24496 crypto: caam - add tag object header to blob
+    - MLK-24497 crypto: caam - update job descriptor with inline commands
+    - MLK-24517-1 crypto: caam - removed unnecessary validation of black key for
+      blob decapsulation
+    - MLK-24517-2 crypto: caam - removed unnecessary validation of black key for
+      blob encapsulation
+    - MLK-24517-3 crypto: caam - add null terminator to temporary buffer
+    - MLK-24517-4 crypto: caam - validate arguments received from user-space
+    - MLK-23664-3 crypto: caam - use struct hwrng's .init for initialization
+    - MLK-23664-4 crypto: caam - drop global context pointer and init_done
+    - MLK-23664-7 crypto: caam - invalidate entropy register during RNG
+      initialization
+    - MLK-21698: tee:optee: fix shared memory page attribute checks
+    - driver: tee: Handle NULL pointer indication from client
+    - tee: add support for session's client UUID generation
+    - tee: optee: Add support for session login client UUID generation
+    - tee: optee: remove need_resched() before cond_resched()
+    - MLK-16912 PL310: unlock ways during initialization
+    - MLK-16224-1: dmaengine: add src_fifo_num and dst_fifo_num in
+      dma_slave_config
+    - MLK-17385: dma: imx-sdma: update sdma script for multi fifo on SAI
+    - dma: engine: imx-sdma: add mcu_2_ecspi script
+    - dmaengine: imx-sdma: remove ERR009165 on i.mx6ul
+    - dmaengine: imx-sdma: fix ecspi1 rx dma not work on i.mx8mm
+    - dmaengine: imx-sdma: support allocate memory from iram
+    - dmaengine: imx-sdma: Add hdmi audio support in sdma
+    - dmaengine: imx-sdma: add sdma resume back after megafast off
+    - MLK-11259-1: dmaengine: imx-sdma: support dual fifo for DEV_TO_DEV
+    - MLK-16885-1: DMA: imx-sdma: update the buswidth that is supported
+    - include: dma-imx: support dual fifo for for DEV_TO_DEV
+    - dmaengine: imx-sdma: update sdma script for multi fifo on SAI
+    - MLK-22239-1: dmaengine: imx-sdma: Support 24bit/3bytes for sg mode
+    - dma: imx-sdma: Fix issue with IMX_DMATYPE_HDMI
+    - dma: imx-sdma: Add pm_ops to support suspend & resume
+    - MLK-22972 dmaengine: imx-sdma: correct the script number for v3
+    - MLK-23005: dmaengine: imx-sdma: correct data size of channel context
+    - LF-246: dmaengine: imx-sdma: correct is_ram_script checking
+    - LF-301: dmaengine: imx-sdma: Add once more loading firmware
+    - MLK-23400-1: dmaengine: imx-sdma: add sdma restore back for i.mx8mp
+    - MLK-20598 dmaengine: imx-sdma: fix potential system hang
+    - MLK-23869-1 dmaengine: imx-sdma: split sdma init hw and sw
+    - MLK-23869-2 dmaengine: imx-sdma: add runtime suspend/resume
+    - MLK-23869-3: dmaengine: imx-sdma: add sdma_get_firmware_wait
+    - MLK-24071 dmaengine: imx-sdma: fix random channel stop
+    - MLK-23540 dmaengine: imx-sdma: restore DONEx_CONFIG register
+    - MLK-24483-1: dmaengine: imx-sdma: remove ecspi_fixed on imx8mq
+    - MLK-25116-1: dmaengine: imx-sdma: save iram pool for bd allocated
+    - MLK-25116-2: dmaengine: imx-sdma: correct iram_pool check point
+    - LF-3132: dmaengine: imx-sdma: raise up channel0 priority after resume
+    - net: fec: add FEC_QUIRK_HAS_MULTI_QUEUES represents i.MX6SX ENET IP
+    - net: fec: add ndo_select_queue to fix TX bandwidth fluctuations
+    - MLK-16347-6 drm/bridge: adv7511: Add new compatible string
+    - MLK-16918-15 drm/bridge: Update adv7511 driver with some regs for adv7535
+    - MLK-16986-4 drm/bridge: adv7511: set bus_flags and bus_format
+    - MLK-17275-1 drm/bridge: adv7511: Add support for OF_DYNAMIC
+    - MLK-17275-7 drm/bridge: adv7511: Add dsi-channel property
+    - MLK-17650-1 drm/bridge: adv7511: Add support for programmable i2c addresses
+    - MLK-18877-1 drm/bridge: adv7511: Add debug info for HPD event
+    - MLK-17537-1 drm/bridge: Correct the ADV7533 init
+    - MLK-21958-13: drm/bridge: adv7511: Limit supported clocks
+    - drm/bridge: adv7511: Fix of_reconfig
+    - MA-17597-1 gpu: drm: select OF_DYNAMIC in it6263 and adv7511 config
+    - optee: model OP-TEE as a platform device/driver
+    - optee: use uuid for sysfs driver entry
+    - optee: enable support for multi-stage bus enumeration
+    - tpm_ftpm_tee: register driver on TEE bus
+    - hwrng: optee - handle unlimited data rates
+    - hwrng: optee - fix wait use case
+    - optee: Refuse to load the driver under the kdump kernel
+    - optee: fix tee out of memory failure seen during kexec reboot
+    - TEE-349 RPC Busfreq High
+
+  [ Ubuntu: 5.4.0-120.136 ]
+
+  * CVE-2022-21123 // CVE-2022-21125 // CVE-2022-21166
+    - cpu/speculation: Add prototype for cpu_show_srbds()
+    - x86/cpu: Add Jasper Lake to Intel family
+    - 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
+    - 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
+
+  [ Ubuntu: 5.4.0-117.132 ]
+
+  * CVE-2022-1966
+    - netfilter: nf_tables: add nft_set_elem_expr_alloc()
+    - netfilter: nf_tables: disallow non-stateful expression in sets earlier
+
+  [ Ubuntu: 5.4.0-115.129 ]
+
+  * CVE-2022-21499
+    - SAUCE: debug: Lock down kgdb
+
+  [ Ubuntu: 5.4.0-114.128 ]
+
+  * focal/linux: 5.4.0-114.128 -proposed tracker (LP: #1974391)
+  * 32 GT/s PCI link speeds reporting "Unknown speed" in sysfs (LP: #1970798)
+    - PCI: Add 32 GT/s decoding in some macros
+    - PCI: Add pci_speed_string()
+    - PCI: Use pci_speed_string() for all PCI/PCI-X/PCIe strings
+    - PCI: Add PCIE_LNKCAP2_SLS2SPEED() macro
+  * issuing invalid ioctl to /dev/vsock may spam dmesg (LP: #1971480)
+    - vsock: remove ratelimit unknown ioctl message
+  * config CONFIG_HISI_PMU for  kunpeng920 (LP: #1956086)
+    - drivers/perf: hisi: Permit modular builds of HiSilicon uncore drivers
+    - [Config] CONFIG_HISI_PMU=m
+  * Focal update: v5.4.189 upstream stable release (LP: #1971497)
+    - swiotlb: fix info leak with DMA_FROM_DEVICE
+    - USB: serial: pl2303: add IBM device IDs
+    - USB: serial: simple: add Nokia phone driver
+    - netdevice: add the case if dev is NULL
+    - HID: logitech-dj: add new lightspeed receiver id
+    - xfrm: fix tunnel model fragmentation behavior
+    - virtio_console: break out of buf poll on remove
+    - ethernet: sun: Free the coherent when failing in probing
+    - spi: Fix invalid sgs value
+    - net:mcf8390: Use platform_get_irq() to get the interrupt
+    - spi: Fix erroneous sgs value with min_t()
+    - af_key: add __GFP_ZERO flag for compose_sadb_supported in function
+      pfkey_register
+    - net: dsa: microchip: add spi_device_id tables
+    - iommu/iova: Improve 32-bit free space estimate
+    - tpm: fix reference counting for struct tpm_chip
+    - block: Add a helper to validate the block size
+    - virtio-blk: Use blk_validate_block_size() to validate block size
+    - USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c
+    - xhci: fix runtime PM imbalance in USB2 resume
+    - xhci: make xhci_handshake timeout for xhci_reset() adjustable
+    - xhci: fix uninitialized string returned by xhci_decode_ctrl_ctx()
+    - coresight: Fix TRCCONFIGR.QE sysfs interface
+    - iio: afe: rescale: use s64 for temporary scale calculations
+    - iio: inkern: apply consumer scale on IIO_VAL_INT cases
+    - iio: inkern: apply consumer scale when no channel scale is available
+    - iio: inkern: make a best effort on offset calculation
+    - greybus: svc: fix an error handling bug in gb_svc_hello()
+    - clk: uniphier: Fix fixed-rate initialization
+    - KEYS: fix length validation in keyctl_pkey_params_get_2()
+    - Documentation: add link to stable release candidate tree
+    - Documentation: update stable tree link
+    - HID: intel-ish-hid: Use dma_alloc_coherent for firmware update
+    - SUNRPC: avoid race between mod_timer() and del_timer_sync()
+    - NFSD: prevent underflow in nfssvc_decode_writeargs()
+    - NFSD: prevent integer overflow on 32 bit systems
+    - f2fs: fix to unlock page correctly in error path of is_alive()
+    - f2fs: quota: fix loop condition at f2fs_quota_sync()
+    - f2fs: fix to do sanity check on .cp_pack_total_block_count
+    - pinctrl: samsung: drop pin banks references on error paths
+    - spi: mxic: Fix the transmit path
+    - jffs2: fix use-after-free in jffs2_clear_xattr_subsystem
+    - jffs2: fix memory leak in jffs2_do_mount_fs
+    - jffs2: fix memory leak in jffs2_scan_medium
+    - mm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node
+    - mm: invalidate hwpoison page cache page in fault path
+    - mempolicy: mbind_range() set_policy() after vma_merge()
+    - scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands
+    - qed: display VF trust config
+    - qed: validate and restrict untrusted VFs vlan promisc mode
+    - riscv: Fix fill_callchain return value
+    - Revert "Input: clear BTN_RIGHT/MIDDLE on buttonpads"
+    - ALSA: cs4236: fix an incorrect NULL check on list iterator
+    - ALSA: hda/realtek: Fix audio regression on Mi Notebook Pro 2020
+    - mm,hwpoison: unmap poisoned page before invalidation
+    - mm/kmemleak: reset tag when compare object pointer
+    - drbd: fix potential silent data corruption
+    - powerpc/kvm: Fix kvm_use_magic_page
+    - udp: call udp_encap_enable for v6 sockets when enabling encap
+    - ACPI: properties: Consistently return -ENOENT if there are no more
+      references
+    - drivers: hamradio: 6pack: fix UAF bug caused by mod_timer()
+    - mailbox: tegra-hsp: Flush whole channel
+    - block: don't merge across cgroup boundaries if blkcg is enabled
+    - drm/edid: check basic audio support on CEA extension block
+    - video: fbdev: sm712fb: Fix crash in smtcfb_read()
+    - video: fbdev: atari: Atari 2 bpp (STe) palette bugfix
+    - ARM: dts: at91: sama5d2: Fix PMERRLOC resource size
+    - ARM: dts: exynos: fix UART3 pins configuration in Exynos5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5250
+    - ARM: dts: exynos: add missing HDMI supplies on SMDK5420
+    - carl9170: fix missing bit-wise or operator for tx_params
+    - thermal: int340x: Increase bitmap size
+    - lib/raid6/test: fix multiple definition linking error
+    - crypto: rsa-pkcs1pad - correctly get hash from source scatterlist
+    - crypto: rsa-pkcs1pad - restore signature length check
+    - crypto: rsa-pkcs1pad - fix buffer overread in pkcs1pad_verify_complete()
+    - DEC: Limit PMAX memory probing to R3k systems
+    - media: davinci: vpif: fix unbalanced runtime PM get
+    - xtensa: fix stop_machine_cpuslocked call in patch_text
+    - xtensa: fix xtensa_wsr always writing 0
+    - brcmfmac: firmware: Allocate space for default boardrev in nvram
+    - brcmfmac: pcie: Release firmwares in the brcmf_pcie_setup error path
+    - brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toio
+    - brcmfmac: pcie: Fix crashes due to early IRQs
+    - PCI: pciehp: Clear cmd_busy bit in polling mode
+    - regulator: qcom_smd: fix for_each_child.cocci warnings
+    - crypto: authenc - Fix sleep in atomic context in decrypt_tail
+    - crypto: mxs-dcp - Fix scatterlist processing
+    - spi: tegra114: Add missing IRQ check in tegra_spi_probe
+    - selftests/x86: Add validity check and allow field splitting
+    - audit: log AUDIT_TIME_* records only from rules
+    - crypto: ccree - don't attempt 0 len DMA mappings
+    - spi: pxa2xx-pci: Balance reference count for PCI DMA device
+    - hwmon: (pmbus) Add mutex to regulator ops
+    - hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNING
+    - block: don't delete queue kobject before its children
+    - PM: hibernate: fix __setup handler error handling
+    - PM: suspend: fix return value of __setup handler
+    - hwrng: atmel - disable trng on failure path
+    - crypto: vmx - add missing dependencies
+    - clocksource/drivers/timer-of: Check return value of of_iomap in
+      timer_of_base_init()
+    - ACPI: APEI: fix return value of __setup handlers
+    - crypto: ccp - ccp_dmaengine_unregister release dma channels
+    - hwmon: (pmbus) Add Vin unit off handling
+    - clocksource: acpi_pm: fix return value of __setup handler
+    - sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa
+    - perf/core: Fix address filter parser for multiple filters
+    - perf/x86/intel/pt: Fix address filter config for 32-bit kernel
+    - f2fs: fix missing free nid in f2fs_handle_failed_inode
+    - f2fs: fix to avoid potential deadlock
+    - media: bttv: fix WARNING regression on tunerless devices
+    - media: coda: Fix missing put_device() call in coda_get_vdoa_data
+    - media: hantro: Fix overfill bottom register field name
+    - media: aspeed: Correct value for h-total-pixels
+    - video: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe()
+    - video: fbdev: atmel_lcdfb: fix an error code in atmel_lcdfb_probe()
+    - video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name()
+    - ARM: dts: qcom: ipq4019: fix sleep clock
+    - soc: qcom: rpmpd: Check for null return of devm_kcalloc
+    - soc: qcom: aoss: remove spurious IRQF_ONESHOT flags
+    - arm64: dts: qcom: sm8150: Correct TCS configuration for apps rsc
+    - soc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe
+    - ARM: dts: imx: Add missing LVDS decoder on M53Menlo
+    - media: video/hdmi: handle short reads of hdmi info frame.
+    - media: em28xx: initialize refcount before kref_get
+    - media: usb: go7007: s2250-board: fix leak in probe()
+    - uaccess: fix nios2 and microblaze get_user_8()
+    - ASoC: rt5663: check the return value of devm_kzalloc() in rt5663_parse_dp()
+    - ASoC: ti: davinci-i2s: Add check for clk_enable()
+    - ALSA: spi: Add check for clk_enable()
+    - arm64: dts: ns2: Fix spi-cpol and spi-cpha property
+    - arm64: dts: broadcom: Fix sata nodename
+    - printk: fix return value of printk.devkmsg __setup handler
+    - ASoC: mxs-saif: Handle errors for clk_enable
+    - ASoC: atmel_ssc_dai: Handle errors for clk_enable
+    - ASoC: soc-compress: prevent the potentially use of null pointer
+    - memory: emif: Add check for setup_interrupts
+    - memory: emif: check the pointer temp in get_device_details()
+    - ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction
+    - arm64: dts: rockchip: Fix SDIO regulator supply properties on rk3399-firefly
+    - media: stk1160: If start stream fails, return buffers with
+      VB2_BUF_STATE_QUEUED
+    - ASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe
+    - ASoC: wm8350: Handle error for wm8350_register_irq
+    - ASoC: fsi: Add check for clk_enable
+    - video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of
+    - ivtv: fix incorrect device_caps for ivtvfb
+    - ASoC: dmaengine: do not use a NULL prepare_slave_config() callback
+    - ASoC: mxs: Fix error handling in mxs_sgtl5000_probe
+    - ASoC: imx-es8328: Fix error return code in imx_es8328_probe()
+    - ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in
+      msm8916_wcd_digital_probe
+    - mmc: davinci_mmc: Handle error for clk_enable
+    - ASoC: msm8916-wcd-analog: Fix error handling in pm8916_wcd_analog_spmi_probe
+    - drm/bridge: Fix free wrong object in sii8620_init_rcp_input_dev
+    - drm/bridge: Add missing pm_runtime_disable() in __dw_mipi_dsi_probe
+    - ath10k: fix memory overwrite of the WoWLAN wakeup packet pattern
+    - udmabuf: validate ubuf->pagecount
+    - Bluetooth: hci_serdev: call init_rwsem() before p->open()
+    - mtd: onenand: Check for error irq
+    - mtd: rawnand: gpmi: fix controller timings setting
+    - drm/edid: Don't clear formats if using deep color
+    - drm/amd/display: Fix a NULL pointer dereference in
+      amdgpu_dm_connector_add_common_modes()
+    - ath9k_htc: fix uninit value bugs
+    - KVM: PPC: Fix vmx/vsx mixup in mmio emulation
+    - i40e: don't reserve excessive XDP_PACKET_HEADROOM on XSK Rx to skb
+    - power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probe
+    - ray_cs: Check ioremap return value
+    - powerpc/perf: Don't use perf_hw_context for trace IMC PMU
+    - mt76: mt7603: check sta_rates pointer in mt7603_sta_rate_tbl_update
+    - mt76: mt7615: check sta_rates pointer in mt7615_sta_rate_tbl_update
+    - net: dsa: mv88e6xxx: Enable port policy support on 6097
+    - PCI: aardvark: Fix reading PCI_EXP_RTSTA_PME bit on emulated bridge
+    - power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_init
+    - HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports
+    - iommu/ipmmu-vmsa: Check for error num after setting mask
+    - drm/amd/display: Add affected crtcs to atomic state for dsc mst unplug
+    - IB/cma: Allow XRC INI QPs to set their local ACK timeout
+    - dax: make sure inodes are flushed before destroy cache
+    - iwlwifi: Fix -EIO error code that is never returned
+    - iwlwifi: mvm: Fix an error code in iwl_mvm_up()
+    - dm crypt: fix get_key_size compiler warning if !CONFIG_KEYS
+    - scsi: pm8001: Fix command initialization in pm80XX_send_read_log()
+    - scsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req()
+    - scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config()
+    - scsi: pm8001: Fix abort all task initialization
+    - drm/amd/display: Remove vupdate_int_entry definition
+    - TOMOYO: fix __setup handlers return values
+    - ext2: correct max file size computing
+    - drm/tegra: Fix reference leak in tegra_dsi_ganged_probe
+    - power: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false
+      return
+    - scsi: hisi_sas: Change permission of parameter prot_mask
+    - drm/bridge: cdns-dsi: Make sure to to create proper aliases for dt
+    - bpf, arm64: Call build_prologue() first in first JIT pass
+    - bpf, arm64: Feed byte-offset into bpf line info
+    - libbpf: Skip forward declaration when counting duplicated type names
+    - powerpc/Makefile: Don't pass -mcpu=powerpc64 when building 32-bit
+    - KVM: x86: Fix emulation in writing cr8
+    - KVM: x86/emulator: Defer not-present segment check in
+      __load_segment_descriptor()
+    - hv_balloon: rate-limit "Unhandled message" warning
+    - i2c: xiic: Make bus names unique
+    - power: supply: wm8350-power: Handle error for wm8350_register_irq
+    - power: supply: wm8350-power: Add missing free in free_charger_irq
+    - PCI: Reduce warnings on possible RW1C corruption
+    - mips: DEC: honor CONFIG_MIPS_FP_SUPPORT=n
+    - powerpc/sysdev: fix incorrect use to determine if list is empty
+    - mfd: mc13xxx: Add check for mc13xxx_irq_request
+    - selftests/bpf: Make test_lwt_ip_encap more stable and faster
+    - powerpc: 8xx: fix a return value error in mpc8xx_pic_init
+    - vxcan: enable local echo for sent CAN frames
+    - MIPS: RB532: fix return value of __setup handler
+    - mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init
+    - RDMA/mlx5: Fix memory leak in error flow for subscribe event routine
+    - bpf, sockmap: Fix memleak in tcp_bpf_sendmsg while sk msg is full
+    - bpf, sockmap: Fix more uncharged while msg has more_data
+    - bpf, sockmap: Fix double uncharge the mem of sk_msg
+    - USB: storage: ums-realtek: fix error code in rts51x_read_mem()
+    - Bluetooth: btmtksdio: Fix kernel oops in btmtksdio_interrupt
+    - af_netlink: Fix shift out of bounds in group mask calculation
+    - i2c: mux: demux-pinctrl: do not deactivate a master that is not active
+    - selftests/bpf/test_lirc_mode2.sh: Exit with proper code
+    - tcp: ensure PMTU updates are processed during fastopen
+    - openvswitch: always update flow key after nat
+    - tipc: fix the timer expires after interval 100ms
+    - mfd: asic3: Add missing iounmap() on error asic3_mfd_probe
+    - mxser: fix xmit_buf leak in activate when LSR == 0xff
+    - pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()
+    - misc: alcor_pci: Fix an error handling path
+    - staging:iio:adc:ad7280a: Fix handing of device address bit reversing.
+    - pinctrl: renesas: r8a77470: Reduce size for narrow VIN1 channel
+    - clk: qcom: ipq8074: Use floor ops for SDCC1 clock
+    - phy: dphy: Correct lpx parameter and its derivatives(ta_{get,go,sure})
+    - serial: 8250_mid: Balance reference count for PCI DMA device
+    - serial: 8250: Fix race condition in RTS-after-send handling
+    - iio: adc: Add check for devm_request_threaded_irq
+    - NFS: Return valid errors from nfs2/3_decode_dirent()
+    - dma-debug: fix return value of __setup handlers
+    - clk: imx7d: Remove audio_mclk_root_clk
+    - clk: qcom: clk-rcg2: Update logic to calculate D value for RCG
+    - clk: qcom: clk-rcg2: Update the frac table for pixel clock
+    - remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_region
+    - remoteproc: qcom_wcnss: Add missing of_node_put() in
+      wcnss_alloc_memory_region
+    - clk: actions: Terminate clk_div_table with sentinel element
+    - clk: loongson1: Terminate clk_div_table with sentinel element
+    - clk: clps711x: Terminate clk_div_table with sentinel element
+    - clk: tegra: tegra124-emc: Fix missing put_device() call in
+      emc_ensure_emc_driver
+    - NFS: remove unneeded check in decode_devicenotify_args()
+    - staging: mt7621-dts: fix LEDs and pinctrl on GB-PC1 devicetree
+    - pinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_init
+    - pinctrl: mediatek: paris: Fix "argument" argument type for mtk_pinconf_get()
+    - pinctrl: mediatek: paris: Fix pingroup pin config state readback
+    - pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe
+    - pinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe
+    - tty: hvc: fix return value of __setup handler
+    - kgdboc: fix return value of __setup handler
+    - kgdbts: fix return value of __setup handler
+    - firmware: google: Properly state IOMEM dependency
+    - driver core: dd: fix return value of __setup handler
+    - jfs: fix divide error in dbNextAG
+    - netfilter: nf_conntrack_tcp: preserve liberal flag in tcp options
+    - NFSv4.1: don't retry BIND_CONN_TO_SESSION on session error
+    - clk: qcom: gcc-msm8994: Fix gpll4 width
+    - clk: Initialize orphan req_rate
+    - xen: fix is_xen_pmu()
+    - net: phy: broadcom: Fix brcm_fet_config_init()
+    - selftests: test_vxlan_under_vrf: Fix broken test case
+    - qlcnic: dcb: default to returning -EOPNOTSUPP
+    - net/x25: Fix null-ptr-deref caused by x25_disconnect
+    - NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
+    - net: dsa: bcm_sf2_cfp: fix an incorrect NULL check on list iterator
+    - lib/test: use after free in register_test_dev_kmod()
+    - LSM: general protection fault in legacy_parse_param
+    - gcc-plugins/stackleak: Exactly match strings instead of prefixes
+    - pinctrl: npcm: Fix broken references to chip->parent_device
+    - block, bfq: don't move oom_bfqq
+    - selinux: use correct type for context length
+    - loop: use sysfs_emit() in the sysfs xxx show()
+    - Fix incorrect type in assignment of ipv6 port for audit
+    - irqchip/qcom-pdc: Fix broken locking
+    - irqchip/nvic: Release nvic_base upon failure
+    - bfq: fix use-after-free in bfq_dispatch_request
+    - ACPICA: Avoid walking the ACPI Namespace if it is not there
+    - lib/raid6/test/Makefile: Use $(pound) instead of \# for Make 4.3
+    - Revert "Revert "block, bfq: honor already-setup queue merges""
+    - ACPI/APEI: Limit printable size of BERT table data
+    - PM: core: keep irq flags in device_pm_check_callbacks()
+    - spi: tegra20: Use of_device_get_match_data()
+    - ext4: don't BUG if someone dirty pages without asking ext4 first
+    - ntfs: add sanity check on allocation size
+    - video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow
+    - video: fbdev: w100fb: Reset global state
+    - video: fbdev: cirrusfb: check pixclock to avoid divide by zero
+    - video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit
+    - ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960
+    - ARM: dts: bcm2837: Add the missing L1/L2 cache information
+    - ASoC: madera: Add dependencies on MFD
+    - video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf()
+    - video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of
+      snprintf()
+    - video: fbdev: udlfb: replace snprintf in show functions with sysfs_emit
+    - ASoC: soc-core: skip zero num_dai component in searching dai name
+    - media: cx88-mpeg: clear interrupt status register before streaming video
+    - ARM: tegra: tamonten: Fix I2C3 pad setting
+    - ARM: mmp: Fix failure to remove sram device
+    - video: fbdev: sm712fb: Fix crash in smtcfb_write()
+    - media: Revert "media: em28xx: add missing em28xx_close_extension"
+    - media: hdpvr: initialize dev->worker at hdpvr_register_videodev
+    - mmc: host: Return an error when ->enable_sdio_irq() ops is missing
+    - ALSA: hda/realtek: Add alc256-samsung-headphone fixup
+    - powerpc/lib/sstep: Fix 'sthcx' instruction
+    - powerpc/lib/sstep: Fix build errors with newer binutils
+    - powerpc: Fix build errors with newer binutils
+    - scsi: qla2xxx: Fix stuck session in gpdb
+    - scsi: qla2xxx: Fix wrong FDMI data for 64G adapter
+    - scsi: qla2xxx: Fix warning for missing error code
+    - scsi: qla2xxx: Fix device reconnect in loop topology
+    - scsi: qla2xxx: Add devids and conditionals for 28xx
+    - scsi: qla2xxx: Check for firmware dump already collected
+    - scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair()
+    - scsi: qla2xxx: Fix disk failure to rediscover
+    - scsi: qla2xxx: Fix incorrect reporting of task management failure
+    - scsi: qla2xxx: Fix hang due to session stuck
+    - scsi: qla2xxx: Fix missed DMA unmap for NVMe ls requests
+    - scsi: qla2xxx: Fix N2N inconsistent PLOGI
+    - scsi: qla2xxx: Reduce false trigger to login
+    - scsi: qla2xxx: Use correct feature type field during RFF_ID processing
+    - KVM: Prevent module exit until all VMs are freed
+    - KVM: x86: fix sending PV IPI
+    - ASoC: SOF: Intel: Fix NULL ptr dereference when ENOMEM
+    - ubifs: rename_whiteout: Fix double free for whiteout_ui->data
+    - ubifs: Fix deadlock in concurrent rename whiteout and inode writeback
+    - ubifs: Add missing iput if do_tmpfile() failed in rename whiteout
+    - ubifs: setflags: Make dirtied_ino_d 8 bytes aligned
+    - ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()
+    - ubifs: rename_whiteout: correct old_dir size computing
+    - XArray: Fix xas_create_range() when multi-order entry present
+    - can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path
+    - can: mcba_usb: properly check endpoint type
+    - XArray: Update the LRU list in xas_split()
+    - rtc: check if __rtc_read_time was successful
+    - gfs2: Make sure FITRIM minlen is rounded up to fs block size
+    - net: hns3: fix software vlan talbe of vlan 0 inconsistent with hardware
+    - pinctrl: pinconf-generic: Print arguments for bias-pull-*
+    - pinctrl: nuvoton: npcm7xx: Rename DS() macro to DSTR()
+    - pinctrl: nuvoton: npcm7xx: Use %zu printk format for ARRAY_SIZE()
+    - ASoC: mediatek: mt6358: add missing EXPORT_SYMBOLs
+    - ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
+    - ARM: iop32x: offset IRQ numbers by 1
+    - ACPI: CPPC: Avoid out of bounds access when parsing _CPC data
+    - powerpc/kasan: Fix early region not updated correctly
+    - ASoC: soc-compress: Change the check for codec_dai
+    - mm/mmap: return 1 from stack_guard_gap __setup() handler
+    - mm/memcontrol: return 1 from cgroup.memory __setup() handler
+    - mm/usercopy: return 1 from hardened_usercopy __setup() handler
+    - bpf: Fix comment for helper bpf_current_task_under_cgroup()
+    - dt-bindings: mtd: nand-controller: Fix the reg property description
+    - dt-bindings: mtd: nand-controller: Fix a comment in the examples
+    - dt-bindings: spi: mxic: The interrupt property is not mandatory
+    - ubi: fastmap: Return error code if memory allocation fails in add_aeb()
+    - ASoC: topology: Allow TLV control to be either read or write
+    - ARM: dts: spear1340: Update serial node properties
+    - ARM: dts: spear13xx: Update SPI dma properties
+    - um: Fix uml_mconsole stop/go
+    - openvswitch: Fixed nd target mask field in the flow dump.
+    - KVM: x86/mmu: do compare-and-exchange of gPTE via the user address
+    - KVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activated
+    - ubifs: Rectify space amount budget for mkdir/tmpfile operations
+    - rtc: wm8350: Handle error for wm8350_register_irq
+    - riscv module: remove (NOLOAD)
+    - ARM: 9187/1: JIVE: fix return value of __setup handler
+    - KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs
+    - drm: Add orientation quirk for GPD Win Max
+    - ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111
+    - drm/amd/amdgpu/amdgpu_cs: fix refcount leak of a dma_fence obj
+    - ptp: replace snprintf with sysfs_emit
+    - powerpc: dts: t104xrdb: fix phy type for FMAN 4/5
+    - bpf: Make dst_port field in struct bpf_sock 16-bit wide
+    - scsi: mvsas: Replace snprintf() with sysfs_emit()
+    - scsi: bfa: Replace snprintf() with sysfs_emit()
+    - power: supply: axp20x_battery: properly report current when discharging
+    - ipv6: make mc_forwarding atomic
+    - powerpc: Set crashkernel offset to mid of RMA region
+    - drm/amdgpu: Fix recursive locking warning
+    - PCI: aardvark: Fix support for MSI interrupts
+    - iommu/arm-smmu-v3: fix event handling soft lockup
+    - usb: ehci: add pci device support for Aspeed platforms
+    - PCI: pciehp: Add Qualcomm quirk for Command Completed erratum
+    - power: supply: axp288-charger: Set Vhold to 4.4V
+    - ipv4: Invalidate neighbour for broadcast address upon address addition
+    - dm ioctl: prevent potential spectre v1 gadget
+    - drm/amdkfd: make CRAT table missing message informational only
+    - scsi: pm8001: Fix pm8001_mpi_task_abort_resp()
+    - scsi: aha152x: Fix aha152x_setup() __setup handler return value
+    - net/smc: correct settings of RMB window update limit
+    - mips: ralink: fix a refcount leak in ill_acc_of_setup()
+    - macvtap: advertise link netns via netlink
+    - tuntap: add sanity checks about msg_controllen in sendmsg
+    - bnxt_en: Eliminate unintended link toggle during FW reset
+    - MIPS: fix fortify panic when copying asm exception handlers
+    - scsi: libfc: Fix use after free in fc_exch_abts_resp()
+    - usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evm
+    - xtensa: fix DTC warning unit_address_format
+    - Bluetooth: Fix use after free in hci_send_acl
+    - netlabel: fix out-of-bounds memory accesses
+    - init/main.c: return 1 from handled __setup() functions
+    - minix: fix bug when opening a file with O_DIRECT
+    - clk: si5341: fix reported clk_rate when output divider is 2
+    - w1: w1_therm: fixes w1_seq for ds28ea00 sensors
+    - NFSv4: Protect the state recovery thread against direct reclaim
+    - xen: delay xen_hvm_init_time_ops() if kdump is boot on vcpu>=32
+    - clk: Enforce that disjoints limits are invalid
+    - SUNRPC/call_alloc: async tasks mustn't block waiting for memory
+    - NFS: swap IO handling is slightly different for O_DIRECT IO
+    - NFS: swap-out must always use STABLE writes.
+    - serial: samsung_tty: do not unlock port->lock for uart_write_wakeup()
+    - virtio_console: eliminate anonymous module_init & module_exit
+    - jfs: prevent NULL deref in diFree
+    - SUNRPC: Fix socket waits for write buffer space
+    - parisc: Fix CPU affinity for Lasi, WAX and Dino chips
+    - parisc: Fix patch code locking and flushing
+    - mm: fix race between MADV_FREE reclaim and blkdev direct IO read
+    - KVM: arm64: Check arm64_get_bp_hardening_data() didn't return NULL
+    - drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire()
+    - Drivers: hv: vmbus: Fix potential crash on module unload
+    - scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one()
+    - net/tls: fix slab-out-of-bounds bug in decrypt_internal
+    - net: ipv4: fix route with nexthop object delete warning
+    - net: stmmac: Fix unset max_speed difference between DT and non-DT platforms
+    - drm/imx: Fix memory leak in imx_pd_connector_get_modes
+    - bnxt_en: reserve space inside receive page for skb_shared_info
+    - IB/rdmavt: add lock to call to rvt_error_qp to prevent a race condition
+    - dpaa2-ptp: Fix refcount leak in dpaa2_ptp_probe
+    - ipv6: Fix stats accounting in ip6_pkt_drop
+    - net: openvswitch: don't send internal clone attribute to the userspace.
+    - rxrpc: fix a race in rxrpc_exit_net()
+    - qede: confirm skb is allocated before using
+    - spi: bcm-qspi: fix MSPI only access with bcm_qspi_exec_mem_op()
+    - bpf: Support dual-stack sockets in bpf_tcp_check_syncookie
+    - drbd: Fix five use after free bugs in get_initial_state
+    - SUNRPC: Handle ENOMEM in call_transmit_status()
+    - SUNRPC: Handle low memory situations in call_status()
+    - perf tools: Fix perf's libperf_print callback
+    - perf session: Remap buf if there is no space for event
+    - Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"
+    - mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is
+      complete
+    - lz4: fix LZ4_decompress_safe_partial read out of bound
+    - mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0)
+    - mm/mempolicy: fix mpol_new leak in shared_policy_replace
+    - x86/pm: Save the MSR validity status at context setup
+    - x86/speculation: Restore speculation related MSRs during S3 resume
+    - btrfs: fix qgroup reserve overflow the qgroup limit
+    - arm64: patch_text: Fixup last cpu should be master
+    - ata: sata_dwc_460ex: Fix crash due to OOB write
+    - perf: qcom_l2_pmu: fix an incorrect NULL check on list iterator
+    - irqchip/gic-v3: Fix GICR_CTLR.RWP polling
+    - tools build: Filter out options and warnings not supported by clang
+    - tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts
+    - dmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error"
+    - mmc: mmci_sdmmc: Replace sg_dma_xxx macros
+    - mmc: mmci: stm32: correctly check all elements of sg list
+    - mm: don't skip swap entry even if zap_details specified
+    - arm64: module: remove (NOLOAD) from linker script
+    - mm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning
+    - drm/amdkfd: add missing void argument to function kgd2kfd_init
+    - drm/amdkfd: Fix -Wstrict-prototypes from
+      amdgpu_amdkfd_gfx_10_0_get_functions()
+    - cgroup: Use open-time credentials for process migraton perm checks
+    - cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv
+    - cgroup: Use open-time cgroup namespace for process migration perm checks
+    - selftests: cgroup: Make cg_create() use 0755 for permission instead of 0644
+    - selftests: cgroup: Test open-time credential usage for migration checks
+    - selftests: cgroup: Test open-time cgroup namespace usage for migration
+      checks
+    - cpuidle: PSCI: Move the `has_lpi` check to the beginning of the function
+    - ACPI: processor idle: Check for architectural support for LPI
+    - Linux 5.4.189
+  * Focal update: v5.4.188 upstream stable release (LP: #1971496)
+    - nfsd: cleanup nfsd_file_lru_dispose()
+    - nfsd: Containerise filecache laundrette
+    - net: ipv6: fix skb_over_panic in __ip6_append_data
+    - tpm: Fix error handling in async work
+    - staging: fbtft: fb_st7789v: reset display before initialization
+    - thermal: int340x: fix memory leak in int3400_notify()
+    - llc: fix netdevice reference leaks in llc_ui_bind()
+    - ALSA: pcm: Add stream lock during PCM reset ioctl operations
+    - ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB
+    - ALSA: cmipci: Restore aux vol on suspend/resume
+    - ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec
+    - drivers: net: xgene: Fix regression in CRC stripping
+    - ASoC: sti: Fix deadlock via snd_pcm_stop_xrun() call
+    - ALSA: oss: Fix PCM OSS buffer allocation overflow
+    - ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671
+    - ALSA: hda/realtek: Add quirk for ASUS GA402
+    - ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
+    - ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
+    - ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU
+    - crypto: qat - disable registration of algorithms
+    - rcu: Don't deboost before reporting expedited quiescent state
+    - mac80211: fix potential double free on mesh join
+    - tpm: use try_get_ops() in tpm-space.c
+    - nds32: fix access_ok() checks in get/put_user
+    - llc: only change llc->dev when bind() succeeds
+    - Linux 5.4.188
+  * Focal update: v5.4.187 upstream stable release (LP: #1971493)
+    - crypto: qcom-rng - ensure buffer for generate is completely filled
+    - ocfs2: fix crash when initialize filecheck kobj fails
+    - efi: fix return value of __setup handlers
+    - net: phy: marvell: Fix invalid comparison in the resume and suspend
+      functions
+    - net/packet: fix slab-out-of-bounds access in packet_recvmsg()
+    - atm: eni: Add check for dma_map_single
+    - hv_netvsc: Add check for kvmalloc_array
+    - drm/panel: simple: Fix Innolux G070Y2-L01 BPP settings
+    - net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit()
+    - net: dsa: Add missing of_node_put() in dsa_port_parse_of
+    - arm64: fix clang warning about TRAMP_VALIAS
+    - usb: gadget: rndis: prevent integer overflow in rndis_set_response()
+    - usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
+    - usb: usbtmc: Fix bug in pipe direction for control transfers
+    - Input: aiptek - properly check endpoint type
+    - perf symbols: Fix symbol size calculation condition
+    - Linux 5.4.187
+  * Focal update: v5.4.186 upstream stable release (LP: #1969678)
+    - Revert "xfrm: state and policy should fail if XFRMA_IF_ID 0"
+    - sctp: fix the processing for INIT chunk
+    - xfrm: Check if_id in xfrm_migrate
+    - xfrm: Fix xfrm migrate issues when address family changes
+    - arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity
+    - arm64: dts: rockchip: reorder rk3399 hdmi clocks
+    - arm64: dts: agilex: use the compatible "intel,socfpga-agilex-hsotg"
+    - ARM: dts: rockchip: reorder rk322x hmdi clocks
+    - ARM: dts: rockchip: fix a typo on rk3288 crypto-controller
+    - mac80211: refuse aggregations sessions before authorized
+    - MIPS: smp: fill in sibling and core maps earlier
+    - ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE
+    - can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when
+      fully ready
+    - atm: firestream: check the return value of ioremap() in fs_init()
+    - iwlwifi: don't advertise TWT support
+    - drm/vrr: Set VRR capable prop only if it is attached to connector
+    - nl80211: Update bss channel on channel switch for P2P_CLIENT
+    - tcp: make tcp_read_sock() more robust
+    - sfc: extend the locking on mcdi->seqno
+    - kselftest/vm: fix tests build with old libc
+    - fixup for "arm64 entry: Add macro for reading symbol address from the
+      trampoline"
+    - Linux 5.4.186
+  * Focal update: v5.4.185 upstream stable release (LP: #1969672)
+    - clk: qcom: gdsc: Add support to update GDSC transition delay
+    - arm64: dts: armada-3720-turris-mox: Add missing ethernet0 alias
+    - virtio-blk: Don't use MAX_DISCARD_SEGMENTS if max_discard_seg is zero
+    - net: qlogic: check the return value of dma_alloc_coherent() in
+      qed_vf_hw_prepare()
+    - qed: return status of qed_iov_get_link
+    - drm/sun4i: mixer: Fix P010 and P210 format numbers
+    - ARM: dts: aspeed: Fix AST2600 quad spi group
+    - ethernet: Fix error handling in xemaclite_of_probe
+    - net: ethernet: ti: cpts: Handle error for clk_enable
+    - net: ethernet: lpc_eth: Handle error for clk_enable
+    - ax25: Fix NULL pointer dereference in ax25_kill_by_device
+    - net/mlx5: Fix size field in bufferx_reg struct
+    - net/mlx5: Fix a race on command flush flow
+    - NFC: port100: fix use-after-free in port100_send_complete
+    - selftests: pmtu.sh: Kill tcpdump processes launched by subshell.
+    - gpio: ts4900: Do not set DAT and OE together
+    - gianfar: ethtool: Fix refcount leak in gfar_get_ts_info
+    - net: phy: DP83822: clear MISR2 register to disable interrupts
+    - sctp: fix kernel-infoleak for SCTP sockets
+    - net: bcmgenet: Don't claim WOL when its not available
+    - net-sysfs: add check for netdevice being present to speed_show
+    - Revert "xen-netback: remove 'hotplug-status' once it has served its purpose"
+    - Revert "xen-netback: Check for hotplug-status existence before watching"
+    - ipv6: prevent a possible race condition with lifetimes
+    - tracing: Ensure trace buffer is at least 4096 bytes large
+    - selftest/vm: fix map_fixed_noreplace test failure
+    - selftests/memfd: clean up mapping in mfd_fail_write
+    - ARM: Spectre-BHB: provide empty stub for non-config
+    - fuse: fix pipe buffer lifetime for direct_io
+    - staging: gdm724x: fix use after free in gdm_lte_rx()
+    - net: macb: Fix lost RX packet wakeup race in NAPI receive
+    - mmc: meson: Fix usage of meson_mmc_post_req()
+    - riscv: Fix auipc+jalr relocation range checks
+    - arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0
+    - virtio: unexport virtio_finalize_features
+    - virtio: acknowledge all features before access
+    - ARM: fix Thumb2 regression with Spectre BHB
+    - ext4: add check to prevent attempting to resize an fs with sparse_super2
+    - x86/cpufeatures: Mark two free bits in word 3
+    - x86/cpu: Add hardware-enforced cache coherency as a CPUID feature
+    - x86/mm/pat: Don't flush cache if hardware enforces cache coherency across
+      encryption domnains
+    - KVM: SVM: Don't flush cache if hardware enforces cache coherency across
+      encryption domains
+    - Linux 5.4.185
+  * Focal update: v5.4.184 upstream stable release (LP: #1969242)
+    - arm/arm64: Provide a wrapper for SMCCC 1.1 calls
+    - arm/arm64: smccc/psci: add arm_smccc_1_1_get_conduit()
+    - ARM: report Spectre v2 status through sysfs
+    - ARM: early traps initialisation
+    - ARM: use LOADADDR() to get load address of sections
+    - [Config] updateconfigs for HARDEN_BRANCH_HISTORY
+    - ARM: Spectre-BHB workaround
+    - ARM: include unprivileged BPF status in Spectre V2 reporting
+    - ARM: fix build error when BPF_SYSCALL is disabled
+    - ARM: fix co-processor register typo
+    - ARM: Do not use NOCROSSREFS directive with ld.lld
+    - ARM: fix build warning in proc-v7-bugs.c
+    - xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
+    - xen/grant-table: add gnttab_try_end_foreign_access()
+    - xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/netfront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/scsifront: don't use gnttab_query_foreign_access() for mapped status
+    - xen/gntalloc: don't use gnttab_query_foreign_access()
+    - xen: remove gnttab_query_foreign_access()
+    - xen/9p: use alloc/free_pages_exact()
+    - xen/pvcalls: use alloc/free_pages_exact()
+    - xen/gnttab: fix gnttab_end_foreign_access() without page specified
+    - xen/netfront: react properly to failing gnttab_end_foreign_access_ref()
+    - Linux 5.4.184
+  * Focal update: v5.4.183 upstream stable release (LP: #1969239)
+    - mac80211_hwsim: report NOACK frames in tx_status
+    - mac80211_hwsim: initialize ieee80211_tx_info at hw_scan_work
+    - i2c: bcm2835: Avoid clock stretching timeouts
+    - ASoC: rt5668: do not block workqueue if card is unbound
+    - ASoC: rt5682: do not block workqueue if card is unbound
+    - Input: clear BTN_RIGHT/MIDDLE on buttonpads
+    - cifs: fix double free race when mount fails in cifs_get_root()
+    - dmaengine: shdma: Fix runtime PM imbalance on error
+    - i2c: cadence: allow COMPILE_TEST
+    - i2c: qup: allow COMPILE_TEST
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit FN990
+    - usb: gadget: don't release an existing dev->buf
+    - usb: gadget: clear related members when goto fail
+    - ata: pata_hpt37x: fix PCI clock detection
+    - ALSA: intel_hdmi: Fix reference to PCM buffer address
+    - ASoC: ops: Shift tested values in snd_soc_put_volsw() by +min
+    - xfrm: fix MTU regression
+    - netfilter: fix use-after-free in __nf_register_net_hook()
+    - xfrm: enforce validity of offload input flags
+    - netfilter: nf_queue: don't assume sk is full socket
+    - netfilter: nf_queue: fix possible use-after-free
+    - batman-adv: Request iflink once in batadv-on-batadv check
+    - batman-adv: Request iflink once in batadv_get_real_netdevice
+    - batman-adv: Don't expect inter-netns unique iflink indices
+    - net: dcb: flush lingering app table entries for unregistered devices
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error generated by client
+    - net/smc: fix unexpected SMC_CLC_DECL_ERR_REGRMB error cause by server
+    - block: Fix fsync always failed if once failed
+    - xen/netfront: destroy queues before real_num_tx_queues is zeroed
+    - sched/topology: Make sched_init_numa() use a set for the deduplicating sort
+    - sched/topology: Fix sched_domain_topology_level alloc in sched_init_numa()
+    - ia64: ensure proper NUMA distance and possible map initialization
+    - mac80211: fix forwarded mesh frames AC & queue selection
+    - net: stmmac: fix return value of __setup handler
+    - iavf: Fix missing check for running netdev
+    - net: sxgbe: fix return value of __setup handler
+    - net: arcnet: com20020: Fix null-ptr-deref in com20020pci_probe()
+    - ixgbe: xsk: change !netif_carrier_ok() handling in ixgbe_xmit_zc()
+    - efivars: Respect "block" flag in efivar_entry_set_safe()
+    - firmware: arm_scmi: Remove space in MODULE_ALIAS name
+    - ASoC: cs4265: Fix the duplicated control name
+    - can: gs_usb: change active_channels's type from atomic_t to u8
+    - arm64: dts: rockchip: Switch RK3399-Gru DP to SPDIF output
+    - igc: igc_read_phy_reg_gpy: drop premature return
+    - ARM: Fix kgdb breakpoint for Thumb2
+    - ARM: 9182/1: mmu: fix returns from early_param() and __setup() functions
+    - igc: igc_write_phy_reg_gpy: drop premature return
+    - ibmvnic: free reset-work-item when flushing
+    - memfd: fix F_SEAL_WRITE after shmem huge page allocated
+    - soc: fsl: qe: Check of ioremap return value
+    - net: chelsio: cxgb3: check the return value of pci_find_capability()
+    - nl80211: Handle nla_memdup failures in handle_nan_filter
+    - Input: elan_i2c - move regulator_[en|dis]able() out of
+      elan_[en|dis]able_power()
+    - Input: elan_i2c - fix regulator enable count imbalance after suspend/resume
+    - HID: add mapping for KEY_DICTATE
+    - HID: add mapping for KEY_ALL_APPLICATIONS
+    - tracing/histogram: Fix sorting on old "cpu" value
+    - tracing: Fix return value of __setup handlers
+    - btrfs: fix lost prealloc extents beyond eof after full fsync
+    - btrfs: qgroup: fix deadlock between rescan worker and remove qgroup
+    - btrfs: add missing run of delayed items after unlink during log replay
+    - Revert "xfrm: xfrm_state_mtu should return at least 1280 for ipv6"
+    - net: dcb: disable softirqs in dcbnl_flush_dev()
+    - hamradio: fix macro redefine warning
+    - Linux 5.4.183
+  * Focal update: v5.4.182 upstream stable release (LP: #1969236)
+    - cgroup/cpuset: Fix a race between cpuset_attach() and cpu hotplug
+    - clk: jz4725b: fix mmc0 clock gating
+    - vhost/vsock: don't check owner in vhost_vsock_stop() while releasing
+    - parisc/unaligned: Fix fldd and fstd unaligned handlers on 32-bit kernel
+    - parisc/unaligned: Fix ldw() and stw() unalignment handlers
+    - drm/amdgpu: disable MMHUB PG for Picasso
+    - sr9700: sanity check for packet length
+    - USB: zaurus: support another broken Zaurus
+    - x86/fpu: Correct pkru/xstate inconsistency
+    - tee: export teedev_open() and teedev_close_context()
+    - optee: use driver internal tee_context for some rpc
+    - lan743x: fix deadlock in lan743x_phy_link_status_change()
+    - ping: remove pr_err from ping_lookup
+    - perf data: Fix double free in perf_session__delete()
+    - bpf: Do not try bpf_msg_push_data with len 0
+    - net: __pskb_pull_tail() & pskb_carve_frag_list() drop_monitor friends
+    - tipc: Fix end of loop tests for list_for_each_entry()
+    - gso: do not skip outer ip header in case of ipip and net_failover
+    - openvswitch: Fix setting ipv6 fields causing hw csum failure
+    - drm/edid: Always set RGB444
+    - net/mlx5e: Fix wrong return value on ioctl EEPROM query failure
+    - net: ll_temac: check the return value of devm_kmalloc()
+    - net: Force inlining of checksum functions in net/checksum.h
+    - nfp: flower: Fix a potential leak in nfp_tunnel_add_shared_mac()
+    - netfilter: nf_tables: fix memory leak during stateful obj update
+    - net/mlx5: Fix possible deadlock on rule deletion
+    - net/mlx5: Fix wrong limitation of metadata match on ecpf
+    - spi: spi-zynq-qspi: Fix a NULL pointer dereference in
+      zynq_qspi_exec_mem_op()
+    - configfs: fix a race in configfs_{,un}register_subsystem()
+    - RDMA/ib_srp: Fix a deadlock
+    - tracing: Have traceon and traceoff trigger honor the instance
+    - iio: adc: men_z188_adc: Fix a resource leak in an error handling path
+    - iio: adc: ad7124: fix mask used for setting AIN_BUFP & AIN_BUFM bits
+    - iio: Fix error handling for PM
+    - ata: pata_hpt37x: disable primary channel on HPT371
+    - Revert "USB: serial: ch341: add new Product ID for CH341A"
+    - usb: gadget: rndis: add spinlock for rndis response list
+    - tracefs: Set the group ownership in apply_options() not parse_options()
+    - USB: serial: option: add support for DW5829e
+    - USB: serial: option: add Telit LE910R1 compositions
+    - usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
+    - usb: dwc3: gadget: Let the interrupt handler disable bottom halves.
+    - xhci: re-initialize the HC during resume if HCE was set
+    - xhci: Prevent futile URB re-submissions due to incorrect return value.
+    - tty: n_gsm: fix encoding of control signal octet bit DV
+    - tty: n_gsm: fix proper link termination after failed open
+    - tty: n_gsm: fix NULL pointer access due to DLCI release
+    - gpio: tegra186: Fix chip_data type confusion
+    - Revert "drm/nouveau/pmu/gm200-: avoid touching PMU outside of
+      DEVINIT/PREOS/ACR"
+    - memblock: use kfree() to release kmalloced memblock regions
+    - fget: clarify and improve __fget_files() implementation
+    - Linux 5.4.182
+  * CVE-2022-28390
+    - can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
+
+  [ Ubuntu: 5.4.0-113.127 ]
+
+  * focal/linux: 5.4.0-113.127 -proposed tracker (LP: #1973980)
+  * CVE-2022-29581
+    - net/sched: cls_u32: fix netns refcount changes in u32_change()
+  * CVE-2022-1116
+    - io_uring: fix fs->users overflow
+  * ext4: limit length to bitmap_maxbytes (LP: #1972281)
+    - ext4: limit length to bitmap_maxbytes - blocksize in punch_hole
+  * 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
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Thu, 16 Jun 2022 14:40:57 +0800
+
+linux-imx (5.4.0-1020.21) focal; urgency=medium
+
+  * CVE-2022-23960
+    - [Config] set CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+
+  * Disable unprivileged BPF by default (LP: #1961338)
+    - [Config] set CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
+
+  * Re-enable DEBUG_INFO_BTF where it was disabled (LP: #1945632)
+    - [Config] Enable CONFIG_DEBUG_INFO_BTF on all arches
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys
+
+  * Focal update: v5.4.129 upstream stable release (LP: #1936242)
+    - [Config] enable CONFIG_SYSTEM_REVOCATION_LIST
+
+  * Kernel worker blocked for long time on system boot (LP: #1973786)
+    - lan743x: fix deadlock in lan743x_phy_link_status_change()
+
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+
+  [ Ubuntu: 5.4.0-110.124 ]
+
+  * focal/linux: 5.4.0-110.124 -proposed tracker (LP: #1969053)
+  * net/mlx5e: Fix page DMA map/unmap attributes (LP: #1967292)
+    - net/mlx5e: Fix page DMA map/unmap attributes
+  * xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+    (LP: #1966803)
+    - xfs: Fix deadlock between AGI and AGF when target_ip exists in xfs_rename()
+  * LRMv6: add multi-architecture support (LP: #1968774)
+    - [Packaging] resync dkms-build{,--nvidia-N}
+  * xfrm interface cannot be changed anymore (LP: #1968591)
+    - xfrm: fix the if_id check in changelink
+  * Use kernel-testing repo from launchpad for ADT tests (LP: #1968016)
+    - [Debian] Use kernel-testing repo from launchpad
+  * vmx_ldtr_test in ubuntu_kvm_unit_tests failed (FAIL: Expected 0 for L1 LDTR
+    selector (got 50)) (LP: #1956315)
+    - KVM: nVMX: Set LDTR to its architecturally defined value on nested VM-Exit
+  * [SRU][Regression] Revert "PM: ACPI: reboot: Use S5 for reboot" which causes
+    Bus Fatal Error when rebooting system with BCM5720 NIC (LP: #1917471)
+    - Revert "PM: ACPI: reboot: Use S5 for reboot"
+  * Focal update: v5.4.181 upstream stable release (LP: #1967582)
+    - Makefile.extrawarn: Move -Wunaligned-access to W=1
+    - HID:Add support for UGTABLET WP5540
+    - Revert "svm: Add warning message for AVIC IPI invalid target"
+    - serial: parisc: GSC: fix build when IOSAPIC is not set
+    - parisc: Drop __init from map_pages declaration
+    - parisc: Fix data TLB miss in sba_unmap_sg
+    - parisc: Fix sglist access in ccio-dma.c
+    - btrfs: send: in case of IO error log it
+    - platform/x86: ISST: Fix possible circular locking dependency detected
+    - selftests: rtc: Increase test timeout so that all tests run
+    - net: ieee802154: at86rf230: Stop leaking skb's
+    - selftests/zram: Skip max_comp_streams interface on newer kernel
+    - selftests/zram01.sh: Fix compression ratio calculation
+    - selftests/zram: Adapt the situation that /dev/zram0 is being used
+    - ax25: improve the incomplete fix to avoid UAF and NPD bugs
+    - vfs: make freeze_super abort when sync_filesystem returns error
+    - quota: make dquot_quota_sync return errors from ->sync_fs
+    - nvme: fix a possible use-after-free in controller reset during load
+    - nvme-tcp: fix possible use-after-free in transport error_recovery work
+    - nvme-rdma: fix possible use-after-free in transport error_recovery work
+    - drm/amdgpu: fix logic inversion in check
+    - Revert "module, async: async_synchronize_full() on module init iff async is
+      used"
+    - ftrace: add ftrace_init_nop()
+    - module/ftrace: handle patchable-function-entry
+    - arm64: module: rework special section handling
+    - arm64: module/ftrace: intialize PLT at load time
+    - iwlwifi: fix use-after-free
+    - drm/radeon: Fix backlight control on iMac 12,1
+    - ext4: check for out-of-order index extents in ext4_valid_extent_entries()
+    - ext4: check for inconsistent extents between index and leaf block
+    - ext4: prevent partial update of the extent blocks
+    - taskstats: Cleanup the use of task->exit_code
+    - dmaengine: at_xdmac: Start transfer for cyclic channels in issue_pending
+    - vsock: remove vsock from connected table when connect is interrupted by a
+      signal
+    - mmc: block: fix read single on recovery logic
+    - iwlwifi: pcie: fix locking when "HW not ready"
+    - iwlwifi: pcie: gen2: fix locking when "HW not ready"
+    - netfilter: nft_synproxy: unregister hooks on init error path
+    - net: dsa: lan9303: fix reset on probe
+    - net: ieee802154: ca8210: Fix lifs/sifs periods
+    - ping: fix the dif and sdif check in ping_lookup
+    - bonding: force carrier update when releasing slave
+    - drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit
+    - bonding: fix data-races around agg_select_timer
+    - libsubcmd: Fix use-after-free for realloc(..., 0)
+    - ALSA: hda: Fix regression on forced probe mask option
+    - ALSA: hda: Fix missing codec probe on Shenker Dock 15
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw()
+    - ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw_range()
+    - powerpc/lib/sstep: fix 'ptesync' build error
+    - mtd: rawnand: gpmi: don't leak PM reference in error path
+    - block/wbt: fix negative inflight counter when remove scsi device
+    - NFS: LOOKUP_DIRECTORY is also ok with symlinks
+    - NFS: Do not report writeback errors in nfs_getattr()
+    - mtd: rawnand: qcom: Fix clock sequencing in qcom_nandc_probe()
+    - mtd: rawnand: brcmnand: Fixed incorrect sub-page ECC status
+    - scsi: lpfc: Fix pt2pt NVMe PRLI reject LOGO loop
+    - EDAC: Fix calculation of returned address and next offset in
+      edac_align_ptr()
+    - net: sched: limit TC_ACT_REPEAT loops
+    - dmaengine: sh: rcar-dmac: Check for error num after setting mask
+    - copy_process(): Move fd_install() out of sighand->siglock critical section
+    - i2c: brcmstb: fix support for DSL and CM variants
+    - Drivers: hv: vmbus: Fix memory leak in vmbus_add_channel_kobj
+    - KVM: x86/pmu: Use AMD64_RAW_EVENT_MASK for PERF_TYPE_RAW
+    - ARM: OMAP2+: hwmod: Add of_node_put() before break
+    - ARM: OMAP2+: adjust the location of put_device() call in omapdss_init_of
+    - irqchip/sifive-plic: Add missing thead,c900-plic match string
+    - netfilter: conntrack: don't refresh sctp entries in closed state
+    - arm64: dts: meson-gx: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: add ATF BL32 reserved-memory region
+    - arm64: dts: meson-g12: drop BL32 region from SEI510/SEI610
+    - kconfig: let 'shell' return enough output for deep path names
+    - ata: libata-core: Disable TRIM on M88V29
+    - drm/rockchip: dw_hdmi: Do not leave clock enabled in error case
+    - tracing: Fix tp_printk option related with tp_printk_stop_on_boot
+    - net: usb: qmi_wwan: Add support for Dell DW5829e
+    - net: macb: Align the dma and coherent dma masks
+    - kconfig: fix failing to generate auto.conf
+    - Linux 5.4.181
+  * Focal update: v5.4.180 upstream stable release (LP: #1966118)
+    - integrity: check the return value of audit_log_start()
+    - ima: Remove ima_policy file before directory
+    - ima: Allow template selection with ima_template[_fmt]= after ima_hash=
+    - ima: Do not print policy rule with inactive LSM labels
+    - mmc: sdhci-of-esdhc: Check for error num after setting mask
+    - net: phy: marvell: Fix RGMII Tx/Rx delays setting in 88e1121-compatible PHYs
+    - net: phy: marvell: Fix MDI-x polarity setting in 88e1118-compatible PHYs
+    - NFS: Fix initialisation of nfs_client cl_flags field
+    - NFSD: Clamp WRITE offsets
+    - NFSD: Fix offset type in I/O trace points
+    - NFSv4 only print the label when its queried
+    - nfs: nfs4clinet: check the return value of kstrdup()
+    - NFSv4.1: Fix uninitialised variable in devicenotify
+    - NFSv4 remove zero number of fs_locations entries error check
+    - NFSv4 expose nfs_parse_server_name function
+    - drm: panel-orientation-quirks: Add quirk for the 1Netbook OneXPlayer
+    - net: sched: Clarify error message when qdisc kind is unknown
+    - scsi: target: iscsi: Make sure the np under each tpg is unique
+    - scsi: qedf: Fix refcount issue when LOGO is received during TMF
+    - scsi: myrs: Fix crash in error case
+    - PM: hibernate: Remove register_nosave_region_late()
+    - usb: dwc2: gadget: don't try to disable ep0 in dwc2_hsotg_suspend
+    - net: stmmac: dwmac-sun8i: use return val of readl_poll_timeout()
+    - KVM: nVMX: eVMCS: Filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER
+    - riscv: fix build with binutils 2.38
+    - ARM: dts: imx23-evk: Remove MX23_PAD_SSP1_DETECT from hog group
+    - ARM: socfpga: fix missing RESET_CONTROLLER
+    - nvme-tcp: fix bogus request completion when failing to send AER
+    - ACPI/IORT: Check node revision for PMCG resources
+    - PM: s2idle: ACPI: Fix wakeup interrupts handling
+    - net: bridge: fix stale eth hdr pointer in br_dev_xmit
+    - perf probe: Fix ppc64 'perf probe add events failed' case
+    - ARM: dts: meson: Fix the UART compatible strings
+    - staging: fbtft: Fix error path in fbtft_driver_module_init()
+    - ARM: dts: imx6qdl-udoo: Properly describe the SD card detect
+    - usb: f_fs: Fix use-after-free for epfile
+    - misc: fastrpc: avoid double fput() on failed usercopy
+    - ixgbevf: Require large buffers for build_skb on 82599VF
+    - bonding: pair enable_port with slave_arr_updates
+    - ipmr,ip6mr: acquire RTNL before calling ip[6]mr_free_table() on failure path
+    - nfp: flower: fix ida_idx not being released
+    - net: do not keep the dst cache when uncloning an skb dst and its metadata
+    - net: fix a memleak when uncloning an skb dst and its metadata
+    - veth: fix races around rq->rx_notify_masked
+    - net: mdio: aspeed: Add missing MODULE_DEVICE_TABLE
+    - tipc: rate limit warning for received illegal binding update
+    - net: amd-xgbe: disable interrupts during pci removal
+    - vt_ioctl: fix array_index_nospec in vt_setactivate
+    - vt_ioctl: add array_index_nospec to VT_ACTIVATE
+    - n_tty: wake up poll(POLLRDNORM) on receiving data
+    - eeprom: ee1004: limit i2c reads to I2C_SMBUS_BLOCK_MAX
+    - net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
+    - usb: ulpi: Move of_node_put to ulpi_dev_release
+    - usb: ulpi: Call of_node_put correctly
+    - usb: dwc3: gadget: Prevent core from processing stale TRBs
+    - usb: gadget: udc: renesas_usb3: Fix host to USB_ROLE_NONE transition
+    - USB: gadget: validate interface OS descriptor requests
+    - usb: gadget: rndis: check size of RNDIS_MSG_SET command
+    - usb: gadget: f_uac2: Define specific wTerminalType
+    - USB: serial: ftdi_sio: add support for Brainboxes US-159/235/320
+    - USB: serial: option: add ZTE MF286D modem
+    - USB: serial: ch341: add support for GW Instek USB2.0-Serial devices
+    - USB: serial: cp210x: add NCR Retail IO box id
+    - USB: serial: cp210x: add CPI Bulk Coin Recycler id
+    - seccomp: Invalidate seccomp mode to catch death failures
+    - hwmon: (dell-smm) Speed up setting of fan speed
+    - scsi: lpfc: Remove NVMe support if kernel has NVME_FC disabled
+    - perf: Fix list corruption in perf_cgroup_switch()
+    - Linux 5.4.180
+  * Focal update: v5.4.179 upstream stable release (LP: #1965591)
+    - moxart: fix potential use-after-free on remove path
+    - Linux 5.4.179
+  * CVE-2020-27820
+    - drm/nouveau: Add a dedicated mutex for the clients list
+    - drm/nouveau: clean up all clients on device removal
+  * CVE-2022-1016
+    - netfilter: nf_tables: initialize registers in nft_do_chain()
+  * CVE-2022-27223
+    - USB: gadget: validate endpoint index for xilinx udc
+  * CVE-2022-26490
+    - nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
+  * CVE-2021-26401
+    - x86/speculation: Use generic retpoline by default on AMD
+    - x86/speculation: Update link to AMD speculation whitepaper
+    - x86/speculation: Warn about Spectre v2 LFENCE mitigation
+    - x86/speculation: Warn about eIBRS + LFENCE + Unprivileged eBPF + SMT
+  * CVE-2022-0001
+    - x86/speculation: Include unprivileged eBPF status in Spectre v2 mitigation
+      reporting
+
+  [ Ubuntu: 5.4.0-109.123 ]
+
+  * focal/linux: 5.4.0-109.123 -proposed tracker (LP: #1968290)
+  * USB devices not detected during boot on USB 3.0 hubs (LP: #1968210)
+    - SAUCE: Revert "Revert "xhci: Set HCD flag to defer primary roothub
+      registration""
+    - SAUCE: Revert "Revert "usb: core: hcd: Add support for deferring roothub
+      registration""
+
+  [ Ubuntu: 5.4.0-108.122 ]
+
+  * focal/linux: 5.4.0-108.122 -proposed tracker (LP: #1966740)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync dkms-build{,--nvidia-N} from LRMv5
+    - debian/dkms-versions -- update from kernel-versions (main/2022.03.21)
+  * Low RX performance for 40G Solarflare NICs (LP: #1964512)
+    - SAUCE: sfc: The size of the RX recycle ring should be more flexible
+  * [UBUNTU 20.04] KVM: Enable storage key checking for intercepted instruction
+    (LP: #1962831)
+    - selftests: kvm: add _vm_ioctl
+    - selftests: kvm: Introduce the TEST_FAIL macro
+    - KVM: selftests: Add GUEST_ASSERT variants to pass values to host
+    - KVM: s390: gaccess: Refactor gpa and length calculation
+    - KVM: s390: gaccess: Refactor access address range check
+    - KVM: s390: gaccess: Cleanup access to guest pages
+    - s390/uaccess: introduce bit field for OAC specifier
+    - s390/uaccess: fix compile error
+    - s390/uaccess: Add copy_from/to_user_key functions
+    - KVM: s390: Honor storage keys when accessing guest memory
+    - KVM: s390: handle_tprot: Honor storage keys
+    - KVM: s390: selftests: Test TEST PROTECTION emulation
+    - KVM: s390: Add optional storage key checking to MEMOP IOCTL
+    - KVM: s390: Add vm IOCTL for key checked guest absolute memory access
+    - KVM: s390: Rename existing vcpu memop functions
+    - KVM: s390: Add capability for storage key extension of MEM_OP IOCTL
+    - KVM: s390: Update api documentation for memop ioctl
+    - KVM: s390: Clarify key argument for MEM_OP in api docs
+    - KVM: s390: Add missing vm MEM_OP size check
+  * 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon/sec2 - Add workqueue for SEC driver.
+    - crypto: hisilicon/sec2 - update SEC initialization and reset
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117)
+    - crypto: hisilicon - Use one workqueue per qm instead of per qp
+  * Lots of hisi_qm zombie task slow down system after stress test
+    (LP: #1932117) // 【sec-0911】 fail to reset sec module (LP: #1943301)
+    - crypto: hisilicon - Unify hardware error init/uninit into QM
+  * [UBUNTU 20.04] Fix SIGP processing on KVM/s390 (LP: #1962578)
+    - KVM: s390: Simplify SIGP Set Arch handling
+    - KVM: s390: Add a routine for setting userspace CPU state
+  * Move virtual graphics drivers from linux-modules-extra to linux-modules
+    (LP: #1960633)
+    - [Packaging] Move VM DRM drivers into modules
+  * Focal update: v5.4.178 upstream stable release (LP: #1964634)
+    - audit: improve audit queue handling when "audit=1" on cmdline
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_volsw_sx()
+    - ASoC: ops: Reject out of bounds values in snd_soc_put_xr_sx()
+    - ALSA: usb-audio: Simplify quirk entries with a macro
+    - ALSA: hda/realtek: Add quirk for ASUS GU603
+    - ALSA: hda/realtek: Add missing fixup-model entry for Gigabyte X570 ALC1220
+      quirks
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570S Aorus Master (newer
+      chipset)
+    - ALSA: hda/realtek: Fix silent output on Gigabyte X570 Aorus Xtreme after
+      reboot from Windows
+    - btrfs: fix deadlock between quota disable and qgroup rescan worker
+    - drm/nouveau: fix off by one in BIOS boundary checking
+    - mm/kmemleak: avoid scanning potential huge holes
+    - block: bio-integrity: Advance seed correctly for larger interval sizes
+    - memcg: charge fs_context and legacy_fs_context
+    - IB/rdmavt: Validate remote_addr during loopback atomic tests
+    - RDMA/siw: Fix broken RDMA Read Fence/Resume logic.
+    - RDMA/mlx4: Don't continue event handler after memory allocation failure
+    - iommu/vt-d: Fix potential memory leak in intel_setup_irq_remapping()
+    - iommu/amd: Fix loop timeout issue in iommu_ga_log_enable()
+    - spi: bcm-qspi: check for valid cs before applying chip select
+    - spi: mediatek: Avoid NULL pointer crash in interrupt
+    - spi: meson-spicc: add IRQ check in meson_spicc_probe
+    - net: ieee802154: hwsim: Ensure proper channel selection at probe time
+    - net: ieee802154: mcr20a: Fix lifs/sifs periods
+    - net: ieee802154: ca8210: Stop leaking skb's
+    - net: ieee802154: Return meaningful error codes from the netlink helpers
+    - net: macsec: Verify that send_sci is on when setting Tx sci explicitly
+    - net: stmmac: dump gmac4 DMA registers correctly
+    - net: stmmac: ensure PTP time register reads are consistent
+    - drm/i915/overlay: Prevent divide by zero bugs in scaling
+    - ASoC: fsl: Add missing error handling in pcm030_fabric_probe
+    - ASoC: xilinx: xlnx_formatter_pcm: Make buffer bytes multiple of period bytes
+    - ASoC: cpcap: Check for NULL pointer after calling of_get_child_by_name
+    - ASoC: max9759: fix underflow in speaker_gain_control_put()
+    - pinctrl: bcm2835: Fix a few error paths
+    - scsi: bnx2fc: Make bnx2fc_recv_frame() mp safe
+    - nfsd: nfsd4_setclientid_confirm mistakenly expires confirmed client.
+    - selftests: futex: Use variable MAKE instead of make
+    - rtc: cmos: Evaluate century appropriate
+    - EDAC/altera: Fix deferred probing
+    - EDAC/xgene: Fix deferred probing
+    - ext4: fix error handling in ext4_restore_inline_data()
+    - cgroup/cpuset: Fix "suspicious RCU usage" lockdep warning
+    - Linux 5.4.178
+  * Focal update: v5.4.177 upstream stable release (LP: #1964628)
+    - PCI: pciehp: Fix infinite loop in IRQ handler upon power fault
+    - psi: Fix uaf issue when psi trigger is destroyed while being polled
+    - ipheth: fix EOVERFLOW in ipheth_rcvbulk_callback
+    - net: amd-xgbe: ensure to reset the tx_timer_active flag
+    - net: amd-xgbe: Fix skb data length underflow
+    - rtnetlink: make sure to refresh master_dev/m_ops in __rtnl_newlink()
+    - cpuset: Fix the bug that subpart_cpus updated wrongly in update_cpumask()
+    - af_packet: fix data-race in packet_setsockopt / packet_setsockopt
+    - Linux 5.4.177
+  * Focal update: v5.4.176 upstream stable release (LP: #1962345)
+    - s390/hypfs: include z/VM guests with access control group set
+    - scsi: zfcp: Fix failed recovery on gone remote port with non-NPIV FCP
+      devices
+    - udf: Restore i_lenAlloc when inode expansion fails
+    - udf: Fix NULL ptr deref when converting from inline format
+    - PM: wakeup: simplify the output logic of pm_show_wakelocks()
+    - tracing/histogram: Fix a potential memory leak for kstrdup()
+    - tracing: Don't inc err_log entry count if entry allocation fails
+    - fsnotify: fix fsnotify hooks in pseudo filesystems
+    - drm/etnaviv: relax submit size limits
+    - arm64: errata: Fix exec handling in erratum 1418040 workaround
+    - netfilter: nft_payload: do not update layer 4 checksum when mangling
+      fragments
+    - serial: 8250: of: Fix mapped region size when using reg-offset property
+    - serial: stm32: fix software flow control transfer
+    - tty: n_gsm: fix SW flow control encoding/handling
+    - tty: Add support for Brainboxes UC cards.
+    - usb-storage: Add unusual-devs entry for VL817 USB-SATA bridge
+    - usb: common: ulpi: Fix crash in ulpi_match()
+    - usb: gadget: f_sourcesink: Fix isoc transfer for USB_SPEED_SUPER_PLUS
+    - USB: core: Fix hang in usb_kill_urb by adding memory barriers
+    - usb: typec: tcpm: Do not disconnect while receiving VBUS off
+    - ucsi_ccg: Check DEV_INT bit only when starting CCG4
+    - net: sfp: ignore disabled SFP node
+    - powerpc/32: Fix boot failure with GCC latent entropy plugin
+    - i40e: Increase delay to 1 s after global EMP reset
+    - i40e: Fix issue when maximum queues is exceeded
+    - i40e: Fix queues reservation for XDP
+    - i40e: fix unsigned stat widths
+    - rpmsg: char: Fix race between the release of rpmsg_ctrldev and cdev
+    - rpmsg: char: Fix race between the release of rpmsg_eptdev and cdev
+    - scsi: bnx2fc: Flush destroy_work queue before calling bnx2fc_interface_put()
+    - ipv6_tunnel: Rate limit warning messages
+    - net: fix information leakage in /proc/net/ptype
+    - hwmon: (lm90) Mark alert as broken for MAX6646/6647/6649
+    - hwmon: (lm90) Mark alert as broken for MAX6680
+    - ping: fix the sk_bound_dev_if match in ping_lookup
+    - ipv4: avoid using shared IP generator for connected sockets
+    - hwmon: (lm90) Reduce maximum conversion rate for G781
+    - NFSv4: Handle case where the lookup of a directory fails
+    - NFSv4: nfs_atomic_open() can race when looking up a non-regular file
+    - net-procfs: show net devices bound packet types
+    - drm/msm: Fix wrong size calculation
+    - drm/msm/dsi: Fix missing put_device() call in dsi_get_phy
+    - drm/msm/dsi: invalid parameter check in msm_dsi_phy_enable
+    - ipv6: annotate accesses to fn->fn_sernum
+    - NFS: Ensure the server has an up to date ctime before hardlinking
+    - NFS: Ensure the server has an up to date ctime before renaming
+    - netfilter: conntrack: don't increment invalid counter on NF_REPEAT
+    - net: phy: broadcom: hook up soft_reset for BCM54616S
+    - phylib: fix potential use-after-free
+    - rxrpc: Adjust retransmission backoff
+    - hwmon: (lm90) Mark alert as broken for MAX6654
+    - ibmvnic: init ->running_cap_crqs early
+    - ibmvnic: don't spin in tasklet
+    - drm/msm/hdmi: Fix missing put_device() call in msm_hdmi_get_phy
+    - yam: fix a memory leak in yam_siocdevprivate()
+    - net: hns3: handle empty unknown interrupt for VF
+    - ipv4: raw: lock the socket in raw_bind()
+    - ipv4: tcp: send zero IPID in SYNACK messages
+    - ipv4: remove sparse error in ip_neigh_gw4()
+    - dt-bindings: can: tcan4x5x: fix mram-cfg RX FIFO config
+    - fsnotify: invalidate dcache before IN_DELETE event
+    - block: Fix wrong offset in bio_truncate()
+    - mtd: rawnand: mpc5121: Remove unused variable in ads5121_select_chip()
+    - Linux 5.4.176
+  * Focal update: v5.4.175 upstream stable release (LP: #1962330)
+    - rcu: Tighten rcu_advance_cbs_nowake() checks
+    - pinctrl: bcm2835: Drop unused define
+    - pinctrl: bcm2835: Refactor platform data
+    - pinctrl: bcm2835: Add support for all GPIOs on BCM2711
+    - pinctrl: bcm2835: Match BCM7211 compatible string
+    - pinctrl: bcm2835: Add support for wake-up interrupts
+    - pinctrl: bcm2835: Change init order for gpio hogs
+    - ARM: dts: gpio-ranges property is now required
+    - mmc: sdhci-esdhc-imx: disable CMDQ support
+    - select: Fix indefinitely sleeping task in poll_schedule_timeout()
+    - Linux 5.4.175
+
+  [ Ubuntu: 5.4.0-107.121 ]
+
+  * focal/linux: 5.4.0-107.121 -proposed tracker (LP: #1966275)
+  * CVE-2022-27666
+    - esp: Fix possible buffer overflow in ESP transformation
+  * CVE-2022-1055
+    - net: sched: fix use-after-free in tc_new_tfilter()
+  * Pick fixup from v5.4.176 upstream stable release to address cert
+    failure with clock jitter test in NUC7i3DNHE (LP: #1964204)
+    - Bluetooth: refactor malicious adv data check
+
+  [ Ubuntu: 5.4.0-105.119 ]
+
+  * CVE-2022-0847
+    - lib/iov_iter: initialize "flags" in new pipe_buffer
+  * Broken network on some AWS instances with focal/impish kernels
+    (LP: #1961968)
+    - SAUCE: Revert "PCI/MSI: Mask MSI-X vectors only on success"
+  * [UBUNTU 20.04] kernel: Add support for CPU-MF counter second version 7
+    (LP: #1960182)
+    - s390/cpumf: Support for CPU Measurement Facility CSVN 7
+    - s390/cpumf: Support for CPU Measurement Sampling Facility LS bit
+  * Hipersocket page allocation failure on Ubuntu 20.04 based SSC environments
+    (LP: #1959529)
+    - s390/qeth: use memory reserves to back RX buffers
+  * CVE-2022-0516
+    - KVM: s390: Return error on SIDA memop on normal guest
+  * CVE-2022-0435
+    - tipc: improve size validations for received domain records
+  * CVE-2022-0492
+    - cgroup-v1: Require capabilities to set release_agent
+  * Recalled NFSv4 files delegations overwhelm server (LP: #1957986)
+    - NFSv4: Fix delegation handling in update_open_stateid()
+    - NFSv4: nfs4_callback_getattr() should ignore revoked delegations
+    - NFSv4: Delegation recalls should not find revoked delegations
+    - NFSv4: fail nfs4_refresh_delegation_stateid() when the delegation was
+      revoked
+    - NFS: Rename nfs_inode_return_delegation_noreclaim()
+    - NFSv4: Don't remove the delegation from the super_list more than once
+    - NFSv4: Hold the delegation spinlock when updating the seqid
+    - NFSv4: Clear the NFS_DELEGATION_REVOKED flag in
+      nfs_update_inplace_delegation()
+    - NFSv4: Update the stateid seqid in nfs_revoke_delegation()
+    - NFSv4: Revoke the delegation on success in nfs4_delegreturn_done()
+    - NFSv4: Ignore requests to return the delegation if it was revoked
+    - NFSv4: Don't reclaim delegations that have been returned or revoked
+    - NFSv4: nfs4_return_incompatible_delegation() should check delegation
+      validity
+    - NFSv4: Fix nfs4_inode_make_writeable()
+    - NFS: nfs_inode_find_state_and_recover() fix stateid matching
+    - NFSv4: Fix races between open and delegreturn
+    - NFSv4: Handle NFS4ERR_OLD_STATEID in delegreturn
+    - NFSv4: Don't retry the GETATTR on old stateid in nfs4_delegreturn_done()
+    - NFSv4: nfs_inode_evict_delegation() should set NFS_DELEGATION_RETURNING
+    - NFS: Clear NFS_DELEGATION_RETURN_IF_CLOSED when the delegation is returned
+    - NFSv4: Try to return the delegation immediately when marked for return on
+      close
+    - NFSv4: Add accounting for the number of active delegations held
+    - NFSv4: Limit the total number of cached delegations
+    - NFSv4: Ensure the delegation is pinned in nfs_do_return_delegation()
+    - NFSv4: Ensure the delegation cred is pinned when we call delegreturn
+  * Focal update: v5.4.174 upstream stable release (LP: #1960566)
+    - HID: uhid: Fix worker destroying device without any protection
+    - HID: wacom: Reset expected and received contact counts at the same time
+    - HID: wacom: Ignore the confidence flag when a touch is removed
+    - HID: wacom: Avoid using stale array indicies to read contact count
+    - f2fs: fix to do sanity check in is_alive()
+    - nfc: llcp: fix NULL error pointer dereference on sendmsg() after failed
+      bind()
+    - mtd: rawnand: gpmi: Add ERR007117 protection for nfc_apply_timings
+    - mtd: rawnand: gpmi: Remove explicit default gpmi clock setting for i.MX6
+    - x86/gpu: Reserve stolen memory for first integrated Intel GPU
+    - tools/nolibc: x86-64: Fix startup code bug
+    - tools/nolibc: i386: fix initial stack alignment
+    - tools/nolibc: fix incorrect truncation of exit code
+    - rtc: cmos: take rtc_lock while reading from CMOS
+    - media: v4l2-ioctl.c: readbuffers depends on V4L2_CAP_READWRITE
+    - media: flexcop-usb: fix control-message timeouts
+    - media: mceusb: fix control-message timeouts
+    - media: em28xx: fix control-message timeouts
+    - media: cpia2: fix control-message timeouts
+    - media: s2255: fix control-message timeouts
+    - media: dib0700: fix undefined behavior in tuner shutdown
+    - media: redrat3: fix control-message timeouts
+    - media: pvrusb2: fix control-message timeouts
+    - media: stk1160: fix control-message timeouts
+    - can: softing_cs: softingcs_probe(): fix memleak on registration failure
+    - lkdtm: Fix content of section containing lkdtm_rodata_do_nothing()
+    - iommu/io-pgtable-arm-v7s: Add error handle for page table allocation failure
+    - dma_fence_array: Fix PENDING_ERROR leak in dma_fence_array_signaled()
+    - PCI: Add function 1 DMA alias quirk for Marvell 88SE9125 SATA controller
+    - mm_zone: add function to check if managed dma zone exists
+    - mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed
+      pages
+    - shmem: fix a race between shmem_unused_huge_shrink and shmem_evict_inode
+    - drm/rockchip: dsi: Hold pm-runtime across bind/unbind
+    - drm/rockchip: dsi: Reconfigure hardware on resume()
+    - drm/panel: kingdisplay-kd097d04: Delete panel on attach() failure
+    - drm/panel: innolux-p079zca: Delete panel on attach() failure
+    - drm/rockchip: dsi: Fix unbalanced clock on probe error
+    - Bluetooth: cmtp: fix possible panic when cmtp_init_sockets() fails
+    - clk: bcm-2835: Pick the closest clock rate
+    - clk: bcm-2835: Remove rounding up the dividers
+    - wcn36xx: Indicate beacon not connection loss on MISSED_BEACON_IND
+    - wcn36xx: Release DMA channel descriptor allocations
+    - media: videobuf2: Fix the size printk format
+    - media: aspeed: fix mode-detect always time out at 2nd run
+    - media: em28xx: fix memory leak in em28xx_init_dev
+    - media: aspeed: Update signal status immediately to ensure sane hw state
+    - arm64: dts: meson-gxbb-wetek: fix HDMI in early boot
+    - arm64: dts: meson-gxbb-wetek: fix missing GPIO binding
+    - Bluetooth: stop proccessing malicious adv data
+    - tee: fix put order in teedev_close_context()
+    - media: dmxdev: fix UAF when dvb_register_device() fails
+    - crypto: qce - fix uaf on qce_ahash_register_one
+    - arm64: dts: ti: k3-j721e: correct cache-sets info
+    - tty: serial: atmel: Check return code of dmaengine_submit()
+    - tty: serial: atmel: Call dma_async_issue_pending()
+    - media: rcar-csi2: Correct the selection of hsfreqrange
+    - media: imx-pxp: Initialize the spinlock prior to using it
+    - media: si470x-i2c: fix possible memory leak in si470x_i2c_probe()
+    - media: mtk-vcodec: call v4l2_m2m_ctx_release first when file is released
+    - media: venus: core: Fix a resource leak in the error handling path of
+      'venus_probe()'
+    - netfilter: bridge: add support for pppoe filtering
+    - arm64: dts: qcom: msm8916: fix MMC controller aliases
+    - ACPI: EC: Rework flushing of EC work while suspended to idle
+    - drm/amdgpu: Fix a NULL pointer dereference in
+      amdgpu_connector_lcd_native_mode()
+    - drm/radeon/radeon_kms: Fix a NULL pointer dereference in
+      radeon_driver_open_kms()
+    - arm64: dts: ti: k3-j721e: Fix the L2 cache sets
+    - tty: serial: uartlite: allow 64 bit address
+    - serial: amba-pl011: do not request memory region twice
+    - floppy: Fix hang in watchdog when disk is ejected
+    - staging: rtl8192e: return error code from rtllib_softmac_init()
+    - staging: rtl8192e: rtllib_module: fix error handle case in alloc_rtllib()
+    - Bluetooth: btmtksdio: fix resume failure
+    - media: dib8000: Fix a memleak in dib8000_init()
+    - media: saa7146: mxb: Fix a NULL pointer dereference in mxb_attach()
+    - media: si2157: Fix "warm" tuner state detection
+    - sched/rt: Try to restart rt period timer when rt runtime exceeded
+    - rcu/exp: Mark current CPU as exp-QS in IPI loop second pass
+    - mwifiex: Fix possible ABBA deadlock
+    - xfrm: fix a small bug in xfrm_sa_len()
+    - crypto: stm32/cryp - fix xts and race condition in crypto_engine requests
+    - crypto: stm32/cryp - fix double pm exit
+    - crypto: stm32/cryp - fix lrw chaining mode
+    - ARM: dts: gemini: NAS4220-B: fis-index-block with 128 KiB sectors
+    - media: dw2102: Fix use after free
+    - media: msi001: fix possible null-ptr-deref in msi001_probe()
+    - media: coda/imx-vdoa: Handle dma_set_coherent_mask error codes
+    - drm/msm/dpu: fix safe status debugfs file
+    - drm/bridge: ti-sn65dsi86: Set max register for regmap
+    - media: hantro: Fix probe func error path
+    - xfrm: interface with if_id 0 should return error
+    - xfrm: state and policy should fail if XFRMA_IF_ID 0
+    - ARM: 9159/1: decompressor: Avoid UNPREDICTABLE NOP encoding
+    - usb: ftdi-elan: fix memory leak on device disconnect
+    - ARM: dts: armada-38x: Add generic compatible to UART nodes
+    - mmc: meson-mx-sdio: add IRQ check
+    - selinux: fix potential memleak in selinux_add_opt()
+    - bpftool: Enable line buffering for stdout
+    - x86/mce/inject: Avoid out-of-bounds write when setting flags
+    - ACPI: scan: Create platform device for BCM4752 and LNV4752 ACPI nodes
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      __nonstatic_find_io_region()
+    - pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in
+      nonstatic_find_mem_region()
+    - netfilter: ipt_CLUSTERIP: fix refcount leak in clusterip_tg_check()
+    - bpf: Fix SO_RCVBUF/SO_SNDBUF handling in _bpf_setsockopt().
+    - ppp: ensure minimum packet size in ppp_write()
+    - rocker: fix a sleeping in atomic bug
+    - staging: greybus: audio: Check null pointer
+    - fsl/fman: Check for null pointer after calling devm_ioremap
+    - Bluetooth: hci_bcm: Check for error irq
+    - HID: hid-uclogic-params: Invalid parameter check in uclogic_params_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_get_str_desc
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_huion_init
+    - HID: hid-uclogic-params: Invalid parameter check in
+      uclogic_params_frame_init_v1_buttonpad
+    - debugfs: lockdown: Allow reading debugfs files that are not world readable
+    - net/mlx5e: Don't block routes with nexthop objects in SW
+    - Revert "net/mlx5e: Block offload of outer header csum for UDP tunnels"
+    - net/mlx5: Set command entry semaphore up once got index free
+    - spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe
+    - tpm: add request_locality before write TPM_INT_ENABLE
+    - can: softing: softing_startstop(): fix set but not used variable warning
+    - can: xilinx_can: xcan_probe(): check for error irq
+    - pcmcia: fix setting of kthread task states
+    - net: mcs7830: handle usb read errors properly
+    - ext4: avoid trim error on fs with small groups
+    - ALSA: jack: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: PCM: Add missing rwsem around snd_ctl_remove() calls
+    - ALSA: hda: Add missing rwsem around snd_ctl_remove() calls
+    - RDMA/hns: Validate the pkey index
+    - clk: imx8mn: Fix imx8mn_clko1_sels
+    - powerpc/prom_init: Fix improper check of prom_getprop()
+    - ASoC: uniphier: drop selecting non-existing SND_SOC_UNIPHIER_AIO_DMA
+    - ALSA: oss: fix compile error when OSS_DEBUG is enabled
+    - char/mwave: Adjust io port register size
+    - binder: fix handling of error during copy
+    - iommu/io-pgtable-arm: Fix table descriptor paddr formatting
+    - scsi: ufs: Fix race conditions related to driver data
+    - PCI/MSI: Fix pci_irq_vector()/pci_irq_get_affinity()
+    - powerpc/powermac: Add additional missing lockdep_register_key()
+    - RDMA/core: Let ib_find_gid() continue search even after empty entry
+    - RDMA/cma: Let cma_resolve_ib_dev() continue search even after empty entry
+    - ASoC: rt5663: Handle device_property_read_u32_array error codes
+    - clk: stm32: Fix ltdc's clock turn off by clk_disable_unused() after system
+      enter shell
+    - dmaengine: pxa/mmp: stop referencing config->slave_id
+    - iommu/iova: Fix race between FQ timeout and teardown
+    - phy: uniphier-usb3ss: fix unintended writing zeros to PHY register
+    - ASoC: samsung: idma: Check of ioremap return value
+    - misc: lattice-ecp3-config: Fix task hung when firmware load failed
+    - mips: lantiq: add support for clk_set_parent()
+    - mips: bcm63xx: add support for clk_set_parent()
+    - RDMA/cxgb4: Set queue pair state when being queried
+    - of: base: Fix phandle argument length mismatch error message
+    - Bluetooth: Fix debugfs entry leak in hci_register_dev()
+    - fs: dlm: filter user dlm messages for kernel locks
+    - drm/lima: fix warning when CONFIG_DEBUG_SG=y & CONFIG_DMA_API_DEBUG=y
+    - ar5523: Fix null-ptr-deref with unexpected WDCMSG_TARGET_START reply
+    - drm/nouveau/pmu/gm200-: avoid touching PMU outside of DEVINIT/PREOS/ACR
+    - ARM: shmobile: rcar-gen2: Add missing of_node_put()
+    - batman-adv: allow netlink usage in unprivileged containers
+    - usb: gadget: f_fs: Use stream_open() for endpoint files
+    - drm: panel-orientation-quirks: Add quirk for the Lenovo Yoga Book X91F/L
+    - HID: apple: Do not reset quirks when the Fn key is not found
+    - media: b2c2: Add missing check in flexcop_pci_isr:
+    - EDAC/synopsys: Use the quirk for version instead of ddr version
+    - mlxsw: pci: Add shutdown method in PCI driver
+    - drm/bridge: megachips: Ensure both bridges are probed before registration
+    - gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use
+    - HSI: core: Fix return freed object in hsi_new_client
+    - mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
+    - rsi: Fix use-after-free in rsi_rx_done_handler()
+    - rsi: Fix out-of-bounds read in rsi_read_pkt()
+    - usb: uhci: add aspeed ast2600 uhci support
+    - floppy: Add max size check for user space request
+    - x86/mm: Flush global TLB when switching to trampoline page-table
+    - media: uvcvideo: Increase UVC_CTRL_CONTROL_TIMEOUT to 5 seconds.
+    - media: saa7146: hexium_orion: Fix a NULL pointer dereference in
+      hexium_attach()
+    - media: m920x: don't use stack on USB reads
+    - iwlwifi: mvm: synchronize with FW after multicast commands
+    - ath10k: Fix tx hanging
+    - net-sysfs: update the queue counts in the unregistration path
+    - net: phy: prefer 1000baseT over 1000baseKX
+    - gpio: aspeed: Convert aspeed_gpio.lock to raw_spinlock
+    - x86/mce: Mark mce_panic() noinstr
+    - x86/mce: Mark mce_end() noinstr
+    - x86/mce: Mark mce_read_aux() noinstr
+    - net: bonding: debug: avoid printing debug logs when bond is not notifying
+      peers
+    - bpf: Do not WARN in bpf_warn_invalid_xdp_action()
+    - HID: quirks: Allow inverting the absolute X/Y values
+    - media: igorplugusb: receiver overflow should be reported
+    - media: saa7146: hexium_gemini: Fix a NULL pointer dereference in
+      hexium_attach()
+    - mmc: core: Fixup storing of OCR for MMC_QUIRK_NONSTD_SDIO
+    - audit: ensure userspace is penalized the same as the kernel when under
+      pressure
+    - arm64: dts: ls1028a-qds: move rtc node to the correct i2c bus
+    - arm64: tegra: Adjust length of CCPLEX cluster MMIO region
+    - cpufreq: Fix initialization of min and max frequency QoS requests
+    - usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0
+    - ath9k: Fix out-of-bound memcpy in ath9k_hif_usb_rx_stream
+    - iwlwifi: fix leaks/bad data after failed firmware load
+    - iwlwifi: remove module loading failure message
+    - iwlwifi: mvm: Fix calculation of frame length
+    - um: registers: Rename function names to avoid conflicts and build problems
+    - jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
+    - ACPICA: actypes.h: Expand the ACPI_ACCESS_ definitions
+    - ACPICA: Utilities: Avoid deleting the same object twice in a row
+    - ACPICA: Executer: Fix the REFCLASS_REFOF case in acpi_ex_opcode_1A_0T_1R()
+    - ACPICA: Fix wrong interpretation of PCC address
+    - ACPICA: Hardware: Do not flush CPU cache when entering S4 and S5
+    - drm/amdgpu: fixup bad vram size on gmc v8
+    - ACPI: battery: Add the ThinkPad "Not Charging" quirk
+    - btrfs: remove BUG_ON() in find_parent_nodes()
+    - btrfs: remove BUG_ON(!eie) in find_parent_nodes
+    - net: mdio: Demote probed message to debug print
+    - mac80211: allow non-standard VHT MCS-10/11
+    - dm btree: add a defensive bounds check to insert_at()
+    - dm space map common: add bounds check to sm_ll_lookup_bitmap()
+    - net: phy: marvell: configure RGMII delays for 88E1118
+    - net: gemini: allow any RGMII interface mode
+    - regulator: qcom_smd: Align probe function with rpmh-regulator
+    - serial: pl010: Drop CR register reset on set_termios
+    - serial: core: Keep mctrl register state and cached copy in sync
+    - random: do not throw away excess input to crng_fast_load
+    - parisc: Avoid calling faulthandler_disabled() twice
+    - powerpc/6xx: add missing of_node_put
+    - powerpc/powernv: add missing of_node_put
+    - powerpc/cell: add missing of_node_put
+    - powerpc/btext: add missing of_node_put
+    - powerpc/watchdog: Fix missed watchdog reset due to memory ordering race
+    - i2c: i801: Don't silently correct invalid transfer size
+    - powerpc/smp: Move setup_profiling_timer() under CONFIG_PROFILING
+    - i2c: mpc: Correct I2C reset procedure
+    - clk: meson: gxbb: Fix the SDM_EN bit for MPLL0 on GXBB
+    - powerpc/powermac: Add missing lockdep_register_key()
+    - KVM: PPC: Book3S: Suppress failed alloc warning in H_COPY_TOFROM_GUEST
+    - w1: Misuse of get_user()/put_user() reported by sparse
+    - scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup
+    - ALSA: seq: Set upper limit of processed events
+    - powerpc: handle kdump appropriately with crash_kexec_post_notifiers option
+    - MIPS: OCTEON: add put_device() after of_find_device_by_node()
+    - i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters
+    - MIPS: Octeon: Fix build errors using clang
+    - scsi: sr: Don't use GFP_DMA
+    - ASoC: mediatek: mt8173: fix device_node leak
+    - power: bq25890: Enable continuous conversion for ADC at charging
+    - rpmsg: core: Clean up resources on announce_create failure.
+    - crypto: omap-aes - Fix broken pm_runtime_and_get() usage
+    - crypto: stm32/crc32 - Fix kernel BUG triggered in probe()
+    - crypto: caam - replace this_cpu_ptr with raw_cpu_ptr
+    - ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
+    - fuse: Pass correct lend value to filemap_write_and_wait_range()
+    - serial: Fix incorrect rs485 polarity on uart open
+    - cputime, cpuacct: Include guest time in user time in cpuacct.stat
+    - tracing/kprobes: 'nmissed' not showed correctly for kretprobe
+    - iwlwifi: mvm: Increase the scan timeout guard to 30 seconds
+    - s390/mm: fix 2KB pgtable release race
+    - drm/etnaviv: limit submit sizes
+    - drm/nouveau/kms/nv04: use vzalloc for nv04_display
+    - drm/bridge: analogix_dp: Make PSR-exit block less
+    - PCI: pci-bridge-emul: Properly mark reserved PCIe bits in PCI config space
+    - PCI: pci-bridge-emul: Correctly set PCIe capabilities
+    - PCI: pci-bridge-emul: Set PCI_STATUS_CAP_LIST for PCIe device
+    - xfrm: fix policy lookup for ipv6 gre packets
+    - btrfs: fix deadlock between quota enable and other quota operations
+    - btrfs: check the root node for uptodate before returning it
+    - btrfs: respect the max size in the header when activating swap file
+    - ext4: make sure to reset inode lockdep class when quota enabling fails
+    - ext4: make sure quota gets properly shutdown on error
+    - ext4: set csum seed in tmp inode while migrating to extents
+    - ext4: Fix BUG_ON in ext4_bread when write quota data
+    - ext4: don't use the orphan list when migrating an inode
+    - drm/radeon: fix error handling in radeon_driver_open_kms
+    - of: base: Improve argument length mismatch error
+    - firmware: Update Kconfig help text for Google firmware
+    - media: rcar-csi2: Optimize the selection PHTW register
+    - Documentation: dmaengine: Correctly describe dmatest with channel unset
+    - Documentation: ACPI: Fix data node reference documentation
+    - Documentation: refer to config RANDOMIZE_BASE for kernel address-space
+      randomization
+    - Documentation: fix firewire.rst ABI file path error
+    - scsi: core: Show SCMD_LAST in text form
+    - RDMA/hns: Modify the mapping attribute of doorbell to device
+    - RDMA/rxe: Fix a typo in opcode name
+    - dmaengine: stm32-mdma: fix STM32_MDMA_CTBR_TSEL_MASK
+    - Revert "net/mlx5: Add retry mechanism to the command entry index allocation"
+    - powerpc/cell: Fix clang -Wimplicit-fallthrough warning
+    - powerpc/fsl/dts: Enable WA for erratum A-009885 on fman3l MDIO buses
+    - bpftool: Remove inclusion of utilities.mak from Makefiles
+    - ipv4: avoid quadratic behavior in netns dismantle
+    - net/fsl: xgmac_mdio: Fix incorrect iounmap when removing module
+    - parisc: pdc_stable: Fix memory leak in pdcs_register_pathentries
+    - f2fs: fix to reserve space for IO align feature
+    - af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
+    - clk: si5341: Fix clock HW provider cleanup
+    - net: axienet: limit minimum TX ring size
+    - net: axienet: fix number of TX ring slots for available check
+    - net: axienet: increase default TX ring size to 128
+    - rtc: pxa: fix null pointer dereference
+    - inet: frags: annotate races around fqdir->dead and fqdir->high_thresh
+    - netns: add schedule point in ops_exit_list()
+    - xfrm: Don't accidentally set RTO_ONLINK in decode_session4()
+    - gre: Don't accidentally set RTO_ONLINK in gre_fill_metadata_dst()
+    - libcxgb: Don't accidentally set RTO_ONLINK in cxgb_find_route()
+    - perf script: Fix hex dump character output
+    - dmaengine: at_xdmac: Don't start transactions at tx_submit level
+    - dmaengine: at_xdmac: Print debug message after realeasing the lock
+    - dmaengine: at_xdmac: Fix concurrency over xfers_list
+    - dmaengine: at_xdmac: Fix lld view setting
+    - dmaengine: at_xdmac: Fix at_xdmac_lld struct definition
+    - arm64: dts: qcom: msm8996: drop not documented adreno properties
+    - net_sched: restore "mpu xxx" handling
+    - bcmgenet: add WOL IRQ check
+    - net: ethernet: mtk_eth_soc: fix error checking in mtk_mac_config()
+    - dt-bindings: display: meson-dw-hdmi: add missing sound-name-prefix property
+    - dt-bindings: display: meson-vpu: Add missing amlogic,canvas property
+    - scripts/dtc: dtx_diff: remove broken example from help text
+    - lib82596: Fix IRQ check in sni_82596_probe
+    - lib/test_meminit: destroy cache in kmem_cache_alloc_bulk() test
+    - mtd: nand: bbt: Fix corner case in bad block table handling
+    - Revert "ia64: kprobes: Use generic kretprobe trampoline handler"
+    - Linux 5.4.174
+  * Focal update: v5.4.173 upstream stable release (LP: #1959701)
+    - kbuild: Add $(KBUILD_HOSTLDFLAGS) to 'has_libelf' test
+    - devtmpfs regression fix: reconfigure on each mount
+    - orangefs: Fix the size of a memory allocation in orangefs_bufmap_alloc()
+    - perf: Protect perf_guest_cbs with RCU
+    - KVM: s390: Clarify SIGP orders versus STOP/RESTART
+    - media: uvcvideo: fix division by zero at stream start
+    - rtlwifi: rtl8192cu: Fix WARNING when calling local_irq_restore() with
+      interrupts enabled
+    - firmware: qemu_fw_cfg: fix sysfs information leak
+    - firmware: qemu_fw_cfg: fix NULL-pointer deref on duplicate entries
+    - firmware: qemu_fw_cfg: fix kobject leak in probe error path
+    - KVM: x86: remove PMU FIXED_CTR3 from msrs_to_save_all
+    - ALSA: hda/realtek - Fix silent output on Gigabyte X570 Aorus Master after
+      reboot from Windows
+    - mtd: fixup CFI on ixp4xx
+    - ARM: 9025/1: Kconfig: CPU_BIG_ENDIAN depends on !LD_IS_LLD
+    - Linux 5.4.173
+  * Focal update: v5.4.172 upstream stable release (LP: #1959698)
+    - workqueue: Fix unbind_workers() VS wq_worker_running() race
+    - Bluetooth: btusb: fix memory leak in btusb_mtk_submit_wmt_recv_urb()
+    - Bluetooth: bfusb: fix division by zero in send path
+    - USB: core: Fix bug in resuming hub's handling of wakeup requests
+    - USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
+    - mmc: sdhci-pci: Add PCI ID for Intel ADL
+    - veth: Do not record rx queue hint in veth_xmit
+    - mfd: intel-lpss: Fix too early PM enablement in the ACPI ->probe()
+    - drivers core: Use sysfs_emit and sysfs_emit_at for show(device *...)
+      functions
+    - can: gs_usb: fix use of uninitialized variable, detach device on reception
+      of invalid USB data
+    - can: gs_usb: gs_can_start_xmit(): zero-initialize hf->{flags,reserved}
+    - random: fix data race on crng_node_pool
+    - random: fix data race on crng init time
+    - random: fix crash on multiple early calls to add_bootloader_randomness()
+    - media: Revert "media: uvcvideo: Set unique vdev name based in type"
+    - staging: wlan-ng: Avoid bitwise vs logical OR warning in
+      hfa384x_usb_throttlefn()
+    - drm/i915: Avoid bitwise vs logical OR warning in snb_wm_latency_quirk()
+    - staging: greybus: fix stack size warning with UBSAN
+    - Linux 5.4.172
+  * Focal update: v5.4.171 upstream stable release (LP: #1959437)
+    - f2fs: quota: fix potential deadlock
+    - Input: touchscreen - Fix backport of
+      a02dcde595f7cbd240ccd64de96034ad91cffc40
+    - selftests: x86: fix [-Wstringop-overread] warn in test_process_vm_readv()
+    - tracing: Fix check for trace_percpu_buffer validity in get_trace_buf()
+    - tracing: Tag trace_percpu_buffer as a percpu pointer
+    - ieee802154: atusb: fix uninit value in atusb_set_extended_addr
+    - iavf: Fix limit of total number of queues to active queues of VF
+    - RDMA/core: Don't infoleak GRH fields
+    - RDMA/uverbs: Check for null return of kmalloc_array
+    - mac80211: initialize variable have_higher_than_11mbit
+    - i40e: fix use-after-free in i40e_sync_filters_subtask()
+    - i40e: Fix for displaying message regarding NVM version
+    - i40e: Fix incorrect netdev's real number of RX/TX queues
+    - ipv4: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv4: Check attribute length for RTA_FLOW in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY in multipath route
+    - ipv6: Check attribute length for RTA_GATEWAY when deleting multipath route
+    - lwtunnel: Validate RTA_ENCAP_TYPE attribute length
+    - batman-adv: mcast: don't send link-local multicast to mcast routers
+    - sch_qfq: prevent shift-out-of-bounds in qfq_init_qdisc
+    - net: phy: micrel: set soft_reset callback to genphy_soft_reset for KSZ8081
+    - power: supply: core: Break capacity loop
+    - power: reset: ltc2952: Fix use of floating point literals
+    - rndis_host: support Hytera digital radios
+    - phonet: refcount leak in pep_sock_accep
+    - ipv6: Continue processing multipath route even if gateway attribute is
+      invalid
+    - ipv6: Do cleanup if attribute validation fails in multipath route
+    - usb: mtu3: fix interval value for intr and isoc
+    - scsi: libiscsi: Fix UAF in iscsi_conn_get_param()/iscsi_conn_teardown()
+    - ip6_vti: initialize __ip6_tnl_parm struct in vti6_siocdevprivate
+    - net: udp: fix alignment problem in udp4_seq_show()
+    - atlantic: Fix buff_ring OOB in aq_ring_rx_clean
+    - mISDN: change function names to avoid conflicts
+    - Linux 5.4.171
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898)
+    - tee: handle lookup of shm with reference count 0
+    - Input: i8042 - add deferred probe support
+    - Input: i8042 - enable deferred probe quirk for ASUS UM325UA
+    - tomoyo: Check exceeded quota early in tomoyo_domain_quota_is_ok().
+    - platform/x86: apple-gmux: use resource_size() with res
+    - memblock: fix memblock_phys_alloc() section mismatch error
+    - recordmcount.pl: fix typo in s390 mcount regex
+    - selinux: initialize proto variable in selinux_ip_postroute_compat()
+    - scsi: lpfc: Terminate string in lpfc_debugfs_nvmeio_trc_write()
+    - net/mlx5: DR, Fix NULL vs IS_ERR checking in dr_domain_init_resources
+    - sctp: use call_rcu to free endpoint
+    - net: usb: pegasus: Do not drop long Ethernet frames
+    - net: lantiq_xrx200: fix statistics of received bytes
+    - NFC: st21nfca: Fix memory leak in device probe and remove
+    - ionic: Initialize the 'lif->dbid_inuse' bitmap
+    - net/mlx5e: Fix wrong features assignment in case of error
+    - selftests/net: udpgso_bench_tx: fix dst ip argument
+    - net/ncsi: check for error return from call to nla_put_u32
+    - fsl/fman: Fix missing put_device() call in fman_port_probe
+    - i2c: validate user data in compat ioctl
+    - nfc: uapi: use kernel size_t to fix user-space builds
+    - uapi: fix linux/nfc.h userspace compilation errors
+    - xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.
+    - usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
+    - usb: mtu3: add memory barrier before set GPD's HWO
+    - usb: mtu3: fix list_head check warning
+    - usb: mtu3: set interval of FS intr and isoc endpoint
+    - binder: fix async_free_space accounting for empty parcels
+    - scsi: vmw_pvscsi: Set residual data length conditionally
+    - Input: appletouch - initialize work before device registration
+    - Input: spaceball - fix parsing of movement data packets
+    - net: fix use-after-free in tw_timer_handler
+    - perf script: Fix CPU filtering of a script's switch events
+    - Linux 5.4.170
+  * Focal update: v5.4.170 upstream stable release (LP: #1958898) // HID_ASUS
+    should depend on USB_HID in stable v4.15 backports (LP: #1959762)
+    - HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option
+  * Focal update: v5.4.169 upstream stable release (LP: #1958557)
+    - net: usb: lan78xx: add Allied Telesis AT29M2-AF
+    - serial: 8250_fintek: Fix garbled text for console
+    - arm64: dts: allwinner: orangepi-zero-plus: fix PHY mode
+    - spi: change clk_disable_unprepare to clk_unprepare
+    - IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
+    - netfilter: fix regression in looped (broad|multi)cast's MAC handling
+    - qlcnic: potential dereference null pointer of rx_queue->page_ring
+    - net: accept UFOv6 packages in virtio_net_hdr_to_skb
+    - net: skip virtio_net_hdr_set_proto if protocol already set
+    - ipmi: Fix UAF when uninstall ipmi_si and ipmi_msghandler module
+    - bonding: fix ad_actor_system option setting to default
+    - fjes: Check for error irq
+    - drivers: net: smc911x: Check for error irq
+    - sfc: falcon: Check null pointer of rx_queue->page_ring
+    - Input: elantech - fix stack out of bound access in
+      elantech_change_report_id()
+    - hwmon: (lm90) Fix usage of CONFIG2 register in detect function
+    - hwmon: (lm90) Add max6654 support to lm90 driver
+    - hwmon: (lm90) Add basic support for TI TMP461
+    - hwmon: (lm90) Introduce flag indicating extended temperature support
+    - hwmon: (lm90) Drop critical attribute support for MAX6654
+    - ALSA: jack: Check the return value of kstrdup()
+    - ALSA: drivers: opl3: Fix incorrect use of vp->state
+    - ALSA: hda/realtek: Amp init fixup for HP ZBook 15 G6
+    - Input: atmel_mxt_ts - fix double free in mxt_read_info_block
+    - ipmi: bail out if init_srcu_struct fails
+    - ipmi: ssif: initialize ssif_info->client early
+    - ipmi: fix initialization when workqueue allocation fails
+    - parisc: Correct completer in lws start
+    - x86/pkey: Fix undefined behaviour with PKRU_WD_BIT
+    - pinctrl: stm32: consider the GPIO offset to expose all the GPIO lines
+    - mmc: sdhci-tegra: Fix switch to HS400ES mode
+    - mmc: core: Disable card detect during shutdown
+    - ARM: 9169/1: entry: fix Thumb2 bug in iWMMXt exception handling
+    - tee: optee: Fix incorrect page free bug
+    - f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr()
+    - usb: gadget: u_ether: fix race in setting MAC address in setup phase
+    - KVM: VMX: Fix stale docs for kvm-intel.emulate_invalid_guest_state
+    - mm: mempolicy: fix THP allocations escaping mempolicy restrictions
+    - pinctrl: mediatek: fix global-out-of-bounds issue
+    - hwmom: (lm90) Fix citical alarm status for MAX6680/MAX6681
+    - hwmon: (lm90) Do not report 'busy' status bit as alarm
+    - ax25: NPD bug when detaching AX25 device
+    - hamradio: defer ax25 kfree after unregister_netdev
+    - hamradio: improve the incomplete fix to avoid NPD
+    - phonet/pep: refuse to enable an unbound pipe
+    - Linux 5.4.169
+  * Focal update: v5.4.168 upstream stable release (LP: #1957991)
+    - KVM: selftests: Make sure kvm_create_max_vcpus test won't hit RLIMIT_NOFILE
+    - mac80211: mark TX-during-stop for TX in in_reconfig
+    - mac80211: send ADDBA requests using the tid/queue of the aggregation session
+    - firmware: arm_scpi: Fix string overflow in SCPI genpd driver
+    - virtio_ring: Fix querying of maximum DMA mapping size for virtio device
+    - recordmcount.pl: look for jgnop instruction as well as bcrl on s390
+    - dm btree remove: fix use after free in rebalance_children()
+    - audit: improve robustness of the audit queue handling
+    - iio: adc: stm32: fix a current leak by resetting pcsel before disabling vdda
+    - nfsd: fix use-after-free due to delegation race
+    - arm64: dts: rockchip: remove mmc-hs400-enhanced-strobe from rk3399-khadas-
+      edge
+    - arm64: dts: rockchip: fix rk3399-leez-p710 vcc3v3-lan supply
+    - arm64: dts: rockchip: fix audio-supply for Rock Pi 4
+    - mac80211: track only QoS data frames for admission control
+    - ARM: socfpga: dts: fix qspi node compatible
+    - clk: Don't parent clks until the parent is fully registered
+    - selftests: net: Correct ping6 expected rc from 2 to 1
+    - s390/kexec_file: fix error handling when applying relocations
+    - sch_cake: do not call cake_destroy() from cake_init()
+    - inet_diag: use jiffies_delta_to_msecs()
+    - inet_diag: fix kernel-infoleak for UDP sockets
+    - selftests: Fix raw socket bind tests with VRF
+    - selftests: Fix IPv6 address bind tests
+    - dmaengine: st_fdma: fix MODULE_ALIAS
+    - selftest/net/forwarding: declare NETIFS p9 p10
+    - mac80211: agg-tx: refactor sending addba
+    - mac80211: agg-tx: don't schedule_and_wake_txq() under sta->lock
+    - mac80211: accept aggregation sessions on 6 GHz
+    - mac80211: fix lookup when adding AddBA extension element
+    - net: sched: lock action when translating it to flow_action infra
+    - flow_offload: return EOPNOTSUPP for the unsupported mpls action type
+    - rds: memory leak in __rds_conn_create()
+    - soc/tegra: fuse: Fix bitwise vs. logical OR warning
+    - igb: Fix removal of unicast MAC filters of VFs
+    - igbvf: fix double free in `igbvf_probe`
+    - ixgbe: set X550 MDIO speed before talking to PHY
+    - netdevsim: Zero-initialize memory for new map's value in function
+      nsim_bpf_map_alloc
+    - net: Fix double 0x prefix print in SKB dump
+    - net/smc: Prevent smc_release() from long blocking
+    - net: systemport: Add global locking for descriptor lifecycle
+    - sit: do not call ipip6_dev_free() from sit_init_net()
+    - USB: NO_LPM quirk Lenovo USB-C to Ethernet Adapher(RTL8153-04)
+    - PCI/MSI: Clear PCI_MSIX_FLAGS_MASKALL on error
+    - PCI/MSI: Mask MSI-X vectors only on success
+    - usb: xhci: Extend support for runtime power management for AMD's Yellow
+      carp.
+    - USB: serial: cp210x: fix CP2105 GPIO registration
+    - USB: serial: option: add Telit FN990 compositions
+    - timekeeping: Really make sure wall_to_monotonic isn't positive
+    - libata: if T_LENGTH is zero, dma direction should be DMA_NONE
+    - drm/amdgpu: correct register access for RLC_JUMP_TABLE_RESTORE
+    - mac80211: validate extended element ID is present
+    - mwifiex: Remove unnecessary braces from HostCmd_SET_SEQ_NO_BSS_INFO
+    - Input: touchscreen - avoid bitwise vs logical OR warning
+    - ARM: dts: imx6ull-pinfunc: Fix CSI_DATA07__ESAI_TX0 pad name
+    - xsk: Do not sleep in poll() when need_wakeup set
+    - media: mxl111sf: change mutex_init() location
+    - fuse: annotate lock in fuse_reverse_inval_entry()
+    - ovl: fix warning in ovl_create_real()
+    - scsi: scsi_debug: Sanity check block descriptor length in resp_mode_select()
+    - rcu: Mark accesses to rcu_state.n_force_qs
+    - mac80211: fix regression in SSN handling of addba tx
+    - net: sched: Fix suspicious RCU usage while accessing tcf_tunnel_info
+    - Revert "xsk: Do not sleep in poll() when need_wakeup set"
+    - xen/blkfront: harden blkfront against event channel storms
+    - xen/netfront: harden netfront against event channel storms
+    - xen/console: harden hvc_xen against event channel storms
+    - xen/netback: fix rx queue stall detection
+    - xen/netback: don't queue unlimited number of packages
+    - Linux 5.4.168
+  * Focal update: v5.4.167 upstream stable release (LP: #1957987)
+    - nfc: fix segfault in nfc_genl_dump_devices_done
+    - drm/msm/dsi: set default num_data_lanes
+    - net/mlx4_en: Update reported link modes for 1/10G
+    - parisc/agp: Annotate parisc agp init functions with __init
+    - i2c: rk3x: Handle a spurious start completion interrupt flag
+    - net: netlink: af_netlink: Prevent empty skb by adding a check on len.
+    - drm/amd/display: Fix for the no Audio bug with Tiled Displays
+    - drm/amd/display: add connector type check for CRC source set
+    - tracing: Fix a kmemleak false positive in tracing_map
+    - KVM: x86: Ignore sparse banks size for an "all CPUs", non-sparse IPI req
+    - selinux: fix race condition when computing ocontext SIDs
+    - bpf: Fix integer overflow in argument calculation for bpf_map_area_alloc
+    - hwmon: (dell-smm) Fix warning on /proc/i8k creation error
+    - memblock: free_unused_memmap: use pageblock units instead of MAX_ORDER
+    - memblock: align freed memory map on pageblock boundaries with SPARSEMEM
+    - memblock: ensure there is no overflow in memblock_overlaps_region()
+    - arm: extend pfn_valid to take into account freed memory map alignment
+    - arm: ioremap: don't abuse pfn_valid() to check if pfn is in RAM
+    - Linux 5.4.167
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+
+  [ Ubuntu: 5.4.0-104.118 ]
+
+  * CVE-2022-23960
+    - SAUCE: kvm: arm: fix build on 32-bit
+
+  [ Ubuntu: 5.4.0-103.117 ]
+
+  * CVE-2022-23960
+    - arm64: Add part number for Arm Cortex-A77
+    - arm64: Add Neoverse-N2, Cortex-A710 CPU part definition
+    - arm64: Add Cortex-X2 CPU part definition
+    - arm64: add ID_AA64ISAR2_EL1 sys register
+    - SAUCE: arm64: entry.S: Add ventry overflow sanity checks
+    - SAUCE: arm64: entry: Make the trampoline cleanup optional
+    - SAUCE: arm64: entry: Free up another register on kpti's tramp_exit path
+    - SAUCE: arm64: entry: Move the trampoline data page before the text page
+    - SAUCE: arm64: entry: Allow tramp_alias to access symbols after the 4K
+      boundary
+    - SAUCE: arm64: entry: Don't assume tramp_vectors is the start of the vectors
+    - SAUCE: arm64: entry: Move trampoline macros out of ifdef'd section
+    - SAUCE: arm64: entry: Make the kpti trampoline's kpti sequence optional
+    - SAUCE: arm64: entry: Allow the trampoline text to occupy multiple pages
+    - SAUCE: arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations
+    - SAUCE: arm64: entry: Add vectors that have the bhb mitigation sequences
+    - SAUCE: arm64: entry: Add macro for reading symbol addresses from the
+      trampoline
+    - SAUCE: arm64: Add percpu vectors for EL1
+    - SAUCE: arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of
+      Spectre-v2
+    - SAUCE: KVM: arm64: Add templates for BHB mitigation sequences
+    - SAUCE: arm64: Mitigate spectre style branch history side channels
+    - SAUCE: KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and
+      migrated
+    - SAUCE: arm64: Use the clearbhb instruction in mitigations
+    - [Config]: set CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+  * CVE-2022-25636
+    - netfilter: nf_tables_offload: incorrect flow offload action array size
+  * CVE-2022-0001
+    - 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
+
+  [ Ubuntu: 5.4.0-100.113 ]
+
+  * focal/linux: 5.4.0-100.113 -proposed tracker (LP: #1959900)
+  * CVE-2022-22942
+    - SAUCE: drm/vmwgfx: Fix stale file descriptors on failed usercopy
+  * CVE-2022-0330
+    - drm/i915: Flush TLBs before releasing backing store
+  * Focal update: v5.4.166 upstream stable release (LP: #1957008)
+    - netfilter: selftest: conntrack_vrf.sh: fix file permission
+    - Linux 5.4.166
+    - net/packet: rx_owner_map depends on pg_vec
+    - USB: gadget: bRequestType is a bitfield, not a enum
+    - HID: holtek: fix mouse probing
+    - udp: using datalen to cap ipv6 udp max gso segments
+    - selftests: Calculate udpgso segment count without header adjustment
+  * Focal update: v5.4.165 upstream stable release (LP: #1957007)
+    - serial: tegra: Change lower tolerance baud rate limit for tegra20 and
+      tegra30
+    - ntfs: fix ntfs_test_inode and ntfs_init_locked_inode function type
+    - HID: quirks: Add quirk for the Microsoft Surface 3 type-cover
+    - HID: google: add eel USB id
+    - HID: add hid_is_usb() function to make it simpler for USB detection
+    - HID: add USB_HID dependancy to hid-prodikeys
+    - HID: add USB_HID dependancy to hid-chicony
+    - HID: add USB_HID dependancy on some USB HID drivers
+    - HID: bigbenff: prevent null pointer dereference
+    - HID: wacom: fix problems when device is not a valid USB device
+    - HID: check for valid USB device for many HID drivers
+    - can: kvaser_usb: get CAN clock frequency from device
+    - can: kvaser_pciefd: kvaser_pciefd_rx_error_frame(): increase correct
+      stats->{rx,tx}_errors counter
+    - can: sja1000: fix use after free in ems_pcmcia_add_card()
+    - nfc: fix potential NULL pointer deref in nfc_genl_dump_ses_done
+    - selftests: netfilter: add a vrf+conntrack testcase
+    - vrf: don't run conntrack on vrf with !dflt qdisc
+    - bpf: Fix the off-by-two error in range markings
+    - ice: ignore dropped packets during init
+    - bonding: make tx_rebalance_counter an atomic
+    - nfp: Fix memory leak in nfp_cpp_area_cache_add()
+    - seg6: fix the iif in the IPv6 socket control block
+    - udp: using datalen to cap max gso segments
+    - iavf: restore MSI state on reset
+    - iavf: Fix reporting when setting descriptor count
+    - IB/hfi1: Correct guard on eager buffer deallocation
+    - mm: bdi: initialize bdi_min_ratio when bdi is unregistered
+    - ALSA: ctl: Fix copy of updated id with element read/write
+    - ALSA: hda/realtek - Add headset Mic support for Lenovo ALC897 platform
+    - ALSA: pcm: oss: Fix negative period/buffer sizes
+    - ALSA: pcm: oss: Limit the period size to 16MB
+    - ALSA: pcm: oss: Handle missing errors in snd_pcm_oss_change_params*()
+    - btrfs: clear extent buffer uptodate when we fail to write it
+    - btrfs: replace the BUG_ON in btrfs_del_root_ref with proper error handling
+    - nfsd: Fix nsfd startup race (again)
+    - tracefs: Have new files inherit the ownership of their parent
+    - clk: qcom: regmap-mux: fix parent clock lookup
+    - drm/syncobj: Deal with signalled fences in drm_syncobj_find_fence.
+    - can: pch_can: pch_can_rx_normal: fix use after free
+    - can: m_can: Disable and ignore ELO interrupt
+    - x86/sme: Explicitly map new EFI memmap table as encrypted
+    - libata: add horkage for ASMedia 1092
+    - wait: add wake_up_pollfree()
+    - SAUCE: binder: export __wake_up_pollfree for binder module
+    - binder: use wake_up_pollfree()
+    - signalfd: use wake_up_pollfree()
+    - aio: keep poll requests on waitqueue until completed
+    - aio: fix use-after-free due to missing POLLFREE handling
+    - tracefs: Set all files to the same group ownership as the mount option
+    - block: fix ioprio_get(IOPRIO_WHO_PGRP) vs setuid(2)
+    - qede: validate non LSO skb length
+    - ASoC: qdsp6: q6routing: Fix return value from msm_routing_put_audio_mixer
+    - i40e: Fix failed opcode appearing if handling messages from VF
+    - i40e: Fix pre-set max number of queues for VF
+    - mtd: rawnand: fsmc: Take instruction delay into account
+    - mtd: rawnand: fsmc: Fix timing computation
+    - dt-bindings: net: Reintroduce PHY no lane swap binding
+    - tools build: Remove needless libpython-version feature check that breaks
+      test-all fast path
+    - net: cdc_ncm: Allow for dwNtbOutMaxSize to be unset or zero
+    - net: altera: set a couple error code in probe()
+    - net: fec: only clear interrupt of handling queue in fec_enet_rx_queue()
+    - net, neigh: clear whole pneigh_entry at alloc time
+    - net/qla3xxx: fix an error code in ql_adapter_up()
+    - Revert "UBUNTU: SAUCE: selftests: fib_tests: assign address to dummy1 for
+      rp_filter tests"
+    - selftests/fib_tests: Rework fib_rp_filter_test()
+    - USB: gadget: detect too-big endpoint 0 requests
+    - USB: gadget: zero allocate endpoint 0 buffers
+    - usb: core: config: fix validation of wMaxPacketValue entries
+    - xhci: Remove CONFIG_USB_DEFAULT_PERSIST to prevent xHCI from runtime
+      suspending
+    - usb: core: config: using bit mask instead of individual bits
+    - xhci: avoid race between disable slot command and host runtime suspend
+    - iio: trigger: Fix reference counting
+    - iio: trigger: stm32-timer: fix MODULE_ALIAS
+    - iio: stk3310: Don't return error code in interrupt handler
+    - iio: mma8452: Fix trigger reference couting
+    - iio: ltr501: Don't return error code in trigger handler
+    - iio: kxsd9: Don't return error code in trigger handler
+    - iio: itg3200: Call iio_trigger_notify_done() on error
+    - iio: dln2-adc: Fix lockdep complaint
+    - iio: dln2: Check return value of devm_iio_trigger_register()
+    - iio: at91-sama5d2: Fix incorrect sign extension
+    - iio: adc: axp20x_adc: fix charging current reporting on AXP22x
+    - iio: ad7768-1: Call iio_trigger_notify_done() on error
+    - iio: accel: kxcjk-1013: Fix possible memory leak in probe and remove
+    - irqchip/armada-370-xp: Fix return value of armada_370_xp_msi_alloc()
+    - irqchip/armada-370-xp: Fix support for Multi-MSI interrupts
+    - irqchip/irq-gic-v3-its.c: Force synchronisation when issuing INVALL
+    - irqchip: nvic: Fix offset for Interrupt Priority Offsets
+    - misc: fastrpc: fix improper packet size calculation
+    - bpf: Add selftests to cover packet access corner cases
+    - Linux 5.4.165
+  * Focal update: v5.4.164 upstream stable release (LP: #1956381)
+    - NFSv42: Fix pagecache invalidation after COPY/CLONE
+    - of: clk: Make <linux/of_clk.h> self-contained
+    - arm64: dts: mcbin: support 2W SFP modules
+    - can: j1939: j1939_tp_cmd_recv(): check the dst address of TP.CM_BAM
+    - gfs2: Fix length of holes reported at end-of-file
+    - drm/sun4i: fix unmet dependency on RESET_CONTROLLER for PHY_SUN6I_MIPI_DPHY
+    - mac80211: do not access the IV when it was stripped
+    - net/smc: Transfer remaining wait queue entries during fallback
+    - atlantic: Fix OOB read and write in hw_atl_utils_fw_rpc_wait
+    - net: return correct error code
+    - platform/x86: thinkpad_acpi: Fix WWAN device disabled issue after S3 deep
+    - s390/setup: avoid using memblock_enforce_memory_limit
+    - btrfs: check-integrity: fix a warning on write caching disabled disk
+    - thermal: core: Reset previous low and high trip during thermal zone init
+    - scsi: iscsi: Unblock session then wake up error handler
+    - ata: ahci: Add Green Sardine vendor ID as board_ahci_mobile
+    - ethernet: hisilicon: hns: hns_dsaf_misc: fix a possible array overflow in
+      hns_dsaf_ge_srst_by_port()
+    - net: tulip: de4x5: fix the problem that the array 'lp->phy[8]' may be out of
+      bound
+    - net: ethernet: dec: tulip: de4x5: fix possible array overflows in
+      type3_infoblock()
+    - perf hist: Fix memory leak of a perf_hpp_fmt
+    - perf report: Fix memory leaks around perf_tip()
+    - net/smc: Avoid warning of possible recursive locking
+    - vrf: Reset IPCB/IP6CB when processing outbound pkts in vrf dev xmit
+    - kprobes: Limit max data_size of the kretprobe instances
+    - rt2x00: do not mark device gone on EPROTO errors during start
+    - cpufreq: Fix get_cpu_device() failure in add_cpu_dev_symlink()
+    - s390/pci: move pseudo-MMIO to prevent MIO overlap
+    - sata_fsl: fix UAF in sata_fsl_port_stop when rmmod sata_fsl
+    - sata_fsl: fix warning in remove_proc_entry when rmmod sata_fsl
+    - i2c: stm32f7: flush TX FIFO upon transfer errors
+    - i2c: stm32f7: recover the bus on access timeout
+    - i2c: stm32f7: stop dma transfer in case of NACK
+    - i2c: cbus-gpio: set atomic transfer callback
+    - natsemi: xtensa: fix section mismatch warnings
+    - net: qlogic: qlcnic: Fix a NULL pointer dereference in
+      qlcnic_83xx_add_rings()
+    - net: mpls: Fix notifications when deleting a device
+    - siphash: use _unaligned version by default
+    - net/mlx4_en: Fix an use-after-free bug in mlx4_en_try_alloc_resources()
+    - selftests: net: Correct case name
+    - rxrpc: Fix rxrpc_local leak in rxrpc_lookup_peer()
+    - net: usb: lan78xx: lan78xx_phy_init(): use PHY_POLL instead of "0" if no IRQ
+      is available
+    - net: marvell: mvpp2: Fix the computation of shared CPUs
+    - net: annotate data-races on txq->xmit_lock_owner
+    - ipv4: convert fib_num_tclassid_users to atomic_t
+    - net/rds: correct socket tunable error in rds_tcp_tune()
+    - net/smc: Keep smc_close_final rc during active close
+    - drm/msm: Do hw_init() before capturing GPU state
+    - ipv6: fix memory leak in fib6_rule_suppress
+    - KVM: x86/pmu: Fix reserved bits for AMD PerfEvtSeln register
+    - sched/uclamp: Fix rq->uclamp_max not set on first enqueue
+    - parisc: Fix KBUILD_IMAGE for self-extracting kernel
+    - parisc: Fix "make install" on newer debian releases
+    - vgacon: Propagate console boot parameters before calling `vc_resize'
+    - xhci: Fix commad ring abort, write all 64 bits to CRCR register.
+    - USB: NO_LPM quirk Lenovo Powered USB-C Travel Hub
+    - usb: typec: tcpm: Wait in SNK_DEBOUNCED until disconnect
+    - x86/tsc: Add a timer to make sure TSC_adjust is always checked
+    - x86/tsc: Disable clocksource watchdog for TSC on qualified platorms
+    - x86/64/mm: Map all kernel memory into trampoline_pgd
+    - tty: serial: msm_serial: Deactivate RX DMA for polling support
+    - serial: pl011: Add ACPI SBSA UART match id
+    - serial: core: fix transmit-buffer reset and memleak
+    - serial: 8250_pci: Fix ACCES entries in pci_serial_quirks array
+    - serial: 8250_pci: rewrite pericom_do_set_divisor()
+    - iwlwifi: mvm: retry init flow if failed
+    - parisc: Mark cr16 CPU clocksource unstable on all SMP machines
+    - net/tls: Fix authentication failure in CCM mode
+    - Linux 5.4.164
+  * Focal update: v5.4.163 upstream stable release (LP: #1956380)
+    - USB: serial: option: add Telit LE910S1 0x9200 composition
+    - USB: serial: option: add Fibocom FM101-GL variants
+    - usb: dwc2: gadget: Fix ISOC flow for elapsed frames
+    - usb: dwc2: hcd_queue: Fix use of floating point literal
+    - net: nexthop: fix null pointer dereference when IPv6 is not enabled
+    - usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts
+    - usb: hub: Fix usb enumeration issue due to address0 race
+    - usb: hub: Fix locking issues with address0_mutex
+    - binder: fix test regression due to sender_euid change
+    - ALSA: ctxfi: Fix out-of-range access
+    - media: cec: copy sequence field for the reply
+    - HID: wacom: Use "Confidence" flag to prevent reporting invalid contacts
+    - staging/fbtft: Fix backlight
+    - staging: rtl8192e: Fix use after free in _rtl92e_pci_disconnect()
+    - xen: don't continue xenstore initialization in case of errors
+    - xen: detect uninitialized xenbus in xenbus_init
+    - KVM: PPC: Book3S HV: Prevent POWER7/8 TLB flush flushing SLB
+    - tracing/uprobe: Fix uprobe_perf_open probes iteration
+    - tracing: Fix pid filtering when triggers are attached
+    - mmc: sdhci: Fix ADMA for PAGE_SIZE >= 64KiB
+    - mdio: aspeed: Fix "Link is Down" issue
+    - PCI: aardvark: Deduplicate code in advk_pcie_rd_conf()
+    - PCI: aardvark: Wait for endpoint to be ready before training link
+    - PCI: aardvark: Fix big endian support
+    - PCI: aardvark: Train link immediately after enabling training
+    - PCI: aardvark: Improve link training
+    - PCI: aardvark: Issue PERST via GPIO
+    - PCI: aardvark: Replace custom macros by standard linux/pci_regs.h macros
+    - PCI: aardvark: Don't touch PCIe registers if no card connected
+    - PCI: aardvark: Fix compilation on s390
+    - PCI: aardvark: Move PCIe reset card code to advk_pcie_train_link()
+    - PCI: aardvark: Update comment about disabling link training
+    - PCI: pci-bridge-emul: Fix array overruns, improve safety
+    - PCI: aardvark: Configure PCIe resources from 'ranges' DT property
+    - PCI: aardvark: Fix PCIe Max Payload Size setting
+    - PCI: aardvark: Implement re-issuing config requests on CRS response
+    - PCI: aardvark: Simplify initialization of rootcap on virtual bridge
+    - PCI: aardvark: Fix link training
+    - PCI: aardvark: Fix support for bus mastering and PCI_COMMAND on emulated
+      bridge
+    - PCI: aardvark: Set PCI Bridge Class Code to PCI Bridge
+    - PCI: aardvark: Fix support for PCI_BRIDGE_CTL_BUS_RESET on emulated bridge
+    - pinctrl: armada-37xx: Correct PWM pins definitions
+    - arm64: dts: marvell: armada-37xx: Set pcie_reset_pin to gpio function
+    - proc/vmcore: fix clearing user buffer by properly using clear_user()
+    - netfilter: ipvs: Fix reuse connection if RS weight is 0
+    - ARM: dts: BCM5301X: Fix I2C controller interrupt
+    - ARM: dts: BCM5301X: Add interrupt properties to GPIO node
+    - ASoC: qdsp6: q6routing: Conditionally reset FrontEnd Mixer
+    - ASoC: topology: Add missing rwsem around snd_ctl_remove() calls
+    - net: ieee802154: handle iftypes as u32
+    - firmware: arm_scmi: pm: Propagate return value to caller
+    - NFSv42: Don't fail clone() unless the OP_CLONE operation failed
+    - ARM: socfpga: Fix crash with CONFIG_FORTIRY_SOURCE
+    - scsi: mpt3sas: Fix kernel panic during drive powercycle test
+    - drm/vc4: fix error code in vc4_create_object()
+    - iavf: Prevent changing static ITR values if adaptive moderation is on
+    - ipv6: fix typos in __ip6_finish_output()
+    - nfp: checking parameter process for rx-usecs/tx-usecs is invalid
+    - net: ipv6: add fib6_nh_release_dsts stub
+    - net: nexthop: release IPv6 per-cpu dsts when replacing a nexthop group
+    - scsi: core: sysfs: Fix setting device state to SDEV_RUNNING
+    - net/smc: Ensure the active closing peer first closes clcsock
+    - nvmet-tcp: fix incomplete data digest send
+    - net/ncsi : Add payload to be 32-bit aligned to fix dropped packets
+    - PM: hibernate: use correct mode for swsusp_close()
+    - tcp_cubic: fix spurious Hystart ACK train detections for not-cwnd-limited
+      flows
+    - nvmet: use IOCB_NOWAIT only if the filesystem supports it
+    - igb: fix netpoll exit with traffic
+    - MIPS: use 3-level pgtable for 64KB page size on MIPS_VA_BITS_48
+    - net: vlan: fix underflow for the real_dev refcnt
+    - net/smc: Don't call clcsock shutdown twice when smc shutdown
+    - net: hns3: fix VF RSS failed problem after PF enable multi-TCs
+    - net: mscc: ocelot: don't downgrade timestamping RX filters in SIOCSHWTSTAMP
+    - net: mscc: ocelot: correctly report the timestamping RX filters in ethtool
+    - f2fs: set SBI_NEED_FSCK flag when inconsistent node block found
+    - smb3: do not error on fsync when readonly
+    - vhost/vsock: fix incorrect used length reported to the guest
+    - tracing: Check pid filtering when creating events
+    - s390/mm: validate VMA in PGSTE manipulation functions
+    - shm: extend forced shm destroy to support objects from several IPC nses
+    - NFC: add NCI_UNREG flag to eliminate the race
+    - fuse: release pipe buf after last use
+    - xen: sync include/xen/interface/io/ring.h with Xen's newest version
+    - xen/blkfront: read response from backend only once
+    - xen/blkfront: don't take local copy of a request from the ring page
+    - xen/blkfront: don't trust the backend response data blindly
+    - xen/netfront: read response from backend only once
+    - xen/netfront: don't read data from request on the ring page
+    - xen/netfront: disentangle tx_skb_freelist
+    - xen/netfront: don't trust the backend response data blindly
+    - tty: hvc: replace BUG_ON() with negative return value
+    - Linux 5.4.163
+  * net/mlx5e: EPERM on vlan 0 programming (LP: #1957753)
+    - net/mlx5e: Unblock setting vid 0 for VF in case PF isn't eswitch manager
+  * CVE-2021-4083
+    - fget: check that the fd still exists after getting a ref to it
+  * CVE-2021-4155
+    - xfs: map unwritten blocks in XFS_IOC_{ALLOC, FREE}SP just like fallocate
+
+  [ Ubuntu: 5.4.0-99.112 ]
+
+  * focal/linux: 5.4.0-99.112 -proposed tracker (LP: #1959817)
+  * linux-image-5.4.0-97.110 freezes by accessing cifs shares (LP: #1959665)
+    - Revert "cifs: To match file servers, make sure the server hostname matches"
+    - Revert "cifs: set a minimum of 120s for next dns resolution"
+    - Revert "cifs: use the expiry output of dns_query to schedule next
+      resolution"
+
+  [ Ubuntu: 5.4.0-97.110 ]
+
+  * icmp_redirect from selftests fails on F/kvm (unary operator expected)
+    (LP: #1938964)
+    - selftests: icmp_redirect: pass xfail=0 to log_test()
+  * Focal: CIFS stable updates (LP: #1954926)
+    - cifs: use the expiry output of dns_query to schedule next resolution
+    - cifs: set a minimum of 120s for next dns resolution
+    - cifs: To match file servers, make sure the server hostname matches
+  * seccomp_bpf in seccomp from ubuntu_kernel_selftests failed to build on B-5.4
+    (LP: #1896420)
+    - SAUCE: selftests/seccomp: fix "storage size of 'md' isn't known" build issue
+    - SAUCE: selftests/seccomp: Fix s390x regs not defined issue
+  * system crash when removing ipmi_msghandler module (LP: #1950666)
+    - ipmi: Move remove_work to dedicated workqueue
+    - ipmi: msghandler: Make symbol 'remove_work_wq' static
+  * zcrypt DD: Toleration for new IBM Z Crypto Hardware - (Backport to Ubuntu
+    20.04) (LP: #1954680)
+    - s390/AP: support new dynamic AP bus size limit
+  * [UBUNTU 20.04] KVM hardware diagnose data improvements for guest kernel -
+    kernel part (LP: #1953334)
+    - s390/setup: diag 318: refactor struct
+    - s390/kvm: diagnose 0x318 sync and reset
+    - KVM: s390: remove diag318 reset code
+    - KVM: s390: add debug statement for diag 318 CPNC data
+  * Updates to ib_peer_memory requested by Nvidia (LP: #1947206)
+    - SAUCE: RDMA/core: Updated ib_peer_memory
+  * Include Infiniband Peer Memory interface (LP: #1923104)
+    - IB: Allow calls to ib_umem_get from kernel ULPs
+    - SAUCE: RDMA/core: Introduce peer memory interface
+  * Focal update: v5.4.162 upstream stable release (LP: #1954834)
+    - arm64: zynqmp: Do not duplicate flash partition label property
+    - arm64: zynqmp: Fix serial compatible string
+    - ARM: dts: NSP: Fix mpcore, mmc node names
+    - scsi: lpfc: Fix list_add() corruption in lpfc_drain_txq()
+    - arm64: dts: hisilicon: fix arm,sp805 compatible string
+    - RDMA/bnxt_re: Check if the vlan is valid before reporting
+    - usb: musb: tusb6010: check return value after calling
+      platform_get_resource()
+    - usb: typec: tipd: Remove WARN_ON in tps6598x_block_read
+    - arm64: dts: qcom: msm8998: Fix CPU/L2 idle state latency and residency
+    - arm64: dts: freescale: fix arm,sp805 compatible string
+    - ASoC: SOF: Intel: hda-dai: fix potential locking issue
+    - clk: imx: imx6ul: Move csi_sel mux to correct base register
+    - ASoC: nau8824: Add DMI quirk mechanism for active-high jack-detect
+    - scsi: advansys: Fix kernel pointer leak
+    - firmware_loader: fix pre-allocated buf built-in firmware use
+    - ARM: dts: omap: fix gpmc,mux-add-data type
+    - usb: host: ohci-tmio: check return value after calling
+      platform_get_resource()
+    - ARM: dts: ls1021a: move thermal-zones node out of soc/
+    - ARM: dts: ls1021a-tsn: use generic "jedec,spi-nor" compatible for flash
+    - ALSA: ISA: not for M68K
+    - tty: tty_buffer: Fix the softlockup issue in flush_to_ldisc
+    - MIPS: sni: Fix the build
+    - scsi: target: Fix ordered tag handling
+    - scsi: target: Fix alua_tg_pt_gps_count tracking
+    - iio: imu: st_lsm6dsx: Avoid potential array overflow in st_lsm6dsx_set_odr()
+    - powerpc/5200: dts: fix memory node unit name
+    - ALSA: gus: fix null pointer dereference on pointer block
+    - powerpc/dcr: Use cmplwi instead of 3-argument cmpli
+    - sh: check return code of request_irq
+    - maple: fix wrong return value of maple_bus_init().
+    - f2fs: fix up f2fs_lookup tracepoints
+    - sh: fix kconfig unmet dependency warning for FRAME_POINTER
+    - sh: math-emu: drop unused functions
+    - sh: define __BIG_ENDIAN for math-emu
+    - clk: ingenic: Fix bugs with divided dividers
+    - clk/ast2600: Fix soc revision for AHB
+    - clk: qcom: gcc-msm8996: Drop (again) gcc_aggre1_pnoc_ahb_clk
+    - mips: BCM63XX: ensure that CPU_SUPPORTS_32BIT_KERNEL is set
+    - sched/core: Mitigate race cpus_share_cache()/update_top_cache_domain()
+    - tracing: Save normal string variables
+    - tracing/histogram: Do not copy the fixed-size char array field over the
+      field size
+    - RDMA/netlink: Add __maybe_unused to static inline in C file
+    - perf bpf: Avoid memory leak from perf_env__insert_btf()
+    - perf bench futex: Fix memory leak of perf_cpu_map__new()
+    - perf tests: Remove bash construct from record+zstd_comp_decomp.sh
+    - net: bnx2x: fix variable dereferenced before check
+    - iavf: check for null in iavf_fix_features
+    - iavf: free q_vectors before queues in iavf_disable_vf
+    - iavf: Fix failure to exit out from last all-multicast mode
+    - iavf: prevent accidental free of filter structure
+    - iavf: validate pointers
+    - iavf: Fix for the false positive ASQ/ARQ errors while issuing VF reset
+    - MIPS: generic/yamon-dt: fix uninitialized variable error
+    - mips: bcm63xx: add support for clk_get_parent()
+    - mips: lantiq: add support for clk_get_parent()
+    - platform/x86: hp_accel: Fix an error handling path in 'lis3lv02d_probe()'
+    - scsi: core: sysfs: Fix hang when device state is set via sysfs
+    - net: sched: act_mirred: drop dst for the direction from egress to ingress
+    - net: dpaa2-eth: fix use-after-free in dpaa2_eth_remove
+    - net: virtio_net_hdr_to_skb: count transport header in UFO
+    - i40e: Fix correct max_pkt_size on VF RX queue
+    - i40e: Fix NULL ptr dereference on VSI filter sync
+    - i40e: Fix changing previously set num_queue_pairs for PFs
+    - i40e: Fix ping is lost after configuring ADq on VF
+    - i40e: Fix creation of first queue by omitting it if is not power of two
+    - i40e: Fix display error code in dmesg
+    - NFC: reorganize the functions in nci_request
+    - drm/nouveau: hdmigv100.c: fix corrupted HDMI Vendor InfoFrame
+    - NFC: reorder the logic in nfc_{un,}register_device
+    - KVM: PPC: Book3S HV: Use GLOBAL_TOC for kvmppc_h_set_dabr/xdabr()
+    - perf/x86/intel/uncore: Fix filter_tid mask for CHA events on Skylake Server
+    - perf/x86/intel/uncore: Fix IIO event constraints for Skylake Server
+    - s390/kexec: fix return code handling
+    - arm64: vdso32: suppress error message for 'make mrproper'
+    - tun: fix bonding active backup with arp monitoring
+    - hexagon: export raw I/O routines for modules
+    - ipc: WARN if trying to remove ipc object which is absent
+    - mm: kmemleak: slob: respect SLAB_NOLEAKTRACE flag
+    - x86/hyperv: Fix NULL deref in set_hv_tscchange_cb() if Hyper-V setup fails
+    - s390/kexec: fix memory leak of ipl report buffer
+    - udf: Fix crash after seekdir
+    - btrfs: fix memory ordering between normal and ordered work functions
+    - parisc/sticon: fix reverse colors
+    - cfg80211: call cfg80211_stop_ap when switch from P2P_GO type
+    - drm/udl: fix control-message timeout
+    - drm/nouveau: use drm_dev_unplug() during device removal
+    - drm/i915/dp: Ensure sink rate values are always valid
+    - drm/amdgpu: fix set scaling mode Full/Full aspect/Center not works on vga
+      and dvi connectors
+    - Revert "net: mvpp2: disable force link UP during port init procedure"
+    - perf/core: Avoid put_page() when GUP fails
+    - batman-adv: Consider fragmentation for needed_headroom
+    - batman-adv: Reserve needed_*room for fragments
+    - batman-adv: Don't always reallocate the fragmentation skb head
+    - ASoC: DAPM: Cover regression by kctl change notification fix
+    - usb: max-3421: Use driver data instead of maintaining a list of bound
+      devices
+    - ice: Delete always true check of PF pointer
+    - ALSA: hda: hdac_ext_stream: fix potential locking issues
+    - ALSA: hda: hdac_stream: fix potential locking issue in
+      snd_hdac_stream_assign()
+    - Linux 5.4.162
+  * Focal update: v5.4.161 upstream stable release (LP: #1954828)
+    - scsi: ufs: Fix interrupt error message for shared interrupts
+    - MIPS: Fix assembly error from MIPSr2 code used within MIPS_ISA_ARCH_LEVEL
+    - ext4: fix lazy initialization next schedule time computation in more
+      granular unit
+    - scsi: ufs: Fix tm request when non-fatal error happens
+    - fortify: Explicitly disable Clang support
+    - parisc/entry: fix trace test in syscall exit path
+    - PCI/MSI: Destroy sysfs before freeing entries
+    - PCI/MSI: Deal with devices lying about their MSI mask capability
+    - PCI: Add MSI masking quirk for Nvidia ION AHCI
+    - erofs: remove the occupied parameter from z_erofs_pagevec_enqueue()
+    - erofs: fix unsafe pagevec reuse of hooked pclusters
+    - Linux 5.4.161
+  * Focal update: v5.4.160 upstream stable release (LP: #1953387)
+    - xhci: Fix USB 3.1 enumeration issues by increasing roothub power-on-good
+      delay
+    - usb: xhci: Enable runtime-pm by default on AMD Yellow Carp platform
+    - binder: use euid from cred instead of using task
+    - binder: use cred instead of task for selinux checks
+    - binder: use cred instead of task for getsecid
+    - Input: iforce - fix control-message timeout
+    - Input: elantench - fix misreporting trackpoint coordinates
+    - Input: i8042 - Add quirk for Fujitsu Lifebook T725
+    - libata: fix read log timeout value
+    - ocfs2: fix data corruption on truncate
+    - scsi: qla2xxx: Fix kernel crash when accessing port_speed sysfs file
+    - scsi: qla2xxx: Fix use after free in eh_abort path
+    - mmc: dw_mmc: Dont wait for DRTO on Write RSP error
+    - parisc: Fix ptrace check on syscall return
+    - tpm: Check for integer overflow in tpm2_map_response_body()
+    - firmware/psci: fix application of sizeof to pointer
+    - crypto: s5p-sss - Add error handling in s5p_aes_probe()
+    - media: ite-cir: IR receiver stop working after receive overflow
+    - media: ir-kbd-i2c: improve responsiveness of hauppauge zilog receivers
+    - media: v4l2-ioctl: Fix check_ext_ctrls
+    - ALSA: hda/realtek: Add quirk for Clevo PC70HS
+    - ALSA: hda/realtek: Add a quirk for Acer Spin SP513-54N
+    - ALSA: hda/realtek: Add quirk for ASUS UX550VE
+    - ALSA: hda/realtek: Add quirk for HP EliteBook 840 G7 mute LED
+    - ALSA: ua101: fix division by zero at probe
+    - ALSA: 6fire: fix control and bulk message timeouts
+    - ALSA: line6: fix control and interrupt message timeouts
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 400
+    - ALSA: synth: missing check for possible NULL after the call to kstrdup
+    - ALSA: timer: Fix use-after-free problem
+    - ALSA: timer: Unconditionally unlink slave instances, too
+    - fuse: fix page stealing
+    - x86/sme: Use #define USE_EARLY_PGTABLE_L5 in mem_encrypt_identity.c
+    - x86/cpu: Fix migration safety with X86_BUG_NULL_SEL
+    - x86/irq: Ensure PI wakeup handler is unregistered before module unload
+    - cavium: Return negative value when pci_alloc_irq_vectors() fails
+    - scsi: qla2xxx: Return -ENOMEM if kzalloc() fails
+    - scsi: qla2xxx: Fix unmap of already freed sgl
+    - cavium: Fix return values of the probe function
+    - sfc: Don't use netif_info before net_device setup
+    - hyperv/vmbus: include linux/bitops.h
+    - ARM: dts: sun7i: A20-olinuxino-lime2: Fix ethernet phy-mode
+    - reset: socfpga: add empty driver allowing consumers to probe
+    - mmc: winbond: don't build on M68K
+    - drm: panel-orientation-quirks: Add quirk for Aya Neo 2021
+    - bpf: Define bpf_jit_alloc_exec_limit for arm64 JIT
+    - bpf: Prevent increasing bpf_jit_limit above max
+    - xen/netfront: stop tx queues during live migration
+    - nvmet-tcp: fix a memory leak when releasing a queue
+    - spi: spl022: fix Microwire full duplex mode
+    - net: multicast: calculate csum of looped-back and forwarded packets
+    - watchdog: Fix OMAP watchdog early handling
+    - drm: panel-orientation-quirks: Add quirk for GPD Win3
+    - nvmet-tcp: fix header digest verification
+    - r8169: Add device 10ec:8162 to driver r8169
+    - vmxnet3: do not stop tx queues after netif_device_detach()
+    - nfp: bpf: relax prog rejection for mtu check through max_pkt_offset
+    - net/smc: Correct spelling mistake to TCPF_SYN_RECV
+    - btrfs: clear MISSING device status bit in btrfs_close_one_device
+    - btrfs: fix lost error handling when replaying directory deletes
+    - btrfs: call btrfs_check_rw_degradable only if there is a missing device
+    - ia64: kprobes: Fix to pass correct trampoline address to the handler
+    - hwmon: (pmbus/lm25066) Add offset coefficients
+    - regulator: s5m8767: do not use reset value as DVS voltage if GPIO DVS is
+      disabled
+    - regulator: dt-bindings: samsung,s5m8767: correct s5m8767,pmic-buck-default-
+      dvs-idx property
+    - EDAC/sb_edac: Fix top-of-high-memory value for Broadwell/Haswell
+    - mwifiex: fix division by zero in fw download path
+    - ath6kl: fix division by zero in send path
+    - ath6kl: fix control-message timeout
+    - ath10k: fix control-message timeout
+    - ath10k: fix division by zero in send path
+    - PCI: Mark Atheros QCA6174 to avoid bus reset
+    - rtl8187: fix control-message timeouts
+    - evm: mark evm_fixmode as __ro_after_init
+    - wcn36xx: Fix HT40 capability for 2Ghz band
+    - mwifiex: Read a PCI register after writing the TX ring write pointer
+    - libata: fix checking of DMA state
+    - wcn36xx: handle connection loss indication
+    - rsi: fix occasional initialisation failure with BT coex
+    - rsi: fix key enabled check causing unwanted encryption for vap_id > 0
+    - rsi: fix rate mask set leading to P2P failure
+    - rsi: Fix module dev_oper_mode parameter description
+    - RDMA/qedr: Fix NULL deref for query_qp on the GSI QP
+    - signal: Remove the bogus sigkill_pending in ptrace_stop
+    - signal/mips: Update (_save|_restore)_fp_context to fail with -EFAULT
+    - power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
+    - power: supply: max17042_battery: use VFSOC for capacity when no rsns
+    - KVM: nVMX: Query current VMCS when determining if MSR bitmaps are in use
+    - can: j1939: j1939_tp_cmd_recv(): ignore abort message in the BAM transport
+    - can: j1939: j1939_can_recv(): ignore messages with invalid source address
+    - powerpc/85xx: Fix oops when mpc85xx_smp_guts_ids node cannot be found
+    - serial: core: Fix initializing and restoring termios speed
+    - ALSA: mixer: oss: Fix racy access to slots
+    - ALSA: mixer: fix deadlock in snd_mixer_oss_set_volume
+    - xen/balloon: add late_initcall_sync() for initial ballooning done
+    - PCI: pci-bridge-emul: Fix emulation of W1C bits
+    - PCI: aardvark: Do not clear status bits of masked interrupts
+    - PCI: aardvark: Fix checking for link up via LTSSM state
+    - PCI: aardvark: Do not unmask unused interrupts
+    - PCI: aardvark: Fix reporting Data Link Layer Link Active
+    - PCI: aardvark: Fix return value of MSI domain .alloc() method
+    - PCI: aardvark: Read all 16-bits from PCIE_MSI_PAYLOAD_REG
+    - quota: check block number when reading the block in quota file
+    - quota: correct error number in free_dqentry()
+    - pinctrl: core: fix possible memory leak in pinctrl_enable()
+    - iio: dac: ad5446: Fix ad5622_write() return value
+    - USB: serial: keyspan: fix memleak on probe errors
+    - USB: iowarrior: fix control-message timeouts
+    - USB: chipidea: fix interrupt deadlock
+    - dma-buf: WARN on dmabuf release with pending attachments
+    - drm: panel-orientation-quirks: Update the Lenovo Ideapad D330 quirk (v2)
+    - drm: panel-orientation-quirks: Add quirk for KD Kurio Smart C15200 2-in-1
+    - drm: panel-orientation-quirks: Add quirk for the Samsung Galaxy Book 10.6
+    - Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg()
+    - Bluetooth: fix use-after-free error in lock_sock_nested()
+    - drm/panel-orientation-quirks: add Valve Steam Deck
+    - platform/x86: wmi: do not fail if disabling fails
+    - MIPS: lantiq: dma: add small delay after reset
+    - MIPS: lantiq: dma: reset correct number of channel
+    - locking/lockdep: Avoid RCU-induced noinstr fail
+    - net: sched: update default qdisc visibility after Tx queue cnt changes
+    - smackfs: Fix use-after-free in netlbl_catmap_walk()
+    - x86: Increase exception stack sizes
+    - mwifiex: Run SET_BSS_MODE when changing from P2P to STATION vif-type
+    - mwifiex: Properly initialize private structure on interface type changes
+    - ath10k: high latency fixes for beacon buffer
+    - media: mt9p031: Fix corrupted frame after restarting stream
+    - media: netup_unidvb: handle interrupt properly according to the firmware
+    - media: stm32: Potential NULL pointer dereference in dcmi_irq_thread()
+    - media: uvcvideo: Set capability in s_param
+    - media: uvcvideo: Return -EIO for control errors
+    - media: uvcvideo: Set unique vdev name based in type
+    - media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe()
+    - media: s5p-mfc: Add checking to s5p_mfc_probe().
+    - media: imx: set a media_device bus_info string
+    - media: mceusb: return without resubmitting URB in case of -EPROTO error.
+    - ia64: don't do IA64_CMPXCHG_DEBUG without CONFIG_PRINTK
+    - brcmfmac: Add DMI nvram filename quirk for Cyberbook T116 tablet
+    - media: rcar-csi2: Add checking to rcsi2_start_receiver()
+    - ipmi: Disable some operations during a panic
+    - ACPICA: Avoid evaluating methods too early during system resume
+    - media: ipu3-imgu: imgu_fmt: Handle properly try
+    - media: ipu3-imgu: VIDIOC_QUERYCAP: Fix bus_info
+    - media: usb: dvd-usb: fix uninit-value bug in dibusb_read_eeprom_byte()
+    - net-sysfs: try not to restart the syscall if it will fail eventually
+    - tracefs: Have tracefs directories not set OTH permission bits by default
+    - ath: dfs_pattern_detector: Fix possible null-pointer dereference in
+      channel_detector_create()
+    - iov_iter: Fix iov_iter_get_pages{,_alloc} page fault return value
+    - ACPI: battery: Accept charges over the design capacity as full
+    - leaking_addresses: Always print a trailing newline
+    - memstick: r592: Fix a UAF bug when removing the driver
+    - lib/xz: Avoid overlapping memcpy() with invalid input with in-place
+      decompression
+    - lib/xz: Validate the value before assigning it to an enum variable
+    - workqueue: make sysfs of unbound kworker cpumask more clever
+    - tracing/cfi: Fix cmp_entries_* functions signature mismatch
+    - mwl8k: Fix use-after-free in mwl8k_fw_state_machine()
+    - block: remove inaccurate requeue check
+    - nvmet: fix use-after-free when a port is removed
+    - nvmet-tcp: fix use-after-free when a port is removed
+    - nvme: drop scan_lock and always kick requeue list when removing namespaces
+    - PM: hibernate: Get block device exclusively in swsusp_check()
+    - selftests: kvm: fix mismatched fclose() after popen()
+    - iwlwifi: mvm: disable RX-diversity in powersave
+    - smackfs: use __GFP_NOFAIL for smk_cipso_doi()
+    - ARM: clang: Do not rely on lr register for stacktrace
+    - gre/sit: Don't generate link-local addr if addr_gen_mode is
+      IN6_ADDR_GEN_MODE_NONE
+    - ARM: 9136/1: ARMv7-M uses BE-8, not BE-32
+    - vrf: run conntrack only in context of lower/physdev for locally generated
+      packets
+    - net: annotate data-race in neigh_output()
+    - btrfs: do not take the uuid_mutex in btrfs_rm_device
+    - spi: bcm-qspi: Fix missing clk_disable_unprepare() on error in
+      bcm_qspi_probe()
+    - x86/hyperv: Protect set_hv_tscchange_cb() against getting preempted
+    - parisc: fix warning in flush_tlb_all
+    - task_stack: Fix end_of_stack() for architectures with upwards-growing stack
+    - parisc/unwind: fix unwinder when CONFIG_64BIT is enabled
+    - parisc/kgdb: add kgdb_roundup() to make kgdb work with idle polling
+    - netfilter: conntrack: set on IPS_ASSURED if flows enters internal stream
+      state
+    - selftests/bpf: Fix strobemeta selftest regression
+    - Bluetooth: fix init and cleanup of sco_conn.timeout_work
+    - rcu: Fix existing exp request check in sync_sched_exp_online_cleanup()
+    - drm/v3d: fix wait for TMU write combiner flush
+    - virtio-gpu: fix possible memory allocation failure
+    - net: net_namespace: Fix undefined member in key_remove_domain()
+    - cgroup: Make rebind_subsystems() disable v2 controllers all at once
+    - wilc1000: fix possible memory leak in cfg_scan_result()
+    - Bluetooth: btmtkuart: fix a memleak in mtk_hci_wmt_sync
+    - crypto: caam - disable pkc for non-E SoCs
+    - rxrpc: Fix _usecs_to_jiffies() by using usecs_to_jiffies()
+    - net: dsa: rtl8366rb: Fix off-by-one bug
+    - ath10k: Fix missing frame timestamp for beacon/probe-resp
+    - drm/amdgpu: fix warning for overflow check
+    - media: em28xx: add missing em28xx_close_extension
+    - media: cxd2880-spi: Fix a null pointer dereference on error handling path
+    - media: dvb-usb: fix ununit-value in az6027_rc_query
+    - media: TDA1997x: handle short reads of hdmi info frame.
+    - media: mtk-vpu: Fix a resource leak in the error handling path of
+      'mtk_vpu_probe()'
+    - media: radio-wl1273: Avoid card name truncation
+    - media: si470x: Avoid card name truncation
+    - media: tm6000: Avoid card name truncation
+    - media: cx23885: Fix snd_card_free call on null card pointer
+    - kprobes: Do not use local variable when creating debugfs file
+    - crypto: ecc - fix CRYPTO_DEFAULT_RNG dependency
+    - cpuidle: Fix kobject memory leaks in error paths
+    - media: em28xx: Don't use ops->suspend if it is NULL
+    - ath9k: Fix potential interrupt storm on queue reset
+    - EDAC/amd64: Handle three rank interleaving mode
+    - netfilter: nft_dynset: relax superfluous check on set updates
+    - media: dvb-frontends: mn88443x: Handle errors of clk_prepare_enable()
+    - crypto: qat - detect PFVF collision after ACK
+    - crypto: qat - disregard spurious PFVF interrupts
+    - hwrng: mtk - Force runtime pm ops for sleep ops
+    - b43legacy: fix a lower bounds test
+    - b43: fix a lower bounds test
+    - mmc: sdhci-omap: Fix NULL pointer exception if regulator is not configured
+    - memstick: avoid out-of-range warning
+    - memstick: jmb38x_ms: use appropriate free function in jmb38x_ms_alloc_host()
+    - net, neigh: Fix NTF_EXT_LEARNED in combination with NTF_USE
+    - hwmon: Fix possible memleak in __hwmon_device_register()
+    - hwmon: (pmbus/lm25066) Let compiler determine outer dimension of
+      lm25066_coeff
+    - ath10k: fix max antenna gain unit
+    - drm/msm: uninitialized variable in msm_gem_import()
+    - net: stream: don't purge sk_error_queue in sk_stream_kill_queues()
+    - mmc: mxs-mmc: disable regulator on error and in the remove function
+    - block: ataflop: fix breakage introduced at blk-mq refactoring
+    - platform/x86: thinkpad_acpi: Fix bitwise vs. logical warning
+    - mt76: mt76x02: fix endianness warnings in mt76x02_mac.c
+    - rsi: stop thread firstly in rsi_91x_init() error handling
+    - mwifiex: Send DELBA requests according to spec
+    - phy: micrel: ksz8041nl: do not use power down mode
+    - nvme-rdma: fix error code in nvme_rdma_setup_ctrl
+    - PM: hibernate: fix sparse warnings
+    - clocksource/drivers/timer-ti-dm: Select TIMER_OF
+    - drm/msm: Fix potential NULL dereference in DPU SSPP
+    - smackfs: use netlbl_cfg_cipsov4_del() for deleting cipso_v4_doi
+    - libbpf: Fix BTF data layout checks and allow empty BTF
+    - s390/gmap: don't unconditionally call pte_unmap_unlock() in __gmap_zap()
+    - irq: mips: avoid nested irq_enter()
+    - tcp: don't free a FIN sk_buff in tcp_remove_empty_skb()
+    - samples/kretprobes: Fix return value if register_kretprobe() failed
+    - KVM: s390: Fix handle_sske page fault handling
+    - libertas_tf: Fix possible memory leak in probe and disconnect
+    - libertas: Fix possible memory leak in probe and disconnect
+    - wcn36xx: add proper DMA memory barriers in rx path
+    - drm/amdgpu/gmc6: fix DMA mask from 44 to 40 bits
+    - net: amd-xgbe: Toggle PLL settings during rate change
+    - net: phylink: avoid mvneta warning when setting pause parameters
+    - crypto: pcrypt - Delay write to padata->info
+    - selftests/bpf: Fix fclose/pclose mismatch in test_progs
+    - udp6: allow SO_MARK ctrl msg to affect routing
+    - ibmvnic: don't stop queue in xmit
+    - ibmvnic: Process crqs after enabling interrupts
+    - RDMA/rxe: Fix wrong port_cap_flags
+    - clk: mvebu: ap-cpu-clk: Fix a memory leak in error handling paths
+    - ARM: s3c: irq-s3c24xx: Fix return value check for s3c24xx_init_intc()
+    - arm64: dts: rockchip: Fix GPU register width for RK3328
+    - ARM: dts: qcom: msm8974: Add xo_board reference clock to DSI0 PHY
+    - RDMA/bnxt_re: Fix query SRQ failure
+    - arm64: dts: meson-g12a: Fix the pwm regulator supply properties
+    - ARM: dts: at91: tse850: the emac<->phy interface is rmii
+    - scsi: dc395: Fix error case unwinding
+    - MIPS: loongson64: make CPU_LOONGSON64 depends on MIPS_FP_SUPPORT
+    - JFS: fix memleak in jfs_mount
+    - ALSA: hda: Reduce udelay() at SKL+ position reporting
+    - arm: dts: omap3-gta04a4: accelerometer irq fix
+    - soc/tegra: Fix an error handling path in tegra_powergate_power_up()
+    - memory: fsl_ifc: fix leak of irq and nand_irq in fsl_ifc_ctrl_probe
+    - clk: at91: check pmc node status before registering syscore ops
+    - video: fbdev: chipsfb: use memset_io() instead of memset()
+    - serial: 8250_dw: Drop wrong use of ACPI_PTR()
+    - usb: gadget: hid: fix error code in do_config()
+    - power: supply: rt5033_battery: Change voltage values to µV
+    - scsi: csiostor: Uninitialized data in csio_ln_vnp_read_cbfn()
+    - RDMA/mlx4: Return missed an error if device doesn't support steering
+    - staging: ks7010: select CRYPTO_HASH/CRYPTO_MICHAEL_MIC
+    - ARM: dts: stm32: fix SAI sub nodes register range
+    - ASoC: cs42l42: Correct some register default values
+    - ASoC: cs42l42: Defer probe if request_threaded_irq() returns EPROBE_DEFER
+    - phy: qcom-qusb2: Fix a memory leak on probe
+    - serial: xilinx_uartps: Fix race condition causing stuck TX
+    - HID: u2fzero: clarify error check and length calculations
+    - HID: u2fzero: properly handle timeouts in usb_submit_urb
+    - powerpc/44x/fsp2: add missing of_node_put
+    - mips: cm: Convert to bitfield API to fix out-of-bounds access
+    - power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
+    - apparmor: fix error check
+    - rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined
+    - pnfs/flexfiles: Fix misplaced barrier in nfs4_ff_layout_prepare_ds
+    - drm/plane-helper: fix uninitialized variable reference
+    - PCI: aardvark: Don't spam about PIO Response Status
+    - PCI: aardvark: Fix preserving PCI_EXP_RTCTL_CRSSVE flag on emulated bridge
+    - opp: Fix return in _opp_add_static_v2()
+    - NFS: Fix deadlocks in nfs_scan_commit_list()
+    - fs: orangefs: fix error return code of orangefs_revalidate_lookup()
+    - mtd: spi-nor: hisi-sfc: Remove excessive clk_disable_unprepare()
+    - mtd: core: don't remove debugfs directory if device is in use
+    - dmaengine: at_xdmac: fix AT_XDMAC_CC_PERID() macro
+    - auxdisplay: img-ascii-lcd: Fix lock-up when displaying empty string
+    - auxdisplay: ht16k33: Connect backlight to fbdev
+    - auxdisplay: ht16k33: Fix frame buffer device blanking
+    - soc: fsl: dpaa2-console: free buffer before returning from
+      dpaa2_console_read
+    - netfilter: nfnetlink_queue: fix OOB when mac header was cleared
+    - dmaengine: dmaengine_desc_callback_valid(): Check for `callback_result`
+    - signal/sh: Use force_sig(SIGKILL) instead of do_group_exit(SIGKILL)
+    - m68k: set a default value for MEMORY_RESERVE
+    - watchdog: f71808e_wdt: fix inaccurate report in WDIOC_GETTIMEOUT
+    - ar7: fix kernel builds for compiler test
+    - scsi: qla2xxx: Fix gnl list corruption
+    - scsi: qla2xxx: Turn off target reset during issue_lip
+    - NFSv4: Fix a regression in nfs_set_open_stateid_locked()
+    - i2c: xlr: Fix a resource leak in the error handling path of
+      'xlr_i2c_probe()'
+    - xen-pciback: Fix return in pm_ctrl_init()
+    - net: davinci_emac: Fix interrupt pacing disable
+    - net: vlan: fix a UAF in vlan_dev_real_dev()
+    - ACPI: PMIC: Fix intel_pmic_regs_handler() read accesses
+    - bonding: Fix a use-after-free problem when bond_sysfs_slave_add() failed
+    - mm/zsmalloc.c: close race window between zs_pool_dec_isolated() and
+      zs_unregister_migration()
+    - zram: off by one in read_block_state()
+    - perf bpf: Add missing free to bpf_event__print_bpf_prog_info()
+    - llc: fix out-of-bound array index in llc_sk_dev_hash()
+    - nfc: pn533: Fix double free when pn533_fill_fragment_skbs() fails
+    - arm64: pgtable: make __pte_to_phys/__phys_to_pte_val inline functions
+    - bpf: sockmap, strparser, and tls are reusing qdisc_skb_cb and colliding
+    - net/sched: sch_taprio: fix undefined behavior in ktime_mono_to_any
+    - net: hns3: allow configure ETS bandwidth of all TCs
+    - vsock: prevent unnecessary refcnt inc for nonblocking connect
+    - net/smc: fix sk_refcnt underflow on linkdown and fallback
+    - cxgb4: fix eeprom len when diagnostics not implemented
+    - selftests/net: udpgso_bench_rx: fix port argument
+    - ARM: 9155/1: fix early early_iounmap()
+    - ARM: 9156/1: drop cc-option fallbacks for architecture selection
+    - parisc: Fix set_fixmap() on PA1.x CPUs
+    - irqchip/sifive-plic: Fixup EOI failed when masked
+    - f2fs: should use GFP_NOFS for directory inodes
+    - net, neigh: Enable state migration between NUD_PERMANENT and NTF_USE
+    - 9p/net: fix missing error check in p9_check_errors
+    - ovl: fix deadlock in splice write
+    - powerpc/lib: Add helper to check if offset is within conditional branch
+      range
+    - powerpc/bpf: Validate branch ranges
+    - powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
+    - powerpc/security: Add a helper to query stf_barrier type
+    - powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
+    - mm, oom: pagefault_out_of_memory: don't force global OOM for dying tasks
+    - mm, oom: do not trigger out_of_memory from the #PF
+    - video: backlight: Drop maximum brightness override for brightness zero
+    - s390/cio: check the subchannel validity for dev_busid
+    - s390/tape: fix timer initialization in tape_std_assign()
+    - s390/cio: make ccw_device_dma_* more robust
+    - powerpc/powernv/prd: Unregister OPAL_MSG_PRD2 notifier during module unload
+    - PCI: Add PCI_EXP_DEVCTL_PAYLOAD_* macros
+    - SUNRPC: Partial revert of commit 6f9f17287e78
+    - ath10k: fix invalid dma_addr_t token assignment
+    - selftests/bpf: Fix also no-alu32 strobemeta selftest
+    - Linux 5.4.160
+    - soc/tegra: pmc: Fix imbalanced clock disabling in error code path
+  * Focal update: v5.4.159 upstream stable release (LP: #1953071)
+    - Revert "x86/kvm: fix vcpu-id indexed array sizes"
+    - usb: ehci: handshake CMD_RUN instead of STS_HALT
+    - usb: gadget: Mark USB_FSL_QE broken on 64-bit
+    - usb: musb: Balance list entry in musb_gadget_queue
+    - usb-storage: Add compatibility quirk flags for iODD 2531/2541
+    - binder: don't detect sender/target during buffer cleanup
+    - printk/console: Allow to disable console output by using console="" or
+      console=null
+    - isofs: Fix out of bound access for corrupted isofs image
+    - comedi: dt9812: fix DMA buffers on stack
+    - comedi: ni_usb6501: fix NULL-deref in command paths
+    - comedi: vmk80xx: fix transfer-buffer overflows
+    - comedi: vmk80xx: fix bulk-buffer overflow
+    - comedi: vmk80xx: fix bulk and interrupt message timeouts
+    - staging: r8712u: fix control-message timeout
+    - staging: rtl8192u: fix control-message timeouts
+    - media: staging/intel-ipu3: css: Fix wrong size comparison imgu_css_fw_init
+    - rsi: fix control-message timeout
+    - Linux 5.4.159
+  * Focal update: v5.4.158 upstream stable release (LP: #1953066)
+    - scsi: core: Put LLD module refcnt after SCSI device is released
+    - vrf: Revert "Reset skb conntrack connection..."
+    - net: ethernet: microchip: lan743x: Fix skb allocation failure
+    - media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
+    - Revert "xhci: Set HCD flag to defer primary roothub registration"
+    - Revert "usb: core: hcd: Add support for deferring roothub registration"
+    - sfc: Fix reading non-legacy supported link modes
+    - ARM: 9120/1: Revert "amba: make use of -1 IRQs warn"
+    - Linux 5.4.158
+  * [Ubuntu 20.04] Problem leading IUCV service down (on s390x) (LP: #1913442)
+    - usercopy: mark dma-kmalloc caches as usercopy caches
+
+  [ Ubuntu: 5.4.0-96.109 ]
+
+  * Support builtin revoked certificates (LP: #1932029)
+    - [Config]: add i386 to CONFIG_SYSTEM_REVOCATION_KEYS annotation
+  * CVE-2022-0185
+    - SAUCE: vfs: Out-of-bounds write of heap buffer in fs_context.c
+    - SAUCE: vfs: test that one given mount param is not larger than PAGE_SIZE
+
+  [ Ubuntu: 5.4.0-94.106 ]
+
+  * focal/linux: 5.4.0-94.106 -proposed tracker (LP: #1956628)
+  * [Regression] Focal kernel  5.4.0-92.103 fails to boot when Secure Encrypted
+    Virtualization(SEV) is enabled (LP: #1956575)
+    - x86/ioremap: Map EFI-reserved memory as encrypted for SEV
+
+  [ Ubuntu: 5.4.0-92.103 ]
+
+  * focal/linux: 5.4.0-92.103 -proposed tracker (LP: #1952316)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync update-dkms-versions helper
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.29)
+  * CVE-2021-4002
+    - tlb: mmu_gather: add tlb_flush_*_range APIs
+    - hugetlbfs: flush TLBs correctly after huge_pmd_unshare
+  * Re-enable DEBUG_INFO_BTF where it was disabled (LP: #1945632)
+    - [Config] Enable CONFIG_DEBUG_INFO_BTF on all arches
+  * Focal linux-azure: Vm crash on Dv5/Ev5 (LP: #1950462)
+    - KVM: VMX: eVMCS: make evmcs_sanitize_exec_ctrls() work again
+    - jump_label: Fix usage in module __init
+  * Support builtin revoked certificates (LP: #1932029)
+    - Revert "UBUNTU: SAUCE: (lockdown) Make get_cert_list() not complain about
+      cert lists that aren't present."
+    - integrity: Move import of MokListRT certs to a separate routine
+    - integrity: Load certs from the EFI MOK config table
+    - certs: Add ability to preload revocation certs
+    - integrity: Load mokx variables into the blacklist keyring
+    - certs: add 'x509_revocation_list' to gitignore
+    - SAUCE: Dump stack when X.509 certificates cannot be loaded
+    - [Packaging] build canonical-revoked-certs.pem from branch/arch certs
+    - [Packaging] Revoke 2012 UEFI signing certificate as built-in
+    - [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679)
+    - efi: Support for MOK variable config table
+    - efi: mokvar-table: fix some issues in new code
+    - efi: mokvar: add missing include of asm/early_ioremap.h
+    - efi/mokvar: Reserve the table only if it is in boot services data
+    - SAUCE: integrity: add informational messages when revoking certs
+  * Support importing mokx keys into revocation list from the mok table
+    (LP: #1928679) // CVE-2020-26541 when certificates are revoked via
+    MokListXRT.
+    - SAUCE: integrity: Load mokx certs from the EFI MOK config table
+  * Focal update: v5.4.157 upstream stable release (LP: #1951883)
+    - ARM: 9133/1: mm: proc-macros: ensure *_tlb_fns are 4B aligned
+    - ARM: 9134/1: remove duplicate memcpy() definition
+    - ARM: 9139/1: kprobes: fix arch_init_kprobes() prototype
+    - ARM: 9141/1: only warn about XIP address when not compile testing
+    - ipv6: use siphash in rt6_exception_hash()
+    - ipv4: use siphash instead of Jenkins in fnhe_hashfun()
+    - usbnet: sanity check for maxpacket
+    - usbnet: fix error return code in usbnet_probe()
+    - Revert "pinctrl: bcm: ns: support updated DT binding as syscon subnode"
+    - ata: sata_mv: Fix the error handling of mv_chip_id()
+    - nfc: port100: fix using -ERRNO as command type mask
+    - net/tls: Fix flipped sign in tls_err_abort() calls
+    - mmc: vub300: fix control-message timeouts
+    - mmc: cqhci: clear HALT state after CQE enable
+    - mmc: dw_mmc: exynos: fix the finding clock sample value
+    - mmc: sdhci: Map more voltage level to SDHCI_POWER_330
+    - mmc: sdhci-esdhc-imx: clear the buffer_read_ready to reset standard tuning
+      circuit
+    - cfg80211: scan: fix RCU in cfg80211_add_nontrans_list()
+    - net: lan78xx: fix division by zero in send path
+    - tcp_bpf: Fix one concurrency problem in the tcp_bpf_send_verdict function
+    - IB/qib: Protect from buffer overflow in struct qib_user_sdma_pkt fields
+    - IB/hfi1: Fix abba locking issue with sc_disable()
+    - nvmet-tcp: fix data digest pointer calculation
+    - nvme-tcp: fix data digest pointer calculation
+    - RDMA/mlx5: Set user priority for DCT
+    - arm64: dts: allwinner: h5: NanoPI Neo 2: Fix ethernet node
+    - regmap: Fix possible double-free in regcache_rbtree_exit()
+    - net: batman-adv: fix error handling
+    - net: Prevent infinite while loop in skb_tx_hash()
+    - RDMA/sa_query: Use strscpy_pad instead of memcpy to copy a string
+    - nios2: Make NIOS2_DTB_SOURCE_BOOL depend on !COMPILE_TEST
+    - net: ethernet: microchip: lan743x: Fix driver crash when lan743x_pm_resume
+      fails
+    - net: ethernet: microchip: lan743x: Fix dma allocation failure by using
+      dma_set_mask_and_coherent
+    - net: nxp: lpc_eth.c: avoid hang when bringing interface down
+    - net/tls: Fix flipped sign in async_wait.err assignment
+    - phy: phy_ethtool_ksettings_get: Lock the phy for consistency
+    - phy: phy_start_aneg: Add an unlocked version
+    - sctp: use init_tag from inithdr for ABORT 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
+    - net: use netif_is_bridge_port() to check for IFF_BRIDGE_PORT
+    - cfg80211: correct bridge/4addr mode check
+    - KVM: s390: clear kicked_mask before sleeping again
+    - KVM: s390: preserve deliverable_mask in __airqs_kick_single_vcpu
+    - perf script: Check session->header.env.arch before using it
+    - Linux 5.4.157
+  * keyboard not working on Medion notebook s17 series (LP: #1950536)
+    - ACPI: resources: Add one more Medion model in IRQ override quirk
+  * creat09 from ubuntu_ltp_syscalls and cve-2018-13405 from ubuntu_ltp/cve
+    failed with XFS (LP: #1950239)
+    - xfs: ensure that the inode uid/gid match values match the icdinode ones
+    - xfs: merge the projid fields in struct xfs_icdinode
+    - xfs: remove the icdinode di_uid/di_gid members
+    - xfs: fix up non-directory creation in SGID directories
+  * reuseport_bpf_numa in net from ubuntu_kernel_selftests fails on ppc64le
+    (LP: #1867570)
+    - selftests/net: Fix reuseport_bpf_numa by skipping unavailable nodes
+  * Focal update: v5.4.156 upstream stable release (LP: #1951295)
+    - parisc: math-emu: Fix fall-through warnings
+    - net: switchdev: do not propagate bridge updates across bridges
+    - tee: optee: Fix missing devices unregister during optee_remove
+    - ARM: dts: at91: sama5d2_som1_ek: disable ISC node by default
+    - xtensa: xtfpga: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: xtfpga: Try software restart before simulating CPU reset
+    - NFSD: Keep existing listeners on portlist error
+    - dma-debug: fix sg checks in debug_dma_map_sg()
+    - ASoC: wm8960: Fix clock configuration on slave mode
+    - netfilter: ipvs: make global sysctl readonly in non-init netns
+    - lan78xx: select CRC32
+    - net: dsa: lantiq_gswip: fix register definition
+    - NIOS2: irqflags: rename a redefined register name
+    - net: hns3: reset DWRR of unused tc to zero
+    - net: hns3: add limit ets dwrr bandwidth cannot be 0
+    - net: hns3: disable sriov before unload hclge layer
+    - net: stmmac: Fix E2E delay mechanism
+    - net: enetc: fix ethtool counter name for PM0_TERR
+    - can: rcar_can: fix suspend/resume
+    - can: peak_usb: pcan_usb_fd_decode_status(): fix back to ERROR_ACTIVE state
+      notification
+    - can: peak_pci: peak_pci_remove(): fix UAF
+    - can: j1939: j1939_tp_rxtimer(): fix errant alert in j1939_tp_rxtimer
+    - can: j1939: j1939_netdev_start(): fix UAF for rx_kref of j1939_priv
+    - can: j1939: j1939_xtp_rx_dat_one(): cancel session if receive TP.DT with
+      error length
+    - can: j1939: j1939_xtp_rx_rts_session_new(): abort TP less than 9 bytes
+    - ceph: fix handling of "meta" errors
+    - ocfs2: fix data corruption after conversion from inline format
+    - ocfs2: mount fails with buffer overflow in strlen
+    - elfcore: correct reference to CONFIG_UML
+    - ALSA: usb-audio: Provide quirk for Sennheiser GSP670 Headset
+    - ALSA: hda/realtek: Add quirk for Clevo PC50HS
+    - ASoC: DAPM: Fix missing kctl change notifications
+    - audit: fix possible null-pointer dereference in audit_filter_rules
+    - powerpc64/idle: Fix SP offsets when saving GPRs
+    - KVM: PPC: Book3S HV: Fix stack handling in idle_kvm_start_guest()
+    - KVM: PPC: Book3S HV: Make idle_kvm_start_guest() return 0 if it went to
+      guest
+    - powerpc/idle: Don't corrupt back chain when going idle
+    - mm, slub: fix mismatch between reconstructed freelist depth and cnt
+    - mm, slub: fix potential memoryleak in kmem_cache_open()
+    - nfc: nci: fix the UAF of rf_conn_info object
+    - isdn: cpai: check ctr->cnr to avoid array index out of bound
+    - netfilter: Kconfig: use 'default y' instead of 'm' for bool config option
+    - selftests: netfilter: remove stray bash debug line
+    - gcc-plugins/structleak: add makefile var for disabling structleak
+    - btrfs: deal with errors when checking if a dir entry exists during log
+      replay
+    - net: stmmac: add support for dwmac 3.40a
+    - ARM: dts: spear3xx: Fix gmac node
+    - isdn: mISDN: Fix sleeping function called from invalid context
+    - platform/x86: intel_scu_ipc: Update timeout value in comment
+    - ALSA: hda: avoid write to STATESTS if controller is in reset
+    - Input: snvs_pwrkey - add clk handling
+    - scsi: core: Fix shost->cmd_per_lun calculation in scsi_add_host_with_dma()
+    - tracing: Have all levels of checks prevent recursion
+    - ARM: 9122/1: select HAVE_FUTEX_CMPXCHG
+    - pinctrl: stm32: use valid pin identifier in stm32_pinctrl_resume()
+    - Linux 5.4.156
+  * ubuntu_ltp / finit_module02 fails on v4.15 and other kernels
+    (LP: #1950644) // Focal update: v5.4.156 upstream stable release
+    (LP: #1951295)
+    - vfs: check fd has read access in kernel_read_file_from_fd()
+  * Focal update: v5.4.155 upstream stable release (LP: #1951291)
+    - ovl: simplify file splice
+    - ALSA: usb-audio: Add quirk for VF0770
+    - ALSA: seq: Fix a potential UAF by wrong private_free call order
+    - ALSA: hda/realtek: Complete partial device name to avoid ambiguity
+    - ALSA: hda/realtek: Add quirk for Clevo X170KM-G
+    - ALSA: hda/realtek - ALC236 headset MIC recording issue
+    - ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
+    - nds32/ftrace: Fix Error: invalid operands (*UND* and *UND* sections) for `^'
+    - s390: fix strrchr() implementation
+    - csky: don't let sigreturn play with priveleged bits of status register
+    - csky: Fixup regs.sr broken in ptrace
+    - btrfs: unlock newly allocated extent buffer after error
+    - btrfs: deal with errors when replaying dir entry during log replay
+    - btrfs: deal with errors when adding inode reference during log replay
+    - btrfs: check for error when looking up inode during dir entry replay
+    - watchdog: orion: use 0 for unset heartbeat
+    - x86/resctrl: Free the ctrlval arrays when domain_setup_mon_state() fails
+    - mei: me: add Ice Lake-N device id.
+    - xhci: guard accesses to ep_state in xhci_endpoint_reset()
+    - xhci: Fix command ring pointer corruption while aborting a command
+    - xhci: Enable trust tx length quirk for Fresco FL11 USB controller
+    - cb710: avoid NULL pointer subtraction
+    - efi/cper: use stack buffer for error record decoding
+    - efi: Change down_interruptible() in virt_efi_reset_system() to
+      down_trylock()
+    - usb: musb: dsps: Fix the probe error path
+    - Input: xpad - add support for another USB ID of Nacon GC-100
+    - USB: serial: qcserial: add EM9191 QDL support
+    - USB: serial: option: add Quectel EC200S-CN module support
+    - USB: serial: option: add Telit LE910Cx composition 0x1204
+    - USB: serial: option: add prod. id for Quectel EG91
+    - EDAC/armada-xp: Fix output of uncorrectable error counter
+    - nvmem: Fix shift-out-of-bound (UBSAN) with byte size cells
+    - x86/Kconfig: Do not enable AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT automatically
+    - powerpc/xive: Discard disabled interrupts in get_irqchip_state()
+    - iio: adc: aspeed: set driver data when adc probe.
+    - iio: adc128s052: Fix the error handling path of 'adc128_probe()'
+    - iio: mtk-auxadc: fix case IIO_CHAN_INFO_PROCESSED
+    - iio: light: opt3001: Fixed timeout error when 0 lux
+    - iio: ssp_sensors: add more range checking in ssp_parse_dataframe()
+    - iio: ssp_sensors: fix error code in ssp_print_mcu_debug()
+    - iio: dac: ti-dac5571: fix an error code in probe()
+    - sctp: account stream padding length for reconf chunk
+    - gpio: pca953x: Improve bias setting
+    - net: arc: select CRC32
+    - net: korina: select CRC32
+    - net/mlx5e: Mutually exclude RX-FCS and RX-port-timestamp
+    - net: stmmac: fix get_hw_feature() on old hardware
+    - net: encx24j600: check error in devm_regmap_init_encx24j600
+    - ethernet: s2io: fix setting mac address during resume
+    - nfc: fix error handling of nfc_proto_register()
+    - NFC: digital: fix possible memory leak in digital_tg_listen_mdaa()
+    - NFC: digital: fix possible memory leak in digital_in_send_sdd_req()
+    - pata_legacy: fix a couple uninitialized variable bugs
+    - ata: ahci_platform: fix null-ptr-deref in ahci_platform_enable_regulators()
+    - mlxsw: thermal: Fix out-of-bounds memory accesses
+    - platform/mellanox: mlxreg-io: Fix argument base in kstrtou32() call
+    - drm/panel: olimex-lcd-olinuxino: select CRC32
+    - drm/msm: Fix null pointer dereference on pointer edp
+    - drm/msm/dsi: Fix an error code in msm_dsi_modeset_init()
+    - drm/msm/dsi: fix off by one in dsi_bus_clk_enable error handling
+    - acpi/arm64: fix next_platform_timer() section mismatch error
+    - mqprio: Correct stats in mqprio_dump_class_stats().
+    - qed: Fix missing error code in qed_slowpath_start()
+    - r8152: select CRC32 and CRYPTO/CRYPTO_HASH/CRYPTO_SHA256
+    - ionic: don't remove netdev->dev_addr when syncing uc list
+    - Linux 5.4.155
+  * [UBUNTU 20.04] kernel:  unable to read partitions on virtio-block dasd (kvm)
+    (LP: #1950144) // Focal update: v5.4.155 upstream stable release
+    (LP: #1951291)
+    - virtio: write back F_VERSION_1 before validate
+  * Focal update: v5.4.154 upstream stable release (LP: #1951288)
+    - net: phy: bcm7xxx: Fixed indirect MMD operations
+    - ext4: correct the error path of ext4_write_inline_data_end()
+    - HID: apple: Fix logical maximum and usage maximum of Magic Keyboard JIS
+    - netfilter: ip6_tables: zero-initialize fragment offset
+    - HID: wacom: Add new Intuos BT (CTL-4100WL/CTL-6100WL) device IDs
+    - netfilter: nf_nat_masquerade: make async masq_inet6_event handling generic
+    - netfilter: nf_nat_masquerade: defer conntrack walk to work queue
+    - mac80211: Drop frames from invalid MAC address in ad-hoc mode
+    - m68k: Handle arrivals of multiple signals correctly
+    - net: prevent user from passing illegal stab size
+    - mac80211: check return value of rhashtable_init
+    - net: sun: SUNVNET_COMMON should depend on INET
+    - drm/amdgpu: fix gart.bo pin_count leak
+    - scsi: ses: Fix unsigned comparison with less than zero
+    - scsi: virtio_scsi: Fix spelling mistake "Unsupport" -> "Unsupported"
+    - sched: Always inline is_percpu_thread()
+    - Linux 5.4.154
+  * Focal update: v5.4.153 upstream stable release (LP: #1950014)
+    - Partially revert "usb: Kconfig: using select for USB_COMMON dependency"
+    - USB: cdc-acm: fix racy tty buffer accesses
+    - USB: cdc-acm: fix break reporting
+    - usb: typec: tcpm: handle SRC_STARTUP state if cc changes
+    - xen/privcmd: fix error handling in mmap-resource processing
+    - mmc: meson-gx: do not use memcpy_to/fromio for dram-access-quirk
+    - ovl: fix missing negative dentry check in ovl_rename()
+    - nfsd: fix error handling of register_pernet_subsys() in init_nfsd()
+    - nfsd4: Handle the NFSv4 READDIR 'dircount' hint being zero
+    - xen/balloon: fix cancelled balloon action
+    - ARM: dts: omap3430-sdp: Fix NAND device node
+    - ARM: dts: qcom: apq8064: use compatible which contains chipid
+    - MIPS: BPF: Restore MIPS32 cBPF JIT
+    - bpf, mips: Validate conditional branch offsets
+    - soc: qcom: socinfo: Fixed argument passed to platform_set_data()
+    - ARM: dts: qcom: apq8064: Use 27MHz PXO clock as DSI PLL reference
+    - soc: qcom: mdt_loader: Drop PT_LOAD check on hash segment
+    - ARM: dts: imx: Add missing pinctrl-names for panel on M53Menlo
+    - ARM: dts: imx: Fix USB host power regulator polarity on M53Menlo
+    - arm64: dts: qcom: pm8150: use qcom,pm8998-pon binding
+    - xtensa: move XCHAL_KIO_* definitions to kmem_layout.h
+    - xtensa: use CONFIG_USE_OF instead of CONFIG_OF
+    - xtensa: call irqchip_init only when CONFIG_USE_OF is selected
+    - bpf, arm: Fix register clobbering in div/mod implementation
+    - bpf: Fix integer overflow in prealloc_elems_and_freelist()
+    - phy: mdio: fix memory leak
+    - net_sched: fix NULL deref in fifo_set_limit()
+    - powerpc/fsl/dts: Fix phy-connection-type for fm1mac3
+    - ptp_pch: Load module automatically if ID matches
+    - arm64: dts: freescale: Fix SP805 clock-names
+    - arm64: dts: ls1028a: add missing CAN nodes
+    - ARM: imx6: disable the GIC CPU interface before calling stby-poweroff
+      sequence
+    - net: bridge: use nla_total_size_64bit() in br_get_linkxstats_size()
+    - net/sched: sch_taprio: properly cancel timer from taprio_destroy()
+    - net: sfp: Fix typo in state machine debug string
+    - netlink: annotate data races around nlk->bound
+    - bus: ti-sysc: Use CLKDM_NOAUTO for dra7 dcan1 for errata i893
+    - video: fbdev: gbefb: Only instantiate device when built for IP32
+    - drm/nouveau/debugfs: fix file release memory leak
+    - gve: Correct available tx qpl check
+    - rtnetlink: fix if_nlmsg_stats_size() under estimation
+    - gve: fix gve_get_stats()
+    - i40e: fix endless loop under rtnl
+    - i40e: Fix freeing of uninitialized misc IRQ vector
+    - net: prefer socket bound to interface when not in VRF
+    - i2c: acpi: fix resource leak in reconfiguration device addition
+    - bpf, s390: Fix potential memory leak about jit_data
+    - RISC-V: Include clone3() on rv32
+    - x86/platform/olpc: Correct ifdef symbol to intended CONFIG_OLPC_XO15_SCI
+    - x86/hpet: Use another crystalball to evaluate HPET usability
+    - x86/Kconfig: Correct reference to MWINCHIP3D
+    - Linux 5.4.153
+  * Focal update: v5.4.152 upstream stable release (LP: #1950009)
+    - net: mdio: introduce a shutdown method to mdio device drivers
+    - xen-netback: correct success/error reporting for the SKB-with-fraglist case
+    - sparc64: fix pci_iounmap() when CONFIG_PCI is not set
+    - ext2: fix sleeping in atomic bugs on error
+    - scsi: sd: Free scsi_disk device via put_device()
+    - usb: testusb: Fix for showing the connection speed
+    - usb: dwc2: check return value after calling platform_get_resource()
+    - selftests: be sure to make khdr before other targets
+    - selftests:kvm: fix get_warnings_count() ignoring fscanf() return warn
+    - scsi: ses: Retry failed Send/Receive Diagnostic commands
+    - tools/vm/page-types: remove dependency on opt_file for idle page tracking
+    - KVM: do not shrink halt_poll_ns below grow_start
+    - kvm: x86: Add AMD PMU MSRs to msrs_to_save_all[]
+    - perf/x86: Reset destroy callback on event init failure
+    - silence nfscache allocation warnings with kvzalloc
+    - libata: Add ATA_HORKAGE_NO_NCQ_ON_ATI for Samsung 860 and 870 SSD.
+    - Linux 5.4.152
+  * linux-aws: Fix backport of RDMA/efa: Expose maximum  TX doorbell batch
+    (LP: #1949882)
+    - SAUCE: aws: Fix backport of RDMA/efa: Expose maximum TX doorbell batch
+
+  [ Ubuntu: 5.4.0-91.102 ]
+
+  * focal/linux: 5.4.0-91.102 -proposed tracker (LP: #1949840)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] update Ubuntu.md
+    - debian/dkms-versions -- update from kernel-versions (main/2021.11.08)
+  * KVM emulation failure when booting into  VM crash kernel with multiple CPUs
+    (LP: #1948862)
+    - KVM: x86: Properly reset MMU context at vCPU RESET/INIT
+  * aufs: kernel bug with apparmor and fuseblk (LP: #1948470)
+    - SAUCE: aufs: bugfix, stop omitting path->mnt
+  * ebpf:  bpf_redirect fails with ip6 gre interfaces (LP: #1947164)
+    - net: handle ARPHRD_IP6GRE in dev_is_mac_header_xmit()
+  * require CAP_NET_ADMIN to attach N_HCI ldisc (LP: #1949516)
+    - Bluetooth: hci_ldisc: require CAP_NET_ADMIN to attach N_HCI ldisc
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161)
+    - ocfs2: fix remounting needed after setfacl command
+  * ppc64 BPF JIT mod by 1 will not return 0 (LP: #1948351)
+    - powerpc/bpf: Fix BPF_MOD when imm == 1
+  * Drop "UBUNTU: SAUCE: cachefiles: Page leaking in
+    cachefiles_read_backing_file while vmscan is active" (LP: #1947709)
+    - Revert "UBUNTU: SAUCE: cachefiles: Page leaking in
+      cachefiles_read_backing_file while vmscan is active"
+  * Reassign I/O Path of ConnectX-5 Port 1 before Port 2 causes NULL dereference
+    (LP: #1943464)
+    - s390/pci: fix leak of PCI device structure
+    - s390/pci: fix use after free of zpci_dev
+    - s390/pci: fix zpci_zdev_put() on reserve
+  * [SRU][F] USB: serial: pl2303: add support for PL2303HXN (LP: #1948377)
+    - USB: serial: pl2303: add support for PL2303HXN
+    - USB: serial: pl2303: fix line-speed handling on newer chips
+  * Focal update: v5.4.151 upstream stable release (LP: #1947888)
+    - tty: Fix out-of-bound vmalloc access in imageblit
+    - cpufreq: schedutil: Use kobject release() method to free sugov_tunables
+    - cpufreq: schedutil: Destroy mutex before kobject_put() frees the memory
+    - usb: cdns3: fix race condition before setting doorbell
+    - fs-verity: fix signed integer overflow with i_size near S64_MAX
+    - hwmon: (w83793) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83792d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - hwmon: (w83791d) Fix NULL pointer dereference by removing unnecessary
+      structure field
+    - scsi: ufs: Fix illegal offset in UPIU event trace
+    - mac80211: fix use-after-free in CCMP/GCMP RX
+    - x86/kvmclock: Move this_cpu_pvti into kvmclock.h
+    - drm/amd/display: Pass PCI deviceid into DC
+    - ipvs: check that ip_vs_conn_tab_bits is between 8 and 20
+    - hwmon: (mlxreg-fan) Return non-zero value when fan current state is enforced
+      from sysfs
+    - mac80211: Fix ieee80211_amsdu_aggregate frag_tail bug
+    - mac80211: limit injected vht mcs/nss in ieee80211_parse_tx_radiotap
+    - mac80211: mesh: fix potentially unaligned access
+    - mac80211-hwsim: fix late beacon hrtimer handling
+    - sctp: break out if skb_header_pointer returns NULL in sctp_rcv_ootb
+    - hwmon: (tmp421) report /PVLD condition as fault
+    - hwmon: (tmp421) fix rounding for negative values
+    - net: ipv4: Fix rtnexthop len when RTA_FLOW is present
+    - e100: fix length calculation in e100_get_regs_len
+    - e100: fix buffer overrun in e100_get_regs
+    - selftests, bpf: test_lwt_ip_encap: Really disable rp_filter
+    - scsi: csiostor: Add module softdep on cxgb4
+    - net: hns3: do not allow call hns3_nic_net_open repeatedly
+    - net: sched: flower: protect fl_walk() with rcu
+    - af_unix: fix races in sk_peer_pid and sk_peer_cred accesses
+    - perf/x86/intel: Update event constraints for ICX
+    - elf: don't use MAP_FIXED_NOREPLACE for elf interpreter mappings
+    - debugfs: debugfs_create_file_size(): use IS_ERR to check for error
+    - ipack: ipoctal: fix stack information leak
+    - ipack: ipoctal: fix tty registration race
+    - ipack: ipoctal: fix tty-registration error handling
+    - ipack: ipoctal: fix missing allocation-failure check
+    - ipack: ipoctal: fix module reference leak
+    - ext4: fix loff_t overflow in ext4_max_bitmap_size()
+    - ext4: fix reserved space counter leakage
+    - ext4: fix potential infinite loop in ext4_dx_readdir()
+    - HID: u2fzero: ignore incomplete packets without data
+    - net: udp: annotate data race around udp_sk(sk)->corkflag
+    - net: stmmac: don't attach interface until resume finishes
+    - PCI: Fix pci_host_bridge struct device release/free handling
+    - libnvdimm/pmem: Fix crash triggered when I/O in-flight during unbind
+    - hso: fix bailout in error case of probe
+    - usb: hso: fix error handling code of hso_create_net_device
+    - usb: hso: remove the bailout parameter
+    - crypto: ccp - fix resource leaks in ccp_run_aes_gcm_cmd()
+    - HID: betop: fix slab-out-of-bounds Write in betop_probe
+    - netfilter: ipset: Fix oversized kvmalloc() calls
+    - HID: usbhid: free raw_report buffers in usbhid_stop
+    - Linux 5.4.151
+  * Focal update: v5.4.150 upstream stable release (LP: #1947886)
+    - usb: gadget: r8a66597: fix a loop in set_feature()
+    - usb: dwc2: gadget: Fix ISOC flow for BDMA and Slave
+    - usb: dwc2: gadget: Fix ISOC transfer complete handling for DDMA
+    - usb: musb: tusb6010: uninitialized data in tusb_fifo_write_unaligned()
+    - cifs: fix incorrect check for null pointer in header_assemble
+    - xen/x86: fix PV trap handling on secondary processors
+    - usb-storage: Add quirk for ScanLogic SL11R-IDE older than 2.6c
+    - USB: serial: cp210x: add ID for GW Instek GDM-834x Digital Multimeter
+    - USB: cdc-acm: fix minor-number release
+    - binder: make sure fd closes complete
+    - staging: greybus: uart: fix tty use after free
+    - Re-enable UAS for LaCie Rugged USB3-FW with fk quirk
+    - USB: serial: mos7840: remove duplicated 0xac24 device ID
+    - USB: serial: option: add Telit LN920 compositions
+    - USB: serial: option: remove duplicate USB device ID
+    - USB: serial: option: add device id for Foxconn T99W265
+    - mcb: fix error handling in mcb_alloc_bus()
+    - erofs: fix up erofs_lookup tracepoint
+    - btrfs: prevent __btrfs_dump_space_info() to underflow its free space
+    - serial: mvebu-uart: fix driver's tx_empty callback
+    - net: hso: fix muxed tty registration
+    - afs: Fix incorrect triggering of sillyrename on 3rd-party invalidation
+    - platform/x86/intel: punit_ipc: Drop wrong use of ACPI_PTR()
+    - enetc: Fix illegal access when reading affinity_hint
+    - bnxt_en: Fix TX timeout when TX ring size is set to the smallest
+    - net/smc: add missing error check in smc_clc_prfx_set()
+    - gpio: uniphier: Fix void functions to remove return value
+    - qed: rdma - don't wait for resources under hw error recovery flow
+    - net/mlx4_en: Don't allow aRFS for encapsulated packets
+    - scsi: iscsi: Adjust iface sysfs attr detection
+    - tty: synclink_gt, drop unneeded forward declarations
+    - tty: synclink_gt: rename a conflicting function name
+    - fpga: machxo2-spi: Return an error on failure
+    - fpga: machxo2-spi: Fix missing error code in machxo2_write_complete()
+    - thermal/core: Potential buffer overflow in thermal_build_list_of_policies()
+    - cifs: fix a sign extension bug
+    - scsi: qla2xxx: Restore initiator in dual mode
+    - scsi: lpfc: Use correct scnprintf() limit
+    - irqchip/goldfish-pic: Select GENERIC_IRQ_CHIP to fix build
+    - irqchip/gic-v3-its: Fix potential VPE leak on error
+    - md: fix a lock order reversal in md_alloc
+    - blktrace: Fix uaf in blk_trace access after removing by sysfs
+    - net: macb: fix use after free on rmmod
+    - net: stmmac: allow CSR clock of 300MHz
+    - m68k: Double cast io functions to unsigned long
+    - ipv6: delay fib6_sernum increase in fib6_add
+    - bpf: Add oversize check before call kvcalloc()
+    - xen/balloon: use a kernel thread instead a workqueue
+    - nvme-multipath: fix ANA state updates when a namespace is not present
+    - sparc32: page align size in arch_dma_alloc
+    - blk-cgroup: fix UAF by grabbing blkcg lock before destroying blkg pd
+    - compiler.h: Introduce absolute_pointer macro
+    - net: i825xx: Use absolute_pointer for memcpy from fixed memory location
+    - sparc: avoid stringop-overread errors
+    - qnx4: avoid stringop-overread errors
+    - parisc: Use absolute_pointer() to define PAGE0
+    - arm64: Mark __stack_chk_guard as __ro_after_init
+    - alpha: Declare virt_to_phys and virt_to_bus parameter as pointer to volatile
+    - net: 6pack: Fix tx timeout and slot time
+    - spi: Fix tegra20 build with CONFIG_PM=n
+    - EDAC/synopsys: Fix wrong value type assignment for edac_mode
+    - thermal/drivers/int340x: Do not set a wrong tcc offset on resume
+    - arm64: dts: marvell: armada-37xx: Extend PCIe MEM space
+    - xen/balloon: fix balloon kthread freezing
+    - qnx4: work around gcc false positive warning bug
+    - Linux 5.4.150
+  * ACL updates on OCFS2 are not revalidated (LP: #1947161) // Focal update:
+    v5.4.150 upstream stable release (LP: #1947886)
+    - ocfs2: drop acl cache for directories too
+  * Focal update: v5.4.149 upstream stable release (LP: #1947885)
+    - PCI: pci-bridge-emul: Fix big-endian support
+    - PCI: aardvark: Indicate error in 'val' when config read fails
+    - PCI: pci-bridge-emul: Add PCIe Root Capabilities Register
+    - PCI: aardvark: Fix reporting CRS value
+    - PCI/ACPI: Add Ampere Altra SOC MCFG quirk
+    - KVM: remember position in kvm->vcpus array
+    - console: consume APC, DM, DCS
+    - s390/pci_mmio: fully validate the VMA before calling follow_pte()
+    - ARM: Qualify enabling of swiotlb_init()
+    - apparmor: remove duplicate macro list_entry_is_head()
+    - ARM: 9077/1: PLT: Move struct plt_entries definition to header
+    - ARM: 9078/1: Add warn suppress parameter to arm_gen_branch_link()
+    - ARM: 9079/1: ftrace: Add MODULE_PLTS support
+    - ARM: 9098/1: ftrace: MODULE_PLT: Fix build problem without DYNAMIC_FTRACE
+    - sctp: validate chunk size in __rcv_asconf_lookup
+    - sctp: add param size validation for SCTP_PARAM_SET_PRIMARY
+    - staging: rtl8192u: Fix bitwise vs logical operator in
+      TranslateRxSignalStuff819xUsb()
+    - um: virtio_uml: fix memory leak on init failures
+    - dmaengine: acpi: Avoid comparison GSI with Linux vIRQ
+    - thermal/drivers/exynos: Fix an error code in exynos_tmu_probe()
+    - 9p/trans_virtio: Remove sysfs file on probe failure
+    - prctl: allow to setup brk for et_dyn executables
+    - nilfs2: use refcount_dec_and_lock() to fix potential UAF
+    - profiling: fix shift-out-of-bounds bugs
+    - pwm: lpc32xx: Don't modify HW state in .probe() after the PWM chip was
+      registered
+    - phy: avoid unnecessary link-up delay in polling mode
+    - net: stmmac: reset Tx desc base address before restarting Tx
+    - Kconfig.debug: drop selecting non-existing HARDLOCKUP_DETECTOR_ARCH
+    - thermal/core: Fix thermal_cooling_device_register() prototype
+    - drivers: base: cacheinfo: Get rid of DEFINE_SMP_CALL_CACHE_FUNCTION()
+    - parisc: Move pci_dev_is_behind_card_dino to where it is used
+    - dmaengine: sprd: Add missing MODULE_DEVICE_TABLE
+    - dmaengine: ioat: depends on !UML
+    - dmaengine: xilinx_dma: Set DMA mask for coherent APIs
+    - ceph: request Fw caps before updating the mtime in ceph_write_iter
+    - ceph: lockdep annotations for try_nonblocking_invalidate
+    - btrfs: fix lockdep warning while mounting sprout fs
+    - nilfs2: fix memory leak in nilfs_sysfs_create_device_group
+    - nilfs2: fix NULL pointer in nilfs_##name##_attr_release
+    - nilfs2: fix memory leak in nilfs_sysfs_create_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_##name##_group
+    - nilfs2: fix memory leak in nilfs_sysfs_create_snapshot_group
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_snapshot_group
+    - pwm: img: Don't modify HW state in .remove() callback
+    - pwm: rockchip: Don't modify HW state in .remove() callback
+    - pwm: stm32-lp: Don't modify HW state in .remove() callback
+    - blk-throttle: fix UAF by deleteing timer in blk_throtl_exit()
+    - rtc: rx8010: select REGMAP_I2C
+    - drm/nouveau/nvkm: Replace -ENOSYS with -ENODEV
+    - Linux 5.4.149
+
+  [ Ubuntu: 5.4.0-90.101 ]
+
+  * focal/linux: 5.4.0-90.101 -proposed tracker (LP: #1947260)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.10.18)
+  * Add final-checks to check certificates (LP: #1947174)
+    - [Packaging] Add system trusted and revocation keys final check
+  * No sound on Lenovo laptop models Legion 15IMHG05, Yoga 7 14ITL5, and 13s
+    Gen2 (LP: #1939052)
+    - ALSA: hda/realtek: Quirks to enable speaker output for Lenovo Legion 7i
+      15IMHG05, Yoga 7i 14ITL5/15ITL5, and 13s Gen2 laptops.
+    - ALSA: hda/realtek: Fix for quirk to enable speaker output on the Lenovo 13s
+      Gen2
+  * CVE-2020-36385
+    - 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
+  * Focal update: v5.4.148 upstream stable release (LP: #1946802)
+    - rtc: tps65910: Correct driver module alias
+    - btrfs: wake up async_delalloc_pages waiters after submit
+    - btrfs: reset replace target device to allocation state on close
+    - blk-zoned: allow zone management send operations without CAP_SYS_ADMIN
+    - blk-zoned: allow BLKREPORTZONE without CAP_SYS_ADMIN
+    - PCI/MSI: Skip masking MSI-X on Xen PV
+    - powerpc/perf/hv-gpci: Fix counter value parsing
+    - xen: fix setting of max_pfn in shared_info
+    - include/linux/list.h: add a macro to test if entry is pointing to the head
+    - 9p/xen: Fix end of loop tests for list_for_each_entry
+    - tools/thermal/tmon: Add cross compiling support
+    - pinctrl: stmfx: Fix hazardous u8[] to unsigned long cast
+    - pinctrl: ingenic: Fix incorrect pull up/down info
+    - soc: qcom: aoss: Fix the out of bound usage of cooling_devs
+    - soc: aspeed: lpc-ctrl: Fix boundary check for mmap
+    - soc: aspeed: p2a-ctrl: Fix boundary check for mmap
+    - arm64: head: avoid over-mapping in map_memory
+    - crypto: public_key: fix overflow during implicit conversion
+    - block: bfq: fix bfq_set_next_ioprio_data()
+    - power: supply: max17042: handle fails of reading status register
+    - dm crypt: Avoid percpu_counter spinlock contention in crypt_page_alloc()
+    - VMCI: fix NULL pointer dereference when unmapping queue pair
+    - media: uvc: don't do DMA on stack
+    - media: rc-loopback: return number of emitters rather than error
+    - Revert "dmaengine: imx-sdma: refine to load context only once"
+    - dmaengine: imx-sdma: remove duplicated sdma_load_context
+    - libata: add ATA_HORKAGE_NO_NCQ_TRIM for Samsung 860 and 870 SSDs
+    - ARM: 9105/1: atags_to_fdt: don't warn about stack size
+    - PCI/portdrv: Enable Bandwidth Notification only if port supports it
+    - PCI: Restrict ASMedia ASM1062 SATA Max Payload Size Supported
+    - PCI: Return ~0 data on pciconfig_read() CAP_SYS_ADMIN failure
+    - PCI: xilinx-nwl: Enable the clock through CCF
+    - PCI: aardvark: Fix checking for PIO status
+    - PCI: aardvark: Increase polling delay to 1.5s while waiting for PIO response
+    - PCI: aardvark: Fix masking and unmasking legacy INTx interrupts
+    - HID: input: do not report stylus battery state as "full"
+    - f2fs: quota: fix potential deadlock
+    - scsi: bsg: Remove support for SCSI_IOCTL_SEND_COMMAND
+    - IB/hfi1: Adjust pkey entry in index 0
+    - RDMA/iwcm: Release resources if iw_cm module initialization fails
+    - docs: Fix infiniband uverbs minor number
+    - pinctrl: samsung: Fix pinctrl bank pin count
+    - vfio: Use config not menuconfig for VFIO_NOIOMMU
+    - powerpc/stacktrace: Include linux/delay.h
+    - RDMA/efa: Remove double QP type assignment
+    - f2fs: show f2fs instance in printk_ratelimited
+    - f2fs: reduce the scope of setting fsck tag when de->name_len is zero
+    - openrisc: don't printk() unconditionally
+    - dma-debug: fix debugfs initialization order
+    - SUNRPC: Fix potential memory corruption
+    - scsi: fdomain: Fix error return code in fdomain_probe()
+    - pinctrl: single: Fix error return code in pcs_parse_bits_in_pinctrl_entry()
+    - scsi: smartpqi: Fix an error code in pqi_get_raid_map()
+    - scsi: qedi: Fix error codes in qedi_alloc_global_queues()
+    - scsi: qedf: Fix error codes in qedf_alloc_global_queues()
+    - powerpc/config: Renable MTD_PHYSMAP_OF
+    - scsi: target: avoid per-loop XCOPY buffer allocations
+    - HID: i2c-hid: Fix Elan touchpad regression
+    - KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs
+      are live
+    - platform/x86: dell-smbios-wmi: Add missing kfree in error-exit from
+      run_smbios_call
+    - fscache: Fix cookie key hashing
+    - clk: at91: sam9x60: Don't use audio PLL
+    - clk: at91: clk-generated: pass the id of changeable parent at registration
+    - clk: at91: clk-generated: Limit the requested rate to our range
+    - KVM: PPC: Fix clearing never mapped TCEs in realmode
+    - f2fs: fix to account missing .skipped_gc_rwsem
+    - f2fs: fix unexpected ENOENT comes from f2fs_map_blocks()
+    - f2fs: fix to unmap pages from userspace process in punch_hole()
+    - MIPS: Malta: fix alignment of the devicetree buffer
+    - kbuild: Fix 'no symbols' warning when CONFIG_TRIM_UNUSD_KSYMS=y
+    - userfaultfd: prevent concurrent API initialization
+    - drm/amdgpu: Fix amdgpu_ras_eeprom_init()
+    - ASoC: atmel: ATMEL drivers don't need HAS_DMA
+    - media: dib8000: rewrite the init prbs logic
+    - crypto: mxs-dcp - Use sg_mapping_iter to copy data
+    - PCI: Use pci_update_current_state() in pci_enable_device_flags()
+    - tipc: keep the skb in rcv queue until the whole data is read
+    - iio: dac: ad5624r: Fix incorrect handling of an optional regulator.
+    - iavf: do not override the adapter state in the watchdog task
+    - iavf: fix locking of critical sections
+    - ARM: dts: qcom: apq8064: correct clock names
+    - video: fbdev: kyro: fix a DoS bug by restricting user input
+    - netlink: Deal with ESRCH error in nlmsg_notify()
+    - Smack: Fix wrong semantics in smk_access_entry()
+    - drm: avoid blocking in drm_clients_info's rcu section
+    - igc: Check if num of q_vectors is smaller than max before array access
+    - usb: host: fotg210: fix the endpoint's transactional opportunities
+      calculation
+    - usb: host: fotg210: fix the actual_length of an iso packet
+    - usb: gadget: u_ether: fix a potential null pointer dereference
+    - USB: EHCI: ehci-mv: improve error handling in mv_ehci_enable()
+    - usb: gadget: composite: Allow bMaxPower=0 if self-powered
+    - staging: board: Fix uninitialized spinlock when attaching genpd
+    - tty: serial: jsm: hold port lock when reporting modem line changes
+    - drm/amd/display: Fix timer_per_pixel unit error
+    - drm/amd/amdgpu: Update debugfs link_settings output link_rate field in hex
+    - bpf/tests: Fix copy-and-paste error in double word test
+    - bpf/tests: Do not PASS tests without actually testing the result
+    - video: fbdev: asiliantfb: Error out if 'pixclock' equals zero
+    - video: fbdev: kyro: Error out if 'pixclock' equals zero
+    - video: fbdev: riva: Error out if 'pixclock' equals zero
+    - ipv4: ip_output.c: Fix out-of-bounds warning in ip_copy_addrs()
+    - flow_dissector: Fix out-of-bounds warnings
+    - s390/jump_label: print real address in a case of a jump label bug
+    - s390: make PCI mio support a machine flag
+    - serial: 8250: Define RX trigger levels for OxSemi 950 devices
+    - xtensa: ISS: don't panic in rs_init
+    - hvsi: don't panic on tty_register_driver failure
+    - serial: 8250_pci: make setup_port() parameters explicitly unsigned
+    - staging: ks7010: Fix the initialization of the 'sleep_status' structure
+    - samples: bpf: Fix tracex7 error raised on the missing argument
+    - ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init()
+    - Bluetooth: skip invalid hci_sync_conn_complete_evt
+    - workqueue: Fix possible memory leaks in wq_numa_init()
+    - bonding: 3ad: fix the concurrency between __bond_release_one() and
+      bond_3ad_state_machine_handler()
+    - arm64: tegra: Fix Tegra194 PCIe EP compatible string
+    - ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the
+      matching in-/output
+    - media: imx258: Rectify mismatch of VTS value
+    - media: imx258: Limit the max analogue gain to 480
+    - media: v4l2-dv-timings.c: fix wrong condition in two for-loops
+    - media: TDA1997x: fix tda1997x_query_dv_timings() return value
+    - media: tegra-cec: Handle errors of clk_prepare_enable()
+    - ARM: dts: imx53-ppd: Fix ACHC entry
+    - arm64: dts: qcom: sdm660: use reg value for memory node
+    - net: ethernet: stmmac: Do not use unreachable() in ipq806x_gmac_probe()
+    - drm/msm: mdp4: drop vblank get/put from prepare/complete_commit
+    - selftests/bpf: Fix xdp_tx.c prog section name
+    - Bluetooth: schedule SCO timeouts with delayed_work
+    - Bluetooth: avoid circular locks in sco_sock_connect
+    - net/mlx5: Fix variable type to match 64bit
+    - gpu: drm: amd: amdgpu: amdgpu_i2c: fix possible uninitialized-variable
+      access in amdgpu_i2c_router_select_ddc_port()
+    - drm/display: fix possible null-pointer dereference in dcn10_set_clock()
+    - mac80211: Fix monitor MTU limit so that A-MSDUs get through
+    - ARM: tegra: tamonten: Fix UART pad setting
+    - arm64: tegra: Fix compatible string for Tegra132 CPUs
+    - arm64: dts: ls1046a: fix eeprom entries
+    - nvme-tcp: don't check blk_mq_tag_to_rq when receiving pdu data
+    - Bluetooth: Fix handling of LE Enhanced Connection Complete
+    - opp: Don't print an error if required-opps is missing
+    - serial: sh-sci: fix break handling for sysrq
+    - tcp: enable data-less, empty-cookie SYN with TFO_SERVER_COOKIE_NOT_REQD
+    - rpc: fix gss_svc_init cleanup on failure
+    - staging: rts5208: Fix get_ms_information() heap buffer size
+    - gfs2: Don't call dlm after protocol is unmounted
+    - usb: chipidea: host: fix port index underflow and UBSAN complains
+    - lockd: lockd server-side shouldn't set fl_ops
+    - drm/exynos: Always initialize mapping in exynos_drm_register_dma()
+    - m68knommu: only set CONFIG_ISA_DMA_API for ColdFire sub-arch
+    - btrfs: tree-log: check btrfs_lookup_data_extent return value
+    - ASoC: Intel: Skylake: Fix module configuration for KPB and MIXER
+    - ASoC: Intel: Skylake: Fix passing loadable flag for module
+    - of: Don't allow __of_attached_node_sysfs() without CONFIG_SYSFS
+    - mmc: sdhci-of-arasan: Check return value of non-void funtions
+    - mmc: rtsx_pci: Fix long reads when clock is prescaled
+    - selftests/bpf: Enlarge select() timeout for test_maps
+    - mmc: core: Return correct emmc response in case of ioctl error
+    - cifs: fix wrong release in sess_alloc_buffer() failed path
+    - Revert "USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST
+      quirk set"
+    - usb: musb: musb_dsps: request_irq() after initializing musb
+    - usbip: give back URBs for unsent unlink requests during cleanup
+    - usbip:vhci_hcd USB port can get stuck in the disabled state
+    - ASoC: rockchip: i2s: Fix regmap_ops hang
+    - ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B
+    - drm/amdkfd: Account for SH/SE count when setting up cu masks.
+    - iwlwifi: mvm: fix a memory leak in iwl_mvm_mac_ctxt_beacon_changed
+    - iwlwifi: mvm: avoid static queue number aliasing
+    - iwlwifi: mvm: fix access to BSS elements
+    - net/mlx5: DR, Enable QP retransmission
+    - parport: remove non-zero check on count
+    - ath9k: fix OOB read ar9300_eeprom_restore_internal
+    - ath9k: fix sleeping in atomic context
+    - net: fix NULL pointer reference in cipso_v4_doi_free
+    - fix array-index-out-of-bounds in taprio_change
+    - net: w5100: check return value after calling platform_get_resource()
+    - parisc: fix crash with signals and alloca
+    - ovl: fix BUG_ON() in may_delete() when called from ovl_cleanup()
+    - scsi: BusLogic: Fix missing pr_cont() use
+    - scsi: qla2xxx: Changes to support kdump kernel
+    - scsi: qla2xxx: Sync queue idx with queue_pair_map idx
+    - cpufreq: powernv: Fix init_chip_info initialization in numa=off
+    - s390/pv: fix the forcing of the swiotlb
+    - mm/hugetlb: initialize hugetlb_usage in mm_init
+    - mm,vmscan: fix divide by zero in get_scan_count
+    - memcg: enable accounting for pids in nested pid namespaces
+    - platform/chrome: cros_ec_proto: Send command again when timeout occurs
+    - lib/test_stackinit: Fix static initializer test
+    - net: dsa: lantiq_gswip: fix maximum frame length
+    - drm/msi/mdp4: populate priv->kms in mdp4_kms_init
+    - drm/amdgpu: Fix BUG_ON assert
+    - drm/panfrost: Simplify lock_region calculation
+    - drm/panfrost: Use u64 for size in lock_region
+    - drm/panfrost: Clamp lock region to Bifrost minimum
+    - btrfs: fix upper limit for max_inline for page size 64K
+    - xen: reset legacy rtc flag for PV domU
+    - bnx2x: Fix enabling network interfaces without VFs
+    - arm64/sve: Use correct size when reinitialising SVE state
+    - PM: base: power: don't try to use non-existing RTC for storing data
+    - PCI: Add AMD GPU multi-function power dependencies
+    - drm/amd/amdgpu: Increase HWIP_MAX_INSTANCE to 10
+    - drm/etnaviv: return context from etnaviv_iommu_context_get
+    - drm/etnaviv: put submit prev MMU context when it exists
+    - drm/etnaviv: stop abusing mmu_context as FE running marker
+    - drm/etnaviv: keep MMU context across runtime suspend/resume
+    - drm/etnaviv: exec and MMU state is lost when resetting the GPU
+    - drm/etnaviv: fix MMU context leak on GPU reset
+    - drm/etnaviv: reference MMU context when setting up hardware state
+    - drm/etnaviv: add missing MMU context put when reaping MMU mapping
+    - s390/sclp: fix Secure-IPL facility detection
+    - x86/mm: Fix kern_addr_valid() to cope with existing but not present entries
+    - tipc: fix an use-after-free issue in tipc_recvmsg
+    - net-caif: avoid user-triggerable WARN_ON(1)
+    - ptp: dp83640: don't define PAGE0
+    - net/l2tp: Fix reference count leak in l2tp_udp_recv_core
+    - r6040: Restore MDIO clock frequency after MAC reset
+    - tipc: increase timeout in tipc_sk_enqueue()
+    - perf machine: Initialize srcline string member in add_location struct
+    - net/mlx5: FWTrace, cancel work on alloc pd error flow
+    - net/mlx5: Fix potential sleeping in atomic context
+    - events: Reuse value read using READ_ONCE instead of re-reading it
+    - vhost_net: fix OoB on sendmsg() failure.
+    - net/af_unix: fix a data-race in unix_dgram_poll
+    - net: dsa: destroy the phylink instance on any error in dsa_slave_phy_setup
+    - tcp: fix tp->undo_retrans accounting in tcp_sacktag_one()
+    - qed: Handle management FW error
+    - dt-bindings: arm: Fix Toradex compatible typo
+    - ibmvnic: check failover_pending in login response
+    - KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing
+      registers
+    - net: hns3: pad the short tunnel frame before sending to hardware
+    - net: hns3: change affinity_mask to numa node range
+    - net: hns3: disable mac in flr process
+    - net: hns3: fix the timing issue of VF clearing interrupt sources
+    - mm/memory_hotplug: use "unsigned long" for PFN in zone_for_pfn_range()
+    - dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation
+    - mfd: db8500-prcmu: Adjust map to reality
+    - PCI: Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms
+    - fuse: fix use after free in fuse_read_interrupt()
+    - mfd: Don't use irq_create_mapping() to resolve a mapping
+    - tracing/probes: Reject events which have the same name of existing one
+    - PCI: Add ACS quirks for Cavium multi-function devices
+    - Set fc_nlinfo in nh_create_ipv4, nh_create_ipv6
+    - net: usb: cdc_mbim: avoid altsetting toggling for Telit LN920
+    - PCI: ibmphp: Fix double unmap of io_mem
+    - ethtool: Fix an error code in cxgb2.c
+    - NTB: Fix an error code in ntb_msit_probe()
+    - NTB: perf: Fix an error code in perf_setup_inbuf()
+    - mfd: axp20x: Update AXP288 volatile ranges
+    - PCI: Fix pci_dev_str_match_path() alloc while atomic bug
+    - mfd: tqmx86: Clear GPIO IRQ resource when no IRQ is set
+    - KVM: arm64: Handle PSCI resets before userspace touches vCPU state
+    - PCI: Sync __pci_register_driver() stub for CONFIG_PCI=n
+    - mtd: rawnand: cafe: Fix a resource leak in the error handling path of
+      'cafe_nand_probe()'
+    - ARC: export clear_user_page() for modules
+    - perf unwind: Do not overwrite FEATURE_CHECK_LDFLAGS-libunwind-{x86,aarch64}
+    - net: dsa: b53: Fix calculating number of switch ports
+    - netfilter: socket: icmp6: fix use-after-scope
+    - fq_codel: reject silly quantum parameters
+    - qlcnic: Remove redundant unlock in qlcnic_pinit_from_rom
+    - ip_gre: validate csum_start only on pull
+    - net: renesas: sh_eth: Fix freeing wrong tx descriptor
+    - Linux 5.4.148
+  * Focal update: v5.4.147 upstream stable release (LP: #1946795)
+    - Linux 5.4.147
+    - upstream stable to v5.4.147
+  * CVE-2021-3428
+    - ext4: save the error code which triggered an ext4_error() in the superblock
+    - ext4: simulate various I/O and checksum errors when reading metadata
+    - ext4: save all error info in save_error_info() and drop ext4_set_errno()
+    - ext4: check journal inode extents more carefully
+  * ip6gretap / erspan / ip6erspan in rtnetlink.sh from net of
+    ubuntu_kernel_selftests failed on B-5.4-aws / B-5.4-gke / B-5.4-oracle /
+    B-5.4-azure / B-5.4 (LP: #1896448)
+    - SAUCE: selftests: rtnetlink: fixes for older iproute2
+  * CVE-2019-19449
+    - f2fs: fix wrong total_sections check and fsmeta check
+    - f2fs: fix to do sanity check on segment/section count
+  * kernel bug found when disconnecting one fiber channel interface on Cisco
+    Chassis with fnic DRV_VERSION "1.6.0.47" (LP: #1944586)
+    - scsi: fnic: Do not call 'scsi_done()' for unhandled commands
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (unknown type
+    name ‘__u64’) (LP: #1944613)
+    - SAUCE: selftests/memfd: fix __u64 not defined build issue
+  * Medion Notebook Keyboard not working (LP: #1909814)
+    - ACPI: resources: Add DMI-based legacy IRQ override quirk
+  * vrf: fix refcnt leak with vxlan slaves (LP: #1945180)
+    - ipv4: Fix device used for dst_alloc with local routes
+  * Check for changes relevant for security certifications (LP: #1945989)
+    - [Packaging] Add a new fips-checks script
+    - [Packaging] Add fips-checks as part of finalchecks
+  * Fix cold plugged USB device on certain PCIe USB cards (LP: #1945211)
+    - Revert "UBUNTU: SAUCE: Revert "usb: core: reduce power-on-good delay time of
+      root hub""
+    - usb: core: hcd: Add support for deferring roothub registration
+    - xhci: Set HCD flag to defer primary roothub registration
+    - usb: core: hcd: Modularize HCD stop configuration in usb_stop_hcd()
+  * CVE-2021-3759
+    - memcg: enable accounting of ipc resources
+  * Focal update: v5.4.146 upstream stable release (LP: #1946024)
+    - locking/mutex: Fix HANDOFF condition
+    - regmap: fix the offset of register error log
+    - crypto: mxs-dcp - Check for DMA mapping errors
+    - sched/deadline: Fix reset_on_fork reporting of DL tasks
+    - power: supply: axp288_fuel_gauge: Report register-address on readb / writeb
+      errors
+    - crypto: omap-sham - clear dma flags only after omap_sham_update_dma_stop()
+    - sched/deadline: Fix missing clock update in migrate_task_rq_dl()
+    - rcu/tree: Handle VM stoppage in stall detection
+    - hrtimer: Avoid double reprogramming in __hrtimer_start_range_ns()
+    - hrtimer: Ensure timerfd notification for HIGHRES=n
+    - udf: Check LVID earlier
+    - udf: Fix iocharset=utf8 mount option
+    - isofs: joliet: Fix iocharset=utf8 mount option
+    - bcache: add proper error unwinding in bcache_device_init
+    - nvme-tcp: don't update queue count when failing to set io queues
+    - nvme-rdma: don't update queue count when failing to set io queues
+    - nvmet: pass back cntlid on successful completion
+    - power: supply: max17042_battery: fix typo in MAx17042_TOFF
+    - s390/cio: add dev_busid sysfs entry for each subchannel
+    - libata: fix ata_host_start()
+    - crypto: qat - do not ignore errors from enable_vf2pf_comms()
+    - crypto: qat - handle both source of interrupt in VF ISR
+    - crypto: qat - fix reuse of completion variable
+    - crypto: qat - fix naming for init/shutdown VF to PF notifications
+    - crypto: qat - do not export adf_iov_putmsg()
+    - fcntl: fix potential deadlock for &fasync_struct.fa_lock
+    - udf_get_extendedattr() had no boundary checks.
+    - s390/kasan: fix large PMD pages address alignment check
+    - s390/debug: fix debug area life cycle
+    - m68k: emu: Fix invalid free in nfeth_cleanup()
+    - sched: Fix UCLAMP_FLAG_IDLE setting
+    - spi: spi-fsl-dspi: Fix issue with uninitialized dma_slave_config
+    - spi: spi-pic32: Fix issue with uninitialized dma_slave_config
+    - genirq/timings: Fix error return code in irq_timings_test_irqs()
+    - lib/mpi: use kcalloc in mpi_resize
+    - clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock
+      source channel
+    - crypto: qat - use proper type for vf_mask
+    - certs: Trigger creation of RSA module signing key if it's not an RSA key
+    - regulator: vctrl: Use locked regulator_get_voltage in probe path
+    - regulator: vctrl: Avoid lockdep warning in enable/disable ops
+    - spi: sprd: Fix the wrong WDG_LOAD_VAL
+    - spi: spi-zynq-qspi: use wait_for_completion_timeout to make
+      zynq_qspi_exec_mem_op not interruptible
+    - EDAC/i10nm: Fix NVDIMM detection
+    - drm/panfrost: Fix missing clk_disable_unprepare() on error in
+      panfrost_clk_init()
+    - media: TDA1997x: enable EDID support
+    - soc: rockchip: ROCKCHIP_GRF should not default to y, unconditionally
+    - media: cxd2880-spi: Fix an error handling path
+    - bpf: Fix a typo of reuseport map in bpf.h.
+    - bpf: Fix potential memleak and UAF in the verifier.
+    - ARM: dts: aspeed-g6: Fix HVI3C function-group in pinctrl dtsi
+    - arm64: dts: renesas: r8a77995: draak: Remove bogus adv7511w properties
+    - soc: qcom: rpmhpd: Use corner in power_off
+    - media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init
+    - media: dvb-usb: fix uninit-value in vp702x_read_mac_addr
+    - media: dvb-usb: Fix error handling in dvb_usb_i2c_init
+    - media: go7007: remove redundant initialization
+    - media: coda: fix frame_mem_ctrl for YUV420 and YVU420 formats
+    - Bluetooth: sco: prevent information leak in sco_conn_defer_accept()
+    - 6lowpan: iphc: Fix an off-by-one check of array index
+    - netns: protect netns ID lookups with RCU
+    - tcp: seq_file: Avoid skipping sk during tcp_seek_last_pos
+    - ARM: dts: meson8: Use a higher default GPU clock frequency
+    - ARM: dts: meson8b: odroidc1: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: mxq: Fix the pwm regulator supply properties
+    - ARM: dts: meson8b: ec100: Fix the pwm regulator supply properties
+    - net/mlx5e: Prohibit inner indir TIRs in IPoIB
+    - cgroup/cpuset: Fix a partition bug with hotplug
+    - net: cipso: fix warnings in netlbl_cipsov4_add_std
+    - i2c: highlander: add IRQ check
+    - leds: lt3593: Put fwnode in any case during ->probe()
+    - leds: trigger: audio: Add an activate callback to ensure the initial
+      brightness is set
+    - media: em28xx-input: fix refcount bug in em28xx_usb_disconnect
+    - media: venus: venc: Fix potential null pointer dereference on pointer fmt
+    - PCI: PM: Avoid forcing PCI_D0 for wakeup reasons inconsistently
+    - PCI: PM: Enable PME if it can be signaled from D3cold
+    - soc: qcom: smsm: Fix missed interrupts if state changes while masked
+    - debugfs: Return error during {full/open}_proxy_open() on rmmod
+    - Bluetooth: increase BTNAMSIZ to 21 chars to fix potential buffer overflow
+    - PM: EM: Increase energy calculation precision
+    - drm/msm/dpu: make dpu_hw_ctl_clear_all_blendstages clear necessary LMs
+    - arm64: dts: exynos: correct GIC CPU interfaces address range on Exynos7
+    - counter: 104-quad-8: Return error when invalid mode during ceiling_write
+    - Bluetooth: fix repeated calls to sco_sock_kill
+    - drm/msm/dsi: Fix some reference counted resource leaks
+    - usb: gadget: udc: at91: add IRQ check
+    - usb: phy: fsl-usb: add IRQ check
+    - usb: phy: twl6030: add IRQ checks
+    - usb: gadget: udc: renesas_usb3: Fix soc_device_match() abuse
+    - usb: host: ohci-tmio: add IRQ check
+    - usb: phy: tahvo: add IRQ check
+    - mac80211: Fix insufficient headroom issue for AMSDU
+    - lockd: Fix invalid lockowner cast after vfs_test_lock
+    - nfsd4: Fix forced-expiry locking
+    - usb: gadget: mv_u3d: request_irq() after initializing UDC
+    - mm/swap: consider max pages in iomap_swapfile_add_extent
+    - Bluetooth: add timeout sanity check to hci_inquiry
+    - i2c: iop3xx: fix deferred probing
+    - i2c: s3c2410: fix IRQ check
+    - rsi: fix error code in rsi_load_9116_firmware()
+    - rsi: fix an error code in rsi_probe()
+    - ASoC: Intel: Skylake: Leave data as is when invoking TLV IPCs
+    - ASoC: Intel: Skylake: Fix module resource and format selection
+    - mmc: dw_mmc: Fix issue with uninitialized dma_slave_config
+    - mmc: moxart: Fix issue with uninitialized dma_slave_config
+    - bpf: Fix possible out of bound write in narrow load handling
+    - CIFS: Fix a potencially linear read overflow
+    - i2c: mt65xx: fix IRQ check
+    - usb: ehci-orion: Handle errors of clk_prepare_enable() in probe
+    - usb: bdc: Fix an error handling path in 'bdc_probe()' when no suitable DMA
+      config is available
+    - tty: serial: fsl_lpuart: fix the wrong mapbase value
+    - ASoC: wcd9335: Fix a double irq free in the remove function
+    - ASoC: wcd9335: Fix a memory leak in the error handling path of the probe
+      function
+    - ASoC: wcd9335: Disable irq on slave ports in the remove function
+    - ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point()
+    - bcma: Fix memory leak for internally-handled cores
+    - brcmfmac: pcie: fix oops on failure to resume and reprobe
+    - ipv6: make exception cache less predictible
+    - ipv4: make exception cache less predictible
+    - net: sched: Fix qdisc_rate_table refcount leak when get tcf_block failed
+    - net: qualcomm: fix QCA7000 checksum handling
+    - octeontx2-af: Fix loop in free and unmap counter
+    - ipv4: fix endianness issue in inet_rtm_getroute_build_skb()
+    - bpf: Introduce BPF nospec instruction for mitigating Spectre v4
+    - bpf: Fix leakage due to insufficient speculative store bypass mitigation
+    - bpf: verifier: Allocate idmap scratch in verifier env
+    - bpf: Fix pointer arithmetic mask tightening under state pruning
+    - tty: Fix data race between tiocsti() and flush_to_ldisc()
+    - perf/x86/amd/ibs: Extend PERF_PMU_CAP_NO_EXCLUDE to IBS Op
+    - x86/resctrl: Fix a maybe-uninitialized build warning treated as error
+    - KVM: s390: index kvm->arch.idle_mask by vcpu_idx
+    - KVM: x86: Update vCPU's hv_clock before back to guest when tsc_offset is
+      adjusted
+    - KVM: nVMX: Unconditionally clear nested.pi_pending on nested VM-Enter
+    - fuse: truncate pagecache on atomic_o_trunc
+    - fuse: flush extending writes
+    - IMA: remove -Wmissing-prototypes warning
+    - IMA: remove the dependency on CRYPTO_MD5
+    - fbmem: don't allow too huge resolutions
+    - backlight: pwm_bl: Improve bootloader/kernel device handover
+    - clk: kirkwood: Fix a clocking boot regression
+    - Linux 5.4.146
+  * AMD A8-7680 (amdgpu): broken Xorg acceleration and hibernation
+    (LP: #1920674) // Focal update: v5.4.146 upstream stable release
+    (LP: #1946024)
+    - drm/amdgpu/acp: Make PM domain really work
+  * Focal update: v5.4.145 upstream stable release (LP: #1945517)
+    - fscrypt: add fscrypt_symlink_getattr() for computing st_size
+    - ext4: report correct st_size for encrypted symlinks
+    - f2fs: report correct st_size for encrypted symlinks
+    - ubifs: report correct st_size for encrypted symlinks
+    - kthread: Fix PF_KTHREAD vs to_kthread() race
+    - xtensa: fix kconfig unmet dependency warning for HAVE_FUTEX_CMPXCHG
+    - gpu: ipu-v3: Fix i.MX IPU-v3 offset calculations for (semi)planar U/V
+      formats
+    - reset: reset-zynqmp: Fixed the argument data type
+    - qed: Fix the VF msix vectors flow
+    - net: macb: Add a NULL check on desc_ptp
+    - qede: Fix memset corruption
+    - perf/x86/intel/pt: Fix mask of num_address_ranges
+    - perf/x86/amd/ibs: Work around erratum #1197
+    - perf/x86/amd/power: Assign pmu.module
+    - cryptoloop: add a deprecation warning
+    - ARM: 8918/2: only build return_address() if needed
+    - ALSA: hda/realtek: Workaround for conflicting SSID on ASUS ROG Strix G17
+    - ALSA: pcm: fix divide error in snd_pcm_lib_ioctl
+    - ARC: wireup clone3 syscall
+    - media: stkwebcam: fix memory leak in stk_camera_probe
+    - igmp: Add ip_mc_list lock in ip_check_mc_rcu
+    - USB: serial: mos7720: improve OOM-handling in read_mos_reg()
+    - ipv4/icmp: l3mdev: Perform icmp error route lookup on source device routing
+      table (v2)
+    - powerpc/boot: Delete unneeded .globl _zimage_start
+    - net: ll_temac: Remove left-over debug message
+    - mm/page_alloc: speed up the iteration of max_order
+    - Revert "r8169: avoid link-up interrupt issue on RTL8106e if user enables
+      ASPM"
+    - x86/events/amd/iommu: Fix invalid Perf result due to IOMMU PMC power-gating
+    - Revert "btrfs: compression: don't try to compress if we don't have enough
+      pages"
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 800
+    - usb: host: xhci-rcar: Don't reload firmware after the completion
+    - usb: mtu3: use @mult for HS isoc or intr
+    - usb: mtu3: fix the wrong HS mult value
+    - xhci: fix unsafe memory usage in xhci tracing
+    - x86/reboot: Limit Dell Optiplex 990 quirk to early BIOS versions
+    - PCI: Call Max Payload Size-related fixup quirks early
+    - Linux 5.4.145
+  * Focal update: v5.4.144 upstream stable release (LP: #1944756)
+    - net: qrtr: fix another OOB Read in qrtr_endpoint_post
+    - ARC: Fix CONFIG_STACKDEPOT
+    - netfilter: conntrack: collect all entries in one cycle
+    - once: Fix panic when module unload
+    - ovl: fix uninitialized pointer read in ovl_lookup_real_one()
+    - mmc: sdhci-msm: Update the software timeout value for sdhc
+    - mm, oom: make the calculation of oom badness more accurate
+    - can: usb: esd_usb2: esd_usb2_rx_event(): fix the interchange of the CAN RX
+      and TX error counters
+    - Revert "USB: serial: ch341: fix character loss at high transfer rates"
+    - USB: serial: option: add new VID/PID to support Fibocom FG150
+    - usb: dwc3: gadget: Fix dwc3_calc_trbs_left()
+    - usb: dwc3: gadget: Stop EP0 transfers during pullup disable
+    - scsi: core: Fix hang of freezing queue between blocking and running device
+    - RDMA/bnxt_re: Add missing spin lock initialization
+    - IB/hfi1: Fix possible null-pointer dereference in _extend_sdma_tx_descs()
+    - e1000e: Fix the max snoop/no-snoop latency for 10M
+    - RDMA/efa: Free IRQ vectors on error flow
+    - ip_gre: add validation for csum_start
+    - xgene-v2: Fix a resource leak in the error handling path of 'xge_probe()'
+    - net: marvell: fix MVNETA_TX_IN_PRGRS bit number
+    - rtnetlink: Return correct error on changing device netns
+    - net: hns3: clear hardware resource when loading driver
+    - net: hns3: fix duplicate node in VLAN list
+    - net: hns3: fix get wrong pfc_en when query PFC configuration
+    - drm/i915: Fix syncmap memory leak
+    - usb: gadget: u_audio: fix race condition on endpoint stop
+    - perf/x86/intel/uncore: Fix integer overflow on 23 bit left shift of a u32
+    - opp: remove WARN when no valid OPPs remain
+    - virtio: Improve vq->broken access to avoid any compiler optimization
+    - virtio_pci: Support surprise removal of virtio pci device
+    - vringh: Use wiov->used to check for read/write desc order
+    - qed: qed ll2 race condition fixes
+    - qed: Fix null-pointer dereference in qed_rdma_create_qp()
+    - drm: Copy drm_wait_vblank to user before returning
+    - drm/nouveau/disp: power down unused DP links during init
+    - net/rds: dma_map_sg is entitled to merge entries
+    - btrfs: fix race between marking inode needs to be logged and log syncing
+    - vt_kdsetmode: extend console locking
+    - bpf: Track contents of read-only maps as scalars
+    - bpf: Fix cast to pointer from integer of different size warning
+    - net: dsa: mt7530: fix VLAN traffic leaks again
+    - KVM: x86/mmu: Treat NX as used (not reserved) for all !TDP shadow MMUs
+    - arm64: dts: qcom: msm8994-angler: Fix gpio-reserved-ranges 85-88
+    - btrfs: fix NULL pointer dereference when deleting device by invalid id
+    - Revert "floppy: reintroduce O_NDELAY fix"
+    - Revert "parisc: Add assembly implementations for memset, strlen, strcpy,
+      strncpy and strcat"
+    - net: don't unconditionally copy_from_user a struct ifreq for socket ioctls
+    - audit: move put_tree() to avoid trim_trees refcount underflow and UAF
+    - Linux 5.4.144
+
+  [ Ubuntu: 5.4.0-89.100 ]
+
+  * focal/linux: 5.4.0-89.100 -proposed tracker (LP: #1944901)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.27)
+  * ext4 journal recovery fails w/ data=journal + mmap (LP: #1847340)
+    - jbd2: introduce/export functions
+      jbd2_journal_submit|finish_inode_data_buffers()
+    - jbd2, ext4, ocfs2: introduce/use journal callbacks
+      j_submit|finish_inode_data_buffers()
+    - ext4: data=journal: fixes for ext4_page_mkwrite()
+    - ext4: data=journal: write-protect pages on j_submit_inode_data_buffers()
+    - ext4: fix mmap write protection for data=journal mode
+  * CVE-2021-40490
+    - ext4: fix race writing to an inline_data file while its xattrs are changing
+  * Obsolete patch "UBUNTU: SAUCE: ext4: fix directory index node split
+    corruption" (LP: #1942902)
+    - Revert "UBUNTU: SAUCE: ext4: fix directory index node split corruption"
+  * psock_snd.sh in net from ubuntu_kernel_selftests ADT failure with
+    focal/groovy/hirsute/impish (LP: #1892213)
+    - selftests/net: remove min gso test in packet_snd
+  * Focal update: v5.4.143 upstream stable release (LP: #1944212)
+    - ext4: fix EXT4_MAX_LOGICAL_BLOCK macro
+    - x86/fpu: Make init_fpstate correct with optimized XSAVE
+    - 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
+    - mtd: cfi_cmdset_0002: fix crash when erasing/writing AMD cards
+    - media: zr364xx: propagate errors from zr364xx_start_readpipe()
+    - media: zr364xx: fix memory leaks in probe()
+    - media: drivers/media/usb: fix memory leak in zr364xx_probe
+    - USB: core: Avoid WARNings for 0-length descriptor requests
+    - dmaengine: xilinx_dma: Fix read-after-free bug when terminating transfers
+    - dmaengine: usb-dmac: Fix PM reference leak in usb_dmac_probe()
+    - ARM: dts: am43x-epos-evm: Reduce i2c0 bus speed for tps65218
+    - dmaengine: of-dma: router_xlate to return -EPROBE_DEFER if controller is not
+      yet available
+    - scsi: megaraid_mm: Fix end of loop tests for list_for_each_entry()
+    - scsi: scsi_dh_rdac: Avoid crash during rdac_bus_attach()
+    - scsi: core: Avoid printing an error if target_alloc() returns -ENXIO
+    - scsi: core: Fix capacity set to zero after offlinining device
+    - ARM: dts: nomadik: Fix up interrupt controller node names
+    - net: usb: lan78xx: don't modify phy_device state concurrently
+    - drm/amd/display: Fix Dynamic bpp issue with 8K30 with Navi 1X
+    - Bluetooth: hidp: use correct wait queue when removing ctrl_wait
+    - iommu: Check if group is NULL before remove device
+    - cpufreq: armada-37xx: forbid cpufreq for 1.2 GHz variant
+    - dccp: add do-while-0 stubs for dccp_pr_debug macros
+    - virtio: Protect vqs list access
+    - vhost: Fix the calculation in vhost_overflow()
+    - bpf: Clear zext_dst of dead insns
+    - bnxt: don't lock the tx queue from napi poll
+    - bnxt: disable napi before canceling DIM
+    - net: 6pack: fix slab-out-of-bounds in decode_data
+    - ptp_pch: Restore dependency on PCI
+    - bnxt_en: Add missing DMA memory barriers
+    - vrf: Reset skb conntrack connection on VRF rcv
+    - virtio-net: support XDP when not more queues
+    - virtio-net: use NETIF_F_GRO_HW instead of NETIF_F_LRO
+    - net: qlcnic: add missed unlock in qlcnic_83xx_flash_read32
+    - net: mdio-mux: Don't ignore memory allocation errors
+    - net: mdio-mux: Handle -EPROBE_DEFER correctly
+    - ovs: clear skb->tstamp in forwarding path
+    - i40e: Fix ATR queue selection
+    - iavf: Fix ping is lost after untrusted VF had tried to change MAC
+    - ovl: add splice file read write helper
+    - mmc: dw_mmc: Fix hang on data CRC error
+    - ALSA: hda - fix the 'Capture Switch' value change notifications
+    - tracing / histogram: Fix NULL pointer dereference on strcmp() on NULL event
+      name
+    - slimbus: messaging: start transaction ids from 1 instead of zero
+    - slimbus: messaging: check for valid transaction id
+    - slimbus: ngd: reset dma setup during runtime pm
+    - ipack: tpci200: fix many double free issues in tpci200_pci_probe
+    - ipack: tpci200: fix memory leak in the tpci200_register
+    - btrfs: prevent rename2 from exchanging a subvol with a directory from
+      different parents
+    - PCI: Increase D3 delay for AMD Renoir/Cezanne XHCI
+    - ASoC: intel: atom: Fix breakage for PCM buffer address setup
+    - mm, memcg: avoid stale protection values when cgroup is above protection
+    - mm: memcontrol: fix occasional OOMs due to proportional memory.low reclaim
+    - fs: warn about impending deprecation of mandatory locks
+    - netfilter: nft_exthdr: fix endianness of tcp option cast
+    - Linux 5.4.143
+  * Focal update: v5.4.142 upstream stable release (LP: #1944202)
+    - iio: adc: ti-ads7950: Ensure CS is deasserted after reading channels
+    - iio: humidity: hdc100x: Add margin to the conversion time
+    - iio: adc: Fix incorrect exit of for-loop
+    - ASoC: xilinx: Fix reference to PCM buffer address
+    - ASoC: intel: atom: Fix reference to PCM buffer address
+    - i2c: dev: zero out array used for i2c reads from userspace
+    - ceph: reduce contention in ceph_check_delayed_caps()
+    - ACPI: NFIT: Fix support for virtual SPA ranges
+    - libnvdimm/region: Fix label activation vs errors
+    - ieee802154: hwsim: fix GPF in hwsim_set_edge_lqi
+    - ieee802154: hwsim: fix GPF in hwsim_new_edge_nl
+    - ASoC: cs42l42: Correct definition of ADC Volume control
+    - ASoC: cs42l42: Don't allow SND_SOC_DAIFMT_LEFT_J
+    - ASoC: cs42l42: Fix inversion of ADC Notch Switch control
+    - ASoC: cs42l42: Remove duplicate control for WNF filter frequency
+    - netfilter: nf_conntrack_bridge: Fix memory leak when error
+    - ASoC: cs42l42: Fix LRCLK frame start edge
+    - net: dsa: mt7530: add the missing RxUnicast MIB counter
+    - platform/x86: pcengines-apuv2: revert wiring up simswitch GPIO as LED
+    - platform/x86: pcengines-apuv2: Add missing terminating entries to gpio-
+      lookup tables
+    - net: phy: micrel: Fix link detection on ksz87xx switch"
+    - ppp: Fix generating ifname when empty IFLA_IFNAME is specified
+    - net: sched: act_mirred: Reset ct info when mirror/redirect skb
+    - iavf: Set RSS LUT and key in reset handle path
+    - psample: Add a fwd declaration for skbuff
+    - net/mlx5: Fix return value from tracer initialization
+    - drm/meson: fix colour distortion from HDR set during vendor u-boot
+    - net: dsa: microchip: Fix ksz_read64()
+    - net: Fix memory leak in ieee802154_raw_deliver
+    - net: igmp: fix data-race in igmp_ifc_timer_expire()
+    - net: dsa: lan9303: fix broken backpressure in .port_fdb_dump
+    - net: dsa: lantiq: fix broken backpressure in .port_fdb_dump
+    - net: dsa: sja1105: fix broken backpressure in .port_fdb_dump
+    - net: bridge: fix memleak in br_add_if()
+    - net: linkwatch: fix failure to restore device state across suspend/resume
+    - tcp_bbr: fix u32 wrap bug in round logic if bbr_init() called after 2B
+      packets
+    - net: igmp: increase size of mr_ifc_count
+    - xen/events: Fix race in set_evtchn_to_irq
+    - vsock/virtio: avoid potential deadlock when vsock device remove
+    - nbd: Aovid double completion of a request
+    - powerpc/kprobes: Fix kprobe Oops happens in booke
+    - x86/tools: Fix objdump version check again
+    - genirq: Provide IRQCHIP_AFFINITY_PRE_STARTUP
+    - x86/msi: Force affinity setup before startup
+    - x86/ioapic: Force affinity setup before startup
+    - x86/resctrl: Fix default monitoring groups reporting
+    - genirq/msi: Ensure deactivation on teardown
+    - genirq/timings: Prevent potential array overflow in __irq_timings_store()
+    - PCI/MSI: Enable and mask MSI-X early
+    - PCI/MSI: Mask all unused MSI-X entries
+    - PCI/MSI: Enforce that MSI-X table entry is masked for update
+    - PCI/MSI: Enforce MSI[X] entry updates to be visible
+    - PCI/MSI: Do not set invalid bits in MSI mask
+    - PCI/MSI: Correct misleading comments
+    - PCI/MSI: Use msi_mask_irq() in pci_msi_shutdown()
+    - PCI/MSI: Protect msi_desc::masked for multi-MSI
+    - KVM: VMX: Use current VMCS to query WAITPKG support for MSR emulation
+    - ceph: add some lockdep assertions around snaprealm handling
+    - ceph: clean up locking annotation for ceph_get_snap_realm and
+      __lookup_snap_realm
+    - ceph: take snap_empty_lock atomically with snaprealm refcount change
+    - vmlinux.lds.h: Handle clang's module.{c,d}tor sections
+    - iommu/vt-d: Fix agaw for a supported 48 bit guest address width
+    - Linux 5.4.142
+  * Focal update: v5.4.141 upstream stable release (LP: #1943484)
+    - KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB
+    - tee: Correct inappropriate usage of TEE_SHM_DMA_BUF flag
+    - media: v4l2-mem2mem: always consider OUTPUT queue during poll
+    - tracing: Reject string operand in the histogram expression
+    - usb: dwc3: Stop active transfers before halting the controller
+    - usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
+    - usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
+    - usb: dwc3: gadget: Prevent EP queuing while stopping transfers
+    - usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
+    - usb: dwc3: gadget: Disable gadget IRQ during pullup disable
+    - usb: dwc3: gadget: Avoid runtime resume if disabling pullup
+    - KVM: X86: MMU: Use the correct inherited permissions to get shadow page
+    - USB:ehci:fix Kunpeng920 ehci hardware problem
+    - ALSA: hda: Add quirk for ASUS Flow x13
+    - ppp: Fix generating ppp unit id when ifname is not specified
+    - ovl: prevent private clone if bind mount is not allowed
+    - btrfs: make qgroup_free_reserved_data take btrfs_inode
+    - btrfs: make btrfs_qgroup_reserve_data take btrfs_inode
+    - btrfs: qgroup: allow to unreserve range without releasing other ranges
+    - btrfs: qgroup: try to flush qgroup space when we get -EDQUOT
+    - btrfs: transaction: Cleanup unused TRANS_STATE_BLOCKED
+    - btrfs: qgroup: remove ASYNC_COMMIT mechanism in favor of reserve retry-
+      after-EDQUOT
+    - btrfs: fix lockdep splat when enabling and disabling qgroups
+    - net: xilinx_emaclite: Do not print real IOMEM pointer
+    - btrfs: qgroup: don't commit transaction when we already hold the handle
+    - btrfs: export and rename qgroup_reserve_meta
+    - btrfs: don't flush from btrfs_delayed_inode_reserve_metadata
+    - Linux 5.4.141
+
+  [ Ubuntu: 5.4.0-88.99 ]
+
+  * focal/linux: 5.4.0-88.99 -proposed tracker (LP: #1944747)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - Revert "UBUNTU: [Config] Disable virtualbox dkms build"
+
+  [ Ubuntu: 5.4.0-87.98 ]
+
+  * please drop virtualbox-guest-dkms virtualbox-guest-source (LP: #1933248)
+    - [Config] Disable virtualbox dkms build
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.09.06)
+  *  LRMv5: switch primary version handling to kernel-versions data set
+    (LP: #1928921)
+    - [Packaging] switch to kernel-versions
+  * disable “CONFIG_HISI_DMA” config for ubuntu version (LP: #1936771)
+    - Disable CONFIG_HISI_DMA
+    - [Config] Record hisi_dma no longer built for arm64
+  * memory leaking when removing a profile (LP: #1939915)
+    - apparmor: Fix memory leak of profile proxy
+  * CryptoExpress EP11 cards are going offline (LP: #1939618)
+    - s390/zcrypt: Support for CCA protected key block version 2
+    - s390: Replace zero-length array with flexible-array member
+    - s390/zcrypt: Use scnprintf() for avoiding potential buffer overflow
+    - s390/zcrypt: replace snprintf/sprintf with scnprintf
+    - s390/ap: Remove ap device suspend and resume callbacks
+    - s390/zcrypt: use fallthrough;
+    - s390/zcrypt: use kvmalloc instead of kmalloc for 256k alloc
+    - s390/ap: remove power management code from ap bus and drivers
+    - s390/ap: introduce new ap function ap_get_qdev()
+    - s390/zcrypt: use kzalloc
+    - s390/zcrypt: fix smatch warnings
+    - s390/zcrypt: code beautification and struct field renames
+    - s390/zcrypt: split ioctl function into smaller code units
+    - s390/ap: rename and clarify ap state machine related stuff
+    - s390/zcrypt: provide cex4 cca sysfs attributes for cex3
+    - s390/ap: rework crypto config info and default domain code
+    - s390/zcrypt: simplify cca_findcard2 loop code
+    - s390/zcrypt: remove set_fs() invocation in zcrypt device driver
+    - s390/ap: remove unnecessary spin_lock_init()
+    - s390/zcrypt: Support for CCA APKA master keys
+    - s390/zcrypt: introduce msg tracking in zcrypt functions
+    - s390/ap: split ap queue state machine state from device state
+    - s390/ap: add error response code field for ap queue devices
+    - s390/ap: add card/queue deconfig state
+    - s390/sclp: Add support for SCLP AP adapter config/deconfig
+    - s390/ap: Support AP card SCLP config and deconfig operations
+    - s390/ap/zcrypt: revisit ap and zcrypt error handling
+    - s390/zcrypt: move ap_msg param one level up the call chain
+    - s390/zcrypt: Introduce Failure Injection feature
+    - s390/zcrypt: fix wrong format specifications
+    - s390/ap: fix ap devices reference counting
+    - s390/zcrypt: return EIO when msg retry limit reached
+    - s390/zcrypt: fix zcard and zqueue hot-unplug memleak
+    - s390/ap: Fix hanging ioctl caused by wrong msg counter
+  * memfd from ubuntu_kernel_selftests failed to build on B-5.4 (LP: #1926142)
+    - SAUCE: selftests/memfd: fix build when F_SEAL_FUTURE_WRITE is not defined
+  * [SRU] Ice driver causes the kernel to crash with Ubuntu 20.04.2 with ethtool
+    specific register commands (LP: #1939855)
+    - ice: Fix bad register reads
+  * ubunut_kernel_selftests: memory-hotplug: avoid spamming logs with
+    dump_page() (LP: #1941829)
+    - selftests: memory-hotplug: avoid spamming logs with dump_page(), ratio limit
+      hot-remove error test
+  * e1000e blocks the boot process when it tried to write checksum to its NVM
+    (LP: #1936998)
+    - e1000e: Do not take care about recovery NVM checksum
+  * Focal update: v5.4.140 upstream stable release (LP: #1941798)
+    - Revert "ACPICA: Fix memory leak caused by _CID repair function"
+    - ALSA: seq: Fix racy deletion of subscriber
+    - arm64: dts: ls1028a: fix node name for the sysclk
+    - ARM: imx: add missing iounmap()
+    - ARM: imx: add missing clk_disable_unprepare()
+    - ARM: dts: imx6qdl-sr-som: Increase the PHY reset duration to 10ms
+    - ARM: dts: colibri-imx6ull: limit SDIO clock to 25MHz
+    - ARM: imx: fix missing 3rd argument in macro imx_mmdc_perf_init
+    - ARM: dts: imx: Swap M53Menlo pinctrl_power_button/pinctrl_power_out pins
+    - arm64: dts: armada-3720-turris-mox: remove mrvl,i2c-fast-mode
+    - ALSA: usb-audio: fix incorrect clock source setting
+    - clk: stm32f4: fix post divisor setup for I2S/SAI PLLs
+    - ARM: dts: am437x-l4: fix typo in can@0 node
+    - omap5-board-common: remove not physically existing vdds_1v8_main fixed-
+      regulator
+    - spi: imx: mx51-ecspi: Reinstate low-speed CONFIGREG delay
+    - spi: imx: mx51-ecspi: Fix low-speed CONFIGREG delay calculation
+    - scsi: sr: Return correct event when media event code is 3
+    - media: videobuf2-core: dequeue if start_streaming fails
+    - dmaengine: imx-dma: configure the generic DMA type to make it work
+    - net, gro: Set inner transport header offset in tcp/udp GRO hook
+    - net: dsa: sja1105: overwrite dynamic FDB entries with static ones in
+      .port_fdb_add
+    - net: dsa: sja1105: invalidate dynamic FDB entries learned concurrently with
+      statically added ones
+    - net: phy: micrel: Fix detection of ksz87xx switch
+    - net: natsemi: Fix missing pci_disable_device() in probe and remove
+    - gpio: tqmx86: really make IRQ optional
+    - sctp: move the active_key update after sh_keys is added
+    - nfp: update ethtool reporting of pauseframe control
+    - net: ipv6: fix returned variable type in ip6_skb_dst_mtu
+    - mips: Fix non-POSIX regexp
+    - bnx2x: fix an error code in bnx2x_nic_load()
+    - net: pegasus: fix uninit-value in get_interrupt_interval
+    - net: fec: fix use-after-free in fec_drv_remove
+    - net: vxge: fix use-after-free in vxge_device_unregister
+    - blk-iolatency: error out if blk_get_queue() failed in iolatency_set_limit()
+    - Bluetooth: defer cleanup of resources in hci_unregister_dev()
+    - USB: usbtmc: Fix RCU stall warning
+    - USB: serial: option: add Telit FD980 composition 0x1056
+    - USB: serial: ch341: fix character loss at high transfer rates
+    - USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2
+    - firmware_loader: use -ETIMEDOUT instead of -EAGAIN in fw_load_sysfs_fallback
+    - firmware_loader: fix use-after-free in firmware_fallback_sysfs
+    - ALSA: hda/realtek: add mic quirk for Acer SF314-42
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum 600
+    - usb: cdns3: Fixed incorrect gadget state
+    - usb: gadget: f_hid: added GET_IDLE and SET_IDLE handlers
+    - usb: gadget: f_hid: fixed NULL pointer dereference
+    - usb: gadget: f_hid: idle uses the highest byte for duration
+    - usb: otg-fsm: Fix hrtimer list corruption
+    - clk: fix leak on devm_clk_bulk_get_all() unwind
+    - scripts/tracing: fix the bug that can't parse raw_trace_func
+    - tracing / histogram: Give calculation hist_fields a size
+    - optee: Clear stale cache entries during initialization
+    - tee: add tee_shm_alloc_kernel_buf()
+    - optee: Fix memory leak when failing to register shm pages
+    - tpm_ftpm_tee: Free and unregister TEE shared memory during kexec
+    - staging: rtl8723bs: Fix a resource leak in sd_int_dpc
+    - staging: rtl8712: get rid of flush_scheduled_work
+    - media: rtl28xxu: fix zero-length control request
+    - pipe: increase minimum default pipe size to 2 pages
+    - ext4: fix potential htree corruption when growing large_dir directories
+    - serial: tegra: Only print FIFO error message when an error occurs
+    - serial: 8250_mtk: fix uart corruption issue when rx power off
+    - serial: 8250: Mask out floating 16/32-bit bus bits
+    - MIPS: Malta: Do not byte-swap accesses to the CBUS UART
+    - serial: 8250_pci: Enumerate Elkhart Lake UARTs via dedicated driver
+    - serial: 8250_pci: Avoid irq sharing for MSI(-X) interrupts.
+    - timers: Move clearing of base::timer_running under base:: Lock
+    - pcmcia: i82092: fix a null pointer dereference bug
+    - md/raid10: properly indicate failure when ending a failed write request
+    - KVM: x86: accept userspace interrupt only if no event is injected
+    - KVM: Do not leak memory for duplicate debugfs directories
+    - KVM: x86/mmu: Fix per-cpu counter corruption on 32-bit builds
+    - arm64: vdso: Avoid ISB after reading from cntvct_el0
+    - soc: ixp4xx: fix printing resources
+    - spi: meson-spicc: fix memory leak in meson_spicc_remove
+    - soc: ixp4xx/qmgr: fix invalid __iomem access
+    - perf/x86/amd: Don't touch the AMD64_EVENTSEL_HOSTONLY bit inside the guest
+    - bpf, selftests: Adjust few selftest result_unpriv outcomes
+    - libata: fix ata_pio_sector for CONFIG_HIGHMEM
+    - reiserfs: add check for root_inode in reiserfs_fill_super
+    - reiserfs: check directory items on read from disk
+    - virt_wifi: fix error on connect
+    - alpha: Send stop IPI to send to online CPUs
+    - net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and
+      ql_adapter_reset
+    - arm64: fix compat syscall return truncation
+    - Linux 5.4.140
+  * Focal update: v5.4.139 upstream stable release (LP: #1941796)
+    - btrfs: delete duplicated words + other fixes in comments
+    - btrfs: do not commit logs and transactions during link and rename operations
+    - btrfs: fix race causing unnecessary inode logging during link and rename
+    - btrfs: fix lost inode on log replay after mix of fsync, rename and inode
+      eviction
+    - regulator: rt5033: Fix n_voltages settings for BUCK and LDO
+    - spi: stm32h7: fix full duplex irq handler handling
+    - ASoC: tlv320aic31xx: fix reversed bclk/wclk master bits
+    - r8152: Fix potential PM refcount imbalance
+    - qed: fix possible unpaired spin_{un}lock_bh in _qed_mcp_cmd_and_union()
+    - net: Fix zero-copy head len calculation.
+    - nvme: fix nvme_setup_command metadata trace event
+    - ACPI: fix NULL pointer dereference
+    - Revert "Bluetooth: Shutdown controller after workqueues are flushed or
+      cancelled"
+    - firmware: arm_scmi: Ensure drivers provide a probe function
+    - firmware: arm_scmi: Add delayed response status check
+    - bpf: Inherit expanded/patched seen count from old aux data
+    - bpf: Do not mark insn as seen under speculative path verification
+    - bpf: Fix leakage under speculation on mispredicted branches
+    - bpf: Test_verifier, add alu32 bounds tracking tests
+    - bpf, selftests: Add a verifier test for assigning 32bit reg states to 64bit
+      ones
+    - bpf, selftests: Adjust few selftest outcomes wrt unreachable code
+    - spi: mediatek: Fix fifo transfer
+    - Linux 5.4.139
+  * Focal update: v5.4.138 upstream stable release (LP: #1940559)
+    - net_sched: check error pointer in tcf_dump_walker()
+    - x86/asm: Ensure asm/proto.h can be included stand-alone
+    - btrfs: fix rw device counting in __btrfs_free_extra_devids
+    - btrfs: mark compressed range uptodate only if all bio succeed
+    - x86/kvm: fix vcpu-id indexed array sizes
+    - KVM: add missing compat KVM_CLEAR_DIRTY_LOG
+    - ocfs2: fix zero out valid data
+    - ocfs2: issue zeroout to EOF blocks
+    - can: j1939: j1939_xtp_rx_dat_one(): fix rxtimer value between consecutive
+      TP.DT to 750ms
+    - can: raw: raw_setsockopt(): fix raw_rcv panic for sock UAF
+    - can: mcba_usb_start(): add missing urb->transfer_dma initialization
+    - can: usb_8dev: fix memory leak
+    - can: ems_usb: fix memory leak
+    - can: esd_usb2: fix memory leak
+    - HID: wacom: Re-enable touch by default for Cintiq 24HDT / 27QHDT
+    - NIU: fix incorrect error return, missed in previous revert
+    - nfc: nfcsim: fix use after free during module unload
+    - cfg80211: Fix possible memory leak in function cfg80211_bss_update
+    - netfilter: conntrack: adjust stop timestamp to real expiry value
+    - netfilter: nft_nat: allow to specify layer 4 protocol NAT only
+    - i40e: Fix logic of disabling queues
+    - i40e: Fix firmware LLDP agent related warning
+    - i40e: Fix queue-to-TC mapping on Tx
+    - i40e: Fix log TC creation failure when max num of queues is exceeded
+    - tipc: fix sleeping in tipc accept routine
+    - net: Set true network header for ECN decapsulation
+    - mlx4: Fix missing error code in mlx4_load_one()
+    - net: llc: fix skb_over_panic
+    - net/mlx5: Fix flow table chaining
+    - net/mlx5e: Fix nullptr in mlx5e_hairpin_get_mdev()
+    - sctp: fix return value check in __sctp_rcv_asconf_lookup
+    - tulip: windbond-840: Fix missing pci_disable_device() in probe and remove
+    - sis900: Fix missing pci_disable_device() in probe and remove
+    - can: hi311x: fix a signedness bug in hi3110_cmd()
+    - PCI: mvebu: Setup BAR0 in order to fix MSI
+    - powerpc/pseries: Fix regression while building external modules
+    - i40e: Add additional info to PHY type error
+    - can: j1939: j1939_session_deactivate(): clarify lifetime of session object
+    - Linux 5.4.138
+  * Focal update: v5.4.137 upstream stable release (LP: #1940557)
+    - selftest: fix build error in tools/testing/selftests/vm/userfaultfd.c
+    - tools: Allow proper CC/CXX/... override with LLVM=1 in Makefile.include
+    - KVM: x86: determine if an exception has an error code only when injecting
+      it.
+    - af_unix: fix garbage collect vs MSG_PEEK
+    - workqueue: fix UAF in pwq_unbound_release_workfn()
+    - cgroup1: fix leaked context root causing sporadic NULL deref in LTP
+    - net/802/mrp: fix memleak in mrp_request_join()
+    - net/802/garp: fix memleak in garp_request_join()
+    - net: annotate data race around sk_ll_usec
+    - sctp: move 198 addresses from unusable to private scope
+    - ipv6: allocate enough headroom in ip6_finish_output2()
+    - hfs: add missing clean-up in hfs_fill_super
+    - hfs: fix high memory mapping in hfs_bnode_read
+    - hfs: add lock nesting notation to hfs_find_init
+    - firmware: arm_scmi: Fix possible scmi_linux_errmap buffer overflow
+    - firmware: arm_scmi: Fix range check for the maximum number of pending
+      messages
+    - cifs: fix the out of range assignment to bit fields in
+      parse_server_interfaces
+    - iomap: remove the length variable in iomap_seek_data
+    - iomap: remove the length variable in iomap_seek_hole
+    - ARM: dts: versatile: Fix up interrupt controller node names
+    - ipv6: ip6_finish_output2: set sk into newly allocated nskb
+    - Linux 5.4.137
+  * Focal update: v5.4.136 upstream stable release (LP: #1939899)
+    - igc: Fix use-after-free error during reset
+    - igb: Fix use-after-free error during reset
+    - igc: change default return of igc_read_phy_reg()
+    - ixgbe: Fix an error handling path in 'ixgbe_probe()'
+    - igc: Prefer to use the pci_release_mem_regions method
+    - igc: Fix an error handling path in 'igc_probe()'
+    - igb: Fix an error handling path in 'igb_probe()'
+    - fm10k: Fix an error handling path in 'fm10k_probe()'
+    - e1000e: Fix an error handling path in 'e1000_probe()'
+    - iavf: Fix an error handling path in 'iavf_probe()'
+    - igb: Check if num of q_vectors is smaller than max before array access
+    - igb: Fix position of assignment to *ring
+    - gve: Fix an error handling path in 'gve_probe()'
+    - ipv6: fix 'disable_policy' for fwd packets
+    - selftests: icmp_redirect: remove from checking for IPv6 route get
+    - selftests: icmp_redirect: IPv6 PMTU info should be cleared after redirect
+    - pwm: sprd: Ensure configuring period and duty_cycle isn't wrongly skipped
+    - cxgb4: fix IRQ free race during driver unload
+    - nvme-pci: do not call nvme_dev_remove_admin from nvme_remove
+    - perf probe: Fix dso->nsinfo refcounting
+    - perf env: Fix sibling_dies memory leak
+    - perf test session_topology: Delete session->evlist
+    - perf test event_update: Fix memory leak of evlist
+    - perf dso: Fix memory leak in dso__new_map()
+    - perf script: Fix memory 'threads' and 'cpus' leaks on exit
+    - perf lzma: Close lzma stream on exit
+    - perf probe-file: Delete namelist in del_events() on the error path
+    - perf data: Close all files in close_dir()
+    - spi: imx: add a check for speed_hz before calculating the clock
+    - spi: stm32: Use dma_request_chan() instead dma_request_slave_channel()
+    - spi: stm32: fixes pm_runtime calls in probe/remove
+    - regulator: hi6421: Use correct variable type for regmap api val argument
+    - regulator: hi6421: Fix getting wrong drvdata
+    - spi: mediatek: fix fifo rx mode
+    - ASoC: rt5631: Fix regcache sync errors on resume
+    - liquidio: Fix unintentional sign extension issue on left shift of u16
+    - s390/bpf: Perform r1 range checking before accessing jit->seen_reg[r1]
+    - bpf, sockmap, tcp: sk_prot needs inuse_idx set for proc stats
+    - bpftool: Check malloc return value in mount_bpffs_for_pin
+    - net: fix uninit-value in caif_seqpkt_sendmsg
+    - efi/tpm: Differentiate missing and invalid final event log table.
+    - net: decnet: Fix sleeping inside in af_decnet
+    - KVM: PPC: Book3S: Fix CONFIG_TRANSACTIONAL_MEM=n crash
+    - KVM: PPC: Fix kvm_arch_vcpu_ioctl vcpu_load leak
+    - net: sched: fix memory leak in tcindex_partial_destroy_work
+    - netrom: Decrease sock refcount when sock timers expire
+    - scsi: iscsi: Fix iface sysfs attr detection
+    - scsi: target: Fix protect handling in WRITE SAME(32)
+    - spi: cadence: Correct initialisation of runtime PM again
+    - bnxt_en: Improve bnxt_ulp_stop()/bnxt_ulp_start() call sequence.
+    - bnxt_en: Refresh RoCE capabilities in bnxt_ulp_probe()
+    - bnxt_en: Add missing check for BNXT_STATE_ABORT_ERR in bnxt_fw_rset_task()
+    - bnxt_en: Check abort error state in bnxt_half_open_nic()
+    - net: hisilicon: rename CACHE_LINE_MASK to avoid redefinition
+    - net/tcp_fastopen: fix data races around tfo_active_disable_stamp
+    - net: hns3: fix rx VLAN offload state inconsistent issue
+    - net/sched: act_skbmod: Skip non-Ethernet packets
+    - ipv6: fix another slab-out-of-bounds in fib6_nh_flush_exceptions
+    - nvme-pci: don't WARN_ON in nvme_reset_work if ctrl.state is not RESETTING
+    - Revert "USB: quirks: ignore remote wake-up on Fibocom L850-GL LTE modem"
+    - afs: Fix tracepoint string placement with built-in AFS
+    - r8169: Avoid duplicate sysfs entry creation error
+    - nvme: set the PRACT bit when using Write Zeroes with T10 PI
+    - sctp: update active_key for asoc when old key is being replaced
+    - net: sched: cls_api: Fix the the wrong parameter
+    - drm/panel: raspberrypi-touchscreen: Prevent double-free
+    - proc: Avoid mixing integer types in mem_rw()
+    - s390/ftrace: fix ftrace_update_ftrace_func implementation
+    - s390/boot: fix use of expolines in the DMA code
+    - ALSA: usb-audio: Add missing proc text entry for BESPOKEN type
+    - ALSA: usb-audio: Add registration quirk for JBL Quantum headsets
+    - ALSA: sb: Fix potential ABBA deadlock in CSP driver
+    - ALSA: hdmi: Expose all pins on MSI MS-7C94 board
+    - xhci: Fix lost USB 2 remote wake
+    - KVM: PPC: Book3S: Fix H_RTAS rets buffer overflow
+    - KVM: PPC: Book3S HV Nested: Sanitise H_ENTER_NESTED TM state
+    - usb: hub: Disable USB 3 device initiated lpm if exit latency is too high
+    - usb: hub: Fix link power management max exit latency (MEL) calculations
+    - USB: usb-storage: Add LaCie Rugged USB3-FW to IGNORE_UAS
+    - usb: max-3421: Prevent corruption of freed memory
+    - usb: renesas_usbhs: Fix superfluous irqs happen after usb_pkt_pop()
+    - USB: serial: option: add support for u-blox LARA-R6 family
+    - USB: serial: cp210x: fix comments for GE CS1000
+    - USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick
+    - usb: dwc2: gadget: Fix sending zero length packet in DDMA mode.
+    - firmware/efi: Tell memblock about EFI iomem reservations
+    - tracing/histogram: Rename "cpu" to "common_cpu"
+    - tracing: Fix bug in rb_per_cpu_empty() that might cause deadloop.
+    - btrfs: check for missing device in btrfs_trim_fs
+    - media: ngene: Fix out-of-bounds bug in ngene_command_config_free_buf()
+    - ixgbe: Fix packet corruption due to missing DMA sync
+    - selftest: use mmap instead of posix_memalign to allocate memory
+    - userfaultfd: do not untag user pointers
+    - hugetlbfs: fix mount mode command line processing
+    - rbd: don't hold lock_rwsem while running_list is being drained
+    - rbd: always kick acquire on "acquired" and "released" notifications
+    - nds32: fix up stack guard gap
+    - drm: Return -ENOTTY for non-drm ioctls
+    - net: dsa: mv88e6xxx: use correct .stats_set_histogram() on Topaz
+    - net: bcmgenet: ensure EXT_ENERGY_DET_MASK is clear
+    - iio: accel: bma180: Use explicit member assignment
+    - iio: accel: bma180: Fix BMA25x bandwidth register values
+    - btrfs: compression: don't try to compress if we don't have enough pages
+    - PCI: Mark AMD Navi14 GPU ATS as broken
+    - perf inject: Close inject.output on exit
+    - xhci: add xhci_get_virt_ep() helper
+    - Linux 5.4.136
+  * Focal update: v5.4.135 upstream stable release (LP: #1939442)
+    - ARM: dts: gemini: rename mdio to the right name
+    - ARM: dts: gemini: add device_type on pci
+    - ARM: dts: rockchip: fix pinctrl sleep nodename for rk3036-kylin and rk3288
+    - arm64: dts: rockchip: fix pinctrl sleep nodename for rk3399.dtsi
+    - ARM: dts: rockchip: Fix the timer clocks order
+    - ARM: dts: rockchip: Fix IOMMU nodes properties on rk322x
+    - ARM: dts: rockchip: Fix power-controller node names for rk3066a
+    - ARM: dts: rockchip: Fix power-controller node names for rk3188
+    - ARM: dts: rockchip: Fix power-controller node names for rk3288
+    - arm64: dts: rockchip: Fix power-controller node names for px30
+    - arm64: dts: rockchip: Fix power-controller node names for rk3328
+    - reset: ti-syscon: fix to_ti_syscon_reset_data macro
+    - ARM: brcmstb: dts: fix NAND nodes names
+    - ARM: Cygnus: dts: fix NAND nodes names
+    - ARM: NSP: dts: fix NAND nodes names
+    - ARM: dts: BCM63xx: Fix NAND nodes names
+    - ARM: dts: Hurricane 2: Fix NAND nodes names
+    - ARM: dts: imx6: phyFLEX: Fix UART hardware flow control
+    - ARM: imx: pm-imx5: Fix references to imx5_cpu_suspend_info
+    - rtc: mxc_v2: add missing MODULE_DEVICE_TABLE
+    - kbuild: sink stdout from cmd for silent build
+    - ARM: dts: am57xx-cl-som-am57x: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: am437x-gp-evm: fix ti,no-reset-on-init flag for gpios
+    - ARM: dts: stm32: fix gpio-keys node on STM32 MCU boards
+    - ARM: dts: stm32: fix RCC node name on stm32f429 MCU
+    - ARM: dts: stm32: fix timer nodes on STM32 MCU to prevent warnings
+    - arm64: dts: juno: Update SCPI nodes as per the YAML schema
+    - ARM: dts: rockchip: fix supply properties in io-domains nodes
+    - ARM: dts: stm32: fix i2c node name on stm32f746 to prevent warnings
+    - ARM: dts: stm32: move stmmac axi config in ethernet node on stm32mp15
+    - soc/tegra: fuse: Fix Tegra234-only builds
+    - firmware: tegra: bpmp: Fix Tegra234-only builds
+    - arm64: dts: ls208xa: remove bus-num from dspi node
+    - arm64: dts: imx8mq: assign PCIe clocks
+    - thermal/core: Correct function name thermal_zone_device_unregister()
+    - kbuild: mkcompile_h: consider timestamp if KBUILD_BUILD_TIMESTAMP is set
+    - rtc: max77686: Do not enforce (incorrect) interrupt trigger type
+    - scsi: aic7xxx: Fix unintentional sign extension issue on left shift of u8
+    - scsi: libsas: Add LUN number check in .slave_alloc callback
+    - scsi: libfc: Fix array index out of bound exception
+    - scsi: qedf: Add check to synchronize abort and flush
+    - sched/fair: Fix CFS bandwidth hrtimer expiry type
+    - s390: introduce proper type handling call_on_stack() macro
+    - cifs: prevent NULL deref in cifs_compose_mount_options()
+    - arm64: dts: armada-3720-turris-mox: add firmware node
+    - firmware: turris-mox-rwtm: add marvell,armada-3700-rwtm-firmware compatible
+      string
+    - arm64: dts: marvell: armada-37xx: move firmware node to generic dtsi file
+    - f2fs: Show casefolding support only when supported
+    - usb: cdns3: Enable TDL_CHK only for OUT ep
+    - Revert "UBUNTU: SAUCE: Revert "mm: memcg/slab: fix memory leak at non-root
+      kmem_cache destroy""
+    - mm: slab: fix kmem_cache_create failed when sysfs node not destroyed
+    - dm writecache: return the exact table values that were set
+    - net: dsa: mv88e6xxx: enable .port_set_policy() on Topaz
+    - net: dsa: mv88e6xxx: enable .rmu_disable() on Topaz
+    - net: ipv6: fix return value of ip6_skb_dst_mtu
+    - netfilter: ctnetlink: suspicious RCU usage in ctnetlink_dump_helpinfo
+    - net/sched: act_ct: fix err check for nf_conntrack_confirm
+    - net: bridge: sync fdb to new unicast-filtering ports
+    - net: bcmgenet: Ensure all TX/RX queues DMAs are disabled
+    - net: ip_tunnel: fix mtu calculation for ETHER tunnel devices
+    - net: moxa: fix UAF in moxart_mac_probe
+    - net: qcom/emac: fix UAF in emac_remove
+    - net: ti: fix UAF in tlan_remove_one
+    - net: send SYNACK packet with accepted fwmark
+    - net: validate lwtstate->data before returning from skb_tunnel_info()
+    - net: fddi: fix UAF in fza_probe
+    - dma-buf/sync_file: Don't leak fences on merge failure
+    - tcp: annotate data races around tp->mtu_info
+    - ipv6: tcp: drop silly ICMPv6 packet too big messages
+    - bpftool: Properly close va_list 'ap' by va_end() on error
+    - perf test bpf: Free obj_buf
+    - udp: annotate data races around unix_sk(sk)->gso_size
+    - Linux 5.4.135
+  * Focal update: v5.4.134 upstream stable release (LP: #1939440)
+    - KVM: mmio: Fix use-after-free Read in kvm_vm_ioctl_unregister_coalesced_mmio
+    - KVM: x86: Use guest MAXPHYADDR from CPUID.0x8000_0008 iff TDP is enabled
+    - KVM: X86: Disable hardware breakpoints unconditionally before kvm_x86->run()
+    - scsi: core: Fix bad pointer dereference when ehandler kthread is invalid
+    - tracing: Do not reference char * as a string in histograms
+    - cgroup: verify that source is a string
+    - fbmem: Do not delete the mode that is still in use
+    - net: moxa: Use devm_platform_get_and_ioremap_resource()
+    - dmaengine: fsl-qdma: check dma_set_mask return value
+    - srcu: Fix broken node geometry after early ssp init
+    - tty: serial: fsl_lpuart: fix the potential risk of division or modulo by
+      zero
+    - misc/libmasm/module: Fix two use after free in ibmasm_init_one
+    - misc: alcor_pci: fix null-ptr-deref when there is no PCI bridge
+    - iio: gyro: fxa21002c: Balance runtime pm + use pm_runtime_resume_and_get().
+    - iio: magn: bmc150: Balance runtime pm + use pm_runtime_resume_and_get()
+    - ALSA: usx2y: Don't call free_pages_exact() with NULL address
+    - Revert "ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro"
+    - w1: ds2438: fixing bug that would always get page0
+    - scsi: hisi_sas: Propagate errors in interrupt_init_v1_hw()
+    - scsi: lpfc: Fix "Unexpected timeout" error in direct attach topology
+    - scsi: lpfc: Fix crash when lpfc_sli4_hba_setup() fails to initialize the
+      SGLs
+    - scsi: core: Cap scsi_host cmd_per_lun at can_queue
+    - ALSA: ac97: fix PM reference leak in ac97_bus_remove()
+    - tty: serial: 8250: serial_cs: Fix a memory leak in error handling path
+    - scsi: scsi_dh_alua: Check for negative result value
+    - fs/jfs: Fix missing error code in lmLogInit()
+    - scsi: megaraid_sas: Fix resource leak in case of probe failure
+    - scsi: megaraid_sas: Early detection of VD deletion through RaidMap update
+    - scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs
+    - scsi: iscsi: Add iscsi_cls_conn refcount helpers
+    - scsi: iscsi: Fix conn use after free during resets
+    - scsi: iscsi: Fix shost->max_id use
+    - scsi: qedi: Fix null ref during abort handling
+    - mfd: da9052/stmpe: Add and modify MODULE_DEVICE_TABLE
+    - mfd: cpcap: Fix cpcap dmamask not set warnings
+    - ASoC: img: Fix PM reference leak in img_i2s_in_probe()
+    - serial: tty: uartlite: fix console setup
+    - s390/sclp_vt220: fix console name to match device
+    - ALSA: sb: Fix potential double-free of CSP mixer elements
+    - powerpc/ps3: Add dma_mask to ps3_dma_region
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak when arm_smmu_rpm_get
+      fails
+    - iommu/arm-smmu: Fix arm_smmu_device refcount leak in address translation
+    - gpio: zynq: Check return value of pm_runtime_get_sync
+    - ALSA: ppc: fix error return code in snd_pmac_probe()
+    - selftests/powerpc: Fix "no_handler" EBB selftest
+    - gpio: pca953x: Add support for the On Semi pca9655
+    - ASoC: soc-core: Fix the error return code in
+      snd_soc_of_parse_audio_routing()
+    - s390/processor: always inline stap() and __load_psw_mask()
+    - s390/ipl_parm: fix program check new psw handling
+    - s390/mem_detect: fix diag260() program check new psw handling
+    - s390/mem_detect: fix tprot() program check new psw handling
+    - Input: hideep - fix the uninitialized use in hideep_nvm_unlock()
+    - ALSA: bebob: add support for ToneWeal FW66
+    - ALSA: usb-audio: scarlett2: Fix 18i8 Gen 2 PCM Input count
+    - ALSA: usb-audio: scarlett2: Fix data_mutex lock
+    - ALSA: usb-audio: scarlett2: Fix scarlett2_*_ctl_put() return values
+    - usb: gadget: f_hid: fix endianness issue with descriptors
+    - usb: gadget: hid: fix error return code in hid_bind()
+    - powerpc/boot: Fixup device-tree on little endian
+    - ASoC: Intel: kbl_da7219_max98357a: shrink platform_id below 20 characters
+    - backlight: lm3630a: Fix return code of .update_status() callback
+    - ALSA: hda: Add IRQ check for platform_get_irq()
+    - ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions
+    - staging: rtl8723bs: fix macro value for 2.4Ghz only device
+    - intel_th: Wait until port is in reset before programming it
+    - i2c: core: Disable client irq on reboot/shutdown
+    - power: supply: sc27xx: Add missing MODULE_DEVICE_TABLE
+    - power: supply: sc2731_charger: Add missing MODULE_DEVICE_TABLE
+    - pwm: spear: Don't modify HW state in .remove callback
+    - power: supply: ab8500: Avoid NULL pointers
+    - power: supply: max17042: Do not enforce (incorrect) interrupt trigger type
+    - power: reset: gpio-poweroff: add missing MODULE_DEVICE_TABLE
+    - ARM: 9087/1: kprobes: test-thumb: fix for LLVM_IAS=1
+    - PCI/P2PDMA: Avoid pci_get_slot(), which may sleep
+    - watchdog: Fix possible use-after-free in wdt_startup()
+    - watchdog: sc520_wdt: Fix possible use-after-free in wdt_turnoff()
+    - watchdog: Fix possible use-after-free by calling del_timer_sync()
+    - watchdog: imx_sc_wdt: fix pretimeout
+    - x86/fpu: Return proper error codes from user access functions
+    - PCI: tegra: Add missing MODULE_DEVICE_TABLE
+    - orangefs: fix orangefs df output.
+    - ceph: remove bogus checks and WARN_ONs from ceph_set_page_dirty
+    - NFS: nfs_find_open_context() may only select open files
+    - power: supply: charger-manager: add missing MODULE_DEVICE_TABLE
+    - power: supply: ab8500: add missing MODULE_DEVICE_TABLE
+    - pwm: img: Fix PM reference leak in img_pwm_enable()
+    - pwm: tegra: Don't modify HW state in .remove callback
+    - ACPI: AMBA: Fix resource name in /proc/iomem
+    - ACPI: video: Add quirk for the Dell Vostro 3350
+    - virtio-blk: Fix memory leak among suspend/resume procedure
+    - virtio_net: Fix error handling in virtnet_restore()
+    - virtio_console: Assure used length from device is limited
+    - x86/signal: Detect and prevent an alternate signal stack overflow
+    - f2fs: add MODULE_SOFTDEP to ensure crc32 is included in the initramfs
+    - PCI/sysfs: Fix dsm_label_utf16s_to_utf8s() buffer overrun
+    - power: supply: rt5033_battery: Fix device tree enumeration
+    - NFSv4: Initialise connection to the server in nfs4_alloc_client()
+    - um: fix error return code in slip_open()
+    - um: fix error return code in winch_tramp()
+    - watchdog: aspeed: fix hardware timeout calculation
+    - nfs: fix acl memory leak of posix_acl_create()
+    - ubifs: Set/Clear I_LINKABLE under i_lock for whiteout inode
+    - PCI: iproc: Fix multi-MSI base vector number allocation
+    - PCI: iproc: Support multi-MSI only on uniprocessor kernel
+    - x86/fpu: Limit xstate copy size in xstateregs_set()
+    - pwm: imx1: Don't disable clocks at device remove time
+    - virtio_net: move tx vq operation under tx queue lock
+    - nvme-tcp: can't set sk_user_data without write_lock
+    - ALSA: isa: Fix error return code in snd_cmi8330_probe()
+    - NFSv4/pNFS: Don't call _nfs4_pnfs_v3_ds_connect multiple times
+    - hexagon: use common DISCARDS macro
+    - ARM: dts: gemini-rut1xx: remove duplicate ethernet node
+    - reset: a10sr: add missing of_match_table reference
+    - ARM: exynos: add missing of_node_put for loop iteration
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU/XU3
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid HC1
+    - ARM: dts: exynos: fix PWM LED max brightness on Odroid XU4
+    - memory: atmel-ebi: add missing of_node_put for loop iteration
+    - reset: brcmstb: Add missing MODULE_DEVICE_TABLE
+    - memory: pl353: Fix error return code in pl353_smc_probe()
+    - rtc: fix snprintf() checking in is_rtc_hctosys()
+    - arm64: dts: renesas: v3msk: Fix memory size
+    - ARM: dts: r8a7779, marzen: Fix DU clock names
+    - firmware: tegra: Fix error return code in tegra210_bpmp_init()
+    - firmware: arm_scmi: Reset Rx buffer to max size during async commands
+    - ARM: dts: BCM5301X: Fixup SPI binding
+    - reset: bail if try_module_get() fails
+    - memory: fsl_ifc: fix leak of IO mapping on probe failure
+    - memory: fsl_ifc: fix leak of private memory on probe failure
+    - ARM: dts: am335x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: am437x: align ti,pindir-d0-out-d1-in property with dt-shema
+    - ARM: dts: imx6q-dhcom: Fix ethernet reset time properties
+    - ARM: dts: imx6q-dhcom: Fix ethernet plugin detection problems
+    - ARM: dts: imx6q-dhcom: Add gpios pinctrl for i2c bus recovery
+    - thermal/drivers/rcar_gen3_thermal: Fix coefficient calculations
+    - firmware: turris-mox-rwtm: fix reply status decoding function
+    - firmware: turris-mox-rwtm: report failures better
+    - firmware: turris-mox-rwtm: fail probing when firmware does not support hwrng
+    - scsi: be2iscsi: Fix an error handling path in beiscsi_dev_probe()
+    - mips: always link byteswap helpers into decompressor
+    - mips: disable branch profiling in boot/decompress.o
+    - MIPS: vdso: Invalid GIC access through VDSO
+    - scsi: scsi_dh_alua: Fix signedness bug in alua_rtpg()
+    - misc: alcor_pci: fix inverted branch condition
+    - Linux 5.4.134
+
+  [ Ubuntu: 5.4.0-86.97 ]
+
+  * 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
+
+  [ Ubuntu: 5.4.0-84.94 ]
+
+  * focal/linux: 5.4.0-84.94 -proposed tracker (LP: #1941767)
+  * Server boot failure after adding checks for ACPI IRQ override (LP: #1941657)
+    - Revert "ACPI: resources: Add checks for ACPI IRQ override"
+
+  [ Ubuntu: 5.4.0-83.93 ]
+
+  * focal/linux: 5.4.0-83.93 -proposed tracker (LP: #1940159)
+  * fails to launch linux L2 guests on AMD (LP: #1940134) // CVE-2021-3653
+    - KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+      (CVE-2021-3653)
+  * fails to launch linux L2 guests on AMD (LP: #1940134)
+    - SAUCE: Revert "UBUNTU: SAUCE: KVM: nSVM: avoid picking up unsupported bits
+      from L2 in int_ctl"
+
+  [ Ubuntu: 5.4.0-82.92 ]
+
+  * focal/linux: 5.4.0-82.92 -proposed tracker (LP: #1939799)
+  * Packaging resync (LP: #1786013)
+    - debian/dkms-versions -- update from kernel-versions (main/2021.08.16)
+  * CVE-2021-3656
+    - SAUCE: KVM: nSVM: always intercept VMLOAD/VMSAVE when nested
+  * CVE-2021-3653
+    - SAUCE: KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl
+  * [regression] USB device is not detected during boot (LP: #1939638)
+    - SAUCE: Revert "usb: core: reduce power-on-good delay time of root hub"
+  * dev_forward_skb: do not scrub skb mark within the same name space
+    (LP: #1935040)
+    - dev_forward_skb: do not scrub skb mark within the same name space
+  * XPS 9510 (TGL) Screen Brightness could not be changed (LP: #1933566)
+    - SAUCE: drm/i915: Force DPCD backlight mode for Dell XPS 9510(TGL)
+  * Acer Aspire 5 sound driver issues (LP: #1930188)
+    - ALSA: hda/realtek: headphone and mic don't work on an Acer laptop
+  * Sony Dualshock 4 usb dongle crashes the whole system (LP: #1935846)
+    - HID: sony: Workaround for DS4 dongle hotplug kernel crash.
+  * [21.10 FEAT] KVM: Provide a secure guest indication (LP: #1933173)
+    - s390/uv: add prot virt guest/host indication files
+    - s390/uv: fix prot virt host indication compilation
+  * Skip rtcpie test in kselftests/timers if the default RTC device does not
+    exist (LP: #1937991)
+    - selftests: timers: rtcpie: skip test if default RTC device does not exist
+  * Focal update: v5.4.133 upstream stable release (LP: #1938713)
+    - drm/mxsfb: Don't select DRM_KMS_FB_HELPER
+    - drm/zte: Don't select DRM_KMS_FB_HELPER
+    - drm/amd/amdgpu/sriov disable all ip hw status by default
+    - drm/vc4: fix argument ordering in vc4_crtc_get_margins()
+    - net: pch_gbe: Use proper accessors to BE data in pch_ptp_match()
+    - drm/amd/display: fix use_max_lb flag for 420 pixel formats
+    - hugetlb: clear huge pte during flush function on mips platform
+    - atm: iphase: fix possible use-after-free in ia_module_exit()
+    - mISDN: fix possible use-after-free in HFC_cleanup()
+    - atm: nicstar: Fix possible use-after-free in nicstar_cleanup()
+    - net: Treat __napi_schedule_irqoff() as __napi_schedule() on PREEMPT_RT
+    - drm/mediatek: Fix PM reference leak in mtk_crtc_ddp_hw_init()
+    - reiserfs: add check for invalid 1st journal block
+    - drm/virtio: Fix double free on probe failure
+    - drm/sched: Avoid data corruptions
+    - udf: Fix NULL pointer dereference in udf_symlink function
+    - e100: handle eeprom as little endian
+    - igb: handle vlan types with checker enabled
+    - drm/bridge: cdns: Fix PM reference leak in cdns_dsi_transfer()
+    - clk: renesas: r8a77995: Add ZA2 clock
+    - clk: tegra: Ensure that PLLU configuration is applied properly
+    - ipv6: use prandom_u32() for ID generation
+    - RDMA/cxgb4: Fix missing error code in create_qp()
+    - dm space maps: don't reset space map allocation cursor when committing
+    - pinctrl: mcp23s08: fix race condition in irq handler
+    - ice: set the value of global config lock timeout longer
+    - virtio_net: Remove BUG() to avoid machine dead
+    - net: bcmgenet: check return value after calling platform_get_resource()
+    - net: mvpp2: check return value after calling platform_get_resource()
+    - net: micrel: check return value after calling platform_get_resource()
+    - drm/amd/display: Update scaling settings on modeset
+    - drm/amd/display: Release MST resources on switch from MST to SST
+    - drm/amd/display: Set DISPCLK_MAX_ERRDET_CYCLES to 7
+    - drm/amdkfd: use allowed domain for vmbo validation
+    - fjes: check return value after calling platform_get_resource()
+    - selinux: use __GFP_NOWARN with GFP_NOWAIT in the AVC
+    - r8169: avoid link-up interrupt issue on RTL8106e if user enables ASPM
+    - drm/amd/display: Verify Gamma & Degamma LUT sizes in amdgpu_dm_atomic_check
+    - xfrm: Fix error reporting in xfrm_state_construct.
+    - wlcore/wl12xx: Fix wl12xx get_mac error if device is in ELP
+    - wl1251: Fix possible buffer overflow in wl1251_cmd_scan
+    - cw1200: add missing MODULE_DEVICE_TABLE
+    - bpf: Fix up register-based shifts in interpreter to silence KUBSAN
+    - mt76: mt7615: fix fixed-rate tx status reporting
+    - net: fix mistake path for netdev_features_strings
+    - net: sched: fix error return code in tcf_del_walker()
+    - drm/amdkfd: Walk through list with dqm lock hold
+    - rtl8xxxu: Fix device info for RTL8192EU devices
+    - atm: nicstar: use 'dma_free_coherent' instead of 'kfree'
+    - atm: nicstar: register the interrupt handler in the right place
+    - vsock: notify server to shutdown when client has pending signal
+    - RDMA/rxe: Don't overwrite errno from ib_umem_get()
+    - iwlwifi: mvm: don't change band on bound PHY contexts
+    - iwlwifi: pcie: free IML DMA memory allocation
+    - iwlwifi: pcie: fix context info freeing
+    - sfc: avoid double pci_remove of VFs
+    - sfc: error code if SRIOV cannot be disabled
+    - wireless: wext-spy: Fix out-of-bounds warning
+    - media, bpf: Do not copy more entries than user space requested
+    - net: ip: avoid OOM kills with large UDP sends over loopback
+    - RDMA/cma: Fix rdma_resolve_route() memory leak
+    - Bluetooth: btusb: Fixed too many in-token issue for Mediatek Chip.
+    - Bluetooth: Fix the HCI to MGMT status conversion table
+    - Bluetooth: Shutdown controller after workqueues are flushed or cancelled
+    - Bluetooth: btusb: fix bt fiwmare downloading failure issue for qca btsoc.
+    - sctp: validate from_addr_param return
+    - sctp: add size validation when walking chunks
+    - MIPS: loongsoon64: Reserve memory below starting pfn to prevent Oops
+    - MIPS: set mips32r5 for virt extensions
+    - fscrypt: don't ignore minor_hash when hash is 0
+    - crypto: ccp - Annotate SEV Firmware file names
+    - perf bench: Fix 2 memory sanitizer warnings
+    - powerpc/mm: Fix lockup on kernel exec fault
+    - powerpc/barrier: Avoid collision with clang's __lwsync macro
+    - drm/amdgpu: Update NV SIMD-per-CU to 2
+    - drm/radeon: Add the missed drm_gem_object_put() in
+      radeon_user_framebuffer_create()
+    - drm/rockchip: dsi: remove extra component_del() call
+    - drm/amd/display: fix incorrrect valid irq check
+    - pinctrl/amd: Add device HID for new AMD GPIO controller
+    - drm/tegra: Don't set allow_fb_modifiers explicitly
+    - drm/msm/mdp4: Fix modifier support enabling
+    - drm/arm/malidp: Always list modifiers
+    - mmc: sdhci: Fix warning message when accessing RPMB in HS400 mode
+    - mmc: core: clear flags before allowing to retune
+    - mmc: core: Allow UHS-I voltage switch for SDSC cards if supported
+    - ata: ahci_sunxi: Disable DIPM
+    - cpu/hotplug: Cure the cpusets trainwreck
+    - clocksource/arm_arch_timer: Improve Allwinner A64 timer workaround
+    - fpga: stratix10-soc: Add missing fpga_mgr_free() call
+    - MIPS: fix "mipsel-linux-ld: decompress.c:undefined reference to `memmove'"
+    - ASoC: tegra: Set driver_name=tegra for all machine drivers
+    - qemu_fw_cfg: Make fw_cfg_rev_attr a proper kobj_attribute
+    - ipmi/watchdog: Stop watchdog timer when the current action is 'none'
+    - thermal/drivers/int340x/processor_thermal: Fix tcc setting
+    - ubifs: Fix races between xattr_{set|get} and listxattr operations
+    - power: supply: ab8500: Fix an old bug
+    - nvmem: core: add a missing of_node_put
+    - extcon: intel-mrfld: Sync hardware and software state on init
+    - seq_buf: Fix overflow in seq_buf_putmem_hex()
+    - rq-qos: fix missed wake-ups in rq_qos_throttle try two
+    - tracing: Simplify & fix saved_tgids logic
+    - tracing: Resize tgid_map to pid_max, not PID_MAX_DEFAULT
+    - ipack/carriers/tpci200: Fix a double free in tpci200_pci_probe
+    - coresight: tmc-etf: Fix global-out-of-bounds in tmc_update_etf_buffer()
+    - dm btree remove: assign new_root only when removal succeeds
+    - PCI: Leave Apple Thunderbolt controllers on for s2idle or standby
+    - PCI: aardvark: Fix checking for PIO Non-posted Request
+    - PCI: aardvark: Implement workaround for the readback value of VEND_ID
+    - media: subdev: disallow ioctl for saa6588/davinci
+    - media: dtv5100: fix control-request directions
+    - media: zr364xx: fix memory leak in zr364xx_start_readpipe
+    - media: gspca/sq905: fix control-request direction
+    - media: gspca/sunplus: fix zero-length control requests
+    - pinctrl: mcp23s08: Fix missing unlock on error in mcp23s08_irq()
+    - jfs: fix GPF in diFree
+    - smackfs: restrict bytes count in smk_set_cipso()
+    - Linux 5.4.133
+  * Focal update: v5.4.132 upstream stable release (LP: #1938199)
+    - ALSA: usb-audio: fix rate on Ozone Z90 USB headset
+    - ALSA: usb-audio: Fix OOB access at proc output
+    - ALSA: usb-audio: scarlett2: Fix wrong resume call
+    - ALSA: intel8x0: Fix breakage at ac97 clock measurement
+    - ALSA: hda/realtek: Add another ALC236 variant support
+    - ALSA: hda/realtek: Improve fixup for HP Spectre x360 15-df0xxx
+    - ALSA: hda/realtek: Fix bass speaker DAC mapping for Asus UM431D
+    - ALSA: hda/realtek: Apply LED fixup for HP Dragonfly G1, too
+    - media: dvb-usb: fix wrong definition
+    - Input: usbtouchscreen - fix control-request directions
+    - net: can: ems_usb: fix use-after-free in ems_usb_disconnect()
+    - usb: gadget: eem: fix echo command packet response issue
+    - USB: cdc-acm: blacklist Heimann USB Appset device
+    - usb: dwc3: Fix debugfs creation flow
+    - usb: typec: Add the missed altmode_id_remove() in typec_register_altmode()
+    - xhci: solve a double free problem while doing s4
+    - ntfs: fix validity check for file name attribute
+    - copy_page_to_iter(): fix ITER_DISCARD case
+    - iov_iter_fault_in_readable() should do nothing in xarray case
+    - Input: joydev - prevent use of not validated data in JSIOCSBTNMAP ioctl
+    - arm_pmu: Fix write counter incorrect in ARMv7 big-endian mode
+    - ARM: dts: at91: sama5d4: fix pinctrl muxing
+    - btrfs: send: fix invalid path for unlink operations after parent
+      orphanization
+    - btrfs: clear defrag status of a root if starting transaction fails
+    - ext4: cleanup in-core orphan list if ext4_truncate() failed to get a
+      transaction handle
+    - ext4: fix kernel infoleak via ext4_extent_header
+    - ext4: return error code when ext4_fill_flex_info() fails
+    - ext4: correct the cache_nr in tracepoint ext4_es_shrink_exit
+    - ext4: remove check for zero nr_to_scan in ext4_es_scan()
+    - ext4: fix avefreec in find_group_orlov
+    - ext4: use ext4_grp_locked_error in mb_find_extent
+    - can: gw: synchronize rcu operations before removing gw job entry
+    - can: j1939: j1939_sk_init(): set SOCK_RCU_FREE to call sk_destruct() after
+      RCU is done
+    - can: peak_pciefd: pucan_handle_status(): fix a potential starvation issue in
+      TX path
+    - mac80211: remove iwlwifi specific workaround that broke sta NDP tx
+    - SUNRPC: Fix the batch tasks count wraparound.
+    - SUNRPC: Should wake up the privileged task firstly.
+    - perf/smmuv3: Don't trample existing events with global filter
+    - KVM: PPC: Book3S HV: Workaround high stack usage with clang
+    - s390/cio: dont call css_wait_for_slow_path() inside a lock
+    - rtc: stm32: Fix unbalanced clk_disable_unprepare() on probe error path
+    - iio: light: tcs3472: do not free unallocated IRQ
+    - iio: ltr501: mark register holding upper 8 bits of ALS_DATA{0,1} and PS_DATA
+      as volatile, too
+    - iio: ltr501: ltr559: fix initialization of LTR501_ALS_CONTR
+    - iio: ltr501: ltr501_read_ps(): add missing endianness conversion
+    - serial: mvebu-uart: fix calculation of clock divisor
+    - serial: sh-sci: Stop dmaengine transfer in sci_stop_tx()
+    - serial_cs: Add Option International GSM-Ready 56K/ISDN modem
+    - serial_cs: remove wrong GLOBETROTTER.cis entry
+    - ath9k: Fix kernel NULL pointer dereference during ath_reset_internal()
+    - ssb: sdio: Don't overwrite const buffer if block_write fails
+    - rsi: Assign beacon rate settings to the correct rate_info descriptor field
+    - rsi: fix AP mode with WPA failure due to encrypted EAPOL
+    - tracing/histograms: Fix parsing of "sym-offset" modifier
+    - tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing
+    - seq_buf: Make trace_seq_putmem_hex() support data longer than 8
+    - powerpc/stacktrace: Fix spurious "stale" traces in raise_backtrace_ipi()
+    - evm: Execute evm_inode_init_security() only when an HMAC key is loaded
+    - evm: Refuse EVM_ALLOW_METADATA_WRITES only if an HMAC key is loaded
+    - fuse: ignore PG_workingset after stealing
+    - fuse: check connected before queueing on fpq->io
+    - fuse: reject internal errno
+    - spi: Make of_register_spi_device also set the fwnode
+    - media: mdk-mdp: fix pm_runtime_get_sync() usage count
+    - media: s5p: fix pm_runtime_get_sync() usage count
+    - media: sh_vou: fix pm_runtime_get_sync() usage count
+    - media: mtk-vcodec: fix PM runtime get logic
+    - media: s5p-jpeg: fix pm_runtime_get_sync() usage count
+    - media: sti/bdisp: fix pm_runtime_get_sync() usage count
+    - media: exynos-gsc: fix pm_runtime_get_sync() usage count
+    - spi: spi-loopback-test: Fix 'tx_buf' might be 'rx_buf'
+    - spi: spi-topcliff-pch: Fix potential double free in
+      pch_spi_process_messages()
+    - spi: omap-100k: Fix the length judgment problem
+    - regulator: uniphier: Add missing MODULE_DEVICE_TABLE
+    - hwrng: exynos - Fix runtime PM imbalance on error
+    - crypto: nx - add missing MODULE_DEVICE_TABLE
+    - media: sti: fix obj-$(config) targets
+    - media: cpia2: fix memory leak in cpia2_usb_probe
+    - media: cobalt: fix race condition in setting HPD
+    - media: pvrusb2: fix warning in pvr2_i2c_core_done
+    - media: imx: imx7_mipi_csis: Fix logging of only error event counters
+    - crypto: qat - check return code of qat_hal_rd_rel_reg()
+    - crypto: qat - remove unused macro in FW loader
+    - sched/fair: Fix ascii art by relpacing tabs
+    - media: em28xx: Fix possible memory leak of em28xx struct
+    - media: v4l2-core: Avoid the dangling pointer in v4l2_fh_release
+    - media: bt8xx: Fix a missing check bug in bt878_probe
+    - media: st-hva: Fix potential NULL pointer dereferences
+    - Makefile: fix GDB warning with CONFIG_RELR
+    - media: dvd_usb: memory leak in cinergyt2_fe_attach
+    - memstick: rtsx_usb_ms: fix UAF
+    - mmc: sdhci-sprd: use sdhci_sprd_writew
+    - mmc: via-sdmmc: add a check against NULL pointer dereference
+    - crypto: shash - avoid comparing pointers to exported functions under CFI
+    - media: dvb_net: avoid speculation from net slot
+    - media: siano: fix device register error path
+    - media: imx-csi: Skip first few frames from a BT.656 source
+    - hwmon: (max31790) Report correct current pwm duty cycles
+    - hwmon: (max31790) Fix pwmX_enable attributes
+    - drivers/perf: fix the missed ida_simple_remove() in ddr_perf_probe()
+    - KVM: PPC: Book3S HV: Fix TLB management on SMT8 POWER9 and POWER10
+      processors
+    - btrfs: fix error handling in __btrfs_update_delayed_inode
+    - btrfs: abort transaction if we fail to update the delayed inode
+    - btrfs: disable build on platforms having page size 256K
+    - locking/lockdep: Fix the dep path printing for backwards BFS
+    - lockding/lockdep: Avoid to find wrong lock dep path in check_irq_usage()
+    - KVM: s390: get rid of register asm usage
+    - regulator: mt6358: Fix vdram2 .vsel_mask
+    - regulator: da9052: Ensure enough delay time for .set_voltage_time_sel
+    - media: Fix Media Controller API config checks
+    - HID: do not use down_interruptible() when unbinding devices
+    - EDAC/ti: Add missing MODULE_DEVICE_TABLE
+    - ACPI: processor idle: Fix up C-state latency if not ordered
+    - hv_utils: Fix passing zero to 'PTR_ERR' warning
+    - lib: vsprintf: Fix handling of number field widths in vsscanf
+    - ACPI: EC: Make more Asus laptops use ECDT _GPE
+    - block_dump: remove block_dump feature in mark_inode_dirty()
+    - fs: dlm: cancel work sync othercon
+    - random32: Fix implicit truncation warning in prandom_seed_state()
+    - fs: dlm: fix memory leak when fenced
+    - ACPICA: Fix memory leak caused by _CID repair function
+    - ACPI: bus: Call kobject_put() in acpi_init() error path
+    - block: fix race between adding/removing rq qos and normal IO
+    - platform/x86: toshiba_acpi: Fix missing error code in
+      toshiba_acpi_setup_keyboard()
+    - nvmet-fc: do not check for invalid target port in nvmet_fc_handle_fcp_rqst()
+    - EDAC/Intel: Do not load EDAC driver when running as a guest
+    - PCI: hv: Add check for hyperv_initialized in init_hv_pci_drv()
+    - clocksource: Retry clock read if long delays detected
+    - ACPI: tables: Add custom DSDT file as makefile prerequisite
+    - HID: wacom: Correct base usage for capacitive ExpressKey status bits
+    - cifs: fix missing spinlock around update to ses->status
+    - block: fix discard request merge
+    - kthread_worker: fix return value when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - ia64: mca_drv: fix incorrect array size calculation
+    - writeback, cgroup: increment isw_nr_in_flight before grabbing an inode
+    - media: s5p_cec: decrement usage count if disabled
+    - crypto: ixp4xx - dma_unmap the correct address
+    - crypto: ux500 - Fix error return code in hash_hw_final()
+    - sata_highbank: fix deferred probing
+    - pata_rb532_cf: fix deferred probing
+    - media: I2C: change 'RST' to "RSET" to fix multiple build errors
+    - sched/uclamp: Fix wrong implementation of cpu.uclamp.min
+    - sched/uclamp: Fix locking around cpu_util_update_eff()
+    - kbuild: run the checker after the compiler
+    - kbuild: Fix objtool dependency for 'OBJECT_FILES_NON_STANDARD_<obj> := n'
+    - pata_octeon_cf: avoid WARN_ON() in ata_host_activate()
+    - evm: fix writing <securityfs>/evm overflow
+    - crypto: ccp - Fix a resource leak in an error handling path
+    - media: rc: i2c: Fix an error message
+    - pata_ep93xx: fix deferred probing
+    - media: exynos4-is: Fix a use after free in isp_video_release
+    - media: au0828: fix a NULL vs IS_ERR() check
+    - media: tc358743: Fix error return code in tc358743_probe_of()
+    - media: gspca/gl860: fix zero-length control requests
+    - m68k: atari: Fix ATARI_KBD_CORE kconfig unmet dependency warning
+    - media: siano: Fix out-of-bounds warnings in smscore_load_firmware_family2()
+    - crypto: nitrox - fix unchecked variable in nitrox_register_interrupts
+    - crypto: omap-sham - Fix PM reference leak in omap sham ops
+    - mmc: usdhi6rol0: fix error return code in usdhi6_probe()
+    - arm64: consistently use reserved_pg_dir
+    - arm64/mm: Fix ttbr0 values stored in struct thread_info for software-pan
+    - media: s5p-g2d: Fix a memory leak on ctx->fh.m2m_ctx
+    - hwmon: (max31722) Remove non-standard ACPI device IDs
+    - hwmon: (max31790) Fix fan speed reporting for fan7..12
+    - KVM: nVMX: Ensure 64-bit shift when checking VMFUNC bitmap
+    - regulator: hi655x: Fix pass wrong pointer to config.driver_data
+    - btrfs: clear log tree recovering status if starting transaction fails
+    - sched/rt: Fix RT utilization tracking during policy change
+    - sched/rt: Fix Deadline utilization tracking during policy change
+    - sched/uclamp: Fix uclamp_tg_restrict()
+    - spi: spi-sun6i: Fix chipselect/clock bug
+    - crypto: nx - Fix RCU warning in nx842_OF_upd_status
+    - ACPI: sysfs: Fix a buffer overrun problem with description_show()
+    - extcon: extcon-max8997: Fix IRQ freeing at error path
+    - blk-wbt: introduce a new disable state to prevent false positive by
+      rwb_enabled()
+    - blk-wbt: make sure throttle is enabled properly
+    - ACPI: Use DEVICE_ATTR_<RW|RO|WO> macros
+    - ACPI: bgrt: Fix CFI violation
+    - cpufreq: Make cpufreq_online() call driver->offline() on errors
+    - ocfs2: fix snprintf() checking
+    - dax: fix ENOMEM handling in grab_mapping_entry()
+    - xfrm: xfrm_state_mtu should return at least 1280 for ipv6
+    - video: fbdev: imxfb: Fix an error message
+    - net: mvpp2: Put fwnode in error case during ->probe()
+    - net: pch_gbe: Propagate error from devm_gpio_request_one()
+    - pinctrl: renesas: r8a7796: Add missing bias for PRESET# pin
+    - pinctrl: renesas: r8a77990: JTAG pins do not have pull-down capabilities
+    - clk: meson: g12a: fix gp0 and hifi ranges
+    - net: ftgmac100: add missing error return code in ftgmac100_probe()
+    - drm/rockchip: cdn-dp-core: add missing clk_disable_unprepare() on error in
+      cdn_dp_grf_write()
+    - drm/rockchip: dsi: move all lane config except LCDC mux to bind()
+    - ehea: fix error return code in ehea_restart_qps()
+    - net/sched: act_vlan: Fix modify to allow 0
+    - RDMA/core: Sanitize WQ state received from the userspace
+    - RDMA/rxe: Fix failure during driver load
+    - drm: qxl: ensure surf.data is ininitialized
+    - tools/bpftool: Fix error return code in do_batch()
+    - ath10k: go to path err_unsupported when chip id is not supported
+    - ath10k: add missing error return code in ath10k_pci_probe()
+    - wireless: carl9170: fix LEDS build errors & warnings
+    - ieee802154: hwsim: Fix possible memory leak in hwsim_subscribe_all_others
+    - wcn36xx: Move hal_buf allocation to devm_kmalloc in probe
+    - ssb: Fix error return code in ssb_bus_scan()
+    - brcmfmac: fix setting of station info chains bitmask
+    - brcmfmac: correctly report average RSSI in station info
+    - brcmsmac: mac80211_if: Fix a resource leak in an error handling path
+    - ath10k: Fix an error code in ath10k_add_interface()
+    - netlabel: Fix memory leak in netlbl_mgmt_add_common
+    - RDMA/mlx5: Don't add slave port to unaffiliated list
+    - netfilter: nft_exthdr: check for IPv6 packet before further processing
+    - netfilter: nft_osf: check for TCP packet before further processing
+    - netfilter: nft_tproxy: restrict support to TCP and UDP transport protocols
+    - RDMA/rxe: Fix qp reference counting for atomic ops
+    - samples/bpf: Fix the error return code of xdp_redirect's main()
+    - net: ethernet: aeroflex: fix UAF in greth_of_remove
+    - net: ethernet: ezchip: fix UAF in nps_enet_remove
+    - net: ethernet: ezchip: fix error handling
+    - vrf: do not push non-ND strict packets with a source LLA through packet taps
+      again
+    - net: sched: add barrier to ensure correct ordering for lockless qdisc
+    - tls: prevent oversized sendfile() hangs by ignoring MSG_MORE
+    - pkt_sched: sch_qfq: fix qfq_change_class() error path
+    - vxlan: add missing rcu_read_lock() in neigh_reduce()
+    - net/ipv4: swap flow ports when validating source
+    - tc-testing: fix list handling
+    - ieee802154: hwsim: Fix memory leak in hwsim_add_one
+    - ieee802154: hwsim: avoid possible crash in hwsim_del_edge_nl()
+    - mac80211: remove iwlwifi specific workaround NDPs of null_response
+    - net: bcmgenet: Fix attaching to PYH failed on RPi 4B
+    - ipv6: exthdrs: do not blindly use init_net
+    - bpf: Do not change gso_size during bpf_skb_change_proto()
+    - i40e: Fix error handling in i40e_vsi_open
+    - i40e: Fix autoneg disabling for non-10GBaseT links
+    - Revert "ibmvnic: remove duplicate napi_schedule call in open function"
+    - ibmvnic: free tx_pool if tso_pool alloc fails
+    - ipv6: fix out-of-bound access in ip6_parse_tlv()
+    - e1000e: Check the PCIm state
+    - bpfilter: Specify the log level for the kmsg message
+    - gve: Fix swapped vars when fetching max queues
+    - Revert "be2net: disable bh with spin_lock in be_process_mcc"
+    - Bluetooth: mgmt: Fix slab-out-of-bounds in tlv_data_is_valid
+    - Bluetooth: Fix handling of HCI_LE_Advertising_Set_Terminated event
+    - clk: actions: Fix UART clock dividers on Owl S500 SoC
+    - clk: actions: Fix SD clocks factor table on Owl S500 SoC
+    - clk: actions: Fix bisp_factor_table based clocks on Owl S500 SoC
+    - clk: si5341: Avoid divide errors due to bogus register contents
+    - clk: si5341: Update initialization magic
+    - writeback: fix obtain a reference to a freeing memcg css
+    - net: lwtunnel: handle MTU calculation in forwading
+    - net: sched: fix warning in tcindex_alloc_perfect_hash
+    - RDMA/mlx5: Don't access NULL-cleared mpi pointer
+    - MIPS: Fix PKMAP with 32-bit MIPS huge page support
+    - staging: fbtft: Rectify GPIO handling
+    - rcu: Invoke rcu_spawn_core_kthreads() from rcu_spawn_gp_kthread()
+    - tty: nozomi: Fix a resource leak in an error handling function
+    - mwifiex: re-fix for unaligned accesses
+    - iio: adis_buffer: do not return ints in irq handlers
+    - iio: adis16400: do not return ints in irq handlers
+    - iio: accel: bma180: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: bma220: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: hid: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: kxcjk-1013: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio:accel:mxc4005: Drop unnecessary explicit casts in regmap_bulk_read calls
+    - iio: accel: mxc4005: Fix overread of data and alignment issue.
+    - iio: accel: stk8312: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: accel: stk8ba50: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads1015: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: vf610: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: gyro: bmg160: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: humidity: am2315: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: srf08: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: pulsed-light: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: as3935: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: hmc5843: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: bmc150: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: isl29125: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3414: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: light: tcs3472: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: cros_ec_sensors: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: potentiostat: lmp91000: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: rk3328: fix missing clk_disable_unprepare() on error in
+      rk3328_platform_probe()
+    - ASoC: hisilicon: fix missing clk_disable_unprepare() on error in
+      hi6210_i2s_startup()
+    - backlight: lm3630a_bl: Put fwnode in error case during ->probe()
+    - ASoC: rsnd: tidyup loop on rsnd_adg_clk_query()
+    - Input: hil_kbd - fix error return code in hil_dev_connect()
+    - mtd: partitions: redboot: seek fis-index-block in the right node
+    - char: pcmcia: error out if 'num_bytes_read' is greater than 4 in
+      set_protocol()
+    - firmware: stratix10-svc: Fix a resource leak in an error handling path
+    - tty: nozomi: Fix the error handling path of 'nozomi_card_init()'
+    - leds: lm3532: select regmap I2C API
+    - leds: lm36274: cosmetic: rename lm36274_data to chip
+    - leds: lm3692x: Put fwnode in any case during ->probe()
+    - scsi: FlashPoint: Rename si_flags field
+    - fsi: core: Fix return of error values on failures
+    - fsi: scom: Reset the FSI2PIB engine for any error
+    - fsi: occ: Don't accept response from un-initialized OCC
+    - fsi/sbefifo: Clean up correct FIFO when receiving reset request from SBE
+    - fsi/sbefifo: Fix reset timeout
+    - visorbus: fix error return code in visorchipset_init()
+    - s390: appldata depends on PROC_SYSCTL
+    - iommu/dma: Fix IOVA reserve dma ranges
+    - ASoC: mediatek: mtk-btcvsd: Fix an error handling path in
+      'mtk_btcvsd_snd_probe()'
+    - usb: gadget: f_fs: Fix setting of device and driver data cross-references
+    - usb: dwc2: Don't reset the core after setting turnaround time
+    - eeprom: idt_89hpesx: Put fwnode in matching case during ->probe()
+    - eeprom: idt_89hpesx: Restore printing the unsupported fwnode name
+    - iio: at91-sama5d2_adc: remove usage of iio_priv_to_dev() helper
+    - iio: adc: at91-sama5d2: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: hx711: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: mxs-lradc: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ti-ads8688: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - iio: magn: rm3100: Fix alignment of buffer in
+      iio_push_to_buffers_with_timestamp()
+    - staging: gdm724x: check for buffer overflow in gdm_lte_multi_sdu_pkt()
+    - staging: gdm724x: check for overflow in gdm_lte_netif_rx()
+    - staging: rtl8712: remove redundant check in r871xu_drv_init
+    - staging: rtl8712: fix memory leak in rtl871x_load_fw_cb
+    - staging: mt7621-dts: fix pci address for PCI memory range
+    - serial: 8250: Actually allow UPF_MAGIC_MULTIPLIER baud rates
+    - iio: light: vcnl4035: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - iio: prox: isl29501: Fix buffer alignment in
+      iio_push_to_buffers_with_timestamp()
+    - ASoC: cs42l42: Correct definition of CS42L42_ADC_PDN_MASK
+    - of: Fix truncation of memory sizes on 32-bit platforms
+    - mtd: rawnand: marvell: add missing clk_disable_unprepare() on error in
+      marvell_nfc_resume()
+    - scsi: mpt3sas: Fix error return value in _scsih_expander_add()
+    - soundwire: stream: Fix test for DP prepare complete
+    - phy: uniphier-pcie: Fix updating phy parameters
+    - phy: ti: dm816x: Fix the error handling path in 'dm816x_usb_phy_probe()
+    - extcon: sm5502: Drop invalid register write in sm5502_reg_data
+    - extcon: max8997: Add missing modalias string
+    - ASoC: atmel-i2s: Fix usage of capture and playback at the same time
+    - configfs: fix memleak in configfs_release_bin_file
+    - leds: as3645a: Fix error return code in as3645a_parse_node()
+    - leds: ktd2692: Fix an error handling path
+    - powerpc: Offline CPU in stop_this_cpu()
+    - serial: mvebu-uart: do not allow changing baudrate when uartclk is not
+      available
+    - serial: mvebu-uart: correctly calculate minimal possible baudrate
+    - arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
+    - vfio/pci: Handle concurrent vma faults
+    - mm/huge_memory.c: don't discard hugepage if other processes are mapping it
+    - mm/z3fold: fix potential memory leak in z3fold_destroy_pool()
+    - selftests/vm/pkeys: fix alloc_random_pkey() to make it really, really random
+    - perf llvm: Return -ENOMEM when asprintf() fails
+    - scsi: target: cxgbit: Unmap DMA buffer before calling target_execute_cmd()
+    - mmc: block: Disable CMDQ on the ioctl path
+    - mmc: vub3000: fix control-request direction
+    - scsi: core: Retry I/O for Notify (Enable Spinup) Required error
+    - iommu/dma: Fix compile warning in 32-bit builds
+    - Linux 5.4.132
+  * Keyboard not working (LP: #1909814) // Focal update: v5.4.132 upstream
+    stable release (LP: #1938199)
+    - ACPI: resources: Add checks for ACPI IRQ override
+  * Focal update: v5.4.131 upstream stable release (LP: #1936245)
+    - KVM: SVM: Periodically schedule when unregistering regions on destroy
+    - s390/stack: fix possible register corruption with stack switch helper
+    - KVM: SVM: Call SEV Guest Decommission if ASID binding fails
+    - xen/events: reset active flag for lateeoi events later
+    - Linux 5.4.131
+  * Focal update: v5.4.130 upstream stable release (LP: #1936244)
+    - scsi: sr: Return appropriate error code when disk is ejected
+    - drm/nouveau: fix dma_address check for CPU/GPU sync
+    - gpio: AMD8111 and TQMX86 require HAS_IOPORT_MAP
+    - RDMA/mlx5: Block FDB rules when not in switchdev mode
+    - Linux 5.4.130
+  * Focal update: v5.4.129 upstream stable release (LP: #1936242)
+    - module: limit enabling module.sig_enforce
+    - drm/nouveau: wait for moving fence after pinning v2
+    - drm/radeon: wait for moving fence after pinning
+    - ARM: 9081/1: fix gcc-10 thumb2-kernel regression
+    - mmc: meson-gx: use memcpy_to/fromio for dram-access-quirk
+    - kbuild: add CONFIG_LD_IS_LLD
+    - arm64: link with -z norelro for LLD or aarch64-elf
+    - MIPS: generic: Update node names to avoid unit addresses
+    - spi: spi-nxp-fspi: move the register operation after the clock enable
+    - Revert "PCI: PM: Do not read power state in pci_enable_device_flags()"
+    - dmaengine: zynqmp_dma: Fix PM reference leak in
+      zynqmp_dma_alloc_chan_resourc()
+    - mac80211: remove warning in ieee80211_get_sband()
+    - mac80211_hwsim: drop pending frames on stop
+    - cfg80211: call cfg80211_leave_ocb when switching away from OCB
+    - dmaengine: rcar-dmac: Fix PM reference leak in rcar_dmac_probe()
+    - dmaengine: mediatek: free the proper desc in desc_free handler
+    - dmaengine: mediatek: do not issue a new desc if one is still current
+    - dmaengine: mediatek: use GFP_NOWAIT instead of GFP_ATOMIC in prep_dma
+    - net: ipv4: Remove unneed BUG() function
+    - mac80211: drop multicast fragments
+    - net: ethtool: clear heap allocations for ethtool function
+    - ping: Check return value of function 'ping_queue_rcv_skb'
+    - inet: annotate date races around sk->sk_txhash
+    - net: phy: dp83867: perform soft reset and retain established link
+    - net: caif: fix memory leak in ldisc_open
+    - net/packet: annotate accesses to po->bind
+    - net/packet: annotate accesses to po->ifindex
+    - r8152: Avoid memcpy() over-reading of ETH_SS_STATS
+    - sh_eth: Avoid memcpy() over-reading of ETH_SS_STATS
+    - r8169: Avoid memcpy() over-reading of ETH_SS_STATS
+    - KVM: selftests: Fix kvm_check_cap() assertion
+    - net: qed: Fix memcpy() overflow of qed_dcbx_params()
+    - recordmcount: Correct st_shndx handling
+    - PCI: Add AMD RS690 quirk to enable 64-bit DMA
+    - net: ll_temac: Add memory-barriers for TX BD access
+    - net: ll_temac: Avoid ndo_start_xmit returning NETDEV_TX_BUSY
+    - pinctrl: stm32: fix the reported number of GPIO lines per bank
+    - nilfs2: fix memory leak in nilfs_sysfs_delete_device_group
+    - KVM: do not allow mapping valid but non-reference-counted pages
+    - i2c: robotfuzz-osif: fix control-request directions
+    - kthread_worker: split code for canceling the delayed work timer
+    - kthread: prevent deadlock when kthread_mod_delayed_work() races with
+      kthread_cancel_delayed_work_sync()
+    - mm: add VM_WARN_ON_ONCE_PAGE() macro
+    - mm/rmap: remove unneeded semicolon in page_not_mapped()
+    - mm/rmap: use page_not_mapped in try_to_unmap()
+    - mm, thp: use head page in __migration_entry_wait()
+    - mm/thp: fix __split_huge_pmd_locked() on shmem migration entry
+    - mm/thp: make is_huge_zero_pmd() safe and quicker
+    - mm/thp: try_to_unmap() use TTU_SYNC for safe splitting
+    - mm/thp: fix vma_address() if virtual address below file offset
+    - mm/thp: fix page_address_in_vma() on file THP tails
+    - mm/thp: unmap_mapping_page() to fix THP truncate_cleanup_page()
+    - mm: thp: replace DEBUG_VM BUG with VM_WARN when unmap fails for split
+    - mm: page_vma_mapped_walk(): use page for pvmw->page
+    - mm: page_vma_mapped_walk(): settle PageHuge on entry
+    - mm: page_vma_mapped_walk(): use pmde for *pvmw->pmd
+    - mm: page_vma_mapped_walk(): prettify PVMW_MIGRATION block
+    - mm: page_vma_mapped_walk(): crossing page table boundary
+    - mm: page_vma_mapped_walk(): add a level of indentation
+    - mm: page_vma_mapped_walk(): use goto instead of while (1)
+    - mm: page_vma_mapped_walk(): get vma_address_end() earlier
+    - mm/thp: fix page_vma_mapped_walk() if THP mapped by ptes
+    - mm/thp: another PVMW_SYNC fix in page_vma_mapped_walk()
+    - mm, futex: fix shared futex pgoff on shmem huge page
+    - [Config] enable CONFIG_SYSTEM_REVOCATION_LIST
+    - certs: Add EFI_CERT_X509_GUID support for dbx entries
+    - certs: Move load_system_certificate_list to a common function
+    - Linux 5.4.129
+  * Patch To Fix Bug in the Linux Block Layer Responsible For  Merging BIOs
+    (LP: #1931497)
+    - block: return the correct bvec when checking for gaps
+
+  [ Ubuntu: 5.4.0-81.91 ]
+
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+  * large_dir in ext4 broken (LP: #1933074)
+    - SAUCE: ext4: fix directory index node split corruption
+  * Some test in kselftest/net on focal source tree were not tested at all
+    (LP: #1934282)
+    - selftests/net: add missing tests to Makefile
+  * curtin: install flash-kernel in arm64 UEFI unexpected (LP: #1918427)
+    - [Packaging] Allow grub-efi-arm* to satisfy recommends on ARM
+  * Add l2tp.sh in net from ubuntu_kernel_selftests back (LP: #1934293)
+    - Revert "UBUNTU: SAUCE: selftests/net -- disable l2tp.sh test"
+  * icmp_redirect.sh in net from ubuntu_kernel_selftests failed on F-OEM-5.6 /
+    F-OEM-5.10 / F-OEM-5.13 / F / G / H (LP: #1880645)
+    - selftests: icmp_redirect: support expected failures
+  * Focal update: v5.4.128 upstream stable release (LP: #1934179)
+    - dmaengine: ALTERA_MSGDMA depends on HAS_IOMEM
+    - dmaengine: QCOM_HIDMA_MGMT depends on HAS_IOMEM
+    - dmaengine: stedma40: add missing iounmap() on error in d40_probe()
+    - afs: Fix an IS_ERR() vs NULL check
+    - mm/memory-failure: make sure wait for page writeback in memory_failure
+    - kvm: LAPIC: Restore guard to prevent illegal APIC register access
+    - batman-adv: Avoid WARN_ON timing related checks
+    - net: ipv4: fix memory leak in netlbl_cipsov4_add_std
+    - vrf: fix maximum MTU
+    - net: rds: fix memory leak in rds_recvmsg
+    - net: lantiq: disable interrupt before sheduling NAPI
+    - udp: fix race between close() and udp_abort()
+    - rtnetlink: Fix regression in bridge VLAN configuration
+    - net/sched: act_ct: handle DNAT tuple collision
+    - net/mlx5e: Remove dependency in IPsec initialization flows
+    - net/mlx5e: Fix page reclaim for dead peer hairpin
+    - net/mlx5: Consider RoCE cap before init RDMA resources
+    - net/mlx5e: allow TSO on VXLAN over VLAN topologies
+    - net/mlx5e: Block offload of outer header csum for UDP tunnels
+    - netfilter: synproxy: Fix out of bounds when parsing TCP options
+    - sch_cake: Fix out of bounds when parsing TCP options and header
+    - alx: Fix an error handling path in 'alx_probe()'
+    - net: stmmac: dwmac1000: Fix extended MAC address registers definition
+    - net: make get_net_ns return error if NET_NS is disabled
+    - qlcnic: Fix an error handling path in 'qlcnic_probe()'
+    - netxen_nic: Fix an error handling path in 'netxen_nic_probe()'
+    - net: qrtr: fix OOB Read in qrtr_endpoint_post
+    - ptp: improve max_adj check against unreasonable values
+    - net: cdc_ncm: switch to eth%d interface naming
+    - lantiq: net: fix duplicated skb in rx descriptor ring
+    - net: usb: fix possible use-after-free in smsc75xx_bind
+    - net: fec_ptp: fix issue caused by refactor the fec_devtype
+    - net: ipv4: fix memory leak in ip_mc_add1_src
+    - net/af_unix: fix a data-race in unix_dgram_sendmsg / unix_release_sock
+    - be2net: Fix an error handling path in 'be_probe()'
+    - net: hamradio: fix memory leak in mkiss_close
+    - net: cdc_eem: fix tx fixup skb leak
+    - cxgb4: fix wrong shift.
+    - bnxt_en: Rediscover PHY capabilities after firmware reset
+    - bnxt_en: Call bnxt_ethtool_free() in bnxt_init_one() error path
+    - icmp: don't send out ICMP messages with a source address of 0.0.0.0
+    - net: ethernet: fix potential use-after-free in ec_bhf_remove
+    - regulator: bd70528: Fix off-by-one for buck123 .n_voltages setting
+    - ASoC: rt5659: Fix the lost powers for the HDA header
+    - spi: stm32-qspi: Always wait BUSY bit to be cleared in stm32_qspi_wait_cmd()
+    - pinctrl: ralink: rt2880: avoid to error in calls is pin is already enabled
+    - radeon: use memcpy_to/fromio for UVD fw upload
+    - hwmon: (scpi-hwmon) shows the negative temperature properly
+    - can: bcm: fix infoleak in struct bcm_msg_head
+    - can: bcm/raw/isotp: use per module netdevice notifier
+    - can: j1939: fix Use-after-Free, hold skb ref while in use
+    - can: mcba_usb: fix memory leak in mcba_usb
+    - usb: core: hub: Disable autosuspend for Cypress CY7C65632
+    - tracing: Do not stop recording cmdlines when tracing is off
+    - tracing: Do not stop recording comms if the trace file is being read
+    - tracing: Do no increment trace_clock_global() by one
+    - PCI: Mark TI C667X to avoid bus reset
+    - PCI: Mark some NVIDIA GPUs to avoid bus reset
+    - PCI: aardvark: Don't rely on jiffies while holding spinlock
+    - PCI: aardvark: Fix kernel panic during PIO transfer
+    - PCI: Add ACS quirk for Broadcom BCM57414 NIC
+    - PCI: Work around Huawei Intelligent NIC VF FLR erratum
+    - KVM: x86: Immediately reset the MMU context when the SMM flag is cleared
+    - ARCv2: save ABI registers across signal handling
+    - x86/process: Check PF_KTHREAD and not current->mm for kernel threads
+    - x86/pkru: Write hardware init value to PKRU when xstate is init
+    - x86/fpu: Reset state for all signal restore failures
+    - dmaengine: pl330: fix wrong usage of spinlock flags in dma_cyclc
+    - cfg80211: make certificate generation more robust
+    - cfg80211: avoid double free of PMSR request
+    - net: ll_temac: Make sure to free skb when it is completely used
+    - net: ll_temac: Fix TX BD buffer overwrite
+    - net: bridge: fix vlan tunnel dst null pointer dereference
+    - net: bridge: fix vlan tunnel dst refcnt when egressing
+    - mm/slub: clarify verification reporting
+    - mm/slub: fix redzoning for small allocations
+    - mm/slub.c: include swab.h
+    - net: stmmac: disable clocks in stmmac_remove_config_dt()
+    - net: fec_ptp: add clock rate zero check
+    - tools headers UAPI: Sync linux/in.h copy with the kernel sources
+    - KVM: arm/arm64: Fix KVM_VGIC_V3_ADDR_TYPE_REDIST read
+    - ARM: OMAP: replace setup_irq() by request_irq()
+    - clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support
+    - clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
+    - clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
+    - usb: dwc3: debugfs: Add and remove endpoint dirs dynamically
+    - usb: dwc3: core: fix kernel panic when do reboot
+    - Linux 5.4.128
+  * linux-azure CIFS DFS oops (LP: #1935833)
+    - cifs: get rid of unused parameter in reconn_setup_dfs_targets()
+    - cifs: handle empty list of targets in cifs_reconnect()
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: improve the test result processing
+  * cifs: On cifs_reconnect, resolve the hostname again (LP: #1929831)
+    - cifs: rename reconn_inval_dfs_target()
+    - cifs: Simplify reconnect code when dfs upcall is enabled
+    - cifs: Avoid error pointer dereference
+    - cifs: On cifs_reconnect, resolve the hostname again.
+  * Pixel format change broken for Elgato Cam Link 4K (LP: #1932367)
+    - (upstream) media: uvcvideo: Fix pixel format change for Elgato Cam Link 4K
+  * Focal update: v5.4.127 upstream stable release (LP: #1933851)
+    - net: ieee802154: fix null deref in parse dev addr
+    - HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for Saitek X65
+    - HID: hid-input: add mapping for emoji picker key
+    - HID: hid-sensor-hub: Return error for hid_set_field() failure
+    - HID: quirks: Add quirk for Lenovo optical mouse
+    - HID: multitouch: set Stylus suffix for Stylus-application devices, too
+    - HID: Add BUS_VIRTUAL to hid_connect logging
+    - HID: usbhid: fix info leak in hid_submit_ctrl
+    - drm/tegra: sor: Do not leak runtime PM reference
+    - ARM: OMAP2+: Fix build warning when mmc_omap is not built
+    - gfs2: Prevent direct-I/O write fallback errors from getting lost
+    - HID: gt683r: add missing MODULE_DEVICE_TABLE
+    - riscv: Use -mno-relax when using lld linker
+    - gfs2: Fix use-after-free in gfs2_glock_shrink_scan
+    - scsi: target: core: Fix warning on realtime kernels
+    - ethernet: myri10ge: Fix missing error code in myri10ge_probe()
+    - scsi: qedf: Do not put host in qedf_vport_create() unconditionally
+    - scsi: scsi_devinfo: Add blacklist entry for HPE OPEN-V
+    - nvme-loop: reset queue count to 1 in nvme_loop_destroy_io_queues()
+    - nvme-loop: clear NVME_LOOP_Q_LIVE when nvme_loop_configure_admin_queue()
+      fails
+    - nvme-loop: check for NVME_LOOP_Q_LIVE in nvme_loop_destroy_admin_queue()
+    - net: ipconfig: Don't override command-line hostnames or domains
+    - drm/amd/display: Allow bandwidth validation for 0 streams.
+    - rtnetlink: Fix missing error code in rtnl_bridge_notify()
+    - net/x25: Return the correct errno code
+    - net: Return the correct errno code
+    - fib: Return the correct errno code
+    - Linux 5.4.127
+  * Focal update: v5.4.126 upstream stable release (LP: #1933369)
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - proc: Track /proc/$pid/attr/ opener mm_struct
+    - ASoC: max98088: fix ni clock divider calculation
+    - spi: Fix spi device unregister flow
+    - net/nfc/rawsock.c: fix a permission check bug
+    - usb: cdns3: Fix runtime PM imbalance on error
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Glavey TM800A550L tablet
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Lenovo Miix 3-830 tablet
+    - vfio-ccw: Serialize FSM IDLE state with I/O completion
+    - ASoC: sti-sas: add missing MODULE_DEVICE_TABLE
+    - spi: sprd: Add missing MODULE_DEVICE_TABLE
+    - isdn: mISDN: netjet: Fix crash in nj_probe:
+    - bonding: init notify_work earlier to avoid uninitialized use
+    - netlink: disable IRQs for netlink_lock_table()
+    - net: mdiobus: get rid of a BUG_ON()
+    - cgroup: disable controllers at parse time
+    - wq: handle VM suspension in stall detection
+    - net/qla3xxx: fix schedule while atomic in ql_sem_spinlock
+    - RDS tcp loopback connection can hang
+    - scsi: bnx2fc: Return failure if io_req is already in ABTS processing
+    - scsi: vmw_pvscsi: Set correct residual data length
+    - scsi: hisi_sas: Drop free_irq() of devm_request_irq() allocated irq
+    - scsi: target: qla2xxx: Wait for stop_phase1 at WWN removal
+    - net: macb: ensure the device is available before accessing GEMGXL control
+      registers
+    - net: appletalk: cops: Fix data race in cops_probe1
+    - net: dsa: microchip: enable phy errata workaround on 9567
+    - nvme-fabrics: decode host pathing error for connect
+    - MIPS: Fix kernel hang under FUNCTION_GRAPH_TRACER and PREEMPT_TRACER
+    - dm verity: fix require_signatures module_param permissions
+    - bnx2x: Fix missing error code in bnx2x_iov_init_one()
+    - nvme-tcp: remove incorrect Kconfig dep in BLK_DEV_NVME
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P2041 i2c controllers
+    - powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P1010 i2c controllers
+    - spi: Don't have controller clean up spi device before driver unbind
+    - spi: Cleanup on failure of initial setup
+    - i2c: mpc: Make use of i2c_recover_bus()
+    - i2c: mpc: implement erratum A-004447 workaround
+    - x86/boot: Add .text.* to setup.ld
+    - spi: bcm2835: Fix out-of-bounds access with more than 4 slaves
+    - drm: Fix use-after-free read in drm_getunique()
+    - drm: Lock pointer access in drm_master_release()
+    - kvm: avoid speculation-based attacks from out-of-range memslot accesses
+    - staging: rtl8723bs: Fix uninitialized variables
+    - btrfs: return value from btrfs_mark_extent_written() in case of error
+    - btrfs: promote debugging asserts to full-fledged checks in validate_super
+    - cgroup1: don't allow '\n' in renaming
+    - USB: f_ncm: ncm_bitrate (speed) is unsigned
+    - usb: f_ncm: only first packet of aggregate needs to start timer
+    - usb: pd: Set PD_T_SINK_WAIT_CAP to 310ms
+    - usb: dwc3: ep0: fix NULL pointer exception
+    - usb: musb: fix MUSB_QUIRK_B_DISCONNECT_99 handling
+    - usb: typec: wcove: Use LE to CPU conversion when accessing msg->header
+    - usb: typec: ucsi: Clear PPM capability data in ucsi_init() error path
+    - usb: gadget: f_fs: Ensure io_completion_wq is idle during unbind
+    - USB: serial: ftdi_sio: add NovaTech OrionMX product ID
+    - USB: serial: omninet: add device id for Zyxel Omni 56K Plus
+    - USB: serial: quatech2: fix control-request directions
+    - USB: serial: cp210x: fix alternate function for CP2102N QFN20
+    - usb: gadget: eem: fix wrong eem header operation
+    - usb: fix various gadgets null ptr deref on 10gbps cabling.
+    - usb: fix various gadget panics on 10gbps cabling
+    - regulator: core: resolve supply for boot-on/always-on regulators
+    - regulator: max77620: Use device_set_of_node_from_dev()
+    - usb: typec: mux: Fix copy-paste mistake in typec_mux_match
+    - RDMA/ipoib: Fix warning caused by destroying non-initial netns
+    - RDMA/mlx4: Do not map the core_clock page to user space unless enabled
+    - vmlinux.lds.h: Avoid orphan section with !SMP
+    - perf: Fix data race between pin_count increment/decrement
+    - sched/fair: Make sure to update tg contrib for blocked load
+    - KVM: x86: Ensure liveliness of nested VM-Enter fail tracepoint message
+    - IB/mlx5: Fix initializing CQ fragments buffer
+    - NFS: Fix a potential NULL dereference in nfs_get_client()
+    - NFSv4: Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()
+    - perf session: Correct buffer copying when peeking events
+    - kvm: fix previous commit for 32-bit builds
+    - NFS: Fix use-after-free in nfs4_init_client()
+    - NFSv4: Fix second deadlock in nfs4_evict_inode()
+    - NFSv4: nfs4_proc_set_acl needs to restore NFS_CAP_UIDGID_NOMAP on error.
+    - scsi: core: Fix error handling of scsi_host_alloc()
+    - scsi: core: Fix failure handling of scsi_add_host_with_dma()
+    - scsi: core: Put .shost_dev in failure path if host state changes to RUNNING
+    - scsi: core: Only put parent device if host state differs from SHOST_CREATED
+    - ftrace: Do not blindly read the ip address in ftrace_bug()
+    - tracing: Correct the length check which causes memory corruption
+    - proc: only require mm_struct for writing
+    - Linux 5.4.126
+  * Focal update: v5.4.125 upstream stable release (LP: #1932957)
+    - btrfs: tree-checker: do not error out if extent ref hash doesn't match
+    - net: usb: cdc_ncm: don't spew notifications
+    - ALSA: usb: update old-style static const declaration
+    - nl80211: validate key indexes for cfg80211_registered_device
+    - hwmon: (dell-smm-hwmon) Fix index values
+    - netfilter: conntrack: unregister ipv4 sockopts on error unwind
+    - efi: Allow EFI_MEMORY_XP and EFI_MEMORY_RO both to be cleared
+    - efi: cper: fix snprintf() use in cper_dimm_err_location()
+    - vfio/pci: Fix error return code in vfio_ecap_init()
+    - vfio/pci: zap_vma_ptes() needs MMU
+    - samples: vfio-mdev: fix error handing in mdpy_fb_probe()
+    - vfio/platform: fix module_put call in error flow
+    - ipvs: ignore IP_VS_SVC_F_HASHED flag when adding service
+    - HID: pidff: fix error return code in hid_pidff_init()
+    - HID: i2c-hid: fix format string mismatch
+    - net/sched: act_ct: Fix ct template allocation for zone 0
+    - ACPICA: Clean up context mutex during object deletion
+    - netfilter: nft_ct: skip expectations for confirmed conntrack
+    - netfilter: nfnetlink_cthelper: hit EBUSY on updates if size mismatches
+    - ieee802154: fix error return code in ieee802154_add_iface()
+    - ieee802154: fix error return code in ieee802154_llsec_getparams()
+    - ixgbevf: add correct exception tracing for XDP
+    - ipv6: Fix KASAN: slab-out-of-bounds Read in fib6_nh_flush_exceptions
+    - ice: write register with correct offset
+    - ice: Fix VFR issues for AVF drivers that expect ATQLEN cleared
+    - ice: Allow all LLDP packets from PF to Tx
+    - i2c: qcom-geni: Add shutdown callback for i2c
+    - i40e: optimize for XDP_REDIRECT in xsk path
+    - i40e: add correct exception tracing for XDP
+    - arm64: dts: ls1028a: fix memory node
+    - arm64: dts: zii-ultra: fix 12V_MAIN voltage
+    - ARM: dts: imx7d-meerkat96: Fix the 'tuning-step' property
+    - ARM: dts: imx7d-pico: Fix the 'tuning-step' property
+    - ARM: dts: imx: emcon-avari: Fix nxp,pca8574 #gpio-cells
+    - bus: ti-sysc: Fix flakey idling of uarts and stop using swsup_sidle_act
+    - tipc: add extack messages for bearer/media failure
+    - tipc: fix unique bearer names sanity check
+    - Bluetooth: fix the erroneous flush_work() order
+    - Bluetooth: use correct lock to prevent UAF of hdev object
+    - net: caif: added cfserl_release function
+    - net: caif: add proper error handling
+    - net: caif: fix memory leak in caif_device_notify
+    - net: caif: fix memory leak in cfusbl_device_notify
+    - HID: i2c-hid: Skip ELAN power-on command after reset
+    - HID: magicmouse: fix NULL-deref on disconnect
+    - HID: multitouch: require Finger field to mark Win8 reports as MT
+    - ALSA: timer: Fix master timer notification
+    - ALSA: hda: Fix for mute key LED for HP Pavilion 15-CK0xx
+    - ARM: dts: imx6dl-yapp4: Fix RGMII connection to QCA8334 switch
+    - ARM: dts: imx6q-dhcom: Add PU,VDD1P1,VDD2P5 regulators
+    - ext4: fix bug on in ext4_es_cache_extent as ext4_split_extent_at failed
+    - usb: dwc2: Fix build in periphal-only mode
+    - pid: take a reference when initializing `cad_pid`
+    - ocfs2: fix data corruption by fallocate
+    - nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+    - drm/amdgpu: Don't query CE and UE errors
+    - drm/amdgpu: make sure we unpin the UVD BO
+    - x86/apic: Mark _all_ legacy interrupts when IO/APIC is missing
+    - btrfs: mark ordered extent and inode with error if we fail to finish
+    - btrfs: fix error handling in btrfs_del_csums
+    - btrfs: return errors from btrfs_del_csums in cleanup_ref_head
+    - btrfs: fixup error handling in fixup_inode_link_counts
+    - mm, hugetlb: fix simple resv_huge_pages underflow on UFFDIO_COPY
+    - bnxt_en: Remove the setting of dev_port.
+    - mm: add thp_order
+    - XArray: add xa_get_order
+    - XArray: add xas_split
+    - mm/filemap: fix storing to a THP shadow entry
+    - btrfs: fix unmountable seed device after fstrim
+    - KVM: SVM: Truncate GPR value for DR and CR accesses in !64-bit mode
+    - KVM: arm64: Fix debug register indexing
+    - lib/lz4: explicitly support in-place decompression
+    - xen-pciback: redo VF placement in the virtual topology
+    - i2c: qcom-geni: Suspend and resume the bus during SYSTEM_SLEEP_PM ops
+    - neighbour: allow NUD_NOARP entries to be forced GCed
+    - Linux 5.4.125
+
+  [ Ubuntu: 5.4.0-80.90 ]
+
+  * CVE-2021-33909
+    - SAUCE: seq_file: Disallow extremely large seq buffer allocations
+
+  [ Ubuntu: 5.4.0-79.88 ]
+
+  * focal/linux: 5.4.0-79.88 -proposed tracker (LP: #1934343)
+  * lxd exec fails (LP: #1934187)
+    - SAUCE: Revert "proc: Check /proc/$pid/attr/ writes against file opener"
+
+  [ Ubuntu: 5.4.0-78.87 ]
+
+  * focal/linux: 5.4.0-78.87 -proposed tracker (LP: #1932478)
+  * Packaging resync (LP: #1786013)
+    - [Packaging] resync getabis
+    - [Packaging] update helper scripts
+    - update dkms package versions
+  * Disable hv-kvp-daemon.service on certain instance types (LP: #1932081)
+    - [Packaging]: Add kernel command line condition to hv-kvp-daemon service
+  * QLogic Direct-Connect host can't discover SCSI-FC or NVMe/FC devices
+    (LP: #1860724)
+    - scsi: qla2xxx: Serialize fc_port alloc in N2N
+    - scsi: qla2xxx: Set Nport ID for N2N
+    - scsi: qla2xxx: Fix point-to-point (N2N) device discovery issue
+    - scsi: qla2xxx: Fix N2N and NVMe connect retry failure
+  * [SRU] Add support for E810 NIC to Ice Driver in Focal (LP: #1912511)
+    - ice: add additional E810 device id
+  * Focal update: v5.4.124 upstream stable release (LP: #1931166)
+    - ALSA: hda/realtek: Headphone volume is controlled by Front mixer
+    - ALSA: usb-audio: scarlett2: Fix device hang with ehci-pci
+    - ALSA: usb-audio: scarlett2: Improve driver startup messages
+    - cifs: set server->cipher_type to AES-128-CCM for SMB3.0
+    - NFSv4: Fix a NULL pointer dereference in pnfs_mark_matching_lsegs_return()
+    - iommu/vt-d: Fix sysfs leak in alloc_iommu()
+    - perf intel-pt: Fix sample instruction bytes
+    - perf intel-pt: Fix transaction abort handling
+    - perf scripts python: exported-sql-viewer.py: Fix copy to clipboard from Top
+      Calls by elapsed Time report
+    - perf scripts python: exported-sql-viewer.py: Fix Array TypeError
+    - perf scripts python: exported-sql-viewer.py: Fix warning display
+    - proc: Check /proc/$pid/attr/ writes against file opener
+    - net: hso: fix control-request directions
+    - ath10k: Validate first subframe of A-MSDU before processing the list
+    - dm snapshot: properly fix a crash when an origin has no snapshots
+    - drm/amdgpu/vcn1: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.0: add cancel_delayed_work_sync before power gate
+    - drm/amdgpu/vcn2.5: add cancel_delayed_work_sync before power gate
+    - selftests/gpio: Use TEST_GEN_PROGS_EXTENDED
+    - selftests/gpio: Move include of lib.mk up
+    - selftests/gpio: Fix build when source tree is read only
+    - kgdb: fix gcc-11 warnings harder
+    - Documentation: seccomp: Fix user notification documentation
+    - serial: core: fix suspicious security_locked_down() call
+    - misc/uss720: fix memory leak in uss720_probe
+    - thunderbolt: dma_port: Fix NVM read buffer bounds and offset issue
+    - mei: request autosuspend after sending rx flow control
+    - staging: iio: cdc: ad7746: avoid overwrite of num_channels
+    - iio: gyro: fxas21002c: balance runtime power in error path
+    - iio: adc: ad7768-1: Fix too small buffer passed to
+      iio_push_to_buffers_with_timestamp()
+    - iio: adc: ad7124: Fix missbalanced regulator enable / disable on error.
+    - iio: adc: ad7124: Fix potential overflow due to non sequential channel
+      numbers
+    - iio: adc: ad7793: Add missing error code in ad7793_setup()
+    - serial: 8250_pci: Add support for new HPE serial device
+    - serial: 8250_pci: handle FL_NOIRQ board flag
+    - USB: trancevibrator: fix control-request direction
+    - USB: usbfs: Don't WARN about excessively large memory allocations
+    - serial: tegra: Fix a mask operation that is always true
+    - serial: sh-sci: Fix off-by-one error in FIFO threshold register setting
+    - serial: rp2: use 'request_firmware' instead of 'request_firmware_nowait'
+    - USB: serial: ti_usb_3410_5052: add startech.com device id
+    - USB: serial: option: add Telit LE910-S1 compositions 0x7010, 0x7011
+    - USB: serial: ftdi_sio: add IDs for IDS GmbH Products
+    - USB: serial: pl2303: add device id for ADLINK ND-6530 GC
+    - thermal/drivers/intel: Initialize RW trip to THERMAL_TEMP_INVALID
+    - usb: dwc3: gadget: Properly track pending and queued SG
+    - usb: gadget: udc: renesas_usb3: Fix a race in usb3_start_pipen()
+    - net: usb: fix memory leak in smsc75xx_bind
+    - spi: spi-geni-qcom: Fix use-after-free on unbind
+    - Bluetooth: cmtp: fix file refcount when cmtp_attach_device fails
+    - fs/nfs: Use fatal_signal_pending instead of signal_pending
+    - NFS: fix an incorrect limit in filelayout_decode_layout()
+    - NFS: Fix an Oopsable condition in __nfs_pageio_add_request()
+    - NFS: Don't corrupt the value of pg_bytes_written in nfs_do_recoalesce()
+    - NFSv4: Fix v4.0/v4.1 SEEK_DATA return -ENOTSUPP when set NFS_V4_2 config
+    - drm/meson: fix shutdown crash when component not probed
+    - net/mlx5e: Fix multipath lag activation
+    - net/mlx5e: Fix nullptr in add_vlan_push_action()
+    - net/mlx4: Fix EEPROM dump support
+    - Revert "net:tipc: Fix a double free in tipc_sk_mcast_rcv"
+    - tipc: wait and exit until all work queues are done
+    - tipc: skb_linearize the head skb when reassembling msgs
+    - spi: spi-fsl-dspi: Fix a resource leak in an error handling path
+    - net: dsa: mt7530: fix VLAN traffic leaks
+    - net: dsa: fix a crash if ->get_sset_count() fails
+    - net: dsa: sja1105: error out on unsupported PHY mode
+    - i2c: s3c2410: fix possible NULL pointer deref on read message after write
+    - i2c: i801: Don't generate an interrupt on bus reset
+    - i2c: sh_mobile: Use new clock calculation formulas for RZ/G2E
+    - perf jevents: Fix getting maximum number of fds
+    - platform/x86: hp_accel: Avoid invoking _INI to speed up resume
+    - gpio: cadence: Add missing MODULE_DEVICE_TABLE
+    - Revert "media: usb: gspca: add a missed check for goto_low_power"
+    - Revert "ALSA: sb: fix a missing check of snd_ctl_add"
+    - Revert "serial: max310x: pass return value of spi_register_driver"
+    - serial: max310x: unregister uart driver in case of failure and abort
+    - Revert "net: fujitsu: fix a potential NULL pointer dereference"
+    - net: fujitsu: fix potential null-ptr-deref
+    - Revert "net/smc: fix a NULL pointer dereference"
+    - net: caif: remove BUG_ON(dev == NULL) in caif_xmit
+    - Revert "char: hpet: fix a missing check of ioremap"
+    - char: hpet: add checks after calling ioremap
+    - Revert "ALSA: gus: add a check of the status of snd_ctl_add"
+    - Revert "ALSA: usx2y: Fix potential NULL pointer dereference"
+    - Revert "isdn: mISDNinfineon: fix potential NULL pointer dereference"
+    - isdn: mISDNinfineon: check/cleanup ioremap failure correctly in setup_io
+    - Revert "ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()"
+    - ath6kl: return error code in ath6kl_wmi_set_roam_lrssi_cmd()
+    - Revert "isdn: mISDN: Fix potential NULL pointer dereference of kzalloc"
+    - isdn: mISDN: correctly handle ph_info allocation failure in hfcsusb_ph_info
+    - Revert "dmaengine: qcom_hidma: Check for driver register failure"
+    - dmaengine: qcom_hidma: comment platform_driver_register call
+    - Revert "libertas: add checks for the return value of sysfs_create_group"
+    - libertas: register sysfs groups properly
+    - Revert "ASoC: cs43130: fix a NULL pointer dereference"
+    - ASoC: cs43130: handle errors in cs43130_probe() properly
+    - Revert "media: dvb: Add check on sp8870_readreg"
+    - media: dvb: Add check on sp8870_readreg return
+    - Revert "media: gspca: mt9m111: Check write_bridge for timeout"
+    - media: gspca: mt9m111: Check write_bridge for timeout
+    - Revert "media: gspca: Check the return value of write_bridge for timeout"
+    - media: gspca: properly check for errors in po1030_probe()
+    - Revert "net: liquidio: fix a NULL pointer dereference"
+    - net: liquidio: Add missing null pointer checks
+    - Revert "brcmfmac: add a check for the status of usb_register"
+    - brcmfmac: properly check for bus register errors
+    - btrfs: return whole extents in fiemap
+    - scsi: BusLogic: Fix 64-bit system enumeration error for Buslogic
+    - openrisc: Define memory barrier mb
+    - btrfs: do not BUG_ON in link_to_fixup_dir
+    - platform/x86: hp-wireless: add AMD's hardware id to the supported list
+    - platform/x86: intel_punit_ipc: Append MODULE_DEVICE_TABLE for ACPI
+    - platform/x86: touchscreen_dmi: Add info for the Mediacom Winpad 7.0 W700
+      tablet
+    - SMB3: incorrect file id in requests compounded with open
+    - drm/amd/display: Disconnect non-DP with no EDID
+    - drm/amd/amdgpu: fix refcount leak
+    - drm/amdgpu: Fix a use-after-free
+    - drm/amd/amdgpu: fix a potential deadlock in gpu reset
+    - net: netcp: Fix an error message
+    - net: dsa: fix error code getting shifted with 4 in dsa_slave_get_sset_count
+    - ASoC: cs42l42: Regmap must use_single_read/write
+    - vfio-ccw: Check initialized flag in cp_init()
+    - net: really orphan skbs tied to closing sk
+    - net: fec: fix the potential memory leak in fec_enet_init()
+    - net: mdio: thunder: Fix a double free issue in the .remove function
+    - net: mdio: octeon: Fix some double free issues
+    - openvswitch: meter: fix race when getting now_ms.
+    - tls splice: check SPLICE_F_NONBLOCK instead of MSG_DONTWAIT
+    - net: sched: fix packet stuck problem for lockless qdisc
+    - net: sched: fix tx action rescheduling issue during deactivation
+    - net: sched: fix tx action reschedule issue with stopped queue
+    - net: hso: check for allocation failure in hso_create_bulk_serial_device()
+    - net: bnx2: Fix error return code in bnx2_init_board()
+    - bnxt_en: Include new P5 HV definition in VF check.
+    - mld: fix panic in mld_newpack()
+    - gve: Check TX QPL was actually assigned
+    - gve: Update mgmt_msix_idx if num_ntfy changes
+    - gve: Add NULL pointer checks when freeing irqs.
+    - gve: Upgrade memory barrier in poll routine
+    - gve: Correct SKB queue index validation.
+    - cxgb4: avoid accessing registers when clearing filters
+    - staging: emxx_udc: fix loop in _nbu2ss_nuke()
+    - ASoC: cs35l33: fix an error code in probe()
+    - bpf: Set mac_len in bpf_skb_change_head
+    - ixgbe: fix large MTU request from VF
+    - scsi: libsas: Use _safe() loop in sas_resume_port()
+    - net: lantiq: fix memory corruption in RX ring
+    - ipv6: record frag_max_size in atomic fragments in input path
+    - ALSA: usb-audio: scarlett2: snd_scarlett_gen2_controls_create() can be
+      static
+    - net: ethernet: mtk_eth_soc: Fix packet statistics support for MT7628/88
+    - sch_dsmark: fix a NULL deref in qdisc_reset()
+    - MIPS: alchemy: xxs1500: add gpio-au1000.h header file
+    - MIPS: ralink: export rt_sysc_membase for rt2880_wdt.c
+    - drm/i915/display: fix compiler warning about array overrun
+    - i915: fix build warning in intel_dp_get_link_status()
+    - drivers/net/ethernet: clean up unused assignments
+    - net: hns3: check the return of skb_checksum_help()
+    - Revert "Revert "ALSA: usx2y: Fix potential NULL pointer dereference""
+    - net: hso: bail out on interrupt URB allocation failure
+    - neighbour: Prevent Race condition in neighbour subsytem
+    - usb: core: reduce power-on-good delay time of root hub
+    - Linux 5.4.124
+  * Focal update: v5.4.123 upstream stable release (LP: #1931160)
+    - usb: dwc3: gadget: Enable suspend events
+    - perf unwind: Fix separate debug info files when using elfutils' libdw's
+      unwinder
+    - perf unwind: Set userdata for all __report_module() paths
+    - NFC: nci: fix memory leak in nci_allocate_device
+    - Linux 5.4.123
+  * Focal update: v5.4.122 upstream stable release (LP: #1931159)
+    - firmware: arm_scpi: Prevent the ternary sign expansion bug
+    - openrisc: Fix a memory leak
+    - RDMA/siw: Properly check send and receive CQ pointers
+    - RDMA/siw: Release xarray entry
+    - RDMA/rxe: Clear all QP fields if creation failed
+    - scsi: ufs: core: Increase the usable queue depth
+    - scsi: qla2xxx: Fix error return code in qla82xx_write_flash_dword()
+    - RDMA/mlx5: Recover from fatal event in dual port mode
+    - RDMA/core: Don't access cm_id after its destruction
+    - platform/mellanox: mlxbf-tmfifo: Fix a memory barrier issue
+    - platform/x86: dell-smbios-wmi: Fix oops on rmmod dell_smbios
+    - RDMA/uverbs: Fix a NULL vs IS_ERR() bug
+    - ptrace: make ptrace() fail if the tracee changed its pid unexpectedly
+    - nvmet: seset ns->file when open fails
+    - locking/mutex: clear MUTEX_FLAGS if wait_list is empty due to signal
+    - btrfs: avoid RCU stalls while running delayed iputs
+    - cifs: fix memory leak in smb2_copychunk_range
+    - ALSA: dice: fix stream format for TC Electronic Konnekt Live at high
+      sampling transfer frequency
+    - ALSA: intel8x0: Don't update period unless prepared
+    - ALSA: line6: Fix racy initialization of LINE6 MIDI
+    - ALSA: dice: fix stream format at middle sampling rate for Alesis iO 26
+    - ALSA: firewire-lib: fix calculation for size of IR context payload
+    - ALSA: usb-audio: Validate MS endpoint descriptors
+    - ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro
+    - ALSA: hda: fixup headset for ASUS GU502 laptop
+    - Revert "ALSA: sb8: add a check for request_region"
+    - ALSA: firewire-lib: fix check for the size of isochronous packet payload
+    - ALSA: hda/realtek: reset eapd coeff to default value for alc287
+    - ALSA: hda/realtek: Add some CLOVE SSIDs of ALC293
+    - ALSA: hda/realtek: Fix silent headphone output on ASUS UX430UA
+    - ALSA: hda/realtek: Add fixup for HP OMEN laptop
+    - ALSA: hda/realtek: Add fixup for HP Spectre x360 15-df0xxx
+    - uio_hv_generic: Fix a memory leak in error handling paths
+    - Revert "rapidio: fix a NULL pointer dereference when create_workqueue()
+      fails"
+    - rapidio: handle create_workqueue() failure
+    - Revert "serial: mvebu-uart: Fix to avoid a potential NULL pointer
+      dereference"
+    - drm/amdgpu: disable 3DCGCG on picasso/raven1 to avoid compute hang
+    - drm/amdgpu: update gc golden setting for Navi12
+    - drm/amdgpu: update sdma golden setting for Navi12
+    - mmc: sdhci-pci-gli: increase 1.8V regulator wait
+    - xen-pciback: reconfigure also from backend watch handler
+    - dm snapshot: fix crash with transient storage and zero chunk size
+    - Revert "video: hgafb: fix potential NULL pointer dereference"
+    - Revert "net: stmicro: fix a missing check of clk_prepare"
+    - Revert "leds: lp5523: fix a missing check of return value of lp55xx_read"
+    - Revert "hwmon: (lm80) fix a missing check of bus read in lm80 probe"
+    - Revert "video: imsttfb: fix potential NULL pointer dereferences"
+    - Revert "ecryptfs: replace BUG_ON with error handling code"
+    - Revert "scsi: ufs: fix a missing check of devm_reset_control_get"
+    - Revert "gdrom: fix a memory leak bug"
+    - cdrom: gdrom: deallocate struct gdrom_unit fields in remove_gdrom
+    - cdrom: gdrom: initialize global variable at init time
+    - Revert "media: rcar_drif: fix a memory disclosure"
+    - Revert "rtlwifi: fix a potential NULL pointer dereference"
+    - Revert "qlcnic: Avoid potential NULL pointer dereference"
+    - Revert "niu: fix missing checks of niu_pci_eeprom_read"
+    - ethernet: sun: niu: fix missing checks of niu_pci_eeprom_read()
+    - net: stmicro: handle clk_prepare() failure during init
+    - scsi: ufs: handle cleanup correctly on devm_reset_control_get error
+    - net: rtlwifi: properly check for alloc_workqueue() failure
+    - ics932s401: fix broken handling of errors when word reading fails
+    - leds: lp5523: check return value of lp5xx_read and jump to cleanup code
+    - qlcnic: Add null check after calling netdev_alloc_skb
+    - video: hgafb: fix potential NULL pointer dereference
+    - vgacon: Record video mode changes with VT_RESIZEX
+    - vt: Fix character height handling with VT_RESIZEX
+    - tty: vt: always invoke vc->vc_sw->con_resize callback
+    - nvme-multipath: fix double initialization of ANA state
+    - ext4: fix error handling in ext4_end_enable_verity()
+    - Bluetooth: L2CAP: Fix handling LE modes by L2CAP_OPTIONS
+    - nvmet: use new ana_log_size instead the old one
+    - video: hgafb: correctly handle card detect failure during probe
+    - Bluetooth: SMP: Fail if remote and local public keys are identical
+    - Linux 5.4.122
+  * Focal update: v5.4.121 upstream stable release (LP: #1931158)
+    - x86/msr: Fix wr/rdmsr_safe_regs_on_cpu() prototypes
+    - kgdb: fix gcc-11 warning on indentation
+    - usb: sl811-hcd: improve misleading indentation
+    - cxgb4: Fix the -Wmisleading-indentation warning
+    - isdn: capi: fix mismatched prototypes
+    - pinctrl: ingenic: Improve unreachable code generation
+    - xsk: Simplify detection of empty and full rings
+    - virtio_net: Do not pull payload in skb->head
+    - PCI: thunder: Fix compile testing
+    - dmaengine: dw-edma: Fix crash on loading/unloading driver
+    - ARM: 9066/1: ftrace: pause/unpause function graph tracer in cpu_suspend()
+    - ACPI / hotplug / PCI: Fix reference count leak in enable_slot()
+    - Input: elants_i2c - do not bind to i2c-hid compatible ACPI instantiated
+      devices
+    - Input: silead - add workaround for x86 BIOS-es which bring the chip up in a
+      stuck state
+    - um: Mark all kernel symbols as local
+    - um: Disable CONFIG_GCOV with MODULES
+    - ARM: 9075/1: kernel: Fix interrupted SMC calls
+    - scripts/recordmcount.pl: Fix RISC-V regex for clang
+    - riscv: Workaround mcount name prior to clang-13
+    - scsi: lpfc: Fix illegal memory access on Abort IOCBs
+    - ceph: fix fscache invalidation
+    - scsi: target: tcmu: Return from tcmu_handle_completions() if cmd_id not
+      found
+    - bridge: Fix possible races between assigning rx_handler_data and setting
+      IFF_BRIDGE_PORT bit
+    - drm/amd/display: Fix two cursor duplication when using overlay
+    - gpiolib: acpi: Add quirk to ignore EC wakeups on Dell Venue 10 Pro 5055
+    - ALSA: hda: generic: change the DAC ctl name for LO+SPK or LO+HP
+    - block: reexpand iov_iter after read/write
+    - lib: stackdepot: turn depot_lock spinlock to raw_spinlock
+    - net: stmmac: Do not enable RX FIFO overflow interrupts
+    - ip6_gre: proper dev_{hold|put} in ndo_[un]init methods
+    - sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ip6_tunnel: sit: proper dev_{hold|put} in ndo_[un]init methods
+    - ipv6: remove extra dev_hold() for fallback tunnels
+    - KVM: arm64: Initialize VCPU mdcr_el2 before loading it
+    - tweewide: Fix most Shebang lines
+    - scripts: switch explicitly to Python 3
+    - Linux 5.4.121
+  * Focal update: v5.4.120 upstream stable release (LP: #1930474)
+    - tpm: fix error return code in tpm2_get_cc_attrs_tbl()
+    - tpm, tpm_tis: Extend locality handling to TPM2 in tpm_tis_gen_interrupt()
+    - tpm, tpm_tis: Reserve locality in tpm_tis_resume()
+    - KVM: x86/mmu: Remove the defunct update_pte() paging hook
+    - PM: runtime: Fix unpaired parent child_count for force_resume
+    - fs: dlm: fix debugfs dump
+    - tipc: convert dest node's address to network order
+    - ASoC: Intel: bytcr_rt5640: Enable jack-detect support on Asus T100TAF
+    - net: stmmac: Set FIFO sizes for ipq806x
+    - ASoC: rsnd: core: Check convert rate in rsnd_hw_params
+    - i2c: bail out early when RDWR parameters are wrong
+    - ALSA: hdsp: don't disable if not enabled
+    - ALSA: hdspm: don't disable if not enabled
+    - ALSA: rme9652: don't disable if not enabled
+    - ALSA: bebob: enable to deliver MIDI messages for multiple ports
+    - Bluetooth: Set CONF_NOT_COMPLETE as l2cap_chan default
+    - Bluetooth: initialize skb_queue_head at l2cap_chan_create()
+    - net: bridge: when suppression is enabled exclude RARP packets
+    - Bluetooth: check for zapped sk before connecting
+    - ip6_vti: proper dev_{hold|put} in ndo_[un]init methods
+    - ASoC: Intel: bytcr_rt5640: Add quirk for the Chuwi Hi8 tablet
+    - i2c: Add I2C_AQ_NO_REP_START adapter quirk
+    - mac80211: clear the beacon's CRC after channel switch
+    - pinctrl: samsung: use 'int' for register masks in Exynos
+    - mt76: mt76x0: disable GTK offloading
+    - cuse: prevent clone
+    - ASoC: rsnd: call rsnd_ssi_master_clk_start() from rsnd_ssi_init()
+    - Revert "iommu/amd: Fix performance counter initialization"
+    - iommu/amd: Remove performance counter pre-initialization test
+    - drm/amd/display: Force vsync flip when reconfiguring MPCC
+    - selftests: Set CC to clang in lib.mk if LLVM is set
+    - kconfig: nconf: stop endless search loops
+    - ALSA: hda/hdmi: fix race in handling acomp ELD notification at resume
+    - sctp: Fix out-of-bounds warning in sctp_process_asconf_param()
+    - flow_dissector: Fix out-of-bounds warning in __skb_flow_bpf_to_target()
+    - powerpc/smp: Set numa node before updating mask
+    - ASoC: rt286: Generalize support for ALC3263 codec
+    - ethtool: ioctl: Fix out-of-bounds warning in store_link_ksettings_for_user()
+    - net: sched: tapr: prevent cycle_time == 0 in parse_taprio_schedule
+    - samples/bpf: Fix broken tracex1 due to kprobe argument change
+    - powerpc/pseries: Stop calling printk in rtas_stop_self()
+    - drm/amd/display: fixed divide by zero kernel crash during dsc enablement
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_send_pkt
+    - wl3501_cs: Fix out-of-bounds warnings in wl3501_mgmt_join
+    - qtnfmac: Fix possible buffer overflow in qtnf_event_handle_external_auth
+    - powerpc/iommu: Annotate nested lock for lockdep
+    - iavf: remove duplicate free resources calls
+    - net: ethernet: mtk_eth_soc: fix RX VLAN offload
+    - bnxt_en: Add PCI IDs for Hyper-V VF devices.
+    - ia64: module: fix symbolizer crash on fdescr
+    - ASoC: rt286: Make RT286_SET_GPIO_* readable and writable
+    - thermal: thermal_of: Fix error return code of
+      thermal_of_populate_bind_params()
+    - f2fs: fix a redundant call to f2fs_balance_fs if an error occurs
+    - PCI: iproc: Fix return value of iproc_msi_irq_domain_alloc()
+    - PCI: Release OF node in pci_scan_device()'s error path
+    - ARM: 9064/1: hw_breakpoint: Do not directly check the event's
+      overflow_handler hook
+    - rpmsg: qcom_glink_native: fix error return code of qcom_glink_rx_data()
+    - NFSv4.2: Always flush out writes in nfs42_proc_fallocate()
+    - NFS: Deal correctly with attribute generation counter overflow
+    - PCI: endpoint: Fix missing destroy_workqueue()
+    - pNFS/flexfiles: fix incorrect size check in decode_nfs_fh()
+    - NFSv4.2 fix handling of sr_eof in SEEK's reply
+    - rtc: fsl-ftm-alarm: add MODULE_TABLE()
+    - ceph: fix inode leak on getattr error in __fh_to_dentry
+    - rtc: ds1307: Fix wday settings for rx8130
+    - net: hns3: fix incorrect configuration for igu_egu_hw_err
+    - net: hns3: initialize the message content in hclge_get_link_mode()
+    - net: hns3: add check for HNS3_NIC_STATE_INITED in
+      hns3_reset_notify_up_enet()
+    - net: hns3: fix for vxlan gpe tx checksum bug
+    - net: hns3: use netif_tx_disable to stop the transmit queue
+    - net: hns3: disable phy loopback setting in hclge_mac_start_phy
+    - sctp: do asoc update earlier in sctp_sf_do_dupcook_a
+    - RISC-V: Fix error code returned by riscv_hartid_to_cpuid()
+    - sunrpc: Fix misplaced barrier in call_decode
+    - ethernet:enic: Fix a use after free bug in enic_hard_start_xmit
+    - sctp: fix a SCTP_MIB_CURRESTAB leak in sctp_sf_do_dupcook_b
+    - netfilter: xt_SECMARK: add new revision to fix structure layout
+    - drm/radeon: Fix off-by-one power_state index heap overwrite
+    - drm/radeon: Avoid power table parsing memory leaks
+    - khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
+    - mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
+    - mm/migrate.c: fix potential indeterminate pte entry in
+      migrate_vma_insert_page()
+    - ksm: fix potential missing rmap_item for stable_node
+    - net: fix nla_strcmp to handle more then one trailing null character
+    - smc: disallow TCP_ULP in smc_setsockopt()
+    - netfilter: nfnetlink_osf: Fix a missing skb_header_pointer() NULL check
+    - can: m_can: m_can_tx_work_queue(): fix tx_skb race condition
+    - sched: Fix out-of-bound access in uclamp
+    - sched/fair: Fix unfairness caused by missing load decay
+    - kernel: kexec_file: fix error return code of kexec_calculate_store_digests()
+    - netfilter: nftables: avoid overflows in nft_hash_buckets()
+    - i40e: Fix use-after-free in i40e_client_subtask()
+    - i40e: fix the restart auto-negotiation after FEC modified
+    - i40e: Fix PHY type identifiers for 2.5G and 5G adapters
+    - ARC: entry: fix off-by-one error in syscall number validation
+    - ARC: mm: PAE: use 40-bit physical page mask
+    - powerpc/64s: Fix crashes when toggling stf barrier
+    - powerpc/64s: Fix crashes when toggling entry flush barrier
+    - hfsplus: prevent corruption in shrinking truncate
+    - squashfs: fix divide error in calculate_skip()
+    - userfaultfd: release page in error path to avoid BUG_ON
+    - mm/hugetlb: fix F_SEAL_FUTURE_WRITE
+    - drm/radeon/dpm: Disable sclk switching on Oland when two 4K 60Hz monitors
+      are connected
+    - drm/i915: Avoid div-by-zero on gen2
+    - iio: proximity: pulsedlight: Fix rumtime PM imbalance on error
+    - usb: fotg210-hcd: Fix an error message
+    - hwmon: (occ) Fix poll rate limiting
+    - ACPI: scan: Fix a memory leak in an error handling path
+    - kyber: fix out of bounds access when preempted
+    - nbd: Fix NULL pointer in flush_workqueue
+    - blk-mq: Swap two calls in blk_mq_exit_queue()
+    - iomap: fix sub-page uptodate handling
+    - usb: dwc3: omap: improve extcon initialization
+    - usb: dwc3: pci: Enable usb2-gadget-lpm-disable for Intel Merrifield
+    - usb: xhci: Increase timeout for HC halt
+    - usb: dwc2: Fix gadget DMA unmap direction
+    - usb: core: hub: fix race condition about TRSMRCY of resume
+    - usb: dwc3: gadget: Return success always for kick transfer in ep queue
+    - xhci: Do not use GFP_KERNEL in (potentially) atomic context
+    - xhci: Add reset resume quirk for AMD xhci controller.
+    - iio: gyro: mpu3050: Fix reported temperature value
+    - iio: tsl2583: Fix division by a zero lux_val
+    - cdc-wdm: untangle a circular dependency between callback and softint
+    - KVM: x86: Cancel pvclock_gtod_work on module removal
+    - mm: fix struct page layout on 32-bit systems
+    - FDDI: defxx: Make MMIO the configuration default except for EISA
+    - MIPS: Reinstate platform `__div64_32' handler
+    - MIPS: Avoid DIVU in `__div64_32' is result would be zero
+    - MIPS: Avoid handcoded DIVU in `__div64_32' altogether
+    - thermal/core/fair share: Lock the thermal zone while looping over instances
+    - f2fs: fix error handling in f2fs_end_enable_verity()
+    - ARM: 9011/1: centralize phys-to-virt conversion of DT/ATAGS address
+    - ARM: 9012/1: move device tree mapping out of linear region
+    - ARM: 9020/1: mm: use correct section size macro to describe the FDT virtual
+      address
+    - ARM: 9027/1: head.S: explicitly map DT even if it lives in the first
+      physical section
+    - usb: typec: tcpm: Fix error while calculating PPS out values
+    - kobject_uevent: remove warning in init_uevent_argv()
+    - netfilter: conntrack: Make global sysctls readonly in non-init netns
+    - clk: exynos7: Mark aclk_fsys1_200 as critical
+    - nvme: do not try to reconfigure APST when the controller is not live
+    - ASoC: rsnd: check all BUSIF status when error
+    - Linux 5.4.120
+  * scsi: storvsc: Parameterize number hardware queues (LP: #1930626)
+    - scsi: storvsc: Parameterize number hardware queues
+
+  [ Ubuntu: 5.4.0-77.86 ]
+
+  * UAF on CAN J1939 j1939_can_recv (LP: #1932209)
+    - SAUCE: can: j1939: delay release of j1939_priv after synchronize_rcu
+  * UAF on CAN BCM bcm_rx_handler (LP: #1931855)
+    - SAUCE: can: bcm: delay release of struct bcm_op after synchronize_rcu
+
+  [ Ubuntu: 5.4.0-76.85 ]
+
+  * focal/linux: 5.4.0-76.85 -proposed tracker (LP: #1932123)
+  * Upstream v5.9 introduced 'module' patches that removed exported symbols
+    (LP: #1932065)
+    - SAUCE: Revert "modules: inherit TAINT_PROPRIETARY_MODULE"
+    - SAUCE: Revert "modules: return licensing information from find_symbol"
+    - SAUCE: Revert "modules: rename the licence field in struct symsearch to
+      license"
+    - SAUCE: Revert "modules: unexport __module_address"
+    - SAUCE: Revert "modules: unexport __module_text_address"
+    - SAUCE: Revert "modules: mark each_symbol_section static"
+    - SAUCE: Revert "modules: mark find_symbol static"
+    - SAUCE: Revert "modules: mark ref_module static"
+
+  [ Ubuntu: 5.4.0-75.84 ]
+
+  * focal/linux: 5.4.0-75.84 -proposed tracker (LP: #1930032)
+  * Packaging resync (LP: #1786013)
+    - update dkms package versions
+  * CVE-2021-33200
+    - bpf: Wrap aux data inside bpf_sanitize_info container
+    - bpf: Fix mask direction swap upon off reg sign change
+    - bpf: No need to simulate speculative domain for immediates
+  * Realtek USB hubs in Dell WD19SC/DC/TB fail to work after exiting s2idle
+    (LP: #1928242)
+    - USB: Verify the port status when timeout happens during port suspend
+  * CVE-2020-26145
+    - ath10k: drop fragments with multicast DA for SDIO
+    - ath10k: add CCMP PN replay protection for fragmented frames for PCIe
+    - ath10k: drop fragments with multicast DA for PCIe
+  * CVE-2020-26141
+    - ath10k: Fix TKIP Michael MIC verification for PCIe
+  * CVE-2020-24588
+    - mac80211: properly handle A-MSDUs that start with an RFC 1042 header
+    - cfg80211: mitigate A-MSDU aggregation attacks
+    - mac80211: drop A-MSDUs on old ciphers
+    - ath10k: drop MPDU which has discard flag set by firmware for SDIO
+  * CVE-2020-26139
+    - mac80211: do not accept/forward invalid EAPOL frames
+  * CVE-2020-24586 // CVE-2020-24587 // CVE-2020-24587 for such cases.
+    - mac80211: extend protection against mixed key and fragment cache attacks
+  * CVE-2020-24586 // CVE-2020-24587
+    - mac80211: prevent mixed key and fragment cache attacks
+    - mac80211: add fragment cache to sta_info
+    - mac80211: check defrag PN against current frame
+    - mac80211: prevent attacks on TKIP/WEP as well
+  * CVE-2020-26147
+    - mac80211: assure all fragments are encrypted
+  * raid10: Block discard is very slow, causing severe delays for mkfs and
+    fstrim operations (LP: #1896578)
+    - md: add md_submit_discard_bio() for submitting discard bio
+    - md/raid10: extend r10bio devs to raid disks
+    - md/raid10: pull the code that wait for blocked dev into one function
+    - md/raid10: improve raid10 discard request
+    - md/raid10: improve discard request for far layout
+    - dm raid: remove unnecessary discard limits for raid0 and raid10
+  * [SRU] mpt3sas: only one vSES is handy even IOC has multi vSES (LP: #1926517)
+    - scsi: mpt3sas: Only one vSES is present even when IOC has multi vSES
+  * kvm: properly tear down PV features on hibernate (LP: #1920944)
+    - x86/kvm: Fix pr_info() for async PF setup/teardown
+    - x86/kvm: Teardown PV features on boot CPU as well
+    - x86/kvm: Disable kvmclock on all CPUs on shutdown
+    - x86/kvm: Disable all PV features on crash
+    - x86/kvm: Unify kvm_pv_guest_cpu_reboot() with kvm_guest_cpu_offline()
+  * Focal update: v5.4.119 upstream stable release (LP: #1929615)
+    - Bluetooth: verify AMP hci_chan before amp_destroy
+    - hsr: use netdev_err() instead of WARN_ONCE()
+    - bluetooth: eliminate the potential race condition when removing the HCI
+      controller
+    - net/nfc: fix use-after-free llcp_sock_bind/connect
+    - Revert "USB: cdc-acm: fix rounding error in TIOCSSERIAL"
+    - tty: moxa: fix TIOCSSERIAL jiffies conversions
+    - tty: amiserial: fix TIOCSSERIAL permission check
+    - USB: serial: usb_wwan: fix TIOCSSERIAL jiffies conversions
+    - staging: greybus: uart: fix TIOCSSERIAL jiffies conversions
+    - USB: serial: ti_usb_3410_5052: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL jiffies conversions
+    - tty: moxa: fix TIOCSSERIAL permission check
+    - staging: fwserial: fix TIOCSSERIAL permission check
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for fixed supply
+    - usb: typec: tcpm: Address incorrect values of tcpm psy for pps supply
+    - usb: typec: tcpm: update power supply once partner accepts
+    - usb: xhci-mtk: remove or operator for setting schedule parameters
+    - usb: xhci-mtk: improve bandwidth scheduling with TT
+    - ASoC: samsung: tm2_wm5110: check of of_parse return value
+    - ASoC: Intel: kbl_da7219_max98927: Fix kabylake_ssp_fixup function
+    - MIPS: pci-mt7620: fix PLL lock check
+    - MIPS: pci-rt2880: fix slot 0 configuration
+    - FDDI: defxx: Bail out gracefully with unassigned PCI resource for CSR
+    - PCI: Allow VPD access for QLogic ISP2722
+    - iio:accel:adis16201: Fix wrong axis assignment that prevents loading
+    - misc: lis3lv02d: Fix false-positive WARN on various HP models
+    - misc: vmw_vmci: explicitly initialize vmci_notify_bm_set_msg struct
+    - misc: vmw_vmci: explicitly initialize vmci_datagram payload
+    - md/bitmap: wait for external bitmap writes to complete during tear down
+    - md-cluster: fix use-after-free issue when removing rdev
+    - md: split mddev_find
+    - md: factor out a mddev_find_locked helper from mddev_find
+    - md: md_open returns -EBUSY when entering racing area
+    - md: Fix missing unused status line of /proc/mdstat
+    - ipw2x00: potential buffer overflow in libipw_wx_set_encodeext()
+    - cfg80211: scan: drop entry from hidden_list on overflow
+    - rtw88: Fix array overrun in rtw_get_tx_power_params()
+    - drm/panfrost: Clear MMU irqs before handling the fault
+    - drm/panfrost: Don't try to map pages that are already mapped
+    - drm/radeon: fix copy of uninitialized variable back to userspace
+    - drm/amd/display: Reject non-zero src_y and src_x for video planes
+    - ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC882 Clevo quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 HP quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Acer quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Dell quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 ASUS quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries
+    - ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries
+    - ALSA: hda/realtek: Re-order remaining ALC269 quirk table entries
+    - ALSA: hda/realtek: Re-order ALC662 quirk table entries
+    - ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices
+    - ALSA: hda/realtek: ALC285 Thinkpad jack pin quirk is unreachable
+    - KVM: s390: split kvm_s390_logical_to_effective
+    - KVM: s390: fix guarded storage control register handling
+    - s390: fix detection of vector enhancements facility 1 vs. vector packed
+      decimal facility
+    - KVM: s390: split kvm_s390_real_to_abs
+    - KVM: nVMX: Truncate bits 63:32 of VMCS field on nested check in !64-bit
+    - KVM: Stop looking for coalesced MMIO zones if the bus is destroyed
+    - Revert "i3c master: fix missing destroy_workqueue() on error in
+      i3c_master_register"
+    - ovl: fix missing revert_creds() on error path
+    - usb: gadget: pch_udc: Revert d3cb25a12138 completely
+    - memory: gpmc: fix out of bounds read and dereference on gpmc_cs[]
+    - ARM: dts: exynos: correct fuel gauge interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct MUIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Midas family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Odroid X/U3 family
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on SMDK5250
+    - ARM: dts: exynos: correct PMIC interrupt trigger level on Snow
+    - serial: stm32: fix incorrect characters on console
+    - serial: stm32: fix tx_empty condition
+    - usb: typec: tcpci: Check ROLE_CONTROL while interpreting CC_STATUS
+    - regmap: set debugfs_name to NULL after it is freed
+    - mtd: rawnand: fsmc: Fix error code in fsmc_nand_probe()
+    - mtd: rawnand: brcmnand: fix OOB R/W with Hamming ECC
+    - mtd: Handle possible -EPROBE_DEFER from parse_mtd_partitions()
+    - mtd: rawnand: qcom: Return actual error code instead of -ENODEV
+    - arm64: dts: qcom: sm8150: fix number of pins in 'gpio-ranges'
+    - spi: stm32: drop devres version of spi_register_master
+    - arm64: dts: renesas: r8a77980: Fix vin4-7 endpoint binding
+    - x86/microcode: Check for offline CPUs before requesting new microcode
+    - usb: gadget: pch_udc: Replace cpu_to_le32() by lower_32_bits()
+    - usb: gadget: pch_udc: Check if driver is present before calling ->setup()
+    - usb: gadget: pch_udc: Check for DMA mapping error
+    - crypto: qat - don't release uninitialized resources
+    - crypto: qat - ADF_STATUS_PF_RUNNING should be set after adf_dev_init
+    - fotg210-udc: Fix DMA on EP0 for length > max packet size
+    - fotg210-udc: Fix EP0 IN requests bigger than two packets
+    - fotg210-udc: Remove a dubious condition leading to fotg210_done
+    - fotg210-udc: Mask GRP2 interrupts we don't handle
+    - fotg210-udc: Don't DMA more than the buffer can take
+    - fotg210-udc: Complete OUT requests on short packets
+    - mtd: require write permissions for locking and badblock ioctls
+    - bus: qcom: Put child node before return
+    - soundwire: bus: Fix device found flag correctly
+    - phy: marvell: ARMADA375_USBCLUSTER_PHY should not default to y,
+      unconditionally
+    - crypto: qat - fix error path in adf_isr_resource_alloc()
+    - usb: gadget: aspeed: fix dma map failure
+    - USB: gadget: udc: fix wrong pointer passed to IS_ERR() and PTR_ERR()
+    - memory: pl353: fix mask of ECC page_size config register
+    - soundwire: stream: fix memory leak in stream config error path
+    - m68k: mvme147,mvme16x: Don't wipe PCC timer config bits
+    - mtd: rawnand: gpmi: Fix a double free in gpmi_nand_init
+    - irqchip/gic-v3: Fix OF_BAD_ADDR error handling
+    - staging: rtl8192u: Fix potential infinite loop
+    - staging: greybus: uart: fix unprivileged TIOCCSERIAL
+    - PM / devfreq: Use more accurate returned new_freq as resume_freq
+    - spi: Fix use-after-free with devm_spi_alloc_*
+    - soc: qcom: mdt_loader: Validate that p_filesz < p_memsz
+    - soc: qcom: mdt_loader: Detect truncated read of segments
+    - ACPI: CPPC: Replace cppc_attr with kobj_attribute
+    - crypto: qat - Fix a double free in adf_create_ring
+    - cpufreq: armada-37xx: Fix setting TBG parent for load levels
+    - clk: mvebu: armada-37xx-periph: remove .set_parent method for CPU PM clock
+    - cpufreq: armada-37xx: Fix the AVS value for load L1
+    - clk: mvebu: armada-37xx-periph: Fix switching CPU freq from 250 Mhz to 1 GHz
+    - clk: mvebu: armada-37xx-periph: Fix workaround for switching from L1 to L0
+    - cpufreq: armada-37xx: Fix driver cleanup when registration failed
+    - cpufreq: armada-37xx: Fix determining base CPU frequency
+    - spi: fsl-lpspi: Fix PM reference leak in lpspi_prepare_xfer_hardware()
+    - usb: gadget: r8a66597: Add missing null check on return from
+      platform_get_resource
+    - USB: cdc-acm: fix unprivileged TIOCCSERIAL
+    - USB: cdc-acm: fix TIOCGSERIAL implementation
+    - tty: fix return value for unsupported ioctls
+    - serial: core: return early on unsupported ioctls
+    - firmware: qcom-scm: Fix QCOM_SCM configuration
+    - node: fix device cleanups in error handling code
+    - usbip: vudc: fix missing unlock on error in usbip_sockfd_store()
+    - platform/x86: pmc_atom: Match all Beckhoff Automation baytrail boards with
+      critclk_systems DMI table
+    - x86/platform/uv: Fix !KEXEC build failure
+    - usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
+    - usb: dwc2: Fix hibernation between host and device modes.
+    - ttyprintk: Add TTY hangup callback.
+    - xen-blkback: fix compatibility bug with single page rings
+    - soc: aspeed: fix a ternary sign expansion bug
+    - media: vivid: fix assignment of dev->fbuf_out_flags
+    - media: omap4iss: return error code when omap4iss_get() failed
+    - media: aspeed: fix clock handling logic
+    - media: platform: sunxi: sun6i-csi: fix error return code of
+      sun6i_video_start_streaming()
+    - media: m88rs6000t: avoid potential out-of-bounds reads on arrays
+    - drm/amdkfd: fix build error with AMD_IOMMU_V2=m
+    - x86/kprobes: Fix to check non boostable prefixes correctly
+    - pata_arasan_cf: fix IRQ check
+    - pata_ipx4xx_cf: fix IRQ check
+    - sata_mv: add IRQ checks
+    - ata: libahci_platform: fix IRQ check
+    - nvme-tcp: block BH in sk state_change sk callback
+    - nvmet-tcp: fix incorrect locking in state_change sk callback
+    - nvme: retrigger ANA log update if group descriptor isn't found
+    - media: v4l2-ctrls.c: fix race condition in hdl->requests list
+    - vfio/mdev: Do not allow a mdev_type to have a NULL parent pointer
+    - clk: zynqmp: move zynqmp_pll_set_mode out of round_rate callback
+    - clk: qcom: a53-pll: Add missing MODULE_DEVICE_TABLE
+    - clk: uniphier: Fix potential infinite loop
+    - scsi: hisi_sas: Fix IRQ checks
+    - scsi: jazz_esp: Add IRQ check
+    - scsi: sun3x_esp: Add IRQ check
+    - scsi: sni_53c710: Add IRQ check
+    - scsi: ibmvfc: Fix invalid state machine BUG_ON()
+    - mfd: stm32-timers: Avoid clearing auto reload register
+    - nvme-pci: don't simple map sgl when sgls are disabled
+    - HSI: core: fix resource leaks in hsi_add_client_from_dt()
+    - x86/events/amd/iommu: Fix sysfs type mismatch
+    - sched/debug: Fix cgroup_path[] serialization
+    - drivers/block/null_blk/main: Fix a double free in null_init.
+    - HID: plantronics: Workaround for double volume key presses
+    - perf symbols: Fix dso__fprintf_symbols_by_name() to return the number of
+      printed chars
+    - net: lapbether: Prevent racing when checking whether the netif is running
+    - powerpc/fadump: Mark fadump_calculate_reserve_size as __init
+    - powerpc/prom: Mark identical_pvr_fixup as __init
+    - inet: use bigger hash table for IP ID generation
+    - powerpc: Fix HAVE_HARDLOCKUP_DETECTOR_ARCH build configuration
+    - ALSA: core: remove redundant spin_lock pair in snd_card_disconnect
+    - bug: Remove redundant condition check in report_bug
+    - nfc: pn533: prevent potential memory corruption
+    - net: hns3: Limiting the scope of vector_ring_chain variable
+    - mips: bmips: fix syscon-reboot nodes
+    - ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls
+    - ASoC: simple-card: fix possible uninitialized single_cpu local variable
+    - liquidio: Fix unintented sign extension of a left shift of a u16
+    - powerpc/64s: Fix pte update for kernel memory on radix
+    - powerpc/perf: Fix PMU constraint check for EBB events
+    - powerpc: iommu: fix build when neither PCI or IBMVIO is set
+    - mac80211: bail out if cipher schemes are invalid
+    - mt7601u: fix always true expression
+    - KVM: PPC: Book3S HV P9: Restore host CTRL SPR after guest exit
+    - RDMA/qedr: Fix error return code in qedr_iw_connect()
+    - IB/hfi1: Fix error return code in parse_platform_config()
+    - cxgb4: Fix unintentional sign extension issues
+    - net: thunderx: Fix unintentional sign extension issue
+    - RDMA/srpt: Fix error return code in srpt_cm_req_recv()
+    - i2c: img-scb: fix reference leak when pm_runtime_get_sync fails
+    - i2c: imx-lpi2c: fix reference leak when pm_runtime_get_sync fails
+    - i2c: omap: fix reference leak when pm_runtime_get_sync fails
+    - i2c: sprd: fix reference leak when pm_runtime_get_sync fails
+    - i2c: cadence: add IRQ check
+    - i2c: emev2: add IRQ check
+    - i2c: jz4780: add IRQ check
+    - i2c: sh7760: add IRQ check
+    - powerpc/xive: Fix xmon command "dxi"
+    - ASoC: ak5558: correct reset polarity
+    - drm/i915/gvt: Fix error code in intel_gvt_init_device()
+    - perf beauty: Fix fsconfig generator
+    - MIPS: pci-legacy: stop using of_pci_range_to_resource
+    - powerpc/pseries: extract host bridge from pci_bus prior to bus removal
+    - rtlwifi: 8821ae: upgrade PHY and RF parameters
+    - i2c: sh7760: fix IRQ error path
+    - mwl8k: Fix a double Free in mwl8k_probe_hw
+    - vsock/vmci: log once the failed queue pair allocation
+    - gro: fix napi_gro_frags() Fast GRO breakage due to IP alignment check
+    - RDMA/cxgb4: add missing qpid increment
+    - RDMA/i40iw: Fix error unwinding when i40iw_hmc_sd_one fails
+    - ALSA: usb: midi: don't return -ENOMEM when usb_urb_ep_type_check fails
+    - net: davinci_emac: Fix incorrect masking of tx and rx error channel
+    - net: renesas: ravb: Fix a stuck issue when a lot of frames are received
+    - net: phy: intel-xway: enable integrated led functions
+    - ath9k: Fix error check in ath9k_hw_read_revisions() for PCI devices
+    - ath10k: Fix ath10k_wmi_tlv_op_pull_peer_stats_info() unlock without lock
+    - powerpc/52xx: Fix an invalid ASM expression ('addi' used instead of 'add')
+    - bnxt_en: fix ternary sign extension bug in bnxt_show_temp()
+    - ARM: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - arm64: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins for
+      RTL8211E
+    - net: geneve: modify IP header check in geneve6_xmit_skb and geneve_xmit_skb
+    - selftests: net: mirror_gre_vlan_bridge_1q: Make an FDB entry static
+    - bnxt_en: Fix RX consumer index logic in the error path.
+    - net:emac/emac-mac: Fix a use after free in emac_mac_tx_buf_send
+    - RDMA/siw: Fix a use after free in siw_alloc_mr
+    - RDMA/bnxt_re: Fix a double free in bnxt_qplib_alloc_res
+    - net: bridge: mcast: fix broken length + header check for MRDv6 Adv.
+    - net:nfc:digital: Fix a double free in digital_tg_recv_dep_req
+    - kfifo: fix ternary sign extension bugs
+    - mm/sparse: add the missing sparse_buffer_fini() in error branch
+    - mm/memory-failure: unnecessary amount of unmapping
+    - net: Only allow init netns to set default tcp cong to a restricted algo
+    - smp: Fix smp_call_function_single_async prototype
+    - Revert "net/sctp: fix race condition in sctp_destroy_sock"
+    - sctp: delay auto_asconf init until binding the first addr
+    - Revert "of/fdt: Make sure no-map does not remove already reserved regions"
+    - Revert "fdt: Properly handle "no-map" field in the memory region"
+    - Linux 5.4.119
+  * seccomp_bpf:syscall_faked from kselftests fail on s390x (LP: #1928522)
+    - selftests/seccomp: s390 shares the syscall and return value register
+  * Can't detect intel wifi 6235 (LP: #1920180)
+    - SAUCE: iwlwifi: add new pci id for 6235
+  * Mark kprobe_args_user.tc in kselftest/ftrace as unsupported (LP: #1929527)
+    - selftests/ftrace: Return unsupported for the unconfigured features
+  * pmtu.sh from net in ubuntu_kernel_selftests failed with no error message
+    (LP: #1887661)
+    - selftests: pmtu.sh: use $ksft_skip for skipped return code
+  * alsa/sof: make sof driver work in the case of without i915 (focal kernel)
+    (LP: #1927672)
+    - SAUCE: ASoC: SOF: Intel: hda: move the probe_bus ahead of creation of mach
+      device
+  * Fix kdump failures (LP: #1927518)
+    - video: hyperv_fb: Add ratelimit on error message
+    - Drivers: hv: vmbus: Increase wait time for VMbus unload
+    - Drivers: hv: vmbus: Initialize unload_event statically
+  * Ubuntu 20.04 - 'Support flow counters offset for bulk counters'
+    (LP: #1922494)
+    - IB/mlx5: Support flow counters offset for bulk counters
+  * Focal update: v5.4.118 upstream stable release (LP: #1928825)
+    - s390/disassembler: increase ebpf disasm buffer size
+    - ACPI: custom_method: fix potential use-after-free issue
+    - ACPI: custom_method: fix a possible memory leak
+    - ftrace: Handle commands when closing set_ftrace_filter file
+    - ARM: 9056/1: decompressor: fix BSS size calculation for LLVM ld.lld
+    - arm64: dts: marvell: armada-37xx: add syscon compatible to NB clk node
+    - arm64: dts: mt8173: fix property typo of 'phys' in dsi node
+    - ecryptfs: fix kernel panic with null dev_name
+    - mtd: spinand: core: add missing MODULE_DEVICE_TABLE()
+    - mtd: rawnand: atmel: Update ecc_stats.corrected counter
+    - erofs: add unsupported inode i_format check
+    - spi: spi-ti-qspi: Free DMA resources
+    - scsi: qla2xxx: Fix crash in qla2xxx_mqueuecommand()
+    - scsi: mpt3sas: Block PCI config access from userspace during reset
+    - mmc: uniphier-sd: Fix an error handling path in uniphier_sd_probe()
+    - mmc: uniphier-sd: Fix a resource leak in the remove function
+    - mmc: sdhci: Check for reset prior to DMA address unmap
+    - mmc: sdhci-pci: Fix initialization of some SD cards for Intel BYT-based
+      controllers
+    - mmc: block: Update ext_csd.cache_ctrl if it was written
+    - mmc: block: Issue a cache flush only when it's enabled
+    - mmc: core: Do a power cycle when the CMD11 fails
+    - mmc: core: Set read only for SD cards with permanent write protect bit
+    - mmc: core: Fix hanging on I/O during system suspend for removable cards
+    - modules: mark ref_module static
+    - modules: mark find_symbol static
+    - modules: mark each_symbol_section static
+    - modules: unexport __module_text_address
+    - modules: unexport __module_address
+    - modules: rename the licence field in struct symsearch to license
+    - modules: return licensing information from find_symbol
+    - modules: inherit TAINT_PROPRIETARY_MODULE
+    - irqchip/gic-v3: Do not enable irqs when handling spurious interrups
+    - cifs: Return correct error code from smb2_get_enc_key
+    - btrfs: fix metadata extent leak after failure to create subvolume
+    - intel_th: pci: Add Rocket Lake CPU support
+    - posix-timers: Preserve return value in clock_adjtime32()
+    - fbdev: zero-fill colormap in fbcmap.c
+    - bus: ti-sysc: Probe for l4_wkup and l4_cfg interconnect devices first
+    - staging: wimax/i2400m: fix byte-order issue
+    - spi: ath79: always call chipselect function
+    - spi: ath79: remove spi-master setup and cleanup assignment
+    - crypto: api - check for ERR pointers in crypto_destroy_tfm()
+    - crypto: qat - fix unmap invalid dma address
+    - usb: gadget: uvc: add bInterval checking for HS mode
+    - usb: webcam: Invalid size of Processing Unit Descriptor
+    - genirq/matrix: Prevent allocation counter corruption
+    - usb: gadget: f_uac2: validate input parameters
+    - usb: gadget: f_uac1: validate input parameters
+    - usb: dwc3: gadget: Ignore EP queue requests during bus reset
+    - usb: xhci: Fix port minor revision
+    - PCI: PM: Do not read power state in pci_enable_device_flags()
+    - x86/build: Propagate $(CLANG_FLAGS) to $(REALMODE_FLAGS)
+    - tee: optee: do not check memref size on return from Secure World
+    - perf/arm_pmu_platform: Fix error handling
+    - usb: xhci-mtk: support quirk to disable usb2 lpm
+    - xhci: check control context is valid before dereferencing it.
+    - xhci: fix potential array out of bounds with several interrupters
+    - spi: dln2: Fix reference leak to master
+    - spi: omap-100k: Fix reference leak to master
+    - spi: qup: fix PM reference leak in spi_qup_remove()
+    - usb: musb: fix PM reference leak in musb_irq_work()
+    - usb: core: hub: Fix PM reference leak in usb_port_resume()
+    - tty: n_gsm: check error while registering tty devices
+    - intel_th: Consistency and off-by-one fix
+    - phy: phy-twl4030-usb: Fix possible use-after-free in twl4030_usb_remove()
+    - crypto: stm32/hash - Fix PM reference leak on stm32-hash.c
+    - crypto: stm32/cryp - Fix PM reference leak on stm32-cryp.c
+    - crypto: omap-aes - Fix PM reference leak on omap-aes.c
+    - platform/x86: intel_pmc_core: Don't use global pmcdev in quirks
+    - btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s
+    - drm: Added orientation quirk for OneGX1 Pro
+    - drm/qxl: release shadow on shutdown
+    - drm/amd/display: Check for DSC support instead of ASIC revision
+    - drm/amd/display: Don't optimize bandwidth before disabling planes
+    - scsi: lpfc: Fix incorrect dbde assignment when building target abts wqe
+    - scsi: lpfc: Fix pt2pt connection does not recover after LOGO
+    - scsi: target: pscsi: Fix warning in pscsi_complete_cmd()
+    - media: ite-cir: check for receive overflow
+    - media: drivers: media: pci: sta2x11: fix Kconfig dependency on GPIOLIB
+    - media: imx: capture: Return -EPIPE from __capture_legacy_try_fmt()
+    - power: supply: bq27xxx: fix power_avg for newer ICs
+    - extcon: arizona: Fix some issues when HPDET IRQ fires after the jack has
+      been unplugged
+    - extcon: arizona: Fix various races on driver unbind
+    - media: media/saa7164: fix saa7164_encoder_register() memory leak bugs
+    - media: gspca/sq905.c: fix uninitialized variable
+    - power: supply: Use IRQF_ONESHOT
+    - drm/amdgpu: mask the xgmi number of hops reported from psp to kfd
+    - drm/amdkfd: Fix UBSAN shift-out-of-bounds warning
+    - drm/amdgpu : Fix asic reset regression issue introduce by 8f211fe8ac7c4f
+    - drm/amd/display: Fix UBSAN warning for not a valid value for type '_Bool'
+    - drm/amd/display: fix dml prefetch validation
+    - scsi: qla2xxx: Always check the return value of qla24xx_get_isp_stats()
+    - drm/vkms: fix misuse of WARN_ON
+    - scsi: qla2xxx: Fix use after free in bsg
+    - mmc: sdhci-pci: Add PCI IDs for Intel LKF
+    - ata: ahci: Disable SXS for Hisilicon Kunpeng920
+    - scsi: smartpqi: Correct request leakage during reset operations
+    - scsi: smartpqi: Add new PCI IDs
+    - scsi: scsi_dh_alua: Remove check for ASC 24h in alua_rtpg()
+    - media: em28xx: fix memory leak
+    - media: vivid: update EDID
+    - clk: socfpga: arria10: Fix memory leak of socfpga_clk on error return
+    - power: supply: generic-adc-battery: fix possible use-after-free in
+      gab_remove()
+    - power: supply: s3c_adc_battery: fix possible use-after-free in
+      s3c_adc_bat_remove()
+    - media: tc358743: fix possible use-after-free in tc358743_remove()
+    - media: adv7604: fix possible use-after-free in adv76xx_remove()
+    - media: i2c: adv7511-v4l2: fix possible use-after-free in adv7511_remove()
+    - media: i2c: tda1997: Fix possible use-after-free in tda1997x_remove()
+    - media: i2c: adv7842: fix possible use-after-free in adv7842_remove()
+    - media: platform: sti: Fix runtime PM imbalance in regs_show
+    - media: dvb-usb: fix memory leak in dvb_usb_adapter_init
+    - media: gscpa/stv06xx: fix memory leak
+    - sched/fair: Ignore percpu threads for imbalance pulls
+    - drm/msm/mdp5: Configure PP_SYNC_HEIGHT to double the vtotal
+    - drm/msm/mdp5: Do not multiply vclk line count by 100
+    - drm/amdkfd: Fix cat debugfs hang_hws file causes system crash bug
+    - amdgpu: avoid incorrect %hu format string
+    - drm/amdgpu: fix NULL pointer dereference
+    - scsi: lpfc: Fix crash when a REG_RPI mailbox fails triggering a LOGO
+      response
+    - scsi: lpfc: Fix error handling for mailboxes completed in MBX_POLL mode
+    - scsi: lpfc: Remove unsupported mbox PORT_CAPABILITIES logic
+    - mfd: arizona: Fix rumtime PM imbalance on error
+    - scsi: libfc: Fix a format specifier
+    - s390/archrandom: add parameter check for s390_arch_random_generate
+    - ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer
+    - ALSA: hda/conexant: Re-order CX5066 quirk table entries
+    - ALSA: sb: Fix two use after free in snd_sb_qsound_build
+    - ALSA: usb-audio: Explicitly set up the clock selector
+    - ALSA: usb-audio: More constifications
+    - ALSA: usb-audio: Add dB range mapping for Sennheiser Communications Headset
+      PC 8
+    - ALSA: hda/realtek: GA503 use same quirks as GA401
+    - ALSA: hda/realtek: fix mic boost on Intel NUC 8
+    - ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops
+    - ALSA: hda/realtek: Add quirk for Intel Clevo PCx0Dx
+    - btrfs: fix race when picking most recent mod log operation for an old root
+    - arm64/vdso: Discard .note.gnu.property sections in vDSO
+    - Makefile: Move -Wno-unused-but-set-variable out of GCC only block
+    - virtiofs: fix memory leak in virtio_fs_probe()
+    - ubifs: Only check replay with inode type to judge if inode linked
+    - f2fs: fix to avoid out-of-bounds memory access
+    - mlxsw: spectrum_mr: Update egress RIF list before route's action
+    - openvswitch: fix stack OOB read while fragmenting IPv4 packets
+    - ACPI: GTDT: Don't corrupt interrupt mappings on watchdow probe failure
+    - NFS: Don't discard pNFS layout segments that are marked for return
+    - NFSv4: Don't discard segments marked for return in _pnfs_return_layout()
+    - Input: ili210x - add missing negation for touch indication on ili210x
+    - jffs2: Fix kasan slab-out-of-bounds problem
+    - powerpc/eeh: Fix EEH handling for hugepages in ioremap space.
+    - powerpc: fix EDEADLOCK redefinition error in uapi/asm/errno.h
+    - intel_th: pci: Add Alder Lake-M support
+    - tpm: efi: Use local variable for calculating final log size
+    - tpm: vtpm_proxy: Avoid reading host log when using a virtual device
+    - crypto: rng - fix crypto_rng_reset() refcounting when !CRYPTO_STATS
+    - md/raid1: properly indicate failure when ending a failed write request
+    - dm raid: fix inconclusive reshape layout on fast raid4/5/6 table reload
+      sequences
+    - fuse: fix write deadlock
+    - security: commoncap: fix -Wstringop-overread warning
+    - Fix misc new gcc warnings
+    - jffs2: check the validity of dstlen in jffs2_zlib_compress()
+    - Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
+    - x86/cpu: Initialize MSR_TSC_AUX if RDTSCP *or* RDPID is supported
+    - kbuild: update config_data.gz only when the content of .config is changed
+    - ext4: fix check to prevent false positive report of incorrect used inodes
+    - ext4: do not set SB_ACTIVE in ext4_orphan_cleanup()
+    - ext4: fix error code in ext4_commit_super
+    - media: dvbdev: Fix memory leak in dvb_media_device_free()
+    - media: dvb-usb: Fix use-after-free access
+    - media: dvb-usb: Fix memory leak at error in dvb_usb_device_init()
+    - media: staging/intel-ipu3: Fix memory leak in imu_fmt
+    - media: staging/intel-ipu3: Fix set_fmt error handling
+    - media: staging/intel-ipu3: Fix race condition during set_fmt
+    - usb: gadget: dummy_hcd: fix gpf in gadget_setup
+    - usb: gadget: Fix double free of device descriptor pointers
+    - usb: gadget/function/f_fs string table fix for multiple languages
+    - usb: dwc3: gadget: Fix START_TRANSFER link state check
+    - usb: dwc2: Fix session request interrupt handler
+    - tty: fix memory leak in vc_deallocate
+    - rsi: Use resume_noirq for SDIO
+    - tracing: Map all PIDs to command lines
+    - tracing: Restructure trace_clock_global() to never block
+    - dm persistent data: packed struct should have an aligned() attribute too
+    - dm space map common: fix division bug in sm_ll_find_free_block()
+    - dm integrity: fix missing goto in bitmap_flush_interval error handling
+    - dm rq: fix double free of blk_mq_tag_set in dev remove after table load
+      fails
+    - Linux 5.4.118
+  * Focal update: v5.4.117 upstream stable release (LP: #1928823)
+    - mips: Do not include hi and lo in clobber list for R6
+    - ACPI: tables: x86: Reserve memory occupied by ACPI tables
+    - ACPI: x86: Call acpi_boot_table_init() after acpi_table_upgrade()
+    - net: usb: ax88179_178a: initialize local variables before use
+    - igb: Enable RSS for Intel I211 Ethernet Controller
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_enqueue_hcmd()
+    - bpf: Fix masking negation logic upon negative dst register
+    - bpf: Fix leakage of uninitialized bpf stack under speculation
+    - avoid __memcat_p link failure
+    - iwlwifi: Fix softirq/hardirq disabling in iwl_pcie_gen2_enqueue_hcmd()
+    - perf data: Fix error return code in perf_data__create_dir()
+    - perf ftrace: Fix access to pid in array when setting a pid filter
+    - ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX
+    - USB: Add reset-resume quirk for WD19's Realtek Hub
+    - platform/x86: thinkpad_acpi: Correct thermal sensor allocation
+    - scsi: ufs: Unlock on a couple error paths
+    - ovl: allow upperdir inside lowerdir
+    - perf/core: Fix unconditional security_locked_down() call
+    - vfio: Depend on MMU
+    - Linux 5.4.117
+  * r8152 tx status -71 (LP: #1922651) // Focal update: v5.4.117 upstream stable
+    release (LP: #1928823)
+    - USB: Add LPM quirk for Lenovo ThinkPad USB-C Dock Gen2 Ethernet
+  * Focal update: v5.4.116 upstream stable release (LP: #1928821)
+    - bpf: Move off_reg into sanitize_ptr_alu
+    - bpf: Ensure off_reg has no mixed signed bounds for all types
+    - bpf: Rework ptr_limit into alu_limit and add common error path
+    - bpf: Improve verifier error messages for users
+    - bpf: Refactor and streamline bounds check into helper
+    - bpf: Move sanitize_val_alu out of op switch
+    - bpf: Tighten speculative pointer arithmetic mask
+    - bpf: Update selftests to reflect new error states
+    - Linux 5.4.116
+  * Focal update: v5.4.115 upstream stable release (LP: #1927997)
+    - gpio: omap: Save and restore sysconfig
+    - pinctrl: lewisburg: Update number of pins in community
+    - arm64: dts: allwinner: Revert SD card CD GPIO for Pine64-LTS
+    - perf/x86/intel/uncore: Remove uncore extra PCI dev HSWEP_PCI_PCU_3
+    - perf/x86/kvm: Fix Broadwell Xeon stepping in isolation_ucodes[]
+    - perf auxtrace: Fix potential NULL pointer dereference
+    - HID: google: add don USB id
+    - HID: alps: fix error return code in alps_input_configured()
+    - HID: wacom: Assign boolean values to a bool variable
+    - ARM: dts: Fix swapped mmc order for omap3
+    - net: geneve: check skb is large enough for IPv4/IPv6 header
+    - s390/entry: save the caller of psw_idle
+    - xen-netback: Check for hotplug-status existence before watching
+    - cavium/liquidio: Fix duplicate argument
+    - csky: change a Kconfig symbol name to fix e1000 build error
+    - ia64: fix discontig.c section mismatches
+    - ia64: tools: remove duplicate definition of ia64_mf() on ia64
+    - x86/crash: Fix crash_setup_memmap_entries() out-of-bounds access
+    - net: hso: fix NULL-deref on disconnect regression
+    - USB: CDC-ACM: fix poison/unpoison imbalance
+    - Linux 5.4.115
+
+ -- Wen-chien Jesse Sung <jesse.sung@canonical.com>  Tue, 17 May 2022 23:22:43 +0800
+
+linux-imx (5.4.0-1013.13) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_OPTEE=y by default on armhf too
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 22 Oct 2021 01:24:50 +0800
+
+linux-imx (5.4.0-1012.12) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix uart3 pinmux functions
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix pinconf for led shutdown & led
+      alarm clear gpios
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: configure uart1 dte mode for
+      RS485/touchflakes
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: add support for FRAM/SPI-NOR flash
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: add support for gpio-wdog
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: enable support for flexcan1
+    - [Config] CONFIG_ADIN_PHY=m
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: uart4 rs485 mode at boot by default
+    - SAUCE: mtd: spi-nor: add support for for Fujitsu MB85RQ4ML FRAM
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix pinmux conf for i2c4 bus
+    - [Config] updateconfigs for NXP/IMX controllers, MTD NOR support built-in
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: switch uart2 to rs485 port
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: stop passing uart2 as boot console
+      output
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: support push-button on led front board
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: fix bt & wifi power regulator
+      definitions
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add spi entries for common module p1/p2
+      & lte
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: set external rtc as default
+    - SAUCE: arm64: dts: imx8mn-venice-gw7902: set external rtc as default
+    - SAUCE: arm64: dts: imx8m*-venice-gw7902: add reserved memory areas for optee
+    - SAUCE: arm64: dts: imx8m*-venice-gw7902: add firmware entry for optee-tz
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: don't define gpio-hogs for uart-sel
+      pins
+
+  * Miscellaneous upstream changes
+    - can: dev: can_restart(): remove unused code
+    - can: rx-offload: fix long lines
+    - can: rx-offload: can_rx_offload_compare(): fix typo
+    - can: rx-offload: can_rx_offload_irq_offload_timestamp(): don't use
+      assignment in if condition
+    - can: rx-offload: can_rx_offload_reset(): remove no-op function
+    - can: rx-offload: Prepare for CAN FD support
+    - can: flexcan: use devm_platform_ioremap_resource() to simplify code
+    - can: flexcan: flexcan_irq_state(): only read timestamp if needed
+    - can: flexcan: rename macro FLEXCAN_IFLAG_MB() -> FLEXCAN_IFLAG2_MB()
+    - can: flexcan: flexcan_irq(): rename variable reg_iflag -> reg_iflag_rx
+    - can: flexcan: rename struct flexcan_priv::reg_imask{1,2}_default to
+      rx_mask{1,2}
+    - can: flexcan: remove TX mailbox bit from struct flexcan_priv::rx_mask{1,2}
+    - can: flexcan: convert struct flexcan_priv::rx_mask{1,2} to rx_mask
+    - can: flexcan: introduce struct flexcan_priv::tx_mask and make use of it
+    - can: flexcan: flexcan_read_reg_iflag_rx(): optimize reading
+    - can: flexcan: flexcan_irq(): add support for TX mailbox in iflag1
+    - can: flexcan: flexcan_mailbox_read() make use of flexcan_write64() to mark
+      the mailbox as read
+    - can: flexcan: fix spelling mistake "reserverd" -> "reserved"
+    - can: flexcan: sort include files alphabetically
+    - can: flexcan: flexcan_exit_stop_mode(): remove stray empty line
+    - can: flexcan: more register names
+    - can: flexcan: struct flexcan_regs: document registers not affected by soft
+      reset
+    - can: flexcan: quirks: get rid of long lines
+    - can: flexcan: Ack wakeup interrupt separately
+    - can: flexcan: flexcan_probe(): make regulator xceiver optional
+    - can: flexcan: Add check for transceiver maximum bitrate limitation
+    - can: flexcan: add correctable errors correction when HW supports ECC
+    - can: flexcan: add LPSR mode support
+    - can: flexcan: flexcan_set_bittiming(): move setup of CAN-2.0 bitiming into
+      separate function
+    - can: flexcan: use struct canfd_frame for CAN classic frame
+    - can: flexcan: add CAN-FD mode support
+    - can: flexcan: add ISO CAN FD feature support
+    - can: flexcan: add CAN FD BRS support
+    - can: flexcan: add Transceiver Delay Compensation support
+    - can: flexcan: add imx8qm support
+    - can: flexcan: add lx2160ar1 support
+    - can: flexcan: initialize all flexcan memory for ECC function
+    - can: flexcan: add flexcan driver for i.MX8MP
+    - can: flexcan: disable runtime PM if register flexcandev failed
+    - can: flexcan: remove ack_grp and ack_bit handling from driver
+    - can: flexcan: flexcan_setup_stop_mode(): add missing "req_bit" to stop mode
+      property comment
+    - serial: sc16is7xx: Replace zero-length array with flexible-array member
+    - sc16is7xx: Always use falling edge IRQ
+    - sc16is7xx: Use threaded IRQ
+    - sc16is7xx: Allow sharing the IRQ line
+    - sc16is7xx: Read the LSR register for basic device presence check
+    - sc16is7xx: Add flag to activate IrDA mode
+    - sc16is7xx: Set iobase to device index
+    - sc16is7xx: Defer probe if device read fails
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Thu, 21 Oct 2021 14:31:04 +0800
+
+linux-imx (5.4.0-1011.11) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: reserve memory for global dma usage
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: adjust ocram memory sections for optee-
+      lpm
+    - SAUCE: MLK-11488-1 driver: char: sema4: add sema4 support
+    - SAUCE: MLK-11488-2 arm: imx: add HAVE_IMX_AMP for imx6sx
+    - SAUCE: MLK-11488-4 arm: dts: imx6sx: add sema4 support
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add qspi restore node for
+      suspend/resume when M4 is enabled
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add mailbox support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: Add spi-[tx/rx]-bus-width for the FSL
+      QSPI controller
+    - [Config] CONFIG_IMX_SEMA4=y
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix simple-audio-card widget names
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable pixel pipeline module
+    - [Config] FLEXSPI, QUADSPI drivers as modules
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: OV5640 camera module is on i2c4
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: use unique labels instead of colour-ids
+      for gpio-leds
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix gpio-keys pinconfig defs
+    - SAUCE: media: mipi csi: add mixel's mipi csi driver
+    - SAUCE: media: mipi csi: add samsung's mipi csi support
+    - SAUCE: media: mipi csi: accommodate the driver to framework's change
+    - SAUCE: mxc-jpeg: Add v4l2 driver for i.MX8 CAST IP JPEG Encoder/Decoder
+    - SAUCE: mxc-jpeg: Add support for multi power domain
+    - SAUCE: mxc-jpeg: Build mxc-jpeg as module, by default
+    - SAUCE: media: mxc-jpeg: jpeg: Replace stracpy with strscpy
+    - SAUCE: mxc-jpeg: Fix warning at build, for EXPORT_SYMBOL on static variable
+    - SAUCE: MLK-22835: mxc-jpeg: jpeg decoder stuck due to race condition
+    - SAUCE: media: IPU: add IPU csi and prp driver
+    - SAUCE: media: v4l2: add int device framework for backward support
+    - SAUCE: media: capture: add mxc v4l2 capture driver
+    - SAUCE: media: add Kconfig and Makefile for the capture driver
+    - SAUCE: media: add adv7180 video decoder driver
+    - SAUCE: media: v4l2 capture: add v4l2 capture driver based on csi
+    - SAUCE: media: mx6s_capture: accommodate the driver to framework's change
+    - SAUCE: media: v4l2: vadc: Enable vadc driver
+    - SAUCE: media: capture: add ov5640 mipi and parallel driver
+    - SAUCE: media: capture: add ov5640 mipi and parallel driver of subdev version
+    - SAUCE: media: ov5640: fix kernel warning when no camera is plugged in
+    - SAUCE: media: ov5640 mipi: fix kernel warning when no camera is plugged in
+    - SAUCE: media: ov5640 mipi v2: fix kernel warning when no camera is plugged
+      in
+    - SAUCE: media: ov5640 v2: fix kernel warning when no camera is plugged in
+    - SAUCE: media: platform: mxc: capture: ov5640: Disable regulators in
+      ov5640_remove()
+    - SAUCE: LF-237 media: ov5640_mipi: fix regulator dump when i2c access for
+      camera fail
+    - SAUCE: media: platform: mxc: output: Forward IPUv3 V4L2 output driver from
+      imx_4.19.y
+    - SAUCE: media: v4l2: add pxp_v4l2 driver
+    - SAUCE: LF-135 media: mx6s_capture: fix kernel dump when start two instances
+      of capture
+    - SAUCE: LF-300-1 media: mipi csi: make the csi clock usecount to 0 when it's
+      not used
+    - SAUCE: LF-300-2 media: mipi csi: make the csi clock usecount to 0 when it's
+      not used
+    - SAUCE: LF-482 media: mipi csi: fix build warning
+    - SAUCE: MLK-23712: media: capture: add get/set_register callback
+    - SAUCE: LF-1599 media: platform: mxc_vout: Do not check 's->r.width/height<0'
+      in ->vidioc_s_selection
+    - SAUCE: LF-1561 check return value of v4l2_async_notifier_add_subdev
+    - SAUCE: MLK-24261 media: mipi csi: fix kernel dump when do module removal
+    - SAUCE: MLK-24389 media: mx6s_capture: use vb2_fop_mmap instead
+    - SAUCE: LF-1564 media: capture: check return value of devm_kzalloc against
+      NULL
+    - SAUCE: LF-1711 media: mipi csi: check return value of
+      v4l2_async_notifier_add_subdev
+    - SAUCE: LF-1583: mxc-jpeg: Fix possible null pointer dereference
+    - SAUCE: LF-1571: mxc-jpeg: Fix result independent of operands
+    - SAUCE: media: staging: csi: add mipi csi driver support for IMX8
+    - SAUCE: staging: media: imx: add video ops for imx8 mipi csi subdev
+    - SAUCE: staging: media: imx: add V4L2 subdev driver for MIPI CSI2 of Samsung
+    - SAUCE: media: staging: imx: add isi driver support for imx8qm/qxp
+    - SAUCE: MLK-21985-8 media: isi: fix build for next 20190607 upgrade
+    - SAUCE: media: isi: fix boot warning by intialize device_caps
+    - SAUCE: media: staging: imx: add isi core driver support for imx8qm/qxp
+    - SAUCE: media: staging: imx: add isi capture driver support for imx8qm/qxp
+    - SAUCE: media: staging: imx: add V4L2 memory to memory driver for ISI of
+      imx8qxp/qm
+    - SAUCE: staging: media: imx: enable ISI for imx8mn platform
+    - SAUCE: staging: media: imx: add g_parm/s_parm for imx8 capture device
+    - SAUCE: media: staging: imx: add driver for GMSL MAX9286 device
+    - SAUCE: LF-116: staging: media: imx: fix no enum_frameinterval result issue
+    - SAUCE: media: staging: imx: add media device driver support for IMX8
+    - SAUCE: staging: media: imx: add parallel capture interface driver for
+      imx8qxp
+    - SAUCE: staging: media: imx: add video ops for imx8 parallel subdev
+    - SAUCE: LF-101: staging: media: imx: fix XR24 format R and B are opposite
+      issue
+    - SAUCE: LF-356: media: imx8 isi: fix buffer active bit change for QXP C0
+    - SAUCE: LF-364: media: isi: correct capabilities for ISI m2m video device
+    - SAUCE: LF-79: staging: media: imx: replace s_parm/g_parm with
+      s/g_frame_interval
+    - SAUCE: LF-433: staging: media: imx: refine mipi csi2 driver for Samsung
+    - SAUCE: LF-467: media: imx: isi: fix some typo issues
+    - SAUCE: LF-510: staging: media: imx: add s/g_frame_interval support for
+      max9286
+    - SAUCE: LF-486: staging: media: imx: fix uninitialized variable
+    - SAUCE: LF-221: staging: media: imx: fix potential memory out of bound
+    - SAUCE: LF-762: media: correct multi instance management for CSI camera
+    - SAUCE: MLK-23227-3: media: imx: add ISI IER register as platform data
+    - SAUCE: MLK-23227-4: media: imx: add input image source port selection as
+      platform data
+    - SAUCE: MLK-23227-5: media: imx: refine soc version match method for ISI
+    - SAUCE: MLK-23227-6: media: imx: add driver support for ISI of i.MX8MP
+    - SAUCE: MLK-23227-7: media: imx: add multi instance for MIPI CSI driver
+    - SAUCE: MLK-23227-8: media: imx: remove CSI PHY clock operation
+    - SAUCE: MLK-23227-9: media: imx: use no-reset-control property in ISI of
+      i.MX8MP
+    - SAUCE: MLK-23227-11: media: imx: set panic threshold in ISI
+    - SAUCE: MLK-23358-1: media: imx8: fix dereferencing null pointer issue
+    - SAUCE: MLK-23358-2: media: imx: fix variable uninitialized issue
+    - SAUCE: LF-1089: media: imx: fix 1024x768@15 camera issue for imx8qm and qxp
+    - SAUCE: MLK-23578-1: media: m2m: enable ISI m2m feature for i.MX865
+    - SAUCE: MLK-23750-2: media: csi: fix ISI_0, CSI_0 can't enter lp when suspend
+    - SAUCE: MLK-23750-3: media: pi: fix ISI_0, PI_0 can't enter lp when suspend
+    - SAUCE: MLK-23860: media: imx: improve calculation for csi RXHS_SETTLE
+      parameter
+    - SAUCE: MLK-24375-01: mixel: csi2: detach power domain when driver removed
+    - SAUCE: MLK-24375-02: imx: pi: detach power domain when pi drvier removed
+    - SAUCE: MLK-24376: isi: core: depopulate child device when parent driver
+      removed
+    - SAUCE: LF-1409-01: media: imx: isi: export functions in imx8-isi-hw.c file
+    - SAUCE: LF-1409-02: media: isi: cap: export mxc_isi_cap_frame_write_done
+    - SAUCE: LF-1409-03: media: isi: m2m: export mxc_isi_m2m_frame_write_done
+    - SAUCE: LF-1409-04: media: isi: move two methods in isi core driver to hw
+      driver
+    - SAUCE: LF-1409-05: media: isi: config ISI HW driver as a separate driver
+    - SAUCE: LF-1409-06: media: isi: cap: config capture driver as tristate
+    - SAUCE: LF-1409-07: media: isi: m2m: config mem2mem driver as tristate
+    - SAUCE: LF-1409-08: media: isi: core: config ISI core driver as tristate
+    - SAUCE: MLK-24494-1: staging: media: csi: reuse csi driver for isp
+    - SAUCE: MLK-24494-4: staging: media: imx8: work around to support isi + isp
+      dual camera
+    - SAUCE: MLK-24514-1: staging: media: samsung csi: print message when fail to
+      get gpr
+    - SAUCE: MLK-24696: media: csi: return error when no command support
+    - SAUCE: MLK-24745: media: isi: fix pyeiq can't detect camera device
+    - SAUCE: MLK-24746: media: imx8: return directly for independent entity
+    - SAUCE: MLK-24981: media: isi: correct ISI chain buffer mask value
+    - SAUCE: MLK-24982: media: isi: disable ISI channel clock after stream off
+    - SAUCE: MLK-24983-01: media: isi: remove redundant code for clean the list
+    - SAUCE: MLK-24983-02: isi: use list_del_init instead of list_del
+    - SAUCE: MLK-24984: isi: use spin_lock_irqsave in irq handler to disable
+      interrupt
+    - SAUCE: MLK-24986: media: isi: add 4K support for iMX8MN ISI
+    - SAUCE: MLK-24987: media: isi: align discard buffer size to page size
+    - SAUCE: MLK-25000-1: media: csi: Enable V4L2_SUBDEV_FL_HAS_DEVNODE flag
+    - SAUCE: MLK-25027-2: media: isi: add workaround for iMX865 ISI to support 4K
+    - SAUCE: MLK-25027-3: media: isi: remove "fsl,chain_buf" property parse
+    - SAUCE: MLK-25027-4: media: isi: remove 4K feature for ISI channel1
+    - SAUCE: MLK-25039-01: media: isi: m2m: use V4L2 RGBA32 format define in V4L2
+      framework
+    - SAUCE: MLK-25041: media: imx8: media-dev: return if media device has been
+      registered
+    - SAUCE: LF-2474: media: samsung csi: fix string overflow issue
+    - SAUCE: MLK-9662 [V4L2 Capture] Revert patch to re-add support for
+      _G_CHIP_IDENT
+    - SAUCE: MLK-21770: media: v4l: Add packed YUV444 24bpp pixel format
+    - SAUCE: MLK-24477-1:[8QM_MEK/8QXP_MEK]mxc:vpu_windsor: enable color
+      description in vui
+    - SAUCE: media: mx6s_capture: remove imx-busfreq support
+    - SAUCE: MMFMWK-7549 [media] videobuf: store field and timestamp when queue
+      USERPTR buffer
+    - SAUCE: media: v4l2: export video_usercopy function
+    - SAUCE: Revert "media: v4l2-ioctl: clear fields in s_parm"
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: switch to fslc mxc csi platform driver
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: switch to ov5640_v2 mxc csi platform
+      driver
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: use clk names that csi fslc driver
+      expects
+    - SAUCE: clk: imx6sx: keep OCRAM_S always ON
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add pxp_v4l2_out support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: let sound card driver control codec clk
+    - [Config] updateconfigs, enable fslc camera drivers, disable upstream
+      versions
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add pinctrl hogs for board_id, run led
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: usb2 host mode for lte-cellular module
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: rs485 uarts are full-duplex with hw
+      flow control
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: update gpio hogs for common port 1,2
+      uart_sel & ttl/rs232 port
+    - SAUCE: clk: imx6sx: explicitly gate gpmi_io & qspi2 clks during init
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable adc support
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: cleanup wifi/bt regulators
+    - SAUCE: MLK-13793-6 regulator: anatop: fix min dropout for bypass mode
+    - SAUCE: MLK-23562: regulator: core: adjust supply voltage in bypass
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add power domain for csi
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: allow ldo-bypass for gpc power domain
+    - SAUCE: MLK-22986-1: soc: imx: gpc: add ldo-bypass
+
+  * Miscellaneous upstream changes
+    - Revert "drm/imx/dcss: allow using nearest neighbor interpolation scaling"
+    - Revert "drm/imx/dcss: fix coccinelle warning"
+    - Revert "drm/imx/dcss: fix rotations for Vivante tiled formats"
+    - Revert "drm/imx/dcss: fix unused but set variable warnings"
+    - Revert "drm/imx/dcss: fix compilation issue on 32bit"
+    - Revert "drm/imx/dcss: use drm_bridge_connector API"
+    - Revert "drm/imx: Add initial support for DCSS on iMX8MQ"
+    - Revert "UBUNTU: SAUCE: ARM: dts: imx6sx-x6med35-som: disable rpmsg, don't
+      reserve memory"
+    - Revert "media: v4l2-subdev.h: remove obsolete g/s_parm"
+    - Revert "UBUNTU: [Config] CONFIG_REGULATOR_ANATOP=y on imx6 based platforms"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Tue, 21 Sep 2021 01:54:41 +0800
+
+linux-imx (5.4.0-1010.10) focal; urgency=medium
+
+  * Miscellaneous upstream changes
+    - rtc: m41t80: set range
+    - arm64: dts: imx8m*-venice-gw7902: fix M2_RST# gpio
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 06 Sep 2021 16:33:15 +0800
+
+linux-imx (5.4.0-1009.9) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: fix phandle node definition for bwm-
+      beeper
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: cleanup re-init of i2c2 properties
+    - SAUCE: arm64: dts: imx8mp: support x8high35 bms
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: only emmc, crypto & soc are on the SOM
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add rts-gpios for rs485 uarts
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add gpio-hogs for ttl/rs232 uart_sel,
+      rs485 common port sel
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: ensure P11,P12 are set in rs485 mode
+      from boot
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable s1, s2 push-buttons as wakeup-
+      source
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: support OV5640 camera sensor on csi0
+    - [Config] support OV5640 cmos camera sensors
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: reduce pwm-beeper freq
+    - [Config] disable unused audio codec drivers
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix audmux pinconf
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: support nau8822 audio with simple-
+      sound-card
+    - [Config] CONFIG_SND_SOC_NAU8822=m
+    - [Config] enable IMX PXP, CODA
+    - [Config] DM_CRYPT, SHA256/512, ARMv7/8 AES built-in
+    - SAUCE: arm64: dts: imx8mp: x8high-som: define 2G memory properly
+    - SAUCE: arm64: dts: imx8mp: x8high-som: rename 35som status led node
+    - SAUCE: arm64: dts: imx8mp: x8high-som: rename regulators as per the dt-
+      schema
+    - SAUCE: ARM: dts: imx8mp-x8high-bms: disable rts-gpio for uart2 to enable
+      serial console
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: ldo5 1v8 to power BM28 SDIO VIO
+    - [Config] CONFIG_OF_NUMA=y by default
+    - SAUCE: ARM: dts: imx8mp-x8high35-bms: reserve memory for global dma usage
+    - CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C=m
+
+  * Miscellaneous upstream changes
+    - ASoC: fsl: Replace HTTP links with HTTPS ones
+    - arm64: dts: imx8mp: Add dsp node
+    - arm64: dts: imx8mp: remove fallback compatible string for FlexCAN
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Sun, 22 Aug 2021 22:35:14 +0800
+
+linux-imx (5.4.0-1008.8) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] add canonical-hwe-team ppa to get abis
+
+  * Miscellaneous upstream changes
+    - arm64: dts: imx8mn-venice-gw7901: update gpio for revision-B board
+    - i2c: imx: support slave mode for imx I2C driver
+    - arm64: dts: imx8m*-venice-gw7902: fix phy configuration
+    - arm64: dts: imx8m*-venice-gw7902: fix phy configuration for 5.4 kernel
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Wed, 04 Aug 2021 22:58:57 +0800
+
+linux-imx (5.4.0-1007.7) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: only pmic, emmc, crypto & soc are on
+      the SOM
+    - SAUCE: extcon: poll cable status using timer
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: remove optional vbus supply to get
+      usb working
+    - SAUCE: arm64: dts: imx8mp: x8high-pdk: read eqos eth mac addr from ocotp-
+      nvmem
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: read fec1/2 eth mac addrs from nvmem-
+      ocotp
+
+  * Miscellaneous upstream changes
+    - usb: dwc3: imx8mp: fix error return code in dwc3_imx8mp_probe()
+    - usb: dwc3: ep0: fix NULL pointer exception
+    - usb: dwc3: core: fix kernel panic when do reboot
+    - usb: dwc3: create debugfs directory under usb root
+    - usb: dwc3: Disable phy suspend after power-on reset
+    - usb: dwc3: debug: Remove newline printout
+    - usb: dwc3: of-simple: add a shutdown
+    - usb: dwc3: gadget: Don't send unintended link state change
+    - usb: dwc3: gadget: Set link state to RX_Detect on disconnect
+    - usb: dwc3: gadget: Clear DCTL.ULSTCHNGREQ before set
+    - usb: dwc3: gadget: Remove END_TRANSFER delay
+    - usb: dwc3: Registering a role switch in the DRD code.
+    - usb: dwc3: Add support for role-switch-default-mode binding
+    - usb: dwc3: Rework clock initialization to be more flexible
+    - usb: dwc3: Rework resets initialization to be more flexible
+    - usb: dwc3: core: don't do suspend for device mode if already suspended
+    - usb: dwc3: Fix GTXFIFOSIZ.TXFDEP macro name
+    - usb: dwc3: select USB_ROLE_SWITCH
+    - usb: dwc3: support continuous runtime PM with dual role
+    - usb: dwc3: gadget: Give back staled requests
+    - usb: dwc3: gadget: Remove unnecessary checks
+    - usb: dwc3: gadget: Refactor dwc3_gadget_ep_dequeue
+    - usb: dwc3: drd: Don't free non-existing irq
+    - usb: dwc3: core: Use role-switch default dr_mode
+    - usb: dwc3: gadget: Store resource index of start cmd
+    - usb: dwc3: gadget: Issue END_TRANSFER to retry isoc transfer
+    - usb: dwc3: gadget: WARN on no-resource status
+    - usb: dwc3: use true,false for dwc->otg_restart_host
+    - usb: dwc3: gadget: make starting isoc transfers more robust
+    - usb: dwc3: gadget: add frame number mask
+    - usb: dwc3: gadget: Refactor ep command completion
+    - usb: dwc3: gadget: Introduce a DWC3 VBUS draw callback
+    - usb: dwc3: gadget: Preserve UDC max speed setting
+    - usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression
+    - cpufreq: imx: Select NVMEM_IMX_OCOTP
+    - cpufreq: Initialize the governors in core_initcall
+    - cpufreq: Make cpufreq_global_kobject static
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Sun, 11 Jul 2021 20:48:24 +0800
+
+linux-imx (5.4.0-1006.6) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: imx: Add i.mx8mn Gateworks gw7902 dts support
+    - SAUCE: arm64: dts: imx8mn: gw7902: disable gpc, gpu & mu nodes
+    - SAUCE: arm64: dts: imx8mn: gw7902: update usbotg1 clks, clk parents
+    - [Packaging] ignore bpfilter module during crossbuild
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 05 Jul 2021 21:01:45 +0800
+
+linux-imx (5.4.0-1005.5) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - SAUCE: arm64: dts: x8high35-pdk: correct copyright in SPDX license ident
+    - [Packaging] Ignore if bpfilter module is missing
+    - SAUCE: ARM: dts: imx: add support for X6MED-35 PDK
+    - [Config] Disable iMX6SL/SLL iMX7D/ULP SoC's
+    - [Packaging] fix armhf imx flavour variables
+    - [Config] remoteproc, rpmsg drivers to be built-in
+    - [Config] disable lpae support for imx6(armhf) systems
+    - [Config] CONFIG_REMOTEPROC_CDEV=y
+    - [Config] cleanup power,cpugreq & clk related configs for armhf
+    - [Config] CONFIG_MMC_SDHCI_ESDHC_IMX=y, CONFIG_MMC_SDHCI_OF_ESDHC=y
+    - [Config] updateconfigs for earlyprintk on imx6sx uart1"
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: available memory to linux is ~511MiB
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add reserved memory for rpmsg
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add rpmsg node for imx6sx
+    - [Config] CONFIG_FEC=m
+    - [Config] CONFIG_REGULATOR_ANATOP=y on imx6 based platforms
+    - SAUCE: ARM: dts: imx6sx-x6med35: fix pinctrl for USB_CC interrupt
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: add pinctrl defs for fec rmii support
+    - [Config] CONFIG_SPI_FSL_QUADSPI=y, CONFIG_SPI_FSL_LPSPI=y
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: fix dt config for usb_otg1
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: usbotg2 config for LTE expansion
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: disable rpmsg, don't reserve memory
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: disable qspi nand-flash for now
+    - SAUCE: ARM: dts: imx6sx-x6med35-som: Assign corresponding power supply for
+      LDOs
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add 5v, 3v3 psu regulators
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: enable wdog1
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: add aliases for watchdog devices
+    - SAUCE: ARM: dts: imx6sx-x6med35-pdk: disable anatop-regulator
+
+  * Miscellaneous upstream changes
+    - ARM: dts: imx7: Unify temp-grade and speed-grade nodes
+    - ARM: dts: imx: Replace "simple-bus" with "simple-mfd" for anatop
+    - ARM: dts: imx: use generic name bus
+    - ARM: dts: imx: make gpt node name generic
+    - ARM: dts: imx: make kpp node name generic
+    - ARM: dts: imx: make clks node name generic
+    - ARM: dts: imx6sx: Improve UART pins macro defines
+    - ARM: dts: imx6sx: Add missing UART RTS/CTS pins mux
+    - ARM: dts: imx6sx-nitrogen6sx: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-sabreauto: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-sdb: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx6sx-softing-vining-2000: Use new pin names with DCE/DTE for
+      UART pins
+    - ARM: dts: imx6sx-udoo-neo: Use new pin names with DCE/DTE for UART pins
+    - ARM: dts: imx: make wdog node name generic
+    - ARM: dts: imx: Align ocotp node name
+    - ARM: dts: imx6sx-softing-vining-2000: Enable PCI support
+    - ARM: dts: imx: Make iomuxc node name generic
+    - ARM: dts: imx: add nvmem property for cpu0
+    - dt-bindings: fec: update the gpr property
+    - ARM: dts: imx: add ethernet stop mode property
+    - ARM: dts: imx6qdl: Use nvmem interface to get fuse data
+    - ARM: dts: imx6sl: Use nvmem interface to get fuse data
+    - ARM: dts: imx: Make tempmon node as child of anatop node
+    - ARM: dts: imx: change ocotp node name on i.MX6/7 SoCs
+    - ARM: dts: imx: change ocotp node name on MXS SoCs
+    - ARM: dts: imx: change iim node name on i.MX SoCs
+    - ARM: dts: imx6qdl: Remove invalid interrupt for GPC node
+    - ARM: dts: imx: Change sdhci node name on i.MX27/i.MX31 SoCs
+    - ARM: dts: imx: Change esdhc node name on i.MX2/i.MX3/i.MX5 SoCs
+    - ARM: dts: imx: Change usdhc node name on i.MX6/i.MX7 SoCs
+    - ARM: dts: imx6sll: Make ssi node name same as other platforms
+    - ARM: dts: imx6sx: Enable ASRC device
+    - ARM: dts: imx6sx-sdb: Add SPDIF support
+    - ARM: dts: imx6sx-sabreauto: Add SPDIF support
+    - ARM: dts: imx6sx-sabreauto: Add cs42888 sound card support
+    - ARM: dts: imx6sx-sdb: Add MQS support
+    - ARM: dts: imx: Align L2 cache-controller nodename with dtschema
+    - ARM: dts: imx6ul: Add ASRC device node
+    - ARM: dts: imx: default to #pwm-cells = <3> in the SoC dtsi files
+    - ASoC: bindings: fsl-asoc-card: Add compatible string for MQS
+    - ASoC: fsl-asoc-card: Add MQS support
+    - ASoC: bindings: fsl_spdif: Add new compatible string for imx6sx
+    - ASoC: fsl_spdif: Add support for imx6sx platform
+    - ASoC: fsl_spdif: Add pm runtime function
+    - ARM: dts: imx6sx: fix the pad QSPI1B_SCLK mux mode for uart3
+    - ARM: dts: imx6sx-sdb: Add headphone detection for sound card
+    - ARM: dts: imx6/7: sync fsl,stop-mode with current flexcan driver
+    - ARM: dts: imx: add usb alias
+    - ARM: dts: imx: Change gpmi nand node name to nand-controller
+    - ARM: dts: imx: make src node name generic
+    - ARM: dts: imx: align name for crypto node and child nodes
+    - remoteproc: use struct_size() helper
+    - remoteproc: Use size_t type for len in da_to_va
+    - remoteproc: Use size_t instead of int for rproc_mem_entry len
+    - remoteproc: Use u64 type for boot_addr
+    - remoteproc: Add elf helpers to access elf64 and elf32 fields
+    - remoteproc: Rename rproc_elf_sanity_check for elf32
+    - remoteproc: Add elf64 support in elf loader
+    - remoteproc: Allow overriding only sanity_check
+    - remoteproc: Adapt coredump to generate correct elf type
+    - remoteproc: re-check state in rproc_trigger_recovery()
+    - remoteproc: remoteproc debugfs file fixes
+    - remoteproc: return error for bad "recovery" debugfs input
+    - remoteproc: Traverse rproc_list under RCU read lock
+    - remoteproc: Introduce "panic" callback in ops
+    - remoteproc: qcom: q6v5: Add common panic handler
+    - remoteproc: qcom: Introduce panic handler for PAS and ADSP
+    - remoteproc: core: Remove casting to rproc_handle_resource_t
+    - remoteproc: introduce is_iomem to rproc_mem_entry
+    - remoteproc: convert to DEFINE_SHOW_ATTRIBUTE
+    - remoteproc: Split firmware name allocation from rproc_alloc()
+    - remoteproc: Simplify default name allocation
+    - remoteproc: add rproc_coredump_set_elf_info
+    - remoteproc: sysmon: Add ability to send type of notification
+    - remoteproc: Use kstrdup_const() rather than kstrdup()
+    - remoteproc: Restructure firmware name allocation
+    - remoteproc: Split rproc_ops allocation from rproc_alloc()
+    - remoteproc: Get rid of tedious error path
+    - remoteproc: Use a local copy for the name field
+    - remoteproc: Add device-managed variants of rproc_alloc/rproc_add
+    - remoteproc: remove rproc_elf32_sanity_check
+    - remoteproc: Add prepare and unprepare ops
+    - remoteproc: Add missing '\n' in log messages
+    - remoteproc: Fix an error code in devm_rproc_alloc()
+    - remoteproc: remoteproc_core: Use 'gnu_printf' format notation
+    - remoteproc: Add new RPROC_DETACHED state
+    - remoteproc: Add new attach() remoteproc operation
+    - remoteproc: Introducing function rproc_attach()
+    - remoteproc: Introducing function rproc_actuate()
+    - remoteproc: Introducing function rproc_validate()
+    - remoteproc: Refactor function rproc_boot()
+    - remoteproc: Refactor function rproc_trigger_auto_boot()
+    - remoteproc: Refactor function rproc_free_vring()
+    - remoteproc: Properly handle firmware name when attaching
+    - remoteproc: Make function rproc_resource_cleanup() public
+    - remoteproc: Move coredump functionality to a new file
+    - remoteproc: Pass size and offset as arguments to segment dump function
+    - remoteproc: Add inline coredump functionality
+    - remoteproc: Add coredump debugfs entry
+    - remoteproc: Introduce rproc_of_parse_firmware() helper
+    - remoteproc: Add remoteproc character device interface
+    - remoteproc: core: Register the character device interface
+    - remoteproc: Change default dump configuration to "disabled"
+    - remoteproc: coredump: Add minidump functionality
+    - remoteproc: add is_iomem to da_to_va
+    - remoteproc: imx_rproc: correct err message
+    - remoteproc: imx_rproc: use devm_ioremap
+    - remoteproc: imx_rproc: add i.MX specific parse fw hook
+    - remoteproc: imx_rproc: support i.MX8MQ/M
+    - remoteproc: imx_rproc: ignore mapping vdev regions
+    - remoteproc: imx_proc: enable virtio/mailbox
+    - remoteproc: imx_rproc: fix return value check in imx_rproc_addr_init()
+    - remoteproc: Remove useless check in rproc_del()
+    - remoteproc: Rename function rproc_actuate()
+    - remoteproc: Add new RPROC_ATTACHED state
+    - remoteproc: Properly represent the attached state
+    - remoteproc: Add new get_loaded_rsc_table() to rproc_ops
+    - remoteproc: imx_rproc: fix build error without CONFIG_MAILBOX
+    - remoteproc: imx_rproc: add missing of_node_put
+    - remoteproc: imx_rproc: enlarge IMX7D_RPROC_MEM_MAX
+    - remoteproc: imx_rproc: move memory parsing to rproc_ops
+    - remoteproc: imx_rproc: support remote cores booted before Linux Kernel
+    - spi: spi-fsl-qspi: Reduce devm_ioremap size to 4 times AHB buffer size
+    - spi: spi-fsl-qspi: Fix return value check of devm_ioremap() in probe
+    - regulator: anatop: Lower error message level for -EPROBE_DEFER
+    - regulator: anatop: Constify anatop_core_rops
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 02 Jul 2021 09:32:58 +0800
+
+linux-imx (5.4.0-1004.4) focal; urgency=medium
+
+  * Bump ABI: 5.4.0-1004.4
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 18 Jun 2021 18:15:48 +0800
+
+linux-imx (5.4.0-1003.3) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM=m
+    - [Config] CONFIG_IMX8MM_THERMAL=m, CONFIG_IMX_SC_THERMAL=m
+    - [Config] CONFIG_NVMEM_IMX_OCOTP_SCU=y, CONFIG_NVMEM_SNVS_LPGPR=y
+    - SAUCE: arm64: dts: fix brcm sdio wifi compatible string
+    - SAUCE: arm64: dts: imx8mp: specify dma-ranges
+    - SAUCE: usb: dwc3: imx8mp: detect dwc3 child nodes with name "usb*"
+    - SAUCE: arm64: dts: imx8mp: A53 cpufreq opp table
+    - SAUCE: arm64: dts: imx8mp: add nvmem entries for A53 speed-grade
+    - SAUCE: arm64: dts: imx8mp: Enable cpu-idle driver
+    - SAUCE: cpufreq: Use imx-cpufreq-dt for i.MX8MP's speed grading
+    - SAUCE: arm64: dts: x8high35-pdk: fix node for wifi sdio card
+    - [Config] select ondemand gov as default
+    - SAUCE: arm64: dts: imx8mp: configure gpio1_01 for ecspi1-cs
+    - SAUCE: arm64: dts: x8high35-pdk: fix cs-pins for uart_exp ports
+    - SAUCE: arm64: dts: x8high35-pdk: enable uart3
+    - SAUCE: arm64: dts: imx8mp: update i2c addr for crypto chip as per HW
+      recommendation
+    - SAUCE: arm64: dts: imx8mm: add gpc iomux compatible
+    - SAUCE: arm64: dts: imx: Add i.mx8mm Gateworks gw7902 dts support
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: add PCI support
+    - [Config] CONFIG_LAN743X=m
+    - SAUCE: regmap: irq: fix ack-invert
+    - [Config] CONFIG_GPIO_PCA953X=y, CONFIG_GPIO_PCA953X_IRQ=y
+    - [Config] updateconfigs for watchdog support
+    - SAUCE: MLK-22404-02 soc: imx: Add power domain driver support for i.mx8m
+      family
+    - SAUCE: MLK-22404-03 arm64: dts: freescale: Add power domain nodes for
+      i.mx8mm
+    - SAUCE: arm64: dts: imx8mm-venice-gw7902: add power-domain configs for USB
+      controllers
+    - [Config] CONFIG_IMX8M_PM_DOMAINS=y
+    - SAUCE: clk: imx: imx8mm: set the parent clks of pcie
+    - SAUCE: PCI: imx: set the according disable signal
+    - SAUCE: PCI: imx: enable imx8qm/qxp pcie support
+    - SAUCE: pci: imx: fix build failure due to 5.1 RC7 upgrade
+    - SAUCE: PCI: imx: msi enable bit of rc should be set in resume
+    - SAUCE: PCI: imx: set up the hsio regmap itself
+    - SAUCE: PCI: imx: enable imx8mm pcie support
+    - [Config] CONFIG_PCIE_DW_*=y
+
+  * Miscellaneous upstream changes
+    - thermal: of-thermal: add API for getting sensor ID from DT
+    - thermal: imx_sc: add i.MX system controller thermal support
+    - thermal: imx8mm: Add support for i.MX8MM thermal monitoring unit
+    - thermal: imx_sc_thermal: Align imx sc thermal msg structs to 4
+    - thermal: imx_sc_thermal: Fix incorrect data type
+    - thermal: imx8mm: Add i.MX8MP support
+    - thermal: imx8mm: Fix build warning of incorrect argument type
+    - dt-bindings: firmware: imx: Move system control into dt-binding headfile
+    - thermal: imx_sc_thermal: Add hwmon support
+    - thermal: imx8mm: Replace zero-length array with flexible-array
+    - thermal: imx8mm: Support module autoloading
+    - thermal: imx8mm: Print the correct error code
+    - thermal: imx8mm: Disable the clock on probe failure
+    - arm64: dts: imx8m: add NVMEM provider and consumer to read soc unique ID
+    - nvmem: imx: scu: support hole region check
+    - nvmem: imx: scu: support write
+    - nvmem: imx: scu: fix dependency in Kconfig
+    - nvmem: imx: scu: fix write SIP
+    - nvmem: imx: scu: correct the fuse word index
+    - nvmem: imx: ocotp: introduce ocotp_ctrl_reg
+    - nvmem: imx: ocotp: add i.MX8MP support
+    - nvmem: imx-ocotp: Drop unnecessary initializations
+    - nvmem: imx-ocotp: Improve logic to save many code lines
+    - nvmem: imx-ocotp: add support for the unaliged word count
+    - arm64: dts: imx8mp: Use the correct name for child node "snps, dwc3"
+    - Revert "soc: imx8m: change to use platform driver"
+    - arm64: dts: imx8mp: add flexspi node
+    - arm64: dts: imx8mp: Remove the reference to audio ipg clock on imx8mp
+    - spi: nxp-fspi: Use devm API to fix missed unregistration of controller
+    - spi: fspi: enable fspi on imx8qxp and imx8mm
+    - spi: fspi: dynamically alloc AHB memory
+    - spi: spi-nxp-fspi: Enable the Octal Mode in MCR0
+    - spi: spi-nxp-fspi: Add support for imx8mm, imx8qxp
+    - spi: spi-nxp-fspi: Fix a NULL vs IS_ERR() check in probe
+    - spi: spi-nxp-fspi: Add ACPI support
+    - spi: spi-nxp-fspi: Add support for IP read only
+    - spi: spi-nxp-fspi: Add imx8dxl driver support
+    - spi: spi-nxp-fspi: Implement errata workaround for LS1028A
+    - spi: spi-nxp-fspi: Add imx8dxl support
+    - spi: fspi: enable fspi driver for on imx8mp
+    - dt-bindings: spi: add compatible entry for imx8mp in FlexSPI controller
+    - soc: imx: gpcv2: move to more ideomatic error handling in probe
+    - soc: imx: gpcv2: move domain mapping to domain driver probe
+    - soc: imx: gpcv2: switch to clk_bulk_* API
+    - soc: imx: gpcv2: split power up and power down sequence control
+    - soc: imx: gpcv2: wait for ADB400 handshake
+    - soc: imx: gpcv2: add runtime PM support for power-domains
+    - soc: imx: gpcv2: allow domains without power-sequence control
+    - soc: imx: gpcv2: add support for optional resets
+    - dt-bindings: power: add defines for i.MX8MM power domains
+    - soc: imx: gpcv2: add support for i.MX8MM power domains
+    - soc: imx: gpcv2: Add support for missing i.MX8MM VPU/DISPMIX power domains
+    - soc: imx: gpcv2: move reset assert after requesting domain power up
+    - dt-bindings: add defines for i.MX8MN power domains
+    - soc: imx: gpcv2: add support for i.MX8MN power domains
+    - arm64: dts: imx8mn: add GPC node and power domains
+    - arm64: dts: imx8mn: Add power-domain reference in USB controller
+    - arm64: dts: imx8mn: Add GPU node
+    - dt-bindings: reset: imx7: Add support for i.MX8MN
+    - dt-bindings: reset: imx7: Document usage on i.MX8MP SoC
+    - reset: imx7: Add support for i.MX8MP SoC
+    - reset: imx7: Support module build
+    - dt-bindings: reset: imx8mq: add m4 reset
+    - reset: imx7: add the cm4 reset for i.MX8MQ
+    - arm64: dts: imx8mm: specify dma-ranges
+    - arm64: dts: imx8mn: specify dma-ranges
+    - regmap: provide helpers for simple bit operations
+    - cpufreq: Initialize cpufreq-dt driver earlier
+    - cpufreq: Add i.MX7ULP to cpufreq-dt-platdev blacklist
+    - spi: imx: use true,false for bool variable
+    - spi: imx: fallback to PIO if dma setup failure
+    - spi: introduce fallback to pio
+    - spi: imx: add fallback feature
+    - spi: imx: enable runtime pm support
+    - spi: imx: Fix freeing of DMA channels if spi_bitbang_start() fails
+    - spi: imx: Do not print an error when PIO is used
+    - spi: imx: Remove unneeded probe message
+    - spi: imx: fix runtime pm support for !CONFIG_PM
+    - spi: imx: fix reference leak in two imx operations
+    - spi: imx: fix the unbalanced spi runtime pm management
+    - spi: imx: Improve driver description
+    - spi: imx: add a check for speed_hz before calculating the clock
+    - UBUTNU: SAUCE: arm64: dts: imx8mm-venice-gw7902: add PCIe nodes
+    - dt-bindings: mfd: Add Gateworks System Controller bindings
+    - mfd: Add Gateworks System Controller core driver
+    - hwmon: Add Gateworks System Controller support
+    - lan743x: add MODULE_DEVICE_TABLE for module loading alias
+    - hwmon: (gsc-hwmon) Scale temperature to millidegrees
+    - hwmon: (gsc) add 16bit pre-scaled voltage mode
+    - lan743x: allow mac address to come from dt
+    - dt-bindings: mfd: gateworks-gsc: Add 16bit pre-scaled voltage mode
+    - hwmon: (gsc-hwmon) add fan sensor
+    - dt-bindings: vendor-prefixes: favor "gateworks" over "gw"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 18 Jun 2021 13:38:42 +0800
+
+linux-imx (5.4.0-1002.2) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] add hwe iot-build ppa to get abis
+    - [Packaging] add abi files for imx armhf
+    - [Config] disable drm configs for imx armhf
+    - [Config] CONFIG_MICREL_PHY=y
+    - [Config] CONFIG_CRYPTO_DEV_FSL_CAAM=y, CONFIG_CRYPTO_DEV_ATMEL_ECC=y
+
+  * Miscellaneous upstream changes
+    - media: v4l2-subdev: Introduce [get|set]_mbus_config pad ops
+    - net: phy: micrel.c: add rgmii interface delay possibility to ksz9131
+    - net: phy: micrel: add phy-mode support for the KSZ9031 PHY
+    - net: phy: mchp: Add support for LAN8814 QUAD PHY
+    - Revert "UBUNTU: SAUCE: arm64: dts: remove phy-reset-gpios from ethernet
+      nodes"
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Wed, 02 Jun 2021 13:20:33 +0800
+
+linux-imx (5.4.0-1001.1) focal; urgency=medium
+
+  * Miscellaneous Ubuntu changes
+    - [Packaging] Initial focal/imx packaging
+    - [Packaging] updateconfigs and annotations
+    - SAUCE: regulator: pca9450: fix build errors on backported 5.4 based kernel
+    - [Config] update configs for i.MX8 processors
+    - [Config] CONFIG_DWMAC_IMX8=m on i.MX8
+    - [Config] drm: updateconfigs, disable iMX8MP DCSS for now
+    - [Packaging] fix annotatoins for focal updates
+    - SAUCE: arm64: dts: imx8mp: support x8high35 pdk
+    - [Packaging] fix modules-check-imx
+    - [Packaging] arm64: imx: switch kernel format to Image
+    - [Config] CONFIG_SERIAL_IMX_CONSOLE=y
+    - SAUCE: arm64: dts: imx8mp: add optee fw node
+    - [Config] remove layerscape soc suooprt, cleanup configs
+    - SAUCE: arm64: dts: imx8mp: don't advertise broken eee modes for network phys
+    - [Config] CONFIG_USB_DWC3_IMX8MP=m
+    - SAUCE: arm64: dts: imx8mp: fix phy-reset-gpio assignments
+    - SAUCE: arm64: dts: imx8mp: correct wrong addr on i2c gpio expansion
+    - SAUCE: arm64: dts: imx8mp: setup pmic INT_B gpio
+    - SAUCE: regulator: pca9450: only warn if pmic irq allocation fails
+    - SAUCE: arm64: dts: imx8mp: fix uart-exp (ecspi1) SS0 pinconfig
+    - SAUCE: extcon: ptn5150: dont fail if interrupt cannot be configured
+    - SAUCE: arm64: dts: add a53 cpu supplies
+    - SAUCE: arm64: dts: fix usb-vbus pins, cc i2c addresses & add wifi regulator
+      supply
+    - SAUCE: arm64: dts: remove phy-reset-gpios from ethernet nodes
+    - SAUCE: MLK-23173-06 net: stmmac: enable dwmac5 34Bits address width
+    - SAUCE: MLK-23222 net: stmmac: add clocks management for gmac driver
+    - SAUCE: MLK-23251-01: net: stmac: tsn: add tc mqprio support
+    - SAUCE: MGS-5511 net: stmmac: start phylink instance before stmmac_hw_setup()
+    - SAUCE: MLK-23409 net: stmmac: correctly handle mdio bus reset error path
+    - SAUCE: MLK-23784 net: stmmac: disable bus/pclk clocks when probe failed
+    - SAUCE: net: fec: add imx8mq and imx8qm new versions support
+    - SAUCE: MLK-24911-1: soc: imx: Add support to get iMX8mp LDO trim fuse value
+    - [Packaging] build fail - remove bpfilter
+
+  * Miscellaneous upstream changes
+    - arm64: dts: imx8mn-ddr4-evk: Enable GPIO LED
+    - arm64: dts: imx8mn: Add "fsl,imx8mq-src" as src's fallback compatible
+    - arm64: dts: imx8mn: Add system counter node
+    - arm64: dts: imx8mn: Enable cpu-idle driver
+    - arm64: dts: imx8mm: Remove incorrect fallback compatible for ocotp
+    - arm64: dts: imx8mn: add ddr pmu node
+    - arm64: dts: imx8mm-evk: Adjust i2c nodes following alphabetical sort
+    - arm64: dts: imx8mm-evk: Add i2c3 support
+    - arm64: dts: imx8mm-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mq-evk: Adjust nodes following alphabetical sort
+    - arm64: dts: imx8mn-ddr4-evk: Move iomuxc node to end of file
+    - arm64: dts: imx8mq-evk: VDD_ARM power rail is always ON
+    - arm64: dts: imx8mq: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mm: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mn: Move usdhc clocks assignment to board DT
+    - arm64: dts: imx8mn: Create EVK dtsi file for common use
+    - arm64: dts: imx8mq-evk: Add remote control
+    - arm64: dts: imx8mm: Remove duplicated machine compatible
+    - arm64: dts: imx8mn: Remove duplicated machine compatible
+    - arm64: dts: imx8mn-evk: Remove invalid Atheros properties
+    - arm64: dts: imx8mm: remove "simple-bus" for anatop
+    - arm64: dts: imx8mn: remove "simple-bus" for anatop
+    - arm64: dts: imx8m: Add ddr controller nodes
+    - arm64: dts: imx8mq: increase NOC clock to 800 MHz
+    - arm64: dts: imx8mq: Add eLCDIF controller
+    - arm64: dts: imx8mq: add missing SAI nodes
+    - arm64: dts: imx8mn: Remove setting for IMX8MN_CLK_USB_CORE_REF
+    - arm64: dts: imx8mn-evk: enable usb1 and typec support
+    - arm64: dts: imx8mm: Add missing mux options for UART1 and UART2 signals
+    - arm64: dts: imx8m: drop "fsl,aips-bus" and "fsl,imx8mq-aips-bus"
+    - dt-bindings: arm: Add Google Coral Edge TPU entry
+    - arm64: dts: freescale: add initial support for Google i.MX 8MQ Phanbell
+    - arm64: dts: imx8mm: Add Crypto CAAM support
+    - arm64: dts: imx8mn: add crypto node
+    - arm64: dts: imx8mm: Memory node should be in board DT
+    - arm64: dts: imx8mn: Memory node should be in board DT
+    - arm64: dts: imx8mn: add clock for snvs rtc node
+    - arm64: dts: imx8mn: Init rates and parents configs for clocks
+    - arm64: dts: imx8mm: drop redundant interrupt-parent
+    - arm64: dts: freescale: Add i.MX8MP dtsi support
+    - arm64: dts: freescale: Add i.MX8MP EVK board support
+    - arm64: dts: imx8mq-phanbell: Add support for ethernet
+    - arm64: dts: imx8mm-evk: add phy-reset-gpios for fec1
+    - arm64: dts: imx8mq-evk: add phy-reset-gpios for fec1
+    - arm64: dts: imx8mp-evk: Add GPIO LED support
+    - arm64: dts: imx8mp: Add system counter timer node
+    - arm64: dts: imx8mn: Adjust 1.2GHz OPP voltage to OD mode
+    - arm64: dts: imx: add i.MX8QXP thermal support
+    - arm64: dts: imx8mp: add crypto node
+    - arm64: dts: imx8mm: add snvs clock to pwrkey
+    - arm64: dts: imx8mq: add snvs clock to pwrkey
+    - arm64: dts: imx8mq: Align iomuxc node name
+    - arm64: dts: imx8mp: Add src node
+    - arm64: dts: imx8mn-evk: Add i2c3 support
+    - arm64: dts: imx8mn-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mp-evk: Add i2c3 support
+    - arm64: dts: imx8mp-evk: Enable pca6416 on i2c3 bus
+    - arm64: dts: imx8mq-phanbell: Add gpio-fan/thermal support
+    - arm64: dts: imx8mn: align name for crypto child nodes
+    - arm64: dts: enable fspi in imx8mm dts
+    - arm64: dts: imx8mq-phanbell: Fix Ethernet PHY post-reset duration
+    - arm64: dts: imx8mm: Add thermal zone support
+    - arm64: dts: imx8mn: Add CPU thermal zone support
+    - arm64: dts: imx8m: fix aips dts node
+    - arm64: dts: imx8mn: Add snvs clock to powerkey
+    - arm64: dts: imx8mp: Add snvs clock to powerkey
+    - arm64: dts: imx8mm-evk: Add secondary cpus supply
+    - arm64: dts: imx8m: Fix AIPS reg properties
+    - arm64: dts: imx8mp: Add thermal zones support
+    - arm64: dts: imx8mm: specify #sound-dai-cells for SAI nodes
+    - arm64: dts: freescale: imx8mp: update input_val for AUDIOMIX_BIT_STREAM
+    - arm64: dts: imx8mn: Update VDD_ARM 1.2GHz setpoint voltage
+    - arm64: dts: imx8mp: add "fsl,imx6sx-fec" compatible string
+    - arm64: dts: imx8m: assign clocks for A53
+    - arm64: dts: imx8mq: Add src node interrupts
+    - arm64: dts: imx8mp: Add src node interrupts
+    - arm64: dts: imx8mq: enable Hantro G1/G2 VPU
+    - arm64: dts: imx8mq: Add mmc aliases
+    - arm64: dts: imx8mq: Add ethernet alias
+    - arm64: dts: imx8mm: sort the aliases
+    - arm64: dts: imx8mp: add i2c aliases
+    - arm64: dts: imx8m: change ocotp node name on i.MX8M SoCs
+    - arm64: dts: imx8m: add mu node
+    - arm64: dts: imx8mp: Add fallback compatible to ocotp node
+    - arm64: dts: imx8mp: add ddr pmu device node
+    - arm64: dts: imx8mm-evk: add two parameters for samsung picophy tuning
+    - arm64: dts: imx8mn-evk: add two parameters for samsung picophy tuning
+    - arm64: dts: imx8m: Add the ENET PPS interrupt
+    - arm64: dts: imx8mq: Add NWL MIPI DSI controller
+    - arm64: dts: imx8mp: Update pinfunc header file
+    - arm64: dts: imx8mm-evk: Add flexspi support
+    - arm64: dts: imx8mm-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mn-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mp-evk: remove orphaned pinctrl-names property
+    - arm64: dts: imx8mm-evk: Replace deprecated phy reset properties
+    - arm64: dts: imx8mq-evk: Replace deprecated phy reset properties
+    - arm64: dts: imx8mq-phanbell: Replace deprecated phy reset properties
+    - arm64: dts: imx8mm-evk: Align regulator names with schema
+    - arm64: dts: imx8mq-evk: Add hog suffix to wl-reg-on
+    - arm64: dts: imx8mm: Split the imx8mm evk board dts to a common dtsi
+    - arm64: dts: imx8mm: Add imx8mm ddr4 evk board support
+    - arm64: dts: imx8mm-evk: Add 32.768 kHz clock to PMIC
+    - arm64: dts: imx8mm-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mm-ddr4-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mn-ddr4-evk: Align regulator names with schema
+    - arm64: dts: imx8mq-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mq-phanbell: Align pin configuration group names with schema
+    - arm64: dts: imx8mp: correct sdma1 clk setting
+    - arm64: dts: imx8mp-evk: Align pin configuration group names with schema
+    - arm64: dts: imx8mn-ddr4-evk: fix missing PMIC's interrupt line pull-up
+    - arm64: dts: imx8mm: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: imx8mn: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: imx8mp: adjust GIC CPU mask to match number of CPUs
+    - arm64: dts: freescale: Add pmu support on imx8mp
+    - arm64: dts: freescale: Add pmu support on imx8mn
+    - arm64: dts: imx8mp-evk: Correct WDOG_B pin configuration
+    - arm64: dts: imx8mm: Add support for micfil
+    - arm64: dts: imx8mm: Add node for SPDIF
+    - arm64: dts: imx8mq: Configure clock rate for audio plls
+    - arm64: dts: imx8mq-evk: Add spdif sound card support
+    - arm64: dts: imx8mp-evk: add CAN support
+    - arm64: dts: imx8mq-evk: add linux,autosuspend-period property for IR
+    - arm64: dts: imx8mm-evk: add IR support
+    - arm64: dts: imx8mn-evk: add IR support
+    - arm64: dts: imx8mn: Enable Asynchronous Sample Rate Converter
+    - arm64: dts: imx8mn: Add SAI nodes
+    - arm64: dts: imx8mn: Add support for micfil
+    - arm64: dts: imx8mn: Add node for SPDIF
+    - arm64: dtsi: imx8mp: add usb nodes
+    - arm64: dts: imx8mp-evk: enable usb1 as host mode
+    - arm64: dts: imx8mn: Fix duplicate node name
+    - arm64: dts: imx8mn: Configure clock rate for audio plls
+    - arm64: dts: imx8mn-evk: Add sound-wm8524 card nodes
+    - arm64: dts: imx8mn-evk: Add sound-spdif card nodes
+    - arm64: dts: imx8mq: Add clock parents for mipi dphy
+    - arm64: dts: imx8m: add SoC ID compatible
+    - arm64: dts: imx8m: correct assigned clocks for FEC
+    - arm64: dts: imx8mq: assign clock parents for FEC
+    - arm64: dts: imx8m: add mac address for FEC
+    - arm64: dts: imx8m: add fsl,stop-mode property for FEC
+    - arm64: dts: imx8mq: use_dt_domains for pci node
+    - arm64: dts: imx8mn: Add fspi node
+    - pinctrl: core: Add pinctrl_select_default_state() and export it
+    - pinctrl: freescale: Add i.MX8MP pinctrl driver support
+    - pinctrl: freescale: drop the dependency on ARM64 for i.MX8M
+    - pinctrl: imx: Support i.MX8 SoCs pinctrl driver built as module
+    - pinctrl: imx: scu: Support i.MX8 SCU SoCs pinctrl driver built as module
+    - pinctrl: imx8mm: Support building as module
+    - pinctrl: imx8mn: Support building as module
+    - pinctrl: imx8mq: Support building as module
+    - pinctrl: imx8mp: Support building as module
+    - pinctrl: imx8qm: Support building as module
+    - pinctrl: imx: Support building i.MX pinctrl core driver as module
+    - clk: imx8mm: Move 1443X/1416X PLL clock structure to common place
+    - clk: imx8mn: Use common 1443X/1416X PLL clock structure
+    - clk: imx8mq: Add VIDEO2_PLL clock
+    - clk: imx: clk-pll14xx: Make two variables static
+    - clk: imx8mq: Define gates for pll1/2 fixed dividers
+    - clk: imx8mm: Define gates for pll1/2 fixed dividers
+    - clk: imx8mn: Define gates for pll1/2 fixed dividers
+    - clk: imx: imx8mm: mark sys_pll1/2 as fixed clock
+    - clk: imx: imx8mn: mark sys_pll1/2 as fixed clock
+    - clk: imx: imx8mq: mark sys1/2_pll as fixed clock
+    - clk: imx: imx7d: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6sll: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6sx: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx6ul: use imx_obtain_fixed_clk_hw to simplify code
+    - clk: imx: imx8mq: fix sys3_pll_out_sels
+    - clk: imx: imx8mn: drop unused pll enum
+    - clk: imx: clk-divider-gate: fix a typo in comment
+    - clk: imx: clk-divider-gate: drop redundant initialization
+    - clk: imx8m: Set CLK_GET_RATE_NOCACHE on dram clocks
+    - clk: imx: Mark dram pll on 8mm and 8mn with CLK_GET_RATE_NOCACHE
+    - clk: imx6q: disable non functional divider
+    - clk: imx7ulp: Fix watchdog2 clock name typo
+    - clk: imx8m: Suppress bind attrs
+    - clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
+    - clk: imx8qxp-lpcg: Warn against devm_platform_ioremap_resource
+    - clk: imx: Rename the SCCG to SSCG
+    - clk: imx: Replace all the clk based helpers with macros
+    - clk: imx: pllv1: Switch to clk_hw based API
+    - clk: imx: pllv2: Switch to clk_hw based API
+    - clk: imx: imx7ulp composite: Rename to show is clk_hw based
+    - clk: imx: Rename sccg and frac pll register to suggest clk_hw
+    - clk: imx: Rename the imx_clk_pllv4 to imply it's clk_hw based
+    - clk: imx: Rename the imx_clk_pfdv2 to imply it's clk_hw based
+    - clk: imx: Rename the imx_clk_divider_gate to imply it's clk_hw based
+    - clk: imx7up: Rename the clks to hws
+    - clk: imx: clk-pll14xx: Switch to clk_hw based API
+    - clk: imx: clk-composite-8m: Switch to clk_hw based API
+    - clk: imx: add imx_unregister_hw_clocks
+    - clk: imx: add hw API imx_clk_hw_mux2_flags
+    - clk: imx: gate3: Switch to clk_hw based API
+    - clk: imx: Remove __init for imx_obtain_fixed_clk_hw() API
+    - clk: imx: imx8mn: Switch to clk_hw based API
+    - clk: imx: imx8mm: Switch to clk_hw based API
+    - clk: imx: imx8mq: Switch to clk_hw based API
+    - clk: imx: gate4: Switch imx_clk_gate4_flags() to clk_hw based API
+    - clk: imx: Add support for i.MX8MP clock driver
+    - clk: imx8mp: Correct IMX8MP_CLK_HDMI_AXI clock parent
+    - clk: imx8mp: Correct the enet_qos parent clock
+    - clk: imx8mn: add SNVS clock to clock tree
+    - clk: imx: pll14xx: Add new frequency entries for pll1443x table
+    - clk: imx: imx8mp: add ocotp root clk
+    - clk: imx: composite-8m: add imx8m_clk_hw_composite_core
+    - clk: imx: imx8mq: use imx8m_clk_hw_composite_core
+    - clk: imx: imx8mm: use imx8m_clk_hw_composite_core
+    - dt-bindings: clock: imx8mn: add SNVS clock
+    - clk: imx: imx8mn: use imx8m_clk_hw_composite_core
+    - clk: imx8mm: Fix the CLKO1 source select list
+    - clk: imx8mm: Add CLKO2 support
+    - clk: imx: Include clk-provider.h instead of clk.h for i.MX8M SoCs clock
+      driver
+    - clk: imx: drop redundant initialization
+    - clk: imx7ulp: Include clk-provider.h instead of clk.h
+    - clk: imx6sl: Add missing of_node_put()
+    - clk: imx8mq: Add missing of_node_put()
+    - clk: imx8mm: Add missing of_node_put()
+    - clk: imx8mn: Add missing of_node_put()
+    - clk: imx8mp: Add missing of_node_put()
+    - clk: imx8mp: Include slab.h instead of clkdev.h
+    - clk: imx8mm: Remove unused includes
+    - clk: imx8mn: Remove unused includes
+    - dt-bindings: imx: Add clock binding doc for i.MX8MP
+    - clk: imx8mp: Rename the IMX8MP_CLK_HDMI_27M clock
+    - clk: imx: imx8mq: fix a53 cpu clock
+    - clk: imx: imx8mm: fix a53 cpu clock
+    - clk: imx: imx8mn: fix a53 cpu clock
+    - clk: imx: imx8mp: fix a53 cpu clock
+    - dt-bindings: clocks: imx8mp: Add ids for audiomix clocks
+    - clk: imx: pll14xx: Return error if pll type is invalid
+    - clk: imx: clk-sscg-pll: Drop unnecessary initialization
+    - clk: imx: pfdv2: switch to use determine_rate
+    - clk: imx: pfdv2: determine best parent rate
+    - clk: imx: pllv4: use prepare/unprepare
+    - clk: imx8mn: A53 core clock no need to be critical
+    - clk: imx8mm: A53 core clock no need to be critical
+    - clk: imx8mp: A53 core clock no need to be critical
+    - clk: imx8mq: A53 core clock no need to be critical
+    - clk: imx7d: Add PXP clock
+    - clk: imx: clk-gate2: Pass the device to the register function
+    - clk: imx: imx6ul: change flexcan clock to support CiA bitrates
+    - clk: imx: drop the dependency on ARM64 for i.MX8M
+    - clk: imx: clk-sscg-pll: Remove unnecessary blank lines
+    - clk: imx: clk-pllv3: Use readl_relaxed_poll_timeout() for PLL lock wait
+    - clk: imx: gate2: Allow single bit gating clock
+    - clk: imx: pll14xx: Add the device as argument when registering
+    - clk: imx: Add helpers for passing the device as argument
+    - clk: imx8m: drop clk_hw_set_parent for A53
+    - clk: imx: imx8mp: fix pll mux bit
+    - clk: imx8mp: Define gates for pll1/2 fixed dividers
+    - clk: imx8mp: use imx8m_clk_hw_composite_core to simplify code
+    - clk: imx8m: migrate A53 clk root to use composite core
+    - clk: imx: add mux ops for i.MX8M composite clk
+    - clk: imx: add imx8m_clk_hw_composite_bus
+    - clk: imx: use imx8m_clk_hw_composite_bus for i.MX8M bus clk slice
+    - clk: imx8mp: add mu root clk
+    - clk: imx: vf610: add CAAM clock
+    - clk: imx: Use fallthrough pseudo-keyword
+    - clk: imx6sl: Use BIT(x) to avoid shifting signed 32-bit value by 31 bits
+    - clk: imx: Support building i.MX common clock driver as module
+    - clk: imx: Add clock configuration for ARMv7 platforms
+    - clk: imx8m: Support module build
+    - clk: imx8qxp: Support building i.MX8QXP clock driver as module
+    - clk: imx: Explicitly include bits.h
+    - clk: imx: vf610: Add CRC clock
+    - clk: imx: Correct the root clk of media ldb on imx8mp
+    - clk: imx: Correct the memrepair clock on imx8mp
+    - clk: imx: fix composite peripheral flags
+    - clk: imx: fix i.MX7D peripheral clk mux flags
+    - clk: imx: Fix and update kerneldoc
+    - clk: imx: gate2: Fix a few typos
+    - clk: imx8m: fix bus critical clk registration
+    - clk: imx: scu: fix MXC_CLK_SCU module build break
+    - clk: imx: scu: add two cells binding support
+    - clk: imx: scu: bypass cpu power domains
+    - clk: imx: scu: allow scu clk to take device pointer
+    - clk: imx: scu: add runtime pm support
+    - clk: imx: scu: add suspend/resume support
+    - clk: imx: imx8qxp-lpcg: add parsing clocks from device tree
+    - clk: imx: lpcg: allow lpcg clk to take device pointer
+    - clk: imx: clk-imx8qxp-lpcg: add runtime pm support
+    - clk: imx: lpcg: add suspend/resume support
+    - clk: imx: remove unneeded semicolon
+    - clk: imx: remove redundant assignment to pointer np
+    - clk: imx: scu: fix build break when compiled as modules
+    - clk: imx: gate2: Remove the IMX_CLK_GATE2_SINGLE_BIT special case
+    - clk: imx: gate2: Keep the register writing in on place
+    - clk: imx: gate2: Check if clock is enabled against cgr_val
+    - clk: imx: gate2: Add cgr_mask for more flexible number of control bits
+    - clk: imx: gate2: Add locking in is_enabled op
+    - clk: imx: gate2: Remove unused variable ret
+    - clk: imx8mm: drop of_match_ptr from of_device_id table
+    - clk: imx8mn: drop of_match_ptr from of_device_id table
+    - clk: imx8mp: drop of_match_ptr from of_device_id table
+    - clk: imx8mq: drop of_match_ptr from of_device_id table
+    - clk: imx: scu: Make pd_np with static keyword
+    - clk: imx: scu: remove the calling of device_is_bound
+    - clk: imx: fix Kconfig warning for i.MX SCU clk
+    - clk: imx: clk-imx8qxp: Add SCU clocks support for DC0 PLL clocks
+    - clk: imx: clk-imx8qxp: Add SCU clocks support for DC0 bypass clocks
+    - clk: imx: clk-imx8qxp: Register DC0 display clocks with imx_clk_scu2()
+    - clk: imx: clk-imx8qxp: Add some SCU clocks support for MIPI-LVDS subsystems
+    - clk: imx6q: demote warning about pre-boot ldb_di_clk reparenting
+    - clk: imx: clk-imx31: Remove unused static const table 'uart_clks'
+    - clk: imx8mq: add PLL monitor output
+    - clk: imx8mm: add clkout1/2 support
+    - clk: imx8mn: add clkout1/2 support
+    - clk: imx: Move 'imx6sl_set_wait_clk()'s prototype out to accessible header
+    - cpufreq: imx-cpufreq-dt: Add i.MX8MP support
+    - cpufreq: imx-cpufreq-dt: Add "cpu-supply" property check
+    - cpufreq: imx6q: read OCOTP through nvmem for imx6q
+    - cpufreq: imx-cpufreq-dt: Correct i.MX8MP's market segment fuse location
+    - cpufreq: dt: Allow platform specific intermediate callbacks
+    - cpufreq: imx6q-cpufreq: Improve the logic of -EPROBE_DEFER handling
+    - cpufreq: imx-cpufreq-dt: support i.MX7ULP
+    - cpufreq: imx6q: Unconditionally call dev_pm_opp_of_remove_table()
+    - watchdog: imx2_wdt: Remove unnecessary blank line
+    - watchdog: imx2_wdt: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
+    - watchdog: imx2_wdt: Use 'dev' instead of dereferencing it repeatedly
+    - watchdog: imx_sc_wdt: Remove unused includes
+    - watchdog: imx2_wdt: Drop .remove callback
+    - watchdog: imx2_wdt: update contact email
+    - gpio: mxc: Support module build
+    - rtc: imx-sc: Align imx sc msg structs to 4
+    - iopoll: introduce read_poll_timeout macro
+    - iopoll: redefined readx_poll_timeout macro to simplify the code
+    - iopoll: Introduce read_poll_timeout_atomic macro
+    - iopoll: update kerneldoc of read_poll_timeout_atomic()
+    - mmc: sdhci-esdhc-imx: Convert to pinctrl_select_default_state()
+    - mmc: sdhci-esdhc-imx: no fail when no pinctrl available
+    - mmc: sdhci-esdhci-imx: retune needed for Mega/Mix enabled SoCs
+    - mmc: sdhci-esdhc-imx: restore the per_clk rate in PM_RUNTIME
+    - mmc: sdhci-esdhc-imx: add strobe-dll-delay-target support
+    - mmc: sdhci-esdhc-imx: optimize the clock setting
+    - mmc: sdhci-esdhc-imx: optimize the strobe dll setting
+    - mmc: sdhci-esdhc-imx: add flag ESDHC_FLAG_BROKEN_AUTO_CMD23
+    - mmc: sdhci-esdhc-imx: Add an new esdhc_soc_data for i.MX8MM
+    - mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
+    - mmc: sdhci-esdhc-imx: clear DMA_SEL when disable DMA mode
+    - mmc: sdhci-esdhc-imx: restore pin state when resume back
+    - mmc: sdhci: use FIELD_GET for preset value bit masks
+    - mmc: sdhci: use FIELD_GET/PREP for capabilities bit masks
+    - mmc: sdhci: use FIELD_GET/PREP for current capabilities bit masks
+    - mmc: sdhci-esdhc: update contact email
+    - mmc: sdhci-esdhc-imx: Add HS400 support for i.MX6SLL
+    - mmc: host: sdhci-esdhc-imx: add wakeup feature for GPIO CD pin
+    - mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
+    - mmc: sdhci-msm: Introduce new ops to dump vendor specific registers
+    - mmc: sdhci-esdhc-imx: dump internal IC debug status during error
+    - mmc: sdhci-esdhc-imx: Reset before sending tuning command for manual tuning
+    - mmc: sdhci-esdhc-imx: remove unused code
+    - mmc: Set PROBE_PREFER_ASYNCHRONOUS for drivers that existed in v4.4
+    - mmc: sdhci-of-esdhc: make sure delay chain locked for HS400
+    - nvmem: core: add nvmem_cell_read_common
+    - nvmem: core: add nvmem_cell_read_u64
+    - soc: imx8: Using existing serial_number instead of UID
+    - soc: imx-scu: Using existing serial_number instead of UID
+    - soc: imx8mq: Read SOC revision from TF-A
+    - soc: imx8: print SoC type and revision
+    - soc: imx: Add i.MX8MP SoC driver support
+    - soc: imx: Enable compile testing of IMX_SCU_SOC
+    - soc: imx: gpcv2: include linux/sizes.h
+    - soc: imx: increase build coverage for imx8m soc driver
+    - soc: imx: drop COMPILE_TEST for IMX_SCU_SOC
+    - soc: imx8: select SOC_BUS
+    - soc: imx8m: Correct i.MX8MP UID fuse offset
+    - soc: imx8m: fix build warning
+    - soc: imx: scu: use devm_kasprintf
+    - cpuidle: Consolidate disabled state checks
+    - cpuidle: Introduce cpuidle_driver_state_disabled() for driver quirks
+    - ARM: imx: Drop imx_anatop_usb_chrg_detect_disable()
+    - ARM: imx: Add serial number support for i.MX6/7 SoCs
+    - ARM: imx: use generic function to exit coherency
+    - ARM: imx: Correct ocotp id for serial number support of i.MX6ULL/ULZ SoCs
+    - ARM: imx: Fix boot crash if ocotp is not found
+    - ARM: imx: Add i.MX7ULP SoC serial number support
+    - ARM: imx: limit errata selection to Cortex-A9 based designs
+    - ARM: imx: Remove unused include of linux/irqchip/arm-gic.h
+    - ARM: imx: Remove unused includes on mach-imx6q.c
+    - ARM: imx: Remove unused include of linux/of.h on mach-imx6sl.c
+    - ARM: imx: Add missing of_node_put()
+    - ARM: imx: Remove unnecessary blank lines
+    - ARM: imx: Drop unnecessary src_base check
+    - ARM: vf610: report soc info via soc device
+    - ARM: imx: use device_initcall for imx_soc_device_init
+    - ARM: imx: move cpu definitions into a header
+    - soc: imx: move cpu code to drivers/soc/imx
+    - ARM: imx: Provide correct number of resources when registering gpio devices
+    - ARM: imx: Place "Cortex-A/Cortex-M" comment in the correct location
+    - ARM: imx: Use correct SRC base address
+    - ARM: imx: Add revision support for i.MX7ULP revision 2.2
+    - ARM: imx: imx7ulp: Add a comment explaining the B2 silicon version
+    - ARM: imx: mach-imx6q: correctly identify i.MX6QP SoCs
+    - ARM: mach-imx: imx6ul: Print SOC revision on boot
+    - soc: imx: select ARM_GIC_V3 for i.MX8M
+    - ARM: imx: fix imx8m dependencies
+    - soc: imx8m: change to use platform driver
+    - pwm: imx27: Cache duty cycle register value
+    - pwm: imx27: Unconditionally write state to hardware
+    - pwm: imx27: Eliminate error message for defer probe
+    - pwm: imx27: Fix clock handling in pwm_imx27_apply()
+    - pwm: imx27: Simplify helper function to enable and disable clocks
+    - pwm: imx27: Don't disable clocks at device remove time
+    - pwm: imx27: Ensure clocks being on iff the PWM is on
+    - pwm: imx-tpm: Remove unused includes
+    - pwm: imx27: Remove unused include of of_device.h
+    - pwm: imx27: Fix rounding behavior
+    - pwm: imx-tpm: Use 64-bit division macro
+    - pwm: imx27: Use 64-bit division macro
+    - pwm: imx27: Fix overflow for bigger periods
+    - arm64: defconfig: add pca9450 pmic driver
+    - dt-bindings: regulator: add pca9450 regulator yaml
+    - regulator: pca9450: Add sd-vsel GPIO
+    - regulator: pca9450: add pca9450 pmic driver
+    - regulator: pca9450: Convert to use module_i2c_driver
+    - regulator: pca9450: Constify static regulator_ops
+    - regulator: pca9450: Add SD_VSEL GPIO for LDO5
+    - regulator: pca9450: Enable system reset on WDOG_B assertion
+    - phy: freescale: imx8mq-usb: add support for imx8mp usb phy
+    - dt-bindings: phy-imx8mq-usb: add compatible string for imx8mp usb phy
+    - phy: fsl-imx8mq-usb: Constify imx8mq_usb_phy_ops
+    - phy: fsl-imx8mq-usb: Constify imx8mp_usb_phy_ops
+    - phy: freescale: convert to devm_platform_ioremap_resource
+    - dt-bindings: imx: Add pinctrl binding doc for i.MX8MP
+    - dt-bindings: pinctrl: imx8mp: Replace the uint32-array with uint32-matrix
+    - usb: chipidea: debug: create debugfs directory under usb root
+    - usb: chipidea: udc: add new API ci_hdrc_gadget_connect
+    - usb: chipidea: udc: protect usb interrupt enable
+    - usb: chipidea: imx: enable vbus and id wakeup only for OTG events
+    - usb: chipidea: core: change vbus-regulator as optional
+    - usb: chipidea: imx: check data->usbmisc_data against NULL before access
+    - usb: chipidea: imx: change hsic power regulator as optional
+    - usb: chipidea: imx: refine the error handling for hsic
+    - usb: chipidea: imx: pinctrl for HSIC is optional
+    - usb: chipidea: ci_hdrc_imx: restore pinctrl
+    - usb: chipidea: usbmisc_imx: Use of_device_get_match_data()
+    - usb: chipidea: ci_hdrc_imx: Use of_device_get_match_data()
+    - USB: host: Use the correct style for SPDX License Identifier
+    - usb: host: ehci-fsl: Fix incorrectly named function argument
+    - crypto: caam - use mapped_{src,dst}_nents for descriptor
+    - crypto: caam - use devres to unmap memory
+    - crypto: caam - use devres to remove debugfs
+    - crypto: caam - use devres to de-initialize the RNG
+    - crypto: caam - use devres to de-initialize QI
+    - crypto: caam - use devres to populate platform devices
+    - crypto: caam - populate platform devices last
+    - crypto: caam - remove double buffering for ahash
+    - crypto: caam/qi2 - remove double buffering for ahash
+    - crypto: caam - Add support for i.MX8M Mini
+    - crypto: caam - add support for i.MX8M Nano
+    - crypto: caam - add support for i.MX8M Plus
+    - crypto: caam/qi - optimize frame queue cleanup
+    - drm/fsl-dcu: Use simple encoder
+    - drm/etnaviv: avoid deprecated timespec
+    - drm/etnaviv: Use dma_resv locking wrappers
+    - drm/etnaviv: update hardware headers from rnndb
+    - drm/etnaviv: determine product, customer and eco id
+    - drm/etnaviv: show identity information in debugfs
+    - drm/etnaviv: update gc7000 chip identity entry
+    - drm/etnaviv: update hwdb selection logic
+    - drm/etnaviv: add hwdb entry for gc400 found in STM32
+    - drm/etnaviv: Fix typo in comment
+    - drm/etnaviv: Update idle bits
+    - drm/etnaviv: Consider all kwnown idle bits in debugfs
+    - drm/etnaviv: Ignore MC when checking runtime suspend idleness
+    - drm/etnaviv: Warn when GPU doesn't idle fast enough
+    - drm/etnaviv: Replace zero-length array with flexible-array member
+    - drm/etnaviv: request pages from DMA32 zone when needed
+    - drm/etnaviv: remove check for return value of drm_debugfs_create_files()
+    - drm/etnaviv: remove _unlocked suffix in drm_gem_object_put_unlocked
+    - drm/etnaviv: Don't ignore errors on getting clocks
+    - drm/etnaviv: Make the "core" clock mandatory
+    - drm/etnaviv: Simplify clock enable/disable
+    - drm/etnaviv: fix external abort seen on GC600 rev 0x19
+    - drm/etnaviv: always start/stop scheduler in timeout processing
+    - drm/imx: plane_state->fb iff plane_state->crtc
+    - drm/imx: pd: Use bus format/flags provided by the bridge when available
+    - drm/imx: Remove the bogus possible_clones setup
+    - drm/imx: Use simple encoder
+    - drm/imx: Use __drm_atomic_helper_crtc_reset
+    - drm/imx: parallel-display: Adjust bus_flags handling
+    - drm/imx: drop useless best_encoder callback
+    - drm/imx: imx-ldb: remove useless enum
+    - drm/imx: parallel-display: move panel/bridge detection to fail early
+    - drm/imx: imx-tve: Delete an error message in imx_tve_bind()
+    - drm/imx: compile imx directory by default
+    - drm/imx: Add initial support for DCSS on iMX8MQ
+    - drm/imx/dcss: use drm_bridge_connector API
+    - MAINTAINERS: Add entry for i.MX 8MQ DCSS driver
+    - dt-bindings: display: imx: add bindings for DCSS
+    - drm/imx/dcss: fix compilation issue on 32bit
+    - drm/imx/dcss: fix unused but set variable warnings
+    - drm/imx: dw_hdmi-imx: use imx_drm_encoder_parse_of
+    - drm/imx: imx-ldb: reduce scope of edid_len
+    - drm/imx/dcss: fix rotations for Vivante tiled formats
+    - drm/imx/dcss: fix coccinelle warning
+    - drm/imx/dcss: allow using nearest neighbor interpolation scaling
+    - drm/imx: depend on COMMON_CLK to fix compile tests
+    - gpu: drm: imx: convert comma to semicolon
+    - media: imx: enable V4L2_PIX_FMT_XBGR32, _BGRX32, and _RGBX32
+    - media: staging: media: imx: Fix alignment to match open parenthesis
+    - media: staging: media: imx: Use devm_platform_ioremap_resource().
+    - media: imx: Move capture device init to registered
+    - media: imx: Move pads init to probe
+    - media: imx7-mipi-csis: make array 'registers' static const, makes object
+      smaller
+    - media: imx7-mipi-csis: remove subdev_notifier
+    - media: imx: Propagate quantization and encoding in CSI
+    - media: imx: imx7_mipi_csis: Print the RESOL_CH0 register
+    - media: imx: imx7_mipi_csis: Add greyscale formats support
+    - media: imx: imx7-mipi-csis: Filter on CSI-2 data type
+    - media: imx: imx7-media-csi: Remove unneeded register read
+    - media: imx: imx6-media-csi: Replace Y16 with Y10 and Y12
+    - media: imx: imx6-media-csi: Support clamping Y10 and Y12 to Y8
+    - media: imx: imx7-media-csi: Add Y10 and Y12 formats support
+    - media: imx: imx7-media-csi: Support clamping Y10 and Y12 to Y8
+    - staging: media: imx: remove temporary variable
+    - staging: media: imx: remove parentheses
+    - media: imx: imx7-mipi-csis: Centralize initialization of pad formats
+    - media: imx: imx7-mipi-csis: Add missing RAW formats
+    - media: imx: imx7-mipi-csis: Expose correct YUV formats
+    - media: imx: imx7-mipi-csis: Fix MEDIA_BUS_FMT_UYVY8_2X8 data alignment
+    - media: imx: imx7-mipi-csis: Add MEDIA_BUS_FMT_UYVY10_2X10 support
+    - media: imx: imx7-mipi-csis: Rename data_alignment field to width
+    - media: imx: imx7-mipi-csis: Align image width based on format
+    - media: imx: imx7-mipi-csis: Never set MIPI_CSIS_ISPCFG_ALIGN_32BIT
+    - media: imx: imx7-mipi-csis: Align macro definitions
+    - media: imx: imx7-mipi-csis: Remove link setup on source pad
+    - media: imx: imx7-mipi-csis: Cleanup includes
+    - media: imx: imx7-mipi-csis: Don't use imx-media-utils helpers
+    - media: imx: imx7-mipi-csis: Implement the .enum_mbus_code() operation
+    - media: imx: utils: fix and simplify pixel format enumeration
+    - media: imx: utils: fix media bus format enumeration
+    - media: imx: utils: Inline init_mbus_colorimetry() in its caller
+    - media: imx: utils: Handle Bayer format lookup through a selection flag
+    - media: imx: Fix some pixel format selections
+    - media: imx: utils: Rename pixel format selection enumeration
+    - media: imx: utils: Introduce PIXFMT_SEL_IPU
+    - media: imx: utils: Make imx_media_pixfmt handle variable number of codes
+    - media: imx: utils: Split find|enum_format into fourcc and mbus functions
+    - media: imx: utils: Rename format lookup and enumeration functions
+    - media: imx: utils: Constify some mbus and ipu_image arguments
+    - media: imx-media-csc-scaler: Use a shorter name for driver
+    - media: imx: utils: Default colorspace to SRGB
+    - media: staging: media: imx: no need to check return value of debugfs_create
+      functions
+    - media: imx: Parse information from firmware without using callbacks
+    - media: v4l2-mc: add v4l2_create_fwnode_links helpers
+    - media: v4l2: Correct kernel-doc inconsistency
+    - media: entity: Pass entity to get_fwnode_pad operation
+    - media: v4l2-subdev: add v4l2_subdev_get_fwnode_pad_1_to_1
+    - media: video-mux: Parse information from firmware without using callbacks
+    - media: video-mux: Implement get_fwnode_pad op
+    - media: video-mux: Create media links in bound notifier
+    - media: imx: csi: Implement get_fwnode_pad op
+    - media: imx: mipi csi-2: Implement get_fwnode_pad op
+    - media: imx: imx7-mipi-csis: Implement get_fwnode_pad op
+    - media: imx: imx7-media-csi: Implement get_fwnode_pad op
+    - media: imx: mipi csi-2: Create media links in bound notifier
+    - media: imx7: mipi csis: Create media links in bound notifier
+    - media: imx7: csi: Create media links in bound notifier
+    - media: imx: csi: Create media links in bound notifier
+    - media: imx7: csi: Remove imx7_csi_get_upstream_endpoint()
+    - media: imx5/6/7: csi: Mark a bound video mux as a CSI mux
+    - media: imx: csi: Lookup upstream endpoint with imx_media_get_pad_fwnode
+    - media: imx: Create missing links from CSI-2 receiver
+    - media: imx: silence a couple debug messages
+    - media: imx: TODO: Remove media link creation todos
+    - staging/media: Remove unneeded geometry restrictions from i.MX CSI driver
+    - media: staging: media: imx: Update TODO entry
+    - media: staging: media: imx: remove commented code
+    - media: staging: media: imx: remove unnecessary variable use
+    - media: staging/imx: Increase IMX_MEDIA_EOF_TIMEOUT
+    - media: staging: media: imx: Kconfig: support VIDEO_IMX7_CSI for imx8m
+    - media: imx: Clean capture unregister
+    - media: imx7: csi: Fix regression for parallel cameras on i.MX6UL
+    - media: imx7: csi: Fix pad link validation
+    - media: imx6-mipi-csi2: Call remote subdev get_mbus_config to get active
+      lanes
+    - thermal: imx_thermal: Use __maybe_unused instead of CONFIG_PM_SLEEP
+    - thermal: imx: Remove unused includes
+    - thermal: imx: Calling imx_thermal_unregister_legacy_cooling() in .remove
+    - stmmac: platform: add "snps, dwmac-5.10a" IP compatible string
+    - net: ethernet: dwmac: add ethernet glue logic for NXP imx8 chip
+    - net: ethernet: dwmac: Fix an error code in imx_dwmac_probe()
+    - arm64: dts: imx8mp: Correct the gpio ranges of gpio3
+    - clk: imx8mp: Remove the none exist pcie clocks
+    - clk: imx8mq: Correct the pcie1 sels
+    - arm64: dts: imx8mp: add eqos node and alias
+    - arm64: dts: imx8mp: add wdog2/3 nodes
+    - net: fec: remove redundant assignment to pointer bdp
+    - net: fec: Prevent unbind operation
+    - net: ethernet: fec: Replace interrupt driven MDIO with polled IO
+    - net: ethernet: fec: Allow configuration of MDIO bus speed
+    - net: ethernet: fec: Allow the MDIO preamble to be disabled
+    - net: ethernet: fec: Prevent MII event after MII_SPEED write
+    - Revert "net: ethernet: fec: Prevent MII event after MII_SPEED write"
+    - net: ethernet: fec: Revert "net: ethernet: fec: Replace interrupt driven
+      MDIO with polled IO"
+    - net: ethernet: fec: Replace interrupt driven MDIO with polled IO
+    - net: ethernet: fec: move GPR register offset and bit into DT
+    - net: fec: disable correct clk in the err path of fec_enet_clk_enable
+    - net: ethernet: fec: prevent tx starvation under high rx load
+    - net: fec: Set max MTU size to allow the MTU to be changed
+    - net: fec: enable to use PPS feature without time stamping
+    - net: fec: initialize clock with 0 rather than current kernel time
+    - net: fec: get rid of redundant code in fec_ptp_set()
+    - net: fec: replace snprintf() with strlcpy() in fec_ptp_init()
+    - net: ethernet: fec: remove redundant null check before
+      clk_disable_unprepare()
+    - net: fec: ptp: remove unused variable 'ns' in fec_time_keep()
+    - net: fec_mpc52xx: Replace in_interrupt() usage
+    - net: fec: Fix PHY init after phy_reset_after_clk_enable()
+    - net: fec: Fix phy_device lookup for phy_reset_after_clk_enable()
+    - net: fec: fix MDIO probing for some FEC hardware blocks
+    - net: fec: Fix reference count leak in fec series ops
+    - net: fec: put child node on error path
+    - net: fec: Fix temporary RMII clock reset on link up
+    - net: fec: Silence M5272 build warnings
+    - net: stmmac: dwc-qos: use generic device api
+    - net: stmmac: dwc-qos: avoid clk and reset for acpi device
+    - net: stmmac: Print more information in DebugFS DMA Capabilities file
+    - net: stmmac: Let TX and RX interrupts be independently enabled/disabled
+    - net: stmmac: Always use TX coalesce timer value when rescheduling
+    - net: stmmac: Add basic EST support for GMAC5+
+    - net: stmmac: Add basic EST support for XGMAC
+    - net: stmmac: Integrate EST with TAPRIO scheduler API
+    - net: stmmac: Add Frame Preemption support using TAPRIO API
+    - net: stmmac: gmac5+: Add support for Frame Preemption
+    - net: stmmac: xgmac3+: Add support for Frame Preemption
+    - net: stmmac: mmc: Add Frame Preemption counters on GMAC5+ cores
+    - net: stmmac: tc: Fix TAPRIO division operation
+    - net: stmmac: Do not accept invalid MTU values
+    - stmmac: debugfs entry name is not be changed when udev rename device name.
+    - net: stmmac: xgmac: Fix missing return
+    - net: stmmac: gmac5+: Fix missing return
+    - net: stmmac: modified pcs mode support for RGMII
+    - net: stmmac: fix incorrect GMAC_VLAN_TAG register writting in GMAC4+
+    - net: ethernet: stmmac: don't warn about missing optional wakeup IRQ
+    - net: stmmac: fix notifier registration
+    - net: stmmac: use readl_poll_timeout() function in init_systime()
+    - net: stmmac: use readl_poll_timeout() function in dwmac4_dma_reset()
+    - net: stmmac: dwmac_lib: remove unnecessary checks in dwmac_dma_reset()
+    - net: stmmac: Remove WAKE_MAGIC if HW shows no pmt_magic_frame
+    - net: stmmac: Move device_can_wakeup() check earlier in set_wol
+    - net: stmmac: only call pmt() during suspend/resume if HW enables PMT
+    - net: stmmac: Support WOL with phy
+    - net: stmmac: fix failed to suspend if phy based WOL is enabled
+    - net: stmmac: increase the timeout for dma reset
+    - net: stmmac: overwrite the dma_cap.addr64 according to HW design
+    - net: stmmac: fix taprio schedule configuration
+    - net: stmmac: fix taprio configuration when base_time is in the past
+    - extcon: ptn5150: Use generic "interrupts" property
+    - extcon: ptn5150: Simplify getting vbus-gpios with flags
+    - extcon: ptn5150: Lower the noisiness of probe
+    - extcon: ptn5150: Check current USB mode when probing
+    - extcon: ptn5150: Make 'vbus-gpios' optional
+    - extcon: ptn5150: Convert to module_i2c_driver
+    - extcon: ptn5150: Set the VBUS and POLARITY property capability
+    - extcon: ptn5150: Use defines for registers
+    - usb: dwc3: debugfs: do not queue work if try to change mode on non-drd
+    - usb: dwc3: add imx8mp dwc3 glue layer driver
+    - net: fec: add eee mode tx lpi support
+    - net: fec: change the default rx copybreak value to maximum
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Mon, 31 May 2021 18:02:41 +0800
+
+linux-imx (5.4.0-1000.1) focal; urgency=medium
+
+  * Initial focal/imx packaging
+
+ -- Shrirang Bagul <shrirang.bagul@canonical.com>  Fri, 16 Apr 2021 00:50:22 +0800
--- linux-ein-5.4.0.orig/debian/cloud-tools/hv_get_dhcp_info
+++ linux-ein-5.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-ein-5.4.0.orig/debian/cloud-tools/hv_get_dns_info
+++ linux-ein-5.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-ein-5.4.0.orig/debian/cloud-tools/hv_set_ifconfig
+++ linux-ein-5.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-ein-5.4.0.orig/debian/commit-templates/bumpabi
+++ linux-ein-5.4.0/debian/commit-templates/bumpabi
@@ -0,0 +1,3 @@
+UBUNTU: Bump ABI
+
+Ignore: yes
--- linux-ein-5.4.0.orig/debian/commit-templates/config-updates
+++ linux-ein-5.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-ein-5.4.0.orig/debian/commit-templates/external-driver
+++ linux-ein-5.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-ein-5.4.0.orig/debian/commit-templates/missing-modules
+++ linux-ein-5.4.0/debian/commit-templates/missing-modules
@@ -0,0 +1,3 @@
+UBUNTU: build/modules: Add modules that have intentionally gone missing
+
+Ignore: yes
--- linux-ein-5.4.0.orig/debian/commit-templates/newrelease
+++ linux-ein-5.4.0/debian/commit-templates/newrelease
@@ -0,0 +1,3 @@
+UBUNTU: Start new release
+
+Ignore: yes
--- linux-ein-5.4.0.orig/debian/commit-templates/sauce-patch
+++ linux-ein-5.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-ein-5.4.0.orig/debian/commit-templates/upstream-patch
+++ linux-ein-5.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-ein-5.4.0.orig/debian/compat
+++ linux-ein-5.4.0/debian/compat
@@ -0,0 +1 @@
+9
--- linux-ein-5.4.0.orig/debian/control
+++ linux-ein-5.4.0/debian/control
@@ -0,0 +1,181 @@
+Source: linux-ein
+Section: devel
+Priority: optional
+Maintainer: Ubuntu Kernel Team <kernel-team@lists.ubuntu.com>
+XSC-Ubuntu-Compatible-Signing: ubuntu/4 pro/3
+Standards-Version: 3.9.4.0
+Build-Depends:
+ debhelper (>= 9),
+ dh-systemd,
+ cpio,
+ kernel-wedge,
+ kmod <!stage1>,
+ libcap-dev <!stage1>,
+ makedumpfile [amd64] <!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 ppc64el] <!stage1>,
+ openssl <!stage1>,
+ libssl-dev <!stage1>,
+ libaudit-dev <!stage1>,
+ bc <!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>,
+ dwarves <!stage1>,
+Build-Depends-Indep:
+ xmlto <!stage1>,
+ docbook-utils <!stage1>,
+ ghostscript <!stage1>,
+ fig2dev <!stage1>,
+ bzip2 <!stage1>,
+ sharutils <!stage1>,
+ asciidoc <!stage1>,
+ python3-sphinx <!stage1>,
+ python3-sphinx-rtd-theme <!stage1>,
+ python3-docutils <!stage1>,
+Vcs-Git: git://git.launchpad.net/~canonical-hwe-imx/ubuntu/+source/linux-imx/+git/focal
+Vcs-Browser: https://git.launchpad.net/~canonical-hwe-imx/ubuntu/+source/linux-imx/+git/focal/log/
+XS-Testsuite: autopkgtest
+#XS-Testsuite-Depends: gcc-4.7 binutils
+
+Package: linux-ein-headers-5.4.0-1056
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Multi-Arch: foreign
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, coreutils
+Description: Header files related to Linux kernel version 5.4.0
+ This package provides kernel header files for version 5.4.0, for sites
+ that want the latest kernel headers. Please read
+ /usr/share/doc/linux-ein-headers-5.4.0-1056/debian.README.gz for details
+
+Package: linux-ein-tools-5.4.0-1056
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, linux-tools-common
+Description: Linux kernel version specific tools for version 5.4.0-1056
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 5.4.0-1056 on
+ .
+ You probably want to install linux-tools-5.4.0-1056-<flavour>.
+
+
+
+Package: linux-image-5.4.0-1056-ein
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: kernel
+Priority: optional
+Provides: linux-image, fuse-module, aufs-dkms, kvm-api-4, redhat-cluster-modules, ivtv-modules, ${linux:rprovides}
+Depends: ${misc:Depends}, ${shlibs:Depends}, kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-5.4.0-1056-ein
+Recommends: grub-pc [amd64 x32] | grub-efi-amd64 [amd64 x32] | grub-efi-ia32 [amd64 x32] | grub [amd64 x32] | lilo (>= 19.1) [amd64 x32] | flash-kernel [armhf arm64] | grub-ieee1275 [ppc64el], initramfs-tools | linux-initramfs-tool
+Breaks: flash-kernel (<< 3.90ubuntu2) [arm64 armhf], s390-tools (<< 2.3.0-0ubuntu3) [s390x]
+Conflicts: linux-image-unsigned-5.4.0-1056-ein
+Suggests: fdutils, linux-ein-doc-5.4.0 | linux-ein-source-5.4.0, linux-ein-tools, linux-headers-5.4.0-1056-ein
+Description: Linux kernel image for version 5.4.0 on  SMP
+ This package contains the Linux kernel image for version 5.4.0 on
+  SMP.
+ .
+ Supports Generic processors.
+ .
+ Geared toward desktop and server systems.
+ .
+ You likely do not want to install this package directly. Instead, install
+ the linux-ein meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-modules-5.4.0-1056-ein
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}, crda
+Built-Using: ${linux:BuiltUsing}
+Description: Linux kernel extra modules for version 5.4.0 on  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-ein meta-package, which will ensure that upgrades work
+ correctly, and that supporting packages are also installed.
+
+Package: linux-headers-5.4.0-1056-ein
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-ein-headers-5.4.0-1056, ${shlibs:Depends}
+Provides: linux-headers, linux-headers-3.0
+Description: Linux kernel headers for version 5.4.0 on  SMP
+ This package provides kernel header files for version 5.4.0 on
+  SMP.
+ .
+ This is for sites that want the latest kernel headers.  Please read
+ /usr/share/doc/linux-headers-5.4.0-1056/debian.README.gz for details.
+
+Package: linux-image-5.4.0-1056-ein-dbgsym
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}
+Provides: linux-debug
+Description: Linux kernel debug image for version 5.4.0 on  SMP
+ This package provides the kernel debug image for version 5.4.0 on
+  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-5.4.0-1056-ein
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: devel
+Priority: optional
+Depends: ${misc:Depends}, linux-ein-tools-5.4.0-1056
+Description: Linux kernel version specific tools for version 5.4.0-1056
+ This package provides the architecture dependant parts for kernel
+ version locked tools (such as perf and x86_energy_perf_policy) for
+ version 5.4.0-1056 on
+ .
+
+Package: linux-buildinfo-5.4.0-1056-ein
+Build-Profiles: <!stage1>
+Architecture: armhf arm64
+Section: kernel
+Priority: optional
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Built-Using: ${linux:BuiltUsing}
+Description: Linux kernel buildinfo for version 5.4.0 on  SMP
+ This package contains the Linux kernel buildinfo for version 5.4.0 on
+  SMP.
+ .
+ You likely do not want to install this package.
--- linux-ein-5.4.0.orig/debian/control.d/flavour-buildinfo.stub
+++ linux-ein-5.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-ein-5.4.0.orig/debian/copyright
+++ linux-ein-5.4.0/debian/copyright
@@ -0,0 +1,29 @@
+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'.
--- linux-ein-5.4.0.orig/debian/debian.env
+++ linux-ein-5.4.0/debian/debian.env
@@ -0,0 +1 @@
+DEBIAN=debian.ein
--- linux-ein-5.4.0.orig/debian/docs/README.inclusion-list
+++ linux-ein-5.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-ein-5.4.0.orig/debian/gbp.conf
+++ linux-ein-5.4.0/debian/gbp.conf
@@ -0,0 +1,2 @@
+[buildpackage]
+debian-tag = Ubuntu-ein-%(version)s
--- linux-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.service
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.udev
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-fcopy-daemon.upstart
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.service
+++ linux-ein-5.4.0/debian/linux-cloud-tools-common.hv-kvp-daemon.service
@@ -0,0 +1,20 @@
+# 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
+ConditionKernelCommandLine=!snapd_recovery_mode
+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
+ConditionPathExists=/dev/vmbus/hv_kvp
+
+[Service]
+ExecStart=/usr/sbin/hv_kvp_daemon -n
+
+[Install]
+WantedBy=multi-user.target
--- linux-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.udev
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-kvp-daemon.upstart
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.service
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.udev
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.hv-vss-daemon.upstart
+++ linux-ein-5.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-ein-5.4.0.orig/debian/linux-cloud-tools-common.intel-sgx-load-module.service
+++ linux-ein-5.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-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2012-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2012-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Apr 12 11:39:08 2012 GMT
+            Not After : Apr 11 11:39:08 2042 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c9:5f:9b:62:8f:0b:b0:64:82:ac:be:c9:e2:62:
+                    e3:4b:d2:9f:1e:8a:d5:61:1a:2b:5d:38:f4:b7:ce:
+                    b9:9a:b8:43:b8:43:97:77:ab:4f:7f:0c:70:46:0b:
+                    fc:7f:6d:c6:6d:ea:80:5e:01:d2:b7:66:1e:87:de:
+                    0d:6d:d0:41:97:a8:a5:af:0c:63:4f:f7:7c:c2:52:
+                    cc:a0:31:a9:bb:89:5d:99:1e:46:6f:55:73:b9:76:
+                    69:ec:d7:c1:fc:21:d6:c6:07:e7:4f:bd:22:de:e4:
+                    a8:5b:2d:db:95:34:19:97:d6:28:4b:21:4c:ca:bb:
+                    1d:79:a6:17:7f:5a:f9:67:e6:5c:78:45:3d:10:6d:
+                    b0:17:59:26:11:c5:57:e3:7f:4e:82:ba:f6:2c:4e:
+                    c8:37:4d:ff:85:15:84:47:e0:ed:3b:7c:7f:bc:af:
+                    e9:01:05:a7:0c:6f:c3:e9:8d:a3:ce:be:a6:e3:cd:
+                    3c:b5:58:2c:9e:c2:03:1c:60:22:37:39:ff:41:02:
+                    c1:29:a4:65:51:ff:33:34:aa:42:15:f9:95:78:fc:
+                    2d:f5:da:8a:85:7c:82:9d:fb:37:2c:6b:a5:a8:df:
+                    7c:55:0b:80:2e:3c:b0:63:e1:cd:38:48:89:e8:14:
+                    06:0b:82:bc:fd:d4:07:68:1b:0f:3e:d9:15:dd:94:
+                    11:1b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                61:48:2A:A2:83:0D:0A:B2:AD:5A:F1:0B:72:50:DA:90:33:DD:CE:F0
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        8f:8a:a1:06:1f:29:b7:0a:4a:d5:c5:fd:81:ab:25:ea:c0:7d:
+        e2:fc:6a:96:a0:79:93:67:ee:05:0e:25:12:25:e4:5a:f6:aa:
+        1a:f1:12:f3:05:8d:87:5e:f1:5a:5c:cb:8d:23:73:65:1d:15:
+        b9:de:22:6b:d6:49:67:c9:a3:c6:d7:62:4e:5c:b5:f9:03:83:
+        40:81:dc:87:9c:3c:3f:1c:0d:51:9f:94:65:0a:84:48:67:e4:
+        a2:f8:a6:4a:f0:e7:cd:cd:bd:94:e3:09:d2:5d:2d:16:1b:05:
+        15:0b:cb:44:b4:3e:61:42:22:c4:2a:5c:4e:c5:1d:a3:e2:e0:
+        52:b2:eb:f4:8b:2b:dc:38:39:5d:fb:88:a1:56:65:5f:2b:4f:
+        26:ff:06:78:10:12:eb:8c:5d:32:e3:c6:45:af:25:9b:a0:ff:
+        8e:ef:47:09:a3:e9:8b:37:92:92:69:76:7e:34:3b:92:05:67:
+        4e:b0:25:ed:bc:5e:5f:8f:b4:d6:ca:40:ff:e4:e2:31:23:0c:
+        85:25:ae:0c:55:01:ec:e5:47:5e:df:5b:bc:14:33:e3:c6:f5:
+        18:b6:d9:f7:dd:b3:b4:a1:31:d3:5a:5c:5d:7d:3e:bf:0a:e4:
+        e4:e8:b4:59:7d:3b:b4:8c:a3:1b:b5:20:a3:b9:3e:84:6f:8c:
+        21:00:c3:39
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIBATANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xMjA0MTIxMTM5MDhaFw00MjA0MTEx
+MTM5MDhaMH8xCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEXMBUG
+A1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MSswKQYD
+VQQDDCJDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyV+bYo8LsGSCrL7J4mLjS9KfHorVYRor
+XTj0t865mrhDuEOXd6tPfwxwRgv8f23GbeqAXgHSt2Yeh94NbdBBl6ilrwxjT/d8
+wlLMoDGpu4ldmR5Gb1VzuXZp7NfB/CHWxgfnT70i3uSoWy3blTQZl9YoSyFMyrsd
+eaYXf1r5Z+ZceEU9EG2wF1kmEcVX439Ogrr2LE7IN03/hRWER+DtO3x/vK/pAQWn
+DG/D6Y2jzr6m4808tVgsnsIDHGAiNzn/QQLBKaRlUf8zNKpCFfmVePwt9dqKhXyC
+nfs3LGulqN98VQuALjywY+HNOEiJ6BQGC4K8/dQHaBsPPtkV3ZQRGwIDAQABo4Gg
+MIGdMAwGA1UdEwEB/wQCMAAwHwYDVR0lBBgwFgYIKwYBBQUHAwMGCisGAQQBgjcK
+AwYwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl
+MB0GA1UdDgQWBBRhSCqigw0Ksq1a8QtyUNqQM93O8DAfBgNVHSMEGDAWgBStkZkL
+wiqx9RcEjCO2ZVomjjRaYzANBgkqhkiG9w0BAQsFAAOCAQEAj4qhBh8ptwpK1cX9
+gasl6sB94vxqlqB5k2fuBQ4lEiXkWvaqGvES8wWNh17xWlzLjSNzZR0Vud4ia9ZJ
+Z8mjxtdiTly1+QODQIHch5w8PxwNUZ+UZQqESGfkovimSvDnzc29lOMJ0l0tFhsF
+FQvLRLQ+YUIixCpcTsUdo+LgUrLr9Isr3Dg5XfuIoVZlXytPJv8GeBAS64xdMuPG
+Ra8lm6D/ju9HCaPpizeSkml2fjQ7kgVnTrAl7bxeX4+01spA/+TiMSMMhSWuDFUB
+7OVHXt9bvBQz48b1GLbZ992ztKEx01pcXX0+vwrk5Oi0WX07tIyjG7Ugo7k+hG+M
+IQDDOQ==
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2017-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2017-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 26 21:52:11 2017 GMT
+            Not After : Sep 25 21:52:11 2047 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2017)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ef:9f:fa:9f:19:3a:9d:38:23:91:cc:c4:f9:42:
+                    e0:f8:54:12:82:dc:97:2c:d6:5b:c1:35:eb:ff:4a:
+                    74:06:b5:9d:32:aa:7b:f3:fc:31:5a:34:3e:a1:a4:
+                    44:db:7b:6d:16:af:35:76:e0:9b:99:ad:21:11:c6:
+                    12:4b:ae:24:8f:bb:d3:b2:00:fe:c5:1d:9b:3a:1a:
+                    4a:6c:ca:fa:16:37:85:22:f9:ff:22:fc:40:e0:58:
+                    35:c1:39:27:b4:c6:42:1a:96:d8:a5:c5:95:2e:f7:
+                    c5:1e:21:6e:36:84:f7:a9:a1:e1:f1:03:08:96:65:
+                    71:f8:eb:83:cf:82:f7:9a:44:58:72:00:14:39:29:
+                    4b:e9:78:2f:65:20:b3:80:76:3b:ba:0d:2d:46:f6:
+                    37:05:e7:05:fe:bd:6c:c7:a2:65:b5:06:6e:07:24:
+                    99:a1:c1:cf:e1:0e:5e:49:41:71:17:a8:50:e7:38:
+                    99:e5:6e:b6:db:9f:63:db:56:f4:9c:7d:89:f6:d2:
+                    03:6c:99:83:e0:99:23:39:36:bd:cb:b5:26:7c:7d:
+                    b0:c6:fe:82:7c:52:ed:f9:2c:8f:79:71:3d:a9:2f:
+                    b5:aa:7e:77:a0:fd:69:f9:97:10:a8:b2:c6:7d:88:
+                    9e:a2:19:bd:31:b8:02:2d:34:4d:9d:98:60:82:ad:
+                    04:ff
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                24:2A:DE:75:AC:4A:15:E5:0D:50:C8:4B:0D:45:FF:3E:AE:70:7A:03
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        00:b2:b7:57:b5:2b:5d:16:d3:04:88:6a:d7:77:d5:0d:89:f1:
+        d2:6e:11:d1:8e:f5:62:05:c4:6a:57:df:eb:d2:86:68:f2:fd:
+        a7:37:11:3c:f4:ce:5d:fe:32:5f:31:a2:6b:3a:da:28:c2:88:
+        fa:7f:70:b5:25:99:ea:27:9a:56:6a:9d:b2:0f:14:99:e2:b7:
+        c6:39:1e:8e:a7:76:31:d9:ed:c5:05:8d:48:ae:1b:68:18:14:
+        51:a1:7d:f6:c7:df:cb:9d:eb:a4:3b:0b:ff:c2:07:c5:42:bc:
+        0d:b2:11:fa:37:17:2b:1c:b5:84:48:2d:f9:31:4a:57:49:8e:
+        61:a6:82:11:06:4c:34:ea:9c:2a:47:4d:eb:e0:26:af:da:d2:
+        c2:08:a0:37:35:7b:73:71:de:0b:c4:ba:c8:34:de:20:04:03:
+        6f:46:26:0d:b9:91:02:5b:71:76:cc:45:e4:08:d0:a6:dd:a4:
+        50:d3:d9:04:91:2b:d9:5c:34:88:fc:c2:37:fd:c6:d4:3e:57:
+        f7:6b:ba:7b:d7:02:7a:84:0c:c8:c1:19:cc:bc:fa:52:d5:7f:
+        b3:35:c4:53:5d:70:0a:f6:44:60:8d:a9:11:7a:1b:7d:ae:7b:
+        20:5a:4c:8d:44:f6:c1:a9:61:cb:dc:cb:90:37:d5:28:24:73:
+        87:d0:e0:d8
+-----BEGIN CERTIFICATE-----
+MIIEKDCCAxCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA5MjYyMTUyMTFaFw00NzA5MjUy
+MTUyMTFaMIGGMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDEyMDAG
+A1UEAwwpQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoMjAxNykw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvn/qfGTqdOCORzMT5QuD4
+VBKC3Jcs1lvBNev/SnQGtZ0yqnvz/DFaND6hpETbe20WrzV24JuZrSERxhJLriSP
+u9OyAP7FHZs6GkpsyvoWN4Ui+f8i/EDgWDXBOSe0xkIaltilxZUu98UeIW42hPep
+oeHxAwiWZXH464PPgveaRFhyABQ5KUvpeC9lILOAdju6DS1G9jcF5wX+vWzHomW1
+Bm4HJJmhwc/hDl5JQXEXqFDnOJnlbrbbn2PbVvScfYn20gNsmYPgmSM5Nr3LtSZ8
+fbDG/oJ8Uu35LI95cT2pL7Wqfneg/Wn5lxCossZ9iJ6iGb0xuAItNE2dmGCCrQT/
+AgMBAAGjgaAwgZ0wDAYDVR0TAQH/BAIwADAfBgNVHSUEGDAWBggrBgEFBQcDAwYK
+KwYBBAGCNwoDBjAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFCQq3nWsShXlDVDISw1F/z6ucHoDMB8GA1UdIwQY
+MBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA0GCSqGSIb3DQEBCwUAA4IBAQAAsrdX
+tStdFtMEiGrXd9UNifHSbhHRjvViBcRqV9/r0oZo8v2nNxE89M5d/jJfMaJrOtoo
+woj6f3C1JZnqJ5pWap2yDxSZ4rfGOR6Op3Yx2e3FBY1IrhtoGBRRoX32x9/Lneuk
+Owv/wgfFQrwNshH6NxcrHLWESC35MUpXSY5hpoIRBkw06pwqR03r4Cav2tLCCKA3
+NXtzcd4LxLrINN4gBANvRiYNuZECW3F2zEXkCNCm3aRQ09kEkSvZXDSI/MI3/cbU
+Plf3a7p71wJ6hAzIwRnMvPpS1X+zNcRTXXAK9kRgjakReht9rnsgWkyNRPbBqWHL
+3MuQN9UoJHOH0ODY
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2018-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2018-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Oct 26 18:31:14 2018 GMT
+            Not After : Oct 24 18:31:14 2048 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (ESM 2018)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:bf:6a:e5:6d:55:7a:ec:7a:11:37:45:9c:4c:8f:
+                    6b:2d:56:d3:74:2b:32:ac:84:2d:ba:cb:cc:ec:8d:
+                    92:22:69:48:a5:d4:f6:75:11:66:2f:cb:b2:fd:9e:
+                    56:ab:e6:f1:52:8e:75:3e:50:bd:25:b3:50:fc:ef:
+                    3d:76:f3:3f:7f:03:f6:e2:a1:25:69:5c:14:98:54:
+                    bd:11:bf:e9:a5:ac:46:91:4b:1d:de:b7:18:2b:c8:
+                    22:83:15:a7:4a:00:8d:9d:e4:c0:da:f7:41:02:fd:
+                    9f:5f:79:93:56:cc:86:e1:b5:e0:39:0e:3c:a2:5b:
+                    fe:c0:56:f0:92:50:5a:2b:67:67:93:56:d7:7a:75:
+                    99:6a:25:b4:63:a8:5f:69:7e:3a:49:58:2a:a7:80:
+                    f6:5a:b4:be:b2:be:a8:8c:45:41:c9:f2:fc:76:a8:
+                    65:ef:99:29:0d:c9:9c:54:6b:0a:f0:4a:0e:61:0d:
+                    ed:99:32:af:12:e2:12:7b:9f:7b:ec:05:c4:e0:b6:
+                    d5:c3:71:28:ae:dd:0b:ba:97:ad:68:0b:76:e9:bf:
+                    e7:01:7e:64:54:39:23:85:36:c8:9d:dd:27:a1:ff:
+                    df:46:36:14:7e:cb:cc:a1:cd:49:0b:6d:c2:0c:45:
+                    99:56:58:7c:87:0d:59:9a:dc:4a:39:3b:1d:d9:15:
+                    2e:b5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                36:51:88:C1:D3:74:D6:B0:7C:3C:8F:24:0F:8E:F7:22:43:3D:6A:8B
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        4c:0f:cd:77:60:b4:6f:53:87:f3:3c:4f:e6:81:5f:a7:1c:cc:
+        60:29:b6:34:6c:4d:08:9b:e2:d2:bd:f6:17:1a:62:79:b8:17:
+        bc:a2:60:59:fd:03:51:c3:b7:6b:de:73:b3:48:95:f5:0b:aa:
+        b6:3c:b4:34:dc:1d:0b:c4:97:62:87:e7:48:d5:8f:c9:ea:e8:
+        91:8f:2a:40:cd:b7:b3:ee:b2:98:9e:fb:37:31:29:e6:8e:2f:
+        0a:39:99:1e:c6:aa:b8:05:62:85:d3:a8:3e:60:38:98:0f:f0:
+        fe:c7:ab:01:a5:6a:a5:7f:70:a6:26:94:76:23:2f:08:89:74:
+        97:c2:2a:ca:22:3e:7a:ea:22:22:08:07:f4:bb:f6:bc:69:9c:
+        4e:44:33:e2:8e:70:17:b0:9b:cb:33:94:66:6d:ff:9a:7d:e9:
+        50:b2:e8:90:14:e4:2b:91:cb:a0:c5:2e:0e:cf:19:ef:44:ef:
+        84:f0:bd:57:9e:26:c2:63:3d:df:fc:a1:84:de:5c:d7:5f:3b:
+        fb:94:61:f0:93:89:1f:cf:c3:b2:d1:90:97:35:7d:b9:8a:ad:
+        e6:05:f0:e8:3b:a1:7c:af:2b:c4:af:18:33:2e:5e:87:db:9d:
+        80:b5:04:fd:00:d0:60:ab:ff:85:77:0f:cb:47:22:c9:b2:85:
+        a8:48:16:e2
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xODEwMjYxODMxMTRaFw00ODEwMjQx
+ODMxMTRaMIGKMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDE2MDQG
+A1UEAwwtQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoRVNNIDIw
+MTgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2rlbVV67HoRN0Wc
+TI9rLVbTdCsyrIQtusvM7I2SImlIpdT2dRFmL8uy/Z5Wq+bxUo51PlC9JbNQ/O89
+dvM/fwP24qElaVwUmFS9Eb/ppaxGkUsd3rcYK8gigxWnSgCNneTA2vdBAv2fX3mT
+VsyG4bXgOQ48olv+wFbwklBaK2dnk1bXenWZaiW0Y6hfaX46SVgqp4D2WrS+sr6o
+jEVByfL8dqhl75kpDcmcVGsK8EoOYQ3tmTKvEuISe5977AXE4LbVw3Eort0Lupet
+aAt26b/nAX5kVDkjhTbInd0nof/fRjYUfsvMoc1JC23CDEWZVlh8hw1ZmtxKOTsd
+2RUutQIDAQABo4GgMIGdMAwGA1UdEwEB/wQCMAAwHwYDVR0lBBgwFgYIKwYBBQUH
+AwMGCisGAQQBgjcKAwYwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk
+IENlcnRpZmljYXRlMB0GA1UdDgQWBBQ2UYjB03TWsHw8jyQPjvciQz1qizAfBgNV
+HSMEGDAWgBStkZkLwiqx9RcEjCO2ZVomjjRaYzANBgkqhkiG9w0BAQsFAAOCAQEA
+TA/Nd2C0b1OH8zxP5oFfpxzMYCm2NGxNCJvi0r32FxpiebgXvKJgWf0DUcO3a95z
+s0iV9Quqtjy0NNwdC8SXYofnSNWPyerokY8qQM23s+6ymJ77NzEp5o4vCjmZHsaq
+uAVihdOoPmA4mA/w/serAaVqpX9wpiaUdiMvCIl0l8IqyiI+euoiIggH9Lv2vGmc
+TkQz4o5wF7CbyzOUZm3/mn3pULLokBTkK5HLoMUuDs8Z70TvhPC9V54mwmM93/yh
+hN5c1187+5Rh8JOJH8/DstGQlzV9uYqt5gXw6DuhfK8rxK8YMy5eh9udgLUE/QDQ
+YKv/hXcPy0ciybKFqEgW4g==
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2019-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2019-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 18 16:10:17 2019 GMT
+            Not After : Sep 16 16:10:17 2049 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2019)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e6:47:d8:75:e5:87:59:26:87:83:7d:5b:7a:b8:
+                    58:3d:7c:ef:36:f8:a0:7a:b7:14:56:58:7d:01:f1:
+                    1c:3b:8c:e6:5b:03:77:7d:a0:ed:47:0a:45:e6:75:
+                    5c:de:95:38:0d:38:fa:41:79:89:56:31:87:e7:a3:
+                    9a:36:70:b6:cf:24:2f:99:26:89:08:39:0e:14:c3:
+                    35:be:02:8b:52:e1:8e:7b:0c:a6:9d:78:ff:01:60:
+                    d7:f5:c3:d5:f0:5e:dc:e4:23:09:59:72:93:d3:b5:
+                    22:af:7c:cd:e0:84:0f:af:11:2d:bc:c6:72:42:af:
+                    ea:67:63:c4:10:41:78:02:80:62:0d:43:74:b4:1c:
+                    ed:50:d7:94:f1:b0:bb:f9:57:80:e4:69:0f:83:4b:
+                    a2:e6:2c:4a:9a:e1:7d:7c:62:19:29:27:97:1f:4c:
+                    f1:85:f0:39:f5:31:9f:3a:39:0e:d4:4d:07:3a:40:
+                    55:4b:a6:6c:9d:04:89:51:2d:7c:b0:ef:40:b5:42:
+                    29:16:cc:65:73:38:62:21:f6:e3:2c:17:50:9d:74:
+                    34:4e:df:7c:4a:33:a4:bb:40:cf:d5:e5:ed:05:07:
+                    cd:4c:f9:af:7f:a6:5c:b9:f7:c5:16:45:4e:44:40:
+                    d7:85:32:de:ac:e5:75:ad:9b:d7:c0:26:33:1f:77:
+                    a5:37
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                C0:74:6F:D6:C5:DA:3A:E8:27:86:46:51:AD:66:AE:47:FE:24:B3:E8
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        aa:12:6c:d1:9d:6a:da:f0:ec:7c:17:46:3b:57:b8:d6:76:5f:
+        24:e6:06:a2:0a:55:1f:2f:d3:5e:8f:de:cf:02:f2:ff:e0:dd:
+        d3:c7:bd:75:59:aa:cd:34:f3:28:80:73:cc:28:69:e7:a2:70:
+        88:a2:c7:dc:66:f0:92:0e:ff:64:bf:30:04:54:01:1b:96:ad:
+        15:c5:61:fd:32:61:d7:5e:b5:ba:91:fd:31:fc:6b:15:df:ee:
+        22:d9:e4:1f:f3:cc:8b:0c:9f:f5:e8:f7:e2:62:3f:40:52:c9:
+        f0:f1:1c:63:fc:6c:90:e1:5b:74:03:b9:df:d1:3e:a8:ec:db:
+        2b:6e:83:6f:9f:7f:ba:b4:79:fc:3d:e7:12:2f:4a:e7:17:8c:
+        2b:77:a5:90:74:3c:bd:cf:75:83:0d:1a:95:d5:56:ef:07:9b:
+        a6:b3:31:e3:8c:97:ce:68:11:b5:7b:25:03:72:1c:ea:67:e9:
+        7c:3e:73:c7:7c:3e:fc:f5:ae:8a:b2:07:0d:15:6a:66:09:d7:
+        23:b9:5d:80:7a:26:d6:b6:22:30:aa:84:af:c0:42:e9:75:c3:
+        59:ab:a3:84:87:6b:0c:b7:ab:4e:92:69:ae:2c:82:6f:ab:01:
+        24:ab:ff:78:6d:59:85:c2:3b:23:c0:bd:0d:d8:6e:3a:29:82:
+        e1:c4:5f:db
+-----BEGIN CERTIFICATE-----
+MIIEKDCCAxCgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTA5MTgxNjEwMTdaFw00OTA5MTYx
+NjEwMTdaMIGGMQswCQYDVQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xFzAV
+BgNVBAoMDkNhbm9uaWNhbCBMdGQuMRQwEgYDVQQLDAtTZWN1cmUgQm9vdDEyMDAG
+A1UEAwwpQ2Fub25pY2FsIEx0ZC4gU2VjdXJlIEJvb3QgU2lnbmluZyAoMjAxOSkw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDmR9h15YdZJoeDfVt6uFg9
+fO82+KB6txRWWH0B8Rw7jOZbA3d9oO1HCkXmdVzelTgNOPpBeYlWMYfno5o2cLbP
+JC+ZJokIOQ4UwzW+AotS4Y57DKadeP8BYNf1w9XwXtzkIwlZcpPTtSKvfM3ghA+v
+ES28xnJCr+pnY8QQQXgCgGINQ3S0HO1Q15TxsLv5V4DkaQ+DS6LmLEqa4X18Yhkp
+J5cfTPGF8Dn1MZ86OQ7UTQc6QFVLpmydBIlRLXyw70C1QikWzGVzOGIh9uMsF1Cd
+dDRO33xKM6S7QM/V5e0FB81M+a9/ply598UWRU5EQNeFMt6s5XWtm9fAJjMfd6U3
+AgMBAAGjgaAwgZ0wDAYDVR0TAQH/BAIwADAfBgNVHSUEGDAWBggrBgEFBQcDAwYK
+KwYBBAGCNwoDBjAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFMB0b9bF2jroJ4ZGUa1mrkf+JLPoMB8GA1UdIwQY
+MBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA0GCSqGSIb3DQEBCwUAA4IBAQCqEmzR
+nWra8Ox8F0Y7V7jWdl8k5gaiClUfL9Nej97PAvL/4N3Tx711WarNNPMogHPMKGnn
+onCIosfcZvCSDv9kvzAEVAEblq0VxWH9MmHXXrW6kf0x/GsV3+4i2eQf88yLDJ/1
+6PfiYj9AUsnw8Rxj/GyQ4Vt0A7nf0T6o7NsrboNvn3+6tHn8PecSL0rnF4wrd6WQ
+dDy9z3WDDRqV1VbvB5umszHjjJfOaBG1eyUDchzqZ+l8PnPHfD789a6KsgcNFWpm
+CdcjuV2AeibWtiIwqoSvwELpdcNZq6OEh2sMt6tOkmmuLIJvqwEkq/94bVmFwjsj
+wL0N2G46KYLhxF/b
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2021v1-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2021v1-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 6 (0x6)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:29:32 2021 GMT
+            Not After : Sep 22 19:29:32 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v1)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:aa:b8:34:5b:b6:ae:44:bf:41:e1:78:11:b9:7a:
+                    c8:88:b3:b0:26:50:10:9c:98:d1:f3:98:9f:23:50:
+                    64:f6:39:dd:50:3a:23:44:53:65:fc:f3:9f:f5:a5:
+                    8b:ae:8b:df:47:9f:e9:d5:a0:92:19:f1:21:ea:cc:
+                    59:3a:74:df:45:71:bc:de:64:15:a5:f6:db:ca:71:
+                    fa:19:d4:44:0d:12:ec:47:3a:43:e2:f2:dd:8b:fe:
+                    0d:7b:dc:4d:db:53:06:22:61:e5:8b:35:49:b6:33:
+                    c4:0a:69:5f:5b:81:09:84:6b:42:33:18:09:9d:a0:
+                    35:f7:9c:1e:de:6e:de:90:69:1a:e8:32:e4:49:ad:
+                    c3:31:e9:f8:4a:a2:28:1d:db:0d:29:b6:48:0a:44:
+                    93:86:41:62:8f:73:97:60:10:8a:74:46:66:55:fe:
+                    a0:95:35:9e:ef:9f:af:11:fa:5b:a3:7c:c2:35:64:
+                    11:67:28:1e:14:0a:7d:68:61:9c:cd:c7:46:39:30:
+                    31:79:94:56:b3:45:16:9a:b5:77:66:fe:41:43:0f:
+                    00:48:6e:99:dd:0c:d4:47:2c:86:8c:50:04:61:20:
+                    dd:aa:8e:73:4f:21:b4:ee:09:4d:d3:40:01:d0:f2:
+                    a7:5b:7d:05:3d:c1:e7:65:26:aa:8c:9a:58:5a:7c:
+                    6d:6f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                A8:D5:4B:BB:38:25:CF:B9:4F:A1:3C:9F:8A:59:4A:19:5C:10:7B:8D
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        24:25:25:7e:01:a5:c8:3d:54:8c:1b:05:73:d1:06:d8:db:d4:
+        3a:71:d5:19:9d:97:1c:85:3c:ca:38:5a:0c:25:25:39:1a:67:
+        bc:6c:9d:98:6c:f3:7d:5f:b7:40:f9:73:a0:f5:7b:40:a8:66:
+        a5:f1:53:b1:78:80:24:3f:19:50:2f:02:09:ec:a1:8a:e6:0d:
+        df:c4:ae:24:9e:69:0d:5c:dc:44:4c:38:3a:53:4e:4b:a1:4b:
+        92:9f:43:a4:9d:1e:76:33:18:1b:bf:62:e5:f5:bc:93:3c:4e:
+        21:d5:5b:20:69:11:28:c1:c5:93:b5:8e:96:1d:1b:ca:72:79:
+        24:de:67:2a:50:9d:ce:8b:41:dd:3e:82:dd:a5:04:75:54:fb:
+        35:70:98:87:b4:f3:ea:41:23:23:80:0e:99:d7:03:16:ee:7e:
+        11:e2:c8:29:ab:73:c5:6d:5c:a8:2f:32:03:9f:8e:66:d6:cb:
+        54:84:55:75:ab:9a:dd:95:fd:05:1e:11:85:37:1e:63:d2:f4:
+        7f:34:64:32:a1:63:91:91:50:39:14:1a:ea:54:78:e6:0d:04:
+        23:c7:83:51:c5:25:27:07:6c:f8:65:b7:da:95:89:76:83:cc:
+        f3:7e:06:74:d3:6c:ef:e9:17:de:29:1e:ab:5c:d7:ec:df:f1:
+        98:b8:e9:66
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTI5MzJaGA8yMDUxMDky
+MjE5MjkzMlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYxKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKq4NFu2rkS/QeF4
+Ebl6yIizsCZQEJyY0fOYnyNQZPY53VA6I0RTZfzzn/Wli66L30ef6dWgkhnxIerM
+WTp030VxvN5kFaX228px+hnURA0S7Ec6Q+Ly3Yv+DXvcTdtTBiJh5Ys1SbYzxApp
+X1uBCYRrQjMYCZ2gNfecHt5u3pBpGugy5EmtwzHp+EqiKB3bDSm2SApEk4ZBYo9z
+l2AQinRGZlX+oJU1nu+frxH6W6N8wjVkEWcoHhQKfWhhnM3HRjkwMXmUVrNFFpq1
+d2b+QUMPAEhumd0M1EcshoxQBGEg3aqOc08htO4JTdNAAdDyp1t9BT3B52Umqoya
+WFp8bW8CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUqNVLuzglz7lPoTyfillKGVwQe40wHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+ACQlJX4Bpcg9VIwbBXPRBtjb1Dpx1RmdlxyFPMo4WgwlJTkaZ7xsnZhs831ft0D5
+c6D1e0CoZqXxU7F4gCQ/GVAvAgnsoYrmDd/EriSeaQ1c3ERMODpTTkuhS5KfQ6Sd
+HnYzGBu/YuX1vJM8TiHVWyBpESjBxZO1jpYdG8pyeSTeZypQnc6LQd0+gt2lBHVU
++zVwmIe08+pBIyOADpnXAxbufhHiyCmrc8VtXKgvMgOfjmbWy1SEVXWrmt2V/QUe
+EYU3HmPS9H80ZDKhY5GRUDkUGupUeOYNBCPHg1HFJScHbPhlt9qViXaDzPN+BnTT
+bO/pF94pHqtc1+zf8Zi46WY=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2021v2-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2021v2-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 7 (0x7)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:29:42 2021 GMT
+            Not After : Sep 22 19:29:42 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v2)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ba:06:8b:ee:58:b7:8b:49:7b:53:7a:d1:df:02:
+                    e3:f2:d8:b0:8c:03:5c:f4:2d:0b:d8:18:3b:23:fa:
+                    68:b0:e8:e9:9d:dc:a2:eb:5e:d3:06:a9:28:d4:9f:
+                    14:b6:1e:1c:1d:ef:69:0e:7f:44:f2:cc:4a:f1:b1:
+                    d0:71:30:6a:50:1e:b0:d3:f8:a4:19:d0:4a:f1:e3:
+                    eb:7a:e5:57:4c:a1:fb:d1:87:b9:48:e0:55:37:52:
+                    f9:de:99:2e:95:85:36:ce:d3:1d:67:2f:14:cb:7f:
+                    05:82:75:21:b6:aa:a5:14:ac:da:4a:f4:fe:fa:5c:
+                    33:49:3d:6f:de:fd:9d:75:ba:e2:c4:02:38:b5:69:
+                    f5:ff:a8:67:4b:3a:e0:34:f6:3b:07:03:a5:7e:59:
+                    6f:3a:d2:28:a4:2f:25:ac:d8:a9:1f:59:52:5d:24:
+                    36:58:51:b5:f0:12:a8:d3:78:56:57:b1:e0:a9:df:
+                    14:05:65:7c:b5:a5:00:f0:88:39:14:44:18:85:2d:
+                    0c:28:69:7b:b9:b4:1c:47:6f:43:66:4c:22:ad:f7:
+                    f6:19:75:e1:14:2c:0d:33:3f:c1:3f:fc:73:56:b2:
+                    68:05:b5:92:03:9b:65:6b:81:80:92:35:03:9b:66:
+                    68:58:c5:66:11:b6:8c:7f:05:09:9a:45:a6:0e:5e:
+                    5f:bf
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                4C:F0:46:89:2D:6F:D3:C9:A5:B0:3F:98:D8:45:F9:08:51:DC:6A:8C
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        93:9d:49:7d:9f:3e:3e:27:79:97:d9:c2:fc:0b:f7:30:b7:f4:
+        78:b2:c9:e4:5e:42:d3:27:26:70:cf:88:96:d1:f2:ea:a0:75:
+        7e:3c:f6:b7:d2:e7:95:30:e3:a6:67:a7:ee:b9:53:8f:fd:b2:
+        cb:db:e1:98:32:be:98:79:09:46:c6:63:6a:57:87:4d:b2:26:
+        46:f6:34:5e:18:75:ca:82:80:8e:33:c2:1d:c7:76:d7:14:57:
+        ef:2e:0e:9e:58:5c:81:8e:ed:53:2c:07:46:0a:8a:fc:2f:f5:
+        b2:c8:58:f5:fa:fa:bb:f9:7d:47:13:39:f0:f2:1c:15:9c:75:
+        90:40:bd:08:04:b3:6a:de:c2:cd:34:21:7e:ba:31:48:bc:a1:
+        23:bc:ee:93:b2:62:96:27:30:86:c2:d4:f7:b4:e6:3c:71:47:
+        37:84:ff:3d:0c:1e:ec:f3:0e:da:6b:dc:64:7a:b8:c0:7e:45:
+        13:09:bf:02:b3:b7:5b:6d:09:2d:6a:4e:0b:93:94:29:4c:a6:
+        c3:c7:05:fa:69:08:04:53:3c:4c:64:c0:7e:89:00:91:1b:a6:
+        c2:d7:ea:c4:db:86:38:fe:66:03:85:7b:fc:39:24:99:4c:2a:
+        3e:10:8b:91:c3:6e:20:9d:0c:ee:51:70:b5:98:58:f3:5c:ac:
+        16:98:7b:ce
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTI5NDJaGA8yMDUxMDky
+MjE5Mjk0MlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYyKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALoGi+5Yt4tJe1N6
+0d8C4/LYsIwDXPQtC9gYOyP6aLDo6Z3coute0wapKNSfFLYeHB3vaQ5/RPLMSvGx
+0HEwalAesNP4pBnQSvHj63rlV0yh+9GHuUjgVTdS+d6ZLpWFNs7THWcvFMt/BYJ1
+IbaqpRSs2kr0/vpcM0k9b979nXW64sQCOLVp9f+oZ0s64DT2OwcDpX5ZbzrSKKQv
+JazYqR9ZUl0kNlhRtfASqNN4Vlex4KnfFAVlfLWlAPCIORREGIUtDChpe7m0HEdv
+Q2ZMIq339hl14RQsDTM/wT/8c1ayaAW1kgObZWuBgJI1A5tmaFjFZhG2jH8FCZpF
+pg5eX78CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTPBGiS1v08mlsD+Y2EX5CFHcaowwHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+AJOdSX2fPj4neZfZwvwL9zC39HiyyeReQtMnJnDPiJbR8uqgdX489rfS55Uw46Zn
+p+65U4/9ssvb4Zgyvph5CUbGY2pXh02yJkb2NF4YdcqCgI4zwh3HdtcUV+8uDp5Y
+XIGO7VMsB0YKivwv9bLIWPX6+rv5fUcTOfDyHBWcdZBAvQgEs2rews00IX66MUi8
+oSO87pOyYpYnMIbC1Pe05jxxRzeE/z0MHuzzDtpr3GR6uMB+RRMJvwKzt1ttCS1q
+TguTlClMpsPHBfppCARTPExkwH6JAJEbpsLX6sTbhjj+ZgOFe/w5JJlMKj4Qi5HD
+biCdDO5RcLWYWPNcrBaYe84=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-2021v3-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-2021v3-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 8 (0x8)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Sep 23 19:30:02 2021 GMT
+            Not After : Sep 22 19:30:02 2051 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v3)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:d6:29:96:87:ae:07:42:45:bb:65:09:b2:9b:de:
+                    5d:8e:78:61:10:d5:6d:ae:ae:26:08:6a:06:ec:4a:
+                    dd:2b:e7:1a:a9:ad:78:e3:fc:cf:8f:d1:47:bd:1e:
+                    33:d8:7a:e3:66:9b:e9:73:c1:5f:42:e2:fe:bc:c3:
+                    41:f7:cd:d7:85:d7:42:c9:ea:31:e5:47:b1:93:5b:
+                    43:2b:07:51:b8:75:08:ad:0f:e7:0d:81:38:5a:21:
+                    df:b1:43:5b:db:37:c5:ac:aa:14:3a:33:19:6a:26:
+                    e0:05:fe:cd:41:31:af:5d:a8:ab:31:77:44:fc:da:
+                    00:e2:7a:44:33:c3:a7:ed:13:54:9f:19:5d:c9:98:
+                    a2:3b:af:4d:0d:87:29:9c:90:9e:42:9e:9a:06:6a:
+                    70:27:c5:aa:f7:a2:f2:88:e0:b9:66:9a:72:a0:f6:
+                    61:7e:30:8f:14:9f:44:0d:dd:54:ae:47:c8:82:ba:
+                    d2:b2:db:6f:24:c1:f4:0a:81:07:90:47:49:5f:57:
+                    d6:3f:bf:2a:73:98:f2:f6:24:1a:74:03:d7:35:f0:
+                    42:d8:14:c5:94:27:5d:3c:49:0c:b0:f0:7a:61:1b:
+                    d7:5a:e3:a3:40:57:e9:a4:07:ee:02:a3:32:27:94:
+                    bb:f3:36:c5:5f:ef:d3:07:04:3a:80:4c:9c:0a:b7:
+                    88:9f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                10:04:37:BB:6D:E6:E4:69:B5:81:E6:1C:D6:6B:CE:3E:F4:ED:53:AF
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        3b:37:d6:a8:8d:cd:d2:df:13:35:ac:8c:92:d6:b0:ac:d1:38:
+        a8:00:97:47:59:b8:4a:84:8c:80:a5:1d:c7:29:bf:00:66:e5:
+        10:40:26:2e:31:f5:e1:13:c0:1b:29:f3:0b:7e:2d:71:d8:db:
+        e1:32:8f:79:8e:e3:97:0c:40:a9:a0:12:c1:fc:c2:50:88:72:
+        44:c5:bc:8b:45:6e:28:fd:d2:37:d6:db:17:cf:4e:61:33:08:
+        5a:5d:08:94:73:44:e2:76:00:44:1b:b8:00:a1:86:00:64:8a:
+        f1:42:32:3c:28:11:67:7c:8b:aa:06:34:74:58:e8:b3:3a:36:
+        8d:f6:04:5d:37:f5:66:52:c9:48:b0:a7:6f:34:09:dd:60:2a:
+        86:b9:14:f1:09:f6:06:16:56:e0:51:b1:e8:75:7f:fa:37:dc:
+        e0:98:a7:69:ae:7b:1a:73:89:0d:06:67:cc:01:ef:80:31:45:
+        9e:bb:03:2a:eb:89:70:d6:19:b2:c7:ce:bc:81:df:da:c8:6f:
+        a9:4b:2d:d7:a7:e1:af:c6:e8:fb:f0:61:c9:cd:d2:91:cd:8b:
+        c2:6c:ef:e0:b6:7f:f1:c4:81:f9:bb:76:9c:26:e3:fa:a1:a0:
+        cd:5e:05:de:ee:f9:1b:5b:50:0a:8b:0f:47:e3:90:32:ac:2a:
+        e7:65:02:80
+-----BEGIN CERTIFICATE-----
+MIIELTCCAxWgAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMTA5MjMxOTMwMDJaGA8yMDUxMDky
+MjE5MzAwMlowgYkxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MTUw
+MwYDVQQDDCxDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nICgyMDIx
+IHYzKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANYploeuB0JFu2UJ
+spveXY54YRDVba6uJghqBuxK3SvnGqmteOP8z4/RR70eM9h642ab6XPBX0Li/rzD
+QffN14XXQsnqMeVHsZNbQysHUbh1CK0P5w2BOFoh37FDW9s3xayqFDozGWom4AX+
+zUExr12oqzF3RPzaAOJ6RDPDp+0TVJ8ZXcmYojuvTQ2HKZyQnkKemgZqcCfFqvei
+8ojguWaacqD2YX4wjxSfRA3dVK5HyIK60rLbbyTB9AqBB5BHSV9X1j+/KnOY8vYk
+GnQD1zXwQtgUxZQnXTxJDLDwemEb11rjo0BX6aQH7gKjMieUu/M2xV/v0wcEOoBM
+nAq3iJ8CAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQYMBYGCCsGAQUF
+BwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl
+ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUEAQ3u23m5Gm1geYc1mvOPvTtU68wHwYD
+VR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcNAQELBQADggEB
+ADs31qiNzdLfEzWsjJLWsKzROKgAl0dZuEqEjIClHccpvwBm5RBAJi4x9eETwBsp
+8wt+LXHY2+Eyj3mO45cMQKmgEsH8wlCIckTFvItFbij90jfW2xfPTmEzCFpdCJRz
+ROJ2AEQbuAChhgBkivFCMjwoEWd8i6oGNHRY6LM6No32BF039WZSyUiwp280Cd1g
+Koa5FPEJ9gYWVuBRseh1f/o33OCYp2muexpziQ0GZ8wB74AxRZ67AyrriXDWGbLH
+zryB39rIb6lLLden4a/G6PvwYcnN0pHNi8Js7+C2f/HEgfm7dpwm4/qhoM1eBd7u
++RtbUAqLD0fjkDKsKudlAoA=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/revoked-certs/canonical-uefi-uc2019-all.pem
+++ linux-ein-5.4.0/debian/revoked-certs/canonical-uefi-uc2019-all.pem
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
+        Validity
+            Not Before: Mar  4 10:27:14 2020 GMT
+            Not After : Mar  3 10:27:14 2050 GMT
+        Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (Ubuntu Core 2019)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b9:10:47:2e:75:5d:f3:10:23:bb:a0:75:d2:fa:
+                    02:2d:ff:22:df:c1:e6:cd:38:7c:36:0f:ae:74:15:
+                    6e:a5:34:52:2b:c3:a4:3a:60:d7:06:ee:1d:99:93:
+                    ff:66:91:a3:18:52:2c:8c:58:e6:b4:2f:4b:c5:fb:
+                    83:e6:f3:19:bd:1b:ca:23:ec:97:1f:d8:f1:9a:f1:
+                    04:da:da:10:04:53:4b:ec:1d:b6:26:47:7c:bb:8f:
+                    a7:0a:6e:2e:e8:91:e6:c4:bb:64:34:78:3c:fa:09:
+                    15:1c:8f:9e:eb:04:99:36:22:c6:8d:07:15:0f:b9:
+                    69:08:fa:ff:4b:45:bd:ba:2b:cd:01:0e:e7:01:23:
+                    c9:e5:7a:39:3b:91:b0:45:3c:d5:77:ba:ca:f9:29:
+                    3d:11:3f:1c:6b:5b:8e:6c:4b:3f:c9:29:05:cb:59:
+                    d6:b1:c1:c0:2d:56:88:70:27:fa:73:05:5c:c2:11:
+                    d4:27:11:f7:0b:c2:d5:68:d3:1a:cd:ed:d0:e4:10:
+                    ff:34:cb:b7:45:70:34:2c:23:53:b6:9c:30:70:b4:
+                    5c:d1:e2:64:18:82:8f:62:b1:5e:aa:0b:d4:89:f2:
+                    1c:53:c4:32:7d:ef:53:ee:9b:6e:02:ab:78:bd:25:
+                    67:8b:39:36:d8:84:3b:06:99:02:d6:75:73:4e:f2:
+                    f6:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Extended Key Usage: 
+                Code Signing, 1.3.6.1.4.1.311.10.3.6
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                C1:D5:7B:8F:6B:74:3F:23:EE:41:F4:F7:EE:29:2F:06:EE:CA:DF:B9
+            X509v3 Authority Key Identifier: 
+                AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
+    Signature Algorithm: sha256WithRSAEncryption
+    Signature Value:
+        2d:b5:11:a8:d2:a0:af:81:a0:18:22:18:2c:08:d0:f4:63:e8:
+        8f:9a:f4:f5:20:dd:eb:22:77:19:9a:1a:09:3d:7f:aa:7d:c9:
+        81:bc:26:98:65:94:46:30:4b:c2:51:7c:f7:21:41:63:87:31:
+        fc:a4:c9:41:28:c7:2e:2a:2e:d8:a8:75:7a:72:77:3b:1b:9f:
+        72:15:0d:0c:96:8d:8b:51:f3:ce:37:b6:ca:9f:ca:59:40:4a:
+        fc:73:7a:94:12:99:aa:c2:8d:52:ce:91:19:2e:b4:da:ff:e5:
+        2c:67:74:d9:58:47:38:2f:61:88:c5:cf:a7:48:e1:08:ba:bc:
+        ec:d5:3a:47:d9:8c:dc:c3:bc:cb:98:2b:79:7a:02:46:ef:85:
+        19:2f:03:4b:05:84:eb:56:98:5f:6d:cf:a5:8b:a2:b6:e5:50:
+        51:7c:33:44:bd:7a:94:2e:0d:90:39:39:3e:62:60:ae:3a:e2:
+        f5:17:fa:f1:94:06:1d:ae:a3:f8:19:20:7f:4b:4c:07:c4:e6:
+        2d:0d:e5:94:84:51:6d:6f:0f:c4:c6:79:1d:f0:e8:0e:23:9e:
+        fd:f9:46:2c:b9:ec:97:38:56:7e:b8:13:f6:d2:e1:8e:a5:93:
+        02:7b:6e:dd:33:9a:bf:10:a8:1b:3d:fa:c4:f2:15:f0:27:73:
+        26:a6:94:d1
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
+IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0yMDAzMDQxMDI3MTRaGA8yMDUwMDMw
+MzEwMjcxNFowgZIxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEX
+MBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MT4w
+PAYDVQQDDDVDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nIChVYnVu
+dHUgQ29yZSAyMDE5KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkQ
+Ry51XfMQI7ugddL6Ai3/It/B5s04fDYPrnQVbqU0UivDpDpg1wbuHZmT/2aRoxhS
+LIxY5rQvS8X7g+bzGb0byiPslx/Y8ZrxBNraEARTS+wdtiZHfLuPpwpuLuiR5sS7
+ZDR4PPoJFRyPnusEmTYixo0HFQ+5aQj6/0tFvborzQEO5wEjyeV6OTuRsEU81Xe6
+yvkpPRE/HGtbjmxLP8kpBctZ1rHBwC1WiHAn+nMFXMIR1CcR9wvC1WjTGs3t0OQQ
+/zTLt0VwNCwjU7acMHC0XNHiZBiCj2KxXqoL1InyHFPEMn3vU+6bbgKreL0lZ4s5
+NtiEOwaZAtZ1c07y9rkCAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMB8GA1UdJQQY
+MBYGCCsGAQUFBwMDBgorBgEEAYI3CgMGMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
+IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUwdV7j2t0PyPuQfT37ikv
+Bu7K37kwHwYDVR0jBBgwFoAUrZGZC8IqsfUXBIwjtmVaJo40WmMwDQYJKoZIhvcN
+AQELBQADggEBAC21EajSoK+BoBgiGCwI0PRj6I+a9PUg3esidxmaGgk9f6p9yYG8
+JphllEYwS8JRfPchQWOHMfykyUEoxy4qLtiodXpydzsbn3IVDQyWjYtR8843tsqf
+yllASvxzepQSmarCjVLOkRkutNr/5SxndNlYRzgvYYjFz6dI4Qi6vOzVOkfZjNzD
+vMuYK3l6AkbvhRkvA0sFhOtWmF9tz6WLorblUFF8M0S9epQuDZA5OT5iYK464vUX
++vGUBh2uo/gZIH9LTAfE5i0N5ZSEUW1vD8TGeR3w6A4jnv35Riy57Jc4Vn64E/bS
+4Y6lkwJ7bt0zmr8QqBs9+sTyFfAncyamlNE=
+-----END CERTIFICATE-----
--- linux-ein-5.4.0.orig/debian/rules
+++ linux-ein-5.4.0/debian/rules
@@ -0,0 +1,254 @@
+#!/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_bpftool) $(do_tools_x86)))
+do_cloud_tools=$(sort $(filter-out false,$(do_tools_hyperv)))
+do_tools_common?=true
+do_tools_host?=false
+do_tools_perf_jvmti?=false
+do_enforce_all?=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_nvidia=false
+	do_dkms_nvidia_server=false
+	do_dkms_vbox=false
+	do_dkms_wireguard=false
+endif
+
+# Are any of the kernel signing options enabled.
+any_signed=$(sort $(filter-out false,$(uefi_signed) $(opal_signed) $(sipl_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
+
+# autopkgtest -- rebuild support
+#  - only build the first flavour on the assumption it is representative
+#  - disable dkms builds as the versions used may have been deleted
+ifneq ($(filter autopkgtest,$(DEB_BUILD_PROFILES)),)
+	flavours := $(firstword $(flavours))
+	disable_d_i=true
+	do_zfs=false
+	do_dkms_nvidia=false
+	do_dkms_nvidia_server=false
+	do_dkms_vbox=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_nvidia=false
+	do_dkms_nvidia_server=false
+	do_dkms_vbox=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)))
+
+# Versions of dkms packages.
+dkms_zfs_linux_version=$(shell gawk '/^zfs-linux / { print $$2; }' $(DEBIAN)/dkms-versions)
+dkms_vbox_guest_version=$(shell gawk '/^virtualbox/ { print $$2; }' $(DEBIAN)/dkms-versions)
+dkms_wireguard_version=$(shell gawk '/^wireguard-linux-compat / { print $$2; }' $(DEBIAN)/dkms-versions)
+
+# NVIDIA DKMS package gross series split into desktop and server.
+nvidia_desktop_series=$(shell sed -n -e 's/^nvidia-graphics-drivers-\([0-9][0-9]*\) .*/\1/p' $(DEBIAN)/dkms-versions)
+nvidia_server_series=$(shell sed -n -e 's/^nvidia-graphics-drivers-\([0-9][0-9]*-server\) .*/\1/p' $(DEBIAN)/dkms-versions)
+
+# Debian Build System targets
+binary: binary-indep binary-arch
+
+build: build-arch build-indep
+
+clean: debian/control debian/canonical-certs.pem debian/canonical-revoked-certs.pem
+	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/$(arch)/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 || true
+
+	# Remove generated intermediate files
+	rm -f $(DROOT)/control.stub $(DEBIAN)/control.stub
+	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
+
+control_files := $(DEBIAN)/control.stub.in
+ifeq ($(do_libc_dev_package),true)
+ifneq (,$(wildcard $(DEBIAN)/control.d/linux-libc-dev.stub))
+	control_files += $(DEBIAN)/control.d/linux-libc-dev.stub
+endif
+endif
+ifeq ($(do_doc_package),true)
+ifneq (,$(wildcard $(DEBIAN)/control.d/linux-doc.stub))
+	control_files += $(DEBIAN)/control.d/linux-doc.stub
+endif
+endif
+
+# Calculate Ubuntu Compatible Signing levels
+UBUNTU_COMPATIBLE_SIGNING=$(shell grep -qx ' *Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing (2021 v3)' debian/canonical-revoked-certs.pem && echo ubuntu/4 pro/3)
+
+# Misc stuff
+.PHONY: $(DEBIAN)/control.stub
+$(DEBIAN)/control.stub: 				\
+		$(DROOT)/scripts/control-create		\
+		$(control_files)			\
+		debian/canonical-revoked-certs.pem	\
+		$(DEBIAN)/changelog			\
+		$(wildcard $(DEBIAN)/control.d/* $(DEBIAN)/sub-flavours/*.vars)
+	for i in $(control_files); do                                           \
+	  cat $$i;                                                              \
+	  echo "";                                                              \
+	done | sed -e 's/PKGVER/$(release)/g'                                   \
+	        -e 's/ABINUM/$(abinum)/g'                                       \
+		-e 's/SRCPKGNAME/$(src_pkg_name)/g'                             \
+		-e 's/=HUMAN=/$(human_arch)/g'                                  \
+		-e 's/=SERIES=/$(series)/g'                                     \
+		-e 's|\(^Maintainer:.*\)|\1\nXSC-Ubuntu-Compatible-Signing: $(UBUNTU_COMPATIBLE_SIGNING)|g' \
+	  > $(DEBIAN)/control.stub;
+	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'                                  \
+		-e 's/=SERIES=/$(series)/g'                                     \
+		>> $(DEBIAN)/control.stub;                                      \
+	done
+
+.PHONY: debian/control
+debian/control: $(DEBIAN)/control.stub
+	echo "# placebo control.stub for kernel-wedge flow change" >debian/control.stub
+	cp $(DEBIAN)/control.stub debian/control
+	export KW_DEFCONFIG_DIR=$(DEBIAN)/d-i && \
+	export KW_CONFIG_DIR=$(DEBIAN)/d-i && \
+	LANG=C kernel-wedge gen-control $(release)-$(abinum) | \
+		perl -f $(DROOT)/scripts/misc/kernel-wedge-arch.pl $(arch) \
+		>>$(CURDIR)/debian/control
+
+debian/canonical-certs.pem: $(wildcard $(DROOT)/certs/*-all.pem) $(wildcard $(DROOT)/certs/*-$(arch).pem) $(wildcard $(DEBIAN)/certs/*-all.pem) $(wildcard $(DEBIAN)/certs/*-$(arch).pem)
+	for cert in $(sort $(notdir $^));					\
+	do									\
+		for dir in $(DEBIAN) $(DROOT);					\
+		do								\
+			if [ -f "$$dir/certs/$$cert" ]; then			\
+				cat "$$dir/certs/$$cert";			\
+				break;						\
+			fi;							\
+		done;								\
+	done >"$@"
+
+debian/canonical-revoked-certs.pem: $(wildcard $(DROOT)/revoked-certs/*-all.pem) $(wildcard $(DROOT)/revoked-certs/*-$(arch).pem) $(wildcard $(DEBIAN)/revoked-certs/*-all.pem) $(wildcard $(DEBIAN)/revoked-certs/*-$(arch).pem)
+	for cert in $(sort $(notdir $^));					\
+	do									\
+		for dir in $(DEBIAN) $(DROOT);					\
+		do								\
+			if [ -f "$$dir/revoked-certs/$$cert" ]; then		\
+				cat "$$dir/revoked-certs/$$cert";		\
+				break;						\
+			fi;							\
+		done;								\
+	done >"$@"
--- linux-ein-5.4.0.orig/debian/rules.d/0-common-vars.mk
+++ linux-ein-5.4.0/debian/rules.d/0-common-vars.mk
@@ -0,0 +1,278 @@
+# 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 the series
+series=$(shell dpkg-parsechangelog -l$(DEBIAN)/changelog | sed -ne 's/^Distribution: *//p' | sed -e 's/-\(security\|updates\|proposed\)$$//')
+
+# 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 variants. Assume primary if debian/variants is not present.
+variants = --
+ifneq (,$(wildcard $(DEBIAN)/variants))
+	variants := $(shell cat $(DEBIAN)/variants)
+endif
+
+# 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_tag := "v$(upstream_version).$(upstream_patchlevel)"
+
+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.current/$(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.
+ifneq ($(filter --,$(variants)),)
+do_doc_package=true
+else
+do_doc_package=false
+endif
+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 only for the
+# primary variant
+ifneq ($(filter --,$(variants)),)
+do_libc_dev_package=true
+else
+do_libc_dev_package=false
+endif
+
+# 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
+
+# Add an option to enable special drivers which should only be build when
+# explicitly enabled.
+do_odm_drivers=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 bpf cpu-hotplug efivarfs memfd memory-hotplug mount net ptrace seccomp timers powerpc user ftrace
--- linux-ein-5.4.0.orig/debian/rules.d/1-maintainer.mk
+++ linux-ein-5.4.0/debian/rules.d/1-maintainer.mk
@@ -0,0 +1,198 @@
+# The following targets are for the maintainer only! do not run if you don't
+# know what they do.
+
+.PHONY: printenv updateconfigs migrateconfigs 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 "  migrateconfigs       : Automatically import old configs into annotations"
+	@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;
+ifneq ($(wildcard $(DEBIAN)/config/config.common.ubuntu),)
+	$(SHELL) $(DROOT)/scripts/misc/old-kernelconfig $@ "$(do_enforce_all)"
+else
+	kmake='$(kmake)' skip_checks=$(do_skip_checks) conc_level=$(conc_level) \
+		$(SHELL) $(DROOT)/scripts/misc/kernelconfig $@
+	@rm -rf build
+endif
+
+migrateconfigs:
+ifneq ($(wildcard $(DEBIAN)/config/config.common.ubuntu),)
+	dh_testdir
+	conc_level=$(conc_level) $(SHELL) $(DROOT)/scripts/misc/old-kernelconfig genconfigs
+	rm -rf build
+	mkdir build
+	mv $(DEBIAN)/config/annotations build/.annotations
+	mv $(DEBIAN)/config/README.rst build/.README.rst 2>/dev/null || true
+	rm -rf $(DEBIAN)/config
+	mkdir -p $(DEBIAN)/config
+	debian/scripts/misc/migrate-annotations < build/.annotations > $(DEBIAN)/config/annotations
+	mv build/.README.rst $(DEBIAN)/config/README.rst 2>/dev/null || true
+	rm -rf build
+	kmake='$(kmake)' conc_level=$(conc_level) $(SHELL) $(DROOT)/scripts/misc/kernelconfig updateconfigs
+endif
+
+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 "series            = $(series)"
+	@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 "variants          = $(variants)"
+	@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_odm_drivers            = $(do_odm_drivers)"
+	@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_bpftool          = $(do_tools_bpftool)"
+	@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 " sipl_signed               = $(sipl_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:
+	# No need for reconstruct for -rc kernels since we don't upload an
+	# orig tarball, so just remove it.
+	if grep -q "^EXTRAVERSION = -rc[0-9]\+$$" Makefile; then \
+		echo "exit 0" >$(DEBIAN)/reconstruct; \
+	else \
+		$(DROOT)/scripts/misc/gen-auto-reconstruct $(upstream_tag) $(DEBIAN)/reconstruct $(DROOT)/source/options; \
+	fi
+
+finalchecks: debian/control
+	$(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-ein-5.4.0.orig/debian/rules.d/2-binary-arch.mk
+++ linux-ein-5.4.0/debian/rules.d/2-binary-arch.mk
@@ -0,0 +1,824 @@
+# 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-%: 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-$*
+	if [ -e $(commonconfdir)/config.common.ubuntu ]; then \
+		cat $(commonconfdir)/config.common.ubuntu $(archconfdir)/config.common.$(arch) $(archconfdir)/config.flavour.$(target_flavour) > $(builddir)/build-$*/.config; \
+	else \
+		python3 debian/scripts/misc/annotations --export --arch $(arch) --flavour $(target_flavour) | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$* $(raw_kernelversion)"/' > $(builddir)/build-$*/.config; \
+	fi
+	sed -i 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$* $(raw_kernelversion)"/' $(builddir)/build-$*/.config
+	[ "$(do_odm_drivers)" = 'true' ] && true || \
+		sed -ie 's/.*CONFIG_UBUNTU_ODM_DRIVERS.*/# CONFIG_UBUNTU_ODM_DRIVERS is not set/' \
+		    $(builddir)/build-$*/.config
+	find $(builddir)/build-$* -name "*.ko" | xargs rm -f
+	$(build_cd) $(kmake) $(build_O) -j1 syncconfig 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: $@
+
+# Do the actual build, including image and modules
+$(stampdir)/stamp-build-%: target_flavour = $*
+$(stampdir)/stamp-build-%: bldimg = $(call custom_override,build_image,$*)
+$(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)
+
+	@touch $@
+
+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 =
+	CROSS_COMPILE=$(CROSS_COMPILE) $(SHELL) $(DROOT)/scripts/dkms-build $(dkms_dir) $(abi_release)-$* '$(call build_dkms_sign,$(builddir)/build-$*)' $(1) $(2) $(3) $(4) $(5)
+endef
+
+# nvidia_build_payload 450 450 450_450.102.04-0ubuntu0.20.04.1
+# nvidia_build_payload 450-server 450srv 50.102.04-0ubuntu0.20.04.1
+define nvidia_build_payload =
+	$(call build_dkms, $(bldinfo_pkg_name)-$*, $(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/signatures, "", nvidia-$(2), pool/restricted/n/nvidia-graphics-drivers-$(1)/nvidia-kernel-source-$(1)_$(3)_$(arch).deb pool/restricted/n/nvidia-graphics-drivers-$(1)/nvidia-dkms-$(1)_$(3)_$(arch).deb)
+endef
+# nvidia_build 450
+# nvidia_build 450-server
+define nvidia_build =
+	$(call nvidia_build_payload,$(1),$(shell echo $(1) | sed -e 's/-server/srv/'),$(shell awk '/^nvidia-graphics-drivers-$(1) / {print($$2);}' $(DEBIAN)/dkms-versions))
+
+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-%: dbgpkgdir_zfs = $(if $(filter true,$(skipdbg)),"",$(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/kernel)
+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)
+	# gzipped kernel images must be decompressed for signing
+	if [[ "$(kernfile)" =~ \.gz$$ ]]; then \
+		< $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+			gunzip -cv > $(signingv)/$(instfile)-$(abi_release)-$*.efi; \
+		cp -p --attributes-only $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+			$(signingv)/$(instfile)-$(abi_release)-$*.efi; \
+		echo "GZIP=1" >> $(signingv)/$(instfile)-$(abi_release)-$*.efi.vars; \
+	else \
+		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
+ifeq ($(sipl_signed),true)
+	install -d $(signingv)
+	cp -p $(pkgdir_bin)/boot/$(instfile)-$(abi_release)-$* \
+		$(signingv)/$(instfile)-$(abi_release)-$*.sipl;
+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/$(arch)/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)-$*
+
+	#
+	# 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/ | \
+		grep -v '^bcm2835_wdt$$' | \
+		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"
+	install -d $(pkgdir_bin)/usr/lib/linux/triggers
+	$(call install_control,$(bin_pkg_name)-$*,image,postinst postrm preinst prerm)
+	install -d $(pkgdir)/usr/lib/linux/triggers
+	$(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	\
+		install -d $(pkgdir_ex)/usr/lib/linux/triggers; \
+		$(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 only after all/DKMS modules are built.
+	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 syncconfig 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
+	if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin.modinfo ] ; then \
+	    mv $(pkgdir)/lib/modules/$(abi_release)-$*/modules.builtin.modinfo \
+		$(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)-$*
+ifeq ($(do_tools_perf_jvmti),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/libperf-jvmti.so $(toolspkgdir)/usr/lib/linux-tools/$(abi_release)-$*
+endif
+endif
+ifeq ($(do_tools_bpftool),true)
+	$(LN) ../../$(src_pkg_name)-tools-$(abi_release)/bpftool $(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,$(enable_zfs)),$(call build_dkms, $(mods_pkg_name)-$*, $(pkgdir)/lib/modules/$(abi_release)-$*/kernel, $(dbgpkgdir_zfs), zfs, pool/universe/z/zfs-linux/zfs-dkms_$(dkms_zfs_linux_version)_all.deb))
+
+	$(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))
+
+ifeq ($(do_dkms_nvidia),true)
+	$(foreach series,$(nvidia_desktop_series),$(call nvidia_build,$(series)))
+endif
+ifeq ($(do_dkms_nvidia_server),true)
+	$(foreach series,$(nvidia_server_series),$(call nvidia_build,$(series)))
+endif
+
+ifeq ($(do_extras_package),true)
+	$(if $(filter true,$(do_dkms_vbox)),$(call build_dkms, $(mods_pkg_name)-$*, $(pkgdir)/lib/modules/$(abi_release)-$*/kernel, "", virtualbox-guest, pool/multiverse/v/virtualbox/virtualbox-guest-dkms_$(dkms_vbox_guest_version)_all.deb))
+endif
+
+ifneq ($(skipdbg),true)
+	# Add .gnu_debuglink sections to each stripped .ko
+	# pointing to unstripped verson
+	find $(pkgdir) \
+	  $(if $(filter true,$(do_extras_package)),$(pkgdir_ex)) \
+	  -name '*.ko' | while read path_module ; do \
+		module="/lib/modules/$${path_module#*/lib/modules/}"; \
+		if [[ -f "$(dbgpkgdir)/usr/lib/debug/$$module" ]] ; then \
+			while IFS= read -r -d '' signature < <(tail -c 28 "$$path_module"); do \
+				break; \
+			done; \
+			$(CROSS_COMPILE)objcopy \
+				--add-gnu-debuglink=$(dbgpkgdir)/usr/lib/debug/$$module \
+				$$path_module; \
+			if grep -q CONFIG_MODULE_SIG=y $(builddir)/build-$*/.config && \
+			   [ "$$signature" = $$'~Module signature appended~\n' ]; then \
+				$(builddir)/build-$*/scripts/sign-file $(MODHASHALGO) \
+					$(MODSECKEY) \
+					$(MODPUBKEY) \
+					$$path_module; \
+			fi; \
+		else \
+			echo "WARNING: Missing debug symbols for module '$$module'."; \
+		fi; \
+	done
+endif
+
+	# 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
+	install -m644 $(DROOT)/canonical-certs.pem $(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/canonical-certs.pem
+	install -m644 $(DROOT)/canonical-revoked-certs.pem $(pkgdir_bldinfo)/usr/lib/linux/$(abi_release)-$*/canonical-revoked-certs.pem
+
+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) syncconfig
+	$(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 $(headers_dir)/usr/include/$(DEB_HOST_MULTIARCH)
+	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)
+endef
+define newline
+
+
+endef
+define dh_all_inline
+        $(subst ${newline},; \${newline},$(call dh_all,$(1)))
+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/$(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,$*)),spl-modules$(comma) spl-dkms$(comma) zfs-modules$(comma) zfs-dkms$(comma))
+binary-%: rprovides += $(if $(filter true,$(call custom_override,do_dkms_vbox,$*)),virtualbox-guest-dkms$(comma))
+binary-%: target_flavour = $*
+binary-%: checks-%
+	@echo Debug: $@
+	dh_testdir
+	dh_testroot
+
+	$(call dh_all,$(pkgimg))
+	$(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)); \
+	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) syncconfig
+	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
+endif
+ifeq ($(do_tools_bpftool),true)
+	$(kmake) CROSS_COMPILE=$(CROSS_COMPILE) -C $(builddirpa)/tools/bpf/bpftool
+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)
+ifeq ($(do_tools_perf_jvmti),true)
+	install -m755 $(builddirpa)/tools/perf/libperf-jvmti.so $(toolspkgdir)/usr/lib/$(src_pkg_name)-tools-$(abi_release)
+endif
+endif
+ifeq ($(do_tools_bpftool),true)
+	install -m755 $(builddirpa)/tools/bpf/bpftool/bpftool $(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-ein-5.4.0.orig/debian/rules.d/3-binary-indep.mk
+++ linux-ein-5.4.0/debian/rules.d/3-binary-indep.mk
@@ -0,0 +1,221 @@
+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/output/ \
+			$(docdir)/html/; \
+		rm -rf $(docdir)/$(doc_pkg_name)-tmp; \
+	fi
+endif
+	# Copy the rest
+	cp -a Documentation/* $(docdir)
+	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 \
+		-path './$(DEBIAN)/__abi.current' -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: toolsbashcomp = $(CURDIR)/debian/$(toolspkg)/usr/share/bash-completion/completions
+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)
+	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 $(toolssbin)
+	install -d $(toolsman)/man1
+	install -d $(toolsman)/man8
+	install -d $(toolsbashcomp)
+
+	install -m755 debian/tools/generic $(toolsbin)/usbip
+	install -m755 debian/tools/generic $(toolsbin)/usbipd
+	install -m644 $(CURDIR)/tools/usb/usbip/doc/*.8 $(toolsman)/man8/
+
+	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 $(toolssbin)/bpftool
+	make -C $(builddir)/tools/tools/bpf/bpftool doc
+	install -m644 $(builddir)/tools/tools/bpf/bpftool/Documentation/*.8 \
+		$(toolsman)/man8
+	install -m644 $(builddir)/tools/tools/bpf/bpftool/bash-completion/bpftool \
+		$(toolsbashcomp)
+
+	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 -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)
+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 --no-enable --name intel-sgx-load-module
+endif
+endif
+	dh_installdeb -i
+	$(lockme) dh_gencontrol -i
+	dh_md5sums -i
+	dh_builddeb -i
--- linux-ein-5.4.0.orig/debian/rules.d/4-checks.mk
+++ linux-ein-5.4.0/debian/rules.d/4-checks.mk
@@ -0,0 +1,14 @@
+checks-%: install-%
+	@echo Debug: $@
+
+# Check the config against the known options list.
+config-prepare-check-%: $(stampdir)/stamp-prepare-tree-%
+	@echo Debug: $@
+	if [ -e $(commonconfdir)/config.common.ubuntu ]; then \
+		perl -f $(DROOT)/scripts/config-check \
+			$(builddir)/build-$*/.config "$(arch)" "$*" "$(commonconfdir)" \
+			"$(skipconfig)" "$(do_enforce_all)"; \
+	else \
+		python3 $(DROOT)/scripts/misc/annotations -f $(commonconfdir)/annotations \
+			--arch $(arch) --flavour $* --check $(builddir)/build-$*/.config; \
+	fi
--- linux-ein-5.4.0.orig/debian/rules.d/5-udebs.mk
+++ linux-ein-5.4.0/debian/rules.d/5-udebs.mk
@@ -0,0 +1,79 @@
+# 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 $(DEBIAN)/d-i/no-modules
+
+	touch $(CURDIR)/$(DEBIAN)/d-i/ignore-dups
+	export KW_DEFCONFIG_DIR=$(CURDIR)/$(DEBIAN)/d-i && \
+	export KW_CONFIG_DIR=$(CURDIR)/$(DEBIAN)/d-i && \
+	export SOURCEDIR=$(CURDIR)/debian/d-i-${arch} && \
+	  kernel-wedge install-files $(release)-$(abinum) && \
+	  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-ein-5.4.0.orig/debian/scripts/config-check
+++ linux-ein-5.4.0/debian/scripts/config-check
@@ -0,0 +1,163 @@
+#!/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 != 5) {
+	die "Usage: $P <config> <arch> <flavour> <commonconfig> <warn-only> <enforce-all>\n";
+}
+
+my ($configfile, $arch, $flavour, $commonconfig, $warn_only, $enforce_all) = @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;
+
+$enforce_all = 0 if $enforce_all eq "no" or $enforce_all eq "false";
+
+# 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 > 4);
+	    $form = $1;
+	}
+
+	# Format #3 and #4 add 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 = $enforce_all;
+	$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 "$config: $@" if ($@);
+			} else {
+				$policy = undef;
+			}
+		}
+	}
+	if ($check == 1 && !defined($policy)) {
+		print "$P: INVALID POLICY (use policy<{...}>) $config$options\n";
+		$total++;
+		$check = 0;
+	}
+	if ($check) {
+		# CONFIG_VERSION_SIGNATURE is dynamically set during the build
+		next if ($config eq "CONFIG_VERSION_SIGNATURE");
+		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-ein-5.4.0.orig/debian/scripts/control-create
+++ linux-ein-5.4.0/debian/scripts/control-create
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. debian/debian.env
+
+vars=$1
+any_signed=$2
+
+. $vars
+
+[ "$provides" != '' ] && provides="$provides, "
+
+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-ein-5.4.0.orig/debian/scripts/dkms-build
+++ linux-ein-5.4.0/debian/scripts/dkms-build
@@ -0,0 +1,261 @@
+#!/bin/sh
+set -e
+
+dkms_dir="$1"
+abi_flavour="$2"
+sign="$3"
+pkgname="$4"
+pkgdir="$5"
+dbgpkgdir="$6"
+package="$7"
+shift 7
+
+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"
+
+# Run any dkms-package specfic configuration steps
+dkms_config_specific="$srcdir/$0-configure--$package"
+dkms_config_generic=$(echo "$dkms_config_specific" | sed -e 's/-[0-9][0-9]*$/-N/')
+for dkms_config in "$dkms_config_specific" "$dkms_config_generic"
+do
+	if [ -z "$dkms_config" -o ! -e "$dkms_config" ]; then
+		continue
+	fi
+	echo "II: dkms-build-configure $(basename "$dkms_config") found, executing"
+	"$dkms_config" \
+		"$srcdir" \
+		"$dkms_conf" \
+		"$dkms_dir" \
+		"$abi_flavour" \
+		"$sign" \
+		"$pkgname" \
+		"$pkgdir" \
+		"$dbgpkgdir" \
+		"$package" \
+		"$@" || exit 1
+	break
+done
+
+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"
+fakeroot=""
+[ $(id -u) -ne 0 ] && fakeroot="/usr/bin/fakeroot"
+rc=0
+$fakeroot /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 the modules with debug symbols we possibly built,
+# and strip the original modules for the next install step.
+if [ -n "$dbgpkgdir" ]; then
+	dbgpkgdir="$dbgpkgdir/$package"
+	echo "II: dkms-build installing $package into $dbgpkgdir (debug symbols)"
+	install -d "$dbgpkgdir"
+	find "$dkms_dir/build/$dkms_package/$dkms_version/$abi_version" -name \*.ko |
+	while read module; do
+		vmodule=$( basename "$module" )
+
+		# Check for '.debug_info' section in order to copy module.
+		# Useful if debug symbols are requested but not built for
+		# any reason (including not yet supported by DKMS package).
+		# Strip module just in case even if section isn't present.
+		if ${CROSS_COMPILE}objdump -h -j '.debug_info' "$module" >/dev/null 2>&1
+		then
+			echo "copying $vmodule"
+			cp "$module" "$dbgpkgdir"
+		else
+			echo "ignoring $vmodule (missing debug symbols)"
+		fi
+
+		# Just 'strip -g' as '/usr/sbin/dkms' does.
+		echo "stripping $vmodule"
+		strip -g "$module"
+	done
+fi
+
+# 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 -n -e 's/-[0-9][0-9]*[a-z]*$/-N/p')
+for dkms_build in "$dkms_build_specific" "$dkms_build_generic"
+do
+	if [ -z "$dkms_build" -o ! -e "$dkms_build" ]; then
+		continue
+	fi
+	echo "II: dkms-build override $(basename "$dkms_build") found, executing"
+	"$dkms_build" \
+		"$srcdir" \
+		"$dkms_dir/build/$dkms_package/$dkms_version/objects" \
+		"$log" \
+		"$dkms_dir" \
+		"$abi_flavour" \
+		"$sign" \
+		"$pkgname" \
+		"$pkgdir" \
+		"$dbgpkgdir" \
+		"$package" \
+		"$@" || exit 1
+	break
+done
+
+echo "II: dkms-build build $package complete"
--- linux-ein-5.4.0.orig/debian/scripts/dkms-build--nvidia-N
+++ linux-ein-5.4.0/debian/scripts/dkms-build--nvidia-N
@@ -0,0 +1,113 @@
+#!/bin/sh
+set -e
+
+srcdir="$1"
+objects="$2"
+log="$3"
+shift 3
+
+dkms_dir="$1"
+abi_flavour="$2"
+sign="$3"
+pkgname="$4"
+pkgdir="$5"
+dbgpkgdir="$6"
+package="$7"
+shift 7
+
+build="$( dirname "$objects" )/build"
+
+# Copy over the objects ready for reconstruction.  The objects copy contains
+# the *.o files and the *.o-ur* retpoline files to allow the kernel to track
+# any retpoline sequences therein.  For our purposes we only want the *.o
+# files, elide the rest.
+mkdir -p "$pkgdir/bits/scripts"
+(
+	gcc_variant1=$(gcc --version | head -1 | sed -e 's/^gcc/GCC:/')
+	gcc_variant2=$(gcc --version | head -1 | sed -e 's/^\(gcc\) \((.*)\) \(.*\)$/\1 version \3 \2/')
+	cd "$objects" || exit 1
+	find -name \*.o | \
+	while read file
+	do
+		cp --parents "$file" "$pkgdir/bits"
+		"$srcdir/debian/scripts/fix-filenames" "$pkgdir/bits/$file" "$gcc_variant1"
+		"$srcdir/debian/scripts/fix-filenames" "$pkgdir/bits/$file" "$gcc_variant2"
+	done
+)
+
+# Install the support files we need.
+echo "II: copying support files ..."
+for lds_src in \
+	"$dkms_dir/headers/linux-headers-$abi_flavour/scripts/module.lds" \
+	"/usr/src/linux-headers-$abi_flavour/scripts/module.lds" \
+	"$dkms_dir/headers/linux-headers-$abi_flavour/scripts/module-common.lds" \
+	"/usr/src/linux-headers-$abi_flavour/scripts/module-common.lds"
+do
+	[ ! -f "$lds_src" ] && continue
+	echo "II: copying support files ... found $lds_src"
+	cp "$lds_src" "$pkgdir/bits/scripts"
+	break
+done
+
+# Build helper scripts.
+cat - <<'EOL' >"$pkgdir/bits/BUILD"
+[ "$1" = "unsigned" ] && { signed_only=:; shift; }
+[ "$1" = "nocheck" ] && { check_only=:; shift; }
+EOL
+grep /usr/bin/ld.bfd "$log" | grep -v scripts/genksyms/genksyms | sed -e "s@$build/@@g" >>"$pkgdir/bits/BUILD"
+sed -e 's/.*-o  *\([^ ]*\) .*/rm -f \1/g' <"$pkgdir/bits/BUILD" >"$pkgdir/bits/CLEAN"
+
+# As the builds contain the absolute filenames as used.  Use RECONSTRUCT to
+# rebuild the .ko's, sign them, pull off the signatures and then finally clean
+# up again.
+(
+	cd "$pkgdir/bits" || exit 1
+
+	# Add checksum check.
+	echo "\$check_only sha256sum -c SHA256SUMS || exit 1" >>"$pkgdir/bits/BUILD"
+
+	# Add .ko handling to the CLEAN/BUILD dance.
+	for ko in "$pkgdir"/*.ko
+	do
+		ko=$(basename "$ko")
+		echo "\$signed_only cat '$ko' '$ko.sig' >'../$ko'" >>"$pkgdir/bits/BUILD"
+		echo "\$signed_only rm -f '$ko'" >>"$pkgdir/bits/BUILD"
+		echo "rm -f '../$ko'" >>"$pkgdir/bits/CLEAN"
+	done
+
+	# Clear out anything we are not going to distribute and build unsigned .kos.
+	sh ./CLEAN
+	sh ./BUILD unsigned nocheck
+
+	if [ "$sign" = "--custom" ]; then
+		# We are building for and archive custom signing upload.  Keep everything.
+		:
+	elif [ "$sign" = "--lrm" ]; then
+		# We are in the LRM build; grab sha256 checksums and clean up.
+		sha256sum -b *.ko >"SHA256SUMS"
+		sh ./CLEAN
+
+	else
+		# We are in the main kernel, put the .kos together as we will
+		# on the users machine, sign them, and keep just the signature.
+		: >"SHA256SUMS"
+		for ko in *.ko
+		do
+			echo "detached-signature $ko"
+			$sign "$ko" "$ko.signed"
+			length=$( stat --format %s "$ko" )
+			dd if="$ko.signed" of="$ko.sig" bs=1 skip="$length" 2>/dev/null
+
+			rm -f "$ko.signed"
+			# Keep a checksum of the pre-signed object so we can check it is
+			# built correctly in LRM.
+			sha256sum -b "$ko" >>"SHA256SUMS"
+		done
+
+		# Clean out anything which not a signature.
+		mv "$pkgdir/bits/"*.sig "$pkgdir"
+		mv "$pkgdir/bits/SHA256SUMS" "$pkgdir"
+		find "$pkgdir" -name \*.sig -prune -o -name SHA256SUMS -prune -o -type f -print | xargs rm -f
+		find "$pkgdir" -depth -type d -print | xargs rmdir --ignore-fail-on-non-empty
+	fi
+) || exit "$?"
--- linux-ein-5.4.0.orig/debian/scripts/dkms-build--virtualbox-guest
+++ linux-ein-5.4.0/debian/scripts/dkms-build--virtualbox-guest
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+srcdir="$1"
+objects="$2"
+log="$3"
+shift 3
+
+dkms_dir="$1"
+abi_flavour="$2"
+sign="$3"
+pkgname="$4"
+pkgdir="$5"
+dbgpkgdir="$6"
+package="$7"
+shift 7
+
+# We want to ship the vboxvideo.ko from the upstream staging tree, so
+# remove the one built via dkms.
+rm -f "$pkgdir/vboxvideo.ko"
--- linux-ein-5.4.0.orig/debian/scripts/dkms-build-configure--zfs
+++ linux-ein-5.4.0/debian/scripts/dkms-build-configure--zfs
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+srcdir="$1"
+dkms_conf="$2"
+shift 2
+
+dkms_dir="$1"
+abi_flavour="$2"
+sign="$3"
+pkgname="$4"
+pkgdir="$5"
+dbgpkgdir="$6"
+package="$7"
+shift 7
+
+# ZFS debug symbols are enabled in dkms.conf via PACKAGE_CONFIG file.
+if [ -n "$dbgpkgdir" ]; then
+	echo "enable zfs debug symbols"
+	pkg_cfg="$(dirname "$dkms_conf")/pkg_cfg"
+	echo 'ZFS_DKMS_ENABLE_DEBUGINFO=yes' >"$pkg_cfg"
+	echo 'ZFS_DKMS_DISABLE_STRIP=yes'   >>"$pkg_cfg"
+	sed -i "s,^\(PACKAGE_CONFIG=\).*,\1$pkg_cfg," $dkms_conf
+fi
--- linux-ein-5.4.0.orig/debian/scripts/file-downloader
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/fix-filenames.c
+++ linux-ein-5.4.0/debian/scripts/fix-filenames.c
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+	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;
+		/* In the case of an exact match there there is nothing to move. */
+		if (in[prefix_len] == '\0')
+			length = 0;
+		/* If this is a filename, strip the leading slash. */
+		else if (in[prefix_len] == '/')
+			length = strlen(in + prefix_len + 1) + 1;
+		/* Otherwise just keep the suffix. */
+		else
+			length = strlen(in + prefix_len) + 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, '\0', prefix_len);
+	}
+}
--- linux-ein-5.4.0.orig/debian/scripts/link-headers
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/annotations
+++ linux-ein-5.4.0/debian/scripts/misc/annotations
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+# -*- mode: python -*-
+
+# This file is not installed; it's just to run annotations from inside a source
+# distribution without installing it in the system.
+
+import sys
+
+# Prevent generating .pyc files on import
+#
+# We may end up adding these files to our git repos by mistake, so simply
+# prevent generating them in advance.
+#
+# There's a tiny performance penalty with this, because python needs to
+# re-generate the bytecode on-the-fly every time the script is executed, but
+# this overhead is absolutely negligible compared the rest of the kernel build
+# time.
+sys.dont_write_bytecode = True
+
+import os  # noqa: E402 Import not at top of file
+from kconfig import run  # noqa: E402 Import not at top of file
+
+
+# Update PATH to make sure that annotations can be executed directly from the
+# source directory.
+def update_path():
+    script_dir = os.path.dirname(os.path.abspath(__file__))
+    current_path = os.environ.get("PATH", "")
+    new_path = f"{script_dir}:{current_path}"
+    os.environ["PATH"] = new_path
+
+
+update_path()
+exit(run.main())
--- linux-ein-5.4.0.orig/debian/scripts/misc/arch-has-odm-enabled.sh
+++ linux-ein-5.4.0/debian/scripts/misc/arch-has-odm-enabled.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Evaluate whether arch ($1) will be built with do_odm_drivers set to true.
+set -e
+
+if [ "$1" = "" ]; then
+	# This would be set doing the actual kernel build
+	if [ "$KBUILD_VERBOSE" = "" ]; then
+		return 1
+	fi
+	case $ARCH in
+	x86)	ARCH=amd64;;
+	*)	;;
+	esac
+else
+	ARCH=$1
+fi
+
+TOPDIR=$(dirname $0)/../../..
+. $TOPDIR/debian/debian.env
+RULESDIR=$TOPDIR/$DEBIAN/rules.d
+
+do_odm_drivers=false
+for f in $ARCH.mk hooks.mk; do
+	eval $(cat $RULESDIR/$f | sed -n -e '/do_odm_drivers/s/ \+//gp')
+done
+if [ "$do_odm_drivers" != "true" ]; then
+	return 1
+fi
+
+return 0
--- linux-ein-5.4.0.orig/debian/scripts/misc/final-checks
+++ linux-ein-5.4.0/debian/scripts/misc/final-checks
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+debian="$1"
+abi="$2"
+
+. "$debian/etc/kernelconfig"
+archs=$( awk '/^Architecture:/ { $1=""; for (i=1; i<=NF; i++) { if ($i != "all") { print $i }}}' debian/control | sort -u)
+
+fail=0
+
+failure()
+{
+	echo "EE: $@" 1>&2
+	fail=1
+}
+
+if [ -e $debian/config/config.common.ubuntu ]; then
+    if [ -d debian/certs ]; then
+        if ! grep -q '^CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"$' $debian/config/config.common.ubuntu; then
+	    failure "'CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"' is required"
+        fi
+    fi
+
+    if [ -d debian/revoked-certs ]; then
+        if ! grep -q '^CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"$' $debian/config/config.common.ubuntu; then
+	    failure "'CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"' is required"
+        fi
+    fi
+fi
+
+for arch in $archs
+do
+	image_pkg=$(awk -F '\\s*=\\s*' '$1 == "do_flavour_image_package" { print $2 }' $debian/rules.d/$arch.mk)
+	if [ "$image_pkg" = "false" ]; then
+		continue
+	fi
+	if [ ! -f "$debian/rules.d/$arch.mk" ]; then
+		continue
+	fi
+	flavours=$(
+		awk '/^\s*flavours\s*=/{
+			sub(/^\s*flavours\s*=\s*/, "");
+			print
+		}' "$debian/rules.d/$arch.mk")
+	for flavour in $flavours
+	do
+		flavour=$(echo "$flavour" | sed -e 's@.*/config.flavour.@@')
+	done
+done
+
+exit "$fail"
--- linux-ein-5.4.0.orig/debian/scripts/misc/find-missing-sauce.sh
+++ linux-ein-5.4.0/debian/scripts/misc/find-missing-sauce.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# Find the 'UBUNTU: SAUCE:' patches that have been dropped from
+# the previous release.
+#
+PREV_REL=artful
+PREV_REPO=git://kernel.ubuntu.com/ubuntu/ubuntu-${PREV_REL}.git
+
+git fetch ${PREV_REPO} master-next
+git log --pretty=oneline FETCH_HEAD|grep SAUCE|while read c m;do echo $m;done |sort > $$.prev-rel
+git log --pretty=oneline |grep SAUCE|while read c m;do echo $m;done |sort > $$.curr-rel
+
+diff -u $$.prev-rel $$.curr-rel |grep "^-"
+rm -f $$.prev-rel $$.curr-rel
+
--- linux-ein-5.4.0.orig/debian/scripts/misc/find-obsolete-firmware
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/fw-to-ihex.sh
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/gen-auto-reconstruct
+++ linux-ein-5.4.0/debian/scripts/misc/gen-auto-reconstruct
@@ -0,0 +1,89 @@
+#!/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 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
+			added=$(( new & 0111 ))
+			if [ "$added" -ne 0 ]; then
+				echo "chmod +x '$name'"
+                       elif [ "$new" -ne 0 ]; then
+				echo "chmod -x '$name'"
+			fi
+		fi
+	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
+
+	# 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-ein-5.4.0.orig/debian/scripts/misc/get-firmware
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/git-ubuntu-log
+++ linux-ein-5.4.0/debian/scripts/misc/git-ubuntu-log
@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+
+import sys
+
+import codecs
+import urllib.request
+import json
+
+import textwrap
+
+sys.stdin = codecs.getreader("utf-8")(sys.stdin.detach())
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
+
+entries = []
+
+
+def add_entry(entry):
+    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':
+                # Construct a key with '__trackingbug__' on the first position
+                # and the tracking bug number afterwards
+                combo.insert(0, '__trackingbug__')
+                # Tracking bug goes at the top
+                keys.insert(0, combo)
+            else:
+                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 = []
+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__')
+
+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 == '__trackingbug__':
+                # Look for the tracking bug number on the second
+                # position of the key
+                continue
+            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[0] != '__trackingbug__':
+            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-ein-5.4.0.orig/debian/scripts/misc/insert-changes.pl
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/insert-mainline-changes
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/insert-ubuntu-changes
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/kconfig/annotations.py
+++ linux-ein-5.4.0/debian/scripts/misc/kconfig/annotations.py
@@ -0,0 +1,522 @@
+# -*- mode: python -*-
+# python module to manage Ubuntu kernel .config and annotations
+# Copyright © 2022 Canonical Ltd.
+
+import json
+import re
+import shutil
+import tempfile
+
+from abc import abstractmethod
+from ast import literal_eval
+from os.path import dirname, abspath
+
+from kconfig.version import ANNOTATIONS_FORMAT_VERSION
+
+
+class Config:
+    def __init__(self, fname, do_include=True):
+        """
+        Basic configuration file object
+        """
+        self.fname = fname
+        self.config = {}
+        self.do_include = do_include
+
+        raw_data = self._load(fname)
+        self._parse(raw_data)
+
+    @staticmethod
+    def _load(fname: str) -> str:
+        with open(fname, "rt", encoding="utf-8") as fd:
+            data = fd.read()
+        return data.rstrip()
+
+    def __str__(self):
+        """Return a JSON representation of the config"""
+        return json.dumps(self.config, indent=4)
+
+    @abstractmethod
+    def _parse(self, data: str):
+        pass
+
+
+class KConfig(Config):
+    """
+    Parse a .config file, individual config options can be accessed via
+    .config[<CONFIG_OPTION>]
+    """
+
+    def _parse(self, data: str):
+        self.config = {}
+        for line in data.splitlines():
+            m = re.match(r"^# (CONFIG_.*) is not set$", line)
+            if m:
+                self.config[m.group(1)] = literal_eval("'n'")
+                continue
+            m = re.match(r"^(CONFIG_[A-Za-z0-9_]+)=(.*)$", line)
+            if m:
+                self.config[m.group(1)] = literal_eval("'" + m.group(2) + "'")
+                continue
+
+
+class Annotation(Config):
+    """
+    Parse body of annotations file
+    """
+
+    def __init__(self, fname, do_include=True, do_json=False):
+        self.do_json = do_json
+        super().__init__(fname, do_include=True)
+
+    def _parse_body(self, data: str, parent=True):
+        for line in data.splitlines():
+            # Replace tabs with spaces, squeeze multiple into singles and
+            # remove leading and trailing spaces
+            line = line.replace("\t", " ")
+            line = re.sub(r" +", " ", line)
+            line = line.strip()
+
+            # Ignore empty lines
+            if not line:
+                continue
+
+            # Catpure flavors of included files
+            if line.startswith("# FLAVOUR: "):
+                self.include_flavour += line.split(" ")[2:]
+                continue
+
+            # Ignore comments
+            if line.startswith("#"):
+                continue
+
+            # Handle includes (recursively)
+            m = re.match(r'^include\s+"?([^"]*)"?', line)
+            if m:
+                if parent:
+                    self.include.append(m.group(1))
+                if self.do_include:
+                    include_fname = dirname(abspath(self.fname)) + "/" + m.group(1)
+                    include_data = self._load(include_fname)
+                    self._parse_body(include_data, parent=False)
+                continue
+
+            # Handle policy and note lines
+            if re.match(r".* (policy|note)<", line):
+                try:
+                    conf = line.split(" ")[0]
+                    if conf in self.config:
+                        entry = self.config[conf]
+                    else:
+                        entry = {"policy": {}}
+
+                    match = False
+                    m = re.match(r".* policy<(.*?)>", line)
+                    if m:
+                        match = True
+                        # Update the previous entry considering potential overrides:
+                        #  - if the new entry is adding a rule for a new
+                        #    arch/flavour, simply add that
+                        #  - if the new entry is overriding a previous
+                        #    arch-flavour item, then overwrite that item
+                        #  - if the new entry is overriding a whole arch, then
+                        #    remove all the previous flavour rules of that arch
+                        new_entry = literal_eval(m.group(1))
+                        for key in new_entry:
+                            if key in self.arch:
+                                for flavour_key in list(entry["policy"].keys()):
+                                    if flavour_key.startswith(key):
+                                        del entry["policy"][flavour_key]
+                                entry["policy"][key] = new_entry[key]
+                            else:
+                                entry["policy"][key] = new_entry[key]
+
+                    m = re.match(r".* note<(.*?)>", line)
+                    if m:
+                        entry["oneline"] = match
+                        match = True
+                        entry["note"] = "'" + m.group(1).replace("'", "") + "'"
+
+                    if not match:
+                        raise SyntaxError("syntax error")
+                    self.config[conf] = entry
+                except Exception as e:
+                    raise SyntaxError(str(e) + f", line = {line}") from e
+                continue
+
+            # Invalid line
+            raise SyntaxError(f"invalid line: {line}")
+
+    def _legacy_parse(self, data: str):
+        """
+        Parse main annotations file, individual config options can be accessed
+        via self.config[<CONFIG_OPTION>]
+        """
+        self.config = {}
+        self.arch = []
+        self.flavour = []
+        self.flavour_dep = {}
+        self.include = []
+        self.header = ""
+        self.include_flavour = []
+
+        # Parse header (only main header will considered, headers in includes
+        # will be treated as comments)
+        for line in data.splitlines():
+            if re.match(r"^#.*", line):
+                m = re.match(r"^# ARCH: (.*)", line)
+                if m:
+                    self.arch = list(m.group(1).split(" "))
+                m = re.match(r"^# FLAVOUR: (.*)", line)
+                if m:
+                    self.flavour = list(m.group(1).split(" "))
+                m = re.match(r"^# FLAVOUR_DEP: (.*)", line)
+                if m:
+                    self.flavour_dep = literal_eval(m.group(1))
+                self.header += line + "\n"
+            else:
+                break
+
+        # Return an error if architectures are not defined
+        if not self.arch:
+            raise SyntaxError("ARCH not defined in annotations")
+        # Return an error if flavours are not defined
+        if not self.flavour:
+            raise SyntaxError("FLAVOUR not defined in annotations")
+
+        # Parse body
+        self._parse_body(data)
+
+        # Sanity check: Verify that all FLAVOUR_DEP flavors are valid
+        if self.do_include:
+            for src, tgt in self.flavour_dep.items():
+                if src not in self.flavour:
+                    raise SyntaxError(f"Invalid source flavour in FLAVOUR_DEP: {src}")
+                if tgt not in self.include_flavour:
+                    raise SyntaxError(f"Invalid target flavour in FLAVOUR_DEP: {tgt}")
+
+    def _json_parse(self, data, is_included=False):
+        data = json.loads(data)
+
+        # Check if version is supported
+        version = data["attributes"]["_version"]
+        if version > ANNOTATIONS_FORMAT_VERSION:
+            raise SyntaxError(f"annotations format version {version} not supported")
+
+        # Check for top-level annotations vs imported annotations
+        if not is_included:
+            self.config = data["config"]
+            self.arch = data["attributes"]["arch"]
+            self.flavour = data["attributes"]["flavour"]
+            self.flavour_dep = data["attributes"]["flavour_dep"]
+            self.include = data["attributes"]["include"]
+            self.include_flavour = []
+        else:
+            # We are procesing an imported annotations, so merge all the
+            # configs and attributes.
+            try:
+                self.config = data["config"] | self.config
+            except TypeError:
+                self.config = {**self.config, **data["config"]}
+            self.arch = list(set(self.arch) | set(data["attributes"]["arch"]))
+            self.flavour = list(set(self.flavour) | set(data["attributes"]["flavour"]))
+            self.include_flavour = list(set(self.include_flavour) | set(data["attributes"]["flavour"]))
+            self.flavour_dep = self.flavour_dep | data["attributes"]["flavour_dep"]
+
+        # Handle recursive inclusions
+        if self.do_include:
+            for f in data["attributes"]["include"]:
+                include_fname = dirname(abspath(self.fname)) + "/" + f
+                data = self._load(include_fname)
+                self._json_parse(data, is_included=True)
+
+    def _parse(self, data: str):
+        if self.do_json:
+            self._json_parse(data, is_included=False)
+        else:
+            self._legacy_parse(data)
+
+    def _remove_entry(self, config: str):
+        if self.config[config]:
+            del self.config[config]
+
+    def remove(self, config: str, arch: str = None, flavour: str = None):
+        if config not in self.config:
+            return
+        if arch is not None:
+            if flavour is not None:
+                flavour = f"{arch}-{flavour}"
+            else:
+                flavour = arch
+            del self.config[config]["policy"][flavour]
+            if not self.config[config]["policy"]:
+                self._remove_entry(config)
+        else:
+            self._remove_entry(config)
+
+    def set(
+        self,
+        config: str,
+        arch: str = None,
+        flavour: str = None,
+        value: str = None,
+        note: str = None,
+    ):
+        if value is not None:
+            if config not in self.config:
+                self.config[config] = {"policy": {}}
+            if arch is not None:
+                if flavour is not None:
+                    flavour = f"{arch}-{flavour}"
+                else:
+                    flavour = arch
+                self.config[config]["policy"][flavour] = value
+            else:
+                for a in self.arch:
+                    self.config[config]["policy"][a] = value
+        if note is not None:
+            self.config[config]["note"] = "'" + note.replace("'", "") + "'"
+
+    def update(self, c: KConfig, arch: str, flavour: str = None, configs: list = None):
+        """Merge configs from a Kconfig object into Annotation object"""
+
+        # Determine if we need to import all configs or a single config
+        if not configs:
+            configs = c.config.keys()
+            try:
+                configs |= self.search_config(arch=arch, flavour=flavour).keys()
+            except TypeError:
+                configs = {
+                    **configs,
+                    **self.search_config(arch=arch, flavour=flavour).keys(),
+                }
+
+        # Import configs from the Kconfig object into Annotations
+        flavour_arg = flavour
+        if flavour is not None:
+            flavour = arch + f"-{flavour}"
+        else:
+            flavour = arch
+        for conf in configs:
+            if conf in c.config:
+                val = c.config[conf]
+            else:
+                val = "-"
+            if conf in self.config:
+                if "policy" in self.config[conf]:
+                    # Add a TODO if a config with a note is changing and print
+                    # a warning
+                    old_val = self.search_config(config=conf, arch=arch, flavour=flavour_arg)
+                    if old_val:
+                        old_val = old_val[conf]
+                    if val != old_val and "note" in self.config[conf]:
+                        self.config[conf]["note"] = "TODO: update note"
+                        print(f"WARNING: {conf} changed from {old_val} to {val}, updating note")
+                    self.config[conf]["policy"][flavour] = val
+                else:
+                    self.config[conf]["policy"] = {flavour: val}
+            else:
+                self.config[conf] = {"policy": {flavour: val}}
+
+    def _compact(self):
+        # Try to remove redundant settings: if the config value of a flavour is
+        # the same as the one of the main arch simply drop it.
+        for conf in self.config.copy():
+            if "policy" not in self.config[conf]:
+                continue
+            for flavour in self.flavour:
+                if flavour not in self.config[conf]["policy"]:
+                    continue
+                m = re.match(r"^(.*?)-(.*)$", flavour)
+                if not m:
+                    continue
+                arch = m.group(1)
+                if arch in self.config[conf]["policy"]:
+                    if self.config[conf]["policy"][flavour] == self.config[conf]["policy"][arch]:
+                        del self.config[conf]["policy"][flavour]
+                        continue
+                if flavour not in self.flavour_dep:
+                    continue
+                generic = self.flavour_dep[flavour]
+                if generic in self.config[conf]["policy"]:
+                    if self.config[conf]["policy"][flavour] == self.config[conf]["policy"][generic]:
+                        del self.config[conf]["policy"][flavour]
+                        continue
+            # Remove rules for flavours / arches that are not supported (not
+            # listed in the annotations header).
+            for flavour in self.config[conf]["policy"].copy():
+                if flavour not in list(set(self.arch + self.flavour)):
+                    del self.config[conf]["policy"][flavour]
+            # Remove configs that are all undefined across all arches/flavours
+            # (unless we have includes)
+            if not self.include:
+                if "policy" in self.config[conf]:
+                    if list(set(self.config[conf]["policy"].values())) == ["-"]:
+                        self.config[conf]["policy"] = {}
+            # Drop empty rules
+            if not self.config[conf]["policy"]:
+                del self.config[conf]
+            else:
+                # Compact same value across all flavour within the same arch
+                for arch in self.arch:
+                    arch_flavours = [i for i in self.flavour if i.startswith(arch)]
+                    value = None
+                    for flavour in arch_flavours:
+                        if flavour not in self.config[conf]["policy"]:
+                            break
+                        if value is None:
+                            value = self.config[conf]["policy"][flavour]
+                        elif value != self.config[conf]["policy"][flavour]:
+                            break
+                    else:
+                        for flavour in arch_flavours:
+                            del self.config[conf]["policy"][flavour]
+                        self.config[conf]["policy"][arch] = value
+        # After the first round of compaction we may end up having configs that
+        # are undefined across all arches, so do another round of compaction to
+        # drop these settings that are not needed anymore
+        # (unless we have includes).
+        if not self.include:
+            for conf in self.config.copy():
+                # Remove configs that are all undefined across all arches/flavours
+                if "policy" in self.config[conf]:
+                    if list(set(self.config[conf]["policy"].values())) == ["-"]:
+                        self.config[conf]["policy"] = {}
+                # Drop empty rules
+                if not self.config[conf]["policy"]:
+                    del self.config[conf]
+
+    @staticmethod
+    def _sorted(config):
+        """Sort configs alphabetically but return configs with a note first"""
+        w_note = []
+        wo_note = []
+        for c in sorted(config):
+            if "note" in config[c]:
+                w_note.append(c)
+            else:
+                wo_note.append(c)
+        return w_note + wo_note
+
+    def save(self, fname: str):
+        """Save annotations data to the annotation file"""
+        # Compact annotations structure
+        self._compact()
+
+        # Save annotations to disk
+        with tempfile.NamedTemporaryFile(mode="w+t", delete=False) as tmp:
+            # Write header
+            tmp.write(self.header + "\n")
+
+            # Write includes
+            for i in self.include:
+                tmp.write(f'include "{i}"\n')
+            if self.include:
+                tmp.write("\n")
+
+            # Write config annotations and notes
+            tmp.flush()
+            shutil.copy(tmp.name, fname)
+            tmp_a = Annotation(fname)
+
+            # Only save local differences (preserve includes)
+            marker = False
+            for conf in self._sorted(self.config):
+                new_val = self.config[conf]
+                if "policy" not in new_val:
+                    continue
+
+                # If new_val is a subset of old_val, skip it unless there are
+                # new notes that are different than the old ones.
+                old_val = tmp_a.config.get(conf)
+                if old_val and "policy" in old_val:
+                    try:
+                        can_skip = old_val["policy"] == old_val["policy"] | new_val["policy"]
+                    except TypeError:
+                        can_skip = old_val["policy"] == {
+                            **old_val["policy"],
+                            **new_val["policy"],
+                        }
+                    if can_skip:
+                        if "note" not in new_val:
+                            continue
+                        if "note" in old_val and "note" in new_val:
+                            if old_val["note"] == new_val["note"]:
+                                continue
+
+                # Write out the policy (and note) line(s)
+                val = dict(sorted(new_val["policy"].items()))
+                line = f"{conf : <47} policy<{val}>"
+                if "note" in new_val:
+                    val = new_val["note"]
+                    if new_val.get("oneline", False):
+                        # Single line
+                        line += f" note<{val}>"
+                    else:
+                        # Separate policy and note lines,
+                        # followed by an empty line
+                        line += f"\n{conf : <47} note<{val}>\n"
+                elif not marker:
+                    # Write out a marker indicating the start of annotations
+                    # without notes
+                    tmp.write("\n# ---- Annotations without notes ----\n\n")
+                    marker = True
+                tmp.write(line + "\n")
+
+            # Replace annotations with the updated version
+            tmp.flush()
+            shutil.move(tmp.name, fname)
+
+    def search_config(self, config: str = None, arch: str = None, flavour: str = None) -> dict:
+        """Return config value of a specific config option or architecture"""
+        if flavour is None:
+            flavour = "generic"
+        flavour = f"{arch}-{flavour}"
+        if flavour in self.flavour_dep:
+            generic = self.flavour_dep[flavour]
+        else:
+            generic = flavour
+        if config is None and arch is None:
+            # Get all config options for all architectures
+            return self.config
+        if config is None and arch is not None:
+            # Get config options of a specific architecture
+            ret = {}
+            for c, val in self.config.items():
+                if "policy" not in val:
+                    continue
+                if flavour in val["policy"]:
+                    ret[c] = val["policy"][flavour]
+                elif generic != flavour and generic in val["policy"]:
+                    ret[c] = val["policy"][generic]
+                elif arch in val["policy"]:
+                    ret[c] = val["policy"][arch]
+            return ret
+        if config is not None and arch is None:
+            # Get a specific config option for all architectures
+            return self.config[config] if config in self.config else None
+        if config is not None and arch is not None:
+            # Get a specific config option for a specific architecture
+            if config in self.config:
+                if "policy" in self.config[config]:
+                    if flavour in self.config[config]["policy"]:
+                        return {config: self.config[config]["policy"][flavour]}
+                    if generic != flavour and generic in self.config[config]["policy"]:
+                        return {config: self.config[config]["policy"][generic]}
+                    if arch in self.config[config]["policy"]:
+                        return {config: self.config[config]["policy"][arch]}
+        return None
+
+    @staticmethod
+    def to_config(data: dict) -> str:
+        """Convert annotations data to .config format"""
+        s = ""
+        for c in data:
+            v = data[c]
+            if v == "n":
+                s += f"# {c} is not set\n"
+            elif v == "-":
+                pass
+            else:
+                s += f"{c}={v}\n"
+        return s.rstrip()
--- linux-ein-5.4.0.orig/debian/scripts/misc/kconfig/run.py
+++ linux-ein-5.4.0/debian/scripts/misc/kconfig/run.py
@@ -0,0 +1,370 @@
+# -*- mode: python -*-
+# Manage Ubuntu kernel .config and annotations
+# Copyright © 2022 Canonical Ltd.
+
+import sys
+import os
+import argparse
+import json
+from signal import signal, SIGPIPE, SIG_DFL
+
+try:
+    from argcomplete import autocomplete
+except ModuleNotFoundError:
+    # Allow to run this program also when argcomplete is not available
+    def autocomplete(_unused):
+        pass
+
+
+from kconfig.annotations import Annotation, KConfig  # noqa: E402 Import not at top of file
+from kconfig.utils import autodetect_annotations, arg_fail  # noqa: E402 Import not at top of file
+from kconfig.version import VERSION, ANNOTATIONS_FORMAT_VERSION  # noqa: E402 Import not at top of file
+
+
+SKIP_CONFIGS = (
+    # CONFIG_VERSION_SIGNATURE is dynamically set during the build
+    "CONFIG_VERSION_SIGNATURE",
+    # Allow to use a different versions of toolchain tools
+    "CONFIG_GCC_VERSION",
+    "CONFIG_CC_VERSION_TEXT",
+    "CONFIG_AS_VERSION",
+    "CONFIG_LD_VERSION",
+    "CONFIG_LLD_VERSION",
+    "CONFIG_CLANG_VERSION",
+    "CONFIG_PAHOLE_VERSION",
+    "CONFIG_RUSTC_VERSION_TEXT",
+    "CONFIG_BINDGEN_VERSION_TEXT",
+)
+
+
+def make_parser():
+    parser = argparse.ArgumentParser(
+        description="Manage Ubuntu kernel .config and annotations",
+    )
+    parser.add_argument("--version", "-v", action="version", version=f"%(prog)s {VERSION}")
+
+    parser.add_argument(
+        "--file",
+        "-f",
+        action="store",
+        help="Pass annotations or .config file to be parsed",
+    )
+    parser.add_argument("--arch", "-a", action="store", help="Select architecture")
+    parser.add_argument("--flavour", "-l", action="store", help='Select flavour (default is "generic")')
+    parser.add_argument("--config", "-c", action="store", help="Select a specific config option")
+    parser.add_argument("--query", "-q", action="store_true", help="Query annotations")
+    parser.add_argument(
+        "--note",
+        "-n",
+        action="store",
+        help="Write a specific note to a config option in annotations",
+    )
+    parser.add_argument(
+        "--autocomplete",
+        action="store_true",
+        help="Enable config bash autocomplete: `source <(annotations --autocomplete)`",
+    )
+    parser.add_argument(
+        "--source",
+        "-t",
+        action="store_true",
+        help="Jump to a config definition in the kernel source code",
+    )
+    parser.add_argument(
+        "--no-include",
+        action="store_true",
+        help="Do not process included annotations (stop at the main file)",
+    )
+    parser.add_argument(
+        "--json",
+        action="store_true",
+        help="Try to parse annotations file in pure JSON format",
+    )
+
+    ga = parser.add_argument_group(title="Action").add_mutually_exclusive_group(required=False)
+    ga.add_argument(
+        "--write",
+        "-w",
+        action="store",
+        metavar="VALUE",
+        dest="value",
+        help="Set a specific config value in annotations (use 'null' to remove)",
+    )
+    ga.add_argument(
+        "--export",
+        "-e",
+        action="store_true",
+        help="Convert annotations to .config format",
+    )
+    ga.add_argument(
+        "--import",
+        "-i",
+        action="store",
+        metavar="FILE",
+        dest="import_file",
+        help="Import a full .config for a specific arch and flavour into annotations",
+    )
+    ga.add_argument(
+        "--update",
+        "-u",
+        action="store",
+        metavar="FILE",
+        dest="update_file",
+        help="Import a partial .config into annotations (only resync configs specified in FILE)",
+    )
+    ga.add_argument(
+        "--check",
+        "-k",
+        action="store",
+        metavar="FILE",
+        dest="check_file",
+        help="Validate kernel .config with annotations",
+    )
+    return parser
+
+
+_ARGPARSER = make_parser()
+
+
+def export_result(data):
+    # Dump metadata / attributes first
+    out = '{\n  "attributes": {\n'
+    for key, value in sorted(data["attributes"].items()):
+        out += f'     "{key}": {json.dumps(value)},\n'
+    out = out.rstrip(",\n")
+    out += "\n  },"
+    print(out)
+
+    configs_with_note = {key: value for key, value in data["config"].items() if "note" in value}
+    configs_without_note = {key: value for key, value in data["config"].items() if "note" not in value}
+
+    # Dump configs, sorted alphabetically, showing items with a note first
+    out = '  "config": {\n'
+    for key in sorted(configs_with_note) + sorted(configs_without_note):
+        policy = data["config"][key]["policy"]
+        if "note" in data["config"][key]:
+            note = data["config"][key]["note"]
+            out += f'    "{key}": {{"policy": {json.dumps(policy)}, "note": {json.dumps(note)}}},\n'
+        else:
+            out += f'    "{key}": {{"policy": {json.dumps(policy)}}},\n'
+    out = out.rstrip(",\n")
+    out += "\n  }\n}"
+    print(out)
+
+
+def print_result(config, data):
+    if data is not None and config is not None and config not in data:
+        data = {config: data}
+    print(json.dumps(data, sort_keys=True, indent=2))
+
+
+def do_query(args):
+    if args.arch is None and args.flavour is not None:
+        arg_fail(_ARGPARSER, "error: --flavour requires --arch")
+    a = Annotation(args.file, do_include=(not args.no_include), do_json=args.json)
+    res = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour)
+    # If no arguments are specified dump the whole annotations structure
+    if args.config is None and args.arch is None and args.flavour is None:
+        res = {
+            "attributes": {
+                "arch": a.arch,
+                "flavour": a.flavour,
+                "flavour_dep": a.flavour_dep,
+                "include": a.include,
+                "_version": ANNOTATIONS_FORMAT_VERSION,
+            },
+            "config": res,
+        }
+        export_result(res)
+    else:
+        print_result(args.config, res)
+
+
+def do_autocomplete(args):
+    a = Annotation(args.file)
+    res = (c.removeprefix("CONFIG_") for c in a.search_config())
+    res_str = " ".join(res)
+    print(f'complete -W "{res_str}" annotations')
+
+
+def do_source(args):
+    if args.config is None:
+        arg_fail(_ARGPARSER, "error: --source requires --config")
+    if not os.path.exists("tags"):
+        print("tags not found in the current directory, try: `make tags`")
+        sys.exit(1)
+    os.system(f"vim -t {args.config}")
+
+
+def do_note(args):
+    if args.config is None:
+        arg_fail(_ARGPARSER, "error: --note requires --config")
+
+    # Set the note in annotations
+    a = Annotation(args.file)
+    a.set(args.config, note=args.note)
+
+    # Save back to annotations
+    a.save(args.file)
+
+    # Query and print back the value
+    a = Annotation(args.file)
+    res = a.search_config(config=args.config)
+    print_result(args.config, res)
+
+
+def do_write(args):
+    if args.config is None:
+        arg_fail(_ARGPARSER, "error: --write requires --config")
+
+    # Set the value in annotations ('null' means remove)
+    a = Annotation(args.file)
+    if args.value == "null":
+        a.remove(args.config, arch=args.arch, flavour=args.flavour)
+    else:
+        a.set(
+            args.config,
+            arch=args.arch,
+            flavour=args.flavour,
+            value=args.value,
+            note=args.note,
+        )
+
+    # Save back to annotations
+    a.save(args.file)
+
+    # Query and print back the value
+    a = Annotation(args.file)
+    res = a.search_config(config=args.config)
+    print_result(args.config, res)
+
+
+def do_export(args):
+    if args.arch is None:
+        arg_fail(_ARGPARSER, "error: --export requires --arch")
+    a = Annotation(args.file)
+    conf = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour)
+    if conf:
+        print(a.to_config(conf))
+
+
+def do_import(args):
+    if args.arch is None:
+        arg_fail(_ARGPARSER, "error: --arch is required with --import")
+    if args.flavour is None:
+        arg_fail(_ARGPARSER, "error: --flavour is required with --import")
+    if args.config is not None:
+        arg_fail(_ARGPARSER, "error: --config cannot be used with --import (try --update)")
+
+    # Merge with the current annotations
+    a = Annotation(args.file)
+    c = KConfig(args.import_file)
+    a.update(c, arch=args.arch, flavour=args.flavour)
+
+    # Save back to annotations
+    a.save(args.file)
+
+
+def do_update(args):
+    if args.arch is None:
+        arg_fail(_ARGPARSER, "error: --arch is required with --update")
+
+    # Merge with the current annotations
+    a = Annotation(args.file)
+    c = KConfig(args.update_file)
+    if args.config is None:
+        configs = list(set(c.config.keys()) - set(SKIP_CONFIGS))
+    if configs:
+        a.update(c, arch=args.arch, flavour=args.flavour, configs=configs)
+
+    # Save back to annotations
+    a.save(args.file)
+
+
+def do_check(args):
+    # Determine arch and flavour
+    if args.arch is None:
+        arg_fail(_ARGPARSER, "error: --arch is required with --check")
+
+    print(f"check-config: loading annotations from {args.file}")
+    total = good = ret = 0
+
+    # Load annotations settings
+    a = Annotation(args.file)
+    a_configs = a.search_config(arch=args.arch, flavour=args.flavour).keys()
+
+    # Parse target .config
+    c = KConfig(args.check_file)
+    c_configs = c.config.keys()
+
+    # Validate .config against annotations
+    for conf in sorted(a_configs | c_configs):
+        if conf in SKIP_CONFIGS:
+            continue
+        entry = a.search_config(config=conf, arch=args.arch, flavour=args.flavour)
+        expected = entry[conf] if entry else "-"
+        value = c.config[conf] if conf in c.config else "-"
+        if value != expected:
+            policy = a.config[conf] if conf in a.config else "undefined"
+            if "policy" in policy:
+                policy = f"policy<{policy['policy']}>"
+            print(f"check-config: {conf} changed from {expected} to {value}: {policy})")
+            ret = 1
+        else:
+            good += 1
+        total += 1
+
+    num = total - good
+    if ret:
+        if os.path.exists(".git"):
+            print(f"check-config: {num} config options have been changed, review them with `git diff`")
+        else:
+            print(f"check-config: {num} config options have changed")
+    else:
+        print("check-config: all good")
+    sys.exit(ret)
+
+
+def main():
+    # Prevent broken pipe errors when showing output in pipe to other tools
+    # (less for example)
+    signal(SIGPIPE, SIG_DFL)
+
+    # Main annotations program
+    autocomplete(_ARGPARSER)
+    args = _ARGPARSER.parse_args()
+
+    if args.file is None:
+        args.file = autodetect_annotations()
+        if args.file is None:
+            arg_fail(
+                _ARGPARSER,
+                "error: could not determine DEBDIR, try using: --file/-f",
+                show_usage=False,
+            )
+
+    if args.config and not args.config.startswith("CONFIG_"):
+        args.config = "CONFIG_" + args.config
+
+    if args.value:
+        do_write(args)
+    elif args.note:
+        do_note(args)
+    elif args.export:
+        do_export(args)
+    elif args.import_file:
+        do_import(args)
+    elif args.update_file:
+        do_update(args)
+    elif args.check_file:
+        do_check(args)
+    elif args.autocomplete:
+        do_autocomplete(args)
+    elif args.source:
+        do_source(args)
+    else:
+        do_query(args)
+
+
+if __name__ == "__main__":
+    main()
--- linux-ein-5.4.0.orig/debian/scripts/misc/kconfig/utils.py
+++ linux-ein-5.4.0/debian/scripts/misc/kconfig/utils.py
@@ -0,0 +1,20 @@
+# -*- mode: python -*-
+# Misc helpers for Kconfig and annotations
+# Copyright © 2023 Canonical Ltd.
+
+import sys
+
+
+def autodetect_annotations():
+    try:
+        with open("debian/debian.env", "rt", encoding="utf-8") as fd:
+            return fd.read().rstrip().split("=")[1] + "/config/annotations"
+    except (FileNotFoundError, IndexError):
+        return None
+
+
+def arg_fail(parser, message, show_usage=True):
+    print(message)
+    if show_usage:
+        parser.print_usage()
+    sys.exit(1)
--- linux-ein-5.4.0.orig/debian/scripts/misc/kconfig/version.py
+++ linux-ein-5.4.0/debian/scripts/misc/kconfig/version.py
@@ -0,0 +1,10 @@
+# -*- mode: python -*-
+# version of annotations module
+# Copyright © 2022 Canonical Ltd.
+
+VERSION = "0.1"
+
+ANNOTATIONS_FORMAT_VERSION = 5
+
+if __name__ == "__main__":
+    print(VERSION)
--- linux-ein-5.4.0.orig/debian/scripts/misc/kernel-wedge-arch.pl
+++ linux-ein-5.4.0/debian/scripts/misc/kernel-wedge-arch.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+#
+# kernel-wedge-arch.pl -- select only specifiers for the supplied arch.
+#
+use strict;
+
+require Dpkg::Control;
+require Dpkg::Deps;
+
+my $fh = \*STDIN;
+
+my @entries;
+
+my $wanted = $ARGV[0];
+
+my $entry;
+while (!eof($fh)) {
+	$entry = Dpkg::Control->new();
+	$entry->parse($fh, '???');
+
+	if ($entry->{'Architecture'} eq $wanted) {
+		print("\n" . $entry);
+	}
+}
+
+close($fh);
--- linux-ein-5.4.0.orig/debian/scripts/misc/kernelconfig
+++ linux-ein-5.4.0/debian/scripts/misc/kernelconfig
@@ -0,0 +1,178 @@
+#!/bin/bash -u
+#
+# Manage kernel config annotations
+#
+# Supported environment variales:
+#   conc_level  : Concurrency level for upstream make (-jX)
+#   skip_checks : Skip config checks if set to 'true'
+#   gcc         : Default gcc to use (mandatory)
+#
+
+function cleanup()
+{
+	rm -rf build "${TMP_DIR}"
+}
+
+# We have to be in the top level Ubuntu kernel source directory
+if ! [ -e debian/debian.env ] ; then
+	echo "ERROR: This is not an Ubuntu kernel source directory" >&2
+	exit 1
+fi
+
+if [ -z "${gcc:-}" ] ; then
+	gcc=gcc
+fi
+
+if [ ${#} -ne 1 ] ; then
+	echo "Usage: $0 updateconfigs|defaultconfigs|genconfigs|editconfigs"
+	exit 2
+fi
+
+mode=${1}
+
+case "${mode}" in
+	updateconfigs)  target="syncconfig" ;;
+	defaultconfigs) target="olddefconfig" ;;
+	genconfigs)     target="oldconfig" ;;
+	editconfigs)    ;;  # Target is set later based on user input
+	*) echo "ERROR: Invalid mode: ${1}" >&2
+	   exit 1 ;;
+esac
+
+. debian/debian.env
+
+annotations_file=${DEBIAN}/config/annotations
+warning_partial=()
+
+TMP_DIR=$(mktemp -d)
+trap cleanup EXIT
+
+# Use annotations to generate configs
+FLAVOURS=$(sed -ne 's/^# FLAVOUR: //p' "${annotations_file}")
+
+for arch_flavour in ${FLAVOURS} ; do
+	arch=${arch_flavour%%-*}
+	flavour=${arch_flavour#*-}
+	tmp_conf_file=${TMP_DIR}/${arch}-config.flavour.${flavour}
+
+	# Map debian archs to kernel archs
+	case "${arch}" in
+		amd64)   kern_arch="x86_64" ;;
+		arm64)   kern_arch="arm64" ;;
+		armhf)   kern_arch="arm" ;;
+		i386)    kern_arch="i386" ;;
+		ppc64el) kern_arch="powerpc" ;;
+		riscv64) kern_arch="riscv" ;;
+		s390x)   kern_arch="s390" ;;
+		*)       echo "WARNING: Unsupported architecture: ${arch}"
+		         warning_partial+=("${arch}")
+		         continue ;;
+	esac
+
+	# Determine cross toolchain to use for Kconfig compiler tests
+	cross_compile="$(dpkg-architecture -qDEB_HOST_GNU_TYPE -a"${arch}" 2>/dev/null)-"
+
+	# Arch-specific compiler, if any
+	arch_gcc=$(cat <<EOF | make -s -f - all
+include ${DEBIAN}/rules.d/${arch}.mk
+all:
+	@echo \$(if \$(gcc),\$(gcc),${gcc})
+EOF
+			)
+	gcc_path=$(which "${cross_compile}${arch_gcc}" || true)
+	if [ -z "${gcc_path}" ] ; then
+		echo "WARNING: ${cross_compile}${arch_gcc} not installed"
+		warning_partial+=("${arch}")
+		continue
+	fi
+
+	if [ "${mode}" = "editconfigs" ] ; then
+		while true ; do
+			echo -n "Do you want to edit configs for ${arch}-${flavour}? [Y/n] "
+			read -r choice
+			case "${choice,,}" in
+				y|"") target="menuconfig" ; break ;;
+				n)    target="syncconfig" ; break ;;
+			esac
+		done
+	fi
+
+	rm -rf build
+	mkdir build
+
+	# Generate .config from annotations
+	python3 debian/scripts/misc/annotations -f "${annotations_file}" \
+			--arch "${arch}" --flavour "${flavour}" --export > build/.config
+
+	# Environment variables for 'make *config'
+	env=(ARCH="${kern_arch}"
+		 DEB_ARCH="${arch}"
+		 CROSS_COMPILE="${cross_compile}"
+		 CC="${gcc_path}")
+
+	# Concurrency level
+	if [ -n "${conc_level:-}" ] ; then
+		env+=("${conc_level}")
+	fi
+
+	# Call config target
+	echo
+	echo "* Run ${target} on ${arch}/${flavour} ..."
+	${kmake} O=build "${env[@]}" "${target}"
+
+	# Move config for further processing
+	mv build/.config "${tmp_conf_file}"
+done
+
+rc=0
+
+if [ "${skip_checks:-}" = "true" ] ; then
+	echo
+	echo "Skipping config-check (skip_checks=${skip_checks}) ..."
+else
+	echo
+	echo "Running config-check for all configurations ..."
+	fail=0
+	for arch_flavour in ${FLAVOURS} ; do
+		arch=${arch_flavour%%-*}
+		flavour=${arch_flavour#*-}
+		tmp_conf_file=${TMP_DIR}/${arch}-config.flavour.${flavour}
+
+		echo
+		echo "* Run config-check for ${arch}-${flavour} ..."
+		python3 debian/scripts/misc/annotations -f "${annotations_file}" \
+				--arch "${arch}" --flavour "${flavour}" --check "${tmp_conf_file}" || \
+			fail=$((fail + 1))
+	done
+
+	if [ ${fail} -gt 0 ] ; then
+		rc=1
+		echo "ERROR: ${fail} config-check failures detected" >&2
+	fi
+fi
+
+if [ ${#warning_partial[@]} -gt 0 ] ; then
+	rc=1
+	echo "ERROR: Config operation not applied to all architectures (skipped ${warning_partial[*]})" >&2
+fi
+
+# Recreate the annotations file
+if [ "${mode}" = "genconfigs" ] ; then
+	rm -rf CONFIGS
+	mv "${TMP_DIR}" CONFIGS
+else
+	echo
+	echo "Importing all configurations ..."
+	echo
+	for arch_flavour in ${FLAVOURS} ; do
+		arch=${arch_flavour%%-*}
+		flavour=${arch_flavour#*-}
+		tmp_conf_file=${TMP_DIR}/${arch}-config.flavour.${flavour}
+
+		echo "* Import configs for ${arch}-${flavour} ..."
+		python3 debian/scripts/misc/annotations -f "${annotations_file}" \
+				--arch "${arch}" --flavour "${flavour}" --import "${tmp_conf_file}"
+	done
+fi
+
+exit "${rc}"
--- linux-ein-5.4.0.orig/debian/scripts/misc/migrate-annotations
+++ linux-ein-5.4.0/debian/scripts/misc/migrate-annotations
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+. debian/debian.env
+
+# 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
+
+. ${DEBIAN}/etc/kernelconfig
+
+ARCH=$(echo $archs | tr " " "\n" | sort -u)
+FLAVOUR=$(for arch in ${ARCH}; do
+	flavours=$(sed -ne 's/^flavours\s*=\s*\(.*\)$/\1/p' ${DEBIAN}/rules.d/${arch}.mk)
+	for flavour in ${flavours}; do
+		echo ${arch}-${flavour}
+	done
+done | tr " " "\n" | sort -u)
+
+while read line; do
+	(echo $line | grep -q '^#') || break
+done
+
+cat << EOF
+# Menu: HEADER
+# FORMAT: 4
+# ARCH: $(echo ${ARCH})
+# FLAVOUR: $(echo ${FLAVOUR})
+
+EOF
+
+while read line; do
+	echo ${line}
+done
--- linux-ein-5.4.0.orig/debian/scripts/misc/old-kernelconfig
+++ linux-ein-5.4.0/debian/scripts/misc/old-kernelconfig
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+. debian/debian.env
+
+# Script to merge all configs and run 'make syncconfig' 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) [do_enforce_all]"}
+do_enforce_all=${2:-0}
+yes=0
+case "$mode" in
+    update*configs)  mode='syncconfig' ;;
+    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
+
+warning_partial=
+
+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"		;;
+		riscv64)	kernarch="riscv"	;;
+		*)		kernarch="$arch"	;;
+	esac
+
+	# Determine cross toolchain to use for Kconfig compiler tests
+	cross_compile=""
+	deb_build_arch=$(dpkg-architecture -qDEB_BUILD_ARCH -a$arch 2>/dev/null)
+	deb_host_arch=$(dpkg-architecture -qDEB_HOST_ARCH -a$arch 2>/dev/null)
+	[ $deb_build_arch != $deb_host_arch ] && cross_compile="$(dpkg-architecture -qDEB_HOST_GNU_TYPE -a$arch 2>/dev/null)-"
+
+	# Environment variables for 'make *config'. We omit CROSS_COMPILE
+	# for i386 since it is no longer supported after 19.04, however
+	# we maintain the configs for hwe.
+	modify_config=true
+	env="ARCH=$kernarch DEB_ARCH=$arch"
+	compiler_path=$(which "${cross_compile}gcc" || true)
+	if [ "$compiler_path" != '' ]; then
+		env="$env CROSS_COMPILE=$cross_compile"
+	else
+		echo "WARNING: ${cross_compile}gcc not installed"
+		modify_config=
+		warning_partial="$warning_partial $arch"
+	fi
+
+	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
+			if [ "$modify_config" ]; then
+				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 $env menuconfig
+							break ;;
+						n* | N* )
+							# 'syncconfig' prevents
+							# errors for '-' options set
+							# in common config fragments
+							make O=`pwd`/build $env syncconfig
+							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 $env "$mode"
+					else
+						make O=`pwd`/build $env "$mode"
+					fi ;;
+				esac
+			fi
+			cat build/.config > $archconfdir/$config
+			[ "$modify_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"
+			[ ! -f "$fullconf" ] && continue
+			"$bindir/../config-check" "$fullconf" "$arch" "$flavour" "$confdir" "0" "$do_enforce_all" || let "fail=$fail+1"
+		fi
+	done
+done
+
+if [ "$fail" != 0 ]; then
+	echo ""
+	echo "*** ERROR: $fail config-check failures detected"
+	echo ""
+fi
+
+rm -rf build
+
+if [ "$warning_partial" ]; then
+	echo ""
+	echo "WARNING: configuration operation applied only to a subset of architectures (skipped$warning_partial)" 1>&2
+	echo ""
+fi
--- linux-ein-5.4.0.orig/debian/scripts/misc/retag
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/splitconfig.pl
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/misc/tristate.sh
+++ linux-ein-5.4.0/debian/scripts/misc/tristate.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#
+# Find config variables that might be able to transition from =y to =m
+#
+# Example: debian/scripts/misc/tristate.sh debian.master/config/config.common.ubuntu
+#
+
+KC=Kconfig.tmp
+rm -f ${KC}
+find .|grep Kconfig | while read f
+do
+	cat $f >> ${KC}
+done
+
+grep =y $1 | sed -e 's/CONFIG_//' -e 's/=y//' | while read c
+do
+	cat <<EOF > tristate.awk
+BEGIN { tristate=0; }
+/^config ${c}\$/ { tristate=1; next; }
+/tristate/ { if (tristate == 1) printf("CONFIG_%s=m\n","${c}"); next; }
+{ if (tristate == 1) exit; }
+EOF
+
+	gawk -f tristate.awk ${KC}
+done
--- linux-ein-5.4.0.orig/debian/scripts/misc/update-aufs.sh
+++ linux-ein-5.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/aufs5-standalone.git ${AUFS}
+	(cd ${AUFS}; git checkout -b aufs5.x-rcN remotes/origin/aufs5.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} aufs5-kbuild.patch"
+PATCHES="${PATCHES} aufs5-base.patch"
+PATCHES="${PATCHES} aufs5-mmap.patch"
+PATCHES="${PATCHES} aufs5-standalone.patch"
+PATCHES="${PATCHES} aufs5-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-ein-5.4.0.orig/debian/scripts/module-inclusion
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/retpoline-extract
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/retpoline-extract-one
+++ linux-ein-5.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-ein-5.4.0.orig/debian/scripts/sub-flavour
+++ linux-ein-5.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-ein-5.4.0.orig/debian/snapcraft.mk
+++ linux-ein-5.4.0/debian/snapcraft.mk
@@ -0,0 +1,15 @@
+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:
+	if [ -e debian/config/config.common.ubuntu ]; then \
+	    cat debian.$(branch)/config/config.common.ubuntu debian.$(branch)/config/$(arch)/config.common.$(arch) debian.$(branch)/config/$(arch)/config.flavour.$(flavour) >.config; \
+	else \
+	    python3 debian/scripts/misc/annotations --export --arch $(arch) --flavour $(flavour) >.config; \
+	fi
--- linux-ein-5.4.0.orig/debian/source/format
+++ linux-ein-5.4.0/debian/source/format
@@ -0,0 +1 @@
+1.0
--- linux-ein-5.4.0.orig/debian/source/options
+++ linux-ein-5.4.0/debian/source/options
@@ -0,0 +1,8 @@
+# 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.
+## autoreconstruct -- end
+
+# force "dpkg-source -I -i" behavior
+diff-ignore
+tar-ignore
--- linux-ein-5.4.0.orig/debian/stamps/keep-dir
+++ linux-ein-5.4.0/debian/stamps/keep-dir
@@ -0,0 +1 @@
+Place holder
--- linux-ein-5.4.0.orig/debian/templates/extra.postinst.in
+++ linux-ein-5.4.0/debian/templates/extra.postinst.in
@@ -0,0 +1,20 @@
+#!/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
+    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-ein-5.4.0.orig/debian/templates/extra.postrm.in
+++ linux-ein-5.4.0/debian/templates/extra.postrm.in
@@ -0,0 +1,31 @@
+#!/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.
+#    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-ein-5.4.0.orig/debian/templates/headers.postinst.in
+++ linux-ein-5.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-ein-5.4.0.orig/debian/templates/image.postinst.in
+++ linux-ein-5.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-ein-5.4.0.orig/debian/templates/image.postrm.in
+++ linux-ein-5.4.0/debian/templates/image.postrm.in
@@ -0,0 +1,40 @@
+#!/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
+    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-ein-5.4.0.orig/debian/templates/image.preinst.in
+++ linux-ein-5.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-ein-5.4.0.orig/debian/templates/image.prerm.in
+++ linux-ein-5.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-ein-5.4.0.orig/debian/tests-build/README
+++ linux-ein-5.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-ein-5.4.0.orig/debian/tests-build/check-aliases
+++ linux-ein-5.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-ein-5.4.0.orig/debian/tests/control
+++ linux-ein-5.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 armhf i386], gdb, git, python2 | python, bzr
+Restrictions: allow-stderr, isolation-machine, breaks-testbed, skippable
--- linux-ein-5.4.0.orig/debian/tests/rebuild
+++ linux-ein-5.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*/*|linux-oem*/*|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-ein-5.4.0.orig/debian/tests/ubuntu-regression-suite
+++ linux-ein-5.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-ein-5.4.0.orig/debian/tools/generic
+++ linux-ein-5.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-ein-5.4.0.orig/debian/vbox-modules.ignore
+++ linux-ein-5.4.0/debian/vbox-modules.ignore
@@ -0,0 +1,2 @@
+vboxguest
+vboxsf
--- linux-ein-5.4.0.orig/debian/wireguard-modules.ignore
+++ linux-ein-5.4.0/debian/wireguard-modules.ignore
@@ -0,0 +1 @@
+wireguard
--- linux-ein-5.4.0.orig/debian/zfs-modules.ignore
+++ linux-ein-5.4.0/debian/zfs-modules.ignore
@@ -0,0 +1,10 @@
+icp
+spl
+splat
+zavl
+zcommon
+zfs
+zlua
+znvpair
+zpios
+zunicode
--- linux-ein-5.4.0.orig/drivers/Kconfig
+++ linux-ein-5.4.0/drivers/Kconfig
@@ -228,4 +228,5 @@
 
 source "drivers/counter/Kconfig"
 
+source "drivers/mxc/Kconfig"
 endmenu
--- linux-ein-5.4.0.orig/drivers/Makefile
+++ linux-ein-5.4.0/drivers/Makefile
@@ -58,14 +58,9 @@
 # iommu/ comes before gpu as gpu are using iommu controllers
 obj-y				+= iommu/
 
-# gpu/ comes after char for AGP vs DRM startup and after iommu
-obj-y				+= gpu/
 
 obj-$(CONFIG_CONNECTOR)		+= connector/
 
-# i810fb and intelfb depend on char/agp/
-obj-$(CONFIG_FB_I810)           += video/fbdev/i810/
-obj-$(CONFIG_FB_INTEL)          += video/fbdev/intelfb/
 
 obj-$(CONFIG_PARPORT)		+= parport/
 obj-$(CONFIG_NVM)		+= lightnvm/
@@ -79,6 +74,12 @@
 obj-y				+= scsi/
 obj-y				+= nvme/
 obj-$(CONFIG_ATA)		+= ata/
+
+# gpu/ comes after char for AGP vs DRM startup and after iommu
+obj-y				+= gpu/
+# i810fb and intelfb depend on char/agp/
+obj-$(CONFIG_FB_I810)           += video/fbdev/i810/
+obj-$(CONFIG_FB_INTEL)          += video/fbdev/intelfb/
 obj-$(CONFIG_TARGET_CORE)	+= target/
 obj-$(CONFIG_MTD)		+= mtd/
 obj-$(CONFIG_SPI)		+= spi/
@@ -186,3 +187,4 @@
 obj-$(CONFIG_GNSS)		+= gnss/
 obj-$(CONFIG_INTERCONNECT)	+= interconnect/
 obj-$(CONFIG_COUNTER)		+= counter/
+obj-y		 		+= mxc/
--- linux-ein-5.4.0.orig/drivers/acpi/Makefile
+++ linux-ein-5.4.0/drivers/acpi/Makefile
@@ -8,6 +8,11 @@
 #
 # ACPI Boot-Time Table Parsing
 #
+ifeq ($(CONFIG_ACPI_CUSTOM_DSDT),y)
+tables.o: $(src)/../../include/$(subst $\",,$(CONFIG_ACPI_CUSTOM_DSDT_FILE)) ;
+
+endif
+
 obj-$(CONFIG_ACPI)		+= tables.o
 obj-$(CONFIG_X86)		+= blacklist.o
 
@@ -48,7 +53,7 @@
 acpi-$(CONFIG_ARM_AMBA)	+= acpi_amba.o
 acpi-y				+= power.o
 acpi-y				+= event.o
-acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o
+acpi-y				+= evged.o
 acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_amba.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_amba.c
@@ -76,6 +76,7 @@
 		case IORESOURCE_MEM:
 			if (!address_found) {
 				dev->res = *rentry->res;
+				dev->res.name = dev_name(&dev->dev);
 				address_found = true;
 			}
 			break;
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_configfs.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_configfs.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/configfs.h>
 #include <linux/acpi.h>
+#include <linux/security.h>
 
 #include "acpica/accommon.h"
 #include "acpica/actables.h"
@@ -28,7 +29,10 @@
 {
 	const struct acpi_table_header *header = data;
 	struct acpi_table *table;
-	int ret;
+	int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
+
+	if (ret)
+		return ret;
 
 	table = container_of(cfg, struct acpi_table, cfg);
 
@@ -263,7 +267,12 @@
 
 	acpi_table_group = configfs_register_default_group(root, "table",
 							   &acpi_tables_type);
-	return PTR_ERR_OR_ZERO(acpi_table_group);
+	if (IS_ERR(acpi_table_group)) {
+		configfs_unregister_subsystem(&acpi_configfs);
+		return PTR_ERR(acpi_table_group);
+	}
+
+	return 0;
 }
 module_init(acpi_configfs_init);
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_dbg.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_dbg.c
@@ -749,6 +749,9 @@
 {
 	int ret;
 
+	if (acpi_disabled)
+		return -ENODEV;
+
 	/* Initialize AML IO interface */
 	mutex_init(&acpi_aml_io.lock);
 	init_waitqueue_head(&acpi_aml_io.wait);
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_extlog.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_extlog.c
@@ -12,6 +12,7 @@
 #include <linux/ratelimit.h>
 #include <linux/edac.h>
 #include <linux/ras.h>
+#include <acpi/ghes.h>
 #include <asm/cpu.h>
 #include <asm/mce.h>
 
@@ -140,8 +141,8 @@
 	int	cpu = mce->extcpu;
 	struct acpi_hest_generic_status *estatus, *tmp;
 	struct acpi_hest_generic_data *gdata;
-	const guid_t *fru_id = &guid_null;
-	char *fru_text = "";
+	const guid_t *fru_id;
+	char *fru_text;
 	guid_t *sec_type;
 	static u32 err_seq;
 
@@ -162,17 +163,23 @@
 
 	/* log event via trace */
 	err_seq++;
-	gdata = (struct acpi_hest_generic_data *)(tmp + 1);
-	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
-		fru_id = (guid_t *)gdata->fru_id;
-	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
-		fru_text = gdata->fru_text;
-	sec_type = (guid_t *)gdata->section_type;
-	if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
-		struct cper_sec_mem_err *mem = (void *)(gdata + 1);
-		if (gdata->error_data_length >= sizeof(*mem))
-			trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
-					       (u8)gdata->error_severity);
+	apei_estatus_for_each_section(tmp, gdata) {
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+			fru_id = (guid_t *)gdata->fru_id;
+		else
+			fru_id = &guid_null;
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+			fru_text = gdata->fru_text;
+		else
+			fru_text = "";
+		sec_type = (guid_t *)gdata->section_type;
+		if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
+			struct cper_sec_mem_err *mem = (void *)(gdata + 1);
+
+			if (gdata->error_data_length >= sizeof(*mem))
+				trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
+						       (u8)gdata->error_severity);
+		}
 	}
 
 out:
@@ -223,9 +230,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 (edac_get_report_status() == EDAC_REPORTING_FORCE) {
@@ -309,9 +316,10 @@
 {
 	edac_set_report_status(old_edac_report_status);
 	mce_unregister_decode_chain(&extlog_mce_dec);
-	((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
-	if (extlog_l1_addr)
+	if (extlog_l1_addr) {
+		((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
 		acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
+	}
 	if (elog_addr)
 		acpi_os_unmap_iomem(elog_addr, elog_size);
 	release_mem_region(elog_base, elog_size);
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_lpit.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_lpit.c
@@ -98,7 +98,7 @@
 				 struct acpi_lpit_native *lpit_native)
 {
 	info->frequency = lpit_native->counter_frequency ?
-				lpit_native->counter_frequency : tsc_khz * 1000;
+				lpit_native->counter_frequency : mul_u32_u32(tsc_khz, 1000U);
 	if (!info->frequency)
 		info->frequency = 1;
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_lpss.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_lpss.c
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
+#include <linux/dmi.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
@@ -400,6 +401,9 @@
 	if (!lpss_clk_dev)
 		lpt_register_clock_device();
 
+	if (IS_ERR(lpss_clk_dev))
+		return PTR_ERR(lpss_clk_dev);
+
 	clk_data = platform_get_drvdata(lpss_clk_dev);
 	if (!clk_data)
 		return -ENODEV;
@@ -463,6 +467,18 @@
 	const char *consumer_hid;
 	const char *consumer_uid;
 	u32 flags;
+	const struct dmi_system_id *dep_missing_ids;
+};
+
+/* Please keep this list sorted alphabetically by vendor and model */
+static const struct dmi_system_id i2c1_dep_missing_dmi_ids[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
+		},
+	},
+	{}
 };
 
 /*
@@ -473,9 +489,17 @@
  * the supplier is not enumerated until after the consumer is probed.
  */
 static const struct lpss_device_links lpss_device_links[] = {
+	/* CHT External sdcard slot controller depends on PMIC I2C ctrl */
 	{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
+	/* CHT iGPU depends on PMIC I2C controller */
 	{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+	/* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */
+	{"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME,
+	 i2c1_dep_missing_dmi_ids},
+	/* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */
 	{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+	/* BYT iGPU depends on PMIC I2C controller (UID 7 on non CR) */
+	{"80860F41", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
 };
 
 static bool hid_uid_match(struct acpi_device *adev,
@@ -570,7 +594,8 @@
 	if (!dev2)
 		return;
 
-	if (acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
+	if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
+	    || acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
 		device_link_add(dev2, dev1, link->flags);
 
 	put_device(dev2);
@@ -585,7 +610,8 @@
 	if (!dev2)
 		return;
 
-	if (acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
+	if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
+	    || acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
 		device_link_add(dev1, dev2, link->flags);
 
 	put_device(dev2);
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_pad.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_pad.c
@@ -88,7 +88,7 @@
 	cpumask_var_t tmp;
 	int cpu;
 	unsigned long min_weight = -1;
-	unsigned long uninitialized_var(preferred_cpu);
+	unsigned long preferred_cpu;
 
 	if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
 		return;
@@ -262,7 +262,7 @@
 	return ps_tsk_num;
 }
 
-static ssize_t acpi_pad_rrtime_store(struct device *dev,
+static ssize_t rrtime_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned long num;
@@ -276,16 +276,14 @@
 	return count;
 }
 
-static ssize_t acpi_pad_rrtime_show(struct device *dev,
+static ssize_t rrtime_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	return scnprintf(buf, PAGE_SIZE, "%d\n", round_robin_time);
 }
-static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR,
-	acpi_pad_rrtime_show,
-	acpi_pad_rrtime_store);
+static DEVICE_ATTR_RW(rrtime);
 
-static ssize_t acpi_pad_idlepct_store(struct device *dev,
+static ssize_t idlepct_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned long num;
@@ -299,16 +297,14 @@
 	return count;
 }
 
-static ssize_t acpi_pad_idlepct_show(struct device *dev,
+static ssize_t idlepct_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	return scnprintf(buf, PAGE_SIZE, "%d\n", idle_pct);
 }
-static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR,
-	acpi_pad_idlepct_show,
-	acpi_pad_idlepct_store);
+static DEVICE_ATTR_RW(idlepct);
 
-static ssize_t acpi_pad_idlecpus_store(struct device *dev,
+static ssize_t idlecpus_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned long num;
@@ -320,16 +316,14 @@
 	return count;
 }
 
-static ssize_t acpi_pad_idlecpus_show(struct device *dev,
+static ssize_t idlecpus_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	return cpumap_print_to_pagebuf(false, buf,
 				       to_cpumask(pad_busy_cpus_bits));
 }
 
-static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR,
-	acpi_pad_idlecpus_show,
-	acpi_pad_idlecpus_store);
+static DEVICE_ATTR_RW(idlecpus);
 
 static int acpi_pad_add_sysfs(struct acpi_device *device)
 {
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_platform.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_platform.c
@@ -31,6 +31,44 @@
 	{"", 0},
 };
 
+static struct platform_device *acpi_platform_device_find_by_companion(struct acpi_device *adev)
+{
+	struct device *dev;
+
+	dev = bus_find_device_by_acpi_dev(&platform_bus_type, adev);
+	return dev ? to_platform_device(dev) : NULL;
+}
+
+static int acpi_platform_device_remove_notify(struct notifier_block *nb,
+					      unsigned long value, void *arg)
+{
+	struct acpi_device *adev = arg;
+	struct platform_device *pdev;
+
+	switch (value) {
+	case ACPI_RECONFIG_DEVICE_ADD:
+		/* Nothing to do here */
+		break;
+	case ACPI_RECONFIG_DEVICE_REMOVE:
+		if (!acpi_device_enumerated(adev))
+			break;
+
+		pdev = acpi_platform_device_find_by_companion(adev);
+		if (!pdev)
+			break;
+
+		platform_device_unregister(pdev);
+		put_device(&pdev->dev);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_platform_notifier = {
+	.notifier_call = acpi_platform_device_remove_notify,
+};
+
 static void acpi_platform_fill_resource(struct acpi_device *adev,
 	const struct resource *src, struct resource *dest)
 {
@@ -130,3 +168,8 @@
 	return pdev;
 }
 EXPORT_SYMBOL_GPL(acpi_create_platform_device);
+
+void __init acpi_platform_init(void)
+{
+	acpi_reconfig_notifier_register(&acpi_platform_notifier);
+}
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_pnp.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_pnp.c
@@ -317,6 +317,9 @@
 {
 	int i;
 
+	if (strlen(idstr) != strlen(list_id))
+		return false;
+
 	if (memcmp(idstr, list_id, 3))
 		return false;
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_tad.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_tad.c
@@ -237,7 +237,7 @@
 		       rt.tz, rt.daylight);
 }
 
-static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store);
+static DEVICE_ATTR_RW(time);
 
 static struct attribute *acpi_tad_time_attrs[] = {
 	&dev_attr_time.attr,
@@ -446,7 +446,7 @@
 	return acpi_tad_alarm_read(dev, buf, ACPI_TAD_AC_TIMER);
 }
 
-static DEVICE_ATTR(ac_alarm, S_IRUSR | S_IWUSR, ac_alarm_show, ac_alarm_store);
+static DEVICE_ATTR_RW(ac_alarm);
 
 static ssize_t ac_policy_store(struct device *dev, struct device_attribute *attr,
 			       const char *buf, size_t count)
@@ -462,7 +462,7 @@
 	return acpi_tad_policy_read(dev, buf, ACPI_TAD_AC_TIMER);
 }
 
-static DEVICE_ATTR(ac_policy, S_IRUSR | S_IWUSR, ac_policy_show, ac_policy_store);
+static DEVICE_ATTR_RW(ac_policy);
 
 static ssize_t ac_status_store(struct device *dev, struct device_attribute *attr,
 			       const char *buf, size_t count)
@@ -478,7 +478,7 @@
 	return acpi_tad_status_read(dev, buf, ACPI_TAD_AC_TIMER);
 }
 
-static DEVICE_ATTR(ac_status, S_IRUSR | S_IWUSR, ac_status_show, ac_status_store);
+static DEVICE_ATTR_RW(ac_status);
 
 static struct attribute *acpi_tad_attrs[] = {
 	&dev_attr_caps.attr,
@@ -505,7 +505,7 @@
 	return acpi_tad_alarm_read(dev, buf, ACPI_TAD_DC_TIMER);
 }
 
-static DEVICE_ATTR(dc_alarm, S_IRUSR | S_IWUSR, dc_alarm_show, dc_alarm_store);
+static DEVICE_ATTR_RW(dc_alarm);
 
 static ssize_t dc_policy_store(struct device *dev, struct device_attribute *attr,
 			       const char *buf, size_t count)
@@ -521,7 +521,7 @@
 	return acpi_tad_policy_read(dev, buf, ACPI_TAD_DC_TIMER);
 }
 
-static DEVICE_ATTR(dc_policy, S_IRUSR | S_IWUSR, dc_policy_show, dc_policy_store);
+static DEVICE_ATTR_RW(dc_policy);
 
 static ssize_t dc_status_store(struct device *dev, struct device_attribute *attr,
 			       const char *buf, size_t count)
@@ -537,7 +537,7 @@
 	return acpi_tad_status_read(dev, buf, ACPI_TAD_DC_TIMER);
 }
 
-static DEVICE_ATTR(dc_status, S_IRUSR | S_IWUSR, dc_status_show, dc_status_store);
+static DEVICE_ATTR_RW(dc_status);
 
 static struct attribute *acpi_tad_dc_attrs[] = {
 	&dev_attr_dc_alarm.attr,
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_video.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_video.c
@@ -498,6 +498,22 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE R830"),
 		},
 	},
+	{
+	 .callback = video_disable_backlight_sysfs_if,
+	 .ident = "Toshiba Satellite Z830",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Z830"),
+		},
+	},
+	{
+	 .callback = video_disable_backlight_sysfs_if,
+	 .ident = "Toshiba Portege Z830",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE Z830"),
+		},
+	},
 	/*
 	 * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set
 	 * but the IDs actually follow the Device ID Scheme.
@@ -543,6 +559,24 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
 		},
 	},
+	{
+	 .callback = video_set_report_key_events,
+	 .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
+	 .ident = "Dell Vostro 3350",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
+		},
+	},
+	{
+	 .callback = video_set_report_key_events,
+	 .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
+	 .ident = "COLORFUL X15 AT 23",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"),
+		},
+	},
 	/*
 	 * Some machines change the brightness themselves when a brightness
 	 * hotkey gets pressed, despite us telling them not to. In this case
@@ -1759,12 +1793,12 @@
 		return;
 	count++;
 
-	acpi_get_parent(device->dev->handle, &acpi_parent);
-
-	pdev = acpi_get_pci_dev(acpi_parent);
-	if (pdev) {
-		parent = &pdev->dev;
-		pci_dev_put(pdev);
+	if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) {
+		pdev = acpi_get_pci_dev(acpi_parent);
+		if (pdev) {
+			parent = &pdev->dev;
+			pci_dev_put(pdev);
+		}
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
--- linux-ein-5.4.0.orig/drivers/acpi/acpi_watchdog.c
+++ linux-ein-5.4.0/drivers/acpi/acpi_watchdog.c
@@ -55,12 +55,14 @@
 }
 #endif
 
+static bool acpi_no_watchdog;
+
 static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
 {
 	const struct acpi_table_wdat *wdat = NULL;
 	acpi_status status;
 
-	if (acpi_disabled)
+	if (acpi_disabled || acpi_no_watchdog)
 		return NULL;
 
 	status = acpi_get_table(ACPI_SIG_WDAT, 0,
@@ -88,6 +90,14 @@
 }
 EXPORT_SYMBOL_GPL(acpi_has_watchdog);
 
+/* ACPI watchdog can be disabled on boot command line */
+static int __init disable_acpi_watchdog(char *str)
+{
+	acpi_no_watchdog = true;
+	return 1;
+}
+__setup("acpi_no_watchdog", disable_acpi_watchdog);
+
 void __init acpi_watchdog_init(void)
 {
 	const struct acpi_wdat_entry *entries;
@@ -126,12 +136,11 @@
 		gas = &entries[i].register_region;
 
 		res.start = gas->address;
+		res.end = res.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
 		if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 			res.flags = IORESOURCE_MEM;
-			res.end = res.start + ALIGN(gas->access_width, 4) - 1;
 		} else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
 			res.flags = IORESOURCE_IO;
-			res.end = res.start + gas->access_width - 1;
 		} else {
 			pr_warn("Unsupported address space: %u\n",
 				gas->space_id);
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/Makefile
+++ linux-ein-5.4.0/drivers/acpi/acpica/Makefile
@@ -3,7 +3,7 @@
 # Makefile for ACPICA Core interpreter
 #
 
-ccflags-y			:= -Os -D_LINUX -DBUILDING_ACPICA
+ccflags-y			:= -D_LINUX -DBUILDING_ACPICA
 ccflags-$(CONFIG_ACPI_DEBUG)	+= -DACPI_DEBUG_OUTPUT
 
 # use acpi.o to put all files here into acpi.o modparam namespace
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/acglobal.h
+++ linux-ein-5.4.0/drivers/acpi/acpica/acglobal.h
@@ -220,6 +220,8 @@
     acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
 ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a);
 ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a_s0);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b_s0);
 
 /*****************************************************************************
  *
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/achware.h
+++ linux-ein-5.4.0/drivers/acpi/acpica/achware.h
@@ -101,6 +101,8 @@
 
 acpi_status acpi_hw_enable_all_wakeup_gpes(void);
 
+u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number);
+
 acpi_status
 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 				 struct acpi_gpe_block_info *gpe_block,
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/acnamesp.h
+++ linux-ein-5.4.0/drivers/acpi/acpica/acnamesp.h
@@ -256,6 +256,8 @@
 acpi_ns_build_normalized_path(struct acpi_namespace_node *node,
 			      char *full_path, u32 path_size, u8 no_trailing);
 
+void acpi_ns_normalize_pathname(char *original_path);
+
 char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node,
 				      u8 no_trailing);
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/acobject.h
+++ linux-ein-5.4.0/drivers/acpi/acpica/acobject.h
@@ -283,6 +283,7 @@
 	acpi_adr_space_handler handler;
 	struct acpi_namespace_node *node;	/* Parent device */
 	void *context;
+	acpi_mutex context_mutex;
 	acpi_adr_space_setup setup;
 	union acpi_operand_object *region_list;	/* Regions using this handler */
 	union acpi_operand_object *next;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dbinput.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dbinput.c
@@ -464,16 +464,14 @@
 		return (NULL);
 	}
 
-	/* Remove any spaces at the beginning */
+	/* Remove any spaces at the beginning, ignore blank lines */
 
-	if (*string == ' ') {
-		while (*string && (*string == ' ')) {
-			string++;
-		}
+	while (*string && isspace(*string)) {
+		string++;
+	}
 
-		if (!(*string)) {
-			return (NULL);
-		}
+	if (!(*string)) {
+		return (NULL);
 	}
 
 	switch (*string) {
@@ -551,7 +549,7 @@
 
 		/* Find end of token */
 
-		while (*string && (*string != ' ')) {
+		while (*string && !isspace(*string)) {
 			string++;
 		}
 		break;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dbnames.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dbnames.c
@@ -571,6 +571,9 @@
 		object_info =
 		    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info));
 
+		if (!object_info)
+			return (AE_NO_MEMORY);
+
 		/* Walk the namespace from the root */
 
 		(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dsfield.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dsfield.c
@@ -244,7 +244,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
@@ -518,13 +518,20 @@
 	info.region_node = region_node;
 
 	status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	if (info.region_node->object->region.space_id ==
-	    ACPI_ADR_SPACE_PLATFORM_COMM
-	    && !(region_node->object->field.internal_pcc_buffer =
-		 ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
-				      length))) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
+	    ACPI_ADR_SPACE_PLATFORM_COMM) {
+		region_node->object->field.internal_pcc_buffer =
+		    ACPI_ALLOCATE_ZEROED(info.region_node->object->region.
+					 length);
+		if (!region_node->object->field.internal_pcc_buffer) {
+			return_ACPI_STATUS(AE_NO_MEMORY);
+		}
 	}
+
 	return_ACPI_STATUS(status);
 }
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dsmethod.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dsmethod.c
@@ -517,7 +517,7 @@
 	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
 	if (!info) {
 		status = AE_NO_MEMORY;
-		goto cleanup;
+		goto pop_walk_state;
 	}
 
 	info->parameters = &this_walk_state->operands[0];
@@ -529,7 +529,7 @@
 
 	ACPI_FREE(info);
 	if (ACPI_FAILURE(status)) {
-		goto cleanup;
+		goto pop_walk_state;
 	}
 
 	next_walk_state->method_nesting_depth =
@@ -575,6 +575,12 @@
 
 	return_ACPI_STATUS(status);
 
+pop_walk_state:
+
+	/* On error, pop the walk state to be deleted from thread */
+
+	acpi_ds_pop_walk_state(thread);
+
 cleanup:
 
 	/* On error, we must terminate the method properly */
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dswexec.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dswexec.c
@@ -16,6 +16,9 @@
 #include "acinterp.h"
 #include "acnamesp.h"
 #include "acdebug.h"
+#ifdef ACPI_EXEC_APP
+#include "aecommon.h"
+#endif
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dswexec")
@@ -329,6 +332,10 @@
 	u32 op_class;
 	union acpi_parse_object *next_op;
 	union acpi_parse_object *first_arg;
+#ifdef ACPI_EXEC_APP
+	char *namepath;
+	union acpi_operand_object *obj_desc;
+#endif
 
 	ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state);
 
@@ -537,6 +544,32 @@
 
 			status =
 			    acpi_ds_eval_buffer_field_operands(walk_state, op);
+			if (ACPI_FAILURE(status)) {
+				break;
+			}
+#ifdef ACPI_EXEC_APP
+			/*
+			 * acpi_exec support for namespace initialization file (initialize
+			 * buffer_fields in this code.)
+			 */
+			namepath =
+			    acpi_ns_get_external_pathname(op->common.node);
+			status = ae_lookup_init_file_entry(namepath, &obj_desc);
+			if (ACPI_SUCCESS(status)) {
+				status =
+				    acpi_ex_write_data_to_field(obj_desc,
+								op->common.
+								node->object,
+								NULL);
+				if ACPI_FAILURE
+					(status) {
+					ACPI_EXCEPTION((AE_INFO, status,
+							"While writing to buffer field"));
+					}
+			}
+			ACPI_FREE(namepath);
+			status = AE_OK;
+#endif
 			break;
 
 		case AML_TYPE_CREATE_OBJECT:
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dswload.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dswload.c
@@ -14,7 +14,6 @@
 #include "acdispat.h"
 #include "acinterp.h"
 #include "acnamesp.h"
-
 #ifdef ACPI_ASL_COMPILER
 #include "acdisasm.h"
 #endif
@@ -399,7 +398,6 @@
 	union acpi_parse_object *op;
 	acpi_object_type object_type;
 	acpi_status status = AE_OK;
-
 #ifdef ACPI_ASL_COMPILER
 	u8 param_count;
 #endif
@@ -410,6 +408,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-ein-5.4.0.orig/drivers/acpi/acpica/dswload2.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dswload2.c
@@ -15,6 +15,9 @@
 #include "acinterp.h"
 #include "acnamesp.h"
 #include "acevents.h"
+#ifdef ACPI_EXEC_APP
+#include "aecommon.h"
+#endif
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dswload2")
@@ -373,6 +376,10 @@
 	struct acpi_namespace_node *new_node;
 	u32 i;
 	u8 region_space;
+#ifdef ACPI_EXEC_APP
+	union acpi_operand_object *obj_desc;
+	char *namepath;
+#endif
 
 	ACPI_FUNCTION_TRACE(ds_load2_end_op);
 
@@ -466,6 +473,11 @@
 		 * be evaluated later during the execution phase
 		 */
 		status = acpi_ds_create_buffer_field(op, walk_state);
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status,
+					"CreateBufferField failure"));
+			goto cleanup;
+			}
 		break;
 
 	case AML_TYPE_NAMED_FIELD:
@@ -604,6 +616,29 @@
 		case AML_NAME_OP:
 
 			status = acpi_ds_create_node(walk_state, node, op);
+			if (ACPI_FAILURE(status)) {
+				goto cleanup;
+			}
+#ifdef ACPI_EXEC_APP
+			/*
+			 * acpi_exec support for namespace initialization file (initialize
+			 * Name opcodes in this code.)
+			 */
+			namepath = acpi_ns_get_external_pathname(node);
+			status = ae_lookup_init_file_entry(namepath, &obj_desc);
+			if (ACPI_SUCCESS(status)) {
+
+				/* Detach any existing object, attach new object */
+
+				if (node->object) {
+					acpi_ns_detach_object(node);
+				}
+				acpi_ns_attach_object(node, obj_desc,
+						      obj_desc->common.type);
+			}
+			ACPI_FREE(namepath);
+			status = AE_OK;
+#endif
 			break;
 
 		case AML_METHOD_OP:
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/dswstate.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/dswstate.c
@@ -576,9 +576,14 @@
 	ACPI_FUNCTION_TRACE(ds_init_aml_walk);
 
 	walk_state->parser_state.aml =
-	    walk_state->parser_state.aml_start = aml_start;
-	walk_state->parser_state.aml_end =
-	    walk_state->parser_state.pkg_end = aml_start + aml_length;
+	    walk_state->parser_state.aml_start =
+	    walk_state->parser_state.aml_end =
+	    walk_state->parser_state.pkg_end = aml_start;
+	/* Avoid undefined behavior: applying zero offset to null pointer */
+	if (aml_length != 0) {
+		walk_state->parser_state.aml_end += aml_length;
+		walk_state->parser_state.pkg_end += aml_length;
+	}
 
 	/* The next_op of the next_walk will be the beginning of the method */
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/evevent.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/evevent.c
@@ -265,4 +265,49 @@
 		 handler) (acpi_gbl_fixed_event_handlers[event].context));
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_any_fixed_event_status_set
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      TRUE or FALSE
+ *
+ * DESCRIPTION: Checks the PM status register for active fixed events
+ *
+ ******************************************************************************/
+
+u32 acpi_any_fixed_event_status_set(void)
+{
+	acpi_status status;
+	u32 in_status;
+	u32 in_enable;
+	u32 i;
+
+	status = acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &in_enable);
+	if (ACPI_FAILURE(status)) {
+		return (FALSE);
+	}
+
+	status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &in_status);
+	if (ACPI_FAILURE(status)) {
+		return (FALSE);
+	}
+
+	/*
+	 * Check for all possible Fixed Events and dispatch those that are active
+	 */
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+
+		/* Both the status and enable bits must be on for this event */
+
+		if ((in_status & acpi_gbl_fixed_event_info[i].status_bit_mask) &&
+		    (in_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) {
+			return (TRUE);
+		}
+	}
+
+	return (FALSE);
+}
+
 #endif				/* !ACPI_REDUCED_HARDWARE */
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/evhandler.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/evhandler.c
@@ -489,6 +489,13 @@
 
 	/* Init handler obj */
 
+	status =
+	    acpi_os_create_mutex(&handler_obj->address_space.context_mutex);
+	if (ACPI_FAILURE(status)) {
+		acpi_ut_remove_reference(handler_obj);
+		goto unlock_and_exit;
+	}
+
 	handler_obj->address_space.space_id = (u8)space_id;
 	handler_obj->address_space.handler_flags = flags;
 	handler_obj->address_space.region_list = NULL;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/evregion.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/evregion.c
@@ -111,6 +111,8 @@
 	union acpi_operand_object *region_obj2;
 	void *region_context = NULL;
 	struct acpi_connection_info *context;
+	acpi_mutex context_mutex;
+	u8 context_locked;
 	acpi_physical_address address;
 
 	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
@@ -135,6 +137,8 @@
 	}
 
 	context = handler_desc->address_space.context;
+	context_mutex = handler_desc->address_space.context_mutex;
+	context_locked = FALSE;
 
 	/*
 	 * It may be the case that the region has never been initialized.
@@ -203,6 +207,23 @@
 	handler = handler_desc->address_space.handler;
 	address = (region_obj->region.address + region_offset);
 
+	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
+			  &region_obj->region.handler->address_space, handler,
+			  ACPI_FORMAT_UINT64(address),
+			  acpi_ut_get_region_name(region_obj->region.
+						  space_id)));
+
+	if (!(handler_desc->address_space.handler_flags &
+	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+		/*
+		 * For handlers other than the default (supplied) handlers, we must
+		 * exit the interpreter because the handler *might* block -- we don't
+		 * know what it will do, so we can't hold the lock on the interpreter.
+		 */
+		acpi_ex_exit_interpreter();
+	}
+
 	/*
 	 * Special handling for generic_serial_bus and general_purpose_io:
 	 * There are three extra parameters that must be passed to the
@@ -211,6 +232,11 @@
 	 *   2) Length of the above buffer
 	 *   3) Actual access length from the access_as() op
 	 *
+	 * Since we pass these extra parameters via the context, which is
+	 * shared between threads, we must lock the context to avoid these
+	 * parameters being changed from another thread before the handler
+	 * has completed running.
+	 *
 	 * In addition, for general_purpose_io, the Address and bit_width fields
 	 * are defined as follows:
 	 *   1) Address is the pin number index of the field (bit offset from
@@ -220,6 +246,14 @@
 	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
 	    context && field_obj) {
 
+		status =
+		    acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+		if (ACPI_FAILURE(status)) {
+			goto re_enter_interpreter;
+		}
+
+		context_locked = TRUE;
+
 		/* Get the Connection (resource_template) buffer */
 
 		context->connection = field_obj->field.resource_buffer;
@@ -229,6 +263,14 @@
 	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
 	    context && field_obj) {
 
+		status =
+		    acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
+		if (ACPI_FAILURE(status)) {
+			goto re_enter_interpreter;
+		}
+
+		context_locked = TRUE;
+
 		/* Get the Connection (resource_template) buffer */
 
 		context->connection = field_obj->field.resource_buffer;
@@ -238,28 +280,15 @@
 		bit_width = field_obj->field.bit_length;
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
-			  &region_obj->region.handler->address_space, handler,
-			  ACPI_FORMAT_UINT64(address),
-			  acpi_ut_get_region_name(region_obj->region.
-						  space_id)));
-
-	if (!(handler_desc->address_space.handler_flags &
-	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
-		/*
-		 * For handlers other than the default (supplied) handlers, we must
-		 * exit the interpreter because the handler *might* block -- we don't
-		 * know what it will do, so we can't hold the lock on the interpreter.
-		 */
-		acpi_ex_exit_interpreter();
-	}
-
 	/* Call the handler */
 
 	status = handler(function, address, bit_width, value, context,
 			 region_obj2->extra.region_context);
 
+	if (context_locked) {
+		acpi_os_release_mutex(context_mutex);
+	}
+
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
 				acpi_ut_get_region_name(region_obj->region.
@@ -276,6 +305,7 @@
 		}
 	}
 
+re_enter_interpreter:
 	if (!(handler_desc->address_space.handler_flags &
 	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
 		/*
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/evxfgpe.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/evxfgpe.c
@@ -795,6 +795,45 @@
 
 ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_any_gpe_status_set
+ *
+ * PARAMETERS:  gpe_skip_number      - Number of the GPE to skip
+ *
+ * RETURN:      Whether or not the status bit is set for any GPE
+ *
+ * DESCRIPTION: Check the status bits of all enabled GPEs, except for the one
+ *              represented by the "skip" argument, and return TRUE if any of
+ *              them is set or FALSE otherwise.
+ *
+ ******************************************************************************/
+u32 acpi_any_gpe_status_set(u32 gpe_skip_number)
+{
+	acpi_status status;
+	acpi_handle gpe_device;
+	u8 ret;
+
+	ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set);
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return (FALSE);
+	}
+
+	status = acpi_get_gpe_device(gpe_skip_number, &gpe_device);
+	if (ACPI_FAILURE(status)) {
+		gpe_device = NULL;
+	}
+
+	ret = acpi_hw_check_all_gpes(gpe_device, gpe_skip_number);
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+	return (ret);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_any_gpe_status_set)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_gpe_block
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/evxfregn.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/evxfregn.c
@@ -201,6 +201,8 @@
 
 			/* Now we can delete the handler object */
 
+			acpi_os_release_mutex(handler_obj->address_space.
+					      context_mutex);
 			acpi_ut_remove_reference(handler_obj);
 			goto unlock_and_exit;
 		}
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/exfield.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/exfield.c
@@ -320,12 +320,7 @@
 		       obj_desc->field.base_byte_offset,
 		       source_desc->buffer.pointer, data_length);
 
-		if ((obj_desc->field.region_obj->region.address ==
-		     PCC_MASTER_SUBSPACE
-		     && MASTER_SUBSPACE_COMMAND(obj_desc->field.
-						base_byte_offset))
-		    || GENERIC_SUBSPACE_COMMAND(obj_desc->field.
-						base_byte_offset)) {
+		if (MASTER_SUBSPACE_COMMAND(obj_desc->field.base_byte_offset)) {
 
 			/* Perform the write */
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/exoparg1.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/exoparg1.c
@@ -1007,7 +1007,8 @@
 						    (walk_state, return_desc,
 						     &temp_desc);
 						if (ACPI_FAILURE(status)) {
-							goto cleanup;
+							return_ACPI_STATUS
+							    (status);
 						}
 
 						return_desc = temp_desc;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/exprep.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/exprep.c
@@ -473,10 +473,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-ein-5.4.0.orig/drivers/acpi/acpica/hwesleep.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/hwesleep.c
@@ -104,7 +104,9 @@
 
 	/* Flush caches, as per ACPI specification */
 
-	ACPI_FLUSH_CPU_CACHE();
+	if (sleep_state < ACPI_STATE_S4) {
+		ACPI_FLUSH_CPU_CACHE();
+	}
 
 	status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
 	if (status == AE_CTRL_TERMINATE) {
@@ -147,17 +149,13 @@
 
 acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
 {
-	acpi_status status;
 	u8 sleep_type_value;
 
 	ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
 
-	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
-					  &acpi_gbl_sleep_type_a,
-					  &acpi_gbl_sleep_type_b);
-	if (ACPI_SUCCESS(status)) {
+	if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
 		sleep_type_value =
-		    ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+		    ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) &
 		     ACPI_X_SLEEP_TYPE_MASK);
 
 		(void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/hwgpe.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/hwgpe.c
@@ -444,6 +444,65 @@
 	return (AE_OK);
 }
 
+struct acpi_gpe_block_status_context {
+	struct acpi_gpe_register_info *gpe_skip_register_info;
+	u8 gpe_skip_mask;
+	u8 retval;
+};
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_get_gpe_block_status
+ *
+ * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
+ *              gpe_block           - Gpe Block info
+ *              context             - GPE list walk context data
+ *
+ * RETURN:      Success
+ *
+ * DESCRIPTION: Produce a combined GPE status bits mask for the given block.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+			     struct acpi_gpe_block_info *gpe_block,
+			     void *context)
+{
+	struct acpi_gpe_block_status_context *c = context;
+	struct acpi_gpe_register_info *gpe_register_info;
+	u64 in_enable, in_status;
+	acpi_status status;
+	u8 ret_mask;
+	u32 i;
+
+	/* Examine each GPE Register within the block */
+
+	for (i = 0; i < gpe_block->register_count; i++) {
+		gpe_register_info = &gpe_block->register_info[i];
+
+		status = acpi_hw_read(&in_enable,
+				      &gpe_register_info->enable_address);
+		if (ACPI_FAILURE(status)) {
+			continue;
+		}
+
+		status = acpi_hw_read(&in_status,
+				      &gpe_register_info->status_address);
+		if (ACPI_FAILURE(status)) {
+			continue;
+		}
+
+		ret_mask = in_enable & in_status;
+		if (ret_mask && c->gpe_skip_register_info == gpe_register_info) {
+			ret_mask &= ~c->gpe_skip_mask;
+		}
+		c->retval |= ret_mask;
+	}
+
+	return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_disable_all_gpes
@@ -510,4 +569,45 @@
 	return_ACPI_STATUS(status);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_check_all_gpes
+ *
+ * PARAMETERS:  gpe_skip_device      - GPE devoce of the GPE to skip
+ *              gpe_skip_number      - Number of the GPE to skip
+ *
+ * RETURN:      Combined status of all GPEs
+ *
+ * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one
+ *              represented by the "skip" arguments, and return TRUE if the
+ *              status bit is set for at least one of them of FALSE otherwise.
+ *
+ ******************************************************************************/
+
+u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number)
+{
+	struct acpi_gpe_block_status_context context = {
+		.gpe_skip_register_info = NULL,
+		.retval = 0,
+	};
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device,
+						    gpe_skip_number);
+	if (gpe_event_info) {
+		context.gpe_skip_register_info = gpe_event_info->register_info;
+		context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info);
+	}
+
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+	(void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context);
+	return (context.retval != 0);
+}
+
 #endif				/* !ACPI_REDUCED_HARDWARE */
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/hwsleep.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/hwsleep.c
@@ -110,7 +110,9 @@
 
 	/* Flush caches, as per ACPI specification */
 
-	ACPI_FLUSH_CPU_CACHE();
+	if (sleep_state < ACPI_STATE_S4) {
+		ACPI_FLUSH_CPU_CACHE();
+	}
 
 	status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
 	if (status == AE_CTRL_TERMINATE) {
@@ -179,7 +181,7 @@
 
 acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 {
-	acpi_status status;
+	acpi_status status = AE_OK;
 	struct acpi_bit_register_info *sleep_type_reg_info;
 	struct acpi_bit_register_info *sleep_enable_reg_info;
 	u32 pm1a_control;
@@ -192,10 +194,7 @@
 	 * This is unclear from the ACPI Spec, but it is required
 	 * by some machines.
 	 */
-	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
-					  &acpi_gbl_sleep_type_a,
-					  &acpi_gbl_sleep_type_b);
-	if (ACPI_SUCCESS(status)) {
+	if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
 		sleep_type_reg_info =
 		    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
 		sleep_enable_reg_info =
@@ -216,9 +215,9 @@
 
 			/* Insert the SLP_TYP bits */
 
-			pm1a_control |= (acpi_gbl_sleep_type_a <<
+			pm1a_control |= (acpi_gbl_sleep_type_a_s0 <<
 					 sleep_type_reg_info->bit_position);
-			pm1b_control |= (acpi_gbl_sleep_type_b <<
+			pm1b_control |= (acpi_gbl_sleep_type_b_s0 <<
 					 sleep_type_reg_info->bit_position);
 
 			/* Write the control registers and ignore any errors */
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/hwvalid.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/hwvalid.c
@@ -23,8 +23,8 @@
  *
  * The table is used to implement the Microsoft port access rules that
  * first appeared in Windows XP. Some ports are always illegal, and some
- * ports are only illegal if the BIOS calls _OSI with a win_XP string or
- * later (meaning that the BIOS itelf is post-XP.)
+ * ports are only illegal if the BIOS calls _OSI with nothing newer than
+ * the specific _OSI strings.
  *
  * This provides ACPICA with the desired port protections and
  * Microsoft compatibility.
@@ -145,7 +145,8 @@
 
 			/* Port illegality may depend on the _OSI calls made by the BIOS */
 
-			if (acpi_gbl_osi_data >= port_info->osi_dependency) {
+			if (port_info->osi_dependency == ACPI_ALWAYS_ILLEGAL ||
+			    acpi_gbl_osi_data == port_info->osi_dependency) {
 				ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
 						  "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)\n",
 						  ACPI_FORMAT_UINT64(address),
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/hwxfsleep.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/hwxfsleep.c
@@ -162,8 +162,6 @@
 		return_ACPI_STATUS(status);
 	}
 
-	ACPI_FLUSH_CPU_CACHE();
-
 	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
 				    (u32)acpi_gbl_FADT.s4_bios_request, 8);
 
@@ -214,6 +212,13 @@
 		return_ACPI_STATUS(status);
 	}
 
+	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
+					  &acpi_gbl_sleep_type_a_s0,
+					  &acpi_gbl_sleep_type_b_s0);
+	if (ACPI_FAILURE(status)) {
+		acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID;
+	}
+
 	/* Execute the _PTS method (Prepare To Sleep) */
 
 	arg_list.count = 1;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/nsaccess.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/nsaccess.c
@@ -99,13 +99,12 @@
 		 * just create and link the new node(s) here.
 		 */
 		new_node =
-		    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_namespace_node));
+		    acpi_ns_create_node(*ACPI_CAST_PTR(u32, init_val->name));
 		if (!new_node) {
 			status = AE_NO_MEMORY;
 			goto unlock_and_exit;
 		}
 
-		ACPI_COPY_NAMESEG(new_node->name.ascii, init_val->name);
 		new_node->descriptor_type = ACPI_DESC_TYPE_NAMED;
 		new_node->type = init_val->type;
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/nsnames.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/nsnames.c
@@ -13,9 +13,6 @@
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsnames")
 
-/* Local Prototypes */
-static void acpi_ns_normalize_pathname(char *original_path);
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_get_external_pathname
@@ -30,7 +27,6 @@
  *              for error and debug statements.
  *
  ******************************************************************************/
-
 char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
 {
 	char *name_buffer;
@@ -411,7 +407,7 @@
  *
  ******************************************************************************/
 
-static void acpi_ns_normalize_pathname(char *original_path)
+void acpi_ns_normalize_pathname(char *original_path)
 {
 	char *input_path = original_path;
 	char *new_path_buffer;
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/nsrepair.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/nsrepair.c
@@ -181,8 +181,9 @@
 	 * Try to fix if there was no return object. Warning if failed to fix.
 	 */
 	if (!return_object) {
-		if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
-			if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+		if (expected_btypes) {
+			if (!(expected_btypes & ACPI_RTYPE_NONE) &&
+			    package_index != ACPI_NOT_PACKAGE_ELEMENT) {
 				ACPI_WARN_PREDEFINED((AE_INFO,
 						      info->full_pathname,
 						      ACPI_WARN_ALWAYS,
@@ -196,14 +197,15 @@
 				if (ACPI_SUCCESS(status)) {
 					return (AE_OK);	/* Repair was successful */
 				}
-			} else {
+			}
+
+			if (expected_btypes != ACPI_RTYPE_NONE) {
 				ACPI_WARN_PREDEFINED((AE_INFO,
 						      info->full_pathname,
 						      ACPI_WARN_ALWAYS,
 						      "Missing expected return value"));
+				return (AE_AML_NO_RETURN_VALUE);
 			}
-
-			return (AE_AML_NO_RETURN_VALUE);
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/nswalk.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/nswalk.c
@@ -169,6 +169,9 @@
 
 	if (start_node == ACPI_ROOT_OBJECT) {
 		start_node = acpi_gbl_root_node;
+		if (!start_node) {
+			return_ACPI_STATUS(AE_NO_NAMESPACE);
+		}
 	}
 
 	/* Null child means "get first node" */
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/psopcode.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/psopcode.c
@@ -603,7 +603,7 @@
 
 /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY,
 			 AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
-			 AML_FLAGS_EXEC_0A_0T_1R),
+			 AML_FLAGS_EXEC_0A_0T_1R | AML_NO_OPERAND_RESOLVE),
 
 /* ACPI 5.0 opcodes */
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/utcopy.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/utcopy.c
@@ -916,13 +916,6 @@
 	status = acpi_ut_walk_package_tree(source_obj, dest_obj,
 					   acpi_ut_copy_ielement_to_ielement,
 					   walk_state);
-	if (ACPI_FAILURE(status)) {
-
-		/* On failure, delete the destination package object */
-
-		acpi_ut_remove_reference(dest_obj);
-	}
-
 	return_ACPI_STATUS(status);
 }
 
--- linux-ein-5.4.0.orig/drivers/acpi/acpica/utdelete.c
+++ linux-ein-5.4.0/drivers/acpi/acpica/utdelete.c
@@ -285,6 +285,14 @@
 		}
 		break;
 
+	case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
+
+		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
+				  "***** Address handler %p\n", object));
+
+		acpi_os_delete_mutex(object->address_space.context_mutex);
+		break;
+
 	default:
 
 		break;
@@ -414,6 +422,7 @@
 			ACPI_WARNING((AE_INFO,
 				      "Obj %p, Reference Count is already zero, cannot decrement\n",
 				      object));
+			return;
 		}
 
 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
@@ -452,13 +461,13 @@
  *
  * FUNCTION:    acpi_ut_update_object_reference
  *
- * PARAMETERS:  object              - Increment ref count for this object
- *                                    and all sub-objects
+ * PARAMETERS:  object              - Increment or decrement the ref count for
+ *                                    this object and all sub-objects
  *              action              - Either REF_INCREMENT or REF_DECREMENT
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Increment the object reference count
+ * DESCRIPTION: Increment or decrement the object reference count
  *
  * Object references are incremented when:
  * 1) An object is attached to a Node (namespace object)
@@ -492,7 +501,7 @@
 		}
 
 		/*
-		 * All sub-objects must have their reference count incremented
+		 * All sub-objects must have their reference count updated
 		 * also. Different object types have different subobjects.
 		 */
 		switch (object->common.type) {
@@ -559,6 +568,7 @@
 					break;
 				}
 			}
+
 			next_object = NULL;
 			break;
 
@@ -567,11 +577,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;
@@ -612,6 +617,7 @@
 			}
 			break;
 
+		case ACPI_TYPE_LOCAL_REGION_FIELD:
 		case ACPI_TYPE_REGION:
 		default:
 
--- linux-ein-5.4.0.orig/drivers/acpi/apei/bert.c
+++ linux-ein-5.4.0/drivers/acpi/apei/bert.c
@@ -30,14 +30,25 @@
 #undef pr_fmt
 #define pr_fmt(fmt) "BERT: " fmt
 
+#define ACPI_BERT_PRINT_MAX_RECORDS 5
+#define ACPI_BERT_PRINT_MAX_LEN 1024
+
 static int bert_disable;
 
+/*
+ * Print "all" the error records in the BERT table, but avoid huge spam to
+ * the console if the BIOS included oversize records, or too many records.
+ * Skipping some records here does not lose anything because the full
+ * data is available to user tools in:
+ *	/sys/firmware/acpi/tables/data/BERT
+ */
 static void __init bert_print_all(struct acpi_bert_region *region,
 				  unsigned int region_len)
 {
 	struct acpi_hest_generic_status *estatus =
 		(struct acpi_hest_generic_status *)region;
 	int remain = region_len;
+	int printed = 0, skipped = 0;
 	u32 estatus_len;
 
 	while (remain >= sizeof(struct acpi_bert_region)) {
@@ -45,21 +56,26 @@
 		if (remain < estatus_len) {
 			pr_err(FW_BUG "Truncated status block (length: %u).\n",
 			       estatus_len);
-			return;
+			break;
 		}
 
 		/* No more error records. */
 		if (!estatus->block_status)
-			return;
+			break;
 
 		if (cper_estatus_check(estatus)) {
 			pr_err(FW_BUG "Invalid error record.\n");
-			return;
+			break;
 		}
 
-		pr_info_once("Error records from previous boot:\n");
-
-		cper_estatus_print(KERN_INFO HW_ERR, estatus);
+		if (estatus_len < ACPI_BERT_PRINT_MAX_LEN &&
+		    printed < ACPI_BERT_PRINT_MAX_RECORDS) {
+			pr_info_once("Error records from previous boot:\n");
+			cper_estatus_print(KERN_INFO HW_ERR, estatus);
+			printed++;
+		} else {
+			skipped++;
+		}
 
 		/*
 		 * Because the boot error source is "one-time polled" type,
@@ -71,13 +87,16 @@
 		estatus = (void *)estatus + estatus_len;
 		remain -= estatus_len;
 	}
+
+	if (skipped)
+		pr_info(HW_ERR "Skipped %d error records\n", skipped);
 }
 
 static int __init setup_bert_disable(char *str)
 {
 	bert_disable = 1;
 
-	return 0;
+	return 1;
 }
 __setup("bert_disable", setup_bert_disable);
 
--- linux-ein-5.4.0.orig/drivers/acpi/apei/erst.c
+++ linux-ein-5.4.0/drivers/acpi/apei/erst.c
@@ -891,7 +891,7 @@
 static int __init setup_erst_disable(char *str)
 {
 	erst_disable = 1;
-	return 0;
+	return 1;
 }
 
 __setup("erst_disable", setup_erst_disable);
--- linux-ein-5.4.0.orig/drivers/acpi/apei/ghes.c
+++ linux-ein-5.4.0/drivers/acpi/apei/ghes.c
@@ -171,7 +171,7 @@
 	 * New allocation must be visible in all pgd before it can be found by
 	 * an NMI allocating from the pool.
 	 */
-	vmalloc_sync_all();
+	vmalloc_sync_mappings();
 
 	rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1);
 	if (rc)
--- linux-ein-5.4.0.orig/drivers/acpi/apei/hest.c
+++ linux-ein-5.4.0/drivers/acpi/apei/hest.c
@@ -219,7 +219,7 @@
 static int __init setup_hest_disable(char *str)
 {
 	hest_disable = HEST_DISABLED;
-	return 0;
+	return 1;
 }
 
 __setup("hest_disable", setup_hest_disable);
--- linux-ein-5.4.0.orig/drivers/acpi/arm64/gtdt.c
+++ linux-ein-5.4.0/drivers/acpi/arm64/gtdt.c
@@ -36,7 +36,7 @@
 
 static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
 
-static inline void *next_platform_timer(void *platform_timer)
+static inline __init void *next_platform_timer(void *platform_timer)
 {
 	struct acpi_gtdt_header *gh = platform_timer;
 
@@ -329,7 +329,7 @@
 					int index)
 {
 	struct platform_device *pdev;
-	int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
+	int irq;
 
 	/*
 	 * According to SBSA specification the size of refresh and control
@@ -338,7 +338,7 @@
 	struct resource res[] = {
 		DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
 		DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
-		DEFINE_RES_IRQ(irq),
+		{},
 	};
 	int nr_res = ARRAY_SIZE(res);
 
@@ -348,10 +348,11 @@
 
 	if (!(wd->refresh_frame_address && wd->control_frame_address)) {
 		pr_err(FW_BUG "failed to get the Watchdog base address.\n");
-		acpi_unregister_gsi(wd->timer_interrupt);
 		return -EINVAL;
 	}
 
+	irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
+	res[2] = (struct resource)DEFINE_RES_IRQ(irq);
 	if (irq <= 0) {
 		pr_warn("failed to map the Watchdog interrupt.\n");
 		nr_res--;
@@ -364,7 +365,8 @@
 	 */
 	pdev = platform_device_register_simple("sbsa-gwdt", index, res, nr_res);
 	if (IS_ERR(pdev)) {
-		acpi_unregister_gsi(wd->timer_interrupt);
+		if (irq > 0)
+			acpi_unregister_gsi(wd->timer_interrupt);
 		return PTR_ERR(pdev);
 	}
 
--- linux-ein-5.4.0.orig/drivers/acpi/arm64/iort.c
+++ linux-ein-5.4.0/drivers/acpi/arm64/iort.c
@@ -361,6 +361,7 @@
 static int iort_get_id_mapping_index(struct acpi_iort_node *node)
 {
 	struct acpi_iort_smmu_v3 *smmu;
+	struct acpi_iort_pmcg *pmcg;
 
 	switch (node->type) {
 	case ACPI_IORT_NODE_SMMU_V3:
@@ -388,6 +389,10 @@
 
 		return smmu->id_mapping_index;
 	case ACPI_IORT_NODE_PMCG:
+		pmcg = (struct acpi_iort_pmcg *)node->node_data;
+		if (pmcg->overflow_gsiv || node->mapping_count == 0)
+			return -EINVAL;
+
 		return 0;
 	default:
 		return -EINVAL;
@@ -498,7 +503,6 @@
 		node = iort_get_iort_node(dev->fwnode);
 		if (node)
 			return node;
-
 		/*
 		 * if not, then it should be a platform device defined in
 		 * DSDT/SSDT (with Named Component node in IORT)
@@ -517,22 +521,22 @@
 }
 
 /**
- * iort_msi_map_rid() - Map a MSI requester ID for a device
+ * iort_msi_map_id() - Map a MSI input ID for a device
  * @dev: The device for which the mapping is to be done.
- * @req_id: The device requester ID.
+ * @input_id: The device input ID.
  *
- * Returns: mapped MSI RID on success, input requester ID otherwise
+ * Returns: mapped MSI ID on success, input ID otherwise
  */
-u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+u32 iort_msi_map_id(struct device *dev, u32 input_id)
 {
 	struct acpi_iort_node *node;
 	u32 dev_id;
 
 	node = iort_find_dev_node(dev);
 	if (!node)
-		return req_id;
+		return input_id;
 
-	iort_node_map_id(node, req_id, &dev_id, IORT_MSI_TYPE);
+	iort_node_map_id(node, input_id, &dev_id, IORT_MSI_TYPE);
 	return dev_id;
 }
 
@@ -589,13 +593,13 @@
 /**
  * iort_dev_find_its_id() - Find the ITS identifier for a device
  * @dev: The device.
- * @req_id: Device's requester ID
+ * @id: Device's ID
  * @idx: Index of the ITS identifier list.
  * @its_id: ITS identifier.
  *
  * Returns: 0 on success, appropriate error value otherwise
  */
-static int iort_dev_find_its_id(struct device *dev, u32 req_id,
+static int iort_dev_find_its_id(struct device *dev, u32 id,
 				unsigned int idx, int *its_id)
 {
 	struct acpi_iort_its_group *its;
@@ -605,7 +609,7 @@
 	if (!node)
 		return -ENXIO;
 
-	node = iort_node_map_id(node, req_id, NULL, IORT_MSI_TYPE);
+	node = iort_node_map_id(node, id, NULL, IORT_MSI_TYPE);
 	if (!node)
 		return -ENXIO;
 
@@ -628,19 +632,20 @@
  *
  * Returns: the MSI domain for this device, NULL otherwise
  */
-struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
+					  enum irq_domain_bus_token bus_token)
 {
 	struct fwnode_handle *handle;
 	int its_id;
 
-	if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
+	if (iort_dev_find_its_id(dev, id, 0, &its_id))
 		return NULL;
 
 	handle = iort_find_domain_token(its_id);
 	if (!handle)
 		return NULL;
 
-	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
+	return irq_find_matching_fwnode(handle, bus_token);
 }
 
 static void iort_set_device_domain(struct device *dev,
@@ -1368,9 +1373,17 @@
 	res[0].start = pmcg->page0_base_address;
 	res[0].end = pmcg->page0_base_address + SZ_4K - 1;
 	res[0].flags = IORESOURCE_MEM;
-	res[1].start = pmcg->page1_base_address;
-	res[1].end = pmcg->page1_base_address + SZ_4K - 1;
-	res[1].flags = IORESOURCE_MEM;
+	/*
+	 * The initial version in DEN0049C lacked a way to describe register
+	 * page 1, which makes it broken for most PMCG implementations; in
+	 * that case, just let the driver fail gracefully if it expects to
+	 * find a second memory resource.
+	 */
+	if (node->revision > 0) {
+		res[1].start = pmcg->page1_base_address;
+		res[1].end = pmcg->page1_base_address + SZ_4K - 1;
+		res[1].flags = IORESOURCE_MEM;
+	}
 
 	if (pmcg->overflow_gsiv)
 		acpi_iort_register_irq(pmcg->overflow_gsiv, "overflow",
@@ -1380,7 +1393,10 @@
 static struct acpi_platform_list pmcg_plat_info[] __initdata = {
 	/* HiSilicon Hip08 Platform */
 	{"HISI  ", "HIP08   ", 0, ACPI_SIG_IORT, greater_than_or_equal,
-	 "Erratum #162001800", IORT_SMMU_V3_PMCG_HISI_HIP08},
+	 "Erratum #162001800, Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP08},
+	/* HiSilicon Hip09 Platform */
+	{"HISI  ", "HIP09   ", 0, ACPI_SIG_IORT, greater_than_or_equal,
+	 "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09},
 	{ }
 };
 
--- linux-ein-5.4.0.orig/drivers/acpi/battery.c
+++ linux-ein-5.4.0/drivers/acpi/battery.c
@@ -38,6 +38,8 @@
 #define PREFIX "ACPI: "
 
 #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
+#define ACPI_BATTERY_CAPACITY_VALID(capacity) \
+	((capacity) != 0 && (capacity) != ACPI_BATTERY_VALUE_UNKNOWN)
 
 #define ACPI_BATTERY_DEVICE_NAME	"Battery"
 
@@ -63,6 +65,7 @@
 static int battery_notification_delay_ms;
 static int battery_ac_is_broken;
 static int battery_check_pmic = 1;
+static int battery_quirk_notcharging;
 static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
@@ -74,6 +77,10 @@
 
 static const struct acpi_device_id battery_device_ids[] = {
 	{"PNP0C0A", 0},
+
+	/* Microsoft Surface Go 3 */
+	{"MSHW0146", 0},
+
 	{"", 0},
 };
 
@@ -183,7 +190,7 @@
 		return 1;
 
 	/* fallback to using design values for broken batteries */
-	if (battery->design_capacity == battery->capacity_now)
+	if (battery->design_capacity <= battery->capacity_now)
 		return 1;
 
 	/* we don't do any sort of metric based on percentages */
@@ -192,7 +199,8 @@
 
 static bool acpi_battery_is_degraded(struct acpi_battery *battery)
 {
-	return battery->full_charge_capacity && battery->design_capacity &&
+	return ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
+		ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity) &&
 		battery->full_charge_capacity < battery->design_capacity;
 }
 
@@ -214,7 +222,7 @@
 				     enum power_supply_property psp,
 				     union power_supply_propval *val)
 {
-	int ret = 0;
+	int full_capacity = ACPI_BATTERY_VALUE_UNKNOWN, ret = 0;
 	struct acpi_battery *battery = to_acpi_battery(psy);
 
 	if (acpi_battery_present(battery)) {
@@ -230,6 +238,8 @@
 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
 		else if (acpi_battery_is_charged(battery))
 			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else if (battery_quirk_notcharging)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 		else
 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
 		break;
@@ -263,14 +273,14 @@
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-		if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+		if (!ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
 			ret = -ENODEV;
 		else
 			val->intval = battery->design_capacity * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
 	case POWER_SUPPLY_PROP_ENERGY_FULL:
-		if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+		if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
 			ret = -ENODEV;
 		else
 			val->intval = battery->full_charge_capacity * 1000;
@@ -283,11 +293,17 @@
 			val->intval = battery->capacity_now * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
-		if (battery->capacity_now && battery->full_charge_capacity)
-			val->intval = battery->capacity_now * 100/
-					battery->full_charge_capacity;
+		if (ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
+			full_capacity = battery->full_charge_capacity;
+		else if (ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
+			full_capacity = battery->design_capacity;
+
+		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
+		    full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
 		else
-			val->intval = 0;
+			val->intval = battery->capacity_now * 100/
+					full_capacity;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
 		if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
@@ -333,6 +349,20 @@
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
+static enum power_supply_property charge_battery_full_cap_broken_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CYCLE_COUNT,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
 static enum power_supply_property energy_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
@@ -435,7 +465,7 @@
 			u8 *ptr = (u8 *)battery + offsets[i].offset;
 			if (element->type == ACPI_TYPE_STRING ||
 			    element->type == ACPI_TYPE_BUFFER)
-				strncpy(ptr, element->string.pointer, 32);
+				strscpy(ptr, element->string.pointer, 32);
 			else if (element->type == ACPI_TYPE_INTEGER) {
 				strncpy(ptr, (u8 *)&element->integer.value,
 					sizeof(u64));
@@ -794,20 +824,34 @@
 static int sysfs_add_battery(struct acpi_battery *battery)
 {
 	struct power_supply_config psy_cfg = { .drv_data = battery, };
+	bool full_cap_broken = false;
+
+	if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
+	    !ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
+		full_cap_broken = true;
 
 	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
-		battery->bat_desc.properties = charge_battery_props;
-		battery->bat_desc.num_properties =
-			ARRAY_SIZE(charge_battery_props);
-	} else if (battery->full_charge_capacity == 0) {
-		battery->bat_desc.properties =
-			energy_battery_full_cap_broken_props;
-		battery->bat_desc.num_properties =
-			ARRAY_SIZE(energy_battery_full_cap_broken_props);
+		if (full_cap_broken) {
+			battery->bat_desc.properties =
+			    charge_battery_full_cap_broken_props;
+			battery->bat_desc.num_properties =
+			    ARRAY_SIZE(charge_battery_full_cap_broken_props);
+		} else {
+			battery->bat_desc.properties = charge_battery_props;
+			battery->bat_desc.num_properties =
+			    ARRAY_SIZE(charge_battery_props);
+		}
 	} else {
-		battery->bat_desc.properties = energy_battery_props;
-		battery->bat_desc.num_properties =
-			ARRAY_SIZE(energy_battery_props);
+		if (full_cap_broken) {
+			battery->bat_desc.properties =
+			    energy_battery_full_cap_broken_props;
+			battery->bat_desc.num_properties =
+			    ARRAY_SIZE(energy_battery_full_cap_broken_props);
+		} else {
+			battery->bat_desc.properties = energy_battery_props;
+			battery->bat_desc.num_properties =
+			    ARRAY_SIZE(energy_battery_props);
+		}
 	}
 
 	battery->bat_desc.name = acpi_device_bid(battery->device);
@@ -1300,6 +1344,12 @@
 	return 0;
 }
 
+static int __init battery_quirk_not_charging(const struct dmi_system_id *d)
+{
+	battery_quirk_notcharging = 1;
+	return 0;
+}
+
 static const struct dmi_system_id bat_dmi_table[] __initconst = {
 	{
 		/* NEC LZ750/LS */
@@ -1344,6 +1394,27 @@
 		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
 		},
 	},
+	{
+		/*
+		 * On Lenovo ThinkPads the BIOS specification defines
+		 * a state when the bits for charging and discharging
+		 * are both set to 0. That state is "Not Charging".
+		 */
+		.callback = battery_quirk_not_charging,
+		.ident = "Lenovo ThinkPad",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"),
+		},
+	},
+	{
+		/* Microsoft Surface Go 3 */
+		.callback = battery_notification_delay_quirk,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
+		},
+	},
 	{},
 };
 
--- linux-ein-5.4.0.orig/drivers/acpi/bgrt.c
+++ linux-ein-5.4.0/drivers/acpi/bgrt.c
@@ -15,40 +15,19 @@
 static void *bgrt_image;
 static struct kobject *bgrt_kobj;
 
-static ssize_t show_version(struct device *dev,
-			    struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.version);
-}
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-
-static ssize_t show_status(struct device *dev,
-			   struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.status);
-}
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
-
-static ssize_t show_type(struct device *dev,
-			 struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_type);
-}
-static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
-
-static ssize_t show_xoffset(struct device *dev,
-			    struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_x);
-}
-static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL);
-
-static ssize_t show_yoffset(struct device *dev,
-			    struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_y);
-}
-static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
+#define BGRT_SHOW(_name, _member) \
+	static ssize_t _name##_show(struct kobject *kobj,			\
+				    struct kobj_attribute *attr, char *buf)	\
+	{									\
+		return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab._member);	\
+	}									\
+	struct kobj_attribute bgrt_attr_##_name = __ATTR_RO(_name)
+
+BGRT_SHOW(version, version);
+BGRT_SHOW(status, status);
+BGRT_SHOW(type, image_type);
+BGRT_SHOW(xoffset, image_offset_x);
+BGRT_SHOW(yoffset, image_offset_y);
 
 static ssize_t image_read(struct file *file, struct kobject *kobj,
 	       struct bin_attribute *attr, char *buf, loff_t off, size_t count)
@@ -60,11 +39,11 @@
 static BIN_ATTR_RO(image, 0);	/* size gets filled in later */
 
 static struct attribute *bgrt_attributes[] = {
-	&dev_attr_version.attr,
-	&dev_attr_status.attr,
-	&dev_attr_type.attr,
-	&dev_attr_xoffset.attr,
-	&dev_attr_yoffset.attr,
+	&bgrt_attr_version.attr,
+	&bgrt_attr_status.attr,
+	&bgrt_attr_type.attr,
+	&bgrt_attr_xoffset.attr,
+	&bgrt_attr_yoffset.attr,
 	NULL,
 };
 
--- linux-ein-5.4.0.orig/drivers/acpi/bus.c
+++ linux-ein-5.4.0/drivers/acpi/bus.c
@@ -153,7 +153,7 @@
 {
 	acpi_status status;
 
-	if (!*data)
+	if (!data)
 		return -EINVAL;
 
 	status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
@@ -1240,6 +1240,7 @@
 
 	result = acpi_bus_init();
 	if (result) {
+		kobject_put(acpi_kobj);
 		disable_acpi();
 		return result;
 	}
--- linux-ein-5.4.0.orig/drivers/acpi/button.c
+++ linux-ein-5.4.0/drivers/acpi/button.c
@@ -78,6 +78,39 @@
 			DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
 		},
 	},
+	{
+		/*
+		 * Medion Akoya E2215T, notification of the LID device only
+		 * happens on close, not on open and _LID always returns closed.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "E2215T"),
+		},
+		.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+	},
+	{
+		/*
+		 * Medion Akoya E2228T, notification of the LID device only
+		 * happens on close, not on open and _LID always returns closed.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "E2228T"),
+		},
+		.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+	},
+	{
+		/*
+		 * Razer Blade Stealth 13 late 2019, notification of the LID device
+		 * only happens on close, not on open and _LID always returns closed.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Razer Blade Stealth 13 Late 2019"),
+		},
+		.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+	},
 	{}
 };
 
@@ -114,6 +147,7 @@
 	int last_state;
 	ktime_t last_time;
 	bool suspended;
+	bool lid_state_initialized;
 };
 
 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
@@ -369,6 +403,8 @@
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
+	struct acpi_button *button = acpi_driver_data(device);
+
 	switch (lid_init_state) {
 	case ACPI_BUTTON_LID_INIT_OPEN:
 		(void)acpi_lid_notify_state(device, 1);
@@ -380,13 +416,14 @@
 	default:
 		break;
 	}
+
+	button->lid_state_initialized = true;
 }
 
 static void acpi_button_notify(struct acpi_device *device, u32 event)
 {
 	struct acpi_button *button = acpi_driver_data(device);
 	struct input_dev *input;
-	int users;
 
 	switch (event) {
 	case ACPI_FIXED_HARDWARE_EVENT:
@@ -395,10 +432,7 @@
 	case ACPI_BUTTON_NOTIFY_STATUS:
 		input = button->input;
 		if (button->type == ACPI_BUTTON_TYPE_LID) {
-			mutex_lock(&button->input->mutex);
-			users = button->input->users;
-			mutex_unlock(&button->input->mutex);
-			if (users)
+			if (button->lid_state_initialized)
 				acpi_lid_update_state(device, true);
 		} else {
 			int keycode;
@@ -443,7 +477,7 @@
 	struct acpi_button *button = acpi_driver_data(device);
 
 	button->suspended = false;
-	if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users) {
+	if (button->type == ACPI_BUTTON_TYPE_LID) {
 		button->last_state = !!acpi_lid_evaluate_state(device);
 		button->last_time = ktime_get();
 		acpi_lid_initialize_state(device);
--- linux-ein-5.4.0.orig/drivers/acpi/cppc_acpi.c
+++ linux-ein-5.4.0/drivers/acpi/cppc_acpi.c
@@ -118,23 +118,15 @@
  */
 #define NUM_RETRIES 500ULL
 
-struct cppc_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct kobject *kobj,
-			struct attribute *attr, char *buf);
-	ssize_t (*store)(struct kobject *kobj,
-			struct attribute *attr, const char *c, ssize_t count);
-};
-
 #define define_one_cppc_ro(_name)		\
-static struct cppc_attr _name =			\
+static struct kobj_attribute _name =		\
 __ATTR(_name, 0444, show_##_name, NULL)
 
 #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj)
 
 #define show_cppc_data(access_fn, struct_name, member_name)		\
 	static ssize_t show_##member_name(struct kobject *kobj,		\
-					struct attribute *attr,	char *buf) \
+				struct kobj_attribute *attr, char *buf)	\
 	{								\
 		struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);		\
 		struct struct_name st_name = {0};			\
@@ -160,7 +152,7 @@
 show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
 
 static ssize_t show_feedback_ctrs(struct kobject *kobj,
-		struct attribute *attr, char *buf)
+		struct kobj_attribute *attr, char *buf)
 {
 	struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);
 	struct cppc_perf_fb_ctrs fb_ctrs = {0};
@@ -634,33 +626,6 @@
 	return 0;
 }
 
-/* Check if CPPC revision + num_ent combination is supported */
-static bool is_cppc_supported(int revision, int num_ent)
-{
-	int expected_num_ent;
-
-	switch (revision) {
-	case CPPC_V2_REV:
-		expected_num_ent = CPPC_V2_NUM_ENT;
-		break;
-	case CPPC_V3_REV:
-		expected_num_ent = CPPC_V3_NUM_ENT;
-		break;
-	default:
-		pr_debug("Firmware exports unsupported CPPC revision: %d\n",
-			revision);
-		return false;
-	}
-
-	if (expected_num_ent != num_ent) {
-		pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n",
-			num_ent, expected_num_ent, revision);
-		return false;
-	}
-
-	return true;
-}
-
 /*
  * An example CPC table looks like the following.
  *
@@ -746,12 +711,16 @@
 	cpc_obj = &out_obj->package.elements[0];
 	if (cpc_obj->type == ACPI_TYPE_INTEGER)	{
 		num_ent = cpc_obj->integer.value;
+		if (num_ent <= 1) {
+			pr_debug("Unexpected _CPC NumEntries value (%d) for CPU:%d\n",
+				 num_ent, pr->id);
+			goto out_free;
+		}
 	} else {
 		pr_debug("Unexpected entry type(%d) for NumEntries\n",
 				cpc_obj->type);
 		goto out_free;
 	}
-	cpc_ptr->num_entries = num_ent;
 
 	/* Second entry should be revision. */
 	cpc_obj = &out_obj->package.elements[1];
@@ -762,10 +731,32 @@
 				cpc_obj->type);
 		goto out_free;
 	}
-	cpc_ptr->version = cpc_rev;
 
-	if (!is_cppc_supported(cpc_rev, num_ent))
+	if (cpc_rev < CPPC_V2_REV) {
+		pr_debug("Unsupported _CPC Revision (%d) for CPU:%d\n", cpc_rev,
+			 pr->id);
+		goto out_free;
+	}
+
+	/*
+	 * Disregard _CPC if the number of entries in the return pachage is not
+	 * as expected, but support future revisions being proper supersets of
+	 * the v3 and only causing more entries to be returned by _CPC.
+	 */
+	if ((cpc_rev == CPPC_V2_REV && num_ent != CPPC_V2_NUM_ENT) ||
+	    (cpc_rev == CPPC_V3_REV && num_ent != CPPC_V3_NUM_ENT) ||
+	    (cpc_rev > CPPC_V3_REV && num_ent <= CPPC_V3_NUM_ENT)) {
+		pr_debug("Unexpected number of _CPC return package entries (%d) for CPU:%d\n",
+			 num_ent, pr->id);
 		goto out_free;
+	}
+	if (cpc_rev > CPPC_V3_REV) {
+		num_ent = CPPC_V3_NUM_ENT;
+		cpc_rev = CPPC_V3_REV;
+	}
+
+	cpc_ptr->num_entries = num_ent;
+	cpc_ptr->version = cpc_rev;
 
 	/* Iterate through remaining entries in _CPC */
 	for (i = 2; i < num_ent; i++) {
@@ -865,6 +856,7 @@
 			"acpi_cppc");
 	if (ret) {
 		per_cpu(cpc_desc_ptr, pr->id) = NULL;
+		kobject_put(&cpc_ptr->kobj);
 		goto out_free;
 	}
 
--- linux-ein-5.4.0.orig/drivers/acpi/custom_method.c
+++ linux-ein-5.4.0/drivers/acpi/custom_method.c
@@ -44,6 +44,8 @@
 				   sizeof(struct acpi_table_header)))
 			return -EFAULT;
 		uncopied_bytes = max_size = table.length;
+		/* make sure the buf is not allocated */
+		kfree(buf);
 		buf = kzalloc(max_size, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
@@ -57,6 +59,7 @@
 	    (*ppos + count < count) ||
 	    (count > uncopied_bytes)) {
 		kfree(buf);
+		buf = NULL;
 		return -EINVAL;
 	}
 
@@ -78,7 +81,6 @@
 		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
 	}
 
-	kfree(buf);
 	return count;
 }
 
--- linux-ein-5.4.0.orig/drivers/acpi/device_pm.c
+++ linux-ein-5.4.0/drivers/acpi/device_pm.c
@@ -186,7 +186,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) {
@@ -273,13 +273,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;
@@ -749,7 +749,7 @@
 static DEFINE_MUTEX(acpi_wakeup_lock);
 
 static int __acpi_device_wakeup_enable(struct acpi_device *adev,
-				       u32 target_state, int max_count)
+				       u32 target_state)
 {
 	struct acpi_device_wakeup *wakeup = &adev->wakeup;
 	acpi_status status;
@@ -757,15 +757,26 @@
 
 	mutex_lock(&acpi_wakeup_lock);
 
-	if (wakeup->enable_count >= max_count)
-		goto out;
-
+	/*
+	 * If the device wakeup power is already enabled, disable it and enable
+	 * it again in case it depends on the configuration of subordinate
+	 * devices and the conditions have changed since it was enabled last
+	 * time.
+	 */
 	if (wakeup->enable_count > 0)
-		goto inc;
+		acpi_disable_wakeup_device_power(adev);
 
 	error = acpi_enable_wakeup_device_power(adev, target_state);
-	if (error)
+	if (error) {
+		if (wakeup->enable_count > 0) {
+			acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
+			wakeup->enable_count = 0;
+		}
 		goto out;
+	}
+
+	if (wakeup->enable_count > 0)
+		goto inc;
 
 	status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
 	if (ACPI_FAILURE(status)) {
@@ -778,7 +789,10 @@
 			  (unsigned int)wakeup->gpe_number);
 
 inc:
-	wakeup->enable_count++;
+	if (wakeup->enable_count < INT_MAX)
+		wakeup->enable_count++;
+	else
+		acpi_handle_info(adev->handle, "Wakeup enable count out of bounds!\n");
 
 out:
 	mutex_unlock(&acpi_wakeup_lock);
@@ -799,7 +813,7 @@
  */
 static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state)
 {
-	return __acpi_device_wakeup_enable(adev, target_state, 1);
+	return __acpi_device_wakeup_enable(adev, target_state);
 }
 
 /**
@@ -829,8 +843,12 @@
 	mutex_unlock(&acpi_wakeup_lock);
 }
 
-static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable,
-				       int max_count)
+/**
+ * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
+ * @dev: Device to enable/disable to generate wakeup events.
+ * @enable: Whether to enable or disable the wakeup functionality.
+ */
+int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
 {
 	struct acpi_device *adev;
 	int error;
@@ -850,37 +868,15 @@
 		return 0;
 	}
 
-	error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(),
-					    max_count);
+	error = __acpi_device_wakeup_enable(adev, acpi_target_system_state());
 	if (!error)
 		dev_dbg(dev, "Wakeup enabled by ACPI\n");
 
 	return error;
 }
-
-/**
- * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
- * @dev: Device to enable/disable to generate wakeup events.
- * @enable: Whether to enable or disable the wakeup functionality.
- */
-int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
-{
-	return __acpi_pm_set_device_wakeup(dev, enable, 1);
-}
 EXPORT_SYMBOL_GPL(acpi_pm_set_device_wakeup);
 
 /**
- * acpi_pm_set_bridge_wakeup - Enable/disable remote wakeup for given bridge.
- * @dev: Bridge device to enable/disable to generate wakeup events.
- * @enable: Whether to enable or disable the wakeup functionality.
- */
-int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable)
-{
-	return __acpi_pm_set_device_wakeup(dev, enable, INT_MAX);
-}
-EXPORT_SYMBOL_GPL(acpi_pm_set_bridge_wakeup);
-
-/**
  * acpi_dev_pm_low_power - Put ACPI device into a low-power state.
  * @dev: Device to put into a low-power state.
  * @adev: ACPI device node corresponding to @dev.
@@ -1314,9 +1310,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 0;
 
 	/*
--- linux-ein-5.4.0.orig/drivers/acpi/device_sysfs.c
+++ linux-ein-5.4.0/drivers/acpi/device_sysfs.c
@@ -156,8 +156,8 @@
 		return 0;
 
 	len = snprintf(modalias, size, "acpi:");
-	if (len <= 0)
-		return len;
+	if (len >= size)
+		return -ENOMEM;
 
 	size -= len;
 
@@ -210,8 +210,10 @@
 	len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
 	ACPI_FREE(buf.pointer);
 
-	if (len <= 0)
-		return len;
+	if (len >= size)
+		return -ENOMEM;
+
+	size -= len;
 
 	of_compatible = acpi_dev->data.of_compatible;
 	if (of_compatible->type == ACPI_TYPE_PACKAGE) {
@@ -251,20 +253,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;
 
@@ -333,11 +327,11 @@
 EXPORT_SYMBOL_GPL(acpi_device_modalias);
 
 static ssize_t
-acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
 }
-static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
+static DEVICE_ATTR_RO(modalias);
 
 static ssize_t real_power_state_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
@@ -366,8 +360,8 @@
 static DEVICE_ATTR_RO(power_state);
 
 static ssize_t
-acpi_eject_store(struct device *d, struct device_attribute *attr,
-		const char *buf, size_t count)
+eject_store(struct device *d, struct device_attribute *attr,
+	    const char *buf, size_t count)
 {
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	acpi_object_type not_used;
@@ -395,28 +389,28 @@
 	return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
 }
 
-static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+static DEVICE_ATTR_WO(eject);
 
 static ssize_t
-acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf)
+hid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
 	return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
 }
-static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+static DEVICE_ATTR_RO(hid);
 
-static ssize_t acpi_device_uid_show(struct device *dev,
-				    struct device_attribute *attr, char *buf)
+static ssize_t uid_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
 	return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
 }
-static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
+static DEVICE_ATTR_RO(uid);
 
-static ssize_t acpi_device_adr_show(struct device *dev,
-				    struct device_attribute *attr, char *buf)
+static ssize_t adr_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
@@ -425,16 +419,16 @@
 	else
 		return sprintf(buf, "0x%08llx\n", acpi_dev->pnp.bus_address);
 }
-static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
+static DEVICE_ATTR_RO(adr);
 
-static ssize_t acpi_device_path_show(struct device *dev,
-				     struct device_attribute *attr, char *buf)
+static ssize_t path_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
 	return acpi_object_path(acpi_dev->handle, buf);
 }
-static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+static DEVICE_ATTR_RO(path);
 
 /* sysfs file that shows description text from the ACPI _STR method */
 static ssize_t description_show(struct device *dev,
@@ -454,7 +448,7 @@
 		(wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
 		acpi_dev->pnp.str_obj->buffer.length,
 		UTF16_LITTLE_ENDIAN, buf,
-		PAGE_SIZE);
+		PAGE_SIZE - 1);
 
 	buf[result++] = '\n';
 
@@ -463,8 +457,8 @@
 static DEVICE_ATTR_RO(description);
 
 static ssize_t
-acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
-		     char *buf) {
+sun_show(struct device *dev, struct device_attribute *attr,
+	 char *buf) {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	acpi_status status;
 	unsigned long long sun;
@@ -475,11 +469,11 @@
 
 	return sprintf(buf, "%llu\n", sun);
 }
-static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
+static DEVICE_ATTR_RO(sun);
 
 static ssize_t
-acpi_device_hrv_show(struct device *dev, struct device_attribute *attr,
-		     char *buf) {
+hrv_show(struct device *dev, struct device_attribute *attr,
+	 char *buf) {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	acpi_status status;
 	unsigned long long hrv;
@@ -490,7 +484,7 @@
 
 	return sprintf(buf, "%llu\n", hrv);
 }
-static DEVICE_ATTR(hrv, 0444, acpi_device_hrv_show, NULL);
+static DEVICE_ATTR_RO(hrv);
 
 static ssize_t status_show(struct device *dev, struct device_attribute *attr,
 				char *buf) {
--- linux-ein-5.4.0.orig/drivers/acpi/dock.c
+++ linux-ein-5.4.0/drivers/acpi/dock.c
@@ -485,7 +485,7 @@
 /*
  * show_docked - read method for "docked" file in sysfs
  */
-static ssize_t show_docked(struct device *dev,
+static ssize_t docked_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
 	struct dock_station *dock_station = dev->platform_data;
@@ -494,25 +494,25 @@
 	acpi_bus_get_device(dock_station->handle, &adev);
 	return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
 }
-static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
+static DEVICE_ATTR_RO(docked);
 
 /*
  * show_flags - read method for flags file in sysfs
  */
-static ssize_t show_flags(struct device *dev,
+static ssize_t flags_show(struct device *dev,
 			  struct device_attribute *attr, char *buf)
 {
 	struct dock_station *dock_station = dev->platform_data;
 	return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
 
 }
-static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+static DEVICE_ATTR_RO(flags);
 
 /*
  * write_undock - write method for "undock" file in sysfs
  */
-static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
+static ssize_t undock_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	int ret;
 	struct dock_station *dock_station = dev->platform_data;
@@ -526,13 +526,13 @@
 	acpi_scan_lock_release();
 	return ret ? ret: count;
 }
-static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+static DEVICE_ATTR_WO(undock);
 
 /*
  * show_dock_uid - read method for "uid" file in sysfs
  */
-static ssize_t show_dock_uid(struct device *dev,
-			     struct device_attribute *attr, char *buf)
+static ssize_t uid_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	unsigned long long lbuf;
 	struct dock_station *dock_station = dev->platform_data;
@@ -543,10 +543,10 @@
 
 	return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
 }
-static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+static DEVICE_ATTR_RO(uid);
 
-static ssize_t show_dock_type(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
 	struct dock_station *dock_station = dev->platform_data;
 	char *type;
@@ -562,7 +562,7 @@
 
 	return snprintf(buf, PAGE_SIZE, "%s\n", type);
 }
-static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
+static DEVICE_ATTR_RO(type);
 
 static struct attribute *dock_attributes[] = {
 	&dev_attr_docked.attr,
--- linux-ein-5.4.0.orig/drivers/acpi/ec.c
+++ linux-ein-5.4.0/drivers/acpi/ec.c
@@ -95,12 +95,12 @@
 	EC_FLAGS_QUERY_ENABLED,		/* Query is enabled */
 	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
 	EC_FLAGS_QUERY_GUARDING,	/* Guard for SCI_EVT check */
-	EC_FLAGS_GPE_HANDLER_INSTALLED,	/* GPE handler installed */
+	EC_FLAGS_EVENT_HANDLER_INSTALLED,	/* Event handler installed */
 	EC_FLAGS_EC_HANDLER_INSTALLED,	/* OpReg handler installed */
-	EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
+	EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
 	EC_FLAGS_STARTED,		/* Driver is started */
 	EC_FLAGS_STOPPED,		/* Driver is stopped */
-	EC_FLAGS_GPE_MASKED,		/* GPE masked */
+	EC_FLAGS_EVENTS_MASKED,		/* Events masked */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -167,6 +167,7 @@
 	struct transaction transaction;
 	struct work_struct work;
 	struct acpi_ec_query_handler *handler;
+	struct acpi_ec *ec;
 };
 
 static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
@@ -179,6 +180,7 @@
 
 static struct acpi_ec *boot_ec;
 static bool boot_ec_is_ecdt = false;
+static struct workqueue_struct *ec_wq;
 static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
@@ -397,8 +399,8 @@
 static void acpi_ec_submit_request(struct acpi_ec *ec)
 {
 	ec->reference_count++;
-	if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
-	    ec->reference_count == 1)
+	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+	    ec->gpe >= 0 && ec->reference_count == 1)
 		acpi_ec_enable_gpe(ec, true);
 }
 
@@ -407,28 +409,36 @@
 	bool flushed = false;
 
 	ec->reference_count--;
-	if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
-	    ec->reference_count == 0)
+	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+	    ec->gpe >= 0 && ec->reference_count == 0)
 		acpi_ec_disable_gpe(ec, true);
 	flushed = acpi_ec_flushed(ec);
 	if (flushed)
 		wake_up(&ec->wait);
 }
 
-static void acpi_ec_mask_gpe(struct acpi_ec *ec)
+static void acpi_ec_mask_events(struct acpi_ec *ec)
 {
-	if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
-		acpi_ec_disable_gpe(ec, false);
+	if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+		if (ec->gpe >= 0)
+			acpi_ec_disable_gpe(ec, false);
+		else
+			disable_irq_nosync(ec->irq);
+
 		ec_dbg_drv("Polling enabled");
-		set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
+		set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
 	}
 }
 
-static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
+static void acpi_ec_unmask_events(struct acpi_ec *ec)
 {
-	if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
-		clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
-		acpi_ec_enable_gpe(ec, false);
+	if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+		clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
+		if (ec->gpe >= 0)
+			acpi_ec_enable_gpe(ec, false);
+		else
+			enable_irq(ec->irq);
+
 		ec_dbg_drv("Polling disabled");
 	}
 }
@@ -454,14 +464,15 @@
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-	acpi_ec_mask_gpe(ec);
+	acpi_ec_mask_events(ec);
 	if (!acpi_ec_event_enabled(ec))
 		return;
 	if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
 		ec_dbg_evt("Command(%s) submitted/blocked",
 			   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
 		ec->nr_pending_queries++;
-		schedule_work(&ec->work);
+		ec->events_in_progress++;
+		queue_work(ec_wq, &ec->work);
 	}
 }
 
@@ -470,7 +481,7 @@
 	if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
 		ec_dbg_evt("Command(%s) unblocked",
 			   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-	acpi_ec_unmask_gpe(ec);
+	acpi_ec_unmask_events(ec);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@@ -525,26 +536,10 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-static bool acpi_ec_query_flushed(struct acpi_ec *ec)
+static void __acpi_ec_flush_work(void)
 {
-	bool flushed;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ec->lock, flags);
-	flushed = !ec->nr_pending_queries;
-	spin_unlock_irqrestore(&ec->lock, flags);
-	return flushed;
-}
-
-static void __acpi_ec_flush_event(struct acpi_ec *ec)
-{
-	/*
-	 * When ec_freeze_events is true, we need to flush events in
-	 * the proper position before entering the noirq stage.
-	 */
-	wait_event(ec->wait, acpi_ec_query_flushed(ec));
-	if (ec_query_wq)
-		flush_workqueue(ec_query_wq);
+	flush_workqueue(ec_wq); /* flush ec->work */
+	flush_workqueue(ec_query_wq); /* flush queries */
 }
 
 static void acpi_ec_disable_event(struct acpi_ec *ec)
@@ -554,15 +549,21 @@
 	spin_lock_irqsave(&ec->lock, flags);
 	__acpi_ec_disable_event(ec);
 	spin_unlock_irqrestore(&ec->lock, flags);
-	__acpi_ec_flush_event(ec);
+
+	/*
+	 * When ec_freeze_events is true, we need to flush events in
+	 * the proper position before entering the noirq stage.
+	 */
+	__acpi_ec_flush_work();
 }
 
 void acpi_ec_flush_work(void)
 {
-	if (first_ec)
-		__acpi_ec_flush_event(first_ec);
+	/* Without ec_wq there is nothing to flush. */
+	if (!ec_wq)
+		return;
 
-	flush_scheduled_work();
+	__acpi_ec_flush_work();
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -648,7 +649,9 @@
 	 * ensure a hardware STS 0->1 change after this clearing can always
 	 * trigger a GPE interrupt.
 	 */
-	acpi_ec_clear_gpe(ec);
+	if (ec->gpe >= 0)
+		acpi_ec_clear_gpe(ec);
+
 	status = acpi_ec_read_status(ec);
 	t = ec->curr;
 	/*
@@ -717,7 +720,7 @@
 				++t->irq_count;
 			/* Allow triggering on 0 threshold */
 			if (t->irq_count == ec_storm_threshold)
-				acpi_ec_mask_gpe(ec);
+				acpi_ec_mask_events(ec);
 		}
 	}
 out:
@@ -815,7 +818,7 @@
 
 	spin_lock_irqsave(&ec->lock, tmp);
 	if (t->irq_count == ec_storm_threshold)
-		acpi_ec_unmask_gpe(ec);
+		acpi_ec_unmask_events(ec);
 	ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
 	/* Disable GPE for command processing (IBF=0/OBF=1) */
@@ -1053,28 +1056,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)
@@ -1133,10 +1128,11 @@
 void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
 {
 	acpi_ec_remove_query_handlers(ec, false, query_bit);
+	flush_workqueue(ec_query_wq);
 }
 EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
-static struct acpi_ec_query *acpi_ec_create_query(u8 *pval)
+static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval)
 {
 	struct acpi_ec_query *q;
 	struct transaction *t;
@@ -1144,11 +1140,13 @@
 	q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL);
 	if (!q)
 		return NULL;
+
 	INIT_WORK(&q->work, acpi_ec_event_processor);
 	t = &q->transaction;
 	t->command = ACPI_EC_COMMAND_QUERY;
 	t->rdata = pval;
 	t->rlen = 1;
+	q->ec = ec;
 	return q;
 }
 
@@ -1165,13 +1163,21 @@
 {
 	struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
 	struct acpi_ec_query_handler *handler = q->handler;
+	struct acpi_ec *ec = q->ec;
 
 	ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
+
 	if (handler->func)
 		handler->func(handler->data);
 	else if (handler->handle)
 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+
 	ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
+
+	spin_lock_irq(&ec->lock);
+	ec->queries_in_progress--;
+	spin_unlock_irq(&ec->lock);
+
 	acpi_ec_delete_query(q);
 }
 
@@ -1181,7 +1187,7 @@
 	int result;
 	struct acpi_ec_query *q;
 
-	q = acpi_ec_create_query(&value);
+	q = acpi_ec_create_query(ec, &value);
 	if (!q)
 		return -ENOMEM;
 
@@ -1203,19 +1209,20 @@
 	}
 
 	/*
-	 * It is reported that _Qxx are evaluated in a parallel way on
-	 * Windows:
+	 * It is reported that _Qxx are evaluated in a parallel way on Windows:
 	 * https://bugzilla.kernel.org/show_bug.cgi?id=94411
 	 *
-	 * Put this log entry before schedule_work() in order to make
-	 * it appearing before any other log entries occurred during the
-	 * work queue execution.
+	 * Put this log entry before queue_work() to make it appear in the log
+	 * before any other messages emitted during workqueue handling.
 	 */
 	ec_dbg_evt("Query(0x%02x) scheduled", value);
-	if (!queue_work(ec_query_wq, &q->work)) {
-		ec_dbg_evt("Query(0x%02x) overlapped", value);
-		result = -EBUSY;
-	}
+
+	spin_lock_irq(&ec->lock);
+
+	ec->queries_in_progress++;
+	queue_work(ec_query_wq, &q->work);
+
+	spin_unlock_irq(&ec->lock);
 
 err_exit:
 	if (result)
@@ -1273,20 +1280,34 @@
 	ec_dbg_evt("Event stopped");
 
 	acpi_ec_check_event(ec);
+
+	spin_lock_irqsave(&ec->lock, flags);
+	ec->events_in_progress--;
+	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
-static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
-	u32 gpe_number, void *data)
+static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
 {
 	unsigned long flags;
-	struct acpi_ec *ec = data;
 
 	spin_lock_irqsave(&ec->lock, flags);
 	advance_transaction(ec);
 	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+			       u32 gpe_number, void *data)
+{
+	acpi_ec_handle_interrupt(data);
 	return ACPI_INTERRUPT_HANDLED;
 }
 
+static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
+{
+	acpi_ec_handle_interrupt(data);
+	return IRQ_HANDLED;
+}
+
 /* --------------------------------------------------------------------------
  *                           Address Space Management
  * -------------------------------------------------------------------------- */
@@ -1359,6 +1380,8 @@
 	ec->timestamp = jiffies;
 	ec->busy_polling = true;
 	ec->polling_guard = 0;
+	ec->gpe = -1;
+	ec->irq = -1;
 	return ec;
 }
 
@@ -1406,9 +1429,13 @@
 		/* Get GPE bit assignment (EC events). */
 		/* TODO: Add support for _GPE returning a package */
 		status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
-		if (ACPI_FAILURE(status))
-			return status;
-		ec->gpe = tmp;
+		if (ACPI_SUCCESS(status))
+			ec->gpe = tmp;
+
+		/*
+		 * Errors are non-fatal, allowing for ACPI Reduced Hardware
+		 * platforms which use GpioInt instead of GPE.
+		 */
 	}
 	/* Use the global lock for all EC transactions? */
 	tmp = 0;
@@ -1418,12 +1445,45 @@
 	return AE_CTRL_TERMINATE;
 }
 
-/*
- * Note: This function returns an error code only when the address space
- *       handler is not installed, which means "not able to handle
- *       transactions".
+static bool install_gpe_event_handler(struct acpi_ec *ec)
+{
+	acpi_status status;
+
+	status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
+					      ACPI_GPE_EDGE_TRIGGERED,
+					      &acpi_ec_gpe_handler, ec);
+	if (ACPI_FAILURE(status))
+		return false;
+
+	if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1)
+		acpi_ec_enable_gpe(ec, true);
+
+	return true;
+}
+
+static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
+{
+	return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
+			   "ACPI EC", ec) >= 0;
+}
+
+/**
+ * ec_install_handlers - Install service callbacks and register query methods.
+ * @ec: Target EC.
+ * @device: ACPI device object corresponding to @ec.
+ *
+ * Install a handler for the EC address space type unless it has been installed
+ * already.  If @device is not NULL, also look for EC query methods in the
+ * namespace and register them, and install an event (either GPE or GPIO IRQ)
+ * handler for the EC, if possible.
+ *
+ * Return:
+ * -ENODEV if the address space handler cannot be installed, which means
+ *  "unable to handle transactions",
+ * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
+ * or 0 (success) otherwise.
  */
-static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
+static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
 {
 	acpi_status status;
 
@@ -1453,28 +1513,45 @@
 		set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
 	}
 
-	if (!handle_events)
+	if (!device)
 		return 0;
 
-	if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+	if (ec->gpe < 0) {
+		/* ACPI reduced hardware platforms use a GpioInt from _CRS. */
+		int irq = acpi_dev_gpio_irq_get(device, 0);
+		/*
+		 * Bail out right away for deferred probing or complete the
+		 * initialization regardless of any other errors.
+		 */
+		if (irq == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		else if (irq >= 0)
+			ec->irq = irq;
+	}
+
+	if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
 		/* Find and register all query methods */
 		acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
 				    acpi_ec_register_query_methods,
 				    NULL, ec, NULL);
-		set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+		set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
 	}
-	if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
-		status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
-					  ACPI_GPE_EDGE_TRIGGERED,
-					  &acpi_ec_gpe_handler, ec);
-		/* This is not fatal as we can poll EC events */
-		if (ACPI_SUCCESS(status)) {
-			set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+	if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+		bool ready = false;
+
+		if (ec->gpe >= 0)
+			ready = install_gpe_event_handler(ec);
+		else if (ec->irq >= 0)
+			ready = install_gpio_irq_event_handler(ec);
+
+		if (ready) {
+			set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
 			acpi_ec_leave_noirq(ec);
-			if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-			    ec->reference_count >= 1)
-				acpi_ec_enable_gpe(ec, true);
 		}
+		/*
+		 * Failures to install an event handler are not fatal, because
+		 * the EC can be polled for events.
+		 */
 	}
 	/* EC is fully operational, allow queries */
 	acpi_ec_enable_event(ec);
@@ -1504,23 +1581,28 @@
 	 */
 	acpi_ec_stop(ec, false);
 
-	if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
-		if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
-					&acpi_ec_gpe_handler)))
+	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+		if (ec->gpe >= 0 &&
+		    ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
+				 &acpi_ec_gpe_handler)))
 			pr_err("failed to remove gpe handler\n");
-		clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+
+		if (ec->irq >= 0)
+			free_irq(ec->irq, ec);
+
+		clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
 	}
-	if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+	if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
 		acpi_ec_remove_query_handlers(ec, true, 0);
-		clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+		clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
 	}
 }
 
-static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
+static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device)
 {
 	int ret;
 
-	ret = ec_install_handlers(ec, handle_events);
+	ret = ec_install_handlers(ec, device);
 	if (ret)
 		return ret;
 
@@ -1531,8 +1613,8 @@
 	}
 
 	acpi_handle_info(ec->handle,
-			 "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
-			 ec->gpe, ec->command_addr, ec->data_addr);
+			 "GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
+			 ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
 	return ret;
 }
 
@@ -1577,7 +1659,7 @@
 		status = ec_parse_device(device->handle, 0, ec, NULL);
 		if (status != AE_CTRL_TERMINATE) {
 			ret = -EINVAL;
-			goto err_alloc;
+			goto err;
 		}
 
 		if (boot_ec && ec->command_addr == boot_ec->command_addr &&
@@ -1596,9 +1678,9 @@
 		}
 	}
 
-	ret = acpi_ec_setup(ec, true);
+	ret = acpi_ec_setup(ec, device);
 	if (ret)
-		goto err_query;
+		goto err;
 
 	if (ec == boot_ec)
 		acpi_handle_info(boot_ec->handle,
@@ -1619,12 +1701,10 @@
 	acpi_handle_debug(ec->handle, "enumerated.\n");
 	return 0;
 
-err_query:
-	if (ec != boot_ec)
-		acpi_ec_remove_query_handlers(ec, true, 0);
-err_alloc:
+err:
 	if (ec != boot_ec)
 		acpi_ec_free(ec);
+
 	return ret;
 }
 
@@ -1716,7 +1796,7 @@
 	 * At this point, the GPE is not fully initialized, so do not to
 	 * handle the events.
 	 */
-	ret = acpi_ec_setup(ec, false);
+	ret = acpi_ec_setup(ec, NULL);
 	if (ret) {
 		acpi_ec_free(ec);
 		return;
@@ -1843,6 +1923,22 @@
 	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 	DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL},
 	{
+	ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BA", {
+	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+	DMI_MATCH(DMI_PRODUCT_NAME, "X505BA"),}, NULL},
+	{
+	ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BP", {
+	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+	DMI_MATCH(DMI_PRODUCT_NAME, "X505BP"),}, NULL},
+	{
+	ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BA", {
+	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+	DMI_MATCH(DMI_PRODUCT_NAME, "X542BA"),}, NULL},
+	{
+	ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BP", {
+	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+	DMI_MATCH(DMI_PRODUCT_NAME, "X542BP"),}, NULL},
+	{
 	ec_honor_ecdt_gpe, "ASUS X550VXK", {
 	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 	DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
@@ -1889,14 +1985,21 @@
 		ec->command_addr = ecdt_ptr->control.address;
 		ec->data_addr = ecdt_ptr->data.address;
 	}
-	ec->gpe = ecdt_ptr->gpe;
+
+	/*
+	 * Ignore the GPE value on Reduced Hardware platforms.
+	 * Some products have this set to an erroneous value.
+	 */
+	if (!acpi_gbl_reduced_hardware)
+		ec->gpe = ecdt_ptr->gpe;
+
 	ec->handle = ACPI_ROOT_OBJECT;
 
 	/*
 	 * At this point, the namespace is not initialized, so do not find
 	 * the namespace objects, or handle the events.
 	 */
-	ret = acpi_ec_setup(ec, false);
+	ret = acpi_ec_setup(ec, NULL);
 	if (ret) {
 		acpi_ec_free(ec);
 		return;
@@ -1928,7 +2031,7 @@
 	 * masked at the low level without side effects.
 	 */
 	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-	    ec->reference_count >= 1)
+	    ec->gpe >= 0 && ec->reference_count >= 1)
 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
 
 	acpi_ec_enter_noirq(ec);
@@ -1943,7 +2046,7 @@
 	acpi_ec_leave_noirq(ec);
 
 	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-	    ec->reference_count >= 1)
+	    ec->gpe >= 0 && ec->reference_count >= 1)
 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
 
 	return 0;
@@ -1973,16 +2076,41 @@
 
 bool acpi_ec_dispatch_gpe(void)
 {
+	bool work_in_progress;
 	u32 ret;
 
 	if (!first_ec)
-		return false;
+		return acpi_any_gpe_status_set(U32_MAX);
 
+	/*
+	 * Report wakeup if the status bit is set for any enabled GPE other
+	 * than the EC one.
+	 */
+	if (acpi_any_gpe_status_set(first_ec->gpe))
+		return true;
+
+	/*
+	 * Dispatch the EC GPE in-band, but do not report wakeup in any case
+	 * to allow the caller to process events properly after that.
+	 */
 	ret = acpi_dispatch_gpe(NULL, first_ec->gpe);
-	if (ret == ACPI_INTERRUPT_HANDLED) {
+	if (ret == ACPI_INTERRUPT_HANDLED)
 		pm_pr_dbg("EC GPE dispatched\n");
-		return true;
-	}
+
+	/* Drain EC work. */
+	do {
+		acpi_ec_flush_work();
+
+		pm_pr_dbg("ACPI EC work flushed\n");
+
+		spin_lock_irq(&first_ec->lock);
+
+		work_in_progress = first_ec->events_in_progress +
+			first_ec->queries_in_progress > 0;
+
+		spin_unlock_irq(&first_ec->lock);
+	} while (work_in_progress && !pm_wakeup_pending());
+
 	return false;
 }
 #endif /* CONFIG_PM_SLEEP */
@@ -2042,25 +2170,33 @@
 	.drv.pm = &acpi_ec_pm,
 };
 
-static inline int acpi_ec_query_init(void)
+static void acpi_ec_destroy_workqueues(void)
 {
-	if (!ec_query_wq) {
-		ec_query_wq = alloc_workqueue("kec_query", 0,
-					      ec_max_queries);
-		if (!ec_query_wq)
-			return -ENODEV;
+	if (ec_wq) {
+		destroy_workqueue(ec_wq);
+		ec_wq = NULL;
 	}
-	return 0;
-}
-
-static inline void acpi_ec_query_exit(void)
-{
 	if (ec_query_wq) {
 		destroy_workqueue(ec_query_wq);
 		ec_query_wq = NULL;
 	}
 }
 
+static int acpi_ec_init_workqueues(void)
+{
+	if (!ec_wq)
+		ec_wq = alloc_ordered_workqueue("kec", 0);
+
+	if (!ec_query_wq)
+		ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries);
+
+	if (!ec_wq || !ec_query_wq) {
+		acpi_ec_destroy_workqueues();
+		return -ENODEV;
+	}
+	return 0;
+}
+
 static const struct dmi_system_id acpi_ec_no_wakeup[] = {
 	{
 		.ident = "Thinkpad X1 Carbon 6th",
@@ -2070,13 +2206,6 @@
 		},
 	},
 	{
-		.ident = "ThinkPad X1 Carbon 6th",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"),
-		},
-	},
-	{
 		.ident = "ThinkPad X1 Yoga 3rd",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -2091,8 +2220,7 @@
 	int result;
 	int ecdt_fail, dsdt_fail;
 
-	/* register workqueue for _Qxx evaluations */
-	result = acpi_ec_query_init();
+	result = acpi_ec_init_workqueues();
 	if (result)
 		return result;
 
@@ -2123,6 +2251,6 @@
 {
 
 	acpi_bus_unregister_driver(&acpi_ec_driver);
-	acpi_ec_query_exit();
+	acpi_ec_destroy_workqueues();
 }
 #endif	/* 0 */
--- linux-ein-5.4.0.orig/drivers/acpi/evged.c
+++ linux-ein-5.4.0/drivers/acpi/evged.c
@@ -79,6 +79,8 @@
 	struct resource r;
 	struct acpi_resource_irq *p = &ares->data.irq;
 	struct acpi_resource_extended_irq *pext = &ares->data.extended_irq;
+	char ev_name[5];
+	u8 trigger;
 
 	if (ares->type == ACPI_RESOURCE_TYPE_END_TAG)
 		return AE_OK;
@@ -87,14 +89,28 @@
 		dev_err(dev, "unable to parse IRQ resource\n");
 		return AE_ERROR;
 	}
-	if (ares->type == ACPI_RESOURCE_TYPE_IRQ)
+	if (ares->type == ACPI_RESOURCE_TYPE_IRQ) {
 		gsi = p->interrupts[0];
-	else
+		trigger = p->triggering;
+	} else {
 		gsi = pext->interrupts[0];
+		trigger = pext->triggering;
+	}
 
 	irq = r.start;
 
-	if (ACPI_FAILURE(acpi_get_handle(handle, "_EVT", &evt_handle))) {
+	switch (gsi) {
+	case 0 ... 255:
+		sprintf(ev_name, "_%c%02X",
+			trigger == ACPI_EDGE_SENSITIVE ? 'E' : 'L', gsi);
+
+		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
+			break;
+		/* fall through */
+	default:
+		if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
+			break;
+
 		dev_err(dev, "cannot locate _EVT method\n");
 		return AE_ERROR;
 	}
--- linux-ein-5.4.0.orig/drivers/acpi/hmat/hmat.c
+++ linux-ein-5.4.0/drivers/acpi/hmat/hmat.c
@@ -403,7 +403,8 @@
 		pr_info("HMAT: Memory Flags:%04x Processor Domain:%d Memory Domain:%d\n",
 			p->flags, p->processor_PD, p->memory_PD);
 
-	if (p->flags & ACPI_HMAT_MEMORY_PD_VALID && hmat_revision == 1) {
+	if ((hmat_revision == 1 && p->flags & ACPI_HMAT_MEMORY_PD_VALID) ||
+	    hmat_revision > 1) {
 		target = find_mem_target(p->memory_PD);
 		if (!target) {
 			pr_debug("HMAT: Memory Domain missing from SRAT\n");
--- linux-ein-5.4.0.orig/drivers/acpi/internal.h
+++ linux-ein-5.4.0/drivers/acpi/internal.h
@@ -9,6 +9,8 @@
 #ifndef _ACPI_INTERNAL_H_
 #define _ACPI_INTERNAL_H_
 
+#include <linux/idr.h>
+
 #define PREFIX "ACPI: "
 
 int early_acpi_osi_init(void);
@@ -96,9 +98,11 @@
 
 extern struct list_head acpi_bus_id_list;
 
+#define ACPI_MAX_DEVICE_INSTANCES	4096
+
 struct acpi_device_bus_id {
-	char bus_id[15];
-	unsigned int instance_no;
+	const char *bus_id;
+	struct ida instance_ida;
 	struct list_head node;
 };
 
@@ -165,7 +169,8 @@
    -------------------------------------------------------------------------- */
 struct acpi_ec {
 	acpi_handle handle;
-	u32 gpe;
+	int gpe;
+	int irq;
 	unsigned long command_addr;
 	unsigned long data_addr;
 	bool global_lock;
@@ -179,6 +184,8 @@
 	struct work_struct work;
 	unsigned long timestamp;
 	unsigned long nr_pending_queries;
+	unsigned int events_in_progress;
+	unsigned int queries_in_progress;
 	bool busy_polling;
 	unsigned int polling_guard;
 };
--- linux-ein-5.4.0.orig/drivers/acpi/irq.c
+++ linux-ein-5.4.0/drivers/acpi/irq.c
@@ -52,6 +52,7 @@
 		      int polarity)
 {
 	struct irq_fwspec fwspec;
+	unsigned int irq;
 
 	if (WARN_ON(!acpi_gsi_domain_id)) {
 		pr_warn("GSI: No registered irqchip, giving up\n");
@@ -63,7 +64,11 @@
 	fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
 	fwspec.param_count = 2;
 
-	return irq_create_fwspec_mapping(&fwspec);
+	irq = irq_create_fwspec_mapping(&fwspec);
+	if (!irq)
+		return -EINVAL;
+
+	return irq;
 }
 EXPORT_SYMBOL_GPL(acpi_register_gsi);
 
--- linux-ein-5.4.0.orig/drivers/acpi/nfit/core.c
+++ linux-ein-5.4.0/drivers/acpi/nfit/core.c
@@ -360,7 +360,7 @@
 
 static u8 nfit_dsm_revid(unsigned family, unsigned func)
 {
-	static const u8 revid_table[NVDIMM_FAMILY_MAX+1][32] = {
+	static const u8 revid_table[NVDIMM_FAMILY_MAX+1][NVDIMM_CMD_MAX+1] = {
 		[NVDIMM_FAMILY_INTEL] = {
 			[NVDIMM_INTEL_GET_MODES] = 2,
 			[NVDIMM_INTEL_GET_FWINFO] = 2,
@@ -386,7 +386,7 @@
 
 	if (family > NVDIMM_FAMILY_MAX)
 		return 0;
-	if (func > 31)
+	if (func > NVDIMM_CMD_MAX)
 		return 0;
 	id = revid_table[family][func];
 	if (id == 0)
@@ -492,7 +492,8 @@
 	 * Check for a valid command.  For ND_CMD_CALL, we also have to
 	 * make sure that the DSM function is supported.
 	 */
-	if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask))
+	if (cmd == ND_CMD_CALL &&
+	    (func > NVDIMM_CMD_MAX || !test_bit(func, &dsm_mask)))
 		return -ENOTTY;
 	else if (!test_bit(cmd, &cmd_mask))
 		return -ENOTTY;
@@ -1552,7 +1553,7 @@
 					le16_to_cpu(nfit_dcr->dcr->code));
 			break;
 		}
-		if (rc != ENXIO)
+		if (rc != -ENXIO)
 			break;
 	}
 	mutex_unlock(&acpi_desc->init_mutex);
@@ -2972,6 +2973,9 @@
 		struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
 		struct nd_mapping_desc *mapping;
 
+		/* range index 0 == unmapped in SPA or invalid-SPA */
+		if (memdev->range_index == 0 || spa->range_index == 0)
+			continue;
 		if (memdev->range_index != spa->range_index)
 			continue;
 		if (count >= ND_MAX_MAPPINGS) {
@@ -3499,7 +3503,8 @@
 	if (nvdimm && cmd == ND_CMD_CALL &&
 			call_pkg->nd_family == NVDIMM_FAMILY_INTEL) {
 		func = call_pkg->nd_command;
-		if ((1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
+		if (func > NVDIMM_CMD_MAX ||
+		    (1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
 			return -EOPNOTSUPP;
 	}
 
@@ -3594,8 +3599,8 @@
 
 	mutex_lock(&acpi_desc->init_mutex);
 	set_bit(ARS_CANCEL, &acpi_desc->scrub_flags);
-	cancel_delayed_work_sync(&acpi_desc->dwork);
 	mutex_unlock(&acpi_desc->init_mutex);
+	cancel_delayed_work_sync(&acpi_desc->dwork);
 
 	/*
 	 * Bounce the nvdimm bus lock to make sure any in-flight
--- linux-ein-5.4.0.orig/drivers/acpi/nfit/nfit.h
+++ linux-ein-5.4.0/drivers/acpi/nfit/nfit.h
@@ -34,6 +34,7 @@
 		| ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED)
 
 #define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
+#define NVDIMM_CMD_MAX 31
 
 #define NVDIMM_STANDARD_CMDMASK \
 (1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \
--- linux-ein-5.4.0.orig/drivers/acpi/numa.c
+++ linux-ein-5.4.0/drivers/acpi/numa.c
@@ -31,7 +31,7 @@
 
 int pxm_to_node(int pxm)
 {
-	if (pxm < 0)
+	if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
 		return NUMA_NO_NODE;
 	return pxm_to_node_map[pxm];
 }
--- linux-ein-5.4.0.orig/drivers/acpi/osi.c
+++ linux-ein-5.4.0/drivers/acpi/osi.c
@@ -468,6 +468,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.
 	 */
--- linux-ein-5.4.0.orig/drivers/acpi/osl.c
+++ linux-ein-5.4.0/drivers/acpi/osl.c
@@ -374,19 +374,21 @@
 }
 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);
 }
 
 /**
@@ -406,6 +408,7 @@
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 {
 	struct acpi_ioremap *map;
+	unsigned long refcount;
 
 	if (!acpi_permanent_mmap) {
 		__acpi_unmap_table(virt, size);
@@ -419,10 +422,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);
 
@@ -457,6 +461,7 @@
 {
 	u64 addr;
 	struct acpi_ioremap *map;
+	unsigned long refcount;
 
 	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
 		return;
@@ -472,10 +477,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);
 
--- linux-ein-5.4.0.orig/drivers/acpi/pci_mcfg.c
+++ linux-ein-5.4.0/drivers/acpi/pci_mcfg.c
@@ -41,6 +41,8 @@
 static struct mcfg_fixup mcfg_quirks[] = {
 /*	{ OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */
 
+#ifdef CONFIG_ARM64
+
 #define AL_ECAM(table_id, rev, seg, ops) \
 	{ "AMAZON", table_id, rev, seg, MCFG_BUS_ANY, ops }
 
@@ -142,6 +144,27 @@
 	XGENE_V2_ECAM_MCFG(4, 0),
 	XGENE_V2_ECAM_MCFG(4, 1),
 	XGENE_V2_ECAM_MCFG(4, 2),
+
+#define ALTRA_ECAM_QUIRK(rev, seg) \
+	{ "Ampere", "Altra   ", rev, seg, MCFG_BUS_ANY, &pci_32b_read_ops }
+
+	ALTRA_ECAM_QUIRK(1, 0),
+	ALTRA_ECAM_QUIRK(1, 1),
+	ALTRA_ECAM_QUIRK(1, 2),
+	ALTRA_ECAM_QUIRK(1, 3),
+	ALTRA_ECAM_QUIRK(1, 4),
+	ALTRA_ECAM_QUIRK(1, 5),
+	ALTRA_ECAM_QUIRK(1, 6),
+	ALTRA_ECAM_QUIRK(1, 7),
+	ALTRA_ECAM_QUIRK(1, 8),
+	ALTRA_ECAM_QUIRK(1, 9),
+	ALTRA_ECAM_QUIRK(1, 10),
+	ALTRA_ECAM_QUIRK(1, 11),
+	ALTRA_ECAM_QUIRK(1, 12),
+	ALTRA_ECAM_QUIRK(1, 13),
+	ALTRA_ECAM_QUIRK(1, 14),
+	ALTRA_ECAM_QUIRK(1, 15),
+#endif /* ARM64 */
 };
 
 static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
--- linux-ein-5.4.0.orig/drivers/acpi/pmic/intel_pmic.c
+++ linux-ein-5.4.0/drivers/acpi/pmic/intel_pmic.c
@@ -211,31 +211,36 @@
 		void *handler_context, void *region_context)
 {
 	struct intel_pmic_opregion *opregion = region_context;
-	int result = 0;
+	int result = -EINVAL;
 
-	switch (address) {
-	case 0:
-		return AE_OK;
-	case 1:
-		opregion->ctx.addr |= (*value64 & 0xff) << 8;
-		return AE_OK;
-	case 2:
-		opregion->ctx.addr |= *value64 & 0xff;
-		return AE_OK;
-	case 3:
-		opregion->ctx.val = *value64 & 0xff;
-		return AE_OK;
-	case 4:
-		if (*value64) {
-			result = regmap_write(opregion->regmap, opregion->ctx.addr,
-					      opregion->ctx.val);
-		} else {
-			result = regmap_read(opregion->regmap, opregion->ctx.addr,
-					     &opregion->ctx.val);
-			if (result == 0)
-				*value64 = opregion->ctx.val;
+	if (function == ACPI_WRITE) {
+		switch (address) {
+		case 0:
+			return AE_OK;
+		case 1:
+			opregion->ctx.addr |= (*value64 & 0xff) << 8;
+			return AE_OK;
+		case 2:
+			opregion->ctx.addr |= *value64 & 0xff;
+			return AE_OK;
+		case 3:
+			opregion->ctx.val = *value64 & 0xff;
+			return AE_OK;
+		case 4:
+			if (*value64) {
+				result = regmap_write(opregion->regmap, opregion->ctx.addr,
+						      opregion->ctx.val);
+			} else {
+				result = regmap_read(opregion->regmap, opregion->ctx.addr,
+						     &opregion->ctx.val);
+			}
+			opregion->ctx.addr = 0;
 		}
-		memset(&opregion->ctx, 0x00, sizeof(opregion->ctx));
+	}
+
+	if (function == ACPI_READ && address == 3) {
+		*value64 = opregion->ctx.val;
+		return AE_OK;
 	}
 
 	if (result < 0) {
--- linux-ein-5.4.0.orig/drivers/acpi/power.c
+++ linux-ein-5.4.0/drivers/acpi/power.c
@@ -888,15 +888,16 @@
 	kfree(resource);
 }
 
-static ssize_t acpi_power_in_use_show(struct device *dev,
-				      struct device_attribute *attr,
-				      char *buf) {
+static ssize_t resource_in_use_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
 	struct acpi_power_resource *resource;
 
 	resource = to_power_resource(to_acpi_device(dev));
 	return sprintf(buf, "%u\n", !!resource->ref_count);
 }
-static DEVICE_ATTR(resource_in_use, 0444, acpi_power_in_use_show, NULL);
+static DEVICE_ATTR_RO(resource_in_use);
 
 static void acpi_power_sysfs_remove(struct acpi_device *device)
 {
--- linux-ein-5.4.0.orig/drivers/acpi/processor_idle.c
+++ linux-ein-5.4.0/drivers/acpi/processor_idle.c
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 #include <linux/dmi.h>
 #include <linux/sched.h>       /* need_resched() */
+#include <linux/sort.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu.h>
@@ -540,10 +541,37 @@
 	return;
 }
 
+static int acpi_cst_latency_cmp(const void *a, const void *b)
+{
+	const struct acpi_processor_cx *x = a, *y = b;
+
+	if (!(x->valid && y->valid))
+		return 0;
+	if (x->latency > y->latency)
+		return 1;
+	if (x->latency < y->latency)
+		return -1;
+	return 0;
+}
+static void acpi_cst_latency_swap(void *a, void *b, int n)
+{
+	struct acpi_processor_cx *x = a, *y = b;
+	u32 tmp;
+
+	if (!(x->valid && y->valid))
+		return;
+	tmp = x->latency;
+	x->latency = y->latency;
+	y->latency = tmp;
+}
+
 static int acpi_processor_power_verify(struct acpi_processor *pr)
 {
 	unsigned int i;
 	unsigned int working = 0;
+	unsigned int last_latency = 0;
+	unsigned int last_type = 0;
+	bool buggy_latency = false;
 
 	pr->power.timer_broadcast_on_state = INT_MAX;
 
@@ -567,12 +595,24 @@
 		}
 		if (!cx->valid)
 			continue;
+		if (cx->type >= last_type && cx->latency < last_latency)
+			buggy_latency = true;
+		last_latency = cx->latency;
+		last_type = cx->type;
 
 		lapic_timer_check_state(i, pr, cx);
 		tsc_check_state(cx->type);
 		working++;
 	}
 
+	if (buggy_latency) {
+		pr_notice("FW issue: working around C-state latencies out of order\n");
+		sort(&pr->power.states[1], max_cstate,
+		     sizeof(struct acpi_processor_cx),
+		     acpi_cst_latency_cmp,
+		     acpi_cst_latency_swap);
+	}
+
 	lapic_timer_propagate_broadcast(pr);
 
 	return (working);
@@ -642,6 +682,36 @@
 	return bm_status;
 }
 
+static void wait_for_freeze(void)
+{
+#ifdef	CONFIG_X86
+	/* No delay is needed if we are in guest */
+	if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+		return;
+	/*
+	 * Modern (>=Nehalem) Intel systems use ACPI via intel_idle,
+	 * not this code.  Assume that any Intel systems using this
+	 * are ancient and may need the dummy wait.  This also assumes
+	 * that the motivating chipset issue was Intel-only.
+	 */
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+		return;
+#endif
+	/*
+	 * Dummy wait op - must do something useless after P_LVL2 read
+	 * because chipsets cannot guarantee that STPCLK# signal gets
+	 * asserted in time to freeze execution properly
+	 *
+	 * This workaround has been in place since the original ACPI
+	 * implementation was merged, circa 2002.
+	 *
+	 * If a profile is pointing to this instruction, please first
+	 * consider moving your system to a more modern idle
+	 * mechanism.
+	 */
+	inl(acpi_gbl_FADT.xpm_timer_block.address);
+}
+
 /**
  * acpi_idle_do_entry - enter idle state using the appropriate method
  * @cx: cstate data
@@ -658,10 +728,7 @@
 	} else {
 		/* IO port based C-state */
 		inb(cx->address);
-		/* Dummy wait op - must do something useless after P_LVL2 read
-		   because chipsets cannot guarantee that STPCLK# signal
-		   gets asserted in time to freeze execution properly. */
-		inl(acpi_gbl_FADT.xpm_timer_block.address);
+		wait_for_freeze();
 	}
 }
 
@@ -682,8 +749,7 @@
 			safe_halt();
 		else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
 			inb(cx->address);
-			/* See comment in acpi_idle_do_entry() */
-			inl(acpi_gbl_FADT.xpm_timer_block.address);
+			wait_for_freeze();
 		} else
 			return -ENODEV;
 	}
@@ -1161,6 +1227,11 @@
 	return 0;
 }
 
+int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
+{
+	return -EOPNOTSUPP;
+}
+
 static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
 {
 	int ret, i;
@@ -1169,6 +1240,11 @@
 	struct acpi_device *d = NULL;
 	struct acpi_lpi_states_array info[2], *tmp, *prev, *curr;
 
+	/* make sure our architecture has support */
+	ret = acpi_processor_ffh_lpi_probe(pr->id);
+	if (ret == -EOPNOTSUPP)
+		return ret;
+
 	if (!osc_pc_lpi_support_confirmed)
 		return -EOPNOTSUPP;
 
@@ -1220,11 +1296,6 @@
 	return 0;
 }
 
-int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
-{
-	return -ENODEV;
-}
-
 int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
 {
 	return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/acpi/processor_perflib.c
+++ linux-ein-5.4.0/drivers/acpi/processor_perflib.c
@@ -56,6 +56,8 @@
 {
 	acpi_status status = 0;
 	unsigned long long ppc = 0;
+	s32 qos_value;
+	int index;
 	int ret;
 
 	if (!pr)
@@ -75,17 +77,30 @@
 		return -ENODEV;
 	}
 
+	index = ppc;
+
+	if (pr->performance_platform_limit == index ||
+	    ppc >= pr->performance->state_count)
+		return 0;
+
 	pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
-		       (int)ppc, ppc ? "" : "not");
+		 index, index ? "is" : "is not");
 
-	pr->performance_platform_limit = (int)ppc;
+	pr->performance_platform_limit = index;
 
-	if (ppc >= pr->performance->state_count ||
-	    unlikely(!freq_qos_request_active(&pr->perflib_req)))
+	if (unlikely(!freq_qos_request_active(&pr->perflib_req)))
 		return 0;
 
-	ret = freq_qos_update_request(&pr->perflib_req,
-			pr->performance->states[ppc].core_frequency * 1000);
+	/*
+	 * If _PPC returns 0, it means that all of the available states can be
+	 * used ("no limit").
+	 */
+	if (index == 0)
+		qos_value = FREQ_QOS_MAX_DEFAULT_VALUE;
+	else
+		qos_value = pr->performance->states[index].core_frequency * 1000;
+
+	ret = freq_qos_update_request(&pr->perflib_req, qos_value);
 	if (ret < 0) {
 		pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
 			pr->id, ret);
@@ -168,9 +183,16 @@
 		if (!pr)
 			continue;
 
+		/*
+		 * Reset performance_platform_limit in case there is a stale
+		 * value in it, so as to make it match the "no limit" QoS value
+		 * below.
+		 */
+		pr->performance_platform_limit = 0;
+
 		ret = freq_qos_add_request(&policy->constraints,
-					   &pr->perflib_req,
-					   FREQ_QOS_MAX, INT_MAX);
+					   &pr->perflib_req, FREQ_QOS_MAX,
+					   FREQ_QOS_MAX_DEFAULT_VALUE);
 		if (ret < 0)
 			pr_err("Failed to add freq constraint for CPU%d (%d)\n",
 			       cpu, ret);
--- linux-ein-5.4.0.orig/drivers/acpi/processor_thermal.c
+++ linux-ein-5.4.0/drivers/acpi/processor_thermal.c
@@ -150,7 +150,7 @@
 	unsigned int cpu;
 
 	for_each_cpu(cpu, policy->related_cpus) {
-		struct acpi_processor *pr = per_cpu(processors, policy->cpu);
+		struct acpi_processor *pr = per_cpu(processors, cpu);
 
 		if (pr)
 			freq_qos_remove_request(&pr->thermal_req);
--- linux-ein-5.4.0.orig/drivers/acpi/processor_throttling.c
+++ linux-ein-5.4.0/drivers/acpi/processor_throttling.c
@@ -897,13 +897,6 @@
 	return pr->throttling.acpi_processor_get_throttling(pr);
 }
 
-static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct)
-{
-	if (direct || (is_percpu_thread() && cpu == smp_processor_id()))
-		return fn(arg);
-	return work_on_cpu(cpu, fn, arg);
-}
-
 static int acpi_processor_get_throttling(struct acpi_processor *pr)
 {
 	if (!pr)
--- linux-ein-5.4.0.orig/drivers/acpi/property.c
+++ linux-ein-5.4.0/drivers/acpi/property.c
@@ -152,10 +152,10 @@
 	return acpi_nondev_subnode_data_ok(handle, link, list, parent);
 }
 
-static int acpi_add_nondev_subnodes(acpi_handle scope,
-				    const union acpi_object *links,
-				    struct list_head *list,
-				    struct fwnode_handle *parent)
+static bool acpi_add_nondev_subnodes(acpi_handle scope,
+				     const union acpi_object *links,
+				     struct list_head *list,
+				     struct fwnode_handle *parent)
 {
 	bool ret = false;
 	int i;
@@ -430,6 +430,16 @@
 		acpi_extract_apple_properties(adev);
 }
 
+static void acpi_free_device_properties(struct list_head *list)
+{
+	struct acpi_device_properties *props, *tmp;
+
+	list_for_each_entry_safe(props, tmp, list, list) {
+		list_del(&props->list);
+		kfree(props);
+	}
+}
+
 static void acpi_destroy_nondev_subnodes(struct list_head *list)
 {
 	struct acpi_data_node *dn, *next;
@@ -442,22 +452,18 @@
 		wait_for_completion(&dn->kobj_done);
 		list_del(&dn->sibling);
 		ACPI_FREE((void *)dn->data.pointer);
+		acpi_free_device_properties(&dn->data.properties);
 		kfree(dn);
 	}
 }
 
 void acpi_free_properties(struct acpi_device *adev)
 {
-	struct acpi_device_properties *props, *tmp;
-
 	acpi_destroy_nondev_subnodes(&adev->data.subnodes);
 	ACPI_FREE((void *)adev->data.pointer);
 	adev->data.of_compatible = NULL;
 	adev->data.pointer = NULL;
-	list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
-		list_del(&props->list);
-		kfree(props);
-	}
+	acpi_free_device_properties(&adev->data.properties);
 }
 
 /**
@@ -640,6 +646,7 @@
  * @index: Index of the reference to return
  * @num_args: Maximum number of arguments after each reference
  * @args: Location to store the returned reference with optional arguments
+ *	  (may be NULL)
  *
  * Find property with @name, verifify that it is a package containing at least
  * one object reference and if so, store the ACPI device object pointer to the
@@ -692,12 +699,15 @@
 	 */
 	if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
 		if (index)
-			return -EINVAL;
+			return -ENOENT;
 
 		ret = acpi_bus_get_device(obj->reference.handle, &device);
 		if (ret)
 			return ret == -ENODEV ? -EINVAL : ret;
 
+		if (!args)
+			return 0;
+
 		args->fwnode = acpi_fwnode_handle(device);
 		args->nargs = 0;
 		return 0;
@@ -794,9 +804,6 @@
 	const union acpi_object *obj;
 	int ret;
 
-	if (!val)
-		return -EINVAL;
-
 	if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
 		ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
 		if (ret)
@@ -806,28 +813,43 @@
 		case DEV_PROP_U8:
 			if (obj->integer.value > U8_MAX)
 				return -EOVERFLOW;
-			*(u8 *)val = obj->integer.value;
+
+			if (val)
+				*(u8 *)val = obj->integer.value;
+
 			break;
 		case DEV_PROP_U16:
 			if (obj->integer.value > U16_MAX)
 				return -EOVERFLOW;
-			*(u16 *)val = obj->integer.value;
+
+			if (val)
+				*(u16 *)val = obj->integer.value;
+
 			break;
 		case DEV_PROP_U32:
 			if (obj->integer.value > U32_MAX)
 				return -EOVERFLOW;
-			*(u32 *)val = obj->integer.value;
+
+			if (val)
+				*(u32 *)val = obj->integer.value;
+
 			break;
 		default:
-			*(u64 *)val = obj->integer.value;
+			if (val)
+				*(u64 *)val = obj->integer.value;
+
 			break;
 		}
+
+		if (!val)
+			return 1;
 	} else if (proptype == DEV_PROP_STRING) {
 		ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
 		if (ret)
 			return ret;
 
-		*(char **)val = obj->string.pointer;
+		if (val)
+			*(char **)val = obj->string.pointer;
 
 		return 1;
 	} else {
@@ -841,7 +863,7 @@
 {
 	int ret;
 
-	if (!adev)
+	if (!adev || !val)
 		return -EINVAL;
 
 	ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
@@ -935,10 +957,20 @@
 	const union acpi_object *items;
 	int ret;
 
-	if (val && nval == 1) {
+	if (nval == 1 || !val) {
 		ret = acpi_data_prop_read_single(data, propname, proptype, val);
-		if (ret >= 0)
+		/*
+		 * The overflow error means that the property is there and it is
+		 * single-value, but its type does not match, so return.
+		 */
+		if (ret >= 0 || ret == -EOVERFLOW)
 			return ret;
+
+		/*
+		 * Reading this property as a single-value one failed, but its
+		 * value may still be represented as one-element array, so
+		 * continue.
+		 */
 	}
 
 	ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
--- linux-ein-5.4.0.orig/drivers/acpi/resource.c
+++ linux-ein-5.4.0/drivers/acpi/resource.c
@@ -16,6 +16,7 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/irq.h>
+#include <linux/dmi.h>
 
 #ifdef CONFIG_X86
 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
@@ -380,21 +381,150 @@
 }
 EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
 
-static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
+static const struct dmi_system_id medion_laptop[] = {
+	{
+		.ident = "MEDION P15651",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_BOARD_NAME, "M15T"),
+		},
+	},
+	{
+		.ident = "MEDION S17405",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_BOARD_NAME, "M17T"),
+		},
+	},
+	{ }
+};
+
+static const struct dmi_system_id asus_laptop[] = {
+	{
+		.ident = "Asus Vivobook K3402ZA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "K3402ZA"),
+		},
+	},
+	{
+		.ident = "Asus Vivobook K3502ZA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "K3502ZA"),
+		},
+	},
+	{
+		.ident = "Asus Vivobook S5402ZA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "S5402ZA"),
+		},
+	},
+	{
+		.ident = "Asus Vivobook S5602ZA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"),
+		},
+	},
+	{
+		.ident = "Asus ExpertBook B1402CBA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"),
+		},
+	},
+	{
+		.ident = "Asus ExpertBook B1502CBA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"),
+		},
+	},
+	{
+		.ident = "Asus ExpertBook B2402CBA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "B2402CBA"),
+		},
+	},
+	{
+		/* TongFang GMxXGxx/TUXEDO Polaris 15 Gen5 AMD */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
+		},
+	},
+	{
+		/* Asus ExpertBook B1402CVA */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "B1402CVA"),
+		},
+	},
+	{
+		/* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Eluktronics Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "RP-15"),
+		},
+	},
+	{
+		/* TongFang GM6XGxX/TUXEDO Stellaris 16 Gen5 AMD */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
+		},
+	},
+	{
+		.ident = "Asus ExpertBook B2502",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"),
+		},
+	},
+	{ }
+};
+
+struct irq_override_cmp {
+	const struct dmi_system_id *system;
+	unsigned char irq;
+	unsigned char triggering;
+	unsigned char polarity;
+	unsigned char shareable;
+};
+
+static const struct irq_override_cmp skip_override_table[] = {
+	{ medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0 },
+	{ asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0 },
+};
+
+static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
+				  u8 shareable)
 {
-	res->start = gsi;
-	res->end = gsi;
-	res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skip_override_table); i++) {
+		const struct irq_override_cmp *entry = &skip_override_table[i];
+
+		if (dmi_check_system(entry->system) &&
+		    entry->irq == gsi &&
+		    entry->triggering == triggering &&
+		    entry->polarity == polarity &&
+		    entry->shareable == shareable)
+			return false;
+	}
+
+	return true;
 }
 
 static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
 				     u8 triggering, u8 polarity, u8 shareable,
-				     bool legacy)
+				     bool check_override)
 {
 	int irq, p, t;
 
 	if (!valid_IRQ(gsi)) {
-		acpi_dev_irqresource_disabled(res, gsi);
+		irqresource_disabled(res, gsi);
 		return;
 	}
 
@@ -408,7 +538,9 @@
 	 * using extended IRQ descriptors we take the IRQ configuration
 	 * from _CRS directly.
 	 */
-	if (legacy && !acpi_get_override_irq(gsi, &t, &p)) {
+	if (check_override &&
+	    acpi_dev_irq_override(gsi, triggering, polarity, shareable) &&
+	    !acpi_get_override_irq(gsi, &t, &p)) {
 		u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
 		u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
 
@@ -426,7 +558,7 @@
 		res->start = irq;
 		res->end = irq;
 	} else {
-		acpi_dev_irqresource_disabled(res, gsi);
+		irqresource_disabled(res, gsi);
 	}
 }
 
@@ -463,7 +595,7 @@
 		 */
 		irq = &ares->data.irq;
 		if (index >= irq->interrupt_count) {
-			acpi_dev_irqresource_disabled(res, 0);
+			irqresource_disabled(res, 0);
 			return false;
 		}
 		acpi_dev_get_irqresource(res, irq->interrupts[index],
@@ -473,7 +605,7 @@
 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 		ext_irq = &ares->data.extended_irq;
 		if (index >= ext_irq->interrupt_count) {
-			acpi_dev_irqresource_disabled(res, 0);
+			irqresource_disabled(res, 0);
 			return false;
 		}
 		if (is_gsi(ext_irq))
@@ -481,7 +613,7 @@
 					 ext_irq->triggering, ext_irq->polarity,
 					 ext_irq->shareable, false);
 		else
-			acpi_dev_irqresource_disabled(res, 0);
+			irqresource_disabled(res, 0);
 		break;
 	default:
 		res->flags = 0;
@@ -541,7 +673,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-ein-5.4.0.orig/drivers/acpi/scan.c
+++ linux-ein-5.4.0/drivers/acpi/scan.c
@@ -483,10 +483,10 @@
 	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
 		if (!strcmp(acpi_device_bus_id->bus_id,
 			    acpi_device_hid(device))) {
-			if (acpi_device_bus_id->instance_no > 0)
-				acpi_device_bus_id->instance_no--;
-			else {
+			ida_simple_remove(&acpi_device_bus_id->instance_ida, device->pnp.instance_no);
+			if (ida_is_empty(&acpi_device_bus_id->instance_ida)) {
 				list_del(&acpi_device_bus_id->node);
+				kfree_const(acpi_device_bus_id->bus_id);
 				kfree(acpi_device_bus_id);
 			}
 			break;
@@ -586,6 +586,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) {
@@ -621,12 +623,38 @@
 	put_device(&adev->dev);
 }
 
+static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id)
+{
+	struct acpi_device_bus_id *acpi_device_bus_id;
+
+	/* Find suitable bus_id and instance number in acpi_bus_id_list. */
+	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+		if (!strcmp(acpi_device_bus_id->bus_id, dev_id))
+			return acpi_device_bus_id;
+	}
+	return NULL;
+}
+
+static int acpi_device_set_name(struct acpi_device *device,
+				struct acpi_device_bus_id *acpi_device_bus_id)
+{
+	struct ida *instance_ida = &acpi_device_bus_id->instance_ida;
+	int result;
+
+	result = ida_simple_get(instance_ida, 0, ACPI_MAX_DEVICE_INSTANCES, GFP_KERNEL);
+	if (result < 0)
+		return result;
+
+	device->pnp.instance_no = result;
+	dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, result);
+	return 0;
+}
+
 int acpi_device_add(struct acpi_device *device,
 		    void (*release)(struct device *))
 {
+	struct acpi_device_bus_id *acpi_device_bus_id;
 	int result;
-	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
-	int found = 0;
 
 	if (device->handle) {
 		acpi_status status;
@@ -652,34 +680,39 @@
 	INIT_LIST_HEAD(&device->del_list);
 	mutex_init(&device->physical_node_lock);
 
-	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
-	if (!new_bus_id) {
-		pr_err(PREFIX "Memory allocation error\n");
-		result = -ENOMEM;
-		goto err_detach;
-	}
-
 	mutex_lock(&acpi_device_lock);
-	/*
-	 * Find suitable bus_id and instance number in acpi_bus_id_list
-	 * If failed, create one and link it into acpi_bus_id_list
-	 */
-	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
-		if (!strcmp(acpi_device_bus_id->bus_id,
-			    acpi_device_hid(device))) {
-			acpi_device_bus_id->instance_no++;
-			found = 1;
-			kfree(new_bus_id);
-			break;
+
+	acpi_device_bus_id = acpi_device_bus_id_match(acpi_device_hid(device));
+	if (acpi_device_bus_id) {
+		result = acpi_device_set_name(device, acpi_device_bus_id);
+		if (result)
+			goto err_unlock;
+	} else {
+		acpi_device_bus_id = kzalloc(sizeof(*acpi_device_bus_id),
+					     GFP_KERNEL);
+		if (!acpi_device_bus_id) {
+			result = -ENOMEM;
+			goto err_unlock;
+		}
+		acpi_device_bus_id->bus_id =
+			kstrdup_const(acpi_device_hid(device), GFP_KERNEL);
+		if (!acpi_device_bus_id->bus_id) {
+			kfree(acpi_device_bus_id);
+			result = -ENOMEM;
+			goto err_unlock;
+		}
+
+		ida_init(&acpi_device_bus_id->instance_ida);
+
+		result = acpi_device_set_name(device, acpi_device_bus_id);
+		if (result) {
+			kfree_const(acpi_device_bus_id->bus_id);
+			kfree(acpi_device_bus_id);
+			goto err_unlock;
 		}
-	}
-	if (!found) {
-		acpi_device_bus_id = new_bus_id;
-		strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
-		acpi_device_bus_id->instance_no = 0;
+
 		list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
 	}
-	dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
 
 	if (device->parent)
 		list_add_tail(&device->node, &device->parent->children);
@@ -710,9 +743,10 @@
 	if (device->parent)
 		list_del(&device->node);
 	list_del(&device->wakeup_list);
+
+ err_unlock:
 	mutex_unlock(&acpi_device_lock);
 
- err_detach:
 	acpi_detach_data(device->handle, acpi_scan_drop_device);
 	return result;
 }
@@ -919,12 +953,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);
 	}
 
@@ -971,14 +1002,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;
 }
@@ -1533,6 +1577,7 @@
 {
 	struct list_head resource_list;
 	bool is_serial_bus_slave = false;
+	static const struct acpi_device_id ignore_serial_bus_ids[] = {
 	/*
 	 * These devices have multiple I2cSerialBus resources and an i2c-client
 	 * must be instantiated for each, each with its own i2c_device_id.
@@ -1541,11 +1586,18 @@
 	 * drivers/platform/x86/i2c-multi-instantiate.c driver, which knows
 	 * which i2c_device_id to use for each resource.
 	 */
-	static const struct acpi_device_id i2c_multi_instantiate_ids[] = {
 		{"BSG1160", },
 		{"BSG2150", },
 		{"INT33FE", },
 		{"INT3515", },
+	/*
+	 * HIDs of device with an UartSerialBusV2 resource for which userspace
+	 * expects a regular tty cdev to be created (instead of the in kernel
+	 * serdev) and which have a kernel driver which expects a platform_dev
+	 * such as the rfkill-gpio driver.
+	 */
+		{"BCM4752", },
+		{"LNV4752", },
 		{}
 	};
 
@@ -1559,8 +1611,7 @@
 	     fwnode_property_present(&device->fwnode, "baud")))
 		return true;
 
-	/* Instantiate a pdev for the i2c-multi-instantiate drv to bind to */
-	if (!acpi_match_device_ids(device, i2c_multi_instantiate_ids))
+	if (!acpi_match_device_ids(device, ignore_serial_bus_ids))
 		return false;
 
 	INIT_LIST_HEAD(&resource_list);
@@ -2174,6 +2225,7 @@
 	acpi_pci_root_init();
 	acpi_pci_link_init();
 	acpi_processor_init();
+	acpi_platform_init();
 	acpi_lpss_init();
 	acpi_apd_init();
 	acpi_cmos_rtc_init();
--- linux-ein-5.4.0.orig/drivers/acpi/sleep.c
+++ linux-ein-5.4.0/drivers/acpi/sleep.c
@@ -361,6 +361,14 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
 		},
 	},
+	{
+	.callback = init_nvs_save_s3,
+	.ident = "Lenovo G40-45",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
+		},
+	},
 	/*
 	 * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
 	 * the Low Power S0 Idle firmware interface (see
@@ -374,6 +382,18 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
 		},
 	},
+	/*
+	 * ASUS B1400CEAE hangs on resume from suspend (see
+	 * https://bugzilla.kernel.org/show_bug.cgi?id=215742).
+	 */
+	{
+	.callback = init_default_s3,
+	.ident = "ASUS B1400CEAE",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
+		},
+	},
 	{},
 };
 
@@ -977,23 +997,38 @@
 	return 0;
 }
 
-static void acpi_s2idle_wake(void)
+static bool acpi_s2idle_wake(void)
 {
-	/*
-	 * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the SCI has
-	 * not triggered while suspended, so bail out.
-	 */
-	if (!acpi_sci_irq_valid() ||
-	    irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq)))
-		return;
+	if (!acpi_sci_irq_valid())
+		return pm_wakeup_pending();
+
+	while (pm_wakeup_pending()) {
+		/*
+		 * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the
+		 * SCI has not triggered while suspended, so bail out (the
+		 * wakeup is pending anyway and the SCI is not the source of
+		 * it).
+		 */
+		if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq)))
+			return true;
+
+		/*
+		 * If the status bit of any enabled fixed event is set, the
+		 * wakeup is regarded as valid.
+		 */
+		if (acpi_any_fixed_event_status_set())
+			return true;
+
+		/* Check wakeups from drivers sharing the SCI. */
+		if (acpi_check_wakeup_handlers())
+			return true;
+
+		/* Check non-EC GPE wakeups and dispatch the EC GPE. */
+		if (acpi_ec_dispatch_gpe())
+			return true;
 
-	/*
-	 * If there are EC events to process, the wakeup may be a spurious one
-	 * coming from the EC.
-	 */
-	if (acpi_ec_dispatch_gpe()) {
 		/*
-		 * Cancel the wakeup and process all pending events in case
+		 * Cancel the SCI wakeup and process all pending events in case
 		 * there are any wakeup ones in there.
 		 *
 		 * Note that if any non-EC GPEs are active at this point, the
@@ -1001,16 +1036,22 @@
 		 * should be missed by canceling the wakeup here.
 		 */
 		pm_system_cancel_wakeup();
+		acpi_os_wait_events_complete();
+
 		/*
-		 * The EC driver uses the system workqueue and an additional
-		 * special one, so those need to be flushed too.
+		 * The SCI is in the "suspended" state now and it cannot produce
+		 * new wakeup events till the rearming below, so if any of them
+		 * are pending here, they must be resulting from the processing
+		 * of EC events above or coming from somewhere else.
 		 */
-		acpi_os_wait_events_complete(); /* synchronize EC GPE processing */
-		acpi_ec_flush_work();
-		acpi_os_wait_events_complete(); /* synchronize Notify handling */
+		if (pm_wakeup_pending())
+			return true;
 
+		pm_wakeup_clear(acpi_sci_irq);
 		rearm_wake_irq(acpi_sci_irq);
 	}
+
+	return false;
 }
 
 static void acpi_s2idle_restore_early(void)
@@ -1024,6 +1065,14 @@
 
 static void acpi_s2idle_restore(void)
 {
+	/*
+	 * Drain pending events before restoring the working-state configuration
+	 * of GPEs.
+	 */
+	acpi_os_wait_events_complete(); /* synchronize GPE processing */
+	acpi_ec_flush_work(); /* flush the EC driver's workqueues */
+	acpi_os_wait_events_complete(); /* synchronize Notify handling */
+
 	s2idle_wakeup = false;
 
 	acpi_enable_all_runtime_gpes();
--- linux-ein-5.4.0.orig/drivers/acpi/sleep.h
+++ linux-ein-5.4.0/drivers/acpi/sleep.h
@@ -2,6 +2,7 @@
 
 extern void acpi_enable_wakeup_devices(u8 sleep_state);
 extern void acpi_disable_wakeup_devices(u8 sleep_state);
+extern bool acpi_check_wakeup_handlers(void);
 
 extern struct list_head acpi_wakeup_device_list;
 extern struct mutex acpi_device_lock;
--- linux-ein-5.4.0.orig/drivers/acpi/sysfs.c
+++ linux-ein-5.4.0/drivers/acpi/sysfs.c
@@ -439,18 +439,29 @@
 {
 	struct acpi_data_attr *data_attr;
 	void __iomem *base;
-	ssize_t rc;
+	ssize_t size;
 
 	data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
+	size = data_attr->attr.size;
 
-	base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size);
+	if (offset < 0)
+		return -EINVAL;
+
+	if (offset >= size)
+		return 0;
+
+	if (count > size - offset)
+		count = size - offset;
+
+	base = acpi_os_map_iomem(data_attr->addr, size);
 	if (!base)
 		return -ENOMEM;
-	rc = memory_read_from_buffer(buf, count, &offset, base,
-				     data_attr->attr.size);
-	acpi_os_unmap_memory(base, data_attr->attr.size);
 
-	return rc;
+	memcpy_fromio(buf, base + offset, count);
+
+	acpi_os_unmap_iomem(base, size);
+
+	return count;
 }
 
 static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
@@ -819,14 +830,14 @@
  * interface:
  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
  */
-#define ACPI_MASKABLE_GPE_MAX	0xFF
+#define ACPI_MASKABLE_GPE_MAX	0x100
 static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
 
 static int __init acpi_gpe_set_masked_gpes(char *val)
 {
 	u8 gpe;
 
-	if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX)
+	if (kstrtou8(val, 0, &gpe))
 		return -EINVAL;
 	set_bit(gpe, acpi_masked_gpes_map);
 
@@ -838,7 +849,7 @@
 {
 	acpi_handle handle;
 	acpi_status status;
-	u8 gpe;
+	u16 gpe;
 
 	for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
 		status = acpi_get_gpe_device(gpe, &handle);
@@ -938,13 +949,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,
@@ -993,8 +1004,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-ein-5.4.0.orig/drivers/acpi/tables.c
+++ linux-ein-5.4.0/drivers/acpi/tables.c
@@ -791,7 +791,7 @@
 }
 
 /*
- * acpi_table_init()
+ * acpi_locate_initial_tables()
  *
  * find RSDP, find and checksum SDT/XSDT.
  * checksum all tables, print SDT/XSDT
@@ -799,7 +799,7 @@
  * result: sdt_entry[] is initialized
  */
 
-int __init acpi_table_init(void)
+int __init acpi_locate_initial_tables(void)
 {
 	acpi_status status;
 
@@ -814,9 +814,45 @@
 	status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
-	acpi_table_initrd_scan();
 
+	return 0;
+}
+
+void __init acpi_reserve_initial_tables(void)
+{
+	int i;
+
+	for (i = 0; i < ACPI_MAX_TABLES; i++) {
+		struct acpi_table_desc *table_desc = &initial_tables[i];
+		u64 start = table_desc->address;
+		u64 size = table_desc->length;
+
+		if (!start || !size)
+			break;
+
+		pr_info("Reserving %4s table memory at [mem 0x%llx-0x%llx]\n",
+			table_desc->signature.ascii, start, start + size - 1);
+
+		memblock_reserve(start, size);
+	}
+}
+
+void __init acpi_table_init_complete(void)
+{
+	acpi_table_initrd_scan();
 	check_multiple_madt();
+}
+
+int __init acpi_table_init(void)
+{
+	int ret;
+
+	ret = acpi_locate_initial_tables();
+	if (ret)
+		return ret;
+
+	acpi_table_init_complete();
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/acpi/thermal.c
+++ linux-ein-5.4.0/drivers/acpi/thermal.c
@@ -174,6 +174,8 @@
 	int tz_enabled;
 	int kelvin_offset;
 	struct work_struct thermal_check_work;
+	struct mutex thermal_check_lock;
+	refcount_t thermal_check_count;
 };
 
 /* --------------------------------------------------------------------------
@@ -494,17 +496,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,
-				   THERMAL_EVENT_UNSPECIFIED);
-}
-
 /* sys I/F for generic thermal sysfs support */
 
 static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
@@ -538,6 +529,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)
 {
@@ -563,7 +556,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;
 }
@@ -932,6 +925,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);
@@ -942,17 +941,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;
@@ -1052,7 +1051,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 (!refcount_dec_not_one(&tz->thermal_check_count))
+		return;
+
+	mutex_lock(&tz->thermal_check_lock);
+
+	thermal_zone_device_update(tz->thermal_zone, THERMAL_EVENT_UNSPECIFIED);
+
+	refcount_inc(&tz->thermal_check_count);
+
+	mutex_unlock(&tz->thermal_check_lock);
 }
 
 static int acpi_thermal_add(struct acpi_device *device)
@@ -1084,6 +1103,8 @@
 	if (result)
 		goto free_memory;
 
+	refcount_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),
@@ -1132,8 +1153,6 @@
 		return -EINVAL;
 
 	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-		if (!(&tz->trips.active[i]))
-			break;
 		if (!tz->trips.active[i].flags.valid)
 			break;
 		tz->trips.active[i].flags.enabled = 1;
@@ -1149,7 +1168,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-ein-5.4.0.orig/drivers/acpi/video_detect.c
+++ linux-ein-5.4.0/drivers/acpi/video_detect.c
@@ -143,6 +143,14 @@
 	},
 	{
 	.callback = video_detect_force_vendor,
+	.ident = "GIGABYTE GB-BXBT-2807",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
+		},
+	},
+	{
+	.callback = video_detect_force_vendor,
 	.ident = "Sony VPCEH3U1E",
 	.matches = {
 		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
@@ -282,6 +290,15 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
 		},
 	},
+	/* 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 */
 	{
@@ -294,12 +311,37 @@
 		},
 	},
 	{
+	 /* https://bugzilla.suse.com/show_bug.cgi?id=1208724 */
+	 .callback = video_detect_force_native,
+	 /* Lenovo Ideapad Z470 */
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Z470"),
+		},
+	},
+	{
 	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
 	 .callback = video_detect_force_native,
 	 .ident = "Lenovo Ideapad Z570",
 	 .matches = {
 		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-		DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
+		DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
+		},
+	},
+	{
+	 .callback = video_detect_force_native,
+	 .ident = "Lenovo E41-25",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "81FS"),
+		},
+	},
+	{
+	 .callback = video_detect_force_native,
+	 .ident = "Lenovo E41-45",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "82BK"),
 		},
 	},
 	{
@@ -337,6 +379,184 @@
 		},
 	},
 	{
+	 .callback = video_detect_force_native,
+	 .ident = "Acer Aspire 5738z",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
+		DMI_MATCH(DMI_BOARD_NAME, "JV50"),
+		},
+	},
+	{
+	 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
+	 .callback = video_detect_force_native,
+	 .ident = "Acer TravelMate 5735Z",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
+		DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
+		},
+	},
+	/*
+	 * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
+	 * working native and video interface. However the default detection
+	 * mechanism first registers the video interface before unregistering
+	 * it again and switching to the native interface during boot. This
+	 * results in a dangling SBIOS request for backlight change for some
+	 * reason, causing the backlight to switch to ~2% once per boot on the
+	 * first power cord connect or disconnect event. Setting the native
+	 * interface explicitly circumvents this buggy behaviour, by avoiding
+	 * the unregistering process.
+	 */
+	{
+	.callback = video_detect_force_native,
+	.ident = "Clevo NL5xRU",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "Clevo NL5xRU",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "Clevo NL5xRU",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "Clevo NL5xNU",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+		},
+	},
+	/*
+	 * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
+	 * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
+	 * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
+	 * above.
+	 */
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF5PU1G",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF4NU1F",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF4NU1F",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF5NU1G",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF5NU1G",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang PF5LUXG",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
+		},
+	},
+	/*
+	 * More Tongfang devices with the same issue as the Clevo NL5xRU and
+	 * NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description above.
+	 */
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GKxNRxx",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "GKxNRxx"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GKxNRxx",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GKxNRxx",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GKxNRxx",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GKxNRxx",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+		DMI_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GMxNGxx",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GMxZGxx",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
+		},
+	},
+	{
+	.callback = video_detect_force_native,
+	.ident = "TongFang GMxRGxx",
+	.matches = {
+		DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
+		},
+	},
+	/*
+	 * Desktops which falsely report a backlight and which our heuristics
+	 * for this do not catch.
+	 */
+	{
 	 .callback = video_detect_force_none,
 	 .ident = "Dell OptiPlex 9020M",
 	 .matches = {
@@ -344,6 +564,14 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
 		},
 	},
+	{
+	 .callback = video_detect_force_none,
+	 .ident = "MSI MS-7721",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
+		},
+	},
 	{ },
 };
 
--- linux-ein-5.4.0.orig/drivers/acpi/wakeup.c
+++ linux-ein-5.4.0/drivers/acpi/wakeup.c
@@ -12,6 +12,15 @@
 #include "internal.h"
 #include "sleep.h"
 
+struct acpi_wakeup_handler {
+	struct list_head list_node;
+	bool (*wakeup)(void *context);
+	void *context;
+};
+
+static LIST_HEAD(acpi_wakeup_handler_head);
+static DEFINE_MUTEX(acpi_wakeup_handler_mutex);
+
 /*
  * We didn't lock acpi_device_lock in the file, because it invokes oops in
  * suspend/resume and isn't really required as this is called in S-state. At
@@ -96,3 +105,75 @@
 	mutex_unlock(&acpi_device_lock);
 	return 0;
 }
+
+/**
+ * acpi_register_wakeup_handler - Register wakeup handler
+ * @wake_irq: The IRQ through which the device may receive wakeups
+ * @wakeup:   Wakeup-handler to call when the SCI has triggered a wakeup
+ * @context:  Context to pass to the handler when calling it
+ *
+ * Drivers which may share an IRQ with the SCI can use this to register
+ * a handler which returns true when the device they are managing wants
+ * to trigger a wakeup.
+ */
+int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context),
+				 void *context)
+{
+	struct acpi_wakeup_handler *handler;
+
+	/*
+	 * If the device is not sharing its IRQ with the SCI, there is no
+	 * need to register the handler.
+	 */
+	if (!acpi_sci_irq_valid() || wake_irq != acpi_sci_irq)
+		return 0;
+
+	handler = kmalloc(sizeof(*handler), GFP_KERNEL);
+	if (!handler)
+		return -ENOMEM;
+
+	handler->wakeup = wakeup;
+	handler->context = context;
+
+	mutex_lock(&acpi_wakeup_handler_mutex);
+	list_add(&handler->list_node, &acpi_wakeup_handler_head);
+	mutex_unlock(&acpi_wakeup_handler_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_register_wakeup_handler);
+
+/**
+ * acpi_unregister_wakeup_handler - Unregister wakeup handler
+ * @wakeup:   Wakeup-handler passed to acpi_register_wakeup_handler()
+ * @context:  Context passed to acpi_register_wakeup_handler()
+ */
+void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context),
+				    void *context)
+{
+	struct acpi_wakeup_handler *handler;
+
+	mutex_lock(&acpi_wakeup_handler_mutex);
+	list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
+		if (handler->wakeup == wakeup && handler->context == context) {
+			list_del(&handler->list_node);
+			kfree(handler);
+			break;
+		}
+	}
+	mutex_unlock(&acpi_wakeup_handler_mutex);
+}
+EXPORT_SYMBOL_GPL(acpi_unregister_wakeup_handler);
+
+bool acpi_check_wakeup_handlers(void)
+{
+	struct acpi_wakeup_handler *handler;
+
+	/* No need to lock, nothing else is running when we're called. */
+	list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
+		if (handler->wakeup(handler->context))
+			return true;
+	}
+
+	return false;
+}
--- linux-ein-5.4.0.orig/drivers/amba/bus.c
+++ linux-ein-5.4.0/drivers/amba/bus.c
@@ -299,10 +299,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() */
@@ -319,7 +320,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));
 }
 
 /**
@@ -332,12 +335,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);
 }
@@ -360,6 +364,7 @@
 {
 	struct amba_device *d = to_amba_device(dev);
 
+	of_node_put(d->dev.of_node);
 	if (d->res.parent)
 		release_resource(&d->res);
 	kfree(d);
@@ -371,9 +376,6 @@
 	void __iomem *tmp;
 	int i, ret;
 
-	WARN_ON(dev->irq[0] == (unsigned int)-1);
-	WARN_ON(dev->irq[1] == (unsigned int)-1);
-
 	ret = request_resource(parent, &dev->res);
 	if (ret)
 		goto err_out;
--- linux-ein-5.4.0.orig/drivers/android/Kconfig
+++ linux-ein-5.4.0/drivers/android/Kconfig
@@ -9,7 +9,7 @@
 if ANDROID
 
 config ANDROID_BINDER_IPC
-	bool "Android Binder IPC Driver"
+	tristate "Android Binder IPC Driver"
 	depends on MMU
 	default n
 	---help---
@@ -21,8 +21,8 @@
 	  between said processes.
 
 config ANDROID_BINDERFS
-	bool "Android Binderfs filesystem"
-	depends on ANDROID_BINDER_IPC
+	tristate "Android Binderfs filesystem"
+	depends on (ANDROID_BINDER_IPC=y) || (ANDROID_BINDER_IPC=m && m)
 	default n
 	---help---
 	  Binderfs is a pseudo-filesystem for the Android Binder IPC driver
--- linux-ein-5.4.0.orig/drivers/android/Makefile
+++ linux-ein-5.4.0/drivers/android/Makefile
@@ -1,6 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 ccflags-y += -I$(src)			# needed for trace events
 
-obj-$(CONFIG_ANDROID_BINDERFS)		+= binderfs.o
-obj-$(CONFIG_ANDROID_BINDER_IPC)	+= binder.o binder_alloc.o
-obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
+binder_linux-y := binder.o binder_alloc.o
+obj-$(CONFIG_ANDROID_BINDER_IPC) += binder_linux.o
+binder_linux-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
+binder_linux-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
+
+# binder-$(CONFIG_ANDROID_BINDER_IPC) := binder.o binder_alloc.o
+# binder-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
--- linux-ein-5.4.0.orig/drivers/android/binder.c
+++ linux-ein-5.4.0/drivers/android/binder.c
@@ -227,7 +227,7 @@
 struct binder_work {
 	struct list_head entry;
 
-	enum {
+	enum binder_work_type {
 		BINDER_WORK_TRANSACTION = 1,
 		BINDER_WORK_TRANSACTION_COMPLETE,
 		BINDER_WORK_RETURN_ERROR,
@@ -424,6 +424,9 @@
  *                        (invariant after initialized)
  * @tsk                   task_struct for group_leader of process
  *                        (invariant after initialized)
+ * @cred                  struct cred associated with the `struct file`
+ *                        in binder_open()
+ *                        (invariant after initialized)
  * @deferred_work_node:   element for binder_deferred_list
  *                        (protected by binder_deferred_lock)
  * @deferred_work:        bitmap of deferred work to perform
@@ -469,6 +472,7 @@
 	struct list_head waiting_threads;
 	int pid;
 	struct task_struct *tsk;
+	const struct cred *cred;
 	struct hlist_node deferred_work_node;
 	int deferred_work;
 	bool is_dead;
@@ -836,6 +840,16 @@
 {
 	WARN_ON(!list_empty(&thread->waiting_thread_node));
 	binder_enqueue_work_ilocked(work, &thread->todo);
+
+	/* (e)poll-based threads require an explicit wakeup signal when
+	 * queuing their own work; they rely on these events to consume
+	 * messages without I/O block. Without it, threads risk waiting
+	 * indefinitely without handling the work.
+	 */
+	if (thread->looper & BINDER_LOOPER_STATE_POLL &&
+	    thread->pid == current->pid && !thread->process_todo)
+		wake_up_interruptible_sync(&thread->wait);
+
 	thread->process_todo = true;
 }
 
@@ -889,27 +903,6 @@
 	return w;
 }
 
-/**
- * binder_dequeue_work_head() - Dequeues the item at head of list
- * @proc:         binder_proc associated with list
- * @list:         list to dequeue head
- *
- * Removes the head of the list if there are items on the list
- *
- * Return: pointer dequeued binder_work, NULL if list was empty
- */
-static struct binder_work *binder_dequeue_work_head(
-					struct binder_proc *proc,
-					struct list_head *list)
-{
-	struct binder_work *w;
-
-	binder_inner_proc_lock(proc);
-	w = binder_dequeue_work_head_ilocked(list);
-	binder_inner_proc_unlock(proc);
-	return w;
-}
-
 static void
 binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
 static void binder_free_thread(struct binder_thread *thread);
@@ -1765,6 +1758,18 @@
 	}
 	ret = binder_inc_ref_olocked(ref, strong, target_list);
 	*rdata = ref->data;
+	if (ret && ref == new_ref) {
+		/*
+		 * Cleanup the failed reference here as the target
+		 * could now be dead and have already released its
+		 * references by now. Calling on the new reference
+		 * with strong=0 and a tmp_refs will not decrement
+		 * the node. The new_ref gets kfree'd below.
+		 */
+		binder_cleanup_ref_olocked(new_ref);
+		ref = NULL;
+	}
+
 	binder_proc_unlock(proc);
 	if (new_ref && ref != new_ref)
 		/*
@@ -2018,15 +2023,21 @@
 /**
  * binder_get_object() - gets object and checks for valid metadata
  * @proc:	binder_proc owning the buffer
+ * @u:		sender's user pointer to base of buffer
  * @buffer:	binder_buffer that we're parsing.
  * @offset:	offset in the @buffer at which to validate an object.
  * @object:	struct binder_object to read into
  *
- * Return:	If there's a valid metadata object at @offset in @buffer, the
+ * Copy the binder object at the given offset into @object. If @u is
+ * provided then the copy is from the sender's buffer. If not, then
+ * it is copied from the target's @buffer.
+ *
+ * Return:	If there's a valid metadata object at @offset, the
  *		size of that object. Otherwise, it returns zero. The object
  *		is read into the struct binder_object pointed to by @object.
  */
 static size_t binder_get_object(struct binder_proc *proc,
+				const void __user *u,
 				struct binder_buffer *buffer,
 				unsigned long offset,
 				struct binder_object *object)
@@ -2036,10 +2047,16 @@
 	size_t object_size = 0;
 
 	read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset);
-	if (offset > buffer->data_size || read_size < sizeof(*hdr) ||
-	    binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
-					  offset, read_size))
+	if (offset > buffer->data_size || read_size < sizeof(*hdr))
 		return 0;
+	if (u) {
+		if (copy_from_user(object, u + offset, read_size))
+			return 0;
+	} else {
+		if (binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
+						  offset, read_size))
+			return 0;
+	}
 
 	/* Ok, now see if we read a complete object. */
 	hdr = &object->hdr;
@@ -2112,7 +2129,7 @@
 					  b, buffer_offset,
 					  sizeof(object_offset)))
 		return NULL;
-	object_size = binder_get_object(proc, b, object_offset, object);
+	object_size = binder_get_object(proc, NULL, b, object_offset, object);
 	if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
 		return NULL;
 	if (object_offsetp)
@@ -2177,7 +2194,8 @@
 		unsigned long buffer_offset;
 		struct binder_object last_object;
 		struct binder_buffer_object *last_bbo;
-		size_t object_size = binder_get_object(proc, b, last_obj_offset,
+		size_t object_size = binder_get_object(proc, NULL, b,
+						       last_obj_offset,
 						       &last_object);
 		if (object_size != sizeof(*last_bbo))
 			return false;
@@ -2260,25 +2278,25 @@
 }
 
 static void binder_transaction_buffer_release(struct binder_proc *proc,
+					      struct binder_thread *thread,
 					      struct binder_buffer *buffer,
-					      binder_size_t failed_at,
+					      binder_size_t off_end_offset,
 					      bool is_failure)
 {
 	int debug_id = buffer->debug_id;
-	binder_size_t off_start_offset, buffer_offset, off_end_offset;
+	binder_size_t off_start_offset, buffer_offset;
 
 	binder_debug(BINDER_DEBUG_TRANSACTION,
 		     "%d buffer release %d, size %zd-%zd, failed at %llx\n",
 		     proc->pid, buffer->debug_id,
 		     buffer->data_size, buffer->offsets_size,
-		     (unsigned long long)failed_at);
+		     (unsigned long long)off_end_offset);
 
 	if (buffer->target_node)
 		binder_dec_node(buffer->target_node, 1, 0);
 
 	off_start_offset = ALIGN(buffer->data_size, sizeof(void *));
-	off_end_offset = is_failure ? failed_at :
-				off_start_offset + buffer->offsets_size;
+
 	for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
 	     buffer_offset += sizeof(binder_size_t)) {
 		struct binder_object_header *hdr;
@@ -2289,7 +2307,7 @@
 		if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
 						   buffer, buffer_offset,
 						   sizeof(object_offset)))
-			object_size = binder_get_object(proc, buffer,
+			object_size = binder_get_object(proc, NULL, buffer,
 							object_offset, &object);
 		if (object_size == 0) {
 			pr_err("transaction release %d bad object at offset %lld, size %zd\n",
@@ -2347,8 +2365,6 @@
 			 * file is done when the transaction is torn
 			 * down.
 			 */
-			WARN_ON(failed_at &&
-				proc->tsk == current->group_leader);
 		} break;
 		case BINDER_TYPE_PTR:
 			/*
@@ -2365,9 +2381,8 @@
 			binder_size_t fd_buf_size;
 			binder_size_t num_valid;
 
-			if (proc->tsk != current->group_leader) {
+			if (is_failure) {
 				/*
-				 * Nothing to do if running in sender context
 				 * The fd fixups have not been applied so no
 				 * fds need to be closed.
 				 */
@@ -2421,8 +2436,16 @@
 						&proc->alloc, &fd, buffer,
 						offset, sizeof(fd));
 				WARN_ON(err);
-				if (!err)
+				if (!err) {
 					binder_deferred_fd_close(fd);
+					/*
+					 * Need to make sure the thread goes
+					 * back to userspace to complete the
+					 * deferred close
+					 */
+					if (thread)
+						thread->looper_need_return = true;
+				}
 			}
 		} break;
 		default:
@@ -2433,6 +2456,21 @@
 	}
 }
 
+/* Clean up all the objects in the buffer */
+static inline void binder_release_entire_buffer(struct binder_proc *proc,
+						struct binder_thread *thread,
+						struct binder_buffer *buffer,
+						bool is_failure)
+{
+	binder_size_t off_end_offset;
+
+	off_end_offset = ALIGN(buffer->data_size, sizeof(void *));
+	off_end_offset += buffer->offsets_size;
+
+	binder_transaction_buffer_release(proc, thread, buffer,
+					  off_end_offset, is_failure);
+}
+
 static int binder_translate_binder(struct flat_binder_object *fp,
 				   struct binder_transaction *t,
 				   struct binder_thread *thread)
@@ -2457,7 +2495,7 @@
 		ret = -EINVAL;
 		goto done;
 	}
-	if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+	if (security_binder_transfer_binder(proc->cred, target_proc->cred)) {
 		ret = -EPERM;
 		goto done;
 	}
@@ -2503,7 +2541,7 @@
 				  proc->pid, thread->pid, fp->handle);
 		return -EINVAL;
 	}
-	if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+	if (security_binder_transfer_binder(proc->cred, target_proc->cred)) {
 		ret = -EPERM;
 		goto done;
 	}
@@ -2591,7 +2629,7 @@
 		ret = -EBADF;
 		goto err_fget;
 	}
-	ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
+	ret = security_binder_transfer_file(proc->cred, target_proc->cred, file);
 	if (ret < 0) {
 		ret = -EPERM;
 		goto err_security;
@@ -2622,16 +2660,266 @@
 	return ret;
 }
 
-static int binder_translate_fd_array(struct binder_fd_array_object *fda,
+/**
+ * struct binder_ptr_fixup - data to be fixed-up in target buffer
+ * @offset	offset in target buffer to fixup
+ * @skip_size	bytes to skip in copy (fixup will be written later)
+ * @fixup_data	data to write at fixup offset
+ * @node	list node
+ *
+ * This is used for the pointer fixup list (pf) which is created and consumed
+ * during binder_transaction() and is only accessed locally. No
+ * locking is necessary.
+ *
+ * The list is ordered by @offset.
+ */
+struct binder_ptr_fixup {
+	binder_size_t offset;
+	size_t skip_size;
+	binder_uintptr_t fixup_data;
+	struct list_head node;
+};
+
+/**
+ * struct binder_sg_copy - scatter-gather data to be copied
+ * @offset		offset in target buffer
+ * @sender_uaddr	user address in source buffer
+ * @length		bytes to copy
+ * @node		list node
+ *
+ * This is used for the sg copy list (sgc) which is created and consumed
+ * during binder_transaction() and is only accessed locally. No
+ * locking is necessary.
+ *
+ * The list is ordered by @offset.
+ */
+struct binder_sg_copy {
+	binder_size_t offset;
+	const void __user *sender_uaddr;
+	size_t length;
+	struct list_head node;
+};
+
+/**
+ * binder_do_deferred_txn_copies() - copy and fixup scatter-gather data
+ * @alloc:	binder_alloc associated with @buffer
+ * @buffer:	binder buffer in target process
+ * @sgc_head:	list_head of scatter-gather copy list
+ * @pf_head:	list_head of pointer fixup list
+ *
+ * Processes all elements of @sgc_head, applying fixups from @pf_head
+ * and copying the scatter-gather data from the source process' user
+ * buffer to the target's buffer. It is expected that the list creation
+ * and processing all occurs during binder_transaction() so these lists
+ * are only accessed in local context.
+ *
+ * Return: 0=success, else -errno
+ */
+static int binder_do_deferred_txn_copies(struct binder_alloc *alloc,
+					 struct binder_buffer *buffer,
+					 struct list_head *sgc_head,
+					 struct list_head *pf_head)
+{
+	int ret = 0;
+	struct binder_sg_copy *sgc, *tmpsgc;
+	struct binder_ptr_fixup *tmppf;
+	struct binder_ptr_fixup *pf =
+		list_first_entry_or_null(pf_head, struct binder_ptr_fixup,
+					 node);
+
+	list_for_each_entry_safe(sgc, tmpsgc, sgc_head, node) {
+		size_t bytes_copied = 0;
+
+		while (bytes_copied < sgc->length) {
+			size_t copy_size;
+			size_t bytes_left = sgc->length - bytes_copied;
+			size_t offset = sgc->offset + bytes_copied;
+
+			/*
+			 * We copy up to the fixup (pointed to by pf)
+			 */
+			copy_size = pf ? min(bytes_left, (size_t)pf->offset - offset)
+				       : bytes_left;
+			if (!ret && copy_size)
+				ret = binder_alloc_copy_user_to_buffer(
+						alloc, buffer,
+						offset,
+						sgc->sender_uaddr + bytes_copied,
+						copy_size);
+			bytes_copied += copy_size;
+			if (copy_size != bytes_left) {
+				BUG_ON(!pf);
+				/* we stopped at a fixup offset */
+				if (pf->skip_size) {
+					/*
+					 * we are just skipping. This is for
+					 * BINDER_TYPE_FDA where the translated
+					 * fds will be fixed up when we get
+					 * to target context.
+					 */
+					bytes_copied += pf->skip_size;
+				} else {
+					/* apply the fixup indicated by pf */
+					if (!ret)
+						ret = binder_alloc_copy_to_buffer(
+							alloc, buffer,
+							pf->offset,
+							&pf->fixup_data,
+							sizeof(pf->fixup_data));
+					bytes_copied += sizeof(pf->fixup_data);
+				}
+				list_del(&pf->node);
+				kfree(pf);
+				pf = list_first_entry_or_null(pf_head,
+						struct binder_ptr_fixup, node);
+			}
+		}
+		list_del(&sgc->node);
+		kfree(sgc);
+	}
+	list_for_each_entry_safe(pf, tmppf, pf_head, node) {
+		BUG_ON(pf->skip_size == 0);
+		list_del(&pf->node);
+		kfree(pf);
+	}
+	BUG_ON(!list_empty(sgc_head));
+
+	return ret > 0 ? -EINVAL : ret;
+}
+
+/**
+ * binder_cleanup_deferred_txn_lists() - free specified lists
+ * @sgc_head:	list_head of scatter-gather copy list
+ * @pf_head:	list_head of pointer fixup list
+ *
+ * Called to clean up @sgc_head and @pf_head if there is an
+ * error.
+ */
+static void binder_cleanup_deferred_txn_lists(struct list_head *sgc_head,
+					      struct list_head *pf_head)
+{
+	struct binder_sg_copy *sgc, *tmpsgc;
+	struct binder_ptr_fixup *pf, *tmppf;
+
+	list_for_each_entry_safe(sgc, tmpsgc, sgc_head, node) {
+		list_del(&sgc->node);
+		kfree(sgc);
+	}
+	list_for_each_entry_safe(pf, tmppf, pf_head, node) {
+		list_del(&pf->node);
+		kfree(pf);
+	}
+}
+
+/**
+ * binder_defer_copy() - queue a scatter-gather buffer for copy
+ * @sgc_head:		list_head of scatter-gather copy list
+ * @offset:		binder buffer offset in target process
+ * @sender_uaddr:	user address in source process
+ * @length:		bytes to copy
+ *
+ * Specify a scatter-gather block to be copied. The actual copy must
+ * be deferred until all the needed fixups are identified and queued.
+ * Then the copy and fixups are done together so un-translated values
+ * from the source are never visible in the target buffer.
+ *
+ * We are guaranteed that repeated calls to this function will have
+ * monotonically increasing @offset values so the list will naturally
+ * be ordered.
+ *
+ * Return: 0=success, else -errno
+ */
+static int binder_defer_copy(struct list_head *sgc_head, binder_size_t offset,
+			     const void __user *sender_uaddr, size_t length)
+{
+	struct binder_sg_copy *bc = kzalloc(sizeof(*bc), GFP_KERNEL);
+
+	if (!bc)
+		return -ENOMEM;
+
+	bc->offset = offset;
+	bc->sender_uaddr = sender_uaddr;
+	bc->length = length;
+	INIT_LIST_HEAD(&bc->node);
+
+	/*
+	 * We are guaranteed that the deferred copies are in-order
+	 * so just add to the tail.
+	 */
+	list_add_tail(&bc->node, sgc_head);
+
+	return 0;
+}
+
+/**
+ * binder_add_fixup() - queue a fixup to be applied to sg copy
+ * @pf_head:	list_head of binder ptr fixup list
+ * @offset:	binder buffer offset in target process
+ * @fixup:	bytes to be copied for fixup
+ * @skip_size:	bytes to skip when copying (fixup will be applied later)
+ *
+ * Add the specified fixup to a list ordered by @offset. When copying
+ * the scatter-gather buffers, the fixup will be copied instead of
+ * data from the source buffer. For BINDER_TYPE_FDA fixups, the fixup
+ * will be applied later (in target process context), so we just skip
+ * the bytes specified by @skip_size. If @skip_size is 0, we copy the
+ * value in @fixup.
+ *
+ * This function is called *mostly* in @offset order, but there are
+ * exceptions. Since out-of-order inserts are relatively uncommon,
+ * we insert the new element by searching backward from the tail of
+ * the list.
+ *
+ * Return: 0=success, else -errno
+ */
+static int binder_add_fixup(struct list_head *pf_head, binder_size_t offset,
+			    binder_uintptr_t fixup, size_t skip_size)
+{
+	struct binder_ptr_fixup *pf = kzalloc(sizeof(*pf), GFP_KERNEL);
+	struct binder_ptr_fixup *tmppf;
+
+	if (!pf)
+		return -ENOMEM;
+
+	pf->offset = offset;
+	pf->fixup_data = fixup;
+	pf->skip_size = skip_size;
+	INIT_LIST_HEAD(&pf->node);
+
+	/* Fixups are *mostly* added in-order, but there are some
+	 * exceptions. Look backwards through list for insertion point.
+	 */
+	list_for_each_entry_reverse(tmppf, pf_head, node) {
+		if (tmppf->offset < pf->offset) {
+			list_add(&pf->node, &tmppf->node);
+			return 0;
+		}
+	}
+	/*
+	 * if we get here, then the new offset is the lowest so
+	 * insert at the head
+	 */
+	list_add(&pf->node, pf_head);
+	return 0;
+}
+
+static int binder_translate_fd_array(struct list_head *pf_head,
+				     struct binder_fd_array_object *fda,
+				     const void __user *sender_ubuffer,
 				     struct binder_buffer_object *parent,
+				     struct binder_buffer_object *sender_uparent,
 				     struct binder_transaction *t,
 				     struct binder_thread *thread,
 				     struct binder_transaction *in_reply_to)
 {
 	binder_size_t fdi, fd_buf_size;
 	binder_size_t fda_offset;
+	const void __user *sender_ufda_base;
 	struct binder_proc *proc = thread->proc;
-	struct binder_proc *target_proc = t->to_proc;
+	int ret;
+
+	if (fda->num_fds == 0)
+		return 0;
 
 	fd_buf_size = sizeof(u32) * fda->num_fds;
 	if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
@@ -2655,29 +2943,36 @@
 	 */
 	fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) +
 		fda->parent_offset;
-	if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32))) {
+	sender_ufda_base = (void __user *)(uintptr_t)sender_uparent->buffer +
+				fda->parent_offset;
+
+	if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32)) ||
+	    !IS_ALIGNED((unsigned long)sender_ufda_base, sizeof(u32))) {
 		binder_user_error("%d:%d parent offset not aligned correctly.\n",
 				  proc->pid, thread->pid);
 		return -EINVAL;
 	}
+	ret = binder_add_fixup(pf_head, fda_offset, 0, fda->num_fds * sizeof(u32));
+	if (ret)
+		return ret;
+
 	for (fdi = 0; fdi < fda->num_fds; fdi++) {
 		u32 fd;
-		int ret;
 		binder_size_t offset = fda_offset + fdi * sizeof(fd);
+		binder_size_t sender_uoffset = fdi * sizeof(fd);
 
-		ret = binder_alloc_copy_from_buffer(&target_proc->alloc,
-						    &fd, t->buffer,
-						    offset, sizeof(fd));
+		ret = copy_from_user(&fd, sender_ufda_base + sender_uoffset, sizeof(fd));
 		if (!ret)
 			ret = binder_translate_fd(fd, offset, t, thread,
 						  in_reply_to);
-		if (ret < 0)
-			return ret;
+		if (ret)
+			return ret > 0 ? -EINVAL : ret;
 	}
 	return 0;
 }
 
-static int binder_fixup_parent(struct binder_transaction *t,
+static int binder_fixup_parent(struct list_head *pf_head,
+			       struct binder_transaction *t,
 			       struct binder_thread *thread,
 			       struct binder_buffer_object *bp,
 			       binder_size_t off_start_offset,
@@ -2723,14 +3018,7 @@
 	}
 	buffer_offset = bp->parent_offset +
 			(uintptr_t)parent->buffer - (uintptr_t)b->user_data;
-	if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
-					&bp->buffer, sizeof(bp->buffer))) {
-		binder_user_error("%d:%d got transaction with invalid parent offset\n",
-				  proc->pid, thread->pid);
-		return -EINVAL;
-	}
-
-	return 0;
+	return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);
 }
 
 /**
@@ -2851,6 +3139,7 @@
 	binder_size_t off_start_offset, off_end_offset;
 	binder_size_t off_min;
 	binder_size_t sg_buf_offset, sg_buf_end_offset;
+	binder_size_t user_offset = 0;
 	struct binder_proc *target_proc = NULL;
 	struct binder_thread *target_thread = NULL;
 	struct binder_node *target_node = NULL;
@@ -2865,6 +3154,12 @@
 	int t_debug_id = atomic_inc_return(&binder_last_id);
 	char *secctx = NULL;
 	u32 secctx_sz = 0;
+	struct list_head sgc_head;
+	struct list_head pf_head;
+	const void __user *user_buffer = (const void __user *)
+				(uintptr_t)tr->data.ptr.buffer;
+	INIT_LIST_HEAD(&sgc_head);
+	INIT_LIST_HEAD(&pf_head);
 
 	e = binder_transaction_log_add(&binder_transaction_log);
 	e->debug_id = t_debug_id;
@@ -2984,8 +3279,14 @@
 			goto err_dead_binder;
 		}
 		e->to_node = target_node->debug_id;
-		if (security_binder_transaction(proc->tsk,
-						target_proc->tsk) < 0) {
+		if (WARN_ON(proc == target_proc)) {
+			return_error = BR_FAILED_REPLY;
+			return_error_param = -EINVAL;
+			return_error_line = __LINE__;
+			goto err_invalid_target_handle;
+		}
+		if (security_binder_transaction(proc->cred,
+						target_proc->cred) < 0) {
 			return_error = BR_FAILED_REPLY;
 			return_error_param = -EPERM;
 			return_error_line = __LINE__;
@@ -3111,7 +3412,7 @@
 		u32 secid;
 		size_t added_size;
 
-		security_task_getsecid(proc->tsk, &secid);
+		security_cred_getsecid(proc->cred, &secid);
 		ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
 		if (ret) {
 			return_error = BR_FAILED_REPLY;
@@ -3167,23 +3468,11 @@
 	t->buffer->debug_id = t->debug_id;
 	t->buffer->transaction = t;
 	t->buffer->target_node = target_node;
+	t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF);
 	trace_binder_transaction_alloc_buf(t->buffer);
 
 	if (binder_alloc_copy_user_to_buffer(
 				&target_proc->alloc,
-				t->buffer, 0,
-				(const void __user *)
-					(uintptr_t)tr->data.ptr.buffer,
-				tr->data_size)) {
-		binder_user_error("%d:%d got transaction with invalid data ptr\n",
-				proc->pid, thread->pid);
-		return_error = BR_FAILED_REPLY;
-		return_error_param = -EFAULT;
-		return_error_line = __LINE__;
-		goto err_copy_data_failed;
-	}
-	if (binder_alloc_copy_user_to_buffer(
-				&target_proc->alloc,
 				t->buffer,
 				ALIGN(tr->data_size, sizeof(void *)),
 				(const void __user *)
@@ -3226,6 +3515,7 @@
 		size_t object_size;
 		struct binder_object object;
 		binder_size_t object_offset;
+		binder_size_t copy_size;
 
 		if (binder_alloc_copy_from_buffer(&target_proc->alloc,
 						  &object_offset,
@@ -3237,8 +3527,27 @@
 			return_error_line = __LINE__;
 			goto err_bad_offset;
 		}
-		object_size = binder_get_object(target_proc, t->buffer,
-						object_offset, &object);
+
+		/*
+		 * Copy the source user buffer up to the next object
+		 * that will be processed.
+		 */
+		copy_size = object_offset - user_offset;
+		if (copy_size && (user_offset > object_offset ||
+				binder_alloc_copy_user_to_buffer(
+					&target_proc->alloc,
+					t->buffer, user_offset,
+					user_buffer + user_offset,
+					copy_size))) {
+			binder_user_error("%d:%d got transaction with invalid data ptr\n",
+					proc->pid, thread->pid);
+			return_error = BR_FAILED_REPLY;
+			return_error_param = -EFAULT;
+			return_error_line = __LINE__;
+			goto err_copy_data_failed;
+		}
+		object_size = binder_get_object(target_proc, user_buffer,
+				t->buffer, object_offset, &object);
 		if (object_size == 0 || object_offset < off_min) {
 			binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n",
 					  proc->pid, thread->pid,
@@ -3250,6 +3559,11 @@
 			return_error_line = __LINE__;
 			goto err_bad_offset;
 		}
+		/*
+		 * Set offset to the next buffer fragment to be
+		 * copied
+		 */
+		user_offset = object_offset + object_size;
 
 		hdr = &object.hdr;
 		off_min = object_offset + object_size;
@@ -3312,9 +3626,11 @@
 		case BINDER_TYPE_FDA: {
 			struct binder_object ptr_object;
 			binder_size_t parent_offset;
+			struct binder_object user_object;
+			size_t user_parent_size;
 			struct binder_fd_array_object *fda =
 				to_binder_fd_array_object(hdr);
-			size_t num_valid = (buffer_offset - off_start_offset) *
+			size_t num_valid = (buffer_offset - off_start_offset) /
 						sizeof(binder_size_t);
 			struct binder_buffer_object *parent =
 				binder_validate_ptr(target_proc, t->buffer,
@@ -3343,11 +3659,35 @@
 				return_error_line = __LINE__;
 				goto err_bad_parent;
 			}
-			ret = binder_translate_fd_array(fda, parent, t, thread,
-							in_reply_to);
-			if (ret < 0) {
+			/*
+			 * We need to read the user version of the parent
+			 * object to get the original user offset
+			 */
+			user_parent_size =
+				binder_get_object(proc, user_buffer, t->buffer,
+						  parent_offset, &user_object);
+			if (user_parent_size != sizeof(user_object.bbo)) {
+				binder_user_error("%d:%d invalid ptr object size: %zd vs %zd\n",
+						  proc->pid, thread->pid,
+						  user_parent_size,
+						  sizeof(user_object.bbo));
 				return_error = BR_FAILED_REPLY;
-				return_error_param = ret;
+				return_error_param = -EINVAL;
+				return_error_line = __LINE__;
+				goto err_bad_parent;
+			}
+			ret = binder_translate_fd_array(&pf_head, fda,
+							user_buffer, parent,
+							&user_object.bbo, t,
+							thread, in_reply_to);
+			if (!ret)
+				ret = binder_alloc_copy_to_buffer(&target_proc->alloc,
+								  t->buffer,
+								  object_offset,
+								  fda, sizeof(*fda));
+			if (ret) {
+				return_error = BR_FAILED_REPLY;
+				return_error_param = ret > 0 ? -EINVAL : ret;
 				return_error_line = __LINE__;
 				goto err_translate_failed;
 			}
@@ -3369,28 +3709,24 @@
 				return_error_line = __LINE__;
 				goto err_bad_offset;
 			}
-			if (binder_alloc_copy_user_to_buffer(
-						&target_proc->alloc,
-						t->buffer,
-						sg_buf_offset,
-						(const void __user *)
-							(uintptr_t)bp->buffer,
-						bp->length)) {
-				binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
-						  proc->pid, thread->pid);
-				return_error_param = -EFAULT;
+			ret = binder_defer_copy(&sgc_head, sg_buf_offset,
+				(const void __user *)(uintptr_t)bp->buffer,
+				bp->length);
+			if (ret) {
 				return_error = BR_FAILED_REPLY;
+				return_error_param = ret;
 				return_error_line = __LINE__;
-				goto err_copy_data_failed;
+				goto err_translate_failed;
 			}
 			/* Fixup buffer pointer to target proc address space */
 			bp->buffer = (uintptr_t)
 				t->buffer->user_data + sg_buf_offset;
 			sg_buf_offset += ALIGN(bp->length, sizeof(u64));
 
-			num_valid = (buffer_offset - off_start_offset) *
+			num_valid = (buffer_offset - off_start_offset) /
 					sizeof(binder_size_t);
-			ret = binder_fixup_parent(t, thread, bp,
+			ret = binder_fixup_parent(&pf_head, t,
+						  thread, bp,
 						  off_start_offset,
 						  num_valid,
 						  last_fixup_obj_off,
@@ -3417,6 +3753,30 @@
 			goto err_bad_object_type;
 		}
 	}
+	/* Done processing objects, copy the rest of the buffer */
+	if (binder_alloc_copy_user_to_buffer(
+				&target_proc->alloc,
+				t->buffer, user_offset,
+				user_buffer + user_offset,
+				tr->data_size - user_offset)) {
+		binder_user_error("%d:%d got transaction with invalid data ptr\n",
+				proc->pid, thread->pid);
+		return_error = BR_FAILED_REPLY;
+		return_error_param = -EFAULT;
+		return_error_line = __LINE__;
+		goto err_copy_data_failed;
+	}
+
+	ret = binder_do_deferred_txn_copies(&target_proc->alloc, t->buffer,
+					    &sgc_head, &pf_head);
+	if (ret) {
+		binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
+				  proc->pid, thread->pid);
+		return_error = BR_FAILED_REPLY;
+		return_error_param = ret;
+		return_error_line = __LINE__;
+		goto err_copy_data_failed;
+	}
 	tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
 	t->work.type = BINDER_WORK_TRANSACTION;
 
@@ -3483,9 +3843,10 @@
 err_bad_offset:
 err_bad_parent:
 err_copy_data_failed:
+	binder_cleanup_deferred_txn_lists(&sgc_head, &pf_head);
 	binder_free_txn_fixups(t);
 	trace_binder_transaction_failed_buffer_release(t->buffer);
-	binder_transaction_buffer_release(target_proc, t->buffer,
+	binder_transaction_buffer_release(target_proc, NULL, t->buffer,
 					  buffer_offset, true);
 	if (target_node)
 		binder_dec_node_tmpref(target_node);
@@ -3555,6 +3916,7 @@
  * binder_free_buf() - free the specified buffer
  * @proc:	binder proc that owns buffer
  * @buffer:	buffer to be freed
+ * @is_failure:	failed to send transaction
  *
  * If buffer for an async transaction, enqueue the next async
  * transaction from the node.
@@ -3562,7 +3924,9 @@
  * Cleanup buffer and free it.
  */
 static void
-binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer)
+binder_free_buf(struct binder_proc *proc,
+		struct binder_thread *thread,
+		struct binder_buffer *buffer, bool is_failure)
 {
 	binder_inner_proc_lock(proc);
 	if (buffer->transaction) {
@@ -3590,7 +3954,7 @@
 		binder_node_inner_unlock(buf_node);
 	}
 	trace_binder_transaction_buffer_release(buffer);
-	binder_transaction_buffer_release(proc, buffer, 0, false);
+	binder_release_entire_buffer(proc, thread, buffer, is_failure);
 	binder_alloc_free_buf(&proc->alloc, buffer);
 }
 
@@ -3637,10 +4001,17 @@
 				struct binder_node *ctx_mgr_node;
 				mutex_lock(&context->context_mgr_node_lock);
 				ctx_mgr_node = context->binder_context_mgr_node;
-				if (ctx_mgr_node)
+				if (ctx_mgr_node) {
+					if (ctx_mgr_node->proc == proc) {
+						binder_user_error("%d:%d context manager tried to acquire desc 0\n",
+								  proc->pid, thread->pid);
+						mutex_unlock(&context->context_mgr_node_lock);
+						return -EINVAL;
+					}
 					ret = binder_inc_ref_for_node(
 							proc, ctx_mgr_node,
 							strong, NULL, &rdata);
+				}
 				mutex_unlock(&context->context_mgr_node_lock);
 			}
 			if (ret)
@@ -3784,7 +4155,7 @@
 				     proc->pid, thread->pid, (u64)data_ptr,
 				     buffer->debug_id,
 				     buffer->transaction ? "active" : "finished");
-			binder_free_buf(proc, buffer);
+			binder_free_buf(proc, thread, buffer, false);
 			break;
 		}
 
@@ -4472,7 +4843,7 @@
 			buffer->transaction = NULL;
 			binder_cleanup_transaction(t, "fd fixups failed",
 						   BR_FAILED_REPLY);
-			binder_free_buf(proc, buffer);
+			binder_free_buf(proc, thread, buffer, true);
 			binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
 				     "%d:%d %stransaction %d fd fixups failed %d/%d, line %d\n",
 				     proc->pid, thread->pid,
@@ -4578,13 +4949,17 @@
 				struct list_head *list)
 {
 	struct binder_work *w;
+	enum binder_work_type wtype;
 
 	while (1) {
-		w = binder_dequeue_work_head(proc, list);
+		binder_inner_proc_lock(proc);
+		w = binder_dequeue_work_head_ilocked(list);
+		wtype = w ? w->type : 0;
+		binder_inner_proc_unlock(proc);
 		if (!w)
 			return;
 
-		switch (w->type) {
+		switch (wtype) {
 		case BINDER_WORK_TRANSACTION: {
 			struct binder_transaction *t;
 
@@ -4618,9 +4993,11 @@
 			kfree(death);
 			binder_stats_deleted(BINDER_STAT_DEATH);
 		} break;
+		case BINDER_WORK_NODE:
+			break;
 		default:
 			pr_err("unexpected work type, %d, not freed\n",
-			       w->type);
+			       wtype);
 			break;
 		}
 	}
@@ -4688,10 +5065,18 @@
 
 static void binder_free_proc(struct binder_proc *proc)
 {
+	struct binder_device *device;
+
 	BUG_ON(!list_empty(&proc->todo));
 	BUG_ON(!list_empty(&proc->delivered_death));
+	device = container_of(proc->context, struct binder_device, context);
+	if (refcount_dec_and_test(&device->ref)) {
+		kfree(proc->context->name);
+		kfree(device);
+	}
 	binder_alloc_deferred_release(&proc->alloc);
 	put_task_struct(proc->tsk);
+	put_cred(proc->cred);
 	binder_stats_deleted(BINDER_STAT_PROC);
 	kfree(proc);
 }
@@ -4768,23 +5153,20 @@
 	__release(&t->lock);
 
 	/*
-	 * 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 inner lock.
+	 * If this thread used poll, make sure we remove the waitqueue from any
+	 * poll data structures holding it.
 	 */
-	if ((thread->looper & BINDER_LOOPER_STATE_POLL) &&
-	    waitqueue_active(&thread->wait)) {
-		wake_up_poll(&thread->wait, EPOLLHUP | POLLFREE);
-	}
+	if (thread->looper & BINDER_LOOPER_STATE_POLL)
+		wake_up_pollfree(&thread->wait);
 
 	binder_inner_proc_unlock(thread->proc);
 
 	/*
-	 * 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().
+	 * This is needed to avoid races between wake_up_pollfree() above and
+	 * someone else removing the last entry from the queue for other reasons
+	 * (e.g. ep_remove_wait_queue() being called due to an epoll file
+	 * descriptor being closed).  Such other users hold an RCU read lock, so
+	 * we can be sure they're done after we call synchronize_rcu().
 	 */
 	if (thread->looper & BINDER_LOOPER_STATE_POLL)
 		synchronize_rcu();
@@ -4805,7 +5187,7 @@
 
 	thread = binder_get_thread(proc);
 	if (!thread)
-		return POLLERR;
+		return EPOLLERR;
 
 	binder_inner_proc_lock(thread->proc);
 	thread->looper |= BINDER_LOOPER_STATE_POLL;
@@ -4902,7 +5284,7 @@
 		ret = -EBUSY;
 		goto out;
 	}
-	ret = security_binder_set_context_mgr(proc->tsk);
+	ret = security_binder_set_context_mgr(proc->cred);
 	if (ret < 0)
 		goto out;
 	if (uid_valid(context->binder_context_mgr_uid)) {
@@ -5203,10 +5585,11 @@
 
 static int binder_open(struct inode *nodp, struct file *filp)
 {
-	struct binder_proc *proc;
+	struct binder_proc *proc, *itr;
 	struct binder_device *binder_dev;
 	struct binderfs_info *info;
 	struct dentry *binder_binderfs_dir_entry_proc = NULL;
+	bool existing_pid = false;
 
 	binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
 		     current->group_leader->pid, current->pid);
@@ -5218,6 +5601,7 @@
 	spin_lock_init(&proc->outer_lock);
 	get_task_struct(current->group_leader);
 	proc->tsk = current->group_leader;
+	proc->cred = get_cred(filp->f_cred);
 	INIT_LIST_HEAD(&proc->todo);
 	proc->default_priority = task_nice(current);
 	/* binderfs stashes devices in i_private */
@@ -5229,6 +5613,7 @@
 		binder_dev = container_of(filp->private_data,
 					  struct binder_device, miscdev);
 	}
+	refcount_inc(&binder_dev->ref);
 	proc->context = &binder_dev->context;
 	binder_alloc_init(&proc->alloc);
 
@@ -5239,19 +5624,24 @@
 	filp->private_data = proc;
 
 	mutex_lock(&binder_procs_lock);
+	hlist_for_each_entry(itr, &binder_procs, proc_node) {
+		if (itr->pid == proc->pid) {
+			existing_pid = true;
+			break;
+		}
+	}
 	hlist_add_head(&proc->proc_node, &binder_procs);
 	mutex_unlock(&binder_procs_lock);
 
-	if (binder_debugfs_dir_entry_proc) {
+	if (binder_debugfs_dir_entry_proc && !existing_pid) {
 		char strbuf[11];
 
 		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
 		/*
-		 * proc debug entries are shared between contexts, so
-		 * this will fail if the process tries to open the driver
-		 * again with a different context. The priting code will
-		 * anyway print all contexts that a given PID has, so this
-		 * is not a problem.
+		 * proc debug entries are shared between contexts.
+		 * Only create for the first PID to avoid debugfs log spamming
+		 * The printing code will anyway print all contexts for a given
+		 * PID so this is not a problem.
 		 */
 		proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
 			binder_debugfs_dir_entry_proc,
@@ -5259,19 +5649,16 @@
 			&proc_fops);
 	}
 
-	if (binder_binderfs_dir_entry_proc) {
+	if (binder_binderfs_dir_entry_proc && !existing_pid) {
 		char strbuf[11];
 		struct dentry *binderfs_entry;
 
 		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
 		/*
 		 * Similar to debugfs, the process specific log file is shared
-		 * between contexts. If the file has already been created for a
-		 * process, the following binderfs_create_file() call will
-		 * fail with error code EEXIST if another context of the same
-		 * process invoked binder_open(). This is ok since same as
-		 * debugfs, the log file will contain information on all
-		 * contexts of a given PID.
+		 * between contexts. Only create for the first PID.
+		 * This is ok since same as debugfs, the log file will contain
+		 * information on all contexts of a given PID.
 		 */
 		binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
 			strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
@@ -5281,10 +5668,8 @@
 			int error;
 
 			error = PTR_ERR(binderfs_entry);
-			if (error != -EEXIST) {
-				pr_warn("Unable to create file %s in binderfs (error %d)\n",
-					strbuf, error);
-			}
+			pr_warn("Unable to create file %s in binderfs (error %d)\n",
+				strbuf, error);
 		}
 	}
 
@@ -6063,6 +6448,7 @@
 	.open = binder_open,
 	.flush = binder_flush,
 	.release = binder_release,
+	.may_pollfree = true,
 };
 
 static int __init init_binder_device(const char *name)
@@ -6078,6 +6464,7 @@
 	binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
 	binder_device->miscdev.name = name;
 
+	refcount_set(&binder_device->ref, 1);
 	binder_device->context.binder_context_mgr_uid = INVALID_UID;
 	binder_device->context.name = name;
 	mutex_init(&binder_device->context.context_mgr_node_lock);
@@ -6178,13 +6565,25 @@
 
 err_alloc_device_names_failed:
 	debugfs_remove_recursive(binder_debugfs_dir_entry_root);
+	binder_alloc_shrinker_exit();
 
 	return ret;
 }
 
-device_initcall(binder_init);
+module_init(binder_init);
+/*
+ * binder will have no exit function since binderfs instances can be mounted
+ * multiple times and also in user namespaces finding and destroying them all
+ * is not feasible without introducing insane locking. Just ignoring existing
+ * instances on module unload also wouldn't work since we would loose track of
+ * what major numer was dynamically allocated and also what minor numbers are
+ * already given out. So this would get us into all kinds of issues with device
+ * number reuse. So simply don't allow unloading unless we are forced to do so.
+ */
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_DESCRIPTION("Driver for Android binder device");
+MODULE_LICENSE("GPL v2");
 
 #define CREATE_TRACE_POINTS
 #include "binder_trace.h"
-
-MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/android/binder_alloc.c
+++ linux-ein-5.4.0/drivers/android/binder_alloc.c
@@ -38,8 +38,7 @@
 };
 static uint32_t binder_alloc_debug_mask = BINDER_DEBUG_USER_ERROR;
 
-module_param_named(debug_mask, binder_alloc_debug_mask,
-		   uint, 0644);
+module_param_named(alloc_debug_mask, binder_alloc_debug_mask, uint, 0644);
 
 #define binder_alloc_debug(mask, x...) \
 	do { \
@@ -212,7 +211,7 @@
 		mm = alloc->vma_vm_mm;
 
 	if (mm) {
-		down_read(&mm->mmap_sem);
+		down_write(&mm->mmap_sem);
 		vma = alloc->vma;
 	}
 
@@ -271,14 +270,13 @@
 		/* vm_insert_page does not seem to increment the refcount */
 	}
 	if (mm) {
-		up_read(&mm->mmap_sem);
-		mmput(mm);
+		up_write(&mm->mmap_sem);
+		mmput_async(mm);
 	}
 	return 0;
 
 free_range:
-	for (page_addr = end - PAGE_SIZE; page_addr >= start;
-	     page_addr -= PAGE_SIZE) {
+	for (page_addr = end - PAGE_SIZE; 1; page_addr -= PAGE_SIZE) {
 		bool ret;
 		size_t index;
 
@@ -291,6 +289,8 @@
 		WARN_ON(!ret);
 
 		trace_binder_free_lru_end(alloc, index);
+		if (page_addr == start)
+			break;
 		continue;
 
 err_vm_insert_page_failed:
@@ -298,12 +298,13 @@
 		page->page_ptr = NULL;
 err_alloc_page_failed:
 err_page_ptr_cleared:
-		;
+		if (page_addr == start)
+			break;
 	}
 err_no_vma:
 	if (mm) {
-		up_read(&mm->mmap_sem);
-		mmput(mm);
+		up_write(&mm->mmap_sem);
+		mmput_async(mm);
 	}
 	return vma ? -ENOMEM : -ESRCH;
 }
@@ -376,17 +377,17 @@
 				alloc->pid, extra_buffers_size);
 		return ERR_PTR(-EINVAL);
 	}
-	if (is_async &&
-	    alloc->free_async_space < size + sizeof(struct binder_buffer)) {
+
+	/* Pad 0-size buffers so they get assigned unique addresses */
+	size = max(size, sizeof(void *));
+
+	if (is_async && alloc->free_async_space < size) {
 		binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
 			     "%d: binder_alloc_buf size %zd failed, no async space left\n",
 			      alloc->pid, size);
 		return ERR_PTR(-ENOSPC);
 	}
 
-	/* Pad 0-size buffers so they get assigned unique addresses */
-	size = max(size, sizeof(void *));
-
 	while (n) {
 		buffer = rb_entry(n, struct binder_buffer, rb_node);
 		BUG_ON(!buffer->free);
@@ -486,7 +487,7 @@
 	buffer->async_transaction = is_async;
 	buffer->extra_buffers_size = extra_buffers_size;
 	if (is_async) {
-		alloc->free_async_space -= size + sizeof(struct binder_buffer);
+		alloc->free_async_space -= size;
 		binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
 			     "%d: binder_alloc_buf size %zd async free %zd\n",
 			      alloc->pid, size, alloc->free_async_space);
@@ -513,7 +514,7 @@
  * is the sum of the three given sizes (each rounded up to
  * pointer-sized boundary)
  *
- * Return:	The allocated buffer or %NULL if error
+ * Return:	The allocated buffer or %ERR_PTR(-errno) if error
  */
 struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
 					   size_t data_size,
@@ -611,8 +612,7 @@
 	BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size);
 
 	if (buffer->async_transaction) {
-		alloc->free_async_space += size + sizeof(struct binder_buffer);
-
+		alloc->free_async_space += buffer_size;
 		binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
 			     "%d: binder_free_buf size %zd async free %zd\n",
 			      alloc->pid, size, alloc->free_async_space);
@@ -645,6 +645,8 @@
 	binder_insert_free_buffer(alloc, buffer);
 }
 
+static void binder_alloc_clear_buf(struct binder_alloc *alloc,
+				   struct binder_buffer *buffer);
 /**
  * binder_alloc_free_buf() - free a binder buffer
  * @alloc:	binder_alloc for this proc
@@ -655,6 +657,18 @@
 void binder_alloc_free_buf(struct binder_alloc *alloc,
 			    struct binder_buffer *buffer)
 {
+	/*
+	 * We could eliminate the call to binder_alloc_clear_buf()
+	 * from binder_alloc_deferred_release() by moving this to
+	 * binder_free_buf_locked(). However, that could
+	 * increase contention for the alloc mutex if clear_on_free
+	 * is used frequently for large buffers. The mutex is not
+	 * needed for correctness here.
+	 */
+	if (buffer->clear_on_free) {
+		binder_alloc_clear_buf(alloc, buffer);
+		buffer->clear_on_free = false;
+	}
 	mutex_lock(&alloc->mutex);
 	binder_free_buf_locked(alloc, buffer);
 	mutex_unlock(&alloc->mutex);
@@ -681,17 +695,17 @@
 	struct binder_buffer *buffer;
 
 	mutex_lock(&binder_alloc_mmap_lock);
-	if (alloc->buffer) {
+	if (alloc->buffer_size) {
 		ret = -EBUSY;
 		failure_string = "already mapped";
 		goto err_already_mapped;
 	}
+	alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start,
+				   SZ_4M);
+	mutex_unlock(&binder_alloc_mmap_lock);
 
 	alloc->buffer = (void __user *)vma->vm_start;
-	mutex_unlock(&binder_alloc_mmap_lock);
 
-	alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start,
-				   SZ_4M);
 	alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE,
 			       sizeof(alloc->pages[0]),
 			       GFP_KERNEL);
@@ -722,8 +736,9 @@
 	kfree(alloc->pages);
 	alloc->pages = NULL;
 err_alloc_pages_failed:
-	mutex_lock(&binder_alloc_mmap_lock);
 	alloc->buffer = NULL;
+	mutex_lock(&binder_alloc_mmap_lock);
+	alloc->buffer_size = 0;
 err_already_mapped:
 	mutex_unlock(&binder_alloc_mmap_lock);
 	binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
@@ -750,6 +765,10 @@
 		/* Transaction should already have been freed */
 		BUG_ON(buffer->transaction);
 
+		if (buffer->clear_on_free) {
+			binder_alloc_clear_buf(alloc, buffer);
+			buffer->clear_on_free = false;
+		}
 		binder_free_buf_locked(alloc, buffer);
 		buffers++;
 	}
@@ -841,14 +860,20 @@
 	int free = 0;
 
 	mutex_lock(&alloc->mutex);
-	for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
-		page = &alloc->pages[i];
-		if (!page->page_ptr)
-			free++;
-		else if (list_empty(&page->lru))
-			active++;
-		else
-			lru++;
+	/*
+	 * Make sure the binder_alloc is fully initialized, otherwise we might
+	 * read inconsistent state.
+	 */
+	if (binder_alloc_get_vma(alloc) != NULL) {
+		for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+			page = &alloc->pages[i];
+			if (!page->page_ptr)
+				free++;
+			else if (list_empty(&page->lru))
+				active++;
+			else
+				lru++;
+		}
 	}
 	mutex_unlock(&alloc->mutex);
 	seq_printf(m, "  pages: %d:%d:%d\n", active, lru, free);
@@ -926,7 +951,9 @@
 		goto err_mmget;
 	if (!down_read_trylock(&mm->mmap_sem))
 		goto err_down_read_mmap_sem_failed;
-	vma = binder_alloc_get_vma(alloc);
+	vma = find_vma(mm, page_addr);
+	if (vma && vma != binder_alloc_get_vma(alloc))
+		goto err_invalid_vma;
 
 	list_lru_isolate(lru, item);
 	spin_unlock(lock);
@@ -939,7 +966,7 @@
 		trace_binder_unmap_user_end(alloc, index);
 	}
 	up_read(&mm->mmap_sem);
-	mmput(mm);
+	mmput_async(mm);
 
 	trace_binder_unmap_kernel_start(alloc, index);
 
@@ -952,6 +979,8 @@
 	mutex_unlock(&alloc->mutex);
 	return LRU_REMOVED_RETRY;
 
+err_invalid_vma:
+	up_read(&mm->mmap_sem);
 err_down_read_mmap_sem_failed:
 	mmput_async(mm);
 err_mmget:
@@ -1010,6 +1039,12 @@
 	return ret;
 }
 
+void binder_alloc_shrinker_exit(void)
+{
+	unregister_shrinker(&binder_shrinker);
+	list_lru_destroy(&binder_alloc_lru);
+}
+
 /**
  * check_buffer() - verify that buffer/offset is safe to access
  * @alloc: binder_alloc for this proc
@@ -1078,6 +1113,36 @@
 }
 
 /**
+ * binder_alloc_clear_buf() - zero out buffer
+ * @alloc: binder_alloc for this proc
+ * @buffer: binder buffer to be cleared
+ *
+ * memset the given buffer to 0
+ */
+static void binder_alloc_clear_buf(struct binder_alloc *alloc,
+				   struct binder_buffer *buffer)
+{
+	size_t bytes = binder_alloc_buffer_size(alloc, buffer);
+	binder_size_t buffer_offset = 0;
+
+	while (bytes) {
+		unsigned long size;
+		struct page *page;
+		pgoff_t pgoff;
+		void *kptr;
+
+		page = binder_alloc_get_page(alloc, buffer,
+					     buffer_offset, &pgoff);
+		size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
+		kptr = kmap(page) + pgoff;
+		memset(kptr, 0, size);
+		kunmap(page);
+		bytes -= size;
+		buffer_offset += size;
+	}
+}
+
+/**
  * binder_alloc_copy_user_to_buffer() - copy src user to tgt user
  * @alloc: binder_alloc for this proc
  * @buffer: binder buffer to be accessed
--- linux-ein-5.4.0.orig/drivers/android/binder_alloc.h
+++ linux-ein-5.4.0/drivers/android/binder_alloc.h
@@ -6,6 +6,7 @@
 #ifndef _LINUX_BINDER_ALLOC_H
 #define _LINUX_BINDER_ALLOC_H
 
+#include <linux/kconfig.h>
 #include <linux/rbtree.h>
 #include <linux/list.h>
 #include <linux/mm.h>
@@ -23,6 +24,7 @@
  * @entry:              entry alloc->buffers
  * @rb_node:            node for allocated_buffers/free_buffers rb trees
  * @free:               %true if buffer is free
+ * @clear_on_free:      %true if buffer must be zeroed after use
  * @allow_user_free:    %true if user is allowed to free buffer
  * @async_transaction:  %true if buffer is in use for an async txn
  * @debug_id:           unique ID for debugging
@@ -40,9 +42,10 @@
 	struct rb_node rb_node; /* free entry by size or allocated entry */
 				/* by address */
 	unsigned free:1;
+	unsigned clear_on_free:1;
 	unsigned allow_user_free:1;
 	unsigned async_transaction:1;
-	unsigned debug_id:29;
+	unsigned debug_id:28;
 
 	struct binder_transaction *transaction;
 
@@ -105,7 +108,7 @@
 	size_t pages_high;
 };
 
-#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
+#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_SELFTEST)
 void binder_selftest_alloc(struct binder_alloc *alloc);
 #else
 static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
@@ -120,6 +123,7 @@
 						  int is_async);
 extern void binder_alloc_init(struct binder_alloc *alloc);
 extern int binder_alloc_shrinker_init(void);
+extern void binder_alloc_shrinker_exit(void);
 extern void binder_alloc_vma_close(struct binder_alloc *alloc);
 extern struct binder_buffer *
 binder_alloc_prepare_to_free(struct binder_alloc *alloc,
--- linux-ein-5.4.0.orig/drivers/android/binder_internal.h
+++ linux-ein-5.4.0/drivers/android/binder_internal.h
@@ -5,9 +5,11 @@
 
 #include <linux/export.h>
 #include <linux/fs.h>
+#include <linux/kconfig.h>
 #include <linux/list.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
+#include <linux/refcount.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/uidgid.h>
@@ -33,6 +35,7 @@
 	struct miscdevice miscdev;
 	struct binder_context context;
 	struct inode *binderfs_inode;
+	refcount_t ref;
 };
 
 /**
@@ -73,7 +76,7 @@
 
 extern char *binder_devices_param;
 
-#ifdef CONFIG_ANDROID_BINDERFS
+#if IS_ENABLED(CONFIG_ANDROID_BINDERFS)
 extern bool is_binderfs_device(const struct inode *inode);
 extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name,
 					   const struct file_operations *fops,
@@ -94,7 +97,7 @@
 static inline void binderfs_remove_file(struct dentry *dentry) {}
 #endif
 
-#ifdef CONFIG_ANDROID_BINDERFS
+#if IS_ENABLED(CONFIG_ANDROID_BINDERFS)
 extern int __init init_binderfs(void);
 #else
 static inline int __init init_binderfs(void)
--- linux-ein-5.4.0.orig/drivers/android/binderfs.c
+++ linux-ein-5.4.0/drivers/android/binderfs.c
@@ -109,7 +109,7 @@
 	struct super_block *sb = ref_inode->i_sb;
 	struct binderfs_info *info = sb->s_fs_info;
 #if defined(CONFIG_IPC_NS)
-	bool use_reserve = (info->ipc_ns == &init_ipc_ns);
+	bool use_reserve = (info->ipc_ns == show_init_ipc_ns());
 #else
 	bool use_reserve = true;
 #endif
@@ -154,6 +154,7 @@
 	if (!name)
 		goto err;
 
+	refcount_set(&device->ref, 1);
 	device->binderfs_inode = inode;
 	device->context.binder_context_mgr_uid = INVALID_UID;
 	device->context.name = name;
@@ -257,8 +258,10 @@
 	ida_free(&binderfs_minors, device->miscdev.minor);
 	mutex_unlock(&binderfs_minors_mutex);
 
-	kfree(device->context.name);
-	kfree(device);
+	if (refcount_dec_and_test(&device->ref)) {
+		kfree(device->context.name);
+		kfree(device);
+	}
 }
 
 /**
@@ -405,7 +408,7 @@
 	struct dentry *root = sb->s_root;
 	struct binderfs_info *info = sb->s_fs_info;
 #if defined(CONFIG_IPC_NS)
-	bool use_reserve = (info->ipc_ns == &init_ipc_ns);
+	bool use_reserve = (info->ipc_ns == show_init_ipc_ns());
 #else
 	bool use_reserve = true;
 #endif
@@ -445,6 +448,7 @@
 	inode->i_uid = info->root_uid;
 	inode->i_gid = info->root_gid;
 
+	refcount_set(&device->ref, 1);
 	device->binderfs_inode = inode;
 	device->miscdev.minor = minor;
 
@@ -683,7 +687,7 @@
 		return -ENOMEM;
 	info = sb->s_fs_info;
 
-	info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
+	info->ipc_ns = get_ipc_ns_exported(current->nsproxy->ipc_ns);
 
 	ret = binderfs_parse_mount_opts(data, &info->mount_opts);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/ata/acard-ahci.c
+++ linux-ein-5.4.0/drivers/ata/acard-ahci.c
@@ -56,7 +56,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);
@@ -210,7 +210,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;
@@ -248,6 +248,8 @@
 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
 	ahci_fill_cmd_slot(pp, qc->hw_tag, opts);
+
+	return AC_ERR_OK;
 }
 
 static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
--- linux-ein-5.4.0.orig/drivers/ata/ahci.c
+++ linux-ein-5.4.0/drivers/ata/ahci.c
@@ -48,6 +48,7 @@
 enum board_ids {
 	/* board IDs by feature in alphabetical order */
 	board_ahci,
+	board_ahci_43bit_dma,
 	board_ahci_ign_iferr,
 	board_ahci_mobile,
 	board_ahci_nomsi,
@@ -80,6 +81,8 @@
 
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static void ahci_remove_one(struct pci_dev *dev);
+static void ahci_shutdown_one(struct pci_dev *dev);
+static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv);
 static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
 				 unsigned long deadline);
 static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
@@ -124,6 +127,13 @@
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
+	[board_ahci_43bit_dma] = {
+		AHCI_HFLAGS	(AHCI_HFLAG_43BIT_ONLY),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= ATA_PIO4,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 	[board_ahci_ign_iferr] = {
 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
 		.flags		= AHCI_FLAG_COMMON,
@@ -236,6 +246,7 @@
 
 static const struct pci_device_id ahci_pci_tbl[] = {
 	/* Intel */
+	{ PCI_VDEVICE(INTEL, 0x06d6), board_ahci }, /* Comet Lake PCH-H RAID */
 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
@@ -392,11 +403,13 @@
 	{ 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, 0x06d7), board_ahci }, /* Comet Lake-H RAID */
 	{ PCI_VDEVICE(INTEL, 0x0f22), board_ahci_mobile }, /* Bay Trail AHCI */
 	{ PCI_VDEVICE(INTEL, 0x0f23), board_ahci_mobile }, /* Bay Trail AHCI */
 	{ PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */
 	{ PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_mobile }, /* ApolloLake AHCI */
 	{ PCI_VDEVICE(INTEL, 0x34d3), board_ahci_mobile }, /* Ice Lake LP AHCI */
+	{ PCI_VDEVICE(INTEL, 0x02d7), board_ahci_mobile }, /* Comet Lake PCH RAID */
 
 	/* 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,
@@ -418,6 +431,7 @@
 	/* AMD */
 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
 	{ PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
+	{ PCI_VDEVICE(AMD, 0x7901), board_ahci_mobile }, /* AMD Green Sardine */
 	/* AMD is using RAID class only for ahci controllers */
 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -557,11 +571,11 @@
 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
 	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
 
-	/* Asmedia */
+	/* ASMedia */
 	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },	/* ASM1060 */
 	{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },	/* ASM1060 */
-	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },	/* ASM1061 */
-	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },	/* ASM1062 */
+	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma },	/* ASM1061 */
+	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma },	/* ASM1061/1062 */
 	{ PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci },   /* ASM1061R */
 	{ PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci },   /* ASM1062R */
 
@@ -593,6 +607,7 @@
 	.id_table		= ahci_pci_tbl,
 	.probe			= ahci_init_one,
 	.remove			= ahci_remove_one,
+	.shutdown		= ahci_shutdown_one,
 	.driver = {
 		.pm		= &ahci_pci_pm_ops,
 	},
@@ -613,6 +628,11 @@
 static void ahci_pci_save_initial_config(struct pci_dev *pdev,
 					 struct ahci_host_priv *hpriv)
 {
+	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) {
+		dev_info(&pdev->dev, "ASM1166 has only six ports\n");
+		hpriv->saved_port_map = 0x3f;
+	}
+
 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
 		dev_info(&pdev->dev, "JMB361 has only one port\n");
 		hpriv->force_port_map = 1;
@@ -635,6 +655,25 @@
 	ahci_save_initial_config(&pdev->dev, hpriv);
 }
 
+static int ahci_pci_reset_controller(struct ata_host *host)
+{
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	struct ahci_host_priv *hpriv = host->private_data;
+	int rc;
+
+	rc = ahci_reset_controller(host);
+	if (rc)
+		return rc;
+
+	/*
+	 * If platform firmware failed to enable ports, try to enable
+	 * them here.
+	 */
+	ahci_intel_pcs_quirk(pdev, hpriv);
+
+	return 0;
+}
+
 static void ahci_pci_init_controller(struct ata_host *host)
 {
 	struct ahci_host_priv *hpriv = host->private_data;
@@ -837,7 +876,7 @@
 	struct ata_host *host = pci_get_drvdata(pdev);
 	int rc;
 
-	rc = ahci_reset_controller(host);
+	rc = ahci_pci_reset_controller(host);
 	if (rc)
 		return rc;
 	ahci_pci_init_controller(host);
@@ -872,7 +911,7 @@
 		ahci_mcp89_apple_enable(pdev);
 
 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(host);
+		rc = ahci_pci_reset_controller(host);
 		if (rc)
 			return rc;
 
@@ -887,11 +926,20 @@
 
 #endif /* CONFIG_PM */
 
-static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
+static int ahci_configure_dma_masks(struct pci_dev *pdev,
+				    struct ahci_host_priv *hpriv)
 {
-	const int dma_bits = using_dac ? 64 : 32;
+	int dma_bits;
 	int rc;
 
+	if (hpriv->cap & HOST_CAP_64) {
+		dma_bits = 64;
+		if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY)
+			dma_bits = 43;
+	} else {
+		dma_bits = 32;
+	}
+
 	/*
 	 * If the device fixup already set the dma_mask to some non-standard
 	 * value, don't extend it here. This happens on STA2X11, for example.
@@ -1473,7 +1521,7 @@
 static void ahci_remap_check(struct pci_dev *pdev, int bar,
 		struct ahci_host_priv *hpriv)
 {
-	int i, count = 0;
+	int i;
 	u32 cap;
 
 	/*
@@ -1494,13 +1542,14 @@
 			continue;
 
 		/* We've found a remapped device */
-		count++;
+		hpriv->remapped_nvme++;
 	}
 
-	if (!count)
+	if (!hpriv->remapped_nvme)
 		return;
 
-	dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count);
+	dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
+		 hpriv->remapped_nvme);
 	dev_warn(&pdev->dev,
 		 "Switch your BIOS from RAID to AHCI mode to use them.\n");
 
@@ -1620,6 +1669,18 @@
 	}
 }
 
+static ssize_t remapped_nvme_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct ata_host *host = dev_get_drvdata(dev);
+	struct ahci_host_priv *hpriv = host->private_data;
+
+	return sprintf(buf, "%u\n", hpriv->remapped_nvme);
+}
+
+static DEVICE_ATTR_RO(remapped_nvme);
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	unsigned int board_id = ent->driver_data;
@@ -1720,11 +1781,20 @@
 	/* detect remapped nvme devices */
 	ahci_remap_check(pdev, ahci_pci_bar, hpriv);
 
+	sysfs_add_file_to_group(&pdev->dev.kobj,
+				&dev_attr_remapped_nvme.attr,
+				NULL);
+
 	/* must set flag prior to save config in order to take effect */
 	if (ahci_broken_devslp(pdev))
 		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
 
 #ifdef CONFIG_ARM64
+	if (pdev->vendor == PCI_VENDOR_ID_HUAWEI &&
+	    pdev->device == 0xa235 &&
+	    pdev->revision < 0x30)
+		hpriv->flags |= AHCI_HFLAG_NO_SXS;
+
 	if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
 		hpriv->irq_handler = ahci_thunderx_irq_handler;
 #endif
@@ -1732,12 +1802,6 @@
 	/* save initial config */
 	ahci_pci_save_initial_config(pdev, hpriv);
 
-	/*
-	 * If platform firmware failed to enable ports, try to enable
-	 * them here.
-	 */
-	ahci_intel_pcs_quirk(pdev, hpriv);
-
 	/* prepare host */
 	if (hpriv->cap & HOST_CAP_NCQ) {
 		pi.flags |= ATA_FLAG_NCQ;
@@ -1815,6 +1879,15 @@
 	else
 		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
 
+	if (!(hpriv->cap & HOST_CAP_PART))
+		host->flags |= ATA_HOST_NO_PART;
+
+	if (!(hpriv->cap & HOST_CAP_SSC))
+		host->flags |= ATA_HOST_NO_SSC;
+
+	if (!(hpriv->cap2 & HOST_CAP2_SDS))
+		host->flags |= ATA_HOST_NO_DEVSLP;
+
 	if (pi.flags & ATA_FLAG_EM)
 		ahci_reset_em(host);
 
@@ -1843,11 +1916,11 @@
 	ahci_gtf_filter_workaround(host);
 
 	/* initialize adapter */
-	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
+	rc = ahci_configure_dma_masks(pdev, hpriv);
 	if (rc)
 		return rc;
 
-	rc = ahci_reset_controller(host);
+	rc = ahci_pci_reset_controller(host);
 	if (rc)
 		return rc;
 
@@ -1864,8 +1937,16 @@
 	return 0;
 }
 
+static void ahci_shutdown_one(struct pci_dev *pdev)
+{
+	ata_pci_shutdown_one(pdev);
+}
+
 static void ahci_remove_one(struct pci_dev *pdev)
 {
+	sysfs_remove_file_from_group(&pdev->dev.kobj,
+				     &dev_attr_remapped_nvme.attr,
+				     NULL);
 	pm_runtime_get_noresume(&pdev->dev);
 	ata_pci_remove_one(pdev);
 }
--- linux-ein-5.4.0.orig/drivers/ata/ahci.h
+++ linux-ein-5.4.0/drivers/ata/ahci.h
@@ -24,6 +24,7 @@
 #include <linux/libata.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
+#include <linux/bits.h>
 
 /* Enclosure Management Control */
 #define EM_CTRL_MSG_TYPE              0x000f0000
@@ -54,12 +55,12 @@
 	AHCI_PORT_PRIV_FBS_DMA_SZ	= AHCI_CMD_SLOT_SZ +
 					  AHCI_CMD_TBL_AR_SZ +
 					  (AHCI_RX_FIS_SZ * 16),
-	AHCI_IRQ_ON_SG		= (1 << 31),
-	AHCI_CMD_ATAPI		= (1 << 5),
-	AHCI_CMD_WRITE		= (1 << 6),
-	AHCI_CMD_PREFETCH	= (1 << 7),
-	AHCI_CMD_RESET		= (1 << 8),
-	AHCI_CMD_CLR_BUSY	= (1 << 10),
+	AHCI_IRQ_ON_SG		= BIT(31),
+	AHCI_CMD_ATAPI		= BIT(5),
+	AHCI_CMD_WRITE		= BIT(6),
+	AHCI_CMD_PREFETCH	= BIT(7),
+	AHCI_CMD_RESET		= BIT(8),
+	AHCI_CMD_CLR_BUSY	= BIT(10),
 
 	RX_FIS_PIO_SETUP	= 0x20,	/* offset of PIO Setup FIS data */
 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
@@ -77,37 +78,37 @@
 	HOST_CAP2		= 0x24, /* host capabilities, extended */
 
 	/* HOST_CTL bits */
-	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
-	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
-	HOST_MRSM		= (1 << 2),  /* MSI Revert to Single Message */
-	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
+	HOST_RESET		= BIT(0),  /* reset controller; self-clear */
+	HOST_IRQ_EN		= BIT(1),  /* global IRQ enable */
+	HOST_MRSM		= BIT(2),  /* MSI Revert to Single Message */
+	HOST_AHCI_EN		= BIT(31), /* AHCI enabled */
 
 	/* HOST_CAP bits */
-	HOST_CAP_SXS		= (1 << 5),  /* Supports External SATA */
-	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
-	HOST_CAP_CCC		= (1 << 7),  /* Command Completion Coalescing */
-	HOST_CAP_PART		= (1 << 13), /* Partial state capable */
-	HOST_CAP_SSC		= (1 << 14), /* Slumber state capable */
-	HOST_CAP_PIO_MULTI	= (1 << 15), /* PIO multiple DRQ support */
-	HOST_CAP_FBS		= (1 << 16), /* FIS-based switching support */
-	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
-	HOST_CAP_ONLY		= (1 << 18), /* Supports AHCI mode only */
-	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
-	HOST_CAP_LED		= (1 << 25), /* Supports activity LED */
-	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
-	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
-	HOST_CAP_MPS		= (1 << 28), /* Mechanical presence switch */
-	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
-	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
-	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
+	HOST_CAP_SXS		= BIT(5),  /* Supports External SATA */
+	HOST_CAP_EMS		= BIT(6),  /* Enclosure Management support */
+	HOST_CAP_CCC		= BIT(7),  /* Command Completion Coalescing */
+	HOST_CAP_PART		= BIT(13), /* Partial state capable */
+	HOST_CAP_SSC		= BIT(14), /* Slumber state capable */
+	HOST_CAP_PIO_MULTI	= BIT(15), /* PIO multiple DRQ support */
+	HOST_CAP_FBS		= BIT(16), /* FIS-based switching support */
+	HOST_CAP_PMP		= BIT(17), /* Port Multiplier support */
+	HOST_CAP_ONLY		= BIT(18), /* Supports AHCI mode only */
+	HOST_CAP_CLO		= BIT(24), /* Command List Override support */
+	HOST_CAP_LED		= BIT(25), /* Supports activity LED */
+	HOST_CAP_ALPM		= BIT(26), /* Aggressive Link PM support */
+	HOST_CAP_SSS		= BIT(27), /* Staggered Spin-up */
+	HOST_CAP_MPS		= BIT(28), /* Mechanical presence switch */
+	HOST_CAP_SNTF		= BIT(29), /* SNotification register */
+	HOST_CAP_NCQ		= BIT(30), /* Native Command Queueing */
+	HOST_CAP_64		= BIT(31), /* PCI DAC (64-bit DMA) support */
 
 	/* HOST_CAP2 bits */
-	HOST_CAP2_BOH		= (1 << 0),  /* BIOS/OS handoff supported */
-	HOST_CAP2_NVMHCI	= (1 << 1),  /* NVMHCI supported */
-	HOST_CAP2_APST		= (1 << 2),  /* Automatic partial to slumber */
-	HOST_CAP2_SDS		= (1 << 3),  /* Support device sleep */
-	HOST_CAP2_SADM		= (1 << 4),  /* Support aggressive DevSlp */
-	HOST_CAP2_DESO		= (1 << 5),  /* DevSlp from slumber only */
+	HOST_CAP2_BOH		= BIT(0),  /* BIOS/OS handoff supported */
+	HOST_CAP2_NVMHCI	= BIT(1),  /* NVMHCI supported */
+	HOST_CAP2_APST		= BIT(2),  /* Automatic partial to slumber */
+	HOST_CAP2_SDS		= BIT(3),  /* Support device sleep */
+	HOST_CAP2_SADM		= BIT(4),  /* Support aggressive DevSlp */
+	HOST_CAP2_DESO		= BIT(5),  /* DevSlp from slumber only */
 
 	/* registers for each SATA port */
 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
@@ -129,24 +130,24 @@
 	PORT_DEVSLP		= 0x44, /* device sleep */
 
 	/* PORT_IRQ_{STAT,MASK} bits */
-	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
-	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
-	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
-	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
-	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
-	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
-	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
-	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
-
-	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
-	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
-	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
-	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
-	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
-	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
-	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
-	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
-	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
+	PORT_IRQ_COLD_PRES	= BIT(31), /* cold presence detect */
+	PORT_IRQ_TF_ERR		= BIT(30), /* task file error */
+	PORT_IRQ_HBUS_ERR	= BIT(29), /* host bus fatal error */
+	PORT_IRQ_HBUS_DATA_ERR	= BIT(28), /* host bus data error */
+	PORT_IRQ_IF_ERR		= BIT(27), /* interface fatal error */
+	PORT_IRQ_IF_NONFATAL	= BIT(26), /* interface non-fatal error */
+	PORT_IRQ_OVERFLOW	= BIT(24), /* xfer exhausted available S/G */
+	PORT_IRQ_BAD_PMP	= BIT(23), /* incorrect port multiplier */
+
+	PORT_IRQ_PHYRDY		= BIT(22), /* PhyRdy changed */
+	PORT_IRQ_DEV_ILCK	= BIT(7),  /* device interlock */
+	PORT_IRQ_CONNECT	= BIT(6),  /* port connect change status */
+	PORT_IRQ_SG_DONE	= BIT(5),  /* descriptor processed */
+	PORT_IRQ_UNK_FIS	= BIT(4),  /* unknown FIS rx'd */
+	PORT_IRQ_SDB_FIS	= BIT(3),  /* Set Device Bits FIS rx'd */
+	PORT_IRQ_DMAS_FIS	= BIT(2),  /* DMA Setup FIS rx'd */
+	PORT_IRQ_PIOS_FIS	= BIT(1),  /* PIO Setup FIS rx'd */
+	PORT_IRQ_D2H_REG_FIS	= BIT(0),  /* D2H Register FIS rx'd */
 
 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
 				  PORT_IRQ_IF_ERR |
@@ -162,34 +163,34 @@
 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
 
 	/* PORT_CMD bits */
-	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
-	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
-	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
-	PORT_CMD_FBSCP		= (1 << 22), /* FBS Capable Port */
-	PORT_CMD_ESP		= (1 << 21), /* External Sata Port */
-	PORT_CMD_HPCP		= (1 << 18), /* HotPlug Capable Port */
-	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
-	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
-	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
-	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
-	PORT_CMD_CLO		= (1 << 3), /* Command list override */
-	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
-	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
-	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
-
-	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
-	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
-	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
-	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
+	PORT_CMD_ASP		= BIT(27), /* Aggressive Slumber/Partial */
+	PORT_CMD_ALPE		= BIT(26), /* Aggressive Link PM enable */
+	PORT_CMD_ATAPI		= BIT(24), /* Device is ATAPI */
+	PORT_CMD_FBSCP		= BIT(22), /* FBS Capable Port */
+	PORT_CMD_ESP		= BIT(21), /* External Sata Port */
+	PORT_CMD_HPCP		= BIT(18), /* HotPlug Capable Port */
+	PORT_CMD_PMP		= BIT(17), /* PMP attached */
+	PORT_CMD_LIST_ON	= BIT(15), /* cmd list DMA engine running */
+	PORT_CMD_FIS_ON		= BIT(14), /* FIS DMA engine running */
+	PORT_CMD_FIS_RX		= BIT(4),  /* Enable FIS receive DMA engine */
+	PORT_CMD_CLO		= BIT(3),  /* Command list override */
+	PORT_CMD_POWER_ON	= BIT(2),  /* Power up device */
+	PORT_CMD_SPIN_UP	= BIT(1),  /* Spin up device */
+	PORT_CMD_START		= BIT(0),  /* Enable port DMA engine */
+
+	PORT_CMD_ICC_MASK	= (0xfu << 28), /* i/f ICC state mask */
+	PORT_CMD_ICC_ACTIVE	= (0x1u << 28), /* Put i/f in active state */
+	PORT_CMD_ICC_PARTIAL	= (0x2u << 28), /* Put i/f in partial state */
+	PORT_CMD_ICC_SLUMBER	= (0x6u << 28), /* Put i/f in slumber state */
 
 	/* PORT_FBS bits */
 	PORT_FBS_DWE_OFFSET	= 16, /* FBS device with error offset */
 	PORT_FBS_ADO_OFFSET	= 12, /* FBS active dev optimization offset */
 	PORT_FBS_DEV_OFFSET	= 8,  /* FBS device to issue offset */
 	PORT_FBS_DEV_MASK	= (0xf << PORT_FBS_DEV_OFFSET),  /* FBS.DEV */
-	PORT_FBS_SDE		= (1 << 2), /* FBS single device error */
-	PORT_FBS_DEC		= (1 << 1), /* FBS device error clear */
-	PORT_FBS_EN		= (1 << 0), /* Enable FBS */
+	PORT_FBS_SDE		= BIT(2), /* FBS single device error */
+	PORT_FBS_DEC		= BIT(1), /* FBS device error clear */
+	PORT_FBS_EN		= BIT(0), /* Enable FBS */
 
 	/* PORT_DEVSLP bits */
 	PORT_DEVSLP_DM_OFFSET	= 25,             /* DITO multiplier offset */
@@ -197,49 +198,53 @@
 	PORT_DEVSLP_DITO_OFFSET	= 15,             /* DITO offset */
 	PORT_DEVSLP_MDAT_OFFSET	= 10,             /* Minimum assertion time */
 	PORT_DEVSLP_DETO_OFFSET	= 2,              /* DevSlp exit timeout */
-	PORT_DEVSLP_DSP		= (1 << 1),       /* DevSlp present */
-	PORT_DEVSLP_ADSE	= (1 << 0),       /* Aggressive DevSlp enable */
+	PORT_DEVSLP_DSP		= BIT(1),         /* DevSlp present */
+	PORT_DEVSLP_ADSE	= BIT(0),         /* Aggressive DevSlp enable */
 
 	/* hpriv->flags bits */
 
 #define AHCI_HFLAGS(flags)		.private_data	= (void *)(flags)
 
-	AHCI_HFLAG_NO_NCQ		= (1 << 0),
-	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
-	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
-	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
-	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
-	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
-	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
-	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
-	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
-	AHCI_HFLAG_NO_SUSPEND		= (1 << 10), /* don't suspend */
-	AHCI_HFLAG_SRST_TOUT_IS_OFFLINE	= (1 << 11), /* treat SRST timeout as
-							link offline */
-	AHCI_HFLAG_NO_SNTF		= (1 << 12), /* no sntf */
-	AHCI_HFLAG_NO_FPDMA_AA		= (1 << 13), /* no FPDMA AA */
-	AHCI_HFLAG_YES_FBS		= (1 << 14), /* force FBS cap on */
-	AHCI_HFLAG_DELAY_ENGINE		= (1 << 15), /* do not start engine on
-						        port start (wait until
-						        error-handling stage) */
-	AHCI_HFLAG_NO_DEVSLP		= (1 << 17), /* no device sleep */
-	AHCI_HFLAG_NO_FBS		= (1 << 18), /* no FBS */
+	AHCI_HFLAG_NO_NCQ		= BIT(0),
+	AHCI_HFLAG_IGN_IRQ_IF_ERR	= BIT(1), /* ignore IRQ_IF_ERR */
+	AHCI_HFLAG_IGN_SERR_INTERNAL	= BIT(2), /* ignore SERR_INTERNAL */
+	AHCI_HFLAG_32BIT_ONLY		= BIT(3), /* force 32bit */
+	AHCI_HFLAG_MV_PATA		= BIT(4), /* PATA port */
+	AHCI_HFLAG_NO_MSI		= BIT(5), /* no PCI MSI */
+	AHCI_HFLAG_NO_PMP		= BIT(6), /* no PMP */
+	AHCI_HFLAG_SECT255		= BIT(8), /* max 255 sectors */
+	AHCI_HFLAG_YES_NCQ		= BIT(9), /* force NCQ cap on */
+	AHCI_HFLAG_NO_SUSPEND		= BIT(10), /* don't suspend */
+	AHCI_HFLAG_SRST_TOUT_IS_OFFLINE	= BIT(11), /* treat SRST timeout as
+						      link offline */
+	AHCI_HFLAG_NO_SNTF		= BIT(12), /* no sntf */
+	AHCI_HFLAG_NO_FPDMA_AA		= BIT(13), /* no FPDMA AA */
+	AHCI_HFLAG_YES_FBS		= BIT(14), /* force FBS cap on */
+	AHCI_HFLAG_DELAY_ENGINE		= BIT(15), /* do not start engine on
+						      port start (wait until
+						      error-handling stage) */
+	AHCI_HFLAG_NO_DEVSLP		= BIT(17), /* no device sleep */
+	AHCI_HFLAG_NO_FBS		= BIT(18), /* no FBS */
 
 #ifdef CONFIG_PCI_MSI
-	AHCI_HFLAG_MULTI_MSI		= (1 << 20), /* per-port MSI(-X) */
+	AHCI_HFLAG_MULTI_MSI		= BIT(20), /* per-port MSI(-X) */
 #else
 	/* compile out MSI infrastructure */
 	AHCI_HFLAG_MULTI_MSI		= 0,
 #endif
-	AHCI_HFLAG_WAKE_BEFORE_STOP	= (1 << 22), /* wake before DMA stop */
-	AHCI_HFLAG_YES_ALPM		= (1 << 23), /* force ALPM cap on */
-	AHCI_HFLAG_NO_WRITE_TO_RO	= (1 << 24), /* don't write to read
-							only registers */
-	AHCI_HFLAG_IS_MOBILE		= (1 << 25), /* mobile chipset, use
-							SATA_MOBILE_LPM_POLICY
-							as default lpm_policy */
-	AHCI_HFLAG_SUSPEND_PHYS		= (1 << 26), /* handle PHYs during
-							suspend/resume */
+	AHCI_HFLAG_WAKE_BEFORE_STOP	= BIT(22), /* wake before DMA stop */
+	AHCI_HFLAG_YES_ALPM		= BIT(23), /* force ALPM cap on */
+	AHCI_HFLAG_NO_WRITE_TO_RO	= BIT(24), /* don't write to read
+						      only registers */
+	AHCI_HFLAG_IS_MOBILE            = BIT(25), /* mobile chipset, use
+						      SATA_MOBILE_LPM_POLICY
+						      as default lpm_policy */
+	AHCI_HFLAG_SUSPEND_PHYS		= BIT(26), /* handle PHYs during
+						      suspend/resume */
+	AHCI_HFLAG_IGN_NOTSUPP_POWER_ON	= BIT(27), /* ignore -EOPNOTSUPP
+						      from phy_power_on() */
+	AHCI_HFLAG_NO_SXS		= BIT(28), /* SXS not supported */
+	AHCI_HFLAG_43BIT_ONLY		= BIT(29), /* 43bit DMA addr limit */
 
 	/* ap->flags bits */
 
@@ -251,26 +256,26 @@
 	PCS_7				= 0x94, /* 7+ port PCS (Denverton) */
 
 	/* em constants */
-	EM_MAX_SLOTS			= 8,
+	EM_MAX_SLOTS			= SATA_PMP_MAX_PORTS,
 	EM_MAX_RETRY			= 5,
 
 	/* em_ctl bits */
-	EM_CTL_RST		= (1 << 9), /* Reset */
-	EM_CTL_TM		= (1 << 8), /* Transmit Message */
-	EM_CTL_MR		= (1 << 0), /* Message Received */
-	EM_CTL_ALHD		= (1 << 26), /* Activity LED */
-	EM_CTL_XMT		= (1 << 25), /* Transmit Only */
-	EM_CTL_SMB		= (1 << 24), /* Single Message Buffer */
-	EM_CTL_SGPIO		= (1 << 19), /* SGPIO messages supported */
-	EM_CTL_SES		= (1 << 18), /* SES-2 messages supported */
-	EM_CTL_SAFTE		= (1 << 17), /* SAF-TE messages supported */
-	EM_CTL_LED		= (1 << 16), /* LED messages supported */
+	EM_CTL_RST		= BIT(9), /* Reset */
+	EM_CTL_TM		= BIT(8), /* Transmit Message */
+	EM_CTL_MR		= BIT(0), /* Message Received */
+	EM_CTL_ALHD		= BIT(26), /* Activity LED */
+	EM_CTL_XMT		= BIT(25), /* Transmit Only */
+	EM_CTL_SMB		= BIT(24), /* Single Message Buffer */
+	EM_CTL_SGPIO		= BIT(19), /* SGPIO messages supported */
+	EM_CTL_SES		= BIT(18), /* SES-2 messages supported */
+	EM_CTL_SAFTE		= BIT(17), /* SAF-TE messages supported */
+	EM_CTL_LED		= BIT(16), /* LED messages supported */
 
 	/* em message type */
-	EM_MSG_TYPE_LED		= (1 << 0), /* LED */
-	EM_MSG_TYPE_SAFTE	= (1 << 1), /* SAF-TE */
-	EM_MSG_TYPE_SES2	= (1 << 2), /* SES-2 */
-	EM_MSG_TYPE_SGPIO	= (1 << 3), /* SGPIO */
+	EM_MSG_TYPE_LED		= BIT(0), /* LED */
+	EM_MSG_TYPE_SAFTE	= BIT(1), /* SAF-TE */
+	EM_MSG_TYPE_SES2	= BIT(2), /* SES-2 */
+	EM_MSG_TYPE_SGPIO	= BIT(3), /* SGPIO */
 };
 
 struct ahci_cmd_hdr {
@@ -336,6 +341,7 @@
 	u32 			em_loc; /* enclosure management location */
 	u32			em_buf_sz;	/* EM buffer size in byte */
 	u32			em_msg_type;	/* EM message type */
+	u32			remapped_nvme;	/* NVMe remapped device count */
 	bool			got_runtime_pm; /* Did we do pm_runtime_get? */
 	struct clk		*clks[AHCI_MAX_CLKS]; /* Optional */
 	struct reset_control	*rsts;		/* Optional */
--- linux-ein-5.4.0.orig/drivers/ata/ahci_brcm.c
+++ linux-ein-5.4.0/drivers/ata/ahci_brcm.c
@@ -76,8 +76,7 @@
 };
 
 enum brcm_ahci_quirks {
-	BRCM_AHCI_QUIRK_NO_NCQ		= BIT(0),
-	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(1),
+	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(0),
 };
 
 struct brcm_ahci_priv {
@@ -213,19 +212,12 @@
 			brcm_sata_phy_disable(priv, i);
 }
 
-static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
+static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,
 				  struct brcm_ahci_priv *priv)
 {
-	void __iomem *ahci;
-	struct resource *res;
 	u32 impl;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
-	ahci = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ahci))
-		return 0;
-
-	impl = readl(ahci + HOST_PORTS_IMPL);
+	impl = readl(hpriv->mmio + HOST_PORTS_IMPL);
 
 	if (fls(impl) > SATA_TOP_MAX_PHYS)
 		dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
@@ -233,9 +225,6 @@
 	else if (!impl)
 		dev_info(priv->dev, "no ports found\n");
 
-	devm_iounmap(&pdev->dev, ahci);
-	devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-
 	return impl;
 }
 
@@ -285,6 +274,13 @@
 	/* Perform the SATA PHY reset sequence */
 	brcm_sata_phy_disable(priv, ap->port_no);
 
+	/* Reset the SATA clock */
+	ahci_platform_disable_clks(hpriv);
+	msleep(10);
+
+	ahci_platform_enable_clks(hpriv);
+	msleep(10);
+
 	/* Bring the PHY back on */
 	brcm_sata_phy_enable(priv, ap->port_no);
 
@@ -347,11 +343,10 @@
 	struct ata_host *host = dev_get_drvdata(dev);
 	struct ahci_host_priv *hpriv = host->private_data;
 	struct brcm_ahci_priv *priv = hpriv->plat_data;
-	int ret;
 
-	ret = ahci_platform_suspend(dev);
 	brcm_sata_phys_disable(priv);
-	return ret;
+
+	return ahci_platform_suspend(dev);
 }
 
 static int brcm_ahci_resume(struct device *dev)
@@ -359,11 +354,50 @@
 	struct ata_host *host = dev_get_drvdata(dev);
 	struct ahci_host_priv *hpriv = host->private_data;
 	struct brcm_ahci_priv *priv = hpriv->plat_data;
+	int ret;
+
+	/* Make sure clocks are turned on before re-configuration */
+	ret = ahci_platform_enable_clks(hpriv);
+	if (ret)
+		return ret;
+
+	ret = ahci_platform_enable_regulators(hpriv);
+	if (ret)
+		goto out_disable_clks;
 
 	brcm_sata_init(priv);
 	brcm_sata_phys_enable(priv);
 	brcm_sata_alpm_init(hpriv);
-	return ahci_platform_resume(dev);
+
+	/* Since we had to enable clocks earlier on, we cannot use
+	 * ahci_platform_resume() as-is since a second call to
+	 * ahci_platform_enable_resources() would bump up the resources
+	 * (regulators, clocks, PHYs) count artificially so we copy the part
+	 * after ahci_platform_enable_resources().
+	 */
+	ret = ahci_platform_enable_phys(hpriv);
+	if (ret)
+		goto out_disable_phys;
+
+	ret = ahci_platform_resume_host(dev);
+	if (ret)
+		goto out_disable_platform_phys;
+
+	/* We resumed so update PM runtime state */
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+
+out_disable_platform_phys:
+	ahci_platform_disable_phys(hpriv);
+out_disable_phys:
+	brcm_sata_phys_disable(priv);
+	ahci_platform_disable_regulators(hpriv);
+out_disable_clks:
+	ahci_platform_disable_clks(hpriv);
+	return ret;
 }
 #endif
 
@@ -410,44 +444,77 @@
 	if (!IS_ERR_OR_NULL(priv->rcdev))
 		reset_control_deassert(priv->rcdev);
 
-	if ((priv->version == BRCM_SATA_BCM7425) ||
-		(priv->version == BRCM_SATA_NSP)) {
-		priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
+	hpriv = ahci_platform_get_resources(pdev, 0);
+	if (IS_ERR(hpriv)) {
+		ret = PTR_ERR(hpriv);
+		goto out_reset;
+	}
+
+	hpriv->plat_data = priv;
+	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;
+
+	switch (priv->version) {
+	case BRCM_SATA_BCM7425:
+		hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
+		/* fall through */
+	case BRCM_SATA_NSP:
+		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
 		priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
+		break;
+	default:
+		break;
 	}
 
+	ret = ahci_platform_enable_clks(hpriv);
+	if (ret)
+		goto out_reset;
+
+	ret = ahci_platform_enable_regulators(hpriv);
+	if (ret)
+		goto out_disable_clks;
+
+	/* Must be first so as to configure endianness including that
+	 * of the standard AHCI register space.
+	 */
 	brcm_sata_init(priv);
 
-	priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
-	if (!priv->port_mask)
-		return -ENODEV;
+	/* Initializes priv->port_mask which is used below */
+	priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
+	if (!priv->port_mask) {
+		ret = -ENODEV;
+		goto out_disable_regulators;
+	}
 
+	/* Must be done before ahci_platform_enable_phys() */
 	brcm_sata_phys_enable(priv);
 
-	hpriv = ahci_platform_get_resources(pdev, 0);
-	if (IS_ERR(hpriv))
-		return PTR_ERR(hpriv);
-	hpriv->plat_data = priv;
-	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
-
 	brcm_sata_alpm_init(hpriv);
 
-	ret = ahci_platform_enable_resources(hpriv);
+	ret = ahci_platform_enable_phys(hpriv);
 	if (ret)
-		return ret;
-
-	if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
-		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
-	hpriv->flags |= AHCI_HFLAG_NO_WRITE_TO_RO;
+		goto out_disable_phys;
 
 	ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
 				      &ahci_platform_sht);
 	if (ret)
-		return ret;
+		goto out_disable_platform_phys;
 
 	dev_info(dev, "Broadcom AHCI SATA3 registered\n");
 
 	return 0;
+
+out_disable_platform_phys:
+	ahci_platform_disable_phys(hpriv);
+out_disable_phys:
+	brcm_sata_phys_disable(priv);
+out_disable_regulators:
+	ahci_platform_disable_regulators(hpriv);
+out_disable_clks:
+	ahci_platform_disable_clks(hpriv);
+out_reset:
+	if (!IS_ERR_OR_NULL(priv->rcdev))
+		reset_control_assert(priv->rcdev);
+	return ret;
 }
 
 static int brcm_ahci_remove(struct platform_device *pdev)
@@ -457,12 +524,12 @@
 	struct brcm_ahci_priv *priv = hpriv->plat_data;
 	int ret;
 
+	brcm_sata_phys_disable(priv);
+
 	ret = ata_platform_remove_one(pdev);
 	if (ret)
 		return ret;
 
-	brcm_sata_phys_disable(priv);
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/ata/ahci_imx.c
+++ linux-ein-5.4.0/drivers/ata/ahci_imx.c
@@ -1239,4 +1239,4 @@
 MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
 MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("ahci:imx");
+MODULE_ALIAS("platform:" DRV_NAME);
--- linux-ein-5.4.0.orig/drivers/ata/ahci_mvebu.c
+++ linux-ein-5.4.0/drivers/ata/ahci_mvebu.c
@@ -227,7 +227,7 @@
 
 static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = {
 	.plat_config = ahci_mvebu_armada_3700_config,
-	.flags = AHCI_HFLAG_SUSPEND_PHYS,
+	.flags = AHCI_HFLAG_SUSPEND_PHYS | AHCI_HFLAG_IGN_NOTSUPP_POWER_ON,
 };
 
 static const struct of_device_id ahci_mvebu_of_match[] = {
--- linux-ein-5.4.0.orig/drivers/ata/ahci_sunxi.c
+++ linux-ein-5.4.0/drivers/ata/ahci_sunxi.c
@@ -200,7 +200,7 @@
 }
 
 static const struct ata_port_info ahci_sunxi_port_info = {
-	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NCQ | ATA_FLAG_NO_DIPM,
 	.pio_mask	= ATA_PIO4,
 	.udma_mask	= ATA_UDMA6,
 	.port_ops	= &ahci_platform_ops,
--- linux-ein-5.4.0.orig/drivers/ata/libahci.c
+++ linux-ein-5.4.0/drivers/ata/libahci.c
@@ -57,7 +57,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);
@@ -493,6 +493,11 @@
 		cap |= HOST_CAP_ALPM;
 	}
 
+	if ((cap & HOST_CAP_SXS) && (hpriv->flags & AHCI_HFLAG_NO_SXS)) {
+		dev_info(dev, "controller does not support SXS, disabling CAP_SXS\n");
+		cap &= ~HOST_CAP_SXS;
+	}
+
 	if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
 		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
 			 port_map, hpriv->force_port_map);
@@ -1194,6 +1199,26 @@
 	return sprintf(buf, "%d\n", emp->blink_policy);
 }
 
+static void ahci_port_clear_pending_irq(struct ata_port *ap)
+{
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u32 tmp;
+
+	/* clear SError */
+	tmp = readl(port_mmio + PORT_SCR_ERR);
+	dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp);
+	writel(tmp, port_mmio + PORT_SCR_ERR);
+
+	/* clear port IRQ */
+	tmp = readl(port_mmio + PORT_IRQ_STAT);
+	dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp);
+	if (tmp)
+		writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+	writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT);
+}
+
 static void ahci_port_init(struct device *dev, struct ata_port *ap,
 			   int port_no, void __iomem *mmio,
 			   void __iomem *port_mmio)
@@ -1208,18 +1233,7 @@
 	if (rc)
 		dev_warn(dev, "%s (%d)\n", emsg, rc);
 
-	/* clear SError */
-	tmp = readl(port_mmio + PORT_SCR_ERR);
-	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
-	writel(tmp, port_mmio + PORT_SCR_ERR);
-
-	/* clear port IRQ */
-	tmp = readl(port_mmio + PORT_IRQ_STAT);
-	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
-	if (tmp)
-		writel(tmp, port_mmio + PORT_IRQ_STAT);
-
-	writel(1 << port_no, mmio + HOST_IRQ_STAT);
+	ahci_port_clear_pending_irq(ap);
 
 	/* mark esata ports */
 	tmp = readl(port_mmio + PORT_CMD);
@@ -1549,6 +1563,8 @@
 	tf.command = ATA_BUSY;
 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
+	ahci_port_clear_pending_irq(ap);
+
 	rc = sata_link_hardreset(link, timing, deadline, online,
 				 ahci_check_ready);
 
@@ -1624,7 +1640,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;
@@ -1660,6 +1676,8 @@
 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
 	ahci_fill_cmd_slot(pp, qc->hw_tag, opts);
+
+	return AC_ERR_OK;
 }
 
 static void ahci_fbs_dec_intr(struct ata_port *ap)
--- linux-ein-5.4.0.orig/drivers/ata/libahci_platform.c
+++ linux-ein-5.4.0/drivers/ata/libahci_platform.c
@@ -43,7 +43,7 @@
  * RETURNS:
  * 0 on success otherwise a negative error code
  */
-static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
+int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
 {
 	int rc, i;
 
@@ -59,7 +59,7 @@
 		}
 
 		rc = phy_power_on(hpriv->phys[i]);
-		if (rc) {
+		if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) {
 			phy_exit(hpriv->phys[i]);
 			goto disable_phys;
 		}
@@ -74,6 +74,7 @@
 	}
 	return rc;
 }
+EXPORT_SYMBOL_GPL(ahci_platform_enable_phys);
 
 /**
  * ahci_platform_disable_phys - Disable PHYs
@@ -81,7 +82,7 @@
  *
  * This function disables all PHYs found in hpriv->phys.
  */
-static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
+void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
 {
 	int i;
 
@@ -90,6 +91,7 @@
 		phy_exit(hpriv->phys[i]);
 	}
 }
+EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
 
 /**
  * ahci_platform_enable_clks - Enable platform clocks
@@ -438,10 +440,7 @@
 	hpriv->phy_regulator = devm_regulator_get(dev, "phy");
 	if (IS_ERR(hpriv->phy_regulator)) {
 		rc = PTR_ERR(hpriv->phy_regulator);
-		if (rc == -EPROBE_DEFER)
-			goto err_out;
-		rc = 0;
-		hpriv->phy_regulator = NULL;
+		goto err_out;
 	}
 
 	if (flags & AHCI_PLATFORM_GET_RESETS) {
@@ -452,14 +451,24 @@
 		}
 	}
 
-	hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
+	/*
+	 * Too many sub-nodes most likely means having something wrong with
+	 * the firmware.
+	 */
+	child_nodes = of_get_child_count(dev->of_node);
+	if (child_nodes > AHCI_MAX_PORTS) {
+		rc = -EINVAL;
+		goto err_out;
+	}
 
 	/*
 	 * If no sub-node was found, we still need to set nports to
 	 * one in order to be able to use the
 	 * ahci_platform_[en|dis]able_[phys|regulators] functions.
 	 */
-	if (!child_nodes)
+	if (child_nodes)
+		hpriv->nports = child_nodes;
+	else
 		hpriv->nports = 1;
 
 	hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
@@ -580,11 +589,13 @@
 	int i, irq, n_ports, rc;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
+	if (irq < 0) {
 		if (irq != -EPROBE_DEFER)
 			dev_err(dev, "no irq\n");
 		return irq;
 	}
+	if (!irq)
+		return -EINVAL;
 
 	hpriv->irq = irq;
 
--- linux-ein-5.4.0.orig/drivers/ata/libata-core.c
+++ linux-ein-5.4.0/drivers/ata/libata-core.c
@@ -41,7 +41,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>
@@ -2058,7 +2057,7 @@
 
 retry:
 	ata_tf_init(dev, &tf);
-	if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
+	if (ata_dma_enabled(dev) && ata_id_has_read_log_dma_ext(dev->id) &&
 	    !(dev->horkage & ATA_HORKAGE_NO_DMA_LOG)) {
 		tf.command = ATA_CMD_READ_LOG_DMA_EXT;
 		tf.protocol = ATA_PROT_DMA;
@@ -2253,6 +2252,25 @@
 
 }
 
+static bool ata_dev_check_adapter(struct ata_device *dev,
+				  unsigned short vendor_id)
+{
+	struct pci_dev *pcidev = NULL;
+	struct device *parent_dev = NULL;
+
+	for (parent_dev = dev->tdev.parent; parent_dev != NULL;
+	     parent_dev = parent_dev->parent) {
+		if (dev_is_pci(parent_dev)) {
+			pcidev = to_pci_dev(parent_dev);
+			if (pcidev->vendor == vendor_id)
+				return true;
+			break;
+		}
+	}
+
+	return false;
+}
+
 static int ata_dev_config_ncq(struct ata_device *dev,
 			       char *desc, size_t desc_sz)
 {
@@ -2269,6 +2287,13 @@
 		snprintf(desc, desc_sz, "NCQ (not used)");
 		return 0;
 	}
+
+	if (dev->horkage & ATA_HORKAGE_NO_NCQ_ON_ATI &&
+	    ata_dev_check_adapter(dev, PCI_VENDOR_ID_ATI)) {
+		snprintf(desc, desc_sz, "NCQ (not used)");
+		return 0;
+	}
+
 	if (ap->flags & ATA_FLAG_NCQ) {
 		hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE);
 		dev->flags |= ATA_DFLAG_NCQ;
@@ -3071,7 +3096,7 @@
 	 */
 	if (spd > 1)
 		mask &= (1 << (spd - 1)) - 1;
-	else
+	else if (link->sata_spd)
 		return -EINVAL;
 
 	/* were we already at the bottom? */
@@ -3956,10 +3981,23 @@
 	case ATA_LPM_MED_POWER_WITH_DIPM:
 	case ATA_LPM_MIN_POWER_WITH_PARTIAL:
 	case ATA_LPM_MIN_POWER:
-		if (ata_link_nr_enabled(link) > 0)
-			/* no restrictions on LPM transitions */
+		if (ata_link_nr_enabled(link) > 0) {
+			/* assume no restrictions on LPM transitions */
 			scontrol &= ~(0x7 << 8);
-		else {
+
+			/*
+			 * If the controller does not support partial, slumber,
+			 * or devsleep, then disallow these transitions.
+			 */
+			if (link->ap->host->flags & ATA_HOST_NO_PART)
+				scontrol |= (0x1 << 8);
+
+			if (link->ap->host->flags & ATA_HOST_NO_SSC)
+				scontrol |= (0x2 << 8);
+
+			if (link->ap->host->flags & ATA_HOST_NO_DEVSLP)
+				scontrol |= (0x4 << 8);
+		} else {
 			/* empty port, power off */
 			scontrol &= ~0xf;
 			scontrol |= (0x1 << 2);
@@ -4412,6 +4450,8 @@
 	{ "VRFDFC22048UCHC-TE*", NULL,		ATA_HORKAGE_NODMA },
 	/* Odd clown on sil3726/4726 PMPs */
 	{ "Config  Disk",	NULL,		ATA_HORKAGE_DISABLE },
+	/* Similar story with ASMedia 1092 */
+	{ "ASMT109x- Config",	NULL,		ATA_HORKAGE_DISABLE },
 
 	/* Weird ATAPI devices */
 	{ "TORiSAN DVD-ROM DRD-N216", NULL,	ATA_HORKAGE_MAX_SEC_128 },
@@ -4475,9 +4515,8 @@
 	/* 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, },
+	/* Sandisk SD7/8/9s lock up hard on large trims */
+	{ "SanDisk SD[789]*",	NULL,		ATA_HORKAGE_MAX_TRIM_128M, },
 
 	/* devices which puke on READ_NATIVE_MAX */
 	{ "HDS724040KLSA80",	"KFAOA20N",	ATA_HORKAGE_BROKEN_HPA, },
@@ -4516,6 +4555,10 @@
 	{ "PIONEER DVD-RW  DVR-212D",	NULL,	ATA_HORKAGE_NOSETXFER },
 	{ "PIONEER DVD-RW  DVR-216D",	NULL,	ATA_HORKAGE_NOSETXFER },
 
+	/* These specific Pioneer models have LPM issues */
+	{ "PIONEER BD-RW   BDR-207M",	NULL,	ATA_HORKAGE_NOLPM },
+	{ "PIONEER BD-RW   BDR-205",	NULL,	ATA_HORKAGE_NOLPM },
+
 	/* Crucial BX100 SSD 500GB has broken LPM support */
 	{ "CT500BX100SSD1",		NULL,	ATA_HORKAGE_NOLPM },
 
@@ -4554,15 +4597,25 @@
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 	{ "Crucial_CT*MX100*",		"MU01",	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
+	{ "Samsung SSD 840 EVO*",	NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_NO_DMA_LOG |
+						ATA_HORKAGE_ZERO_AFTER_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, },
+	{ "Samsung SSD 860*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NO_NCQ_ON_ATI, },
+	{ "Samsung SSD 870*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NO_NCQ_ON_ATI, },
 	{ "FCCT*M500*",			NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
 	/* devices that don't properly handle TRIM commands */
 	{ "SuperSSpeed S238*",		NULL,	ATA_HORKAGE_NOTRIM, },
+	{ "M88V29*",			NULL,	ATA_HORKAGE_NOTRIM, },
 
 	/*
 	 * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4980,7 +5033,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.
@@ -5326,6 +5382,30 @@
 }
 
 /**
+ *	ata_qc_get_active - get bitmask of active qcs
+ *	@ap: port in question
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	Bitmask of active qcs
+ */
+u64 ata_qc_get_active(struct ata_port *ap)
+{
+	u64 qc_active = ap->qc_active;
+
+	/* ATA_TAG_INTERNAL is sent to hw as tag 0 */
+	if (qc_active & (1ULL << ATA_TAG_INTERNAL)) {
+		qc_active |= (1 << 0);
+		qc_active &= ~(1ULL << ATA_TAG_INTERNAL);
+	}
+
+	return qc_active;
+}
+EXPORT_SYMBOL_GPL(ata_qc_get_active);
+
+/**
  *	ata_qc_complete_multiple - Complete multiple qcs successfully
  *	@ap: port in question
  *	@qc_active: new qc_active mask
@@ -5443,7 +5523,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))
@@ -5669,17 +5751,19 @@
 	struct ata_link *link;
 	unsigned long flags;
 
-	/* Previous resume operation might still be in
-	 * progress.  Wait for PM_PENDING to clear.
+	spin_lock_irqsave(ap->lock, flags);
+
+	/*
+	 * A previous PM operation might still be in progress. Wait for
+	 * ATA_PFLAG_PM_PENDING to clear.
 	 */
 	if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+		spin_unlock_irqrestore(ap->lock, flags);
 		ata_port_wait_eh(ap);
-		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+		spin_lock_irqsave(ap->lock, flags);
 	}
 
-	/* request PM ops to EH */
-	spin_lock_irqsave(ap->lock, flags);
-
+	/* Request PM operation to EH */
 	ap->pm_mesg = mesg;
 	ap->pflags |= ATA_PFLAG_PM_PENDING;
 	ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5691,10 +5775,8 @@
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
-	if (!async) {
+	if (!async)
 		ata_port_wait_eh(ap);
-		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
-	}
 }
 
 /*
@@ -5860,7 +5942,7 @@
 #endif
 
 const struct device_type ata_port_type = {
-	.name = "ata_port",
+	.name = ATA_PORT_TYPE_NAME,
 #ifdef CONFIG_PM
 	.pm = &ata_port_pm_ops,
 #endif
@@ -6170,7 +6252,7 @@
 				      const struct ata_port_info * const * ppi,
 				      int n_ports)
 {
-	const struct ata_port_info *pi;
+	const struct ata_port_info *pi = &ata_dummy_port_info;
 	struct ata_host *host;
 	int i, j;
 
@@ -6178,7 +6260,7 @@
 	if (!host)
 		return NULL;
 
-	for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {
+	for (i = 0, j = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
 		if (ppi[j])
@@ -6367,7 +6449,7 @@
 			have_stop = 1;
 	}
 
-	if (host->ops->host_stop)
+	if (host->ops && host->ops->host_stop)
 		have_stop = 1;
 
 	if (have_stop) {
@@ -6568,7 +6650,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;
@@ -6663,11 +6745,30 @@
 	if (!ap->ops->error_handler)
 		goto skip_eh;
 
-	/* tell EH we're leaving & flush EH */
+	/* Wait for any ongoing EH */
+	ata_port_wait_eh(ap);
+
+	mutex_lock(&ap->scsi_scan_mutex);
 	spin_lock_irqsave(ap->lock, flags);
+
+	/* Remove scsi devices */
+	ata_for_each_link(link, ap, HOST_FIRST) {
+		ata_for_each_dev(dev, link, ALL) {
+			if (dev->sdev) {
+				spin_unlock_irqrestore(ap->lock, flags);
+				scsi_remove_device(dev->sdev);
+				spin_lock_irqsave(ap->lock, flags);
+				dev->sdev = NULL;
+			}
+		}
+	}
+
+	/* Tell EH to disable all devices */
 	ap->pflags |= ATA_PFLAG_UNLOADING;
 	ata_port_schedule_eh(ap);
+
 	spin_unlock_irqrestore(ap->lock, flags);
+	mutex_unlock(&ap->scsi_scan_mutex);
 
 	/* wait till EH commits suicide */
 	ata_port_wait_eh(ap);
@@ -6708,8 +6809,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);
@@ -6735,6 +6839,26 @@
 	ata_host_detach(host);
 }
 
+void ata_pci_shutdown_one(struct pci_dev *pdev)
+{
+	struct ata_host *host = pci_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		ap->pflags |= ATA_PFLAG_FROZEN;
+
+		/* Disable port interrupts */
+		if (ap->ops->freeze)
+			ap->ops->freeze(ap);
+
+		/* Stop the port DMA engines */
+		if (ap->ops->port_stop)
+			ap->ops->port_stop(ap);
+	}
+}
+
 /* move to PCI subsystem */
 int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
 {
@@ -6862,6 +6986,8 @@
 		{ "ncq",	.horkage_off	= ATA_HORKAGE_NONCQ },
 		{ "noncqtrim",	.horkage_on	= ATA_HORKAGE_NO_NCQ_TRIM },
 		{ "ncqtrim",	.horkage_off	= ATA_HORKAGE_NO_NCQ_TRIM },
+		{ "noncqati",	.horkage_on	= ATA_HORKAGE_NO_NCQ_ON_ATI },
+		{ "ncqati",	.horkage_off	= ATA_HORKAGE_NO_NCQ_ON_ATI },
 		{ "dump_id",	.horkage_on	= ATA_HORKAGE_DUMP_ID },
 		{ "pio0",	.xfer_mask	= 1 << (ATA_SHIFT_PIO + 0) },
 		{ "pio1",	.xfer_mask	= 1 << (ATA_SHIFT_PIO + 1) },
@@ -7355,6 +7481,7 @@
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_pci_shutdown_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
--- linux-ein-5.4.0.orig/drivers/ata/libata-eh.c
+++ linux-ein-5.4.0/drivers/ata/libata-eh.c
@@ -97,6 +97,12 @@
 	ULONG_MAX,
 };
 
+static const unsigned long ata_eh_revalidate_timeouts[] = {
+	15000,	/* Some drives are slow to read log pages when waking-up */
+	15000,  /* combined time till here is enough even for media access */
+	ULONG_MAX,
+};
+
 static const unsigned long ata_eh_flush_timeouts[] = {
 	15000,	/* be generous with flush */
 	15000,  /* ditto */
@@ -133,6 +139,8 @@
 ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
 	{ .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI),
 	  .timeouts = ata_eh_identify_timeouts, },
+	{ .commands = CMDS(ATA_CMD_READ_LOG_EXT, ATA_CMD_READ_LOG_DMA_EXT),
+	  .timeouts = ata_eh_revalidate_timeouts, },
 	{ .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT),
 	  .timeouts = ata_eh_other_timeouts, },
 	{ .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT),
@@ -2321,6 +2329,7 @@
 		{ ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
 		{ ATA_CMD_FPDMA_READ,		"READ FPDMA QUEUED" },
 		{ ATA_CMD_FPDMA_WRITE,		"WRITE FPDMA QUEUED" },
+		{ ATA_CMD_NCQ_NON_DATA,		"NCQ NON-DATA" },
 		{ ATA_CMD_FPDMA_SEND,		"SEND FPDMA QUEUED" },
 		{ ATA_CMD_FPDMA_RECV,		"RECEIVE FPDMA QUEUED" },
 		{ ATA_CMD_PIO_READ,		"READ SECTOR(S)" },
@@ -2413,7 +2422,7 @@
 	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_queued_cmd *qc;
 	const char *frozen, *desc;
-	char tries_buf[6] = "";
+	char tries_buf[16] = "";
 	int tag, nr_failed = 0;
 
 	if (ehc->i.flags & ATA_EHI_QUIET)
@@ -2892,18 +2901,11 @@
 			postreset(slave, classes);
 	}
 
-	/*
-	 * Some controllers can't be frozen very well and may set spurious
-	 * error conditions during reset.  Clear accumulated error
-	 * information and re-thaw the port if frozen.  As reset is the
-	 * final recovery action and we cross check link onlineness against
-	 * device classification later, no hotplug event is lost by this.
-	 */
+	/* clear cached SError */
 	spin_lock_irqsave(link->ap->lock, flags);
-	memset(&link->eh_info, 0, sizeof(link->eh_info));
+	link->eh_info.serror = 0;
 	if (slave)
-		memset(&slave->eh_info, 0, sizeof(link->eh_info));
-	ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+		slave->eh_info.serror = 0;
 	spin_unlock_irqrestore(link->ap->lock, flags);
 
 	if (ap->pflags & ATA_PFLAG_FROZEN)
--- linux-ein-5.4.0.orig/drivers/ata/libata-pmp.c
+++ linux-ein-5.4.0/drivers/ata/libata-pmp.c
@@ -763,6 +763,7 @@
 
 	if (dev->flags & ATA_DFLAG_DETACH) {
 		detach = 1;
+		rc = -ENODEV;
 		goto fail;
 	}
 
--- linux-ein-5.4.0.orig/drivers/ata/libata-scsi.c
+++ linux-ein-5.4.0/drivers/ata/libata-scsi.c
@@ -162,7 +162,7 @@
 	struct ata_link *link;
 	struct ata_device *dev;
 	unsigned long now;
-	unsigned int uninitialized_var(msecs);
+	unsigned int msecs;
 	int rc = 0;
 
 	ap = ata_shost_to_port(sdev->host);
@@ -2374,6 +2374,7 @@
 
 static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
 {
+	struct ata_device *dev = args->dev;
 	u16 min_io_sectors;
 
 	rbuf[1] = 0xb0;
@@ -2399,7 +2400,12 @@
 	 * with the unmap bit set.
 	 */
 	if (ata_id_has_trim(args->id)) {
-		put_unaligned_be64(65535 * ATA_MAX_TRIM_RNUM, &rbuf[36]);
+		u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM;
+
+		if (dev->horkage & ATA_HORKAGE_MAX_TRIM_128M)
+			max_blocks = 128 << (20 - SECTOR_SHIFT);
+
+		put_unaligned_be64(max_blocks, &rbuf[36]);
 		put_unaligned_be32(1, &rbuf[28]);
 	}
 
@@ -3030,18 +3036,36 @@
 	return 0;
 }
 
-static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
+static struct ata_device *ata_find_dev(struct ata_port *ap, unsigned int devno)
 {
-	if (!sata_pmp_attached(ap)) {
-		if (likely(devno >= 0 &&
-			   devno < ata_link_max_devices(&ap->link)))
+	/*
+	 * For the non-PMP case, ata_link_max_devices() returns 1 (SATA case),
+	 * or 2 (IDE master + slave case). However, the former case includes
+	 * libsas hosted devices which are numbered per scsi host, leading
+	 * to devno potentially being larger than 0 but with each struct
+	 * ata_device having its own struct ata_port and struct ata_link.
+	 * To accommodate these, ignore devno and always use device number 0.
+	 */
+	if (likely(!sata_pmp_attached(ap))) {
+		int link_max_devices = ata_link_max_devices(&ap->link);
+
+		if (link_max_devices == 1)
+			return &ap->link.device[0];
+
+		if (devno < link_max_devices)
 			return &ap->link.device[devno];
-	} else {
-		if (likely(devno >= 0 &&
-			   devno < ap->nr_pmp_links))
-			return &ap->pmp_link[devno].device[0];
+
+		return NULL;
 	}
 
+	/*
+	 * For PMP-attached devices, the device number corresponds to C
+	 * (channel) of SCSI [H:C:I:L], indicating the port pmp link
+	 * for the device.
+	 */
+	if (devno < ap->nr_pmp_links)
+		return &ap->pmp_link[devno].device[0];
+
 	return NULL;
 }
 
@@ -3158,8 +3182,19 @@
 		goto invalid_fld;
 	}
 
-	if (ata_is_ncq(tf->protocol) && (cdb[2 + cdb_offset] & 0x3) == 0)
-		tf->protocol = ATA_PROT_NCQ_NODATA;
+	if ((cdb[2 + cdb_offset] & 0x3) == 0) {
+		/*
+		 * When T_LENGTH is zero (No data is transferred), dir should
+		 * be DMA_NONE.
+		 */
+		if (scmd->sc_data_direction != DMA_NONE) {
+			fp = 2 + cdb_offset;
+			goto invalid_fld;
+		}
+
+		if (ata_is_ncq(tf->protocol))
+			tf->protocol = ATA_PROT_NCQ_NODATA;
+	}
 
 	/* enable LBA */
 	tf->flags |= ATA_TFLAG_LBA;
@@ -3978,12 +4013,13 @@
 {
 	struct scsi_cmnd *scmd = qc->scsicmd;
 	const u8 *cdb = scmd->cmnd;
-	const u8 *p;
 	u8 pg, spg;
 	unsigned six_byte, pg_len, hdr_len, bd_len;
 	int len;
 	u16 fp = (u16)-1;
 	u8 bp = 0xff;
+	u8 buffer[64];
+	const u8 *p = buffer;
 
 	VPRINTK("ENTER\n");
 
@@ -4017,12 +4053,14 @@
 	if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len)
 		goto invalid_param_len;
 
-	p = page_address(sg_page(scsi_sglist(scmd)));
-
 	/* Move past header and block descriptors.  */
 	if (len < hdr_len)
 		goto invalid_param_len;
 
+	if (!sg_copy_to_buffer(scsi_sglist(scmd), scsi_sg_count(scmd),
+			       buffer, sizeof(buffer)))
+		goto invalid_param_len;
+
 	if (six_byte)
 		bd_len = p[3];
 	else
@@ -4506,7 +4544,7 @@
 		break;
 
 	case MAINTENANCE_IN:
-		if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES)
+		if ((scsicmd[1] & 0x1f) == MI_REPORT_SUPPORTED_OPERATION_CODES)
 			ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in);
 		else
 			ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
@@ -4553,22 +4591,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-ein-5.4.0.orig/drivers/ata/libata-sff.c
+++ linux-ein-5.4.0/drivers/ata/libata-sff.c
@@ -641,6 +641,20 @@
 }
 EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
 
+static void ata_pio_xfer(struct ata_queued_cmd *qc, struct page *page,
+		unsigned int offset, size_t xfer_size)
+{
+	bool do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+	unsigned char *buf;
+
+	buf = kmap_atomic(page);
+	qc->ap->ops->sff_data_xfer(qc, buf + offset, xfer_size, do_write);
+	kunmap_atomic(buf);
+
+	if (!do_write && !PageSlab(page))
+		flush_dcache_page(page);
+}
+
 /**
  *	ata_pio_sector - Transfer a sector of data.
  *	@qc: Command on going
@@ -652,11 +666,9 @@
  */
 static void ata_pio_sector(struct ata_queued_cmd *qc)
 {
-	int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
 	struct ata_port *ap = qc->ap;
 	struct page *page;
 	unsigned int offset;
-	unsigned char *buf;
 
 	if (!qc->cursg) {
 		qc->curbytes = qc->nbytes;
@@ -674,13 +686,20 @@
 
 	DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
 
-	/* do the actual data transfer */
-	buf = kmap_atomic(page);
-	ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write);
-	kunmap_atomic(buf);
-
-	if (!do_write && !PageSlab(page))
-		flush_dcache_page(page);
+	/*
+	 * Split the transfer when it splits a page boundary.  Note that the
+	 * split still has to be dword aligned like all ATA data transfers.
+	 */
+	WARN_ON_ONCE(offset % 4);
+	if (offset + qc->sect_size > PAGE_SIZE) {
+		unsigned int split_len = PAGE_SIZE - offset;
+
+		ata_pio_xfer(qc, page, offset, split_len);
+		ata_pio_xfer(qc, nth_page(page, 1), 0,
+			     qc->sect_size - split_len);
+	} else {
+		ata_pio_xfer(qc, page, offset, qc->sect_size);
+	}
 
 	qc->curbytes += qc->sect_size;
 	qc->cursg_ofs += qc->sect_size;
@@ -2679,12 +2698,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);
 
@@ -2697,12 +2718,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-ein-5.4.0.orig/drivers/ata/libata-transport.c
+++ linux-ein-5.4.0/drivers/ata/libata-transport.c
@@ -196,7 +196,7 @@
 	{ XFER_PIO_0,			"XFER_PIO_0" },
 	{ XFER_PIO_SLOW,		"XFER_PIO_SLOW" }
 };
-ata_bitfield_name_match(xfer,ata_xfer_names)
+ata_bitfield_name_search(xfer, ata_xfer_names)
 
 /*
  * ATA Port attributes
@@ -266,6 +266,10 @@
 	put_device(dev);
 }
 
+static const struct device_type ata_port_sas_type = {
+	.name = ATA_PORT_TYPE_NAME,
+};
+
 /** ata_tport_add - initialize a transport ATA port structure
  *
  * @parent:	parent device
@@ -283,7 +287,10 @@
 	struct device *dev = &ap->tdev;
 
 	device_initialize(dev);
-	dev->type = &ata_port_type;
+	if (ap->flags & ATA_FLAG_SAS_HOST)
+		dev->type = &ata_port_sas_type;
+	else
+		dev->type = &ata_port_type;
 
 	dev->parent = parent;
 	ata_host_get(ap->host);
@@ -317,7 +324,6 @@
  tport_err:
 	transport_destroy_device(dev);
 	put_device(dev);
-	ata_host_put(ap->host);
 	return error;
 }
 
--- linux-ein-5.4.0.orig/drivers/ata/libata.h
+++ linux-ein-5.4.0/drivers/ata/libata.h
@@ -30,6 +30,8 @@
 	ATA_DNXFER_QUIET	= (1 << 31),
 };
 
+#define ATA_PORT_TYPE_NAME	"ata_port"
+
 extern atomic_t ata_print_id;
 extern int atapi_passthru16;
 extern int libata_fua;
--- linux-ein-5.4.0.orig/drivers/ata/pata_arasan_cf.c
+++ linux-ein-5.4.0/drivers/ata/pata_arasan_cf.c
@@ -817,12 +817,19 @@
 	else
 		quirk = CF_BROKEN_UDMA; /* as it is on spear1340 */
 
-	/* if irq is 0, support only PIO */
-	acdev->irq = platform_get_irq(pdev, 0);
-	if (acdev->irq)
+	/*
+	 * If there's an error getting IRQ (or we do get IRQ0),
+	 * support only PIO
+	 */
+	ret = platform_get_irq(pdev, 0);
+	if (ret > 0) {
+		acdev->irq = ret;
 		irq_handler = arasan_cf_interrupt;
-	else
+	} else	if (ret == -EPROBE_DEFER) {
+		return ret;
+	} else	{
 		quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA;
+	}
 
 	acdev->pbase = res->start;
 	acdev->vbase = devm_ioremap_nocache(&pdev->dev, res->start,
--- linux-ein-5.4.0.orig/drivers/ata/pata_ep93xx.c
+++ linux-ein-5.4.0/drivers/ata/pata_ep93xx.c
@@ -928,7 +928,7 @@
 	/* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		err = -ENXIO;
+		err = irq;
 		goto err_rel_gpio;
 	}
 
--- linux-ein-5.4.0.orig/drivers/ata/pata_ftide010.c
+++ linux-ein-5.4.0/drivers/ata/pata_ftide010.c
@@ -570,6 +570,7 @@
 };
 module_platform_driver(pata_ftide010_driver);
 
+MODULE_DESCRIPTION("low level driver for Faraday Technology FTIDE010");
 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
--- linux-ein-5.4.0.orig/drivers/ata/pata_hpt37x.c
+++ linux-ein-5.4.0/drivers/ata/pata_hpt37x.c
@@ -918,6 +918,20 @@
 	pci_write_config_byte(dev, 0x5a, irqmask);
 
 	/*
+	 * HPT371 chips physically have only one channel, the secondary one,
+	 * but the primary channel registers do exist!  Go figure...
+	 * So,  we manually disable the non-existing channel here
+	 * (if the BIOS hasn't done this already).
+	 */
+	if (dev->device == PCI_DEVICE_ID_TTI_HPT371) {
+		u8 mcr1;
+
+		pci_read_config_byte(dev, 0x50, &mcr1);
+		mcr1 &= ~0x04;
+		pci_write_config_byte(dev, 0x50, mcr1);
+	}
+
+	/*
 	 * default to pci clock. make sure MA15/16 are set to output
 	 * to prevent drives having problems with 40-pin cables. Needed
 	 * for some drives such as IBM-DTLA which will not enter ready
@@ -948,14 +962,14 @@
 
 	if ((freq >> 12) != 0xABCDE) {
 		int i;
-		u8 sr;
+		u16 sr;
 		u32 total = 0;
 
 		pr_warn("BIOS has not set timing clocks\n");
 
 		/* This is the process the HPT371 BIOS is reported to use */
 		for (i = 0; i < 128; i++) {
-			pci_read_config_byte(dev, 0x78, &sr);
+			pci_read_config_word(dev, 0x78, &sr);
 			total += sr & 0x1FF;
 			udelay(15);
 		}
--- linux-ein-5.4.0.orig/drivers/ata/pata_isapnp.c
+++ linux-ein-5.4.0/drivers/ata/pata_isapnp.c
@@ -82,6 +82,9 @@
 	if (pnp_port_valid(idev, 1)) {
 		ctl_addr = devm_ioport_map(&idev->dev,
 					   pnp_port_start(idev, 1), 1);
+		if (!ctl_addr)
+			return -ENOMEM;
+
 		ap->ioaddr.altstatus_addr = ctl_addr;
 		ap->ioaddr.ctl_addr = ctl_addr;
 		ap->ops = &isapnp_port_ops;
--- linux-ein-5.4.0.orig/drivers/ata/pata_ixp4xx_cf.c
+++ linux-ein-5.4.0/drivers/ata/pata_ixp4xx_cf.c
@@ -135,12 +135,12 @@
 
 static int ixp4xx_pata_probe(struct platform_device *pdev)
 {
-	unsigned int irq;
 	struct resource *cs0, *cs1;
 	struct ata_host *host;
 	struct ata_port *ap;
 	struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev);
 	int ret;
+	int irq;
 
 	cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -165,8 +165,12 @@
 		return -ENOMEM;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq)
+	if (irq > 0)
 		irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+	else if (irq < 0)
+		return irq;
+	else
+		return -EINVAL;
 
 	/* Setup expansion bus chip selects */
 	*data->cs0_cfg = data->cs0_bits;
--- linux-ein-5.4.0.orig/drivers/ata/pata_legacy.c
+++ linux-ein-5.4.0/drivers/ata/pata_legacy.c
@@ -278,9 +278,10 @@
 	outb(inb(0x1F4) & 0x07, 0x1F4);
 
 	rt = inb(0x1F3);
-	rt &= 0x07 << (3 * adev->devno);
+	rt &= ~(0x07 << (3 * !adev->devno));
 	if (pio)
-		rt |= (1 + 3 * pio) << (3 * adev->devno);
+		rt |= (1 + 3 * pio) << (3 * !adev->devno);
+	outb(rt, 0x1F3);
 
 	udelay(100);
 	outb(inb(0x1F2) | 0x01, 0x1F2);
@@ -315,7 +316,8 @@
 			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
 		if (unlikely(slop)) {
-			__le32 pad;
+			__le32 pad = 0;
+
 			if (rw == READ) {
 				pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
 				memcpy(buf + buflen - slop, &pad, slop);
@@ -705,7 +707,8 @@
 			ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
 		if (unlikely(slop)) {
-			__le32 pad;
+			__le32 pad = 0;
+
 			if (rw == WRITE) {
 				memcpy(&pad, buf + buflen - slop, slop);
 				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
--- linux-ein-5.4.0.orig/drivers/ata/pata_macio.c
+++ linux-ein-5.4.0/drivers/ata/pata_macio.c
@@ -510,7 +510,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;
@@ -523,7 +523,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;
 
@@ -568,6 +568,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-ein-5.4.0.orig/drivers/ata/pata_marvell.c
+++ linux-ein-5.4.0/drivers/ata/pata_marvell.c
@@ -83,6 +83,8 @@
 	switch(ap->port_no)
 	{
 	case 0:
+		if (!ap->ioaddr.bmdma_addr)
+			return ATA_CBL_PATA_UNK;
 		if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
 			return ATA_CBL_PATA40;
 		return ATA_CBL_PATA80;
--- linux-ein-5.4.0.orig/drivers/ata/pata_ns87415.c
+++ linux-ein-5.4.0/drivers/ata/pata_ns87415.c
@@ -261,7 +261,7 @@
  *	LOCKING:
  *	Inherited from caller.
  */
-void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+static void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
--- linux-ein-5.4.0.orig/drivers/ata/pata_octeon_cf.c
+++ linux-ein-5.4.0/drivers/ata/pata_octeon_cf.c
@@ -888,20 +888,24 @@
 				int i;
 				res_dma = platform_get_resource(dma_dev, IORESOURCE_MEM, 0);
 				if (!res_dma) {
+					put_device(&dma_dev->dev);
 					of_node_put(dma_node);
 					return -EINVAL;
 				}
 				cf_port->dma_base = (u64)devm_ioremap_nocache(&pdev->dev, res_dma->start,
 									 resource_size(res_dma));
 				if (!cf_port->dma_base) {
+					put_device(&dma_dev->dev);
 					of_node_put(dma_node);
 					return -EINVAL;
 				}
 
-				irq_handler = octeon_cf_interrupt;
 				i = platform_get_irq(dma_dev, 0);
-				if (i > 0)
+				if (i > 0) {
 					irq = i;
+					irq_handler = octeon_cf_interrupt;
+				}
+				put_device(&dma_dev->dev);
 			}
 			of_node_put(dma_node);
 		}
--- linux-ein-5.4.0.orig/drivers/ata/pata_pxa.c
+++ linux-ein-5.4.0/drivers/ata/pata_pxa.c
@@ -44,25 +44,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-ein-5.4.0.orig/drivers/ata/pata_rb532_cf.c
+++ linux-ein-5.4.0/drivers/ata/pata_rb532_cf.c
@@ -115,10 +115,12 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
+	if (irq < 0) {
 		dev_err(&pdev->dev, "no IRQ resource found\n");
-		return -ENOENT;
+		return irq;
 	}
+	if (!irq)
+		return -EINVAL;
 
 	gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
 	if (IS_ERR(gpiod)) {
--- linux-ein-5.4.0.orig/drivers/ata/pdc_adma.c
+++ linux-ein-5.4.0/drivers/ata/pdc_adma.c
@@ -116,7 +116,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);
@@ -295,7 +295,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;
@@ -306,7 +306,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 */
@@ -371,6 +371,7 @@
 			printk("%s\n", obuf);
 	}
 #endif
+	return AC_ERR_OK;
 }
 
 static inline void adma_packet_start(struct ata_queued_cmd *qc)
--- linux-ein-5.4.0.orig/drivers/ata/sata_dwc_460ex.c
+++ linux-ein-5.4.0/drivers/ata/sata_dwc_460ex.c
@@ -145,7 +145,11 @@
 #endif
 };
 
-#define SATA_DWC_QCMD_MAX	32
+/*
+ * Allow one extra special slot for commands and DMA management
+ * to account for libata internal commands.
+ */
+#define SATA_DWC_QCMD_MAX	(ATA_MAX_QUEUE + 1)
 
 struct sata_dwc_device_port {
 	struct sata_dwc_device	*hsdev;
@@ -1249,24 +1253,20 @@
 	irq = irq_of_parse_and_map(np, 0);
 	if (irq == NO_IRQ) {
 		dev_err(&ofdev->dev, "no SATA DMA irq\n");
-		err = -ENODEV;
-		goto error_out;
+		return -ENODEV;
 	}
 
 #ifdef CONFIG_SATA_DWC_OLD_DMA
 	if (!of_find_property(np, "dmas", NULL)) {
 		err = sata_dwc_dma_init_old(ofdev, hsdev);
 		if (err)
-			goto error_out;
+			return err;
 	}
 #endif
 
 	hsdev->phy = devm_phy_optional_get(hsdev->dev, "sata-phy");
-	if (IS_ERR(hsdev->phy)) {
-		err = PTR_ERR(hsdev->phy);
-		hsdev->phy = NULL;
-		goto error_out;
-	}
+	if (IS_ERR(hsdev->phy))
+		return PTR_ERR(hsdev->phy);
 
 	err = phy_init(hsdev->phy);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/ata/sata_fsl.c
+++ linux-ein-5.4.0/drivers/ata/sata_fsl.c
@@ -502,7 +502,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;
@@ -548,6 +548,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)
@@ -1278,7 +1280,7 @@
 				     i, ioread32(hcr_base + CC),
 				     ioread32(hcr_base + CA));
 		}
-		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+		ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
 		return;
 
 	} else if ((ap->qc_active & (1ULL << ATA_TAG_INTERNAL))) {
@@ -1392,6 +1394,14 @@
 	return 0;
 }
 
+static void sata_fsl_host_stop(struct ata_host *host)
+{
+        struct sata_fsl_host_priv *host_priv = host->private_data;
+
+        iounmap(host_priv->hcr_base);
+        kfree(host_priv);
+}
+
 /*
  * scsi mid-layer and libata interface structures
  */
@@ -1424,6 +1434,8 @@
 	.port_start = sata_fsl_port_start,
 	.port_stop = sata_fsl_port_stop,
 
+	.host_stop      = sata_fsl_host_stop,
+
 	.pmp_attach = sata_fsl_pmp_attach,
 	.pmp_detach = sata_fsl_pmp_detach,
 };
@@ -1478,9 +1490,9 @@
 	host_priv->ssr_base = ssr_base;
 	host_priv->csr_base = csr_base;
 
-	irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
-	if (!irq) {
-		dev_err(&ofdev->dev, "invalid irq from platform\n");
+	irq = platform_get_irq(ofdev, 0);
+	if (irq < 0) {
+		retval = irq;
 		goto error_exit_with_cleanup;
 	}
 	host_priv->irq = irq;
@@ -1555,10 +1567,6 @@
 
 	ata_host_detach(host);
 
-	irq_dispose_mapping(host_priv->irq);
-	iounmap(host_priv->hcr_base);
-	kfree(host_priv);
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/ata/sata_gemini.c
+++ linux-ein-5.4.0/drivers/ata/sata_gemini.c
@@ -435,6 +435,7 @@
 };
 module_platform_driver(gemini_sata_driver);
 
+MODULE_DESCRIPTION("low level driver for Cortina Systems Gemini SATA bridge");
 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
--- linux-ein-5.4.0.orig/drivers/ata/sata_highbank.c
+++ linux-ein-5.4.0/drivers/ata/sata_highbank.c
@@ -469,10 +469,12 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
+	if (irq < 0) {
 		dev_err(dev, "no irq\n");
-		return -EINVAL;
+		return irq;
 	}
+	if (!irq)
+		return -EINVAL;
 
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv) {
--- linux-ein-5.4.0.orig/drivers/ata/sata_inic162x.c
+++ linux-ein-5.4.0/drivers/ata/sata_inic162x.c
@@ -478,7 +478,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;
@@ -538,6 +538,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-ein-5.4.0.orig/drivers/ata/sata_mv.c
+++ linux-ein-5.4.0/drivers/ata/sata_mv.c
@@ -592,8 +592,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);
@@ -2031,7 +2031,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;
@@ -2043,15 +2043,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
@@ -2098,12 +2098,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);
@@ -2116,8 +2114,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;
 }
 
 /**
@@ -2132,7 +2132,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;
@@ -2143,9 +2143,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))
@@ -2186,8 +2186,10 @@
 		);
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+		return AC_ERR_OK;
 	mv_fill_sg(qc);
+
+	return AC_ERR_OK;
 }
 
 /**
@@ -2827,7 +2829,7 @@
 	}
 
 	if (work_done) {
-		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+		ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
 
 		/* Update the software queue position index in hardware */
 		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
@@ -3890,8 +3892,8 @@
 		break;
 
 	default:
-		dev_err(host->dev, "BUG: invalid board index %u\n", board_idx);
-		return 1;
+		dev_alert(host->dev, "BUG: invalid board index %u\n", board_idx);
+		return -EINVAL;
 	}
 
 	hpriv->hp_flags = hp_flags;
@@ -4095,6 +4097,10 @@
 		n_ports = mv_platform_data->n_ports;
 		irq = platform_get_irq(pdev, 0);
 	}
+	if (irq < 0)
+		return irq;
+	if (!irq)
+		return -EINVAL;
 
 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
--- linux-ein-5.4.0.orig/drivers/ata/sata_nv.c
+++ linux-ein-5.4.0/drivers/ata/sata_nv.c
@@ -297,7 +297,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);
@@ -319,7 +319,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);
@@ -984,7 +984,7 @@
 					check_commands = 0;
 				check_commands &= ~(1 << pos);
 			}
-			ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+			ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
 		}
 	}
 
@@ -1344,7 +1344,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->hw_tag];
@@ -1356,7 +1356,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;
@@ -1388,6 +1388,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)
@@ -1950,17 +1952,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)
@@ -2096,7 +2100,7 @@
 	pp->dhfis_bits &= ~done_mask;
 	pp->dmafis_bits &= ~done_mask;
 	pp->sdbfis_bits |= done_mask;
-	ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+	ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
 
 	if (!ap->qc_active) {
 		DPRINTK("over\n");
--- linux-ein-5.4.0.orig/drivers/ata/sata_promise.c
+++ linux-ein-5.4.0/drivers/ata/sata_promise.c
@@ -139,7 +139,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);
@@ -633,7 +633,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;
@@ -665,6 +665,8 @@
 	default:
 		break;
 	}
+
+	return AC_ERR_OK;
 }
 
 static int pdc_is_sataii_tx4(unsigned long flags)
--- linux-ein-5.4.0.orig/drivers/ata/sata_qstor.c
+++ linux-ein-5.4.0/drivers/ata/sata_qstor.c
@@ -100,7 +100,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);
@@ -260,7 +260,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;
@@ -272,7 +272,7 @@
 
 	qs_enter_reg_mode(qc->ap);
 	if (qc->tf.protocol != ATA_PROT_DMA)
-		return;
+		return AC_ERR_OK;
 
 	nelem = qs_fill_sg(qc);
 
@@ -295,6 +295,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-ein-5.4.0.orig/drivers/ata/sata_rcar.c
+++ linux-ein-5.4.0/drivers/ata/sata_rcar.c
@@ -120,7 +120,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
@@ -550,12 +550,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)
@@ -905,7 +907,7 @@
 	pm_runtime_enable(dev);
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0)
-		goto err_pm_disable;
+		goto err_pm_put;
 
 	host = ata_host_alloc(dev, 1);
 	if (!host) {
@@ -935,7 +937,6 @@
 
 err_pm_put:
 	pm_runtime_put(dev);
-err_pm_disable:
 	pm_runtime_disable(dev);
 	return ret;
 }
@@ -989,8 +990,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put(dev);
 		return ret;
+	}
 
 	if (priv->type == RCAR_GEN3_SATA) {
 		sata_rcar_init_module(priv);
@@ -1015,8 +1018,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put(dev);
 		return ret;
+	}
 
 	sata_rcar_setup_port(host);
 
--- linux-ein-5.4.0.orig/drivers/ata/sata_sil.c
+++ linux-ein-5.4.0/drivers/ata/sata_sil.c
@@ -103,7 +103,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);
@@ -317,12 +317,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-ein-5.4.0.orig/drivers/ata/sata_sil24.c
+++ linux-ein-5.4.0/drivers/ata/sata_sil24.c
@@ -326,7 +326,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);
@@ -830,7 +830,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;
@@ -874,6 +874,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-ein-5.4.0.orig/drivers/ata/sata_sx4.c
+++ linux-ein-5.4.0/drivers/ata/sata_sx4.c
@@ -202,7 +202,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);
@@ -530,7 +530,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:
@@ -542,6 +542,8 @@
 	default:
 		break;
 	}
+
+	return AC_ERR_OK;
 }
 
 static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
--- linux-ein-5.4.0.orig/drivers/atm/atmtcp.c
+++ linux-ein-5.4.0/drivers/atm/atmtcp.c
@@ -433,9 +433,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-ein-5.4.0.orig/drivers/atm/eni.c
+++ linux-ein-5.4.0/drivers/atm/eni.c
@@ -374,7 +374,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;
@@ -447,7 +447,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");
@@ -1116,6 +1116,8 @@
 	}
 	paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len,
 			       DMA_TO_DEVICE);
+	if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr))
+		return enq_next;
 	ENI_PRV_PADDR(skb) = paddr;
 	/* prepare DMA queue entries */
 	j = 0;
@@ -2245,7 +2247,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);
@@ -2281,7 +2283,8 @@
 	return rc;
 
 err_eni_release:
-	eni_do_release(dev);
+	dev->phy = NULL;
+	iounmap(ENI_DEV(dev)->ioaddr);
 err_unregister:
 	atm_dev_deregister(dev);
 err_free_consistent:
--- linux-ein-5.4.0.orig/drivers/atm/firestream.c
+++ linux-ein-5.4.0/drivers/atm/firestream.c
@@ -912,6 +912,7 @@
 			}
 			if (!to) {
 				printk ("No more free channels for FS50..\n");
+				kfree(vcc);
 				return -EBUSY;
 			}
 			vcc->channo = dev->channo;
@@ -922,6 +923,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;
 			}
 		}
@@ -935,6 +937,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;
 		}
 
@@ -995,6 +998,7 @@
 				error = make_rate (pcr, r, &tmc0, NULL);
 				if (error) {
 					kfree(tc);
+					kfree(vcc);
 					return error;
 				}
 			}
@@ -1673,6 +1677,8 @@
 	dev->hw_base = pci_resource_start(pci_dev, 0);
 
 	dev->base = ioremap(dev->hw_base, 0x1000);
+	if (!dev->base)
+		return 1;
 
 	reset_chip (dev);
   
--- linux-ein-5.4.0.orig/drivers/atm/fore200e.c
+++ linux-ein-5.4.0/drivers/atm/fore200e.c
@@ -1414,12 +1414,14 @@
 static void
 fore200e_close(struct atm_vcc* vcc)
 {
-    struct fore200e*        fore200e = FORE200E_DEV(vcc->dev);
     struct fore200e_vcc*    fore200e_vcc;
+    struct fore200e*        fore200e;
     struct fore200e_vc_map* vc_map;
     unsigned long           flags;
 
     ASSERT(vcc);
+    fore200e = FORE200E_DEV(vcc->dev);
+
     ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<<FORE200E_VPI_BITS));
     ASSERT((vcc->vci >= 0) && (vcc->vci < 1<<FORE200E_VCI_BITS));
 
@@ -1464,10 +1466,10 @@
 static int
 fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
-    struct fore200e*        fore200e     = FORE200E_DEV(vcc->dev);
-    struct fore200e_vcc*    fore200e_vcc = FORE200E_VCC(vcc);
+    struct fore200e*        fore200e;
+    struct fore200e_vcc*    fore200e_vcc;
     struct fore200e_vc_map* vc_map;
-    struct host_txq*        txq          = &fore200e->host_txq;
+    struct host_txq*        txq;
     struct host_txq_entry*  entry;
     struct tpd*             tpd;
     struct tpd_haddr        tpd_haddr;
@@ -1480,9 +1482,18 @@
     unsigned char*          data;
     unsigned long           flags;
 
-    ASSERT(vcc);
-    ASSERT(fore200e);
-    ASSERT(fore200e_vcc);
+    if (!vcc)
+        return -EINVAL;
+
+    fore200e = FORE200E_DEV(vcc->dev);
+    fore200e_vcc = FORE200E_VCC(vcc);
+
+    if (!fore200e)
+        return -EINVAL;
+
+    txq = &fore200e->host_txq;
+    if (!fore200e_vcc)
+        return -EINVAL;
 
     if (!test_bit(ATM_VF_READY, &vcc->flags)) {
 	DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi);
--- linux-ein-5.4.0.orig/drivers/atm/idt77105.c
+++ linux-ein-5.4.0/drivers/atm/idt77105.c
@@ -262,7 +262,7 @@
 {
 	unsigned long flags;
 
-	if (!(dev->dev_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	PRIV(dev)->dev = dev;
 	spin_lock_irqsave(&idt77105_priv_lock, flags);
@@ -337,7 +337,7 @@
                 else
                     idt77105_all = walk->next;
 	        dev->phy = NULL;
-                dev->dev_data = NULL;
+                dev->phy_data = NULL;
                 kfree(walk);
                 break;
             }
--- linux-ein-5.4.0.orig/drivers/atm/idt77252.c
+++ linux-ein-5.4.0/drivers/atm/idt77252.c
@@ -2914,6 +2914,7 @@
 
 				recycle_rx_pool_skb(card, &vc->rcv.rx_pool);
 			}
+			kfree(vc);
 		}
 	}
 }
@@ -2934,6 +2935,8 @@
 	vc->scq = alloc_scq(card, vc->class);
 	if (!vc->scq) {
 		printk("%s: can't get SCQ.\n", card->name);
+		kfree(card->vcs[0]);
+		card->vcs[0] = NULL;
 		return -ENOMEM;
 	}
 
@@ -2957,6 +2960,15 @@
 	return 0;
 }
 
+static void
+close_card_ubr0(struct idt77252_dev *card)
+{
+	struct vc_map *vc = card->vcs[0];
+
+	free_scq(card, vc->scq);
+	kfree(vc);
+}
+
 static int
 idt77252_dev_open(struct idt77252_dev *card)
 {
@@ -3006,6 +3018,7 @@
 	struct idt77252_dev *card = dev->dev_data;
 	u32 conf;
 
+	close_card_ubr0(card);
 	close_card_oam(card);
 
 	conf = SAR_CFG_RXPTH |	/* enable receive path           */
@@ -3606,7 +3619,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);
@@ -3766,6 +3779,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-ein-5.4.0.orig/drivers/atm/iphase.c
+++ linux-ein-5.4.0/drivers/atm/iphase.c
@@ -2290,19 +2290,21 @@
 static int reset_sar(struct atm_dev *dev)  
 {  
 	IADEV *iadev;  
-	int i, error = 1;  
+	int i, error;
 	unsigned int pci[64];  
 	  
 	iadev = INPH_IA_DEV(dev);  
-	for(i=0; i<64; i++)  
-	  if ((error = pci_read_config_dword(iadev->pci,  
-				i*4, &pci[i])) != PCIBIOS_SUCCESSFUL)  
-  	      return error;  
+	for (i = 0; i < 64; i++) {
+		error = pci_read_config_dword(iadev->pci, i * 4, &pci[i]);
+		if (error != PCIBIOS_SUCCESSFUL)
+			return error;
+	}
 	writel(0, iadev->reg+IPHASE5575_EXT_RESET);  
-	for(i=0; i<64; i++)  
-	  if ((error = pci_write_config_dword(iadev->pci,  
-					i*4, pci[i])) != PCIBIOS_SUCCESSFUL)  
-	    return error;  
+	for (i = 0; i < 64; i++) {
+		error = pci_write_config_dword(iadev->pci, i * 4, pci[i]);
+		if (error != PCIBIOS_SUCCESSFUL)
+			return error;
+	}
 	udelay(5);  
 	return 0;  
 }  
@@ -3295,7 +3297,7 @@
 {
 	pci_unregister_driver(&ia_driver);
 
-        del_timer(&ia_timer);
+	del_timer_sync(&ia_timer);
 }
 
 module_init(ia_module_init);
--- linux-ein-5.4.0.orig/drivers/atm/lanai.c
+++ linux-ein-5.4.0/drivers/atm/lanai.c
@@ -2234,6 +2234,7 @@
 	conf1_write(lanai);
 #endif
 	iounmap(lanai->base);
+	lanai->base = NULL;
     error_pci:
 	pci_disable_device(lanai->pci);
     error:
@@ -2246,6 +2247,8 @@
 static void lanai_dev_close(struct atm_dev *atmdev)
 {
 	struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data;
+	if (lanai->base==NULL)
+		return;
 	printk(KERN_INFO DEV_LABEL "(itf %d): shutting down interface\n",
 	    lanai->number);
 	lanai_timed_poll_stop(lanai);
@@ -2555,7 +2558,7 @@
 	struct atm_dev *atmdev;
 	int result;
 
-	lanai = kmalloc(sizeof(*lanai), GFP_KERNEL);
+	lanai = kzalloc(sizeof(*lanai), GFP_KERNEL);
 	if (lanai == NULL) {
 		printk(KERN_ERR DEV_LABEL
 		       ": couldn't allocate dev_data structure!\n");
--- linux-ein-5.4.0.orig/drivers/atm/nicstar.c
+++ linux-ein-5.4.0/drivers/atm/nicstar.c
@@ -297,7 +297,7 @@
 {
 	XPRINTK("nicstar: nicstar_cleanup() called.\n");
 
-	del_timer(&ns_timer);
+	del_timer_sync(&ns_timer);
 
 	pci_unregister_driver(&nicstar_driver);
 
@@ -525,6 +525,15 @@
 	/* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
 	writel(0x00000000, card->membase + VPM);
 
+	card->intcnt = 0;
+	if (request_irq
+	    (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
+		pr_err("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+		error = 9;
+		ns_init_card_error(card, error);
+		return error;
+	}
+
 	/* Initialize TSQ */
 	card->tsq.org = dma_alloc_coherent(&card->pcidev->dev,
 					   NS_TSQSIZE + NS_TSQ_ALIGNMENT,
@@ -751,15 +760,6 @@
 
 	card->efbie = 1;
 
-	card->intcnt = 0;
-	if (request_irq
-	    (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
-		printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
-		error = 9;
-		ns_init_card_error(card, error);
-		return error;
-	}
-
 	/* Register device */
 	card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops,
 					-1, NULL);
@@ -837,10 +837,12 @@
 			dev_kfree_skb_any(hb);
 	}
 	if (error >= 12) {
-		kfree(card->rsq.org);
+		dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+				card->rsq.org, card->rsq.dma);
 	}
 	if (error >= 11) {
-		kfree(card->tsq.org);
+		dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+				card->tsq.org, card->tsq.dma);
 	}
 	if (error >= 10) {
 		free_irq(card->pcidev->irq, card);
@@ -1706,6 +1708,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-ein-5.4.0.orig/drivers/atm/solos-pci.c
+++ linux-ein-5.4.0/drivers/atm/solos-pci.c
@@ -449,9 +449,9 @@
 	struct sk_buff *skb;
 	unsigned int len;
 
-	spin_lock(&card->cli_queue_lock);
+	spin_lock_bh(&card->cli_queue_lock);
 	skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]);
-	spin_unlock(&card->cli_queue_lock);
+	spin_unlock_bh(&card->cli_queue_lock);
 	if(skb == NULL)
 		return sprintf(buf, "No data.\n");
 
@@ -956,14 +956,14 @@
 	struct pkt_hdr *header;
 
 	/* Remove any yet-to-be-transmitted packets from the pending queue */
-	spin_lock(&card->tx_queue_lock);
+	spin_lock_bh(&card->tx_queue_lock);
 	skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) {
 		if (SKB_CB(skb)->vcc == vcc) {
 			skb_unlink(skb, &card->tx_queue[port]);
 			solos_pop(vcc, skb);
 		}
 	}
-	spin_unlock(&card->tx_queue_lock);
+	spin_unlock_bh(&card->tx_queue_lock);
 
 	skb = alloc_skb(sizeof(*header), GFP_KERNEL);
 	if (!skb) {
--- linux-ein-5.4.0.orig/drivers/atm/uPD98402.c
+++ linux-ein-5.4.0/drivers/atm/uPD98402.c
@@ -211,7 +211,7 @@
 static int uPD98402_start(struct atm_dev *dev)
 {
 	DPRINTK("phy_start\n");
-	if (!(dev->dev_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	spin_lock_init(&PRIV(dev)->lock);
 	memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
--- linux-ein-5.4.0.orig/drivers/atm/zatm.c
+++ linux-ein-5.4.0/drivers/atm/zatm.c
@@ -940,7 +940,7 @@
 	    vcc->qos.txtp.max_pcr >= ATM_OC3_PCR);
 	if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr;
 	else {
-		int uninitialized_var(pcr);
+		int pcr;
 
 		if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU;
 		if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr,
--- linux-ein-5.4.0.orig/drivers/auxdisplay/ht16k33.c
+++ linux-ein-5.4.0/drivers/auxdisplay/ht16k33.c
@@ -117,8 +117,7 @@
 {
 	struct ht16k33_fbdev *fbdev = &priv->fbdev;
 
-	schedule_delayed_work(&fbdev->work,
-			      msecs_to_jiffies(HZ / fbdev->refresh_rate));
+	schedule_delayed_work(&fbdev->work, HZ / fbdev->refresh_rate);
 }
 
 /*
@@ -220,6 +219,15 @@
 	.check_fb	= ht16k33_bl_check_fb,
 };
 
+/*
+ * Blank events will be passed to the actual device handling the backlight when
+ * we return zero here.
+ */
+static int ht16k33_blank(int blank, struct fb_info *info)
+{
+	return 0;
+}
+
 static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct ht16k33_priv *priv = info->par;
@@ -232,6 +240,7 @@
 	.owner = THIS_MODULE,
 	.fb_read = fb_sys_read,
 	.fb_write = fb_sys_write,
+	.fb_blank = ht16k33_blank,
 	.fb_fillrect = sys_fillrect,
 	.fb_copyarea = sys_copyarea,
 	.fb_imageblit = sys_imageblit,
@@ -419,6 +428,33 @@
 	if (err)
 		return err;
 
+	/* Backlight */
+	memset(&bl_props, 0, sizeof(struct backlight_properties));
+	bl_props.type = BACKLIGHT_RAW;
+	bl_props.max_brightness = MAX_BRIGHTNESS;
+
+	bl = devm_backlight_device_register(&client->dev, DRIVER_NAME"-bl",
+					    &client->dev, priv,
+					    &ht16k33_bl_ops, &bl_props);
+	if (IS_ERR(bl)) {
+		dev_err(&client->dev, "failed to register backlight\n");
+		return PTR_ERR(bl);
+	}
+
+	err = of_property_read_u32(node, "default-brightness-level",
+				   &dft_brightness);
+	if (err) {
+		dft_brightness = MAX_BRIGHTNESS;
+	} else if (dft_brightness > MAX_BRIGHTNESS) {
+		dev_warn(&client->dev,
+			 "invalid default brightness level: %u, using %u\n",
+			 dft_brightness, MAX_BRIGHTNESS);
+		dft_brightness = MAX_BRIGHTNESS;
+	}
+
+	bl->props.brightness = dft_brightness;
+	ht16k33_bl_update_status(bl);
+
 	/* Framebuffer (2 bytes per column) */
 	BUILD_BUG_ON(PAGE_SIZE < HT16K33_FB_SIZE);
 	fbdev->buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
@@ -451,6 +487,7 @@
 	fbdev->info->screen_size = HT16K33_FB_SIZE;
 	fbdev->info->fix = ht16k33_fb_fix;
 	fbdev->info->var = ht16k33_fb_var;
+	fbdev->info->bl_dev = bl;
 	fbdev->info->pseudo_palette = NULL;
 	fbdev->info->flags = FBINFO_FLAG_DEFAULT;
 	fbdev->info->par = priv;
@@ -463,34 +500,6 @@
 	if (err)
 		goto err_fbdev_unregister;
 
-	/* Backlight */
-	memset(&bl_props, 0, sizeof(struct backlight_properties));
-	bl_props.type = BACKLIGHT_RAW;
-	bl_props.max_brightness = MAX_BRIGHTNESS;
-
-	bl = devm_backlight_device_register(&client->dev, DRIVER_NAME"-bl",
-					    &client->dev, priv,
-					    &ht16k33_bl_ops, &bl_props);
-	if (IS_ERR(bl)) {
-		dev_err(&client->dev, "failed to register backlight\n");
-		err = PTR_ERR(bl);
-		goto err_fbdev_unregister;
-	}
-
-	err = of_property_read_u32(node, "default-brightness-level",
-				   &dft_brightness);
-	if (err) {
-		dft_brightness = MAX_BRIGHTNESS;
-	} else if (dft_brightness > MAX_BRIGHTNESS) {
-		dev_warn(&client->dev,
-			 "invalid default brightness level: %u, using %u\n",
-			 dft_brightness, MAX_BRIGHTNESS);
-		dft_brightness = MAX_BRIGHTNESS;
-	}
-
-	bl->props.brightness = dft_brightness;
-	ht16k33_bl_update_status(bl);
-
 	ht16k33_fb_queue(priv);
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/auxdisplay/img-ascii-lcd.c
+++ linux-ein-5.4.0/drivers/auxdisplay/img-ascii-lcd.c
@@ -280,6 +280,16 @@
 	if (msg[count - 1] == '\n')
 		count--;
 
+	if (!count) {
+		/* clear the LCD */
+		devm_kfree(&ctx->pdev->dev, ctx->message);
+		ctx->message = NULL;
+		ctx->message_len = 0;
+		memset(ctx->curr, ' ', ctx->cfg->num_chars);
+		ctx->cfg->update(ctx);
+		return 0;
+	}
+
 	new_msg = devm_kmalloc(&ctx->pdev->dev, count + 1, GFP_KERNEL);
 	if (!new_msg)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/base/arch_topology.c
+++ linux-ein-5.4.0/drivers/base/arch_topology.c
@@ -48,7 +48,7 @@
 {
 	struct cpu *cpu = container_of(dev, struct cpu, dev);
 
-	return sprintf(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
+	return sysfs_emit(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
 }
 
 static void update_topology_flags_workfn(struct work_struct *work);
@@ -270,7 +270,7 @@
 static int __init parse_core(struct device_node *core, int package_id,
 			     int core_id)
 {
-	char name[10];
+	char name[20];
 	bool leaf = true;
 	int i = 0;
 	int cpu;
@@ -317,7 +317,7 @@
 
 static int __init parse_cluster(struct device_node *cluster, int depth)
 {
-	char name[10];
+	char name[20];
 	bool leaf = true;
 	bool has_cores = false;
 	struct device_node *c;
@@ -457,7 +457,7 @@
 	for_each_online_cpu(cpu) {
 		cpu_topo = &cpu_topology[cpu];
 
-		if (cpuid_topo->llc_id == cpu_topo->llc_id) {
+		if (cpu_topo->llc_id != -1 && cpuid_topo->llc_id == cpu_topo->llc_id) {
 			cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling);
 			cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling);
 		}
@@ -538,4 +538,23 @@
 	else if (of_have_populated_dt() && parse_dt_topology())
 		reset_cpu_topology();
 }
+
+void store_cpu_topology(unsigned int cpuid)
+{
+	struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
+
+	if (cpuid_topo->package_id != -1)
+		goto topology_populated;
+
+	cpuid_topo->thread_id = -1;
+	cpuid_topo->core_id = cpuid;
+	cpuid_topo->package_id = cpu_to_node(cpuid);
+
+	pr_debug("CPU%u: package %d core %d thread %d\n",
+		 cpuid, cpuid_topo->package_id, cpuid_topo->core_id,
+		 cpuid_topo->thread_id);
+
+topology_populated:
+	update_siblings_masks(cpuid);
+}
 #endif
--- linux-ein-5.4.0.orig/drivers/base/bus.c
+++ linux-ein-5.4.0/drivers/base/bus.c
@@ -620,7 +620,7 @@
 	if (drv->bus->p->drivers_autoprobe) {
 		error = driver_attach(drv);
 		if (error)
-			goto out_unregister;
+			goto out_del_list;
 	}
 	module_add_driver(drv->owner, drv);
 
@@ -647,6 +647,8 @@
 
 	return 0;
 
+out_del_list:
+	klist_del(&priv->knode_bus);
 out_unregister:
 	kobject_put(&priv->kobj);
 	/* drv->p is freed in driver_release()  */
--- linux-ein-5.4.0.orig/drivers/base/cacheinfo.c
+++ linux-ein-5.4.0/drivers/base/cacheinfo.c
@@ -377,7 +377,7 @@
 {
 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%uK\n", this_leaf->size >> 10);
+	return sysfs_emit(buf, "%uK\n", this_leaf->size >> 10);
 }
 
 static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf)
@@ -407,11 +407,11 @@
 
 	switch (this_leaf->type) {
 	case CACHE_TYPE_DATA:
-		return sprintf(buf, "Data\n");
+		return sysfs_emit(buf, "Data\n");
 	case CACHE_TYPE_INST:
-		return sprintf(buf, "Instruction\n");
+		return sysfs_emit(buf, "Instruction\n");
 	case CACHE_TYPE_UNIFIED:
-		return sprintf(buf, "Unified\n");
+		return sysfs_emit(buf, "Unified\n");
 	default:
 		return -EINVAL;
 	}
@@ -425,11 +425,11 @@
 	int n = 0;
 
 	if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE))
-		n = sprintf(buf, "ReadWriteAllocate\n");
+		n = sysfs_emit(buf, "ReadWriteAllocate\n");
 	else if (ci_attr & CACHE_READ_ALLOCATE)
-		n = sprintf(buf, "ReadAllocate\n");
+		n = sysfs_emit(buf, "ReadAllocate\n");
 	else if (ci_attr & CACHE_WRITE_ALLOCATE)
-		n = sprintf(buf, "WriteAllocate\n");
+		n = sysfs_emit(buf, "WriteAllocate\n");
 	return n;
 }
 
@@ -441,9 +441,9 @@
 	int n = 0;
 
 	if (ci_attr & CACHE_WRITE_THROUGH)
-		n = sprintf(buf, "WriteThrough\n");
+		n = sysfs_emit(buf, "WriteThrough\n");
 	else if (ci_attr & CACHE_WRITE_BACK)
-		n = sprintf(buf, "WriteBack\n");
+		n = sysfs_emit(buf, "WriteBack\n");
 	return n;
 }
 
--- linux-ein-5.4.0.orig/drivers/base/class.c
+++ linux-ein-5.4.0/drivers/base/class.c
@@ -191,6 +191,11 @@
 	}
 	error = class_add_groups(class_get(cls), cls->class_groups);
 	class_put(cls);
+	if (error) {
+		kobject_del(&cp->subsys.kobj);
+		kfree_const(cp->subsys.kobj.name);
+		kfree(cp);
+	}
 	return error;
 }
 EXPORT_SYMBOL_GPL(__class_register);
--- linux-ein-5.4.0.orig/drivers/base/component.c
+++ linux-ein-5.4.0/drivers/base/component.c
@@ -102,11 +102,11 @@
 	seq_printf(s, "%-40s %20s\n", "device name", "status");
 	seq_puts(s, "-------------------------------------------------------------\n");
 	for (i = 0; i < match->num; i++) {
-		struct device *d = (struct device *)match->compare[i].data;
+		struct component *component = match->compare[i].component;
 
-		seq_printf(s, "%-40s %20s\n", dev_name(d),
-			   match->compare[i].component ?
-			   "registered" : "not registered");
+		seq_printf(s, "%-40s %20s\n",
+			   component ? dev_name(component->dev) : "(unknown)",
+			   component ? (component->bound ? "bound" : "not bound") : "not registered");
 	}
 	mutex_unlock(&component_mutex);
 
@@ -257,7 +257,8 @@
 	ret = master->ops->bind(master->dev);
 	if (ret < 0) {
 		devres_release_group(master->dev, NULL);
-		dev_info(master->dev, "master bind failed: %d\n", ret);
+		if (ret != -EPROBE_DEFER)
+			dev_info(master->dev, "master bind failed: %d\n", ret);
 		return ret;
 	}
 
@@ -611,8 +612,9 @@
 		devres_release_group(component->dev, NULL);
 		devres_release_group(master->dev, NULL);
 
-		dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
-			dev_name(component->dev), component->ops, ret);
+		if (ret != -EPROBE_DEFER)
+			dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+				dev_name(component->dev), component->ops, ret);
 	}
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/base/core.c
+++ linux-ein-5.4.0/drivers/base/core.c
@@ -106,6 +106,16 @@
 #endif
 #endif /* !CONFIG_SRCU */
 
+static bool device_is_ancestor(struct device *dev, struct device *target)
+{
+	while (target->parent) {
+		target = target->parent;
+		if (dev == target)
+			return true;
+	}
+	return false;
+}
+
 /**
  * device_is_dependent - Check if one device depends on another one
  * @dev: Device to check dependencies for.
@@ -119,7 +129,12 @@
 	struct device_link *link;
 	int ret;
 
-	if (dev == target)
+	/*
+	 * The "ancestors" check is needed to catch the case when the target
+	 * device has not been completely initialized yet and it is still
+	 * missing from the list of children of its parent device.
+	 */
+	if (dev == target || device_is_ancestor(dev, target))
 		return 1;
 
 	ret = device_for_each_child(dev, target, device_is_dependent);
@@ -454,8 +469,7 @@
 	dev_dbg(link->consumer, "Dropping the link to %s\n",
 		dev_name(link->supplier));
 
-	if (link->flags & DL_FLAG_PM_RUNTIME)
-		pm_runtime_drop_link(link->consumer);
+	pm_runtime_drop_link(link);
 
 	list_del_rcu(&link->s_node);
 	list_del_rcu(&link->c_node);
@@ -469,8 +483,7 @@
 	dev_info(link->consumer, "Dropping the link to %s\n",
 		 dev_name(link->supplier));
 
-	if (link->flags & DL_FLAG_PM_RUNTIME)
-		pm_runtime_drop_link(link->consumer);
+	pm_runtime_drop_link(link);
 
 	list_del(&link->s_node);
 	list_del(&link->c_node);
@@ -1014,7 +1027,7 @@
 			  char *buf)
 {
 	struct dev_ext_attribute *ea = to_ext_attr(attr);
-	return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
+	return sysfs_emit(buf, "%lx\n", *(unsigned long *)(ea->var));
 }
 EXPORT_SYMBOL_GPL(device_show_ulong);
 
@@ -1044,7 +1057,7 @@
 {
 	struct dev_ext_attribute *ea = to_ext_attr(attr);
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
+	return sysfs_emit(buf, "%d\n", *(int *)(ea->var));
 }
 EXPORT_SYMBOL_GPL(device_show_int);
 
@@ -1065,7 +1078,7 @@
 {
 	struct dev_ext_attribute *ea = to_ext_attr(attr);
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var));
+	return sysfs_emit(buf, "%d\n", *(bool *)(ea->var));
 }
 EXPORT_SYMBOL_GPL(device_show_bool);
 
@@ -1297,7 +1310,7 @@
 	device_lock(dev);
 	val = !dev->offline;
 	device_unlock(dev);
-	return sprintf(buf, "%u\n", val);
+	return sysfs_emit(buf, "%u\n", val);
 }
 
 static ssize_t online_store(struct device *dev, struct device_attribute *attr,
@@ -1709,6 +1722,7 @@
 	device_pm_init(dev);
 	set_dev_node(dev, -1);
 #ifdef CONFIG_GENERIC_MSI_IRQ
+	raw_spin_lock_init(&dev->msi_lock);
 	INIT_LIST_HEAD(&dev->msi_list);
 #endif
 	INIT_LIST_HEAD(&dev->links.consumers);
@@ -3170,6 +3184,126 @@
 }
 EXPORT_SYMBOL_GPL(device_move);
 
+static int device_attrs_change_owner(struct device *dev, kuid_t kuid,
+				     kgid_t kgid)
+{
+	struct kobject *kobj = &dev->kobj;
+	struct class *class = dev->class;
+	const struct device_type *type = dev->type;
+	int error;
+
+	if (class) {
+		/*
+		 * Change the device groups of the device class for @dev to
+		 * @kuid/@kgid.
+		 */
+		error = sysfs_groups_change_owner(kobj, class->dev_groups, kuid,
+						  kgid);
+		if (error)
+			return error;
+	}
+
+	if (type) {
+		/*
+		 * Change the device groups of the device type for @dev to
+		 * @kuid/@kgid.
+		 */
+		error = sysfs_groups_change_owner(kobj, type->groups, kuid,
+						  kgid);
+		if (error)
+			return error;
+	}
+
+	/* Change the device groups of @dev to @kuid/@kgid. */
+	error = sysfs_groups_change_owner(kobj, dev->groups, kuid, kgid);
+	if (error)
+		return error;
+
+	if (device_supports_offline(dev) && !dev->offline_disabled) {
+		/* Change online device attributes of @dev to @kuid/@kgid. */
+		error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name,
+						kuid, kgid);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+/**
+ * device_change_owner - change the owner of an existing device.
+ * @dev: device.
+ * @kuid: new owner's kuid
+ * @kgid: new owner's kgid
+ *
+ * This changes the owner of @dev and its corresponding sysfs entries to
+ * @kuid/@kgid. This function closely mirrors how @dev was added via driver
+ * core.
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
+{
+	int error;
+	struct kobject *kobj = &dev->kobj;
+
+	dev = get_device(dev);
+	if (!dev)
+		return -EINVAL;
+
+	/*
+	 * Change the kobject and the default attributes and groups of the
+	 * ktype associated with it to @kuid/@kgid.
+	 */
+	error = sysfs_change_owner(kobj, kuid, kgid);
+	if (error)
+		goto out;
+
+	/*
+	 * Change the uevent file for @dev to the new owner. The uevent file
+	 * was created in a separate step when @dev got added and we mirror
+	 * that step here.
+	 */
+	error = sysfs_file_change_owner(kobj, dev_attr_uevent.attr.name, kuid,
+					kgid);
+	if (error)
+		goto out;
+
+	/*
+	 * Change the device groups, the device groups associated with the
+	 * device class, and the groups associated with the device type of @dev
+	 * to @kuid/@kgid.
+	 */
+	error = device_attrs_change_owner(dev, kuid, kgid);
+	if (error)
+		goto out;
+
+	error = dpm_sysfs_change_owner(dev, kuid, kgid);
+	if (error)
+		goto out;
+
+#ifdef CONFIG_BLOCK
+	if (sysfs_deprecated && dev->class == &block_class)
+		goto out;
+#endif
+
+	/*
+	 * Change the owner of the symlink located in the class directory of
+	 * the device class associated with @dev which points to the actual
+	 * directory entry for @dev to @kuid/@kgid. This ensures that the
+	 * symlink shows the same permissions as its target.
+	 */
+	error = sysfs_link_change_owner(&dev->class->p->subsys.kobj, &dev->kobj,
+					dev_name(dev), kuid, kgid);
+	if (error)
+		goto out;
+
+out:
+	put_device(dev);
+	return error;
+}
+EXPORT_SYMBOL_GPL(device_change_owner);
+
 /**
  * device_shutdown - call ->shutdown() on each device to shutdown.
  */
@@ -3385,6 +3519,50 @@
 
 #endif
 
+/**
+ * dev_err_probe - probe error check and log helper
+ * @dev: the pointer to the struct device
+ * @err: error value to test
+ * @fmt: printf-style format string
+ * @...: arguments as specified in the format string
+ *
+ * This helper implements common pattern present in probe functions for error
+ * checking: print debug or error message depending if the error value is
+ * -EPROBE_DEFER and propagate error upwards.
+ * It replaces code sequence::
+ * 	if (err != -EPROBE_DEFER)
+ * 		dev_err(dev, ...);
+ * 	else
+ * 		dev_dbg(dev, ...);
+ * 	return err;
+ *
+ * with::
+ *
+ * 	return dev_err_probe(dev, err, ...);
+ *
+ * Returns @err.
+ *
+ */
+int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (err != -EPROBE_DEFER)
+		dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
+	else
+		dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
+
+	va_end(args);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(dev_err_probe);
+
 static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
 {
 	return fwnode && !IS_ERR(fwnode->secondary);
@@ -3400,9 +3578,10 @@
  */
 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;
 
@@ -3412,8 +3591,13 @@
 		}
 		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);
@@ -3454,6 +3638,13 @@
 }
 EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
 
+void device_set_node(struct device *dev, struct fwnode_handle *fwnode)
+{
+	dev->fwnode = fwnode;
+	dev->of_node = to_of_node(fwnode);
+}
+EXPORT_SYMBOL_GPL(device_set_node);
+
 int device_match_name(struct device *dev, const void *name)
 {
 	return sysfs_streq(dev_name(dev), name);
--- linux-ein-5.4.0.orig/drivers/base/cpu.c
+++ linux-ein-5.4.0/drivers/base/cpu.c
@@ -156,7 +156,7 @@
 	 * operation should be safe. No locking required.
 	 */
 	addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
-	rc = sprintf(buf, "%Lx\n", addr);
+	rc = sysfs_emit(buf, "%Lx\n", addr);
 	return rc;
 }
 static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL);
@@ -167,7 +167,7 @@
 {
 	ssize_t rc;
 
-	rc = sprintf(buf, "%zu\n", sizeof(note_buf_t));
+	rc = sysfs_emit(buf, "%zu\n", sizeof(note_buf_t));
 	return rc;
 }
 static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL);
@@ -231,8 +231,7 @@
 static ssize_t print_cpus_kernel_max(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
-	return n;
+	return sprintf(buf, "%d\n", NR_CPUS - 1);
 }
 static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
 
@@ -272,7 +271,7 @@
 static ssize_t print_cpus_isolated(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	int n = 0, len = PAGE_SIZE-2;
+	int n;
 	cpumask_var_t isolated;
 
 	if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
@@ -280,7 +279,7 @@
 
 	cpumask_andnot(isolated, cpu_possible_mask,
 		       housekeeping_cpumask(HK_FLAG_DOMAIN));
-	n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(isolated));
+	n = sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(isolated));
 
 	free_cpumask_var(isolated);
 
@@ -292,11 +291,7 @@
 static ssize_t print_cpus_nohz_full(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	int n = 0, len = PAGE_SIZE-2;
-
-	n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
-
-	return n;
+	return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
 }
 static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
 #endif
@@ -328,8 +323,8 @@
 	ssize_t n;
 	u32 i;
 
-	n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
-		    CPU_FEATURE_TYPEVAL);
+	n = sysfs_emit(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
+		       CPU_FEATURE_TYPEVAL);
 
 	for (i = 0; i < MAX_CPU_FEATURES; i++)
 		if (cpu_have_feature(i)) {
@@ -496,7 +491,8 @@
 bool cpu_is_hotpluggable(unsigned cpu)
 {
 	struct device *dev = get_cpu_device(cpu);
-	return dev && container_of(dev, struct cpu, dev)->hotpluggable;
+	return dev && container_of(dev, struct cpu, dev)->hotpluggable
+		&& tick_nohz_cpu_hotpluggable(cpu);
 }
 EXPORT_SYMBOL_GPL(cpu_is_hotpluggable);
 
@@ -521,50 +517,74 @@
 ssize_t __weak cpu_show_meltdown(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "Not affected\n");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(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");
+	return sysfs_emit(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_srbds(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(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");
 }
 
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
@@ -575,6 +595,10 @@
 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 struct attribute *cpu_root_vulnerabilities_attrs[] = {
 	&dev_attr_meltdown.attr,
@@ -585,6 +609,10 @@
 	&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,
 	NULL
 };
 
--- linux-ein-5.4.0.orig/drivers/base/dd.c
+++ linux-ein-5.4.0/drivers/base/dd.c
@@ -300,14 +300,16 @@
 
 static void deferred_probe_timeout_work_func(struct work_struct *work)
 {
-	struct device_private *private, *p;
+	struct device_private *p;
 
 	deferred_probe_timeout = 0;
 	driver_deferred_probe_trigger();
 	flush_work(&deferred_probe_work);
 
-	list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
-		dev_info(private->device, "deferred probe pending");
+	mutex_lock(&deferred_probe_mutex);
+	list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
+		dev_info(p->device, "deferred probe pending\n");
+	mutex_unlock(&deferred_probe_mutex);
 }
 static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
 
@@ -516,7 +518,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;
+	}
 
 re_probe:
 	dev->driver = drv;
@@ -636,7 +642,7 @@
 	ret = 0;
 done:
 	atomic_dec(&probe_count);
-	wake_up(&probe_waitqueue);
+	wake_up_all(&probe_waitqueue);
 	return ret;
 }
 
@@ -741,7 +747,7 @@
 			"Too long list of driver names for 'driver_async_probe'!\n");
 
 	strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
-	return 0;
+	return 1;
 }
 __setup("driver_async_probe=", save_async_options);
 
@@ -812,6 +818,11 @@
 	} else if (ret == -EPROBE_DEFER) {
 		dev_dbg(dev, "Device match requests probe deferral\n");
 		driver_deferred_probe_add(dev);
+		/*
+		 * Device can't match with a driver right now, so don't attempt
+		 * to match or bind with other drivers on the bus.
+		 */
+		return ret;
 	} else if (ret < 0) {
 		dev_dbg(dev, "Bus failed to match device: %d", ret);
 		return ret;
@@ -867,9 +878,12 @@
 static int __device_attach(struct device *dev, bool allow_async)
 {
 	int ret = 0;
+	bool async = false;
 
 	device_lock(dev);
-	if (dev->driver) {
+	if (dev->p->dead) {
+		goto out_unlock;
+	} else if (dev->driver) {
 		if (device_is_bound(dev)) {
 			ret = 1;
 			goto out_unlock;
@@ -903,7 +917,7 @@
 			 */
 			dev_dbg(dev, "scheduling asynchronous probe\n");
 			get_device(dev);
-			async_schedule_dev(__device_attach_async_helper, dev);
+			async = true;
 		} else {
 			pm_request_idle(dev);
 		}
@@ -913,6 +927,8 @@
 	}
 out_unlock:
 	device_unlock(dev);
+	if (async)
+		async_schedule_dev(__device_attach_async_helper, dev);
 	return ret;
 }
 
@@ -1026,6 +1042,7 @@
 static int __driver_attach(struct device *dev, void *data)
 {
 	struct device_driver *drv = data;
+	bool async = false;
 	int ret;
 
 	/*
@@ -1045,9 +1062,18 @@
 	} else if (ret == -EPROBE_DEFER) {
 		dev_dbg(dev, "Device match requests probe deferral\n");
 		driver_deferred_probe_add(dev);
+		/*
+		 * Driver could not match with device, but may match with
+		 * another device on the bus.
+		 */
+		return 0;
 	} else if (ret < 0) {
-		dev_dbg(dev, "Bus failed to match device: %d", ret);
-		return ret;
+		dev_dbg(dev, "Bus failed to match device: %d\n", ret);
+		/*
+		 * Driver could not match with device, but may match with
+		 * another device on the bus.
+		 */
+		return 0;
 	} /* ret > 0 means positive match */
 
 	if (driver_allows_async_probing(drv)) {
@@ -1063,9 +1089,11 @@
 		if (!dev->driver) {
 			get_device(dev);
 			dev->p->async_driver = drv;
-			async_schedule_dev(__driver_attach_async_helper, dev);
+			async = true;
 		}
 		device_unlock(dev);
+		if (async)
+			async_schedule_dev(__driver_attach_async_helper, dev);
 		return 0;
 	}
 
@@ -1099,6 +1127,8 @@
 
 	drv = dev->driver;
 	if (drv) {
+		pm_runtime_get_sync(dev);
+
 		while (device_links_busy(dev)) {
 			__device_driver_unlock(dev, parent);
 
@@ -1110,13 +1140,12 @@
 			 * have released the driver successfully while this one
 			 * was waiting, so check for that.
 			 */
-			if (dev->driver != drv)
+			if (dev->driver != drv) {
+				pm_runtime_put(dev);
 				return;
+			}
 		}
 
-		pm_runtime_get_sync(dev);
-		pm_runtime_clean_up_links(dev);
-
 		driver_sysfs_remove(dev);
 
 		if (dev->bus)
@@ -1132,8 +1161,13 @@
 			dev->bus->remove(dev);
 		else if (drv->remove)
 			drv->remove(dev);
-
-		device_links_driver_cleanup(dev);
+		/*
+		 * A concurrent invocation of the same function might
+		 * have released the driver successfully while this one
+		 * was waiting, so check for that.
+		 */
+		if (dev->driver != drv)
+			return;
 
 		devres_release_all(dev);
 		arch_teardown_dma_ops(dev);
@@ -1144,6 +1178,8 @@
 		pm_runtime_reinit(dev);
 		dev_pm_set_driver_flags(dev, 0);
 
+		device_links_driver_cleanup(dev);
+
 		klist_remove(&dev->p->knode_driver);
 		device_pm_check_callbacks(dev);
 		if (dev->bus)
--- linux-ein-5.4.0.orig/drivers/base/devcoredump.c
+++ linux-ein-5.4.0/drivers/base/devcoredump.c
@@ -29,6 +29,47 @@
 	struct device devcd_dev;
 	void *data;
 	size_t datalen;
+	/*
+	 * Here, mutex is required to serialize the calls to del_wk work between
+	 * user/kernel space which happens when devcd is added with device_add()
+	 * and that sends uevent to user space. User space reads the uevents,
+	 * and calls to devcd_data_write() which try to modify the work which is
+	 * not even initialized/queued from devcoredump.
+	 *
+	 *
+	 *
+	 *        cpu0(X)                                 cpu1(Y)
+	 *
+	 *        dev_coredump() uevent sent to user space
+	 *        device_add()  ======================> user space process Y reads the
+	 *                                              uevents writes to devcd fd
+	 *                                              which results into writes to
+	 *
+	 *                                             devcd_data_write()
+	 *                                               mod_delayed_work()
+	 *                                                 try_to_grab_pending()
+	 *                                                   del_timer()
+	 *                                                     debug_assert_init()
+	 *       INIT_DELAYED_WORK()
+	 *       schedule_delayed_work()
+	 *
+	 *
+	 * Also, mutex alone would not be enough to avoid scheduling of
+	 * del_wk work after it get flush from a call to devcd_free()
+	 * mentioned as below.
+	 *
+	 *	disabled_store()
+	 *        devcd_free()
+	 *          mutex_lock()             devcd_data_write()
+	 *          flush_delayed_work()
+	 *          mutex_unlock()
+	 *                                   mutex_lock()
+	 *                                   mod_delayed_work()
+	 *                                   mutex_unlock()
+	 * So, delete_work flag is required.
+	 */
+	struct mutex mutex;
+	bool delete_work;
 	struct module *owner;
 	ssize_t (*read)(char *buffer, loff_t offset, size_t count,
 			void *data, size_t datalen);
@@ -88,7 +129,12 @@
 	struct device *dev = kobj_to_dev(kobj);
 	struct devcd_entry *devcd = dev_to_devcd(dev);
 
-	mod_delayed_work(system_wq, &devcd->del_wk, 0);
+	mutex_lock(&devcd->mutex);
+	if (!devcd->delete_work) {
+		devcd->delete_work = true;
+		mod_delayed_work(system_wq, &devcd->del_wk, 0);
+	}
+	mutex_unlock(&devcd->mutex);
 
 	return count;
 }
@@ -116,7 +162,12 @@
 {
 	struct devcd_entry *devcd = dev_to_devcd(dev);
 
+	mutex_lock(&devcd->mutex);
+	if (!devcd->delete_work)
+		devcd->delete_work = true;
+
 	flush_delayed_work(&devcd->del_wk);
+	mutex_unlock(&devcd->mutex);
 	return 0;
 }
 
@@ -126,6 +177,30 @@
 	return sprintf(buf, "%d\n", devcd_disabled);
 }
 
+/*
+ *
+ *	disabled_store()                                	worker()
+ *	 class_for_each_device(&devcd_class,
+ *		NULL, NULL, devcd_free)
+ *         ...
+ *         ...
+ *	   while ((dev = class_dev_iter_next(&iter))
+ *                                                             devcd_del()
+ *                                                               device_del()
+ *                                                                 put_device() <- last reference
+ *             error = fn(dev, data)                           devcd_dev_release()
+ *             devcd_free(dev, data)                           kfree(devcd)
+ *             mutex_lock(&devcd->mutex);
+ *
+ *
+ * In the above diagram, It looks like disabled_store() would be racing with parallely
+ * running devcd_del() and result in memory abort while acquiring devcd->mutex which
+ * is called after kfree of devcd memory  after dropping its last reference with
+ * put_device(). However, this will not happens as fn(dev, data) runs
+ * with its own reference to device via klist_node so it is not its last reference.
+ * so, above situation would not occur.
+ */
+
 static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -282,13 +357,17 @@
 	devcd->read = read;
 	devcd->free = free;
 	devcd->failing_dev = get_device(dev);
+	devcd->delete_work = false;
 
+	mutex_init(&devcd->mutex);
 	device_initialize(&devcd->devcd_dev);
 
 	dev_set_name(&devcd->devcd_dev, "devcd%d",
 		     atomic_inc_return(&devcd_count));
 	devcd->devcd_dev.class = &devcd_class;
 
+	mutex_lock(&devcd->mutex);
+	dev_set_uevent_suppress(&devcd->devcd_dev, true);
 	if (device_add(&devcd->devcd_dev))
 		goto put_device;
 
@@ -300,12 +379,15 @@
 			      "devcoredump"))
 		/* nothing - symlink will be missing */;
 
+	dev_set_uevent_suppress(&devcd->devcd_dev, false);
+	kobject_uevent(&devcd->devcd_dev.kobj, KOBJ_ADD);
 	INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
 	schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
-
+	mutex_unlock(&devcd->mutex);
 	return;
  put_device:
 	put_device(&devcd->devcd_dev);
+	mutex_unlock(&devcd->mutex);
  put_module:
 	module_put(owner);
  free:
--- linux-ein-5.4.0.orig/drivers/base/devtmpfs.c
+++ linux-ein-5.4.0/drivers/base/devtmpfs.c
@@ -25,6 +25,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/fs_context.h>
 #include <uapi/linux/mount.h>
 #include "base.h"
 
@@ -62,8 +63,15 @@
 		      const char *dev_name, void *data)
 {
 	struct super_block *s = mnt->mnt_sb;
+	int err;
+
 	atomic_inc(&s->s_active);
 	down_write(&s->s_umount);
+	err = reconfigure_single(s, flags, data);
+	if (err < 0) {
+		deactivate_locked_super(s);
+		return ERR_PTR(err);
+	}
 	return dget(s->s_root);
 }
 
--- linux-ein-5.4.0.orig/drivers/base/driver.c
+++ linux-ein-5.4.0/drivers/base/driver.c
@@ -30,6 +30,75 @@
 }
 
 /**
+ * driver_set_override() - Helper to set or clear driver override.
+ * @dev: Device to change
+ * @override: Address of string to change (e.g. &device->driver_override);
+ *            The contents will be freed and hold newly allocated override.
+ * @s: NUL-terminated string, new driver name to force a match, pass empty
+ *     string to clear it ("" or "\n", where the latter is only for sysfs
+ *     interface).
+ * @len: length of @s
+ *
+ * Helper to set or clear driver override in a device, intended for the cases
+ * when the driver_override field is allocated by driver/bus code.
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int driver_set_override(struct device *dev, const char **override,
+			const char *s, size_t len)
+{
+	const char *new, *old;
+	char *cp;
+
+	if (!override || !s)
+		return -EINVAL;
+
+	/*
+	 * The stored value will be used in sysfs show callback (sysfs_emit()),
+	 * which has a length limit of PAGE_SIZE and adds a trailing newline.
+	 * Thus we can store one character less to avoid truncation during sysfs
+	 * show.
+	 */
+	if (len >= (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	if (!len) {
+		/* Empty string passed - clear override */
+		device_lock(dev);
+		old = *override;
+		*override = NULL;
+		device_unlock(dev);
+		kfree(old);
+
+		return 0;
+	}
+
+	cp = strnchr(s, len, '\n');
+	if (cp)
+		len = cp - s;
+
+	new = kstrndup(s, len, GFP_KERNEL);
+	if (!new)
+		return -ENOMEM;
+
+	device_lock(dev);
+	old = *override;
+	if (cp != s) {
+		*override = new;
+	} else {
+		/* "\n" passed - clear override */
+		kfree(new);
+		*override = NULL;
+	}
+	device_unlock(dev);
+
+	kfree(old);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(driver_set_override);
+
+/**
  * driver_for_each_device - Iterator for devices bound to a driver.
  * @drv: Driver we're iterating.
  * @start: Device to begin with
--- linux-ein-5.4.0.orig/drivers/base/firmware_loader/builtin/Makefile
+++ linux-ein-5.4.0/drivers/base/firmware_loader/builtin/Makefile
@@ -8,7 +8,8 @@
 obj-y  := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE)))
 
 FWNAME    = $(patsubst $(obj)/%.gen.S,%,$@)
-FWSTR     = $(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME))))
+comma     := ,
+FWSTR     = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME)))))
 ASM_WORD  = $(if $(CONFIG_64BIT),.quad,.long)
 ASM_ALIGN = $(if $(CONFIG_64BIT),3,2)
 PROGBITS  = $(if $(CONFIG_ARM),%,@)progbits
@@ -16,7 +17,7 @@
 filechk_fwbin = \
 	echo "/* Generated by $(src)/Makefile */"		;\
 	echo "    .section .rodata"				;\
-	echo "    .p2align $(ASM_ALIGN)"			;\
+	echo "    .p2align 4"					;\
 	echo "_fw_$(FWSTR)_bin:"				;\
 	echo "    .incbin \"$(fwdir)/$(FWNAME)\""		;\
 	echo "_fw_end:"						;\
--- linux-ein-5.4.0.orig/drivers/base/firmware_loader/fallback.c
+++ linux-ein-5.4.0/drivers/base/firmware_loader/fallback.c
@@ -86,12 +86,11 @@
 {
 	/*
 	 * There is a small window in which user can write to 'loading'
-	 * between loading done and disappearance of 'loading'
+	 * between loading done/aborted and disappearance of 'loading'
 	 */
-	if (fw_sysfs_done(fw_priv))
+	if (fw_state_is_aborted(fw_priv) || fw_sysfs_done(fw_priv))
 		return;
 
-	list_del_init(&fw_priv->pending_list);
 	fw_state_aborted(fw_priv);
 }
 
@@ -216,7 +215,7 @@
 		loading = fw_sysfs_loading(fw_sysfs->fw_priv);
 	mutex_unlock(&fw_lock);
 
-	return sprintf(buf, "%d\n", loading);
+	return sysfs_emit(buf, "%d\n", loading);
 }
 
 /**
@@ -277,7 +276,6 @@
 			 * Same logic as fw_load_abort, only the DONE bit
 			 * is ignored and we set ABORT only on failure.
 			 */
-			list_del_init(&fw_priv->pending_list);
 			if (rc) {
 				fw_state_aborted(fw_priv);
 				written = rc;
@@ -512,6 +510,11 @@
 	}
 
 	mutex_lock(&fw_lock);
+	if (fw_state_is_aborted(fw_priv)) {
+		mutex_unlock(&fw_lock);
+		retval = -EINTR;
+		goto out;
+	}
 	list_add(&fw_priv->pending_list, &pending_fw_head);
 	mutex_unlock(&fw_lock);
 
@@ -525,7 +528,7 @@
 	}
 
 	retval = fw_sysfs_wait_timeout(fw_priv, timeout);
-	if (retval < 0) {
+	if (retval < 0 && retval != -ENOENT) {
 		mutex_lock(&fw_lock);
 		fw_load_abort(fw_sysfs);
 		mutex_unlock(&fw_lock);
@@ -534,11 +537,10 @@
 	if (fw_state_is_aborted(fw_priv)) {
 		if (retval == -ERESTARTSYS)
 			retval = -EINTR;
-		else
-			retval = -EAGAIN;
 	} else if (fw_priv->is_paged_buf && !fw_priv->data)
 		retval = -ENOMEM;
 
+out:
 	device_del(f_dev);
 err_put_dev:
 	put_device(f_dev);
--- linux-ein-5.4.0.orig/drivers/base/firmware_loader/firmware.h
+++ linux-ein-5.4.0/drivers/base/firmware_loader/firmware.h
@@ -108,8 +108,16 @@
 
 	WRITE_ONCE(fw_st->status, status);
 
-	if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
+	if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) {
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+		/*
+		 * Doing this here ensures that the fw_priv is deleted from
+		 * the pending list in all abort/done paths.
+		 */
+		list_del_init(&fw_priv->pending_list);
+#endif
 		complete_all(&fw_st->completion);
+	}
 }
 
 static inline void fw_state_aborted(struct fw_priv *fw_priv)
@@ -139,10 +147,12 @@
 void fw_free_paged_buf(struct fw_priv *fw_priv);
 int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
 int fw_map_paged_buf(struct fw_priv *fw_priv);
+bool fw_is_paged_buf(struct fw_priv *fw_priv);
 #else
 static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
 static inline int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
 static inline int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
+static inline bool fw_is_paged_buf(struct fw_priv *fw_priv) { return false; }
 #endif
 
 #endif /* __FIRMWARE_LOADER_H */
--- linux-ein-5.4.0.orig/drivers/base/firmware_loader/main.c
+++ linux-ein-5.4.0/drivers/base/firmware_loader/main.c
@@ -98,12 +98,15 @@
 extern struct builtin_fw __start_builtin_fw[];
 extern struct builtin_fw __end_builtin_fw[];
 
-static void fw_copy_to_prealloc_buf(struct firmware *fw,
+static bool fw_copy_to_prealloc_buf(struct firmware *fw,
 				    void *buf, size_t size)
 {
-	if (!buf || size < fw->size)
-		return;
+	if (!buf)
+		return true;
+	if (size < fw->size)
+		return false;
 	memcpy(buf, fw->data, fw->size);
+	return true;
 }
 
 static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
@@ -115,9 +118,7 @@
 		if (strcmp(name, b_fw->name) == 0) {
 			fw->size = b_fw->size;
 			fw->data = b_fw->data;
-			fw_copy_to_prealloc_buf(fw, buf, size);
-
-			return true;
+			return fw_copy_to_prealloc_buf(fw, buf, size);
 		}
 	}
 
@@ -252,9 +253,11 @@
 	list_del(&fw_priv->list);
 	spin_unlock(&fwc->lock);
 
-	fw_free_paged_buf(fw_priv); /* free leftover pages */
-	if (!fw_priv->allocated_size)
+	if (fw_is_paged_buf(fw_priv))
+		fw_free_paged_buf(fw_priv);
+	else if (!fw_priv->allocated_size)
 		vfree(fw_priv->data);
+
 	kfree_const(fw_priv->fw_name);
 	kfree(fw_priv);
 }
@@ -268,6 +271,11 @@
 }
 
 #ifdef CONFIG_FW_LOADER_PAGED_BUF
+bool fw_is_paged_buf(struct fw_priv *fw_priv)
+{
+	return fw_priv->is_paged_buf;
+}
+
 void fw_free_paged_buf(struct fw_priv *fw_priv)
 {
 	int i;
@@ -275,6 +283,8 @@
 	if (!fw_priv->pages)
 		return;
 
+	vunmap(fw_priv->data);
+
 	for (i = 0; i < fw_priv->nr_pages; i++)
 		__free_page(fw_priv->pages[i]);
 	kvfree(fw_priv->pages);
@@ -328,10 +338,6 @@
 	if (!fw_priv->data)
 		return -ENOMEM;
 
-	/* page table is no longer needed after mapping, let's free */
-	kvfree(fw_priv->pages);
-	fw_priv->pages = NULL;
-
 	return 0;
 }
 #endif
@@ -742,8 +748,10 @@
 		return;
 
 	fw_priv = fw->priv;
+	mutex_lock(&fw_lock);
 	if (!fw_state_is_aborted(fw_priv))
 		fw_state_aborted(fw_priv);
+	mutex_unlock(&fw_lock);
 }
 
 /* called from request_firmware() and request_firmware_work_func() */
@@ -753,6 +761,8 @@
 		  enum fw_opt opt_flags)
 {
 	struct firmware *fw = NULL;
+	struct cred *kern_cred = NULL;
+	const struct cred *old_cred;
 	int ret;
 
 	if (!firmware_p)
@@ -768,6 +778,18 @@
 	if (ret <= 0) /* error or already assigned */
 		goto out;
 
+	/*
+	 * We are about to try to access the firmware file. Because we may have been
+	 * called by a driver when serving an unrelated request from userland, we use
+	 * the kernel credentials to read the file.
+	 */
+	kern_cred = prepare_kernel_cred(NULL);
+	if (!kern_cred) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	old_cred = override_creds(kern_cred);
+
 	ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
 #ifdef CONFIG_FW_LOADER_COMPRESS
 	if (ret == -ENOENT)
@@ -784,6 +806,9 @@
 	} else
 		ret = assign_fw(fw, device, opt_flags);
 
+	revert_creds(old_cred);
+	put_cred(kern_cred);
+
  out:
 	if (ret < 0) {
 		fw_abort_batch_reqs(fw);
--- linux-ein-5.4.0.orig/drivers/base/memory.c
+++ linux-ein-5.4.0/drivers/base/memory.c
@@ -110,34 +110,17 @@
 	unsigned long phys_index;
 
 	phys_index = mem->start_section_nr / sections_per_block;
-	return sprintf(buf, "%08lx\n", phys_index);
+	return sysfs_emit(buf, "%08lx\n", phys_index);
 }
 
 /*
- * Show whether the memory block is likely to be offlineable (or is already
- * offline). Once offline, the memory block could be removed. The return
- * value does, however, not indicate that there is a way to remove the
- * memory block.
+ * Legacy interface that we cannot remove. Always indicate "removable"
+ * with CONFIG_MEMORY_HOTREMOVE - bad heuristic.
  */
 static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
 			      char *buf)
 {
-	struct memory_block *mem = to_memory_block(dev);
-	unsigned long pfn;
-	int ret = 1, i;
-
-	if (mem->state != MEM_ONLINE)
-		goto out;
-
-	for (i = 0; i < sections_per_block; i++) {
-		if (!present_section_nr(mem->start_section_nr + i))
-			continue;
-		pfn = section_nr_to_pfn(mem->start_section_nr + i);
-		ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
-	}
-
-out:
-	return sprintf(buf, "%d\n", ret);
+	return sysfs_emit(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE));
 }
 
 /*
@@ -155,17 +138,17 @@
 	 */
 	switch (mem->state) {
 	case MEM_ONLINE:
-		len = sprintf(buf, "online\n");
+		len = sysfs_emit(buf, "online\n");
 		break;
 	case MEM_OFFLINE:
-		len = sprintf(buf, "offline\n");
+		len = sysfs_emit(buf, "offline\n");
 		break;
 	case MEM_GOING_OFFLINE:
-		len = sprintf(buf, "going-offline\n");
+		len = sysfs_emit(buf, "going-offline\n");
 		break;
 	default:
-		len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
-				mem->state);
+		len = sysfs_emit(buf, "ERROR-UNKNOWN-%ld\n",
+				 mem->state);
 		WARN_ON(1);
 		break;
 	}
@@ -375,7 +358,7 @@
 				struct device_attribute *attr, char *buf)
 {
 	struct memory_block *mem = to_memory_block(dev);
-	return sprintf(buf, "%d\n", mem->phys_device);
+	return sysfs_emit(buf, "%d\n", mem->phys_device);
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
@@ -413,7 +396,7 @@
 		 */
 		if (!test_pages_in_a_zone(start_pfn, start_pfn + nr_pages,
 					  &valid_start_pfn, &valid_end_pfn))
-			return sprintf(buf, "none\n");
+			return sysfs_emit(buf, "none\n");
 		start_pfn = valid_start_pfn;
 		strcat(buf, page_zone(pfn_to_page(start_pfn))->name);
 		goto out;
@@ -446,7 +429,7 @@
 static ssize_t block_size_bytes_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%lx\n", memory_block_size_bytes());
+	return sysfs_emit(buf, "%lx\n", memory_block_size_bytes());
 }
 
 static DEVICE_ATTR_RO(block_size_bytes);
@@ -459,9 +442,9 @@
 				       struct device_attribute *attr, char *buf)
 {
 	if (memhp_auto_online)
-		return sprintf(buf, "online\n");
+		return sysfs_emit(buf, "online\n");
 	else
-		return sprintf(buf, "offline\n");
+		return sysfs_emit(buf, "offline\n");
 }
 
 static ssize_t auto_online_blocks_store(struct device *dev,
--- linux-ein-5.4.0.orig/drivers/base/node.c
+++ linux-ein-5.4.0/drivers/base/node.c
@@ -262,21 +262,20 @@
 	if (!dev)
 		return;
 
+	device_initialize(dev);
 	dev->parent = &node->dev;
 	dev->release = node_cache_release;
 	if (dev_set_name(dev, "memory_side_cache"))
-		goto free_dev;
+		goto put_device;
 
-	if (device_register(dev))
-		goto free_name;
+	if (device_add(dev))
+		goto put_device;
 
 	pm_runtime_no_callbacks(dev);
 	node->cache_dev = dev;
 	return;
-free_name:
-	kfree_const(dev->kobj.name);
-free_dev:
-	kfree(dev);
+put_device:
+	put_device(dev);
 }
 
 /**
@@ -313,25 +312,24 @@
 		return;
 
 	dev = &info->dev;
+	device_initialize(dev);
 	dev->parent = node->cache_dev;
 	dev->release = node_cacheinfo_release;
 	dev->groups = cache_groups;
 	if (dev_set_name(dev, "index%d", cache_attrs->level))
-		goto free_cache;
+		goto put_device;
 
 	info->cache_attrs = *cache_attrs;
-	if (device_register(dev)) {
+	if (device_add(dev)) {
 		dev_warn(&node->dev, "failed to add cache level:%d\n",
 			 cache_attrs->level);
-		goto free_name;
+		goto put_device;
 	}
 	pm_runtime_no_callbacks(dev);
 	list_add_tail(&info->node, &node->cache_attrs);
 	return;
-free_name:
-	kfree_const(dev->kobj.name);
-free_cache:
-	kfree(info);
+put_device:
+	put_device(dev);
 }
 
 static void node_remove_caches(struct node *node)
@@ -370,7 +368,7 @@
 	si_meminfo_node(&i, nid);
 	sreclaimable = node_page_state(pgdat, NR_SLAB_RECLAIMABLE);
 	sunreclaimable = node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE);
-	n = sprintf(buf,
+	n = sysfs_emit(buf,
 		       "Node %d MemTotal:       %8lu kB\n"
 		       "Node %d MemFree:        %8lu kB\n"
 		       "Node %d MemUsed:        %8lu kB\n"
@@ -471,19 +469,19 @@
 static ssize_t node_read_numastat(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf,
-		       "numa_hit %lu\n"
-		       "numa_miss %lu\n"
-		       "numa_foreign %lu\n"
-		       "interleave_hit %lu\n"
-		       "local_node %lu\n"
-		       "other_node %lu\n",
-		       sum_zone_numa_state(dev->id, NUMA_HIT),
-		       sum_zone_numa_state(dev->id, NUMA_MISS),
-		       sum_zone_numa_state(dev->id, NUMA_FOREIGN),
-		       sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
-		       sum_zone_numa_state(dev->id, NUMA_LOCAL),
-		       sum_zone_numa_state(dev->id, NUMA_OTHER));
+	return sysfs_emit(buf,
+			  "numa_hit %lu\n"
+			  "numa_miss %lu\n"
+			  "numa_foreign %lu\n"
+			  "interleave_hit %lu\n"
+			  "local_node %lu\n"
+			  "other_node %lu\n",
+			  sum_zone_numa_state(dev->id, NUMA_HIT),
+			  sum_zone_numa_state(dev->id, NUMA_MISS),
+			  sum_zone_numa_state(dev->id, NUMA_FOREIGN),
+			  sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
+			  sum_zone_numa_state(dev->id, NUMA_LOCAL),
+			  sum_zone_numa_state(dev->id, NUMA_OTHER));
 }
 static DEVICE_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
 
@@ -643,6 +641,7 @@
  */
 void unregister_node(struct node *node)
 {
+	compaction_unregister_node(node);
 	hugetlb_unregister_node(node);		/* no-op, if memoryless node */
 	node_remove_accesses(node);
 	node_remove_caches(node);
@@ -758,14 +757,36 @@
 	return pfn_to_nid(pfn);
 }
 
+static int do_register_memory_block_under_node(int nid,
+					       struct memory_block *mem_blk)
+{
+	int ret;
+
+	/*
+	 * If this memory block spans multiple nodes, we only indicate
+	 * the last processed node.
+	 */
+	mem_blk->nid = nid;
+
+	ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj,
+				       &mem_blk->dev.kobj,
+				       kobject_name(&mem_blk->dev.kobj));
+	if (ret)
+		return ret;
+
+	return sysfs_create_link_nowarn(&mem_blk->dev.kobj,
+				&node_devices[nid]->dev.kobj,
+				kobject_name(&node_devices[nid]->dev.kobj));
+}
+
 /* register memory section under specified node if it spans that node */
-static int register_mem_sect_under_node(struct memory_block *mem_blk,
-					 void *arg)
+static int register_mem_block_under_node_early(struct memory_block *mem_blk,
+					       void *arg)
 {
 	unsigned long memory_block_pfns = memory_block_size_bytes() / PAGE_SIZE;
 	unsigned long start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
 	unsigned long end_pfn = start_pfn + memory_block_pfns - 1;
-	int ret, nid = *(int *)arg;
+	int nid = *(int *)arg;
 	unsigned long pfn;
 
 	for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
@@ -782,39 +803,34 @@
 		}
 
 		/*
-		 * We need to check if page belongs to nid only for the boot
-		 * case, during hotplug we know that all pages in the memory
-		 * block belong to the same node.
-		 */
-		if (system_state == SYSTEM_BOOTING) {
-			page_nid = get_nid_for_pfn(pfn);
-			if (page_nid < 0)
-				continue;
-			if (page_nid != nid)
-				continue;
-		}
-
-		/*
-		 * If this memory block spans multiple nodes, we only indicate
-		 * the last processed node.
+		 * We need to check if page belongs to nid only at the boot
+		 * case because node's ranges can be interleaved.
 		 */
-		mem_blk->nid = nid;
-
-		ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj,
-					&mem_blk->dev.kobj,
-					kobject_name(&mem_blk->dev.kobj));
-		if (ret)
-			return ret;
+		page_nid = get_nid_for_pfn(pfn);
+		if (page_nid < 0)
+			continue;
+		if (page_nid != nid)
+			continue;
 
-		return sysfs_create_link_nowarn(&mem_blk->dev.kobj,
-				&node_devices[nid]->dev.kobj,
-				kobject_name(&node_devices[nid]->dev.kobj));
+		return do_register_memory_block_under_node(nid, mem_blk);
 	}
 	/* mem section does not span the specified node */
 	return 0;
 }
 
 /*
+ * During hotplug we know that all pages in the memory block belong to the same
+ * node.
+ */
+static int register_mem_block_under_node_hotplug(struct memory_block *mem_blk,
+						 void *arg)
+{
+	int nid = *(int *)arg;
+
+	return do_register_memory_block_under_node(nid, mem_blk);
+}
+
+/*
  * Unregister a memory block device under the node it spans. Memory blocks
  * with multiple nodes cannot be offlined and therefore also never be removed.
  */
@@ -829,11 +845,19 @@
 			  kobject_name(&node_devices[mem_blk->nid]->dev.kobj));
 }
 
-int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn)
+int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn,
+		      enum meminit_context context)
 {
+	walk_memory_blocks_func_t func;
+
+	if (context == MEMINIT_HOTPLUG)
+		func = register_mem_block_under_node_hotplug;
+	else
+		func = register_mem_block_under_node_early;
+
 	return walk_memory_blocks(PFN_PHYS(start_pfn),
 				  PFN_PHYS(end_pfn - start_pfn), (void *)&nid,
-				  register_mem_sect_under_node);
+				  func);
 }
 
 #ifdef CONFIG_HUGETLBFS
--- linux-ein-5.4.0.orig/drivers/base/platform.c
+++ linux-ein-5.4.0/drivers/base/platform.c
@@ -27,6 +27,7 @@
 #include <linux/limits.h>
 #include <linux/property.h>
 #include <linux/kmemleak.h>
+#include <linux/types.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -48,7 +49,7 @@
 struct resource *platform_get_resource(struct platform_device *dev,
 				       unsigned int type, unsigned int num)
 {
-	int i;
+	u32 i;
 
 	for (i = 0; i < dev->num_resources; i++) {
 		struct resource *r = &dev->resource[i];
@@ -226,7 +227,7 @@
 					      unsigned int type,
 					      const char *name)
 {
-	int i;
+	u32 i;
 
 	for (i = 0; i < dev->num_resources; i++) {
 		struct resource *r = &dev->resource[i];
@@ -334,10 +335,10 @@
 {
 	if (!pdev->dev.coherent_dma_mask)
 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	if (!pdev->dma_mask)
-		pdev->dma_mask = DMA_BIT_MASK(32);
-	if (!pdev->dev.dma_mask)
-		pdev->dev.dma_mask = &pdev->dma_mask;
+	if (!pdev->dev.dma_mask) {
+		pdev->platform_dma_mask = DMA_BIT_MASK(32);
+		pdev->dev.dma_mask = &pdev->platform_dma_mask;
+	}
 };
 
 /**
@@ -473,7 +474,8 @@
  */
 int platform_device_add(struct platform_device *pdev)
 {
-	int i, ret;
+	u32 i;
+	int ret;
 
 	if (!pdev)
 		return -EINVAL;
@@ -541,7 +543,7 @@
 		pdev->id = PLATFORM_DEVID_AUTO;
 	}
 
-	while (--i >= 0) {
+	while (i--) {
 		struct resource *r = &pdev->resource[i];
 		if (r->parent)
 			release_resource(r);
@@ -562,7 +564,7 @@
  */
 void platform_device_del(struct platform_device *pdev)
 {
-	int i;
+	u32 i;
 
 	if (!IS_ERR_OR_NULL(pdev)) {
 		device_del(&pdev->dev);
@@ -632,20 +634,8 @@
 	pdev->dev.of_node_reused = pdevinfo->of_node_reused;
 
 	if (pdevinfo->dma_mask) {
-		/*
-		 * This memory isn't freed when the device is put,
-		 * I don't have a nice idea for that though.  Conceptually
-		 * dma_mask in struct device should not be a pointer.
-		 * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
-		 */
-		pdev->dev.dma_mask =
-			kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
-		if (!pdev->dev.dma_mask)
-			goto err;
-
-		kmemleak_ignore(pdev->dev.dma_mask);
-
-		*pdev->dev.dma_mask = pdevinfo->dma_mask;
+		pdev->platform_dma_mask = pdevinfo->dma_mask;
+		pdev->dev.dma_mask = &pdev->platform_dma_mask;
 		pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
 	}
 
@@ -670,7 +660,6 @@
 	if (ret) {
 err:
 		ACPI_COMPANION_SET(&pdev->dev, NULL);
-		kfree(pdev->dev.dma_mask);
 		platform_device_put(pdev);
 		return ERR_PTR(ret);
 	}
@@ -813,6 +802,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
@@ -982,31 +973,11 @@
 				     const char *buf, size_t count)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	char *driver_override, *old, *cp;
-
-	/* We need to keep extra room for a newline */
-	if (count >= (PAGE_SIZE - 1))
-		return -EINVAL;
-
-	driver_override = kstrndup(buf, count, GFP_KERNEL);
-	if (!driver_override)
-		return -ENOMEM;
-
-	cp = strchr(driver_override, '\n');
-	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);
+	int ret;
 
-	kfree(old);
+	ret = driver_set_override(dev, &pdev->driver_override, buf, count);
+	if (ret)
+		return ret;
 
 	return count;
 }
@@ -1018,7 +989,7 @@
 	ssize_t len;
 
 	device_lock(dev);
-	len = sprintf(buf, "%s\n", pdev->driver_override);
+	len = sysfs_emit(buf, "%s\n", pdev->driver_override);
 	device_unlock(dev);
 	return len;
 }
@@ -1278,6 +1249,11 @@
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
+static inline int __platform_match(struct device *dev, const void *drv)
+{
+	return platform_match(dev, (struct device_driver *)drv);
+}
+
 /**
  * platform_find_device_by_driver - Find a platform device with a given
  * driver.
@@ -1288,7 +1264,7 @@
 					      const struct device_driver *drv)
 {
 	return bus_find_device(&platform_bus_type, start, drv,
-			       (void *)platform_match);
+			       __platform_match);
 }
 EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
 
--- linux-ein-5.4.0.orig/drivers/base/power/domain.c
+++ linux-ein-5.4.0/drivers/base/power/domain.c
@@ -263,18 +263,18 @@
 	/*
 	 * Traverse all sub-domains within the domain. This can be
 	 * done without any additional locking as the link->performance_state
-	 * field is protected by the master genpd->lock, which is already taken.
+	 * field is protected by the parent genpd->lock, which is already taken.
 	 *
 	 * Also note that link->performance_state (subdomain's performance state
-	 * requirement to master domain) is different from
-	 * link->slave->performance_state (current performance state requirement
+	 * requirement to parent domain) is different from
+	 * link->child->performance_state (current performance state requirement
 	 * of the devices/sub-domains of the subdomain) and so can have a
 	 * different value.
 	 *
 	 * Note that we also take vote from powered-off sub-domains into account
 	 * as the same is done for devices right now.
 	 */
-	list_for_each_entry(link, &genpd->master_links, master_node) {
+	list_for_each_entry(link, &genpd->parent_links, parent_node) {
 		if (link->performance_state > state)
 			state = link->performance_state;
 	}
@@ -285,40 +285,40 @@
 static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
 					unsigned int state, int depth)
 {
-	struct generic_pm_domain *master;
+	struct generic_pm_domain *parent;
 	struct gpd_link *link;
-	int master_state, ret;
+	int parent_state, ret;
 
 	if (state == genpd->performance_state)
 		return 0;
 
-	/* Propagate to masters of genpd */
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		master = link->master;
+	/* Propagate to parents of genpd */
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		parent = link->parent;
 
-		if (!master->set_performance_state)
+		if (!parent->set_performance_state)
 			continue;
 
-		/* Find master's performance state */
+		/* Find parent's performance state */
 		ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
-							 master->opp_table,
+							 parent->opp_table,
 							 state);
 		if (unlikely(ret < 0))
 			goto err;
 
-		master_state = ret;
+		parent_state = ret;
 
-		genpd_lock_nested(master, depth + 1);
+		genpd_lock_nested(parent, depth + 1);
 
 		link->prev_performance_state = link->performance_state;
-		link->performance_state = master_state;
-		master_state = _genpd_reeval_performance_state(master,
-						master_state);
-		ret = _genpd_set_performance_state(master, master_state, depth + 1);
+		link->performance_state = parent_state;
+		parent_state = _genpd_reeval_performance_state(parent,
+						parent_state);
+		ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
 		if (ret)
 			link->performance_state = link->prev_performance_state;
 
-		genpd_unlock(master);
+		genpd_unlock(parent);
 
 		if (ret)
 			goto err;
@@ -333,26 +333,26 @@
 
 err:
 	/* Encountered an error, lets rollback */
-	list_for_each_entry_continue_reverse(link, &genpd->slave_links,
-					     slave_node) {
-		master = link->master;
+	list_for_each_entry_continue_reverse(link, &genpd->child_links,
+					     child_node) {
+		parent = link->parent;
 
-		if (!master->set_performance_state)
+		if (!parent->set_performance_state)
 			continue;
 
-		genpd_lock_nested(master, depth + 1);
+		genpd_lock_nested(parent, depth + 1);
 
-		master_state = link->prev_performance_state;
-		link->performance_state = master_state;
+		parent_state = link->prev_performance_state;
+		link->performance_state = parent_state;
 
-		master_state = _genpd_reeval_performance_state(master,
-						master_state);
-		if (_genpd_set_performance_state(master, master_state, depth + 1)) {
+		parent_state = _genpd_reeval_performance_state(parent,
+						parent_state);
+		if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
 			pr_err("%s: Failed to roll back to %d performance state\n",
-			       master->name, master_state);
+			       parent->name, parent_state);
 		}
 
-		genpd_unlock(master);
+		genpd_unlock(parent);
 	}
 
 	return ret;
@@ -552,7 +552,7 @@
 
 		/*
 		 * If sd_count > 0 at this point, one of the subdomains hasn't
-		 * managed to call genpd_power_on() for the master yet after
+		 * managed to call genpd_power_on() for the parent yet after
 		 * incrementing it.  In that case genpd_power_on() will wait
 		 * for us to drop the lock, so we can call .power_off() and let
 		 * the genpd_power_on() restore power for us (this shouldn't
@@ -566,22 +566,22 @@
 	genpd->status = GPD_STATE_POWER_OFF;
 	genpd_update_accounting(genpd);
 
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		genpd_sd_counter_dec(link->master);
-		genpd_lock_nested(link->master, depth + 1);
-		genpd_power_off(link->master, false, depth + 1);
-		genpd_unlock(link->master);
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		genpd_sd_counter_dec(link->parent);
+		genpd_lock_nested(link->parent, depth + 1);
+		genpd_power_off(link->parent, false, depth + 1);
+		genpd_unlock(link->parent);
 	}
 
 	return 0;
 }
 
 /**
- * genpd_power_on - Restore power to a given PM domain and its masters.
+ * genpd_power_on - Restore power to a given PM domain and its parents.
  * @genpd: PM domain to power up.
  * @depth: nesting count for lockdep.
  *
- * Restore power to @genpd and all of its masters so that it is possible to
+ * Restore power to @genpd and all of its parents so that it is possible to
  * resume a device belonging to it.
  */
 static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
@@ -594,20 +594,20 @@
 
 	/*
 	 * The list is guaranteed not to change while the loop below is being
-	 * executed, unless one of the masters' .power_on() callbacks fiddles
+	 * executed, unless one of the parents' .power_on() callbacks fiddles
 	 * with it.
 	 */
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		struct generic_pm_domain *master = link->master;
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		struct generic_pm_domain *parent = link->parent;
 
-		genpd_sd_counter_inc(master);
+		genpd_sd_counter_inc(parent);
 
-		genpd_lock_nested(master, depth + 1);
-		ret = genpd_power_on(master, depth + 1);
-		genpd_unlock(master);
+		genpd_lock_nested(parent, depth + 1);
+		ret = genpd_power_on(parent, depth + 1);
+		genpd_unlock(parent);
 
 		if (ret) {
-			genpd_sd_counter_dec(master);
+			genpd_sd_counter_dec(parent);
 			goto err;
 		}
 	}
@@ -623,12 +623,12 @@
 
  err:
 	list_for_each_entry_continue_reverse(link,
-					&genpd->slave_links,
-					slave_node) {
-		genpd_sd_counter_dec(link->master);
-		genpd_lock_nested(link->master, depth + 1);
-		genpd_power_off(link->master, false, depth + 1);
-		genpd_unlock(link->master);
+					&genpd->child_links,
+					child_node) {
+		genpd_sd_counter_dec(link->parent);
+		genpd_lock_nested(link->parent, depth + 1);
+		genpd_power_off(link->parent, false, depth + 1);
+		genpd_unlock(link->parent);
 	}
 
 	return ret;
@@ -920,7 +920,7 @@
 
 	return 0;
 }
-late_initcall(genpd_power_off_unused);
+late_initcall_sync(genpd_power_off_unused);
 
 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)
 
@@ -943,13 +943,13 @@
 #ifdef CONFIG_PM_SLEEP
 
 /**
- * genpd_sync_power_off - Synchronously power off a PM domain and its masters.
+ * genpd_sync_power_off - Synchronously power off a PM domain and its parents.
  * @genpd: PM domain to power off, if possible.
  * @use_lock: use the lock.
  * @depth: nesting count for lockdep.
  *
  * Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so.  Also, in that case propagate to its masters.
+ * hibernation) and do that if so.  Also, in that case propagate to its parents.
  *
  * This function is only called in "noirq" and "syscore" stages of system power
  * transitions. The "noirq" callbacks may be executed asynchronously, thus in
@@ -974,21 +974,21 @@
 
 	genpd->status = GPD_STATE_POWER_OFF;
 
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		genpd_sd_counter_dec(link->master);
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		genpd_sd_counter_dec(link->parent);
 
 		if (use_lock)
-			genpd_lock_nested(link->master, depth + 1);
+			genpd_lock_nested(link->parent, depth + 1);
 
-		genpd_sync_power_off(link->master, use_lock, depth + 1);
+		genpd_sync_power_off(link->parent, use_lock, depth + 1);
 
 		if (use_lock)
-			genpd_unlock(link->master);
+			genpd_unlock(link->parent);
 	}
 }
 
 /**
- * genpd_sync_power_on - Synchronously power on a PM domain and its masters.
+ * genpd_sync_power_on - Synchronously power on a PM domain and its parents.
  * @genpd: PM domain to power on.
  * @use_lock: use the lock.
  * @depth: nesting count for lockdep.
@@ -1005,16 +1005,16 @@
 	if (genpd_status_on(genpd))
 		return;
 
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		genpd_sd_counter_inc(link->master);
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		genpd_sd_counter_inc(link->parent);
 
 		if (use_lock)
-			genpd_lock_nested(link->master, depth + 1);
+			genpd_lock_nested(link->parent, depth + 1);
 
-		genpd_sync_power_on(link->master, use_lock, depth + 1);
+		genpd_sync_power_on(link->parent, use_lock, depth + 1);
 
 		if (use_lock)
-			genpd_unlock(link->master);
+			genpd_unlock(link->parent);
 	}
 
 	_genpd_power_on(genpd, false);
@@ -1454,12 +1454,12 @@
 	if (!genpd_is_cpu_domain(genpd))
 		return;
 
-	list_for_each_entry(link, &genpd->slave_links, slave_node) {
-		struct generic_pm_domain *master = link->master;
+	list_for_each_entry(link, &genpd->child_links, child_node) {
+		struct generic_pm_domain *parent = link->parent;
 
-		genpd_lock_nested(master, depth + 1);
-		genpd_update_cpumask(master, cpu, set, depth + 1);
-		genpd_unlock(master);
+		genpd_lock_nested(parent, depth + 1);
+		genpd_update_cpumask(parent, cpu, set, depth + 1);
+		genpd_unlock(parent);
 	}
 
 	if (set)
@@ -1647,17 +1647,17 @@
 		goto out;
 	}
 
-	list_for_each_entry(itr, &genpd->master_links, master_node) {
-		if (itr->slave == subdomain && itr->master == genpd) {
+	list_for_each_entry(itr, &genpd->parent_links, parent_node) {
+		if (itr->child == subdomain && itr->parent == genpd) {
 			ret = -EINVAL;
 			goto out;
 		}
 	}
 
-	link->master = genpd;
-	list_add_tail(&link->master_node, &genpd->master_links);
-	link->slave = subdomain;
-	list_add_tail(&link->slave_node, &subdomain->slave_links);
+	link->parent = genpd;
+	list_add_tail(&link->parent_node, &genpd->parent_links);
+	link->child = subdomain;
+	list_add_tail(&link->child_node, &subdomain->child_links);
 	if (genpd_status_on(subdomain))
 		genpd_sd_counter_inc(genpd);
 
@@ -1671,7 +1671,7 @@
 
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
- * @genpd: Master PM domain to add the subdomain to.
+ * @genpd: Leader PM domain to add the subdomain to.
  * @subdomain: Subdomain to be added.
  */
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
@@ -1689,7 +1689,7 @@
 
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
- * @genpd: Master PM domain to remove the subdomain from.
+ * @genpd: Leader PM domain to remove the subdomain from.
  * @subdomain: Subdomain to be removed.
  */
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
@@ -1704,19 +1704,19 @@
 	genpd_lock(subdomain);
 	genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING);
 
-	if (!list_empty(&subdomain->master_links) || subdomain->device_count) {
+	if (!list_empty(&subdomain->parent_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_safe(link, l, &genpd->master_links, master_node) {
-		if (link->slave != subdomain)
+	list_for_each_entry_safe(link, l, &genpd->parent_links, parent_node) {
+		if (link->child != subdomain)
 			continue;
 
-		list_del(&link->master_node);
-		list_del(&link->slave_node);
+		list_del(&link->parent_node);
+		list_del(&link->child_node);
 		kfree(link);
 		if (genpd_status_on(subdomain))
 			genpd_sd_counter_dec(genpd);
@@ -1781,8 +1781,8 @@
 	if (IS_ERR_OR_NULL(genpd))
 		return -EINVAL;
 
-	INIT_LIST_HEAD(&genpd->master_links);
-	INIT_LIST_HEAD(&genpd->slave_links);
+	INIT_LIST_HEAD(&genpd->parent_links);
+	INIT_LIST_HEAD(&genpd->child_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
 	genpd_lock_init(genpd);
 	genpd->gov = gov;
@@ -1858,15 +1858,15 @@
 		return -EBUSY;
 	}
 
-	if (!list_empty(&genpd->master_links) || genpd->device_count) {
+	if (!list_empty(&genpd->parent_links) || genpd->device_count) {
 		genpd_unlock(genpd);
 		pr_err("%s: unable to remove %s\n", __func__, genpd->name);
 		return -EBUSY;
 	}
 
-	list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) {
-		list_del(&link->master_node);
-		list_del(&link->slave_node);
+	list_for_each_entry_safe(link, l, &genpd->child_links, child_node) {
+		list_del(&link->parent_node);
+		list_del(&link->child_node);
 		kfree(link);
 	}
 
@@ -2596,10 +2596,10 @@
 
 	err = of_property_read_u32(state_node, "min-residency-us", &residency);
 	if (!err)
-		genpd_state->residency_ns = 1000 * residency;
+		genpd_state->residency_ns = 1000LL * residency;
 
-	genpd_state->power_on_latency_ns = 1000 * exit_latency;
-	genpd_state->power_off_latency_ns = 1000 * entry_latency;
+	genpd_state->power_on_latency_ns = 1000LL * exit_latency;
+	genpd_state->power_off_latency_ns = 1000LL * entry_latency;
 	genpd_state->fwnode = &state_node->fwnode;
 
 	return 0;
@@ -2615,13 +2615,17 @@
 
 	ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL);
 	if (ret <= 0)
-		return ret;
+		return ret == -ENOENT ? 0 : ret;
 
 	/* Loop over the phandles until all the requested entry is found */
 	of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) {
 		np = it.node;
 		if (!of_match_node(idle_state_match, np))
 			continue;
+
+		if (!of_device_is_available(np))
+			continue;
+
 		if (states) {
 			ret = genpd_parse_state(&states[i], np);
 			if (ret) {
@@ -2789,12 +2793,12 @@
 
 	/*
 	 * Modifications on the list require holding locks on both
-	 * master and slave, so we are safe.
+	 * parent and child, so we are safe.
 	 * Also genpd->name is immutable.
 	 */
-	list_for_each_entry(link, &genpd->master_links, master_node) {
-		seq_printf(s, "%s", link->slave->name);
-		if (!list_is_last(&link->master_node, &genpd->master_links))
+	list_for_each_entry(link, &genpd->parent_links, parent_node) {
+		seq_printf(s, "%s", link->child->name);
+		if (!list_is_last(&link->parent_node, &genpd->parent_links))
 			seq_puts(s, ", ");
 	}
 
@@ -2822,7 +2826,7 @@
 	struct generic_pm_domain *genpd;
 	int ret = 0;
 
-	seq_puts(s, "domain                          status          slaves\n");
+	seq_puts(s, "domain                          status          children\n");
 	seq_puts(s, "    /device                                             runtime status\n");
 	seq_puts(s, "----------------------------------------------------------------------\n");
 
@@ -2877,8 +2881,8 @@
 	if (ret)
 		return -ERESTARTSYS;
 
-	list_for_each_entry(link, &genpd->master_links, master_node)
-		seq_printf(s, "%s\n", link->slave->name);
+	list_for_each_entry(link, &genpd->parent_links, parent_node)
+		seq_printf(s, "%s\n", link->child->name);
 
 	genpd_unlock(genpd);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/base/power/domain_governor.c
+++ linux-ein-5.4.0/drivers/base/power/domain_governor.c
@@ -135,8 +135,8 @@
 	 *
 	 * All subdomains have been powered off already at this point.
 	 */
-	list_for_each_entry(link, &genpd->master_links, master_node) {
-		struct generic_pm_domain *sd = link->slave;
+	list_for_each_entry(link, &genpd->parent_links, parent_node) {
+		struct generic_pm_domain *sd = link->child;
 		s64 sd_max_off_ns = sd->max_off_time_ns;
 
 		if (sd_max_off_ns < 0)
@@ -217,13 +217,13 @@
 	}
 
 	/*
-	 * We have to invalidate the cached results for the masters, so
+	 * We have to invalidate the cached results for the parents, so
 	 * use the observation that default_power_down_ok() is not
-	 * going to be called for any master until this instance
+	 * going to be called for any parent until this instance
 	 * returns.
 	 */
-	list_for_each_entry(link, &genpd->slave_links, slave_node)
-		link->master->max_off_time_changed = true;
+	list_for_each_entry(link, &genpd->child_links, child_node)
+		link->parent->max_off_time_changed = true;
 
 	genpd->max_off_time_ns = -1;
 	genpd->max_off_time_changed = false;
--- linux-ein-5.4.0.orig/drivers/base/power/main.c
+++ linux-ein-5.4.0/drivers/base/power/main.c
@@ -273,10 +273,38 @@
 	device_links_read_unlock(idx);
 }
 
-static void dpm_wait_for_superior(struct device *dev, bool async)
+static bool dpm_wait_for_superior(struct device *dev, bool async)
 {
-	dpm_wait(dev->parent, async);
+	struct device *parent;
+
+	/*
+	 * If the device is resumed asynchronously and the parent's callback
+	 * deletes both the device and the parent itself, the parent object may
+	 * be freed while this function is running, so avoid that by reference
+	 * counting the parent once more unless the device has been deleted
+	 * already (in which case return right away).
+	 */
+	mutex_lock(&dpm_list_mtx);
+
+	if (!device_pm_initialized(dev)) {
+		mutex_unlock(&dpm_list_mtx);
+		return false;
+	}
+
+	parent = get_device(dev->parent);
+
+	mutex_unlock(&dpm_list_mtx);
+
+	dpm_wait(parent, async);
+	put_device(parent);
+
 	dpm_wait_for_suppliers(dev, async);
+
+	/*
+	 * If the parent's callback has deleted the device, attempting to resume
+	 * it would be invalid, so avoid doing that then.
+	 */
+	return device_pm_initialized(dev);
 }
 
 static void dpm_wait_for_consumers(struct device *dev, bool async)
@@ -621,7 +649,8 @@
 	if (!dev->power.is_noirq_suspended)
 		goto Out;
 
-	dpm_wait_for_superior(dev, async);
+	if (!dpm_wait_for_superior(dev, async))
+		goto Out;
 
 	skip_resume = dev_pm_may_skip_resume(dev);
 
@@ -697,7 +726,7 @@
 
 	if (is_async(dev)) {
 		get_device(dev);
-		async_schedule(func, dev);
+		async_schedule_dev(func, dev);
 		return true;
 	}
 
@@ -829,7 +858,8 @@
 	if (!dev->power.is_late_suspended)
 		goto Out;
 
-	dpm_wait_for_superior(dev, async);
+	if (!dpm_wait_for_superior(dev, async))
+		goto Out;
 
 	callback = dpm_subsys_resume_early_cb(dev, state, &info);
 
@@ -944,7 +974,9 @@
 		goto Complete;
 	}
 
-	dpm_wait_for_superior(dev, async);
+	if (!dpm_wait_for_superior(dev, async))
+		goto Complete;
+
 	dpm_watchdog_set(&wd, dev);
 	device_lock(dev);
 
@@ -1696,13 +1728,17 @@
 	}
 
 	/*
-	 * 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;
@@ -2085,7 +2121,9 @@
 
 void device_pm_check_callbacks(struct device *dev)
 {
-	spin_lock_irq(&dev->power.lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->power.lock, flags);
 	dev->power.no_pm_callbacks =
 		(!dev->bus || (pm_ops_is_empty(dev->bus->pm) &&
 		 !dev->bus->suspend && !dev->bus->resume)) &&
@@ -2094,7 +2132,7 @@
 		(!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) &&
 		(!dev->driver || (pm_ops_is_empty(dev->driver->pm) &&
 		 !dev->driver->suspend && !dev->driver->resume));
-	spin_unlock_irq(&dev->power.lock);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
 }
 
 bool dev_pm_smart_suspend_and_suspended(struct device *dev)
--- linux-ein-5.4.0.orig/drivers/base/power/power.h
+++ linux-ein-5.4.0/drivers/base/power/power.h
@@ -25,8 +25,11 @@
 
 #define WAKE_IRQ_DEDICATED_ALLOCATED	BIT(0)
 #define WAKE_IRQ_DEDICATED_MANAGED	BIT(1)
+#define WAKE_IRQ_DEDICATED_REVERSE	BIT(2)
 #define WAKE_IRQ_DEDICATED_MASK		(WAKE_IRQ_DEDICATED_ALLOCATED | \
-					 WAKE_IRQ_DEDICATED_MANAGED)
+					 WAKE_IRQ_DEDICATED_MANAGED | \
+					 WAKE_IRQ_DEDICATED_REVERSE)
+#define WAKE_IRQ_DEDICATED_ENABLED	BIT(3)
 
 struct wake_irq {
 	struct device *dev;
@@ -39,7 +42,8 @@
 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);
+extern void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable);
+extern void dev_pm_enable_wake_irq_complete(struct device *dev);
 
 #ifdef CONFIG_PM_SLEEP
 
@@ -74,6 +78,7 @@
 extern void pm_qos_sysfs_remove_flags(struct device *dev);
 extern int pm_qos_sysfs_add_latency_tolerance(struct device *dev);
 extern void pm_qos_sysfs_remove_latency_tolerance(struct device *dev);
+extern int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid);
 
 #else /* CONFIG_PM */
 
@@ -88,6 +93,8 @@
 
 static inline int dpm_sysfs_add(struct device *dev) { return 0; }
 static inline void dpm_sysfs_remove(struct device *dev) {}
+static inline int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid,
+					 kgid_t kgid) { return 0; }
 
 #endif
 
--- linux-ein-5.4.0.orig/drivers/base/power/runtime.c
+++ linux-ein-5.4.0/drivers/base/power/runtime.c
@@ -291,8 +291,7 @@
 				device_links_read_lock_held()) {
 		int retval;
 
-		if (!(link->flags & DL_FLAG_PM_RUNTIME) ||
-		    READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND)
+		if (!(link->flags & DL_FLAG_PM_RUNTIME))
 			continue;
 
 		retval = pm_runtime_get_sync(link->supplier);
@@ -306,20 +305,38 @@
 	return 0;
 }
 
-static void rpm_put_suppliers(struct device *dev)
+static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
 {
 	struct device_link *link;
 
 	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
 				device_links_read_lock_held()) {
-		if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND)
-			continue;
 
 		while (refcount_dec_not_one(&link->rpm_active))
-			pm_runtime_put(link->supplier);
+			pm_runtime_put_noidle(link->supplier);
+
+		if (try_to_suspend)
+			pm_request_idle(link->supplier);
 	}
 }
 
+static void rpm_put_suppliers(struct device *dev)
+{
+	__rpm_put_suppliers(dev, true);
+}
+
+static void rpm_suspend_suppliers(struct device *dev)
+{
+	struct device_link *link;
+	int idx = device_links_read_lock();
+
+	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
+				device_links_read_lock_held())
+		pm_request_idle(link->supplier);
+
+	device_links_read_unlock(idx);
+}
+
 /**
  * __rpm_callback - Run a given runtime PM callback for a given device.
  * @cb: Runtime PM callback to run.
@@ -347,8 +364,10 @@
 			idx = device_links_read_lock();
 
 			retval = rpm_get_suppliers(dev);
-			if (retval)
+			if (retval) {
+				rpm_put_suppliers(dev);
 				goto fail;
+			}
 
 			device_links_read_unlock(idx);
 		}
@@ -371,9 +390,9 @@
 		    || (dev->power.runtime_status == RPM_RESUMING && retval))) {
 			idx = device_links_read_lock();
 
- fail:
-			rpm_put_suppliers(dev);
+			__rpm_put_suppliers(dev, false);
 
+fail:
 			device_links_read_unlock(idx);
 		}
 
@@ -427,7 +446,10 @@
 	/* Pending requests need to be canceled. */
 	dev->power.request = RPM_REQ_NONE;
 
-	if (dev->power.no_callbacks)
+	callback = RPM_GET_CALLBACK(dev, runtime_idle);
+
+	/* If no callback assume success. */
+	if (!callback || dev->power.no_callbacks)
 		goto out;
 
 	/* Carry out an asynchronous or a synchronous idle notification. */
@@ -443,10 +465,17 @@
 
 	dev->power.idle_notification = true;
 
-	callback = RPM_GET_CALLBACK(dev, runtime_idle);
+	if (dev->power.irq_safe)
+		spin_unlock(&dev->power.lock);
+	else
+		spin_unlock_irq(&dev->power.lock);
 
-	if (callback)
-		retval = __rpm_callback(callback, dev);
+	retval = callback(dev);
+
+	if (dev->power.irq_safe)
+		spin_lock(&dev->power.lock);
+	else
+		spin_lock_irq(&dev->power.lock);
 
 	dev->power.idle_notification = false;
 	wake_up_all(&dev->power.wait_queue);
@@ -630,6 +659,8 @@
 	if (retval)
 		goto fail;
 
+	dev_pm_enable_wake_irq_complete(dev);
+
  no_callback:
 	__update_runtime_status(dev, RPM_SUSPENDED);
 	pm_runtime_deactivate_timer(dev);
@@ -647,8 +678,11 @@
 		goto out;
 	}
 
+	if (dev->power.irq_safe)
+		goto out;
+
 	/* Maybe the parent is now able to suspend. */
-	if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
+	if (parent && !parent->power.ignore_children) {
 		spin_unlock(&dev->power.lock);
 
 		spin_lock(&parent->power.lock);
@@ -657,6 +691,14 @@
 
 		spin_lock(&dev->power.lock);
 	}
+	/* Maybe the suppliers are now able to suspend. */
+	if (dev->power.links_count > 0) {
+		spin_unlock_irq(&dev->power.lock);
+
+		rpm_suspend_suppliers(dev);
+
+		spin_lock_irq(&dev->power.lock);
+	}
 
  out:
 	trace_rpm_return_int_rcuidle(dev, _THIS_IP_, retval);
@@ -664,7 +706,7 @@
 	return retval;
 
  fail:
-	dev_pm_disable_wake_irq_check(dev);
+	dev_pm_disable_wake_irq_check(dev, true);
 	__update_runtime_status(dev, RPM_ACTIVE);
 	dev->power.deferred_resume = false;
 	wake_up_all(&dev->power.wait_queue);
@@ -847,7 +889,7 @@
 
 	callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
-	dev_pm_disable_wake_irq_check(dev);
+	dev_pm_disable_wake_irq_check(dev, false);
 	retval = rpm_callback(callback, dev);
 	if (retval) {
 		__update_runtime_status(dev, RPM_SUSPENDED);
@@ -1006,8 +1048,10 @@
 	int retval;
 
 	if (rpmflags & RPM_GET_PUT) {
-		if (!atomic_dec_and_test(&dev->power.usage_count))
+		if (!atomic_dec_and_test(&dev->power.usage_count)) {
+			trace_rpm_usage_rcuidle(dev, rpmflags);
 			return 0;
+		}
 	}
 
 	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
@@ -1038,8 +1082,10 @@
 	int retval;
 
 	if (rpmflags & RPM_GET_PUT) {
-		if (!atomic_dec_and_test(&dev->power.usage_count))
+		if (!atomic_dec_and_test(&dev->power.usage_count)) {
+			trace_rpm_usage_rcuidle(dev, rpmflags);
 			return 0;
+		}
 	}
 
 	might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
@@ -1083,28 +1129,47 @@
 EXPORT_SYMBOL_GPL(__pm_runtime_resume);
 
 /**
- * pm_runtime_get_if_in_use - Conditionally bump up the device's usage counter.
+ * pm_runtime_get_if_active - 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.
+ * Otherwise, if the device's runtime PM status is RPM_ACTIVE and either
+ * ign_usage_count is true or the device's usage_count is non-zero, increment
+ * the counter and return 1. Otherwise return 0 without changing the counter.
+ *
+ * If ign_usage_count is true, the function can be used to prevent suspending
+ * the device when its runtime PM status is RPM_ACTIVE.
+ *
+ * If ign_usage_count is false, the function can be used to prevent suspending
+ * the device when both its runtime PM status is RPM_ACTIVE and its usage_count
+ * is non-zero.
+ *
+ * The caller is resposible for putting the device's usage count when ther
+ * return value is greater than zero.
  */
-int pm_runtime_get_if_in_use(struct device *dev)
+int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count)
 {
 	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);
+	if (dev->power.disable_depth > 0) {
+		retval = -EINVAL;
+	} else if (dev->power.runtime_status != RPM_ACTIVE) {
+		retval = 0;
+	} else if (ign_usage_count) {
+		retval = 1;
+		atomic_inc(&dev->power.usage_count);
+	} else {
+		retval = atomic_inc_not_zero(&dev->power.usage_count);
+	}
+	trace_rpm_usage_rcuidle(dev, 0);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
+
 	return retval;
 }
-EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
+EXPORT_SYMBOL_GPL(pm_runtime_get_if_active);
 
 /**
  * __pm_runtime_set_status - Set runtime PM status of a device.
@@ -1396,6 +1461,28 @@
 }
 EXPORT_SYMBOL_GPL(pm_runtime_enable);
 
+static void pm_runtime_disable_action(void *data)
+{
+	pm_runtime_dont_use_autosuspend(data);
+	pm_runtime_disable(data);
+}
+
+/**
+ * devm_pm_runtime_enable - devres-enabled version of pm_runtime_enable.
+ *
+ * NOTE: this will also handle calling pm_runtime_dont_use_autosuspend() for
+ * you at driver exit time if needed.
+ *
+ * @dev: Device to handle.
+ */
+int devm_pm_runtime_enable(struct device *dev)
+{
+	pm_runtime_enable(dev);
+
+	return devm_add_action_or_reset(dev, pm_runtime_disable_action, dev);
+}
+EXPORT_SYMBOL_GPL(devm_pm_runtime_enable);
+
 /**
  * pm_runtime_forbid - Block runtime PM of a device.
  * @dev: Device to handle.
@@ -1434,6 +1521,8 @@
 	dev->power.runtime_auto = true;
 	if (atomic_dec_and_test(&dev->power.usage_count))
 		rpm_idle(dev, RPM_AUTO | RPM_ASYNC);
+	else
+		trace_rpm_usage_rcuidle(dev, RPM_AUTO | RPM_ASYNC);
 
  out:
 	spin_unlock_irq(&dev->power.lock);
@@ -1501,6 +1590,8 @@
 		if (!old_use || old_delay >= 0) {
 			atomic_inc(&dev->power.usage_count);
 			rpm_resume(dev, 0);
+		} else {
+			trace_rpm_usage_rcuidle(dev, 0);
 		}
 	}
 
@@ -1580,6 +1671,7 @@
 	dev->power.request_pending = false;
 	dev->power.request = RPM_REQ_NONE;
 	dev->power.deferred_resume = false;
+	dev->power.needs_force_resume = 0;
 	INIT_WORK(&dev->power.work, pm_runtime_work);
 
 	dev->power.timer_expires = 0;
@@ -1619,42 +1711,6 @@
 }
 
 /**
- * pm_runtime_clean_up_links - Prepare links to consumers for driver removal.
- * @dev: Device whose driver is going to be removed.
- *
- * Check links from this device to any consumers and if any of them have active
- * runtime PM references to the device, drop the usage counter of the device
- * (as many times as needed).
- *
- * Links with the DL_FLAG_MANAGED flag unset are ignored.
- *
- * Since the device is guaranteed to be runtime-active at the point this is
- * called, nothing else needs to be done here.
- *
- * Moreover, this is called after device_links_busy() has returned 'false', so
- * the status of each link is guaranteed to be DL_STATE_SUPPLIER_UNBIND and
- * therefore rpm_active can't be manipulated concurrently.
- */
-void pm_runtime_clean_up_links(struct device *dev)
-{
-	struct device_link *link;
-	int idx;
-
-	idx = device_links_read_lock();
-
-	list_for_each_entry_rcu(link, &dev->links.consumers, s_node,
-				device_links_read_lock_held()) {
-		if (!(link->flags & DL_FLAG_MANAGED))
-			continue;
-
-		while (refcount_dec_not_one(&link->rpm_active))
-			pm_runtime_put_noidle(dev);
-	}
-
-	device_links_read_unlock(idx);
-}
-
-/**
  * pm_runtime_get_suppliers - Resume and reference-count supplier devices.
  * @dev: Consumer device.
  */
@@ -1669,8 +1725,8 @@
 				device_links_read_lock_held())
 		if (link->flags & DL_FLAG_PM_RUNTIME) {
 			link->supplier_preactivated = true;
-			refcount_inc(&link->rpm_active);
 			pm_runtime_get_sync(link->supplier);
+			refcount_inc(&link->rpm_active);
 		}
 
 	device_links_read_unlock(idx);
@@ -1683,6 +1739,8 @@
 void pm_runtime_put_suppliers(struct device *dev)
 {
 	struct device_link *link;
+	unsigned long flags;
+	bool put;
 	int idx;
 
 	idx = device_links_read_lock();
@@ -1691,7 +1749,11 @@
 				device_links_read_lock_held())
 		if (link->supplier_preactivated) {
 			link->supplier_preactivated = false;
-			if (refcount_dec_not_one(&link->rpm_active))
+			spin_lock_irqsave(&dev->power.lock, flags);
+			put = pm_runtime_status_suspended(dev) &&
+			      refcount_dec_not_one(&link->rpm_active);
+			spin_unlock_irqrestore(&dev->power.lock, flags);
+			if (put)
 				pm_runtime_put(link->supplier);
 		}
 
@@ -1705,7 +1767,7 @@
 	spin_unlock_irq(&dev->power.lock);
 }
 
-void pm_runtime_drop_link(struct device *dev)
+static void pm_runtime_drop_link_count(struct device *dev)
 {
 	spin_lock_irq(&dev->power.lock);
 	WARN_ON(dev->power.links_count == 0);
@@ -1713,6 +1775,25 @@
 	spin_unlock_irq(&dev->power.lock);
 }
 
+/**
+ * pm_runtime_drop_link - Prepare for device link removal.
+ * @link: Device link going away.
+ *
+ * Drop the link count of the consumer end of @link and decrement the supplier
+ * device's runtime PM usage counter as many times as needed to drop all of the
+ * PM runtime reference to it from the consumer.
+ */
+void pm_runtime_drop_link(struct device_link *link)
+{
+	if (!(link->flags & DL_FLAG_PM_RUNTIME))
+		return;
+
+	pm_runtime_drop_link_count(link->consumer);
+
+	while (refcount_dec_not_one(&link->rpm_active))
+		pm_runtime_put(link->supplier);
+}
+
 static bool pm_runtime_need_not_resume(struct device *dev)
 {
 	return atomic_read(&dev->power.usage_count) <= 1 &&
@@ -1758,10 +1839,12 @@
 	 * its parent, but set its status to RPM_SUSPENDED anyway in case this
 	 * function will be called again for it in the meantime.
 	 */
-	if (pm_runtime_need_not_resume(dev))
+	if (pm_runtime_need_not_resume(dev)) {
 		pm_runtime_set_suspended(dev);
-	else
+	} else {
 		__update_runtime_status(dev, RPM_SUSPENDED);
+		dev->power.needs_force_resume = 1;
+	}
 
 	return 0;
 
@@ -1788,7 +1871,7 @@
 	int (*callback)(struct device *);
 	int ret = 0;
 
-	if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev))
+	if (!pm_runtime_status_suspended(dev) || !dev->power.needs_force_resume)
 		goto out;
 
 	/*
@@ -1807,6 +1890,7 @@
 
 	pm_runtime_mark_last_busy(dev);
 out:
+	dev->power.needs_force_resume = 0;
 	pm_runtime_enable(dev);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/base/power/sysfs.c
+++ linux-ein-5.4.0/drivers/base/power/sysfs.c
@@ -100,7 +100,7 @@
 static ssize_t control_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
-	return sprintf(buf, "%s\n",
+	return sysfs_emit(buf, "%s\n",
 				dev->power.runtime_auto ? ctrl_auto : ctrl_on);
 }
 
@@ -126,7 +126,7 @@
 	int ret;
 	u64 tmp = pm_runtime_active_time(dev);
 	do_div(tmp, NSEC_PER_MSEC);
-	ret = sprintf(buf, "%llu\n", tmp);
+	ret = sysfs_emit(buf, "%llu\n", tmp);
 	return ret;
 }
 
@@ -138,7 +138,7 @@
 	int ret;
 	u64 tmp = pm_runtime_suspended_time(dev);
 	do_div(tmp, NSEC_PER_MSEC);
-	ret = sprintf(buf, "%llu\n", tmp);
+	ret = sysfs_emit(buf, "%llu\n", tmp);
 	return ret;
 }
 
@@ -171,7 +171,7 @@
 			return -EIO;
 		}
 	}
-	return sprintf(buf, p);
+	return sysfs_emit(buf, p);
 }
 
 static DEVICE_ATTR_RO(runtime_status);
@@ -181,7 +181,7 @@
 {
 	if (!dev->power.use_autosuspend)
 		return -EIO;
-	return sprintf(buf, "%d\n", dev->power.autosuspend_delay);
+	return sysfs_emit(buf, "%d\n", dev->power.autosuspend_delay);
 }
 
 static ssize_t autosuspend_delay_ms_store(struct device *dev,
@@ -210,11 +210,11 @@
 	s32 value = dev_pm_qos_requested_resume_latency(dev);
 
 	if (value == 0)
-		return sprintf(buf, "n/a\n");
+		return sysfs_emit(buf, "n/a\n");
 	if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
 		value = 0;
 
-	return sprintf(buf, "%d\n", value);
+	return sysfs_emit(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_us_store(struct device *dev,
@@ -254,11 +254,11 @@
 	s32 value = dev_pm_qos_get_user_latency_tolerance(dev);
 
 	if (value < 0)
-		return sprintf(buf, "auto\n");
+		return sysfs_emit(buf, "auto\n");
 	if (value == PM_QOS_LATENCY_ANY)
-		return sprintf(buf, "any\n");
+		return sysfs_emit(buf, "any\n");
 
-	return sprintf(buf, "%d\n", value);
+	return sysfs_emit(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_latency_tolerance_us_store(struct device *dev,
@@ -290,8 +290,8 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
-					& PM_QOS_FLAG_NO_POWER_OFF));
+	return sysfs_emit(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
+					  & PM_QOS_FLAG_NO_POWER_OFF));
 }
 
 static ssize_t pm_qos_no_power_off_store(struct device *dev,
@@ -319,9 +319,9 @@
 static ssize_t wakeup_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
-	return sprintf(buf, "%s\n", device_can_wakeup(dev)
-		? (device_may_wakeup(dev) ? _enabled : _disabled)
-		: "");
+	return sysfs_emit(buf, "%s\n", device_can_wakeup(dev)
+			  ? (device_may_wakeup(dev) ? _enabled : _disabled)
+			  : "");
 }
 
 static ssize_t wakeup_store(struct device *dev, struct device_attribute *attr,
@@ -480,6 +480,14 @@
 	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
 }
 
+static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid,
+						kgid_t kgid)
+{
+	if (dev->power.wakeup && dev->power.wakeup->dev)
+		return device_change_owner(dev->power.wakeup->dev, kuid, kgid);
+	return 0;
+}
+
 static DEVICE_ATTR_RO(wakeup_last_time_ms);
 
 #ifdef CONFIG_PM_AUTOSLEEP
@@ -501,13 +509,19 @@
 
 static DEVICE_ATTR_RO(wakeup_prevent_sleep_time_ms);
 #endif /* CONFIG_PM_AUTOSLEEP */
-#endif /* CONFIG_PM_SLEEP */
+#else /* CONFIG_PM_SLEEP */
+static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid,
+						kgid_t kgid)
+{
+	return 0;
+}
+#endif
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 static ssize_t runtime_usage_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", atomic_read(&dev->power.usage_count));
+	return sysfs_emit(buf, "%d\n", atomic_read(&dev->power.usage_count));
 }
 static DEVICE_ATTR_RO(runtime_usage);
 
@@ -515,8 +529,8 @@
 					struct device_attribute *attr,
 					char *buf)
 {
-	return sprintf(buf, "%d\n", dev->power.ignore_children ?
-		0 : atomic_read(&dev->power.child_count));
+	return sysfs_emit(buf, "%d\n", dev->power.ignore_children ?
+			  0 : atomic_read(&dev->power.child_count));
 }
 static DEVICE_ATTR_RO(runtime_active_kids);
 
@@ -524,12 +538,12 @@
 				    struct device_attribute *attr, char *buf)
 {
 	if (dev->power.disable_depth && (dev->power.runtime_auto == false))
-		return sprintf(buf, "disabled & forbidden\n");
+		return sysfs_emit(buf, "disabled & forbidden\n");
 	if (dev->power.disable_depth)
-		return sprintf(buf, "disabled\n");
+		return sysfs_emit(buf, "disabled\n");
 	if (dev->power.runtime_auto == false)
-		return sprintf(buf, "forbidden\n");
-	return sprintf(buf, "enabled\n");
+		return sysfs_emit(buf, "forbidden\n");
+	return sysfs_emit(buf, "enabled\n");
 }
 static DEVICE_ATTR_RO(runtime_enabled);
 
@@ -537,9 +551,9 @@
 static ssize_t async_show(struct device *dev, struct device_attribute *attr,
 			  char *buf)
 {
-	return sprintf(buf, "%s\n",
-			device_async_suspend_enabled(dev) ?
-				_enabled : _disabled);
+	return sysfs_emit(buf, "%s\n",
+			  device_async_suspend_enabled(dev) ?
+			  _enabled : _disabled);
 }
 
 static ssize_t async_store(struct device *dev, struct device_attribute *attr,
@@ -684,6 +698,45 @@
 	return rc;
 }
 
+int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
+{
+	int rc;
+
+	if (device_pm_not_required(dev))
+		return 0;
+
+	rc = sysfs_group_change_owner(&dev->kobj, &pm_attr_group, kuid, kgid);
+	if (rc)
+		return rc;
+
+	if (pm_runtime_callbacks_present(dev)) {
+		rc = sysfs_group_change_owner(
+			&dev->kobj, &pm_runtime_attr_group, kuid, kgid);
+		if (rc)
+			return rc;
+	}
+
+	if (device_can_wakeup(dev)) {
+		rc = sysfs_group_change_owner(&dev->kobj, &pm_wakeup_attr_group,
+					      kuid, kgid);
+		if (rc)
+			return rc;
+
+		rc = dpm_sysfs_wakeup_change_owner(dev, kuid, kgid);
+		if (rc)
+			return rc;
+	}
+
+	if (dev->power.set_latency_tolerance) {
+		rc = sysfs_group_change_owner(
+			&dev->kobj, &pm_qos_latency_tolerance_attr_group, kuid,
+			kgid);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
 int wakeup_sysfs_add(struct device *dev)
 {
 	return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
--- linux-ein-5.4.0.orig/drivers/base/power/trace.c
+++ linux-ein-5.4.0/drivers/base/power/trace.c
@@ -13,6 +13,7 @@
 #include <linux/export.h>
 #include <linux/rtc.h>
 #include <linux/suspend.h>
+#include <linux/init.h>
 
 #include <linux/mc146818rtc.h>
 
@@ -165,6 +166,9 @@
 	const char *file = *(const char **)(tracedata + 2);
 	unsigned int user_hash_value, file_hash_value;
 
+	if (!x86_platform.legacy.rtc)
+		return;
+
 	user_hash_value = user % USERHASH;
 	file_hash_value = hash_string(lineno, file, FILEHASH);
 	set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
@@ -267,6 +271,9 @@
 
 static int early_resume_init(void)
 {
+	if (!x86_platform.legacy.rtc)
+		return 0;
+
 	hash_value_early_read = read_magic_time();
 	register_pm_notifier(&pm_trace_nb);
 	return 0;
@@ -277,6 +284,9 @@
 	unsigned int val = hash_value_early_read;
 	unsigned int user, file, dev;
 
+	if (!x86_platform.legacy.rtc)
+		return 0;
+
 	user = val % USERHASH;
 	val = val / USERHASH;
 	file = val % FILEHASH;
--- linux-ein-5.4.0.orig/drivers/base/power/wakeirq.c
+++ linux-ein-5.4.0/drivers/base/power/wakeirq.c
@@ -145,24 +145,7 @@
 	return IRQ_HANDLED;
 }
 
-/**
- * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
- * @dev: Device entry
- * @irq: Device wake-up interrupt
- *
- * Unless your hardware has separate wake-up interrupts in addition
- * to the device IO interrupts, you don't need this.
- *
- * Sets up a threaded interrupt handler for a device that has
- * a dedicated wake-up interrupt in addition to the device IO
- * interrupt.
- *
- * The interrupt starts disabled, and needs to be managed for
- * the device by the bus code or the device driver using
- * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
- * functions.
- */
-int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
+static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag)
 {
 	struct wake_irq *wirq;
 	int err;
@@ -200,7 +183,7 @@
 	if (err)
 		goto err_free_irq;
 
-	wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED;
+	wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED | flag;
 
 	return err;
 
@@ -213,9 +196,58 @@
 
 	return err;
 }
+
+
+/**
+ * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
+ * @dev: Device entry
+ * @irq: Device wake-up interrupt
+ *
+ * Unless your hardware has separate wake-up interrupts in addition
+ * to the device IO interrupts, you don't need this.
+ *
+ * Sets up a threaded interrupt handler for a device that has
+ * a dedicated wake-up interrupt in addition to the device IO
+ * interrupt.
+ *
+ * The interrupt starts disabled, and needs to be managed for
+ * the device by the bus code or the device driver using
+ * dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*()
+ * functions.
+ */
+int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
+{
+	return __dev_pm_set_dedicated_wake_irq(dev, irq, 0);
+}
 EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
 
 /**
+ * dev_pm_set_dedicated_wake_irq_reverse - Request a dedicated wake-up interrupt
+ *                                         with reverse enable ordering
+ * @dev: Device entry
+ * @irq: Device wake-up interrupt
+ *
+ * Unless your hardware has separate wake-up interrupts in addition
+ * to the device IO interrupts, you don't need this.
+ *
+ * Sets up a threaded interrupt handler for a device that has a dedicated
+ * wake-up interrupt in addition to the device IO interrupt. It sets
+ * the status of WAKE_IRQ_DEDICATED_REVERSE to tell rpm_suspend()
+ * to enable dedicated wake-up interrupt after running the runtime suspend
+ * callback for @dev.
+ *
+ * The interrupt starts disabled, and needs to be managed for
+ * the device by the bus code or the device driver using
+ * dev_pm_enable_wake_irq*() and dev_pm_disable_wake_irq*()
+ * functions.
+ */
+int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
+{
+	return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE);
+}
+EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_reverse);
+
+/**
  * dev_pm_enable_wake_irq - Enable device wake-up interrupt
  * @dev: Device
  *
@@ -285,25 +317,56 @@
 	return;
 
 enable:
-	enable_irq(wirq->irq);
+	if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) {
+		enable_irq(wirq->irq);
+		wirq->status |= WAKE_IRQ_DEDICATED_ENABLED;
+	}
 }
 
 /**
  * dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
  * @dev: Device
+ * @cond_disable: if set, also check WAKE_IRQ_DEDICATED_REVERSE
  *
  * 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)
+void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable)
 {
 	struct wake_irq *wirq = dev->power.wakeirq;
 
 	if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
 		return;
 
-	if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED)
+	if (cond_disable && (wirq->status & WAKE_IRQ_DEDICATED_REVERSE))
+		return;
+
+	if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED) {
+		wirq->status &= ~WAKE_IRQ_DEDICATED_ENABLED;
 		disable_irq_nosync(wirq->irq);
+	}
+}
+
+/**
+ * dev_pm_enable_wake_irq_complete - enable wake IRQ not enabled before
+ * @dev: Device using the wake IRQ
+ *
+ * Enable wake IRQ conditionally based on status, mainly used if want to
+ * enable wake IRQ after running ->runtime_suspend() which depends on
+ * WAKE_IRQ_DEDICATED_REVERSE.
+ *
+ * Should be only called from rpm_suspend() path.
+ */
+void dev_pm_enable_wake_irq_complete(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 &&
+	    wirq->status & WAKE_IRQ_DEDICATED_REVERSE)
+		enable_irq(wirq->irq);
 }
 
 /**
@@ -320,7 +383,7 @@
 
 	if (device_may_wakeup(wirq->dev)) {
 		if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
-		    !pm_runtime_status_suspended(wirq->dev))
+		    !(wirq->status & WAKE_IRQ_DEDICATED_ENABLED))
 			enable_irq(wirq->irq);
 
 		enable_irq_wake(wirq->irq);
@@ -343,7 +406,7 @@
 		disable_irq_wake(wirq->irq);
 
 		if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
-		    !pm_runtime_status_suspended(wirq->dev))
+		    !(wirq->status & WAKE_IRQ_DEDICATED_ENABLED))
 			disable_irq_nosync(wirq->irq);
 	}
 }
--- linux-ein-5.4.0.orig/drivers/base/power/wakeup.c
+++ linux-ein-5.4.0/drivers/base/power/wakeup.c
@@ -31,7 +31,8 @@
 bool events_check_enabled __read_mostly;
 
 /* First wakeup IRQ seen by the kernel in the last cycle. */
-unsigned int pm_wakeup_irq __read_mostly;
+static unsigned int wakeup_irq[2] __read_mostly;
+static DEFINE_RAW_SPINLOCK(wakeup_irq_lock);
 
 /* If greater than 0 and the system is suspending, terminate the suspend. */
 static atomic_t pm_abort_suspend __read_mostly;
@@ -241,7 +242,9 @@
 {
 	if (ws) {
 		wakeup_source_remove(ws);
-		wakeup_source_sysfs_remove(ws);
+		if (ws->dev)
+			wakeup_source_sysfs_remove(ws);
+
 		wakeup_source_destroy(ws);
 	}
 }
@@ -882,19 +885,45 @@
 	atomic_dec_if_positive(&pm_abort_suspend);
 }
 
-void pm_wakeup_clear(bool reset)
+void pm_wakeup_clear(unsigned int irq_number)
 {
-	pm_wakeup_irq = 0;
-	if (reset)
+	raw_spin_lock_irq(&wakeup_irq_lock);
+
+	if (irq_number && wakeup_irq[0] == irq_number)
+		wakeup_irq[0] = wakeup_irq[1];
+	else
+		wakeup_irq[0] = 0;
+
+	wakeup_irq[1] = 0;
+
+	raw_spin_unlock_irq(&wakeup_irq_lock);
+
+	if (!irq_number)
 		atomic_set(&pm_abort_suspend, 0);
 }
 
 void pm_system_irq_wakeup(unsigned int irq_number)
 {
-	if (pm_wakeup_irq == 0) {
-		pm_wakeup_irq = irq_number;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&wakeup_irq_lock, flags);
+
+	if (wakeup_irq[0] == 0)
+		wakeup_irq[0] = irq_number;
+	else if (wakeup_irq[1] == 0)
+		wakeup_irq[1] = irq_number;
+	else
+		irq_number = 0;
+
+	raw_spin_unlock_irqrestore(&wakeup_irq_lock, flags);
+
+	if (irq_number)
 		pm_system_wakeup();
-	}
+}
+
+unsigned int pm_wakeup_irq(void)
+{
+	return wakeup_irq[0];
 }
 
 /**
@@ -1071,6 +1100,9 @@
 		break;
 	}
 
+	if (!next_ws)
+		print_wakeup_source_stats(m, &deleted_ws);
+
 	return next_ws;
 }
 
--- linux-ein-5.4.0.orig/drivers/base/power/wakeup_stats.c
+++ linux-ein-5.4.0/drivers/base/power/wakeup_stats.c
@@ -42,7 +42,7 @@
 	ktime_t active_time =
 		ws->active ? ktime_sub(ktime_get(), ws->last_time) : 0;
 
-	return sprintf(buf, "%lld\n", ktime_to_ms(active_time));
+	return sysfs_emit(buf, "%lld\n", ktime_to_ms(active_time));
 }
 static DEVICE_ATTR_RO(active_time_ms);
 
@@ -57,7 +57,7 @@
 		active_time = ktime_sub(ktime_get(), ws->last_time);
 		total_time = ktime_add(total_time, active_time);
 	}
-	return sprintf(buf, "%lld\n", ktime_to_ms(total_time));
+	return sysfs_emit(buf, "%lld\n", ktime_to_ms(total_time));
 }
 static DEVICE_ATTR_RO(total_time_ms);
 
@@ -73,7 +73,7 @@
 		if (active_time > max_time)
 			max_time = active_time;
 	}
-	return sprintf(buf, "%lld\n", ktime_to_ms(max_time));
+	return sysfs_emit(buf, "%lld\n", ktime_to_ms(max_time));
 }
 static DEVICE_ATTR_RO(max_time_ms);
 
@@ -82,7 +82,7 @@
 {
 	struct wakeup_source *ws = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%lld\n", ktime_to_ms(ws->last_time));
+	return sysfs_emit(buf, "%lld\n", ktime_to_ms(ws->last_time));
 }
 static DEVICE_ATTR_RO(last_change_ms);
 
@@ -91,7 +91,7 @@
 {
 	struct wakeup_source *ws = dev_get_drvdata(dev);
 
-	return sprintf(buf, "%s\n", ws->name);
+	return sysfs_emit(buf, "%s\n", ws->name);
 }
 static DEVICE_ATTR_RO(name);
 
@@ -106,7 +106,7 @@
 		prevent_sleep_time = ktime_add(prevent_sleep_time,
 			ktime_sub(ktime_get(), ws->start_prevent_time));
 	}
-	return sprintf(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
+	return sysfs_emit(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
 }
 static DEVICE_ATTR_RO(prevent_suspend_time_ms);
 
--- linux-ein-5.4.0.orig/drivers/base/regmap/internal.h
+++ linux-ein-5.4.0/drivers/base/regmap/internal.h
@@ -259,7 +259,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-ein-5.4.0.orig/drivers/base/regmap/regcache-rbtree.c
+++ linux-ein-5.4.0/drivers/base/regmap/regcache-rbtree.c
@@ -277,18 +277,18 @@
 
 	blk = krealloc(rbnode->block,
 		       blklen * map->cache_word_size,
-		       GFP_KERNEL);
+		       map->alloc_flags);
 	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);
+				   map->alloc_flags);
+		if (!present)
 			return -ENOMEM;
-		}
 
 		memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
 		       (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
@@ -305,7 +305,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;
@@ -321,7 +320,7 @@
 	const struct regmap_range *range;
 	int i;
 
-	rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
+	rbnode = kzalloc(sizeof(*rbnode), map->alloc_flags);
 	if (!rbnode)
 		return NULL;
 
@@ -347,13 +346,13 @@
 	}
 
 	rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
-				      GFP_KERNEL);
+				      map->alloc_flags);
 	if (!rbnode->block)
 		goto err_free;
 
 	rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
 					sizeof(*rbnode->cache_present),
-					GFP_KERNEL);
+					map->alloc_flags);
 	if (!rbnode->cache_present)
 		goto err_free_block;
 
@@ -454,7 +453,8 @@
 		if (!rbnode)
 			return -ENOMEM;
 		regcache_rbtree_set_register(map, rbnode,
-					     reg - rbnode->base_reg, value);
+					     (reg - rbnode->base_reg) / map->reg_stride,
+					     value);
 		regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
 		rbtree_ctx->cached_rbnode = rbnode;
 	}
--- linux-ein-5.4.0.orig/drivers/base/regmap/regcache.c
+++ linux-ein-5.4.0/drivers/base/regmap/regcache.c
@@ -343,6 +343,9 @@
 	const char *name;
 	bool bypass;
 
+	if (WARN_ON(map->cache_type == REGCACHE_NONE))
+		return -EINVAL;
+
 	BUG_ON(!map->cache_ops);
 
 	map->lock(map->lock_arg);
@@ -412,6 +415,9 @@
 	const char *name;
 	bool bypass;
 
+	if (WARN_ON(map->cache_type == REGCACHE_NONE))
+		return -EINVAL;
+
 	BUG_ON(!map->cache_ops);
 
 	map->lock(map->lock_arg);
@@ -717,7 +723,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-ein-5.4.0.orig/drivers/base/regmap/regmap-debugfs.c
+++ linux-ein-5.4.0/drivers/base/regmap/regmap-debugfs.c
@@ -49,7 +49,7 @@
 		name = map->dev->driver->name;
 
 	ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
-	if (ret < 0) {
+	if (ret >= PAGE_SIZE) {
 		kfree(buf);
 		return ret;
 	}
@@ -227,6 +227,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;
@@ -371,6 +374,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;
@@ -457,29 +463,31 @@
 {
 	struct regmap *map = container_of(file->private_data,
 					  struct regmap, cache_only);
-	ssize_t result;
-	bool was_enabled, require_sync = false;
+	bool new_val, require_sync = false;
 	int err;
 
-	map->lock(map->lock_arg);
-
-	was_enabled = map->cache_only;
+	err = kstrtobool_from_user(user_buf, count, &new_val);
+	/* Ignore malforned data like debugfs_write_file_bool() */
+	if (err)
+		return count;
+
+	err = debugfs_file_get(file->f_path.dentry);
+	if (err)
+		return err;
 
-	result = debugfs_write_file_bool(file, user_buf, count, ppos);
-	if (result < 0) {
-		map->unlock(map->lock_arg);
-		return result;
-	}
+	map->lock(map->lock_arg);
 
-	if (map->cache_only && !was_enabled) {
+	if (new_val && !map->cache_only) {
 		dev_warn(map->dev, "debugfs cache_only=Y forced\n");
 		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
-	} else if (!map->cache_only && was_enabled) {
+	} else if (!new_val && map->cache_only) {
 		dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n");
 		require_sync = true;
 	}
+	map->cache_only = new_val;
 
 	map->unlock(map->lock_arg);
+	debugfs_file_put(file->f_path.dentry);
 
 	if (require_sync) {
 		err = regcache_sync(map);
@@ -487,7 +495,7 @@
 			dev_err(map->dev, "Failed to sync cache %d\n", err);
 	}
 
-	return result;
+	return count;
 }
 
 static const struct file_operations regmap_cache_only_fops = {
@@ -502,28 +510,32 @@
 {
 	struct regmap *map = container_of(file->private_data,
 					  struct regmap, cache_bypass);
-	ssize_t result;
-	bool was_enabled;
-
-	map->lock(map->lock_arg);
+	bool new_val;
+	int err;
 
-	was_enabled = map->cache_bypass;
+	err = kstrtobool_from_user(user_buf, count, &new_val);
+	/* Ignore malforned data like debugfs_write_file_bool() */
+	if (err)
+		return count;
+
+	err = debugfs_file_get(file->f_path.dentry);
+	if (err)
+		return err;
 
-	result = debugfs_write_file_bool(file, user_buf, count, ppos);
-	if (result < 0)
-		goto out;
+	map->lock(map->lock_arg);
 
-	if (map->cache_bypass && !was_enabled) {
+	if (new_val && !map->cache_bypass) {
 		dev_warn(map->dev, "debugfs cache_bypass=Y forced\n");
 		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
-	} else if (!map->cache_bypass && was_enabled) {
+	} else if (!new_val && map->cache_bypass) {
 		dev_warn(map->dev, "debugfs cache_bypass=N forced\n");
 	}
+	map->cache_bypass = new_val;
 
-out:
 	map->unlock(map->lock_arg);
+	debugfs_file_put(file->f_path.dentry);
 
-	return result;
+	return count;
 }
 
 static const struct file_operations regmap_cache_bypass_fops = {
@@ -571,8 +583,12 @@
 		devname = dev_name(map->dev);
 
 	if (name) {
-		map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
+		if (!map->debugfs_name) {
+			map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
 					      devname, name);
+			if (!map->debugfs_name)
+				return;
+		}
 		name = map->debugfs_name;
 	} else {
 		name = devname;
@@ -580,9 +596,10 @@
 
 	if (!strcmp(name, "dummy")) {
 		kfree(map->debugfs_name);
-
 		map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d",
 						dummy_index);
+		if (!map->debugfs_name)
+				return;
 		name = map->debugfs_name;
 		dummy_index++;
 	}
@@ -644,6 +661,7 @@
 		regmap_debugfs_free_dump_cache(map);
 		mutex_unlock(&map->cache_lock);
 		kfree(map->debugfs_name);
+		map->debugfs_name = NULL;
 	} else {
 		struct regmap_debugfs_node *node, *tmp;
 
--- linux-ein-5.4.0.orig/drivers/base/regmap/regmap-i2c.c
+++ linux-ein-5.4.0/drivers/base/regmap/regmap-i2c.c
@@ -242,6 +242,63 @@
 static struct regmap_bus regmap_i2c_smbus_i2c_block = {
 	.write = regmap_i2c_smbus_i2c_write,
 	.read = regmap_i2c_smbus_i2c_read,
+	.max_raw_read = I2C_SMBUS_BLOCK_MAX - 1,
+	.max_raw_write = I2C_SMBUS_BLOCK_MAX - 1,
+};
+
+static int regmap_i2c_smbus_i2c_write_reg16(void *context, const void *data,
+				      size_t count)
+{
+	struct device *dev = context;
+	struct i2c_client *i2c = to_i2c_client(dev);
+
+	if (count < 2)
+		return -EINVAL;
+
+	count--;
+	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
+					      (u8 *)data + 1);
+}
+
+static int regmap_i2c_smbus_i2c_read_reg16(void *context, const void *reg,
+				     size_t reg_size, void *val,
+				     size_t val_size)
+{
+	struct device *dev = context;
+	struct i2c_client *i2c = to_i2c_client(dev);
+	int ret, count, len = val_size;
+
+	if (reg_size != 2)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_byte_data(i2c, ((u16 *)reg)[0] & 0xff,
+					((u16 *)reg)[0] >> 8);
+	if (ret < 0)
+		return ret;
+
+	count = 0;
+	do {
+		/* Current Address Read */
+		ret = i2c_smbus_read_byte(i2c);
+		if (ret < 0)
+			break;
+
+		*((u8 *)val++) = ret;
+		count++;
+		len--;
+	} while (len > 0);
+
+	if (count == val_size)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
+	.write = regmap_i2c_smbus_i2c_write_reg16,
+	.read = regmap_i2c_smbus_i2c_read_reg16,
 	.max_raw_read = I2C_SMBUS_BLOCK_MAX,
 	.max_raw_write = I2C_SMBUS_BLOCK_MAX,
 };
@@ -255,6 +312,10 @@
 		 i2c_check_functionality(i2c->adapter,
 					 I2C_FUNC_SMBUS_I2C_BLOCK))
 		return &regmap_i2c_smbus_i2c_block;
+	else if (config->val_bits == 8 && config->reg_bits == 16 &&
+		i2c_check_functionality(i2c->adapter,
+					I2C_FUNC_SMBUS_I2C_BLOCK))
+		return &regmap_i2c_smbus_i2c_block_reg16;
 	else if (config->val_bits == 16 && config->reg_bits == 8 &&
 		 i2c_check_functionality(i2c->adapter,
 					 I2C_FUNC_SMBUS_WORD_DATA))
--- linux-ein-5.4.0.orig/drivers/base/regmap/regmap-irq.c
+++ linux-ein-5.4.0/drivers/base/regmap/regmap-irq.c
@@ -214,6 +214,7 @@
 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
 	struct regmap *map = d->map;
 	const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+	unsigned int reg = irq_data->reg_offset / map->reg_stride;
 	unsigned int mask, type;
 
 	type = irq_data->type.type_falling_val | irq_data->type.type_rising_val;
@@ -230,14 +231,14 @@
 	 * at the corresponding offset in regmap_irq_set_type().
 	 */
 	if (d->chip->type_in_mask && type)
-		mask = d->type_buf[irq_data->reg_offset / map->reg_stride];
+		mask = d->type_buf[reg] & irq_data->mask;
 	else
 		mask = irq_data->mask;
 
 	if (d->chip->clear_on_unmask)
 		d->clear_status = true;
 
-	d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~mask;
+	d->mask_buf[reg] &= ~mask;
 }
 
 static void regmap_irq_disable(struct irq_data *data)
@@ -493,7 +494,10 @@
 		if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) {
 			reg = chip->ack_base +
 				(i * map->reg_stride * data->irq_reg_stride);
-			ret = regmap_write(map, reg, data->status_buf[i]);
+			ret = regmap_irq_update_bits(d, reg,
+						     data->status_buf[i],
+						     chip->ack_invert ?
+						     0x00 : 0xFF);
 			if (ret != 0)
 				dev_err(map->dev, "Failed to ack 0x%x: %d\n",
 					reg, ret);
--- linux-ein-5.4.0.orig/drivers/base/regmap/regmap-sdw.c
+++ linux-ein-5.4.0/drivers/base/regmap/regmap-sdw.c
@@ -12,7 +12,7 @@
 	struct device *dev = context;
 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
 
-	return sdw_write(slave, reg, val);
+	return sdw_write_no_pm(slave, reg, val);
 }
 
 static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
@@ -21,7 +21,7 @@
 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
 	int read;
 
-	read = sdw_read(slave, reg);
+	read = sdw_read_no_pm(slave, reg);
 	if (read < 0)
 		return read;
 
--- linux-ein-5.4.0.orig/drivers/base/regmap/regmap.c
+++ linux-ein-5.4.0/drivers/base/regmap/regmap.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/log2.h>
 #include <linux/hwspinlock.h>
+#include <asm/unaligned.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -249,22 +250,20 @@
 
 static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
 {
-	__be16 *b = buf;
-
-	b[0] = cpu_to_be16(val << shift);
+	put_unaligned_be16(val << shift, buf);
 }
 
 static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift)
 {
-	__le16 *b = buf;
-
-	b[0] = cpu_to_le16(val << shift);
+	put_unaligned_le16(val << shift, buf);
 }
 
 static void regmap_format_16_native(void *buf, unsigned int val,
 				    unsigned int shift)
 {
-	*(u16 *)buf = val << shift;
+	u16 v = val << shift;
+
+	memcpy(buf, &v, sizeof(v));
 }
 
 static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
@@ -280,43 +279,39 @@
 
 static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
 {
-	__be32 *b = buf;
-
-	b[0] = cpu_to_be32(val << shift);
+	put_unaligned_be32(val << shift, buf);
 }
 
 static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift)
 {
-	__le32 *b = buf;
-
-	b[0] = cpu_to_le32(val << shift);
+	put_unaligned_le32(val << shift, buf);
 }
 
 static void regmap_format_32_native(void *buf, unsigned int val,
 				    unsigned int shift)
 {
-	*(u32 *)buf = val << shift;
+	u32 v = val << shift;
+
+	memcpy(buf, &v, sizeof(v));
 }
 
 #ifdef CONFIG_64BIT
 static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
 {
-	__be64 *b = buf;
-
-	b[0] = cpu_to_be64((u64)val << shift);
+	put_unaligned_be64((u64) val << shift, buf);
 }
 
 static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
 {
-	__le64 *b = buf;
-
-	b[0] = cpu_to_le64((u64)val << shift);
+	put_unaligned_le64((u64) val << shift, buf);
 }
 
 static void regmap_format_64_native(void *buf, unsigned int val,
 				    unsigned int shift)
 {
-	*(u64 *)buf = (u64)val << shift;
+	u64 v = (u64) val << shift;
+
+	memcpy(buf, &v, sizeof(v));
 }
 #endif
 
@@ -333,35 +328,34 @@
 
 static unsigned int regmap_parse_16_be(const void *buf)
 {
-	const __be16 *b = buf;
-
-	return be16_to_cpu(b[0]);
+	return get_unaligned_be16(buf);
 }
 
 static unsigned int regmap_parse_16_le(const void *buf)
 {
-	const __le16 *b = buf;
-
-	return le16_to_cpu(b[0]);
+	return get_unaligned_le16(buf);
 }
 
 static void regmap_parse_16_be_inplace(void *buf)
 {
-	__be16 *b = buf;
+	u16 v = get_unaligned_be16(buf);
 
-	b[0] = be16_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static void regmap_parse_16_le_inplace(void *buf)
 {
-	__le16 *b = buf;
+	u16 v = get_unaligned_le16(buf);
 
-	b[0] = le16_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static unsigned int regmap_parse_16_native(const void *buf)
 {
-	return *(u16 *)buf;
+	u16 v;
+
+	memcpy(&v, buf, sizeof(v));
+	return v;
 }
 
 static unsigned int regmap_parse_24(const void *buf)
@@ -376,69 +370,67 @@
 
 static unsigned int regmap_parse_32_be(const void *buf)
 {
-	const __be32 *b = buf;
-
-	return be32_to_cpu(b[0]);
+	return get_unaligned_be32(buf);
 }
 
 static unsigned int regmap_parse_32_le(const void *buf)
 {
-	const __le32 *b = buf;
-
-	return le32_to_cpu(b[0]);
+	return get_unaligned_le32(buf);
 }
 
 static void regmap_parse_32_be_inplace(void *buf)
 {
-	__be32 *b = buf;
+	u32 v = get_unaligned_be32(buf);
 
-	b[0] = be32_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static void regmap_parse_32_le_inplace(void *buf)
 {
-	__le32 *b = buf;
+	u32 v = get_unaligned_le32(buf);
 
-	b[0] = le32_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static unsigned int regmap_parse_32_native(const void *buf)
 {
-	return *(u32 *)buf;
+	u32 v;
+
+	memcpy(&v, buf, sizeof(v));
+	return v;
 }
 
 #ifdef CONFIG_64BIT
 static unsigned int regmap_parse_64_be(const void *buf)
 {
-	const __be64 *b = buf;
-
-	return be64_to_cpu(b[0]);
+	return get_unaligned_be64(buf);
 }
 
 static unsigned int regmap_parse_64_le(const void *buf)
 {
-	const __le64 *b = buf;
-
-	return le64_to_cpu(b[0]);
+	return get_unaligned_le64(buf);
 }
 
 static void regmap_parse_64_be_inplace(void *buf)
 {
-	__be64 *b = buf;
+	u64 v =  get_unaligned_be64(buf);
 
-	b[0] = be64_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static void regmap_parse_64_le_inplace(void *buf)
 {
-	__le64 *b = buf;
+	u64 v = get_unaligned_le64(buf);
 
-	b[0] = le64_to_cpu(b[0]);
+	memcpy(buf, &v, sizeof(v));
 }
 
 static unsigned int regmap_parse_64_native(const void *buf)
 {
-	return *(u64 *)buf;
+	u64 v;
+
+	memcpy(&v, buf, sizeof(v));
+	return v;
 }
 #endif
 
@@ -1356,6 +1348,7 @@
 	if (map->hwlock)
 		hwspin_lock_free(map->hwlock);
 	kfree_const(map->name);
+	kfree(map->patch);
 	kfree(map);
 }
 EXPORT_SYMBOL_GPL(regmap_exit);
@@ -1370,7 +1363,7 @@
 
 	/* If the user didn't specify a name match any */
 	if (data)
-		return (*r)->name == data;
+		return (*r)->name && !strcmp((*r)->name, data);
 	else
 		return 1;
 }
@@ -1475,7 +1468,7 @@
 }
 
 static int _regmap_raw_write_impl(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;
@@ -1488,24 +1481,33 @@
 
 	WARN_ON(!map->bus);
 
-	/* Check for unwritable registers before we start */
-	for (i = 0; i < val_len / map->format.val_bytes; i++)
-		if (!regmap_writeable(map,
-				     reg + regmap_get_offset(map, i)))
-			return -EINVAL;
+	/* Check for unwritable or noinc registers in range
+	 * before we start
+	 */
+	if (!regmap_writeable_noinc(map, reg)) {
+		for (i = 0; i < val_len / map->format.val_bytes; i++) {
+			unsigned int element =
+				reg + regmap_get_offset(map, i);
+			if (!regmap_writeable(map, element) ||
+				regmap_writeable_noinc(map, element))
+				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 + regmap_get_offset(map, i),
-					     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 : regmap_get_offset(map, i / val_bytes);
+			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;
 			}
 		}
@@ -1527,7 +1529,7 @@
 				win_residue, val_len / map->format.val_bytes);
 			ret = _regmap_raw_write_impl(map, reg, val,
 						     win_residue *
-						     map->format.val_bytes);
+						     map->format.val_bytes, noinc);
 			if (ret != 0)
 				return ret;
 
@@ -1541,7 +1543,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;
 	}
@@ -1749,7 +1751,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)
@@ -1843,12 +1846,14 @@
 EXPORT_SYMBOL_GPL(regmap_write_async);
 
 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)
 {
 	size_t val_bytes = map->format.val_bytes;
 	size_t val_count = val_len / val_bytes;
 	size_t chunk_count, chunk_bytes;
 	size_t chunk_regs = val_count;
+	size_t max_data = map->max_raw_write - map->format.reg_bytes -
+			map->format.pad_bytes;
 	int ret, i;
 
 	if (!val_count)
@@ -1856,15 +1861,15 @@
 
 	if (map->use_single_write)
 		chunk_regs = 1;
-	else if (map->max_raw_write && val_len > map->max_raw_write)
-		chunk_regs = map->max_raw_write / val_bytes;
+	else if (map->max_raw_write && val_len > max_data)
+		chunk_regs = max_data / val_bytes;
 
 	chunk_count = val_count / chunk_regs;
 	chunk_bytes = chunk_regs * val_bytes;
 
 	/* Write as many bytes as possible with chunk_size */
 	for (i = 0; i < chunk_count; i++) {
-		ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes);
+		ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes, noinc);
 		if (ret)
 			return ret;
 
@@ -1875,7 +1880,7 @@
 
 	/* Write remaining bytes */
 	if (val_len)
-		ret = _regmap_raw_write_impl(map, reg, val, val_len);
+		ret = _regmap_raw_write_impl(map, reg, val, val_len, noinc);
 
 	return ret;
 }
@@ -1908,7 +1913,7 @@
 
 	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);
 
@@ -1966,7 +1971,7 @@
 			write_len = map->max_raw_write;
 		else
 			write_len = val_len;
-		ret = _regmap_raw_write(map, reg, val, write_len);
+		ret = _regmap_raw_write(map, reg, val, write_len, true);
 		if (ret)
 			goto out_unlock;
 		val = ((u8 *)val) + write_len;
@@ -2443,7 +2448,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;
 
@@ -2454,7 +2459,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;
 	int ret;
@@ -2467,7 +2472,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;
 	}
@@ -2505,7 +2510,7 @@
 	if (!map->format.parse_val)
 		return -EINVAL;
 
-	ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes);
+	ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes, false);
 	if (ret == 0)
 		*val = map->format.parse_val(work_val);
 
@@ -2621,7 +2626,7 @@
 
 		/* Read bytes that fit into whole chunks */
 		for (i = 0; i < chunk_count; i++) {
-			ret = _regmap_raw_read(map, reg, val, chunk_bytes);
+			ret = _regmap_raw_read(map, reg, val, chunk_bytes, false);
 			if (ret != 0)
 				goto out;
 
@@ -2632,7 +2637,7 @@
 
 		/* Read remaining bytes */
 		if (val_len) {
-			ret = _regmap_raw_read(map, reg, val, val_len);
+			ret = _regmap_raw_read(map, reg, val, val_len, false);
 			if (ret != 0)
 				goto out;
 		}
@@ -2707,7 +2712,7 @@
 			read_len = map->max_raw_read;
 		else
 			read_len = val_len;
-		ret = _regmap_raw_read(map, reg, val, read_len);
+		ret = _regmap_raw_read(map, reg, val, read_len, true);
 		if (ret)
 			goto out_unlock;
 		val = ((u8 *)val) + read_len;
@@ -2929,6 +2934,28 @@
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_base);
 
+/**
+ * regmap_test_bits() - Check if all specified bits are set in a register.
+ *
+ * @map: Register map to operate on
+ * @reg: Register to read from
+ * @bits: Bits to test
+ *
+ * Returns -1 if the underlying regmap_read() fails, 0 if at least one of the
+ * tested bits is not set and 1 if all tested bits are set.
+ */
+int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits)
+{
+	unsigned int val, ret;
+
+	ret = regmap_read(map, reg, &val);
+	if (ret)
+		return ret;
+
+	return (val & bits) == bits;
+}
+EXPORT_SYMBOL_GPL(regmap_test_bits);
+
 void regmap_async_complete_cb(struct regmap_async *async, int ret)
 {
 	struct regmap *map = async->map;
--- linux-ein-5.4.0.orig/drivers/base/soc.c
+++ linux-ein-5.4.0/drivers/base/soc.c
@@ -76,15 +76,15 @@
 	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
 
 	if (attr == &dev_attr_machine)
-		return sprintf(buf, "%s\n", soc_dev->attr->machine);
+		return sysfs_emit(buf, "%s\n", soc_dev->attr->machine);
 	if (attr == &dev_attr_family)
-		return sprintf(buf, "%s\n", soc_dev->attr->family);
+		return sysfs_emit(buf, "%s\n", soc_dev->attr->family);
 	if (attr == &dev_attr_revision)
-		return sprintf(buf, "%s\n", soc_dev->attr->revision);
+		return sysfs_emit(buf, "%s\n", soc_dev->attr->revision);
 	if (attr == &dev_attr_serial_number)
-		return sprintf(buf, "%s\n", soc_dev->attr->serial_number);
+		return sysfs_emit(buf, "%s\n", soc_dev->attr->serial_number);
 	if (attr == &dev_attr_soc_id)
-		return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
+		return sysfs_emit(buf, "%s\n", soc_dev->attr->soc_id);
 
 	return -EINVAL;
 
--- linux-ein-5.4.0.orig/drivers/base/swnode.c
+++ linux-ein-5.4.0/drivers/base/swnode.c
@@ -520,7 +520,10 @@
 {
 	struct swnode *swnode = to_swnode(fwnode);
 
-	return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : NULL;
+	if (!swnode || !swnode->parent)
+		return NULL;
+
+	return fwnode_handle_get(&swnode->parent->fwnode);
 }
 
 static struct fwnode_handle *
@@ -531,14 +534,18 @@
 	struct swnode *c = to_swnode(child);
 
 	if (!p || list_empty(&p->children) ||
-	    (c && list_is_last(&c->entry, &p->children)))
+	    (c && list_is_last(&c->entry, &p->children))) {
+		fwnode_handle_put(child);
 		return NULL;
+	}
 
 	if (c)
 		c = list_next_entry(c, entry);
 	else
 		c = list_first_entry(&p->children, struct swnode, entry);
-	return &c->fwnode;
+
+	fwnode_handle_put(child);
+	return fwnode_handle_get(&c->fwnode);
 }
 
 static struct fwnode_handle *
@@ -597,6 +604,9 @@
 	if (nargs > NR_FWNODE_REFERENCE_ARGS)
 		return -EINVAL;
 
+	if (!args)
+		return 0;
+
 	args->fwnode = software_node_get(refnode);
 	args->nargs = nargs;
 
@@ -676,6 +686,13 @@
 {
 	struct swnode *swnode = kobj_to_swnode(kobj);
 
+	if (swnode->parent) {
+		ida_simple_remove(&swnode->parent->child_ids, swnode->id);
+		list_del(&swnode->entry);
+	} else {
+		ida_simple_remove(&swnode_root_ids, swnode->id);
+	}
+
 	if (swnode->allocated) {
 		property_entries_free(swnode->node->properties);
 		kfree(swnode->node);
@@ -798,6 +815,9 @@
 	if (software_node_to_swnode(node))
 		return -EEXIST;
 
+	if (node->parent && !parent)
+		return -EINVAL;
+
 	return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
 }
 EXPORT_SYMBOL_GPL(software_node_register);
@@ -841,13 +861,6 @@
 	if (!swnode)
 		return;
 
-	if (swnode->parent) {
-		ida_simple_remove(&swnode->parent->child_ids, swnode->id);
-		list_del(&swnode->entry);
-	} else {
-		ida_simple_remove(&swnode_root_ids, swnode->id);
-	}
-
 	kobject_put(&swnode->kobj);
 }
 EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
--- linux-ein-5.4.0.orig/drivers/base/test/test_async_driver_probe.c
+++ linux-ein-5.4.0/drivers/base/test/test_async_driver_probe.c
@@ -44,7 +44,8 @@
 	 * performing an async init on that node.
 	 */
 	if (dev->driver->probe_type == PROBE_PREFER_ASYNCHRONOUS) {
-		if (dev_to_node(dev) != numa_node_id()) {
+		if (IS_ENABLED(CONFIG_NUMA) &&
+		    dev_to_node(dev) != numa_node_id()) {
 			dev_warn(dev, "NUMA node mismatch %d != %d\n",
 				 dev_to_node(dev), numa_node_id());
 			atomic_inc(&warnings);
@@ -83,7 +84,7 @@
 
 	pdev = platform_device_alloc(name, id);
 	if (!pdev)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	if (nid != NUMA_NO_NODE)
 		set_dev_node(&pdev->dev, nid);
@@ -145,7 +146,7 @@
 	calltime = ktime_get();
 	for_each_online_cpu(cpu) {
 		nid = cpu_to_node(cpu);
-		pdev = &sync_dev[sync_id];
+		pdev = &async_dev[async_id];
 
 		*pdev = test_platform_device_register_node("test_async_driver",
 							   async_id,
--- linux-ein-5.4.0.orig/drivers/bcma/main.c
+++ linux-ein-5.4.0/drivers/bcma/main.c
@@ -236,6 +236,7 @@
 
 void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
 {
+	device_initialize(&core->dev);
 	core->dev.release = bcma_release_core_dev;
 	core->dev.bus = &bcma_bus_type;
 	dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
@@ -277,11 +278,10 @@
 {
 	int err;
 
-	err = device_register(&core->dev);
+	err = device_add(&core->dev);
 	if (err) {
 		bcma_err(bus, "Could not register dev for core 0x%03X\n",
 			 core->id.id);
-		put_device(&core->dev);
 		return;
 	}
 	core->dev_registered = true;
@@ -372,7 +372,7 @@
 	/* Now noone uses internally-handled cores, we can free them */
 	list_for_each_entry_safe(core, tmp, &bus->cores, list) {
 		list_del(&core->list);
-		kfree(core);
+		put_device(&core->dev);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/block/Kconfig
+++ linux-ein-5.4.0/drivers/block/Kconfig
@@ -39,6 +39,22 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called floppy.
 
+config BLK_DEV_FD_RAWCMD
+	bool "Support for raw floppy disk commands (DEPRECATED)"
+	depends on BLK_DEV_FD
+	help
+	  If you want to use actual physical floppies and expect to do
+	  special low-level hardware accesses to them (access and use
+	  non-standard formats, for example), then enable this.
+
+	  Note that the code enabled by this option is rarely used and
+	  might be unstable or insecure, and distros should not enable it.
+
+	  Note: FDRAWCMD is deprecated and will be removed from the kernel
+	  in the near future.
+
+	  If unsure, say N.
+
 config AMIGA_FLOPPY
 	tristate "Amiga floppy support"
 	depends on AMIGA
@@ -230,7 +246,7 @@
 	  dynamically allocated with the /dev/loop-control interface.
 
 config BLK_DEV_CRYPTOLOOP
-	tristate "Cryptoloop Support"
+	tristate "Cryptoloop Support (DEPRECATED)"
 	select CRYPTO
 	select CRYPTO_CBC
 	depends on BLK_DEV_LOOP
@@ -242,7 +258,7 @@
 	  WARNING: This device is not safe for journaled file systems like
 	  ext3 or Reiserfs. Please use the Device Mapper crypto module
 	  instead, which can be configured to be on-disk compatible with the
-	  cryptoloop device.
+	  cryptoloop device.  cryptoloop support will be removed in Linux 5.16.
 
 source "drivers/block/drbd/Kconfig"
 
@@ -283,15 +299,6 @@
 
 	Use device /dev/skd$N amd /dev/skd$Np$M.
 
-config BLK_DEV_SX8
-	tristate "Promise SATA SX8 support"
-	depends on PCI
-	---help---
-	  Saying Y or M here will enable support for the 
-	  Promise SATA SX8 controllers.
-
-	  Use devices /dev/sx8/$N and /dev/sx8/$Np$M.
-
 config BLK_DEV_RAM
 	tristate "RAM block device support"
 	---help---
@@ -461,6 +468,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-ein-5.4.0.orig/drivers/block/Makefile
+++ linux-ein-5.4.0/drivers/block/Makefile
@@ -26,8 +26,6 @@
 obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
 obj-$(CONFIG_VIRTIO_BLK)	+= virtio_blk.o
 
-obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
-
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= xen-blkfront.o
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)	+= xen-blkback/
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
--- linux-ein-5.4.0.orig/drivers/block/ataflop.c
+++ linux-ein-5.4.0/drivers/block/ataflop.c
@@ -653,9 +653,6 @@
 		*p2++ = *p1++;
 }
 
-  
-  
-
 /* General Interrupt Handling */
 
 static void (*FloppyIRQHandler)( int status ) = NULL;
@@ -1225,6 +1222,7 @@
 	}
 	else {
 		/* all sectors finished */
+		finish_fdc();
 		fd_end_request_cur(BLK_STS_OK);
 	}
 	return;
@@ -1472,15 +1470,6 @@
 			ReqTrack, ReqSector, (unsigned long)ReqData ));
 }
 
-static void ataflop_commit_rqs(struct blk_mq_hw_ctx *hctx)
-{
-	spin_lock_irq(&ataflop_lock);
-	atari_disable_irq(IRQ_MFP_FDC);
-	finish_fdc();
-	atari_enable_irq(IRQ_MFP_FDC);
-	spin_unlock_irq(&ataflop_lock);
-}
-
 static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
 				     const struct blk_mq_queue_data *bd)
 {
@@ -1488,6 +1477,8 @@
 	int drive = floppy - unit;
 	int type = floppy->type;
 
+	DPRINT(("Queue request: drive %d type %d last %d\n", drive, type, bd->last));
+
 	spin_lock_irq(&ataflop_lock);
 	if (fd_request) {
 		spin_unlock_irq(&ataflop_lock);
@@ -1547,8 +1538,6 @@
 	setup_req_params( drive );
 	do_fd_action( drive );
 
-	if (bd->last)
-		finish_fdc();
 	atari_enable_irq( IRQ_MFP_FDC );
 
 out:
@@ -1958,7 +1947,6 @@
 
 static const struct blk_mq_ops ataflop_mq_ops = {
 	.queue_rq = ataflop_queue_rq,
-	.commit_rqs = ataflop_commit_rqs,
 };
 
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
--- linux-ein-5.4.0.orig/drivers/block/brd.c
+++ linux-ein-5.4.0/drivers/block/brd.c
@@ -470,6 +470,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;
@@ -493,8 +512,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-ein-5.4.0.orig/drivers/block/cryptoloop.c
+++ linux-ein-5.4.0/drivers/block/cryptoloop.c
@@ -189,6 +189,8 @@
 
 	if (rc)
 		printk(KERN_ERR "cryptoloop: loop_register_transfer failed\n");
+	else
+		pr_warn("the cryptoloop driver has been deprecated and will be removed in in Linux 5.16\n");
 	return rc;
 }
 
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_int.h
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_int.h
@@ -1673,22 +1673,22 @@
 };
 void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib);
 
-extern void notify_resource_state(struct sk_buff *,
+extern int notify_resource_state(struct sk_buff *,
 				  unsigned int,
 				  struct drbd_resource *,
 				  struct resource_info *,
 				  enum drbd_notification_type);
-extern void notify_device_state(struct sk_buff *,
+extern int notify_device_state(struct sk_buff *,
 				unsigned int,
 				struct drbd_device *,
 				struct device_info *,
 				enum drbd_notification_type);
-extern void notify_connection_state(struct sk_buff *,
+extern int notify_connection_state(struct sk_buff *,
 				    unsigned int,
 				    struct drbd_connection *,
 				    struct connection_info *,
 				    enum drbd_notification_type);
-extern void notify_peer_device_state(struct sk_buff *,
+extern int notify_peer_device_state(struct sk_buff *,
 				     unsigned int,
 				     struct drbd_peer_device *,
 				     struct peer_device_info *,
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_main.c
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_main.c
@@ -183,7 +183,7 @@
 		unsigned int set_size)
 {
 	struct drbd_request *r;
-	struct drbd_request *req = NULL;
+	struct drbd_request *req = NULL, *tmp = NULL;
 	int expect_epoch = 0;
 	int expect_size = 0;
 
@@ -237,8 +237,11 @@
 	 * to catch requests being barrier-acked "unexpectedly".
 	 * It usually should find the same req again, or some READ preceding it. */
 	list_for_each_entry(req, &connection->transfer_log, tl_requests)
-		if (req->epoch == expect_epoch)
+		if (req->epoch == expect_epoch) {
+			tmp = req;
 			break;
+		}
+	req = list_prepare_entry(tmp, &connection->transfer_log, tl_requests);
 	list_for_each_entry_safe_from(req, r, &connection->transfer_log, tl_requests) {
 		if (req->epoch != expect_epoch)
 			break;
@@ -2775,7 +2778,7 @@
 enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor)
 {
 	struct drbd_resource *resource = adm_ctx->resource;
-	struct drbd_connection *connection;
+	struct drbd_connection *connection, *n;
 	struct drbd_device *device;
 	struct drbd_peer_device *peer_device, *tmp_peer_device;
 	struct gendisk *disk;
@@ -2903,7 +2906,7 @@
 out_idr_remove_vol:
 	idr_remove(&connection->peer_devices, vnr);
 out_idr_remove_from_resource:
-	for_each_connection(connection, resource) {
+	for_each_connection_safe(connection, n, resource) {
 		peer_device = idr_remove(&connection->peer_devices, vnr);
 		if (peer_device)
 			kref_put(&connection->kref, drbd_destroy_connection);
@@ -3706,9 +3709,8 @@
 	 * when we want to support more than
 	 * one PRO_VERSION */
 	static const char *cmdnames[] = {
+
 		[P_DATA]	        = "Data",
-		[P_WSAME]	        = "WriteSame",
-		[P_TRIM]	        = "Trim",
 		[P_DATA_REPLY]	        = "DataReply",
 		[P_RS_DATA_REPLY]	= "RSDataReply",
 		[P_BARRIER]	        = "Barrier",
@@ -3719,7 +3721,6 @@
 		[P_DATA_REQUEST]	= "DataRequest",
 		[P_RS_DATA_REQUEST]     = "RSDataRequest",
 		[P_SYNC_PARAM]	        = "SyncParam",
-		[P_SYNC_PARAM89]	= "SyncParam89",
 		[P_PROTOCOL]            = "ReportProtocol",
 		[P_UUIDS]	        = "ReportUUIDs",
 		[P_SIZES]	        = "ReportSizes",
@@ -3727,6 +3728,7 @@
 		[P_SYNC_UUID]           = "ReportSyncUUID",
 		[P_AUTH_CHALLENGE]      = "AuthChallenge",
 		[P_AUTH_RESPONSE]	= "AuthResponse",
+		[P_STATE_CHG_REQ]       = "StateChgRequest",
 		[P_PING]		= "Ping",
 		[P_PING_ACK]	        = "PingAck",
 		[P_RECV_ACK]	        = "RecvAck",
@@ -3737,24 +3739,26 @@
 		[P_NEG_DREPLY]	        = "NegDReply",
 		[P_NEG_RS_DREPLY]	= "NegRSDReply",
 		[P_BARRIER_ACK]	        = "BarrierAck",
-		[P_STATE_CHG_REQ]       = "StateChgRequest",
 		[P_STATE_CHG_REPLY]     = "StateChgReply",
 		[P_OV_REQUEST]          = "OVRequest",
 		[P_OV_REPLY]            = "OVReply",
 		[P_OV_RESULT]           = "OVResult",
 		[P_CSUM_RS_REQUEST]     = "CsumRSRequest",
 		[P_RS_IS_IN_SYNC]	= "CsumRSIsInSync",
+		[P_SYNC_PARAM89]	= "SyncParam89",
 		[P_COMPRESSED_BITMAP]   = "CBitmap",
 		[P_DELAY_PROBE]         = "DelayProbe",
 		[P_OUT_OF_SYNC]		= "OutOfSync",
-		[P_RETRY_WRITE]		= "RetryWrite",
 		[P_RS_CANCEL]		= "RSCancel",
 		[P_CONN_ST_CHG_REQ]	= "conn_st_chg_req",
 		[P_CONN_ST_CHG_REPLY]	= "conn_st_chg_reply",
 		[P_RETRY_WRITE]		= "retry_write",
 		[P_PROTOCOL_UPDATE]	= "protocol_update",
+		[P_TRIM]	        = "Trim",
 		[P_RS_THIN_REQ]         = "rs_thin_req",
 		[P_RS_DEALLOCATED]      = "rs_deallocated",
+		[P_WSAME]	        = "WriteSame",
+		[P_ZEROES]		= "Zeroes",
 
 		/* enum drbd_packet, but not commands - obsoleted flags:
 		 *	P_MAY_IGNORE
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_nl.c
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_nl.c
@@ -791,9 +791,11 @@
 	mutex_lock(&adm_ctx.resource->adm_mutex);
 
 	if (info->genlhdr->cmd == DRBD_ADM_PRIMARY)
-		retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate);
+		retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device,
+						R_PRIMARY, parms.assume_uptodate);
 	else
-		retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0);
+		retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device,
+						R_SECONDARY, 0);
 
 	mutex_unlock(&adm_ctx.resource->adm_mutex);
 	genl_lock();
@@ -1971,7 +1973,7 @@
 	drbd_flush_workqueue(&connection->sender_work);
 
 	rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE);
-	retcode = rv;  /* FIXME: Type mismatch. */
+	retcode = (enum drbd_ret_code)rv;
 	drbd_resume_io(device);
 	if (rv < SS_SUCCESS)
 		goto fail;
@@ -2696,7 +2698,8 @@
 	}
 	rcu_read_unlock();
 
-	retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+	retcode = (enum drbd_ret_code)conn_request_state(connection,
+					NS(conn, C_UNCONNECTED), CS_VERBOSE);
 
 	conn_reconfig_done(connection);
 	mutex_unlock(&adm_ctx.resource->adm_mutex);
@@ -2809,7 +2812,7 @@
 	mutex_lock(&adm_ctx.resource->adm_mutex);
 	rv = conn_try_disconnect(connection, parms.force_disconnect);
 	if (rv < SS_SUCCESS)
-		retcode = rv;  /* FIXME: Type mismatch. */
+		retcode = (enum drbd_ret_code)rv;
 	else
 		retcode = NO_ERROR;
 	mutex_unlock(&adm_ctx.resource->adm_mutex);
@@ -3423,7 +3426,7 @@
 {
 	struct nlattr *resource_filter;
 	struct drbd_resource *resource;
-	struct drbd_device *uninitialized_var(device);
+	struct drbd_device *device;
 	int minor, err, retcode;
 	struct drbd_genlmsghdr *dh;
 	struct device_info device_info;
@@ -3512,7 +3515,7 @@
 {
 	struct nlattr *resource_filter;
 	struct drbd_resource *resource = NULL, *next_resource;
-	struct drbd_connection *uninitialized_var(connection);
+	struct drbd_connection *connection;
 	int err = 0, retcode;
 	struct drbd_genlmsghdr *dh;
 	struct connection_info connection_info;
@@ -3674,7 +3677,7 @@
 {
 	struct nlattr *resource_filter;
 	struct drbd_resource *resource;
-	struct drbd_device *uninitialized_var(device);
+	struct drbd_device *device;
 	struct drbd_peer_device *peer_device = NULL;
 	int minor, err, retcode;
 	struct drbd_genlmsghdr *dh;
@@ -4630,7 +4633,7 @@
 	return drbd_notification_header_to_skb(msg, &nh, true);
 }
 
-void notify_resource_state(struct sk_buff *skb,
+int notify_resource_state(struct sk_buff *skb,
 			   unsigned int seq,
 			   struct drbd_resource *resource,
 			   struct resource_info *resource_info,
@@ -4672,16 +4675,17 @@
 		if (err && err != -ESRCH)
 			goto failed;
 	}
-	return;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(skb);
 failed:
 	drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n",
 			err, seq);
+	return err;
 }
 
-void notify_device_state(struct sk_buff *skb,
+int notify_device_state(struct sk_buff *skb,
 			 unsigned int seq,
 			 struct drbd_device *device,
 			 struct device_info *device_info,
@@ -4721,16 +4725,17 @@
 		if (err && err != -ESRCH)
 			goto failed;
 	}
-	return;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(skb);
 failed:
 	drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n",
 		 err, seq);
+	return err;
 }
 
-void notify_connection_state(struct sk_buff *skb,
+int notify_connection_state(struct sk_buff *skb,
 			     unsigned int seq,
 			     struct drbd_connection *connection,
 			     struct connection_info *connection_info,
@@ -4770,16 +4775,17 @@
 		if (err && err != -ESRCH)
 			goto failed;
 	}
-	return;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(skb);
 failed:
 	drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n",
 		 err, seq);
+	return err;
 }
 
-void notify_peer_device_state(struct sk_buff *skb,
+int notify_peer_device_state(struct sk_buff *skb,
 			      unsigned int seq,
 			      struct drbd_peer_device *peer_device,
 			      struct peer_device_info *peer_device_info,
@@ -4820,13 +4826,14 @@
 		if (err && err != -ESRCH)
 			goto failed;
 	}
-	return;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(skb);
 failed:
 	drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n",
 		 err, seq);
+	return err;
 }
 
 void notify_helper(enum drbd_notification_type type,
@@ -4877,7 +4884,7 @@
 		 err, seq);
 }
 
-static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
+static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
 {
 	struct drbd_genlmsghdr *dh;
 	int err;
@@ -4891,11 +4898,12 @@
 	if (nla_put_notification_header(skb, NOTIFY_EXISTS))
 		goto nla_put_failure;
 	genlmsg_end(skb, dh);
-	return;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(skb);
 	pr_err("Error %d sending event. Event seq:%u\n", err, seq);
+	return err;
 }
 
 static void free_state_changes(struct list_head *list)
@@ -4922,6 +4930,7 @@
 	unsigned int seq = cb->args[2];
 	unsigned int n;
 	enum drbd_notification_type flags = 0;
+	int err = 0;
 
 	/* There is no need for taking notification_mutex here: it doesn't
 	   matter if the initial state events mix with later state chage
@@ -4930,32 +4939,32 @@
 
 	cb->args[5]--;
 	if (cb->args[5] == 1) {
-		notify_initial_state_done(skb, seq);
+		err = notify_initial_state_done(skb, seq);
 		goto out;
 	}
 	n = cb->args[4]++;
 	if (cb->args[4] < cb->args[3])
 		flags |= NOTIFY_CONTINUES;
 	if (n < 1) {
-		notify_resource_state_change(skb, seq, state_change->resource,
+		err = notify_resource_state_change(skb, seq, state_change->resource,
 					     NOTIFY_EXISTS | flags);
 		goto next;
 	}
 	n--;
 	if (n < state_change->n_connections) {
-		notify_connection_state_change(skb, seq, &state_change->connections[n],
+		err = notify_connection_state_change(skb, seq, &state_change->connections[n],
 					       NOTIFY_EXISTS | flags);
 		goto next;
 	}
 	n -= state_change->n_connections;
 	if (n < state_change->n_devices) {
-		notify_device_state_change(skb, seq, &state_change->devices[n],
+		err = notify_device_state_change(skb, seq, &state_change->devices[n],
 					   NOTIFY_EXISTS | flags);
 		goto next;
 	}
 	n -= state_change->n_devices;
 	if (n < state_change->n_devices * state_change->n_connections) {
-		notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
+		err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
 						NOTIFY_EXISTS | flags);
 		goto next;
 	}
@@ -4970,7 +4979,10 @@
 		cb->args[4] = 0;
 	}
 out:
-	return skb->len;
+	if (err)
+		return err;
+	else
+		return skb->len;
 }
 
 int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_receiver.c
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_receiver.c
@@ -1298,7 +1298,7 @@
 	bio_set_dev(bio, device->ldev->backing_bdev);
 	bio->bi_private = octx;
 	bio->bi_end_io = one_flush_endio;
-	bio->bi_opf = REQ_OP_FLUSH | REQ_PREFLUSH;
+	bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
 
 	device->flush_jif = jiffies;
 	set_bit(FLUSH_PENDING, &device->flags);
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_req.c
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_req.c
@@ -195,7 +195,8 @@
 void complete_master_bio(struct drbd_device *device,
 		struct bio_and_error *m)
 {
-	m->bio->bi_status = errno_to_blk_status(m->error);
+	if (unlikely(m->error))
+		m->bio->bi_status = errno_to_blk_status(m->error);
 	bio_endio(m->bio);
 	dec_ap_bio(device);
 }
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_state.c
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_state.c
@@ -1537,7 +1537,7 @@
 	return rv;
 }
 
-void notify_resource_state_change(struct sk_buff *skb,
+int notify_resource_state_change(struct sk_buff *skb,
 				  unsigned int seq,
 				  struct drbd_resource_state_change *resource_state_change,
 				  enum drbd_notification_type type)
@@ -1550,10 +1550,10 @@
 		.res_susp_fen = resource_state_change->susp_fen[NEW],
 	};
 
-	notify_resource_state(skb, seq, resource, &resource_info, type);
+	return notify_resource_state(skb, seq, resource, &resource_info, type);
 }
 
-void notify_connection_state_change(struct sk_buff *skb,
+int notify_connection_state_change(struct sk_buff *skb,
 				    unsigned int seq,
 				    struct drbd_connection_state_change *connection_state_change,
 				    enum drbd_notification_type type)
@@ -1564,10 +1564,10 @@
 		.conn_role = connection_state_change->peer_role[NEW],
 	};
 
-	notify_connection_state(skb, seq, connection, &connection_info, type);
+	return notify_connection_state(skb, seq, connection, &connection_info, type);
 }
 
-void notify_device_state_change(struct sk_buff *skb,
+int notify_device_state_change(struct sk_buff *skb,
 				unsigned int seq,
 				struct drbd_device_state_change *device_state_change,
 				enum drbd_notification_type type)
@@ -1577,10 +1577,10 @@
 		.dev_disk_state = device_state_change->disk_state[NEW],
 	};
 
-	notify_device_state(skb, seq, device, &device_info, type);
+	return notify_device_state(skb, seq, device, &device_info, type);
 }
 
-void notify_peer_device_state_change(struct sk_buff *skb,
+int notify_peer_device_state_change(struct sk_buff *skb,
 				     unsigned int seq,
 				     struct drbd_peer_device_state_change *p,
 				     enum drbd_notification_type type)
@@ -1594,7 +1594,7 @@
 		.peer_resync_susp_dependency = p->resync_susp_dependency[NEW],
 	};
 
-	notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
+	return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
 }
 
 static void broadcast_state_change(struct drbd_state_change *state_change)
@@ -1602,7 +1602,7 @@
 	struct drbd_resource_state_change *resource_state_change = &state_change->resource[0];
 	bool resource_state_has_changed;
 	unsigned int n_device, n_connection, n_peer_device, n_peer_devices;
-	void (*last_func)(struct sk_buff *, unsigned int, void *,
+	int (*last_func)(struct sk_buff *, unsigned int, void *,
 			  enum drbd_notification_type) = NULL;
 	void *uninitialized_var(last_arg);
 
--- linux-ein-5.4.0.orig/drivers/block/drbd/drbd_state_change.h
+++ linux-ein-5.4.0/drivers/block/drbd/drbd_state_change.h
@@ -44,19 +44,19 @@
 extern void copy_old_to_new_state_change(struct drbd_state_change *);
 extern void forget_state_change(struct drbd_state_change *);
 
-extern void notify_resource_state_change(struct sk_buff *,
+extern int notify_resource_state_change(struct sk_buff *,
 					 unsigned int,
 					 struct drbd_resource_state_change *,
 					 enum drbd_notification_type type);
-extern void notify_connection_state_change(struct sk_buff *,
+extern int notify_connection_state_change(struct sk_buff *,
 					   unsigned int,
 					   struct drbd_connection_state_change *,
 					   enum drbd_notification_type type);
-extern void notify_device_state_change(struct sk_buff *,
+extern int notify_device_state_change(struct sk_buff *,
 				       unsigned int,
 				       struct drbd_device_state_change *,
 				       enum drbd_notification_type type);
-extern void notify_peer_device_state_change(struct sk_buff *,
+extern int notify_peer_device_state_change(struct sk_buff *,
 					    unsigned int,
 					    struct drbd_peer_device_state_change *,
 					    enum drbd_notification_type type);
--- linux-ein-5.4.0.orig/drivers/block/floppy.c
+++ linux-ein-5.4.0/drivers/block/floppy.c
@@ -521,8 +521,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;
@@ -542,7 +542,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);
@@ -853,14 +852,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);
@@ -1000,7 +1002,7 @@
 static void cancel_activity(void)
 {
 	do_floppy = NULL;
-	cancel_delayed_work_sync(&fd_timer);
+	cancel_delayed_work(&fd_timer);
 	cancel_work_sync(&floppy_work);
 }
 
@@ -1432,7 +1434,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)
@@ -2052,7 +2054,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);
@@ -2197,9 +2199,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;
@@ -2674,7 +2675,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);
@@ -2798,10 +2799,11 @@
 	current_req = list_first_entry_or_null(&floppy_reqs, struct request,
 					       queuelist);
 	if (current_req) {
-		current_req->error_count = 0;
+		floppy_errors = 0;
 		list_del_init(&current_req->queuelist);
+		return 1;
 	}
-	return current_req != NULL;
+	return 0;
 }
 
 static void redo_fd_request(void)
@@ -2857,7 +2859,6 @@
 		_floppy = floppy_type + DP->autodetect[DRS->probed_format];
 	} else
 		probing = 0;
-	errors = &(current_req->error_count);
 	tmp = make_raw_rw_request();
 	if (tmp < 2) {
 		request_done(tmp);
@@ -2899,17 +2900,17 @@
 		 (unsigned long long) current_req->cmd_flags))
 		return BLK_STS_IOERR;
 
-	spin_lock_irq(&floppy_lock);
-	list_add_tail(&bd->rq->queuelist, &floppy_reqs);
-	spin_unlock_irq(&floppy_lock);
-
 	if (test_and_set_bit(0, &fdc_busy)) {
 		/* fdc busy, this new request will be treated when the
 		   current one is done */
 		is_alive(__func__, "old request running");
-		return BLK_STS_OK;
+		return BLK_STS_RESOURCE;
 	}
 
+	spin_lock_irq(&floppy_lock);
+	list_add_tail(&bd->rq->queuelist, &floppy_reqs);
+	spin_unlock_irq(&floppy_lock);
+
 	command_status = FD_COMMAND_NONE;
 	__reschedule_timeout(MAXTIMEOUT, "fd_request");
 	set_fdc(0);
@@ -3009,6 +3010,8 @@
 		return "(null)";
 }
 
+#ifdef CONFIG_BLK_DEV_FD_RAWCMD
+
 /* raw commands */
 static void raw_cmd_done(int flag)
 {
@@ -3109,6 +3112,8 @@
 	}
 }
 
+#define MAX_LEN (1UL << MAX_ORDER << PAGE_SHIFT)
+
 static int raw_cmd_copyin(int cmd, void __user *param,
 				 struct floppy_raw_cmd **rcmd)
 {
@@ -3146,7 +3151,7 @@
 	ptr->resultcode = 0;
 
 	if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
-		if (ptr->length <= 0)
+		if (ptr->length <= 0 || ptr->length >= MAX_LEN)
 			return -EINVAL;
 		ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
 		fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
@@ -3218,6 +3223,35 @@
 	return ret;
 }
 
+static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
+				void __user *param)
+{
+	int ret;
+
+	pr_warn_once("Note: FDRAWCMD is deprecated and will be removed from the kernel in the near future.\n");
+
+	if (type)
+		return -EINVAL;
+	if (lock_fdc(drive))
+		return -EINTR;
+	set_floppy(drive);
+	ret = raw_cmd_ioctl(cmd, param);
+	if (ret == -EINTR)
+		return -EINTR;
+	process_fd_request();
+	return ret;
+}
+
+#else /* CONFIG_BLK_DEV_FD_RAWCMD */
+
+static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
+				void __user *param)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
 static int invalidate_drive(struct block_device *bdev)
 {
 	/* invalidate the buffer track to force a reread */
@@ -3405,7 +3439,6 @@
 {
 	int drive = (long)bdev->bd_disk->private_data;
 	int type = ITYPE(UDRS->fd_device);
-	int i;
 	int ret;
 	int size;
 	union inparam {
@@ -3556,16 +3589,7 @@
 		outparam = UDRWE;
 		break;
 	case FDRAWCMD:
-		if (type)
-			return -EINVAL;
-		if (lock_fdc(drive))
-			return -EINTR;
-		set_floppy(drive);
-		i = raw_cmd_ioctl(cmd, (void __user *)param);
-		if (i == -EINTR)
-			return -EINTR;
-		process_fd_request();
-		return i;
+		return floppy_raw_cmd_ioctl(type, drive, cmd, (void __user *)param);
 	case FDTWADDLE:
 		if (lock_fdc(drive))
 			return -EINTR;
--- linux-ein-5.4.0.orig/drivers/block/loop.c
+++ linux-ein-5.4.0/drivers/block/loop.c
@@ -417,19 +417,22 @@
 	return ret;
 }
 
-static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos)
+static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos,
+			int mode)
 {
 	/*
-	 * We use punch hole to reclaim the free space used by the
-	 * image a.k.a. discard. However we do not support discard if
-	 * encryption is enabled, because it may give an attacker
-	 * useful information.
+	 * We use fallocate to manipulate the space mappings used by the image
+	 * a.k.a. discard/zerorange. However we do not support this if
+	 * encryption is enabled, because it may give an attacker useful
+	 * information.
 	 */
 	struct file *file = lo->lo_backing_file;
-	int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
+	struct request_queue *q = lo->lo_queue;
 	int ret;
 
-	if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
+	mode |= FALLOC_FL_KEEP_SIZE;
+
+	if (!blk_queue_discard(q)) {
 		ret = -EOPNOTSUPP;
 		goto out;
 	}
@@ -494,7 +497,8 @@
 		return;
 	kfree(cmd->bvec);
 	cmd->bvec = NULL;
-	blk_mq_complete_request(rq);
+	if (likely(!blk_should_fake_timeout(rq->q)))
+		blk_mq_complete_request(rq);
 }
 
 static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
@@ -596,9 +600,17 @@
 	switch (req_op(rq)) {
 	case REQ_OP_FLUSH:
 		return lo_req_flush(lo, rq);
-	case REQ_OP_DISCARD:
 	case REQ_OP_WRITE_ZEROES:
-		return lo_discard(lo, rq, pos);
+		/*
+		 * If the caller doesn't want deallocation, call zeroout to
+		 * write zeroes the range.  Otherwise, punch them out.
+		 */
+		return lo_fallocate(lo, rq, pos,
+			(rq->cmd_flags & REQ_NOUNMAP) ?
+				FALLOC_FL_ZERO_RANGE :
+				FALLOC_FL_PUNCH_HOLE);
+	case REQ_OP_DISCARD:
+		return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE);
 	case REQ_OP_WRITE:
 		if (lo->transfer)
 			return lo_write_transfer(lo, rq, pos);
@@ -625,6 +637,15 @@
 			lo->use_dio);
 }
 
+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,
 				   struct block_device *bdev)
 {
@@ -678,6 +699,7 @@
 			  unsigned int arg)
 {
 	struct file	*file = NULL, *old_file;
+	struct file	*f, *virt_file = NULL, *old_virt_file;
 	int		error;
 	bool		partscan;
 
@@ -697,12 +719,19 @@
 	file = fget(arg);
 	if (!file)
 		goto out_err;
+	f = loop_real_file(file);
+	if (f) {
+		virt_file = file;
+		file = f;
+		get_file(file);
+	}
 
 	error = loop_validate_file(file, bdev);
 	if (error)
 		goto out_err;
 
 	old_file = lo->lo_backing_file;
+	old_virt_file = lo->lo_backing_virt_file;
 
 	error = -EINVAL;
 
@@ -714,6 +743,7 @@
 	blk_mq_freeze_queue(lo->lo_queue);
 	mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
 	lo->lo_backing_file = file;
+	lo->lo_backing_virt_file = virt_file;
 	lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping);
 	mapping_set_gfp_mask(file->f_mapping,
 			     lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
@@ -727,6 +757,8 @@
 	 * dependency.
 	 */
 	fput(old_file);
+	if (old_virt_file)
+		fput(old_virt_file);
 	if (partscan)
 		loop_reread_partitions(lo, bdev);
 	return 0;
@@ -735,9 +767,29 @@
 	mutex_unlock(&loop_ctl_mutex);
 	if (file)
 		fput(file);
+	if (virt_file)
+		fput(virt_file);
 	return error;
 }
 
+/*
+ * for AUFS
+ * no get/put for file.
+ */
+struct file *loop_backing_file(struct super_block *sb)
+{
+	struct file *ret;
+	struct loop_device *l;
+
+	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_GPL(loop_backing_file);
+
 /* loop sysfs attributes */
 
 static ssize_t loop_attr_show(struct device *dev, char *page,
@@ -783,33 +835,33 @@
 
 static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf)
 {
-	return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset);
+	return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_offset);
 }
 
 static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf)
 {
-	return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit);
+	return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit);
 }
 
 static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf)
 {
 	int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR);
 
-	return sprintf(buf, "%s\n", autoclear ? "1" : "0");
+	return sysfs_emit(buf, "%s\n", autoclear ? "1" : "0");
 }
 
 static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
 {
 	int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN);
 
-	return sprintf(buf, "%s\n", partscan ? "1" : "0");
+	return sysfs_emit(buf, "%s\n", partscan ? "1" : "0");
 }
 
 static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
 {
 	int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
 
-	return sprintf(buf, "%s\n", dio ? "1" : "0");
+	return sysfs_emit(buf, "%s\n", dio ? "1" : "0");
 }
 
 LOOP_ATTR_RO(backing_file);
@@ -852,6 +904,23 @@
 	struct file *file = lo->lo_backing_file;
 	struct inode *inode = file->f_mapping->host;
 	struct request_queue *q = lo->lo_queue;
+	u32 granularity, max_discard_sectors;
+
+	/*
+	 * If the backing device is a block device, mirror its zeroing
+	 * capability. Set the discard sectors to the block device's zeroing
+	 * capabilities because loop discards result in blkdev_issue_zeroout(),
+	 * not blkdev_issue_discard(). This maintains consistent behavior with
+	 * file-backed loop devices: discarded regions read back as zero.
+	 */
+	if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) {
+		struct request_queue *backingq;
+
+		backingq = bdev_get_queue(inode->i_bdev);
+
+		max_discard_sectors = backingq->limits.max_write_zeroes_sectors;
+		granularity = backingq->limits.discard_granularity ?:
+			queue_physical_block_size(backingq);
 
 	/*
 	 * We use punch hole to reclaim the free space used by the
@@ -859,22 +928,27 @@
 	 * encryption is enabled, because it may give an attacker
 	 * useful information.
 	 */
-	if ((!file->f_op->fallocate) ||
-	    lo->lo_encrypt_key_size) {
+	} else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) {
+		max_discard_sectors = 0;
+		granularity = 0;
+
+	} else {
+		max_discard_sectors = UINT_MAX >> 9;
+		granularity = inode->i_sb->s_blocksize;
+	}
+
+	if (max_discard_sectors) {
+		q->limits.discard_granularity = granularity;
+		blk_queue_max_discard_sectors(q, max_discard_sectors);
+		blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+		blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+	} else {
 		q->limits.discard_granularity = 0;
-		q->limits.discard_alignment = 0;
 		blk_queue_max_discard_sectors(q, 0);
 		blk_queue_max_write_zeroes_sectors(q, 0);
 		blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
-		return;
 	}
-
-	q->limits.discard_granularity = inode->i_sb->s_blocksize;
 	q->limits.discard_alignment = 0;
-
-	blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
-	blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
-	blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
 }
 
 static void loop_unprepare_queue(struct loop_device *lo)
@@ -921,7 +995,7 @@
 static int loop_set_fd(struct loop_device *lo, fmode_t mode,
 		       struct block_device *bdev, unsigned int arg)
 {
-	struct file	*file;
+	struct file	*file, *f, *virt_file = NULL;
 	struct inode	*inode;
 	struct address_space *mapping;
 	struct block_device *claimed_bdev = NULL;
@@ -937,6 +1011,12 @@
 	file = fget(arg);
 	if (!file)
 		goto out;
+	f = loop_real_file(file);
+	if (f) {
+		virt_file = file;
+		file = f;
+		get_file(file);
+	}
 
 	/*
 	 * If we don't hold exclusive handle for the device, upgrade to it
@@ -985,6 +1065,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;
@@ -1038,6 +1119,8 @@
 		bd_abort_claiming(bdev, claimed_bdev, loop_set_fd);
 out_putf:
 	fput(file);
+	if (virt_file)
+		fput(virt_file);
 out:
 	/* This is safe: open() is still holding a reference. */
 	module_put(THIS_MODULE);
@@ -1084,6 +1167,7 @@
 static int __loop_clr_fd(struct loop_device *lo, bool release)
 {
 	struct file *filp = NULL;
+	struct file *virt_filp = lo->lo_backing_virt_file;
 	gfp_t gfp = lo->old_gfp_mask;
 	struct block_device *bdev = lo->lo_device;
 	int err = 0;
@@ -1102,11 +1186,15 @@
 		goto out_unlock;
 	}
 
+	if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags))
+		blk_queue_write_cache(lo->lo_queue, false, false);
+
 	/* freeze request queue during the transition */
 	blk_mq_freeze_queue(lo->lo_queue);
 
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_backing_file = NULL;
+	lo->lo_backing_virt_file = NULL;
 	spin_unlock_irq(&lo->lo_lock);
 
 	loop_release_xfer(lo);
@@ -1189,6 +1277,8 @@
 	 */
 	if (filp)
 		fput(filp);
+	if (virt_filp)
+		fput(virt_filp);
 	return err;
 }
 
@@ -1254,7 +1344,7 @@
 	if (lo->lo_offset != info->lo_offset ||
 	    lo->lo_sizelimit != info->lo_sizelimit) {
 		sync_blockdev(lo->lo_device);
-		kill_bdev(lo->lo_device);
+		invalidate_bdev(lo->lo_device);
 	}
 
 	/* I/O need to be drained during transfer transition */
@@ -1364,6 +1454,11 @@
 	info->lo_number = lo->lo_number;
 	info->lo_offset = lo->lo_offset;
 	info->lo_sizelimit = lo->lo_sizelimit;
+
+	/* loff_t vars have been assigned __u64 */
+	if (lo->lo_offset < 0 || lo->lo_sizelimit < 0)
+		return -EOVERFLOW;
+
 	info->lo_flags = lo->lo_flags;
 	memcpy(info->lo_file_name, lo->lo_file_name, LO_NAME_SIZE);
 	memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE);
@@ -1528,12 +1623,12 @@
 
 	if (lo->lo_queue->limits.logical_block_size != arg) {
 		sync_blockdev(lo->lo_device);
-		kill_bdev(lo->lo_device);
+		invalidate_bdev(lo->lo_device);
 	}
 
 	blk_mq_freeze_queue(lo->lo_queue);
 
-	/* kill_bdev should have truncated all the pages */
+	/* invalidate_bdev should have truncated all the pages */
 	if (lo->lo_queue->limits.logical_block_size != arg &&
 			lo->lo_device->bd_inode->i_mapping->nrpages) {
 		err = -EAGAIN;
@@ -1941,7 +2036,8 @@
 	/* complete non-aio request */
 	if (!cmd->use_aio || ret) {
 		cmd->ret = ret ? -EIO : 0;
-		blk_mq_complete_request(rq);
+		if (likely(!blk_should_fake_timeout(rq->q)))
+			blk_mq_complete_request(rq);
 	}
 }
 
@@ -1999,7 +2095,7 @@
 	lo->tag_set.queue_depth = 128;
 	lo->tag_set.numa_node = NUMA_NO_NODE;
 	lo->tag_set.cmd_size = sizeof(struct loop_cmd);
-	lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+	lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_NO_SCHED;
 	lo->tag_set.driver_data = lo;
 
 	err = blk_mq_alloc_tag_set(&lo->tag_set);
@@ -2295,6 +2391,8 @@
 
 	range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
 
+	mutex_lock(&loop_ctl_mutex);
+
 	idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
 	idr_destroy(&loop_index_idr);
 
@@ -2302,6 +2400,8 @@
 	unregister_blkdev(LOOP_MAJOR, "loop");
 
 	misc_deregister(&loop_misc);
+
+	mutex_unlock(&loop_ctl_mutex);
 }
 
 module_init(loop_init);
--- linux-ein-5.4.0.orig/drivers/block/loop.h
+++ linux-ein-5.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;
 	void		*key_data; 
 
--- linux-ein-5.4.0.orig/drivers/block/mtip32xx/mtip32xx.c
+++ linux-ein-5.4.0/drivers/block/mtip32xx/mtip32xx.c
@@ -492,7 +492,8 @@
 	struct request *req = blk_mq_rq_from_pdu(cmd);
 
 	cmd->status = status;
-	blk_mq_complete_request(req);
+	if (likely(!blk_should_fake_timeout(req->q)))
+		blk_mq_complete_request(req);
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/block/nbd.c
+++ linux-ein-5.4.0/drivers/block/nbd.c
@@ -78,8 +78,7 @@
 #define NBD_RT_HAS_PID_FILE		3
 #define NBD_RT_HAS_CONFIG_REF		4
 #define NBD_RT_BOUND			5
-#define NBD_RT_DESTROY_ON_DISCONNECT	6
-#define NBD_RT_DISCONNECT_ON_CLOSE	7
+#define NBD_RT_DISCONNECT_ON_CLOSE	6
 
 #define NBD_DESTROY_ON_DISCONNECT	0
 #define NBD_DISCONNECT_REQUESTED	1
@@ -123,6 +122,12 @@
 };
 
 #define NBD_CMD_REQUEUED	1
+/*
+ * This flag will be set if nbd_queue_rq() succeed, and will be checked and
+ * cleared in completion. Both setting and clearing of the flag are protected
+ * by cmd->lock.
+ */
+#define NBD_CMD_INFLIGHT	2
 
 struct nbd_cmd {
 	struct nbd_device *nbd;
@@ -296,7 +301,7 @@
 	}
 }
 
-static void nbd_size_update(struct nbd_device *nbd)
+static void nbd_size_update(struct nbd_device *nbd, bool start)
 {
 	struct nbd_config *config = nbd->config;
 	struct block_device *bdev = bdget_disk(nbd->disk, 0);
@@ -312,7 +317,8 @@
 	if (bdev) {
 		if (bdev->bd_disk) {
 			bd_set_size(bdev, config->bytesize);
-			set_blocksize(bdev, config->blksize);
+			if (start)
+				set_blocksize(bdev, config->blksize);
 		} else
 			bdev->bd_invalidated = 1;
 		bdput(bdev);
@@ -327,7 +333,7 @@
 	config->blksize = blocksize;
 	config->bytesize = blocksize * nr_blocks;
 	if (nbd->task_recv != NULL)
-		nbd_size_update(nbd);
+		nbd_size_update(nbd, false);
 }
 
 static void nbd_complete_rq(struct request *req)
@@ -388,8 +394,14 @@
 	if (!mutex_trylock(&cmd->lock))
 		return BLK_EH_RESET_TIMER;
 
+	if (!test_bit(NBD_CMD_INFLIGHT, &cmd->flags)) {
+		mutex_unlock(&cmd->lock);
+		return BLK_EH_DONE;
+	}
+
 	if (!refcount_inc_not_zero(&nbd->config_refs)) {
 		cmd->status = BLK_STS_TIMEOUT;
+		__clear_bit(NBD_CMD_INFLIGHT, &cmd->flags);
 		mutex_unlock(&cmd->lock);
 		goto done;
 	}
@@ -445,6 +457,7 @@
 	dev_err_ratelimited(nbd_to_dev(nbd), "Connection timed out\n");
 	set_bit(NBD_RT_TIMEDOUT, &config->runtime_flags);
 	cmd->status = BLK_STS_IOERR;
+	__clear_bit(NBD_CMD_INFLIGHT, &cmd->flags);
 	mutex_unlock(&cmd->lock);
 	sock_shutdown(nbd);
 	nbd_config_put(nbd);
@@ -704,6 +717,12 @@
 	cmd = blk_mq_rq_to_pdu(req);
 
 	mutex_lock(&cmd->lock);
+	if (!test_bit(NBD_CMD_INFLIGHT, &cmd->flags)) {
+		dev_err(disk_to_dev(nbd->disk), "Suspicious reply %d (status %u flags %lu)",
+			tag, cmd->status, cmd->flags);
+		ret = -ENOENT;
+		goto out;
+	}
 	if (cmd->cmd_cookie != nbd_handle_to_cookie(handle)) {
 		dev_err(disk_to_dev(nbd->disk), "Double reply on req %p, cmd_cookie %u, handle cookie %u\n",
 			req, cmd->cmd_cookie, nbd_handle_to_cookie(handle));
@@ -773,6 +792,7 @@
 	struct nbd_device *nbd = args->nbd;
 	struct nbd_config *config = nbd->config;
 	struct nbd_cmd *cmd;
+	struct request *rq;
 
 	while (1) {
 		cmd = nbd_read_stat(nbd, args->index);
@@ -785,11 +805,21 @@
 			break;
 		}
 
-		blk_mq_complete_request(blk_mq_rq_from_pdu(cmd));
+		rq = blk_mq_rq_from_pdu(cmd);
+		if (likely(!blk_should_fake_timeout(rq->q))) {
+			bool complete;
+
+			mutex_lock(&cmd->lock);
+			complete = __test_and_clear_bit(NBD_CMD_INFLIGHT,
+							&cmd->flags);
+			mutex_unlock(&cmd->lock);
+			if (complete)
+				blk_mq_complete_request(rq);
+		}
 	}
+	nbd_config_put(nbd);
 	atomic_dec(&config->recv_threads);
 	wake_up(&config->recv_wq);
-	nbd_config_put(nbd);
 	kfree(args);
 }
 
@@ -797,7 +827,15 @@
 {
 	struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
 
+	/* don't abort one completed request */
+	if (blk_mq_request_completed(req))
+		return true;
+
 	mutex_lock(&cmd->lock);
+	if (!__test_and_clear_bit(NBD_CMD_INFLIGHT, &cmd->flags)) {
+		mutex_unlock(&cmd->lock);
+		return true;
+	}
 	cmd->status = BLK_STS_IOERR;
 	mutex_unlock(&cmd->lock);
 
@@ -861,11 +899,15 @@
 	struct nbd_config *config = nbd->config;
 	if (!config->dead_conn_timeout)
 		return 0;
-	if (test_bit(NBD_RT_DISCONNECTED, &config->runtime_flags))
+
+	if (!wait_event_timeout(config->conn_wait,
+				test_bit(NBD_RT_DISCONNECTED,
+					 &config->runtime_flags) ||
+				atomic_read(&config->live_connections) > 0,
+				config->dead_conn_timeout))
 		return 0;
-	return wait_event_timeout(config->conn_wait,
-				  atomic_read(&config->live_connections) > 0,
-				  config->dead_conn_timeout) > 0;
+
+	return !test_bit(NBD_RT_DISCONNECTED, &config->runtime_flags);
 }
 
 static int nbd_handle_cmd(struct nbd_cmd *cmd, int index)
@@ -934,7 +976,13 @@
 	 * returns EAGAIN can be retried on a different socket.
 	 */
 	ret = nbd_send_cmd(nbd, cmd, index);
-	if (ret == -EAGAIN) {
+	/*
+	 * Access to this flag is protected by cmd->lock, thus it's safe to set
+	 * the flag after nbd_send_cmd() succeed to send request to server.
+	 */
+	if (!ret)
+		__set_bit(NBD_CMD_INFLIGHT, &cmd->flags);
+	else if (ret == -EAGAIN) {
 		dev_err_ratelimited(disk_to_dev(nbd->disk),
 				    "Request send failed, requeueing\n");
 		nbd_mark_nsock_dead(nbd, nsock, 1);
@@ -1013,6 +1061,12 @@
 	if (!sock)
 		return err;
 
+	/*
+	 * We need to make sure we don't get any errant requests while we're
+	 * reallocating the ->socks array.
+	 */
+	blk_mq_freeze_queue(nbd->disk->queue);
+
 	if (!netlink && !nbd->task_setup &&
 	    !test_bit(NBD_RT_BOUND, &config->runtime_flags))
 		nbd->task_setup = current;
@@ -1022,20 +1076,22 @@
 	     test_bit(NBD_RT_BOUND, &config->runtime_flags))) {
 		dev_err(disk_to_dev(nbd->disk),
 			"Device being setup by another task");
-		sockfd_put(sock);
-		return -EBUSY;
+		err = -EBUSY;
+		goto put_socket;
+	}
+
+	nsock = kzalloc(sizeof(*nsock), GFP_KERNEL);
+	if (!nsock) {
+		err = -ENOMEM;
+		goto put_socket;
 	}
 
 	socks = krealloc(config->socks, (config->num_connections + 1) *
 			 sizeof(struct nbd_sock *), GFP_KERNEL);
 	if (!socks) {
-		sockfd_put(sock);
-		return -ENOMEM;
-	}
-	nsock = kzalloc(sizeof(struct nbd_sock), GFP_KERNEL);
-	if (!nsock) {
-		sockfd_put(sock);
-		return -ENOMEM;
+		kfree(nsock);
+		err = -ENOMEM;
+		goto put_socket;
 	}
 
 	config->socks = socks;
@@ -1049,8 +1105,14 @@
 	nsock->cookie = 0;
 	socks[config->num_connections++] = nsock;
 	atomic_inc(&config->live_connections);
+	blk_mq_unfreeze_queue(nbd->disk->queue);
 
 	return 0;
+
+put_socket:
+	blk_mq_unfreeze_queue(nbd->disk->queue);
+	sockfd_put(sock);
+	return err;
 }
 
 static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
@@ -1264,6 +1326,16 @@
 		args = kzalloc(sizeof(*args), GFP_KERNEL);
 		if (!args) {
 			sock_shutdown(nbd);
+			/*
+			 * If num_connections is m (2 < m),
+			 * and NO.1 ~ NO.n(1 < n < m) kzallocs are successful.
+			 * But NO.(n + 1) failed. We still have n recv threads.
+			 * So, add flush_workqueue here to prevent recv threads
+			 * dropping the last config_refs and trying to destroy
+			 * the workqueue from inside the workqueue.
+			 */
+			if (i)
+				flush_workqueue(nbd->recv_workq);
 			return -ENOMEM;
 		}
 		sk_set_memalloc(config->socks[i]->sock->sk);
@@ -1277,7 +1349,7 @@
 		args->index = i;
 		queue_work(nbd->recv_workq, &args->work);
 	}
-	nbd_size_update(nbd);
+	nbd_size_update(nbd, true);
 	return error;
 }
 
@@ -1297,8 +1369,10 @@
 					 atomic_read(&config->recv_threads) == 0);
 	if (ret) {
 		sock_shutdown(nbd);
-		flush_workqueue(nbd->recv_workq);
+		nbd_clear_que(nbd);
 	}
+
+	flush_workqueue(nbd->recv_workq);
 	mutex_lock(&nbd->config_lock);
 	nbd_bdev_reset(bdev);
 	/* user requested, ignore socket errors */
@@ -1312,7 +1386,7 @@
 static void nbd_clear_sock_ioctl(struct nbd_device *nbd,
 				 struct block_device *bdev)
 {
-	sock_shutdown(nbd);
+	nbd_clear_sock(nbd);
 	__invalidate_device(bdev, true);
 	nbd_bdev_reset(bdev);
 	if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
@@ -1333,6 +1407,8 @@
 	nbd->tag_set.timeout = timeout * HZ;
 	if (timeout)
 		blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ);
+	else
+		blk_queue_rq_timeout(nbd->disk->queue, 30 * HZ);
 }
 
 /* Must be called with config_lock held */
@@ -1423,15 +1499,20 @@
 {
 	struct nbd_config *config;
 
+	if (!try_module_get(THIS_MODULE))
+		return ERR_PTR(-ENODEV);
+
 	config = kzalloc(sizeof(struct nbd_config), GFP_NOFS);
-	if (!config)
-		return NULL;
+	if (!config) {
+		module_put(THIS_MODULE);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	atomic_set(&config->recv_threads, 0);
 	init_waitqueue_head(&config->recv_wq);
 	init_waitqueue_head(&config->conn_wait);
 	config->blksize = NBD_DEF_BLKSIZE;
 	atomic_set(&config->live_connections, 0);
-	try_module_get(THIS_MODULE);
 	return config;
 }
 
@@ -1458,12 +1539,13 @@
 			mutex_unlock(&nbd->config_lock);
 			goto out;
 		}
-		config = nbd->config = nbd_alloc_config();
-		if (!config) {
-			ret = -ENOMEM;
+		config = nbd_alloc_config();
+		if (IS_ERR(config)) {
+			ret = PTR_ERR(config);
 			mutex_unlock(&nbd->config_lock);
 			goto out;
 		}
+		nbd->config = config;
 		refcount_set(&nbd->config_refs, 1);
 		refcount_inc(&nbd->refs);
 		mutex_unlock(&nbd->config_lock);
@@ -1484,6 +1566,7 @@
 	if (test_bit(NBD_RT_DISCONNECT_ON_CLOSE, &nbd->config->runtime_flags) &&
 			bdev->bd_openers == 0)
 		nbd_disconnect_and_put(nbd);
+	bdput(bdev);
 
 	nbd_config_put(nbd);
 	nbd_put(nbd);
@@ -1566,7 +1649,7 @@
 		return -EIO;
 
 	dir = debugfs_create_dir(nbd_name(nbd), nbd_dbg_dir);
-	if (!dir) {
+	if (IS_ERR(dir)) {
 		dev_err(nbd_to_dev(nbd), "Failed to create debugfs dir for '%s'\n",
 			nbd_name(nbd));
 		return -EIO;
@@ -1592,7 +1675,7 @@
 	struct dentry *dbg_dir;
 
 	dbg_dir = debugfs_create_dir("nbd", NULL);
-	if (!dbg_dir)
+	if (IS_ERR(dbg_dir))
 		return -EIO;
 
 	nbd_dbg_dir = dbg_dir;
@@ -1665,7 +1748,8 @@
 		if (err == -ENOSPC)
 			err = -EEXIST;
 	} else {
-		err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL);
+		err = idr_alloc(&nbd_index_idr, nbd, 0,
+				(MINORMASK >> part_shift) + 1, GFP_KERNEL);
 		if (err >= 0)
 			index = err;
 	}
@@ -1884,13 +1968,14 @@
 		nbd_put(nbd);
 		return -EINVAL;
 	}
-	config = nbd->config = nbd_alloc_config();
-	if (!nbd->config) {
+	config = nbd_alloc_config();
+	if (IS_ERR(config)) {
 		mutex_unlock(&nbd->config_lock);
 		nbd_put(nbd);
 		printk(KERN_ERR "nbd: couldn't allocate config\n");
-		return -ENOMEM;
+		return PTR_ERR(config);
 	}
+	nbd->config = config;
 	refcount_set(&nbd->config_refs, 1);
 	set_bit(NBD_RT_BOUND, &config->runtime_flags);
 
@@ -1912,12 +1997,21 @@
 	if (info->attrs[NBD_ATTR_CLIENT_FLAGS]) {
 		u64 flags = nla_get_u64(info->attrs[NBD_ATTR_CLIENT_FLAGS]);
 		if (flags & NBD_CFLAG_DESTROY_ON_DISCONNECT) {
-			set_bit(NBD_RT_DESTROY_ON_DISCONNECT,
-				&config->runtime_flags);
-			set_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags);
-			put_dev = true;
+			/*
+			 * We have 1 ref to keep the device around, and then 1
+			 * ref for our current operation here, which will be
+			 * inherited by the config.  If we already have
+			 * DESTROY_ON_DISCONNECT set then we know we don't have
+			 * that extra ref already held so we don't need the
+			 * put_dev.
+			 */
+			if (!test_and_set_bit(NBD_DESTROY_ON_DISCONNECT,
+					      &nbd->flags))
+				put_dev = true;
 		} else {
-			clear_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags);
+			if (test_and_clear_bit(NBD_DESTROY_ON_DISCONNECT,
+					       &nbd->flags))
+				refcount_inc(&nbd->refs);
 		}
 		if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) {
 			set_bit(NBD_RT_DISCONNECT_ON_CLOSE,
@@ -1973,14 +2067,20 @@
 {
 	mutex_lock(&nbd->config_lock);
 	nbd_disconnect(nbd);
-	nbd_clear_sock(nbd);
-	mutex_unlock(&nbd->config_lock);
+	sock_shutdown(nbd);
+	wake_up(&nbd->config->conn_wait);
 	/*
 	 * Make sure recv thread has finished, so it does not drop the last
 	 * config ref and try to destroy the workqueue from inside the work
-	 * queue.
+	 * queue. And this also ensure that we can safely call nbd_clear_que()
+	 * to cancel the inflight I/Os.
 	 */
-	flush_workqueue(nbd->recv_workq);
+	if (nbd->recv_workq)
+		flush_workqueue(nbd->recv_workq);
+	nbd_clear_que(nbd);
+	nbd->task_setup = NULL;
+	mutex_unlock(&nbd->config_lock);
+
 	if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
 			       &nbd->config->runtime_flags))
 		nbd_config_put(nbd);
@@ -2088,15 +2188,13 @@
 	if (info->attrs[NBD_ATTR_CLIENT_FLAGS]) {
 		u64 flags = nla_get_u64(info->attrs[NBD_ATTR_CLIENT_FLAGS]);
 		if (flags & NBD_CFLAG_DESTROY_ON_DISCONNECT) {
-			if (!test_and_set_bit(NBD_RT_DESTROY_ON_DISCONNECT,
-					      &config->runtime_flags))
+			if (!test_and_set_bit(NBD_DESTROY_ON_DISCONNECT,
+					      &nbd->flags))
 				put_dev = true;
-			set_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags);
 		} else {
-			if (test_and_clear_bit(NBD_RT_DESTROY_ON_DISCONNECT,
-					       &config->runtime_flags))
+			if (test_and_clear_bit(NBD_DESTROY_ON_DISCONNECT,
+					       &nbd->flags))
 				refcount_inc(&nbd->refs);
-			clear_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags);
 		}
 
 		if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) {
@@ -2255,6 +2353,12 @@
 	}
 
 	dev_list = nla_nest_start_noflag(reply, NBD_ATTR_DEVICE_LIST);
+	if (!dev_list) {
+		nlmsg_free(reply);
+		ret = -EMSGSIZE;
+		goto out;
+	}
+
 	if (index == -1) {
 		ret = idr_for_each(&nbd_index_idr, &status_cb, reply);
 		if (ret) {
@@ -2398,6 +2502,12 @@
 	struct nbd_device *nbd;
 	LIST_HEAD(del_list);
 
+	/*
+	 * Unregister netlink interface prior to waiting
+	 * for the completion of netlink commands.
+	 */
+	genl_unregister_family(&nbd_genl_family);
+
 	nbd_dbg_close();
 
 	mutex_lock(&nbd_index_mutex);
@@ -2407,13 +2517,15 @@
 	while (!list_empty(&del_list)) {
 		nbd = list_first_entry(&del_list, struct nbd_device, list);
 		list_del_init(&nbd->list);
+		if (refcount_read(&nbd->config_refs))
+			printk(KERN_ERR "nbd: possibly leaking nbd_config (ref %d)\n",
+					refcount_read(&nbd->config_refs));
 		if (refcount_read(&nbd->refs) != 1)
 			printk(KERN_ERR "nbd: possibly leaking a device\n");
 		nbd_put(nbd);
 	}
 
 	idr_destroy(&nbd_index_idr);
-	genl_unregister_family(&nbd_genl_family);
 	unregister_blkdev(NBD_MAJOR, "nbd");
 }
 
--- linux-ein-5.4.0.orig/drivers/block/null_blk_main.c
+++ linux-ein-5.4.0/drivers/block/null_blk_main.c
@@ -579,6 +579,7 @@
 	if (tag != -1U) {
 		cmd = &nq->cmds[tag];
 		cmd->tag = tag;
+		cmd->error = BLK_STS_OK;
 		cmd->nq = nq;
 		if (nq->dev->irqmode == NULL_IRQ_TIMER) {
 			hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
@@ -1071,7 +1072,7 @@
 		len = bvec.bv_len;
 		err = null_transfer(nullb, bvec.bv_page, len, bvec.bv_offset,
 				     op_is_write(req_op(rq)), sector,
-				     req_op(rq) & REQ_FUA);
+				     rq->cmd_flags & REQ_FUA);
 		if (err) {
 			spin_unlock_irq(&nullb->lock);
 			return err;
@@ -1189,7 +1190,8 @@
 	case NULL_IRQ_SOFTIRQ:
 		switch (cmd->nq->dev->queue_mode) {
 		case NULL_Q_MQ:
-			blk_mq_complete_request(cmd->rq);
+			if (likely(!blk_should_fake_timeout(cmd->rq->q)))
+				blk_mq_complete_request(cmd->rq);
 			break;
 		case NULL_Q_BIO:
 			/*
@@ -1335,6 +1337,7 @@
 		cmd->timer.function = null_cmd_timer_expired;
 	}
 	cmd->rq = bd->rq;
+	cmd->error = BLK_STS_OK;
 	cmd->nq = nq;
 
 	blk_mq_start_request(bd->rq);
@@ -1382,7 +1385,12 @@
 
 static void null_del_dev(struct nullb *nullb)
 {
-	struct nullb_device *dev = nullb->dev;
+	struct nullb_device *dev;
+
+	if (!nullb)
+		return;
+
+	dev = nullb->dev;
 
 	ida_simple_remove(&nullb_indexes, nullb->index);
 
@@ -1704,8 +1712,13 @@
 	blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, nullb->q);
 
 	mutex_lock(&lock);
-	nullb->index = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL);
-	dev->index = nullb->index;
+	rv = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL);
+	if (rv < 0) {
+		mutex_unlock(&lock);
+		goto out_cleanup_zone;
+	}
+	nullb->index = rv;
+	dev->index = rv;
 	mutex_unlock(&lock);
 
 	blk_queue_logical_block_size(nullb->q, dev->blocksize);
@@ -1717,13 +1730,16 @@
 
 	rv = null_gendisk_register(nullb);
 	if (rv)
-		goto out_cleanup_zone;
+		goto out_ida_free;
 
 	mutex_lock(&lock);
 	list_add_tail(&nullb->list, &nullb_list);
 	mutex_unlock(&lock);
 
 	return 0;
+
+out_ida_free:
+	ida_free(&nullb_indexes, nullb->index);
 out_cleanup_zone:
 	if (dev->zoned)
 		null_zone_exit(dev);
@@ -1736,6 +1752,7 @@
 	cleanup_queues(nullb);
 out_free_nullb:
 	kfree(nullb);
+	dev->nullb = NULL;
 out:
 	return rv;
 }
--- linux-ein-5.4.0.orig/drivers/block/null_blk_zoned.c
+++ linux-ein-5.4.0/drivers/block/null_blk_zoned.c
@@ -2,8 +2,7 @@
 #include <linux/vmalloc.h>
 #include "null_blk.h"
 
-/* zone_size in MBs to sectors. */
-#define ZONE_SIZE_SHIFT		11
+#define MB_TO_SECTS(mb) (((sector_t)mb * SZ_1M) >> SECTOR_SHIFT)
 
 static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
 {
@@ -12,7 +11,7 @@
 
 int null_zone_init(struct nullb_device *dev)
 {
-	sector_t dev_size = (sector_t)dev->size * 1024 * 1024;
+	sector_t dev_capacity_sects;
 	sector_t sector = 0;
 	unsigned int i;
 
@@ -20,10 +19,17 @@
 		pr_err("zone_size must be power-of-two\n");
 		return -EINVAL;
 	}
+	if (dev->zone_size > dev->size) {
+		pr_err("Zone size larger than device capacity\n");
+		return -EINVAL;
+	}
+
+	dev_capacity_sects = MB_TO_SECTS(dev->size);
+	dev->zone_size_sects = MB_TO_SECTS(dev->zone_size);
+	dev->nr_zones = dev_capacity_sects >> ilog2(dev->zone_size_sects);
+	if (dev_capacity_sects & (dev->zone_size_sects - 1))
+		dev->nr_zones++;
 
-	dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT;
-	dev->nr_zones = dev_size >>
-				(SECTOR_SHIFT + ilog2(dev->zone_size_sects));
 	dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone),
 			GFP_KERNEL | __GFP_ZERO);
 	if (!dev->zones)
@@ -51,7 +57,10 @@
 		struct blk_zone *zone = &dev->zones[i];
 
 		zone->start = zone->wp = sector;
-		zone->len = dev->zone_size_sects;
+		if (zone->start + dev->zone_size_sects > dev_capacity_sects)
+			zone->len = dev_capacity_sects - zone->start;
+		else
+			zone->len = dev->zone_size_sects;
 		zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
 		zone->cond = BLK_ZONE_COND_EMPTY;
 
@@ -64,6 +73,7 @@
 void null_zone_exit(struct nullb_device *dev)
 {
 	kvfree(dev->zones);
+	dev->zones = NULL;
 }
 
 int null_zone_report(struct gendisk *disk, sector_t sector,
--- linux-ein-5.4.0.orig/drivers/block/ps3disk.c
+++ linux-ein-5.4.0/drivers/block/ps3disk.c
@@ -454,7 +454,6 @@
 	queue->queuedata = dev;
 
 	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-ein-5.4.0.orig/drivers/block/rbd.c
+++ linux-ein-5.4.0/drivers/block/rbd.c
@@ -626,9 +626,8 @@
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
 
 static int rbd_dev_refresh(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev);
-static int rbd_dev_header_info(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev);
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+				     struct rbd_image_header *header);
 static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
 					u64 snap_id);
 static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
@@ -1098,15 +1097,24 @@
 	RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
 }
 
+static void rbd_image_header_cleanup(struct rbd_image_header *header)
+{
+	kfree(header->object_prefix);
+	ceph_put_snap_context(header->snapc);
+	kfree(header->snap_sizes);
+	kfree(header->snap_names);
+
+	memset(header, 0, sizeof(*header));
+}
+
 /*
  * Fill an rbd image header with information from the given format 1
  * on-disk header.
  */
-static int rbd_header_from_disk(struct rbd_device *rbd_dev,
-				 struct rbd_image_header_ondisk *ondisk)
+static int rbd_header_from_disk(struct rbd_image_header *header,
+				struct rbd_image_header_ondisk *ondisk,
+				bool first_time)
 {
-	struct rbd_image_header *header = &rbd_dev->header;
-	bool first_time = header->object_prefix == NULL;
 	struct ceph_snap_context *snapc;
 	char *object_prefix = NULL;
 	char *snap_names = NULL;
@@ -1173,11 +1181,6 @@
 	if (first_time) {
 		header->object_prefix = object_prefix;
 		header->obj_order = ondisk->options.order;
-		rbd_init_layout(rbd_dev);
-	} else {
-		ceph_put_snap_context(header->snapc);
-		kfree(header->snap_names);
-		kfree(header->snap_sizes);
 	}
 
 	/* The remaining fields always get updated (when we refresh) */
@@ -1493,14 +1496,30 @@
 /*
  * Must be called after rbd_obj_calc_img_extents().
  */
-static bool rbd_obj_copyup_enabled(struct rbd_obj_request *obj_req)
+static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req)
 {
-	if (!obj_req->num_img_extents ||
-	    (rbd_obj_is_entire(obj_req) &&
-	     !obj_req->img_request->snapc->num_snaps))
-		return false;
+	rbd_assert(obj_req->img_request->snapc);
 
-	return true;
+	if (obj_req->img_request->op_type == OBJ_OP_DISCARD) {
+		dout("%s %p objno %llu discard\n", __func__, obj_req,
+		     obj_req->ex.oe_objno);
+		return;
+	}
+
+	if (!obj_req->num_img_extents) {
+		dout("%s %p objno %llu not overlapping\n", __func__, obj_req,
+		     obj_req->ex.oe_objno);
+		return;
+	}
+
+	if (rbd_obj_is_entire(obj_req) &&
+	    !obj_req->img_request->snapc->num_snaps) {
+		dout("%s %p objno %llu entire\n", __func__, obj_req,
+		     obj_req->ex.oe_objno);
+		return;
+	}
+
+	obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
 }
 
 static u64 rbd_obj_img_extents_bytes(struct rbd_obj_request *obj_req)
@@ -1599,6 +1618,7 @@
 static struct ceph_osd_request *
 rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
 {
+	rbd_assert(obj_req->img_request->snapc);
 	return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
 					 num_ops);
 }
@@ -1727,11 +1747,14 @@
  * Caller is responsible for filling in the list of object requests
  * that comprises the image request, and the Linux request pointer
  * (if there is one).
+ *
+ * Only snap_id is captured here, for reads.  For writes, snapshot
+ * context is captured in rbd_img_object_requests() after exclusive
+ * lock is ensured to be held.
  */
 static struct rbd_img_request *rbd_img_request_create(
 					struct rbd_device *rbd_dev,
-					enum obj_operation_type op_type,
-					struct ceph_snap_context *snapc)
+					enum obj_operation_type op_type)
 {
 	struct rbd_img_request *img_request;
 
@@ -1743,8 +1766,6 @@
 	img_request->op_type = op_type;
 	if (!rbd_img_is_write(img_request))
 		img_request->snap_id = rbd_dev->spec->snap_id;
-	else
-		img_request->snapc = snapc;
 
 	if (rbd_dev_parent_get(rbd_dev))
 		img_request_layered_set(img_request);
@@ -2087,7 +2108,7 @@
 	struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
 	struct ceph_osd_data *osd_data;
 	u64 objno;
-	u8 state, new_state, uninitialized_var(current_state);
+	u8 state, new_state, current_state;
 	bool has_current_state;
 	void *p;
 
@@ -2389,9 +2410,6 @@
 	if (ret)
 		return ret;
 
-	if (rbd_obj_copyup_enabled(obj_req))
-		obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
-
 	obj_req->write_state = RBD_OBJ_WRITE_START;
 	return 0;
 }
@@ -2497,8 +2515,6 @@
 	if (ret)
 		return ret;
 
-	if (rbd_obj_copyup_enabled(obj_req))
-		obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
 	if (!obj_req->num_img_extents) {
 		obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
 		if (rbd_obj_is_entire(obj_req))
@@ -2739,7 +2755,7 @@
 			       u64 off, u64 len)
 {
 	struct ceph_file_extent ex = { off, len };
-	union rbd_img_fill_iter dummy;
+	union rbd_img_fill_iter dummy = {};
 	struct rbd_img_fill_ctx fctx = {
 		.pos_type = OBJ_REQUEST_NODATA,
 		.pos = &dummy,
@@ -2935,7 +2951,7 @@
 	int ret;
 
 	child_img_req = rbd_img_request_create(img_req->rbd_dev->parent,
-					       OBJ_OP_READ, NULL);
+					       OBJ_OP_READ);
 	if (!child_img_req)
 		return -ENOMEM;
 
@@ -3439,6 +3455,7 @@
 	case RBD_OBJ_WRITE_START:
 		rbd_assert(!*result);
 
+		rbd_obj_set_copyup_enabled(obj_req);
 		if (rbd_obj_write_is_noop(obj_req))
 			return true;
 
@@ -3586,14 +3603,15 @@
 static void rbd_lock_del_request(struct rbd_img_request *img_req)
 {
 	struct rbd_device *rbd_dev = img_req->rbd_dev;
-	bool need_wakeup;
+	bool need_wakeup = false;
 
 	lockdep_assert_held(&rbd_dev->lock_rwsem);
 	spin_lock(&rbd_dev->lock_lists_lock);
-	rbd_assert(!list_empty(&img_req->lock_item));
-	list_del_init(&img_req->lock_item);
-	need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
-		       list_empty(&rbd_dev->running_list));
+	if (!list_empty(&img_req->lock_item)) {
+		list_del_init(&img_req->lock_item);
+		need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
+			       list_empty(&rbd_dev->running_list));
+	}
 	spin_unlock(&rbd_dev->lock_lists_lock);
 	if (need_wakeup)
 		complete(&rbd_dev->releasing_wait);
@@ -3625,9 +3643,19 @@
 
 static void rbd_img_object_requests(struct rbd_img_request *img_req)
 {
+	struct rbd_device *rbd_dev = img_req->rbd_dev;
 	struct rbd_obj_request *obj_req;
 
 	rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
+	rbd_assert(!need_exclusive_lock(img_req) ||
+		   __rbd_is_lock_owner(rbd_dev));
+
+	if (rbd_img_is_write(img_req)) {
+		rbd_assert(!img_req->snapc);
+		down_read(&rbd_dev->header_rwsem);
+		img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
+		up_read(&rbd_dev->header_rwsem);
+	}
 
 	for_each_obj_request(img_req, obj_req) {
 		int result = 0;
@@ -3645,7 +3673,6 @@
 
 static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
 {
-	struct rbd_device *rbd_dev = img_req->rbd_dev;
 	int ret;
 
 again:
@@ -3666,9 +3693,6 @@
 		if (*result)
 			return true;
 
-		rbd_assert(!need_exclusive_lock(img_req) ||
-			   __rbd_is_lock_owner(rbd_dev));
-
 		rbd_img_object_requests(img_req);
 		if (!img_req->pending.num_pending) {
 			*result = img_req->pending.result;
@@ -3974,14 +3998,19 @@
 		return;
 	}
 
-	list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) {
+	while (!list_empty(&rbd_dev->acquiring_list)) {
+		img_req = list_first_entry(&rbd_dev->acquiring_list,
+					   struct rbd_img_request, lock_item);
 		mutex_lock(&img_req->state_mutex);
 		rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK);
+		if (!result)
+			list_move_tail(&img_req->lock_item,
+				       &rbd_dev->running_list);
+		else
+			list_del_init(&img_req->lock_item);
 		rbd_img_schedule(img_req, result);
 		mutex_unlock(&img_req->state_mutex);
 	}
-
-	list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
 }
 
 static int get_lock_owner_info(struct rbd_device *rbd_dev,
@@ -4130,6 +4159,10 @@
 {
 	int ret;
 
+	ret = rbd_dev_refresh(rbd_dev);
+	if (ret)
+		return ret;
+
 	if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
 		ret = rbd_object_map_open(rbd_dev);
 		if (ret)
@@ -4239,8 +4272,6 @@
 
 static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)
 {
-	bool need_wait;
-
 	dout("%s rbd_dev %p\n", __func__, rbd_dev);
 	lockdep_assert_held_write(&rbd_dev->lock_rwsem);
 
@@ -4252,11 +4283,11 @@
 	 */
 	rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
 	rbd_assert(!completion_done(&rbd_dev->releasing_wait));
-	need_wait = !list_empty(&rbd_dev->running_list);
-	downgrade_write(&rbd_dev->lock_rwsem);
-	if (need_wait)
-		wait_for_completion(&rbd_dev->releasing_wait);
-	up_read(&rbd_dev->lock_rwsem);
+	if (list_empty(&rbd_dev->running_list))
+		return true;
+
+	up_write(&rbd_dev->lock_rwsem);
+	wait_for_completion(&rbd_dev->releasing_wait);
 
 	down_write(&rbd_dev->lock_rwsem);
 	if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING)
@@ -4342,15 +4373,11 @@
 	if (!rbd_cid_equal(&cid, &rbd_empty_cid)) {
 		down_write(&rbd_dev->lock_rwsem);
 		if (rbd_cid_equal(&cid, &rbd_dev->owner_cid)) {
-			/*
-			 * we already know that the remote client is
-			 * the owner
-			 */
-			up_write(&rbd_dev->lock_rwsem);
-			return;
+			dout("%s rbd_dev %p cid %llu-%llu == owner_cid\n",
+			     __func__, rbd_dev, cid.gid, cid.handle);
+		} else {
+			rbd_set_owner_cid(rbd_dev, &cid);
 		}
-
-		rbd_set_owner_cid(rbd_dev, &cid);
 		downgrade_write(&rbd_dev->lock_rwsem);
 	} else {
 		down_read(&rbd_dev->lock_rwsem);
@@ -4375,14 +4402,12 @@
 	if (!rbd_cid_equal(&cid, &rbd_empty_cid)) {
 		down_write(&rbd_dev->lock_rwsem);
 		if (!rbd_cid_equal(&cid, &rbd_dev->owner_cid)) {
-			dout("%s rbd_dev %p unexpected owner, cid %llu-%llu != owner_cid %llu-%llu\n",
+			dout("%s rbd_dev %p cid %llu-%llu != owner_cid %llu-%llu\n",
 			     __func__, rbd_dev, cid.gid, cid.handle,
 			     rbd_dev->owner_cid.gid, rbd_dev->owner_cid.handle);
-			up_write(&rbd_dev->lock_rwsem);
-			return;
+		} else {
+			rbd_set_owner_cid(rbd_dev, &rbd_empty_cid);
 		}
-
-		rbd_set_owner_cid(rbd_dev, &rbd_empty_cid);
 		downgrade_write(&rbd_dev->lock_rwsem);
 	} else {
 		down_read(&rbd_dev->lock_rwsem);
@@ -4636,6 +4661,10 @@
 	cancel_work_sync(&rbd_dev->unlock_work);
 }
 
+/*
+ * header_rwsem must not be held to avoid a deadlock with
+ * rbd_dev_refresh() when flushing notifies.
+ */
 static void rbd_unregister_watch(struct rbd_device *rbd_dev)
 {
 	cancel_tasks_sync(rbd_dev);
@@ -4792,7 +4821,6 @@
 	struct request *rq = blk_mq_rq_from_pdu(work);
 	struct rbd_device *rbd_dev = rq->q->queuedata;
 	struct rbd_img_request *img_request;
-	struct ceph_snap_context *snapc = NULL;
 	u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
 	u64 length = blk_rq_bytes(rq);
 	enum obj_operation_type op_type;
@@ -4857,10 +4885,6 @@
 
 	down_read(&rbd_dev->header_rwsem);
 	mapping_size = rbd_dev->mapping.size;
-	if (op_type != OBJ_OP_READ) {
-		snapc = rbd_dev->header.snapc;
-		ceph_get_snap_context(snapc);
-	}
 	up_read(&rbd_dev->header_rwsem);
 
 	if (offset + length > mapping_size) {
@@ -4870,13 +4894,12 @@
 		goto err_rq;
 	}
 
-	img_request = rbd_img_request_create(rbd_dev, op_type, snapc);
+	img_request = rbd_img_request_create(rbd_dev, op_type);
 	if (!img_request) {
 		result = -ENOMEM;
 		goto err_rq;
 	}
 	img_request->rq = rq;
-	snapc = NULL; /* img_request consumes a ref */
 
 	dout("%s rbd_dev %p img_req %p %s %llu~%llu\n", __func__, rbd_dev,
 	     img_request, obj_op_name(op_type), offset, length);
@@ -4898,7 +4921,6 @@
 	if (result)
 		rbd_warn(rbd_dev, "%s %llx at %llx result %d",
 			 obj_op_name(op_type), length, offset, result);
-	ceph_put_snap_context(snapc);
 err:
 	blk_mq_end_request(rq, errno_to_blk_status(result));
 }
@@ -4970,7 +4992,9 @@
  * return, the rbd_dev->header field will contain up-to-date
  * information about the image.
  */
-static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev,
+				  struct rbd_image_header *header,
+				  bool first_time)
 {
 	struct rbd_image_header_ondisk *ondisk = NULL;
 	u32 snap_count = 0;
@@ -5018,7 +5042,7 @@
 		snap_count = le32_to_cpu(ondisk->snap_count);
 	} while (snap_count != want_count);
 
-	ret = rbd_header_from_disk(rbd_dev, ondisk);
+	ret = rbd_header_from_disk(header, ondisk, first_time);
 out:
 	kfree(ondisk);
 
@@ -5062,43 +5086,6 @@
 	}
 }
 
-static int rbd_dev_refresh(struct rbd_device *rbd_dev)
-{
-	u64 mapping_size;
-	int ret;
-
-	down_write(&rbd_dev->header_rwsem);
-	mapping_size = rbd_dev->mapping.size;
-
-	ret = rbd_dev_header_info(rbd_dev);
-	if (ret)
-		goto out;
-
-	/*
-	 * If there is a parent, see if it has disappeared due to the
-	 * mapped image getting flattened.
-	 */
-	if (rbd_dev->parent) {
-		ret = rbd_dev_v2_parent_info(rbd_dev);
-		if (ret)
-			goto out;
-	}
-
-	if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
-		rbd_dev->mapping.size = rbd_dev->header.image_size;
-	} else {
-		/* validate mapped snapshot's EXISTS flag */
-		rbd_exists_validate(rbd_dev);
-	}
-
-out:
-	up_write(&rbd_dev->header_rwsem);
-	if (!ret && mapping_size != rbd_dev->mapping.size)
-		rbd_dev_update_size(rbd_dev);
-
-	return ret;
-}
-
 static int rbd_init_request(struct blk_mq_tag_set *set, struct request *rq,
 		unsigned int hctx_idx, unsigned int numa_node)
 {
@@ -5276,6 +5263,9 @@
 {
 	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	return sprintf(buf, "%s\n", rbd_dev->config_info);
 }
 
@@ -5387,6 +5377,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;
@@ -5527,8 +5520,7 @@
 		module_put(THIS_MODULE);
 }
 
-static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
-					   struct rbd_spec *spec)
+static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec)
 {
 	struct rbd_device *rbd_dev;
 
@@ -5573,9 +5565,6 @@
 	rbd_dev->dev.parent = &rbd_root_dev;
 	device_initialize(&rbd_dev->dev);
 
-	rbd_dev->rbd_client = rbdc;
-	rbd_dev->spec = spec;
-
 	return rbd_dev;
 }
 
@@ -5588,12 +5577,10 @@
 {
 	struct rbd_device *rbd_dev;
 
-	rbd_dev = __rbd_dev_create(rbdc, spec);
+	rbd_dev = __rbd_dev_create(spec);
 	if (!rbd_dev)
 		return NULL;
 
-	rbd_dev->opts = opts;
-
 	/* get an id and fill in device name */
 	rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0,
 					 minor_to_rbd_dev_id(1 << MINORBITS),
@@ -5610,6 +5597,10 @@
 	/* we have a ref from do_rbd_add() */
 	__module_get(THIS_MODULE);
 
+	rbd_dev->rbd_client = rbdc;
+	rbd_dev->spec = spec;
+	rbd_dev->opts = opts;
+
 	dout("%s rbd_dev %p dev_id %d\n", __func__, rbd_dev, rbd_dev->dev_id);
 	return rbd_dev;
 
@@ -5664,17 +5655,12 @@
 	return 0;
 }
 
-static int rbd_dev_v2_image_size(struct rbd_device *rbd_dev)
-{
-	return _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
-					&rbd_dev->header.obj_order,
-					&rbd_dev->header.image_size);
-}
-
-static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev,
+				    char **pobject_prefix)
 {
 	size_t size;
 	void *reply_buf;
+	char *object_prefix;
 	int ret;
 	void *p;
 
@@ -5692,16 +5678,16 @@
 		goto out;
 
 	p = reply_buf;
-	rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p,
-						p + ret, NULL, GFP_NOIO);
+	object_prefix = ceph_extract_encoded_string(&p, p + ret, NULL,
+						    GFP_NOIO);
+	if (IS_ERR(object_prefix)) {
+		ret = PTR_ERR(object_prefix);
+		goto out;
+	}
 	ret = 0;
 
-	if (IS_ERR(rbd_dev->header.object_prefix)) {
-		ret = PTR_ERR(rbd_dev->header.object_prefix);
-		rbd_dev->header.object_prefix = NULL;
-	} else {
-		dout("  object_prefix = %s\n", rbd_dev->header.object_prefix);
-	}
+	*pobject_prefix = object_prefix;
+	dout("  object_prefix = %s\n", object_prefix);
 out:
 	kfree(reply_buf);
 
@@ -5746,12 +5732,6 @@
 	return 0;
 }
 
-static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
-{
-	return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
-						&rbd_dev->header.features);
-}
-
 /*
  * These are generic image flags, but since they are used only for
  * object map, store them in rbd_dev->object_map_flags.
@@ -5788,6 +5768,14 @@
 	u64		overlap;
 };
 
+static void rbd_parent_info_cleanup(struct parent_image_info *pii)
+{
+	kfree(pii->pool_ns);
+	kfree(pii->image_id);
+
+	memset(pii, 0, sizeof(*pii));
+}
+
 /*
  * The caller is responsible for @pii.
  */
@@ -5857,6 +5845,9 @@
 	if (pii->has_overlap)
 		ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+	dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+	     __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+	     pii->has_overlap, pii->overlap);
 	return 0;
 
 e_inval:
@@ -5895,14 +5886,17 @@
 	pii->has_overlap = true;
 	ceph_decode_64_safe(&p, end, pii->overlap, e_inval);
 
+	dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
+	     __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id,
+	     pii->has_overlap, pii->overlap);
 	return 0;
 
 e_inval:
 	return -EINVAL;
 }
 
-static int get_parent_info(struct rbd_device *rbd_dev,
-			   struct parent_image_info *pii)
+static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev,
+				  struct parent_image_info *pii)
 {
 	struct page *req_page, *reply_page;
 	void *p;
@@ -5930,7 +5924,7 @@
 	return ret;
 }
 
-static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
+static int rbd_dev_setup_parent(struct rbd_device *rbd_dev)
 {
 	struct rbd_spec *parent_spec;
 	struct parent_image_info pii = { 0 };
@@ -5940,37 +5934,12 @@
 	if (!parent_spec)
 		return -ENOMEM;
 
-	ret = get_parent_info(rbd_dev, &pii);
+	ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
 	if (ret)
 		goto out_err;
 
-	dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n",
-	     __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id,
-	     pii.has_overlap, pii.overlap);
-
-	if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) {
-		/*
-		 * Either the parent never existed, or we have
-		 * record of it but the image got flattened so it no
-		 * longer has a parent.  When the parent of a
-		 * layered image disappears we immediately set the
-		 * overlap to 0.  The effect of this is that all new
-		 * requests will be treated as if the image had no
-		 * parent.
-		 *
-		 * If !pii.has_overlap, the parent image spec is not
-		 * applicable.  It's there to avoid duplication in each
-		 * snapshot record.
-		 */
-		if (rbd_dev->parent_overlap) {
-			rbd_dev->parent_overlap = 0;
-			rbd_dev_parent_put(rbd_dev);
-			pr_info("%s: clone image has been flattened\n",
-				rbd_dev->disk->disk_name);
-		}
-
+	if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap)
 		goto out;	/* No parent?  No problem. */
-	}
 
 	/* The ceph file layout needs to fit pool id in 32 bits */
 
@@ -5982,58 +5951,46 @@
 	}
 
 	/*
-	 * The parent won't change (except when the clone is
-	 * flattened, already handled that).  So we only need to
-	 * record the parent spec we have not already done so.
+	 * The parent won't change except when the clone is flattened,
+	 * so we only need to record the parent image spec once.
 	 */
-	if (!rbd_dev->parent_spec) {
-		parent_spec->pool_id = pii.pool_id;
-		if (pii.pool_ns && *pii.pool_ns) {
-			parent_spec->pool_ns = pii.pool_ns;
-			pii.pool_ns = NULL;
-		}
-		parent_spec->image_id = pii.image_id;
-		pii.image_id = NULL;
-		parent_spec->snap_id = pii.snap_id;
-
-		rbd_dev->parent_spec = parent_spec;
-		parent_spec = NULL;	/* rbd_dev now owns this */
-	}
+	parent_spec->pool_id = pii.pool_id;
+	if (pii.pool_ns && *pii.pool_ns) {
+		parent_spec->pool_ns = pii.pool_ns;
+		pii.pool_ns = NULL;
+	}
+	parent_spec->image_id = pii.image_id;
+	pii.image_id = NULL;
+	parent_spec->snap_id = pii.snap_id;
+
+	rbd_assert(!rbd_dev->parent_spec);
+	rbd_dev->parent_spec = parent_spec;
+	parent_spec = NULL;	/* rbd_dev now owns this */
 
 	/*
-	 * We always update the parent overlap.  If it's zero we issue
-	 * a warning, as we will proceed as if there was no parent.
+	 * Record the parent overlap.  If it's zero, issue a warning as
+	 * we will proceed as if there is no parent.
 	 */
-	if (!pii.overlap) {
-		if (parent_spec) {
-			/* refresh, careful to warn just once */
-			if (rbd_dev->parent_overlap)
-				rbd_warn(rbd_dev,
-				    "clone now standalone (overlap became 0)");
-		} else {
-			/* initial probe */
-			rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
-		}
-	}
+	if (!pii.overlap)
+		rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
 	rbd_dev->parent_overlap = pii.overlap;
 
 out:
 	ret = 0;
 out_err:
-	kfree(pii.pool_ns);
-	kfree(pii.image_id);
+	rbd_parent_info_cleanup(&pii);
 	rbd_spec_put(parent_spec);
 	return ret;
 }
 
-static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev,
+				    u64 *stripe_unit, u64 *stripe_count)
 {
 	struct {
 		__le64 stripe_unit;
 		__le64 stripe_count;
 	} __attribute__ ((packed)) striping_info_buf = { 0 };
 	size_t size = sizeof (striping_info_buf);
-	void *p;
 	int ret;
 
 	ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
@@ -6045,27 +6002,33 @@
 	if (ret < size)
 		return -ERANGE;
 
-	p = &striping_info_buf;
-	rbd_dev->header.stripe_unit = ceph_decode_64(&p);
-	rbd_dev->header.stripe_count = ceph_decode_64(&p);
+	*stripe_unit = le64_to_cpu(striping_info_buf.stripe_unit);
+	*stripe_count = le64_to_cpu(striping_info_buf.stripe_count);
+	dout("  stripe_unit = %llu stripe_count = %llu\n", *stripe_unit,
+	     *stripe_count);
+
 	return 0;
 }
 
-static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id)
 {
-	__le64 data_pool_id;
+	__le64 data_pool_buf;
 	int ret;
 
 	ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
 				  &rbd_dev->header_oloc, "get_data_pool",
-				  NULL, 0, &data_pool_id, sizeof(data_pool_id));
+				  NULL, 0, &data_pool_buf,
+				  sizeof(data_pool_buf));
+	dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret);
 	if (ret < 0)
 		return ret;
-	if (ret < sizeof(data_pool_id))
+	if (ret < sizeof(data_pool_buf))
 		return -EBADMSG;
 
-	rbd_dev->header.data_pool_id = le64_to_cpu(data_pool_id);
-	WARN_ON(rbd_dev->header.data_pool_id == CEPH_NOPOOL);
+	*data_pool_id = le64_to_cpu(data_pool_buf);
+	dout("  data_pool_id = %lld\n", *data_pool_id);
+	WARN_ON(*data_pool_id == CEPH_NOPOOL);
+
 	return 0;
 }
 
@@ -6257,7 +6220,8 @@
 	return ret;
 }
 
-static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
+				   struct ceph_snap_context **psnapc)
 {
 	size_t size;
 	int ret;
@@ -6318,9 +6282,7 @@
 	for (i = 0; i < snap_count; i++)
 		snapc->snaps[i] = ceph_decode_64(&p);
 
-	ceph_put_snap_context(rbd_dev->header.snapc);
-	rbd_dev->header.snapc = snapc;
-
+	*psnapc = snapc;
 	dout("  snap context seq = %llu, snap_count = %u\n",
 		(unsigned long long)seq, (unsigned int)snap_count);
 out:
@@ -6369,38 +6331,42 @@
 	return snap_name;
 }
 
-static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev,
+				  struct rbd_image_header *header,
+				  bool first_time)
 {
-	bool first_time = rbd_dev->header.object_prefix == NULL;
 	int ret;
 
-	ret = rbd_dev_v2_image_size(rbd_dev);
+	ret = _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP,
+				    first_time ? &header->obj_order : NULL,
+				    &header->image_size);
 	if (ret)
 		return ret;
 
 	if (first_time) {
-		ret = rbd_dev_v2_header_onetime(rbd_dev);
+		ret = rbd_dev_v2_header_onetime(rbd_dev, header);
 		if (ret)
 			return ret;
 	}
 
-	ret = rbd_dev_v2_snap_context(rbd_dev);
-	if (ret && first_time) {
-		kfree(rbd_dev->header.object_prefix);
-		rbd_dev->header.object_prefix = NULL;
-	}
+	ret = rbd_dev_v2_snap_context(rbd_dev, &header->snapc);
+	if (ret)
+		return ret;
 
-	return ret;
+	return 0;
 }
 
-static int rbd_dev_header_info(struct rbd_device *rbd_dev)
+static int rbd_dev_header_info(struct rbd_device *rbd_dev,
+			       struct rbd_image_header *header,
+			       bool first_time)
 {
 	rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+	rbd_assert(!header->object_prefix && !header->snapc);
 
 	if (rbd_dev->image_format == 1)
-		return rbd_dev_v1_header_info(rbd_dev);
+		return rbd_dev_v1_header_info(rbd_dev, header, first_time);
 
-	return rbd_dev_v2_header_info(rbd_dev);
+	return rbd_dev_v2_header_info(rbd_dev, header, first_time);
 }
 
 /*
@@ -6750,60 +6716,49 @@
  */
 static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
 {
-	struct rbd_image_header	*header;
-
 	rbd_dev_parent_put(rbd_dev);
 	rbd_object_map_free(rbd_dev);
 	rbd_dev_mapping_clear(rbd_dev);
 
 	/* Free dynamic fields from the header, then zero it out */
 
-	header = &rbd_dev->header;
-	ceph_put_snap_context(header->snapc);
-	kfree(header->snap_sizes);
-	kfree(header->snap_names);
-	kfree(header->object_prefix);
-	memset(header, 0, sizeof (*header));
+	rbd_image_header_cleanup(&rbd_dev->header);
 }
 
-static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
+				     struct rbd_image_header *header)
 {
 	int ret;
 
-	ret = rbd_dev_v2_object_prefix(rbd_dev);
+	ret = rbd_dev_v2_object_prefix(rbd_dev, &header->object_prefix);
 	if (ret)
-		goto out_err;
+		return ret;
 
 	/*
 	 * Get the and check features for the image.  Currently the
 	 * features are assumed to never change.
 	 */
-	ret = rbd_dev_v2_features(rbd_dev);
+	ret = _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP,
+					&header->features);
 	if (ret)
-		goto out_err;
+		return ret;
 
 	/* If the image supports fancy striping, get its parameters */
 
-	if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) {
-		ret = rbd_dev_v2_striping_info(rbd_dev);
-		if (ret < 0)
-			goto out_err;
+	if (header->features & RBD_FEATURE_STRIPINGV2) {
+		ret = rbd_dev_v2_striping_info(rbd_dev, &header->stripe_unit,
+					       &header->stripe_count);
+		if (ret)
+			return ret;
 	}
 
-	if (rbd_dev->header.features & RBD_FEATURE_DATA_POOL) {
-		ret = rbd_dev_v2_data_pool(rbd_dev);
+	if (header->features & RBD_FEATURE_DATA_POOL) {
+		ret = rbd_dev_v2_data_pool(rbd_dev, &header->data_pool_id);
 		if (ret)
-			goto out_err;
+			return ret;
 	}
 
-	rbd_init_layout(rbd_dev);
 	return 0;
-
-out_err:
-	rbd_dev->header.features = 0;
-	kfree(rbd_dev->header.object_prefix);
-	rbd_dev->header.object_prefix = NULL;
-	return ret;
 }
 
 /*
@@ -6825,7 +6780,7 @@
 		goto out_err;
 	}
 
-	parent = __rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
+	parent = __rbd_dev_create(rbd_dev->parent_spec);
 	if (!parent) {
 		ret = -ENOMEM;
 		goto out_err;
@@ -6835,8 +6790,8 @@
 	 * Images related by parent/child relationships always share
 	 * rbd_client and spec/parent_spec, so bump their refcounts.
 	 */
-	__rbd_get_client(rbd_dev->rbd_client);
-	rbd_spec_get(rbd_dev->parent_spec);
+	parent->rbd_client = __rbd_get_client(rbd_dev->rbd_client);
+	parent->spec = rbd_spec_get(rbd_dev->parent_spec);
 
 	ret = rbd_dev_image_probe(parent, depth);
 	if (ret < 0)
@@ -6929,9 +6884,10 @@
 
 static void rbd_dev_image_release(struct rbd_device *rbd_dev)
 {
-	rbd_dev_unprobe(rbd_dev);
 	if (rbd_dev->opts)
 		rbd_unregister_watch(rbd_dev);
+
+	rbd_dev_unprobe(rbd_dev);
 	rbd_dev->image_format = 0;
 	kfree(rbd_dev->spec->image_id);
 	rbd_dev->spec->image_id = NULL;
@@ -6942,6 +6898,9 @@
  * device.  If this image is the one being mapped (i.e., not a
  * parent), initiate a watch on its header object before using that
  * object to get detailed information about the rbd image.
+ *
+ * On success, returns with header_rwsem held for write if called
+ * with @depth == 0.
  */
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
 {
@@ -6974,9 +6933,14 @@
 		}
 	}
 
-	ret = rbd_dev_header_info(rbd_dev);
+	if (!depth)
+		down_write(&rbd_dev->header_rwsem);
+
+	ret = rbd_dev_header_info(rbd_dev, &rbd_dev->header, true);
 	if (ret)
-		goto err_out_watch;
+		goto err_out_probe;
+
+	rbd_init_layout(rbd_dev);
 
 	/*
 	 * If this image is the one being mapped, we have pool name and
@@ -7011,7 +6975,7 @@
 	}
 
 	if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
-		ret = rbd_dev_v2_parent_info(rbd_dev);
+		ret = rbd_dev_setup_parent(rbd_dev);
 		if (ret)
 			goto err_out_probe;
 	}
@@ -7025,10 +6989,11 @@
 	return 0;
 
 err_out_probe:
-	rbd_dev_unprobe(rbd_dev);
-err_out_watch:
+	if (!depth)
+		up_write(&rbd_dev->header_rwsem);
 	if (!depth)
 		rbd_unregister_watch(rbd_dev);
+	rbd_dev_unprobe(rbd_dev);
 err_out_format:
 	rbd_dev->image_format = 0;
 	kfree(rbd_dev->spec->image_id);
@@ -7036,6 +7001,112 @@
 	return ret;
 }
 
+static void rbd_dev_update_header(struct rbd_device *rbd_dev,
+				  struct rbd_image_header *header)
+{
+	rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+	rbd_assert(rbd_dev->header.object_prefix); /* !first_time */
+
+	if (rbd_dev->header.image_size != header->image_size) {
+		rbd_dev->header.image_size = header->image_size;
+
+		if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
+			rbd_dev->mapping.size = header->image_size;
+			rbd_dev_update_size(rbd_dev);
+		}
+	}
+
+	if (rbd_dev->spec->snap_id != CEPH_NOSNAP) {
+		/* validate mapped snapshot's EXISTS flag */
+		rbd_exists_validate(rbd_dev);
+	}
+
+	ceph_put_snap_context(rbd_dev->header.snapc);
+	rbd_dev->header.snapc = header->snapc;
+	header->snapc = NULL;
+
+	if (rbd_dev->image_format == 1) {
+		kfree(rbd_dev->header.snap_names);
+		rbd_dev->header.snap_names = header->snap_names;
+		header->snap_names = NULL;
+
+		kfree(rbd_dev->header.snap_sizes);
+		rbd_dev->header.snap_sizes = header->snap_sizes;
+		header->snap_sizes = NULL;
+	}
+}
+
+static void rbd_dev_update_parent(struct rbd_device *rbd_dev,
+				  struct parent_image_info *pii)
+{
+	if (pii->pool_id == CEPH_NOPOOL || !pii->has_overlap) {
+		/*
+		 * Either the parent never existed, or we have
+		 * record of it but the image got flattened so it no
+		 * longer has a parent.  When the parent of a
+		 * layered image disappears we immediately set the
+		 * overlap to 0.  The effect of this is that all new
+		 * requests will be treated as if the image had no
+		 * parent.
+		 *
+		 * If !pii.has_overlap, the parent image spec is not
+		 * applicable.  It's there to avoid duplication in each
+		 * snapshot record.
+		 */
+		if (rbd_dev->parent_overlap) {
+			rbd_dev->parent_overlap = 0;
+			rbd_dev_parent_put(rbd_dev);
+			pr_info("%s: clone has been flattened\n",
+				rbd_dev->disk->disk_name);
+		}
+	} else {
+		rbd_assert(rbd_dev->parent_spec);
+
+		/*
+		 * Update the parent overlap.  If it became zero, issue
+		 * a warning as we will proceed as if there is no parent.
+		 */
+		if (!pii->overlap && rbd_dev->parent_overlap)
+			rbd_warn(rbd_dev,
+				 "clone has become standalone (overlap 0)");
+		rbd_dev->parent_overlap = pii->overlap;
+	}
+}
+
+static int rbd_dev_refresh(struct rbd_device *rbd_dev)
+{
+	struct rbd_image_header	header = { 0 };
+	struct parent_image_info pii = { 0 };
+	int ret;
+
+	dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+	ret = rbd_dev_header_info(rbd_dev, &header, false);
+	if (ret)
+		goto out;
+
+	/*
+	 * If there is a parent, see if it has disappeared due to the
+	 * mapped image getting flattened.
+	 */
+	if (rbd_dev->parent) {
+		ret = rbd_dev_v2_parent_info(rbd_dev, &pii);
+		if (ret)
+			goto out;
+	}
+
+	down_write(&rbd_dev->header_rwsem);
+	rbd_dev_update_header(rbd_dev, &header);
+	if (rbd_dev->parent)
+		rbd_dev_update_parent(rbd_dev, &pii);
+	up_write(&rbd_dev->header_rwsem);
+
+out:
+	rbd_parent_info_cleanup(&pii);
+	rbd_image_header_cleanup(&header);
+	return ret;
+}
+
 static ssize_t do_rbd_add(struct bus_type *bus,
 			  const char *buf,
 			  size_t count)
@@ -7047,6 +7118,9 @@
 	struct rbd_client *rbdc;
 	int rc;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	if (!try_module_get(THIS_MODULE))
 		return -ENODEV;
 
@@ -7085,12 +7159,9 @@
 		goto err_out_rbd_dev;
 	}
 
-	down_write(&rbd_dev->header_rwsem);
 	rc = rbd_dev_image_probe(rbd_dev, 0);
-	if (rc < 0) {
-		up_write(&rbd_dev->header_rwsem);
+	if (rc < 0)
 		goto err_out_rbd_dev;
-	}
 
 	/* If we are mapping a snapshot it must be marked read-only */
 	if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
@@ -7199,6 +7270,9 @@
 	bool force = false;
 	int ret;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	dev_id = -1;
 	opt_buf[0] = '\0';
 	sscanf(buf, "%d %5s", &dev_id, opt_buf);
--- linux-ein-5.4.0.orig/drivers/block/rsxx/core.c
+++ linux-ein-5.4.0/drivers/block/rsxx/core.c
@@ -165,15 +165,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;
@@ -867,6 +869,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;
 	}
 
--- linux-ein-5.4.0.orig/drivers/block/skd_main.c
+++ linux-ein-5.4.0/drivers/block/skd_main.c
@@ -1417,7 +1417,8 @@
 	case SKD_CHECK_STATUS_REPORT_GOOD:
 	case SKD_CHECK_STATUS_REPORT_SMART_ALERT:
 		skreq->status = BLK_STS_OK;
-		blk_mq_complete_request(req);
+		if (likely(!blk_should_fake_timeout(req->q)))
+			blk_mq_complete_request(req);
 		break;
 
 	case SKD_CHECK_STATUS_BUSY_IMMINENT:
@@ -1440,7 +1441,8 @@
 	case SKD_CHECK_STATUS_REPORT_ERROR:
 	default:
 		skreq->status = BLK_STS_IOERR;
-		blk_mq_complete_request(req);
+		if (likely(!blk_should_fake_timeout(req->q)))
+			blk_mq_complete_request(req);
 		break;
 	}
 }
@@ -1560,7 +1562,8 @@
 		 */
 		if (likely(cmp_status == SAM_STAT_GOOD)) {
 			skreq->status = BLK_STS_OK;
-			blk_mq_complete_request(rq);
+			if (likely(!blk_should_fake_timeout(rq->q)))
+				blk_mq_complete_request(rq);
 		} else {
 			skd_resolve_req_exception(skdev, skreq, rq);
 		}
--- linux-ein-5.4.0.orig/drivers/block/sunvdc.c
+++ linux-ein-5.4.0/drivers/block/sunvdc.c
@@ -983,6 +983,8 @@
 	print_version();
 
 	hp = mdesc_grab();
+	if (!hp)
+		return -ENODEV;
 
 	err = -ENODEV;
 	if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
--- linux-ein-5.4.0.orig/drivers/block/virtio_blk.c
+++ linux-ein-5.4.0/drivers/block/virtio_blk.c
@@ -33,6 +33,15 @@
 } ____cacheline_aligned_in_smp;
 
 struct virtio_blk {
+	/*
+	 * This mutex must be held by anything that may run after
+	 * virtblk_remove() sets vblk->vdev to NULL.
+	 *
+	 * blk-mq, virtqueue processing, and sysfs attribute code paths are
+	 * shut down before vblk->vdev is set to NULL and therefore do not need
+	 * to hold this mutex.
+	 */
+	struct mutex vdev_mutex;
 	struct virtio_device *vdev;
 
 	/* The disk structure for the kernel. */
@@ -44,6 +53,13 @@
 	/* Process context for config space updates */
 	struct work_struct config_work;
 
+	/*
+	 * Tracks references from block_device_operations open/release and
+	 * virtio_driver probe/remove so this object can be freed once no
+	 * longer in use.
+	 */
+	refcount_t refs;
+
 	/* What host tells us, plus 2 for header & tailer. */
 	unsigned int sg_elems;
 
@@ -189,16 +205,31 @@
 	if (!range)
 		return -ENOMEM;
 
-	__rq_for_each_bio(bio, req) {
-		u64 sector = bio->bi_iter.bi_sector;
-		u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT;
-
-		range[n].flags = cpu_to_le32(flags);
-		range[n].num_sectors = cpu_to_le32(num_sectors);
-		range[n].sector = cpu_to_le64(sector);
-		n++;
+	/*
+	 * Single max discard segment means multi-range discard isn't
+	 * supported, and block layer only runs contiguity merge like
+	 * normal RW request. So we can't reply on bio for retrieving
+	 * each range info.
+	 */
+	if (queue_max_discard_segments(req->q) == 1) {
+		range[0].flags = cpu_to_le32(flags);
+		range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req));
+		range[0].sector = cpu_to_le64(blk_rq_pos(req));
+		n = 1;
+	} else {
+		__rq_for_each_bio(bio, req) {
+			u64 sector = bio->bi_iter.bi_sector;
+			u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT;
+
+			range[n].flags = cpu_to_le32(flags);
+			range[n].num_sectors = cpu_to_le32(num_sectors);
+			range[n].sector = cpu_to_le64(sector);
+			n++;
+		}
 	}
 
+	WARN_ON_ONCE(n != segments);
+
 	req->special_vec.bv_page = virt_to_page(range);
 	req->special_vec.bv_offset = offset_in_page(range);
 	req->special_vec.bv_len = sizeof(*range) * segments;
@@ -241,7 +272,8 @@
 		while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
 			struct request *req = blk_mq_rq_from_pdu(vbr);
 
-			blk_mq_complete_request(req);
+			if (likely(!blk_should_fake_timeout(req->q)))
+				blk_mq_complete_request(req);
 			req_done = true;
 		}
 		if (unlikely(virtqueue_is_broken(vq)))
@@ -339,13 +371,20 @@
 		err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
 	if (err) {
 		virtqueue_kick(vblk->vqs[qid].vq);
-		blk_mq_stop_hw_queue(hctx);
+		/* Don't stop the queue if -ENOMEM: we may have failed to
+		 * bounce the buffer due to global resource outage.
+		 */
+		if (err == -ENOSPC)
+			blk_mq_stop_hw_queue(hctx);
 		spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
-		/* Out of mem doesn't actually happen, since we fall back
-		 * to direct descriptors */
-		if (err == -ENOMEM || err == -ENOSPC)
+		switch (err) {
+		case -ENOSPC:
 			return BLK_STS_DEV_RESOURCE;
-		return BLK_STS_IOERR;
+		case -ENOMEM:
+			return BLK_STS_RESOURCE;
+		default:
+			return BLK_STS_IOERR;
+		}
 	}
 
 	if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq))
@@ -381,10 +420,55 @@
 	return err;
 }
 
+static void virtblk_get(struct virtio_blk *vblk)
+{
+	refcount_inc(&vblk->refs);
+}
+
+static void virtblk_put(struct virtio_blk *vblk)
+{
+	if (refcount_dec_and_test(&vblk->refs)) {
+		ida_simple_remove(&vd_index_ida, vblk->index);
+		mutex_destroy(&vblk->vdev_mutex);
+		kfree(vblk);
+	}
+}
+
+static int virtblk_open(struct block_device *bd, fmode_t mode)
+{
+	struct virtio_blk *vblk = bd->bd_disk->private_data;
+	int ret = 0;
+
+	mutex_lock(&vblk->vdev_mutex);
+
+	if (vblk->vdev)
+		virtblk_get(vblk);
+	else
+		ret = -ENXIO;
+
+	mutex_unlock(&vblk->vdev_mutex);
+	return ret;
+}
+
+static void virtblk_release(struct gendisk *disk, fmode_t mode)
+{
+	struct virtio_blk *vblk = disk->private_data;
+
+	virtblk_put(vblk);
+}
+
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
 	struct virtio_blk *vblk = bd->bd_disk->private_data;
+	int ret = 0;
+
+	mutex_lock(&vblk->vdev_mutex);
+
+	if (!vblk->vdev) {
+		ret = -ENXIO;
+		goto out;
+	}
 
 	/* see if the host passed in geometry config */
 	if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) {
@@ -400,12 +484,16 @@
 		geo->sectors = 1 << 5;
 		geo->cylinders = get_capacity(bd->bd_disk) >> 11;
 	}
-	return 0;
+out:
+	mutex_unlock(&vblk->vdev_mutex);
+	return ret;
 }
 
 static const struct block_device_operations virtblk_fops = {
 	.ioctl  = virtblk_ioctl,
 	.owner  = THIS_MODULE,
+	.open = virtblk_open,
+	.release = virtblk_release,
 	.getgeo = virtblk_getgeo,
 };
 
@@ -760,6 +848,10 @@
 		goto out_free_index;
 	}
 
+	/* This reference is dropped in virtblk_remove(). */
+	refcount_set(&vblk->refs, 1);
+	mutex_init(&vblk->vdev_mutex);
+
 	vblk->vdev = vdev;
 	vblk->sg_elems = sg_elems;
 
@@ -845,9 +937,17 @@
 	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
 				   struct virtio_blk_config, blk_size,
 				   &blk_size);
-	if (!err)
+	if (!err) {
+		err = blk_validate_block_size(blk_size);
+		if (err) {
+			dev_err(&vdev->dev,
+				"virtio_blk: invalid block size: 0x%x\n",
+				blk_size);
+			goto out_free_tags;
+		}
+
 		blk_queue_logical_block_size(q, blk_size);
-	else
+	} else
 		blk_size = queue_logical_block_size(q);
 
 	/* Use topology information if available */
@@ -877,11 +977,12 @@
 		blk_queue_io_opt(q, blk_size * opt_io_size);
 
 	if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
-		q->limits.discard_granularity = blk_size;
-
 		virtio_cread(vdev, struct virtio_blk_config,
 			     discard_sector_alignment, &v);
-		q->limits.discard_alignment = v ? v << SECTOR_SHIFT : 0;
+		if (v)
+			q->limits.discard_granularity = v << SECTOR_SHIFT;
+		else
+			q->limits.discard_granularity = blk_size;
 
 		virtio_cread(vdev, struct virtio_blk_config,
 			     max_discard_sectors, &v);
@@ -889,9 +990,15 @@
 
 		virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
 			     &v);
+
+		/*
+		 * max_discard_seg == 0 is out of spec but we always
+		 * handled it.
+		 */
+		if (!v)
+			v = sg_elems - 2;
 		blk_queue_max_discard_segments(q,
-					       min_not_zero(v,
-							    MAX_DISCARD_SEGMENTS));
+					       min(v, MAX_DISCARD_SEGMENTS));
 
 		blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
 	}
@@ -914,6 +1021,7 @@
 	put_disk(vblk->disk);
 out_free_vq:
 	vdev->config->del_vqs(vdev);
+	kfree(vblk->vqs);
 out_free_vblk:
 	kfree(vblk);
 out_free_index:
@@ -925,8 +1033,6 @@
 static void virtblk_remove(struct virtio_device *vdev)
 {
 	struct virtio_blk *vblk = vdev->priv;
-	int index = vblk->index;
-	int refc;
 
 	/* Make sure no work handler is accessing the device. */
 	flush_work(&vblk->config_work);
@@ -936,18 +1042,21 @@
 
 	blk_mq_free_tag_set(&vblk->tag_set);
 
+	mutex_lock(&vblk->vdev_mutex);
+
 	/* Stop all the virtqueues. */
 	vdev->config->reset(vdev);
 
-	refc = kref_read(&disk_to_dev(vblk->disk)->kobj.kref);
+	/* Virtqueues are stopped, nothing can use vblk->vdev anymore. */
+	vblk->vdev = NULL;
+
 	put_disk(vblk->disk);
 	vdev->config->del_vqs(vdev);
 	kfree(vblk->vqs);
-	kfree(vblk);
 
-	/* Only free device id if we don't have any users */
-	if (refc == 1)
-		ida_simple_remove(&vd_index_ida, index);
+	mutex_unlock(&vblk->vdev_mutex);
+
+	virtblk_put(vblk);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -955,15 +1064,18 @@
 {
 	struct virtio_blk *vblk = vdev->priv;
 
+	/* Ensure no requests in virtqueues before deleting vqs. */
+	blk_mq_freeze_queue(vblk->disk->queue);
+
 	/* Ensure we don't receive any more interrupts */
 	vdev->config->reset(vdev);
 
 	/* Make sure no work handler is accessing the device. */
 	flush_work(&vblk->config_work);
 
-	blk_mq_quiesce_queue(vblk->disk->queue);
-
 	vdev->config->del_vqs(vdev);
+	kfree(vblk->vqs);
+
 	return 0;
 }
 
@@ -978,7 +1090,7 @@
 
 	virtio_device_ready(vdev);
 
-	blk_mq_unquiesce_queue(vblk->disk->queue);
+	blk_mq_unfreeze_queue(vblk->disk->queue);
 	return 0;
 }
 #endif
--- linux-ein-5.4.0.orig/drivers/block/xen-blkback/blkback.c
+++ linux-ein-5.4.0/drivers/block/xen-blkback/blkback.c
@@ -202,7 +202,7 @@
 
 #define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))
 
-static int do_block_io_op(struct xen_blkif_ring *ring);
+static int do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags);
 static int dispatch_rw_block_io(struct xen_blkif_ring *ring,
 				struct blkif_request *req,
 				struct pending_req *pending_req);
@@ -615,6 +615,8 @@
 	struct xen_vbd *vbd = &blkif->vbd;
 	unsigned long timeout;
 	int ret;
+	bool do_eoi;
+	unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS;
 
 	set_freezable();
 	while (!kthread_should_stop()) {
@@ -639,16 +641,23 @@
 		if (timeout == 0)
 			goto purge_gnt_list;
 
+		do_eoi = ring->waiting_reqs;
+
 		ring->waiting_reqs = 0;
 		smp_mb(); /* clear flag *before* checking for work */
 
-		ret = do_block_io_op(ring);
+		ret = do_block_io_op(ring, &eoi_flags);
 		if (ret > 0)
 			ring->waiting_reqs = 1;
 		if (ret == -EACCES)
 			wait_event_interruptible(ring->shutdown_wq,
 						 kthread_should_stop());
 
+		if (do_eoi && !ring->waiting_reqs) {
+			xen_irq_lateeoi(ring->irq, eoi_flags);
+			eoi_flags |= XEN_EOI_FLAG_SPURIOUS;
+		}
+
 purge_gnt_list:
 		if (blkif->vbd.feature_gnt_persistent &&
 		    time_after(jiffies, ring->next_lru)) {
@@ -841,8 +850,11 @@
 			pages[i]->page = persistent_gnt->page;
 			pages[i]->persistent_gnt = persistent_gnt;
 		} else {
-			if (get_free_page(ring, &pages[i]->page))
-				goto out_of_memory;
+			if (get_free_page(ring, &pages[i]->page)) {
+				put_free_pages(ring, 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;
@@ -858,10 +870,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
@@ -876,7 +886,7 @@
 				pr_debug("invalid buffer -- could not remap it\n");
 				put_free_pages(ring, &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;
@@ -928,15 +938,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(ring, pages_to_gnt, segs_to_map);
-	return -ENOMEM;
+	return ret;
 }
 
 static int xen_blkbk_map_seg(struct pending_req *pending_req)
@@ -1119,7 +1132,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_ring *ring)
+__do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags)
 {
 	union blkif_back_rings *blk_rings = &ring->blk_rings;
 	struct blkif_request req;
@@ -1142,6 +1155,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;
@@ -1200,13 +1216,13 @@
 }
 
 static int
-do_block_io_op(struct xen_blkif_ring *ring)
+do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags)
 {
 	union blkif_back_rings *blk_rings = &ring->blk_rings;
 	int more_to_do;
 
 	do {
-		more_to_do = __do_block_io_op(ring);
+		more_to_do = __do_block_io_op(ring, eoi_flags);
 		if (more_to_do)
 			break;
 
--- linux-ein-5.4.0.orig/drivers/block/xen-blkback/common.h
+++ linux-ein-5.4.0/drivers/block/xen-blkback/common.h
@@ -316,6 +316,7 @@
 
 	struct work_struct	free_work;
 	unsigned int 		nr_ring_pages;
+	bool			multi_ref;
 	/* All rings for this device. */
 	struct xen_blkif_ring	*rings;
 	unsigned int		nr_rings;
--- linux-ein-5.4.0.orig/drivers/block/xen-blkback/xenbus.c
+++ linux-ein-5.4.0/drivers/block/xen-blkback/xenbus.c
@@ -171,6 +171,15 @@
 	blkif->domid = domid;
 	atomic_set(&blkif->refcnt, 1);
 	init_completion(&blkif->drain_complete);
+
+	/*
+	 * Because freeing back to the cache may be deferred, it is not
+	 * safe to unload the module (and hence destroy the cache) until
+	 * this has completed. To prevent premature unloading, take an
+	 * extra module reference here and release only when the object
+	 * has been freed back to the cache.
+	 */
+	__module_get(THIS_MODULE);
 	INIT_WORK(&blkif->free_work, xen_blkif_deferred_free);
 
 	return blkif;
@@ -220,9 +229,8 @@
 		BUG();
 	}
 
-	err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
-						    xen_blkif_be_int, 0,
-						    "blkif-backend", ring);
+	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(blkif->domid,
+			evtchn, xen_blkif_be_int, 0, "blkif-backend", ring);
 	if (err < 0) {
 		xenbus_unmap_ring_vfree(blkif->be->dev, ring->blk_ring);
 		ring->blk_rings.common.sring = NULL;
@@ -248,6 +256,7 @@
 
 		if (ring->xenblkd) {
 			kthread_stop(ring->xenblkd);
+			ring->xenblkd = NULL;
 			wake_up(&ring->shutdown_wq);
 		}
 
@@ -320,6 +329,7 @@
 
 	/* Make sure everything is drained before shutting down */
 	kmem_cache_free(xen_blkif_cachep, blkif);
+	module_put(THIS_MODULE);
 }
 
 int __init xen_blkif_interface_init(void)
@@ -634,7 +644,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;
@@ -938,14 +949,17 @@
 	for (i = 0; i < nr_grefs; i++) {
 		char ring_ref_name[RINGREF_NAME_LEN];
 
-		snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i);
+		if (blkif->multi_ref)
+			snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i);
+		else {
+			WARN_ON(i != 0);
+			snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref");
+		}
+
 		err = xenbus_scanf(XBT_NIL, dir, ring_ref_name,
 				   "%u", &ring_ref[i]);
 
 		if (err != 1) {
-			if (nr_grefs == 1)
-				break;
-
 			err = -EINVAL;
 			xenbus_dev_fatal(dev, err, "reading %s/%s",
 					 dir, ring_ref_name);
@@ -953,18 +967,6 @@
 		}
 	}
 
-	if (err != 1) {
-		WARN_ON(nr_grefs != 1);
-
-		err = xenbus_scanf(XBT_NIL, dir, "ring-ref", "%u",
-				   &ring_ref[0]);
-		if (err != 1) {
-			err = -EINVAL;
-			xenbus_dev_fatal(dev, err, "reading %s/ring-ref", dir);
-			return err;
-		}
-	}
-
 	err = -ENOMEM;
 	for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) {
 		req = kzalloc(sizeof(*req), GFP_KERNEL);
@@ -1068,10 +1070,15 @@
 		 blkif->nr_rings, blkif->blk_protocol, protocol,
 		 pers_grants ? "persistent grants" : "");
 
-	ring_page_order = xenbus_read_unsigned(dev->otherend,
-					       "ring-page-order", 0);
-
-	if (ring_page_order > xen_blkif_max_ring_order) {
+	err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-page-order", "%u",
+			   &ring_page_order);
+	if (err != 1) {
+		blkif->nr_ring_pages = 1;
+		blkif->multi_ref = false;
+	} else if (ring_page_order <= xen_blkif_max_ring_order) {
+		blkif->nr_ring_pages = 1 << ring_page_order;
+		blkif->multi_ref = true;
+	} else {
 		err = -EINVAL;
 		xenbus_dev_fatal(dev, err,
 				 "requested ring page order %d exceed max:%d",
@@ -1080,8 +1087,6 @@
 		return err;
 	}
 
-	blkif->nr_ring_pages = 1 << ring_page_order;
-
 	if (blkif->nr_rings == 1)
 		return read_per_ring_refs(&blkif->rings[0], dev->otherend);
 	else {
--- linux-ein-5.4.0.orig/drivers/block/xen-blkfront.c
+++ linux-ein-5.4.0/drivers/block/xen-blkfront.c
@@ -47,6 +47,7 @@
 #include <linux/bitmap.h>
 #include <linux/list.h>
 #include <linux/workqueue.h>
+#include <linux/sched/mm.h>
 
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -79,6 +80,7 @@
 	BLKIF_STATE_DISCONNECTED,
 	BLKIF_STATE_CONNECTED,
 	BLKIF_STATE_SUSPENDED,
+	BLKIF_STATE_ERROR,
 };
 
 struct grant {
@@ -88,6 +90,7 @@
 };
 
 enum blk_req_status {
+	REQ_PROCESSING,
 	REQ_WAITING,
 	REQ_DONE,
 	REQ_ERROR,
@@ -148,6 +151,10 @@
 module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444);
 MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring");
 
+static bool __read_mostly xen_blkif_trusted = true;
+module_param_named(trusted, xen_blkif_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define BLK_RING_SIZE(info)	\
 	__CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages)
 
@@ -208,6 +215,7 @@
 	unsigned int feature_discard:1;
 	unsigned int feature_secdiscard:1;
 	unsigned int feature_persistent:1;
+	unsigned int bounce:1;
 	unsigned int discard_granularity;
 	unsigned int discard_alignment;
 	/* Number of 4KB segments handled */
@@ -297,8 +305,8 @@
 		if (!gnt_list_entry)
 			goto out_of_memory;
 
-		if (info->feature_persistent) {
-			granted_page = alloc_page(GFP_NOIO);
+		if (info->bounce) {
+			granted_page = alloc_page(GFP_NOIO | __GFP_ZERO);
 			if (!granted_page) {
 				kfree(gnt_list_entry);
 				goto out_of_memory;
@@ -317,7 +325,7 @@
 	list_for_each_entry_safe(gnt_list_entry, n,
 	                         &rinfo->grants, node) {
 		list_del(&gnt_list_entry->node);
-		if (info->feature_persistent)
+		if (info->bounce)
 			__free_page(gnt_list_entry->page);
 		kfree(gnt_list_entry);
 		i--;
@@ -363,7 +371,7 @@
 	/* Assign a gref to this page */
 	gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
 	BUG_ON(gnt_list_entry->gref == -ENOSPC);
-	if (info->feature_persistent)
+	if (info->bounce)
 		grant_foreign_access(gnt_list_entry, info);
 	else {
 		/* Grant access to the GFN passed by the caller */
@@ -387,7 +395,7 @@
 	/* Assign a gref to this page */
 	gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
 	BUG_ON(gnt_list_entry->gref == -ENOSPC);
-	if (!info->feature_persistent) {
+	if (!info->bounce) {
 		struct page *indirect_page;
 
 		/* Fetch a pre-allocated page to use for indirect grefs */
@@ -532,10 +540,10 @@
 
 	id = get_id_from_freelist(rinfo);
 	rinfo->shadow[id].request = req;
-	rinfo->shadow[id].status = REQ_WAITING;
+	rinfo->shadow[id].status = REQ_PROCESSING;
 	rinfo->shadow[id].associated_id = NO_ASSOCIATED_ID;
 
-	(*ring_req)->u.rw.id = id;
+	rinfo->shadow[id].req.u.rw.id = id;
 
 	return id;
 }
@@ -543,11 +551,12 @@
 static int blkif_queue_discard_req(struct request *req, struct blkfront_ring_info *rinfo)
 {
 	struct blkfront_info *info = rinfo->dev_info;
-	struct blkif_request *ring_req;
+	struct blkif_request *ring_req, *final_ring_req;
 	unsigned long id;
 
 	/* Fill out a communications ring structure. */
-	id = blkif_ring_get_request(rinfo, req, &ring_req);
+	id = blkif_ring_get_request(rinfo, req, &final_ring_req);
+	ring_req = &rinfo->shadow[id].req;
 
 	ring_req->operation = BLKIF_OP_DISCARD;
 	ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
@@ -558,8 +567,9 @@
 	else
 		ring_req->u.discard.flag = 0;
 
-	/* Keep a private copy so we can reissue requests when recovering. */
-	rinfo->shadow[id].req = *ring_req;
+	/* Copy the request to the ring page. */
+	*final_ring_req = *ring_req;
+	rinfo->shadow[id].status = REQ_WAITING;
 
 	return 0;
 }
@@ -692,6 +702,7 @@
 {
 	struct blkfront_info *info = rinfo->dev_info;
 	struct blkif_request *ring_req, *extra_ring_req = NULL;
+	struct blkif_request *final_ring_req, *final_extra_ring_req = NULL;
 	unsigned long id, extra_id = NO_ASSOCIATED_ID;
 	bool require_extra_req = false;
 	int i;
@@ -699,7 +710,7 @@
 		.grant_idx = 0,
 		.segments = NULL,
 		.rinfo = rinfo,
-		.need_copy = rq_data_dir(req) && info->feature_persistent,
+		.need_copy = rq_data_dir(req) && info->bounce,
 	};
 
 	/*
@@ -736,7 +747,8 @@
 	}
 
 	/* Fill out a communications ring structure. */
-	id = blkif_ring_get_request(rinfo, req, &ring_req);
+	id = blkif_ring_get_request(rinfo, req, &final_ring_req);
+	ring_req = &rinfo->shadow[id].req;
 
 	num_sg = blk_rq_map_sg(req->q, req, rinfo->shadow[id].sg);
 	num_grant = 0;
@@ -767,7 +779,8 @@
 		ring_req->u.rw.handle = info->handle;
 		ring_req->operation = rq_data_dir(req) ?
 			BLKIF_OP_WRITE : BLKIF_OP_READ;
-		if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) {
+		if (req_op(req) == REQ_OP_FLUSH ||
+		    (req_op(req) == REQ_OP_WRITE && (req->cmd_flags & REQ_FUA))) {
 			/*
 			 * Ideally we can do an unordered flush-to-disk.
 			 * In case the backend onlysupports barriers, use that.
@@ -787,7 +800,9 @@
 		ring_req->u.rw.nr_segments = num_grant;
 		if (unlikely(require_extra_req)) {
 			extra_id = blkif_ring_get_request(rinfo, req,
-							  &extra_ring_req);
+							  &final_extra_ring_req);
+			extra_ring_req = &rinfo->shadow[extra_id].req;
+
 			/*
 			 * Only the first request contains the scatter-gather
 			 * list.
@@ -829,10 +844,13 @@
 	if (setup.segments)
 		kunmap_atomic(setup.segments);
 
-	/* Keep a private copy so we can reissue requests when recovering. */
-	rinfo->shadow[id].req = *ring_req;
-	if (unlikely(require_extra_req))
-		rinfo->shadow[extra_id].req = *extra_ring_req;
+	/* Copy request(s) to the ring page. */
+	*final_ring_req = *ring_req;
+	rinfo->shadow[id].status = REQ_WAITING;
+	if (unlikely(require_extra_req)) {
+		*final_extra_ring_req = *extra_ring_req;
+		rinfo->shadow[extra_id].status = REQ_WAITING;
+	}
 
 	if (new_persistent_gnts)
 		gnttab_free_grant_references(setup.gref_head);
@@ -935,7 +953,8 @@
 	if (info->feature_discard) {
 		blk_queue_flag_set(QUEUE_FLAG_DISCARD, rq);
 		blk_queue_max_discard_sectors(rq, get_capacity(gd));
-		rq->limits.discard_granularity = info->discard_granularity;
+		rq->limits.discard_granularity = info->discard_granularity ?:
+						 info->physical_sector_size;
 		rq->limits.discard_alignment = info->discard_alignment;
 		if (info->feature_secdiscard)
 			blk_queue_flag_set(QUEUE_FLAG_SECERASE, rq);
@@ -1013,11 +1032,12 @@
 {
 	blk_queue_write_cache(info->rq, info->feature_flush ? true : false,
 			      info->feature_fua ? true : false);
-	pr_info("blkfront: %s: %s %s %s %s %s\n",
+	pr_info("blkfront: %s: %s %s %s %s %s %s %s\n",
 		info->gd->disk_name, flush_info(info),
 		"persistent grants:", info->feature_persistent ?
 		"enabled;" : "disabled;", "indirect descriptors:",
-		info->max_indirect_segments ? "enabled;" : "disabled;");
+		info->max_indirect_segments ? "enabled;" : "disabled;",
+		"bounce buffer:", info->bounce ? "enabled" : "disabled;");
 }
 
 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -1113,8 +1133,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;
@@ -1252,7 +1272,7 @@
 	if (!list_empty(&rinfo->indirect_pages)) {
 		struct page *indirect_page, *n;
 
-		BUG_ON(info->feature_persistent);
+		BUG_ON(info->bounce);
 		list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) {
 			list_del(&indirect_page->lru);
 			__free_page(indirect_page);
@@ -1269,7 +1289,7 @@
 							  0, 0UL);
 				rinfo->persistent_gnts_c--;
 			}
-			if (info->feature_persistent)
+			if (info->bounce)
 				__free_page(persistent_gnt->page);
 			kfree(persistent_gnt);
 		}
@@ -1290,7 +1310,7 @@
 		for (j = 0; j < segs; j++) {
 			persistent_gnt = rinfo->shadow[i].grants_used[j];
 			gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
-			if (info->feature_persistent)
+			if (info->bounce)
 				__free_page(persistent_gnt->page);
 			kfree(persistent_gnt);
 		}
@@ -1331,7 +1351,8 @@
 			rinfo->ring_ref[i] = GRANT_INVALID_REF;
 		}
 	}
-	free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
+	free_pages_exact(rinfo->ring.sring,
+			 info->nr_ring_pages * XEN_PAGE_SIZE);
 	rinfo->ring.sring = NULL;
 
 	if (rinfo->irq)
@@ -1405,8 +1426,8 @@
 static int blkif_get_final_status(enum blk_req_status s1,
 				  enum blk_req_status s2)
 {
-	BUG_ON(s1 == REQ_WAITING);
-	BUG_ON(s2 == REQ_WAITING);
+	BUG_ON(s1 < REQ_DONE);
+	BUG_ON(s2 < REQ_DONE);
 
 	if (s1 == REQ_ERROR || s2 == REQ_ERROR)
 		return BLKIF_RSP_ERROR;
@@ -1415,9 +1436,15 @@
 	return BLKIF_RSP_OKAY;
 }
 
-static bool blkif_completion(unsigned long *id,
-			     struct blkfront_ring_info *rinfo,
-			     struct blkif_response *bret)
+/*
+ * Return values:
+ *  1 response processed.
+ *  0 missing further responses.
+ * -1 error while processing.
+ */
+static int blkif_completion(unsigned long *id,
+			    struct blkfront_ring_info *rinfo,
+			    struct blkif_response *bret)
 {
 	int i = 0;
 	struct scatterlist *sg;
@@ -1439,8 +1466,8 @@
 		s->status = blkif_rsp_to_req_status(bret->status);
 
 		/* Wait the second response if not yet here. */
-		if (s2->status == REQ_WAITING)
-			return false;
+		if (s2->status < REQ_DONE)
+			return 0;
 
 		bret->status = blkif_get_final_status(s->status,
 						      s2->status);
@@ -1473,7 +1500,7 @@
 	data.s = s;
 	num_sg = s->num_sg;
 
-	if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
+	if (bret->operation == BLKIF_OP_READ && info->bounce) {
 		for_each_sg(s->sg, sg, num_sg, i) {
 			BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
@@ -1491,47 +1518,48 @@
 	}
 	/* Add the persistent grant into the list of free grants */
 	for (i = 0; i < num_grant; i++) {
-		if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
+		if (!gnttab_try_end_foreign_access(s->grants_used[i]->gref)) {
 			/*
 			 * If the grant is still mapped by the backend (the
 			 * backend has chosen to make this grant persistent)
 			 * we add it at the head of the list, so it will be
 			 * reused first.
 			 */
-			if (!info->feature_persistent)
-				pr_alert_ratelimited("backed has not unmapped grant: %u\n",
-						     s->grants_used[i]->gref);
+			if (!info->feature_persistent) {
+				pr_alert("backed has not unmapped grant: %u\n",
+					 s->grants_used[i]->gref);
+				return -1;
+			}
 			list_add(&s->grants_used[i]->node, &rinfo->grants);
 			rinfo->persistent_gnts_c++;
 		} else {
 			/*
-			 * If the grant is not mapped by the backend we end the
-			 * foreign access and add it to the tail of the list,
-			 * so it will not be picked again unless we run out of
-			 * persistent grants.
+			 * If the grant is not mapped by the backend we add it
+			 * to the tail of the list, so it will not be picked
+			 * again unless we run out of persistent grants.
 			 */
-			gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
 			s->grants_used[i]->gref = GRANT_INVALID_REF;
 			list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
 		}
 	}
 	if (s->req.operation == BLKIF_OP_INDIRECT) {
 		for (i = 0; i < INDIRECT_GREFS(num_grant); i++) {
-			if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) {
-				if (!info->feature_persistent)
-					pr_alert_ratelimited("backed has not unmapped grant: %u\n",
-							     s->indirect_grants[i]->gref);
+			if (!gnttab_try_end_foreign_access(s->indirect_grants[i]->gref)) {
+				if (!info->feature_persistent) {
+					pr_alert("backed has not unmapped grant: %u\n",
+						 s->indirect_grants[i]->gref);
+					return -1;
+				}
 				list_add(&s->indirect_grants[i]->node, &rinfo->grants);
 				rinfo->persistent_gnts_c++;
 			} else {
 				struct page *indirect_page;
 
-				gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL);
 				/*
 				 * Add the used indirect page back to the list of
 				 * available pages for indirect grefs.
 				 */
-				if (!info->feature_persistent) {
+				if (!info->bounce) {
 					indirect_page = s->indirect_grants[i]->page;
 					list_add(&indirect_page->lru, &rinfo->indirect_pages);
 				}
@@ -1541,71 +1569,103 @@
 		}
 	}
 
-	return true;
+	return 1;
 }
 
 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_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
 	struct blkfront_info *info = rinfo->dev_info;
+	unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
 
-	if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+	if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
 		return IRQ_HANDLED;
+	}
 
 	spin_lock_irqsave(&rinfo->ring_lock, flags);
  again:
-	rp = rinfo->ring.sring->rsp_prod;
-	rmb(); /* Ensure we see queued responses up to 'rp'. */
+	rp = READ_ONCE(rinfo->ring.sring->rsp_prod);
+	virt_rmb(); /* Ensure we see queued responses up to 'rp'. */
+	if (RING_RESPONSE_PROD_OVERFLOW(&rinfo->ring, rp)) {
+		pr_alert("%s: illegal number of responses %u\n",
+			 info->gd->disk_name, rp - rinfo->ring.rsp_cons);
+		goto err;
+	}
 
 	for (i = rinfo->ring.rsp_cons; i != rp; i++) {
 		unsigned long id;
+		unsigned int op;
+
+		eoiflag = 0;
+
+		RING_COPY_RESPONSE(&rinfo->ring, i, &bret);
+		id = bret.id;
 
-		bret = RING_GET_RESPONSE(&rinfo->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 (rinfo->shadow[id].status != REQ_WAITING) {
+			pr_alert("%s: response references no pending request\n",
+				 info->gd->disk_name);
+			goto err;
+		}
+
+		rinfo->shadow[id].status = REQ_PROCESSING;
 		req  = rinfo->shadow[id].request;
 
-		if (bret->operation != BLKIF_OP_DISCARD) {
+		op = rinfo->shadow[id].req.operation;
+		if (op == BLKIF_OP_INDIRECT)
+			op = rinfo->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) {
+			int ret;
+
 			/*
 			 * We may need to wait for an extra response if the
 			 * I/O request is split in 2
 			 */
-			if (!blkif_completion(&id, rinfo, bret))
+			ret = blkif_completion(&id, rinfo, &bret);
+			if (!ret)
 				continue;
+			if (unlikely(ret < 0))
+				goto err;
 		}
 
 		if (add_id_to_freelist(rinfo, 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;
 		}
 
-		if (bret->status == BLKIF_RSP_OKAY)
+		if (bret.status == BLKIF_RSP_OKAY)
 			blkif_req(req)->error = BLK_STS_OK;
 		else
 			blkif_req(req)->error = BLK_STS_IOERR;
 
-		switch (bret->operation) {
+		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));
 				blkif_req(req)->error = BLK_STS_NOTSUPP;
 				info->feature_discard = 0;
 				info->feature_secdiscard = 0;
@@ -1615,15 +1675,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));
 				blkif_req(req)->error = BLK_STS_NOTSUPP;
 			}
-			if (unlikely(bret->status == BLKIF_RSP_ERROR &&
+			if (unlikely(bret.status == BLKIF_RSP_ERROR &&
 				     rinfo->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));
 				blkif_req(req)->error = BLK_STS_NOTSUPP;
 			}
 			if (unlikely(blkif_req(req)->error)) {
@@ -1636,16 +1696,18 @@
 			/* 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);
 
 			break;
 		default:
 			BUG();
 		}
 
-		blk_mq_complete_request(req);
+		if (likely(!blk_should_fake_timeout(req->q)))
+			blk_mq_complete_request(req);
 	}
 
 	rinfo->ring.rsp_cons = i;
@@ -1662,6 +1724,18 @@
 
 	spin_unlock_irqrestore(&rinfo->ring_lock, flags);
 
+	xen_irq_lateeoi(irq, eoiflag);
+
+	return IRQ_HANDLED;
+
+ err:
+	info->connected = BLKIF_STATE_ERROR;
+
+	spin_unlock_irqrestore(&rinfo->ring_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;
 }
 
@@ -1678,8 +1752,7 @@
 	for (i = 0; i < info->nr_ring_pages; i++)
 		rinfo->ring_ref[i] = GRANT_INVALID_REF;
 
-	sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
-						       get_order(ring_size));
+	sring = alloc_pages_exact(ring_size, GFP_NOIO | __GFP_ZERO);
 	if (!sring) {
 		xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
 		return -ENOMEM;
@@ -1689,7 +1762,7 @@
 
 	err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
 	if (err < 0) {
-		free_pages((unsigned long)sring, get_order(ring_size));
+		free_pages_exact(sring, ring_size);
 		rinfo->ring.sring = NULL;
 		goto fail;
 	}
@@ -1700,8 +1773,8 @@
 	if (err)
 		goto fail;
 
-	err = bind_evtchn_to_irqhandler(rinfo->evtchn, blkif_interrupt, 0,
-					"blkif", rinfo);
+	err = bind_evtchn_to_irqhandler_lateeoi(rinfo->evtchn, blkif_interrupt,
+						0, "blkif", rinfo);
 	if (err <= 0) {
 		xenbus_dev_fatal(dev, err,
 				 "bind_evtchn_to_irqhandler failed");
@@ -1782,6 +1855,10 @@
 	if (!info)
 		return -ENODEV;
 
+	/* Check if backend is trusted. */
+	info->bounce = !xen_blkif_trusted ||
+		       !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
 	max_page_order = xenbus_read_unsigned(info->xbdev->otherend,
 					      "max-ring-page-order", 0);
 	ring_page_order = min(xen_blkif_max_ring_order, max_page_order);
@@ -2168,19 +2245,12 @@
 
 static void blkfront_setup_discard(struct blkfront_info *info)
 {
-	int err;
-	unsigned int discard_granularity;
-	unsigned int discard_alignment;
-
 	info->feature_discard = 1;
-	err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-		"discard-granularity", "%u", &discard_granularity,
-		"discard-alignment", "%u", &discard_alignment,
-		NULL);
-	if (!err) {
-		info->discard_granularity = discard_granularity;
-		info->discard_alignment = discard_alignment;
-	}
+	info->discard_granularity = xenbus_read_unsigned(info->xbdev->otherend,
+							 "discard-granularity",
+							 0);
+	info->discard_alignment = xenbus_read_unsigned(info->xbdev->otherend,
+						       "discard-alignment", 0);
 	info->feature_secdiscard =
 		!!xenbus_read_unsigned(info->xbdev->otherend, "discard-secure",
 				       0);
@@ -2188,10 +2258,12 @@
 
 static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
 {
-	unsigned int psegs, grants;
+	unsigned int psegs, grants, memflags;
 	int err, i;
 	struct blkfront_info *info = rinfo->dev_info;
 
+	memflags = memalloc_noio_save();
+
 	if (info->max_indirect_segments == 0) {
 		if (!HAS_EXTRA_REQ)
 			grants = BLKIF_MAX_SEGMENTS_PER_REQUEST;
@@ -2213,17 +2285,18 @@
 	if (err)
 		goto out_of_memory;
 
-	if (!info->feature_persistent && info->max_indirect_segments) {
+	if (!info->bounce && info->max_indirect_segments) {
 		/*
-		 * We are using indirect descriptors but not persistent
-		 * grants, we need to allocate a set of pages that can be
+		 * We are using indirect descriptors but don't have a bounce
+		 * buffer, we need to allocate a set of pages that can be
 		 * used for mapping indirect grefs
 		 */
 		int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info);
 
 		BUG_ON(!list_empty(&rinfo->indirect_pages));
 		for (i = 0; i < num; i++) {
-			struct page *indirect_page = alloc_page(GFP_NOIO);
+			struct page *indirect_page = alloc_page(GFP_KERNEL |
+			                                        __GFP_ZERO);
 			if (!indirect_page)
 				goto out_of_memory;
 			list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2234,15 +2307,15 @@
 		rinfo->shadow[i].grants_used =
 			kvcalloc(grants,
 				 sizeof(rinfo->shadow[i].grants_used[0]),
-				 GFP_NOIO);
+				 GFP_KERNEL);
 		rinfo->shadow[i].sg = kvcalloc(psegs,
 					       sizeof(rinfo->shadow[i].sg[0]),
-					       GFP_NOIO);
+					       GFP_KERNEL);
 		if (info->max_indirect_segments)
 			rinfo->shadow[i].indirect_grants =
 				kvcalloc(INDIRECT_GREFS(grants),
 					 sizeof(rinfo->shadow[i].indirect_grants[0]),
-					 GFP_NOIO);
+					 GFP_KERNEL);
 		if ((rinfo->shadow[i].grants_used == NULL) ||
 			(rinfo->shadow[i].sg == NULL) ||
 		     (info->max_indirect_segments &&
@@ -2251,6 +2324,7 @@
 		sg_init_table(rinfo->shadow[i].sg, psegs);
 	}
 
+	memalloc_noio_restore(memflags);
 
 	return 0;
 
@@ -2270,6 +2344,9 @@
 			__free_page(indirect_page);
 		}
 	}
+
+	memalloc_noio_restore(memflags);
+
 	return -ENOMEM;
 }
 
@@ -2311,6 +2388,8 @@
 	info->feature_persistent =
 		!!xenbus_read_unsigned(info->xbdev->otherend,
 				       "feature-persistent", 0);
+	if (info->feature_persistent)
+		info->bounce = true;
 
 	indirect_segments = xenbus_read_unsigned(info->xbdev->otherend,
 					"feature-max-indirect-segments", 0);
@@ -2668,11 +2747,10 @@
 		list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
 					 node) {
 			if (gnt_list_entry->gref == GRANT_INVALID_REF ||
-			    gnttab_query_foreign_access(gnt_list_entry->gref))
+			    !gnttab_try_end_foreign_access(gnt_list_entry->gref))
 				continue;
 
 			list_del(&gnt_list_entry->node);
-			gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL);
 			rinfo->persistent_gnts_c--;
 			gnt_list_entry->gref = GRANT_INVALID_REF;
 			list_add_tail(&gnt_list_entry->node, &rinfo->grants);
@@ -2687,6 +2765,13 @@
 	struct blkfront_info *info;
 	bool need_schedule_work = false;
 
+	/*
+	 * Note that when using bounce buffers but not persistent grants
+	 * there's no need to run blkfront_delay_work because grants are
+	 * revoked in blkif_completion or else an error is reported and the
+	 * connection is closed.
+	 */
+
 	mutex_lock(&blkfront_mutex);
 
 	list_for_each_entry(info, &info_list, info_list) {
--- linux-ein-5.4.0.orig/drivers/block/zram/zram_drv.c
+++ linux-ein-5.4.0/drivers/block/zram/zram_drv.c
@@ -626,8 +626,8 @@
 	struct bio bio;
 	struct bio_vec bio_vec;
 	struct page *page;
-	ssize_t ret;
-	int mode;
+	ssize_t ret = len;
+	int mode, err;
 	unsigned long blk_idx = 0;
 
 	if (sysfs_streq(buf, "idle"))
@@ -719,12 +719,17 @@
 		 * XXX: A single page IO would be inefficient for write
 		 * but it would be not bad as starter.
 		 */
-		ret = submit_bio_wait(&bio);
-		if (ret) {
+		err = submit_bio_wait(&bio);
+		if (err) {
 			zram_slot_lock(zram, index);
 			zram_clear_flag(zram, index, ZRAM_UNDER_WB);
 			zram_clear_flag(zram, index, ZRAM_IDLE);
 			zram_slot_unlock(zram, index);
+			/*
+			 * Return last IO error unless every IO were
+			 * not suceeded.
+			 */
+			ret = err;
 			continue;
 		}
 
@@ -762,7 +767,6 @@
 
 	if (blk_idx)
 		free_block_bdev(zram, blk_idx);
-	ret = len;
 	__free_page(page);
 release_init_lock:
 	up_read(&zram->init_lock);
@@ -897,7 +901,7 @@
 			zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.',
 			zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.');
 
-		if (count < copied) {
+		if (count <= copied) {
 			zram_slot_unlock(zram, index);
 			break;
 		}
@@ -1073,7 +1077,7 @@
 			zram->limit_pages << PAGE_SHIFT,
 			max_used << PAGE_SHIFT,
 			(u64)atomic64_read(&zram->stats.same_pages),
-			pool_stats.pages_compacted,
+			atomic_long_read(&pool_stats.pages_compacted),
 			(u64)atomic64_read(&zram->stats.huge_pages));
 	up_read(&zram->init_lock);
 
@@ -2024,7 +2028,8 @@
 		return ret;
 	return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
 }
-static CLASS_ATTR_RO(hot_add);
+static struct class_attribute class_attr_hot_add =
+	__ATTR(hot_add, 0400, hot_add_show, NULL);
 
 static ssize_t hot_remove_store(struct class *class,
 			struct class_attribute *attr,
--- linux-ein-5.4.0.orig/drivers/bluetooth/Kconfig
+++ linux-ein-5.4.0/drivers/bluetooth/Kconfig
@@ -167,6 +167,17 @@
 
 	  Say Y here to compile support for HCILL protocol.
 
+config BT_HCIUART_IBS
+	bool "HCI_IBS protocol support"
+	depends on BT_HCIUART
+	default n
+	help
+	  HCI_IBS (HCI In-Band Sleep) is a serial protocol for communication
+	  between Bluetooth device and host. This protocol is required for
+	  UART clock control for some Qualcomm Bluetooth devices.
+
+	  Say Y here to compile support for HCI_IBS protocol.
+
 config BT_HCIUART_3WIRE
 	bool "Three-wire UART (H5) protocol support"
 	depends on BT_HCIUART
--- linux-ein-5.4.0.orig/drivers/bluetooth/Makefile
+++ linux-ein-5.4.0/drivers/bluetooth/Makefile
@@ -39,6 +39,7 @@
 hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
 hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
 hci_uart-$(CONFIG_BT_HCIUART_LL)	+= hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_IBS)	+= hci_ibs.o
 hci_uart-$(CONFIG_BT_HCIUART_ATH3K)	+= hci_ath.o
 hci_uart-$(CONFIG_BT_HCIUART_3WIRE)	+= hci_h5.o
 hci_uart-$(CONFIG_BT_HCIUART_INTEL)	+= hci_intel.o
--- linux-ein-5.4.0.orig/drivers/bluetooth/bfusb.c
+++ linux-ein-5.4.0/drivers/bluetooth/bfusb.c
@@ -629,6 +629,9 @@
 	data->bulk_out_ep   = bulk_out_ep->desc.bEndpointAddress;
 	data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
 
+	if (!data->bulk_pkt_size)
+		goto done;
+
 	rwlock_init(&data->lock);
 
 	data->reassembly = NULL;
--- linux-ein-5.4.0.orig/drivers/bluetooth/btbcm.c
+++ linux-ein-5.4.0/drivers/bluetooth/btbcm.c
@@ -329,6 +329,7 @@
 	{ 0x410e, "BCM43341B0"	},	/* 002.001.014 */
 	{ 0x4204, "BCM2076B1"	},	/* 002.002.004 */
 	{ 0x4406, "BCM4324B3"	},	/* 002.004.006 */
+	{ 0x4606, "BCM4324B5"	},	/* 002.006.006 */
 	{ 0x6109, "BCM4335C0"	},	/* 003.001.009 */
 	{ 0x610c, "BCM4354"	},	/* 003.001.012 */
 	{ 0x2122, "BCM4343A0"	},	/* 001.001.034 */
@@ -343,6 +344,7 @@
 };
 
 static const struct bcm_subver_table bcm_usb_subver_table[] = {
+	{ 0x2105, "BCM20703A1"	},	/* 001.001.005 */
 	{ 0x210b, "BCM43142A0"	},	/* 001.001.011 */
 	{ 0x2112, "BCM4314A0"	},	/* 001.001.018 */
 	{ 0x2118, "BCM20702A0"	},	/* 001.001.024 */
@@ -440,6 +442,12 @@
 
 	set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
 
+	/* Some devices ship with the controller default address.
+	 * Allow the bootloader to set a valid address through the
+	 * device tree.
+	 */
+	set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(btbcm_finalize);
--- linux-ein-5.4.0.orig/drivers/bluetooth/btmrvl_sdio.c
+++ linux-ein-5.4.0/drivers/bluetooth/btmrvl_sdio.c
@@ -328,7 +328,7 @@
 
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
 	.helper         = NULL,
-	.firmware       = "mrvl/sd8977_uapsta.bin",
+	.firmware       = "mrvl/sdsd8977_combo_v2.bin",
 	.reg            = &btmrvl_reg_8977,
 	.support_pscan_win_report = true,
 	.sd_blksz_fw_dl = 256,
@@ -346,7 +346,7 @@
 
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
 	.helper         = NULL,
-	.firmware       = "mrvl/sd8997_uapsta.bin",
+	.firmware       = "mrvl/sdsd8997_combo_v4.bin",
 	.reg            = &btmrvl_reg_8997,
 	.support_pscan_win_report = true,
 	.sd_blksz_fw_dl = 256,
@@ -1831,6 +1831,6 @@
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
-MODULE_FIRMWARE("mrvl/sd8977_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sdsd8977_combo_v2.bin");
 MODULE_FIRMWARE("mrvl/sd8987_uapsta.bin");
-MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sdsd8997_combo_v4.bin");
--- linux-ein-5.4.0.orig/drivers/bluetooth/btmtksdio.c
+++ linux-ein-5.4.0/drivers/bluetooth/btmtksdio.c
@@ -684,7 +684,7 @@
 	const u8 *fw_ptr;
 	size_t fw_size;
 	int err, dlen;
-	u8 flag;
+	u8 flag, param;
 
 	err = request_firmware(&fw, fwname, &hdev->dev);
 	if (err < 0) {
@@ -692,6 +692,20 @@
 		return err;
 	}
 
+	/* Power on data RAM the firmware relies on. */
+	param = 1;
+	wmt_params.op = MTK_WMT_FUNC_CTRL;
+	wmt_params.flag = 3;
+	wmt_params.dlen = sizeof(param);
+	wmt_params.data = &param;
+	wmt_params.status = NULL;
+
+	err = mtk_hci_wmt_sync(hdev, &wmt_params);
+	if (err < 0) {
+		bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
+		goto free_fw;
+	}
+
 	fw_ptr = fw->data;
 	fw_size = fw->size;
 
@@ -966,6 +980,8 @@
 	hdev->manufacturer = 70;
 	set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
 
+	sdio_set_drvdata(func, bdev);
+
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		dev_err(&func->dev, "Can't register HCI device\n");
@@ -973,8 +989,6 @@
 		return err;
 	}
 
-	sdio_set_drvdata(func, bdev);
-
 	/* pm_runtime_enable would be done after the firmware is being
 	 * downloaded because the core layer probably already enables
 	 * runtime PM for this func such as the case host->caps &
@@ -1027,6 +1041,8 @@
 	if (!bdev)
 		return 0;
 
+	sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+
 	sdio_claim_host(bdev->func);
 
 	sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
--- linux-ein-5.4.0.orig/drivers/bluetooth/btmtkuart.c
+++ linux-ein-5.4.0/drivers/bluetooth/btmtkuart.c
@@ -158,8 +158,10 @@
 	int err;
 
 	hlen = sizeof(*hdr) + wmt_params->dlen;
-	if (hlen > 255)
-		return -EINVAL;
+	if (hlen > 255) {
+		err = -EINVAL;
+		goto err_free_skb;
+	}
 
 	hdr = (struct mtk_wmt_hdr *)&wc;
 	hdr->dir = 1;
@@ -173,7 +175,7 @@
 	err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
 	if (err < 0) {
 		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
-		return err;
+		goto err_free_skb;
 	}
 
 	/* The vendor specific WMT commands are all answered by a vendor
@@ -190,13 +192,14 @@
 	if (err == -EINTR) {
 		bt_dev_err(hdev, "Execution of wmt command interrupted");
 		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
-		return err;
+		goto err_free_skb;
 	}
 
 	if (err) {
 		bt_dev_err(hdev, "Execution of wmt command timed out");
 		clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
-		return -ETIMEDOUT;
+		err = -ETIMEDOUT;
+		goto err_free_skb;
 	}
 
 	/* Parse and handle the return WMT event */
@@ -468,7 +471,7 @@
 	return data;
 }
 
-static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
+static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
 {
 	struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
 	const unsigned char *p_left = data, *p_h4;
@@ -507,25 +510,20 @@
 			bt_dev_err(bdev->hdev,
 				   "Frame reassembly failed (%d)", err);
 			bdev->rx_skb = NULL;
-			return err;
+			return;
 		}
 
 		sz_left -= sz_h4;
 		p_left += sz_h4;
 	}
-
-	return 0;
 }
 
 static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data,
 				 size_t count)
 {
 	struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
-	int err;
 
-	err = btmtkuart_recv(bdev->hdev, data, count);
-	if (err < 0)
-		return err;
+	btmtkuart_recv(bdev->hdev, data, count);
 
 	bdev->hdev->stat.byte_rx += count;
 
@@ -1015,7 +1013,7 @@
 	if (btmtkuart_is_standalone(bdev)) {
 		err = clk_prepare_enable(bdev->osc);
 		if (err < 0)
-			return err;
+			goto err_hci_free_dev;
 
 		if (bdev->boot) {
 			gpiod_set_value_cansleep(bdev->boot, 1);
@@ -1028,10 +1026,8 @@
 
 		/* Power on */
 		err = regulator_enable(bdev->vcc);
-		if (err < 0) {
-			clk_disable_unprepare(bdev->osc);
-			return err;
-		}
+		if (err < 0)
+			goto err_clk_disable_unprepare;
 
 		/* Reset if the reset-gpios is available otherwise the board
 		 * -level design should be guaranteed.
@@ -1063,7 +1059,6 @@
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		dev_err(&serdev->dev, "Can't register HCI device\n");
-		hci_free_dev(hdev);
 		goto err_regulator_disable;
 	}
 
@@ -1072,6 +1067,11 @@
 err_regulator_disable:
 	if (btmtkuart_is_standalone(bdev))
 		regulator_disable(bdev->vcc);
+err_clk_disable_unprepare:
+	if (btmtkuart_is_standalone(bdev))
+		clk_disable_unprepare(bdev->osc);
+err_hci_free_dev:
+	hci_free_dev(hdev);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/bluetooth/btqcomsmd.c
+++ linux-ein-5.4.0/drivers/bluetooth/btqcomsmd.c
@@ -122,6 +122,21 @@
 	return 0;
 }
 
+static int btqcomsmd_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+{
+	int ret;
+
+	ret = qca_set_bdaddr_rome(hdev, bdaddr);
+	if (ret)
+		return ret;
+
+	/* The firmware stops responding for a while after setting the bdaddr,
+	 * causing timeouts for subsequent commands. Sleep a bit to avoid this.
+	 */
+	usleep_range(1000, 10000);
+	return 0;
+}
+
 static int btqcomsmd_probe(struct platform_device *pdev)
 {
 	struct btqcomsmd *btq;
@@ -142,12 +157,16 @@
 
 	btq->cmd_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_CMD",
 						   btqcomsmd_cmd_callback, btq);
-	if (IS_ERR(btq->cmd_channel))
-		return PTR_ERR(btq->cmd_channel);
+	if (IS_ERR(btq->cmd_channel)) {
+		ret = PTR_ERR(btq->cmd_channel);
+		goto destroy_acl_channel;
+	}
 
 	hdev = hci_alloc_dev();
-	if (!hdev)
-		return -ENOMEM;
+	if (!hdev) {
+		ret = -ENOMEM;
+		goto destroy_cmd_channel;
+	}
 
 	hci_set_drvdata(hdev, btq);
 	btq->hdev = hdev;
@@ -158,17 +177,24 @@
 	hdev->close = btqcomsmd_close;
 	hdev->send = btqcomsmd_send;
 	hdev->setup = btqcomsmd_setup;
-	hdev->set_bdaddr = qca_set_bdaddr_rome;
+	hdev->set_bdaddr = btqcomsmd_set_bdaddr;
 
 	ret = hci_register_dev(hdev);
-	if (ret < 0) {
-		hci_free_dev(hdev);
-		return ret;
-	}
+	if (ret < 0)
+		goto hci_free_dev;
 
 	platform_set_drvdata(pdev, btq);
 
 	return 0;
+
+hci_free_dev:
+	hci_free_dev(hdev);
+destroy_cmd_channel:
+	rpmsg_destroy_ept(btq->cmd_channel);
+destroy_acl_channel:
+	rpmsg_destroy_ept(btq->acl_channel);
+
+	return ret;
 }
 
 static int btqcomsmd_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/bluetooth/btrtl.c
+++ linux-ein-5.4.0/drivers/bluetooth/btrtl.c
@@ -55,6 +55,7 @@
 	int fw_len;
 	u8 *cfg_data;
 	int cfg_len;
+	bool drop_fw;
 };
 
 static const struct id_table ic_id_table[] = {
@@ -130,12 +131,19 @@
 	  .cfg_name = "rtl_bt/rtl8821c_config" },
 
 	/* 8761A */
-	{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0,
+	{ IC_INFO(RTL_ROM_LMP_8761A, 0xa),
 	  .config_needed = false,
 	  .has_rom_version = true,
 	  .fw_name  = "rtl_bt/rtl8761a_fw.bin",
 	  .cfg_name = "rtl_bt/rtl8761a_config" },
 
+	/* 8761B */
+	{ IC_INFO(RTL_ROM_LMP_8761A, 0xb),
+	  .config_needed = false,
+	  .has_rom_version = true,
+	  .fw_name  = "rtl_bt/rtl8761b_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8761b_config" },
+
 	/* 8822C with USB interface */
 	{ IC_INFO(RTL_ROM_LMP_8822B, 0xc),
 	  .config_needed = false,
@@ -255,6 +263,7 @@
 		{ RTL_ROM_LMP_8723B, 9 },	/* 8723D */
 		{ RTL_ROM_LMP_8821A, 10 },	/* 8821C */
 		{ RTL_ROM_LMP_8822B, 13 },	/* 8822C */
+		{ RTL_ROM_LMP_8761A, 14 },	/* 8761B */
 	};
 
 	min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
@@ -370,11 +379,11 @@
 	 * the end.
 	 */
 	len = patch_length;
-	buf = kmemdup(btrtl_dev->fw_data + patch_offset, patch_length,
-		      GFP_KERNEL);
+	buf = kvmalloc(patch_length, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
+	memcpy(buf, btrtl_dev->fw_data + patch_offset, patch_length - 4);
 	memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
 
 	*_buf = buf;
@@ -460,8 +469,10 @@
 	if (ret < 0)
 		return ret;
 	ret = fw->size;
-	*buff = kmemdup(fw->data, ret, GFP_KERNEL);
-	if (!*buff)
+	*buff = kvmalloc(fw->size, GFP_KERNEL);
+	if (*buff)
+		memcpy(*buff, fw->data, ret);
+	else
 		ret = -ENOMEM;
 
 	release_firmware(fw);
@@ -499,14 +510,14 @@
 		goto out;
 
 	if (btrtl_dev->cfg_len > 0) {
-		tbuff = kzalloc(ret + btrtl_dev->cfg_len, GFP_KERNEL);
+		tbuff = kvzalloc(ret + btrtl_dev->cfg_len, GFP_KERNEL);
 		if (!tbuff) {
 			ret = -ENOMEM;
 			goto out;
 		}
 
 		memcpy(tbuff, fw_data, ret);
-		kfree(fw_data);
+		kvfree(fw_data);
 
 		memcpy(tbuff + ret, btrtl_dev->cfg_data, btrtl_dev->cfg_len);
 		ret += btrtl_dev->cfg_len;
@@ -519,14 +530,14 @@
 	ret = rtl_download_firmware(hdev, fw_data, ret);
 
 out:
-	kfree(fw_data);
+	kvfree(fw_data);
 	return ret;
 }
 
 void btrtl_free(struct btrtl_device_info *btrtl_dev)
 {
-	kfree(btrtl_dev->fw_data);
-	kfree(btrtl_dev->cfg_data);
+	kvfree(btrtl_dev->fw_data);
+	kvfree(btrtl_dev->cfg_data);
 	kfree(btrtl_dev);
 }
 EXPORT_SYMBOL_GPL(btrtl_free);
@@ -541,6 +552,8 @@
 	u16 hci_rev, lmp_subver;
 	u8 hci_ver;
 	int ret;
+	u16 opcode;
+	u8 cmd[2];
 
 	btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
 	if (!btrtl_dev) {
@@ -562,6 +575,49 @@
 	hci_ver = resp->hci_ver;
 	hci_rev = le16_to_cpu(resp->hci_rev);
 	lmp_subver = le16_to_cpu(resp->lmp_subver);
+
+	if (resp->hci_ver == 0x8 && le16_to_cpu(resp->hci_rev) == 0x826c &&
+	    resp->lmp_ver == 0x8 && le16_to_cpu(resp->lmp_subver) == 0xa99e)
+		btrtl_dev->drop_fw = true;
+
+	if (btrtl_dev->drop_fw) {
+		opcode = hci_opcode_pack(0x3f, 0x66);
+		cmd[0] = opcode & 0xff;
+		cmd[1] = opcode >> 8;
+
+		skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
+		if (!skb)
+			goto out_free;
+
+		skb_put_data(skb, cmd, sizeof(cmd));
+		hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
+
+		hdev->send(hdev, skb);
+
+		/* Ensure the above vendor command is sent to controller and
+		 * process has done.
+		 */
+		msleep(200);
+
+		/* Read the local version again. Expect to have the vanilla
+		 * version as cold boot.
+		 */
+		skb = btrtl_read_local_version(hdev);
+		if (IS_ERR(skb)) {
+			ret = PTR_ERR(skb);
+			goto err_free;
+		}
+
+		resp = (struct hci_rp_read_local_version *)skb->data;
+		rtl_dev_info(hdev, "examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x lmp_subver=%04x",
+			     resp->hci_ver, resp->hci_rev,
+			     resp->lmp_ver, resp->lmp_subver);
+
+		hci_ver = resp->hci_ver;
+		hci_rev = le16_to_cpu(resp->hci_rev);
+		lmp_subver = le16_to_cpu(resp->lmp_subver);
+	}
+out_free:
 	kfree_skb(skb);
 
 	btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
--- linux-ein-5.4.0.orig/drivers/bluetooth/btsdio.c
+++ linux-ein-5.4.0/drivers/bluetooth/btsdio.c
@@ -346,6 +346,7 @@
 	if (!data)
 		return;
 
+	cancel_work_sync(&data->work);
 	hdev = data->hdev;
 
 	sdio_set_drvdata(func, NULL);
--- linux-ein-5.4.0.orig/drivers/bluetooth/btusb.c
+++ linux-ein-5.4.0/drivers/bluetooth/btusb.c
@@ -14,6 +14,7 @@
 #include <linux/iopoll.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pci.h>
 #include <linux/suspend.h>
 #include <linux/gpio/consumer.h>
 #include <asm/unaligned.h>
@@ -57,6 +58,7 @@
 #define BTUSB_IFNUM_2		0x80000
 #define BTUSB_CW6622		0x100000
 #define BTUSB_MEDIATEK		0x200000
+#define BTUSB_WIDEBAND_SPEECH	0x400000
 
 static const struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -332,20 +334,42 @@
 	{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
 
 	/* Intel Bluetooth devices */
-	{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW },
-	{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW },
-	{ USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW },
+	{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW |
+						     BTUSB_WIDEBAND_SPEECH },
 	{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
 	{ 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 },
-	{ USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW },
+	{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW |
+						     BTUSB_WIDEBAND_SPEECH },
 
 	/* Other Intel Bluetooth devices */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
 	  .driver_info = BTUSB_IGNORE },
 
+	/* Realtek 8822CE Bluetooth devices */
+	{ USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+
+	/* Realtek 8852BE Bluetooth devices */
+	{ USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+	{ USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
+						     BTUSB_WIDEBAND_SPEECH },
+
 	/* Realtek Bluetooth devices */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
 	  .driver_info = BTUSB_REALTEK },
@@ -373,6 +397,10 @@
 	{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
 
+	/* Additional Realtek 8761BU Bluetooth devices */
+	{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
+	  					     BTUSB_WIDEBAND_SPEECH },
+
 	/* Additional Realtek 8821AE Bluetooth devices */
 	{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
@@ -563,13 +591,13 @@
 
 	spin_lock_irqsave(&data->rxlock, flags);
 
-	kfree_skb(data->evt_skb);
+	dev_kfree_skb_irq(data->evt_skb);
 	data->evt_skb = NULL;
 
-	kfree_skb(data->acl_skb);
+	dev_kfree_skb_irq(data->acl_skb);
 	data->acl_skb = NULL;
 
-	kfree_skb(data->sco_skb);
+	dev_kfree_skb_irq(data->sco_skb);
 	data->sco_skb = NULL;
 
 	spin_unlock_irqrestore(&data->rxlock, flags);
@@ -1200,7 +1228,7 @@
 	if (data->setup_on_usb) {
 		err = data->setup_on_usb(hdev);
 		if (err < 0)
-			return err;
+			goto setup_fail;
 	}
 
 	data->intf->needs_remote_wakeup = 1;
@@ -1239,6 +1267,7 @@
 
 failed:
 	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+setup_fail:
 	usb_autopm_put_interface(data->intf);
 	return err;
 }
@@ -2567,7 +2596,8 @@
 		skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC);
 		if (!skb) {
 			hdev->stat.err_rx++;
-			goto err_out;
+			kfree(urb->setup_packet);
+			return;
 		}
 
 		hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
@@ -2584,14 +2614,21 @@
 		 * and being processed the events from there then.
 		 */
 		if (test_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags)) {
-			data->evt_skb = skb_clone(skb, GFP_KERNEL);
-			if (!data->evt_skb)
-				goto err_out;
+			data->evt_skb = skb_clone(skb, GFP_ATOMIC);
+			if (!data->evt_skb) {
+				kfree_skb(skb);
+				kfree(urb->setup_packet);
+				return;
+			}
 		}
 
 		err = hci_recv_frame(hdev, skb);
-		if (err < 0)
-			goto err_free_skb;
+		if (err < 0) {
+			kfree_skb(data->evt_skb);
+			data->evt_skb = NULL;
+			kfree(urb->setup_packet);
+			return;
+		}
 
 		if (test_and_clear_bit(BTUSB_TX_WAIT_VND_EVT,
 				       &data->flags)) {
@@ -2600,11 +2637,7 @@
 			wake_up_bit(&data->flags,
 				    BTUSB_TX_WAIT_VND_EVT);
 		}
-err_out:
-		return;
-err_free_skb:
-		kfree_skb(data->evt_skb);
-		data->evt_skb = NULL;
+		kfree(urb->setup_packet);
 		return;
 	} else if (urb->status == -ENOENT) {
 		/* Avoid suspend failed when usb_kill_urb */
@@ -2625,6 +2658,7 @@
 	usb_anchor_urb(urb, &data->ctrl_anchor);
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err < 0) {
+		kfree(urb->setup_packet);
 		/* -EPERM: urb is being killed;
 		 * -ENODEV: device got disconnected
 		 */
@@ -2663,6 +2697,7 @@
 	buf = kmalloc(size, GFP_KERNEL);
 	if (!buf) {
 		kfree(dr);
+		usb_free_urb(urb);
 		return -ENOMEM;
 	}
 
@@ -2698,11 +2733,6 @@
 	struct btmtk_wmt_hdr *hdr;
 	int err;
 
-	/* Submit control IN URB on demand to process the WMT event */
-	err = btusb_mtk_submit_wmt_recv_urb(hdev);
-	if (err < 0)
-		return err;
-
 	/* Send the WMT command and wait until the WMT event returns */
 	hlen = sizeof(*hdr) + wmt_params->dlen;
 	if (hlen > 255)
@@ -2724,6 +2754,11 @@
 		return err;
 	}
 
+	/* Submit control IN URB on demand to process the WMT event */
+	err = btusb_mtk_submit_wmt_recv_urb(hdev);
+	if (err < 0)
+		return err;
+
 	/* The vendor specific WMT commands are all answered by a vendor
 	 * specific event and will have the Command Status or Command
 	 * Complete as with usual HCI command flow control.
@@ -2791,7 +2826,7 @@
 	const u8 *fw_ptr;
 	size_t fw_size;
 	int err, dlen;
-	u8 flag;
+	u8 flag, param;
 
 	err = request_firmware(&fw, fwname, &hdev->dev);
 	if (err < 0) {
@@ -2799,6 +2834,20 @@
 		return err;
 	}
 
+	/* Power on data RAM the firmware relies on. */
+	param = 1;
+	wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+	wmt_params.flag = 3;
+	wmt_params.dlen = sizeof(param);
+	wmt_params.data = &param;
+	wmt_params.status = NULL;
+
+	err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+	if (err < 0) {
+		bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
+		goto err_release_fw;
+	}
+
 	fw_ptr = fw->data;
 	fw_size = fw->size;
 
@@ -2849,7 +2898,7 @@
 	err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
 	if (err < 0) {
 		bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
-		return err;
+		goto err_release_fw;
 	}
 
 	/* Wait a few moments for firmware activation done */
@@ -3120,6 +3169,35 @@
 	return 0;
 }
 
+#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 int btusb_edge_post_init(struct hci_dev *hdev)
+{
+	btusb_edge_set_led(hdev, true);
+	return 0;
+}
+
+static int btusb_edge_shutdown(struct hci_dev *hdev)
+{
+	btusb_edge_set_led(hdev, false);
+	return 0;
+}
+
 static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
 				    const bdaddr_t *bdaddr)
 {
@@ -3247,6 +3325,11 @@
 	sent += size;
 	count -= size;
 
+	/* ep2 need time to switch from function acl to function dfu,
+	 * so we add 20ms delay here.
+	 */
+	msleep(20);
+
 	while (count) {
 		size = min_t(size_t, count, QCA_DFU_PACKET_LEN);
 
@@ -3771,8 +3854,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_init = btusb_edge_post_init;
+			hdev->shutdown = btusb_edge_shutdown;
+		}
+	}
 
 #ifdef CONFIG_BT_HCIBTUSB_MTK
 	if (id->driver_info & BTUSB_MEDIATEK) {
@@ -3807,8 +3900,8 @@
 		btusb_check_needs_reset_resume(intf);
 	}
 
-#ifdef CONFIG_BT_HCIBTUSB_RTL
-	if (id->driver_info & BTUSB_REALTEK) {
+	if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
+	    (id->driver_info & BTUSB_REALTEK)) {
 		hdev->setup = btrtl_setup_realtek;
 		hdev->shutdown = btrtl_shutdown_realtek;
 		hdev->cmd_timeout = btusb_rtl_cmd_timeout;
@@ -3818,8 +3911,11 @@
 		 * (DEVICE_REMOTE_WAKEUP)
 		 */
 		set_bit(BTUSB_WAKEUP_DISABLE, &data->flags);
+
+		err = usb_autopm_get_interface(intf);
+		if (err < 0)
+			goto out_free_dev;
 	}
-#endif
 
 	if (id->driver_info & BTUSB_AMP) {
 		/* AMP controllers do not support SCO packets */
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_bcm.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_bcm.c
@@ -107,6 +107,7 @@
 	u32			oper_speed;
 	int			irq;
 	bool			irq_active_low;
+	bool			irq_acquired;
 
 #ifdef CONFIG_PM
 	struct hci_uart		*hu;
@@ -319,6 +320,8 @@
 		goto unlock;
 	}
 
+	bdev->irq_acquired = true;
+
 	device_init_wakeup(bdev->dev, true);
 
 	pm_runtime_set_autosuspend_delay(bdev->dev,
@@ -487,7 +490,7 @@
 	}
 
 	if (bdev) {
-		if (IS_ENABLED(CONFIG_PM) && bdev->irq > 0) {
+		if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) {
 			devm_free_irq(bdev->dev, bdev->irq, bdev);
 			device_init_wakeup(bdev->dev, false);
 			pm_runtime_disable(bdev->dev);
@@ -1124,7 +1127,12 @@
 		return -ENOMEM;
 
 	dev->dev = &pdev->dev;
-	dev->irq = platform_get_irq(pdev, 0);
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		return ret;
+
+	dev->irq = ret;
 
 	if (has_acpi_companion(&pdev->dev)) {
 		ret = bcm_acpi_probe(dev);
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_bcsp.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_bcsp.c
@@ -378,7 +378,7 @@
 		i++;
 
 		__skb_unlink(skb, &bcsp->unack);
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 	}
 
 	if (skb_queue_empty(&bcsp->unack))
@@ -591,6 +591,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
@@ -606,6 +607,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;
@@ -630,6 +632,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;
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_h5.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_h5.c
@@ -244,6 +244,9 @@
 	skb_queue_purge(&h5->rel);
 	skb_queue_purge(&h5->unrel);
 
+	kfree_skb(h5->rx_skb);
+	h5->rx_skb = NULL;
+
 	if (h5->vnd && h5->vnd->close)
 		h5->vnd->close(h5);
 
@@ -295,7 +298,7 @@
 			break;
 
 		__skb_unlink(skb, &h5->unack);
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 	}
 
 	if (skb_queue_empty(&h5->unack))
@@ -790,7 +793,7 @@
 	if (!h5)
 		return -ENOMEM;
 
-	set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.flags);
+	set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.hdev_flags);
 
 	h5->hu = &h5->serdev_hu;
 	h5->serdev_hu.serdev = serdev;
@@ -891,6 +894,11 @@
 	/* Give the device some time before the hci-core sends it a reset */
 	usleep_range(10000, 20000);
 
+	/* Enable controller to do both LE scan and BR/EDR inquiry
+	 * simultaneously.
+	 */
+	set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &h5->hu->hdev->quirks);
+
 out_free:
 	btrtl_free(btrtl_dev);
 
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_ibs.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_ibs.c
@@ -0,0 +1,820 @@
+/*
+ *  Qualcomm's Bluetooth Software In-Band Sleep UART protocol
+ *
+ *  HCI_IBS (HCI In-Band Sleep) is Qualcomm's power management
+ *  protocol extension to H4.
+ *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_ll.c, which was...
+ *  Written by Ohad Ben-Cohen <ohad@bencohen.org>
+ *  which was in turn based on hci_h4.c, which was written
+ *  by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/serial_core.h>
+
+#ifdef CONFIG_SERIAL_MSM_HS
+#include <mach/msm_serial_hs.h>
+#endif
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCI_IBS protocol messages */
+#define HCI_IBS_SLEEP_IND	0xFE
+#define HCI_IBS_WAKE_IND	0xFD
+#define HCI_IBS_WAKE_ACK	0xFC
+
+/* HCI_IBS receiver States */
+#define HCI_IBS_W4_PACKET_TYPE	0
+#define HCI_IBS_W4_EVENT_HDR	1
+#define HCI_IBS_W4_ACL_HDR	2
+#define HCI_IBS_W4_SCO_HDR	3
+#define HCI_IBS_W4_DATA		4
+
+/* HCI_IBS transmit side sleep protocol states */
+enum tx_ibs_states_e {
+	HCI_IBS_TX_ASLEEP,
+	HCI_IBS_TX_WAKING,
+	HCI_IBS_TX_AWAKE,
+};
+
+/* HCI_IBS receive side sleep protocol states */
+enum rx_states_e {
+	HCI_IBS_RX_ASLEEP,
+	HCI_IBS_RX_AWAKE,
+};
+
+/* HCI_IBS transmit and receive side clock state vote */
+enum hci_ibs_clock_state_vote_e {
+	HCI_IBS_VOTE_STATS_UPDATE,
+	HCI_IBS_TX_VOTE_CLOCK_ON,
+	HCI_IBS_TX_VOTE_CLOCK_OFF,
+	HCI_IBS_RX_VOTE_CLOCK_ON,
+	HCI_IBS_RX_VOTE_CLOCK_OFF,
+};
+
+static unsigned long wake_retrans = 1;
+static unsigned long tx_idle_delay = (HZ * 2);
+
+struct hci_ibs_cmd {
+	u8 cmd;
+} __attribute__((packed));
+
+struct ibs_struct {
+	struct hci_uart *hu;
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
+	struct sk_buff_head tx_wait_q;	/* HCI_IBS wait queue	*/
+	spinlock_t hci_ibs_lock;	/* HCI_IBS state lock	*/
+	unsigned long tx_ibs_state;	/* HCI_IBS transmit side power state */
+	unsigned long rx_ibs_state;	/* HCI_IBS receive side power state */
+	unsigned long tx_vote;		/* clock must be on for TX */
+	unsigned long rx_vote;		/* clock must be on for RX */
+	struct	timer_list tx_idle_timer;
+	struct	timer_list wake_retrans_timer;
+	/* debug */
+	unsigned long ibs_sent_wacks;
+	unsigned long ibs_sent_slps;
+	unsigned long ibs_sent_wakes;
+	unsigned long ibs_recv_wacks;
+	unsigned long ibs_recv_slps;
+	unsigned long ibs_recv_wakes;
+	unsigned long vote_last_jif;
+	unsigned long vote_on_ticks;
+	unsigned long vote_off_ticks;
+	unsigned long tx_votes_on;
+	unsigned long rx_votes_on;
+	unsigned long tx_votes_off;
+	unsigned long rx_votes_off;
+	unsigned long votes_on;
+	unsigned long votes_off;
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static void __ibs_msm_serial_clock_on(struct tty_struct *tty)
+{
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+
+	msm_hs_request_clock_on(port);
+}
+
+static void __ibs_msm_serial_clock_request_off(struct tty_struct *tty)
+{
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+
+	msm_hs_request_clock_off(port);
+}
+#else
+static inline void __ibs_msm_serial_clock_on(struct tty_struct *tty) {}
+static inline void __ibs_msm_serial_clock_request_off(struct tty_struct *tty) {}
+#endif
+
+/* clock_vote needs to be called with the ibs lock held */
+static void ibs_msm_serial_clock_vote(unsigned long vote, struct hci_uart *hu)
+{
+	struct ibs_struct *ibs = hu->priv;
+
+	unsigned long old_vote = (ibs->tx_vote | ibs->rx_vote);
+	unsigned long new_vote;
+
+	switch (vote) {
+	default: /* error */
+		BT_ERR("voting irregularity");
+		return;
+	case HCI_IBS_VOTE_STATS_UPDATE:
+		if (old_vote)
+			ibs->vote_off_ticks += (jiffies - ibs->vote_last_jif);
+		else
+			ibs->vote_on_ticks += (jiffies - ibs->vote_last_jif);
+		return;
+	case HCI_IBS_TX_VOTE_CLOCK_ON:
+		ibs->tx_vote = 1;
+		ibs->tx_votes_on++;
+		new_vote = 1;
+		break;
+	case HCI_IBS_RX_VOTE_CLOCK_ON:
+		ibs->rx_vote = 1;
+		ibs->rx_votes_on++;
+		new_vote = 1;
+		break;
+	case HCI_IBS_TX_VOTE_CLOCK_OFF:
+		ibs->tx_vote = 0;
+		ibs->tx_votes_off++;
+		new_vote = ibs->rx_vote | ibs->tx_vote;
+		break;
+	case HCI_IBS_RX_VOTE_CLOCK_OFF:
+		ibs->rx_vote = 0;
+		ibs->rx_votes_off++;
+		new_vote = ibs->rx_vote | ibs->tx_vote;
+		break;
+	}
+	if (new_vote != old_vote) {
+		if (new_vote)
+			__ibs_msm_serial_clock_on(hu->tty);
+		else
+			__ibs_msm_serial_clock_request_off(hu->tty);
+
+		BT_DBG("HCIUART_IBS: vote msm_serial_hs clock %lu(%lu)",
+			new_vote, vote);
+		/* debug */
+		if (new_vote) {
+			ibs->votes_on++;
+			ibs->vote_off_ticks += (jiffies - ibs->vote_last_jif);
+		} else {
+			ibs->votes_off++;
+			ibs->vote_on_ticks += (jiffies - ibs->vote_last_jif);
+		}
+		ibs->vote_last_jif = jiffies;
+	}
+}
+
+/*
+ * Builds and sends an HCI_IBS command packet.
+ * These are very simple packets with only 1 cmd byte
+ */
+static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu)
+{
+	int err = 0;
+	struct sk_buff *skb = NULL;
+	struct ibs_struct *ibs = hu->priv;
+	struct hci_ibs_cmd *hci_ibs_packet;
+
+	BT_DBG("hu %p cmd 0x%x", hu, cmd);
+
+	/* allocate packet */
+	skb = bt_skb_alloc(1, GFP_ATOMIC);
+	if (!skb) {
+		BT_ERR("cannot allocate memory for HCI_IBS packet");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* prepare packet */
+	hci_ibs_packet = (struct hci_ibs_cmd *) skb_put(skb, 1);
+	hci_ibs_packet->cmd = cmd;
+	skb->dev = (void *) hu->hdev;
+
+	/* send packet */
+	skb_queue_tail(&ibs->txq, skb);
+out:
+	return err;
+}
+
+static void hci_ibs_tx_idle_timeout(struct timer_list *t)
+{
+	struct ibs_struct *ibs = from_timer(ibs, t, wake_retrans_timer);
+	struct hci_uart *hu = ibs->hu;
+	unsigned long flags;
+	unsigned long vote_tx_sleep = 0;
+
+	BT_DBG("hu %p idle timeout in %lu state", hu, ibs->tx_ibs_state);
+
+	spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
+					flags, SINGLE_DEPTH_NESTING);
+
+	switch (ibs->tx_ibs_state) {
+	default:
+	case HCI_IBS_TX_ASLEEP:
+	case HCI_IBS_TX_WAKING:
+		BT_ERR("spurrious timeout in tx state %ld", ibs->tx_ibs_state);
+		goto out;
+	case HCI_IBS_TX_AWAKE: /* TX_IDLE, go to SLEEP */
+		if (send_hci_ibs_cmd(HCI_IBS_SLEEP_IND, hu) < 0) {
+			BT_ERR("cannot send SLEEP to device");
+			goto out;
+		}
+		ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
+		ibs->ibs_sent_slps++; /* debug */
+		vote_tx_sleep = 1;
+		break;
+	}
+
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
+	hci_uart_tx_wakeup(hu);  /* run HCI tx handling unlocked */
+
+	if (!vote_tx_sleep)
+		return;
+	/* now that message queued to tty driver, vote for tty clocks off */
+	/* It is up to the tty driver to pend the clocks off until tx done. */
+
+	spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
+					flags, SINGLE_DEPTH_NESTING);
+	ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+out:
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+}
+
+static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
+{
+	struct ibs_struct *ibs = from_timer(ibs, t, wake_retrans_timer);
+	struct hci_uart *hu = ibs->hu;
+	unsigned long flags;
+	unsigned long retransmit = 0;
+
+	BT_DBG("hu %p wake retransmit timeout in %lu state",
+		hu, ibs->tx_ibs_state);
+
+	spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
+					flags, SINGLE_DEPTH_NESTING);
+
+	switch (ibs->tx_ibs_state) {
+	default:
+	case HCI_IBS_TX_ASLEEP:
+	case HCI_IBS_TX_AWAKE:
+		BT_ERR("spurrious timeout tx state %ld", ibs->tx_ibs_state);
+		goto out;
+	case HCI_IBS_TX_WAKING: /* No WAKE_ACK, retransmit WAKE */
+		retransmit = 1;
+		if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
+			BT_ERR("cannot acknowledge device wake up");
+			goto out;
+		}
+		ibs->ibs_sent_wakes++; /* debug */
+		mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
+		break;
+	}
+out:
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+	if (retransmit)
+		hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ibs_open(struct hci_uart *hu)
+{
+	struct ibs_struct *ibs;
+
+	BT_DBG("hu %p", hu);
+
+	ibs = kzalloc(sizeof(*ibs), GFP_ATOMIC);
+	if (!ibs)
+		return -ENOMEM;
+
+	skb_queue_head_init(&ibs->txq);
+	skb_queue_head_init(&ibs->tx_wait_q);
+	spin_lock_init(&ibs->hci_ibs_lock);
+
+	/* Assume we start with both sides asleep -- extra wakes OK */
+	ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
+	ibs->rx_ibs_state = HCI_IBS_RX_ASLEEP;
+	/* clocks actually on, but we start votes off */
+	ibs->tx_vote = 0;
+	ibs->rx_vote = 0;
+
+	/* debug */
+	ibs->ibs_sent_wacks = 0;
+	ibs->ibs_sent_slps = 0;
+	ibs->ibs_sent_wakes = 0;
+	ibs->ibs_recv_wacks = 0;
+	ibs->ibs_recv_slps = 0;
+	ibs->ibs_recv_wakes = 0;
+	ibs->vote_last_jif = jiffies;
+	ibs->vote_on_ticks = 0;
+	ibs->vote_off_ticks = 0;
+	ibs->votes_on = 0;
+	ibs->votes_off = 0;
+	ibs->tx_votes_on = 0;
+	ibs->tx_votes_off = 0;
+	ibs->rx_votes_on = 0;
+	ibs->rx_votes_off = 0;
+
+	ibs->hu = hu;
+
+	hu->priv = ibs;
+
+	timer_setup(&ibs->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
+
+	timer_setup(&ibs->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
+
+	BT_INFO("HCI_IBS open, tx_idle_delay=%lu, wake_retrans=%lu",
+		tx_idle_delay, wake_retrans);
+
+	return 0;
+}
+
+void ibs_log_local_stats(struct ibs_struct *ibs)
+{
+	BT_INFO("HCI_IBS stats: tx_idle_delay=%lu, wake_retrans=%lu",
+		tx_idle_delay, wake_retrans);
+
+	BT_INFO("HCI_IBS stats: tx_ibs_state=%lu, rx_ibs_state=%lu",
+		ibs->tx_ibs_state, ibs->rx_ibs_state);
+	BT_INFO("HCI_IBS stats: sent: sleep=%lu, wake=%lu, wake_ack=%lu",
+		ibs->ibs_sent_slps, ibs->ibs_sent_wakes, ibs->ibs_sent_wacks);
+	BT_INFO("HCI_IBS stats: recv: sleep=%lu, wake=%lu, wake_ack=%lu",
+		ibs->ibs_recv_slps, ibs->ibs_recv_wakes, ibs->ibs_recv_wacks);
+
+	BT_INFO("HCI_IBS stats: queues: txq=%s, txwaitq=%s",
+		skb_queue_empty(&(ibs->txq)) ? "empty" : "full",
+		skb_queue_empty(&(ibs->tx_wait_q)) ? "empty" : "full");
+
+	BT_INFO("HCI_IBS stats: vote state: tx=%lu, rx=%lu",
+		ibs->tx_vote, ibs->rx_vote);
+	BT_INFO("HCI_IBS stats: tx votes cast: on=%lu, off=%lu",
+		ibs->tx_votes_on, ibs->tx_votes_off);
+	BT_INFO("HCI_IBS stats: rx votes cast: on=%lu, off=%lu",
+		ibs->rx_votes_on, ibs->rx_votes_off);
+	BT_INFO("HCI_IBS stats: msm_clock votes cast: on=%lu, off=%lu",
+		ibs->votes_on, ibs->votes_off);
+	BT_INFO("HCI_IBS stats: vote ticks: on=%lu, off=%lu",
+		ibs->vote_on_ticks, ibs->vote_off_ticks);
+}
+
+/* Flush protocol data */
+static int ibs_flush(struct hci_uart *hu)
+{
+	struct ibs_struct *ibs = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&ibs->tx_wait_q);
+	skb_queue_purge(&ibs->txq);
+
+	return 0;
+}
+
+/* Close protocol */
+static int ibs_close(struct hci_uart *hu)
+{
+	struct ibs_struct *ibs = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	ibs_msm_serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu);
+	ibs_log_local_stats(ibs);
+
+	skb_queue_purge(&ibs->tx_wait_q);
+	skb_queue_purge(&ibs->txq);
+	del_timer(&ibs->tx_idle_timer);
+	del_timer(&ibs->wake_retrans_timer);
+
+	kfree_skb(ibs->rx_skb);
+
+	hu->priv = NULL;
+
+	kfree(ibs);
+
+	return 0;
+}
+
+/*
+ * Called upon a wake-up-indication from the device
+ */
+static void ibs_device_want_to_wakeup(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ibs_struct *ibs = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hci_ibs state */
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
+	/* debug */
+	ibs->ibs_recv_wakes++;
+
+	switch (ibs->rx_ibs_state) {
+	case HCI_IBS_RX_ASLEEP:
+		/* Make sure clock is on - we may have turned clock off since
+		 * receiving the wake up indicator
+		 */
+		ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
+		ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
+		/* deliberate fall-through */
+	case HCI_IBS_RX_AWAKE:
+		/* Always acknowledge device wake up,
+		 * sending IBS message doesn't count as TX ON.
+		 */
+		if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) {
+			BT_ERR("cannot acknowledge device wake up");
+			goto out;
+		}
+		ibs->ibs_sent_wacks++; /* debug */
+		break;
+	default:
+		/* any other state is illegal */
+		BT_ERR("received HCI_IBS_WAKE_IND in rx state %ld",
+			ibs->rx_ibs_state);
+		break;
+	}
+
+out:
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
+	/* actually send the packets */
+	hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon a sleep-indication from the device
+ */
+static void ibs_device_want_to_sleep(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ibs_struct *ibs = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hci_ibs state */
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
+	/* debug */
+	ibs->ibs_recv_slps++;
+
+	switch (ibs->rx_ibs_state) {
+	case HCI_IBS_RX_AWAKE:
+		/* update state */
+		ibs->rx_ibs_state = HCI_IBS_RX_ASLEEP;
+		ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+		break;
+	case HCI_IBS_RX_ASLEEP:
+		/* deliberate fall-through */
+	default:
+		/* any other state is illegal */
+		BT_ERR("received HCI_IBS_SLEEP_IND in rx state %ld",
+			ibs->rx_ibs_state);
+		break;
+	}
+
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+}
+
+/*
+ * Called upon wake-up-acknowledgement from the device
+ */
+static void ibs_device_woke_up(struct hci_uart *hu)
+{
+	unsigned long flags;
+	struct ibs_struct *ibs = hu->priv;
+	struct sk_buff *skb = NULL;
+
+	BT_DBG("hu %p", hu);
+
+	/* lock hci_ibs state */
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
+	/* debug */
+	ibs->ibs_recv_wacks++;
+
+	switch (ibs->tx_ibs_state) {
+	case HCI_IBS_TX_ASLEEP:
+		/* This could be spurrious rx wake on the BT chip.
+		 * Send it another SLEEP othwise it will stay awake. */
+	default:
+		BT_ERR("received HCI_IBS_WAKE_ACK in tx state %ld",
+			ibs->tx_ibs_state);
+		break;
+	case HCI_IBS_TX_AWAKE:
+		/* expect one if we send 2 WAKEs */
+		BT_DBG("received HCI_IBS_WAKE_ACK in tx state %ld",
+			ibs->tx_ibs_state);
+		break;
+	case HCI_IBS_TX_WAKING:
+		/* send pending packets */
+		while ((skb = skb_dequeue(&ibs->tx_wait_q)))
+			skb_queue_tail(&ibs->txq, skb);
+		/* switch timers and change state to HCI_IBS_TX_AWAKE */
+		del_timer(&ibs->wake_retrans_timer);
+		mod_timer(&ibs->tx_idle_timer, jiffies + tx_idle_delay);
+		ibs->tx_ibs_state = HCI_IBS_TX_AWAKE;
+	}
+
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
+	/* actually send the packets */
+	hci_uart_tx_wakeup(hu);
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ibs_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	unsigned long flags = 0;
+	struct ibs_struct *ibs = hu->priv;
+
+	BT_DBG("hu %p skb %p", hu, skb);
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+	/* lock hci_ibs state */
+	spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
+	/* act according to current state */
+	switch (ibs->tx_ibs_state) {
+	case HCI_IBS_TX_AWAKE:
+		BT_DBG("device awake, sending normally");
+		skb_queue_tail(&ibs->txq, skb);
+		mod_timer(&ibs->tx_idle_timer, jiffies + tx_idle_delay);
+		break;
+
+	case HCI_IBS_TX_ASLEEP:
+		BT_DBG("device asleep, waking up and queueing packet");
+		ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
+		/* save packet for later */
+		skb_queue_tail(&ibs->tx_wait_q, skb);
+		/* awake device */
+		if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
+			BT_ERR("cannot send WAKE to device");
+			break;
+		}
+		ibs->ibs_sent_wakes++; /* debug */
+
+		/* start retransmit timer */
+		mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
+
+		ibs->tx_ibs_state = HCI_IBS_TX_WAKING;
+		break;
+
+	case HCI_IBS_TX_WAKING:
+		BT_DBG("device waking up, queueing packet");
+		/* transient state; just keep packet for later */
+		skb_queue_tail(&ibs->tx_wait_q, skb);
+		break;
+
+	default:
+		BT_ERR("illegal tx state: %ld (losing packet)",
+			ibs->tx_ibs_state);
+		kfree_skb(skb);
+		break;
+	}
+
+	spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
+	return 0;
+}
+
+static inline int ibs_check_data_len(struct hci_uart *hu, struct ibs_struct *ibs, int len)
+{
+	register int room = skb_tailroom(ibs->rx_skb);
+
+	BT_DBG("len %d room %d", len, room);
+
+	if (!len) {
+		hci_recv_frame(hu->hdev, ibs->rx_skb);
+	} else if (len > room) {
+		BT_ERR("Data length is too large");
+		kfree_skb(ibs->rx_skb);
+	} else {
+		ibs->rx_state = HCI_IBS_W4_DATA;
+		ibs->rx_count = len;
+		return len;
+	}
+
+	ibs->rx_state = HCI_IBS_W4_PACKET_TYPE;
+	ibs->rx_skb   = NULL;
+	ibs->rx_count = 0;
+
+	return 0;
+}
+
+/* Recv data */
+static int ibs_recv(struct hci_uart *hu, const void *data, int count)
+{
+	struct ibs_struct *ibs = hu->priv;
+	register char *ptr;
+	struct hci_event_hdr *eh;
+	struct hci_acl_hdr   *ah;
+	struct hci_sco_hdr   *sh;
+	register int len, type, dlen;
+
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
+			hu, count, ibs->rx_state, ibs->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (ibs->rx_count) {
+			len = min_t(unsigned int, ibs->rx_count, count);
+			memcpy(skb_put(ibs->rx_skb, len), ptr, len);
+			ibs->rx_count -= len; count -= len; ptr += len;
+
+			if (ibs->rx_count)
+				continue;
+
+			switch (ibs->rx_state) {
+			case HCI_IBS_W4_DATA:
+				BT_DBG("Complete data");
+				hci_recv_frame(hu->hdev, ibs->rx_skb);
+
+				ibs->rx_state = HCI_IBS_W4_PACKET_TYPE;
+				ibs->rx_skb = NULL;
+				continue;
+
+			case HCI_IBS_W4_EVENT_HDR:
+				eh = (struct hci_event_hdr *) ibs->rx_skb->data;
+
+				BT_DBG("Event header: evt 0x%2.2x plen %d",
+					eh->evt, eh->plen);
+
+				ibs_check_data_len(hu, ibs, eh->plen);
+				continue;
+
+			case HCI_IBS_W4_ACL_HDR:
+				ah = (struct hci_acl_hdr *) ibs->rx_skb->data;
+				dlen = __le16_to_cpu(ah->dlen);
+
+				BT_DBG("ACL header: dlen %d", dlen);
+
+				ibs_check_data_len(hu, ibs, dlen);
+				continue;
+
+			case HCI_IBS_W4_SCO_HDR:
+				sh = (struct hci_sco_hdr *) ibs->rx_skb->data;
+
+				BT_DBG("SCO header: dlen %d", sh->dlen);
+
+				ibs_check_data_len(hu, ibs, sh->dlen);
+				continue;
+			}
+		}
+
+		/* HCI_IBS_W4_PACKET_TYPE */
+		switch (*ptr) {
+		case HCI_EVENT_PKT:
+			BT_DBG("Event packet");
+			ibs->rx_state = HCI_IBS_W4_EVENT_HDR;
+			ibs->rx_count = HCI_EVENT_HDR_SIZE;
+			type = HCI_EVENT_PKT;
+			break;
+
+		case HCI_ACLDATA_PKT:
+			BT_DBG("ACL packet");
+			ibs->rx_state = HCI_IBS_W4_ACL_HDR;
+			ibs->rx_count = HCI_ACL_HDR_SIZE;
+			type = HCI_ACLDATA_PKT;
+			break;
+
+		case HCI_SCODATA_PKT:
+			BT_DBG("SCO packet");
+			ibs->rx_state = HCI_IBS_W4_SCO_HDR;
+			ibs->rx_count = HCI_SCO_HDR_SIZE;
+			type = HCI_SCODATA_PKT;
+			break;
+
+		/* HCI_IBS signals */
+		case HCI_IBS_SLEEP_IND:
+			BT_DBG("HCI_IBS_SLEEP_IND packet");
+			ibs_device_want_to_sleep(hu);
+			ptr++; count--;
+			continue;
+
+		case HCI_IBS_WAKE_IND:
+			BT_DBG("HCI_IBS_WAKE_IND packet");
+			ibs_device_want_to_wakeup(hu);
+			ptr++; count--;
+			continue;
+
+		case HCI_IBS_WAKE_ACK:
+			BT_DBG("HCI_IBS_WAKE_ACK packet");
+			ibs_device_woke_up(hu);
+			ptr++; count--;
+			continue;
+
+		default:
+			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+			hu->hdev->stat.err_rx++;
+			ptr++; count--;
+			continue;
+		};
+
+		ptr++; count--;
+
+		/* Allocate packet */
+		ibs->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+		if (!ibs->rx_skb) {
+			BT_ERR("Can't allocate mem for new packet");
+			ibs->rx_state = HCI_IBS_W4_PACKET_TYPE;
+			ibs->rx_count = 0;
+			return 0;
+		}
+
+		ibs->rx_skb->dev = (void *) hu->hdev;
+		bt_cb(ibs->rx_skb)->pkt_type = type;
+	}
+
+	return count;
+}
+
+static struct sk_buff *ibs_dequeue(struct hci_uart *hu)
+{
+	struct ibs_struct *ibs = hu->priv;
+	return skb_dequeue(&ibs->txq);
+}
+
+static struct hci_uart_proto ibs_p = {
+	.id		= HCI_UART_IBS,
+	.open		= ibs_open,
+	.close		= ibs_close,
+	.recv		= ibs_recv,
+	.enqueue	= ibs_enqueue,
+	.dequeue	= ibs_dequeue,
+	.flush		= ibs_flush,
+};
+
+int ibs_init(void)
+{
+	int err = hci_uart_register_proto(&ibs_p);
+
+	if (!err)
+		BT_INFO("HCI_IBS protocol initialized");
+	else
+		BT_ERR("HCI_IBS protocol registration failed");
+
+	return err;
+}
+
+int ibs_deinit(void)
+{
+	return hci_uart_unregister_proto(&ibs_p);
+}
+
+module_param(wake_retrans, ulong, 0644);
+MODULE_PARM_DESC(wake_retrans, "Delay (1/HZ) to retransmit WAKE_IND");
+
+module_param(tx_idle_delay, ulong, 0644);
+MODULE_PARM_DESC(tx_idle_delay, "Delay (1/HZ) since last tx for SLEEP_IND");
+
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_intel.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_intel.c
@@ -1230,7 +1230,11 @@
 
 int __init intel_init(void)
 {
-	platform_driver_register(&intel_driver);
+	int err;
+
+	err = platform_driver_register(&intel_driver);
+	if (err)
+		return err;
 
 	return hci_uart_register_proto(&intel_proto);
 }
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_ldisc.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_ldisc.c
@@ -127,10 +127,9 @@
 	if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
 		goto no_schedule;
 
-	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
-		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+	set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state))
 		goto no_schedule;
-	}
 
 	BT_DBG("");
 
@@ -174,10 +173,10 @@
 		kfree_skb(skb);
 	}
 
+	clear_bit(HCI_UART_SENDING, &hu->tx_state);
 	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
 		goto restart;
 
-	clear_bit(HCI_UART_SENDING, &hu->tx_state);
 	wake_up_bit(&hu->tx_state, HCI_UART_SENDING);
 }
 
@@ -480,6 +479,9 @@
 
 	BT_DBG("tty %p", tty);
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	/* Error if the tty has no write op instead of leaving an exploitable
 	 * hole
 	 */
@@ -538,6 +540,7 @@
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
 
+		cancel_work_sync(&hu->init_ready);
 		cancel_work_sync(&hu->write_work);
 
 		if (hdev) {
@@ -765,7 +768,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))
 			err = hu->proto->id;
 		else
 			err = -EUNATCH;
@@ -877,6 +881,9 @@
 #ifdef CONFIG_BT_HCIUART_MRVL
 	mrvl_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_IBS
+	ibs_init();
+#endif
 
 	return 0;
 }
@@ -915,6 +922,9 @@
 #ifdef CONFIG_BT_HCIUART_MRVL
 	mrvl_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_IBS
+	ibs_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	err = tty_unregister_ldisc(N_HCI);
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_ll.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_ll.c
@@ -345,7 +345,7 @@
 	default:
 		BT_ERR("illegal hcill state: %ld (losing packet)",
 		       ll->hcill_state);
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		break;
 	}
 
@@ -621,13 +621,6 @@
 
 	serdev_device_set_flow_control(serdev, true);
 
-	if (hu->oper_speed)
-		speed = hu->oper_speed;
-	else if (hu->proto->oper_speed)
-		speed = hu->proto->oper_speed;
-	else
-		speed = 0;
-
 	do {
 		/* Reset the Bluetooth device */
 		gpiod_set_value_cansleep(lldev->enable_gpio, 0);
@@ -639,20 +632,6 @@
 			return err;
 		}
 
-		if (speed) {
-			__le32 speed_le = cpu_to_le32(speed);
-			struct sk_buff *skb;
-
-			skb = __hci_cmd_sync(hu->hdev,
-					     HCI_VS_UPDATE_UART_HCI_BAUDRATE,
-					     sizeof(speed_le), &speed_le,
-					     HCI_INIT_TIMEOUT);
-			if (!IS_ERR(skb)) {
-				kfree_skb(skb);
-				serdev_device_set_baudrate(serdev, speed);
-			}
-		}
-
 		err = download_firmware(lldev);
 		if (!err)
 			break;
@@ -677,7 +656,25 @@
 	}
 
 	/* Operational speed if any */
+	if (hu->oper_speed)
+		speed = hu->oper_speed;
+	else if (hu->proto->oper_speed)
+		speed = hu->proto->oper_speed;
+	else
+		speed = 0;
 
+	if (speed) {
+		__le32 speed_le = cpu_to_le32(speed);
+		struct sk_buff *skb;
+
+		skb = __hci_cmd_sync(hu->hdev, HCI_VS_UPDATE_UART_HCI_BAUDRATE,
+				     sizeof(speed_le), &speed_le,
+				     HCI_INIT_TIMEOUT);
+		if (!IS_ERR(skb)) {
+			kfree_skb(skb);
+			serdev_device_set_baudrate(serdev, speed);
+		}
+	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_nokia.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_nokia.c
@@ -734,7 +734,11 @@
 		return err;
 	}
 
-	clk_prepare_enable(sysclk);
+	err = clk_prepare_enable(sysclk);
+	if (err) {
+		dev_err(dev, "could not enable sysclk: %d", err);
+		return err;
+	}
 	btdev->sysclk_speed = clk_get_rate(sysclk);
 	clk_disable_unprepare(sysclk);
 
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_qca.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_qca.c
@@ -816,7 +816,7 @@
 	default:
 		BT_ERR("Illegal tx state: %d (losing packet)",
 		       qca->tx_ibs_state);
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		break;
 	}
 
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_serdev.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_serdev.c
@@ -85,9 +85,9 @@
 			hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
 			kfree_skb(skb);
 		}
-	} while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
 
-	clear_bit(HCI_UART_SENDING, &hu->tx_state);
+		clear_bit(HCI_UART_SENDING, &hu->tx_state);
+	} while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
 }
 
 /* ------- Interface to HCI layer ------ */
@@ -279,6 +279,8 @@
 	if (err)
 		return err;
 
+	percpu_init_rwsem(&hu->proto_lock);
+
 	err = p->open(hu);
 	if (err)
 		goto err_open;
@@ -301,7 +303,6 @@
 
 	INIT_WORK(&hu->init_ready, hci_uart_init_work);
 	INIT_WORK(&hu->write_work, hci_uart_write_work);
-	percpu_init_rwsem(&hu->proto_lock);
 
 	/* Only when vendor specific setup callback is provided, consider
 	 * the manufacturer information valid. This avoids filling in the
@@ -357,7 +358,10 @@
 	struct hci_dev *hdev = hu->hdev;
 
 	clear_bit(HCI_UART_PROTO_READY, &hu->flags);
-	hci_unregister_dev(hdev);
+
+	cancel_work_sync(&hu->init_ready);
+	if (test_bit(HCI_UART_REGISTERED, &hu->flags))
+		hci_unregister_dev(hdev);
 	hci_free_dev(hdev);
 
 	cancel_work_sync(&hu->write_work);
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_uart.h
+++ linux-ein-5.4.0/drivers/bluetooth/hci_uart.h
@@ -20,7 +20,7 @@
 #define HCIUARTGETFLAGS		_IOR('U', 204, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO	12
+#define HCI_UART_MAX_PROTO	13
 
 #define HCI_UART_H4	0
 #define HCI_UART_BCSP	1
@@ -34,6 +34,7 @@
 #define HCI_UART_AG6XX	9
 #define HCI_UART_NOKIA	10
 #define HCI_UART_MRVL	11
+#define HCI_UART_IBS	12
 
 #define HCI_UART_RAW_DEVICE	0
 #define HCI_UART_RESET_ON_INIT	1
@@ -192,3 +193,8 @@
 int mrvl_init(void);
 int mrvl_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_IBS
+int ibs_init(void);
+int ibs_deinit(void);
+#endif
--- linux-ein-5.4.0.orig/drivers/bluetooth/hci_vhci.c
+++ linux-ein-5.4.0/drivers/bluetooth/hci_vhci.c
@@ -67,7 +67,10 @@
 	struct vhci_data *data = hci_get_drvdata(hdev);
 
 	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+
+	mutex_lock(&data->open_mutex);
 	skb_queue_tail(&data->readq, skb);
+	mutex_unlock(&data->open_mutex);
 
 	wake_up_interruptible(&data->read_wait);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/bus/Kconfig
+++ linux-ein-5.4.0/drivers/bus/Kconfig
@@ -138,7 +138,6 @@
 	tristate "Tegra ACONNECT Bus Driver"
 	depends on ARCH_TEGRA_210_SOC
 	depends on OF && PM
-	select PM_CLK
 	help
 	  Driver for the Tegra ACONNECT bus which is used to interface with
 	  the devices inside the Audio Processing Engine (APE) for Tegra210.
--- linux-ein-5.4.0.orig/drivers/bus/fsl-mc/fsl-mc-allocator.c
+++ linux-ein-5.4.0/drivers/bus/fsl-mc/fsl-mc-allocator.c
@@ -292,8 +292,10 @@
 		goto error;
 
 	mc_adev = resource->data;
-	if (!mc_adev)
+	if (!mc_adev) {
+		error = -EINVAL;
 		goto error;
+	}
 
 	mc_adev->consumer_link = device_link_add(&mc_dev->dev,
 						 &mc_adev->dev,
--- linux-ein-5.4.0.orig/drivers/bus/fsl-mc/mc-io.c
+++ linux-ein-5.4.0/drivers/bus/fsl-mc/mc-io.c
@@ -129,7 +129,12 @@
  */
 void fsl_destroy_mc_io(struct fsl_mc_io *mc_io)
 {
-	struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
+	struct fsl_mc_device *dpmcp_dev;
+
+	if (!mc_io)
+		return;
+
+	dpmcp_dev = mc_io->dpmcp_dev;
 
 	if (dpmcp_dev)
 		fsl_mc_io_unset_dpmcp(mc_io);
--- linux-ein-5.4.0.orig/drivers/bus/hisi_lpc.c
+++ linux-ein-5.4.0/drivers/bus/hisi_lpc.c
@@ -359,6 +359,26 @@
 }
 
 /*
+ * Released firmware describes the IO port max address as 0x3fff, which is
+ * the max host bus address. Fixup to a proper range. This will probably
+ * never be fixed in firmware.
+ */
+static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
+					       struct resource *r)
+{
+	if (r->end != 0x3fff)
+		return;
+
+	if (r->start == 0xe4)
+		r->end = 0xe4 + 0x04 - 1;
+	else if (r->start == 0x2f8)
+		r->end = 0x2f8 + 0x08 - 1;
+	else
+		dev_warn(hostdev, "unrecognised resource %pR to fixup, ignoring\n",
+			 r);
+}
+
+/*
  * hisi_lpc_acpi_set_io_res - set the resources for a child
  * @child: the device node to be updated the I/O resource
  * @hostdev: the device node associated with host controller
@@ -419,8 +439,11 @@
 		return -ENOMEM;
 	}
 	count = 0;
-	list_for_each_entry(rentry, &resource_list, node)
-		resources[count++] = *rentry->res;
+	list_for_each_entry(rentry, &resource_list, node) {
+		resources[count] = *rentry->res;
+		hisi_lpc_acpi_fixup_child_resource(hostdev, &resources[count]);
+		count++;
+	}
 
 	acpi_dev_free_resource_list(&resource_list);
 
@@ -481,13 +504,13 @@
 {
 	struct acpi_device *adev = ACPI_COMPANION(hostdev);
 	struct acpi_device *child;
+	struct platform_device *pdev;
 	int ret;
 
 	/* Only consider the children of the host */
 	list_for_each_entry(child, &adev->children, node) {
 		const char *hid = acpi_device_hid(child);
 		const struct hisi_lpc_acpi_cell *cell;
-		struct platform_device *pdev;
 		const struct resource *res;
 		bool found = false;
 		int num_res;
@@ -549,22 +572,24 @@
 
 		ret = platform_device_add_resources(pdev, res, num_res);
 		if (ret)
-			goto fail;
+			goto fail_put_device;
 
 		ret = platform_device_add_data(pdev, cell->pdata,
 					       cell->pdata_size);
 		if (ret)
-			goto fail;
+			goto fail_put_device;
 
 		ret = platform_device_add(pdev);
 		if (ret)
-			goto fail;
+			goto fail_put_device;
 
 		acpi_device_set_enumerated(child);
 	}
 
 	return 0;
 
+fail_put_device:
+	platform_device_put(pdev);
 fail:
 	hisi_lpc_acpi_remove(hostdev);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/bus/imx-weim.c
+++ linux-ein-5.4.0/drivers/bus/imx-weim.c
@@ -192,8 +192,8 @@
 	const struct of_device_id *of_id = of_match_device(weim_id_table,
 							   &pdev->dev);
 	const struct imx_weim_devtype *devtype = of_id->data;
+	int ret = 0, have_child = 0;
 	struct device_node *child;
-	int ret, have_child = 0;
 	struct cs_timing_state ts = {};
 	u32 reg;
 
--- linux-ein-5.4.0.orig/drivers/bus/mips_cdmm.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/bus/moxtet.c
+++ linux-ein-5.4.0/drivers/bus/moxtet.c
@@ -466,7 +466,7 @@
 {
 	struct moxtet *moxtet = file->private_data;
 	u8 bin[TURRIS_MOX_MAX_MODULES];
-	u8 hex[sizeof(buf) * 2 + 1];
+	u8 hex[sizeof(bin) * 2 + 1];
 	int ret, n;
 
 	ret = moxtet_spi_read(moxtet, bin);
@@ -833,6 +833,12 @@
 	return 0;
 }
 
+static const struct spi_device_id moxtet_spi_ids[] = {
+	{ "moxtet" },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, moxtet_spi_ids);
+
 static const struct of_device_id moxtet_dt_ids[] = {
 	{ .compatible = "cznic,moxtet" },
 	{},
@@ -844,6 +850,7 @@
 		.name		= "moxtet",
 		.of_match_table = moxtet_dt_ids,
 	},
+	.id_table	= moxtet_spi_ids,
 	.probe		= moxtet_probe,
 	.remove		= moxtet_remove,
 };
--- linux-ein-5.4.0.orig/drivers/bus/omap_l3_noc.c
+++ linux-ein-5.4.0/drivers/bus/omap_l3_noc.c
@@ -285,7 +285,7 @@
 	 */
 	l3->debug_irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler,
-			       0x0, "l3-dbg-irq", l3);
+			       IRQF_NO_THREAD, "l3-dbg-irq", l3);
 	if (ret) {
 		dev_err(l3->dev, "request_irq failed for %d\n",
 			l3->debug_irq);
@@ -294,7 +294,7 @@
 
 	l3->app_irq = platform_get_irq(pdev, 1);
 	ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler,
-			       0x0, "l3-app-irq", l3);
+			       IRQF_NO_THREAD, "l3-app-irq", l3);
 	if (ret)
 		dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq);
 
--- linux-ein-5.4.0.orig/drivers/bus/qcom-ebi2.c
+++ linux-ein-5.4.0/drivers/bus/qcom-ebi2.c
@@ -353,8 +353,10 @@
 
 		/* Figure out the chipselect */
 		ret = of_property_read_u32(child, "reg", &csindex);
-		if (ret)
+		if (ret) {
+			of_node_put(child);
 			return ret;
+		}
 
 		if (csindex > 5) {
 			dev_err(dev,
--- linux-ein-5.4.0.orig/drivers/bus/sunxi-rsb.c
+++ linux-ein-5.4.0/drivers/bus/sunxi-rsb.c
@@ -224,6 +224,8 @@
 
 	dev_dbg(&rdev->dev, "device %s registered\n", dev_name(&rdev->dev));
 
+	return rdev;
+
 err_device_add:
 	put_device(&rdev->dev);
 
@@ -266,6 +268,9 @@
 /* common code that starts a transfer */
 static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
 {
+	u32 int_mask, status;
+	bool timeout;
+
 	if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) {
 		dev_dbg(rsb->dev, "RSB transfer still in progress\n");
 		return -EBUSY;
@@ -273,13 +278,23 @@
 
 	reinit_completion(&rsb->complete);
 
-	writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
-	       rsb->regs + RSB_INTE);
+	int_mask = RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER;
+	writel(int_mask, rsb->regs + RSB_INTE);
 	writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB,
 	       rsb->regs + RSB_CTRL);
 
-	if (!wait_for_completion_io_timeout(&rsb->complete,
-					    msecs_to_jiffies(100))) {
+	if (irqs_disabled()) {
+		timeout = readl_poll_timeout_atomic(rsb->regs + RSB_INTS,
+						    status, (status & int_mask),
+						    10, 100000);
+		writel(status, rsb->regs + RSB_INTS);
+	} else {
+		timeout = !wait_for_completion_io_timeout(&rsb->complete,
+							  msecs_to_jiffies(100));
+		status = rsb->status;
+	}
+
+	if (timeout) {
 		dev_dbg(rsb->dev, "RSB timeout\n");
 
 		/* abort the transfer */
@@ -291,18 +306,18 @@
 		return -ETIMEDOUT;
 	}
 
-	if (rsb->status & RSB_INTS_LOAD_BSY) {
+	if (status & RSB_INTS_LOAD_BSY) {
 		dev_dbg(rsb->dev, "RSB busy\n");
 		return -EBUSY;
 	}
 
-	if (rsb->status & RSB_INTS_TRANS_ERR) {
-		if (rsb->status & RSB_INTS_TRANS_ERR_ACK) {
+	if (status & RSB_INTS_TRANS_ERR) {
+		if (status & RSB_INTS_TRANS_ERR_ACK) {
 			dev_dbg(rsb->dev, "RSB slave nack\n");
 			return -EINVAL;
 		}
 
-		if (rsb->status & RSB_INTS_TRANS_ERR_DATA) {
+		if (status & RSB_INTS_TRANS_ERR_DATA) {
 			dev_dbg(rsb->dev, "RSB transfer data error\n");
 			return -EIO;
 		}
@@ -345,7 +360,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);
@@ -766,7 +781,13 @@
 		return ret;
 	}
 
-	return platform_driver_register(&sunxi_rsb_driver);
+	ret = platform_driver_register(&sunxi_rsb_driver);
+	if (ret) {
+		bus_unregister(&sunxi_rsb_bus);
+		return ret;
+	}
+
+	return 0;
 }
 module_init(sunxi_rsb_init);
 
--- linux-ein-5.4.0.orig/drivers/bus/ti-sysc.c
+++ linux-ein-5.4.0/drivers/bus/ti-sysc.c
@@ -70,11 +70,13 @@
  * @child_needs_resume: runtime resume needed for child on resume from suspend
  * @disable_on_idle: status flag used for disabling modules with resets
  * @idle_work: work structure used to perform delayed idle on a module
- * @clk_enable_quirk: module specific clock enable quirk
- * @clk_disable_quirk: module specific clock disable quirk
+ * @pre_reset_quirk: module specific pre-reset quirk
+ * @post_reset_quirk: module specific post-reset quirk
  * @reset_done_quirk: module specific reset done quirk
  * @module_enable_quirk: module specific enable quirk
  * @module_disable_quirk: module specific disable quirk
+ * @module_unlock_quirk: module specific sysconfig unlock quirk
+ * @module_lock_quirk: module specific sysconfig lock quirk
  */
 struct sysc {
 	struct device *dev;
@@ -97,11 +99,13 @@
 	unsigned int needs_resume:1;
 	unsigned int child_needs_resume:1;
 	struct delayed_work idle_work;
-	void (*clk_enable_quirk)(struct sysc *sysc);
-	void (*clk_disable_quirk)(struct sysc *sysc);
+	void (*pre_reset_quirk)(struct sysc *sysc);
+	void (*post_reset_quirk)(struct sysc *sysc);
 	void (*reset_done_quirk)(struct sysc *sysc);
 	void (*module_enable_quirk)(struct sysc *sysc);
 	void (*module_disable_quirk)(struct sysc *sysc);
+	void (*module_unlock_quirk)(struct sysc *sysc);
+	void (*module_lock_quirk)(struct sysc *sysc);
 };
 
 static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
@@ -182,6 +186,37 @@
 	return sysc_read(ddata, offset);
 }
 
+/* Poll on reset status */
+static int sysc_wait_softreset(struct sysc *ddata)
+{
+	u32 sysc_mask, syss_done, rstval;
+	int syss_offset, error = 0;
+
+	if (ddata->cap->regbits->srst_shift < 0)
+		return 0;
+
+	syss_offset = ddata->offsets[SYSC_SYSSTATUS];
+	sysc_mask = BIT(ddata->cap->regbits->srst_shift);
+
+	if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
+		syss_done = 0;
+	else
+		syss_done = ddata->cfg.syss_mask;
+
+	if (syss_offset >= 0) {
+		error = readx_poll_timeout_atomic(sysc_read_sysstatus, ddata,
+				rstval, (rstval & ddata->cfg.syss_mask) ==
+				syss_done, 100, MAX_MODULE_SOFTRESET_WAIT);
+
+	} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
+		error = readx_poll_timeout_atomic(sysc_read_sysconfig, ddata,
+				rstval, !(rstval & sysc_mask),
+				100, MAX_MODULE_SOFTRESET_WAIT);
+	}
+
+	return error;
+}
+
 static int sysc_add_named_clock_from_child(struct sysc *ddata,
 					   const char *name,
 					   const char *optfck_name)
@@ -343,6 +378,12 @@
 		return -EINVAL;
 	}
 
+	/* Always add a slot for main clocks fck and ick even if unused */
+	if (!nr_fck)
+		ddata->nr_clocks++;
+	if (!nr_ick)
+		ddata->nr_clocks++;
+
 	ddata->clocks = devm_kcalloc(ddata->dev,
 				     ddata->nr_clocks, sizeof(*ddata->clocks),
 				     GFP_KERNEL);
@@ -421,7 +462,7 @@
 	struct clk *clock;
 	int i, error;
 
-	if (!ddata->clocks)
+	if (!ddata->clocks || ddata->nr_clocks < SYSC_OPTFCK0 + 1)
 		return 0;
 
 	for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
@@ -455,7 +496,7 @@
 	struct clk *clock;
 	int i;
 
-	if (!ddata->clocks)
+	if (!ddata->clocks || ddata->nr_clocks < SYSC_OPTFCK0 + 1)
 		return;
 
 	for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
@@ -473,7 +514,7 @@
 {
 	struct ti_sysc_platform_data *pdata;
 
-	if (ddata->legacy_mode)
+	if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO))
 		return;
 
 	pdata = dev_get_platdata(ddata->dev);
@@ -485,7 +526,7 @@
 {
 	struct ti_sysc_platform_data *pdata;
 
-	if (ddata->legacy_mode)
+	if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO))
 		return;
 
 	pdata = dev_get_platdata(ddata->dev);
@@ -561,6 +602,51 @@
 	return 0;
 }
 
+/* Interconnect instances to probe before l4_per instances */
+static struct resource early_bus_ranges[] = {
+	/* am3/4 l4_wkup */
+	{ .start = 0x44c00000, .end = 0x44c00000 + 0x300000, },
+	/* omap4/5 and dra7 l4_cfg */
+	{ .start = 0x4a000000, .end = 0x4a000000 + 0x300000, },
+	/* omap4 l4_wkup */
+	{ .start = 0x4a300000, .end = 0x4a300000 + 0x30000,  },
+	/* omap5 and dra7 l4_wkup without dra7 dcan segment */
+	{ .start = 0x4ae00000, .end = 0x4ae00000 + 0x30000,  },
+};
+
+static atomic_t sysc_defer = ATOMIC_INIT(10);
+
+/**
+ * sysc_defer_non_critical - defer non_critical interconnect probing
+ * @ddata: device driver data
+ *
+ * We want to probe l4_cfg and l4_wkup interconnect instances before any
+ * l4_per instances as l4_per instances depend on resources on l4_cfg and
+ * l4_wkup interconnects.
+ */
+static int sysc_defer_non_critical(struct sysc *ddata)
+{
+	struct resource *res;
+	int i;
+
+	if (!atomic_read(&sysc_defer))
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(early_bus_ranges); i++) {
+		res = &early_bus_ranges[i];
+		if (ddata->module_pa >= res->start &&
+		    ddata->module_pa <= res->end) {
+			atomic_set(&sysc_defer, 0);
+
+			return 0;
+		}
+	}
+
+	atomic_dec_if_positive(&sysc_defer);
+
+	return -EPROBE_DEFER;
+}
+
 static struct device_node *stdout_path;
 
 static void sysc_init_stdout_path(struct sysc *ddata)
@@ -785,6 +871,10 @@
 	if (error)
 		return error;
 
+	error = sysc_defer_non_critical(ddata);
+	if (error)
+		return error;
+
 	sysc_check_children(ddata);
 
 	error = sysc_parse_registers(ddata);
@@ -857,6 +947,22 @@
 		buf);
 }
 
+/**
+ * sysc_write_sysconfig - handle sysconfig quirks for register write
+ * @ddata: device driver data
+ * @value: register value
+ */
+static void sysc_write_sysconfig(struct sysc *ddata, u32 value)
+{
+	if (ddata->module_unlock_quirk)
+		ddata->module_unlock_quirk(ddata);
+
+	sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], value);
+
+	if (ddata->module_lock_quirk)
+		ddata->module_lock_quirk(ddata);
+}
+
 #define SYSC_IDLE_MASK	(SYSC_NR_IDLEMODES - 1)
 #define SYSC_CLOCACT_ICK	2
 
@@ -866,18 +972,47 @@
 	struct sysc *ddata;
 	const struct sysc_regbits *regbits;
 	u32 reg, idlemodes, best_mode;
+	int error;
 
 	ddata = dev_get_drvdata(dev);
+
+	/*
+	 * Some modules like DSS reset automatically on idle. Enable optional
+	 * reset clocks and wait for OCP softreset to complete.
+	 */
+	if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) {
+		error = sysc_enable_opt_clocks(ddata);
+		if (error) {
+			dev_err(ddata->dev,
+				"Optional clocks failed for enable: %i\n",
+				error);
+			return error;
+		}
+	}
+	error = sysc_wait_softreset(ddata);
+	if (error)
+		dev_warn(ddata->dev, "OCP softreset timed out\n");
+	if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET)
+		sysc_disable_opt_clocks(ddata);
+
+	/*
+	 * Some subsystem private interconnects, like DSS top level module,
+	 * need only the automatic OCP softreset handling with no sysconfig
+	 * register bits to configure.
+	 */
 	if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
 		return 0;
 
 	regbits = ddata->cap->regbits;
 	reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
 
-	/* Set CLOCKACTIVITY, we only use it for ick */
+	/*
+	 * Set CLOCKACTIVITY, we only use it for ick. And we only configure it
+	 * based on the SYSC_QUIRK_USE_CLOCKACT flag, not based on the hardware
+	 * capabilities. See the old HWMOD_SET_DEFAULT_CLOCKACT flag.
+	 */
 	if (regbits->clkact_shift >= 0 &&
-	    (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT ||
-	     ddata->cfg.sysc_val & BIT(regbits->clkact_shift)))
+	    (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT))
 		reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift;
 
 	/* Set SIDLE mode */
@@ -888,6 +1023,11 @@
 	if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE |
 				 SYSC_QUIRK_SWSUP_SIDLE_ACT)) {
 		best_mode = SYSC_IDLE_NO;
+
+		/* Clear WAKEUP */
+		if (regbits->enwkup_shift >= 0 &&
+		    ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
+			reg &= ~BIT(regbits->enwkup_shift);
 	} else {
 		best_mode = fls(ddata->cfg.sidlemodes) - 1;
 		if (best_mode > SYSC_IDLE_MASK) {
@@ -903,7 +1043,7 @@
 
 	reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
 	reg |= best_mode << regbits->sidle_shift;
-	sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+	sysc_write_sysconfig(ddata, reg);
 
 set_midle:
 	/* Set MIDLE mode */
@@ -917,18 +1057,24 @@
 		return -EINVAL;
 	}
 
+	if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
+		best_mode = SYSC_IDLE_NO;
+
 	reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
 	reg |= best_mode << regbits->midle_shift;
-	sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+	sysc_write_sysconfig(ddata, reg);
 
 set_autoidle:
 	/* Autoidle bit must enabled separately if available */
 	if (regbits->autoidle_shift >= 0 &&
 	    ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
 		reg |= 1 << regbits->autoidle_shift;
-		sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+		sysc_write_sysconfig(ddata, reg);
 	}
 
+	/* Flush posted write */
+	sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
+
 	if (ddata->module_enable_quirk)
 		ddata->module_enable_quirk(ddata);
 
@@ -978,9 +1124,13 @@
 		return ret;
 	}
 
+	if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_MSTANDBY) ||
+	    ddata->cfg.quirks & (SYSC_QUIRK_FORCE_MSTANDBY))
+		best_mode = SYSC_IDLE_FORCE;
+
 	reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
 	reg |= best_mode << regbits->midle_shift;
-	sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+	sysc_write_sysconfig(ddata, reg);
 
 set_sidle:
 	/* Set SIDLE mode */
@@ -998,12 +1148,22 @@
 		}
 	}
 
+	if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT) {
+		/* Set WAKEUP */
+		if (regbits->enwkup_shift >= 0 &&
+		    ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
+			reg |= BIT(regbits->enwkup_shift);
+	}
+
 	reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
 	reg |= best_mode << regbits->sidle_shift;
 	if (regbits->autoidle_shift >= 0 &&
 	    ddata->cfg.sysc_val & BIT(regbits->autoidle_shift))
 		reg |= 1 << regbits->autoidle_shift;
-	sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+	sysc_write_sysconfig(ddata, reg);
+
+	/* Flush posted write */
+	sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
 
 	return 0;
 }
@@ -1149,7 +1309,8 @@
 
 	ddata = dev_get_drvdata(dev);
 
-	if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
+	if (ddata->cfg.quirks &
+	    (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
 		return 0;
 
 	return pm_runtime_force_suspend(dev);
@@ -1161,7 +1322,8 @@
 
 	ddata = dev_get_drvdata(dev);
 
-	if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
+	if (ddata->cfg.quirks &
+	    (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
 		return 0;
 
 	return pm_runtime_force_resume(dev);
@@ -1209,33 +1371,54 @@
 		   SYSC_QUIRK_LEGACY_IDLE),
 	SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
 		   SYSC_QUIRK_LEGACY_IDLE),
-	SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
+	SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff,
 		   SYSC_QUIRK_LEGACY_IDLE),
-	SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
+	SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff,
 		   SYSC_QUIRK_LEGACY_IDLE),
 	SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
 		   0),
 	/* Some timers on omap4 and later */
-	SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff,
+	SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff,
 		   0),
-	SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
+	SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff,
 		   0),
 	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
-		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+		   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
 	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
-		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
+		   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
 	/* Uarts on omap4 and later */
 	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
 		   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
 	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
 		   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff,
+		   SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
 
 	/* Quirks that need to be set based on the module address */
-	SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -1, 0x50000800, 0xffffffff,
+	SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff,
 		   SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
 		   SYSC_QUIRK_SWSUP_SIDLE),
 
 	/* Quirks that need to be set based on detected module */
+	SYSC_QUIRK("aess", 0, 0, 0x10, -ENODEV, 0x40000000, 0xffffffff,
+		   SYSC_MODULE_QUIRK_AESS),
+	/* Errata i893 handling for dra7 dcan1 and 2 */
+	SYSC_QUIRK("dcan", 0x4ae3c000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff,
+		   SYSC_QUIRK_CLKDM_NOAUTO),
+	SYSC_QUIRK("dcan", 0x48480000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff,
+		   SYSC_QUIRK_CLKDM_NOAUTO),
+	SYSC_QUIRK("dss", 0x4832a000, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
+		   SYSC_QUIRK_OPT_CLKS_IN_RESET),
+	SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000040, 0xffffffff,
+		   SYSC_QUIRK_OPT_CLKS_IN_RESET),
+	SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000061, 0xffffffff,
+		   SYSC_QUIRK_OPT_CLKS_IN_RESET),
+	SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
+		   SYSC_QUIRK_CLKDM_NOAUTO),
+	SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
+		   SYSC_QUIRK_CLKDM_NOAUTO),
+	SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff,
+		   SYSC_QUIRK_OPT_CLKS_NEEDED),
 	SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
 		   SYSC_MODULE_QUIRK_HDQ1W),
 	SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff,
@@ -1248,9 +1431,23 @@
 		   SYSC_MODULE_QUIRK_I2C),
 	SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0,
 		   SYSC_MODULE_QUIRK_I2C),
-	SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0),
-	SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff,
+	SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0),
+	SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff,
 		   SYSC_MODULE_QUIRK_SGX),
+	SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0,
+		   SYSC_MODULE_QUIRK_RTC_UNLOCK),
+	SYSC_QUIRK("tptc", 0, 0, 0x10, -ENODEV, 0x40006c00, 0xffffefff,
+		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+	SYSC_QUIRK("tptc", 0, 0, -ENODEV, -ENODEV, 0x40007c00, 0xffffffff,
+		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+	SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff,
+		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+	SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff,
+		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+	SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
+		   0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+	SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
+		   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
 	SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
 		   SYSC_MODULE_QUIRK_WDT),
 	/* Watchdog on am3 and am4 */
@@ -1258,60 +1455,66 @@
 		   SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE),
 
 #ifdef DEBUG
-	SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
-	SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
-	SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0),
-	SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0),
-	SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
+	SYSC_QUIRK("adc", 0, 0, 0x10, -ENODEV, 0x47300001, 0xffffffff, 0),
+	SYSC_QUIRK("atl", 0, 0, -ENODEV, -ENODEV, 0x0a070100, 0xffffffff, 0),
+	SYSC_QUIRK("cm", 0, 0, -ENODEV, -ENODEV, 0x40000301, 0xffffffff, 0),
+	SYSC_QUIRK("control", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0),
 	SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
 		   0xffff00f0, 0),
-	SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0xa3170504, 0xffffffff, 0),
-	SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0x4edb1902, 0xffffffff, 0),
-	SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
-	SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
+	SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 0),
+	SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0x4edb1902, 0xffffffff, 0),
+	SYSC_QUIRK("dispc", 0x4832a400, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0),
+	SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0),
+	SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000051, 0xffffffff, 0),
+	SYSC_QUIRK("dmic", 0, 0, 0x10, -ENODEV, 0x50010000, 0xffffffff, 0),
+	SYSC_QUIRK("dsi", 0x58004000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0),
+	SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0),
+	SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0),
+	SYSC_QUIRK("dsi", 0x58009000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0),
+	SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0),
 	SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
 	SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
-	SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
-	SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
-	SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, 0),
+	SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0),
+	SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0),
+	SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0),
+	SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50031d00, 0xffffffff, 0),
 	SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
-	SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
-	SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
-	SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
-	SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
-	SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
-	SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0),
+	SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0),
+	SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff, 0),
+	SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0),
+	SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0),
+	SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0),
+	SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0),
 	SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0),
-	SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
-	SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0),
+	SYSC_QUIRK("mailbox", 0, 0, 0x10, -ENODEV, 0x00000400, 0xffffffff, 0),
+	SYSC_QUIRK("m3", 0, 0, -ENODEV, -ENODEV, 0x5f580105, 0x0fff0f00, 0),
 	SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
-	SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
-	SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
-	SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0),
-	SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
-	SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
-	SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
-	SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
-	SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0),
-	SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0),
-	SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0),
-	SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
-	SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0),
+	SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0),
+	SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0),
+	SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0),
+	SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0),
+	SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0),
+	SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0),
+	SYSC_QUIRK("rfbi", 0x4832a800, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
+	SYSC_QUIRK("rfbi", 0x58002000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
+	SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0),
+	SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0),
+	SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0),
+	SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x40000900, 0xffffffff, 0),
+	SYSC_QUIRK("scrm", 0, 0, -ENODEV, -ENODEV, 0x00000010, 0xffffffff, 0),
+	SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0),
 	SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
 	SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
-	SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
-	SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
-	SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
-	SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0),
-	SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
-	SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
+	SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0),
+	SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
+	SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0),
+	SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0),
+	SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0),
+	SYSC_QUIRK("tpcc", 0, 0, -ENODEV, -ENODEV, 0x40014c00, 0xffffffff, 0),
 	SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
 	SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
-	SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
-	SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
-	SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
-		   0xffffffff, 0),
-	SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
+	SYSC_QUIRK("venc", 0x58003000, 0, -ENODEV, -ENODEV, 0x00000002, 0xffffffff, 0),
+	SYSC_QUIRK("vfpe", 0, 0, 0x104, -ENODEV, 0x4d001200, 0xffffffff, 0),
 #endif
 };
 
@@ -1333,16 +1536,13 @@
 		if (q->base != ddata->module_pa)
 			continue;
 
-		if (q->rev_offset >= 0 &&
-		    q->rev_offset != ddata->offsets[SYSC_REVISION])
+		if (q->rev_offset != ddata->offsets[SYSC_REVISION])
 			continue;
 
-		if (q->sysc_offset >= 0 &&
-		    q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+		if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
 			continue;
 
-		if (q->syss_offset >= 0 &&
-		    q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+		if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
 			continue;
 
 		ddata->name = q->name;
@@ -1362,16 +1562,13 @@
 		if (q->base && q->base != ddata->module_pa)
 			continue;
 
-		if (q->rev_offset >= 0 &&
-		    q->rev_offset != ddata->offsets[SYSC_REVISION])
+		if (q->rev_offset != ddata->offsets[SYSC_REVISION])
 			continue;
 
-		if (q->sysc_offset >= 0 &&
-		    q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+		if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
 			continue;
 
-		if (q->syss_offset >= 0 &&
-		    q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+		if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
 			continue;
 
 		if (q->revision == ddata->revision ||
@@ -1384,7 +1581,7 @@
 }
 
 /* 1-wire needs module's internal clocks enabled for reset */
-static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata)
+static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata)
 {
 	int offset = 0x0c;	/* HDQ_CTRL_STATUS */
 	u16 val;
@@ -1394,7 +1591,15 @@
 	sysc_write(ddata, offset, val);
 }
 
-/* I2C needs extra enable bit toggling for reset */
+/* AESS (Audio Engine SubSystem) needs autogating set after enable */
+static void sysc_module_enable_quirk_aess(struct sysc *ddata)
+{
+	int offset = 0x7c;	/* AESS_AUTO_GATING_ENABLE */
+
+	sysc_write(ddata, offset, 1);
+}
+
+/* I2C needs to be disabled for reset */
 static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable)
 {
 	int offset;
@@ -1415,14 +1620,48 @@
 	sysc_write(ddata, offset, val);
 }
 
-static void sysc_clk_enable_quirk_i2c(struct sysc *ddata)
+static void sysc_pre_reset_quirk_i2c(struct sysc *ddata)
+{
+	sysc_clk_quirk_i2c(ddata, false);
+}
+
+static void sysc_post_reset_quirk_i2c(struct sysc *ddata)
 {
 	sysc_clk_quirk_i2c(ddata, true);
 }
 
-static void sysc_clk_disable_quirk_i2c(struct sysc *ddata)
+/* RTC on am3 and 4 needs to be unlocked and locked for sysconfig */
+static void sysc_quirk_rtc(struct sysc *ddata, bool lock)
 {
-	sysc_clk_quirk_i2c(ddata, false);
+	u32 val, kick0_val = 0, kick1_val = 0;
+	unsigned long flags;
+	int error;
+
+	if (!lock) {
+		kick0_val = 0x83e70b13;
+		kick1_val = 0x95a4f1e0;
+	}
+
+	local_irq_save(flags);
+	/* RTC_STATUS BUSY bit may stay active for 1/32768 seconds (~30 usec) */
+	error = readl_poll_timeout_atomic(ddata->module_va + 0x44, val,
+					  !(val & BIT(0)), 100, 50);
+	if (error)
+		dev_warn(ddata->dev, "rtc busy timeout\n");
+	/* Now we have ~15 microseconds to read/write various registers */
+	sysc_write(ddata, 0x6c, kick0_val);
+	sysc_write(ddata, 0x70, kick1_val);
+	local_irq_restore(flags);
+}
+
+static void sysc_module_unlock_quirk_rtc(struct sysc *ddata)
+{
+	sysc_quirk_rtc(ddata, false);
+}
+
+static void sysc_module_lock_quirk_rtc(struct sysc *ddata)
+{
+	sysc_quirk_rtc(ddata, true);
 }
 
 /* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */
@@ -1464,14 +1703,24 @@
 		return;
 
 	if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
-		ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w;
+		ddata->pre_reset_quirk = sysc_pre_reset_quirk_hdq1w;
 
 		return;
 	}
 
 	if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
-		ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c;
-		ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c;
+		ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c;
+		ddata->post_reset_quirk = sysc_post_reset_quirk_i2c;
+
+		return;
+	}
+
+	if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS)
+		ddata->module_enable_quirk = sysc_module_enable_quirk_aess;
+
+	if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_RTC_UNLOCK) {
+		ddata->module_unlock_quirk = sysc_module_unlock_quirk_rtc;
+		ddata->module_lock_quirk = sysc_module_lock_quirk_rtc;
 
 		return;
 	}
@@ -1569,46 +1818,39 @@
  */
 static int sysc_reset(struct sysc *ddata)
 {
-	int sysc_offset, syss_offset, sysc_val, rstval, error = 0;
-	u32 sysc_mask, syss_done;
+	int sysc_offset, sysc_val, error;
+	u32 sysc_mask;
 
 	sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
-	syss_offset = ddata->offsets[SYSC_SYSSTATUS];
 
-	if (ddata->legacy_mode || sysc_offset < 0 ||
+	if (ddata->legacy_mode ||
 	    ddata->cap->regbits->srst_shift < 0 ||
 	    ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
 		return 0;
 
 	sysc_mask = BIT(ddata->cap->regbits->srst_shift);
 
-	if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
-		syss_done = 0;
-	else
-		syss_done = ddata->cfg.syss_mask;
-
-	if (ddata->clk_disable_quirk)
-		ddata->clk_disable_quirk(ddata);
+	if (ddata->pre_reset_quirk)
+		ddata->pre_reset_quirk(ddata);
 
-	sysc_val = sysc_read_sysconfig(ddata);
-	sysc_val |= sysc_mask;
-	sysc_write(ddata, sysc_offset, sysc_val);
+	if (sysc_offset >= 0) {
+		sysc_val = sysc_read_sysconfig(ddata);
+		sysc_val |= sysc_mask;
+		sysc_write(ddata, sysc_offset, sysc_val);
+		/* Flush posted write */
+		sysc_val = sysc_read_sysconfig(ddata);
+	}
 
-	if (ddata->clk_enable_quirk)
-		ddata->clk_enable_quirk(ddata);
+	if (ddata->cfg.srst_udelay)
+		usleep_range(ddata->cfg.srst_udelay,
+			     ddata->cfg.srst_udelay * 2);
 
-	/* Poll on reset status */
-	if (syss_offset >= 0) {
-		error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
-					   (rstval & ddata->cfg.syss_mask) ==
-					   syss_done,
-					   100, MAX_MODULE_SOFTRESET_WAIT);
+	if (ddata->post_reset_quirk)
+		ddata->post_reset_quirk(ddata);
 
-	} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
-		error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
-					   !(rstval & sysc_mask),
-					   100, MAX_MODULE_SOFTRESET_WAIT);
-	}
+	error = sysc_wait_softreset(ddata);
+	if (error)
+		dev_warn(ddata->dev, "OCP softreset timed out\n");
 
 	if (ddata->reset_done_quirk)
 		ddata->reset_done_quirk(ddata);
@@ -2500,7 +2742,9 @@
 	struct sysc *ddata = platform_get_drvdata(pdev);
 	int error;
 
-	cancel_delayed_work_sync(&ddata->idle_work);
+	/* Device can still be enabled, see deferred idle quirk in probe */
+	if (cancel_delayed_work_sync(&ddata->idle_work))
+		ti_sysc_idle(&ddata->idle_work.work);
 
 	error = pm_runtime_get_sync(ddata->dev);
 	if (error < 0) {
@@ -2513,7 +2757,9 @@
 
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	reset_control_assert(ddata->rsts);
+
+	if (!reset_control_status(ddata->rsts))
+		reset_control_assert(ddata->rsts);
 
 unprepare:
 	sysc_unprepare(ddata);
--- linux-ein-5.4.0.orig/drivers/cdrom/cdrom.c
+++ linux-ein-5.4.0/drivers/cdrom/cdrom.c
@@ -291,7 +291,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 */
@@ -996,6 +996,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) {
@@ -1162,7 +1168,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))
@@ -2882,6 +2889,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)))
--- linux-ein-5.4.0.orig/drivers/cdrom/gdrom.c
+++ linux-ein-5.4.0/drivers/cdrom/gdrom.c
@@ -740,6 +740,13 @@
 static int probe_gdrom(struct platform_device *devptr)
 {
 	int err;
+
+	/*
+	 * Ensure our "one" device is initialized properly in case of previous
+	 * usages of it
+	 */
+	memset(&gd, 0, sizeof(gd));
+
 	/* Start the device */
 	if (gdrom_execute_diagnostic() != 1) {
 		pr_warning("ATA Probe for GDROM failed\n");
@@ -828,6 +835,8 @@
 	if (gdrom_major)
 		unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
 	unregister_cdrom(gd.cd_info);
+	kfree(gd.cd_info);
+	kfree(gd.toc);
 
 	return 0;
 }
@@ -843,7 +852,7 @@
 static int __init init_gdrom(void)
 {
 	int rc;
-	gd.toc = NULL;
+
 	rc = platform_driver_register(&gdrom_driver);
 	if (rc)
 		return rc;
@@ -859,8 +868,6 @@
 {
 	platform_device_unregister(pd);
 	platform_driver_unregister(&gdrom_driver);
-	kfree(gd.toc);
-	kfree(gd.cd_info);
 }
 
 module_init(init_gdrom);
--- linux-ein-5.4.0.orig/drivers/char/Kconfig
+++ linux-ein-5.4.0/drivers/char/Kconfig
@@ -535,28 +535,43 @@
 	  and SSM (Silicon Secured Memory).  Intended consumers of this
 	  driver include crash and makedumpfile.
 
-endmenu
+source "drivers/char/imx_amp/Kconfig"
 
 config RANDOM_TRUST_CPU
-	bool "Trust the CPU manufacturer to initialize Linux's CRNG"
-	depends on X86 || S390 || PPC
-	default n
+	bool "Initialize RNG using CPU RNG instructions"
+	default y
+	depends on ARCH_RANDOM
 	help
-	Assume that CPU manufacturer (e.g., Intel or AMD for RDSEED or
-	RDRAND, IBM for the S390 and Power PC architectures) is trustworthy
-	for the purposes of initializing Linux's CRNG.  Since this is not
-	something that can be independently audited, this amounts to trusting
-	that CPU manufacturer (perhaps with the insistence or mandate
-	of a Nation State's intelligence or law enforcement agencies)
-	has not installed a hidden back door to compromise the CPU's
-	random number generation facilities. This can also be configured
-	at boot with "random.trust_cpu=on/off".
+	  Initialize the RNG using random numbers supplied by the CPU's
+	  RNG instructions (e.g. RDRAND), if supported and available. These
+	  random numbers are never used directly, but are rather hashed into
+	  the main input pool, and this happens regardless of whether or not
+	  this option is enabled. Instead, this option controls whether the
+	  they are credited and hence can initialize the RNG. Additionally,
+	  other sources of randomness are always used, regardless of this
+	  setting.  Enabling this implies trusting that the CPU can supply high
+	  quality and non-backdoored random numbers.
+
+	  Say Y here unless you have reason to mistrust your CPU or believe
+	  its RNG facilities may be faulty. This may also be configured at
+	  boot time with "random.trust_cpu=on/off".
 
 config RANDOM_TRUST_BOOTLOADER
-	bool "Trust the bootloader to initialize Linux's CRNG"
+	bool "Initialize RNG using bootloader-supplied seed"
+	default y
 	help
-	Some bootloaders can provide entropy to increase the kernel's initial
-	device randomness. Say Y here to assume the entropy provided by the
-	booloader is trustworthy so it will be added to the kernel's entropy
-	pool. Otherwise, say N here so it will be regarded as device input that
-	only mixes the entropy pool.
\ No newline at end of file
+	  Initialize the RNG using a seed supplied by the bootloader or boot
+	  environment (e.g. EFI or a bootloader-generated device tree). This
+	  seed is not used directly, but is rather hashed into the main input
+	  pool, and this happens regardless of whether or not this option is
+	  enabled. Instead, this option controls whether the seed is credited
+	  and hence can initialize the RNG. Additionally, other sources of
+	  randomness are always used, regardless of this setting. Enabling
+	  this implies trusting that the bootloader can supply high quality and
+	  non-backdoored seeds.
+
+	  Say Y here unless you have reason to mistrust your bootloader or
+	  believe its RNG facilities may be faulty. This may also be configured
+	  at boot time with "random.trust_bootloader=on/off".
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/char/Makefile
+++ linux-ein-5.4.0/drivers/char/Makefile
@@ -52,3 +52,4 @@
 obj-$(CONFIG_XILLYBUS)		+= xillybus/
 obj-$(CONFIG_POWERNV_OP_PANEL)	+= powernv-op-panel.o
 obj-$(CONFIG_ADI)		+= adi.o
+obj-$(CONFIG_HAVE_IMX_AMP)      += imx_amp/
--- linux-ein-5.4.0.orig/drivers/char/agp/Kconfig
+++ linux-ein-5.4.0/drivers/char/agp/Kconfig
@@ -125,7 +125,7 @@
 
 config AGP_PARISC
 	tristate "HP Quicksilver AGP support"
-	depends on AGP && PARISC && 64BIT
+	depends on AGP && PARISC && 64BIT && IOMMU_SBA
 	help
 	  This option gives you AGP GART support for the HP Quicksilver
 	  AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
--- linux-ein-5.4.0.orig/drivers/char/agp/intel-gtt.c
+++ linux-ein-5.4.0/drivers/char/agp/intel-gtt.c
@@ -304,8 +304,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
@@ -846,6 +848,7 @@
 			   unsigned int flags)
 {
 	intel_private.driver->write_entry(addr, pg, flags);
+	readl(intel_private.gtt + pg);
 	if (intel_private.driver->chipset_flush)
 		intel_private.driver->chipset_flush();
 }
@@ -871,7 +874,7 @@
 			j++;
 		}
 	}
-	wmb();
+	readl(intel_private.gtt + j - 1);
 	if (intel_private.driver->chipset_flush)
 		intel_private.driver->chipset_flush();
 }
@@ -1105,6 +1108,7 @@
 
 static void i9xx_chipset_flush(void)
 {
+	wmb();
 	if (intel_private.i9xx_flush_page)
 		writel(1, intel_private.i9xx_flush_page);
 }
--- linux-ein-5.4.0.orig/drivers/char/agp/parisc-agp.c
+++ linux-ein-5.4.0/drivers/char/agp/parisc-agp.c
@@ -90,6 +90,9 @@
 {
 	struct _parisc_agp_info *info = &parisc_agp_info;
 
+	/* force fdc ops to be visible to IOMMU */
+	asm_io_sync();
+
 	writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
 	readq(info->ioc_regs+IOC_PCOM);	/* flush */
 }
@@ -158,6 +161,7 @@
 			info->gatt[j] =
 				parisc_agp_mask_memory(agp_bridge,
 					paddr, type);
+			asm_io_fdc(&info->gatt[j]);
 		}
 	}
 
@@ -191,7 +195,16 @@
 parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
 		       int type)
 {
-	return SBA_PDIR_VALID_BIT | addr;
+	unsigned ci;			/* coherent index */
+	dma_addr_t pa;
+
+	pa = addr & IOVP_MASK;
+	asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pa)));
+
+	pa |= (ci >> PAGE_SHIFT) & 0xff;/* move CI (8 bits) into lowest byte */
+	pa |= SBA_PDIR_VALID_BIT;	/* set "valid" bit */
+
+	return cpu_to_le64(pa);
 }
 
 static void
@@ -281,7 +294,7 @@
         return 0;
 }
 
-static int
+static int __init
 lba_find_capability(int cap)
 {
 	struct _parisc_agp_info *info = &parisc_agp_info;
@@ -366,7 +379,7 @@
 	return error;
 }
 
-static int
+static int __init
 find_quicksilver(struct device *dev, void *data)
 {
 	struct parisc_device **lba = data;
@@ -378,11 +391,9 @@
 	return 0;
 }
 
-static int
+static int __init
 parisc_agp_init(void)
 {
-	extern struct sba_device *sba_list;
-
 	int err = -1;
 	struct parisc_device *sba = NULL, *lba = NULL;
 	struct lba_device *lbadev = NULL;
--- linux-ein-5.4.0.orig/drivers/char/hpet.c
+++ linux-ein-5.4.0/drivers/char/hpet.c
@@ -855,7 +855,7 @@
 		return 0;
 	}
 
-	hpetp = kzalloc(struct_size(hpetp, hp_dev, hdp->hd_nirqs - 1),
+	hpetp = kzalloc(struct_size(hpetp, hp_dev, hdp->hd_nirqs),
 			GFP_KERNEL);
 
 	if (!hpetp)
@@ -984,6 +984,8 @@
 		hdp->hd_phys_address = fixmem32->address;
 		hdp->hd_address = ioremap(fixmem32->address,
 						HPET_RANGE_SIZE);
+		if (!hdp->hd_address)
+			return AE_ERROR;
 
 		if (hpet_is_known(hdp)) {
 			iounmap(hdp->hd_address);
--- linux-ein-5.4.0.orig/drivers/char/hw_random/Kconfig
+++ linux-ein-5.4.0/drivers/char/hw_random/Kconfig
@@ -308,6 +308,19 @@
 
 	  If unsure, say Y.
 
+config HW_RANDOM_HISI_V2
+	tristate "HiSilicon True Random Number Generator V2 support"
+	depends on HW_RANDOM && ARM64 && ACPI
+	default HW_RANDOM
+	help
+	  This driver provides kernel-side support for the True Random Number
+	  Generator V2 hardware found on HiSilicon Hi1620 SoC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hisi-trng-v2.
+
+	  If unsure, say Y.
+
 config HW_RANDOM_ST
 	tristate "ST Microelectronics HW Random Number Generator support"
 	depends on HW_RANDOM && ARCH_STI
--- linux-ein-5.4.0.orig/drivers/char/hw_random/Makefile
+++ linux-ein-5.4.0/drivers/char/hw_random/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_HISI)	+= hisi-rng.o
+obj-$(CONFIG_HW_RANDOM_HISI_V2) += hisi-trng-v2.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
 obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
--- linux-ein-5.4.0.orig/drivers/char/hw_random/amd-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/amd-rng.c
@@ -143,15 +143,19 @@
 found:
 	err = pci_read_config_dword(pdev, 0x58, &pmbase);
 	if (err)
-		return err;
+		goto put_dev;
 
 	pmbase &= 0x0000FF00;
-	if (pmbase == 0)
-		return -EIO;
+	if (pmbase == 0) {
+		err = -EIO;
+		goto put_dev;
+	}
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	if (!priv) {
+		err = -ENOMEM;
+		goto put_dev;
+	}
 
 	if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
 		dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
@@ -185,6 +189,8 @@
 	release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
 out:
 	kfree(priv);
+put_dev:
+	pci_dev_put(pdev);
 	return err;
 }
 
@@ -200,6 +206,8 @@
 
 	release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
 
+	pci_dev_put(priv->pcidev);
+
 	kfree(priv);
 }
 
--- linux-ein-5.4.0.orig/drivers/char/hw_random/atmel-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/atmel-rng.c
@@ -96,6 +96,7 @@
 
 err_register:
 	clk_disable_unprepare(trng->clk);
+	atmel_trng_disable(trng);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/char/hw_random/core.c
+++ linux-ein-5.4.0/drivers/char/hw_random/core.c
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/hw_random.h>
+#include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/sched/signal.h>
@@ -23,10 +24,13 @@
 #include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/uaccess.h>
 
 #define RNG_MODULE_NAME		"hw_random"
 
+#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES)
+
 static struct hwrng *current_rng;
 /* the current rng has been explicitly chosen by user via sysfs */
 static int cur_rng_set_by_user;
@@ -58,7 +62,7 @@
 
 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)
@@ -201,6 +205,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;
@@ -228,34 +233,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);
@@ -266,6 +274,7 @@
 		}
 	}
 out:
+	memzero_explicit(buffer, sizeof(buffer));
 	return ret ? : err;
 
 out_unlock_reading:
--- linux-ein-5.4.0.orig/drivers/char/hw_random/exynos-trng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/exynos-trng.c
@@ -134,7 +134,7 @@
 		return PTR_ERR(trng->mem);
 
 	pm_runtime_enable(&pdev->dev);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not get runtime PM.\n");
 		goto err_pm_get;
@@ -167,7 +167,7 @@
 	clk_disable_unprepare(trng->clk);
 
 err_clock:
-	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
 
 err_pm_get:
 	pm_runtime_disable(&pdev->dev);
--- linux-ein-5.4.0.orig/drivers/char/hw_random/geode-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/geode-rng.c
@@ -51,10 +51,15 @@
 };
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
+struct amd_geode_priv {
+	struct pci_dev *pcidev;
+	void __iomem *membase;
+};
 
 static int geode_rng_data_read(struct hwrng *rng, u32 *data)
 {
-	void __iomem *mem = (void __iomem *)rng->priv;
+	struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv;
+	void __iomem *mem = priv->membase;
 
 	*data = readl(mem + GEODE_RNG_DATA_REG);
 
@@ -63,7 +68,8 @@
 
 static int geode_rng_data_present(struct hwrng *rng, int wait)
 {
-	void __iomem *mem = (void __iomem *)rng->priv;
+	struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv;
+	void __iomem *mem = priv->membase;
 	int data, i;
 
 	for (i = 0; i < 20; i++) {
@@ -90,6 +96,7 @@
 	const struct pci_device_id *ent;
 	void __iomem *mem;
 	unsigned long rng_base;
+	struct amd_geode_priv *priv;
 
 	for_each_pci_dev(pdev) {
 		ent = pci_match_id(pci_tbl, pdev);
@@ -97,17 +104,26 @@
 			goto found;
 	}
 	/* Device not found. */
-	goto out;
+	return err;
 
 found:
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		err = -ENOMEM;
+		goto put_dev;
+	}
+
 	rng_base = pci_resource_start(pdev, 0);
 	if (rng_base == 0)
-		goto out;
+		goto free_priv;
 	err = -ENOMEM;
 	mem = ioremap(rng_base, 0x58);
 	if (!mem)
-		goto out;
-	geode_rng.priv = (unsigned long)mem;
+		goto free_priv;
+
+	geode_rng.priv = (unsigned long)priv;
+	priv->membase = mem;
+	priv->pcidev = pdev;
 
 	pr_info("AMD Geode RNG detected\n");
 	err = hwrng_register(&geode_rng);
@@ -116,20 +132,26 @@
 		       err);
 		goto err_unmap;
 	}
-out:
 	return err;
 
 err_unmap:
 	iounmap(mem);
-	goto out;
+free_priv:
+	kfree(priv);
+put_dev:
+	pci_dev_put(pdev);
+	return err;
 }
 
 static void __exit mod_exit(void)
 {
-	void __iomem *mem = (void __iomem *)geode_rng.priv;
+	struct amd_geode_priv *priv;
 
+	priv = (struct amd_geode_priv *)geode_rng.priv;
 	hwrng_unregister(&geode_rng);
-	iounmap(mem);
+	iounmap(priv->membase);
+	pci_dev_put(priv->pcidev);
+	kfree(priv);
 }
 
 module_init(mod_init);
--- linux-ein-5.4.0.orig/drivers/char/hw_random/hisi-trng-v2.c
+++ linux-ein-5.4.0/drivers/char/hw_random/hisi-trng-v2.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 HiSilicon Limited. */
+
+#include <linux/acpi.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+
+#define HISI_TRNG_REG		0x00F0
+#define HISI_TRNG_BYTES		4
+#define HISI_TRNG_QUALITY	512
+#define SLEEP_US		10
+#define TIMEOUT_US		10000
+
+struct hisi_trng {
+	void __iomem *base;
+	struct hwrng rng;
+};
+
+static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+	struct hisi_trng *trng;
+	int currsize = 0;
+	u32 val = 0;
+	u32 ret;
+
+	trng = container_of(rng, struct hisi_trng, rng);
+
+	do {
+		ret = readl_poll_timeout(trng->base + HISI_TRNG_REG, val,
+					 val, SLEEP_US, TIMEOUT_US);
+		if (ret)
+			return currsize;
+
+		if (max - currsize >= HISI_TRNG_BYTES) {
+			memcpy(buf + currsize, &val, HISI_TRNG_BYTES);
+			currsize += HISI_TRNG_BYTES;
+			if (currsize == max)
+				return currsize;
+			continue;
+		}
+
+		/* copy remaining bytes */
+		memcpy(buf + currsize, &val, max - currsize);
+		currsize = max;
+	} while (currsize < max);
+
+	return currsize;
+}
+
+static int hisi_trng_probe(struct platform_device *pdev)
+{
+	struct hisi_trng *trng;
+	int ret;
+
+	trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+	if (!trng)
+		return -ENOMEM;
+
+	trng->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(trng->base))
+		return PTR_ERR(trng->base);
+
+	trng->rng.name = pdev->name;
+	trng->rng.read = hisi_trng_read;
+	trng->rng.quality = HISI_TRNG_QUALITY;
+
+	ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+	if (ret)
+		dev_err(&pdev->dev, "failed to register hwrng!\n");
+
+	return ret;
+}
+
+static const struct acpi_device_id hisi_trng_acpi_match[] = {
+	{ "HISI02B3", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
+
+static struct platform_driver hisi_trng_driver = {
+	.probe		= hisi_trng_probe,
+	.driver		= {
+		.name	= "hisi-trng-v2",
+		.acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
+	},
+};
+
+module_platform_driver(hisi_trng_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
+MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
+MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");
--- linux-ein-5.4.0.orig/drivers/char/hw_random/imx-rngc.c
+++ linux-ein-5.4.0/drivers/char/hw_random/imx-rngc.c
@@ -99,14 +99,16 @@
 	cmd = readl(rngc->base + RNGC_COMMAND);
 	writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);
 
-	ret = wait_for_completion_timeout(&rngc->rng_op_done, RNGC_TIMEOUT);
+	ret = wait_for_completion_timeout(&rngc->rng_op_done, msecs_to_jiffies(RNGC_TIMEOUT));
 	if (!ret) {
 		imx_rngc_irq_mask_clear(rngc);
 		return -ETIMEDOUT;
 	}
 
-	if (rngc->err_reg != 0)
+	if (rngc->err_reg != 0) {
+		imx_rngc_irq_mask_clear(rngc);
 		return -EIO;
+	}
 
 	return 0;
 }
@@ -180,9 +182,7 @@
 		cmd = readl(rngc->base + RNGC_COMMAND);
 		writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND);
 
-		ret = wait_for_completion_timeout(&rngc->rng_op_done,
-				RNGC_TIMEOUT);
-
+		ret = wait_for_completion_timeout(&rngc->rng_op_done, msecs_to_jiffies(RNGC_TIMEOUT));
 		if (!ret) {
 			imx_rngc_irq_mask_clear(rngc);
 			return -ETIMEDOUT;
--- linux-ein-5.4.0.orig/drivers/char/hw_random/iproc-rng200.c
+++ linux-ein-5.4.0/drivers/char/hw_random/iproc-rng200.c
@@ -202,10 +202,12 @@
 		return PTR_ERR(priv->base);
 	}
 
-	priv->rng.name = "iproc-rng200",
-	priv->rng.read = iproc_rng200_read,
-	priv->rng.init = iproc_rng200_init,
-	priv->rng.cleanup = iproc_rng200_cleanup,
+	dev_set_drvdata(dev, priv);
+
+	priv->rng.name = "iproc-rng200";
+	priv->rng.read = iproc_rng200_read;
+	priv->rng.init = iproc_rng200_init;
+	priv->rng.cleanup = iproc_rng200_cleanup;
 
 	/* Register driver */
 	ret = devm_hwrng_register(dev, &priv->rng);
@@ -219,6 +221,28 @@
 	return 0;
 }
 
+static int __maybe_unused iproc_rng200_suspend(struct device *dev)
+{
+	struct iproc_rng200_dev *priv = dev_get_drvdata(dev);
+
+	iproc_rng200_cleanup(&priv->rng);
+
+	return 0;
+}
+
+static int __maybe_unused iproc_rng200_resume(struct device *dev)
+{
+	struct iproc_rng200_dev *priv =  dev_get_drvdata(dev);
+
+	iproc_rng200_init(&priv->rng);
+
+	return 0;
+}
+
+static const struct dev_pm_ops iproc_rng200_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(iproc_rng200_suspend, iproc_rng200_resume)
+};
+
 static const struct of_device_id iproc_rng200_of_match[] = {
 	{ .compatible = "brcm,bcm7211-rng200", },
 	{ .compatible = "brcm,bcm7278-rng200", },
@@ -231,6 +255,7 @@
 	.driver = {
 		.name		= "iproc-rng200",
 		.of_match_table = iproc_rng200_of_match,
+		.pm		= &iproc_rng200_pm_ops,
 	},
 	.probe		= iproc_rng200_probe,
 };
--- linux-ein-5.4.0.orig/drivers/char/hw_random/ks-sa-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/ks-sa-rng.c
@@ -208,6 +208,7 @@
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
 		dev_err(dev, "Failed to enable SA power-domain\n");
+		pm_runtime_put_noidle(dev);
 		pm_runtime_disable(dev);
 		return ret;
 	}
--- linux-ein-5.4.0.orig/drivers/char/hw_random/mtk-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/mtk-rng.c
@@ -173,8 +173,13 @@
 	return mtk_rng_init(&priv->rng);
 }
 
-static UNIVERSAL_DEV_PM_OPS(mtk_rng_pm_ops, mtk_rng_runtime_suspend,
-			    mtk_rng_runtime_resume, NULL);
+static const struct dev_pm_ops mtk_rng_pm_ops = {
+	SET_RUNTIME_PM_OPS(mtk_rng_runtime_suspend,
+			   mtk_rng_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
 #define MTK_RNG_PM_OPS (&mtk_rng_pm_ops)
 #else	/* CONFIG_PM */
 #define MTK_RNG_PM_OPS NULL
--- linux-ein-5.4.0.orig/drivers/char/hw_random/omap-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/omap-rng.c
@@ -66,6 +66,13 @@
 #define OMAP4_RNG_OUTPUT_SIZE			0x8
 #define EIP76_RNG_OUTPUT_SIZE			0x10
 
+/*
+ * EIP76 RNG takes approx. 700us to produce 16 bytes of output data
+ * as per testing results. And to account for the lack of udelay()'s
+ * reliability, we keep the timeout as 1000us.
+ */
+#define RNG_DATA_FILL_TIMEOUT			100
+
 enum {
 	RNG_OUTPUT_0_REG = 0,
 	RNG_OUTPUT_1_REG,
@@ -176,7 +183,7 @@
 	if (max < priv->pdata->data_size)
 		return 0;
 
-	for (i = 0; i < 20; i++) {
+	for (i = 0; i < RNG_DATA_FILL_TIMEOUT; i++) {
 		present = priv->pdata->data_present(priv);
 		if (present || !wait)
 			break;
--- linux-ein-5.4.0.orig/drivers/char/hw_random/omap3-rom-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/omap3-rom-rng.c
@@ -20,6 +20,8 @@
 #include <linux/workqueue.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #define RNG_RESET			0x01
@@ -86,14 +88,18 @@
 
 static struct hwrng omap3_rom_rng_ops = {
 	.name		= "omap3-rom",
-	.read		= omap3_rom_rng_read,
 };
 
 static int omap3_rom_rng_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 
-	pr_info("initializing\n");
+	omap3_rom_rng_ops.read = of_device_get_match_data(&pdev->dev);
+	if (!omap3_rom_rng_ops.read) {
+		dev_err(&pdev->dev, "missing rom code handler\n");
+
+		return -ENODEV;
+	}
 
 	omap3_rom_rng_call = pdev->dev.platform_data;
 	if (!omap3_rom_rng_call) {
@@ -121,13 +127,21 @@
 {
 	cancel_delayed_work_sync(&idle_work);
 	hwrng_unregister(&omap3_rom_rng_ops);
-	clk_disable_unprepare(rng_clk);
+	if (!rng_idle)
+		clk_disable_unprepare(rng_clk);
 	return 0;
 }
 
+static const struct of_device_id omap_rom_rng_match[] = {
+	{ .compatible = "nokia,n900-rom-rng", .data = omap3_rom_rng_read, },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, omap_rom_rng_match);
+
 static struct platform_driver omap3_rom_rng_driver = {
 	.driver = {
 		.name		= "omap3-rom-rng",
+		.of_match_table = omap_rom_rng_match,
 	},
 	.probe		= omap3_rom_rng_probe,
 	.remove		= omap3_rom_rng_remove,
--- linux-ein-5.4.0.orig/drivers/char/hw_random/optee-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/optee-rng.c
@@ -122,14 +122,14 @@
 	if (max > MAX_ENTROPY_REQ_SZ)
 		max = MAX_ENTROPY_REQ_SZ;
 
-	while (read == 0) {
+	while (read < max) {
 		rng_size = get_optee_rng_data(pvt_data, data, (max - read));
 
 		data += rng_size;
 		read += rng_size;
 
-		if (wait) {
-			if (timeout-- == 0)
+		if (wait && pvt_data->data_rate) {
+			if ((timeout-- == 0) || (read == max))
 				return read;
 			msleep((1000 * (max - read)) / pvt_data->data_rate);
 		} else {
--- linux-ein-5.4.0.orig/drivers/char/hw_random/st-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/st-rng.c
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/hw_random.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -41,7 +42,6 @@
 
 struct st_rng_data {
 	void __iomem	*base;
-	struct clk	*clk;
 	struct hwrng	ops;
 };
 
@@ -86,26 +86,18 @@
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	clk = devm_clk_get(&pdev->dev, NULL);
+	clk = devm_clk_get_enabled(&pdev->dev, NULL);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
 
-	ret = clk_prepare_enable(clk);
-	if (ret)
-		return ret;
-
 	ddata->ops.priv	= (unsigned long)ddata;
 	ddata->ops.read	= st_rng_read;
 	ddata->ops.name	= pdev->name;
 	ddata->base	= base;
-	ddata->clk	= clk;
-
-	dev_set_drvdata(&pdev->dev, ddata);
 
 	ret = devm_hwrng_register(&pdev->dev, &ddata->ops);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register HW RNG\n");
-		clk_disable_unprepare(clk);
 		return ret;
 	}
 
@@ -114,16 +106,7 @@
 	return 0;
 }
 
-static int st_rng_remove(struct platform_device *pdev)
-{
-	struct st_rng_data *ddata = dev_get_drvdata(&pdev->dev);
-
-	clk_disable_unprepare(ddata->clk);
-
-	return 0;
-}
-
-static const struct of_device_id st_rng_match[] = {
+static const struct of_device_id st_rng_match[] __maybe_unused = {
 	{ .compatible = "st,rng" },
 	{},
 };
@@ -135,7 +118,6 @@
 		.of_match_table = of_match_ptr(st_rng_match),
 	},
 	.probe = st_rng_probe,
-	.remove = st_rng_remove
 };
 
 module_platform_driver(st_rng_driver);
--- linux-ein-5.4.0.orig/drivers/char/hw_random/timeriomem-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/timeriomem-rng.c
@@ -69,7 +69,7 @@
 		 */
 		if (retval > 0)
 			usleep_range(period_us,
-					period_us + min(1, period_us / 100));
+					period_us + max(1, period_us / 100));
 
 		*(u32 *)data = readl(priv->io_base);
 		retval += sizeof(u32);
--- linux-ein-5.4.0.orig/drivers/char/hw_random/virtio-rng.c
+++ linux-ein-5.4.0/drivers/char/hw_random/virtio-rng.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 2007, 2008 Rusty Russell IBM Corporation
  */
 
+#include <asm/barrier.h>
 #include <linux/err.h>
 #include <linux/hw_random.h>
 #include <linux/scatterlist.h>
@@ -17,71 +18,111 @@
 struct virtrng_info {
 	struct hwrng hwrng;
 	struct virtqueue *vq;
-	struct completion have_data;
 	char name[25];
-	unsigned int data_avail;
 	int index;
-	bool busy;
 	bool hwrng_register_done;
 	bool hwrng_removed;
+	/* data transfer */
+	struct completion have_data;
+	unsigned int data_avail;
+	unsigned int data_idx;
+	/* minimal size returned by rng_buffer_size() */
+#if SMP_CACHE_BYTES < 32
+	u8 data[32];
+#else
+	u8 data[SMP_CACHE_BYTES];
+#endif
 };
 
 static void random_recv_done(struct virtqueue *vq)
 {
 	struct virtrng_info *vi = vq->vdev->priv;
+	unsigned int len;
 
 	/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
-	if (!virtqueue_get_buf(vi->vq, &vi->data_avail))
+	if (!virtqueue_get_buf(vi->vq, &len))
 		return;
 
+	smp_store_release(&vi->data_avail, len);
 	complete(&vi->have_data);
 }
 
-/* The host will fill any buffer we give it with sweet, sweet randomness. */
-static void register_buffer(struct virtrng_info *vi, u8 *buf, size_t size)
+static void request_entropy(struct virtrng_info *vi)
 {
 	struct scatterlist sg;
 
-	sg_init_one(&sg, buf, size);
+	reinit_completion(&vi->have_data);
+	vi->data_idx = 0;
+
+	sg_init_one(&sg, vi->data, sizeof(vi->data));
 
 	/* There should always be room for one buffer. */
-	virtqueue_add_inbuf(vi->vq, &sg, 1, buf, GFP_KERNEL);
+	virtqueue_add_inbuf(vi->vq, &sg, 1, vi->data, GFP_KERNEL);
 
 	virtqueue_kick(vi->vq);
 }
 
+static unsigned int copy_data(struct virtrng_info *vi, void *buf,
+			      unsigned int size)
+{
+	size = min_t(unsigned int, size, vi->data_avail);
+	memcpy(buf, vi->data + vi->data_idx, size);
+	vi->data_idx += size;
+	vi->data_avail -= size;
+	if (vi->data_avail == 0)
+		request_entropy(vi);
+	return size;
+}
+
 static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
 {
 	int ret;
 	struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
+	unsigned int chunk;
+	size_t read;
 
 	if (vi->hwrng_removed)
 		return -ENODEV;
 
-	if (!vi->busy) {
-		vi->busy = true;
-		reinit_completion(&vi->have_data);
-		register_buffer(vi, buf, size);
+	read = 0;
+
+	/* copy available data */
+	if (smp_load_acquire(&vi->data_avail)) {
+		chunk = copy_data(vi, buf, size);
+		size -= chunk;
+		read += chunk;
 	}
 
 	if (!wait)
-		return 0;
-
-	ret = wait_for_completion_killable(&vi->have_data);
-	if (ret < 0)
-		return ret;
+		return read;
 
-	vi->busy = false;
+	/* We have already copied available entropy,
+	 * so either size is 0 or data_avail is 0
+	 */
+	while (size != 0) {
+		/* data_avail is 0 but a request is pending */
+		ret = wait_for_completion_killable(&vi->have_data);
+		if (ret < 0)
+			return ret;
+		/* if vi->data_avail is 0, we have been interrupted
+		 * by a cleanup, but buffer stays in the queue
+		 */
+		if (vi->data_avail == 0)
+			return read;
+
+		chunk = copy_data(vi, buf + read, size);
+		size -= chunk;
+		read += chunk;
+	}
 
-	return vi->data_avail;
+	return read;
 }
 
 static void virtio_cleanup(struct hwrng *rng)
 {
 	struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
 
-	if (vi->busy)
-		wait_for_completion(&vi->have_data);
+	complete(&vi->have_data);
 }
 
 static int probe_common(struct virtio_device *vdev)
@@ -117,6 +158,9 @@
 		goto err_find;
 	}
 
+	/* we always have a pending entropy request */
+	request_entropy(vi);
+
 	return 0;
 
 err_find:
@@ -132,9 +176,9 @@
 
 	vi->hwrng_removed = true;
 	vi->data_avail = 0;
+	vi->data_idx = 0;
 	complete(&vi->have_data);
 	vdev->config->reset(vdev);
-	vi->busy = false;
 	if (vi->hwrng_register_done)
 		hwrng_unregister(&vi->hwrng);
 	vdev->config->del_vqs(vdev);
--- linux-ein-5.4.0.orig/drivers/char/imx_amp/Kconfig
+++ linux-ein-5.4.0/drivers/char/imx_amp/Kconfig
@@ -0,0 +1,9 @@
+#
+# imx mcc
+#
+
+config IMX_SEMA4
+	bool "IMX SEMA4 driver"
+	depends on SOC_IMX6SX
+	help
+	  Support for IMX SEMA4 driver, most people should say N here.
--- linux-ein-5.4.0.orig/drivers/char/imx_amp/Makefile
+++ linux-ein-5.4.0/drivers/char/imx_amp/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for imx mcc
+#
+#
+obj-$(CONFIG_IMX_SEMA4)		+= imx_sema4.o
--- linux-ein-5.4.0.orig/drivers/char/imx_amp/imx_sema4.c
+++ linux-ein-5.4.0/drivers/char/imx_amp/imx_sema4.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/imx_sema4.h>
+
+static struct imx_sema4_mutex_device *imx6_sema4;
+
+/*!
+ * \brief mutex create function.
+ *
+ * This function allocates imx_sema4_mutex structure and returns a handle
+ * to it. The mutex to be created is identified by SEMA4 device number and mutex
+ * (gate) number. The handle is used to reference the created mutex in calls to
+ * other imx_sema4_mutex API functions. This function is to be called only
+ * once for each mutex.
+ *
+ * \param[in] dev_num     SEMA4 device (module) number.
+ * \param[in] mutex_num   Mutex (gate) number.
+ *
+ * \return NULL (Failure.)
+ * \return imx_sema4_mutex (Success.)
+ */
+struct imx_sema4_mutex *
+imx_sema4_mutex_create(u32 dev_num, u32 mutex_num)
+{
+	struct imx_sema4_mutex *mutex_ptr = NULL;
+
+	if ((mutex_num > SEMA4_NUM_GATES) || dev_num >= SEMA4_NUM_DEVICES)
+		goto out;
+
+	if (imx6_sema4->cpine_val & (1 < mutex_num)) {
+		pr_err("Error: requiring a allocated sema4.\n");
+		pr_err("mutex_num %d cpine_val 0x%08x.\n",
+				mutex_num, imx6_sema4->cpine_val);
+	}
+	mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL);
+	if (!mutex_ptr)
+		goto out;
+	imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr;
+	imx6_sema4->alloced |= 1 < mutex_num;
+	imx6_sema4->cpine_val |= idx_sema4[mutex_num];
+	writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
+
+	mutex_ptr->valid = CORE_MUTEX_VALID;
+	mutex_ptr->gate_num = mutex_num;
+	init_waitqueue_head(&mutex_ptr->wait_q);
+
+out:
+	return mutex_ptr;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_create);
+
+/*!
+ * \brief mutex destroy function.
+ *
+ * This function destroys a mutex.
+ *
+ * \param[in] mutex_ptr   Pointer to mutex structure.
+ *
+ * \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.)
+ * \return MQX_INVALID_PARAMETER (Wrong input parameter.)
+ * \return COREMUTEX_OK (Success.)
+ *
+ */
+int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr)
+{
+	u32 mutex_num;
+
+	if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+		return -EINVAL;
+
+	mutex_num = mutex_ptr->gate_num;
+	if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) {
+		pr_err("Error: trying to destroy a un-allocated sema4.\n");
+		pr_err("mutex_num %d cpine_val 0x%08x.\n",
+				mutex_num, imx6_sema4->cpine_val);
+	}
+	imx6_sema4->mutex_ptr[mutex_num] = NULL;
+	imx6_sema4->alloced &= ~(1 << mutex_num);
+	imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]);
+	writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
+
+	kfree(mutex_ptr);
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_destroy);
+
+/*!
+ * \brief Lock the mutex, shouldn't be interruted by INT.
+ *
+ * This function attempts to lock a mutex. If the mutex is already locked
+ * by another task the function return -EBUSY, and tell invoker wait until
+ * it is possible to lock the mutex.
+ *
+ * \param[in] mutex_ptr   Pointer to mutex structure.
+ *
+ * \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.)
+ * \return COREMUTEX_OK (mutex successfully locked.)
+ *
+ * \see imx_sema4_mutex_unlock
+ */
+int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
+{
+	int ret = 0, i = mutex_ptr->gate_num;
+
+	if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+		return -EINVAL;
+
+	mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+	mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+	/* Check to see if this core already own it */
+	if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
+		/* return -EBUSY, invoker should be in sleep, and re-lock ag */
+		pr_err("%s -> %s %d already locked, wait! num %d val %d.\n",
+				__FILE__, __func__, __LINE__,
+				i, mutex_ptr->gate_val);
+		ret = -EBUSY;
+		goto out;
+	} else {
+		/* try to lock the mutex */
+		mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+		mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+		mutex_ptr->gate_val |= SEMA4_A9_LOCK;
+		writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
+		mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+		mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+		/* double check the mutex is locked, otherwise, return -EBUSY */
+		if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
+			pr_debug("wait-locked num %d val %d.\n",
+					i, mutex_ptr->gate_val);
+			ret = -EBUSY;
+		}
+	}
+out:
+	return ret;
+}
+
+/* !
+ * \brief Try to lock the core mutex.
+ *
+ * This function attempts to lock a mutex. If the mutex is successfully locked
+ * for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already
+ * locked by another task, the function does not block but rather returns
+ * negative immediately.
+ *
+ * \param[in] mutex_ptr  Pointer to core_mutex structure.
+ *
+ * \return SEMA4_A9_LOCK (mutex successfully locked.)
+ * \return negative (mutex not locked.)
+ *
+ */
+int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr)
+{
+	int ret = 0;
+
+	ret = _imx_sema4_mutex_lock(mutex_ptr);
+	if (ret == 0)
+		return SEMA4_A9_LOCK;
+	else
+		return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_trylock);
+
+/*!
+ * \brief Invoke _imx_sema4_mutex_lock to lock the mutex.
+ *
+ * This function attempts to lock a mutex. If the mutex is already locked
+ * by another task the function, sleep itself and schedule out.
+ * Wait until it is possible to lock the mutex.
+ *
+ * Invoker should add its own wait queue into the wait queue header of the
+ * required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by
+ * schedule() when the lock is failed. Re-try to lock the semaphore when
+ * it is woke up by the sema4 isr.
+ *
+ * \param[in] mutex_ptr  Pointer to mutex structure.
+ *
+ * \return SEMA4_A9_LOCK (mutex successfully locked.)
+ *
+ * \see imx_sema4_mutex_unlock
+ */
+int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx6_sema4->lock, flags);
+	ret = _imx_sema4_mutex_lock(mutex_ptr);
+	spin_unlock_irqrestore(&imx6_sema4->lock, flags);
+	while (-EBUSY == ret) {
+		spin_lock_irqsave(&imx6_sema4->lock, flags);
+		ret = _imx_sema4_mutex_lock(mutex_ptr);
+		spin_unlock_irqrestore(&imx6_sema4->lock, flags);
+		if (ret == 0)
+			break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_lock);
+
+/*!
+ * \brief Unlock the mutex.
+ *
+ * This function unlocks the specified mutex.
+ *
+ * \param[in] mutex_ptr   Pointer to mutex structure.
+ *
+ * \return -EINVAL (Wrong pointer to the mutex structure provided.)
+ * \return -EINVAL (This mutex has not been locked by this core.)
+ * \return 0 (mutex successfully unlocked.)
+ *
+ * \see imx_sema4_mutex_lock
+ */
+int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr)
+{
+	int ret = 0, i = mutex_ptr->gate_num;
+
+	if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+		return -EINVAL;
+
+	mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+	mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+	/* make sure it is locked by this core */
+	if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
+		pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__);
+		ret = -EINVAL;
+		goto out;
+	}
+	/* unlock it */
+	mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+	mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+	writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i);
+	mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+	mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+	/* make sure it is locked by this core */
+	if (mutex_ptr->gate_val == SEMA4_A9_LOCK)
+		pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_unlock);
+
+/*
+ * isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting
+ * for locking semaphore.
+ * FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet!
+ */
+static irqreturn_t imx_sema4_isr(int irq, void *dev_id)
+{
+	int i;
+	struct imx_sema4_mutex *mutex_ptr;
+	u32 mask;
+	struct imx_sema4_mutex_device *imx6_sema4 = dev_id;
+
+	imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF);
+	for (i = 0; i < SEMA4_NUM_GATES; i++) {
+		mask = idx_sema4[i];
+		if ((imx6_sema4->cpntf_val) & mask) {
+			mutex_ptr = imx6_sema4->mutex_ptr[i];
+			/*
+			 * An interrupt is pending on this mutex, the only way
+			 * to clear it is to lock it (either by this core or
+			 * another).
+			 */
+			mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+			mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+			mutex_ptr->gate_val |= SEMA4_A9_LOCK;
+			writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
+			mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+			mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+			if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
+				/*
+				 * wake up the wait queue, whatever there
+				 * are wait task or not.
+				 * NOTE: check gate is locted or not in
+				 * sema4_lock func by wait task.
+				 */
+				mutex_ptr->gate_val =
+					readb(imx6_sema4->ioaddr + i);
+				mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+				mutex_ptr->gate_val |= SEMA4_UNLOCK;
+
+				writeb(mutex_ptr->gate_val,
+						imx6_sema4->ioaddr + i);
+				wake_up(&mutex_ptr->wait_q);
+			} else {
+				pr_debug("can't lock gate%d %s retry!\n", i,
+						mutex_ptr->gate_val ?
+						"locked by m4" : "");
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id imx_sema4_dt_ids[] = {
+	{ .compatible = "fsl,imx6sx-sema4", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids);
+
+static int imx_sema4_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+
+	imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL);
+	if (!imx6_sema4)
+		return -ENOMEM;
+
+	imx6_sema4->dev = &pdev->dev;
+	imx6_sema4->cpine_val = 0;
+	spin_lock_init(&imx6_sema4->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (IS_ERR(res)) {
+		dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(imx6_sema4->ioaddr)) {
+		ret = PTR_ERR(imx6_sema4->ioaddr);
+		goto err;
+	}
+
+	imx6_sema4->irq = platform_get_irq(pdev, 0);
+	if (!imx6_sema4->irq) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr,
+				IRQF_SHARED, "imx6sx-sema4", imx6_sema4);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request imx sema4 irq\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, imx6_sema4);
+
+err:
+	return ret;
+}
+
+static int imx_sema4_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver imx_sema4_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "imx-sema4",
+		   .of_match_table = imx_sema4_dt_ids,
+		   },
+	.probe = imx_sema4_probe,
+	.remove = imx_sema4_remove,
+};
+
+static int __init imx_sema4_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&imx_sema4_driver);
+	if (ret)
+		pr_err("Unable to initialize sema4 driver\n");
+	else
+		pr_info("imx sema4 driver is registered.\n");
+
+	return ret;
+}
+
+static void __exit imx_sema4_exit(void)
+{
+	pr_info("imx sema4 driver is unregistered.\n");
+	platform_driver_unregister(&imx_sema4_driver);
+}
+
+module_exit(imx_sema4_exit);
+module_init(imx_sema4_init);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IMX SEMA4 driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/char/ipmi/bt-bmc.c
+++ linux-ein-5.4.0/drivers/char/ipmi/bt-bmc.c
@@ -399,15 +399,15 @@
 	struct device *dev = &pdev->dev;
 	int rc;
 
-	bt_bmc->irq = platform_get_irq(pdev, 0);
-	if (!bt_bmc->irq)
-		return -ENODEV;
+	bt_bmc->irq = platform_get_irq_optional(pdev, 0);
+	if (bt_bmc->irq < 0)
+		return bt_bmc->irq;
 
 	rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED,
 			      DEVICE_NAME, bt_bmc);
 	if (rc < 0) {
 		dev_warn(dev, "Unable to request IRQ %d\n", bt_bmc->irq);
-		bt_bmc->irq = 0;
+		bt_bmc->irq = rc;
 		return rc;
 	}
 
@@ -479,7 +479,7 @@
 
 	bt_bmc_config_irq(bt_bmc, pdev);
 
-	if (bt_bmc->irq) {
+	if (bt_bmc->irq >= 0) {
 		dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
 	} else {
 		dev_info(dev, "No IRQ; using timer\n");
@@ -505,7 +505,7 @@
 	struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
 
 	misc_deregister(&bt_bmc->miscdev);
-	if (!bt_bmc->irq)
+	if (bt_bmc->irq < 0)
 		del_timer_sync(&bt_bmc->poll_timer);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmb_dev_int.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmb_dev_int.c
@@ -265,7 +265,7 @@
 		break;
 
 	case I2C_SLAVE_WRITE_RECEIVED:
-		if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg))
+		if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg) - 1)
 			break;
 
 		buf[++ipmb_dev->msg_idx] = *val;
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmi_msghandler.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmi_msghandler.c
@@ -11,8 +11,8 @@
  * Copyright 2002 MontaVista Software Inc.
  */
 
-#define pr_fmt(fmt) "%s" fmt, "IPMI message handler: "
-#define dev_fmt pr_fmt
+#define pr_fmt(fmt) "IPMI message handler: " fmt
+#define dev_fmt(fmt) pr_fmt(fmt)
 
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -33,6 +33,7 @@
 #include <linux/workqueue.h>
 #include <linux/uuid.h>
 #include <linux/nospec.h>
+#include <linux/vmalloc.h>
 
 #define IPMI_DRIVER_VERSION "39.2"
 
@@ -219,6 +220,8 @@
 	struct work_struct remove_work;
 };
 
+static struct workqueue_struct *remove_work_wq;
+
 static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index)
 	__acquires(user->release_barrier)
 {
@@ -448,6 +451,8 @@
 
 #define IPMI_IPMB_NUM_SEQ	64
 struct ipmi_smi {
+	struct module *owner;
+
 	/* What interface number are we? */
 	int intf_num;
 
@@ -1168,7 +1173,7 @@
 					      remove_work);
 
 	cleanup_srcu_struct(&user->release_barrier);
-	kfree(user);
+	vfree(user);
 }
 
 int ipmi_create_user(unsigned int          if_num,
@@ -1200,7 +1205,7 @@
 	if (rv)
 		return rv;
 
-	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
+	new_user = vzalloc(sizeof(*new_user));
 	if (!new_user)
 		return -ENOMEM;
 
@@ -1220,6 +1225,11 @@
 	if (rv)
 		goto out_kfree;
 
+	if (!try_module_get(intf->owner)) {
+		rv = -ENODEV;
+		goto out_kfree;
+	}
+
 	/* Note that each existing user holds a refcount to the interface. */
 	kref_get(&intf->refcount);
 
@@ -1242,7 +1252,7 @@
 
 out_kfree:
 	srcu_read_unlock(&ipmi_interfaces_srcu, index);
-	kfree(new_user);
+	vfree(new_user);
 	return rv;
 }
 EXPORT_SYMBOL(ipmi_create_user);
@@ -1278,7 +1288,7 @@
 	struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount);
 
 	/* SRCU cleanup must happen in task context. */
-	schedule_work(&user->remove_work);
+	queue_work(remove_work_wq, &user->remove_work);
 }
 
 static void _ipmi_destroy_user(struct ipmi_user *user)
@@ -1288,6 +1298,7 @@
 	unsigned long    flags;
 	struct cmd_rcvr  *rcvr;
 	struct cmd_rcvr  *rcvrs = NULL;
+	struct module    *owner;
 
 	if (!acquire_ipmi_user(user, &i)) {
 		/*
@@ -1348,7 +1359,9 @@
 		kfree(rcvr);
 	}
 
+	owner = intf->owner;
 	kref_put(&intf->refcount, intf_free);
+	module_put(owner);
 }
 
 int ipmi_destroy_user(struct ipmi_user *user)
@@ -2459,7 +2472,7 @@
  * been recently fetched, this will just use the cached data.  Otherwise
  * it will run a new fetch.
  *
- * Except for the first time this is called (in ipmi_register_smi()),
+ * Except for the first time this is called (in ipmi_add_smi()),
  * this will always return good data;
  */
 static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
@@ -2927,7 +2940,7 @@
 	 * with removing the device attributes while reading a device
 	 * attribute.
 	 */
-	schedule_work(&bmc->remove_work);
+	queue_work(remove_work_wq, &bmc->remove_work);
 }
 
 /*
@@ -3031,8 +3044,11 @@
 		bmc->pdev.name = "ipmi_bmc";
 
 		rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL);
-		if (rv < 0)
+		if (rv < 0) {
+			kfree(bmc);
 			goto out;
+		}
+
 		bmc->pdev.dev.driver = &ipmidriver.driver;
 		bmc->pdev.id = rv;
 		bmc->pdev.dev.release = release_bmc_device;
@@ -3196,8 +3212,8 @@
 	if (rv)
 		/* Send failed, no GUID available. */
 		bmc->dyn_guid_set = 0;
-
-	wait_event(intf->waitq, bmc->dyn_guid_set != 2);
+	else
+		wait_event(intf->waitq, bmc->dyn_guid_set != 2);
 
 	/* dyn_guid_set makes the guid data available. */
 	smp_rmb();
@@ -3377,10 +3393,11 @@
 	kref_put(&intf->refcount, intf_free);
 }
 
-int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
-		      void		       *send_info,
-		      struct device            *si_dev,
-		      unsigned char            slave_addr)
+int ipmi_add_smi(struct module         *owner,
+		 const struct ipmi_smi_handlers *handlers,
+		 void		       *send_info,
+		 struct device         *si_dev,
+		 unsigned char         slave_addr)
 {
 	int              i, j;
 	int              rv;
@@ -3406,7 +3423,7 @@
 		return rv;
 	}
 
-
+	intf->owner = owner;
 	intf->bmc = &intf->tmp_bmc;
 	INIT_LIST_HEAD(&intf->bmc->intfs);
 	mutex_init(&intf->bmc->dyn_mutex);
@@ -3514,18 +3531,22 @@
 
 	return rv;
 }
-EXPORT_SYMBOL(ipmi_register_smi);
+EXPORT_SYMBOL(ipmi_add_smi);
 
 static void deliver_smi_err_response(struct ipmi_smi *intf,
 				     struct ipmi_smi_msg *msg,
 				     unsigned char err)
 {
+	int rv;
 	msg->rsp[0] = msg->data[0] | 4;
 	msg->rsp[1] = msg->data[1];
 	msg->rsp[2] = err;
 	msg->rsp_size = 3;
-	/* It's an error, so it will never requeue, no need to check return. */
-	handle_one_recv_msg(intf, msg);
+
+	/* This will never requeue, but it may ask us to free the message. */
+	rv = handle_one_recv_msg(intf, msg);
+	if (rv == 0)
+		ipmi_free_smi_msg(msg);
 }
 
 static void cleanup_smi_msgs(struct ipmi_smi *intf)
@@ -4784,7 +4805,9 @@
 static void free_smi_msg(struct ipmi_smi_msg *msg)
 {
 	atomic_dec(&smi_msg_inuse_count);
-	kfree(msg);
+	/* Try to keep as much stuff out of the panic path as possible. */
+	if (!oops_in_progress)
+		kfree(msg);
 }
 
 struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
@@ -4803,7 +4826,9 @@
 static void free_recv_msg(struct ipmi_recv_msg *msg)
 {
 	atomic_dec(&recv_msg_inuse_count);
-	kfree(msg);
+	/* Try to keep as much stuff out of the panic path as possible. */
+	if (!oops_in_progress)
+		kfree(msg);
 }
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
@@ -4821,7 +4846,7 @@
 
 void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
 {
-	if (msg->user)
+	if (msg->user && !oops_in_progress)
 		kref_put(&msg->user->refcount, free_user);
 	msg->done(msg);
 }
@@ -5137,7 +5162,16 @@
 	if (initialized)
 		goto out;
 
-	init_srcu_struct(&ipmi_interfaces_srcu);
+	rv = init_srcu_struct(&ipmi_interfaces_srcu);
+	if (rv)
+		goto out;
+
+	remove_work_wq = create_singlethread_workqueue("ipmi-msghandler-remove-wq");
+	if (!remove_work_wq) {
+		pr_err("unable to create ipmi-msghandler-remove-wq workqueue");
+		rv = -ENOMEM;
+		goto out_wq;
+	}
 
 	timer_setup(&ipmi_timer, ipmi_timeout, 0);
 	mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
@@ -5146,6 +5180,9 @@
 
 	initialized = true;
 
+out_wq:
+	if (rv)
+		cleanup_srcu_struct(&ipmi_interfaces_srcu);
 out:
 	mutex_unlock(&ipmi_interfaces_mutex);
 	return rv;
@@ -5169,6 +5206,8 @@
 	int count;
 
 	if (initialized) {
+		destroy_workqueue(remove_work_wq);
+
 		atomic_notifier_chain_unregister(&panic_notifier_list,
 						 &panic_block);
 
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmi_si_intf.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmi_si_intf.c
@@ -1977,7 +1977,7 @@
 	/* Do this early so it's available for logs. */
 	if (!new_smi->io.dev) {
 		pr_err("IPMI interface added with no device\n");
-		rv = EIO;
+		rv = -EIO;
 		goto out_err;
 	}
 
@@ -2086,6 +2086,11 @@
 		new_smi->io.io_cleanup = NULL;
 	}
 
+	if (rv && new_smi->si_sm) {
+		kfree(new_smi->si_sm);
+		new_smi->si_sm = NULL;
+	}
+
 	return rv;
 }
 
@@ -2157,6 +2162,20 @@
 }
 module_init(init_ipmi_si);
 
+static void wait_msg_processed(struct smi_info *smi_info)
+{
+	unsigned long jiffies_now;
+	long time_diff;
+
+	while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
+		jiffies_now = jiffies;
+		time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
+		     * SI_USEC_PER_JIFFY);
+		smi_event_handler(smi_info, time_diff);
+		schedule_timeout_uninterruptible(1);
+	}
+}
+
 static void shutdown_smi(void *send_info)
 {
 	struct smi_info *smi_info = send_info;
@@ -2191,16 +2210,13 @@
 	 * in the BMC.  Note that timers and CPU interrupts are off,
 	 * so no need for locks.
 	 */
-	while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
-		poll(smi_info);
-		schedule_timeout_uninterruptible(1);
-	}
+	wait_msg_processed(smi_info);
+
 	if (smi_info->handlers)
 		disable_si_irq(smi_info);
-	while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
-		poll(smi_info);
-		schedule_timeout_uninterruptible(1);
-	}
+
+	wait_msg_processed(smi_info);
+
 	if (smi_info->handlers)
 		smi_info->handlers->cleanup(smi_info->si_sm);
 
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmi_si_platform.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmi_si_platform.c
@@ -194,7 +194,7 @@
 	else
 		io.slave_addr = slave_addr;
 
-	io.irq = platform_get_irq(pdev, 0);
+	io.irq = platform_get_irq_optional(pdev, 0);
 	if (io.irq > 0)
 		io.irq_setup = ipmi_std_irq_setup;
 	else
@@ -378,7 +378,7 @@
 		io.irq = tmp;
 		io.irq_setup = acpi_gpe_irq_setup;
 	} else {
-		int irq = platform_get_irq(pdev, 0);
+		int irq = platform_get_irq_optional(pdev, 0);
 
 		if (irq > 0) {
 			io.irq = irq;
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmi_ssif.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmi_ssif.c
@@ -79,7 +79,8 @@
 /*
  * Timer values
  */
-#define SSIF_MSG_USEC		20000	/* 20ms between message tries. */
+#define SSIF_MSG_USEC		60000	/* 60ms between message tries (T3). */
+#define SSIF_REQ_RETRY_USEC	60000	/* 60ms between send retries (T6). */
 #define SSIF_MSG_PART_USEC	5000	/* 5ms for a message part */
 
 /* How many times to we retry sending/receiving the message. */
@@ -87,7 +88,9 @@
 #define	SSIF_RECV_RETRIES	250
 
 #define SSIF_MSG_MSEC		(SSIF_MSG_USEC / 1000)
+#define SSIF_REQ_RETRY_MSEC	(SSIF_REQ_RETRY_USEC / 1000)
 #define SSIF_MSG_JIFFIES	((SSIF_MSG_USEC * 1000) / TICK_NSEC)
+#define SSIF_REQ_RETRY_JIFFIES	((SSIF_REQ_RETRY_USEC * 1000) / TICK_NSEC)
 #define SSIF_MSG_PART_JIFFIES	((SSIF_MSG_PART_USEC * 1000) / TICK_NSEC)
 
 /*
@@ -97,7 +100,7 @@
 #define SSIF_WATCH_WATCHDOG_TIMEOUT	msecs_to_jiffies(250)
 
 enum ssif_intf_state {
-	SSIF_NORMAL,
+	SSIF_IDLE,
 	SSIF_GETTING_FLAGS,
 	SSIF_GETTING_EVENTS,
 	SSIF_CLEARING_FLAGS,
@@ -105,8 +108,8 @@
 	/* FIXME - add watchdog stuff. */
 };
 
-#define SSIF_IDLE(ssif)	 ((ssif)->ssif_state == SSIF_NORMAL \
-			  && (ssif)->curr_msg == NULL)
+#define IS_SSIF_IDLE(ssif) ((ssif)->ssif_state == SSIF_IDLE \
+			    && (ssif)->curr_msg == NULL)
 
 /*
  * Indexes into stats[] in ssif_info below.
@@ -236,6 +239,9 @@
 	bool		    got_alert;
 	bool		    waiting_alert;
 
+	/* Used to inform the timeout that it should do a resend. */
+	bool		    do_resend;
+
 	/*
 	 * If set to true, this will request events the next time the
 	 * state machine is idle.
@@ -248,12 +254,6 @@
 	 */
 	bool                req_flags;
 
-	/*
-	 * Used to perform timer operations when run-to-completion
-	 * mode is on.  This is a countdown timer.
-	 */
-	int                 rtc_us_timer;
-
 	/* Used for sending/receiving data.  +1 for the length. */
 	unsigned char data[IPMI_MAX_MSG_LENGTH + 1];
 	unsigned int  data_len;
@@ -353,9 +353,9 @@
 
 /*
  * Must be called with the message lock held.  This will release the
- * message lock.  Note that the caller will check SSIF_IDLE and start a
- * new operation, so there is no need to check for new messages to
- * start in here.
+ * message lock.  Note that the caller will check IS_SSIF_IDLE and
+ * start a new operation, so there is no need to check for new
+ * messages to start in here.
  */
 static void start_clear_flags(struct ssif_info *ssif_info, unsigned long *flags)
 {
@@ -372,7 +372,7 @@
 
 	if (start_send(ssif_info, msg, 3) != 0) {
 		/* Error, just go to normal state. */
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 	}
 }
 
@@ -387,7 +387,7 @@
 	mb[0] = (IPMI_NETFN_APP_REQUEST << 2);
 	mb[1] = IPMI_GET_MSG_FLAGS_CMD;
 	if (start_send(ssif_info, mb, 2) != 0)
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 }
 
 static void check_start_send(struct ssif_info *ssif_info, unsigned long *flags,
@@ -398,7 +398,7 @@
 
 		flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
 		ssif_info->curr_msg = NULL;
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		ipmi_free_smi_msg(msg);
 	}
@@ -412,7 +412,7 @@
 
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
@@ -435,7 +435,7 @@
 
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
@@ -453,9 +453,9 @@
 
 /*
  * Must be called with the message lock held.  This will release the
- * message lock.  Note that the caller will check SSIF_IDLE and start a
- * new operation, so there is no need to check for new messages to
- * start in here.
+ * message lock.  Note that the caller will check IS_SSIF_IDLE and
+ * start a new operation, so there is no need to check for new
+ * messages to start in here.
  */
 static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags)
 {
@@ -471,7 +471,7 @@
 		/* Events available. */
 		start_event_fetch(ssif_info, flags);
 	else {
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 	}
 }
@@ -515,7 +515,7 @@
 	return 0;
 }
 
-static int ssif_i2c_send(struct ssif_info *ssif_info,
+static void ssif_i2c_send(struct ssif_info *ssif_info,
 			ssif_i2c_done handler,
 			int read_write, int command,
 			unsigned char *data, unsigned int size)
@@ -527,7 +527,6 @@
 	ssif_info->i2c_data = data;
 	ssif_info->i2c_size = size;
 	complete(&ssif_info->wake_thread);
-	return 0;
 }
 
 
@@ -536,40 +535,37 @@
 
 static void start_get(struct ssif_info *ssif_info)
 {
-	int rv;
-
-	ssif_info->rtc_us_timer = 0;
 	ssif_info->multi_pos = 0;
 
-	rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
-			  SSIF_IPMI_RESPONSE,
-			  ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
-	if (rv < 0) {
-		/* request failed, just return the error. */
-		if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
-			dev_dbg(&ssif_info->client->dev,
-				"Error from i2c_non_blocking_op(5)\n");
-
-		msg_done_handler(ssif_info, -EIO, NULL, 0);
-	}
+	ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
+		  SSIF_IPMI_RESPONSE,
+		  ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
 }
 
+static void start_resend(struct ssif_info *ssif_info);
+
 static void retry_timeout(struct timer_list *t)
 {
 	struct ssif_info *ssif_info = from_timer(ssif_info, t, retry_timer);
 	unsigned long oflags, *flags;
-	bool waiting;
+	bool waiting, resend;
 
 	if (ssif_info->stopping)
 		return;
 
 	flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+	resend = ssif_info->do_resend;
+	ssif_info->do_resend = false;
 	waiting = ssif_info->waiting_alert;
 	ssif_info->waiting_alert = false;
 	ipmi_ssif_unlock_cond(ssif_info, flags);
 
 	if (waiting)
 		start_get(ssif_info);
+	if (resend) {
+		start_resend(ssif_info);
+		ssif_inc_stat(ssif_info, send_retries);
+	}
 }
 
 static void watch_timeout(struct timer_list *t)
@@ -584,7 +580,7 @@
 	if (ssif_info->watch_timeout) {
 		mod_timer(&ssif_info->watch_timer,
 			  jiffies + ssif_info->watch_timeout);
-		if (SSIF_IDLE(ssif_info)) {
+		if (IS_SSIF_IDLE(ssif_info)) {
 			start_flag_fetch(ssif_info, flags); /* Releases lock */
 			return;
 		}
@@ -618,14 +614,11 @@
 		start_get(ssif_info);
 }
 
-static int start_resend(struct ssif_info *ssif_info);
-
 static void msg_done_handler(struct ssif_info *ssif_info, int result,
 			     unsigned char *data, unsigned int len)
 {
 	struct ipmi_smi_msg *msg;
 	unsigned long oflags, *flags;
-	int rv;
 
 	/*
 	 * We are single-threaded here, so no need for a lock until we
@@ -639,7 +632,6 @@
 
 			flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
 			ssif_info->waiting_alert = true;
-			ssif_info->rtc_us_timer = SSIF_MSG_USEC;
 			if (!ssif_info->stopping)
 				mod_timer(&ssif_info->retry_timer,
 					  jiffies + SSIF_MSG_JIFFIES);
@@ -671,17 +663,10 @@
 		ssif_info->multi_len = len;
 		ssif_info->multi_pos = 1;
 
-		rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
-				  SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE,
-				  ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
-		if (rv < 0) {
-			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
-				dev_dbg(&ssif_info->client->dev,
-					"Error from i2c_non_blocking_op(1)\n");
-
-			result = -EIO;
-		} else
-			return;
+		ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
+			 SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE,
+			 ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
+		return;
 	} else if (ssif_info->multi_pos) {
 		/* Middle of multi-part read.  Start the next transaction. */
 		int i;
@@ -743,19 +728,12 @@
 
 			ssif_info->multi_pos++;
 
-			rv = ssif_i2c_send(ssif_info, msg_done_handler,
-					   I2C_SMBUS_READ,
-					   SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE,
-					   ssif_info->recv,
-					   I2C_SMBUS_BLOCK_DATA);
-			if (rv < 0) {
-				if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
-					dev_dbg(&ssif_info->client->dev,
-						"Error from ssif_i2c_send\n");
-
-				result = -EIO;
-			} else
-				return;
+			ssif_i2c_send(ssif_info, msg_done_handler,
+				  I2C_SMBUS_READ,
+				  SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE,
+				  ssif_info->recv,
+				  I2C_SMBUS_BLOCK_DATA);
+			return;
 		}
 	}
 
@@ -775,15 +753,19 @@
 	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;
 	}
 
 	switch (ssif_info->ssif_state) {
-	case SSIF_NORMAL:
+	case SSIF_IDLE:
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		if (!msg)
 			break;
@@ -801,7 +783,7 @@
 			 * Error fetching flags, or invalid length,
 			 * just give up for now.
 			 */
-			ssif_info->ssif_state = SSIF_NORMAL;
+			ssif_info->ssif_state = SSIF_IDLE;
 			ipmi_ssif_unlock_cond(ssif_info, flags);
 			dev_warn(&ssif_info->client->dev,
 				 "Error getting flags: %d %d, %x\n",
@@ -809,9 +791,9 @@
 		} 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.
+			 * Recv error response, give up.
 			 */
+			ssif_info->ssif_state = SSIF_IDLE;
 			ipmi_ssif_unlock_cond(ssif_info, flags);
 			dev_warn(&ssif_info->client->dev,
 				 "Invalid response getting flags: %x %x\n",
@@ -836,11 +818,19 @@
 				 "Invalid response clearing flags: %x %x\n",
 				 data[0], data[1]);
 		}
-		ssif_info->ssif_state = SSIF_NORMAL;
+		ssif_info->ssif_state = SSIF_IDLE;
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		break;
 
 	case SSIF_GETTING_EVENTS:
+		if (!msg) {
+			/* Should never happen, but just in case. */
+			dev_warn(&ssif_info->client->dev,
+				 "No message set while getting events\n");
+			ipmi_ssif_unlock_cond(ssif_info, flags);
+			break;
+		}
+
 		if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
 			/* Error getting event, probably done. */
 			msg->done(msg);
@@ -865,6 +855,14 @@
 		break;
 
 	case SSIF_GETTING_MESSAGES:
+		if (!msg) {
+			/* Should never happen, but just in case. */
+			dev_warn(&ssif_info->client->dev,
+				 "No message set while getting messages\n");
+			ipmi_ssif_unlock_cond(ssif_info, flags);
+			break;
+		}
+
 		if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
 			/* Error getting event, probably done. */
 			msg->done(msg);
@@ -888,10 +886,17 @@
 			deliver_recv_msg(ssif_info, msg);
 		}
 		break;
+
+	default:
+		/* Should never happen, but just in case. */
+		dev_warn(&ssif_info->client->dev,
+			 "Invalid state in message done handling: %d\n",
+			 ssif_info->ssif_state);
+		ipmi_ssif_unlock_cond(ssif_info, flags);
 	}
 
 	flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
-	if (SSIF_IDLE(ssif_info) && !ssif_info->stopping) {
+	if (IS_SSIF_IDLE(ssif_info) && !ssif_info->stopping) {
 		if (ssif_info->req_events)
 			start_event_fetch(ssif_info, flags);
 		else if (ssif_info->req_flags)
@@ -909,37 +914,27 @@
 static void msg_written_handler(struct ssif_info *ssif_info, int result,
 				unsigned char *data, unsigned int len)
 {
-	int rv;
-
 	/* We are single-threaded here, so no need for a lock. */
 	if (result < 0) {
 		ssif_info->retries_left--;
 		if (ssif_info->retries_left > 0) {
-			if (!start_resend(ssif_info)) {
-				ssif_inc_stat(ssif_info, send_retries);
-				return;
-			}
-			/* request failed, just return the error. */
-			ssif_inc_stat(ssif_info, send_errors);
-
-			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
-				dev_dbg(&ssif_info->client->dev,
-					"%s: Out of retries\n", __func__);
-			msg_done_handler(ssif_info, -EIO, NULL, 0);
+			/*
+			 * Wait the retry timeout time per the spec,
+			 * then redo the send.
+			 */
+			ssif_info->do_resend = true;
+			mod_timer(&ssif_info->retry_timer,
+				  jiffies + SSIF_REQ_RETRY_JIFFIES);
 			return;
 		}
 
 		ssif_inc_stat(ssif_info, send_errors);
 
-		/*
-		 * Got an error on transmit, let the done routine
-		 * handle it.
-		 */
 		if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
 			dev_dbg(&ssif_info->client->dev,
-				"%s: Error  %d\n", __func__, result);
+				"%s: Out of retries\n", __func__);
 
-		msg_done_handler(ssif_info, result, NULL, 0);
+		msg_done_handler(ssif_info, -EIO, NULL, 0);
 		return;
 	}
 
@@ -973,18 +968,9 @@
 			ssif_info->multi_data = NULL;
 		}
 
-		rv = ssif_i2c_send(ssif_info, msg_written_handler,
-				   I2C_SMBUS_WRITE, cmd,
-				   data_to_send, I2C_SMBUS_BLOCK_DATA);
-		if (rv < 0) {
-			/* request failed, just return the error. */
-			ssif_inc_stat(ssif_info, send_errors);
-
-			if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
-				dev_dbg(&ssif_info->client->dev,
-					"Error from i2c_non_blocking_op(3)\n");
-			msg_done_handler(ssif_info, -EIO, NULL, 0);
-		}
+		ssif_i2c_send(ssif_info, msg_written_handler,
+			  I2C_SMBUS_WRITE, cmd,
+			  data_to_send, I2C_SMBUS_BLOCK_DATA);
 	} else {
 		/* Ready to request the result. */
 		unsigned long oflags, *flags;
@@ -1002,7 +988,6 @@
 			/* Wait a jiffie then request the next message */
 			ssif_info->waiting_alert = true;
 			ssif_info->retries_left = SSIF_RECV_RETRIES;
-			ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
 			if (!ssif_info->stopping)
 				mod_timer(&ssif_info->retry_timer,
 					  jiffies + SSIF_MSG_PART_JIFFIES);
@@ -1011,9 +996,8 @@
 	}
 }
 
-static int start_resend(struct ssif_info *ssif_info)
+static void start_resend(struct ssif_info *ssif_info)
 {
-	int rv;
 	int command;
 
 	ssif_info->got_alert = false;
@@ -1035,12 +1019,8 @@
 		ssif_info->data[0] = ssif_info->data_len;
 	}
 
-	rv = ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE,
-			  command, ssif_info->data, I2C_SMBUS_BLOCK_DATA);
-	if (rv && (ssif_info->ssif_debug & SSIF_DEBUG_MSG))
-		dev_dbg(&ssif_info->client->dev,
-			"Error from i2c_non_blocking_op(4)\n");
-	return rv;
+	ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE,
+		   command, ssif_info->data, I2C_SMBUS_BLOCK_DATA);
 }
 
 static int start_send(struct ssif_info *ssif_info,
@@ -1055,7 +1035,8 @@
 	ssif_info->retries_left = SSIF_SEND_RETRIES;
 	memcpy(ssif_info->data + 1, data, len);
 	ssif_info->data_len = len;
-	return start_resend(ssif_info);
+	start_resend(ssif_info);
+	return 0;
 }
 
 /* Must be called with the message lock held. */
@@ -1065,7 +1046,7 @@
 	unsigned long oflags;
 
  restart:
-	if (!SSIF_IDLE(ssif_info)) {
+	if (!IS_SSIF_IDLE(ssif_info)) {
 		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
@@ -1288,7 +1269,7 @@
 	dev_set_drvdata(&ssif_info->client->dev, NULL);
 
 	/* make sure the driver is not looking for flags any more. */
-	while (ssif_info->ssif_state != SSIF_NORMAL)
+	while (ssif_info->ssif_state != SSIF_IDLE)
 		schedule_timeout(1);
 
 	ssif_info->stopping = true;
@@ -1355,8 +1336,10 @@
 	ret = i2c_smbus_write_block_data(client, SSIF_IPMI_REQUEST, len, msg);
 	if (ret) {
 		retry_cnt--;
-		if (retry_cnt > 0)
+		if (retry_cnt > 0) {
+			msleep(SSIF_REQ_RETRY_MSEC);
 			goto retry1;
+		}
 		return -ENODEV;
 	}
 
@@ -1427,7 +1410,7 @@
 restart:
 	list_for_each_entry(info, &ssif_infos, link) {
 		if (info->binfo.addr == addr) {
-			if (info->addr_src == SI_SMBIOS)
+			if (info->addr_src == SI_SMBIOS && !info->adapter_name)
 				info->adapter_name = kstrdup(adapter_name,
 							     GFP_KERNEL);
 
@@ -1496,8 +1479,10 @@
 					 32, msg);
 	if (ret) {
 		retry_cnt--;
-		if (retry_cnt > 0)
+		if (retry_cnt > 0) {
+			msleep(SSIF_REQ_RETRY_MSEC);
 			goto retry_write;
+		}
 		dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it.  Just limit sends to one part.\n");
 		return ret;
 	}
@@ -1624,6 +1609,11 @@
 	info->addr_src = SI_ACPI;
 	info->client = client;
 	info->adapter_name = kstrdup(client->adapter->name, GFP_KERNEL);
+	if (!info->adapter_name) {
+		kfree(info);
+		return -ENOMEM;
+	}
+
 	info->binfo.addr = client->addr;
 	list_add_tail(&info->link, &ssif_infos);
 	return 0;
@@ -1700,6 +1690,9 @@
 		}
 	}
 
+	ssif_info->client = client;
+	i2c_set_clientdata(client, ssif_info);
+
 	rv = ssif_check_and_remove(client, ssif_info);
 	/* If rv is 0 and addr source is not SI_ACPI, continue probing */
 	if (!rv && ssif_info->addr_source == SI_ACPI) {
@@ -1720,9 +1713,6 @@
 		ipmi_addr_src_to_str(ssif_info->addr_source),
 		client->addr, client->adapter->name, slave_addr);
 
-	ssif_info->client = client;
-	i2c_set_clientdata(client, ssif_info);
-
 	/* Now check for system interface capabilities */
 	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
 	msg[1] = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD;
@@ -1859,7 +1849,7 @@
 	}
 
 	spin_lock_init(&ssif_info->lock);
-	ssif_info->ssif_state = SSIF_NORMAL;
+	ssif_info->ssif_state = SSIF_IDLE;
 	timer_setup(&ssif_info->retry_timer, retry_timeout, 0);
 	timer_setup(&ssif_info->watch_timer, watch_timeout, 0);
 
@@ -1922,6 +1912,7 @@
 
 		dev_err(&ssif_info->client->dev,
 			"Unable to start IPMI SSIF: %d\n", rv);
+		i2c_set_clientdata(client, NULL);
 		kfree(ssif_info);
 	}
 	kfree(resp);
--- linux-ein-5.4.0.orig/drivers/char/ipmi/ipmi_watchdog.c
+++ linux-ein-5.4.0/drivers/char/ipmi/ipmi_watchdog.c
@@ -337,13 +337,17 @@
 static DECLARE_COMPLETION(msg_wait);
 static void msg_free_smi(struct ipmi_smi_msg *msg)
 {
-	if (atomic_dec_and_test(&msg_tofree))
-		complete(&msg_wait);
+	if (atomic_dec_and_test(&msg_tofree)) {
+		if (!oops_in_progress)
+			complete(&msg_wait);
+	}
 }
 static void msg_free_recv(struct ipmi_recv_msg *msg)
 {
-	if (atomic_dec_and_test(&msg_tofree))
-		complete(&msg_wait);
+	if (atomic_dec_and_test(&msg_tofree)) {
+		if (!oops_in_progress)
+			complete(&msg_wait);
+	}
 }
 static struct ipmi_smi_msg smi_msg = {
 	.done = msg_free_smi
@@ -366,16 +370,18 @@
 	data[0] = 0;
 	WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
 
-	if ((ipmi_version_major > 1)
-	    || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
-		/* This is an IPMI 1.5-only feature. */
-		data[0] |= WDOG_DONT_STOP_ON_SET;
-	} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
-		/*
-		 * In ipmi 1.0, setting the timer stops the watchdog, we
-		 * need to start it back up again.
-		 */
-		hbnow = 1;
+	if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+		if ((ipmi_version_major > 1) ||
+		    ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
+			/* This is an IPMI 1.5-only feature. */
+			data[0] |= WDOG_DONT_STOP_ON_SET;
+		} else {
+			/*
+			 * In ipmi 1.0, setting the timer stops the watchdog, we
+			 * need to start it back up again.
+			 */
+			hbnow = 1;
+		}
 	}
 
 	data[1] = 0;
@@ -427,8 +433,10 @@
 	rv = __ipmi_set_timeout(&smi_msg,
 				&recv_msg,
 				&send_heartbeat_now);
-	if (rv)
+	if (rv) {
+		atomic_set(&msg_tofree, 0);
 		return rv;
+	}
 
 	wait_for_completion(&msg_wait);
 
@@ -490,7 +498,7 @@
 	msg.cmd = IPMI_WDOG_RESET_TIMER;
 	msg.data = NULL;
 	msg.data_len = 0;
-	atomic_add(1, &panic_done_count);
+	atomic_add(2, &panic_done_count);
 	rv = ipmi_request_supply_msgs(watchdog_user,
 				      (struct ipmi_addr *) &addr,
 				      0,
@@ -500,7 +508,7 @@
 				      &panic_halt_heartbeat_recv_msg,
 				      1);
 	if (rv)
-		atomic_sub(1, &panic_done_count);
+		atomic_sub(2, &panic_done_count);
 }
 
 static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -524,12 +532,12 @@
 	/* Wait for the messages to be free. */
 	while (atomic_read(&panic_done_count) != 0)
 		ipmi_poll_interface(watchdog_user);
-	atomic_add(1, &panic_done_count);
+	atomic_add(2, &panic_done_count);
 	rv = __ipmi_set_timeout(&panic_halt_smi_msg,
 				&panic_halt_recv_msg,
 				&send_heartbeat_now);
 	if (rv) {
-		atomic_sub(1, &panic_done_count);
+		atomic_sub(2, &panic_done_count);
 		pr_warn("Unable to extend the watchdog timeout\n");
 	} else {
 		if (send_heartbeat_now)
@@ -573,6 +581,7 @@
 				      &recv_msg,
 				      1);
 	if (rv) {
+		atomic_set(&msg_tofree, 0);
 		pr_warn("heartbeat send failure: %d\n", rv);
 		return rv;
 	}
--- linux-ein-5.4.0.orig/drivers/char/lp.c
+++ linux-ein-5.4.0/drivers/char/lp.c
@@ -713,6 +713,10 @@
 	if (copy_from_user(karg, arg, sizeof(karg)))
 		return -EFAULT;
 
+	/* sparc64 suseconds_t is 32-bit only */
+	if (IS_ENABLED(CONFIG_SPARC64) && !in_compat_syscall())
+		karg[1] >>= 32;
+
 	return lp_set_timeout(minor, karg[0], karg[1]);
 }
 
--- linux-ein-5.4.0.orig/drivers/char/mem.c
+++ linux-ein-5.4.0/drivers/char/mem.c
@@ -31,11 +31,15 @@
 #include <linux/uio.h>
 #include <linux/uaccess.h>
 #include <linux/security.h>
+#include <linux/pseudo_fs.h>
+#include <uapi/linux/magic.h>
+#include <linux/mount.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
 #endif
 
+#define DEVMEM_MINOR	1
 #define DEVPORT_MINOR	4
 
 static inline unsigned long size_inside_page(unsigned long start,
@@ -805,12 +809,65 @@
 	return ret;
 }
 
+static struct inode *devmem_inode;
+
+#ifdef CONFIG_IO_STRICT_DEVMEM
+void revoke_devmem(struct resource *res)
+{
+	/* pairs with smp_store_release() in devmem_init_inode() */
+	struct inode *inode = smp_load_acquire(&devmem_inode);
+
+	/*
+	 * Check that the initialization has completed. Losing the race
+	 * is ok because it means drivers are claiming resources before
+	 * the fs_initcall level of init and prevent /dev/mem from
+	 * establishing mappings.
+	 */
+	if (!inode)
+		return;
+
+	/*
+	 * The expectation is that the driver has successfully marked
+	 * the resource busy by this point, so devmem_is_allowed()
+	 * should start returning false, however for performance this
+	 * does not iterate the entire resource range.
+	 */
+	if (devmem_is_allowed(PHYS_PFN(res->start)) &&
+	    devmem_is_allowed(PHYS_PFN(res->end))) {
+		/*
+		 * *cringe* iomem=relaxed says "go ahead, what's the
+		 * worst that can happen?"
+		 */
+		return;
+	}
+
+	unmap_mapping_range(inode->i_mapping, res->start, resource_size(res), 1);
+}
+#endif
+
 static int open_port(struct inode *inode, struct file *filp)
 {
+	int rc;
+
 	if (!capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
-	return security_locked_down(LOCKDOWN_DEV_MEM);
+	rc = security_locked_down(LOCKDOWN_DEV_MEM);
+	if (rc)
+		return rc;
+
+	if (iminor(inode) != DEVMEM_MINOR)
+		return 0;
+
+	/*
+	 * Use a unified address space to have a single point to manage
+	 * revocations when drivers want to take over a /dev/mem mapped
+	 * range.
+	 */
+	inode->i_mapping = devmem_inode->i_mapping;
+	filp->f_mapping = inode->i_mapping;
+
+	return 0;
 }
 
 #define zero_lseek	null_lseek
@@ -885,7 +942,7 @@
 	fmode_t fmode;
 } devlist[] = {
 #ifdef CONFIG_DEVMEM
-	 [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+	 [DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
 #endif
 #ifdef CONFIG_DEVKMEM
 	 [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
@@ -896,8 +953,8 @@
 #endif
 	 [5] = { "zero", 0666, &zero_fops, 0 },
 	 [7] = { "full", 0666, &full_fops, 0 },
-	 [8] = { "random", 0666, &random_fops, 0 },
-	 [9] = { "urandom", 0666, &urandom_fops, 0 },
+	 [8] = { "random", 0666, &random_fops, FMODE_NOWAIT },
+	 [9] = { "urandom", 0666, &urandom_fops, FMODE_NOWAIT },
 #ifdef CONFIG_PRINTK
 	[11] = { "kmsg", 0644, &kmsg_fops, 0 },
 #endif
@@ -939,6 +996,48 @@
 
 static struct class *mem_class;
 
+static int devmem_fs_init_fs_context(struct fs_context *fc)
+{
+	return init_pseudo(fc, DEVMEM_MAGIC) ? 0 : -ENOMEM;
+}
+
+static struct file_system_type devmem_fs_type = {
+	.name		= "devmem",
+	.owner		= THIS_MODULE,
+	.init_fs_context = devmem_fs_init_fs_context,
+	.kill_sb	= kill_anon_super,
+};
+
+static int devmem_init_inode(void)
+{
+	static struct vfsmount *devmem_vfs_mount;
+	static int devmem_fs_cnt;
+	struct inode *inode;
+	int rc;
+
+	rc = simple_pin_fs(&devmem_fs_type, &devmem_vfs_mount, &devmem_fs_cnt);
+	if (rc < 0) {
+		pr_err("Cannot mount /dev/mem pseudo filesystem: %d\n", rc);
+		return rc;
+	}
+
+	inode = alloc_anon_inode(devmem_vfs_mount->mnt_sb);
+	if (IS_ERR(inode)) {
+		rc = PTR_ERR(inode);
+		pr_err("Cannot allocate inode for /dev/mem: %d\n", rc);
+		simple_release_fs(&devmem_vfs_mount, &devmem_fs_cnt);
+		return rc;
+	}
+
+	/*
+	 * Publish /dev/mem initialized.
+	 * Pairs with smp_load_acquire() in revoke_devmem().
+	 */
+	smp_store_release(&devmem_inode, inode);
+
+	return 0;
+}
+
 static int __init chr_dev_init(void)
 {
 	int minor;
@@ -960,6 +1059,8 @@
 		 */
 		if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
 			continue;
+		if ((minor == DEVMEM_MINOR) && devmem_init_inode() != 0)
+			continue;
 
 		device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
 			      NULL, devlist[minor].name);
--- linux-ein-5.4.0.orig/drivers/char/mwave/3780i.h
+++ linux-ein-5.4.0/drivers/char/mwave/3780i.h
@@ -68,7 +68,7 @@
 	unsigned char ClockControl:1;	/* RW: Clock control: 0=normal, 1=stop 3780i clocks */
 	unsigned char SoftReset:1;	/* RW: Soft reset 0=normal, 1=soft reset active */
 	unsigned char ConfigMode:1;	/* RW: Configuration mode, 0=normal, 1=config mode */
-	unsigned char Reserved:5;	/* 0: Reserved */
+	unsigned short Reserved:13;	/* 0: Reserved */
 } DSP_ISA_SLAVE_CONTROL;
 
 
--- linux-ein-5.4.0.orig/drivers/char/pcmcia/cm4000_cs.c
+++ linux-ein-5.4.0/drivers/char/pcmcia/cm4000_cs.c
@@ -544,6 +544,10 @@
 		io_read_num_rec_bytes(iobase, &num_bytes_read);
 		if (num_bytes_read >= 4) {
 			DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
+			if (num_bytes_read > 4) {
+				rc = -EIO;
+				goto exit_setprotocol;
+			}
 			break;
 		}
 		usleep_range(10000, 11000);
--- linux-ein-5.4.0.orig/drivers/char/ppdev.c
+++ linux-ein-5.4.0/drivers/char/ppdev.c
@@ -619,20 +619,27 @@
 		if (copy_from_user(time32, argp, sizeof(time32)))
 			return -EFAULT;
 
+		if ((time32[0] < 0) || (time32[1] < 0))
+			return -EINVAL;
+
 		return pp_set_timeout(pp->pdev, time32[0], time32[1]);
 
 	case PPSETTIME64:
 		if (copy_from_user(time64, argp, sizeof(time64)))
 			return -EFAULT;
 
+		if ((time64[0] < 0) || (time64[1] < 0))
+			return -EINVAL;
+
+		if (IS_ENABLED(CONFIG_SPARC64) && !in_compat_syscall())
+			time64[1] >>= 32;
+
 		return pp_set_timeout(pp->pdev, time64[0], time64[1]);
 
 	case PPGETTIME32:
 		jiffies_to_timespec64(pp->pdev->timeout, &ts);
 		time32[0] = ts.tv_sec;
 		time32[1] = ts.tv_nsec / NSEC_PER_USEC;
-		if ((time32[0] < 0) || (time32[1] < 0))
-			return -EINVAL;
 
 		if (copy_to_user(argp, time32, sizeof(time32)))
 			return -EFAULT;
@@ -643,8 +650,9 @@
 		jiffies_to_timespec64(pp->pdev->timeout, &ts);
 		time64[0] = ts.tv_sec;
 		time64[1] = ts.tv_nsec / NSEC_PER_USEC;
-		if ((time64[0] < 0) || (time64[1] < 0))
-			return -EINVAL;
+
+		if (IS_ENABLED(CONFIG_SPARC64) && !in_compat_syscall())
+			time64[1] <<= 32;
 
 		if (copy_to_user(argp, time64, sizeof(time64)))
 			return -EFAULT;
--- linux-ein-5.4.0.orig/drivers/char/random.c
+++ linux-ein-5.4.0/drivers/char/random.c
@@ -1,312 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
 /*
- * random.c -- A strong random number generator
- *
- * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All
- * Rights Reserved.
- *
+ * Copyright (C) 2017-2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  * Copyright Matt Mackall <mpm@selenic.com>, 2003, 2004, 2005
+ * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights reserved.
  *
- * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999.  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, and the entire permission notice in its entirety,
- *    including the disclaimer of warranties.
- * 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. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU General Public License, in which case the provisions of the GPL are
- * required INSTEAD OF the above restrictions.  (This clause is
- * necessary due to a potential bad interaction between the GPL and
- * the restrictions contained in a BSD-style copyright.)
- *
- * 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, ALL OF
- * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- */
-
-/*
- * (now, with legal B.S. out of the way.....)
- *
- * This routine gathers environmental noise from device drivers, etc.,
- * and returns good random numbers, suitable for cryptographic use.
- * Besides the obvious cryptographic uses, these numbers are also good
- * for seeding TCP sequence numbers, and other places where it is
- * desirable to have numbers which are not only random, but hard to
- * predict by an attacker.
- *
- * Theory of operation
- * ===================
- *
- * Computers are very predictable devices.  Hence it is extremely hard
- * to produce truly random numbers on a computer --- as opposed to
- * pseudo-random numbers, which can easily generated by using a
- * algorithm.  Unfortunately, it is very easy for attackers to guess
- * the sequence of pseudo-random number generators, and for some
- * applications this is not acceptable.  So instead, we must try to
- * gather "environmental noise" from the computer's environment, which
- * must be hard for outside attackers to observe, and use that to
- * generate random numbers.  In a Unix environment, this is best done
- * from inside the kernel.
- *
- * Sources of randomness from the environment include inter-keyboard
- * timings, inter-interrupt timings from some interrupts, and other
- * events which are both (a) non-deterministic and (b) hard for an
- * outside observer to measure.  Randomness from these sources are
- * added to an "entropy pool", which is mixed using a CRC-like function.
- * This is not cryptographically strong, but it is adequate assuming
- * the randomness is not chosen maliciously, and it is fast enough that
- * the overhead of doing it on every interrupt is very reasonable.
- * As random bytes are mixed into the entropy pool, the routines keep
- * an *estimate* of how many bits of randomness have been stored into
- * the random number generator's internal state.
- *
- * When random bytes are desired, they are obtained by taking the SHA
- * hash of the contents of the "entropy pool".  The SHA hash avoids
- * exposing the internal state of the entropy pool.  It is believed to
- * be computationally infeasible to derive any useful information
- * about the input of SHA from its output.  Even if it is possible to
- * analyze SHA in some clever way, as long as the amount of data
- * returned from the generator is less than the inherent entropy in
- * the pool, the output data is totally unpredictable.  For this
- * reason, the routine decreases its internal estimate of how many
- * bits of "true randomness" are contained in the entropy pool as it
- * outputs random numbers.
- *
- * If this estimate goes to zero, the routine can still generate
- * random numbers; however, an attacker may (at least in theory) be
- * able to infer the future output of the generator from prior
- * outputs.  This requires successful cryptanalysis of SHA, which is
- * not believed to be feasible, but there is a remote possibility.
- * Nonetheless, these numbers should be useful for the vast majority
- * of purposes.
- *
- * Exported interfaces ---- output
- * ===============================
- *
- * There are four exported interfaces; two for use within the kernel,
- * and two or use from userspace.
- *
- * Exported interfaces ---- userspace output
- * -----------------------------------------
- *
- * The userspace interfaces are two character devices /dev/random and
- * /dev/urandom.  /dev/random is suitable for use when very high
- * quality randomness is desired (for example, for key generation or
- * one-time pads), as it will only return a maximum of the number of
- * bits of randomness (as estimated by the random number generator)
- * contained in the entropy pool.
- *
- * The /dev/urandom device does not have this limit, and will return
- * as many bytes as are requested.  As more and more random bytes are
- * requested without giving time for the entropy pool to recharge,
- * this will result in random numbers that are merely cryptographically
- * strong.  For many applications, however, this is acceptable.
- *
- * Exported interfaces ---- kernel output
- * --------------------------------------
- *
- * The primary kernel interface is
- *
- * 	void get_random_bytes(void *buf, int nbytes);
- *
- * This interface will return the requested number of random bytes,
- * and place it in the requested buffer.  This is equivalent to a
- * read from /dev/urandom.
- *
- * For less critical applications, there are the functions:
- *
- * 	u32 get_random_u32()
- * 	u64 get_random_u64()
- * 	unsigned int get_random_int()
- * 	unsigned long get_random_long()
- *
- * These are produced by a cryptographic RNG seeded from get_random_bytes,
- * and so do not deplete the entropy pool as much.  These are recommended
- * for most in-kernel operations *if the result is going to be stored in
- * the kernel*.
- *
- * Specifically, the get_random_int() family do not attempt to do
- * "anti-backtracking".  If you capture the state of the kernel (e.g.
- * by snapshotting the VM), you can figure out previous get_random_int()
- * return values.  But if the value is stored in the kernel anyway,
- * this is not a problem.
- *
- * It *is* safe to expose get_random_int() output to attackers (e.g. as
- * network cookies); given outputs 1..n, it's not feasible to predict
- * outputs 0 or n+1.  The only concern is an attacker who breaks into
- * the kernel later; the get_random_int() engine is not reseeded as
- * often as the get_random_bytes() one.
- *
- * get_random_bytes() is needed for keys that need to stay secret after
- * they are erased from the kernel.  For example, any key that will
- * be wrapped and stored encrypted.  And session encryption keys: we'd
- * like to know that after the session is closed and the keys erased,
- * the plaintext is unrecoverable to someone who recorded the ciphertext.
- *
- * But for network ports/cookies, stack canaries, PRNG seeds, address
- * space layout randomization, session *authentication* keys, or other
- * applications where the sensitive data is stored in the kernel in
- * plaintext for as long as it's sensitive, the get_random_int() family
- * is just fine.
- *
- * Consider ASLR.  We want to keep the address space secret from an
- * outside attacker while the process is running, but once the address
- * space is torn down, it's of no use to an attacker any more.  And it's
- * stored in kernel data structures as long as it's alive, so worrying
- * about an attacker's ability to extrapolate it from the get_random_int()
- * CRNG is silly.
- *
- * Even some cryptographic keys are safe to generate with get_random_int().
- * In particular, keys for SipHash are generally fine.  Here, knowledge
- * of the key authorizes you to do something to a kernel object (inject
- * packets to a network connection, or flood a hash table), and the
- * key is stored with the object being protected.  Once it goes away,
- * we no longer care if anyone knows the key.
- *
- * prandom_u32()
- * -------------
- *
- * For even weaker applications, see the pseudorandom generator
- * prandom_u32(), prandom_max(), and prandom_bytes().  If the random
- * numbers aren't security-critical at all, these are *far* cheaper.
- * Useful for self-tests, random error simulation, randomized backoffs,
- * and any other application where you trust that nobody is trying to
- * maliciously mess with you by guessing the "random" numbers.
- *
- * Exported interfaces ---- input
- * ==============================
- *
- * The current exported interfaces for gathering environmental noise
- * from the devices are:
- *
- *	void add_device_randomness(const void *buf, unsigned int size);
- * 	void add_input_randomness(unsigned int type, unsigned int code,
- *                                unsigned int value);
- *	void add_interrupt_randomness(int irq, int irq_flags);
- * 	void add_disk_randomness(struct gendisk *disk);
- *
- * add_device_randomness() is for adding data to the random pool that
- * is likely to differ between two devices (or possibly even per boot).
- * This would be things like MAC addresses or serial numbers, or the
- * read-out of the RTC. This does *not* add any actual entropy to the
- * pool, but it initializes the pool to different values for devices
- * that might otherwise be identical and have very little entropy
- * available to them (particularly common in the embedded world).
- *
- * add_input_randomness() uses the input layer interrupt timing, as well as
- * the event type information from the hardware.
- *
- * add_interrupt_randomness() uses the interrupt timing as random
- * inputs to the entropy pool. Using the cycle counters and the irq source
- * as inputs, it feeds the randomness roughly once a second.
- *
- * add_disk_randomness() uses what amounts to the seek time of block
- * layer request events, on a per-disk_devt basis, as input to the
- * entropy pool. Note that high-speed solid state drives with very low
- * seek times do not make for good sources of entropy, as their seek
- * times are usually fairly consistent.
+ * This driver produces cryptographically secure pseudorandom data. It is divided
+ * into roughly six sections, each with a section header:
  *
- * All of these routines try to estimate how many bits of randomness a
- * particular randomness source.  They do this by keeping track of the
- * first and second order deltas of the event timings.
- *
- * Ensuring unpredictability at system startup
- * ============================================
- *
- * When any operating system starts up, it will go through a sequence
- * of actions that are fairly predictable by an adversary, especially
- * if the start-up does not involve interaction with a human operator.
- * This reduces the actual number of bits of unpredictability in the
- * entropy pool below the value in entropy_count.  In order to
- * counteract this effect, it helps to carry information in the
- * entropy pool across shut-downs and start-ups.  To do this, put the
- * following lines an appropriate script which is run during the boot
- * sequence:
- *
- *	echo "Initializing random number generator..."
- *	random_seed=/var/run/random-seed
- *	# Carry a random seed from start-up to start-up
- *	# Load and then save the whole entropy pool
- *	if [ -f $random_seed ]; then
- *		cat $random_seed >/dev/urandom
- *	else
- *		touch $random_seed
- *	fi
- *	chmod 600 $random_seed
- *	dd if=/dev/urandom of=$random_seed count=1 bs=512
- *
- * and the following lines in an appropriate script which is run as
- * the system is shutdown:
- *
- *	# Carry a random seed from shut-down to start-up
- *	# Save the whole entropy pool
- *	echo "Saving random seed..."
- *	random_seed=/var/run/random-seed
- *	touch $random_seed
- *	chmod 600 $random_seed
- *	dd if=/dev/urandom of=$random_seed count=1 bs=512
- *
- * For example, on most modern systems using the System V init
- * scripts, such code fragments would be found in
- * /etc/rc.d/init.d/random.  On older Linux systems, the correct script
- * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0.
- *
- * Effectively, these commands cause the contents of the entropy pool
- * to be saved at shut-down time and reloaded into the entropy pool at
- * start-up.  (The 'dd' in the addition to the bootup script is to
- * make sure that /etc/random-seed is different for every start-up,
- * even if the system crashes without executing rc.0.)  Even with
- * complete knowledge of the start-up activities, predicting the state
- * of the entropy pool requires knowledge of the previous history of
- * the system.
- *
- * Configuring the /dev/random driver under Linux
- * ==============================================
- *
- * The /dev/random driver under Linux uses minor numbers 8 and 9 of
- * the /dev/mem major number (#1).  So if your system does not have
- * /dev/random and /dev/urandom created already, they can be created
- * by using the commands:
- *
- * 	mknod /dev/random c 1 8
- * 	mknod /dev/urandom c 1 9
- *
- * Acknowledgements:
- * =================
- *
- * Ideas for constructing this random number generator were derived
- * from Pretty Good Privacy's random number generator, and from private
- * discussions with Phil Karn.  Colin Plumb provided a faster random
- * number generator, which speed up the mixing function of the entropy
- * pool, taken from PGPfone.  Dale Worley has also contributed many
- * useful ideas and suggestions to improve this driver.
- *
- * Any flaws in the design are solely my responsibility, and should
- * not be attributed to the Phil, Colin, or any of authors of PGP.
- *
- * Further background information on this topic may be obtained from
- * RFC 1750, "Randomness Recommendations for Security", by Donald
- * Eastlake, Steve Crocker, and Jeff Schiller.
+ *   - Initialization and readiness waiting.
+ *   - Fast key erasure RNG, the "crng".
+ *   - Entropy accumulation and extraction routines.
+ *   - Entropy collection routines.
+ *   - Userspace reader/writer interfaces.
+ *   - Sysctl interface.
+ *
+ * The high level overview is that there is one input pool, into which
+ * various pieces of data are hashed. Prior to initialization, some of that
+ * data is then "credited" as having a certain number of bits of entropy.
+ * When enough bits of entropy are available, the hash is finalized and
+ * handed as a key to a stream cipher that expands it indefinitely for
+ * various consumers. This key is periodically refreshed as the various
+ * entropy collectors, described below, add data to the input pool.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/utsname.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -325,8 +43,6 @@
 #include <linux/spinlock.h>
 #include <linux/kthread.h>
 #include <linux/percpu.h>
-#include <linux/cryptohash.h>
-#include <linux/fips.h>
 #include <linux/ptrace.h>
 #include <linux/workqueue.h>
 #include <linux/irq.h>
@@ -334,1403 +50,1085 @@
 #include <linux/syscalls.h>
 #include <linux/completion.h>
 #include <linux/uuid.h>
+#include <linux/uaccess.h>
+#include <linux/siphash.h>
+#include <linux/uio.h>
 #include <crypto/chacha.h>
-
+#include <crypto/blake2s.h>
 #include <asm/processor.h>
-#include <linux/uaccess.h>
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/io.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/random.h>
-
-/* #define ADD_INTERRUPT_BENCH */
-
-/*
- * Configuration information
- */
-#define INPUT_POOL_SHIFT	12
-#define INPUT_POOL_WORDS	(1 << (INPUT_POOL_SHIFT-5))
-#define OUTPUT_POOL_SHIFT	10
-#define OUTPUT_POOL_WORDS	(1 << (OUTPUT_POOL_SHIFT-5))
-#define SEC_XFER_SIZE		512
-#define EXTRACT_SIZE		10
-
-
-#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
-
-/*
- * To allow fractional bits to be tracked, the entropy_count field is
- * denominated in units of 1/8th bits.
- *
- * 2*(ENTROPY_SHIFT + poolbitshift) must <= 31, or the multiply in
- * credit_entropy_bits() needs to be 64 bits wide.
- */
-#define ENTROPY_SHIFT 3
-#define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT)
-
-/*
- * The minimum number of bits of entropy before we wake up a read on
- * /dev/random.  Should be enough to do a significant reseed.
- */
-static int random_read_wakeup_bits = 64;
-
-/*
- * If the entropy count falls under this number of bits, then we
- * should wake up processes which are selecting or polling on write
- * access to /dev/random.
- */
-static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;
-
-/*
- * Originally, we used a primitive polynomial of degree .poolwords
- * over GF(2).  The taps for various sizes are defined below.  They
- * were chosen to be evenly spaced except for the last tap, which is 1
- * to get the twisting happening as fast as possible.
- *
- * For the purposes of better mixing, we use the CRC-32 polynomial as
- * well to make a (modified) twisted Generalized Feedback Shift
- * Register.  (See M. Matsumoto & Y. Kurita, 1992.  Twisted GFSR
- * generators.  ACM Transactions on Modeling and Computer Simulation
- * 2(3):179-194.  Also see M. Matsumoto & Y. Kurita, 1994.  Twisted
- * GFSR generators II.  ACM Transactions on Modeling and Computer
- * Simulation 4:254-266)
- *
- * Thanks to Colin Plumb for suggesting this.
- *
- * The mixing operation is much less sensitive than the output hash,
- * where we use SHA-1.  All that we want of mixing operation is that
- * it be a good non-cryptographic hash; i.e. it not produce collisions
- * when fed "random" data of the sort we expect to see.  As long as
- * the pool state differs for different inputs, we have preserved the
- * input entropy and done a good job.  The fact that an intelligent
- * attacker can construct inputs that will produce controlled
- * alterations to the pool's state is not important because we don't
- * consider such inputs to contribute any randomness.  The only
- * property we need with respect to them is that the attacker can't
- * increase his/her knowledge of the pool's state.  Since all
- * additions are reversible (knowing the final state and the input,
- * you can reconstruct the initial state), if an attacker has any
- * uncertainty about the initial state, he/she can only shuffle that
- * uncertainty about, but never cause any collisions (which would
- * decrease the uncertainty).
- *
- * Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and
- * Videau in their paper, "The Linux Pseudorandom Number Generator
- * Revisited" (see: http://eprint.iacr.org/2012/251.pdf).  In their
- * paper, they point out that we are not using a true Twisted GFSR,
- * since Matsumoto & Kurita used a trinomial feedback polynomial (that
- * is, with only three taps, instead of the six that we are using).
- * As a result, the resulting polynomial is neither primitive nor
- * irreducible, and hence does not have a maximal period over
- * GF(2**32).  They suggest a slight change to the generator
- * polynomial which improves the resulting TGFSR polynomial to be
- * irreducible, which we have made here.
- */
-static const struct poolinfo {
-	int poolbitshift, poolwords, poolbytes, poolfracbits;
-#define S(x) ilog2(x)+5, (x), (x)*4, (x) << (ENTROPY_SHIFT+5)
-	int tap1, tap2, tap3, tap4, tap5;
-} poolinfo_table[] = {
-	/* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */
-	/* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */
-	{ S(128),	104,	76,	51,	25,	1 },
-	/* was: x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 */
-	/* x^32 + x^26 + x^19 + x^14 + x^7 + x + 1 */
-	{ S(32),	26,	19,	14,	7,	1 },
-#if 0
-	/* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1  -- 115 */
-	{ S(2048),	1638,	1231,	819,	411,	1 },
-
-	/* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
-	{ S(1024),	817,	615,	412,	204,	1 },
-
-	/* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
-	{ S(1024),	819,	616,	410,	207,	2 },
-
-	/* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
-	{ S(512),	411,	308,	208,	104,	1 },
-
-	/* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
-	{ S(512),	409,	307,	206,	102,	2 },
-	/* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */
-	{ S(512),	409,	309,	205,	103,	2 },
-
-	/* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
-	{ S(256),	205,	155,	101,	52,	1 },
-
-	/* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
-	{ S(128),	103,	78,	51,	27,	2 },
-
-	/* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */
-	{ S(64),	52,	39,	26,	14,	1 },
-#endif
-};
+/*********************************************************************
+ *
+ * Initialization and readiness waiting.
+ *
+ * Much of the RNG infrastructure is devoted to various dependencies
+ * being able to wait until the RNG has collected enough entropy and
+ * is ready for safe consumption.
+ *
+ *********************************************************************/
 
 /*
- * Static global variables
+ * crng_init is protected by base_crng->lock, and only increases
+ * its value (from empty->early->ready).
  */
-static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
-static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
+static enum {
+	CRNG_EMPTY = 0, /* Little to no entropy collected */
+	CRNG_EARLY = 1, /* At least POOL_EARLY_BITS collected */
+	CRNG_READY = 2  /* Fully initialized with POOL_READY_BITS collected */
+} crng_init __read_mostly = CRNG_EMPTY;
+#define crng_ready() (likely(crng_init >= CRNG_READY))
+/* Various types of waiters for crng_init->CRNG_READY transition. */
+static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
 static struct fasync_struct *fasync;
+static DEFINE_SPINLOCK(random_ready_chain_lock);
+static RAW_NOTIFIER_HEAD(random_ready_chain);
 
-static DEFINE_SPINLOCK(random_ready_list_lock);
-static LIST_HEAD(random_ready_list);
-
-struct crng_state {
-	__u32		state[16];
-	unsigned long	init_time;
-	spinlock_t	lock;
-};
-
-static struct crng_state primary_crng = {
-	.lock = __SPIN_LOCK_UNLOCKED(primary_crng.lock),
-};
-
-/*
- * crng_init =  0 --> Uninitialized
- *		1 --> Initialized
- *		2 --> Initialized from input_pool
- *
- * crng_init is protected by primary_crng->lock, and only increases
- * its value (from 0->1->2).
- */
-static int crng_init = 0;
-#define crng_ready() (likely(crng_init > 1))
-static int crng_init_cnt = 0;
-static unsigned long crng_global_init_time = 0;
-#define CRNG_INIT_CNT_THRESH (2*CHACHA_KEY_SIZE)
-static void _extract_crng(struct crng_state *crng, __u8 out[CHACHA_BLOCK_SIZE]);
-static void _crng_backtrack_protect(struct crng_state *crng,
-				    __u8 tmp[CHACHA_BLOCK_SIZE], int used);
-static void process_random_ready_list(void);
-static void _get_random_bytes(void *buf, int nbytes);
-
-static struct ratelimit_state unseeded_warning =
-	RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3);
+/* Control how we warn userspace. */
 static struct ratelimit_state urandom_warning =
-	RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3);
-
-static int ratelimit_disable __read_mostly;
-
+	RATELIMIT_STATE_INIT_FLAGS("urandom_warning", HZ, 3, RATELIMIT_MSG_ON_RELEASE);
+static int ratelimit_disable __read_mostly =
+	IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM);
 module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
 MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
 
-/**********************************************************************
- *
- * OS independent entropy store.   Here are the functions which handle
- * storing entropy in an entropy pool.
+/*
+ * Returns whether or not the input pool has been seeded and thus guaranteed
+ * to supply cryptographically secure random numbers. This applies to: the
+ * /dev/urandom device, the get_random_bytes function, and the get_random_{u32,
+ * ,u64,int,long} family of functions.
  *
- **********************************************************************/
-
-struct entropy_store;
-struct entropy_store {
-	/* read-only data: */
-	const struct poolinfo *poolinfo;
-	__u32 *pool;
-	const char *name;
-	struct entropy_store *pull;
-	struct work_struct push_work;
-
-	/* read-write data: */
-	unsigned long last_pulled;
-	spinlock_t lock;
-	unsigned short add_ptr;
-	unsigned short input_rotate;
-	int entropy_count;
-	unsigned int initialized:1;
-	unsigned int last_data_init:1;
-	__u8 last_data[EXTRACT_SIZE];
-};
-
-static ssize_t extract_entropy(struct entropy_store *r, void *buf,
-			       size_t nbytes, int min, int rsvd);
-static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
-				size_t nbytes, int fips);
-
-static void crng_reseed(struct crng_state *crng, struct entropy_store *r);
-static void push_to_pool(struct work_struct *work);
-static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy;
-static __u32 blocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy;
-
-static struct entropy_store input_pool = {
-	.poolinfo = &poolinfo_table[0],
-	.name = "input",
-	.lock = __SPIN_LOCK_UNLOCKED(input_pool.lock),
-	.pool = input_pool_data
-};
-
-static struct entropy_store blocking_pool = {
-	.poolinfo = &poolinfo_table[1],
-	.name = "blocking",
-	.pull = &input_pool,
-	.lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock),
-	.pool = blocking_pool_data,
-	.push_work = __WORK_INITIALIZER(blocking_pool.push_work,
-					push_to_pool),
-};
+ * Returns: true if the input pool has been seeded.
+ *          false if the input pool has not been seeded.
+ */
+bool rng_is_initialized(void)
+{
+	return crng_ready();
+}
+EXPORT_SYMBOL(rng_is_initialized);
 
-static __u32 const twist_table[8] = {
-	0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
-	0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+/* Used by wait_for_random_bytes(), and considered an entropy collector, below. */
+static void try_to_generate_entropy(void);
 
 /*
- * This function adds bytes into the entropy "pool".  It does not
- * update the entropy estimate.  The caller should call
- * credit_entropy_bits if this is appropriate.
+ * Wait for the input pool to be seeded and thus guaranteed to supply
+ * cryptographically secure random numbers. This applies to: the /dev/urandom
+ * device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
+ * family of functions. Using any of these functions without first calling
+ * this function forfeits the guarantee of security.
  *
- * The pool is stirred with a primitive polynomial of the appropriate
- * degree, and then twisted.  We twist by three bits at a time because
- * it's cheap to do so and helps slightly in the expected case where
- * the entropy is concentrated in the low-order bits.
+ * Returns: 0 if the input pool has been seeded.
+ *          -ERESTARTSYS if the function was interrupted by a signal.
  */
-static void _mix_pool_bytes(struct entropy_store *r, const void *in,
-			    int nbytes)
+int wait_for_random_bytes(void)
 {
-	unsigned long i, tap1, tap2, tap3, tap4, tap5;
-	int input_rotate;
-	int wordmask = r->poolinfo->poolwords - 1;
-	const char *bytes = in;
-	__u32 w;
-
-	tap1 = r->poolinfo->tap1;
-	tap2 = r->poolinfo->tap2;
-	tap3 = r->poolinfo->tap3;
-	tap4 = r->poolinfo->tap4;
-	tap5 = r->poolinfo->tap5;
-
-	input_rotate = r->input_rotate;
-	i = r->add_ptr;
-
-	/* mix one byte at a time to simplify size handling and churn faster */
-	while (nbytes--) {
-		w = rol32(*bytes++, input_rotate);
-		i = (i - 1) & wordmask;
+	while (!crng_ready()) {
+		int ret;
 
-		/* XOR in the various taps */
-		w ^= r->pool[i];
-		w ^= r->pool[(i + tap1) & wordmask];
-		w ^= r->pool[(i + tap2) & wordmask];
-		w ^= r->pool[(i + tap3) & wordmask];
-		w ^= r->pool[(i + tap4) & wordmask];
-		w ^= r->pool[(i + tap5) & wordmask];
+		try_to_generate_entropy();
+		ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
+		if (ret)
+			return ret > 0 ? 0 : ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(wait_for_random_bytes);
 
-		/* Mix the result back in with a twist */
-		r->pool[i] = (w >> 3) ^ twist_table[w & 7];
+/*
+ * Add a callback function that will be invoked when the input
+ * pool is initialised.
+ *
+ * returns: 0 if callback is successfully added
+ *	    -EALREADY if pool is already initialised (callback not called)
+ */
+int __cold register_random_ready_notifier(struct notifier_block *nb)
+{
+	unsigned long flags;
+	int ret = -EALREADY;
 
-		/*
-		 * Normally, we add 7 bits of rotation to the pool.
-		 * At the beginning of the pool, add an extra 7 bits
-		 * rotation, so that successive passes spread the
-		 * input bits across the pool evenly.
-		 */
-		input_rotate = (input_rotate + (i ? 7 : 14)) & 31;
-	}
+	if (crng_ready())
+		return ret;
 
-	r->input_rotate = input_rotate;
-	r->add_ptr = i;
+	spin_lock_irqsave(&random_ready_chain_lock, flags);
+	if (!crng_ready())
+		ret = raw_notifier_chain_register(&random_ready_chain, nb);
+	spin_unlock_irqrestore(&random_ready_chain_lock, flags);
+	return ret;
 }
 
-static void __mix_pool_bytes(struct entropy_store *r, const void *in,
-			     int nbytes)
+/*
+ * Delete a previously registered readiness callback function.
+ */
+int __cold unregister_random_ready_notifier(struct notifier_block *nb)
 {
-	trace_mix_pool_bytes_nolock(r->name, nbytes, _RET_IP_);
-	_mix_pool_bytes(r, in, nbytes);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&random_ready_chain_lock, flags);
+	ret = raw_notifier_chain_unregister(&random_ready_chain, nb);
+	spin_unlock_irqrestore(&random_ready_chain_lock, flags);
+	return ret;
 }
 
-static void mix_pool_bytes(struct entropy_store *r, const void *in,
-			   int nbytes)
+static void __cold process_random_ready_list(void)
 {
 	unsigned long flags;
 
-	trace_mix_pool_bytes(r->name, nbytes, _RET_IP_);
-	spin_lock_irqsave(&r->lock, flags);
-	_mix_pool_bytes(r, in, nbytes);
-	spin_unlock_irqrestore(&r->lock, flags);
+	spin_lock_irqsave(&random_ready_chain_lock, flags);
+	raw_notifier_call_chain(&random_ready_chain, 0, NULL);
+	spin_unlock_irqrestore(&random_ready_chain_lock, flags);
 }
 
-struct fast_pool {
-	__u32		pool[4];
-	unsigned long	last;
-	unsigned short	reg_idx;
-	unsigned char	count;
-};
+#define warn_unseeded_randomness() \
+	if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
+		printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
+				__func__, (void *)_RET_IP_, crng_init)
 
-/*
- * This is a fast mixing routine used by the interrupt randomness
- * collector.  It's hardcoded for an 128 bit pool and assumes that any
- * locks that might be needed are taken by the caller.
- */
-static void fast_mix(struct fast_pool *f)
-{
-	__u32 a = f->pool[0],	b = f->pool[1];
-	__u32 c = f->pool[2],	d = f->pool[3];
 
-	a += b;			c += d;
-	b = rol32(b, 6);	d = rol32(d, 27);
-	d ^= a;			b ^= c;
+/*********************************************************************
+ *
+ * Fast key erasure RNG, the "crng".
+ *
+ * These functions expand entropy from the entropy extractor into
+ * long streams for external consumption using the "fast key erasure"
+ * RNG described at <https://blog.cr.yp.to/20170723-random.html>.
+ *
+ * There are a few exported interfaces for use by other drivers:
+ *
+ *	void get_random_bytes(void *buf, size_t len)
+ *	u32 get_random_u32()
+ *	u64 get_random_u64()
+ *	unsigned int get_random_int()
+ *	unsigned long get_random_long()
+ *
+ * These interfaces will return the requested number of random bytes
+ * into the given buffer or as a return value. This is equivalent to
+ * a read from /dev/urandom. The u32, u64, int, and long family of
+ * functions may be higher performance for one-off random integers,
+ * because they do a bit of buffering and do not invoke reseeding
+ * until the buffer is emptied.
+ *
+ *********************************************************************/
+
+enum {
+	CRNG_RESEED_START_INTERVAL = HZ,
+	CRNG_RESEED_INTERVAL = 60 * HZ
+};
 
-	a += b;			c += d;
-	b = rol32(b, 16);	d = rol32(d, 14);
-	d ^= a;			b ^= c;
+static struct {
+	u8 key[CHACHA_KEY_SIZE] __aligned(__alignof__(long));
+	unsigned long birth;
+	unsigned long generation;
+	spinlock_t lock;
+} base_crng = {
+	.lock = __SPIN_LOCK_UNLOCKED(base_crng.lock)
+};
 
-	a += b;			c += d;
-	b = rol32(b, 6);	d = rol32(d, 27);
-	d ^= a;			b ^= c;
+struct crng {
+	u8 key[CHACHA_KEY_SIZE];
+	unsigned long generation;
+};
 
-	a += b;			c += d;
-	b = rol32(b, 16);	d = rol32(d, 14);
-	d ^= a;			b ^= c;
+static DEFINE_PER_CPU(struct crng, crngs) = {
+	.generation = ULONG_MAX
+};
 
-	f->pool[0] = a;  f->pool[1] = b;
-	f->pool[2] = c;  f->pool[3] = d;
-	f->count++;
-}
+/* Used by crng_reseed() and crng_make_state() to extract a new seed from the input pool. */
+static void extract_entropy(void *buf, size_t len);
 
-static void process_random_ready_list(void)
+/* This extracts a new crng key from the input pool. */
+static void crng_reseed(void)
 {
 	unsigned long flags;
-	struct random_ready_callback *rdy, *tmp;
+	unsigned long next_gen;
+	u8 key[CHACHA_KEY_SIZE];
 
-	spin_lock_irqsave(&random_ready_list_lock, flags);
-	list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) {
-		struct module *owner = rdy->owner;
+	extract_entropy(key, sizeof(key));
 
-		list_del_init(&rdy->list);
-		rdy->func(rdy);
-		module_put(owner);
-	}
-	spin_unlock_irqrestore(&random_ready_list_lock, flags);
+	/*
+	 * We copy the new key into the base_crng, overwriting the old one,
+	 * and update the generation counter. We avoid hitting ULONG_MAX,
+	 * because the per-cpu crngs are initialized to ULONG_MAX, so this
+	 * forces new CPUs that come online to always initialize.
+	 */
+	spin_lock_irqsave(&base_crng.lock, flags);
+	memcpy(base_crng.key, key, sizeof(base_crng.key));
+	next_gen = base_crng.generation + 1;
+	if (next_gen == ULONG_MAX)
+		++next_gen;
+	WRITE_ONCE(base_crng.generation, next_gen);
+	WRITE_ONCE(base_crng.birth, jiffies);
+	if (!crng_ready())
+		crng_init = CRNG_READY;
+	spin_unlock_irqrestore(&base_crng.lock, flags);
+	memzero_explicit(key, sizeof(key));
 }
 
 /*
- * Credit (or debit) the entropy store with n bits of entropy.
- * Use credit_entropy_bits_safe() if the value comes from userspace
- * or otherwise should be checked for extreme values.
+ * This generates a ChaCha block using the provided key, and then
+ * immediately overwites that key with half the block. It returns
+ * the resultant ChaCha state to the user, along with the second
+ * half of the block containing 32 bytes of random data that may
+ * be used; random_data_len may not be greater than 32.
+ *
+ * The returned ChaCha state contains within it a copy of the old
+ * key value, at index 4, so the state should always be zeroed out
+ * immediately after using in order to maintain forward secrecy.
+ * If the state cannot be erased in a timely manner, then it is
+ * safer to set the random_data parameter to &chacha_state[4] so
+ * that this function overwrites it before returning.
  */
-static void credit_entropy_bits(struct entropy_store *r, int nbits)
+static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE],
+				  u32 chacha_state[CHACHA_BLOCK_SIZE / sizeof(u32)],
+				  u8 *random_data, size_t random_data_len)
 {
-	int entropy_count, orig, has_initialized = 0;
-	const int pool_size = r->poolinfo->poolfracbits;
-	int nfrac = nbits << ENTROPY_SHIFT;
+	u8 first_block[CHACHA_BLOCK_SIZE];
 
-	if (!nbits)
-		return;
+	BUG_ON(random_data_len > 32);
 
-retry:
-	entropy_count = orig = READ_ONCE(r->entropy_count);
-	if (nfrac < 0) {
-		/* Debit */
-		entropy_count += nfrac;
-	} else {
-		/*
-		 * Credit: we have to account for the possibility of
-		 * overwriting already present entropy.	 Even in the
-		 * ideal case of pure Shannon entropy, new contributions
-		 * approach the full value asymptotically:
-		 *
-		 * entropy <- entropy + (pool_size - entropy) *
-		 *	(1 - exp(-add_entropy/pool_size))
-		 *
-		 * For add_entropy <= pool_size/2 then
-		 * (1 - exp(-add_entropy/pool_size)) >=
-		 *    (add_entropy/pool_size)*0.7869...
-		 * so we can approximate the exponential with
-		 * 3/4*add_entropy/pool_size and still be on the
-		 * safe side by adding at most pool_size/2 at a time.
-		 *
-		 * The use of pool_size-2 in the while statement is to
-		 * prevent rounding artifacts from making the loop
-		 * arbitrarily long; this limits the loop to log2(pool_size)*2
-		 * turns no matter how large nbits is.
-		 */
-		int pnfrac = nfrac;
-		const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2;
-		/* The +2 corresponds to the /4 in the denominator */
-
-		do {
-			unsigned int anfrac = min(pnfrac, pool_size/2);
-			unsigned int add =
-				((pool_size - entropy_count)*anfrac*3) >> s;
-
-			entropy_count += add;
-			pnfrac -= anfrac;
-		} while (unlikely(entropy_count < pool_size-2 && pnfrac));
-	}
-
-	if (unlikely(entropy_count < 0)) {
-		pr_warn("random: negative entropy/overflow: pool %s count %d\n",
-			r->name, entropy_count);
-		WARN_ON(1);
-		entropy_count = 0;
-	} else if (entropy_count > pool_size)
-		entropy_count = pool_size;
-	if ((r == &blocking_pool) && !r->initialized &&
-	    (entropy_count >> ENTROPY_SHIFT) > 128)
-		has_initialized = 1;
-	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
-		goto retry;
-
-	if (has_initialized) {
-		r->initialized = 1;
-		wake_up_interruptible(&random_read_wait);
-		kill_fasync(&fasync, SIGIO, POLL_IN);
-	}
+	chacha_init_consts(chacha_state);
+	memcpy(&chacha_state[4], key, CHACHA_KEY_SIZE);
+	memset(&chacha_state[12], 0, sizeof(u32) * 4);
+	chacha20_block(chacha_state, first_block);
 
-	trace_credit_entropy_bits(r->name, nbits,
-				  entropy_count >> ENTROPY_SHIFT, _RET_IP_);
-
-	if (r == &input_pool) {
-		int entropy_bits = entropy_count >> ENTROPY_SHIFT;
-		struct entropy_store *other = &blocking_pool;
-
-		if (crng_init < 2) {
-			if (entropy_bits < 128)
-				return;
-			crng_reseed(&primary_crng, r);
-			entropy_bits = r->entropy_count >> ENTROPY_SHIFT;
-		}
-
-		/* initialize the blocking pool if necessary */
-		if (entropy_bits >= random_read_wakeup_bits &&
-		    !other->initialized) {
-			schedule_work(&other->push_work);
-			return;
-		}
-
-		/* should we wake readers? */
-		if (entropy_bits >= random_read_wakeup_bits &&
-		    wq_has_sleeper(&random_read_wait)) {
-			wake_up_interruptible(&random_read_wait);
-			kill_fasync(&fasync, SIGIO, POLL_IN);
-		}
-		/* If the input pool is getting full, and the blocking
-		 * pool has room, send some entropy to the blocking
-		 * pool.
-		 */
-		if (!work_pending(&other->push_work) &&
-		    (ENTROPY_BITS(r) > 6 * r->poolinfo->poolbytes) &&
-		    (ENTROPY_BITS(other) <= 6 * other->poolinfo->poolbytes))
-			schedule_work(&other->push_work);
-	}
+	memcpy(key, first_block, CHACHA_KEY_SIZE);
+	memcpy(random_data, first_block + CHACHA_KEY_SIZE, random_data_len);
+	memzero_explicit(first_block, sizeof(first_block));
 }
 
-static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
+/*
+ * Return whether the crng seed is considered to be sufficiently old
+ * that a reseeding is needed. This happens if the last reseeding
+ * was CRNG_RESEED_INTERVAL ago, or during early boot, at an interval
+ * proportional to the uptime.
+ */
+static bool crng_has_old_seed(void)
 {
-	const int nbits_max = r->poolinfo->poolwords * 32;
+	static bool early_boot = true;
+	unsigned long interval = CRNG_RESEED_INTERVAL;
 
-	if (nbits < 0)
-		return -EINVAL;
-
-	/* Cap the value to avoid overflows */
-	nbits = min(nbits,  nbits_max);
-
-	credit_entropy_bits(r, nbits);
-	return 0;
+	if (unlikely(READ_ONCE(early_boot))) {
+		time64_t uptime = ktime_get_seconds();
+		if (uptime >= CRNG_RESEED_INTERVAL / HZ * 2)
+			WRITE_ONCE(early_boot, false);
+		else
+			interval = max_t(unsigned int, CRNG_RESEED_START_INTERVAL,
+					 (unsigned int)uptime / 2 * HZ);
+	}
+	return time_is_before_jiffies(READ_ONCE(base_crng.birth) + interval);
 }
 
-/*********************************************************************
- *
- * CRNG using CHACHA20
- *
- *********************************************************************/
-
-#define CRNG_RESEED_INTERVAL (300*HZ)
-
-static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
-
-#ifdef CONFIG_NUMA
 /*
- * Hack to deal with crazy userspace progams when they are all trying
- * to access /dev/urandom in parallel.  The programs are almost
- * certainly doing something terribly wrong, but we'll work around
- * their brain damage.
+ * This function returns a ChaCha state that you may use for generating
+ * random data. It also returns up to 32 bytes on its own of random data
+ * that may be used; random_data_len may not be greater than 32.
  */
-static struct crng_state **crng_node_pool __read_mostly;
-#endif
+static void crng_make_state(u32 chacha_state[CHACHA_BLOCK_SIZE / sizeof(u32)],
+			    u8 *random_data, size_t random_data_len)
+{
+	unsigned long flags;
+	struct crng *crng;
 
-static void invalidate_batched_entropy(void);
-static void numa_crng_init(void);
+	BUG_ON(random_data_len > 32);
 
-static bool trust_cpu __ro_after_init = IS_ENABLED(CONFIG_RANDOM_TRUST_CPU);
-static int __init parse_trust_cpu(char *arg)
-{
-	return kstrtobool(arg, &trust_cpu);
-}
-early_param("random.trust_cpu", parse_trust_cpu);
+	/*
+	 * For the fast path, we check whether we're ready, unlocked first, and
+	 * then re-check once locked later. In the case where we're really not
+	 * ready, we do fast key erasure with the base_crng directly, extracting
+	 * when crng_init is CRNG_EMPTY.
+	 */
+	if (!crng_ready()) {
+		bool ready;
 
-static void crng_initialize(struct crng_state *crng)
-{
-	int		i;
-	int		arch_init = 1;
-	unsigned long	rv;
-
-	memcpy(&crng->state[0], "expand 32-byte k", 16);
-	if (crng == &primary_crng)
-		_extract_entropy(&input_pool, &crng->state[4],
-				 sizeof(__u32) * 12, 0);
-	else
-		_get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
-	for (i = 4; i < 16; i++) {
-		if (!arch_get_random_seed_long(&rv) &&
-		    !arch_get_random_long(&rv)) {
-			rv = random_get_entropy();
-			arch_init = 0;
+		spin_lock_irqsave(&base_crng.lock, flags);
+		ready = crng_ready();
+		if (!ready) {
+			if (crng_init == CRNG_EMPTY)
+				extract_entropy(base_crng.key, sizeof(base_crng.key));
+			crng_fast_key_erasure(base_crng.key, chacha_state,
+					      random_data, random_data_len);
 		}
-		crng->state[i] ^= rv;
+		spin_unlock_irqrestore(&base_crng.lock, flags);
+		if (!ready)
+			return;
 	}
-	if (trust_cpu && arch_init && crng == &primary_crng) {
-		invalidate_batched_entropy();
-		numa_crng_init();
-		crng_init = 2;
-		pr_notice("random: crng done (trusting CPU's manufacturer)\n");
+
+	/*
+	 * If the base_crng is old enough, we reseed, which in turn bumps the
+	 * generation counter that we check below.
+	 */
+	if (unlikely(crng_has_old_seed()))
+		crng_reseed();
+
+	local_irq_save(flags);
+	crng = raw_cpu_ptr(&crngs);
+
+	/*
+	 * If our per-cpu crng is older than the base_crng, then it means
+	 * somebody reseeded the base_crng. In that case, we do fast key
+	 * erasure on the base_crng, and use its output as the new key
+	 * for our per-cpu crng. This brings us up to date with base_crng.
+	 */
+	if (unlikely(crng->generation != READ_ONCE(base_crng.generation))) {
+		spin_lock(&base_crng.lock);
+		crng_fast_key_erasure(base_crng.key, chacha_state,
+				      crng->key, sizeof(crng->key));
+		crng->generation = base_crng.generation;
+		spin_unlock(&base_crng.lock);
 	}
-	crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
+
+	/*
+	 * Finally, when we've made it this far, our per-cpu crng has an up
+	 * to date key, and we can do fast key erasure with it to produce
+	 * some random data and a ChaCha state for the caller. All other
+	 * branches of this function are "unlikely", so most of the time we
+	 * should wind up here immediately.
+	 */
+	crng_fast_key_erasure(crng->key, chacha_state, random_data, random_data_len);
+	local_irq_restore(flags);
 }
 
-#ifdef CONFIG_NUMA
-static void do_numa_crng_init(struct work_struct *work)
+static void _get_random_bytes(void *buf, size_t len)
 {
-	int i;
-	struct crng_state *crng;
-	struct crng_state **pool;
+	u32 chacha_state[CHACHA_BLOCK_SIZE / sizeof(u32)];
+	u8 tmp[CHACHA_BLOCK_SIZE];
+	size_t first_block_len;
 
-	pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL);
-	for_each_online_node(i) {
-		crng = kmalloc_node(sizeof(struct crng_state),
-				    GFP_KERNEL | __GFP_NOFAIL, i);
-		spin_lock_init(&crng->lock);
-		crng_initialize(crng);
-		pool[i] = crng;
-	}
-	mb();
-	if (cmpxchg(&crng_node_pool, NULL, pool)) {
-		for_each_node(i)
-			kfree(pool[i]);
-		kfree(pool);
-	}
-}
+	if (!len)
+		return;
 
-static DECLARE_WORK(numa_crng_init_work, do_numa_crng_init);
+	first_block_len = min_t(size_t, 32, len);
+	crng_make_state(chacha_state, buf, first_block_len);
+	len -= first_block_len;
+	buf += first_block_len;
+
+	while (len) {
+		if (len < CHACHA_BLOCK_SIZE) {
+			chacha20_block(chacha_state, tmp);
+			memcpy(buf, tmp, len);
+			memzero_explicit(tmp, sizeof(tmp));
+			break;
+		}
 
-static void numa_crng_init(void)
-{
-	schedule_work(&numa_crng_init_work);
+		chacha20_block(chacha_state, buf);
+		if (unlikely(chacha_state[12] == 0))
+			++chacha_state[13];
+		len -= CHACHA_BLOCK_SIZE;
+		buf += CHACHA_BLOCK_SIZE;
+	}
+
+	memzero_explicit(chacha_state, sizeof(chacha_state));
 }
-#else
-static void numa_crng_init(void) {}
-#endif
 
 /*
- * crng_fast_load() can be called by code in the interrupt service
- * path.  So we can't afford to dilly-dally.
+ * This function is the exported kernel interface.  It returns some
+ * number of good random numbers, suitable for key generation, seeding
+ * TCP sequence numbers, etc.  It does not rely on the hardware random
+ * number generator.  For random bytes direct from the hardware RNG
+ * (when available), use get_random_bytes_arch(). In order to ensure
+ * that the randomness provided by this function is okay, the function
+ * wait_for_random_bytes() should be called and return 0 at least once
+ * at any point prior.
  */
-static int crng_fast_load(const char *cp, size_t len)
+void get_random_bytes(void *buf, size_t len)
 {
-	unsigned long flags;
-	char *p;
-
-	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
-		return 0;
-	if (crng_init != 0) {
-		spin_unlock_irqrestore(&primary_crng.lock, flags);
-		return 0;
-	}
-	p = (unsigned char *) &primary_crng.state[4];
-	while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) {
-		p[crng_init_cnt % CHACHA_KEY_SIZE] ^= *cp;
-		cp++; crng_init_cnt++; len--;
-	}
-	spin_unlock_irqrestore(&primary_crng.lock, flags);
-	if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
-		invalidate_batched_entropy();
-		crng_init = 1;
-		wake_up_interruptible(&crng_init_wait);
-		pr_notice("random: fast init done\n");
-	}
-	return 1;
+	warn_unseeded_randomness();
+	_get_random_bytes(buf, len);
 }
+EXPORT_SYMBOL(get_random_bytes);
 
-/*
- * crng_slow_load() is called by add_device_randomness, which has two
- * attributes.  (1) We can't trust the buffer passed to it is
- * guaranteed to be unpredictable (so it might not have any entropy at
- * all), and (2) it doesn't have the performance constraints of
- * crng_fast_load().
- *
- * So we do something more comprehensive which is guaranteed to touch
- * all of the primary_crng's state, and which uses a LFSR with a
- * period of 255 as part of the mixing algorithm.  Finally, we do
- * *not* advance crng_init_cnt since buffer we may get may be something
- * like a fixed DMI table (for example), which might very well be
- * unique to the machine, but is otherwise unvarying.
- */
-static int crng_slow_load(const char *cp, size_t len)
+static ssize_t get_random_bytes_user(struct iov_iter *iter)
 {
-	unsigned long		flags;
-	static unsigned char	lfsr = 1;
-	unsigned char		tmp;
-	unsigned		i, max = CHACHA_KEY_SIZE;
-	const char *		src_buf = cp;
-	char *			dest_buf = (char *) &primary_crng.state[4];
+	u32 chacha_state[CHACHA_BLOCK_SIZE / sizeof(u32)];
+	u8 block[CHACHA_BLOCK_SIZE];
+	size_t ret = 0, copied;
 
-	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
-		return 0;
-	if (crng_init != 0) {
-		spin_unlock_irqrestore(&primary_crng.lock, flags);
+	if (unlikely(!iov_iter_count(iter)))
 		return 0;
+
+	/*
+	 * Immediately overwrite the ChaCha key at index 4 with random
+	 * bytes, in case userspace causes copy_to_iter() below to sleep
+	 * forever, so that we still retain forward secrecy in that case.
+	 */
+	crng_make_state(chacha_state, (u8 *)&chacha_state[4], CHACHA_KEY_SIZE);
+	/*
+	 * However, if we're doing a read of len <= 32, we don't need to
+	 * use chacha_state after, so we can simply return those bytes to
+	 * the user directly.
+	 */
+	if (iov_iter_count(iter) <= CHACHA_KEY_SIZE) {
+		ret = copy_to_iter(&chacha_state[4], CHACHA_KEY_SIZE, iter);
+		goto out_zero_chacha;
 	}
-	if (len > max)
-		max = len;
 
-	for (i = 0; i < max ; i++) {
-		tmp = lfsr;
-		lfsr >>= 1;
-		if (tmp & 1)
-			lfsr ^= 0xE1;
-		tmp = dest_buf[i % CHACHA_KEY_SIZE];
-		dest_buf[i % CHACHA_KEY_SIZE] ^= src_buf[i % len] ^ lfsr;
-		lfsr += (tmp << 3) | (tmp >> 5);
-	}
-	spin_unlock_irqrestore(&primary_crng.lock, flags);
-	return 1;
-}
-
-static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
-{
-	unsigned long	flags;
-	int		i, num;
-	union {
-		__u8	block[CHACHA_BLOCK_SIZE];
-		__u32	key[8];
-	} buf;
-
-	if (r) {
-		num = extract_entropy(r, &buf, 32, 16, 0);
-		if (num == 0)
-			return;
-	} else {
-		_extract_crng(&primary_crng, buf.block);
-		_crng_backtrack_protect(&primary_crng, buf.block,
-					CHACHA_KEY_SIZE);
-	}
-	spin_lock_irqsave(&crng->lock, flags);
-	for (i = 0; i < 8; i++) {
-		unsigned long	rv;
-		if (!arch_get_random_seed_long(&rv) &&
-		    !arch_get_random_long(&rv))
-			rv = random_get_entropy();
-		crng->state[i+4] ^= buf.key[i] ^ rv;
-	}
-	memzero_explicit(&buf, sizeof(buf));
-	crng->init_time = jiffies;
-	spin_unlock_irqrestore(&crng->lock, flags);
-	if (crng == &primary_crng && crng_init < 2) {
-		invalidate_batched_entropy();
-		numa_crng_init();
-		crng_init = 2;
-		process_random_ready_list();
-		wake_up_interruptible(&crng_init_wait);
-		pr_notice("random: crng init done\n");
-		if (unseeded_warning.missed) {
-			pr_notice("random: %d get_random_xx warning(s) missed "
-				  "due to ratelimiting\n",
-				  unseeded_warning.missed);
-			unseeded_warning.missed = 0;
-		}
-		if (urandom_warning.missed) {
-			pr_notice("random: %d urandom warning(s) missed "
-				  "due to ratelimiting\n",
-				  urandom_warning.missed);
-			urandom_warning.missed = 0;
+	for (;;) {
+		chacha20_block(chacha_state, block);
+		if (unlikely(chacha_state[12] == 0))
+			++chacha_state[13];
+
+		copied = copy_to_iter(block, sizeof(block), iter);
+		ret += copied;
+		if (!iov_iter_count(iter) || copied != sizeof(block))
+			break;
+
+		BUILD_BUG_ON(PAGE_SIZE % sizeof(block) != 0);
+		if (ret % PAGE_SIZE == 0) {
+			if (signal_pending(current))
+				break;
+			cond_resched();
 		}
 	}
-}
 
-static void _extract_crng(struct crng_state *crng,
-			  __u8 out[CHACHA_BLOCK_SIZE])
-{
-	unsigned long v, flags;
-
-	if (crng_ready() &&
-	    (time_after(crng_global_init_time, crng->init_time) ||
-	     time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)))
-		crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
-	spin_lock_irqsave(&crng->lock, flags);
-	if (arch_get_random_long(&v))
-		crng->state[14] ^= v;
-	chacha20_block(&crng->state[0], out);
-	if (crng->state[12] == 0)
-		crng->state[13]++;
-	spin_unlock_irqrestore(&crng->lock, flags);
-}
-
-static void extract_crng(__u8 out[CHACHA_BLOCK_SIZE])
-{
-	struct crng_state *crng = NULL;
-
-#ifdef CONFIG_NUMA
-	if (crng_node_pool)
-		crng = crng_node_pool[numa_node_id()];
-	if (crng == NULL)
-#endif
-		crng = &primary_crng;
-	_extract_crng(crng, out);
-}
+	memzero_explicit(block, sizeof(block));
+out_zero_chacha:
+	memzero_explicit(chacha_state, sizeof(chacha_state));
+	return ret ? ret : -EFAULT;
+}
+
+/*
+ * Batched entropy returns random integers. The quality of the random
+ * number is good as /dev/urandom. In order to ensure that the randomness
+ * provided by this function is okay, the function wait_for_random_bytes()
+ * should be called and return 0 at least once at any point prior.
+ */
+
+#define DEFINE_BATCHED_ENTROPY(type)						\
+struct batch_ ##type {								\
+	/*									\
+	 * We make this 1.5x a ChaCha block, so that we get the			\
+	 * remaining 32 bytes from fast key erasure, plus one full		\
+	 * block from the detached ChaCha state. We can increase		\
+	 * the size of this later if needed so long as we keep the		\
+	 * formula of (integer_blocks + 0.5) * CHACHA_BLOCK_SIZE.		\
+	 */									\
+	type entropy[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(type))];		\
+	unsigned long generation;						\
+	unsigned int position;							\
+};										\
+										\
+static DEFINE_PER_CPU(struct batch_ ##type, batched_entropy_ ##type) = {	\
+	.position = UINT_MAX							\
+};										\
+										\
+type get_random_ ##type(void)							\
+{										\
+	type ret;								\
+	unsigned long flags;							\
+	struct batch_ ##type *batch;						\
+	unsigned long next_gen;							\
+										\
+	warn_unseeded_randomness();						\
+										\
+	if  (!crng_ready()) {							\
+		_get_random_bytes(&ret, sizeof(ret));				\
+		return ret;							\
+	}									\
+										\
+	local_irq_save(flags);		\
+	batch = raw_cpu_ptr(&batched_entropy_##type);				\
+										\
+	next_gen = READ_ONCE(base_crng.generation);				\
+	if (batch->position >= ARRAY_SIZE(batch->entropy) ||			\
+	    next_gen != batch->generation) {					\
+		_get_random_bytes(batch->entropy, sizeof(batch->entropy));	\
+		batch->position = 0;						\
+		batch->generation = next_gen;					\
+	}									\
+										\
+	ret = batch->entropy[batch->position];					\
+	batch->entropy[batch->position] = 0;					\
+	++batch->position;							\
+	local_irq_restore(flags);		\
+	return ret;								\
+}										\
+EXPORT_SYMBOL(get_random_ ##type);
+
+DEFINE_BATCHED_ENTROPY(u64)
+DEFINE_BATCHED_ENTROPY(u32)
 
+#ifdef CONFIG_SMP
 /*
- * Use the leftover bytes from the CRNG block output (if there is
- * enough) to mutate the CRNG key to provide backtracking protection.
+ * This function is called when the CPU is coming up, with entry
+ * CPUHP_RANDOM_PREPARE, which comes before CPUHP_WORKQUEUE_PREP.
  */
-static void _crng_backtrack_protect(struct crng_state *crng,
-				    __u8 tmp[CHACHA_BLOCK_SIZE], int used)
+int __cold random_prepare_cpu(unsigned int cpu)
 {
-	unsigned long	flags;
-	__u32		*s, *d;
-	int		i;
-
-	used = round_up(used, sizeof(__u32));
-	if (used + CHACHA_KEY_SIZE > CHACHA_BLOCK_SIZE) {
-		extract_crng(tmp);
-		used = 0;
-	}
-	spin_lock_irqsave(&crng->lock, flags);
-	s = (__u32 *) &tmp[used];
-	d = &crng->state[4];
-	for (i=0; i < 8; i++)
-		*d++ ^= *s++;
-	spin_unlock_irqrestore(&crng->lock, flags);
+	/*
+	 * When the cpu comes back online, immediately invalidate both
+	 * the per-cpu crng and all batches, so that we serve fresh
+	 * randomness.
+	 */
+	per_cpu_ptr(&crngs, cpu)->generation = ULONG_MAX;
+	per_cpu_ptr(&batched_entropy_u32, cpu)->position = UINT_MAX;
+	per_cpu_ptr(&batched_entropy_u64, cpu)->position = UINT_MAX;
+	return 0;
 }
-
-static void crng_backtrack_protect(__u8 tmp[CHACHA_BLOCK_SIZE], int used)
-{
-	struct crng_state *crng = NULL;
-
-#ifdef CONFIG_NUMA
-	if (crng_node_pool)
-		crng = crng_node_pool[numa_node_id()];
-	if (crng == NULL)
 #endif
-		crng = &primary_crng;
-	_crng_backtrack_protect(crng, tmp, used);
-}
 
-static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
+/*
+ * This function will use the architecture-specific hardware random
+ * number generator if it is available. It is not recommended for
+ * use. Use get_random_bytes() instead. It returns the number of
+ * bytes filled in.
+ */
+size_t __must_check get_random_bytes_arch(void *buf, size_t len)
 {
-	ssize_t ret = 0, i = CHACHA_BLOCK_SIZE;
-	__u8 tmp[CHACHA_BLOCK_SIZE] __aligned(4);
-	int large_request = (nbytes > 256);
+	size_t left = len;
+	u8 *p = buf;
 
-	while (nbytes) {
-		if (large_request && need_resched()) {
-			if (signal_pending(current)) {
-				if (ret == 0)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			schedule();
-		}
+	while (left) {
+		unsigned long v;
+		size_t block_len = min_t(size_t, left, sizeof(unsigned long));
 
-		extract_crng(tmp);
-		i = min_t(int, nbytes, CHACHA_BLOCK_SIZE);
-		if (copy_to_user(buf, tmp, i)) {
-			ret = -EFAULT;
+		if (!arch_get_random_long(&v))
 			break;
-		}
 
-		nbytes -= i;
-		buf += i;
-		ret += i;
+		memcpy(p, &v, block_len);
+		p += block_len;
+		left -= block_len;
 	}
-	crng_backtrack_protect(tmp, i);
-
-	/* Wipe data just written to memory */
-	memzero_explicit(tmp, sizeof(tmp));
 
-	return ret;
+	return len - left;
 }
+EXPORT_SYMBOL(get_random_bytes_arch);
 
 
-/*********************************************************************
+/**********************************************************************
  *
- * Entropy input management
+ * Entropy accumulation and extraction routines.
  *
- *********************************************************************/
+ * Callers may add entropy via:
+ *
+ *     static void mix_pool_bytes(const void *buf, size_t len)
+ *
+ * After which, if added entropy should be credited:
+ *
+ *     static void credit_init_bits(size_t bits)
+ *
+ * Finally, extract entropy via:
+ *
+ *     static void extract_entropy(void *buf, size_t len)
+ *
+ **********************************************************************/
 
-/* There is one of these per entropy source */
-struct timer_rand_state {
-	cycles_t last_time;
-	long last_delta, last_delta2;
+enum {
+	POOL_BITS = BLAKE2S_HASH_SIZE * 8,
+	POOL_READY_BITS = POOL_BITS, /* When crng_init->CRNG_READY */
+	POOL_EARLY_BITS = POOL_READY_BITS / 2 /* When crng_init->CRNG_EARLY */
+};
+
+static struct {
+	struct blake2s_state hash;
+	spinlock_t lock;
+	unsigned int init_bits;
+} input_pool = {
+	.hash.h = { BLAKE2S_IV0 ^ (0x01010000 | BLAKE2S_HASH_SIZE),
+		    BLAKE2S_IV1, BLAKE2S_IV2, BLAKE2S_IV3, BLAKE2S_IV4,
+		    BLAKE2S_IV5, BLAKE2S_IV6, BLAKE2S_IV7 },
+	.hash.outlen = BLAKE2S_HASH_SIZE,
+	.lock = __SPIN_LOCK_UNLOCKED(input_pool.lock),
 };
 
-#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, };
+static void _mix_pool_bytes(const void *buf, size_t len)
+{
+	blake2s_update(&input_pool.hash, buf, len);
+}
 
 /*
- * Add device- or boot-specific data to the input pool to help
- * initialize it.
- *
- * None of this adds any entropy; it is meant to avoid the problem of
- * the entropy pool having similar initial state across largely
- * identical devices.
+ * This function adds bytes into the input pool. It does not
+ * update the initialization bit counter; the caller should call
+ * credit_init_bits if this is appropriate.
  */
-void add_device_randomness(const void *buf, unsigned int size)
+static void mix_pool_bytes(const void *buf, size_t len)
 {
-	unsigned long time = random_get_entropy() ^ jiffies;
 	unsigned long flags;
 
-	if (!crng_ready() && size)
-		crng_slow_load(buf, size);
-
-	trace_add_device_randomness(size, _RET_IP_);
 	spin_lock_irqsave(&input_pool.lock, flags);
-	_mix_pool_bytes(&input_pool, buf, size);
-	_mix_pool_bytes(&input_pool, &time, sizeof(time));
+	_mix_pool_bytes(buf, len);
 	spin_unlock_irqrestore(&input_pool.lock, flags);
 }
-EXPORT_SYMBOL(add_device_randomness);
-
-static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE;
 
 /*
- * This function adds entropy to the entropy "pool" by using timing
- * delays.  It uses the timer_rand_state structure to make an estimate
- * of how many bits of entropy this call has added to the pool.
- *
- * The number "num" is also added to the pool - it should somehow describe
- * the type of event which just happened.  This is currently 0-255 for
- * keyboard scan codes, and 256 upwards for interrupts.
- *
+ * This is an HKDF-like construction for using the hashed collected entropy
+ * as a PRF key, that's then expanded block-by-block.
  */
-static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
+static void extract_entropy(void *buf, size_t len)
 {
-	struct entropy_store	*r;
+	unsigned long flags;
+	u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE];
 	struct {
-		long jiffies;
-		unsigned cycles;
-		unsigned num;
-	} sample;
-	long delta, delta2, delta3;
-
-	sample.jiffies = jiffies;
-	sample.cycles = random_get_entropy();
-	sample.num = num;
-	r = &input_pool;
-	mix_pool_bytes(r, &sample, sizeof(sample));
-
-	/*
-	 * Calculate number of bits of randomness we probably added.
-	 * We take into account the first, second and third-order deltas
-	 * in order to make our estimate.
-	 */
-	delta = sample.jiffies - state->last_time;
-	state->last_time = sample.jiffies;
+		unsigned long rdseed[32 / sizeof(long)];
+		size_t counter;
+	} block;
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(block.rdseed); ++i) {
+		if (!arch_get_random_seed_long(&block.rdseed[i]) &&
+		    !arch_get_random_long(&block.rdseed[i]))
+			block.rdseed[i] = random_get_entropy();
+	}
 
-	delta2 = delta - state->last_delta;
-	state->last_delta = delta;
+	spin_lock_irqsave(&input_pool.lock, flags);
 
-	delta3 = delta2 - state->last_delta2;
-	state->last_delta2 = delta2;
+	/* seed = HASHPRF(last_key, entropy_input) */
+	blake2s_final(&input_pool.hash, seed);
 
-	if (delta < 0)
-		delta = -delta;
-	if (delta2 < 0)
-		delta2 = -delta2;
-	if (delta3 < 0)
-		delta3 = -delta3;
-	if (delta > delta2)
-		delta = delta2;
-	if (delta > delta3)
-		delta = delta3;
-
-	/*
-	 * delta is now minimum absolute delta.
-	 * Round down by 1 bit on general principles,
-	 * and limit entropy entimate to 12 bits.
-	 */
-	credit_entropy_bits(r, min_t(int, fls(delta>>1), 11));
-}
+	/* next_key = HASHPRF(seed, RDSEED || 0) */
+	block.counter = 0;
+	blake2s(next_key, (u8 *)&block, seed, sizeof(next_key), sizeof(block), sizeof(seed));
+	blake2s_init_key(&input_pool.hash, BLAKE2S_HASH_SIZE, next_key, sizeof(next_key));
 
-void add_input_randomness(unsigned int type, unsigned int code,
-				 unsigned int value)
-{
-	static unsigned char last_value;
+	spin_unlock_irqrestore(&input_pool.lock, flags);
+	memzero_explicit(next_key, sizeof(next_key));
 
-	/* ignore autorepeat and the like */
-	if (value == last_value)
-		return;
+	while (len) {
+		i = min_t(size_t, len, BLAKE2S_HASH_SIZE);
+		/* output = HASHPRF(seed, RDSEED || ++counter) */
+		++block.counter;
+		blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed));
+		len -= i;
+		buf += i;
+	}
 
-	last_value = value;
-	add_timer_randomness(&input_timer_state,
-			     (type << 4) ^ code ^ (code >> 4) ^ value);
-	trace_add_input_randomness(ENTROPY_BITS(&input_pool));
+	memzero_explicit(seed, sizeof(seed));
+	memzero_explicit(&block, sizeof(block));
 }
-EXPORT_SYMBOL_GPL(add_input_randomness);
-
-static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
-
-#ifdef ADD_INTERRUPT_BENCH
-static unsigned long avg_cycles, avg_deviation;
 
-#define AVG_SHIFT 8     /* Exponential average factor k=1/256 */
-#define FIXED_1_2 (1 << (AVG_SHIFT-1))
+#define credit_init_bits(bits) if (!crng_ready()) _credit_init_bits(bits)
 
-static void add_interrupt_bench(cycles_t start)
+static void __cold _credit_init_bits(size_t bits)
 {
-        long delta = random_get_entropy() - start;
-
-        /* Use a weighted moving average */
-        delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT);
-        avg_cycles += delta;
-        /* And average deviation */
-        delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT);
-        avg_deviation += delta;
-}
-#else
-#define add_interrupt_bench(x)
-#endif
-
-static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
-{
-	__u32 *ptr = (__u32 *) regs;
-	unsigned int idx;
-
-	if (regs == NULL)
-		return 0;
-	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)
-{
-	struct entropy_store	*r;
-	struct fast_pool	*fast_pool = this_cpu_ptr(&irq_randomness);
-	struct pt_regs		*regs = get_irq_regs();
-	unsigned long		now = jiffies;
-	cycles_t		cycles = random_get_entropy();
-	__u32			c_high, j_high;
-	__u64			ip;
-	unsigned long		seed;
-	int			credit = 0;
-
-	if (cycles == 0)
-		cycles = get_reg(fast_pool, regs);
-	c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
-	j_high = (sizeof(now) > 4) ? now >> 32 : 0;
-	fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
-	fast_pool->pool[1] ^= now ^ c_high;
-	ip = regs ? instruction_pointer(regs) : _RET_IP_;
-	fast_pool->pool[2] ^= ip;
-	fast_pool->pool[3] ^= (sizeof(ip) > 4) ? ip >> 32 :
-		get_reg(fast_pool, regs);
-
-	fast_mix(fast_pool);
-	add_interrupt_bench(cycles);
-
-	if (unlikely(crng_init == 0)) {
-		if ((fast_pool->count >= 64) &&
-		    crng_fast_load((char *) fast_pool->pool,
-				   sizeof(fast_pool->pool))) {
-			fast_pool->count = 0;
-			fast_pool->last = now;
-		}
-		return;
-	}
+	unsigned int new, orig, add;
+	unsigned long flags;
 
-	if ((fast_pool->count < 64) &&
-	    !time_after(now, fast_pool->last + HZ))
+	if (!bits)
 		return;
 
-	r = &input_pool;
-	if (!spin_trylock(&r->lock))
-		return;
+	add = min_t(size_t, bits, POOL_BITS);
 
-	fast_pool->last = now;
-	__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool));
+	do {
+		orig = READ_ONCE(input_pool.init_bits);
+		new = min_t(unsigned int, POOL_BITS, orig + add);
+	} while (cmpxchg(&input_pool.init_bits, orig, new) != orig);
 
-	/*
-	 * If we have architectural seed generator, produce a seed and
-	 * add it to the pool.  For the sake of paranoia don't let the
-	 * architectural seed generator dominate the input from the
-	 * interrupt noise.
-	 */
-	if (arch_get_random_seed_long(&seed)) {
-		__mix_pool_bytes(r, &seed, sizeof(seed));
-		credit = 1;
+	if (orig < POOL_READY_BITS && new >= POOL_READY_BITS) {
+		crng_reseed(); /* Sets crng_init to CRNG_READY under base_crng.lock. */
+		process_random_ready_list();
+		wake_up_interruptible(&crng_init_wait);
+		kill_fasync(&fasync, SIGIO, POLL_IN);
+		pr_notice("crng init done\n");
+		if (urandom_warning.missed)
+			pr_notice("%d urandom warning(s) missed due to ratelimiting\n",
+				  urandom_warning.missed);
+	} else if (orig < POOL_EARLY_BITS && new >= POOL_EARLY_BITS) {
+		spin_lock_irqsave(&base_crng.lock, flags);
+		/* Check if crng_init is CRNG_EMPTY, to avoid race with crng_reseed(). */
+		if (crng_init == CRNG_EMPTY) {
+			extract_entropy(base_crng.key, sizeof(base_crng.key));
+			crng_init = CRNG_EARLY;
+		}
+		spin_unlock_irqrestore(&base_crng.lock, flags);
 	}
-	spin_unlock(&r->lock);
-
-	fast_pool->count = 0;
-
-	/* 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)
-{
-	if (!disk || !disk->random)
-		return;
-	/* first major is 1, so we get >= 0x200 here */
-	add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
-	trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool));
-}
-EXPORT_SYMBOL_GPL(add_disk_randomness);
-#endif
 
-/*********************************************************************
+/**********************************************************************
  *
- * Entropy extraction routines
+ * Entropy collection routines.
  *
- *********************************************************************/
-
-/*
- * This utility inline function is responsible for transferring entropy
- * from the primary pool to the secondary extraction pool. We make
- * sure we pull enough for a 'catastrophic reseed'.
- */
-static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes);
-static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
-{
-	if (!r->pull ||
-	    r->entropy_count >= (nbytes << (ENTROPY_SHIFT + 3)) ||
-	    r->entropy_count > r->poolinfo->poolfracbits)
-		return;
+ * The following exported functions are used for pushing entropy into
+ * the above entropy accumulation routines:
+ *
+ *	void add_device_randomness(const void *buf, size_t len);
+ *	void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
+ *	void add_bootloader_randomness(const void *buf, size_t len);
+ *	void add_interrupt_randomness(int irq);
+ *	void add_input_randomness(unsigned int type, unsigned int code, unsigned int value);
+ *	void add_disk_randomness(struct gendisk *disk);
+ *
+ * add_device_randomness() adds data to the input pool that
+ * is likely to differ between two devices (or possibly even per boot).
+ * This would be things like MAC addresses or serial numbers, or the
+ * read-out of the RTC. This does *not* credit any actual entropy to
+ * the pool, but it initializes the pool to different values for devices
+ * that might otherwise be identical and have very little entropy
+ * available to them (particularly common in the embedded world).
+ *
+ * add_hwgenerator_randomness() is for true hardware RNGs, and will credit
+ * entropy as specified by the caller. If the entropy pool is full it will
+ * block until more entropy is needed.
+ *
+ * add_bootloader_randomness() is called by bootloader drivers, such as EFI
+ * and device tree, and credits its input depending on whether or not the
+ * configuration option CONFIG_RANDOM_TRUST_BOOTLOADER is set.
+ *
+ * add_interrupt_randomness() uses the interrupt timing as random
+ * inputs to the entropy pool. Using the cycle counters and the irq source
+ * as inputs, it feeds the input pool roughly once a second or after 64
+ * interrupts, crediting 1 bit of entropy for whichever comes first.
+ *
+ * add_input_randomness() uses the input layer interrupt timing, as well
+ * as the event type information from the hardware.
+ *
+ * add_disk_randomness() uses what amounts to the seek time of block
+ * layer request events, on a per-disk_devt basis, as input to the
+ * entropy pool. Note that high-speed solid state drives with very low
+ * seek times do not make for good sources of entropy, as their seek
+ * times are usually fairly consistent.
+ *
+ * The last two routines try to estimate how many bits of entropy
+ * to credit. They do this by keeping track of the first and second
+ * order deltas of the event timings.
+ *
+ **********************************************************************/
 
-	_xfer_secondary_pool(r, nbytes);
+static bool trust_cpu __initdata = IS_ENABLED(CONFIG_RANDOM_TRUST_CPU);
+static bool trust_bootloader __initdata = IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER);
+static int __init parse_trust_cpu(char *arg)
+{
+	return kstrtobool(arg, &trust_cpu);
 }
+static int __init parse_trust_bootloader(char *arg)
+{
+	return kstrtobool(arg, &trust_bootloader);
+}
+early_param("random.trust_cpu", parse_trust_cpu);
+early_param("random.trust_bootloader", parse_trust_bootloader);
 
-static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
+/*
+ * The first collection of entropy occurs at system boot while interrupts
+ * are still turned off. Here we push in latent entropy, RDSEED, a timestamp,
+ * utsname(), and the command line. Depending on the above configuration knob,
+ * RDSEED may be considered sufficient for initialization. Note that much
+ * earlier setup may already have pushed entropy into the input pool by the
+ * time we get here.
+ */
+int __init random_init(const char *command_line)
 {
-	__u32	tmp[OUTPUT_POOL_WORDS];
+	ktime_t now = ktime_get_real();
+	unsigned int i, arch_bits;
+	unsigned long entropy;
 
-	int bytes = nbytes;
+#if defined(LATENT_ENTROPY_PLUGIN)
+	static const u8 compiletime_seed[BLAKE2S_BLOCK_SIZE] __initconst __latent_entropy;
+	_mix_pool_bytes(compiletime_seed, sizeof(compiletime_seed));
+#endif
 
-	/* pull at least as much as a wakeup */
-	bytes = max_t(int, bytes, random_read_wakeup_bits / 8);
-	/* but never more than the buffer size */
-	bytes = min_t(int, bytes, sizeof(tmp));
+	for (i = 0, arch_bits = BLAKE2S_BLOCK_SIZE * 8;
+	     i < BLAKE2S_BLOCK_SIZE; i += sizeof(entropy)) {
+		if (!arch_get_random_seed_long_early(&entropy) &&
+		    !arch_get_random_long_early(&entropy)) {
+			entropy = random_get_entropy();
+			arch_bits -= sizeof(entropy) * 8;
+		}
+		_mix_pool_bytes(&entropy, sizeof(entropy));
+	}
+	_mix_pool_bytes(&now, sizeof(now));
+	_mix_pool_bytes(utsname(), sizeof(*(utsname())));
+	_mix_pool_bytes(command_line, strlen(command_line));
+	add_latent_entropy();
+
+	if (crng_ready())
+		crng_reseed();
+	else if (trust_cpu)
+		_credit_init_bits(arch_bits);
 
-	trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8,
-				  ENTROPY_BITS(r), ENTROPY_BITS(r->pull));
-	bytes = extract_entropy(r->pull, tmp, bytes,
-				random_read_wakeup_bits / 8, 0);
-	mix_pool_bytes(r, tmp, bytes);
-	credit_entropy_bits(r, bytes*8);
+	return 0;
 }
 
 /*
- * Used as a workqueue function so that when the input pool is getting
- * full, we can "spill over" some entropy to the output pools.  That
- * way the output pools can store some of the excess entropy instead
- * of letting it go to waste.
+ * Add device- or boot-specific data to the input pool to help
+ * initialize it.
+ *
+ * None of this adds any entropy; it is meant to avoid the problem of
+ * the entropy pool having similar initial state across largely
+ * identical devices.
  */
-static void push_to_pool(struct work_struct *work)
+void add_device_randomness(const void *buf, size_t len)
 {
-	struct entropy_store *r = container_of(work, struct entropy_store,
-					      push_work);
-	BUG_ON(!r);
-	_xfer_secondary_pool(r, random_read_wakeup_bits/8);
-	trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT,
-			   r->pull->entropy_count >> ENTROPY_SHIFT);
+	unsigned long entropy = random_get_entropy();
+	unsigned long flags;
+
+	spin_lock_irqsave(&input_pool.lock, flags);
+	_mix_pool_bytes(&entropy, sizeof(entropy));
+	_mix_pool_bytes(buf, len);
+	spin_unlock_irqrestore(&input_pool.lock, flags);
 }
+EXPORT_SYMBOL(add_device_randomness);
 
 /*
- * This function decides how many bytes to actually take from the
- * given pool, and also debits the entropy count accordingly.
+ * Interface for in-kernel drivers of true hardware RNGs.
+ * Those devices may produce endless random bits and will be throttled
+ * when our pool is full.
  */
-static size_t account(struct entropy_store *r, size_t nbytes, int min,
-		      int reserved)
+void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
 {
-	int entropy_count, orig, have_bytes;
-	size_t ibytes, nfrac;
-
-	BUG_ON(r->entropy_count > r->poolinfo->poolfracbits);
+	mix_pool_bytes(buf, len);
+	credit_init_bits(entropy);
 
-	/* Can we pull enough? */
-retry:
-	entropy_count = orig = READ_ONCE(r->entropy_count);
-	ibytes = nbytes;
-	/* never pull more than available */
-	have_bytes = entropy_count >> (ENTROPY_SHIFT + 3);
+	/*
+	 * Throttle writing to once every CRNG_RESEED_INTERVAL, unless
+	 * we're not yet initialized.
+	 */
+	if (!kthread_should_stop() && crng_ready())
+		schedule_timeout_interruptible(CRNG_RESEED_INTERVAL);
+}
+EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
 
-	if ((have_bytes -= reserved) < 0)
-		have_bytes = 0;
-	ibytes = min_t(size_t, ibytes, have_bytes);
-	if (ibytes < min)
-		ibytes = 0;
+/*
+ * Handle random seed passed by bootloader, and credit it if
+ * CONFIG_RANDOM_TRUST_BOOTLOADER is set.
+ */
+void __init add_bootloader_randomness(const void *buf, size_t len)
+{
+	mix_pool_bytes(buf, len);
+	if (trust_bootloader)
+		credit_init_bits(len * 8);
+}
 
-	if (unlikely(entropy_count < 0)) {
-		pr_warn("random: negative entropy count: pool %s count %d\n",
-			r->name, entropy_count);
-		WARN_ON(1);
-		entropy_count = 0;
-	}
-	nfrac = ibytes << (ENTROPY_SHIFT + 3);
-	if ((size_t) entropy_count > nfrac)
-		entropy_count -= nfrac;
-	else
-		entropy_count = 0;
+struct fast_pool {
+	unsigned long pool[4];
+	unsigned long last;
+	unsigned int count;
+	struct timer_list mix;
+};
 
-	if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
-		goto retry;
+static void mix_interrupt_randomness(struct timer_list *work);
 
-	trace_debit_entropy(r->name, 8 * ibytes);
-	if (ibytes &&
-	    (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) {
-		wake_up_interruptible(&random_write_wait);
-		kill_fasync(&fasync, SIGIO, POLL_OUT);
-	}
+static DEFINE_PER_CPU(struct fast_pool, irq_randomness) = {
+#ifdef CONFIG_64BIT
+#define FASTMIX_PERM SIPHASH_PERMUTATION
+	.pool = { SIPHASH_CONST_0, SIPHASH_CONST_1, SIPHASH_CONST_2, SIPHASH_CONST_3 },
+#else
+#define FASTMIX_PERM HSIPHASH_PERMUTATION
+	.pool = { HSIPHASH_CONST_0, HSIPHASH_CONST_1, HSIPHASH_CONST_2, HSIPHASH_CONST_3 },
+#endif
+	.mix = __TIMER_INITIALIZER(mix_interrupt_randomness, 0)
+};
 
-	return ibytes;
+/*
+ * This is [Half]SipHash-1-x, starting from an empty key. Because
+ * the key is fixed, it assumes that its inputs are non-malicious,
+ * and therefore this has no security on its own. s represents the
+ * four-word SipHash state, while v represents a two-word input.
+ */
+static void fast_mix(unsigned long s[4], unsigned long v1, unsigned long v2)
+{
+	s[3] ^= v1;
+	FASTMIX_PERM(s[0], s[1], s[2], s[3]);
+	s[0] ^= v1;
+	s[3] ^= v2;
+	FASTMIX_PERM(s[0], s[1], s[2], s[3]);
+	s[0] ^= v2;
 }
 
+#ifdef CONFIG_SMP
 /*
- * This function does the actual extraction for extract_entropy and
- * extract_entropy_user.
- *
- * Note: we assume that .poolwords is a multiple of 16 words.
+ * This function is called when the CPU has just come online, with
+ * entry CPUHP_AP_RANDOM_ONLINE, just after CPUHP_AP_WORKQUEUE_ONLINE.
  */
-static void extract_buf(struct entropy_store *r, __u8 *out)
+int __cold random_online_cpu(unsigned int cpu)
 {
-	int i;
-	union {
-		__u32 w[5];
-		unsigned long l[LONGS(20)];
-	} hash;
-	__u32 workspace[SHA_WORKSPACE_WORDS];
-	unsigned long flags;
-
 	/*
-	 * If we have an architectural hardware random number
-	 * generator, use it for SHA's initial vector
+	 * During CPU shutdown and before CPU onlining, add_interrupt_
+	 * randomness() may schedule mix_interrupt_randomness(), and
+	 * set the MIX_INFLIGHT flag. However, because the worker can
+	 * be scheduled on a different CPU during this period, that
+	 * flag will never be cleared. For that reason, we zero out
+	 * the flag here, which runs just after workqueues are onlined
+	 * for the CPU again. This also has the effect of setting the
+	 * irq randomness count to zero so that new accumulated irqs
+	 * are fresh.
 	 */
-	sha_init(hash.w);
-	for (i = 0; i < LONGS(20); i++) {
-		unsigned long v;
-		if (!arch_get_random_long(&v))
-			break;
-		hash.l[i] = v;
-	}
-
-	/* Generate a hash across the pool, 16 words (512 bits) at a time */
-	spin_lock_irqsave(&r->lock, flags);
-	for (i = 0; i < r->poolinfo->poolwords; i += 16)
-		sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
+	per_cpu_ptr(&irq_randomness, cpu)->count = 0;
+	return 0;
+}
+#endif
 
+static void mix_interrupt_randomness(struct timer_list *work)
+{
+	struct fast_pool *fast_pool = container_of(work, struct fast_pool, mix);
 	/*
-	 * We mix the hash back into the pool to prevent backtracking
-	 * attacks (where the attacker knows the state of the pool
-	 * plus the current outputs, and attempts to find previous
-	 * ouputs), unless the hash function can be inverted. By
-	 * mixing at least a SHA1 worth of hash data back, we make
-	 * brute-forcing the feedback as hard as brute-forcing the
-	 * hash.
+	 * The size of the copied stack pool is explicitly 2 longs so that we
+	 * only ever ingest half of the siphash output each time, retaining
+	 * the other half as the next "key" that carries over. The entropy is
+	 * supposed to be sufficiently dispersed between bits so on average
+	 * we don't wind up "losing" some.
 	 */
-	__mix_pool_bytes(r, hash.w, sizeof(hash.w));
-	spin_unlock_irqrestore(&r->lock, flags);
+	unsigned long pool[2];
+	unsigned int count;
 
-	memzero_explicit(workspace, sizeof(workspace));
+	/* Check to see if we're running on the wrong CPU due to hotplug. */
+	local_irq_disable();
+	if (fast_pool != this_cpu_ptr(&irq_randomness)) {
+		local_irq_enable();
+		return;
+	}
 
 	/*
-	 * In case the hash function has some recognizable output
-	 * pattern, we fold it in half. Thus, we always feed back
-	 * twice as much data as we output.
+	 * Copy the pool to the stack so that the mixer always has a
+	 * consistent view, before we reenable irqs again.
 	 */
-	hash.w[0] ^= hash.w[3];
-	hash.w[1] ^= hash.w[4];
-	hash.w[2] ^= rol32(hash.w[2], 16);
+	memcpy(pool, fast_pool->pool, sizeof(pool));
+	count = fast_pool->count;
+	fast_pool->count = 0;
+	fast_pool->last = jiffies;
+	local_irq_enable();
+
+	mix_pool_bytes(pool, sizeof(pool));
+	credit_init_bits(clamp_t(unsigned int, (count & U16_MAX) / 64, 1, sizeof(pool) * 8));
 
-	memcpy(out, &hash, EXTRACT_SIZE);
-	memzero_explicit(&hash, sizeof(hash));
+	memzero_explicit(pool, sizeof(pool));
 }
 
-static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
-				size_t nbytes, int fips)
+void add_interrupt_randomness(int irq)
 {
-	ssize_t ret = 0, i;
-	__u8 tmp[EXTRACT_SIZE];
-	unsigned long flags;
+	enum { MIX_INFLIGHT = 1U << 31 };
+	unsigned long entropy = random_get_entropy();
+	struct fast_pool *fast_pool = this_cpu_ptr(&irq_randomness);
+	struct pt_regs *regs = get_irq_regs();
+	unsigned int new_count;
 
-	while (nbytes) {
-		extract_buf(r, tmp);
+	fast_mix(fast_pool->pool, entropy,
+		 (regs ? instruction_pointer(regs) : _RET_IP_) ^ swab(irq));
+	new_count = ++fast_pool->count;
 
-		if (fips) {
-			spin_lock_irqsave(&r->lock, flags);
-			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
-				panic("Hardware RNG duplicated output!\n");
-			memcpy(r->last_data, tmp, EXTRACT_SIZE);
-			spin_unlock_irqrestore(&r->lock, flags);
-		}
-		i = min_t(int, nbytes, EXTRACT_SIZE);
-		memcpy(buf, tmp, i);
-		nbytes -= i;
-		buf += i;
-		ret += i;
-	}
+	if (new_count & MIX_INFLIGHT)
+		return;
 
-	/* Wipe data just returned from memory */
-	memzero_explicit(tmp, sizeof(tmp));
+	if (new_count < 1024 && !time_is_before_jiffies(fast_pool->last + HZ))
+		return;
 
-	return ret;
+	fast_pool->count |= MIX_INFLIGHT;
+	if (!timer_pending(&fast_pool->mix)) {
+		fast_pool->mix.expires = jiffies;
+		add_timer_on(&fast_pool->mix, raw_smp_processor_id());
+	}
 }
+EXPORT_SYMBOL_GPL(add_interrupt_randomness);
+
+/* There is one of these per entropy source */
+struct timer_rand_state {
+	unsigned long last_time;
+	long last_delta, last_delta2;
+};
 
 /*
- * This function extracts randomness from the "entropy pool", and
- * returns it in a buffer.
- *
- * The min parameter specifies the minimum amount we can pull before
- * failing to avoid races that defeat catastrophic reseeding while the
- * reserved parameter indicates how much entropy we must leave in the
- * pool after each pull to avoid starving other readers.
+ * This function adds entropy to the entropy "pool" by using timing
+ * delays. It uses the timer_rand_state structure to make an estimate
+ * of how many bits of entropy this call has added to the pool. The
+ * value "num" is also added to the pool; it should somehow describe
+ * the type of event that just happened.
  */
-static ssize_t extract_entropy(struct entropy_store *r, void *buf,
-				 size_t nbytes, int min, int reserved)
+static void add_timer_randomness(struct timer_rand_state *state, unsigned int num)
 {
-	__u8 tmp[EXTRACT_SIZE];
-	unsigned long flags;
+	unsigned long entropy = random_get_entropy(), now = jiffies, flags;
+	long delta, delta2, delta3;
+	unsigned int bits;
 
-	/* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
-	if (fips_enabled) {
-		spin_lock_irqsave(&r->lock, flags);
-		if (!r->last_data_init) {
-			r->last_data_init = 1;
-			spin_unlock_irqrestore(&r->lock, flags);
-			trace_extract_entropy(r->name, EXTRACT_SIZE,
-					      ENTROPY_BITS(r), _RET_IP_);
-			xfer_secondary_pool(r, EXTRACT_SIZE);
-			extract_buf(r, tmp);
-			spin_lock_irqsave(&r->lock, flags);
-			memcpy(r->last_data, tmp, EXTRACT_SIZE);
-		}
-		spin_unlock_irqrestore(&r->lock, flags);
+	/*
+	 * If we're in a hard IRQ, add_interrupt_randomness() will be called
+	 * sometime after, so mix into the fast pool.
+	 */
+	if (in_irq()) {
+		fast_mix(this_cpu_ptr(&irq_randomness)->pool, entropy, num);
+	} else {
+		spin_lock_irqsave(&input_pool.lock, flags);
+		_mix_pool_bytes(&entropy, sizeof(entropy));
+		_mix_pool_bytes(&num, sizeof(num));
+		spin_unlock_irqrestore(&input_pool.lock, flags);
 	}
 
-	trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
-	xfer_secondary_pool(r, nbytes);
-	nbytes = account(r, nbytes, min, reserved);
-
-	return _extract_entropy(r, buf, nbytes, fips_enabled);
-}
-
-/*
- * This function extracts randomness from the "entropy pool", and
- * returns it in a userspace buffer.
- */
-static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
-				    size_t nbytes)
-{
-	ssize_t ret = 0, i;
-	__u8 tmp[EXTRACT_SIZE];
-	int large_request = (nbytes > 256);
+	if (crng_ready())
+		return;
 
-	trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
-	if (!r->initialized && r->pull) {
-		xfer_secondary_pool(r, ENTROPY_BITS(r->pull)/8);
-		if (!r->initialized)
-			return 0;
-	}
-	xfer_secondary_pool(r, nbytes);
-	nbytes = account(r, nbytes, 0, 0);
+	/*
+	 * Calculate number of bits of randomness we probably added.
+	 * We take into account the first, second and third-order deltas
+	 * in order to make our estimate.
+	 */
+	delta = now - READ_ONCE(state->last_time);
+	WRITE_ONCE(state->last_time, now);
 
-	while (nbytes) {
-		if (large_request && need_resched()) {
-			if (signal_pending(current)) {
-				if (ret == 0)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			schedule();
-		}
+	delta2 = delta - READ_ONCE(state->last_delta);
+	WRITE_ONCE(state->last_delta, delta);
 
-		extract_buf(r, tmp);
-		i = min_t(int, nbytes, EXTRACT_SIZE);
-		if (copy_to_user(buf, tmp, i)) {
-			ret = -EFAULT;
-			break;
-		}
+	delta3 = delta2 - READ_ONCE(state->last_delta2);
+	WRITE_ONCE(state->last_delta2, delta2);
 
-		nbytes -= i;
-		buf += i;
-		ret += i;
-	}
+	if (delta < 0)
+		delta = -delta;
+	if (delta2 < 0)
+		delta2 = -delta2;
+	if (delta3 < 0)
+		delta3 = -delta3;
+	if (delta > delta2)
+		delta = delta2;
+	if (delta > delta3)
+		delta = delta3;
 
-	/* Wipe data just returned from memory */
-	memzero_explicit(tmp, sizeof(tmp));
+	/*
+	 * delta is now minimum absolute delta. Round down by 1 bit
+	 * on general principles, and limit entropy estimate to 11 bits.
+	 */
+	bits = min(fls(delta >> 1), 11);
 
-	return ret;
+	/*
+	 * As mentioned above, if we're in a hard IRQ, add_interrupt_randomness()
+	 * will run after this, which uses a different crediting scheme of 1 bit
+	 * per every 64 interrupts. In order to let that function do accounting
+	 * close to the one in this function, we credit a full 64/64 bit per bit,
+	 * and then subtract one to account for the extra one added.
+	 */
+	if (in_irq())
+		this_cpu_ptr(&irq_randomness)->count += max(1u, bits * 64) - 1;
+	else
+		_credit_init_bits(bits);
 }
 
-#define warn_unseeded_randomness(previous) \
-	_warn_unseeded_randomness(__func__, (void *) _RET_IP_, (previous))
-
-static void _warn_unseeded_randomness(const char *func_name, void *caller,
-				      void **previous)
+void add_input_randomness(unsigned int type, unsigned int code, unsigned int value)
 {
-#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
-	const bool print_once = false;
-#else
-	static bool print_once __read_mostly;
-#endif
+	static unsigned char last_value;
+	static struct timer_rand_state input_timer_state = { INITIAL_JIFFIES };
 
-	if (print_once ||
-	    crng_ready() ||
-	    (previous && (caller == READ_ONCE(*previous))))
+	/* Ignore autorepeat and the like. */
+	if (value == last_value)
 		return;
-	WRITE_ONCE(*previous, caller);
-#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
-	print_once = true;
-#endif
-	if (__ratelimit(&unseeded_warning))
-		pr_notice("random: %s called from %pS with crng_init=%d\n",
-			  func_name, caller, crng_init);
+
+	last_value = value;
+	add_timer_randomness(&input_timer_state,
+			     (type << 4) ^ code ^ (code >> 4) ^ value);
 }
+EXPORT_SYMBOL_GPL(add_input_randomness);
 
-/*
- * This function is the exported kernel interface.  It returns some
- * number of good random numbers, suitable for key generation, seeding
- * TCP sequence numbers, etc.  It does not rely on the hardware random
- * number generator.  For random bytes direct from the hardware RNG
- * (when available), use get_random_bytes_arch(). In order to ensure
- * that the randomness provided by this function is okay, the function
- * wait_for_random_bytes() should be called and return 0 at least once
- * at any point prior.
- */
-static void _get_random_bytes(void *buf, int nbytes)
+#ifdef CONFIG_BLOCK
+void add_disk_randomness(struct gendisk *disk)
 {
-	__u8 tmp[CHACHA_BLOCK_SIZE] __aligned(4);
-
-	trace_get_random_bytes(nbytes, _RET_IP_);
-
-	while (nbytes >= CHACHA_BLOCK_SIZE) {
-		extract_crng(buf);
-		buf += CHACHA_BLOCK_SIZE;
-		nbytes -= CHACHA_BLOCK_SIZE;
-	}
-
-	if (nbytes > 0) {
-		extract_crng(tmp);
-		memcpy(buf, tmp, nbytes);
-		crng_backtrack_protect(tmp, nbytes);
-	} else
-		crng_backtrack_protect(tmp, CHACHA_BLOCK_SIZE);
-	memzero_explicit(tmp, sizeof(tmp));
+	if (!disk || !disk->random)
+		return;
+	/* First major is 1, so we get >= 0x200 here. */
+	add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
 }
+EXPORT_SYMBOL_GPL(add_disk_randomness);
 
-void get_random_bytes(void *buf, int nbytes)
+void __cold rand_initialize_disk(struct gendisk *disk)
 {
-	static void *previous;
+	struct timer_rand_state *state;
 
-	warn_unseeded_randomness(&previous);
-	_get_random_bytes(buf, nbytes);
+	/*
+	 * If kzalloc returns null, we just won't use that entropy
+	 * source.
+	 */
+	state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
+	if (state) {
+		state->last_time = INITIAL_JIFFIES;
+		disk->random = state;
+	}
 }
-EXPORT_SYMBOL(get_random_bytes);
-
+#endif
 
 /*
  * Each time the timer fires, we expect that we got an unpredictable
@@ -1745,371 +1143,181 @@
  *
  * So the re-arming always happens in the entropy loop itself.
  */
-static void entropy_timer(struct timer_list *t)
+static void __cold entropy_timer(struct timer_list *t)
 {
-	credit_entropy_bits(&input_pool, 1);
+	credit_init_bits(1);
 }
 
 /*
  * If we have an actual cycle counter, see if we can
  * generate enough entropy with timing noise
  */
-static void try_to_generate_entropy(void)
+static void __cold try_to_generate_entropy(void)
 {
 	struct {
-		unsigned long now;
+		unsigned long entropy;
 		struct timer_list timer;
 	} stack;
 
-	stack.now = random_get_entropy();
+	stack.entropy = random_get_entropy();
 
 	/* Slow counter - or none. Don't even bother */
-	if (stack.now == random_get_entropy())
+	if (stack.entropy == random_get_entropy())
 		return;
 
 	timer_setup_on_stack(&stack.timer, entropy_timer, 0);
-	while (!crng_ready()) {
+	while (!crng_ready() && !signal_pending(current)) {
 		if (!timer_pending(&stack.timer))
-			mod_timer(&stack.timer, jiffies+1);
-		mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
+			mod_timer(&stack.timer, jiffies + 1);
+		mix_pool_bytes(&stack.entropy, sizeof(stack.entropy));
 		schedule();
-		stack.now = random_get_entropy();
+		stack.entropy = random_get_entropy();
 	}
 
 	del_timer_sync(&stack.timer);
 	destroy_timer_on_stack(&stack.timer);
-	mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
+	mix_pool_bytes(&stack.entropy, sizeof(stack.entropy));
 }
 
-/*
- * Wait for the urandom pool to be seeded and thus guaranteed to supply
- * cryptographically secure random numbers. This applies to: the /dev/urandom
- * device, the get_random_bytes function, and the get_random_{u32,u64,int,long}
- * family of functions. Using any of these functions without first calling
- * this function forfeits the guarantee of security.
- *
- * Returns: 0 if the urandom pool has been seeded.
- *          -ERESTARTSYS if the function was interrupted by a signal.
- */
-int wait_for_random_bytes(void)
-{
-	if (likely(crng_ready()))
-		return 0;
-
-	do {
-		int ret;
-		ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
-		if (ret)
-			return ret > 0 ? 0 : ret;
-
-		try_to_generate_entropy();
-	} while (!crng_ready());
 
-	return 0;
-}
-EXPORT_SYMBOL(wait_for_random_bytes);
-
-/*
- * Returns whether or not the urandom pool has been seeded and thus guaranteed
- * to supply cryptographically secure random numbers. This applies to: the
- * /dev/urandom device, the get_random_bytes function, and the get_random_{u32,
- * ,u64,int,long} family of functions.
+/**********************************************************************
  *
- * Returns: true if the urandom pool has been seeded.
- *          false if the urandom pool has not been seeded.
- */
-bool rng_is_initialized(void)
-{
-	return crng_ready();
-}
-EXPORT_SYMBOL(rng_is_initialized);
-
-/*
- * Add a callback function that will be invoked when the nonblocking
- * pool is initialised.
+ * Userspace reader/writer interfaces.
  *
- * returns: 0 if callback is successfully added
- *	    -EALREADY if pool is already initialised (callback not called)
- *	    -ENOENT if module for callback is not alive
- */
-int add_random_ready_callback(struct random_ready_callback *rdy)
-{
-	struct module *owner;
-	unsigned long flags;
-	int err = -EALREADY;
-
-	if (crng_ready())
-		return err;
-
-	owner = rdy->owner;
-	if (!try_module_get(owner))
-		return -ENOENT;
-
-	spin_lock_irqsave(&random_ready_list_lock, flags);
-	if (crng_ready())
-		goto out;
-
-	owner = NULL;
-
-	list_add(&rdy->list, &random_ready_list);
-	err = 0;
-
-out:
-	spin_unlock_irqrestore(&random_ready_list_lock, flags);
-
-	module_put(owner);
-
-	return err;
-}
-EXPORT_SYMBOL(add_random_ready_callback);
-
-/*
- * Delete a previously registered readiness callback function.
- */
-void del_random_ready_callback(struct random_ready_callback *rdy)
-{
-	unsigned long flags;
-	struct module *owner = NULL;
-
-	spin_lock_irqsave(&random_ready_list_lock, flags);
-	if (!list_empty(&rdy->list)) {
-		list_del_init(&rdy->list);
-		owner = rdy->owner;
-	}
-	spin_unlock_irqrestore(&random_ready_list_lock, flags);
-
-	module_put(owner);
-}
-EXPORT_SYMBOL(del_random_ready_callback);
-
-/*
- * This function will use the architecture-specific hardware random
- * number generator if it is available.  The arch-specific hw RNG will
- * almost certainly be faster than what we can do in software, but it
- * is impossible to verify that it is implemented securely (as
- * opposed, to, say, the AES encryption of a sequence number using a
- * key known by the NSA).  So it's useful if we need the speed, but
- * only if we're willing to trust the hardware manufacturer not to
- * have put in a back door.
+ * getrandom(2) is the primary modern interface into the RNG and should
+ * be used in preference to anything else.
  *
- * Return number of bytes filled in.
- */
-int __must_check get_random_bytes_arch(void *buf, int nbytes)
-{
-	int left = nbytes;
-	char *p = buf;
-
-	trace_get_random_bytes_arch(left, _RET_IP_);
-	while (left) {
-		unsigned long v;
-		int chunk = min_t(int, left, sizeof(unsigned long));
-
-		if (!arch_get_random_long(&v))
-			break;
-
-		memcpy(p, &v, chunk);
-		p += chunk;
-		left -= chunk;
-	}
-
-	return nbytes - left;
-}
-EXPORT_SYMBOL(get_random_bytes_arch);
-
-/*
- * init_std_data - initialize pool with system data
+ * Reading from /dev/random has the same functionality as calling
+ * getrandom(2) with flags=0. In earlier versions, however, it had
+ * vastly different semantics and should therefore be avoided, to
+ * prevent backwards compatibility issues.
  *
- * @r: pool to initialize
+ * Reading from /dev/urandom has the same functionality as calling
+ * getrandom(2) with flags=GRND_INSECURE. Because it does not block
+ * waiting for the RNG to be ready, it should not be used.
  *
- * This function clears the pool's entropy count and mixes some system
- * data into the pool to prepare it for use. The pool is not cleared
- * as that can only decrease the entropy in the pool.
- */
-static void __init init_std_data(struct entropy_store *r)
+ * Writing to either /dev/random or /dev/urandom adds entropy to
+ * the input pool but does not credit it.
+ *
+ * Polling on /dev/random indicates when the RNG is initialized, on
+ * the read side, and when it wants new entropy, on the write side.
+ *
+ * Both /dev/random and /dev/urandom have the same set of ioctls for
+ * adding entropy, getting the entropy count, zeroing the count, and
+ * reseeding the crng.
+ *
+ **********************************************************************/
+
+SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags)
 {
-	int i;
-	ktime_t now = ktime_get_real();
-	unsigned long rv;
+	struct iov_iter iter;
+	struct iovec iov;
+	int ret;
 
-	r->last_pulled = jiffies;
-	mix_pool_bytes(r, &now, sizeof(now));
-	for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
-		if (!arch_get_random_seed_long(&rv) &&
-		    !arch_get_random_long(&rv))
-			rv = random_get_entropy();
-		mix_pool_bytes(r, &rv, sizeof(rv));
-	}
-	mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
-}
+	if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE))
+		return -EINVAL;
 
-/*
- * Note that setup_arch() may call add_device_randomness()
- * long before we get here. This allows seeding of the pools
- * with some platform dependent data very early in the boot
- * process. But it limits our options here. We must use
- * statically allocated structures that already have all
- * initializations complete at compile time. We should also
- * take care not to overwrite the precious per platform data
- * we were given.
- */
-int __init rand_initialize(void)
-{
-	init_std_data(&input_pool);
-	init_std_data(&blocking_pool);
-	crng_initialize(&primary_crng);
-	crng_global_init_time = jiffies;
-	if (ratelimit_disable) {
-		urandom_warning.interval = 0;
-		unseeded_warning.interval = 0;
+	/*
+	 * Requesting insecure and blocking randomness at the same time makes
+	 * no sense.
+	 */
+	if ((flags & (GRND_INSECURE | GRND_RANDOM)) == (GRND_INSECURE | GRND_RANDOM))
+		return -EINVAL;
+
+	if (!crng_ready() && !(flags & GRND_INSECURE)) {
+		if (flags & GRND_NONBLOCK)
+			return -EAGAIN;
+		ret = wait_for_random_bytes();
+		if (unlikely(ret))
+			return ret;
 	}
-	return 0;
+
+	ret = import_single_range(READ, ubuf, len, &iov, &iter);
+	if (unlikely(ret))
+		return ret;
+	return get_random_bytes_user(&iter);
 }
 
-#ifdef CONFIG_BLOCK
-void rand_initialize_disk(struct gendisk *disk)
+static __poll_t random_poll(struct file *file, poll_table *wait)
 {
-	struct timer_rand_state *state;
-
-	/*
-	 * If kzalloc returns null, we just won't use that entropy
-	 * source.
-	 */
-	state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
-	if (state) {
-		state->last_time = INITIAL_JIFFIES;
-		disk->random = state;
-	}
+	poll_wait(file, &crng_init_wait, wait);
+	return crng_ready() ? EPOLLIN | EPOLLRDNORM : EPOLLOUT | EPOLLWRNORM;
 }
-#endif
 
-static ssize_t
-_random_read(int nonblock, char __user *buf, size_t nbytes)
+static ssize_t write_pool_user(struct iov_iter *iter)
 {
-	ssize_t n;
+	u8 block[BLAKE2S_BLOCK_SIZE];
+	ssize_t ret = 0;
+	size_t copied;
 
-	if (nbytes == 0)
+	if (unlikely(!iov_iter_count(iter)))
 		return 0;
 
-	nbytes = min_t(size_t, nbytes, SEC_XFER_SIZE);
-	while (1) {
-		n = extract_entropy_user(&blocking_pool, buf, nbytes);
-		if (n < 0)
-			return n;
-		trace_random_read(n*8, (nbytes-n)*8,
-				  ENTROPY_BITS(&blocking_pool),
-				  ENTROPY_BITS(&input_pool));
-		if (n > 0)
-			return n;
-
-		/* Pool is (near) empty.  Maybe wait and retry. */
-		if (nonblock)
-			return -EAGAIN;
+	for (;;) {
+		copied = copy_from_iter(block, sizeof(block), iter);
+		ret += copied;
+		mix_pool_bytes(block, copied);
+		if (!iov_iter_count(iter) || copied != sizeof(block))
+			break;
 
-		wait_event_interruptible(random_read_wait,
-		    blocking_pool.initialized &&
-		    (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits));
-		if (signal_pending(current))
-			return -ERESTARTSYS;
+		BUILD_BUG_ON(PAGE_SIZE % sizeof(block) != 0);
+		if (ret % PAGE_SIZE == 0) {
+			if (signal_pending(current))
+				break;
+			cond_resched();
+		}
 	}
-}
-
-static ssize_t
-random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
-{
-	return _random_read(file->f_flags & O_NONBLOCK, buf, nbytes);
-}
-
-static ssize_t
-urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
-{
-	unsigned long flags;
-	static int maxwarn = 10;
-	int ret;
 
-	if (!crng_ready() && maxwarn > 0) {
-		maxwarn--;
-		if (__ratelimit(&urandom_warning))
-			printk(KERN_NOTICE "random: %s: uninitialized "
-			       "urandom read (%zd bytes read)\n",
-			       current->comm, nbytes);
-		spin_lock_irqsave(&primary_crng.lock, flags);
-		crng_init_cnt = 0;
-		spin_unlock_irqrestore(&primary_crng.lock, flags);
-	}
-	nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
-	ret = extract_crng_user(buf, nbytes);
-	trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool));
-	return ret;
+	memzero_explicit(block, sizeof(block));
+	return ret ? ret : -EFAULT;
 }
 
-static __poll_t
-random_poll(struct file *file, poll_table * wait)
+static ssize_t random_write_iter(struct kiocb *kiocb, struct iov_iter *iter)
 {
-	__poll_t mask;
-
-	poll_wait(file, &random_read_wait, wait);
-	poll_wait(file, &random_write_wait, wait);
-	mask = 0;
-	if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits)
-		mask |= EPOLLIN | EPOLLRDNORM;
-	if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits)
-		mask |= EPOLLOUT | EPOLLWRNORM;
-	return mask;
+	return write_pool_user(iter);
 }
 
-static int
-write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
+static ssize_t urandom_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
 {
-	size_t bytes;
-	__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;
+	static int maxwarn = 10;
 
-		for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) {
-			if (!arch_get_random_int(&t))
-				break;
-			buf[i] ^= t;
+	if (!crng_ready()) {
+		if (!ratelimit_disable && maxwarn <= 0)
+			++urandom_warning.missed;
+		else if (ratelimit_disable || __ratelimit(&urandom_warning)) {
+			--maxwarn;
+			pr_notice("%s: uninitialized urandom read (%zu bytes read)\n",
+				  current->comm, iov_iter_count(iter));
 		}
-
-		count -= bytes;
-		p += bytes;
-
-		mix_pool_bytes(r, buf, bytes);
-		cond_resched();
 	}
 
-	return 0;
+	return get_random_bytes_user(iter);
 }
 
-static ssize_t random_write(struct file *file, const char __user *buffer,
-			    size_t count, loff_t *ppos)
+static ssize_t random_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
 {
-	size_t ret;
+	int ret;
 
-	ret = write_pool(&input_pool, buffer, count);
-	if (ret)
-		return ret;
+	if (!crng_ready() &&
+	    ((kiocb->ki_flags & IOCB_NOWAIT) ||
+	     (kiocb->ki_filp->f_flags & O_NONBLOCK)))
+		return -EAGAIN;
 
-	return (ssize_t)count;
+	ret = wait_for_random_bytes();
+	if (ret != 0)
+		return ret;
+	return get_random_bytes_user(iter);
 }
 
 static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
-	int size, ent_count;
 	int __user *p = (int __user *)arg;
-	int retval;
+	int ent_count;
 
 	switch (cmd) {
 	case RNDGETENTCNT:
-		/* inherently racy, no point locking */
-		ent_count = ENTROPY_BITS(&input_pool);
-		if (put_user(ent_count, p))
+		/* Inherently racy, no point locking. */
+		if (put_user(input_pool.init_bits, p))
 			return -EFAULT;
 		return 0;
 	case RNDADDTOENTCNT:
@@ -2117,39 +1325,48 @@
 			return -EPERM;
 		if (get_user(ent_count, p))
 			return -EFAULT;
-		return credit_entropy_bits_safe(&input_pool, ent_count);
-	case RNDADDENTROPY:
+		if (ent_count < 0)
+			return -EINVAL;
+		credit_init_bits(ent_count);
+		return 0;
+	case RNDADDENTROPY: {
+		struct iov_iter iter;
+		struct iovec iov;
+		ssize_t ret;
+		int len;
+
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		if (get_user(ent_count, p++))
 			return -EFAULT;
 		if (ent_count < 0)
 			return -EINVAL;
-		if (get_user(size, p++))
+		if (get_user(len, p++))
 			return -EFAULT;
-		retval = write_pool(&input_pool, (const char __user *)p,
-				    size);
-		if (retval < 0)
-			return retval;
-		return credit_entropy_bits_safe(&input_pool, ent_count);
+		ret = import_single_range(WRITE, p, len, &iov, &iter);
+		if (unlikely(ret))
+			return ret;
+		ret = write_pool_user(&iter);
+		if (unlikely(ret < 0))
+			return ret;
+		/* Since we're crediting, enforce that it was all written into the pool. */
+		if (unlikely(ret != len))
+			return -EFAULT;
+		credit_init_bits(ent_count);
+		return 0;
+	}
 	case RNDZAPENTCNT:
 	case RNDCLEARPOOL:
-		/*
-		 * Clear the entropy pool counters. We no longer clear
-		 * the entropy pool, as that's silly.
-		 */
+		/* No longer has any effect. */
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		input_pool.entropy_count = 0;
-		blocking_pool.entropy_count = 0;
 		return 0;
 	case RNDRESEEDCRNG:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (crng_init < 2)
+		if (!crng_ready())
 			return -ENODATA;
-		crng_reseed(&primary_crng, NULL);
-		crng_global_init_time = jiffies - 1;
+		crng_reseed();
 		return 0;
 	default:
 		return -EINVAL;
@@ -2162,49 +1379,56 @@
 }
 
 const struct file_operations random_fops = {
-	.read  = random_read,
-	.write = random_write,
-	.poll  = random_poll,
+	.read_iter = random_read_iter,
+	.write_iter = random_write_iter,
+	.poll = random_poll,
 	.unlocked_ioctl = random_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
 	.fasync = random_fasync,
 	.llseek = noop_llseek,
+	.splice_read = generic_file_splice_read,
+	.splice_write = iter_file_splice_write,
 };
 
 const struct file_operations urandom_fops = {
-	.read  = urandom_read,
-	.write = random_write,
+	.read_iter = urandom_read_iter,
+	.write_iter = random_write_iter,
 	.unlocked_ioctl = random_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
 	.fasync = random_fasync,
 	.llseek = noop_llseek,
+	.splice_read = generic_file_splice_read,
+	.splice_write = iter_file_splice_write,
 };
 
-SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
-		unsigned int, flags)
-{
-	int ret;
-
-	if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
-		return -EINVAL;
-
-	if (count > INT_MAX)
-		count = INT_MAX;
-
-	if (flags & GRND_RANDOM)
-		return _random_read(flags & GRND_NONBLOCK, buf, count);
-
-	if (!crng_ready()) {
-		if (flags & GRND_NONBLOCK)
-			return -EAGAIN;
-		ret = wait_for_random_bytes();
-		if (unlikely(ret))
-			return ret;
-	}
-	return urandom_read(NULL, buf, count, NULL);
-}
 
 /********************************************************************
  *
- * Sysctl interface
+ * Sysctl interface.
+ *
+ * These are partly unused legacy knobs with dummy values to not break
+ * userspace and partly still useful things. They are usually accessible
+ * in /proc/sys/kernel/random/ and are as follows:
+ *
+ * - boot_id - a UUID representing the current boot.
+ *
+ * - uuid - a random UUID, different each time the file is read.
+ *
+ * - poolsize - the number of bits of entropy that the input pool can
+ *   hold, tied to the POOL_BITS constant.
+ *
+ * - entropy_avail - the number of bits of entropy currently in the
+ *   input pool. Always <= poolsize.
+ *
+ * - write_wakeup_threshold - the amount of entropy in the input pool
+ *   below which write polls to /dev/random will unblock, requesting
+ *   more entropy, tied to the POOL_READY_BITS constant. It is writable
+ *   to avoid breaking old userspaces, but writing to it does not
+ *   change any behavior of the RNG.
+ *
+ * - urandom_min_reseed_secs - fixed to the value CRNG_RESEED_INTERVAL.
+ *   It is writable to avoid breaking old userspaces, but writing
+ *   to it does not change any behavior of the RNG.
  *
  ********************************************************************/
 
@@ -2212,26 +1436,28 @@
 
 #include <linux/sysctl.h>
 
-static int min_read_thresh = 8, min_write_thresh;
-static int max_read_thresh = OUTPUT_POOL_WORDS * 32;
-static int max_write_thresh = INPUT_POOL_WORDS * 32;
-static int random_min_urandom_seed = 60;
-static char sysctl_bootid[16];
+static int sysctl_random_min_urandom_seed = CRNG_RESEED_INTERVAL / HZ;
+static int sysctl_random_write_wakeup_bits = POOL_READY_BITS;
+static int sysctl_poolsize = POOL_BITS;
+static u8 sysctl_bootid[UUID_SIZE];
 
 /*
  * This function is used to return both the bootid UUID, and random
- * UUID.  The difference is in whether table->data is NULL; if it is,
+ * UUID. The difference is in whether table->data is NULL; if it is,
  * then a new UUID is generated and returned to the user.
- *
- * If the user accesses this via the proc interface, the UUID will be
- * returned as an ASCII string in the standard UUID format; if via the
- * sysctl system call, as 16 bytes of binary data.
  */
-static int proc_do_uuid(struct ctl_table *table, int write,
-			void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_do_uuid(struct ctl_table *table, int write, void __user *buf,
+			size_t *lenp, loff_t *ppos)
 {
-	struct ctl_table fake_table;
-	unsigned char buf[64], tmp_uuid[16], *uuid;
+	u8 tmp_uuid[UUID_SIZE], *uuid;
+	char uuid_string[UUID_STRING_LEN + 1];
+	struct ctl_table fake_table = {
+		.data = uuid_string,
+		.maxlen = UUID_STRING_LEN
+	};
+
+	if (write)
+		return -EPERM;
 
 	uuid = table->data;
 	if (!uuid) {
@@ -2246,32 +1472,17 @@
 		spin_unlock(&bootid_spinlock);
 	}
 
-	sprintf(buf, "%pU", uuid);
-
-	fake_table.data = buf;
-	fake_table.maxlen = sizeof(buf);
-
-	return proc_dostring(&fake_table, write, buffer, lenp, ppos);
+	snprintf(uuid_string, sizeof(uuid_string), "%pU", uuid);
+	return proc_dostring(&fake_table, 0, buf, lenp, ppos);
 }
 
-/*
- * Return entropy available scaled to integral bits
- */
-static int proc_do_entropy(struct ctl_table *table, int write,
-			   void __user *buffer, size_t *lenp, loff_t *ppos)
+/* The same as proc_dointvec, but writes don't change anything. */
+static int proc_do_rointvec(struct ctl_table *table, int write, void __user *buf,
+			    size_t *lenp, loff_t *ppos)
 {
-	struct ctl_table fake_table;
-	int entropy_count;
-
-	entropy_count = *(int *)table->data >> ENTROPY_SHIFT;
-
-	fake_table.data = &entropy_count;
-	fake_table.maxlen = sizeof(entropy_count);
-
-	return proc_dointvec(&fake_table, write, buffer, lenp, ppos);
+	return write ? 0 : proc_dointvec(table, 0, buf, lenp, ppos);
 }
 
-static int sysctl_poolsize = INPUT_POOL_WORDS * 32;
 extern struct ctl_table random_table[];
 struct ctl_table random_table[] = {
 	{
@@ -2283,239 +1494,36 @@
 	},
 	{
 		.procname	= "entropy_avail",
+		.data		= &input_pool.init_bits,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
-		.proc_handler	= proc_do_entropy,
-		.data		= &input_pool.entropy_count,
-	},
-	{
-		.procname	= "read_wakeup_threshold",
-		.data		= &random_read_wakeup_bits,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &min_read_thresh,
-		.extra2		= &max_read_thresh,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "write_wakeup_threshold",
-		.data		= &random_write_wakeup_bits,
+		.data		= &sysctl_random_write_wakeup_bits,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &min_write_thresh,
-		.extra2		= &max_write_thresh,
+		.proc_handler	= proc_do_rointvec,
 	},
 	{
 		.procname	= "urandom_min_reseed_secs",
-		.data		= &random_min_urandom_seed,
+		.data		= &sysctl_random_min_urandom_seed,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_do_rointvec,
 	},
 	{
 		.procname	= "boot_id",
 		.data		= &sysctl_bootid,
-		.maxlen		= 16,
 		.mode		= 0444,
 		.proc_handler	= proc_do_uuid,
 	},
 	{
 		.procname	= "uuid",
-		.maxlen		= 16,
 		.mode		= 0444,
 		.proc_handler	= proc_do_uuid,
 	},
-#ifdef ADD_INTERRUPT_BENCH
-	{
-		.procname	= "add_interrupt_avg_cycles",
-		.data		= &avg_cycles,
-		.maxlen		= sizeof(avg_cycles),
-		.mode		= 0444,
-		.proc_handler	= proc_doulongvec_minmax,
-	},
-	{
-		.procname	= "add_interrupt_avg_deviation",
-		.data		= &avg_deviation,
-		.maxlen		= sizeof(avg_deviation),
-		.mode		= 0444,
-		.proc_handler	= proc_doulongvec_minmax,
-	},
-#endif
 	{ }
 };
-#endif 	/* CONFIG_SYSCTL */
-
-struct batched_entropy {
-	union {
-		u64 entropy_u64[CHACHA_BLOCK_SIZE / sizeof(u64)];
-		u32 entropy_u32[CHACHA_BLOCK_SIZE / sizeof(u32)];
-	};
-	unsigned int position;
-	spinlock_t batch_lock;
-};
-
-/*
- * Get a random word for internal kernel use only. The quality of the random
- * number is either as good as RDRAND or as good as /dev/urandom, with the
- * goal of being quite fast and not depleting entropy. In order to ensure
- * that the randomness provided by this function is okay, the function
- * wait_for_random_bytes() should be called and return 0 at least once
- * at any point prior.
- */
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = {
-	.batch_lock	= __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock),
-};
-
-u64 get_random_u64(void)
-{
-	u64 ret;
-	unsigned long flags;
-	struct batched_entropy *batch;
-	static void *previous;
-
-#if BITS_PER_LONG == 64
-	if (arch_get_random_long((unsigned long *)&ret))
-		return ret;
-#else
-	if (arch_get_random_long((unsigned long *)&ret) &&
-	    arch_get_random_long((unsigned long *)&ret + 1))
-	    return ret;
-#endif
-
-	warn_unseeded_randomness(&previous);
-
-	batch = raw_cpu_ptr(&batched_entropy_u64);
-	spin_lock_irqsave(&batch->batch_lock, flags);
-	if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
-		extract_crng((u8 *)batch->entropy_u64);
-		batch->position = 0;
-	}
-	ret = batch->entropy_u64[batch->position++];
-	spin_unlock_irqrestore(&batch->batch_lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(get_random_u64);
-
-static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) = {
-	.batch_lock	= __SPIN_LOCK_UNLOCKED(batched_entropy_u32.lock),
-};
-u32 get_random_u32(void)
-{
-	u32 ret;
-	unsigned long flags;
-	struct batched_entropy *batch;
-	static void *previous;
-
-	if (arch_get_random_int(&ret))
-		return ret;
-
-	warn_unseeded_randomness(&previous);
-
-	batch = raw_cpu_ptr(&batched_entropy_u32);
-	spin_lock_irqsave(&batch->batch_lock, flags);
-	if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
-		extract_crng((u8 *)batch->entropy_u32);
-		batch->position = 0;
-	}
-	ret = batch->entropy_u32[batch->position++];
-	spin_unlock_irqrestore(&batch->batch_lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(get_random_u32);
-
-/* It's important to invalidate all potential batched entropy that might
- * be stored before the crng is initialized, which we can do lazily by
- * simply resetting the counter to zero so that it's re-extracted on the
- * next usage. */
-static void invalidate_batched_entropy(void)
-{
-	int cpu;
-	unsigned long flags;
-
-	for_each_possible_cpu (cpu) {
-		struct batched_entropy *batched_entropy;
-
-		batched_entropy = per_cpu_ptr(&batched_entropy_u32, cpu);
-		spin_lock_irqsave(&batched_entropy->batch_lock, flags);
-		batched_entropy->position = 0;
-		spin_unlock(&batched_entropy->batch_lock);
-
-		batched_entropy = per_cpu_ptr(&batched_entropy_u64, cpu);
-		spin_lock(&batched_entropy->batch_lock);
-		batched_entropy->position = 0;
-		spin_unlock_irqrestore(&batched_entropy->batch_lock, flags);
-	}
-}
-
-/**
- * randomize_page - Generate a random, page aligned address
- * @start:	The smallest acceptable address the caller will take.
- * @range:	The size of the area, starting at @start, within which the
- *		random address must fall.
- *
- * If @start + @range would overflow, @range is capped.
- *
- * NOTE: Historical use of randomize_range, which this replaces, presumed that
- * @start was already page aligned.  We now align it regardless.
- *
- * Return: A page aligned address within [start, start + range).  On error,
- * @start is returned.
- */
-unsigned long
-randomize_page(unsigned long start, unsigned long range)
-{
-	if (!PAGE_ALIGNED(start)) {
-		range -= PAGE_ALIGN(start) - start;
-		start = PAGE_ALIGN(start);
-	}
-
-	if (start > ULONG_MAX - range)
-		range = ULONG_MAX - start;
-
-	range >>= PAGE_SHIFT;
-
-	if (range == 0)
-		return start;
-
-	return start + (get_random_long() % range << PAGE_SHIFT);
-}
-
-/* Interface for in-kernel drivers of true hardware RNGs.
- * Those devices may produce endless random bits and will be throttled
- * when our pool is full.
- */
-void add_hwgenerator_randomness(const char *buffer, size_t count,
-				size_t entropy)
-{
-	struct entropy_store *poolp = &input_pool;
-
-	if (unlikely(crng_init == 0)) {
-		crng_fast_load(buffer, count);
-		return;
-	}
-
-	/* 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);
-}
-EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
-
-/* Handle random seed passed by bootloader.
- * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise
- * it would be regarded as device data.
- * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER.
- */
-void add_bootloader_randomness(const void *buf, unsigned int size)
-{
-	if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER))
-		add_hwgenerator_randomness(buf, size, size * 8);
-	else
-		add_device_randomness(buf, size);
-}
-EXPORT_SYMBOL_GPL(add_bootloader_randomness);
+#endif	/* CONFIG_SYSCTL */
--- linux-ein-5.4.0.orig/drivers/char/tlclk.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/char/tpm/eventlog/common.c
+++ linux-ein-5.4.0/drivers/char/tpm/eventlog/common.c
@@ -99,20 +99,20 @@
  *
  * If an event log is found then the securityfs files are setup to
  * export it to userspace, otherwise nothing is done.
- *
- * Returns -ENODEV if the firmware has no event log or securityfs is not
- * supported.
  */
-int tpm_bios_log_setup(struct tpm_chip *chip)
+void tpm_bios_log_setup(struct tpm_chip *chip)
 {
 	const char *name = dev_name(&chip->dev);
 	unsigned int cnt;
 	int log_version;
 	int rc = 0;
 
+	if (chip->flags & TPM_CHIP_FLAG_VIRTUAL)
+		return;
+
 	rc = tpm_read_log(chip);
 	if (rc < 0)
-		return rc;
+		return;
 	log_version = rc;
 
 	cnt = 0;
@@ -158,13 +158,12 @@
 		cnt++;
 	}
 
-	return 0;
+	return;
 
 err:
-	rc = PTR_ERR(chip->bios_dir[cnt]);
 	chip->bios_dir[cnt] = NULL;
 	tpm_bios_log_teardown(chip);
-	return rc;
+	return;
 }
 
 void tpm_bios_log_teardown(struct tpm_chip *chip)
--- linux-ein-5.4.0.orig/drivers/char/tpm/eventlog/efi.c
+++ linux-ein-5.4.0/drivers/char/tpm/eventlog/efi.c
@@ -17,6 +17,7 @@
 {
 
 	struct efi_tcg2_final_events_table *final_tbl = NULL;
+	int final_events_log_size = efi_tpm_final_log_size;
 	struct linux_efi_tpm_eventlog *log_tbl;
 	struct tpm_bios_log *log;
 	u32 log_size;
@@ -41,6 +42,11 @@
 	log_size = log_tbl->size;
 	memunmap(log_tbl);
 
+	if (!log_size) {
+		pr_warn("UEFI TPM log area empty\n");
+		return -EIO;
+	}
+
 	log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
 			   MEMREMAP_WB);
 	if (!log_tbl) {
@@ -61,12 +67,12 @@
 	ret = tpm_log_version;
 
 	if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
-	    efi_tpm_final_log_size == 0 ||
+	    final_events_log_size == 0 ||
 	    tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
 		goto out;
 
 	final_tbl = memremap(efi.tpm_final_log,
-			     sizeof(*final_tbl) + efi_tpm_final_log_size,
+			     sizeof(*final_tbl) + final_events_log_size,
 			     MEMREMAP_WB);
 	if (!final_tbl) {
 		pr_err("Could not map UEFI TPM final log\n");
@@ -75,10 +81,18 @@
 		goto out;
 	}
 
-	efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
+	/*
+	 * The 'final events log' size excludes the 'final events preboot log'
+	 * at its beginning.
+	 */
+	final_events_log_size -= log_tbl->final_events_preboot_size;
 
+	/*
+	 * Allocate memory for the 'combined log' where we will append the
+	 * 'final events log' to.
+	 */
 	tmp = krealloc(log->bios_event_log,
-		       log_size + efi_tpm_final_log_size,
+		       log_size + final_events_log_size,
 		       GFP_KERNEL);
 	if (!tmp) {
 		kfree(log->bios_event_log);
@@ -89,15 +103,19 @@
 	log->bios_event_log = tmp;
 
 	/*
-	 * Copy any of the final events log that didn't also end up in the
-	 * main log. Events can be logged in both if events are generated
+	 * Append any of the 'final events log' that didn't also end up in the
+	 * 'main log'. Events can be logged in both if events are generated
 	 * between GetEventLog() and ExitBootServices().
 	 */
 	memcpy((void *)log->bios_event_log + log_size,
 	       final_tbl->events + log_tbl->final_events_preboot_size,
-	       efi_tpm_final_log_size);
+	       final_events_log_size);
+	/*
+	 * The size of the 'combined log' is the size of the 'main log' plus
+	 * the size of the 'final events log'.
+	 */
 	log->bios_event_log_end = log->bios_event_log +
-		log_size + efi_tpm_final_log_size;
+		log_size + final_events_log_size;
 
 out:
 	memunmap(final_tbl);
--- linux-ein-5.4.0.orig/drivers/char/tpm/eventlog/tpm1.c
+++ linux-ein-5.4.0/drivers/char/tpm/eventlog/tpm1.c
@@ -115,6 +115,7 @@
 	u32 converted_event_size;
 	u32 converted_event_type;
 
+	(*pos)++;
 	converted_event_size = do_endian_conversion(event->event_size);
 
 	v += sizeof(struct tcpa_event) + converted_event_size;
@@ -132,7 +133,6 @@
 	    ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
 		return NULL;
 
-	(*pos)++;
 	return v;
 }
 
--- linux-ein-5.4.0.orig/drivers/char/tpm/eventlog/tpm2.c
+++ linux-ein-5.4.0/drivers/char/tpm/eventlog/tpm2.c
@@ -94,6 +94,7 @@
 	size_t event_size;
 	void *marker;
 
+	(*pos)++;
 	event_header = log->bios_event_log;
 
 	if (v == SEQ_START_TOKEN) {
@@ -118,7 +119,6 @@
 	if (((v + event_size) >= limit) || (event_size == 0))
 		return NULL;
 
-	(*pos)++;
 	return v;
 }
 
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm-chip.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm-chip.c
@@ -274,14 +274,6 @@
 	kfree(chip);
 }
 
-static void tpm_devs_release(struct device *dev)
-{
-	struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
-
-	/* release the master device reference */
-	put_device(&chip->dev);
-}
-
 /**
  * tpm_class_shutdown() - prepare the TPM device for loss of power.
  * @dev: device to which the chip is associated.
@@ -344,7 +336,6 @@
 	chip->dev_num = rc;
 
 	device_initialize(&chip->dev);
-	device_initialize(&chip->devs);
 
 	chip->dev.class = tpm_class;
 	chip->dev.class->shutdown_pre = tpm_class_shutdown;
@@ -352,47 +343,23 @@
 	chip->dev.parent = pdev;
 	chip->dev.groups = chip->groups;
 
-	chip->devs.parent = pdev;
-	chip->devs.class = tpmrm_class;
-	chip->devs.release = tpm_devs_release;
-	/* get extra reference on main device to hold on
-	 * behalf of devs.  This holds the chip structure
-	 * while cdevs is in use.  The corresponding put
-	 * is in the tpm_devs_release (TPM2 only)
-	 */
-	if (chip->flags & TPM_CHIP_FLAG_TPM2)
-		get_device(&chip->dev);
-
 	if (chip->dev_num == 0)
 		chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
 	else
 		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
 
-	chip->devs.devt =
-		MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
-
 	rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
 	if (rc)
 		goto out;
-	rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
-	if (rc)
-		goto out;
 
 	if (!pdev)
 		chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
 
 	cdev_init(&chip->cdev, &tpm_fops);
-	cdev_init(&chip->cdevs, &tpmrm_fops);
 	chip->cdev.owner = THIS_MODULE;
-	chip->cdevs.owner = THIS_MODULE;
 
-	chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!chip->work_space.context_buf) {
-		rc = -ENOMEM;
-		goto out;
-	}
-	chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!chip->work_space.session_buf) {
+	rc = tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE);
+	if (rc) {
 		rc = -ENOMEM;
 		goto out;
 	}
@@ -401,7 +368,6 @@
 	return chip;
 
 out:
-	put_device(&chip->devs);
 	put_device(&chip->dev);
 	return ERR_PTR(rc);
 }
@@ -450,14 +416,9 @@
 	}
 
 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
-		rc = cdev_device_add(&chip->cdevs, &chip->devs);
-		if (rc) {
-			dev_err(&chip->devs,
-				"unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
-				dev_name(&chip->devs), MAJOR(chip->devs.devt),
-				MINOR(chip->devs.devt), rc);
-			return rc;
-		}
+		rc = tpm_devs_add(chip);
+		if (rc)
+			goto err_del_cdev;
 	}
 
 	/* Make the chip available. */
@@ -465,6 +426,10 @@
 	idr_replace(&dev_nums_idr, chip, chip->dev_num);
 	mutex_unlock(&idr_lock);
 
+	return 0;
+
+err_del_cdev:
+	cdev_device_del(&chip->cdev, &chip->dev);
 	return rc;
 }
 
@@ -596,9 +561,7 @@
 
 	tpm_sysfs_add_device(chip);
 
-	rc = tpm_bios_log_setup(chip);
-	if (rc != 0 && rc != -ENODEV)
-		return rc;
+	tpm_bios_log_setup(chip);
 
 	tpm_add_ppi(chip);
 
@@ -648,7 +611,7 @@
 		hwrng_unregister(&chip->hwrng);
 	tpm_bios_log_teardown(chip);
 	if (chip->flags & TPM_CHIP_FLAG_TPM2)
-		cdev_device_del(&chip->cdevs, &chip->devs);
+		tpm_devs_remove(chip);
 	tpm_del_char_device(chip);
 }
 EXPORT_SYMBOL_GPL(tpm_chip_unregister);
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm-dev-common.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm-dev-common.c
@@ -61,13 +61,26 @@
 
 	mutex_lock(&priv->buffer_mutex);
 	priv->command_enqueued = false;
+	ret = tpm_try_get_ops(priv->chip);
+	if (ret) {
+		priv->response_length = ret;
+		goto out;
+	}
+
 	ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
 			       sizeof(priv->data_buffer));
 	tpm_put_ops(priv->chip);
-	if (ret > 0) {
+
+	/*
+	 * If ret is > 0 then tpm_dev_transmit returned the size of the
+	 * response. If ret is < 0 then tpm_dev_transmit failed and
+	 * returned an error code.
+	 */
+	if (ret != 0) {
 		priv->response_length = ret;
 		mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
 	}
+out:
 	mutex_unlock(&priv->buffer_mutex);
 	wake_up_interruptible(&priv->async_wait);
 }
@@ -123,7 +136,7 @@
 		priv->response_read = true;
 
 		ret_size = min_t(ssize_t, size, priv->response_length);
-		if (!ret_size) {
+		if (ret_size <= 0) {
 			priv->response_length = 0;
 			goto out;
 		}
@@ -182,15 +195,6 @@
 		goto out;
 	}
 
-	/* 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)) {
-		ret = -EPIPE;
-		goto out;
-	}
-
 	priv->response_length = 0;
 	priv->response_read = false;
 	*off = 0;
@@ -208,6 +212,15 @@
 		return size;
 	}
 
+	/* 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)) {
+		ret = -EPIPE;
+		goto out;
+	}
+
 	ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
 			       sizeof(priv->data_buffer));
 	tpm_put_ops(priv->chip);
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm-dev.h
+++ linux-ein-5.4.0/drivers/char/tpm/tpm-dev.h
@@ -14,7 +14,7 @@
 	struct work_struct timeout_work;
 	struct work_struct async_work;
 	wait_queue_head_t async_wait;
-	size_t response_length;
+	ssize_t response_length;
 	bool response_read;
 	bool command_enqueued;
 
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm-interface.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm-interface.c
@@ -322,7 +322,7 @@
 
 	for (i = 0; i < chip->nr_allocated_banks; i++) {
 		if (digests[i].alg_id != chip->allocated_banks[i].alg_id) {
-			rc = EINVAL;
+			rc = -EINVAL;
 			goto out;
 		}
 	}
@@ -396,13 +396,14 @@
 	if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
 		return 0;
 
-	if (!tpm_chip_start(chip)) {
+	rc = tpm_try_get_ops(chip);
+	if (!rc) {
 		if (chip->flags & TPM_CHIP_FLAG_TPM2)
 			tpm2_shutdown(chip, TPM2_SU_STATE);
 		else
 			rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
 
-		tpm_chip_stop(chip);
+		tpm_put_ops(chip);
 	}
 
 	return rc;
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm.h
+++ linux-ein-5.4.0/drivers/char/tpm/tpm.h
@@ -177,6 +177,9 @@
 
 #define TPM_TAG_RQU_COMMAND 193
 
+/* TPM2 specific constants. */
+#define TPM2_SPACE_BUFFER_SIZE		16384 /* 16 kB */
+
 struct	stclear_flags_t {
 	__be16	tag;
 	u8	deactivated;
@@ -456,15 +459,17 @@
 unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
 int tpm2_probe(struct tpm_chip *chip);
 int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
-int tpm2_init_space(struct tpm_space *space);
+int tpm2_init_space(struct tpm_space *space, unsigned int buf_size);
 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space);
 void tpm2_flush_space(struct tpm_chip *chip);
 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
 		       size_t cmdsiz);
 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
 		      size_t *bufsiz);
+int tpm_devs_add(struct tpm_chip *chip);
+void tpm_devs_remove(struct tpm_chip *chip);
 
-int tpm_bios_log_setup(struct tpm_chip *chip);
+void tpm_bios_log_setup(struct tpm_chip *chip);
 void tpm_bios_log_teardown(struct tpm_chip *chip);
 int tpm_dev_common_init(void);
 void tpm_dev_common_exit(void);
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm2-cmd.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm2-cmd.c
@@ -706,7 +706,16 @@
 	if (!rc) {
 		out = (struct tpm2_get_cap_out *)
 			&buf.data[TPM_HEADER_SIZE];
-		*value = be32_to_cpu(out->value);
+		/*
+		 * To prevent failing boot up of some systems, Infineon TPM2.0
+		 * returns SUCCESS on TPM2_Startup in field upgrade mode. Also
+		 * the TPM2_Getcapability command returns a zero length list
+		 * in field upgrade mode.
+		 */
+		if (be32_to_cpu(out->property_cnt) > 0)
+			*value = be32_to_cpu(out->value);
+		else
+			rc = -ENODATA;
 	}
 	tpm_buf_destroy(&buf);
 	return rc;
@@ -831,6 +840,8 @@
 		return 0;
 	}
 
+	bank->crypto_id = HASH_ALGO__LAST;
+
 	return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size);
 }
 
@@ -939,6 +950,10 @@
 
 	chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands,
 					  GFP_KERNEL);
+	if (!chip->cc_attrs_tbl) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
 	if (rc)
@@ -956,6 +971,7 @@
 
 	if (nr_commands !=
 	    be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+		rc = -EFAULT;
 		tpm_buf_destroy(&buf);
 		goto out;
 	}
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm2-space.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm2-space.c
@@ -38,29 +38,32 @@
 	}
 }
 
-int tpm2_init_space(struct tpm_space *space)
+int tpm2_init_space(struct tpm_space *space, unsigned int buf_size)
 {
-	space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	space->context_buf = kzalloc(buf_size, GFP_KERNEL);
 	if (!space->context_buf)
 		return -ENOMEM;
 
-	space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	space->session_buf = kzalloc(buf_size, GFP_KERNEL);
 	if (space->session_buf == NULL) {
 		kfree(space->context_buf);
+		/* Prevent caller getting a dangling pointer. */
+		space->context_buf = NULL;
 		return -ENOMEM;
 	}
 
+	space->buf_size = buf_size;
 	return 0;
 }
 
 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
 {
-	mutex_lock(&chip->tpm_mutex);
-	if (!tpm_chip_start(chip)) {
+
+	if (tpm_try_get_ops(chip) == 0) {
 		tpm2_flush_sessions(chip, space);
-		tpm_chip_stop(chip);
+		tpm_put_ops(chip);
 	}
-	mutex_unlock(&chip->tpm_mutex);
+
 	kfree(space->context_buf);
 	kfree(space->session_buf);
 }
@@ -311,8 +314,10 @@
 	       sizeof(space->context_tbl));
 	memcpy(&chip->work_space.session_tbl, &space->session_tbl,
 	       sizeof(space->session_tbl));
-	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
-	memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE);
+	memcpy(chip->work_space.context_buf, space->context_buf,
+	       space->buf_size);
+	memcpy(chip->work_space.session_buf, space->session_buf,
+	       space->buf_size);
 
 	rc = tpm2_load_space(chip);
 	if (rc) {
@@ -450,6 +455,9 @@
 	if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
 		return 0;
 
+	if (be32_to_cpu(data->count) > (UINT_MAX - TPM_HEADER_SIZE - 9) / 4)
+		return -EFAULT;
+
 	if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
 		return -EFAULT;
 
@@ -492,7 +500,7 @@
 			continue;
 
 		rc = tpm2_save_context(chip, space->context_tbl[i],
-				       space->context_buf, PAGE_SIZE,
+				       space->context_buf, space->buf_size,
 				       &offset);
 		if (rc == -ENOENT) {
 			space->context_tbl[i] = 0;
@@ -509,9 +517,8 @@
 			continue;
 
 		rc = tpm2_save_context(chip, space->session_tbl[i],
-				       space->session_buf, PAGE_SIZE,
+				       space->session_buf, space->buf_size,
 				       &offset);
-
 		if (rc == -ENOENT) {
 			/* handle error saving session, just forget it */
 			space->session_tbl[i] = 0;
@@ -557,11 +564,78 @@
 	       sizeof(space->context_tbl));
 	memcpy(&space->session_tbl, &chip->work_space.session_tbl,
 	       sizeof(space->session_tbl));
-	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
-	memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
+	memcpy(space->context_buf, chip->work_space.context_buf,
+	       space->buf_size);
+	memcpy(space->session_buf, chip->work_space.session_buf,
+	       space->buf_size);
 
 	return 0;
 out:
 	dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
 	return rc;
 }
+
+/*
+ * Put the reference to the main device.
+ */
+static void tpm_devs_release(struct device *dev)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
+
+	/* release the master device reference */
+	put_device(&chip->dev);
+}
+
+/*
+ * Remove the device file for exposed TPM spaces and release the device
+ * reference. This may also release the reference to the master device.
+ */
+void tpm_devs_remove(struct tpm_chip *chip)
+{
+	cdev_device_del(&chip->cdevs, &chip->devs);
+	put_device(&chip->devs);
+}
+
+/*
+ * Add a device file to expose TPM spaces. Also take a reference to the
+ * main device.
+ */
+int tpm_devs_add(struct tpm_chip *chip)
+{
+	int rc;
+
+	device_initialize(&chip->devs);
+	chip->devs.parent = chip->dev.parent;
+	chip->devs.class = tpmrm_class;
+
+	/*
+	 * Get extra reference on main device to hold on behalf of devs.
+	 * This holds the chip structure while cdevs is in use. The
+	 * corresponding put is in the tpm_devs_release.
+	 */
+	get_device(&chip->dev);
+	chip->devs.release = tpm_devs_release;
+	chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
+	cdev_init(&chip->cdevs, &tpmrm_fops);
+	chip->cdevs.owner = THIS_MODULE;
+
+	rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
+	if (rc)
+		goto err_put_devs;
+
+	rc = cdev_device_add(&chip->cdevs, &chip->devs);
+	if (rc) {
+		dev_err(&chip->devs,
+			"unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
+			dev_name(&chip->devs), MAJOR(chip->devs.devt),
+			MINOR(chip->devs.devt), rc);
+		goto err_put_devs;
+	}
+
+	return 0;
+
+err_put_devs:
+	put_device(&chip->devs);
+
+	return rc;
+}
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_crb.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_crb.c
@@ -22,6 +22,7 @@
 #include "tpm.h"
 
 #define ACPI_SIG_TPM2 "TPM2"
+#define TPM_CRB_MAX_RESOURCES 3
 
 static const guid_t crb_acpi_start_guid =
 	GUID_INIT(0x6BBF6CAB, 0x5463, 0x4714,
@@ -91,7 +92,6 @@
 struct crb_priv {
 	u32 sm;
 	const char *hid;
-	void __iomem *iobase;
 	struct crb_regs_head __iomem *regs_h;
 	struct crb_regs_tail __iomem *regs_t;
 	u8 __iomem *cmd;
@@ -252,7 +252,7 @@
 	iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl);
 	if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, mask, value,
 				 TPM2_TIMEOUT_C)) {
-		dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
+		dev_warn(dev, "TPM_LOC_STATE_x.Relinquish timed out\n");
 		return -ETIME;
 	}
 
@@ -434,21 +434,27 @@
 
 static int crb_check_resource(struct acpi_resource *ares, void *data)
 {
-	struct resource *io_res = data;
+	struct resource *iores_array = data;
 	struct resource_win win;
 	struct resource *res = &(win.res);
+	int i;
 
 	if (acpi_dev_resource_memory(ares, res) ||
 	    acpi_dev_resource_address_space(ares, &win)) {
-		*io_res = *res;
-		io_res->name = NULL;
+		for (i = 0; i < TPM_CRB_MAX_RESOURCES + 1; ++i) {
+			if (resource_type(iores_array + i) != IORESOURCE_MEM) {
+				iores_array[i] = *res;
+				iores_array[i].name = NULL;
+				break;
+			}
+		}
 	}
 
 	return 1;
 }
 
-static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv,
-				 struct resource *io_res, u64 start, u32 size)
+static void __iomem *crb_map_res(struct device *dev, struct resource *iores,
+				 void __iomem **iobase_ptr, u64 start, u32 size)
 {
 	struct resource new_res = {
 		.start	= start,
@@ -460,10 +466,16 @@
 	if (start != new_res.start)
 		return (void __iomem *) ERR_PTR(-EINVAL);
 
-	if (!resource_contains(io_res, &new_res))
+	if (!iores)
 		return devm_ioremap_resource(dev, &new_res);
 
-	return priv->iobase + (new_res.start - io_res->start);
+	if (!*iobase_ptr) {
+		*iobase_ptr = devm_ioremap_resource(dev, iores);
+		if (IS_ERR(*iobase_ptr))
+			return *iobase_ptr;
+	}
+
+	return *iobase_ptr + (new_res.start - iores->start);
 }
 
 /*
@@ -490,9 +502,13 @@
 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 list_head acpi_resource_list;
+	struct resource iores_array[TPM_CRB_MAX_RESOURCES + 1] = { {0} };
+	void __iomem *iobase_array[TPM_CRB_MAX_RESOURCES] = {NULL};
 	struct device *dev = &device->dev;
+	struct resource *iores;
+	void __iomem **iobase_ptr;
+	int i;
 	u32 pa_high, pa_low;
 	u64 cmd_pa;
 	u32 cmd_size;
@@ -501,21 +517,41 @@
 	u32 rsp_size;
 	int ret;
 
-	INIT_LIST_HEAD(&resources);
-	ret = acpi_dev_get_resources(device, &resources, crb_check_resource,
-				     &io_res);
+	INIT_LIST_HEAD(&acpi_resource_list);
+	ret = acpi_dev_get_resources(device, &acpi_resource_list,
+				     crb_check_resource, iores_array);
 	if (ret < 0)
 		return ret;
-	acpi_dev_free_resource_list(&resources);
+	acpi_dev_free_resource_list(&acpi_resource_list);
 
-	if (resource_type(&io_res) != IORESOURCE_MEM) {
+	if (resource_type(iores_array) != IORESOURCE_MEM) {
 		dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
 		return -EINVAL;
+	} else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) ==
+		IORESOURCE_MEM) {
+		dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n");
+		memset(iores_array + TPM_CRB_MAX_RESOURCES,
+		       0, sizeof(*iores_array));
+		iores_array[TPM_CRB_MAX_RESOURCES].flags = 0;
+	}
+
+	iores = NULL;
+	iobase_ptr = NULL;
+	for (i = 0; resource_type(iores_array + i) == IORESOURCE_MEM; ++i) {
+		if (buf->control_address >= iores_array[i].start &&
+		    buf->control_address + sizeof(struct crb_regs_tail) - 1 <=
+		    iores_array[i].end) {
+			iores = iores_array + i;
+			iobase_ptr = iobase_array + i;
+			break;
+		}
 	}
 
-	priv->iobase = devm_ioremap_resource(dev, &io_res);
-	if (IS_ERR(priv->iobase))
-		return PTR_ERR(priv->iobase);
+	priv->regs_t = crb_map_res(dev, iores, iobase_ptr, buf->control_address,
+				   sizeof(struct crb_regs_tail));
+
+	if (IS_ERR(priv->regs_t))
+		return PTR_ERR(priv->regs_t);
 
 	/* The ACPI IO region starts at the head area and continues to include
 	 * the control area, as one nice sane region except for some older
@@ -523,9 +559,10 @@
 	 */
 	if ((priv->sm == ACPI_TPM2_COMMAND_BUFFER) ||
 	    (priv->sm == ACPI_TPM2_MEMORY_MAPPED)) {
-		if (buf->control_address == io_res.start +
+		if (iores &&
+		    buf->control_address == iores->start +
 		    sizeof(*priv->regs_h))
-			priv->regs_h = priv->iobase;
+			priv->regs_h = *iobase_ptr;
 		else
 			dev_warn(dev, FW_BUG "Bad ACPI memory layout");
 	}
@@ -534,13 +571,6 @@
 	if (ret)
 		return ret;
 
-	priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address,
-				   sizeof(struct crb_regs_tail));
-	if (IS_ERR(priv->regs_t)) {
-		ret = PTR_ERR(priv->regs_t);
-		goto out_relinquish_locality;
-	}
-
 	/*
 	 * PTT HW bug w/a: wake up the device to access
 	 * possibly not retained registers.
@@ -552,13 +582,26 @@
 	pa_high = ioread32(&priv->regs_t->ctrl_cmd_pa_high);
 	pa_low  = ioread32(&priv->regs_t->ctrl_cmd_pa_low);
 	cmd_pa = ((u64)pa_high << 32) | pa_low;
-	cmd_size = crb_fixup_cmd_size(dev, &io_res, cmd_pa,
-				      ioread32(&priv->regs_t->ctrl_cmd_size));
+	cmd_size = ioread32(&priv->regs_t->ctrl_cmd_size);
+
+	iores = NULL;
+	iobase_ptr = NULL;
+	for (i = 0; iores_array[i].end; ++i) {
+		if (cmd_pa >= iores_array[i].start &&
+		    cmd_pa <= iores_array[i].end) {
+			iores = iores_array + i;
+			iobase_ptr = iobase_array + i;
+			break;
+		}
+	}
+
+	if (iores)
+		cmd_size = crb_fixup_cmd_size(dev, iores, cmd_pa, cmd_size);
 
 	dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n",
 		pa_high, pa_low, cmd_size);
 
-	priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size);
+	priv->cmd = crb_map_res(dev, iores, iobase_ptr,	cmd_pa, cmd_size);
 	if (IS_ERR(priv->cmd)) {
 		ret = PTR_ERR(priv->cmd);
 		goto out;
@@ -566,11 +609,25 @@
 
 	memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8);
 	rsp_pa = le64_to_cpu(__rsp_pa);
-	rsp_size = crb_fixup_cmd_size(dev, &io_res, rsp_pa,
-				      ioread32(&priv->regs_t->ctrl_rsp_size));
+	rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size);
+
+	iores = NULL;
+	iobase_ptr = NULL;
+	for (i = 0; resource_type(iores_array + i) == IORESOURCE_MEM; ++i) {
+		if (rsp_pa >= iores_array[i].start &&
+		    rsp_pa <= iores_array[i].end) {
+			iores = iores_array + i;
+			iobase_ptr = iobase_array + i;
+			break;
+		}
+	}
+
+	if (iores)
+		rsp_size = crb_fixup_cmd_size(dev, iores, rsp_pa, rsp_size);
 
 	if (cmd_pa != rsp_pa) {
-		priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size);
+		priv->rsp = crb_map_res(dev, iores, iobase_ptr,
+					rsp_pa, rsp_size);
 		ret = PTR_ERR_OR_ZERO(priv->rsp);
 		goto out;
 	}
@@ -619,12 +676,16 @@
 
 	/* Should the FIFO driver handle this? */
 	sm = buf->start_method;
-	if (sm == ACPI_TPM2_MEMORY_MAPPED)
-		return -ENODEV;
+	if (sm == ACPI_TPM2_MEMORY_MAPPED) {
+		rc = -ENODEV;
+		goto out;
+	}
 
 	priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	if (!priv) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
 		if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
@@ -632,7 +693,8 @@
 				FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
 				buf->header.length,
 				ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC);
-			return -EINVAL;
+			rc = -EINVAL;
+			goto out;
 		}
 		crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
 		priv->smc_func_id = crb_smc->smc_func_id;
@@ -643,17 +705,23 @@
 
 	rc = crb_map_io(device, priv, buf);
 	if (rc)
-		return rc;
+		goto out;
 
 	chip = tpmm_chip_alloc(dev, &tpm_crb);
-	if (IS_ERR(chip))
-		return PTR_ERR(chip);
+	if (IS_ERR(chip)) {
+		rc = PTR_ERR(chip);
+		goto out;
+	}
 
 	dev_set_drvdata(&chip->dev, priv);
 	chip->acpi_dev_handle = device->handle;
 	chip->flags = TPM_CHIP_FLAG_TPM2;
 
-	return tpm_chip_register(chip);
+	rc = tpm_chip_register(chip);
+
+out:
+	acpi_put_table((struct acpi_table_header *)buf);
+	return rc;
 }
 
 static int crb_acpi_remove(struct acpi_device *device)
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_ftpm_tee.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_ftpm_tee.c
@@ -32,7 +32,7 @@
 		  0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96);
 
 /**
- * ftpm_tee_tpm_op_recv - retrieve fTPM response.
+ * ftpm_tee_tpm_op_recv() - retrieve fTPM response.
  * @chip:	the tpm_chip description as specified in driver/char/tpm/tpm.h.
  * @buf:	the buffer to store data.
  * @count:	the number of bytes to read.
@@ -61,7 +61,7 @@
 }
 
 /**
- * ftpm_tee_tpm_op_send - send TPM commands through the TEE shared memory.
+ * ftpm_tee_tpm_op_send() - send TPM commands through the TEE shared memory.
  * @chip:	the tpm_chip description as specified in driver/char/tpm/tpm.h
  * @buf:	the buffer to send.
  * @len:	the number of bytes to send.
@@ -208,17 +208,16 @@
 }
 
 /**
- * ftpm_tee_probe - initialize the fTPM
+ * ftpm_tee_probe() - initialize the fTPM
  * @pdev: the platform_device description.
  *
  * Return:
  *	On success, 0. On failure, -errno.
  */
-static int ftpm_tee_probe(struct platform_device *pdev)
+static int ftpm_tee_probe(struct device *dev)
 {
 	int rc;
 	struct tpm_chip *chip;
-	struct device *dev = &pdev->dev;
 	struct ftpm_tee_private *pvt_data = NULL;
 	struct tee_ioctl_open_session_arg sess_arg;
 
@@ -255,11 +254,11 @@
 	pvt_data->session = sess_arg.session;
 
 	/* Allocate dynamic shared memory with fTPM TA */
-	pvt_data->shm = tee_shm_alloc(pvt_data->ctx,
-				      MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE,
-				      TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+	pvt_data->shm = tee_shm_alloc_kernel_buf(pvt_data->ctx,
+						 MAX_COMMAND_SIZE +
+						 MAX_RESPONSE_SIZE);
 	if (IS_ERR(pvt_data->shm)) {
-		dev_err(dev, "%s: tee_shm_alloc failed\n", __func__);
+		dev_err(dev, "%s: tee_shm_alloc_kernel_buf failed\n", __func__);
 		rc = -ENOMEM;
 		goto out_shm_alloc;
 	}
@@ -297,16 +296,23 @@
 	return rc;
 }
 
+static int ftpm_plat_tee_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	return ftpm_tee_probe(dev);
+}
+
 /**
- * ftpm_tee_remove - remove the TPM device
+ * ftpm_tee_remove() - remove the TPM device
  * @pdev: the platform_device description.
  *
  * Return:
  *	0 always.
  */
-static int ftpm_tee_remove(struct platform_device *pdev)
+static int ftpm_tee_remove(struct device *dev)
 {
-	struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
+	struct ftpm_tee_private *pvt_data = dev_get_drvdata(dev);
 
 	/* Release the chip */
 	tpm_chip_unregister(pvt_data->chip);
@@ -328,22 +334,80 @@
 	return 0;
 }
 
+static int ftpm_plat_tee_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	return ftpm_tee_remove(dev);
+}
+
+/**
+ * ftpm_tee_shutdown() - shutdown the TPM device
+ * @pdev: the platform_device description.
+ */
+static void ftpm_plat_tee_shutdown(struct platform_device *pdev)
+{
+	struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
+
+	tee_shm_free(pvt_data->shm);
+	tee_client_close_session(pvt_data->ctx, pvt_data->session);
+	tee_client_close_context(pvt_data->ctx);
+}
+
 static const struct of_device_id of_ftpm_tee_ids[] = {
 	{ .compatible = "microsoft,ftpm" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
 
-static struct platform_driver ftpm_tee_driver = {
+static struct platform_driver ftpm_tee_plat_driver = {
 	.driver = {
 		.name = "ftpm-tee",
 		.of_match_table = of_match_ptr(of_ftpm_tee_ids),
 	},
-	.probe = ftpm_tee_probe,
-	.remove = ftpm_tee_remove,
+	.shutdown = ftpm_plat_tee_shutdown,
+	.probe = ftpm_plat_tee_probe,
+	.remove = ftpm_plat_tee_remove,
+};
+
+/* UUID of the fTPM TA */
+static const struct tee_client_device_id optee_ftpm_id_table[] = {
+	{UUID_INIT(0xbc50d971, 0xd4c9, 0x42c4,
+		   0x82, 0xcb, 0x34, 0x3f, 0xb7, 0xf3, 0x78, 0x96)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(tee, optee_ftpm_id_table);
+
+static struct tee_client_driver ftpm_tee_driver = {
+	.id_table	= optee_ftpm_id_table,
+	.driver		= {
+		.name		= "optee-ftpm",
+		.bus		= &tee_bus_type,
+		.probe		= ftpm_tee_probe,
+		.remove		= ftpm_tee_remove,
+	},
 };
 
-module_platform_driver(ftpm_tee_driver);
+static int __init ftpm_mod_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&ftpm_tee_plat_driver);
+	if (rc)
+		return rc;
+
+	return driver_register(&ftpm_tee_driver.driver);
+}
+
+static void __exit ftpm_mod_exit(void)
+{
+	platform_driver_unregister(&ftpm_tee_plat_driver);
+	driver_unregister(&ftpm_tee_driver.driver);
+}
+
+module_init(ftpm_mod_init);
+module_exit(ftpm_mod_exit);
 
 MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
 MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_ibmvtpm.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_ibmvtpm.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2012 IBM Corporation
+ * Copyright (C) 2012-2020 IBM Corporation
  *
  * Author: Ashley Lai <ashleydlai@gmail.com>
  *
@@ -134,6 +134,64 @@
 }
 
 /**
+ * ibmvtpm_crq_send_init - Send a CRQ initialize message
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return:
+ *	0 on success.
+ *	Non-zero on failure.
+ */
+static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc;
+
+	rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"%s failed rc=%d\n", __func__, rc);
+
+	return rc;
+}
+
+/**
+ * tpm_ibmvtpm_resume - Resume from suspend
+ *
+ * @dev:	device struct
+ *
+ * Return: Always 0.
+ */
+static int tpm_ibmvtpm_resume(struct device *dev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+	struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
+	int rc = 0;
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_ENABLE_CRQ,
+					ibmvtpm->vdev->unit_address);
+	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	if (rc) {
+		dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = vio_enable_interrupts(ibmvtpm->vdev);
+	if (rc) {
+		dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = ibmvtpm_crq_send_init(ibmvtpm);
+	if (rc)
+		dev_err(dev, "Error send_init rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
  * tpm_ibmvtpm_send() - Send a TPM command
  * @chip:	tpm chip struct
  * @buf:	buffer contains data to send
@@ -146,6 +204,7 @@
 static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
+	bool retry = true;
 	int rc, sig;
 
 	if (!ibmvtpm->rtce_buf) {
@@ -179,18 +238,27 @@
 	 */
 	ibmvtpm->tpm_processing_cmd = true;
 
+again:
 	rc = ibmvtpm_send_crq(ibmvtpm->vdev,
 			IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND,
 			count, ibmvtpm->rtce_dma_handle);
 	if (rc != H_SUCCESS) {
+		/*
+		 * H_CLOSED can be returned after LPM resume.  Call
+		 * tpm_ibmvtpm_resume() to re-enable the CRQ then retry
+		 * ibmvtpm_send_crq() once before failing.
+		 */
+		if (rc == H_CLOSED && retry) {
+			tpm_ibmvtpm_resume(ibmvtpm->dev);
+			retry = false;
+			goto again;
+		}
 		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
-		rc = 0;
 		ibmvtpm->tpm_processing_cmd = false;
-	} else
-		rc = 0;
+	}
 
 	spin_unlock(&ibmvtpm->rtce_lock);
-	return rc;
+	return 0;
 }
 
 static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
@@ -269,26 +337,6 @@
 }
 
 /**
- * ibmvtpm_crq_send_init - Send a CRQ initialize message
- * @ibmvtpm:	vtpm device struct
- *
- * Return:
- *	0 on success.
- *	Non-zero on failure.
- */
-static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
-{
-	int rc;
-
-	rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD);
-	if (rc != H_SUCCESS)
-		dev_err(ibmvtpm->dev,
-			"ibmvtpm_crq_send_init failed rc=%d\n", rc);
-
-	return rc;
-}
-
-/**
  * tpm_ibmvtpm_remove - ibm vtpm remove entry point
  * @vdev:	vio device struct
  *
@@ -400,44 +448,6 @@
 				  ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
 }
 
-/**
- * tpm_ibmvtpm_resume - Resume from suspend
- *
- * @dev:	device struct
- *
- * Return: Always 0.
- */
-static int tpm_ibmvtpm_resume(struct device *dev)
-{
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-	struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
-	int rc = 0;
-
-	do {
-		if (rc)
-			msleep(100);
-		rc = plpar_hcall_norets(H_ENABLE_CRQ,
-					ibmvtpm->vdev->unit_address);
-	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
-
-	if (rc) {
-		dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = vio_enable_interrupts(ibmvtpm->vdev);
-	if (rc) {
-		dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = ibmvtpm_crq_send_init(ibmvtpm);
-	if (rc)
-		dev_err(dev, "Error send_init rc=%d\n", rc);
-
-	return rc;
-}
-
 static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
 {
 	return (status == 0);
@@ -571,6 +581,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();
 	}
@@ -618,6 +629,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);
@@ -670,6 +682,14 @@
 	if (rc)
 		goto init_irq_cleanup;
 
+	if (!wait_event_timeout(ibmvtpm->crq_queue.wq,
+				ibmvtpm->rtce_buf != NULL,
+				HZ)) {
+		rc = -ENODEV;
+		dev_err(dev, "CRQ response timed out\n");
+		goto init_irq_cleanup;
+	}
+
 	return tpm_chip_register(chip);
 init_irq_cleanup:
 	do {
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_ibmvtpm.h
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_ibmvtpm.h
@@ -26,6 +26,7 @@
 	struct ibmvtpm_crq *crq_addr;
 	u32 index;
 	u32 num_entry;
+	wait_queue_head_t wq;
 };
 
 struct ibmvtpm_dev {
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_tis.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_tis.c
@@ -27,6 +27,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/kernel.h>
+#include <linux/dmi.h>
 #include "tpm.h"
 #include "tpm_tis_core.h"
 
@@ -49,8 +50,8 @@
 	return container_of(data, struct tpm_tis_tcg_phy, priv);
 }
 
-static bool interrupts = true;
-module_param(interrupts, bool, 0444);
+static int interrupts = -1;
+module_param(interrupts, int, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
 static bool itpm;
@@ -63,6 +64,44 @@
 MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
 #endif
 
+static int tpm_tis_disable_irq(const struct dmi_system_id *d)
+{
+	if (interrupts == -1) {
+		pr_notice("tpm_tis: %s detected: disabling interrupts.\n", d->ident);
+		interrupts = 0;
+	}
+
+	return 0;
+}
+
+static const struct dmi_system_id tpm_tis_dmi_table[] = {
+	{
+		.callback = tpm_tis_disable_irq,
+		.ident = "ThinkPad T490s",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T490s"),
+		},
+	},
+	{
+		.callback = tpm_tis_disable_irq,
+		.ident = "ThinkStation P360 Tiny",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P360 Tiny"),
+		},
+	},
+	{
+		.callback = tpm_tis_disable_irq,
+		.ident = "ThinkPad L490",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"),
+		},
+	},
+	{}
+};
+
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 static int has_hid(struct acpi_device *dev, const char *hid)
 {
@@ -102,6 +141,7 @@
 	const struct acpi_device_id *aid = acpi_match_device(tpm_acpi_tbl, dev);
 	struct acpi_table_tpm2 *tbl;
 	acpi_status st;
+	int ret = 0;
 
 	if (!aid || aid->driver_data != DEVICE_IS_TPM2)
 		return 0;
@@ -109,8 +149,7 @@
 	/* If the ACPI TPM2 signature is matched then a global ACPI_SIG_TPM2
 	 * table is mandatory
 	 */
-	st =
-	    acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
+	st = acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
 	if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
 		dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
 		return -EINVAL;
@@ -118,9 +157,10 @@
 
 	/* The tpm2_crb driver handles this device */
 	if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
-		return -ENODEV;
+		ret = -ENODEV;
 
-	return 0;
+	acpi_put_table((struct acpi_table_header *)tbl);
+	return ret;
 }
 #else
 static int check_acpi_tpm2(struct device *dev)
@@ -192,6 +232,8 @@
 	int irq = -1;
 	int rc;
 
+	dmi_check_system(tpm_tis_dmi_table);
+
 	rc = check_acpi_tpm2(dev);
 	if (rc)
 		return rc;
@@ -286,7 +328,7 @@
 	}
 	tpm_info.res = *res;
 
-	tpm_info.irq = platform_get_irq(pdev, 0);
+	tpm_info.irq = platform_get_irq_optional(pdev, 0);
 	if (tpm_info.irq <= 0) {
 		if (pdev != force_pdev)
 			tpm_info.irq = -1;
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_tis_core.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_tis_core.c
@@ -125,7 +125,8 @@
 	if (rc < 0)
 		return false;
 
-	if ((access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+	if ((access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID
+		       | TPM_ACCESS_REQUEST_USE)) ==
 	    (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
 		priv->locality = l;
 		return true;
@@ -134,58 +135,13 @@
 	return false;
 }
 
-static bool locality_inactive(struct tpm_chip *chip, int l)
-{
-	struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
-	int rc;
-	u8 access;
-
-	rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access);
-	if (rc < 0)
-		return false;
-
-	if ((access & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
-	    == TPM_ACCESS_VALID)
-		return true;
-
-	return false;
-}
-
 static int release_locality(struct tpm_chip *chip, int l)
 {
 	struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
-	unsigned long stop, timeout;
-	long rc;
 
 	tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
 
-	stop = jiffies + chip->timeout_a;
-
-	if (chip->flags & TPM_CHIP_FLAG_IRQ) {
-again:
-		timeout = stop - jiffies;
-		if ((long)timeout <= 0)
-			return -1;
-
-		rc = wait_event_interruptible_timeout(priv->int_queue,
-						      (locality_inactive(chip, l)),
-						      timeout);
-
-		if (rc > 0)
-			return 0;
-
-		if (rc == -ERESTARTSYS && freezing(current)) {
-			clear_thread_flag(TIF_SIGPENDING);
-			goto again;
-		}
-	} else {
-		do {
-			if (locality_inactive(chip, l))
-				return 0;
-			tpm_msleep(TPM_TIMEOUT);
-		} while (time_before(jiffies, stop));
-	}
-	return -1;
+	return 0;
 }
 
 static int request_locality(struct tpm_chip *chip, int l)
@@ -310,6 +266,7 @@
 	int size = 0;
 	int status;
 	u32 expected;
+	int rc;
 
 	if (count < TPM_HEADER_SIZE) {
 		size = -EIO;
@@ -329,8 +286,13 @@
 		goto out;
 	}
 
-	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
-			  expected - TPM_HEADER_SIZE);
+	rc = recv_data(chip, &buf[TPM_HEADER_SIZE],
+		       expected - TPM_HEADER_SIZE);
+	if (rc < 0) {
+		size = rc;
+		goto out;
+	}
+	size += rc;
 	if (size < expected) {
 		dev_err(&chip->dev, "Unable to read remainder of result\n");
 		size = -ETIME;
@@ -433,6 +395,9 @@
 	u32 intmask;
 	int rc;
 
+	if (priv->irq == 0)
+		return;
+
 	rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
 	if (rc < 0)
 		intmask = 0;
@@ -456,10 +421,17 @@
 	int rc;
 	u32 ordinal;
 	unsigned long dur;
+	unsigned int try;
 
-	rc = tpm_tis_send_data(chip, buf, len);
-	if (rc < 0)
-		return rc;
+	for (try = 0; try < TPM_RETRY; try++) {
+		rc = tpm_tis_send_data(chip, buf, len);
+		if (rc >= 0)
+			/* Data transfer done successfully */
+			break;
+		else if (rc != -EIO)
+			/* Data transfer failed, not recoverable */
+			return rc;
+	}
 
 	/* go and do it */
 	rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
@@ -654,17 +626,23 @@
 	return IRQ_HANDLED;
 }
 
-static int tpm_tis_gen_interrupt(struct tpm_chip *chip)
+static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
 {
 	const char *desc = "attempting to generate an interrupt";
 	u32 cap2;
 	cap_t cap;
+	int ret;
+
+	ret = request_locality(chip, 0);
+	if (ret < 0)
+		return;
 
 	if (chip->flags & TPM_CHIP_FLAG_TPM2)
-		return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
+		ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
 	else
-		return tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc,
-				  0);
+		ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0);
+
+	release_locality(chip, 0);
 }
 
 /* Register the IRQ and issue a command that will cause an interrupt. If an
@@ -694,42 +672,37 @@
 
 	rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq);
 	if (rc < 0)
-		return rc;
+		goto restore_irqs;
 
 	rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status);
 	if (rc < 0)
-		return rc;
+		goto restore_irqs;
 
 	/* Clear all existing */
 	rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status);
 	if (rc < 0)
-		return rc;
-
+		goto restore_irqs;
 	/* Turn on */
 	rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality),
 			     intmask | TPM_GLOBAL_INT_ENABLE);
 	if (rc < 0)
-		return rc;
+		goto restore_irqs;
 
 	priv->irq_tested = false;
 
 	/* Generate an interrupt by having the core call through to
 	 * tpm_tis_send
 	 */
-	rc = tpm_tis_gen_interrupt(chip);
-	if (rc < 0)
-		return rc;
+	tpm_tis_gen_interrupt(chip);
 
+restore_irqs:
 	/* tpm_tis_send will either confirm the interrupt is working or it
 	 * will call disable_irq which undoes all of the above.
 	 */
 	if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
-		rc = tpm_tis_write8(priv, original_int_vec,
-				TPM_INT_VECTOR(priv->locality));
-		if (rc < 0)
-			return rc;
-
-		return 1;
+		tpm_tis_write8(priv, original_int_vec,
+			       TPM_INT_VECTOR(priv->locality));
+		return -1;
 	}
 
 	return 0;
@@ -910,7 +883,15 @@
 	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;
+
+	rc = request_locality(chip, 0);
+	if (rc < 0) {
+		rc = -ENODEV;
+		goto out_err;
+	}
+
 	tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
+	release_locality(chip, 0);
 
 	rc = tpm_chip_start(chip);
 	if (rc)
@@ -970,28 +951,38 @@
 	init_waitqueue_head(&priv->read_queue);
 	init_waitqueue_head(&priv->int_queue);
 	if (irq != -1) {
-		/* Before doing irq testing issue a command to the TPM in polling mode
+		/*
+		 * Before doing irq testing 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)) {
+
+		rc = request_locality(chip, 0);
+		if (rc < 0)
+			goto out_err;
+
+		rc = tpm_get_timeouts(chip);
+
+		release_locality(chip, 0);
+
+		if (rc) {
 			dev_err(dev, "Could not get TPM timeouts and durations\n");
 			rc = -ENODEV;
 			goto out_err;
 		}
 
-		tpm_chip_start(chip);
-		chip->flags |= TPM_CHIP_FLAG_IRQ;
 		if (irq) {
 			tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
 						 irq);
-			if (!(chip->flags & TPM_CHIP_FLAG_IRQ))
+			if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
 				dev_err(&chip->dev, FW_BUG
 					"TPM interrupt not working, polling instead\n");
+
+				disable_interrupts(chip);
+			}
 		} else {
 			tpm_tis_probe_irq(chip, intmask);
 		}
-		tpm_chip_stop(chip);
 	}
 
 	rc = tpm_chip_register(chip);
@@ -1003,7 +994,7 @@
 
 	return 0;
 out_err:
-	if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL))
+	if (chip->ops->clk_enable != NULL)
 		chip->ops->clk_enable(chip, false);
 
 	tpm_tis_remove(chip);
@@ -1058,12 +1049,20 @@
 	if (ret)
 		return ret;
 
-	/* TPM 1.2 requires self-test on resume. This function actually returns
+	/*
+	 * TPM 1.2 requires self-test on resume. This function actually returns
 	 * an error code but for unknown reason it isn't handled.
 	 */
-	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+		ret = request_locality(chip, 0);
+		if (ret < 0)
+			return ret;
+
 		tpm1_do_selftest(chip);
 
+		release_locality(chip, 0);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_tis_resume);
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpm_vtpm_proxy.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -693,37 +693,21 @@
 	.fops = &vtpmx_fops,
 };
 
-static int vtpmx_init(void)
-{
-	return misc_register(&vtpmx_miscdev);
-}
-
-static void vtpmx_cleanup(void)
-{
-	misc_deregister(&vtpmx_miscdev);
-}
-
 static int __init vtpm_module_init(void)
 {
 	int rc;
 
-	rc = vtpmx_init();
-	if (rc) {
-		pr_err("couldn't create vtpmx device\n");
-		return rc;
-	}
-
 	workqueue = create_workqueue("tpm-vtpm");
 	if (!workqueue) {
 		pr_err("couldn't create workqueue\n");
-		rc = -ENOMEM;
-		goto err_vtpmx_cleanup;
+		return -ENOMEM;
 	}
 
-	return 0;
-
-err_vtpmx_cleanup:
-	vtpmx_cleanup();
+	rc = misc_register(&vtpmx_miscdev);
+	if (rc) {
+		pr_err("couldn't create vtpmx device\n");
+		destroy_workqueue(workqueue);
+	}
 
 	return rc;
 }
@@ -731,7 +715,7 @@
 static void __exit vtpm_module_exit(void)
 {
 	destroy_workqueue(workqueue);
-	vtpmx_cleanup();
+	misc_deregister(&vtpmx_miscdev);
 }
 
 module_init(vtpm_module_init);
--- linux-ein-5.4.0.orig/drivers/char/tpm/tpmrm-dev.c
+++ linux-ein-5.4.0/drivers/char/tpm/tpmrm-dev.c
@@ -21,7 +21,7 @@
 	if (priv == NULL)
 		return -ENOMEM;
 
-	rc = tpm2_init_space(&priv->space);
+	rc = tpm2_init_space(&priv->space, TPM2_SPACE_BUFFER_SIZE);
 	if (rc) {
 		kfree(priv);
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/char/ttyprintk.c
+++ linux-ein-5.4.0/drivers/char/ttyprintk.c
@@ -15,10 +15,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;
@@ -99,11 +100,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);
 }
@@ -115,13 +117,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;
 }
@@ -155,12 +158,23 @@
 	return 0;
 }
 
+/*
+ * TTY operations hangup function.
+ */
+static void tpk_hangup(struct tty_struct *tty)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	tty_port_hangup(&tpkp->port);
+}
+
 static const struct tty_operations ttyprintk_ops = {
 	.open = tpk_open,
 	.close = tpk_close,
 	.write = tpk_write,
 	.write_room = tpk_write_room,
 	.ioctl = tpk_ioctl,
+	.hangup = tpk_hangup,
 };
 
 static const struct tty_port_operations null_ops = { };
@@ -171,7 +185,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-ein-5.4.0.orig/drivers/char/virtio_console.c
+++ linux-ein-5.4.0/drivers/char/virtio_console.c
@@ -435,12 +435,12 @@
 		/*
 		 * Allocate DMA memory from ancestor. When a virtio
 		 * device is created by remoteproc, the DMA memory is
-		 * associated with the grandparent device:
-		 * vdev => rproc => platform-dev.
+		 * associated with the parent device:
+		 * virtioY => remoteprocX#vdevYbuffer.
 		 */
-		if (!vdev->dev.parent || !vdev->dev.parent->parent)
+		buf->dev = vdev->dev.parent;
+		if (!buf->dev)
 			goto free_buf;
-		buf->dev = vdev->dev.parent->parent;
 
 		/* Increase device refcnt to avoid freeing it */
 		get_device(buf->dev);
@@ -475,7 +475,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;
 	}
@@ -1714,7 +1714,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);
@@ -1961,6 +1961,13 @@
 	list_del(&portdev->list);
 	spin_unlock_irq(&pdrvdata_lock);
 
+	/* Device is going away, exit any polling for buffers */
+	virtio_break_device(vdev);
+	if (use_multiport(portdev))
+		flush_work(&portdev->control_work);
+	else
+		flush_work(&portdev->config_work);
+
 	/* Disable interrupts for vqs */
 	vdev->config->reset(vdev);
 	/* Finish up work that's lined up */
@@ -2118,6 +2125,7 @@
 	{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
 	{ 0 },
 };
+MODULE_DEVICE_TABLE(virtio, id_table);
 
 static unsigned int features[] = {
 	VIRTIO_CONSOLE_F_SIZE,
@@ -2130,6 +2138,7 @@
 #endif
 	{ 0 },
 };
+MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);
 
 static unsigned int rproc_serial_features[] = {
 };
@@ -2232,7 +2241,7 @@
 	.remove =	virtcons_remove,
 };
 
-static int __init init(void)
+static int __init virtio_console_init(void)
 {
 	int err;
 
@@ -2269,7 +2278,7 @@
 	return err;
 }
 
-static void __exit fini(void)
+static void __exit virtio_console_fini(void)
 {
 	reclaim_dma_bufs();
 
@@ -2279,9 +2288,8 @@
 	class_destroy(pdrvdata.class);
 	debugfs_remove_recursive(pdrvdata.debugfs_dir);
 }
-module_init(init);
-module_exit(fini);
+module_init(virtio_console_init);
+module_exit(virtio_console_fini);
 
-MODULE_DEVICE_TABLE(virtio, id_table);
 MODULE_DESCRIPTION("Virtio console driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/clk/Kconfig
+++ linux-ein-5.4.0/drivers/clk/Kconfig
@@ -63,7 +63,7 @@
 config COMMON_CLK_HI655X
 	tristate "Clock driver for Hi655x" if EXPERT
 	depends on (MFD_HI655X_PMIC || COMPILE_TEST)
-	depends on REGMAP
+	select REGMAP
 	default MFD_HI655X_PMIC
 	---help---
 	  This driver supports the hi655x PMIC clock. This
@@ -302,6 +302,7 @@
 config COMMON_CLK_FIXED_MMIO
 	bool "Clock driver for Memory Mapped Fixed values"
 	depends on COMMON_CLK && OF
+	depends on HAS_IOMEM
 	help
 	  Support for Memory Mapped IO Fixed clocks
 
--- linux-ein-5.4.0.orig/drivers/clk/actions/owl-s500.c
+++ linux-ein-5.4.0/drivers/clk/actions/owl-s500.c
@@ -125,8 +125,7 @@
 	{ 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 },
 	{ 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 },
 	{ 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 },
-	{ 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 },
-	{ 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 },
+	{ 24, 1, 25 },
 
 	/* bit8: /128 */
 	{ 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 },
@@ -135,14 +134,20 @@
 	{ 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 },
 	{ 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 },
 	{ 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 },
-	{ 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 },
-	{ 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 },
+	{ 280, 1, 25 * 128 },
 	{ 0, 0, 0 },
 };
 
-static struct clk_factor_table bisp_factor_table[] = {
-	{ 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 },
-	{ 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 },
+static struct clk_factor_table de_factor_table[] = {
+	{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
+	{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
+	{ 8, 1, 12 },
+	{ 0, 0, 0 },
+};
+
+static struct clk_factor_table hde_factor_table[] = {
+	{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
+	{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
 	{ 0, 0, 0 },
 };
 
@@ -156,6 +161,13 @@
 	{ 0, 0 },
 };
 
+static struct clk_div_table std12rate_div_table[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 0, 0 },
+};
+
 static struct clk_div_table i2s_div_table[] = {
 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
 	{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
@@ -183,44 +195,44 @@
 static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
 
 /* divider clocks */
-static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
+static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
 static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0);
 
 /* factor clocks */
 static OWL_FACTOR(ahb_clk, "ahb_clk", "h_clk", CMU_BUSCLK1, 2, 2, ahb_factor_table, 0, 0);
-static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0);
-static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0);
+static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 4, de_factor_table, 0, 0);
+static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 4, de_factor_table, 0, 0);
 
 /* composite clocks */
 static OWL_COMP_FACTOR(vce_clk, "vce_clk", hde_clk_mux_p,
 			OWL_MUX_HW(CMU_VCECLK, 4, 2),
 			OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0),
-			OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table),
+			OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, hde_factor_table),
 			0);
 
 static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p,
 			OWL_MUX_HW(CMU_VDECLK, 4, 2),
 			OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0),
-			OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table),
+			OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, hde_factor_table),
 			0);
 
-static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p,
+static OWL_COMP_DIV(bisp_clk, "bisp_clk", bisp_clk_mux_p,
 			OWL_MUX_HW(CMU_BISPCLK, 4, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
-			OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table),
+			OWL_DIVIDER_HW(CMU_BISPCLK, 0, 4, 0, std12rate_div_table),
 			0);
 
-static OWL_COMP_FACTOR(sensor0_clk, "sensor0_clk", sensor_clk_mux_p,
+static OWL_COMP_DIV(sensor0_clk, "sensor0_clk", sensor_clk_mux_p,
 			OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
-			OWL_FACTOR_HW(CMU_SENSORCLK, 0, 3, 0, bisp_factor_table),
-			CLK_IGNORE_UNUSED);
+			OWL_DIVIDER_HW(CMU_SENSORCLK, 0, 4, 0, std12rate_div_table),
+			0);
 
-static OWL_COMP_FACTOR(sensor1_clk, "sensor1_clk", sensor_clk_mux_p,
+static OWL_COMP_DIV(sensor1_clk, "sensor1_clk", sensor_clk_mux_p,
 			OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
-			OWL_FACTOR_HW(CMU_SENSORCLK, 8, 3, 0, bisp_factor_table),
-			CLK_IGNORE_UNUSED);
+			OWL_DIVIDER_HW(CMU_SENSORCLK, 8, 4, 0, std12rate_div_table),
+			0);
 
 static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p,
 			OWL_MUX_HW(CMU_SD0CLK, 9, 1),
@@ -300,7 +312,7 @@
 static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART0CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART0CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p,
@@ -312,31 +324,31 @@
 static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART2CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART2CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART3CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART3CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART4CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART4CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART5CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART5CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p,
 			OWL_MUX_HW(CMU_UART6CLK, 16, 1),
 			OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0),
-			OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+			OWL_DIVIDER_HW(CMU_UART6CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
 			CLK_IGNORE_UNUSED);
 
 static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p,
--- linux-ein-5.4.0.orig/drivers/clk/actions/owl-s700.c
+++ linux-ein-5.4.0/drivers/clk/actions/owl-s700.c
@@ -162,6 +162,7 @@
 
 static struct clk_div_table rmii_div_table[] = {
 	{0, 4},   {1, 10},
+	{0, 0}
 };
 
 /* divider clocks */
--- linux-ein-5.4.0.orig/drivers/clk/actions/owl-s900.c
+++ linux-ein-5.4.0/drivers/clk/actions/owl-s900.c
@@ -140,7 +140,7 @@
 
 static struct clk_div_table usb3_mac_div_table[] = {
 	{ 1, 2 }, { 2, 3 }, { 3, 4 },
-	{ 0, 8 },
+	{ 0, 0 }
 };
 
 static struct clk_div_table i2s_div_table[] = {
--- linux-ein-5.4.0.orig/drivers/clk/at91/at91sam9260.c
+++ linux-ein-5.4.0/drivers/clk/at91/at91sam9260.c
@@ -348,7 +348,7 @@
 		return;
 	mainxtal_name = of_clk_get_parent_name(np, i);
 
-	regmap = syscon_node_to_regmap(np);
+	regmap = device_node_to_regmap(np);
 	if (IS_ERR(regmap))
 		return;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/at91sam9rl.c
+++ linux-ein-5.4.0/drivers/clk/at91/at91sam9rl.c
@@ -83,7 +83,7 @@
 		return;
 	mainxtal_name = of_clk_get_parent_name(np, i);
 
-	regmap = syscon_node_to_regmap(np);
+	regmap = device_node_to_regmap(np);
 	if (IS_ERR(regmap))
 		return;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/at91sam9x5.c
+++ linux-ein-5.4.0/drivers/clk/at91/at91sam9x5.c
@@ -146,7 +146,7 @@
 		return;
 	mainxtal_name = of_clk_get_parent_name(np, i);
 
-	regmap = syscon_node_to_regmap(np);
+	regmap = device_node_to_regmap(np);
 	if (IS_ERR(regmap))
 		return;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/clk-generated.c
+++ linux-ein-5.4.0/drivers/clk/at91/clk-generated.c
@@ -18,8 +18,6 @@
 
 #define GENERATED_MAX_DIV	255
 
-#define GCK_INDEX_DT_AUDIO_PLL	5
-
 struct clk_generated {
 	struct clk_hw hw;
 	struct regmap *regmap;
@@ -29,7 +27,7 @@
 	u32 gckdiv;
 	const struct clk_pcr_layout *layout;
 	u8 parent_id;
-	bool audio_pll_allowed;
+	int chg_pid;
 };
 
 #define to_clk_generated(hw) \
@@ -107,9 +105,13 @@
 		tmp_rate = parent_rate;
 	else
 		tmp_rate = parent_rate / div;
+
+	if (tmp_rate < req->min_rate || tmp_rate > req->max_rate)
+		return;
+
 	tmp_diff = abs(req->rate - tmp_rate);
 
-	if (*best_diff < 0 || *best_diff > tmp_diff) {
+	if (*best_diff < 0 || *best_diff >= tmp_diff) {
 		*best_rate = tmp_rate;
 		*best_diff = tmp_diff;
 		req->best_parent_rate = parent_rate;
@@ -129,7 +131,16 @@
 	int i;
 	u32 div;
 
-	for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
+	/* do not look for a rate that is outside of our range */
+	if (gck->range.max && req->rate > gck->range.max)
+		req->rate = gck->range.max;
+	if (gck->range.min && req->rate < gck->range.min)
+		req->rate = gck->range.min;
+
+	for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+		if (gck->chg_pid == i)
+			continue;
+
 		parent = clk_hw_get_parent_by_index(hw, i);
 		if (!parent)
 			continue;
@@ -161,10 +172,10 @@
 	 * that the only clks able to modify gck rate are those of audio IPs.
 	 */
 
-	if (!gck->audio_pll_allowed)
+	if (gck->chg_pid < 0)
 		goto end;
 
-	parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
+	parent = clk_hw_get_parent_by_index(hw, gck->chg_pid);
 	if (!parent)
 		goto end;
 
@@ -271,8 +282,8 @@
 at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
 			    const struct clk_pcr_layout *layout,
 			    const char *name, const char **parent_names,
-			    u8 num_parents, u8 id, bool pll_audio,
-			    const struct clk_range *range)
+			    u8 num_parents, u8 id,
+			    const struct clk_range *range, int chg_pid)
 {
 	struct clk_generated *gck;
 	struct clk_init_data init;
@@ -287,15 +298,16 @@
 	init.ops = &generated_ops;
 	init.parent_names = parent_names;
 	init.num_parents = num_parents;
-	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
-		CLK_SET_RATE_PARENT;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+	if (chg_pid >= 0)
+		init.flags |= CLK_SET_RATE_PARENT;
 
 	gck->id = id;
 	gck->hw.init = &init;
 	gck->regmap = regmap;
 	gck->lock = lock;
 	gck->range = *range;
-	gck->audio_pll_allowed = pll_audio;
+	gck->chg_pid = chg_pid;
 	gck->layout = layout;
 
 	clk_generated_startup(gck);
--- linux-ein-5.4.0.orig/drivers/clk/at91/clk-main.c
+++ linux-ein-5.4.0/drivers/clk/at91/clk-main.c
@@ -437,12 +437,17 @@
 		return -EINVAL;
 
 	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
-	tmp &= ~MOR_KEY_MASK;
 
 	if (index && !(tmp & AT91_PMC_MOSCSEL))
-		regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
+		tmp = AT91_PMC_MOSCSEL;
 	else if (!index && (tmp & AT91_PMC_MOSCSEL))
-		regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
+		tmp = 0;
+	else
+		return 0;
+
+	regmap_update_bits(regmap, AT91_CKGR_MOR,
+			   AT91_PMC_MOSCSEL | MOR_KEY_MASK,
+			   tmp | AT91_PMC_KEY);
 
 	while (!clk_sam9x5_main_ready(regmap))
 		cpu_relax();
--- linux-ein-5.4.0.orig/drivers/clk/at91/clk-usb.c
+++ linux-ein-5.4.0/drivers/clk/at91/clk-usb.c
@@ -75,6 +75,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;
@@ -211,7 +214,7 @@
 
 	usb->hw.init = &init;
 	usb->regmap = regmap;
-	usb->usbs_mask = SAM9X5_USBS_MASK;
+	usb->usbs_mask = usbs_mask;
 
 	hw = &usb->hw;
 	ret = clk_hw_register(NULL, &usb->hw);
--- linux-ein-5.4.0.orig/drivers/clk/at91/dt-compat.c
+++ linux-ein-5.4.0/drivers/clk/at91/dt-compat.c
@@ -22,6 +22,8 @@
 
 #define SYSTEM_MAX_ID		31
 
+#define GCK_INDEX_DT_AUDIO_PLL	5
+
 #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
 static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
 {
@@ -135,7 +137,7 @@
 		return;
 
 	for_each_child_of_node(np, gcknp) {
-		bool pll_audio = false;
+		int chg_pid = INT_MIN;
 
 		if (of_property_read_u32(gcknp, "reg", &id))
 			continue;
@@ -152,12 +154,12 @@
 		if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
 		    (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
 		     id == GCK_ID_CLASSD))
-			pll_audio = true;
+			chg_pid = GCK_INDEX_DT_AUDIO_PLL;
 
 		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
 						 &dt_pcr_layout, name,
 						 parent_names, num_parents,
-						 id, pll_audio, &range);
+						 id, &range, chg_pid);
 		if (IS_ERR(hw))
 			continue;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/pmc.c
+++ linux-ein-5.4.0/drivers/clk/at91/pmc.c
@@ -275,7 +275,12 @@
 
 	np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids);
 
-	pmcreg = syscon_node_to_regmap(np);
+	if (!of_device_is_available(np)) {
+		of_node_put(np);
+		return -ENODEV;
+	}
+
+	pmcreg = device_node_to_regmap(np);
 	if (IS_ERR(pmcreg))
 		return PTR_ERR(pmcreg);
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/pmc.h
+++ linux-ein-5.4.0/drivers/clk/at91/pmc.h
@@ -118,8 +118,8 @@
 at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
 			    const struct clk_pcr_layout *layout,
 			    const char *name, const char **parent_names,
-			    u8 num_parents, u8 id, bool pll_audio,
-			    const struct clk_range *range);
+			    u8 num_parents, u8 id,
+			    const struct clk_range *range, int chg_pid);
 
 struct clk_hw * __init
 at91_clk_register_h32mx(struct regmap *regmap, const char *name,
--- linux-ein-5.4.0.orig/drivers/clk/at91/sam9x60.c
+++ linux-ein-5.4.0/drivers/clk/at91/sam9x60.c
@@ -47,6 +47,7 @@
 	.pres_shift = 8,
 	.css_mask = 0x1f,
 	.have_slck_mck = 0,
+	.is_pres_direct = 1,
 };
 
 static const struct clk_pcr_layout sam9x60_pcr_layout = {
@@ -123,7 +124,6 @@
 	char *n;
 	u8 id;
 	struct clk_range r;
-	bool pll;
 } sam9x60_gck[] = {
 	{ .n = "flex0_gclk",  .id = 5, },
 	{ .n = "flex1_gclk",  .id = 6, },
@@ -143,11 +143,9 @@
 	{ .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, },
 	{ .n = "flex11_gclk", .id = 32, },
 	{ .n = "flex12_gclk", .id = 33, },
-	{ .n = "i2s_gclk",    .id = 34, .r = { .min = 0, .max = 105000000 },
-		.pll = true, },
+	{ .n = "i2s_gclk",    .id = 34, .r = { .min = 0, .max = 105000000 }, },
 	{ .n = "pit64b_gclk", .id = 37, },
-	{ .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 },
-		.pll = true, },
+	{ .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, },
 	{ .n = "tcb1_gclk",   .id = 45, },
 	{ .n = "dbgu_gclk",   .id = 47, },
 };
@@ -161,7 +159,6 @@
 	struct regmap *regmap;
 	struct clk_hw *hw;
 	int i;
-	bool bypass;
 
 	i = of_property_match_string(np, "clock-names", "td_slck");
 	if (i < 0)
@@ -196,10 +193,7 @@
 	if (IS_ERR(hw))
 		goto err_free;
 
-	bypass = of_property_read_bool(np, "atmel,osc-bypass");
-
-	hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
-					bypass);
+	hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0);
 	if (IS_ERR(hw))
 		goto err_free;
 
@@ -236,9 +230,8 @@
 
 	parent_names[0] = "pllack";
 	parent_names[1] = "upllck";
-	parent_names[2] = "mainck";
-	parent_names[3] = "mainck";
-	hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4);
+	parent_names[2] = "main_osc";
+	hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
 	if (IS_ERR(hw))
 		goto err_free;
 
@@ -289,8 +282,7 @@
 						 sam9x60_gck[i].n,
 						 parent_names, 6,
 						 sam9x60_gck[i].id,
-						 sam9x60_gck[i].pll,
-						 &sam9x60_gck[i].r);
+						 &sam9x60_gck[i].r, INT_MIN);
 		if (IS_ERR(hw))
 			goto err_free;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/sama5d2.c
+++ linux-ein-5.4.0/drivers/clk/at91/sama5d2.c
@@ -115,21 +115,20 @@
 	char *n;
 	u8 id;
 	struct clk_range r;
-	bool pll;
+	int chg_pid;
 } sama5d2_gck[] = {
-	{ .n = "sdmmc0_gclk", .id = 31, },
-	{ .n = "sdmmc1_gclk", .id = 32, },
-	{ .n = "tcb0_gclk",   .id = 35, .r = { .min = 0, .max = 83000000 }, },
-	{ .n = "tcb1_gclk",   .id = 36, .r = { .min = 0, .max = 83000000 }, },
-	{ .n = "pwm_gclk",    .id = 38, .r = { .min = 0, .max = 83000000 }, },
-	{ .n = "isc_gclk",    .id = 46, },
-	{ .n = "pdmic_gclk",  .id = 48, },
-	{ .n = "i2s0_gclk",   .id = 54, .pll = true },
-	{ .n = "i2s1_gclk",   .id = 55, .pll = true },
-	{ .n = "can0_gclk",   .id = 56, .r = { .min = 0, .max = 80000000 }, },
-	{ .n = "can1_gclk",   .id = 57, .r = { .min = 0, .max = 80000000 }, },
-	{ .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 },
-	  .pll = true },
+	{ .n = "sdmmc0_gclk", .id = 31, .chg_pid = INT_MIN, },
+	{ .n = "sdmmc1_gclk", .id = 32, .chg_pid = INT_MIN, },
+	{ .n = "tcb0_gclk",   .id = 35, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+	{ .n = "tcb1_gclk",   .id = 36, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+	{ .n = "pwm_gclk",    .id = 38, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+	{ .n = "isc_gclk",    .id = 46, .chg_pid = INT_MIN, },
+	{ .n = "pdmic_gclk",  .id = 48, .chg_pid = INT_MIN, },
+	{ .n = "i2s0_gclk",   .id = 54, .chg_pid = 5, },
+	{ .n = "i2s1_gclk",   .id = 55, .chg_pid = 5, },
+	{ .n = "can0_gclk",   .id = 56, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
+	{ .n = "can1_gclk",   .id = 57, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
+	{ .n = "classd_gclk", .id = 59, .chg_pid = 5, .r = { .min = 0, .max = 100000000 }, },
 };
 
 static const struct clk_programmable_layout sama5d2_programmable_layout = {
@@ -162,7 +161,7 @@
 		return;
 	mainxtal_name = of_clk_get_parent_name(np, i);
 
-	regmap = syscon_node_to_regmap(np);
+	regmap = device_node_to_regmap(np);
 	if (IS_ERR(regmap))
 		return;
 
@@ -317,8 +316,8 @@
 						 sama5d2_gck[i].n,
 						 parent_names, 6,
 						 sama5d2_gck[i].id,
-						 sama5d2_gck[i].pll,
-						 &sama5d2_gck[i].r);
+						 &sama5d2_gck[i].r,
+						 sama5d2_gck[i].chg_pid);
 		if (IS_ERR(hw))
 			goto err_free;
 
--- linux-ein-5.4.0.orig/drivers/clk/at91/sama5d4.c
+++ linux-ein-5.4.0/drivers/clk/at91/sama5d4.c
@@ -136,7 +136,7 @@
 		return;
 	mainxtal_name = of_clk_get_parent_name(np, i);
 
-	regmap = syscon_node_to_regmap(np);
+	regmap = device_node_to_regmap(np);
 	if (IS_ERR(regmap))
 		return;
 
--- linux-ein-5.4.0.orig/drivers/clk/bcm/clk-bcm2835.c
+++ linux-ein-5.4.0/drivers/clk/bcm/clk-bcm2835.c
@@ -314,6 +314,7 @@
 	struct device *dev;
 	void __iomem *regs;
 	spinlock_t regs_lock; /* spinlock for all clocks */
+	unsigned int soc;
 
 	/*
 	 * Real names of cprman clock parents looked up through
@@ -525,6 +526,20 @@
 		A2W_PLL_CTRL_PRST_DISABLE;
 }
 
+static u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman,
+				       const struct bcm2835_pll_data *data)
+{
+	/*
+	 * On BCM2711 there isn't a pre-divisor available in the PLL feedback
+	 * loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed
+	 * for to for VCO RANGE bits.
+	 */
+	if (cprman->soc & SOC_BCM2711)
+		return 0;
+
+	return data->ana->fb_prediv_mask;
+}
+
 static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
 					     unsigned long parent_rate,
 					     u32 *ndiv, u32 *fdiv)
@@ -582,7 +597,7 @@
 	ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT;
 	pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT;
 	using_prediv = cprman_read(cprman, data->ana_reg_base + 4) &
-		data->ana->fb_prediv_mask;
+		       bcm2835_pll_get_prediv_mask(cprman, data);
 
 	if (using_prediv) {
 		ndiv *= 2;
@@ -665,6 +680,7 @@
 	struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
 	struct bcm2835_cprman *cprman = pll->cprman;
 	const struct bcm2835_pll_data *data = pll->data;
+	u32 prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data);
 	bool was_using_prediv, use_fb_prediv, do_ana_setup_first;
 	u32 ndiv, fdiv, a2w_ctl;
 	u32 ana[4];
@@ -682,7 +698,7 @@
 	for (i = 3; i >= 0; i--)
 		ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4);
 
-	was_using_prediv = ana[1] & data->ana->fb_prediv_mask;
+	was_using_prediv = ana[1] & prediv_mask;
 
 	ana[0] &= ~data->ana->mask0;
 	ana[0] |= data->ana->set0;
@@ -692,10 +708,10 @@
 	ana[3] |= data->ana->set3;
 
 	if (was_using_prediv && !use_fb_prediv) {
-		ana[1] &= ~data->ana->fb_prediv_mask;
+		ana[1] &= ~prediv_mask;
 		do_ana_setup_first = true;
 	} else if (!was_using_prediv && use_fb_prediv) {
-		ana[1] |= data->ana->fb_prediv_mask;
+		ana[1] |= prediv_mask;
 		do_ana_setup_first = false;
 	} else {
 		do_ana_setup_first = true;
@@ -916,8 +932,7 @@
 
 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
 				    unsigned long rate,
-				    unsigned long parent_rate,
-				    bool round_up)
+				    unsigned long parent_rate)
 {
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	const struct bcm2835_clock_data *data = clock->data;
@@ -929,10 +944,6 @@
 
 	rem = do_div(temp, rate);
 	div = temp;
-
-	/* Round up and mask off the unused bits */
-	if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
-		div += unused_frac_mask + 1;
 	div &= ~unused_frac_mask;
 
 	/* different clamping limits apply for a mash clock */
@@ -956,9 +967,9 @@
 	return div;
 }
 
-static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
-					    unsigned long parent_rate,
-					    u32 div)
+static unsigned long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
+						     unsigned long parent_rate,
+						     u32 div)
 {
 	const struct bcm2835_clock_data *data = clock->data;
 	u64 temp;
@@ -1063,7 +1074,7 @@
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	struct bcm2835_cprman *cprman = clock->cprman;
 	const struct bcm2835_clock_data *data = clock->data;
-	u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
+	u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
 	u32 ctl;
 
 	spin_lock(&cprman->regs_lock);
@@ -1114,7 +1125,7 @@
 
 	if (!(BIT(parent_idx) & data->set_rate_parent)) {
 		*prate = clk_hw_get_rate(parent);
-		*div = bcm2835_clock_choose_div(hw, rate, *prate, true);
+		*div = bcm2835_clock_choose_div(hw, rate, *prate);
 
 		*avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div);
 
@@ -1200,7 +1211,7 @@
 		rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate,
 							  &div, &prate,
 							  &avgrate);
-		if (rate > best_rate && rate <= req->rate) {
+		if (abs(req->rate - rate) < abs(req->rate - best_rate)) {
 			best_parent = parent;
 			best_prate = prate;
 			best_rate = rate;
@@ -1320,8 +1331,10 @@
 	pll->hw.init = &init;
 
 	ret = devm_clk_hw_register(cprman->dev, &pll->hw);
-	if (ret)
+	if (ret) {
+		kfree(pll);
 		return NULL;
+	}
 	return &pll->hw;
 }
 
@@ -1448,13 +1461,13 @@
 	return &clock->hw;
 }
 
-static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
+static struct clk_hw *bcm2835_register_gate(struct bcm2835_cprman *cprman,
 					 const struct bcm2835_gate_data *data)
 {
-	return clk_register_gate(cprman->dev, data->name, data->parent,
-				 CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
-				 cprman->regs + data->ctl_reg,
-				 CM_GATE_BIT, 0, &cprman->regs_lock);
+	return clk_hw_register_gate(cprman->dev, data->name, data->parent,
+				    CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
+				    cprman->regs + data->ctl_reg,
+				    CM_GATE_BIT, 0, &cprman->regs_lock);
 }
 
 typedef struct clk_hw *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
@@ -1743,7 +1756,7 @@
 		.load_mask = CM_PLLC_LOADPER,
 		.hold_mask = CM_PLLC_HOLDPER,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
 
 	/*
 	 * PLLD is the display PLL, used to drive DSI display panels.
@@ -2234,6 +2247,7 @@
 	platform_set_drvdata(pdev, cprman);
 
 	cprman->onecell.num = asize;
+	cprman->soc = pdata->soc;
 	hws = cprman->onecell.hws;
 
 	for (i = 0; i < asize; i++) {
--- linux-ein-5.4.0.orig/drivers/clk/bcm/clk-bcm63xx-gate.c
+++ linux-ein-5.4.0/drivers/clk/bcm/clk-bcm63xx-gate.c
@@ -155,6 +155,7 @@
 
 	for (entry = table; entry->name; entry++)
 		maxbit = max_t(u8, maxbit, entry->bit);
+	maxbit++;
 
 	hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
 			  GFP_KERNEL);
--- linux-ein-5.4.0.orig/drivers/clk/bcm/clk-iproc-pll.c
+++ linux-ein-5.4.0/drivers/clk/bcm/clk-iproc-pll.c
@@ -736,6 +736,7 @@
 	const char *parent_name;
 	struct iproc_clk *iclk_array;
 	struct clk_hw_onecell_data *clk_data;
+	const char *clk_name;
 
 	if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl))
 		return;
@@ -783,7 +784,12 @@
 	iclk = &iclk_array[0];
 	iclk->pll = pll;
 
-	init.name = node->name;
+	ret = of_property_read_string_index(node, "clock-output-names",
+					    0, &clk_name);
+	if (WARN_ON(ret))
+		goto err_pll_register;
+
+	init.name = clk_name;
 	init.ops = &iproc_pll_ops;
 	init.flags = 0;
 	parent_name = of_clk_get_parent_name(node, 0);
@@ -803,13 +809,11 @@
 		goto err_pll_register;
 
 	clk_data->hws[0] = &iclk->hw;
+	parent_name = clk_name;
 
 	/* now initialize and register all leaf clocks */
 	for (i = 1; i < num_clks; i++) {
-		const char *clk_name;
-
 		memset(&init, 0, sizeof(init));
-		parent_name = node->name;
 
 		ret = of_property_read_string_index(node, "clock-output-names",
 						    i, &clk_name);
--- linux-ein-5.4.0.orig/drivers/clk/bcm/clk-raspberrypi.c
+++ linux-ein-5.4.0/drivers/clk/bcm/clk-raspberrypi.c
@@ -113,7 +113,7 @@
 					 RPI_FIRMWARE_ARM_CLK_ID,
 					 &val);
 	if (ret)
-		return ret;
+		return 0;
 
 	return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
 }
--- linux-ein-5.4.0.orig/drivers/clk/berlin/bg2.c
+++ linux-ein-5.4.0/drivers/clk/berlin/bg2.c
@@ -500,12 +500,15 @@
 	int n, ret;
 
 	clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
-	if (!clk_data)
+	if (!clk_data) {
+		of_node_put(parent_np);
 		return;
+	}
 	clk_data->num = MAX_CLKS;
 	hws = clk_data->hws;
 
 	gbase = of_iomap(parent_np, 0);
+	of_node_put(parent_np);
 	if (!gbase)
 		return;
 
--- linux-ein-5.4.0.orig/drivers/clk/berlin/bg2q.c
+++ linux-ein-5.4.0/drivers/clk/berlin/bg2q.c
@@ -286,19 +286,23 @@
 	int n, ret;
 
 	clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
-	if (!clk_data)
+	if (!clk_data) {
+		of_node_put(parent_np);
 		return;
+	}
 	clk_data->num = MAX_CLKS;
 	hws = clk_data->hws;
 
 	gbase = of_iomap(parent_np, 0);
 	if (!gbase) {
+		of_node_put(parent_np);
 		pr_err("%pOF: Unable to map global base\n", np);
 		return;
 	}
 
 	/* BG2Q CPU PLL is not part of global registers */
 	cpupll_base = of_iomap(parent_np, 1);
+	of_node_put(parent_np);
 	if (!cpupll_base) {
 		pr_err("%pOF: Unable to map cpupll base\n", np);
 		iounmap(gbase);
--- linux-ein-5.4.0.orig/drivers/clk/clk-ast2600.c
+++ linux-ein-5.4.0/drivers/clk/clk-ast2600.c
@@ -17,7 +17,8 @@
 
 #define ASPEED_G6_NUM_CLKS		67
 
-#define ASPEED_G6_SILICON_REV		0x004
+#define ASPEED_G6_SILICON_REV		0x014
+#define CHIP_REVISION_ID			GENMASK(23, 16)
 
 #define ASPEED_G6_RESET_CTRL		0x040
 #define ASPEED_G6_RESET_CTRL2		0x050
@@ -47,6 +48,8 @@
 static struct clk_hw_onecell_data *aspeed_g6_clk_data;
 
 static void __iomem *scu_g6_base;
+/* AST2600 revision: A0, A1, A2, etc */
+static u8 soc_rev;
 
 /*
  * Clocks marked with CLK_IS_CRITICAL:
@@ -57,10 +60,10 @@
 static const struct aspeed_gate_data aspeed_g6_gates[] = {
 	/*				    clk rst  name		parent	 flags */
 	[ASPEED_CLK_GATE_MCLK]		= {  0, -1, "mclk-gate",	"mpll",	 CLK_IS_CRITICAL }, /* SDRAM */
-	[ASPEED_CLK_GATE_ECLK]		= {  1, -1, "eclk-gate",	"eclk",	 0 },	/* Video Engine */
+	[ASPEED_CLK_GATE_ECLK]		= {  1,  6, "eclk-gate",	"eclk",	 0 },	/* Video Engine */
 	[ASPEED_CLK_GATE_GCLK]		= {  2,  7, "gclk-gate",	NULL,	 0 },	/* 2D engine */
 	/* vclk parent - dclk/d1clk/hclk/mclk */
-	[ASPEED_CLK_GATE_VCLK]		= {  3,  6, "vclk-gate",	NULL,	 0 },	/* Video Capture */
+	[ASPEED_CLK_GATE_VCLK]		= {  3, -1, "vclk-gate",	NULL,	 0 },	/* Video Capture */
 	[ASPEED_CLK_GATE_BCLK]		= {  4,  8, "bclk-gate",	"bclk",	 0 }, /* PCIe/PCI */
 	/* From dpll */
 	[ASPEED_CLK_GATE_DCLK]		= {  5, -1, "dclk-gate",	NULL,	 CLK_IS_CRITICAL }, /* DAC */
@@ -130,6 +133,18 @@
 	{ 0 }
 };
 
+static const struct clk_div_table ast2600_emmc_extclk_div_table[] = {
+	{ 0x0, 2 },
+	{ 0x1, 4 },
+	{ 0x2, 6 },
+	{ 0x3, 8 },
+	{ 0x4, 10 },
+	{ 0x5, 12 },
+	{ 0x6, 14 },
+	{ 0x7, 16 },
+	{ 0 }
+};
+
 static const struct clk_div_table ast2600_mac_div_table[] = {
 	{ 0x0, 4 },
 	{ 0x1, 4 },
@@ -178,17 +193,32 @@
 {
 	unsigned int mult, div;
 
-	if (val & BIT(20)) {
-		/* Pass through mode */
-		mult = div = 1;
+	if (soc_rev >= 2) {
+		if (val & BIT(24)) {
+			/* Pass through mode */
+			mult = div = 1;
+		} else {
+			/* F = 25Mhz * [(m + 1) / (n + 1)] / (p + 1) */
+			u32 m = val & 0x1fff;
+			u32 n = (val >> 13) & 0x3f;
+			u32 p = (val >> 19) & 0xf;
+
+			mult = (m + 1);
+			div = (n + 1) * (p + 1);
+		}
 	} else {
-		/* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */
-		u32 m = (val >> 5) & 0x3f;
-		u32 od = (val >> 4) & 0x1;
-		u32 n = val & 0xf;
-
-		mult = (2 - od) * (m + 2);
-		div = n + 1;
+		if (val & BIT(20)) {
+			/* Pass through mode */
+			mult = div = 1;
+		} else {
+			/* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */
+			u32 m = (val >> 5) & 0x3f;
+			u32 od = (val >> 4) & 0x1;
+			u32 n = val & 0xf;
+
+			mult = (2 - od) * (m + 2);
+			div = n + 1;
+		}
 	}
 	return clk_hw_register_fixed_factor(NULL, name, "clkin", 0,
 			mult, div);
@@ -389,6 +419,11 @@
 	return hw;
 }
 
+static const char *const emmc_extclk_parent_names[] = {
+	"emmc_extclk_hpll_in",
+	"mpll",
+};
+
 static const char * const vclk_parent_names[] = {
 	"dpll",
 	"d1pll",
@@ -458,16 +493,32 @@
 		return PTR_ERR(hw);
 	aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = hw;
 
-	/* EMMC ext clock divider */
-	hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "hpll", 0,
-			scu_g6_base + ASPEED_G6_CLK_SELECTION1, 15, 0,
-			&aspeed_g6_clk_lock);
+	/* EMMC ext clock */
+	hw = clk_hw_register_fixed_factor(dev, "emmc_extclk_hpll_in", "hpll",
+					  0, 1, 2);
 	if (IS_ERR(hw))
 		return PTR_ERR(hw);
-	hw = clk_hw_register_divider_table(dev, "emmc_extclk", "emmc_extclk_gate", 0,
-			scu_g6_base + ASPEED_G6_CLK_SELECTION1, 12, 3, 0,
-			ast2600_div_table,
-			&aspeed_g6_clk_lock);
+
+	hw = clk_hw_register_mux(dev, "emmc_extclk_mux",
+				 emmc_extclk_parent_names,
+				 ARRAY_SIZE(emmc_extclk_parent_names), 0,
+				 scu_g6_base + ASPEED_G6_CLK_SELECTION1, 11, 1,
+				 0, &aspeed_g6_clk_lock);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "emmc_extclk_mux",
+				  0, scu_g6_base + ASPEED_G6_CLK_SELECTION1,
+				  15, 0, &aspeed_g6_clk_lock);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hw = clk_hw_register_divider_table(dev, "emmc_extclk",
+					   "emmc_extclk_gate", 0,
+					   scu_g6_base +
+						ASPEED_G6_CLK_SELECTION1, 12,
+					   3, 0, ast2600_emmc_extclk_div_table,
+					   &aspeed_g6_clk_lock);
 	if (IS_ERR(hw))
 		return PTR_ERR(hw);
 	aspeed_g6_clk_data->hws[ASPEED_CLK_EMMC] = hw;
@@ -528,7 +579,7 @@
 	regmap_write(map, 0x308, 0x12000); /* 3x3 = 9 */
 
 	/* P-Bus (BCLK) clock divider */
-	hw = clk_hw_register_divider_table(dev, "bclk", "hpll", 0,
+	hw = clk_hw_register_divider_table(dev, "bclk", "epll", 0,
 			scu_g6_base + ASPEED_G6_CLK_SELECTION1, 20, 3, 0,
 			ast2600_div_table,
 			&aspeed_g6_clk_lock);
@@ -599,14 +650,22 @@
 	2, 2, 3, 5,
 };
 
-static const u32 ast2600_a1_axi_ahb_div_table[] = {
-	4, 6, 2, 4,
+static const u32 ast2600_a1_axi_ahb_div0_tbl[] = {
+	3, 2, 3, 4,
+};
+
+static const u32 ast2600_a1_axi_ahb_div1_tbl[] = {
+	3, 4, 6, 8,
+};
+
+static const u32 ast2600_a1_axi_ahb200_tbl[] = {
+	3, 4, 3, 4, 2, 2, 2, 2,
 };
 
 static void __init aspeed_g6_cc(struct regmap *map)
 {
 	struct clk_hw *hw;
-	u32 val, div, chip_id, axi_div, ahb_div;
+	u32 val, div, divbits, axi_div, ahb_div;
 
 	clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000);
 
@@ -636,11 +695,21 @@
 	else
 		axi_div = 2;
 
-	regmap_read(map, ASPEED_G6_SILICON_REV, &chip_id);
-	if (chip_id & BIT(16))
-		ahb_div = ast2600_a1_axi_ahb_div_table[(val >> 11) & 0x3];
-	else
+	divbits = (val >> 11) & 0x3;
+	if (soc_rev >= 1) {
+		if (!divbits) {
+			ahb_div = ast2600_a1_axi_ahb200_tbl[(val >> 8) & 0x3];
+			if (val & BIT(16))
+				ahb_div *= 2;
+		} else {
+			if (val & BIT(16))
+				ahb_div = ast2600_a1_axi_ahb_div1_tbl[divbits];
+			else
+				ahb_div = ast2600_a1_axi_ahb_div0_tbl[divbits];
+		}
+	} else {
 		ahb_div = ast2600_a0_axi_ahb_div_table[(val >> 11) & 0x3];
+	}
 
 	hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, axi_div * ahb_div);
 	aspeed_g6_clk_data->hws[ASPEED_CLK_AHB] = hw;
@@ -672,6 +741,8 @@
 	if (!scu_g6_base)
 		return;
 
+	soc_rev = (readl(scu_g6_base + ASPEED_G6_SILICON_REV) & CHIP_REVISION_ID) >> 16;
+
 	aspeed_g6_clk_data = kzalloc(struct_size(aspeed_g6_clk_data, hws,
 				      ASPEED_G6_NUM_CLKS), GFP_KERNEL);
 	if (!aspeed_g6_clk_data)
--- linux-ein-5.4.0.orig/drivers/clk/clk-cdce925.c
+++ linux-ein-5.4.0/drivers/clk/clk-cdce925.c
@@ -705,6 +705,10 @@
 	for (i = 0; i < data->chip_info->num_plls; ++i) {
 		pll_clk_name[i] = kasprintf(GFP_KERNEL, "%pOFn.pll%d",
 			client->dev.of_node, i);
+		if (!pll_clk_name[i]) {
+			err = -ENOMEM;
+			goto error;
+		}
 		init.name = pll_clk_name[i];
 		data->pll[i].chip = data;
 		data->pll[i].hw.init = &init;
@@ -746,6 +750,10 @@
 	init.num_parents = 1;
 	init.parent_names = &parent_name; /* Mux Y1 to input */
 	init.name = kasprintf(GFP_KERNEL, "%pOFn.Y1", client->dev.of_node);
+	if (!init.name) {
+		err = -ENOMEM;
+		goto error;
+	}
 	data->clk[0].chip = data;
 	data->clk[0].hw.init = &init;
 	data->clk[0].index = 0;
@@ -764,6 +772,10 @@
 	for (i = 1; i < data->chip_info->num_outputs; ++i) {
 		init.name = kasprintf(GFP_KERNEL, "%pOFn.Y%d",
 			client->dev.of_node, i+1);
+		if (!init.name) {
+			err = -ENOMEM;
+			goto error;
+		}
 		data->clk[i].chip = data;
 		data->clk[i].hw.init = &init;
 		data->clk[i].index = i;
--- linux-ein-5.4.0.orig/drivers/clk/clk-clps711x.c
+++ linux-ein-5.4.0/drivers/clk/clk-clps711x.c
@@ -28,11 +28,13 @@
 	{ .val = 1, .div = 8, },
 	{ .val = 2, .div = 2, },
 	{ .val = 3, .div = 1, },
+	{ /* sentinel */ }
 };
 
 static const struct clk_div_table timer_div_table[] = {
 	{ .val = 0, .div = 256, },
 	{ .val = 1, .div = 1, },
+	{ /* sentinel */ }
 };
 
 struct clps711x_clk {
--- linux-ein-5.4.0.orig/drivers/clk/clk-conf.c
+++ linux-ein-5.4.0/drivers/clk/clk-conf.c
@@ -33,9 +33,12 @@
 			else
 				return rc;
 		}
-		if (clkspec.np == node && !clk_supplier)
+		if (clkspec.np == node && !clk_supplier) {
+			of_node_put(clkspec.np);
 			return 0;
+		}
 		pclk = of_clk_get_from_provider(&clkspec);
+		of_node_put(clkspec.np);
 		if (IS_ERR(pclk)) {
 			if (PTR_ERR(pclk) != -EPROBE_DEFER)
 				pr_warn("clk: couldn't get parent clock %d for %pOF\n",
@@ -48,10 +51,12 @@
 		if (rc < 0)
 			goto err;
 		if (clkspec.np == node && !clk_supplier) {
+			of_node_put(clkspec.np);
 			rc = 0;
 			goto err;
 		}
 		clk = of_clk_get_from_provider(&clkspec);
+		of_node_put(clkspec.np);
 		if (IS_ERR(clk)) {
 			if (PTR_ERR(clk) != -EPROBE_DEFER)
 				pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
@@ -93,10 +98,13 @@
 				else
 					return rc;
 			}
-			if (clkspec.np == node && !clk_supplier)
+			if (clkspec.np == node && !clk_supplier) {
+				of_node_put(clkspec.np);
 				return 0;
+			}
 
 			clk = of_clk_get_from_provider(&clkspec);
+			of_node_put(clkspec.np);
 			if (IS_ERR(clk)) {
 				if (PTR_ERR(clk) != -EPROBE_DEFER)
 					pr_warn("clk: couldn't get clock %d for %pOF\n",
--- linux-ein-5.4.0.orig/drivers/clk/clk-devres.c
+++ linux-ein-5.4.0/drivers/clk/clk-devres.c
@@ -4,42 +4,101 @@
 #include <linux/export.h>
 #include <linux/gfp.h>
 
+struct devm_clk_state {
+	struct clk *clk;
+	void (*exit)(struct clk *clk);
+};
+
 static void devm_clk_release(struct device *dev, void *res)
 {
-	clk_put(*(struct clk **)res);
+	struct devm_clk_state *state = res;
+
+	if (state->exit)
+		state->exit(state->clk);
+
+	clk_put(state->clk);
 }
 
-struct clk *devm_clk_get(struct device *dev, const char *id)
+static struct clk *__devm_clk_get(struct device *dev, const char *id,
+				  struct clk *(*get)(struct device *dev, const char *id),
+				  int (*init)(struct clk *clk),
+				  void (*exit)(struct clk *clk))
 {
-	struct clk **ptr, *clk;
+	struct devm_clk_state *state;
+	struct clk *clk;
+	int ret;
 
-	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
+	state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+	if (!state)
 		return ERR_PTR(-ENOMEM);
 
-	clk = clk_get(dev, id);
-	if (!IS_ERR(clk)) {
-		*ptr = clk;
-		devres_add(dev, ptr);
-	} else {
-		devres_free(ptr);
+	clk = get(dev, id);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		goto err_clk_get;
+	}
+
+	if (init) {
+		ret = init(clk);
+		if (ret)
+			goto err_clk_init;
 	}
 
+	state->clk = clk;
+	state->exit = exit;
+
+	devres_add(dev, state);
+
 	return clk;
+
+err_clk_init:
+
+	clk_put(clk);
+err_clk_get:
+
+	devres_free(state);
+	return ERR_PTR(ret);
+}
+
+struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get, NULL, NULL);
 }
 EXPORT_SYMBOL(devm_clk_get);
 
-struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
 {
-	struct clk *clk = devm_clk_get(dev, id);
+	return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
+}
+EXPORT_SYMBOL_GPL(devm_clk_get_prepared);
 
-	if (clk == ERR_PTR(-ENOENT))
-		return NULL;
+struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get,
+			      clk_prepare_enable, clk_disable_unprepare);
+}
+EXPORT_SYMBOL_GPL(devm_clk_get_enabled);
 
-	return clk;
+struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
 }
 EXPORT_SYMBOL(devm_clk_get_optional);
 
+struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional,
+			      clk_prepare, clk_unprepare);
+}
+EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared);
+
+struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional,
+			      clk_prepare_enable, clk_disable_unprepare);
+}
+EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
+
 struct clk_bulk_devres {
 	struct clk_bulk_data *clks;
 	int num_clks;
@@ -92,13 +151,20 @@
 }
 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
 
+static void devm_clk_bulk_release_all(struct device *dev, void *res)
+{
+	struct clk_bulk_devres *devres = res;
+
+	clk_bulk_put_all(devres->num_clks, devres->clks);
+}
+
 int __must_check devm_clk_bulk_get_all(struct device *dev,
 				       struct clk_bulk_data **clks)
 {
 	struct clk_bulk_devres *devres;
 	int ret;
 
-	devres = devres_alloc(devm_clk_bulk_release,
+	devres = devres_alloc(devm_clk_bulk_release_all,
 			      sizeof(*devres), GFP_KERNEL);
 	if (!devres)
 		return -ENOMEM;
@@ -139,18 +205,19 @@
 struct clk *devm_get_clk_from_child(struct device *dev,
 				    struct device_node *np, const char *con_id)
 {
-	struct clk **ptr, *clk;
+	struct devm_clk_state *state;
+	struct clk *clk;
 
-	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
+	state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+	if (!state)
 		return ERR_PTR(-ENOMEM);
 
 	clk = of_clk_get_by_name(np, con_id);
 	if (!IS_ERR(clk)) {
-		*ptr = clk;
-		devres_add(dev, ptr);
+		state->clk = clk;
+		devres_add(dev, state);
 	} else {
-		devres_free(ptr);
+		devres_free(state);
 	}
 
 	return clk;
--- linux-ein-5.4.0.orig/drivers/clk/clk-gate.c
+++ linux-ein-5.4.0/drivers/clk/clk-gate.c
@@ -56,7 +56,7 @@
 {
 	struct clk_gate *gate = to_clk_gate(hw);
 	int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
-	unsigned long uninitialized_var(flags);
+	unsigned long flags;
 	u32 reg;
 
 	set ^= enable;
--- linux-ein-5.4.0.orig/drivers/clk/clk-gpio.c
+++ linux-ein-5.4.0/drivers/clk/clk-gpio.c
@@ -280,7 +280,7 @@
 	else
 		clk = clk_register_gpio_gate(&pdev->dev, node->name,
 				parent_names ?  parent_names[0] : NULL, gpiod,
-				0);
+				CLK_SET_RATE_PARENT);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
 
--- linux-ein-5.4.0.orig/drivers/clk/clk-npcm7xx.c
+++ linux-ein-5.4.0/drivers/clk/clk-npcm7xx.c
@@ -647,7 +647,7 @@
 	return;
 
 npcm7xx_init_fail:
-	kfree(npcm7xx_clk_data->hws);
+	kfree(npcm7xx_clk_data);
 npcm7xx_init_np_err:
 	iounmap(clk_base);
 npcm7xx_init_error:
--- linux-ein-5.4.0.orig/drivers/clk/clk-oxnas.c
+++ linux-ein-5.4.0/drivers/clk/clk-oxnas.c
@@ -207,7 +207,7 @@
 
 static int oxnas_stdclk_probe(struct platform_device *pdev)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = pdev->dev.of_node, *parent_np;
 	const struct oxnas_stdclk_data *data;
 	const struct of_device_id *id;
 	struct regmap *regmap;
@@ -219,7 +219,9 @@
 		return -ENODEV;
 	data = id->data;
 
-	regmap = syscon_node_to_regmap(of_get_parent(np));
+	parent_np = of_get_parent(np);
+	regmap = syscon_node_to_regmap(parent_np);
+	of_node_put(parent_np);
 	if (IS_ERR(regmap)) {
 		dev_err(&pdev->dev, "failed to have parent regmap\n");
 		return PTR_ERR(regmap);
--- linux-ein-5.4.0.orig/drivers/clk/clk-s2mps11.c
+++ linux-ein-5.4.0/drivers/clk/clk-s2mps11.c
@@ -195,6 +195,7 @@
 	return ret;
 
 err_reg:
+	of_node_put(s2mps11_clks[0].clk_np);
 	while (--i >= 0)
 		clkdev_drop(s2mps11_clks[i].lookup);
 
--- linux-ein-5.4.0.orig/drivers/clk/clk-scmi.c
+++ linux-ein-5.4.0/drivers/clk/clk-scmi.c
@@ -103,6 +103,8 @@
 static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
 {
 	int ret;
+	unsigned long min_rate, max_rate;
+
 	struct clk_init_data init = {
 		.flags = CLK_GET_RATE_NOCACHE,
 		.num_parents = 0,
@@ -112,9 +114,23 @@
 
 	sclk->hw.init = &init;
 	ret = devm_clk_hw_register(dev, &sclk->hw);
-	if (!ret)
-		clk_hw_set_rate_range(&sclk->hw, sclk->info->range.min_rate,
-				      sclk->info->range.max_rate);
+	if (ret)
+		return ret;
+
+	if (sclk->info->rate_discrete) {
+		int num_rates = sclk->info->list.num_rates;
+
+		if (num_rates <= 0)
+			return -EINVAL;
+
+		min_rate = sclk->info->list.rates[0];
+		max_rate = sclk->info->list.rates[num_rates - 1];
+	} else {
+		min_rate = sclk->info->range.min_rate;
+		max_rate = sclk->info->range.max_rate;
+	}
+
+	clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
 	return ret;
 }
 
@@ -154,6 +170,7 @@
 		sclk->info = handle->clk_ops->info_get(handle, idx);
 		if (!sclk->info) {
 			dev_dbg(dev, "invalid clock info for idx %d\n", idx);
+			devm_kfree(dev, sclk);
 			continue;
 		}
 
--- linux-ein-5.4.0.orig/drivers/clk/clk-si5341.c
+++ linux-ein-5.4.0/drivers/clk/clk-si5341.c
@@ -304,6 +304,8 @@
 	{ 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
 	{ 0x0A02, 0x00 }, /* Not in datasheet */
 	{ 0x0B44, 0x0F }, /* PDIV_ENB (datasheet does not mention what it is) */
+	{ 0x0B57, 0x10 }, /* VCO_RESET_CALCODE (not described in datasheet) */
+	{ 0x0B58, 0x05 }, /* VCO_RESET_CALCODE (not described in datasheet) */
 };
 
 /* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
@@ -482,6 +484,9 @@
 			SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
 	if (err < 0)
 		return err;
+	/* Check for bogus/uninitialized settings */
+	if (!n_num || !n_den)
+		return 0;
 
 	/*
 	 * n_num and n_den are shifted left as much as possible, so to prevent
@@ -633,6 +638,15 @@
 	u32 r_divider;
 	u8 r[3];
 
+	err = regmap_read(output->data->regmap,
+			SI5341_OUT_CONFIG(output), &val);
+	if (err < 0)
+		return err;
+
+	/* If SI5341_OUT_CFG_RDIV_FORCE2 is set, r_divider is 2 */
+	if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+		return parent_rate / 2;
+
 	err = regmap_bulk_read(output->data->regmap,
 			SI5341_OUT_R_REG(output), r, 3);
 	if (err < 0)
@@ -649,13 +663,6 @@
 	r_divider += 1;
 	r_divider <<= 1;
 
-	err = regmap_read(output->data->regmap,
-			SI5341_OUT_CONFIG(output), &val);
-	if (err < 0)
-		return err;
-
-	if (val & SI5341_OUT_CFG_RDIV_FORCE2)
-		r_divider = 2;
 
 	return parent_rate / r_divider;
 }
@@ -665,6 +672,9 @@
 {
 	unsigned long r;
 
+	if (!rate)
+		return 0;
+
 	r = *parent_rate >> 1;
 
 	/* If rate is an even divisor, no changes to parent required */
@@ -693,11 +703,16 @@
 		unsigned long parent_rate)
 {
 	struct clk_si5341_output *output = to_clk_si5341_output(hw);
-	/* Frequency divider is (r_div + 1) * 2 */
-	u32 r_div = (parent_rate / rate) >> 1;
+	u32 r_div;
 	int err;
 	u8 r[3];
 
+	if (!rate)
+		return -EINVAL;
+
+	/* Frequency divider is (r_div + 1) * 2 */
+	r_div = (parent_rate / rate) >> 1;
+
 	if (r_div <= 1)
 		r_div = 0;
 	else if (r_div >= BIT(24))
@@ -717,10 +732,8 @@
 	r[0] = r_div ? (r_div & 0xff) : 1;
 	r[1] = (r_div >> 8) & 0xff;
 	r[2] = (r_div >> 16) & 0xff;
-	err = regmap_bulk_write(output->data->regmap,
+	return regmap_bulk_write(output->data->regmap,
 			SI5341_OUT_R_REG(output), r, 3);
-
-	return 0;
 }
 
 static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
@@ -924,7 +937,7 @@
 	{ 0x0B25, 0x00 },
 	{ 0x0502, 0x01 },
 	{ 0x0505, 0x03 },
-	{ 0x0957, 0x1F },
+	{ 0x0957, 0x17 },
 	{ 0x0B4E, 0x1A },
 };
 
@@ -1290,7 +1303,7 @@
 			clk_prepare(data->clk[i].hw.clk);
 	}
 
-	err = of_clk_add_hw_provider(client->dev.of_node, of_clk_si5341_get,
+	err = devm_of_clk_add_hw_provider(&client->dev, of_clk_si5341_get,
 			data);
 	if (err) {
 		dev_err(&client->dev, "unable to add clk provider\n");
--- linux-ein-5.4.0.orig/drivers/clk/clk-stm32f4.c
+++ linux-ein-5.4.0/drivers/clk/clk-stm32f4.c
@@ -129,7 +129,6 @@
 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
-	{ STM32F4_RCC_APB2ENR, 26,	"ltdc",		"apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
@@ -211,7 +210,6 @@
 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
-	{ STM32F4_RCC_APB2ENR, 26,	"ltdc",		"apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f746_gates[] __initconst = {
@@ -286,7 +284,6 @@
 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
-	{ STM32F4_RCC_APB2ENR, 26,	"ltdc",		"apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
@@ -364,7 +361,6 @@
 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
-	{ STM32F4_RCC_APB2ENR, 26,	"ltdc",		"apb2_div" },
 	{ STM32F4_RCC_APB2ENR, 30,	"mdio",		"apb2_div" },
 };
 
@@ -526,7 +522,7 @@
 
 struct stm32f4_pll_post_div_data {
 	int idx;
-	u8 pll_num;
+	int pll_idx;
 	const char *name;
 	const char *parent;
 	u8 flag;
@@ -557,13 +553,13 @@
 
 #define MAX_POST_DIV 3
 static const struct stm32f4_pll_post_div_data  post_div_data[MAX_POST_DIV] = {
-	{ CLK_I2SQ_PDIV, PLL_I2S, "plli2s-q-div", "plli2s-q",
+	{ CLK_I2SQ_PDIV, PLL_VCO_I2S, "plli2s-q-div", "plli2s-q",
 		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
 
-	{ CLK_SAIQ_PDIV, PLL_SAI, "pllsai-q-div", "pllsai-q",
+	{ CLK_SAIQ_PDIV, PLL_VCO_SAI, "pllsai-q-div", "pllsai-q",
 		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
 
-	{ NO_IDX, PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
+	{ NO_IDX, PLL_VCO_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
 		STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table },
 };
 
@@ -1774,7 +1770,7 @@
 				post_div->width,
 				post_div->flag_div,
 				post_div->div_table,
-				clks[post_div->pll_num],
+				clks[post_div->pll_idx],
 				&stm32f4_clk_lock);
 
 		if (post_div->idx != NO_IDX)
--- linux-ein-5.4.0.orig/drivers/clk/clk.c
+++ linux-ein-5.4.0/drivers/clk/clk.c
@@ -114,7 +114,11 @@
 		return 0;
 
 	ret = pm_runtime_get_sync(core->dev);
-	return ret < 0 ? ret : 0;
+	if (ret < 0) {
+		pm_runtime_put_noidle(core->dev);
+		return ret;
+	}
+	return 0;
 }
 
 static void clk_pm_runtime_put(struct clk_core *core)
@@ -247,6 +251,17 @@
 		}
 	}
 
+	/*
+	 * This could be called with the enable lock held, or from atomic
+	 * context. If the parent isn't enabled already, we can't do
+	 * anything here. We can also assume this clock isn't enabled.
+	 */
+	if ((core->flags & CLK_OPS_PARENT_ENABLE) && core->parent)
+		if (!clk_core_is_enabled(core->parent)) {
+			ret = false;
+			goto done;
+		}
+
 	ret = core->ops->is_enabled(core->hw);
 done:
 	if (core->rpm_enabled)
@@ -633,6 +648,24 @@
 		*max_rate = min(*max_rate, clk_user->max_rate);
 }
 
+static bool clk_core_check_boundaries(struct clk_core *core,
+				      unsigned long min_rate,
+				      unsigned long max_rate)
+{
+	struct clk *user;
+
+	lockdep_assert_held(&prepare_lock);
+
+	if (min_rate > core->max_rate || max_rate < core->min_rate)
+		return false;
+
+	hlist_for_each_entry(user, &core->clks, clks_node)
+		if (min_rate > user->max_rate || max_rate < user->min_rate)
+			return false;
+
+	return true;
+}
+
 void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
 			   unsigned long max_rate)
 {
@@ -830,10 +863,9 @@
 	if (core->ops->unprepare)
 		core->ops->unprepare(core->hw);
 
-	clk_pm_runtime_put(core);
-
 	trace_clk_unprepare_complete(core);
 	clk_core_unprepare(core->parent);
+	clk_pm_runtime_put(core);
 }
 
 static void clk_core_unprepare_lock(struct clk_core *core)
@@ -2302,6 +2334,11 @@
 	clk->min_rate = min;
 	clk->max_rate = max;
 
+	if (!clk_core_check_boundaries(clk->core, min, max)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	rate = clk_core_get_rate_nolock(clk->core);
 	if (rate < min || rate > max) {
 		/*
@@ -2330,6 +2367,7 @@
 		}
 	}
 
+out:
 	if (clk->exclusive_count)
 		clk_core_rate_protect(clk->core);
 
@@ -2642,12 +2680,14 @@
 {
 	int ret;
 
-	clk_prepare_lock();
+	lockdep_assert_held(&prepare_lock);
+	if (!core->ops->get_phase)
+		return 0;
+
 	/* 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();
+	ret = core->ops->get_phase(core->hw);
+	if (ret >= 0)
+		core->phase = ret;
 
 	return ret;
 }
@@ -2661,10 +2701,16 @@
  */
 int clk_get_phase(struct clk *clk)
 {
+	int ret;
+
 	if (!clk)
 		return 0;
 
-	return clk_core_get_phase(clk->core);
+	clk_prepare_lock();
+	ret = clk_core_get_phase(clk->core);
+	clk_prepare_unlock();
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(clk_get_phase);
 
@@ -2878,13 +2924,21 @@
 static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
 				 int level)
 {
-	seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
+	int phase;
+
+	seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ",
 		   level * 3 + 1, "",
 		   30 - level * 3, c->name,
 		   c->enable_count, c->prepare_count, c->protect_count,
-		   clk_core_get_rate(c), clk_core_get_accuracy(c),
-		   clk_core_get_phase(c),
-		   clk_core_get_scaled_duty_cycle(c, 100000));
+		   clk_core_get_rate(c), clk_core_get_accuracy(c));
+
+	phase = clk_core_get_phase(c);
+	if (phase >= 0)
+		seq_printf(s, "%5d", phase);
+	else
+		seq_puts(s, "-----");
+
+	seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000));
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2921,6 +2975,7 @@
 
 static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
 {
+	int phase;
 	unsigned long min_rate, max_rate;
 
 	clk_core_get_boundaries(c, &min_rate, &max_rate);
@@ -2934,7 +2989,9 @@
 	seq_printf(s, "\"min_rate\": %lu,", min_rate);
 	seq_printf(s, "\"max_rate\": %lu,", max_rate);
 	seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
-	seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c));
+	phase = clk_core_get_phase(c);
+	if (phase >= 0)
+		seq_printf(s, "\"phase\": %d,", phase);
 	seq_printf(s, "\"duty_cycle\": %u",
 		   clk_core_get_scaled_duty_cycle(c, 100000));
 }
@@ -3023,6 +3080,7 @@
 				 unsigned int i, char terminator)
 {
 	struct clk_core *parent;
+	const char *name = NULL;
 
 	/*
 	 * Go through the following options to fetch a parent's name.
@@ -3037,18 +3095,20 @@
 	 * registered (yet).
 	 */
 	parent = clk_core_get_parent_by_index(core, i);
-	if (parent)
+	if (parent) {
 		seq_puts(s, parent->name);
-	else if (core->parents[i].name)
+	} else if (core->parents[i].name) {
 		seq_puts(s, core->parents[i].name);
-	else if (core->parents[i].fw_name)
+	} else if (core->parents[i].fw_name) {
 		seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
-	else if (core->parents[i].index >= 0)
-		seq_puts(s,
-			 of_clk_get_parent_name(core->of_node,
-						core->parents[i].index));
-	else
-		seq_puts(s, "(missing)");
+	} else {
+		if (core->parents[i].index >= 0)
+			name = of_clk_get_parent_name(core->of_node, core->parents[i].index);
+		if (!name)
+			name = "(missing)";
+
+		seq_puts(s, name);
+	}
 
 	seq_putc(s, terminator);
 }
@@ -3231,6 +3291,47 @@
 }
 #endif
 
+static void clk_core_reparent_orphans_nolock(void)
+{
+	struct clk_core *orphan;
+	struct hlist_node *tmp2;
+
+	/*
+	 * walk the list of orphan clocks and reparent any that newly finds a
+	 * parent.
+	 */
+	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
+		struct clk_core *parent = __clk_init_parent(orphan);
+
+		/*
+		 * We need to use __clk_set_parent_before() and _after() to
+		 * to properly migrate any prepare/enable count of the orphan
+		 * clock. This is important for CLK_IS_CRITICAL clocks, which
+		 * are enabled during init but might not have a parent yet.
+		 */
+		if (parent) {
+			/* update the clk tree topology */
+			__clk_set_parent_before(orphan, parent);
+			__clk_set_parent_after(orphan, parent, NULL);
+			__clk_recalc_accuracies(orphan);
+			__clk_recalc_rates(orphan, 0);
+
+			/*
+			 * __clk_init_parent() will set the initial req_rate to
+			 * 0 if the clock doesn't have clk_ops::recalc_rate and
+			 * is an orphan when it's registered.
+			 *
+			 * 'req_rate' is used by clk_set_rate_range() and
+			 * clk_put() to trigger a clk_set_rate() call whenever
+			 * the boundaries are modified. Let's make sure
+			 * 'req_rate' is set to something non-zero so that
+			 * clk_set_rate_range() doesn't drop the frequency.
+			 */
+			orphan->req_rate = orphan->rate;
+		}
+	}
+}
+
 /**
  * __clk_core_init - initialize the data structures in a struct clk_core
  * @core:	clk_core being initialized
@@ -3241,8 +3342,6 @@
 static int __clk_core_init(struct clk_core *core)
 {
 	int ret;
-	struct clk_core *orphan;
-	struct hlist_node *tmp2;
 	unsigned long rate;
 
 	if (!core)
@@ -3250,6 +3349,14 @@
 
 	clk_prepare_lock();
 
+	/*
+	 * Set hw->core after grabbing the prepare_lock to synchronize with
+	 * callers of clk_core_fill_parent_index() where we treat hw->core
+	 * being NULL as the clk not being registered yet. This is crucial so
+	 * that clks aren't parented until their parent is fully registered.
+	 */
+	core->hw->core = core;
+
 	ret = clk_pm_runtime_get(core);
 	if (ret)
 		goto unlock;
@@ -3294,6 +3401,21 @@
 		goto out;
 	}
 
+	/*
+	 * optional platform-specific magic
+	 *
+	 * The .init callback is not used by any of the basic clock types, but
+	 * exists for weird hardware that must perform initialization magic.
+	 * Please consider other ways of solving initialization problems before
+	 * using this callback, as its use is discouraged.
+	 *
+	 * If it exist, this callback should called before any other callback of
+	 * the clock
+	 */
+	if (core->ops->init)
+		core->ops->init(core->hw);
+
+
 	core->parent = __clk_init_parent(core);
 
 	/*
@@ -3319,17 +3441,6 @@
 	}
 
 	/*
-	 * optional platform-specific magic
-	 *
-	 * The .init callback is not used by any of the basic clock types, but
-	 * exists for weird hardware that must perform initialization magic.
-	 * Please consider other ways of solving initialization problems before
-	 * using this callback, as its use is discouraged.
-	 */
-	if (core->ops->init)
-		core->ops->init(core->hw);
-
-	/*
 	 * Set clk's accuracy.  The preferred method is to use
 	 * .recalc_accuracy. For simple clocks and lazy developers the default
 	 * fallback is to use the parent's accuracy.  If a clock doesn't have a
@@ -3345,14 +3456,11 @@
 		core->accuracy = 0;
 
 	/*
-	 * Set clk's phase.
+	 * Set clk's phase by clk_core_get_phase() caching the phase.
 	 * Since a phase is by definition relative to its parent, just
 	 * query the current clock phase, or just assume it's in phase.
 	 */
-	if (core->ops->get_phase)
-		core->phase = core->ops->get_phase(core->hw);
-	else
-		core->phase = 0;
+	clk_core_get_phase(core);
 
 	/*
 	 * Set clk's duty cycle.
@@ -3382,39 +3490,31 @@
 	if (core->flags & CLK_IS_CRITICAL) {
 		unsigned long flags;
 
-		clk_core_prepare(core);
+		ret = clk_core_prepare(core);
+		if (ret)
+			goto out;
 
 		flags = clk_enable_lock();
-		clk_core_enable(core);
+		ret = clk_core_enable(core);
 		clk_enable_unlock(flags);
+		if (ret) {
+			clk_core_unprepare(core);
+			goto out;
+		}
 	}
 
-	/*
-	 * walk the list of orphan clocks and reparent any that newly finds a
-	 * parent.
-	 */
-	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
-		struct clk_core *parent = __clk_init_parent(orphan);
+	clk_core_reparent_orphans_nolock();
 
-		/*
-		 * We need to use __clk_set_parent_before() and _after() to
-		 * to properly migrate any prepare/enable count of the orphan
-		 * clock. This is important for CLK_IS_CRITICAL clocks, which
-		 * are enabled during init but might not have a parent yet.
-		 */
-		if (parent) {
-			/* update the clk tree topology */
-			__clk_set_parent_before(orphan, parent);
-			__clk_set_parent_after(orphan, parent, NULL);
-			__clk_recalc_accuracies(orphan);
-			__clk_recalc_rates(orphan, 0);
-		}
-	}
 
 	kref_init(&core->ref);
 out:
 	clk_pm_runtime_put(core);
 unlock:
+	if (ret) {
+		hlist_del_init(&core->child_node);
+		core->hw->core = NULL;
+	}
+
 	clk_prepare_unlock();
 
 	if (!ret)
@@ -3659,7 +3759,6 @@
 	core->num_parents = init->num_parents;
 	core->min_rate = 0;
 	core->max_rate = ULONG_MAX;
-	hw->core = core;
 
 	ret = clk_core_populate_parent_map(core, init);
 	if (ret)
@@ -3677,7 +3776,7 @@
 		goto fail_create_clk;
 	}
 
-	clk_core_link_consumer(hw->core, hw->clk);
+	clk_core_link_consumer(core, hw->clk);
 
 	ret = __clk_core_init(core);
 	if (!ret)
@@ -3702,6 +3801,28 @@
 }
 
 /**
+ * dev_or_parent_of_node() - Get device node of @dev or @dev's parent
+ * @dev: Device to get device node of
+ *
+ * Return: device node pointer of @dev, or the device node pointer of
+ * @dev->parent if dev doesn't have a device node, or NULL if neither
+ * @dev or @dev->parent have a device node.
+ */
+static struct device_node *dev_or_parent_of_node(struct device *dev)
+{
+	struct device_node *np;
+
+	if (!dev)
+		return NULL;
+
+	np = dev_of_node(dev);
+	if (!np)
+		np = dev_of_node(dev->parent);
+
+	return np;
+}
+
+/**
  * clk_register - allocate a new clock, register it and return an opaque cookie
  * @dev: device that is registering this clock
  * @hw: link to hardware-specific clock data
@@ -3716,7 +3837,7 @@
  */
 struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 {
-	return __clk_register(dev, dev_of_node(dev), hw);
+	return __clk_register(dev, dev_or_parent_of_node(dev), hw);
 }
 EXPORT_SYMBOL_GPL(clk_register);
 
@@ -3732,7 +3853,8 @@
  */
 int clk_hw_register(struct device *dev, struct clk_hw *hw)
 {
-	return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw));
+	return PTR_ERR_OR_ZERO(__clk_register(dev, dev_or_parent_of_node(dev),
+			       hw));
 }
 EXPORT_SYMBOL_GPL(clk_hw_register);
 
@@ -3879,6 +4001,7 @@
 					__func__, clk->core->name);
 
 	kref_put(&clk->core->ref, __clk_release);
+	free_clk(clk);
 unlock:
 	clk_prepare_unlock();
 }
@@ -4087,20 +4210,19 @@
 	/* search the list of notifiers for this clk */
 	list_for_each_entry(cn, &clk_notifier_list, node)
 		if (cn->clk == clk)
-			break;
+			goto found;
 
 	/* if clk wasn't in the notifier list, allocate new clk_notifier */
-	if (cn->clk != clk) {
-		cn = kzalloc(sizeof(*cn), GFP_KERNEL);
-		if (!cn)
-			goto out;
+	cn = kzalloc(sizeof(*cn), GFP_KERNEL);
+	if (!cn)
+		goto out;
 
-		cn->clk = clk;
-		srcu_init_notifier_head(&cn->notifier_head);
+	cn->clk = clk;
+	srcu_init_notifier_head(&cn->notifier_head);
 
-		list_add(&cn->node, &clk_notifier_list);
-	}
+	list_add(&cn->node, &clk_notifier_list);
 
+found:
 	ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
 
 	clk->core->notifier_count++;
@@ -4125,32 +4247,28 @@
  */
 int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
 {
-	struct clk_notifier *cn = NULL;
-	int ret = -EINVAL;
+	struct clk_notifier *cn;
+	int ret = -ENOENT;
 
 	if (!clk || !nb)
 		return -EINVAL;
 
 	clk_prepare_lock();
 
-	list_for_each_entry(cn, &clk_notifier_list, node)
-		if (cn->clk == clk)
-			break;
-
-	if (cn->clk == clk) {
-		ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
+	list_for_each_entry(cn, &clk_notifier_list, node) {
+		if (cn->clk == clk) {
+			ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
 
-		clk->core->notifier_count--;
+			clk->core->notifier_count--;
 
-		/* XXX the notifier code should handle this better */
-		if (!cn->notifier_head.head) {
-			srcu_cleanup_notifier_head(&cn->notifier_head);
-			list_del(&cn->node);
-			kfree(cn);
+			/* XXX the notifier code should handle this better */
+			if (!cn->notifier_head.head) {
+				srcu_cleanup_notifier_head(&cn->notifier_head);
+				list_del(&cn->node);
+				kfree(cn);
+			}
+			break;
 		}
-
-	} else {
-		ret = -ENOENT;
 	}
 
 	clk_prepare_unlock();
@@ -4160,6 +4278,13 @@
 EXPORT_SYMBOL_GPL(clk_notifier_unregister);
 
 #ifdef CONFIG_OF
+static void clk_core_reparent_orphans(void)
+{
+	clk_prepare_lock();
+	clk_core_reparent_orphans_nolock();
+	clk_prepare_unlock();
+}
+
 /**
  * struct of_clk_provider - Clock provider registration structure
  * @link: Entry in global list of clock providers
@@ -4255,6 +4380,8 @@
 	mutex_unlock(&of_clk_mutex);
 	pr_debug("Added clock from %pOF\n", np);
 
+	clk_core_reparent_orphans();
+
 	ret = of_clk_set_defaults(np, true);
 	if (ret < 0)
 		of_clk_del_provider(np);
@@ -4290,6 +4417,8 @@
 	mutex_unlock(&of_clk_mutex);
 	pr_debug("Added clk_hw provider from %pOF\n", np);
 
+	clk_core_reparent_orphans();
+
 	ret = of_clk_set_defaults(np, true);
 	if (ret < 0)
 		of_clk_del_provider(np);
--- linux-ein-5.4.0.orig/drivers/clk/davinci/pll.c
+++ linux-ein-5.4.0/drivers/clk/davinci/pll.c
@@ -491,7 +491,7 @@
 		parent_name = postdiv_name;
 	}
 
-	pllen = kzalloc(sizeof(*pllout), GFP_KERNEL);
+	pllen = kzalloc(sizeof(*pllen), GFP_KERNEL);
 	if (!pllen) {
 		ret = -ENOMEM;
 		goto err_unregister_postdiv;
--- linux-ein-5.4.0.orig/drivers/clk/hisilicon/clk-hi3620.c
+++ linux-ein-5.4.0/drivers/clk/hisilicon/clk-hi3620.c
@@ -467,8 +467,10 @@
 		return;
 
 	clk_data->clks = kcalloc(num, sizeof(*clk_data->clks), GFP_KERNEL);
-	if (!clk_data->clks)
+	if (!clk_data->clks) {
+		kfree(clk_data);
 		return;
+	}
 
 	for (i = 0; i < num; i++) {
 		struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
--- linux-ein-5.4.0.orig/drivers/clk/imx/Kconfig
+++ linux-ein-5.4.0/drivers/clk/imx/Kconfig
@@ -1,34 +1,105 @@
 # SPDX-License-Identifier: GPL-2.0
 # common clock support for NXP i.MX SoC family.
 config MXC_CLK
-	bool
-	def_bool ARCH_MXC
+	tristate "IMX clock"
+	depends on ARCH_MXC || COMPILE_TEST
 
 config MXC_CLK_SCU
-	bool
-	depends on IMX_SCU
+	tristate
+
+config CLK_IMX1
+	def_bool SOC_IMX1
+	select MXC_CLK
+
+config CLK_IMX21
+	def_bool SOC_IMX21
+	select MXC_CLK
+
+config CLK_IMX25
+	def_bool SOC_IMX25
+	select MXC_CLK
+
+config CLK_IMX27
+	def_bool SOC_IMX27
+	select MXC_CLK
+
+config CLK_IMX31
+	def_bool SOC_IMX31
+	select MXC_CLK
+
+config CLK_IMX35
+	def_bool SOC_IMX35
+	select MXC_CLK
+
+config CLK_IMX5
+	def_bool SOC_IMX5
+	select MXC_CLK
+
+config CLK_IMX6Q
+	def_bool SOC_IMX6Q
+	select MXC_CLK
+
+config CLK_IMX6SL
+	def_bool SOC_IMX6SL
+	select MXC_CLK
+
+config CLK_IMX6SLL
+	def_bool SOC_IMX6SLL
+	select MXC_CLK
+
+config CLK_IMX6SX
+	def_bool SOC_IMX6SX
+	select MXC_CLK
+
+config CLK_IMX6UL
+	def_bool SOC_IMX6UL
+	select MXC_CLK
+
+config CLK_IMX7D
+	def_bool SOC_IMX7D
+	select MXC_CLK
+
+config CLK_IMX7ULP
+	def_bool SOC_IMX7ULP
+	select MXC_CLK
+
+config CLK_VF610
+	def_bool SOC_VF610
+	select MXC_CLK
 
 config CLK_IMX8MM
-	bool "IMX8MM CCM Clock Driver"
-	depends on ARCH_MXC && ARM64
+	tristate "IMX8MM CCM Clock Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select MXC_CLK
 	help
 	    Build the driver for i.MX8MM CCM Clock Driver
 
 config CLK_IMX8MN
-	bool "IMX8MN CCM Clock Driver"
-	depends on ARCH_MXC && ARM64
+	tristate "IMX8MN CCM Clock Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select MXC_CLK
 	help
 	    Build the driver for i.MX8MN CCM Clock Driver
 
+config CLK_IMX8MP
+	tristate "IMX8MP CCM Clock Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select MXC_CLK
+	help
+	    Build the driver for i.MX8MP CCM Clock Driver
+
 config CLK_IMX8MQ
-	bool "IMX8MQ CCM Clock Driver"
-	depends on ARCH_MXC && ARM64
+	tristate "IMX8MQ CCM Clock Driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	select MXC_CLK
 	help
 	    Build the driver for i.MX8MQ CCM Clock Driver
 
 config CLK_IMX8QXP
-	bool "IMX8QXP SCU Clock"
-	depends on ARCH_MXC && IMX_SCU && ARM64
+	tristate "IMX8QXP SCU Clock"
+	depends on (ARCH_MXC && ARM64) || COMPILE_TEST
+	depends on IMX_SCU && HAVE_ARM_SMCCC
 	select MXC_CLK_SCU
+	select MXC_CLK
 	help
 	  Build the driver for IMX8QXP SCU based clocks.
--- linux-ein-5.4.0.orig/drivers/clk/imx/Makefile
+++ linux-ein-5.4.0/drivers/clk/imx/Makefile
@@ -1,47 +1,47 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_MXC_CLK) += \
-	clk.o \
-	clk-busy.o \
-	clk-composite-8m.o \
-	clk-cpu.o \
-	clk-composite-7ulp.o \
-	clk-divider-gate.o \
-	clk-fixup-div.o \
-	clk-fixup-mux.o \
-	clk-frac-pll.o \
-	clk-gate-exclusive.o \
-	clk-gate2.o \
-	clk-pfd.o \
-	clk-pfdv2.o \
-	clk-pllv1.o \
-	clk-pllv2.o \
-	clk-pllv3.o \
-	clk-pllv4.o \
-	clk-sccg-pll.o \
-	clk-pll14xx.o
-
-obj-$(CONFIG_MXC_CLK_SCU) += \
-	clk-scu.o \
-	clk-lpcg-scu.o
+mxc-clk-objs += clk.o
+mxc-clk-objs += clk-busy.o
+mxc-clk-objs += clk-composite-7ulp.o
+mxc-clk-objs += clk-composite-8m.o
+mxc-clk-objs += clk-cpu.o
+mxc-clk-objs += clk-divider-gate.o
+mxc-clk-objs += clk-fixup-div.o
+mxc-clk-objs += clk-fixup-mux.o
+mxc-clk-objs += clk-frac-pll.o
+mxc-clk-objs += clk-gate2.o
+mxc-clk-objs += clk-gate-exclusive.o
+mxc-clk-objs += clk-pfd.o
+mxc-clk-objs += clk-pfdv2.o
+mxc-clk-objs += clk-pllv1.o
+mxc-clk-objs += clk-pllv2.o
+mxc-clk-objs += clk-pllv3.o
+mxc-clk-objs += clk-pllv4.o
+mxc-clk-objs += clk-pll14xx.o
+mxc-clk-objs += clk-sscg-pll.o
+obj-$(CONFIG_MXC_CLK) += mxc-clk.o
 
 obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
 obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
+obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-audiomix.o clk-hdmimix.o clk-gate-shared.o
 obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
-obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
 
-obj-$(CONFIG_SOC_IMX1)   += clk-imx1.o
-obj-$(CONFIG_SOC_IMX21)  += clk-imx21.o
-obj-$(CONFIG_SOC_IMX25)  += clk-imx25.o
-obj-$(CONFIG_SOC_IMX27)  += clk-imx27.o
-obj-$(CONFIG_SOC_IMX31)  += clk-imx31.o
-obj-$(CONFIG_SOC_IMX35)  += clk-imx35.o
-obj-$(CONFIG_SOC_IMX5)   += clk-imx5.o
-obj-$(CONFIG_SOC_IMX6Q)  += clk-imx6q.o
-obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
-obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o
-obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
-obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
-obj-$(CONFIG_SOC_IMX7D)  += clk-imx7d.o
-obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o
-obj-$(CONFIG_SOC_VF610)  += clk-vf610.o
+obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o
+clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o
+clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
+
+obj-$(CONFIG_CLK_IMX1)   += clk-imx1.o
+obj-$(CONFIG_CLK_IMX21)  += clk-imx21.o
+obj-$(CONFIG_CLK_IMX25)  += clk-imx25.o
+obj-$(CONFIG_CLK_IMX27)  += clk-imx27.o
+obj-$(CONFIG_CLK_IMX31)  += clk-imx31.o
+obj-$(CONFIG_CLK_IMX35)  += clk-imx35.o
+obj-$(CONFIG_CLK_IMX5)   += clk-imx5.o
+obj-$(CONFIG_CLK_IMX6Q)  += clk-imx6q.o
+obj-$(CONFIG_CLK_IMX6SL) += clk-imx6sl.o
+obj-$(CONFIG_CLK_IMX6SLL) += clk-imx6sll.o
+obj-$(CONFIG_CLK_IMX6SX) += clk-imx6sx.o
+obj-$(CONFIG_CLK_IMX6UL) += clk-imx6ul.o
+obj-$(CONFIG_CLK_IMX7D)  += clk-imx7d.o
+obj-$(CONFIG_CLK_IMX7ULP) += clk-imx7ulp.o
+obj-$(CONFIG_CLK_VF610)  += clk-vf610.o
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-audiomix.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-audiomix.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <dt-bindings/clock/imx8mp-clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+static int shared_count_pdm;
+static struct clk *clks[IMX8MP_CLK_AUDIOMIX_END];
+static struct clk_onecell_data clk_data;
+static uint32_t audiomix_clk_saved_regs[14];
+static struct clk *clk_audio_root;
+
+/* descending order */
+static const struct imx_pll14xx_rate_table imx_audiomix_sai_pll_tbl[] = {
+	PLL_1443X_RATE(245760000U, 328, 4, 3, 0xae15),
+	PLL_1443X_RATE(225792000U, 226, 3, 3, 0xcac1),
+	PLL_1443X_RATE(122880000U, 328, 4, 4, 0xae15),
+	PLL_1443X_RATE(112896000U, 226,	3, 4, 0xcac1),
+	PLL_1443X_RATE(61440000U, 328, 4, 5, 0xae15),
+	PLL_1443X_RATE(56448000U, 226, 3, 5, 0xcac1),
+	PLL_1443X_RATE(49152000U, 393, 3, 6, 0x374c),
+	PLL_1443X_RATE(45158400U, 241, 2, 6, 0xd845),
+	PLL_1443X_RATE(40960000U, 109, 1, 6, 0x3a07),
+};
+
+static const struct imx_pll14xx_clk imx_audiomix_sai_pll = {
+	.type = PLL_1443X,
+	.rate_table = imx_audiomix_sai_pll_tbl,
+	.rate_count = ARRAY_SIZE(imx_audiomix_sai_pll_tbl),
+};
+
+static const char *imx_sai_mclk2_sels[] = {"sai1", "sai2", "sai3", "dummy",
+					"sai5", "sai6", "sai7", "dummy",
+					"dummy", "dummy", "dummy",
+					"dummy", "dummy", "dummy", "dummy"};
+static const char *imx_sai1_mclk1_sels[] = {"sai1", "dummy", };
+static const char *imx_sai2_mclk1_sels[] = {"sai2", "dummy", };
+static const char *imx_sai3_mclk1_sels[] = {"sai3", "dummy", };
+static const char *imx_sai5_mclk1_sels[] = {"sai5", "dummy", };
+static const char *imx_sai6_mclk1_sels[] = {"sai6", "dummy", };
+static const char *imx_sai7_mclk1_sels[] = {"sai7", "dummy", };
+static const char *imx_pdm_sels[] = {"pdm", "sai_pll_div2", "dummy", "dummy" };
+static const char *imx_sai_pll_ref_sels[] = {"osc_24m", "dummy", "dummy", "dummy", };
+static const char *imx_sai_pll_bypass_sels[] = {"sai_pll", "sai_pll_ref_sel", };
+
+static int imx_audiomix_clk_runtime_suspend(struct device *dev)
+{
+	void __iomem *base;
+
+	base = dev_get_drvdata(dev->parent);
+
+	audiomix_clk_saved_regs[0] = readl(base);
+	audiomix_clk_saved_regs[1] = readl(base + 0x4);
+
+	audiomix_clk_saved_regs[2] = readl(base + 0x300);
+	audiomix_clk_saved_regs[3] = readl(base + 0x304);
+	audiomix_clk_saved_regs[4] = readl(base + 0x308);
+	audiomix_clk_saved_regs[5] = readl(base + 0x30C);
+	audiomix_clk_saved_regs[6] = readl(base + 0x310);
+	audiomix_clk_saved_regs[7] = readl(base + 0x314);
+	audiomix_clk_saved_regs[8] = readl(base + 0x318);
+
+	audiomix_clk_saved_regs[9] = readl(base + 0x400);
+	audiomix_clk_saved_regs[10] = readl(base + 0x404);
+	audiomix_clk_saved_regs[11] = readl(base + 0x408);
+	audiomix_clk_saved_regs[12] = readl(base + 0x40C);
+	audiomix_clk_saved_regs[13] = readl(base + 0x410);
+
+	clk_disable_unprepare(clk_audio_root);
+
+	return 0;
+}
+
+static int imx_audiomix_clk_runtime_resume(struct device *dev)
+{
+	void __iomem *base;
+
+	base = dev_get_drvdata(dev->parent);
+
+	clk_prepare_enable(clk_audio_root);
+
+	/*
+	 * Ignore bit26, which are clock gate for sdma clock root.
+	 * We need to keep it on as reset state for hardware issue
+	 * that sdma3' event logic depends on sdma2's clock gate.
+	 * keep it enabled can workaround the issue.
+	 */
+	writel(audiomix_clk_saved_regs[0] | 0x4000000, base);
+	writel(audiomix_clk_saved_regs[1], base + 0x4);
+
+	writel(audiomix_clk_saved_regs[2], base + 0x300);
+	writel(audiomix_clk_saved_regs[3], base + 0x304);
+	writel(audiomix_clk_saved_regs[4], base + 0x308);
+	writel(audiomix_clk_saved_regs[5], base + 0x30C);
+	writel(audiomix_clk_saved_regs[6], base + 0x310);
+	writel(audiomix_clk_saved_regs[7], base + 0x314);
+	writel(audiomix_clk_saved_regs[8], base + 0x318);
+
+	writel(audiomix_clk_saved_regs[9], base + 0x400);
+	writel(audiomix_clk_saved_regs[10], base + 0x404);
+	writel(audiomix_clk_saved_regs[11], base + 0x408);
+	writel(audiomix_clk_saved_regs[12], base + 0x40C);
+	writel(audiomix_clk_saved_regs[13], base + 0x410);
+
+	return 0;
+}
+
+static int imx_audiomix_clk_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void __iomem *base;
+	int ret;
+
+	clk_audio_root = of_clk_get_by_name(np, "audio_root");
+	if (IS_ERR(clk_audio_root))
+		return PTR_ERR(clk_audio_root);
+
+	base = dev_get_drvdata(dev->parent);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = imx_dev_clk_mux(dev, "sai_pll_ref_sel", base + 0x400, 0, 2, imx_sai_pll_ref_sels, ARRAY_SIZE(imx_sai_pll_ref_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = imx_dev_clk_pll14xx(dev, "sai_pll", "sai_pll_ref_sel", base + 0x400, &imx_audiomix_sai_pll);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = imx_dev_clk_mux_flags(dev, "sai_pll_bypass", base + 0x400, 4, 1, imx_sai_pll_bypass_sels, ARRAY_SIZE(imx_sai_pll_bypass_sels), CLK_SET_RATE_PARENT);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = imx_dev_clk_gate(dev, "sai_pll_out", "sai_pll_bypass", base + 0x400, 13);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1_SEL] = imx_dev_clk_mux_flags(dev, "sai1_mclk1_sel", base + 0x300, 0, 1, imx_sai1_mclk1_sels, ARRAY_SIZE(imx_sai1_mclk1_sels), CLK_SET_RATE_PARENT);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai1_mclk2_sel", base + 0x300, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1_SEL] = imx_dev_clk_mux_flags(dev, "sai2_mclk1_sel", base + 0x304, 0, 1, imx_sai2_mclk1_sels, ARRAY_SIZE(imx_sai2_mclk1_sels), CLK_SET_RATE_PARENT);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai2_mclk2_sel", base + 0x304, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1_SEL] = imx_dev_clk_mux_flags(dev, "sai3_mclk1_sel", base + 0x308, 0, 1, imx_sai3_mclk1_sels, ARRAY_SIZE(imx_sai3_mclk1_sels), CLK_SET_RATE_PARENT);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai3_mclk2_sel", base + 0x308, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1_SEL] = imx_dev_clk_mux(dev, "sai5_mclk1_sel", base + 0x30C, 0, 1, imx_sai5_mclk1_sels, ARRAY_SIZE(imx_sai5_mclk1_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai5_mclk2_sel", base + 0x30C, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1_SEL] = imx_dev_clk_mux(dev, "sai6_mclk1_sel", base + 0x310, 0, 1, imx_sai6_mclk1_sels, ARRAY_SIZE(imx_sai6_mclk1_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai6_mclk2_sel", base + 0x310, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1_SEL] = imx_dev_clk_mux(dev, "sai7_mclk1_sel", base + 0x314, 0, 1, imx_sai7_mclk1_sels, ARRAY_SIZE(imx_sai7_mclk1_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2_SEL] = imx_dev_clk_mux(dev, "sai7_mclk2_sel", base + 0x314, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
+	clks[IMX8MP_CLK_AUDIOMIX_PDM_SEL]        = imx_dev_clk_mux_flags(dev, "pdm_sel", base + 0x318, 0, 2, imx_pdm_sels, ARRAY_SIZE(imx_pdm_sels), CLK_SET_RATE_PARENT);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_IPG]    = imx_dev_clk_gate(dev, "sai1_ipg_clk",   "ipg_audio_root", base, 0);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1]  = imx_dev_clk_gate(dev, "sai1_mclk1_clk", "sai1_mclk1_sel", base, 1);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2]  = imx_dev_clk_gate(dev, "sai1_mclk2_clk", "sai1_mclk2_sel", base, 2);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK3]  = imx_dev_clk_gate(dev, "sai1_mclk3_clk", "sai_pll_out", base, 3);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_IPG]    = imx_dev_clk_gate(dev, "sai2_ipg_clk",   "ipg_audio_root", base, 4);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1]  = imx_dev_clk_gate(dev, "sai2_mclk1_clk", "sai2_mclk1_sel", base, 5);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2]  = imx_dev_clk_gate(dev, "sai2_mclk2_clk", "sai2_mclk2_sel", base, 6);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK3]  = imx_dev_clk_gate(dev, "sai2_mclk3_clk", "sai_pll_out", base, 7);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_IPG]    = imx_dev_clk_gate(dev, "sai3_ipg_clk",   "ipg_audio_root", base, 8);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1]  = imx_dev_clk_gate(dev, "sai3_mclk1_clk", "sai3_mclk1_sel", base, 9);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2]  = imx_dev_clk_gate(dev, "sai3_mclk2_clk", "sai3_mclk2_sel", base, 10);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK3]  = imx_dev_clk_gate(dev, "sai3_mclk3_clk", "sai_pll_out", base, 11);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_IPG]    = imx_dev_clk_gate(dev, "sai5_ipg_clk",   "ipg_audio_root", base, 12);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1]  = imx_dev_clk_gate(dev, "sai5_mclk1_clk", "sai5_mclk1_sel", base, 13);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2]  = imx_dev_clk_gate(dev, "sai5_mclk2_clk", "sai5_mclk2_sel", base, 14);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK3]  = imx_dev_clk_gate(dev, "sai5_mclk3_clk", "sai_pll_out", base, 15);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_IPG]    = imx_dev_clk_gate(dev, "sai6_ipg_clk",   "ipg_audio_root", base, 16);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1]  = imx_dev_clk_gate(dev, "sai6_mclk1_clk", "sai6_mclk1_sel", base, 17);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2]  = imx_dev_clk_gate(dev, "sai6_mclk2_clk", "sai6_mclk2_sel", base, 18);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK3]  = imx_dev_clk_gate(dev, "sai6_mclk3_clk", "sai_pll_out", base, 19);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_IPG]    = imx_dev_clk_gate(dev, "sai7_ipg_clk",   "ipg_audio_root", base, 20);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1]  = imx_dev_clk_gate(dev, "sai7_mclk1_clk", "sai7_mclk1_sel", base, 21);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2]  = imx_dev_clk_gate(dev, "sai7_mclk2_clk", "sai7_mclk2_sel", base, 22);
+	clks[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK3]  = imx_dev_clk_gate(dev, "sai7_mclk3_clk", "sai_pll_out", base, 23);
+	clks[IMX8MP_CLK_AUDIOMIX_ASRC_IPG]    = imx_dev_clk_gate(dev, "asrc_ipg_clk",   "ipg_audio_root", base, 24);
+	clks[IMX8MP_CLK_AUDIOMIX_PDM_IPG]     = imx_dev_clk_gate_shared(dev, "pdm_ipg_clk", "ipg_audio_root", base, 25, &shared_count_pdm);
+	clks[IMX8MP_CLK_AUDIOMIX_PDM_ROOT]    = imx_dev_clk_gate_shared(dev, "pdm_root_clk", "pdm_sel", base, 25, &shared_count_pdm);
+
+	clks[IMX8MP_CLK_AUDIOMIX_SDMA3_ROOT]  = imx_dev_clk_gate(dev, "sdma3_root_clk", "ipg_audio_root", base, 27);
+	clks[IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT]  = imx_dev_clk_gate(dev, "spba2_root_clk", "ipg_audio_root", base, 28);
+	clks[IMX8MP_CLK_AUDIOMIX_DSP_ROOT]    = imx_dev_clk_gate(dev, "dsp_root_clk",   "ipg_audio_root", base, 29);
+	clks[IMX8MP_CLK_AUDIOMIX_DSPDBG_ROOT] = imx_dev_clk_gate(dev, "dsp_dbg_clk",    "ipg_audio_root", base, 30);
+	clks[IMX8MP_CLK_AUDIOMIX_EARC_IPG]    = imx_dev_clk_gate(dev, "earc_ipg_clk",   "ipg_audio_root", base, 31);
+
+	clks[IMX8MP_CLK_AUDIOMIX_OCRAMA_IPG]  = imx_dev_clk_gate(dev, "ocram_a_ipg_clk", "ipg_audio_root", base + 4, 0);
+	clks[IMX8MP_CLK_AUDIOMIX_AUD2HTX_IPG] = imx_dev_clk_gate(dev, "aud2htx_ipg_clk", "ipg_audio_root", base + 4, 1);
+	clks[IMX8MP_CLK_AUDIOMIX_EDMA_ROOT]   = imx_dev_clk_gate(dev, "edma_root_clk",   "ipg_audio_root", base + 4, 2);
+	clks[IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT] = imx_dev_clk_gate(dev, "aud_pll_clk",  "ipg_audio_root", base + 4, 3);
+	clks[IMX8MP_CLK_AUDIOMIX_MU2_ROOT]    = imx_dev_clk_gate(dev, "mu2_root_clk", "ipg_audio_root", base + 4, 4);
+	clks[IMX8MP_CLK_AUDIOMIX_MU3_ROOT]    = imx_dev_clk_gate(dev, "mu3_root_clk", "ipg_audio_root", base + 4, 5);
+	clks[IMX8MP_CLK_AUDIOMIX_EARC_PHY]    = imx_dev_clk_gate(dev, "earc_phy_clk", "sai_pll_out", base + 4, 6);
+
+	/* unbypass the pll */
+	clk_set_parent(clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS], clks[IMX8MP_CLK_AUDIOMIX_SAI_PLL]);
+
+	imx_check_clocks(clks, ARRAY_SIZE(clks));
+
+	clk_data.clks = clks;
+	clk_data.clk_num = ARRAY_SIZE(clks);
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (ret < 0) {
+		pr_err("failed to register clks for i.MX8MP\n");
+		return -EINVAL;
+	}
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops imx_audiomix_clk_pm_ops = {
+	SET_RUNTIME_PM_OPS(imx_audiomix_clk_runtime_suspend,
+			   imx_audiomix_clk_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id imx_audiomix_clk_of_match[] = {
+	{ .compatible = "fsl,imx8mp-audiomix-clk" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_audiomix_clk_of_match);
+
+
+static struct platform_driver imx_audiomix_clk_driver = {
+	.probe = imx_audiomix_clk_probe,
+	.driver = {
+		.name = "imx-audiomix-clk",
+		.of_match_table = of_match_ptr(imx_audiomix_clk_of_match),
+		.pm = &imx_audiomix_clk_pm_ops,
+	},
+};
+module_platform_driver(imx_audiomix_clk_driver);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-busy.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-busy.c
@@ -4,6 +4,7 @@
  * Copyright 2012 Linaro Ltd.
  */
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-composite-7ulp.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-composite-7ulp.c
@@ -5,6 +5,7 @@
  *
  */
 
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -21,7 +22,7 @@
 #define PCG_PCD_WIDTH	3
 #define PCG_PCD_MASK	0x7
 
-struct clk_hw *imx7ulp_clk_composite(const char *name,
+struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
 				     const char * const *parent_names,
 				     int num_parents, bool mux_present,
 				     bool rate_present, bool gate_present,
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-composite-8m.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-composite-8m.c
@@ -5,6 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 
@@ -15,6 +16,7 @@
 #define PCG_PREDIV_MAX		8
 
 #define PCG_DIV_SHIFT		0
+#define PCG_CORE_DIV_WIDTH	3
 #define PCG_DIV_WIDTH		6
 #define PCG_DIV_MAX		64
 
@@ -91,11 +93,11 @@
 					unsigned long parent_rate)
 {
 	struct clk_divider *divider = to_clk_divider(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	int prediv_value;
 	int div_value;
 	int ret;
-	u32 val;
+	u32 orig, val;
 
 	ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
 						&prediv_value, &div_value);
@@ -104,13 +106,15 @@
 
 	spin_lock_irqsave(divider->lock, flags);
 
-	val = readl(divider->reg);
-	val &= ~((clk_div_mask(divider->width) << divider->shift) |
-			(clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
+	orig = readl(divider->reg);
+	val = orig & ~((clk_div_mask(divider->width) << divider->shift) |
+		       (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
 
 	val |= (u32)(prediv_value  - 1) << divider->shift;
 	val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;
-	writel(val, divider->reg);
+
+	if (val != orig)
+		writel(val, divider->reg);
 
 	spin_unlock_irqrestore(divider->lock, flags);
 
@@ -123,9 +127,56 @@
 	.set_rate = imx8m_clk_composite_divider_set_rate,
 };
 
-struct clk *imx8m_clk_composite_flags(const char *name,
+static u8 imx8m_clk_composite_mux_get_parent(struct clk_hw *hw)
+{
+	return clk_mux_ops.get_parent(hw);
+}
+
+static int imx8m_clk_composite_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
+	unsigned long flags = 0;
+	u32 reg;
+
+	if (mux->lock)
+		spin_lock_irqsave(mux->lock, flags);
+
+	reg = readl(mux->reg);
+	reg &= ~(mux->mask << mux->shift);
+	val = val << mux->shift;
+	reg |= val;
+	/*
+	 * write twice to make sure non-target interface
+	 * SEL_A/B point the same clk input.
+	 */
+	writel(reg, mux->reg);
+	writel(reg, mux->reg);
+
+	if (mux->lock)
+		spin_unlock_irqrestore(mux->lock, flags);
+
+	return 0;
+}
+
+static int
+imx8m_clk_composite_mux_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
+{
+	return clk_mux_ops.determine_rate(hw, req);
+}
+
+
+static const struct clk_ops imx8m_clk_composite_mux_ops = {
+	.get_parent = imx8m_clk_composite_mux_get_parent,
+	.set_parent = imx8m_clk_composite_mux_set_parent,
+	.determine_rate = imx8m_clk_composite_mux_determine_rate,
+};
+
+struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
 					const char * const *parent_names,
 					int num_parents, void __iomem *reg,
+					u32 composite_flags,
 					unsigned long flags)
 {
 	struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
@@ -133,6 +184,8 @@
 	struct clk_divider *div = NULL;
 	struct clk_gate *gate = NULL;
 	struct clk_mux *mux = NULL;
+	const struct clk_ops *divider_ops;
+	const struct clk_ops *mux_ops;
 
 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 	if (!mux)
@@ -142,6 +195,7 @@
 	mux->reg = reg;
 	mux->shift = PCG_PCS_SHIFT;
 	mux->mask = PCG_PCS_MASK;
+	mux->lock = &imx_ccm_lock;
 
 	div = kzalloc(sizeof(*div), GFP_KERNEL);
 	if (!div)
@@ -149,8 +203,24 @@
 
 	div_hw = &div->hw;
 	div->reg = reg;
-	div->shift = PCG_PREDIV_SHIFT;
-	div->width = PCG_PREDIV_WIDTH;
+	if (composite_flags & IMX_COMPOSITE_CORE) {
+		div->shift = PCG_DIV_SHIFT;
+		div->width = PCG_CORE_DIV_WIDTH;
+		divider_ops = &clk_divider_ops;
+		mux_ops = &imx8m_clk_composite_mux_ops;
+	} else if (composite_flags & IMX_COMPOSITE_BUS) {
+		div->shift = PCG_PREDIV_SHIFT;
+		div->width = PCG_PREDIV_WIDTH;
+		divider_ops = &imx8m_clk_composite_divider_ops;
+		mux_ops = &imx8m_clk_composite_mux_ops;
+	} else {
+		div->shift = PCG_PREDIV_SHIFT;
+		div->width = PCG_PREDIV_WIDTH;
+		divider_ops = &imx8m_clk_composite_divider_ops;
+		mux_ops = &clk_mux_ops;
+		flags |= CLK_SET_PARENT_GATE;
+	}
+
 	div->lock = &imx_ccm_lock;
 	div->flags = CLK_DIVIDER_ROUND_CLOSEST;
 
@@ -161,15 +231,15 @@
 	gate_hw = &gate->hw;
 	gate->reg = reg;
 	gate->bit_idx = PCG_CGC_SHIFT;
+	gate->lock = &imx_ccm_lock;
 
 	hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
-			mux_hw, &clk_mux_ops, div_hw,
-			&imx8m_clk_composite_divider_ops,
-			gate_hw, &clk_gate_ops, flags);
+			mux_hw, mux_ops, div_hw,
+			divider_ops, gate_hw, &clk_gate_ops, flags);
 	if (IS_ERR(hw))
 		goto fail;
 
-	return hw->clk;
+	return hw;
 
 fail:
 	kfree(gate);
@@ -177,3 +247,4 @@
 	kfree(mux);
 	return ERR_CAST(hw);
 }
+EXPORT_SYMBOL_GPL(imx8m_clk_hw_composite_flags);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-cpu.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-cpu.c
@@ -5,6 +5,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include "clk.h"
 
@@ -104,3 +105,4 @@
 
 	return hw;
 }
+EXPORT_SYMBOL_GPL(imx_clk_hw_cpu);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-divider-gate.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-divider-gate.c
@@ -43,7 +43,7 @@
 {
 	struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
 	struct clk_divider *div = to_clk_divider(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	unsigned int val;
 
 	spin_lock_irqsave(div->lock, flags);
@@ -75,7 +75,7 @@
 {
 	struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
 	struct clk_divider *div = to_clk_divider(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	int value;
 	u32 val;
 
@@ -104,7 +104,7 @@
 {
 	struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
 	struct clk_divider *div = to_clk_divider(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	u32 val;
 
 	if (!div_gate->cached_val) {
@@ -127,7 +127,7 @@
 {
 	struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
 	struct clk_divider *div = to_clk_divider(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	u32 val;
 
 	spin_lock_irqsave(div->lock, flags);
@@ -167,13 +167,13 @@
 };
 
 /*
- * NOTE: In order to resue the most code from the common divider,
+ * NOTE: In order to reuse the most code from the common divider,
  * we also design our divider following the way that provids an extra
  * clk_divider_flags, however it's fixed to CLK_DIVIDER_ONE_BASED by
  * default as our HW is. Besides that it supports only CLK_DIVIDER_READ_ONLY
  * flag which can be specified by user flexibly.
  */
-struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name,
 				    unsigned long flags, void __iomem *reg,
 				    u8 shift, u8 width, u8 clk_divider_flags,
 				    const struct clk_div_table *table,
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-fixup-div.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-fixup-div.c
@@ -55,7 +55,7 @@
 	struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
 	struct clk_divider *div = to_clk_divider(hw);
 	unsigned int divider, value;
-	unsigned long flags = 0;
+	unsigned long flags;
 	u32 val;
 
 	divider = parent_rate / rate;
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-fixup-mux.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-fixup-mux.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  */
 
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -42,7 +43,7 @@
 {
 	struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
 	struct clk_mux *mux = to_clk_mux(hw);
-	unsigned long flags = 0;
+	unsigned long flags;
 	u32 val;
 
 	spin_lock_irqsave(mux->lock, flags);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-frac-pll.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-frac-pll.c
@@ -10,6 +10,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
@@ -201,8 +202,9 @@
 	.set_rate	= clk_pll_set_rate,
 };
 
-struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
-			     void __iomem *base)
+struct clk_hw *imx_clk_hw_frac_pll(const char *name,
+				   const char *parent_name,
+				   void __iomem *base)
 {
 	struct clk_init_data init;
 	struct clk_frac_pll *pll;
@@ -230,5 +232,6 @@
 		return ERR_PTR(ret);
 	}
 
-	return hw->clk;
+	return hw;
 }
+EXPORT_SYMBOL_GPL(imx_clk_hw_frac_pll);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-gate-shared.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-gate-shared.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "clk.h"
+
+/**
+ * struct clk_gate_shared - i.MX specific gate clock having the gate flag
+ * shared with other gate clocks
+ */
+struct clk_gate_shared {
+	struct clk_gate gate;
+	spinlock_t	*lock;
+	unsigned int	*share_count;
+};
+
+static int clk_gate_shared_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct clk_gate_shared *shgate = container_of(gate,
+					struct clk_gate_shared, gate);
+	unsigned long flags = 0;
+	int ret = 0;
+
+	spin_lock_irqsave(shgate->lock, flags);
+
+	if (shgate->share_count && (*shgate->share_count)++ > 0)
+		goto out;
+
+	ret = clk_gate_ops.enable(hw);
+out:
+	spin_unlock_irqrestore(shgate->lock, flags);
+
+	return ret;
+}
+
+static void clk_gate_shared_disable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct clk_gate_shared *shgate = container_of(gate,
+					struct clk_gate_shared, gate);
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(shgate->lock, flags);
+
+	if (shgate->share_count) {
+		if (WARN_ON(*shgate->share_count == 0))
+			goto out;
+		else if (--(*shgate->share_count) > 0)
+			goto out;
+	}
+
+	clk_gate_ops.disable(hw);
+out:
+	spin_unlock_irqrestore(shgate->lock, flags);
+}
+
+static int clk_gate_shared_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static const struct clk_ops clk_gate_shared_ops = {
+	.enable = clk_gate_shared_enable,
+	.disable = clk_gate_shared_disable,
+	.is_enabled = clk_gate_shared_is_enabled,
+};
+
+struct clk *imx_dev_clk_gate_shared(struct device *dev, const char *name,
+				const char *parent, void __iomem *reg,
+				u8 shift, unsigned int *share_count)
+{
+	struct clk_gate_shared *shgate;
+	struct clk_gate *gate;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	shgate = kzalloc(sizeof(*shgate), GFP_KERNEL);
+	if (!shgate)
+		return ERR_PTR(-ENOMEM);
+	gate = &shgate->gate;
+
+	init.name = name;
+	init.ops = &clk_gate_shared_ops;
+	init.flags = CLK_OPS_PARENT_ENABLE;
+	init.parent_names = parent ? &parent : NULL;
+	init.num_parents = parent ? 1 : 0;
+
+	gate->reg = reg;
+	gate->bit_idx = shift;
+	gate->lock = NULL;
+	gate->hw.init = &init;
+	shgate->lock = &imx_ccm_lock;
+	shgate->share_count = share_count;
+
+	clk = clk_register(NULL, &gate->hw);
+	if (IS_ERR(clk))
+		kfree(shgate);
+
+	return clk;
+}
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-gate2.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-gate2.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/export.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -15,7 +16,7 @@
 #include "clk.h"
 
 /**
- * DOC: basic gatable clock which can gate and ungate it's ouput
+ * DOC: basic gateable clock which can gate and ungate its output
  *
  * Traits of this clock:
  * prepare - clk_(un)prepare only ensures parent is (un)prepared
@@ -29,6 +30,7 @@
 	void __iomem	*reg;
 	u8		bit_idx;
 	u8		cgr_val;
+	u8		cgr_mask;
 	u8		flags;
 	spinlock_t	*lock;
 	unsigned int	*share_count;
@@ -36,22 +38,29 @@
 
 #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
 
-static int clk_gate2_enable(struct clk_hw *hw)
+static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
 {
 	struct clk_gate2 *gate = to_clk_gate2(hw);
 	u32 reg;
-	unsigned long flags = 0;
+
+	reg = readl(gate->reg);
+	reg &= ~(gate->cgr_mask << gate->bit_idx);
+	if (enable)
+		reg |= (gate->cgr_val & gate->cgr_mask) << gate->bit_idx;
+	writel(reg, gate->reg);
+}
+
+static int clk_gate2_enable(struct clk_hw *hw)
+{
+	struct clk_gate2 *gate = to_clk_gate2(hw);
+	unsigned long flags;
 
 	spin_lock_irqsave(gate->lock, flags);
 
 	if (gate->share_count && (*gate->share_count)++ > 0)
 		goto out;
 
-	reg = readl(gate->reg);
-	reg &= ~(3 << gate->bit_idx);
-	reg |= gate->cgr_val << gate->bit_idx;
-	writel(reg, gate->reg);
-
+	clk_gate2_do_shared_clks(hw, true);
 out:
 	spin_unlock_irqrestore(gate->lock, flags);
 
@@ -61,8 +70,7 @@
 static void clk_gate2_disable(struct clk_hw *hw)
 {
 	struct clk_gate2 *gate = to_clk_gate2(hw);
-	u32 reg;
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	spin_lock_irqsave(gate->lock, flags);
 
@@ -73,19 +81,17 @@
 			goto out;
 	}
 
-	reg = readl(gate->reg);
-	reg &= ~(3 << gate->bit_idx);
-	writel(reg, gate->reg);
-
+	clk_gate2_do_shared_clks(hw, false);
 out:
 	spin_unlock_irqrestore(gate->lock, flags);
 }
 
-static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
+static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx,
+					u8 cgr_val, u8 cgr_mask)
 {
 	u32 val = readl(reg);
 
-	if (((val >> bit_idx) & 1) == 1)
+	if (((val >> bit_idx) & cgr_mask) == cgr_val)
 		return 1;
 
 	return 0;
@@ -94,23 +100,28 @@
 static int clk_gate2_is_enabled(struct clk_hw *hw)
 {
 	struct clk_gate2 *gate = to_clk_gate2(hw);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(gate->lock, flags);
 
-	return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
+	ret = clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx,
+					gate->cgr_val, gate->cgr_mask);
+
+	spin_unlock_irqrestore(gate->lock, flags);
+
+	return ret;
 }
 
 static void clk_gate2_disable_unused(struct clk_hw *hw)
 {
 	struct clk_gate2 *gate = to_clk_gate2(hw);
-	unsigned long flags = 0;
-	u32 reg;
+	unsigned long flags;
 
 	spin_lock_irqsave(gate->lock, flags);
 
-	if (!gate->share_count || *gate->share_count == 0) {
-		reg = readl(gate->reg);
-		reg &= ~(3 << gate->bit_idx);
-		writel(reg, gate->reg);
-	}
+	if (!gate->share_count || *gate->share_count == 0)
+		clk_gate2_do_shared_clks(hw, false);
 
 	spin_unlock_irqrestore(gate->lock, flags);
 }
@@ -124,7 +135,7 @@
 
 struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 bit_idx, u8 cgr_val,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
 		u8 clk_gate2_flags, spinlock_t *lock,
 		unsigned int *share_count)
 {
@@ -141,6 +152,7 @@
 	gate->reg = reg;
 	gate->bit_idx = bit_idx;
 	gate->cgr_val = cgr_val;
+	gate->cgr_mask = cgr_mask;
 	gate->flags = clk_gate2_flags;
 	gate->lock = lock;
 	gate->share_count = share_count;
@@ -154,7 +166,7 @@
 	gate->hw.init = &init;
 	hw = &gate->hw;
 
-	ret = clk_hw_register(NULL, hw);
+	ret = clk_hw_register(dev, hw);
 	if (ret) {
 		kfree(gate);
 		return ERR_PTR(ret);
@@ -162,3 +174,4 @@
 
 	return hw;
 }
+EXPORT_SYMBOL_GPL(clk_hw_register_gate2);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-hdmimix.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-hdmimix.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020 NXP.
+ */
+
+#include <dt-bindings/clock/imx8mp-clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+static struct clk *clks[IMX8MP_CLK_HDMIMIX_END];
+static struct clk_onecell_data clk_data;
+static uint32_t hdmimix_clk_saved_regs[2];
+
+static const char *imx_hdmi_phy_clks_sels[] = { "hdmi_glb_24m", "dummy",};
+static const char *imx_lcdif_clks_sels[] = { "dummy", "hdmi_glb_pix", };
+static const char *imx_hdmi_pipe_clks_sels[] = {"dummy","hdmi_glb_pix", };
+
+static int imx_hdmimix_clk_suspend(struct device *dev)
+{
+	void __iomem *base;
+
+	base = dev_get_drvdata(dev->parent);
+
+	hdmimix_clk_saved_regs[0] = readl(base + 0x40);
+	hdmimix_clk_saved_regs[1] = readl(base + 0x50);
+
+	return 0;
+}
+
+static int imx_hdmimix_clk_resume(struct device *dev)
+{
+	void __iomem *base;
+
+	base = dev_get_drvdata(dev->parent);
+
+	writel(hdmimix_clk_saved_regs[0], base + 0x40);
+	writel(hdmimix_clk_saved_regs[1], base + 0x50);
+
+	return 0;
+}
+
+static int imx_hdmimix_clk_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void __iomem *base;
+	struct clk *clk_dummy;
+	int ret;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	/* Defer until CCM driver is probed */
+	clk_dummy = of_clk_get_by_name(np, "dummy");
+	if (IS_ERR(clk_dummy))
+		return PTR_ERR(clk_dummy);
+
+	base = dev_get_drvdata(dev->parent);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_APB_CLK]	   = imx_dev_clk_gate(dev, "hdmi_glb_apb",     "hdmi_apb",      base + 0x40, 0);
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_B_CLK]      = imx_dev_clk_gate(dev, "hdmi_glb_b",       "hdmi_axi",      base + 0x40, 1);
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_REF266M_CLK]= imx_dev_clk_gate(dev, "hdmi_glb_ref_266m","hdmi_ref_266m", base + 0x40, 2);
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_XTAL24M_CLK]= imx_dev_clk_gate(dev, "hdmi_glb_24m",     "hdmi_24m",      base + 0x40, 4);
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_XTAL32K_CLK]= imx_dev_clk_gate(dev, "hdmi_glb_32k",     "osc_32k",       base + 0x40, 5);
+	clks[IMX8MP_CLK_HDMIMIX_GLOBAL_TX_PIX_CLK] = imx_dev_clk_gate(dev, "hdmi_glb_pix",     "hdmi_phy",      base + 0x40, 7);
+	clks[IMX8MP_CLK_HDMIMIX_IRQS_STEER_CLK]	   = imx_dev_clk_gate(dev, "hdmi_irq_steer",   "hdmi_glb_apb",  base + 0x40, 9);
+	clks[IMX8MP_CLK_HDMIMIX_NOC_HDMI_CLK]      = imx_dev_clk_gate(dev, "hdmi_noc",         "hdmi_glb_apb",  base + 0x40, 10);
+	clks[IMX8MP_CLK_HDMIMIX_NOC_HDCP_CLK]      = imx_dev_clk_gate(dev, "hdcp_noc",         "hdmi_glb_apb",  base + 0x40, 11);
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_APB_CLK]     = imx_dev_clk_gate(dev, "lcdif3_apb",       "hdmi_glb_apb",  base + 0x40, 16);
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_B_CLK]       = imx_dev_clk_gate(dev, "lcdif3_b",         "hdmi_glb_b",    base + 0x40, 17);
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_PDI_CLK]     = imx_dev_clk_gate(dev, "lcdif3_pdi",       "hdmi_glb_apb",  base + 0x40, 18);
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_PIX_CLK]     = imx_dev_clk_gate(dev, "lcdif3_pxl",       "hdmi_glb_pix",  base + 0x40, 19);
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_SPU_CLK]     = imx_dev_clk_gate(dev, "lcdif3_spu",       "hdmi_glb_apb",  base + 0x40, 20);
+
+	clks[IMX8MP_CLK_HDMIMIX_FDCC_REF_CLK]      = imx_dev_clk_gate(dev, "hdmi_fdcc_ref",    "hdmi_fdcc_tst", base + 0x50, 2);
+	clks[IMX8MP_CLK_HDMIMIX_HRV_MWR_APB_CLK]   = imx_dev_clk_gate(dev, "hrv_mwr_apb",       "hdmi_glb_apb", base + 0x50, 3);
+	clks[IMX8MP_CLK_HDMIMIX_HRV_MWR_B_CLK]     = imx_dev_clk_gate(dev, "hrv_mwr_b",         "hdmi_glb_axi", base + 0x50, 4);
+	clks[IMX8MP_CLK_HDMIMIX_HRV_MWR_CEA_CLK]   = imx_dev_clk_gate(dev, "hrv_mwr_cea",       "hdmi_glb_apb", base + 0x50, 5);
+	clks[IMX8MP_CLK_HDMIMIX_VSFD_CEA_CLK]      = imx_dev_clk_gate(dev, "vsfd_cea",          "hdmi_glb_apb", base + 0x50, 6);
+	clks[IMX8MP_CLK_HDMIMIX_TX_HPI_CLK]        = imx_dev_clk_gate(dev, "hdmi_tx_hpi",       "hdmi_glb_apb", base + 0x50, 13);
+	clks[IMX8MP_CLK_HDMIMIX_TX_APB_CLK]        = imx_dev_clk_gate(dev, "hdmi_tx_apb",       "hdmi_glb_apb", base + 0x50, 14);
+	clks[IMX8MP_CLK_HDMIMIX_TX_CEC_CLK]        = imx_dev_clk_gate(dev, "hdmi_cec",          "hdmi_glb_32k", base + 0x50, 15);
+	clks[IMX8MP_CLK_HDMIMIX_TX_ESM_CLK]        = imx_dev_clk_gate(dev, "hdmi_esm",     "hdmi_glb_ref_266m", base + 0x50, 16);
+	clks[IMX8MP_CLK_HDMIMIX_TX_GPA_CLK]        = imx_dev_clk_gate(dev, "hdmi_tx_gpa",       "hdmi_glb_apb", base + 0x50, 17);
+	clks[IMX8MP_CLK_HDMIMIX_TX_PIXEL_CLK]      = imx_dev_clk_gate(dev, "hdmi_tx_pix",       "hdmi_glb_pix", base + 0x50, 18);
+	clks[IMX8MP_CLK_HDMIMIX_TX_SFR_CLK]        = imx_dev_clk_gate(dev, "hdmi_tx_sfr",       "hdmi_glb_apb", base + 0x50, 19);
+	clks[IMX8MP_CLK_HDMIMIX_TX_SKP_CLK]        = imx_dev_clk_gate(dev, "hdmi_tx_skp",       "hdmi_glb_apb", base + 0x50, 20);
+	clks[IMX8MP_CLK_HDMIMIX_TX_PREP_CLK]       = imx_dev_clk_gate(dev, "hdmi_tx_prep",      "hdmi_glb_apb", base + 0x50, 21);
+	clks[IMX8MP_CLK_HDMIMIX_TX_PHY_APB_CLK]	   = imx_dev_clk_gate(dev, "hdmi_phy_apb",      "hdmi_glb_apb", base + 0x50, 22);
+	clks[IMX8MP_CLK_HDMIMIX_TX_PHY_INT_CLK]	   = imx_dev_clk_gate(dev, "hdmi_phy_int",      "hdmi_glb_apb", base + 0x50, 24);
+	clks[IMX8MP_CLK_HDMIMIX_TX_SEC_MEM_CLK]	   = imx_dev_clk_gate(dev, "hdmi_sec_mem", "hdmi_glb_ref_266m", base + 0x50, 25);
+	clks[IMX8MP_CLK_HDMIMIX_TX_TRNG_SKP_CLK]   = imx_dev_clk_gate(dev, "hdmi_trng_skp",     "hdmi_glb_apb", base + 0x50, 27);
+	clks[IMX8MP_CLK_HDMIMIX_TX_VID_LINK_PIX_CLK]= imx_dev_clk_gate(dev, "hdmi_vid_pix",     "hdmi_glb_pix", base + 0x50, 28);
+	clks[IMX8MP_CLK_HDMIMIX_TX_TRNG_APB_CLK]   = imx_dev_clk_gate(dev, "hdmi_trng_apb",     "hdmi_glb_apb", base + 0x50, 30);
+
+	clks[IMX8MP_CLK_HDMIMIX_HTXPHY_CLK_SEL]    = imx_dev_clk_mux(dev, "hdmi_phy_sel", base + 0x50, 10, 1, imx_hdmi_phy_clks_sels, ARRAY_SIZE(imx_hdmi_phy_clks_sels));
+	clks[IMX8MP_CLK_HDMIMIX_LCDIF_CLK_SEL]     = imx_dev_clk_mux(dev, "lcdif_clk_sel", base + 0x50, 11, 1, imx_lcdif_clks_sels, ARRAY_SIZE(imx_hdmi_phy_clks_sels));
+	clks[IMX8MP_CLK_HDMIMIX_TX_PIPE_CLK_SEL]   = imx_dev_clk_mux(dev, "hdmi_pipe_sel", base + 0x50, 12, 1, imx_hdmi_pipe_clks_sels, ARRAY_SIZE(imx_hdmi_pipe_clks_sels));
+
+	/* hdmi/lcdif pixel clock parent to hdmi phy */
+	clk_set_parent(clks[IMX8MP_CLK_HDMIMIX_TX_PIPE_CLK_SEL], clks[IMX8MP_CLK_HDMIMIX_GLOBAL_TX_PIX_CLK]);
+	clk_set_parent(clks[IMX8MP_CLK_HDMIMIX_LCDIF_CLK_SEL], clks[IMX8MP_CLK_HDMIMIX_GLOBAL_TX_PIX_CLK]);
+	/* hdmi ref clock from 24MHz */
+	clk_set_parent(clks[IMX8MP_CLK_HDMIMIX_HTXPHY_CLK_SEL], clks[IMX8MP_CLK_HDMIMIX_GLOBAL_XTAL24M_CLK]);
+
+	imx_check_clocks(clks, ARRAY_SIZE(clks));
+
+	clk_data.clks = clks;
+	clk_data.clk_num = ARRAY_SIZE(clks);
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (ret < 0) {
+		pr_err("failed to register clks for i.MX8MP\n");
+		return -EINVAL;
+	}
+
+	pm_runtime_put(dev);
+
+	return 0;
+}
+
+UNIVERSAL_DEV_PM_OPS(imx_hdmimix_clk_pm_ops, imx_hdmimix_clk_suspend,
+			imx_hdmimix_clk_resume, NULL);
+
+static const struct of_device_id imx_hdmimix_clk_of_match[] = {
+	{ .compatible = "fsl,imx8mp-hdmimix-clk" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_hdmimix_clk_of_match);
+
+
+static struct platform_driver imx_hdmimix_clk_driver = {
+	.probe = imx_hdmimix_clk_probe,
+	.driver = {
+		.name = "imx-hdmimix-clk",
+		.of_match_table = of_match_ptr(imx_hdmimix_clk_of_match),
+		.pm = &imx_hdmimix_clk_pm_ops,
+	},
+};
+module_platform_driver(imx_hdmimix_clk_driver);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx31.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx31.c
@@ -51,16 +51,6 @@
 static struct clk *clk[clk_max];
 static struct clk_onecell_data clk_data;
 
-static struct clk ** const uart_clks[] __initconst = {
-	&clk[ipg],
-	&clk[uart1_gate],
-	&clk[uart2_gate],
-	&clk[uart3_gate],
-	&clk[uart4_gate],
-	&clk[uart5_gate],
-	NULL
-};
-
 static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref)
 {
 	clk[dummy] = imx_clk_fixed("dummy", 0);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx6q.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx6q.c
@@ -6,6 +6,7 @@
 
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
@@ -337,10 +338,10 @@
 	of_assigned_ldb_sels(np, &sel[0][3], &sel[1][3]);
 
 	for (i = 0; i < 2; i++) {
-		/* Warn if a glitch might have been introduced already */
+		/* Print a notice if a glitch might have been introduced already */
 		if (sel[i][0] != 3) {
-			pr_warn("ccm: ldb_di%d_sel already changed from reset value: %d\n",
-				i, sel[i][0]);
+			pr_notice("ccm: possible glitch: ldb_di%d_sel already changed from reset value: %d\n",
+				  i, sel[i][0]);
 		}
 
 		if (sel[i][0] == sel[i][3])
@@ -598,7 +599,10 @@
 	}
 
 	hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-	hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+	if (clk_on_imx6q() || clk_on_imx6qp())
+		hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = imx_clk_hw_fixed_factor("pll4_audio_div", "pll4_post_div", 1, 1);
+	else
+		hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
 	hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
 	hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx6sl.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx6sl.c
@@ -3,8 +3,10 @@
  * Copyright 2013-2014 Freescale Semiconductor, Inc.
  */
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk/imx.h>
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -14,19 +16,19 @@
 #include "clk.h"
 
 #define CCSR			0xc
-#define BM_CCSR_PLL1_SW_CLK_SEL	(1 << 2)
+#define BM_CCSR_PLL1_SW_CLK_SEL	BIT(2)
 #define CACRR			0x10
 #define CDHIPR			0x48
-#define BM_CDHIPR_ARM_PODF_BUSY	(1 << 16)
+#define BM_CDHIPR_ARM_PODF_BUSY	BIT(16)
 #define ARM_WAIT_DIV_396M	2
 #define ARM_WAIT_DIV_792M	4
 #define ARM_WAIT_DIV_996M	6
 
 #define PLL_ARM			0x0
-#define BM_PLL_ARM_DIV_SELECT	(0x7f << 0)
-#define BM_PLL_ARM_POWERDOWN	(1 << 12)
-#define BM_PLL_ARM_ENABLE	(1 << 13)
-#define BM_PLL_ARM_LOCK		(1 << 31)
+#define BM_PLL_ARM_DIV_SELECT	0x7f
+#define BM_PLL_ARM_POWERDOWN	BIT(12)
+#define BM_PLL_ARM_ENABLE	BIT(13)
+#define BM_PLL_ARM_LOCK		BIT(31)
 #define PLL_ARM_DIV_792M	66
 
 static const char *step_sels[]		= { "osc", "pll2_pfd2", };
@@ -145,7 +147,7 @@
 		val |= BM_PLL_ARM_ENABLE;
 		val &= ~BM_PLL_ARM_POWERDOWN;
 		writel_relaxed(val, anatop_base + PLL_ARM);
-		while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
+		while (!(readl_relaxed(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
 			;
 	} else {
 		 writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM);
@@ -208,6 +210,7 @@
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
+	of_node_put(np);
 	anatop_base = base;
 
 	hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx6sll.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx6sll.c
@@ -107,12 +107,12 @@
 
 	hws[IMX6SLL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-	hws[IMX6SLL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
-	hws[IMX6SLL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+	hws[IMX6SLL_CLK_CKIL] = imx_obtain_fixed_clk_hw(ccm_node, "ckil");
+	hws[IMX6SLL_CLK_OSC] = imx_obtain_fixed_clk_hw(ccm_node, "osc");
 
 	/* ipp_di clock is external input */
-	hws[IMX6SLL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
-	hws[IMX6SLL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
+	hws[IMX6SLL_CLK_IPP_DI0] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di0");
+	hws[IMX6SLL_CLK_IPP_DI1] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di1");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
 	base = of_iomap(np, 0);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx6sx.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx6sx.c
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/imx6sx-clock.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
@@ -17,6 +18,8 @@
 
 #include "clk.h"
 
+#define CCM_CCGR_OFFSET(index)		(index * 2)
+
 static const char *step_sels[]		= { "osc", "pll2_pfd2_396m", };
 static const char *pll1_sw_sels[]	= { "pll1_sys", "step", };
 static const char *periph_pre_sels[]	= { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -139,16 +142,16 @@
 
 	hws[IMX6SX_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-	hws[IMX6SX_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
-	hws[IMX6SX_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+	hws[IMX6SX_CLK_CKIL] = imx_obtain_fixed_clk_hw(ccm_node, "ckil");
+	hws[IMX6SX_CLK_OSC] = imx_obtain_fixed_clk_hw(ccm_node, "osc");
 
 	/* ipp_di clock is external input */
-	hws[IMX6SX_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
-	hws[IMX6SX_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
+	hws[IMX6SX_CLK_IPP_DI0] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di0");
+	hws[IMX6SX_CLK_IPP_DI1] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di1");
 
 	/* Clock source from external clock via CLK1/2 PAD */
-	hws[IMX6SX_CLK_ANACLK1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk1"));
-	hws[IMX6SX_CLK_ANACLK2] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk2"));
+	hws[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clk_hw(ccm_node, "anaclk1");
+	hws[IMX6SX_CLK_ANACLK2] = imx_obtain_fixed_clk_hw(ccm_node, "anaclk2");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
 	base = of_iomap(np, 0);
@@ -287,13 +290,13 @@
 	hws[IMX6SX_CLK_SSI3_SEL]           = imx_clk_hw_mux("ssi3_sel",         base + 0x1c,  14,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
 	hws[IMX6SX_CLK_SSI2_SEL]           = imx_clk_hw_mux("ssi2_sel",         base + 0x1c,  12,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
 	hws[IMX6SX_CLK_SSI1_SEL]           = imx_clk_hw_mux("ssi1_sel",         base + 0x1c,  10,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-	hws[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_hw_mux_flags("qspi1_sel", base + 0x1c,  7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
+	hws[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_hw_mux("qspi1_sel",        base + 0x1c,  7,      3,      qspi1_sels,        ARRAY_SIZE(qspi1_sels));
 	hws[IMX6SX_CLK_PERCLK_SEL]         = imx_clk_hw_mux("perclk_sel",       base + 0x1c,  6,      1,      perclk_sels,       ARRAY_SIZE(perclk_sels));
 	hws[IMX6SX_CLK_VID_SEL]            = imx_clk_hw_mux("vid_sel",          base + 0x20,  21,     3,      vid_sels,          ARRAY_SIZE(vid_sels));
 	hws[IMX6SX_CLK_ESAI_SEL]           = imx_clk_hw_mux("esai_sel",         base + 0x20,  19,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
 	hws[IMX6SX_CLK_CAN_SEL]            = imx_clk_hw_mux("can_sel",          base + 0x20,  8,      2,      can_sels,          ARRAY_SIZE(can_sels));
 	hws[IMX6SX_CLK_UART_SEL]           = imx_clk_hw_mux("uart_sel",         base + 0x24,  6,      1,      uart_sels,         ARRAY_SIZE(uart_sels));
-	hws[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_hw_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
+	hws[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_hw_mux("qspi2_sel",        base + 0x2c,  15,     3,      qspi2_sels,        ARRAY_SIZE(qspi2_sels));
 	hws[IMX6SX_CLK_SPDIF_SEL]          = imx_clk_hw_mux("spdif_sel",        base + 0x30,  20,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
 	hws[IMX6SX_CLK_AUDIO_SEL]          = imx_clk_hw_mux("audio_sel",        base + 0x30,  7,      2,      audio_sels,        ARRAY_SIZE(audio_sels));
 	hws[IMX6SX_CLK_ENET_PRE_SEL]       = imx_clk_hw_mux("enet_pre_sel",     base + 0x34,  15,     3,      enet_pre_sels,     ARRAY_SIZE(enet_pre_sels));
@@ -405,7 +408,7 @@
 	hws[IMX6SX_CLK_GPT_BUS]      = imx_clk_hw_gate2("gpt_bus",       "perclk",            base + 0x6c, 20);
 	hws[IMX6SX_CLK_GPT_SERIAL]   = imx_clk_hw_gate2("gpt_serial",    "perclk",            base + 0x6c, 22);
 	hws[IMX6SX_CLK_GPU]          = imx_clk_hw_gate2("gpu",           "gpu_core_podf",     base + 0x6c, 26);
-	hws[IMX6SX_CLK_OCRAM_S]      = imx_clk_hw_gate2("ocram_s",       "ahb",               base + 0x6c, 28);
+	hws[IMX6SX_CLK_OCRAM_S]      = imx_clk_hw_gate2_flags("ocram_s",       "ahb",               base + 0x6c, 28, CLK_IS_CRITICAL);
 	hws[IMX6SX_CLK_CANFD]        = imx_clk_hw_gate2("canfd",         "can_podf",          base + 0x6c, 30);
 
 	/* CCGR2 */
@@ -494,6 +497,16 @@
 
 	imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
 
+	/*
+	 * QSPI2/GPMI_IO share the same clock source but with the
+	 * different gate, need explicitely gate the QSPI2 & GPMI_IO
+	 * during the clock init phase according to the SOC design.
+	 */
+	writel_relaxed(readl_relaxed(base + 0x78) &
+			~(3 << CCM_CCGR_OFFSET(5)), base + 0x78);
+	writel_relaxed(readl_relaxed(base + 0x78) &
+			~(3 << CCM_CCGR_OFFSET(14)), base + 0x78);
+
 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
 	if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx6ul.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx6ul.c
@@ -126,12 +126,12 @@
 
 	hws[IMX6UL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-	hws[IMX6UL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
-	hws[IMX6UL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+	hws[IMX6UL_CLK_CKIL] = imx_obtain_fixed_clk_hw(ccm_node, "ckil");
+	hws[IMX6UL_CLK_OSC] = imx_obtain_fixed_clk_hw(ccm_node, "osc");
 
 	/* ipp_di clock is external input */
-	hws[IMX6UL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
-	hws[IMX6UL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
+	hws[IMX6UL_CLK_IPP_DI0] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di0");
+	hws[IMX6UL_CLK_IPP_DI1] = imx_obtain_fixed_clk_hw(ccm_node, "ipp_di1");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
 	base = of_iomap(np, 0);
@@ -161,7 +161,6 @@
 	hws[IMX6UL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
 	hws[IMX6UL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
 	hws[IMX6UL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-	hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
 
 	/* Do not bypass PLLs initially */
 	clk_set_parent(hws[IMX6UL_PLL1_BYPASS]->clk, hws[IMX6UL_CLK_PLL1]->clk);
@@ -270,6 +269,7 @@
 	hws[IMX6UL_CLK_ECSPI_SEL]	  = imx_clk_hw_mux("ecspi_sel",	base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
 	hws[IMX6UL_CLK_LCDIF_PRE_SEL]	  = imx_clk_hw_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
 	hws[IMX6UL_CLK_LCDIF_SEL]	  = imx_clk_hw_mux("lcdif_sel",	base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+	hws[IMX6UL_CLK_CSI_SEL]		  = imx_clk_hw_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
 
 	hws[IMX6UL_CLK_LDB_DI0_DIV_SEL]  = imx_clk_hw_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
 	hws[IMX6UL_CLK_LDB_DI1_DIV_SEL]  = imx_clk_hw_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
@@ -503,7 +503,7 @@
 		clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
 	}
 
-	clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
+	clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk);
 	if (clk_on_imx6ul())
 		clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
 	else if (clk_on_imx6ull())
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx7d.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx7d.c
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/imx7d-clock.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
@@ -14,6 +15,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/types.h>
+#include <soc/imx/src.h>
 
 #include "clk.h"
 
@@ -403,8 +405,8 @@
 	hws = clk_hw_data->hws;
 
 	hws[IMX7D_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
-	hws[IMX7D_OSC_24M_CLK] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
-	hws[IMX7D_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+	hws[IMX7D_OSC_24M_CLK] = imx_obtain_fixed_clk_hw(ccm_node, "osc");
+	hws[IMX7D_CKIL] = imx_obtain_fixed_clk_hw(ccm_node, "ckil");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
 	base = of_iomap(np, 0);
@@ -505,72 +507,73 @@
 	hws[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
 	hws[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_hw_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
 	hws[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_hw_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
-	hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
-	hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
 	hws[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_hw_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
-	hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
-	hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
-	hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
-	hws[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
-	hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
-	hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
-	hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
-	hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
-	hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
-	hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
-	hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
-	hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
-	hws[IMX7D_SAI1_ROOT_SRC] = imx_clk_hw_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
-	hws[IMX7D_SAI2_ROOT_SRC] = imx_clk_hw_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
-	hws[IMX7D_SAI3_ROOT_SRC] = imx_clk_hw_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
-	hws[IMX7D_SPDIF_ROOT_SRC] = imx_clk_hw_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
-	hws[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_hw_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
-	hws[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
-	hws[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_hw_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
-	hws[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
-	hws[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_hw_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
-	hws[IMX7D_EIM_ROOT_SRC] = imx_clk_hw_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
-	hws[IMX7D_NAND_ROOT_SRC] = imx_clk_hw_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
-	hws[IMX7D_QSPI_ROOT_SRC] = imx_clk_hw_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
-	hws[IMX7D_USDHC1_ROOT_SRC] = imx_clk_hw_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
-	hws[IMX7D_USDHC2_ROOT_SRC] = imx_clk_hw_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
-	hws[IMX7D_USDHC3_ROOT_SRC] = imx_clk_hw_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
-	hws[IMX7D_CAN1_ROOT_SRC] = imx_clk_hw_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
-	hws[IMX7D_CAN2_ROOT_SRC] = imx_clk_hw_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
-	hws[IMX7D_I2C1_ROOT_SRC] = imx_clk_hw_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
-	hws[IMX7D_I2C2_ROOT_SRC] = imx_clk_hw_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
-	hws[IMX7D_I2C3_ROOT_SRC] = imx_clk_hw_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
-	hws[IMX7D_I2C4_ROOT_SRC] = imx_clk_hw_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
-	hws[IMX7D_UART1_ROOT_SRC] = imx_clk_hw_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
-	hws[IMX7D_UART2_ROOT_SRC] = imx_clk_hw_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
-	hws[IMX7D_UART3_ROOT_SRC] = imx_clk_hw_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
-	hws[IMX7D_UART4_ROOT_SRC] = imx_clk_hw_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
-	hws[IMX7D_UART5_ROOT_SRC] = imx_clk_hw_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
-	hws[IMX7D_UART6_ROOT_SRC] = imx_clk_hw_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
-	hws[IMX7D_UART7_ROOT_SRC] = imx_clk_hw_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
-	hws[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_hw_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
-	hws[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_hw_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
-	hws[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_hw_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
-	hws[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_hw_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
-	hws[IMX7D_PWM1_ROOT_SRC] = imx_clk_hw_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
-	hws[IMX7D_PWM2_ROOT_SRC] = imx_clk_hw_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
-	hws[IMX7D_PWM3_ROOT_SRC] = imx_clk_hw_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
-	hws[IMX7D_PWM4_ROOT_SRC] = imx_clk_hw_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
-	hws[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_hw_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
-	hws[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_hw_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
-	hws[IMX7D_SIM1_ROOT_SRC] = imx_clk_hw_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
-	hws[IMX7D_SIM2_ROOT_SRC] = imx_clk_hw_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
-	hws[IMX7D_GPT1_ROOT_SRC] = imx_clk_hw_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
-	hws[IMX7D_GPT2_ROOT_SRC] = imx_clk_hw_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
-	hws[IMX7D_GPT3_ROOT_SRC] = imx_clk_hw_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
-	hws[IMX7D_GPT4_ROOT_SRC] = imx_clk_hw_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
-	hws[IMX7D_TRACE_ROOT_SRC] = imx_clk_hw_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
-	hws[IMX7D_WDOG_ROOT_SRC] = imx_clk_hw_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
-	hws[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_hw_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
-	hws[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_hw_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
-	hws[IMX7D_WRCLK_ROOT_SRC] = imx_clk_hw_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
-	hws[IMX7D_CLKO1_ROOT_SRC] = imx_clk_hw_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
-	hws[IMX7D_CLKO2_ROOT_SRC] = imx_clk_hw_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
+
+	hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_hw_mux2_flags("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SAI1_ROOT_SRC] = imx_clk_hw_mux2_flags("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SAI2_ROOT_SRC] = imx_clk_hw_mux2_flags("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SAI3_ROOT_SRC] = imx_clk_hw_mux2_flags("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SPDIF_ROOT_SRC] = imx_clk_hw_mux2_flags("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_hw_mux2_flags("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_hw_mux2_flags("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_hw_mux2_flags("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_hw_mux2_flags("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_EIM_ROOT_SRC] = imx_clk_hw_mux2_flags("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_NAND_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_QSPI_ROOT_SRC] = imx_clk_hw_mux2_flags("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_USDHC1_ROOT_SRC] = imx_clk_hw_mux2_flags("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_USDHC2_ROOT_SRC] = imx_clk_hw_mux2_flags("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_USDHC3_ROOT_SRC] = imx_clk_hw_mux2_flags("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_CAN1_ROOT_SRC] = imx_clk_hw_mux2_flags("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_CAN2_ROOT_SRC] = imx_clk_hw_mux2_flags("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_I2C1_ROOT_SRC] = imx_clk_hw_mux2_flags("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_I2C2_ROOT_SRC] = imx_clk_hw_mux2_flags("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_I2C3_ROOT_SRC] = imx_clk_hw_mux2_flags("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_I2C4_ROOT_SRC] = imx_clk_hw_mux2_flags("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART1_ROOT_SRC] = imx_clk_hw_mux2_flags("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART2_ROOT_SRC] = imx_clk_hw_mux2_flags("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART3_ROOT_SRC] = imx_clk_hw_mux2_flags("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART4_ROOT_SRC] = imx_clk_hw_mux2_flags("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART5_ROOT_SRC] = imx_clk_hw_mux2_flags("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART6_ROOT_SRC] = imx_clk_hw_mux2_flags("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_UART7_ROOT_SRC] = imx_clk_hw_mux2_flags("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_hw_mux2_flags("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_hw_mux2_flags("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_hw_mux2_flags("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_hw_mux2_flags("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PWM1_ROOT_SRC] = imx_clk_hw_mux2_flags("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PWM2_ROOT_SRC] = imx_clk_hw_mux2_flags("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PWM3_ROOT_SRC] = imx_clk_hw_mux2_flags("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_PWM4_ROOT_SRC] = imx_clk_hw_mux2_flags("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_hw_mux2_flags("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_hw_mux2_flags("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SIM1_ROOT_SRC] = imx_clk_hw_mux2_flags("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_SIM2_ROOT_SRC] = imx_clk_hw_mux2_flags("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_GPT1_ROOT_SRC] = imx_clk_hw_mux2_flags("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_GPT2_ROOT_SRC] = imx_clk_hw_mux2_flags("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_GPT3_ROOT_SRC] = imx_clk_hw_mux2_flags("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_GPT4_ROOT_SRC] = imx_clk_hw_mux2_flags("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_TRACE_ROOT_SRC] = imx_clk_hw_mux2_flags("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_WDOG_ROOT_SRC] = imx_clk_hw_mux2_flags("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_hw_mux2_flags("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_hw_mux2_flags("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_WRCLK_ROOT_SRC] = imx_clk_hw_mux2_flags("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_CLKO1_ROOT_SRC] = imx_clk_hw_mux2_flags("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel), CLK_SET_PARENT_GATE);
+	hws[IMX7D_CLKO2_ROOT_SRC] = imx_clk_hw_mux2_flags("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel), CLK_SET_PARENT_GATE);
 
 	hws[IMX7D_ARM_A7_ROOT_CG] = imx_clk_hw_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
 	hws[IMX7D_ARM_M4_ROOT_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
@@ -802,6 +805,7 @@
 	hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
 	hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
 	hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
+	hws[IMX7D_PXP_CLK] = imx_clk_hw_gate4("pxp_clk", "main_axi_root_clk", base + 0x44c0, 0);
 	hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
 	hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
 	hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
@@ -859,7 +863,6 @@
 	hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
 	hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
 	hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
-	hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
 	hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
 	hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
 	hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
@@ -887,6 +890,11 @@
 
 	clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
 
+	if (imx_src_is_m4_enabled()) {
+		clk_set_parent(hws[IMX7D_ARM_M4_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_MAIN_240M_CLK]->clk);
+		clk_prepare_enable(hws[IMX7D_ARM_M4_ROOT_CLK]->clk);
+	}
+
 	/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
 	clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
 
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx7ulp.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx7ulp.c
@@ -8,7 +8,7 @@
  */
 
 #include <dt-bindings/clock/imx7ulp-clock.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -24,8 +24,8 @@
 static const char * const spll_sels[]		= { "spll", "spll_pfd_sel", };
 static const char * const apll_pfd_sels[]	= { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", };
 static const char * const apll_sels[]		= { "apll", "apll_pfd_sel", };
-static const char * const scs_sels[]		= { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", };
-static const char * const ddr_sels[]		= { "apll_pfd_sel", "upll", };
+static const char * const scs_sels[]		= { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "dummy", };
+static const char * const ddr_sels[]		= { "apll_pfd_sel", "dummy", "dummy", "dummy", };
 static const char * const nic_sels[]		= { "firc", "ddr_clk", };
 static const char * const periph_plat_sels[]	= { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
 static const char * const periph_bus_sels[]	= { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
@@ -40,6 +40,7 @@
 	{ .val = 5, .div = 16, },
 	{ .val = 6, .div = 32, },
 	{ .val = 7, .div = 64, },
+	{ /* sentinel */ },
 };
 
 static const int pcc2_uart_clk_ids[] __initconst = {
@@ -58,7 +59,7 @@
 static void __init imx7ulp_clk_scg1_init(struct device_node *np)
 {
 	struct clk_hw_onecell_data *clk_data;
-	struct clk_hw **clks;
+	struct clk_hw **hws;
 	void __iomem *base;
 
 	clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SCG1_END),
@@ -67,77 +68,76 @@
 		return;
 
 	clk_data->num = IMX7ULP_CLK_SCG1_END;
-	clks = clk_data->hws;
+	hws = clk_data->hws;
 
-	clks[IMX7ULP_CLK_DUMMY]		= imx_clk_hw_fixed("dummy", 0);
+	hws[IMX7ULP_CLK_DUMMY]		= imx_clk_hw_fixed("dummy", 0);
 
-	clks[IMX7ULP_CLK_ROSC]		= imx_obtain_fixed_clk_hw(np, "rosc");
-	clks[IMX7ULP_CLK_SOSC]		= imx_obtain_fixed_clk_hw(np, "sosc");
-	clks[IMX7ULP_CLK_SIRC]		= imx_obtain_fixed_clk_hw(np, "sirc");
-	clks[IMX7ULP_CLK_FIRC]		= imx_obtain_fixed_clk_hw(np, "firc");
-	clks[IMX7ULP_CLK_MIPI_PLL]	= imx_obtain_fixed_clk_hw(np, "mpll");
-	clks[IMX7ULP_CLK_UPLL]		= imx_obtain_fixed_clk_hw(np, "upll");
+	hws[IMX7ULP_CLK_ROSC]		= imx_obtain_fixed_clk_hw(np, "rosc");
+	hws[IMX7ULP_CLK_SOSC]		= imx_obtain_fixed_clk_hw(np, "sosc");
+	hws[IMX7ULP_CLK_SIRC]		= imx_obtain_fixed_clk_hw(np, "sirc");
+	hws[IMX7ULP_CLK_FIRC]		= imx_obtain_fixed_clk_hw(np, "firc");
+	hws[IMX7ULP_CLK_UPLL]		= imx_obtain_fixed_clk_hw(np, "upll");
 
 	/* SCG1 */
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
 	/* NOTE: xPLL config can't be changed when xPLL is enabled */
-	clks[IMX7ULP_CLK_APLL_PRE_SEL]	= imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
-	clks[IMX7ULP_CLK_SPLL_PRE_SEL]	= imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_APLL_PRE_SEL]	= imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_SPLL_PRE_SEL]	= imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
 
 	/*							   name		    parent_name	   reg			shift	width	flags */
-	clks[IMX7ULP_CLK_APLL_PRE_DIV]	= imx_clk_hw_divider_flags("apll_pre_div", "apll_pre_sel", base + 0x508,	8,	3,	CLK_SET_RATE_GATE);
-	clks[IMX7ULP_CLK_SPLL_PRE_DIV]	= imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608,	8,	3,	CLK_SET_RATE_GATE);
+	hws[IMX7ULP_CLK_APLL_PRE_DIV]	= imx_clk_hw_divider_flags("apll_pre_div", "apll_pre_sel", base + 0x508,	8,	3,	CLK_SET_RATE_GATE);
+	hws[IMX7ULP_CLK_SPLL_PRE_DIV]	= imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608,	8,	3,	CLK_SET_RATE_GATE);
 
 	/*						name	 parent_name	 base */
-	clks[IMX7ULP_CLK_APLL]		= imx_clk_pllv4("apll",  "apll_pre_div", base + 0x500);
-	clks[IMX7ULP_CLK_SPLL]		= imx_clk_pllv4("spll",  "spll_pre_div", base + 0x600);
+	hws[IMX7ULP_CLK_APLL]		= imx_clk_hw_pllv4("apll",  "apll_pre_div", base + 0x500);
+	hws[IMX7ULP_CLK_SPLL]		= imx_clk_hw_pllv4("spll",  "spll_pre_div", base + 0x600);
 
 	/* APLL PFDs */
-	clks[IMX7ULP_CLK_APLL_PFD0]	= imx_clk_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
-	clks[IMX7ULP_CLK_APLL_PFD1]	= imx_clk_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
-	clks[IMX7ULP_CLK_APLL_PFD2]	= imx_clk_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
-	clks[IMX7ULP_CLK_APLL_PFD3]	= imx_clk_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
+	hws[IMX7ULP_CLK_APLL_PFD0]	= imx_clk_hw_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
+	hws[IMX7ULP_CLK_APLL_PFD1]	= imx_clk_hw_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
+	hws[IMX7ULP_CLK_APLL_PFD2]	= imx_clk_hw_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
+	hws[IMX7ULP_CLK_APLL_PFD3]	= imx_clk_hw_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
 
 	/* SPLL PFDs */
-	clks[IMX7ULP_CLK_SPLL_PFD0]	= imx_clk_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
-	clks[IMX7ULP_CLK_SPLL_PFD1]	= imx_clk_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
-	clks[IMX7ULP_CLK_SPLL_PFD2]	= imx_clk_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
-	clks[IMX7ULP_CLK_SPLL_PFD3]	= imx_clk_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
+	hws[IMX7ULP_CLK_SPLL_PFD0]	= imx_clk_hw_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
+	hws[IMX7ULP_CLK_SPLL_PFD1]	= imx_clk_hw_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
+	hws[IMX7ULP_CLK_SPLL_PFD2]	= imx_clk_hw_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
+	hws[IMX7ULP_CLK_SPLL_PFD3]	= imx_clk_hw_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
 
 	/* PLL Mux */
-	clks[IMX7ULP_CLK_APLL_PFD_SEL]	= imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
-	clks[IMX7ULP_CLK_SPLL_PFD_SEL]	= imx_clk_hw_mux_flags("spll_pfd_sel", base + 0x608, 14, 2, spll_pfd_sels, ARRAY_SIZE(spll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
-	clks[IMX7ULP_CLK_APLL_SEL]	= imx_clk_hw_mux_flags("apll_sel", base + 0x508, 1, 1, apll_sels, ARRAY_SIZE(apll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
-	clks[IMX7ULP_CLK_SPLL_SEL]	= imx_clk_hw_mux_flags("spll_sel", base + 0x608, 1, 1, spll_sels, ARRAY_SIZE(spll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_APLL_PFD_SEL]	= imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_SPLL_PFD_SEL]	= imx_clk_hw_mux_flags("spll_pfd_sel", base + 0x608, 14, 2, spll_pfd_sels, ARRAY_SIZE(spll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_APLL_SEL]	= imx_clk_hw_mux_flags("apll_sel", base + 0x508, 1, 1, apll_sels, ARRAY_SIZE(apll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
+	hws[IMX7ULP_CLK_SPLL_SEL]	= imx_clk_hw_mux_flags("spll_sel", base + 0x608, 1, 1, spll_sels, ARRAY_SIZE(spll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
 
-	clks[IMX7ULP_CLK_SPLL_BUS_CLK]	= imx_clk_divider_gate("spll_bus_clk", "spll_sel", CLK_SET_RATE_GATE, base + 0x604, 8, 3, 0, ulp_div_table, &imx_ccm_lock);
+	hws[IMX7ULP_CLK_SPLL_BUS_CLK]	= imx_clk_hw_divider_gate("spll_bus_clk", "spll_sel", CLK_SET_RATE_GATE, base + 0x604, 8, 3, 0, ulp_div_table, &imx_ccm_lock);
 
 	/* scs/ddr/nic select different clock source requires that clock to be enabled first */
-	clks[IMX7ULP_CLK_SYS_SEL]	= imx_clk_hw_mux2("scs_sel", base + 0x14, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
-	clks[IMX7ULP_CLK_HSRUN_SYS_SEL] = imx_clk_hw_mux2("hsrun_scs_sel", base + 0x1c, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
-	clks[IMX7ULP_CLK_NIC_SEL]	= imx_clk_hw_mux2("nic_sel", base + 0x40, 28, 1, nic_sels, ARRAY_SIZE(nic_sels));
-	clks[IMX7ULP_CLK_DDR_SEL]	= imx_clk_hw_mux_flags("ddr_sel", base + 0x30, 24, 1, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+	hws[IMX7ULP_CLK_SYS_SEL]	= imx_clk_hw_mux2("scs_sel", base + 0x14, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
+	hws[IMX7ULP_CLK_HSRUN_SYS_SEL] = imx_clk_hw_mux2("hsrun_scs_sel", base + 0x1c, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
+	hws[IMX7ULP_CLK_NIC_SEL]	= imx_clk_hw_mux2("nic_sel", base + 0x40, 28, 1, nic_sels, ARRAY_SIZE(nic_sels));
+	hws[IMX7ULP_CLK_DDR_SEL]	= imx_clk_hw_mux_flags("ddr_sel", base + 0x30, 24, 2, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
 
-	clks[IMX7ULP_CLK_CORE_DIV]	= imx_clk_hw_divider_flags("divcore",	"scs_sel",  base + 0x14, 16, 4, CLK_SET_RATE_PARENT);
-	clks[IMX7ULP_CLK_HSRUN_CORE_DIV] = imx_clk_hw_divider_flags("hsrun_divcore", "hsrun_scs_sel", base + 0x1c, 16, 4, CLK_SET_RATE_PARENT);
+	hws[IMX7ULP_CLK_CORE_DIV]	= imx_clk_hw_divider_flags("divcore",	"scs_sel",  base + 0x14, 16, 4, CLK_SET_RATE_PARENT);
+	hws[IMX7ULP_CLK_HSRUN_CORE_DIV] = imx_clk_hw_divider_flags("hsrun_divcore", "hsrun_scs_sel", base + 0x1c, 16, 4, CLK_SET_RATE_PARENT);
 
-	clks[IMX7ULP_CLK_DDR_DIV]	= imx_clk_divider_gate("ddr_clk", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
+	hws[IMX7ULP_CLK_DDR_DIV]	= imx_clk_hw_divider_gate("ddr_clk", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
 							       0, ulp_div_table, &imx_ccm_lock);
 
-	clks[IMX7ULP_CLK_NIC0_DIV]	= imx_clk_hw_divider_flags("nic0_clk",		"nic_sel",  base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
-	clks[IMX7ULP_CLK_NIC1_DIV]	= imx_clk_hw_divider_flags("nic1_clk",		"nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
-	clks[IMX7ULP_CLK_NIC1_BUS_DIV]	= imx_clk_hw_divider_flags("nic1_bus_clk",	"nic0_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+	hws[IMX7ULP_CLK_NIC0_DIV]	= imx_clk_hw_divider_flags("nic0_clk",		"nic_sel",  base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+	hws[IMX7ULP_CLK_NIC1_DIV]	= imx_clk_hw_divider_flags("nic1_clk",		"nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+	hws[IMX7ULP_CLK_NIC1_BUS_DIV]	= imx_clk_hw_divider_flags("nic1_bus_clk",	"nic0_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
 
-	clks[IMX7ULP_CLK_GPU_DIV]	= imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
+	hws[IMX7ULP_CLK_GPU_DIV]	= imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
 
-	clks[IMX7ULP_CLK_SOSC_BUS_CLK]	= imx_clk_divider_gate("sosc_bus_clk", "sosc", 0, base + 0x104, 8, 3,
+	hws[IMX7ULP_CLK_SOSC_BUS_CLK]	= imx_clk_hw_divider_gate("sosc_bus_clk", "sosc", 0, base + 0x104, 8, 3,
 							       CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
-	clks[IMX7ULP_CLK_FIRC_BUS_CLK]	= imx_clk_divider_gate("firc_bus_clk", "firc", 0, base + 0x304, 8, 3,
+	hws[IMX7ULP_CLK_FIRC_BUS_CLK]	= imx_clk_hw_divider_gate("firc_bus_clk", "firc", 0, base + 0x304, 8, 3,
 							       CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
 
-	imx_check_clk_hws(clks, clk_data->num);
+	imx_check_clk_hws(hws, clk_data->num);
 
 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 }
@@ -146,7 +146,7 @@
 static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
 {
 	struct clk_hw_onecell_data *clk_data;
-	struct clk_hw **clks;
+	struct clk_hw **hws;
 	void __iomem *base;
 	int i;
 
@@ -156,42 +156,42 @@
 		return;
 
 	clk_data->num = IMX7ULP_CLK_PCC2_END;
-	clks = clk_data->hws;
+	hws = clk_data->hws;
 
 	/* PCC2 */
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
-	clks[IMX7ULP_CLK_DMA1]		= imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30);
-	clks[IMX7ULP_CLK_RGPIO2P1]	= imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30);
-	clks[IMX7ULP_CLK_DMA_MUX1]	= imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30);
-	clks[IMX7ULP_CLK_CAAM]		= imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30);
-	clks[IMX7ULP_CLK_LPTPM4]	= imx7ulp_clk_composite("lptpm4",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
-	clks[IMX7ULP_CLK_LPTPM5]	= imx7ulp_clk_composite("lptpm5",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
-	clks[IMX7ULP_CLK_LPIT1]		= imx7ulp_clk_composite("lpit1",   periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
-	clks[IMX7ULP_CLK_LPSPI2]	= imx7ulp_clk_composite("lpspi2",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa4);
-	clks[IMX7ULP_CLK_LPSPI3]	= imx7ulp_clk_composite("lpspi3",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa8);
-	clks[IMX7ULP_CLK_LPI2C4]	= imx7ulp_clk_composite("lpi2c4",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xac);
-	clks[IMX7ULP_CLK_LPI2C5]	= imx7ulp_clk_composite("lpi2c5",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb0);
-	clks[IMX7ULP_CLK_LPUART4]	= imx7ulp_clk_composite("lpuart4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb4);
-	clks[IMX7ULP_CLK_LPUART5]	= imx7ulp_clk_composite("lpuart5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb8);
-	clks[IMX7ULP_CLK_FLEXIO1]	= imx7ulp_clk_composite("flexio1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xc4);
-	clks[IMX7ULP_CLK_USB0]		= imx7ulp_clk_composite("usb0",    periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xcc);
-	clks[IMX7ULP_CLK_USB1]		= imx7ulp_clk_composite("usb1",    periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xd0);
-	clks[IMX7ULP_CLK_USB_PHY]	= imx_clk_hw_gate("usb_phy", "nic1_bus_clk", base + 0xd4, 30);
-	clks[IMX7ULP_CLK_USDHC0]	= imx7ulp_clk_composite("usdhc0",  periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xdc);
-	clks[IMX7ULP_CLK_USDHC1]	= imx7ulp_clk_composite("usdhc1",  periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xe0);
-	clks[IMX7ULP_CLK_WDG1]		= imx7ulp_clk_composite("wdg1",    periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0xf4);
-	clks[IMX7ULP_CLK_WDG2]		= imx7ulp_clk_composite("sdg2",    periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0x10c);
+	hws[IMX7ULP_CLK_DMA1]		= imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30);
+	hws[IMX7ULP_CLK_RGPIO2P1]	= imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30);
+	hws[IMX7ULP_CLK_DMA_MUX1]	= imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30);
+	hws[IMX7ULP_CLK_CAAM]		= imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30);
+	hws[IMX7ULP_CLK_LPTPM4]		= imx7ulp_clk_hw_composite("lptpm4",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
+	hws[IMX7ULP_CLK_LPTPM5]		= imx7ulp_clk_hw_composite("lptpm5",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
+	hws[IMX7ULP_CLK_LPIT1]		= imx7ulp_clk_hw_composite("lpit1",   periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
+	hws[IMX7ULP_CLK_LPSPI2]		= imx7ulp_clk_hw_composite("lpspi2",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa4);
+	hws[IMX7ULP_CLK_LPSPI3]		= imx7ulp_clk_hw_composite("lpspi3",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa8);
+	hws[IMX7ULP_CLK_LPI2C4]		= imx7ulp_clk_hw_composite("lpi2c4",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xac);
+	hws[IMX7ULP_CLK_LPI2C5]		= imx7ulp_clk_hw_composite("lpi2c5",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb0);
+	hws[IMX7ULP_CLK_LPUART4]	= imx7ulp_clk_hw_composite("lpuart4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb4);
+	hws[IMX7ULP_CLK_LPUART5]	= imx7ulp_clk_hw_composite("lpuart5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb8);
+	hws[IMX7ULP_CLK_FLEXIO1]	= imx7ulp_clk_hw_composite("flexio1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xc4);
+	hws[IMX7ULP_CLK_USB0]		= imx7ulp_clk_hw_composite("usb0",    periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xcc);
+	hws[IMX7ULP_CLK_USB1]		= imx7ulp_clk_hw_composite("usb1",    periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xd0);
+	hws[IMX7ULP_CLK_USB_PHY]	= imx_clk_hw_gate("usb_phy", "nic1_bus_clk", base + 0xd4, 30);
+	hws[IMX7ULP_CLK_USDHC0]		= imx7ulp_clk_hw_composite("usdhc0",  periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xdc);
+	hws[IMX7ULP_CLK_USDHC1]		= imx7ulp_clk_hw_composite("usdhc1",  periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xe0);
+	hws[IMX7ULP_CLK_WDG1]		= imx7ulp_clk_hw_composite("wdg1",    periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0xf4);
+	hws[IMX7ULP_CLK_WDG2]		= imx7ulp_clk_hw_composite("wdg2",    periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0x10c);
 
-	imx_check_clk_hws(clks, clk_data->num);
+	imx_check_clk_hws(hws, clk_data->num);
 
 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 
 	for (i = 0; i < ARRAY_SIZE(pcc2_uart_clk_ids); i++) {
 		int index = pcc2_uart_clk_ids[i];
 
-		pcc2_uart_clks[i] = &clks[index]->clk;
+		pcc2_uart_clks[i] = &hws[index]->clk;
 	}
 
 	imx_register_uart_clocks(pcc2_uart_clks);
@@ -201,7 +201,7 @@
 static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
 {
 	struct clk_hw_onecell_data *clk_data;
-	struct clk_hw **clks;
+	struct clk_hw **hws;
 	void __iomem *base;
 	int i;
 
@@ -211,41 +211,41 @@
 		return;
 
 	clk_data->num = IMX7ULP_CLK_PCC3_END;
-	clks = clk_data->hws;
+	hws = clk_data->hws;
 
 	/* PCC3 */
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
-	clks[IMX7ULP_CLK_LPTPM6]	= imx7ulp_clk_composite("lptpm6",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x84);
-	clks[IMX7ULP_CLK_LPTPM7]	= imx7ulp_clk_composite("lptpm7",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x88);
+	hws[IMX7ULP_CLK_LPTPM6]	= imx7ulp_clk_hw_composite("lptpm6",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x84);
+	hws[IMX7ULP_CLK_LPTPM7]	= imx7ulp_clk_hw_composite("lptpm7",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x88);
 
-	clks[IMX7ULP_CLK_MMDC]		= clk_hw_register_gate(NULL, "mmdc", "nic1_clk", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+	hws[IMX7ULP_CLK_MMDC]		= clk_hw_register_gate(NULL, "mmdc", "nic1_clk", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 							       base + 0xac, 30, 0, &imx_ccm_lock);
-	clks[IMX7ULP_CLK_LPI2C6]	= imx7ulp_clk_composite("lpi2c6",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x90);
-	clks[IMX7ULP_CLK_LPI2C7]	= imx7ulp_clk_composite("lpi2c7",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
-	clks[IMX7ULP_CLK_LPUART6]	= imx7ulp_clk_composite("lpuart6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
-	clks[IMX7ULP_CLK_LPUART7]	= imx7ulp_clk_composite("lpuart7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
-	clks[IMX7ULP_CLK_DSI]		= imx7ulp_clk_composite("dsi",     periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0xa4);
-	clks[IMX7ULP_CLK_LCDIF]		= imx7ulp_clk_composite("lcdif",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xa8);
-
-	clks[IMX7ULP_CLK_VIU]		= imx_clk_hw_gate("viu",   "nic1_clk",	   base + 0xa0, 30);
-	clks[IMX7ULP_CLK_PCTLC]		= imx_clk_hw_gate("pctlc", "nic1_bus_clk", base + 0xb8, 30);
-	clks[IMX7ULP_CLK_PCTLD]		= imx_clk_hw_gate("pctld", "nic1_bus_clk", base + 0xbc, 30);
-	clks[IMX7ULP_CLK_PCTLE]		= imx_clk_hw_gate("pctle", "nic1_bus_clk", base + 0xc0, 30);
-	clks[IMX7ULP_CLK_PCTLF]		= imx_clk_hw_gate("pctlf", "nic1_bus_clk", base + 0xc4, 30);
+	hws[IMX7ULP_CLK_LPI2C6]	= imx7ulp_clk_hw_composite("lpi2c6",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x90);
+	hws[IMX7ULP_CLK_LPI2C7]	= imx7ulp_clk_hw_composite("lpi2c7",  periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
+	hws[IMX7ULP_CLK_LPUART6]	= imx7ulp_clk_hw_composite("lpuart6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
+	hws[IMX7ULP_CLK_LPUART7]	= imx7ulp_clk_hw_composite("lpuart7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
+	hws[IMX7ULP_CLK_DSI]		= imx7ulp_clk_hw_composite("dsi",     periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true,  true, base + 0xa4);
+	hws[IMX7ULP_CLK_LCDIF]		= imx7ulp_clk_hw_composite("lcdif",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true,  true, base + 0xa8);
+
+	hws[IMX7ULP_CLK_VIU]		= imx_clk_hw_gate("viu",   "nic1_clk",	   base + 0xa0, 30);
+	hws[IMX7ULP_CLK_PCTLC]		= imx_clk_hw_gate("pctlc", "nic1_bus_clk", base + 0xb8, 30);
+	hws[IMX7ULP_CLK_PCTLD]		= imx_clk_hw_gate("pctld", "nic1_bus_clk", base + 0xbc, 30);
+	hws[IMX7ULP_CLK_PCTLE]		= imx_clk_hw_gate("pctle", "nic1_bus_clk", base + 0xc0, 30);
+	hws[IMX7ULP_CLK_PCTLF]		= imx_clk_hw_gate("pctlf", "nic1_bus_clk", base + 0xc4, 30);
 
-	clks[IMX7ULP_CLK_GPU3D]		= imx7ulp_clk_composite("gpu3d",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x140);
-	clks[IMX7ULP_CLK_GPU2D]		= imx7ulp_clk_composite("gpu2d",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x144);
+	hws[IMX7ULP_CLK_GPU3D]		= imx7ulp_clk_hw_composite("gpu3d",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x140);
+	hws[IMX7ULP_CLK_GPU2D]		= imx7ulp_clk_hw_composite("gpu2d",   periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x144);
 
-	imx_check_clk_hws(clks, clk_data->num);
+	imx_check_clk_hws(hws, clk_data->num);
 
 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 
 	for (i = 0; i < ARRAY_SIZE(pcc3_uart_clk_ids); i++) {
 		int index = pcc3_uart_clk_ids[i];
 
-		pcc3_uart_clks[i] = &clks[index]->clk;
+		pcc3_uart_clks[i] = &hws[index]->clk;
 	}
 
 	imx_register_uart_clocks(pcc3_uart_clks);
@@ -255,7 +255,7 @@
 static void __init imx7ulp_clk_smc1_init(struct device_node *np)
 {
 	struct clk_hw_onecell_data *clk_data;
-	struct clk_hw **clks;
+	struct clk_hw **hws;
 	void __iomem *base;
 
 	clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SMC1_END),
@@ -264,15 +264,15 @@
 		return;
 
 	clk_data->num = IMX7ULP_CLK_SMC1_END;
-	clks = clk_data->hws;
+	hws = clk_data->hws;
 
 	/* SMC1 */
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
 
-	clks[IMX7ULP_CLK_ARM] = imx_clk_hw_mux_flags("arm", base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels), CLK_IS_CRITICAL);
+	hws[IMX7ULP_CLK_ARM] = imx_clk_hw_mux_flags("arm", base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels), CLK_IS_CRITICAL);
 
-	imx_check_clk_hws(clks, clk_data->num);
+	imx_check_clk_hws(hws, clk_data->num);
 
 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 }
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8mm.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8mm.c
@@ -4,14 +4,13 @@
  */
 
 #include <dt-bindings/clock/imx8mm-clock.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 #include "clk.h"
@@ -26,73 +25,6 @@
 static u32 share_count_pdm;
 static u32 share_count_nand;
 
-static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = {
-	PLL_1416X_RATE(1800000000U, 225, 3, 0),
-	PLL_1416X_RATE(1600000000U, 200, 3, 0),
-	PLL_1416X_RATE(1200000000U, 300, 3, 1),
-	PLL_1416X_RATE(1000000000U, 250, 3, 1),
-	PLL_1416X_RATE(800000000U,  200, 3, 1),
-	PLL_1416X_RATE(750000000U,  250, 2, 2),
-	PLL_1416X_RATE(700000000U,  350, 3, 2),
-	PLL_1416X_RATE(600000000U,  300, 3, 2),
-};
-
-static const struct imx_pll14xx_rate_table imx8mm_audiopll_tbl[] = {
-	PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
-	PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
-};
-
-static const struct imx_pll14xx_rate_table imx8mm_videopll_tbl[] = {
-	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
-	PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
-};
-
-static const struct imx_pll14xx_rate_table imx8mm_drampll_tbl[] = {
-	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
-};
-
-static struct imx_pll14xx_clk imx8mm_audio_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mm_audiopll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_audiopll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_video_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mm_videopll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_videopll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_dram_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mm_drampll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_drampll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_arm_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mm_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_gpu_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mm_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_vpu_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mm_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mm_sys_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mm_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl),
-};
-
 static const char *pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
 static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
 static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
@@ -101,14 +33,14 @@
 static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
 static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
 static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
-static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
-static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
 static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
 
 /* CCM ROOT */
 static const char *imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
 					"sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", };
 
+static const char * const imx8mm_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
+
 static const char *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m",
 				       "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
 
@@ -351,106 +283,128 @@
 
 static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
 
-static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
-					 "vpu_pll", "sys_pll1_80m", };
-
-static struct clk *clks[IMX8MM_CLK_END];
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] = {
-	&clks[IMX8MM_CLK_UART1_ROOT],
-	&clks[IMX8MM_CLK_UART2_ROOT],
-	&clks[IMX8MM_CLK_UART3_ROOT],
-	&clks[IMX8MM_CLK_UART4_ROOT],
-	NULL
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "dummy", "sys_pll1_200m",
+					  "audio_pll2_out", "sys_pll2_500m", "vpu_pll", "sys_pll1_80m", };
+static const char *imx8mm_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m", "sys_pll2_166m",
+					  "sys_pll3_out", "audio_pll1_out", "video_pll1_out", "osc_32k", };
+
+static const char * const clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+					   "dummy", "dummy", "gpu_pll_out", "vpu_pll_out",
+					   "arm_pll_out", "sys_pll1", "sys_pll2", "sys_pll3",
+					   "dummy", "dummy", "osc_24m", "dummy", "osc_32k"};
+
+static struct clk_hw_onecell_data *clk_hw_data;
+static struct clk_hw **hws;
+
+static const int uart_clk_ids[] = {
+	IMX8MM_CLK_UART1_ROOT,
+	IMX8MM_CLK_UART2_ROOT,
+	IMX8MM_CLK_UART3_ROOT,
+	IMX8MM_CLK_UART4_ROOT,
 };
+static struct clk **uart_hws[ARRAY_SIZE(uart_clk_ids) + 1];
 
 static int imx8mm_clocks_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	void __iomem *base;
-	int ret;
+	int ret, i;
+
+	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+					  IMX8MM_CLK_END), GFP_KERNEL);
+	if (WARN_ON(!clk_hw_data))
+		return -ENOMEM;
+
+	clk_hw_data->num = IMX8MM_CLK_END;
+	hws = clk_hw_data->hws;
 
-	clks[IMX8MM_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-	clks[IMX8MM_CLK_24M] = of_clk_get_by_name(np, "osc_24m");
-	clks[IMX8MM_CLK_32K] = of_clk_get_by_name(np, "osc_32k");
-	clks[IMX8MM_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1");
-	clks[IMX8MM_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2");
-	clks[IMX8MM_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3");
-	clks[IMX8MM_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4");
+	hws[IMX8MM_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+	hws[IMX8MM_CLK_24M] = imx_obtain_fixed_clk_hw(np, "osc_24m");
+	hws[IMX8MM_CLK_32K] = imx_obtain_fixed_clk_hw(np, "osc_32k");
+	hws[IMX8MM_CLK_EXT1] = imx_obtain_fixed_clk_hw(np, "clk_ext1");
+	hws[IMX8MM_CLK_EXT2] = imx_obtain_fixed_clk_hw(np, "clk_ext2");
+	hws[IMX8MM_CLK_EXT3] = imx_obtain_fixed_clk_hw(np, "clk_ext3");
+	hws[IMX8MM_CLK_EXT4] = imx_obtain_fixed_clk_hw(np, "clk_ext4");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
 	base = of_iomap(np, 0);
+	of_node_put(np);
 	if (WARN_ON(!base))
 		return -ENOMEM;
 
-	clks[IMX8MM_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_SYS_PLL1_REF_SEL] = imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-
-	clks[IMX8MM_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx8mm_audio_pll);
-	clks[IMX8MM_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mm_audio_pll);
-	clks[IMX8MM_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mm_video_pll);
-	clks[IMX8MM_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mm_dram_pll);
-	clks[IMX8MM_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mm_gpu_pll);
-	clks[IMX8MM_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mm_vpu_pll);
-	clks[IMX8MM_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mm_arm_pll);
-	clks[IMX8MM_SYS_PLL1] = imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mm_sys_pll);
-	clks[IMX8MM_SYS_PLL2] = imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mm_sys_pll);
-	clks[IMX8MM_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mm_sys_pll);
+	hws[IMX8MM_AUDIO_PLL1_REF_SEL] = imx_clk_hw_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_AUDIO_PLL2_REF_SEL] = imx_clk_hw_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_VIDEO_PLL1_REF_SEL] = imx_clk_hw_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_DRAM_PLL_REF_SEL] = imx_clk_hw_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_VPU_PLL_REF_SEL] = imx_clk_hw_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_hw_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+	hws[IMX8MM_AUDIO_PLL1] = imx_clk_hw_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx_1443x_pll);
+	hws[IMX8MM_AUDIO_PLL2] = imx_clk_hw_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx_1443x_pll);
+	hws[IMX8MM_VIDEO_PLL1] = imx_clk_hw_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx_1443x_pll);
+	hws[IMX8MM_DRAM_PLL] = imx_clk_hw_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx_1443x_dram_pll);
+	hws[IMX8MM_GPU_PLL] = imx_clk_hw_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx_1416x_pll);
+	hws[IMX8MM_VPU_PLL] = imx_clk_hw_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx_1416x_pll);
+	hws[IMX8MM_ARM_PLL] = imx_clk_hw_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx_1416x_pll);
+	hws[IMX8MM_SYS_PLL1] = imx_clk_hw_fixed("sys_pll1", 800000000);
+	hws[IMX8MM_SYS_PLL2] = imx_clk_hw_fixed("sys_pll2", 1000000000);
+	hws[IMX8MM_SYS_PLL3] = imx_clk_hw_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx_1416x_pll);
 
 	/* PLL bypass out */
-	clks[IMX8MM_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", base + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", base + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", base + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_SYS_PLL1_BYPASS] = imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 28, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_SYS_PLL2_BYPASS] = imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 28, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MM_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_AUDIO_PLL1_BYPASS] = imx_clk_hw_mux_flags("audio_pll1_bypass", base, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_AUDIO_PLL2_BYPASS] = imx_clk_hw_mux_flags("audio_pll2_bypass", base + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_VIDEO_PLL1_BYPASS] = imx_clk_hw_mux_flags("video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_DRAM_PLL_BYPASS] = imx_clk_hw_mux_flags("dram_pll_bypass", base + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_GPU_PLL_BYPASS] = imx_clk_hw_mux_flags("gpu_pll_bypass", base + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_VPU_PLL_BYPASS] = imx_clk_hw_mux_flags("vpu_pll_bypass", base + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_ARM_PLL_BYPASS] = imx_clk_hw_mux_flags("arm_pll_bypass", base + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MM_SYS_PLL3_BYPASS] = imx_clk_hw_mux_flags("sys_pll3_bypass", base + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
 
 	/* PLL out gate */
-	clks[IMX8MM_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base, 13);
-	clks[IMX8MM_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13);
-	clks[IMX8MM_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13);
-	clks[IMX8MM_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13);
-	clks[IMX8MM_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 11);
-	clks[IMX8MM_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 11);
-	clks[IMX8MM_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11);
-	clks[IMX8MM_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11);
-	clks[IMX8MM_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 11);
-	clks[IMX8MM_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
-
-	/* SYS PLL fixed output */
-	clks[IMX8MM_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
-	clks[IMX8MM_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
-	clks[IMX8MM_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
-	clks[IMX8MM_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
-	clks[IMX8MM_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
-	clks[IMX8MM_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
-	clks[IMX8MM_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
-	clks[IMX8MM_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
-	clks[IMX8MM_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
-
-	clks[IMX8MM_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
-	clks[IMX8MM_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
-	clks[IMX8MM_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
-	clks[IMX8MM_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
-	clks[IMX8MM_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
-	clks[IMX8MM_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
-	clks[IMX8MM_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
-	clks[IMX8MM_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
-	clks[IMX8MM_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+	hws[IMX8MM_AUDIO_PLL1_OUT] = imx_clk_hw_gate("audio_pll1_out", "audio_pll1_bypass", base, 13);
+	hws[IMX8MM_AUDIO_PLL2_OUT] = imx_clk_hw_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13);
+	hws[IMX8MM_VIDEO_PLL1_OUT] = imx_clk_hw_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13);
+	hws[IMX8MM_DRAM_PLL_OUT] = imx_clk_hw_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13);
+	hws[IMX8MM_GPU_PLL_OUT] = imx_clk_hw_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 11);
+	hws[IMX8MM_VPU_PLL_OUT] = imx_clk_hw_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 11);
+	hws[IMX8MM_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11);
+	hws[IMX8MM_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
+
+	/* SYS PLL1 fixed output */
+	hws[IMX8MM_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
+
+	hws[IMX8MM_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+	hws[IMX8MM_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+	hws[IMX8MM_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+	hws[IMX8MM_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+	hws[IMX8MM_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+	hws[IMX8MM_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+	hws[IMX8MM_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+	hws[IMX8MM_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
+	hws[IMX8MM_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+	/* SYS PLL2 fixed output */
+	hws[IMX8MM_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
+
+	hws[IMX8MM_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+	hws[IMX8MM_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+	hws[IMX8MM_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+	hws[IMX8MM_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+	hws[IMX8MM_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+	hws[IMX8MM_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+	hws[IMX8MM_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+	hws[IMX8MM_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
+	hws[IMX8MM_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+	hws[IMX8MM_CLK_CLKOUT1_SEL] = imx_clk_hw_mux("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+	hws[IMX8MM_CLK_CLKOUT1_DIV] = imx_clk_hw_divider("clkout1_div", "clkout1_sel", base + 0x128, 0, 4);
+	hws[IMX8MM_CLK_CLKOUT1] = imx_clk_hw_gate("clkout1", "clkout1_div", base + 0x128, 8);
+	hws[IMX8MM_CLK_CLKOUT2_SEL] = imx_clk_hw_mux("clkout2_sel", base + 0x128, 20, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+	hws[IMX8MM_CLK_CLKOUT2_DIV] = imx_clk_hw_divider("clkout2_div", "clkout2_sel", base + 0x128, 16, 4);
+	hws[IMX8MM_CLK_CLKOUT2] = imx_clk_hw_gate("clkout2", "clkout2_div", base + 0x128, 24);
 
 	np = dev->of_node;
 	base = devm_platform_ioremap_resource(pdev, 0);
@@ -458,204 +412,227 @@
 		return PTR_ERR(base);
 
 	/* Core Slice */
-	clks[IMX8MM_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels));
-	clks[IMX8MM_CLK_M4_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels));
-	clks[IMX8MM_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels));
-	clks[IMX8MM_CLK_GPU3D_SRC] = imx_clk_mux2("gpu3d_src", base + 0x8180, 24, 3,  imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels));
-	clks[IMX8MM_CLK_GPU2D_SRC] = imx_clk_mux2("gpu2d_src", base + 0x8200, 24, 3, imx8mm_gpu2d_sels,  ARRAY_SIZE(imx8mm_gpu2d_sels));
-	clks[IMX8MM_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
-	clks[IMX8MM_CLK_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
-	clks[IMX8MM_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
-	clks[IMX8MM_CLK_GPU3D_CG] = imx_clk_gate3("gpu3d_cg", "gpu3d_src", base + 0x8180, 28);
-	clks[IMX8MM_CLK_GPU2D_CG] = imx_clk_gate3("gpu2d_cg", "gpu2d_src", base + 0x8200, 28);
-	clks[IMX8MM_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
-	clks[IMX8MM_CLK_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
-	clks[IMX8MM_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
-	clks[IMX8MM_CLK_GPU3D_DIV] = imx_clk_divider2("gpu3d_div", "gpu3d_cg", base + 0x8180, 0, 3);
-	clks[IMX8MM_CLK_GPU2D_DIV] = imx_clk_divider2("gpu2d_div", "gpu2d_cg", base + 0x8200, 0, 3);
+	hws[IMX8MM_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mm_a53_sels, base + 0x8000);
+	hws[IMX8MM_CLK_A53_CG] = hws[IMX8MM_CLK_A53_DIV];
+	hws[IMX8MM_CLK_A53_SRC] = hws[IMX8MM_CLK_A53_DIV];
+
+	hws[IMX8MM_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mm_m4_sels, base + 0x8080);
+	hws[IMX8MM_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mm_vpu_sels, base + 0x8100);
+	hws[IMX8MM_CLK_GPU3D_CORE] = imx8m_clk_hw_composite_core("gpu3d_core", imx8mm_gpu3d_sels, base + 0x8180);
+	hws[IMX8MM_CLK_GPU2D_CORE] = imx8m_clk_hw_composite_core("gpu2d_core", imx8mm_gpu2d_sels, base + 0x8200);
+
+	/* For backwards compatibility */
+	hws[IMX8MM_CLK_M4_SRC] = hws[IMX8MM_CLK_M4_CORE];
+	hws[IMX8MM_CLK_M4_CG] = hws[IMX8MM_CLK_M4_CORE];
+	hws[IMX8MM_CLK_M4_DIV] = hws[IMX8MM_CLK_M4_CORE];
+	hws[IMX8MM_CLK_VPU_SRC] = hws[IMX8MM_CLK_VPU_CORE];
+	hws[IMX8MM_CLK_VPU_CG] = hws[IMX8MM_CLK_VPU_CORE];
+	hws[IMX8MM_CLK_VPU_DIV] = hws[IMX8MM_CLK_VPU_CORE];
+	hws[IMX8MM_CLK_GPU3D_SRC] = hws[IMX8MM_CLK_GPU3D_CORE];
+	hws[IMX8MM_CLK_GPU3D_CG] = hws[IMX8MM_CLK_GPU3D_CORE];
+	hws[IMX8MM_CLK_GPU3D_DIV] = hws[IMX8MM_CLK_GPU3D_CORE];
+	hws[IMX8MM_CLK_GPU2D_SRC] = hws[IMX8MM_CLK_GPU2D_CORE];
+	hws[IMX8MM_CLK_GPU2D_CG] = hws[IMX8MM_CLK_GPU2D_CORE];
+	hws[IMX8MM_CLK_GPU2D_DIV] = hws[IMX8MM_CLK_GPU2D_CORE];
+
+	/* CORE SEL */
+	hws[IMX8MM_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mm_a53_core_sels, ARRAY_SIZE(imx8mm_a53_core_sels));
 
 	/* BUS */
-	clks[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi",  imx8mm_main_axi_sels, base + 0x8800);
-	clks[IMX8MM_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
-	clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
-	clks[IMX8MM_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
-	clks[IMX8MM_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
-	clks[IMX8MM_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
-	clks[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mm_disp_rtrm_sels, base + 0x8b00);
-	clks[IMX8MM_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80);
-	clks[IMX8MM_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mm_gpu_axi_sels, base + 0x8c00);
-	clks[IMX8MM_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mm_gpu_ahb_sels, base + 0x8c80);
-	clks[IMX8MM_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mm_noc_sels, base + 0x8d00);
-	clks[IMX8MM_CLK_NOC_APB] = imx8m_clk_composite_critical("noc_apb", imx8mm_noc_apb_sels, base + 0x8d80);
+	hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi",  imx8mm_main_axi_sels, base + 0x8800);
+	hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
+	hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
+	hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
+	hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
+	hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
+	hws[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_hw_composite_bus("disp_rtrm", imx8mm_disp_rtrm_sels, base + 0x8b00);
+	hws[IMX8MM_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80);
+	hws[IMX8MM_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mm_gpu_axi_sels, base + 0x8c00);
+	hws[IMX8MM_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mm_gpu_ahb_sels, base + 0x8c80);
+	hws[IMX8MM_CLK_NOC] = imx8m_clk_hw_composite_bus_critical("noc", imx8mm_noc_sels, base + 0x8d00);
+	hws[IMX8MM_CLK_NOC_APB] = imx8m_clk_hw_composite_bus_critical("noc_apb", imx8mm_noc_apb_sels, base + 0x8d80);
 
 	/* AHB */
-	clks[IMX8MM_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels, base + 0x9000);
-	clks[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mm_audio_ahb_sels, base + 0x9100);
+	hws[IMX8MM_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb", imx8mm_ahb_sels, base + 0x9000);
+	hws[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mm_audio_ahb_sels, base + 0x9100);
 
 	/* IPG */
-	clks[IMX8MM_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
-	clks[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
+	hws[IMX8MM_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
+	hws[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
+
+	/*
+	 * DRAM clocks are manipulated from TF-A outside clock framework.
+	 * Mark with GET_RATE_NOCACHE to always read div value from hardware
+	 */
+	hws[IMX8MM_CLK_DRAM_ALT] = __imx8m_clk_hw_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000, CLK_GET_RATE_NOCACHE);
+	hws[IMX8MM_CLK_DRAM_APB] = __imx8m_clk_hw_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
 
 	/* IP */
-	clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000);
-	clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
-	clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
-	clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
-	clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
-	clks[IMX8MM_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mm_disp_dc8000_sels, base + 0xa280);
-	clks[IMX8MM_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels, base + 0xa300);
-	clks[IMX8MM_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mm_pcie1_phy_sels, base + 0xa380);
-	clks[IMX8MM_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mm_pcie1_aux_sels, base + 0xa400);
-	clks[IMX8MM_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mm_dc_pixel_sels, base + 0xa480);
-	clks[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mm_lcdif_pixel_sels, base + 0xa500);
-	clks[IMX8MM_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mm_sai1_sels, base + 0xa580);
-	clks[IMX8MM_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mm_sai2_sels, base + 0xa600);
-	clks[IMX8MM_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mm_sai3_sels, base + 0xa680);
-	clks[IMX8MM_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mm_sai4_sels, base + 0xa700);
-	clks[IMX8MM_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mm_sai5_sels, base + 0xa780);
-	clks[IMX8MM_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mm_sai6_sels, base + 0xa800);
-	clks[IMX8MM_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mm_spdif1_sels, base + 0xa880);
-	clks[IMX8MM_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mm_spdif2_sels, base + 0xa900);
-	clks[IMX8MM_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mm_enet_ref_sels, base + 0xa980);
-	clks[IMX8MM_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mm_enet_timer_sels, base + 0xaa00);
-	clks[IMX8MM_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mm_enet_phy_sels, base + 0xaa80);
-	clks[IMX8MM_CLK_NAND] = imx8m_clk_composite("nand", imx8mm_nand_sels, base + 0xab00);
-	clks[IMX8MM_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80);
-	clks[IMX8MM_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels, base + 0xac00);
-	clks[IMX8MM_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels, base + 0xac80);
-	clks[IMX8MM_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00);
-	clks[IMX8MM_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80);
-	clks[IMX8MM_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00);
-	clks[IMX8MM_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80);
-	clks[IMX8MM_CLK_UART1] = imx8m_clk_composite("uart1", imx8mm_uart1_sels, base + 0xaf00);
-	clks[IMX8MM_CLK_UART2] = imx8m_clk_composite("uart2", imx8mm_uart2_sels, base + 0xaf80);
-	clks[IMX8MM_CLK_UART3] = imx8m_clk_composite("uart3", imx8mm_uart3_sels, base + 0xb000);
-	clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, base + 0xb080);
-	clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100);
-	clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180);
-	clks[IMX8MM_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mm_gic_sels, base + 0xb200);
-	clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280);
-	clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300);
-	clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380);
-	clks[IMX8MM_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mm_pwm2_sels, base + 0xb400);
-	clks[IMX8MM_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mm_pwm3_sels, base + 0xb480);
-	clks[IMX8MM_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mm_pwm4_sels, base + 0xb500);
-	clks[IMX8MM_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mm_gpt1_sels, base + 0xb580);
-	clks[IMX8MM_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900);
-	clks[IMX8MM_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mm_wrclk_sels, base + 0xb980);
-	clks[IMX8MM_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mm_clko1_sels, base + 0xba00);
-	clks[IMX8MM_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mm_dsi_core_sels, base + 0xbb00);
-	clks[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, base + 0xbb80);
-	clks[IMX8MM_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mm_dsi_dbi_sels, base + 0xbc00);
-	clks[IMX8MM_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels, base + 0xbc80);
-	clks[IMX8MM_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mm_csi1_core_sels, base + 0xbd00);
-	clks[IMX8MM_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mm_csi1_phy_sels, base + 0xbd80);
-	clks[IMX8MM_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mm_csi1_esc_sels, base + 0xbe00);
-	clks[IMX8MM_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mm_csi2_core_sels, base + 0xbe80);
-	clks[IMX8MM_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mm_csi2_phy_sels, base + 0xbf00);
-	clks[IMX8MM_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mm_csi2_esc_sels, base + 0xbf80);
-	clks[IMX8MM_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mm_pcie2_ctrl_sels, base + 0xc000);
-	clks[IMX8MM_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mm_pcie2_phy_sels, base + 0xc080);
-	clks[IMX8MM_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mm_pcie2_aux_sels, base + 0xc100);
-	clks[IMX8MM_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mm_ecspi3_sels, base + 0xc180);
-	clks[IMX8MM_CLK_PDM] = imx8m_clk_composite("pdm", imx8mm_pdm_sels, base + 0xc200);
-	clks[IMX8MM_CLK_VPU_H1] = imx8m_clk_composite("vpu_h1", imx8mm_vpu_h1_sels, base + 0xc280);
+	hws[IMX8MM_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
+	hws[IMX8MM_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
+	hws[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_hw_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
+	hws[IMX8MM_CLK_DISP_DC8000] = imx8m_clk_hw_composite("disp_dc8000", imx8mm_disp_dc8000_sels, base + 0xa280);
+	hws[IMX8MM_CLK_PCIE1_CTRL] = imx8m_clk_hw_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels, base + 0xa300);
+	hws[IMX8MM_CLK_PCIE1_PHY] = imx8m_clk_hw_composite("pcie1_phy", imx8mm_pcie1_phy_sels, base + 0xa380);
+	hws[IMX8MM_CLK_PCIE1_AUX] = imx8m_clk_hw_composite("pcie1_aux", imx8mm_pcie1_aux_sels, base + 0xa400);
+	hws[IMX8MM_CLK_DC_PIXEL] = imx8m_clk_hw_composite("dc_pixel", imx8mm_dc_pixel_sels, base + 0xa480);
+	hws[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_hw_composite("lcdif_pixel", imx8mm_lcdif_pixel_sels, base + 0xa500);
+	hws[IMX8MM_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mm_sai1_sels, base + 0xa580);
+	hws[IMX8MM_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mm_sai2_sels, base + 0xa600);
+	hws[IMX8MM_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mm_sai3_sels, base + 0xa680);
+	hws[IMX8MM_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mm_sai4_sels, base + 0xa700);
+	hws[IMX8MM_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mm_sai5_sels, base + 0xa780);
+	hws[IMX8MM_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mm_sai6_sels, base + 0xa800);
+	hws[IMX8MM_CLK_SPDIF1] = imx8m_clk_hw_composite("spdif1", imx8mm_spdif1_sels, base + 0xa880);
+	hws[IMX8MM_CLK_SPDIF2] = imx8m_clk_hw_composite("spdif2", imx8mm_spdif2_sels, base + 0xa900);
+	hws[IMX8MM_CLK_ENET_REF] = imx8m_clk_hw_composite("enet_ref", imx8mm_enet_ref_sels, base + 0xa980);
+	hws[IMX8MM_CLK_ENET_TIMER] = imx8m_clk_hw_composite("enet_timer", imx8mm_enet_timer_sels, base + 0xaa00);
+	hws[IMX8MM_CLK_ENET_PHY_REF] = imx8m_clk_hw_composite("enet_phy", imx8mm_enet_phy_sels, base + 0xaa80);
+	hws[IMX8MM_CLK_NAND] = imx8m_clk_hw_composite("nand", imx8mm_nand_sels, base + 0xab00);
+	hws[IMX8MM_CLK_QSPI] = imx8m_clk_hw_composite("qspi", imx8mm_qspi_sels, base + 0xab80);
+	hws[IMX8MM_CLK_USDHC1] = imx8m_clk_hw_composite("usdhc1", imx8mm_usdhc1_sels, base + 0xac00);
+	hws[IMX8MM_CLK_USDHC2] = imx8m_clk_hw_composite("usdhc2", imx8mm_usdhc2_sels, base + 0xac80);
+	hws[IMX8MM_CLK_I2C1] = imx8m_clk_hw_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00);
+	hws[IMX8MM_CLK_I2C2] = imx8m_clk_hw_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80);
+	hws[IMX8MM_CLK_I2C3] = imx8m_clk_hw_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00);
+	hws[IMX8MM_CLK_I2C4] = imx8m_clk_hw_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80);
+	hws[IMX8MM_CLK_UART1] = imx8m_clk_hw_composite("uart1", imx8mm_uart1_sels, base + 0xaf00);
+	hws[IMX8MM_CLK_UART2] = imx8m_clk_hw_composite("uart2", imx8mm_uart2_sels, base + 0xaf80);
+	hws[IMX8MM_CLK_UART3] = imx8m_clk_hw_composite("uart3", imx8mm_uart3_sels, base + 0xb000);
+	hws[IMX8MM_CLK_UART4] = imx8m_clk_hw_composite("uart4", imx8mm_uart4_sels, base + 0xb080);
+	hws[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_hw_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100);
+	hws[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_hw_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180);
+	hws[IMX8MM_CLK_GIC] = imx8m_clk_hw_composite_critical("gic", imx8mm_gic_sels, base + 0xb200);
+	hws[IMX8MM_CLK_ECSPI1] = imx8m_clk_hw_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280);
+	hws[IMX8MM_CLK_ECSPI2] = imx8m_clk_hw_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300);
+	hws[IMX8MM_CLK_PWM1] = imx8m_clk_hw_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380);
+	hws[IMX8MM_CLK_PWM2] = imx8m_clk_hw_composite("pwm2", imx8mm_pwm2_sels, base + 0xb400);
+	hws[IMX8MM_CLK_PWM3] = imx8m_clk_hw_composite("pwm3", imx8mm_pwm3_sels, base + 0xb480);
+	hws[IMX8MM_CLK_PWM4] = imx8m_clk_hw_composite("pwm4", imx8mm_pwm4_sels, base + 0xb500);
+	hws[IMX8MM_CLK_GPT1] = imx8m_clk_hw_composite("gpt1", imx8mm_gpt1_sels, base + 0xb580);
+	hws[IMX8MM_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mm_wdog_sels, base + 0xb900);
+	hws[IMX8MM_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mm_wrclk_sels, base + 0xb980);
+	hws[IMX8MM_CLK_CLKO1] = imx8m_clk_hw_composite("clko1", imx8mm_clko1_sels, base + 0xba00);
+	hws[IMX8MM_CLK_CLKO2] = imx8m_clk_hw_composite("clko2", imx8mm_clko2_sels, base + 0xba80);
+	hws[IMX8MM_CLK_DSI_CORE] = imx8m_clk_hw_composite("dsi_core", imx8mm_dsi_core_sels, base + 0xbb00);
+	hws[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_hw_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, base + 0xbb80);
+	hws[IMX8MM_CLK_DSI_DBI] = imx8m_clk_hw_composite("dsi_dbi", imx8mm_dsi_dbi_sels, base + 0xbc00);
+	hws[IMX8MM_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mm_usdhc3_sels, base + 0xbc80);
+	hws[IMX8MM_CLK_CSI1_CORE] = imx8m_clk_hw_composite("csi1_core", imx8mm_csi1_core_sels, base + 0xbd00);
+	hws[IMX8MM_CLK_CSI1_PHY_REF] = imx8m_clk_hw_composite("csi1_phy_ref", imx8mm_csi1_phy_sels, base + 0xbd80);
+	hws[IMX8MM_CLK_CSI1_ESC] = imx8m_clk_hw_composite("csi1_esc", imx8mm_csi1_esc_sels, base + 0xbe00);
+	hws[IMX8MM_CLK_CSI2_CORE] = imx8m_clk_hw_composite("csi2_core", imx8mm_csi2_core_sels, base + 0xbe80);
+	hws[IMX8MM_CLK_CSI2_PHY_REF] = imx8m_clk_hw_composite("csi2_phy_ref", imx8mm_csi2_phy_sels, base + 0xbf00);
+	hws[IMX8MM_CLK_CSI2_ESC] = imx8m_clk_hw_composite("csi2_esc", imx8mm_csi2_esc_sels, base + 0xbf80);
+	hws[IMX8MM_CLK_PCIE2_CTRL] = imx8m_clk_hw_composite("pcie2_ctrl", imx8mm_pcie2_ctrl_sels, base + 0xc000);
+	hws[IMX8MM_CLK_PCIE2_PHY] = imx8m_clk_hw_composite("pcie2_phy", imx8mm_pcie2_phy_sels, base + 0xc080);
+	hws[IMX8MM_CLK_PCIE2_AUX] = imx8m_clk_hw_composite("pcie2_aux", imx8mm_pcie2_aux_sels, base + 0xc100);
+	hws[IMX8MM_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mm_ecspi3_sels, base + 0xc180);
+	hws[IMX8MM_CLK_PDM] = imx8m_clk_hw_composite("pdm", imx8mm_pdm_sels, base + 0xc200);
+	hws[IMX8MM_CLK_VPU_H1] = imx8m_clk_hw_composite("vpu_h1", imx8mm_vpu_h1_sels, base + 0xc280);
 
 	/* CCGR */
-	clks[IMX8MM_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
-	clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
-	clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
-	clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
-	clks[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
-	clks[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
-	clks[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
-	clks[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
-	clks[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
-	clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
-	clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
-	clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
-	clks[IMX8MM_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
-	clks[IMX8MM_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
-	clks[IMX8MM_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
-	clks[IMX8MM_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
-	clks[IMX8MM_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
-	clks[IMX8MM_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
-	clks[IMX8MM_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
-	clks[IMX8MM_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
-	clks[IMX8MM_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
-	clks[IMX8MM_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
-	clks[IMX8MM_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MM_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1);
-	clks[IMX8MM_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
-	clks[IMX8MM_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MM_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MM_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MM_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MM_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4);
-	clks[IMX8MM_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
-	clks[IMX8MM_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MM_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
-	clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
-	clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
-	clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
-	clks[IMX8MM_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
-	clks[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
-	clks[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_gate4("gpu3d_root_clk", "gpu3d_div", base + 0x44f0, 0);
-	clks[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
-	clks[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
-	clks[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
-	clks[IMX8MM_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
-	clks[IMX8MM_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
-	clks[IMX8MM_CLK_VPU_G1_ROOT] = imx_clk_gate4("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0);
-	clks[IMX8MM_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0);
-	clks[IMX8MM_CLK_VPU_H1_ROOT] = imx_clk_gate4("vpu_h1_root_clk", "vpu_h1", base + 0x4590, 0);
-	clks[IMX8MM_CLK_VPU_G2_ROOT] = imx_clk_gate4("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0);
-	clks[IMX8MM_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm);
-	clks[IMX8MM_CLK_PDM_IPG]  = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm);
-	clks[IMX8MM_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MM_CLK_DISP_AXI_ROOT]  = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MM_CLK_DISP_APB_ROOT]  = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MM_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MM_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0);
-	clks[IMX8MM_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
-	clks[IMX8MM_CLK_VPU_DEC_ROOT] = imx_clk_gate4("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0);
-	clks[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
-	clks[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
-	clks[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
-	clks[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_gate4("gpu2d_root_clk", "gpu2d_div", base + 0x4660, 0);
-	clks[IMX8MM_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
-
-	clks[IMX8MM_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc_24m", 1, 8);
-
-	clks[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
-	clks[IMX8MM_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL);
-
-	clks[IMX8MM_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div",
-					   clks[IMX8MM_CLK_A53_DIV],
-					   clks[IMX8MM_CLK_A53_SRC],
-					   clks[IMX8MM_ARM_PLL_OUT],
-					   clks[IMX8MM_SYS_PLL1_800M]);
-
-	imx_check_clocks(clks, ARRAY_SIZE(clks));
-
-	clk_data.clks = clks;
-	clk_data.clk_num = ARRAY_SIZE(clks);
-	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	hws[IMX8MM_CLK_ECSPI1_ROOT] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
+	hws[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
+	hws[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
+	hws[IMX8MM_CLK_ENET1_ROOT] = imx_clk_hw_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+	hws[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_hw_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+	hws[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_hw_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+	hws[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_hw_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+	hws[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_hw_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+	hws[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_hw_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
+	hws[IMX8MM_CLK_GPT1_ROOT] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
+	hws[IMX8MM_CLK_I2C1_ROOT] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
+	hws[IMX8MM_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
+	hws[IMX8MM_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
+	hws[IMX8MM_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
+	hws[IMX8MM_CLK_MU_ROOT] = imx_clk_hw_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
+	hws[IMX8MM_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
+	hws[IMX8MM_CLK_PCIE1_ROOT] = imx_clk_hw_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
+	hws[IMX8MM_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
+	hws[IMX8MM_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
+	hws[IMX8MM_CLK_PWM3_ROOT] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
+	hws[IMX8MM_CLK_PWM4_ROOT] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
+	hws[IMX8MM_CLK_QSPI_ROOT] = imx_clk_hw_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
+	hws[IMX8MM_CLK_NAND_ROOT] = imx_clk_hw_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MM_CLK_SAI1_ROOT] = imx_clk_hw_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1);
+	hws[IMX8MM_CLK_SAI1_IPG] = imx_clk_hw_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
+	hws[IMX8MM_CLK_SAI2_ROOT] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MM_CLK_SAI2_IPG] = imx_clk_hw_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MM_CLK_SAI3_ROOT] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MM_CLK_SAI3_IPG] = imx_clk_hw_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MM_CLK_SAI4_ROOT] = imx_clk_hw_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4);
+	hws[IMX8MM_CLK_SAI4_IPG] = imx_clk_hw_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
+	hws[IMX8MM_CLK_SAI5_ROOT] = imx_clk_hw_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MM_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MM_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MM_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MM_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+	hws[IMX8MM_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
+	hws[IMX8MM_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
+	hws[IMX8MM_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
+	hws[IMX8MM_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
+	hws[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
+	hws[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core", base + 0x44f0, 0);
+	hws[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
+	hws[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
+	hws[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
+	hws[IMX8MM_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
+	hws[IMX8MM_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
+	hws[IMX8MM_CLK_VPU_G1_ROOT] = imx_clk_hw_gate4("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0);
+	hws[IMX8MM_CLK_GPU_BUS_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0);
+	hws[IMX8MM_CLK_VPU_H1_ROOT] = imx_clk_hw_gate4("vpu_h1_root_clk", "vpu_h1", base + 0x4590, 0);
+	hws[IMX8MM_CLK_VPU_G2_ROOT] = imx_clk_hw_gate4("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0);
+	hws[IMX8MM_CLK_PDM_ROOT] = imx_clk_hw_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm);
+	hws[IMX8MM_CLK_PDM_IPG]  = imx_clk_hw_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm);
+	hws[IMX8MM_CLK_DISP_ROOT] = imx_clk_hw_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MM_CLK_DISP_AXI_ROOT]  = imx_clk_hw_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MM_CLK_DISP_APB_ROOT]  = imx_clk_hw_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MM_CLK_DISP_RTRM_ROOT] = imx_clk_hw_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MM_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0);
+	hws[IMX8MM_CLK_TMU_ROOT] = imx_clk_hw_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+	hws[IMX8MM_CLK_VPU_DEC_ROOT] = imx_clk_hw_gate4("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0);
+	hws[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+	hws[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
+	hws[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
+	hws[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_core", base + 0x4660, 0);
+	hws[IMX8MM_CLK_CSI1_ROOT] = imx_clk_hw_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
+
+	hws[IMX8MM_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8);
+
+	hws[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+	hws[IMX8MM_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL);
+
+	hws[IMX8MM_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
+					   hws[IMX8MM_CLK_A53_CORE]->clk,
+					   hws[IMX8MM_CLK_A53_CORE]->clk,
+					   hws[IMX8MM_ARM_PLL_OUT]->clk,
+					   hws[IMX8MM_CLK_A53_DIV]->clk);
+
+	imx_check_clk_hws(hws, IMX8MM_CLK_END);
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 	if (ret < 0) {
-		pr_err("failed to register clks for i.MX8MM\n");
-		goto unregister_clks;
+		dev_err(dev, "failed to register clks for i.MX8MM\n");
+		goto unregister_hws;
 	}
 
-	imx_register_uart_clocks(uart_clks);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+		int index = uart_clk_ids[i];
+
+		uart_hws[i] = &hws[index]->clk;
+	}
+
+	imx_register_uart_clocks(uart_hws);
+
+	clk_hw_set_parent(hws[IMX8MM_CLK_PCIE1_CTRL], hws[IMX8MM_SYS_PLL2_250M]);
+	clk_hw_set_parent(hws[IMX8MM_CLK_PCIE1_PHY], hws[IMX8MM_SYS_PLL2_100M]);
 
 	return 0;
 
-unregister_clks:
-	imx_unregister_clocks(clks, ARRAY_SIZE(clks));
+unregister_hws:
+	imx_unregister_hw_clocks(hws, IMX8MM_CLK_END);
 
 	return ret;
 }
@@ -670,7 +647,16 @@
 	.probe = imx8mm_clocks_probe,
 	.driver = {
 		.name = "imx8mm-ccm",
-		.of_match_table = of_match_ptr(imx8mm_clk_of_match),
+		/*
+		 * Disable bind attributes: clocks are not removed and
+		 * reloading the driver will crash or break devices.
+		 */
+		.suppress_bind_attrs = true,
+		.of_match_table = imx8mm_clk_of_match,
 	},
 };
 module_platform_driver(imx8mm_clk_driver);
+
+MODULE_AUTHOR("Bai Ping <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8MM clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8mn.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8mn.c
@@ -4,14 +4,13 @@
  */
 
 #include <dt-bindings/clock/imx8mn-clock.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 #include "clk.h"
@@ -25,89 +24,6 @@
 static u32 share_count_pdm;
 static u32 share_count_nand;
 
-enum {
-	ARM_PLL,
-	GPU_PLL,
-	VPU_PLL,
-	SYS_PLL1,
-	SYS_PLL2,
-	SYS_PLL3,
-	DRAM_PLL,
-	AUDIO_PLL1,
-	AUDIO_PLL2,
-	VIDEO_PLL2,
-	NR_PLLS,
-};
-
-static const struct imx_pll14xx_rate_table imx8mn_pll1416x_tbl[] = {
-	PLL_1416X_RATE(1800000000U, 225, 3, 0),
-	PLL_1416X_RATE(1600000000U, 200, 3, 0),
-	PLL_1416X_RATE(1500000000U, 375, 3, 1),
-	PLL_1416X_RATE(1400000000U, 350, 3, 1),
-	PLL_1416X_RATE(1200000000U, 300, 3, 1),
-	PLL_1416X_RATE(1000000000U, 250, 3, 1),
-	PLL_1416X_RATE(800000000U,  200, 3, 1),
-	PLL_1416X_RATE(750000000U,  250, 2, 2),
-	PLL_1416X_RATE(700000000U,  350, 3, 2),
-	PLL_1416X_RATE(600000000U,  300, 3, 2),
-};
-
-static const struct imx_pll14xx_rate_table imx8mn_audiopll_tbl[] = {
-	PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
-	PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
-};
-
-static const struct imx_pll14xx_rate_table imx8mn_videopll_tbl[] = {
-	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
-	PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
-};
-
-static const struct imx_pll14xx_rate_table imx8mn_drampll_tbl[] = {
-	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
-};
-
-static struct imx_pll14xx_clk imx8mn_audio_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mn_audiopll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_audiopll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_video_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mn_videopll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_videopll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_dram_pll = {
-		.type = PLL_1443X,
-		.rate_table = imx8mn_drampll_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_drampll_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_arm_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mn_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_gpu_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mn_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_vpu_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mn_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl),
-};
-
-static struct imx_pll14xx_clk imx8mn_sys_pll = {
-		.type = PLL_1416X,
-		.rate_table = imx8mn_pll1416x_tbl,
-		.rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl),
-};
-
 static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
 static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
 static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
@@ -116,14 +32,14 @@
 static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
 static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
 static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
-static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
-static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
 static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
 
 static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
 					       "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
 					       "audio_pll1_out", "sys_pll3_out", };
 
+static const char * const imx8mn_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
+
 static const char * const imx8mn_gpu_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
 						    "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
 						    "video_pll1_out", "audio_pll2_out", };
@@ -189,27 +105,27 @@
 						      "sys_pll3_out", "clk_ext4", };
 
 static const char * const imx8mn_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"video_pll1_out", "sys_pll1_133m", "dummy",
 						"clk_ext3", "clk_ext4", };
 
 static const char * const imx8mn_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"video_pll1_out", "sys_pll1_133m", "dummy",
 						"clk_ext3", "clk_ext4", };
 
 static const char * const imx8mn_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"video_pll1_out", "sys_pll1_133m", "dummy",
 						"clk_ext2", "clk_ext3", };
 
 static const char * const imx8mn_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"video_pll1_out", "sys_pll1_133m", "dummy",
 						"clk_ext3", "clk_ext4", };
 
 static const char * const imx8mn_sai7_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"video_pll1_out", "sys_pll1_133m", "dummy",
 						"clk_ext3", "clk_ext4", };
 
 static const char * const imx8mn_spdif1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
-						  "video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						  "video_pll1_out", "sys_pll1_133m", "dummy",
 						  "clk_ext2", "clk_ext3", };
 
 static const char * const imx8mn_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
@@ -358,276 +274,313 @@
 
 static const char * const imx8mn_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
 
-static const char * const imx8mn_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m",
-						 "sys_pll1_200m", "audio_pll2_out", "vpu_pll",
-						 "sys_pll1_80m", };
+static const char * const imx8mn_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "dummy",
+						 "sys_pll1_200m", "audio_pll2_out", "sys_pll2_500m",
+						 "dummy", "sys_pll1_80m", };
 static const char * const imx8mn_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m",
 						 "sys_pll2_166m", "sys_pll3_out", "audio_pll1_out",
 						 "video_pll1_out", "osc_32k", };
 
-static struct clk *clks[IMX8MN_CLK_END];
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] = {
-	&clks[IMX8MN_CLK_UART1_ROOT],
-	&clks[IMX8MN_CLK_UART2_ROOT],
-	&clks[IMX8MN_CLK_UART3_ROOT],
-	&clks[IMX8MN_CLK_UART4_ROOT],
-	NULL
+static const char * const clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+					   "dummy", "dummy", "gpu_pll_out", "dummy",
+					   "arm_pll_out", "sys_pll1", "sys_pll2", "sys_pll3",
+					   "dummy", "dummy", "osc_24m", "dummy", "osc_32k"};
+
+static struct clk_hw_onecell_data *clk_hw_data;
+static struct clk_hw **hws;
+
+static const int uart_clk_ids[] = {
+	IMX8MN_CLK_UART1_ROOT,
+	IMX8MN_CLK_UART2_ROOT,
+	IMX8MN_CLK_UART3_ROOT,
+	IMX8MN_CLK_UART4_ROOT,
 };
+static struct clk **uart_hws[ARRAY_SIZE(uart_clk_ids) + 1];
 
 static int imx8mn_clocks_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	void __iomem *base;
-	int ret;
+	int ret, i;
 
-	clks[IMX8MN_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-	clks[IMX8MN_CLK_24M] = of_clk_get_by_name(np, "osc_24m");
-	clks[IMX8MN_CLK_32K] = of_clk_get_by_name(np, "osc_32k");
-	clks[IMX8MN_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1");
-	clks[IMX8MN_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2");
-	clks[IMX8MN_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3");
-	clks[IMX8MN_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4");
+	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+					  IMX8MN_CLK_END), GFP_KERNEL);
+	if (WARN_ON(!clk_hw_data))
+		return -ENOMEM;
+
+	clk_hw_data->num = IMX8MN_CLK_END;
+	hws = clk_hw_data->hws;
+
+	hws[IMX8MN_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+	hws[IMX8MN_CLK_24M] = imx_obtain_fixed_clk_hw(np, "osc_24m");
+	hws[IMX8MN_CLK_32K] = imx_obtain_fixed_clk_hw(np, "osc_32k");
+	hws[IMX8MN_CLK_EXT1] = imx_obtain_fixed_clk_hw(np, "clk_ext1");
+	hws[IMX8MN_CLK_EXT2] = imx_obtain_fixed_clk_hw(np, "clk_ext2");
+	hws[IMX8MN_CLK_EXT3] = imx_obtain_fixed_clk_hw(np, "clk_ext3");
+	hws[IMX8MN_CLK_EXT4] = imx_obtain_fixed_clk_hw(np, "clk_ext4");
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx8mn-anatop");
 	base = of_iomap(np, 0);
+	of_node_put(np);
 	if (WARN_ON(!base)) {
 		ret = -ENOMEM;
-		goto unregister_clks;
+		goto unregister_hws;
 	}
 
-	clks[IMX8MN_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_SYS_PLL1_REF_SEL] = imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MN_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-
-	clks[IMX8MN_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx8mn_audio_pll);
-	clks[IMX8MN_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mn_audio_pll);
-	clks[IMX8MN_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mn_video_pll);
-	clks[IMX8MN_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mn_dram_pll);
-	clks[IMX8MN_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mn_gpu_pll);
-	clks[IMX8MN_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mn_vpu_pll);
-	clks[IMX8MN_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mn_arm_pll);
-	clks[IMX8MN_SYS_PLL1] = imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mn_sys_pll);
-	clks[IMX8MN_SYS_PLL2] = imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mn_sys_pll);
-	clks[IMX8MN_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mn_sys_pll);
+	hws[IMX8MN_AUDIO_PLL1_REF_SEL] = imx_clk_hw_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_AUDIO_PLL2_REF_SEL] = imx_clk_hw_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_VIDEO_PLL1_REF_SEL] = imx_clk_hw_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_DRAM_PLL_REF_SEL] = imx_clk_hw_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_VPU_PLL_REF_SEL] = imx_clk_hw_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MN_SYS_PLL3_REF_SEL] = imx_clk_hw_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+	hws[IMX8MN_AUDIO_PLL1] = imx_clk_hw_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx_1443x_pll);
+	hws[IMX8MN_AUDIO_PLL2] = imx_clk_hw_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx_1443x_pll);
+	hws[IMX8MN_VIDEO_PLL1] = imx_clk_hw_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx_1443x_pll);
+	hws[IMX8MN_DRAM_PLL] = imx_clk_hw_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx_1443x_dram_pll);
+	hws[IMX8MN_GPU_PLL] = imx_clk_hw_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx_1416x_pll);
+	hws[IMX8MN_VPU_PLL] = imx_clk_hw_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx_1416x_pll);
+	hws[IMX8MN_ARM_PLL] = imx_clk_hw_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx_1416x_pll);
+	hws[IMX8MN_SYS_PLL1] = imx_clk_hw_fixed("sys_pll1", 800000000);
+	hws[IMX8MN_SYS_PLL2] = imx_clk_hw_fixed("sys_pll2", 1000000000);
+	hws[IMX8MN_SYS_PLL3] = imx_clk_hw_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx_1416x_pll);
 
 	/* PLL bypass out */
-	clks[IMX8MN_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", base + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", base + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", base + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_SYS_PLL1_BYPASS] = imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 28, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_SYS_PLL2_BYPASS] = imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 28, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MN_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_AUDIO_PLL1_BYPASS] = imx_clk_hw_mux_flags("audio_pll1_bypass", base, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_AUDIO_PLL2_BYPASS] = imx_clk_hw_mux_flags("audio_pll2_bypass", base + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_VIDEO_PLL1_BYPASS] = imx_clk_hw_mux_flags("video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_DRAM_PLL_BYPASS] = imx_clk_hw_mux_flags("dram_pll_bypass", base + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_GPU_PLL_BYPASS] = imx_clk_hw_mux_flags("gpu_pll_bypass", base + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_VPU_PLL_BYPASS] = imx_clk_hw_mux_flags("vpu_pll_bypass", base + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_ARM_PLL_BYPASS] = imx_clk_hw_mux_flags("arm_pll_bypass", base + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MN_SYS_PLL3_BYPASS] = imx_clk_hw_mux_flags("sys_pll3_bypass", base + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
 
 	/* PLL out gate */
-	clks[IMX8MN_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base, 13);
-	clks[IMX8MN_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13);
-	clks[IMX8MN_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13);
-	clks[IMX8MN_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13);
-	clks[IMX8MN_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 11);
-	clks[IMX8MN_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 11);
-	clks[IMX8MN_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11);
-	clks[IMX8MN_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11);
-	clks[IMX8MN_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 11);
-	clks[IMX8MN_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
-
-	/* SYS PLL fixed output */
-	clks[IMX8MN_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
-	clks[IMX8MN_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
-	clks[IMX8MN_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
-	clks[IMX8MN_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
-	clks[IMX8MN_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
-	clks[IMX8MN_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
-	clks[IMX8MN_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
-	clks[IMX8MN_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
-	clks[IMX8MN_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
-
-	clks[IMX8MN_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
-	clks[IMX8MN_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
-	clks[IMX8MN_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
-	clks[IMX8MN_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
-	clks[IMX8MN_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
-	clks[IMX8MN_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
-	clks[IMX8MN_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
-	clks[IMX8MN_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
-	clks[IMX8MN_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+	hws[IMX8MN_AUDIO_PLL1_OUT] = imx_clk_hw_gate("audio_pll1_out", "audio_pll1_bypass", base, 13);
+	hws[IMX8MN_AUDIO_PLL2_OUT] = imx_clk_hw_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13);
+	hws[IMX8MN_VIDEO_PLL1_OUT] = imx_clk_hw_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13);
+	hws[IMX8MN_DRAM_PLL_OUT] = imx_clk_hw_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13);
+	hws[IMX8MN_GPU_PLL_OUT] = imx_clk_hw_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 11);
+	hws[IMX8MN_VPU_PLL_OUT] = imx_clk_hw_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 11);
+	hws[IMX8MN_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11);
+	hws[IMX8MN_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
+
+	/* SYS PLL1 fixed output */
+	hws[IMX8MN_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
+
+	hws[IMX8MN_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+	hws[IMX8MN_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+	hws[IMX8MN_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+	hws[IMX8MN_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+	hws[IMX8MN_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+	hws[IMX8MN_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+	hws[IMX8MN_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+	hws[IMX8MN_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
+	hws[IMX8MN_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+	/* SYS PLL2 fixed output */
+	hws[IMX8MN_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
+
+	hws[IMX8MN_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+	hws[IMX8MN_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+	hws[IMX8MN_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+	hws[IMX8MN_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+	hws[IMX8MN_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+	hws[IMX8MN_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+	hws[IMX8MN_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+	hws[IMX8MN_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
+	hws[IMX8MN_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+	hws[IMX8MN_CLK_CLKOUT1_SEL] = imx_clk_hw_mux("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+	hws[IMX8MN_CLK_CLKOUT1_DIV] = imx_clk_hw_divider("clkout1_div", "clkout1_sel", base + 0x128, 0, 4);
+	hws[IMX8MN_CLK_CLKOUT1] = imx_clk_hw_gate("clkout1", "clkout1_div", base + 0x128, 8);
+	hws[IMX8MN_CLK_CLKOUT2_SEL] = imx_clk_hw_mux("clkout2_sel", base + 0x128, 20, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
+	hws[IMX8MN_CLK_CLKOUT2_DIV] = imx_clk_hw_divider("clkout2_div", "clkout2_sel", base + 0x128, 16, 4);
+	hws[IMX8MN_CLK_CLKOUT2] = imx_clk_hw_gate("clkout2", "clkout2_div", base + 0x128, 24);
 
 	np = dev->of_node;
 	base = devm_platform_ioremap_resource(pdev, 0);
 	if (WARN_ON(IS_ERR(base))) {
 		ret = PTR_ERR(base);
-		goto unregister_clks;
+		goto unregister_hws;
 	}
 
 	/* CORE */
-	clks[IMX8MN_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels));
-	clks[IMX8MN_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3,  imx8mn_gpu_core_sels, ARRAY_SIZE(imx8mn_gpu_core_sels));
-	clks[IMX8MN_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mn_gpu_shader_sels,  ARRAY_SIZE(imx8mn_gpu_shader_sels));
-	clks[IMX8MN_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
-	clks[IMX8MN_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
-	clks[IMX8MN_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
-
-	clks[IMX8MN_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
-	clks[IMX8MN_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
-	clks[IMX8MN_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
+	hws[IMX8MN_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mn_a53_sels, base + 0x8000);
+	hws[IMX8MN_CLK_A53_SRC] = hws[IMX8MN_CLK_A53_DIV];
+	hws[IMX8MN_CLK_A53_CG] = hws[IMX8MN_CLK_A53_DIV];
+
+	hws[IMX8MN_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mn_gpu_core_sels, base + 0x8180);
+	hws[IMX8MN_CLK_GPU_SHADER] = imx8m_clk_hw_composite_core("gpu_shader", imx8mn_gpu_shader_sels, base + 0x8200);
+
+	hws[IMX8MN_CLK_GPU_CORE_SRC] = hws[IMX8MN_CLK_GPU_CORE];
+	hws[IMX8MN_CLK_GPU_CORE_CG] = hws[IMX8MN_CLK_GPU_CORE];
+	hws[IMX8MN_CLK_GPU_CORE_DIV] = hws[IMX8MN_CLK_GPU_CORE];
+	hws[IMX8MN_CLK_GPU_SHADER_SRC] = hws[IMX8MN_CLK_GPU_SHADER];
+	hws[IMX8MN_CLK_GPU_SHADER_CG] = hws[IMX8MN_CLK_GPU_SHADER];
+	hws[IMX8MN_CLK_GPU_SHADER_DIV] = hws[IMX8MN_CLK_GPU_SHADER];
+
+	/* CORE SEL */
+	hws[IMX8MN_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mn_a53_core_sels, ARRAY_SIZE(imx8mn_a53_core_sels));
 
 	/* BUS */
-	clks[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800);
-	clks[IMX8MN_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mn_enet_axi_sels, base + 0x8880);
-	clks[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900);
-	clks[IMX8MN_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mn_disp_axi_sels, base + 0x8a00);
-	clks[IMX8MN_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mn_disp_apb_sels, base + 0x8a80);
-	clks[IMX8MN_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80);
-	clks[IMX8MN_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mn_gpu_axi_sels, base + 0x8c00);
-	clks[IMX8MN_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mn_gpu_ahb_sels, base + 0x8c80);
-	clks[IMX8MN_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mn_noc_sels, base + 0x8d00);
-
-	clks[IMX8MN_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels, base + 0x9000);
-	clks[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100);
-	clks[IMX8MN_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
-	clks[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
-	clks[IMX8MN_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL);
-	clks[IMX8MN_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000);
-	clks[IMX8MN_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mn_dram_apb_sels, base + 0xa080);
-	clks[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_composite("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500);
-	clks[IMX8MN_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mn_sai2_sels, base + 0xa600);
-	clks[IMX8MN_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mn_sai3_sels, base + 0xa680);
-	clks[IMX8MN_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mn_sai5_sels, base + 0xa780);
-	clks[IMX8MN_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mn_sai6_sels, base + 0xa800);
-	clks[IMX8MN_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mn_spdif1_sels, base + 0xa880);
-	clks[IMX8MN_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels, base + 0xa980);
-	clks[IMX8MN_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels, base + 0xaa00);
-	clks[IMX8MN_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels, base + 0xaa80);
-	clks[IMX8MN_CLK_NAND] = imx8m_clk_composite("nand", imx8mn_nand_sels, base + 0xab00);
-	clks[IMX8MN_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80);
-	clks[IMX8MN_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mn_usdhc1_sels, base + 0xac00);
-	clks[IMX8MN_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mn_usdhc2_sels, base + 0xac80);
-	clks[IMX8MN_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mn_i2c1_sels, base + 0xad00);
-	clks[IMX8MN_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mn_i2c2_sels, base + 0xad80);
-	clks[IMX8MN_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mn_i2c3_sels, base + 0xae00);
-	clks[IMX8MN_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mn_i2c4_sels, base + 0xae80);
-	clks[IMX8MN_CLK_UART1] = imx8m_clk_composite("uart1", imx8mn_uart1_sels, base + 0xaf00);
-	clks[IMX8MN_CLK_UART2] = imx8m_clk_composite("uart2", imx8mn_uart2_sels, base + 0xaf80);
-	clks[IMX8MN_CLK_UART3] = imx8m_clk_composite("uart3", imx8mn_uart3_sels, base + 0xb000);
-	clks[IMX8MN_CLK_UART4] = imx8m_clk_composite("uart4", imx8mn_uart4_sels, base + 0xb080);
-	clks[IMX8MN_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100);
-	clks[IMX8MN_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180);
-	clks[IMX8MN_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mn_gic_sels, base + 0xb200);
-	clks[IMX8MN_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mn_ecspi1_sels, base + 0xb280);
-	clks[IMX8MN_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mn_ecspi2_sels, base + 0xb300);
-	clks[IMX8MN_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mn_pwm1_sels, base + 0xb380);
-	clks[IMX8MN_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mn_pwm2_sels, base + 0xb400);
-	clks[IMX8MN_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mn_pwm3_sels, base + 0xb480);
-	clks[IMX8MN_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mn_pwm4_sels, base + 0xb500);
-	clks[IMX8MN_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mn_wdog_sels, base + 0xb900);
-	clks[IMX8MN_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mn_wrclk_sels, base + 0xb980);
-	clks[IMX8MN_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mn_clko1_sels, base + 0xba00);
-	clks[IMX8MN_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mn_clko2_sels, base + 0xba80);
-	clks[IMX8MN_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mn_dsi_core_sels, base + 0xbb00);
-	clks[IMX8MN_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mn_dsi_phy_sels, base + 0xbb80);
-	clks[IMX8MN_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mn_dsi_dbi_sels, base + 0xbc00);
-	clks[IMX8MN_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels, base + 0xbc80);
-	clks[IMX8MN_CLK_CAMERA_PIXEL] = imx8m_clk_composite("camera_pixel", imx8mn_camera_pixel_sels, base + 0xbd00);
-	clks[IMX8MN_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mn_csi1_phy_sels, base + 0xbd80);
-	clks[IMX8MN_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mn_csi2_phy_sels, base + 0xbf00);
-	clks[IMX8MN_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mn_csi2_esc_sels, base + 0xbf80);
-	clks[IMX8MN_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mn_ecspi3_sels, base + 0xc180);
-	clks[IMX8MN_CLK_PDM] = imx8m_clk_composite("pdm", imx8mn_pdm_sels, base + 0xc200);
-	clks[IMX8MN_CLK_SAI7] = imx8m_clk_composite("sai7", imx8mn_sai7_sels, base + 0xc300);
-
-	clks[IMX8MN_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
-	clks[IMX8MN_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
-	clks[IMX8MN_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
-	clks[IMX8MN_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
-	clks[IMX8MN_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
-	clks[IMX8MN_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
-	clks[IMX8MN_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
-	clks[IMX8MN_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
-	clks[IMX8MN_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
-	clks[IMX8MN_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
-	clks[IMX8MN_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
-	clks[IMX8MN_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
-	clks[IMX8MN_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
-	clks[IMX8MN_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
-	clks[IMX8MN_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
-	clks[IMX8MN_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
-	clks[IMX8MN_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
-	clks[IMX8MN_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
-	clks[IMX8MN_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
-	clks[IMX8MN_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
-	clks[IMX8MN_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MN_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MN_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MN_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MN_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MN_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MN_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MN_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MN_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MN_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
-	clks[IMX8MN_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
-	clks[IMX8MN_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
-	clks[IMX8MN_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
-	clks[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref", base + 0x44d0, 0);
-	clks[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_gate4("gpu_core_root_clk", "gpu_core_div", base + 0x44f0, 0);
-	clks[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
-	clks[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
-	clks[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
-	clks[IMX8MN_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
-	clks[IMX8MN_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
-	clks[IMX8MN_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0);
-	clks[IMX8MN_CLK_ASRC_ROOT] = imx_clk_gate4("asrc_root_clk", "audio_ahb", base + 0x4580, 0);
-	clks[IMX8MN_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm);
-	clks[IMX8MN_CLK_PDM_IPG]  = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm);
-	clks[IMX8MN_CLK_DISP_AXI_ROOT]  = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MN_CLK_DISP_APB_ROOT]  = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MN_CLK_CAMERA_PIXEL_ROOT] = imx_clk_gate2_shared2("camera_pixel_clk", "camera_pixel", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MN_CLK_DISP_PIXEL_ROOT] = imx_clk_gate2_shared2("disp_pixel_clk", "disp_pixel", base + 0x45d0, 0, &share_count_disp);
-	clks[IMX8MN_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0);
-	clks[IMX8MN_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
-	clks[IMX8MN_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
-	clks[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
-	clks[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
-	clks[IMX8MN_CLK_SAI7_ROOT] = imx_clk_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7);
-
-	clks[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
-
-	clks[IMX8MN_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div",
-					   clks[IMX8MN_CLK_A53_DIV],
-					   clks[IMX8MN_CLK_A53_SRC],
-					   clks[IMX8MN_ARM_PLL_OUT],
-					   clks[IMX8MN_SYS_PLL1_800M]);
-
-	imx_check_clocks(clks, ARRAY_SIZE(clks));
-
-	clk_data.clks = clks;
-	clk_data.clk_num = ARRAY_SIZE(clks);
-	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800);
+	hws[IMX8MN_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mn_enet_axi_sels, base + 0x8880);
+	hws[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900);
+	hws[IMX8MN_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mn_disp_axi_sels, base + 0x8a00);
+	hws[IMX8MN_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mn_disp_apb_sels, base + 0x8a80);
+	hws[IMX8MN_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80);
+	hws[IMX8MN_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mn_gpu_axi_sels, base + 0x8c00);
+	hws[IMX8MN_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mn_gpu_ahb_sels, base + 0x8c80);
+	hws[IMX8MN_CLK_NOC] = imx8m_clk_hw_composite_bus_critical("noc", imx8mn_noc_sels, base + 0x8d00);
+
+	hws[IMX8MN_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb", imx8mn_ahb_sels, base + 0x9000);
+	hws[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100);
+	hws[IMX8MN_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
+	hws[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
+	hws[IMX8MN_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL);
+
+	/*
+	 * DRAM clocks are manipulated from TF-A outside clock framework.
+	 * Mark with GET_RATE_NOCACHE to always read div value from hardware
+	 */
+	hws[IMX8MN_CLK_DRAM_ALT] = __imx8m_clk_hw_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000, CLK_GET_RATE_NOCACHE);
+	hws[IMX8MN_CLK_DRAM_APB] = __imx8m_clk_hw_composite("dram_apb", imx8mn_dram_apb_sels, base + 0xa080, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
+
+	hws[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_hw_composite("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500);
+	hws[IMX8MN_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mn_sai2_sels, base + 0xa600);
+	hws[IMX8MN_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mn_sai3_sels, base + 0xa680);
+	hws[IMX8MN_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mn_sai5_sels, base + 0xa780);
+	hws[IMX8MN_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mn_sai6_sels, base + 0xa800);
+	hws[IMX8MN_CLK_SPDIF1] = imx8m_clk_hw_composite("spdif1", imx8mn_spdif1_sels, base + 0xa880);
+	hws[IMX8MN_CLK_ENET_REF] = imx8m_clk_hw_composite("enet_ref", imx8mn_enet_ref_sels, base + 0xa980);
+	hws[IMX8MN_CLK_ENET_TIMER] = imx8m_clk_hw_composite("enet_timer", imx8mn_enet_timer_sels, base + 0xaa00);
+	hws[IMX8MN_CLK_ENET_PHY_REF] = imx8m_clk_hw_composite("enet_phy", imx8mn_enet_phy_sels, base + 0xaa80);
+	hws[IMX8MN_CLK_NAND] = imx8m_clk_hw_composite("nand", imx8mn_nand_sels, base + 0xab00);
+	hws[IMX8MN_CLK_QSPI] = imx8m_clk_hw_composite("qspi", imx8mn_qspi_sels, base + 0xab80);
+	hws[IMX8MN_CLK_USDHC1] = imx8m_clk_hw_composite("usdhc1", imx8mn_usdhc1_sels, base + 0xac00);
+	hws[IMX8MN_CLK_USDHC2] = imx8m_clk_hw_composite("usdhc2", imx8mn_usdhc2_sels, base + 0xac80);
+	hws[IMX8MN_CLK_I2C1] = imx8m_clk_hw_composite("i2c1", imx8mn_i2c1_sels, base + 0xad00);
+	hws[IMX8MN_CLK_I2C2] = imx8m_clk_hw_composite("i2c2", imx8mn_i2c2_sels, base + 0xad80);
+	hws[IMX8MN_CLK_I2C3] = imx8m_clk_hw_composite("i2c3", imx8mn_i2c3_sels, base + 0xae00);
+	hws[IMX8MN_CLK_I2C4] = imx8m_clk_hw_composite("i2c4", imx8mn_i2c4_sels, base + 0xae80);
+	hws[IMX8MN_CLK_UART1] = imx8m_clk_hw_composite("uart1", imx8mn_uart1_sels, base + 0xaf00);
+	hws[IMX8MN_CLK_UART2] = imx8m_clk_hw_composite("uart2", imx8mn_uart2_sels, base + 0xaf80);
+	hws[IMX8MN_CLK_UART3] = imx8m_clk_hw_composite("uart3", imx8mn_uart3_sels, base + 0xb000);
+	hws[IMX8MN_CLK_UART4] = imx8m_clk_hw_composite("uart4", imx8mn_uart4_sels, base + 0xb080);
+	hws[IMX8MN_CLK_USB_CORE_REF] = imx8m_clk_hw_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100);
+	hws[IMX8MN_CLK_USB_PHY_REF] = imx8m_clk_hw_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180);
+	hws[IMX8MN_CLK_GIC] = imx8m_clk_hw_composite_critical("gic", imx8mn_gic_sels, base + 0xb200);
+	hws[IMX8MN_CLK_ECSPI1] = imx8m_clk_hw_composite("ecspi1", imx8mn_ecspi1_sels, base + 0xb280);
+	hws[IMX8MN_CLK_ECSPI2] = imx8m_clk_hw_composite("ecspi2", imx8mn_ecspi2_sels, base + 0xb300);
+	hws[IMX8MN_CLK_PWM1] = imx8m_clk_hw_composite("pwm1", imx8mn_pwm1_sels, base + 0xb380);
+	hws[IMX8MN_CLK_PWM2] = imx8m_clk_hw_composite("pwm2", imx8mn_pwm2_sels, base + 0xb400);
+	hws[IMX8MN_CLK_PWM3] = imx8m_clk_hw_composite("pwm3", imx8mn_pwm3_sels, base + 0xb480);
+	hws[IMX8MN_CLK_PWM4] = imx8m_clk_hw_composite("pwm4", imx8mn_pwm4_sels, base + 0xb500);
+	hws[IMX8MN_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mn_wdog_sels, base + 0xb900);
+	hws[IMX8MN_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mn_wrclk_sels, base + 0xb980);
+	hws[IMX8MN_CLK_CLKO1] = imx8m_clk_hw_composite("clko1", imx8mn_clko1_sels, base + 0xba00);
+	hws[IMX8MN_CLK_CLKO2] = imx8m_clk_hw_composite("clko2", imx8mn_clko2_sels, base + 0xba80);
+	hws[IMX8MN_CLK_DSI_CORE] = imx8m_clk_hw_composite("dsi_core", imx8mn_dsi_core_sels, base + 0xbb00);
+	hws[IMX8MN_CLK_DSI_PHY_REF] = imx8m_clk_hw_composite("dsi_phy_ref", imx8mn_dsi_phy_sels, base + 0xbb80);
+	hws[IMX8MN_CLK_DSI_DBI] = imx8m_clk_hw_composite("dsi_dbi", imx8mn_dsi_dbi_sels, base + 0xbc00);
+	hws[IMX8MN_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mn_usdhc3_sels, base + 0xbc80);
+	hws[IMX8MN_CLK_CAMERA_PIXEL] = imx8m_clk_hw_composite("camera_pixel", imx8mn_camera_pixel_sels, base + 0xbd00);
+	hws[IMX8MN_CLK_CSI1_PHY_REF] = imx8m_clk_hw_composite("csi1_phy_ref", imx8mn_csi1_phy_sels, base + 0xbd80);
+	hws[IMX8MN_CLK_CSI2_PHY_REF] = imx8m_clk_hw_composite("csi2_phy_ref", imx8mn_csi2_phy_sels, base + 0xbf00);
+	hws[IMX8MN_CLK_CSI2_ESC] = imx8m_clk_hw_composite("csi2_esc", imx8mn_csi2_esc_sels, base + 0xbf80);
+	hws[IMX8MN_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mn_ecspi3_sels, base + 0xc180);
+	hws[IMX8MN_CLK_PDM] = imx8m_clk_hw_composite("pdm", imx8mn_pdm_sels, base + 0xc200);
+	hws[IMX8MN_CLK_SAI7] = imx8m_clk_hw_composite("sai7", imx8mn_sai7_sels, base + 0xc300);
+
+	hws[IMX8MN_CLK_ECSPI1_ROOT] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
+	hws[IMX8MN_CLK_ECSPI2_ROOT] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
+	hws[IMX8MN_CLK_ECSPI3_ROOT] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
+	hws[IMX8MN_CLK_ENET1_ROOT] = imx_clk_hw_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+	hws[IMX8MN_CLK_GPIO1_ROOT] = imx_clk_hw_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+	hws[IMX8MN_CLK_GPIO2_ROOT] = imx_clk_hw_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+	hws[IMX8MN_CLK_GPIO3_ROOT] = imx_clk_hw_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+	hws[IMX8MN_CLK_GPIO4_ROOT] = imx_clk_hw_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+	hws[IMX8MN_CLK_GPIO5_ROOT] = imx_clk_hw_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
+	hws[IMX8MN_CLK_I2C1_ROOT] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
+	hws[IMX8MN_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
+	hws[IMX8MN_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
+	hws[IMX8MN_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
+	hws[IMX8MN_CLK_MU_ROOT] = imx_clk_hw_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
+	hws[IMX8MN_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
+	hws[IMX8MN_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
+	hws[IMX8MN_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
+	hws[IMX8MN_CLK_PWM3_ROOT] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
+	hws[IMX8MN_CLK_PWM4_ROOT] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
+	hws[IMX8MN_CLK_QSPI_ROOT] = imx_clk_hw_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
+	hws[IMX8MN_CLK_NAND_ROOT] = imx_clk_hw_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MN_CLK_SAI2_ROOT] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MN_CLK_SAI2_IPG] = imx_clk_hw_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MN_CLK_SAI3_ROOT] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MN_CLK_SAI3_IPG] = imx_clk_hw_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MN_CLK_SAI5_ROOT] = imx_clk_hw_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MN_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MN_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MN_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MN_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+	hws[IMX8MN_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
+	hws[IMX8MN_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
+	hws[IMX8MN_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
+	hws[IMX8MN_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
+	hws[IMX8MN_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
+	hws[IMX8MN_CLK_GPU_CORE_ROOT] = imx_clk_hw_gate4("gpu_core_root_clk", "gpu_core", base + 0x44f0, 0);
+	hws[IMX8MN_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
+	hws[IMX8MN_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
+	hws[IMX8MN_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
+	hws[IMX8MN_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
+	hws[IMX8MN_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
+	hws[IMX8MN_CLK_GPU_BUS_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0);
+	hws[IMX8MN_CLK_ASRC_ROOT] = imx_clk_hw_gate4("asrc_root_clk", "audio_ahb", base + 0x4580, 0);
+	hws[IMX8MN_CLK_PDM_ROOT] = imx_clk_hw_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm);
+	hws[IMX8MN_CLK_PDM_IPG]  = imx_clk_hw_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm);
+	hws[IMX8MN_CLK_DISP_AXI_ROOT]  = imx_clk_hw_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MN_CLK_DISP_APB_ROOT]  = imx_clk_hw_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MN_CLK_CAMERA_PIXEL_ROOT] = imx_clk_hw_gate2_shared2("camera_pixel_clk", "camera_pixel", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MN_CLK_DISP_PIXEL_ROOT] = imx_clk_hw_gate2_shared2("disp_pixel_clk", "disp_pixel", base + 0x45d0, 0, &share_count_disp);
+	hws[IMX8MN_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0);
+	hws[IMX8MN_CLK_TMU_ROOT] = imx_clk_hw_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+	hws[IMX8MN_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+	hws[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
+	hws[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
+	hws[IMX8MN_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7);
+
+	hws[IMX8MN_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+
+	hws[IMX8MN_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
+					   hws[IMX8MN_CLK_A53_CORE]->clk,
+					   hws[IMX8MN_CLK_A53_CORE]->clk,
+					   hws[IMX8MN_ARM_PLL_OUT]->clk,
+					   hws[IMX8MN_CLK_A53_DIV]->clk);
+
+	imx_check_clk_hws(hws, IMX8MN_CLK_END);
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 	if (ret < 0) {
-		dev_err(dev, "failed to register clks for i.MX8MN\n");
-		goto unregister_clks;
+		dev_err(dev, "failed to register hws for i.MX8MN\n");
+		goto unregister_hws;
 	}
 
-	imx_register_uart_clocks(uart_clks);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+		int index = uart_clk_ids[i];
+
+		uart_hws[i] = &hws[index]->clk;
+	}
+
+	imx_register_uart_clocks(uart_hws);
 
 	return 0;
 
-unregister_clks:
-	imx_unregister_clocks(clks, ARRAY_SIZE(clks));
+unregister_hws:
+	imx_unregister_hw_clocks(hws, IMX8MN_CLK_END);
 
 	return ret;
 }
@@ -642,7 +595,16 @@
 	.probe = imx8mn_clocks_probe,
 	.driver = {
 		.name = "imx8mn-ccm",
-		.of_match_table = of_match_ptr(imx8mn_clk_of_match),
+		/*
+		 * Disable bind attributes: clocks are not removed and
+		 * reloading the driver will crash or break devices.
+		 */
+		.suppress_bind_attrs = true,
+		.of_match_table = imx8mn_clk_of_match,
 	},
 };
 module_platform_driver(imx8mn_clk_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8MN clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8mp.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8mp.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <dt-bindings/clock/imx8mp-clock.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+static u32 share_count_nand;
+static u32 share_count_media;
+
+static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
+static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
+static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
+static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
+static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
+static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
+static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
+static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
+static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
+
+static const char * const imx8mp_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
+					       "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
+					       "audio_pll1_out", "sys_pll3_out", };
+
+static const char * const imx8mp_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
+
+static const char * const imx8mp_m7_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m",
+					      "vpu_pll_out", "sys_pll1_800m", "audio_pll1_out",
+					      "video_pll1_out", "sys_pll3_out", };
+
+static const char * const imx8mp_ml_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+					      "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+					      "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_gpu3d_core_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+						      "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						      "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_gpu3d_shader_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+							"sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+							"video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_gpu2d_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+						 "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						 "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_audio_axi_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m",
+						     "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						     "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_hsio_axi_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
+						    "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+						    "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mp_media_isp_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
+						     "sys_pll3_out", "sys_pll1_400m", "audio_pll2_out",
+						     "clk_ext1", "sys_pll2_500m", };
+
+static const char * const imx8mp_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m",
+						    "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
+						    "video_pll1_out", "sys_pll1_100m",};
+
+static const char * const imx8mp_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
+						    "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
+						    "video_pll1_out", "sys_pll3_out", };
+
+static const char * const imx8mp_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
+						      "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
+						      "sys_pll2_250m", "audio_pll1_out", };
+
+static const char * const imx8mp_vpu_bus_sels[] = {"osc_24m", "sys_pll1_800m", "vpu_pll_out",
+						   "audio_pll2_out", "sys_pll3_out", "sys_pll2_1000m",
+						   "sys_pll2_200m", "sys_pll1_100m", };
+
+static const char * const imx8mp_media_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
+						     "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+						     "clk_ext1", "sys_pll2_500m", };
+
+static const char * const imx8mp_media_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m",
+						     "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+						     "clk_ext1", "sys_pll1_133m", };
+
+static const char * const imx8mp_gpu_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+						   "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						   "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_gpu_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+						   "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						   "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
+					       "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
+					       "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_noc_io_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
+						  "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
+						  "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_ml_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+						  "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						  "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_ml_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out",
+						  "sys_pll3_out", "sys_pll2_1000m", "audio_pll1_out",
+						  "video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m",
+					       "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out",
+					       "audio_pll1_out", "video_pll1_out", };
+
+static const char * const imx8mp_audio_ahb_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
+						     "sys_pll2_1000m", "sys_pll2_166m", "sys_pll3_out",
+						     "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mp_media_disp2_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
+						    "audio_pll1_out", "sys_pll1_800m", "sys_pll2_1000m",
+						    "sys_pll3_out", "clk_ext4", };
+
+static const char * const imx8mp_mipi_dsi_esc_rx_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m",
+							   "sys_pll1_800m", "sys_pll2_1000m",
+							   "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m",
+						    "sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out",
+						    "audio_pll1_out", "sys_pll1_266m", };
+
+static const char * const imx8mp_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						    "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						    "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_vpu_g1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m",
+						  "sys_pll2_1000m", "sys_pll1_100m", "sys_pll2_125m",
+						  "sys_pll3_out", "audio_pll1_out", };
+
+static const char * const imx8mp_vpu_g2_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m",
+						  "sys_pll2_1000m", "sys_pll1_100m", "sys_pll2_125m",
+						  "sys_pll3_out", "audio_pll1_out", };
+
+static const char * const imx8mp_can1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						"sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_can2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						"sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_pcie_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m",
+						    "sys_pll3_out", "sys_pll2_100m", "sys_pll1_80m",
+						    "sys_pll1_160m", "sys_pll1_200m", };
+
+static const char * const imx8mp_i2c5_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_i2c6_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_sai1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext1", "clk_ext2", };
+
+static const char * const imx8mp_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext2", "clk_ext3", };
+
+static const char * const imx8mp_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext3", "clk_ext4", };
+
+static const char * const imx8mp_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext1", "clk_ext2", };
+
+static const char * const imx8mp_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext2", "clk_ext3", };
+
+static const char * const imx8mp_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext3", "clk_ext4", };
+
+static const char * const imx8mp_enet_qos_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
+						    "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
+						    "video_pll1_out", "clk_ext4", };
+
+static const char * const imx8mp_enet_qos_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
+							  "clk_ext1", "clk_ext2", "clk_ext3",
+							  "clk_ext4", "video_pll1_out", };
+
+static const char * const imx8mp_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
+						    "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
+						    "video_pll1_out", "clk_ext4", };
+
+static const char * const imx8mp_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
+						      "clk_ext1", "clk_ext2", "clk_ext3",
+						      "clk_ext4", "video_pll1_out", };
+
+static const char * const imx8mp_enet_phy_ref_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m",
+							"sys_pll2_200m", "sys_pll2_500m", "audio_pll1_out",
+							"video_pll1_out", "audio_pll2_out", };
+
+static const char * const imx8mp_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out",
+						"sys_pll1_400m", "audio_pll2_out", "sys_pll3_out",
+						"sys_pll2_250m", "video_pll1_out", };
+
+static const char * const imx8mp_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll2_333m",
+						"sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
+						"sys_pll3_out", "sys_pll1_100m", };
+
+static const char * const imx8mp_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+						  "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+						  "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mp_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+						  "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+						  "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mp_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						"audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+						 "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+						 "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mp_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+						 "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+						 "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+						 "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+						 "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mp_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
+						 "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+						 "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_usb_core_ref_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
+							"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+							"clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_usb_phy_ref_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
+						       "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+						       "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+					       "sys_pll2_100m", "sys_pll1_800m",
+					       "sys_pll2_500m", "clk_ext4", "audio_pll2_out" };
+
+static const char * const imx8mp_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						  "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						  "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						  "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						  "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+						"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
+						"sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mp_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+						"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
+						"sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mp_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+						"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
+						"sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mp_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
+						"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
+						"sys_pll1_80m", "video_pll1_out", };
+
+static const char * const imx8mp_gpt1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext1" };
+
+static const char * const imx8mp_gpt2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext2" };
+
+static const char * const imx8mp_gpt3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext3" };
+
+static const char * const imx8mp_gpt4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext1" };
+
+static const char * const imx8mp_gpt5_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext2" };
+
+static const char * const imx8mp_gpt6_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m",
+						"sys_pll1_40m", "video_pll1_out", "sys_pll1_80m",
+						"audio_pll1_out", "clk_ext3" };
+
+static const char * const imx8mp_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m",
+						"vpu_pll_out", "sys_pll2_125m", "sys_pll3_out",
+						"sys_pll1_80m", "sys_pll2_166m" };
+
+static const char * const imx8mp_wrclk_sels[] = {"osc_24m", "sys_pll1_40m", "vpu_pll_out",
+						 "sys_pll3_out", "sys_pll2_200m", "sys_pll1_266m",
+						 "sys_pll2_500m", "sys_pll1_100m" };
+
+static const char * const imx8mp_ipp_do_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_133m",
+							"sys_pll1_200m", "audio_pll2_out", "sys_pll2_500m",
+							"vpu_pll_out", "sys_pll1_80m" };
+
+static const char * const imx8mp_ipp_do_clko2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_400m",
+							"sys_pll1_166m", "sys_pll3_out", "audio_pll1_out",
+							"video_pll1_out", "osc_32k" };
+
+static const char * const imx8mp_hdmi_fdcc_tst_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m",
+							 "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+							 "audio_pll2_out", "video_pll1_out", };
+
+static const char * const imx8mp_hdmi_24m_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
+						    "sys_pll3_out", "audio_pll1_out", "video_pll1_out",
+						    "audio_pll2_out", "sys_pll1_133m", };
+
+static const char * const imx8mp_hdmi_ref_266m_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll3_out",
+							 "sys_pll2_333m", "sys_pll1_266m", "sys_pll2_200m",
+							 "audio_pll1_out", "video_pll1_out", };
+
+static const char * const imx8mp_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
+						  "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
+						  "audio_pll2_out", "sys_pll1_100m", };
+
+static const char * const imx8mp_media_cam1_pix_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m",
+							  "sys_pll1_800m", "sys_pll2_1000m",
+							  "sys_pll3_out", "audio_pll2_out",
+							  "video_pll1_out", };
+
+static const char * const imx8mp_media_mipi_phy1_ref_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
+							       "sys_pll1_800m", "sys_pll2_1000m",
+							       "clk_ext2", "audio_pll2_out",
+							       "video_pll1_out", };
+
+static const char * const imx8mp_media_disp1_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
+							   "audio_pll1_out", "sys_pll1_800m",
+							   "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", };
+
+static const char * const imx8mp_media_cam2_pix_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m",
+							  "sys_pll1_800m", "sys_pll2_1000m",
+							  "sys_pll3_out", "audio_pll2_out",
+							  "video_pll1_out", };
+
+static const char * const imx8mp_media_ldb_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
+						     "sys_pll1_800m", "sys_pll2_1000m",
+						     "clk_ext2", "audio_pll2_out",
+						     "video_pll1_out", };
+
+static const char * const imx8mp_memrepair_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m",
+							"sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+							"clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_media_mipi_test_byte_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m",
+								"sys_pll3_out", "sys_pll2_100m",
+								"sys_pll1_80m", "sys_pll1_160m",
+								"sys_pll1_200m", };
+
+static const char * const imx8mp_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
+						  "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
+						  "sys_pll2_250m", "audio_pll2_out", };
+
+static const char * const imx8mp_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
+					       "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out",
+					       "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mp_vpu_vc8000e_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m",
+						       "sys_pll2_1000m", "audio_pll2_out", "sys_pll2_125m",
+						       "sys_pll3_out", "audio_pll1_out", };
+
+static const char * const imx8mp_sai7_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
+						"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
+						"clk_ext3", "clk_ext4", };
+
+static const char * const imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
+
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
+
+static const int uart_clk_ids[] = {
+	IMX8MP_CLK_UART1_ROOT,
+	IMX8MP_CLK_UART2_ROOT,
+	IMX8MP_CLK_UART3_ROOT,
+	IMX8MP_CLK_UART4_ROOT,
+};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1];
+
+static int imx8mp_clocks_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np;
+	void __iomem *anatop_base, *ccm_base;
+	int i;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx8mp-anatop");
+	anatop_base = of_iomap(np, 0);
+	of_node_put(np);
+	if (WARN_ON(!anatop_base))
+		return -ENOMEM;
+
+	np = dev->of_node;
+	ccm_base = devm_platform_ioremap_resource(pdev, 0);
+	if (WARN_ON(IS_ERR(ccm_base))) {
+		iounmap(anatop_base);
+		return PTR_ERR(ccm_base);
+	}
+
+	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX8MP_CLK_END), GFP_KERNEL);
+	if (WARN_ON(!clk_hw_data)) {
+		iounmap(anatop_base);
+		return -ENOMEM;
+	}
+
+	clk_hw_data->num = IMX8MP_CLK_END;
+	hws = clk_hw_data->hws;
+
+	hws[IMX8MP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+	hws[IMX8MP_CLK_24M] = imx_obtain_fixed_clk_hw(np, "osc_24m");
+	hws[IMX8MP_CLK_32K] = imx_obtain_fixed_clk_hw(np, "osc_32k");
+	hws[IMX8MP_CLK_EXT1] = imx_obtain_fixed_clk_hw(np, "clk_ext1");
+	hws[IMX8MP_CLK_EXT2] = imx_obtain_fixed_clk_hw(np, "clk_ext2");
+	hws[IMX8MP_CLK_EXT3] = imx_obtain_fixed_clk_hw(np, "clk_ext3");
+	hws[IMX8MP_CLK_EXT4] = imx_obtain_fixed_clk_hw(np, "clk_ext4");
+
+	hws[IMX8MP_AUDIO_PLL1_REF_SEL] = imx_clk_hw_mux("audio_pll1_ref_sel", anatop_base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_AUDIO_PLL2_REF_SEL] = imx_clk_hw_mux("audio_pll2_ref_sel", anatop_base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_VIDEO_PLL1_REF_SEL] = imx_clk_hw_mux("video_pll1_ref_sel", anatop_base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_DRAM_PLL_REF_SEL] = imx_clk_hw_mux("dram_pll_ref_sel", anatop_base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", anatop_base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_VPU_PLL_REF_SEL] = imx_clk_hw_mux("vpu_pll_ref_sel", anatop_base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", anatop_base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_SYS_PLL1_REF_SEL] = imx_clk_hw_mux("sys_pll1_ref_sel", anatop_base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_SYS_PLL2_REF_SEL] = imx_clk_hw_mux("sys_pll2_ref_sel", anatop_base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MP_SYS_PLL3_REF_SEL] = imx_clk_hw_mux("sys_pll3_ref_sel", anatop_base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+	hws[IMX8MP_AUDIO_PLL1] = imx_clk_hw_pll14xx("audio_pll1", "audio_pll1_ref_sel", anatop_base, &imx_1443x_pll);
+	hws[IMX8MP_AUDIO_PLL2] = imx_clk_hw_pll14xx("audio_pll2", "audio_pll2_ref_sel", anatop_base + 0x14, &imx_1443x_pll);
+	hws[IMX8MP_VIDEO_PLL1] = imx_clk_hw_pll14xx("video_pll1", "video_pll1_ref_sel", anatop_base + 0x28, &imx_1443x_pll);
+	hws[IMX8MP_DRAM_PLL] = imx_clk_hw_pll14xx("dram_pll", "dram_pll_ref_sel", anatop_base + 0x50, &imx_1443x_dram_pll);
+	hws[IMX8MP_GPU_PLL] = imx_clk_hw_pll14xx("gpu_pll", "gpu_pll_ref_sel", anatop_base + 0x64, &imx_1416x_pll);
+	hws[IMX8MP_VPU_PLL] = imx_clk_hw_pll14xx("vpu_pll", "vpu_pll_ref_sel", anatop_base + 0x74, &imx_1416x_pll);
+	hws[IMX8MP_ARM_PLL] = imx_clk_hw_pll14xx("arm_pll", "arm_pll_ref_sel", anatop_base + 0x84, &imx_1416x_pll);
+	hws[IMX8MP_SYS_PLL1] = imx_clk_hw_pll14xx("sys_pll1", "sys_pll1_ref_sel", anatop_base + 0x94, &imx_1416x_pll);
+	hws[IMX8MP_SYS_PLL2] = imx_clk_hw_pll14xx("sys_pll2", "sys_pll2_ref_sel", anatop_base + 0x104, &imx_1416x_pll);
+	hws[IMX8MP_SYS_PLL3] = imx_clk_hw_pll14xx("sys_pll3", "sys_pll3_ref_sel", anatop_base + 0x114, &imx_1416x_pll);
+
+	hws[IMX8MP_AUDIO_PLL1_BYPASS] = imx_clk_hw_mux_flags("audio_pll1_bypass", anatop_base, 16, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_AUDIO_PLL2_BYPASS] = imx_clk_hw_mux_flags("audio_pll2_bypass", anatop_base + 0x14, 16, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_VIDEO_PLL1_BYPASS] = imx_clk_hw_mux_flags("video_pll1_bypass", anatop_base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_DRAM_PLL_BYPASS] = imx_clk_hw_mux_flags("dram_pll_bypass", anatop_base + 0x50, 16, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_GPU_PLL_BYPASS] = imx_clk_hw_mux_flags("gpu_pll_bypass", anatop_base + 0x64, 28, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_VPU_PLL_BYPASS] = imx_clk_hw_mux_flags("vpu_pll_bypass", anatop_base + 0x74, 28, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_ARM_PLL_BYPASS] = imx_clk_hw_mux_flags("arm_pll_bypass", anatop_base + 0x84, 28, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_SYS_PLL1_BYPASS] = imx_clk_hw_mux_flags("sys_pll1_bypass", anatop_base + 0x94, 28, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_SYS_PLL2_BYPASS] = imx_clk_hw_mux_flags("sys_pll2_bypass", anatop_base + 0x104, 28, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MP_SYS_PLL3_BYPASS] = imx_clk_hw_mux_flags("sys_pll3_bypass", anatop_base + 0x114, 28, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
+
+	hws[IMX8MP_AUDIO_PLL1_OUT] = imx_clk_hw_gate("audio_pll1_out", "audio_pll1_bypass", anatop_base, 13);
+	hws[IMX8MP_AUDIO_PLL2_OUT] = imx_clk_hw_gate("audio_pll2_out", "audio_pll2_bypass", anatop_base + 0x14, 13);
+	hws[IMX8MP_VIDEO_PLL1_OUT] = imx_clk_hw_gate("video_pll1_out", "video_pll1_bypass", anatop_base + 0x28, 13);
+	hws[IMX8MP_DRAM_PLL_OUT] = imx_clk_hw_gate("dram_pll_out", "dram_pll_bypass", anatop_base + 0x50, 13);
+	hws[IMX8MP_GPU_PLL_OUT] = imx_clk_hw_gate("gpu_pll_out", "gpu_pll_bypass", anatop_base + 0x64, 11);
+	hws[IMX8MP_VPU_PLL_OUT] = imx_clk_hw_gate("vpu_pll_out", "vpu_pll_bypass", anatop_base + 0x74, 11);
+	hws[IMX8MP_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", anatop_base + 0x84, 11);
+	hws[IMX8MP_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", anatop_base + 0x114, 11);
+
+	hws[IMX8MP_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1_bypass", anatop_base + 0x94, 27);
+	hws[IMX8MP_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1_bypass", anatop_base + 0x94, 25);
+	hws[IMX8MP_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1_bypass", anatop_base + 0x94, 23);
+	hws[IMX8MP_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1_bypass", anatop_base + 0x94, 21);
+	hws[IMX8MP_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1_bypass", anatop_base + 0x94, 19);
+	hws[IMX8MP_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1_bypass", anatop_base + 0x94, 17);
+	hws[IMX8MP_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1_bypass", anatop_base + 0x94, 15);
+	hws[IMX8MP_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1_bypass", anatop_base + 0x94, 13);
+	hws[IMX8MP_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1_bypass", anatop_base + 0x94, 11);
+
+	hws[IMX8MP_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
+	hws[IMX8MP_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
+	hws[IMX8MP_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
+	hws[IMX8MP_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
+	hws[IMX8MP_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
+	hws[IMX8MP_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
+	hws[IMX8MP_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
+	hws[IMX8MP_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
+	hws[IMX8MP_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+	hws[IMX8MP_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2_bypass", anatop_base + 0x104, 27);
+	hws[IMX8MP_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2_bypass", anatop_base + 0x104, 25);
+	hws[IMX8MP_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2_bypass", anatop_base + 0x104, 23);
+	hws[IMX8MP_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2_bypass", anatop_base + 0x104, 21);
+	hws[IMX8MP_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2_bypass", anatop_base + 0x104, 19);
+	hws[IMX8MP_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2_bypass", anatop_base + 0x104, 17);
+	hws[IMX8MP_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2_bypass", anatop_base + 0x104, 15);
+	hws[IMX8MP_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2_bypass", anatop_base + 0x104, 13);
+	hws[IMX8MP_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2_bypass", anatop_base + 0x104, 11);
+
+	hws[IMX8MP_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
+	hws[IMX8MP_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
+	hws[IMX8MP_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
+	hws[IMX8MP_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
+	hws[IMX8MP_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
+	hws[IMX8MP_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
+	hws[IMX8MP_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
+	hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
+	hws[IMX8MP_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+	hws[IMX8MP_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mp_a53_sels, ccm_base + 0x8000);
+	hws[IMX8MP_CLK_A53_SRC] = hws[IMX8MP_CLK_A53_DIV];
+	hws[IMX8MP_CLK_A53_CG] = hws[IMX8MP_CLK_A53_DIV];
+	hws[IMX8MP_CLK_M7_CORE] = imx8m_clk_hw_composite_core("m7_core", imx8mp_m7_sels, ccm_base + 0x8080);
+	hws[IMX8MP_CLK_ML_CORE] = imx8m_clk_hw_composite_core("ml_core", imx8mp_ml_sels, ccm_base + 0x8100);
+	hws[IMX8MP_CLK_ML_SRC] = hws[IMX8MP_CLK_ML_CORE];
+	hws[IMX8MP_CLK_ML_CG] = hws[IMX8MP_CLK_ML_CORE];
+	hws[IMX8MP_CLK_ML_DIV] = hws[IMX8MP_CLK_ML_CORE];
+	hws[IMX8MP_CLK_GPU3D_CORE] = imx8m_clk_hw_composite_core("gpu3d_core", imx8mp_gpu3d_core_sels, ccm_base + 0x8180);
+	hws[IMX8MP_CLK_GPU3D_CORE_SRC] = hws[IMX8MP_CLK_GPU3D_CORE];
+	hws[IMX8MP_CLK_GPU3D_CORE_CG] = hws[IMX8MP_CLK_GPU3D_CORE];
+	hws[IMX8MP_CLK_GPU3D_CORE_DIV] = hws[IMX8MP_CLK_GPU3D_CORE];
+	hws[IMX8MP_CLK_GPU3D_SHADER_CORE] = imx8m_clk_hw_composite_core("gpu3d_shader_core", imx8mp_gpu3d_shader_sels, ccm_base + 0x8200);
+	hws[IMX8MP_CLK_GPU3D_SHADER_SRC] = hws[IMX8MP_CLK_GPU3D_SHADER_CORE];
+	hws[IMX8MP_CLK_GPU3D_SHADER_CG] = hws[IMX8MP_CLK_GPU3D_SHADER_CORE];
+	hws[IMX8MP_CLK_GPU3D_SHADER_DIV] = hws[IMX8MP_CLK_GPU3D_SHADER_CORE];
+	hws[IMX8MP_CLK_GPU2D_CORE] = imx8m_clk_hw_composite_core("gpu2d_core", imx8mp_gpu2d_sels, ccm_base + 0x8280);
+	hws[IMX8MP_CLK_GPU2D_SRC] = hws[IMX8MP_CLK_GPU2D_CORE];
+	hws[IMX8MP_CLK_GPU2D_CG] = hws[IMX8MP_CLK_GPU2D_CORE];
+	hws[IMX8MP_CLK_GPU2D_DIV] = hws[IMX8MP_CLK_GPU2D_CORE];
+	hws[IMX8MP_CLK_AUDIO_AXI] = imx8m_clk_hw_composite_core("audio_axi", imx8mp_audio_axi_sels, ccm_base + 0x8300);
+	hws[IMX8MP_CLK_AUDIO_AXI_SRC] = hws[IMX8MP_CLK_AUDIO_AXI];
+	hws[IMX8MP_CLK_AUDIO_AXI_CG] = hws[IMX8MP_CLK_AUDIO_AXI];
+	hws[IMX8MP_CLK_AUDIO_AXI_DIV] = hws[IMX8MP_CLK_AUDIO_AXI];
+	hws[IMX8MP_CLK_HSIO_AXI] = imx8m_clk_hw_composite("hsio_axi", imx8mp_hsio_axi_sels, ccm_base + 0x8380);
+	hws[IMX8MP_CLK_MEDIA_ISP] = imx8m_clk_hw_composite("media_isp", imx8mp_media_isp_sels, ccm_base + 0x8400);
+
+	/* CORE SEL */
+	hws[IMX8MP_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", ccm_base + 0x9880, 24, 1, imx8mp_a53_core_sels, ARRAY_SIZE(imx8mp_a53_core_sels));
+
+	hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800);
+	hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880);
+	hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900);
+	hws[IMX8MP_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mp_vpu_bus_sels, ccm_base + 0x8980);
+	hws[IMX8MP_CLK_MEDIA_AXI] = imx8m_clk_hw_composite_bus("media_axi", imx8mp_media_axi_sels, ccm_base + 0x8a00);
+	hws[IMX8MP_CLK_MEDIA_APB] = imx8m_clk_hw_composite_bus("media_apb", imx8mp_media_apb_sels, ccm_base + 0x8a80);
+	hws[IMX8MP_CLK_HDMI_APB] = imx8m_clk_hw_composite_bus("hdmi_apb", imx8mp_media_apb_sels, ccm_base + 0x8b00);
+	hws[IMX8MP_CLK_HDMI_AXI] = imx8m_clk_hw_composite_bus("hdmi_axi", imx8mp_media_axi_sels, ccm_base + 0x8b80);
+	hws[IMX8MP_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mp_gpu_axi_sels, ccm_base + 0x8c00);
+	hws[IMX8MP_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mp_gpu_ahb_sels, ccm_base + 0x8c80);
+	hws[IMX8MP_CLK_NOC] = imx8m_clk_hw_composite_bus_critical("noc", imx8mp_noc_sels, ccm_base + 0x8d00);
+	hws[IMX8MP_CLK_NOC_IO] = imx8m_clk_hw_composite_bus_critical("noc_io", imx8mp_noc_io_sels, ccm_base + 0x8d80);
+	hws[IMX8MP_CLK_ML_AXI] = imx8m_clk_hw_composite_bus("ml_axi", imx8mp_ml_axi_sels, ccm_base + 0x8e00);
+	hws[IMX8MP_CLK_ML_AHB] = imx8m_clk_hw_composite_bus("ml_ahb", imx8mp_ml_ahb_sels, ccm_base + 0x8e80);
+
+	hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000);
+	hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100);
+	hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200);
+	hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite("media_disp2_pix", imx8mp_media_disp2_pix_sels, ccm_base + 0x9300);
+
+	hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1);
+
+	hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000);
+	hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080);
+	hws[IMX8MP_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mp_vpu_g1_sels, ccm_base + 0xa100);
+	hws[IMX8MP_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mp_vpu_g2_sels, ccm_base + 0xa180);
+	hws[IMX8MP_CLK_CAN1] = imx8m_clk_hw_composite("can1", imx8mp_can1_sels, ccm_base + 0xa200);
+	hws[IMX8MP_CLK_CAN2] = imx8m_clk_hw_composite("can2", imx8mp_can2_sels, ccm_base + 0xa280);
+	hws[IMX8MP_CLK_PCIE_AUX] = imx8m_clk_hw_composite("pcie_aux", imx8mp_pcie_aux_sels, ccm_base + 0xa400);
+	hws[IMX8MP_CLK_I2C5] = imx8m_clk_hw_composite("i2c5", imx8mp_i2c5_sels, ccm_base + 0xa480);
+	hws[IMX8MP_CLK_I2C6] = imx8m_clk_hw_composite("i2c6", imx8mp_i2c6_sels, ccm_base + 0xa500);
+	hws[IMX8MP_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mp_sai1_sels, ccm_base + 0xa580);
+	hws[IMX8MP_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mp_sai2_sels, ccm_base + 0xa600);
+	hws[IMX8MP_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mp_sai3_sels, ccm_base + 0xa680);
+	hws[IMX8MP_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mp_sai4_sels, ccm_base + 0xa700);
+	hws[IMX8MP_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mp_sai5_sels, ccm_base + 0xa780);
+	hws[IMX8MP_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mp_sai6_sels, ccm_base + 0xa800);
+	hws[IMX8MP_CLK_ENET_QOS] = imx8m_clk_hw_composite("enet_qos", imx8mp_enet_qos_sels, ccm_base + 0xa880);
+	hws[IMX8MP_CLK_ENET_QOS_TIMER] = imx8m_clk_hw_composite("enet_qos_timer", imx8mp_enet_qos_timer_sels, ccm_base + 0xa900);
+	hws[IMX8MP_CLK_ENET_REF] = imx8m_clk_hw_composite("enet_ref", imx8mp_enet_ref_sels, ccm_base + 0xa980);
+	hws[IMX8MP_CLK_ENET_TIMER] = imx8m_clk_hw_composite("enet_timer", imx8mp_enet_timer_sels, ccm_base + 0xaa00);
+	hws[IMX8MP_CLK_ENET_PHY_REF] = imx8m_clk_hw_composite("enet_phy_ref", imx8mp_enet_phy_ref_sels, ccm_base + 0xaa80);
+	hws[IMX8MP_CLK_NAND] = imx8m_clk_hw_composite("nand", imx8mp_nand_sels, ccm_base + 0xab00);
+	hws[IMX8MP_CLK_QSPI] = imx8m_clk_hw_composite("qspi", imx8mp_qspi_sels, ccm_base + 0xab80);
+	hws[IMX8MP_CLK_USDHC1] = imx8m_clk_hw_composite("usdhc1", imx8mp_usdhc1_sels, ccm_base + 0xac00);
+	hws[IMX8MP_CLK_USDHC2] = imx8m_clk_hw_composite("usdhc2", imx8mp_usdhc2_sels, ccm_base + 0xac80);
+	hws[IMX8MP_CLK_I2C1] = imx8m_clk_hw_composite("i2c1", imx8mp_i2c1_sels, ccm_base + 0xad00);
+	hws[IMX8MP_CLK_I2C2] = imx8m_clk_hw_composite("i2c2", imx8mp_i2c2_sels, ccm_base + 0xad80);
+	hws[IMX8MP_CLK_I2C3] = imx8m_clk_hw_composite("i2c3", imx8mp_i2c3_sels, ccm_base + 0xae00);
+	hws[IMX8MP_CLK_I2C4] = imx8m_clk_hw_composite("i2c4", imx8mp_i2c4_sels, ccm_base + 0xae80);
+
+	hws[IMX8MP_CLK_UART1] = imx8m_clk_hw_composite("uart1", imx8mp_uart1_sels, ccm_base + 0xaf00);
+	hws[IMX8MP_CLK_UART2] = imx8m_clk_hw_composite("uart2", imx8mp_uart2_sels, ccm_base + 0xaf80);
+	hws[IMX8MP_CLK_UART3] = imx8m_clk_hw_composite("uart3", imx8mp_uart3_sels, ccm_base + 0xb000);
+	hws[IMX8MP_CLK_UART4] = imx8m_clk_hw_composite("uart4", imx8mp_uart4_sels, ccm_base + 0xb080);
+	hws[IMX8MP_CLK_USB_CORE_REF] = imx8m_clk_hw_composite("usb_core_ref", imx8mp_usb_core_ref_sels, ccm_base + 0xb100);
+	hws[IMX8MP_CLK_USB_PHY_REF] = imx8m_clk_hw_composite("usb_phy_ref", imx8mp_usb_phy_ref_sels, ccm_base + 0xb180);
+	hws[IMX8MP_CLK_GIC] = imx8m_clk_hw_composite_critical("gic", imx8mp_gic_sels, ccm_base + 0xb200);
+	hws[IMX8MP_CLK_ECSPI1] = imx8m_clk_hw_composite("ecspi1", imx8mp_ecspi1_sels, ccm_base + 0xb280);
+	hws[IMX8MP_CLK_ECSPI2] = imx8m_clk_hw_composite("ecspi2", imx8mp_ecspi2_sels, ccm_base + 0xb300);
+	hws[IMX8MP_CLK_PWM1] = imx8m_clk_hw_composite("pwm1", imx8mp_pwm1_sels, ccm_base + 0xb380);
+	hws[IMX8MP_CLK_PWM2] = imx8m_clk_hw_composite("pwm2", imx8mp_pwm2_sels, ccm_base + 0xb400);
+	hws[IMX8MP_CLK_PWM3] = imx8m_clk_hw_composite("pwm3", imx8mp_pwm3_sels, ccm_base + 0xb480);
+	hws[IMX8MP_CLK_PWM4] = imx8m_clk_hw_composite("pwm4", imx8mp_pwm4_sels, ccm_base + 0xb500);
+
+	hws[IMX8MP_CLK_GPT1] = imx8m_clk_hw_composite("gpt1", imx8mp_gpt1_sels, ccm_base + 0xb580);
+	hws[IMX8MP_CLK_GPT2] = imx8m_clk_hw_composite("gpt2", imx8mp_gpt2_sels, ccm_base + 0xb600);
+	hws[IMX8MP_CLK_GPT3] = imx8m_clk_hw_composite("gpt3", imx8mp_gpt3_sels, ccm_base + 0xb680);
+	hws[IMX8MP_CLK_GPT4] = imx8m_clk_hw_composite("gpt4", imx8mp_gpt4_sels, ccm_base + 0xb700);
+	hws[IMX8MP_CLK_GPT5] = imx8m_clk_hw_composite("gpt5", imx8mp_gpt5_sels, ccm_base + 0xb780);
+	hws[IMX8MP_CLK_GPT6] = imx8m_clk_hw_composite("gpt6", imx8mp_gpt6_sels, ccm_base + 0xb800);
+	hws[IMX8MP_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mp_wdog_sels, ccm_base + 0xb900);
+	hws[IMX8MP_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mp_wrclk_sels, ccm_base + 0xb980);
+	hws[IMX8MP_CLK_IPP_DO_CLKO1] = imx8m_clk_hw_composite("ipp_do_clko1", imx8mp_ipp_do_clko1_sels, ccm_base + 0xba00);
+	hws[IMX8MP_CLK_IPP_DO_CLKO2] = imx8m_clk_hw_composite("ipp_do_clko2", imx8mp_ipp_do_clko2_sels, ccm_base + 0xba80);
+	hws[IMX8MP_CLK_HDMI_FDCC_TST] = imx8m_clk_hw_composite("hdmi_fdcc_tst", imx8mp_hdmi_fdcc_tst_sels, ccm_base + 0xbb00);
+	hws[IMX8MP_CLK_HDMI_24M] = imx8m_clk_hw_composite("hdmi_24m", imx8mp_hdmi_24m_sels, ccm_base + 0xbb80);
+	hws[IMX8MP_CLK_HDMI_REF_266M] = imx8m_clk_hw_composite("hdmi_ref_266m", imx8mp_hdmi_ref_266m_sels, ccm_base + 0xbc00);
+	hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80);
+	hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00);
+	hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80);
+	hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite("media_disp1_pix", imx8mp_media_disp1_pix_sels, ccm_base + 0xbe00);
+	hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80);
+	hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00);
+	hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80);
+	hws[IMX8MP_CLK_MEDIA_MIPI_TEST_BYTE] = imx8m_clk_hw_composite("media_mipi_test_byte", imx8mp_media_mipi_test_byte_sels, ccm_base + 0xc100);
+	hws[IMX8MP_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mp_ecspi3_sels, ccm_base + 0xc180);
+	hws[IMX8MP_CLK_PDM] = imx8m_clk_hw_composite("pdm", imx8mp_pdm_sels, ccm_base + 0xc200);
+	hws[IMX8MP_CLK_VPU_VC8000E] = imx8m_clk_hw_composite("vpu_vc8000e", imx8mp_vpu_vc8000e_sels, ccm_base + 0xc280);
+	hws[IMX8MP_CLK_SAI7] = imx8m_clk_hw_composite("sai7", imx8mp_sai7_sels, ccm_base + 0xc300);
+
+	hws[IMX8MP_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+	hws[IMX8MP_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", ccm_base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL);
+
+	hws[IMX8MP_CLK_DRAM1_ROOT] = imx_clk_hw_gate4_flags("dram1_root_clk", "dram_core_clk", ccm_base + 0x4050, 0, CLK_IS_CRITICAL);
+	hws[IMX8MP_CLK_ECSPI1_ROOT] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1", ccm_base + 0x4070, 0);
+	hws[IMX8MP_CLK_ECSPI2_ROOT] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2", ccm_base + 0x4080, 0);
+	hws[IMX8MP_CLK_ECSPI3_ROOT] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3", ccm_base + 0x4090, 0);
+	hws[IMX8MP_CLK_ENET1_ROOT] = imx_clk_hw_gate4("enet1_root_clk", "enet_axi", ccm_base + 0x40a0, 0);
+	hws[IMX8MP_CLK_GPIO1_ROOT] = imx_clk_hw_gate4("gpio1_root_clk", "ipg_root", ccm_base + 0x40b0, 0);
+	hws[IMX8MP_CLK_GPIO2_ROOT] = imx_clk_hw_gate4("gpio2_root_clk", "ipg_root", ccm_base + 0x40c0, 0);
+	hws[IMX8MP_CLK_GPIO3_ROOT] = imx_clk_hw_gate4("gpio3_root_clk", "ipg_root", ccm_base + 0x40d0, 0);
+	hws[IMX8MP_CLK_GPIO4_ROOT] = imx_clk_hw_gate4("gpio4_root_clk", "ipg_root", ccm_base + 0x40e0, 0);
+	hws[IMX8MP_CLK_GPIO5_ROOT] = imx_clk_hw_gate4("gpio5_root_clk", "ipg_root", ccm_base + 0x40f0, 0);
+	hws[IMX8MP_CLK_GPT1_ROOT] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1", ccm_base + 0x4100, 0);
+	hws[IMX8MP_CLK_GPT2_ROOT] = imx_clk_hw_gate4("gpt2_root_clk", "gpt2", ccm_base + 0x4110, 0);
+	hws[IMX8MP_CLK_GPT3_ROOT] = imx_clk_hw_gate4("gpt3_root_clk", "gpt3", ccm_base + 0x4120, 0);
+	hws[IMX8MP_CLK_GPT4_ROOT] = imx_clk_hw_gate4("gpt4_root_clk", "gpt4", ccm_base + 0x4130, 0);
+	hws[IMX8MP_CLK_GPT5_ROOT] = imx_clk_hw_gate4("gpt5_root_clk", "gpt5", ccm_base + 0x4140, 0);
+	hws[IMX8MP_CLK_GPT6_ROOT] = imx_clk_hw_gate4("gpt6_root_clk", "gpt6", ccm_base + 0x4150, 0);
+	hws[IMX8MP_CLK_I2C1_ROOT] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1", ccm_base + 0x4170, 0);
+	hws[IMX8MP_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", ccm_base + 0x4180, 0);
+	hws[IMX8MP_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", ccm_base + 0x4190, 0);
+	hws[IMX8MP_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", ccm_base + 0x41a0, 0);
+	hws[IMX8MP_CLK_MU_ROOT] = imx_clk_hw_gate4("mu_root_clk", "ipg_root", ccm_base + 0x4210, 0);
+	hws[IMX8MP_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", ccm_base + 0x4220, 0);
+	hws[IMX8MP_CLK_PCIE_ROOT] = imx_clk_hw_gate4("pcie_root_clk", "pcie_aux", ccm_base + 0x4250, 0);
+	hws[IMX8MP_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", ccm_base + 0x4280, 0);
+	hws[IMX8MP_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", ccm_base + 0x4290, 0);
+	hws[IMX8MP_CLK_PWM3_ROOT] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3", ccm_base + 0x42a0, 0);
+	hws[IMX8MP_CLK_PWM4_ROOT] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4", ccm_base + 0x42b0, 0);
+	hws[IMX8MP_CLK_QOS_ROOT] = imx_clk_hw_gate4("qos_root_clk", "ipg_root", ccm_base + 0x42c0, 0);
+	hws[IMX8MP_CLK_QOS_ENET_ROOT] = imx_clk_hw_gate4("qos_enet_root_clk", "ipg_root", ccm_base + 0x42e0, 0);
+	hws[IMX8MP_CLK_QSPI_ROOT] = imx_clk_hw_gate4("qspi_root_clk", "qspi", ccm_base + 0x42f0, 0);
+	hws[IMX8MP_CLK_NAND_ROOT] = imx_clk_hw_gate2_shared2("nand_root_clk", "nand", ccm_base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MP_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", ccm_base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MP_CLK_I2C5_ROOT] = imx_clk_hw_gate2("i2c5_root_clk", "i2c5", ccm_base + 0x4330, 0);
+	hws[IMX8MP_CLK_I2C6_ROOT] = imx_clk_hw_gate2("i2c6_root_clk", "i2c6", ccm_base + 0x4340, 0);
+	hws[IMX8MP_CLK_CAN1_ROOT] = imx_clk_hw_gate2("can1_root_clk", "can1", ccm_base + 0x4350, 0);
+	hws[IMX8MP_CLK_CAN2_ROOT] = imx_clk_hw_gate2("can2_root_clk", "can2", ccm_base + 0x4360, 0);
+	hws[IMX8MP_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_root_clk", "ipg_root", ccm_base + 0x43a0, 0);
+	hws[IMX8MP_CLK_ENET_QOS_ROOT] = imx_clk_hw_gate4("enet_qos_root_clk", "sim_enet_root_clk", ccm_base + 0x43b0, 0);
+	hws[IMX8MP_CLK_SIM_ENET_ROOT] = imx_clk_hw_gate4("sim_enet_root_clk", "enet_axi", ccm_base + 0x4400, 0);
+	hws[IMX8MP_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_core", ccm_base + 0x4450, 0);
+	hws[IMX8MP_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core", ccm_base + 0x4460, 0);
+	hws[IMX8MP_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", ccm_base + 0x4470, 0);
+	hws[IMX8MP_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", ccm_base + 0x4490, 0);
+	hws[IMX8MP_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", ccm_base + 0x44a0, 0);
+	hws[IMX8MP_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", ccm_base + 0x44b0, 0);
+	hws[IMX8MP_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", ccm_base + 0x44c0, 0);
+	hws[IMX8MP_CLK_USB_ROOT] = imx_clk_hw_gate4("usb_root_clk", "osc_32k", ccm_base + 0x44d0, 0);
+	hws[IMX8MP_CLK_USB_PHY_ROOT] = imx_clk_hw_gate4("usb_phy_root_clk", "usb_phy_ref", ccm_base + 0x44f0, 0);
+	hws[IMX8MP_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", ccm_base + 0x4510, 0);
+	hws[IMX8MP_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", ccm_base + 0x4520, 0);
+	hws[IMX8MP_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", ccm_base + 0x4530, 0);
+	hws[IMX8MP_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", ccm_base + 0x4540, 0);
+	hws[IMX8MP_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", ccm_base + 0x4550, 0);
+	hws[IMX8MP_CLK_VPU_G1_ROOT] = imx_clk_hw_gate4("vpu_g1_root_clk", "vpu_g1", ccm_base + 0x4560, 0);
+	hws[IMX8MP_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_axi", ccm_base + 0x4570, 0);
+	hws[IMX8MP_CLK_VPU_VC8KE_ROOT] = imx_clk_hw_gate4("vpu_vc8ke_root_clk", "vpu_vc8000e", ccm_base + 0x4590, 0);
+	hws[IMX8MP_CLK_VPU_G2_ROOT] = imx_clk_hw_gate4("vpu_g2_root_clk", "vpu_g2", ccm_base + 0x45a0, 0);
+	hws[IMX8MP_CLK_NPU_ROOT] = imx_clk_hw_gate4("npu_root_clk", "ml_core", ccm_base + 0x45b0, 0);
+	hws[IMX8MP_CLK_HSIO_ROOT] = imx_clk_hw_gate4("hsio_root_clk", "ipg_root", ccm_base + 0x45c0, 0);
+	hws[IMX8MP_CLK_MEDIA_APB_ROOT] = imx_clk_hw_gate2_shared2("media_apb_root_clk", "media_apb", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_AXI_ROOT] = imx_clk_hw_gate2_shared2("media_axi_root_clk", "media_axi", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_CAM1_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_cam1_pix_root_clk", "media_cam1_pix", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_CAM2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_cam2_pix_root_clk", "media_cam2_pix", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp1_pix_root_clk", "media_disp1_pix", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp2_pix_root_clk", "media_disp2_pix", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_LDB_ROOT] = imx_clk_hw_gate2_shared2("media_ldb_root_clk", "media_ldb", ccm_base + 0x45d0, 0, &share_count_media);
+	hws[IMX8MP_CLK_MEDIA_ISP_ROOT] = imx_clk_hw_gate2_shared2("media_isp_root_clk", "media_isp", ccm_base + 0x45d0, 0, &share_count_media);
+
+	hws[IMX8MP_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", ccm_base + 0x45e0, 0);
+	hws[IMX8MP_CLK_HDMI_ROOT] = imx_clk_hw_gate4("hdmi_root_clk", "hdmi_axi", ccm_base + 0x45f0, 0);
+	hws[IMX8MP_CLK_TSENSOR_ROOT] = imx_clk_hw_gate4("tsensor_root_clk", "ipg_root", ccm_base + 0x4620, 0);
+	hws[IMX8MP_CLK_VPU_ROOT] = imx_clk_hw_gate4("vpu_root_clk", "vpu_bus", ccm_base + 0x4630, 0);
+	hws[IMX8MP_CLK_AUDIO_ROOT] = imx_clk_hw_gate4("audio_root_clk", "audio_ahb", ccm_base + 0x4650, 0);
+
+	hws[IMX8MP_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
+					     hws[IMX8MP_CLK_A53_CORE]->clk,
+					     hws[IMX8MP_CLK_A53_CORE]->clk,
+					     hws[IMX8MP_ARM_PLL_OUT]->clk,
+					     hws[IMX8MP_CLK_A53_DIV]->clk);
+
+	imx_check_clk_hws(hws, IMX8MP_CLK_END);
+
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+	for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+		int index = uart_clk_ids[i];
+
+		uart_clks[i] = &hws[index]->clk;
+	}
+
+	imx_register_uart_clocks(uart_clks);
+
+	return 0;
+}
+
+static const struct of_device_id imx8mp_clk_of_match[] = {
+	{ .compatible = "fsl,imx8mp-ccm" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8mp_clk_of_match);
+
+static struct platform_driver imx8mp_clk_driver = {
+	.probe = imx8mp_clocks_probe,
+	.driver = {
+		.name = "imx8mp-ccm",
+		/*
+		 * Disable bind attributes: clocks are not removed and
+		 * reloading the driver will crash or break devices.
+		 */
+		.suppress_bind_attrs = true,
+		.of_match_table = imx8mp_clk_of_match,
+	},
+};
+module_platform_driver(imx8mp_clk_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8MP clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8mq.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8mq.c
@@ -5,12 +5,13 @@
  */
 
 #include <dt-bindings/clock/imx8mq-clock.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/types.h>
+#include <linux/slab.h>
 #include <linux/platform_device.h>
 
 #include "clk.h"
@@ -24,9 +25,7 @@
 static u32 share_count_dcss;
 static u32 share_count_nand;
 
-static struct clk *clks[IMX8MQ_CLK_END];
-
-static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "phy_27m", "dummy", };
 static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
 static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
 static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
@@ -34,15 +33,16 @@
 static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
 static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
 
-static const char * const sys1_pll_out_sels[] = {"sys1_pll1_ref_sel", };
-static const char * const sys2_pll_out_sels[] = {"sys1_pll1_ref_sel", "sys2_pll1_ref_sel", };
-static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", "sys2_pll1_ref_sel", };
+static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", };
 static const char * const dram_pll_out_sels[] = {"dram_pll1_ref_sel", };
+static const char * const video2_pll_out_sels[] = {"video2_pll1_ref_sel", };
 
 /* CCM ROOT */
 static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
 					"sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll_out", };
 
+static const char * const imx8mq_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", };
+
 static const char * const imx8mq_arm_m4_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_250m", "sys1_pll_266m",
 					"sys1_pll_800m", "audio_pll1_out", "video_pll1_out", "sys3_pll_out", };
 
@@ -113,12 +113,12 @@
 static const char * const imx8mq_disp_dc8000_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll_out", "audio_pll2_out", };
 
 static const char * const imx8mq_pcie1_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
-					       "sys1_pll_800m", "sys2_pll_500m", "sys2_pll_250m", "sys3_pll_out", };
+					       "sys1_pll_800m", "sys2_pll_500m", "sys2_pll_333m", "sys3_pll_out", };
 
 static const char * const imx8mq_pcie1_phy_sels[] = {"osc_25m", "sys2_pll_100m", "sys2_pll_500m", "clk_ext1", "clk_ext2",
 					      "clk_ext3", "clk_ext4", };
 
-static const char * const imx8mq_pcie1_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_500m", "sys3_pll_out",
+static const char * const imx8mq_pcie1_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_50m", "sys3_pll_out",
 					      "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_160m", "sys1_pll_200m", };
 
 static const char * const imx8mq_dc_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll_out", "clk_ext4", };
@@ -157,10 +157,10 @@
 					 "audio_pll2_out", "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m", };
 
 static const char * const imx8mq_usdhc1_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
-					 "audio_pll2_out", "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m", };
+					 "sys3_pll_out", "sys1_pll_266m", "audio_pll2_out", "sys1_pll_100m", };
 
 static const char * const imx8mq_usdhc2_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
-					 "audio_pll2_out", "sys1_pll_266m", "sys3_pll_out", "sys1_pll_100m", };
+					 "sys3_pll_out", "sys1_pll_266m", "audio_pll2_out", "sys1_pll_100m", };
 
 static const char * const imx8mq_i2c1_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll_out", "audio_pll1_out",
 					 "video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
@@ -270,102 +270,157 @@
 static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m",
 					  "sys3_pll_out", "audio_pll1_out", "video_pll1_out", "ckil", };
 
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] = {
-	&clks[IMX8MQ_CLK_UART1_ROOT],
-	&clks[IMX8MQ_CLK_UART2_ROOT],
-	&clks[IMX8MQ_CLK_UART3_ROOT],
-	&clks[IMX8MQ_CLK_UART4_ROOT],
-	NULL
+static const char * const pllout_monitor_sels[] = {"osc_25m", "osc_27m", "dummy", "dummy", "ckil",
+						   "audio_pll1_out_monitor", "audio_pll2_out_monitor",
+						   "video_pll1_out_monitor", "gpu_pll_out_monitor",
+						   "vpu_pll_out_monitor", "arm_pll_out_monitor",
+						   "sys_pll1_out_monitor", "sys_pll2_out_monitor",
+						   "sys_pll3_out_monitor", "dram_pll_out_monitor",
+						   "video_pll2_out_monitor", };
+
+static struct clk_hw_onecell_data *clk_hw_data;
+static struct clk_hw **hws;
+
+static const int uart_clk_ids[] = {
+	IMX8MQ_CLK_UART1_ROOT,
+	IMX8MQ_CLK_UART2_ROOT,
+	IMX8MQ_CLK_UART3_ROOT,
+	IMX8MQ_CLK_UART4_ROOT,
 };
+static struct clk **uart_hws[ARRAY_SIZE(uart_clk_ids) + 1];
 
 static int imx8mq_clocks_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	void __iomem *base;
-	int err;
+	int err, i;
+
+	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+					  IMX8MQ_CLK_END), GFP_KERNEL);
+	if (WARN_ON(!clk_hw_data))
+		return -ENOMEM;
 
-	clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-	clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
-	clks[IMX8MQ_CLK_25M] = of_clk_get_by_name(np, "osc_25m");
-	clks[IMX8MQ_CLK_27M] = of_clk_get_by_name(np, "osc_27m");
-	clks[IMX8MQ_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1");
-	clks[IMX8MQ_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2");
-	clks[IMX8MQ_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3");
-	clks[IMX8MQ_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4");
+	clk_hw_data->num = IMX8MQ_CLK_END;
+	hws = clk_hw_data->hws;
+
+	hws[IMX8MQ_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+	hws[IMX8MQ_CLK_32K] = imx_obtain_fixed_clk_hw(np, "ckil");
+	hws[IMX8MQ_CLK_25M] = imx_obtain_fixed_clk_hw(np, "osc_25m");
+	hws[IMX8MQ_CLK_27M] = imx_obtain_fixed_clk_hw(np, "osc_27m");
+	hws[IMX8MQ_CLK_EXT1] = imx_obtain_fixed_clk_hw(np, "clk_ext1");
+	hws[IMX8MQ_CLK_EXT2] = imx_obtain_fixed_clk_hw(np, "clk_ext2");
+	hws[IMX8MQ_CLK_EXT3] = imx_obtain_fixed_clk_hw(np, "clk_ext3");
+	hws[IMX8MQ_CLK_EXT4] = imx_obtain_fixed_clk_hw(np, "clk_ext4");
+	hws[IMX8MQ_CLK_PHY_27MHZ] = imx_clk_hw_fixed("phy_27m", 27000000);
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
 	base = of_iomap(np, 0);
+	of_node_put(np);
 	if (WARN_ON(!base))
 		return -ENOMEM;
 
-	clks[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_SYS1_PLL1_REF_SEL]	= imx_clk_mux("sys1_pll1_ref_sel", base + 0x30, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_SYS2_PLL1_REF_SEL]	= imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_SYS3_PLL1_REF_SEL]	= imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-	clks[IMX8MQ_DRAM_PLL1_REF_SEL]	= imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
-
-	clks[IMX8MQ_ARM_PLL_REF_DIV]	= imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
-	clks[IMX8MQ_GPU_PLL_REF_DIV]	= imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
-	clks[IMX8MQ_VPU_PLL_REF_DIV]	= imx_clk_divider("vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6);
-	clks[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6);
-	clks[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6);
-	clks[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6);
-
-	clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
-	clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
-	clks[IMX8MQ_VPU_PLL] = imx_clk_frac_pll("vpu_pll", "vpu_pll_ref_div", base + 0x20);
-	clks[IMX8MQ_AUDIO_PLL1] = imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0);
-	clks[IMX8MQ_AUDIO_PLL2] = imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8);
-	clks[IMX8MQ_VIDEO_PLL1] = imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10);
+	hws[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_VPU_PLL_REF_SEL] = imx_clk_hw_mux("vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_AUDIO_PLL1_REF_SEL] = imx_clk_hw_mux("audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_AUDIO_PLL2_REF_SEL] = imx_clk_hw_mux("audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_VIDEO_PLL1_REF_SEL] = imx_clk_hw_mux("video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_SYS3_PLL1_REF_SEL]	= imx_clk_hw_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_DRAM_PLL1_REF_SEL]	= imx_clk_hw_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+	hws[IMX8MQ_VIDEO2_PLL1_REF_SEL] = imx_clk_hw_mux("video2_pll1_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+	hws[IMX8MQ_ARM_PLL_REF_DIV]	= imx_clk_hw_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
+	hws[IMX8MQ_GPU_PLL_REF_DIV]	= imx_clk_hw_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
+	hws[IMX8MQ_VPU_PLL_REF_DIV]	= imx_clk_hw_divider("vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6);
+	hws[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_hw_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6);
+	hws[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_hw_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6);
+	hws[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_hw_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6);
+
+	hws[IMX8MQ_ARM_PLL] = imx_clk_hw_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
+	hws[IMX8MQ_GPU_PLL] = imx_clk_hw_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
+	hws[IMX8MQ_VPU_PLL] = imx_clk_hw_frac_pll("vpu_pll", "vpu_pll_ref_div", base + 0x20);
+	hws[IMX8MQ_AUDIO_PLL1] = imx_clk_hw_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0);
+	hws[IMX8MQ_AUDIO_PLL2] = imx_clk_hw_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8);
+	hws[IMX8MQ_VIDEO_PLL1] = imx_clk_hw_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10);
 
 	/* PLL bypass out */
-	clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
-	clks[IMX8MQ_GPU_PLL_BYPASS] = imx_clk_mux("gpu_pll_bypass", base + 0x18, 14, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels));
-	clks[IMX8MQ_VPU_PLL_BYPASS] = imx_clk_mux("vpu_pll_bypass", base + 0x20, 14, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels));
-	clks[IMX8MQ_AUDIO_PLL1_BYPASS] = imx_clk_mux("audio_pll1_bypass", base + 0x0, 14, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels));
-	clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
-	clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
+	hws[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_hw_mux_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+	hws[IMX8MQ_GPU_PLL_BYPASS] = imx_clk_hw_mux("gpu_pll_bypass", base + 0x18, 14, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels));
+	hws[IMX8MQ_VPU_PLL_BYPASS] = imx_clk_hw_mux("vpu_pll_bypass", base + 0x20, 14, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels));
+	hws[IMX8MQ_AUDIO_PLL1_BYPASS] = imx_clk_hw_mux("audio_pll1_bypass", base + 0x0, 14, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels));
+	hws[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_hw_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
+	hws[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_hw_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
 
 	/* PLL OUT GATE */
-	clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
-	clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
-	clks[IMX8MQ_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x20, 21);
-	clks[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21);
-	clks[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21);
-	clks[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21);
-
-	clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_sccg_pll("sys1_pll_out", sys1_pll_out_sels, ARRAY_SIZE(sys1_pll_out_sels), 0, 0, 0, base + 0x30, CLK_IS_CRITICAL);
-	clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_sccg_pll("sys2_pll_out", sys2_pll_out_sels, ARRAY_SIZE(sys2_pll_out_sels), 0, 0, 1, base + 0x3c, CLK_IS_CRITICAL);
-	clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_sccg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 1, base + 0x48, CLK_IS_CRITICAL);
-	clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_sccg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL);
-	/* SYS PLL fixed output */
-	clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
-	clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
-	clks[IMX8MQ_SYS1_PLL_100M] = imx_clk_fixed_factor("sys1_pll_100m", "sys1_pll_out", 1, 8);
-	clks[IMX8MQ_SYS1_PLL_133M] = imx_clk_fixed_factor("sys1_pll_133m", "sys1_pll_out", 1, 6);
-	clks[IMX8MQ_SYS1_PLL_160M] = imx_clk_fixed_factor("sys1_pll_160m", "sys1_pll_out", 1, 5);
-	clks[IMX8MQ_SYS1_PLL_200M] = imx_clk_fixed_factor("sys1_pll_200m", "sys1_pll_out", 1, 4);
-	clks[IMX8MQ_SYS1_PLL_266M] = imx_clk_fixed_factor("sys1_pll_266m", "sys1_pll_out", 1, 3);
-	clks[IMX8MQ_SYS1_PLL_400M] = imx_clk_fixed_factor("sys1_pll_400m", "sys1_pll_out", 1, 2);
-	clks[IMX8MQ_SYS1_PLL_800M] = imx_clk_fixed_factor("sys1_pll_800m", "sys1_pll_out", 1, 1);
-
-	clks[IMX8MQ_SYS2_PLL_50M] = imx_clk_fixed_factor("sys2_pll_50m", "sys2_pll_out", 1, 20);
-	clks[IMX8MQ_SYS2_PLL_100M] = imx_clk_fixed_factor("sys2_pll_100m", "sys2_pll_out", 1, 10);
-	clks[IMX8MQ_SYS2_PLL_125M] = imx_clk_fixed_factor("sys2_pll_125m", "sys2_pll_out", 1, 8);
-	clks[IMX8MQ_SYS2_PLL_166M] = imx_clk_fixed_factor("sys2_pll_166m", "sys2_pll_out", 1, 6);
-	clks[IMX8MQ_SYS2_PLL_200M] = imx_clk_fixed_factor("sys2_pll_200m", "sys2_pll_out", 1, 5);
-	clks[IMX8MQ_SYS2_PLL_250M] = imx_clk_fixed_factor("sys2_pll_250m", "sys2_pll_out", 1, 4);
-	clks[IMX8MQ_SYS2_PLL_333M] = imx_clk_fixed_factor("sys2_pll_333m", "sys2_pll_out", 1, 3);
-	clks[IMX8MQ_SYS2_PLL_500M] = imx_clk_fixed_factor("sys2_pll_500m", "sys2_pll_out", 1, 2);
-	clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
+	hws[IMX8MQ_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
+	hws[IMX8MQ_GPU_PLL_OUT] = imx_clk_hw_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
+	hws[IMX8MQ_VPU_PLL_OUT] = imx_clk_hw_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x20, 21);
+	hws[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_hw_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21);
+	hws[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_hw_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21);
+	hws[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_hw_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21);
+
+	hws[IMX8MQ_SYS1_PLL_OUT] = imx_clk_hw_fixed("sys1_pll_out", 800000000);
+	hws[IMX8MQ_SYS2_PLL_OUT] = imx_clk_hw_fixed("sys2_pll_out", 1000000000);
+	hws[IMX8MQ_SYS3_PLL_OUT] = imx_clk_hw_sscg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 0, base + 0x48, CLK_IS_CRITICAL);
+	hws[IMX8MQ_DRAM_PLL_OUT] = imx_clk_hw_sscg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
+	hws[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_hw_sscg_pll("video2_pll_out", video2_pll_out_sels, ARRAY_SIZE(video2_pll_out_sels), 0, 0, 0, base + 0x54, 0);
+
+	/* SYS PLL1 fixed output */
+	hws[IMX8MQ_SYS1_PLL_40M_CG] = imx_clk_hw_gate("sys1_pll_40m_cg", "sys1_pll_out", base + 0x30, 9);
+	hws[IMX8MQ_SYS1_PLL_80M_CG] = imx_clk_hw_gate("sys1_pll_80m_cg", "sys1_pll_out", base + 0x30, 11);
+	hws[IMX8MQ_SYS1_PLL_100M_CG] = imx_clk_hw_gate("sys1_pll_100m_cg", "sys1_pll_out", base + 0x30, 13);
+	hws[IMX8MQ_SYS1_PLL_133M_CG] = imx_clk_hw_gate("sys1_pll_133m_cg", "sys1_pll_out", base + 0x30, 15);
+	hws[IMX8MQ_SYS1_PLL_160M_CG] = imx_clk_hw_gate("sys1_pll_160m_cg", "sys1_pll_out", base + 0x30, 17);
+	hws[IMX8MQ_SYS1_PLL_200M_CG] = imx_clk_hw_gate("sys1_pll_200m_cg", "sys1_pll_out", base + 0x30, 19);
+	hws[IMX8MQ_SYS1_PLL_266M_CG] = imx_clk_hw_gate("sys1_pll_266m_cg", "sys1_pll_out", base + 0x30, 21);
+	hws[IMX8MQ_SYS1_PLL_400M_CG] = imx_clk_hw_gate("sys1_pll_400m_cg", "sys1_pll_out", base + 0x30, 23);
+	hws[IMX8MQ_SYS1_PLL_800M_CG] = imx_clk_hw_gate("sys1_pll_800m_cg", "sys1_pll_out", base + 0x30, 25);
+
+	hws[IMX8MQ_SYS1_PLL_40M] = imx_clk_hw_fixed_factor("sys1_pll_40m", "sys1_pll_40m_cg", 1, 20);
+	hws[IMX8MQ_SYS1_PLL_80M] = imx_clk_hw_fixed_factor("sys1_pll_80m", "sys1_pll_80m_cg", 1, 10);
+	hws[IMX8MQ_SYS1_PLL_100M] = imx_clk_hw_fixed_factor("sys1_pll_100m", "sys1_pll_100m_cg", 1, 8);
+	hws[IMX8MQ_SYS1_PLL_133M] = imx_clk_hw_fixed_factor("sys1_pll_133m", "sys1_pll_133m_cg", 1, 6);
+	hws[IMX8MQ_SYS1_PLL_160M] = imx_clk_hw_fixed_factor("sys1_pll_160m", "sys1_pll_160m_cg", 1, 5);
+	hws[IMX8MQ_SYS1_PLL_200M] = imx_clk_hw_fixed_factor("sys1_pll_200m", "sys1_pll_200m_cg", 1, 4);
+	hws[IMX8MQ_SYS1_PLL_266M] = imx_clk_hw_fixed_factor("sys1_pll_266m", "sys1_pll_266m_cg", 1, 3);
+	hws[IMX8MQ_SYS1_PLL_400M] = imx_clk_hw_fixed_factor("sys1_pll_400m", "sys1_pll_400m_cg", 1, 2);
+	hws[IMX8MQ_SYS1_PLL_800M] = imx_clk_hw_fixed_factor("sys1_pll_800m", "sys1_pll_800m_cg", 1, 1);
+
+	/* SYS PLL2 fixed output */
+	hws[IMX8MQ_SYS2_PLL_50M_CG] = imx_clk_hw_gate("sys2_pll_50m_cg", "sys2_pll_out", base + 0x3c, 9);
+	hws[IMX8MQ_SYS2_PLL_100M_CG] = imx_clk_hw_gate("sys2_pll_100m_cg", "sys2_pll_out", base + 0x3c, 11);
+	hws[IMX8MQ_SYS2_PLL_125M_CG] = imx_clk_hw_gate("sys2_pll_125m_cg", "sys2_pll_out", base + 0x3c, 13);
+	hws[IMX8MQ_SYS2_PLL_166M_CG] = imx_clk_hw_gate("sys2_pll_166m_cg", "sys2_pll_out", base + 0x3c, 15);
+	hws[IMX8MQ_SYS2_PLL_200M_CG] = imx_clk_hw_gate("sys2_pll_200m_cg", "sys2_pll_out", base + 0x3c, 17);
+	hws[IMX8MQ_SYS2_PLL_250M_CG] = imx_clk_hw_gate("sys2_pll_250m_cg", "sys2_pll_out", base + 0x3c, 19);
+	hws[IMX8MQ_SYS2_PLL_333M_CG] = imx_clk_hw_gate("sys2_pll_333m_cg", "sys2_pll_out", base + 0x3c, 21);
+	hws[IMX8MQ_SYS2_PLL_500M_CG] = imx_clk_hw_gate("sys2_pll_500m_cg", "sys2_pll_out", base + 0x3c, 23);
+	hws[IMX8MQ_SYS2_PLL_1000M_CG] = imx_clk_hw_gate("sys2_pll_1000m_cg", "sys2_pll_out", base + 0x3c, 25);
+
+	hws[IMX8MQ_SYS2_PLL_50M] = imx_clk_hw_fixed_factor("sys2_pll_50m", "sys2_pll_50m_cg", 1, 20);
+	hws[IMX8MQ_SYS2_PLL_100M] = imx_clk_hw_fixed_factor("sys2_pll_100m", "sys2_pll_100m_cg", 1, 10);
+	hws[IMX8MQ_SYS2_PLL_125M] = imx_clk_hw_fixed_factor("sys2_pll_125m", "sys2_pll_125m_cg", 1, 8);
+	hws[IMX8MQ_SYS2_PLL_166M] = imx_clk_hw_fixed_factor("sys2_pll_166m", "sys2_pll_166m_cg", 1, 6);
+	hws[IMX8MQ_SYS2_PLL_200M] = imx_clk_hw_fixed_factor("sys2_pll_200m", "sys2_pll_200m_cg", 1, 5);
+	hws[IMX8MQ_SYS2_PLL_250M] = imx_clk_hw_fixed_factor("sys2_pll_250m", "sys2_pll_250m_cg", 1, 4);
+	hws[IMX8MQ_SYS2_PLL_333M] = imx_clk_hw_fixed_factor("sys2_pll_333m", "sys2_pll_333m_cg", 1, 3);
+	hws[IMX8MQ_SYS2_PLL_500M] = imx_clk_hw_fixed_factor("sys2_pll_500m", "sys2_pll_500m_cg", 1, 2);
+	hws[IMX8MQ_SYS2_PLL_1000M] = imx_clk_hw_fixed_factor("sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1);
+
+	hws[IMX8MQ_CLK_MON_AUDIO_PLL1_DIV] = imx_clk_hw_divider("audio_pll1_out_monitor", "audio_pll1_bypass", base + 0x78, 0, 3);
+	hws[IMX8MQ_CLK_MON_AUDIO_PLL2_DIV] = imx_clk_hw_divider("audio_pll2_out_monitor", "audio_pll2_bypass", base + 0x78, 4, 3);
+	hws[IMX8MQ_CLK_MON_VIDEO_PLL1_DIV] = imx_clk_hw_divider("video_pll1_out_monitor", "video_pll1_bypass", base + 0x78, 8, 3);
+	hws[IMX8MQ_CLK_MON_GPU_PLL_DIV] = imx_clk_hw_divider("gpu_pll_out_monitor", "gpu_pll_bypass", base + 0x78, 12, 3);
+	hws[IMX8MQ_CLK_MON_VPU_PLL_DIV] = imx_clk_hw_divider("vpu_pll_out_monitor", "vpu_pll_bypass", base + 0x78, 16, 3);
+	hws[IMX8MQ_CLK_MON_ARM_PLL_DIV] = imx_clk_hw_divider("arm_pll_out_monitor", "arm_pll_bypass", base + 0x78, 20, 3);
+	hws[IMX8MQ_CLK_MON_SYS_PLL1_DIV] = imx_clk_hw_divider("sys_pll1_out_monitor", "sys1_pll_out", base + 0x7c, 0, 3);
+	hws[IMX8MQ_CLK_MON_SYS_PLL2_DIV] = imx_clk_hw_divider("sys_pll2_out_monitor", "sys2_pll_out", base + 0x7c, 4, 3);
+	hws[IMX8MQ_CLK_MON_SYS_PLL3_DIV] = imx_clk_hw_divider("sys_pll3_out_monitor", "sys3_pll_out", base + 0x7c, 8, 3);
+	hws[IMX8MQ_CLK_MON_DRAM_PLL_DIV] = imx_clk_hw_divider("dram_pll_out_monitor", "dram_pll_out", base + 0x7c, 12, 3);
+	hws[IMX8MQ_CLK_MON_VIDEO_PLL2_DIV] = imx_clk_hw_divider("video_pll2_out_monitor", "video2_pll_out", base + 0x7c, 16, 3);
+	hws[IMX8MQ_CLK_MON_SEL] = imx_clk_hw_mux("pllout_monitor_sel", base + 0x74, 0, 4, pllout_monitor_sels, ARRAY_SIZE(pllout_monitor_sels));
+	hws[IMX8MQ_CLK_MON_CLK2_OUT] = imx_clk_hw_gate("pllout_monitor_clk2", "pllout_monitor_sel", base + 0x74, 4);
 
 	np = dev->of_node;
 	base = devm_platform_ioremap_resource(pdev, 0);
@@ -373,206 +428,220 @@
 		return PTR_ERR(base);
 
 	/* CORE */
-	clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
-	clks[IMX8MQ_CLK_M4_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mq_arm_m4_sels, ARRAY_SIZE(imx8mq_arm_m4_sels));
-	clks[IMX8MQ_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels));
-	clks[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3,  imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels));
-	clks[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels,  ARRAY_SIZE(imx8mq_gpu_shader_sels));
-
-	clks[IMX8MQ_CLK_A53_CG] = imx_clk_gate3_flags("arm_a53_cg", "arm_a53_src", base + 0x8000, 28, CLK_IS_CRITICAL);
-	clks[IMX8MQ_CLK_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
-	clks[IMX8MQ_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
-	clks[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
-	clks[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
-
-	clks[IMX8MQ_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
-	clks[IMX8MQ_CLK_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
-	clks[IMX8MQ_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
-	clks[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
-	clks[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
+	hws[IMX8MQ_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mq_a53_sels, base + 0x8000);
+	hws[IMX8MQ_CLK_A53_CG] = hws[IMX8MQ_CLK_A53_DIV];
+	hws[IMX8MQ_CLK_A53_SRC] = hws[IMX8MQ_CLK_A53_DIV];
+
+	hws[IMX8MQ_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mq_arm_m4_sels, base + 0x8080);
+	hws[IMX8MQ_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mq_vpu_sels, base + 0x8100);
+	hws[IMX8MQ_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mq_gpu_core_sels, base + 0x8180);
+	hws[IMX8MQ_CLK_GPU_SHADER] = imx8m_clk_hw_composite("gpu_shader", imx8mq_gpu_shader_sels, base + 0x8200);
+	/* For backwards compatibility */
+	hws[IMX8MQ_CLK_M4_SRC] = hws[IMX8MQ_CLK_M4_CORE];
+	hws[IMX8MQ_CLK_M4_CG] = hws[IMX8MQ_CLK_M4_CORE];
+	hws[IMX8MQ_CLK_M4_DIV] = hws[IMX8MQ_CLK_M4_CORE];
+	hws[IMX8MQ_CLK_VPU_SRC] = hws[IMX8MQ_CLK_VPU_CORE];
+	hws[IMX8MQ_CLK_VPU_CG] = hws[IMX8MQ_CLK_VPU_CORE];
+	hws[IMX8MQ_CLK_VPU_DIV] = hws[IMX8MQ_CLK_VPU_CORE];
+	hws[IMX8MQ_CLK_GPU_CORE_SRC] = hws[IMX8MQ_CLK_GPU_CORE];
+	hws[IMX8MQ_CLK_GPU_CORE_CG] = hws[IMX8MQ_CLK_GPU_CORE];
+	hws[IMX8MQ_CLK_GPU_CORE_DIV] = hws[IMX8MQ_CLK_GPU_CORE];
+	hws[IMX8MQ_CLK_GPU_SHADER_SRC] = hws[IMX8MQ_CLK_GPU_SHADER];
+	hws[IMX8MQ_CLK_GPU_SHADER_CG] = hws[IMX8MQ_CLK_GPU_SHADER];
+	hws[IMX8MQ_CLK_GPU_SHADER_DIV] = hws[IMX8MQ_CLK_GPU_SHADER];
+
+	/* CORE SEL */
+	hws[IMX8MQ_CLK_A53_CORE] = imx_clk_hw_mux2("arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels));
 
 	/* BUS */
-	clks[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800);
-	clks[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
-	clks[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
-	clks[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
-	clks[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
-	clks[IMX8MQ_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
-	clks[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
-	clks[IMX8MQ_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
-	clks[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
-	clks[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
-	clks[IMX8MQ_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mq_noc_sels, base + 0x8d00);
-	clks[IMX8MQ_CLK_NOC_APB] = imx8m_clk_composite_critical("noc_apb", imx8mq_noc_apb_sels, base + 0x8d80);
+	hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800);
+	hws[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
+	hws[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
+	hws[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
+	hws[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
+	hws[IMX8MQ_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
+	hws[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_hw_composite_bus("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
+	hws[IMX8MQ_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
+	hws[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
+	hws[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
+	hws[IMX8MQ_CLK_NOC] = imx8m_clk_hw_composite_bus_critical("noc", imx8mq_noc_sels, base + 0x8d00);
+	hws[IMX8MQ_CLK_NOC_APB] = imx8m_clk_hw_composite_bus_critical("noc_apb", imx8mq_noc_apb_sels, base + 0x8d80);
 
 	/* AHB */
 	/* AHB clock is used by the AHB bus therefore marked as critical */
-	clks[IMX8MQ_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mq_ahb_sels, base + 0x9000);
-	clks[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
+	hws[IMX8MQ_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb", imx8mq_ahb_sels, base + 0x9000);
+	hws[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
 
 	/* IPG */
-	clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
-	clks[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
+	hws[IMX8MQ_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
+	hws[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
+
+	/*
+	 * DRAM clocks are manipulated from TF-A outside clock framework.
+	 * Mark with GET_RATE_NOCACHE to always read div value from hardware
+	 */
+	hws[IMX8MQ_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels), CLK_IS_CRITICAL);
+	hws[IMX8MQ_CLK_DRAM_ALT] = __imx8m_clk_hw_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000, CLK_GET_RATE_NOCACHE);
+	hws[IMX8MQ_CLK_DRAM_APB] = __imx8m_clk_hw_composite("dram_apb", imx8mq_dram_apb_sels, base + 0xa080, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
 
 	/* IP */
-	clks[IMX8MQ_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels), CLK_IS_CRITICAL);
+	hws[IMX8MQ_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mq_vpu_g1_sels, base + 0xa100);
+	hws[IMX8MQ_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mq_vpu_g2_sels, base + 0xa180);
+	hws[IMX8MQ_CLK_DISP_DTRC] = imx8m_clk_hw_composite("disp_dtrc", imx8mq_disp_dtrc_sels, base + 0xa200);
+	hws[IMX8MQ_CLK_DISP_DC8000] = imx8m_clk_hw_composite("disp_dc8000", imx8mq_disp_dc8000_sels, base + 0xa280);
+	hws[IMX8MQ_CLK_PCIE1_CTRL] = imx8m_clk_hw_composite("pcie1_ctrl", imx8mq_pcie1_ctrl_sels, base + 0xa300);
+	hws[IMX8MQ_CLK_PCIE1_PHY] = imx8m_clk_hw_composite("pcie1_phy", imx8mq_pcie1_phy_sels, base + 0xa380);
+	hws[IMX8MQ_CLK_PCIE1_AUX] = imx8m_clk_hw_composite("pcie1_aux", imx8mq_pcie1_aux_sels, base + 0xa400);
+	hws[IMX8MQ_CLK_DC_PIXEL] = imx8m_clk_hw_composite("dc_pixel", imx8mq_dc_pixel_sels, base + 0xa480);
+	hws[IMX8MQ_CLK_LCDIF_PIXEL] = imx8m_clk_hw_composite("lcdif_pixel", imx8mq_lcdif_pixel_sels, base + 0xa500);
+	hws[IMX8MQ_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mq_sai1_sels, base + 0xa580);
+	hws[IMX8MQ_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mq_sai2_sels, base + 0xa600);
+	hws[IMX8MQ_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mq_sai3_sels, base + 0xa680);
+	hws[IMX8MQ_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mq_sai4_sels, base + 0xa700);
+	hws[IMX8MQ_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mq_sai5_sels, base + 0xa780);
+	hws[IMX8MQ_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mq_sai6_sels, base + 0xa800);
+	hws[IMX8MQ_CLK_SPDIF1] = imx8m_clk_hw_composite("spdif1", imx8mq_spdif1_sels, base + 0xa880);
+	hws[IMX8MQ_CLK_SPDIF2] = imx8m_clk_hw_composite("spdif2", imx8mq_spdif2_sels, base + 0xa900);
+	hws[IMX8MQ_CLK_ENET_REF] = imx8m_clk_hw_composite("enet_ref", imx8mq_enet_ref_sels, base + 0xa980);
+	hws[IMX8MQ_CLK_ENET_TIMER] = imx8m_clk_hw_composite("enet_timer", imx8mq_enet_timer_sels, base + 0xaa00);
+	hws[IMX8MQ_CLK_ENET_PHY_REF] = imx8m_clk_hw_composite("enet_phy", imx8mq_enet_phy_sels, base + 0xaa80);
+	hws[IMX8MQ_CLK_NAND] = imx8m_clk_hw_composite("nand", imx8mq_nand_sels, base + 0xab00);
+	hws[IMX8MQ_CLK_QSPI] = imx8m_clk_hw_composite("qspi", imx8mq_qspi_sels, base + 0xab80);
+	hws[IMX8MQ_CLK_USDHC1] = imx8m_clk_hw_composite("usdhc1", imx8mq_usdhc1_sels, base + 0xac00);
+	hws[IMX8MQ_CLK_USDHC2] = imx8m_clk_hw_composite("usdhc2", imx8mq_usdhc2_sels, base + 0xac80);
+	hws[IMX8MQ_CLK_I2C1] = imx8m_clk_hw_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00);
+	hws[IMX8MQ_CLK_I2C2] = imx8m_clk_hw_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80);
+	hws[IMX8MQ_CLK_I2C3] = imx8m_clk_hw_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00);
+	hws[IMX8MQ_CLK_I2C4] = imx8m_clk_hw_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80);
+	hws[IMX8MQ_CLK_UART1] = imx8m_clk_hw_composite("uart1", imx8mq_uart1_sels, base + 0xaf00);
+	hws[IMX8MQ_CLK_UART2] = imx8m_clk_hw_composite("uart2", imx8mq_uart2_sels, base + 0xaf80);
+	hws[IMX8MQ_CLK_UART3] = imx8m_clk_hw_composite("uart3", imx8mq_uart3_sels, base + 0xb000);
+	hws[IMX8MQ_CLK_UART4] = imx8m_clk_hw_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
+	hws[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_hw_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
+	hws[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_hw_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
+	hws[IMX8MQ_CLK_GIC] = imx8m_clk_hw_composite_critical("gic", imx8mq_gic_sels, base + 0xb200);
+	hws[IMX8MQ_CLK_ECSPI1] = imx8m_clk_hw_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
+	hws[IMX8MQ_CLK_ECSPI2] = imx8m_clk_hw_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
+	hws[IMX8MQ_CLK_PWM1] = imx8m_clk_hw_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
+	hws[IMX8MQ_CLK_PWM2] = imx8m_clk_hw_composite("pwm2", imx8mq_pwm2_sels, base + 0xb400);
+	hws[IMX8MQ_CLK_PWM3] = imx8m_clk_hw_composite("pwm3", imx8mq_pwm3_sels, base + 0xb480);
+	hws[IMX8MQ_CLK_PWM4] = imx8m_clk_hw_composite("pwm4", imx8mq_pwm4_sels, base + 0xb500);
+	hws[IMX8MQ_CLK_GPT1] = imx8m_clk_hw_composite("gpt1", imx8mq_gpt1_sels, base + 0xb580);
+	hws[IMX8MQ_CLK_WDOG] = imx8m_clk_hw_composite("wdog", imx8mq_wdog_sels, base + 0xb900);
+	hws[IMX8MQ_CLK_WRCLK] = imx8m_clk_hw_composite("wrclk", imx8mq_wrclk_sels, base + 0xb980);
+	hws[IMX8MQ_CLK_CLKO1] = imx8m_clk_hw_composite("clko1", imx8mq_clko1_sels, base + 0xba00);
+	hws[IMX8MQ_CLK_CLKO2] = imx8m_clk_hw_composite("clko2", imx8mq_clko2_sels, base + 0xba80);
+	hws[IMX8MQ_CLK_DSI_CORE] = imx8m_clk_hw_composite("dsi_core", imx8mq_dsi_core_sels, base + 0xbb00);
+	hws[IMX8MQ_CLK_DSI_PHY_REF] = imx8m_clk_hw_composite("dsi_phy_ref", imx8mq_dsi_phy_sels, base + 0xbb80);
+	hws[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_hw_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00);
+	hws[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_hw_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80);
+	hws[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_hw_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200);
+	hws[IMX8MQ_CLK_DSI_IPG_DIV] = imx_clk_hw_divider2("dsi_ipg_div", "dsi_ahb", base + 0x9280, 0, 6);
+	hws[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_hw_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00);
+	hws[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_hw_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80);
+	hws[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_hw_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00);
+	hws[IMX8MQ_CLK_CSI2_CORE] = imx8m_clk_hw_composite("csi2_core", imx8mq_csi2_core_sels, base + 0xbe80);
+	hws[IMX8MQ_CLK_CSI2_PHY_REF] = imx8m_clk_hw_composite("csi2_phy_ref", imx8mq_csi2_phy_sels, base + 0xbf00);
+	hws[IMX8MQ_CLK_CSI2_ESC] = imx8m_clk_hw_composite("csi2_esc", imx8mq_csi2_esc_sels, base + 0xbf80);
+	hws[IMX8MQ_CLK_PCIE2_CTRL] = imx8m_clk_hw_composite("pcie2_ctrl", imx8mq_pcie2_ctrl_sels, base + 0xc000);
+	hws[IMX8MQ_CLK_PCIE2_PHY] = imx8m_clk_hw_composite("pcie2_phy", imx8mq_pcie2_phy_sels, base + 0xc080);
+	hws[IMX8MQ_CLK_PCIE2_AUX] = imx8m_clk_hw_composite("pcie2_aux", imx8mq_pcie2_aux_sels, base + 0xc100);
+	hws[IMX8MQ_CLK_ECSPI3] = imx8m_clk_hw_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180);
+
+	hws[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
+	hws[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
+	hws[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
+	hws[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_hw_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+	hws[IMX8MQ_CLK_GPIO1_ROOT] = imx_clk_hw_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+	hws[IMX8MQ_CLK_GPIO2_ROOT] = imx_clk_hw_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+	hws[IMX8MQ_CLK_GPIO3_ROOT] = imx_clk_hw_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+	hws[IMX8MQ_CLK_GPIO4_ROOT] = imx_clk_hw_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+	hws[IMX8MQ_CLK_GPIO5_ROOT] = imx_clk_hw_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
+	hws[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
+	hws[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
+	hws[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
+	hws[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
+	hws[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
+	hws[IMX8MQ_CLK_MU_ROOT] = imx_clk_hw_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
+	hws[IMX8MQ_CLK_OCOTP_ROOT] = imx_clk_hw_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
+	hws[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_hw_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
+	hws[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_hw_gate4("pcie2_root_clk", "pcie2_ctrl", base + 0x4640, 0);
+	hws[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
+	hws[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
+	hws[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
+	hws[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
+	hws[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_hw_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
+	hws[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_hw_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
+	hws[IMX8MQ_CLK_SAI1_ROOT] = imx_clk_hw_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1);
+	hws[IMX8MQ_CLK_SAI1_IPG] = imx_clk_hw_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
+	hws[IMX8MQ_CLK_SAI2_ROOT] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MQ_CLK_SAI2_IPG] = imx_clk_hw_gate2_shared2("sai2_ipg_clk", "ipg_root", base + 0x4340, 0, &share_count_sai2);
+	hws[IMX8MQ_CLK_SAI3_ROOT] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MQ_CLK_SAI3_IPG] = imx_clk_hw_gate2_shared2("sai3_ipg_clk", "ipg_root", base + 0x4350, 0, &share_count_sai3);
+	hws[IMX8MQ_CLK_SAI4_ROOT] = imx_clk_hw_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4);
+	hws[IMX8MQ_CLK_SAI4_IPG] = imx_clk_hw_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
+	hws[IMX8MQ_CLK_SAI5_ROOT] = imx_clk_hw_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MQ_CLK_SAI5_IPG] = imx_clk_hw_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
+	hws[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_hw_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MQ_CLK_SAI6_IPG] = imx_clk_hw_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+	hws[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_hw_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
+	hws[IMX8MQ_CLK_UART1_ROOT] = imx_clk_hw_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
+	hws[IMX8MQ_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
+	hws[IMX8MQ_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
+	hws[IMX8MQ_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
+	hws[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_hw_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
+	hws[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_hw_gate4("usb2_ctrl_root_clk", "usb_bus", base + 0x44e0, 0);
+	hws[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_hw_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0);
+	hws[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_hw_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0);
+	hws[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
+	hws[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
+	hws[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_hw_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
+	hws[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_hw_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
+	hws[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_hw_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
+	hws[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_hw_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+	hws[IMX8MQ_CLK_GPU_ROOT] = imx_clk_hw_gate4("gpu_root_clk", "gpu_core", base + 0x4570, 0);
+	hws[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_hw_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+	hws[IMX8MQ_CLK_DISP_ROOT] = imx_clk_hw_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss);
+	hws[IMX8MQ_CLK_DISP_AXI_ROOT]  = imx_clk_hw_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss);
+	hws[IMX8MQ_CLK_DISP_APB_ROOT]  = imx_clk_hw_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_dcss);
+	hws[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_hw_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_dcss);
+	hws[IMX8MQ_CLK_TMU_ROOT] = imx_clk_hw_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+	hws[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_hw_gate2_flags("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+	hws[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_hw_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
+	hws[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_hw_gate4("csi2_root_clk", "csi2_core", base + 0x4660, 0);
+	hws[IMX8MQ_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+	hws[IMX8MQ_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
+
+	hws[IMX8MQ_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc_25m", 1, 8);
+	hws[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_hw_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
+
+	hws[IMX8MQ_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a53_core",
+					   hws[IMX8MQ_CLK_A53_CORE]->clk,
+					   hws[IMX8MQ_CLK_A53_CORE]->clk,
+					   hws[IMX8MQ_ARM_PLL_OUT]->clk,
+					   hws[IMX8MQ_CLK_A53_DIV]->clk);
 
-	clks[IMX8MQ_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000);
-	clks[IMX8MQ_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mq_dram_apb_sels, base + 0xa080);
-	clks[IMX8MQ_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mq_vpu_g1_sels, base + 0xa100);
-	clks[IMX8MQ_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mq_vpu_g2_sels, base + 0xa180);
-	clks[IMX8MQ_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mq_disp_dtrc_sels, base + 0xa200);
-	clks[IMX8MQ_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mq_disp_dc8000_sels, base + 0xa280);
-	clks[IMX8MQ_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mq_pcie1_ctrl_sels, base + 0xa300);
-	clks[IMX8MQ_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mq_pcie1_phy_sels, base + 0xa380);
-	clks[IMX8MQ_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mq_pcie1_aux_sels, base + 0xa400);
-	clks[IMX8MQ_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mq_dc_pixel_sels, base + 0xa480);
-	clks[IMX8MQ_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mq_lcdif_pixel_sels, base + 0xa500);
-	clks[IMX8MQ_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mq_sai1_sels, base + 0xa580);
-	clks[IMX8MQ_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mq_sai2_sels, base + 0xa600);
-	clks[IMX8MQ_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mq_sai3_sels, base + 0xa680);
-	clks[IMX8MQ_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mq_sai4_sels, base + 0xa700);
-	clks[IMX8MQ_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mq_sai5_sels, base + 0xa780);
-	clks[IMX8MQ_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mq_sai6_sels, base + 0xa800);
-	clks[IMX8MQ_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mq_spdif1_sels, base + 0xa880);
-	clks[IMX8MQ_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mq_spdif2_sels, base + 0xa900);
-	clks[IMX8MQ_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mq_enet_ref_sels, base + 0xa980);
-	clks[IMX8MQ_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mq_enet_timer_sels, base + 0xaa00);
-	clks[IMX8MQ_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mq_enet_phy_sels, base + 0xaa80);
-	clks[IMX8MQ_CLK_NAND] = imx8m_clk_composite("nand", imx8mq_nand_sels, base + 0xab00);
-	clks[IMX8MQ_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mq_qspi_sels, base + 0xab80);
-	clks[IMX8MQ_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mq_usdhc1_sels, base + 0xac00);
-	clks[IMX8MQ_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mq_usdhc2_sels, base + 0xac80);
-	clks[IMX8MQ_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00);
-	clks[IMX8MQ_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80);
-	clks[IMX8MQ_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00);
-	clks[IMX8MQ_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80);
-	clks[IMX8MQ_CLK_UART1] = imx8m_clk_composite("uart1", imx8mq_uart1_sels, base + 0xaf00);
-	clks[IMX8MQ_CLK_UART2] = imx8m_clk_composite("uart2", imx8mq_uart2_sels, base + 0xaf80);
-	clks[IMX8MQ_CLK_UART3] = imx8m_clk_composite("uart3", imx8mq_uart3_sels, base + 0xb000);
-	clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
-	clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
-	clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
-	clks[IMX8MQ_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mq_gic_sels, base + 0xb200);
-	clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
-	clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
-	clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
-	clks[IMX8MQ_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mq_pwm2_sels, base + 0xb400);
-	clks[IMX8MQ_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mq_pwm3_sels, base + 0xb480);
-	clks[IMX8MQ_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mq_pwm4_sels, base + 0xb500);
-	clks[IMX8MQ_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mq_gpt1_sels, base + 0xb580);
-	clks[IMX8MQ_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mq_wdog_sels, base + 0xb900);
-	clks[IMX8MQ_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mq_wrclk_sels, base + 0xb980);
-	clks[IMX8MQ_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mq_clko1_sels, base + 0xba00);
-	clks[IMX8MQ_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mq_clko2_sels, base + 0xba80);
-	clks[IMX8MQ_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mq_dsi_core_sels, base + 0xbb00);
-	clks[IMX8MQ_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mq_dsi_phy_sels, base + 0xbb80);
-	clks[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00);
-	clks[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80);
-	clks[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200);
-	clks[IMX8MQ_CLK_DSI_IPG_DIV] = imx_clk_divider2("dsi_ipg_div", "dsi_ahb", base + 0x9280, 0, 6);
-	clks[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00);
-	clks[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80);
-	clks[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00);
-	clks[IMX8MQ_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mq_csi2_core_sels, base + 0xbe80);
-	clks[IMX8MQ_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mq_csi2_phy_sels, base + 0xbf00);
-	clks[IMX8MQ_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mq_csi2_esc_sels, base + 0xbf80);
-	clks[IMX8MQ_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mq_pcie2_ctrl_sels, base + 0xc000);
-	clks[IMX8MQ_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mq_pcie2_phy_sels, base + 0xc080);
-	clks[IMX8MQ_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mq_pcie2_aux_sels, base + 0xc100);
-	clks[IMX8MQ_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180);
-
-	clks[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
-	clks[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
-	clks[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
-	clks[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
-	clks[IMX8MQ_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
-	clks[IMX8MQ_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
-	clks[IMX8MQ_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
-	clks[IMX8MQ_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
-	clks[IMX8MQ_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
-	clks[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
-	clks[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
-	clks[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
-	clks[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
-	clks[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
-	clks[IMX8MQ_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
-	clks[IMX8MQ_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
-	clks[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
-	clks[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_gate4("pcie2_root_clk", "pcie2_ctrl", base + 0x4640, 0);
-	clks[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
-	clks[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
-	clks[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
-	clks[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
-	clks[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
-	clks[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
-	clks[IMX8MQ_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1);
-	clks[IMX8MQ_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
-	clks[IMX8MQ_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MQ_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root", base + 0x4340, 0, &share_count_sai2);
-	clks[IMX8MQ_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MQ_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root", base + 0x4350, 0, &share_count_sai3);
-	clks[IMX8MQ_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4);
-	clks[IMX8MQ_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
-	clks[IMX8MQ_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
-	clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
-	clks[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
-	clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
-	clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
-	clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
-	clks[IMX8MQ_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
-	clks[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0);
-	clks[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_gate4("usb2_ctrl_root_clk", "usb_bus", base + 0x44e0, 0);
-	clks[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0);
-	clks[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0);
-	clks[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
-	clks[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
-	clks[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
-	clks[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
-	clks[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
-	clks[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
-	clks[IMX8MQ_CLK_GPU_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0);
-	clks[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
-	clks[IMX8MQ_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss);
-	clks[IMX8MQ_CLK_DISP_AXI_ROOT]  = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss);
-	clks[IMX8MQ_CLK_DISP_APB_ROOT]  = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_dcss);
-	clks[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_dcss);
-	clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
-	clks[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_gate2_flags("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
-	clks[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
-	clks[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_gate4("csi2_root_clk", "csi2_core", base + 0x4660, 0);
-	clks[IMX8MQ_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
-	clks[IMX8MQ_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
-
-	clks[IMX8MQ_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc_25m", 1, 8);
-	clks[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
-
-	clks[IMX8MQ_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div",
-					   clks[IMX8MQ_CLK_A53_DIV],
-					   clks[IMX8MQ_CLK_A53_SRC],
-					   clks[IMX8MQ_ARM_PLL_OUT],
-					   clks[IMX8MQ_SYS1_PLL_800M]);
+	imx_check_clk_hws(hws, IMX8MQ_CLK_END);
 
-	imx_check_clocks(clks, ARRAY_SIZE(clks));
+	err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+	if (err < 0) {
+		dev_err(dev, "failed to register hws for i.MX8MQ\n");
+		goto unregister_hws;
+	}
 
-	clk_data.clks = clks;
-	clk_data.clk_num = ARRAY_SIZE(clks);
+	for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+		int index = uart_clk_ids[i];
 
-	err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-	if (err < 0) {
-		dev_err(dev, "failed to register clks for i.MX8MQ\n");
-		goto unregister_clks;
+		uart_hws[i] = &hws[index]->clk;
 	}
 
-	imx_register_uart_clocks(uart_clks);
+	imx_register_uart_clocks(uart_hws);
 
 	return 0;
 
-unregister_clks:
-	imx_unregister_clocks(clks, ARRAY_SIZE(clks));
+unregister_hws:
+	imx_unregister_hw_clocks(hws, IMX8MQ_CLK_END);
 
 	return err;
 }
@@ -588,7 +657,16 @@
 	.probe = imx8mq_clocks_probe,
 	.driver = {
 		.name = "imx8mq-ccm",
-		.of_match_table = of_match_ptr(imx8mq_clk_of_match),
+		/*
+		 * Disable bind attributes: clocks are not removed and
+		 * reloading the driver will crash or break devices.
+		 */
+		.suppress_bind_attrs = true,
+		.of_match_table = imx8mq_clk_of_match,
 	},
 };
 module_platform_driver(imx8mq_clk_driver);
+
+MODULE_AUTHOR("Abel Vesa <abel.vesa@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8MQ clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8qxp-lpcg.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8qxp-lpcg.c
@@ -9,8 +9,10 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "clk-scu.h"
@@ -157,6 +159,135 @@
 	.num_max = IMX_LSIO_LPCG_CLK_END,
 };
 
+#define IMX_LPCG_MAX_CLKS	8
+
+static struct clk_hw *imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec,
+					      void *data)
+{
+	struct clk_hw_onecell_data *hw_data = data;
+	unsigned int idx = clkspec->args[0] / 4;
+
+	if (idx >= hw_data->num) {
+		pr_err("%s: invalid index %u\n", __func__, idx);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return hw_data->hws[idx];
+}
+
+static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
+				       struct device_node *np)
+{
+	const char *output_names[IMX_LPCG_MAX_CLKS];
+	const char *parent_names[IMX_LPCG_MAX_CLKS];
+	unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
+	struct clk_hw_onecell_data *clk_data;
+	struct clk_hw **clk_hws;
+	struct resource *res;
+	void __iomem *base;
+	int count;
+	int idx;
+	int ret;
+	int i;
+
+	if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg"))
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	count = of_property_count_u32_elems(np, "clock-indices");
+	if (count < 0) {
+		dev_err(&pdev->dev, "failed to count clocks\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * A trick here is that we set the num of clks to the MAX instead
+	 * of the count from clock-indices because one LPCG supports up to
+	 * 8 clock outputs which each of them is fixed to 4 bits. Then we can
+	 * easily get the clock by clk-indices (bit-offset) / 4.
+	 * And the cost is very limited few pointers.
+	 */
+
+	clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
+				IMX_LPCG_MAX_CLKS), GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->num = IMX_LPCG_MAX_CLKS;
+	clk_hws = clk_data->hws;
+
+	ret = of_property_read_u32_array(np, "clock-indices", bit_offset,
+					 count);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to read clock-indices\n");
+		return -EINVAL;
+	}
+
+	ret = of_clk_parent_fill(np, parent_names, count);
+	if (ret != count) {
+		dev_err(&pdev->dev, "failed to get clock parent names\n");
+		return count;
+	}
+
+	ret = of_property_read_string_array(np, "clock-output-names",
+					    output_names, count);
+	if (ret != count) {
+		dev_err(&pdev->dev, "failed to read clock-output-names\n");
+		return -EINVAL;
+	}
+
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	for (i = 0; i < count; i++) {
+		idx = bit_offset[i] / 4;
+		if (idx > IMX_LPCG_MAX_CLKS) {
+			dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
+				 i);
+			ret = -EINVAL;
+			goto unreg;
+		}
+
+		clk_hws[idx] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
+						    parent_names[i], 0, base,
+						    bit_offset[i], false);
+		if (IS_ERR(clk_hws[idx])) {
+			dev_warn(&pdev->dev, "failed to register clock %d\n",
+				 idx);
+			ret = PTR_ERR(clk_hws[idx]);
+			goto unreg;
+		}
+	}
+
+	ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get,
+					  clk_data);
+	if (ret)
+		goto unreg;
+
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
+	return 0;
+
+unreg:
+	while (--i >= 0) {
+		idx = bit_offset[i] / 4;
+		if (clk_hws[idx])
+			imx_clk_lpcg_scu_unregister(clk_hws[idx]);
+	}
+
+	pm_runtime_disable(&pdev->dev);
+
+	return ret;
+}
+
 static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -167,12 +298,29 @@
 	struct resource *res;
 	struct clk_hw **clks;
 	void __iomem *base;
+	int ret;
 	int i;
 
+	/* try new binding to parse clocks from device tree first */
+	ret = imx_lpcg_parse_clks_from_dt(pdev, np);
+	if (!ret)
+		return 0;
+
 	ss_lpcg = of_device_get_match_data(dev);
 	if (!ss_lpcg)
 		return -ENODEV;
 
+	/*
+	 * Please don't replace this with devm_platform_ioremap_resource.
+	 *
+	 * devm_platform_ioremap_resource calls devm_ioremap_resource which
+	 * differs from devm_ioremap by also calling devm_request_mem_region
+	 * and preventing other mappings in the same area.
+	 *
+	 * On imx8 the LPCG nodes map entire subsystems and overlap
+	 * peripherals, this means that using devm_platform_ioremap_resource
+	 * will cause many devices to fail to probe including serial ports.
+	 */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
 		return -EINVAL;
@@ -208,6 +356,7 @@
 	{ .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
 	{ .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
 	{ .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
+	{ .compatible = "fsl,imx8qxp-lpcg", NULL },
 	{ /* sentinel */ }
 };
 
@@ -215,9 +364,14 @@
 	.driver = {
 		.name = "imx8qxp-lpcg-clk",
 		.of_match_table = imx8qxp_lpcg_match,
+		.pm = &imx_clk_lpcg_scu_pm_ops,
 		.suppress_bind_attrs = true,
 	},
 	.probe = imx8qxp_lpcg_clk_probe,
 };
 
 builtin_platform_driver(imx8qxp_lpcg_clk_driver);
+
+MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8QXP LPCG clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-imx8qxp.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-imx8qxp.c
@@ -17,14 +17,23 @@
 #include <dt-bindings/clock/imx8-clock.h>
 #include <dt-bindings/firmware/imx/rsrc.h>
 
+static const char *dc0_sels[] = {
+	"clk_dummy",
+	"clk_dummy",
+	"dc0_pll0_clk",
+	"dc0_pll1_clk",
+	"dc0_bypass0_clk",
+};
+
 static int imx8qxp_clk_probe(struct platform_device *pdev)
 {
 	struct device_node *ccm_node = pdev->dev.of_node;
 	struct clk_hw_onecell_data *clk_data;
 	struct clk_hw **clks;
+	u32 clk_cells;
 	int ret, i;
 
-	ret = imx_clk_scu_init();
+	ret = imx_clk_scu_init(ccm_node);
 	if (ret)
 		return ret;
 
@@ -33,6 +42,9 @@
 	if (!clk_data)
 		return -ENOMEM;
 
+	if (of_property_read_u32(ccm_node, "#clock-cells", &clk_cells))
+		return -EINVAL;
+
 	clk_data->num = IMX_SCU_CLK_END;
 	clks = clk_data->hws;
 
@@ -55,78 +67,92 @@
 	clks[IMX_LSIO_BUS_CLK]		= clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
 
 	/* ARM core */
-	clks[IMX_A35_CLK]		= imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+	clks[IMX_A35_CLK]		= imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU, clk_cells);
 
 	/* LSIO SS */
-	clks[IMX_LSIO_PWM0_CLK]		= imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM1_CLK]		= imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM2_CLK]		= imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM3_CLK]		= imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM4_CLK]		= imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM5_CLK]		= imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM6_CLK]		= imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_PWM7_CLK]		= imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_GPT0_CLK]		= imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_GPT1_CLK]		= imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_GPT2_CLK]		= imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_GPT3_CLK]		= imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_GPT4_CLK]		= imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_FSPI0_CLK]	= imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_LSIO_FSPI1_CLK]	= imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
+	clks[IMX_LSIO_PWM0_CLK]		= imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM1_CLK]		= imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM2_CLK]		= imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM3_CLK]		= imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM4_CLK]		= imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM5_CLK]		= imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM6_CLK]		= imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_PWM7_CLK]		= imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_GPT0_CLK]		= imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_GPT1_CLK]		= imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_GPT2_CLK]		= imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_GPT3_CLK]		= imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_GPT4_CLK]		= imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_FSPI0_CLK]	= imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_LSIO_FSPI1_CLK]	= imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, clk_cells);
 
 	/* ADMA SS */
-	clks[IMX_ADMA_UART0_CLK]	= imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_UART1_CLK]	= imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_UART2_CLK]	= imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_UART3_CLK]	= imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_SPI0_CLK]		= imx_clk_scu("spi0_clk",  IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_SPI1_CLK]		= imx_clk_scu("spi1_clk",  IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_SPI2_CLK]		= imx_clk_scu("spi2_clk",  IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_SPI3_CLK]		= imx_clk_scu("spi3_clk",  IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_CAN0_CLK]		= imx_clk_scu("can0_clk",  IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_I2C0_CLK]		= imx_clk_scu("i2c0_clk",  IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_I2C1_CLK]		= imx_clk_scu("i2c1_clk",  IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_I2C2_CLK]		= imx_clk_scu("i2c2_clk",  IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_I2C3_CLK]		= imx_clk_scu("i2c3_clk",  IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_FTM0_CLK]		= imx_clk_scu("ftm0_clk",  IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_FTM1_CLK]		= imx_clk_scu("ftm1_clk",  IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_ADC0_CLK]		= imx_clk_scu("adc0_clk",  IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_PWM_CLK]		= imx_clk_scu("pwm_clk",   IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_ADMA_LCD_CLK]		= imx_clk_scu("lcd_clk",   IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+	clks[IMX_ADMA_UART0_CLK]	= imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_UART1_CLK]	= imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_UART2_CLK]	= imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_UART3_CLK]	= imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_SPI0_CLK]		= imx_clk_scu("spi0_clk",  IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_SPI1_CLK]		= imx_clk_scu("spi1_clk",  IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_SPI2_CLK]		= imx_clk_scu("spi2_clk",  IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_SPI3_CLK]		= imx_clk_scu("spi3_clk",  IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_CAN0_CLK]		= imx_clk_scu("can0_clk",  IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_I2C0_CLK]		= imx_clk_scu("i2c0_clk",  IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_I2C1_CLK]		= imx_clk_scu("i2c1_clk",  IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_I2C2_CLK]		= imx_clk_scu("i2c2_clk",  IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_I2C3_CLK]		= imx_clk_scu("i2c3_clk",  IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_FTM0_CLK]		= imx_clk_scu("ftm0_clk",  IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_FTM1_CLK]		= imx_clk_scu("ftm1_clk",  IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_ADC0_CLK]		= imx_clk_scu("adc0_clk",  IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_PWM_CLK]		= imx_clk_scu("pwm_clk",   IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_ADMA_LCD_CLK]		= imx_clk_scu("lcd_clk",   IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, clk_cells);
 
 	/* Connectivity */
-	clks[IMX_CONN_SDHC0_CLK]	= imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_SDHC1_CLK]	= imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_SDHC2_CLK]	= imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_ENET0_ROOT_CLK]	= imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_ENET0_BYPASS_CLK]	= imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
-	clks[IMX_CONN_ENET0_RGMII_CLK]	= imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
-	clks[IMX_CONN_ENET1_ROOT_CLK]	= imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_ENET1_BYPASS_CLK]	= imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
-	clks[IMX_CONN_ENET1_RGMII_CLK]	= imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
-	clks[IMX_CONN_GPMI_BCH_IO_CLK]	= imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
-	clks[IMX_CONN_GPMI_BCH_CLK]	= imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_USB2_ACLK]	= imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
-	clks[IMX_CONN_USB2_BUS_CLK]	= imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
-	clks[IMX_CONN_USB2_LPM_CLK]	= imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
+	clks[IMX_CONN_SDHC0_CLK]	= imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_SDHC1_CLK]	= imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_SDHC2_CLK]	= imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_ENET0_ROOT_CLK]	= imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_ENET0_BYPASS_CLK]	= imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
+	clks[IMX_CONN_ENET0_RGMII_CLK]	= imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0, clk_cells);
+	clks[IMX_CONN_ENET1_ROOT_CLK]	= imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_ENET1_BYPASS_CLK]	= imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
+	clks[IMX_CONN_ENET1_RGMII_CLK]	= imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0, clk_cells);
+	clks[IMX_CONN_GPMI_BCH_IO_CLK]	= imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, clk_cells);
+	clks[IMX_CONN_GPMI_BCH_CLK]	= imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_USB2_ACLK]	= imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CONN_USB2_BUS_CLK]	= imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, clk_cells);
+	clks[IMX_CONN_USB2_LPM_CLK]	= imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, clk_cells);
 
 	/* Display controller SS */
-	clks[IMX_DC0_DISP0_CLK]		= imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
-	clks[IMX_DC0_DISP1_CLK]		= imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
+	clks[IMX_DC0_DISP0_CLK]		= imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, clk_cells);
+	clks[IMX_DC0_DISP1_CLK]		= imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, clk_cells);
+	clks[IMX_DC0_PLL0_CLK]		= imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL, clk_cells);
+	clks[IMX_DC0_PLL1_CLK]		= imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL, clk_cells);
+	clks[IMX_DC0_BYPASS0_CLK]	= imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS, clk_cells);
+	clks[IMX_DC0_BYPASS1_CLK]	= imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS, clk_cells);
 
 	/* MIPI-LVDS SS */
-	clks[IMX_MIPI0_I2C0_CLK]	= imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
-	clks[IMX_MIPI0_I2C1_CLK]	= imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+	clks[IMX_MIPI0_LVDS_PIXEL_CLK]	= imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI0_LVDS_BYPASS_CLK]	= imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
+	clks[IMX_MIPI0_LVDS_PHY_CLK]	= imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3, clk_cells);
+	clks[IMX_MIPI0_I2C0_CLK]	= imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI0_I2C1_CLK]	= imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI0_PWM0_CLK]	= imx_clk_scu("mipi0_pwm0_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_MIPI1_LVDS_PIXEL_CLK]	= imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI1_LVDS_BYPASS_CLK]	= imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
+	clks[IMX_MIPI1_LVDS_PHY_CLK]	= imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3, clk_cells);
+	clks[IMX_MIPI1_I2C0_CLK]	= imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI1_I2C1_CLK]	= imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
+	clks[IMX_MIPI1_PWM0_CLK]	= imx_clk_scu("mipi1_pwm0_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
 
 	/* MIPI CSI SS */
-	clks[IMX_CSI0_CORE_CLK]		= imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_CSI0_ESC_CLK]		= imx_clk_scu("mipi_csi0_esc_clk",  IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
-	clks[IMX_CSI0_I2C0_CLK]		= imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
-	clks[IMX_CSI0_PWM0_CLK]		= imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+	clks[IMX_CSI0_CORE_CLK]		= imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CSI0_ESC_CLK]		= imx_clk_scu("mipi_csi0_esc_clk",  IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, clk_cells);
+	clks[IMX_CSI0_I2C0_CLK]		= imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_CSI0_PWM0_CLK]		= imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
 
 	/* GPU SS */
-	clks[IMX_GPU0_CORE_CLK]		= imx_clk_scu("gpu_core0_clk",	 IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
-	clks[IMX_GPU0_SHADER_CLK]	= imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
+	clks[IMX_GPU0_CORE_CLK]		= imx_clk_scu("gpu_core0_clk",	 IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, clk_cells);
+	clks[IMX_GPU0_SHADER_CLK]	= imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, clk_cells);
 
 	for (i = 0; i < clk_data->num; i++) {
 		if (IS_ERR(clks[i]))
@@ -134,7 +160,19 @@
 				i, PTR_ERR(clks[i]));
 	}
 
-	return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
+	if (clk_cells == 2) {
+		ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
+		if (ret)
+			imx_clk_scu_unregister();
+	} else {
+		/*
+		 * legacy binding code path doesn't unregister here because
+		 * it will be removed later.
+		 */
+		ret = of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
+	}
+
+	return ret;
 }
 
 static const struct of_device_id imx8qxp_match[] = {
@@ -152,3 +190,7 @@
 	.probe = imx8qxp_clk_probe,
 };
 builtin_platform_driver(imx8qxp_clk_driver);
+
+MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8QXP clock driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-lpcg-scu.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-lpcg-scu.c
@@ -4,6 +4,7 @@
  *	Dong Aisheng <aisheng.dong@nxp.com>
  */
 
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -33,6 +34,9 @@
 	void __iomem *reg;
 	u8 bit_idx;
 	bool hw_gate;
+
+	/* for state save&restore */
+	u32 state;
 };
 
 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
@@ -80,9 +84,9 @@
 	.disable = clk_lpcg_scu_disable,
 };
 
-struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
-				unsigned long flags, void __iomem *reg,
-				u8 bit_idx, bool hw_gate)
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+				  const char *parent_name, unsigned long flags,
+				  void __iomem *reg, u8 bit_idx, bool hw_gate)
 {
 	struct clk_lpcg_scu *clk;
 	struct clk_init_data init;
@@ -106,11 +110,53 @@
 	clk->hw.init = &init;
 
 	hw = &clk->hw;
-	ret = clk_hw_register(NULL, hw);
+	ret = clk_hw_register(dev, hw);
 	if (ret) {
 		kfree(clk);
 		hw = ERR_PTR(ret);
 	}
 
+	if (dev)
+		dev_set_drvdata(dev, clk);
+
 	return hw;
 }
+
+void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
+{
+	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+
+	clk_hw_unregister(&clk->hw);
+	kfree(clk);
+}
+
+static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
+{
+	struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+	clk->state = readl_relaxed(clk->reg);
+	dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
+
+	return 0;
+}
+
+static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
+{
+	struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+	/*
+	 * FIXME: Sometimes writes don't work unless the CPU issues
+	 * them twice
+	 */
+
+	writel(clk->state, clk->reg);
+	writel(clk->state, clk->reg);
+	dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
+
+	return 0;
+}
+
+const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
+				      imx_clk_lpcg_scu_resume)
+};
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pfd.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pfd.c
@@ -12,7 +12,7 @@
 
 /**
  * struct clk_pfd - IMX PFD clock
- * @clk_hw:	clock source
+ * @hw:		clock source
  * @reg:	PFD register address
  * @idx:	the index of PFD encoded in the register
  *
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pfdv2.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pfdv2.c
@@ -17,7 +17,7 @@
 
 /**
  * struct clk_pfdv2 - IMX PFD clock
- * @clk_hw:	clock source
+ * @hw:		clock source
  * @reg:	PFD register address
  * @gate_bit:	Gate bit offset
  * @vld_bit:	Valid bit offset
@@ -98,26 +98,45 @@
 	return tmp;
 }
 
-static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate,
-				 unsigned long *prate)
+static int clk_pfdv2_determine_rate(struct clk_hw *hw,
+				    struct clk_rate_request *req)
 {
-	u64 tmp = *prate;
+	unsigned long parent_rates[] = {
+					480000000,
+					528000000,
+					req->best_parent_rate
+				       };
+	unsigned long best_rate = -1UL, rate = req->rate;
+	unsigned long best_parent_rate = req->best_parent_rate;
+	u64 tmp;
 	u8 frac;
+	int i;
 
-	tmp = tmp * 18 + rate / 2;
-	do_div(tmp, rate);
-	frac = tmp;
-
-	if (frac < 12)
-		frac = 12;
-	else if (frac > 35)
-		frac = 35;
+	for (i = 0; i < ARRAY_SIZE(parent_rates); i++) {
+		tmp = parent_rates[i];
+		tmp = tmp * 18 + rate / 2;
+		do_div(tmp, rate);
+		frac = tmp;
+
+		if (frac < 12)
+			frac = 12;
+		else if (frac > 35)
+			frac = 35;
+
+		tmp = parent_rates[i];
+		tmp *= 18;
+		do_div(tmp, frac);
+
+		if (abs(tmp - req->rate) < abs(best_rate - req->rate)) {
+			best_rate = tmp;
+			best_parent_rate = parent_rates[i];
+		}
+	}
 
-	tmp = *prate;
-	tmp *= 18;
-	do_div(tmp, frac);
+	req->best_parent_rate = best_parent_rate;
+	req->rate = best_rate;
 
-	return tmp;
+	return 0;
 }
 
 static int clk_pfdv2_is_enabled(struct clk_hw *hw)
@@ -139,6 +158,12 @@
 	u32 val;
 	u8 frac;
 
+	if (!rate)
+		return -EINVAL;
+
+	/* PFD can NOT change rate without gating */
+	WARN_ON(clk_pfdv2_is_enabled(hw));
+
 	tmp = tmp * 18 + rate / 2;
 	do_div(tmp, rate);
 	frac = tmp;
@@ -161,12 +186,12 @@
 	.enable		= clk_pfdv2_enable,
 	.disable	= clk_pfdv2_disable,
 	.recalc_rate	= clk_pfdv2_recalc_rate,
-	.round_rate	= clk_pfdv2_round_rate,
+	.determine_rate	= clk_pfdv2_determine_rate,
 	.set_rate	= clk_pfdv2_set_rate,
 	.is_enabled     = clk_pfdv2_is_enabled,
 };
 
-struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
 			     void __iomem *reg, u8 idx)
 {
 	struct clk_init_data init;
@@ -189,7 +214,7 @@
 	init.ops = &clk_pfdv2_ops;
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
-	init.flags = CLK_SET_RATE_GATE;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
 
 	pfd->hw.init = &init;
 
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pll14xx.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pll14xx.c
@@ -3,9 +3,10 @@
  * Copyright 2017-2018 NXP.
  */
 
-#include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
@@ -41,6 +42,50 @@
 
 #define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
 
+static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
+	PLL_1416X_RATE(1800000000U, 225, 3, 0),
+	PLL_1416X_RATE(1600000000U, 200, 3, 0),
+	PLL_1416X_RATE(1500000000U, 375, 3, 1),
+	PLL_1416X_RATE(1400000000U, 350, 3, 1),
+	PLL_1416X_RATE(1200000000U, 300, 3, 1),
+	PLL_1416X_RATE(1000000000U, 250, 3, 1),
+	PLL_1416X_RATE(800000000U,  200, 3, 1),
+	PLL_1416X_RATE(750000000U,  250, 2, 2),
+	PLL_1416X_RATE(700000000U,  350, 3, 2),
+	PLL_1416X_RATE(600000000U,  300, 3, 2),
+};
+
+static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
+	PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384),
+	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+	PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
+	PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
+	PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
+	PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
+};
+
+struct imx_pll14xx_clk imx_1443x_pll = {
+	.type = PLL_1443X,
+	.rate_table = imx_pll1443x_tbl,
+	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
+};
+EXPORT_SYMBOL_GPL(imx_1443x_pll);
+
+struct imx_pll14xx_clk imx_1443x_dram_pll = {
+	.type = PLL_1443X,
+	.rate_table = imx_pll1443x_tbl,
+	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
+	.flags = CLK_GET_RATE_NOCACHE,
+};
+EXPORT_SYMBOL_GPL(imx_1443x_dram_pll);
+
+struct imx_pll14xx_clk imx_1416x_pll = {
+	.type = PLL_1416X,
+	.rate_table = imx_pll1416x_tbl,
+	.rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
+};
+EXPORT_SYMBOL_GPL(imx_1416x_pll);
+
 static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
 		struct clk_pll14xx *pll, unsigned long rate)
 {
@@ -112,48 +157,22 @@
 	return fvco;
 }
 
-static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
+static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
 					  u32 pll_div)
 {
 	u32 old_mdiv, old_pdiv;
 
-	old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK;
-	old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK;
+	old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+	old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
 
 	return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
 }
 
-static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate,
-					  u32 pll_div_ctl0, u32 pll_div_ctl1)
-{
-	u32 old_mdiv, old_pdiv, old_kdiv;
-
-	old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
-	old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
-	old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
-
-	return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
-		rate->kdiv != old_kdiv;
-}
-
-static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate,
-					  u32 pll_div_ctl0, u32 pll_div_ctl1)
-{
-	u32 old_mdiv, old_pdiv, old_kdiv;
-
-	old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
-	old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
-	old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
-
-	return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
-		rate->kdiv != old_kdiv;
-}
-
 static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
 {
 	u32 val;
 
-	return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US, 0,
+	return readl_poll_timeout(pll->base, val, val & LOCK_STATUS, 0,
 			LOCK_TIMEOUT_US);
 }
 
@@ -174,7 +193,7 @@
 
 	tmp = readl_relaxed(pll->base + 4);
 
-	if (!clk_pll1416x_mp_change(rate, tmp)) {
+	if (!clk_pll14xx_mp_change(rate, tmp)) {
 		tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
 		tmp |= rate->sdiv << SDIV_SHIFT;
 		writel_relaxed(tmp, pll->base + 4);
@@ -239,13 +258,15 @@
 	}
 
 	tmp = readl_relaxed(pll->base + 4);
-	div_val = readl_relaxed(pll->base + 8);
 
-	if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) {
+	if (!clk_pll14xx_mp_change(rate, tmp)) {
 		tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
 		tmp |= rate->sdiv << SDIV_SHIFT;
 		writel_relaxed(tmp, pll->base + 4);
 
+		tmp = rate->kdiv << KDIV_SHIFT;
+		writel_relaxed(tmp, pll->base + 8);
+
 		return 0;
 	}
 
@@ -361,13 +382,14 @@
 	.set_rate	= clk_pll1443x_set_rate,
 };
 
-struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
-			    void __iomem *base,
-			    const struct imx_pll14xx_clk *pll_clk)
+struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
+				const char *parent_name, void __iomem *base,
+				const struct imx_pll14xx_clk *pll_clk)
 {
 	struct clk_pll14xx *pll;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 	u32 val;
 
 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
@@ -392,7 +414,9 @@
 	default:
 		pr_err("%s: Unknown pll type for pll clk %s\n",
 		       __func__, name);
-	};
+		kfree(pll);
+		return ERR_PTR(-EINVAL);
+	}
 
 	pll->base = base;
 	pll->hw.init = &init;
@@ -404,12 +428,16 @@
 	val &= ~BYPASS_MASK;
 	writel_relaxed(val, pll->base + GNRL_CTL);
 
-	clk = clk_register(NULL, &pll->hw);
-	if (IS_ERR(clk)) {
-		pr_err("%s: failed to register pll %s %lu\n",
-			__func__, name, PTR_ERR(clk));
+	hw = &pll->hw;
+
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		pr_err("%s: failed to register pll %s %d\n",
+			__func__, name, ret);
 		kfree(pll);
+		return ERR_PTR(ret);
 	}
 
-	return clk;
+	return hw;
 }
+EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pllv1.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pllv1.c
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -111,12 +112,13 @@
 	.recalc_rate = clk_pllv1_recalc_rate,
 };
 
-struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
 		const char *parent, void __iomem *base)
 {
 	struct clk_pllv1 *pll;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 
 	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
 	if (!pll)
@@ -132,10 +134,13 @@
 	init.num_parents = 1;
 
 	pll->hw.init = &init;
+	hw = &pll->hw;
 
-	clk = clk_register(NULL, &pll->hw);
-	if (IS_ERR(clk))
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
 		kfree(pll);
+		return ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
 }
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pllv2.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pllv2.c
@@ -239,12 +239,13 @@
 	.set_rate = clk_pllv2_set_rate,
 };
 
-struct clk *imx_clk_pllv2(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent,
 		void __iomem *base)
 {
 	struct clk_pllv2 *pll;
-	struct clk *clk;
+	struct clk_hw *hw;
 	struct clk_init_data init;
+	int ret;
 
 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 	if (!pll)
@@ -259,10 +260,13 @@
 	init.num_parents = 1;
 
 	pll->hw.init = &init;
+	hw = &pll->hw;
 
-	clk = clk_register(NULL, &pll->hw);
-	if (IS_ERR(clk))
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
 		kfree(pll);
+		return ERR_PTR(ret);
+	}
 
-	return clk;
+	return hw;
 }
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pllv3.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pllv3.c
@@ -7,6 +7,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/err.h>
@@ -25,14 +26,19 @@
 #define IMX7_ENET_PLL_POWER	(0x1 << 5)
 #define IMX7_DDR_PLL_POWER	(0x1 << 20)
 
+#define PLL_LOCK_TIMEOUT	10000
+
 /**
  * struct clk_pllv3 - IMX PLL clock version 3
- * @clk_hw:	 clock source
+ * @hw:		clock source
  * @base:	 base address of PLL registers
  * @power_bit:	 pll power bit mask
  * @powerup_set: set power_bit to power up the PLL
  * @div_mask:	 mask of divider bits
  * @div_shift:	 shift of divider bits
+ * @ref_clock:	reference clock rate
+ * @num_offset:	num register offset
+ * @denom_offset: denom register offset
  *
  * IMX PLL clock version 3, found on i.MX6 series.  Divider for pllv3
  * is actually a multiplier, and always sits at bit 0.
@@ -53,23 +59,14 @@
 
 static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(10);
 	u32 val = readl_relaxed(pll->base) & pll->power_bit;
 
 	/* No need to wait for lock when pll is not powered up */
 	if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
 		return 0;
 
-	/* Wait for PLL to lock */
-	do {
-		if (readl_relaxed(pll->base) & BM_PLL_LOCK)
-			break;
-		if (time_after(jiffies, timeout))
-			break;
-		usleep_range(50, 500);
-	} while (1);
-
-	return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
+	return readl_relaxed_poll_timeout(pll->base, val, val & BM_PLL_LOCK,
+					  500, PLL_LOCK_TIMEOUT);
 }
 
 static int clk_pllv3_prepare(struct clk_hw *hw)
@@ -439,7 +436,7 @@
 		break;
 	case IMX_PLLV3_USB_VF610:
 		pll->div_shift = 1;
-		/* fall through */
+		fallthrough;
 	case IMX_PLLV3_USB:
 		ops = &clk_pllv3_ops;
 		pll->powerup_set = true;
@@ -447,7 +444,7 @@
 	case IMX_PLLV3_AV_IMX7:
 		pll->num_offset = PLL_IMX7_NUM_OFFSET;
 		pll->denom_offset = PLL_IMX7_DENOM_OFFSET;
-		/* fall through */
+		fallthrough;
 	case IMX_PLLV3_AV:
 		ops = &clk_pllv3_av_ops;
 		break;
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-pllv4.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-pllv4.c
@@ -7,6 +7,7 @@
  *
  */
 
+#include <linux/bits.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -54,7 +55,7 @@
 				  csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
 }
 
-static int clk_pllv4_is_enabled(struct clk_hw *hw)
+static int clk_pllv4_is_prepared(struct clk_hw *hw)
 {
 	struct clk_pllv4 *pll = to_clk_pllv4(hw);
 
@@ -175,7 +176,7 @@
 	return 0;
 }
 
-static int clk_pllv4_enable(struct clk_hw *hw)
+static int clk_pllv4_prepare(struct clk_hw *hw)
 {
 	u32 val;
 	struct clk_pllv4 *pll = to_clk_pllv4(hw);
@@ -187,7 +188,7 @@
 	return clk_pllv4_wait_lock(pll);
 }
 
-static void clk_pllv4_disable(struct clk_hw *hw)
+static void clk_pllv4_unprepare(struct clk_hw *hw)
 {
 	u32 val;
 	struct clk_pllv4 *pll = to_clk_pllv4(hw);
@@ -201,12 +202,12 @@
 	.recalc_rate	= clk_pllv4_recalc_rate,
 	.round_rate	= clk_pllv4_round_rate,
 	.set_rate	= clk_pllv4_set_rate,
-	.enable		= clk_pllv4_enable,
-	.disable	= clk_pllv4_disable,
-	.is_enabled	= clk_pllv4_is_enabled,
+	.prepare	= clk_pllv4_prepare,
+	.unprepare	= clk_pllv4_unprepare,
+	.is_prepared	= clk_pllv4_is_prepared,
 };
 
-struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
 			  void __iomem *base)
 {
 	struct clk_pllv4 *pll;
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-scu.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-scu.c
@@ -8,6 +8,10 @@
 #include <linux/arm-smccc.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "clk-scu.h"
@@ -16,6 +20,21 @@
 #define IMX_SIP_SET_CPUFREQ		0x00
 
 static struct imx_sc_ipc *ccm_ipc_handle;
+static struct device_node *pd_np;
+static struct platform_driver imx_clk_scu_driver;
+
+struct imx_scu_clk_node {
+	const char *name;
+	u32 rsrc;
+	u8 clk_type;
+	const char * const *parents;
+	int num_parents;
+
+	struct clk_hw *hw;
+	struct list_head node;
+};
+
+struct list_head imx_scu_clks[IMX_SC_R_LAST];
 
 /*
  * struct clk_scu - Description of one SCU clock
@@ -27,6 +46,10 @@
 	struct clk_hw hw;
 	u16 rsrc_id;
 	u8 clk_type;
+
+	/* for state save&restore */
+	bool is_enabled;
+	u32 rate;
 };
 
 /*
@@ -43,12 +66,12 @@
 	__le32 rate;
 	__le16 resource;
 	u8 clk;
-} __packed;
+} __packed __aligned(4);
 
 struct req_get_clock_rate {
 	__le16 resource;
 	u8 clk;
-} __packed;
+} __packed __aligned(4);
 
 struct resp_get_clock_rate {
 	__le32 rate;
@@ -84,7 +107,7 @@
 		struct req_get_clock_parent {
 			__le16 resource;
 			u8 clk;
-		} __packed req;
+		} __packed __aligned(4) req;
 		struct resp_get_clock_parent {
 			u8 parent;
 		} resp;
@@ -121,16 +144,35 @@
 	u8 clk;
 	u8 enable;
 	u8 autog;
-} __packed;
+} __packed __aligned(4);
 
 static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
 {
 	return container_of(hw, struct clk_scu, hw);
 }
 
-int imx_clk_scu_init(void)
+int imx_clk_scu_init(struct device_node *np)
 {
-	return imx_scu_get_handle(&ccm_ipc_handle);
+	u32 clk_cells;
+	int ret, i;
+
+	ret = imx_scu_get_handle(&ccm_ipc_handle);
+	if (ret)
+		return ret;
+
+	of_property_read_u32(np, "#clock-cells", &clk_cells);
+
+	if (clk_cells == 2) {
+		for (i = 0; i < IMX_SC_R_LAST; i++)
+			INIT_LIST_HEAD(&imx_scu_clks[i]);
+
+		/* pd_np will be used to attach power domains later */
+		pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
+		if (!pd_np)
+			return -EINVAL;
+	}
+
+	return platform_driver_register(&imx_clk_scu_driver);
 }
 
 /*
@@ -344,8 +386,9 @@
 	.unprepare = clk_scu_unprepare,
 };
 
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
-			     int num_parents, u32 rsrc_id, u8 clk_type)
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+			     const char * const *parents, int num_parents,
+			     u32 rsrc_id, u8 clk_type)
 {
 	struct clk_init_data init;
 	struct clk_scu *clk;
@@ -379,11 +422,185 @@
 	clk->hw.init = &init;
 
 	hw = &clk->hw;
-	ret = clk_hw_register(NULL, hw);
+	ret = clk_hw_register(dev, hw);
 	if (ret) {
 		kfree(clk);
 		hw = ERR_PTR(ret);
 	}
 
+	if (dev)
+		dev_set_drvdata(dev, clk);
+
 	return hw;
 }
+
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+				      void *data)
+{
+	unsigned int rsrc = clkspec->args[0];
+	unsigned int idx = clkspec->args[1];
+	struct list_head *scu_clks = data;
+	struct imx_scu_clk_node *clk;
+
+	list_for_each_entry(clk, &scu_clks[rsrc], node) {
+		if (clk->clk_type == idx)
+			return clk->hw;
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static int imx_clk_scu_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_scu_clk_node *clk = dev_get_platdata(dev);
+	struct clk_hw *hw;
+	int ret;
+
+	pm_runtime_set_suspended(dev);
+	pm_runtime_set_autosuspend_delay(dev, 50);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_enable(dev);
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret) {
+		pm_runtime_disable(dev);
+		return ret;
+	}
+
+	hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents,
+			   clk->rsrc, clk->clk_type);
+	if (IS_ERR(hw)) {
+		pm_runtime_disable(dev);
+		return PTR_ERR(hw);
+	}
+
+	clk->hw = hw;
+	list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
+
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
+	dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
+		clk->clk_type);
+
+	return 0;
+}
+
+static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
+{
+	struct clk_scu *clk = dev_get_drvdata(dev);
+
+	clk->rate = clk_hw_get_rate(&clk->hw);
+	clk->is_enabled = clk_hw_is_enabled(&clk->hw);
+
+	if (clk->rate)
+		dev_dbg(dev, "save rate %d\n", clk->rate);
+
+	if (clk->is_enabled)
+		dev_dbg(dev, "save enabled state\n");
+
+	return 0;
+}
+
+static int __maybe_unused imx_clk_scu_resume(struct device *dev)
+{
+	struct clk_scu *clk = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (clk->rate) {
+		ret = clk_scu_set_rate(&clk->hw, clk->rate, 0);
+		dev_dbg(dev, "restore rate %d %s\n", clk->rate,
+			!ret ? "success" : "failed");
+	}
+
+	if (clk->is_enabled) {
+		ret = clk_scu_prepare(&clk->hw);
+		dev_dbg(dev, "restore enabled state %s\n",
+			!ret ? "success" : "failed");
+	}
+
+	return ret;
+}
+
+static const struct dev_pm_ops imx_clk_scu_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend,
+				      imx_clk_scu_resume)
+};
+
+static struct platform_driver imx_clk_scu_driver = {
+	.driver = {
+		.name = "imx-scu-clk",
+		.suppress_bind_attrs = true,
+		.pm = &imx_clk_scu_pm_ops,
+	},
+	.probe = imx_clk_scu_probe,
+};
+
+static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
+{
+	struct of_phandle_args genpdspec = {
+		.np = pd_np,
+		.args_count = 1,
+		.args[0] = rsrc_id,
+	};
+
+	if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 ||
+	    rsrc_id == IMX_SC_R_A72)
+		return 0;
+
+	return of_genpd_add_device(&genpdspec, dev);
+}
+
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+				     const char * const *parents,
+				     int num_parents, u32 rsrc_id, u8 clk_type)
+{
+	struct imx_scu_clk_node clk = {
+		.name = name,
+		.rsrc = rsrc_id,
+		.clk_type = clk_type,
+		.parents = parents,
+		.num_parents = num_parents,
+	};
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
+	if (!pdev) {
+		pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
+		       name, rsrc_id, clk_type);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = platform_device_add_data(pdev, &clk, sizeof(clk));
+	if (ret) {
+		platform_device_put(pdev);
+		return ERR_PTR(ret);
+	}
+
+	pdev->driver_override = "imx-scu-clk";
+
+	ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id);
+	if (ret)
+		pr_warn("%s: failed to attached the power domain %d\n",
+			name, ret);
+
+	platform_device_add(pdev);
+
+	/* For API backwards compatiblilty, simply return NULL for success */
+	return NULL;
+}
+
+void imx_clk_scu_unregister(void)
+{
+	struct imx_scu_clk_node *clk;
+	int i;
+
+	for (i = 0; i < IMX_SC_R_LAST; i++) {
+		list_for_each_entry(clk, &imx_scu_clks[i], node) {
+			clk_hw_unregister(clk->hw);
+			kfree(clk);
+		}
+	}
+}
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-scu.h
+++ linux-ein-5.4.0/drivers/clk/imx/clk-scu.h
@@ -8,25 +8,61 @@
 #define __IMX_CLK_SCU_H
 
 #include <linux/firmware/imx/sci.h>
+#include <linux/of.h>
 
-int imx_clk_scu_init(void);
+extern struct list_head imx_scu_clks[];
+extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
 
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
-			     int num_parents, u32 rsrc_id, u8 clk_type);
+int imx_clk_scu_init(struct device_node *np);
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+				      void *data);
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+				     const char * const *parents,
+				     int num_parents, u32 rsrc_id, u8 clk_type);
+
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+			     const char * const *parents, int num_parents,
+			     u32 rsrc_id, u8 clk_type);
+
+void imx_clk_scu_unregister(void);
+
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+				  const char *parent_name, unsigned long flags,
+				  void __iomem *reg, u8 bit_idx, bool hw_gate);
+void imx_clk_lpcg_scu_unregister(struct clk_hw *hw);
 
 static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
-					 u8 clk_type)
+					 u8 clk_type, u8 clk_cells)
 {
-	return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
+	if (clk_cells == 2)
+		return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
+	else
+		return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type);
 }
 
 static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
-					  int num_parents, u32 rsrc_id, u8 clk_type)
+					  int num_parents, u32 rsrc_id, u8 clk_type,
+					  u8 clk_cells)
 {
-	return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
+	if (clk_cells == 2)
+		return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
+	else
+		return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type);
 }
 
-struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
-				unsigned long flags, void __iomem *reg,
-				u8 bit_idx, bool hw_gate);
+static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name,
+						  const char *parent_name, unsigned long flags,
+						  void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+	return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg,
+				  bit_idx, hw_gate);
+}
+
+static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
+					      unsigned long flags, void __iomem *reg,
+					      u8 bit_idx, bool hw_gate)
+{
+	return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg,
+				  bit_idx, hw_gate);
+}
 #endif
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-sscg-pll.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-sscg-pll.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 NXP.
+ *
+ * This driver supports the SCCG plls found in the imx8m SOCs
+ *
+ * Documentation for this SCCG pll can be found at:
+ *   https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/slab.h>
+#include <linux/bitfield.h>
+
+#include "clk.h"
+
+/* PLL CFGs */
+#define PLL_CFG0		0x0
+#define PLL_CFG1		0x4
+#define PLL_CFG2		0x8
+
+#define PLL_DIVF1_MASK		GENMASK(18, 13)
+#define PLL_DIVF2_MASK		GENMASK(12, 7)
+#define PLL_DIVR1_MASK		GENMASK(27, 25)
+#define PLL_DIVR2_MASK		GENMASK(24, 19)
+#define PLL_DIVQ_MASK           GENMASK(6, 1)
+#define PLL_REF_MASK		GENMASK(2, 0)
+
+#define PLL_LOCK_MASK		BIT(31)
+#define PLL_PD_MASK		BIT(7)
+
+/* These are the specification limits for the SSCG PLL */
+#define PLL_REF_MIN_FREQ		25000000UL
+#define PLL_REF_MAX_FREQ		235000000UL
+
+#define PLL_STAGE1_MIN_FREQ		1600000000UL
+#define PLL_STAGE1_MAX_FREQ		2400000000UL
+
+#define PLL_STAGE1_REF_MIN_FREQ		25000000UL
+#define PLL_STAGE1_REF_MAX_FREQ		54000000UL
+
+#define PLL_STAGE2_MIN_FREQ		1200000000UL
+#define PLL_STAGE2_MAX_FREQ		2400000000UL
+
+#define PLL_STAGE2_REF_MIN_FREQ		54000000UL
+#define PLL_STAGE2_REF_MAX_FREQ		75000000UL
+
+#define PLL_OUT_MIN_FREQ		20000000UL
+#define PLL_OUT_MAX_FREQ		1200000000UL
+
+#define PLL_DIVR1_MAX			7
+#define PLL_DIVR2_MAX			63
+#define PLL_DIVF1_MAX			63
+#define PLL_DIVF2_MAX			63
+#define PLL_DIVQ_MAX			63
+
+#define PLL_BYPASS_NONE			0x0
+#define PLL_BYPASS1			0x2
+#define PLL_BYPASS2			0x1
+
+#define SSCG_PLL_BYPASS1_MASK           BIT(5)
+#define SSCG_PLL_BYPASS2_MASK           BIT(4)
+#define SSCG_PLL_BYPASS_MASK		GENMASK(5, 4)
+
+#define PLL_SCCG_LOCK_TIMEOUT		70
+
+struct clk_sscg_pll_setup {
+	int divr1, divf1;
+	int divr2, divf2;
+	int divq;
+	int bypass;
+	uint64_t vco1;
+	uint64_t vco2;
+	uint64_t fout;
+	uint64_t ref;
+	uint64_t ref_div1;
+	uint64_t ref_div2;
+	uint64_t fout_request;
+	int fout_error;
+};
+
+struct clk_sscg_pll {
+	struct clk_hw	hw;
+	const struct clk_ops  ops;
+	void __iomem *base;
+	struct clk_sscg_pll_setup setup;
+	u8 parent;
+	u8 bypass1;
+	u8 bypass2;
+};
+
+#define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw)
+
+static int clk_sscg_pll_wait_lock(struct clk_sscg_pll *pll)
+{
+	u32 val;
+
+	val = readl_relaxed(pll->base + PLL_CFG0);
+
+	/* don't wait for lock if all plls are bypassed */
+	if (!(val & SSCG_PLL_BYPASS2_MASK))
+		return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,
+						0, PLL_SCCG_LOCK_TIMEOUT);
+
+	return 0;
+}
+
+static int clk_sscg_pll2_check_match(struct clk_sscg_pll_setup *setup,
+					struct clk_sscg_pll_setup *temp_setup)
+{
+	int new_diff = temp_setup->fout - temp_setup->fout_request;
+	int diff = temp_setup->fout_error;
+
+	if (abs(diff) > abs(new_diff)) {
+		temp_setup->fout_error = new_diff;
+		memcpy(setup, temp_setup, sizeof(struct clk_sscg_pll_setup));
+
+		if (temp_setup->fout_request == temp_setup->fout)
+			return 0;
+	}
+	return -1;
+}
+
+static int clk_sscg_divq_lookup(struct clk_sscg_pll_setup *setup,
+				struct clk_sscg_pll_setup *temp_setup)
+{
+	int ret = -EINVAL;
+
+	for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;
+	     temp_setup->divq++) {
+		temp_setup->vco2 = temp_setup->vco1;
+		do_div(temp_setup->vco2, temp_setup->divr2 + 1);
+		temp_setup->vco2 *= 2;
+		temp_setup->vco2 *= temp_setup->divf2 + 1;
+		if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&
+				temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {
+			temp_setup->fout = temp_setup->vco2;
+			do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));
+
+			ret = clk_sscg_pll2_check_match(setup, temp_setup);
+			if (!ret) {
+				temp_setup->bypass = PLL_BYPASS1;
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int clk_sscg_divf2_lookup(struct clk_sscg_pll_setup *setup,
+					struct clk_sscg_pll_setup *temp_setup)
+{
+	int ret = -EINVAL;
+
+	for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;
+	     temp_setup->divf2++) {
+		ret = clk_sscg_divq_lookup(setup, temp_setup);
+		if (!ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int clk_sscg_divr2_lookup(struct clk_sscg_pll_setup *setup,
+				struct clk_sscg_pll_setup *temp_setup)
+{
+	int ret = -EINVAL;
+
+	for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;
+	     temp_setup->divr2++) {
+		temp_setup->ref_div2 = temp_setup->vco1;
+		do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);
+		if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&
+		    temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {
+			ret = clk_sscg_divf2_lookup(setup, temp_setup);
+			if (!ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,
+					struct clk_sscg_pll_setup *temp_setup,
+					uint64_t ref)
+{
+	int ret;
+
+	if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
+		return -EINVAL;
+
+	temp_setup->vco1 = ref;
+
+	ret = clk_sscg_divr2_lookup(setup, temp_setup);
+	return ret;
+}
+
+static int clk_sscg_divf1_lookup(struct clk_sscg_pll_setup *setup,
+				struct clk_sscg_pll_setup *temp_setup)
+{
+	int ret = -EINVAL;
+
+	for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;
+	     temp_setup->divf1++) {
+		uint64_t vco1 = temp_setup->ref;
+
+		do_div(vco1, temp_setup->divr1 + 1);
+		vco1 *= 2;
+		vco1 *= temp_setup->divf1 + 1;
+
+		ret = clk_sscg_pll2_find_setup(setup, temp_setup, vco1);
+		if (!ret) {
+			temp_setup->bypass = PLL_BYPASS_NONE;
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int clk_sscg_divr1_lookup(struct clk_sscg_pll_setup *setup,
+				struct clk_sscg_pll_setup *temp_setup)
+{
+	int ret = -EINVAL;
+
+	for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;
+	     temp_setup->divr1++) {
+		temp_setup->ref_div1 = temp_setup->ref;
+		do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);
+		if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&
+		    temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {
+			ret = clk_sscg_divf1_lookup(setup, temp_setup);
+			if (!ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,
+					struct clk_sscg_pll_setup *temp_setup,
+					uint64_t ref)
+{
+	int ret;
+
+	if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
+		return -EINVAL;
+
+	temp_setup->ref = ref;
+
+	ret = clk_sscg_divr1_lookup(setup, temp_setup);
+
+	return ret;
+}
+
+static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
+					uint64_t prate,
+					uint64_t rate, int try_bypass)
+{
+	struct clk_sscg_pll_setup temp_setup;
+	int ret = -EINVAL;
+
+	memset(&temp_setup, 0, sizeof(struct clk_sscg_pll_setup));
+	memset(setup, 0, sizeof(struct clk_sscg_pll_setup));
+
+	temp_setup.fout_error = PLL_OUT_MAX_FREQ;
+	temp_setup.fout_request = rate;
+
+	switch (try_bypass) {
+	case PLL_BYPASS2:
+		if (prate == rate) {
+			setup->bypass = PLL_BYPASS2;
+			setup->fout = rate;
+			ret = 0;
+		}
+		break;
+	case PLL_BYPASS1:
+		ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate);
+		break;
+	case PLL_BYPASS_NONE:
+		ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate);
+		break;
+	}
+
+	return ret;
+}
+
+static int clk_sscg_pll_is_prepared(struct clk_hw *hw)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+
+	u32 val = readl_relaxed(pll->base + PLL_CFG0);
+
+	return (val & PLL_PD_MASK) ? 0 : 1;
+}
+
+static int clk_sscg_pll_prepare(struct clk_hw *hw)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->base + PLL_CFG0);
+	val &= ~PLL_PD_MASK;
+	writel_relaxed(val, pll->base + PLL_CFG0);
+
+	return clk_sscg_pll_wait_lock(pll);
+}
+
+static void clk_sscg_pll_unprepare(struct clk_hw *hw)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->base + PLL_CFG0);
+	val |= PLL_PD_MASK;
+	writel_relaxed(val, pll->base + PLL_CFG0);
+}
+
+static unsigned long clk_sscg_pll_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	u32 val, divr1, divf1, divr2, divf2, divq;
+	u64 temp64;
+
+	val = readl_relaxed(pll->base + PLL_CFG2);
+	divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
+	divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
+	divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
+	divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
+	divq = FIELD_GET(PLL_DIVQ_MASK, val);
+
+	temp64 = parent_rate;
+
+	val = readl(pll->base + PLL_CFG0);
+	if (val & SSCG_PLL_BYPASS2_MASK) {
+		temp64 = parent_rate;
+	} else if (val & SSCG_PLL_BYPASS1_MASK) {
+		temp64 *= divf2;
+		do_div(temp64, (divr2 + 1) * (divq + 1));
+	} else {
+		temp64 *= 2;
+		temp64 *= (divf1 + 1) * (divf2 + 1);
+		do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));
+	}
+
+	return temp64;
+}
+
+static int clk_sscg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	struct clk_sscg_pll_setup *setup = &pll->setup;
+	u32 val;
+
+	/* set bypass here too since the parent might be the same */
+	val = readl(pll->base + PLL_CFG0);
+	val &= ~SSCG_PLL_BYPASS_MASK;
+	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
+	writel(val, pll->base + PLL_CFG0);
+
+	val = readl_relaxed(pll->base + PLL_CFG2);
+	val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
+	val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);
+	val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);
+	val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);
+	val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);
+	val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);
+	val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);
+	writel_relaxed(val, pll->base + PLL_CFG2);
+
+	return clk_sscg_pll_wait_lock(pll);
+}
+
+static u8 clk_sscg_pll_get_parent(struct clk_hw *hw)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	u32 val;
+	u8 ret = pll->parent;
+
+	val = readl(pll->base + PLL_CFG0);
+	if (val & SSCG_PLL_BYPASS2_MASK)
+		ret = pll->bypass2;
+	else if (val & SSCG_PLL_BYPASS1_MASK)
+		ret = pll->bypass1;
+	return ret;
+}
+
+static int clk_sscg_pll_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	u32 val;
+
+	val = readl(pll->base + PLL_CFG0);
+	val &= ~SSCG_PLL_BYPASS_MASK;
+	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
+	writel(val, pll->base + PLL_CFG0);
+
+	return clk_sscg_pll_wait_lock(pll);
+}
+
+static int __clk_sscg_pll_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req,
+					uint64_t min,
+					uint64_t max,
+					uint64_t rate,
+					int bypass)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	struct clk_sscg_pll_setup *setup = &pll->setup;
+	struct clk_hw *parent_hw = NULL;
+	int bypass_parent_index;
+	int ret;
+
+	req->max_rate = max;
+	req->min_rate = min;
+
+	switch (bypass) {
+	case PLL_BYPASS2:
+		bypass_parent_index = pll->bypass2;
+		break;
+	case PLL_BYPASS1:
+		bypass_parent_index = pll->bypass1;
+		break;
+	default:
+		bypass_parent_index = pll->parent;
+		break;
+	}
+
+	parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);
+	ret = __clk_determine_rate(parent_hw, req);
+	if (!ret) {
+		ret = clk_sscg_pll_find_setup(setup, req->rate,
+						rate, bypass);
+	}
+
+	req->best_parent_hw = parent_hw;
+	req->best_parent_rate = req->rate;
+	req->rate = setup->fout;
+
+	return ret;
+}
+
+static int clk_sscg_pll_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
+{
+	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
+	struct clk_sscg_pll_setup *setup = &pll->setup;
+	uint64_t rate = req->rate;
+	uint64_t min = req->min_rate;
+	uint64_t max = req->max_rate;
+	int ret;
+
+	if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
+		return -EINVAL;
+
+	ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate,
+						rate, PLL_BYPASS2);
+	if (!ret)
+		return ret;
+
+	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,
+						PLL_STAGE1_REF_MAX_FREQ, rate,
+						PLL_BYPASS1);
+	if (!ret)
+		return ret;
+
+	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,
+						PLL_REF_MAX_FREQ, rate,
+						PLL_BYPASS_NONE);
+	if (!ret)
+		return ret;
+
+	if (setup->fout >= min && setup->fout <= max)
+		ret = 0;
+
+	return ret;
+}
+
+static const struct clk_ops clk_sscg_pll_ops = {
+	.prepare	= clk_sscg_pll_prepare,
+	.unprepare	= clk_sscg_pll_unprepare,
+	.is_prepared	= clk_sscg_pll_is_prepared,
+	.recalc_rate	= clk_sscg_pll_recalc_rate,
+	.set_rate	= clk_sscg_pll_set_rate,
+	.set_parent	= clk_sscg_pll_set_parent,
+	.get_parent	= clk_sscg_pll_get_parent,
+	.determine_rate	= clk_sscg_pll_determine_rate,
+};
+
+struct clk_hw *imx_clk_hw_sscg_pll(const char *name,
+				const char * const *parent_names,
+				u8 num_parents,
+				u8 parent, u8 bypass1, u8 bypass2,
+				void __iomem *base,
+				unsigned long flags)
+{
+	struct clk_sscg_pll *pll;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->parent = parent;
+	pll->bypass1 = bypass1;
+	pll->bypass2 = bypass2;
+
+	pll->base = base;
+	init.name = name;
+	init.ops = &clk_sscg_pll_ops;
+
+	init.flags = flags;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	pll->base = base;
+	pll->hw.init = &init;
+
+	hw = &pll->hw;
+
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	return hw;
+}
+EXPORT_SYMBOL_GPL(imx_clk_hw_sscg_pll);
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk-vf610.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk-vf610.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/of_address.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/syscore_ops.h>
 #include <dt-bindings/clock/vf610-clock.h>
@@ -328,6 +329,7 @@
 	clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(12));
 	clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(13));
 
+	clk[VF610_CLK_CRC] = imx_clk_gate2("crc", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(3));
 	clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(14));
 
 	clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel", CCM_CSCMR1, 16, 2, esdhc_sels, 4);
@@ -438,6 +440,7 @@
 	clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));
 	clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus", CCM_CCSR, 24);
 	clk[VF610_CLK_OCOTP] = imx_clk_gate("ocotp", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(5));
+	clk[VF610_CLK_CAAM] = imx_clk_gate2("caam", "ipg_bus", CCM_CCGR11, CCM_CCGRx_CGn(0));
 
 	imx_check_clocks(clk, ARRAY_SIZE(clk));
 
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk.c
+++ linux-ein-5.4.0/drivers/clk/imx/clk.c
@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -13,6 +15,7 @@
 #define CCDR_MMDC_CH1_MASK		BIT(16)
 
 DEFINE_SPINLOCK(imx_ccm_lock);
+EXPORT_SYMBOL_GPL(imx_ccm_lock);
 
 void imx_unregister_clocks(struct clk *clks[], unsigned int count)
 {
@@ -22,7 +25,16 @@
 		clk_unregister(clks[i]);
 }
 
-void __init imx_mmdc_mask_handshake(void __iomem *ccm_base,
+void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++)
+		clk_hw_unregister(hws[i]);
+}
+EXPORT_SYMBOL_GPL(imx_unregister_hw_clocks);
+
+void imx_mmdc_mask_handshake(void __iomem *ccm_base,
 				    unsigned int chn)
 {
 	unsigned int reg;
@@ -51,8 +63,9 @@
 			pr_err("i.MX clk %u: register failed with %ld\n",
 			       i, PTR_ERR(clks[i]));
 }
+EXPORT_SYMBOL_GPL(imx_check_clk_hws);
 
-static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name)
+static struct clk *imx_obtain_fixed_clock_from_dt(const char *name)
 {
 	struct of_phandle_args phandle;
 	struct clk *clk = ERR_PTR(-ENODEV);
@@ -72,7 +85,7 @@
 	return clk;
 }
 
-struct clk * __init imx_obtain_fixed_clock(
+struct clk *imx_obtain_fixed_clock(
 			const char *name, unsigned long rate)
 {
 	struct clk *clk;
@@ -83,7 +96,7 @@
 	return clk;
 }
 
-struct clk_hw * __init imx_obtain_fixed_clock_hw(
+struct clk_hw *imx_obtain_fixed_clock_hw(
 			const char *name, unsigned long rate)
 {
 	struct clk *clk;
@@ -94,8 +107,8 @@
 	return __clk_get_hw(clk);
 }
 
-struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
-					       const char *name)
+struct clk_hw * imx_obtain_fixed_clk_hw(struct device_node *np,
+					const char *name)
 {
 	struct clk *clk;
 
@@ -105,6 +118,7 @@
 
 	return __clk_get_hw(clk);
 }
+EXPORT_SYMBOL_GPL(imx_obtain_fixed_clk_hw);
 
 /*
  * This fixups the register CCM_CSCMR1 write value.
@@ -132,6 +146,7 @@
 	return;
 }
 
+#ifndef MODULE
 static int imx_keep_uart_clocks;
 static struct clk ** const *imx_uart_clocks;
 
@@ -159,6 +174,9 @@
 
 static int __init imx_clk_disable_uart(void)
 {
+	if (imx_src_is_m4_enabled())
+		return 0;
+
 	if (imx_keep_uart_clocks && imx_uart_clocks) {
 		int i;
 
@@ -169,3 +187,6 @@
 	return 0;
 }
 late_initcall_sync(imx_clk_disable_uart);
+#endif
+
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/clk/imx/clk.h
+++ linux-ein-5.4.0/drivers/clk/imx/clk.h
@@ -2,16 +2,25 @@
 #ifndef __MACH_IMX_CLK_H
 #define __MACH_IMX_CLK_H
 
+#include <linux/bits.h>
 #include <linux/spinlock.h>
 #include <linux/clk-provider.h>
+#include <soc/imx/src.h>
 
 extern spinlock_t imx_ccm_lock;
 
 void imx_check_clocks(struct clk *clks[], unsigned int count);
 void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
+#ifndef MODULE
 void imx_register_uart_clocks(struct clk ** const clks[]);
+#else
+static inline void imx_register_uart_clocks(struct clk ** const clks[])
+{
+}
+#endif
 void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn);
 void imx_unregister_clocks(struct clk *clks[], unsigned int count);
+void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count);
 
 extern void imx_cscmr1_fixup(u32 *val);
 
@@ -24,7 +33,7 @@
 	IMX_PLLV1_IMX35,
 };
 
-enum imx_sccg_pll_type {
+enum imx_sscg_pll_type {
 	SCCG_PLL1,
 	SCCG_PLL2,
 };
@@ -50,63 +59,104 @@
 	int flags;
 };
 
+extern struct imx_pll14xx_clk imx_1416x_pll;
+extern struct imx_pll14xx_clk imx_1443x_pll;
+extern struct imx_pll14xx_clk imx_1443x_dram_pll;
+
 #define imx_clk_cpu(name, parent_name, div, mux, pll, step) \
-	imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)->clk
+	to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step))
 
 #define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
-				cgr_val, clk_gate_flags, lock, share_count) \
-	clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
-				cgr_val, clk_gate_flags, lock, share_count)->clk
+				cgr_val, cgr_mask, clk_gate_flags, lock, share_count) \
+	to_clk(clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+				cgr_val, cgr_mask, clk_gate_flags, lock, share_count))
 
 #define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
-	imx_clk_hw_pllv3(type, name, parent_name, base, div_mask)->clk
+	to_clk(imx_clk_hw_pllv3(type, name, parent_name, base, div_mask))
 
 #define imx_clk_pfd(name, parent_name, reg, idx) \
-	imx_clk_hw_pfd(name, parent_name, reg, idx)->clk
+	to_clk(imx_clk_hw_pfd(name, parent_name, reg, idx))
 
 #define imx_clk_gate_exclusive(name, parent, reg, shift, exclusive_mask) \
-	imx_clk_hw_gate_exclusive(name, parent, reg, shift, exclusive_mask)->clk
+	to_clk(imx_clk_hw_gate_exclusive(name, parent, reg, shift, exclusive_mask))
+
+#define imx_clk_fixed(name, rate) \
+	to_clk(imx_clk_hw_fixed(name, rate))
 
 #define imx_clk_fixed_factor(name, parent, mult, div) \
-	imx_clk_hw_fixed_factor(name, parent, mult, div)->clk
+	to_clk(imx_clk_hw_fixed_factor(name, parent, mult, div))
+
+#define imx_clk_divider(name, parent, reg, shift, width) \
+	to_clk(imx_clk_hw_divider(name, parent, reg, shift, width))
 
 #define imx_clk_divider2(name, parent, reg, shift, width) \
-	imx_clk_hw_divider2(name, parent, reg, shift, width)->clk
+	to_clk(imx_clk_hw_divider2(name, parent, reg, shift, width))
+
+#define imx_clk_divider_flags(name, parent, reg, shift, width, flags) \
+	to_clk(imx_clk_hw_divider_flags(name, parent, reg, shift, width, flags))
+
+#define imx_clk_gate(name, parent, reg, shift) \
+	to_clk(imx_clk_hw_gate(name, parent, reg, shift))
 
 #define imx_clk_gate_dis(name, parent, reg, shift) \
-	imx_clk_hw_gate_dis(name, parent, reg, shift)->clk
+	to_clk(imx_clk_hw_gate_dis(name, parent, reg, shift))
 
 #define imx_clk_gate2(name, parent, reg, shift) \
-	imx_clk_hw_gate2(name, parent, reg, shift)->clk
+	to_clk(imx_clk_hw_gate2(name, parent, reg, shift))
 
 #define imx_clk_gate2_flags(name, parent, reg, shift, flags) \
-	imx_clk_hw_gate2_flags(name, parent, reg, shift, flags)->clk
+	to_clk(imx_clk_hw_gate2_flags(name, parent, reg, shift, flags))
 
 #define imx_clk_gate2_shared2(name, parent, reg, shift, share_count) \
-	imx_clk_hw_gate2_shared2(name, parent, reg, shift, share_count)->clk
+	to_clk(imx_clk_hw_gate2_shared2(name, parent, reg, shift, share_count))
 
 #define imx_clk_gate3(name, parent, reg, shift) \
-	imx_clk_hw_gate3(name, parent, reg, shift)->clk
+	to_clk(imx_clk_hw_gate3(name, parent, reg, shift))
 
 #define imx_clk_gate4(name, parent, reg, shift) \
-	imx_clk_hw_gate4(name, parent, reg, shift)->clk
+	to_clk(imx_clk_hw_gate4(name, parent, reg, shift))
 
 #define imx_clk_mux(name, reg, shift, width, parents, num_parents) \
-	imx_clk_hw_mux(name, reg, shift, width, parents, num_parents)->clk
+	to_clk(imx_clk_hw_mux(name, reg, shift, width, parents, num_parents))
+
+#define imx_clk_pllv1(type, name, parent, base) \
+	to_clk(imx_clk_hw_pllv1(type, name, parent, base))
+
+#define imx_clk_pllv2(name, parent, base) \
+	to_clk(imx_clk_hw_pllv2(name, parent, base))
+
+#define imx_clk_frac_pll(name, parent_name, base) \
+	to_clk(imx_clk_hw_frac_pll(name, parent_name, base))
+
+#define imx_clk_sscg_pll(name, parent_names, num_parents, parent,\
+				bypass1, bypass2, base, flags) \
+	to_clk(imx_clk_hw_sscg_pll(name, parent_names, num_parents, parent,\
+				bypass1, bypass2, base, flags))
 
 struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
 		 void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
 
-struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
+#define imx_clk_pll14xx(name, parent_name, base, pll_clk) \
+	to_clk(imx_clk_hw_pll14xx(name, parent_name, base, pll_clk))
+
+struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
+				const char *parent_name, void __iomem *base,
+				const struct imx_pll14xx_clk *pll_clk);
+
+#define imx_dev_clk_pll14xx(dev, name, parent_name, base, pll_clk)	\
+	to_clk(imx_dev_clk_hw_pll14xx(dev, name, parent_name, base, pll_clk))
+
+
+struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
 		const char *parent, void __iomem *base);
 
-struct clk *imx_clk_pllv2(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent,
 		void __iomem *base);
 
-struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_frac_pll(const char *name, const char *parent_name,
 			     void __iomem *base);
 
-struct clk *imx_clk_sccg_pll(const char *name,
+struct clk_hw *imx_clk_hw_sscg_pll(const char *name,
 				const char * const *parent_names,
 				u8 num_parents,
 				u8 parent, u8 bypass1, u8 bypass2,
@@ -146,12 +196,12 @@
 		.kdiv	=	(_k),			\
 	}
 
-struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
 			     void __iomem *base);
 
 struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 bit_idx, u8 cgr_val,
+		void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
 		u8 clk_gate_flags, spinlock_t *lock,
 		unsigned int *share_count);
 
@@ -170,7 +220,7 @@
 struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
 		void __iomem *reg, u8 idx);
 
-struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
 			     void __iomem *reg, u8 idx);
 
 struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
@@ -181,7 +231,7 @@
 			     u8 width, void __iomem *busy_reg, u8 busy_shift,
 			     const char * const *parent_names, int num_parents);
 
-struct clk_hw *imx7ulp_clk_composite(const char *name,
+struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
 				     const char * const *parent_names,
 				     int num_parents, bool mux_present,
 				     bool rate_present, bool gate_present,
@@ -195,9 +245,18 @@
 			      u8 shift, u8 width, const char * const *parents,
 			      int num_parents, void (*fixup)(u32 *val));
 
-static inline struct clk *imx_clk_fixed(const char *name, int rate)
+static inline struct clk *to_clk(struct clk_hw *hw)
+{
+	if (IS_ERR_OR_NULL(hw))
+		return ERR_CAST(hw);
+	return hw->clk;
+}
+
+static inline struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
+				  void __iomem *base,
+				  const struct imx_pll14xx_clk *pll_clk)
 {
-	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+	return imx_dev_clk_hw_pll14xx(NULL, name, parent_name, base, pll_clk);
 }
 
 static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
@@ -221,13 +280,6 @@
 			CLK_SET_RATE_PARENT, mult, div);
 }
 
-static inline struct clk *imx_clk_divider(const char *name, const char *parent,
-		void __iomem *reg, u8 shift, u8 width)
-{
-	return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
-			reg, shift, width, 0, &imx_ccm_lock);
-}
-
 static inline struct clk_hw *imx_clk_hw_divider(const char *name,
 						const char *parent,
 						void __iomem *reg, u8 shift,
@@ -237,14 +289,6 @@
 				       reg, shift, width, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_divider_flags(const char *name,
-		const char *parent, void __iomem *reg, u8 shift, u8 width,
-		unsigned long flags)
-{
-	return clk_register_divider(NULL, name, parent, flags,
-			reg, shift, width, 0, &imx_ccm_lock);
-}
-
 static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
 						   const char *parent,
 						   void __iomem *reg, u8 shift,
@@ -271,13 +315,25 @@
 			reg, shift, width, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate(const char *name, const char *parent,
+static inline struct clk *imx_dev_clk_gate(struct device *dev,
+		const char *name, const char *parent,
 		void __iomem *reg, u8 shift)
 {
-	return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+	return clk_register_gate(dev, name, parent, CLK_SET_RATE_PARENT, reg,
 			shift, 0, &imx_ccm_lock);
 }
 
+struct clk *imx_dev_clk_gate_shared(struct device *dev, const char *name,
+					const char *parent, void __iomem *reg,
+					u8 shift, unsigned int *share_count);
+
+static inline struct clk *imx_clk_gate_shared(const char *name,
+		const char *parent, void __iomem *reg, u8 shift,
+		unsigned int *share_count)
+{
+	return imx_dev_clk_gate_shared(NULL, name, parent, reg, shift, share_count);
+}
+
 static inline struct clk_hw *imx_clk_hw_gate_flags(const char *name, const char *parent,
 		void __iomem *reg, u8 shift, unsigned long flags)
 {
@@ -292,6 +348,13 @@
 				    shift, 0, &imx_ccm_lock);
 }
 
+static inline struct clk_hw *imx_dev_clk_hw_gate(struct device *dev, const char *name,
+						const char *parent, void __iomem *reg, u8 shift)
+{
+	return clk_hw_register_gate(dev, name, parent, CLK_SET_RATE_PARENT, reg,
+				    shift, 0, &imx_ccm_lock);
+}
+
 static inline struct clk_hw *imx_clk_hw_gate_dis(const char *name, const char *parent,
 		void __iomem *reg, u8 shift)
 {
@@ -310,14 +373,14 @@
 		void __iomem *reg, u8 shift)
 {
 	return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, 0x3, 0, &imx_ccm_lock, NULL);
+			shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
 		void __iomem *reg, u8 shift, unsigned long flags)
 {
 	return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
-			shift, 0x3, 0, &imx_ccm_lock, NULL);
+			shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
@@ -325,7 +388,7 @@
 		unsigned int *share_count)
 {
 	return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, 0x3, 0, &imx_ccm_lock, share_count);
+			shift, 0x3, 0x3, 0, &imx_ccm_lock, share_count);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
@@ -333,51 +396,77 @@
 		unsigned int *share_count)
 {
 	return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
-				  CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
+				  CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0x3, 0,
 				  &imx_ccm_lock, share_count);
 }
 
+static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev,
+				const char *name, const char *parent,
+				void __iomem *reg, u8 shift,
+				unsigned int *share_count)
+{
+	return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+					CLK_OPS_PARENT_ENABLE, reg, shift, 0x1,
+					0x1, 0, &imx_ccm_lock, share_count);
+}
+
 static inline struct clk *imx_clk_gate2_cgr(const char *name,
 		const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
 {
 	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, cgr_val, 0, &imx_ccm_lock, NULL);
+			shift, cgr_val, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
 		void __iomem *reg, u8 shift)
 {
-	return clk_hw_register_gate(NULL, name, parent,
+	/*
+	 * per design team's suggestion, clk root is NOT consuming
+	 * much power, and clk root enable/disable does NOT have domain
+	 * control, so they suggest to leave clk root always on when
+	 * M4 is enabled.
+	 */
+	if (imx_src_is_m4_enabled())
+		return clk_hw_register_fixed_factor(NULL, name, parent,
+						 CLK_SET_RATE_PARENT, 1, 1);
+	else
+		return clk_hw_register_gate(NULL, name, parent,
 			CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
 			reg, shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate3_flags(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate3_flags(const char *name,
 		const char *parent, void __iomem *reg, u8 shift,
 		unsigned long flags)
 {
-	return clk_register_gate(NULL, name, parent,
+	return clk_hw_register_gate(NULL, name, parent,
 			flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
 			reg, shift, 0, &imx_ccm_lock);
 }
 
+#define imx_clk_gate3_flags(name, parent, reg, shift, flags) \
+	to_clk(imx_clk_hw_gate3_flags(name, parent, reg, shift, flags))
+
 static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *parent,
 		void __iomem *reg, u8 shift)
 {
 	return clk_hw_register_gate2(NULL, name, parent,
 			CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-			reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
+			reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate4_flags(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name,
 		const char *parent, void __iomem *reg, u8 shift,
 		unsigned long flags)
 {
-	return clk_register_gate2(NULL, name, parent,
+	return clk_hw_register_gate2(NULL, name, parent,
 			flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-			reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
+			reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
+#define imx_clk_gate4_flags(name, parent, reg, shift, flags) \
+	to_clk(imx_clk_hw_gate4_flags(name, parent, reg, shift, flags))
+
 static inline struct clk_hw *imx_clk_hw_mux(const char *name, void __iomem *reg,
 			u8 shift, u8 width, const char * const *parents,
 			int num_parents)
@@ -387,6 +476,24 @@
 			width, 0, &imx_ccm_lock);
 }
 
+static inline struct clk *imx_dev_clk_mux(struct device *dev, const char *name,
+                       void __iomem *reg, u8 shift, u8 width,
+                       const char * const *parents, int num_parents)
+{
+	return clk_register_mux(dev, name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+			reg, shift, width, 0, &imx_ccm_lock);
+}
+
+static inline struct clk_hw *imx_dev_clk_hw_mux(struct device *dev,
+			const char *name, void __iomem *reg, u8 shift,
+			u8 width, const char * const *parents, int num_parents)
+{
+	return clk_hw_register_mux(dev, name, parents, num_parents,
+			CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+			reg, shift, width, 0, &imx_ccm_lock);
+}
+
 static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
 			u8 shift, u8 width, const char * const *parents,
 			int num_parents)
@@ -417,6 +524,26 @@
 			&imx_ccm_lock);
 }
 
+static inline struct clk *imx_dev_clk_mux_flags(struct device *dev,
+                       const char *name, void __iomem *reg, u8 shift,
+                       u8 width, const char * const *parents, int num_parents,
+                       unsigned long flags)
+{
+       return clk_register_mux(dev, name, parents, num_parents,
+                       flags | CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+                       reg, shift, width, 0, &imx_ccm_lock);
+}
+
+static inline struct clk_hw *imx_clk_hw_mux2_flags(const char *name,
+		void __iomem *reg, u8 shift, u8 width,
+		const char * const *parents,
+		int num_parents, unsigned long flags)
+{
+	return clk_hw_register_mux(NULL, name, parents, num_parents,
+			flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
+			reg, shift, width, 0, &imx_ccm_lock);
+}
+
 static inline struct clk *imx_clk_mux2_flags(const char *name,
 		void __iomem *reg, u8 shift, u8 width,
 		const char * const *parents,
@@ -439,27 +566,76 @@
 				   reg, shift, width, 0, &imx_ccm_lock);
 }
 
+static inline struct clk_hw *imx_dev_clk_hw_mux_flags(struct device *dev,
+						  const char *name,
+						  void __iomem *reg, u8 shift,
+						  u8 width,
+						  const char * const *parents,
+						  int num_parents,
+						  unsigned long flags)
+{
+	return clk_hw_register_mux(dev, name, parents, num_parents,
+				   flags | CLK_SET_RATE_NO_REPARENT,
+				   reg, shift, width, 0, &imx_ccm_lock);
+}
+
 struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
 		struct clk *div, struct clk *mux, struct clk *pll,
 		struct clk *step);
 
-struct clk *imx8m_clk_composite_flags(const char *name,
-					const char * const *parent_names,
-					int num_parents, void __iomem *reg,
-					unsigned long flags);
+#define IMX_COMPOSITE_CORE	BIT(0)
+#define IMX_COMPOSITE_BUS	BIT(1)
 
-#define __imx8m_clk_composite(name, parent_names, reg, flags) \
-	imx8m_clk_composite_flags(name, parent_names, \
-		ARRAY_SIZE(parent_names), reg, \
+struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
+					    const char * const *parent_names,
+					    int num_parents,
+					    void __iomem *reg,
+					    u32 composite_flags,
+					    unsigned long flags);
+
+#define imx8m_clk_hw_composite_bus(name, parent_names, reg)	\
+	imx8m_clk_hw_composite_flags(name, parent_names, \
+			ARRAY_SIZE(parent_names), reg, \
+			IMX_COMPOSITE_BUS, \
+			CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
+
+#define imx8m_clk_hw_composite_bus_critical(name, parent_names, reg)	\
+	imx8m_clk_hw_composite_flags(name, parent_names, ARRAY_SIZE(parent_names), reg, \
+			IMX_COMPOSITE_BUS, \
+			CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE | CLK_IS_CRITICAL)
+
+#define imx8m_clk_hw_composite_core(name, parent_names, reg)	\
+	imx8m_clk_hw_composite_flags(name, parent_names, \
+			ARRAY_SIZE(parent_names), reg, \
+			IMX_COMPOSITE_CORE, \
+			CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
+
+#define imx8m_clk_composite_flags(name, parent_names, num_parents, reg, \
+				  flags) \
+	to_clk(imx8m_clk_hw_composite_flags(name, parent_names, \
+				num_parents, reg, 0, flags))
+
+#define __imx8m_clk_hw_composite(name, parent_names, reg, flags) \
+	imx8m_clk_hw_composite_flags(name, parent_names, \
+		ARRAY_SIZE(parent_names), reg, 0, \
 		flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
 
+#define __imx8m_clk_composite(name, parent_names, reg, flags) \
+	to_clk(__imx8m_clk_hw_composite(name, parent_names, reg, flags))
+
+#define imx8m_clk_hw_composite(name, parent_names, reg) \
+	__imx8m_clk_hw_composite(name, parent_names, reg, 0)
+
 #define imx8m_clk_composite(name, parent_names, reg) \
 	__imx8m_clk_composite(name, parent_names, reg, 0)
 
+#define imx8m_clk_hw_composite_critical(name, parent_names, reg) \
+	__imx8m_clk_hw_composite(name, parent_names, reg, CLK_IS_CRITICAL)
+
 #define imx8m_clk_composite_critical(name, parent_names, reg) \
 	__imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
 
-struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name,
 		unsigned long flags, void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock);
--- linux-ein-5.4.0.orig/drivers/clk/ingenic/cgu.c
+++ linux-ein-5.4.0/drivers/clk/ingenic/cgu.c
@@ -393,15 +393,21 @@
 ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
 			unsigned int div)
 {
-	unsigned int i;
+	unsigned int i, best_i = 0, best = (unsigned int)-1;
 
 	for (i = 0; i < (1 << clk_info->div.bits)
 				&& clk_info->div.div_table[i]; i++) {
-		if (clk_info->div.div_table[i] >= div)
-			return i;
+		if (clk_info->div.div_table[i] >= div &&
+		    clk_info->div.div_table[i] < best) {
+			best = clk_info->div.div_table[i];
+			best_i = i;
+
+			if (div == best)
+				break;
+		}
 	}
 
-	return i - 1;
+	return best_i;
 }
 
 static unsigned
@@ -420,15 +426,15 @@
 	}
 
 	/* Impose hardware constraints */
-	div = min_t(unsigned, div, 1 << clk_info->div.bits);
-	div = max_t(unsigned, div, 1);
+	div = clamp_t(unsigned int, div, clk_info->div.div,
+		      clk_info->div.div << clk_info->div.bits);
 
 	/*
 	 * If the divider value itself must be divided before being written to
 	 * the divider register, we must ensure we don't have any bits set that
 	 * would be lost as a result of doing so.
 	 */
-	div /= clk_info->div.div;
+	div = DIV_ROUND_UP(div, clk_info->div.div);
 	div *= clk_info->div.div;
 
 	return div;
--- linux-ein-5.4.0.orig/drivers/clk/ingenic/jz4725b-cgu.c
+++ linux-ein-5.4.0/drivers/clk/ingenic/jz4725b-cgu.c
@@ -135,11 +135,10 @@
 	},
 
 	[JZ4725B_CLK_I2S] = {
-		"i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+		"i2s", CGU_CLK_MUX | CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
 		.mux = { CGU_REG_CPCCR, 31, 1 },
 		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
-		.gate = { CGU_REG_CLKGR, 6 },
 	},
 
 	[JZ4725B_CLK_SPI] = {
--- linux-ein-5.4.0.orig/drivers/clk/ingenic/jz4770-cgu.c
+++ linux-ein-5.4.0/drivers/clk/ingenic/jz4770-cgu.c
@@ -432,8 +432,10 @@
 
 	cgu = ingenic_cgu_new(jz4770_cgu_clocks,
 			      ARRAY_SIZE(jz4770_cgu_clocks), np);
-	if (!cgu)
+	if (!cgu) {
 		pr_err("%s: failed to initialise CGU\n", __func__);
+		return;
+	}
 
 	retval = ingenic_cgu_register_clocks(cgu);
 	if (retval)
--- linux-ein-5.4.0.orig/drivers/clk/ingenic/tcu.c
+++ linux-ein-5.4.0/drivers/clk/ingenic/tcu.c
@@ -100,15 +100,11 @@
 	bool enabled = false;
 
 	/*
-	 * If the SoC has no global TCU clock, we must ungate the channel's
-	 * clock to be able to access its registers.
-	 * If we have a TCU clock, it will be enabled automatically as it has
-	 * been attached to the regmap.
+	 * According to the programming manual, a timer channel's registers can
+	 * only be accessed when the channel's stop bit is clear.
 	 */
-	if (!tcu->clk) {
-		enabled = !!ingenic_tcu_is_enabled(hw);
-		regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
-	}
+	enabled = !!ingenic_tcu_is_enabled(hw);
+	regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));
 
 	return enabled;
 }
@@ -119,8 +115,7 @@
 	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
 	struct ingenic_tcu *tcu = tcu_clk->tcu;
 
-	if (!tcu->clk)
-		regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
+	regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
 }
 
 static u8 ingenic_tcu_get_parent(struct clk_hw *hw)
@@ -189,7 +184,7 @@
 	u8 prescale;
 
 	if (req_rate > rate)
-		return -EINVAL;
+		return rate;
 
 	prescale = ingenic_tcu_get_prescale(rate, req_rate);
 
--- linux-ein-5.4.0.orig/drivers/clk/keystone/pll.c
+++ linux-ein-5.4.0/drivers/clk/keystone/pll.c
@@ -209,7 +209,7 @@
 	}
 
 	clk = clk_register_pll(NULL, node->name, parent_name, pll_data);
-	if (clk) {
+	if (!IS_ERR_OR_NULL(clk)) {
 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 		return;
 	}
@@ -281,12 +281,13 @@
 
 	clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift,
 				 mask, 0, NULL);
-	if (clk) {
-		of_clk_add_provider(node, of_clk_src_simple_get, clk);
-	} else {
+	if (IS_ERR(clk)) {
 		pr_err("%s: error registering divider %s\n", __func__, clk_name);
 		iounmap(reg);
+		return;
 	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
 }
 CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init);
 
@@ -328,10 +329,12 @@
 	clk = clk_register_mux(NULL, clk_name, (const char **)&parents,
 				ARRAY_SIZE(parents) , 0, reg, shift, mask,
 				0, NULL);
-	if (clk)
-		of_clk_add_provider(node, of_clk_src_simple_get, clk);
-	else
+	if (IS_ERR(clk)) {
 		pr_err("%s: error registering mux %s\n", __func__, clk_name);
+		return;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
 }
 CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init);
 
--- linux-ein-5.4.0.orig/drivers/clk/keystone/sci-clk.c
+++ linux-ein-5.4.0/drivers/clk/keystone/sci-clk.c
@@ -287,6 +287,8 @@
 
 	name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
 			 sci_clk->clk_id);
+	if (!name)
+		return -ENOMEM;
 
 	init.name = name;
 
@@ -522,7 +524,7 @@
 		np = of_find_node_with_property(np, *clk_name);
 		if (!np) {
 			clk_name++;
-			break;
+			continue;
 		}
 
 		if (!of_device_is_available(np))
--- linux-ein-5.4.0.orig/drivers/clk/loongson1/clk-loongson1c.c
+++ linux-ein-5.4.0/drivers/clk/loongson1/clk-loongson1c.c
@@ -37,6 +37,7 @@
 	[1] = { .val = 1, .div = 4 },
 	[2] = { .val = 2, .div = 3 },
 	[3] = { .val = 3, .div = 3 },
+	[4] = { /* sentinel */ }
 };
 
 void __init ls1x_clk_init(void)
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt2701.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt2701.c
@@ -675,6 +675,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
 								clk_data);
@@ -742,6 +744,8 @@
 
 	if (!infra_clk_data) {
 		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
+		if (!infra_clk_data)
+			return;
 
 		for (i = 0; i < CLK_INFRA_NR; i++)
 			infra_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER);
@@ -768,6 +772,8 @@
 
 	if (!infra_clk_data) {
 		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
+		if (!infra_clk_data)
+			return -ENOMEM;
 	} else {
 		for (i = 0; i < CLK_INFRA_NR; i++) {
 			if (infra_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER))
@@ -896,6 +902,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
 						clk_data);
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt6779.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt6779.c
@@ -919,6 +919,8 @@
 		    "pwm_sel", 19),
 	GATE_INFRA0(CLK_INFRA_PWM, "infra_pwm",
 		    "pwm_sel", 21),
+	GATE_INFRA0(CLK_INFRA_UART0, "infra_uart0",
+		    "uart_sel", 22),
 	GATE_INFRA0(CLK_INFRA_UART1, "infra_uart1",
 		    "uart_sel", 23),
 	GATE_INFRA0(CLK_INFRA_UART2, "infra_uart2",
@@ -1214,6 +1216,8 @@
 	struct device_node *node = pdev->dev.of_node;
 
 	clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
 
@@ -1235,6 +1239,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
 				    clk_data);
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt6797.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt6797.c
@@ -392,6 +392,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
 				 clk_data);
@@ -564,6 +566,8 @@
 
 	if (!infra_clk_data) {
 		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
+		if (!infra_clk_data)
+			return;
 
 		for (i = 0; i < CLK_INFRA_NR; i++)
 			infra_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER);
@@ -588,6 +592,8 @@
 
 	if (!infra_clk_data) {
 		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
+		if (!infra_clk_data)
+			return -ENOMEM;
 	} else {
 		for (i = 0; i < CLK_INFRA_NR; i++) {
 			if (infra_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER))
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt7629-eth.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt7629-eth.c
@@ -83,6 +83,8 @@
 	int r;
 
 	clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_gates(node, eth_clks, CLK_ETH_NR_CLK, clk_data);
 
@@ -105,6 +107,8 @@
 	int r;
 
 	clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_gates(node, sgmii_clks[id++], CLK_SGMII_NR_CLK,
 			       clk_data);
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt7629.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt7629.c
@@ -581,6 +581,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
 				    clk_data);
@@ -605,6 +607,8 @@
 	int r;
 
 	clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
 			       clk_data);
@@ -633,6 +637,8 @@
 		return PTR_ERR(base);
 
 	clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+	if (!clk_data)
+		return -ENOMEM;
 
 	mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
 			       clk_data);
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mt8183-mfgcfg.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mt8183-mfgcfg.c
@@ -18,9 +18,9 @@
 	.sta_ofs = 0x0,
 };
 
-#define GATE_MFG(_id, _name, _parent, _shift)			\
-	GATE_MTK(_id, _name, _parent, &mfg_cg_regs, _shift,	\
-		&mtk_clk_gate_ops_setclr)
+#define GATE_MFG(_id, _name, _parent, _shift)				\
+	GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift,	\
+		       &mtk_clk_gate_ops_setclr, CLK_SET_RATE_PARENT)
 
 static const struct mtk_gate mfg_clks[] = {
 	GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_sel", 0)
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/clk-mux.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/clk-mux.c
@@ -160,7 +160,7 @@
 				 spinlock_t *lock)
 {
 	struct mtk_clk_mux *clk_mux;
-	struct clk_init_data init;
+	struct clk_init_data init = {};
 	struct clk *clk;
 
 	clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
--- linux-ein-5.4.0.orig/drivers/clk/mediatek/reset.c
+++ linux-ein-5.4.0/drivers/clk/mediatek/reset.c
@@ -25,7 +25,7 @@
 	struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
 	unsigned int reg = data->regofs + ((id / 32) << 4);
 
-	return regmap_write(data->regmap, reg, 1);
+	return regmap_write(data->regmap, reg, BIT(id % 32));
 }
 
 static int mtk_reset_deassert_set_clr(struct reset_controller_dev *rcdev,
@@ -34,7 +34,7 @@
 	struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
 	unsigned int reg = data->regofs + ((id / 32) << 4) + 0x4;
 
-	return regmap_write(data->regmap, reg, 1);
+	return regmap_write(data->regmap, reg, BIT(id % 32));
 }
 
 static int mtk_reset_assert(struct reset_controller_dev *rcdev,
--- linux-ein-5.4.0.orig/drivers/clk/meson/Kconfig
+++ linux-ein-5.4.0/drivers/clk/meson/Kconfig
@@ -103,6 +103,7 @@
 	select COMMON_CLK_MESON_AO_CLKC
 	select COMMON_CLK_MESON_EE_CLKC
 	select COMMON_CLK_MESON_CPU_DYNDIV
+	select COMMON_CLK_MESON_VID_PLL_DIV
 	select MFD_SYSCON
 	help
 	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
--- linux-ein-5.4.0.orig/drivers/clk/meson/axg-audio.c
+++ linux-ein-5.4.0/drivers/clk/meson/axg-audio.c
@@ -1001,7 +1001,7 @@
 	.reg_bits	= 32,
 	.val_bits	= 32,
 	.reg_stride	= 4,
-	.max_register	= AUDIO_CLK_PDMIN_CTRL1,
+	.max_register	= AUDIO_CLK_SPDIFOUT_B_CTRL,
 };
 
 struct audioclk_data {
--- linux-ein-5.4.0.orig/drivers/clk/meson/clk-pll.c
+++ linux-ein-5.4.0/drivers/clk/meson/clk-pll.c
@@ -77,6 +77,15 @@
 	unsigned int m, n, frac;
 
 	n = meson_parm_read(clk->map, &pll->n);
+
+	/*
+	 * On some HW, N is set to zero on init. This value is invalid as
+	 * it would result in a division by zero. The rate can't be
+	 * calculated in this case
+	 */
+	if (n == 0)
+		return 0;
+
 	m = meson_parm_read(clk->map, &pll->m);
 
 	frac = MESON_PARM_APPLICABLE(&pll->frac) ?
@@ -354,13 +363,14 @@
 {
 	struct clk_regmap *clk = to_clk_regmap(hw);
 	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
-	unsigned int enabled, m, n, frac = 0, ret;
+	unsigned int enabled, m, n, frac = 0;
 	unsigned long old_rate;
+	int ret;
 
 	if (parent_rate == 0 || rate == 0)
 		return -EINVAL;
 
-	old_rate = rate;
+	old_rate = clk_hw_get_rate(hw);
 
 	ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll);
 	if (ret)
@@ -382,7 +392,8 @@
 	if (!enabled)
 		return 0;
 
-	if (meson_clk_pll_enable(hw)) {
+	ret = meson_clk_pll_enable(hw);
+	if (ret) {
 		pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
 			__func__, old_rate);
 		/*
@@ -394,7 +405,7 @@
 		meson_clk_pll_set_rate(hw, old_rate, parent_rate);
 	}
 
-	return 0;
+	return ret;
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/clk/meson/g12a.c
+++ linux-ein-5.4.0/drivers/clk/meson/g12a.c
@@ -298,6 +298,17 @@
 			&g12a_fclk_div2_div.hw
 		},
 		.num_parents = 1,
+		/*
+		 * Similar to fclk_div3, it seems that this clock is used by
+		 * the resident firmware and is required by the platform to
+		 * operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_IS_CRITICAL,
 	},
 };
 
@@ -1591,7 +1602,7 @@
 };
 
 static const struct pll_mult_range g12a_gp0_pll_mult_range = {
-	.min = 55,
+	.min = 125,
 	.max = 255,
 };
 
@@ -4692,6 +4703,7 @@
 	&g12a_bt656,
 	&g12a_usb1_to_ddr,
 	&g12a_mmc_pclk,
+	&g12a_uart2,
 	&g12a_vpu_intr,
 	&g12a_gic,
 	&g12a_sd_emmc_a_clk0,
--- linux-ein-5.4.0.orig/drivers/clk/meson/gxbb.c
+++ linux-ein-5.4.0/drivers/clk/meson/gxbb.c
@@ -719,6 +719,35 @@
 			.width   = 14,
 		},
 		.sdm_en = {
+			.reg_off = HHI_MPLL_CNTL,
+			.shift   = 25,
+			.width	 = 1,
+		},
+		.n2 = {
+			.reg_off = HHI_MPLL_CNTL7,
+			.shift   = 16,
+			.width   = 9,
+		},
+		.lock = &meson_clk_lock,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "mpll0_div",
+		.ops = &meson_clk_mpll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&gxbb_mpll_prediv.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap gxl_mpll0_div = {
+	.data = &(struct meson_clk_mpll_data){
+		.sdm = {
+			.reg_off = HHI_MPLL_CNTL7,
+			.shift   = 0,
+			.width   = 14,
+		},
+		.sdm_en = {
 			.reg_off = HHI_MPLL_CNTL7,
 			.shift   = 15,
 			.width	 = 1,
@@ -748,7 +777,16 @@
 	.hw.init = &(struct clk_init_data){
 		.name = "mpll0",
 		.ops = &clk_regmap_gate_ops,
-		.parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw },
+		.parent_data = &(const struct clk_parent_data) {
+			/*
+			 * Note:
+			 * GXL and GXBB have different SDM_EN registers. We
+			 * fallback to the global naming string mechanism so
+			 * mpll0_div picks up the appropriate one.
+			 */
+			.name = "mpll0_div",
+			.index = -1,
+		},
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
 	},
@@ -3036,7 +3074,7 @@
 		[CLKID_VAPB_1]		    = &gxbb_vapb_1.hw,
 		[CLKID_VAPB_SEL]	    = &gxbb_vapb_sel.hw,
 		[CLKID_VAPB]		    = &gxbb_vapb.hw,
-		[CLKID_MPLL0_DIV]	    = &gxbb_mpll0_div.hw,
+		[CLKID_MPLL0_DIV]	    = &gxl_mpll0_div.hw,
 		[CLKID_MPLL1_DIV]	    = &gxbb_mpll1_div.hw,
 		[CLKID_MPLL2_DIV]	    = &gxbb_mpll2_div.hw,
 		[CLKID_MPLL_PREDIV]	    = &gxbb_mpll_prediv.hw,
@@ -3430,7 +3468,7 @@
 	&gxbb_mpll0,
 	&gxbb_mpll1,
 	&gxbb_mpll2,
-	&gxbb_mpll0_div,
+	&gxl_mpll0_div,
 	&gxbb_mpll1_div,
 	&gxbb_mpll2_div,
 	&gxbb_cts_amclk_div,
--- linux-ein-5.4.0.orig/drivers/clk/meson/meson-aoclk.c
+++ linux-ein-5.4.0/drivers/clk/meson/meson-aoclk.c
@@ -36,6 +36,7 @@
 	struct meson_aoclk_reset_controller *rstc;
 	struct meson_aoclk_data *data;
 	struct device *dev = &pdev->dev;
+	struct device_node *np;
 	struct regmap *regmap;
 	int ret, clkid;
 
@@ -47,7 +48,9 @@
 	if (!rstc)
 		return -ENOMEM;
 
-	regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
+	np = of_get_parent(dev->of_node);
+	regmap = syscon_node_to_regmap(np);
+	of_node_put(np);
 	if (IS_ERR(regmap)) {
 		dev_err(dev, "failed to get regmap\n");
 		return PTR_ERR(regmap);
--- linux-ein-5.4.0.orig/drivers/clk/meson/meson-eeclk.c
+++ linux-ein-5.4.0/drivers/clk/meson/meson-eeclk.c
@@ -17,6 +17,7 @@
 {
 	const struct meson_eeclkc_data *data;
 	struct device *dev = &pdev->dev;
+	struct device_node *np;
 	struct regmap *map;
 	int ret, i;
 
@@ -25,7 +26,9 @@
 		return -EINVAL;
 
 	/* Get the hhi system controller node */
-	map = syscon_node_to_regmap(of_get_parent(dev->of_node));
+	np = of_get_parent(dev->of_node);
+	map = syscon_node_to_regmap(np);
+	of_node_put(np);
 	if (IS_ERR(map)) {
 		dev_err(dev,
 			"failed to get HHI regmap\n");
--- linux-ein-5.4.0.orig/drivers/clk/meson/meson8b.c
+++ linux-ein-5.4.0/drivers/clk/meson/meson8b.c
@@ -1071,7 +1071,7 @@
 		 * Meson8m2: vid2_pll
 		 */
 		.parent_hws = (const struct clk_hw *[]) {
-			&meson8b_hdmi_pll_dco.hw
+			&meson8b_hdmi_pll_lvds_out.hw
 		},
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
@@ -1207,7 +1207,7 @@
 
 static struct clk_regmap meson8b_vclk_div1_gate = {
 	.data = &(struct clk_regmap_gate_data){
-		.offset = HHI_VID_CLK_DIV,
+		.offset = HHI_VID_CLK_CNTL,
 		.bit_idx = 0,
 	},
 	.hw.init = &(struct clk_init_data){
@@ -1237,7 +1237,7 @@
 
 static struct clk_regmap meson8b_vclk_div2_div_gate = {
 	.data = &(struct clk_regmap_gate_data){
-		.offset = HHI_VID_CLK_DIV,
+		.offset = HHI_VID_CLK_CNTL,
 		.bit_idx = 1,
 	},
 	.hw.init = &(struct clk_init_data){
@@ -1267,7 +1267,7 @@
 
 static struct clk_regmap meson8b_vclk_div4_div_gate = {
 	.data = &(struct clk_regmap_gate_data){
-		.offset = HHI_VID_CLK_DIV,
+		.offset = HHI_VID_CLK_CNTL,
 		.bit_idx = 2,
 	},
 	.hw.init = &(struct clk_init_data){
@@ -1297,7 +1297,7 @@
 
 static struct clk_regmap meson8b_vclk_div6_div_gate = {
 	.data = &(struct clk_regmap_gate_data){
-		.offset = HHI_VID_CLK_DIV,
+		.offset = HHI_VID_CLK_CNTL,
 		.bit_idx = 3,
 	},
 	.hw.init = &(struct clk_init_data){
@@ -1327,7 +1327,7 @@
 
 static struct clk_regmap meson8b_vclk_div12_div_gate = {
 	.data = &(struct clk_regmap_gate_data){
-		.offset = HHI_VID_CLK_DIV,
+		.offset = HHI_VID_CLK_CNTL,
 		.bit_idx = 4,
 	},
 	.hw.init = &(struct clk_init_data){
@@ -1764,8 +1764,11 @@
 
 /*
  * The MALI IP is clocked by two identical clocks (mali_0 and mali_1)
- * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only
- * has mali_0 and no glitch-free mux.
+ * muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can
+ * actually manage this glitch-free mux because it does top-to-bottom
+ * updates the each clock tree and switches to the "inactive" one when
+ * CLK_SET_RATE_GATE is set.
+ * Meson8 only has mali_0 and no glitch-free mux.
  */
 static const struct clk_hw *meson8b_mali_0_1_parent_hws[] = {
 	&meson8b_xtal.hw,
@@ -1830,7 +1833,7 @@
 			&meson8b_mali_0_div.hw
 		},
 		.num_parents = 1,
-		.flags = CLK_SET_RATE_PARENT,
+		.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -1885,7 +1888,7 @@
 			&meson8b_mali_1_div.hw
 		},
 		.num_parents = 1,
-		.flags = CLK_SET_RATE_PARENT,
+		.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -1907,6 +1910,13 @@
 	},
 };
 
+static const struct reg_sequence meson8m2_gp_pll_init_regs[] = {
+	{ .reg = HHI_GP_PLL_CNTL2,	.def = 0x59c88000 },
+	{ .reg = HHI_GP_PLL_CNTL3,	.def = 0xca463823 },
+	{ .reg = HHI_GP_PLL_CNTL4,	.def = 0x0286a027 },
+	{ .reg = HHI_GP_PLL_CNTL5,	.def = 0x00003000 },
+};
+
 static const struct pll_params_table meson8m2_gp_pll_params_table[] = {
 	PLL_PARAMS(182, 3),
 	{ /* sentinel */ },
@@ -1940,6 +1950,8 @@
 			.width   = 1,
 		},
 		.table = meson8m2_gp_pll_params_table,
+		.init_regs = meson8m2_gp_pll_init_regs,
+		.init_count = ARRAY_SIZE(meson8m2_gp_pll_init_regs),
 	},
 	.hw.init = &(struct clk_init_data){
 		.name = "gp_pll_dco",
@@ -3488,54 +3500,87 @@
 static const struct meson8b_clk_reset_line {
 	u32 reg;
 	u8 bit_idx;
+	bool active_low;
 } meson8b_clk_reset_bits[] = {
 	[CLKC_RESET_L2_CACHE_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 30
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 30,
+		.active_low = false,
 	},
 	[CLKC_RESET_AXI_64_TO_128_BRIDGE_A5_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 29
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 29,
+		.active_low = false,
 	},
 	[CLKC_RESET_SCU_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 28
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 28,
+		.active_low = false,
 	},
 	[CLKC_RESET_CPU3_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 27
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 27,
+		.active_low = false,
 	},
 	[CLKC_RESET_CPU2_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 26
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 26,
+		.active_low = false,
 	},
 	[CLKC_RESET_CPU1_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 25
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 25,
+		.active_low = false,
 	},
 	[CLKC_RESET_CPU0_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 24
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 24,
+		.active_low = false,
 	},
 	[CLKC_RESET_A5_GLOBAL_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 18
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 18,
+		.active_low = false,
 	},
 	[CLKC_RESET_A5_AXI_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 17
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 17,
+		.active_low = false,
 	},
 	[CLKC_RESET_A5_ABP_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 16
+		.reg = HHI_SYS_CPU_CLK_CNTL0,
+		.bit_idx = 16,
+		.active_low = false,
 	},
 	[CLKC_RESET_AXI_64_TO_128_BRIDGE_MMC_SOFT_RESET] = {
-		.reg = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 30
+		.reg = HHI_SYS_CPU_CLK_CNTL1,
+		.bit_idx = 30,
+		.active_low = false,
 	},
 	[CLKC_RESET_VID_CLK_CNTL_SOFT_RESET] = {
-		.reg = HHI_VID_CLK_CNTL, .bit_idx = 15
+		.reg = HHI_VID_CLK_CNTL,
+		.bit_idx = 15,
+		.active_low = false,
 	},
 	[CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST] = {
-		.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 7
+		.reg = HHI_VID_DIVIDER_CNTL,
+		.bit_idx = 7,
+		.active_low = false,
 	},
 	[CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE] = {
-		.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 3
+		.reg = HHI_VID_DIVIDER_CNTL,
+		.bit_idx = 3,
+		.active_low = false,
 	},
 	[CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST] = {
-		.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 1
+		.reg = HHI_VID_DIVIDER_CNTL,
+		.bit_idx = 1,
+		.active_low = true,
 	},
 	[CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE] = {
-		.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 0
+		.reg = HHI_VID_DIVIDER_CNTL,
+		.bit_idx = 0,
+		.active_low = true,
 	},
 };
 
@@ -3544,22 +3589,22 @@
 {
 	struct meson8b_clk_reset *meson8b_clk_reset =
 		container_of(rcdev, struct meson8b_clk_reset, reset);
-	unsigned long flags;
 	const struct meson8b_clk_reset_line *reset;
+	unsigned int value = 0;
+	unsigned long flags;
 
 	if (id >= ARRAY_SIZE(meson8b_clk_reset_bits))
 		return -EINVAL;
 
 	reset = &meson8b_clk_reset_bits[id];
 
+	if (assert != reset->active_low)
+		value = BIT(reset->bit_idx);
+
 	spin_lock_irqsave(&meson_clk_lock, flags);
 
-	if (assert)
-		regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
-				   BIT(reset->bit_idx), BIT(reset->bit_idx));
-	else
-		regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
-				   BIT(reset->bit_idx), 0);
+	regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
+			   BIT(reset->bit_idx), value);
 
 	spin_unlock_irqrestore(&meson_clk_lock, flags);
 
@@ -3639,13 +3684,16 @@
 			struct clk_hw_onecell_data *clk_hw_onecell_data)
 {
 	struct meson8b_clk_reset *rstc;
+	struct device_node *parent_np;
 	const char *notifier_clk_name;
 	struct clk *notifier_clk;
 	void __iomem *clk_base;
 	struct regmap *map;
 	int i, ret;
 
-	map = syscon_node_to_regmap(of_get_parent(np));
+	parent_np = of_get_parent(np);
+	map = syscon_node_to_regmap(parent_np);
+	of_node_put(parent_np);
 	if (IS_ERR(map)) {
 		pr_info("failed to get HHI regmap - Trying obsolete regs\n");
 
--- linux-ein-5.4.0.orig/drivers/clk/meson/meson8b.h
+++ linux-ein-5.4.0/drivers/clk/meson/meson8b.h
@@ -20,6 +20,10 @@
  * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf
  */
 #define HHI_GP_PLL_CNTL			0x40  /* 0x10 offset in data sheet */
+#define HHI_GP_PLL_CNTL2		0x44  /* 0x11 offset in data sheet */
+#define HHI_GP_PLL_CNTL3		0x48  /* 0x12 offset in data sheet */
+#define HHI_GP_PLL_CNTL4		0x4C  /* 0x13 offset in data sheet */
+#define HHI_GP_PLL_CNTL5		0x50  /* 0x14 offset in data sheet */
 #define HHI_VIID_CLK_DIV		0x128 /* 0x4a offset in data sheet */
 #define HHI_VIID_CLK_CNTL		0x12c /* 0x4b offset in data sheet */
 #define HHI_GCLK_MPEG0			0x140 /* 0x50 offset in data sheet */
--- linux-ein-5.4.0.orig/drivers/clk/mmp/clk-of-mmp2.c
+++ linux-ein-5.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);
 
--- linux-ein-5.4.0.orig/drivers/clk/mmp/clk-of-pxa168.c
+++ linux-ein-5.4.0/drivers/clk/mmp/clk-of-pxa168.c
@@ -258,18 +258,21 @@
 	pxa_unit->mpmu_base = of_iomap(np, 0);
 	if (!pxa_unit->mpmu_base) {
 		pr_err("failed to map mpmu registers\n");
+		kfree(pxa_unit);
 		return;
 	}
 
 	pxa_unit->apmu_base = of_iomap(np, 1);
 	if (!pxa_unit->apmu_base) {
 		pr_err("failed to map apmu registers\n");
+		kfree(pxa_unit);
 		return;
 	}
 
 	pxa_unit->apbc_base = of_iomap(np, 2);
 	if (!pxa_unit->apbc_base) {
 		pr_err("failed to map apbc registers\n");
+		kfree(pxa_unit);
 		return;
 	}
 
--- linux-ein-5.4.0.orig/drivers/clk/mvebu/Kconfig
+++ linux-ein-5.4.0/drivers/clk/mvebu/Kconfig
@@ -42,6 +42,7 @@
 
 config ARMADA_AP_CPU_CLK
 	bool
+	select ARMADA_AP_CP_HELPER
 
 config ARMADA_CP110_SYSCON
 	bool
--- linux-ein-5.4.0.orig/drivers/clk/mvebu/ap-cpu-clk.c
+++ linux-ein-5.4.0/drivers/clk/mvebu/ap-cpu-clk.c
@@ -256,12 +256,15 @@
 		int cpu, err;
 
 		err = of_property_read_u32(dn, "reg", &cpu);
-		if (WARN_ON(err))
+		if (WARN_ON(err)) {
+			of_node_put(dn);
 			return err;
+		}
 
 		/* If cpu2 or cpu3 is enabled */
 		if (cpu & APN806_CLUSTER_NUM_MASK) {
 			nclusters = 2;
+			of_node_put(dn);
 			break;
 		}
 	}
@@ -288,8 +291,10 @@
 		int cpu, err;
 
 		err = of_property_read_u32(dn, "reg", &cpu);
-		if (WARN_ON(err))
+		if (WARN_ON(err)) {
+			of_node_put(dn);
 			return err;
+		}
 
 		cluster_index = cpu & APN806_CLUSTER_NUM_MASK;
 		cluster_index >>= APN806_CLUSTER_NUM_OFFSET;
@@ -301,6 +306,7 @@
 		parent = of_clk_get(np, cluster_index);
 		if (IS_ERR(parent)) {
 			dev_err(dev, "Could not get the clock parent\n");
+			of_node_put(dn);
 			return -EINVAL;
 		}
 		parent_name =  __clk_get_name(parent);
@@ -319,8 +325,10 @@
 		init.parent_names = &parent_name;
 
 		ret = devm_clk_hw_register(dev, &ap_cpu_clk[cluster_index].hw);
-		if (ret)
+		if (ret) {
+			of_node_put(dn);
 			return ret;
+		}
 		ap_cpu_data->hws[cluster_index] = &ap_cpu_clk[cluster_index].hw;
 	}
 
--- linux-ein-5.4.0.orig/drivers/clk/mvebu/armada-37xx-periph.c
+++ linux-ein-5.4.0/drivers/clk/mvebu/armada-37xx-periph.c
@@ -84,6 +84,7 @@
 	void __iomem *reg_div;
 	u8 shift_div;
 	struct regmap *nb_pm_base;
+	unsigned long l1_expiration;
 };
 
 #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw)
@@ -438,33 +439,6 @@
 	return val;
 }
 
-static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index)
-{
-	struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
-	struct regmap *base = pm_cpu->nb_pm_base;
-	int load_level;
-
-	/*
-	 * We set the clock parent only if the DVFS is available but
-	 * not enabled.
-	 */
-	if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base))
-		return -EINVAL;
-
-	/* Set the parent clock for all the load level */
-	for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
-		unsigned int reg, mask,  val,
-			offset = ARMADA_37XX_NB_TBG_SEL_OFF;
-
-		armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
-
-		val = index << offset;
-		mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset;
-		regmap_update_bits(base, reg, mask, val);
-	}
-	return 0;
-}
-
 static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw,
 					    unsigned long parent_rate)
 {
@@ -512,8 +486,10 @@
 }
 
 /*
- * Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
- * respectively) to L0 frequency (1.2 Ghz) requires a significant
+ * Workaround when base CPU frequnecy is 1000 or 1200 MHz
+ *
+ * Switching the CPU from the L2 or L3 frequencies (250/300 or 200 MHz
+ * respectively) to L0 frequency (1/1.2 GHz) requires a significant
  * amount of time to let VDD stabilize to the appropriate
  * voltage. This amount of time is large enough that it cannot be
  * covered by the hardware countdown register. Due to this, the CPU
@@ -523,26 +499,56 @@
  * To work around this problem, we prevent switching directly from the
  * L2/L3 frequencies to the L0 frequency, and instead switch to the L1
  * frequency in-between. The sequence therefore becomes:
- * 1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
+ * 1. First switch from L2/L3 (200/250/300 MHz) to L1 (500/600 MHz)
  * 2. Sleep 20ms for stabling VDD voltage
- * 3. Then switch from L1(600MHZ) to L0(1200Mhz).
+ * 3. Then switch from L1 (500/600 MHz) to L0 (1000/1200 MHz).
  */
-static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base)
+static void clk_pm_cpu_set_rate_wa(struct clk_pm_cpu *pm_cpu,
+				   unsigned int new_level, unsigned long rate,
+				   struct regmap *base)
 {
 	unsigned int cur_level;
 
-	if (rate != 1200 * 1000 * 1000)
-		return;
-
 	regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level);
 	cur_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
-	if (cur_level <= ARMADA_37XX_DVFS_LOAD_1)
+
+	if (cur_level == new_level)
+		return;
+
+	/*
+	 * System wants to go to L1 on its own. If we are going from L2/L3,
+	 * remember when 20ms will expire. If from L0, set the value so that
+	 * next switch to L0 won't have to wait.
+	 */
+	if (new_level == ARMADA_37XX_DVFS_LOAD_1) {
+		if (cur_level == ARMADA_37XX_DVFS_LOAD_0)
+			pm_cpu->l1_expiration = jiffies;
+		else
+			pm_cpu->l1_expiration = jiffies + msecs_to_jiffies(20);
 		return;
+	}
+
+	/*
+	 * If we are setting to L2/L3, just invalidate L1 expiration time,
+	 * sleeping is not needed.
+	 */
+	if (rate < 1000*1000*1000)
+		goto invalidate_l1_exp;
+
+	/*
+	 * We are going to L0 with rate >= 1GHz. Check whether we have been at
+	 * L1 for long enough time. If not, go to L1 for 20ms.
+	 */
+	if (pm_cpu->l1_expiration && jiffies >= pm_cpu->l1_expiration)
+		goto invalidate_l1_exp;
 
 	regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD,
 			   ARMADA_37XX_NB_CPU_LOAD_MASK,
 			   ARMADA_37XX_DVFS_LOAD_1);
 	msleep(20);
+
+invalidate_l1_exp:
+	pm_cpu->l1_expiration = 0;
 }
 
 static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -576,7 +582,9 @@
 			reg = ARMADA_37XX_NB_CPU_LOAD;
 			mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
 
-			clk_pm_cpu_set_rate_wa(rate, base);
+			/* Apply workaround when base CPU frequency is 1000 or 1200 MHz */
+			if (parent_rate >= 1000*1000*1000)
+				clk_pm_cpu_set_rate_wa(pm_cpu, load_level, rate, base);
 
 			regmap_update_bits(base, reg, mask, load_level);
 
@@ -590,7 +598,6 @@
 
 static const struct clk_ops clk_pm_cpu_ops = {
 	.get_parent = clk_pm_cpu_get_parent,
-	.set_parent = clk_pm_cpu_set_parent,
 	.round_rate = clk_pm_cpu_round_rate,
 	.set_rate = clk_pm_cpu_set_rate,
 	.recalc_rate = clk_pm_cpu_recalc_rate,
--- linux-ein-5.4.0.orig/drivers/clk/mvebu/armada-37xx-xtal.c
+++ linux-ein-5.4.0/drivers/clk/mvebu/armada-37xx-xtal.c
@@ -13,8 +13,8 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
-#define NB_GPIO1_LATCH	0xC
-#define XTAL_MODE	    BIT(31)
+#define NB_GPIO1_LATCH	0x8
+#define XTAL_MODE	    BIT(9)
 
 static int armada_3700_xtal_clock_probe(struct platform_device *pdev)
 {
--- linux-ein-5.4.0.orig/drivers/clk/mvebu/kirkwood.c
+++ linux-ein-5.4.0/drivers/clk/mvebu/kirkwood.c
@@ -265,6 +265,7 @@
 static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
 	{ "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
 		11, 1, 0 },
+	{ }
 };
 
 static struct clk *clk_muxing_get_src(
--- linux-ein-5.4.0.orig/drivers/clk/pxa/clk-pxa27x.c
+++ linux-ein-5.4.0/drivers/clk/pxa/clk-pxa27x.c
@@ -459,6 +459,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-ein-5.4.0.orig/drivers/clk/qcom/a53-pll.c
+++ linux-ein-5.4.0/drivers/clk/qcom/a53-pll.c
@@ -93,6 +93,7 @@
 	{ .compatible = "qcom,msm8916-a53pll" },
 	{ }
 };
+MODULE_DEVICE_TABLE(of, qcom_a53pll_match_table);
 
 static struct platform_driver qcom_a53pll_driver = {
 	.probe = qcom_a53pll_probe,
--- linux-ein-5.4.0.orig/drivers/clk/qcom/camcc-sdm845.c
+++ linux-ein-5.4.0/drivers/clk/qcom/camcc-sdm845.c
@@ -1521,6 +1521,8 @@
 	},
 };
 
+static struct gdsc titan_top_gdsc;
+
 static struct gdsc bps_gdsc = {
 	.gdscr = 0x6004,
 	.pd = {
@@ -1554,6 +1556,7 @@
 		.name = "ife_0_gdsc",
 	},
 	.flags = POLL_CFG_GDSCR,
+	.parent = &titan_top_gdsc.pd,
 	.pwrsts = PWRSTS_OFF_ON,
 };
 
@@ -1563,6 +1566,7 @@
 		.name = "ife_1_gdsc",
 	},
 	.flags = POLL_CFG_GDSCR,
+	.parent = &titan_top_gdsc.pd,
 	.pwrsts = PWRSTS_OFF_ON,
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-alpha-pll.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-alpha-pll.c
@@ -55,7 +55,6 @@
 #define PLL_STATUS(p)		((p)->offset + (p)->regs[PLL_OFF_STATUS])
 #define PLL_OPMODE(p)		((p)->offset + (p)->regs[PLL_OFF_OPMODE])
 #define PLL_FRAC(p)		((p)->offset + (p)->regs[PLL_OFF_FRAC])
-#define PLL_CAL_VAL(p)		((p)->offset + (p)->regs[PLL_OFF_CAL_VAL])
 
 const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
 	[CLK_ALPHA_PLL_TYPE_DEFAULT] =  {
@@ -114,7 +113,6 @@
 		[PLL_OFF_STATUS] = 0x30,
 		[PLL_OFF_OPMODE] = 0x38,
 		[PLL_OFF_ALPHA_VAL] = 0x40,
-		[PLL_OFF_CAL_VAL] = 0x44,
 	},
 };
 EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-krait.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-krait.c
@@ -32,11 +32,16 @@
 		regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
 	}
 	krait_set_l2_indirect_reg(mux->offset, regval);
-	spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
 
 	/* Wait for switch to complete. */
 	mb();
 	udelay(1);
+
+	/*
+	 * Unlock now to make sure the mux register is not
+	 * modified while switching to the new parent.
+	 */
+	spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
 }
 
 static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
@@ -93,6 +98,8 @@
 
 	if (d->lpl)
 		mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
+	else
+		mask <<= d->shift;
 
 	spin_lock_irqsave(&krait_clock_reg_lock, flags);
 	val = krait_get_l2_indirect_reg(d->offset);
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-rcg2.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-rcg2.c
@@ -146,17 +146,11 @@
 static unsigned long
 calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
 {
-	if (hid_div) {
-		rate *= 2;
-		rate /= hid_div + 1;
-	}
+	if (hid_div)
+		rate = mult_frac(rate, 2, hid_div + 1);
 
-	if (mode) {
-		u64 tmp = rate;
-		tmp *= m;
-		do_div(tmp, n);
-		rate = tmp;
-	}
+	if (mode)
+		rate = mult_frac(rate, m, n);
 
 	return rate;
 }
@@ -217,9 +211,14 @@
 
 	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) {
 		rate = f->freq;
 		if (f->pre_div) {
+			if (!rate)
+				rate = req->rate;
 			rate /= 2;
 			rate *= f->pre_div + 1;
 		}
@@ -258,7 +257,7 @@
 
 static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
 {
-	u32 cfg, mask;
+	u32 cfg, mask, d_val, not2d_val, n_minus_m;
 	struct clk_hw *hw = &rcg->clkr.hw;
 	int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
 
@@ -277,8 +276,17 @@
 		if (ret)
 			return ret;
 
+		/* Calculate 2d value */
+		d_val = f->n;
+
+		n_minus_m = f->n - f->m;
+		n_minus_m *= 2;
+
+		d_val = clamp_t(u32, d_val, f->m, n_minus_m);
+		not2d_val = ~d_val & mask;
+
 		ret = regmap_update_bits(rcg->clkr.regmap,
-				RCG_D_OFFSET(rcg), mask, ~f->n);
+				RCG_D_OFFSET(rcg), mask, not2d_val);
 		if (ret)
 			return ret;
 	}
@@ -633,6 +641,7 @@
 	{ 2, 9 },
 	{ 4, 9 },
 	{ 1, 1 },
+	{ 2, 3 },
 	{ }
 };
 
@@ -950,7 +959,7 @@
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	struct clk_hw *p;
 	unsigned long prate = 0;
-	u32 val, mask, cfg, mode;
+	u32 val, mask, cfg, mode, src;
 	int i, num_parents;
 
 	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg);
@@ -960,12 +969,12 @@
 	if (cfg & mask)
 		f->pre_div = cfg & mask;
 
-	cfg &= CFG_SRC_SEL_MASK;
-	cfg >>= CFG_SRC_SEL_SHIFT;
+	src = cfg & CFG_SRC_SEL_MASK;
+	src >>= CFG_SRC_SEL_SHIFT;
 
 	num_parents = clk_hw_get_num_parents(hw);
 	for (i = 0; i < num_parents; i++) {
-		if (cfg == rcg->parent_map[i].cfg) {
+		if (src == rcg->parent_map[i].cfg) {
 			f->src = rcg->parent_map[i].src;
 			p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i);
 			prate = clk_hw_get_rate(p);
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-regmap-mux.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-regmap-mux.c
@@ -28,7 +28,7 @@
 	val &= mask;
 
 	if (mux->parent_map)
-		return qcom_find_src_index(hw, mux->parent_map, val);
+		return qcom_find_cfg_index(hw, mux->parent_map, val);
 
 	return val;
 }
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-rpmh.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-rpmh.c
@@ -143,12 +143,22 @@
 		!= (c->aggr_state & BIT(state));
 }
 
+static int clk_rpmh_send(struct clk_rpmh *c, enum rpmh_state state,
+			 struct tcs_cmd *cmd, bool wait)
+{
+	if (wait)
+		return rpmh_write(c->dev, state, cmd, 1);
+
+	return rpmh_write_async(c->dev, state, cmd, 1);
+}
+
 static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
 {
 	struct tcs_cmd cmd = { 0 };
 	u32 cmd_state, on_val;
 	enum rpmh_state state = RPMH_SLEEP_STATE;
 	int ret;
+	bool wait;
 
 	cmd.addr = c->res_addr;
 	cmd_state = c->aggr_state;
@@ -159,7 +169,8 @@
 			if (cmd_state & BIT(state))
 				cmd.data = on_val;
 
-			ret = rpmh_write_async(c->dev, state, &cmd, 1);
+			wait = cmd_state && state == RPMH_ACTIVE_ONLY_STATE;
+			ret = clk_rpmh_send(c, state, &cmd, wait);
 			if (ret) {
 				dev_err(c->dev, "set %s state of %s failed: (%d)\n",
 					!state ? "sleep" :
@@ -267,7 +278,7 @@
 	cmd.addr = c->res_addr;
 	cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state);
 
-	ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1);
+	ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable);
 	if (ret) {
 		dev_err(c->dev, "set active state of %s failed: (%d)\n",
 			c->res_name, ret);
--- linux-ein-5.4.0.orig/drivers/clk/qcom/clk-smd-rpm.c
+++ linux-ein-5.4.0/drivers/clk/qcom/clk-smd-rpm.c
@@ -648,6 +648,8 @@
 };
 
 /* msm8998 */
+DEFINE_CLK_SMD_RPM(msm8998, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
+DEFINE_CLK_SMD_RPM(msm8998, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 DEFINE_CLK_SMD_RPM(msm8998, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 DEFINE_CLK_SMD_RPM(msm8998, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
 DEFINE_CLK_SMD_RPM(msm8998, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
@@ -670,6 +672,10 @@
 DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6);
 DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6);
 static struct clk_smd_rpm *msm8998_clks[] = {
+	[RPM_SMD_BIMC_CLK] = &msm8998_bimc_clk,
+	[RPM_SMD_BIMC_A_CLK] = &msm8998_bimc_a_clk,
+	[RPM_SMD_PCNOC_CLK] = &msm8998_pcnoc_clk,
+	[RPM_SMD_PCNOC_A_CLK] = &msm8998_pcnoc_a_clk,
 	[RPM_SMD_SNOC_CLK] = &msm8998_snoc_clk,
 	[RPM_SMD_SNOC_A_CLK] = &msm8998_snoc_a_clk,
 	[RPM_SMD_CNOC_CLK] = &msm8998_cnoc_clk,
--- linux-ein-5.4.0.orig/drivers/clk/qcom/common.c
+++ linux-ein-5.4.0/drivers/clk/qcom/common.c
@@ -29,6 +29,9 @@
 	if (!f)
 		return NULL;
 
+	if (!f->freq)
+		return f;
+
 	for (; f->freq; f++)
 		if (rate <= f->freq)
 			return f;
@@ -66,6 +69,18 @@
 }
 EXPORT_SYMBOL_GPL(qcom_find_src_index);
 
+int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map, u8 cfg)
+{
+	int i, num_parents = clk_hw_get_num_parents(hw);
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == map[i].cfg)
+			return i;
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(qcom_find_cfg_index);
+
 struct regmap *
 qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc)
 {
--- linux-ein-5.4.0.orig/drivers/clk/qcom/common.h
+++ linux-ein-5.4.0/drivers/clk/qcom/common.h
@@ -49,6 +49,8 @@
 qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count);
 extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
 			       u8 src);
+extern int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map,
+			       u8 cfg);
 
 extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
 				      const char *name, unsigned long rate);
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-ipq8074.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-ipq8074.c
@@ -423,7 +423,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_fixed_factor_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -470,7 +469,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_alpha_pll_postdiv_ro_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -503,7 +501,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_alpha_pll_postdiv_ro_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -537,7 +534,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_alpha_pll_postdiv_ro_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -551,7 +547,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_fixed_factor_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -616,7 +611,6 @@
 		},
 		.num_parents = 1,
 		.ops = &clk_alpha_pll_postdiv_ro_ops,
-		.flags = CLK_SET_RATE_PARENT,
 	},
 };
 
@@ -667,6 +661,7 @@
 			},
 			.num_parents = 1,
 			.ops = &clk_branch2_ops,
+			.flags = CLK_IS_CRITICAL,
 		},
 	},
 };
@@ -1074,7 +1069,7 @@
 		.name = "sdcc1_apps_clk_src",
 		.parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2,
 		.num_parents = 4,
-		.ops = &clk_rcg2_ops,
+		.ops = &clk_rcg2_floor_ops,
 	},
 };
 
@@ -1788,8 +1783,10 @@
 static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
+	F(25000000, P_UNIPHY0_RX, 5, 0, 0),
 	F(78125000, P_UNIPHY1_RX, 4, 0, 0),
 	F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
+	F(125000000, P_UNIPHY0_RX, 1, 0, 0),
 	F(156250000, P_UNIPHY1_RX, 2, 0, 0),
 	F(312500000, P_UNIPHY1_RX, 1, 0, 0),
 	{ }
@@ -1828,8 +1825,10 @@
 static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
+	F(25000000, P_UNIPHY0_TX, 5, 0, 0),
 	F(78125000, P_UNIPHY1_TX, 4, 0, 0),
 	F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
+	F(125000000, P_UNIPHY0_TX, 1, 0, 0),
 	F(156250000, P_UNIPHY1_TX, 2, 0, 0),
 	F(312500000, P_UNIPHY1_TX, 1, 0, 0),
 	{ }
@@ -1867,8 +1866,10 @@
 
 static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
 	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_UNIPHY2_RX, 5, 0, 0),
 	F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
 	F(78125000, P_UNIPHY2_RX, 4, 0, 0),
+	F(125000000, P_UNIPHY2_RX, 1, 0, 0),
 	F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
 	F(156250000, P_UNIPHY2_RX, 2, 0, 0),
 	F(312500000, P_UNIPHY2_RX, 1, 0, 0),
@@ -1907,8 +1908,10 @@
 
 static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
 	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_UNIPHY2_TX, 5, 0, 0),
 	F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
 	F(78125000, P_UNIPHY2_TX, 4, 0, 0),
+	F(125000000, P_UNIPHY2_TX, 1, 0, 0),
 	F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
 	F(156250000, P_UNIPHY2_TX, 2, 0, 0),
 	F(312500000, P_UNIPHY2_TX, 1, 0, 0),
@@ -3346,6 +3349,7 @@
 
 static struct clk_branch gcc_ubi0_ahb_clk = {
 	.halt_reg = 0x6820c,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x6820c,
 		.enable_mask = BIT(0),
@@ -3363,6 +3367,7 @@
 
 static struct clk_branch gcc_ubi0_axi_clk = {
 	.halt_reg = 0x68200,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68200,
 		.enable_mask = BIT(0),
@@ -3380,6 +3385,7 @@
 
 static struct clk_branch gcc_ubi0_nc_axi_clk = {
 	.halt_reg = 0x68204,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68204,
 		.enable_mask = BIT(0),
@@ -3397,6 +3403,7 @@
 
 static struct clk_branch gcc_ubi0_core_clk = {
 	.halt_reg = 0x68210,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68210,
 		.enable_mask = BIT(0),
@@ -3414,6 +3421,7 @@
 
 static struct clk_branch gcc_ubi0_mpt_clk = {
 	.halt_reg = 0x68208,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68208,
 		.enable_mask = BIT(0),
@@ -3431,6 +3439,7 @@
 
 static struct clk_branch gcc_ubi1_ahb_clk = {
 	.halt_reg = 0x6822c,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x6822c,
 		.enable_mask = BIT(0),
@@ -3448,6 +3457,7 @@
 
 static struct clk_branch gcc_ubi1_axi_clk = {
 	.halt_reg = 0x68220,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68220,
 		.enable_mask = BIT(0),
@@ -3465,6 +3475,7 @@
 
 static struct clk_branch gcc_ubi1_nc_axi_clk = {
 	.halt_reg = 0x68224,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68224,
 		.enable_mask = BIT(0),
@@ -3482,6 +3493,7 @@
 
 static struct clk_branch gcc_ubi1_core_clk = {
 	.halt_reg = 0x68230,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68230,
 		.enable_mask = BIT(0),
@@ -3499,6 +3511,7 @@
 
 static struct clk_branch gcc_ubi1_mpt_clk = {
 	.halt_reg = 0x68228,
+	.halt_check = BRANCH_HALT_DELAY,
 	.clkr = {
 		.enable_reg = 0x68228,
 		.enable_mask = BIT(0),
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-mdm9615.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-mdm9615.c
@@ -58,7 +58,7 @@
 	.enable_mask = BIT(0),
 	.hw.init = &(struct clk_init_data){
 		.name = "pll0_vote",
-		.parent_names = (const char *[]){ "pll8" },
+		.parent_names = (const char *[]){ "pll0" },
 		.num_parents = 1,
 		.ops = &clk_pll_vote_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-msm8916.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-msm8916.c
@@ -260,7 +260,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,
@@ -287,7 +287,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,
@@ -314,7 +314,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,
@@ -341,7 +341,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,
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-msm8994.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-msm8994.c
@@ -107,6 +107,7 @@
 
 static struct clk_alpha_pll_postdiv gpll4 = {
 	.offset = 0x1dc0,
+	.width = 4,
 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
 	.clkr.hw.init = &(struct clk_init_data)
 	{
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-msm8996.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-msm8996.c
@@ -2937,20 +2937,6 @@
 	},
 };
 
-static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
-	.halt_reg = 0x82014,
-	.clkr = {
-		.enable_reg = 0x82014,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_aggre1_pnoc_ahb_clk",
-			.parent_names = (const char *[]){ "periph_noc_clk_src" },
-			.num_parents = 1,
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_aggre2_ufs_axi_clk = {
 	.halt_reg = 0x83014,
 	.clkr = {
@@ -3453,7 +3439,6 @@
 	[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
 	[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
 	[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
-	[GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
 	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
 	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
 	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-msm8998.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-msm8998.c
@@ -135,7 +135,7 @@
 
 static struct clk_alpha_pll gpll0 = {
 	.offset = 0x0,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.vco_table = fabia_vco,
 	.num_vco = ARRAY_SIZE(fabia_vco),
 	.clkr = {
@@ -145,58 +145,58 @@
 			.name = "gpll0",
 			.parent_names = (const char *[]){ "xo" },
 			.num_parents = 1,
-			.ops = &clk_alpha_pll_ops,
+			.ops = &clk_alpha_pll_fixed_fabia_ops,
 		}
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll0_out_even = {
 	.offset = 0x0,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll0_out_even",
 		.parent_names = (const char *[]){ "gpll0" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll0_out_main = {
 	.offset = 0x0,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll0_out_main",
 		.parent_names = (const char *[]){ "gpll0" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll0_out_odd = {
 	.offset = 0x0,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll0_out_odd",
 		.parent_names = (const char *[]){ "gpll0" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll0_out_test = {
 	.offset = 0x0,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll0_out_test",
 		.parent_names = (const char *[]){ "gpll0" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll gpll1 = {
 	.offset = 0x1000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.vco_table = fabia_vco,
 	.num_vco = ARRAY_SIZE(fabia_vco),
 	.clkr = {
@@ -206,58 +206,58 @@
 			.name = "gpll1",
 			.parent_names = (const char *[]){ "xo" },
 			.num_parents = 1,
-			.ops = &clk_alpha_pll_ops,
+			.ops = &clk_alpha_pll_fixed_fabia_ops,
 		}
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll1_out_even = {
 	.offset = 0x1000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll1_out_even",
 		.parent_names = (const char *[]){ "gpll1" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll1_out_main = {
 	.offset = 0x1000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll1_out_main",
 		.parent_names = (const char *[]){ "gpll1" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll1_out_odd = {
 	.offset = 0x1000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll1_out_odd",
 		.parent_names = (const char *[]){ "gpll1" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll1_out_test = {
 	.offset = 0x1000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll1_out_test",
 		.parent_names = (const char *[]){ "gpll1" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll gpll2 = {
 	.offset = 0x2000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.vco_table = fabia_vco,
 	.num_vco = ARRAY_SIZE(fabia_vco),
 	.clkr = {
@@ -267,58 +267,58 @@
 			.name = "gpll2",
 			.parent_names = (const char *[]){ "xo" },
 			.num_parents = 1,
-			.ops = &clk_alpha_pll_ops,
+			.ops = &clk_alpha_pll_fixed_fabia_ops,
 		}
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll2_out_even = {
 	.offset = 0x2000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll2_out_even",
 		.parent_names = (const char *[]){ "gpll2" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll2_out_main = {
 	.offset = 0x2000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll2_out_main",
 		.parent_names = (const char *[]){ "gpll2" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll2_out_odd = {
 	.offset = 0x2000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll2_out_odd",
 		.parent_names = (const char *[]){ "gpll2" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll2_out_test = {
 	.offset = 0x2000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll2_out_test",
 		.parent_names = (const char *[]){ "gpll2" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll gpll3 = {
 	.offset = 0x3000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.vco_table = fabia_vco,
 	.num_vco = ARRAY_SIZE(fabia_vco),
 	.clkr = {
@@ -328,58 +328,58 @@
 			.name = "gpll3",
 			.parent_names = (const char *[]){ "xo" },
 			.num_parents = 1,
-			.ops = &clk_alpha_pll_ops,
+			.ops = &clk_alpha_pll_fixed_fabia_ops,
 		}
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll3_out_even = {
 	.offset = 0x3000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll3_out_even",
 		.parent_names = (const char *[]){ "gpll3" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll3_out_main = {
 	.offset = 0x3000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll3_out_main",
 		.parent_names = (const char *[]){ "gpll3" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll3_out_odd = {
 	.offset = 0x3000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll3_out_odd",
 		.parent_names = (const char *[]){ "gpll3" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll3_out_test = {
 	.offset = 0x3000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll3_out_test",
 		.parent_names = (const char *[]){ "gpll3" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll gpll4 = {
 	.offset = 0x77000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.vco_table = fabia_vco,
 	.num_vco = ARRAY_SIZE(fabia_vco),
 	.clkr = {
@@ -389,52 +389,52 @@
 			.name = "gpll4",
 			.parent_names = (const char *[]){ "xo" },
 			.num_parents = 1,
-			.ops = &clk_alpha_pll_ops,
+			.ops = &clk_alpha_pll_fixed_fabia_ops,
 		}
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll4_out_even = {
 	.offset = 0x77000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll4_out_even",
 		.parent_names = (const char *[]){ "gpll4" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll4_out_main = {
 	.offset = 0x77000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll4_out_main",
 		.parent_names = (const char *[]){ "gpll4" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll4_out_odd = {
 	.offset = 0x77000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll4_out_odd",
 		.parent_names = (const char *[]){ "gpll4" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
 static struct clk_alpha_pll_postdiv gpll4_out_test = {
 	.offset = 0x77000,
-	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll4_out_test",
 		.parent_names = (const char *[]){ "gpll4" },
 		.num_parents = 1,
-		.ops = &clk_alpha_pll_postdiv_ops,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-qcs404.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-qcs404.c
@@ -25,11 +25,9 @@
 	P_CORE_BI_PLL_TEST_SE,
 	P_DSI0_PHY_PLL_OUT_BYTECLK,
 	P_DSI0_PHY_PLL_OUT_DSICLK,
-	P_GPLL0_OUT_AUX,
 	P_GPLL0_OUT_MAIN,
 	P_GPLL1_OUT_MAIN,
 	P_GPLL3_OUT_MAIN,
-	P_GPLL4_OUT_AUX,
 	P_GPLL4_OUT_MAIN,
 	P_GPLL6_OUT_AUX,
 	P_HDMI_PHY_PLL_CLK,
@@ -109,28 +107,24 @@
 static const struct parent_map gcc_parent_map_5[] = {
 	{ P_XO, 0 },
 	{ P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
-	{ P_GPLL0_OUT_AUX, 2 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_5[] = {
 	"cxo",
-	"dsi0pll_byteclk_src",
-	"gpll0_out_aux",
+	"dsi0pllbyte",
 	"core_bi_pll_test_se",
 };
 
 static const struct parent_map gcc_parent_map_6[] = {
 	{ P_XO, 0 },
 	{ P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
-	{ P_GPLL0_OUT_AUX, 3 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_6[] = {
 	"cxo",
-	"dsi0_phy_pll_out_byteclk",
-	"gpll0_out_aux",
+	"dsi0pllbyte",
 	"core_bi_pll_test_se",
 };
 
@@ -139,7 +133,6 @@
 	{ P_GPLL0_OUT_MAIN, 1 },
 	{ P_GPLL3_OUT_MAIN, 2 },
 	{ P_GPLL6_OUT_AUX, 3 },
-	{ P_GPLL4_OUT_AUX, 4 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
@@ -148,7 +141,6 @@
 	"gpll0_out_main",
 	"gpll3_out_main",
 	"gpll6_out_aux",
-	"gpll4_out_aux",
 	"core_bi_pll_test_se",
 };
 
@@ -175,7 +167,7 @@
 static const char * const gcc_parent_names_9[] = {
 	"cxo",
 	"gpll0_out_main",
-	"dsi0_phy_pll_out_dsiclk",
+	"dsi0pll",
 	"gpll6_out_aux",
 	"core_bi_pll_test_se",
 };
@@ -207,14 +199,12 @@
 static const struct parent_map gcc_parent_map_12[] = {
 	{ P_XO, 0 },
 	{ P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
-	{ P_GPLL0_OUT_AUX, 2 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_12[] = {
 	"cxo",
-	"dsi0pll_pclk_src",
-	"gpll0_out_aux",
+	"dsi0pll",
 	"core_bi_pll_test_se",
 };
 
@@ -237,40 +227,34 @@
 static const struct parent_map gcc_parent_map_14[] = {
 	{ P_XO, 0 },
 	{ P_GPLL0_OUT_MAIN, 1 },
-	{ P_GPLL4_OUT_AUX, 2 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_14[] = {
 	"cxo",
 	"gpll0_out_main",
-	"gpll4_out_aux",
 	"core_bi_pll_test_se",
 };
 
 static const struct parent_map gcc_parent_map_15[] = {
 	{ P_XO, 0 },
-	{ P_GPLL0_OUT_AUX, 2 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_15[] = {
 	"cxo",
-	"gpll0_out_aux",
 	"core_bi_pll_test_se",
 };
 
 static const struct parent_map gcc_parent_map_16[] = {
 	{ P_XO, 0 },
 	{ P_GPLL0_OUT_MAIN, 1 },
-	{ P_GPLL0_OUT_AUX, 2 },
 	{ P_CORE_BI_PLL_TEST_SE, 7 },
 };
 
 static const char * const gcc_parent_names_16[] = {
 	"cxo",
 	"gpll0_out_main",
-	"gpll0_out_aux",
 	"core_bi_pll_test_se",
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-sdm660.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-sdm660.c
@@ -666,7 +666,7 @@
 	.cmd_rcgr = 0x48044,
 	.mnd_width = 0,
 	.hid_width = 5,
-	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.parent_map = gcc_parent_map_xo_gpll0,
 	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "hmss_rbcpr_clk_src",
@@ -1715,6 +1715,9 @@
 
 static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
 	.halt_reg = 0x8a004,
+	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x8a004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x8a004,
 		.enable_mask = BIT(0),
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-sdm845.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-sdm845.c
@@ -3255,6 +3255,7 @@
 		.name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc = {
@@ -3263,6 +3264,7 @@
 		.name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_aggre_noc_mmu_tbu1_gdsc = {
@@ -3271,6 +3273,7 @@
 		.name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_aggre_noc_mmu_tbu2_gdsc = {
@@ -3279,6 +3282,7 @@
 		.name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = {
@@ -3287,6 +3291,7 @@
 		.name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = {
@@ -3295,6 +3300,7 @@
 		.name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = {
@@ -3303,6 +3309,7 @@
 		.name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc",
 	},
 	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
 };
 
 static struct clk_regmap *gcc_sdm845_clocks[] = {
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gcc-sm8150.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gcc-sm8150.c
@@ -75,8 +75,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpll0_out_even",
 		.parent_data = &(const struct clk_parent_data){
-			.fw_name = "bi_tcxo",
-			.name = "bi_tcxo",
+			.hw = &gpll0.clkr.hw,
 		},
 		.num_parents = 1,
 		.ops = &clk_trion_pll_postdiv_ops,
@@ -251,7 +250,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_cpuss_ahb_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -274,7 +273,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_emac_ptp_clk_src",
 		.parent_data = gcc_parents_5,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_5),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -300,7 +299,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_emac_rgmii_clk_src",
 		.parent_data = gcc_parents_5,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_5),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -324,7 +323,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_gp1_clk_src",
 		.parent_data = gcc_parents_1,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_1),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -339,7 +338,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_gp2_clk_src",
 		.parent_data = gcc_parents_1,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_1),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -354,7 +353,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_gp3_clk_src",
 		.parent_data = gcc_parents_1,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_1),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -375,7 +374,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_pcie_0_aux_clk_src",
 		.parent_data = gcc_parents_2,
-		.num_parents = 3,
+		.num_parents = ARRAY_SIZE(gcc_parents_2),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -390,7 +389,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_pcie_1_aux_clk_src",
 		.parent_data = gcc_parents_2,
-		.num_parents = 3,
+		.num_parents = ARRAY_SIZE(gcc_parents_2),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -411,7 +410,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_pcie_phy_refgen_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -433,7 +432,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_pdm2_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -456,7 +455,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qspi_core_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -490,7 +489,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s0_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -505,7 +504,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s1_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -520,7 +519,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s2_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -535,7 +534,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s3_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -550,7 +549,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s4_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -565,7 +564,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s5_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -580,7 +579,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s6_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -595,7 +594,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap0_s7_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -610,7 +609,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s0_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -625,7 +624,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s1_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -640,7 +639,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s2_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -655,7 +654,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s3_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -670,7 +669,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s4_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -685,7 +684,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap1_s5_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -700,7 +699,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s0_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -715,7 +714,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s1_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -730,7 +729,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s2_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -745,7 +744,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s3_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -760,7 +759,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s4_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -775,7 +774,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_qupv3_wrap2_s5_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -801,8 +800,8 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_sdcc2_apps_clk_src",
 		.parent_data = gcc_parents_6,
-		.num_parents = 5,
-		.flags = CLK_SET_RATE_PARENT,
+		.num_parents = ARRAY_SIZE(gcc_parents_6),
+		.flags = CLK_OPS_PARENT_ENABLE,
 		.ops = &clk_rcg2_floor_ops,
 	},
 };
@@ -826,7 +825,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_sdcc4_apps_clk_src",
 		.parent_data = gcc_parents_3,
-		.num_parents = 3,
+		.num_parents = ARRAY_SIZE(gcc_parents_3),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_floor_ops,
 	},
@@ -846,7 +845,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_tsif_ref_clk_src",
 		.parent_data = gcc_parents_7,
-		.num_parents = 5,
+		.num_parents = ARRAY_SIZE(gcc_parents_7),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -870,7 +869,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_axi_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -893,7 +892,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_ice_core_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -913,7 +912,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_phy_aux_clk_src",
 		.parent_data = gcc_parents_4,
-		.num_parents = 2,
+		.num_parents = ARRAY_SIZE(gcc_parents_4),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -935,7 +934,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_card_unipro_core_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -959,7 +958,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_phy_axi_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -974,7 +973,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_phy_ice_core_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -989,7 +988,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_phy_phy_aux_clk_src",
 		.parent_data = gcc_parents_4,
-		.num_parents = 2,
+		.num_parents = ARRAY_SIZE(gcc_parents_4),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1004,7 +1003,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_ufs_phy_unipro_core_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1028,7 +1027,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb30_prim_master_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1050,7 +1049,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb30_prim_mock_utmi_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1065,7 +1064,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb30_sec_master_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1080,7 +1079,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb30_sec_mock_utmi_clk_src",
 		.parent_data = gcc_parents_0,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gcc_parents_0),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1095,7 +1094,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb3_prim_phy_aux_clk_src",
 		.parent_data = gcc_parents_2,
-		.num_parents = 3,
+		.num_parents = ARRAY_SIZE(gcc_parents_2),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1110,7 +1109,7 @@
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_usb3_sec_phy_aux_clk_src",
 		.parent_data = gcc_parents_2,
-		.num_parents = 3,
+		.num_parents = ARRAY_SIZE(gcc_parents_2),
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 	},
@@ -1616,6 +1615,38 @@
 	},
 };
 
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(15),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_clk_src",
+			.parent_hws = (const struct clk_hw *[]){
+				&gpll0.clkr.hw },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(16),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_div_clk_src",
+			.parent_hws = (const struct clk_hw *[]){
+				&gpll0_out_even.clkr.hw },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_gpu_iref_clk = {
 	.halt_reg = 0x8c010,
 	.halt_check = BRANCH_HALT,
@@ -1698,6 +1729,38 @@
 	},
 };
 
+static struct clk_branch gcc_npu_gpll0_clk_src = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(18),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_npu_gpll0_clk_src",
+			.parent_hws = (const struct clk_hw *[]){
+				&gpll0.clkr.hw },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_npu_gpll0_div_clk_src = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(19),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_npu_gpll0_div_clk_src",
+			.parent_hws = (const struct clk_hw *[]){
+				&gpll0_out_even.clkr.hw },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_npu_trig_clk = {
 	.halt_reg = 0x4d00c,
 	.halt_check = BRANCH_VOTED,
@@ -2812,6 +2875,45 @@
 	},
 };
 
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_card_rx_symbol_0_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x7501c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_card_rx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_card_rx_symbol_1_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x750ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_card_rx_symbol_1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_card_tx_symbol_0_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_card_tx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_ufs_card_unipro_core_clk = {
 	.halt_reg = 0x75058,
 	.halt_check = BRANCH_HALT,
@@ -2992,6 +3094,45 @@
 	},
 };
 
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x7701c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_rx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x770ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_rx_symbol_1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+/* external clocks so add BRANCH_HALT_SKIP */
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x77018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_tx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
 	.halt_reg = 0x77058,
 	.halt_check = BRANCH_HALT,
@@ -3332,12 +3473,16 @@
 	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
 	[GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
 	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+	[GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+	[GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
 	[GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr,
 	[GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
 	[GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
 	[GCC_NPU_AT_CLK] = &gcc_npu_at_clk.clkr,
 	[GCC_NPU_AXI_CLK] = &gcc_npu_axi_clk.clkr,
 	[GCC_NPU_CFG_AHB_CLK] = &gcc_npu_cfg_ahb_clk.clkr,
+	[GCC_NPU_GPLL0_CLK_SRC] = &gcc_npu_gpll0_clk_src.clkr,
+	[GCC_NPU_GPLL0_DIV_CLK_SRC] = &gcc_npu_gpll0_div_clk_src.clkr,
 	[GCC_NPU_TRIG_CLK] = &gcc_npu_trig_clk.clkr,
 	[GCC_PCIE0_PHY_REFGEN_CLK] = &gcc_pcie0_phy_refgen_clk.clkr,
 	[GCC_PCIE1_PHY_REFGEN_CLK] = &gcc_pcie1_phy_refgen_clk.clkr,
@@ -3442,6 +3587,9 @@
 	[GCC_UFS_CARD_PHY_AUX_CLK_SRC] = &gcc_ufs_card_phy_aux_clk_src.clkr,
 	[GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] =
 		&gcc_ufs_card_phy_aux_hw_ctl_clk.clkr,
+	[GCC_UFS_CARD_RX_SYMBOL_0_CLK] = &gcc_ufs_card_rx_symbol_0_clk.clkr,
+	[GCC_UFS_CARD_RX_SYMBOL_1_CLK] = &gcc_ufs_card_rx_symbol_1_clk.clkr,
+	[GCC_UFS_CARD_TX_SYMBOL_0_CLK] = &gcc_ufs_card_tx_symbol_0_clk.clkr,
 	[GCC_UFS_CARD_UNIPRO_CORE_CLK] = &gcc_ufs_card_unipro_core_clk.clkr,
 	[GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] =
 		&gcc_ufs_card_unipro_core_clk_src.clkr,
@@ -3459,6 +3607,9 @@
 	[GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
 	[GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
 	[GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr,
+	[GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+	[GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr,
+	[GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
 	[GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
 	[GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] =
 		&gcc_ufs_phy_unipro_core_clk_src.clkr,
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gdsc.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gdsc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/bitops.h>
@@ -31,9 +31,14 @@
 #define CFG_GDSCR_OFFSET		0x4
 
 /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL	(0x2 << 20)
-#define EN_FEW_WAIT_VAL		(0x8 << 16)
-#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+#define EN_REST_WAIT_VAL	0x2
+#define EN_FEW_WAIT_VAL		0x8
+#define CLK_DIS_WAIT_VAL	0x2
+
+/* Transition delay shifts */
+#define EN_REST_WAIT_SHIFT	20
+#define EN_FEW_WAIT_SHIFT	16
+#define CLK_DIS_WAIT_SHIFT	12
 
 #define RETAIN_MEM		BIT(14)
 #define RETAIN_PERIPH		BIT(13)
@@ -308,7 +313,18 @@
 	 */
 	mask = HW_CONTROL_MASK | SW_OVERRIDE_MASK |
 	       EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK;
-	val = EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+
+	if (!sc->en_rest_wait_val)
+		sc->en_rest_wait_val = EN_REST_WAIT_VAL;
+	if (!sc->en_few_wait_val)
+		sc->en_few_wait_val = EN_FEW_WAIT_VAL;
+	if (!sc->clk_dis_wait_val)
+		sc->clk_dis_wait_val = CLK_DIS_WAIT_VAL;
+
+	val = sc->en_rest_wait_val << EN_REST_WAIT_SHIFT |
+		sc->en_few_wait_val << EN_FEW_WAIT_SHIFT |
+		sc->clk_dis_wait_val << CLK_DIS_WAIT_SHIFT;
+
 	ret = regmap_update_bits(sc->regmap, sc->gdscr, mask, val);
 	if (ret)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gdsc.h
+++ linux-ein-5.4.0/drivers/clk/qcom/gdsc.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __QCOM_GDSC_H__
@@ -21,6 +21,9 @@
  * @cxcs: offsets of branch registers to toggle mem/periph bits in
  * @cxc_count: number of @cxcs
  * @pwrsts: Possible powerdomain power states
+ * @en_rest_wait_val: transition delay value for receiving enr ack signal
+ * @en_few_wait_val: transition delay value for receiving enf ack signal
+ * @clk_dis_wait_val: transition delay value for halting clock
  * @resets: ids of resets associated with this gdsc
  * @reset_count: number of @resets
  * @rcdev: reset controller
@@ -34,6 +37,9 @@
 	unsigned int			clamp_io_ctrl;
 	unsigned int			*cxcs;
 	unsigned int			cxc_count;
+	unsigned int			en_rest_wait_val;
+	unsigned int			en_few_wait_val;
+	unsigned int			clk_dis_wait_val;
 	const u8			pwrsts;
 /* Powerdomain allowable state bitfields */
 #define PWRSTS_OFF		BIT(0)
--- linux-ein-5.4.0.orig/drivers/clk/qcom/gpucc-sdm845.c
+++ linux-ein-5.4.0/drivers/clk/qcom/gpucc-sdm845.c
@@ -22,8 +22,6 @@
 #define CX_GMU_CBCR_SLEEP_SHIFT		4
 #define CX_GMU_CBCR_WAKE_MASK		0xf
 #define CX_GMU_CBCR_WAKE_SHIFT		8
-#define CLK_DIS_WAIT_SHIFT		12
-#define CLK_DIS_WAIT_MASK		(0xf << CLK_DIS_WAIT_SHIFT)
 
 enum {
 	P_BI_TCXO,
@@ -124,6 +122,7 @@
 static struct gdsc gpu_cx_gdsc = {
 	.gdscr = 0x106c,
 	.gds_hw_ctrl = 0x1540,
+	.clk_dis_wait_val = 0x8,
 	.pd = {
 		.name = "gpu_cx_gdsc",
 	},
@@ -221,10 +220,6 @@
 	value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT;
 	regmap_update_bits(regmap, 0x1098, mask, value);
 
-	/* Configure clk_dis_wait for gpu_cx_gdsc */
-	regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK,
-						8 << CLK_DIS_WAIT_SHIFT);
-
 	return qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
 }
 
--- linux-ein-5.4.0.orig/drivers/clk/renesas/r7s9210-cpg-mssr.c
+++ linux-ein-5.4.0/drivers/clk/renesas/r7s9210-cpg-mssr.c
@@ -213,7 +213,7 @@
 	.cpg_clk_register = rza2_cpg_clk_register,
 
 	/* RZ/A2 has Standby Control Registers */
-	.stbyctrl = true,
+	.reg_layout = CLK_REG_LAYOUT_RZ_A,
 };
 
 static void __init r7s9210_cpg_mssr_early_init(struct device_node *np)
--- linux-ein-5.4.0.orig/drivers/clk/renesas/r8a77995-cpg-mssr.c
+++ linux-ein-5.4.0/drivers/clk/renesas/r8a77995-cpg-mssr.c
@@ -75,6 +75,7 @@
 	DEF_RATE(".oco",       CLK_OCO,            8 * 1000 * 1000),
 
 	/* Core Clock Outputs */
+	DEF_FIXED("za2",       R8A77995_CLK_ZA2,   CLK_PLL0D3,     2, 1),
 	DEF_FIXED("z2",        R8A77995_CLK_Z2,    CLK_PLL0D3,     1, 1),
 	DEF_FIXED("ztr",       R8A77995_CLK_ZTR,   CLK_PLL1,       6, 1),
 	DEF_FIXED("zt",        R8A77995_CLK_ZT,    CLK_PLL1,       4, 1),
--- linux-ein-5.4.0.orig/drivers/clk/renesas/r9a06g032-clocks.c
+++ linux-ein-5.4.0/drivers/clk/renesas/r9a06g032-clocks.c
@@ -55,7 +55,7 @@
 			u16 sel, g1, r1, g2, r2;
 		} dual;
 	};
-} __packed;
+};
 
 #define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \
 	{ .gate = _clk, .reset = _rst, \
@@ -286,8 +286,8 @@
 		.name = "uart_group_012",
 		.type = K_BITSEL,
 		.source = 1 + R9A06G032_DIV_UART,
-		/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */
-		.dual.sel = ((0xec / 4) << 5) | 24,
+		/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */
+		.dual.sel = ((0x34 / 4) << 5) | 30,
 		.dual.group = 0,
 	},
 	{
@@ -295,8 +295,8 @@
 		.name = "uart_group_34567",
 		.type = K_BITSEL,
 		.source = 1 + R9A06G032_DIV_P2_PG,
-		/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */
-		.dual.sel = ((0x34 / 4) << 5) | 30,
+		/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */
+		.dual.sel = ((0xec / 4) << 5) | 24,
 		.dual.group = 1,
 	},
 	D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5),
@@ -386,7 +386,7 @@
 	int error;
 	int index;
 
-	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i++,
 					   &clkspec)) {
 		if (clkspec.np != pd->dev.of_node)
 			continue;
@@ -399,7 +399,6 @@
 			if (error)
 				return error;
 		}
-		i++;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/clk/renesas/rcar-gen3-cpg.c
+++ linux-ein-5.4.0/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -464,7 +464,8 @@
 
 	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
 				     &rpc->div.hw,  &clk_divider_ops,
-				     &rpc->gate.hw, &clk_gate_ops, 0);
+				     &rpc->gate.hw, &clk_gate_ops,
+				     CLK_SET_RATE_PARENT);
 	if (IS_ERR(clk)) {
 		kfree(rpc);
 		return clk;
@@ -500,7 +501,8 @@
 
 	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
 				     &rpcd2->fixed.hw, &clk_fixed_factor_ops,
-				     &rpcd2->gate.hw, &clk_gate_ops, 0);
+				     &rpcd2->gate.hw, &clk_gate_ops,
+				     CLK_SET_RATE_PARENT);
 	if (IS_ERR(clk))
 		kfree(rpcd2);
 
--- linux-ein-5.4.0.orig/drivers/clk/renesas/renesas-cpg-mssr.c
+++ linux-ein-5.4.0/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -111,12 +111,12 @@
  * @rcdev: Optional reset controller entity
  * @dev: CPG/MSSR device
  * @base: CPG/MSSR register block base address
+ * @reg_layout: CPG/MSSR register layout
  * @rmw_lock: protects RMW register accesses
  * @np: Device node in DT for this CPG/MSSR module
  * @num_core_clks: Number of Core Clocks in clks[]
  * @num_mod_clks: Number of Module Clocks in clks[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
- * @stbyctrl: This device has Standby Control Registers
  * @notifiers: Notifier chain to save/restore clock state for system resume
  * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
  * @smstpcr_saved[].val: Saved values of SMSTPCR[]
@@ -128,13 +128,13 @@
 #endif
 	struct device *dev;
 	void __iomem *base;
+	enum clk_reg_layout reg_layout;
 	spinlock_t rmw_lock;
 	struct device_node *np;
 
 	unsigned int num_core_clks;
 	unsigned int num_mod_clks;
 	unsigned int last_dt_core_clk;
-	bool stbyctrl;
 
 	struct raw_notifier_head notifiers;
 	struct {
@@ -177,7 +177,7 @@
 		enable ? "ON" : "OFF");
 	spin_lock_irqsave(&priv->rmw_lock, flags);
 
-	if (priv->stbyctrl) {
+	if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
 		value = readb(priv->base + STBCR(reg));
 		if (enable)
 			value &= ~bitmask;
@@ -199,7 +199,7 @@
 
 	spin_unlock_irqrestore(&priv->rmw_lock, flags);
 
-	if (!enable || priv->stbyctrl)
+	if (!enable || priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
 		return 0;
 
 	for (i = 1000; i > 0; --i) {
@@ -233,7 +233,7 @@
 	struct cpg_mssr_priv *priv = clock->priv;
 	u32 value;
 
-	if (priv->stbyctrl)
+	if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
 		value = readb(priv->base + STBCR(clock->index / 32));
 	else
 		value = readl(priv->base + MSTPSR(clock->index / 32));
@@ -272,7 +272,7 @@
 
 	case CPG_MOD:
 		type = "module";
-		if (priv->stbyctrl) {
+		if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
 			idx = MOD_CLK_PACK_10(clkidx);
 			range_check = 7 - (clkidx % 10);
 		} else {
@@ -801,6 +801,8 @@
 	for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
 		if (priv->smstpcr_saved[reg].mask)
 			priv->smstpcr_saved[reg].val =
+				priv->reg_layout == CLK_REG_LAYOUT_RZ_A ?
+				readb(priv->base + STBCR(reg)) :
 				readl(priv->base + SMSTPCR(reg));
 	}
 
@@ -829,7 +831,7 @@
 		if (!mask)
 			continue;
 
-		if (priv->stbyctrl)
+		if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
 			oldval = readb(priv->base + STBCR(reg));
 		else
 			oldval = readl(priv->base + SMSTPCR(reg));
@@ -838,7 +840,7 @@
 		if (newval == oldval)
 			continue;
 
-		if (priv->stbyctrl) {
+		if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
 			writeb(newval, priv->base + STBCR(reg));
 			/* dummy read to ensure write has completed */
 			readb(priv->base + STBCR(reg));
@@ -860,8 +862,8 @@
 		}
 
 		if (!i)
-			dev_warn(dev, "Failed to enable SMSTP %p[0x%x]\n",
-				 priv->base + SMSTPCR(reg), oldval & mask);
+			dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
+				 oldval & mask);
 	}
 
 	return 0;
@@ -905,12 +907,11 @@
 		goto out_err;
 	}
 
-	cpg_mssr_priv = priv;
 	priv->num_core_clks = info->num_total_core_clks;
 	priv->num_mod_clks = info->num_hw_mod_clks;
 	priv->last_dt_core_clk = info->last_dt_core_clk;
 	RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
-	priv->stbyctrl = info->stbyctrl;
+	priv->reg_layout = info->reg_layout;
 
 	for (i = 0; i < nclks; i++)
 		priv->clks[i] = ERR_PTR(-ENOENT);
@@ -919,6 +920,8 @@
 	if (error)
 		goto out_err;
 
+	cpg_mssr_priv = priv;
+
 	return 0;
 
 out_err:
@@ -988,7 +991,7 @@
 		return error;
 
 	/* Reset Controller not supported for Standby Control SoCs */
-	if (info->stbyctrl)
+	if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
 		return 0;
 
 	error = cpg_mssr_reset_controller_register(priv);
--- linux-ein-5.4.0.orig/drivers/clk/renesas/renesas-cpg-mssr.h
+++ linux-ein-5.4.0/drivers/clk/renesas/renesas-cpg-mssr.h
@@ -85,6 +85,11 @@
 
 struct device_node;
 
+enum clk_reg_layout {
+	CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3 = 0,
+	CLK_REG_LAYOUT_RZ_A,
+};
+
     /**
      * SoC-specific CPG/MSSR Description
      *
@@ -105,6 +110,7 @@
      * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
      *                 should not be disabled without a knowledgeable driver
      * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+     * @reg_layout: CPG/MSSR register layout from enum clk_reg_layout
      *
      * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
      *                Management, in addition to Module Clocks
@@ -112,10 +118,6 @@
      *
      * @init: Optional callback to perform SoC-specific initialization
      * @cpg_clk_register: Optional callback to handle special Core Clock types
-     *
-     * @stbyctrl: This device has Standby Control Registers which are 8-bits
-     *            wide, no status registers (MSTPSR) and have different address
-     *            offsets.
      */
 
 struct cpg_mssr_info {
@@ -130,7 +132,7 @@
 	unsigned int num_core_clks;
 	unsigned int last_dt_core_clk;
 	unsigned int num_total_core_clks;
-	bool stbyctrl;
+	enum clk_reg_layout reg_layout;
 
 	/* Module Clocks */
 	const struct mssr_mod_clk *mod_clks;
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-half-divider.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-half-divider.c
@@ -167,7 +167,7 @@
 					  unsigned long flags,
 					  spinlock_t *lock)
 {
-	struct clk *clk;
+	struct clk *clk = ERR_PTR(-ENOMEM);
 	struct clk_mux *mux = NULL;
 	struct clk_gate *gate = NULL;
 	struct clk_divider *div = NULL;
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-pll.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-pll.c
@@ -963,6 +963,7 @@
 	return mux_clk;
 
 err_pll:
+	kfree(pll->rate_table);
 	clk_unregister(mux_clk);
 	mux_clk = pll_clk;
 err_mux:
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-rk3128.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-rk3128.c
@@ -489,7 +489,7 @@
 	GATE(HCLK_I2S_2CH, "hclk_i2s_2ch", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
 	GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS),
 	GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
-	GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 13, GFLAGS),
+	GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 13, GFLAGS),
 	GATE(0, "hclk_peri_ahb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS),
 	GATE(HCLK_SPDIF, "hclk_spdif", "hclk_peri", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS),
 	GATE(HCLK_TSP, "hclk_tsp", "hclk_peri", 0, RK2928_CLKGATE_CON(10), 12, GFLAGS),
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-rk3188.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-rk3188.c
@@ -751,6 +751,7 @@
 	"pclk_peri",
 	"hclk_cpubus",
 	"hclk_vio_bus",
+	"sclk_mac_lbtest",
 };
 
 static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np)
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-rk3228.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-rk3228.c
@@ -137,7 +137,7 @@
 PNAME(mux_hdmiphy_p)		= { "hdmiphy_phy", "xin24m" };
 PNAME(mux_aclk_cpu_src_p)	= { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" };
 
-PNAME(mux_pll_src_4plls_p)	= { "cpll", "gpll", "hdmiphy" "usb480m" };
+PNAME(mux_pll_src_4plls_p)	= { "cpll", "gpll", "hdmiphy", "usb480m" };
 PNAME(mux_pll_src_3plls_p)	= { "cpll", "gpll", "hdmiphy" };
 PNAME(mux_pll_src_2plls_p)	= { "cpll", "gpll" };
 PNAME(mux_sclk_hdmi_cec_p)	= { "cpll", "gpll", "xin24m" };
@@ -156,8 +156,6 @@
 PNAME(mux_i2s2_p)		= { "i2s2_src", "i2s2_frac", "xin12m" };
 PNAME(mux_sclk_spdif_p)		= { "sclk_spdif_src", "spdif_frac", "xin12m" };
 
-PNAME(mux_aclk_gpu_pre_p)	= { "cpll_gpu", "gpll_gpu", "hdmiphy_gpu", "usb480m_gpu" };
-
 PNAME(mux_uart0_p)		= { "uart0_src", "uart0_frac", "xin24m" };
 PNAME(mux_uart1_p)		= { "uart1_src", "uart1_frac", "xin24m" };
 PNAME(mux_uart2_p)		= { "uart2_src", "uart2_frac", "xin24m" };
@@ -468,16 +466,9 @@
 			RK2928_CLKSEL_CON(24), 6, 10, DFLAGS,
 			RK2928_CLKGATE_CON(2), 8, GFLAGS),
 
-	GATE(0, "cpll_gpu", "cpll", 0,
-			RK2928_CLKGATE_CON(3), 13, GFLAGS),
-	GATE(0, "gpll_gpu", "gpll", 0,
-			RK2928_CLKGATE_CON(3), 13, GFLAGS),
-	GATE(0, "hdmiphy_gpu", "hdmiphy", 0,
-			RK2928_CLKGATE_CON(3), 13, GFLAGS),
-	GATE(0, "usb480m_gpu", "usb480m", 0,
+	COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(34), 5, 2, MFLAGS, 0, 5, DFLAGS,
 			RK2928_CLKGATE_CON(3), 13, GFLAGS),
-	COMPOSITE_NOGATE(0, "aclk_gpu_pre", mux_aclk_gpu_pre_p, 0,
-			RK2928_CLKSEL_CON(34), 5, 2, MFLAGS, 0, 5, DFLAGS),
 
 	COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_2plls_p, 0,
 			RK2928_CLKSEL_CON(25), 8, 1, MFLAGS, 0, 7, DFLAGS,
@@ -582,8 +573,8 @@
 	GATE(0, "pclk_peri_noc", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 2, GFLAGS),
 
 	/* PD_GPU */
-	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 14, GFLAGS),
-	GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 15, GFLAGS),
+	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS),
+	GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS),
 
 	/* PD_BUS */
 	GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
--- linux-ein-5.4.0.orig/drivers/clk/rockchip/clk-rk3399.c
+++ linux-ein-5.4.0/drivers/clk/rockchip/clk-rk3399.c
@@ -1259,7 +1259,7 @@
 			RK3399_CLKSEL_CON(56), 6, 2, MFLAGS,
 			RK3399_CLKGATE_CON(10), 7, GFLAGS),
 
-	COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0,
+	COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, CLK_SET_RATE_PARENT,
 			 RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS),
 
 	/* gic */
--- linux-ein-5.4.0.orig/drivers/clk/samsung/clk-exynos4.c
+++ linux-ein-5.4.0/drivers/clk/samsung/clk-exynos4.c
@@ -927,7 +927,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,
@@ -969,7 +969,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,
--- linux-ein-5.4.0.orig/drivers/clk/samsung/clk-exynos5420.c
+++ linux-ein-5.4.0/drivers/clk/samsung/clk-exynos5420.c
@@ -12,6 +12,7 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/clk.h>
 
 #include "clk.h"
 #include "clk-cpu.h"
@@ -165,6 +166,8 @@
 	GATE_BUS_CPU,
 	GATE_SCLK_CPU,
 	CLKOUT_CMU_CPU,
+	APLL_CON0,
+	KPLL_CON0,
 	CPLL_CON0,
 	DPLL_CON0,
 	EPLL_CON0,
@@ -537,7 +540,7 @@
 
 static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = {
 	GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
-				GATE_BUS_TOP, 24, 0, 0),
+				GATE_BUS_TOP, 24, CLK_IS_CRITICAL, 0),
 	GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
 				GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
 };
@@ -937,25 +940,25 @@
 	GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg",
 			GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0",
-			GATE_BUS_TOP, 5, 0, 0),
+			GATE_BUS_TOP, 5, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl",
 			GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl",
 			GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp",
-			GATE_BUS_TOP, 8, 0, 0),
+			GATE_BUS_TOP, 8, CLK_IS_CRITICAL, 0),
 	GATE(CLK_PCLK66_GPIO, "pclk66_gpio", "mout_user_pclk66_gpio",
 			GATE_BUS_TOP, 9, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk66_psgen", "mout_user_aclk66_psgen",
 			GATE_BUS_TOP, 10, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk266_isp", "mout_user_aclk266_isp",
-			GATE_BUS_TOP, 13, 0, 0),
+			GATE_BUS_TOP, 13, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk166", "mout_user_aclk166",
 			GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333",
 			GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
-			GATE_BUS_TOP, 16, 0, 0),
+			GATE_BUS_TOP, 16, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl",
 			GATE_BUS_TOP, 17, CLK_IS_CRITICAL, 0),
 	GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1",
@@ -1155,8 +1158,10 @@
 			GATE_IP_GSCL1, 3, 0, 0),
 	GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "dout_gscl_blk_333",
 			GATE_IP_GSCL1, 4, 0, 0),
-	GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12, 0, 0),
-	GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13, 0, 0),
+	GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12,
+			CLK_IS_CRITICAL, 0),
+	GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13,
+			CLK_IS_CRITICAL, 0),
 	GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "dout_gscl_blk_333",
 			GATE_IP_GSCL1, 16, 0, 0),
 	GATE(CLK_FIMC_LITE3, "fimc_lite3", "aclk333_432_gscl",
@@ -1628,6 +1633,13 @@
 				     exynos5x_subcmus);
 	}
 
+	/*
+	 * Keep top part of G3D clock path enabled permanently to ensure
+	 * that the internal busses get their clock regardless of the
+	 * main G3D clock enablement status.
+	 */
+	clk_prepare_enable(__clk_lookup("mout_sw_aclk_g3d"));
+
 	samsung_clk_of_add_provider(np, ctx);
 }
 
--- linux-ein-5.4.0.orig/drivers/clk/samsung/clk-exynos5433.c
+++ linux-ein-5.4.0/drivers/clk/samsung/clk-exynos5433.c
@@ -1706,7 +1706,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-ein-5.4.0.orig/drivers/clk/samsung/clk-exynos7.c
+++ linux-ein-5.4.0/drivers/clk/samsung/clk-exynos7.c
@@ -537,8 +537,13 @@
 	GATE(CLK_ACLK_FSYS0_200, "aclk_fsys0_200", "dout_aclk_fsys0_200",
 		ENABLE_ACLK_TOP13, 28, CLK_SET_RATE_PARENT |
 		CLK_IS_CRITICAL, 0),
+	/*
+	 * This clock is required for the CMU_FSYS1 registers access, keep it
+	 * enabled permanently until proper runtime PM support is added.
+	 */
 	GATE(CLK_ACLK_FSYS1_200, "aclk_fsys1_200", "dout_aclk_fsys1_200",
-		ENABLE_ACLK_TOP13, 24, CLK_SET_RATE_PARENT, 0),
+		ENABLE_ACLK_TOP13, 24, CLK_SET_RATE_PARENT |
+		CLK_IS_CRITICAL, 0),
 
 	GATE(CLK_SCLK_PHY_FSYS1_26M, "sclk_phy_fsys1_26m",
 		"dout_sclk_phy_fsys1_26m", ENABLE_SCLK_TOP1_FSYS11,
--- linux-ein-5.4.0.orig/drivers/clk/samsung/clk-pll.c
+++ linux-ein-5.4.0/drivers/clk/samsung/clk-pll.c
@@ -1390,6 +1390,7 @@
 	if (ret) {
 		pr_err("%s: failed to register pll clock %s : %d\n",
 			__func__, pll_clk->name, ret);
+		kfree(pll->rate_table);
 		kfree(pll);
 		return;
 	}
--- linux-ein-5.4.0.orig/drivers/clk/sifive/fu540-prci.c
+++ linux-ein-5.4.0/drivers/clk/sifive/fu540-prci.c
@@ -586,7 +586,10 @@
 	struct __prci_data *pd;
 	int r;
 
-	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	pd = devm_kzalloc(dev,
+			  struct_size(pd, hw_clks.hws,
+				      ARRAY_SIZE(__prci_init_clocks)),
+			  GFP_KERNEL);
 	if (!pd)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/drivers/clk/sirf/clk-atlas6.c
+++ linux-ein-5.4.0/drivers/clk/sirf/clk-atlas6.c
@@ -135,7 +135,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-ein-5.4.0.orig/drivers/clk/socfpga/clk-gate-a10.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-gate-a10.c
@@ -146,6 +146,7 @@
 		if (IS_ERR(socfpga_clk->sys_mgr_base_addr)) {
 			pr_err("%s: failed to find altr,sys-mgr regmap!\n",
 					__func__);
+			kfree(socfpga_clk);
 			return;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/clk/socfpga/clk-gate.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-gate.c
@@ -99,7 +99,7 @@
 		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
 		val &= GENMASK(socfpgaclk->width - 1, 0);
 		/* Check for GPIO_DB_CLK by its offset */
-		if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
+		if ((uintptr_t) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
 			div = val + 1;
 		else
 			div = (1 << val);
@@ -174,21 +174,24 @@
 	u32 div_reg[3];
 	u32 clk_phase[2];
 	u32 fixed_div;
-	struct clk *clk;
+	struct clk_hw *hw_clk;
 	struct socfpga_gate_clk *socfpga_clk;
 	const char *clk_name = node->name;
 	const char *parent_name[SOCFPGA_MAX_PARENTS];
 	struct clk_init_data init;
 	struct clk_ops *ops;
 	int rc;
+	int err;
 
 	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
 	if (WARN_ON(!socfpga_clk))
 		return;
 
 	ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL);
-	if (WARN_ON(!ops))
+	if (WARN_ON(!ops)) {
+		kfree(socfpga_clk);
 		return;
+	}
 
 	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
 	if (rc)
@@ -238,12 +241,15 @@
 	init.parent_names = parent_name;
 	socfpga_clk->hw.hw.init = &init;
 
-	clk = clk_register(NULL, &socfpga_clk->hw.hw);
-	if (WARN_ON(IS_ERR(clk))) {
+	hw_clk = &socfpga_clk->hw.hw;
+
+	err = clk_hw_register(NULL, hw_clk);
+	if (err) {
+		kfree(ops);
 		kfree(socfpga_clk);
 		return;
 	}
-	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
 	if (WARN_ON(rc))
 		return;
 }
--- linux-ein-5.4.0.orig/drivers/clk/socfpga/clk-periph.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-periph.c
@@ -51,7 +51,7 @@
 	const struct clk_ops *ops)
 {
 	u32 reg;
-	struct clk *clk;
+	struct clk_hw *hw_clk;
 	struct socfpga_periph_clk *periph_clk;
 	const char *clk_name = node->name;
 	const char *parent_name[SOCFPGA_MAX_PARENTS];
@@ -94,13 +94,13 @@
 	init.parent_names = parent_name;
 
 	periph_clk->hw.hw.init = &init;
+	hw_clk = &periph_clk->hw.hw;
 
-	clk = clk_register(NULL, &periph_clk->hw.hw);
-	if (WARN_ON(IS_ERR(clk))) {
+	if (clk_hw_register(NULL, hw_clk)) {
 		kfree(periph_clk);
 		return;
 	}
-	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
 }
 
 void __init socfpga_periph_init(struct device_node *node)
--- linux-ein-5.4.0.orig/drivers/clk/socfpga/clk-pll-s10.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-pll-s10.c
@@ -39,7 +39,9 @@
 	/* read VCO1 reg for numerator and denominator */
 	reg = readl(socfpgaclk->hw.reg);
 	refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
-	vco_freq = (unsigned long long)parent_rate / refdiv;
+
+	vco_freq = parent_rate;
+	do_div(vco_freq, refdiv);
 
 	/* Read mdiv and fdiv from the fdbck register */
 	reg = readl(socfpgaclk->hw.reg + 0x4);
--- linux-ein-5.4.0.orig/drivers/clk/socfpga/clk-pll.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-pll.c
@@ -70,17 +70,18 @@
 	.get_parent = clk_pll_get_parent,
 };
 
-static __init struct clk *__socfpga_pll_init(struct device_node *node,
+static __init struct clk_hw *__socfpga_pll_init(struct device_node *node,
 	const struct clk_ops *ops)
 {
 	u32 reg;
-	struct clk *clk;
+	struct clk_hw *hw_clk;
 	struct socfpga_pll *pll_clk;
 	const char *clk_name = node->name;
 	const char *parent_name[SOCFPGA_MAX_PARENTS];
 	struct clk_init_data init;
 	struct device_node *clkmgr_np;
 	int rc;
+	int err;
 
 	of_property_read_u32(node, "reg", &reg);
 
@@ -108,13 +109,15 @@
 	clk_pll_ops.enable = clk_gate_ops.enable;
 	clk_pll_ops.disable = clk_gate_ops.disable;
 
-	clk = clk_register(NULL, &pll_clk->hw.hw);
-	if (WARN_ON(IS_ERR(clk))) {
+	hw_clk = &pll_clk->hw.hw;
+
+	err = clk_hw_register(NULL, hw_clk);
+	if (err) {
 		kfree(pll_clk);
-		return NULL;
+		return ERR_PTR(err);
 	}
-	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
-	return clk;
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
+	return hw_clk;
 }
 
 void __init socfpga_pll_init(struct device_node *node)
--- linux-ein-5.4.0.orig/drivers/clk/socfpga/clk-s10.c
+++ linux-ein-5.4.0/drivers/clk/socfpga/clk-s10.c
@@ -107,7 +107,7 @@
 	{ STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
 	  0, 0, 2, 0xB0, 1},
 	{ STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux,
-	  ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2},
+	  ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 2, 0xB0, 2},
 	{ STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
 	  ARRAY_SIZE(gpio_db_free_mux), 0, 0, 0, 0xB0, 3},
 	{ STRATIX10_SDMMC_FREE_CLK, "sdmmc_free_clk", NULL, sdmmc_free_mux,
--- linux-ein-5.4.0.orig/drivers/clk/sprd/common.c
+++ linux-ein-5.4.0/drivers/clk/sprd/common.c
@@ -46,7 +46,7 @@
 
 	if (of_find_property(node, "sprd,syscon", NULL)) {
 		regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
-		if (IS_ERR_OR_NULL(regmap)) {
+		if (IS_ERR(regmap)) {
 			pr_err("%s: failed to get syscon regmap\n", __func__);
 			return PTR_ERR(regmap);
 		}
--- linux-ein-5.4.0.orig/drivers/clk/sprd/pll.c
+++ linux-ein-5.4.0/drivers/clk/sprd/pll.c
@@ -105,7 +105,7 @@
 
 	cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL);
 	if (!cfg)
-		return -ENOMEM;
+		return parent_rate;
 
 	for (i = 0; i < regs_num; i++)
 		cfg[i] = sprd_pll_read(pll, i);
--- linux-ein-5.4.0.orig/drivers/clk/st/clk-flexgen.c
+++ linux-ein-5.4.0/drivers/clk/st/clk-flexgen.c
@@ -375,6 +375,7 @@
 			break;
 		}
 
+		flex_flags &= ~CLK_IS_CRITICAL;
 		of_clk_detect_critical(np, i, &flex_flags);
 
 		/*
--- linux-ein-5.4.0.orig/drivers/clk/st/clkgen-fsyn.c
+++ linux-ein-5.4.0/drivers/clk/st/clkgen-fsyn.c
@@ -943,9 +943,10 @@
 
 	clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, data,
 			reg, lock);
-	if (IS_ERR(clk))
+	if (IS_ERR(clk)) {
+		kfree(lock);
 		goto err_exit;
-	else
+	} else
 		pr_debug("%s: parent %s rate %u\n",
 			__clk_get_name(clk),
 			__clk_get_name(clk_get_parent(clk)),
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -389,6 +389,7 @@
 	{ .val = 1, .div = 2 },
 	{ .val = 2, .div = 4 },
 	{ .val = 3, .div = 6 },
+	{ /* Sentinel */ },
 };
 static const char * const ths_parents[] = { "osc24M" };
 static struct ccu_div ths_clk = {
@@ -921,11 +922,26 @@
 	.num_resets	= ARRAY_SIZE(sun50i_a64_ccu_resets),
 };
 
+static struct ccu_pll_nb sun50i_a64_pll_cpu_nb = {
+	.common	= &pll_cpux_clk.common,
+	/* copy from pll_cpux_clk */
+	.enable	= BIT(31),
+	.lock	= BIT(28),
+};
+
+static struct ccu_mux_nb sun50i_a64_cpu_nb = {
+	.common		= &cpux_clk.common,
+	.cm		= &cpux_clk.mux,
+	.delay_us	= 1, /* > 8 clock cycles at 24 MHz */
+	.bypass_index	= 1, /* index of 24 MHz oscillator */
+};
+
 static int sun50i_a64_ccu_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	void __iomem *reg;
 	u32 val;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	reg = devm_ioremap_resource(&pdev->dev, res);
@@ -939,7 +955,18 @@
 
 	writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
 
-	return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
+	ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
+	if (ret)
+		return ret;
+
+	/* Gate then ungate PLL CPU after any rate changes */
+	ccu_pll_notifier_register(&sun50i_a64_pll_cpu_nb);
+
+	/* Reparent CPU during PLL CPU rate changes */
+	ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+				  &sun50i_a64_cpu_nb);
+
+	return 0;
 }
 
 static const struct of_device_id sun50i_a64_ccu_ids[] = {
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
@@ -23,9 +23,9 @@
  */
 
 static const char * const ar100_r_apb2_parents[] = { "osc24M", "osc32k",
-					     "pll-periph0", "iosc" };
+						     "iosc", "pll-periph0" };
 static const struct ccu_mux_var_prediv ar100_r_apb2_predivs[] = {
-	{ .index = 2, .shift = 0, .width = 5 },
+	{ .index = 3, .shift = 0, .width = 5 },
 };
 
 static struct ccu_div ar100_clk = {
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
@@ -228,7 +228,7 @@
 static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2",
 			     psi_ahb1_ahb2_parents,
 			     0x510,
-			     0, 5,	/* M */
+			     0, 2,	/* M */
 			     8, 2,	/* P */
 			     24, 2,	/* mux */
 			     0);
@@ -237,19 +237,19 @@
 						       "psi-ahb1-ahb2",
 						       "pll-periph0" };
 static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c,
-			     0, 5,	/* M */
+			     0, 2,	/* M */
 			     8, 2,	/* P */
 			     24, 2,	/* mux */
 			     0);
 
 static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520,
-			     0, 5,	/* M */
+			     0, 2,	/* M */
 			     8, 2,	/* P */
 			     24, 2,	/* mux */
 			     0);
 
 static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524,
-			     0, 5,	/* M */
+			     0, 2,	/* M */
 			     8, 2,	/* P */
 			     24, 2,	/* mux */
 			     0);
@@ -673,7 +673,7 @@
 
 	.common		= {
 		.reg		= 0xb10,
-		.features	= CCU_FEATURE_VARIABLE_PREDIV,
+		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("hdmi-cec",
 						      hdmi_cec_parents,
 						      &ccu_mux_ops,
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -322,6 +322,7 @@
 	{ .val = 1, .div = 2 },
 	{ .val = 2, .div = 4 },
 	{ .val = 3, .div = 6 },
+	{ /* Sentinel */ },
 };
 static SUNXI_CCU_DIV_TABLE_WITH_GATE(ths_clk, "ths", "osc24M",
 				     0x074, 0, 2, ths_div_table, BIT(31), 0);
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun8i-r.c
@@ -51,19 +51,7 @@
 
 static CLK_FIXED_FACTOR_HW(ahb0_clk, "ahb0", &ar100_clk.common.hw, 1, 1, 0);
 
-static struct ccu_div apb0_clk = {
-	.div		= _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO),
-
-	.common		= {
-		.reg		= 0x0c,
-		.hw.init	= CLK_HW_INIT_HW("apb0",
-						 &ahb0_clk.hw,
-						 &ccu_div_ops,
-						 0),
-	},
-};
-
-static SUNXI_CCU_M(a83t_apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
+static SUNXI_CCU_M(apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
 
 /*
  * Define the parent as an array that can be reused to save space
@@ -127,7 +115,7 @@
 
 static struct ccu_common *sun8i_a83t_r_ccu_clks[] = {
 	&ar100_clk.common,
-	&a83t_apb0_clk.common,
+	&apb0_clk.common,
 	&apb0_pio_clk.common,
 	&apb0_ir_clk.common,
 	&apb0_timer_clk.common,
@@ -167,7 +155,7 @@
 	.hws	= {
 		[CLK_AR100]		= &ar100_clk.common.hw,
 		[CLK_AHB0]		= &ahb0_clk.hw,
-		[CLK_APB0]		= &a83t_apb0_clk.common.hw,
+		[CLK_APB0]		= &apb0_clk.common.hw,
 		[CLK_APB0_PIO]		= &apb0_pio_clk.common.hw,
 		[CLK_APB0_IR]		= &apb0_ir_clk.common.hw,
 		[CLK_APB0_TIMER]	= &apb0_timer_clk.common.hw,
@@ -282,9 +270,6 @@
 
 static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
 {
-	/* Fix apb0 bus gate parents here */
-	apb0_gate_parent[0] = &a83t_apb0_clk.common.hw;
-
 	sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
 }
 CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -761,7 +761,8 @@
 		.reg		= 0x1f0,
 		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("outa", out_parents,
-						      &ccu_mp_ops, 0),
+						      &ccu_mp_ops,
+						      CLK_SET_RATE_PARENT),
 	}
 };
 
@@ -779,7 +780,8 @@
 		.reg		= 0x1f4,
 		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("outb", out_parents,
-						      &ccu_mp_ops, 0),
+						      &ccu_mp_ops,
+						      CLK_SET_RATE_PARENT),
 	}
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
@@ -618,7 +618,7 @@
 		[CLK_MBUS]		= &mbus_clk.common.hw,
 		[CLK_MIPI_CSI]		= &mipi_csi_clk.common.hw,
 	},
-	.num	= CLK_NUMBER,
+	.num	= CLK_PLL_DDR1 + 1,
 };
 
 static struct clk_hw_onecell_data sun8i_v3_hw_clks = {
@@ -700,7 +700,7 @@
 		[CLK_MBUS]		= &mbus_clk.common.hw,
 		[CLK_MIPI_CSI]		= &mipi_csi_clk.common.hw,
 	},
-	.num	= CLK_NUMBER,
+	.num	= CLK_I2S0 + 1,
 };
 
 static struct ccu_reset_map sun8i_v3s_ccu_resets[] = {
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h
@@ -51,6 +51,4 @@
 
 #define CLK_PLL_DDR1		74
 
-#define CLK_NUMBER		(CLK_I2S0 + 1)
-
 #endif /* _CCU_SUN8I_H3_H_ */
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu_mmc_timing.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu_mmc_timing.c
@@ -43,7 +43,7 @@
 EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode);
 
 /**
- * sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode
+ * sunxi_ccu_get_mmc_timing_mode: Get the current MMC clock timing mode
  * @clk: clock to query
  *
  * Returns 0 if the clock is in old timing mode, > 0 if it is in
--- linux-ein-5.4.0.orig/drivers/clk/sunxi-ng/ccu_mp.c
+++ linux-ein-5.4.0/drivers/clk/sunxi-ng/ccu_mp.c
@@ -108,7 +108,7 @@
 	max_m = cmp->m.max ?: 1 << cmp->m.width;
 	max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
 
-	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+	if (!clk_hw_can_set_rate_parent(&cmp->common.hw)) {
 		ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
 		rate = *parent_rate / p / m;
 	} else {
--- linux-ein-5.4.0.orig/drivers/clk/sunxi/clk-sun9i-mmc.c
+++ linux-ein-5.4.0/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -109,6 +109,8 @@
 	spin_lock_init(&data->lock);
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EINVAL;
 	/* one clock/reset pair per word */
 	count = DIV_ROUND_UP((resource_size(r)), SUN9I_MMC_WIDTH);
 	data->membase = devm_ioremap_resource(&pdev->dev, r);
--- linux-ein-5.4.0.orig/drivers/clk/sunxi/clk-sunxi.c
+++ linux-ein-5.4.0/drivers/clk/sunxi/clk-sunxi.c
@@ -90,7 +90,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-ein-5.4.0.orig/drivers/clk/tegra/clk-bpmp.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-bpmp.c
@@ -159,7 +159,7 @@
 
 	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
 	if (err < 0)
-		return err;
+		return 0;
 
 	return response.rate;
 }
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-dfll.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-dfll.c
@@ -1801,13 +1801,13 @@
 			    &td->reg_init_uV);
 	if (!ret) {
 		dev_err(td->dev, "couldn't get initialized voltage\n");
-		return ret;
+		return -EINVAL;
 	}
 
 	ret = read_dt_param(td, "nvidia,pwm-period-nanoseconds", &pwm_period);
 	if (!ret) {
 		dev_err(td->dev, "couldn't get PWM period\n");
-		return ret;
+		return -EINVAL;
 	}
 	td->pwm_rate = (NSEC_PER_SEC / pwm_period) * (MAX_DFLL_VOLTAGES - 1);
 
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-emc.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-emc.c
@@ -191,6 +191,7 @@
 
 	tegra->emc = platform_get_drvdata(pdev);
 	if (!tegra->emc) {
+		put_device(&pdev->dev);
 		pr_err("%s: cannot find EMC driver\n", __func__);
 		return NULL;
 	}
@@ -458,6 +459,7 @@
 		err = load_one_timing_from_dt(tegra, timing, child);
 		if (err) {
 			of_node_put(child);
+			kfree(tegra->timings);
 			return err;
 		}
 
@@ -509,6 +511,7 @@
 		err = load_timings_from_dt(tegra, node, node_ram_code);
 		if (err) {
 			of_node_put(node);
+			kfree(tegra);
 			return ERR_PTR(err);
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-id.h
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-id.h
@@ -233,6 +233,7 @@
 	tegra_clk_sdmmc4,
 	tegra_clk_sdmmc4_8,
 	tegra_clk_se,
+	tegra_clk_se_10,
 	tegra_clk_soc_therm,
 	tegra_clk_soc_therm_8,
 	tegra_clk_sor0,
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-pll.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-pll.c
@@ -1089,7 +1089,8 @@
 	if (pll->lock)
 		spin_lock_irqsave(pll->lock, flags);
 
-	_clk_pll_enable(hw);
+	if (!clk_pll_is_enabled(hw))
+		_clk_pll_enable(hw);
 
 	ret = clk_pll_wait_for_lock(pll);
 	if (ret < 0)
@@ -1569,9 +1570,6 @@
 	unsigned long flags = 0;
 	unsigned long input_rate;
 
-	if (clk_pll_is_enabled(hw))
-		return 0;
-
 	input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
 
 	if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
@@ -1709,15 +1707,13 @@
 		return -EINVAL;
 	}
 
-	if (clk_pll_is_enabled(hw))
-		return 0;
-
 	input_rate = clk_hw_get_rate(__clk_get_hw(osc));
 
 	if (pll->lock)
 		spin_lock_irqsave(pll->lock, flags);
 
-	_clk_pll_enable(hw);
+	if (!clk_pll_is_enabled(hw))
+		_clk_pll_enable(hw);
 
 	ret = clk_pll_wait_for_lock(pll);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra-periph.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra-periph.c
@@ -636,7 +636,7 @@
 	INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
 	INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
 	INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
-	INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
+	INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se_10),
 	INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
 	INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
 	INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
@@ -785,7 +785,11 @@
 	GATE("ahbdma", "hclk", 33, 0, tegra_clk_ahbdma, 0),
 	GATE("apbdma", "pclk", 34, 0, tegra_clk_apbdma, 0),
 	GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0),
-	GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 0),
+	/*
+	 * Critical for RAM re-repair operation, which must occur on resume
+	 * from LP1 system suspend and as part of CCPLEX cluster switching.
+	 */
+	GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, CLK_IS_CRITICAL),
 	GATE("fuse_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 0),
 	GATE("kfuse", "clk_m", 40, TEGRA_PERIPH_ON_APB, tegra_clk_kfuse, 0),
 	GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0),
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra-pmc.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra-pmc.c
@@ -49,16 +49,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-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra114.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra114.c
@@ -1337,6 +1337,7 @@
 	}
 
 	pmc_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!pmc_base) {
 		pr_err("Can't map pmc registers\n");
 		WARN_ON(1);
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra20.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra20.c
@@ -18,24 +18,24 @@
 #define MISC_CLK_ENB 0x48
 
 #define OSC_CTRL 0x50
-#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
-#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
-#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
-#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
-#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28)
-#define OSC_CTRL_PLL_REF_DIV_1		(0<<28)
-#define OSC_CTRL_PLL_REF_DIV_2		(1<<28)
-#define OSC_CTRL_PLL_REF_DIV_4		(2<<28)
+#define OSC_CTRL_OSC_FREQ_MASK (3u<<30)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0u<<30)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (1u<<30)
+#define OSC_CTRL_OSC_FREQ_12MHZ (2u<<30)
+#define OSC_CTRL_OSC_FREQ_26MHZ (3u<<30)
+#define OSC_CTRL_MASK (0x3f2u | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK	(3u<<28)
+#define OSC_CTRL_PLL_REF_DIV_1		(0u<<28)
+#define OSC_CTRL_PLL_REF_DIV_2		(1u<<28)
+#define OSC_CTRL_PLL_REF_DIV_4		(2u<<28)
 
 #define OSC_FREQ_DET 0x58
-#define OSC_FREQ_DET_TRIG (1<<31)
+#define OSC_FREQ_DET_TRIG (1u<<31)
 
 #define OSC_FREQ_DET_STATUS 0x5c
-#define OSC_FREQ_DET_BUSY (1<<31)
-#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+#define OSC_FREQ_DET_BUSYu (1<<31)
+#define OSC_FREQ_DET_CNT_MASK 0xFFFFu
 
 #define TEGRA20_CLK_PERIPH_BANKS	3
 
@@ -1151,6 +1151,7 @@
 	}
 
 	pmc_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!pmc_base) {
 		pr_err("Can't map pmc registers\n");
 		BUG();
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra210.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra210.c
@@ -3523,6 +3523,7 @@
 	}
 
 	pmc_base = of_iomap(node, 0);
+	of_node_put(node);
 	if (!pmc_base) {
 		pr_err("Can't map pmc registers\n");
 		WARN_ON(1);
--- linux-ein-5.4.0.orig/drivers/clk/tegra/clk-tegra30.c
+++ linux-ein-5.4.0/drivers/clk/tegra/clk-tegra30.c
@@ -1263,6 +1263,8 @@
 	{ TEGRA30_CLK_I2S3_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
 	{ TEGRA30_CLK_I2S4_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
 	{ TEGRA30_CLK_VIMCLK_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
+	{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
+	{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
 	/* must be the last entry */
 	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
 };
--- linux-ein-5.4.0.orig/drivers/clk/ti/adpll.c
+++ linux-ein-5.4.0/drivers/clk/ti/adpll.c
@@ -194,15 +194,8 @@
 		if (err)
 			return NULL;
 	} else {
-		const char *base_name = "adpll";
-		char *buf;
-
-		buf = devm_kzalloc(d->dev, 8 + 1 + strlen(base_name) + 1 +
-				    strlen(postfix), GFP_KERNEL);
-		if (!buf)
-			return NULL;
-		sprintf(buf, "%08lx.%s.%s", d->pa, base_name, postfix);
-		name = buf;
+		name = devm_kasprintf(d->dev, GFP_KERNEL, "%08lx.adpll.%s",
+				      d->pa, postfix);
 	}
 
 	return name;
--- linux-ein-5.4.0.orig/drivers/clk/ti/clk-33xx.c
+++ linux-ein-5.4.0/drivers/clk/ti/clk-33xx.c
@@ -212,7 +212,7 @@
 };
 
 static const struct omap_clkctrl_reg_data am3_l4_rtc_clkctrl_regs[] __initconst = {
-	{ AM3_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+	{ AM3_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk-24mhz-clkctrl:0000:0" },
 	{ 0 },
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/ti/clk-43xx.c
+++ linux-ein-5.4.0/drivers/clk/ti/clk-43xx.c
@@ -78,7 +78,7 @@
 };
 
 static const struct omap_clkctrl_reg_data am4_l4_rtc_clkctrl_regs[] __initconst = {
-	{ AM4_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+	{ AM4_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ick" },
 	{ 0 },
 };
 
--- linux-ein-5.4.0.orig/drivers/clk/ti/clk-7xx.c
+++ linux-ein-5.4.0/drivers/clk/ti/clk-7xx.c
@@ -405,7 +405,7 @@
 };
 
 static const struct omap_clkctrl_reg_data dra7_gmac_clkctrl_regs[] __initconst = {
-	{ DRA7_GMAC_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "dpll_gmac_ck" },
+	{ DRA7_GMAC_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "gmac_main_clk" },
 	{ 0 },
 };
 
@@ -793,6 +793,7 @@
 	DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
 	DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"),
 	DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
+	DT_CLK(NULL, "timer_sys_ck", "timer_sys_clk_div"),
 	DT_CLK(NULL, "atl_dpll_clk_mux", "atl-clkctrl:0000:24"),
 	DT_CLK(NULL, "atl_gfclk_mux", "atl-clkctrl:0000:26"),
 	DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon-clkctrl:0068:24"),
--- linux-ein-5.4.0.orig/drivers/clk/ti/clk-dra7-atl.c
+++ linux-ein-5.4.0/drivers/clk/ti/clk-dra7-atl.c
@@ -252,14 +252,16 @@
 		if (rc) {
 			pr_err("%s: failed to lookup atl clock %d\n", __func__,
 			       i);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto pm_put;
 		}
 
 		clk = of_clk_get_from_provider(&clkspec);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to get atl clock %d from provider\n",
 			       __func__, i);
-			return PTR_ERR(clk);
+			ret = PTR_ERR(clk);
+			goto pm_put;
 		}
 
 		cdesc = to_atl_desc(__clk_get_hw(clk));
@@ -292,8 +294,9 @@
 		if (cdesc->enabled)
 			atl_clk_enable(__clk_get_hw(clk));
 	}
-	pm_runtime_put_sync(cinfo->dev);
 
+pm_put:
+	pm_runtime_put_sync(cinfo->dev);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/clk/ti/clockdomain.c
+++ linux-ein-5.4.0/drivers/clk/ti/clockdomain.c
@@ -146,10 +146,12 @@
 		if (!omap2_clk_is_hw_omap(clk_hw)) {
 			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-ein-5.4.0.orig/drivers/clk/ti/composite.c
+++ linux-ein-5.4.0/drivers/clk/ti/composite.c
@@ -196,6 +196,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-ein-5.4.0.orig/drivers/clk/ti/fapll.c
+++ linux-ein-5.4.0/drivers/clk/ti/fapll.c
@@ -498,6 +498,7 @@
 {
 	struct clk_init_data *init;
 	struct fapll_synth *synth;
+	struct clk *clk = ERR_PTR(-ENOMEM);
 
 	init = kzalloc(sizeof(*init), GFP_KERNEL);
 	if (!init)
@@ -520,13 +521,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-ein-5.4.0.orig/drivers/clk/uniphier/clk-uniphier-fixed-rate.c
+++ linux-ein-5.4.0/drivers/clk/uniphier/clk-uniphier-fixed-rate.c
@@ -24,6 +24,7 @@
 
 	init.name = name;
 	init.ops = &clk_fixed_rate_ops;
+	init.flags = 0;
 	init.parent_names = NULL;
 	init.num_parents = 0;
 
--- linux-ein-5.4.0.orig/drivers/clk/uniphier/clk-uniphier-mux.c
+++ linux-ein-5.4.0/drivers/clk/uniphier/clk-uniphier-mux.c
@@ -31,10 +31,10 @@
 static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw)
 {
 	struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
-	int num_parents = clk_hw_get_num_parents(hw);
+	unsigned int num_parents = clk_hw_get_num_parents(hw);
 	int ret;
 	unsigned int val;
-	u8 i;
+	unsigned int i;
 
 	ret = regmap_read(mux->regmap, mux->reg, &val);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/clk/uniphier/clk-uniphier-peri.c
+++ linux-ein-5.4.0/drivers/clk/uniphier/clk-uniphier-peri.c
@@ -18,8 +18,8 @@
 #define UNIPHIER_PERI_CLK_FI2C(idx, ch)					\
 	UNIPHIER_CLK_GATE("i2c" #ch, (idx), "i2c", 0x24, 24 + (ch))
 
-#define UNIPHIER_PERI_CLK_SCSSI(idx)					\
-	UNIPHIER_CLK_GATE("scssi", (idx), "spi", 0x20, 17)
+#define UNIPHIER_PERI_CLK_SCSSI(idx, ch)				\
+	UNIPHIER_CLK_GATE("scssi" #ch, (idx), "spi", 0x20, 17 + (ch))
 
 #define UNIPHIER_PERI_CLK_MCSSI(idx)					\
 	UNIPHIER_CLK_GATE("mcssi", (idx), "spi", 0x24, 14)
@@ -35,7 +35,7 @@
 	UNIPHIER_PERI_CLK_I2C(6, 2),
 	UNIPHIER_PERI_CLK_I2C(7, 3),
 	UNIPHIER_PERI_CLK_I2C(8, 4),
-	UNIPHIER_PERI_CLK_SCSSI(11),
+	UNIPHIER_PERI_CLK_SCSSI(11, 0),
 	{ /* sentinel */ }
 };
 
@@ -51,7 +51,10 @@
 	UNIPHIER_PERI_CLK_FI2C(8, 4),
 	UNIPHIER_PERI_CLK_FI2C(9, 5),
 	UNIPHIER_PERI_CLK_FI2C(10, 6),
-	UNIPHIER_PERI_CLK_SCSSI(11),
-	UNIPHIER_PERI_CLK_MCSSI(12),
+	UNIPHIER_PERI_CLK_SCSSI(11, 0),
+	UNIPHIER_PERI_CLK_SCSSI(12, 1),
+	UNIPHIER_PERI_CLK_SCSSI(13, 2),
+	UNIPHIER_PERI_CLK_SCSSI(14, 3),
+	UNIPHIER_PERI_CLK_MCSSI(15),
 	{ /* sentinel */ }
 };
--- linux-ein-5.4.0.orig/drivers/clk/zynqmp/clk-mux-zynqmp.c
+++ linux-ein-5.4.0/drivers/clk/zynqmp/clk-mux-zynqmp.c
@@ -85,7 +85,7 @@
 static const struct clk_ops zynqmp_clk_mux_ops = {
 	.get_parent = zynqmp_clk_mux_get_parent,
 	.set_parent = zynqmp_clk_mux_set_parent,
-	.determine_rate = __clk_mux_determine_rate,
+	.determine_rate = __clk_mux_determine_rate_closest,
 };
 
 static const struct clk_ops zynqmp_clk_mux_ro_ops = {
--- linux-ein-5.4.0.orig/drivers/clk/zynqmp/clkc.c
+++ linux-ein-5.4.0/drivers/clk/zynqmp/clkc.c
@@ -558,7 +558,7 @@
 {
 	int j;
 	u32 num_nodes, clk_dev_id;
-	char *clk_out = NULL;
+	char *clk_out[MAX_NODES];
 	struct clock_topology *nodes;
 	struct clk_hw *hw = NULL;
 
@@ -572,16 +572,16 @@
 		 * Intermediate clock names are postfixed with type of clock.
 		 */
 		if (j != (num_nodes - 1)) {
-			clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name,
+			clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name,
 					    clk_type_postfix[nodes[j].type]);
 		} else {
-			clk_out = kasprintf(GFP_KERNEL, "%s", clk_name);
+			clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name);
 		}
 
 		if (!clk_topology[nodes[j].type])
 			continue;
 
-		hw = (*clk_topology[nodes[j].type])(clk_out, clk_dev_id,
+		hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id,
 						    parent_names,
 						    num_parents,
 						    &nodes[j]);
@@ -590,9 +590,12 @@
 				     __func__,  clk_dev_id, clk_name,
 				     PTR_ERR(hw));
 
-		parent_names[0] = clk_out;
+		parent_names[0] = clk_out[j];
 	}
-	kfree(clk_out);
+
+	for (j = 0; j < num_nodes; j++)
+		kfree(clk_out[j]);
+
 	return hw;
 }
 
@@ -676,6 +679,13 @@
 				  FIELD_PREP(CLK_ATTR_NODE_INDEX, i);
 
 		zynqmp_pm_clock_get_name(clock[i].clk_id, &name);
+
+		/*
+		 * Terminate with NULL character in case name provided by firmware
+		 * is longer and truncated due to size limit.
+		 */
+		name.name[sizeof(name.name) - 1] = '\0';
+
 		if (!strcmp(name.name, RESERVED_CLK_NAME))
 			continue;
 		strncpy(clock[i].clk_name, name.name, MAX_NAME_LEN);
--- linux-ein-5.4.0.orig/drivers/clk/zynqmp/pll.c
+++ linux-ein-5.4.0/drivers/clk/zynqmp/pll.c
@@ -98,28 +98,25 @@
 				  unsigned long *prate)
 {
 	u32 fbdiv;
-	long rate_div, f;
+	u32 mult, div;
 
-	/* Enable the fractional mode if needed */
-	rate_div = (rate * FRAC_DIV) / *prate;
-	f = rate_div % FRAC_DIV;
-	zynqmp_pll_set_mode(hw, !!f);
-
-	if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
-		if (rate > PS_PLL_VCO_MAX) {
-			fbdiv = rate / PS_PLL_VCO_MAX;
-			rate = rate / (fbdiv + 1);
-		}
-		if (rate < PS_PLL_VCO_MIN) {
-			fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
-			rate = rate * fbdiv;
-		}
-		return rate;
+	/* Let rate fall inside the range PS_PLL_VCO_MIN ~ PS_PLL_VCO_MAX */
+	if (rate > PS_PLL_VCO_MAX) {
+		div = DIV_ROUND_UP(rate, PS_PLL_VCO_MAX);
+		rate = rate / div;
+	}
+	if (rate < PS_PLL_VCO_MIN) {
+		mult = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
+		rate = rate * mult;
 	}
 
 	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
-	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
-	return *prate * fbdiv;
+	if (fbdiv < PLL_FBDIV_MIN || fbdiv > PLL_FBDIV_MAX) {
+		fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
+		rate = *prate * fbdiv;
+	}
+
+	return rate;
 }
 
 /**
@@ -179,10 +176,12 @@
 	int ret;
 	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-	if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
-		rate_div = (rate * FRAC_DIV) / parent_rate;
+	rate_div = (rate * FRAC_DIV) / parent_rate;
+	f = rate_div % FRAC_DIV;
+	zynqmp_pll_set_mode(hw, !!f);
+
+	if (f) {
 		m = rate_div / FRAC_DIV;
-		f = rate_div % FRAC_DIV;
 		m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
 		rate = parent_rate * m;
 		frac = (parent_rate * f) / FRAC_DIV;
--- linux-ein-5.4.0.orig/drivers/clocksource/Kconfig
+++ linux-ein-5.4.0/drivers/clocksource/Kconfig
@@ -24,6 +24,7 @@
 
 config OMAP_DM_TIMER
 	bool
+	select TIMER_OF
 
 config CLKBLD_I8253
 	def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK
@@ -79,6 +80,7 @@
 	bool "Intel XScale IXP4xx timer driver" if COMPILE_TEST
 	depends on HAS_IOMEM
 	select CLKSRC_MMIO
+	select TIMER_OF if OF
 	help
 	  Enables support for the Intel XScale IXP4xx SoC timer.
 
--- linux-ein-5.4.0.orig/drivers/clocksource/acpi_pm.c
+++ linux-ein-5.4.0/drivers/clocksource/acpi_pm.c
@@ -229,8 +229,10 @@
 	int ret;
 
 	ret = kstrtouint(arg, 16, &base);
-	if (ret)
-		return ret;
+	if (ret) {
+		pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg);
+		return 1;
+	}
 
 	pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport,
 		base);
--- linux-ein-5.4.0.orig/drivers/clocksource/arm_arch_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/arm_arch_timer.c
@@ -69,7 +69,7 @@
 static bool arch_timer_c3stop;
 static bool arch_timer_mem_use_virtual;
 static bool arch_counter_suspend_stop;
-static bool vdso_default = true;
+static enum vdso_arch_clockmode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
 
 static cpumask_t evtstrm_available = CPU_MASK_NONE;
 static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
@@ -348,7 +348,7 @@
 	do {								\
 		_val = read_sysreg(reg);				\
 		_retries--;						\
-	} while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries);	\
+	} while (((_val + 1) & GENMASK(8, 0)) <= 1 && _retries);	\
 									\
 	WARN_ON_ONCE(!_retries);					\
 	_val;								\
@@ -392,10 +392,10 @@
 	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
 
 	if (access == ARCH_TIMER_PHYS_ACCESS) {
-		cval = evt + arch_counter_get_cntpct();
+		cval = evt + arch_counter_get_cntpct_stable();
 		write_sysreg(cval, cntp_cval_el0);
 	} else {
-		cval = evt + arch_counter_get_cntvct();
+		cval = evt + arch_counter_get_cntvct_stable();
 		write_sysreg(cval, cntv_cval_el0);
 	}
 
@@ -476,6 +476,14 @@
 		.set_next_event_virt = erratum_set_next_event_tval_virt,
 	},
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_1418040
+	{
+		.match_type = ate_match_local_cap_id,
+		.id = (void *)ARM64_WORKAROUND_1418040,
+		.desc = "ARM erratum 1418040",
+		.disable_compat_vdso = true,
+	},
+#endif
 };
 
 typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *,
@@ -560,8 +568,11 @@
 	 * change both the default value and the vdso itself.
 	 */
 	if (wa->read_cntvct_el0) {
-		clocksource_counter.archdata.vdso_direct = false;
-		vdso_default = false;
+		clocksource_counter.archdata.clock_mode = VDSO_CLOCKMODE_NONE;
+		vdso_default = VDSO_CLOCKMODE_NONE;
+	} else if (wa->disable_compat_vdso && vdso_default != VDSO_CLOCKMODE_NONE) {
+		vdso_default = VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT;
+		clocksource_counter.archdata.clock_mode = vdso_default;
 	}
 }
 
@@ -807,15 +818,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)
@@ -979,7 +999,7 @@
 		}
 
 		arch_timer_read_counter = rd;
-		clocksource_counter.archdata.vdso_direct = vdso_default;
+		clocksource_counter.archdata.clock_mode = vdso_default;
 	} else {
 		arch_timer_read_counter = arch_counter_get_cntvct_mem;
 	}
--- linux-ein-5.4.0.orig/drivers/clocksource/asm9260_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/asm9260_timer.c
@@ -194,6 +194,10 @@
 	}
 
 	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-ein-5.4.0.orig/drivers/clocksource/bcm2835_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/bcm2835_timer.c
@@ -121,7 +121,7 @@
 	ret = setup_irq(irq, &timer->act);
 	if (ret) {
 		pr_err("Can't set up timer IRQ\n");
-		goto err_iounmap;
+		goto err_timer_free;
 	}
 
 	clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
@@ -130,6 +130,9 @@
 
 	return 0;
 
+err_timer_free:
+	kfree(timer);
+
 err_iounmap:
 	iounmap(base);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/clocksource/dw_apb_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/dw_apb_timer.c
@@ -222,7 +222,8 @@
 /**
  * dw_apb_clockevent_init() - use an APB timer as a clock_event_device
  *
- * @cpu:	The CPU the events will be targeted at.
+ * @cpu:	The CPU the events will be targeted at or -1 if CPU affiliation
+ *		isn't required.
  * @name:	The name used for the timer and the IRQ for it.
  * @rating:	The rating to give the timer.
  * @base:	I/O base for the timer registers.
@@ -257,7 +258,7 @@
 	dw_ced->ced.max_delta_ticks = 0x7fffffff;
 	dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
 	dw_ced->ced.min_delta_ticks = 5000;
-	dw_ced->ced.cpumask = cpumask_of(cpu);
+	dw_ced->ced.cpumask = cpu < 0 ? cpu_possible_mask : cpumask_of(cpu);
 	dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
 				CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
 	dw_ced->ced.set_state_shutdown = apbt_shutdown;
--- linux-ein-5.4.0.orig/drivers/clocksource/dw_apb_timer_of.c
+++ linux-ein-5.4.0/drivers/clocksource/dw_apb_timer_of.c
@@ -147,10 +147,6 @@
 static int __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);
@@ -161,6 +157,8 @@
 #endif
 		break;
 	default:
+		pr_debug("%s: found clockevent timer\n", __func__);
+		add_clockevent(timer);
 		break;
 	}
 
--- linux-ein-5.4.0.orig/drivers/clocksource/h8300_timer8.c
+++ linux-ein-5.4.0/drivers/clocksource/h8300_timer8.c
@@ -169,7 +169,7 @@
 		return PTR_ERR(clk);
 	}
 
-	ret = ENXIO;
+	ret = -ENXIO;
 	base = of_iomap(node, 0);
 	if (!base) {
 		pr_err("failed to map registers for clockevent\n");
--- linux-ein-5.4.0.orig/drivers/clocksource/hyperv_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/hyperv_timer.c
@@ -233,7 +233,8 @@
 
 static u64 read_hv_sched_clock_tsc(void)
 {
-	return read_hv_clock_tsc(NULL) - hv_sched_clock_offset;
+	return (read_hv_clock_tsc(NULL) - hv_sched_clock_offset) *
+		(NSEC_PER_SEC / HV_CLOCK_HZ);
 }
 
 static struct clocksource hyperv_cs_tsc = {
@@ -258,7 +259,8 @@
 
 static u64 read_hv_sched_clock_msr(void)
 {
-	return read_hv_clock_msr(NULL) - hv_sched_clock_offset;
+	return (read_hv_clock_msr(NULL) - hv_sched_clock_offset) *
+		(NSEC_PER_SEC / HV_CLOCK_HZ);
 }
 
 static struct clocksource hyperv_cs_msr = {
@@ -323,4 +325,3 @@
 	hv_sched_clock_offset = hyperv_cs->read(hyperv_cs);
 	hv_setup_sched_clock(read_hv_sched_clock_msr);
 }
-EXPORT_SYMBOL_GPL(hv_init_clocksource);
--- linux-ein-5.4.0.orig/drivers/clocksource/mxs_timer.c
+++ linux-ein-5.4.0/drivers/clocksource/mxs_timer.c
@@ -138,10 +138,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-ein-5.4.0.orig/drivers/clocksource/sh_cmt.c
+++ linux-ein-5.4.0/drivers/clocksource/sh_cmt.c
@@ -231,6 +231,8 @@
 #define CMCNT 1 /* channel register */
 #define CMCOR 2 /* channel register */
 
+#define CMCLKE	0x1000	/* CLK Enable Register (R-Car Gen2) */
+
 static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
 {
 	if (ch->iostart)
@@ -568,7 +570,8 @@
 	ch->flags |= flag;
 
 	/* setup timeout if no clockevent */
-	if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
+	if (ch->cmt->num_channels == 1 &&
+	    flag == FLAG_CLOCKSOURCE && (!(ch->flags & FLAG_CLOCKEVENT)))
 		__sh_cmt_set_next(ch, ch->max_match_value);
  out:
 	raw_spin_unlock_irqrestore(&ch->lock, flags);
@@ -604,20 +607,25 @@
 static u64 sh_cmt_clocksource_read(struct clocksource *cs)
 {
 	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
-	unsigned long flags;
 	u32 has_wrapped;
-	u64 value;
-	u32 raw;
 
-	raw_spin_lock_irqsave(&ch->lock, flags);
-	value = ch->total_cycles;
-	raw = sh_cmt_get_counter(ch, &has_wrapped);
+	if (ch->cmt->num_channels == 1) {
+		unsigned long flags;
+		u64 value;
+		u32 raw;
 
-	if (unlikely(has_wrapped))
-		raw += ch->match_value + 1;
-	raw_spin_unlock_irqrestore(&ch->lock, flags);
+		raw_spin_lock_irqsave(&ch->lock, flags);
+		value = ch->total_cycles;
+		raw = sh_cmt_get_counter(ch, &has_wrapped);
 
-	return value + raw;
+		if (unlikely(has_wrapped))
+			raw += ch->match_value + 1;
+		raw_spin_unlock_irqrestore(&ch->lock, flags);
+
+		return value + raw;
+	}
+
+	return sh_cmt_get_counter(ch, &has_wrapped);
 }
 
 static int sh_cmt_clocksource_enable(struct clocksource *cs)
@@ -680,7 +688,7 @@
 	cs->disable = sh_cmt_clocksource_disable;
 	cs->suspend = sh_cmt_clocksource_suspend;
 	cs->resume = sh_cmt_clocksource_resume;
-	cs->mask = CLOCKSOURCE_MASK(sizeof(u64) * 8);
+	cs->mask = CLOCKSOURCE_MASK(ch->cmt->info->width);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 
 	dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
@@ -839,6 +847,7 @@
 				unsigned int hwidx, bool clockevent,
 				bool clocksource, struct sh_cmt_device *cmt)
 {
+	u32 value;
 	int ret;
 
 	/* Skip unused channels. */
@@ -868,6 +877,11 @@
 		ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
 		ch->ioctrl = ch->iostart + 0x10;
 		ch->timer_bit = 0;
+
+		/* Enable the clock supply to the channel */
+		value = ioread32(cmt->mapbase + CMCLKE);
+		value |= BIT(hwidx);
+		iowrite32(value, cmt->mapbase + CMCLKE);
 		break;
 	}
 
@@ -1000,12 +1014,10 @@
 	else
 		cmt->rate = clk_get_rate(cmt->clk) / 8;
 
-	clk_disable(cmt->clk);
-
 	/* Map the memory resource(s). */
 	ret = sh_cmt_map_memory(cmt);
 	if (ret < 0)
-		goto err_clk_unprepare;
+		goto err_clk_disable;
 
 	/* Allocate and setup the channels. */
 	cmt->num_channels = hweight8(cmt->hw_channels);
@@ -1033,6 +1045,8 @@
 		mask &= ~(1 << hwidx);
 	}
 
+	clk_disable(cmt->clk);
+
 	platform_set_drvdata(pdev, cmt);
 
 	return 0;
@@ -1040,6 +1054,8 @@
 err_unmap:
 	kfree(cmt->channels);
 	iounmap(cmt->mapbase);
+err_clk_disable:
+	clk_disable(cmt->clk);
 err_clk_unprepare:
 	clk_unprepare(cmt->clk);
 err_clk_put:
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-atmel-tcb.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-atmel-tcb.c
@@ -310,6 +310,7 @@
 	writel(mck_divisor_idx			/* likely divide-by-8 */
 			| ATMEL_TC_WAVE
 			| ATMEL_TC_WAVESEL_UP		/* free-run */
+			| ATMEL_TC_ASWTRG_SET		/* TIOA0 rises at software trigger */
 			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */
 			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */
 			tcaddr + ATMEL_TC_REG(0, CMR));
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-cadence-ttc.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-cadence-ttc.c
@@ -15,6 +15,8 @@
 #include <linux/of_irq.h>
 #include <linux/slab.h>
 #include <linux/sched_clock.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
 
 /*
  * This driver configures the 2 16/32-bit count-up timers as follows:
@@ -411,10 +413,8 @@
 	ttcce->ttc.clk = clk;
 
 	err = clk_prepare_enable(ttcce->ttc.clk);
-	if (err) {
-		kfree(ttcce);
-		return err;
-	}
+	if (err)
+		goto out_kfree;
 
 	ttcce->ttc.clk_rate_change_nb.notifier_call =
 		ttc_rate_change_clockevent_cb;
@@ -424,7 +424,7 @@
 				    &ttcce->ttc.clk_rate_change_nb);
 	if (err) {
 		pr_warn("Unable to register clock notifier.\n");
-		return err;
+		goto out_kfree;
 	}
 
 	ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk);
@@ -453,24 +453,20 @@
 
 	err = request_irq(irq, ttc_clock_event_interrupt,
 			  IRQF_TIMER, ttcce->ce.name, ttcce);
-	if (err) {
-		kfree(ttcce);
-		return err;
-	}
+	if (err)
+		goto out_kfree;
 
 	clockevents_config_and_register(&ttcce->ce,
 			ttcce->ttc.freq / PRESCALE, 1, 0xfffe);
 
 	return 0;
+
+out_kfree:
+	kfree(ttcce);
+	return err;
 }
 
-/**
- * ttc_timer_init - Initialize the timer
- *
- * Initializes the timer hardware and register the clock source and clock event
- * timers with Linux kernal timer framework
- */
-static int __init ttc_timer_init(struct device_node *timer)
+static int __init ttc_timer_probe(struct platform_device *pdev)
 {
 	unsigned int irq;
 	void __iomem *timer_baseaddr;
@@ -478,6 +474,7 @@
 	static int initialized;
 	int clksel, ret;
 	u32 timer_width = 16;
+	struct device_node *timer = pdev->dev.of_node;
 
 	if (initialized)
 		return 0;
@@ -489,10 +486,10 @@
 	 * and use it. Note that the event timer uses the interrupt and it's the
 	 * 2nd TTC hence the irq_of_parse_and_map(,1)
 	 */
-	timer_baseaddr = of_iomap(timer, 0);
-	if (!timer_baseaddr) {
+	timer_baseaddr = devm_of_iomap(&pdev->dev, timer, 0, NULL);
+	if (IS_ERR(timer_baseaddr)) {
 		pr_err("ERROR: invalid timer base address\n");
-		return -ENXIO;
+		return PTR_ERR(timer_baseaddr);
 	}
 
 	irq = irq_of_parse_and_map(timer, 1);
@@ -516,20 +513,40 @@
 	clk_ce = of_clk_get(timer, clksel);
 	if (IS_ERR(clk_ce)) {
 		pr_err("ERROR: timer input clock not found\n");
-		return PTR_ERR(clk_ce);
+		ret = PTR_ERR(clk_ce);
+		goto put_clk_cs;
 	}
 
 	ret = ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width);
 	if (ret)
-		return ret;
+		goto put_clk_ce;
 
 	ret = ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq);
 	if (ret)
-		return ret;
+		goto put_clk_ce;
 
 	pr_info("%pOFn #0 at %p, irq=%d\n", timer, timer_baseaddr, irq);
 
 	return 0;
+
+put_clk_ce:
+	clk_put(clk_ce);
+put_clk_cs:
+	clk_put(clk_cs);
+	return ret;
 }
 
-TIMER_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init);
+static const struct of_device_id ttc_timer_of_match[] = {
+	{.compatible = "cdns,ttc"},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, ttc_timer_of_match);
+
+static struct platform_driver ttc_timer_driver = {
+	.driver = {
+		.name	= "cdns_ttc_timer",
+		.of_match_table = ttc_timer_of_match,
+	},
+};
+builtin_platform_driver_probe(ttc_timer_driver, ttc_timer_probe);
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-davinci.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-davinci.c
@@ -18,7 +18,7 @@
 #include <clocksource/timer-davinci.h>
 
 #undef pr_fmt
-#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+#define pr_fmt(fmt) "%s: " fmt, __func__
 
 #define DAVINCI_TIMER_REG_TIM12			0x10
 #define DAVINCI_TIMER_REG_TIM34			0x14
@@ -250,30 +250,32 @@
 
 	rv = clk_prepare_enable(clk);
 	if (rv) {
-		pr_err("Unable to prepare and enable the timer clock");
+		pr_err("Unable to prepare and enable the timer clock\n");
 		return rv;
 	}
 
 	if (!request_mem_region(timer_cfg->reg.start,
 				resource_size(&timer_cfg->reg),
 				"davinci-timer")) {
-		pr_err("Unable to request memory region");
-		return -EBUSY;
+		pr_err("Unable to request memory region\n");
+		rv = -EBUSY;
+		goto exit_clk_disable;
 	}
 
 	base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg));
 	if (!base) {
-		pr_err("Unable to map the register range");
-		return -ENOMEM;
+		pr_err("Unable to map the register range\n");
+		rv = -ENOMEM;
+		goto exit_mem_region;
 	}
 
 	davinci_timer_init(base);
 	tick_rate = clk_get_rate(clk);
 
-	clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL | __GFP_NOFAIL);
+	clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL);
 	if (!clockevent) {
-		pr_err("Error allocating memory for clockevent data");
-		return -ENOMEM;
+		rv = -ENOMEM;
+		goto exit_iounmap_base;
 	}
 
 	clockevent->dev.name = "tim12";
@@ -298,14 +300,10 @@
 			 davinci_timer_irq_timer, IRQF_TIMER,
 			 "clockevent/tim12", clockevent);
 	if (rv) {
-		pr_err("Unable to request the clockevent interrupt");
-		return rv;
+		pr_err("Unable to request the clockevent interrupt\n");
+		goto exit_free_clockevent;
 	}
 
-	clockevents_config_and_register(&clockevent->dev, tick_rate,
-					DAVINCI_TIMER_MIN_DELTA,
-					DAVINCI_TIMER_MAX_DELTA);
-
 	davinci_clocksource.dev.rating = 300;
 	davinci_clocksource.dev.read = davinci_clocksource_read;
 	davinci_clocksource.dev.mask =
@@ -323,16 +321,34 @@
 		davinci_clocksource_init_tim34(base);
 	}
 
+	clockevents_config_and_register(&clockevent->dev, tick_rate,
+					DAVINCI_TIMER_MIN_DELTA,
+					DAVINCI_TIMER_MAX_DELTA);
+
 	rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate);
 	if (rv) {
-		pr_err("Unable to register clocksource");
-		return rv;
+		pr_err("Unable to register clocksource\n");
+		goto exit_free_irq;
 	}
 
 	sched_clock_register(davinci_timer_read_sched_clock,
 			     DAVINCI_TIMER_CLKSRC_BITS, tick_rate);
 
 	return 0;
+
+exit_free_irq:
+	free_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start,
+			clockevent);
+exit_free_clockevent:
+	kfree(clockevent);
+exit_iounmap_base:
+	iounmap(base);
+exit_mem_region:
+	release_mem_region(timer_cfg->reg.start,
+			   resource_size(&timer_cfg->reg));
+exit_clk_disable:
+	clk_disable_unprepare(clk);
+	return rv;
 }
 
 static int __init of_davinci_timer_register(struct device_node *np)
@@ -343,20 +359,20 @@
 
 	rv = of_address_to_resource(np, 0, &timer_cfg.reg);
 	if (rv) {
-		pr_err("Unable to get the register range for timer");
+		pr_err("Unable to get the register range for timer\n");
 		return rv;
 	}
 
 	rv = of_irq_to_resource_table(np, timer_cfg.irq,
 				      DAVINCI_TIMER_NUM_IRQS);
 	if (rv != DAVINCI_TIMER_NUM_IRQS) {
-		pr_err("Unable to get the interrupts for timer");
+		pr_err("Unable to get the interrupts for timer\n");
 		return rv;
 	}
 
 	clk = of_clk_get(np, 0);
 	if (IS_ERR(clk)) {
-		pr_err("Unable to get the timer clock");
+		pr_err("Unable to get the timer clock\n");
 		return PTR_ERR(clk);
 	}
 
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-gx6605s.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-gx6605s.c
@@ -28,6 +28,7 @@
 	void __iomem *base = timer_of_base(to_timer_of(ce));
 
 	writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS);
+	writel_relaxed(0, base + TIMER_INI);
 
 	ce->event_handler(ce);
 
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-imx-gpt.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-imx-gpt.c
@@ -460,12 +460,16 @@
 		return -ENOMEM;
 
 	imxtm->base = of_iomap(np, 0);
-	if (!imxtm->base)
-		return -ENXIO;
+	if (!imxtm->base) {
+		ret = -ENXIO;
+		goto err_kfree;
+	}
 
 	imxtm->irq = irq_of_parse_and_map(np, 0);
-	if (imxtm->irq <= 0)
-		return -EINVAL;
+	if (imxtm->irq <= 0) {
+		ret = -EINVAL;
+		goto err_kfree;
+	}
 
 	imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
 
@@ -478,11 +482,15 @@
 
 	ret = _mxc_timer_init(imxtm);
 	if (ret)
-		return ret;
+		goto err_kfree;
 
 	initialized = 1;
 
 	return 0;
+
+err_kfree:
+	kfree(imxtm);
+	return ret;
 }
 
 static int __init imx1_timer_init_dt(struct device_node *np)
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-ixp4xx.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-ixp4xx.c
@@ -258,7 +258,6 @@
 	}
 	ixp4xx_timer_register(base, timer_irq, timer_freq);
 }
-EXPORT_SYMBOL_GPL(ixp4xx_timer_setup);
 
 #ifdef CONFIG_OF
 static __init int ixp4xx_of_timer_init(struct device_node *np)
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-of.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-of.c
@@ -157,9 +157,9 @@
 	of_base->base = of_base->name ?
 		of_io_request_and_map(np, of_base->index, of_base->name) :
 		of_iomap(np, of_base->index);
-	if (IS_ERR(of_base->base)) {
-		pr_err("Failed to iomap (%s)\n", of_base->name);
-		return PTR_ERR(of_base->base);
+	if (IS_ERR_OR_NULL(of_base->base)) {
+		pr_err("Failed to iomap (%s:%s)\n", np->name, of_base->name);
+		return of_base->base ? PTR_ERR(of_base->base) : -ENOMEM;
 	}
 
 	return 0;
@@ -192,7 +192,7 @@
 	}
 
 	if (!to->clkevt.name)
-		to->clkevt.name = np->name;
+		to->clkevt.name = np->full_name;
 
 	to->np = np;
 
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-orion.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-orion.c
@@ -149,7 +149,8 @@
 	irq = irq_of_parse_and_map(np, 1);
 	if (irq <= 0) {
 		pr_err("%pOFn: unable to parse timer1 irq\n", np);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out_unprep_clk;
 	}
 
 	rate = clk_get_rate(clk);
@@ -166,7 +167,7 @@
 				    clocksource_mmio_readl_down);
 	if (ret) {
 		pr_err("Failed to initialize mmio timer\n");
-		return ret;
+		goto out_unprep_clk;
 	}
 
 	sched_clock_register(orion_read_sched_clock, 32, rate);
@@ -175,7 +176,7 @@
 	ret = setup_irq(irq, &orion_clkevt_irq);
 	if (ret) {
 		pr_err("%pOFn: unable to setup irq\n", np);
-		return ret;
+		goto out_unprep_clk;
 	}
 
 	ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
@@ -188,5 +189,9 @@
 	orion_delay_timer_init(rate);
 
 	return 0;
+
+out_unprep_clk:
+	clk_disable_unprepare(clk);
+	return ret;
 }
 TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-oxnas-rps.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-oxnas-rps.c
@@ -236,7 +236,7 @@
 	}
 
 	rps->irq = irq_of_parse_and_map(np, 0);
-	if (rps->irq < 0) {
+	if (!rps->irq) {
 		ret = -EINVAL;
 		goto err_iomap;
 	}
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-riscv.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-riscv.c
@@ -41,7 +41,7 @@
 	return get_cycles64();
 }
 
-static u64 riscv_sched_clock(void)
+static u64 notrace riscv_sched_clock(void)
 {
 	return get_cycles64();
 }
--- linux-ein-5.4.0.orig/drivers/clocksource/timer-sp804.c
+++ linux-ein-5.4.0/drivers/clocksource/timer-sp804.c
@@ -215,6 +215,11 @@
 	struct clk *clk1, *clk2;
 	const char *name = of_get_property(np, "compatible", NULL);
 
+	if (initialized) {
+		pr_debug("%pOF: skipping further SP804 timer device\n", np);
+		return 0;
+	}
+
 	base = of_iomap(np, 0);
 	if (!base)
 		return -ENXIO;
@@ -223,11 +228,6 @@
 	writel(0, base + TIMER_CTRL);
 	writel(0, base + TIMER_2_BASE + TIMER_CTRL);
 
-	if (initialized || !of_device_is_available(np)) {
-		ret = -EINVAL;
-		goto err;
-	}
-
 	clk1 = of_clk_get(np, 0);
 	if (IS_ERR(clk1))
 		clk1 = NULL;
--- linux-ein-5.4.0.orig/drivers/counter/104-quad-8.c
+++ linux-ein-5.4.0/drivers/counter/104-quad-8.c
@@ -42,6 +42,7 @@
  * @base:		base port address of the IIO device
  */
 struct quad8_iio {
+	struct mutex lock;
 	struct counter_device counter;
 	unsigned int preset[QUAD8_NUM_COUNTERS];
 	unsigned int count_mode[QUAD8_NUM_COUNTERS];
@@ -56,10 +57,6 @@
 
 #define QUAD8_REG_CHAN_OP 0x11
 #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
-/* Borrow Toggle flip-flop */
-#define QUAD8_FLAG_BT BIT(0)
-/* Carry Toggle flip-flop */
-#define QUAD8_FLAG_CT BIT(1)
 /* Error flag */
 #define QUAD8_FLAG_E BIT(4)
 /* Up/Down flag */
@@ -96,9 +93,6 @@
 {
 	struct quad8_iio *const priv = iio_priv(indio_dev);
 	const int base_offset = priv->base + 2 * chan->channel;
-	unsigned int flags;
-	unsigned int borrow;
-	unsigned int carry;
 	int i;
 
 	switch (mask) {
@@ -109,12 +103,9 @@
 			return IIO_VAL_INT;
 		}
 
-		flags = inb(base_offset + 1);
-		borrow = flags & QUAD8_FLAG_BT;
-		carry = !!(flags & QUAD8_FLAG_CT);
+		*val = 0;
 
-		/* Borrow XOR Carry effectively doubles count range */
-		*val = (borrow ^ carry) << 24;
+		mutex_lock(&priv->lock);
 
 		/* Reset Byte Pointer; transfer Counter to Output Latch */
 		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
@@ -123,6 +114,8 @@
 		for (i = 0; i < 3; i++)
 			*val |= (unsigned int)inb(base_offset) << (8 * i);
 
+		mutex_unlock(&priv->lock);
+
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_ENABLE:
 		*val = priv->ab_enable[chan->channel];
@@ -153,6 +146,8 @@
 		if ((unsigned int)val > 0xFFFFFF)
 			return -EINVAL;
 
+		mutex_lock(&priv->lock);
+
 		/* Reset Byte Pointer */
 		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 
@@ -176,12 +171,16 @@
 		/* Reset Error flag */
 		outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
 
+		mutex_unlock(&priv->lock);
+
 		return 0;
 	case IIO_CHAN_INFO_ENABLE:
 		/* only boolean values accepted */
 		if (val < 0 || val > 1)
 			return -EINVAL;
 
+		mutex_lock(&priv->lock);
+
 		priv->ab_enable[chan->channel] = val;
 
 		ior_cfg = val | priv->preset_enable[chan->channel] << 1;
@@ -189,11 +188,18 @@
 		/* Load I/O control configuration */
 		outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
 
+		mutex_unlock(&priv->lock);
+
 		return 0;
 	case IIO_CHAN_INFO_SCALE:
+		mutex_lock(&priv->lock);
+
 		/* Quadrature scaling only available in quadrature mode */
-		if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1))
+		if (!priv->quadrature_mode[chan->channel] &&
+				(val2 || val != 1)) {
+			mutex_unlock(&priv->lock);
 			return -EINVAL;
+		}
 
 		/* Only three gain states (1, 0.5, 0.25) */
 		if (val == 1 && !val2)
@@ -207,11 +213,15 @@
 				priv->quadrature_scale[chan->channel] = 2;
 				break;
 			default:
+				mutex_unlock(&priv->lock);
 				return -EINVAL;
 			}
-		else
+		else {
+			mutex_unlock(&priv->lock);
 			return -EINVAL;
+		}
 
+		mutex_unlock(&priv->lock);
 		return 0;
 	}
 
@@ -248,6 +258,8 @@
 	if (preset > 0xFFFFFF)
 		return -EINVAL;
 
+	mutex_lock(&priv->lock);
+
 	priv->preset[chan->channel] = preset;
 
 	/* Reset Byte Pointer */
@@ -257,6 +269,8 @@
 	for (i = 0; i < 3; i++)
 		outb(preset >> (8 * i), base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return len;
 }
 
@@ -286,6 +300,8 @@
 	/* Preset enable is active low in Input/Output Control register */
 	preset_enable = !preset_enable;
 
+	mutex_lock(&priv->lock);
+
 	priv->preset_enable[chan->channel] = preset_enable;
 
 	ior_cfg = priv->ab_enable[chan->channel] |
@@ -294,6 +310,8 @@
 	/* Load I/O control configuration to Input / Output Control Register */
 	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return len;
 }
 
@@ -351,6 +369,8 @@
 	unsigned int mode_cfg = cnt_mode << 1;
 	const int base_offset = priv->base + 2 * chan->channel + 1;
 
+	mutex_lock(&priv->lock);
+
 	priv->count_mode[chan->channel] = cnt_mode;
 
 	/* Add quadrature mode configuration */
@@ -360,6 +380,8 @@
 	/* Load mode configuration to Counter Mode Register */
 	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -387,19 +409,26 @@
 	const struct iio_chan_spec *chan, unsigned int synchronous_mode)
 {
 	struct quad8_iio *const priv = iio_priv(indio_dev);
-	const unsigned int idr_cfg = synchronous_mode |
-		priv->index_polarity[chan->channel] << 1;
 	const int base_offset = priv->base + 2 * chan->channel + 1;
+	unsigned int idr_cfg = synchronous_mode;
+
+	mutex_lock(&priv->lock);
+
+	idr_cfg |= priv->index_polarity[chan->channel] << 1;
 
 	/* Index function must be non-synchronous in non-quadrature mode */
-	if (synchronous_mode && !priv->quadrature_mode[chan->channel])
+	if (synchronous_mode && !priv->quadrature_mode[chan->channel]) {
+		mutex_unlock(&priv->lock);
 		return -EINVAL;
+	}
 
 	priv->synchronous_mode[chan->channel] = synchronous_mode;
 
 	/* Load Index Control configuration to Index Control Register */
 	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -427,8 +456,12 @@
 	const struct iio_chan_spec *chan, unsigned int quadrature_mode)
 {
 	struct quad8_iio *const priv = iio_priv(indio_dev);
-	unsigned int mode_cfg = priv->count_mode[chan->channel] << 1;
 	const int base_offset = priv->base + 2 * chan->channel + 1;
+	unsigned int mode_cfg;
+
+	mutex_lock(&priv->lock);
+
+	mode_cfg = priv->count_mode[chan->channel] << 1;
 
 	if (quadrature_mode)
 		mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
@@ -446,6 +479,8 @@
 	/* Load mode configuration to Counter Mode Register */
 	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -473,15 +508,20 @@
 	const struct iio_chan_spec *chan, unsigned int index_polarity)
 {
 	struct quad8_iio *const priv = iio_priv(indio_dev);
-	const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] |
-		index_polarity << 1;
 	const int base_offset = priv->base + 2 * chan->channel + 1;
+	unsigned int idr_cfg = index_polarity << 1;
+
+	mutex_lock(&priv->lock);
+
+	idr_cfg |= priv->synchronous_mode[chan->channel];
 
 	priv->index_polarity[chan->channel] = index_polarity;
 
 	/* Load Index Control configuration to Index Control Register */
 	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -585,20 +625,12 @@
 static int quad8_count_read(struct counter_device *counter,
 	struct counter_count *count, struct counter_count_read_value *val)
 {
-	const struct quad8_iio *const priv = counter->priv;
+	struct quad8_iio *const priv = counter->priv;
 	const int base_offset = priv->base + 2 * count->id;
-	unsigned int flags;
-	unsigned int borrow;
-	unsigned int carry;
-	unsigned long position;
+	unsigned long position = 0;
 	int i;
 
-	flags = inb(base_offset + 1);
-	borrow = flags & QUAD8_FLAG_BT;
-	carry = !!(flags & QUAD8_FLAG_CT);
-
-	/* Borrow XOR Carry effectively doubles count range */
-	position = (unsigned long)(borrow ^ carry) << 24;
+	mutex_lock(&priv->lock);
 
 	/* Reset Byte Pointer; transfer Counter to Output Latch */
 	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
@@ -609,13 +641,15 @@
 
 	counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
 static int quad8_count_write(struct counter_device *counter,
 	struct counter_count *count, struct counter_count_write_value *val)
 {
-	const struct quad8_iio *const priv = counter->priv;
+	struct quad8_iio *const priv = counter->priv;
 	const int base_offset = priv->base + 2 * count->id;
 	int err;
 	unsigned long position;
@@ -630,6 +664,8 @@
 	if (position > 0xFFFFFF)
 		return -EINVAL;
 
+	mutex_lock(&priv->lock);
+
 	/* Reset Byte Pointer */
 	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
 
@@ -653,6 +689,8 @@
 	/* Reset Error flag */
 	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -673,13 +711,13 @@
 static int quad8_function_get(struct counter_device *counter,
 	struct counter_count *count, size_t *function)
 {
-	const struct quad8_iio *const priv = counter->priv;
+	struct quad8_iio *const priv = counter->priv;
 	const int id = count->id;
-	const unsigned int quadrature_mode = priv->quadrature_mode[id];
-	const unsigned int scale = priv->quadrature_scale[id];
 
-	if (quadrature_mode)
-		switch (scale) {
+	mutex_lock(&priv->lock);
+
+	if (priv->quadrature_mode[id])
+		switch (priv->quadrature_scale[id]) {
 		case 0:
 			*function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1;
 			break;
@@ -693,6 +731,8 @@
 	else
 		*function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION;
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -703,10 +743,15 @@
 	const int id = count->id;
 	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
 	unsigned int *const scale = priv->quadrature_scale + id;
-	unsigned int mode_cfg = priv->count_mode[id] << 1;
 	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
-	const unsigned int idr_cfg = priv->index_polarity[id] << 1;
 	const int base_offset = priv->base + 2 * id + 1;
+	unsigned int mode_cfg;
+	unsigned int idr_cfg;
+
+	mutex_lock(&priv->lock);
+
+	mode_cfg = priv->count_mode[id] << 1;
+	idr_cfg = priv->index_polarity[id] << 1;
 
 	if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) {
 		*quadrature_mode = 0;
@@ -742,6 +787,8 @@
 	/* Load mode configuration to Counter Mode Register */
 	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -858,15 +905,20 @@
 {
 	struct quad8_iio *const priv = counter->priv;
 	const size_t channel_id = signal->id - 16;
-	const unsigned int idr_cfg = priv->synchronous_mode[channel_id] |
-		index_polarity << 1;
 	const int base_offset = priv->base + 2 * channel_id + 1;
+	unsigned int idr_cfg = index_polarity << 1;
+
+	mutex_lock(&priv->lock);
+
+	idr_cfg |= priv->synchronous_mode[channel_id];
 
 	priv->index_polarity[channel_id] = index_polarity;
 
 	/* Load Index Control configuration to Index Control Register */
 	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -893,19 +945,26 @@
 {
 	struct quad8_iio *const priv = counter->priv;
 	const size_t channel_id = signal->id - 16;
-	const unsigned int idr_cfg = synchronous_mode |
-		priv->index_polarity[channel_id] << 1;
 	const int base_offset = priv->base + 2 * channel_id + 1;
+	unsigned int idr_cfg = synchronous_mode;
+
+	mutex_lock(&priv->lock);
+
+	idr_cfg |= priv->index_polarity[channel_id] << 1;
 
 	/* Index function must be non-synchronous in non-quadrature mode */
-	if (synchronous_mode && !priv->quadrature_mode[channel_id])
+	if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
+		mutex_unlock(&priv->lock);
 		return -EINVAL;
+	}
 
 	priv->synchronous_mode[channel_id] = synchronous_mode;
 
 	/* Load Index Control configuration to Index Control Register */
 	outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -970,6 +1029,8 @@
 		break;
 	}
 
+	mutex_lock(&priv->lock);
+
 	priv->count_mode[count->id] = cnt_mode;
 
 	/* Set count mode configuration value */
@@ -982,6 +1043,8 @@
 	/* Load mode configuration to Counter Mode Register */
 	outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return 0;
 }
 
@@ -1023,6 +1086,8 @@
 	if (err)
 		return err;
 
+	mutex_lock(&priv->lock);
+
 	priv->ab_enable[count->id] = ab_enable;
 
 	ior_cfg = ab_enable | priv->preset_enable[count->id] << 1;
@@ -1030,6 +1095,8 @@
 	/* Load I/O control configuration */
 	outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
 
+	mutex_unlock(&priv->lock);
+
 	return len;
 }
 
@@ -1058,14 +1125,28 @@
 	return sprintf(buf, "%u\n", priv->preset[count->id]);
 }
 
+static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id,
+		unsigned int preset)
+{
+	const unsigned int base_offset = quad8iio->base + 2 * id;
+	int i;
+
+	quad8iio->preset[id] = preset;
+
+	/* Reset Byte Pointer */
+	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+
+	/* Set Preset Register */
+	for (i = 0; i < 3; i++)
+		outb(preset >> (8 * i), base_offset);
+}
+
 static ssize_t quad8_count_preset_write(struct counter_device *counter,
 	struct counter_count *count, void *private, const char *buf, size_t len)
 {
 	struct quad8_iio *const priv = counter->priv;
-	const int base_offset = priv->base + 2 * count->id;
 	unsigned int preset;
 	int ret;
-	int i;
 
 	ret = kstrtouint(buf, 0, &preset);
 	if (ret)
@@ -1075,14 +1156,11 @@
 	if (preset > 0xFFFFFF)
 		return -EINVAL;
 
-	priv->preset[count->id] = preset;
+	mutex_lock(&priv->lock);
 
-	/* Reset Byte Pointer */
-	outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+	quad8_preset_register_set(priv, count->id, preset);
 
-	/* Set Preset Register */
-	for (i = 0; i < 3; i++)
-		outb(preset >> (8 * i), base_offset);
+	mutex_unlock(&priv->lock);
 
 	return len;
 }
@@ -1090,33 +1168,53 @@
 static ssize_t quad8_count_ceiling_read(struct counter_device *counter,
 	struct counter_count *count, void *private, char *buf)
 {
-	const struct quad8_iio *const priv = counter->priv;
+	struct quad8_iio *const priv = counter->priv;
+
+	mutex_lock(&priv->lock);
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 	switch (priv->count_mode[count->id]) {
 	case 1:
 	case 3:
-		return quad8_count_preset_read(counter, count, private, buf);
+		mutex_unlock(&priv->lock);
+		return sprintf(buf, "%u\n", priv->preset[count->id]);
 	}
 
-	/* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
-	return sprintf(buf, "33554431\n");
+	mutex_unlock(&priv->lock);
+
+	/* By default 0xFFFFFF (24 bits unsigned) is maximum count */
+	return sprintf(buf, "16777215\n");
 }
 
 static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
 	struct counter_count *count, void *private, const char *buf, size_t len)
 {
 	struct quad8_iio *const priv = counter->priv;
+	unsigned int ceiling;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &ceiling);
+	if (ret)
+		return ret;
+
+	/* Only 24-bit values are supported */
+	if (ceiling > 0xFFFFFF)
+		return -EINVAL;
+
+	mutex_lock(&priv->lock);
 
 	/* Range Limit and Modulo-N count modes use preset value as ceiling */
 	switch (priv->count_mode[count->id]) {
 	case 1:
 	case 3:
-		return quad8_count_preset_write(counter, count, private, buf,
-						len);
+		quad8_preset_register_set(priv, count->id, ceiling);
+		mutex_unlock(&priv->lock);
+		return len;
 	}
 
-	return len;
+	mutex_unlock(&priv->lock);
+
+	return -EINVAL;
 }
 
 static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
@@ -1143,6 +1241,8 @@
 	/* Preset enable is active low in Input/Output Control register */
 	preset_enable = !preset_enable;
 
+	mutex_lock(&priv->lock);
+
 	priv->preset_enable[count->id] = preset_enable;
 
 	ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1;
@@ -1150,6 +1250,8 @@
 	/* Load I/O control configuration to Input / Output Control Register */
 	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
 
+	mutex_unlock(&priv->lock);
+
 	return len;
 }
 
@@ -1320,6 +1422,9 @@
 	quad8iio->counter.priv = quad8iio;
 	quad8iio->base = base[id];
 
+	/* Initialize mutex */
+	mutex_init(&quad8iio->lock);
+
 	/* Reset all counters and disable interrupt function */
 	outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
 	/* Set initial configuration for all counters */
--- linux-ein-5.4.0.orig/drivers/counter/stm32-lptimer-cnt.c
+++ linux-ein-5.4.0/drivers/counter/stm32-lptimer-cnt.c
@@ -69,7 +69,7 @@
 
 	/* ensure CMP & ARR registers are properly written */
 	ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,
-				       (val & STM32_LPTIM_CMPOK_ARROK),
+				       (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
 				       100, 1000);
 	if (ret)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/counter/stm32-timer-cnt.c
+++ linux-ein-5.4.0/drivers/counter/stm32-timer-cnt.c
@@ -24,7 +24,7 @@
 	struct counter_device counter;
 	struct regmap *regmap;
 	struct clk *clk;
-	u32 ceiling;
+	u32 max_arr;
 };
 
 /**
@@ -35,13 +35,14 @@
  * @STM32_COUNT_ENCODER_MODE_3: counts on both TI1FP1 and TI2FP2 edges
  */
 enum stm32_count_function {
-	STM32_COUNT_SLAVE_MODE_DISABLED = -1,
+	STM32_COUNT_SLAVE_MODE_DISABLED,
 	STM32_COUNT_ENCODER_MODE_1,
 	STM32_COUNT_ENCODER_MODE_2,
 	STM32_COUNT_ENCODER_MODE_3,
 };
 
 static enum counter_count_function stm32_count_functions[] = {
+	[STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
 	[STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
 	[STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
 	[STM32_COUNT_ENCODER_MODE_3] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
@@ -65,14 +66,15 @@
 			     struct counter_count_write_value *val)
 {
 	struct stm32_timer_cnt *const priv = counter->priv;
-	u32 cnt;
+	u32 cnt, ceiling;
 	int err;
 
 	err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
 	if (err)
 		return err;
 
-	if (cnt > priv->ceiling)
+	regmap_read(priv->regmap, TIM_ARR, &ceiling);
+	if (cnt > ceiling)
 		return -EINVAL;
 
 	return regmap_write(priv->regmap, TIM_CNT, cnt);
@@ -88,6 +90,9 @@
 	regmap_read(priv->regmap, TIM_SMCR, &smcr);
 
 	switch (smcr & TIM_SMCR_SMS) {
+	case 0:
+		*function = STM32_COUNT_SLAVE_MODE_DISABLED;
+		return 0;
 	case 1:
 		*function = STM32_COUNT_ENCODER_MODE_1;
 		return 0;
@@ -97,9 +102,9 @@
 	case 3:
 		*function = STM32_COUNT_ENCODER_MODE_3;
 		return 0;
+	default:
+		return -EINVAL;
 	}
-
-	return -EINVAL;
 }
 
 static int stm32_count_function_set(struct counter_device *counter,
@@ -110,6 +115,9 @@
 	u32 cr1, sms;
 
 	switch (function) {
+	case STM32_COUNT_SLAVE_MODE_DISABLED:
+		sms = 0;
+		break;
 	case STM32_COUNT_ENCODER_MODE_1:
 		sms = 1;
 		break;
@@ -120,8 +128,7 @@
 		sms = 3;
 		break;
 	default:
-		sms = 0;
-		break;
+		return -EINVAL;
 	}
 
 	/* Store enable status */
@@ -129,10 +136,6 @@
 
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
 
-	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
-	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
-	regmap_write(priv->regmap, TIM_ARR, priv->ceiling);
-
 	regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
 
 	/* Make sure that registers are updated */
@@ -183,11 +186,13 @@
 	if (ret)
 		return ret;
 
+	if (ceiling > priv->max_arr)
+		return -ERANGE;
+
 	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_write(priv->regmap, TIM_ARR, ceiling);
 
-	priv->ceiling = ceiling;
 	return len;
 }
 
@@ -269,31 +274,36 @@
 	size_t function;
 	int err;
 
-	/* Default action mode (e.g. STM32_COUNT_SLAVE_MODE_DISABLED) */
-	*action = STM32_SYNAPSE_ACTION_NONE;
-
 	err = stm32_count_function_get(counter, count, &function);
 	if (err)
-		return 0;
+		return err;
 
 	switch (function) {
+	case STM32_COUNT_SLAVE_MODE_DISABLED:
+		/* counts on internal clock when CEN=1 */
+		*action = STM32_SYNAPSE_ACTION_NONE;
+		return 0;
 	case STM32_COUNT_ENCODER_MODE_1:
 		/* counts up/down on TI1FP1 edge depending on TI2FP2 level */
 		if (synapse->signal->id == count->synapses[0].signal->id)
 			*action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-		break;
+		else
+			*action = STM32_SYNAPSE_ACTION_NONE;
+		return 0;
 	case STM32_COUNT_ENCODER_MODE_2:
 		/* counts up/down on TI2FP2 edge depending on TI1FP1 level */
 		if (synapse->signal->id == count->synapses[1].signal->id)
 			*action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-		break;
+		else
+			*action = STM32_SYNAPSE_ACTION_NONE;
+		return 0;
 	case STM32_COUNT_ENCODER_MODE_3:
 		/* counts up/down on both TI1FP1 and TI2FP2 edges */
 		*action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-		break;
+		return 0;
+	default:
+		return -EINVAL;
 	}
-
-	return 0;
 }
 
 static const struct counter_ops stm32_timer_cnt_ops = {
@@ -354,7 +364,7 @@
 
 	priv->regmap = ddata->regmap;
 	priv->clk = ddata->clk;
-	priv->ceiling = ddata->max_arr;
+	priv->max_arr = ddata->max_arr;
 
 	priv->counter.name = dev_name(dev);
 	priv->counter.parent = dev;
--- linux-ein-5.4.0.orig/drivers/cpufreq/Kconfig.arm
+++ linux-ein-5.4.0/drivers/cpufreq/Kconfig.arm
@@ -41,6 +41,7 @@
 config ARM_ARMADA_8K_CPUFREQ
 	tristate "Armada 8K CPUFreq driver"
 	depends on ARCH_MVEBU && CPUFREQ_DT
+	select ARMADA_AP_CPU_CLK
 	help
 	  This enables the CPUFreq driver support for Marvell
 	  Armada8k SOCs.
@@ -99,6 +100,7 @@
 	tristate "Freescale i.MX6 cpufreq support"
 	depends on ARCH_MXC
 	depends on REGULATOR_ANATOP
+	select NVMEM_IMX_OCOTP
 	select PM_OPP
 	help
 	  This adds cpufreq driver support for Freescale i.MX6 series SoCs.
--- linux-ein-5.4.0.orig/drivers/cpufreq/acpi-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/acpi-cpufreq.c
@@ -30,6 +30,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");
@@ -688,7 +689,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-ein-5.4.0.orig/drivers/cpufreq/amd_freq_sensitivity.c
+++ linux-ein-5.4.0/drivers/cpufreq/amd_freq_sensitivity.c
@@ -18,6 +18,7 @@
 
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #include "cpufreq_ondemand.h"
 
@@ -123,6 +124,8 @@
 	if (!pcidev) {
 		if (!boot_cpu_has(X86_FEATURE_PROC_FEEDBACK))
 			return -ENODEV;
+	} else {
+		pci_dev_put(pcidev);
 	}
 
 	if (rdmsrl_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val))
--- linux-ein-5.4.0.orig/drivers/cpufreq/armada-37xx-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/armada-37xx-cpufreq.c
@@ -25,6 +25,10 @@
 
 #include "cpufreq-dt.h"
 
+/* Clk register set */
+#define ARMADA_37XX_CLK_TBG_SEL		0
+#define ARMADA_37XX_CLK_TBG_SEL_CPU_OFF	22
+
 /* Power management in North Bridge register set */
 #define ARMADA_37XX_NB_L0L1	0x18
 #define ARMADA_37XX_NB_L2L3	0x1C
@@ -69,6 +73,8 @@
 #define LOAD_LEVEL_NR	4
 
 #define MIN_VOLT_MV 1000
+#define MIN_VOLT_MV_FOR_L1_1000MHZ 1108
+#define MIN_VOLT_MV_FOR_L1_1200MHZ 1155
 
 /*  AVS value for the corresponding voltage (in mV) */
 static int avs_map[] = {
@@ -96,7 +102,11 @@
 };
 
 static struct armada_37xx_dvfs armada_37xx_dvfs[] = {
-	{.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} },
+	/*
+	 * The cpufreq scaling for 1.2 GHz variant of the SOC is currently
+	 * unstable because we do not know how to configure it properly.
+	 */
+	/* {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, */
 	{.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} },
 	{.cpu_freq_max = 800*1000*1000,  .divider = {1, 2, 3, 4} },
 	{.cpu_freq_max = 600*1000*1000,  .divider = {2, 4, 5, 6} },
@@ -120,10 +130,15 @@
  * will be configured then the DVFS will be enabled.
  */
 static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
-						 struct clk *clk, u8 *divider)
+						 struct regmap *clk_base, u8 *divider)
 {
+	u32 cpu_tbg_sel;
 	int load_lvl;
-	struct clk *parent;
+
+	/* Determine to which TBG clock is CPU connected */
+	regmap_read(clk_base, ARMADA_37XX_CLK_TBG_SEL, &cpu_tbg_sel);
+	cpu_tbg_sel >>= ARMADA_37XX_CLK_TBG_SEL_CPU_OFF;
+	cpu_tbg_sel &= ARMADA_37XX_NB_TBG_SEL_MASK;
 
 	for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) {
 		unsigned int reg, mask, val, offset = 0;
@@ -142,6 +157,11 @@
 		mask = (ARMADA_37XX_NB_CLK_SEL_MASK
 			<< ARMADA_37XX_NB_CLK_SEL_OFF);
 
+		/* Set TBG index, for all levels we use the same TBG */
+		val = cpu_tbg_sel << ARMADA_37XX_NB_TBG_SEL_OFF;
+		mask = (ARMADA_37XX_NB_TBG_SEL_MASK
+			<< ARMADA_37XX_NB_TBG_SEL_OFF);
+
 		/*
 		 * Set cpu divider based on the pre-computed array in
 		 * order to have balanced step.
@@ -160,14 +180,6 @@
 
 		regmap_update_bits(base, reg, mask, val);
 	}
-
-	/*
-	 * Set cpu clock source, for all the level we keep the same
-	 * clock source that the one already configured. For this one
-	 * we need to use the clock framework
-	 */
-	parent = clk_get_parent(clk);
-	clk_set_parent(clk, parent);
 }
 
 /*
@@ -202,6 +214,8 @@
  * - L2 & L3 voltage should be about 150mv smaller than L0 voltage.
  * This function calculates L1 & L2 & L3 AVS values dynamically based
  * on L0 voltage and fill all AVS values to the AVS value table.
+ * When base CPU frequency is 1000 or 1200 MHz then there is additional
+ * minimal avs value for load L1.
  */
 static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
 						struct armada_37xx_dvfs *dvfs)
@@ -233,6 +247,19 @@
 		for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++)
 			dvfs->avs[load_level] = avs_min;
 
+		/*
+		 * Set the avs values for load L0 and L1 when base CPU frequency
+		 * is 1000/1200 MHz to its typical initial values according to
+		 * the Armada 3700 Hardware Specifications.
+		 */
+		if (dvfs->cpu_freq_max >= 1000*1000*1000) {
+			if (dvfs->cpu_freq_max >= 1200*1000*1000)
+				avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
+			else
+				avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
+			dvfs->avs[0] = dvfs->avs[1] = avs_min;
+		}
+
 		return;
 	}
 
@@ -252,6 +279,26 @@
 	target_vm = avs_map[l0_vdd_min] - 150;
 	target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
 	dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm);
+
+	/*
+	 * Fix the avs value for load L1 when base CPU frequency is 1000/1200 MHz,
+	 * otherwise the CPU gets stuck when switching from load L1 to load L0.
+	 * Also ensure that avs value for load L1 is not higher than for L0.
+	 */
+	if (dvfs->cpu_freq_max >= 1000*1000*1000) {
+		u32 avs_min_l1;
+
+		if (dvfs->cpu_freq_max >= 1200*1000*1000)
+			avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
+		else
+			avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
+
+		if (avs_min_l1 > dvfs->avs[0])
+			avs_min_l1 = dvfs->avs[0];
+
+		if (dvfs->avs[1] < avs_min_l1)
+			dvfs->avs[1] = avs_min_l1;
+	}
 }
 
 static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
@@ -358,11 +405,16 @@
 	struct platform_device *pdev;
 	unsigned long freq;
 	unsigned int cur_frequency, base_frequency;
-	struct regmap *nb_pm_base, *avs_base;
+	struct regmap *nb_clk_base, *nb_pm_base, *avs_base;
 	struct device *cpu_dev;
 	int load_lvl, ret;
 	struct clk *clk, *parent;
 
+	nb_clk_base =
+		syscon_regmap_lookup_by_compatible("marvell,armada-3700-periph-clock-nb");
+	if (IS_ERR(nb_clk_base))
+		return -ENODEV;
+
 	nb_pm_base =
 		syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
 
@@ -391,7 +443,7 @@
 		return -ENODEV;
 	}
 
-	clk = clk_get(cpu_dev, 0);
+	clk = clk_get(cpu_dev, NULL);
 	if (IS_ERR(clk)) {
 		dev_err(cpu_dev, "Cannot get clock for CPU0\n");
 		return PTR_ERR(clk);
@@ -421,7 +473,7 @@
 		return -EINVAL;
 	}
 
-	dvfs = armada_37xx_cpu_freq_info_get(cur_frequency);
+	dvfs = armada_37xx_cpu_freq_info_get(base_frequency);
 	if (!dvfs) {
 		clk_put(clk);
 		return -EINVAL;
@@ -439,7 +491,7 @@
 	armada37xx_cpufreq_avs_configure(avs_base, dvfs);
 	armada37xx_cpufreq_avs_setup(avs_base, dvfs);
 
-	armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider);
+	armada37xx_cpufreq_dvfs_setup(nb_pm_base, nb_clk_base, dvfs->divider);
 	clk_put(clk);
 
 	for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR;
@@ -456,6 +508,7 @@
 	/* Now that everything is setup, enable the DVFS at hardware level */
 	armada37xx_cpufreq_enable_dvfs(nb_pm_base);
 
+	memset(&pdata, 0, sizeof(pdata));
 	pdata.suspend = armada37xx_cpufreq_suspend;
 	pdata.resume = armada37xx_cpufreq_resume;
 
@@ -472,7 +525,7 @@
 remove_opp:
 	/* clean-up the already added opp before leaving */
 	while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
-		freq = cur_frequency / dvfs->divider[load_lvl];
+		freq = base_frequency / dvfs->divider[load_lvl];
 		dev_pm_opp_remove(cpu_dev, freq);
 	}
 
@@ -483,6 +536,12 @@
 /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
 late_initcall(armada37xx_cpufreq_driver_init);
 
+static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = {
+	{ .compatible = "marvell,armada-3700-nb-pm" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, armada37xx_cpufreq_of_match);
+
 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
 MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/cpufreq/armada-8k-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/armada-8k-cpufreq.c
@@ -204,6 +204,12 @@
 }
 module_exit(armada_8k_cpufreq_exit);
 
+static const struct of_device_id __maybe_unused armada_8k_cpufreq_of_match[] = {
+	{ .compatible = "marvell,ap806-cpu-clock" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, armada_8k_cpufreq_of_match);
+
 MODULE_AUTHOR("Gregory Clement <gregory.clement@bootlin.com>");
 MODULE_DESCRIPTION("Armada 8K cpufreq driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/cpufreq/brcmstb-avs-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/brcmstb-avs-cpufreq.c
@@ -410,7 +410,11 @@
 	if (ret)
 		return ERR_PTR(ret);
 
-	table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table),
+	/*
+	 * We allocate space for the 5 different P-STATES AVS,
+	 * plus extra space for a terminating element.
+	 */
+	table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1 + 1, sizeof(*table),
 			     GFP_KERNEL);
 	if (!table)
 		return ERR_PTR(-ENOMEM);
@@ -566,6 +570,16 @@
 	return ret;
 }
 
+static void brcm_avs_prepare_uninit(struct platform_device *pdev)
+{
+	struct private_data *priv;
+
+	priv = platform_get_drvdata(pdev);
+
+	iounmap(priv->avs_intr_base);
+	iounmap(priv->base);
+}
+
 static int brcm_avs_cpufreq_init(struct cpufreq_policy *policy)
 {
 	struct cpufreq_frequency_table *freq_table;
@@ -701,21 +715,21 @@
 
 	brcm_avs_driver.driver_data = pdev;
 
-	return cpufreq_register_driver(&brcm_avs_driver);
+	ret = cpufreq_register_driver(&brcm_avs_driver);
+	if (ret)
+		brcm_avs_prepare_uninit(pdev);
+
+	return ret;
 }
 
 static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
 {
-	struct private_data *priv;
 	int ret;
 
 	ret = cpufreq_unregister_driver(&brcm_avs_driver);
-	if (ret)
-		return ret;
+	WARN_ON(ret);
 
-	priv = platform_get_drvdata(pdev);
-	iounmap(priv->base);
-	iounmap(priv->avs_intr_base);
+	brcm_avs_prepare_uninit(pdev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/cpufreq/cppc_cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/cppc_cpufreq.c
@@ -217,7 +217,7 @@
 	return ret;
 }
 
-static int cppc_verify_policy(struct cpufreq_policy *policy)
+static int cppc_verify_policy(struct cpufreq_policy_data *policy)
 {
 	cpufreq_verify_within_cpu_limits(policy);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq-dt-platdev.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -103,13 +103,17 @@
 static const struct of_device_id blacklist[] __initconst = {
 	{ .compatible = "allwinner,sun50i-h6", },
 
+	{ .compatible = "arm,vexpress", },
+
 	{ .compatible = "calxeda,highbank", },
 	{ .compatible = "calxeda,ecx-2000", },
 
+	{ .compatible = "fsl,imx7ulp", },
 	{ .compatible = "fsl,imx7d", },
 	{ .compatible = "fsl,imx8mq", },
 	{ .compatible = "fsl,imx8mm", },
 	{ .compatible = "fsl,imx8mn", },
+	{ .compatible = "fsl,imx8mp", },
 
 	{ .compatible = "marvell,armadaxp", },
 
@@ -124,6 +128,7 @@
 
 	{ .compatible = "nvidia,tegra124", },
 	{ .compatible = "nvidia,tegra210", },
+	{ .compatible = "nvidia,tegra234", },
 
 	{ .compatible = "qcom,apq8096", },
 	{ .compatible = "qcom,msm8996", },
@@ -180,4 +185,4 @@
 			       -1, data,
 			       sizeof(struct cpufreq_dt_platform_data)));
 }
-device_initcall(cpufreq_dt_platdev_init);
+core_initcall(cpufreq_dt_platdev_init);
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq-dt.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq-dt.c
@@ -363,6 +363,10 @@
 		dt_cpufreq_driver.resume = data->resume;
 		if (data->suspend)
 			dt_cpufreq_driver.suspend = data->suspend;
+		if (data->get_intermediate) {
+			dt_cpufreq_driver.target_intermediate = data->target_intermediate;
+			dt_cpufreq_driver.get_intermediate = data->get_intermediate;
+		}
 	}
 
 	ret = cpufreq_register_driver(&dt_cpufreq_driver);
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq-dt.h
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq-dt.h
@@ -14,6 +14,10 @@
 struct cpufreq_dt_platform_data {
 	bool have_governor_per_policy;
 
+	unsigned int	(*get_intermediate)(struct cpufreq_policy *policy,
+					    unsigned int index);
+	int		(*target_intermediate)(struct cpufreq_policy *policy,
+					       unsigned int index);
 	int (*suspend)(struct cpufreq_policy *policy);
 	int (*resume)(struct cpufreq_policy *policy);
 };
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq-nforce2.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq-nforce2.c
@@ -291,7 +291,7 @@
  * nforce2_verify - verifies a new CPUFreq policy
  * @policy: new policy
  */
-static int nforce2_verify(struct cpufreq_policy *policy)
+static int nforce2_verify(struct cpufreq_policy_data *policy)
 {
 	unsigned int fsb_pol_max;
 
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq.c
@@ -74,6 +74,9 @@
 static int cpufreq_start_governor(struct cpufreq_policy *policy);
 static void cpufreq_stop_governor(struct cpufreq_policy *policy);
 static void cpufreq_governor_limits(struct cpufreq_policy *policy);
+static int cpufreq_set_policy(struct cpufreq_policy *policy,
+			      struct cpufreq_governor *new_gov,
+			      unsigned int new_pol);
 
 /**
  * Two notifier lists: the "policy" list is involved in the
@@ -102,6 +105,8 @@
 }
 EXPORT_SYMBOL_GPL(have_governor_per_policy);
 
+static struct kobject *cpufreq_global_kobject;
+
 struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
 {
 	if (have_governor_per_policy())
@@ -438,8 +443,10 @@
 
 	cpufreq_notify_post_transition(policy, freqs, transition_failed);
 
+	spin_lock(&policy->transition_lock);
 	policy->transition_ongoing = false;
 	policy->transition_task = NULL;
+	spin_unlock(&policy->transition_lock);
 
 	wake_up(&policy->transition_wait);
 }
@@ -613,55 +620,51 @@
 	return NULL;
 }
 
-static int cpufreq_parse_policy(char *str_governor,
-				struct cpufreq_policy *policy)
-{
-	if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
-		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
-		return 0;
-	}
-	if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
-		policy->policy = CPUFREQ_POLICY_POWERSAVE;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-/**
- * cpufreq_parse_governor - parse a governor string only for has_target()
- */
-static int cpufreq_parse_governor(char *str_governor,
-				  struct cpufreq_policy *policy)
+static struct cpufreq_governor *get_governor(const char *str_governor)
 {
 	struct cpufreq_governor *t;
 
 	mutex_lock(&cpufreq_governor_mutex);
-
 	t = find_governor(str_governor);
-	if (!t) {
-		int ret;
+	if (!t)
+		goto unlock;
 
-		mutex_unlock(&cpufreq_governor_mutex);
+	if (!try_module_get(t->owner))
+		t = NULL;
 
-		ret = request_module("cpufreq_%s", str_governor);
-		if (ret)
-			return -EINVAL;
+unlock:
+	mutex_unlock(&cpufreq_governor_mutex);
 
-		mutex_lock(&cpufreq_governor_mutex);
+	return t;
+}
 
-		t = find_governor(str_governor);
-	}
-	if (t && !try_module_get(t->owner))
-		t = NULL;
+static unsigned int cpufreq_parse_policy(char *str_governor)
+{
+	if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN))
+		return CPUFREQ_POLICY_PERFORMANCE;
 
-	mutex_unlock(&cpufreq_governor_mutex);
+	if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN))
+		return CPUFREQ_POLICY_POWERSAVE;
 
-	if (t) {
-		policy->governor = t;
-		return 0;
-	}
+	return CPUFREQ_POLICY_UNKNOWN;
+}
 
-	return -EINVAL;
+/**
+ * cpufreq_parse_governor - parse a governor string only for has_target()
+ * @str_governor: Governor name.
+ */
+static struct cpufreq_governor *cpufreq_parse_governor(char *str_governor)
+{
+	struct cpufreq_governor *t;
+
+	t = get_governor(str_governor);
+	if (t)
+		return t;
+
+	if (request_module("cpufreq_%s", str_governor))
+		return NULL;
+
+	return get_governor(str_governor);
 }
 
 /**
@@ -762,28 +765,33 @@
 static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
 					const char *buf, size_t count)
 {
+	char str_governor[16];
 	int ret;
-	char	str_governor[16];
-	struct cpufreq_policy new_policy;
-
-	memcpy(&new_policy, policy, sizeof(*policy));
 
 	ret = sscanf(buf, "%15s", str_governor);
 	if (ret != 1)
 		return -EINVAL;
 
 	if (cpufreq_driver->setpolicy) {
-		if (cpufreq_parse_policy(str_governor, &new_policy))
+		unsigned int new_pol;
+
+		new_pol = cpufreq_parse_policy(str_governor);
+		if (!new_pol)
 			return -EINVAL;
+
+		ret = cpufreq_set_policy(policy, NULL, new_pol);
 	} else {
-		if (cpufreq_parse_governor(str_governor, &new_policy))
+		struct cpufreq_governor *new_gov;
+
+		new_gov = cpufreq_parse_governor(str_governor);
+		if (!new_gov)
 			return -EINVAL;
-	}
 
-	ret = cpufreq_set_policy(policy, &new_policy);
+		ret = cpufreq_set_policy(policy, new_gov,
+					 CPUFREQ_POLICY_UNKNOWN);
 
-	if (new_policy.governor)
-		module_put(new_policy.governor->owner);
+		module_put(new_gov->owner);
+	}
 
 	return ret ? ret : count;
 }
@@ -810,12 +818,14 @@
 		goto out;
 	}
 
+	mutex_lock(&cpufreq_governor_mutex);
 	for_each_governor(t) {
 		if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
 		    - (CPUFREQ_NAME_LEN + 2)))
-			goto out;
+			break;
 		i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name);
 	}
+	mutex_unlock(&cpufreq_governor_mutex);
 out:
 	i += sprintf(&buf[i], "\n");
 	return i;
@@ -933,6 +943,9 @@
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret;
 
+	if (!fattr->show)
+		return -EIO;
+
 	down_read(&policy->rwsem);
 	ret = fattr->show(policy, buf);
 	up_read(&policy->rwsem);
@@ -947,6 +960,9 @@
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret = -EINVAL;
 
+	if (!fattr->store)
+		return -EIO;
+
 	/*
 	 * cpus_read_trylock() is used here to work around a circular lock
 	 * dependency problem with respect to the cpufreq_register_driver().
@@ -983,10 +999,9 @@
 	.release	= cpufreq_sysfs_release,
 };
 
-static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
+static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu,
+				struct device *dev)
 {
-	struct device *dev = get_cpu_device(cpu);
-
 	if (unlikely(!dev))
 		return;
 
@@ -1044,40 +1059,47 @@
 
 static int cpufreq_init_policy(struct cpufreq_policy *policy)
 {
-	struct cpufreq_governor *gov = NULL, *def_gov = NULL;
-	struct cpufreq_policy new_policy;
-
-	memcpy(&new_policy, policy, sizeof(*policy));
-
-	def_gov = cpufreq_default_governor();
+	struct cpufreq_governor *def_gov = cpufreq_default_governor();
+	struct cpufreq_governor *gov = NULL;
+	unsigned int pol = CPUFREQ_POLICY_UNKNOWN;
+	int ret;
 
 	if (has_target()) {
-		/*
-		 * Update governor of new_policy to the governor used before
-		 * hotplug
-		 */
-		gov = find_governor(policy->last_governor);
+		/* Update policy governor to the one used before hotplug. */
+		gov = get_governor(policy->last_governor);
 		if (gov) {
 			pr_debug("Restoring governor %s for cpu %d\n",
-				policy->governor->name, policy->cpu);
-		} else {
-			if (!def_gov)
-				return -ENODATA;
+				 policy->governor->name, policy->cpu);
+		} else if (def_gov) {
 			gov = def_gov;
+			__module_get(gov->owner);
+		} else {
+			return -ENODATA;
 		}
-		new_policy.governor = gov;
 	} else {
 		/* Use the default policy if there is no last_policy. */
 		if (policy->last_policy) {
-			new_policy.policy = policy->last_policy;
-		} else {
-			if (!def_gov)
-				return -ENODATA;
-			cpufreq_parse_policy(def_gov->name, &new_policy);
+			pol = policy->last_policy;
+		} else if (def_gov) {
+			pol = cpufreq_parse_policy(def_gov->name);
+			/*
+			 * In case the default governor is neiter "performance"
+			 * nor "powersave", fall back to the initial policy
+			 * value set by the driver.
+			 */
+			if (pol == CPUFREQ_POLICY_UNKNOWN)
+				pol = policy->policy;
 		}
+		if (pol != CPUFREQ_POLICY_PERFORMANCE &&
+		    pol != CPUFREQ_POLICY_POWERSAVE)
+			return -ENODATA;
 	}
 
-	return cpufreq_set_policy(policy, &new_policy);
+	ret = cpufreq_set_policy(policy, gov, pol);
+	if (gov)
+		module_put(gov->owner);
+
+	return ret;
 }
 
 static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
@@ -1105,13 +1127,10 @@
 
 void refresh_frequency_limits(struct cpufreq_policy *policy)
 {
-	struct cpufreq_policy new_policy;
-
 	if (!policy_is_inactive(policy)) {
-		new_policy = *policy;
 		pr_debug("updating policy for CPU %u\n", policy->cpu);
 
-		cpufreq_set_policy(policy, &new_policy);
+		cpufreq_set_policy(policy, policy->governor, policy->policy);
 	}
 }
 EXPORT_SYMBOL(refresh_frequency_limits);
@@ -1189,6 +1208,7 @@
 	if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
 		goto err_free_rcpumask;
 
+	init_completion(&policy->kobj_unregister);
 	ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
 				   cpufreq_global_kobject, "policy%u", cpu);
 	if (ret) {
@@ -1227,7 +1247,6 @@
 	init_rwsem(&policy->rwsem);
 	spin_lock_init(&policy->transition_lock);
 	init_waitqueue_head(&policy->transition_wait);
-	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
 
 	policy->cpu = cpu;
@@ -1345,9 +1364,14 @@
 			goto out_free_policy;
 		}
 
+		/*
+		 * The initialization has succeeded and the policy is online.
+		 * If there is a problem with its frequency table, take it
+		 * offline and drop it.
+		 */
 		ret = cpufreq_table_validate_and_sort(policy);
 		if (ret)
-			goto out_exit_policy;
+			goto out_offline_policy;
 
 		/* related_cpus should at least include policy->cpus. */
 		cpumask_copy(policy->related_cpus, policy->cpus);
@@ -1363,7 +1387,7 @@
 	if (new_policy) {
 		for_each_cpu(j, policy->related_cpus) {
 			per_cpu(cpufreq_cpu_data, j) = policy;
-			add_cpu_dev_symlink(policy, j);
+			add_cpu_dev_symlink(policy, j, get_cpu_device(j));
 		}
 
 		policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
@@ -1373,7 +1397,7 @@
 
 		ret = freq_qos_add_request(&policy->constraints,
 					   policy->min_freq_req, FREQ_QOS_MIN,
-					   policy->min);
+					   FREQ_QOS_MIN_DEFAULT_VALUE);
 		if (ret < 0) {
 			/*
 			 * So we don't call freq_qos_remove_request() for an
@@ -1393,7 +1417,7 @@
 
 		ret = freq_qos_add_request(&policy->constraints,
 					   policy->max_freq_req, FREQ_QOS_MAX,
-					   policy->max);
+					   FREQ_QOS_MAX_DEFAULT_VALUE);
 		if (ret < 0) {
 			policy->max_freq_req = NULL;
 			goto out_destroy_policy;
@@ -1491,6 +1515,10 @@
 
 	up_write(&policy->rwsem);
 
+out_offline_policy:
+	if (cpufreq_driver->offline)
+		cpufreq_driver->offline(policy);
+
 out_exit_policy:
 	if (cpufreq_driver->exit)
 		cpufreq_driver->exit(policy);
@@ -1522,7 +1550,7 @@
 	/* Create sysfs link on CPU registration */
 	policy = per_cpu(cpufreq_cpu_data, cpu);
 	if (policy)
-		add_cpu_dev_symlink(policy, cpu);
+		add_cpu_dev_symlink(policy, cpu, dev);
 
 	return 0;
 }
@@ -2355,43 +2383,46 @@
 /**
  * cpufreq_set_policy - Modify cpufreq policy parameters.
  * @policy: Policy object to modify.
- * @new_policy: New policy data.
+ * @new_gov: Policy governor pointer.
+ * @new_pol: Policy value (for drivers with built-in governors).
  *
- * Pass @new_policy to the cpufreq driver's ->verify() callback. Next, copy the
- * min and max parameters of @new_policy to @policy and either invoke the
- * driver's ->setpolicy() callback (if present) or carry out a governor update
- * for @policy.  That is, run the current governor's ->limits() callback (if the
- * governor field in @new_policy points to the same object as the one in
- * @policy) or replace the governor for @policy with the new one stored in
- * @new_policy.
+ * Invoke the cpufreq driver's ->verify() callback to sanity-check the frequency
+ * limits to be set for the policy, update @policy with the verified limits
+ * values and either invoke the driver's ->setpolicy() callback (if present) or
+ * carry out a governor update for @policy.  That is, run the current governor's
+ * ->limits() callback (if @new_gov points to the same object as the one in
+ * @policy) or replace the governor for @policy with @new_gov.
  *
  * The cpuinfo part of @policy is not updated by this function.
  */
-int cpufreq_set_policy(struct cpufreq_policy *policy,
-		       struct cpufreq_policy *new_policy)
+static int cpufreq_set_policy(struct cpufreq_policy *policy,
+			      struct cpufreq_governor *new_gov,
+			      unsigned int new_pol)
 {
+	struct cpufreq_policy_data new_data;
 	struct cpufreq_governor *old_gov;
 	int ret;
 
-	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
-		 new_policy->cpu, new_policy->min, new_policy->max);
-
-	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
-
+	memcpy(&new_data.cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
+	new_data.freq_table = policy->freq_table;
+	new_data.cpu = policy->cpu;
 	/*
 	 * PM QoS framework collects all the requests from users and provide us
 	 * the final aggregated value here.
 	 */
-	new_policy->min = freq_qos_read_value(&policy->constraints, FREQ_QOS_MIN);
-	new_policy->max = freq_qos_read_value(&policy->constraints, FREQ_QOS_MAX);
+	new_data.min = freq_qos_read_value(&policy->constraints, FREQ_QOS_MIN);
+	new_data.max = freq_qos_read_value(&policy->constraints, FREQ_QOS_MAX);
+
+	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
+		 new_data.cpu, new_data.min, new_data.max);
 
 	/* verify the cpu speed can be set within this limit */
-	ret = cpufreq_driver->verify(new_policy);
+	ret = cpufreq_driver->verify(&new_data);
 	if (ret)
 		return ret;
 
-	policy->min = new_policy->min;
-	policy->max = new_policy->max;
+	policy->min = new_data.min;
+	policy->max = new_data.max;
 	trace_cpu_frequency_limits(policy);
 
 	policy->cached_target_freq = UINT_MAX;
@@ -2400,12 +2431,12 @@
 		 policy->min, policy->max);
 
 	if (cpufreq_driver->setpolicy) {
-		policy->policy = new_policy->policy;
+		policy->policy = new_pol;
 		pr_debug("setting range\n");
 		return cpufreq_driver->setpolicy(policy);
 	}
 
-	if (new_policy->governor == policy->governor) {
+	if (new_gov == policy->governor) {
 		pr_debug("governor limits update\n");
 		cpufreq_governor_limits(policy);
 		return 0;
@@ -2422,7 +2453,7 @@
 	}
 
 	/* start new governor */
-	policy->governor = new_policy->governor;
+	policy->governor = new_gov;
 	ret = cpufreq_init_governor(policy);
 	if (!ret) {
 		ret = cpufreq_start_governor(policy);
@@ -2500,26 +2531,27 @@
 static int cpufreq_boost_set_sw(int state)
 {
 	struct cpufreq_policy *policy;
-	int ret = -EINVAL;
 
 	for_each_active_policy(policy) {
+		int ret;
+
 		if (!policy->freq_table)
-			continue;
+			return -ENXIO;
 
 		ret = cpufreq_frequency_table_cpuinfo(policy,
 						      policy->freq_table);
 		if (ret) {
 			pr_err("%s: Policy frequency update failed\n",
 			       __func__);
-			break;
+			return ret;
 		}
 
 		ret = freq_qos_update_request(policy->max_freq_req, policy->max);
 		if (ret < 0)
-			break;
+			return ret;
 	}
 
-	return ret;
+	return 0;
 }
 
 int cpufreq_boost_trigger_state(int state)
@@ -2610,6 +2642,20 @@
 	return 0;
 }
 
+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#
@@ -2628,6 +2674,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) ||
@@ -2637,7 +2690,13 @@
 	     (!driver_data->online != !driver_data->offline))
 		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. */
 	cpus_read_lock();
@@ -2733,9 +2792,6 @@
 }
 EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
 
-struct kobject *cpufreq_global_kobject;
-EXPORT_SYMBOL(cpufreq_global_kobject);
-
 static int __init cpufreq_core_init(void)
 {
 	if (cpufreq_disabled())
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_conservative.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_conservative.c
@@ -346,7 +346,7 @@
 	return CPU_FREQ_GOV_CONSERVATIVE;
 }
 
-fs_initcall(cpufreq_gov_dbs_init);
+core_initcall(cpufreq_gov_dbs_init);
 #else
 module_init(cpufreq_gov_dbs_init);
 #endif
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_governor_attr_set.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_governor_attr_set.c
@@ -74,8 +74,8 @@
 	if (count)
 		return count;
 
-	kobject_put(&attr_set->kobj);
 	mutex_destroy(&attr_set->update_lock);
+	kobject_put(&attr_set->kobj);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(gov_attr_set_put);
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_ondemand.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_ondemand.c
@@ -483,7 +483,7 @@
 	return CPU_FREQ_GOV_ONDEMAND;
 }
 
-fs_initcall(cpufreq_gov_dbs_init);
+core_initcall(cpufreq_gov_dbs_init);
 #else
 module_init(cpufreq_gov_dbs_init);
 #endif
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_performance.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_performance.c
@@ -50,5 +50,5 @@
 MODULE_DESCRIPTION("CPUfreq policy governor 'performance'");
 MODULE_LICENSE("GPL");
 
-fs_initcall(cpufreq_gov_performance_init);
+core_initcall(cpufreq_gov_performance_init);
 module_exit(cpufreq_gov_performance_exit);
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_powersave.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_powersave.c
@@ -43,7 +43,7 @@
 	return &cpufreq_gov_powersave;
 }
 
-fs_initcall(cpufreq_gov_powersave_init);
+core_initcall(cpufreq_gov_powersave_init);
 #else
 module_init(cpufreq_gov_powersave_init);
 #endif
--- linux-ein-5.4.0.orig/drivers/cpufreq/cpufreq_userspace.c
+++ linux-ein-5.4.0/drivers/cpufreq/cpufreq_userspace.c
@@ -147,7 +147,7 @@
 	return &cpufreq_gov_userspace;
 }
 
-fs_initcall(cpufreq_gov_userspace_init);
+core_initcall(cpufreq_gov_userspace_init);
 #else
 module_init(cpufreq_gov_userspace_init);
 #endif
--- linux-ein-5.4.0.orig/drivers/cpufreq/freq_table.c
+++ linux-ein-5.4.0/drivers/cpufreq/freq_table.c
@@ -60,7 +60,7 @@
 		return 0;
 }
 
-int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
+int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
 				   struct cpufreq_frequency_table *table)
 {
 	struct cpufreq_frequency_table *pos;
@@ -100,7 +100,7 @@
  * Generic routine to verify policy & frequency table, requires driver to set
  * policy->freq_table prior to it.
  */
-int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
+int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy)
 {
 	if (!policy->freq_table)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/cpufreq/gx-suspmod.c
+++ linux-ein-5.4.0/drivers/cpufreq/gx-suspmod.c
@@ -328,7 +328,7 @@
  *      for the hardware supported by the driver.
  */
 
-static int cpufreq_gx_verify(struct cpufreq_policy *policy)
+static int cpufreq_gx_verify(struct cpufreq_policy_data *policy)
 {
 	unsigned int tmp_freq = 0;
 	u8 tmp1, tmp2;
--- linux-ein-5.4.0.orig/drivers/cpufreq/highbank-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/highbank-cpufreq.c
@@ -101,6 +101,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-ein-5.4.0.orig/drivers/cpufreq/imx-cpufreq-dt.c
+++ linux-ein-5.4.0/drivers/cpufreq/imx-cpufreq-dt.c
@@ -3,7 +3,9 @@
  * Copyright 2019 NXP
  */
 
+#include <linux/clk.h>
 #include <linux/cpu.h>
+#include <linux/cpufreq.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -12,51 +14,139 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
+#include "cpufreq-dt.h"
+
 #define OCOTP_CFG3_SPEED_GRADE_SHIFT	8
 #define OCOTP_CFG3_SPEED_GRADE_MASK	(0x3 << 8)
 #define IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK	(0xf << 8)
 #define OCOTP_CFG3_MKT_SEGMENT_SHIFT    6
 #define OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 6)
+#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT    5
+#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 5)
+
+#define IMX7ULP_MAX_RUN_FREQ	528000
 
 /* cpufreq-dt device registered by imx-cpufreq-dt */
 static struct platform_device *cpufreq_dt_pdev;
 static struct opp_table *cpufreq_opp_table;
+static struct device *cpu_dev;
+
+enum IMX7ULP_CPUFREQ_CLKS {
+	ARM,
+	CORE,
+	SCS_SEL,
+	HSRUN_CORE,
+	HSRUN_SCS_SEL,
+	FIRC,
+};
+
+static struct clk_bulk_data imx7ulp_clks[] = {
+	{ .id = "arm" },
+	{ .id = "core" },
+	{ .id = "scs_sel" },
+	{ .id = "hsrun_core" },
+	{ .id = "hsrun_scs_sel" },
+	{ .id = "firc" },
+};
+
+static unsigned int imx7ulp_get_intermediate(struct cpufreq_policy *policy,
+					     unsigned int index)
+{
+	return clk_get_rate(imx7ulp_clks[FIRC].clk);
+}
+
+static int imx7ulp_target_intermediate(struct cpufreq_policy *policy,
+					unsigned int index)
+{
+	unsigned int newfreq = policy->freq_table[index].frequency;
+
+	clk_set_parent(imx7ulp_clks[SCS_SEL].clk, imx7ulp_clks[FIRC].clk);
+	clk_set_parent(imx7ulp_clks[HSRUN_SCS_SEL].clk, imx7ulp_clks[FIRC].clk);
+
+	if (newfreq > IMX7ULP_MAX_RUN_FREQ)
+		clk_set_parent(imx7ulp_clks[ARM].clk,
+			       imx7ulp_clks[HSRUN_CORE].clk);
+	else
+		clk_set_parent(imx7ulp_clks[ARM].clk, imx7ulp_clks[CORE].clk);
+
+	return 0;
+}
+
+static struct cpufreq_dt_platform_data imx7ulp_data = {
+	.target_intermediate = imx7ulp_target_intermediate,
+	.get_intermediate = imx7ulp_get_intermediate,
+};
 
 static int imx_cpufreq_dt_probe(struct platform_device *pdev)
 {
-	struct device *cpu_dev = get_cpu_device(0);
+	struct platform_device *dt_pdev;
 	u32 cell_value, supported_hw[2];
 	int speed_grade, mkt_segment;
 	int ret;
 
+	cpu_dev = get_cpu_device(0);
+
+	if (!of_find_property(cpu_dev->of_node, "cpu-supply", NULL))
+		return -ENODEV;
+
+	if (of_machine_is_compatible("fsl,imx7ulp")) {
+		ret = clk_bulk_get(cpu_dev, ARRAY_SIZE(imx7ulp_clks),
+				   imx7ulp_clks);
+		if (ret)
+			return ret;
+
+		dt_pdev = platform_device_register_data(NULL, "cpufreq-dt",
+							-1, &imx7ulp_data,
+							sizeof(imx7ulp_data));
+		if (IS_ERR(dt_pdev)) {
+			clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
+			ret = PTR_ERR(dt_pdev);
+			dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
+			return ret;
+		}
+
+		cpufreq_dt_pdev = dt_pdev;
+
+		return 0;
+	}
+
 	ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
 	if (ret)
 		return ret;
 
-	if (of_machine_is_compatible("fsl,imx8mn"))
+	if (of_machine_is_compatible("fsl,imx8mn") ||
+	    of_machine_is_compatible("fsl,imx8mp"))
 		speed_grade = (cell_value & IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK)
 			      >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
 	else
 		speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK)
 			      >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
-	mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+
+	if (of_machine_is_compatible("fsl,imx8mp"))
+		mkt_segment = (cell_value & IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK)
+			       >> IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+	else
+		mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK)
+			       >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
 
 	/*
-	 * Early samples without fuses written report "0 0" which means
-	 * consumer segment and minimum speed grading.
-	 *
-	 * According to datasheet minimum speed grading is not supported for
-	 * consumer parts so clamp to 1 to avoid warning for "no OPPs"
+	 * Early samples without fuses written report "0 0" which may NOT
+	 * match any OPP defined in DT. So clamp to minimum OPP defined in
+	 * DT to avoid warning for "no OPPs".
 	 *
 	 * Applies to i.MX8M series SoCs.
 	 */
-	if (mkt_segment == 0 && speed_grade == 0 && (
-			of_machine_is_compatible("fsl,imx8mm") ||
-			of_machine_is_compatible("fsl,imx8mn") ||
-			of_machine_is_compatible("fsl,imx8mq")))
-		speed_grade = 1;
+	if (mkt_segment == 0 && speed_grade == 0) {
+		if (of_machine_is_compatible("fsl,imx8mm") ||
+		    of_machine_is_compatible("fsl,imx8mq"))
+			speed_grade = 1;
+		if (of_machine_is_compatible("fsl,imx8mn") ||
+		    of_machine_is_compatible("fsl,imx8mp"))
+			speed_grade = 0xb;
+	}
 
 	supported_hw[0] = BIT(speed_grade);
 	supported_hw[1] = BIT(mkt_segment);
@@ -85,7 +175,10 @@
 static int imx_cpufreq_dt_remove(struct platform_device *pdev)
 {
 	platform_device_unregister(cpufreq_dt_pdev);
-	dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+	if (!of_machine_is_compatible("fsl,imx7ulp"))
+		dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+	else
+		clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/cpufreq/imx6q-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/imx6q-cpufreq.c
@@ -48,7 +48,6 @@
 };
 
 static struct device *cpu_dev;
-static bool free_opp;
 static struct cpufreq_frequency_table *freq_table;
 static unsigned int max_freq;
 static unsigned int transition_latency;
@@ -210,56 +209,71 @@
 	.suspend = cpufreq_generic_suspend,
 };
 
+static void imx6x_disable_freq_in_opp(struct device *dev, unsigned long freq)
+{
+	int ret = dev_pm_opp_disable(dev, freq);
+
+	if (ret < 0 && ret != -ENODEV)
+		dev_warn(dev, "failed to disable %ldMHz OPP\n", freq / 1000000);
+}
+
 #define OCOTP_CFG3			0x440
 #define OCOTP_CFG3_SPEED_SHIFT		16
 #define OCOTP_CFG3_SPEED_1P2GHZ		0x3
 #define OCOTP_CFG3_SPEED_996MHZ		0x2
 #define OCOTP_CFG3_SPEED_852MHZ		0x1
 
-static void imx6q_opp_check_speed_grading(struct device *dev)
+static int imx6q_opp_check_speed_grading(struct device *dev)
 {
 	struct device_node *np;
 	void __iomem *base;
 	u32 val;
+	int ret;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
-	if (!np)
-		return;
-
-	base = of_iomap(np, 0);
-	if (!base) {
-		dev_err(dev, "failed to map ocotp\n");
-		goto put_node;
+	if (of_find_property(dev->of_node, "nvmem-cells", NULL)) {
+		ret = nvmem_cell_read_u32(dev, "speed_grade", &val);
+		if (ret)
+			return ret;
+	} else {
+		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+		if (!np)
+			return -ENOENT;
+
+		base = of_iomap(np, 0);
+		of_node_put(np);
+		if (!base) {
+			dev_err(dev, "failed to map ocotp\n");
+			return -EFAULT;
+		}
+
+		/*
+		 * SPEED_GRADING[1:0] defines the max speed of ARM:
+		 * 2b'11: 1200000000Hz;
+		 * 2b'10: 996000000Hz;
+		 * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
+		 * 2b'00: 792000000Hz;
+		 * We need to set the max speed of ARM according to fuse map.
+		 */
+		val = readl_relaxed(base + OCOTP_CFG3);
+		iounmap(base);
 	}
 
-	/*
-	 * SPEED_GRADING[1:0] defines the max speed of ARM:
-	 * 2b'11: 1200000000Hz;
-	 * 2b'10: 996000000Hz;
-	 * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
-	 * 2b'00: 792000000Hz;
-	 * We need to set the max speed of ARM according to fuse map.
-	 */
-	val = readl_relaxed(base + OCOTP_CFG3);
 	val >>= OCOTP_CFG3_SPEED_SHIFT;
 	val &= 0x3;
 
 	if (val < OCOTP_CFG3_SPEED_996MHZ)
-		if (dev_pm_opp_disable(dev, 996000000))
-			dev_warn(dev, "failed to disable 996MHz OPP\n");
+		imx6x_disable_freq_in_opp(dev, 996000000);
 
 	if (of_machine_is_compatible("fsl,imx6q") ||
 	    of_machine_is_compatible("fsl,imx6qp")) {
 		if (val != OCOTP_CFG3_SPEED_852MHZ)
-			if (dev_pm_opp_disable(dev, 852000000))
-				dev_warn(dev, "failed to disable 852MHz OPP\n");
+			imx6x_disable_freq_in_opp(dev, 852000000);
+
 		if (val != OCOTP_CFG3_SPEED_1P2GHZ)
-			if (dev_pm_opp_disable(dev, 1200000000))
-				dev_warn(dev, "failed to disable 1.2GHz OPP\n");
+			imx6x_disable_freq_in_opp(dev, 1200000000);
 	}
-	iounmap(base);
-put_node:
-	of_node_put(np);
+
+	return 0;
 }
 
 #define OCOTP_CFG3_6UL_SPEED_696MHZ	0x2
@@ -281,6 +295,9 @@
 
 		np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
 		if (!np)
+			np = of_find_compatible_node(NULL, NULL,
+						     "fsl,imx6ull-ocotp");
+		if (!np)
 			return -ENOENT;
 
 		base = of_iomap(np, 0);
@@ -305,20 +322,16 @@
 	val >>= OCOTP_CFG3_SPEED_SHIFT;
 	val &= 0x3;
 
-	if (of_machine_is_compatible("fsl,imx6ul")) {
+	if (of_machine_is_compatible("fsl,imx6ul"))
 		if (val != OCOTP_CFG3_6UL_SPEED_696MHZ)
-			if (dev_pm_opp_disable(dev, 696000000))
-				dev_warn(dev, "failed to disable 696MHz OPP\n");
-	}
+			imx6x_disable_freq_in_opp(dev, 696000000);
 
 	if (of_machine_is_compatible("fsl,imx6ull")) {
-		if (val != OCOTP_CFG3_6ULL_SPEED_792MHZ)
-			if (dev_pm_opp_disable(dev, 792000000))
-				dev_warn(dev, "failed to disable 792MHz OPP\n");
+		if (val < OCOTP_CFG3_6ULL_SPEED_792MHZ)
+			imx6x_disable_freq_in_opp(dev, 792000000);
 
 		if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ)
-			if (dev_pm_opp_disable(dev, 900000000))
-				dev_warn(dev, "failed to disable 900MHz OPP\n");
+			imx6x_disable_freq_in_opp(dev, 900000000);
 	}
 
 	return ret;
@@ -381,20 +394,16 @@
 	if (of_machine_is_compatible("fsl,imx6ul") ||
 	    of_machine_is_compatible("fsl,imx6ull")) {
 		ret = imx6ul_opp_check_speed_grading(cpu_dev);
-		if (ret) {
-			if (ret == -EPROBE_DEFER)
-				goto put_node;
-
+	} else {
+		ret = imx6q_opp_check_speed_grading(cpu_dev);
+	}
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
 			dev_err(cpu_dev, "failed to read ocotp: %d\n",
 				ret);
-			goto put_node;
-		}
-	} else {
-		imx6q_opp_check_speed_grading(cpu_dev);
+		goto out_free_opp;
 	}
 
-	/* Because we have added the OPPs here, we must free them */
-	free_opp = true;
 	num = dev_pm_opp_get_opp_count(cpu_dev);
 	if (num < 0) {
 		ret = num;
@@ -496,8 +505,7 @@
 free_freq_table:
 	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
 out_free_opp:
-	if (free_opp)
-		dev_pm_opp_of_remove_table(cpu_dev);
+	dev_pm_opp_of_remove_table(cpu_dev);
 put_reg:
 	if (!IS_ERR(arm_reg))
 		regulator_put(arm_reg);
@@ -517,8 +525,7 @@
 {
 	cpufreq_unregister_driver(&imx6q_cpufreq_driver);
 	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-	if (free_opp)
-		dev_pm_opp_of_remove_table(cpu_dev);
+	dev_pm_opp_of_remove_table(cpu_dev);
 	regulator_put(arm_reg);
 	if (!IS_ERR(pu_reg))
 		regulator_put(pu_reg);
--- linux-ein-5.4.0.orig/drivers/cpufreq/intel_pstate.c
+++ linux-ein-5.4.0/drivers/cpufreq/intel_pstate.c
@@ -442,20 +442,6 @@
 			 (u32) cpu->acpi_perf_data.states[i].control);
 	}
 
-	/*
-	 * The _PSS table doesn't contain whole turbo frequency range.
-	 * This just contains +1 MHZ above the max non turbo frequency,
-	 * with control value corresponding to max turbo ratio. But
-	 * when cpufreq set policy is called, it will call with this
-	 * max frequency, which will cause a reduced performance as
-	 * this driver uses real max turbo frequency as the max
-	 * frequency. So correct this frequency in _PSS table to
-	 * correct max turbo frequency based on the turbo state.
-	 * Also need to convert to MHz as _PSS freq is in MHz.
-	 */
-	if (!global.turbo_disabled)
-		cpu->acpi_perf_data.states[0].core_frequency =
-					policy->cpuinfo.max_freq / 1000;
 	cpu->valid_pss_table = true;
 	pr_debug("_PPC limits will be enforced\n");
 
@@ -649,11 +635,12 @@
 	mutex_lock(&intel_pstate_limits_lock);
 
 	if (boot_cpu_has(X86_FEATURE_HWP_EPP)) {
-		u64 value;
-
-		ret = rdmsrl_on_cpu(cpu_data->cpu, MSR_HWP_REQUEST, &value);
-		if (ret)
-			goto return_pref;
+		/*
+		 * Use the cached HWP Request MSR value, because the register
+		 * itself may be updated by intel_pstate_hwp_boost_up() or
+		 * intel_pstate_hwp_boost_down() at any time.
+		 */
+		u64 value = READ_ONCE(cpu_data->hwp_req_cached);
 
 		value &= ~GENMASK_ULL(31, 24);
 
@@ -661,13 +648,18 @@
 			epp = epp_values[pref_index - 1];
 
 		value |= (u64)epp << 24;
+		/*
+		 * The only other updater of hwp_req_cached in the active mode,
+		 * intel_pstate_hwp_set(), is called under the same lock as this
+		 * function, so it cannot run in parallel with the update below.
+		 */
+		WRITE_ONCE(cpu_data->hwp_req_cached, value);
 		ret = wrmsrl_on_cpu(cpu_data->cpu, MSR_HWP_REQUEST, value);
 	} else {
 		if (epp == -EINVAL)
 			epp = (pref_index - 1) << 2;
 		ret = intel_pstate_set_epb(cpu_data->cpu, epp);
 	}
-return_pref:
 	mutex_unlock(&intel_pstate_limits_lock);
 
 	return ret;
@@ -756,7 +748,7 @@
 
 	rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
 	WRITE_ONCE(all_cpu_data[cpu]->hwp_cap_cached, cap);
-	if (global.no_turbo)
+	if (global.no_turbo || global.turbo_disabled)
 		*current_max = HWP_GUARANTEED_PERF(cap);
 	else
 		*current_max = HWP_HIGHEST_PERF(cap);
@@ -1058,7 +1050,7 @@
 
 	update_turbo_state();
 	if (global.turbo_disabled) {
-		pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
+		pr_notice_once("Turbo disabled by BIOS or unavailable on processor\n");
 		mutex_unlock(&intel_pstate_limits_lock);
 		mutex_unlock(&intel_pstate_driver_lock);
 		return -EPERM;
@@ -1560,20 +1552,22 @@
 static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 {
 	cpu->pstate.min_pstate = pstate_funcs.get_min();
-	cpu->pstate.max_pstate = pstate_funcs.get_max();
 	cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
 	cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
 	cpu->pstate.scaling = pstate_funcs.get_scaling();
-	cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
 
 	if (hwp_active && !hwp_mode_bdw) {
 		unsigned int phy_max, current_max;
 
 		intel_pstate_get_hwp_max(cpu->cpu, &phy_max, &current_max);
 		cpu->pstate.turbo_freq = phy_max * cpu->pstate.scaling;
+		cpu->pstate.turbo_pstate = phy_max;
+		cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(READ_ONCE(cpu->hwp_cap_cached));
 	} else {
 		cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+		cpu->pstate.max_pstate = pstate_funcs.get_max();
 	}
+	cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
 
 	if (pstate_funcs.get_aperf_mperf_shift)
 		cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
@@ -2036,8 +2030,9 @@
 			cpu->pstate.max_freq : cpu->pstate.turbo_freq;
 }
 
-static void intel_pstate_update_perf_limits(struct cpufreq_policy *policy,
-					    struct cpudata *cpu)
+static void intel_pstate_update_perf_limits(struct cpudata *cpu,
+					    unsigned int policy_min,
+					    unsigned int policy_max)
 {
 	int max_freq = intel_pstate_get_max_freq(cpu);
 	int32_t max_policy_perf, min_policy_perf;
@@ -2056,18 +2051,17 @@
 		turbo_max = cpu->pstate.turbo_pstate;
 	}
 
-	max_policy_perf = max_state * policy->max / max_freq;
-	if (policy->max == policy->min) {
+	max_policy_perf = max_state * policy_max / max_freq;
+	if (policy_max == policy_min) {
 		min_policy_perf = max_policy_perf;
 	} else {
-		min_policy_perf = max_state * policy->min / max_freq;
+		min_policy_perf = max_state * policy_min / max_freq;
 		min_policy_perf = clamp_t(int32_t, min_policy_perf,
 					  0, max_policy_perf);
 	}
 
 	pr_debug("cpu:%d max_state %d min_policy_perf:%d max_policy_perf:%d\n",
-		 policy->cpu, max_state,
-		 min_policy_perf, max_policy_perf);
+		 cpu->cpu, max_state, min_policy_perf, max_policy_perf);
 
 	/* Normalize user input to [min_perf, max_perf] */
 	if (per_cpu_limits) {
@@ -2081,7 +2075,7 @@
 		global_min = DIV_ROUND_UP(turbo_max * global.min_perf_pct, 100);
 		global_min = clamp_t(int32_t, global_min, 0, global_max);
 
-		pr_debug("cpu:%d global_min:%d global_max:%d\n", policy->cpu,
+		pr_debug("cpu:%d global_min:%d global_max:%d\n", cpu->cpu,
 			 global_min, global_max);
 
 		cpu->min_perf_ratio = max(min_policy_perf, global_min);
@@ -2094,7 +2088,7 @@
 					  cpu->max_perf_ratio);
 
 	}
-	pr_debug("cpu:%d max_perf_ratio:%d min_perf_ratio:%d\n", policy->cpu,
+	pr_debug("cpu:%d max_perf_ratio:%d min_perf_ratio:%d\n", cpu->cpu,
 		 cpu->max_perf_ratio,
 		 cpu->min_perf_ratio);
 }
@@ -2114,7 +2108,7 @@
 
 	mutex_lock(&intel_pstate_limits_lock);
 
-	intel_pstate_update_perf_limits(policy, cpu);
+	intel_pstate_update_perf_limits(cpu, policy->min, policy->max);
 
 	if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
 		/*
@@ -2143,8 +2137,8 @@
 	return 0;
 }
 
-static void intel_pstate_adjust_policy_max(struct cpufreq_policy *policy,
-					 struct cpudata *cpu)
+static void intel_pstate_adjust_policy_max(struct cpudata *cpu,
+					   struct cpufreq_policy_data *policy)
 {
 	if (!hwp_active &&
 	    cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate &&
@@ -2155,7 +2149,7 @@
 	}
 }
 
-static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
+static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
 {
 	struct cpudata *cpu = all_cpu_data[policy->cpu];
 
@@ -2163,11 +2157,7 @@
 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
 				     intel_pstate_get_max_freq(cpu));
 
-	if (policy->policy != CPUFREQ_POLICY_POWERSAVE &&
-	    policy->policy != CPUFREQ_POLICY_PERFORMANCE)
-		return -EINVAL;
-
-	intel_pstate_adjust_policy_max(policy, cpu);
+	intel_pstate_adjust_policy_max(cpu, policy);
 
 	return 0;
 }
@@ -2268,7 +2258,7 @@
 	.name		= "intel_pstate",
 };
 
-static int intel_cpufreq_verify_policy(struct cpufreq_policy *policy)
+static int intel_cpufreq_verify_policy(struct cpufreq_policy_data *policy)
 {
 	struct cpudata *cpu = all_cpu_data[policy->cpu];
 
@@ -2276,9 +2266,9 @@
 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
 				     intel_pstate_get_max_freq(cpu));
 
-	intel_pstate_adjust_policy_max(policy, cpu);
+	intel_pstate_adjust_policy_max(cpu, policy);
 
-	intel_pstate_update_perf_limits(policy, cpu);
+	intel_pstate_update_perf_limits(cpu, policy->min, policy->max);
 
 	return 0;
 }
@@ -2530,9 +2520,15 @@
 {
 	int ret;
 
-	if (size == 3 && !strncmp(buf, "off", size))
-		return intel_pstate_driver ?
-			intel_pstate_unregister_driver() : -EINVAL;
+	if (size == 3 && !strncmp(buf, "off", size)) {
+		if (!intel_pstate_driver)
+			return -EINVAL;
+
+		if (hwp_active)
+			return -EBUSY;
+
+		return intel_pstate_unregister_driver();
+	}
 
 	if (size == 6 && !strncmp(buf, "active", size)) {
 		if (intel_pstate_driver) {
--- linux-ein-5.4.0.orig/drivers/cpufreq/longrun.c
+++ linux-ein-5.4.0/drivers/cpufreq/longrun.c
@@ -122,7 +122,7 @@
  * Validates a new CPUFreq policy. This function has to be called with
  * cpufreq_driver locked.
  */
-static int longrun_verify_policy(struct cpufreq_policy *policy)
+static int longrun_verify_policy(struct cpufreq_policy_data *policy)
 {
 	if (!policy)
 		return -EINVAL;
@@ -130,10 +130,6 @@
 	policy->cpu = 0;
 	cpufreq_verify_within_cpu_limits(policy);
 
-	if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
-	    (policy->policy != CPUFREQ_POLICY_PERFORMANCE))
-		return -EINVAL;
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/cpufreq/loongson1-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/loongson1-cpufreq.c
@@ -216,6 +216,7 @@
 
 module_platform_driver(ls1x_cpufreq_platdrv);
 
+MODULE_ALIAS("platform:ls1x-cpufreq");
 MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
 MODULE_DESCRIPTION("Loongson1 CPUFreq driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/cpufreq/mediatek-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/mediatek-cpufreq.c
@@ -540,6 +540,7 @@
 
 	{ }
 };
+MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
 
 static int __init mtk_cpufreq_driver_init(void)
 {
--- linux-ein-5.4.0.orig/drivers/cpufreq/pcc-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/pcc-cpufreq.c
@@ -109,7 +109,7 @@
 
 static struct pcc_cpu __percpu *pcc_cpu_info;
 
-static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
+static int pcc_cpufreq_verify(struct cpufreq_policy_data *policy)
 {
 	cpufreq_verify_within_cpu_limits(policy);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/cpufreq/pmac32-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/pmac32-cpufreq.c
@@ -471,6 +471,10 @@
 	if (slew_done_gpio_np)
 		slew_done_gpio = read_gpio(slew_done_gpio_np);
 
+	of_node_put(volt_gpio_np);
+	of_node_put(freq_gpio_np);
+	of_node_put(slew_done_gpio_np);
+
 	/* If we use the frequency GPIOs, calculate the min/max speeds based
 	 * on the bus frequencies
 	 */
--- linux-ein-5.4.0.orig/drivers/cpufreq/powernow-k8.c
+++ linux-ein-5.4.0/drivers/cpufreq/powernow-k8.c
@@ -878,9 +878,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;
@@ -912,9 +912,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);
@@ -969,7 +966,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");
@@ -1104,7 +1101,8 @@
 
 	kfree(data->powernow_table);
 	kfree(data);
-	for_each_cpu(cpu, pol->cpus)
+	/* pol->cpus will be empty here, use related_cpus instead. */
+	for_each_cpu(cpu, pol->related_cpus)
 		per_cpu(powernow_data, cpu) = NULL;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/cpufreq/powernv-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/powernv-cpufreq.c
@@ -36,6 +36,7 @@
 #define MAX_PSTATE_SHIFT	32
 #define LPSTATE_SHIFT		48
 #define GPSTATE_SHIFT		56
+#define MAX_NR_CHIPS		32
 
 #define MAX_RAMP_DOWN_TIME				5120
 /*
@@ -884,12 +885,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;
@@ -902,6 +906,7 @@
 void powernv_cpufreq_work_fn(struct work_struct *work)
 {
 	struct chip *chip = container_of(work, struct chip, throttle);
+	struct cpufreq_policy *policy;
 	unsigned int cpu;
 	cpumask_t mask;
 
@@ -916,12 +921,14 @@
 	chip->restore = false;
 	for_each_cpu(cpu, &mask) {
 		int index;
-		struct cpufreq_policy policy;
 
-		cpufreq_get_policy(&policy, cpu);
-		index = cpufreq_table_find_index_c(&policy, policy.cur);
-		powernv_cpufreq_target_index(&policy, index);
-		cpumask_andnot(&mask, &mask, policy.cpus);
+		policy = cpufreq_cpu_get(cpu);
+		if (!policy)
+			continue;
+		index = cpufreq_table_find_index_c(policy, policy->cur);
+		powernv_cpufreq_target_index(policy, index);
+		cpumask_andnot(&mask, &mask, policy->cpus);
+		cpufreq_cpu_put(policy);
 	}
 out:
 	put_online_cpus();
@@ -1041,9 +1048,22 @@
 
 static int init_chip_info(void)
 {
-	unsigned int chip[256];
+	unsigned int *chip;
 	unsigned int cpu, i;
 	unsigned int prev_chip_id = UINT_MAX;
+	cpumask_t *chip_cpu_mask;
+	int ret = 0;
+
+	chip = kcalloc(num_possible_cpus(), sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	/* Allocate a chip cpu mask large enough to fit mask for all chips */
+	chip_cpu_mask = kcalloc(MAX_NR_CHIPS, sizeof(cpumask_t), GFP_KERNEL);
+	if (!chip_cpu_mask) {
+		ret = -ENOMEM;
+		goto free_and_return;
+	}
 
 	for_each_possible_cpu(cpu) {
 		unsigned int id = cpu_to_chip_id(cpu);
@@ -1052,25 +1072,38 @@
 			prev_chip_id = id;
 			chip[nr_chips++] = id;
 		}
+		cpumask_set_cpu(cpu, &chip_cpu_mask[nr_chips-1]);
 	}
 
 	chips = kcalloc(nr_chips, sizeof(struct chip), GFP_KERNEL);
-	if (!chips)
-		return -ENOMEM;
+	if (!chips) {
+		ret = -ENOMEM;
+		goto out_free_chip_cpu_mask;
+	}
 
 	for (i = 0; i < nr_chips; i++) {
 		chips[i].id = chip[i];
-		cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
+		cpumask_copy(&chips[i].mask, &chip_cpu_mask[i]);
 		INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
 		for_each_cpu(cpu, &chips[i].mask)
 			per_cpu(chip_info, cpu) =  &chips[i];
 	}
 
-	return 0;
+out_free_chip_cpu_mask:
+	kfree(chip_cpu_mask);
+free_and_return:
+	kfree(chip);
+	return ret;
 }
 
 static inline void clean_chip_info(void)
 {
+	int i;
+
+	/* flush any pending work items */
+	if (chips)
+		for (i = 0; i < nr_chips; i++)
+			cancel_work_sync(&chips[i].throttle);
 	kfree(chips);
 }
 
--- linux-ein-5.4.0.orig/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ linux-ein-5.4.0/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -305,6 +305,7 @@
 	{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
 	{},
 };
+MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list);
 
 /*
  * Since the driver depends on smem and nvmem drivers, which may
--- linux-ein-5.4.0.orig/drivers/cpufreq/scpi-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/scpi-cpufreq.c
@@ -239,6 +239,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-ein-5.4.0.orig/drivers/cpufreq/sh-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/sh-cpufreq.c
@@ -87,7 +87,7 @@
 	return work_on_cpu(policy->cpu, __sh_cpufreq_target, &data);
 }
 
-static int sh_cpufreq_verify(struct cpufreq_policy *policy)
+static int sh_cpufreq_verify(struct cpufreq_policy_data *policy)
 {
 	struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
 	struct cpufreq_frequency_table *freq_table;
--- linux-ein-5.4.0.orig/drivers/cpufreq/sti-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/sti-cpufreq.c
@@ -141,7 +141,8 @@
 static const struct reg_field *sti_cpufreq_match(void)
 {
 	if (of_machine_is_compatible("st,stih407") ||
-	    of_machine_is_compatible("st,stih410"))
+	    of_machine_is_compatible("st,stih410") ||
+	    of_machine_is_compatible("st,stih418"))
 		return sti_stih407_dvfs_regfields;
 
 	return NULL;
@@ -258,7 +259,8 @@
 	int ret;
 
 	if ((!of_machine_is_compatible("st,stih407")) &&
-		(!of_machine_is_compatible("st,stih410")))
+		(!of_machine_is_compatible("st,stih410")) &&
+		(!of_machine_is_compatible("st,stih418")))
 		return -ENODEV;
 
 	ddata.cpu = get_cpu_device(0);
@@ -290,6 +292,13 @@
 }
 module_init(sti_cpufreq_init);
 
+static const struct of_device_id __maybe_unused sti_cpufreq_of_match[] = {
+	{ .compatible = "st,stih407" },
+	{ .compatible = "st,stih410" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sti_cpufreq_of_match);
+
 MODULE_DESCRIPTION("STMicroelectronics CPUFreq/OPP driver");
 MODULE_AUTHOR("Ajitpal Singh <ajitpal.singh@st.com>");
 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
--- linux-ein-5.4.0.orig/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+++ linux-ein-5.4.0/drivers/cpufreq/sun50i-cpufreq-nvmem.c
@@ -25,7 +25,7 @@
 static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
 
 /**
- * sun50i_cpufreq_get_efuse() - Parse and return efuse value present on SoC
+ * sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
  * @versions: Set to the value parsed from efuse
  *
  * Returns 0 if success.
@@ -69,21 +69,16 @@
 		return PTR_ERR(speedbin);
 
 	efuse_value = (*speedbin >> NVMEM_SHIFT) & NVMEM_MASK;
-	switch (efuse_value) {
-	case 0b0001:
-		*versions = 1;
-		break;
-	case 0b0011:
-		*versions = 2;
-		break;
-	default:
-		/*
-		 * For other situations, we treat it as bin0.
-		 * This vf table can be run for any good cpu.
-		 */
+
+	/*
+	 * We treat unexpected efuse values as if the SoC was from
+	 * the slowest bin. Expected efuse values are 1-3, slowest
+	 * to fastest.
+	 */
+	if (efuse_value >= 1 && efuse_value <= 3)
+		*versions = efuse_value - 1;
+	else
 		*versions = 0;
-		break;
-	}
 
 	kfree(speedbin);
 	return 0;
@@ -103,8 +98,10 @@
 		return -ENOMEM;
 
 	ret = sun50i_cpufreq_get_efuse(&speed);
-	if (ret)
+	if (ret) {
+		kfree(opp_tables);
 		return ret;
+	}
 
 	snprintf(name, MAX_NAME_LEN, "speed%d", speed);
 
@@ -172,6 +169,7 @@
 	{ .compatible = "allwinner,sun50i-h6" },
 	{}
 };
+MODULE_DEVICE_TABLE(of, sun50i_cpufreq_match_list);
 
 static const struct of_device_id *sun50i_cpufreq_match_node(void)
 {
--- linux-ein-5.4.0.orig/drivers/cpufreq/unicore2-cpufreq.c
+++ linux-ein-5.4.0/drivers/cpufreq/unicore2-cpufreq.c
@@ -22,7 +22,7 @@
 /* make sure that only the "userspace" governor is run
  * -- anything else wouldn't make sense on this platform, anyway.
  */
-static int ucv2_verify_speed(struct cpufreq_policy *policy)
+static int ucv2_verify_speed(struct cpufreq_policy_data *policy)
 {
 	if (policy->cpu)
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/cpuidle/cpuidle-powernv.c
+++ linux-ein-5.4.0/drivers/cpuidle/cpuidle-powernv.c
@@ -56,13 +56,10 @@
 		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)
+		if (dev->states_usage[i].disable)
 			continue;
 
-		return s->target_residency * tb_ticks_per_usec;
+		return drv->states[i].target_residency * tb_ticks_per_usec;
 	}
 
 	return default_snooze_timeout;
--- linux-ein-5.4.0.orig/drivers/cpuidle/cpuidle.c
+++ linux-ein-5.4.0/drivers/cpuidle/cpuidle.c
@@ -84,12 +84,12 @@
 
 	for (i = 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 || s->exit_latency <= latency_req
-		    || s->exit_latency > max_latency
-		    || (s->flags & forbidden_flags)
-		    || (s2idle && !s->enter_s2idle))
+		if (dev->states_usage[i].disable ||
+		    s->exit_latency <= latency_req ||
+		    s->exit_latency > max_latency ||
+		    (s->flags & forbidden_flags) ||
+		    (s2idle && !s->enter_s2idle))
 			continue;
 
 		latency_req = s->exit_latency;
@@ -148,7 +148,8 @@
 	 */
 	stop_critical_timings();
 	drv->states[index].enter_s2idle(dev, drv, index);
-	WARN_ON(!irqs_disabled());
+	if (WARN_ON_ONCE(!irqs_disabled()))
+		local_irq_disable();
 	/*
 	 * timekeeping_resume() that will be called by tick_unfreeze() for the
 	 * first CPU executing it calls functions containing RCU read-side
@@ -265,8 +266,7 @@
 
 		if (diff < drv->states[entered_state].target_residency) {
 			for (i = entered_state - 1; i >= 0; i--) {
-				if (drv->states[i].disabled ||
-				    dev->states_usage[i].disable)
+				if (dev->states_usage[i].disable)
 					continue;
 
 				/* Shallower states are enabled, so update. */
@@ -275,8 +275,7 @@
 			}
 		} else if (diff > delay) {
 			for (i = entered_state + 1; i < drv->state_count; i++) {
-				if (drv->states[i].disabled ||
-				    dev->states_usage[i].disable)
+				if (dev->states_usage[i].disable)
 					continue;
 
 				/*
@@ -380,10 +379,11 @@
 
 	limit_ns = TICK_NSEC;
 	for (i = 1; i < drv->state_count; i++) {
-		if (drv->states[i].disabled || dev->states_usage[i].disable)
+		if (dev->states_usage[i].disable)
 			continue;
 
 		limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
+		break;
 	}
 
 	dev->poll_limit_ns = limit_ns;
@@ -567,12 +567,16 @@
  */
 static int __cpuidle_register_device(struct cpuidle_device *dev)
 {
-	int ret;
 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+	int i, ret;
 
 	if (!try_module_get(drv->owner))
 		return -EINVAL;
 
+	for (i = 0; i < drv->state_count; i++)
+		if (drv->states[i].disabled)
+			dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
+
 	per_cpu(cpuidle_devices, dev->cpu) = dev;
 	list_add(&dev->device_list, &cpuidle_detected_devices);
 
--- linux-ein-5.4.0.orig/drivers/cpuidle/driver.c
+++ linux-ein-5.4.0/drivers/cpuidle/driver.c
@@ -62,24 +62,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;
 }
@@ -379,3 +378,31 @@
 
 	spin_unlock(&cpuidle_driver_lock);
 }
+
+/**
+ * cpuidle_driver_state_disabled - Disable or enable an idle state
+ * @drv: cpuidle driver owning the state
+ * @idx: State index
+ * @disable: Whether or not to disable the state
+ */
+void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
+				 bool disable)
+{
+	unsigned int cpu;
+
+	mutex_lock(&cpuidle_lock);
+
+	for_each_cpu(cpu, drv->cpumask) {
+		struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
+
+		if (!dev)
+			continue;
+
+		if (disable)
+			dev->states_usage[idx].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
+		else
+			dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER;
+	}
+
+	mutex_unlock(&cpuidle_lock);
+}
--- linux-ein-5.4.0.orig/drivers/cpuidle/dt_idle_states.c
+++ linux-ein-5.4.0/drivers/cpuidle/dt_idle_states.c
@@ -224,6 +224,6 @@
 	 * also be 0 on platforms with missing DT idle states or legacy DT
 	 * configuration predating the DT idle states bindings.
 	 */
-	return i;
+	return state_idx - start_idx;
 }
 EXPORT_SYMBOL_GPL(dt_init_idle_driver);
--- linux-ein-5.4.0.orig/drivers/cpuidle/governors/ladder.c
+++ linux-ein-5.4.0/drivers/cpuidle/governors/ladder.c
@@ -84,7 +84,6 @@
 
 	/* consider promotion */
 	if (last_idx < drv->state_count - 1 &&
-	    !drv->states[last_idx + 1].disabled &&
 	    !dev->states_usage[last_idx + 1].disable &&
 	    last_residency > last_state->threshold.promotion_time &&
 	    drv->states[last_idx + 1].exit_latency <= latency_req) {
@@ -98,8 +97,7 @@
 
 	/* consider demotion */
 	if (last_idx > first_idx &&
-	    (drv->states[last_idx].disabled ||
-	    dev->states_usage[last_idx].disable ||
+	    (dev->states_usage[last_idx].disable ||
 	    drv->states[last_idx].exit_latency > latency_req)) {
 		int i;
 
--- linux-ein-5.4.0.orig/drivers/cpuidle/governors/menu.c
+++ linux-ein-5.4.0/drivers/cpuidle/governors/menu.c
@@ -298,7 +298,7 @@
 	if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
 	    ((data->next_timer_us < drv->states[1].target_residency ||
 	      latency_req < drv->states[1].exit_latency) &&
-	     !drv->states[0].disabled && !dev->states_usage[0].disable)) {
+	     !dev->states_usage[0].disable)) {
 		/*
 		 * In this case state[0] will be used no matter what, so return
 		 * it right away and keep the tick running if state[0] is a
@@ -349,9 +349,8 @@
 	idx = -1;
 	for (i = 0; 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)
+		if (dev->states_usage[i].disable)
 			continue;
 
 		if (idx == -1)
@@ -422,8 +421,7 @@
 			 * tick, so try to correct that.
 			 */
 			for (i = idx - 1; i >= 0; i--) {
-				if (drv->states[i].disabled ||
-				    dev->states_usage[i].disable)
+				if (dev->states_usage[i].disable)
 					continue;
 
 				idx = i;
--- linux-ein-5.4.0.orig/drivers/cpuidle/governors/teo.c
+++ linux-ein-5.4.0/drivers/cpuidle/governors/teo.c
@@ -194,7 +194,7 @@
 	 * pattern detection.
 	 */
 	cpu_data->intervals[cpu_data->interval_idx++] = measured_us;
-	if (cpu_data->interval_idx > INTERVALS)
+	if (cpu_data->interval_idx >= INTERVALS)
 		cpu_data->interval_idx = 0;
 }
 
@@ -212,7 +212,7 @@
 	int i;
 
 	for (i = state_idx - 1; i >= 0; i--) {
-		if (drv->states[i].disabled || dev->states_usage[i].disable)
+		if (dev->states_usage[i].disable)
 			continue;
 
 		state_idx = i;
@@ -233,8 +233,8 @@
 {
 	struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
 	int latency_req = cpuidle_governor_latency_req(dev->cpu);
-	unsigned int duration_us, count;
-	int max_early_idx, constraint_idx, idx, i;
+	unsigned int duration_us, hits, misses, early_hits;
+	int max_early_idx, prev_max_early_idx, constraint_idx, idx, i;
 	ktime_t delta_tick;
 
 	if (dev->last_state_idx >= 0) {
@@ -247,34 +247,75 @@
 	cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick);
 	duration_us = ktime_to_us(cpu_data->sleep_length_ns);
 
-	count = 0;
+	hits = 0;
+	misses = 0;
+	early_hits = 0;
 	max_early_idx = -1;
+	prev_max_early_idx = -1;
 	constraint_idx = drv->state_count;
 	idx = -1;
 
 	for (i = 0; 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) {
+		if (dev->states_usage[i].disable) {
 			/*
-			 * If the "early hits" metric of a disabled state is
-			 * greater than the current maximum, it should be taken
-			 * into account, because it would be a mistake to select
-			 * a deeper state with lower "early hits" metric.  The
-			 * index cannot be changed to point to it, however, so
-			 * just increase the max count alone and let the index
-			 * still point to a shallower idle state.
+			 * Ignore disabled states with target residencies beyond
+			 * the anticipated idle duration.
 			 */
-			if (max_early_idx >= 0 &&
-			    count < cpu_data->states[i].early_hits)
-				count = cpu_data->states[i].early_hits;
+			if (s->target_residency > duration_us)
+				continue;
+
+			/*
+			 * This state is disabled, so the range of idle duration
+			 * values corresponding to it is covered by the current
+			 * candidate state, but still the "hits" and "misses"
+			 * metrics of the disabled state need to be used to
+			 * decide whether or not the state covering the range in
+			 * question is good enough.
+			 */
+			hits = cpu_data->states[i].hits;
+			misses = cpu_data->states[i].misses;
+
+			if (early_hits >= cpu_data->states[i].early_hits ||
+			    idx < 0)
+				continue;
+
+			/*
+			 * If the current candidate state has been the one with
+			 * the maximum "early hits" metric so far, the "early
+			 * hits" metric of the disabled state replaces the
+			 * current "early hits" count to avoid selecting a
+			 * deeper state with lower "early hits" metric.
+			 */
+			if (max_early_idx == idx) {
+				early_hits = cpu_data->states[i].early_hits;
+				continue;
+			}
+
+			/*
+			 * The current candidate state is closer to the disabled
+			 * one than the current maximum "early hits" state, so
+			 * replace the latter with it, but in case the maximum
+			 * "early hits" state index has not been set so far,
+			 * check if the current candidate state is not too
+			 * shallow for that role.
+			 */
+			if (!(tick_nohz_tick_stopped() &&
+			      drv->states[idx].target_residency < TICK_USEC)) {
+				prev_max_early_idx = max_early_idx;
+				early_hits = cpu_data->states[i].early_hits;
+				max_early_idx = idx;
+			}
 
 			continue;
 		}
 
-		if (idx < 0)
+		if (idx < 0) {
 			idx = i; /* first enabled state */
+			hits = cpu_data->states[i].hits;
+			misses = cpu_data->states[i].misses;
+		}
 
 		if (s->target_residency > duration_us)
 			break;
@@ -283,11 +324,14 @@
 			constraint_idx = i;
 
 		idx = i;
+		hits = cpu_data->states[i].hits;
+		misses = cpu_data->states[i].misses;
 
-		if (count < cpu_data->states[i].early_hits &&
+		if (early_hits < cpu_data->states[i].early_hits &&
 		    !(tick_nohz_tick_stopped() &&
 		      drv->states[i].target_residency < TICK_USEC)) {
-			count = cpu_data->states[i].early_hits;
+			prev_max_early_idx = max_early_idx;
+			early_hits = cpu_data->states[i].early_hits;
 			max_early_idx = i;
 		}
 	}
@@ -300,10 +344,19 @@
 	 * "early hits" metric, but if that cannot be determined, just use the
 	 * state selected so far.
 	 */
-	if (cpu_data->states[idx].hits <= cpu_data->states[idx].misses &&
-	    max_early_idx >= 0) {
-		idx = max_early_idx;
-		duration_us = drv->states[idx].target_residency;
+	if (hits <= misses) {
+		/*
+		 * The current candidate state is not suitable, so take the one
+		 * whose "early hits" metric is the maximum for the range of
+		 * shallower states.
+		 */
+		if (idx == max_early_idx)
+			max_early_idx = prev_max_early_idx;
+
+		if (max_early_idx >= 0) {
+			idx = max_early_idx;
+			duration_us = drv->states[idx].target_residency;
+		}
 	}
 
 	/*
@@ -316,10 +369,9 @@
 	if (idx < 0) {
 		idx = 0; /* No states enabled. Must use 0. */
 	} else if (idx > 0) {
+		unsigned int count = 0;
 		u64 sum = 0;
 
-		count = 0;
-
 		/*
 		 * Count and sum the most recent idle duration values less than
 		 * the current expected idle duration value.
--- linux-ein-5.4.0.orig/drivers/cpuidle/sysfs.c
+++ linux-ein-5.4.0/drivers/cpuidle/sysfs.c
@@ -255,25 +255,6 @@
 	return sprintf(buf, "%u\n", state->_name);\
 }
 
-#define define_store_state_ull_function(_name) \
-static ssize_t store_state_##_name(struct cpuidle_state *state, \
-				   struct cpuidle_state_usage *state_usage, \
-				   const char *buf, size_t size)	\
-{ \
-	unsigned long long value; \
-	int err; \
-	if (!capable(CAP_SYS_ADMIN)) \
-		return -EPERM; \
-	err = kstrtoull(buf, 0, &value); \
-	if (err) \
-		return err; \
-	if (value) \
-		state_usage->_name = 1; \
-	else \
-		state_usage->_name = 0; \
-	return size; \
-}
-
 #define define_show_state_ull_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
 				  struct cpuidle_state_usage *state_usage, \
@@ -299,11 +280,39 @@
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
-define_show_state_ull_function(disable)
-define_store_state_ull_function(disable)
 define_show_state_ull_function(above)
 define_show_state_ull_function(below)
 
+static ssize_t show_state_disable(struct cpuidle_state *state,
+				  struct cpuidle_state_usage *state_usage,
+				  char *buf)
+{
+	return sprintf(buf, "%llu\n",
+		       state_usage->disable & CPUIDLE_STATE_DISABLED_BY_USER);
+}
+
+static ssize_t store_state_disable(struct cpuidle_state *state,
+				   struct cpuidle_state_usage *state_usage,
+				   const char *buf, size_t size)
+{
+	unsigned int value;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	err = kstrtouint(buf, 0, &value);
+	if (err)
+		return err;
+
+	if (value)
+		state_usage->disable |= CPUIDLE_STATE_DISABLED_BY_USER;
+	else
+		state_usage->disable &= ~CPUIDLE_STATE_DISABLED_BY_USER;
+
+	return size;
+}
+
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
 define_one_state_ro(latency, show_state_exit_latency);
@@ -480,6 +489,7 @@
 		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
 					   &kdev->kobj, "state%d", i);
 		if (ret) {
+			kobject_put(&kobj->kobj);
 			kfree(kobj);
 			goto error_state;
 		}
@@ -611,6 +621,7 @@
 	ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
 				   &kdev->kobj, "driver");
 	if (ret) {
+		kobject_put(&kdrv->kobj);
 		kfree(kdrv);
 		return ret;
 	}
@@ -698,17 +709,18 @@
 	if (!kdev)
 		return -ENOMEM;
 	kdev->dev = dev;
-	dev->kobj_dev = kdev;
 
 	init_completion(&kdev->kobj_unregister);
 
 	error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
 				   "cpuidle");
 	if (error) {
+		kobject_put(&kdev->kobj);
 		kfree(kdev);
 		return error;
 	}
 
+	dev->kobj_dev = kdev;
 	kobject_uevent(&kdev->kobj, KOBJ_ADD);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/crypto/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/Kconfig
@@ -287,6 +287,7 @@
 	select CRYPTO_AUTHENC
 	select CRYPTO_BLKCIPHER
 	select CRYPTO_HASH
+	select CRYPTO_LIB_DES
 	select HW_RANDOM
 	depends on FSL_SOC
 	help
@@ -332,6 +333,7 @@
 	depends on PPC && 4xx
 	select CRYPTO_HASH
 	select CRYPTO_AEAD
+	select CRYPTO_AES
 	select CRYPTO_LIB_AES
 	select CRYPTO_CCM
 	select CRYPTO_CTR
@@ -489,11 +491,9 @@
 endif # if CRYPTO_DEV_UX500
 
 config CRYPTO_DEV_ATMEL_AUTHENC
-	tristate "Support for Atmel IPSEC/SSL hw accelerator"
+	bool "Support for Atmel IPSEC/SSL hw accelerator"
 	depends on ARCH_AT91 || COMPILE_TEST
-	select CRYPTO_AUTHENC
-	select CRYPTO_DEV_ATMEL_AES
-	select CRYPTO_DEV_ATMEL_SHA
+	depends on CRYPTO_DEV_ATMEL_AES
 	help
 	  Some Atmel processors can combine the AES and SHA hw accelerators
 	  to enhance support of IPSEC/SSL.
@@ -506,6 +506,8 @@
 	select CRYPTO_AES
 	select CRYPTO_AEAD
 	select CRYPTO_BLKCIPHER
+	select CRYPTO_AUTHENC if CRYPTO_DEV_ATMEL_AUTHENC
+	select CRYPTO_DEV_ATMEL_SHA if CRYPTO_DEV_ATMEL_AUTHENC
 	help
 	  Some Atmel processors have AES hw accelerator.
 	  Select this if you want to use the Atmel module for
@@ -542,6 +544,7 @@
 
 config CRYPTO_DEV_ATMEL_I2C
 	tristate
+	select BITREVERSE
 
 config CRYPTO_DEV_ATMEL_ECC
 	tristate "Support for Microchip / Atmel ECC hw accelerator"
@@ -737,7 +740,7 @@
 
 config CRYPTO_DEV_SAFEXCEL
 	tristate "Inside Secure's SafeXcel cryptographic engine driver"
-	depends on OF || PCI || COMPILE_TEST
+	depends on (OF || PCI || COMPILE_TEST) && HAS_IOMEM
 	select CRYPTO_LIB_AES
 	select CRYPTO_AUTHENC
 	select CRYPTO_BLKCIPHER
--- linux-ein-5.4.0.orig/drivers/crypto/amcc/crypto4xx_core.c
+++ linux-ein-5.4.0/drivers/crypto/amcc/crypto4xx_core.c
@@ -365,12 +365,8 @@
 		dma_alloc_coherent(dev->core_dev->device,
 			PPC4XX_SD_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;
-	}
 
 	for (i = 0; i < PPC4XX_NUM_SD; i++) {
 		dev->sdr[i].ptr = dev->scatter_buffer_pa +
@@ -525,7 +521,6 @@
 {
 	struct skcipher_request *req;
 	struct scatterlist *dst;
-	dma_addr_t addr;
 
 	req = skcipher_request_cast(pd_uinfo->async_req);
 
@@ -534,8 +529,8 @@
 					  req->cryptlen, req->dst);
 	} else {
 		dst = pd_uinfo->dest_va;
-		addr = dma_map_page(dev->core_dev->device, sg_page(dst),
-				    dst->offset, dst->length, DMA_FROM_DEVICE);
+		dma_unmap_page(dev->core_dev->device, pd->dest, dst->length,
+			       DMA_FROM_DEVICE);
 	}
 
 	if (pd_uinfo->sa_va->sa_command_0.bf.save_iv == SA_SAVE_IV) {
@@ -560,10 +555,9 @@
 	struct ahash_request *ahash_req;
 
 	ahash_req = ahash_request_cast(pd_uinfo->async_req);
-	ctx  = crypto_tfm_ctx(ahash_req->base.tfm);
+	ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(ahash_req));
 
-	crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo,
-				     crypto_tfm_ctx(ahash_req->base.tfm));
+	crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo, ctx);
 	crypto4xx_ret_sg_desc(dev, pd_uinfo);
 
 	if (pd_uinfo->state & PD_ENTRY_BUSY)
@@ -920,7 +914,7 @@
 	}
 
 	pd->pd_ctl.w = PD_CTL_HOST_READY |
-		((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) |
+		((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) ||
 		 (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
 			PD_CTL_HASH_FINAL : 0);
 	pd->pd_ctl_len.w = 0x00400000 | (assoclen + datalen);
--- linux-ein-5.4.0.orig/drivers/crypto/atmel-aes.c
+++ linux-ein-5.4.0/drivers/crypto/atmel-aes.c
@@ -88,7 +88,6 @@
 struct atmel_aes_caps {
 	bool			has_dualbuff;
 	bool			has_cfb64;
-	bool			has_ctr32;
 	bool			has_gcm;
 	bool			has_xts;
 	bool			has_authenc;
@@ -145,7 +144,7 @@
 	u32			key2[AES_KEYSIZE_256 / sizeof(u32)];
 };
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 struct atmel_aes_authenc_ctx {
 	struct atmel_aes_base_ctx	base;
 	struct atmel_sha_authenc_ctx	*auth;
@@ -157,7 +156,7 @@
 	u32			lastc[AES_BLOCK_SIZE / sizeof(u32)];
 };
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 struct atmel_aes_authenc_reqctx {
 	struct atmel_aes_reqctx	base;
 
@@ -486,13 +485,36 @@
 	return (dd->flags & AES_FLAGS_ENCRYPT);
 }
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
 #endif
 
+static void atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev *dd)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq);
+	struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
+	unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+
+	if (req->nbytes < ivsize)
+		return;
+
+	if (rctx->mode & AES_FLAGS_ENCRYPT) {
+		scatterwalk_map_and_copy(req->info, req->dst,
+					 req->nbytes - ivsize, ivsize, 0);
+	} else {
+		if (req->src == req->dst)
+			memcpy(req->info, rctx->lastc, ivsize);
+		else
+			scatterwalk_map_and_copy(req->info, req->src,
+						 req->nbytes - ivsize,
+						 ivsize, 0);
+	}
+}
+
 static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
 {
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 	if (dd->ctx->is_aead)
 		atmel_aes_authenc_complete(dd, err);
 #endif
@@ -500,26 +522,8 @@
 	clk_disable(dd->iclk);
 	dd->flags &= ~AES_FLAGS_BUSY;
 
-	if (!dd->ctx->is_aead) {
-		struct ablkcipher_request *req =
-			ablkcipher_request_cast(dd->areq);
-		struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
-		struct crypto_ablkcipher *ablkcipher =
-			crypto_ablkcipher_reqtfm(req);
-		int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
-
-		if (rctx->mode & AES_FLAGS_ENCRYPT) {
-			scatterwalk_map_and_copy(req->info, req->dst,
-				req->nbytes - ivsize, ivsize, 0);
-		} else {
-			if (req->src == req->dst) {
-				memcpy(req->info, rctx->lastc, ivsize);
-			} else {
-				scatterwalk_map_and_copy(req->info, req->src,
-					req->nbytes - ivsize, ivsize, 0);
-			}
-		}
-	}
+	if (!dd->ctx->is_aead)
+		atmel_aes_set_iv_as_last_ciphertext_block(dd);
 
 	if (dd->is_async)
 		dd->areq->complete(dd->areq, err);
@@ -1008,8 +1012,9 @@
 	struct atmel_aes_ctr_ctx *ctx = atmel_aes_ctr_ctx_cast(dd->ctx);
 	struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq);
 	struct scatterlist *src, *dst;
-	u32 ctr, blocks;
 	size_t datalen;
+	u32 ctr;
+	u16 blocks, start, end;
 	bool use_dma, fragmented = false;
 
 	/* Check for transfer completion. */
@@ -1021,27 +1026,17 @@
 	datalen = req->nbytes - ctx->offset;
 	blocks = DIV_ROUND_UP(datalen, AES_BLOCK_SIZE);
 	ctr = be32_to_cpu(ctx->iv[3]);
-	if (dd->caps.has_ctr32) {
-		/* Check 32bit counter overflow. */
-		u32 start = ctr;
-		u32 end = start + blocks - 1;
-
-		if (end < start) {
-			ctr |= 0xffffffff;
-			datalen = AES_BLOCK_SIZE * -start;
-			fragmented = true;
-		}
-	} else {
-		/* Check 16bit counter overflow. */
-		u16 start = ctr & 0xffff;
-		u16 end = start + (u16)blocks - 1;
-
-		if (blocks >> 16 || end < start) {
-			ctr |= 0xffff;
-			datalen = AES_BLOCK_SIZE * (0x10000-start);
-			fragmented = true;
-		}
+
+	/* Check 16bit counter overflow. */
+	start = ctr & 0xffff;
+	end = start + blocks - 1;
+
+	if (blocks >> 16 || end < start) {
+		ctr |= 0xffff;
+		datalen = AES_BLOCK_SIZE * (0x10000 - start);
+		fragmented = true;
 	}
+
 	use_dma = (datalen >= ATMEL_AES_DMA_THRESHOLD);
 
 	/* Jump to offset. */
@@ -1125,10 +1120,12 @@
 	rctx->mode = mode;
 
 	if (!(mode & AES_FLAGS_ENCRYPT) && (req->src == req->dst)) {
-		int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+		unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
 
-		scatterwalk_map_and_copy(rctx->lastc, req->src,
-			(req->nbytes - ivsize), ivsize, 0);
+		if (req->nbytes >= ivsize)
+			scatterwalk_map_and_copy(rctx->lastc, req->src,
+						 req->nbytes - ivsize,
+						 ivsize, 0);
 	}
 
 	return atmel_aes_handle_queue(dd, &req->base);
@@ -1973,7 +1970,7 @@
 	}
 };
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 /* authenc aead functions */
 
 static int atmel_aes_authenc_start(struct atmel_aes_dev *dd);
@@ -2460,7 +2457,7 @@
 {
 	int i;
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 	if (dd->caps.has_authenc)
 		for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++)
 			crypto_unregister_aead(&aes_authenc_algs[i]);
@@ -2507,7 +2504,7 @@
 			goto err_aes_xts_alg;
 	}
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 	if (dd->caps.has_authenc) {
 		for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) {
 			err = crypto_register_aead(&aes_authenc_algs[i]);
@@ -2519,7 +2516,7 @@
 
 	return 0;
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 	/* i = ARRAY_SIZE(aes_authenc_algs); */
 err_aes_authenc_alg:
 	for (j = 0; j < i; j++)
@@ -2543,7 +2540,6 @@
 {
 	dd->caps.has_dualbuff = 0;
 	dd->caps.has_cfb64 = 0;
-	dd->caps.has_ctr32 = 0;
 	dd->caps.has_gcm = 0;
 	dd->caps.has_xts = 0;
 	dd->caps.has_authenc = 0;
@@ -2554,7 +2550,6 @@
 	case 0x500:
 		dd->caps.has_dualbuff = 1;
 		dd->caps.has_cfb64 = 1;
-		dd->caps.has_ctr32 = 1;
 		dd->caps.has_gcm = 1;
 		dd->caps.has_xts = 1;
 		dd->caps.has_authenc = 1;
@@ -2563,7 +2558,6 @@
 	case 0x200:
 		dd->caps.has_dualbuff = 1;
 		dd->caps.has_cfb64 = 1;
-		dd->caps.has_ctr32 = 1;
 		dd->caps.has_gcm = 1;
 		dd->caps.max_burst_size = 4;
 		break;
@@ -2709,7 +2703,7 @@
 
 	atmel_aes_get_cap(aes_dd);
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 	if (aes_dd->caps.has_authenc && !atmel_sha_authenc_is_ready()) {
 		err = -EPROBE_DEFER;
 		goto iclk_unprepare;
--- linux-ein-5.4.0.orig/drivers/crypto/atmel-authenc.h
+++ linux-ein-5.4.0/drivers/crypto/atmel-authenc.h
@@ -12,7 +12,7 @@
 #ifndef __ATMEL_AUTHENC_H__
 #define __ATMEL_AUTHENC_H__
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 
 #include <crypto/authenc.h>
 #include <crypto/hash.h>
--- linux-ein-5.4.0.orig/drivers/crypto/atmel-sha.c
+++ linux-ein-5.4.0/drivers/crypto/atmel-sha.c
@@ -1918,12 +1918,7 @@
 {
 	struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
 
-	if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) {
-		crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-		return -EINVAL;
-	}
-
-	return 0;
+	return atmel_sha_hmac_key_set(&hmac->hkey, key, keylen);
 }
 
 static int atmel_sha_hmac_init(struct ahash_request *req)
@@ -2212,7 +2207,7 @@
 },
 };
 
-#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
 /* authenc functions */
 
 static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd);
--- linux-ein-5.4.0.orig/drivers/crypto/axis/artpec6_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/axis/artpec6_crypto.c
@@ -1251,7 +1251,7 @@
 
 	if (len != 16 && len != 24 && len != 32) {
 		crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-		return -1;
+		return -EINVAL;
 	}
 
 	ctx->key_length = len;
--- linux-ein-5.4.0.orig/drivers/crypto/bcm/cipher.c
+++ linux-ein-5.4.0/drivers/crypto/bcm/cipher.c
@@ -41,7 +41,7 @@
 
 /* ================= Device Structure ================== */
 
-struct device_private iproc_priv;
+struct bcm_device_private iproc_priv;
 
 /* ==================== Parameters ===================== */
 
@@ -2937,7 +2937,6 @@
 
 	ctx->enckeylen = keylen;
 	ctx->authkeylen = 0;
-	memcpy(ctx->enckey, key, ctx->enckeylen);
 
 	switch (ctx->enckeylen) {
 	case AES_KEYSIZE_128:
@@ -2953,6 +2952,8 @@
 		goto badkey;
 	}
 
+	memcpy(ctx->enckey, key, ctx->enckeylen);
+
 	flow_log("  enckeylen:%u authkeylen:%u\n", ctx->enckeylen,
 		 ctx->authkeylen);
 	flow_dump("  enc: ", ctx->enckey, ctx->enckeylen);
@@ -3013,6 +3014,10 @@
 	struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
 	flow_log("%s\n", __func__);
+
+	if (keylen < GCM_ESP_SALT_SIZE)
+		return -EINVAL;
+
 	ctx->salt_len = GCM_ESP_SALT_SIZE;
 	ctx->salt_offset = GCM_ESP_SALT_OFFSET;
 	memcpy(ctx->salt, key + keylen - GCM_ESP_SALT_SIZE, GCM_ESP_SALT_SIZE);
@@ -3041,6 +3046,10 @@
 	struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
 	flow_log("%s\n", __func__);
+
+	if (keylen < GCM_ESP_SALT_SIZE)
+		return -EINVAL;
+
 	ctx->salt_len = GCM_ESP_SALT_SIZE;
 	ctx->salt_offset = GCM_ESP_SALT_OFFSET;
 	memcpy(ctx->salt, key + keylen - GCM_ESP_SALT_SIZE, GCM_ESP_SALT_SIZE);
@@ -3070,6 +3079,10 @@
 	struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
 	flow_log("%s\n", __func__);
+
+	if (keylen < CCM_ESP_SALT_SIZE)
+		return -EINVAL;
+
 	ctx->salt_len = CCM_ESP_SALT_SIZE;
 	ctx->salt_offset = CCM_ESP_SALT_OFFSET;
 	memcpy(ctx->salt, key + keylen - CCM_ESP_SALT_SIZE, CCM_ESP_SALT_SIZE);
--- linux-ein-5.4.0.orig/drivers/crypto/bcm/cipher.h
+++ linux-ein-5.4.0/drivers/crypto/bcm/cipher.h
@@ -418,7 +418,7 @@
 	u32 num_chan;
 };
 
-struct device_private {
+struct bcm_device_private {
 	struct platform_device *pdev;
 
 	struct spu_hw spu;
@@ -465,6 +465,6 @@
 	struct mbox_chan **mbox;
 };
 
-extern struct device_private iproc_priv;
+extern struct bcm_device_private iproc_priv;
 
 #endif
--- linux-ein-5.4.0.orig/drivers/crypto/bcm/util.c
+++ linux-ein-5.4.0/drivers/crypto/bcm/util.c
@@ -348,7 +348,7 @@
 static ssize_t spu_debugfs_read(struct file *filp, char __user *ubuf,
 				size_t count, loff_t *offp)
 {
-	struct device_private *ipriv;
+	struct bcm_device_private *ipriv;
 	char *buf;
 	ssize_t ret, out_offset, out_count;
 	int i;
--- linux-ein-5.4.0.orig/drivers/crypto/caam/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/caam/Kconfig
@@ -8,6 +8,17 @@
 config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
 	tristate
 
+config CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC
+	tristate
+
+config CRYPTO_DEV_FSL_CAAM_SECVIO
+	tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
+	depends on ARCH_MXC
+	help
+	  Enables installation of an interrupt handler with registrable
+          handler functions which can be specified to act on the consequences
+          of a security violation.
+
 config CRYPTO_DEV_FSL_CAAM
 	tristate "Freescale CAAM-Multicore platform driver backend"
 	depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
@@ -112,6 +123,7 @@
 	select CRYPTO_AUTHENC
 	select CRYPTO_BLKCIPHER
 	select CRYPTO_DES
+	select CRYPTO_XTS
 	help
 	  Selecting this will use CAAM Queue Interface (QI) for sending
 	  & receiving crypto jobs to/from CAAM. This gives better performance
@@ -147,6 +159,67 @@
 	  Selecting this will register the SEC4 hardware rng to
 	  the hw_random API for suppying the kernel entropy pool.
 
+config CRYPTO_DEV_FSL_CAAM_TK_API
+	bool "Register tagged key cryptography implementations with Crypto API"
+	default y
+	select CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+	select CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC
+	help
+	  Selecting this will register algorithms supporting tagged key and
+	  generate black keys and encapsulate them into black blobs.
+
+	  Tagged keys are black keys that contain metadata indicating what
+	  they are and how to handle them.
+	  CAAM protects data in a data structure called a Blob, which provides
+	  both confidentiality and integrity protection.
+
+config CRYPTO_DEV_FSL_CAAM_TK_API_TEST
+	tristate "CAAM keys and blobs test"
+	depends on CRYPTO_DEV_FSL_CAAM_TK_API
+	depends on m
+	help
+	  Test to exercise black key generation and blob encapsulation and
+	  decapsulation.
+
+config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+	bool "Test caam rng"
+	depends on CRYPTO_DEV_FSL_CAAM_RNG_API
+	help
+	  Selecting this will enable a self-test to run for the
+	  caam RNG. This test is several minutes long and executes
+	  just before the RNG is registered with the hw_random API.
+
+config CRYPTO_DEV_FSL_CAAM_SM
+	bool "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
+	help
+	  Enables use of a prototype kernel-level Keystore API with CAAM
+	  Secure Memory for insertion/extraction of bus-protected secrets.
+
+config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE
+	int "Size of each keystore slot in Secure Memory"
+	depends on CRYPTO_DEV_FSL_CAAM_SM
+	range 5 9
+	default 7
+	help
+	  Select size of allocation units to divide Secure Memory pages into
+	  (the size of a "slot" as referenced inside the API code).
+	  Established as powers of two.
+	  Examples:
+		5 => 32 bytes
+		6 => 64 bytes
+		7 => 128 bytes
+		8 => 256 bytes
+		9 => 512 bytes
+
+config CRYPTO_DEV_FSL_CAAM_SM_TEST
+	tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)"
+	depends on CRYPTO_DEV_FSL_CAAM_SM
+	depends on m
+	help
+	  Example thread to exercise the Keystore API and to verify that
+	  stored and recovered secrets can be used for general purpose
+	  encryption/decryption.
+
 endif # CRYPTO_DEV_FSL_CAAM_JR
 
 endif # CRYPTO_DEV_FSL_CAAM
--- linux-ein-5.4.0.orig/drivers/crypto/caam/Makefile
+++ linux-ein-5.4.0/drivers/crypto/caam/Makefile
@@ -13,14 +13,20 @@
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC) += caamkeyblob_desc.o
 
 caam-y := ctrl.o
 caam_jr-y := jr.o key_gen.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o caamkeyblob.o caamkeygen.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
 caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API_TEST) += caamkeyblob_test.o
 
 caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
 ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamalg.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamalg.c
@@ -3,7 +3,7 @@
  * caam - Freescale FSL CAAM support for crypto API
  *
  * Copyright 2008-2011 Freescale Semiconductor, Inc.
- * Copyright 2016-2019 NXP
+ * Copyright 2016-2020 NXP
  *
  * Based on talitos crypto API driver.
  *
@@ -57,6 +57,10 @@
 #include "key_gen.h"
 #include "caamalg_desc.h"
 
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
+#include "tag_object.h"
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
+
 /*
  * crypto alg
  */
@@ -83,6 +87,7 @@
 	bool rfc3686;
 	bool geniv;
 	bool nodkp;
+	bool support_tagged_key;
 };
 
 struct caam_aead_alg {
@@ -553,7 +558,8 @@
 		return -EINVAL;
 	}
 
-	ctx->cdata.key_virt = key;
+	memcpy(ctx->key, key, keylen);
+	ctx->cdata.key_virt = ctx->key;
 	ctx->cdata.keylen = keylen - saltlen;
 
 	return chachapoly_set_sh_desc(aead);
@@ -732,12 +738,19 @@
 	u32 *desc;
 	const bool is_rfc3686 = alg->caam.rfc3686;
 
-	print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+	/*
+	 * If the algorithm has support for tagged key,
+	 * this is already set in tk_skcipher_setkey().
+	 * Otherwise, set here the algorithm details.
+	 */
+	if (!alg->caam.support_tagged_key) {
+		ctx->cdata.keylen = keylen;
+		ctx->cdata.key_virt = key;
+		ctx->cdata.key_inline = true;
+	}
 
-	ctx->cdata.keylen = keylen;
-	ctx->cdata.key_virt = key;
-	ctx->cdata.key_inline = true;
+	print_hex_dump_debug("key in @" __stringify(__LINE__) ": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
 
 	/* skcipher_encrypt shared descriptor */
 	desc = ctx->sh_desc_enc;
@@ -818,11 +831,64 @@
 	return skcipher_setkey(skcipher, key, keylen, ctx1_iv_off);
 }
 
-static int arc4_skcipher_setkey(struct crypto_skcipher *skcipher,
-				const u8 *key, unsigned int keylen)
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
+static int tk_skcipher_setkey(struct crypto_skcipher *skcipher,
+			      const u8 *key, unsigned int keylen)
 {
-	return skcipher_setkey(skcipher, key, keylen, 0);
+	struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+	struct device *jrdev = ctx->jrdev;
+	struct header_conf *header;
+	struct tagged_object *tag_obj;
+	int ret;
+
+	ctx->cdata.key_inline = true;
+
+	/* Check if one can retrieve the tag object header configuration */
+	if (keylen <= TAG_OVERHEAD_SIZE)
+		return -EINVAL;
+
+	/* Retrieve the tag object */
+	tag_obj = (struct tagged_object *)key;
+
+	/*
+	 * Check tag object header configuration
+	 * and retrieve the tag object header configuration
+	 */
+	if (is_valid_header_conf(&tag_obj->header)) {
+		header = &tag_obj->header;
+	} else {
+		dev_err(jrdev,
+			"unable to get tag object header configuration\n");
+		return -EINVAL;
+	}
+
+	/* Check if the tag object header is a black key */
+	if (!is_black_key(header)) {
+		dev_err(jrdev,
+			"tagged key provided is not a black key\n");
+		return -EINVAL;
+	}
+
+	/* Retrieve the black key configuration */
+	get_key_conf(header,
+		     &ctx->cdata.key_real_len,
+		     &ctx->cdata.keylen,
+		     &ctx->cdata.key_cmd_opt);
+
+	/* Retrieve the address of the data of the tagged object */
+	ctx->cdata.key_virt = &tag_obj->object;
+
+	/* Validate key length for AES algorithms */
+	ret = aes_check_keylen(ctx->cdata.key_real_len);
+	if (ret) {
+		crypto_skcipher_set_flags(skcipher,
+					  CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return ret;
+	}
+
+	return skcipher_setkey(skcipher, NULL, 0, 0);
 }
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
 
 static int des_skcipher_setkey(struct crypto_skcipher *skcipher,
 			       const u8 *key, unsigned int keylen)
@@ -1810,7 +1876,7 @@
 
 	if (ivsize || mapped_dst_nents > 1)
 		sg_to_sec4_set_last(edesc->sec4_sg + dst_sg_idx +
-				    mapped_dst_nents);
+				    mapped_dst_nents - 1 + !!ivsize);
 
 	if (sec4_sg_bytes) {
 		edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
@@ -1924,6 +1990,25 @@
 		},
 		.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
 	},
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
+	{
+		.skcipher = {
+			.base = {
+				.cra_name = "tk(cbc(aes))",
+				.cra_driver_name = "tk-cbc-aes-caam",
+				.cra_blocksize = AES_BLOCK_SIZE,
+			},
+			.setkey = tk_skcipher_setkey,
+			.encrypt = skcipher_encrypt,
+			.decrypt = skcipher_decrypt,
+			.min_keysize = TAG_MIN_SIZE,
+			.max_keysize = CAAM_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+		},
+		.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+		.caam.support_tagged_key = true,
+	},
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
 	{
 		.skcipher = {
 			.base = {
@@ -2043,35 +2128,38 @@
 		},
 		.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
 	},
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
 	{
 		.skcipher = {
 			.base = {
-				.cra_name = "ecb(des3_ede)",
-				.cra_driver_name = "ecb-des3-caam",
-				.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+				.cra_name = "tk(ecb(aes))",
+				.cra_driver_name = "tk-ecb-aes-caam",
+				.cra_blocksize = AES_BLOCK_SIZE,
 			},
-			.setkey = des3_skcipher_setkey,
+			.setkey = tk_skcipher_setkey,
 			.encrypt = skcipher_encrypt,
 			.decrypt = skcipher_decrypt,
-			.min_keysize = DES3_EDE_KEY_SIZE,
-			.max_keysize = DES3_EDE_KEY_SIZE,
+			.min_keysize = TAG_MIN_SIZE,
+			.max_keysize = CAAM_MAX_KEY_SIZE,
 		},
-		.caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB,
+		.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
+		.caam.support_tagged_key = true,
 	},
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
 	{
 		.skcipher = {
 			.base = {
-				.cra_name = "ecb(arc4)",
-				.cra_driver_name = "ecb-arc4-caam",
-				.cra_blocksize = ARC4_BLOCK_SIZE,
+				.cra_name = "ecb(des3_ede)",
+				.cra_driver_name = "ecb-des3-caam",
+				.cra_blocksize = DES3_EDE_BLOCK_SIZE,
 			},
-			.setkey = arc4_skcipher_setkey,
+			.setkey = des3_skcipher_setkey,
 			.encrypt = skcipher_encrypt,
 			.decrypt = skcipher_decrypt,
-			.min_keysize = ARC4_MIN_KEY_SIZE,
-			.max_keysize = ARC4_MAX_KEY_SIZE,
+			.min_keysize = DES3_EDE_KEY_SIZE,
+			.max_keysize = DES3_EDE_KEY_SIZE,
 		},
-		.caam.class1_alg_type = OP_ALG_ALGSEL_ARC4 | OP_ALG_AAI_ECB,
+		.caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB,
 	},
 };
 
@@ -3533,7 +3621,6 @@
 	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
 	int i = 0, err = 0;
 	u32 aes_vid, aes_inst, des_inst, md_vid, md_inst, ccha_inst, ptha_inst;
-	u32 arc4_inst;
 	unsigned int md_limit = SHA512_DIGEST_SIZE;
 	bool registered = false, gcm_support;
 
@@ -3542,40 +3629,38 @@
 	 * First, detect presence and attributes of DES, AES, and MD blocks.
 	 */
 	if (priv->era < 10) {
+		struct caam_perfmon __iomem *perfmon = &priv->jr[0]->perfmon;
 		u32 cha_vid, cha_inst, aes_rn;
 
-		cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+		cha_vid = rd_reg32(&perfmon->cha_id_ls);
 		aes_vid = cha_vid & CHA_ID_LS_AES_MASK;
 		md_vid = (cha_vid & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
 
-		cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+		cha_inst = rd_reg32(&perfmon->cha_num_ls);
 		des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >>
 			   CHA_ID_LS_DES_SHIFT;
 		aes_inst = cha_inst & CHA_ID_LS_AES_MASK;
 		md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
-		arc4_inst = (cha_inst & CHA_ID_LS_ARC4_MASK) >>
-			    CHA_ID_LS_ARC4_SHIFT;
 		ccha_inst = 0;
 		ptha_inst = 0;
 
-		aes_rn = rd_reg32(&priv->ctrl->perfmon.cha_rev_ls) &
-			 CHA_ID_LS_AES_MASK;
+		aes_rn = rd_reg32(&perfmon->cha_rev_ls) & CHA_ID_LS_AES_MASK;
 		gcm_support = !(aes_vid == CHA_VER_VID_AES_LP && aes_rn < 8);
 	} else {
+		struct version_regs __iomem *vreg = &priv->jr[0]->vreg;
 		u32 aesa, mdha;
 
-		aesa = rd_reg32(&priv->ctrl->vreg.aesa);
-		mdha = rd_reg32(&priv->ctrl->vreg.mdha);
+		aesa = rd_reg32(&vreg->aesa);
+		mdha = rd_reg32(&vreg->mdha);
 
 		aes_vid = (aesa & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
 		md_vid = (mdha & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
 
-		des_inst = rd_reg32(&priv->ctrl->vreg.desa) & CHA_VER_NUM_MASK;
+		des_inst = rd_reg32(&vreg->desa) & CHA_VER_NUM_MASK;
 		aes_inst = aesa & CHA_VER_NUM_MASK;
 		md_inst = mdha & CHA_VER_NUM_MASK;
-		ccha_inst = rd_reg32(&priv->ctrl->vreg.ccha) & CHA_VER_NUM_MASK;
-		ptha_inst = rd_reg32(&priv->ctrl->vreg.ptha) & CHA_VER_NUM_MASK;
-		arc4_inst = rd_reg32(&priv->ctrl->vreg.afha) & CHA_VER_NUM_MASK;
+		ccha_inst = rd_reg32(&vreg->ccha) & CHA_VER_NUM_MASK;
+		ptha_inst = rd_reg32(&vreg->ptha) & CHA_VER_NUM_MASK;
 
 		gcm_support = aesa & CHA_VER_MISC_AES_GCM;
 	}
@@ -3598,10 +3683,6 @@
 		if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES))
 				continue;
 
-		/* Skip ARC4 algorithms if not supported by device */
-		if (!arc4_inst && alg_sel == OP_ALG_ALGSEL_ARC4)
-			continue;
-
 		/*
 		 * Check support for AES modes not available
 		 * on LP devices.
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamalg_desc.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamalg_desc.c
@@ -1379,6 +1379,9 @@
 				const u32 ctx1_iv_off)
 {
 	u32 *key_jump_cmd;
+	u32 options = cdata->algtype | OP_ALG_AS_INIT | OP_ALG_ENCRYPT;
+	bool is_chacha20 = ((cdata->algtype & OP_ALG_ALGSEL_MASK) ==
+			    OP_ALG_ALGSEL_CHACHA20);
 
 	init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);
 	/* Skip if already shared */
@@ -1386,8 +1389,18 @@
 				   JUMP_COND_SHRD);
 
 	/* Load class1 key only */
-	append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
-			  cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
+	if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) &&
+	    cdata->key_cmd_opt)
+		/*
+		 * Black keys can be loaded using only a KEY command
+		 * with ENC=1 and the proper setting of the EKT bit.
+		 */
+		append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+				  cdata->key_real_len, CLASS_1 |
+				  KEY_DEST_CLASS_REG | cdata->key_cmd_opt);
+	else
+		append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+				  cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
 
 	/* Load nonce into CONTEXT1 reg */
 	if (is_rfc3686) {
@@ -1417,14 +1430,15 @@
 				      LDST_OFFSET_SHIFT));
 
 	/* Load operation */
-	append_operation(desc, cdata->algtype | OP_ALG_AS_INIT |
-			 OP_ALG_ENCRYPT);
+	if (is_chacha20)
+		options |= OP_ALG_AS_FINALIZE;
+	append_operation(desc, options);
 
 	/* Perform operation */
 	skcipher_append_src_dst(desc);
 
 	/* Store IV */
-	if (ivsize)
+	if (!is_chacha20 && ivsize)
 		append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT |
 				 LDST_CLASS_1_CCB | (ctx1_iv_off <<
 				 LDST_OFFSET_SHIFT));
@@ -1451,6 +1465,8 @@
 				const u32 ctx1_iv_off)
 {
 	u32 *key_jump_cmd;
+	bool is_chacha20 = ((cdata->algtype & OP_ALG_ALGSEL_MASK) ==
+			    OP_ALG_ALGSEL_CHACHA20);
 
 	init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);
 	/* Skip if already shared */
@@ -1458,8 +1474,18 @@
 				   JUMP_COND_SHRD);
 
 	/* Load class1 key only */
-	append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
-			  cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
+	if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) &&
+	    cdata->key_cmd_opt)
+		/*
+		 * Black keys can be loaded using only a KEY command
+		 * with ENC=1 and the proper setting of the EKT bit.
+		 */
+		append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+				  cdata->key_real_len, CLASS_1 |
+				  KEY_DEST_CLASS_REG | cdata->key_cmd_opt);
+	else
+		append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
+				  cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
 
 	/* Load nonce into CONTEXT1 reg */
 	if (is_rfc3686) {
@@ -1499,7 +1525,7 @@
 	skcipher_append_src_dst(desc);
 
 	/* Store IV */
-	if (ivsize)
+	if (!is_chacha20 && ivsize)
 		append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT |
 				 LDST_CLASS_1_CCB | (ctx1_iv_off <<
 				 LDST_OFFSET_SHIFT));
@@ -1518,7 +1544,13 @@
  */
 void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata)
 {
-	__be64 sector_size = cpu_to_be64(512);
+	/*
+	 * Set sector size to a big value, practically disabling
+	 * sector size segmentation in xts implementation. We cannot
+	 * take full advantage of this HW feature with existing
+	 * crypto API / dm-crypt SW architecture.
+	 */
+	__be64 sector_size = cpu_to_be64(BIT(15));
 	u32 *key_jump_cmd;
 
 	init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);
@@ -1571,7 +1603,13 @@
  */
 void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata)
 {
-	__be64 sector_size = cpu_to_be64(512);
+	/*
+	 * Set sector size to a big value, practically disabling
+	 * sector size segmentation in xts implementation. We cannot
+	 * take full advantage of this HW feature with existing
+	 * crypto API / dm-crypt SW architecture.
+	 */
+	__be64 sector_size = cpu_to_be64(BIT(15));
 	u32 *key_jump_cmd;
 
 	init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamalg_qi.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamalg_qi.c
@@ -18,6 +18,7 @@
 #include "qi.h"
 #include "jr.h"
 #include "caamalg_desc.h"
+#include <asm/unaligned.h>
 
 /*
  * crypto alg
@@ -67,6 +68,11 @@
 	struct device *qidev;
 	spinlock_t lock;	/* Protects multiple init of driver context */
 	struct caam_drv_ctx *drv_ctx[NUM_OP];
+	struct crypto_skcipher *fallback;
+};
+
+struct caam_skcipher_req_ctx {
+	struct skcipher_request fallback_req;
 };
 
 static int aead_set_sh_desc(struct crypto_aead *aead)
@@ -745,12 +751,17 @@
 	struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
 	struct device *jrdev = ctx->jrdev;
 	int ret = 0;
+	int err;
 
 	if (keylen != 2 * AES_MIN_KEY_SIZE  && keylen != 2 * AES_MAX_KEY_SIZE) {
 		dev_err(jrdev, "key size mismatch\n");
 		goto badkey;
 	}
 
+	err = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+	if (err)
+		return err;
+
 	ctx->cdata.keylen = keylen;
 	ctx->cdata.key_virt = key;
 	ctx->cdata.key_inline = true;
@@ -1395,6 +1406,14 @@
 	return edesc;
 }
 
+static inline bool xts_skcipher_ivsize(struct skcipher_request *req)
+{
+	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+	unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
+
+	return !!get_unaligned((u64 *)(req->iv + (ivsize / 2)));
+}
+
 static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
 {
 	struct skcipher_edesc *edesc;
@@ -1405,6 +1424,21 @@
 	if (!req->cryptlen)
 		return 0;
 
+	if (ctx->fallback && xts_skcipher_ivsize(req)) {
+		struct caam_skcipher_req_ctx *rctx = skcipher_request_ctx(req);
+
+		skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+		skcipher_request_set_callback(&rctx->fallback_req,
+					      req->base.flags,
+					      req->base.complete,
+					      req->base.data);
+		skcipher_request_set_crypt(&rctx->fallback_req, req->src,
+					   req->dst, req->cryptlen, req->iv);
+
+		return encrypt ? crypto_skcipher_encrypt(&rctx->fallback_req) :
+				 crypto_skcipher_decrypt(&rctx->fallback_req);
+	}
+
 	if (unlikely(caam_congested))
 		return -EAGAIN;
 
@@ -1529,6 +1563,7 @@
 			.base = {
 				.cra_name = "xts(aes)",
 				.cra_driver_name = "xts-aes-caam-qi",
+				.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
 				.cra_blocksize = AES_BLOCK_SIZE,
 			},
 			.setkey = xts_skcipher_setkey,
@@ -2462,9 +2497,32 @@
 	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
 	struct caam_skcipher_alg *caam_alg =
 		container_of(alg, typeof(*caam_alg), skcipher);
+	struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+	u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
+	int ret = 0;
+
+	if (alg_aai == OP_ALG_AAI_XTS) {
+		const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
+		struct crypto_skcipher *fallback;
+
+		fallback = crypto_alloc_skcipher(tfm_name, 0,
+						 CRYPTO_ALG_NEED_FALLBACK);
+		if (IS_ERR(fallback)) {
+			dev_err(ctx->jrdev, "Failed to allocate %s fallback: %ld\n",
+				tfm_name, PTR_ERR(fallback));
+			return PTR_ERR(fallback);
+		}
+
+		ctx->fallback = fallback;
+		crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_skcipher_req_ctx) +
+					    crypto_skcipher_reqsize(fallback));
+	}
+
+	ret = caam_init_common(ctx, &caam_alg->caam, false);
+	if (ret && ctx->fallback)
+		crypto_free_skcipher(ctx->fallback);
 
-	return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam,
-				false);
+	return ret;
 }
 
 static int caam_aead_init(struct crypto_aead *tfm)
@@ -2490,7 +2548,11 @@
 
 static void caam_cra_exit(struct crypto_skcipher *tfm)
 {
-	caam_exit_common(crypto_skcipher_ctx(tfm));
+	struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+	if (ctx->fallback)
+		crypto_free_skcipher(ctx->fallback);
+	caam_exit_common(ctx);
 }
 
 static void caam_aead_exit(struct crypto_aead *tfm)
@@ -2524,7 +2586,7 @@
 	alg->base.cra_module = THIS_MODULE;
 	alg->base.cra_priority = CAAM_CRA_PRIORITY;
 	alg->base.cra_ctxsize = sizeof(struct caam_ctx);
-	alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
+	alg->base.cra_flags |= CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
 
 	alg->init = caam_cra_init;
 	alg->exit = caam_cra_exit;
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamalg_qi2.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamalg_qi2.c
@@ -639,7 +639,8 @@
 		return -EINVAL;
 	}
 
-	ctx->cdata.key_virt = key;
+	memcpy(ctx->key, key, keylen);
+	ctx->cdata.key_virt = ctx->key;
 	ctx->cdata.keylen = keylen - saltlen;
 
 	return chachapoly_set_sh_desc(aead);
@@ -2481,7 +2482,7 @@
 				.cra_name = "echainiv(authenc(hmac(sha256),"
 					    "cbc(des)))",
 				.cra_driver_name = "echainiv-authenc-"
-						   "hmac-sha256-cbc-desi-"
+						   "hmac-sha256-cbc-des-"
 						   "caam-qi2",
 				.cra_blocksize = DES_BLOCK_SIZE,
 			},
@@ -2998,15 +2999,13 @@
 	dma_addr_t buf_dma;
 	dma_addr_t ctx_dma;
 	int ctx_dma_len;
-	u8 buf_0[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
-	int buflen_0;
-	u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
-	int buflen_1;
+	u8 buf[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
+	int buflen;
+	int next_buflen;
 	u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned;
 	int (*update)(struct ahash_request *req);
 	int (*final)(struct ahash_request *req);
 	int (*finup)(struct ahash_request *req);
-	int current_buf;
 };
 
 struct caam_export_state {
@@ -3018,42 +3017,17 @@
 	int (*finup)(struct ahash_request *req);
 };
 
-static inline void switch_buf(struct caam_hash_state *state)
-{
-	state->current_buf ^= 1;
-}
-
-static inline u8 *current_buf(struct caam_hash_state *state)
-{
-	return state->current_buf ? state->buf_1 : state->buf_0;
-}
-
-static inline u8 *alt_buf(struct caam_hash_state *state)
-{
-	return state->current_buf ? state->buf_0 : state->buf_1;
-}
-
-static inline int *current_buflen(struct caam_hash_state *state)
-{
-	return state->current_buf ? &state->buflen_1 : &state->buflen_0;
-}
-
-static inline int *alt_buflen(struct caam_hash_state *state)
-{
-	return state->current_buf ? &state->buflen_0 : &state->buflen_1;
-}
-
 /* Map current buffer in state (if length > 0) and put it in link table */
 static inline int buf_map_to_qm_sg(struct device *dev,
 				   struct dpaa2_sg_entry *qm_sg,
 				   struct caam_hash_state *state)
 {
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 
 	if (!buflen)
 		return 0;
 
-	state->buf_dma = dma_map_single(dev, current_buf(state), buflen,
+	state->buf_dma = dma_map_single(dev, state->buf, buflen,
 					DMA_TO_DEVICE);
 	if (dma_mapping_error(dev, state->buf_dma)) {
 		dev_err(dev, "unable to map buf\n");
@@ -3321,7 +3295,7 @@
 				 DMA_TO_DEVICE);
 
 	if (state->buf_dma) {
-		dma_unmap_single(dev, state->buf_dma, *current_buflen(state),
+		dma_unmap_single(dev, state->buf_dma, state->buflen,
 				 DMA_TO_DEVICE);
 		state->buf_dma = 0;
 	}
@@ -3383,9 +3357,17 @@
 		ecode = caam_qi2_strstatus(ctx->dev, status);
 
 	ahash_unmap_ctx(ctx->dev, edesc, req, DMA_BIDIRECTIONAL);
-	switch_buf(state);
 	qi_cache_free(edesc);
 
+	scatterwalk_map_and_copy(state->buf, req->src,
+				 req->nbytes - state->next_buflen,
+				 state->next_buflen, 0);
+	state->buflen = state->next_buflen;
+
+	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, state->buf,
+			     state->buflen, 1);
+
 	print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
 			     DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
 			     ctx->ctx_len, 1);
@@ -3440,9 +3422,17 @@
 		ecode = caam_qi2_strstatus(ctx->dev, status);
 
 	ahash_unmap_ctx(ctx->dev, edesc, req, DMA_FROM_DEVICE);
-	switch_buf(state);
 	qi_cache_free(edesc);
 
+	scatterwalk_map_and_copy(state->buf, req->src,
+				 req->nbytes - state->next_buflen,
+				 state->next_buflen, 0);
+	state->buflen = state->next_buflen;
+
+	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, state->buf,
+			     state->buflen, 1);
+
 	print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
 			     DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
 			     ctx->ctx_len, 1);
@@ -3464,16 +3454,14 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int *buflen = current_buflen(state);
-	u8 *next_buf = alt_buf(state);
-	int *next_buflen = alt_buflen(state), last_buflen;
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int in_len = *buflen + req->nbytes, to_hash;
 	int src_nents, mapped_nents, qm_sg_bytes, qm_sg_src_index;
 	struct ahash_edesc *edesc;
 	int ret = 0;
 
-	last_buflen = *next_buflen;
 	*next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
 	to_hash = in_len - *next_buflen;
 
@@ -3524,10 +3512,6 @@
 		if (mapped_nents) {
 			sg_to_qm_sg_last(req->src, src_len,
 					 sg_table + qm_sg_src_index, 0);
-			if (*next_buflen)
-				scatterwalk_map_and_copy(next_buf, req->src,
-							 to_hash - *buflen,
-							 *next_buflen, 0);
 		} else {
 			dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1,
 					   true);
@@ -3566,14 +3550,11 @@
 		scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
 					 req->nbytes, 0);
 		*buflen = *next_buflen;
-		*next_buflen = last_buflen;
-	}
 
-	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-	print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
-			     1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
 unmap_ctx:
@@ -3592,7 +3573,7 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	int qm_sg_bytes;
 	int digestsize = crypto_ahash_digestsize(ahash);
 	struct ahash_edesc *edesc;
@@ -3663,7 +3644,7 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	int qm_sg_bytes, qm_sg_src_index;
 	int src_nents, mapped_nents;
 	int digestsize = crypto_ahash_digestsize(ahash);
@@ -3852,8 +3833,8 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int buflen = *current_buflen(state);
+	u8 *buf = state->buf;
+	int buflen = state->buflen;
 	int digestsize = crypto_ahash_digestsize(ahash);
 	struct ahash_edesc *edesc;
 	int ret = -ENOMEM;
@@ -3925,10 +3906,9 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int *buflen = current_buflen(state);
-	u8 *next_buf = alt_buf(state);
-	int *next_buflen = alt_buflen(state);
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int in_len = *buflen + req->nbytes, to_hash;
 	int qm_sg_bytes, src_nents, mapped_nents;
 	struct ahash_edesc *edesc;
@@ -3977,11 +3957,6 @@
 
 		sg_to_qm_sg_last(req->src, src_len, sg_table + 1, 0);
 
-		if (*next_buflen)
-			scatterwalk_map_and_copy(next_buf, req->src,
-						 to_hash - *buflen,
-						 *next_buflen, 0);
-
 		edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
 						  qm_sg_bytes, DMA_TO_DEVICE);
 		if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
@@ -4029,14 +4004,11 @@
 		scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
 					 req->nbytes, 0);
 		*buflen = *next_buflen;
-		*next_buflen = 0;
-	}
 
-	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-	print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
-			     1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
 unmap_ctx:
@@ -4055,7 +4027,7 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	int qm_sg_bytes, src_nents, mapped_nents;
 	int digestsize = crypto_ahash_digestsize(ahash);
 	struct ahash_edesc *edesc;
@@ -4151,8 +4123,9 @@
 	struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		      GFP_KERNEL : GFP_ATOMIC;
-	u8 *next_buf = alt_buf(state);
-	int *next_buflen = alt_buflen(state);
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int to_hash;
 	int src_nents, mapped_nents;
 	struct ahash_edesc *edesc;
@@ -4220,10 +4193,6 @@
 			dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src));
 		}
 
-		if (*next_buflen)
-			scatterwalk_map_and_copy(next_buf, req->src, to_hash,
-						 *next_buflen, 0);
-
 		state->ctx_dma_len = ctx->ctx_len;
 		state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx,
 						ctx->ctx_len, DMA_FROM_DEVICE);
@@ -4257,14 +4226,14 @@
 		state->update = ahash_update_no_ctx;
 		state->finup = ahash_finup_no_ctx;
 		state->final = ahash_final_no_ctx;
-		scatterwalk_map_and_copy(next_buf, req->src, 0,
+		scatterwalk_map_and_copy(buf, req->src, 0,
 					 req->nbytes, 0);
-		switch_buf(state);
-	}
+		*buflen = *next_buflen;
 
-	print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
-			     1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
 unmap_ctx:
@@ -4288,10 +4257,9 @@
 
 	state->ctx_dma = 0;
 	state->ctx_dma_len = 0;
-	state->current_buf = 0;
 	state->buf_dma = 0;
-	state->buflen_0 = 0;
-	state->buflen_1 = 0;
+	state->buflen = 0;
+	state->next_buflen = 0;
 
 	return 0;
 }
@@ -4321,16 +4289,8 @@
 {
 	struct caam_hash_state *state = ahash_request_ctx(req);
 	struct caam_export_state *export = out;
-	int len;
-	u8 *buf;
-
-	if (state->current_buf) {
-		buf = state->buf_1;
-		len = state->buflen_1;
-	} else {
-		buf = state->buf_0;
-		len = state->buflen_0;
-	}
+	u8 *buf = state->buf;
+	int len = state->buflen;
 
 	memcpy(export->buf, buf, len);
 	memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx));
@@ -4348,9 +4308,9 @@
 	const struct caam_export_state *export = in;
 
 	memset(state, 0, sizeof(*state));
-	memcpy(state->buf_0, export->buf, export->buflen);
+	memcpy(state->buf, export->buf, export->buflen);
 	memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx));
-	state->buflen_0 = export->buflen;
+	state->buflen = export->buflen;
 	state->update = export->update;
 	state->final = export->final;
 	state->finup = export->finup;
@@ -5421,7 +5381,7 @@
 	dpaa2_fd_set_len(&fd, dpaa2_fl_get_len(&req->fd_flt[1]));
 	dpaa2_fd_set_flc(&fd, req->flc_dma);
 
-	ppriv = this_cpu_ptr(priv->ppriv);
+	ppriv = raw_cpu_ptr(priv->ppriv);
 	for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) {
 		err = dpaa2_io_service_enqueue_fq(ppriv->dpio, ppriv->req_fqid,
 						  &fd);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamhash.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamhash.c
@@ -107,15 +107,13 @@
 	dma_addr_t buf_dma;
 	dma_addr_t ctx_dma;
 	int ctx_dma_len;
-	u8 buf_0[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
-	int buflen_0;
-	u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
-	int buflen_1;
+	u8 buf[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
+	int buflen;
+	int next_buflen;
 	u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned;
 	int (*update)(struct ahash_request *req);
 	int (*final)(struct ahash_request *req);
 	int (*finup)(struct ahash_request *req);
-	int current_buf;
 };
 
 struct caam_export_state {
@@ -127,31 +125,6 @@
 	int (*finup)(struct ahash_request *req);
 };
 
-static inline void switch_buf(struct caam_hash_state *state)
-{
-	state->current_buf ^= 1;
-}
-
-static inline u8 *current_buf(struct caam_hash_state *state)
-{
-	return state->current_buf ? state->buf_1 : state->buf_0;
-}
-
-static inline u8 *alt_buf(struct caam_hash_state *state)
-{
-	return state->current_buf ? state->buf_0 : state->buf_1;
-}
-
-static inline int *current_buflen(struct caam_hash_state *state)
-{
-	return state->current_buf ? &state->buflen_1 : &state->buflen_0;
-}
-
-static inline int *alt_buflen(struct caam_hash_state *state)
-{
-	return state->current_buf ? &state->buflen_0 : &state->buflen_1;
-}
-
 static inline bool is_cmac_aes(u32 algtype)
 {
 	return (algtype & (OP_ALG_ALGSEL_MASK | OP_ALG_AAI_MASK)) ==
@@ -183,12 +156,12 @@
 				     struct sec4_sg_entry *sec4_sg,
 				     struct caam_hash_state *state)
 {
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 
 	if (!buflen)
 		return 0;
 
-	state->buf_dma = dma_map_single(jrdev, current_buf(state), buflen,
+	state->buf_dma = dma_map_single(jrdev, state->buf, buflen,
 					DMA_TO_DEVICE);
 	if (dma_mapping_error(jrdev, state->buf_dma)) {
 		dev_err(jrdev, "unable to map buf\n");
@@ -578,7 +551,7 @@
 				 edesc->sec4_sg_bytes, DMA_TO_DEVICE);
 
 	if (state->buf_dma) {
-		dma_unmap_single(dev, state->buf_dma, *current_buflen(state),
+		dma_unmap_single(dev, state->buf_dma, state->buflen,
 				 DMA_TO_DEVICE);
 		state->buf_dma = 0;
 	}
@@ -643,9 +616,17 @@
 		ecode = caam_jr_strstatus(jrdev, err);
 
 	ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
-	switch_buf(state);
 	kfree(edesc);
 
+	scatterwalk_map_and_copy(state->buf, req->src,
+				 req->nbytes - state->next_buflen,
+				 state->next_buflen, 0);
+	state->buflen = state->next_buflen;
+
+	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, state->buf,
+			     state->buflen, 1);
+
 	print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
 			     DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
 			     ctx->ctx_len, 1);
@@ -703,9 +684,17 @@
 		ecode = caam_jr_strstatus(jrdev, err);
 
 	ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE);
-	switch_buf(state);
 	kfree(edesc);
 
+	scatterwalk_map_and_copy(state->buf, req->src,
+				 req->nbytes - state->next_buflen,
+				 state->next_buflen, 0);
+	state->buflen = state->next_buflen;
+
+	print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, state->buf,
+			     state->buflen, 1);
+
 	print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
 			     DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
 			     ctx->ctx_len, 1);
@@ -786,18 +775,16 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int *buflen = current_buflen(state);
-	u8 *next_buf = alt_buf(state);
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int blocksize = crypto_ahash_blocksize(ahash);
-	int *next_buflen = alt_buflen(state), last_buflen;
 	int in_len = *buflen + req->nbytes, to_hash;
 	u32 *desc;
 	int src_nents, mapped_nents, sec4_sg_bytes, sec4_sg_src_index;
 	struct ahash_edesc *edesc;
 	int ret = 0;
 
-	last_buflen = *next_buflen;
 	*next_buflen = in_len & (blocksize - 1);
 	to_hash = in_len - *next_buflen;
 
@@ -868,10 +855,6 @@
 			sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index -
 					    1);
 
-		if (*next_buflen)
-			scatterwalk_map_and_copy(next_buf, req->src,
-						 to_hash - *buflen,
-						 *next_buflen, 0);
 		desc = edesc->hw_desc;
 
 		edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
@@ -901,14 +884,11 @@
 		scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
 					 req->nbytes, 0);
 		*buflen = *next_buflen;
-		*next_buflen = last_buflen;
-	}
 
-	print_hex_dump_debug("buf@"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-	print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
-			     *next_buflen, 1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
 unmap_ctx:
@@ -925,7 +905,7 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	u32 *desc;
 	int sec4_sg_bytes;
 	int digestsize = crypto_ahash_digestsize(ahash);
@@ -991,7 +971,7 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	u32 *desc;
 	int sec4_sg_src_index;
 	int src_nents, mapped_nents;
@@ -1148,8 +1128,8 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int buflen = *current_buflen(state);
+	u8 *buf = state->buf;
+	int buflen = state->buflen;
 	u32 *desc;
 	int digestsize = crypto_ahash_digestsize(ahash);
 	struct ahash_edesc *edesc;
@@ -1207,11 +1187,10 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	u8 *buf = current_buf(state);
-	int *buflen = current_buflen(state);
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int blocksize = crypto_ahash_blocksize(ahash);
-	u8 *next_buf = alt_buf(state);
-	int *next_buflen = alt_buflen(state);
 	int in_len = *buflen + req->nbytes, to_hash;
 	int sec4_sg_bytes, src_nents, mapped_nents;
 	struct ahash_edesc *edesc;
@@ -1278,12 +1257,6 @@
 
 		sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + 1, 0);
 
-		if (*next_buflen) {
-			scatterwalk_map_and_copy(next_buf, req->src,
-						 to_hash - *buflen,
-						 *next_buflen, 0);
-		}
-
 		desc = edesc->hw_desc;
 
 		edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
@@ -1317,14 +1290,11 @@
 		scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
 					 req->nbytes, 0);
 		*buflen = *next_buflen;
-		*next_buflen = 0;
-	}
 
-	print_hex_dump_debug("buf@"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
-	print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
-			     1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
  unmap_ctx:
@@ -1342,7 +1312,7 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	int buflen = *current_buflen(state);
+	int buflen = state->buflen;
 	u32 *desc;
 	int sec4_sg_bytes, sec4_sg_src_index, src_nents, mapped_nents;
 	int digestsize = crypto_ahash_digestsize(ahash);
@@ -1428,8 +1398,9 @@
 	struct device *jrdev = ctx->jrdev;
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
-	u8 *next_buf = alt_buf(state);
-	int *next_buflen = alt_buflen(state);
+	u8 *buf = state->buf;
+	int *buflen = &state->buflen;
+	int *next_buflen = &state->next_buflen;
 	int to_hash;
 	int blocksize = crypto_ahash_blocksize(ahash);
 	u32 *desc;
@@ -1491,10 +1462,6 @@
 		if (ret)
 			goto unmap_ctx;
 
-		if (*next_buflen)
-			scatterwalk_map_and_copy(next_buf, req->src, to_hash,
-						 *next_buflen, 0);
-
 		desc = edesc->hw_desc;
 
 		ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len);
@@ -1517,14 +1484,14 @@
 		state->update = ahash_update_no_ctx;
 		state->finup = ahash_finup_no_ctx;
 		state->final = ahash_final_no_ctx;
-		scatterwalk_map_and_copy(next_buf, req->src, 0,
+		scatterwalk_map_and_copy(buf, req->src, 0,
 					 req->nbytes, 0);
-		switch_buf(state);
-	}
+		*buflen = *next_buflen;
 
-	print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
-			     DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
-			     1);
+		print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, buf,
+				     *buflen, 1);
+	}
 
 	return ret;
  unmap_ctx:
@@ -1548,10 +1515,9 @@
 
 	state->ctx_dma = 0;
 	state->ctx_dma_len = 0;
-	state->current_buf = 0;
 	state->buf_dma = 0;
-	state->buflen_0 = 0;
-	state->buflen_1 = 0;
+	state->buflen = 0;
+	state->next_buflen = 0;
 
 	return 0;
 }
@@ -1581,16 +1547,8 @@
 {
 	struct caam_hash_state *state = ahash_request_ctx(req);
 	struct caam_export_state *export = out;
-	int len;
-	u8 *buf;
-
-	if (state->current_buf) {
-		buf = state->buf_1;
-		len = state->buflen_1;
-	} else {
-		buf = state->buf_0;
-		len = state->buflen_0;
-	}
+	u8 *buf = state->buf;
+	int len = state->buflen;
 
 	memcpy(export->buf, buf, len);
 	memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx));
@@ -1608,9 +1566,9 @@
 	const struct caam_export_state *export = in;
 
 	memset(state, 0, sizeof(*state));
-	memcpy(state->buf_0, export->buf, export->buflen);
+	memcpy(state->buf, export->buf, export->buflen);
 	memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx));
-	state->buflen_0 = export->buflen;
+	state->buflen = export->buflen;
 	state->update = export->update;
 	state->final = export->final;
 	state->finup = export->finup;
@@ -1991,12 +1949,14 @@
 	 * presence and attributes of MD block.
 	 */
 	if (priv->era < 10) {
-		md_vid = (rd_reg32(&priv->ctrl->perfmon.cha_id_ls) &
+		struct caam_perfmon __iomem *perfmon = &priv->jr[0]->perfmon;
+
+		md_vid = (rd_reg32(&perfmon->cha_id_ls) &
 			  CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
-		md_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
+		md_inst = (rd_reg32(&perfmon->cha_num_ls) &
 			   CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
 	} else {
-		u32 mdha = rd_reg32(&priv->ctrl->vreg.mdha);
+		u32 mdha = rd_reg32(&priv->jr[0]->vreg.mdha);
 
 		md_vid = (mdha & CHA_VER_VID_MASK) >> CHA_VER_VID_SHIFT;
 		md_inst = mdha & CHA_VER_NUM_MASK;
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeyblob.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeyblob.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Black key generation and blob encapsulation/decapsulation for CAAM
+ *
+ * Copyright 2018-2020 NXP
+ */
+#include "caamkeyblob.h"
+#include "error.h"
+
+/* Black key generation and blob encap/decap job completion handler */
+static void caam_key_blob_done(struct device *dev, u32 *desc, u32 err,
+			       void *context)
+{
+	struct jr_job_result *res = context;
+	int ecode = 0;
+
+	dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+
+	if (err)
+		ecode = caam_jr_strstatus(dev, err);
+
+	/* Save the error for post-processing */
+	res->error = ecode;
+	/* Mark job as complete */
+	complete(&res->completion);
+}
+
+/**
+ * map_write_data   - Prepare data to be written to CAAM
+ *
+ * @dev             : struct device of the job ring to be used
+ * @data            : The data to be prepared
+ * @size            : The size of data to be prepared
+ * @dma_addr        : The retrieve DMA address of the input data
+ * @allocated_data  : Pointer to a DMA-able address where the input
+ *                    data is copied and synchronized
+ *
+ * Return           : '0' on success, error code otherwise
+ */
+static int map_write_data(struct device *dev, const u8 *data, size_t size,
+			  dma_addr_t *dma_addr, u8 **allocated_data)
+{
+	int ret = 0;
+
+	/* Allocate memory for data and copy it to DMA zone */
+	*allocated_data = kmemdup(data, size, GFP_KERNEL | GFP_DMA);
+	if (!*allocated_data) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	*dma_addr = dma_map_single(dev, *allocated_data, size, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, *dma_addr)) {
+		dev_err(dev, "Unable to map write data\n");
+		ret = -ENOMEM;
+		goto free_alloc;
+	}
+
+	goto exit;
+
+free_alloc:
+	kfree(*allocated_data);
+
+exit:
+	return ret;
+}
+
+/**
+ * map_read_data   - Prepare data to be read from CAAM
+ *
+ * @dev             : struct device of the job ring to be used
+ * @size            : The size of data to be prepared
+ * @dma_addr        : The retrieve DMA address of the data to be read
+ * @allocated_data  : Pointer to a DMA-able address where the data
+ *                    to be read will be copied and synchronized
+ *
+ * Return           : '0' on success, error code otherwise
+ */
+static int map_read_data(struct device *dev, size_t size, dma_addr_t *dma_addr,
+			 u8 **allocated_data)
+{
+	int ret = 0;
+
+	/* Allocate memory for data compatible with DMA */
+	*allocated_data = kmalloc(size, GFP_KERNEL | GFP_DMA);
+	if (!*allocated_data) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	*dma_addr = dma_map_single(dev, *allocated_data, size, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, *dma_addr)) {
+		dev_err(dev, "Unable to map read data\n");
+		ret = -ENOMEM;
+		goto free_alloc;
+	}
+
+	goto exit;
+
+free_alloc:
+	kfree(*allocated_data);
+
+exit:
+	return ret;
+}
+
+/**
+ * read_map_data   - Read the data from CAAM
+ *
+ * @dev             : struct device of the job ring to be used
+ * @data            : The read data from CAAM will be copied here
+ * @dma_addr        : The DMA address of the data to be read
+ * @allocated_data  : Pointer to a DMA-able address where the data
+ *                    to be read is
+ * @size            : The size of data to be read
+ */
+static void read_map_data(struct device *dev, u8 *data, dma_addr_t dma_addr,
+			  u8 *allocated_data, size_t size)
+{
+	/* Synchronize the DMA and copy the data */
+	dma_sync_single_for_cpu(dev, dma_addr, size, DMA_FROM_DEVICE);
+	memcpy(data, allocated_data, size);
+}
+
+/**
+ * unmap_read_write_data - Unmap the data needed for or from CAAM
+ *
+ * @dev             : struct device of the job ring to be used
+ * @dma_addr        : The DMA address of the data used for DMA transfer
+ * @allocated_data  : The data used for DMA transfer
+ * @size            : The size of data
+ * @dir             : The DMA_API direction
+ */
+static void unmap_read_write_data(struct device *dev, dma_addr_t dma_addr,
+				  u8 *allocated_data, size_t size,
+				  enum dma_data_direction dir)
+{
+	/* Free the resources and clear the data*/
+	dma_unmap_single(dev, dma_addr, size, dir);
+	kzfree(allocated_data);
+}
+
+/**
+ * get_caam_dma_addr - Get the CAAM DMA address of a physical address.
+ *
+ * @phy_address     : The physical address
+ *
+ * Return           : The CAAM DMA address
+ */
+static dma_addr_t get_caam_dma_addr(const void *phy_address)
+{
+	uintptr_t ptr_conv;
+	dma_addr_t caam_dma_address = 0;
+
+	/* Check if conversion is possible */
+	if (sizeof(caam_dma_address) < sizeof(phy_address)) {
+		/*
+		 * Check that all bits sets in the phy_address
+		 * can be stored in caam_dma_address
+		 */
+
+		/* Generate a mask of the representable bits */
+		u64 mask = GENMASK_ULL(sizeof(caam_dma_address) * 8 - 1, 0);
+
+		/*
+		 * Check that the bits not representable of
+		 * the physical address are not set
+		 */
+		if ((uintptr_t)phy_address & ~mask)
+			goto exit;
+	}
+
+	/* Convert address to caam_dma_address */
+	ptr_conv = (uintptr_t)phy_address;
+	caam_dma_address = (dma_addr_t)ptr_conv;
+
+exit:
+	return caam_dma_address;
+}
+
+/**
+ * generate_black_key - Generate a black key from a plaintext or random,
+ *                      based on the given input: a size for a random black
+ *                      key, or a plaintext (input key).
+ *
+ * If the memory type is Secure Memory, the key to cover is read
+ * directly by CAAM from Secure Memory without intermediate copy.
+ * The value of the input key (plaintext) must be a physical address
+ * in Secure Memory.
+ *
+ * Notes:
+ * Limited to Class 1 keys, at the present time.
+ * The input and output data are copied to temporary arrays
+ * except for the input key if the memory type is Secure Memory.
+ * For now, we have support for Black keys, stored in General Memory.
+ *
+ * @dev             : struct device of the job ring to be used
+ * @info            : keyblob_info structure, will be updated with
+ *                    the black key data from CAAM.
+ *                    This contains, also, all the data necessary to generate
+ *                    a black key from plaintext/random like: key encryption
+ *                    key, memory type, input key, etc.
+ *
+ * Return           : '0' on success, error code otherwise
+ */
+int generate_black_key(struct device *dev, struct keyblob_info *info)
+{
+	int ret = 0;
+	bool not_random = false;
+	u8 trusted_key, key_enc;
+	u32 *desc = NULL;
+	size_t black_key_length_req = 0;
+	dma_addr_t black_key_dma;
+	u8 *tmp_black_key = NULL;
+
+	/* Validate device */
+	if (!dev)
+		return -EINVAL;
+
+	/*
+	 * If an input key (plaintext) is given,
+	 * generate a black key from it, not from random
+	 */
+	if (info->key)
+		not_random = true;
+
+	/* Get trusted key and key encryption type from type */
+	trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+	key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+
+	dev_dbg(dev, "%s input: [key: (%zu) black_key: %p(%zu), key_enc: %x]\n",
+		__func__, info->key_len, info->black_key, info->black_key_len,
+		key_enc);
+	if (not_random)
+		print_hex_dump_debug("input key @" __stringify(__LINE__) ": ",
+				     DUMP_PREFIX_ADDRESS, 16, 4, info->key,
+				     info->key_len, 1);
+
+	/* Validate key type - only JDKEK keys are supported */
+	if (!is_key_type(info->type) || is_trusted_type(info->type))
+		return -EINVAL;
+
+	/*
+	 * Validate key size, expected values are
+	 * between 16 and 64 bytes.
+	 * See TODO from cnstr_desc_black_key().
+	 */
+	if (info->key_len < MIN_KEY_SIZE || info->key_len > MAX_KEY_SIZE)
+		return -EINVAL;
+
+	/*
+	 * Based on key encryption type (ecb or ccm),
+	 * compute the black key size
+	 */
+	if (key_enc == KEY_COVER_ECB)
+		/*
+		 * ECB-Black Key will be padded with zeros to make it a
+		 * multiple of 16 bytes long before it is encrypted,
+		 * and the resulting Black Key will be this length.
+		 */
+		black_key_length_req = ECB_BLACK_KEY_SIZE(info->key_len);
+	else if (key_enc == KEY_COVER_CCM)
+		/*
+		 * CCM-Black Key will always be at least 12 bytes longer,
+		 * since the encapsulation uses a 6-byte nonce and adds
+		 * a 6-byte ICV. But first, the key is padded as necessary so
+		 * that CCM-Black Key is a multiple of 8 bytes long.
+		 */
+		black_key_length_req = CCM_BLACK_KEY_SIZE(info->key_len);
+
+	/* Check if there is enough space for black key */
+	if (info->black_key_len < black_key_length_req) {
+		info->black_key_len = black_key_length_req;
+		return -EINVAL;
+	}
+
+	/* Black key will have at least the same length as the input key */
+	info->black_key_len = info->key_len;
+
+	dev_dbg(dev, "%s processing: [key: (%zu) black_key: %p(%zu)",
+		__func__, info->key_len, info->black_key, info->black_key_len);
+	dev_dbg(dev, "req:%zu, key_enc: 0x%x]\n", black_key_length_req, key_enc);
+
+	/* Map black key, this will be read from CAAM */
+	if (map_read_data(dev, black_key_length_req,
+			  &black_key_dma, &tmp_black_key)) {
+		dev_err(dev, "Unable to map black key\n");
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	/* Construct descriptor for black key */
+	if (not_random)
+		ret = cnstr_desc_black_key(&desc, info->key, info->key_len,
+					   black_key_dma, info->black_key_len,
+					   key_enc, trusted_key);
+	else
+		ret = cnstr_desc_random_black_key(&desc, info->key_len,
+						  black_key_dma,
+						  info->black_key_len,
+						  key_enc, trusted_key);
+
+	if (ret) {
+		dev_err(dev,
+			"Failed to construct the descriptor for black key\n");
+		goto unmap_black_key;
+	}
+
+	/* Execute descriptor and wait for its completion */
+	ret = caam_jr_run_and_wait_for_completion(dev, desc,
+						  caam_key_blob_done);
+	if (ret) {
+		dev_err(dev, "Failed to execute black key descriptor\n");
+		goto free_desc;
+	}
+
+	/* Read black key from CAAM */
+	read_map_data(dev, info->black_key, black_key_dma,
+		      tmp_black_key, black_key_length_req);
+
+	/* Update black key length with the correct size */
+	info->black_key_len = black_key_length_req;
+
+free_desc:
+	kfree(desc);
+
+unmap_black_key:
+	unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+			      black_key_length_req, DMA_FROM_DEVICE);
+
+exit:
+	return ret;
+}
+EXPORT_SYMBOL(generate_black_key);
+
+/**
+ * caam_blob_encap - Encapsulate a black key into a blob
+ *
+ * If the memory type is Secure Memory, the key to encapsulate is read
+ * directly by CAAM from Secure Memory without intermediate copy.
+ * The value of the key (black key) must be a physical address
+ * in Secure Memory.
+ *
+ * Notes:
+ * For now, we have support for Black keys, stored in General Memory and
+ * encapsulated into black blobs.
+ *
+ * @dev             : struct device of the job ring to be used
+ * @info            : keyblob_info structure, will be updated with
+ *                    the blob data from CAAM.
+ *                    This contains, also, all the data necessary to
+ *                    encapsulate a black key into a blob: key encryption
+ *                    key, memory type, color, etc.
+ *
+ * Return           : '0' on success, error code otherwise
+ */
+int caam_blob_encap(struct device *dev, struct keyblob_info *info)
+{
+	int ret = 0;
+	u32 *desc = NULL;
+	size_t black_key_real_len = 0;
+	size_t blob_req_len = 0;
+	u8 mem_type, color, key_enc, trusted_key;
+	dma_addr_t black_key_dma, blob_dma;
+	unsigned char *blob = info->blob;
+	u8 *tmp_black_key = NULL, *tmp_blob = NULL;
+
+	/* Validate device */
+	if (!dev)
+		return -EINVAL;
+
+	/*
+	 * Get memory type, trusted key, key encryption
+	 * type and color from type
+	 */
+	mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
+	color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
+	key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+	trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+
+	/* Validate input data*/
+	if (!info->key_mod || !blob)
+		return -EINVAL;
+
+	/* Validate object type - only JDKEK keys are supported */
+	if (is_trusted_type(info->type))
+		return -EINVAL;
+
+	dev_dbg(dev, "%s input:[black_key: %p (%zu) color: %x, key_enc: %x",
+		__func__, info->black_key, info->black_key_len, color, key_enc);
+	dev_dbg(dev, ", key_mod: %p (%zu)", info->key_mod, info->key_mod_len);
+	dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
+
+	/*
+	 * Based on memory type, the key modifier length
+	 * can be 8-byte or 16-byte.
+	 */
+	if (mem_type == DATA_SECMEM)
+		info->key_mod_len = KEYMOD_SIZE_SM;
+	else
+		info->key_mod_len = KEYMOD_SIZE_GM;
+
+	/* Adapt the size of the black key */
+	black_key_real_len = info->black_key_len;
+
+	blob_req_len = CCM_BLACK_KEY_SIZE(info->key_len);
+
+	/* Check if the blob can be stored */
+	if (info->blob_len < (blob_req_len + BLOB_OVERHEAD))
+		return -EINVAL;
+
+	/* Update the blob length */
+	info->blob_len = blob_req_len + BLOB_OVERHEAD;
+
+	dev_dbg(dev, "%s processing: [black_key: %p (%zu) cnstr: %zu",
+		__func__, info->black_key, info->black_key_len,
+		black_key_real_len);
+	dev_dbg(dev, " color: %x key_enc: %x, mem_type: %x,",
+		color, key_enc, mem_type);
+	dev_dbg(dev, ", key_mod: %p (%zu) ", info->key_mod, info->key_mod_len);
+	dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
+
+	/* Map black key, this will be transferred to CAAM */
+	if (mem_type == DATA_GENMEM) {
+		if (map_write_data(dev, info->black_key, info->black_key_len,
+				   &black_key_dma, &tmp_black_key)) {
+			dev_err(dev, "Unable to map black key for blob\n");
+			ret = -ENOMEM;
+			goto exit;
+		}
+	} else {
+		black_key_dma = get_caam_dma_addr(info->black_key);
+		if (!black_key_dma)
+			return -ENOMEM;
+	}
+
+	/* Map blob, this will be read to CAAM */
+	if (mem_type == DATA_GENMEM) {
+		if (map_read_data(dev, info->blob_len, &blob_dma, &tmp_blob)) {
+			dev_err(dev, "Unable to map blob\n");
+			ret = -ENOMEM;
+			goto unmap_black_key;
+		}
+	} else {
+		blob_dma = get_caam_dma_addr(info->blob);
+		if (!blob_dma)
+			return -ENOMEM;
+	}
+
+	/* Construct descriptor for blob encapsulation */
+	ret = cnstr_desc_blob_encap(&desc, black_key_dma, info->key_len,
+				    color, key_enc, trusted_key, mem_type,
+				    info->key_mod, info->key_mod_len,
+				    blob_dma, info->blob_len);
+	if (ret) {
+		dev_err(dev,
+			"Failed to construct the descriptor for blob encap\n");
+		goto unmap_blob;
+	}
+
+	/* Execute descriptor and wait for its completion */
+	ret = caam_jr_run_and_wait_for_completion(dev, desc,
+						  caam_key_blob_done);
+	if (ret) {
+		dev_err(dev, "Failed to execute blob encap descriptor\n");
+		goto free_desc;
+	}
+
+	/* Read blob from CAAM */
+	if (mem_type == DATA_GENMEM)
+		read_map_data(dev, blob, blob_dma, tmp_blob, info->blob_len);
+
+	print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, blob,
+			     info->blob_len, 1);
+free_desc:
+	kfree(desc);
+
+unmap_blob:
+	if (mem_type == DATA_GENMEM)
+		unmap_read_write_data(dev, blob_dma, tmp_blob,
+				      info->blob_len, DMA_FROM_DEVICE);
+
+unmap_black_key:
+	if (mem_type == DATA_GENMEM)
+		unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+				      info->black_key_len, DMA_TO_DEVICE);
+
+exit:
+	return ret;
+}
+EXPORT_SYMBOL(caam_blob_encap);
+
+/**
+ * caam_blob_decap - Decapsulate a black key from a blob
+ *
+ * Notes:
+ * For now, we have support for Black blob, stored in General Memory and
+ * can be decapsulated into a black key.
+ *
+ * @dev             : struct device of the job ring to be used
+ * @info            : keyblob_info structure, will be updated with
+ *                    the black key decapsulated from the blob.
+ *                    This contains, also, all the data necessary to
+ *                    encapsulate a black key into a blob: key encryption
+ *                    key, memory type, color, etc.
+ *
+ * Return           : '0' on success, error code otherwise
+ */
+int caam_blob_decap(struct device *dev, struct keyblob_info *info)
+{
+	int ret = 0;
+	u32 *desc = NULL;
+	u8 mem_type, color, key_enc, trusted_key;
+	size_t black_key_real_len;
+	dma_addr_t black_key_dma, blob_dma;
+	unsigned char *blob = info->blob + TAG_OVERHEAD_SIZE;
+	u8 *tmp_black_key = NULL, *tmp_blob = NULL;
+
+	/* Validate device */
+	if (!dev)
+		return -EINVAL;
+
+	/*
+	 * Get memory type, trusted key, key encryption
+	 * type and color from type
+	 */
+	mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
+	color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
+	key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+	trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+
+	/* Validate input data*/
+	if (!info->key_mod || !blob)
+		return -EINVAL;
+
+	dev_dbg(dev, "%s input: [blob: %p (%zu), mem_type: %x, color: %x",
+		__func__, blob, info->blob_len, mem_type, color);
+	dev_dbg(dev, " keymod: %p (%zu)", info->key_mod, info->key_mod_len);
+	dev_dbg(dev, " secret: %p (%zu) key_enc: %x]\n",
+		info->black_key, info->black_key_len, key_enc);
+
+	/* Validate object type - only JDKEK keys are supported */
+	if (is_trusted_type(info->type))
+		return -EINVAL;
+
+	print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, blob,
+			     info->blob_len, 1);
+
+	/*
+	 * Based on memory type, the key modifier length
+	 * can be 8-byte or 16-byte.
+	 */
+	if (mem_type == DATA_SECMEM)
+		info->key_mod_len = KEYMOD_SIZE_SM;
+	else
+		info->key_mod_len = KEYMOD_SIZE_GM;
+
+	/* Check if the blob is valid */
+	if (info->blob_len <= BLOB_OVERHEAD)
+		return -EINVAL;
+
+	/* Initialize black key length */
+	black_key_real_len = info->blob_len - BLOB_OVERHEAD;
+
+	/* Check if the black key has enough space to be stored */
+	if (info->black_key_len < black_key_real_len)
+		return -EINVAL;
+
+	/*
+	 * Based on key encryption type (ecb or ccm),
+	 * compute the black key size
+	 */
+	if (key_enc == KEY_COVER_ECB)
+		/*
+		 * ECB-Black Key will be padded with zeros to make it a
+		 * multiple of 16 bytes long before it is encrypted,
+		 * and the resulting Black Key will be this length.
+		 */
+		black_key_real_len = ECB_BLACK_KEY_SIZE(info->key_len);
+	else if (key_enc == KEY_COVER_CCM)
+		/*
+		 * CCM-Black Key will always be at least 12 bytes longer,
+		 * since the encapsulation uses a 6-byte nonce and adds
+		 * a 6-byte ICV. But first, the key is padded as necessary so
+		 * that CCM-Black Key is a multiple of 8 bytes long.
+		 */
+		black_key_real_len = CCM_BLACK_KEY_SIZE(info->key_len);
+
+	/* Check if there is enough space for black key */
+	if (info->black_key_len < black_key_real_len)
+		return -EINVAL;
+
+	/* Update black key length with the one computed based on key_enc */
+	info->black_key_len = black_key_real_len;
+
+	dev_dbg(dev, "%s processing: [blob: %p (%zu), mem_type: %x, color: %x,",
+		__func__, blob, info->blob_len, mem_type, color);
+	dev_dbg(dev, " key_mod: %p (%zu), black_key: %p (%zu) real_len: %zu]\n",
+		info->key_mod, info->key_mod_len, info->black_key,
+		info->black_key_len, black_key_real_len);
+
+	/* Map blob, this will be transferred to CAAM */
+	if (mem_type == DATA_GENMEM) {
+		if (map_write_data(dev, blob, info->blob_len,
+				   &blob_dma, &tmp_blob)) {
+			dev_err(dev, "Unable to map blob for decap\n");
+			ret = -ENOMEM;
+			goto exit;
+		}
+	} else {
+		blob_dma = get_caam_dma_addr(blob);
+		if (!blob_dma)
+			return -ENOMEM;
+	}
+
+	/* Map black key, this will be read from CAAM */
+	if (mem_type == DATA_GENMEM) {
+		if (map_read_data(dev, info->black_key_len,
+				  &black_key_dma, &tmp_black_key)) {
+			dev_err(dev, "Unable to map black key for blob decap\n");
+			ret = -ENOMEM;
+			goto unmap_blob;
+		}
+	} else {
+		black_key_dma = get_caam_dma_addr(info->black_key);
+		if (!black_key_dma)
+			return -ENOMEM;
+	}
+
+	ret = cnstr_desc_blob_decap(&desc, blob_dma, info->blob_len,
+				    info->key_mod, info->key_mod_len,
+				    black_key_dma, info->key_len,
+				    color, key_enc, trusted_key, mem_type);
+	if (ret) {
+		dev_err(dev,
+			"Failed to construct the descriptor for blob decap\n");
+		goto unmap_black_key;
+	}
+
+	ret = caam_jr_run_and_wait_for_completion(dev, desc,
+						  caam_key_blob_done);
+	if (ret) {
+		dev_err(dev, "Failed to execute blob decap descriptor\n");
+		goto free_desc;
+	}
+
+	/* Read black key from CAAM */
+	if (mem_type == DATA_GENMEM)
+		read_map_data(dev, info->black_key, black_key_dma,
+			      tmp_black_key, info->black_key_len);
+
+free_desc:
+	kfree(desc);
+
+unmap_black_key:
+	if (mem_type == DATA_GENMEM)
+		unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+				      info->black_key_len, DMA_FROM_DEVICE);
+
+unmap_blob:
+	if (mem_type == DATA_GENMEM)
+		unmap_read_write_data(dev, blob_dma, tmp_blob,
+				      info->blob_len, DMA_TO_DEVICE);
+
+exit:
+	return ret;
+}
+EXPORT_SYMBOL(caam_blob_decap);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeyblob.h
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeyblob.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Black key generation and blob encapsulation/decapsualtion for CAAM
+ *
+ * Copyright 2018-2020 NXP
+ */
+
+#ifndef _CAAMKEYBLOB_H_
+#define _CAAMKEYBLOB_H_
+
+#include <linux/device.h>
+#include "caamkeyblob_desc.h"
+
+/*
+ * Minimum key size to be used is 16 bytes and maximum key size fixed
+ * is 64 bytes.
+ * Blob size to be kept is Maximum key size + tag object header added by CAAM.
+ */
+
+#define MIN_KEY_SIZE			16
+#define MAX_KEY_SIZE			64
+
+#define MAX_BLACK_KEY_SIZE		(MAX_KEY_SIZE + CCM_OVERHEAD +\
+					TAG_OVERHEAD_SIZE)
+
+/*
+ * For blobs a randomly-generated, 256-bit blob key is used to
+ * encrypt the data using the AES-CCM cryptographic algorithm.
+ * Therefore, blob size is max key size, CCM_OVERHEAD, blob header
+ * added by CAAM and the tagged object header size.
+ */
+#define MAX_BLOB_SIZE			(MAX_KEY_SIZE + CCM_OVERHEAD +\
+					BLOB_OVERHEAD + TAG_OVERHEAD_SIZE)
+
+/* Key modifier for CAAM blobs, used as a revision number */
+static const char caam_key_modifier[KEYMOD_SIZE_GM] = {
+		'C', 'A', 'A', 'M', '_', 'K', 'E', 'Y',
+		'_', 'T', 'Y', 'P', 'E', '_', 'V', '1',
+};
+
+/**
+ * struct keyblob_info - Structure that contains all the data necessary
+ *                       to generate a black key and encapsulate it into a blob
+ *
+ * @key                : The plaintext used as input key
+ *                       for black key generation
+ * @key_len            : Size of plaintext or size of key in case of
+ *                       black key generated from random
+ * @type               : The type of data contained (e.g. black key, blob, etc.)
+ * @black_key_len      : Length of the generated black key
+ * @black_key          : Black key data obtained from CAAM
+ * @blob_len           : Length of the blob that encapsulates the black key
+ * @blob               : Blob data obtained from CAAM
+ * @key_modifier_len   : 8-byte or 16-byte Key_Modifier based on general or
+ *                       secure memory blob type
+ * @key_modifier       : can be either a secret value, or used as a revision
+ *                       number, revision date or nonce
+ *                       In this case is used as a revision number.
+ */
+struct keyblob_info {
+	char *key;
+	size_t key_len;
+
+	u32 type;
+
+	size_t black_key_len;
+	unsigned char black_key[MAX_BLACK_KEY_SIZE];
+
+	size_t blob_len;
+	unsigned char blob[MAX_BLOB_SIZE];
+
+	size_t key_mod_len;
+	const void *key_mod;
+};
+
+int generate_black_key(struct device *dev, struct keyblob_info *info);
+
+int caam_blob_encap(struct device *dev, struct keyblob_info *info);
+
+int caam_blob_decap(struct device *dev, struct keyblob_info *info);
+
+#endif /* _CAAMKEYBLOB_H_ */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeyblob_desc.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeyblob_desc.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Shared descriptors for CAAM black key
+ * and blob encapsulation/decapsulation
+ *
+ * Copyright 2018-2020 NXP
+ */
+#include "caamkeyblob_desc.h"
+
+/* Size of tmp buffer for descriptor const. */
+#define INITIAL_DESCSZ 64
+
+/*
+ * Construct a black key conversion job descriptor
+ *
+ * This function constructs a job descriptor capable of performing
+ * a key blackening operation on a plaintext secure memory resident object.
+ *
+ * @desc          : Pointer to a pointer to the descriptor generated by this
+ *                  function. Caller will be responsible to kfree() this
+ *                  descriptor after execution.
+ * @key           : Pointer to the plaintext, which will also hold
+ *                  the result. Since encryption occurs in place, caller must
+ *                  ensure that the space is large enough to accommodate the
+ *                  blackened key
+ * @key_len       : Size of the plaintext
+ * @black_key     : DMA address of the black key obtained from hardware
+ * @black_key_len : Size of the black key
+ * @key_enc       : Encrypted Key Type (AES-ECB or AES-CCM)
+ * @trusted_key   : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
+ *                  or Trusted Descriptor Key Encryption Key (TDKEK) to
+ *                  decrypt the key to be loaded into a Key Register).
+ *
+ * Return         : '0' on success, error code otherwise
+ */
+int cnstr_desc_black_key(u32 **desc, char *key, size_t key_len,
+			 dma_addr_t black_key, size_t black_key_len,
+			 u8 key_enc, u8 trusted_key)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize;
+	u32 bk_store;
+	u32 key_length_for_desc = key_len;
+
+	/* Trusted key not supported */
+	if (trusted_key != UNTRUSTED_KEY)
+		return -ENOTSUPP;
+
+	memset(tmpdesc, 0, sizeof(tmpdesc));
+
+	init_job_desc(tmpdesc, 0);
+
+	/*
+	 * KEY commands seems limited to 32 bytes, so we should use the load
+	 * command instead which can load up to 64 bytes.
+	 * The size must also be loaded.
+	 *
+	 * TODO: The KEY command indicate it should be able to load key bigger
+	 * than 32bytes but it doesn't work in practice
+	 *
+	 * TODO: The LOAD command indicate it should be able to load up to 96
+	 * byte keys it doesn't work in practice and is limited to 64 bytes
+	 */
+
+	/* Load key to class 1 key register */
+	append_load_as_imm(tmpdesc, (void *)key, key_length_for_desc,
+			   LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_KEY);
+
+	/* Load the size of the key */
+	append_load_imm_u32(tmpdesc, key_length_for_desc, LDST_CLASS_1_CCB |
+			    LDST_IMM | LDST_SRCDST_WORD_KEYSZ_REG);
+
+	/* ...and write back out via FIFO store*/
+	bk_store = CLASS_1;
+	if (key_enc == KEY_COVER_ECB)
+		bk_store |= FIFOST_TYPE_KEY_KEK;
+	else
+		bk_store |= FIFOST_TYPE_KEY_CCM_JKEK;
+
+	/* Save the key as black key in memory */
+	append_fifo_store(tmpdesc, black_key, black_key_len, bk_store);
+
+	dsize = desc_bytes(&tmpdesc);
+
+	/* Now allocate execution buffer and coat it with executable */
+	tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
+	if (!tdesc)
+		return -ENOMEM;
+
+	*desc = tdesc;
+
+	print_hex_dump_debug("black key desc@" __stringify(__LINE__) ":",
+			     DUMP_PREFIX_ADDRESS, 16, 4, *desc,
+			     desc_bytes(*desc), 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnstr_desc_black_key);
+
+/*
+ * Construct a black key using RNG job descriptor
+ *
+ * This function constructs a job descriptor capable of performing
+ * a key blackening operation on RNG generated.
+ *
+ * @desc          : Pointer to a pointer to the descriptor generated by this
+ *                  function. Caller will be responsible to kfree() this
+ *                  descriptor after execution.
+ * @key_len       : Size of the random plaintext
+ * @black_key     : DMA address of the black key obtained from hardware
+ * @black_key_len : Size of the black key
+ * @key_enc       : Encrypted Key Type (AES-ECB or AES-CCM)
+ * @trusted_key   : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
+ *                  or Trusted Descriptor Key Encryption Key (TDKEK) to
+ *                  decrypt the key to be loaded into a Key Register).
+ *
+ * Return         : '0' on success, error code otherwise
+ */
+int cnstr_desc_random_black_key(u32 **desc, size_t key_len,
+				dma_addr_t black_key, size_t black_key_len,
+				u8 key_enc, u8 trusted_key)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize;
+	u32 bk_store;
+
+	memset(tmpdesc, 0, sizeof(tmpdesc));
+
+	init_job_desc(tmpdesc, 0);
+
+	/* Prepare RNG */
+	append_operation(tmpdesc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
+
+	/* Generate RNG and left it in output data fifo */
+	append_cmd(tmpdesc, CMD_FIFO_STORE | FIFOST_TYPE_RNGFIFO | key_len);
+
+	/* Copy RNG from outfifo to class 1 Key register */
+	append_move(tmpdesc, MOVE_SRC_OUTFIFO | MOVE_DEST_CLASS1KEY |
+			MOVE_WAITCOMP | (key_len & MOVE_LEN_MASK));
+
+	/* Write the size of the key moved */
+	append_load_imm_u32(tmpdesc, key_len, LDST_CLASS_1_CCB |
+			    LDST_SRCDST_WORD_KEYSZ_REG | LDST_IMM);
+
+	bk_store = CLASS_1;
+	if (key_enc == KEY_COVER_ECB)
+		bk_store |= FIFOST_TYPE_KEY_KEK;
+	else
+		bk_store |= FIFOST_TYPE_KEY_CCM_JKEK;
+
+	/* Fifo store to save the key as black key in memory */
+	append_fifo_store(tmpdesc, black_key, black_key_len, bk_store);
+
+	dsize = desc_bytes(&tmpdesc);
+
+	/* Now allocate execution buffer and coat it with executable */
+	tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
+	if (!tdesc)
+		return -ENOMEM;
+
+	*desc = tdesc;
+
+	print_hex_dump_debug("black key random desc@" __stringify(__LINE__) ":",
+			     DUMP_PREFIX_ADDRESS, 16, 4, *desc,
+			     desc_bytes(*desc), 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnstr_desc_random_black_key);
+
+/*
+ * Construct a blob encapsulation job descriptor
+ *
+ * This function dynamically constructs a blob encapsulation job descriptor
+ * from the following arguments:
+ *
+ * @desc          : Pointer to a pointer to the descriptor generated by this
+ *                  function. Caller will be responsible to kfree() this
+ *                  descriptor after execution.
+ * @black_key     : Physical pointer to a secret, normally a black or red key,
+ *                  possibly residing within an accessible secure memory page,
+ *                  of the secret to be encapsulated to an output blob.
+ * @black_key_len : Size of input secret, in bytes. This is limited to 65536
+ *                  less the size of blob overhead, since the length embeds
+ *                  into DECO pointer in/out instructions.
+ * @keycolor      : Determines if the source data is covered (black key) or
+ *                  plaintext (red key). RED_KEY or BLACK_KEY are defined in
+ *                  for this purpose.
+ * @key_enc       : If BLACK_KEY source is covered via AES-CCM, specify
+ *                  KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
+ * @trusted_key   : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
+ *                  or Trusted Descriptor Key Encryption Key (TDKEK) to
+ *                  decrypt the key to be loaded into a Key Register).
+ * @mem_type      : Determine if encapsulated blob should be a secure memory
+ *                  blob (DATA_SECMEM), with partition data embedded with key
+ *                  material, or a general memory blob (DATA_GENMEM).
+ * @key_mod       : Pointer to a key modifier, which must reside in a
+ *                  contiguous piece of memory. Modifier will be assumed to be
+ *                  8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
+ *                  long for a blob of type DATA_GENMEM
+ * @key_mod_len   : Modifier length is 8 bytes long for a blob of type
+ *                  DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
+ * @blob          : Physical pointer to the destination buffer to receive the
+ *                  encapsulated output. This buffer will need to be 48 bytes
+ *                  larger than the input because of the added encapsulation
+ *                  data. The generated descriptor will account for the
+ *                  increase in size, but the caller must also account for
+ *                  this increase in the buffer allocator.
+ * @blob_len      : Size of the destination buffer to receive the
+ *                  encapsulated output.
+ * Return         : '0' on success, error code otherwise
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job
+ * descriptor which encapsulates data into an externally-storable blob
+ * suitable for use across power cycles.
+ *
+ * This is an example of a black key encapsulation job into a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
+ * the output 48 bytes longer than the input:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400010           ld: ccb2-key len=16 offs=0
+ * [02] 08144891               ptr->@0x08144891
+ * [03] F800003A    seqoutptr: len=58
+ * [04] 01000000               out_ptr->@0x01000000
+ * [05] F000000A     seqinptr: len=10
+ * [06] 09745090               in_ptr->@0x09745090
+ * [07] 870D0004    operation: encap blob  reg=memory, black, format=normal
+ *
+ * This is an example of a red key encapsulation job for storing a red key
+ * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction; this accounts for blob permission storage:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400C08           ld: ccb2-key len=8 offs=12
+ * [02] 087D0784               ptr->@0x087d0784
+ * [03] F8000050    seqoutptr: len=80
+ * [04] 09251BB2               out_ptr->@0x09251bb2
+ * [05] F0000020     seqinptr: len=32
+ * [06] 40000F31               in_ptr->@0x40000f31
+ * [07] 870D0008    operation: encap blob  reg=memory, red, sec_mem,
+ *                             format=normal
+ */
+int cnstr_desc_blob_encap(u32 **desc, dma_addr_t black_key,
+			  size_t key_len, u8 keycolor, u8 key_enc,
+			  u8 trusted_key, u8 mem_type, const void *key_mod,
+			  size_t key_mod_len, dma_addr_t blob, size_t blob_len)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize;
+	u32 bk_store;
+
+	/* Trusted key not supported */
+	if (trusted_key != UNTRUSTED_KEY)
+		return -ENOTSUPP;
+
+	memset(tmpdesc, 0, sizeof(tmpdesc));
+
+	init_job_desc(tmpdesc, 0);
+
+	/*
+	 * Key modifier works differently for secure/general memory blobs
+	 * This accounts for the permission/protection data encapsulated
+	 * within the blob if a secure memory blob is requested
+	 */
+	if (mem_type == DATA_SECMEM)
+		append_load_as_imm(tmpdesc, key_mod, key_mod_len,
+				   LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
+				   ((12 << LDST_OFFSET_SHIFT) &
+				    LDST_OFFSET_MASK));
+	else /* is general memory blob */
+		append_load_as_imm(tmpdesc, key_mod, key_mod_len,
+				   LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY);
+
+	/* Input data, should be somewhere in secure memory */
+	append_seq_in_ptr_intlen(tmpdesc, black_key, key_len, 0);
+
+	/*
+	 * Encapsulation output must include space for blob key encryption
+	 * key and MAC tag
+	 */
+	append_seq_out_ptr_intlen(tmpdesc, blob, CCM_BLACK_KEY_SIZE(key_len) +
+				  BLOB_OVERHEAD, 0);
+
+	bk_store = OP_PCLID_BLOB;
+	if (mem_type == DATA_SECMEM)
+		bk_store |= OP_PCL_BLOB_PTXT_SECMEM;
+
+	if (key_enc == KEY_COVER_CCM)
+		bk_store |= OP_PCL_BLOB_EKT;
+
+	/* An input black key cannot be stored in a red blob */
+	if (keycolor == BLACK_KEY)
+		bk_store |= OP_PCL_BLOB_BLACK;
+
+	/* Set blob encap, then color */
+	append_operation(tmpdesc, OP_TYPE_ENCAP_PROTOCOL | bk_store);
+
+	dsize = desc_bytes(&tmpdesc);
+
+	tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
+	if (!tdesc)
+		return -ENOMEM;
+
+	*desc = tdesc;
+
+	print_hex_dump_debug("blob encap desc@" __stringify(__LINE__) ":",
+			     DUMP_PREFIX_ADDRESS, 16, 4, *desc,
+			     desc_bytes(*desc), 1);
+	return 0;
+}
+EXPORT_SYMBOL(cnstr_desc_blob_encap);
+
+/*
+ * Construct a blob decapsulation job descriptor
+ *
+ * This function dynamically constructs a blob decapsulation job descriptor
+ * from the following arguments:
+ *
+ * @desc          : Pointer to a pointer to the descriptor generated by this
+ *                  function. Caller will be responsible to kfree() this
+ *                  descriptor after execution.
+ * @blob          : Physical pointer (into external memory) of the blob to
+ *                  be decapsulated. Blob must reside in a contiguous memory
+ *                  segment.
+ * @blob_len      : Size of the blob buffer to be decapsulated.
+ * @key_mod       : Pointer to a key modifier, which must reside in a
+ *                  contiguous piece of memory. Modifier will be assumed to be
+ *                  8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
+ *                  long for a blob of type DATA_GENMEM
+ * @key_mod_len   : Modifier length is 8 bytes long for a blob of type
+ *                  DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
+ * @black_key     : Physical pointer of the decapsulated output, possibly into
+ *                  a location within a secure memory page. Must be contiguous.
+ * @black_key_len : Size of encapsulated secret in bytes (not the size of the
+ *                  input blob).
+ * @keycolor      : Determines if the source data is covered (black key) or
+ *                  plaintext (red key). RED_KEY or BLACK_KEY are defined in
+ *                  for this purpose.
+ * @key_enc       : If BLACK_KEY source is covered via AES-CCM, specify
+ *                  KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
+ * @trusted_key   : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
+ *                  or Trusted Descriptor Key Encryption Key (TDKEK) to
+ *                  decrypt the key to be loaded into a Key Register).
+ * @mem_type      : Determine if encapsulated blob should be a secure memory
+ *                  blob (DATA_SECMEM), with partition data embedded with key
+ *                  material, or a general memory blob (DATA_GENMEM).
+ * Return         : '0' on success, error code otherwise
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job descriptor
+ * that decapsulates a key blob from external memory into a black (encrypted)
+ * key or red (plaintext) content.
+ *
+ * This is an example of a black key decapsulation job from a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction.
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400010           ld: ccb2-key len=16 offs=0
+ * [02] 08A63B7F               ptr->@0x08a63b7f
+ * [03] F8000010    seqoutptr: len=16
+ * [04] 01000000               out_ptr->@0x01000000
+ * [05] F000003A     seqinptr: len=58
+ * [06] 01000010               in_ptr->@0x01000010
+ * [07] 860D0004    operation: decap blob  reg=memory, black, format=normal
+ *
+ * This is an example of a red key decapsulation job for restoring a red key
+ * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400C08           ld: ccb2-key len=8 offs=12
+ * [02] 01000000               ptr->@0x01000000
+ * [03] F8000020    seqoutptr: len=32
+ * [04] 400000E6               out_ptr->@0x400000e6
+ * [05] F0000050     seqinptr: len=80
+ * [06] 08F0C0EA               in_ptr->@0x08f0c0ea
+ * [07] 860D0008    operation: decap blob  reg=memory, red, sec_mem,
+ *			       format=normal
+ */
+int cnstr_desc_blob_decap(u32 **desc, dma_addr_t blob, size_t blob_len,
+			  const void *key_mod, size_t key_mod_len,
+			  dma_addr_t black_key, size_t plaintext_len,
+			  u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize;
+	u32 bk_store;
+
+	/* Trusted key not supported */
+	if (trusted_key != UNTRUSTED_KEY)
+		return -ENOTSUPP;
+
+	memset(tmpdesc, 0, sizeof(tmpdesc));
+
+	init_job_desc(tmpdesc, 0);
+
+	/* Load key modifier */
+	if (mem_type == DATA_SECMEM)
+		append_load_as_imm(tmpdesc, key_mod, key_mod_len,
+				   LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
+				   ((12 << LDST_OFFSET_SHIFT) &
+				    LDST_OFFSET_MASK));
+	else /* is general memory blob */
+		append_load_as_imm(tmpdesc, key_mod, key_mod_len,
+				   LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY);
+
+	/* Compensate blob header + MAC tag over size of encapsulated secret */
+	append_seq_in_ptr_intlen(tmpdesc, blob, plaintext_len + BLOB_OVERHEAD,
+				 0);
+
+	append_seq_out_ptr_intlen(tmpdesc, black_key, plaintext_len, 0);
+
+	/* Decapsulate from secure memory partition to black blob */
+	bk_store = OP_PCLID_BLOB;
+	if (mem_type == DATA_SECMEM)
+		bk_store |= OP_PCL_BLOB_PTXT_SECMEM;
+
+	if (key_enc == KEY_COVER_CCM)
+		bk_store |= OP_PCL_BLOB_EKT;
+
+	/* An input black key cannot be stored in a red blob */
+	if (keycolor == BLACK_KEY)
+		bk_store |= OP_PCL_BLOB_BLACK;
+
+	/* Set blob encap, then color */
+	append_operation(tmpdesc, OP_TYPE_DECAP_PROTOCOL | bk_store);
+
+	dsize = desc_bytes(&tmpdesc);
+
+	tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
+	if (!tdesc)
+		return -ENOMEM;
+
+	*desc = tdesc;
+
+	print_hex_dump_debug("blob decap desc@" __stringify(__LINE__) ":",
+			     DUMP_PREFIX_ADDRESS, 16, 4, *desc,
+			     desc_bytes(*desc), 1);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnstr_desc_blob_decap);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("NXP CAAM Black Key and Blob descriptors");
+MODULE_AUTHOR("NXP Semiconductors");
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeyblob_desc.h
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeyblob_desc.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Shared descriptors for CAAM black key and blob
+ *
+ * Copyright 2018-2020 NXP
+ */
+
+#ifndef _CAAMKEYBLOB_DESC_H_
+#define _CAAMKEYBLOB_DESC_H_
+
+#include <linux/types.h>
+
+#include "jr.h"
+#include "regs.h"
+#include "desc.h"
+
+#include "compat.h"
+#include "tag_object.h"
+#include "desc_constr.h"
+
+/* Defines for secure memory and general memory blobs */
+#define DATA_GENMEM 0
+#define DATA_SECMEM 1
+
+/* Encrypted key */
+#define BLACK_KEY 1
+
+/* Define key encryption/covering options */
+#define KEY_COVER_ECB 0	/* cover key in AES-ECB */
+#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
+
+/* Define the trust in the key, to select either JDKEK or TDKEK */
+#define UNTRUSTED_KEY 0
+#define TRUSTED_KEY 1
+
+/* Define space required for BKEK + MAC tag storage in any blob */
+#define BLOB_OVERHEAD (32 + 16)
+
+#define PAD_16_BYTE(_key_size) (roundup(_key_size, 16))
+#define PAD_8_BYTE(_key_size) (roundup(_key_size, 8))
+
+/*
+ * ECB-Black Key will be padded with zeros to make it a
+ * multiple of 16 bytes long before it is encrypted,
+ * and the resulting Black Key will be this length.
+ */
+#define ECB_BLACK_KEY_SIZE(_key_size) (PAD_16_BYTE(_key_size))
+
+/*
+ * CCM-Black Key will always be at least 12 bytes longer,
+ * since the encapsulation uses a 6-byte nonce and adds
+ * a 6-byte ICV. But first, the key is padded as necessary so
+ * that CCM-Black Key is a multiple of 8 bytes long.
+ */
+#define NONCE_SIZE 6
+#define ICV_SIZE 6
+#define CCM_OVERHEAD (NONCE_SIZE + ICV_SIZE)
+#define CCM_BLACK_KEY_SIZE(_key_size) (PAD_8_BYTE(_key_size) \
+							+ CCM_OVERHEAD)
+
+static inline int secret_size_in_ccm_black_key(int key_size)
+{
+	return ((key_size >= CCM_OVERHEAD) ? key_size - CCM_OVERHEAD : 0);
+}
+
+#define SECRET_SIZE_IN_CCM_BLACK_KEY(_key_size) \
+	secret_size_in_ccm_black_key(_key_size)
+
+/* A red key is not encrypted so its size is the same */
+#define RED_KEY_SIZE(_key_size) (_key_size)
+
+/*
+ * Based on memory type, the key modifier length
+ * can be either 8-byte or 16-byte.
+ */
+#define KEYMOD_SIZE_SM 8
+#define KEYMOD_SIZE_GM 16
+
+/* Create job descriptor to cover key */
+int cnstr_desc_black_key(u32 **desc, char *key, size_t key_len,
+			 dma_addr_t black_key, size_t black_key_len,
+			 u8 key_enc, u8 trusted_key);
+
+/* Create job descriptor to generate a random key and cover it */
+int cnstr_desc_random_black_key(u32 **desc, size_t key_len,
+				dma_addr_t black_key, size_t black_key_len,
+				u8 key_enc, u8 trusted_key);
+
+/* Encapsulate data in a blob */
+int cnstr_desc_blob_encap(u32 **desc, dma_addr_t black_key,
+			  size_t black_key_len, u8 color, u8 key_enc,
+			  u8 trusted_key, u8 mem_type, const void *key_mod,
+			  size_t key_mod_len, dma_addr_t blob, size_t blob_len);
+
+/* Decapsulate data from a blob */
+int cnstr_desc_blob_decap(u32 **desc, dma_addr_t blob, size_t blob_len,
+			  const void *key_mod, size_t key_mod_len,
+			  dma_addr_t black_key, size_t black_key_len,
+			  u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type);
+
+#endif /* _CAAMKEYBLOB_DESC_H_ */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeyblob_test.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeyblob_test.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * Test of black key generation from a plaintext (of different size)
+ * and from random.
+ * The random black key is encapsulated into a blob.
+ * Next, the blob is decapsulated and the new obtained black key is
+ * compared to the random black key.
+ */
+#include <linux/module.h>
+#include "caamkeyblob.h"
+
+#define MAX_INPUT_SIZE 64
+#define KEY_ENCRYPTION_ECB 1
+#define KEY_ENCRYPTION_CCM 9
+
+static char input[MAX_INPUT_SIZE];
+
+static int create_black_key(struct device *dev, struct keyblob_info *info)
+{
+	int ret;
+
+	ret = generate_black_key(dev, info);
+	if (ret)
+		dev_err(dev, "black key of size: %zd, type: %d returned %d",
+			info->key_len, info->type, ret);
+
+	return (ret) ? 1 : 0;
+}
+
+static int black_key_test(void)
+{
+	struct device *dev;
+	struct keyblob_info *info;
+	int i, ret = 0, nb_errors = 0;
+	unsigned char tmp_black_key[MAX_BLACK_KEY_SIZE];
+	size_t tmp_black_key_len = 0;
+
+	dev = caam_jr_alloc();
+	if (!dev)
+		return -ENOMEM;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->key = input;
+
+	for (i = 1; i <= MAX_INPUT_SIZE; i++) {
+		info->key_len = i;
+
+		/* Create a black key encrypted with AES-ECB */
+		info->type = KEY_ENCRYPTION_ECB;
+		info->black_key_len = MAX_INPUT_SIZE;
+		nb_errors += create_black_key(dev, info);
+
+		/* Create a black key encrypted with AES-CCM */
+		info->type = KEY_ENCRYPTION_CCM;
+		info->black_key_len = MAX_INPUT_SIZE + CCM_OVERHEAD;
+		nb_errors += create_black_key(dev, info);
+	}
+
+	/* Create, from random, a black key encrypted with AES-ECB */
+	info->key = NULL;
+	info->type = KEY_ENCRYPTION_ECB;
+	info->black_key_len = MAX_INPUT_SIZE;
+	ret = create_black_key(dev, info);
+	nb_errors += (ret) ? 1 : 0;
+
+	/* Save it for later to compare it */
+	tmp_black_key_len = info->black_key_len;
+	memcpy(tmp_black_key, info->black_key, tmp_black_key_len);
+
+	/* Encapsulate the random black key into a black blob */
+	info->key = NULL;
+	/* Set key modifier, used as revision number, for blob */
+	info->key_mod = caam_key_modifier;
+	info->key_mod_len = ARRAY_SIZE(caam_key_modifier);
+	/* Black key, encrypted with ECB-AES, in General Memory */
+	info->type = KEY_ENCRYPTION_ECB;
+	info->key_len = MAX_INPUT_SIZE;
+	info->blob_len = MAX_BLOB_SIZE;
+	ret = caam_blob_encap(dev, info);
+	nb_errors += (ret) ? 1 : 0;
+
+	/* Decapsulate the black key from the above black blob */
+	ret = caam_blob_decap(dev, info);
+	nb_errors += (ret) ? 1 : 0;
+
+	/*
+	 * Compare the generated black key with
+	 * the one decapsulated from the blob
+	 */
+	if (info->black_key_len == tmp_black_key_len)
+		ret = memcmp(tmp_black_key, info->black_key, tmp_black_key_len);
+	else
+		ret = 1;
+	nb_errors += ret;
+
+	/*
+	 * Check number of errors.
+	 * If nb_errors > 0, at least one operation failed, success otherwise
+	 */
+	pr_info("Nb errors: %d\n", nb_errors);
+
+	caam_jr_free(dev);
+	kfree(info);
+
+	return nb_errors;
+}
+
+static int black_key_test_init(void)
+{
+	return black_key_test();
+}
+
+static void black_key_test_exit(void)
+{
+}
+
+module_init(black_key_test_init);
+module_exit(black_key_test_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("NXP CAAM Black Key and Blob Test");
+MODULE_AUTHOR("NXP Semiconductors");
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamkeygen.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamkeygen.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/ioctl.h>
+
+#include "caamkeyblob.h"
+#include "intern.h"
+#include <linux/caam_keygen.h>
+
+#define DEVICE_NAME "caam-keygen"
+
+static long caam_keygen_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg);
+
+/**
+ * tag_black_obj      - Tag a black object (key/blob) with a tag object header.
+ *
+ * @info              : keyblob_info structure, which contains
+ *                      the black key/blob, obtained from CAAM,
+ *                      that needs to be tagged
+ * @black_max_len     : The maximum size of the black object (blob/key)
+ * @blob              : Used to determine if it's a blob or key object
+ *
+ * Return             : '0' on success, error code otherwise
+ */
+static int tag_black_obj(struct keyblob_info *info, size_t black_max_len,
+			 bool blob)
+{
+	struct header_conf tag;
+	u32 type;
+	int ret;
+	u32 size_tagged = black_max_len;
+
+	if (!info)
+		return -EINVAL;
+
+	type = info->type;
+
+	/* Prepare and set the tag */
+	if (blob) {
+		init_tag_object_header(&tag, 0, type, info->key_len,
+				       info->blob_len);
+		ret = set_tag_object_header_conf(&tag, info->blob,
+						 info->blob_len,
+						 &size_tagged);
+	} else {
+		init_tag_object_header(&tag, 0, type, info->key_len,
+				       info->black_key_len);
+		ret = set_tag_object_header_conf(&tag, info->black_key,
+						 info->black_key_len,
+						 &size_tagged);
+	}
+	if (ret)
+		return ret;
+
+	/* Update the size of the black key tagged */
+	if (blob)
+		info->blob_len = size_tagged;
+	else
+		info->black_key_len = size_tagged;
+
+	return ret;
+}
+/**
+ * send_err_msg      - Send the error message from kernel to user-space
+ *
+ * @msg              : The message to be sent
+ * @output           : The output buffer where we want to copy the error msg
+ * @size             : The size of output buffer
+ */
+static void send_err_msg(char *msg, void __user *output, size_t size)
+{
+	size_t min_s;
+	char null_ch = 0;
+
+	/* Not enough space to copy any message */
+	if (size <= 1)
+		return;
+
+	min_s = min(size - 1, strlen(msg));
+	/*
+	 * Avoid compile and checkpatch warnings, since we don't
+	 * care about return value from copy_to_user
+	 */
+	(void)(copy_to_user(output, msg, min_s) + 1);
+	/* Copy null terminator */
+	(void)(copy_to_user((output + min_s), &null_ch, 1) + 1);
+}
+
+/**
+ * validate_key_size - Validate the key size from user.
+ *                     This can be the exact size given by user when
+ *                     generating a black key from random (with -s),
+ *                     or the size of the plaintext (with -t).
+ *
+ * @key_len          : The size of key we want to validate
+ * @output           : The output buffer where we want to copy the error msg
+ * @size             : The size of output buffer
+ *
+ *Return             : '0' on success, error code otherwise
+ */
+static int validate_key_size(size_t key_len, void __user *output, size_t size)
+{
+	char *msg = NULL;
+
+	if (key_len < MIN_KEY_SIZE || key_len > MAX_KEY_SIZE) {
+		msg = "Invalid key size, expected values are between 16 and 64 bytes.\n";
+		send_err_msg(msg, output, size);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * validate_input    - Validate the input from user and set the
+ *                     keyblob_info structure.
+ *                     This contains the input key in case of black key
+ *                     generated from plaintext or size for random
+ *                     black key.
+ *
+ * @key_crt          : Structure with data from user
+ * @arg              : User-space argument from ioctl call
+ * @info             : keyblob_info structure, will be updated with all the
+ *                     data from user-space
+ * @create_key_op    : Used to determine if it's a create or import operation
+ *
+ * Return            : '0' on success, error code otherwise
+ */
+static int validate_input(struct caam_keygen_cmd *key_crt, unsigned long arg,
+			  struct keyblob_info *info, bool create_key_op)
+{
+	char *tmp, *msg;
+	size_t tmp_size;
+	bool random = false;
+	int ret = 0;
+	u32 tmp_len = 0;
+	char null_ch = 0;
+
+	/*
+	 * So far, we only support Black keys, encrypted with JDKEK,
+	 * kept in general memory, non-secure state.
+	 * Therefore, default value for type is 1.
+	 */
+	u32 type = 1;
+
+	if (copy_from_user(key_crt, (void __user *)arg,
+			   sizeof(struct caam_keygen_cmd)))
+		return -EFAULT;
+
+	/* Get blob_len from user. */
+	info->blob_len = key_crt->blob_len;
+	/* Get black_key_len from user. */
+	info->black_key_len = key_crt->black_key_len;
+
+	/*
+	 * Based on operation type validate a different set of input data.
+	 *
+	 * For key creation, validate the Encrypted Key Type,
+	 * the Key Mode and Key Value
+	 */
+	if (create_key_op) {
+		/*
+		 * Validate arguments received from user.
+		 * These must be at least 1 since
+		 * they have null terminator.
+		 */
+		if (key_crt->key_enc_len < 1 || key_crt->key_mode_len < 1 ||
+		    key_crt->key_value_len < 1) {
+			msg = "Invalid arguments.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			return -EFAULT;
+		}
+		/*
+		 * Allocate memory for temporary buffer used to
+		 * get the user arguments from user-space
+		 */
+		tmp_size = max_t(size_t, key_crt->key_enc_len,
+				 max_t(size_t, key_crt->key_mode_len,
+				       key_crt->key_value_len)) + 1;
+		tmp = kmalloc(tmp_size, GFP_KERNEL);
+		if (!tmp) {
+			msg = "Unable to allocate memory for temporary buffer.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			return -ENOMEM;
+		}
+		/* Add null terminator */
+		tmp[tmp_size - 1] = null_ch;
+		/*
+		 * Validate and set, in type, the Encrypted Key Type
+		 * given from user-space.
+		 * This must be ecb or ccm.
+		 */
+		if (copy_from_user(tmp, u64_to_user_ptr(key_crt->key_enc),
+				   key_crt->key_enc_len)) {
+			msg = "Unable to copy from user the Encrypted Key Type.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			ret = -EFAULT;
+			goto free_resource;
+		}
+		if (!strcmp(tmp, "ccm")) {
+			type |= BIT(TAG_OBJ_EKT_OFFSET);
+		} else if (strcmp(tmp, "ecb")) {
+			msg = "Invalid argument for Encrypted Key Type, expected ecb or ccm.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			ret = -EINVAL;
+			goto free_resource;
+		}
+		/*
+		 * Validate the Key Mode given from user-space.
+		 * This must be -t (text), for a black key generated
+		 * from a plaintext, or -s (size) for a black key
+		 * generated from random.
+		 */
+		if (copy_from_user(tmp, u64_to_user_ptr(key_crt->key_mode),
+				   key_crt->key_mode_len)) {
+			msg = "Unable to copy from user the Key Mode: random (-s) or plaintext (-t).\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			ret = -EFAULT;
+			goto free_resource;
+		}
+		if (!strcmp(tmp, "-s")) {
+			random = true; /* black key generated from random */
+		} else if (strcmp(tmp, "-t")) {
+			msg = "Invalid argument for Key Mode, expected -s or -t.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			ret = -EINVAL;
+			goto free_resource;
+		}
+		/*
+		 * Validate and set, into keyblob_info structure,
+		 * the plaintext or key size, based on Key Mode.
+		 */
+		if (copy_from_user(tmp, u64_to_user_ptr(key_crt->key_value),
+				   key_crt->key_value_len)) {
+			msg = "Unable to copy from user the Key Value: size or plaintext.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			ret = -EFAULT;
+			goto free_resource;
+		}
+		/* Black key generated from random, get its size */
+		if (random) {
+			info->key = NULL;
+			ret = kstrtou32(tmp, 10, &tmp_len);
+			if (ret != 0) {
+				msg = "Invalid key size.\n";
+				send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+					     key_crt->blob_len);
+				goto free_resource;
+			}
+			ret = validate_key_size(tmp_len,
+						u64_to_user_ptr(key_crt->blob),
+						key_crt->blob_len);
+			if (ret)
+				goto free_resource;
+
+			info->key_len = tmp_len;
+		} else {
+			/*
+			 * Black key generated from plaintext,
+			 * get the plaintext (input key) and its size
+			 */
+			ret = validate_key_size(strlen(tmp),
+						u64_to_user_ptr(key_crt->blob),
+						key_crt->blob_len);
+			if (ret)
+				goto free_resource;
+
+			info->key = tmp;
+			info->key_len = strlen(tmp);
+		}
+		info->type = type;
+	} else {
+		/* For key import, get the blob from user-space */
+		if (copy_from_user(info->blob, u64_to_user_ptr(key_crt->blob),
+				   info->blob_len)) {
+			msg = "Unable to copy from user the blob.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->black_key),
+				     key_crt->black_key_len);
+			return -EFAULT;
+		}
+	}
+
+	goto exit;
+
+free_resource:
+	kfree(tmp);
+
+exit:
+	return ret;
+}
+
+/**
+ * keygen_create_keyblob - Generate key and blob
+ *
+ * @info             : keyblob_info structure, will be updated with
+ *                     the black key and blob data from CAAM
+ *
+ * Return            : '0' on success, error code otherwise
+ */
+static int keygen_create_keyblob(struct keyblob_info *info)
+{
+	int ret = 0;
+	struct device *jrdev;
+
+	/* Allocate caam job ring for operation to be performed from CAAM */
+	jrdev = caam_jr_alloc();
+	if (IS_ERR(jrdev)) {
+		pr_err("Job Ring Device allocation failed\n");
+		return PTR_ERR(jrdev);
+	}
+
+	/* Create a black key */
+	ret = generate_black_key(jrdev, info);
+	if (ret) {
+		dev_err(jrdev, "Black key generation failed: (%d)\n", ret);
+		goto free_jr;
+	}
+
+	/* Clear the input key, if exists */
+	if (info->key)
+		memset(info->key, 0, info->key_len);
+
+	/* Set key modifier, used as revision number, for blob */
+	info->key_mod = caam_key_modifier;
+	info->key_mod_len = ARRAY_SIZE(caam_key_modifier);
+
+	/*
+	 * Encapsulate the key, into a black blob, in general memory
+	 * (the only memory type supported, right now)
+	 */
+	ret = caam_blob_encap(jrdev, info);
+	if (ret) {
+		dev_err(jrdev, "Blob encapsulation of black key failed: %d\n",
+			ret);
+		goto free_jr;
+	}
+
+	/* Tag the black key so it can be passed to CAAM Crypto API */
+	ret = tag_black_obj(info, sizeof(info->black_key), false);
+	if (ret) {
+		dev_err(jrdev, "Black key tagging failed: %d\n", ret);
+		goto free_jr;
+	}
+
+	/* Tag the black blob so it can be passed to CAAM Crypto API */
+	ret = tag_black_obj(info, sizeof(info->blob), true);
+	if (ret) {
+		dev_err(jrdev, "Black blob tagging failed: %d\n", ret);
+		goto free_jr;
+	}
+
+free_jr:
+	caam_jr_free(jrdev);
+
+	return ret;
+}
+
+/**
+ * keygen_import_key - Import a black key from a blob
+ *
+ * @info             : keyblob_info structure, will be updated with
+ *                     the black key obtained after blob decapsulation by CAAM
+ *
+ * Return            : '0' on success, error code otherwise
+ */
+static int keygen_import_key(struct keyblob_info *info)
+{
+	int ret = 0;
+	struct device *jrdev;
+	struct header_conf *header;
+	struct tagged_object *tag_obj;
+
+	/* Allocate CAAM Job Ring for operation to be performed from CAAM */
+	jrdev = caam_jr_alloc();
+	if (IS_ERR(jrdev)) {
+		pr_err("Job Ring Device allocation failed\n");
+		return PTR_ERR(jrdev);
+	}
+
+	/* Set key modifier, used as revision number, for blob */
+	info->key_mod = caam_key_modifier;
+	info->key_mod_len = ARRAY_SIZE(caam_key_modifier);
+
+	print_hex_dump_debug("input blob @ " __stringify(__LINE__) " : ",
+			     DUMP_PREFIX_ADDRESS, 16, 4, info->blob,
+			     info->blob_len, 1);
+
+	/* Check if one can retrieve the tag object header configuration */
+	if (info->blob_len <= TAG_OVERHEAD_SIZE) {
+		dev_err(jrdev, "Invalid blob length\n");
+		ret = -EINVAL;
+		goto free_jr;
+	}
+
+	/* Retrieve the tag object */
+	tag_obj = (struct tagged_object *)info->blob;
+
+	/*
+	 * Check tag object header configuration
+	 * and retrieve the tag object header configuration
+	 */
+	if (is_valid_header_conf(&tag_obj->header)) {
+		header = &tag_obj->header;
+	} else {
+		dev_err(jrdev,
+			"Unable to get tag object header configuration for blob\n");
+		ret = -EINVAL;
+		goto free_jr;
+	}
+
+	info->key_len = header->red_key_len;
+
+	/* Validate the red key size extracted from blob */
+	if (info->key_len < MIN_KEY_SIZE || info->key_len > MAX_KEY_SIZE) {
+		dev_err(jrdev,
+			"Invalid red key length extracted from blob, expected values are between 16 and 64 bytes\n");
+		ret = -EINVAL;
+		goto free_jr;
+	}
+
+	info->type = header->type;
+
+	/* Update blob length by removing the header size */
+	info->blob_len -= TAG_OVERHEAD_SIZE;
+
+	/*
+	 * Check the received, from user, blob length
+	 * with the one from tag header
+	 */
+	if (info->blob_len != header->obj_len) {
+		dev_err(jrdev, "Mismatch between received blob length and the one from tag header\n");
+		ret = -EINVAL;
+		goto free_jr;
+	}
+
+	/*
+	 * Decapsulate the blob into a black key,
+	 * in general memory (the only memory type supported, right now)
+	 */
+	ret = caam_blob_decap(jrdev, info);
+	if (ret) {
+		dev_err(jrdev, "Blob decapsulation failed: %d\n", ret);
+		goto free_jr;
+	}
+
+	/* Tag the black key so it can be passed to CAAM Crypto API */
+	ret = tag_black_obj(info, sizeof(info->black_key), false);
+	if (ret)
+		dev_err(jrdev, "Black key tagging failed: %d\n", ret);
+
+free_jr:
+	caam_jr_free(jrdev);
+
+	return ret;
+}
+
+/**
+ * send_output       - Send the output data (tagged key and blob)
+ *                     from kernel to user-space.
+ *
+ * @key_crt          : Structure used to transfer data
+ *                     from user-space to kernel
+ * @info             : keyblob_info structure, which contains all
+ *                     the data obtained from CAAM that needs to
+ *                     be transferred to user-space
+ * @create_key_op    : Used to determine if it's a create or import operation
+ * @err              : Error code received from previous operations
+ *
+ * Return            : '0' on success, error code otherwise
+ */
+static int send_output(struct caam_keygen_cmd *key_crt, unsigned long arg,
+		       struct keyblob_info *info, bool create_key_op, int err)
+{
+	int ret = 0;
+	char *msg;
+
+	/* Free resource used on validate_input */
+	kfree(info->key);
+
+	if (err)
+		return err;
+
+	/* Check if there's enough space to copy black key to user */
+	if (key_crt->black_key_len < info->black_key_len) {
+		msg = "Not enough space for black key.\n";
+		send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+			     key_crt->blob_len);
+		/* Send, to user, the necessary size for key */
+		key_crt->black_key_len = info->black_key_len;
+
+		ret = -EINVAL;
+		goto exit;
+	}
+	key_crt->black_key_len = info->black_key_len;
+
+	/* For key import, copy to user only the black key */
+	if (copy_to_user(u64_to_user_ptr(key_crt->black_key),
+			 info->black_key, info->black_key_len))
+		return -EFAULT;
+
+	/* For key creation, copy to user, also, the blob */
+	if (create_key_op) {
+		/* Check if there's enough space to copy blob user */
+		if (key_crt->blob_len < info->blob_len) {
+			msg = "Not enough space for blob key.\n";
+			send_err_msg(msg, u64_to_user_ptr(key_crt->blob),
+				     key_crt->blob_len);
+			/* Send, to user, the necessary size for blob */
+			key_crt->blob_len = info->blob_len;
+
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		key_crt->blob_len = info->blob_len;
+
+		if (copy_to_user(u64_to_user_ptr(key_crt->blob), info->blob,
+				 info->blob_len))
+			return -EFAULT;
+	}
+
+exit:
+	if (copy_to_user((void __user *)arg, key_crt,
+			 sizeof(struct caam_keygen_cmd)))
+		return -EFAULT;
+
+	return ret;
+}
+
+static long caam_keygen_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	int ret = 0;
+	struct keyblob_info info = {.key = NULL};
+	struct caam_keygen_cmd key_crt;
+	/* Used to determine if it's a create or import operation */
+	bool create_key_op = false;
+
+	switch (cmd) {
+	case CAAM_KEYGEN_IOCTL_CREATE:
+	{
+		create_key_op = true;
+
+		/* Validate user-space input */
+		ret = validate_input(&key_crt, arg, &info, create_key_op);
+		if (ret)
+			break;
+
+		/* Create tagged key and blob */
+		ret = keygen_create_keyblob(&info);
+
+		/* Send data from kernel to user-space */
+		ret = send_output(&key_crt, arg, &info, create_key_op, ret);
+
+		break;
+	}
+	case CAAM_KEYGEN_IOCTL_IMPORT:
+	{
+		/* Validate user-space input */
+		ret = validate_input(&key_crt, arg, &info, create_key_op);
+		if (ret)
+			break;
+
+		/* Import tagged key from blob */
+		ret = keygen_import_key(&info);
+
+		/* Send data from kernel to user-space */
+		ret = send_output(&key_crt, arg, &info, create_key_op, ret);
+
+		break;
+	}
+	default:
+		ret = -ENOTTY;
+	}
+
+	return ret;
+}
+
+static const struct file_operations fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = caam_keygen_ioctl,
+	.compat_ioctl = compat_ptr_ioctl,
+};
+
+static struct miscdevice caam_keygen_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = DEVICE_NAME,
+	.fops = &fops
+};
+
+int caam_keygen_init(void)
+{
+	int ret;
+
+	ret = misc_register(&caam_keygen_dev);
+	if (ret) {
+		pr_err("Failed to register device %s\n",
+		       caam_keygen_dev.name);
+		return ret;
+	}
+
+	pr_info("Device %s registered\n", caam_keygen_dev.name);
+
+	return 0;
+}
+
+void caam_keygen_exit(void)
+{
+	misc_deregister(&caam_keygen_dev);
+
+	pr_info("caam_keygen unregistered\n");
+}
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caampkc.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caampkc.c
@@ -225,7 +225,9 @@
 		if (len && *buff)
 			break;
 
-		sg_miter_next(&miter);
+		if (!sg_miter_next(&miter))
+			break;
+
 		buff = miter.addr;
 		len = miter.length;
 
@@ -252,9 +254,9 @@
 	gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
 		       GFP_KERNEL : GFP_ATOMIC;
 	int sg_flags = (flags == GFP_ATOMIC) ? SG_MITER_ATOMIC : 0;
-	int sgc;
 	int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
 	int src_nents, dst_nents;
+	int mapped_src_nents, mapped_dst_nents;
 	unsigned int diff_size = 0;
 	int lzeros;
 
@@ -285,13 +287,27 @@
 				     req_ctx->fixup_src_len);
 	dst_nents = sg_nents_for_len(req->dst, req->dst_len);
 
-	if (!diff_size && src_nents == 1)
+	mapped_src_nents = dma_map_sg(dev, req_ctx->fixup_src, src_nents,
+				      DMA_TO_DEVICE);
+	if (unlikely(!mapped_src_nents)) {
+		dev_err(dev, "unable to map source\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
+				      DMA_FROM_DEVICE);
+	if (unlikely(!mapped_dst_nents)) {
+		dev_err(dev, "unable to map destination\n");
+		goto src_fail;
+	}
+
+	if (!diff_size && mapped_src_nents == 1)
 		sec4_sg_len = 0; /* no need for an input hw s/g table */
 	else
-		sec4_sg_len = src_nents + !!diff_size;
+		sec4_sg_len = mapped_src_nents + !!diff_size;
 	sec4_sg_index = sec4_sg_len;
-	if (dst_nents > 1)
-		sec4_sg_len += pad_sg_nents(dst_nents);
+
+	if (mapped_dst_nents > 1)
+		sec4_sg_len += pad_sg_nents(mapped_dst_nents);
 	else
 		sec4_sg_len = pad_sg_nents(sec4_sg_len);
 
@@ -301,19 +317,7 @@
 	edesc = kzalloc(sizeof(*edesc) + desclen + sec4_sg_bytes,
 			GFP_DMA | flags);
 	if (!edesc)
-		return ERR_PTR(-ENOMEM);
-
-	sgc = dma_map_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
-	if (unlikely(!sgc)) {
-		dev_err(dev, "unable to map source\n");
-		goto src_fail;
-	}
-
-	sgc = dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
-	if (unlikely(!sgc)) {
-		dev_err(dev, "unable to map destination\n");
 		goto dst_fail;
-	}
 
 	edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen;
 	if (diff_size)
@@ -324,7 +328,7 @@
 		sg_to_sec4_sg_last(req_ctx->fixup_src, req_ctx->fixup_src_len,
 				   edesc->sec4_sg + !!diff_size, 0);
 
-	if (dst_nents > 1)
+	if (mapped_dst_nents > 1)
 		sg_to_sec4_sg_last(req->dst, req->dst_len,
 				   edesc->sec4_sg + sec4_sg_index, 0);
 
@@ -335,6 +339,9 @@
 	if (!sec4_sg_bytes)
 		return edesc;
 
+	edesc->mapped_src_nents = mapped_src_nents;
+	edesc->mapped_dst_nents = mapped_dst_nents;
+
 	edesc->sec4_sg_dma = dma_map_single(dev, edesc->sec4_sg,
 					    sec4_sg_bytes, DMA_TO_DEVICE);
 	if (dma_mapping_error(dev, edesc->sec4_sg_dma)) {
@@ -351,11 +358,11 @@
 	return edesc;
 
 sec4_sg_fail:
-	dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
+	kfree(edesc);
 dst_fail:
-	dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
+	dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
 src_fail:
-	kfree(edesc);
+	dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
 	return ERR_PTR(-ENOMEM);
 }
 
@@ -383,15 +390,15 @@
 		return -ENOMEM;
 	}
 
-	if (edesc->src_nents > 1) {
+	if (edesc->mapped_src_nents > 1) {
 		pdb->sgf |= RSA_PDB_SGF_F;
 		pdb->f_dma = edesc->sec4_sg_dma;
-		sec4_sg_index += edesc->src_nents;
+		sec4_sg_index += edesc->mapped_src_nents;
 	} else {
 		pdb->f_dma = sg_dma_address(req_ctx->fixup_src);
 	}
 
-	if (edesc->dst_nents > 1) {
+	if (edesc->mapped_dst_nents > 1) {
 		pdb->sgf |= RSA_PDB_SGF_G;
 		pdb->g_dma = edesc->sec4_sg_dma +
 			     sec4_sg_index * sizeof(struct sec4_sg_entry);
@@ -428,17 +435,18 @@
 		return -ENOMEM;
 	}
 
-	if (edesc->src_nents > 1) {
+	if (edesc->mapped_src_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_G;
 		pdb->g_dma = edesc->sec4_sg_dma;
-		sec4_sg_index += edesc->src_nents;
+		sec4_sg_index += edesc->mapped_src_nents;
+
 	} else {
 		struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
 
 		pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
 	}
 
-	if (edesc->dst_nents > 1) {
+	if (edesc->mapped_dst_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_F;
 		pdb->f_dma = edesc->sec4_sg_dma +
 			     sec4_sg_index * sizeof(struct sec4_sg_entry);
@@ -493,17 +501,17 @@
 		goto unmap_tmp1;
 	}
 
-	if (edesc->src_nents > 1) {
+	if (edesc->mapped_src_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_G;
 		pdb->g_dma = edesc->sec4_sg_dma;
-		sec4_sg_index += edesc->src_nents;
+		sec4_sg_index += edesc->mapped_src_nents;
 	} else {
 		struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
 
 		pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
 	}
 
-	if (edesc->dst_nents > 1) {
+	if (edesc->mapped_dst_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_F;
 		pdb->f_dma = edesc->sec4_sg_dma +
 			     sec4_sg_index * sizeof(struct sec4_sg_entry);
@@ -582,17 +590,17 @@
 		goto unmap_tmp1;
 	}
 
-	if (edesc->src_nents > 1) {
+	if (edesc->mapped_src_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_G;
 		pdb->g_dma = edesc->sec4_sg_dma;
-		sec4_sg_index += edesc->src_nents;
+		sec4_sg_index += edesc->mapped_src_nents;
 	} else {
 		struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
 
 		pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
 	}
 
-	if (edesc->dst_nents > 1) {
+	if (edesc->mapped_dst_nents > 1) {
 		pdb->sgf |= RSA_PRIV_PDB_SGF_F;
 		pdb->f_dma = edesc->sec4_sg_dma +
 			     sec4_sg_index * sizeof(struct sec4_sg_entry);
@@ -1087,16 +1095,27 @@
 int caam_pkc_init(struct device *ctrldev)
 {
 	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
-	u32 pk_inst;
+	u32 pk_inst, pkha;
 	int err;
 	init_done = false;
 
 	/* Determine public key hardware accelerator presence. */
-	if (priv->era < 10)
-		pk_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
+	if (priv->era < 10) {
+		pk_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
 			   CHA_ID_LS_PK_MASK) >> CHA_ID_LS_PK_SHIFT;
-	else
-		pk_inst = rd_reg32(&priv->ctrl->vreg.pkha) & CHA_VER_NUM_MASK;
+	} else {
+		pkha = rd_reg32(&priv->jr[0]->vreg.pkha);
+		pk_inst = pkha & CHA_VER_NUM_MASK;
+
+		/*
+		 * Newer CAAMs support partially disabled functionality. If this is the
+		 * case, the number is non-zero, but this bit is set to indicate that
+		 * no encryption or decryption is supported. Only signing and verifying
+		 * is supported.
+		 */
+		if (pkha & CHA_VER_MISC_PKHA_NO_CRYPT)
+			pk_inst = 0;
+	}
 
 	/* Do not register algorithms if PKHA is not present. */
 	if (!pk_inst)
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caampkc.h
+++ linux-ein-5.4.0/drivers/crypto/caam/caampkc.h
@@ -112,8 +112,10 @@
 
 /**
  * rsa_edesc - s/w-extended rsa descriptor
- * @src_nents     : number of segments in input scatterlist
- * @dst_nents     : number of segments in output scatterlist
+ * @src_nents     : number of segments in input s/w scatterlist
+ * @dst_nents     : number of segments in output s/w scatterlist
+ * @mapped_src_nents: number of segments in input h/w link table
+ * @mapped_dst_nents: number of segments in output h/w link table
  * @sec4_sg_bytes : length of h/w link table
  * @sec4_sg_dma   : dma address of h/w link table
  * @sec4_sg       : pointer to h/w link table
@@ -123,6 +125,8 @@
 struct rsa_edesc {
 	int src_nents;
 	int dst_nents;
+	int mapped_src_nents;
+	int mapped_dst_nents;
 	int sec4_sg_bytes;
 	dma_addr_t sec4_sg_dma;
 	struct sec4_sg_entry *sec4_sg;
--- linux-ein-5.4.0.orig/drivers/crypto/caam/caamrng.c
+++ linux-ein-5.4.0/drivers/crypto/caam/caamrng.c
@@ -70,6 +70,7 @@
 
 /* rng per-device context */
 struct caam_rng_ctx {
+	struct hwrng rng;
 	struct device *jrdev;
 	dma_addr_t sh_desc_dma;
 	u32 sh_desc[DESC_RNG_LEN];
@@ -78,13 +79,10 @@
 	struct buf_data bufs[2];
 };
 
-static struct caam_rng_ctx *rng_ctx;
-
-/*
- * Variable used to avoid double free of resources in case
- * algorithm registration was unsuccessful
- */
-static bool init_done;
+static struct caam_rng_ctx *to_caam_rng_ctx(struct hwrng *r)
+{
+	return (struct caam_rng_ctx *)r->priv;
+}
 
 static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd)
 {
@@ -143,7 +141,7 @@
 
 static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait)
 {
-	struct caam_rng_ctx *ctx = rng_ctx;
+	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
 	struct buf_data *bd = &ctx->bufs[ctx->current_buf];
 	int next_buf_idx, copied_idx;
 	int err;
@@ -246,18 +244,63 @@
 
 static void caam_cleanup(struct hwrng *rng)
 {
+	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
 	int i;
 	struct buf_data *bd;
 
 	for (i = 0; i < 2; i++) {
-		bd = &rng_ctx->bufs[i];
+		bd = &ctx->bufs[i];
 		if (atomic_read(&bd->empty) == BUF_PENDING)
 			wait_for_completion(&bd->filled);
 	}
 
-	rng_unmap_ctx(rng_ctx);
+	rng_unmap_ctx(ctx);
+	caam_jr_free(ctx->jrdev);
+}
+
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
+static inline void test_len(struct hwrng *rng, size_t len, bool wait)
+{
+	u8 *buf;
+	int real_len;
+
+	buf = kzalloc(sizeof(u8) * len, GFP_KERNEL);
+	real_len = rng->read(rng, buf, len, wait);
+	if (real_len == 0 && wait)
+		pr_err("WAITING FAILED\n");
+	pr_info("wanted %zu bytes, got %d\n", len, real_len);
+	print_hex_dump(KERN_INFO, "random bytes@: ", DUMP_PREFIX_ADDRESS,
+		       16, 4, buf, real_len, 1);
+	kfree(buf);
+}
+
+static inline void test_mode_once(struct hwrng *rng, bool wait)
+{
+#define TEST_CHUNK (RN_BUF_SIZE / 4)
+
+	test_len(rng, TEST_CHUNK, wait);
+	test_len(rng, RN_BUF_SIZE * 2, wait);
+	test_len(rng, RN_BUF_SIZE * 2 - TEST_CHUNK, wait);
 }
 
+static inline void test_mode(struct hwrng *rng, bool wait)
+{
+#define TEST_PASS 1
+	int i;
+
+	for (i = 0; i < TEST_PASS; i++)
+		test_mode_once(rng, wait);
+}
+
+static void self_test(struct hwrng *rng)
+{
+	pr_info("testing without waiting\n");
+	test_mode(rng, false);
+	pr_info("testing with waiting\n");
+	test_mode(rng, true);
+}
+#endif
+
 static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
 {
 	struct buf_data *bd = &ctx->bufs[buf_id];
@@ -274,85 +317,90 @@
 	return 0;
 }
 
-static int caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev)
+static int caam_init(struct hwrng *rng)
 {
+	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
 	int err;
 
-	ctx->jrdev = jrdev;
+	ctx->jrdev = caam_jr_alloc();
+	err = PTR_ERR_OR_ZERO(ctx->jrdev);
+	if (err) {
+		pr_err("Job Ring Device allocation for transform failed\n");
+		return err;
+	}
 
 	err = rng_create_sh_desc(ctx);
 	if (err)
-		return err;
+		goto free_jrdev;
 
 	ctx->current_buf = 0;
 	ctx->cur_buf_idx = 0;
 
 	err = caam_init_buf(ctx, 0);
 	if (err)
-		return err;
+		goto free_jrdev;
 
-	return caam_init_buf(ctx, 1);
+	err = caam_init_buf(ctx, 1);
+	if (err)
+		goto free_jrdev;
+
+	return 0;
+
+free_jrdev:
+	caam_jr_free(ctx->jrdev);
+	return err;
 }
 
-static struct hwrng caam_rng = {
-	.name		= "rng-caam",
-	.cleanup	= caam_cleanup,
-	.read		= caam_read,
-};
+int caam_rng_init(struct device *ctrldev);
 
-void caam_rng_exit(void)
+void caam_rng_exit(struct device *ctrldev)
 {
-	if (!init_done)
-		return;
-
-	caam_jr_free(rng_ctx->jrdev);
-	hwrng_unregister(&caam_rng);
-	kfree(rng_ctx);
+	devres_release_group(ctrldev, caam_rng_init);
 }
 
 int caam_rng_init(struct device *ctrldev)
 {
-	struct device *dev;
+	struct caam_rng_ctx *ctx;
 	u32 rng_inst;
 	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
-	int err;
-	init_done = false;
+	int ret;
 
 	/* Check for an instantiated RNG before registration */
 	if (priv->era < 10)
-		rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
+		rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
 			    CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
 	else
-		rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
+		rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK;
 
 	if (!rng_inst)
 		return 0;
 
-	dev = caam_jr_alloc();
-	if (IS_ERR(dev)) {
-		pr_err("Job Ring Device allocation for transform failed\n");
-		return PTR_ERR(dev);
-	}
-	rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL);
-	if (!rng_ctx) {
-		err = -ENOMEM;
-		goto free_caam_alloc;
-	}
-	err = caam_init_rng(rng_ctx, dev);
-	if (err)
-		goto free_rng_ctx;
+	if (!devres_open_group(ctrldev, caam_rng_init, GFP_KERNEL))
+		return -ENOMEM;
 
-	dev_info(dev, "registering rng-caam\n");
+	ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_DMA | GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
 
-	err = hwrng_register(&caam_rng);
-	if (!err) {
-		init_done = true;
-		return err;
+	ctx->rng.name    = "rng-caam";
+	ctx->rng.init    = caam_init;
+	ctx->rng.cleanup = caam_cleanup;
+	ctx->rng.read    = caam_read;
+	ctx->rng.priv    = (unsigned long)ctx;
+
+	dev_info(ctrldev, "registering rng-caam\n");
+
+	ret = devm_hwrng_register(ctrldev, &ctx->rng);
+	if (ret) {
+		caam_rng_exit(ctrldev);
+		return ret;
 	}
 
-free_rng_ctx:
-	kfree(rng_ctx);
-free_caam_alloc:
-	caam_jr_free(dev);
-	return err;
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
+	dev_info(ctrldev, "Running self-test\n");
+	self_test(&ctx->rng);
+#endif
+
+	devres_close_group(ctrldev, caam_rng_init);
+	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/crypto/caam/compat.h
+++ linux-ein-5.4.0/drivers/crypto/caam/compat.h
@@ -43,7 +43,6 @@
 #include <crypto/akcipher.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/skcipher.h>
-#include <crypto/arc4.h>
 #include <crypto/internal/skcipher.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/rsa.h>
--- linux-ein-5.4.0.orig/drivers/crypto/caam/ctrl.c
+++ linux-ein-5.4.0/drivers/crypto/caam/ctrl.c
@@ -17,6 +17,7 @@
 #include "jr.h"
 #include "desc_constr.h"
 #include "ctrl.h"
+#include "sm.h"
 
 bool caam_dpaa2;
 EXPORT_SYMBOL(caam_dpaa2);
@@ -99,10 +100,13 @@
 
 	if (ctrlpriv->virt_en == 1 ||
 	    /*
-	     * Apparently on i.MX8MQ it doesn't matter if virt_en == 1
+	     * Apparently on i.MX8M{Q,M,N,P} it doesn't matter if virt_en == 1
 	     * and the following steps should be performed regardless
 	     */
-	    of_machine_is_compatible("fsl,imx8mq")) {
+	    of_machine_is_compatible("fsl,imx8mq") ||
+	    of_machine_is_compatible("fsl,imx8mm") ||
+	    of_machine_is_compatible("fsl,imx8mn") ||
+	    of_machine_is_compatible("fsl,imx8mp")) {
 		clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0);
 
 		while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) &&
@@ -176,6 +180,73 @@
 }
 
 /*
+ * deinstantiate_rng - builds and executes a descriptor on DECO0,
+ *		       which deinitializes the RNG block.
+ * @ctrldev - pointer to device
+ * @state_handle_mask - bitmask containing the instantiation status
+ *			for the RNG4 state handles which exist in
+ *			the RNG4 block: 1 if it's been instantiated
+ *
+ * Return: - 0 if no error occurred
+ *	   - -ENOMEM if there isn't enough memory to allocate the descriptor
+ *	   - -ENODEV if DECO0 couldn't be acquired
+ *	   - -EAGAIN if an error occurred when executing the descriptor
+ */
+static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
+{
+	u32 *desc, status;
+	int sh_idx, ret = 0;
+
+	desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL | GFP_DMA);
+	if (!desc)
+		return -ENOMEM;
+
+	for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
+		/*
+		 * If the corresponding bit is set, then it means the state
+		 * handle was initialized by us, and thus it needs to be
+		 * deinitialized as well
+		 */
+		if ((1 << sh_idx) & state_handle_mask) {
+			/*
+			 * Create the descriptor for deinstantating this state
+			 * handle
+			 */
+			build_deinstantiation_desc(desc, sh_idx);
+
+			/* Try to run it through DECO0 */
+			ret = run_descriptor_deco0(ctrldev, desc, &status);
+
+			if (ret ||
+			    (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
+				dev_err(ctrldev,
+					"Failed to deinstantiate RNG4 SH%d\n",
+					sh_idx);
+				break;
+			}
+			dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
+		}
+	}
+
+	kfree(desc);
+
+	return ret;
+}
+
+static void devm_deinstantiate_rng(void *data)
+{
+	struct device *ctrldev = data;
+	struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+
+	/*
+	 * De-initialize RNG state handles initialized by this driver.
+	 * In case of SoCs with Management Complex, RNG is managed by MC f/w.
+	 */
+	if (ctrlpriv->rng4_sh_init)
+		deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
+}
+
+/*
  * instantiate_rng - builds and executes a descriptor on DECO0,
  *		     which initializes the RNG block.
  * @ctrldev - pointer to device
@@ -203,7 +274,7 @@
 	int ret = 0, sh_idx;
 
 	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
-	desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
+	desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL | GFP_DMA);
 	if (!desc)
 		return -ENOMEM;
 
@@ -247,99 +318,13 @@
 
 	kfree(desc);
 
-	return ret;
-}
-
-/*
- * deinstantiate_rng - builds and executes a descriptor on DECO0,
- *		       which deinitializes the RNG block.
- * @ctrldev - pointer to device
- * @state_handle_mask - bitmask containing the instantiation status
- *			for the RNG4 state handles which exist in
- *			the RNG4 block: 1 if it's been instantiated
- *
- * Return: - 0 if no error occurred
- *	   - -ENOMEM if there isn't enough memory to allocate the descriptor
- *	   - -ENODEV if DECO0 couldn't be acquired
- *	   - -EAGAIN if an error occurred when executing the descriptor
- */
-static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
-{
-	u32 *desc, status;
-	int sh_idx, ret = 0;
-
-	desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
-	for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
-		/*
-		 * If the corresponding bit is set, then it means the state
-		 * handle was initialized by us, and thus it needs to be
-		 * deinitialized as well
-		 */
-		if ((1 << sh_idx) & state_handle_mask) {
-			/*
-			 * Create the descriptor for deinstantating this state
-			 * handle
-			 */
-			build_deinstantiation_desc(desc, sh_idx);
-
-			/* Try to run it through DECO0 */
-			ret = run_descriptor_deco0(ctrldev, desc, &status);
-
-			if (ret ||
-			    (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
-				dev_err(ctrldev,
-					"Failed to deinstantiate RNG4 SH%d\n",
-					sh_idx);
-				break;
-			}
-			dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
-		}
-	}
-
-	kfree(desc);
+	if (!ret)
+		ret = devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng,
+					       ctrldev);
 
 	return ret;
 }
 
-static int caam_remove(struct platform_device *pdev)
-{
-	struct device *ctrldev;
-	struct caam_drv_private *ctrlpriv;
-	struct caam_ctrl __iomem *ctrl;
-
-	ctrldev = &pdev->dev;
-	ctrlpriv = dev_get_drvdata(ctrldev);
-	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
-
-	/* Remove platform devices under the crypto node */
-	of_platform_depopulate(ctrldev);
-
-#ifdef CONFIG_CAAM_QI
-	if (ctrlpriv->qi_init)
-		caam_qi_shutdown(ctrldev);
-#endif
-
-	/*
-	 * De-initialize RNG state handles initialized by this driver.
-	 * In case of SoCs with Management Complex, RNG is managed by MC f/w.
-	 */
-	if (!ctrlpriv->mc_en && ctrlpriv->rng4_sh_init)
-		deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
-
-	/* Shut down debug views */
-#ifdef CONFIG_DEBUG_FS
-	debugfs_remove_recursive(ctrlpriv->dfs_root);
-#endif
-
-	/* Unmap controller region */
-	iounmap(ctrl);
-
-	return 0;
-}
-
 /*
  * kick_trng - sets the various parameters for enabling the initialization
  *	       of the RNG4 block in CAAM
@@ -357,8 +342,12 @@
 	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
 	r4tst = &ctrl->r4tst[0];
 
-	/* put RNG4 into program mode */
-	clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM);
+	/*
+	 * Setting both RTMCTL:PRGM and RTMCTL:TRNG_ACC causes TRNG to
+	 * properly invalidate the entropy in the entropy register and
+	 * force re-generation.
+	 */
+	clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC);
 
 	/*
 	 * Performance-wise, it does not make sense to
@@ -379,8 +368,8 @@
 	wr_reg32(&r4tst->rtsdctl, val);
 	/* min. freq. count, equal to 1/4 of the entropy sample length */
 	wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2);
-	/* disable maximum frequency count */
-	wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE);
+	/* max. freq. count, equal to 16 times the entropy sample length */
+	wr_reg32(&r4tst->rtfrqmax, ent_delay << 4);
 	/* read the control register */
 	val = rd_reg32(&r4tst->rtmctl);
 start_rng:
@@ -388,10 +377,11 @@
 	 * select raw sampling in both entropy shifter
 	 * and statistical checker; ; put RNG4 into run mode
 	 */
-	clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, RTMCTL_SAMP_MODE_RAW_ES_SC);
+	clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC,
+		      RTMCTL_SAMP_MODE_RAW_ES_SC);
 }
 
-static int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl)
+static int caam_get_era_from_hw(struct caam_perfmon __iomem *perfmon)
 {
 	static const struct {
 		u16 ip_id;
@@ -417,12 +407,12 @@
 	u16 ip_id;
 	int i;
 
-	ccbvid = rd_reg32(&ctrl->perfmon.ccb_id);
+	ccbvid = rd_reg32(&perfmon->ccb_id);
 	era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT;
 	if (era)	/* This is '0' prior to CAAM ERA-6 */
 		return era;
 
-	id_ms = rd_reg32(&ctrl->perfmon.caam_id_ms);
+	id_ms = rd_reg32(&perfmon->caam_id_ms);
 	ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT;
 	maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT;
 
@@ -440,7 +430,7 @@
  * In case this property is not passed an attempt to retrieve the CAAM
  * era via register reads will be made.
  **/
-static int caam_get_era(struct caam_ctrl __iomem *ctrl)
+static int caam_get_era(struct caam_perfmon __iomem *perfmon)
 {
 	struct device_node *caam_node;
 	int ret;
@@ -453,7 +443,7 @@
 	if (!ret)
 		return prop;
 	else
-		return caam_get_era_from_hw(ctrl);
+		return caam_get_era_from_hw(perfmon);
 }
 
 /*
@@ -527,7 +517,7 @@
 	{ .soc_id = "i.MX6UL", .data = &caam_imx6ul_data },
 	{ .soc_id = "i.MX6*",  .data = &caam_imx6_data },
 	{ .soc_id = "i.MX7*",  .data = &caam_imx7_data },
-	{ .soc_id = "i.MX8MQ", .data = &caam_imx7_data },
+	{ .soc_id = "i.MX8M*", .data = &caam_imx7_data },
 	{ .family = "Freescale i.MX" },
 	{ /* sentinel */ }
 };
@@ -568,6 +558,13 @@
 	return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv);
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void caam_remove_debugfs(void *root)
+{
+	debugfs_remove_recursive(root);
+}
+#endif
+
 /* Probe routine for CAAM top (controller) level */
 static int caam_probe(struct platform_device *pdev)
 {
@@ -576,15 +573,18 @@
 	const struct soc_device_attribute *imx_soc_match;
 	struct device *dev;
 	struct device_node *nprop, *np;
+	struct resource res_regs;
 	struct caam_ctrl __iomem *ctrl;
 	struct caam_drv_private *ctrlpriv;
+	struct caam_perfmon __iomem *perfmon;
 #ifdef CONFIG_DEBUG_FS
-	struct caam_perfmon *perfmon;
+	struct dentry *dfs_root;
 #endif
 	u32 scfgr, comp_params;
 	u8 rng_vid;
 	int pg_size;
 	int BLOCK_OFFSET = 0;
+	bool reg_access = true;
 
 	ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL);
 	if (!ctrlpriv)
@@ -598,6 +598,30 @@
 	caam_imx = (bool)imx_soc_match;
 
 	if (imx_soc_match) {
+		np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
+		ctrlpriv->scu_en = !!np;
+		of_node_put(np);
+
+		reg_access = !ctrlpriv->scu_en;
+
+		/*
+		 * CAAM clocks cannot be controlled from kernel.
+		 * They are automatically turned on by SCU f/w.
+		 */
+		if (ctrlpriv->scu_en)
+			goto iomap_ctrl;
+
+		/*
+		 * Until Layerscape and i.MX OP-TEE get in sync,
+		 * only i.MX OP-TEE use cases disallow access to
+		 * caam page 0 (controller) registers.
+		 */
+		np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz");
+		ctrlpriv->optee_en = !!np;
+		of_node_put(np);
+
+		reg_access = reg_access && !ctrlpriv->optee_en;
+
 		if (!imx_soc_match->data) {
 			dev_err(dev, "No clock data provided for i.MX SoC");
 			return -EINVAL;
@@ -608,19 +632,48 @@
 			return ret;
 	}
 
-
+iomap_ctrl:
 	/* Get configuration properties from device tree */
 	/* First, get register page */
-	ctrl = of_iomap(nprop, 0);
-	if (!ctrl) {
+	ctrl = devm_of_iomap(dev, nprop, 0, NULL);
+	ret = PTR_ERR_OR_ZERO(ctrl);
+	if (ret) {
 		dev_err(dev, "caam: of_iomap() failed\n");
-		return -ENOMEM;
+		return ret;
 	}
 
-	caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
+	ring = 0;
+	for_each_available_child_of_node(nprop, np)
+		if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+		    of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
+			u32 reg;
+
+			if (of_property_read_u32_index(np, "reg", 0, &reg)) {
+				dev_err(dev, "%s read reg property error\n",
+					np->full_name);
+				continue;
+			}
+
+			ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
+					     ((__force uint8_t *)ctrl + reg);
+
+			ctrlpriv->total_jobrs++;
+			ring++;
+		}
+
+	/*
+	 * Wherever possible, instead of accessing registers from the global page,
+	 * use the alias registers in the first (cf. DT nodes order)
+	 * job ring's page.
+	 */
+	perfmon = ring ? (struct caam_perfmon *)&ctrlpriv->jr[0]->perfmon :
+			 (struct caam_perfmon *)&ctrl->perfmon;
+
+	caam_little_end = !(bool)(rd_reg32(&perfmon->status) &
 				  (CSTA_PLEND | CSTA_ALT_PLEND));
-	comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms);
-	if (comp_params & CTPR_MS_PS && rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
+	comp_params = rd_reg32(&perfmon->comp_parms_ms);
+	if (reg_access && comp_params & CTPR_MS_PS &&
+	    rd_reg32(&ctrl->mcr) & MCFGR_LONG_PTR)
 		caam_ptr_sz = sizeof(u64);
 	else
 		caam_ptr_sz = sizeof(u32);
@@ -632,22 +685,18 @@
 	if (ctrlpriv->qi_present && !caam_dpaa2) {
 		ret = qman_is_probed();
 		if (!ret) {
-			ret = -EPROBE_DEFER;
-			goto iounmap_ctrl;
+			return -EPROBE_DEFER;
 		} else if (ret < 0) {
 			dev_err(dev, "failing probe due to qman probe error\n");
-			ret = -ENODEV;
-			goto iounmap_ctrl;
+			return -ENODEV;
 		}
 
 		ret = qman_portals_probed();
 		if (!ret) {
-			ret = -EPROBE_DEFER;
-			goto iounmap_ctrl;
+			return -EPROBE_DEFER;
 		} else if (ret < 0) {
 			dev_err(dev, "failing probe due to qman portals probe error\n");
-			ret = -ENODEV;
-			goto iounmap_ctrl;
+			return -ENODEV;
 		}
 	}
 #endif
@@ -671,9 +720,46 @@
 			 BLOCK_OFFSET * DECO_BLOCK_NUMBER
 			 );
 
-	/* Get the IRQ of the controller (for security violations only) */
-	ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
+	/* Only i.MX SoCs have sm */
+	if (!imx_soc_match)
+		goto mc_fw;
+
+	/* Get CAAM-SM node and of_iomap() and save */
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+	if (!np)
+		return -ENODEV;
 
+	/* Get CAAM SM registers base address from device tree */
+	ret = of_address_to_resource(np, 0, &res_regs);
+	if (ret) {
+		dev_err(dev, "failed to retrieve registers base from device tree\n");
+		of_node_put(np);
+		return -ENODEV;
+	}
+
+	ctrlpriv->sm_phy = res_regs.start;
+	ctrlpriv->sm_base = devm_ioremap_resource(dev, &res_regs);
+	if (IS_ERR(ctrlpriv->sm_base)) {
+		of_node_put(np);
+		return PTR_ERR(ctrlpriv->sm_base);
+	}
+
+	if (!of_machine_is_compatible("fsl,imx8mn") &&
+	    !of_machine_is_compatible("fsl,imx8mm") &&
+	    !of_machine_is_compatible("fsl,imx8mq") &&
+	    !of_machine_is_compatible("fsl,imx8qm") &&
+	    !of_machine_is_compatible("fsl,imx8qxp"))
+		ctrlpriv->sm_size = resource_size(&res_regs);
+	else
+		ctrlpriv->sm_size = PG_SIZE_64K;
+
+	ctrlpriv->sm_present = 1;
+	of_node_put(np);
+
+	if (!reg_access)
+		goto set_dma_mask;
+
+mc_fw:
 	/*
 	 * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
 	 * long pointers in master configuration register.
@@ -685,11 +771,9 @@
 	of_node_put(np);
 
 	if (!ctrlpriv->mc_en)
-		clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
+		clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK,
 			      MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
-			      MCFGR_WDENABLE | MCFGR_LARGE_BURST |
-			      (sizeof(dma_addr_t) == sizeof(u64) ?
-			       MCFGR_LONG_PTR : 0));
+			      MCFGR_WDENABLE | MCFGR_LARGE_BURST);
 
 	handle_imx6_err005766(&ctrl->mcr);
 
@@ -719,13 +803,14 @@
 			      JRSTART_JR1_START | JRSTART_JR2_START |
 			      JRSTART_JR3_START);
 
+set_dma_mask:
 	ret = dma_set_mask_and_coherent(dev, caam_get_dma_mask(dev));
 	if (ret) {
 		dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
-		goto iounmap_ctrl;
+		return ret;
 	}
 
-	ctrlpriv->era = caam_get_era(ctrl);
+	ctrlpriv->era = caam_get_era(perfmon);
 	ctrlpriv->domain = iommu_get_domain_for_dev(dev);
 
 #ifdef CONFIG_DEBUG_FS
@@ -734,10 +819,12 @@
 	 * "caam" and nprop->full_name. The OF name isn't distinctive,
 	 * but does separate instances
 	 */
-	perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
+	dfs_root = debugfs_create_dir(dev_name(dev), NULL);
+	ret = devm_add_action_or_reset(dev, caam_remove_debugfs, dfs_root);
+	if (ret)
+		return ret;
 
-	ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
-	ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
+	ctrlpriv->ctl = debugfs_create_dir("ctl", dfs_root);
 #endif
 
 	/* Check to see if (DPAA 1.x) QI present. If so, enable */
@@ -757,38 +844,27 @@
 #endif
 	}
 
-	ret = of_platform_populate(nprop, caam_match, NULL, dev);
-	if (ret) {
-		dev_err(dev, "JR platform devices creation error\n");
-		goto shutdown_qi;
-	}
-
-	ring = 0;
-	for_each_available_child_of_node(nprop, np)
-		if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
-		    of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
-			ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
-					     ((__force uint8_t *)ctrl +
-					     (ring + JR_BLOCK_NUMBER) *
-					      BLOCK_OFFSET
-					     );
-			ctrlpriv->total_jobrs++;
-			ring++;
-		}
-
 	/* If no QI and no rings specified, quit and go home */
 	if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
 		dev_err(dev, "no queues configured, terminating\n");
-		ret = -ENOMEM;
-		goto caam_remove;
+		return -ENOMEM;
 	}
 
-	if (ctrlpriv->era < 10)
-		rng_vid = (rd_reg32(&ctrl->perfmon.cha_id_ls) &
+	if (!reg_access)
+		goto report_live;
+
+	if (ctrlpriv->era < 10) {
+		rng_vid = (rd_reg32(&perfmon->cha_id_ls) &
 			   CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
-	else
-		rng_vid = (rd_reg32(&ctrl->vreg.rng) & CHA_VER_VID_MASK) >>
+	} else {
+		struct version_regs __iomem *vreg;
+
+		vreg = ring ? (struct version_regs *)&ctrlpriv->jr[0]->vreg :
+			      (struct version_regs *)&ctrl->vreg;
+
+		rng_vid = (rd_reg32(&vreg->rng) & CHA_VER_VID_MASK) >>
 			   CHA_VER_VID_SHIFT;
+	}
 
 	/*
 	 * If SEC has RNG version >= 4 and RNG state handle has not been
@@ -843,7 +919,7 @@
 		} while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
 		if (ret) {
 			dev_err(dev, "failed to instantiate RNG");
-			goto caam_remove;
+			return ret;
 		}
 		/*
 		 * Set handles init'ed by this module as the complement of the
@@ -857,8 +933,9 @@
 
 	/* NOTE: RTIC detection ought to go here, around Si time */
 
-	caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 |
-		  (u64)rd_reg32(&ctrl->perfmon.caam_id_ls);
+report_live:
+	caam_id = (u64)rd_reg32(&perfmon->caam_id_ms) << 32 |
+		  (u64)rd_reg32(&perfmon->caam_id_ls);
 
 	/* Report "alive" for developer to see */
 	dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
@@ -900,6 +977,9 @@
 			    ctrlpriv->ctl, &perfmon->status,
 			    &caam_fops_u32_ro);
 
+	if (!reg_access)
+		goto probe_jrs;
+
 	/* Internal covering keys (useful in non-secure mode only) */
 	ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0];
 	ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
@@ -916,19 +996,12 @@
 	debugfs_create_blob("tdsk", S_IRUSR | S_IRGRP | S_IROTH, ctrlpriv->ctl,
 			    &ctrlpriv->ctl_tdsk_wrap);
 #endif
-	return 0;
 
-caam_remove:
-	caam_remove(pdev);
-	return ret;
+probe_jrs:
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		dev_err(dev, "JR platform devices creation error\n");
 
-shutdown_qi:
-#ifdef CONFIG_CAAM_QI
-	if (ctrlpriv->qi_init)
-		caam_qi_shutdown(dev);
-#endif
-iounmap_ctrl:
-	iounmap(ctrl);
 	return ret;
 }
 
@@ -938,7 +1011,6 @@
 		.of_match_table = caam_match,
 	},
 	.probe       = caam_probe,
-	.remove      = caam_remove,
 };
 
 module_platform_driver(caam_driver);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/desc.h
+++ linux-ein-5.4.0/drivers/crypto/caam/desc.h
@@ -152,7 +152,7 @@
  * with the TDKEK if TK is set
  */
 #define KEY_ENC			0x00400000
-
+#define KEY_ENC_OFFSET		22
 /*
  * No Write Back - Do not allow key to be FIFO STOREd
  */
@@ -162,11 +162,13 @@
  * Enhanced Encryption of Key
  */
 #define KEY_EKT			0x00100000
+#define KEY_EKT_OFFSET		20
 
 /*
  * Encrypted with Trusted Key
  */
 #define KEY_TK			0x00008000
+#define KEY_TK_OFFSET		15
 
 /*
  * KDEST - Key Destination: 0 - class key register,
@@ -403,6 +405,10 @@
 #define FIFOST_TYPE_PKHA_N	 (0x08 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_PKHA_A	 (0x0c << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_PKHA_B	 (0x0d << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_CCM_JKEK	(0x10 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_CCM_TKEK	(0x11 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_CCM_JKEK	(0x14 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_CCM_TKEK	(0x15 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_PKHA_E_JKEK	 (0x22 << FIFOST_TYPE_SHIFT)
@@ -1136,6 +1142,23 @@
 #define OP_PCL_PKPROT_ECC			 0x0002
 #define OP_PCL_PKPROT_F2M			 0x0001
 
+/* Blob protocol protinfo bits */
+#define OP_PCL_BLOB_TK			0x0200
+#define OP_PCL_BLOB_EKT			0x0100
+
+#define OP_PCL_BLOB_K2KR_MEM		0x0000
+#define OP_PCL_BLOB_K2KR_C1KR		0x0010
+#define OP_PCL_BLOB_K2KR_C2KR		0x0030
+#define OP_PCL_BLOB_K2KR_AFHAS		0x0050
+#define OP_PCL_BLOB_K2KR_C2KR_SPLIT	0x0070
+
+#define OP_PCL_BLOB_PTXT_SECMEM		0x0008
+#define OP_PCL_BLOB_BLACK		0x0004
+
+#define OP_PCL_BLOB_FMT_NORMAL		0x0000
+#define OP_PCL_BLOB_FMT_MSTR		0x0002
+#define OP_PCL_BLOB_FMT_TEST		0x0003
+
 /* For non-protocol/alg-only op commands */
 #define OP_ALG_TYPE_SHIFT	24
 #define OP_ALG_TYPE_MASK	(0x7 << OP_ALG_TYPE_SHIFT)
--- linux-ein-5.4.0.orig/drivers/crypto/caam/desc_constr.h
+++ linux-ein-5.4.0/drivers/crypto/caam/desc_constr.h
@@ -500,6 +500,8 @@
  * @key_virt: virtual address where algorithm key resides
  * @key_inline: true - key can be inlined in the descriptor; false - key is
  *              referenced by the descriptor
+ * @key_real_len: size of the key to be loaded by the CAAM
+ * @key_cmd_opt: optional parameters for KEY command
  */
 struct alginfo {
 	u32 algtype;
@@ -508,6 +510,8 @@
 	dma_addr_t key_dma;
 	const void *key_virt;
 	bool key_inline;
+	u32 key_real_len;
+	u32 key_cmd_opt;
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/crypto/caam/intern.h
+++ linux-ein-5.4.0/drivers/crypto/caam/intern.h
@@ -46,6 +46,7 @@
 	struct caam_job_ring __iomem *rregs;	/* JobR's register space */
 	struct tasklet_struct irqtask;
 	int irq;			/* One per queue */
+	bool hwrng;
 
 	/* Number of scatterlist crypt transforms active on the JobR */
 	atomic_t tfm_count ____cacheline_aligned;
@@ -66,12 +67,17 @@
  * Driver-private storage for a single CAAM block instance
  */
 struct caam_drv_private {
+	struct device *smdev;
+
 	/* Physical-presence section */
 	struct caam_ctrl __iomem *ctrl; /* controller region */
 	struct caam_deco __iomem *deco; /* DECO/CCB views */
 	struct caam_assurance __iomem *assure;
 	struct caam_queue_if __iomem *qi; /* QI control region */
 	struct caam_job_ring __iomem *jr[4];	/* JobR's register space */
+	dma_addr_t __iomem *sm_base;	/* Secure memory storage base */
+	phys_addr_t sm_phy;		/* Secure memory storage physical */
+	u32 sm_size;
 
 	struct iommu_domain *domain;
 
@@ -81,11 +87,10 @@
 	 */
 	u8 total_jobrs;		/* Total Job Rings in device */
 	u8 qi_present;		/* Nonzero if QI present in device */
-#ifdef CONFIG_CAAM_QI
-	u8 qi_init;		/* Nonzero if QI has been initialized */
-#endif
+	u8 sm_present;		/* Nonzero if Secure Memory is supported */
 	u8 mc_en;		/* Nonzero if MC f/w is active */
-	int secvio_irq;		/* Security violation interrupt number */
+	u8 scu_en;		/* Nonzero if SCU f/w is active */
+	u8 optee_en;		/* Nonzero if OP-TEE f/w is active */
 	int virt_en;		/* Virtualization enabled in CAAM */
 	int era;		/* CAAM Era (internal HW revision) */
 
@@ -102,7 +107,6 @@
 	 * variables at runtime.
 	 */
 #ifdef CONFIG_DEBUG_FS
-	struct dentry *dfs_root;
 	struct dentry *ctl; /* controller dir */
 	struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
 #endif
@@ -165,7 +169,7 @@
 #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API
 
 int caam_rng_init(struct device *dev);
-void caam_rng_exit(void);
+void caam_rng_exit(struct device *dev);
 
 #else
 
@@ -174,9 +178,7 @@
 	return 0;
 }
 
-static inline void caam_rng_exit(void)
-{
-}
+static inline void caam_rng_exit(struct device *dev) {}
 
 #endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */
 
@@ -198,6 +200,42 @@
 
 #endif /* CONFIG_CAAM_QI */
 
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_SM
+
+int caam_sm_startup(struct device *dev);
+void caam_sm_shutdown(struct device *dev);
+
+#else
+
+static inline int caam_sm_startup(struct device *dev)
+{
+	return 0;
+}
+
+static inline void caam_sm_shutdown(struct device *dev)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_SM */
+
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API
+
+int caam_keygen_init(void);
+void caam_keygen_exit(void);
+
+#else
+
+static inline int caam_keygen_init(void)
+{
+	return 0;
+}
+
+static inline void caam_keygen_exit(void)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API */
+
 #ifdef CONFIG_DEBUG_FS
 static int caam_debugfs_u64_get(void *data, u64 *val)
 {
--- linux-ein-5.4.0.orig/drivers/crypto/caam/jr.c
+++ linux-ein-5.4.0/drivers/crypto/caam/jr.c
@@ -4,7 +4,7 @@
  * JobR backend functionality
  *
  * Copyright 2008-2012 Freescale Semiconductor, Inc.
- * Copyright 2019 NXP
+ * Copyright 2019-2020 NXP
  */
 
 #include <linux/of_irq.h>
@@ -27,36 +27,40 @@
 static DEFINE_MUTEX(algs_lock);
 static unsigned int active_devs;
 
-static void register_algs(struct device *dev)
+static void register_algs(struct caam_drv_private_jr *jrpriv,
+			  struct device *dev)
 {
 	mutex_lock(&algs_lock);
 
 	if (++active_devs != 1)
 		goto algs_unlock;
 
+	caam_sm_startup(dev);
 	caam_algapi_init(dev);
 	caam_algapi_hash_init(dev);
 	caam_pkc_init(dev);
-	caam_rng_init(dev);
+	jrpriv->hwrng = !caam_rng_init(dev);
 	caam_qi_algapi_init(dev);
+	caam_keygen_init();
 
 algs_unlock:
 	mutex_unlock(&algs_lock);
 }
 
-static void unregister_algs(void)
+static void unregister_algs(struct device *dev)
 {
 	mutex_lock(&algs_lock);
 
 	if (--active_devs != 0)
 		goto algs_unlock;
 
+	caam_keygen_exit();
 	caam_qi_algapi_exit();
 
-	caam_rng_exit();
 	caam_pkc_exit();
 	caam_algapi_hash_exit();
 	caam_algapi_exit();
+	caam_sm_shutdown(dev);
 
 algs_unlock:
 	mutex_unlock(&algs_lock);
@@ -126,6 +130,9 @@
 	jrdev = &pdev->dev;
 	jrpriv = dev_get_drvdata(jrdev);
 
+	if (jrpriv->hwrng)
+		caam_rng_exit(jrdev->parent);
+
 	/*
 	 * Return EBUSY if job ring already allocated.
 	 */
@@ -135,7 +142,7 @@
 	}
 
 	/* Unregister JR-based RNG & crypto algorithms */
-	unregister_algs();
+	unregister_algs(jrdev->parent);
 
 	/* Remove the node from Physical JobR list maintained by driver */
 	spin_lock(&driver_data.jr_alloc_lock);
@@ -327,8 +334,7 @@
  * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
  * -EBUSY if the queue is full, -EIO if it cannot map the caller's
  * descriptor.
- * @dev:  device of the job ring to be used. This device should have
- *        been assigned prior by caam_jr_register().
+ * @dev:  struct device of the job ring to be used
  * @desc: points to a job descriptor that execute our request. All
  *        descriptors (and all referenced data) must be in a DMAable
  *        region, and all data references must be physical addresses
@@ -393,8 +399,16 @@
 	 * Guarantee that the descriptor's DMA address has been written to
 	 * the next slot in the ring before the write index is updated, since
 	 * other cores may update this index independently.
+	 *
+	 * Under heavy DDR load, smp_wmb() or dma_wmb() fail to make the input
+	 * ring be updated before the CAAM starts reading it. So, CAAM will
+	 * process, again, an old descriptor address and will put it in the
+	 * output ring. This will make caam_jr_dequeue() to fail, since this
+	 * old descriptor is not in the software ring.
+	 * To fix this, use wmb() which works on the full system instead of
+	 * inner/outer shareable domains.
 	 */
-	smp_wmb();
+	wmb();
 
 	jrp->head = (head + 1) & (JOBR_DEPTH - 1);
 
@@ -418,6 +432,80 @@
 }
 EXPORT_SYMBOL(caam_jr_enqueue);
 
+/**
+ * caam_jr_run_and_wait_for_completion() - Enqueue a job and wait for its
+ * completion. Returns 0 if OK, -ENOSPC if the queue is full,
+ * -EIO if it cannot map the caller's descriptor.
+ * @dev:  struct device of the job ring to be used
+ * @desc: points to a job descriptor that execute our request. All
+ *        descriptors (and all referenced data) must be in a DMAable
+ *        region, and all data references must be physical addresses
+ *        accessible to CAAM (i.e. within a PAMU window granted
+ *        to it).
+ * @cbk:  pointer to a callback function to be invoked upon completion
+ *        of this request. This has the form:
+ *        callback(struct device *dev, u32 *desc, u32 stat, void *arg)
+ *        where:
+ *        @dev:    contains the job ring device that processed this
+ *                 response.
+ *        @desc:   descriptor that initiated the request, same as
+ *                 "desc" being argued to caam_jr_enqueue().
+ *        @status: untranslated status received from CAAM. See the
+ *                 reference manual for a detailed description of
+ *                 error meaning, or see the JRSTA definitions in the
+ *                 register header file
+ *        @areq:   optional pointer to an argument passed with the
+ *                 original request
+ **/
+int caam_jr_run_and_wait_for_completion(struct device *dev, u32 *desc,
+					void (*cbk)(struct device *dev,
+						    u32 *desc, u32 status,
+						    void *areq))
+{
+	int ret = 0;
+	struct jr_job_result jobres = {0};
+
+	/* Initialize the completion structure */
+	init_completion(&jobres.completion);
+
+	/* Enqueue job for execution */
+	ret = caam_jr_enqueue(dev, desc, cbk, &jobres);
+	if (ret != -EINPROGRESS)
+		return ret;
+
+	/* Wait for job completion */
+	wait_for_completion(&jobres.completion);
+
+	/* Get return code processed in cbk */
+	ret = jobres.error;
+
+	return ret;
+}
+EXPORT_SYMBOL(caam_jr_run_and_wait_for_completion);
+
+static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
+			    dma_addr_t outbusaddr)
+{
+	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+	wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
+	wr_reg64(&jrp->rregs->outring_base, outbusaddr);
+	wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
+	wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+
+	/* Select interrupt coalescing parameters */
+	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
+		      (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+		      (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+}
+
+static void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
+{
+	jrp->out_ring_read_index = 0;
+	jrp->head = 0;
+	jrp->tail = 0;
+}
+
 /*
  * Init JobR independent of platform property detection
  */
@@ -505,7 +593,7 @@
 	int error;
 
 	jrdev = &pdev->dev;
-	jrpriv = devm_kmalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
+	jrpriv = devm_kzalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
 	if (!jrpriv)
 		return -ENOMEM;
 
@@ -562,11 +650,41 @@
 
 	atomic_set(&jrpriv->tfm_count, 0);
 
-	register_algs(jrdev->parent);
+	device_init_wakeup(&pdev->dev, 1);
+	device_set_wakeup_enable(&pdev->dev, false);
+
+	register_algs(jrpriv, jrdev->parent);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int caam_jr_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(jrpriv->irq);
 
 	return 0;
 }
 
+static int caam_jr_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(jrpriv->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
+			 caam_jr_resume);
+#endif
+
 static const struct of_device_id caam_jr_match[] = {
 	{
 		.compatible = "fsl,sec-v4.0-job-ring",
@@ -582,6 +700,9 @@
 	.driver = {
 		.name = "caam_jr",
 		.of_match_table = caam_jr_match,
+#ifdef CONFIG_PM
+		.pm = &caam_jr_pm_ops,
+#endif
 	},
 	.probe       = caam_jr_probe,
 	.remove      = caam_jr_remove,
--- linux-ein-5.4.0.orig/drivers/crypto/caam/jr.h
+++ linux-ein-5.4.0/drivers/crypto/caam/jr.h
@@ -3,11 +3,26 @@
  * CAAM public-level include definitions for the JobR backend
  *
  * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2020 NXP
  */
 
 #ifndef JR_H
 #define JR_H
 
+#include <linux/completion.h>
+
+ /**
+  * struct jr_job_result - Job Ring result structure, used for requests
+  *                        that need to run and wait for their completion
+  *
+  * @error               : The result returned after request was executed
+  * @completion          : Structure used to maintain state for a "completion"
+  */
+struct jr_job_result {
+	int error;
+	struct completion completion;
+};
+
 /* Prototypes for backend-level services exposed to APIs */
 struct device *caam_jr_alloc(void);
 void caam_jr_free(struct device *rdev);
@@ -15,5 +30,9 @@
 		    void (*cbk)(struct device *dev, u32 *desc, u32 status,
 				void *areq),
 		    void *areq);
+int caam_jr_run_and_wait_for_completion(struct device *dev, u32 *desc,
+					void (*cbk)(struct device *dev,
+						    u32 *desc, u32 status,
+						    void *areq));
 
 #endif /* JR_H */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/qi.c
+++ linux-ein-5.4.0/drivers/crypto/caam/qi.c
@@ -4,7 +4,7 @@
  * Queue Interface backend functionality
  *
  * Copyright 2013-2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2017, 2019 NXP
+ * Copyright 2016-2017, 2019-2020 NXP
  */
 
 #include <linux/cpumask.h>
@@ -124,8 +124,10 @@
 
 	do {
 		ret = qman_enqueue(req->drv_ctx->req_fq, &fd);
-		if (likely(!ret))
+		if (likely(!ret)) {
+			refcount_inc(&req->drv_ctx->refcnt);
 			return 0;
+		}
 
 		if (ret != -EBUSY)
 			break;
@@ -148,11 +150,6 @@
 
 	fd = &msg->ern.fd;
 
-	if (qm_fd_get_format(fd) != qm_fd_compound) {
-		dev_err(qidev, "Non-compound FD from CAAM\n");
-		return;
-	}
-
 	drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
 	if (!drv_req) {
 		dev_err(qidev,
@@ -160,6 +157,13 @@
 		return;
 	}
 
+	refcount_dec(&drv_req->drv_ctx->refcnt);
+
+	if (qm_fd_get_format(fd) != qm_fd_compound) {
+		dev_err(qidev, "Non-compound FD from CAAM\n");
+		return;
+	}
+
 	dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
 			 sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
 
@@ -287,9 +291,10 @@
 	return ret;
 }
 
-static int empty_caam_fq(struct qman_fq *fq)
+static int empty_caam_fq(struct qman_fq *fq, struct caam_drv_ctx *drv_ctx)
 {
 	int ret;
+	int retries = 10;
 	struct qm_mcr_queryfq_np np;
 
 	/* Wait till the older CAAM FQ get empty */
@@ -304,11 +309,18 @@
 		msleep(20);
 	} while (1);
 
-	/*
-	 * Give extra time for pending jobs from this FQ in holding tanks
-	 * to get processed
-	 */
-	msleep(20);
+	/* Wait until pending jobs from this FQ are processed by CAAM */
+	do {
+		if (refcount_read(&drv_ctx->refcnt) == 1)
+			break;
+
+		msleep(20);
+	} while (--retries);
+
+	if (!retries)
+		dev_warn_once(drv_ctx->qidev, "%d frames from FQID %u still pending in CAAM\n",
+			      refcount_read(&drv_ctx->refcnt), fq->fqid);
+
 	return 0;
 }
 
@@ -340,7 +352,7 @@
 	drv_ctx->req_fq = new_fq;
 
 	/* Empty and remove the older FQ */
-	ret = empty_caam_fq(old_fq);
+	ret = empty_caam_fq(old_fq, drv_ctx);
 	if (ret) {
 		dev_err(qidev, "Old CAAM FQ empty failed: %d\n", ret);
 
@@ -453,6 +465,9 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	/* init reference counter used to track references to request FQ */
+	refcount_set(&drv_ctx->refcnt, 1);
+
 	drv_ctx->qidev = qidev;
 	return drv_ctx;
 }
@@ -500,9 +515,10 @@
 }
 EXPORT_SYMBOL(caam_drv_ctx_rel);
 
-void caam_qi_shutdown(struct device *qidev)
+static void caam_qi_shutdown(void *data)
 {
 	int i;
+	struct device *qidev = data;
 	struct caam_qi_priv *priv = &qipriv;
 	const cpumask_t *cpus = qman_affine_cpus();
 
@@ -570,6 +586,16 @@
 		return qman_cb_dqrr_stop;
 
 	fd = &dqrr->fd;
+
+	drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
+	if (unlikely(!drv_req)) {
+		dev_err(qidev,
+			"Can't find original request for caam response\n");
+		return qman_cb_dqrr_consume;
+	}
+
+	refcount_dec(&drv_req->drv_ctx->refcnt);
+
 	status = be32_to_cpu(fd->status);
 	if (unlikely(status)) {
 		u32 ssrc = status & JRSTA_SSRC_MASK;
@@ -587,13 +613,6 @@
 		return qman_cb_dqrr_consume;
 	}
 
-	drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
-	if (unlikely(!drv_req)) {
-		dev_err(qidev,
-			"Can't find original request for caam response\n");
-		return qman_cb_dqrr_consume;
-	}
-
 	dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
 			 sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
 
@@ -761,7 +780,10 @@
 			    &times_congested, &caam_fops_u64_ro);
 #endif
 
-	ctrlpriv->qi_init = 1;
+	err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv);
+	if (err)
+		return err;
+
 	dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n");
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/crypto/caam/qi.h
+++ linux-ein-5.4.0/drivers/crypto/caam/qi.h
@@ -3,7 +3,7 @@
  * Public definitions for the CAAM/QI (Queue Interface) backend.
  *
  * Copyright 2013-2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2017 NXP
+ * Copyright 2016-2017, 2020 NXP
  */
 
 #ifndef __QI_H__
@@ -52,6 +52,7 @@
  * @context_a: shared descriptor dma address
  * @req_fq: to-CAAM request frame queue
  * @rsp_fq: from-CAAM response frame queue
+ * @refcnt: reference counter incremented for each frame enqueued in to-CAAM FQ
  * @cpu: cpu on which to receive CAAM response
  * @op_type: operation type
  * @qidev: device pointer for CAAM/QI backend
@@ -62,6 +63,7 @@
 	dma_addr_t context_a;
 	struct qman_fq *req_fq;
 	struct qman_fq *rsp_fq;
+	refcount_t refcnt;
 	int cpu;
 	enum optype op_type;
 	struct device *qidev;
@@ -147,7 +149,6 @@
 void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx);
 
 int caam_qi_init(struct platform_device *pdev);
-void caam_qi_shutdown(struct device *dev);
 
 /**
  * qi_cache_alloc - Allocate buffers from CAAM-QI cache
--- linux-ein-5.4.0.orig/drivers/crypto/caam/regs.h
+++ linux-ein-5.4.0/drivers/crypto/caam/regs.h
@@ -173,9 +173,14 @@
 
 static inline u64 cpu_to_caam_dma64(dma_addr_t value)
 {
-	if (caam_imx)
-		return (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) |
-			 (u64)cpu_to_caam32(upper_32_bits(value)));
+	if (caam_imx) {
+		u64 ret_val = (u64)cpu_to_caam32(lower_32_bits(value)) << 32;
+
+		if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
+			ret_val |= (u64)cpu_to_caam32(upper_32_bits(value));
+
+		return ret_val;
+	}
 
 	return cpu_to_caam64(value);
 }
@@ -317,6 +322,9 @@
 /* CHA Miscellaneous Information - AESA_MISC specific */
 #define CHA_VER_MISC_AES_GCM	BIT(1 + CHA_VER_MISC_SHIFT)
 
+/* CHA Miscellaneous Information - PKHA_MISC specific */
+#define CHA_VER_MISC_PKHA_NO_CRYPT	BIT(7 + CHA_VER_MISC_SHIFT)
+
 /*
  * caam_perfmon - Performance Monitor/Secure Memory Status/
  *                CAAM Global Status/Component Version IDs
@@ -377,6 +385,12 @@
 #define CHA_VER_VID_MD_LP512	0x1ull
 #define CHA_VER_VID_MD_HP	0x2ull
 
+/*
+ * caam_perfmon - Performance Monitor/Secure Memory Status/
+ *                CAAM Global Status/Component Version IDs
+ *
+ * Spans f00-fff wherever instantiated
+ */
 struct sec_vid {
 	u16 ip_id;
 	u8 maj_rev;
@@ -407,17 +421,22 @@
 #define CTPR_MS_PG_SZ_SHIFT	4
 	u32 comp_parms_ms;	/* CTPR - Compile Parameters Register	*/
 	u32 comp_parms_ls;	/* CTPR - Compile Parameters Register	*/
-	u64 rsvd1[2];
+	/* Secure Memory State Visibility */
+	u32 rsvd1;
+	u32 smstatus;	/* Secure memory status */
+	u32 rsvd2;
+	u32 smpartown;	/* Secure memory partition owner */
 
 	/* CAAM Global Status					fc0-fdf */
 	u64 faultaddr;	/* FAR  - Fault Address		*/
 	u32 faultliodn;	/* FALR - Fault Address LIODN	*/
 	u32 faultdetail;	/* FADR - Fault Addr Detail	*/
-	u32 rsvd2;
 #define CSTA_PLEND		BIT(10)
 #define CSTA_ALT_PLEND		BIT(18)
+	u32 rsvd3;
 	u32 status;		/* CSTA - CAAM Status */
-	u64 rsvd3;
+	u32 smpart;		/* Secure Memory Partition Parameters */
+	u32 smvid;		/* Secure Memory Version ID */
 
 	/* Component Instantiation Parameters			fe0-fff */
 	u32 rtic_id;		/* RVID - RTIC Version ID	*/
@@ -436,6 +455,62 @@
 	u32 caam_id_ls;		/* CAAMVID - CAAM Version ID LS	*/
 };
 
+#define SMSTATUS_PART_SHIFT	28
+#define SMSTATUS_PART_MASK	(0xf << SMSTATUS_PART_SHIFT)
+#define SMSTATUS_PAGE_SHIFT	16
+#define SMSTATUS_PAGE_MASK	(0x7ff << SMSTATUS_PAGE_SHIFT)
+#define SMSTATUS_MID_SHIFT	8
+#define SMSTATUS_MID_MASK	(0x3f << SMSTATUS_MID_SHIFT)
+#define SMSTATUS_ACCERR_SHIFT	4
+#define SMSTATUS_ACCERR_MASK	(0xf << SMSTATUS_ACCERR_SHIFT)
+#define SMSTATUS_ACCERR_NONE	0
+#define SMSTATUS_ACCERR_ALLOC	1	/* Page not allocated */
+#define SMSTATUS_ACCESS_ID	2	/* Not granted by ID */
+#define SMSTATUS_ACCESS_WRITE	3	/* Writes not allowed */
+#define SMSTATUS_ACCESS_READ	4	/* Reads not allowed */
+#define SMSTATUS_ACCESS_NONKEY	6	/* Non-key reads not allowed */
+#define SMSTATUS_ACCESS_BLOB	9	/* Blob access not allowed */
+#define SMSTATUS_ACCESS_DESCB	10	/* Descriptor Blob access spans pages */
+#define SMSTATUS_ACCESS_NON_SM	11	/* Outside Secure Memory range */
+#define SMSTATUS_ACCESS_XPAGE	12	/* Access crosses pages */
+#define SMSTATUS_ACCESS_INITPG	13	/* Page still initializing */
+#define SMSTATUS_STATE_SHIFT	0
+#define SMSTATUS_STATE_MASK	(0xf << SMSTATUS_STATE_SHIFT)
+#define SMSTATUS_STATE_RESET	0
+#define SMSTATUS_STATE_INIT	1
+#define SMSTATUS_STATE_NORMAL	2
+#define SMSTATUS_STATE_FAIL	3
+
+/* up to 15 rings, 2 bits shifted by ring number */
+#define SMPARTOWN_RING_SHIFT	2
+#define SMPARTOWN_RING_MASK	3
+#define SMPARTOWN_AVAILABLE	0
+#define SMPARTOWN_NOEXIST	1
+#define SMPARTOWN_UNAVAILABLE	2
+#define SMPARTOWN_OURS		3
+
+/* Maximum number of pages possible */
+#define SMPART_MAX_NUMPG_SHIFT	16
+#define SMPART_MAX_NUMPG_MASK	(0x3f << SMPART_MAX_NUMPG_SHIFT)
+
+/* Maximum partition number */
+#define SMPART_MAX_PNUM_SHIFT	12
+#define SMPART_MAX_PNUM_MASK	(0xf << SMPART_MAX_PNUM_SHIFT)
+
+/* Highest possible page number */
+#define SMPART_MAX_PG_SHIFT	0
+#define SMPART_MAX_PG_MASK	(0x3f << SMPART_MAX_PG_SHIFT)
+
+/* Max size of a page */
+#define SMVID_PG_SIZE_SHIFT	16
+#define SMVID_PG_SIZE_MASK	(0x7 << SMVID_PG_SIZE_SHIFT)
+
+/* Major/Minor Version ID */
+#define SMVID_MAJ_VERS_SHIFT	8
+#define SMVID_MAJ_VERS		(0xf << SMVID_MAJ_VERS_SHIFT)
+#define SMVID_MIN_VERS_SHIFT	0
+#define SMVID_MIN_VERS		(0xf << SMVID_MIN_VERS_SHIFT)
+
 /* LIODN programming for DMA configuration */
 #define MSTRID_LOCK_LIODN	0x80000000
 #define MSTRID_LOCK_MAKETRUSTED	0x00010000	/* only for JR masterid */
@@ -446,12 +521,6 @@
 	u32 liodn_ls;	/* LIODN for non-sequence and seq access */
 };
 
-/* Partition ID for DMA configuration */
-struct partid {
-	u32 rsvd1;
-	u32 pidr;	/* partition ID, DECO */
-};
-
 /* RNGB test mode (replicated twice in some configurations) */
 /* Padded out to 0x100 */
 struct rngtst {
@@ -487,7 +556,8 @@
 
 /* RNG4 TRNG test registers */
 struct rng4tst {
-#define RTMCTL_PRGM	0x00010000	/* 1 -> program mode, 0 -> run mode */
+#define RTMCTL_ACC  BIT(5)  /* TRNG access mode */
+#define RTMCTL_PRGM BIT(16) /* 1 -> program mode, 0 -> run mode */
 #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC	0 /* use von Neumann data in
 						     both entropy shifter and
 						     statistical checker */
@@ -564,7 +634,7 @@
 	u32 deco_rsr;			/* DECORSR - Deco Request Source */
 	u32 rsvd11;
 	u32 deco_rq;			/* DECORR - DECO Request */
-	struct partid deco_mid[5];	/* DECOxLIODNR - 1 per DECO */
+	struct masterid deco_mid[5];	/* DECOxLIODNR - 1 per DECO */
 	u32 rsvd5[22];
 
 	/* DECO Availability/Reset Section			120-3ff */
@@ -639,6 +709,35 @@
 #define JRSTART_JR2_START       0x00000004 /* Start Job ring 2 */
 #define JRSTART_JR3_START       0x00000008 /* Start Job ring 3 */
 
+/* Secure Memory Configuration - if you have it */
+/* Secure Memory Register Offset from JR Base Reg*/
+#define SM_V1_OFFSET 0x0f4
+#define SM_V2_OFFSET 0xa00
+
+/* Minimum SM Version ID requiring v2 SM register mapping */
+#define SMVID_V2 0x20105
+
+struct caam_secure_mem_v1 {
+	u32 sm_cmd;	/* SMCJRx - Secure memory command */
+	u32 rsvd1;
+	u32 sm_status;	/* SMCSJRx - Secure memory status */
+	u32 rsvd2;
+
+	u32 sm_perm;	/* SMAPJRx - Secure memory access perms */
+	u32 sm_group2;	/* SMAP2JRx - Secure memory access group 2 */
+	u32 sm_group1;	/* SMAP1JRx - Secure memory access group 1 */
+};
+
+struct caam_secure_mem_v2 {
+	u32 sm_perm;	/* SMAPJRx - Secure memory access perms */
+	u32 sm_group2;	/* SMAP2JRx - Secure memory access group 2 */
+	u32 sm_group1;	/* SMAP1JRx - Secure memory access group 1 */
+	u32 rsvd1[118];
+	u32 sm_cmd;	/* SMCJRx - Secure memory command */
+	u32 rsvd2;
+	u32 sm_status;	/* SMCSJRx - Secure memory status */
+};
+
 /*
  * caam_job_ring - direct job ring setup
  * 1-4 possible per instantiation, base + 1000/2000/3000/4000
@@ -809,6 +908,62 @@
 
 #define JRCR_RESET                  0x01
 
+/* secure memory command */
+#define SMC_PAGE_SHIFT	16
+#define SMC_PAGE_MASK	(0xffff << SMC_PAGE_SHIFT)
+#define SMC_PART_SHIFT	8
+#define SMC_PART_MASK	(0x0f << SMC_PART_SHIFT)
+#define SMC_CMD_SHIFT	0
+#define SMC_CMD_MASK	(0x0f << SMC_CMD_SHIFT)
+
+#define SMC_CMD_ALLOC_PAGE	0x01	/* allocate page to this partition */
+#define SMC_CMD_DEALLOC_PAGE	0x02	/* deallocate page from partition */
+#define SMC_CMD_DEALLOC_PART	0x03	/* deallocate partition */
+#define SMC_CMD_PAGE_INQUIRY	0x05	/* find partition associate with page */
+
+/* secure memory (command) status */
+#define SMCS_PAGE_SHIFT		16
+#define SMCS_PAGE_MASK		(0x0fff << SMCS_PAGE_SHIFT)
+#define SMCS_CMDERR_SHIFT	14
+#define SMCS_CMDERR_MASK	(3 << SMCS_CMDERR_SHIFT)
+#define SMCS_ALCERR_SHIFT	12
+#define SMCS_ALCERR_MASK	(3 << SMCS_ALCERR_SHIFT)
+#define SMCS_PGOWN_SHIFT	6
+#define SMCS_PGWON_MASK		(3 << SMCS_PGOWN_SHIFT)
+#define SMCS_PART_SHIFT		0
+#define SMCS_PART_MASK		(0xf << SMCS_PART_SHIFT)
+
+#define SMCS_CMDERR_NONE	0
+#define SMCS_CMDERR_INCOMP	1	/* Command not yet complete */
+#define SMCS_CMDERR_SECFAIL	2	/* Security failure occurred */
+#define SMCS_CMDERR_OVERFLOW	3	/* Command overflow */
+
+#define SMCS_ALCERR_NONE	0
+#define SMCS_ALCERR_PSPERR	1	/* Partion marked PSP (dealloc only) */
+#define SMCS_ALCERR_PAGEAVAIL	2	/* Page not available */
+#define SMCS_ALCERR_PARTOWN	3	/* Partition ownership error */
+
+#define SMCS_PGOWN_AVAIL	0	/* Page is available */
+#define SMCS_PGOWN_NOEXIST	1	/* Page initializing or nonexistent */
+#define SMCS_PGOWN_NOOWN	2	/* Page owned by another processor */
+#define SMCS_PGOWN_OWNED	3	/* Page belongs to this processor */
+
+/* secure memory access permissions */
+#define SMCS_PERM_KEYMOD_SHIFT	16
+#define SMCA_PERM_KEYMOD_MASK	(0xff << SMCS_PERM_KEYMOD_SHIFT)
+#define SMCA_PERM_CSP_ZERO	0x8000	/* Zero when deallocated or released */
+#define SMCA_PERM_PSP_LOCK	0x4000	/* Part./pages can't be deallocated */
+#define SMCA_PERM_PERM_LOCK	0x2000	/* Lock permissions */
+#define SMCA_PERM_GRP_LOCK	0x1000	/* Lock access groups */
+#define SMCA_PERM_RINGID_SHIFT	10
+#define SMCA_PERM_RINGID_MASK	(3 << SMCA_PERM_RINGID_SHIFT)
+#define SMCA_PERM_G2_BLOB	0x0080	/* Group 2 blob import/export */
+#define SMCA_PERM_G2_WRITE	0x0020	/* Group 2 write */
+#define SMCA_PERM_G2_READ	0x0010	/* Group 2 read */
+#define SMCA_PERM_G1_BLOB	0x0008	/* Group 1... */
+#define SMCA_PERM_G1_WRITE	0x0002
+#define SMCA_PERM_G1_READ	0x0001
+
 /*
  * caam_assurance - Assurance Controller View
  * base + 0x6000 padded out to 0x1000
--- linux-ein-5.4.0.orig/drivers/crypto/caam/secvio.c
+++ linux-ein-5.4.0/drivers/crypto/caam/secvio.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * SNVS Security Violation Handler
+ *
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ */
+
+#include "compat.h"
+#include "secvio.h"
+#include "regs.h"
+#include "intern.h"
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+/* The driver is matched with node caam_snvs to get regmap
+ * It will then retrieve interruption and tamper alarm configuration from
+ * node caam-secvio searching for the compat string "fsl,imx6q-caam-secvio"
+ */
+#define DRIVER_NAME "caam-snvs"
+
+/*
+ * These names are associated with each violation handler.
+ * The source names were taken from MX6, and are based on recommendations
+ * for most common SoCs.
+ */
+static const u8 *violation_src_name[] = {
+	"CAAM Internal Security Violation",
+	"JTAG Alarm",
+	"Watchdog",
+	"(reserved)",
+	"External Boot",
+	"External Tamper Detect",
+};
+
+/* These names help describe security monitor state for the console */
+static const u8 *snvs_ssm_state_name[] = {
+	"init",
+	"hard fail",
+	"(undef:2)",
+	"soft fail",
+	"(undef:4)",
+	"(undef:5)",
+	"(undef:6)",
+	"(undef:7)",
+	"transition",
+	"check",
+	"(undef:10)",
+	"non-secure",
+	"(undef:12)",
+	"trusted",
+	"(undef:14)",
+	"secure",
+};
+
+/* Top-level security violation interrupt */
+static irqreturn_t snvs_secvio_interrupt(int irq, void *snvsdev)
+{
+	struct device *dev = snvsdev;
+	struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+
+	clk_enable(svpriv->clk);
+	/* Check the HP secvio status register */
+	svpriv->irqcause = rd_reg32(&svpriv->svregs->hp.secvio_status) &
+				    HP_SECVIOST_SECVIOMASK;
+
+	if (!svpriv->irqcause) {
+		clk_disable(svpriv->clk);
+		return IRQ_NONE;
+	}
+
+	/* Now ACK cause */
+	clrsetbits_32(&svpriv->svregs->hp.secvio_status, 0, svpriv->irqcause);
+
+	/* And run deferred service */
+	preempt_disable();
+	tasklet_schedule(&svpriv->irqtask[smp_processor_id()]);
+	preempt_enable();
+
+	clk_disable(svpriv->clk);
+
+	return IRQ_HANDLED;
+}
+
+/* Deferred service handler. Tasklet arg is simply the SNVS dev */
+static void snvs_secvio_dispatch(unsigned long indev)
+{
+	struct device *dev = (struct device *)indev;
+	struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+	unsigned long flags;
+	int i;
+
+
+	/* Look through stored causes, call each handler if exists */
+	for (i = 0; i < MAX_SECVIO_SOURCES; i++)
+		if (svpriv->irqcause & (1 << i)) {
+			spin_lock_irqsave(&svpriv->svlock, flags);
+			svpriv->intsrc[i].handler(dev, i,
+						  svpriv->intsrc[i].ext);
+			spin_unlock_irqrestore(&svpriv->svlock, flags);
+		};
+
+	/* Re-enable now-serviced interrupts */
+	clrsetbits_32(&svpriv->svregs->hp.secvio_intcfg, 0, svpriv->irqcause);
+}
+
+/*
+ * Default cause handler, used in lieu of an application-defined handler.
+ * All it does at this time is print a console message. It could force a halt.
+ */
+static void snvs_secvio_default(struct device *dev, u32 cause, void *ext)
+{
+	struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+
+	dev_err(dev, "Unhandled Security Violation Interrupt %d = %s\n",
+		cause, svpriv->intsrc[cause].intname);
+}
+
+/*
+ * Install an application-defined handler for a specified cause
+ * Arguments:
+ * - dev        points to SNVS-owning device
+ * - cause      interrupt source cause
+ * - handler    application-defined handler, gets called with dev
+ *              source cause, and locally-defined handler argument
+ * - cause_description   points to a string to override the default cause
+ *                       name, this can be used as an alternate for error
+ *                       messages and such. If left NULL, the default
+ *                       description string is used.
+ * - ext        pointer to any extra data needed by the handler.
+ */
+int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+				void (*handler)(struct device *dev, u32 cause,
+						void *ext),
+				u8 *cause_description, void *ext)
+{
+	unsigned long flags;
+	struct snvs_secvio_drv_private *svpriv;
+
+	svpriv = dev_get_drvdata(dev);
+
+	if ((handler == NULL) || (cause > SECVIO_CAUSE_SOURCE_5))
+		return -EINVAL;
+
+	spin_lock_irqsave(&svpriv->svlock, flags);
+	svpriv->intsrc[cause].handler = handler;
+	if (cause_description != NULL)
+		svpriv->intsrc[cause].intname = cause_description;
+	if (ext != NULL)
+		svpriv->intsrc[cause].ext = ext;
+	spin_unlock_irqrestore(&svpriv->svlock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(snvs_secvio_install_handler);
+
+/*
+ * Remove an application-defined handler for a specified cause (and, by
+ * implication, restore the "default".
+ * Arguments:
+ * - dev	points to SNVS-owning device
+ * - cause	interrupt source cause
+ */
+int snvs_secvio_remove_handler(struct device *dev, enum secvio_cause cause)
+{
+	unsigned long flags;
+	struct snvs_secvio_drv_private *svpriv;
+
+	svpriv = dev_get_drvdata(dev);
+
+	if (cause > SECVIO_CAUSE_SOURCE_5)
+		return -EINVAL;
+
+	spin_lock_irqsave(&svpriv->svlock, flags);
+	svpriv->intsrc[cause].intname = violation_src_name[cause];
+	svpriv->intsrc[cause].handler = snvs_secvio_default;
+	svpriv->intsrc[cause].ext = NULL;
+	spin_unlock_irqrestore(&svpriv->svlock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(snvs_secvio_remove_handler);
+
+static int snvs_secvio_remove(struct platform_device *pdev)
+{
+	struct device *svdev;
+	struct snvs_secvio_drv_private *svpriv;
+	int i;
+
+	svdev = &pdev->dev;
+	svpriv = dev_get_drvdata(svdev);
+
+	clk_enable(svpriv->clk);
+	/* Set all sources to nonfatal */
+	wr_reg32(&svpriv->svregs->hp.secvio_intcfg, 0);
+
+	/* Remove tasklets and release interrupt */
+	for_each_possible_cpu(i)
+		tasklet_kill(&svpriv->irqtask[i]);
+
+	clk_disable_unprepare(svpriv->clk);
+	free_irq(svpriv->irq, svdev);
+	iounmap(svpriv->svregs);
+	kfree(svpriv);
+
+	return 0;
+}
+
+static int snvs_secvio_probe(struct platform_device *pdev)
+{
+	struct device *svdev;
+	struct snvs_secvio_drv_private *svpriv;
+	struct device_node *np, *npirq;
+	struct snvs_full __iomem *snvsregs;
+	int i, error;
+	u32 hpstate;
+	const void *jtd, *wtd, *itd, *etd;
+	u32 td_en;
+
+	svpriv = kzalloc(sizeof(struct snvs_secvio_drv_private), GFP_KERNEL);
+	if (!svpriv)
+		return -ENOMEM;
+
+	svdev = &pdev->dev;
+	dev_set_drvdata(svdev, svpriv);
+	svpriv->pdev = pdev;
+	np = pdev->dev.of_node;
+
+	npirq = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio");
+	if (!npirq) {
+		dev_err(svdev, "can't find secvio node\n");
+		kfree(svpriv);
+		return -EINVAL;
+	}
+	svpriv->irq = irq_of_parse_and_map(npirq, 0);
+	if (svpriv->irq <= 0) {
+		dev_err(svdev, "can't identify secvio interrupt\n");
+		kfree(svpriv);
+		return -EINVAL;
+	}
+
+	jtd = of_get_property(npirq, "jtag-tamper", NULL);
+	wtd = of_get_property(npirq, "watchdog-tamper", NULL);
+	itd = of_get_property(npirq, "internal-boot-tamper", NULL);
+	etd = of_get_property(npirq, "external-pin-tamper", NULL);
+	if (!jtd | !wtd | !itd | !etd ) {
+		dev_err(svdev, "can't identify all tamper alarm configuration\n");
+		kfree(svpriv);
+		return -EINVAL;
+	}
+
+	/*
+	 * Configure all sources  according to device tree property.
+	 * If the property is enabled then the source is ser as
+	 * fatal violations except LP section,
+	 * source #5 (typically used as an external tamper detect), and
+	 * source #3 (typically unused). Whenever the transition to
+	 * secure mode has occurred, these will now be "fatal" violations
+	 */
+	td_en = HP_SECVIO_INTEN_SRC0;
+	if (!strcmp(jtd, "enabled"))
+		td_en |= HP_SECVIO_INTEN_SRC1;
+	if (!strcmp(wtd, "enabled"))
+		td_en |= HP_SECVIO_INTEN_SRC2;
+	if (!strcmp(itd, "enabled"))
+		td_en |= HP_SECVIO_INTEN_SRC4;
+	if (!strcmp(etd, "enabled"))
+		td_en |= HP_SECVIO_INTEN_SRC5;
+
+	snvsregs = of_iomap(np, 0);
+	if (!snvsregs) {
+		dev_err(svdev, "register mapping failed\n");
+		return -ENOMEM;
+	}
+	svpriv->svregs = (struct snvs_full __force *)snvsregs;
+
+	svpriv->clk = devm_clk_get_optional(&pdev->dev, "ipg");
+	if (IS_ERR(svpriv->clk))
+		return PTR_ERR(svpriv->clk);
+
+	clk_prepare_enable(svpriv->clk);
+
+	/* Write the Secvio Enable Config the SVCR */
+	wr_reg32(&svpriv->svregs->hp.secvio_ctl, td_en);
+	wr_reg32(&svpriv->svregs->hp.secvio_intcfg, td_en);
+
+	 /* Device data set up. Now init interrupt source descriptions */
+	for (i = 0; i < MAX_SECVIO_SOURCES; i++) {
+		svpriv->intsrc[i].intname = violation_src_name[i];
+		svpriv->intsrc[i].handler = snvs_secvio_default;
+	}
+	/* Connect main handler */
+	for_each_possible_cpu(i)
+		tasklet_init(&svpriv->irqtask[i], snvs_secvio_dispatch,
+			     (unsigned long)svdev);
+
+	error = request_irq(svpriv->irq, snvs_secvio_interrupt,
+			    IRQF_SHARED, DRIVER_NAME, svdev);
+	if (error) {
+		dev_err(svdev, "can't connect secvio interrupt\n");
+		irq_dispose_mapping(svpriv->irq);
+		svpriv->irq = 0;
+		iounmap(svpriv->svregs);
+		kfree(svpriv);
+		return -EINVAL;
+	}
+
+	hpstate = (rd_reg32(&svpriv->svregs->hp.status) &
+			    HP_STATUS_SSM_ST_MASK) >> HP_STATUS_SSM_ST_SHIFT;
+	dev_info(svdev, "violation handlers armed - %s state\n",
+		 snvs_ssm_state_name[hpstate]);
+
+	clk_disable(svpriv->clk);
+
+	return 0;
+}
+
+static struct of_device_id snvs_secvio_match[] = {
+	{
+		.compatible = "fsl,imx6q-caam-snvs",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, snvs_secvio_match);
+
+static struct platform_driver snvs_secvio_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = snvs_secvio_match,
+	},
+	.probe       = snvs_secvio_probe,
+	.remove      = snvs_secvio_remove,
+};
+
+module_platform_driver(snvs_secvio_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL SNVS Security Violation Handler");
+MODULE_AUTHOR("Freescale Semiconductor - MCU");
--- linux-ein-5.4.0.orig/drivers/crypto/caam/secvio.h
+++ linux-ein-5.4.0/drivers/crypto/caam/secvio.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * CAAM Security Violation Handler
+ *
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ */
+
+#ifndef SECVIO_H
+#define SECVIO_H
+
+#include "snvsregs.h"
+
+
+/*
+ * Defines the published interfaces to install/remove application-specified
+ * handlers for catching violations
+ */
+
+#define MAX_SECVIO_SOURCES 6
+
+/* these are the untranslated causes */
+enum secvio_cause {
+	SECVIO_CAUSE_SOURCE_0,
+	SECVIO_CAUSE_SOURCE_1,
+	SECVIO_CAUSE_SOURCE_2,
+	SECVIO_CAUSE_SOURCE_3,
+	SECVIO_CAUSE_SOURCE_4,
+	SECVIO_CAUSE_SOURCE_5
+};
+
+/* These are common "recommended" cause definitions for most devices */
+#define SECVIO_CAUSE_CAAM_VIOLATION	SECVIO_CAUSE_SOURCE_0
+#define SECVIO_CAUSE_JTAG_ALARM		SECVIO_CAUSE_SOURCE_1
+#define SECVIO_CAUSE_WATCHDOG		SECVIO_CAUSE_SOURCE_2
+#define SECVIO_CAUSE_EXTERNAL_BOOT	SECVIO_CAUSE_SOURCE_4
+#define SECVIO_CAUSE_TAMPER_DETECT	SECVIO_CAUSE_SOURCE_5
+
+int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+				void (*handler)(struct device *dev, u32 cause,
+						void *ext),
+				u8 *cause_description, void *ext);
+int snvs_secvio_remove_handler(struct device *dev, enum  secvio_cause cause);
+
+/*
+ * Private data definitions for the secvio "driver"
+ */
+
+struct secvio_int_src {
+	const u8 *intname;	/* Points to a descriptive name for source */
+	void *ext;		/* Extended data to pass to the handler */
+	void (*handler)(struct device *dev, u32 cause, void *ext);
+};
+
+struct snvs_secvio_drv_private {
+	struct platform_device *pdev;
+	spinlock_t svlock ____cacheline_aligned;
+	struct tasklet_struct irqtask[NR_CPUS];
+	struct snvs_full __iomem *svregs;	/* both HP and LP domains */
+	struct clk *clk;
+	int irq;
+	u32 irqcause; /* stashed cause of violation interrupt */
+
+	/* Registered handlers for each violation */
+	struct secvio_int_src intsrc[MAX_SECVIO_SOURCES];
+
+};
+
+#endif /* SECVIO_H */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/sm.h
+++ linux-ein-5.4.0/drivers/crypto/caam/sm.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * CAAM Secure Memory/Keywrap API Definitions
+ *
+ * Copyright 2008-2015 Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ */
+
+#ifndef SM_H
+#define SM_H
+
+
+/* Storage access permissions */
+#define SM_PERM_READ 0x01
+#define SM_PERM_WRITE 0x02
+#define SM_PERM_BLOB 0x03
+
+/* Define treatment of secure memory vs. general memory blobs */
+#define SM_SECMEM 0
+#define SM_GENMEM 1
+
+/* Define treatment of red/black keys */
+#define RED_KEY 0
+#define BLACK_KEY 1
+
+/* Define key encryption/covering options */
+#define KEY_COVER_ECB 0	/* cover key in AES-ECB */
+#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
+
+/*
+ * Round a key size up to an AES blocksize boundary so to allow for
+ * padding out to a full block
+ */
+#define AES_BLOCK_PAD(x) ((x % 16) ? ((x >> 4) + 1) << 4 : x)
+
+/* Define space required for BKEK + MAC tag storage in any blob */
+#define BLOB_OVERHEAD (32 + 16)
+
+/* Keystore maintenance functions */
+void sm_init_keystore(struct device *dev);
+u32 sm_detect_keystore_units(struct device *dev);
+int sm_establish_keystore(struct device *dev, u32 unit);
+void sm_release_keystore(struct device *dev, u32 unit);
+int caam_sm_example_init(struct platform_device *pdev);
+
+/* Keystore accessor functions */
+extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size,
+				  u32 *slot);
+extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot);
+extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
+				 const u8 *key_data, u32 key_length);
+extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
+				 u32 key_length, u8 *key_data);
+extern int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+				 u16 key_length, u8 keyauth);
+extern int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot,
+				   u8 keycolor, u8 keyauth, u8 *outbuf,
+				   u16 keylen, u8 *keymod);
+extern int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot,
+				   u8 keycolor, u8 keyauth, u8 *inbuf,
+				   u16 keylen, u8 *keymod);
+
+/* Prior functions from legacy API, deprecated */
+extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit,
+					u32 inslot, u32 outslot, u16 secretlen,
+					u8 *keymod, u16 keymodlen);
+extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit,
+					u32 inslot, u32 outslot, u16 secretlen,
+					u8 *keymod, u16 keymodlen);
+
+/* Data structure to hold per-slot information */
+struct keystore_data_slot_info {
+	u8	allocated;	/* Track slot assignments */
+	u32	key_length;	/* Size of the key */
+};
+
+/* Data structure to hold keystore information */
+struct keystore_data {
+	void	*base_address;	/* Virtual base of secure memory pages */
+	void	*phys_address;	/* Physical base of secure memory pages */
+	u32	slot_count;	/* Number of slots in the keystore */
+	struct keystore_data_slot_info *slot; /* Per-slot information */
+};
+
+/* store the detected attributes of a secure memory page */
+struct sm_page_descriptor {
+	u16 phys_pagenum;	/* may be discontiguous */
+	u16 own_part;		/* Owning partition */
+	void *pg_base;		/* Calculated virtual address */
+	void *pg_phys;		/* Calculated physical address */
+	struct keystore_data *ksdata;
+};
+
+struct caam_drv_private_sm {
+	struct device *parentdev;	/* this ends up as the controller */
+	struct device *smringdev;	/* ring that owns this instance */
+	struct platform_device *sm_pdev;  /* Secure Memory platform device */
+	spinlock_t kslock ____cacheline_aligned;
+
+	/* SM Register offset from JR base address */
+	u32 sm_reg_offset;
+
+	/* Default parameters for geometry */
+	u32 max_pages;		/* maximum pages this instance can support */
+	u32 top_partition;	/* highest partition number in this instance */
+	u32 top_page;		/* highest page number in this instance */
+	u32 page_size;		/* page size */
+	u32 slot_size;		/* selected size of each storage block */
+
+	/* Partition/Page Allocation Map */
+	u32 localpages;		/* Number of pages we can access */
+	struct sm_page_descriptor *pagedesc;	/* Allocated per-page */
+
+	/* Installed handlers for keystore access */
+	int (*data_init)(struct device *dev, u32 unit);
+	void (*data_cleanup)(struct device *dev, u32 unit);
+	int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot);
+	int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot);
+	void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle);
+	void *(*slot_get_physical)(struct device *dev, u32 unit, u32 handle);
+	u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle);
+	u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle);
+	u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle);
+};
+
+#endif /* SM_H */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/sm_store.c
+++ linux-ein-5.4.0/drivers/crypto/caam/sm_store.c
@@ -0,0 +1,1270 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * CAAM Secure Memory Storage Interface
+ *
+ * Copyright 2008-2015 Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ *
+ * Loosely based on the SHW Keystore API for SCC/SCC2
+ * Experimental implementation and NOT intended for upstream use. Expect
+ * this interface to be amended significantly in the future once it becomes
+ * integrated into live applications.
+ *
+ * Known issues:
+ *
+ * - Executes one instance of an secure memory "driver". This is tied to the
+ *   fact that job rings can't run as standalone instances in the present
+ *   configuration.
+ *
+ * - It does not expose a userspace interface. The value of a userspace
+ *   interface for access to secrets is a point for further architectural
+ *   discussion.
+ *
+ * - Partition/permission management is not part of this interface. It
+ *   depends on some level of "knowledge" agreed upon between bootloader,
+ *   provisioning applications, and OS-hosted software (which uses this
+ *   driver).
+ *
+ * - No means of identifying the location or purpose of secrets managed by
+ *   this interface exists; "slot location" and format of a given secret
+ *   needs to be agreed upon between bootloader, provisioner, and OS-hosted
+ *   application.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "jr.h"
+#include "desc.h"
+#include "intern.h"
+#include "error.h"
+#include "sm.h"
+#include <linux/of_address.h>
+
+#define SECMEM_KEYMOD_LEN 8
+#define GENMEM_KEYMOD_LEN 16
+
+#ifdef SM_DEBUG_CONT
+void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	u32 i, *smdata;
+
+	dev_info(dev, "physical page %d content at 0x%08x\n",
+		 pgdesc->phys_pagenum, pgdesc->pg_base);
+	smdata = pgdesc->pg_base;
+	for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4)
+		dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2],
+			 smdata[i+3]);
+}
+#endif
+
+#define INITIAL_DESCSZ 16	/* size of tmp buffer for descriptor const. */
+
+static __always_inline u32 sm_send_cmd(struct caam_drv_private_sm *smpriv,
+					     struct caam_drv_private_jr *jrpriv,
+					     u32 cmd, u32 *status)
+{
+	void __iomem *write_address;
+	void __iomem *read_address;
+
+	if (smpriv->sm_reg_offset == SM_V1_OFFSET) {
+		struct caam_secure_mem_v1 *sm_regs_v1;
+
+		sm_regs_v1 = (struct caam_secure_mem_v1 *)
+			((void *)jrpriv->rregs + SM_V1_OFFSET);
+		write_address = &sm_regs_v1->sm_cmd;
+		read_address = &sm_regs_v1->sm_status;
+
+	} else if (smpriv->sm_reg_offset == SM_V2_OFFSET) {
+		struct caam_secure_mem_v2 *sm_regs_v2;
+
+		sm_regs_v2 = (struct caam_secure_mem_v2 *)
+			((void *)jrpriv->rregs + SM_V2_OFFSET);
+		write_address = &sm_regs_v2->sm_cmd;
+		read_address = &sm_regs_v2->sm_status;
+
+	} else {
+		return -EINVAL;
+	}
+
+	wr_reg32(write_address, cmd);
+
+	udelay(10);
+
+	/* Read until the command has terminated and the status is correct */
+	do {
+		*status = rd_reg32(read_address);
+	} while (((*status & SMCS_CMDERR_MASK) >>  SMCS_CMDERR_SHIFT)
+				   == SMCS_CMDERR_INCOMP);
+
+	return 0;
+}
+
+/*
+ * Construct a black key conversion job descriptor
+ *
+ * This function constructs a job descriptor capable of performing
+ * a key blackening operation on a plaintext secure memory resident object.
+ *
+ * - desc	pointer to a pointer to the descriptor generated by this
+ *		function. Caller will be responsible to kfree() this
+ *		descriptor after execution.
+ * - key	physical pointer to the plaintext, which will also hold
+ *		the result. Since encryption occurs in place, caller must
+ *              ensure that the space is large enough to accommodate the
+ *              blackened key
+ * - keysz	size of the plaintext
+ * - auth	if a CCM-covered key is required, use KEY_COVER_CCM, else
+ *		use KEY_COVER_ECB.
+ *
+ * KEY to key1 from @key_addr LENGTH 16 BYTES;
+ * FIFO STORE from key1[ecb] TO @key_addr LENGTH 16 BYTES;
+ *
+ * Note that this variant uses the JDKEK only; it does not accommodate the
+ * trusted key encryption key at this time.
+ *
+ */
+static int blacken_key_jobdesc(u32 **desc, void *key, u16 keysz, bool auth)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize, idx;
+
+	memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+	idx = 1;
+
+	/* Load key to class 1 key register */
+	tmpdesc[idx++] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+	tmpdesc[idx++] = (uintptr_t)key;
+
+	/* ...and write back out via FIFO store*/
+	tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+
+	/* plus account for ECB/CCM option in FIFO_STORE */
+	if (auth == KEY_COVER_ECB)
+		tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
+	else
+		tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
+
+	idx++;
+	tmpdesc[idx++] = (uintptr_t)key;
+
+	/* finish off the job header */
+	tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+	dsize = idx * sizeof(u32);
+
+	/* now allocate execution buffer and coat it with executable */
+	tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+	if (tdesc == NULL)
+		return 0;
+
+	memcpy(tdesc, tmpdesc, dsize);
+	*desc = tdesc;
+
+	return dsize;
+}
+
+/*
+ * Construct a blob encapsulation job descriptor
+ *
+ * This function dynamically constructs a blob encapsulation job descriptor
+ * from the following arguments:
+ *
+ * - desc	pointer to a pointer to the descriptor generated by this
+ *		function. Caller will be responsible to kfree() this
+ *		descriptor after execution.
+ * - keymod	Physical pointer to a key modifier, which must reside in a
+ *		contiguous piece of memory. Modifier will be assumed to be
+ *		8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
+ *		for a blob of type SM_GENMEM (see blobtype argument).
+ * - secretbuf	Physical pointer to a secret, normally a black or red key,
+ *		possibly residing within an accessible secure memory page,
+ *		of the secret to be encapsulated to an output blob.
+ * - outbuf	Physical pointer to the destination buffer to receive the
+ *		encapsulated output. This buffer will need to be 48 bytes
+ *		larger than the input because of the added encapsulation data.
+ *		The generated descriptor will account for the increase in size,
+ *		but the caller must also account for this increase in the
+ *		buffer allocator.
+ * - secretsz	Size of input secret, in bytes. This is limited to 65536
+ *		less the size of blob overhead, since the length embeds into
+ *		DECO pointer in/out instructions.
+ * - keycolor   Determines if the source data is covered (black key) or
+ *		plaintext (red key). RED_KEY or BLACK_KEY are defined in
+ *		for this purpose.
+ * - blobtype	Determine if encapsulated blob should be a secure memory
+ *		blob (SM_SECMEM), with partition data embedded with key
+ *		material, or a general memory blob (SM_GENMEM).
+ * - auth	If BLACK_KEY source is covered via AES-CCM, specify
+ *		KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job
+ * descriptor which encapsulates data into an externally-storable blob
+ * suitable for use across power cycles.
+ *
+ * This is an example of a black key encapsulation job into a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
+ * the output 48 bytes longer than the input:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400010           ld: ccb2-key len=16 offs=0
+ * [02] 08144891               ptr->@0x08144891
+ * [03] F800003A    seqoutptr: len=58
+ * [04] 01000000               out_ptr->@0x01000000
+ * [05] F000000A     seqinptr: len=10
+ * [06] 09745090               in_ptr->@0x09745090
+ * [07] 870D0004    operation: encap blob  reg=memory, black, format=normal
+ *
+ * This is an example of a red key encapsulation job for storing a red key
+ * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction; this accounts for blob permission storage:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400C08           ld: ccb2-key len=8 offs=12
+ * [02] 087D0784               ptr->@0x087d0784
+ * [03] F8000050    seqoutptr: len=80
+ * [04] 09251BB2               out_ptr->@0x09251bb2
+ * [05] F0000020     seqinptr: len=32
+ * [06] 40000F31               in_ptr->@0x40000f31
+ * [07] 870D0008    operation: encap blob  reg=memory, red, sec_mem,
+ *                             format=normal
+ *
+ * Note: this function only generates 32-bit pointers at present, and should
+ * be refactored using a scheme that allows both 32 and 64 bit addressing
+ */
+
+static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod,
+			      void *secretbuf, dma_addr_t outbuf,
+			      u16 secretsz, u8 keycolor, u8 blobtype, u8 auth)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize, idx;
+
+	memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+	idx = 1;
+
+	/*
+	 * Key modifier works differently for secure/general memory blobs
+	 * This accounts for the permission/protection data encapsulated
+	 * within the blob if a secure memory blob is requested
+	 */
+	if (blobtype == SM_SECMEM)
+		tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+				 LDST_SRCDST_BYTE_KEY |
+				 ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
+				 | (8 & LDST_LEN_MASK);
+	else /* is general memory blob */
+		tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+				 LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
+
+	tmpdesc[idx++] = (u32)keymod;
+
+	/*
+	 * Encapsulation output must include space for blob key encryption
+	 * key and MAC tag
+	 */
+	tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD);
+	tmpdesc[idx++] = (u32)outbuf;
+
+	/* Input data, should be somewhere in secure memory */
+	tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz;
+	tmpdesc[idx++] = (uintptr_t)secretbuf;
+
+	/* Set blob encap, then color */
+	tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
+
+	if (blobtype == SM_SECMEM)
+		tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
+
+	if (auth == KEY_COVER_CCM)
+		tmpdesc[idx] |= OP_PCL_BLOB_EKT;
+
+	if (keycolor == BLACK_KEY)
+		tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
+
+	idx++;
+	tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+	dsize = idx * sizeof(u32);
+
+	tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+	if (tdesc == NULL)
+		return 0;
+
+	memcpy(tdesc, tmpdesc, dsize);
+	*desc = tdesc;
+	return dsize;
+}
+
+/*
+ * Construct a blob decapsulation job descriptor
+ *
+ * This function dynamically constructs a blob decapsulation job descriptor
+ * from the following arguments:
+ *
+ * - desc	pointer to a pointer to the descriptor generated by this
+ *		function. Caller will be responsible to kfree() this
+ *		descriptor after execution.
+ * - keymod	Physical pointer to a key modifier, which must reside in a
+ *		contiguous piece of memory. Modifier will be assumed to be
+ *		8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
+ *		for a blob of type SM_GENMEM (see blobtype argument).
+ * - blobbuf	Physical pointer (into external memory) of the blob to
+ *		be decapsulated. Blob must reside in a contiguous memory
+ *		segment.
+ * - outbuf	Physical pointer of the decapsulated output, possibly into
+ *		a location within a secure memory page. Must be contiguous.
+ * - secretsz	Size of encapsulated secret in bytes (not the size of the
+ *		input blob).
+ * - keycolor   Determines if decapsulated content is encrypted (BLACK_KEY)
+ *		or left as plaintext (RED_KEY).
+ * - blobtype	Determine if encapsulated blob should be a secure memory
+ *		blob (SM_SECMEM), with partition data embedded with key
+ *		material, or a general memory blob (SM_GENMEM).
+ * - auth	If decapsulation path is specified by BLACK_KEY, then if
+ *		AES-CCM is requested for key covering use KEY_COVER_CCM, else
+ *		use AES-ECB (KEY_COVER_ECB).
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job descriptor
+ * that decapsulates a key blob from external memory into a black (encrypted)
+ * key or red (plaintext) content.
+ *
+ * This is an example of a black key decapsulation job from a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction.
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400010           ld: ccb2-key len=16 offs=0
+ * [02] 08A63B7F               ptr->@0x08a63b7f
+ * [03] F8000010    seqoutptr: len=16
+ * [04] 01000000               out_ptr->@0x01000000
+ * [05] F000003A     seqinptr: len=58
+ * [06] 01000010               in_ptr->@0x01000010
+ * [07] 860D0004    operation: decap blob  reg=memory, black, format=normal
+ *
+ * This is an example of a red key decapsulation job for restoring a red key
+ * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction:
+ *
+ * [00] B0800008       jobhdr: stidx=0 len=8
+ * [01] 14400C08           ld: ccb2-key len=8 offs=12
+ * [02] 01000000               ptr->@0x01000000
+ * [03] F8000020    seqoutptr: len=32
+ * [04] 400000E6               out_ptr->@0x400000e6
+ * [05] F0000050     seqinptr: len=80
+ * [06] 08F0C0EA               in_ptr->@0x08f0c0ea
+ * [07] 860D0008    operation: decap blob  reg=memory, red, sec_mem,
+ *			       format=normal
+ *
+ * Note: this function only generates 32-bit pointers at present, and should
+ * be refactored using a scheme that allows both 32 and 64 bit addressing
+ */
+
+static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf,
+			      u8 *outbuf, u16 secretsz, u8 keycolor,
+			      u8 blobtype, u8 auth)
+{
+	u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+	u16 dsize, idx;
+
+	memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+	idx = 1;
+
+	/* Load key modifier */
+	if (blobtype == SM_SECMEM)
+		tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+				 LDST_SRCDST_BYTE_KEY |
+				 ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
+				 | (8 & LDST_LEN_MASK);
+	else /* is general memory blob */
+		tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+				 LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
+
+	tmpdesc[idx++] = (u32)keymod;
+
+	/* Compensate BKEK + MAC tag over size of encapsulated secret */
+	tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD);
+	tmpdesc[idx++] = (u32)blobbuf;
+	tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz;
+	tmpdesc[idx++] = (uintptr_t)outbuf;
+
+	/* Decapsulate from secure memory partition to black blob */
+	tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
+
+	if (blobtype == SM_SECMEM)
+		tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
+
+	if (auth == KEY_COVER_CCM)
+		tmpdesc[idx] |= OP_PCL_BLOB_EKT;
+
+	if (keycolor == BLACK_KEY)
+		tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
+
+	idx++;
+	tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+	dsize = idx * sizeof(u32);
+
+	tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+	if (tdesc == NULL)
+		return 0;
+
+	memcpy(tdesc, tmpdesc, dsize);
+	*desc = tdesc;
+	return dsize;
+}
+
+/*
+ * Pseudo-synchronous ring access functions for carrying out key
+ * encapsulation and decapsulation
+ */
+
+struct sm_key_job_result {
+	int error;
+	struct completion completion;
+};
+
+void sm_key_job_done(struct device *dev, u32 *desc, u32 err, void *context)
+{
+	struct sm_key_job_result *res = context;
+
+	if (err)
+		caam_jr_strstatus(dev, err);
+
+	res->error = err;	/* save off the error for postprocessing */
+
+	complete(&res->completion);	/* mark us complete */
+}
+
+static int sm_key_job(struct device *ksdev, u32 *jobdesc)
+{
+	struct sm_key_job_result testres = {0};
+	struct caam_drv_private_sm *kspriv;
+	int rtn = 0;
+
+	kspriv = dev_get_drvdata(ksdev);
+
+	init_completion(&testres.completion);
+
+	rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done,
+			      &testres);
+	if (rtn)
+		goto exit;
+
+	wait_for_completion_interruptible(&testres.completion);
+	rtn = testres.error;
+
+exit:
+	return rtn;
+}
+
+/*
+ * Following section establishes the default methods for keystore access
+ * They are NOT intended for use external to this module
+ *
+ * In the present version, these are the only means for the higher-level
+ * interface to deal with the mechanics of accessing the phyiscal keystore
+ */
+
+
+int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+	u32 i;
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size);
+#endif
+
+	if (size > smpriv->slot_size)
+		return -EKEYREJECTED;
+
+	for (i = 0; i < ksdata->slot_count; i++) {
+		if (ksdata->slot[i].allocated == 0) {
+			ksdata->slot[i].allocated = 1;
+			(*slot) = i;
+#ifdef SM_DEBUG
+			dev_info(dev, "slot_alloc(): new slot %d allocated\n",
+				 *slot);
+#endif
+			return 0;
+		}
+	}
+
+	return -ENOSPC;
+}
+EXPORT_SYMBOL(slot_alloc);
+
+int slot_dealloc(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+	u8 __iomem *slotdata;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot);
+#endif
+	if (slot >= ksdata->slot_count)
+		return -EINVAL;
+	slotdata = ksdata->base_address + slot * smpriv->slot_size;
+
+	if (ksdata->slot[slot].allocated == 1) {
+		/* Forcibly overwrite the data from the keystore */
+		memset_io(ksdata->base_address + slot * smpriv->slot_size, 0,
+		       smpriv->slot_size);
+
+		ksdata->slot[slot].allocated = 0;
+#ifdef SM_DEBUG
+		dev_info(dev, "slot_dealloc(): slot %d released\n", slot);
+#endif
+		return 0;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(slot_dealloc);
+
+void *slot_get_address(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+	if (slot >= ksdata->slot_count)
+		return NULL;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_get_address(): slot %d is 0x%08x\n", slot,
+		 (u32)ksdata->base_address + slot * smpriv->slot_size);
+#endif
+
+	return ksdata->base_address + slot * smpriv->slot_size;
+}
+
+void *slot_get_physical(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+	if (slot >= ksdata->slot_count)
+		return NULL;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "%s: slot %d is 0x%08x\n", __func__, slot,
+		 (u32)ksdata->phys_address + slot * smpriv->slot_size);
+#endif
+
+	return ksdata->phys_address + slot * smpriv->slot_size;
+}
+
+u32 slot_get_base(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+	/*
+	 * There could potentially be more than one secure partition object
+	 * associated with this keystore.  For now, there is just one.
+	 */
+
+	(void)slot;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n",
+		slot, (u32)ksdata->base_address);
+#endif
+
+	return (uintptr_t)(ksdata->base_address);
+}
+
+u32 slot_get_offset(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+	if (slot >= ksdata->slot_count)
+		return -EINVAL;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot,
+		slot * smpriv->slot_size);
+#endif
+
+	return slot * smpriv->slot_size;
+}
+
+u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+
+#ifdef SM_DEBUG
+	dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot,
+		 smpriv->slot_size);
+#endif
+	/* All slots are the same size in the default implementation */
+	return smpriv->slot_size;
+}
+
+
+
+int kso_init_data(struct device *dev, u32 unit)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *keystore_data = NULL;
+	u32 slot_count;
+	u32 keystore_data_size;
+
+	/*
+	 * Calculate the required size of the keystore data structure, based
+	 * on the number of keys that can fit in the partition.
+	 */
+	slot_count = smpriv->page_size / smpriv->slot_size;
+#ifdef SM_DEBUG
+	dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count);
+#endif
+
+	keystore_data_size = sizeof(struct keystore_data) +
+				slot_count *
+				sizeof(struct keystore_data_slot_info);
+
+	keystore_data = kzalloc(keystore_data_size, GFP_KERNEL);
+
+	if (!keystore_data)
+		return -ENOMEM;
+
+#ifdef SM_DEBUG
+	dev_info(dev, "kso_init_data: keystore data size = %d\n",
+		 keystore_data_size);
+#endif
+
+	/*
+	 * Place the slot information structure directly after the keystore data
+	 * structure.
+	 */
+	keystore_data->slot = (struct keystore_data_slot_info *)
+			      (keystore_data + 1);
+	keystore_data->slot_count = slot_count;
+
+	smpriv->pagedesc[unit].ksdata = keystore_data;
+	smpriv->pagedesc[unit].ksdata->base_address =
+		smpriv->pagedesc[unit].pg_base;
+	smpriv->pagedesc[unit].ksdata->phys_address =
+		smpriv->pagedesc[unit].pg_phys;
+
+	return 0;
+}
+
+void kso_cleanup_data(struct device *dev, u32 unit)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	struct keystore_data *keystore_data = NULL;
+
+	if (smpriv->pagedesc[unit].ksdata != NULL)
+		keystore_data = smpriv->pagedesc[unit].ksdata;
+
+	/* Release the allocated keystore management data */
+	kfree(smpriv->pagedesc[unit].ksdata);
+
+	return;
+}
+
+
+
+/*
+ * Keystore management section
+ */
+
+void sm_init_keystore(struct device *dev)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+	smpriv->data_init = kso_init_data;
+	smpriv->data_cleanup = kso_cleanup_data;
+	smpriv->slot_alloc = slot_alloc;
+	smpriv->slot_dealloc = slot_dealloc;
+	smpriv->slot_get_address = slot_get_address;
+	smpriv->slot_get_physical = slot_get_physical;
+	smpriv->slot_get_base = slot_get_base;
+	smpriv->slot_get_offset = slot_get_offset;
+	smpriv->slot_get_slot_size = slot_get_slot_size;
+#ifdef SM_DEBUG
+	dev_info(dev, "sm_init_keystore(): handlers installed\n");
+#endif
+}
+EXPORT_SYMBOL(sm_init_keystore);
+
+/* Return available pages/units */
+u32 sm_detect_keystore_units(struct device *dev)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+	return smpriv->localpages;
+}
+EXPORT_SYMBOL(sm_detect_keystore_units);
+
+/*
+ * Do any keystore specific initializations
+ */
+int sm_establish_keystore(struct device *dev, u32 unit)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+	dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit);
+#endif
+
+	if (smpriv->data_init == NULL)
+		return -EINVAL;
+
+	/* Call the data_init function for any user setup */
+	return smpriv->data_init(dev, unit);
+}
+EXPORT_SYMBOL(sm_establish_keystore);
+
+void sm_release_keystore(struct device *dev, u32 unit)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+	dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit);
+#endif
+	if ((smpriv != NULL) && (smpriv->data_cleanup != NULL))
+		smpriv->data_cleanup(dev, unit);
+
+	return;
+}
+EXPORT_SYMBOL(sm_release_keystore);
+
+/*
+ * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to
+ * the keystore
+ */
+int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = -EINVAL;
+
+	spin_lock(&smpriv->kslock);
+
+	if ((smpriv->slot_alloc == NULL) ||
+	    (smpriv->pagedesc[unit].ksdata == NULL))
+		goto out;
+
+	retval =  smpriv->slot_alloc(dev, unit, size, slot);
+
+out:
+	spin_unlock(&smpriv->kslock);
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_alloc);
+
+int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = -EINVAL;
+
+	spin_lock(&smpriv->kslock);
+
+	if ((smpriv->slot_alloc == NULL) ||
+	    (smpriv->pagedesc[unit].ksdata == NULL))
+		goto out;
+
+	retval = smpriv->slot_dealloc(dev, unit, slot);
+out:
+	spin_unlock(&smpriv->kslock);
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_dealloc);
+
+int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
+			  const u8 *key_data, u32 key_length)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = -EINVAL;
+	u32 slot_size;
+	u8 __iomem *slot_location;
+
+	spin_lock(&smpriv->kslock);
+
+	slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+	if (key_length > slot_size) {
+		retval = -EFBIG;
+		goto out;
+	}
+
+	slot_location = smpriv->slot_get_address(dev, unit, slot);
+
+	memcpy_toio(slot_location, key_data, key_length);
+
+	retval = 0;
+
+out:
+	spin_unlock(&smpriv->kslock);
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_load);
+
+int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
+			  u32 key_length, u8 *key_data)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = -EINVAL;
+	u8 __iomem *slot_addr;
+	u32 slot_size;
+
+	spin_lock(&smpriv->kslock);
+
+	slot_addr = smpriv->slot_get_address(dev, unit, slot);
+	slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+	if (key_length > slot_size) {
+		retval = -EKEYREJECTED;
+		goto out;
+	}
+
+	memcpy_fromio(key_data, slot_addr, key_length);
+	retval = 0;
+
+out:
+	spin_unlock(&smpriv->kslock);
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_read);
+
+/*
+ * Blacken a clear key in a slot. Operates "in place".
+ * Limited to class 1 keys at the present time
+ */
+int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+			  u16 key_length, u8 keyauth)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = 0;
+	u8 __iomem *slotaddr;
+	void *slotphys;
+	u32 dsize, jstat;
+	u32 __iomem *coverdesc = NULL;
+
+	/* Get the address of the object in the slot */
+	slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+	slotphys = (u8 *)smpriv->slot_get_physical(dev, unit, slot);
+
+	dsize = blacken_key_jobdesc(&coverdesc, slotphys, key_length, keyauth);
+	if (!dsize)
+		return -ENOMEM;
+	jstat = sm_key_job(dev, coverdesc);
+	if (jstat)
+		retval = -EIO;
+
+	kfree(coverdesc);
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_cover_key);
+
+/* Export a black/red key to a blob in external memory */
+int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+			    u8 keyauth, u8 *outbuf, u16 keylen, u8 *keymod)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = 0;
+	u8 __iomem *slotaddr, *lkeymod;
+	u8 __iomem *slotphys;
+	dma_addr_t keymod_dma, outbuf_dma;
+	u32 dsize, jstat;
+	u32 __iomem *encapdesc = NULL;
+	struct device *dev_for_dma_op;
+
+	/* Use the ring as device for DMA operations */
+	dev_for_dma_op = smpriv->smringdev;
+
+	/* Get the base address(es) of the specified slot */
+	slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+	slotphys = smpriv->slot_get_physical(dev, unit, slot);
+
+	/* Allocate memory for key modifier compatible with DMA */
+	lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+	if (!lkeymod) {
+		retval = (-ENOMEM);
+		goto exit;
+	}
+
+	/* Get DMA address for the key modifier */
+	keymod_dma = dma_map_single(dev_for_dma_op, lkeymod,
+					SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev_for_dma_op, keymod_dma)) {
+		dev_err(dev, "unable to map keymod: %p\n", lkeymod);
+		retval = (-ENOMEM);
+		goto free_keymod;
+	}
+
+	/* Copy the keymod and synchronize the DMA */
+	memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+	dma_sync_single_for_device(dev_for_dma_op, keymod_dma,
+					SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+
+	/* Get DMA address for the destination */
+	outbuf_dma = dma_map_single(dev_for_dma_op, outbuf,
+				keylen + BLOB_OVERHEAD, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev_for_dma_op, outbuf_dma)) {
+		dev_err(dev, "unable to map outbuf: %p\n", outbuf);
+		retval = (-ENOMEM);
+		goto unmap_keymod;
+	}
+
+	/* Build the encapsulation job descriptor */
+	dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, slotphys, outbuf_dma,
+				   keylen, keycolor, SM_SECMEM, keyauth);
+	if (!dsize) {
+		dev_err(dev, "can't alloc an encapsulation descriptor\n");
+		retval = -ENOMEM;
+		goto unmap_outbuf;
+	}
+
+	/* Run the job */
+	jstat = sm_key_job(dev, encapdesc);
+	if (jstat) {
+		retval = (-EIO);
+		goto free_desc;
+	}
+
+	/* Synchronize the data received */
+	dma_sync_single_for_cpu(dev_for_dma_op, outbuf_dma,
+			keylen + BLOB_OVERHEAD, DMA_FROM_DEVICE);
+
+free_desc:
+	kfree(encapdesc);
+
+unmap_outbuf:
+	dma_unmap_single(dev_for_dma_op, outbuf_dma, keylen + BLOB_OVERHEAD,
+			DMA_FROM_DEVICE);
+
+unmap_keymod:
+	dma_unmap_single(dev_for_dma_op, keymod_dma, SECMEM_KEYMOD_LEN,
+			DMA_TO_DEVICE);
+
+free_keymod:
+	kfree(lkeymod);
+
+exit:
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_export);
+
+/* Import a black/red key from a blob residing in external memory */
+int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+			    u8 keyauth, u8 *inbuf, u16 keylen, u8 *keymod)
+{
+	struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+	int retval = 0;
+	u8 __iomem *slotaddr, *lkeymod;
+	u8 __iomem *slotphys;
+	dma_addr_t keymod_dma, inbuf_dma;
+	u32 dsize, jstat;
+	u32 __iomem *decapdesc = NULL;
+	struct device *dev_for_dma_op;
+
+	/* Use the ring as device for DMA operations */
+	dev_for_dma_op = smpriv->smringdev;
+
+	/* Get the base address(es) of the specified slot */
+	slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+	slotphys = smpriv->slot_get_physical(dev, unit, slot);
+
+	/* Allocate memory for key modifier compatible with DMA */
+	lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+	if (!lkeymod) {
+		retval = (-ENOMEM);
+		goto exit;
+	}
+
+	/* Get DMA address for the key modifier */
+	keymod_dma = dma_map_single(dev_for_dma_op, lkeymod,
+					SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev_for_dma_op, keymod_dma)) {
+		dev_err(dev, "unable to map keymod: %p\n", lkeymod);
+		retval = (-ENOMEM);
+		goto free_keymod;
+	}
+
+	/* Copy the keymod and synchronize the DMA */
+	memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+	dma_sync_single_for_device(dev_for_dma_op, keymod_dma,
+					SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+
+	/* Get DMA address for the input */
+	inbuf_dma = dma_map_single(dev_for_dma_op, inbuf,
+					keylen + BLOB_OVERHEAD, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev_for_dma_op, inbuf_dma)) {
+		dev_err(dev, "unable to map inbuf: %p\n", (void *)inbuf_dma);
+		retval = (-ENOMEM);
+		goto unmap_keymod;
+	}
+
+	/* synchronize the DMA */
+	dma_sync_single_for_device(dev_for_dma_op, inbuf_dma,
+					keylen + BLOB_OVERHEAD, DMA_TO_DEVICE);
+
+	/* Build the encapsulation job descriptor */
+	dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, inbuf_dma, slotphys,
+				   keylen, keycolor, SM_SECMEM, keyauth);
+	if (!dsize) {
+		dev_err(dev, "can't alloc a decapsulation descriptor\n");
+		retval = -ENOMEM;
+		goto unmap_inbuf;
+	}
+
+	/* Run the job */
+	jstat = sm_key_job(dev, decapdesc);
+
+	/*
+	 * May want to expand upon error meanings a bit. Any CAAM status
+	 * is reported as EIO, but we might want to look for something more
+	 * meaningful for something like an ICV error on restore, otherwise
+	 * the caller is left guessing.
+	 */
+	if (jstat) {
+		retval = (-EIO);
+		goto free_desc;
+	}
+
+free_desc:
+	kfree(decapdesc);
+
+unmap_inbuf:
+	dma_unmap_single(dev_for_dma_op, inbuf_dma, keylen + BLOB_OVERHEAD,
+			DMA_TO_DEVICE);
+
+unmap_keymod:
+	dma_unmap_single(dev_for_dma_op, keymod_dma, SECMEM_KEYMOD_LEN,
+			DMA_TO_DEVICE);
+
+free_keymod:
+	kfree(lkeymod);
+
+exit:
+	return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_import);
+
+/*
+ * Initialization/shutdown subsystem
+ * Assumes statically-invoked startup/shutdown from the controller driver
+ * for the present time, to be reworked when a device tree becomes
+ * available. This code will not modularize in present form.
+ *
+ * Also, simply uses ring 0 for execution at the present
+ */
+
+int caam_sm_startup(struct device *ctrldev)
+{
+	struct device *smdev;
+	struct caam_drv_private *ctrlpriv;
+	struct caam_drv_private_sm *smpriv;
+	struct caam_drv_private_jr *jrpriv;	/* need this for reg page */
+	struct platform_device *sm_pdev;
+	struct sm_page_descriptor *lpagedesc;
+	u32 page, pgstat, lpagect, detectedpage, smvid, smpart;
+	int ret = 0;
+
+	struct device_node *np;
+	ctrlpriv = dev_get_drvdata(ctrldev);
+
+	if (!ctrlpriv->sm_present)
+		return 0;
+
+	/*
+	 * Set up the private block for secure memory
+	 * Only one instance is possible
+	 */
+	smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL);
+	if (smpriv == NULL) {
+		dev_err(ctrldev, "can't alloc private mem for secure memory\n");
+		ret = -ENOMEM;
+		goto exit;
+	}
+	smpriv->parentdev = ctrldev; /* copy of parent dev is handy */
+	spin_lock_init(&smpriv->kslock);
+
+	/* Create the dev */
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+	if (np)
+		of_node_clear_flag(np, OF_POPULATED);
+	sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev);
+
+	if (sm_pdev == NULL) {
+		ret = -EINVAL;
+		goto free_smpriv;
+	}
+
+	/* Save a pointer to the platform device for Secure Memory */
+	smpriv->sm_pdev = sm_pdev;
+	smdev = &sm_pdev->dev;
+	dev_set_drvdata(smdev, smpriv);
+	ctrlpriv->smdev = smdev;
+
+	/* Set the Secure Memory Register Map Version */
+	smvid = rd_reg32(&ctrlpriv->jr[0]->perfmon.smvid);
+	smpart = rd_reg32(&ctrlpriv->jr[0]->perfmon.smpart);
+
+	if (smvid < SMVID_V2)
+		smpriv->sm_reg_offset = SM_V1_OFFSET;
+	else
+		smpriv->sm_reg_offset = SM_V2_OFFSET;
+
+	/*
+	 * Collect configuration limit data for reference
+	 * This batch comes from the partition data/vid registers in perfmon
+	 */
+	smpriv->max_pages = ((smpart & SMPART_MAX_NUMPG_MASK) >>
+			    SMPART_MAX_NUMPG_SHIFT) + 1;
+	smpriv->top_partition = ((smpart & SMPART_MAX_PNUM_MASK) >>
+				SMPART_MAX_PNUM_SHIFT) + 1;
+	smpriv->top_page =  ((smpart & SMPART_MAX_PG_MASK) >>
+				SMPART_MAX_PG_SHIFT) + 1;
+	smpriv->page_size = 1024 << ((smvid & SMVID_PG_SIZE_MASK) >>
+				SMVID_PG_SIZE_SHIFT);
+	smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE;
+
+#ifdef SM_DEBUG
+	dev_info(smdev, "max pages = %d, top partition = %d\n",
+			smpriv->max_pages, smpriv->top_partition);
+	dev_info(smdev, "top page = %d, page size = %d (total = %d)\n",
+			smpriv->top_page, smpriv->page_size,
+			smpriv->top_page * smpriv->page_size);
+	dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size);
+#endif
+
+	/*
+	 * Now probe for partitions/pages to which we have access. Note that
+	 * these have likely been set up by a bootloader or platform
+	 * provisioning application, so we have to assume that we "inherit"
+	 * a configuration and work within the constraints of what it might be.
+	 *
+	 * Assume use of the zeroth ring in the present iteration (until
+	 * we can divorce the controller and ring drivers, and then assign
+	 * an SM instance to any ring instance).
+	 */
+	smpriv->smringdev = caam_jr_alloc();
+	if (!smpriv->smringdev) {
+		dev_err(smdev, "Device for job ring not created\n");
+		ret = -ENODEV;
+		goto unregister_smpdev;
+	}
+
+	jrpriv = dev_get_drvdata(smpriv->smringdev);
+	lpagect = 0;
+	pgstat = 0;
+	lpagedesc = kzalloc(sizeof(struct sm_page_descriptor)
+			    * smpriv->max_pages, GFP_KERNEL);
+	if (lpagedesc == NULL) {
+		ret = -ENOMEM;
+		goto free_smringdev;
+	}
+
+	for (page = 0; page < smpriv->max_pages; page++) {
+		u32 page_ownership;
+
+		if (sm_send_cmd(smpriv, jrpriv,
+				((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) |
+				(SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK),
+				&pgstat)) {
+			ret = -EINVAL;
+			goto free_lpagedesc;
+		}
+
+		page_ownership = (pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT;
+		if ((page_ownership == SMCS_PGOWN_OWNED)
+			|| (page_ownership == SMCS_PGOWN_NOOWN)) {
+			/* page allocated */
+			lpagedesc[page].phys_pagenum =
+				(pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT;
+			lpagedesc[page].own_part =
+				(pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK;
+			lpagedesc[page].pg_base = (u8 *)ctrlpriv->sm_base +
+				(smpriv->page_size * page);
+			if (ctrlpriv->scu_en) {
+/* FIXME: get different addresses viewed by CPU and CAAM from
+ * platform property
+ */
+				lpagedesc[page].pg_phys = (u8 *)0x20800000 +
+					(smpriv->page_size * page);
+			} else {
+				lpagedesc[page].pg_phys =
+					(u8 *) ctrlpriv->sm_phy +
+					(smpriv->page_size * page);
+			}
+			lpagect++;
+#ifdef SM_DEBUG
+			dev_info(smdev,
+				"physical page %d, owning partition = %d\n",
+				lpagedesc[page].phys_pagenum,
+				lpagedesc[page].own_part);
+#endif
+		}
+	}
+
+	smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect,
+				   GFP_KERNEL);
+	if (smpriv->pagedesc == NULL) {
+		ret = -ENOMEM;
+		goto free_lpagedesc;
+	}
+	smpriv->localpages = lpagect;
+
+	detectedpage = 0;
+	for (page = 0; page < smpriv->max_pages; page++) {
+		if (lpagedesc[page].pg_base != NULL) {	/* e.g. live entry */
+			memcpy(&smpriv->pagedesc[detectedpage],
+			       &lpagedesc[page],
+			       sizeof(struct sm_page_descriptor));
+#ifdef SM_DEBUG_CONT
+			sm_show_page(smdev, &smpriv->pagedesc[detectedpage]);
+#endif
+			detectedpage++;
+		}
+	}
+
+	kfree(lpagedesc);
+
+	sm_init_keystore(smdev);
+
+	goto exit;
+
+free_lpagedesc:
+	kfree(lpagedesc);
+free_smringdev:
+	caam_jr_free(smpriv->smringdev);
+unregister_smpdev:
+	of_device_unregister(smpriv->sm_pdev);
+free_smpriv:
+	kfree(smpriv);
+
+exit:
+	return ret;
+}
+
+void caam_sm_shutdown(struct device *ctrldev)
+{
+	struct device *smdev;
+	struct caam_drv_private *priv;
+	struct caam_drv_private_sm *smpriv;
+
+	priv = dev_get_drvdata(ctrldev);
+	if (!priv->sm_present)
+		return;
+
+	smdev = priv->smdev;
+
+	/* Return if resource not initialized by startup */
+	if (smdev == NULL)
+		return;
+
+	smpriv = dev_get_drvdata(smdev);
+
+	caam_jr_free(smpriv->smringdev);
+
+	/* Remove Secure Memory Platform Device */
+	of_device_unregister(smpriv->sm_pdev);
+
+	kfree(smpriv->pagedesc);
+	kfree(smpriv);
+}
+EXPORT_SYMBOL(caam_sm_shutdown);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/sm_test.c
+++ linux-ein-5.4.0/drivers/crypto/caam/sm_test.c
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Secure Memory / Keystore Exemplification Module
+ *
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ *
+ * This module has been overloaded as an example to show:
+ * - Secure memory subsystem initialization/shutdown
+ * - Allocation/deallocation of "slots" in a secure memory page
+ * - Loading and unloading of key material into slots
+ * - Covering of secure memory objects into "black keys" (ECB only at present)
+ * - Verification of key covering (by differentiation only)
+ * - Exportation of keys into secure memory blobs (with display of result)
+ * - Importation of keys from secure memory blobs (with display of result)
+ * - Verification of re-imported keys where possible.
+ *
+ * The module does not show the use of key objects as working key register
+ * source material at this time.
+ *
+ * This module can use a substantial amount of refactoring, which may occur
+ * after the API gets some mileage. Furthermore, expect this module to
+ * eventually disappear once the API is integrated into "real" software.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "desc.h"
+#include "error.h"
+#include "jr.h"
+#include "sm.h"
+
+/* Fixed known pattern for a key modifier */
+static u8 skeymod[] = {
+	0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+	0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+};
+
+/* Fixed known pattern for a key */
+static u8 clrkey[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static void key_display(struct device *dev, const char *label, u16 size,
+			u8 *key)
+{
+	unsigned i;
+
+	dev_dbg(dev, "%s", label);
+	for (i = 0; i < size; i += 8)
+		dev_dbg(dev,
+			"[%04d] %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			i, key[i], key[i + 1], key[i + 2], key[i + 3],
+			key[i + 4], key[i + 5], key[i + 6], key[i + 7]);
+}
+
+int caam_sm_example_init(struct platform_device *pdev)
+{
+	struct device *ctrldev, *ksdev;
+	struct caam_drv_private *ctrlpriv;
+	struct caam_drv_private_sm *kspriv;
+	u32 unit, units;
+	int rtnval;
+	u8 clrkey8[8], clrkey16[16], clrkey24[24], clrkey32[32];
+	u8 blkkey8[AES_BLOCK_PAD(8)], blkkey16[AES_BLOCK_PAD(16)];
+	u8 blkkey24[AES_BLOCK_PAD(24)], blkkey32[AES_BLOCK_PAD(32)];
+	u8 rstkey8[AES_BLOCK_PAD(8)], rstkey16[AES_BLOCK_PAD(16)];
+	u8 rstkey24[AES_BLOCK_PAD(24)], rstkey32[AES_BLOCK_PAD(32)];
+	u8 __iomem *blob8, *blob16, *blob24, *blob32;
+	u32 keyslot8, keyslot16, keyslot24, keyslot32 = 0;
+
+	blob8 = blob16 = blob24 = blob32 = NULL;
+
+	/*
+	 * 3.5.x and later revs for MX6 should be able to ditch this
+	 * and detect via dts property
+	 */
+	ctrldev = &pdev->dev;
+	ctrlpriv = dev_get_drvdata(ctrldev);
+
+	/*
+	 * If ctrlpriv is NULL, it's probably because the caam driver wasn't
+	 * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
+	 */
+	if (!ctrlpriv)
+		return -ENODEV;
+
+	ksdev = ctrlpriv->smdev;
+	kspriv = dev_get_drvdata(ksdev);
+	if (kspriv == NULL)
+		return -ENODEV;
+
+	/* What keystores are available ? */
+	units = sm_detect_keystore_units(ksdev);
+	if (!units)
+		dev_err(ksdev, "blkkey_ex: no keystore units available\n");
+
+	/*
+	 * MX6 bootloader stores some stuff in unit 0, so let's
+	 * use 1 or above
+	 */
+	if (units < 2) {
+		dev_err(ksdev, "blkkey_ex: insufficient keystore units\n");
+		return -ENODEV;
+	}
+	unit = 1;
+
+	dev_info(ksdev, "blkkey_ex: %d keystore units available\n", units);
+
+	/* Initialize/Establish Keystore */
+	sm_establish_keystore(ksdev, unit);	/* Initalize store in #1 */
+
+	/*
+	 * Now let's set up buffers for blobs in DMA-able memory. All are
+	 * larger than need to be so that blob size can be seen.
+	 */
+	blob8 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+	blob16 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+	blob24 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+	blob32 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+
+	if ((blob8 == NULL) || (blob16 == NULL) || (blob24 == NULL) ||
+	    (blob32 == NULL)) {
+		rtnval = -ENOMEM;
+		dev_err(ksdev, "blkkey_ex: can't get blob buffers\n");
+		goto freemem;
+	}
+
+	/* Initialize clear keys with a known and recognizable pattern */
+	memcpy(clrkey8, clrkey, 8);
+	memcpy(clrkey16, clrkey, 16);
+	memcpy(clrkey24, clrkey, 24);
+	memcpy(clrkey32, clrkey, 32);
+
+	memset(blkkey8, 0, AES_BLOCK_PAD(8));
+	memset(blkkey16, 0, AES_BLOCK_PAD(16));
+	memset(blkkey24, 0, AES_BLOCK_PAD(24));
+	memset(blkkey32, 0, AES_BLOCK_PAD(32));
+
+	memset(rstkey8, 0, AES_BLOCK_PAD(8));
+	memset(rstkey16, 0, AES_BLOCK_PAD(16));
+	memset(rstkey24, 0, AES_BLOCK_PAD(24));
+	memset(rstkey32, 0, AES_BLOCK_PAD(32));
+
+	/*
+	 * Allocate keyslots. Since we're going to blacken keys in-place,
+	 * we want slots big enough to pad out to the next larger AES blocksize
+	 * so pad them out.
+	 */
+	rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(8),
+					&keyslot8);
+	if (rtnval)
+		goto freemem;
+
+	rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(16),
+					&keyslot16);
+	if (rtnval)
+		goto dealloc_slot8;
+
+	rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(24),
+					&keyslot24);
+	if (rtnval)
+		goto dealloc_slot16;
+
+	rtnval = sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(32),
+					&keyslot32);
+	if (rtnval)
+		goto dealloc_slot24;
+
+
+	/* Now load clear key data into the newly allocated slots */
+	rtnval = sm_keystore_slot_load(ksdev, unit, keyslot8, clrkey8, 8);
+	if (rtnval)
+		goto dealloc;
+
+	rtnval = sm_keystore_slot_load(ksdev, unit, keyslot16, clrkey16, 16);
+	if (rtnval)
+		goto dealloc;
+
+	rtnval = sm_keystore_slot_load(ksdev, unit, keyslot24, clrkey24, 24);
+	if (rtnval)
+		goto dealloc;
+
+	rtnval = sm_keystore_slot_load(ksdev, unit, keyslot32, clrkey32, 32);
+	if (rtnval)
+		goto dealloc;
+
+	/*
+	 * All cleartext keys are loaded into slots (in an unprotected
+	 * partition at this time)
+	 *
+	 * Cover keys in-place
+	 */
+	rtnval = sm_keystore_cover_key(ksdev, unit, keyslot8, 8, KEY_COVER_ECB);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't cover 64-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_cover_key(ksdev, unit, keyslot16, 16,
+				       KEY_COVER_ECB);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't cover 128-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_cover_key(ksdev, unit, keyslot24, 24,
+				       KEY_COVER_ECB);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't cover 192-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_cover_key(ksdev, unit, keyslot32, 32,
+				       KEY_COVER_ECB);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't cover 256-bit key\n");
+		goto dealloc;
+	}
+
+	/*
+	 * Keys should be covered and appear sufficiently "random"
+	 * as a result of the covering (blackening) process. Assuming
+	 * non-secure mode, read them back out for examination; they should
+	 * appear as random data, completely differing from the clear
+	 * inputs. So, this will read them back from secure memory and
+	 * compare them. If they match the clear key, then the covering
+	 * operation didn't occur.
+	 */
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
+				       blkkey8);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't read 64-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot16,
+				       AES_BLOCK_PAD(16), blkkey16);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't read 128-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot24,
+				       AES_BLOCK_PAD(24), blkkey24);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't read 192-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot32,
+				       AES_BLOCK_PAD(32), blkkey32);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't read 256-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = -EINVAL;
+	if (!memcmp(blkkey8, clrkey8, 8)) {
+		dev_err(ksdev, "blkkey_ex: 64-bit key cover failed\n");
+		goto dealloc;
+	}
+
+	if (!memcmp(blkkey16, clrkey16, 16)) {
+		dev_err(ksdev, "blkkey_ex: 128-bit key cover failed\n");
+		goto dealloc;
+	}
+
+	if (!memcmp(blkkey24, clrkey24, 24)) {
+		dev_err(ksdev, "blkkey_ex: 192-bit key cover failed\n");
+		goto dealloc;
+	}
+
+	if (!memcmp(blkkey32, clrkey32, 32)) {
+		dev_err(ksdev, "blkkey_ex: 256-bit key cover failed\n");
+		goto dealloc;
+	}
+
+
+	key_display(ksdev, "64-bit clear key:", 8, clrkey8);
+	key_display(ksdev, "64-bit black key:", AES_BLOCK_PAD(8), blkkey8);
+
+	key_display(ksdev, "128-bit clear key:", 16, clrkey16);
+	key_display(ksdev, "128-bit black key:", AES_BLOCK_PAD(16), blkkey16);
+
+	key_display(ksdev, "192-bit clear key:", 24, clrkey24);
+	key_display(ksdev, "192-bit black key:", AES_BLOCK_PAD(24), blkkey24);
+
+	key_display(ksdev, "256-bit clear key:", 32, clrkey32);
+	key_display(ksdev, "256-bit black key:", AES_BLOCK_PAD(32), blkkey32);
+
+	/*
+	 * Now encapsulate all keys as SM blobs out to external memory
+	 * Blobs will appear as random-looking blocks of data different
+	 * from the original source key, and 48 bytes longer than the
+	 * original key, to account for the extra data encapsulated within.
+	 */
+	key_display(ksdev, "64-bit unwritten blob:", 96, blob8);
+	key_display(ksdev, "128-bit unwritten blob:", 96, blob16);
+	key_display(ksdev, "196-bit unwritten blob:", 96, blob24);
+	key_display(ksdev, "256-bit unwritten blob:", 96, blob32);
+
+	rtnval = sm_keystore_slot_export(ksdev, unit, keyslot8, BLACK_KEY,
+					 KEY_COVER_ECB, blob8, 8, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't encapsulate 64-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_export(ksdev, unit, keyslot16, BLACK_KEY,
+					 KEY_COVER_ECB, blob16, 16, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't encapsulate 128-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_export(ksdev, unit, keyslot24, BLACK_KEY,
+					 KEY_COVER_ECB, blob24, 24, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't encapsulate 192-bit key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_export(ksdev, unit, keyslot32, BLACK_KEY,
+					 KEY_COVER_ECB, blob32, 32, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't encapsulate 256-bit key\n");
+		goto dealloc;
+	}
+
+	key_display(ksdev, "64-bit black key in blob:", 96, blob8);
+	key_display(ksdev, "128-bit black key in blob:", 96, blob16);
+	key_display(ksdev, "192-bit black key in blob:", 96, blob24);
+	key_display(ksdev, "256-bit black key in blob:", 96, blob32);
+
+	/*
+	 * Now re-import black keys from secure-memory blobs stored
+	 * in general memory from the previous operation. Since we are
+	 * working with black keys, and since power has not cycled, the
+	 * restored black keys should match the original blackened keys
+	 * (this would not be true if the blobs were save in some non-volatile
+	 * store, and power was cycled between the save and restore)
+	 */
+	rtnval = sm_keystore_slot_import(ksdev, unit, keyslot8, BLACK_KEY,
+					 KEY_COVER_ECB, blob8, 8, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't decapsulate 64-bit blob\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_import(ksdev, unit, keyslot16, BLACK_KEY,
+					 KEY_COVER_ECB, blob16, 16, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't decapsulate 128-bit blob\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_import(ksdev, unit, keyslot24, BLACK_KEY,
+					 KEY_COVER_ECB, blob24, 24, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't decapsulate 196-bit blob\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_import(ksdev, unit, keyslot32, BLACK_KEY,
+					 KEY_COVER_ECB, blob32, 32, skeymod);
+	if (rtnval) {
+		dev_err(ksdev, "blkkey_ex: can't decapsulate 256-bit blob\n");
+		goto dealloc;
+	}
+
+
+	/*
+	 * Blobs are now restored as black keys. Read those black keys back
+	 * for a comparison with the original black key, they should match
+	 */
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
+				       rstkey8);
+	if (rtnval) {
+		dev_err(ksdev,
+			"blkkey_ex: can't read restored 64-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot16,
+				       AES_BLOCK_PAD(16), rstkey16);
+	if (rtnval) {
+		dev_err(ksdev,
+			"blkkey_ex: can't read restored 128-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot24,
+				       AES_BLOCK_PAD(24), rstkey24);
+	if (rtnval) {
+		dev_err(ksdev,
+			"blkkey_ex: can't read restored 196-bit black key\n");
+		goto dealloc;
+	}
+
+	rtnval = sm_keystore_slot_read(ksdev, unit, keyslot32,
+				       AES_BLOCK_PAD(32), rstkey32);
+	if (rtnval) {
+		dev_err(ksdev,
+			"blkkey_ex: can't read restored 256-bit black key\n");
+		goto dealloc;
+	}
+
+	key_display(ksdev, "restored 64-bit black key:", AES_BLOCK_PAD(8),
+		    rstkey8);
+	key_display(ksdev, "restored 128-bit black key:", AES_BLOCK_PAD(16),
+		    rstkey16);
+	key_display(ksdev, "restored 192-bit black key:", AES_BLOCK_PAD(24),
+		    rstkey24);
+	key_display(ksdev, "restored 256-bit black key:", AES_BLOCK_PAD(32),
+		    rstkey32);
+
+	/*
+	 * Compare the restored black keys with the original blackened keys
+	 * As long as we're operating within the same power cycle, a black key
+	 * restored from a blob should match the original black key IF the
+	 * key happens to be of a size that matches a multiple of the AES
+	 * blocksize. Any key that is padded to fill the block size will not
+	 * match, excepting a key that exceeds a block; only the first full
+	 * blocks will match (assuming ECB).
+	 *
+	 * Therefore, compare the 16 and 32 bit keys, they should match.
+	 * The 24 bit key can only match within the first 16 byte block.
+	 */
+
+	if (memcmp(rstkey16, blkkey16, AES_BLOCK_PAD(16))) {
+		dev_err(ksdev, "blkkey_ex: 128-bit restored key mismatch\n");
+		rtnval = -EINVAL;
+	}
+
+	/* Only first AES block will match, remainder subject to padding */
+	if (memcmp(rstkey24, blkkey24, 16)) {
+		dev_err(ksdev, "blkkey_ex: 192-bit restored key mismatch\n");
+		rtnval = -EINVAL;
+	}
+
+	if (memcmp(rstkey32, blkkey32, AES_BLOCK_PAD(32))) {
+		dev_err(ksdev, "blkkey_ex: 256-bit restored key mismatch\n");
+		rtnval = -EINVAL;
+	}
+
+
+	/* Remove keys from keystore */
+dealloc:
+	sm_keystore_slot_dealloc(ksdev, unit, keyslot32);
+dealloc_slot24:
+	sm_keystore_slot_dealloc(ksdev, unit, keyslot24);
+dealloc_slot16:
+	sm_keystore_slot_dealloc(ksdev, unit, keyslot16);
+dealloc_slot8:
+	sm_keystore_slot_dealloc(ksdev, unit, keyslot8);
+
+	/* Free resources */
+freemem:
+	kfree(blob8);
+	kfree(blob16);
+	kfree(blob24);
+	kfree(blob32);
+
+	/* Disconnect from keystore and leave */
+	sm_release_keystore(ksdev, unit);
+
+	return rtnval;
+}
+EXPORT_SYMBOL(caam_sm_example_init);
+
+void caam_sm_example_shutdown(void)
+{
+	/* unused in present version */
+	struct device_node *dev_node;
+	struct platform_device *pdev;
+
+	/*
+	 * Do of_find_compatible_node() then of_find_device_by_node()
+	 * once a functional device tree is available
+	 */
+	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return;
+	}
+
+	pdev = of_find_device_by_node(dev_node);
+	if (!pdev)
+		return;
+
+	of_node_get(dev_node);
+
+}
+
+static int __init caam_sm_test_init(void)
+{
+	struct device_node *dev_node;
+	struct platform_device *pdev;
+	struct caam_drv_private *priv;
+	int ret;
+
+	/*
+	 * Do of_find_compatible_node() then of_find_device_by_node()
+	 * once a functional device tree is available
+	 */
+	dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+	if (!dev_node) {
+		dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+		if (!dev_node)
+			return -ENODEV;
+	}
+
+	pdev = of_find_device_by_node(dev_node);
+	if (!pdev)
+		return -ENODEV;
+
+	of_node_put(dev_node);
+
+	priv = dev_get_drvdata(&pdev->dev);
+	if (!priv) {
+		dev_info(&pdev->dev, "SM driver not ready, aborting tests\n");
+		return -ENODEV;
+	}
+	if (!priv->sm_present) {
+		dev_info(&pdev->dev, "No SM support, skipping tests\n");
+		return -ENODEV;
+	}
+
+	ret = caam_sm_example_init(pdev);
+	if (ret)
+		dev_err(&pdev->dev, "SM test failed: %d\n", ret);
+	else
+		dev_info(&pdev->dev, "SM test passed\n");
+
+	return ret;
+}
+
+
+/* Module-based initialization needs to wait for dev tree */
+#ifdef CONFIG_OF
+module_init(caam_sm_test_init);
+module_exit(caam_sm_example_shutdown);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM Black Key Usage Example");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+#endif
--- linux-ein-5.4.0.orig/drivers/crypto/caam/snvsregs.h
+++ linux-ein-5.4.0/drivers/crypto/caam/snvsregs.h
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * SNVS hardware register-level view
+ *
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ */
+
+#ifndef SNVSREGS_H
+#define SNVSREGS_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * SNVS High Power Domain
+ * Includes security violations, HA counter, RTC, alarm
+ */
+struct snvs_hp {
+	u32 lock;		/* HPLR - HP Lock */
+	u32 cmd;		/* HPCOMR - HP Command */
+	u32 ctl;		/* HPCR - HP Control */
+	u32 secvio_intcfg;	/* HPSICR - Security Violation Int Config */
+	u32 secvio_ctl;		/* HPSVCR - Security Violation Control */
+	u32 status;		/* HPSR - HP Status */
+	u32 secvio_status;	/* HPSVSR - Security Violation Status */
+	u32 ha_counteriv;	/* High Assurance Counter IV */
+	u32 ha_counter;		/* High Assurance Counter */
+	u32 rtc_msb;		/* Real Time Clock/Counter MSB */
+	u32 rtc_lsb;		/* Real Time Counter LSB */
+	u32 time_alarm_msb;	/* Time Alarm MSB */
+	u32 time_alarm_lsb;	/* Time Alarm LSB */
+};
+
+#define HP_LOCK_HAC_LCK		0x00040000
+#define HP_LOCK_HPSICR_LCK	0x00020000
+#define HP_LOCK_HPSVCR_LCK	0x00010000
+#define HP_LOCK_MKEYSEL_LCK	0x00000200
+#define HP_LOCK_TAMPCFG_LCK	0x00000100
+#define HP_LOCK_TAMPFLT_LCK	0x00000080
+#define HP_LOCK_SECVIO_LCK	0x00000040
+#define HP_LOCK_GENP_LCK	0x00000020
+#define HP_LOCK_MONOCTR_LCK	0x00000010
+#define HP_LOCK_CALIB_LCK	0x00000008
+#define HP_LOCK_SRTC_LCK	0x00000004
+#define HP_LOCK_ZMK_RD_LCK	0x00000002
+#define HP_LOCK_ZMK_WT_LCK	0x00000001
+
+#define HP_CMD_NONPRIV_AXS	0x80000000
+#define HP_CMD_HAC_STOP		0x00080000
+#define HP_CMD_HAC_CLEAR	0x00040000
+#define HP_CMD_HAC_LOAD		0x00020000
+#define HP_CMD_HAC_CFG_EN	0x00010000
+#define HP_CMD_SNVS_MSTR_KEY	0x00002000
+#define HP_CMD_PROG_ZMK		0x00001000
+#define HP_CMD_SW_LPSV		0x00000400
+#define HP_CMD_SW_FSV		0x00000200
+#define HP_CMD_SW_SV		0x00000100
+#define HP_CMD_LP_SWR_DIS	0x00000020
+#define HP_CMD_LP_SWR		0x00000010
+#define HP_CMD_SSM_SFNS_DIS	0x00000004
+#define HP_CMD_SSM_ST_DIS	0x00000002
+#define HP_CMD_SMM_ST		0x00000001
+
+#define HP_CTL_TIME_SYNC	0x00010000
+#define HP_CTL_CAL_VAL_SHIFT	10
+#define HP_CTL_CAL_VAL_MASK	(0x1f << HP_CTL_CALIB_SHIFT)
+#define HP_CTL_CALIB_EN		0x00000100
+#define HP_CTL_PI_FREQ_SHIFT	4
+#define HP_CTL_PI_FREQ_MASK	(0xf << HP_CTL_PI_FREQ_SHIFT)
+#define HP_CTL_PI_EN		0x00000008
+#define HP_CTL_TIMEALARM_EN	0x00000002
+#define HP_CTL_RTC_EN		0x00000001
+
+#define HP_SECVIO_INTEN_EN	0x10000000
+#define HP_SECVIO_INTEN_SRC5	0x00000020
+#define HP_SECVIO_INTEN_SRC4	0x00000010
+#define HP_SECVIO_INTEN_SRC3	0x00000008
+#define HP_SECVIO_INTEN_SRC2	0x00000004
+#define HP_SECVIO_INTEN_SRC1	0x00000002
+#define HP_SECVIO_INTEN_SRC0	0x00000001
+#define HP_SECVIO_INTEN_ALL	0x8000003f
+
+#define HP_SECVIO_ICTL_CFG_SHIFT	30
+#define HP_SECVIO_ICTL_CFG_MASK		(0x3 << HP_SECVIO_ICTL_CFG_SHIFT)
+#define HP_SECVIO_ICTL_CFG5_SHIFT	5
+#define HP_SECVIO_ICTL_CFG5_MASK	(0x3 << HP_SECVIO_ICTL_CFG5_SHIFT)
+#define HP_SECVIO_ICTL_CFG_DISABLE	0
+#define HP_SECVIO_ICTL_CFG_NONFATAL	1
+#define HP_SECVIO_ICTL_CFG_FATAL	2
+#define HP_SECVIO_ICTL_CFG4_FATAL	0x00000010
+#define HP_SECVIO_ICTL_CFG3_FATAL	0x00000008
+#define HP_SECVIO_ICTL_CFG2_FATAL	0x00000004
+#define HP_SECVIO_ICTL_CFG1_FATAL	0x00000002
+#define HP_SECVIO_ICTL_CFG0_FATAL	0x00000001
+
+#define HP_STATUS_ZMK_ZERO		0x80000000
+#define HP_STATUS_OTPMK_ZERO		0x08000000
+#define HP_STATUS_OTPMK_SYN_SHIFT	16
+#define HP_STATUS_OTPMK_SYN_MASK	(0x1ff << HP_STATUS_OTPMK_SYN_SHIFT)
+#define HP_STATUS_SSM_ST_SHIFT		8
+#define HP_STATUS_SSM_ST_MASK		(0xf << HP_STATUS_SSM_ST_SHIFT)
+#define HP_STATUS_SSM_ST_INIT		0
+#define HP_STATUS_SSM_ST_HARDFAIL	1
+#define HP_STATUS_SSM_ST_SOFTFAIL	3
+#define HP_STATUS_SSM_ST_INITINT	8
+#define HP_STATUS_SSM_ST_CHECK		9
+#define HP_STATUS_SSM_ST_NONSECURE	11
+#define HP_STATUS_SSM_ST_TRUSTED	13
+#define HP_STATUS_SSM_ST_SECURE		15
+
+#define HP_SECVIOST_ZMK_ECC_FAIL	0x08000000	/* write to clear */
+#define HP_SECVIOST_ZMK_SYN_SHIFT	16
+#define HP_SECVIOST_ZMK_SYN_MASK	(0x1ff << HP_SECVIOST_ZMK_SYN_SHIFT)
+#define HP_SECVIOST_SECVIO5		0x00000020
+#define HP_SECVIOST_SECVIO4		0x00000010
+#define HP_SECVIOST_SECVIO3		0x00000008
+#define HP_SECVIOST_SECVIO2		0x00000004
+#define HP_SECVIOST_SECVIO1		0x00000002
+#define HP_SECVIOST_SECVIO0		0x00000001
+#define HP_SECVIOST_SECVIOMASK		0x0000003f
+
+/*
+ * SNVS Low Power Domain
+ * Includes glitch detector, SRTC, alarm, monotonic counter, ZMK
+ */
+struct snvs_lp {
+	u32 lock;
+	u32 ctl;
+	u32 mstr_key_ctl;	/* Master Key Control */
+	u32 secvio_ctl;		/* Security Violation Control */
+	u32 tamper_filt_cfg;	/* Tamper Glitch Filters Configuration */
+	u32 tamper_det_cfg;	/* Tamper Detectors Configuration */
+	u32 status;
+	u32 srtc_msb;		/* Secure Real Time Clock/Counter MSB */
+	u32 srtc_lsb;		/* Secure Real Time Clock/Counter LSB */
+	u32 time_alarm;		/* Time Alarm */
+	u32 smc_msb;		/* Secure Monotonic Counter MSB */
+	u32 smc_lsb;		/* Secure Monotonic Counter LSB */
+	u32 pwr_glitch_det;	/* Power Glitch Detector */
+	u32 gen_purpose;
+	u32 zmk[8];		/* Zeroizable Master Key */
+};
+
+#define LP_LOCK_MKEYSEL_LCK	0x00000200
+#define LP_LOCK_TAMPDET_LCK	0x00000100
+#define LP_LOCK_TAMPFLT_LCK	0x00000080
+#define LP_LOCK_SECVIO_LCK	0x00000040
+#define LP_LOCK_GENP_LCK	0x00000020
+#define LP_LOCK_MONOCTR_LCK	0x00000010
+#define LP_LOCK_CALIB_LCK	0x00000008
+#define LP_LOCK_SRTC_LCK	0x00000004
+#define LP_LOCK_ZMK_RD_LCK	0x00000002
+#define LP_LOCK_ZMK_WT_LCK	0x00000001
+
+#define LP_CTL_CAL_VAL_SHIFT	10
+#define LP_CTL_CAL_VAL_MASK	(0x1f << LP_CTL_CAL_VAL_SHIFT)
+#define LP_CTL_CALIB_EN		0x00000100
+#define LP_CTL_SRTC_INVAL_EN	0x00000010
+#define LP_CTL_WAKE_INT_EN	0x00000008
+#define LP_CTL_MONOCTR_EN	0x00000004
+#define LP_CTL_TIMEALARM_EN	0x00000002
+#define LP_CTL_SRTC_EN		0x00000001
+
+#define LP_MKEYCTL_ZMKECC_SHIFT	8
+#define LP_MKEYCTL_ZMKECC_MASK	(0xff << LP_MKEYCTL_ZMKECC_SHIFT)
+#define LP_MKEYCTL_ZMKECC_EN	0x00000010
+#define LP_MKEYCTL_ZMKECC_VAL	0x00000008
+#define LP_MKEYCTL_ZMKECC_PROG	0x00000004
+#define LP_MKEYCTL_MKSEL_SHIFT	0
+#define LP_MKEYCTL_MKSEL_MASK	(3 << LP_MKEYCTL_MKSEL_SHIFT)
+#define LP_MKEYCTL_MK_OTP	0
+#define LP_MKEYCTL_MK_ZMK	2
+#define LP_MKEYCTL_MK_COMB	3
+
+#define LP_SECVIO_CTL_SRC5	0x20
+#define LP_SECVIO_CTL_SRC4	0x10
+#define LP_SECVIO_CTL_SRC3	0x08
+#define LP_SECVIO_CTL_SRC2	0x04
+#define LP_SECVIO_CTL_SRC1	0x02
+#define LP_SECVIO_CTL_SRC0	0x01
+
+#define LP_TAMPFILT_EXT2_EN	0x80000000
+#define LP_TAMPFILT_EXT2_SHIFT	24
+#define LP_TAMPFILT_EXT2_MASK	(0x1f << LP_TAMPFILT_EXT2_SHIFT)
+#define LP_TAMPFILT_EXT1_EN	0x00800000
+#define LP_TAMPFILT_EXT1_SHIFT	16
+#define LP_TAMPFILT_EXT1_MASK	(0x1f << LP_TAMPFILT_EXT1_SHIFT)
+#define LP_TAMPFILT_WM_EN	0x00000080
+#define LP_TAMPFILT_WM_SHIFT	0
+#define LP_TAMPFILT_WM_MASK	(0x1f << LP_TAMPFILT_WM_SHIFT)
+
+#define LP_TAMPDET_OSC_BPS	0x10000000
+#define LP_TAMPDET_VRC_SHIFT	24
+#define LP_TAMPDET_VRC_MASK	(3 << LP_TAMPFILT_VRC_SHIFT)
+#define LP_TAMPDET_HTDC_SHIFT	20
+#define LP_TAMPDET_HTDC_MASK	(3 << LP_TAMPFILT_HTDC_SHIFT)
+#define LP_TAMPDET_LTDC_SHIFT	16
+#define LP_TAMPDET_LTDC_MASK	(3 << LP_TAMPFILT_LTDC_SHIFT)
+#define LP_TAMPDET_POR_OBS	0x00008000
+#define LP_TAMPDET_PFD_OBS	0x00004000
+#define LP_TAMPDET_ET2_EN	0x00000400
+#define LP_TAMPDET_ET1_EN	0x00000200
+#define LP_TAMPDET_WMT2_EN	0x00000100
+#define LP_TAMPDET_WMT1_EN	0x00000080
+#define LP_TAMPDET_VT_EN	0x00000040
+#define LP_TAMPDET_TT_EN	0x00000020
+#define LP_TAMPDET_CT_EN	0x00000010
+#define LP_TAMPDET_MCR_EN	0x00000004
+#define LP_TAMPDET_SRTCR_EN	0x00000002
+
+#define LP_STATUS_SECURE
+#define LP_STATUS_NONSECURE
+#define LP_STATUS_SCANEXIT	0x00100000	/* all write 1 clear here on */
+#define LP_STATUS_EXT_SECVIO	0x00010000
+#define LP_STATUS_ET2		0x00000400
+#define LP_STATUS_ET1		0x00000200
+#define LP_STATUS_WMT2		0x00000100
+#define LP_STATUS_WMT1		0x00000080
+#define LP_STATUS_VTD		0x00000040
+#define LP_STATUS_TTD		0x00000020
+#define LP_STATUS_CTD		0x00000010
+#define LP_STATUS_PGD		0x00000008
+#define LP_STATUS_MCR		0x00000004
+#define LP_STATUS_SRTCR		0x00000002
+#define LP_STATUS_LPTA		0x00000001
+
+/* Full SNVS register page, including version/options */
+struct snvs_full {
+	struct snvs_hp hp;
+	struct snvs_lp lp;
+	u32 rsvd[731];		/* deadspace 0x08c-0xbf7 */
+
+	/* Version / Revision / Option ID space - end of register page */
+	u32 vid;		/* 0xbf8 HP Version ID (VID 1) */
+	u32 opt_rev;		/* 0xbfc HP Options / Revision (VID 2) */
+};
+
+#endif /* SNVSREGS_H */
--- linux-ein-5.4.0.orig/drivers/crypto/caam/tag_object.c
+++ linux-ein-5.4.0/drivers/crypto/caam/tag_object.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include "tag_object.h"
+#include "desc.h"
+
+/**
+ * is_key_type -	Check if the object is a key
+ *
+ * @type:		The object type
+ *
+ * Return:		True if the object is a key (of black or red color),
+ *			false otherwise
+ */
+bool is_key_type(u32 type)
+{
+	/* Check type bitfield from object type */
+	return ((type >> TAG_OBJ_TYPE_OFFSET) & TAG_OBJ_TYPE_MASK) == 0;
+}
+EXPORT_SYMBOL(is_key_type);
+
+/**
+ * is_trusted_type -	Check if the object is a trusted key
+ *			Trusted Descriptor Key Encryption Key (TDKEK)
+ *
+ * @type:		The object type
+ *
+ * Return:		True if the object is a trusted key,
+ *			false otherwise
+ */
+bool is_trusted_type(u32 type)
+{
+	/* Check type bitfield from object type */
+	return ((type >> TAG_OBJ_TK_OFFSET) & TAG_OBJ_TK_MASK) == 1;
+}
+EXPORT_SYMBOL(is_trusted_type);
+
+/**
+ * is_black_key -	Check if the tag object header is a black key
+ * @header:		The tag object header configuration
+ *
+ * Return:		True if is a black key, false otherwise
+ */
+bool is_black_key(const struct header_conf *header)
+{
+	u32 type = header->type;
+	/* Check type and color bitfields from tag object type */
+	return (type & (BIT(TAG_OBJ_COLOR_OFFSET) |
+			BIT(TAG_OBJ_TYPE_OFFSET))) == BIT(TAG_OBJ_COLOR_OFFSET);
+}
+EXPORT_SYMBOL(is_black_key);
+
+/**
+ * is_valid_header_conf - Check if the header configuration is valid
+ * @header:		The header configuration
+ *
+ * Return:		True if the header of the tag object configuration,
+ *			has the TAG_OBJECT_MAGIC number and a valid type,
+ *			false otherwise
+ */
+bool is_valid_header_conf(const struct header_conf *header)
+{
+	return (header->_magic_number == TAG_OBJECT_MAGIC);
+}
+EXPORT_SYMBOL(is_valid_header_conf);
+
+/**
+ * get_key_conf -	Retrieve the key configuration,
+ *			meaning the length of the black key and
+ *			the KEY command parameters needed for CAAM
+ * @header:		The tag object header configuration
+ * @red_key_len:	Red key length
+ * @obj_len:		Black/Red key/blob length
+ * @load_param:		Load parameters for KEY command:
+ *			- indicator for encrypted keys: plaintext or black
+ *			- indicator for encryption mode: AES-ECB or AES-CCM
+ *			- indicator for encryption keys: JDKEK or TDKEK
+ */
+void get_key_conf(const struct header_conf *header,
+		  u32 *red_key_len, u32 *obj_len, u32 *load_param)
+{
+	*red_key_len = header->red_key_len;
+	*obj_len = header->obj_len;
+	/* Based on the color of the key, set key encryption bit (ENC) */
+	*load_param = ((header->type >> TAG_OBJ_COLOR_OFFSET) &
+		       TAG_OBJ_COLOR_MASK) << KEY_ENC_OFFSET;
+	/*
+	 * For red keys, the TK and EKT bits are ignored.
+	 * So we set them anyway, to be valid when the key is black.
+	 */
+	*load_param |= ((header->type >> TAG_OBJ_TK_OFFSET) &
+			 TAG_OBJ_TK_MASK) << KEY_TK_OFFSET;
+	*load_param |= ((header->type >> TAG_OBJ_EKT_OFFSET) &
+			 TAG_OBJ_EKT_MASK) << KEY_EKT_OFFSET;
+}
+EXPORT_SYMBOL(get_key_conf);
+
+/**
+ * init_tag_object_header - Initialize the tag object header by setting up
+ *			the TAG_OBJECT_MAGIC number, tag object version,
+ *			a valid type and the object's length
+ * @header:		The header configuration to initialize
+ * @version:		The tag object version
+ * @type:		The tag object type
+ * @red_key_len:	The red key length
+ * @obj_len:		The object (actual data) length
+ */
+void init_tag_object_header(struct header_conf *header, u32 version,
+			    u32 type, size_t red_key_len, size_t obj_len)
+{
+	header->_magic_number = TAG_OBJECT_MAGIC;
+	header->version = version;
+	header->type = type;
+	header->red_key_len = red_key_len;
+	header->obj_len = obj_len;
+}
+EXPORT_SYMBOL(init_tag_object_header);
+
+/**
+ * set_tag_object_header_conf - Set tag object header configuration
+ * @header:			The tag object header configuration to set
+ * @buffer:			The buffer needed to be tagged
+ * @buf_size:			The buffer size
+ * @tag_obj_size:		The tagged object size
+ *
+ * Return:			'0' on success, error code otherwise
+ */
+int set_tag_object_header_conf(const struct header_conf *header,
+			       void *buffer, size_t buf_size, u32 *tag_obj_size)
+{
+	/* Retrieve the tag object */
+	struct tagged_object *tag_obj = (struct tagged_object *)buffer;
+	/*
+	 * Requested size for the tagged object is the buffer size
+	 * and the header configuration size (TAG_OVERHEAD_SIZE)
+	 */
+	size_t req_size = buf_size + TAG_OVERHEAD_SIZE;
+
+	/*
+	 * Check if the configuration can be set,
+	 * based on the size of the tagged object
+	 */
+	if (*tag_obj_size < req_size)
+		return -EINVAL;
+
+	/*
+	 * Buffers might overlap, use memmove to
+	 * copy the buffer into the tagged object
+	 */
+	memmove(&tag_obj->object, buffer, buf_size);
+	/* Copy the tag object header configuration into the tagged object */
+	memcpy(&tag_obj->header, header, TAG_OVERHEAD_SIZE);
+	/* Set tagged object size */
+	*tag_obj_size = req_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(set_tag_object_header_conf);
--- linux-ein-5.4.0.orig/drivers/crypto/caam/tag_object.h
+++ linux-ein-5.4.0/drivers/crypto/caam/tag_object.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+#ifndef _TAG_OBJECT_H_
+#define _TAG_OBJECT_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/**
+ * Magic number to identify the tag object structure
+ * 0x54 = 'T'
+ * 0x61 = 'a'
+ * 0x67 = 'g'
+ * 0x4f = 'O'
+ */
+#define TAG_OBJECT_MAGIC	0x5461674f
+#define TAG_OVERHEAD_SIZE	sizeof(struct header_conf)
+#define MIN_KEY_SIZE		16
+#define TAG_MIN_SIZE		(MIN_KEY_SIZE + TAG_OVERHEAD_SIZE)
+/*
+ * Tag object type is a bitfield:
+ *
+ * EKT:	Encrypted Key Type (AES-ECB or AES-CCM)
+ * TK:	Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
+ *	or Trusted Descriptor Key Encryption Key (TDKEK) to
+ *	decrypt the key to be loaded into a Key Register).
+ *
+ *| Denomination | Security state | Memory  | EKT | TK    | Type | Color |
+ *| ------------ | -------------- | ------- | --- | ----- | ---- | ----- |
+ *| bit(s)       | 5-6            | 4       | 3   | 2     | 1    | 0     |
+ *| option 0     | non-secure     | general | ECB | JDKEK | key  | red   |
+ *| option 1     | secure         | secure  | CCM | TDKEK | blob | black |
+ *| option 2     | trusted        |         |     |       |      |       |
+ *
+ * CAAM supports two different Black Key encapsulation schemes,
+ * one intended for quick decryption (uses AES-ECB encryption),
+ * and another intended for high assurance (uses AES-CCM encryption).
+ *
+ * CAAM implements both Trusted and normal (non-Trusted) Black Keys,
+ * which are encrypted with different key-encryption keys.
+ * Both Trusted and normal Descriptors are allowed to encrypt or decrypt
+ * normal Black Keys, but only Trusted Descriptors are allowed to
+ * encrypt or decrypt Trusted Black Keys.
+ */
+#define TAG_OBJ_COLOR_OFFSET		0
+#define TAG_OBJ_COLOR_MASK		0x1
+#define TAG_OBJ_TYPE_OFFSET		1
+#define TAG_OBJ_TYPE_MASK		0x1
+#define TAG_OBJ_TK_OFFSET		2
+#define TAG_OBJ_TK_MASK			0x1
+#define TAG_OBJ_EKT_OFFSET		3
+#define TAG_OBJ_EKT_MASK		0x1
+#define TAG_OBJ_MEM_OFFSET		4
+#define TAG_OBJ_MEM_MASK		0x1
+#define TAG_OBJ_SEC_STATE_OFFSET	5
+
+/**
+ * struct header_conf - Header configuration structure, which represents
+ *			the metadata (or simply a header) applied to the
+ *			actual data (e.g. black key)
+ * @_magic_number     : A magic number to identify the structure
+ * @version           : The version of the data contained (e.g. tag object)
+ * @type              : The type of data contained (e.g. black key, blob, etc.)
+ * @red_key_len       : Length of the red key to be loaded by CAAM (for key
+ *                      generation or blob encapsulation)
+ * @obj_len           : The total length of the (black/red) object (key/blob),
+ *                      after encryption/encapsulation
+ */
+struct header_conf {
+	u32 _magic_number;
+	u32 version;
+	u32 type;
+	u32 red_key_len;
+	u32 obj_len;
+};
+
+/**
+ * struct tagged_object - Tag object structure, which represents the metadata
+ *                        (or simply a header) and the actual data
+ *                        (e.g. black key) obtained from hardware
+ * @tag                 : The configuration of the data (e.g. header)
+ * @object              : The actual data (e.g. black key)
+ */
+struct tagged_object {
+	struct header_conf header;
+	char object;
+};
+
+bool is_key_type(u32 type);
+
+bool is_trusted_type(u32 type);
+
+bool is_black_key(const struct header_conf * const header);
+
+bool is_black_key(const struct header_conf * const header);
+
+bool is_valid_header_conf(const struct header_conf *header);
+
+void get_key_conf(const struct header_conf *header,
+		  u32 *red_key_len, u32 *obj_len, u32 *load_param);
+
+void init_tag_object_header(struct header_conf *header, u32 version,
+			    u32 type, size_t red_key_len, size_t obj_len);
+
+int set_tag_object_header_conf(const struct header_conf *header,
+			       void *buffer, size_t obj_size, u32 *to_size);
+
+#endif /* _TAG_OBJECT_H_ */
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/cpt/cptpf_main.c
+++ linux-ein-5.4.0/drivers/crypto/cavium/cpt/cptpf_main.c
@@ -254,6 +254,7 @@
 	const struct firmware *fw_entry;
 	struct device *dev = &cpt->pdev->dev;
 	struct ucode_header *ucode;
+	unsigned int code_length;
 	struct microcode *mcode;
 	int j, ret = 0;
 
@@ -264,11 +265,12 @@
 	ucode = (struct ucode_header *)fw_entry->data;
 	mcode = &cpt->mcode[cpt->next_mc_idx];
 	memcpy(mcode->version, (u8 *)fw_entry->data, CPT_UCODE_VERSION_SZ);
-	mcode->code_size = ntohl(ucode->code_length) * 2;
-	if (!mcode->code_size) {
+	code_length = ntohl(ucode->code_length);
+	if (code_length == 0 || code_length >= INT_MAX / 2) {
 		ret = -EINVAL;
 		goto fw_release;
 	}
+	mcode->code_size = code_length * 2;
 
 	mcode->is_ae = is_ae;
 	mcode->core_mask = 0ULL;
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/cpt/cptvf_algs.c
+++ linux-ein-5.4.0/drivers/crypto/cavium/cpt/cptvf_algs.c
@@ -200,6 +200,7 @@
 	int status;
 
 	memset(req_info, 0, sizeof(struct cpt_request_info));
+	req_info->may_sleep = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) != 0;
 	memset(fctx, 0, sizeof(struct fc_context));
 	create_input_list(req, enc, enc_iv_len);
 	create_output_list(req, enc_iv_len);
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
+++ linux-ein-5.4.0/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
@@ -133,7 +133,7 @@
 
 	/* Setup gather (input) components */
 	g_sz_bytes = ((req->incnt + 3) / 4) * sizeof(struct sglist_component);
-	info->gather_components = kzalloc(g_sz_bytes, GFP_KERNEL);
+	info->gather_components = kzalloc(g_sz_bytes, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (!info->gather_components) {
 		ret = -ENOMEM;
 		goto  scatter_gather_clean;
@@ -150,7 +150,7 @@
 
 	/* Setup scatter (output) components */
 	s_sz_bytes = ((req->outcnt + 3) / 4) * sizeof(struct sglist_component);
-	info->scatter_components = kzalloc(s_sz_bytes, GFP_KERNEL);
+	info->scatter_components = kzalloc(s_sz_bytes, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (!info->scatter_components) {
 		ret = -ENOMEM;
 		goto  scatter_gather_clean;
@@ -167,7 +167,7 @@
 
 	/* Create and initialize DPTR */
 	info->dlen = g_sz_bytes + s_sz_bytes + SG_LIST_HDR_SIZE;
-	info->in_buffer = kzalloc(info->dlen, GFP_KERNEL);
+	info->in_buffer = kzalloc(info->dlen, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (!info->in_buffer) {
 		ret = -ENOMEM;
 		goto  scatter_gather_clean;
@@ -195,7 +195,7 @@
 	}
 
 	/* Create and initialize RPTR */
-	info->out_buffer = kzalloc(COMPLETION_CODE_SIZE, GFP_KERNEL);
+	info->out_buffer = kzalloc(COMPLETION_CODE_SIZE, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (!info->out_buffer) {
 		ret = -ENOMEM;
 		goto scatter_gather_clean;
@@ -421,7 +421,7 @@
 	struct cpt_vq_command vq_cmd;
 	union cpt_inst_s cptinst;
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = kzalloc(sizeof(*info), req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (unlikely(!info)) {
 		dev_err(&pdev->dev, "Unable to allocate memory for info_buffer\n");
 		return -ENOMEM;
@@ -443,7 +443,7 @@
 	 * Get buffer for union cpt_res_s response
 	 * structure and its physical address
 	 */
-	info->completion_addr = kzalloc(sizeof(union cpt_res_s), GFP_KERNEL);
+	info->completion_addr = kzalloc(sizeof(union cpt_res_s), req->may_sleep ? GFP_KERNEL : GFP_ATOMIC);
 	if (unlikely(!info->completion_addr)) {
 		dev_err(&pdev->dev, "Unable to allocate memory for completion_addr\n");
 		ret = -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/cpt/request_manager.h
+++ linux-ein-5.4.0/drivers/crypto/cavium/cpt/request_manager.h
@@ -62,6 +62,8 @@
 	union ctrl_info ctrl; /* User control information */
 	struct cptvf_request req; /* Request Information (Core specific) */
 
+	bool may_sleep;
+
 	struct buf_ptr in[MAX_BUF_CNT];
 	struct buf_ptr out[MAX_BUF_CNT];
 
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/nitrox/nitrox_isr.c
+++ linux-ein-5.4.0/drivers/crypto/cavium/nitrox/nitrox_isr.c
@@ -306,6 +306,10 @@
 	 * Entry 192: NPS_CORE_INT_ACTIVE
 	 */
 	nr_vecs = pci_msix_vec_count(pdev);
+	if (nr_vecs < 0) {
+		dev_err(DEV(ndev), "Error in getting vec count %d\n", nr_vecs);
+		return nr_vecs;
+	}
 
 	/* Enable MSI-X */
 	ret = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX);
--- linux-ein-5.4.0.orig/drivers/crypto/cavium/nitrox/nitrox_main.c
+++ linux-ein-5.4.0/drivers/crypto/cavium/nitrox/nitrox_main.c
@@ -103,8 +103,7 @@
 	offset = UCD_UCODE_LOAD_BLOCK_NUM;
 	nitrox_write_csr(ndev, offset, block_num);
 
-	code_size = ucode_size;
-	code_size = roundup(code_size, 8);
+	code_size = roundup(ucode_size, 16);
 	while (code_size) {
 		data = ucode_data[i];
 		/* write 8 bytes at a time */
@@ -220,11 +219,11 @@
 
 	/* write block number and firmware length
 	 * bit:<2:0> block number
-	 * bit:3 is set SE uses 32KB microcode
-	 * bit:3 is clear SE uses 64KB microcode
+	 * bit:3 is set AE uses 32KB microcode
+	 * bit:3 is clear AE uses 64KB microcode
 	 */
 	core_2_eid_val.value = 0ULL;
-	core_2_eid_val.ucode_blk = 0;
+	core_2_eid_val.ucode_blk = 2;
 	if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE)
 		core_2_eid_val.ucode_len = 1;
 	else
@@ -279,7 +278,7 @@
 
 struct nitrox_device *nitrox_get_first_device(void)
 {
-	struct nitrox_device *ndev = NULL;
+	struct nitrox_device *ndev;
 
 	mutex_lock(&devlist_lock);
 	list_for_each_entry(ndev, &ndevlist, list) {
@@ -287,7 +286,7 @@
 			break;
 	}
 	mutex_unlock(&devlist_lock);
-	if (!ndev)
+	if (&ndev->list == &ndevlist)
 		return NULL;
 
 	refcount_inc(&ndev->refcnt);
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/ccp/Kconfig
@@ -10,10 +10,9 @@
 config CRYPTO_DEV_SP_CCP
 	bool "Cryptographic Coprocessor device"
 	default y
-	depends on CRYPTO_DEV_CCP_DD
+	depends on CRYPTO_DEV_CCP_DD && DMADEVICES
 	select HW_RANDOM
 	select DMA_ENGINE
-	select DMADEVICES
 	select CRYPTO_SHA1
 	select CRYPTO_SHA256
 	help
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/ccp-dev-v3.c
+++ linux-ein-5.4.0/drivers/crypto/ccp/ccp-dev-v3.c
@@ -586,6 +586,7 @@
 	.setup = NULL,
 	.perform = &ccp3_actions,
 	.offset = 0,
+	.rsamax = CCP_RSA_MAX_WIDTH,
 };
 
 const struct ccp_vdata ccpv3 = {
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/ccp-dev.h
+++ linux-ein-5.4.0/drivers/crypto/ccp/ccp-dev.h
@@ -469,6 +469,7 @@
 	unsigned int sg_used;
 
 	struct scatterlist *dma_sg;
+	struct scatterlist *dma_sg_head;
 	struct device *dma_dev;
 	unsigned int dma_count;
 	enum dma_data_direction dma_dir;
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/ccp-dmaengine.c
+++ linux-ein-5.4.0/drivers/crypto/ccp/ccp-dmaengine.c
@@ -342,6 +342,7 @@
 	desc->tx_desc.flags = flags;
 	desc->tx_desc.tx_submit = ccp_tx_submit;
 	desc->ccp = chan->ccp;
+	INIT_LIST_HEAD(&desc->entry);
 	INIT_LIST_HEAD(&desc->pending);
 	INIT_LIST_HEAD(&desc->active);
 	desc->status = DMA_IN_PROGRESS;
@@ -632,6 +633,36 @@
 	return 0;
 }
 
+static void ccp_dma_release(struct ccp_device *ccp)
+{
+	struct ccp_dma_chan *chan;
+	struct dma_chan *dma_chan;
+	unsigned int i;
+
+	for (i = 0; i < ccp->cmd_q_count; i++) {
+		chan = ccp->ccp_dma_chan + i;
+		dma_chan = &chan->dma_chan;
+
+		tasklet_kill(&chan->cleanup_tasklet);
+		list_del_rcu(&dma_chan->device_node);
+	}
+}
+
+static void ccp_dma_release_channels(struct ccp_device *ccp)
+{
+	struct ccp_dma_chan *chan;
+	struct dma_chan *dma_chan;
+	unsigned int i;
+
+	for (i = 0; i < ccp->cmd_q_count; i++) {
+		chan = ccp->ccp_dma_chan + i;
+		dma_chan = &chan->dma_chan;
+
+		if (dma_chan->client_count)
+			dma_release_channel(dma_chan);
+	}
+}
+
 int ccp_dmaengine_register(struct ccp_device *ccp)
 {
 	struct ccp_dma_chan *chan;
@@ -736,6 +767,7 @@
 	return 0;
 
 err_reg:
+	ccp_dma_release(ccp);
 	kmem_cache_destroy(ccp->dma_desc_cache);
 
 err_cache:
@@ -751,7 +783,9 @@
 	if (!dmaengine)
 		return;
 
+	ccp_dma_release_channels(ccp);
 	dma_async_device_unregister(dma_dev);
+	ccp_dma_release(ccp);
 
 	kmem_cache_destroy(ccp->dma_desc_cache);
 	kmem_cache_destroy(ccp->dma_cmd_cache);
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/ccp-ops.c
+++ linux-ein-5.4.0/drivers/crypto/ccp/ccp-ops.c
@@ -63,7 +63,7 @@
 static void ccp_sg_free(struct ccp_sg_workarea *wa)
 {
 	if (wa->dma_count)
-		dma_unmap_sg(wa->dma_dev, wa->dma_sg, wa->nents, wa->dma_dir);
+		dma_unmap_sg(wa->dma_dev, wa->dma_sg_head, wa->nents, wa->dma_dir);
 
 	wa->dma_count = 0;
 }
@@ -92,6 +92,7 @@
 		return 0;
 
 	wa->dma_sg = sg;
+	wa->dma_sg_head = sg;
 	wa->dma_dev = dev;
 	wa->dma_dir = dma_dir;
 	wa->dma_count = dma_map_sg(dev, sg, wa->nents, dma_dir);
@@ -104,14 +105,28 @@
 static void ccp_update_sg_workarea(struct ccp_sg_workarea *wa, unsigned int len)
 {
 	unsigned int nbytes = min_t(u64, len, wa->bytes_left);
+	unsigned int sg_combined_len = 0;
 
 	if (!wa->sg)
 		return;
 
 	wa->sg_used += nbytes;
 	wa->bytes_left -= nbytes;
-	if (wa->sg_used == wa->sg->length) {
-		wa->sg = sg_next(wa->sg);
+	if (wa->sg_used == sg_dma_len(wa->dma_sg)) {
+		/* Advance to the next DMA scatterlist entry */
+		wa->dma_sg = sg_next(wa->dma_sg);
+
+		/* In the case that the DMA mapped scatterlist has entries
+		 * that have been merged, the non-DMA mapped scatterlist
+		 * must be advanced multiple times for each merged entry.
+		 * This ensures that the current non-DMA mapped entry
+		 * corresponds to the current DMA mapped entry.
+		 */
+		do {
+			sg_combined_len += wa->sg->length;
+			wa->sg = sg_next(wa->sg);
+		} while (wa->sg_used > sg_combined_len);
+
 		wa->sg_used = 0;
 	}
 }
@@ -163,8 +178,11 @@
 
 		wa->dma.address = dma_map_single(wa->dev, wa->address, len,
 						 dir);
-		if (dma_mapping_error(wa->dev, wa->dma.address))
+		if (dma_mapping_error(wa->dev, wa->dma.address)) {
+			kfree(wa->address);
+			wa->address = NULL;
 			return -ENOMEM;
+		}
 
 		wa->dma.length = len;
 	}
@@ -299,7 +317,7 @@
 	/* Update the structures and generate the count */
 	buf_count = 0;
 	while (sg_wa->bytes_left && (buf_count < dm_wa->length)) {
-		nbytes = min(sg_wa->sg->length - sg_wa->sg_used,
+		nbytes = min(sg_dma_len(sg_wa->dma_sg) - sg_wa->sg_used,
 			     dm_wa->length - buf_count);
 		nbytes = min_t(u64, sg_wa->bytes_left, nbytes);
 
@@ -331,11 +349,11 @@
 	 * and destination. The resulting len values will always be <= UINT_MAX
 	 * because the dma length is an unsigned int.
 	 */
-	sg_src_len = sg_dma_len(src->sg_wa.sg) - src->sg_wa.sg_used;
+	sg_src_len = sg_dma_len(src->sg_wa.dma_sg) - src->sg_wa.sg_used;
 	sg_src_len = min_t(u64, src->sg_wa.bytes_left, sg_src_len);
 
 	if (dst) {
-		sg_dst_len = sg_dma_len(dst->sg_wa.sg) - dst->sg_wa.sg_used;
+		sg_dst_len = sg_dma_len(dst->sg_wa.dma_sg) - dst->sg_wa.sg_used;
 		sg_dst_len = min_t(u64, src->sg_wa.bytes_left, sg_dst_len);
 		op_len = min(sg_src_len, sg_dst_len);
 	} else {
@@ -365,7 +383,7 @@
 		/* Enough data in the sg element, but we need to
 		 * adjust for any previously copied data
 		 */
-		op->src.u.dma.address = sg_dma_address(src->sg_wa.sg);
+		op->src.u.dma.address = sg_dma_address(src->sg_wa.dma_sg);
 		op->src.u.dma.offset = src->sg_wa.sg_used;
 		op->src.u.dma.length = op_len & ~(block_size - 1);
 
@@ -386,7 +404,7 @@
 			/* Enough room in the sg element, but we need to
 			 * adjust for any previously used area
 			 */
-			op->dst.u.dma.address = sg_dma_address(dst->sg_wa.sg);
+			op->dst.u.dma.address = sg_dma_address(dst->sg_wa.dma_sg);
 			op->dst.u.dma.offset = dst->sg_wa.sg_used;
 			op->dst.u.dma.length = op->src.u.dma.length;
 		}
@@ -763,7 +781,7 @@
 				    in_place ? DMA_BIDIRECTIONAL
 					     : DMA_TO_DEVICE);
 		if (ret)
-			goto e_ctx;
+			goto e_aad;
 
 		if (in_place) {
 			dst = src;
@@ -848,7 +866,7 @@
 	op.u.aes.size = 0;
 	ret = cmd_q->ccp->vdata->perform->aes(&op);
 	if (ret)
-		goto e_dst;
+		goto e_final_wa;
 
 	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
 		/* Put the ciphered tag after the ciphertext. */
@@ -858,17 +876,19 @@
 		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize,
 					   DMA_BIDIRECTIONAL);
 		if (ret)
-			goto e_tag;
+			goto e_final_wa;
 		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize);
-		if (ret)
-			goto e_tag;
+		if (ret) {
+			ccp_dm_free(&tag);
+			goto e_final_wa;
+		}
 
 		ret = crypto_memneq(tag.address, final_wa.address,
 				    authsize) ? -EBADMSG : 0;
 		ccp_dm_free(&tag);
 	}
 
-e_tag:
+e_final_wa:
 	ccp_dm_free(&final_wa);
 
 e_dst:
@@ -1731,7 +1751,7 @@
 			break;
 		default:
 			ret = -EINVAL;
-			goto e_ctx;
+			goto e_data;
 		}
 	} else {
 		/* Stash the context */
@@ -1777,8 +1797,9 @@
 			       LSB_ITEM_SIZE);
 			break;
 		default:
+			kfree(hmac_buf);
 			ret = -EINVAL;
-			goto e_ctx;
+			goto e_data;
 		}
 
 		memset(&hmac_cmd, 0, sizeof(hmac_cmd));
@@ -2027,7 +2048,7 @@
 	dst.sg_wa.sg_used = 0;
 	for (i = 1; i <= src.sg_wa.dma_count; i++) {
 		if (!dst.sg_wa.sg ||
-		    (dst.sg_wa.sg->length < src.sg_wa.sg->length)) {
+		    (sg_dma_len(dst.sg_wa.sg) < sg_dma_len(src.sg_wa.sg))) {
 			ret = -EINVAL;
 			goto e_dst;
 		}
@@ -2053,8 +2074,8 @@
 			goto e_dst;
 		}
 
-		dst.sg_wa.sg_used += src.sg_wa.sg->length;
-		if (dst.sg_wa.sg_used == dst.sg_wa.sg->length) {
+		dst.sg_wa.sg_used += sg_dma_len(src.sg_wa.sg);
+		if (dst.sg_wa.sg_used == sg_dma_len(dst.sg_wa.sg)) {
 			dst.sg_wa.sg = sg_next(dst.sg_wa.sg);
 			dst.sg_wa.sg_used = 0;
 		}
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/psp-dev.c
+++ linux-ein-5.4.0/drivers/crypto/ccp/psp-dev.c
@@ -40,6 +40,10 @@
 module_param(psp_probe_timeout, int, 0644);
 MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");
 
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model0xh.sbin"); /* 1st gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model3xh.sbin"); /* 2nd gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam19h_model0xh.sbin"); /* 3rd gen EPYC */
+
 static bool psp_dead;
 static int psp_timeout;
 
--- linux-ein-5.4.0.orig/drivers/crypto/ccp/sp-pci.c
+++ linux-ein-5.4.0/drivers/crypto/ccp/sp-pci.c
@@ -213,7 +213,7 @@
 		if (ret) {
 			dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
 				ret);
-			goto e_err;
+			goto free_irqs;
 		}
 	}
 
@@ -221,10 +221,12 @@
 
 	ret = sp_init(sp);
 	if (ret)
-		goto e_err;
+		goto free_irqs;
 
 	return 0;
 
+free_irqs:
+	sp_free_irqs(sp);
 e_err:
 	dev_notice(dev, "initialization failed\n");
 	return ret;
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_aead.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_aead.c
@@ -237,7 +237,7 @@
 			 * revealed the decrypted message --> zero its memory.
 			 */
 			sg_zero_buffer(areq->dst, sg_nents(areq->dst),
-				       areq->cryptlen, 0);
+				       areq->cryptlen, areq->assoclen);
 			err = -EBADMSG;
 		}
 	/*ENCRYPT*/
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_buffer_mgr.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_buffer_mgr.c
@@ -87,6 +87,8 @@
 {
 	unsigned int nents = 0;
 
+	*lbytes = 0;
+
 	while (nbytes && sg_list) {
 		nents++;
 		/* get the number of bytes in the last entry */
@@ -95,6 +97,7 @@
 				nbytes : sg_list->length;
 		sg_list = sg_next(sg_list);
 	}
+
 	dev_dbg(dev, "nents %d last bytes %d\n", nents, *lbytes);
 	return nents;
 }
@@ -290,37 +293,32 @@
 		     unsigned int nbytes, int direction, u32 *nents,
 		     u32 max_sg_nents, u32 *lbytes, u32 *mapped_nents)
 {
-	if (sg_is_last(sg)) {
-		/* One entry only case -set to DLLI */
-		if (dma_map_sg(dev, sg, 1, direction) != 1) {
-			dev_err(dev, "dma_map_sg() single buffer failed\n");
-			return -ENOMEM;
-		}
-		dev_dbg(dev, "Mapped sg: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n",
-			&sg_dma_address(sg), sg_page(sg), sg_virt(sg),
-			sg->offset, sg->length);
-		*lbytes = nbytes;
-		*nents = 1;
-		*mapped_nents = 1;
-	} else {  /*sg_is_last*/
-		*nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes);
-		if (*nents > max_sg_nents) {
-			*nents = 0;
-			dev_err(dev, "Too many fragments. current %d max %d\n",
-				*nents, max_sg_nents);
-			return -ENOMEM;
-		}
-		/* In case of mmu the number of mapped nents might
-		 * be changed from the original sgl nents
-		 */
-		*mapped_nents = dma_map_sg(dev, sg, *nents, direction);
-		if (*mapped_nents == 0) {
-			*nents = 0;
-			dev_err(dev, "dma_map_sg() sg buffer failed\n");
-			return -ENOMEM;
-		}
+	int ret = 0;
+
+	if (!nbytes) {
+		*mapped_nents = 0;
+		*lbytes = 0;
+		*nents = 0;
+		return 0;
 	}
 
+	*nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes);
+	if (*nents > max_sg_nents) {
+		*nents = 0;
+		dev_err(dev, "Too many fragments. current %d max %d\n",
+			*nents, max_sg_nents);
+		return -ENOMEM;
+	}
+
+	ret = dma_map_sg(dev, sg, *nents, direction);
+	if (dma_mapping_error(dev, ret)) {
+		*nents = 0;
+		dev_err(dev, "dma_map_sg() sg buffer failed %d\n", ret);
+		return -ENOMEM;
+	}
+
+	*mapped_nents = ret;
+
 	return 0;
 }
 
@@ -555,11 +553,12 @@
 		sg_virt(req->src), areq_ctx->src.nents, areq_ctx->assoc.nents,
 		areq_ctx->assoclen, req->cryptlen);
 
-	dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_BIDIRECTIONAL);
+	dma_unmap_sg(dev, req->src, areq_ctx->src.mapped_nents,
+		     DMA_BIDIRECTIONAL);
 	if (req->src != req->dst) {
 		dev_dbg(dev, "Unmapping dst sgl: req->dst=%pK\n",
 			sg_virt(req->dst));
-		dma_unmap_sg(dev, req->dst, sg_nents(req->dst),
+		dma_unmap_sg(dev, req->dst, areq_ctx->dst.mapped_nents,
 			     DMA_BIDIRECTIONAL);
 	}
 	if (drvdata->coherent &&
@@ -881,7 +880,7 @@
 					    &src_last_bytes);
 	sg_index = areq_ctx->src_sgl->length;
 	//check where the data starts
-	while (sg_index <= size_to_skip) {
+	while (src_mapped_nents && (sg_index <= size_to_skip)) {
 		src_mapped_nents--;
 		offset -= areq_ctx->src_sgl->length;
 		sgl = sg_next(areq_ctx->src_sgl);
@@ -902,13 +901,17 @@
 
 	if (req->src != req->dst) {
 		size_for_map = areq_ctx->assoclen + req->cryptlen;
-		size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
-				authsize : 0;
+
+		if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT)
+			size_for_map += authsize;
+		else
+			size_for_map -= authsize;
+
 		if (is_gcm4543)
 			size_for_map += crypto_aead_ivsize(tfm);
 
 		rc = cc_map_sg(dev, req->dst, size_for_map, DMA_BIDIRECTIONAL,
-			       &areq_ctx->dst.nents,
+			       &areq_ctx->dst.mapped_nents,
 			       LLI_MAX_NUM_OF_DATA_ENTRIES, &dst_last_bytes,
 			       &dst_mapped_nents);
 		if (rc)
@@ -921,7 +924,7 @@
 	offset = size_to_skip;
 
 	//check where the data starts
-	while (sg_index <= size_to_skip) {
+	while (dst_mapped_nents && sg_index <= size_to_skip) {
 		dst_mapped_nents--;
 		offset -= areq_ctx->dst_sgl->length;
 		sgl = sg_next(areq_ctx->dst_sgl);
@@ -1117,13 +1120,15 @@
 	}
 
 	size_to_map = req->cryptlen + areq_ctx->assoclen;
-	if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT)
+	/* If we do in-place encryption, we also need the auth tag */
+	if ((areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT) &&
+	   (req->src == req->dst)) {
 		size_to_map += authsize;
-
+	}
 	if (is_gcm4543)
 		size_to_map += crypto_aead_ivsize(tfm);
 	rc = cc_map_sg(dev, req->src, size_to_map, DMA_BIDIRECTIONAL,
-		       &areq_ctx->src.nents,
+		       &areq_ctx->src.mapped_nents,
 		       (LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES +
 			LLI_MAX_NUM_OF_DATA_ENTRIES),
 		       &dummy, &mapped_nents);
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_buffer_mgr.h
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_buffer_mgr.h
@@ -25,6 +25,7 @@
 
 struct cc_mlli {
 	cc_sram_addr_t sram_addr;
+	unsigned int mapped_nents;
 	unsigned int nents; //sg nents
 	unsigned int mlli_nents; //mlli nents might be different than the above
 };
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_cipher.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_cipher.c
@@ -163,7 +163,6 @@
 				     skcipher_alg.base);
 	struct device *dev = drvdata_to_dev(cc_alg->drvdata);
 	unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
-	int rc = 0;
 
 	dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p,
 		crypto_tfm_alg_name(tfm));
@@ -175,10 +174,19 @@
 	ctx_p->flow_mode = cc_alg->flow_mode;
 	ctx_p->drvdata = cc_alg->drvdata;
 
+	if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+		/* Alloc hash tfm for essiv */
+		ctx_p->shash_tfm = crypto_alloc_shash("sha256-generic", 0, 0);
+		if (IS_ERR(ctx_p->shash_tfm)) {
+			dev_err(dev, "Error allocating hash tfm for ESSIV.\n");
+			return PTR_ERR(ctx_p->shash_tfm);
+		}
+	}
+
 	/* Allocate key buffer, cache line aligned */
 	ctx_p->user.key = kmalloc(max_key_buf_size, GFP_KERNEL);
 	if (!ctx_p->user.key)
-		return -ENOMEM;
+		goto free_shash;
 
 	dev_dbg(dev, "Allocated key buffer in context. key=@%p\n",
 		ctx_p->user.key);
@@ -190,21 +198,19 @@
 	if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) {
 		dev_err(dev, "Mapping Key %u B at va=%pK for DMA failed\n",
 			max_key_buf_size, ctx_p->user.key);
-		return -ENOMEM;
+		goto free_key;
 	}
 	dev_dbg(dev, "Mapped key %u B at va=%pK to dma=%pad\n",
 		max_key_buf_size, ctx_p->user.key, &ctx_p->user.key_dma_addr);
 
-	if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
-		/* Alloc hash tfm for essiv */
-		ctx_p->shash_tfm = crypto_alloc_shash("sha256-generic", 0, 0);
-		if (IS_ERR(ctx_p->shash_tfm)) {
-			dev_err(dev, "Error allocating hash tfm for ESSIV.\n");
-			return PTR_ERR(ctx_p->shash_tfm);
-		}
-	}
+	return 0;
 
-	return rc;
+free_key:
+	kfree(ctx_p->user.key);
+free_shash:
+	crypto_free_shash(ctx_p->shash_tfm);
+
+	return -ENOMEM;
 }
 
 static void cc_cipher_exit(struct crypto_tfm *tfm)
@@ -523,6 +529,7 @@
 	}
 }
 
+
 static void cc_setup_state_desc(struct crypto_tfm *tfm,
 				 struct cipher_req_ctx *req_ctx,
 				 unsigned int ivsize, unsigned int nbytes,
@@ -534,8 +541,6 @@
 	int cipher_mode = ctx_p->cipher_mode;
 	int flow_mode = ctx_p->flow_mode;
 	int direction = req_ctx->gen_ctx.op_type;
-	dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
-	unsigned int key_len = ctx_p->keylen;
 	dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr;
 	unsigned int du_size = nbytes;
 
@@ -571,6 +576,47 @@
 	case DRV_CIPHER_XTS:
 	case DRV_CIPHER_ESSIV:
 	case DRV_CIPHER_BITLOCKER:
+		break;
+	default:
+		dev_err(dev, "Unsupported cipher mode (%d)\n", cipher_mode);
+	}
+}
+
+
+static void cc_setup_xex_state_desc(struct crypto_tfm *tfm,
+				 struct cipher_req_ctx *req_ctx,
+				 unsigned int ivsize, unsigned int nbytes,
+				 struct cc_hw_desc desc[],
+				 unsigned int *seq_size)
+{
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+	int cipher_mode = ctx_p->cipher_mode;
+	int flow_mode = ctx_p->flow_mode;
+	int direction = req_ctx->gen_ctx.op_type;
+	dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
+	unsigned int key_len = ctx_p->keylen;
+	dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr;
+	unsigned int du_size = nbytes;
+
+	struct cc_crypto_alg *cc_alg =
+		container_of(tfm->__crt_alg, struct cc_crypto_alg,
+			     skcipher_alg.base);
+
+	if (cc_alg->data_unit)
+		du_size = cc_alg->data_unit;
+
+	switch (cipher_mode) {
+	case DRV_CIPHER_ECB:
+		break;
+	case DRV_CIPHER_CBC:
+	case DRV_CIPHER_CBC_CTS:
+	case DRV_CIPHER_CTR:
+	case DRV_CIPHER_OFB:
+		break;
+	case DRV_CIPHER_XTS:
+	case DRV_CIPHER_ESSIV:
+	case DRV_CIPHER_BITLOCKER:
 		/* load XEX key */
 		hw_desc_init(&desc[*seq_size]);
 		set_cipher_mode(&desc[*seq_size], cipher_mode);
@@ -881,12 +927,14 @@
 
 	/* STAT_PHASE_2: Create sequence */
 
-	/* Setup IV and XEX key used */
+	/* Setup state (IV)  */
 	cc_setup_state_desc(tfm, req_ctx, ivsize, nbytes, desc, &seq_len);
 	/* Setup MLLI line, if needed */
 	cc_setup_mlli_desc(tfm, req_ctx, dst, src, nbytes, req, desc, &seq_len);
 	/* Setup key */
 	cc_setup_key_desc(tfm, req_ctx, nbytes, desc, &seq_len);
+	/* Setup state (IV and XEX key)  */
+	cc_setup_xex_state_desc(tfm, req_ctx, ivsize, nbytes, desc, &seq_len);
 	/* Data processing */
 	cc_setup_flow_desc(tfm, req_ctx, dst, src, nbytes, desc, &seq_len);
 	/* Read next IV */
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_debugfs.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_debugfs.c
@@ -59,7 +59,7 @@
 	cc_debugfs_dir = debugfs_create_dir("ccree", NULL);
 }
 
-void __exit cc_debugfs_global_fini(void)
+void cc_debugfs_global_fini(void)
 {
 	debugfs_remove(cc_debugfs_dir);
 }
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_driver.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_driver.c
@@ -653,10 +653,17 @@
 
 static int __init ccree_init(void)
 {
-	cc_hash_global_init();
+	int rc;
+
 	cc_debugfs_global_init();
 
-	return platform_driver_register(&ccree_driver);
+	rc = platform_driver_register(&ccree_driver);
+	if (rc) {
+		cc_debugfs_global_fini();
+		return rc;
+	}
+
+	return 0;
 }
 module_init(ccree_init);
 
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_driver.h
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_driver.h
@@ -161,6 +161,7 @@
 	int std_bodies;
 	bool sec_disabled;
 	u32 comp_mask;
+	bool pm_on;
 };
 
 struct cc_crypto_alg {
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_hash.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_hash.c
@@ -39,12 +39,19 @@
 	SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 };
 static const u32 cc_digest_len_sha512_init[] = {
 	0x00000080, 0x00000000, 0x00000000, 0x00000000 };
-static u64 cc_sha384_init[] = {
-	SHA384_H7, SHA384_H6, SHA384_H5, SHA384_H4,
-	SHA384_H3, SHA384_H2, SHA384_H1, SHA384_H0 };
-static u64 cc_sha512_init[] = {
-	SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4,
-	SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 };
+
+/*
+ * Due to the way the HW works, every double word in the SHA384 and SHA512
+ * larval hashes must be stored in hi/lo order
+ */
+#define hilo(x)	upper_32_bits(x), lower_32_bits(x)
+static const u32 cc_sha384_init[] = {
+	hilo(SHA384_H7), hilo(SHA384_H6), hilo(SHA384_H5), hilo(SHA384_H4),
+	hilo(SHA384_H3), hilo(SHA384_H2), hilo(SHA384_H1), hilo(SHA384_H0) };
+static const u32 cc_sha512_init[] = {
+	hilo(SHA512_H7), hilo(SHA512_H6), hilo(SHA512_H5), hilo(SHA512_H4),
+	hilo(SHA512_H3), hilo(SHA512_H2), hilo(SHA512_H1), hilo(SHA512_H0) };
+
 static const u32 cc_sm3_init[] = {
 	SM3_IVH, SM3_IVG, SM3_IVF, SM3_IVE,
 	SM3_IVD, SM3_IVC, SM3_IVB, SM3_IVA };
@@ -1948,8 +1955,8 @@
 	}
 
 	if (large_sha_supported) {
-		cc_set_sram_desc((u32 *)cc_sha384_init, sram_buff_ofs,
-				 (ARRAY_SIZE(cc_sha384_init) * 2), larval_seq,
+		cc_set_sram_desc(cc_sha384_init, sram_buff_ofs,
+				 ARRAY_SIZE(cc_sha384_init), larval_seq,
 				 &larval_seq_len);
 		rc = send_request_init(drvdata, larval_seq, larval_seq_len);
 		if (rc)
@@ -1957,8 +1964,8 @@
 		sram_buff_ofs += sizeof(cc_sha384_init);
 		larval_seq_len = 0;
 
-		cc_set_sram_desc((u32 *)cc_sha512_init, sram_buff_ofs,
-				 (ARRAY_SIZE(cc_sha512_init) * 2), larval_seq,
+		cc_set_sram_desc(cc_sha512_init, sram_buff_ofs,
+				 ARRAY_SIZE(cc_sha512_init), larval_seq,
 				 &larval_seq_len);
 		rc = send_request_init(drvdata, larval_seq, larval_seq_len);
 		if (rc)
@@ -1969,28 +1976,6 @@
 	return rc;
 }
 
-static void __init cc_swap_dwords(u32 *buf, unsigned long size)
-{
-	int i;
-	u32 tmp;
-
-	for (i = 0; i < size; i += 2) {
-		tmp = buf[i];
-		buf[i] = buf[i + 1];
-		buf[i + 1] = tmp;
-	}
-}
-
-/*
- * Due to the way the HW works we need to swap every
- * double word in the SHA384 and SHA512 larval hashes
- */
-void __init cc_hash_global_init(void)
-{
-	cc_swap_dwords((u32 *)&cc_sha384_init, (ARRAY_SIZE(cc_sha384_init) * 2));
-	cc_swap_dwords((u32 *)&cc_sha512_init, (ARRAY_SIZE(cc_sha512_init) * 2));
-}
-
 int cc_hash_alloc(struct cc_drvdata *drvdata)
 {
 	struct cc_hash_handle *hash_handle;
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_hash.h
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_hash.h
@@ -104,6 +104,4 @@
  */
 cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode);
 
-void cc_hash_global_init(void);
-
 #endif /*__CC_HASH_H__*/
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_pm.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_pm.c
@@ -22,14 +22,8 @@
 int cc_pm_suspend(struct device *dev)
 {
 	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
-	int rc;
 
 	dev_dbg(dev, "set HOST_POWER_DOWN_EN\n");
-	rc = cc_suspend_req_queue(drvdata);
-	if (rc) {
-		dev_err(dev, "cc_suspend_req_queue (%x)\n", rc);
-		return rc;
-	}
 	fini_cc_regs(drvdata);
 	cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
 	cc_clk_off(drvdata);
@@ -63,13 +57,6 @@
 	/* check if tee fips error occurred during power down */
 	cc_tee_handle_fips_error(drvdata);
 
-	rc = cc_resume_req_queue(drvdata);
-	if (rc) {
-		dev_err(dev, "cc_resume_req_queue (%x)\n", rc);
-		return rc;
-	}
-
-	/* must be after the queue resuming as it uses the HW queue*/
 	cc_init_hash_sram(drvdata);
 
 	return 0;
@@ -80,12 +67,10 @@
 	int rc = 0;
 	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
 
-	if (cc_req_queue_suspended(drvdata))
+	if (drvdata->pm_on)
 		rc = pm_runtime_get_sync(dev);
-	else
-		pm_runtime_get_noresume(dev);
 
-	return rc;
+	return (rc == 1 ? 0 : rc);
 }
 
 int cc_pm_put_suspend(struct device *dev)
@@ -93,14 +78,11 @@
 	int rc = 0;
 	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
 
-	if (!cc_req_queue_suspended(drvdata)) {
+	if (drvdata->pm_on) {
 		pm_runtime_mark_last_busy(dev);
 		rc = pm_runtime_put_autosuspend(dev);
-	} else {
-		/* Something wrong happens*/
-		dev_err(dev, "request to suspend already suspended queue");
-		rc = -EBUSY;
 	}
+
 	return rc;
 }
 
@@ -117,7 +99,7 @@
 	/* must be before the enabling to avoid resdundent suspending */
 	pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
 	pm_runtime_use_autosuspend(dev);
-	/* activate the PM module */
+	/* set us as active - note we won't do PM ops until cc_pm_go()! */
 	return pm_runtime_set_active(dev);
 }
 
@@ -125,9 +107,11 @@
 void cc_pm_go(struct cc_drvdata *drvdata)
 {
 	pm_runtime_enable(drvdata_to_dev(drvdata));
+	drvdata->pm_on = true;
 }
 
 void cc_pm_fini(struct cc_drvdata *drvdata)
 {
 	pm_runtime_disable(drvdata_to_dev(drvdata));
+	drvdata->pm_on = false;
 }
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_request_mgr.c
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_request_mgr.c
@@ -41,7 +41,6 @@
 #else
 	struct tasklet_struct comptask;
 #endif
-	bool is_runtime_suspended;
 };
 
 struct cc_bl_item {
@@ -404,6 +403,7 @@
 		spin_lock(&mgr->bl_lock);
 		list_del(&bli->list);
 		--mgr->bl_len;
+		kfree(bli);
 	}
 
 	spin_unlock(&mgr->bl_lock);
@@ -677,52 +677,3 @@
 	cc_proc_backlog(drvdata);
 	dev_dbg(dev, "Comp. handler done.\n");
 }
-
-/*
- * resume the queue configuration - no need to take the lock as this happens
- * inside the spin lock protection
- */
-#if defined(CONFIG_PM)
-int cc_resume_req_queue(struct cc_drvdata *drvdata)
-{
-	struct cc_req_mgr_handle *request_mgr_handle =
-		drvdata->request_mgr_handle;
-
-	spin_lock_bh(&request_mgr_handle->hw_lock);
-	request_mgr_handle->is_runtime_suspended = false;
-	spin_unlock_bh(&request_mgr_handle->hw_lock);
-
-	return 0;
-}
-
-/*
- * suspend the queue configuration. Since it is used for the runtime suspend
- * only verify that the queue can be suspended.
- */
-int cc_suspend_req_queue(struct cc_drvdata *drvdata)
-{
-	struct cc_req_mgr_handle *request_mgr_handle =
-						drvdata->request_mgr_handle;
-
-	/* lock the send_request */
-	spin_lock_bh(&request_mgr_handle->hw_lock);
-	if (request_mgr_handle->req_queue_head !=
-	    request_mgr_handle->req_queue_tail) {
-		spin_unlock_bh(&request_mgr_handle->hw_lock);
-		return -EBUSY;
-	}
-	request_mgr_handle->is_runtime_suspended = true;
-	spin_unlock_bh(&request_mgr_handle->hw_lock);
-
-	return 0;
-}
-
-bool cc_req_queue_suspended(struct cc_drvdata *drvdata)
-{
-	struct cc_req_mgr_handle *request_mgr_handle =
-						drvdata->request_mgr_handle;
-
-	return	request_mgr_handle->is_runtime_suspended;
-}
-
-#endif
--- linux-ein-5.4.0.orig/drivers/crypto/ccree/cc_request_mgr.h
+++ linux-ein-5.4.0/drivers/crypto/ccree/cc_request_mgr.h
@@ -40,12 +40,4 @@
 
 void cc_req_mgr_fini(struct cc_drvdata *drvdata);
 
-#if defined(CONFIG_PM)
-int cc_resume_req_queue(struct cc_drvdata *drvdata);
-
-int cc_suspend_req_queue(struct cc_drvdata *drvdata);
-
-bool cc_req_queue_suspended(struct cc_drvdata *drvdata);
-#endif
-
 #endif /*__REQUEST_MGR_H__*/
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chcr_algo.c
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chcr_algo.c
@@ -2480,8 +2480,9 @@
 	else
 		reqctx->b0_dma = 0;
 	if (req->src == req->dst) {
-		error = dma_map_sg(dev, req->src, sg_nents(req->src),
-				   DMA_BIDIRECTIONAL);
+		error = dma_map_sg(dev, req->src,
+				sg_nents_for_len(req->src, dst_size),
+					DMA_BIDIRECTIONAL);
 		if (!error)
 			goto err;
 	} else {
@@ -2818,7 +2819,7 @@
 	unsigned int mac_mode = CHCR_SCMD_AUTH_MODE_CBCMAC;
 	unsigned int c_id = a_ctx(tfm)->tx_chan_id;
 	unsigned int ccm_xtra;
-	unsigned char tag_offset = 0, auth_offset = 0;
+	unsigned int tag_offset = 0, auth_offset = 0;
 	unsigned int assoclen;
 
 	if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309)
@@ -3194,9 +3195,6 @@
 		aeadctx->mayverify = VERIFY_SW;
 		break;
 	default:
-
-		  crypto_tfm_set_flags((struct crypto_tfm *) tfm,
-			CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 	return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize);
@@ -3221,8 +3219,6 @@
 		aeadctx->mayverify = VERIFY_HW;
 		break;
 	default:
-		crypto_tfm_set_flags((struct crypto_tfm *)tfm,
-				     CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 	return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize);
@@ -3263,8 +3259,6 @@
 		aeadctx->mayverify = VERIFY_HW;
 		break;
 	default:
-		crypto_tfm_set_flags((struct crypto_tfm *)tfm,
-				     CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 	return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize);
@@ -3289,8 +3283,7 @@
 		ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256;
 		mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_256;
 	} else {
-		crypto_tfm_set_flags((struct crypto_tfm *)aead,
-				     CRYPTO_TFM_RES_BAD_KEY_LEN);
+		crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		aeadctx->enckey_len = 0;
 		return	-EINVAL;
 	}
@@ -3328,8 +3321,7 @@
 	int error;
 
 	if (keylen < 3) {
-		crypto_tfm_set_flags((struct crypto_tfm *)aead,
-				     CRYPTO_TFM_RES_BAD_KEY_LEN);
+		crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		aeadctx->enckey_len = 0;
 		return	-EINVAL;
 	}
@@ -3379,8 +3371,7 @@
 	} else if (keylen == AES_KEYSIZE_256) {
 		ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256;
 	} else {
-		crypto_tfm_set_flags((struct crypto_tfm *)aead,
-				     CRYPTO_TFM_RES_BAD_KEY_LEN);
+		crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		pr_err("GCM: Invalid key length %d\n", keylen);
 		ret = -EINVAL;
 		goto out;
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chcr_core.c
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chcr_core.c
@@ -125,8 +125,6 @@
 	atomic_set(&dev->inflight, 0);
 	mutex_lock(&drv_data.drv_mutex);
 	list_add_tail(&u_ctx->entry, &drv_data.inact_dev);
-	if (!drv_data.last_dev)
-		drv_data.last_dev = u_ctx;
 	mutex_unlock(&drv_data.drv_mutex);
 }
 
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chtls/chtls_cm.c
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chtls/chtls_cm.c
@@ -174,7 +174,7 @@
 {
 	if (likely(skb && !skb_shared(skb) && !skb_cloned(skb))) {
 		__skb_trim(skb, 0);
-		refcount_add(2, &skb->users);
+		refcount_inc(&skb->users);
 	} else {
 		skb = alloc_skb(len, GFP_KERNEL | __GFP_NOFAIL);
 	}
@@ -577,7 +577,7 @@
 
 	while (!skb_queue_empty(&listen_ctx->synq)) {
 		struct chtls_sock *csk =
-			container_of((struct synq *)__skb_dequeue
+			container_of((struct synq *)skb_peek
 				(&listen_ctx->synq), struct chtls_sock, synq);
 		struct sock *child = csk->sk;
 
@@ -692,14 +692,13 @@
 	if (rpl->status != CPL_ERR_NONE) {
 		pr_info("Unexpected PASS_OPEN_RPL status %u for STID %u\n",
 			rpl->status, stid);
-		return CPL_RET_BUF_DONE;
+	} else {
+		cxgb4_free_stid(cdev->tids, stid, listen_ctx->lsk->sk_family);
+		sock_put(listen_ctx->lsk);
+		kfree(listen_ctx);
+		module_put(THIS_MODULE);
 	}
-	cxgb4_free_stid(cdev->tids, stid, listen_ctx->lsk->sk_family);
-	sock_put(listen_ctx->lsk);
-	kfree(listen_ctx);
-	module_put(THIS_MODULE);
-
-	return 0;
+	return CPL_RET_BUF_DONE;
 }
 
 static int chtls_close_listsrv_rpl(struct chtls_dev *cdev, struct sk_buff *skb)
@@ -716,15 +715,21 @@
 	if (rpl->status != CPL_ERR_NONE) {
 		pr_info("Unexpected CLOSE_LISTSRV_RPL status %u for STID %u\n",
 			rpl->status, stid);
-		return CPL_RET_BUF_DONE;
+	} else {
+		cxgb4_free_stid(cdev->tids, stid, listen_ctx->lsk->sk_family);
+		sock_put(listen_ctx->lsk);
+		kfree(listen_ctx);
+		module_put(THIS_MODULE);
 	}
+	return CPL_RET_BUF_DONE;
+}
 
-	cxgb4_free_stid(cdev->tids, stid, listen_ctx->lsk->sk_family);
-	sock_put(listen_ctx->lsk);
-	kfree(listen_ctx);
-	module_put(THIS_MODULE);
+static void chtls_purge_wr_queue(struct sock *sk)
+{
+	struct sk_buff *skb;
 
-	return 0;
+	while ((skb = dequeue_wr(sk)) != NULL)
+		kfree_skb(skb);
 }
 
 static void chtls_release_resources(struct sock *sk)
@@ -741,6 +746,11 @@
 	kfree_skb(csk->txdata_skb_cache);
 	csk->txdata_skb_cache = NULL;
 
+	if (csk->wr_credits != csk->wr_max_credits) {
+		chtls_purge_wr_queue(sk);
+		chtls_reset_wr_list(csk);
+	}
+
 	if (csk->l2t_entry) {
 		cxgb4_l2t_release(csk->l2t_entry);
 		csk->l2t_entry = NULL;
@@ -1011,6 +1021,7 @@
 				    const struct cpl_pass_accept_req *req,
 				    struct chtls_dev *cdev)
 {
+	struct adapter *adap = pci_get_drvdata(cdev->pdev);
 	struct inet_sock *newinet;
 	const struct iphdr *iph;
 	struct tls_context *ctx;
@@ -1020,9 +1031,10 @@
 	struct neighbour *n;
 	struct tcp_sock *tp;
 	struct sock *newsk;
+	bool found = false;
 	u16 port_id;
 	int rxq_idx;
-	int step;
+	int step, i;
 
 	iph = (const struct iphdr *)network_hdr;
 	newsk = tcp_create_openreq_child(lsk, oreq, cdev->askb);
@@ -1034,12 +1046,20 @@
 		goto free_sk;
 
 	n = dst_neigh_lookup(dst, &iph->saddr);
-	if (!n)
-		goto free_sk;
+	if (!n || !n->dev)
+		goto free_dst;
 
 	ndev = n->dev;
-	if (!ndev)
+	if (is_vlan_dev(ndev))
+		ndev = vlan_dev_real_dev(ndev);
+
+	for_each_port(adap, i)
+		if (cdev->ports[i] == ndev)
+			found = true;
+
+	if (!found)
 		goto free_dst;
+
 	port_id = cxgb4_port_idx(ndev);
 
 	csk = chtls_sock_create(cdev);
@@ -1064,6 +1084,7 @@
 	sk_setup_caps(newsk, dst);
 	ctx = tls_get_ctx(lsk);
 	newsk->sk_destruct = ctx->sk_destruct;
+	newsk->sk_prot_creator = lsk->sk_prot_creator;
 	csk->sk = newsk;
 	csk->passive_reap_next = oreq;
 	csk->tx_chan = cxgb4_port_chan(ndev);
@@ -1082,8 +1103,8 @@
 	csk->sndbuf = newsk->sk_sndbuf;
 	csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx;
 	RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
-					   sock_net(newsk)->
-						ipv4.sysctl_tcp_window_scaling,
+					   READ_ONCE(sock_net(newsk)->
+						     ipv4.sysctl_tcp_window_scaling),
 					   tp->window_clamp);
 	neigh_release(n);
 	inet_inherit_port(&tcp_hashinfo, lsk, newsk);
@@ -1094,6 +1115,8 @@
 free_csk:
 	chtls_sock_release(&csk->kref);
 free_dst:
+	if (n)
+		neigh_release(n);
 	dst_release(dst);
 free_sk:
 	inet_csk_prepare_forced_close(newsk);
@@ -1212,7 +1235,7 @@
 	chtls_set_req_addr(oreq, iph->daddr, iph->saddr);
 	ip_dsfield = ipv4_get_dsfield(iph);
 	if (req->tcpopt.wsf <= 14 &&
-	    sock_net(sk)->ipv4.sysctl_tcp_window_scaling) {
+	    READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
 		inet_rsk(oreq)->wscale_ok = 1;
 		inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf;
 	}
@@ -1353,7 +1376,6 @@
 	struct chtls_sock *csk = sk->sk_user_data;
 
 	local_bh_disable();
-	bh_lock_sock(sk);
 	release_tcp_port(sk); /* release the port immediately */
 
 	spin_lock(&reap_list_lock);
@@ -1362,7 +1384,6 @@
 	if (!csk->passive_reap_next)
 		schedule_work(&reap_task);
 	spin_unlock(&reap_list_lock);
-	bh_unlock_sock(sk);
 	local_bh_enable();
 }
 
@@ -1431,6 +1452,11 @@
 			sk_wake_async(sk, 0, POLL_OUT);
 
 		data = lookup_stid(cdev->tids, stid);
+		if (!data) {
+			/* listening server close */
+			kfree_skb(skb);
+			goto unlock;
+		}
 		lsk = ((struct listen_ctx *)data)->lsk;
 
 		bh_lock_sock(lsk);
@@ -1735,6 +1761,7 @@
 		else
 			sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
 	}
+	kfree_skb(skb);
 }
 
 static void chtls_close_con_rpl(struct sock *sk, struct sk_buff *skb)
@@ -1815,39 +1842,6 @@
 	kfree_skb(skb);
 }
 
-static void send_abort_rpl(struct sock *sk, struct sk_buff *skb,
-			   struct chtls_dev *cdev, int status, int queue)
-{
-	struct cpl_abort_req_rss *req = cplhdr(skb);
-	struct sk_buff *reply_skb;
-	struct chtls_sock *csk;
-
-	csk = rcu_dereference_sk_user_data(sk);
-
-	reply_skb = alloc_skb(sizeof(struct cpl_abort_rpl),
-			      GFP_KERNEL);
-
-	if (!reply_skb) {
-		req->status = (queue << 1);
-		send_defer_abort_rpl(cdev, skb);
-		return;
-	}
-
-	set_abort_rpl_wr(reply_skb, GET_TID(req), status);
-	kfree_skb(skb);
-
-	set_wr_txq(reply_skb, CPL_PRIORITY_DATA, queue);
-	if (csk_conn_inline(csk)) {
-		struct l2t_entry *e = csk->l2t_entry;
-
-		if (e && sk->sk_state != TCP_SYN_RECV) {
-			cxgb4_l2t_send(csk->egress_dev, reply_skb, e);
-			return;
-		}
-	}
-	cxgb4_ofld_send(cdev->lldi->ports[0], reply_skb);
-}
-
 /*
  * Add an skb to the deferred skb queue for processing from process context.
  */
@@ -1910,9 +1904,9 @@
 	queue = csk->txq_idx;
 
 	skb->sk	= NULL;
+	chtls_send_abort_rpl(child, skb, BLOG_SKB_CB(skb)->cdev,
+			     CPL_ABORT_NO_RST, queue);
 	do_abort_syn_rcv(child, lsk);
-	send_abort_rpl(child, skb, BLOG_SKB_CB(skb)->cdev,
-		       CPL_ABORT_NO_RST, queue);
 }
 
 static int abort_syn_rcv(struct sock *sk, struct sk_buff *skb)
@@ -1942,8 +1936,8 @@
 	if (!sock_owned_by_user(psk)) {
 		int queue = csk->txq_idx;
 
+		chtls_send_abort_rpl(sk, skb, cdev, CPL_ABORT_NO_RST, queue);
 		do_abort_syn_rcv(sk, psk);
-		send_abort_rpl(sk, skb, cdev, CPL_ABORT_NO_RST, queue);
 	} else {
 		skb->sk = sk;
 		BLOG_SKB_CB(skb)->backlog_rcv = bl_abort_syn_rcv;
@@ -1961,9 +1955,6 @@
 	int queue = csk->txq_idx;
 
 	if (is_neg_adv(req->status)) {
-		if (sk->sk_state == TCP_SYN_RECV)
-			chtls_set_tcb_tflag(sk, 0, 0);
-
 		kfree_skb(skb);
 		return;
 	}
@@ -1989,12 +1980,11 @@
 
 		if (sk->sk_state == TCP_SYN_RECV && !abort_syn_rcv(sk, skb))
 			return;
-
-		chtls_release_resources(sk);
-		chtls_conn_done(sk);
 	}
 
 	chtls_send_abort_rpl(sk, skb, csk->cdev, rst_status, queue);
+	chtls_release_resources(sk);
+	chtls_conn_done(sk);
 }
 
 static void chtls_abort_rpl_rss(struct sock *sk, struct sk_buff *skb)
@@ -2062,19 +2052,6 @@
 	return 0;
 }
 
-static struct sk_buff *dequeue_wr(struct sock *sk)
-{
-	struct chtls_sock *csk = rcu_dereference_sk_user_data(sk);
-	struct sk_buff *skb = csk->wr_skb_head;
-
-	if (likely(skb)) {
-	/* Don't bother clearing the tail */
-		csk->wr_skb_head = WR_SKB_CB(skb)->next_wr;
-		WR_SKB_CB(skb)->next_wr = NULL;
-	}
-	return skb;
-}
-
 static void chtls_rx_ack(struct sock *sk, struct sk_buff *skb)
 {
 	struct cpl_fw4_ack *hdr = cplhdr(skb) + RSS_HDR;
@@ -2115,7 +2092,7 @@
 
 		if (tp->snd_una != snd_una) {
 			tp->snd_una = snd_una;
-			tp->rcv_tstamp = tcp_time_stamp(tp);
+			tp->rcv_tstamp = tcp_jiffies32;
 			if (tp->snd_una == tp->snd_nxt &&
 			    !csk_flag_nochk(csk, CSK_TX_FAILOVER))
 				csk_reset_flag(csk, CSK_TX_WAIT_IDLE);
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chtls/chtls_cm.h
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chtls/chtls_cm.h
@@ -50,9 +50,6 @@
 #define MIN_RCV_WND (24 * 1024U)
 #define LOOPBACK(x)     (((x) & htonl(0xff000000)) == htonl(0x7f000000))
 
-/* ulp_mem_io + ulptx_idata + payload + padding */
-#define MAX_IMM_ULPTX_WR_LEN (32 + 8 + 256 + 8)
-
 /* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */
 #define TX_HEADER_LEN \
 	(sizeof(struct fw_ofld_tx_data_wr) + sizeof(struct sge_opaque_hdr))
@@ -185,6 +182,12 @@
 	kfree_skb(skb);
 }
 
+static inline void chtls_reset_wr_list(struct chtls_sock *csk)
+{
+	csk->wr_skb_head = NULL;
+	csk->wr_skb_tail = NULL;
+}
+
 static inline void enqueue_wr(struct chtls_sock *csk, struct sk_buff *skb)
 {
 	WR_SKB_CB(skb)->next_wr = NULL;
@@ -197,4 +200,19 @@
 		WR_SKB_CB(csk->wr_skb_tail)->next_wr = skb;
 	csk->wr_skb_tail = skb;
 }
+
+static inline struct sk_buff *dequeue_wr(struct sock *sk)
+{
+	struct chtls_sock *csk = rcu_dereference_sk_user_data(sk);
+	struct sk_buff *skb = NULL;
+
+	skb = csk->wr_skb_head;
+
+	if (likely(skb)) {
+	 /* Don't bother clearing the tail */
+		csk->wr_skb_head = WR_SKB_CB(skb)->next_wr;
+		WR_SKB_CB(skb)->next_wr = NULL;
+	}
+	return skb;
+}
 #endif
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chtls/chtls_hw.c
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chtls/chtls_hw.c
@@ -350,17 +350,22 @@
 	kwr->sc_imm.cmd_more = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_IMM));
 	kwr->sc_imm.len = cpu_to_be32(klen);
 
+	lock_sock(sk);
 	/* key info */
 	kctx = (struct _key_ctx *)(kwr + 1);
 	ret = chtls_key_info(csk, kctx, keylen, optname);
 	if (ret)
 		goto out_notcb;
 
+	if (unlikely(csk_flag(sk, CSK_ABORT_SHUTDOWN)))
+		goto out_notcb;
+
 	set_wr_txq(skb, CPL_PRIORITY_DATA, csk->tlshws.txqid);
 	csk->wr_credits -= DIV_ROUND_UP(len, 16);
 	csk->wr_unacked += DIV_ROUND_UP(len, 16);
 	enqueue_wr(csk, skb);
 	cxgb4_ofld_send(csk->egress_dev, skb);
+	skb = NULL;
 
 	chtls_set_scmd(csk);
 	/* Clear quiesce for Rx key */
@@ -388,8 +393,10 @@
 		csk->tlshws.txkey = keyid;
 	}
 
+	release_sock(sk);
 	return ret;
 out_notcb:
+	release_sock(sk);
 	free_tls_keyid(sk);
 out_nokey:
 	kfree_skb(skb);
--- linux-ein-5.4.0.orig/drivers/crypto/chelsio/chtls/chtls_io.c
+++ linux-ein-5.4.0/drivers/crypto/chelsio/chtls/chtls_io.c
@@ -682,7 +682,7 @@
 				make_tx_data_wr(sk, skb, immdlen, len,
 						credits_needed, completion);
 			tp->snd_nxt += len;
-			tp->lsndtime = tcp_time_stamp(tp);
+			tp->lsndtime = tcp_jiffies32;
 			if (completion)
 				ULP_SKB_CB(skb)->flags &= ~ULPCB_FLAG_NEED_HDR;
 		} else {
@@ -910,9 +910,9 @@
 	return (__force int)cpu_to_be16(thdr->length);
 }
 
-static int csk_mem_free(struct chtls_dev *cdev, struct sock *sk)
+static bool csk_mem_free(struct chtls_dev *cdev, struct sock *sk)
 {
-	return (cdev->max_host_sndbuf - sk->sk_wmem_queued);
+	return (cdev->max_host_sndbuf - sk->sk_wmem_queued > 0);
 }
 
 static int csk_wait_memory(struct chtls_dev *cdev,
@@ -1210,6 +1210,7 @@
 	copied = 0;
 	csk = rcu_dereference_sk_user_data(sk);
 	cdev = csk->cdev;
+	lock_sock(sk);
 	timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
 	err = sk_stream_wait_connect(sk, &timeo);
@@ -1437,7 +1438,7 @@
 				      csk->wr_max_credits))
 			sk->sk_write_space(sk);
 
-		if (copied >= target && !sk->sk_backlog.tail)
+		if (copied >= target && !READ_ONCE(sk->sk_backlog.tail))
 			break;
 
 		if (copied) {
@@ -1470,7 +1471,7 @@
 				break;
 			}
 		}
-		if (sk->sk_backlog.tail) {
+		if (READ_ONCE(sk->sk_backlog.tail)) {
 			release_sock(sk);
 			lock_sock(sk);
 			chtls_cleanup_rbuf(sk, copied);
@@ -1536,6 +1537,7 @@
 			tp->urg_data = 0;
 
 		if ((avail + offset) >= skb->len) {
+			struct sk_buff *next_skb;
 			if (ULP_SKB_CB(skb)->flags & ULPCB_FLAG_TLS_HDR) {
 				tp->copied_seq += skb->len;
 				hws->rcvpld = skb->hdr_len;
@@ -1545,8 +1547,10 @@
 			chtls_free_skb(sk, skb);
 			buffers_freed++;
 			hws->copied_seq = 0;
-			if (copied >= target &&
-			    !skb_peek(&sk->sk_receive_queue))
+			next_skb = skb_peek(&sk->sk_receive_queue);
+			if (copied >= target && !next_skb)
+				break;
+			if (ULP_SKB_CB(next_skb)->flags & ULPCB_FLAG_TLS_HDR)
 				break;
 		}
 	} while (len > 0);
@@ -1615,7 +1619,7 @@
 			break;
 		}
 
-		if (sk->sk_backlog.tail) {
+		if (READ_ONCE(sk->sk_backlog.tail)) {
 			/* Do not sleep, just process backlog. */
 			release_sock(sk);
 			lock_sock(sk);
@@ -1743,7 +1747,7 @@
 				      csk->wr_max_credits))
 			sk->sk_write_space(sk);
 
-		if (copied >= target && !sk->sk_backlog.tail)
+		if (copied >= target && !READ_ONCE(sk->sk_backlog.tail))
 			break;
 
 		if (copied) {
@@ -1774,7 +1778,7 @@
 			}
 		}
 
-		if (sk->sk_backlog.tail) {
+		if (READ_ONCE(sk->sk_backlog.tail)) {
 			release_sock(sk);
 			lock_sock(sk);
 			chtls_cleanup_rbuf(sk, copied);
--- linux-ein-5.4.0.orig/drivers/crypto/geode-aes.c
+++ linux-ein-5.4.0/drivers/crypto/geode-aes.c
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
+#include <crypto/internal/skcipher.h>
 
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -23,12 +24,12 @@
 
 /* Write a 128 bit field (either a writable key or IV) */
 static inline void
-_writefield(u32 offset, void *value)
+_writefield(u32 offset, const void *value)
 {
 	int i;
 
 	for (i = 0; i < 4; i++)
-		iowrite32(((u32 *) value)[i], _iobase + offset + (i * 4));
+		iowrite32(((const u32 *) value)[i], _iobase + offset + (i * 4));
 }
 
 /* Read a 128 bit field (either a writable key or IV) */
@@ -42,12 +43,12 @@
 }
 
 static int
-do_crypt(void *src, void *dst, int len, u32 flags)
+do_crypt(const void *src, void *dst, u32 len, u32 flags)
 {
 	u32 status;
 	u32 counter = AES_OP_TIMEOUT;
 
-	iowrite32(virt_to_phys(src), _iobase + AES_SOURCEA_REG);
+	iowrite32(virt_to_phys((void *)src), _iobase + AES_SOURCEA_REG);
 	iowrite32(virt_to_phys(dst), _iobase + AES_DSTA_REG);
 	iowrite32(len,  _iobase + AES_LENA_REG);
 
@@ -64,16 +65,14 @@
 	return counter ? 0 : 1;
 }
 
-static unsigned int
-geode_aes_crypt(struct geode_aes_op *op)
+static void
+geode_aes_crypt(const struct geode_aes_tfm_ctx *tctx, const void *src,
+		void *dst, u32 len, u8 *iv, int mode, int dir)
 {
 	u32 flags = 0;
 	unsigned long iflags;
 	int ret;
 
-	if (op->len == 0)
-		return 0;
-
 	/* If the source and destination is the same, then
 	 * we need to turn on the coherent flags, otherwise
 	 * we don't need to worry
@@ -81,32 +80,28 @@
 
 	flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
 
-	if (op->dir == AES_DIR_ENCRYPT)
+	if (dir == AES_DIR_ENCRYPT)
 		flags |= AES_CTRL_ENCRYPT;
 
 	/* Start the critical section */
 
 	spin_lock_irqsave(&lock, iflags);
 
-	if (op->mode == AES_MODE_CBC) {
+	if (mode == AES_MODE_CBC) {
 		flags |= AES_CTRL_CBC;
-		_writefield(AES_WRITEIV0_REG, op->iv);
+		_writefield(AES_WRITEIV0_REG, iv);
 	}
 
-	if (!(op->flags & AES_FLAGS_HIDDENKEY)) {
-		flags |= AES_CTRL_WRKEY;
-		_writefield(AES_WRITEKEY0_REG, op->key);
-	}
+	flags |= AES_CTRL_WRKEY;
+	_writefield(AES_WRITEKEY0_REG, tctx->key);
 
-	ret = do_crypt(op->src, op->dst, op->len, flags);
+	ret = do_crypt(src, dst, len, flags);
 	BUG_ON(ret);
 
-	if (op->mode == AES_MODE_CBC)
-		_readfield(AES_WRITEIV0_REG, op->iv);
+	if (mode == AES_MODE_CBC)
+		_readfield(AES_WRITEIV0_REG, iv);
 
 	spin_unlock_irqrestore(&lock, iflags);
-
-	return op->len;
 }
 
 /* CRYPTO-API Functions */
@@ -114,13 +109,13 @@
 static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
 		unsigned int len)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
 	unsigned int ret;
 
-	op->keylen = len;
+	tctx->keylen = len;
 
 	if (len == AES_KEYSIZE_128) {
-		memcpy(op->key, key, len);
+		memcpy(tctx->key, key, len);
 		return 0;
 	}
 
@@ -133,135 +128,93 @@
 	/*
 	 * The requested key size is not supported by HW, do a fallback
 	 */
-	op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-	op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+	tctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	tctx->fallback.cip->base.crt_flags |=
+		(tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
 
-	ret = crypto_cipher_setkey(op->fallback.cip, key, len);
+	ret = crypto_cipher_setkey(tctx->fallback.cip, key, len);
 	if (ret) {
 		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-		tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK);
+		tfm->crt_flags |= (tctx->fallback.cip->base.crt_flags &
+				   CRYPTO_TFM_RES_MASK);
 	}
 	return ret;
 }
 
-static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
-		unsigned int len)
+static int geode_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
+				 unsigned int len)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 	unsigned int ret;
 
-	op->keylen = len;
+	tctx->keylen = len;
 
 	if (len == AES_KEYSIZE_128) {
-		memcpy(op->key, key, len);
+		memcpy(tctx->key, key, len);
 		return 0;
 	}
 
 	if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
 		/* not supported at all */
-		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 
 	/*
 	 * The requested key size is not supported by HW, do a fallback
 	 */
-	op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-	op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
-
-	ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
-	if (ret) {
-		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-		tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
-	}
-	return ret;
-}
-
-static int fallback_blk_dec(struct blkcipher_desc *desc,
-		struct scatterlist *dst, struct scatterlist *src,
-		unsigned int nbytes)
-{
-	unsigned int ret;
-	struct crypto_blkcipher *tfm;
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-
-	tfm = desc->tfm;
-	desc->tfm = op->fallback.blk;
-
-	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
-
-	desc->tfm = tfm;
-	return ret;
-}
-static int fallback_blk_enc(struct blkcipher_desc *desc,
-		struct scatterlist *dst, struct scatterlist *src,
-		unsigned int nbytes)
-{
-	unsigned int ret;
-	struct crypto_blkcipher *tfm;
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-
-	tfm = desc->tfm;
-	desc->tfm = op->fallback.blk;
-
-	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
-
-	desc->tfm = tfm;
+	crypto_skcipher_clear_flags(tctx->fallback.skcipher,
+				    CRYPTO_TFM_REQ_MASK);
+	crypto_skcipher_set_flags(tctx->fallback.skcipher,
+				  crypto_skcipher_get_flags(tfm) &
+				  CRYPTO_TFM_REQ_MASK);
+	ret = crypto_skcipher_setkey(tctx->fallback.skcipher, key, len);
+	crypto_skcipher_set_flags(tfm,
+				  crypto_skcipher_get_flags(tctx->fallback.skcipher) &
+				  CRYPTO_TFM_RES_MASK);
 	return ret;
 }
 
 static void
 geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	const struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
 
-	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
-		crypto_cipher_encrypt_one(op->fallback.cip, out, in);
+	if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_encrypt_one(tctx->fallback.cip, out, in);
 		return;
 	}
 
-	op->src = (void *) in;
-	op->dst = (void *) out;
-	op->mode = AES_MODE_ECB;
-	op->flags = 0;
-	op->len = AES_BLOCK_SIZE;
-	op->dir = AES_DIR_ENCRYPT;
-
-	geode_aes_crypt(op);
+	geode_aes_crypt(tctx, in, out, AES_BLOCK_SIZE, NULL,
+			AES_MODE_ECB, AES_DIR_ENCRYPT);
 }
 
 
 static void
 geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	const struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
 
-	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
-		crypto_cipher_decrypt_one(op->fallback.cip, out, in);
+	if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_decrypt_one(tctx->fallback.cip, out, in);
 		return;
 	}
 
-	op->src = (void *) in;
-	op->dst = (void *) out;
-	op->mode = AES_MODE_ECB;
-	op->flags = 0;
-	op->len = AES_BLOCK_SIZE;
-	op->dir = AES_DIR_DECRYPT;
-
-	geode_aes_crypt(op);
+	geode_aes_crypt(tctx, in, out, AES_BLOCK_SIZE, NULL,
+			AES_MODE_ECB, AES_DIR_DECRYPT);
 }
 
 static int fallback_init_cip(struct crypto_tfm *tfm)
 {
 	const char *name = crypto_tfm_alg_name(tfm);
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
 
-	op->fallback.cip = crypto_alloc_cipher(name, 0,
-					       CRYPTO_ALG_NEED_FALLBACK);
+	tctx->fallback.cip = crypto_alloc_cipher(name, 0,
+						 CRYPTO_ALG_NEED_FALLBACK);
 
-	if (IS_ERR(op->fallback.cip)) {
+	if (IS_ERR(tctx->fallback.cip)) {
 		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
-		return PTR_ERR(op->fallback.cip);
+		return PTR_ERR(tctx->fallback.cip);
 	}
 
 	return 0;
@@ -269,10 +222,9 @@
 
 static void fallback_exit_cip(struct crypto_tfm *tfm)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	struct geode_aes_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
 
-	crypto_free_cipher(op->fallback.cip);
-	op->fallback.cip = NULL;
+	crypto_free_cipher(tctx->fallback.cip);
 }
 
 static struct crypto_alg geode_alg = {
@@ -285,7 +237,7 @@
 	.cra_init			=	fallback_init_cip,
 	.cra_exit			=	fallback_exit_cip,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct geode_aes_op),
+	.cra_ctxsize		=	sizeof(struct geode_aes_tfm_ctx),
 	.cra_module			=	THIS_MODULE,
 	.cra_u				=	{
 		.cipher	=	{
@@ -298,209 +250,126 @@
 	}
 };
 
-static int
-geode_cbc_decrypt(struct blkcipher_desc *desc,
-		  struct scatterlist *dst, struct scatterlist *src,
-		  unsigned int nbytes)
-{
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-	int err, ret;
-
-	if (unlikely(op->keylen != AES_KEYSIZE_128))
-		return fallback_blk_dec(desc, dst, src, nbytes);
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	err = blkcipher_walk_virt(desc, &walk);
-	op->iv = walk.iv;
-
-	while ((nbytes = walk.nbytes)) {
-		op->src = walk.src.virt.addr,
-		op->dst = walk.dst.virt.addr;
-		op->mode = AES_MODE_CBC;
-		op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
-		op->dir = AES_DIR_DECRYPT;
-
-		ret = geode_aes_crypt(op);
-
-		nbytes -= ret;
-		err = blkcipher_walk_done(desc, &walk, nbytes);
-	}
-
-	return err;
-}
-
-static int
-geode_cbc_encrypt(struct blkcipher_desc *desc,
-		  struct scatterlist *dst, struct scatterlist *src,
-		  unsigned int nbytes)
-{
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-	int err, ret;
-
-	if (unlikely(op->keylen != AES_KEYSIZE_128))
-		return fallback_blk_enc(desc, dst, src, nbytes);
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	err = blkcipher_walk_virt(desc, &walk);
-	op->iv = walk.iv;
-
-	while ((nbytes = walk.nbytes)) {
-		op->src = walk.src.virt.addr,
-		op->dst = walk.dst.virt.addr;
-		op->mode = AES_MODE_CBC;
-		op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
-		op->dir = AES_DIR_ENCRYPT;
-
-		ret = geode_aes_crypt(op);
-		nbytes -= ret;
-		err = blkcipher_walk_done(desc, &walk, nbytes);
-	}
-
-	return err;
-}
-
-static int fallback_init_blk(struct crypto_tfm *tfm)
+static int geode_init_skcipher(struct crypto_skcipher *tfm)
 {
-	const char *name = crypto_tfm_alg_name(tfm);
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
-
-	op->fallback.blk = crypto_alloc_blkcipher(name, 0,
-			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+	const char *name = crypto_tfm_alg_name(&tfm->base);
+	struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 
-	if (IS_ERR(op->fallback.blk)) {
+	tctx->fallback.skcipher =
+		crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK |
+				      CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tctx->fallback.skcipher)) {
 		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
-		return PTR_ERR(op->fallback.blk);
+		return PTR_ERR(tctx->fallback.skcipher);
 	}
 
+	crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
+				    crypto_skcipher_reqsize(tctx->fallback.skcipher));
 	return 0;
 }
 
-static void fallback_exit_blk(struct crypto_tfm *tfm)
+static void geode_exit_skcipher(struct crypto_skcipher *tfm)
 {
-	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
 
-	crypto_free_blkcipher(op->fallback.blk);
-	op->fallback.blk = NULL;
+	crypto_free_skcipher(tctx->fallback.skcipher);
 }
 
-static struct crypto_alg geode_cbc_alg = {
-	.cra_name		=	"cbc(aes)",
-	.cra_driver_name	=	"cbc-aes-geode",
-	.cra_priority		=	400,
-	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
-						CRYPTO_ALG_KERN_DRIVER_ONLY |
-						CRYPTO_ALG_NEED_FALLBACK,
-	.cra_init			=	fallback_init_blk,
-	.cra_exit			=	fallback_exit_blk,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct geode_aes_op),
-	.cra_alignmask		=	15,
-	.cra_type			=	&crypto_blkcipher_type,
-	.cra_module			=	THIS_MODULE,
-	.cra_u				=	{
-		.blkcipher	=	{
-			.min_keysize	=	AES_MIN_KEY_SIZE,
-			.max_keysize	=	AES_MAX_KEY_SIZE,
-			.setkey			=	geode_setkey_blk,
-			.encrypt		=	geode_cbc_encrypt,
-			.decrypt		=	geode_cbc_decrypt,
-			.ivsize			=	AES_BLOCK_SIZE,
-		}
+static int geode_skcipher_crypt(struct skcipher_request *req, int mode, int dir)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	const struct geode_aes_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+	struct skcipher_walk walk;
+	unsigned int nbytes;
+	int err;
+
+	if (unlikely(tctx->keylen != AES_KEYSIZE_128)) {
+		struct skcipher_request *subreq = skcipher_request_ctx(req);
+
+		*subreq = *req;
+		skcipher_request_set_tfm(subreq, tctx->fallback.skcipher);
+		if (dir == AES_DIR_DECRYPT)
+			return crypto_skcipher_decrypt(subreq);
+		else
+			return crypto_skcipher_encrypt(subreq);
 	}
-};
 
-static int
-geode_ecb_decrypt(struct blkcipher_desc *desc,
-		  struct scatterlist *dst, struct scatterlist *src,
-		  unsigned int nbytes)
-{
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-	int err, ret;
-
-	if (unlikely(op->keylen != AES_KEYSIZE_128))
-		return fallback_blk_dec(desc, dst, src, nbytes);
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	err = blkcipher_walk_virt(desc, &walk);
-
-	while ((nbytes = walk.nbytes)) {
-		op->src = walk.src.virt.addr,
-		op->dst = walk.dst.virt.addr;
-		op->mode = AES_MODE_ECB;
-		op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
-		op->dir = AES_DIR_DECRYPT;
-
-		ret = geode_aes_crypt(op);
-		nbytes -= ret;
-		err = blkcipher_walk_done(desc, &walk, nbytes);
+	err = skcipher_walk_virt(&walk, req, false);
+
+	while ((nbytes = walk.nbytes) != 0) {
+		geode_aes_crypt(tctx, walk.src.virt.addr, walk.dst.virt.addr,
+				round_down(nbytes, AES_BLOCK_SIZE),
+				walk.iv, mode, dir);
+		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
 	}
 
 	return err;
 }
 
-static int
-geode_ecb_encrypt(struct blkcipher_desc *desc,
-		  struct scatterlist *dst, struct scatterlist *src,
-		  unsigned int nbytes)
-{
-	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-	int err, ret;
-
-	if (unlikely(op->keylen != AES_KEYSIZE_128))
-		return fallback_blk_enc(desc, dst, src, nbytes);
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	err = blkcipher_walk_virt(desc, &walk);
-
-	while ((nbytes = walk.nbytes)) {
-		op->src = walk.src.virt.addr,
-		op->dst = walk.dst.virt.addr;
-		op->mode = AES_MODE_ECB;
-		op->len = nbytes - (nbytes % AES_BLOCK_SIZE);
-		op->dir = AES_DIR_ENCRYPT;
-
-		ret = geode_aes_crypt(op);
-		nbytes -= ret;
-		ret =  blkcipher_walk_done(desc, &walk, nbytes);
-	}
+static int geode_cbc_encrypt(struct skcipher_request *req)
+{
+	return geode_skcipher_crypt(req, AES_MODE_CBC, AES_DIR_ENCRYPT);
+}
 
-	return err;
+static int geode_cbc_decrypt(struct skcipher_request *req)
+{
+	return geode_skcipher_crypt(req, AES_MODE_CBC, AES_DIR_DECRYPT);
 }
 
-static struct crypto_alg geode_ecb_alg = {
-	.cra_name			=	"ecb(aes)",
-	.cra_driver_name	=	"ecb-aes-geode",
-	.cra_priority		=	400,
-	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
-						CRYPTO_ALG_KERN_DRIVER_ONLY |
-						CRYPTO_ALG_NEED_FALLBACK,
-	.cra_init			=	fallback_init_blk,
-	.cra_exit			=	fallback_exit_blk,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct geode_aes_op),
-	.cra_alignmask		=	15,
-	.cra_type			=	&crypto_blkcipher_type,
-	.cra_module			=	THIS_MODULE,
-	.cra_u				=	{
-		.blkcipher	=	{
-			.min_keysize	=	AES_MIN_KEY_SIZE,
-			.max_keysize	=	AES_MAX_KEY_SIZE,
-			.setkey			=	geode_setkey_blk,
-			.encrypt		=	geode_ecb_encrypt,
-			.decrypt		=	geode_ecb_decrypt,
-		}
-	}
+static int geode_ecb_encrypt(struct skcipher_request *req)
+{
+	return geode_skcipher_crypt(req, AES_MODE_ECB, AES_DIR_ENCRYPT);
+}
+
+static int geode_ecb_decrypt(struct skcipher_request *req)
+{
+	return geode_skcipher_crypt(req, AES_MODE_ECB, AES_DIR_DECRYPT);
+}
+
+static struct skcipher_alg geode_skcipher_algs[] = {
+	{
+		.base.cra_name		= "cbc(aes)",
+		.base.cra_driver_name	= "cbc-aes-geode",
+		.base.cra_priority	= 400,
+		.base.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.base.cra_blocksize	= AES_BLOCK_SIZE,
+		.base.cra_ctxsize	= sizeof(struct geode_aes_tfm_ctx),
+		.base.cra_alignmask	= 15,
+		.base.cra_module	= THIS_MODULE,
+		.init			= geode_init_skcipher,
+		.exit			= geode_exit_skcipher,
+		.setkey			= geode_setkey_skcipher,
+		.encrypt		= geode_cbc_encrypt,
+		.decrypt		= geode_cbc_decrypt,
+		.min_keysize		= AES_MIN_KEY_SIZE,
+		.max_keysize		= AES_MAX_KEY_SIZE,
+		.ivsize			= AES_BLOCK_SIZE,
+	}, {
+		.base.cra_name		= "ecb(aes)",
+		.base.cra_driver_name	= "ecb-aes-geode",
+		.base.cra_priority	= 400,
+		.base.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
+					  CRYPTO_ALG_NEED_FALLBACK,
+		.base.cra_blocksize	= AES_BLOCK_SIZE,
+		.base.cra_ctxsize	= sizeof(struct geode_aes_tfm_ctx),
+		.base.cra_alignmask	= 15,
+		.base.cra_module	= THIS_MODULE,
+		.init			= geode_init_skcipher,
+		.exit			= geode_exit_skcipher,
+		.setkey			= geode_setkey_skcipher,
+		.encrypt		= geode_ecb_encrypt,
+		.decrypt		= geode_ecb_decrypt,
+		.min_keysize		= AES_MIN_KEY_SIZE,
+		.max_keysize		= AES_MAX_KEY_SIZE,
+	},
 };
 
 static void geode_aes_remove(struct pci_dev *dev)
 {
 	crypto_unregister_alg(&geode_alg);
-	crypto_unregister_alg(&geode_ecb_alg);
-	crypto_unregister_alg(&geode_cbc_alg);
+	crypto_unregister_skciphers(geode_skcipher_algs,
+				    ARRAY_SIZE(geode_skcipher_algs));
 
 	pci_iounmap(dev, _iobase);
 	_iobase = NULL;
@@ -538,20 +407,14 @@
 	if (ret)
 		goto eiomap;
 
-	ret = crypto_register_alg(&geode_ecb_alg);
+	ret = crypto_register_skciphers(geode_skcipher_algs,
+					ARRAY_SIZE(geode_skcipher_algs));
 	if (ret)
 		goto ealg;
 
-	ret = crypto_register_alg(&geode_cbc_alg);
-	if (ret)
-		goto eecb;
-
 	dev_notice(&dev->dev, "GEODE AES engine enabled.\n");
 	return 0;
 
- eecb:
-	crypto_unregister_alg(&geode_ecb_alg);
-
  ealg:
 	crypto_unregister_alg(&geode_alg);
 
--- linux-ein-5.4.0.orig/drivers/crypto/geode-aes.h
+++ linux-ein-5.4.0/drivers/crypto/geode-aes.h
@@ -46,21 +46,10 @@
 
 #define AES_OP_TIMEOUT    0x50000
 
-struct geode_aes_op {
-
-	void *src;
-	void *dst;
-
-	u32 mode;
-	u32 dir;
-	u32 flags;
-	int len;
-
+struct geode_aes_tfm_ctx {
 	u8 key[AES_KEYSIZE_128];
-	u8 *iv;
-
 	union {
-		struct crypto_blkcipher *blk;
+		struct crypto_skcipher *skcipher;
 		struct crypto_cipher *cip;
 	} fallback;
 	u32 keylen;
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/Kconfig
@@ -14,26 +14,53 @@
 	  To compile this as a module, choose M here: the module
 	  will be called hisi_sec.
 
+config CRYPTO_DEV_HISI_SEC2
+	tristate "Support for HiSilicon SEC2 crypto block cipher accelerator"
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_ALGAPI
+	select CRYPTO_LIB_DES
+	select CRYPTO_DEV_HISI_QM
+	select CRYPTO_AEAD
+	select CRYPTO_AUTHENC
+	select CRYPTO_HMAC
+	select CRYPTO_SHA1
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	depends on PCI && PCI_MSI
+	depends on ARM64 || (COMPILE_TEST && 64BIT)
+	help
+	  Support for HiSilicon SEC Engine of version 2 in crypto subsystem.
+	  It provides AES, SM4, and 3DES algorithms with ECB
+	  CBC, and XTS cipher mode, and AEAD algorithms.
+
+	  To compile this as a module, choose M here: the module
+          will be called hisi_sec2.
+
 config CRYPTO_DEV_HISI_QM
 	tristate
-	depends on ARM64 && PCI && PCI_MSI
+	depends on ARM64 || COMPILE_TEST
+	depends on PCI && PCI_MSI
+	select NEED_SG_DMA_LENGTH
 	help
 	  HiSilicon accelerator engines use a common queue management
 	  interface. Specific engine driver may use this module.
 
-config CRYPTO_HISI_SGL
-	tristate
-	depends on ARM64
-	help
-	  HiSilicon accelerator engines use a common hardware scatterlist
-	  interface for data format. Specific engine driver may use this
-	  module.
-
 config CRYPTO_DEV_HISI_ZIP
 	tristate "Support for HiSilicon ZIP accelerator"
-	depends on ARM64 && PCI && PCI_MSI
+	depends on PCI && PCI_MSI
+	depends on ARM64 || (COMPILE_TEST && 64BIT)
+	depends on !CPU_BIG_ENDIAN || COMPILE_TEST
 	select CRYPTO_DEV_HISI_QM
-	select CRYPTO_HISI_SGL
-	select SG_SPLIT
 	help
 	  Support for HiSilicon ZIP Driver
+
+config CRYPTO_DEV_HISI_HPRE
+	tristate "Support for HISI HPRE accelerator"
+	depends on PCI && PCI_MSI
+	depends on ARM64 || (COMPILE_TEST && 64BIT)
+	select CRYPTO_DEV_HISI_QM
+	select CRYPTO_DH
+	select CRYPTO_RSA
+	help
+	  Support for HiSilicon HPRE(High Performance RSA Engine)
+	  accelerator, which can accelerate RSA and DH algorithms.
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/Makefile
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/Makefile
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hpre/
 obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += sec/
-obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += qm.o
-obj-$(CONFIG_CRYPTO_HISI_SGL) += sgl.o
+obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
+obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
+hisi_qm-objs = qm.o sgl.o
 obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/hpre/Makefile
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/hpre/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hisi_hpre.o
+hisi_hpre-objs = hpre_main.o hpre_crypto.o
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/hpre/hpre.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/hpre/hpre.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2019 HiSilicon Limited. */
+#ifndef __HISI_HPRE_H
+#define __HISI_HPRE_H
+
+#include <linux/list.h>
+#include "../qm.h"
+
+#define HPRE_SQE_SIZE			sizeof(struct hpre_sqe)
+#define HPRE_PF_DEF_Q_NUM		64
+#define HPRE_PF_DEF_Q_BASE		0
+
+enum {
+	HPRE_CLUSTER0,
+	HPRE_CLUSTER1,
+	HPRE_CLUSTER2,
+	HPRE_CLUSTER3,
+	HPRE_CLUSTERS_NUM,
+};
+
+enum hpre_ctrl_dbgfs_file {
+	HPRE_CURRENT_QM,
+	HPRE_CLEAR_ENABLE,
+	HPRE_CLUSTER_CTRL,
+	HPRE_DEBUG_FILE_NUM,
+};
+
+#define HPRE_DEBUGFS_FILE_NUM    (HPRE_DEBUG_FILE_NUM + HPRE_CLUSTERS_NUM - 1)
+
+struct hpre_debugfs_file {
+	int index;
+	enum hpre_ctrl_dbgfs_file type;
+	spinlock_t lock;
+	struct hpre_debug *debug;
+};
+
+/*
+ * One HPRE controller has one PF and multiple VFs, some global configurations
+ * which PF has need this structure.
+ * Just relevant for PF.
+ */
+struct hpre_debug {
+	struct dentry *debug_root;
+	struct hpre_debugfs_file files[HPRE_DEBUGFS_FILE_NUM];
+};
+
+struct hpre {
+	struct hisi_qm qm;
+	struct list_head list;
+	struct hpre_debug debug;
+	u32 num_vfs;
+	unsigned long status;
+};
+
+enum hpre_alg_type {
+	HPRE_ALG_NC_NCRT = 0x0,
+	HPRE_ALG_NC_CRT = 0x1,
+	HPRE_ALG_KG_STD = 0x2,
+	HPRE_ALG_KG_CRT = 0x3,
+	HPRE_ALG_DH_G2 = 0x4,
+	HPRE_ALG_DH = 0x5,
+};
+
+struct hpre_sqe {
+	__le32 dw0;
+	__u8 task_len1;
+	__u8 task_len2;
+	__u8 mrttest_num;
+	__u8 resv1;
+	__le64 key;
+	__le64 in;
+	__le64 out;
+	__le16 tag;
+	__le16 resv2;
+#define _HPRE_SQE_ALIGN_EXT	7
+	__le32 rsvd1[_HPRE_SQE_ALIGN_EXT];
+};
+
+struct hpre *hpre_find_device(int node);
+int hpre_algs_register(void);
+void hpre_algs_unregister(void);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/hpre/hpre_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/hpre/hpre_crypto.c
@@ -0,0 +1,1134 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 HiSilicon Limited. */
+#include <crypto/akcipher.h>
+#include <crypto/dh.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/internal/rsa.h>
+#include <crypto/kpp.h>
+#include <crypto/scatterwalk.h>
+#include <linux/dma-mapping.h>
+#include <linux/fips.h>
+#include <linux/module.h>
+#include "hpre.h"
+
+struct hpre_ctx;
+
+#define HPRE_CRYPTO_ALG_PRI	1000
+#define HPRE_ALIGN_SZ		64
+#define HPRE_BITS_2_BYTES_SHIFT	3
+#define HPRE_RSA_512BITS_KSZ	64
+#define HPRE_RSA_1536BITS_KSZ	192
+#define HPRE_CRT_PRMS		5
+#define HPRE_CRT_Q		2
+#define HPRE_CRT_P		3
+#define HPRE_CRT_INV		4
+#define HPRE_DH_G_FLAG		0x02
+#define HPRE_TRY_SEND_TIMES	100
+#define HPRE_INVLD_REQ_ID		(-1)
+#define HPRE_DEV(ctx)		(&((ctx)->qp->qm->pdev->dev))
+
+#define HPRE_SQE_ALG_BITS	5
+#define HPRE_SQE_DONE_SHIFT	30
+#define HPRE_DH_MAX_P_SZ	512
+
+typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe);
+
+struct hpre_rsa_ctx {
+	/* low address: e--->n */
+	char *pubkey;
+	dma_addr_t dma_pubkey;
+
+	/* low address: d--->n */
+	char *prikey;
+	dma_addr_t dma_prikey;
+
+	/* low address: dq->dp->q->p->qinv */
+	char *crt_prikey;
+	dma_addr_t dma_crt_prikey;
+
+	struct crypto_akcipher *soft_tfm;
+};
+
+struct hpre_dh_ctx {
+	/*
+	 * 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]
+	 */
+	char *xa_p; /* low address: d--->n, please refer to Hisilicon HPRE UM */
+	dma_addr_t dma_xa_p;
+
+	char *g; /* m */
+	dma_addr_t dma_g;
+};
+
+struct hpre_ctx {
+	struct hisi_qp *qp;
+	struct hpre_asym_request **req_list;
+	spinlock_t req_lock;
+	unsigned int key_sz;
+	bool crt_g2_mode;
+	struct idr req_idr;
+	union {
+		struct hpre_rsa_ctx rsa;
+		struct hpre_dh_ctx dh;
+	};
+};
+
+struct hpre_asym_request {
+	char *src;
+	char *dst;
+	struct hpre_sqe req;
+	struct hpre_ctx *ctx;
+	union {
+		struct akcipher_request *rsa;
+		struct kpp_request *dh;
+	} areq;
+	int err;
+	int req_id;
+	hpre_cb cb;
+};
+
+static DEFINE_MUTEX(hpre_alg_lock);
+static unsigned int hpre_active_devs;
+
+static int hpre_alloc_req_id(struct hpre_ctx *ctx)
+{
+	unsigned long flags;
+	int id;
+
+	spin_lock_irqsave(&ctx->req_lock, flags);
+	id = idr_alloc(&ctx->req_idr, NULL, 0, QM_Q_DEPTH, GFP_ATOMIC);
+	spin_unlock_irqrestore(&ctx->req_lock, flags);
+
+	return id;
+}
+
+static void hpre_free_req_id(struct hpre_ctx *ctx, int req_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->req_lock, flags);
+	idr_remove(&ctx->req_idr, req_id);
+	spin_unlock_irqrestore(&ctx->req_lock, flags);
+}
+
+static int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req)
+{
+	struct hpre_ctx *ctx;
+	int id;
+
+	ctx = hpre_req->ctx;
+	id = hpre_alloc_req_id(ctx);
+	if (unlikely(id < 0))
+		return -EINVAL;
+
+	ctx->req_list[id] = hpre_req;
+	hpre_req->req_id = id;
+
+	return id;
+}
+
+static void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req)
+{
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	int id = hpre_req->req_id;
+
+	if (hpre_req->req_id >= 0) {
+		hpre_req->req_id = HPRE_INVLD_REQ_ID;
+		ctx->req_list[id] = NULL;
+		hpre_free_req_id(ctx, id);
+	}
+}
+
+static struct hisi_qp *hpre_get_qp_and_start(void)
+{
+	struct hisi_qp *qp;
+	struct hpre *hpre;
+	int ret;
+
+	/* find the proper hpre device, which is near the current CPU core */
+	hpre = hpre_find_device(cpu_to_node(smp_processor_id()));
+	if (!hpre) {
+		pr_err("Can not find proper hpre device!\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	qp = hisi_qm_create_qp(&hpre->qm, 0);
+	if (IS_ERR(qp)) {
+		pci_err(hpre->qm.pdev, "Can not create qp!\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	ret = hisi_qm_start_qp(qp, 0);
+	if (ret < 0) {
+		hisi_qm_release_qp(qp);
+		pci_err(hpre->qm.pdev, "Can not start qp!\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return qp;
+}
+
+static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req,
+				  struct scatterlist *data, unsigned int len,
+				  int is_src, dma_addr_t *tmp)
+{
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	struct device *dev = HPRE_DEV(ctx);
+	enum dma_data_direction dma_dir;
+
+	if (is_src) {
+		hpre_req->src = NULL;
+		dma_dir = DMA_TO_DEVICE;
+	} else {
+		hpre_req->dst = NULL;
+		dma_dir = DMA_FROM_DEVICE;
+	}
+	*tmp = dma_map_single(dev, sg_virt(data),
+			      len, dma_dir);
+	if (unlikely(dma_mapping_error(dev, *tmp))) {
+		dev_err(dev, "dma map data err!\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req,
+				struct scatterlist *data, unsigned int len,
+				int is_src, dma_addr_t *tmp)
+{
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	struct device *dev = HPRE_DEV(ctx);
+	void *ptr;
+	int shift;
+
+	shift = ctx->key_sz - len;
+	if (unlikely(shift < 0))
+		return -EINVAL;
+
+	ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, GFP_KERNEL);
+	if (unlikely(!ptr))
+		return -ENOMEM;
+
+	if (is_src) {
+		scatterwalk_map_and_copy(ptr + shift, data, 0, len, 0);
+		hpre_req->src = ptr;
+	} else {
+		hpre_req->dst = ptr;
+	}
+
+	return 0;
+}
+
+static int hpre_hw_data_init(struct hpre_asym_request *hpre_req,
+			     struct scatterlist *data, unsigned int len,
+			     int is_src, int is_dh)
+{
+	struct hpre_sqe *msg = &hpre_req->req;
+	struct hpre_ctx *ctx = hpre_req->ctx;
+	dma_addr_t tmp = 0;
+	int ret;
+
+	/* when the data is dh's source, we should format it */
+	if ((sg_is_last(data) && len == ctx->key_sz) &&
+	    ((is_dh && !is_src) || !is_dh))
+		ret = hpre_get_data_dma_addr(hpre_req, data, len, is_src, &tmp);
+	else
+		ret = hpre_prepare_dma_buf(hpre_req, data, len,
+					  is_src, &tmp);
+	if (unlikely(ret))
+		return ret;
+
+	if (is_src)
+		msg->in = cpu_to_le64(tmp);
+	else
+		msg->out = cpu_to_le64(tmp);
+
+	return 0;
+}
+
+static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
+				 struct hpre_asym_request *req,
+				 struct scatterlist *dst,
+				 struct scatterlist *src)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	struct hpre_sqe *sqe = &req->req;
+	dma_addr_t tmp;
+
+	tmp = le64_to_cpu(sqe->in);
+	if (unlikely(!tmp))
+		return;
+
+	if (src) {
+		if (req->src)
+			dma_free_coherent(dev, ctx->key_sz,
+					  req->src, tmp);
+		else
+			dma_unmap_single(dev, tmp,
+					 ctx->key_sz, DMA_TO_DEVICE);
+	}
+
+	tmp = le64_to_cpu(sqe->out);
+	if (unlikely(!tmp))
+		return;
+
+	if (req->dst) {
+		if (dst)
+			scatterwalk_map_and_copy(req->dst, dst, 0,
+						 ctx->key_sz, 1);
+		dma_free_coherent(dev, ctx->key_sz, req->dst, tmp);
+	} else {
+		dma_unmap_single(dev, tmp, ctx->key_sz, DMA_FROM_DEVICE);
+	}
+}
+
+static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe,
+				void **kreq)
+{
+	struct hpre_asym_request *req;
+	int err, id, done;
+
+#define HPRE_NO_HW_ERR		0
+#define HPRE_HW_TASK_DONE	3
+#define HREE_HW_ERR_MASK	0x7ff
+#define HREE_SQE_DONE_MASK	0x3
+	id = (int)le16_to_cpu(sqe->tag);
+	req = ctx->req_list[id];
+	hpre_rm_req_from_ctx(req);
+	*kreq = req;
+
+	err = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_ALG_BITS) &
+		HREE_HW_ERR_MASK;
+
+	done = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_DONE_SHIFT) &
+		HREE_SQE_DONE_MASK;
+
+	if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE))
+		return  0;
+
+	return -EINVAL;
+}
+
+static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen)
+{
+	if (!ctx || !qp || qlen < 0)
+		return -EINVAL;
+
+	spin_lock_init(&ctx->req_lock);
+	ctx->qp = qp;
+
+	ctx->req_list = kcalloc(qlen, sizeof(void *), GFP_KERNEL);
+	if (!ctx->req_list)
+		return -ENOMEM;
+	ctx->key_sz = 0;
+	ctx->crt_g2_mode = false;
+	idr_init(&ctx->req_idr);
+
+	return 0;
+}
+
+static void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all)
+{
+	if (is_clear_all) {
+		idr_destroy(&ctx->req_idr);
+		kfree(ctx->req_list);
+		hisi_qm_release_qp(ctx->qp);
+	}
+
+	ctx->crt_g2_mode = false;
+	ctx->key_sz = 0;
+}
+
+static void hpre_dh_cb(struct hpre_ctx *ctx, void *resp)
+{
+	struct hpre_asym_request *req;
+	struct kpp_request *areq;
+	int ret;
+
+	ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req);
+	areq = req->areq.dh;
+	areq->dst_len = ctx->key_sz;
+	hpre_hw_data_clr_all(ctx, req, areq->dst, areq->src);
+	kpp_request_complete(areq, ret);
+}
+
+static void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp)
+{
+	struct hpre_asym_request *req;
+	struct akcipher_request *areq;
+	int ret;
+
+	ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req);
+	areq = req->areq.rsa;
+	areq->dst_len = ctx->key_sz;
+	hpre_hw_data_clr_all(ctx, req, areq->dst, areq->src);
+	akcipher_request_complete(areq, ret);
+}
+
+static void hpre_alg_cb(struct hisi_qp *qp, void *resp)
+{
+	struct hpre_ctx *ctx = qp->qp_ctx;
+	struct hpre_sqe *sqe = resp;
+
+	ctx->req_list[le16_to_cpu(sqe->tag)]->cb(ctx, resp);
+}
+
+static int hpre_ctx_init(struct hpre_ctx *ctx)
+{
+	struct hisi_qp *qp;
+
+	qp = hpre_get_qp_and_start();
+	if (IS_ERR(qp))
+		return PTR_ERR(qp);
+
+	qp->qp_ctx = ctx;
+	qp->req_cb = hpre_alg_cb;
+
+	return hpre_ctx_set(ctx, qp, QM_Q_DEPTH);
+}
+
+static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa)
+{
+	struct hpre_asym_request *h_req;
+	struct hpre_sqe *msg;
+	int req_id;
+	void *tmp;
+
+	if (is_rsa) {
+		struct akcipher_request *akreq = req;
+
+		if (akreq->dst_len < ctx->key_sz) {
+			akreq->dst_len = ctx->key_sz;
+			return -EOVERFLOW;
+		}
+
+		tmp = akcipher_request_ctx(akreq);
+		h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+		h_req->cb = hpre_rsa_cb;
+		h_req->areq.rsa = akreq;
+		msg = &h_req->req;
+		memset(msg, 0, sizeof(*msg));
+	} else {
+		struct kpp_request *kreq = req;
+
+		if (kreq->dst_len < ctx->key_sz) {
+			kreq->dst_len = ctx->key_sz;
+			return -EOVERFLOW;
+		}
+
+		tmp = kpp_request_ctx(kreq);
+		h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+		h_req->cb = hpre_dh_cb;
+		h_req->areq.dh = kreq;
+		msg = &h_req->req;
+		memset(msg, 0, sizeof(*msg));
+		msg->key = cpu_to_le64((u64)ctx->dh.dma_xa_p);
+	}
+
+	msg->dw0 |= cpu_to_le32(0x1 << HPRE_SQE_DONE_SHIFT);
+	msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1;
+	h_req->ctx = ctx;
+
+	req_id = hpre_add_req_to_ctx(h_req);
+	if (req_id < 0)
+		return -EBUSY;
+
+	msg->tag = cpu_to_le16((u16)req_id);
+
+	return 0;
+}
+
+#ifdef CONFIG_CRYPTO_DH
+static int hpre_dh_compute_value(struct kpp_request *req)
+{
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+	void *tmp = kpp_request_ctx(req);
+	struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+	struct hpre_sqe *msg = &hpre_req->req;
+	int ctr = 0;
+	int ret;
+
+	ret = hpre_msg_request_set(ctx, req, false);
+	if (unlikely(ret))
+		return ret;
+
+	if (req->src) {
+		ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 1);
+		if (unlikely(ret))
+			goto clear_all;
+	}
+
+	ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 1);
+	if (unlikely(ret))
+		goto clear_all;
+
+	if (ctx->crt_g2_mode && !req->src)
+		msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_DH_G2);
+	else
+		msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_DH);
+	do {
+		ret = hisi_qp_send(ctx->qp, msg);
+	} while (ret == -EBUSY && ctr++ < HPRE_TRY_SEND_TIMES);
+
+	/* success */
+	if (likely(!ret))
+		return -EINPROGRESS;
+
+clear_all:
+	hpre_rm_req_from_ctx(hpre_req);
+	hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src);
+
+	return ret;
+}
+
+static int hpre_is_dh_params_length_valid(unsigned int key_sz)
+{
+#define _HPRE_DH_GRP1		768
+#define _HPRE_DH_GRP2		1024
+#define _HPRE_DH_GRP5		1536
+#define _HPRE_DH_GRP14		2048
+#define _HPRE_DH_GRP15		3072
+#define _HPRE_DH_GRP16		4096
+	switch (key_sz) {
+	case _HPRE_DH_GRP1:
+	case _HPRE_DH_GRP2:
+	case _HPRE_DH_GRP5:
+	case _HPRE_DH_GRP14:
+	case _HPRE_DH_GRP15:
+	case _HPRE_DH_GRP16:
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int sz;
+
+	if (params->p_size > HPRE_DH_MAX_P_SZ)
+		return -EINVAL;
+
+	if (hpre_is_dh_params_length_valid(params->p_size <<
+					   HPRE_BITS_2_BYTES_SHIFT))
+		return -EINVAL;
+
+	sz = ctx->key_sz = params->p_size;
+	ctx->dh.xa_p = dma_alloc_coherent(dev, sz << 1,
+					  &ctx->dh.dma_xa_p, GFP_KERNEL);
+	if (!ctx->dh.xa_p)
+		return -ENOMEM;
+
+	memcpy(ctx->dh.xa_p + sz, params->p, sz);
+
+	/* If g equals 2 don't copy it */
+	if (params->g_size == 1 && *(char *)params->g == HPRE_DH_G_FLAG) {
+		ctx->crt_g2_mode = true;
+		return 0;
+	}
+
+	ctx->dh.g = dma_alloc_coherent(dev, sz, &ctx->dh.dma_g, GFP_KERNEL);
+	if (!ctx->dh.g) {
+		dma_free_coherent(dev, sz << 1, ctx->dh.xa_p,
+				  ctx->dh.dma_xa_p);
+		ctx->dh.xa_p = NULL;
+		return -ENOMEM;
+	}
+
+	memcpy(ctx->dh.g + (sz - params->g_size), params->g, params->g_size);
+
+	return 0;
+}
+
+static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
+{
+	struct device *dev = HPRE_DEV(ctx);
+	unsigned int sz = ctx->key_sz;
+
+	if (is_clear_all)
+		hisi_qm_stop_qp(ctx->qp);
+
+	if (ctx->dh.g) {
+		dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g);
+		ctx->dh.g = NULL;
+	}
+
+	if (ctx->dh.xa_p) {
+		memzero_explicit(ctx->dh.xa_p, sz);
+		dma_free_coherent(dev, sz << 1, ctx->dh.xa_p,
+				  ctx->dh.dma_xa_p);
+		ctx->dh.xa_p = NULL;
+	}
+
+	hpre_ctx_clear(ctx, is_clear_all);
+}
+
+static int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf,
+			      unsigned int len)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+	struct dh params;
+	int ret;
+
+	if (crypto_dh_decode_key(buf, len, &params) < 0)
+		return -EINVAL;
+
+	/* Free old secret if any */
+	hpre_dh_clear_ctx(ctx, false);
+
+	ret = hpre_dh_set_params(ctx, &params);
+	if (ret < 0)
+		goto err_clear_ctx;
+
+	memcpy(ctx->dh.xa_p + (ctx->key_sz - params.key_size), params.key,
+	       params.key_size);
+
+	return 0;
+
+err_clear_ctx:
+	hpre_dh_clear_ctx(ctx, false);
+	return ret;
+}
+
+static unsigned int hpre_dh_max_size(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	return ctx->key_sz;
+}
+
+static int hpre_dh_init_tfm(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	return hpre_ctx_init(ctx);
+}
+
+static void hpre_dh_exit_tfm(struct crypto_kpp *tfm)
+{
+	struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+	hpre_dh_clear_ctx(ctx, true);
+}
+#endif
+
+static void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len)
+{
+	while (!**ptr && *len) {
+		(*ptr)++;
+		(*len)--;
+	}
+}
+
+static bool hpre_rsa_key_size_is_support(unsigned int len)
+{
+	unsigned int bits = len << HPRE_BITS_2_BYTES_SHIFT;
+
+#define _RSA_1024BITS_KEY_WDTH		1024
+#define _RSA_2048BITS_KEY_WDTH		2048
+#define _RSA_3072BITS_KEY_WDTH		3072
+#define _RSA_4096BITS_KEY_WDTH		4096
+
+	switch (bits) {
+	case _RSA_1024BITS_KEY_WDTH:
+	case _RSA_2048BITS_KEY_WDTH:
+	case _RSA_3072BITS_KEY_WDTH:
+	case _RSA_4096BITS_KEY_WDTH:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int hpre_rsa_enc(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+	void *tmp = akcipher_request_ctx(req);
+	struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+	struct hpre_sqe *msg = &hpre_req->req;
+	int ctr = 0;
+	int ret;
+
+	/* For 512 and 1536 bits key size, use soft tfm instead */
+	if (ctx->key_sz == HPRE_RSA_512BITS_KSZ ||
+	    ctx->key_sz == HPRE_RSA_1536BITS_KSZ) {
+		akcipher_request_set_tfm(req, ctx->rsa.soft_tfm);
+		ret = crypto_akcipher_encrypt(req);
+		akcipher_request_set_tfm(req, tfm);
+		return ret;
+	}
+
+	if (unlikely(!ctx->rsa.pubkey))
+		return -EINVAL;
+
+	ret = hpre_msg_request_set(ctx, req, true);
+	if (unlikely(ret))
+		return ret;
+
+	msg->dw0 |= cpu_to_le32(HPRE_ALG_NC_NCRT);
+	msg->key = cpu_to_le64((u64)ctx->rsa.dma_pubkey);
+
+	ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 0);
+	if (unlikely(ret))
+		goto clear_all;
+
+	ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 0);
+	if (unlikely(ret))
+		goto clear_all;
+
+	do {
+		ret = hisi_qp_send(ctx->qp, msg);
+	} while (ret == -EBUSY && ctr++ < HPRE_TRY_SEND_TIMES);
+
+	/* success */
+	if (likely(!ret))
+		return -EINPROGRESS;
+
+clear_all:
+	hpre_rm_req_from_ctx(hpre_req);
+	hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src);
+
+	return ret;
+}
+
+static int hpre_rsa_dec(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+	void *tmp = akcipher_request_ctx(req);
+	struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
+	struct hpre_sqe *msg = &hpre_req->req;
+	int ctr = 0;
+	int ret;
+
+	/* For 512 and 1536 bits key size, use soft tfm instead */
+	if (ctx->key_sz == HPRE_RSA_512BITS_KSZ ||
+	    ctx->key_sz == HPRE_RSA_1536BITS_KSZ) {
+		akcipher_request_set_tfm(req, ctx->rsa.soft_tfm);
+		ret = crypto_akcipher_decrypt(req);
+		akcipher_request_set_tfm(req, tfm);
+		return ret;
+	}
+
+	if (unlikely(!ctx->rsa.prikey))
+		return -EINVAL;
+
+	ret = hpre_msg_request_set(ctx, req, true);
+	if (unlikely(ret))
+		return ret;
+
+	if (ctx->crt_g2_mode) {
+		msg->key = cpu_to_le64((u64)ctx->rsa.dma_crt_prikey);
+		msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) |
+				       HPRE_ALG_NC_CRT);
+	} else {
+		msg->key = cpu_to_le64((u64)ctx->rsa.dma_prikey);
+		msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) |
+				       HPRE_ALG_NC_NCRT);
+	}
+
+	ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 0);
+	if (unlikely(ret))
+		goto clear_all;
+
+	ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 0);
+	if (unlikely(ret))
+		goto clear_all;
+
+	do {
+		ret = hisi_qp_send(ctx->qp, msg);
+	} while (ret == -EBUSY && ctr++ < HPRE_TRY_SEND_TIMES);
+
+	/* success */
+	if (likely(!ret))
+		return -EINPROGRESS;
+
+clear_all:
+	hpre_rm_req_from_ctx(hpre_req);
+	hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src);
+
+	return ret;
+}
+
+static int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value,
+			  size_t vlen, bool private)
+{
+	const char *ptr = value;
+
+	hpre_rsa_drop_leading_zeros(&ptr, &vlen);
+
+	ctx->key_sz = vlen;
+
+	/* if invalid key size provided, we use software tfm */
+	if (!hpre_rsa_key_size_is_support(ctx->key_sz))
+		return 0;
+
+	ctx->rsa.pubkey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+					     &ctx->rsa.dma_pubkey,
+					     GFP_KERNEL);
+	if (!ctx->rsa.pubkey)
+		return -ENOMEM;
+
+	if (private) {
+		ctx->rsa.prikey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+						     &ctx->rsa.dma_prikey,
+						     GFP_KERNEL);
+		if (!ctx->rsa.prikey) {
+			dma_free_coherent(HPRE_DEV(ctx), vlen << 1,
+					  ctx->rsa.pubkey,
+					  ctx->rsa.dma_pubkey);
+			ctx->rsa.pubkey = NULL;
+			return -ENOMEM;
+		}
+		memcpy(ctx->rsa.prikey + vlen, ptr, vlen);
+	}
+	memcpy(ctx->rsa.pubkey + vlen, ptr, vlen);
+
+	/* Using hardware HPRE to do RSA */
+	return 1;
+}
+
+static int hpre_rsa_set_e(struct hpre_ctx *ctx, const char *value,
+			  size_t vlen)
+{
+	const char *ptr = value;
+
+	hpre_rsa_drop_leading_zeros(&ptr, &vlen);
+
+	if (!ctx->key_sz || !vlen || vlen > ctx->key_sz)
+		return -EINVAL;
+
+	memcpy(ctx->rsa.pubkey + ctx->key_sz - vlen, ptr, vlen);
+
+	return 0;
+}
+
+static int hpre_rsa_set_d(struct hpre_ctx *ctx, const char *value,
+			  size_t vlen)
+{
+	const char *ptr = value;
+
+	hpre_rsa_drop_leading_zeros(&ptr, &vlen);
+
+	if (!ctx->key_sz || !vlen || vlen > ctx->key_sz)
+		return -EINVAL;
+
+	memcpy(ctx->rsa.prikey + ctx->key_sz - vlen, ptr, vlen);
+
+	return 0;
+}
+
+static int hpre_crt_para_get(char *para, size_t para_sz,
+			     const char *raw, size_t raw_sz)
+{
+	const char *ptr = raw;
+	size_t len = raw_sz;
+
+	hpre_rsa_drop_leading_zeros(&ptr, &len);
+	if (!len || len > para_sz)
+		return -EINVAL;
+
+	memcpy(para + para_sz - len, ptr, len);
+
+	return 0;
+}
+
+static int hpre_rsa_setkey_crt(struct hpre_ctx *ctx, struct rsa_key *rsa_key)
+{
+	unsigned int hlf_ksz = ctx->key_sz >> 1;
+	struct device *dev = HPRE_DEV(ctx);
+	u64 offset;
+	int ret;
+
+	ctx->rsa.crt_prikey = dma_alloc_coherent(dev, hlf_ksz * HPRE_CRT_PRMS,
+					&ctx->rsa.dma_crt_prikey,
+					GFP_KERNEL);
+	if (!ctx->rsa.crt_prikey)
+		return -ENOMEM;
+
+	ret = hpre_crt_para_get(ctx->rsa.crt_prikey, hlf_ksz,
+				rsa_key->dq, rsa_key->dq_sz);
+	if (ret)
+		goto free_key;
+
+	offset = hlf_ksz;
+	ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz,
+				rsa_key->dp, rsa_key->dp_sz);
+	if (ret)
+		goto free_key;
+
+	offset = hlf_ksz * HPRE_CRT_Q;
+	ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz,
+				rsa_key->q, rsa_key->q_sz);
+	if (ret)
+		goto free_key;
+
+	offset = hlf_ksz * HPRE_CRT_P;
+	ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz,
+				rsa_key->p, rsa_key->p_sz);
+	if (ret)
+		goto free_key;
+
+	offset = hlf_ksz * HPRE_CRT_INV;
+	ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz,
+				rsa_key->qinv, rsa_key->qinv_sz);
+	if (ret)
+		goto free_key;
+
+	ctx->crt_g2_mode = true;
+
+	return 0;
+
+free_key:
+	offset = hlf_ksz * HPRE_CRT_PRMS;
+	memzero_explicit(ctx->rsa.crt_prikey, offset);
+	dma_free_coherent(dev, hlf_ksz * HPRE_CRT_PRMS, ctx->rsa.crt_prikey,
+			  ctx->rsa.dma_crt_prikey);
+	ctx->rsa.crt_prikey = NULL;
+	ctx->crt_g2_mode = false;
+
+	return ret;
+}
+
+/* If it is clear all, all the resources of the QP will be cleaned. */
+static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
+{
+	unsigned int half_key_sz = ctx->key_sz >> 1;
+	struct device *dev = HPRE_DEV(ctx);
+
+	if (is_clear_all)
+		hisi_qm_stop_qp(ctx->qp);
+
+	if (ctx->rsa.pubkey) {
+		dma_free_coherent(dev, ctx->key_sz << 1,
+				  ctx->rsa.pubkey, ctx->rsa.dma_pubkey);
+		ctx->rsa.pubkey = NULL;
+	}
+
+	if (ctx->rsa.crt_prikey) {
+		memzero_explicit(ctx->rsa.crt_prikey,
+				 half_key_sz * HPRE_CRT_PRMS);
+		dma_free_coherent(dev, half_key_sz * HPRE_CRT_PRMS,
+				  ctx->rsa.crt_prikey, ctx->rsa.dma_crt_prikey);
+		ctx->rsa.crt_prikey = NULL;
+	}
+
+	if (ctx->rsa.prikey) {
+		memzero_explicit(ctx->rsa.prikey, ctx->key_sz);
+		dma_free_coherent(dev, ctx->key_sz << 1, ctx->rsa.prikey,
+				  ctx->rsa.dma_prikey);
+		ctx->rsa.prikey = NULL;
+	}
+
+	hpre_ctx_clear(ctx, is_clear_all);
+}
+
+/*
+ * we should judge if it is CRT or not,
+ * CRT: return true,  N-CRT: return false .
+ */
+static bool hpre_is_crt_key(struct rsa_key *key)
+{
+	u16 len = key->p_sz + key->q_sz + key->dp_sz + key->dq_sz +
+		  key->qinv_sz;
+
+#define LEN_OF_NCRT_PARA	5
+
+	/* N-CRT less than 5 parameters */
+	return len > LEN_OF_NCRT_PARA;
+}
+
+static int hpre_rsa_setkey(struct hpre_ctx *ctx, const void *key,
+			   unsigned int keylen, bool private)
+{
+	struct rsa_key rsa_key;
+	int ret;
+
+	hpre_rsa_clear_ctx(ctx, false);
+
+	if (private)
+		ret = rsa_parse_priv_key(&rsa_key, key, keylen);
+	else
+		ret = rsa_parse_pub_key(&rsa_key, key, keylen);
+	if (ret < 0)
+		return ret;
+
+	ret = hpre_rsa_set_n(ctx, rsa_key.n, rsa_key.n_sz, private);
+	if (ret <= 0)
+		return ret;
+
+	if (private) {
+		ret = hpre_rsa_set_d(ctx, rsa_key.d, rsa_key.d_sz);
+		if (ret < 0)
+			goto free;
+
+		if (hpre_is_crt_key(&rsa_key)) {
+			ret = hpre_rsa_setkey_crt(ctx, &rsa_key);
+			if (ret < 0)
+				goto free;
+		}
+	}
+
+	ret = hpre_rsa_set_e(ctx, rsa_key.e, rsa_key.e_sz);
+	if (ret < 0)
+		goto free;
+
+	if ((private && !ctx->rsa.prikey) || !ctx->rsa.pubkey) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	return 0;
+
+free:
+	hpre_rsa_clear_ctx(ctx, false);
+	return ret;
+}
+
+static int hpre_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key,
+			      unsigned int keylen)
+{
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+	int ret;
+
+	ret = crypto_akcipher_set_pub_key(ctx->rsa.soft_tfm, key, keylen);
+	if (ret)
+		return ret;
+
+	return hpre_rsa_setkey(ctx, key, keylen, false);
+}
+
+static int hpre_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key,
+			       unsigned int keylen)
+{
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+	int ret;
+
+	ret = crypto_akcipher_set_priv_key(ctx->rsa.soft_tfm, key, keylen);
+	if (ret)
+		return ret;
+
+	return hpre_rsa_setkey(ctx, key, keylen, true);
+}
+
+static unsigned int hpre_rsa_max_size(struct crypto_akcipher *tfm)
+{
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+	/* For 512 and 1536 bits key size, use soft tfm instead */
+	if (ctx->key_sz == HPRE_RSA_512BITS_KSZ ||
+	    ctx->key_sz == HPRE_RSA_1536BITS_KSZ)
+		return crypto_akcipher_maxsize(ctx->rsa.soft_tfm);
+
+	return ctx->key_sz;
+}
+
+static int hpre_rsa_init_tfm(struct crypto_akcipher *tfm)
+{
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+	int ret;
+
+	ctx->rsa.soft_tfm = crypto_alloc_akcipher("rsa-generic", 0, 0);
+	if (IS_ERR(ctx->rsa.soft_tfm)) {
+		pr_err("Can not alloc_akcipher!\n");
+		return PTR_ERR(ctx->rsa.soft_tfm);
+	}
+
+	ret = hpre_ctx_init(ctx);
+	if (ret)
+		crypto_free_akcipher(ctx->rsa.soft_tfm);
+
+	return ret;
+}
+
+static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+	struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+	hpre_rsa_clear_ctx(ctx, true);
+	crypto_free_akcipher(ctx->rsa.soft_tfm);
+}
+
+static struct akcipher_alg rsa = {
+	.sign = hpre_rsa_dec,
+	.verify = hpre_rsa_enc,
+	.encrypt = hpre_rsa_enc,
+	.decrypt = hpre_rsa_dec,
+	.set_pub_key = hpre_rsa_setpubkey,
+	.set_priv_key = hpre_rsa_setprivkey,
+	.max_size = hpre_rsa_max_size,
+	.init = hpre_rsa_init_tfm,
+	.exit = hpre_rsa_exit_tfm,
+	.reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ,
+	.base = {
+		.cra_ctxsize = sizeof(struct hpre_ctx),
+		.cra_priority = HPRE_CRYPTO_ALG_PRI,
+		.cra_name = "rsa",
+		.cra_driver_name = "hpre-rsa",
+		.cra_module = THIS_MODULE,
+	},
+};
+
+#ifdef CONFIG_CRYPTO_DH
+static struct kpp_alg dh = {
+	.set_secret = hpre_dh_set_secret,
+	.generate_public_key = hpre_dh_compute_value,
+	.compute_shared_secret = hpre_dh_compute_value,
+	.max_size = hpre_dh_max_size,
+	.init = hpre_dh_init_tfm,
+	.exit = hpre_dh_exit_tfm,
+	.reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ,
+	.base = {
+		.cra_ctxsize = sizeof(struct hpre_ctx),
+		.cra_priority = HPRE_CRYPTO_ALG_PRI,
+		.cra_name = "dh",
+		.cra_driver_name = "hpre-dh",
+		.cra_module = THIS_MODULE,
+	},
+};
+#endif
+
+int hpre_algs_register(void)
+{
+	int ret = 0;
+
+	mutex_lock(&hpre_alg_lock);
+	if (++hpre_active_devs == 1) {
+		rsa.base.cra_flags = 0;
+		ret = crypto_register_akcipher(&rsa);
+		if (ret)
+			goto unlock;
+#ifdef CONFIG_CRYPTO_DH
+		ret = crypto_register_kpp(&dh);
+		if (ret) {
+			crypto_unregister_akcipher(&rsa);
+			goto unlock;
+		}
+#endif
+	}
+
+unlock:
+	mutex_unlock(&hpre_alg_lock);
+	return ret;
+}
+
+void hpre_algs_unregister(void)
+{
+	mutex_lock(&hpre_alg_lock);
+	if (--hpre_active_devs == 0) {
+		crypto_unregister_akcipher(&rsa);
+#ifdef CONFIG_CRYPTO_DH
+		crypto_unregister_kpp(&dh);
+#endif
+	}
+	mutex_unlock(&hpre_alg_lock);
+}
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/hpre/hpre_main.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/hpre/hpre_main.c
@@ -0,0 +1,1037 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018-2019 HiSilicon Limited. */
+#include <linux/acpi.h>
+#include <linux/aer.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/topology.h>
+#include "hpre.h"
+
+#define HPRE_VF_NUM			63
+#define HPRE_QUEUE_NUM_V2		1024
+#define HPRE_QM_ABNML_INT_MASK		0x100004
+#define HPRE_CTRL_CNT_CLR_CE_BIT	BIT(0)
+#define HPRE_COMM_CNT_CLR_CE		0x0
+#define HPRE_CTRL_CNT_CLR_CE		0x301000
+#define HPRE_FSM_MAX_CNT		0x301008
+#define HPRE_VFG_AXQOS			0x30100c
+#define HPRE_VFG_AXCACHE		0x301010
+#define HPRE_RDCHN_INI_CFG		0x301014
+#define HPRE_AWUSR_FP_CFG		0x301018
+#define HPRE_BD_ENDIAN			0x301020
+#define HPRE_ECC_BYPASS			0x301024
+#define HPRE_RAS_WIDTH_CFG		0x301028
+#define HPRE_POISON_BYPASS		0x30102c
+#define HPRE_BD_ARUSR_CFG		0x301030
+#define HPRE_BD_AWUSR_CFG		0x301034
+#define HPRE_TYPES_ENB			0x301038
+#define HPRE_DATA_RUSER_CFG		0x30103c
+#define HPRE_DATA_WUSER_CFG		0x301040
+#define HPRE_INT_MASK			0x301400
+#define HPRE_INT_STATUS			0x301800
+#define HPRE_CORE_INT_ENABLE		0
+#define HPRE_CORE_INT_DISABLE		0x003fffff
+#define HPRE_RAS_ECC_1BIT_TH		0x30140c
+#define HPRE_RDCHN_INI_ST		0x301a00
+#define HPRE_CLSTR_BASE			0x302000
+#define HPRE_CORE_EN_OFFSET		0x04
+#define HPRE_CORE_INI_CFG_OFFSET	0x20
+#define HPRE_CORE_INI_STATUS_OFFSET	0x80
+#define HPRE_CORE_HTBT_WARN_OFFSET	0x8c
+#define HPRE_CORE_IS_SCHD_OFFSET	0x90
+
+#define HPRE_RAS_CE_ENB			0x301410
+#define HPRE_HAC_RAS_CE_ENABLE		0x3f
+#define HPRE_RAS_NFE_ENB		0x301414
+#define HPRE_HAC_RAS_NFE_ENABLE		0x3fffc0
+#define HPRE_RAS_FE_ENB			0x301418
+#define HPRE_HAC_RAS_FE_ENABLE		0
+
+#define HPRE_CORE_ENB		(HPRE_CLSTR_BASE + HPRE_CORE_EN_OFFSET)
+#define HPRE_CORE_INI_CFG	(HPRE_CLSTR_BASE + HPRE_CORE_INI_CFG_OFFSET)
+#define HPRE_CORE_INI_STATUS (HPRE_CLSTR_BASE + HPRE_CORE_INI_STATUS_OFFSET)
+#define HPRE_HAC_ECC1_CNT		0x301a04
+#define HPRE_HAC_ECC2_CNT		0x301a08
+#define HPRE_HAC_INT_STATUS		0x301800
+#define HPRE_HAC_SOURCE_INT		0x301600
+#define MASTER_GLOBAL_CTRL_SHUTDOWN	1
+#define MASTER_TRANS_RETURN_RW		3
+#define HPRE_MASTER_TRANS_RETURN	0x300150
+#define HPRE_MASTER_GLOBAL_CTRL		0x300000
+#define HPRE_CLSTR_ADDR_INTRVL		0x1000
+#define HPRE_CLUSTER_INQURY		0x100
+#define HPRE_CLSTR_ADDR_INQRY_RSLT	0x104
+#define HPRE_TIMEOUT_ABNML_BIT		6
+#define HPRE_PASID_EN_BIT		9
+#define HPRE_REG_RD_INTVRL_US		10
+#define HPRE_REG_RD_TMOUT_US		1000
+#define HPRE_DBGFS_VAL_MAX_LEN		20
+#define HPRE_PCI_DEVICE_ID		0xa258
+#define HPRE_PCI_VF_DEVICE_ID		0xa259
+#define HPRE_ADDR(qm, offset)		((qm)->io_base + (offset))
+#define HPRE_QM_USR_CFG_MASK		0xfffffffe
+#define HPRE_QM_AXI_CFG_MASK		0xffff
+#define HPRE_QM_VFG_AX_MASK		0xff
+#define HPRE_BD_USR_MASK		0x3
+#define HPRE_CLUSTER_CORE_MASK		0xf
+
+#define HPRE_VIA_MSI_DSM		1
+
+static LIST_HEAD(hpre_list);
+static DEFINE_MUTEX(hpre_list_lock);
+static const char hpre_name[] = "hisi_hpre";
+static struct dentry *hpre_debugfs_root;
+static const struct pci_device_id hpre_dev_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HPRE_PCI_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HPRE_PCI_VF_DEVICE_ID) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, hpre_dev_ids);
+
+struct hpre_hw_error {
+	u32 int_msk;
+	const char *msg;
+};
+
+static const char * const hpre_debug_file_name[] = {
+	[HPRE_CURRENT_QM]   = "current_qm",
+	[HPRE_CLEAR_ENABLE] = "rdclr_en",
+	[HPRE_CLUSTER_CTRL] = "cluster_ctrl",
+};
+
+static const struct hpre_hw_error hpre_hw_errors[] = {
+	{ .int_msk = BIT(0), .msg = "core_ecc_1bit_err_int_set" },
+	{ .int_msk = BIT(1), .msg = "core_ecc_2bit_err_int_set" },
+	{ .int_msk = BIT(2), .msg = "dat_wb_poison_int_set" },
+	{ .int_msk = BIT(3), .msg = "dat_rd_poison_int_set" },
+	{ .int_msk = BIT(4), .msg = "bd_rd_poison_int_set" },
+	{ .int_msk = BIT(5), .msg = "ooo_ecc_2bit_err_int_set" },
+	{ .int_msk = BIT(6), .msg = "cluster1_shb_timeout_int_set" },
+	{ .int_msk = BIT(7), .msg = "cluster2_shb_timeout_int_set" },
+	{ .int_msk = BIT(8), .msg = "cluster3_shb_timeout_int_set" },
+	{ .int_msk = BIT(9), .msg = "cluster4_shb_timeout_int_set" },
+	{ .int_msk = GENMASK(15, 10), .msg = "ooo_rdrsp_err_int_set" },
+	{ .int_msk = GENMASK(21, 16), .msg = "ooo_wrrsp_err_int_set" },
+	{ /* sentinel */ }
+};
+
+static const u64 hpre_cluster_offsets[] = {
+	[HPRE_CLUSTER0] =
+		HPRE_CLSTR_BASE + HPRE_CLUSTER0 * HPRE_CLSTR_ADDR_INTRVL,
+	[HPRE_CLUSTER1] =
+		HPRE_CLSTR_BASE + HPRE_CLUSTER1 * HPRE_CLSTR_ADDR_INTRVL,
+	[HPRE_CLUSTER2] =
+		HPRE_CLSTR_BASE + HPRE_CLUSTER2 * HPRE_CLSTR_ADDR_INTRVL,
+	[HPRE_CLUSTER3] =
+		HPRE_CLSTR_BASE + HPRE_CLUSTER3 * HPRE_CLSTR_ADDR_INTRVL,
+};
+
+static struct debugfs_reg32 hpre_cluster_dfx_regs[] = {
+	{"CORES_EN_STATUS          ",  HPRE_CORE_EN_OFFSET},
+	{"CORES_INI_CFG              ",  HPRE_CORE_INI_CFG_OFFSET},
+	{"CORES_INI_STATUS         ",  HPRE_CORE_INI_STATUS_OFFSET},
+	{"CORES_HTBT_WARN         ",  HPRE_CORE_HTBT_WARN_OFFSET},
+	{"CORES_IS_SCHD               ",  HPRE_CORE_IS_SCHD_OFFSET},
+};
+
+static struct debugfs_reg32 hpre_com_dfx_regs[] = {
+	{"READ_CLR_EN          ",  HPRE_CTRL_CNT_CLR_CE},
+	{"AXQOS                   ",  HPRE_VFG_AXQOS},
+	{"AWUSR_CFG              ",  HPRE_AWUSR_FP_CFG},
+	{"QM_ARUSR_MCFG1           ",  QM_ARUSER_M_CFG_1},
+	{"QM_AWUSR_MCFG1           ",  QM_AWUSER_M_CFG_1},
+	{"BD_ENDIAN               ",  HPRE_BD_ENDIAN},
+	{"ECC_CHECK_CTRL       ",  HPRE_ECC_BYPASS},
+	{"RAS_INT_WIDTH       ",  HPRE_RAS_WIDTH_CFG},
+	{"POISON_BYPASS       ",  HPRE_POISON_BYPASS},
+	{"BD_ARUSER               ",  HPRE_BD_ARUSR_CFG},
+	{"BD_AWUSER               ",  HPRE_BD_AWUSR_CFG},
+	{"DATA_ARUSER            ",  HPRE_DATA_RUSER_CFG},
+	{"DATA_AWUSER           ",  HPRE_DATA_WUSER_CFG},
+	{"INT_STATUS               ",  HPRE_INT_STATUS},
+};
+
+static int hpre_pf_q_num_set(const char *val, const struct kernel_param *kp)
+{
+	struct pci_dev *pdev;
+	u32 n, q_num;
+	u8 rev_id;
+	int ret;
+
+	if (!val)
+		return -EINVAL;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_HUAWEI, HPRE_PCI_DEVICE_ID, NULL);
+	if (!pdev) {
+		q_num = HPRE_QUEUE_NUM_V2;
+		pr_info("No device found currently, suppose queue number is %d\n",
+			q_num);
+	} else {
+		rev_id = pdev->revision;
+		if (rev_id != QM_HW_V2)
+			return -EINVAL;
+
+		q_num = HPRE_QUEUE_NUM_V2;
+	}
+
+	ret = kstrtou32(val, 10, &n);
+	if (ret != 0 || n == 0 || n > q_num)
+		return -EINVAL;
+
+	return param_set_int(val, kp);
+}
+
+static const struct kernel_param_ops hpre_pf_q_num_ops = {
+	.set = hpre_pf_q_num_set,
+	.get = param_get_int,
+};
+
+static u32 hpre_pf_q_num = HPRE_PF_DEF_Q_NUM;
+module_param_cb(hpre_pf_q_num, &hpre_pf_q_num_ops, &hpre_pf_q_num, 0444);
+MODULE_PARM_DESC(hpre_pf_q_num, "Number of queues in PF of CS(1-1024)");
+
+static inline void hpre_add_to_list(struct hpre *hpre)
+{
+	mutex_lock(&hpre_list_lock);
+	list_add_tail(&hpre->list, &hpre_list);
+	mutex_unlock(&hpre_list_lock);
+}
+
+static inline void hpre_remove_from_list(struct hpre *hpre)
+{
+	mutex_lock(&hpre_list_lock);
+	list_del(&hpre->list);
+	mutex_unlock(&hpre_list_lock);
+}
+
+struct hpre *hpre_find_device(int node)
+{
+	struct hpre *hpre, *ret = NULL;
+	int min_distance = INT_MAX;
+	struct device *dev;
+	int dev_node = 0;
+
+	mutex_lock(&hpre_list_lock);
+	list_for_each_entry(hpre, &hpre_list, list) {
+		dev = &hpre->qm.pdev->dev;
+#ifdef CONFIG_NUMA
+		dev_node = dev->numa_node;
+		if (dev_node < 0)
+			dev_node = 0;
+#endif
+		if (node_distance(dev_node, node) < min_distance) {
+			ret = hpre;
+			min_distance = node_distance(dev_node, node);
+		}
+	}
+	mutex_unlock(&hpre_list_lock);
+
+	return ret;
+}
+
+static int hpre_cfg_by_dsm(struct hisi_qm *qm)
+{
+	struct device *dev = &qm->pdev->dev;
+	union acpi_object *obj;
+	guid_t guid;
+
+	if (guid_parse("b06b81ab-0134-4a45-9b0c-483447b95fa7", &guid)) {
+		dev_err(dev, "Hpre GUID failed\n");
+		return -EINVAL;
+	}
+
+	/* Switch over to MSI handling due to non-standard PCI implementation */
+	obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid,
+				0, HPRE_VIA_MSI_DSM, NULL);
+	if (!obj) {
+		dev_err(dev, "ACPI handle failed!\n");
+		return -EIO;
+	}
+
+	ACPI_FREE(obj);
+
+	return 0;
+}
+
+static int hpre_set_user_domain_and_cache(struct hpre *hpre)
+{
+	struct hisi_qm *qm = &hpre->qm;
+	struct device *dev = &qm->pdev->dev;
+	unsigned long offset;
+	int ret, i;
+	u32 val;
+
+	writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_ARUSER_M_CFG_ENABLE));
+	writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_AWUSER_M_CFG_ENABLE));
+	writel_relaxed(HPRE_QM_AXI_CFG_MASK, HPRE_ADDR(qm, QM_AXI_M_CFG));
+
+	/* disable FLR triggered by BME(bus master enable) */
+	writel(PEH_AXUSER_CFG, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG));
+	writel(PEH_AXUSER_CFG_ENABLE, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG_ENABLE));
+
+	/* HPRE need more time, we close this interrupt */
+	val = readl_relaxed(HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+	val |= BIT(HPRE_TIMEOUT_ABNML_BIT);
+	writel_relaxed(val, HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+
+	writel(0x1, HPRE_ADDR(qm, HPRE_TYPES_ENB));
+	writel(HPRE_QM_VFG_AX_MASK, HPRE_ADDR(qm, HPRE_VFG_AXCACHE));
+	writel(0x0, HPRE_ADDR(qm, HPRE_BD_ENDIAN));
+	writel(0x0, HPRE_ADDR(qm, HPRE_INT_MASK));
+	writel(0x0, HPRE_ADDR(qm, HPRE_RAS_ECC_1BIT_TH));
+	writel(0x0, HPRE_ADDR(qm, HPRE_POISON_BYPASS));
+	writel(0x0, HPRE_ADDR(qm, HPRE_COMM_CNT_CLR_CE));
+	writel(0x0, HPRE_ADDR(qm, HPRE_ECC_BYPASS));
+
+	writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_ARUSR_CFG));
+	writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_AWUSR_CFG));
+	writel(0x1, HPRE_ADDR(qm, HPRE_RDCHN_INI_CFG));
+	ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, HPRE_RDCHN_INI_ST), val,
+			val & BIT(0),
+			HPRE_REG_RD_INTVRL_US,
+			HPRE_REG_RD_TMOUT_US);
+	if (ret) {
+		dev_err(dev, "read rd channel timeout fail!\n");
+		return -ETIMEDOUT;
+	}
+
+	for (i = 0; i < HPRE_CLUSTERS_NUM; i++) {
+		offset = i * HPRE_CLSTR_ADDR_INTRVL;
+
+		/* clusters initiating */
+		writel(HPRE_CLUSTER_CORE_MASK,
+		       HPRE_ADDR(qm, offset + HPRE_CORE_ENB));
+		writel(0x1, HPRE_ADDR(qm, offset + HPRE_CORE_INI_CFG));
+		ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, offset +
+					HPRE_CORE_INI_STATUS), val,
+					((val & HPRE_CLUSTER_CORE_MASK) ==
+					HPRE_CLUSTER_CORE_MASK),
+					HPRE_REG_RD_INTVRL_US,
+					HPRE_REG_RD_TMOUT_US);
+		if (ret) {
+			dev_err(dev,
+				"cluster %d int st status timeout!\n", i);
+			return -ETIMEDOUT;
+		}
+	}
+
+	ret = hpre_cfg_by_dsm(qm);
+	if (ret)
+		dev_err(dev, "acpi_evaluate_dsm err.\n");
+
+	return ret;
+}
+
+static void hpre_cnt_regs_clear(struct hisi_qm *qm)
+{
+	unsigned long offset;
+	int i;
+
+	/* clear current_qm */
+	writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
+	writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+
+	/* clear clusterX/cluster_ctrl */
+	for (i = 0; i < HPRE_CLUSTERS_NUM; i++) {
+		offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL;
+		writel(0x0, qm->io_base + offset + HPRE_CLUSTER_INQURY);
+	}
+
+	/* clear rdclr_en */
+	writel(0x0, qm->io_base + HPRE_CTRL_CNT_CLR_CE);
+
+	hisi_qm_debug_regs_clear(qm);
+}
+
+static void hpre_hw_error_disable(struct hisi_qm *qm)
+{
+	/* disable hpre hw error interrupts */
+	writel(HPRE_CORE_INT_DISABLE, qm->io_base + HPRE_INT_MASK);
+}
+
+static void hpre_hw_error_enable(struct hisi_qm *qm)
+{
+	/* enable hpre hw error interrupts */
+	writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK);
+	writel(HPRE_HAC_RAS_CE_ENABLE, qm->io_base + HPRE_RAS_CE_ENB);
+	writel(HPRE_HAC_RAS_NFE_ENABLE, qm->io_base + HPRE_RAS_NFE_ENB);
+	writel(HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_RAS_FE_ENB);
+}
+
+static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file)
+{
+	struct hpre *hpre = container_of(file->debug, struct hpre, debug);
+
+	return &hpre->qm;
+}
+
+static u32 hpre_current_qm_read(struct hpre_debugfs_file *file)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+
+	return readl(qm->io_base + QM_DFX_MB_CNT_VF);
+}
+
+static int hpre_current_qm_write(struct hpre_debugfs_file *file, u32 val)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+	struct hpre_debug *debug = file->debug;
+	struct hpre *hpre = container_of(debug, struct hpre, debug);
+	u32 num_vfs = hpre->num_vfs;
+	u32 vfq_num, tmp;
+
+
+	if (val > num_vfs)
+		return -EINVAL;
+
+	/* According PF or VF Dev ID to calculation curr_qm_qp_num and store */
+	if (val == 0) {
+		qm->debug.curr_qm_qp_num = qm->qp_num;
+	} else {
+		vfq_num = (qm->ctrl_qp_num - qm->qp_num) / num_vfs;
+		if (val == num_vfs) {
+			qm->debug.curr_qm_qp_num =
+			qm->ctrl_qp_num - qm->qp_num - (num_vfs - 1) * vfq_num;
+		} else {
+			qm->debug.curr_qm_qp_num = vfq_num;
+		}
+	}
+
+	writel(val, qm->io_base + QM_DFX_MB_CNT_VF);
+	writel(val, qm->io_base + QM_DFX_DB_CNT_VF);
+
+	tmp = val |
+	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK);
+	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
+
+	tmp = val |
+	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK);
+	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
+
+	return  0;
+}
+
+static u32 hpre_clear_enable_read(struct hpre_debugfs_file *file)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+
+	return readl(qm->io_base + HPRE_CTRL_CNT_CLR_CE) &
+	       HPRE_CTRL_CNT_CLR_CE_BIT;
+}
+
+static int hpre_clear_enable_write(struct hpre_debugfs_file *file, u32 val)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+	u32 tmp;
+
+	if (val != 1 && val != 0)
+		return -EINVAL;
+
+	tmp = (readl(qm->io_base + HPRE_CTRL_CNT_CLR_CE) &
+	       ~HPRE_CTRL_CNT_CLR_CE_BIT) | val;
+	writel(tmp, qm->io_base + HPRE_CTRL_CNT_CLR_CE);
+
+	return  0;
+}
+
+static u32 hpre_cluster_inqry_read(struct hpre_debugfs_file *file)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+	int cluster_index = file->index - HPRE_CLUSTER_CTRL;
+	unsigned long offset = HPRE_CLSTR_BASE +
+			       cluster_index * HPRE_CLSTR_ADDR_INTRVL;
+
+	return readl(qm->io_base + offset + HPRE_CLSTR_ADDR_INQRY_RSLT);
+}
+
+static int hpre_cluster_inqry_write(struct hpre_debugfs_file *file, u32 val)
+{
+	struct hisi_qm *qm = hpre_file_to_qm(file);
+	int cluster_index = file->index - HPRE_CLUSTER_CTRL;
+	unsigned long offset = HPRE_CLSTR_BASE + cluster_index *
+			       HPRE_CLSTR_ADDR_INTRVL;
+
+	writel(val, qm->io_base + offset + HPRE_CLUSTER_INQURY);
+
+	return  0;
+}
+
+static ssize_t hpre_ctrl_debug_read(struct file *filp, char __user *buf,
+			       size_t count, loff_t *pos)
+{
+	struct hpre_debugfs_file *file = filp->private_data;
+	char tbuf[HPRE_DBGFS_VAL_MAX_LEN];
+	u32 val;
+	int ret;
+
+	spin_lock_irq(&file->lock);
+	switch (file->type) {
+	case HPRE_CURRENT_QM:
+		val = hpre_current_qm_read(file);
+		break;
+	case HPRE_CLEAR_ENABLE:
+		val = hpre_clear_enable_read(file);
+		break;
+	case HPRE_CLUSTER_CTRL:
+		val = hpre_cluster_inqry_read(file);
+		break;
+	default:
+		spin_unlock_irq(&file->lock);
+		return -EINVAL;
+	}
+	spin_unlock_irq(&file->lock);
+	ret = snprintf(tbuf, HPRE_DBGFS_VAL_MAX_LEN, "%u\n", val);
+	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
+}
+
+static ssize_t hpre_ctrl_debug_write(struct file *filp, const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct hpre_debugfs_file *file = filp->private_data;
+	char tbuf[HPRE_DBGFS_VAL_MAX_LEN];
+	unsigned long val;
+	int len, ret;
+
+	if (*pos != 0)
+		return 0;
+
+	if (count >= HPRE_DBGFS_VAL_MAX_LEN)
+		return -ENOSPC;
+
+	len = simple_write_to_buffer(tbuf, HPRE_DBGFS_VAL_MAX_LEN - 1,
+				     pos, buf, count);
+	if (len < 0)
+		return len;
+
+	tbuf[len] = '\0';
+	if (kstrtoul(tbuf, 0, &val))
+		return -EFAULT;
+
+	spin_lock_irq(&file->lock);
+	switch (file->type) {
+	case HPRE_CURRENT_QM:
+		ret = hpre_current_qm_write(file, val);
+		if (ret)
+			goto err_input;
+		break;
+	case HPRE_CLEAR_ENABLE:
+		ret = hpre_clear_enable_write(file, val);
+		if (ret)
+			goto err_input;
+		break;
+	case HPRE_CLUSTER_CTRL:
+		ret = hpre_cluster_inqry_write(file, val);
+		if (ret)
+			goto err_input;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err_input;
+	}
+	spin_unlock_irq(&file->lock);
+
+	return count;
+
+err_input:
+	spin_unlock_irq(&file->lock);
+	return ret;
+}
+
+static const struct file_operations hpre_ctrl_debug_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = hpre_ctrl_debug_read,
+	.write = hpre_ctrl_debug_write,
+};
+
+static int hpre_create_debugfs_file(struct hpre_debug *dbg, struct dentry *dir,
+				    enum hpre_ctrl_dbgfs_file type, int indx)
+{
+	struct dentry *file_dir;
+
+	if (dir)
+		file_dir = dir;
+	else
+		file_dir = dbg->debug_root;
+
+	if (type >= HPRE_DEBUG_FILE_NUM)
+		return -EINVAL;
+
+	spin_lock_init(&dbg->files[indx].lock);
+	dbg->files[indx].debug = dbg;
+	dbg->files[indx].type = type;
+	dbg->files[indx].index = indx;
+	debugfs_create_file(hpre_debug_file_name[type], 0600, file_dir,
+			    dbg->files + indx, &hpre_ctrl_debug_fops);
+
+	return 0;
+}
+
+static int hpre_pf_comm_regs_debugfs_init(struct hpre_debug *debug)
+{
+	struct hpre *hpre = container_of(debug, struct hpre, debug);
+	struct hisi_qm *qm = &hpre->qm;
+	struct device *dev = &qm->pdev->dev;
+	struct debugfs_regset32 *regset;
+
+	regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
+	if (!regset)
+		return -ENOMEM;
+
+	regset->regs = hpre_com_dfx_regs;
+	regset->nregs = ARRAY_SIZE(hpre_com_dfx_regs);
+	regset->base = qm->io_base;
+
+	debugfs_create_regset32("regs", 0444,  debug->debug_root, regset);
+	return 0;
+}
+
+static int hpre_cluster_debugfs_init(struct hpre_debug *debug)
+{
+	struct hpre *hpre = container_of(debug, struct hpre, debug);
+	struct hisi_qm *qm = &hpre->qm;
+	struct device *dev = &qm->pdev->dev;
+	char buf[HPRE_DBGFS_VAL_MAX_LEN];
+	struct debugfs_regset32 *regset;
+	struct dentry *tmp_d;
+	int i, ret;
+
+	for (i = 0; i < HPRE_CLUSTERS_NUM; i++) {
+		ret = snprintf(buf, HPRE_DBGFS_VAL_MAX_LEN, "cluster%d", i);
+		if (ret < 0)
+			return -EINVAL;
+		tmp_d = debugfs_create_dir(buf, debug->debug_root);
+
+		regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
+		if (!regset)
+			return -ENOMEM;
+
+		regset->regs = hpre_cluster_dfx_regs;
+		regset->nregs = ARRAY_SIZE(hpre_cluster_dfx_regs);
+		regset->base = qm->io_base + hpre_cluster_offsets[i];
+
+		debugfs_create_regset32("regs", 0444, tmp_d, regset);
+		ret = hpre_create_debugfs_file(debug, tmp_d, HPRE_CLUSTER_CTRL,
+					       i + HPRE_CLUSTER_CTRL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int hpre_ctrl_debug_init(struct hpre_debug *debug)
+{
+	int ret;
+
+	ret = hpre_create_debugfs_file(debug, NULL, HPRE_CURRENT_QM,
+				       HPRE_CURRENT_QM);
+	if (ret)
+		return ret;
+
+	ret = hpre_create_debugfs_file(debug, NULL, HPRE_CLEAR_ENABLE,
+				       HPRE_CLEAR_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = hpre_pf_comm_regs_debugfs_init(debug);
+	if (ret)
+		return ret;
+
+	return hpre_cluster_debugfs_init(debug);
+}
+
+static int hpre_debugfs_init(struct hpre *hpre)
+{
+	struct hisi_qm *qm = &hpre->qm;
+	struct device *dev = &qm->pdev->dev;
+	struct dentry *dir;
+	int ret;
+
+	dir = debugfs_create_dir(dev_name(dev), hpre_debugfs_root);
+	qm->debug.debug_root = dir;
+
+	ret = hisi_qm_debug_init(qm);
+	if (ret)
+		goto failed_to_create;
+
+	if (qm->pdev->device == HPRE_PCI_DEVICE_ID) {
+		hpre->debug.debug_root = dir;
+		ret = hpre_ctrl_debug_init(&hpre->debug);
+		if (ret)
+			goto failed_to_create;
+	}
+	return 0;
+
+failed_to_create:
+	debugfs_remove_recursive(qm->debug.debug_root);
+	return ret;
+}
+
+static void hpre_debugfs_exit(struct hpre *hpre)
+{
+	struct hisi_qm *qm = &hpre->qm;
+
+	debugfs_remove_recursive(qm->debug.debug_root);
+}
+
+static int hpre_qm_pre_init(struct hisi_qm *qm, struct pci_dev *pdev)
+{
+	enum qm_hw_ver rev_id;
+
+	rev_id = hisi_qm_get_hw_version(pdev);
+	if (rev_id < 0)
+		return -ENODEV;
+
+	if (rev_id == QM_HW_V1) {
+		pci_warn(pdev, "HPRE version 1 is not supported!\n");
+		return -EINVAL;
+	}
+
+	qm->pdev = pdev;
+	qm->ver = rev_id;
+	qm->sqe_size = HPRE_SQE_SIZE;
+	qm->dev_name = hpre_name;
+	qm->fun_type = (pdev->device == HPRE_PCI_DEVICE_ID) ?
+		       QM_HW_PF : QM_HW_VF;
+	if (pdev->is_physfn) {
+		qm->qp_base = HPRE_PF_DEF_Q_BASE;
+		qm->qp_num = hpre_pf_q_num;
+	}
+	qm->use_dma_api = true;
+
+	return 0;
+}
+
+static const struct hisi_qm_err_ini hpre_err_ini = {
+	.hw_err_enable	= hpre_hw_error_enable,
+	.hw_err_disable	= hpre_hw_error_disable,
+	.err_info	= {
+		.ce		= QM_BASE_CE,
+		.nfe		= QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT,
+		.fe		= 0,
+		.msi		= QM_DB_RANDOM_INVALID,
+	}
+};
+
+static int hpre_pf_probe_init(struct hpre *hpre)
+{
+	struct hisi_qm *qm = &hpre->qm;
+	int ret;
+
+	qm->ctrl_qp_num = HPRE_QUEUE_NUM_V2;
+
+	ret = hpre_set_user_domain_and_cache(hpre);
+	if (ret)
+		return ret;
+
+	qm->err_ini = &hpre_err_ini;
+	hisi_qm_dev_err_init(qm);
+
+	return 0;
+}
+
+static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct hisi_qm *qm;
+	struct hpre *hpre;
+	int ret;
+
+	hpre = devm_kzalloc(&pdev->dev, sizeof(*hpre), GFP_KERNEL);
+	if (!hpre)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, hpre);
+
+	qm = &hpre->qm;
+	ret = hpre_qm_pre_init(qm, pdev);
+	if (ret)
+		return ret;
+
+	ret = hisi_qm_init(qm);
+	if (ret)
+		return ret;
+
+	if (pdev->is_physfn) {
+		ret = hpre_pf_probe_init(hpre);
+		if (ret)
+			goto err_with_qm_init;
+	} else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V2) {
+		/* v2 starts to support get vft by mailbox */
+		ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
+		if (ret)
+			goto err_with_qm_init;
+	}
+
+	ret = hisi_qm_start(qm);
+	if (ret)
+		goto err_with_err_init;
+
+	ret = hpre_debugfs_init(hpre);
+	if (ret)
+		dev_warn(&pdev->dev, "init debugfs fail!\n");
+
+	hpre_add_to_list(hpre);
+
+	ret = hpre_algs_register();
+	if (ret < 0) {
+		hpre_remove_from_list(hpre);
+		pci_err(pdev, "fail to register algs to crypto!\n");
+		goto err_with_qm_start;
+	}
+	return 0;
+
+err_with_qm_start:
+	hisi_qm_stop(qm);
+
+err_with_err_init:
+	hisi_qm_dev_err_uninit(qm);
+
+err_with_qm_init:
+	hisi_qm_uninit(qm);
+
+	return ret;
+}
+
+static int hpre_vf_q_assign(struct hpre *hpre, int num_vfs)
+{
+	struct hisi_qm *qm = &hpre->qm;
+	u32 qp_num = qm->qp_num;
+	int q_num, remain_q_num, i;
+	u32 q_base = qp_num;
+	int ret;
+
+	if (!num_vfs)
+		return -EINVAL;
+
+	remain_q_num = qm->ctrl_qp_num - qp_num;
+
+	/* If remaining queues are not enough, return error. */
+	if (remain_q_num < num_vfs)
+		return -EINVAL;
+
+	q_num = remain_q_num / num_vfs;
+	for (i = 1; i <= num_vfs; i++) {
+		if (i == num_vfs)
+			q_num += remain_q_num % num_vfs;
+		ret = hisi_qm_set_vft(qm, i, q_base, (u32)q_num);
+		if (ret)
+			return ret;
+		q_base += q_num;
+	}
+
+	return 0;
+}
+
+static int hpre_clear_vft_config(struct hpre *hpre)
+{
+	struct hisi_qm *qm = &hpre->qm;
+	u32 num_vfs = hpre->num_vfs;
+	int ret;
+	u32 i;
+
+	for (i = 1; i <= num_vfs; i++) {
+		ret = hisi_qm_set_vft(qm, i, 0, 0);
+		if (ret)
+			return ret;
+	}
+	hpre->num_vfs = 0;
+
+	return 0;
+}
+
+static int hpre_sriov_enable(struct pci_dev *pdev, int max_vfs)
+{
+	struct hpre *hpre = pci_get_drvdata(pdev);
+	int pre_existing_vfs, num_vfs, ret;
+
+	pre_existing_vfs = pci_num_vf(pdev);
+	if (pre_existing_vfs) {
+		pci_err(pdev,
+			"Can't enable VF. Please disable pre-enabled VFs!\n");
+		return 0;
+	}
+
+	num_vfs = min_t(int, max_vfs, HPRE_VF_NUM);
+	ret = hpre_vf_q_assign(hpre, num_vfs);
+	if (ret) {
+		pci_err(pdev, "Can't assign queues for VF!\n");
+		return ret;
+	}
+
+	hpre->num_vfs = num_vfs;
+
+	ret = pci_enable_sriov(pdev, num_vfs);
+	if (ret) {
+		pci_err(pdev, "Can't enable VF!\n");
+		hpre_clear_vft_config(hpre);
+		return ret;
+	}
+
+	return num_vfs;
+}
+
+static int hpre_sriov_disable(struct pci_dev *pdev)
+{
+	struct hpre *hpre = pci_get_drvdata(pdev);
+
+	if (pci_vfs_assigned(pdev)) {
+		pci_err(pdev, "Failed to disable VFs while VFs are assigned!\n");
+		return -EPERM;
+	}
+
+	/* remove in hpre_pci_driver will be called to free VF resources */
+	pci_disable_sriov(pdev);
+
+	return hpre_clear_vft_config(hpre);
+}
+
+static int hpre_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+	if (num_vfs)
+		return hpre_sriov_enable(pdev, num_vfs);
+	else
+		return hpre_sriov_disable(pdev);
+}
+
+static void hpre_remove(struct pci_dev *pdev)
+{
+	struct hpre *hpre = pci_get_drvdata(pdev);
+	struct hisi_qm *qm = &hpre->qm;
+	int ret;
+
+	hpre_algs_unregister();
+	hpre_remove_from_list(hpre);
+	if (qm->fun_type == QM_HW_PF && hpre->num_vfs != 0) {
+		ret = hpre_sriov_disable(pdev);
+		if (ret) {
+			pci_err(pdev, "Disable SRIOV fail!\n");
+			return;
+		}
+	}
+	if (qm->fun_type == QM_HW_PF) {
+		hpre_cnt_regs_clear(qm);
+		qm->debug.curr_qm_qp_num = 0;
+	}
+
+	hpre_debugfs_exit(hpre);
+	hisi_qm_stop(qm);
+	hisi_qm_dev_err_uninit(qm);
+	hisi_qm_uninit(qm);
+}
+
+static void hpre_log_hw_error(struct hpre *hpre, u32 err_sts)
+{
+	const struct hpre_hw_error *err = hpre_hw_errors;
+	struct device *dev = &hpre->qm.pdev->dev;
+
+	while (err->msg) {
+		if (err->int_msk & err_sts)
+			dev_warn(dev, "%s [error status=0x%x] found\n",
+				 err->msg, err->int_msk);
+		err++;
+	}
+}
+
+static pci_ers_result_t hpre_hw_error_handle(struct hpre *hpre)
+{
+	u32 err_sts;
+
+	/* read err sts */
+	err_sts = readl(hpre->qm.io_base + HPRE_HAC_INT_STATUS);
+	if (err_sts) {
+		hpre_log_hw_error(hpre, err_sts);
+
+		/* clear error interrupts */
+		writel(err_sts, hpre->qm.io_base + HPRE_HAC_SOURCE_INT);
+		return PCI_ERS_RESULT_NEED_RESET;
+	}
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t hpre_process_hw_error(struct pci_dev *pdev)
+{
+	struct hpre *hpre = pci_get_drvdata(pdev);
+	pci_ers_result_t qm_ret, hpre_ret;
+
+	/* log qm error */
+	qm_ret = hisi_qm_hw_error_handle(&hpre->qm);
+
+	/* log hpre error */
+	hpre_ret = hpre_hw_error_handle(hpre);
+
+	return (qm_ret == PCI_ERS_RESULT_NEED_RESET ||
+		hpre_ret == PCI_ERS_RESULT_NEED_RESET) ?
+		PCI_ERS_RESULT_NEED_RESET : PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t hpre_error_detected(struct pci_dev *pdev,
+					    pci_channel_state_t state)
+{
+	pci_info(pdev, "PCI error detected, state(=%d)!!\n", state);
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	return hpre_process_hw_error(pdev);
+}
+
+static const struct pci_error_handlers hpre_err_handler = {
+	.error_detected		= hpre_error_detected,
+};
+
+static struct pci_driver hpre_pci_driver = {
+	.name			= hpre_name,
+	.id_table		= hpre_dev_ids,
+	.probe			= hpre_probe,
+	.remove			= hpre_remove,
+	.sriov_configure	= hpre_sriov_configure,
+	.err_handler		= &hpre_err_handler,
+};
+
+static void hpre_register_debugfs(void)
+{
+	if (!debugfs_initialized())
+		return;
+
+	hpre_debugfs_root = debugfs_create_dir(hpre_name, NULL);
+}
+
+static void hpre_unregister_debugfs(void)
+{
+	debugfs_remove_recursive(hpre_debugfs_root);
+}
+
+static int __init hpre_init(void)
+{
+	int ret;
+
+	hpre_register_debugfs();
+
+	ret = pci_register_driver(&hpre_pci_driver);
+	if (ret) {
+		hpre_unregister_debugfs();
+		pr_err("hpre: can't register hisi hpre driver.\n");
+	}
+
+	return ret;
+}
+
+static void __exit hpre_exit(void)
+{
+	pci_unregister_driver(&hpre_pci_driver);
+	hpre_unregister_debugfs();
+}
+
+module_init(hpre_init);
+module_exit(hpre_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
+MODULE_DESCRIPTION("Driver for HiSilicon HPRE accelerator");
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/qm.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/qm.c
@@ -59,17 +59,17 @@
 #define QM_CQ_PHASE_SHIFT		0
 #define QM_CQ_FLAG_SHIFT		1
 
-#define QM_CQE_PHASE(cqe)		((cqe)->w7 & 0x1)
+#define QM_CQE_PHASE(cqe)		(le16_to_cpu((cqe)->w7) & 0x1)
 #define QM_QC_CQE_SIZE			4
 
 /* eqc shift */
 #define QM_EQE_AEQE_SIZE		(2UL << 12)
 #define QM_EQC_PHASE_SHIFT		16
 
-#define QM_EQE_PHASE(eqe)		(((eqe)->dw0 >> 16) & 0x1)
+#define QM_EQE_PHASE(eqe)		((le32_to_cpu((eqe)->dw0) >> 16) & 0x1)
 #define QM_EQE_CQN_MASK			GENMASK(15, 0)
 
-#define QM_AEQE_PHASE(aeqe)		(((aeqe)->dw0 >> 16) & 0x1)
+#define QM_AEQE_PHASE(aeqe)		((le32_to_cpu((aeqe)->dw0) >> 16) & 0x1)
 #define QM_AEQE_TYPE_SHIFT		17
 
 #define QM_DOORBELL_CMD_SQ		0
@@ -169,17 +169,17 @@
 #define QM_MK_SQC_DW3_V2(sqe_sz) \
 	((QM_Q_DEPTH - 1) | ((u32)ilog2(sqe_sz) << QM_SQ_SQE_SIZE_SHIFT))
 
-#define INIT_QC_COMMON(qc, base, pasid) do {	\
-	(qc)->head = 0;				\
-	(qc)->tail = 0;				\
-	(qc)->base_l = lower_32_bits(base);	\
-	(qc)->base_h = upper_32_bits(base);	\
-	(qc)->dw3 = 0;				\
-	(qc)->w8 = 0;				\
-	(qc)->rsvd0 = 0;			\
-	(qc)->pasid = pasid;			\
-	(qc)->w11 = 0;				\
-	(qc)->rsvd1 = 0;			\
+#define INIT_QC_COMMON(qc, base, pasid) do {			\
+	(qc)->head = 0;						\
+	(qc)->tail = 0;						\
+	(qc)->base_l = cpu_to_le32(lower_32_bits(base));	\
+	(qc)->base_h = cpu_to_le32(upper_32_bits(base));	\
+	(qc)->dw3 = 0;						\
+	(qc)->w8 = 0;						\
+	(qc)->rsvd0 = 0;					\
+	(qc)->pasid = cpu_to_le16(pasid);			\
+	(qc)->w11 = 0;						\
+	(qc)->rsvd1 = 0;					\
 } while (0)
 
 enum vft_type {
@@ -277,6 +277,7 @@
 	int (*debug_init)(struct hisi_qm *qm);
 	void (*hw_error_init)(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe,
 			      u32 msi);
+	void (*hw_error_uninit)(struct hisi_qm *qm);
 	pci_ers_result_t (*hw_error_handle)(struct hisi_qm *qm);
 };
 
@@ -331,12 +332,18 @@
 	void __iomem *fun_base = qm->io_base + QM_MB_CMD_SEND_BASE;
 	unsigned long tmp0 = 0, tmp1 = 0;
 
+	if (!IS_ENABLED(CONFIG_ARM64)) {
+		memcpy_toio(fun_base, src, 16);
+		wmb();
+		return;
+	}
+
 	asm volatile("ldp %0, %1, %3\n"
 		     "stp %0, %1, %2\n"
 		     "dsb sy\n"
 		     : "=&r" (tmp0),
 		       "=&r" (tmp1),
-		       "+Q" (*((char *)fun_base))
+		       "+Q" (*((char __iomem *)fun_base))
 		     : "Q" (*((char *)src))
 		     : "memory");
 }
@@ -350,12 +357,12 @@
 	dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n",
 		queue, cmd, (unsigned long long)dma_addr);
 
-	mailbox.w0 = cmd |
+	mailbox.w0 = cpu_to_le16(cmd |
 		     (op ? 0x1 << QM_MB_OP_SHIFT : 0) |
-		     (0x1 << QM_MB_BUSY_SHIFT);
-	mailbox.queue_num = queue;
-	mailbox.base_l = lower_32_bits(dma_addr);
-	mailbox.base_h = upper_32_bits(dma_addr);
+		     (0x1 << QM_MB_BUSY_SHIFT));
+	mailbox.queue_num = cpu_to_le16(queue);
+	mailbox.base_l = cpu_to_le32(lower_32_bits(dma_addr));
+	mailbox.base_h = cpu_to_le32(upper_32_bits(dma_addr));
 	mailbox.rsvd = 0;
 
 	mutex_lock(&qm->mailbox_lock);
@@ -442,7 +449,7 @@
 
 static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe)
 {
-	u16 cqn = eqe->dw0 & QM_EQE_CQN_MASK;
+	u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
 
 	return qm->qp_array[cqn];
 }
@@ -464,7 +471,8 @@
 	if (qp->req_cb) {
 		while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
 			dma_rmb();
-			qp->req_cb(qp, qp->sqe + qm->sqe_size * cqe->sq_head);
+			qp->req_cb(qp, qp->sqe + qm->sqe_size *
+				   le16_to_cpu(cqe->sq_head));
 			qm_cq_head_update(qp);
 			cqe = qp->cqe + qp->qp_status.cq_head;
 			qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ,
@@ -478,17 +486,9 @@
 	}
 }
 
-static void qm_qp_work_func(struct work_struct *work)
-{
-	struct hisi_qp *qp;
-
-	qp = container_of(work, struct hisi_qp, work);
-	qm_poll_qp(qp, qp->qm);
-}
-
-static irqreturn_t qm_irq_handler(int irq, void *data)
+static void qm_work_process(struct work_struct *work)
 {
-	struct hisi_qm *qm = data;
+	struct hisi_qm *qm = container_of(work, struct hisi_qm, work);
 	struct qm_eqe *eqe = qm->eqe + qm->status.eq_head;
 	struct hisi_qp *qp;
 	int eqe_num = 0;
@@ -497,7 +497,7 @@
 		eqe_num++;
 		qp = qm_to_hisi_qp(qm, eqe);
 		if (qp)
-			queue_work(qp->wq, &qp->work);
+			qm_poll_qp(qp, qm);
 
 		if (qm->status.eq_head == QM_Q_DEPTH - 1) {
 			qm->status.eqc_phase = !qm->status.eqc_phase;
@@ -515,6 +515,17 @@
 	}
 
 	qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
+}
+
+static irqreturn_t do_qm_irq(int irq, void *data)
+{
+	struct hisi_qm *qm = (struct hisi_qm *)data;
+
+	/* the workqueue created by device driver of QM */
+	if (qm->wq)
+		queue_work(qm->wq, &qm->work);
+	else
+		schedule_work(&qm->work);
 
 	return IRQ_HANDLED;
 }
@@ -524,7 +535,7 @@
 	struct hisi_qm *qm = data;
 
 	if (readl(qm->io_base + QM_VF_EQ_INT_SOURCE))
-		return qm_irq_handler(irq, data);
+		return do_qm_irq(irq, data);
 
 	dev_err(&qm->pdev->dev, "invalid int source\n");
 	qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
@@ -542,7 +553,7 @@
 		return IRQ_NONE;
 
 	while (QM_AEQE_PHASE(aeqe) == qm->status.aeqc_phase) {
-		type = aeqe->dw0 >> QM_AEQE_TYPE_SHIFT;
+		type = le32_to_cpu(aeqe->dw0) >> QM_AEQE_TYPE_SHIFT;
 		if (type < ARRAY_SIZE(qm_fifo_overflow))
 			dev_err(&qm->pdev->dev, "%s overflow\n",
 				qm_fifo_overflow[type]);
@@ -646,7 +657,7 @@
 
 	qp_status->sq_tail = 0;
 	qp_status->cq_head = 0;
-	qp_status->cqc_phase = 1;
+	qp_status->cqc_phase = true;
 	qp_status->flags = 0;
 }
 
@@ -963,13 +974,11 @@
 
 static int qm_create_debugfs_file(struct hisi_qm *qm, enum qm_debug_file index)
 {
-	struct dentry *qm_d = qm->debug.qm_d, *tmp;
+	struct dentry *qm_d = qm->debug.qm_d;
 	struct debugfs_file *file = qm->debug.files + index;
 
-	tmp = debugfs_create_file(qm_debug_file_name[index], 0600, qm_d, file,
-				  &qm_debug_fops);
-	if (IS_ERR(tmp))
-		return -ENOENT;
+	debugfs_create_file(qm_debug_file_name[index], 0600, qm_d, file,
+			    &qm_debug_fops);
 
 	file->index = index;
 	mutex_init(&file->lock);
@@ -981,9 +990,6 @@
 static void qm_hw_error_init_v1(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe,
 				u32 msi)
 {
-	dev_info(&qm->pdev->dev,
-		 "QM v%d does not support hw error handle\n", qm->ver);
-
 	writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
 }
 
@@ -1009,6 +1015,11 @@
 	writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK);
 }
 
+static void qm_hw_error_uninit_v2(struct hisi_qm *qm)
+{
+	writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
+}
+
 static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status)
 {
 	const struct hisi_qm_hw_error *err = qm_hw_error;
@@ -1080,6 +1091,7 @@
 	.qm_db = qm_db_v2,
 	.get_irq_num = qm_get_irq_num_v2,
 	.hw_error_init = qm_hw_error_init_v2,
+	.hw_error_uninit = qm_hw_error_uninit_v2,
 	.hw_error_handle = qm_hw_error_handle_v2,
 };
 
@@ -1123,6 +1135,7 @@
 	}
 	set_bit(qp_id, qm->qp_bitmap);
 	qm->qp_array[qp_id] = qp;
+	qm->qp_in_used++;
 
 	write_unlock(&qm->qps_lock);
 
@@ -1144,20 +1157,9 @@
 
 	qp->qp_id = qp_id;
 	qp->alg_type = alg_type;
-	INIT_WORK(&qp->work, qm_qp_work_func);
-	qp->wq = alloc_workqueue("hisi_qm", WQ_UNBOUND | WQ_HIGHPRI |
-				 WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0);
-	if (!qp->wq) {
-		ret = -EFAULT;
-		goto err_free_qp_mem;
-	}
 
 	return qp;
 
-err_free_qp_mem:
-	if (qm->use_dma_api)
-		dma_free_coherent(dev, qp->qdma.size, qp->qdma.va,
-				  qp->qdma.dma);
 err_clear_bit:
 	write_lock(&qm->qps_lock);
 	qm->qp_array[qp_id] = NULL;
@@ -1187,6 +1189,7 @@
 	write_lock(&qm->qps_lock);
 	qm->qp_array[qp->qp_id] = NULL;
 	clear_bit(qp->qp_id, qm->qp_bitmap);
+	qm->qp_in_used--;
 	write_unlock(&qm->qps_lock);
 
 	kfree(qp);
@@ -1218,14 +1221,14 @@
 
 	INIT_QC_COMMON(sqc, qp->sqe_dma, pasid);
 	if (ver == QM_HW_V1) {
-		sqc->dw3 = QM_MK_SQC_DW3_V1(0, 0, 0, qm->sqe_size);
-		sqc->w8 = QM_Q_DEPTH - 1;
+		sqc->dw3 = cpu_to_le32(QM_MK_SQC_DW3_V1(0, 0, 0, qm->sqe_size));
+		sqc->w8 = cpu_to_le16(QM_Q_DEPTH - 1);
 	} else if (ver == QM_HW_V2) {
-		sqc->dw3 = QM_MK_SQC_DW3_V2(qm->sqe_size);
+		sqc->dw3 = cpu_to_le32(QM_MK_SQC_DW3_V2(qm->sqe_size));
 		sqc->w8 = 0; /* rand_qc */
 	}
-	sqc->cq_num = qp_id;
-	sqc->w13 = QM_MK_SQC_W13(0, 1, qp->alg_type);
+	sqc->cq_num = cpu_to_le16(qp_id);
+	sqc->w13 = cpu_to_le16(QM_MK_SQC_W13(0, 1, qp->alg_type));
 
 	ret = qm_mb(qm, QM_MB_CMD_SQC, sqc_dma, qp_id, 0);
 	dma_unmap_single(dev, sqc_dma, sizeof(struct qm_sqc), DMA_TO_DEVICE);
@@ -1245,13 +1248,13 @@
 
 	INIT_QC_COMMON(cqc, qp->cqe_dma, pasid);
 	if (ver == QM_HW_V1) {
-		cqc->dw3 = QM_MK_CQC_DW3_V1(0, 0, 0, 4);
-		cqc->w8 = QM_Q_DEPTH - 1;
+		cqc->dw3 = cpu_to_le32(QM_MK_CQC_DW3_V1(0, 0, 0, 4));
+		cqc->w8 = cpu_to_le16(QM_Q_DEPTH - 1);
 	} else if (ver == QM_HW_V2) {
-		cqc->dw3 = QM_MK_CQC_DW3_V2(4);
+		cqc->dw3 = cpu_to_le32(QM_MK_CQC_DW3_V2(4));
 		cqc->w8 = 0;
 	}
-	cqc->dw6 = 1 << QM_CQ_PHASE_SHIFT | 1 << QM_CQ_FLAG_SHIFT;
+	cqc->dw6 = cpu_to_le32(1 << QM_CQ_PHASE_SHIFT | 1 << QM_CQ_FLAG_SHIFT);
 
 	ret = qm_mb(qm, QM_MB_CMD_CQC, cqc_dma, qp_id, 0);
 	dma_unmap_single(dev, cqc_dma, sizeof(struct qm_cqc), DMA_TO_DEVICE);
@@ -1392,6 +1395,24 @@
 }
 
 /**
+ * hisi_qm_get_free_qp_num() - Get free number of qp in qm.
+ * @qm: The qm which want to get free qp.
+ *
+ * This function return free number of qp in qm.
+ */
+int hisi_qm_get_free_qp_num(struct hisi_qm *qm)
+{
+	int ret;
+
+	read_lock(&qm->qps_lock);
+	ret = qm->qp_num - qm->qp_in_used;
+	read_unlock(&qm->qps_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_get_free_qp_num);
+
+/**
  * hisi_qm_init() - Initialize configures about qm.
  * @qm: The qm needing init.
  *
@@ -1454,8 +1475,10 @@
 	if (ret)
 		goto err_free_irq_vectors;
 
+	qm->qp_in_used = 0;
 	mutex_init(&qm->mailbox_lock);
 	rwlock_init(&qm->qps_lock);
+	INIT_WORK(&qm->work, qm_work_process);
 
 	dev_dbg(dev, "init qm %s with %s\n", pdev->is_physfn ? "pf" : "vf",
 		qm->use_dma_api ? "dma api" : "iommu api");
@@ -1560,8 +1583,8 @@
 
 	status->eq_head = 0;
 	status->aeq_head = 0;
-	status->eqc_phase = 1;
-	status->aeqc_phase = 1;
+	status->eqc_phase = true;
+	status->aeqc_phase = true;
 }
 
 static int qm_eq_ctx_cfg(struct hisi_qm *qm)
@@ -1585,11 +1608,11 @@
 		return -ENOMEM;
 	}
 
-	eqc->base_l = lower_32_bits(qm->eqe_dma);
-	eqc->base_h = upper_32_bits(qm->eqe_dma);
+	eqc->base_l = cpu_to_le32(lower_32_bits(qm->eqe_dma));
+	eqc->base_h = cpu_to_le32(upper_32_bits(qm->eqe_dma));
 	if (qm->ver == QM_HW_V1)
-		eqc->dw3 = QM_EQE_AEQE_SIZE;
-	eqc->dw6 = (QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT);
+		eqc->dw3 = cpu_to_le32(QM_EQE_AEQE_SIZE);
+	eqc->dw6 = cpu_to_le32((QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT));
 	ret = qm_mb(qm, QM_MB_CMD_EQC, eqc_dma, 0, 0);
 	dma_unmap_single(dev, eqc_dma, sizeof(struct qm_eqc), DMA_TO_DEVICE);
 	kfree(eqc);
@@ -1606,9 +1629,9 @@
 		return -ENOMEM;
 	}
 
-	aeqc->base_l = lower_32_bits(qm->aeqe_dma);
-	aeqc->base_h = upper_32_bits(qm->aeqe_dma);
-	aeqc->dw6 = (QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT);
+	aeqc->base_l = cpu_to_le32(lower_32_bits(qm->aeqe_dma));
+	aeqc->base_h = cpu_to_le32(upper_32_bits(qm->aeqe_dma));
+	aeqc->dw6 = cpu_to_le32((QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT));
 
 	ret = qm_mb(qm, QM_MB_CMD_AEQC, aeqc_dma, 0, 0);
 	dma_unmap_single(dev, aeqc_dma, sizeof(struct qm_aeqc), DMA_TO_DEVICE);
@@ -1780,12 +1803,10 @@
  */
 int hisi_qm_debug_init(struct hisi_qm *qm)
 {
-	struct dentry *qm_d, *qm_regs;
+	struct dentry *qm_d;
 	int i, ret;
 
 	qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
-	if (IS_ERR(qm_d))
-		return -ENOENT;
 	qm->debug.qm_d = qm_d;
 
 	/* only show this in PF */
@@ -1796,12 +1817,7 @@
 				goto failed_to_create;
 			}
 
-	qm_regs = debugfs_create_file("qm_regs", 0444, qm->debug.qm_d, qm,
-				      &qm_regs_fops);
-	if (IS_ERR(qm_regs)) {
-		ret = -ENOENT;
-		goto failed_to_create;
-	}
+	debugfs_create_file("qm_regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
 
 	return 0;
 
@@ -1840,36 +1856,28 @@
 }
 EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
 
-/**
- * hisi_qm_hw_error_init() - Configure qm hardware error report method.
- * @qm: The qm which we want to configure.
- * @ce: Bit mask of correctable error configure.
- * @nfe: Bit mask of non-fatal error configure.
- * @fe: Bit mask of fatal error configure.
- * @msi: Bit mask of error reported by message signal interrupt.
- *
- * Hardware errors of qm can be reported either by RAS interrupts which will
- * be handled by UEFI and then PCIe AER or by device MSI. User can configure
- * each error to use either of above two methods. For RAS interrupts, we can
- * configure an error as one of correctable error, non-fatal error or
- * fatal error.
- *
- * Bits indicating errors can be configured to ce, nfe, fe and msi to enable
- * related report methods. Error report will be masked if related error bit
- * does not configure.
- */
-void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe,
-			   u32 msi)
+static void qm_hw_error_init(struct hisi_qm *qm)
 {
+	const struct hisi_qm_err_info *err_info = &qm->err_ini->err_info;
+
 	if (!qm->ops->hw_error_init) {
-		dev_err(&qm->pdev->dev, "QM version %d doesn't support hw error handling!\n",
-			qm->ver);
+		dev_err(&qm->pdev->dev, "QM doesn't support hw error handling!\n");
+		return;
+	}
+
+	qm->ops->hw_error_init(qm, err_info->ce, err_info->nfe,
+			       err_info->fe, err_info->msi);
+}
+
+static void qm_hw_error_uninit(struct hisi_qm *qm)
+{
+	if (!qm->ops->hw_error_uninit) {
+		dev_err(&qm->pdev->dev, "Unexpected QM hw error uninit!\n");
 		return;
 	}
 
-	qm->ops->hw_error_init(qm, ce, nfe, fe, msi);
+	qm->ops->hw_error_uninit(qm);
 }
-EXPORT_SYMBOL_GPL(hisi_qm_hw_error_init);
 
 /**
  * hisi_qm_hw_error_handle() - Handle qm non-fatal hardware errors.
@@ -1877,11 +1885,10 @@
  *
  * Accelerators use this function to handle qm non-fatal hardware errors.
  */
-int hisi_qm_hw_error_handle(struct hisi_qm *qm)
+pci_ers_result_t hisi_qm_hw_error_handle(struct hisi_qm *qm)
 {
 	if (!qm->ops->hw_error_handle) {
-		dev_err(&qm->pdev->dev, "QM version %d doesn't support hw error report!\n",
-			qm->ver);
+		dev_err(&qm->pdev->dev, "QM doesn't support hw error report!\n");
 		return PCI_ERS_RESULT_NONE;
 	}
 
@@ -1908,6 +1915,48 @@
 }
 EXPORT_SYMBOL_GPL(hisi_qm_get_hw_version);
 
+/**
+ * hisi_qm_dev_err_init() - Initialize device error configuration.
+ * @qm: The qm for which we want to do error initialization.
+ *
+ * Initialize QM and device error related configuration.
+ */
+void hisi_qm_dev_err_init(struct hisi_qm *qm)
+{
+	if (qm->fun_type == QM_HW_VF)
+		return;
+
+	qm_hw_error_init(qm);
+
+	if (!qm->err_ini->hw_err_enable) {
+		dev_err(&qm->pdev->dev, "Device doesn't support hw error init!\n");
+		return;
+	}
+	qm->err_ini->hw_err_enable(qm);
+}
+EXPORT_SYMBOL_GPL(hisi_qm_dev_err_init);
+
+/**
+ * hisi_qm_dev_err_uninit() - Uninitialize device error configuration.
+ * @qm: The qm for which we want to do error uninitialization.
+ *
+ * Uninitialize QM and device error related configuration.
+ */
+void hisi_qm_dev_err_uninit(struct hisi_qm *qm)
+{
+	if (qm->fun_type == QM_HW_VF)
+		return;
+
+	qm_hw_error_uninit(qm);
+
+	if (!qm->err_ini->hw_err_disable) {
+		dev_err(&qm->pdev->dev, "Unexpected device hw error uninit!\n");
+		return;
+	}
+	qm->err_ini->hw_err_disable(qm);
+}
+EXPORT_SYMBOL_GPL(hisi_qm_dev_err_uninit);
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
 MODULE_DESCRIPTION("HiSilicon Accelerator queue manager driver");
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/qm.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/qm.h
@@ -40,6 +40,7 @@
 #define QM_AXI_M_CFG			0x1000ac
 #define AXI_M_CFG			0xffff
 #define QM_AXI_M_CFG_ENABLE		0x1000b0
+#define AM_CFG_SINGLE_PORT_MAX_TRANS	0x300014
 #define AXI_M_CFG_ENABLE		0xffffffff
 #define QM_PEH_AXUSER_CFG		0x1000cc
 #define QM_PEH_AXUSER_CFG_ENABLE	0x1000d0
@@ -75,6 +76,8 @@
 
 #define QM_Q_DEPTH			1024
 
+#define HISI_ACC_SGL_SGE_NR_MAX		255
+
 enum qp_state {
 	QP_STOP,
 };
@@ -123,6 +126,21 @@
 	unsigned long flags;
 };
 
+struct hisi_qm;
+
+struct hisi_qm_err_info {
+	u32 ce;
+	u32 nfe;
+	u32 fe;
+	u32 msi;
+};
+
+struct hisi_qm_err_ini {
+	void (*hw_err_enable)(struct hisi_qm *qm);
+	void (*hw_err_disable)(struct hisi_qm *qm);
+	struct hisi_qm_err_info err_info;
+};
+
 struct hisi_qm {
 	enum qm_hw_ver ver;
 	enum qm_fun_type fun_type;
@@ -132,6 +150,7 @@
 	u32 sqe_size;
 	u32 qp_base;
 	u32 qp_num;
+	u32 qp_in_used;
 	u32 ctrl_qp_num;
 
 	struct qm_dma qdma;
@@ -145,6 +164,7 @@
 	dma_addr_t aeqe_dma;
 
 	struct hisi_qm_status status;
+	const struct hisi_qm_err_ini *err_ini;
 
 	rwlock_t qps_lock;
 	unsigned long *qp_bitmap;
@@ -159,6 +179,8 @@
 	u32 error_mask;
 	u32 msi_mask;
 
+	struct workqueue_struct *wq;
+	struct work_struct work;
 	bool use_dma_api;
 };
 
@@ -189,8 +211,6 @@
 	struct hisi_qp_ops *hw_ops;
 	void *qp_ctx;
 	void (*req_cb)(struct hisi_qp *qp, void *data);
-	struct work_struct work;
-	struct workqueue_struct *wq;
 
 	struct hisi_qm *qm;
 };
@@ -204,12 +224,24 @@
 int hisi_qm_stop_qp(struct hisi_qp *qp);
 void hisi_qm_release_qp(struct hisi_qp *qp);
 int hisi_qp_send(struct hisi_qp *qp, const void *msg);
+int hisi_qm_get_free_qp_num(struct hisi_qm *qm);
 int hisi_qm_get_vft(struct hisi_qm *qm, u32 *base, u32 *number);
 int hisi_qm_set_vft(struct hisi_qm *qm, u32 fun_num, u32 base, u32 number);
 int hisi_qm_debug_init(struct hisi_qm *qm);
-void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe,
-			   u32 msi);
-int hisi_qm_hw_error_handle(struct hisi_qm *qm);
+pci_ers_result_t hisi_qm_hw_error_handle(struct hisi_qm *qm);
 enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev);
 void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
+void hisi_qm_dev_err_init(struct hisi_qm *qm);
+void hisi_qm_dev_err_uninit(struct hisi_qm *qm);
+
+struct hisi_acc_sgl_pool;
+struct hisi_acc_hw_sgl *hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+	struct scatterlist *sgl, struct hisi_acc_sgl_pool *pool,
+	u32 index, dma_addr_t *hw_sgl_dma);
+void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
+			   struct hisi_acc_hw_sgl *hw_sgl);
+struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev,
+						   u32 count, u32 sge_nr);
+void hisi_acc_free_sgl_pool(struct device *dev,
+			    struct hisi_acc_sgl_pool *pool);
 #endif
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec/sec_algs.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec/sec_algs.c
@@ -175,7 +175,8 @@
 				     dma_addr_t *psec_sgl,
 				     struct scatterlist *sgl,
 				     int count,
-				     struct sec_dev_info *info)
+				     struct sec_dev_info *info,
+				     gfp_t gfp)
 {
 	struct sec_hw_sgl *sgl_current = NULL;
 	struct sec_hw_sgl *sgl_next;
@@ -190,7 +191,7 @@
 		sge_index = i % SEC_MAX_SGE_NUM;
 		if (sge_index == 0) {
 			sgl_next = dma_pool_zalloc(info->hw_sgl_pool,
-						   GFP_KERNEL, &sgl_next_dma);
+						   gfp, &sgl_next_dma);
 			if (!sgl_next) {
 				ret = -ENOMEM;
 				goto err_free_hw_sgls;
@@ -448,7 +449,7 @@
 		 */
 	}
 
-	mutex_lock(&ctx->queue->queuelock);
+	spin_lock_bh(&ctx->queue->queuelock);
 	/* Put the IV in place for chained cases */
 	switch (ctx->cipher_alg) {
 	case SEC_C_AES_CBC_128:
@@ -508,7 +509,7 @@
 			list_del(&backlog_req->backlog_head);
 		}
 	}
-	mutex_unlock(&ctx->queue->queuelock);
+	spin_unlock_bh(&ctx->queue->queuelock);
 
 	mutex_lock(&sec_req->lock);
 	list_del(&sec_req_el->head);
@@ -545,14 +546,14 @@
 }
 
 static int sec_alg_alloc_and_calc_split_sizes(int length, size_t **split_sizes,
-					      int *steps)
+					      int *steps, gfp_t gfp)
 {
 	size_t *sizes;
 	int i;
 
 	/* Split into suitable sized blocks */
 	*steps = roundup(length, SEC_REQ_LIMIT) / SEC_REQ_LIMIT;
-	sizes = kcalloc(*steps, sizeof(*sizes), GFP_KERNEL);
+	sizes = kcalloc(*steps, sizeof(*sizes), gfp);
 	if (!sizes)
 		return -ENOMEM;
 
@@ -568,7 +569,7 @@
 				int steps, struct scatterlist ***splits,
 				int **splits_nents,
 				int sgl_len_in,
-				struct device *dev)
+				struct device *dev, gfp_t gfp)
 {
 	int ret, count;
 
@@ -576,12 +577,12 @@
 	if (!count)
 		return -EINVAL;
 
-	*splits = kcalloc(steps, sizeof(struct scatterlist *), GFP_KERNEL);
+	*splits = kcalloc(steps, sizeof(struct scatterlist *), gfp);
 	if (!*splits) {
 		ret = -ENOMEM;
 		goto err_unmap_sg;
 	}
-	*splits_nents = kcalloc(steps, sizeof(int), GFP_KERNEL);
+	*splits_nents = kcalloc(steps, sizeof(int), gfp);
 	if (!*splits_nents) {
 		ret = -ENOMEM;
 		goto err_free_splits;
@@ -589,7 +590,7 @@
 
 	/* output the scatter list before and after this */
 	ret = sg_split(sgl, count, 0, steps, split_sizes,
-		       *splits, *splits_nents, GFP_KERNEL);
+		       *splits, *splits_nents, gfp);
 	if (ret) {
 		ret = -ENOMEM;
 		goto err_free_splits_nents;
@@ -630,13 +631,13 @@
 			   int el_size, bool different_dest,
 			   struct scatterlist *sgl_in, int n_ents_in,
 			   struct scatterlist *sgl_out, int n_ents_out,
-			   struct sec_dev_info *info)
+			   struct sec_dev_info *info, gfp_t gfp)
 {
 	struct sec_request_el *el;
 	struct sec_bd_info *req;
 	int ret;
 
-	el = kzalloc(sizeof(*el), GFP_KERNEL);
+	el = kzalloc(sizeof(*el), gfp);
 	if (!el)
 		return ERR_PTR(-ENOMEM);
 	el->el_length = el_size;
@@ -668,7 +669,7 @@
 	el->sgl_in = sgl_in;
 
 	ret = sec_alloc_and_fill_hw_sgl(&el->in, &el->dma_in, el->sgl_in,
-					n_ents_in, info);
+					n_ents_in, info, gfp);
 	if (ret)
 		goto err_free_el;
 
@@ -679,7 +680,7 @@
 		el->sgl_out = sgl_out;
 		ret = sec_alloc_and_fill_hw_sgl(&el->out, &el->dma_out,
 						el->sgl_out,
-						n_ents_out, info);
+						n_ents_out, info, gfp);
 		if (ret)
 			goto err_free_hw_sgl_in;
 
@@ -720,6 +721,7 @@
 	int *splits_out_nents = NULL;
 	struct sec_request_el *el, *temp;
 	bool split = skreq->src != skreq->dst;
+	gfp_t gfp = skreq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
 
 	mutex_init(&sec_req->lock);
 	sec_req->req_base = &skreq->base;
@@ -728,13 +730,13 @@
 	sec_req->len_in = sg_nents(skreq->src);
 
 	ret = sec_alg_alloc_and_calc_split_sizes(skreq->cryptlen, &split_sizes,
-						 &steps);
+						 &steps, gfp);
 	if (ret)
 		return ret;
 	sec_req->num_elements = steps;
 	ret = sec_map_and_split_sg(skreq->src, split_sizes, steps, &splits_in,
 				   &splits_in_nents, sec_req->len_in,
-				   info->dev);
+				   info->dev, gfp);
 	if (ret)
 		goto err_free_split_sizes;
 
@@ -742,7 +744,7 @@
 		sec_req->len_out = sg_nents(skreq->dst);
 		ret = sec_map_and_split_sg(skreq->dst, split_sizes, steps,
 					   &splits_out, &splits_out_nents,
-					   sec_req->len_out, info->dev);
+					   sec_req->len_out, info->dev, gfp);
 		if (ret)
 			goto err_unmap_in_sg;
 	}
@@ -775,7 +777,7 @@
 					       splits_in[i], splits_in_nents[i],
 					       split ? splits_out[i] : NULL,
 					       split ? splits_out_nents[i] : 0,
-					       info);
+					       info, gfp);
 		if (IS_ERR(el)) {
 			ret = PTR_ERR(el);
 			goto err_free_elements;
@@ -796,7 +798,7 @@
 	 */
 
 	/* Grab a big lock for a long time to avoid concurrency issues */
-	mutex_lock(&queue->queuelock);
+	spin_lock_bh(&queue->queuelock);
 
 	/*
 	 * Can go on to queue if we have space in either:
@@ -812,15 +814,15 @@
 		ret = -EBUSY;
 		if ((skreq->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
 			list_add_tail(&sec_req->backlog_head, &ctx->backlog);
-			mutex_unlock(&queue->queuelock);
+			spin_unlock_bh(&queue->queuelock);
 			goto out;
 		}
 
-		mutex_unlock(&queue->queuelock);
+		spin_unlock_bh(&queue->queuelock);
 		goto err_free_elements;
 	}
 	ret = sec_send_request(sec_req, queue);
-	mutex_unlock(&queue->queuelock);
+	spin_unlock_bh(&queue->queuelock);
 	if (ret)
 		goto err_free_elements;
 
@@ -879,7 +881,7 @@
 	if (IS_ERR(ctx->queue))
 		return PTR_ERR(ctx->queue);
 
-	mutex_init(&ctx->queue->queuelock);
+	spin_lock_init(&ctx->queue->queuelock);
 	ctx->queue->havesoftqueue = false;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec/sec_drv.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec/sec_drv.h
@@ -347,7 +347,7 @@
 	DECLARE_BITMAP(unprocessed, SEC_QUEUE_LEN);
 	DECLARE_KFIFO_PTR(softqueue, typeof(struct sec_request_el *));
 	bool havesoftqueue;
-	struct mutex queuelock;
+	spinlock_t queuelock;
 	void *shadow[SEC_QUEUE_LEN];
 };
 
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec2/Makefile
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec2/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += hisi_sec2.o
+hisi_sec2-objs = sec_main.o sec_crypto.o
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec2/sec.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec2/sec.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2019 HiSilicon Limited. */
+
+#ifndef __HISI_SEC_V2_H
+#define __HISI_SEC_V2_H
+
+#include <linux/list.h>
+
+#include "../qm.h"
+#include "sec_crypto.h"
+
+/* Algorithm resource per hardware SEC queue */
+struct sec_alg_res {
+	u8 *c_ivin;
+	dma_addr_t c_ivin_dma;
+	u8 *out_mac;
+	dma_addr_t out_mac_dma;
+};
+
+/* Cipher request of SEC private */
+struct sec_cipher_req {
+	struct hisi_acc_hw_sgl *c_in;
+	dma_addr_t c_in_dma;
+	struct hisi_acc_hw_sgl *c_out;
+	dma_addr_t c_out_dma;
+	struct skcipher_request *sk_req;
+	u32 c_len;
+	bool encrypt;
+};
+
+struct sec_aead_req {
+	u8 *out_mac;
+	dma_addr_t out_mac_dma;
+	struct aead_request *aead_req;
+};
+
+/* SEC request of Crypto */
+struct sec_req {
+	struct sec_sqe sec_sqe;
+	struct sec_ctx *ctx;
+	struct sec_qp_ctx *qp_ctx;
+
+	struct sec_cipher_req c_req;
+	struct sec_aead_req aead_req;
+
+	int err_type;
+	int req_id;
+
+	/* Status of the SEC request */
+	bool fake_busy;
+};
+
+/**
+ * struct sec_req_op - Operations for SEC request
+ * @buf_map: DMA map the SGL buffers of the request
+ * @buf_unmap: DMA unmap the SGL buffers of the request
+ * @bd_fill: Fill the SEC queue BD
+ * @bd_send: Send the SEC BD into the hardware queue
+ * @callback: Call back for the request
+ * @process: Main processing logic of Skcipher
+ */
+struct sec_req_op {
+	int (*buf_map)(struct sec_ctx *ctx, struct sec_req *req);
+	void (*buf_unmap)(struct sec_ctx *ctx, struct sec_req *req);
+	void (*do_transfer)(struct sec_ctx *ctx, struct sec_req *req);
+	int (*bd_fill)(struct sec_ctx *ctx, struct sec_req *req);
+	int (*bd_send)(struct sec_ctx *ctx, struct sec_req *req);
+	void (*callback)(struct sec_ctx *ctx, struct sec_req *req, int err);
+	int (*process)(struct sec_ctx *ctx, struct sec_req *req);
+};
+
+/* SEC auth context */
+struct sec_auth_ctx {
+	dma_addr_t a_key_dma;
+	u8 *a_key;
+	u8 a_key_len;
+	u8 mac_len;
+	u8 a_alg;
+	struct crypto_shash *hash_tfm;
+};
+
+/* SEC cipher context which cipher's relatives */
+struct sec_cipher_ctx {
+	u8 *c_key;
+	dma_addr_t c_key_dma;
+	sector_t iv_offset;
+	u32 c_gran_size;
+	u32 ivsize;
+	u8 c_mode;
+	u8 c_alg;
+	u8 c_key_len;
+};
+
+/* SEC queue context which defines queue's relatives */
+struct sec_qp_ctx {
+	struct hisi_qp *qp;
+	struct sec_req *req_list[QM_Q_DEPTH];
+	struct idr req_idr;
+	struct sec_alg_res res[QM_Q_DEPTH];
+	struct sec_ctx *ctx;
+	struct mutex req_lock;
+	struct hisi_acc_sgl_pool *c_in_pool;
+	struct hisi_acc_sgl_pool *c_out_pool;
+	atomic_t pending_reqs;
+};
+
+enum sec_alg_type {
+	SEC_SKCIPHER,
+	SEC_AEAD
+};
+
+/* SEC Crypto TFM context which defines queue and cipher .etc relatives */
+struct sec_ctx {
+	struct sec_qp_ctx *qp_ctx;
+	struct sec_dev *sec;
+	const struct sec_req_op *req_op;
+
+	/* Half queues for encipher, and half for decipher */
+	u32 hlf_q_num;
+
+	/* Threshold for fake busy, trigger to return -EBUSY to user */
+	u32 fake_req_limit;
+
+	/* Currrent cyclic index to select a queue for encipher */
+	atomic_t enc_qcyclic;
+
+	 /* Currrent cyclic index to select a queue for decipher */
+	atomic_t dec_qcyclic;
+
+	enum sec_alg_type alg_type;
+	struct sec_cipher_ctx c_ctx;
+	struct sec_auth_ctx a_ctx;
+};
+
+enum sec_endian {
+	SEC_LE = 0,
+	SEC_32BE,
+	SEC_64BE
+};
+
+enum sec_debug_file_index {
+	SEC_CURRENT_QM,
+	SEC_CLEAR_ENABLE,
+	SEC_DEBUG_FILE_NUM,
+};
+
+struct sec_debug_file {
+	enum sec_debug_file_index index;
+	spinlock_t lock;
+	struct hisi_qm *qm;
+};
+
+struct sec_dfx {
+	atomic64_t send_cnt;
+	atomic64_t recv_cnt;
+};
+
+struct sec_debug {
+	struct sec_dfx dfx;
+	struct sec_debug_file files[SEC_DEBUG_FILE_NUM];
+};
+
+struct sec_dev {
+	struct hisi_qm qm;
+	struct list_head list;
+	struct sec_debug debug;
+	u32 ctx_q_num;
+	u32 num_vfs;
+	unsigned long status;
+};
+
+struct sec_dev *sec_find_device(int node);
+int sec_register_to_crypto(void);
+void sec_unregister_from_crypto(void);
+#endif
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -0,0 +1,1446 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 HiSilicon Limited. */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/authenc.h>
+#include <crypto/des.h>
+#include <crypto/hash.h>
+#include <crypto/internal/aead.h>
+#include <crypto/sha.h>
+#include <crypto/skcipher.h>
+#include <crypto/xts.h>
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+
+#include "sec.h"
+#include "sec_crypto.h"
+
+#define SEC_PRIORITY		4001
+#define SEC_XTS_MIN_KEY_SIZE	(2 * AES_MIN_KEY_SIZE)
+#define SEC_XTS_MAX_KEY_SIZE	(2 * AES_MAX_KEY_SIZE)
+#define SEC_DES3_2KEY_SIZE	(2 * DES_KEY_SIZE)
+#define SEC_DES3_3KEY_SIZE	(3 * DES_KEY_SIZE)
+
+/* SEC sqe(bd) bit operational relative MACRO */
+#define SEC_DE_OFFSET		1
+#define SEC_CIPHER_OFFSET	4
+#define SEC_SCENE_OFFSET	3
+#define SEC_DST_SGL_OFFSET	2
+#define SEC_SRC_SGL_OFFSET	7
+#define SEC_CKEY_OFFSET		9
+#define SEC_CMODE_OFFSET	12
+#define SEC_AKEY_OFFSET         5
+#define SEC_AEAD_ALG_OFFSET     11
+#define SEC_AUTH_OFFSET		6
+
+#define SEC_FLAG_OFFSET		7
+#define SEC_FLAG_MASK		0x0780
+#define SEC_TYPE_MASK		0x0F
+#define SEC_DONE_MASK		0x0001
+
+#define SEC_TOTAL_IV_SZ		(SEC_IV_SIZE * QM_Q_DEPTH)
+#define SEC_SGL_SGE_NR		128
+#define SEC_CTX_DEV(ctx)	(&(ctx)->sec->qm.pdev->dev)
+#define SEC_CIPHER_AUTH		0xfe
+#define SEC_AUTH_CIPHER		0x1
+#define SEC_MAX_MAC_LEN		64
+#define SEC_TOTAL_MAC_SZ	(SEC_MAX_MAC_LEN * QM_Q_DEPTH)
+#define SEC_SQE_LEN_RATE	4
+#define SEC_SQE_CFLAG		2
+#define SEC_SQE_AEAD_FLAG	3
+#define SEC_SQE_DONE		0x1
+
+static atomic_t sec_active_devs;
+
+/* Get an en/de-cipher queue cyclically to balance load over queues of TFM */
+static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
+{
+	if (req->c_req.encrypt)
+		return (u32)atomic_inc_return(&ctx->enc_qcyclic) %
+				 ctx->hlf_q_num;
+
+	return (u32)atomic_inc_return(&ctx->dec_qcyclic) % ctx->hlf_q_num +
+				 ctx->hlf_q_num;
+}
+
+static inline void sec_free_queue_id(struct sec_ctx *ctx, struct sec_req *req)
+{
+	if (req->c_req.encrypt)
+		atomic_dec(&ctx->enc_qcyclic);
+	else
+		atomic_dec(&ctx->dec_qcyclic);
+}
+
+static int sec_alloc_req_id(struct sec_req *req, struct sec_qp_ctx *qp_ctx)
+{
+	int req_id;
+
+	mutex_lock(&qp_ctx->req_lock);
+
+	req_id = idr_alloc_cyclic(&qp_ctx->req_idr, NULL,
+				  0, QM_Q_DEPTH, GFP_ATOMIC);
+	mutex_unlock(&qp_ctx->req_lock);
+	if (unlikely(req_id < 0)) {
+		dev_err(SEC_CTX_DEV(req->ctx), "alloc req id fail!\n");
+		return req_id;
+	}
+
+	req->qp_ctx = qp_ctx;
+	qp_ctx->req_list[req_id] = req;
+	return req_id;
+}
+
+static void sec_free_req_id(struct sec_req *req)
+{
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+	int req_id = req->req_id;
+
+	if (unlikely(req_id < 0 || req_id >= QM_Q_DEPTH)) {
+		dev_err(SEC_CTX_DEV(req->ctx), "free request id invalid!\n");
+		return;
+	}
+
+	qp_ctx->req_list[req_id] = NULL;
+	req->qp_ctx = NULL;
+
+	mutex_lock(&qp_ctx->req_lock);
+	idr_remove(&qp_ctx->req_idr, req_id);
+	mutex_unlock(&qp_ctx->req_lock);
+}
+
+static int sec_aead_verify(struct sec_req *req, struct sec_qp_ctx *qp_ctx)
+{
+	struct aead_request *aead_req = req->aead_req.aead_req;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
+	u8 *mac_out = qp_ctx->res[req->req_id].out_mac;
+	size_t authsize = crypto_aead_authsize(tfm);
+	u8 *mac = mac_out + SEC_MAX_MAC_LEN;
+	struct scatterlist *sgl = aead_req->src;
+	size_t sz;
+
+	sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), mac, authsize,
+				aead_req->cryptlen + aead_req->assoclen -
+				authsize);
+	if (unlikely(sz != authsize || memcmp(mac_out, mac, sz))) {
+		dev_err(SEC_CTX_DEV(req->ctx), "aead verify failure!\n");
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+static void sec_req_cb(struct hisi_qp *qp, void *resp)
+{
+	struct sec_qp_ctx *qp_ctx = qp->qp_ctx;
+	struct sec_sqe *bd = resp;
+	struct sec_ctx *ctx;
+	struct sec_req *req;
+	u16 done, flag;
+	int err = 0;
+	u8 type;
+
+	type = bd->type_cipher_auth & SEC_TYPE_MASK;
+	if (unlikely(type != SEC_BD_TYPE2)) {
+		pr_err("err bd type [%d]\n", type);
+		return;
+	}
+
+	req = qp_ctx->req_list[le16_to_cpu(bd->type2.tag)];
+	req->err_type = bd->type2.error_type;
+	ctx = req->ctx;
+	done = le16_to_cpu(bd->type2.done_flag) & SEC_DONE_MASK;
+	flag = (le16_to_cpu(bd->type2.done_flag) &
+		SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
+	if (unlikely(req->err_type || done != SEC_SQE_DONE ||
+	    (ctx->alg_type == SEC_SKCIPHER && flag != SEC_SQE_CFLAG) ||
+	    (ctx->alg_type == SEC_AEAD && flag != SEC_SQE_AEAD_FLAG))) {
+		dev_err(SEC_CTX_DEV(ctx),
+			"err_type[%d],done[%d],flag[%d]\n",
+			req->err_type, done, flag);
+		err = -EIO;
+	}
+
+	if (ctx->alg_type == SEC_AEAD && !req->c_req.encrypt)
+		err = sec_aead_verify(req, qp_ctx);
+
+	atomic64_inc(&ctx->sec->debug.dfx.recv_cnt);
+
+	ctx->req_op->buf_unmap(ctx, req);
+
+	ctx->req_op->callback(ctx, req, err);
+}
+
+static int sec_bd_send(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+	int ret;
+
+	mutex_lock(&qp_ctx->req_lock);
+	ret = hisi_qp_send(qp_ctx->qp, &req->sec_sqe);
+	mutex_unlock(&qp_ctx->req_lock);
+	atomic64_inc(&ctx->sec->debug.dfx.send_cnt);
+
+	if (unlikely(ret == -EBUSY))
+		return -ENOBUFS;
+
+	if (!ret) {
+		if (req->fake_busy)
+			ret = -EBUSY;
+		else
+			ret = -EINPROGRESS;
+	}
+
+	return ret;
+}
+
+/* Get DMA memory resources */
+static int sec_alloc_civ_resource(struct device *dev, struct sec_alg_res *res)
+{
+	int i;
+
+	res->c_ivin = dma_alloc_coherent(dev, SEC_TOTAL_IV_SZ,
+					 &res->c_ivin_dma, GFP_KERNEL);
+	if (!res->c_ivin)
+		return -ENOMEM;
+
+	for (i = 1; i < QM_Q_DEPTH; i++) {
+		res[i].c_ivin_dma = res->c_ivin_dma + i * SEC_IV_SIZE;
+		res[i].c_ivin = res->c_ivin + i * SEC_IV_SIZE;
+	}
+
+	return 0;
+}
+
+static void sec_free_civ_resource(struct device *dev, struct sec_alg_res *res)
+{
+	if (res->c_ivin)
+		dma_free_coherent(dev, SEC_TOTAL_IV_SZ,
+				  res->c_ivin, res->c_ivin_dma);
+}
+
+static int sec_alloc_mac_resource(struct device *dev, struct sec_alg_res *res)
+{
+	int i;
+
+	res->out_mac = dma_alloc_coherent(dev, SEC_TOTAL_MAC_SZ << 1,
+					  &res->out_mac_dma, GFP_KERNEL);
+	if (!res->out_mac)
+		return -ENOMEM;
+
+	for (i = 1; i < QM_Q_DEPTH; i++) {
+		res[i].out_mac_dma = res->out_mac_dma +
+				     i * (SEC_MAX_MAC_LEN << 1);
+		res[i].out_mac = res->out_mac + i * (SEC_MAX_MAC_LEN << 1);
+	}
+
+	return 0;
+}
+
+static void sec_free_mac_resource(struct device *dev, struct sec_alg_res *res)
+{
+	if (res->out_mac)
+		dma_free_coherent(dev, SEC_TOTAL_MAC_SZ << 1,
+				  res->out_mac, res->out_mac_dma);
+}
+
+static int sec_alg_resource_alloc(struct sec_ctx *ctx,
+				  struct sec_qp_ctx *qp_ctx)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+	struct sec_alg_res *res = qp_ctx->res;
+	int ret;
+
+	ret = sec_alloc_civ_resource(dev, res);
+	if (ret)
+		return ret;
+
+	if (ctx->alg_type == SEC_AEAD) {
+		ret = sec_alloc_mac_resource(dev, res);
+		if (ret)
+			goto get_fail;
+	}
+
+	return 0;
+get_fail:
+	sec_free_civ_resource(dev, res);
+
+	return ret;
+}
+
+static void sec_alg_resource_free(struct sec_ctx *ctx,
+				  struct sec_qp_ctx *qp_ctx)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+
+	sec_free_civ_resource(dev, qp_ctx->res);
+
+	if (ctx->alg_type == SEC_AEAD)
+		sec_free_mac_resource(dev, qp_ctx->res);
+}
+
+static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx,
+			     int qp_ctx_id, int alg_type)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+	struct sec_qp_ctx *qp_ctx;
+	struct hisi_qp *qp;
+	int ret = -ENOMEM;
+
+	qp = hisi_qm_create_qp(qm, alg_type);
+	if (IS_ERR(qp))
+		return PTR_ERR(qp);
+
+	qp_ctx = &ctx->qp_ctx[qp_ctx_id];
+	qp->req_type = 0;
+	qp->qp_ctx = qp_ctx;
+	qp->req_cb = sec_req_cb;
+	qp_ctx->qp = qp;
+	qp_ctx->ctx = ctx;
+
+	mutex_init(&qp_ctx->req_lock);
+	atomic_set(&qp_ctx->pending_reqs, 0);
+	idr_init(&qp_ctx->req_idr);
+
+	qp_ctx->c_in_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH,
+						     SEC_SGL_SGE_NR);
+	if (IS_ERR(qp_ctx->c_in_pool)) {
+		dev_err(dev, "fail to create sgl pool for input!\n");
+		goto err_destroy_idr;
+	}
+
+	qp_ctx->c_out_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH,
+						      SEC_SGL_SGE_NR);
+	if (IS_ERR(qp_ctx->c_out_pool)) {
+		dev_err(dev, "fail to create sgl pool for output!\n");
+		goto err_free_c_in_pool;
+	}
+
+	ret = sec_alg_resource_alloc(ctx, qp_ctx);
+	if (ret)
+		goto err_free_c_out_pool;
+
+	ret = hisi_qm_start_qp(qp, 0);
+	if (ret < 0)
+		goto err_queue_free;
+
+	return 0;
+
+err_queue_free:
+	sec_alg_resource_free(ctx, qp_ctx);
+err_free_c_out_pool:
+	hisi_acc_free_sgl_pool(dev, qp_ctx->c_out_pool);
+err_free_c_in_pool:
+	hisi_acc_free_sgl_pool(dev, qp_ctx->c_in_pool);
+err_destroy_idr:
+	idr_destroy(&qp_ctx->req_idr);
+	hisi_qm_release_qp(qp);
+
+	return ret;
+}
+
+static void sec_release_qp_ctx(struct sec_ctx *ctx,
+			       struct sec_qp_ctx *qp_ctx)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+
+	hisi_qm_stop_qp(qp_ctx->qp);
+	sec_alg_resource_free(ctx, qp_ctx);
+
+	hisi_acc_free_sgl_pool(dev, qp_ctx->c_out_pool);
+	hisi_acc_free_sgl_pool(dev, qp_ctx->c_in_pool);
+
+	idr_destroy(&qp_ctx->req_idr);
+	hisi_qm_release_qp(qp_ctx->qp);
+}
+
+static int sec_ctx_base_init(struct sec_ctx *ctx)
+{
+	struct sec_dev *sec;
+	int i, ret;
+
+	sec = sec_find_device(cpu_to_node(smp_processor_id()));
+	if (!sec) {
+		pr_err("Can not find proper Hisilicon SEC device!\n");
+		return -ENODEV;
+	}
+	ctx->sec = sec;
+	ctx->hlf_q_num = sec->ctx_q_num >> 1;
+
+	/* Half of queue depth is taken as fake requests limit in the queue. */
+	ctx->fake_req_limit = QM_Q_DEPTH >> 1;
+	ctx->qp_ctx = kcalloc(sec->ctx_q_num, sizeof(struct sec_qp_ctx),
+			      GFP_KERNEL);
+	if (!ctx->qp_ctx)
+		return -ENOMEM;
+
+	for (i = 0; i < sec->ctx_q_num; i++) {
+		ret = sec_create_qp_ctx(&sec->qm, ctx, i, 0);
+		if (ret)
+			goto err_sec_release_qp_ctx;
+	}
+
+	return 0;
+err_sec_release_qp_ctx:
+	for (i = i - 1; i >= 0; i--)
+		sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]);
+
+	kfree(ctx->qp_ctx);
+	return ret;
+}
+
+static void sec_ctx_base_uninit(struct sec_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ctx->sec->ctx_q_num; i++)
+		sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]);
+
+	kfree(ctx->qp_ctx);
+}
+
+static int sec_cipher_init(struct sec_ctx *ctx)
+{
+	struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+
+	c_ctx->c_key = dma_alloc_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE,
+					  &c_ctx->c_key_dma, GFP_KERNEL);
+	if (!c_ctx->c_key)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void sec_cipher_uninit(struct sec_ctx *ctx)
+{
+	struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+
+	memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE);
+	dma_free_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE,
+			  c_ctx->c_key, c_ctx->c_key_dma);
+}
+
+static int sec_auth_init(struct sec_ctx *ctx)
+{
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+	a_ctx->a_key = dma_alloc_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE,
+					  &a_ctx->a_key_dma, GFP_KERNEL);
+	if (!a_ctx->a_key)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void sec_auth_uninit(struct sec_ctx *ctx)
+{
+	struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+	memzero_explicit(a_ctx->a_key, SEC_MAX_KEY_SIZE);
+	dma_free_coherent(SEC_CTX_DEV(ctx), SEC_MAX_KEY_SIZE,
+			  a_ctx->a_key, a_ctx->a_key_dma);
+}
+
+static int sec_skcipher_init(struct crypto_skcipher *tfm)
+{
+	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+	int ret;
+
+	ctx = crypto_skcipher_ctx(tfm);
+	ctx->alg_type = SEC_SKCIPHER;
+	crypto_skcipher_set_reqsize(tfm, sizeof(struct sec_req));
+	ctx->c_ctx.ivsize = crypto_skcipher_ivsize(tfm);
+	if (ctx->c_ctx.ivsize > SEC_IV_SIZE) {
+		dev_err(SEC_CTX_DEV(ctx), "get error skcipher iv size!\n");
+		return -EINVAL;
+	}
+
+	ret = sec_ctx_base_init(ctx);
+	if (ret)
+		return ret;
+
+	ret = sec_cipher_init(ctx);
+	if (ret)
+		goto err_cipher_init;
+
+	return 0;
+err_cipher_init:
+	sec_ctx_base_uninit(ctx);
+
+	return ret;
+}
+
+static void sec_skcipher_uninit(struct crypto_skcipher *tfm)
+{
+	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+	sec_cipher_uninit(ctx);
+	sec_ctx_base_uninit(ctx);
+}
+
+static int sec_skcipher_3des_setkey(struct sec_cipher_ctx *c_ctx,
+				    const u32 keylen,
+				    const enum sec_cmode c_mode)
+{
+	switch (keylen) {
+	case SEC_DES3_2KEY_SIZE:
+		c_ctx->c_key_len = SEC_CKEY_3DES_2KEY;
+		break;
+	case SEC_DES3_3KEY_SIZE:
+		c_ctx->c_key_len = SEC_CKEY_3DES_3KEY;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sec_skcipher_aes_sm4_setkey(struct sec_cipher_ctx *c_ctx,
+				       const u32 keylen,
+				       const enum sec_cmode c_mode)
+{
+	if (c_mode == SEC_CMODE_XTS) {
+		switch (keylen) {
+		case SEC_XTS_MIN_KEY_SIZE:
+			c_ctx->c_key_len = SEC_CKEY_128BIT;
+			break;
+		case SEC_XTS_MAX_KEY_SIZE:
+			c_ctx->c_key_len = SEC_CKEY_256BIT;
+			break;
+		default:
+			pr_err("hisi_sec2: xts mode key error!\n");
+			return -EINVAL;
+		}
+	} else {
+		switch (keylen) {
+		case AES_KEYSIZE_128:
+			c_ctx->c_key_len = SEC_CKEY_128BIT;
+			break;
+		case AES_KEYSIZE_192:
+			c_ctx->c_key_len = SEC_CKEY_192BIT;
+			break;
+		case AES_KEYSIZE_256:
+			c_ctx->c_key_len = SEC_CKEY_256BIT;
+			break;
+		default:
+			pr_err("hisi_sec2: aes key error!\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
+			       const u32 keylen, const enum sec_calg c_alg,
+			       const enum sec_cmode c_mode)
+{
+	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+	struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+	int ret;
+
+	if (c_mode == SEC_CMODE_XTS) {
+		ret = xts_verify_key(tfm, key, keylen);
+		if (ret) {
+			dev_err(SEC_CTX_DEV(ctx), "xts mode key err!\n");
+			return ret;
+		}
+	}
+
+	c_ctx->c_alg  = c_alg;
+	c_ctx->c_mode = c_mode;
+
+	switch (c_alg) {
+	case SEC_CALG_3DES:
+		ret = sec_skcipher_3des_setkey(c_ctx, keylen, c_mode);
+		break;
+	case SEC_CALG_AES:
+	case SEC_CALG_SM4:
+		ret = sec_skcipher_aes_sm4_setkey(c_ctx, keylen, c_mode);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(SEC_CTX_DEV(ctx), "set sec key err!\n");
+		return ret;
+	}
+
+	memcpy(c_ctx->c_key, key, keylen);
+
+	return 0;
+}
+
+#define GEN_SEC_SETKEY_FUNC(name, c_alg, c_mode)			\
+static int sec_setkey_##name(struct crypto_skcipher *tfm, const u8 *key,\
+	u32 keylen)							\
+{									\
+	return sec_skcipher_setkey(tfm, key, keylen, c_alg, c_mode);	\
+}
+
+GEN_SEC_SETKEY_FUNC(aes_ecb, SEC_CALG_AES, SEC_CMODE_ECB)
+GEN_SEC_SETKEY_FUNC(aes_cbc, SEC_CALG_AES, SEC_CMODE_CBC)
+GEN_SEC_SETKEY_FUNC(aes_xts, SEC_CALG_AES, SEC_CMODE_XTS)
+
+GEN_SEC_SETKEY_FUNC(3des_ecb, SEC_CALG_3DES, SEC_CMODE_ECB)
+GEN_SEC_SETKEY_FUNC(3des_cbc, SEC_CALG_3DES, SEC_CMODE_CBC)
+
+GEN_SEC_SETKEY_FUNC(sm4_xts, SEC_CALG_SM4, SEC_CMODE_XTS)
+GEN_SEC_SETKEY_FUNC(sm4_cbc, SEC_CALG_SM4, SEC_CMODE_CBC)
+
+static int sec_cipher_map(struct device *dev, struct sec_req *req,
+			  struct scatterlist *src, struct scatterlist *dst)
+{
+	struct sec_cipher_req *c_req = &req->c_req;
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+
+	c_req->c_in = hisi_acc_sg_buf_map_to_hw_sgl(dev, src,
+						    qp_ctx->c_in_pool,
+						    req->req_id,
+						    &c_req->c_in_dma);
+
+	if (IS_ERR(c_req->c_in)) {
+		dev_err(dev, "fail to dma map input sgl buffers!\n");
+		return PTR_ERR(c_req->c_in);
+	}
+
+	if (dst == src) {
+		c_req->c_out = c_req->c_in;
+		c_req->c_out_dma = c_req->c_in_dma;
+	} else {
+		c_req->c_out = hisi_acc_sg_buf_map_to_hw_sgl(dev, dst,
+							     qp_ctx->c_out_pool,
+							     req->req_id,
+							     &c_req->c_out_dma);
+
+		if (IS_ERR(c_req->c_out)) {
+			dev_err(dev, "fail to dma map output sgl buffers!\n");
+			hisi_acc_sg_buf_unmap(dev, src, c_req->c_in);
+			return PTR_ERR(c_req->c_out);
+		}
+	}
+
+	return 0;
+}
+
+static void sec_cipher_unmap(struct device *dev, struct sec_cipher_req *req,
+			     struct scatterlist *src, struct scatterlist *dst)
+{
+	if (dst != src)
+		hisi_acc_sg_buf_unmap(dev, src, req->c_in);
+
+	hisi_acc_sg_buf_unmap(dev, dst, req->c_out);
+}
+
+static int sec_skcipher_sgl_map(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct skcipher_request *sq = req->c_req.sk_req;
+
+	return sec_cipher_map(SEC_CTX_DEV(ctx), req, sq->src, sq->dst);
+}
+
+static void sec_skcipher_sgl_unmap(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+	struct sec_cipher_req *c_req = &req->c_req;
+	struct skcipher_request *sk_req = c_req->sk_req;
+
+	sec_cipher_unmap(dev, c_req, sk_req->src, sk_req->dst);
+}
+
+static int sec_aead_aes_set_key(struct sec_cipher_ctx *c_ctx,
+				struct crypto_authenc_keys *keys)
+{
+	switch (keys->enckeylen) {
+	case AES_KEYSIZE_128:
+		c_ctx->c_key_len = SEC_CKEY_128BIT;
+		break;
+	case AES_KEYSIZE_192:
+		c_ctx->c_key_len = SEC_CKEY_192BIT;
+		break;
+	case AES_KEYSIZE_256:
+		c_ctx->c_key_len = SEC_CKEY_256BIT;
+		break;
+	default:
+		pr_err("hisi_sec2: aead aes key error!\n");
+		return -EINVAL;
+	}
+	memcpy(c_ctx->c_key, keys->enckey, keys->enckeylen);
+
+	return 0;
+}
+
+static int sec_aead_auth_set_key(struct sec_auth_ctx *ctx,
+				 struct crypto_authenc_keys *keys)
+{
+	struct crypto_shash *hash_tfm = ctx->hash_tfm;
+	SHASH_DESC_ON_STACK(shash, hash_tfm);
+	int blocksize, ret;
+
+	if (!keys->authkeylen) {
+		pr_err("hisi_sec2: aead auth key error!\n");
+		return -EINVAL;
+	}
+
+	blocksize = crypto_shash_blocksize(hash_tfm);
+	if (keys->authkeylen > blocksize) {
+		ret = crypto_shash_digest(shash, keys->authkey,
+					  keys->authkeylen, ctx->a_key);
+		if (ret) {
+			pr_err("hisi_sec2: aead auth digest error!\n");
+			return -EINVAL;
+		}
+		ctx->a_key_len = blocksize;
+	} else {
+		memcpy(ctx->a_key, keys->authkey, keys->authkeylen);
+		ctx->a_key_len = keys->authkeylen;
+	}
+
+	return 0;
+}
+
+static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+			   const u32 keylen, const enum sec_hash_alg a_alg,
+			   const enum sec_calg c_alg,
+			   const enum sec_mac_len mac_len,
+			   const enum sec_cmode c_mode)
+{
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+	struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+	struct crypto_authenc_keys keys;
+	int ret;
+
+	ctx->a_ctx.a_alg = a_alg;
+	ctx->c_ctx.c_alg = c_alg;
+	ctx->a_ctx.mac_len = mac_len;
+	c_ctx->c_mode = c_mode;
+
+	if (crypto_authenc_extractkeys(&keys, key, keylen))
+		goto bad_key;
+
+	ret = sec_aead_aes_set_key(c_ctx, &keys);
+	if (ret) {
+		dev_err(SEC_CTX_DEV(ctx), "set sec cipher key err!\n");
+		goto bad_key;
+	}
+
+	ret = sec_aead_auth_set_key(&ctx->a_ctx, &keys);
+	if (ret) {
+		dev_err(SEC_CTX_DEV(ctx), "set sec auth key err!\n");
+		goto bad_key;
+	}
+
+	return 0;
+bad_key:
+	memzero_explicit(&keys, sizeof(struct crypto_authenc_keys));
+
+	return -EINVAL;
+}
+
+
+#define GEN_SEC_AEAD_SETKEY_FUNC(name, aalg, calg, maclen, cmode)	\
+static int sec_setkey_##name(struct crypto_aead *tfm, const u8 *key,	\
+	u32 keylen)							\
+{									\
+	return sec_aead_setkey(tfm, key, keylen, aalg, calg, maclen, cmode);\
+}
+
+GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha1, SEC_A_HMAC_SHA1,
+			 SEC_CALG_AES, SEC_HMAC_SHA1_MAC, SEC_CMODE_CBC)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha256, SEC_A_HMAC_SHA256,
+			 SEC_CALG_AES, SEC_HMAC_SHA256_MAC, SEC_CMODE_CBC)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha512, SEC_A_HMAC_SHA512,
+			 SEC_CALG_AES, SEC_HMAC_SHA512_MAC, SEC_CMODE_CBC)
+
+static int sec_aead_sgl_map(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct aead_request *aq = req->aead_req.aead_req;
+
+	return sec_cipher_map(SEC_CTX_DEV(ctx), req, aq->src, aq->dst);
+}
+
+static void sec_aead_sgl_unmap(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct device *dev = SEC_CTX_DEV(ctx);
+	struct sec_cipher_req *cq = &req->c_req;
+	struct aead_request *aq = req->aead_req.aead_req;
+
+	sec_cipher_unmap(dev, cq, aq->src, aq->dst);
+}
+
+static int sec_request_transfer(struct sec_ctx *ctx, struct sec_req *req)
+{
+	int ret;
+
+	ret = ctx->req_op->buf_map(ctx, req);
+	if (unlikely(ret))
+		return ret;
+
+	ctx->req_op->do_transfer(ctx, req);
+
+	ret = ctx->req_op->bd_fill(ctx, req);
+	if (unlikely(ret))
+		goto unmap_req_buf;
+
+	return ret;
+
+unmap_req_buf:
+	ctx->req_op->buf_unmap(ctx, req);
+
+	return ret;
+}
+
+static void sec_request_untransfer(struct sec_ctx *ctx, struct sec_req *req)
+{
+	ctx->req_op->buf_unmap(ctx, req);
+}
+
+static void sec_skcipher_copy_iv(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct skcipher_request *sk_req = req->c_req.sk_req;
+	u8 *c_ivin = req->qp_ctx->res[req->req_id].c_ivin;
+
+	memcpy(c_ivin, sk_req->iv, ctx->c_ctx.ivsize);
+}
+
+static int sec_skcipher_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+	struct sec_cipher_req *c_req = &req->c_req;
+	struct sec_sqe *sec_sqe = &req->sec_sqe;
+	u8 scene, sa_type, da_type;
+	u8 bd_type, cipher;
+	u8 de = 0;
+
+	memset(sec_sqe, 0, sizeof(struct sec_sqe));
+
+	sec_sqe->type2.c_key_addr = cpu_to_le64(c_ctx->c_key_dma);
+	sec_sqe->type2.c_ivin_addr =
+		cpu_to_le64(req->qp_ctx->res[req->req_id].c_ivin_dma);
+	sec_sqe->type2.data_src_addr = cpu_to_le64(c_req->c_in_dma);
+	sec_sqe->type2.data_dst_addr = cpu_to_le64(c_req->c_out_dma);
+
+	sec_sqe->type2.icvw_kmode |= cpu_to_le16(((u16)c_ctx->c_mode) <<
+						SEC_CMODE_OFFSET);
+	sec_sqe->type2.c_alg = c_ctx->c_alg;
+	sec_sqe->type2.icvw_kmode |= cpu_to_le16(((u16)c_ctx->c_key_len) <<
+						SEC_CKEY_OFFSET);
+
+	bd_type = SEC_BD_TYPE2;
+	if (c_req->encrypt)
+		cipher = SEC_CIPHER_ENC << SEC_CIPHER_OFFSET;
+	else
+		cipher = SEC_CIPHER_DEC << SEC_CIPHER_OFFSET;
+	sec_sqe->type_cipher_auth = bd_type | cipher;
+
+	sa_type = SEC_SGL << SEC_SRC_SGL_OFFSET;
+	scene = SEC_COMM_SCENE << SEC_SCENE_OFFSET;
+	if (c_req->c_in_dma != c_req->c_out_dma)
+		de = 0x1 << SEC_DE_OFFSET;
+
+	sec_sqe->sds_sa_type = (de | scene | sa_type);
+
+	/* Just set DST address type */
+	da_type = SEC_SGL << SEC_DST_SGL_OFFSET;
+	sec_sqe->sdm_addr_type |= da_type;
+
+	sec_sqe->type2.clen_ivhlen |= cpu_to_le32(c_req->c_len);
+	sec_sqe->type2.tag = cpu_to_le16((u16)req->req_id);
+
+	return 0;
+}
+
+static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
+{
+	struct aead_request *aead_req = req->aead_req.aead_req;
+	struct skcipher_request *sk_req = req->c_req.sk_req;
+	u32 iv_size = req->ctx->c_ctx.ivsize;
+	struct scatterlist *sgl;
+	unsigned int cryptlen;
+	size_t sz;
+	u8 *iv;
+
+	if (req->c_req.encrypt)
+		sgl = alg_type == SEC_SKCIPHER ? sk_req->dst : aead_req->dst;
+	else
+		sgl = alg_type == SEC_SKCIPHER ? sk_req->src : aead_req->src;
+
+	if (alg_type == SEC_SKCIPHER) {
+		iv = sk_req->iv;
+		cryptlen = sk_req->cryptlen;
+	} else {
+		iv = aead_req->iv;
+		cryptlen = aead_req->cryptlen;
+	}
+
+	sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size,
+				cryptlen - iv_size);
+	if (unlikely(sz != iv_size))
+		dev_err(SEC_CTX_DEV(req->ctx), "copy output iv error!\n");
+}
+
+static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
+				  int err)
+{
+	struct skcipher_request *sk_req = req->c_req.sk_req;
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+
+	atomic_dec(&qp_ctx->pending_reqs);
+	sec_free_req_id(req);
+
+	/* IV output at encrypto of CBC mode */
+	if (!err && ctx->c_ctx.c_mode == SEC_CMODE_CBC && req->c_req.encrypt)
+		sec_update_iv(req, SEC_SKCIPHER);
+
+	if (req->fake_busy)
+		sk_req->base.complete(&sk_req->base, -EINPROGRESS);
+
+	sk_req->base.complete(&sk_req->base, err);
+}
+
+static void sec_aead_copy_iv(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct aead_request *aead_req = req->aead_req.aead_req;
+	u8 *c_ivin = req->qp_ctx->res[req->req_id].c_ivin;
+
+	memcpy(c_ivin, aead_req->iv, ctx->c_ctx.ivsize);
+}
+
+static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
+			       struct sec_req *req, struct sec_sqe *sec_sqe)
+{
+	struct sec_aead_req *a_req = &req->aead_req;
+	struct sec_cipher_req *c_req = &req->c_req;
+	struct aead_request *aq = a_req->aead_req;
+
+	sec_sqe->type2.a_key_addr = cpu_to_le64(ctx->a_key_dma);
+
+	sec_sqe->type2.mac_key_alg =
+			cpu_to_le32(ctx->mac_len / SEC_SQE_LEN_RATE);
+
+	sec_sqe->type2.mac_key_alg |=
+			cpu_to_le32((u32)((ctx->a_key_len) /
+			SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET);
+
+	sec_sqe->type2.mac_key_alg |=
+			cpu_to_le32((u32)(ctx->a_alg) << SEC_AEAD_ALG_OFFSET);
+
+	sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
+
+	if (dir)
+		sec_sqe->sds_sa_type &= SEC_CIPHER_AUTH;
+	else
+		sec_sqe->sds_sa_type |= SEC_AUTH_CIPHER;
+
+	sec_sqe->type2.alen_ivllen = cpu_to_le32(c_req->c_len + aq->assoclen);
+
+	sec_sqe->type2.cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+
+	sec_sqe->type2.mac_addr =
+		cpu_to_le64(req->qp_ctx->res[req->req_id].out_mac_dma);
+}
+
+static int sec_aead_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_auth_ctx *auth_ctx = &ctx->a_ctx;
+	struct sec_sqe *sec_sqe = &req->sec_sqe;
+	int ret;
+
+	ret = sec_skcipher_bd_fill(ctx, req);
+	if (unlikely(ret)) {
+		dev_err(SEC_CTX_DEV(ctx), "skcipher bd fill is error!\n");
+		return ret;
+	}
+
+	sec_auth_bd_fill_ex(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+
+	return 0;
+}
+
+static void sec_aead_callback(struct sec_ctx *c, struct sec_req *req, int err)
+{
+	struct aead_request *a_req = req->aead_req.aead_req;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(a_req);
+	struct sec_cipher_req *c_req = &req->c_req;
+	size_t authsize = crypto_aead_authsize(tfm);
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+	size_t sz;
+
+	atomic_dec(&qp_ctx->pending_reqs);
+
+	if (!err && c->c_ctx.c_mode == SEC_CMODE_CBC && c_req->encrypt)
+		sec_update_iv(req, SEC_AEAD);
+
+	/* Copy output mac */
+	if (!err && c_req->encrypt) {
+		struct scatterlist *sgl = a_req->dst;
+
+		sz = sg_pcopy_from_buffer(sgl, sg_nents(sgl),
+					  qp_ctx->res[req->req_id].out_mac,
+					  authsize, a_req->cryptlen +
+					  a_req->assoclen);
+
+		if (unlikely(sz != authsize)) {
+			dev_err(SEC_CTX_DEV(req->ctx), "copy out mac err!\n");
+			err = -EINVAL;
+		}
+	}
+
+	sec_free_req_id(req);
+
+	if (req->fake_busy)
+		a_req->base.complete(&a_req->base, -EINPROGRESS);
+
+	a_req->base.complete(&a_req->base, err);
+}
+
+static void sec_request_uninit(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_qp_ctx *qp_ctx = req->qp_ctx;
+
+	atomic_dec(&qp_ctx->pending_reqs);
+	sec_free_req_id(req);
+	sec_free_queue_id(ctx, req);
+}
+
+static int sec_request_init(struct sec_ctx *ctx, struct sec_req *req)
+{
+	struct sec_qp_ctx *qp_ctx;
+	int queue_id;
+
+	/* To load balance */
+	queue_id = sec_alloc_queue_id(ctx, req);
+	qp_ctx = &ctx->qp_ctx[queue_id];
+
+	req->req_id = sec_alloc_req_id(req, qp_ctx);
+	if (unlikely(req->req_id < 0)) {
+		sec_free_queue_id(ctx, req);
+		return req->req_id;
+	}
+
+	if (ctx->fake_req_limit <= atomic_inc_return(&qp_ctx->pending_reqs))
+		req->fake_busy = true;
+	else
+		req->fake_busy = false;
+
+	return 0;
+}
+
+static int sec_process(struct sec_ctx *ctx, struct sec_req *req)
+{
+	int ret;
+
+	ret = sec_request_init(ctx, req);
+	if (unlikely(ret))
+		return ret;
+
+	ret = sec_request_transfer(ctx, req);
+	if (unlikely(ret))
+		goto err_uninit_req;
+
+	/* Output IV as decrypto */
+	if (ctx->c_ctx.c_mode == SEC_CMODE_CBC && !req->c_req.encrypt)
+		sec_update_iv(req, ctx->alg_type);
+
+	ret = ctx->req_op->bd_send(ctx, req);
+	if (unlikely(ret != -EBUSY && ret != -EINPROGRESS)) {
+		dev_err_ratelimited(SEC_CTX_DEV(ctx), "send sec request failed!\n");
+		goto err_send_req;
+	}
+
+	return ret;
+
+err_send_req:
+	/* As failing, restore the IV from user */
+	if (ctx->c_ctx.c_mode == SEC_CMODE_CBC && !req->c_req.encrypt) {
+		if (ctx->alg_type == SEC_SKCIPHER)
+			memcpy(req->c_req.sk_req->iv,
+			       req->qp_ctx->res[req->req_id].c_ivin,
+			       ctx->c_ctx.ivsize);
+		else
+			memcpy(req->aead_req.aead_req->iv,
+			       req->qp_ctx->res[req->req_id].c_ivin,
+			       ctx->c_ctx.ivsize);
+	}
+
+	sec_request_untransfer(ctx, req);
+err_uninit_req:
+	sec_request_uninit(ctx, req);
+
+	return ret;
+}
+
+static const struct sec_req_op sec_skcipher_req_ops = {
+	.buf_map	= sec_skcipher_sgl_map,
+	.buf_unmap	= sec_skcipher_sgl_unmap,
+	.do_transfer	= sec_skcipher_copy_iv,
+	.bd_fill	= sec_skcipher_bd_fill,
+	.bd_send	= sec_bd_send,
+	.callback	= sec_skcipher_callback,
+	.process	= sec_process,
+};
+
+static const struct sec_req_op sec_aead_req_ops = {
+	.buf_map	= sec_aead_sgl_map,
+	.buf_unmap	= sec_aead_sgl_unmap,
+	.do_transfer	= sec_aead_copy_iv,
+	.bd_fill	= sec_aead_bd_fill,
+	.bd_send	= sec_bd_send,
+	.callback	= sec_aead_callback,
+	.process	= sec_process,
+};
+
+static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
+{
+	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+	ctx->req_op = &sec_skcipher_req_ops;
+
+	return sec_skcipher_init(tfm);
+}
+
+static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm)
+{
+	sec_skcipher_uninit(tfm);
+}
+
+static int sec_aead_init(struct crypto_aead *tfm)
+{
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+	int ret;
+
+	crypto_aead_set_reqsize(tfm, sizeof(struct sec_req));
+	ctx->alg_type = SEC_AEAD;
+	ctx->c_ctx.ivsize = crypto_aead_ivsize(tfm);
+	if (ctx->c_ctx.ivsize > SEC_IV_SIZE) {
+		dev_err(SEC_CTX_DEV(ctx), "get error aead iv size!\n");
+		return -EINVAL;
+	}
+
+	ctx->req_op = &sec_aead_req_ops;
+	ret = sec_ctx_base_init(ctx);
+	if (ret)
+		return ret;
+
+	ret = sec_auth_init(ctx);
+	if (ret)
+		goto err_auth_init;
+
+	ret = sec_cipher_init(ctx);
+	if (ret)
+		goto err_cipher_init;
+
+	return ret;
+
+err_cipher_init:
+	sec_auth_uninit(ctx);
+err_auth_init:
+	sec_ctx_base_uninit(ctx);
+
+	return ret;
+}
+
+static void sec_aead_exit(struct crypto_aead *tfm)
+{
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+
+	sec_cipher_uninit(ctx);
+	sec_auth_uninit(ctx);
+	sec_ctx_base_uninit(ctx);
+}
+
+static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name)
+{
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+	struct sec_auth_ctx *auth_ctx = &ctx->a_ctx;
+	int ret;
+
+	ret = sec_aead_init(tfm);
+	if (ret) {
+		pr_err("hisi_sec2: aead init error!\n");
+		return ret;
+	}
+
+	auth_ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0);
+	if (IS_ERR(auth_ctx->hash_tfm)) {
+		dev_err(SEC_CTX_DEV(ctx), "aead alloc shash error!\n");
+		sec_aead_exit(tfm);
+		return PTR_ERR(auth_ctx->hash_tfm);
+	}
+
+	return 0;
+}
+
+static void sec_aead_ctx_exit(struct crypto_aead *tfm)
+{
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+
+	crypto_free_shash(ctx->a_ctx.hash_tfm);
+	sec_aead_exit(tfm);
+}
+
+static int sec_aead_sha1_ctx_init(struct crypto_aead *tfm)
+{
+	return sec_aead_ctx_init(tfm, "sha1");
+}
+
+static int sec_aead_sha256_ctx_init(struct crypto_aead *tfm)
+{
+	return sec_aead_ctx_init(tfm, "sha256");
+}
+
+static int sec_aead_sha512_ctx_init(struct crypto_aead *tfm)
+{
+	return sec_aead_ctx_init(tfm, "sha512");
+}
+
+static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
+{
+	struct skcipher_request *sk_req = sreq->c_req.sk_req;
+	struct device *dev = SEC_CTX_DEV(ctx);
+	u8 c_alg = ctx->c_ctx.c_alg;
+
+	if (unlikely(!sk_req->src || !sk_req->dst)) {
+		dev_err(dev, "skcipher input param error!\n");
+		return -EINVAL;
+	}
+	sreq->c_req.c_len = sk_req->cryptlen;
+	if (c_alg == SEC_CALG_3DES) {
+		if (unlikely(sk_req->cryptlen & (DES3_EDE_BLOCK_SIZE - 1))) {
+			dev_err(dev, "skcipher 3des input length error!\n");
+			return -EINVAL;
+		}
+		return 0;
+	} else if (c_alg == SEC_CALG_AES || c_alg == SEC_CALG_SM4) {
+		if (unlikely(sk_req->cryptlen & (AES_BLOCK_SIZE - 1))) {
+			dev_err(dev, "skcipher aes input length error!\n");
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	dev_err(dev, "skcipher algorithm error!\n");
+	return -EINVAL;
+}
+
+static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(sk_req);
+	struct sec_req *req = skcipher_request_ctx(sk_req);
+	struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+	int ret;
+
+	if (!sk_req->cryptlen)
+		return 0;
+
+	req->c_req.sk_req = sk_req;
+	req->c_req.encrypt = encrypt;
+	req->ctx = ctx;
+
+	ret = sec_skcipher_param_check(ctx, req);
+	if (unlikely(ret))
+		return -EINVAL;
+
+	return ctx->req_op->process(ctx, req);
+}
+
+static int sec_skcipher_encrypt(struct skcipher_request *sk_req)
+{
+	return sec_skcipher_crypto(sk_req, true);
+}
+
+static int sec_skcipher_decrypt(struct skcipher_request *sk_req)
+{
+	return sec_skcipher_crypto(sk_req, false);
+}
+
+#define SEC_SKCIPHER_GEN_ALG(sec_cra_name, sec_set_key, sec_min_key_size, \
+	sec_max_key_size, ctx_init, ctx_exit, blk_size, iv_size)\
+{\
+	.base = {\
+		.cra_name = sec_cra_name,\
+		.cra_driver_name = "hisi_sec_"sec_cra_name,\
+		.cra_priority = SEC_PRIORITY,\
+		.cra_flags = CRYPTO_ALG_ASYNC,\
+		.cra_blocksize = blk_size,\
+		.cra_ctxsize = sizeof(struct sec_ctx),\
+		.cra_module = THIS_MODULE,\
+	},\
+	.init = ctx_init,\
+	.exit = ctx_exit,\
+	.setkey = sec_set_key,\
+	.decrypt = sec_skcipher_decrypt,\
+	.encrypt = sec_skcipher_encrypt,\
+	.min_keysize = sec_min_key_size,\
+	.max_keysize = sec_max_key_size,\
+	.ivsize = iv_size,\
+},
+
+#define SEC_SKCIPHER_ALG(name, key_func, min_key_size, \
+	max_key_size, blk_size, iv_size) \
+	SEC_SKCIPHER_GEN_ALG(name, key_func, min_key_size, max_key_size, \
+	sec_skcipher_ctx_init, sec_skcipher_ctx_exit, blk_size, iv_size)
+
+static struct skcipher_alg sec_skciphers[] = {
+	SEC_SKCIPHER_ALG("ecb(aes)", sec_setkey_aes_ecb,
+			 AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+			 AES_BLOCK_SIZE, 0)
+
+	SEC_SKCIPHER_ALG("cbc(aes)", sec_setkey_aes_cbc,
+			 AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+			 AES_BLOCK_SIZE, AES_BLOCK_SIZE)
+
+	SEC_SKCIPHER_ALG("xts(aes)", sec_setkey_aes_xts,
+			 SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MAX_KEY_SIZE,
+			 AES_BLOCK_SIZE, AES_BLOCK_SIZE)
+
+	SEC_SKCIPHER_ALG("ecb(des3_ede)", sec_setkey_3des_ecb,
+			 SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+			 DES3_EDE_BLOCK_SIZE, 0)
+
+	SEC_SKCIPHER_ALG("cbc(des3_ede)", sec_setkey_3des_cbc,
+			 SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+			 DES3_EDE_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE)
+
+	SEC_SKCIPHER_ALG("xts(sm4)", sec_setkey_sm4_xts,
+			 SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MIN_KEY_SIZE,
+			 AES_BLOCK_SIZE, AES_BLOCK_SIZE)
+
+	SEC_SKCIPHER_ALG("cbc(sm4)", sec_setkey_sm4_cbc,
+			 AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+			 AES_BLOCK_SIZE, AES_BLOCK_SIZE)
+};
+
+static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
+{
+	u8 c_alg = ctx->c_ctx.c_alg;
+	struct aead_request *req = sreq->aead_req.aead_req;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	size_t authsize = crypto_aead_authsize(tfm);
+
+	if (unlikely(!req->src || !req->dst || !req->cryptlen)) {
+		dev_err(SEC_CTX_DEV(ctx), "aead input param error!\n");
+		return -EINVAL;
+	}
+
+	/* Support AES only */
+	if (unlikely(c_alg != SEC_CALG_AES)) {
+		dev_err(SEC_CTX_DEV(ctx), "aead crypto alg error!\n");
+		return -EINVAL;
+
+	}
+	if (sreq->c_req.encrypt)
+		sreq->c_req.c_len = req->cryptlen;
+	else
+		sreq->c_req.c_len = req->cryptlen - authsize;
+
+	if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) {
+		dev_err(SEC_CTX_DEV(ctx), "aead crypto length error!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(a_req);
+	struct sec_req *req = aead_request_ctx(a_req);
+	struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+	int ret;
+
+	req->aead_req.aead_req = a_req;
+	req->c_req.encrypt = encrypt;
+	req->ctx = ctx;
+
+	ret = sec_aead_param_check(ctx, req);
+	if (unlikely(ret))
+		return -EINVAL;
+
+	return ctx->req_op->process(ctx, req);
+}
+
+static int sec_aead_encrypt(struct aead_request *a_req)
+{
+	return sec_aead_crypto(a_req, true);
+}
+
+static int sec_aead_decrypt(struct aead_request *a_req)
+{
+	return sec_aead_crypto(a_req, false);
+}
+
+#define SEC_AEAD_GEN_ALG(sec_cra_name, sec_set_key, ctx_init,\
+			 ctx_exit, blk_size, iv_size, max_authsize)\
+{\
+	.base = {\
+		.cra_name = sec_cra_name,\
+		.cra_driver_name = "hisi_sec_"sec_cra_name,\
+		.cra_priority = SEC_PRIORITY,\
+		.cra_flags = CRYPTO_ALG_ASYNC,\
+		.cra_blocksize = blk_size,\
+		.cra_ctxsize = sizeof(struct sec_ctx),\
+		.cra_module = THIS_MODULE,\
+	},\
+	.init = ctx_init,\
+	.exit = ctx_exit,\
+	.setkey = sec_set_key,\
+	.decrypt = sec_aead_decrypt,\
+	.encrypt = sec_aead_encrypt,\
+	.ivsize = iv_size,\
+	.maxauthsize = max_authsize,\
+}
+
+#define SEC_AEAD_ALG(algname, keyfunc, aead_init, blksize, ivsize, authsize)\
+	SEC_AEAD_GEN_ALG(algname, keyfunc, aead_init,\
+			sec_aead_ctx_exit, blksize, ivsize, authsize)
+
+static struct aead_alg sec_aeads[] = {
+	SEC_AEAD_ALG("authenc(hmac(sha1),cbc(aes))",
+		     sec_setkey_aes_cbc_sha1, sec_aead_sha1_ctx_init,
+		     AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA1_DIGEST_SIZE),
+
+	SEC_AEAD_ALG("authenc(hmac(sha256),cbc(aes))",
+		     sec_setkey_aes_cbc_sha256, sec_aead_sha256_ctx_init,
+		     AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA256_DIGEST_SIZE),
+
+	SEC_AEAD_ALG("authenc(hmac(sha512),cbc(aes))",
+		     sec_setkey_aes_cbc_sha512, sec_aead_sha512_ctx_init,
+		     AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA512_DIGEST_SIZE),
+};
+
+int sec_register_to_crypto(void)
+{
+	int ret = 0;
+
+	/* To avoid repeat register */
+	if (atomic_add_return(1, &sec_active_devs) == 1) {
+		ret = crypto_register_skciphers(sec_skciphers,
+						ARRAY_SIZE(sec_skciphers));
+		if (ret)
+			return ret;
+
+		ret = crypto_register_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+		if (ret)
+			goto reg_aead_fail;
+	}
+
+	return ret;
+
+reg_aead_fail:
+	crypto_unregister_skciphers(sec_skciphers, ARRAY_SIZE(sec_skciphers));
+
+	return ret;
+}
+
+void sec_unregister_from_crypto(void)
+{
+	if (atomic_sub_return(1, &sec_active_devs) == 0) {
+		crypto_unregister_skciphers(sec_skciphers,
+					    ARRAY_SIZE(sec_skciphers));
+		crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+	}
+}
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec2/sec_crypto.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec2/sec_crypto.h
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2019 HiSilicon Limited. */
+
+#ifndef __HISI_SEC_V2_CRYPTO_H
+#define __HISI_SEC_V2_CRYPTO_H
+
+#define SEC_IV_SIZE		24
+#define SEC_MAX_KEY_SIZE	64
+#define SEC_COMM_SCENE		0
+
+enum sec_calg {
+	SEC_CALG_3DES = 0x1,
+	SEC_CALG_AES  = 0x2,
+	SEC_CALG_SM4  = 0x3,
+};
+
+enum sec_hash_alg {
+	SEC_A_HMAC_SHA1   = 0x10,
+	SEC_A_HMAC_SHA256 = 0x11,
+	SEC_A_HMAC_SHA512 = 0x15,
+};
+
+enum sec_mac_len {
+	SEC_HMAC_SHA1_MAC   = 20,
+	SEC_HMAC_SHA256_MAC = 32,
+	SEC_HMAC_SHA512_MAC = 64,
+};
+
+enum sec_cmode {
+	SEC_CMODE_ECB    = 0x0,
+	SEC_CMODE_CBC    = 0x1,
+	SEC_CMODE_CTR    = 0x4,
+	SEC_CMODE_XTS    = 0x7,
+};
+
+enum sec_ckey_type {
+	SEC_CKEY_128BIT = 0x0,
+	SEC_CKEY_192BIT = 0x1,
+	SEC_CKEY_256BIT = 0x2,
+	SEC_CKEY_3DES_3KEY = 0x1,
+	SEC_CKEY_3DES_2KEY = 0x3,
+};
+
+enum sec_bd_type {
+	SEC_BD_TYPE1 = 0x1,
+	SEC_BD_TYPE2 = 0x2,
+};
+
+enum sec_auth {
+	SEC_NO_AUTH = 0x0,
+	SEC_AUTH_TYPE1 = 0x1,
+	SEC_AUTH_TYPE2 = 0x2,
+};
+
+enum sec_cipher_dir {
+	SEC_CIPHER_ENC = 0x1,
+	SEC_CIPHER_DEC = 0x2,
+};
+
+enum sec_addr_type {
+	SEC_PBUF = 0x0,
+	SEC_SGL  = 0x1,
+	SEC_PRP  = 0x2,
+};
+
+struct sec_sqe_type2 {
+
+	/*
+	 * mac_len: 0~4 bits
+	 * a_key_len: 5~10 bits
+	 * a_alg: 11~16 bits
+	 */
+	__le32 mac_key_alg;
+
+	/*
+	 * c_icv_len: 0~5 bits
+	 * c_width: 6~8 bits
+	 * c_key_len: 9~11 bits
+	 * c_mode: 12~15 bits
+	 */
+	__le16 icvw_kmode;
+
+	/* c_alg: 0~3 bits */
+	__u8 c_alg;
+	__u8 rsvd4;
+
+	/*
+	 * a_len: 0~23 bits
+	 * iv_offset_l: 24~31 bits
+	 */
+	__le32 alen_ivllen;
+
+	/*
+	 * c_len: 0~23 bits
+	 * iv_offset_h: 24~31 bits
+	 */
+	__le32 clen_ivhlen;
+
+	__le16 auth_src_offset;
+	__le16 cipher_src_offset;
+	__le16 cs_ip_header_offset;
+	__le16 cs_udp_header_offset;
+	__le16 pass_word_len;
+	__le16 dk_len;
+	__u8 salt3;
+	__u8 salt2;
+	__u8 salt1;
+	__u8 salt0;
+
+	__le16 tag;
+	__le16 rsvd5;
+
+	/*
+	 * c_pad_type: 0~3 bits
+	 * c_pad_len: 4~11 bits
+	 * c_pad_data_type: 12~15 bits
+	 */
+	__le16 cph_pad;
+
+	/* c_pad_len_field: 0~1 bits */
+	__le16 c_pad_len_field;
+
+
+	__le64 long_a_data_len;
+	__le64 a_ivin_addr;
+	__le64 a_key_addr;
+	__le64 mac_addr;
+	__le64 c_ivin_addr;
+	__le64 c_key_addr;
+
+	__le64 data_src_addr;
+	__le64 data_dst_addr;
+
+	/*
+	 * done: 0 bit
+	 * icv: 1~3 bits
+	 * csc: 4~6 bits
+	 * flag: 7-10 bits
+	 * dif_check: 11~13 bits
+	 */
+	__le16 done_flag;
+
+	__u8 error_type;
+	__u8 warning_type;
+	__u8 mac_i3;
+	__u8 mac_i2;
+	__u8 mac_i1;
+	__u8 mac_i0;
+	__le16 check_sum_i;
+	__u8 tls_pad_len_i;
+	__u8 rsvd12;
+	__le32 counter;
+};
+
+struct sec_sqe {
+	/*
+	 * type:	0~3 bits
+	 * cipher:	4~5 bits
+	 * auth:	6~7 bit s
+	 */
+	__u8 type_cipher_auth;
+
+	/*
+	 * seq:	0 bit
+	 * de:	1~2 bits
+	 * scene:	3~6 bits
+	 * src_addr_type: ~7 bit, with sdm_addr_type 0-1 bits
+	 */
+	__u8 sds_sa_type;
+
+	/*
+	 * src_addr_type: 0~1 bits, not used now,
+	 * if support PRP, set this field, or set zero.
+	 * dst_addr_type: 2~4 bits
+	 * mac_addr_type: 5~7 bits
+	 */
+	__u8 sdm_addr_type;
+	__u8 rsvd0;
+
+	/*
+	 * nonce_len(type2): 0~3 bits
+	 * huk(type2): 4 bit
+	 * key_s(type2): 5 bit
+	 * ci_gen: 6~7 bits
+	 */
+	__u8 huk_key_ci;
+
+	/*
+	 * ai_gen: 0~1 bits
+	 * a_pad(type2): 2~3 bits
+	 * c_s(type2): 4~5 bits
+	 */
+	__u8 ai_apd_cs;
+
+	/*
+	 * rhf(type2): 0 bit
+	 * c_key_type: 1~2 bits
+	 * a_key_type: 3~4 bits
+	 * write_frame_len(type2): 5~7 bits
+	 */
+	__u8 rca_key_frm;
+
+	/*
+	 * cal_iv_addr_en(type2): 0 bit
+	 * tls_up(type2): 1 bit
+	 * inveld: 7 bit
+	 */
+	__u8 iv_tls_ld;
+
+	/* Just using type2 BD now */
+	struct sec_sqe_type2 type2;
+};
+
+int sec_register_to_crypto(void);
+void sec_unregister_from_crypto(void);
+#endif
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sec2/sec_main.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sec2/sec_main.c
@@ -0,0 +1,1124 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 HiSilicon Limited. */
+
+#include <linux/acpi.h>
+#include <linux/aer.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/seq_file.h>
+#include <linux/topology.h>
+
+#include "sec.h"
+
+#define SEC_VF_NUM			63
+#define SEC_QUEUE_NUM_V1		4096
+#define SEC_QUEUE_NUM_V2		1024
+#define SEC_PF_PCI_DEVICE_ID		0xa255
+#define SEC_VF_PCI_DEVICE_ID		0xa256
+
+#define SEC_BD_ERR_CHK_EN0		0xEFFFFFFF
+#define SEC_BD_ERR_CHK_EN1		0x7ffff7fd
+#define SEC_BD_ERR_CHK_EN3		0xffffbfff
+
+#define SEC_SQE_SIZE			128
+#define SEC_SQ_SIZE			(SEC_SQE_SIZE * QM_Q_DEPTH)
+#define SEC_PF_DEF_Q_NUM		256
+#define SEC_PF_DEF_Q_BASE		0
+#define SEC_CTX_Q_NUM_DEF		2
+#define SEC_CTX_Q_NUM_MAX		32
+
+#define SEC_CTRL_CNT_CLR_CE		0x301120
+#define SEC_CTRL_CNT_CLR_CE_BIT		BIT(0)
+#define SEC_ENGINE_PF_CFG_OFF		0x300000
+#define SEC_ACC_COMMON_REG_OFF		0x1000
+#define SEC_CORE_INT_SOURCE		0x301010
+#define SEC_CORE_INT_MASK		0x301000
+#define SEC_CORE_INT_STATUS		0x301008
+#define SEC_CORE_SRAM_ECC_ERR_INFO	0x301C14
+#define SEC_ECC_NUM(err)			(((err) >> 16) & 0xFF)
+#define SEC_ECC_ADDR(err)			((err) >> 0)
+#define SEC_CORE_INT_DISABLE		0x0
+#define SEC_CORE_INT_ENABLE		0x1ff
+#define SEC_CORE_INT_CLEAR		0x1ff
+#define SEC_SAA_ENABLE			0x17f
+
+#define SEC_RAS_CE_REG			0x301050
+#define SEC_RAS_FE_REG			0x301054
+#define SEC_RAS_NFE_REG			0x301058
+#define SEC_RAS_CE_ENB_MSK		0x88
+#define SEC_RAS_FE_ENB_MSK		0x0
+#define SEC_RAS_NFE_ENB_MSK		0x177
+#define SEC_RAS_DISABLE			0x0
+#define SEC_MEM_START_INIT_REG		0x0100
+#define SEC_MEM_INIT_DONE_REG		0x0104
+
+#define SEC_CONTROL_REG			0x0200
+#define SEC_TRNG_EN_SHIFT		8
+#define SEC_CLK_GATE_ENABLE		BIT(3)
+#define SEC_CLK_GATE_DISABLE		(~BIT(3))
+#define SEC_AXI_SHUTDOWN_ENABLE	BIT(12)
+#define SEC_AXI_SHUTDOWN_DISABLE	0xFFFFEFFF
+
+#define SEC_INTERFACE_USER_CTRL0_REG	0x0220
+#define SEC_INTERFACE_USER_CTRL1_REG	0x0224
+#define SEC_SAA_EN_REG					0x0270
+#define SEC_BD_ERR_CHK_EN_REG0		0x0380
+#define SEC_BD_ERR_CHK_EN_REG1		0x0384
+#define SEC_BD_ERR_CHK_EN_REG3		0x038c
+
+#define SEC_USER0_SMMU_NORMAL		(BIT(23) | BIT(15))
+#define SEC_USER1_SMMU_NORMAL		(BIT(31) | BIT(23) | BIT(15) | BIT(7))
+#define SEC_CORE_INT_STATUS_M_ECC	BIT(2)
+
+#define SEC_DELAY_10_US			10
+#define SEC_POLL_TIMEOUT_US		1000
+#define SEC_DBGFS_VAL_MAX_LEN		20
+#define SEC_SINGLE_PORT_MAX_TRANS	0x2060
+
+#define SEC_ADDR(qm, offset) ((qm)->io_base + (offset) + \
+			     SEC_ENGINE_PF_CFG_OFF + SEC_ACC_COMMON_REG_OFF)
+
+struct sec_hw_error {
+	u32 int_msk;
+	const char *msg;
+};
+
+static const char sec_name[] = "hisi_sec2";
+static struct dentry *sec_debugfs_root;
+static LIST_HEAD(sec_list);
+static DEFINE_MUTEX(sec_list_lock);
+
+static const struct sec_hw_error sec_hw_errors[] = {
+	{.int_msk = BIT(0), .msg = "sec_axi_rresp_err_rint"},
+	{.int_msk = BIT(1), .msg = "sec_axi_bresp_err_rint"},
+	{.int_msk = BIT(2), .msg = "sec_ecc_2bit_err_rint"},
+	{.int_msk = BIT(3), .msg = "sec_ecc_1bit_err_rint"},
+	{.int_msk = BIT(4), .msg = "sec_req_trng_timeout_rint"},
+	{.int_msk = BIT(5), .msg = "sec_fsm_hbeat_rint"},
+	{.int_msk = BIT(6), .msg = "sec_channel_req_rng_timeout_rint"},
+	{.int_msk = BIT(7), .msg = "sec_bd_err_rint"},
+	{.int_msk = BIT(8), .msg = "sec_chain_buff_err_rint"},
+	{ /* sentinel */ }
+};
+
+struct sec_dev *sec_find_device(int node)
+{
+#define SEC_NUMA_MAX_DISTANCE	100
+	int min_distance = SEC_NUMA_MAX_DISTANCE;
+	int dev_node = 0, free_qp_num = 0;
+	struct sec_dev *sec, *ret = NULL;
+	struct hisi_qm *qm;
+	struct device *dev;
+
+	mutex_lock(&sec_list_lock);
+	list_for_each_entry(sec, &sec_list, list) {
+		qm = &sec->qm;
+		dev = &qm->pdev->dev;
+#ifdef CONFIG_NUMA
+		dev_node = dev->numa_node;
+		if (dev_node < 0)
+			dev_node = 0;
+#endif
+		if (node_distance(dev_node, node) < min_distance) {
+			free_qp_num = hisi_qm_get_free_qp_num(qm);
+			if (free_qp_num >= sec->ctx_q_num) {
+				ret = sec;
+				min_distance = node_distance(dev_node, node);
+			}
+		}
+	}
+	mutex_unlock(&sec_list_lock);
+
+	return ret;
+}
+
+static const char * const sec_dbg_file_name[] = {
+	[SEC_CURRENT_QM] = "current_qm",
+	[SEC_CLEAR_ENABLE] = "clear_enable",
+};
+
+static struct debugfs_reg32 sec_dfx_regs[] = {
+	{"SEC_PF_ABNORMAL_INT_SOURCE    ",  0x301010},
+	{"SEC_SAA_EN                    ",  0x301270},
+	{"SEC_BD_LATENCY_MIN            ",  0x301600},
+	{"SEC_BD_LATENCY_MAX            ",  0x301608},
+	{"SEC_BD_LATENCY_AVG            ",  0x30160C},
+	{"SEC_BD_NUM_IN_SAA0            ",  0x301670},
+	{"SEC_BD_NUM_IN_SAA1            ",  0x301674},
+	{"SEC_BD_NUM_IN_SEC             ",  0x301680},
+	{"SEC_ECC_1BIT_CNT              ",  0x301C00},
+	{"SEC_ECC_1BIT_INFO             ",  0x301C04},
+	{"SEC_ECC_2BIT_CNT              ",  0x301C10},
+	{"SEC_ECC_2BIT_INFO             ",  0x301C14},
+	{"SEC_BD_SAA0                   ",  0x301C20},
+	{"SEC_BD_SAA1                   ",  0x301C24},
+	{"SEC_BD_SAA2                   ",  0x301C28},
+	{"SEC_BD_SAA3                   ",  0x301C2C},
+	{"SEC_BD_SAA4                   ",  0x301C30},
+	{"SEC_BD_SAA5                   ",  0x301C34},
+	{"SEC_BD_SAA6                   ",  0x301C38},
+	{"SEC_BD_SAA7                   ",  0x301C3C},
+	{"SEC_BD_SAA8                   ",  0x301C40},
+};
+
+static int sec_pf_q_num_set(const char *val, const struct kernel_param *kp)
+{
+	struct pci_dev *pdev;
+	u32 n, q_num;
+	u8 rev_id;
+	int ret;
+
+	if (!val)
+		return -EINVAL;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_HUAWEI,
+			      SEC_PF_PCI_DEVICE_ID, NULL);
+	if (!pdev) {
+		q_num = min_t(u32, SEC_QUEUE_NUM_V1, SEC_QUEUE_NUM_V2);
+		pr_info("No device, suppose queue number is %d!\n", q_num);
+	} else {
+		rev_id = pdev->revision;
+
+		switch (rev_id) {
+		case QM_HW_V1:
+			q_num = SEC_QUEUE_NUM_V1;
+			break;
+		case QM_HW_V2:
+			q_num = SEC_QUEUE_NUM_V2;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = kstrtou32(val, 10, &n);
+	if (ret || !n || n > q_num)
+		return -EINVAL;
+
+	return param_set_int(val, kp);
+}
+
+static const struct kernel_param_ops sec_pf_q_num_ops = {
+	.set = sec_pf_q_num_set,
+	.get = param_get_int,
+};
+static u32 pf_q_num = SEC_PF_DEF_Q_NUM;
+module_param_cb(pf_q_num, &sec_pf_q_num_ops, &pf_q_num, 0444);
+MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 0-4096, v2 0-1024)");
+
+static int sec_ctx_q_num_set(const char *val, const struct kernel_param *kp)
+{
+	u32 ctx_q_num;
+	int ret;
+
+	if (!val)
+		return -EINVAL;
+
+	ret = kstrtou32(val, 10, &ctx_q_num);
+	if (ret)
+		return -EINVAL;
+
+	if (!ctx_q_num || ctx_q_num > SEC_CTX_Q_NUM_MAX || ctx_q_num & 0x1) {
+		pr_err("ctx queue num[%u] is invalid!\n", ctx_q_num);
+		return -EINVAL;
+	}
+
+	return param_set_int(val, kp);
+}
+
+static const struct kernel_param_ops sec_ctx_q_num_ops = {
+	.set = sec_ctx_q_num_set,
+	.get = param_get_int,
+};
+static u32 ctx_q_num = SEC_CTX_Q_NUM_DEF;
+module_param_cb(ctx_q_num, &sec_ctx_q_num_ops, &ctx_q_num, 0444);
+MODULE_PARM_DESC(ctx_q_num, "Queue num in ctx (2 default, 2, 4, ..., 32)");
+
+static const struct pci_device_id sec_dev_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, SEC_PF_PCI_DEVICE_ID) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, SEC_VF_PCI_DEVICE_ID) },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, sec_dev_ids);
+
+static inline void sec_add_to_list(struct sec_dev *sec)
+{
+	mutex_lock(&sec_list_lock);
+	list_add_tail(&sec->list, &sec_list);
+	mutex_unlock(&sec_list_lock);
+}
+
+static inline void sec_remove_from_list(struct sec_dev *sec)
+{
+	mutex_lock(&sec_list_lock);
+	list_del(&sec->list);
+	mutex_unlock(&sec_list_lock);
+}
+
+static u8 sec_get_endian(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	u32 reg;
+
+	/*
+	 * As for VF, it is a wrong way to get endian setting by
+	 * reading a register of the engine
+	 */
+	if (qm->pdev->is_virtfn) {
+		dev_err_ratelimited(&qm->pdev->dev,
+				    "cannot access a register in VF!\n");
+		return SEC_LE;
+	}
+	reg = readl_relaxed(qm->io_base + SEC_ENGINE_PF_CFG_OFF +
+			    SEC_ACC_COMMON_REG_OFF + SEC_CONTROL_REG);
+
+	/* BD little endian mode */
+	if (!(reg & BIT(0)))
+		return SEC_LE;
+
+	/* BD 32-bits big endian mode */
+	else if (!(reg & BIT(1)))
+		return SEC_32BE;
+
+	/* BD 64-bits big endian mode */
+	else
+		return SEC_64BE;
+}
+
+static int sec_engine_init(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	int ret;
+	u32 reg;
+
+	/* disable clock gate control */
+	reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG));
+	reg &= SEC_CLK_GATE_DISABLE;
+	writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG));
+
+	writel_relaxed(0x1, SEC_ADDR(qm, SEC_MEM_START_INIT_REG));
+
+	ret = readl_relaxed_poll_timeout(SEC_ADDR(qm, SEC_MEM_INIT_DONE_REG),
+					 reg, reg & 0x1, SEC_DELAY_10_US,
+					 SEC_POLL_TIMEOUT_US);
+	if (ret) {
+		dev_err(&qm->pdev->dev, "fail to init sec mem\n");
+		return ret;
+	}
+
+	reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG));
+	reg |= (0x1 << SEC_TRNG_EN_SHIFT);
+	writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG));
+
+	reg = readl_relaxed(SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL0_REG));
+	reg |= SEC_USER0_SMMU_NORMAL;
+	writel_relaxed(reg, SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL0_REG));
+
+	reg = readl_relaxed(SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL1_REG));
+	reg |= SEC_USER1_SMMU_NORMAL;
+	writel_relaxed(reg, SEC_ADDR(qm, SEC_INTERFACE_USER_CTRL1_REG));
+
+	writel(SEC_SINGLE_PORT_MAX_TRANS,
+	       qm->io_base + AM_CFG_SINGLE_PORT_MAX_TRANS);
+
+	writel(SEC_SAA_ENABLE, SEC_ADDR(qm, SEC_SAA_EN_REG));
+
+	/* Enable sm4 extra mode, as ctr/ecb */
+	writel_relaxed(SEC_BD_ERR_CHK_EN0,
+		       SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG0));
+	/* Enable sm4 xts mode multiple iv */
+	writel_relaxed(SEC_BD_ERR_CHK_EN1,
+		       SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG1));
+	writel_relaxed(SEC_BD_ERR_CHK_EN3,
+		       SEC_ADDR(qm, SEC_BD_ERR_CHK_EN_REG3));
+
+	/* config endian */
+	reg = readl_relaxed(SEC_ADDR(qm, SEC_CONTROL_REG));
+	reg |= sec_get_endian(sec);
+	writel_relaxed(reg, SEC_ADDR(qm, SEC_CONTROL_REG));
+
+	return 0;
+}
+
+static int sec_set_user_domain_and_cache(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+
+	/* qm user domain */
+	writel(AXUSER_BASE, qm->io_base + QM_ARUSER_M_CFG_1);
+	writel(ARUSER_M_CFG_ENABLE, qm->io_base + QM_ARUSER_M_CFG_ENABLE);
+	writel(AXUSER_BASE, qm->io_base + QM_AWUSER_M_CFG_1);
+	writel(AWUSER_M_CFG_ENABLE, qm->io_base + QM_AWUSER_M_CFG_ENABLE);
+	writel(WUSER_M_CFG_ENABLE, qm->io_base + QM_WUSER_M_CFG_ENABLE);
+
+	/* qm cache */
+	writel(AXI_M_CFG, qm->io_base + QM_AXI_M_CFG);
+	writel(AXI_M_CFG_ENABLE, qm->io_base + QM_AXI_M_CFG_ENABLE);
+
+	/* disable FLR triggered by BME(bus master enable) */
+	writel(PEH_AXUSER_CFG, qm->io_base + QM_PEH_AXUSER_CFG);
+	writel(PEH_AXUSER_CFG_ENABLE, qm->io_base + QM_PEH_AXUSER_CFG_ENABLE);
+
+	/* enable sqc,cqc writeback */
+	writel(SQC_CACHE_ENABLE | CQC_CACHE_ENABLE | SQC_CACHE_WB_ENABLE |
+	       CQC_CACHE_WB_ENABLE | FIELD_PREP(SQC_CACHE_WB_THRD, 1) |
+	       FIELD_PREP(CQC_CACHE_WB_THRD, 1), qm->io_base + QM_CACHE_CTL);
+
+	return sec_engine_init(sec);
+}
+
+/* sec_debug_regs_clear() - clear the sec debug regs */
+static void sec_debug_regs_clear(struct hisi_qm *qm)
+{
+	/* clear current_qm */
+	writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
+	writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+
+	/* clear rdclr_en */
+	writel(0x0, qm->io_base + SEC_CTRL_CNT_CLR_CE);
+
+	hisi_qm_debug_regs_clear(qm);
+}
+
+static void sec_hw_error_enable(struct hisi_qm *qm)
+{
+	u32 val;
+
+	if (qm->ver == QM_HW_V1) {
+		writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
+		dev_info(&qm->pdev->dev, "V1 not support hw error handle\n");
+		return;
+	}
+
+	val = readl(SEC_ADDR(qm, SEC_CONTROL_REG));
+
+	/* clear SEC hw error source if having */
+	writel(SEC_CORE_INT_CLEAR, qm->io_base + SEC_CORE_INT_SOURCE);
+
+	/* enable SEC hw error interrupts */
+	writel(SEC_CORE_INT_ENABLE, qm->io_base + SEC_CORE_INT_MASK);
+
+	/* enable RAS int */
+	writel(SEC_RAS_CE_ENB_MSK, qm->io_base + SEC_RAS_CE_REG);
+	writel(SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_RAS_FE_REG);
+	writel(SEC_RAS_NFE_ENB_MSK, qm->io_base + SEC_RAS_NFE_REG);
+
+	/* enable SEC block master OOO when m-bit error occur */
+	val = val | SEC_AXI_SHUTDOWN_ENABLE;
+
+	writel(val, SEC_ADDR(qm, SEC_CONTROL_REG));
+}
+
+static void sec_hw_error_disable(struct hisi_qm *qm)
+{
+	u32 val;
+
+	val = readl(SEC_ADDR(qm, SEC_CONTROL_REG));
+
+	/* disable RAS int */
+	writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_CE_REG);
+	writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_FE_REG);
+	writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_NFE_REG);
+
+	/* disable SEC hw error interrupts */
+	writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
+
+	/* disable SEC block master OOO when m-bit error occur */
+	val = val & SEC_AXI_SHUTDOWN_DISABLE;
+
+	writel(val, SEC_ADDR(qm, SEC_CONTROL_REG));
+}
+
+static u32 sec_current_qm_read(struct sec_debug_file *file)
+{
+	struct hisi_qm *qm = file->qm;
+
+	return readl(qm->io_base + QM_DFX_MB_CNT_VF);
+}
+
+static int sec_current_qm_write(struct sec_debug_file *file, u32 val)
+{
+	struct hisi_qm *qm = file->qm;
+	struct sec_dev *sec = container_of(qm, struct sec_dev, qm);
+	u32 vfq_num;
+	u32 tmp;
+
+	if (val > sec->num_vfs)
+		return -EINVAL;
+
+	/* According PF or VF Dev ID to calculation curr_qm_qp_num and store */
+	if (!val) {
+		qm->debug.curr_qm_qp_num = qm->qp_num;
+	} else {
+		vfq_num = (qm->ctrl_qp_num - qm->qp_num) / sec->num_vfs;
+
+		if (val == sec->num_vfs)
+			qm->debug.curr_qm_qp_num =
+				qm->ctrl_qp_num - qm->qp_num -
+				(sec->num_vfs - 1) * vfq_num;
+		else
+			qm->debug.curr_qm_qp_num = vfq_num;
+	}
+
+	writel(val, qm->io_base + QM_DFX_MB_CNT_VF);
+	writel(val, qm->io_base + QM_DFX_DB_CNT_VF);
+
+	tmp = val |
+	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK);
+	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
+
+	tmp = val |
+	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK);
+	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
+
+	return 0;
+}
+
+static u32 sec_clear_enable_read(struct sec_debug_file *file)
+{
+	struct hisi_qm *qm = file->qm;
+
+	return readl(qm->io_base + SEC_CTRL_CNT_CLR_CE) &
+			SEC_CTRL_CNT_CLR_CE_BIT;
+}
+
+static int sec_clear_enable_write(struct sec_debug_file *file, u32 val)
+{
+	struct hisi_qm *qm = file->qm;
+	u32 tmp;
+
+	if (val != 1 && val)
+		return -EINVAL;
+
+	tmp = (readl(qm->io_base + SEC_CTRL_CNT_CLR_CE) &
+	       ~SEC_CTRL_CNT_CLR_CE_BIT) | val;
+	writel(tmp, qm->io_base + SEC_CTRL_CNT_CLR_CE);
+
+	return 0;
+}
+
+static ssize_t sec_debug_read(struct file *filp, char __user *buf,
+			       size_t count, loff_t *pos)
+{
+	struct sec_debug_file *file = filp->private_data;
+	char tbuf[SEC_DBGFS_VAL_MAX_LEN];
+	u32 val;
+	int ret;
+
+	spin_lock_irq(&file->lock);
+
+	switch (file->index) {
+	case SEC_CURRENT_QM:
+		val = sec_current_qm_read(file);
+		break;
+	case SEC_CLEAR_ENABLE:
+		val = sec_clear_enable_read(file);
+		break;
+	default:
+		spin_unlock_irq(&file->lock);
+		return -EINVAL;
+	}
+
+	spin_unlock_irq(&file->lock);
+	ret = snprintf(tbuf, SEC_DBGFS_VAL_MAX_LEN, "%u\n", val);
+
+	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
+}
+
+static ssize_t sec_debug_write(struct file *filp, const char __user *buf,
+			       size_t count, loff_t *pos)
+{
+	struct sec_debug_file *file = filp->private_data;
+	char tbuf[SEC_DBGFS_VAL_MAX_LEN];
+	unsigned long val;
+	int len, ret;
+
+	if (*pos != 0)
+		return 0;
+
+	if (count >= SEC_DBGFS_VAL_MAX_LEN)
+		return -ENOSPC;
+
+	len = simple_write_to_buffer(tbuf, SEC_DBGFS_VAL_MAX_LEN - 1,
+				     pos, buf, count);
+	if (len < 0)
+		return len;
+
+	tbuf[len] = '\0';
+	if (kstrtoul(tbuf, 0, &val))
+		return -EFAULT;
+
+	spin_lock_irq(&file->lock);
+
+	switch (file->index) {
+	case SEC_CURRENT_QM:
+		ret = sec_current_qm_write(file, val);
+		if (ret)
+			goto err_input;
+		break;
+	case SEC_CLEAR_ENABLE:
+		ret = sec_clear_enable_write(file, val);
+		if (ret)
+			goto err_input;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err_input;
+	}
+
+	spin_unlock_irq(&file->lock);
+
+	return count;
+
+ err_input:
+	spin_unlock_irq(&file->lock);
+	return ret;
+}
+
+static const struct file_operations sec_dbg_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = sec_debug_read,
+	.write = sec_debug_write,
+};
+
+static int sec_debugfs_atomic64_get(void *data, u64 *val)
+{
+	*val = atomic64_read((atomic64_t *)data);
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(sec_atomic64_ops, sec_debugfs_atomic64_get,
+			 NULL, "%lld\n");
+
+static int sec_core_debug_init(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	struct device *dev = &qm->pdev->dev;
+	struct sec_dfx *dfx = &sec->debug.dfx;
+	struct debugfs_regset32 *regset;
+	struct dentry *tmp_d;
+
+	tmp_d = debugfs_create_dir("sec_dfx", sec->qm.debug.debug_root);
+
+	regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
+	if (!regset)
+		return -ENOENT;
+
+	regset->regs = sec_dfx_regs;
+	regset->nregs = ARRAY_SIZE(sec_dfx_regs);
+	regset->base = qm->io_base;
+
+	debugfs_create_regset32("regs", 0444, tmp_d, regset);
+
+	debugfs_create_file("send_cnt", 0444, tmp_d,
+			    &dfx->send_cnt, &sec_atomic64_ops);
+
+	debugfs_create_file("recv_cnt", 0444, tmp_d,
+			    &dfx->recv_cnt, &sec_atomic64_ops);
+
+	return 0;
+}
+
+static int sec_debug_init(struct sec_dev *sec)
+{
+	int i;
+
+	for (i = SEC_CURRENT_QM; i < SEC_DEBUG_FILE_NUM; i++) {
+		spin_lock_init(&sec->debug.files[i].lock);
+		sec->debug.files[i].index = i;
+		sec->debug.files[i].qm = &sec->qm;
+
+		debugfs_create_file(sec_dbg_file_name[i], 0600,
+				    sec->qm.debug.debug_root,
+				    sec->debug.files + i,
+				    &sec_dbg_fops);
+	}
+
+	return sec_core_debug_init(sec);
+}
+
+static int sec_debugfs_init(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	struct device *dev = &qm->pdev->dev;
+	int ret;
+
+	qm->debug.debug_root = debugfs_create_dir(dev_name(dev),
+						  sec_debugfs_root);
+	ret = hisi_qm_debug_init(qm);
+	if (ret)
+		goto failed_to_create;
+
+	if (qm->pdev->device == SEC_PF_PCI_DEVICE_ID) {
+		ret = sec_debug_init(sec);
+		if (ret)
+			goto failed_to_create;
+	}
+
+	return 0;
+
+failed_to_create:
+	debugfs_remove_recursive(sec_debugfs_root);
+
+	return ret;
+}
+
+static void sec_debugfs_exit(struct sec_dev *sec)
+{
+	debugfs_remove_recursive(sec->qm.debug.debug_root);
+}
+
+static const struct hisi_qm_err_ini sec_err_ini = {
+	.hw_err_enable	= sec_hw_error_enable,
+	.hw_err_disable	= sec_hw_error_disable,
+	.err_info	= {
+		.ce		= QM_BASE_CE,
+		.nfe		= QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT |
+				  QM_ACC_WB_NOT_READY_TIMEOUT,
+		.fe		= 0,
+		.msi		= QM_DB_RANDOM_INVALID,
+	}
+};
+
+static int sec_pf_probe_init(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	int ret;
+
+	switch (qm->ver) {
+	case QM_HW_V1:
+		qm->ctrl_qp_num = SEC_QUEUE_NUM_V1;
+		break;
+
+	case QM_HW_V2:
+		qm->ctrl_qp_num = SEC_QUEUE_NUM_V2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	qm->err_ini = &sec_err_ini;
+
+	ret = sec_set_user_domain_and_cache(sec);
+	if (ret)
+		return ret;
+
+	hisi_qm_dev_err_init(qm);
+	sec_debug_regs_clear(qm);
+
+	return 0;
+}
+
+static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
+{
+	enum qm_hw_ver rev_id;
+
+	rev_id = hisi_qm_get_hw_version(pdev);
+	if (rev_id == QM_HW_UNKNOWN)
+		return -ENODEV;
+
+	qm->pdev = pdev;
+	qm->ver = rev_id;
+
+	qm->sqe_size = SEC_SQE_SIZE;
+	qm->dev_name = sec_name;
+	qm->fun_type = (pdev->device == SEC_PF_PCI_DEVICE_ID) ?
+			QM_HW_PF : QM_HW_VF;
+	qm->use_dma_api = true;
+
+	return hisi_qm_init(qm);
+}
+
+static void sec_qm_uninit(struct hisi_qm *qm)
+{
+	hisi_qm_uninit(qm);
+}
+
+static int sec_probe_init(struct hisi_qm *qm, struct sec_dev *sec)
+{
+	int ret;
+
+	/*
+	 * WQ_HIGHPRI: SEC request must be low delayed,
+	 * so need a high priority workqueue.
+	 * WQ_UNBOUND: SEC task is likely with long
+	 * running CPU intensive workloads.
+	 */
+	qm->wq = alloc_workqueue("%s", WQ_HIGHPRI |
+		WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus(),
+		pci_name(qm->pdev));
+	if (!qm->wq) {
+		pci_err(qm->pdev, "fail to alloc workqueue\n");
+		return -ENOMEM;
+	}
+
+	if (qm->fun_type == QM_HW_PF) {
+		qm->qp_base = SEC_PF_DEF_Q_BASE;
+		qm->qp_num = pf_q_num;
+		qm->debug.curr_qm_qp_num = pf_q_num;
+
+		ret = sec_pf_probe_init(sec);
+		if (ret)
+			goto err_probe_uninit;
+	} else if (qm->fun_type == QM_HW_VF) {
+		/*
+		 * have no way to get qm configure in VM in v1 hardware,
+		 * so currently force PF to uses SEC_PF_DEF_Q_NUM, and force
+		 * to trigger only one VF in v1 hardware.
+		 * v2 hardware has no such problem.
+		 */
+		if (qm->ver == QM_HW_V1) {
+			qm->qp_base = SEC_PF_DEF_Q_NUM;
+			qm->qp_num = SEC_QUEUE_NUM_V1 - SEC_PF_DEF_Q_NUM;
+		} else if (qm->ver == QM_HW_V2) {
+			/* v2 starts to support get vft by mailbox */
+			ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
+			if (ret)
+				goto err_probe_uninit;
+		}
+	} else {
+		ret = -ENODEV;
+		goto err_probe_uninit;
+	}
+
+	return 0;
+err_probe_uninit:
+	destroy_workqueue(qm->wq);
+	return ret;
+}
+
+static void sec_probe_uninit(struct hisi_qm *qm)
+{
+	hisi_qm_dev_err_uninit(qm);
+
+	destroy_workqueue(qm->wq);
+}
+
+static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct sec_dev *sec;
+	struct hisi_qm *qm;
+	int ret;
+
+	sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
+	if (!sec)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, sec);
+
+	sec->ctx_q_num = ctx_q_num;
+
+	qm = &sec->qm;
+
+	ret = sec_qm_init(qm, pdev);
+	if (ret) {
+		pci_err(pdev, "Failed to pre init qm!\n");
+		return ret;
+	}
+
+	ret = sec_probe_init(qm, sec);
+	if (ret) {
+		pci_err(pdev, "Failed to probe!\n");
+		goto err_qm_uninit;
+	}
+
+	ret = hisi_qm_start(qm);
+	if (ret) {
+		pci_err(pdev, "Failed to start sec qm!\n");
+		goto err_probe_uninit;
+	}
+
+	ret = sec_debugfs_init(sec);
+	if (ret)
+		pci_warn(pdev, "Failed to init debugfs!\n");
+
+	sec_add_to_list(sec);
+
+	ret = sec_register_to_crypto();
+	if (ret < 0) {
+		pr_err("Failed to register driver to crypto.\n");
+		goto err_remove_from_list;
+	}
+
+	return 0;
+
+err_remove_from_list:
+	sec_remove_from_list(sec);
+	sec_debugfs_exit(sec);
+	hisi_qm_stop(qm);
+
+err_probe_uninit:
+	sec_probe_uninit(qm);
+
+err_qm_uninit:
+	sec_qm_uninit(qm);
+
+	return ret;
+}
+
+/* now we only support equal assignment */
+static int sec_vf_q_assign(struct sec_dev *sec, u32 num_vfs)
+{
+	struct hisi_qm *qm = &sec->qm;
+	u32 qp_num = qm->qp_num;
+	u32 q_base = qp_num;
+	u32 q_num, remain_q_num;
+	int i, j, ret;
+
+	if (!num_vfs)
+		return -EINVAL;
+
+	remain_q_num = qm->ctrl_qp_num - qp_num;
+	q_num = remain_q_num / num_vfs;
+
+	for (i = 1; i <= num_vfs; i++) {
+		if (i == num_vfs)
+			q_num += remain_q_num % num_vfs;
+		ret = hisi_qm_set_vft(qm, i, q_base, q_num);
+		if (ret) {
+			for (j = i; j > 0; j--)
+				hisi_qm_set_vft(qm, j, 0, 0);
+			return ret;
+		}
+		q_base += q_num;
+	}
+
+	return 0;
+}
+
+static int sec_clear_vft_config(struct sec_dev *sec)
+{
+	struct hisi_qm *qm = &sec->qm;
+	u32 num_vfs = sec->num_vfs;
+	int ret;
+	u32 i;
+
+	for (i = 1; i <= num_vfs; i++) {
+		ret = hisi_qm_set_vft(qm, i, 0, 0);
+		if (ret)
+			return ret;
+	}
+
+	sec->num_vfs = 0;
+
+	return 0;
+}
+
+static int sec_sriov_enable(struct pci_dev *pdev, int max_vfs)
+{
+	struct sec_dev *sec = pci_get_drvdata(pdev);
+	int pre_existing_vfs, ret;
+	u32 num_vfs;
+
+	pre_existing_vfs = pci_num_vf(pdev);
+
+	if (pre_existing_vfs) {
+		pci_err(pdev, "Can't enable VF. Please disable at first!\n");
+		return 0;
+	}
+
+	num_vfs = min_t(u32, max_vfs, SEC_VF_NUM);
+
+	ret = sec_vf_q_assign(sec, num_vfs);
+	if (ret) {
+		pci_err(pdev, "Can't assign queues for VF!\n");
+		return ret;
+	}
+
+	sec->num_vfs = num_vfs;
+
+	ret = pci_enable_sriov(pdev, num_vfs);
+	if (ret) {
+		pci_err(pdev, "Can't enable VF!\n");
+		sec_clear_vft_config(sec);
+		return ret;
+	}
+
+	return num_vfs;
+}
+
+static int sec_sriov_disable(struct pci_dev *pdev)
+{
+	struct sec_dev *sec = pci_get_drvdata(pdev);
+
+	if (pci_vfs_assigned(pdev)) {
+		pci_err(pdev, "Can't disable VFs while VFs are assigned!\n");
+		return -EPERM;
+	}
+
+	/* remove in sec_pci_driver will be called to free VF resources */
+	pci_disable_sriov(pdev);
+
+	return sec_clear_vft_config(sec);
+}
+
+static int sec_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+	if (num_vfs)
+		return sec_sriov_enable(pdev, num_vfs);
+	else
+		return sec_sriov_disable(pdev);
+}
+
+static void sec_remove(struct pci_dev *pdev)
+{
+	struct sec_dev *sec = pci_get_drvdata(pdev);
+	struct hisi_qm *qm = &sec->qm;
+
+	sec_unregister_from_crypto();
+
+	sec_remove_from_list(sec);
+
+	if (qm->fun_type == QM_HW_PF && sec->num_vfs)
+		(void)sec_sriov_disable(pdev);
+
+	sec_debugfs_exit(sec);
+
+	(void)hisi_qm_stop(qm);
+
+	if (qm->fun_type == QM_HW_PF)
+		sec_debug_regs_clear(qm);
+
+	sec_probe_uninit(qm);
+
+	sec_qm_uninit(qm);
+}
+
+static void sec_log_hw_error(struct sec_dev *sec, u32 err_sts)
+{
+	const struct sec_hw_error *errs = sec_hw_errors;
+	struct device *dev = &sec->qm.pdev->dev;
+	u32 err_val;
+
+	while (errs->msg) {
+		if (errs->int_msk & err_sts) {
+			dev_err(dev, "%s [error status=0x%x] found\n",
+				errs->msg, errs->int_msk);
+
+			if (SEC_CORE_INT_STATUS_M_ECC & err_sts) {
+				err_val = readl(sec->qm.io_base +
+						SEC_CORE_SRAM_ECC_ERR_INFO);
+				dev_err(dev, "multi ecc sram num=0x%x\n",
+					SEC_ECC_NUM(err_val));
+				dev_err(dev, "multi ecc sram addr=0x%x\n",
+					SEC_ECC_ADDR(err_val));
+			}
+		}
+		errs++;
+	}
+}
+
+static pci_ers_result_t sec_hw_error_handle(struct sec_dev *sec)
+{
+	u32 err_sts;
+
+	/* read err sts */
+	err_sts = readl(sec->qm.io_base + SEC_CORE_INT_STATUS);
+	if (err_sts) {
+		sec_log_hw_error(sec, err_sts);
+
+		/* clear error interrupts */
+		writel(err_sts, sec->qm.io_base + SEC_CORE_INT_SOURCE);
+
+		return PCI_ERS_RESULT_NEED_RESET;
+	}
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t sec_process_hw_error(struct pci_dev *pdev)
+{
+	struct sec_dev *sec = pci_get_drvdata(pdev);
+	pci_ers_result_t qm_ret, sec_ret;
+
+	if (!sec) {
+		pci_err(pdev, "Can't recover error during device init\n");
+		return PCI_ERS_RESULT_NONE;
+	}
+
+	/* log qm error */
+	qm_ret = hisi_qm_hw_error_handle(&sec->qm);
+
+	/* log sec error */
+	sec_ret = sec_hw_error_handle(sec);
+
+	return (qm_ret == PCI_ERS_RESULT_NEED_RESET ||
+		sec_ret == PCI_ERS_RESULT_NEED_RESET) ?
+		PCI_ERS_RESULT_NEED_RESET : PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t sec_error_detected(struct pci_dev *pdev,
+					   pci_channel_state_t state)
+{
+	if (pdev->is_virtfn)
+		return PCI_ERS_RESULT_NONE;
+
+	pci_info(pdev, "PCI error detected, state(=%d)!!\n", state);
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	return sec_process_hw_error(pdev);
+}
+
+static const struct pci_error_handlers sec_err_handler = {
+	.error_detected = sec_error_detected,
+};
+
+static struct pci_driver sec_pci_driver = {
+	.name = "hisi_sec2",
+	.id_table = sec_dev_ids,
+	.probe = sec_probe,
+	.remove = sec_remove,
+	.err_handler = &sec_err_handler,
+	.sriov_configure = sec_sriov_configure,
+};
+
+static void sec_register_debugfs(void)
+{
+	if (!debugfs_initialized())
+		return;
+
+	sec_debugfs_root = debugfs_create_dir("hisi_sec2", NULL);
+}
+
+static void sec_unregister_debugfs(void)
+{
+	debugfs_remove_recursive(sec_debugfs_root);
+}
+
+static int __init sec_init(void)
+{
+	int ret;
+
+	sec_register_debugfs();
+
+	ret = pci_register_driver(&sec_pci_driver);
+	if (ret < 0) {
+		sec_unregister_debugfs();
+		pr_err("Failed to register pci driver.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit sec_exit(void)
+{
+	pci_unregister_driver(&sec_pci_driver);
+	sec_unregister_debugfs();
+}
+
+module_init(sec_init);
+module_exit(sec_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
+MODULE_AUTHOR("Longfang Liu <liulongfang@huawei.com>");
+MODULE_AUTHOR("Wei Zhang <zhangwei375@huawei.com>");
+MODULE_DESCRIPTION("Driver for HiSilicon SEC accelerator");
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/sgl.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/sgl.c
@@ -2,37 +2,13 @@
 /* Copyright (c) 2019 HiSilicon Limited. */
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
-#include "./sgl.h"
+#include <linux/slab.h>
+#include "qm.h"
 
 #define HISI_ACC_SGL_SGE_NR_MIN		1
-#define HISI_ACC_SGL_SGE_NR_MAX		255
-#define HISI_ACC_SGL_SGE_NR_DEF		10
 #define HISI_ACC_SGL_NR_MAX		256
 #define HISI_ACC_SGL_ALIGN_SIZE		64
-
-static int acc_sgl_sge_set(const char *val, const struct kernel_param *kp)
-{
-	int ret;
-	u32 n;
-
-	if (!val)
-		return -EINVAL;
-
-	ret = kstrtou32(val, 10, &n);
-	if (ret != 0 || n > HISI_ACC_SGL_SGE_NR_MAX || n == 0)
-		return -EINVAL;
-
-	return param_set_int(val, kp);
-}
-
-static const struct kernel_param_ops acc_sgl_sge_ops = {
-	.set = acc_sgl_sge_set,
-	.get = param_get_int,
-};
-
-static u32 acc_sgl_sge_nr = HISI_ACC_SGL_SGE_NR_DEF;
-module_param_cb(acc_sgl_sge_nr, &acc_sgl_sge_ops, &acc_sgl_sge_nr, 0444);
-MODULE_PARM_DESC(acc_sgl_sge_nr, "Number of sge in sgl(1-255)");
+#define HISI_ACC_MEM_BLOCK_NR		5
 
 struct acc_hw_sge {
 	dma_addr_t buf;
@@ -55,37 +31,91 @@
 	struct acc_hw_sge sge_entries[];
 } __aligned(1);
 
+struct hisi_acc_sgl_pool {
+	struct mem_block {
+		struct hisi_acc_hw_sgl *sgl;
+		dma_addr_t sgl_dma;
+		size_t size;
+	} mem_block[HISI_ACC_MEM_BLOCK_NR];
+	u32 sgl_num_per_block;
+	u32 block_num;
+	u32 count;
+	u32 sge_nr;
+	size_t sgl_size;
+};
+
 /**
  * hisi_acc_create_sgl_pool() - Create a hw sgl pool.
  * @dev: The device which hw sgl pool belongs to.
- * @pool: Pointer of pool.
  * @count: Count of hisi_acc_hw_sgl in pool.
+ * @sge_nr: The count of sge in hw_sgl
  *
  * This function creates a hw sgl pool, after this user can get hw sgl memory
  * from it.
  */
-int hisi_acc_create_sgl_pool(struct device *dev,
-			     struct hisi_acc_sgl_pool *pool, u32 count)
+struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev,
+						   u32 count, u32 sge_nr)
 {
-	u32 sgl_size;
-	u32 size;
+	u32 sgl_size, block_size, sgl_num_per_block, block_num, remain_sgl = 0;
+	struct hisi_acc_sgl_pool *pool;
+	struct mem_block *block;
+	u32 i, j;
 
-	if (!dev || !pool || !count)
-		return -EINVAL;
+	if (!dev || !count || !sge_nr || sge_nr > HISI_ACC_SGL_SGE_NR_MAX)
+		return ERR_PTR(-EINVAL);
 
-	sgl_size = sizeof(struct acc_hw_sge) * acc_sgl_sge_nr +
+	sgl_size = sizeof(struct acc_hw_sge) * sge_nr +
 		   sizeof(struct hisi_acc_hw_sgl);
-	size = sgl_size * count;
+	block_size = PAGE_SIZE * (1 << (MAX_ORDER - 1));
+	sgl_num_per_block = block_size / sgl_size;
+	block_num = count / sgl_num_per_block;
+	remain_sgl = count % sgl_num_per_block;
+
+	if ((!remain_sgl && block_num > HISI_ACC_MEM_BLOCK_NR) ||
+	    (remain_sgl > 0 && block_num > HISI_ACC_MEM_BLOCK_NR - 1))
+		return ERR_PTR(-EINVAL);
+
+	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+	if (!pool)
+		return ERR_PTR(-ENOMEM);
+	block = pool->mem_block;
+
+	for (i = 0; i < block_num; i++) {
+		block[i].sgl = dma_alloc_coherent(dev, block_size,
+						  &block[i].sgl_dma,
+						  GFP_KERNEL);
+		if (!block[i].sgl)
+			goto err_free_mem;
+
+		block[i].size = block_size;
+	}
 
-	pool->sgl = dma_alloc_coherent(dev, size, &pool->sgl_dma, GFP_KERNEL);
-	if (!pool->sgl)
-		return -ENOMEM;
+	if (remain_sgl > 0) {
+		block[i].sgl = dma_alloc_coherent(dev, remain_sgl * sgl_size,
+						  &block[i].sgl_dma,
+						  GFP_KERNEL);
+		if (!block[i].sgl)
+			goto err_free_mem;
 
-	pool->size = size;
+		block[i].size = remain_sgl * sgl_size;
+	}
+
+	pool->sgl_num_per_block = sgl_num_per_block;
+	pool->block_num = remain_sgl ? block_num + 1 : block_num;
 	pool->count = count;
 	pool->sgl_size = sgl_size;
+	pool->sge_nr = sge_nr;
+
+	return pool;
 
-	return 0;
+err_free_mem:
+	for (j = 0; j < i; j++) {
+		dma_free_coherent(dev, block_size, block[j].sgl,
+				  block[j].sgl_dma);
+		memset(block + j, 0, sizeof(*block));
+	}
+	kfree(pool);
+	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool);
 
@@ -98,38 +128,57 @@
  */
 void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool)
 {
-	dma_free_coherent(dev, pool->size, pool->sgl, pool->sgl_dma);
-	memset(pool, 0, sizeof(struct hisi_acc_sgl_pool));
+	struct mem_block *block;
+	int i;
+
+	if (!dev || !pool)
+		return;
+
+	block = pool->mem_block;
+
+	for (i = 0; i < pool->block_num; i++)
+		dma_free_coherent(dev, block[i].size, block[i].sgl,
+				  block[i].sgl_dma);
+
+	kfree(pool);
 }
 EXPORT_SYMBOL_GPL(hisi_acc_free_sgl_pool);
 
-struct hisi_acc_hw_sgl *acc_get_sgl(struct hisi_acc_sgl_pool *pool, u32 index,
-				    dma_addr_t *hw_sgl_dma)
+static struct hisi_acc_hw_sgl *acc_get_sgl(struct hisi_acc_sgl_pool *pool,
+					   u32 index, dma_addr_t *hw_sgl_dma)
 {
-	if (!pool || !hw_sgl_dma || index >= pool->count || !pool->sgl)
+	struct mem_block *block;
+	u32 block_index, offset;
+
+	if (!pool || !hw_sgl_dma || index >= pool->count)
 		return ERR_PTR(-EINVAL);
 
-	*hw_sgl_dma = pool->sgl_dma + pool->sgl_size * index;
-	return (void *)pool->sgl + pool->sgl_size * index;
-}
+	block = pool->mem_block;
+	block_index = index / pool->sgl_num_per_block;
+	offset = index % pool->sgl_num_per_block;
 
-void acc_put_sgl(struct hisi_acc_sgl_pool *pool, u32 index) {}
+	*hw_sgl_dma = block[block_index].sgl_dma + pool->sgl_size * offset;
+	return (void *)block[block_index].sgl + pool->sgl_size * offset;
+}
 
 static void sg_map_to_hw_sg(struct scatterlist *sgl,
 			    struct acc_hw_sge *hw_sge)
 {
-	hw_sge->buf = sgl->dma_address;
-	hw_sge->len = sgl->dma_length;
+	hw_sge->buf = sg_dma_address(sgl);
+	hw_sge->len = cpu_to_le32(sg_dma_len(sgl));
 }
 
 static void inc_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl)
 {
-	hw_sgl->entry_sum_in_sgl++;
+	u16 var = le16_to_cpu(hw_sgl->entry_sum_in_sgl);
+
+	var++;
+	hw_sgl->entry_sum_in_sgl = cpu_to_le16(var);
 }
 
 static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum)
 {
-	hw_sgl->entry_sum_in_chain = sum;
+	hw_sgl->entry_sum_in_chain = cpu_to_le16(sum);
 }
 
 /**
@@ -153,10 +202,13 @@
 	dma_addr_t curr_sgl_dma = 0;
 	struct acc_hw_sge *curr_hw_sge;
 	struct scatterlist *sg;
-	int sg_n = sg_nents(sgl);
-	int i, ret;
+	int i, ret, sg_n;
+
+	if (!dev || !sgl || !pool || !hw_sgl_dma)
+		return ERR_PTR(-EINVAL);
 
-	if (!dev || !sgl || !pool || !hw_sgl_dma || sg_n > acc_sgl_sge_nr)
+	sg_n = sg_nents(sgl);
+	if (sg_n > pool->sge_nr)
 		return ERR_PTR(-EINVAL);
 
 	ret = dma_map_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
@@ -164,11 +216,12 @@
 		return ERR_PTR(-EINVAL);
 
 	curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
-	if (!curr_hw_sgl) {
-		ret = -ENOMEM;
-		goto err_unmap_sg;
+	if (IS_ERR(curr_hw_sgl)) {
+		dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
+		return ERR_PTR(-ENOMEM);
+
 	}
-	curr_hw_sgl->entry_length_in_sgl = acc_sgl_sge_nr;
+	curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr);
 	curr_hw_sge = curr_hw_sgl->sge_entries;
 
 	for_each_sg(sgl, sg, sg_n, i) {
@@ -177,14 +230,10 @@
 		curr_hw_sge++;
 	}
 
-	update_hw_sgl_sum_sge(curr_hw_sgl, acc_sgl_sge_nr);
+	update_hw_sgl_sum_sge(curr_hw_sgl, pool->sge_nr);
 	*hw_sgl_dma = curr_sgl_dma;
 
 	return curr_hw_sgl;
-
-err_unmap_sg:
-	dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
-	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl);
 
@@ -201,6 +250,9 @@
 void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
 			   struct hisi_acc_hw_sgl *hw_sgl)
 {
+	if (!dev || !sgl || !hw_sgl)
+		return;
+
 	dma_unmap_sg(dev, sgl, sg_nents(sgl), DMA_BIDIRECTIONAL);
 
 	hw_sgl->entry_sum_in_chain = 0;
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/zip/zip.h
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/zip/zip.h
@@ -8,10 +8,13 @@
 
 #include <linux/list.h>
 #include "../qm.h"
-#include "../sgl.h"
 
 /* hisi_zip_sqe dw3 */
 #define HZIP_BD_STATUS_M			GENMASK(7, 0)
+/* hisi_zip_sqe dw7 */
+#define HZIP_IN_SGE_DATA_OFFSET_M		GENMASK(23, 0)
+/* hisi_zip_sqe dw8 */
+#define HZIP_OUT_SGE_DATA_OFFSET_M		GENMASK(23, 0)
 /* hisi_zip_sqe dw9 */
 #define HZIP_REQ_TYPE_M				GENMASK(7, 0)
 #define HZIP_ALG_TYPE_ZLIB			0x02
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/zip/zip_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/zip/zip_crypto.c
@@ -22,6 +22,7 @@
 #define HZIP_CTX_Q_NUM				2
 #define HZIP_GZIP_HEAD_BUF			256
 #define HZIP_ALG_PRIORITY			300
+#define HZIP_SGL_SGE_NR				10
 
 static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c};
 static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {0x1f, 0x8b, 0x08, 0x0, 0x0,
@@ -41,14 +42,12 @@
 
 #define TO_HEAD(req_type)						\
 	(((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head :		\
-	 ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : 0)		\
+	 ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : NULL)		\
 
 struct hisi_zip_req {
 	struct acomp_req *req;
-	struct scatterlist *src;
-	struct scatterlist *dst;
-	size_t slen;
-	size_t dlen;
+	int sskip;
+	int dskip;
 	struct hisi_acc_hw_sgl *hw_src;
 	struct hisi_acc_hw_sgl *hw_dst;
 	dma_addr_t dma_src;
@@ -67,7 +66,7 @@
 	struct hisi_qp *qp;
 	struct hisi_zip_sqe zip_sqe;
 	struct hisi_zip_req_q req_q;
-	struct hisi_acc_sgl_pool sgl_pool;
+	struct hisi_acc_sgl_pool *sgl_pool;
 	struct hisi_zip *zip_dev;
 	struct hisi_zip_ctx *ctx;
 };
@@ -78,6 +77,30 @@
 	struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM];
 };
 
+static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+	u16 n;
+
+	if (!val)
+		return -EINVAL;
+
+	ret = kstrtou16(val, 10, &n);
+	if (ret || n == 0 || n > HISI_ACC_SGL_SGE_NR_MAX)
+		return -EINVAL;
+
+	return param_set_int(val, kp);
+}
+
+static const struct kernel_param_ops sgl_sge_nr_ops = {
+	.set = sgl_sge_nr_set,
+	.get = param_get_int,
+};
+
+static u16 sgl_sge_nr = HZIP_SGL_SGE_NR;
+module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444);
+MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)");
+
 static void hisi_zip_config_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type)
 {
 	u32 val;
@@ -94,13 +117,15 @@
 
 static void hisi_zip_fill_sqe(struct hisi_zip_sqe *sqe, u8 req_type,
 			      dma_addr_t s_addr, dma_addr_t d_addr, u32 slen,
-			      u32 dlen)
+			      u32 dlen, int sskip, int dskip)
 {
 	memset(sqe, 0, sizeof(struct hisi_zip_sqe));
 
-	sqe->input_data_length = slen;
+	sqe->input_data_length = slen - sskip;
+	sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, sskip);
+	sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, dskip);
 	sqe->dw9 = FIELD_PREP(HZIP_REQ_TYPE_M, req_type);
-	sqe->dest_avail_out = dlen;
+	sqe->dest_avail_out = dlen - dskip;
 	sqe->source_addr_l = lower_32_bits(s_addr);
 	sqe->source_addr_h = upper_32_bits(s_addr);
 	sqe->dest_addr_l = lower_32_bits(d_addr);
@@ -265,14 +290,15 @@
 static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx)
 {
 	struct hisi_zip_qp_ctx *tmp;
-	int i, ret;
+	struct device *dev;
+	int i;
 
 	for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
 		tmp = &ctx->qp_ctx[i];
-		ret = hisi_acc_create_sgl_pool(&tmp->qp->qm->pdev->dev,
-					       &tmp->sgl_pool,
-					       QM_Q_DEPTH << 1);
-		if (ret < 0) {
+		dev = &tmp->qp->qm->pdev->dev;
+		tmp->sgl_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH << 1,
+							 sgl_sge_nr);
+		if (IS_ERR(tmp->sgl_pool)) {
 			if (i == 1)
 				goto err_free_sgl_pool0;
 			return -ENOMEM;
@@ -283,7 +309,7 @@
 
 err_free_sgl_pool0:
 	hisi_acc_free_sgl_pool(&ctx->qp_ctx[QPC_COMP].qp->qm->pdev->dev,
-			       &ctx->qp_ctx[QPC_COMP].sgl_pool);
+			       ctx->qp_ctx[QPC_COMP].sgl_pool);
 	return -ENOMEM;
 }
 
@@ -293,7 +319,7 @@
 
 	for (i = 0; i < HZIP_CTX_Q_NUM; i++)
 		hisi_acc_free_sgl_pool(&ctx->qp_ctx[i].qp->qm->pdev->dev,
-				       &ctx->qp_ctx[i].sgl_pool);
+				       ctx->qp_ctx[i].sgl_pool);
 }
 
 static void hisi_zip_remove_req(struct hisi_zip_qp_ctx *qp_ctx,
@@ -301,11 +327,6 @@
 {
 	struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
 
-	if (qp_ctx->qp->alg_type == HZIP_ALG_TYPE_COMP)
-		kfree(req->dst);
-	else
-		kfree(req->src);
-
 	write_lock(&req_q->req_lock);
 	clear_bit(req->req_id, req_q->req_bitmap);
 	memset(req, 0, sizeof(struct hisi_zip_req));
@@ -333,8 +354,8 @@
 	}
 	dlen = sqe->produced;
 
-	hisi_acc_sg_buf_unmap(dev, req->src, req->hw_src);
-	hisi_acc_sg_buf_unmap(dev, req->dst, req->hw_dst);
+	hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src);
+	hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst);
 
 	head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0;
 	acomp_req->dlen = dlen + head_size;
@@ -428,20 +449,6 @@
 	}
 }
 
-static int get_sg_skip_bytes(struct scatterlist *sgl, size_t bytes,
-			     size_t remains, struct scatterlist **out)
-{
-#define SPLIT_NUM 2
-	size_t split_sizes[SPLIT_NUM];
-	int out_mapped_nents[SPLIT_NUM];
-
-	split_sizes[0] = bytes;
-	split_sizes[1] = remains;
-
-	return sg_split(sgl, 0, 0, SPLIT_NUM, split_sizes, out,
-			out_mapped_nents, GFP_KERNEL);
-}
-
 static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req,
 						struct hisi_zip_qp_ctx *qp_ctx,
 						size_t head_size, bool is_comp)
@@ -449,31 +456,7 @@
 	struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
 	struct hisi_zip_req *q = req_q->q;
 	struct hisi_zip_req *req_cache;
-	struct scatterlist *out[2];
-	struct scatterlist *sgl;
-	size_t len;
-	int ret, req_id;
-
-	/*
-	 * remove/add zlib/gzip head, as hardware operations do not include
-	 * comp head. so split req->src to get sgl without heads in acomp, or
-	 * add comp head to req->dst ahead of that hardware output compressed
-	 * data in sgl splited from req->dst without comp head.
-	 */
-	if (is_comp) {
-		sgl = req->dst;
-		len = req->dlen - head_size;
-	} else {
-		sgl = req->src;
-		len = req->slen - head_size;
-	}
-
-	ret = get_sg_skip_bytes(sgl, head_size, len, out);
-	if (ret)
-		return ERR_PTR(ret);
-
-	/* sgl for comp head is useless, so free it now */
-	kfree(out[0]);
+	int req_id;
 
 	write_lock(&req_q->req_lock);
 
@@ -481,7 +464,6 @@
 	if (req_id >= req_q->size) {
 		write_unlock(&req_q->req_lock);
 		dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n");
-		kfree(out[1]);
 		return ERR_PTR(-EBUSY);
 	}
 	set_bit(req_id, req_q->req_bitmap);
@@ -489,16 +471,13 @@
 	req_cache = q + req_id;
 	req_cache->req_id = req_id;
 	req_cache->req = req;
+
 	if (is_comp) {
-		req_cache->src = req->src;
-		req_cache->dst = out[1];
-		req_cache->slen = req->slen;
-		req_cache->dlen = req->dlen - head_size;
+		req_cache->sskip = 0;
+		req_cache->dskip = head_size;
 	} else {
-		req_cache->src = out[1];
-		req_cache->dst = req->dst;
-		req_cache->slen = req->slen - head_size;
-		req_cache->dlen = req->dlen;
+		req_cache->sskip = head_size;
+		req_cache->dskip = 0;
 	}
 
 	write_unlock(&req_q->req_lock);
@@ -510,23 +489,24 @@
 			    struct hisi_zip_qp_ctx *qp_ctx)
 {
 	struct hisi_zip_sqe *zip_sqe = &qp_ctx->zip_sqe;
+	struct acomp_req *a_req = req->req;
 	struct hisi_qp *qp = qp_ctx->qp;
 	struct device *dev = &qp->qm->pdev->dev;
-	struct hisi_acc_sgl_pool *pool = &qp_ctx->sgl_pool;
+	struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool;
 	dma_addr_t input;
 	dma_addr_t output;
 	int ret;
 
-	if (!req->src || !req->slen || !req->dst || !req->dlen)
+	if (!a_req->src || !a_req->slen || !a_req->dst || !a_req->dlen)
 		return -EINVAL;
 
-	req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, req->src, pool,
+	req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool,
 						    req->req_id << 1, &input);
 	if (IS_ERR(req->hw_src))
 		return PTR_ERR(req->hw_src);
 	req->dma_src = input;
 
-	req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, req->dst, pool,
+	req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool,
 						    (req->req_id << 1) + 1,
 						    &output);
 	if (IS_ERR(req->hw_dst)) {
@@ -535,8 +515,8 @@
 	}
 	req->dma_dst = output;
 
-	hisi_zip_fill_sqe(zip_sqe, qp->req_type, input, output, req->slen,
-			  req->dlen);
+	hisi_zip_fill_sqe(zip_sqe, qp->req_type, input, output, a_req->slen,
+			  a_req->dlen, req->sskip, req->dskip);
 	hisi_zip_config_buf_type(zip_sqe, HZIP_SGL);
 	hisi_zip_config_tag(zip_sqe, req->req_id);
 
@@ -548,9 +528,9 @@
 	return -EINPROGRESS;
 
 err_unmap_output:
-	hisi_acc_sg_buf_unmap(dev, req->dst, req->hw_dst);
+	hisi_acc_sg_buf_unmap(dev, a_req->dst, req->hw_dst);
 err_unmap_input:
-	hisi_acc_sg_buf_unmap(dev, req->src, req->hw_src);
+	hisi_acc_sg_buf_unmap(dev, a_req->src, req->hw_src);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/crypto/hisilicon/zip/zip_main.c
+++ linux-ein-5.4.0/drivers/crypto/hisilicon/zip/zip_main.c
@@ -60,13 +60,13 @@
 #define HZIP_CORE_DEBUG_DECOMP_5	0x309000
 
 #define HZIP_CORE_INT_SOURCE		0x3010A0
-#define HZIP_CORE_INT_MASK		0x3010A4
+#define HZIP_CORE_INT_MASK_REG		0x3010A4
 #define HZIP_CORE_INT_STATUS		0x3010AC
 #define HZIP_CORE_INT_STATUS_M_ECC	BIT(1)
 #define HZIP_CORE_SRAM_ECC_ERR_INFO	0x301148
 #define SRAM_ECC_ERR_NUM_SHIFT		16
 #define SRAM_ECC_ERR_ADDR_SHIFT		24
-#define HZIP_CORE_INT_DISABLE		0x000007FF
+#define HZIP_CORE_INT_MASK_ALL		GENMASK(10, 0)
 #define HZIP_COMP_CORE_NUM		2
 #define HZIP_DECOMP_CORE_NUM		6
 #define HZIP_CORE_NUM			(HZIP_COMP_CORE_NUM + \
@@ -79,47 +79,80 @@
 #define HZIP_SOFT_CTRL_CNT_CLR_CE	0x301000
 #define SOFT_CTRL_CNT_CLR_CE_BIT	BIT(0)
 
-#define HZIP_NUMA_DISTANCE		100
 #define HZIP_BUF_SIZE			22
 
 static const char hisi_zip_name[] = "hisi_zip";
 static struct dentry *hzip_debugfs_root;
-LIST_HEAD(hisi_zip_list);
-DEFINE_MUTEX(hisi_zip_list_lock);
+static LIST_HEAD(hisi_zip_list);
+static DEFINE_MUTEX(hisi_zip_list_lock);
 
-#ifdef CONFIG_NUMA
-static struct hisi_zip *find_zip_device_numa(int node)
+struct hisi_zip_resource {
+	struct hisi_zip *hzip;
+	int distance;
+	struct list_head list;
+};
+
+static void free_list(struct list_head *head)
 {
-	struct hisi_zip *zip = NULL;
-	struct hisi_zip *hisi_zip;
-	int min_distance = HZIP_NUMA_DISTANCE;
-	struct device *dev;
+	struct hisi_zip_resource *res, *tmp;
 
-	list_for_each_entry(hisi_zip, &hisi_zip_list, list) {
-		dev = &hisi_zip->qm.pdev->dev;
-		if (node_distance(dev->numa_node, node) < min_distance) {
-			zip = hisi_zip;
-			min_distance = node_distance(dev->numa_node, node);
-		}
+	list_for_each_entry_safe(res, tmp, head, list) {
+		list_del(&res->list);
+		kfree(res);
 	}
-
-	return zip;
 }
-#endif
 
 struct hisi_zip *find_zip_device(int node)
 {
-	struct hisi_zip *zip = NULL;
+	struct hisi_zip_resource *res, *tmp;
+	struct hisi_zip *ret = NULL;
+	struct hisi_zip *hisi_zip;
+	struct list_head *n;
+	struct device *dev;
+	LIST_HEAD(head);
 
 	mutex_lock(&hisi_zip_list_lock);
-#ifdef CONFIG_NUMA
-	zip = find_zip_device_numa(node);
-#else
-	zip = list_first_entry(&hisi_zip_list, struct hisi_zip, list);
-#endif
+
+	if (IS_ENABLED(CONFIG_NUMA)) {
+		list_for_each_entry(hisi_zip, &hisi_zip_list, list) {
+			res = kzalloc(sizeof(*res), GFP_KERNEL);
+			if (!res)
+				goto err;
+
+			dev = &hisi_zip->qm.pdev->dev;
+			res->hzip = hisi_zip;
+			res->distance = node_distance(dev_to_node(dev), node);
+
+			n = &head;
+			list_for_each_entry(tmp, &head, list) {
+				if (res->distance < tmp->distance) {
+					n = &tmp->list;
+					break;
+				}
+			}
+			list_add_tail(&res->list, n);
+		}
+
+		list_for_each_entry(tmp, &head, list) {
+			if (hisi_qm_get_free_qp_num(&tmp->hzip->qm)) {
+				ret = tmp->hzip;
+				break;
+			}
+		}
+
+		free_list(&head);
+	} else {
+		ret = list_first_entry(&hisi_zip_list, struct hisi_zip, list);
+	}
+
 	mutex_unlock(&hisi_zip_list_lock);
 
-	return zip;
+	return ret;
+
+err:
+	free_list(&head);
+	mutex_unlock(&hisi_zip_list_lock);
+	return NULL;
 }
 
 struct hisi_zip_hw_error {
@@ -267,6 +300,10 @@
 static int uacce_mode;
 module_param(uacce_mode, int, 0);
 
+static u32 vfs_num;
+module_param(vfs_num, uint, 0444);
+MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63)");
+
 static const struct pci_device_id hisi_zip_dev_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ZIP_PF) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ZIP_VF) },
@@ -329,28 +366,26 @@
 	       FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL);
 }
 
-static void hisi_zip_hw_error_set_state(struct hisi_zip *hisi_zip, bool state)
+static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
 {
-	struct hisi_qm *qm = &hisi_zip->qm;
-
 	if (qm->ver == QM_HW_V1) {
-		writel(HZIP_CORE_INT_DISABLE, qm->io_base + HZIP_CORE_INT_MASK);
-		dev_info(&qm->pdev->dev, "ZIP v%d does not support hw error handle\n",
-			 qm->ver);
+		writel(HZIP_CORE_INT_MASK_ALL,
+		       qm->io_base + HZIP_CORE_INT_MASK_REG);
+		dev_info(&qm->pdev->dev, "Does not support hw error handle\n");
 		return;
 	}
 
-	if (state) {
-		/* clear ZIP hw error source if having */
-		writel(HZIP_CORE_INT_DISABLE, hisi_zip->qm.io_base +
-					      HZIP_CORE_INT_SOURCE);
-		/* enable ZIP hw error interrupts */
-		writel(0, hisi_zip->qm.io_base + HZIP_CORE_INT_MASK);
-	} else {
-		/* disable ZIP hw error interrupts */
-		writel(HZIP_CORE_INT_DISABLE,
-		       hisi_zip->qm.io_base + HZIP_CORE_INT_MASK);
-	}
+	/* clear ZIP hw error source if having */
+	writel(HZIP_CORE_INT_MASK_ALL, qm->io_base + HZIP_CORE_INT_SOURCE);
+
+	/* enable ZIP hw error interrupts */
+	writel(0, qm->io_base + HZIP_CORE_INT_MASK_REG);
+}
+
+static void hisi_zip_hw_error_disable(struct hisi_qm *qm)
+{
+	/* disable ZIP hw error interrupts */
+	writel(HZIP_CORE_INT_MASK_ALL, qm->io_base + HZIP_CORE_INT_MASK_REG);
 }
 
 static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file)
@@ -511,7 +546,7 @@
 	struct hisi_qm *qm = &hisi_zip->qm;
 	struct device *dev = &qm->pdev->dev;
 	struct debugfs_regset32 *regset;
-	struct dentry *tmp_d, *tmp;
+	struct dentry *tmp_d;
 	char buf[HZIP_BUF_SIZE];
 	int i;
 
@@ -521,10 +556,6 @@
 		else
 			sprintf(buf, "decomp_core%d", i - HZIP_COMP_CORE_NUM);
 
-		tmp_d = debugfs_create_dir(buf, ctrl->debug_root);
-		if (!tmp_d)
-			return -ENOENT;
-
 		regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
 		if (!regset)
 			return -ENOENT;
@@ -533,9 +564,8 @@
 		regset->nregs = ARRAY_SIZE(hzip_dfx_regs);
 		regset->base = qm->io_base + core_offsets[i];
 
-		tmp = debugfs_create_regset32("regs", 0444, tmp_d, regset);
-		if (!tmp)
-			return -ENOENT;
+		tmp_d = debugfs_create_dir(buf, ctrl->debug_root);
+		debugfs_create_regset32("regs", 0444, tmp_d, regset);
 	}
 
 	return 0;
@@ -543,7 +573,6 @@
 
 static int hisi_zip_ctrl_debug_init(struct hisi_zip_ctrl *ctrl)
 {
-	struct dentry *tmp;
 	int i;
 
 	for (i = HZIP_CURRENT_QM; i < HZIP_DEBUG_FILE_NUM; i++) {
@@ -551,11 +580,9 @@
 		ctrl->files[i].ctrl = ctrl;
 		ctrl->files[i].index = i;
 
-		tmp = debugfs_create_file(ctrl_debug_file_name[i], 0600,
-					  ctrl->debug_root, ctrl->files + i,
-					  &ctrl_debug_fops);
-		if (!tmp)
-			return -ENOENT;
+		debugfs_create_file(ctrl_debug_file_name[i], 0600,
+				    ctrl->debug_root, ctrl->files + i,
+				    &ctrl_debug_fops);
 	}
 
 	return hisi_zip_core_debug_init(ctrl);
@@ -569,8 +596,6 @@
 	int ret;
 
 	dev_d = debugfs_create_dir(dev_name(dev), hzip_debugfs_root);
-	if (!dev_d)
-		return -ENOENT;
 
 	qm->debug.debug_root = dev_d;
 	ret = hisi_qm_debug_init(qm);
@@ -612,13 +637,16 @@
 		hisi_zip_debug_regs_clear(hisi_zip);
 }
 
-static void hisi_zip_hw_error_init(struct hisi_zip *hisi_zip)
-{
-	hisi_qm_hw_error_init(&hisi_zip->qm, QM_BASE_CE,
-			      QM_BASE_NFE | QM_ACC_WB_NOT_READY_TIMEOUT, 0,
-			      QM_DB_RANDOM_INVALID);
-	hisi_zip_hw_error_set_state(hisi_zip, true);
-}
+static const struct hisi_qm_err_ini hisi_zip_err_ini = {
+	.hw_err_enable	= hisi_zip_hw_error_enable,
+	.hw_err_disable	= hisi_zip_hw_error_disable,
+	.err_info	= {
+		.ce		= QM_BASE_CE,
+		.nfe		= QM_BASE_NFE | QM_ACC_WB_NOT_READY_TIMEOUT,
+		.fe		= 0,
+		.msi		= QM_DB_RANDOM_INVALID,
+	}
+};
 
 static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
 {
@@ -645,97 +673,15 @@
 		return -EINVAL;
 	}
 
+	qm->err_ini = &hisi_zip_err_ini;
+
 	hisi_zip_set_user_domain_and_cache(hisi_zip);
-	hisi_zip_hw_error_init(hisi_zip);
+	hisi_qm_dev_err_init(qm);
 	hisi_zip_debug_regs_clear(hisi_zip);
 
 	return 0;
 }
 
-static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct hisi_zip *hisi_zip;
-	enum qm_hw_ver rev_id;
-	struct hisi_qm *qm;
-	int ret;
-
-	rev_id = hisi_qm_get_hw_version(pdev);
-	if (rev_id == QM_HW_UNKNOWN)
-		return -EINVAL;
-
-	hisi_zip = devm_kzalloc(&pdev->dev, sizeof(*hisi_zip), GFP_KERNEL);
-	if (!hisi_zip)
-		return -ENOMEM;
-	pci_set_drvdata(pdev, hisi_zip);
-
-	qm = &hisi_zip->qm;
-	qm->pdev = pdev;
-	qm->ver = rev_id;
-
-	qm->sqe_size = HZIP_SQE_SIZE;
-	qm->dev_name = hisi_zip_name;
-	qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? QM_HW_PF :
-								QM_HW_VF;
-	switch (uacce_mode) {
-	case 0:
-		qm->use_dma_api = true;
-		break;
-	case 1:
-		qm->use_dma_api = false;
-		break;
-	case 2:
-		qm->use_dma_api = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = hisi_qm_init(qm);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to init qm!\n");
-		return ret;
-	}
-
-	if (qm->fun_type == QM_HW_PF) {
-		ret = hisi_zip_pf_probe_init(hisi_zip);
-		if (ret)
-			return ret;
-
-		qm->qp_base = HZIP_PF_DEF_Q_BASE;
-		qm->qp_num = pf_q_num;
-	} else if (qm->fun_type == QM_HW_VF) {
-		/*
-		 * have no way to get qm configure in VM in v1 hardware,
-		 * so currently force PF to uses HZIP_PF_DEF_Q_NUM, and force
-		 * to trigger only one VF in v1 hardware.
-		 *
-		 * v2 hardware has no such problem.
-		 */
-		if (qm->ver == QM_HW_V1) {
-			qm->qp_base = HZIP_PF_DEF_Q_NUM;
-			qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM;
-		} else if (qm->ver == QM_HW_V2)
-			/* v2 starts to support get vft by mailbox */
-			hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
-	}
-
-	ret = hisi_qm_start(qm);
-	if (ret)
-		goto err_qm_uninit;
-
-	ret = hisi_zip_debugfs_init(hisi_zip);
-	if (ret)
-		dev_err(&pdev->dev, "Failed to init debugfs (%d)!\n", ret);
-
-	hisi_zip_add_to_list(hisi_zip);
-
-	return 0;
-
-err_qm_uninit:
-	hisi_qm_uninit(qm);
-	return ret;
-}
-
 /* Currently we only support equal assignment */
 static int hisi_zip_vf_q_assign(struct hisi_zip *hisi_zip, int num_vfs)
 {
@@ -832,6 +778,100 @@
 	return hisi_zip_clear_vft_config(hisi_zip);
 }
 
+static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct hisi_zip *hisi_zip;
+	enum qm_hw_ver rev_id;
+	struct hisi_qm *qm;
+	int ret;
+
+	rev_id = hisi_qm_get_hw_version(pdev);
+	if (rev_id == QM_HW_UNKNOWN)
+		return -EINVAL;
+
+	hisi_zip = devm_kzalloc(&pdev->dev, sizeof(*hisi_zip), GFP_KERNEL);
+	if (!hisi_zip)
+		return -ENOMEM;
+	pci_set_drvdata(pdev, hisi_zip);
+
+	qm = &hisi_zip->qm;
+	qm->pdev = pdev;
+	qm->ver = rev_id;
+
+	qm->sqe_size = HZIP_SQE_SIZE;
+	qm->dev_name = hisi_zip_name;
+	qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? QM_HW_PF :
+								QM_HW_VF;
+	switch (uacce_mode) {
+	case 0:
+		qm->use_dma_api = true;
+		break;
+	case 1:
+		qm->use_dma_api = false;
+		break;
+	case 2:
+		qm->use_dma_api = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = hisi_qm_init(qm);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to init qm!\n");
+		return ret;
+	}
+
+	if (qm->fun_type == QM_HW_PF) {
+		ret = hisi_zip_pf_probe_init(hisi_zip);
+		if (ret)
+			return ret;
+
+		qm->qp_base = HZIP_PF_DEF_Q_BASE;
+		qm->qp_num = pf_q_num;
+	} else if (qm->fun_type == QM_HW_VF) {
+		/*
+		 * have no way to get qm configure in VM in v1 hardware,
+		 * so currently force PF to uses HZIP_PF_DEF_Q_NUM, and force
+		 * to trigger only one VF in v1 hardware.
+		 *
+		 * v2 hardware has no such problem.
+		 */
+		if (qm->ver == QM_HW_V1) {
+			qm->qp_base = HZIP_PF_DEF_Q_NUM;
+			qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM;
+		} else if (qm->ver == QM_HW_V2)
+			/* v2 starts to support get vft by mailbox */
+			hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
+	}
+
+	ret = hisi_qm_start(qm);
+	if (ret)
+		goto err_qm_uninit;
+
+	ret = hisi_zip_debugfs_init(hisi_zip);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to init debugfs (%d)!\n", ret);
+
+	hisi_zip_add_to_list(hisi_zip);
+
+	if (qm->fun_type == QM_HW_PF && vfs_num > 0) {
+		ret = hisi_zip_sriov_enable(pdev, vfs_num);
+		if (ret < 0)
+			goto err_remove_from_list;
+	}
+
+	return 0;
+
+err_remove_from_list:
+	hisi_zip_remove_from_list(hisi_zip);
+	hisi_zip_debugfs_exit(hisi_zip);
+	hisi_qm_stop(qm);
+err_qm_uninit:
+	hisi_qm_uninit(qm);
+	return ret;
+}
+
 static int hisi_zip_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
 	if (num_vfs == 0)
@@ -851,9 +891,7 @@
 	hisi_zip_debugfs_exit(hisi_zip);
 	hisi_qm_stop(qm);
 
-	if (qm->fun_type == QM_HW_PF)
-		hisi_zip_hw_error_set_state(hisi_zip, false);
-
+	hisi_qm_dev_err_uninit(qm);
 	hisi_qm_uninit(qm);
 	hisi_zip_remove_from_list(hisi_zip);
 }
@@ -945,7 +983,7 @@
 	.probe			= hisi_zip_probe,
 	.remove			= hisi_zip_remove,
 	.sriov_configure	= IS_ENABLED(CONFIG_PCI_IOV) ?
-					hisi_zip_sriov_configure : 0,
+					hisi_zip_sriov_configure : NULL,
 	.err_handler		= &hisi_zip_err_handler,
 };
 
@@ -955,8 +993,6 @@
 		return;
 
 	hzip_debugfs_root = debugfs_create_dir("hisi_zip", NULL);
-	if (IS_ERR_OR_NULL(hzip_debugfs_root))
-		hzip_debugfs_root = NULL;
 }
 
 static void hisi_zip_unregister_debugfs(void)
--- linux-ein-5.4.0.orig/drivers/crypto/img-hash.c
+++ linux-ein-5.4.0/drivers/crypto/img-hash.c
@@ -356,12 +356,16 @@
 static void img_hash_dma_task(unsigned long d)
 {
 	struct img_hash_dev *hdev = (struct img_hash_dev *)d;
-	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
+	struct img_hash_request_ctx *ctx;
 	u8 *addr;
 	size_t nbytes, bleft, wsend, len, tbc;
 	struct scatterlist tsg;
 
-	if (!hdev->req || !ctx->sg)
+	if (!hdev->req)
+		return;
+
+	ctx = ahash_request_ctx(hdev->req);
+	if (!ctx->sg)
 		return;
 
 	addr = sg_virt(ctx->sg);
--- linux-ein-5.4.0.orig/drivers/crypto/inside-secure/safexcel.c
+++ linux-ein-5.4.0/drivers/crypto/inside-secure/safexcel.c
@@ -221,9 +221,9 @@
 	/* Step #3: Determine log2 of hash table size */
 	cs_ht_sz = __fls(asize - cs_rc_max) - 2;
 	/* Step #4: determine current size of hash table in dwords */
-	cs_ht_wc = 16<<cs_ht_sz; /* dwords, not admin words */
+	cs_ht_wc = 16 << cs_ht_sz; /* dwords, not admin words */
 	/* Step #5: add back excess words and see if we can fit more records */
-	cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 4));
+	cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 2));
 
 	/* Clear the cache RAMs */
 	eip197_trc_cache_clear(priv, cs_rc_max, cs_ht_wc);
@@ -1090,11 +1090,12 @@
 
 static int safexcel_request_ring_irq(void *pdev, int irqid,
 				     int is_pci_dev,
+				     int ring_id,
 				     irq_handler_t handler,
 				     irq_handler_t threaded_handler,
 				     struct safexcel_ring_irq_data *ring_irq_priv)
 {
-	int ret, irq;
+	int ret, irq, cpu;
 	struct device *dev;
 
 	if (IS_ENABLED(CONFIG_PCI) && is_pci_dev) {
@@ -1120,6 +1121,8 @@
 				irq_name, irq);
 			return irq;
 		}
+	} else {
+		return -ENXIO;
 	}
 
 	ret = devm_request_threaded_irq(dev, irq, handler,
@@ -1130,6 +1133,10 @@
 		return ret;
 	}
 
+	/* Set affinity */
+	cpu = cpumask_local_spread(ring_id, NUMA_NO_NODE);
+	irq_set_affinity_hint(irq, get_cpu_mask(cpu));
+
 	return irq;
 }
 
@@ -1460,19 +1467,23 @@
 						     &priv->ring[i].rdr);
 		if (ret) {
 			dev_err(dev, "Failed to initialize rings\n");
-			return ret;
+			goto err_cleanup_rings;
 		}
 
 		priv->ring[i].rdr_req = devm_kcalloc(dev,
 			EIP197_DEFAULT_RING_SIZE,
-			sizeof(priv->ring[i].rdr_req),
+			sizeof(*priv->ring[i].rdr_req),
 			GFP_KERNEL);
-		if (!priv->ring[i].rdr_req)
-			return -ENOMEM;
+		if (!priv->ring[i].rdr_req) {
+			ret = -ENOMEM;
+			goto err_cleanup_rings;
+		}
 
 		ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL);
-		if (!ring_irq)
-			return -ENOMEM;
+		if (!ring_irq) {
+			ret = -ENOMEM;
+			goto err_cleanup_rings;
+		}
 
 		ring_irq->priv = priv;
 		ring_irq->ring = i;
@@ -1480,14 +1491,17 @@
 		irq = safexcel_request_ring_irq(pdev,
 						EIP197_IRQ_NUMBER(i, is_pci_dev),
 						is_pci_dev,
+						i,
 						safexcel_irq_ring,
 						safexcel_irq_ring_thread,
 						ring_irq);
 		if (irq < 0) {
 			dev_err(dev, "Failed to get IRQ ID for ring %d\n", i);
-			return irq;
+			ret = irq;
+			goto err_cleanup_rings;
 		}
 
+		priv->ring[i].irq = irq;
 		priv->ring[i].work_data.priv = priv;
 		priv->ring[i].work_data.ring = i;
 		INIT_WORK(&priv->ring[i].work_data.work,
@@ -1496,8 +1510,10 @@
 		snprintf(wq_name, 9, "wq_ring%d", i);
 		priv->ring[i].workqueue =
 			create_singlethread_workqueue(wq_name);
-		if (!priv->ring[i].workqueue)
-			return -ENOMEM;
+		if (!priv->ring[i].workqueue) {
+			ret = -ENOMEM;
+			goto err_cleanup_rings;
+		}
 
 		priv->ring[i].requests = 0;
 		priv->ring[i].busy = false;
@@ -1514,16 +1530,26 @@
 	ret = safexcel_hw_init(priv);
 	if (ret) {
 		dev_err(dev, "HW init failed (%d)\n", ret);
-		return ret;
+		goto err_cleanup_rings;
 	}
 
 	ret = safexcel_register_algorithms(priv);
 	if (ret) {
 		dev_err(dev, "Failed to register algorithms (%d)\n", ret);
-		return ret;
+		goto err_cleanup_rings;
 	}
 
 	return 0;
+
+err_cleanup_rings:
+	for (i = 0; i < priv->config.rings; i++) {
+		if (priv->ring[i].irq)
+			irq_set_affinity_hint(priv->ring[i].irq, NULL);
+		if (priv->ring[i].workqueue)
+			destroy_workqueue(priv->ring[i].workqueue);
+	}
+
+	return ret;
 }
 
 static void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv)
@@ -1625,8 +1651,10 @@
 
 	clk_disable_unprepare(priv->clk);
 
-	for (i = 0; i < priv->config.rings; i++)
+	for (i = 0; i < priv->config.rings; i++) {
+		irq_set_affinity_hint(priv->ring[i].irq, NULL);
 		destroy_workqueue(priv->ring[i].workqueue);
+	}
 
 	return 0;
 }
@@ -1656,6 +1684,8 @@
 	{},
 };
 
+MODULE_DEVICE_TABLE(of, safexcel_of_match_table);
+
 static struct platform_driver  crypto_safexcel = {
 	.probe		= safexcel_probe,
 	.remove		= safexcel_remove,
--- linux-ein-5.4.0.orig/drivers/crypto/inside-secure/safexcel.h
+++ linux-ein-5.4.0/drivers/crypto/inside-secure/safexcel.h
@@ -640,6 +640,9 @@
 	 */
 	struct crypto_async_request *req;
 	struct crypto_async_request *backlog;
+
+	/* irq of this ring */
+	int irq;
 };
 
 /* EIP integration context flags */
--- linux-ein-5.4.0.orig/drivers/crypto/ixp4xx_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/ixp4xx_crypto.c
@@ -329,7 +329,7 @@
 
 		buf1 = buf->next;
 		phys1 = buf->phys_next;
-		dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir);
+		dma_unmap_single(dev, buf->phys_addr, buf->buf_len, buf->dir);
 		dma_pool_free(buffer_pool, buf, phys);
 		buf = buf1;
 		phys = phys1;
@@ -527,7 +527,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);
 	}
 }
--- linux-ein-5.4.0.orig/drivers/crypto/marvell/cipher.c
+++ linux-ein-5.4.0/drivers/crypto/marvell/cipher.c
@@ -287,7 +287,7 @@
 static int mv_cesa_des3_ede_setkey(struct crypto_skcipher *cipher,
 				   const u8 *key, unsigned int len)
 {
-	struct mv_cesa_des_ctx *ctx = crypto_skcipher_ctx(cipher);
+	struct mv_cesa_des3_ctx *ctx = crypto_skcipher_ctx(cipher);
 	int err;
 
 	err = verify_skcipher_des3_key(cipher, key);
@@ -610,7 +610,6 @@
 	.decrypt = mv_cesa_ecb_des3_ede_decrypt,
 	.min_keysize = DES3_EDE_KEY_SIZE,
 	.max_keysize = DES3_EDE_KEY_SIZE,
-	.ivsize = DES3_EDE_BLOCK_SIZE,
 	.base = {
 		.cra_name = "ecb(des3_ede)",
 		.cra_driver_name = "mv-ecb-des3-ede",
--- linux-ein-5.4.0.orig/drivers/crypto/mediatek/mtk-platform.c
+++ linux-ein-5.4.0/drivers/crypto/mediatek/mtk-platform.c
@@ -442,7 +442,7 @@
 static int mtk_desc_ring_alloc(struct mtk_cryp *cryp)
 {
 	struct mtk_ring **ring = cryp->ring;
-	int i, err = ENOMEM;
+	int i;
 
 	for (i = 0; i < MTK_RING_MAX; i++) {
 		ring[i] = kzalloc(sizeof(**ring), GFP_KERNEL);
@@ -469,14 +469,14 @@
 	return 0;
 
 err_cleanup:
-	for (; i--; ) {
+	do {
 		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
 				  ring[i]->res_base, ring[i]->res_dma);
 		dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
 				  ring[i]->cmd_base, ring[i]->cmd_dma);
 		kfree(ring[i]);
-	}
-	return err;
+	} while (i--);
+	return -ENOMEM;
 }
 
 static int mtk_crypto_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/crypto/mxs-dcp.c
+++ linux-ein-5.4.0/drivers/crypto/mxs-dcp.c
@@ -20,6 +20,7 @@
 #include <crypto/sha.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
 
 #define DCP_MAX_CHANS	4
 #define DCP_BUF_SZ	PAGE_SIZE
@@ -167,15 +168,19 @@
 
 static int mxs_dcp_start_dma(struct dcp_async_ctx *actx)
 {
+	int dma_err;
 	struct dcp *sdcp = global_sdcp;
 	const int chan = actx->chan;
 	uint32_t stat;
 	unsigned long ret;
 	struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
-
 	dma_addr_t desc_phys = dma_map_single(sdcp->dev, desc, sizeof(*desc),
 					      DMA_TO_DEVICE);
 
+	dma_err = dma_mapping_error(sdcp->dev, desc_phys);
+	if (dma_err)
+		return dma_err;
+
 	reinit_completion(&sdcp->completion[chan]);
 
 	/* Clear status register. */
@@ -213,18 +218,29 @@
 static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
 			   struct ablkcipher_request *req, int init)
 {
+	dma_addr_t key_phys, src_phys, dst_phys;
 	struct dcp *sdcp = global_sdcp;
 	struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
 	struct dcp_aes_req_ctx *rctx = ablkcipher_request_ctx(req);
 	int ret;
 
-	dma_addr_t key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
-					     2 * AES_KEYSIZE_128,
-					     DMA_TO_DEVICE);
-	dma_addr_t src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf,
-					     DCP_BUF_SZ, DMA_TO_DEVICE);
-	dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
-					     DCP_BUF_SZ, DMA_FROM_DEVICE);
+	key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
+				  2 * AES_KEYSIZE_128, DMA_TO_DEVICE);
+	ret = dma_mapping_error(sdcp->dev, key_phys);
+	if (ret)
+		return ret;
+
+	src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf,
+				  DCP_BUF_SZ, DMA_TO_DEVICE);
+	ret = dma_mapping_error(sdcp->dev, src_phys);
+	if (ret)
+		goto err_src;
+
+	dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
+				  DCP_BUF_SZ, DMA_FROM_DEVICE);
+	ret = dma_mapping_error(sdcp->dev, dst_phys);
+	if (ret)
+		goto err_dst;
 
 	if (actx->fill % AES_BLOCK_SIZE) {
 		dev_err(sdcp->dev, "Invalid block size!\n");
@@ -262,10 +278,12 @@
 	ret = mxs_dcp_start_dma(actx);
 
 aes_done_run:
+	dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE);
+err_dst:
+	dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
+err_src:
 	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);
-	dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE);
 
 	return ret;
 }
@@ -280,21 +298,20 @@
 
 	struct scatterlist *dst = req->dst;
 	struct scatterlist *src = req->src;
-	const int nents = sg_nents(req->src);
+	int dst_nents = sg_nents(dst);
 
 	const int out_off = DCP_BUF_SZ;
 	uint8_t *in_buf = sdcp->coh->aes_in_buf;
 	uint8_t *out_buf = sdcp->coh->aes_out_buf;
 
-	uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
 	uint32_t dst_off = 0;
+	uint8_t *src_buf = NULL;
 	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, tlen = 0;
+	unsigned int i, len, clen, tlen = 0;
 	int init = 0;
 	bool limit_hit = false;
 
@@ -312,7 +329,7 @@
 		memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128);
 	}
 
-	for_each_sg(req->src, src, nents, i) {
+	for_each_sg(req->src, src, sg_nents(req->src), i) {
 		src_buf = sg_virt(src);
 		len = sg_dma_len(src);
 		tlen += len;
@@ -337,34 +354,17 @@
 			 * submit the buffer.
 			 */
 			if (actx->fill == out_off || sg_is_last(src) ||
-				limit_hit) {
+			    limit_hit) {
 				ret = mxs_dcp_run_aes(actx, req, init);
 				if (ret)
 					return ret;
 				init = 0;
 
-				out_tmp = out_buf;
+				sg_pcopy_from_buffer(dst, dst_nents, out_buf,
+						     actx->fill, dst_off);
+				dst_off += actx->fill;
 				last_out_len = actx->fill;
-				while (dst && actx->fill) {
-					if (!split) {
-						dst_buf = sg_virt(dst);
-						dst_off = 0;
-					}
-					rem = min(sg_dma_len(dst) - dst_off,
-						  actx->fill);
-
-					memcpy(dst_buf + dst_off, out_tmp, rem);
-					out_tmp += rem;
-					dst_off += rem;
-					actx->fill -= rem;
-
-					if (dst_off == sg_dma_len(dst)) {
-						dst = sg_next(dst);
-						split = 0;
-					} else {
-						split = 1;
-					}
-				}
+				actx->fill = 0;
 			}
 		} while (len);
 
@@ -564,6 +564,10 @@
 	dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf,
 					     DCP_BUF_SZ, DMA_TO_DEVICE);
 
+	ret = dma_mapping_error(sdcp->dev, buf_phys);
+	if (ret)
+		return ret;
+
 	/* Fill in the DMA descriptor. */
 	desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
 		    MXS_DCP_CONTROL0_INTERRUPT |
@@ -596,6 +600,10 @@
 	if (rctx->fini) {
 		digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf,
 					     DCP_SHA_PAY_SZ, DMA_FROM_DEVICE);
+		ret = dma_mapping_error(sdcp->dev, digest_phys);
+		if (ret)
+			goto done_run;
+
 		desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
 		desc->payload = digest_phys;
 	}
@@ -621,49 +629,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 *out_buf = sdcp->coh->sha_out_buf;
 
-	uint8_t *src_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;
+	while (len) {
+		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;
+		scatterwalk_map_and_copy(in_buf + actx->fill, src, oft, clen,
+					 0);
 
-			/*
-			 * 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);
+		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) {
--- linux-ein-5.4.0.orig/drivers/crypto/n2_core.c
+++ linux-ein-5.4.0/drivers/crypto/n2_core.c
@@ -1278,6 +1278,7 @@
 	const u32	*hash_init;
 	u8		hw_op_hashsz;
 	u8		digest_size;
+	u8		statesize;
 	u8		block_size;
 	u8		auth_type;
 	u8		hmac_type;
@@ -1309,6 +1310,7 @@
 	  .hmac_type	= AUTH_TYPE_HMAC_MD5,
 	  .hw_op_hashsz	= MD5_DIGEST_SIZE,
 	  .digest_size	= MD5_DIGEST_SIZE,
+	  .statesize	= sizeof(struct md5_state),
 	  .block_size	= MD5_HMAC_BLOCK_SIZE },
 	{ .name		= "sha1",
 	  .hash_zero	= sha1_zero_message_hash,
@@ -1317,6 +1319,7 @@
 	  .hmac_type	= AUTH_TYPE_HMAC_SHA1,
 	  .hw_op_hashsz	= SHA1_DIGEST_SIZE,
 	  .digest_size	= SHA1_DIGEST_SIZE,
+	  .statesize	= sizeof(struct sha1_state),
 	  .block_size	= SHA1_BLOCK_SIZE },
 	{ .name		= "sha256",
 	  .hash_zero	= sha256_zero_message_hash,
@@ -1325,6 +1328,7 @@
 	  .hmac_type	= AUTH_TYPE_HMAC_SHA256,
 	  .hw_op_hashsz	= SHA256_DIGEST_SIZE,
 	  .digest_size	= SHA256_DIGEST_SIZE,
+	  .statesize	= sizeof(struct sha256_state),
 	  .block_size	= SHA256_BLOCK_SIZE },
 	{ .name		= "sha224",
 	  .hash_zero	= sha224_zero_message_hash,
@@ -1333,6 +1337,7 @@
 	  .hmac_type	= AUTH_TYPE_RESERVED,
 	  .hw_op_hashsz	= SHA256_DIGEST_SIZE,
 	  .digest_size	= SHA224_DIGEST_SIZE,
+	  .statesize	= sizeof(struct sha256_state),
 	  .block_size	= SHA224_BLOCK_SIZE },
 };
 #define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls)
@@ -1474,6 +1479,7 @@
 
 	halg = &ahash->halg;
 	halg->digestsize = tmpl->digest_size;
+	halg->statesize = tmpl->statesize;
 
 	base = &halg->base;
 	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
--- linux-ein-5.4.0.orig/drivers/crypto/nx/Makefile
+++ linux-ein-5.4.0/drivers/crypto/nx/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_CRYPTO_DEV_NX_ENCRYPT) += nx-crypto.o
 nx-crypto-objs := nx.o \
-		  nx_debugfs.o \
 		  nx-aes-cbc.o \
 		  nx-aes-ecb.o \
 		  nx-aes-gcm.o \
@@ -11,6 +10,7 @@
 		  nx-sha256.o \
 		  nx-sha512.o
 
+nx-crypto-$(CONFIG_DEBUG_FS) += nx_debugfs.o
 obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o nx-compress.o
 obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o nx-compress.o
 nx-compress-objs := nx-842.o
--- linux-ein-5.4.0.orig/drivers/crypto/nx/nx-842-pseries.c
+++ linux-ein-5.4.0/drivers/crypto/nx/nx-842-pseries.c
@@ -538,13 +538,15 @@
  * The status field indicates if the device is enabled when the status
  * is 'okay'.  Otherwise the device driver will be disabled.
  *
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to use for dev_info
+ * @prop: struct property point containing the maxsyncop for the update
  *
  * Returns:
  *  0 - Device is available
  *  -ENODEV - Device is not available
  */
-static int nx842_OF_upd_status(struct property *prop)
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+			       struct property *prop)
 {
 	const char *status = (const char *)prop->value;
 
@@ -758,7 +760,7 @@
 		goto out;
 
 	/* Perform property updates */
-	ret = nx842_OF_upd_status(status);
+	ret = nx842_OF_upd_status(new_devdata, status);
 	if (ret)
 		goto error_out;
 
@@ -1071,6 +1073,7 @@
 	{"ibm,compression-v1", "ibm,compression"},
 	{"", ""},
 };
+MODULE_DEVICE_TABLE(vio, nx842_vio_driver_ids);
 
 static struct vio_driver nx842_vio_driver = {
 	.name = KBUILD_MODNAME,
--- linux-ein-5.4.0.orig/drivers/crypto/nx/nx.h
+++ linux-ein-5.4.0/drivers/crypto/nx/nx.h
@@ -169,8 +169,8 @@
 void nx_debugfs_init(struct nx_crypto_driver *);
 void nx_debugfs_fini(struct nx_crypto_driver *);
 #else
-#define NX_DEBUGFS_INIT(drv)	(0)
-#define NX_DEBUGFS_FINI(drv)	(0)
+#define NX_DEBUGFS_INIT(drv)	do {} while (0)
+#define NX_DEBUGFS_FINI(drv)	do {} while (0)
 #endif
 
 #define NX_PAGE_NUM(x)		((u64)(x) & 0xfffffffffffff000ULL)
--- linux-ein-5.4.0.orig/drivers/crypto/omap-aes.c
+++ linux-ein-5.4.0/drivers/crypto/omap-aes.c
@@ -103,7 +103,7 @@
 		dd->err = 0;
 	}
 
-	err = pm_runtime_get_sync(dd->dev);
+	err = pm_runtime_resume_and_get(dd->dev);
 	if (err < 0) {
 		dev_err(dd->dev, "failed to get sync: %d\n", err);
 		return err;
@@ -1153,11 +1153,11 @@
 	pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
 
 	pm_runtime_enable(dev);
-	err = pm_runtime_get_sync(dev);
+	err = pm_runtime_resume_and_get(dev);
 	if (err < 0) {
 		dev_err(dev, "%s: failed to get_sync(%d)\n",
 			__func__, err);
-		goto err_res;
+		goto err_pm_disable;
 	}
 
 	omap_aes_dma_stop(dd);
@@ -1267,6 +1267,7 @@
 	omap_aes_dma_cleanup(dd);
 err_irq:
 	tasklet_kill(&dd->done_task);
+err_pm_disable:
 	pm_runtime_disable(dev);
 err_res:
 	dd = NULL;
--- linux-ein-5.4.0.orig/drivers/crypto/omap-sham.c
+++ linux-ein-5.4.0/drivers/crypto/omap-sham.c
@@ -165,8 +165,6 @@
 };
 
 struct omap_sham_ctx {
-	struct omap_sham_dev	*dd;
-
 	unsigned long		flags;
 
 	/* fallback stuff */
@@ -366,7 +364,7 @@
 {
 	int err;
 
-	err = pm_runtime_get_sync(dd->dev);
+	err = pm_runtime_resume_and_get(dd->dev);
 	if (err < 0) {
 		dev_err(dd->dev, "failed to get sync: %d\n", err);
 		return err;
@@ -455,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
@@ -918,27 +919,35 @@
 	return 0;
 }
 
+struct omap_sham_dev *omap_sham_find_dev(struct omap_sham_reqctx *ctx)
+{
+	struct omap_sham_dev *dd;
+
+	if (ctx->dd)
+		return ctx->dd;
+
+	spin_lock_bh(&sham.lock);
+	dd = list_first_entry(&sham.dev_list, struct omap_sham_dev, list);
+	list_move_tail(&dd->list, &sham.dev_list);
+	ctx->dd = dd;
+	spin_unlock_bh(&sham.lock);
+
+	return dd;
+}
+
 static int omap_sham_init(struct ahash_request *req)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
 	struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
 	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
-	struct omap_sham_dev *dd = NULL, *tmp;
+	struct omap_sham_dev *dd;
 	int bs = 0;
 
-	spin_lock_bh(&sham.lock);
-	if (!tctx->dd) {
-		list_for_each_entry(tmp, &sham.dev_list, list) {
-			dd = tmp;
-			break;
-		}
-		tctx->dd = dd;
-	} else {
-		dd = tctx->dd;
-	}
-	spin_unlock_bh(&sham.lock);
+	ctx->dd = NULL;
 
-	ctx->dd = dd;
+	dd = omap_sham_find_dev(ctx);
+	if (!dd)
+		return -ENODEV;
 
 	ctx->flags = 0;
 
@@ -1187,8 +1196,7 @@
 static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
 {
 	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
-	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
-	struct omap_sham_dev *dd = tctx->dd;
+	struct omap_sham_dev *dd = ctx->dd;
 
 	ctx->op = op;
 
@@ -1198,7 +1206,7 @@
 static int omap_sham_update(struct ahash_request *req)
 {
 	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
-	struct omap_sham_dev *dd = ctx->dd;
+	struct omap_sham_dev *dd = omap_sham_find_dev(ctx);
 
 	if (!req->nbytes)
 		return 0;
@@ -1302,21 +1310,8 @@
 	struct omap_sham_hmac_ctx *bctx = tctx->base;
 	int bs = crypto_shash_blocksize(bctx->shash);
 	int ds = crypto_shash_digestsize(bctx->shash);
-	struct omap_sham_dev *dd = NULL, *tmp;
 	int err, i;
 
-	spin_lock_bh(&sham.lock);
-	if (!tctx->dd) {
-		list_for_each_entry(tmp, &sham.dev_list, list) {
-			dd = tmp;
-			break;
-		}
-		tctx->dd = dd;
-	} else {
-		dd = tctx->dd;
-	}
-	spin_unlock_bh(&sham.lock);
-
 	err = crypto_shash_setkey(tctx->fallback, key, keylen);
 	if (err)
 		return err;
@@ -1334,7 +1329,7 @@
 
 	memset(bctx->ipad + keylen, 0, bs - keylen);
 
-	if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
+	if (!test_bit(FLAGS_AUTO_XOR, &sham.flags)) {
 		memcpy(bctx->opad, bctx->ipad, bs);
 
 		for (i = 0; i < bs; i++) {
@@ -1739,7 +1734,7 @@
 		if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
 			goto finish;
 	} else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
-		if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
+		if (test_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
 			omap_sham_update_dma_stop(dd);
 			if (dd->err) {
 				err = dd->err;
@@ -2136,6 +2131,7 @@
 	}
 
 	dd->flags |= dd->pdata->flags;
+	sham.flags |= dd->pdata->flags;
 
 	pm_runtime_use_autosuspend(dev);
 	pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
@@ -2145,7 +2141,7 @@
 	pm_runtime_enable(dev);
 	pm_runtime_irq_safe(dev);
 
-	err = pm_runtime_get_sync(dev);
+	err = pm_runtime_resume_and_get(dev);
 	if (err < 0) {
 		dev_err(dev, "failed to get sync: %d\n", err);
 		goto err_pm;
@@ -2163,6 +2159,9 @@
 	spin_unlock(&sham.lock);
 
 	for (i = 0; i < dd->pdata->algs_info_size; i++) {
+		if (dd->pdata->algs_info[i].registered)
+			break;
+
 		for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
 			struct ahash_alg *alg;
 
@@ -2214,9 +2213,11 @@
 	list_del(&dd->list);
 	spin_unlock(&sham.lock);
 	for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
-		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) {
 			crypto_unregister_ahash(
 					&dd->pdata->algs_info[i].algs_list[j]);
+			dd->pdata->algs_info[i].registered--;
+		}
 	tasklet_kill(&dd->done_task);
 	pm_runtime_disable(&pdev->dev);
 
@@ -2235,7 +2236,7 @@
 
 static int omap_sham_resume(struct device *dev)
 {
-	int err = pm_runtime_get_sync(dev);
+	int err = pm_runtime_resume_and_get(dev);
 	if (err < 0) {
 		dev_err(dev, "failed to get sync: %d\n", err);
 		return err;
--- linux-ein-5.4.0.orig/drivers/crypto/picoxcell_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/picoxcell_crypto.c
@@ -1613,6 +1613,11 @@
 MODULE_DEVICE_TABLE(of, spacc_of_id_table);
 #endif /* CONFIG_OF */
 
+static void spacc_tasklet_kill(void *data)
+{
+	tasklet_kill(data);
+}
+
 static int spacc_probe(struct platform_device *pdev)
 {
 	int i, err, ret;
@@ -1655,6 +1660,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");
@@ -1684,11 +1697,6 @@
 		goto err_clk_put;
 	}
 
-	ret = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh);
-	if (ret)
-		goto err_clk_disable;
-
-
 	/*
 	 * Use an IRQ threshold of 50% as a default. This seems to be a
 	 * reasonable trade off of latency against throughput but can be
@@ -1696,6 +1704,10 @@
 	 */
 	engine->stat_irq_thresh = (engine->fifo_sz / 2);
 
+	ret = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh);
+	if (ret)
+		goto err_clk_disable;
+
 	/*
 	 * Configure the interrupts. We only use the STAT_CNT interrupt as we
 	 * only submit a new packet for processing when we complete another in
@@ -1712,8 +1724,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-ein-5.4.0.orig/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c
@@ -123,10 +123,10 @@
 	hw_data->enable_error_correction = adf_vf_void_noop;
 	hw_data->init_admin_comms = adf_vf_int_noop;
 	hw_data->exit_admin_comms = adf_vf_void_noop;
-	hw_data->send_admin_init = adf_vf2pf_init;
+	hw_data->send_admin_init = adf_vf2pf_notify_init;
 	hw_data->init_arb = adf_vf_int_noop;
 	hw_data->exit_arb = adf_vf_void_noop;
-	hw_data->disable_iov = adf_vf2pf_shutdown;
+	hw_data->disable_iov = adf_vf2pf_notify_shutdown;
 	hw_data->get_accel_mask = get_accel_mask;
 	hw_data->get_ae_mask = get_ae_mask;
 	hw_data->get_num_accels = get_num_accels;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
@@ -233,12 +233,12 @@
 	if (ret)
 		goto out_err_free_reg;
 
-	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
-
 	ret = adf_dev_init(accel_dev);
 	if (ret)
 		goto out_err_dev_shutdown;
 
+	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
 	ret = adf_dev_start(accel_dev);
 	if (ret)
 		goto out_err_dev_stop;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c
@@ -123,10 +123,10 @@
 	hw_data->enable_error_correction = adf_vf_void_noop;
 	hw_data->init_admin_comms = adf_vf_int_noop;
 	hw_data->exit_admin_comms = adf_vf_void_noop;
-	hw_data->send_admin_init = adf_vf2pf_init;
+	hw_data->send_admin_init = adf_vf2pf_notify_init;
 	hw_data->init_arb = adf_vf_int_noop;
 	hw_data->exit_arb = adf_vf_void_noop;
-	hw_data->disable_iov = adf_vf2pf_shutdown;
+	hw_data->disable_iov = adf_vf2pf_notify_shutdown;
 	hw_data->get_accel_mask = get_accel_mask;
 	hw_data->get_ae_mask = get_ae_mask;
 	hw_data->get_num_accels = get_num_accels;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_c62xvf/adf_drv.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_c62xvf/adf_drv.c
@@ -233,12 +233,12 @@
 	if (ret)
 		goto out_err_free_reg;
 
-	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
-
 	ret = adf_dev_init(accel_dev);
 	if (ret)
 		goto out_err_dev_shutdown;
 
+	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
 	ret = adf_dev_start(accel_dev);
 	if (ret)
 		goto out_err_dev_stop;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -239,8 +239,8 @@
 void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
 void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
 
-int adf_vf2pf_init(struct adf_accel_dev *accel_dev);
-void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev);
+int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev);
+void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev);
 int adf_init_pf_wq(void);
 void adf_exit_pf_wq(void);
 int adf_init_vf_wq(void);
@@ -263,12 +263,12 @@
 {
 }
 
-static inline int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
+static inline int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev)
 {
 	return 0;
 }
 
-static inline void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
+static inline void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev)
 {
 }
 
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_init.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_init.c
@@ -105,6 +105,7 @@
 	struct service_hndl *service;
 	struct list_head *list_itr;
 	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+	int ret;
 
 	if (!hw_data) {
 		dev_err(&GET_DEV(accel_dev),
@@ -171,9 +172,9 @@
 	}
 
 	hw_data->enable_error_correction(accel_dev);
-	hw_data->enable_vf2pf_comms(accel_dev);
+	ret = hw_data->enable_vf2pf_comms(accel_dev);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(adf_dev_init);
 
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_isr.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_isr.c
@@ -59,6 +59,8 @@
 #include "adf_transport_access_macros.h"
 #include "adf_transport_internal.h"
 
+#define ADF_MAX_NUM_VFS	32
+
 static int adf_enable_msix(struct adf_accel_dev *accel_dev)
 {
 	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
@@ -111,7 +113,7 @@
 		struct adf_bar *pmisc =
 			&GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
 		void __iomem *pmisc_bar_addr = pmisc->virt_addr;
-		u32 vf_mask;
+		unsigned long vf_mask;
 
 		/* Get the interrupt sources triggered by VFs */
 		vf_mask = ((ADF_CSR_RD(pmisc_bar_addr, ADF_ERRSOU5) &
@@ -132,8 +134,7 @@
 			 * unless the VF is malicious and is attempting to
 			 * flood the host OS with VF2PF interrupts.
 			 */
-			for_each_set_bit(i, (const unsigned long *)&vf_mask,
-					 (sizeof(vf_mask) * BITS_PER_BYTE)) {
+			for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) {
 				vf_info = accel_dev->pf.vf_info + i;
 
 				if (!__ratelimit(&vf_info->vf2pf_ratelimit)) {
@@ -330,19 +331,32 @@
 
 	ret = adf_isr_alloc_msix_entry_table(accel_dev);
 	if (ret)
-		return ret;
-	if (adf_enable_msix(accel_dev))
 		goto err_out;
 
-	if (adf_setup_bh(accel_dev))
-		goto err_out;
+	ret = adf_enable_msix(accel_dev);
+	if (ret)
+		goto err_free_msix_table;
 
-	if (adf_request_irqs(accel_dev))
-		goto err_out;
+	ret = adf_setup_bh(accel_dev);
+	if (ret)
+		goto err_disable_msix;
+
+	ret = adf_request_irqs(accel_dev);
+	if (ret)
+		goto err_cleanup_bh;
 
 	return 0;
+
+err_cleanup_bh:
+	adf_cleanup_bh(accel_dev);
+
+err_disable_msix:
+	adf_disable_msix(&accel_dev->accel_pci_dev);
+
+err_free_msix_table:
+	adf_isr_free_msix_entry_table(accel_dev);
+
 err_out:
-	adf_isr_resource_free(accel_dev);
-	return -EFAULT;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(adf_isr_resource_alloc);
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
@@ -195,6 +195,13 @@
 		val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);
 	} while ((val & int_bit) && (count++ < ADF_IOV_MSG_ACK_MAX_RETRY));
 
+	if (val != msg) {
+		dev_dbg(&GET_DEV(accel_dev),
+			"Collision - PFVF CSR overwritten by remote function\n");
+		ret = -EIO;
+		goto out;
+	}
+
 	if (val & int_bit) {
 		dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");
 		val &= ~int_bit;
@@ -231,7 +238,6 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(adf_iov_putmsg);
 
 void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info)
 {
@@ -244,6 +250,11 @@
 
 	/* Read message from the VF */
 	msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr));
+	if (!(msg & ADF_VF2PF_INT)) {
+		dev_info(&GET_DEV(accel_dev),
+			 "Spurious VF2PF interrupt, msg %X. Ignored\n", msg);
+		goto out;
+	}
 
 	/* To ACK, clear the VF2PFINT bit */
 	msg &= ~ADF_VF2PF_INT;
@@ -327,6 +338,7 @@
 	if (resp && adf_iov_putmsg(accel_dev, resp, vf_nr))
 		dev_err(&GET_DEV(accel_dev), "Failed to send response to VF\n");
 
+out:
 	/* re-enable interrupt on PF from this VF */
 	adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_nr));
 	return;
@@ -361,6 +373,8 @@
 	msg |= ADF_PFVF_COMPATIBILITY_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT;
 	BUILD_BUG_ON(ADF_PFVF_COMPATIBILITY_VERSION > 255);
 
+	reinit_completion(&accel_dev->vf.iov_msg_completion);
+
 	/* Send request from VF to PF */
 	ret = adf_iov_putmsg(accel_dev, msg, 0);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_transport.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_transport.c
@@ -197,6 +197,7 @@
 		dev_err(&GET_DEV(accel_dev), "Ring address not aligned\n");
 		dma_free_coherent(&GET_DEV(accel_dev), ring_size_bytes,
 				  ring->base_addr, ring->dma_addr);
+		ring->base_addr = NULL;
 		return -EFAULT;
 	}
 
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c
@@ -49,14 +49,14 @@
 #include "adf_pf2vf_msg.h"
 
 /**
- * adf_vf2pf_init() - send init msg to PF
+ * adf_vf2pf_notify_init() - send init msg to PF
  * @accel_dev:  Pointer to acceleration VF device.
  *
  * Function sends an init messge from the VF to a PF
  *
  * Return: 0 on success, error code otherwise.
  */
-int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
+int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev)
 {
 	u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
 		(ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
@@ -69,17 +69,17 @@
 	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(adf_vf2pf_init);
+EXPORT_SYMBOL_GPL(adf_vf2pf_notify_init);
 
 /**
- * adf_vf2pf_shutdown() - send shutdown msg to PF
+ * adf_vf2pf_notify_shutdown() - send shutdown msg to PF
  * @accel_dev:  Pointer to acceleration VF device.
  *
  * Function sends a shutdown messge from the VF to a PF
  *
  * Return: void
  */
-void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
+void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev)
 {
 	u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
 	    (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
@@ -89,4 +89,4 @@
 			dev_err(&GET_DEV(accel_dev),
 				"Failed to send Shutdown event to PF\n");
 }
-EXPORT_SYMBOL_GPL(adf_vf2pf_shutdown);
+EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown);
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/adf_vf_isr.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/adf_vf_isr.c
@@ -123,6 +123,11 @@
 
 	/* Read the message from PF */
 	msg = ADF_CSR_RD(pmisc_bar_addr, hw_data->get_pf2vf_offset(0));
+	if (!(msg & ADF_PF2VF_INT)) {
+		dev_info(&GET_DEV(accel_dev),
+			 "Spurious PF2VF interrupt, msg %X. Ignored\n", msg);
+		goto out;
+	}
 
 	if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM))
 		/* Ignore legacy non-system (non-kernel) PF2VF messages */
@@ -171,6 +176,7 @@
 	msg &= ~ADF_PF2VF_INT;
 	ADF_CSR_WR(pmisc_bar_addr, hw_data->get_pf2vf_offset(0), msg);
 
+out:
 	/* Re-enable PF2VF interrupts */
 	adf_enable_pf2vf_interrupts(accel_dev);
 	return;
@@ -203,6 +209,7 @@
 	struct adf_bar *pmisc =
 			&GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
 	void __iomem *pmisc_bar_addr = pmisc->virt_addr;
+	bool handled = false;
 	u32 v_int;
 
 	/* Read VF INT source CSR to determine the source of VF interrupt */
@@ -215,7 +222,7 @@
 
 		/* Schedule tasklet to handle interrupt BH */
 		tasklet_hi_schedule(&accel_dev->vf.pf2vf_bh_tasklet);
-		return IRQ_HANDLED;
+		handled = true;
 	}
 
 	/* Check bundle interrupt */
@@ -227,10 +234,10 @@
 		WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, bank->bank_number,
 					   0);
 		tasklet_hi_schedule(&bank->resp_handler);
-		return IRQ_HANDLED;
+		handled = true;
 	}
 
-	return IRQ_NONE;
+	return handled ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int adf_request_msi_irq(struct adf_accel_dev *accel_dev)
@@ -304,17 +311,26 @@
 		goto err_out;
 
 	if (adf_setup_pf2vf_bh(accel_dev))
-		goto err_out;
+		goto err_disable_msi;
 
 	if (adf_setup_bh(accel_dev))
-		goto err_out;
+		goto err_cleanup_pf2vf_bh;
 
 	if (adf_request_msi_irq(accel_dev))
-		goto err_out;
+		goto err_cleanup_bh;
 
 	return 0;
+
+err_cleanup_bh:
+	adf_cleanup_bh(accel_dev);
+
+err_cleanup_pf2vf_bh:
+	adf_cleanup_pf2vf_bh(accel_dev);
+
+err_disable_msi:
+	adf_disable_msi(accel_dev);
+
 err_out:
-	adf_vf_isr_resource_free(accel_dev);
 	return -EFAULT;
 }
 EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc);
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/qat_algs.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/qat_algs.c
@@ -715,7 +715,7 @@
 	struct qat_alg_buf_list *bufl;
 	struct qat_alg_buf_list *buflout = NULL;
 	dma_addr_t blp;
-	dma_addr_t bloutp = 0;
+	dma_addr_t bloutp;
 	struct scatterlist *sg;
 	size_t sz_out, sz = struct_size(bufl, bufers, n + 1);
 
@@ -727,6 +727,9 @@
 	if (unlikely(!bufl))
 		return -ENOMEM;
 
+	for_each_sg(sgl, sg, n, i)
+		bufl->bufers[i].addr = DMA_MAPPING_ERROR;
+
 	blp = dma_map_single(dev, bufl, sz, DMA_TO_DEVICE);
 	if (unlikely(dma_mapping_error(dev, blp)))
 		goto err_in;
@@ -760,10 +763,14 @@
 				       dev_to_node(&GET_DEV(inst->accel_dev)));
 		if (unlikely(!buflout))
 			goto err_in;
+
+		bufers = buflout->bufers;
+		for_each_sg(sglout, sg, n, i)
+			bufers[i].addr = DMA_MAPPING_ERROR;
+
 		bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE);
 		if (unlikely(dma_mapping_error(dev, bloutp)))
 			goto err_out;
-		bufers = buflout->bufers;
 		for_each_sg(sglout, sg, n, i) {
 			int y = sg_nctr;
 
@@ -873,6 +880,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))
@@ -887,7 +899,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));
@@ -916,6 +928,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;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/qat_crypto.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/qat_crypto.c
@@ -170,6 +170,14 @@
 		goto err;
 	if (adf_cfg_section_add(accel_dev, "Accelerator0"))
 		goto err;
+
+	/* Temporarily set the number of crypto instances to zero to avoid
+	 * registering the crypto algorithms.
+	 * This will be removed when the algorithms will support the
+	 * CRYPTO_TFM_REQ_MAY_BACKLOG flag
+	 */
+	instances = 0;
+
 	for (i = 0; i < instances; i++) {
 		val = i;
 		snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_BANK_NUM, i);
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/qat_hal.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/qat_hal.c
@@ -1189,7 +1189,7 @@
 	unsigned short mask;
 	unsigned short dr_offset = 0x10;
 
-	status = ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES);
+	ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES);
 	if (CE_INUSE_CONTEXTS & ctx_enables) {
 		if (ctx & 0x1) {
 			pr_err("QAT: bad 4-ctx mode,ctx=0x%x\n", ctx);
@@ -1256,7 +1256,11 @@
 		pr_err("QAT: bad xfrAddr=0x%x\n", xfr_addr);
 		return -EINVAL;
 	}
-	qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+	status = qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+	if (status) {
+		pr_err("QAT: failed to read register");
+		return status;
+	}
 	gpr_addr = qat_hal_get_reg_addr(ICP_GPB_REL, gprnum);
 	data16low = 0xffff & data;
 	data16hi = 0xffff & (data >> 0x10);
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_common/qat_uclo.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_common/qat_uclo.c
@@ -332,13 +332,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;
 }
 
@@ -380,7 +385,6 @@
 	return 0;
 }
 
-#define ICP_DH895XCC_PESRAM_BAR_SIZE 0x80000
 static int qat_uclo_init_ae_memory(struct icp_qat_fw_loader_handle *handle,
 				   struct icp_qat_uof_initmem *init_mem)
 {
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c
@@ -123,10 +123,10 @@
 	hw_data->enable_error_correction = adf_vf_void_noop;
 	hw_data->init_admin_comms = adf_vf_int_noop;
 	hw_data->exit_admin_comms = adf_vf_void_noop;
-	hw_data->send_admin_init = adf_vf2pf_init;
+	hw_data->send_admin_init = adf_vf2pf_notify_init;
 	hw_data->init_arb = adf_vf_int_noop;
 	hw_data->exit_arb = adf_vf_void_noop;
-	hw_data->disable_iov = adf_vf2pf_shutdown;
+	hw_data->disable_iov = adf_vf2pf_notify_shutdown;
 	hw_data->get_accel_mask = get_accel_mask;
 	hw_data->get_ae_mask = get_ae_mask;
 	hw_data->get_num_accels = get_num_accels;
--- linux-ein-5.4.0.orig/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
+++ linux-ein-5.4.0/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
@@ -233,12 +233,12 @@
 	if (ret)
 		goto out_err_free_reg;
 
-	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
-
 	ret = adf_dev_init(accel_dev);
 	if (ret)
 		goto out_err_dev_shutdown;
 
+	set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
 	ret = adf_dev_start(accel_dev);
 	if (ret)
 		goto out_err_dev_stop;
--- linux-ein-5.4.0.orig/drivers/crypto/qce/sha.c
+++ linux-ein-5.4.0/drivers/crypto/qce/sha.c
@@ -512,8 +512,8 @@
 
 	ret = crypto_register_ahash(alg);
 	if (ret) {
-		kfree(tmpl);
 		dev_err(qce->dev, "%s registration failed\n", base->cra_name);
+		kfree(tmpl);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/crypto/qcom-rng.c
+++ linux-ein-5.4.0/drivers/crypto/qcom-rng.c
@@ -7,6 +7,7 @@
 #include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/crypto.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -42,16 +43,19 @@
 {
 	unsigned int currsize = 0;
 	u32 val;
+	int ret;
 
 	/* read random data from hardware */
 	do {
-		val = readl_relaxed(rng->base + PRNG_STATUS);
-		if (!(val & PRNG_STATUS_DATA_AVAIL))
-			break;
+		ret = readl_poll_timeout(rng->base + PRNG_STATUS, val,
+					 val & PRNG_STATUS_DATA_AVAIL,
+					 200, 10000);
+		if (ret)
+			return ret;
 
 		val = readl_relaxed(rng->base + PRNG_DATA_OUT);
 		if (!val)
-			break;
+			return -EINVAL;
 
 		if ((max - currsize) >= WORD_SZ) {
 			memcpy(data, &val, WORD_SZ);
@@ -64,7 +68,7 @@
 		}
 	} while (currsize < max);
 
-	return currsize;
+	return 0;
 }
 
 static int qcom_rng_generate(struct crypto_rng *tfm,
@@ -86,7 +90,7 @@
 	mutex_unlock(&rng->lock);
 	clk_disable_unprepare(rng->clk);
 
-	return 0;
+	return ret;
 }
 
 static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
--- linux-ein-5.4.0.orig/drivers/crypto/s5p-sss.c
+++ linux-ein-5.4.0/drivers/crypto/s5p-sss.c
@@ -2208,6 +2208,8 @@
 
 	variant = find_s5p_sss_version(pdev);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
 
 	/*
 	 * Note: HASH and PRNG uses the same registers in secss, avoid
--- linux-ein-5.4.0.orig/drivers/crypto/sahara.c
+++ linux-ein-5.4.0/drivers/crypto/sahara.c
@@ -43,7 +43,6 @@
 #define FLAGS_MODE_MASK		0x000f
 #define FLAGS_ENCRYPT		BIT(0)
 #define FLAGS_CBC		BIT(1)
-#define FLAGS_NEW_KEY		BIT(3)
 
 #define SAHARA_HDR_BASE			0x00800000
 #define SAHARA_HDR_SKHA_ALG_AES	0
@@ -141,8 +140,6 @@
 };
 
 struct sahara_ctx {
-	unsigned long flags;
-
 	/* AES-specific context */
 	int keylen;
 	u8 key[AES_KEYSIZE_128];
@@ -445,27 +442,24 @@
 	int ret;
 	int i, j;
 	int idx = 0;
+	u32 len;
 
-	/* Copy new key if necessary */
-	if (ctx->flags & FLAGS_NEW_KEY) {
-		memcpy(dev->key_base, ctx->key, ctx->keylen);
-		ctx->flags &= ~FLAGS_NEW_KEY;
-
-		if (dev->flags & FLAGS_CBC) {
-			dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE;
-			dev->hw_desc[idx]->p1 = dev->iv_phys_base;
-		} else {
-			dev->hw_desc[idx]->len1 = 0;
-			dev->hw_desc[idx]->p1 = 0;
-		}
-		dev->hw_desc[idx]->len2 = ctx->keylen;
-		dev->hw_desc[idx]->p2 = dev->key_phys_base;
-		dev->hw_desc[idx]->next = dev->hw_phys_desc[1];
-
-		dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev);
+	memcpy(dev->key_base, ctx->key, ctx->keylen);
 
-		idx++;
+	if (dev->flags & FLAGS_CBC) {
+		dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE;
+		dev->hw_desc[idx]->p1 = dev->iv_phys_base;
+	} else {
+		dev->hw_desc[idx]->len1 = 0;
+		dev->hw_desc[idx]->p1 = 0;
 	}
+	dev->hw_desc[idx]->len2 = ctx->keylen;
+	dev->hw_desc[idx]->p2 = dev->key_phys_base;
+	dev->hw_desc[idx]->next = dev->hw_phys_desc[1];
+	dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev);
+
+	idx++;
+
 
 	dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total);
 	if (dev->nb_in_sg < 0) {
@@ -487,24 +481,27 @@
 			 DMA_TO_DEVICE);
 	if (ret != dev->nb_in_sg) {
 		dev_err(dev->device, "couldn't map in sg\n");
-		goto unmap_in;
+		return -EINVAL;
 	}
+
 	ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg,
 			 DMA_FROM_DEVICE);
 	if (ret != dev->nb_out_sg) {
 		dev_err(dev->device, "couldn't map out sg\n");
-		goto unmap_out;
+		goto unmap_in;
 	}
 
 	/* Create input links */
 	dev->hw_desc[idx]->p1 = dev->hw_phys_link[0];
 	sg = dev->in_sg;
+	len = dev->total;
 	for (i = 0; i < dev->nb_in_sg; i++) {
-		dev->hw_link[i]->len = sg->length;
+		dev->hw_link[i]->len = min(len, sg->length);
 		dev->hw_link[i]->p = sg->dma_address;
 		if (i == (dev->nb_in_sg - 1)) {
 			dev->hw_link[i]->next = 0;
 		} else {
+			len -= min(len, sg->length);
 			dev->hw_link[i]->next = dev->hw_phys_link[i + 1];
 			sg = sg_next(sg);
 		}
@@ -513,12 +510,14 @@
 	/* Create output links */
 	dev->hw_desc[idx]->p2 = dev->hw_phys_link[i];
 	sg = dev->out_sg;
+	len = dev->total;
 	for (j = i; j < dev->nb_out_sg + i; j++) {
-		dev->hw_link[j]->len = sg->length;
+		dev->hw_link[j]->len = min(len, sg->length);
 		dev->hw_link[j]->p = sg->dma_address;
 		if (j == (dev->nb_out_sg + i - 1)) {
 			dev->hw_link[j]->next = 0;
 		} else {
+			len -= min(len, sg->length);
 			dev->hw_link[j]->next = dev->hw_phys_link[j + 1];
 			sg = sg_next(sg);
 		}
@@ -537,9 +536,6 @@
 
 	return 0;
 
-unmap_out:
-	dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg,
-		DMA_FROM_DEVICE);
 unmap_in:
 	dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg,
 		DMA_TO_DEVICE);
@@ -584,16 +580,17 @@
 
 	timeout = wait_for_completion_timeout(&dev->dma_completion,
 				msecs_to_jiffies(SAHARA_TIMEOUT_MS));
-	if (!timeout) {
-		dev_err(dev->device, "AES timeout\n");
-		return -ETIMEDOUT;
-	}
 
 	dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg,
 		DMA_FROM_DEVICE);
 	dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg,
 		DMA_TO_DEVICE);
 
+	if (!timeout) {
+		dev_err(dev->device, "AES timeout\n");
+		return -ETIMEDOUT;
+	}
+
 	return 0;
 }
 
@@ -608,7 +605,6 @@
 	/* SAHARA only supports 128bit keys */
 	if (keylen == AES_KEYSIZE_128) {
 		memcpy(ctx->key, key, keylen);
-		ctx->flags |= FLAGS_NEW_KEY;
 		return 0;
 	}
 
@@ -796,6 +792,7 @@
 				       int start)
 {
 	struct scatterlist *sg;
+	unsigned int len;
 	unsigned int i;
 	int ret;
 
@@ -817,12 +814,14 @@
 	if (!ret)
 		return -EFAULT;
 
+	len = rctx->total;
 	for (i = start; i < dev->nb_in_sg + start; i++) {
-		dev->hw_link[i]->len = sg->length;
+		dev->hw_link[i]->len = min(len, sg->length);
 		dev->hw_link[i]->p = sg->dma_address;
 		if (i == (dev->nb_in_sg + start - 1)) {
 			dev->hw_link[i]->next = 0;
 		} else {
+			len -= min(len, sg->length);
 			dev->hw_link[i]->next = dev->hw_phys_link[i + 1];
 			sg = sg_next(sg);
 		}
@@ -903,24 +902,6 @@
 	return 0;
 }
 
-static int sahara_walk_and_recalc(struct scatterlist *sg, unsigned int nbytes)
-{
-	if (!sg || !sg->length)
-		return nbytes;
-
-	while (nbytes && sg) {
-		if (nbytes <= sg->length) {
-			sg->length = nbytes;
-			sg_mark_end(sg);
-			break;
-		}
-		nbytes -= sg->length;
-		sg = sg_next(sg);
-	}
-
-	return nbytes;
-}
-
 static int sahara_sha_prepare_request(struct ahash_request *req)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -957,36 +938,20 @@
 					hash_later, 0);
 	}
 
-	/* nbytes should now be multiple of blocksize */
-	req->nbytes = req->nbytes - hash_later;
-
-	sahara_walk_and_recalc(req->src, req->nbytes);
-
+	rctx->total = len - hash_later;
 	/* have data from previous operation and current */
 	if (rctx->buf_cnt && req->nbytes) {
 		sg_init_table(rctx->in_sg_chain, 2);
 		sg_set_buf(rctx->in_sg_chain, rctx->rembuf, rctx->buf_cnt);
-
 		sg_chain(rctx->in_sg_chain, 2, req->src);
-
-		rctx->total = req->nbytes + rctx->buf_cnt;
 		rctx->in_sg = rctx->in_sg_chain;
-
-		req->src = rctx->in_sg_chain;
 	/* only data from previous operation */
 	} else if (rctx->buf_cnt) {
-		if (req->src)
-			rctx->in_sg = req->src;
-		else
-			rctx->in_sg = rctx->in_sg_chain;
-		/* buf was copied into rembuf above */
+		rctx->in_sg = rctx->in_sg_chain;
 		sg_init_one(rctx->in_sg, rctx->rembuf, rctx->buf_cnt);
-		rctx->total = rctx->buf_cnt;
 	/* no data from previous operation */
 	} else {
 		rctx->in_sg = req->src;
-		rctx->total = req->nbytes;
-		req->src = rctx->in_sg;
 	}
 
 	/* on next call, we only have the remaining data in the buffer */
@@ -1007,7 +972,10 @@
 		return ret;
 
 	if (rctx->first) {
-		sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0);
+		ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0);
+		if (ret)
+			return ret;
+
 		dev->hw_desc[0]->next = 0;
 		rctx->first = 0;
 	} else {
@@ -1015,7 +983,10 @@
 
 		sahara_sha_hw_context_descriptor_create(dev, rctx, req, 0);
 		dev->hw_desc[0]->next = dev->hw_phys_desc[1];
-		sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1);
+		ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1);
+		if (ret)
+			return ret;
+
 		dev->hw_desc[1]->next = 0;
 	}
 
@@ -1028,18 +999,19 @@
 
 	timeout = wait_for_completion_timeout(&dev->dma_completion,
 				msecs_to_jiffies(SAHARA_TIMEOUT_MS));
-	if (!timeout) {
-		dev_err(dev->device, "SHA timeout\n");
-		return -ETIMEDOUT;
-	}
 
 	if (rctx->sg_in_idx)
 		dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg,
 			     DMA_TO_DEVICE);
 
+	if (!timeout) {
+		dev_err(dev->device, "SHA timeout\n");
+		return -ETIMEDOUT;
+	}
+
 	memcpy(rctx->context, dev->context_base, rctx->context_size);
 
-	if (req->result)
+	if (req->result && rctx->last)
 		memcpy(req->result, rctx->context, rctx->digest_size);
 
 	return 0;
@@ -1183,8 +1155,7 @@
 static int sahara_sha_cra_init(struct crypto_tfm *tfm)
 {
 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
-				 sizeof(struct sahara_sha_reqctx) +
-				 SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
+				 sizeof(struct sahara_sha_reqctx));
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/crypto/stm32/stm32-crc32.c
+++ linux-ein-5.4.0/drivers/crypto/stm32/stm32-crc32.c
@@ -28,8 +28,10 @@
 
 /* Registers values */
 #define CRC_CR_RESET            BIT(0)
-#define CRC_CR_REVERSE          (BIT(7) | BIT(6) | BIT(5))
-#define CRC_INIT_DEFAULT        0xFFFFFFFF
+#define CRC_CR_REV_IN_WORD      (BIT(6) | BIT(5))
+#define CRC_CR_REV_IN_BYTE      BIT(5)
+#define CRC_CR_REV_OUT          BIT(7)
+#define CRC32C_INIT_DEFAULT     0xFFFFFFFF
 
 #define CRC_AUTOSUSPEND_DELAY	50
 
@@ -38,8 +40,6 @@
 	struct device    *dev;
 	void __iomem     *regs;
 	struct clk       *clk;
-	u8               pending_data[sizeof(u32)];
-	size_t           nb_pending_bytes;
 };
 
 struct stm32_crc_list {
@@ -59,14 +59,13 @@
 
 struct stm32_crc_desc_ctx {
 	u32    partial; /* crc32c: partial in first 4 bytes of that struct */
-	struct stm32_crc *crc;
 };
 
 static int stm32_crc32_cra_init(struct crypto_tfm *tfm)
 {
 	struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);
 
-	mctx->key = CRC_INIT_DEFAULT;
+	mctx->key = 0;
 	mctx->poly = CRC32_POLY_LE;
 	return 0;
 }
@@ -75,7 +74,7 @@
 {
 	struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);
 
-	mctx->key = CRC_INIT_DEFAULT;
+	mctx->key = CRC32C_INIT_DEFAULT;
 	mctx->poly = CRC32C_POLY_LE;
 	return 0;
 }
@@ -94,32 +93,42 @@
 	return 0;
 }
 
+static struct stm32_crc *stm32_crc_get_next_crc(void)
+{
+	struct stm32_crc *crc;
+
+	spin_lock_bh(&crc_list.lock);
+	crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list);
+	if (crc)
+		list_move_tail(&crc->list, &crc_list.dev_list);
+	spin_unlock_bh(&crc_list.lock);
+
+	return crc;
+}
+
 static int stm32_crc_init(struct shash_desc *desc)
 {
 	struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
 	struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
 	struct stm32_crc *crc;
 
-	spin_lock_bh(&crc_list.lock);
-	list_for_each_entry(crc, &crc_list.dev_list, list) {
-		ctx->crc = crc;
-		break;
-	}
-	spin_unlock_bh(&crc_list.lock);
+	crc = stm32_crc_get_next_crc();
+	if (!crc)
+		return -ENODEV;
 
-	pm_runtime_get_sync(ctx->crc->dev);
+	pm_runtime_get_sync(crc->dev);
 
 	/* Reset, set key, poly and configure in bit reverse mode */
-	writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT);
-	writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL);
-	writel_relaxed(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR);
+	writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT);
+	writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL);
+	writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,
+		       crc->regs + CRC_CR);
 
 	/* Store partial result */
-	ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR);
-	ctx->crc->nb_pending_bytes = 0;
+	ctx->partial = readl_relaxed(crc->regs + CRC_DR);
 
-	pm_runtime_mark_last_busy(ctx->crc->dev);
-	pm_runtime_put_autosuspend(ctx->crc->dev);
+	pm_runtime_mark_last_busy(crc->dev);
+	pm_runtime_put_autosuspend(crc->dev);
 
 	return 0;
 }
@@ -128,31 +137,49 @@
 			    unsigned int length)
 {
 	struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
-	struct stm32_crc *crc = ctx->crc;
-	u32 *d32;
-	unsigned int i;
+	struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
+	struct stm32_crc *crc;
+
+	crc = stm32_crc_get_next_crc();
+	if (!crc)
+		return -ENODEV;
 
 	pm_runtime_get_sync(crc->dev);
 
-	if (unlikely(crc->nb_pending_bytes)) {
-		while (crc->nb_pending_bytes != sizeof(u32) && length) {
-			/* Fill in pending data */
-			crc->pending_data[crc->nb_pending_bytes++] = *(d8++);
+	/*
+	 * Restore previously calculated CRC for this context as init value
+	 * Restore polynomial configuration
+	 * Configure in register for word input data,
+	 * Configure out register in reversed bit mode data.
+	 */
+	writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT);
+	writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL);
+	writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,
+		       crc->regs + CRC_CR);
+
+	if (d8 != PTR_ALIGN(d8, sizeof(u32))) {
+		/* Configure for byte data */
+		writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT,
+			       crc->regs + CRC_CR);
+		while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) {
+			writeb_relaxed(*d8++, crc->regs + CRC_DR);
 			length--;
 		}
-
-		if (crc->nb_pending_bytes == sizeof(u32)) {
-			/* Process completed pending data */
-			writel_relaxed(*(u32 *)crc->pending_data,
-				       crc->regs + CRC_DR);
-			crc->nb_pending_bytes = 0;
-		}
+		/* Configure for word data */
+		writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,
+			       crc->regs + CRC_CR);
 	}
 
-	d32 = (u32 *)d8;
-	for (i = 0; i < length >> 2; i++)
-		/* Process 32 bits data */
-		writel_relaxed(*(d32++), crc->regs + CRC_DR);
+	for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32))
+		writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR);
+
+	if (length) {
+		/* Configure for byte data */
+		writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT,
+			       crc->regs + CRC_CR);
+		while (length--)
+			writeb_relaxed(*d8++, crc->regs + CRC_DR);
+	}
 
 	/* Store partial result */
 	ctx->partial = readl_relaxed(crc->regs + CRC_DR);
@@ -160,22 +187,6 @@
 	pm_runtime_mark_last_busy(crc->dev);
 	pm_runtime_put_autosuspend(crc->dev);
 
-	/* Check for pending data (non 32 bits) */
-	length &= 3;
-	if (likely(!length))
-		return 0;
-
-	if ((crc->nb_pending_bytes + length) >= sizeof(u32)) {
-		/* Shall not happen */
-		dev_err(crc->dev, "Pending data overflow\n");
-		return -EINVAL;
-	}
-
-	d8 = (const u8 *)d32;
-	for (i = 0; i < length; i++)
-		/* Store pending data */
-		crc->pending_data[crc->nb_pending_bytes++] = *(d8++);
-
 	return 0;
 }
 
@@ -204,6 +215,8 @@
 	return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out);
 }
 
+static unsigned int refcnt;
+static DEFINE_MUTEX(refcnt_lock);
 static struct shash_alg algs[] = {
 	/* CRC-32 */
 	{
@@ -217,7 +230,7 @@
 		.digestsize     = CHKSUM_DIGEST_SIZE,
 		.base           = {
 			.cra_name               = "crc32",
-			.cra_driver_name        = DRIVER_NAME,
+			.cra_driver_name        = "stm32-crc32-crc32",
 			.cra_priority           = 200,
 			.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
 			.cra_blocksize          = CHKSUM_BLOCK_SIZE,
@@ -239,7 +252,7 @@
 		.digestsize     = CHKSUM_DIGEST_SIZE,
 		.base           = {
 			.cra_name               = "crc32c",
-			.cra_driver_name        = DRIVER_NAME,
+			.cra_driver_name        = "stm32-crc32-crc32c",
 			.cra_priority           = 200,
 			.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
 			.cra_blocksize          = CHKSUM_BLOCK_SIZE,
@@ -294,12 +307,18 @@
 	list_add(&crc->list, &crc_list.dev_list);
 	spin_unlock(&crc_list.lock);
 
-	ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));
-	if (ret) {
-		dev_err(dev, "Failed to register\n");
-		clk_disable_unprepare(crc->clk);
-		return ret;
+	mutex_lock(&refcnt_lock);
+	if (!refcnt) {
+		ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));
+		if (ret) {
+			mutex_unlock(&refcnt_lock);
+			dev_err(dev, "Failed to register\n");
+			clk_disable_unprepare(crc->clk);
+			return ret;
+		}
 	}
+	refcnt++;
+	mutex_unlock(&refcnt_lock);
 
 	dev_info(dev, "Initialized\n");
 
@@ -313,14 +332,19 @@
 	struct stm32_crc *crc = platform_get_drvdata(pdev);
 	int ret = pm_runtime_get_sync(crc->dev);
 
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(crc->dev);
 		return ret;
+	}
 
 	spin_lock(&crc_list.lock);
 	list_del(&crc->list);
 	spin_unlock(&crc_list.lock);
 
-	crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
+	mutex_lock(&refcnt_lock);
+	if (!--refcnt)
+		crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
+	mutex_unlock(&refcnt_lock);
 
 	pm_runtime_disable(crc->dev);
 	pm_runtime_put_noidle(crc->dev);
--- linux-ein-5.4.0.orig/drivers/crypto/stm32/stm32-cryp.c
+++ linux-ein-5.4.0/drivers/crypto/stm32/stm32-cryp.c
@@ -537,7 +537,7 @@
 	int ret;
 	u32 cfg, hw_mode;
 
-	pm_runtime_get_sync(cryp->dev);
+	pm_runtime_resume_and_get(cryp->dev);
 
 	/* Disable interrupt */
 	stm32_cryp_write(cryp, CRYP_IMSCR, 0);
@@ -639,7 +639,7 @@
 		/* Phase 4 : output tag */
 		err = stm32_cryp_read_auth_tag(cryp);
 
-	if (!err && (!(is_gcm(cryp) || is_ccm(cryp))))
+	if (!err && (!(is_gcm(cryp) || is_ccm(cryp) || is_ecb(cryp))))
 		stm32_cryp_get_iv(cryp);
 
 	if (cryp->sgs_copied) {
@@ -669,8 +669,6 @@
 	else
 		crypto_finalize_ablkcipher_request(cryp->engine, cryp->req,
 						   err);
-
-	memset(cryp->ctx->key, 0, cryp->ctx->keylen);
 }
 
 static int stm32_cryp_cpu_start(struct stm32_cryp *cryp)
@@ -2038,8 +2036,6 @@
 
 	pm_runtime_disable(dev);
 	pm_runtime_put_noidle(dev);
-	pm_runtime_disable(dev);
-	pm_runtime_put_noidle(dev);
 
 	clk_disable_unprepare(cryp->clk);
 
@@ -2054,7 +2050,7 @@
 	if (!cryp)
 		return -ENODEV;
 
-	ret = pm_runtime_get_sync(cryp->dev);
+	ret = pm_runtime_resume_and_get(cryp->dev);
 	if (ret < 0)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/crypto/stm32/stm32-hash.c
+++ linux-ein-5.4.0/drivers/crypto/stm32/stm32-hash.c
@@ -562,9 +562,9 @@
 	}
 
 	for_each_sg(rctx->sg, tsg, rctx->nents, i) {
+		sg[0] = *tsg;
 		len = sg->length;
 
-		sg[0] = *tsg;
 		if (sg_is_last(sg)) {
 			if (hdev->dma_mode == 1) {
 				len = (ALIGN(sg->length, 16) - 16);
@@ -810,7 +810,7 @@
 static int stm32_hash_hw_init(struct stm32_hash_dev *hdev,
 			      struct stm32_hash_request_ctx *rctx)
 {
-	pm_runtime_get_sync(hdev->dev);
+	pm_runtime_resume_and_get(hdev->dev);
 
 	if (!(HASH_FLAGS_INIT & hdev->flags)) {
 		stm32_hash_write(hdev, HASH_CR, HASH_CR_INIT);
@@ -959,7 +959,7 @@
 	u32 *preg;
 	unsigned int i;
 
-	pm_runtime_get_sync(hdev->dev);
+	pm_runtime_resume_and_get(hdev->dev);
 
 	while ((stm32_hash_read(hdev, HASH_SR) & HASH_SR_BUSY))
 		cpu_relax();
@@ -997,7 +997,7 @@
 
 	preg = rctx->hw_context;
 
-	pm_runtime_get_sync(hdev->dev);
+	pm_runtime_resume_and_get(hdev->dev);
 
 	stm32_hash_write(hdev, HASH_IMR, *preg++);
 	stm32_hash_write(hdev, HASH_STR, *preg++);
@@ -1554,8 +1554,6 @@
 		return -ENODEV;
 
 	ret = pm_runtime_get_sync(hdev->dev);
-	if (ret < 0)
-		return ret;
 
 	stm32_hash_unregister_algs(hdev);
 
@@ -1571,7 +1569,8 @@
 	pm_runtime_disable(hdev->dev);
 	pm_runtime_put_noidle(hdev->dev);
 
-	clk_disable_unprepare(hdev->clk);
+	if (ret >= 0)
+		clk_disable_unprepare(hdev->clk);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ linux-ein-5.4.0/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -30,6 +30,8 @@
 	unsigned int ileft = areq->cryptlen;
 	unsigned int oleft = areq->cryptlen;
 	unsigned int todo;
+	unsigned long pi = 0, po = 0; /* progress for in and out */
+	bool miter_err;
 	struct sg_mapping_iter mi, mo;
 	unsigned int oi, oo; /* offset for in and out */
 	unsigned long flags;
@@ -44,59 +46,74 @@
 
 	spin_lock_irqsave(&ss->slock, flags);
 
-	for (i = 0; i < op->keylen; i += 4)
-		writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
+	for (i = 0; i < op->keylen / 4; i++)
+		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
 
 	if (areq->iv) {
 		for (i = 0; i < 4 && i < ivsize / 4; i++) {
 			v = *(u32 *)(areq->iv + i * 4);
-			writel(v, ss->base + SS_IV0 + i * 4);
+			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
 		}
 	}
 	writel(mode, ss->base + SS_CTL);
 
-	sg_miter_start(&mi, areq->src, sg_nents(areq->src),
-		       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
-	sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
-		       SG_MITER_TO_SG | SG_MITER_ATOMIC);
-	sg_miter_next(&mi);
-	sg_miter_next(&mo);
-	if (!mi.addr || !mo.addr) {
-		dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
-		err = -EINVAL;
-		goto release_ss;
-	}
 
 	ileft = areq->cryptlen / 4;
 	oleft = areq->cryptlen / 4;
 	oi = 0;
 	oo = 0;
 	do {
-		todo = min3(rx_cnt, ileft, (mi.length - oi) / 4);
-		if (todo) {
-			ileft -= todo;
-			writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo);
-			oi += todo * 4;
-		}
-		if (oi == mi.length) {
-			sg_miter_next(&mi);
-			oi = 0;
+		if (ileft) {
+			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
+					SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+			if (pi)
+				sg_miter_skip(&mi, pi);
+			miter_err = sg_miter_next(&mi);
+			if (!miter_err || !mi.addr) {
+				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
+				err = -EINVAL;
+				goto release_ss;
+			}
+			todo = min(rx_cnt, ileft);
+			todo = min_t(size_t, todo, (mi.length - oi) / 4);
+			if (todo) {
+				ileft -= todo;
+				writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo);
+				oi += todo * 4;
+			}
+			if (oi == mi.length) {
+				pi += mi.length;
+				oi = 0;
+			}
+			sg_miter_stop(&mi);
 		}
 
 		spaces = readl(ss->base + SS_FCSR);
 		rx_cnt = SS_RXFIFO_SPACES(spaces);
 		tx_cnt = SS_TXFIFO_SPACES(spaces);
 
-		todo = min3(tx_cnt, oleft, (mo.length - oo) / 4);
+		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
+			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
+		if (po)
+			sg_miter_skip(&mo, po);
+		miter_err = sg_miter_next(&mo);
+		if (!miter_err || !mo.addr) {
+			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
+			err = -EINVAL;
+			goto release_ss;
+		}
+		todo = min(tx_cnt, oleft);
+		todo = min_t(size_t, todo, (mo.length - oo) / 4);
 		if (todo) {
 			oleft -= todo;
 			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
 			oo += todo * 4;
 		}
 		if (oo == mo.length) {
-			sg_miter_next(&mo);
 			oo = 0;
+			po += mo.length;
 		}
+		sg_miter_stop(&mo);
 	} while (oleft);
 
 	if (areq->iv) {
@@ -107,8 +124,6 @@
 	}
 
 release_ss:
-	sg_miter_stop(&mi);
-	sg_miter_stop(&mo);
 	writel(0, ss->base + SS_CTL);
 	spin_unlock_irqrestore(&ss->slock, flags);
 	return err;
@@ -162,12 +177,14 @@
 	unsigned int oleft = areq->cryptlen;
 	unsigned int todo;
 	struct sg_mapping_iter mi, mo;
+	unsigned long pi = 0, po = 0; /* progress for in and out */
+	bool miter_err;
 	unsigned int oi, oo;	/* offset for in and out */
 	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;
-	bool need_fallback;
+	bool need_fallback = false;
 
 	if (!areq->cryptlen)
 		return 0;
@@ -186,12 +203,12 @@
 	 * we can use the SS optimized function
 	 */
 	while (in_sg && no_chunk == 1) {
-		if (in_sg->length % 4)
+		if ((in_sg->length | in_sg->offset) & 3u)
 			no_chunk = 0;
 		in_sg = sg_next(in_sg);
 	}
 	while (out_sg && no_chunk == 1) {
-		if (out_sg->length % 4)
+		if ((out_sg->length | out_sg->offset) & 3u)
 			no_chunk = 0;
 		out_sg = sg_next(out_sg);
 	}
@@ -204,28 +221,17 @@
 
 	spin_lock_irqsave(&ss->slock, flags);
 
-	for (i = 0; i < op->keylen; i += 4)
-		writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
+	for (i = 0; i < op->keylen / 4; i++)
+		writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1);
 
 	if (areq->iv) {
 		for (i = 0; i < 4 && i < ivsize / 4; i++) {
 			v = *(u32 *)(areq->iv + i * 4);
-			writel(v, ss->base + SS_IV0 + i * 4);
+			writesl(ss->base + SS_IV0 + i * 4, &v, 1);
 		}
 	}
 	writel(mode, ss->base + SS_CTL);
 
-	sg_miter_start(&mi, areq->src, sg_nents(areq->src),
-		       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
-	sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
-		       SG_MITER_TO_SG | SG_MITER_ATOMIC);
-	sg_miter_next(&mi);
-	sg_miter_next(&mo);
-	if (!mi.addr || !mo.addr) {
-		dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
-		err = -EINVAL;
-		goto release_ss;
-	}
 	ileft = areq->cryptlen;
 	oleft = areq->cryptlen;
 	oi = 0;
@@ -233,13 +239,22 @@
 
 	while (oleft) {
 		if (ileft) {
-			char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
-
+			sg_miter_start(&mi, areq->src, sg_nents(areq->src),
+				       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+			if (pi)
+				sg_miter_skip(&mi, pi);
+			miter_err = sg_miter_next(&mi);
+			if (!miter_err || !mi.addr) {
+				dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
+				err = -EINVAL;
+				goto release_ss;
+			}
 			/*
 			 * todo is the number of consecutive 4byte word that we
 			 * can read from current SG
 			 */
-			todo = min3(rx_cnt, ileft / 4, (mi.length - oi) / 4);
+			todo = min(rx_cnt, ileft / 4);
+			todo = min_t(size_t, todo, (mi.length - oi) / 4);
 			if (todo && !ob) {
 				writesl(ss->base + SS_RXFIFO, mi.addr + oi,
 					todo);
@@ -253,52 +268,59 @@
 				 * we need to be able to write all buf in one
 				 * pass, so it is why we min() with rx_cnt
 				 */
-				todo = min3(rx_cnt * 4 - ob, ileft,
-					    mi.length - oi);
-				memcpy(buf + ob, mi.addr + oi, todo);
+				todo = min(rx_cnt * 4 - ob, ileft);
+				todo = min_t(size_t, todo, mi.length - oi);
+				memcpy(ss->buf + ob, mi.addr + oi, todo);
 				ileft -= todo;
 				oi += todo;
 				ob += todo;
 				if (!(ob % 4)) {
-					writesl(ss->base + SS_RXFIFO, buf,
+					writesl(ss->base + SS_RXFIFO, ss->buf,
 						ob / 4);
 					ob = 0;
 				}
 			}
 			if (oi == mi.length) {
-				sg_miter_next(&mi);
+				pi += mi.length;
 				oi = 0;
 			}
+			sg_miter_stop(&mi);
 		}
 
 		spaces = readl(ss->base + SS_FCSR);
 		rx_cnt = SS_RXFIFO_SPACES(spaces);
 		tx_cnt = SS_TXFIFO_SPACES(spaces);
-		dev_dbg(ss->dev, "%x %u/%u %u/%u cnt=%u %u/%u %u/%u cnt=%u %u\n",
-			mode,
-			oi, mi.length, ileft, areq->cryptlen, rx_cnt,
-			oo, mo.length, oleft, areq->cryptlen, tx_cnt, ob);
 
 		if (!tx_cnt)
 			continue;
+		sg_miter_start(&mo, areq->dst, sg_nents(areq->dst),
+			       SG_MITER_TO_SG | SG_MITER_ATOMIC);
+		if (po)
+			sg_miter_skip(&mo, po);
+		miter_err = sg_miter_next(&mo);
+		if (!miter_err || !mo.addr) {
+			dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n");
+			err = -EINVAL;
+			goto release_ss;
+		}
 		/* todo in 4bytes word */
-		todo = min3(tx_cnt, oleft / 4, (mo.length - oo) / 4);
+		todo = min(tx_cnt, oleft / 4);
+		todo = min_t(size_t, todo, (mo.length - oo) / 4);
+
 		if (todo) {
 			readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo);
 			oleft -= todo * 4;
 			oo += todo * 4;
 			if (oo == mo.length) {
-				sg_miter_next(&mo);
+				po += mo.length;
 				oo = 0;
 			}
 		} else {
-			char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
-
 			/*
 			 * read obl bytes in bufo, we read at maximum for
 			 * emptying the device
 			 */
-			readsl(ss->base + SS_TXFIFO, bufo, tx_cnt);
+			readsl(ss->base + SS_TXFIFO, ss->bufo, tx_cnt);
 			obl = tx_cnt * 4;
 			obo = 0;
 			do {
@@ -308,18 +330,21 @@
 				 * no more than remaining buffer
 				 * no need to test against oleft
 				 */
-				todo = min(mo.length - oo, obl - obo);
-				memcpy(mo.addr + oo, bufo + obo, todo);
+				todo = min_t(size_t,
+					     mo.length - oo, obl - obo);
+				memcpy(mo.addr + oo, ss->bufo + obo, todo);
 				oleft -= todo;
 				obo += todo;
 				oo += todo;
 				if (oo == mo.length) {
+					po += mo.length;
 					sg_miter_next(&mo);
 					oo = 0;
 				}
 			} while (obo < obl);
 			/* bufo must be fully used here */
 		}
+		sg_miter_stop(&mo);
 	}
 	if (areq->iv) {
 		for (i = 0; i < 4 && i < ivsize / 4; i++) {
@@ -329,8 +354,6 @@
 	}
 
 release_ss:
-	sg_miter_stop(&mi);
-	sg_miter_stop(&mo);
 	writel(0, ss->base + SS_CTL);
 	spin_unlock_irqrestore(&ss->slock, flags);
 
--- linux-ein-5.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ linux-ein-5.4.0/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -175,7 +175,7 @@
 	 */
 	unsigned int i = 0, end, fill, min_fill, nwait, nbw = 0, j = 0, todo;
 	unsigned int in_i = 0;
-	u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, wb = 0, v, ivmode = 0;
+	u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, v, ivmode = 0;
 	struct sun4i_req_ctx *op = ahash_request_ctx(areq);
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
 	struct sun4i_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
@@ -184,6 +184,7 @@
 	struct sg_mapping_iter mi;
 	int in_r, err = 0;
 	size_t copied = 0;
+	__le32 wb = 0;
 
 	dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x",
 		__func__, crypto_tfm_alg_name(areq->base.tfm),
@@ -272,8 +273,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;
@@ -293,8 +294,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);
@@ -320,8 +321,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;
@@ -395,7 +396,7 @@
 
 		nbw = op->len - 4 * nwait;
 		if (nbw) {
-			wb = *(u32 *)(op->buf + nwait * 4);
+			wb = cpu_to_le32(*(u32 *)(op->buf + nwait * 4));
 			wb &= GENMASK((nbw * 8) - 1, 0);
 
 			op->byte_count += nbw;
@@ -404,7 +405,7 @@
 
 	/* write the remaining bytes of the nbw buffer */
 	wb |= ((1 << 7) << (nbw * 8));
-	bf[j++] = wb;
+	bf[j++] = le32_to_cpu(wb);
 
 	/*
 	 * number of space to pad to obtain 64o minus 8(size) minus 4 (final 1)
@@ -423,13 +424,13 @@
 
 	/* write the length of data */
 	if (op->mode == SS_OP_SHA1) {
-		__be64 bits = cpu_to_be64(op->byte_count << 3);
-		bf[j++] = lower_32_bits(bits);
-		bf[j++] = upper_32_bits(bits);
+		__be64 *bits = (__be64 *)&bf[j];
+		*bits = cpu_to_be64(op->byte_count << 3);
+		j += 2;
 	} else {
-		__le64 bits = op->byte_count << 3;
-		bf[j++] = lower_32_bits(bits);
-		bf[j++] = upper_32_bits(bits);
+		__le64 *bits = (__le64 *)&bf[j];
+		*bits = cpu_to_le64(op->byte_count << 3);
+		j += 2;
 	}
 	writesl(ss->base + SS_RXFIFO, bf, j);
 
@@ -471,7 +472,7 @@
 		}
 	} else {
 		for (i = 0; i < 4; i++) {
-			v = readl(ss->base + SS_MD0 + i * 4);
+			v = cpu_to_le32(readl(ss->base + SS_MD0 + i * 4));
 			memcpy(areq->result + i * 4, &v, 4);
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/crypto/sunxi-ss/sun4i-ss.h
+++ linux-ein-5.4.0/drivers/crypto/sunxi-ss/sun4i-ss.h
@@ -138,6 +138,8 @@
 	struct reset_control *reset;
 	struct device *dev;
 	struct resource *res;
+	char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+	char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
 	spinlock_t slock; /* control the use of the device */
 #ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
 	u32 seed[SS_SEED_LEN / BITS_PER_LONG];
--- linux-ein-5.4.0.orig/drivers/crypto/talitos.c
+++ linux-ein-5.4.0/drivers/crypto/talitos.c
@@ -460,7 +460,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;
@@ -478,7 +478,7 @@
 
 	iter = tail;
 	while (priv->chan[ch].fifo[iter].dma_desc != cur_desc &&
-	       priv->chan[ch].fifo[iter].desc->next_desc != cur_desc) {
+	       priv->chan[ch].fifo[iter].desc->next_desc != cpu_to_be32(cur_desc)) {
 		iter = (iter + 1) & (priv->fifo_len - 1);
 		if (iter == tail) {
 			dev_err(dev, "couldn't locate current descriptor\n");
@@ -486,7 +486,7 @@
 		}
 	}
 
-	if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc) {
+	if (priv->chan[ch].fifo[iter].desc->next_desc == cpu_to_be32(cur_desc)) {
 		struct talitos_edesc *edesc;
 
 		edesc = container_of(priv->chan[ch].fifo[iter].desc,
@@ -501,13 +501,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:
@@ -1097,11 +1097,12 @@
  */
 static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
 				 unsigned int offset, int datalen, int elen,
-				 struct talitos_ptr *link_tbl_ptr)
+				 struct talitos_ptr *link_tbl_ptr, int align)
 {
 	int n_sg = elen ? sg_count + 1 : sg_count;
 	int count = 0;
 	int cryptlen = datalen + elen;
+	int padding = ALIGN(cryptlen, align) - cryptlen;
 
 	while (cryptlen && sg && n_sg--) {
 		unsigned int len = sg_dma_len(sg);
@@ -1125,7 +1126,7 @@
 			offset += datalen;
 		}
 		to_talitos_ptr(link_tbl_ptr + count,
-			       sg_dma_address(sg) + offset, len, 0);
+			       sg_dma_address(sg) + offset, sg_next(sg) ? len : len + padding, 0);
 		to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0);
 		count++;
 		cryptlen -= len;
@@ -1148,10 +1149,11 @@
 			      unsigned int len, struct talitos_edesc *edesc,
 			      struct talitos_ptr *ptr, int sg_count,
 			      unsigned int offset, int tbl_off, int elen,
-			      bool force)
+			      bool force, int align)
 {
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	bool is_sec1 = has_ftr_sec1(priv);
+	int aligned_len = ALIGN(len, align);
 
 	if (!src) {
 		to_talitos_ptr(ptr, 0, 0, is_sec1);
@@ -1159,22 +1161,22 @@
 	}
 	to_talitos_ptr_ext_set(ptr, elen, is_sec1);
 	if (sg_count == 1 && !force) {
-		to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1);
+		to_talitos_ptr(ptr, sg_dma_address(src) + offset, aligned_len, is_sec1);
 		return sg_count;
 	}
 	if (is_sec1) {
-		to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1);
+		to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, aligned_len, is_sec1);
 		return sg_count;
 	}
 	sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len, elen,
-					 &edesc->link_tbl[tbl_off]);
+					 &edesc->link_tbl[tbl_off], align);
 	if (sg_count == 1 && !force) {
 		/* Only one segment now, so no link tbl needed*/
 		copy_talitos_ptr(ptr, &edesc->link_tbl[tbl_off], is_sec1);
 		return sg_count;
 	}
 	to_talitos_ptr(ptr, edesc->dma_link_tbl +
-			    tbl_off * sizeof(struct talitos_ptr), len, is_sec1);
+			    tbl_off * sizeof(struct talitos_ptr), aligned_len, is_sec1);
 	to_talitos_ptr_ext_or(ptr, DESC_PTR_LNKTBL_JUMP, is_sec1);
 
 	return sg_count;
@@ -1186,7 +1188,7 @@
 			  unsigned int offset, int tbl_off)
 {
 	return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset,
-				  tbl_off, 0, false);
+				  tbl_off, 0, false, 1);
 }
 
 /*
@@ -1255,7 +1257,7 @@
 
 	ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4],
 				 sg_count, areq->assoclen, tbl_off, elen,
-				 false);
+				 false, 1);
 
 	if (ret > 1) {
 		tbl_off += ret;
@@ -1275,7 +1277,7 @@
 		elen = 0;
 	ret = talitos_sg_map_ext(dev, areq->dst, cryptlen, edesc, &desc->ptr[5],
 				 sg_count, areq->assoclen, tbl_off, elen,
-				 is_ipsec_esp && !encrypt);
+				 is_ipsec_esp && !encrypt, 1);
 	tbl_off += ret;
 
 	if (!encrypt && is_ipsec_esp) {
@@ -1583,6 +1585,8 @@
 	bool sync_needed = false;
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	bool is_sec1 = has_ftr_sec1(priv);
+	bool is_ctr = (desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AESU &&
+		      (desc->hdr & DESC_HDR_MODE0_AESU_MASK) == DESC_HDR_MODE0_AESU_CTR;
 
 	/* first DWORD empty */
 
@@ -1603,8 +1607,8 @@
 	/*
 	 * cipher in
 	 */
-	sg_count = talitos_sg_map(dev, areq->src, cryptlen, edesc,
-				  &desc->ptr[3], sg_count, 0, 0);
+	sg_count = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[3],
+				      sg_count, 0, 0, 0, false, is_ctr ? 16 : 1);
 	if (sg_count > 1)
 		sync_needed = true;
 
--- linux-ein-5.4.0.orig/drivers/crypto/talitos.h
+++ linux-ein-5.4.0/drivers/crypto/talitos.h
@@ -344,6 +344,7 @@
 
 /* primary execution unit mode (MODE0) and derivatives */
 #define	DESC_HDR_MODE0_ENCRYPT		cpu_to_be32(0x00100000)
+#define	DESC_HDR_MODE0_AESU_MASK	cpu_to_be32(0x00600000)
 #define	DESC_HDR_MODE0_AESU_CBC		cpu_to_be32(0x00200000)
 #define	DESC_HDR_MODE0_AESU_CTR		cpu_to_be32(0x00600000)
 #define	DESC_HDR_MODE0_DEU_CBC		cpu_to_be32(0x00400000)
--- linux-ein-5.4.0.orig/drivers/crypto/ux500/hash/hash_core.c
+++ linux-ein-5.4.0/drivers/crypto/ux500/hash/hash_core.c
@@ -1009,6 +1009,7 @@
 			goto out;
 		}
 	} else if (req->nbytes == 0 && ctx->keylen > 0) {
+		ret = -EPERM;
 		dev_err(device_data->dev, "%s: Empty message with keylength > 0, NOT supported\n",
 			__func__);
 		goto out;
--- linux-ein-5.4.0.orig/drivers/crypto/virtio/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/virtio/Kconfig
@@ -5,7 +5,6 @@
 	select CRYPTO_AEAD
 	select CRYPTO_BLKCIPHER
 	select CRYPTO_ENGINE
-	default m
 	help
 	  This driver provides support for virtio crypto device. If you
 	  choose 'M' here, this module will be called virtio_crypto.
--- linux-ein-5.4.0.orig/drivers/crypto/virtio/virtio_crypto_algs.c
+++ linux-ein-5.4.0/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -105,8 +105,6 @@
 		*alg = VIRTIO_CRYPTO_CIPHER_AES_CBC;
 		break;
 	default:
-		pr_err("virtio_crypto: Unsupported key length: %d\n",
-			key_len);
 		return -EINVAL;
 	}
 	return 0;
@@ -355,13 +353,18 @@
 	int err;
 	unsigned long flags;
 	struct scatterlist outhdr, iv_sg, status_sg, **sgs;
-	int i;
 	u64 dst_len;
 	unsigned int num_out = 0, num_in = 0;
 	int sg_total;
 	uint8_t *iv;
+	struct scatterlist *sg;
 
 	src_nents = sg_nents_for_len(req->src, req->nbytes);
+	if (src_nents < 0) {
+		pr_err("Invalid number of src SG.\n");
+		return src_nents;
+	}
+
 	dst_nents = sg_nents(req->dst);
 
 	pr_debug("virtio_crypto: Number of sgs (src_nents: %d, dst_nents: %d)\n",
@@ -407,6 +410,7 @@
 		goto free;
 	}
 
+	dst_len = min_t(unsigned int, req->nbytes, dst_len);
 	pr_debug("virtio_crypto: src_len: %u, dst_len: %llu\n",
 			req->nbytes, dst_len);
 
@@ -437,17 +441,22 @@
 		goto free;
 	}
 	memcpy(iv, req->info, ivsize);
+	if (!vc_sym_req->encrypt)
+		scatterwalk_map_and_copy(req->info, req->src,
+					 req->nbytes - AES_BLOCK_SIZE,
+					 AES_BLOCK_SIZE, 0);
+
 	sg_init_one(&iv_sg, iv, ivsize);
 	sgs[num_out++] = &iv_sg;
 	vc_sym_req->iv = iv;
 
 	/* Source data */
-	for (i = 0; i < src_nents; i++)
-		sgs[num_out++] = &req->src[i];
+	for (sg = req->src; src_nents; sg = sg_next(sg), src_nents--)
+		sgs[num_out++] = sg;
 
 	/* Destination data */
-	for (i = 0; i < dst_nents; i++)
-		sgs[num_out + num_in++] = &req->dst[i];
+	for (sg = req->dst; sg; sg = sg_next(sg))
+		sgs[num_out + num_in++] = sg;
 
 	/* Status */
 	sg_init_one(&status_sg, &vc_req->status, sizeof(vc_req->status));
@@ -484,6 +493,11 @@
 	/* Use the first data virtqueue as default */
 	struct data_queue *data_vq = &vcrypto->data_vq[0];
 
+	if (!req->nbytes)
+		return 0;
+	if (req->nbytes % AES_BLOCK_SIZE)
+		return -EINVAL;
+
 	vc_req->dataq = data_vq;
 	vc_req->alg_cb = virtio_crypto_dataq_sym_callback;
 	vc_sym_req->ablkcipher_ctx = ctx;
@@ -504,6 +518,11 @@
 	/* Use the first data virtqueue as default */
 	struct data_queue *data_vq = &vcrypto->data_vq[0];
 
+	if (!req->nbytes)
+		return 0;
+	if (req->nbytes % AES_BLOCK_SIZE)
+		return -EINVAL;
+
 	vc_req->dataq = data_vq;
 	vc_req->alg_cb = virtio_crypto_dataq_sym_callback;
 	vc_sym_req->ablkcipher_ctx = ctx;
@@ -563,10 +582,15 @@
 	struct ablkcipher_request *req,
 	int err)
 {
-	crypto_finalize_ablkcipher_request(vc_sym_req->base.dataq->engine,
-					   req, err);
+	if (vc_sym_req->encrypt)
+		scatterwalk_map_and_copy(req->info, req->dst,
+					 req->nbytes - AES_BLOCK_SIZE,
+					 AES_BLOCK_SIZE, 0);
 	kzfree(vc_sym_req->iv);
 	virtcrypto_clear_request(&vc_sym_req->base);
+
+	crypto_finalize_ablkcipher_request(vc_sym_req->base.dataq->engine,
+					   req, err);
 }
 
 static struct virtio_crypto_algo virtio_crypto_algs[] = { {
--- linux-ein-5.4.0.orig/drivers/crypto/virtio/virtio_crypto_common.h
+++ linux-ein-5.4.0/drivers/crypto/virtio/virtio_crypto_common.h
@@ -10,6 +10,7 @@
 #include <linux/virtio.h>
 #include <linux/crypto.h>
 #include <linux/spinlock.h>
+#include <linux/interrupt.h>
 #include <crypto/aead.h>
 #include <crypto/aes.h>
 #include <crypto/engine.h>
@@ -27,6 +28,7 @@
 	char name[32];
 
 	struct crypto_engine *engine;
+	struct tasklet_struct done_task;
 };
 
 struct virtio_crypto {
--- linux-ein-5.4.0.orig/drivers/crypto/virtio/virtio_crypto_core.c
+++ linux-ein-5.4.0/drivers/crypto/virtio/virtio_crypto_core.c
@@ -22,27 +22,28 @@
 	}
 }
 
-static void virtcrypto_dataq_callback(struct virtqueue *vq)
+static void virtcrypto_done_task(unsigned long data)
 {
-	struct virtio_crypto *vcrypto = vq->vdev->priv;
+	struct data_queue *data_vq = (struct data_queue *)data;
+	struct virtqueue *vq = data_vq->vq;
 	struct virtio_crypto_request *vc_req;
-	unsigned long flags;
 	unsigned int len;
-	unsigned int qid = vq->index;
 
-	spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags);
 	do {
 		virtqueue_disable_cb(vq);
 		while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) {
-			spin_unlock_irqrestore(
-				&vcrypto->data_vq[qid].lock, flags);
 			if (vc_req->alg_cb)
 				vc_req->alg_cb(vc_req, len);
-			spin_lock_irqsave(
-				&vcrypto->data_vq[qid].lock, flags);
 		}
 	} while (!virtqueue_enable_cb(vq));
-	spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags);
+}
+
+static void virtcrypto_dataq_callback(struct virtqueue *vq)
+{
+	struct virtio_crypto *vcrypto = vq->vdev->priv;
+	struct data_queue *dq = &vcrypto->data_vq[vq->index];
+
+	tasklet_schedule(&dq->done_task);
 }
 
 static int virtcrypto_find_vqs(struct virtio_crypto *vi)
@@ -99,6 +100,8 @@
 			ret = -ENOMEM;
 			goto err_engine;
 		}
+		tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task,
+				(unsigned long)&vi->data_vq[i]);
 	}
 
 	kfree(names);
@@ -431,11 +434,14 @@
 static void virtcrypto_remove(struct virtio_device *vdev)
 {
 	struct virtio_crypto *vcrypto = vdev->priv;
+	int i;
 
 	dev_info(&vdev->dev, "Start virtcrypto_remove.\n");
 
 	if (virtcrypto_dev_started(vcrypto))
 		virtcrypto_dev_stop(vcrypto);
+	for (i = 0; i < vcrypto->max_data_queues; i++)
+		tasklet_kill(&vcrypto->data_vq[i].done_task);
 	vdev->config->reset(vdev);
 	virtcrypto_free_unused_reqs(vcrypto);
 	virtcrypto_clear_crypto_engines(vcrypto);
--- linux-ein-5.4.0.orig/drivers/crypto/vmx/Kconfig
+++ linux-ein-5.4.0/drivers/crypto/vmx/Kconfig
@@ -2,7 +2,11 @@
 config CRYPTO_DEV_VMX_ENCRYPT
 	tristate "Encryption acceleration support on P8 CPU"
 	depends on CRYPTO_DEV_VMX
+	select CRYPTO_AES
+	select CRYPTO_CBC
+	select CRYPTO_CTR
 	select CRYPTO_GHASH
+	select CRYPTO_XTS
 	default m
 	help
 	  Support for VMX cryptographic acceleration instructions on Power8 CPU.
--- linux-ein-5.4.0.orig/drivers/crypto/vmx/Makefile
+++ linux-ein-5.4.0/drivers/crypto/vmx/Makefile
@@ -3,13 +3,13 @@
 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) > $(@)
 
 targets += aesp8-ppc.S ghashp8-ppc.S
 
--- linux-ein-5.4.0.orig/drivers/crypto/vmx/aes_xts.c
+++ linux-ein-5.4.0/drivers/crypto/vmx/aes_xts.c
@@ -84,6 +84,9 @@
 	u8 tweak[AES_BLOCK_SIZE];
 	int ret;
 
+	if (req->cryptlen < AES_BLOCK_SIZE)
+		return -EINVAL;
+
 	if (!crypto_simd_usable() || (req->cryptlen % XTS_BLOCK_SIZE) != 0) {
 		struct skcipher_request *subreq = skcipher_request_ctx(req);
 
--- linux-ein-5.4.0.orig/drivers/dax/bus.c
+++ linux-ein-5.4.0/drivers/dax/bus.c
@@ -227,7 +227,7 @@
 
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
 		struct resource *res, int target_node, unsigned int align,
-		unsigned long pfn_flags)
+		unsigned long long pfn_flags)
 {
 	struct dax_region *dax_region;
 
--- linux-ein-5.4.0.orig/drivers/dax/bus.h
+++ linux-ein-5.4.0/drivers/dax/bus.h
@@ -11,7 +11,7 @@
 void dax_region_put(struct dax_region *dax_region);
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
 		struct resource *res, int target_node, unsigned int align,
-		unsigned long flags);
+		unsigned long long flags);
 
 enum dev_dax_subsys {
 	DEV_DAX_BUS,
--- linux-ein-5.4.0.orig/drivers/dax/dax-private.h
+++ linux-ein-5.4.0/drivers/dax/dax-private.h
@@ -32,7 +32,7 @@
 	struct device *dev;
 	unsigned int align;
 	struct resource res;
-	unsigned long pfn_flags;
+	unsigned long long pfn_flags;
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/dax/kmem.c
+++ linux-ein-5.4.0/drivers/dax/kmem.c
@@ -22,6 +22,7 @@
 	resource_size_t kmem_size;
 	resource_size_t kmem_end;
 	struct resource *new_res;
+	const char *new_res_name;
 	int numa_node;
 	int rc;
 
@@ -48,11 +49,16 @@
 	kmem_size &= ~(memory_block_size_bytes() - 1);
 	kmem_end = kmem_start + kmem_size;
 
-	/* Region is permanently reserved.  Hot-remove not yet implemented. */
-	new_res = request_mem_region(kmem_start, kmem_size, dev_name(dev));
+	new_res_name = kstrdup(dev_name(dev), GFP_KERNEL);
+	if (!new_res_name)
+		return -ENOMEM;
+
+	/* Region is permanently reserved if hotremove fails. */
+	new_res = request_mem_region(kmem_start, kmem_size, new_res_name);
 	if (!new_res) {
 		dev_warn(dev, "could not reserve region [%pa-%pa]\n",
 			 &kmem_start, &kmem_end);
+		kfree(new_res_name);
 		return -EBUSY;
 	}
 
@@ -63,12 +69,12 @@
 	 * unknown to us that will break add_memory() below.
 	 */
 	new_res->flags = IORESOURCE_SYSTEM_RAM;
-	new_res->name = dev_name(dev);
 
 	rc = add_memory(numa_node, new_res->start, resource_size(new_res));
 	if (rc) {
 		release_resource(new_res);
 		kfree(new_res);
+		kfree(new_res_name);
 		return rc;
 	}
 	dev_dax->dax_kmem_res = new_res;
@@ -83,6 +89,7 @@
 	struct resource *res = dev_dax->dax_kmem_res;
 	resource_size_t kmem_start = res->start;
 	resource_size_t kmem_size = resource_size(res);
+	const char *res_name = res->name;
 	int rc;
 
 	/*
@@ -102,6 +109,7 @@
 	/* Release and free dax resources */
 	release_resource(res);
 	kfree(res);
+	kfree(res_name);
 	dev_dax->dax_kmem_res = NULL;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/dax/super.c
+++ linux-ein-5.4.0/drivers/dax/super.c
@@ -318,11 +318,15 @@
 bool dax_supported(struct dax_device *dax_dev, struct block_device *bdev,
 		int blocksize, sector_t start, sector_t len)
 {
+	if (!dax_dev)
+		return false;
+
 	if (!dax_alive(dax_dev))
 		return false;
 
 	return dax_dev->ops->dax_supported(dax_dev, bdev, blocksize, start, len);
 }
+EXPORT_SYMBOL_GPL(dax_supported);
 
 size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
 		size_t bytes, struct iov_iter *i)
@@ -687,6 +691,7 @@
 static void dax_fs_exit(void)
 {
 	kern_unmount(dax_mnt);
+	rcu_barrier();
 	kmem_cache_destroy(dax_cache);
 }
 
@@ -716,6 +721,7 @@
 
 static void __exit dax_core_exit(void)
 {
+	dax_bus_exit();
 	unregister_chrdev_region(dax_devt, MINORMASK+1);
 	ida_destroy(&dax_minor_ida);
 	dax_fs_exit();
--- linux-ein-5.4.0.orig/drivers/devfreq/Kconfig
+++ linux-ein-5.4.0/drivers/devfreq/Kconfig
@@ -99,6 +99,7 @@
 		ARCH_TEGRA_210_SOC || \
 		COMPILE_TEST
 	select PM_OPP
+	depends on COMMON_CLK
 	help
 	  This adds the DEVFREQ driver for the Tegra family of SoCs.
 	  It reads ACTMON counters of memory controllers and adjusts the
@@ -117,7 +118,8 @@
 
 config ARM_RK3399_DMC_DEVFREQ
 	tristate "ARM RK3399 DMC DEVFREQ Driver"
-	depends on ARCH_ROCKCHIP
+	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
+		(COMPILE_TEST && HAVE_ARM_SMCCC)
 	select DEVFREQ_EVENT_ROCKCHIP_DFI
 	select DEVFREQ_GOV_SIMPLE_ONDEMAND
 	select PM_DEVFREQ_EVENT
--- linux-ein-5.4.0.orig/drivers/devfreq/devfreq.c
+++ linux-ein-5.4.0/drivers/devfreq/devfreq.c
@@ -160,6 +160,7 @@
 	int lev, prev_lev, ret = 0;
 	unsigned long cur_time;
 
+	lockdep_assert_held(&devfreq->lock);
 	cur_time = jiffies;
 
 	/* Immediately exit if previous_freq is not initialized yet. */
@@ -318,7 +319,7 @@
 	devfreq->previous_freq = new_freq;
 
 	if (devfreq->suspend_freq)
-		devfreq->resume_freq = cur_freq;
+		devfreq->resume_freq = new_freq;
 
 	return err;
 }
@@ -550,26 +551,30 @@
 				 void *devp)
 {
 	struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
-	int ret;
+	int err = -EINVAL;
 
 	mutex_lock(&devfreq->lock);
 
 	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
-	if (!devfreq->scaling_min_freq) {
-		mutex_unlock(&devfreq->lock);
-		return -EINVAL;
-	}
+	if (!devfreq->scaling_min_freq)
+		goto out;
 
 	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
 	if (!devfreq->scaling_max_freq) {
-		mutex_unlock(&devfreq->lock);
-		return -EINVAL;
+		devfreq->scaling_max_freq = ULONG_MAX;
+		goto out;
 	}
 
-	ret = update_devfreq(devfreq);
+	err = update_devfreq(devfreq);
+
+out:
 	mutex_unlock(&devfreq->lock);
+	if (err)
+		dev_err(devfreq->dev.parent,
+			"failed to update frequency from OPP notifier (%d)\n",
+			err);
 
-	return ret;
+	return NOTIFY_OK;
 }
 
 /**
@@ -583,11 +588,6 @@
 	struct devfreq *devfreq = to_devfreq(dev);
 
 	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);
 
@@ -595,6 +595,7 @@
 		devfreq->profile->exit(devfreq->dev.parent);
 
 	mutex_destroy(&devfreq->lock);
+	srcu_cleanup_notifier_head(&devfreq->transition_notifier_list);
 	kfree(devfreq);
 }
 
@@ -603,8 +604,7 @@
  * @dev:	the device to add devfreq feature.
  * @profile:	device-specific profile to run devfreq.
  * @governor_name:	name of the policy to choose frequency.
- * @data:	private data for the governor. The devfreq framework does not
- *		touch this value.
+ * @data:	devfreq driver pass to governors, governor should not change it.
  */
 struct devfreq *devfreq_add_device(struct device *dev,
 				   struct devfreq_dev_profile *profile,
@@ -613,7 +613,6 @@
 {
 	struct devfreq *devfreq;
 	struct devfreq_governor *governor;
-	static atomic_t devfreq_no = ATOMIC_INIT(-1);
 	int err = 0;
 
 	if (!dev || !profile || !governor_name) {
@@ -642,6 +641,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;
@@ -676,8 +676,7 @@
 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
 	atomic_set(&devfreq->suspend_count, 0);
 
-	dev_set_name(&devfreq->dev, "devfreq%d",
-				atomic_inc_return(&devfreq_no));
+	dev_set_name(&devfreq->dev, "%s", dev_name(dev));
 	err = device_register(&devfreq->dev);
 	if (err) {
 		mutex_unlock(&devfreq->lock);
@@ -789,8 +788,7 @@
  * @dev:	the device to add devfreq feature.
  * @profile:	device-specific profile to run devfreq.
  * @governor_name:	name of the policy to choose frequency.
- * @data:	private data for the governor. The devfreq framework does not
- *		touch this value.
+ * @data:	 devfreq driver pass to governors, governor should not change it.
  *
  * This function manages automatically the memory of devfreq device using device
  * resource management and simplify the free operation for memory of devfreq
@@ -903,7 +901,9 @@
 	}
 
 	if (devfreq->suspend_freq) {
+		mutex_lock(&devfreq->lock);
 		ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
+		mutex_unlock(&devfreq->lock);
 		if (ret)
 			return ret;
 	}
@@ -931,7 +931,9 @@
 		return 0;
 
 	if (devfreq->resume_freq) {
+		mutex_lock(&devfreq->lock);
 		ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
+		mutex_unlock(&devfreq->lock);
 		if (ret)
 			return ret;
 	}
@@ -1111,6 +1113,14 @@
 }
 EXPORT_SYMBOL(devfreq_remove_governor);
 
+static ssize_t name_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct devfreq *devfreq = to_devfreq(dev);
+	return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent));
+}
+static DEVICE_ATTR_RO(name);
+
 static ssize_t governor_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
@@ -1195,7 +1205,7 @@
 	 * The devfreq with immutable governor (e.g., passive) shows
 	 * only own governor.
 	 */
-	if (df->governor->immutable) {
+	if (df->governor && df->governor->immutable) {
 		count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
 				  "%s ", df->governor_name);
 	/*
@@ -1397,12 +1407,17 @@
 	int i, j;
 	unsigned int max_state = devfreq->profile->max_state;
 
-	if (!devfreq->stop_polling &&
-			devfreq_update_status(devfreq, devfreq->previous_freq))
-		return 0;
 	if (max_state == 0)
 		return sprintf(buf, "Not Supported.\n");
 
+	mutex_lock(&devfreq->lock);
+	if (!devfreq->stop_polling &&
+			devfreq_update_status(devfreq, devfreq->previous_freq)) {
+		mutex_unlock(&devfreq->lock);
+		return 0;
+	}
+	mutex_unlock(&devfreq->lock);
+
 	len = sprintf(buf, "     From  :   To\n");
 	len += sprintf(buf + len, "           :");
 	for (i = 0; i < max_state; i++)
@@ -1434,6 +1449,7 @@
 static DEVICE_ATTR_RO(trans_stat);
 
 static struct attribute *devfreq_attrs[] = {
+	&dev_attr_name.attr,
 	&dev_attr_governor.attr,
 	&dev_attr_available_governors.attr,
 	&dev_attr_cur_freq.attr,
--- linux-ein-5.4.0.orig/drivers/devfreq/event/Kconfig
+++ linux-ein-5.4.0/drivers/devfreq/event/Kconfig
@@ -34,7 +34,7 @@
 
 config DEVFREQ_EVENT_ROCKCHIP_DFI
 	tristate "ROCKCHIP DFI DEVFREQ event Driver"
-	depends on ARCH_ROCKCHIP
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
 	help
 	  This add the devfreq-event driver for Rockchip SoC. It provides DFI
 	  (DDR Monitor Module) driver to count ddr load.
--- linux-ein-5.4.0.orig/drivers/devfreq/event/exynos-ppmu.c
+++ linux-ein-5.4.0/drivers/devfreq/event/exynos-ppmu.c
@@ -101,17 +101,22 @@
 	PPMU_EVENT(dmc1_1),
 };
 
-static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
+static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
-		if (!strcmp(edev->desc->name, ppmu_events[i].name))
+		if (!strcmp(edev_name, ppmu_events[i].name))
 			return ppmu_events[i].id;
 
 	return -EINVAL;
 }
 
+static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
+{
+	return __exynos_ppmu_find_ppmu_id(edev->desc->name);
+}
+
 /*
  * The devfreq-event ops structure for PPMU v1.1
  */
@@ -509,15 +514,19 @@
 
 	count = of_get_child_count(events_np);
 	desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
+	if (!desc) {
+		of_node_put(events_np);
 		return -ENOMEM;
+	}
 	info->num_events = count;
 
 	of_id = of_match_device(exynos_ppmu_id_match, dev);
 	if (of_id)
 		info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
-	else
+	else {
+		of_node_put(events_np);
 		return -EINVAL;
+	}
 
 	j = 0;
 	for_each_child_of_node(events_np, node) {
@@ -556,13 +565,11 @@
 			 * use default if not.
 			 */
 			if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
-				struct devfreq_event_dev edev;
 				int id;
 				/* Not all registers take the same value for
 				 * read+write data count.
 				 */
-				edev.desc = &desc[j];
-				id = exynos_ppmu_find_ppmu_id(&edev);
+				id = __exynos_ppmu_find_ppmu_id(desc[j].name);
 
 				switch (id) {
 				case PPMU_PMNCNT0:
--- linux-ein-5.4.0.orig/drivers/devfreq/governor_userspace.c
+++ linux-ein-5.4.0/drivers/devfreq/governor_userspace.c
@@ -21,7 +21,7 @@
 
 static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
 {
-	struct userspace_data *data = df->data;
+	struct userspace_data *data = df->governor_data;
 
 	if (data->valid)
 		*freq = data->user_frequency;
@@ -40,7 +40,7 @@
 	int err = 0;
 
 	mutex_lock(&devfreq->lock);
-	data = devfreq->data;
+	data = devfreq->governor_data;
 
 	sscanf(buf, "%lu", &wanted);
 	data->user_frequency = wanted;
@@ -60,7 +60,7 @@
 	int err = 0;
 
 	mutex_lock(&devfreq->lock);
-	data = devfreq->data;
+	data = devfreq->governor_data;
 
 	if (data->valid)
 		err = sprintf(buf, "%lu\n", data->user_frequency);
@@ -91,7 +91,7 @@
 		goto out;
 	}
 	data->valid = false;
-	devfreq->data = data;
+	devfreq->governor_data = data;
 
 	err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
 out:
@@ -107,8 +107,8 @@
 	if (devfreq->dev.kobj.sd)
 		sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
 
-	kfree(devfreq->data);
-	devfreq->data = NULL;
+	kfree(devfreq->governor_data);
+	devfreq->governor_data = NULL;
 }
 
 static int devfreq_userspace_handler(struct devfreq *devfreq,
--- linux-ein-5.4.0.orig/drivers/devfreq/rk3399_dmc.c
+++ linux-ein-5.4.0/drivers/devfreq/rk3399_dmc.c
@@ -95,18 +95,20 @@
 
 	mutex_lock(&dmcfreq->lock);
 
-	if (target_rate >= dmcfreq->odt_dis_freq)
-		odt_enable = true;
-
-	/*
-	 * This makes a SMC call to the TF-A to set the DDR PD (power-down)
-	 * timings and to enable or disable the ODT (on-die termination)
-	 * resistors.
-	 */
-	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
-		      dmcfreq->odt_pd_arg1,
-		      ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
-		      odt_enable, 0, 0, 0, &res);
+	if (dmcfreq->regmap_pmu) {
+		if (target_rate >= dmcfreq->odt_dis_freq)
+			odt_enable = true;
+
+		/*
+		 * This makes a SMC call to the TF-A to set the DDR PD
+		 * (power-down) timings and to enable or disable the
+		 * ODT (on-die termination) resistors.
+		 */
+		arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
+			      dmcfreq->odt_pd_arg1,
+			      ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
+			      odt_enable, 0, 0, 0, &res);
+	}
 
 	/*
 	 * If frequency scaling from low to high, adjust voltage first.
@@ -364,16 +366,21 @@
 			if (res.a0) {
 				dev_err(dev, "Failed to set dram param: %ld\n",
 					res.a0);
-				return -EINVAL;
+				ret = -EINVAL;
+				goto err_edev;
 			}
 		}
 	}
 
 	node = of_parse_phandle(np, "rockchip,pmu", 0);
-	if (node) {
-		data->regmap_pmu = syscon_node_to_regmap(node);
-		if (IS_ERR(data->regmap_pmu))
-			return PTR_ERR(data->regmap_pmu);
+	if (!node)
+		goto no_pmu;
+
+	data->regmap_pmu = syscon_node_to_regmap(node);
+	of_node_put(node);
+	if (IS_ERR(data->regmap_pmu)) {
+		ret = PTR_ERR(data->regmap_pmu);
+		goto err_edev;
 	}
 
 	regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
@@ -391,9 +398,11 @@
 		data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_edev;
 	};
 
+no_pmu:
 	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
 		      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
 		      0, 0, 0, 0, &res);
@@ -425,7 +434,8 @@
 	 */
 	if (dev_pm_opp_of_add_table(dev)) {
 		dev_err(dev, "Invalid operating-points in device tree.\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_edev;
 	}
 
 	of_property_read_u32(np, "upthreshold",
@@ -465,6 +475,9 @@
 
 err_free_opp:
 	dev_pm_opp_of_remove_table(&pdev->dev);
+err_edev:
+	devfreq_event_disable_edev(data->edev);
+
 	return ret;
 }
 
@@ -472,6 +485,8 @@
 {
 	struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(&pdev->dev);
 
+	devfreq_event_disable_edev(dmcfreq->edev);
+
 	/*
 	 * Before remove the opp table we need to unregister the opp notifier.
 	 */
--- linux-ein-5.4.0.orig/drivers/devfreq/tegra30-devfreq.c
+++ linux-ein-5.4.0/drivers/devfreq/tegra30-devfreq.c
@@ -68,6 +68,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
 
@@ -169,7 +171,7 @@
 };
 
 static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = {
-	{ 1400000, ULONG_MAX },
+	{ 1400000,    KHZ_MAX },
 	{ 1200000,    750000 },
 	{ 1100000,    600000 },
 	{ 1000000,    500000 },
--- linux-ein-5.4.0.orig/drivers/dio/dio.c
+++ linux-ein-5.4.0/drivers/dio/dio.c
@@ -110,6 +110,12 @@
 
 #endif /* CONFIG_DIO_CONSTANTS */
 
+static void dio_dev_release(struct device *dev)
+{
+	struct dio_dev *ddev = container_of(dev, typeof(struct dio_dev), dev);
+	kfree(ddev);
+}
+
 int __init dio_find(int deviceid)
 {
 	/* Called to find a DIO device before the full bus scan has run.
@@ -222,6 +228,7 @@
 		dev->bus = &dio_bus;
 		dev->dev.parent = &dio_bus.dev;
 		dev->dev.bus = &dio_bus_type;
+		dev->dev.release = dio_dev_release;
 		dev->scode = scode;
 		dev->resource.start = pa;
 		dev->resource.end = pa + DIO_SIZE(scode, va);
@@ -249,6 +256,7 @@
 		if (error) {
 			pr_err("DIO: Error registering device %s\n",
 			       dev->name);
+			put_device(&dev->dev);
 			continue;
 		}
 		error = dio_create_sysfs_dev_files(dev);
--- linux-ein-5.4.0.orig/drivers/dma-buf/dma-buf.c
+++ linux-ein-5.4.0/drivers/dma-buf/dma-buf.c
@@ -25,6 +25,7 @@
 #include <linux/mm.h>
 #include <linux/mount.h>
 #include <linux/pseudo_fs.h>
+#include <linux/device.h>
 
 #include <uapi/linux/dma-buf.h>
 #include <uapi/linux/magic.h>
@@ -45,46 +46,22 @@
 	size_t ret = 0;
 
 	dmabuf = dentry->d_fsdata;
-	mutex_lock(&dmabuf->lock);
+	spin_lock(&dmabuf->name_lock);
 	if (dmabuf->name)
 		ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
-	mutex_unlock(&dmabuf->lock);
+	spin_unlock(&dmabuf->name_lock);
 
 	return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
 			     dentry->d_name.name, ret > 0 ? name : "");
 }
 
-static const struct dentry_operations dma_buf_dentry_ops = {
-	.d_dname = dmabuffs_dname,
-};
-
-static struct vfsmount *dma_buf_mnt;
-
-static int dma_buf_fs_init_context(struct fs_context *fc)
-{
-	struct pseudo_fs_context *ctx;
-
-	ctx = init_pseudo(fc, DMA_BUF_MAGIC);
-	if (!ctx)
-		return -ENOMEM;
-	ctx->dops = &dma_buf_dentry_ops;
-	return 0;
-}
-
-static struct file_system_type dma_buf_fs_type = {
-	.name = "dmabuf",
-	.init_fs_context = dma_buf_fs_init_context,
-	.kill_sb = kill_anon_super,
-};
-
-static int dma_buf_release(struct inode *inode, struct file *file)
+static void dma_buf_release(struct dentry *dentry)
 {
 	struct dma_buf *dmabuf;
 
-	if (!is_dma_buf_file(file))
-		return -EINVAL;
-
-	dmabuf = file->private_data;
+	dmabuf = dentry->d_fsdata;
+	if (unlikely(!dmabuf))
+		return;
 
 	BUG_ON(dmabuf->vmapping_counter);
 
@@ -100,18 +77,55 @@
 
 	dmabuf->ops->release(dmabuf);
 
-	mutex_lock(&db_list.lock);
-	list_del(&dmabuf->list_node);
-	mutex_unlock(&db_list.lock);
-
 	if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
 		dma_resv_fini(dmabuf->resv);
 
+	WARN_ON(!list_empty(&dmabuf->attachments));
 	module_put(dmabuf->owner);
+	kfree(dmabuf->name);
 	kfree(dmabuf);
+}
+
+static int dma_buf_file_release(struct inode *inode, struct file *file)
+{
+	struct dma_buf *dmabuf;
+
+	if (!is_dma_buf_file(file))
+		return -EINVAL;
+
+	dmabuf = file->private_data;
+
+	mutex_lock(&db_list.lock);
+	list_del(&dmabuf->list_node);
+	mutex_unlock(&db_list.lock);
+
+	return 0;
+}
+
+static const struct dentry_operations dma_buf_dentry_ops = {
+	.d_dname = dmabuffs_dname,
+	.d_release = dma_buf_release,
+};
+
+static struct vfsmount *dma_buf_mnt;
+
+static int dma_buf_fs_init_context(struct fs_context *fc)
+{
+	struct pseudo_fs_context *ctx;
+
+	ctx = init_pseudo(fc, DMA_BUF_MAGIC);
+	if (!ctx)
+		return -ENOMEM;
+	ctx->dops = &dma_buf_dentry_ops;
 	return 0;
 }
 
+static struct file_system_type dma_buf_fs_type = {
+	.name = "dmabuf",
+	.init_fs_context = dma_buf_fs_init_context,
+	.kill_sb = kill_anon_super,
+};
+
 static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
 {
 	struct dma_buf *dmabuf;
@@ -340,8 +354,10 @@
 		kfree(name);
 		goto out_unlock;
 	}
+	spin_lock(&dmabuf->name_lock);
 	kfree(dmabuf->name);
 	dmabuf->name = name;
+	spin_unlock(&dmabuf->name_lock);
 
 out_unlock:
 	mutex_unlock(&dmabuf->lock);
@@ -359,6 +375,36 @@
 	dmabuf = file->private_data;
 
 	switch (cmd) {
+	case DMA_BUF_IOCTL_PHYS: {
+		struct dma_buf_attachment *attachment = NULL;
+		struct sg_table *sgt = NULL;
+		unsigned long phys = 0;
+		struct device dev;
+
+		if (!dmabuf || IS_ERR(dmabuf)) {
+			return -EFAULT;
+		}
+		memset(&dev, 0, sizeof(dev));
+		device_initialize(&dev);
+		dev.coherent_dma_mask = DMA_BIT_MASK(64);
+		dev.dma_mask = &dev.coherent_dma_mask;
+		arch_setup_dma_ops(&dev, 0, 0, NULL, false);
+		attachment = dma_buf_attach(dmabuf, &dev);
+		if (!attachment || IS_ERR(attachment)) {
+			return -EFAULT;
+		}
+
+		sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+		if (sgt && !IS_ERR(sgt)) {
+			phys = sg_dma_address(sgt->sgl);
+			dma_buf_unmap_attachment(attachment, sgt,
+					DMA_BIDIRECTIONAL);
+		}
+		dma_buf_detach(dmabuf, attachment);
+		if (copy_to_user((void __user *) arg, &phys, sizeof(phys)))
+			return -EFAULT;
+		return 0;
+	}
 	case DMA_BUF_IOCTL_SYNC:
 		if (copy_from_user(&sync, (void __user *) arg, sizeof(sync)))
 			return -EFAULT;
@@ -387,7 +433,8 @@
 
 		return ret;
 
-	case DMA_BUF_SET_NAME:
+	case DMA_BUF_SET_NAME_A:
+	case DMA_BUF_SET_NAME_B:
 		return dma_buf_set_name(dmabuf, (const char __user *)arg);
 
 	default:
@@ -403,14 +450,14 @@
 	/* Don't count the temporary reference taken inside procfs seq_show */
 	seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1);
 	seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name);
-	mutex_lock(&dmabuf->lock);
+	spin_lock(&dmabuf->name_lock);
 	if (dmabuf->name)
 		seq_printf(m, "name:\t%s\n", dmabuf->name);
-	mutex_unlock(&dmabuf->lock);
+	spin_unlock(&dmabuf->name_lock);
 }
 
 static const struct file_operations dma_buf_fops = {
-	.release	= dma_buf_release,
+	.release	= dma_buf_file_release,
 	.mmap		= dma_buf_mmap_internal,
 	.llseek		= dma_buf_llseek,
 	.poll		= dma_buf_poll,
@@ -539,6 +586,7 @@
 	dmabuf->size = exp_info->size;
 	dmabuf->exp_name = exp_info->exp_name;
 	dmabuf->owner = exp_info->owner;
+	spin_lock_init(&dmabuf->name_lock);
 	init_waitqueue_head(&dmabuf->poll);
 	dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
 	dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
--- linux-ein-5.4.0.orig/drivers/dma-buf/dma-fence-array.c
+++ linux-ein-5.4.0/drivers/dma-buf/dma-fence-array.c
@@ -104,7 +104,11 @@
 {
 	struct dma_fence_array *array = to_dma_fence_array(fence);
 
-	return atomic_read(&array->num_pending) <= 0;
+	if (atomic_read(&array->num_pending) > 0)
+		return false;
+
+	dma_fence_array_clear_pending_error(array);
+	return true;
 }
 
 static void dma_fence_array_release(struct dma_fence *fence)
--- linux-ein-5.4.0.orig/drivers/dma-buf/dma-fence.c
+++ linux-ein-5.4.0/drivers/dma-buf/dma-fence.c
@@ -273,6 +273,30 @@
 }
 EXPORT_SYMBOL(dma_fence_free);
 
+static bool __dma_fence_enable_signaling(struct dma_fence *fence)
+{
+	bool was_set;
+
+	lockdep_assert_held(fence->lock);
+
+	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
+				   &fence->flags);
+
+	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
+		return false;
+
+	if (!was_set && fence->ops->enable_signaling) {
+		trace_dma_fence_enable_signal(fence);
+
+		if (!fence->ops->enable_signaling(fence)) {
+			dma_fence_signal_locked(fence);
+			return false;
+		}
+	}
+
+	return true;
+}
+
 /**
  * dma_fence_enable_sw_signaling - enable signaling on fence
  * @fence: the fence to enable
@@ -285,19 +309,12 @@
 {
 	unsigned long flags;
 
-	if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
-			      &fence->flags) &&
-	    !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
-	    fence->ops->enable_signaling) {
-		trace_dma_fence_enable_signal(fence);
-
-		spin_lock_irqsave(fence->lock, flags);
-
-		if (!fence->ops->enable_signaling(fence))
-			dma_fence_signal_locked(fence);
+	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
+		return;
 
-		spin_unlock_irqrestore(fence->lock, flags);
-	}
+	spin_lock_irqsave(fence->lock, flags);
+	__dma_fence_enable_signaling(fence);
+	spin_unlock_irqrestore(fence->lock, flags);
 }
 EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
 
@@ -331,7 +348,6 @@
 {
 	unsigned long flags;
 	int ret = 0;
-	bool was_set;
 
 	if (WARN_ON(!fence || !func))
 		return -EINVAL;
@@ -343,25 +359,14 @@
 
 	spin_lock_irqsave(fence->lock, flags);
 
-	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
-				   &fence->flags);
-
-	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
-		ret = -ENOENT;
-	else if (!was_set && fence->ops->enable_signaling) {
-		trace_dma_fence_enable_signal(fence);
-
-		if (!fence->ops->enable_signaling(fence)) {
-			dma_fence_signal_locked(fence);
-			ret = -ENOENT;
-		}
-	}
-
-	if (!ret) {
+	if (__dma_fence_enable_signaling(fence)) {
 		cb->func = func;
 		list_add_tail(&cb->node, &fence->cb_list);
-	} else
+	} else {
 		INIT_LIST_HEAD(&cb->node);
+		ret = -ENOENT;
+	}
+
 	spin_unlock_irqrestore(fence->lock, flags);
 
 	return ret;
@@ -461,7 +466,6 @@
 	struct default_wait_cb cb;
 	unsigned long flags;
 	signed long ret = timeout ? timeout : 1;
-	bool was_set;
 
 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
 		return ret;
@@ -473,21 +477,9 @@
 		goto out;
 	}
 
-	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
-				   &fence->flags);
-
-	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
+	if (!__dma_fence_enable_signaling(fence))
 		goto out;
 
-	if (!was_set && fence->ops->enable_signaling) {
-		trace_dma_fence_enable_signal(fence);
-
-		if (!fence->ops->enable_signaling(fence)) {
-			dma_fence_signal_locked(fence);
-			goto out;
-		}
-	}
-
 	if (!timeout) {
 		ret = 0;
 		goto out;
--- linux-ein-5.4.0.orig/drivers/dma-buf/dma-resv.c
+++ linux-ein-5.4.0/drivers/dma-buf/dma-resv.c
@@ -161,7 +161,7 @@
 			max = max(old->shared_count + num_fences,
 				  old->shared_max * 2);
 	} else {
-		max = 4;
+		max = max(4ul, roundup_pow_of_two(num_fences));
 	}
 
 	new = dma_resv_list_alloc(max);
--- linux-ein-5.4.0.orig/drivers/dma-buf/sw_sync.c
+++ linux-ein-5.4.0/drivers/dma-buf/sw_sync.c
@@ -191,6 +191,7 @@
  */
 static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
 {
+	LIST_HEAD(signalled);
 	struct sync_pt *pt, *next;
 
 	trace_sync_timeline(obj);
@@ -203,21 +204,20 @@
 		if (!timeline_fence_signaled(&pt->base))
 			break;
 
-		list_del_init(&pt->link);
+		dma_fence_get(&pt->base);
+
+		list_move_tail(&pt->link, &signalled);
 		rb_erase(&pt->node, &obj->pt_tree);
 
-		/*
-		 * A signal callback may release the last reference to this
-		 * fence, causing it to be freed. That operation has to be
-		 * last to avoid a use after free inside this loop, and must
-		 * be after we remove the fence from the timeline in order to
-		 * prevent deadlocking on timeline->lock inside
-		 * timeline_fence_release().
-		 */
 		dma_fence_signal_locked(&pt->base);
 	}
 
 	spin_unlock_irq(&obj->lock);
+
+	list_for_each_entry_safe(pt, next, &signalled, link) {
+		list_del_init(&pt->link);
+		dma_fence_put(&pt->base);
+	}
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/dma-buf/sync_file.c
+++ linux-ein-5.4.0/drivers/dma-buf/sync_file.c
@@ -211,8 +211,8 @@
 					 struct sync_file *b)
 {
 	struct sync_file *sync_file;
-	struct dma_fence **fences, **nfences, **a_fences, **b_fences;
-	int i, i_a, i_b, num_fences, a_num_fences, b_num_fences;
+	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
+	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
 
 	sync_file = sync_file_alloc();
 	if (!sync_file)
@@ -221,7 +221,7 @@
 	a_fences = get_fences(a, &a_num_fences);
 	b_fences = get_fences(b, &b_num_fences);
 	if (a_num_fences > INT_MAX - b_num_fences)
-		return NULL;
+		goto err;
 
 	num_fences = a_num_fences + b_num_fences;
 
@@ -236,7 +236,7 @@
 	 * If a sync_file can only be created with sync_file_merge
 	 * and sync_file_create, this is a reasonable assumption.
 	 */
-	for (i = i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
+	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
 		struct dma_fence *pt_a = a_fences[i_a];
 		struct dma_fence *pt_b = b_fences[i_b];
 
@@ -278,15 +278,16 @@
 		fences = nfences;
 	}
 
-	if (sync_file_set_fence(sync_file, fences, i) < 0) {
-		kfree(fences);
+	if (sync_file_set_fence(sync_file, fences, i) < 0)
 		goto err;
-	}
 
 	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
 	return sync_file;
 
 err:
+	while (i)
+		dma_fence_put(fences[--i]);
+	kfree(fences);
 	fput(sync_file->file);
 	return NULL;
 
--- linux-ein-5.4.0.orig/drivers/dma-buf/udmabuf.c
+++ linux-ein-5.4.0/drivers/dma-buf/udmabuf.c
@@ -24,8 +24,11 @@
 {
 	struct vm_area_struct *vma = vmf->vma;
 	struct udmabuf *ubuf = vma->vm_private_data;
+	pgoff_t pgoff = vmf->pgoff;
 
-	vmf->page = ubuf->pages[vmf->pgoff];
+	if (pgoff >= ubuf->pagecount)
+		return VM_FAULT_SIGBUS;
+	vmf->page = ubuf->pages[pgoff];
 	get_page(vmf->page);
 	return 0;
 }
@@ -145,6 +148,10 @@
 		if (ubuf->pagecount > pglimit)
 			goto err;
 	}
+
+	if (!ubuf->pagecount)
+		goto err;
+
 	ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages),
 				    GFP_KERNEL);
 	if (!ubuf->pages) {
@@ -280,7 +287,23 @@
 
 static int __init udmabuf_dev_init(void)
 {
-	return misc_register(&udmabuf_misc);
+	int ret;
+
+	ret = misc_register(&udmabuf_misc);
+	if (ret < 0) {
+		pr_err("Could not initialize udmabuf device\n");
+		return ret;
+	}
+
+	ret = dma_coerce_mask_and_coherent(udmabuf_misc.this_device,
+					   DMA_BIT_MASK(64));
+	if (ret < 0) {
+		pr_err("Could not setup DMA mask for udmabuf device\n");
+		misc_deregister(&udmabuf_misc);
+		return ret;
+	}
+
+	return 0;
 }
 
 static void __exit udmabuf_dev_exit(void)
--- linux-ein-5.4.0.orig/drivers/dma/Kconfig
+++ linux-ein-5.4.0/drivers/dma/Kconfig
@@ -59,6 +59,7 @@
 #devices
 config ALTERA_MSGDMA
 	tristate "Altera / Intel mSGDMA Engine"
+	depends on HAS_IOMEM
 	select DMA_ENGINE
 	help
 	  Enable support for Altera / Intel mSGDMA controller.
@@ -207,6 +208,7 @@
 config FSL_EDMA
 	tristate "Freescale eDMA engine support"
 	depends on OF
+	depends on HAS_IOMEM
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 	help
@@ -239,6 +241,14 @@
           the capability to offload memcpy, xor and pq computation
 	  for raid5/6.
 
+config HISI_DMA
+	tristate "HiSilicon DMA Engine support"
+	depends on ARM64 || (COMPILE_TEST && PCI_MSI)
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Support HiSilicon Kunpeng DMA engine.
+
 config IMG_MDC_DMA
 	tristate "IMG MDC support"
 	depends on MIPS || COMPILE_TEST
@@ -267,6 +277,7 @@
 
 config INTEL_IDMA64
 	tristate "Intel integrated DMA 64-bit support"
+	depends on HAS_IOMEM
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 	help
@@ -275,7 +286,7 @@
 
 config INTEL_IOATDMA
 	tristate "Intel I/OAT DMA support"
-	depends on PCI && X86_64
+	depends on PCI && X86_64 && !UML
 	select DMA_ENGINE
 	select DMA_ENGINE_RAID
 	select DCA
--- linux-ein-5.4.0.orig/drivers/dma/Makefile
+++ linux-ein-5.4.0/drivers/dma/Makefile
@@ -35,6 +35,7 @@
 obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
 obj-$(CONFIG_FSL_QDMA) += fsl-qdma.o
 obj-$(CONFIG_FSL_RAID) += fsl_raid.o
+obj-$(CONFIG_HISI_DMA) += hisi_dma.o
 obj-$(CONFIG_HSU_DMA) += hsu/
 obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
 obj-$(CONFIG_IMX_DMA) += imx-dma.o
--- linux-ein-5.4.0.orig/drivers/dma/acpi-dma.c
+++ linux-ein-5.4.0/drivers/dma/acpi-dma.c
@@ -70,10 +70,14 @@
 
 	si = (const struct acpi_csrt_shared_info *)&grp[1];
 
-	/* Match device by MMIO and IRQ */
+	/* Match device by MMIO */
 	if (si->mmio_base_low != lower_32_bits(mem) ||
-	    si->mmio_base_high != upper_32_bits(mem) ||
-	    si->gsi_interrupt != irq)
+	    si->mmio_base_high != upper_32_bits(mem))
+		return 0;
+
+	/* Match device by Linux vIRQ */
+	ret = acpi_register_gsi(NULL, si->gsi_interrupt, si->interrupt_mode, si->interrupt_polarity);
+	if (ret != irq)
 		return 0;
 
 	dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
@@ -135,11 +139,13 @@
 		if (ret < 0) {
 			dev_warn(&adev->dev,
 				 "error in parsing resource group\n");
-			return;
+			break;
 		}
 
 		grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
 	}
+
+	acpi_put_table((struct acpi_table_header *)csrt);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/dma/at_hdmac.c
+++ linux-ein-5.4.0/drivers/dma/at_hdmac.c
@@ -246,6 +246,8 @@
 		       ATC_SPIP_BOUNDARY(first->boundary));
 	channel_writel(atchan, DPIP, ATC_DPIP_HOLE(first->dst_hole) |
 		       ATC_DPIP_BOUNDARY(first->boundary));
+	/* Don't allow CPU to reorder channel enable. */
+	wmb();
 	dma_writel(atdma, CHER, atchan->mask);
 
 	vdbg_dump_regs(atchan);
@@ -306,7 +308,8 @@
 	struct at_desc *desc_first = atc_first_active(atchan);
 	struct at_desc *desc;
 	int ret;
-	u32 ctrla, dscr, trials;
+	u32 ctrla, dscr;
+	unsigned int i;
 
 	/*
 	 * If the cookie doesn't match to the currently running transfer then
@@ -376,7 +379,7 @@
 		dscr = channel_readl(atchan, DSCR);
 		rmb(); /* ensure DSCR is read before CTRLA */
 		ctrla = channel_readl(atchan, CTRLA);
-		for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) {
+		for (i = 0; i < ATC_MAX_DSCR_TRIALS; ++i) {
 			u32 new_dscr;
 
 			rmb(); /* ensure DSCR is read after CTRLA */
@@ -402,7 +405,7 @@
 			rmb(); /* ensure DSCR is read before CTRLA */
 			ctrla = channel_readl(atchan, CTRLA);
 		}
-		if (unlikely(trials >= ATC_MAX_DSCR_TRIALS))
+		if (unlikely(i == ATC_MAX_DSCR_TRIALS))
 			return -ETIMEDOUT;
 
 		/* for the first descriptor we can be more accurate */
@@ -550,10 +553,6 @@
 	bad_desc = atc_first_active(atchan);
 	list_del_init(&bad_desc->desc_node);
 
-	/* As we are stopped, take advantage to push queued descriptors
-	 * in active_list */
-	list_splice_init(&atchan->queue, atchan->active_list.prev);
-
 	/* Try to restart the controller */
 	if (!list_empty(&atchan->active_list))
 		atc_dostart(atchan, atc_first_active(atchan));
@@ -674,19 +673,11 @@
 	spin_lock_irqsave(&atchan->lock, flags);
 	cookie = dma_cookie_assign(tx);
 
-	if (list_empty(&atchan->active_list)) {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
-				desc->txd.cookie);
-		atc_dostart(atchan, desc);
-		list_add_tail(&desc->desc_node, &atchan->active_list);
-	} else {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
-				desc->txd.cookie);
-		list_add_tail(&desc->desc_node, &atchan->queue);
-	}
-
+	list_add_tail(&desc->desc_node, &atchan->queue);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
+	dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+		 desc->txd.cookie);
 	return cookie;
 }
 
@@ -1667,13 +1658,17 @@
 		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 = kzalloc(sizeof(*atslave), GFP_KERNEL);
-	if (!atslave)
+	atslave = kmalloc(sizeof(*atslave), GFP_KERNEL);
+	if (!atslave) {
+		put_device(&dmac_pdev->dev);
 		return NULL;
+	}
 
 	atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW;
 	/*
@@ -1702,8 +1697,11 @@
 	atslave->dma_dev = &dmac_pdev->dev;
 
 	chan = dma_request_channel(mask, at_dma_filter, atslave);
-	if (!chan)
+	if (!chan) {
+		put_device(&dmac_pdev->dev);
+		kfree(atslave);
 		return NULL;
+	}
 
 	atchan = to_at_dma_chan(chan);
 	atchan->per_if = dma_spec->args[0] & 0xff;
@@ -1950,7 +1948,11 @@
 	  dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)  ? "slave " : "",
 	  plat_dat->nr_channels);
 
-	dma_async_device_register(&atdma->dma_common);
+	err = dma_async_device_register(&atdma->dma_common);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register: %d.\n", err);
+		goto err_dma_async_device_register;
+	}
 
 	/*
 	 * Do not return an error if the dmac node is not present in order to
@@ -1970,6 +1972,7 @@
 
 err_of_dma_controller_register:
 	dma_async_device_unregister(&atdma->dma_common);
+err_dma_async_device_register:
 	dma_pool_destroy(atdma->memset_pool);
 err_memset_pool_create:
 	dma_pool_destroy(atdma->dma_desc_pool);
--- linux-ein-5.4.0.orig/drivers/dma/at_hdmac_regs.h
+++ linux-ein-5.4.0/drivers/dma/at_hdmac_regs.h
@@ -164,13 +164,13 @@
 /* LLI == Linked List Item; aka DMA buffer descriptor */
 struct at_lli {
 	/* values that are not changed by hardware */
-	dma_addr_t	saddr;
-	dma_addr_t	daddr;
+	u32 saddr;
+	u32 daddr;
 	/* value that may get written back: */
-	u32		ctrla;
+	u32 ctrla;
 	/* more values that are not changed by hardware */
-	u32		ctrlb;
-	dma_addr_t	dscr;	/* chain to next lli */
+	u32 ctrlb;
+	u32 dscr;	/* chain to next lli */
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/dma/at_xdmac.c
+++ linux-ein-5.4.0/drivers/dma/at_xdmac.c
@@ -89,6 +89,7 @@
 #define		AT_XDMAC_CNDC_NDE		(0x1 << 0)		/* Channel x Next Descriptor Enable */
 #define		AT_XDMAC_CNDC_NDSUP		(0x1 << 1)		/* Channel x Next Descriptor Source Update */
 #define		AT_XDMAC_CNDC_NDDUP		(0x1 << 2)		/* Channel x Next Descriptor Destination Update */
+#define		AT_XDMAC_CNDC_NDVIEW_MASK	GENMASK(28, 27)
 #define		AT_XDMAC_CNDC_NDVIEW_NDV0	(0x0 << 3)		/* Channel x Next Descriptor View 0 */
 #define		AT_XDMAC_CNDC_NDVIEW_NDV1	(0x1 << 3)		/* Channel x Next Descriptor View 1 */
 #define		AT_XDMAC_CNDC_NDVIEW_NDV2	(0x2 << 3)		/* Channel x Next Descriptor View 2 */
@@ -145,7 +146,7 @@
 #define		AT_XDMAC_CC_WRIP	(0x1 << 23)	/* Write in Progress (read only) */
 #define			AT_XDMAC_CC_WRIP_DONE		(0x0 << 23)
 #define			AT_XDMAC_CC_WRIP_IN_PROGRESS	(0x1 << 23)
-#define		AT_XDMAC_CC_PERID(i)	(0x7f & (i) << 24)	/* Channel Peripheral Identifier */
+#define		AT_XDMAC_CC_PERID(i)	((0x7f & (i)) << 24)	/* Channel Peripheral Identifier */
 #define AT_XDMAC_CDS_MSP	0x2C	/* Channel Data Stride Memory Set Pattern */
 #define AT_XDMAC_CSUS		0x30	/* Channel Source Microblock Stride */
 #define AT_XDMAC_CDUS		0x34	/* Channel Destination Microblock Stride */
@@ -211,6 +212,7 @@
 	int			irq;
 	struct clk		*clk;
 	u32			save_gim;
+	u32			save_gs;
 	struct dma_pool		*at_xdmac_desc_pool;
 	struct at_xdmac_chan	chan[0];
 };
@@ -220,15 +222,15 @@
 
 /* Linked List Descriptor */
 struct at_xdmac_lld {
-	dma_addr_t	mbr_nda;	/* Next Descriptor Member */
-	u32		mbr_ubc;	/* Microblock Control Member */
-	dma_addr_t	mbr_sa;		/* Source Address Member */
-	dma_addr_t	mbr_da;		/* Destination Address Member */
-	u32		mbr_cfg;	/* Configuration Register */
-	u32		mbr_bc;		/* Block Control Register */
-	u32		mbr_ds;		/* Data Stride Register */
-	u32		mbr_sus;	/* Source Microblock Stride Register */
-	u32		mbr_dus;	/* Destination Microblock Stride Register */
+	u32 mbr_nda;	/* Next Descriptor Member */
+	u32 mbr_ubc;	/* Microblock Control Member */
+	u32 mbr_sa;	/* Source Address Member */
+	u32 mbr_da;	/* Destination Address Member */
+	u32 mbr_cfg;	/* Configuration Register */
+	u32 mbr_bc;	/* Block Control Register */
+	u32 mbr_ds;	/* Data Stride Register */
+	u32 mbr_sus;	/* Source Microblock Stride Register */
+	u32 mbr_dus;	/* Destination Microblock Stride Register */
 };
 
 /* 64-bit alignment needed to update CNDA and CUBC registers in an atomic way. */
@@ -338,9 +340,6 @@
 
 	dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, first);
 
-	if (at_xdmac_chan_is_enabled(atchan))
-		return;
-
 	/* Set transfer as active to not try to start it again. */
 	first->active_xfer = true;
 
@@ -356,7 +355,8 @@
 	 */
 	if (at_xdmac_chan_is_cyclic(atchan))
 		reg = AT_XDMAC_CNDC_NDVIEW_NDV1;
-	else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3)
+	else if ((first->lld.mbr_ubc &
+		  AT_XDMAC_CNDC_NDVIEW_MASK) == AT_XDMAC_MBR_UBC_NDV3)
 		reg = AT_XDMAC_CNDC_NDVIEW_NDV3;
 	else
 		reg = AT_XDMAC_CNDC_NDVIEW_NDV2;
@@ -427,13 +427,12 @@
 	spin_lock_irqsave(&atchan->lock, irqflags);
 	cookie = dma_cookie_assign(tx);
 
+	list_add_tail(&desc->xfer_node, &atchan->xfers_list);
+	spin_unlock_irqrestore(&atchan->lock, irqflags);
+
 	dev_vdbg(chan2dev(tx->chan), "%s: atchan 0x%p, add desc 0x%p to xfers_list\n",
 		 __func__, atchan, desc);
-	list_add_tail(&desc->xfer_node, &atchan->xfers_list);
-	if (list_is_singular(&atchan->xfers_list))
-		at_xdmac_start_xfer(atchan, desc);
 
-	spin_unlock_irqrestore(&atchan->lock, irqflags);
 	return cookie;
 }
 
@@ -1392,7 +1391,7 @@
 {
 	struct at_xdmac_chan	*atchan = to_at_xdmac_chan(chan);
 	struct at_xdmac		*atxdmac = to_at_xdmac(atchan->chan.device);
-	struct at_xdmac_desc	*desc, *_desc;
+	struct at_xdmac_desc	*desc, *_desc, *iter;
 	struct list_head	*descs_list;
 	enum dma_status		ret;
 	int			residue, retry;
@@ -1507,11 +1506,13 @@
 	 * microblock.
 	 */
 	descs_list = &desc->descs_list;
-	list_for_each_entry_safe(desc, _desc, descs_list, desc_node) {
-		dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
-		residue -= (desc->lld.mbr_ubc & 0xffffff) << dwidth;
-		if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
+	list_for_each_entry_safe(iter, _desc, descs_list, desc_node) {
+		dwidth = at_xdmac_get_dwidth(iter->lld.mbr_cfg);
+		residue -= (iter->lld.mbr_ubc & 0xffffff) << dwidth;
+		if ((iter->lld.mbr_nda & 0xfffffffc) == cur_nda) {
+			desc = iter;
 			break;
+		}
 	}
 	residue += cur_ubc << dwidth;
 
@@ -1568,14 +1569,17 @@
 	struct at_xdmac_desc		*desc;
 	struct dma_async_tx_descriptor	*txd;
 
-	if (!list_empty(&atchan->xfers_list)) {
-		desc = list_first_entry(&atchan->xfers_list,
-					struct at_xdmac_desc, xfer_node);
-		txd = &desc->tx_dma_desc;
-
-		if (txd->flags & DMA_PREP_INTERRUPT)
-			dmaengine_desc_get_callback_invoke(txd, NULL);
+	spin_lock_irq(&atchan->lock);
+	if (list_empty(&atchan->xfers_list)) {
+		spin_unlock_irq(&atchan->lock);
+		return;
 	}
+	desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc,
+				xfer_node);
+	spin_unlock_irq(&atchan->lock);
+	txd = &desc->tx_dma_desc;
+	if (txd->flags & DMA_PREP_INTERRUPT)
+		dmaengine_desc_get_callback_invoke(txd, NULL);
 }
 
 static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
@@ -1725,11 +1729,13 @@
 static void at_xdmac_issue_pending(struct dma_chan *chan)
 {
 	struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
+	unsigned long flags;
 
 	dev_dbg(chan2dev(&atchan->chan), "%s\n", __func__);
 
-	if (!at_xdmac_chan_is_cyclic(atchan))
-		at_xdmac_advance_work(atchan);
+	spin_lock_irqsave(&atchan->lock, flags);
+	at_xdmac_advance_work(atchan);
+	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	return;
 }
@@ -1843,6 +1849,11 @@
 	for (i = 0; i < init_nr_desc_per_channel; i++) {
 		desc = at_xdmac_alloc_desc(chan, GFP_ATOMIC);
 		if (!desc) {
+			if (i == 0) {
+				dev_warn(chan2dev(chan),
+					 "can't allocate any descriptors\n");
+				return -EIO;
+			}
 			dev_warn(chan2dev(chan),
 				"only %d descriptors have been allocated\n", i);
 			break;
@@ -1912,6 +1923,7 @@
 		}
 	}
 	atxdmac->save_gim = at_xdmac_read(atxdmac, AT_XDMAC_GIM);
+	atxdmac->save_gs = at_xdmac_read(atxdmac, AT_XDMAC_GS);
 
 	at_xdmac_off(atxdmac);
 	clk_disable_unprepare(atxdmac->clk);
@@ -1948,7 +1960,8 @@
 			at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
 			at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim);
 			wmb();
-			at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
+			if (atxdmac->save_gs & atchan->mask)
+				at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
 		}
 	}
 	return 0;
--- linux-ein-5.4.0.orig/drivers/dma/coh901318.c
+++ linux-ein-5.4.0/drivers/dma/coh901318.c
@@ -1947,8 +1947,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
@@ -1969,8 +1967,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-ein-5.4.0.orig/drivers/dma/dma-axi-dmac.c
+++ linux-ein-5.4.0/drivers/dma/dma-axi-dmac.c
@@ -830,6 +830,7 @@
 	struct dma_device *dma_dev;
 	struct axi_dmac *dmac;
 	struct resource *res;
+	struct regmap *regmap;
 	int ret;
 
 	dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
@@ -921,10 +922,17 @@
 
 	platform_set_drvdata(pdev, dmac);
 
-	devm_regmap_init_mmio(&pdev->dev, dmac->base, &axi_dmac_regmap_config);
+	regmap = devm_regmap_init_mmio(&pdev->dev, dmac->base,
+		 &axi_dmac_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		goto err_free_irq;
+	}
 
 	return 0;
 
+err_free_irq:
+	free_irq(dmac->irq, dmac);
 err_unregister_of:
 	of_dma_controller_free(pdev->dev.of_node);
 err_unregister_device:
--- linux-ein-5.4.0.orig/drivers/dma/dma-jz4780.c
+++ linux-ein-5.4.0/drivers/dma/dma-jz4780.c
@@ -639,11 +639,11 @@
 	unsigned long flags;
 	unsigned long residue = 0;
 
+	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) {
@@ -660,6 +660,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;
 }
@@ -885,24 +886,11 @@
 		return -EINVAL;
 	}
 
-	ret = platform_get_irq(pdev, 0);
-	if (ret < 0)
-		return ret;
-
-	jzdma->irq = ret;
-
-	ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev),
-			  jzdma);
-	if (ret) {
-		dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq);
-		return ret;
-	}
-
 	jzdma->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(jzdma->clk)) {
 		dev_err(dev, "failed to get clock\n");
 		ret = PTR_ERR(jzdma->clk);
-		goto err_free_irq;
+		return ret;
 	}
 
 	clk_prepare_enable(jzdma->clk);
@@ -955,10 +943,23 @@
 		jzchan->vchan.desc_free = jz4780_dma_desc_free;
 	}
 
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto err_disable_clk;
+
+	jzdma->irq = ret;
+
+	ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev),
+			  jzdma);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq);
+		goto err_disable_clk;
+	}
+
 	ret = dmaenginem_async_device_register(dd);
 	if (ret) {
 		dev_err(dev, "failed to register device\n");
-		goto err_disable_clk;
+		goto err_free_irq;
 	}
 
 	/* Register with OF DMA helpers. */
@@ -966,17 +967,17 @@
 					 jzdma);
 	if (ret) {
 		dev_err(dev, "failed to register OF DMA controller\n");
-		goto err_disable_clk;
+		goto err_free_irq;
 	}
 
 	dev_info(dev, "JZ4780 DMA controller initialised\n");
 	return 0;
 
-err_disable_clk:
-	clk_disable_unprepare(jzdma->clk);
-
 err_free_irq:
 	free_irq(jzdma->irq, jzdma);
+
+err_disable_clk:
+	clk_disable_unprepare(jzdma->clk);
 	return ret;
 }
 
@@ -1004,7 +1005,8 @@
 static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
 	.nb_channels = 6,
 	.transfer_ord_max = 5,
-	.flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC,
+	.flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC |
+		 JZ_SOC_DATA_BREAK_LINKS,
 };
 
 static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
--- linux-ein-5.4.0.orig/drivers/dma/dmaengine.c
+++ linux-ein-5.4.0/drivers/dma/dmaengine.c
@@ -179,7 +179,7 @@
 
 static struct module *dma_chan_to_owner(struct dma_chan *chan)
 {
-	return chan->device->dev->driver->owner;
+	return chan->device->owner;
 }
 
 /**
@@ -212,7 +212,8 @@
 	/* The channel is already in use, update client count */
 	if (chan->client_count) {
 		__module_get(owner);
-		goto out;
+		chan->client_count++;
+		return 0;
 	}
 
 	if (!try_module_get(owner))
@@ -225,11 +226,11 @@
 			goto err_out;
 	}
 
+	chan->client_count++;
+
 	if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask))
 		balance_ref_count(chan);
 
-out:
-	chan->client_count++;
 	return 0;
 
 err_out:
@@ -919,6 +920,8 @@
 		return -EIO;
 	}
 
+	device->owner = device->dev->driver->owner;
+
 	if (dma_has_cap(DMA_MEMCPY, device->cap_mask) && !device->device_prep_dma_memcpy) {
 		dev_err(device->dev,
 			"Device claims capability %s, but op is not defined\n",
--- linux-ein-5.4.0.orig/drivers/dma/dmaengine.h
+++ linux-ein-5.4.0/drivers/dma/dmaengine.h
@@ -168,7 +168,7 @@
 static inline bool
 dmaengine_desc_callback_valid(struct dmaengine_desc_callback *cb)
 {
-	return (cb->callback) ? true : false;
+	return cb->callback || cb->callback_result;
 }
 
 #endif
--- linux-ein-5.4.0.orig/drivers/dma/dmatest.c
+++ linux-ein-5.4.0/drivers/dma/dmatest.c
@@ -240,7 +240,7 @@
 		struct dmatest_thread *thread;
 
 		list_for_each_entry(thread, &dtc->threads, node) {
-			if (!thread->done)
+			if (!thread->done && !thread->pending)
 				return true;
 		}
 	}
@@ -662,8 +662,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 *dsts;
@@ -1166,10 +1166,13 @@
 		mutex_unlock(&info->lock);
 		return ret;
 	} else if (dmatest_run) {
-		if (is_threaded_test_pending(info))
-			start_threaded_tests(info);
-		else
-			pr_info("Could not start test, no channels configured\n");
+		if (!is_threaded_test_pending(info)) {
+			pr_info("No channels configured, continue with any\n");
+			if (!is_threaded_test_run(info))
+				stop_threaded_test(info);
+			add_threaded_test(info);
+		}
+		start_threaded_tests(info);
 	} else {
 		stop_threaded_test(info);
 	}
@@ -1215,15 +1218,14 @@
 	add_threaded_test(info);
 
 	/* Check if channel was added successfully */
-	dtc = list_last_entry(&info->channels, struct dmatest_chan, node);
-
-	if (dtc->chan) {
+	if (!list_empty(&info->channels)) {
 		/*
 		 * if new channel was not successfully added, revert the
 		 * "test_channel" string to the name of the last successfully
 		 * added channel. exception for when users issues empty string
 		 * to channel parameter.
 		 */
+		dtc = list_last_entry(&info->channels, struct dmatest_chan, node);
 		if ((strcmp(dma_chan_name(dtc->chan), strim(test_channel)) != 0)
 		    && (strcmp("", strim(test_channel)) != 0)) {
 			ret = -EINVAL;
--- linux-ein-5.4.0.orig/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ linux-ein-5.4.0/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -551,6 +551,11 @@
 
 	/* The bad descriptor currently is in the head of vc list */
 	vd = vchan_next_desc(&chan->vc);
+	if (!vd) {
+		dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
+			axi_chan_name(chan));
+		goto out;
+	}
 	/* Remove the completed descriptor from issued list */
 	list_del(&vd->node);
 
@@ -565,6 +570,7 @@
 	/* Try to restart the controller */
 	axi_chan_start_first_queued(chan);
 
+out:
 	spin_unlock_irqrestore(&chan->vc.lock, flags);
 }
 
--- linux-ein-5.4.0.orig/drivers/dma/dw-edma/dw-edma-core.c
+++ linux-ein-5.4.0/drivers/dma/dw-edma/dw-edma-core.c
@@ -85,12 +85,12 @@
 
 	if (desc->chunk) {
 		/* Create and add new element into the linked list */
-		desc->chunks_alloc++;
-		list_add_tail(&chunk->list, &desc->chunk->list);
 		if (!dw_edma_alloc_burst(chunk)) {
 			kfree(chunk);
 			return NULL;
 		}
+		desc->chunks_alloc++;
+		list_add_tail(&chunk->list, &desc->chunk->list);
 	} else {
 		/* List head */
 		chunk->burst = NULL;
@@ -165,7 +165,7 @@
 	dw_edma_free_desc(vd2dw_edma_desc(vdesc));
 }
 
-static void dw_edma_start_transfer(struct dw_edma_chan *chan)
+static int dw_edma_start_transfer(struct dw_edma_chan *chan)
 {
 	struct dw_edma_chunk *child;
 	struct dw_edma_desc *desc;
@@ -173,16 +173,16 @@
 
 	vd = vchan_next_desc(&chan->vc);
 	if (!vd)
-		return;
+		return 0;
 
 	desc = vd2dw_edma_desc(vd);
 	if (!desc)
-		return;
+		return 0;
 
 	child = list_first_entry_or_null(&desc->chunk->list,
 					 struct dw_edma_chunk, list);
 	if (!child)
-		return;
+		return 0;
 
 	dw_edma_v0_core_start(child, !desc->xfer_sz);
 	desc->xfer_sz += child->ll_region.sz;
@@ -190,6 +190,8 @@
 	list_del(&child->list);
 	kfree(child);
 	desc->chunks_alloc--;
+
+	return 1;
 }
 
 static int dw_edma_device_config(struct dma_chan *dchan,
@@ -273,9 +275,12 @@
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
 	unsigned long flags;
 
+	if (!chan->configured)
+		return;
+
 	spin_lock_irqsave(&chan->vc.lock, flags);
-	if (chan->configured && chan->request == EDMA_REQ_NONE &&
-	    chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) {
+	if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE &&
+	    chan->status == EDMA_ST_IDLE) {
 		chan->status = EDMA_ST_BUSY;
 		dw_edma_start_transfer(chan);
 	}
@@ -391,7 +396,7 @@
 			if (xfer->cyclic) {
 				burst->dar = xfer->xfer.cyclic.paddr;
 			} else {
-				burst->dar = sg_dma_address(sg);
+				burst->dar = dst_addr;
 				/* Unlike the typical assumption by other
 				 * drivers/IPs the peripheral memory isn't
 				 * a FIFO memory, in this case, it's a
@@ -399,14 +404,13 @@
 				 * and destination addresses are increased
 				 * by the same portion (data length)
 				 */
-				src_addr += sg_dma_len(sg);
 			}
 		} else {
 			burst->dar = dst_addr;
 			if (xfer->cyclic) {
 				burst->sar = xfer->xfer.cyclic.paddr;
 			} else {
-				burst->sar = sg_dma_address(sg);
+				burst->sar = src_addr;
 				/* Unlike the typical assumption by other
 				 * drivers/IPs the peripheral memory isn't
 				 * a FIFO memory, in this case, it's a
@@ -414,12 +418,14 @@
 				 * and destination addresses are increased
 				 * by the same portion (data length)
 				 */
-				dst_addr += sg_dma_len(sg);
 			}
 		}
 
-		if (!xfer->cyclic)
+		if (!xfer->cyclic) {
+			src_addr += sg_dma_len(sg);
+			dst_addr += sg_dma_len(sg);
 			sg = sg_next(sg);
+		}
 	}
 
 	return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);
@@ -482,14 +488,14 @@
 		switch (chan->request) {
 		case EDMA_REQ_NONE:
 			desc = vd2dw_edma_desc(vd);
-			if (desc->chunks_alloc) {
-				chan->status = EDMA_ST_BUSY;
-				dw_edma_start_transfer(chan);
-			} else {
+			if (!desc->chunks_alloc) {
 				list_del(&vd->node);
 				vchan_cookie_complete(vd);
-				chan->status = EDMA_ST_IDLE;
 			}
+
+			/* Continue transferring if there are remaining chunks or issued requests.
+			 */
+			chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
 			break;
 
 		case EDMA_REQ_STOP:
@@ -909,22 +915,21 @@
 	/* Power management */
 	pm_runtime_disable(dev);
 
+	/* Deregister eDMA device */
+	dma_async_device_unregister(&dw->wr_edma);
 	list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
 				 vc.chan.device_node) {
-		list_del(&chan->vc.chan.device_node);
 		tasklet_kill(&chan->vc.task);
+		list_del(&chan->vc.chan.device_node);
 	}
 
+	dma_async_device_unregister(&dw->rd_edma);
 	list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
 				 vc.chan.device_node) {
-		list_del(&chan->vc.chan.device_node);
 		tasklet_kill(&chan->vc.task);
+		list_del(&chan->vc.chan.device_node);
 	}
 
-	/* Deregister eDMA device */
-	dma_async_device_unregister(&dw->wr_edma);
-	dma_async_device_unregister(&dw->rd_edma);
-
 	/* Turn debugfs off */
 	dw_edma_v0_core_debugfs_off();
 
--- linux-ein-5.4.0.orig/drivers/dma/dw/Kconfig
+++ linux-ein-5.4.0/drivers/dma/dw/Kconfig
@@ -10,6 +10,7 @@
 
 config DW_DMAC
 	tristate "Synopsys DesignWare AHB DMA platform driver"
+	depends on HAS_IOMEM
 	select DW_DMAC_CORE
 	help
 	  Support the Synopsys DesignWare AHB DMA controller. This
@@ -18,6 +19,7 @@
 config DW_DMAC_PCI
 	tristate "Synopsys DesignWare AHB DMA PCI driver"
 	depends on PCI
+	depends on HAS_IOMEM
 	select DW_DMAC_CORE
 	help
 	  Support the Synopsys DesignWare AHB DMA controller on the
--- linux-ein-5.4.0.orig/drivers/dma/dw/core.c
+++ linux-ein-5.4.0/drivers/dma/dw/core.c
@@ -118,16 +118,11 @@
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 
-	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
-		return;
-
 	dw->initialize_chan(dwc);
 
 	/* Enable interrupts */
 	channel_set_bit(dw, MASK.XFER, dwc->mask);
 	channel_set_bit(dw, MASK.ERROR, dwc->mask);
-
-	set_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
 }
 
 /*----------------------------------------------------------------------*/
@@ -777,6 +772,10 @@
 	if (dws->dma_dev != chan->device->dev)
 		return false;
 
+	/* permit channels in accordance with the channels mask */
+	if (dws->channels && !(dws->channels & dwc->mask))
+		return false;
+
 	/* We have to copy data since dws can be temporary storage */
 	memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave));
 
@@ -954,8 +953,6 @@
 
 void do_dw_dma_off(struct dw_dma *dw)
 {
-	unsigned int i;
-
 	dma_writel(dw, CFG, 0);
 
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
@@ -966,9 +963,6 @@
 
 	while (dma_readl(dw, CFG) & DW_CFG_DMA_EN)
 		cpu_relax();
-
-	for (i = 0; i < dw->dma.chancnt; i++)
-		clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
 }
 
 void do_dw_dma_on(struct dw_dma *dw)
@@ -1032,8 +1026,6 @@
 	/* Clear custom channel configuration */
 	memset(&dwc->dws, 0, sizeof(struct dw_dma_slave));
 
-	clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
-
 	/* Disable interrupts */
 	channel_clear_bit(dw, MASK.XFER, dwc->mask);
 	channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
--- linux-ein-5.4.0.orig/drivers/dma/dw/dw.c
+++ linux-ein-5.4.0/drivers/dma/dw/dw.c
@@ -14,7 +14,7 @@
 static void dw_dma_initialize_chan(struct dw_dma_chan *dwc)
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-	u32 cfghi = DWC_CFGH_FIFO_MODE;
+	u32 cfghi = is_slave_direction(dwc->direction) ? 0 : DWC_CFGH_FIFO_MODE;
 	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
 	bool hs_polarity = dwc->dws.hs_polarity;
 
--- linux-ein-5.4.0.orig/drivers/dma/dw/of.c
+++ linux-ein-5.4.0/drivers/dma/dw/of.c
@@ -22,18 +22,21 @@
 	};
 	dma_cap_mask_t cap;
 
-	if (dma_spec->args_count != 3)
+	if (dma_spec->args_count < 3 || dma_spec->args_count > 4)
 		return NULL;
 
 	slave.src_id = dma_spec->args[0];
 	slave.dst_id = dma_spec->args[0];
 	slave.m_master = dma_spec->args[1];
 	slave.p_master = dma_spec->args[2];
+	if (dma_spec->args_count >= 4)
+		slave.channels = dma_spec->args[3];
 
 	if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS ||
 		    slave.dst_id >= DW_DMA_MAX_NR_REQUESTS ||
 		    slave.m_master >= dw->pdata->nr_masters ||
-		    slave.p_master >= dw->pdata->nr_masters))
+		    slave.p_master >= dw->pdata->nr_masters ||
+		    slave.channels >= BIT(dw->pdata->nr_channels)))
 		return NULL;
 
 	dma_cap_zero(cap);
--- linux-ein-5.4.0.orig/drivers/dma/dw/platform.c
+++ linux-ein-5.4.0/drivers/dma/dw/platform.c
@@ -66,7 +66,7 @@
 
 	data->chip = chip;
 
-	chip->clk = devm_clk_get(chip->dev, "hclk");
+	chip->clk = devm_clk_get_optional(chip->dev, "hclk");
 	if (IS_ERR(chip->clk))
 		return PTR_ERR(chip->clk);
 	err = clk_prepare_enable(chip->clk);
--- linux-ein-5.4.0.orig/drivers/dma/fsl-edma-common.c
+++ linux-ein-5.4.0/drivers/dma/fsl-edma-common.c
@@ -347,26 +347,28 @@
 	/*
 	 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
 	 * endian format. However, we need to load the TCD registers in
-	 * big- or little-endian obeying the eDMA engine model endian.
+	 * big- or little-endian obeying the eDMA engine model endian,
+	 * and this is performed from specific edma_write functions
 	 */
 	edma_writew(edma, 0,  &regs->tcd[ch].csr);
-	edma_writel(edma, le32_to_cpu(tcd->saddr), &regs->tcd[ch].saddr);
-	edma_writel(edma, le32_to_cpu(tcd->daddr), &regs->tcd[ch].daddr);
 
-	edma_writew(edma, le16_to_cpu(tcd->attr), &regs->tcd[ch].attr);
-	edma_writew(edma, le16_to_cpu(tcd->soff), &regs->tcd[ch].soff);
+	edma_writel(edma, (s32)tcd->saddr, &regs->tcd[ch].saddr);
+	edma_writel(edma, (s32)tcd->daddr, &regs->tcd[ch].daddr);
 
-	edma_writel(edma, le32_to_cpu(tcd->nbytes), &regs->tcd[ch].nbytes);
-	edma_writel(edma, le32_to_cpu(tcd->slast), &regs->tcd[ch].slast);
+	edma_writew(edma, (s16)tcd->attr, &regs->tcd[ch].attr);
+	edma_writew(edma, tcd->soff, &regs->tcd[ch].soff);
 
-	edma_writew(edma, le16_to_cpu(tcd->citer), &regs->tcd[ch].citer);
-	edma_writew(edma, le16_to_cpu(tcd->biter), &regs->tcd[ch].biter);
-	edma_writew(edma, le16_to_cpu(tcd->doff), &regs->tcd[ch].doff);
+	edma_writel(edma, (s32)tcd->nbytes, &regs->tcd[ch].nbytes);
+	edma_writel(edma, (s32)tcd->slast, &regs->tcd[ch].slast);
 
-	edma_writel(edma, le32_to_cpu(tcd->dlast_sga),
+	edma_writew(edma, (s16)tcd->citer, &regs->tcd[ch].citer);
+	edma_writew(edma, (s16)tcd->biter, &regs->tcd[ch].biter);
+	edma_writew(edma, (s16)tcd->doff, &regs->tcd[ch].doff);
+
+	edma_writel(edma, (s32)tcd->dlast_sga,
 			&regs->tcd[ch].dlast_sga);
 
-	edma_writew(edma, le16_to_cpu(tcd->csr), &regs->tcd[ch].csr);
+	edma_writew(edma, (s16)tcd->csr, &regs->tcd[ch].csr);
 }
 
 static inline
--- linux-ein-5.4.0.orig/drivers/dma/fsl-edma-common.h
+++ linux-ein-5.4.0/drivers/dma/fsl-edma-common.h
@@ -33,7 +33,7 @@
 #define EDMA_TCD_ATTR_DSIZE_16BIT	BIT(0)
 #define EDMA_TCD_ATTR_DSIZE_32BIT	BIT(1)
 #define EDMA_TCD_ATTR_DSIZE_64BIT	(BIT(0) | BIT(1))
-#define EDMA_TCD_ATTR_DSIZE_32BYTE	(BIT(3) | BIT(0))
+#define EDMA_TCD_ATTR_DSIZE_32BYTE	(BIT(2) | BIT(0))
 #define EDMA_TCD_ATTR_SSIZE_8BIT	0
 #define EDMA_TCD_ATTR_SSIZE_16BIT	(EDMA_TCD_ATTR_DSIZE_16BIT << 8)
 #define EDMA_TCD_ATTR_SSIZE_32BIT	(EDMA_TCD_ATTR_DSIZE_32BIT << 8)
--- linux-ein-5.4.0.orig/drivers/dma/fsl-edma.c
+++ linux-ein-5.4.0/drivers/dma/fsl-edma.c
@@ -45,6 +45,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-ein-5.4.0.orig/drivers/dma/fsl-qdma.c
+++ linux-ein-5.4.0/drivers/dma/fsl-qdma.c
@@ -109,6 +109,7 @@
 #define FSL_QDMA_CMD_WTHROTL_OFFSET	20
 #define FSL_QDMA_CMD_DSEN_OFFSET	19
 #define FSL_QDMA_CMD_LWC_OFFSET		16
+#define FSL_QDMA_CMD_PF			BIT(17)
 
 /* Field definition for Descriptor offset */
 #define QDMA_CCDF_STATUS		20
@@ -304,7 +305,7 @@
 
 	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
 
-	if (!fsl_queue->comp_pool && !fsl_queue->comp_pool)
+	if (!fsl_queue->comp_pool && !fsl_queue->desc_pool)
 		return;
 
 	list_for_each_entry_safe(comp_temp, _comp_temp,
@@ -372,7 +373,8 @@
 	qdma_csgf_set_f(csgf_dest, len);
 	/* Descriptor Buffer */
 	cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
-			  FSL_QDMA_CMD_RWTTYPE_OFFSET);
+			  FSL_QDMA_CMD_RWTTYPE_OFFSET) |
+			  FSL_QDMA_CMD_PF;
 	sdf->data = QDMA_SDDF_CMD(cmd);
 
 	cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
@@ -502,11 +504,11 @@
 			queue_temp = queue_head + i + (j * queue_num);
 
 			queue_temp->cq =
-			dma_alloc_coherent(&pdev->dev,
-					   sizeof(struct fsl_qdma_format) *
-					   queue_size[i],
-					   &queue_temp->bus_addr,
-					   GFP_KERNEL);
+			dmam_alloc_coherent(&pdev->dev,
+					    sizeof(struct fsl_qdma_format) *
+					    queue_size[i],
+					    &queue_temp->bus_addr,
+					    GFP_KERNEL);
 			if (!queue_temp->cq)
 				return NULL;
 			queue_temp->block_base = fsl_qdma->block_base +
@@ -551,11 +553,11 @@
 	/*
 	 * Buffer for queue command
 	 */
-	status_head->cq = dma_alloc_coherent(&pdev->dev,
-					     sizeof(struct fsl_qdma_format) *
-					     status_size,
-					     &status_head->bus_addr,
-					     GFP_KERNEL);
+	status_head->cq = dmam_alloc_coherent(&pdev->dev,
+					      sizeof(struct fsl_qdma_format) *
+					      status_size,
+					      &status_head->bus_addr,
+					      GFP_KERNEL);
 	if (!status_head->cq) {
 		devm_kfree(&pdev->dev, status_head);
 		return NULL;
@@ -754,7 +756,7 @@
 	int i;
 	int cpu;
 	int ret;
-	char irq_name[20];
+	char irq_name[32];
 
 	fsl_qdma->error_irq =
 		platform_get_irq_byname(pdev, "qdma-error");
@@ -1150,11 +1152,10 @@
 	if (!fsl_qdma->queue)
 		return -ENOMEM;
 
-	ret = fsl_qdma_irq_init(pdev, fsl_qdma);
-	if (ret)
-		return ret;
-
 	fsl_qdma->irq_base = platform_get_irq_byname(pdev, "qdma-queue0");
+	if (fsl_qdma->irq_base < 0)
+		return fsl_qdma->irq_base;
+
 	fsl_qdma->feature = of_property_read_bool(np, "big-endian");
 	INIT_LIST_HEAD(&fsl_qdma->dma_dev.channels);
 
@@ -1181,20 +1182,27 @@
 	fsl_qdma->dma_dev.device_synchronize = fsl_qdma_synchronize;
 	fsl_qdma->dma_dev.device_terminate_all = fsl_qdma_terminate_all;
 
-	dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
+	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
+	if (ret) {
+		dev_err(&pdev->dev, "dma_set_mask failure.\n");
+		return ret;
+	}
 
 	platform_set_drvdata(pdev, fsl_qdma);
 
-	ret = dma_async_device_register(&fsl_qdma->dma_dev);
+	ret = fsl_qdma_reg_init(fsl_qdma);
 	if (ret) {
-		dev_err(&pdev->dev,
-			"Can't register NXP Layerscape qDMA engine.\n");
+		dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n");
 		return ret;
 	}
 
-	ret = fsl_qdma_reg_init(fsl_qdma);
+	ret = fsl_qdma_irq_init(pdev, fsl_qdma);
+	if (ret)
+		return ret;
+
+	ret = dma_async_device_register(&fsl_qdma->dma_dev);
 	if (ret) {
-		dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n");
+		dev_err(&pdev->dev, "Can't register NXP Layerscape qDMA engine.\n");
 		return ret;
 	}
 
@@ -1214,8 +1222,6 @@
 
 static int fsl_qdma_remove(struct platform_device *pdev)
 {
-	int i;
-	struct fsl_qdma_queue *status;
 	struct device_node *np = pdev->dev.of_node;
 	struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev);
 
@@ -1224,11 +1230,6 @@
 	of_dma_controller_free(np);
 	dma_async_device_unregister(&fsl_qdma->dma_dev);
 
-	for (i = 0; i < fsl_qdma->block_number; i++) {
-		status = fsl_qdma->status[i];
-		dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_format) *
-				status->n_cq, status->cq, status->bus_addr);
-	}
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/dma/fsldma.c
+++ linux-ein-5.4.0/drivers/dma/fsldma.c
@@ -1214,6 +1214,7 @@
 {
 	struct fsldma_device *fdev;
 	struct device_node *child;
+	unsigned int i;
 	int err;
 
 	fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
@@ -1292,6 +1293,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);
 	iounmap(fdev->regs);
 out_free:
@@ -1314,6 +1319,7 @@
 		if (fdev->chan[i])
 			fsl_dma_chan_remove(fdev->chan[i]);
 	}
+	irq_dispose_mapping(fdev->irq);
 
 	iounmap(fdev->regs);
 	kfree(fdev);
--- linux-ein-5.4.0.orig/drivers/dma/fsldma.h
+++ linux-ein-5.4.0/drivers/dma/fsldma.h
@@ -205,10 +205,10 @@
 #else
 static u64 fsl_ioread64(const u64 __iomem *addr)
 {
-	u32 fsl_addr = lower_32_bits(addr);
-	u64 fsl_addr_hi = (u64)in_le32((u32 *)(fsl_addr + 1)) << 32;
+	u32 val_lo = in_le32((u32 __iomem *)addr);
+	u32 val_hi = in_le32((u32 __iomem *)addr + 1);
 
-	return fsl_addr_hi | in_le32((u32 *)fsl_addr);
+	return ((u64)val_hi << 32) + val_lo;
 }
 
 static void fsl_iowrite64(u64 val, u64 __iomem *addr)
@@ -219,10 +219,10 @@
 
 static u64 fsl_ioread64be(const u64 __iomem *addr)
 {
-	u32 fsl_addr = lower_32_bits(addr);
-	u64 fsl_addr_hi = (u64)in_be32((u32 *)fsl_addr) << 32;
+	u32 val_hi = in_be32((u32 __iomem *)addr);
+	u32 val_lo = in_be32((u32 __iomem *)addr + 1);
 
-	return fsl_addr_hi | in_be32((u32 *)(fsl_addr + 1));
+	return ((u64)val_hi << 32) + val_lo;
 }
 
 static void fsl_iowrite64be(u64 val, u64 __iomem *addr)
--- linux-ein-5.4.0.orig/drivers/dma/hisi_dma.c
+++ linux-ein-5.4.0/drivers/dma/hisi_dma.c
@@ -0,0 +1,611 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2019 HiSilicon Limited. */
+#include <linux/bitfield.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "virt-dma.h"
+
+#define HISI_DMA_SQ_BASE_L		0x0
+#define HISI_DMA_SQ_BASE_H		0x4
+#define HISI_DMA_SQ_DEPTH		0x8
+#define HISI_DMA_SQ_TAIL_PTR		0xc
+#define HISI_DMA_CQ_BASE_L		0x10
+#define HISI_DMA_CQ_BASE_H		0x14
+#define HISI_DMA_CQ_DEPTH		0x18
+#define HISI_DMA_CQ_HEAD_PTR		0x1c
+#define HISI_DMA_CTRL0			0x20
+#define HISI_DMA_CTRL0_QUEUE_EN_S	0
+#define HISI_DMA_CTRL0_QUEUE_PAUSE_S	4
+#define HISI_DMA_CTRL1			0x24
+#define HISI_DMA_CTRL1_QUEUE_RESET_S	0
+#define HISI_DMA_Q_FSM_STS		0x30
+#define HISI_DMA_FSM_STS_MASK		GENMASK(3, 0)
+#define HISI_DMA_INT_STS		0x40
+#define HISI_DMA_INT_STS_MASK		GENMASK(12, 0)
+#define HISI_DMA_INT_MSK		0x44
+#define HISI_DMA_MODE			0x217c
+#define HISI_DMA_OFFSET			0x100
+
+#define HISI_DMA_MSI_NUM		30
+#define HISI_DMA_CHAN_NUM		30
+#define HISI_DMA_Q_DEPTH_VAL		1024
+
+#define PCI_BAR_2			2
+
+enum hisi_dma_mode {
+	EP = 0,
+	RC,
+};
+
+enum hisi_dma_chan_status {
+	DISABLE = -1,
+	IDLE = 0,
+	RUN,
+	CPL,
+	PAUSE,
+	HALT,
+	ABORT,
+	WAIT,
+	BUFFCLR,
+};
+
+struct hisi_dma_sqe {
+	__le32 dw0;
+#define OPCODE_MASK			GENMASK(3, 0)
+#define OPCODE_SMALL_PACKAGE		0x1
+#define OPCODE_M2M			0x4
+#define LOCAL_IRQ_EN			BIT(8)
+#define ATTR_SRC_MASK			GENMASK(14, 12)
+	__le32 dw1;
+	__le32 dw2;
+#define ATTR_DST_MASK			GENMASK(26, 24)
+	__le32 length;
+	__le64 src_addr;
+	__le64 dst_addr;
+};
+
+struct hisi_dma_cqe {
+	__le32 rsv0;
+	__le32 rsv1;
+	__le16 sq_head;
+	__le16 rsv2;
+	__le16 rsv3;
+	__le16 w0;
+#define STATUS_MASK			GENMASK(15, 1)
+#define STATUS_SUCC			0x0
+#define VALID_BIT			BIT(0)
+};
+
+struct hisi_dma_desc {
+	struct virt_dma_desc vd;
+	struct hisi_dma_sqe sqe;
+};
+
+struct hisi_dma_chan {
+	struct virt_dma_chan vc;
+	struct hisi_dma_dev *hdma_dev;
+	struct hisi_dma_sqe *sq;
+	struct hisi_dma_cqe *cq;
+	dma_addr_t sq_dma;
+	dma_addr_t cq_dma;
+	u32 sq_tail;
+	u32 cq_head;
+	u32 qp_num;
+	enum hisi_dma_chan_status status;
+	struct hisi_dma_desc *desc;
+};
+
+struct hisi_dma_dev {
+	struct pci_dev *pdev;
+	void __iomem *base;
+	struct dma_device dma_dev;
+	u32 chan_num;
+	u32 chan_depth;
+	struct hisi_dma_chan chan[];
+};
+
+static inline struct hisi_dma_chan *to_hisi_dma_chan(struct dma_chan *c)
+{
+	return container_of(c, struct hisi_dma_chan, vc.chan);
+}
+
+static inline struct hisi_dma_desc *to_hisi_dma_desc(struct virt_dma_desc *vd)
+{
+	return container_of(vd, struct hisi_dma_desc, vd);
+}
+
+static inline void hisi_dma_chan_write(void __iomem *base, u32 reg, u32 index,
+				       u32 val)
+{
+	writel_relaxed(val, base + reg + index * HISI_DMA_OFFSET);
+}
+
+static inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val)
+{
+	u32 tmp;
+
+	tmp = readl_relaxed(addr);
+	tmp = val ? tmp | BIT(pos) : tmp & ~BIT(pos);
+	writel_relaxed(tmp, addr);
+}
+
+static void hisi_dma_free_irq_vectors(void *data)
+{
+	pci_free_irq_vectors(data);
+}
+
+static void hisi_dma_pause_dma(struct hisi_dma_dev *hdma_dev, u32 index,
+			       bool pause)
+{
+	void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index *
+			     HISI_DMA_OFFSET;
+
+	hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_PAUSE_S, pause);
+}
+
+static void hisi_dma_enable_dma(struct hisi_dma_dev *hdma_dev, u32 index,
+				bool enable)
+{
+	void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index *
+			     HISI_DMA_OFFSET;
+
+	hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_EN_S, enable);
+}
+
+static void hisi_dma_mask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index)
+{
+	hisi_dma_chan_write(hdma_dev->base, HISI_DMA_INT_MSK, qp_index,
+			    HISI_DMA_INT_STS_MASK);
+}
+
+static void hisi_dma_unmask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index)
+{
+	void __iomem *base = hdma_dev->base;
+
+	hisi_dma_chan_write(base, HISI_DMA_INT_STS, qp_index,
+			    HISI_DMA_INT_STS_MASK);
+	hisi_dma_chan_write(base, HISI_DMA_INT_MSK, qp_index, 0);
+}
+
+static void hisi_dma_do_reset(struct hisi_dma_dev *hdma_dev, u32 index)
+{
+	void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL1 + index *
+			     HISI_DMA_OFFSET;
+
+	hisi_dma_update_bit(addr, HISI_DMA_CTRL1_QUEUE_RESET_S, 1);
+}
+
+static void hisi_dma_reset_qp_point(struct hisi_dma_dev *hdma_dev, u32 index)
+{
+	hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, index, 0);
+	hisi_dma_chan_write(hdma_dev->base, HISI_DMA_CQ_HEAD_PTR, index, 0);
+}
+
+static void hisi_dma_reset_hw_chan(struct hisi_dma_chan *chan)
+{
+	struct hisi_dma_dev *hdma_dev = chan->hdma_dev;
+	u32 index = chan->qp_num, tmp;
+	int ret;
+
+	hisi_dma_pause_dma(hdma_dev, index, true);
+	hisi_dma_enable_dma(hdma_dev, index, false);
+	hisi_dma_mask_irq(hdma_dev, index);
+
+	ret = readl_relaxed_poll_timeout(hdma_dev->base +
+		HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp,
+		FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) != RUN, 10, 1000);
+	if (ret) {
+		dev_err(&hdma_dev->pdev->dev, "disable channel timeout!\n");
+		WARN_ON(1);
+	}
+
+	hisi_dma_do_reset(hdma_dev, index);
+	hisi_dma_reset_qp_point(hdma_dev, index);
+	hisi_dma_pause_dma(hdma_dev, index, false);
+	hisi_dma_enable_dma(hdma_dev, index, true);
+	hisi_dma_unmask_irq(hdma_dev, index);
+
+	ret = readl_relaxed_poll_timeout(hdma_dev->base +
+		HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp,
+		FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) == IDLE, 10, 1000);
+	if (ret) {
+		dev_err(&hdma_dev->pdev->dev, "reset channel timeout!\n");
+		WARN_ON(1);
+	}
+}
+
+static void hisi_dma_free_chan_resources(struct dma_chan *c)
+{
+	struct hisi_dma_chan *chan = to_hisi_dma_chan(c);
+	struct hisi_dma_dev *hdma_dev = chan->hdma_dev;
+
+	hisi_dma_reset_hw_chan(chan);
+	vchan_free_chan_resources(&chan->vc);
+
+	memset(chan->sq, 0, sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth);
+	memset(chan->cq, 0, sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth);
+	chan->sq_tail = 0;
+	chan->cq_head = 0;
+	chan->status = DISABLE;
+}
+
+static void hisi_dma_desc_free(struct virt_dma_desc *vd)
+{
+	kfree(to_hisi_dma_desc(vd));
+}
+
+static struct dma_async_tx_descriptor *
+hisi_dma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dst, dma_addr_t src,
+			 size_t len, unsigned long flags)
+{
+	struct hisi_dma_chan *chan = to_hisi_dma_chan(c);
+	struct hisi_dma_desc *desc;
+
+	desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+	if (!desc)
+		return NULL;
+
+	desc->sqe.length = cpu_to_le32(len);
+	desc->sqe.src_addr = cpu_to_le64(src);
+	desc->sqe.dst_addr = cpu_to_le64(dst);
+
+	return vchan_tx_prep(&chan->vc, &desc->vd, flags);
+}
+
+static enum dma_status
+hisi_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie,
+		   struct dma_tx_state *txstate)
+{
+	return dma_cookie_status(c, cookie, txstate);
+}
+
+static void hisi_dma_start_transfer(struct hisi_dma_chan *chan)
+{
+	struct hisi_dma_sqe *sqe = chan->sq + chan->sq_tail;
+	struct hisi_dma_dev *hdma_dev = chan->hdma_dev;
+	struct hisi_dma_desc *desc;
+	struct virt_dma_desc *vd;
+
+	vd = vchan_next_desc(&chan->vc);
+	if (!vd) {
+		dev_err(&hdma_dev->pdev->dev, "no issued task!\n");
+		chan->desc = NULL;
+		return;
+	}
+	list_del(&vd->node);
+	desc = to_hisi_dma_desc(vd);
+	chan->desc = desc;
+
+	memcpy(sqe, &desc->sqe, sizeof(struct hisi_dma_sqe));
+
+	/* update other field in sqe */
+	sqe->dw0 = cpu_to_le32(FIELD_PREP(OPCODE_MASK, OPCODE_M2M));
+	sqe->dw0 |= cpu_to_le32(LOCAL_IRQ_EN);
+
+	/* make sure data has been updated in sqe */
+	wmb();
+
+	/* update sq tail, point to new sqe position */
+	chan->sq_tail = (chan->sq_tail + 1) % hdma_dev->chan_depth;
+
+	/* update sq_tail to trigger a new task */
+	hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, chan->qp_num,
+			    chan->sq_tail);
+}
+
+static void hisi_dma_issue_pending(struct dma_chan *c)
+{
+	struct hisi_dma_chan *chan = to_hisi_dma_chan(c);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->vc.lock, flags);
+
+	if (vchan_issue_pending(&chan->vc))
+		hisi_dma_start_transfer(chan);
+
+	spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
+static int hisi_dma_terminate_all(struct dma_chan *c)
+{
+	struct hisi_dma_chan *chan = to_hisi_dma_chan(c);
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&chan->vc.lock, flags);
+
+	hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, true);
+	if (chan->desc) {
+		vchan_terminate_vdesc(&chan->desc->vd);
+		chan->desc = NULL;
+	}
+
+	vchan_get_all_descriptors(&chan->vc, &head);
+
+	spin_unlock_irqrestore(&chan->vc.lock, flags);
+
+	vchan_dma_desc_free_list(&chan->vc, &head);
+	hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, false);
+
+	return 0;
+}
+
+static void hisi_dma_synchronize(struct dma_chan *c)
+{
+	struct hisi_dma_chan *chan = to_hisi_dma_chan(c);
+
+	vchan_synchronize(&chan->vc);
+}
+
+static int hisi_dma_alloc_qps_mem(struct hisi_dma_dev *hdma_dev)
+{
+	size_t sq_size = sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth;
+	size_t cq_size = sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth;
+	struct device *dev = &hdma_dev->pdev->dev;
+	struct hisi_dma_chan *chan;
+	int i;
+
+	for (i = 0; i < hdma_dev->chan_num; i++) {
+		chan = &hdma_dev->chan[i];
+		chan->sq = dmam_alloc_coherent(dev, sq_size, &chan->sq_dma,
+					       GFP_KERNEL);
+		if (!chan->sq)
+			return -ENOMEM;
+
+		chan->cq = dmam_alloc_coherent(dev, cq_size, &chan->cq_dma,
+					       GFP_KERNEL);
+		if (!chan->cq)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void hisi_dma_init_hw_qp(struct hisi_dma_dev *hdma_dev, u32 index)
+{
+	struct hisi_dma_chan *chan = &hdma_dev->chan[index];
+	u32 hw_depth = hdma_dev->chan_depth - 1;
+	void __iomem *base = hdma_dev->base;
+
+	/* set sq, cq base */
+	hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_L, index,
+			    lower_32_bits(chan->sq_dma));
+	hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_H, index,
+			    upper_32_bits(chan->sq_dma));
+	hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_L, index,
+			    lower_32_bits(chan->cq_dma));
+	hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_H, index,
+			    upper_32_bits(chan->cq_dma));
+
+	/* set sq, cq depth */
+	hisi_dma_chan_write(base, HISI_DMA_SQ_DEPTH, index, hw_depth);
+	hisi_dma_chan_write(base, HISI_DMA_CQ_DEPTH, index, hw_depth);
+
+	/* init sq tail and cq head */
+	hisi_dma_chan_write(base, HISI_DMA_SQ_TAIL_PTR, index, 0);
+	hisi_dma_chan_write(base, HISI_DMA_CQ_HEAD_PTR, index, 0);
+}
+
+static void hisi_dma_enable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index)
+{
+	hisi_dma_init_hw_qp(hdma_dev, qp_index);
+	hisi_dma_unmask_irq(hdma_dev, qp_index);
+	hisi_dma_enable_dma(hdma_dev, qp_index, true);
+}
+
+static void hisi_dma_disable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index)
+{
+	hisi_dma_reset_hw_chan(&hdma_dev->chan[qp_index]);
+}
+
+static void hisi_dma_enable_qps(struct hisi_dma_dev *hdma_dev)
+{
+	int i;
+
+	for (i = 0; i < hdma_dev->chan_num; i++) {
+		hdma_dev->chan[i].qp_num = i;
+		hdma_dev->chan[i].hdma_dev = hdma_dev;
+		hdma_dev->chan[i].vc.desc_free = hisi_dma_desc_free;
+		vchan_init(&hdma_dev->chan[i].vc, &hdma_dev->dma_dev);
+		hisi_dma_enable_qp(hdma_dev, i);
+	}
+}
+
+static void hisi_dma_disable_qps(struct hisi_dma_dev *hdma_dev)
+{
+	int i;
+
+	for (i = 0; i < hdma_dev->chan_num; i++) {
+		hisi_dma_disable_qp(hdma_dev, i);
+		tasklet_kill(&hdma_dev->chan[i].vc.task);
+	}
+}
+
+static irqreturn_t hisi_dma_irq(int irq, void *data)
+{
+	struct hisi_dma_chan *chan = data;
+	struct hisi_dma_dev *hdma_dev = chan->hdma_dev;
+	struct hisi_dma_desc *desc;
+	struct hisi_dma_cqe *cqe;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->vc.lock, flags);
+
+	desc = chan->desc;
+	cqe = chan->cq + chan->cq_head;
+	if (desc) {
+		if (FIELD_GET(STATUS_MASK, cqe->w0) == STATUS_SUCC) {
+			chan->cq_head = (chan->cq_head + 1) %
+					hdma_dev->chan_depth;
+			hisi_dma_chan_write(hdma_dev->base,
+					    HISI_DMA_CQ_HEAD_PTR, chan->qp_num,
+					    chan->cq_head);
+			vchan_cookie_complete(&desc->vd);
+		} else {
+			dev_err(&hdma_dev->pdev->dev, "task error!\n");
+		}
+
+		chan->desc = NULL;
+	}
+
+	spin_unlock_irqrestore(&chan->vc.lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int hisi_dma_request_qps_irq(struct hisi_dma_dev *hdma_dev)
+{
+	struct pci_dev *pdev = hdma_dev->pdev;
+	int i, ret;
+
+	for (i = 0; i < hdma_dev->chan_num; i++) {
+		ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i),
+				       hisi_dma_irq, IRQF_SHARED, "hisi_dma",
+				       &hdma_dev->chan[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* This function enables all hw channels in a device */
+static int hisi_dma_enable_hw_channels(struct hisi_dma_dev *hdma_dev)
+{
+	int ret;
+
+	ret = hisi_dma_alloc_qps_mem(hdma_dev);
+	if (ret) {
+		dev_err(&hdma_dev->pdev->dev, "fail to allocate qp memory!\n");
+		return ret;
+	}
+
+	ret = hisi_dma_request_qps_irq(hdma_dev);
+	if (ret) {
+		dev_err(&hdma_dev->pdev->dev, "fail to request qp irq!\n");
+		return ret;
+	}
+
+	hisi_dma_enable_qps(hdma_dev);
+
+	return 0;
+}
+
+static void hisi_dma_disable_hw_channels(void *data)
+{
+	hisi_dma_disable_qps(data);
+}
+
+static void hisi_dma_set_mode(struct hisi_dma_dev *hdma_dev,
+			      enum hisi_dma_mode mode)
+{
+	writel_relaxed(mode == RC ? 1 : 0, hdma_dev->base + HISI_DMA_MODE);
+}
+
+static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct device *dev = &pdev->dev;
+	struct hisi_dma_dev *hdma_dev;
+	struct dma_device *dma_dev;
+	size_t dev_size;
+	int ret;
+
+	ret = pcim_enable_device(pdev);
+	if (ret) {
+		dev_err(dev, "failed to enable device mem!\n");
+		return ret;
+	}
+
+	ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_2, pci_name(pdev));
+	if (ret) {
+		dev_err(dev, "failed to remap I/O region!\n");
+		return ret;
+	}
+
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	dev_size = sizeof(struct hisi_dma_chan) * HISI_DMA_CHAN_NUM +
+		   sizeof(*hdma_dev);
+	hdma_dev = devm_kzalloc(dev, dev_size, GFP_KERNEL);
+	if (!hdma_dev)
+		return -EINVAL;
+
+	hdma_dev->base = pcim_iomap_table(pdev)[PCI_BAR_2];
+	hdma_dev->pdev = pdev;
+	hdma_dev->chan_num = HISI_DMA_CHAN_NUM;
+	hdma_dev->chan_depth = HISI_DMA_Q_DEPTH_VAL;
+
+	pci_set_drvdata(pdev, hdma_dev);
+	pci_set_master(pdev);
+
+	ret = pci_alloc_irq_vectors(pdev, HISI_DMA_MSI_NUM, HISI_DMA_MSI_NUM,
+				    PCI_IRQ_MSI);
+	if (ret < 0) {
+		dev_err(dev, "Failed to allocate MSI vectors!\n");
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev, hisi_dma_free_irq_vectors, pdev);
+	if (ret)
+		return ret;
+
+	dma_dev = &hdma_dev->dma_dev;
+	dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+	dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources;
+	dma_dev->device_prep_dma_memcpy = hisi_dma_prep_dma_memcpy;
+	dma_dev->device_tx_status = hisi_dma_tx_status;
+	dma_dev->device_issue_pending = hisi_dma_issue_pending;
+	dma_dev->device_terminate_all = hisi_dma_terminate_all;
+	dma_dev->device_synchronize = hisi_dma_synchronize;
+	dma_dev->directions = BIT(DMA_MEM_TO_MEM);
+	dma_dev->dev = dev;
+	INIT_LIST_HEAD(&dma_dev->channels);
+
+	hisi_dma_set_mode(hdma_dev, RC);
+
+	ret = hisi_dma_enable_hw_channels(hdma_dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable hw channel!\n");
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev, hisi_dma_disable_hw_channels,
+				       hdma_dev);
+	if (ret)
+		return ret;
+
+	ret = dmaenginem_async_device_register(dma_dev);
+	if (ret < 0)
+		dev_err(dev, "failed to register device!\n");
+
+	return ret;
+}
+
+static const struct pci_device_id hisi_dma_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa122) },
+	{ 0, }
+};
+
+static struct pci_driver hisi_dma_pci_driver = {
+	.name		= "hisi_dma",
+	.id_table	= hisi_dma_pci_tbl,
+	.probe		= hisi_dma_probe,
+};
+
+module_pci_driver(hisi_dma_pci_driver);
+
+MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
+MODULE_AUTHOR("Zhenfa Qiu <qiuzhenfa@hisilicon.com>");
+MODULE_DESCRIPTION("HiSilicon Kunpeng DMA controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, hisi_dma_pci_tbl);
--- linux-ein-5.4.0.orig/drivers/dma/hsu/pci.c
+++ linux-ein-5.4.0/drivers/dma/hsu/pci.c
@@ -26,22 +26,12 @@
 static irqreturn_t hsu_pci_irq(int irq, void *dev)
 {
 	struct hsu_dma_chip *chip = dev;
-	struct pci_dev *pdev = to_pci_dev(chip->dev);
 	u32 dmaisr;
 	u32 status;
 	unsigned short i;
 	int ret = 0;
 	int err;
 
-	/*
-	 * On Intel Tangier B0 and Anniedale the interrupt line, disregarding
-	 * to have different numbers, is shared between HSU DMA and UART IPs.
-	 * Thus on such SoCs we are expecting that IRQ handler is called in
-	 * UART driver only.
-	 */
-	if (pdev->device == PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA)
-		return IRQ_HANDLED;
-
 	dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
 	for (i = 0; i < chip->hsu->nr_channels; i++) {
 		if (dmaisr & 0x1) {
@@ -105,6 +95,17 @@
 	if (ret)
 		goto err_register_irq;
 
+	/*
+	 * On Intel Tangier B0 and Anniedale the interrupt line, disregarding
+	 * to have different numbers, is shared between HSU DMA and UART IPs.
+	 * Thus on such SoCs we are expecting that IRQ handler is called in
+	 * UART driver only. Instead of handling the spurious interrupt
+	 * from HSU DMA here and waste CPU time and delay HSU UART interrupt
+	 * handling, disable the interrupt entirely.
+	 */
+	if (pdev->device == PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA)
+		disable_irq_nosync(chip->irq);
+
 	pci_set_drvdata(pdev, chip);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/dma/imx-dma.c
+++ linux-ein-5.4.0/drivers/dma/imx-dma.c
@@ -832,6 +832,8 @@
 		dma_length += sg_dma_len(sg);
 	}
 
+	imxdma_config_write(chan, &imxdmac->config, direction);
+
 	switch (imxdmac->word_size) {
 	case DMA_SLAVE_BUSWIDTH_4_BYTES:
 		if (sg_dma_len(sgl) & 3 || sgl->dma_address & 3)
--- linux-ein-5.4.0.orig/drivers/dma/imx-sdma.c
+++ linux-ein-5.4.0/drivers/dma/imx-sdma.c
@@ -8,7 +8,8 @@
 //
 // Based on code from Freescale:
 //
-// Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+// Copyright 2004-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+// Copyright 2018 NXP.
 
 #include <linux/init.h>
 #include <linux/iopoll.h>
@@ -23,10 +24,12 @@
 #include <linux/semaphore.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
+#include <linux/genalloc.h>
 #include <linux/dma-mapping.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/dmaengine.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -74,6 +77,9 @@
 #define SDMA_CHNENBL0_IMX35	0x200
 #define SDMA_CHNENBL0_IMX31	0x080
 #define SDMA_CHNPRI_0		0x100
+#define SDMA_DONE0_CONFIG	0x1000
+#define SDMA_DONE0_CONFIG_DONE_SEL	0x7
+#define SDMA_DONE0_CONFIG_DONE_DIS	0x6
 
 /*
  * Buffer descriptor status values.
@@ -168,6 +174,8 @@
 #define SDMA_WATERMARK_LEVEL_SPDIF	BIT(10)
 #define SDMA_WATERMARK_LEVEL_SP		BIT(11)
 #define SDMA_WATERMARK_LEVEL_DP		BIT(12)
+#define SDMA_WATERMARK_LEVEL_SD		BIT(13)
+#define SDMA_WATERMARK_LEVEL_DD		BIT(14)
 #define SDMA_WATERMARK_LEVEL_HWML	(0xFF << 16)
 #define SDMA_WATERMARK_LEVEL_LWE	BIT(28)
 #define SDMA_WATERMARK_LEVEL_HWE	BIT(29)
@@ -175,12 +183,17 @@
 
 #define SDMA_DMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
 				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+				 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
 				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
 #define SDMA_DMA_DIRECTIONS	(BIT(DMA_DEV_TO_MEM) | \
 				 BIT(DMA_MEM_TO_DEV) | \
 				 BIT(DMA_DEV_TO_DEV))
 
+#define SDMA_WATERMARK_LEVEL_FIFOS_OFF	12
+#define SDMA_WATERMARK_LEVEL_SW_DONE	BIT(23)
+#define SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF 24
+
 /*
  * Mode/Count of data node descriptors - IPCv2
  */
@@ -360,6 +373,7 @@
 struct sdma_channel {
 	struct virt_dma_chan		vc;
 	struct sdma_desc		*desc;
+	struct list_head                terminated_node;
 	struct sdma_engine		*sdma;
 	unsigned int			channel;
 	enum dma_transfer_direction		direction;
@@ -377,9 +391,14 @@
 	unsigned long			watermark_level;
 	u32				shp_addr, per_addr;
 	enum dma_status			status;
-	bool				context_loaded;
 	struct imx_dma_data		data;
 	struct work_struct		terminate_worker;
+	bool				is_ram_script;
+	bool				src_dualfifo;
+	bool				dst_dualfifo;
+	unsigned int			fifo_num;
+	bool				sw_done;
+	u32				sw_done_sel;
 };
 
 #define IMX_DMA_SG_LOOP		BIT(0)
@@ -389,6 +408,15 @@
 #define MXC_SDMA_MIN_PRIORITY 1
 #define MXC_SDMA_MAX_PRIORITY 7
 
+/*
+ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are reserved and
+ * can't be accessed. Skip these register touch in suspend/resume. Also below
+ * two macros are only used on i.mx6sx.
+ */
+#define MXC_SDMA_RESERVED_REG (SDMA_CHNPRI_0 - SDMA_XTRIG_CONF2 - 4)
+#define MXC_SDMA_SAVED_REG_NUM (((SDMA_CHNENBL0_IMX35 + 4 * 48) - \
+				MXC_SDMA_RESERVED_REG) / 4)
+
 #define SDMA_FIRMWARE_MAGIC 0x414d4453
 
 /**
@@ -420,6 +448,15 @@
 	int num_events;
 	struct sdma_script_start_addrs	*script_addrs;
 	bool check_ratio;
+	/*
+	 * ecspi ERR009165 fixed should be done in sdma script
+	 * and it be fixed in soc from i.mx6ul.
+	 * please get more information from below link:
+	 * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
+	 */
+	bool ecspi_fixed;
+	bool has_done0;
+	bool pm_runtime;
 };
 
 struct sdma_engine {
@@ -427,9 +464,14 @@
 	struct device_dma_parameters	dma_parms;
 	struct sdma_channel		channel[MAX_DMA_CHANNELS];
 	struct sdma_channel_control	*channel_control;
+	u32				save_regs[MXC_SDMA_SAVED_REG_NUM];
+	u32				save_done0_regs[2];
+	const char			*fw_name;
 	void __iomem			*regs;
 	struct sdma_context_data	*context;
 	dma_addr_t			context_phys;
+	dma_addr_t			ccb_phys;
+	bool				is_on;
 	struct dma_device		dma_device;
 	struct clk			*clk_ipg;
 	struct clk			*clk_ahb;
@@ -444,12 +486,21 @@
 	struct sdma_buffer_descriptor	*bd0;
 	/* clock ratio for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/
 	bool				clk_ratio;
+	struct gen_pool			*iram_pool;
+	bool				fw_loaded;
+	u32				fw_fail;
+	unsigned short			ram_code_start;
 };
 
 static int sdma_config_write(struct dma_chan *chan,
 		       struct dma_slave_config *dmaengine_cfg,
 		       enum dma_transfer_direction direction);
 
+static int sdma_get_firmware(struct sdma_engine *sdma,
+		const char *fw_name);
+static int sdma_get_firmware_wait(struct sdma_engine *sdma,
+		const char *fw_name);
+
 static struct sdma_driver_data sdma_imx31 = {
 	.chnenbl0 = SDMA_CHNENBL0_IMX31,
 	.num_events = 32,
@@ -540,6 +591,31 @@
 	.script_addrs = &sdma_script_imx6q,
 };
 
+static struct sdma_script_start_addrs sdma_script_imx6sx = {
+	.ap_2_ap_addr = 642,
+	.uart_2_mcu_addr = 817,
+	.mcu_2_app_addr = 747,
+	.uartsh_2_mcu_addr = 1032,
+	.mcu_2_shp_addr = 960,
+	.app_2_mcu_addr = 683,
+	.shp_2_mcu_addr = 891,
+	.spdif_2_mcu_addr = 1100,
+	.mcu_2_spdif_addr = 1134,
+};
+
+static struct sdma_driver_data sdma_imx6sx = {
+	.chnenbl0 = SDMA_CHNENBL0_IMX35,
+	.num_events = 48,
+	.script_addrs = &sdma_script_imx6sx,
+};
+
+static struct sdma_driver_data sdma_imx6ul = {
+	.chnenbl0 = SDMA_CHNENBL0_IMX35,
+	.num_events = 48,
+	.script_addrs = &sdma_script_imx6sx,
+	.ecspi_fixed = true,
+};
+
 static struct sdma_script_start_addrs sdma_script_imx7d = {
 	.ap_2_ap_addr = 644,
 	.uart_2_mcu_addr = 819,
@@ -565,6 +641,16 @@
 	.check_ratio = 1,
 };
 
+static struct sdma_driver_data sdma_imx8mp = {
+	.chnenbl0 = SDMA_CHNENBL0_IMX35,
+	.num_events = 48,
+	.script_addrs = &sdma_script_imx7d,
+	.check_ratio = 1,
+	.ecspi_fixed = true,
+	.has_done0 = true,
+/*	.pm_runtime = true, */
+};
+
 static const struct platform_device_id sdma_devtypes[] = {
 	{
 		.name = "imx25-sdma",
@@ -585,12 +671,21 @@
 		.name = "imx6q-sdma",
 		.driver_data = (unsigned long)&sdma_imx6q,
 	}, {
+		.name = "imx6sx-sdma",
+		.driver_data = (unsigned long)&sdma_imx6sx,
+	}, {
 		.name = "imx7d-sdma",
 		.driver_data = (unsigned long)&sdma_imx7d,
 	}, {
+		.name = "imx6ul-sdma",
+		.driver_data = (unsigned long)&sdma_imx6ul,
+	}, {
 		.name = "imx8mq-sdma",
 		.driver_data = (unsigned long)&sdma_imx8mq,
 	}, {
+		.name = "imx8mp-sdma",
+		.driver_data = (unsigned long)&sdma_imx8mp,
+	}, {
 		/* sentinel */
 	}
 };
@@ -603,8 +698,11 @@
 	{ .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
 	{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
 	{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
+	{ .compatible = "fsl,imx6sx-sdma", .data = &sdma_imx6sx, },
 	{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
+	{ .compatible = "fsl,imx6ul-sdma", .data = &sdma_imx6ul, },
 	{ .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8mq, },
+	{ .compatible = "fsl,imx8mp-sdma", .data = &sdma_imx8mp, },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdma_dt_ids);
@@ -656,6 +754,11 @@
 	return 0;
 }
 
+static int is_sdma_channel_enabled(struct sdma_engine *sdma, int channel)
+{
+	return !!(readl(sdma->regs + SDMA_H_STATSTOP) & BIT(channel));
+}
+
 static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
 {
 	writel(BIT(channel), sdma->regs + SDMA_H_START);
@@ -672,7 +775,7 @@
 	sdma_enable_channel(sdma, 0);
 
 	ret = readl_relaxed_poll_timeout_atomic(sdma->regs + SDMA_H_STATSTOP,
-						reg, !(reg & 1), 1, 500);
+						reg, !(reg & 1), 1, 5000);
 	if (ret)
 		dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
 
@@ -695,10 +798,10 @@
 	int ret;
 	unsigned long flags;
 
-	buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys, GFP_KERNEL);
-	if (!buf_virt) {
+	buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys,
+					      GFP_KERNEL);
+	if (!buf_virt)
 		return -ENOMEM;
-	}
 
 	spin_lock_irqsave(&sdma->channel_0_lock, flags);
 
@@ -729,6 +832,21 @@
 	val = readl_relaxed(sdma->regs + chnenbl);
 	__set_bit(channel, &val);
 	writel_relaxed(val, sdma->regs + chnenbl);
+
+	/* Set SDMA_DONEx_CONFIG is sw_done enabled */
+	if (sdmac->sw_done) {
+		u32 offset = SDMA_DONE0_CONFIG + sdmac->sw_done_sel / 4;
+		u32 done_sel = SDMA_DONE0_CONFIG_DONE_SEL +
+				((sdmac->sw_done_sel % 4) << 3);
+		u32 sw_done_dis = SDMA_DONE0_CONFIG_DONE_DIS +
+				((sdmac->sw_done_sel % 4) << 3);
+
+		val = readl_relaxed(sdma->regs + offset);
+		__set_bit(done_sel, &val);
+		__clear_bit(sw_done_dis, &val);
+		writel_relaxed(val, sdma->regs + offset);
+	}
+
 }
 
 static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -802,7 +920,6 @@
 		*/
 
 		desc->chn_real_count = bd->mode.count;
-		bd->mode.status |= BD_DONE;
 		bd->mode.count = desc->period_len;
 		desc->buf_ptail = desc->buf_tail;
 		desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
@@ -817,9 +934,21 @@
 		dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
 		spin_lock(&sdmac->vc.lock);
 
+		/* Assign buffer ownership to SDMA */
+		bd->mode.status |= BD_DONE;
+
 		if (error)
 			sdmac->status = old_status;
 	}
+
+	/*
+	 * SDMA stops cyclic channel when DMA request triggers a channel and no SDMA
+	 * owned buffer is available (i.e. BD_DONE was set too late).
+	 */
+	if (sdmac->desc && !is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
+		dev_warn(sdmac->sdma->dev, "restart cyclic channel %d\n", sdmac->channel);
+		sdma_enable_channel(sdmac->sdma, sdmac->channel);
+	}
 }
 
 static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
@@ -852,6 +981,9 @@
 	struct sdma_engine *sdma = dev_id;
 	unsigned long stat;
 
+	clk_enable(sdma->clk_ipg);
+	clk_enable(sdma->clk_ahb);
+
 	stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
 	writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
 	/* channel 0 is special and not handled here, see run_channel0() */
@@ -866,7 +998,10 @@
 		desc = sdmac->desc;
 		if (desc) {
 			if (sdmac->flags & IMX_DMA_SG_LOOP) {
-				sdma_update_channel_loop(sdmac);
+				if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+					sdma_update_channel_loop(sdmac);
+				else
+					vchan_cyclic_callback(&desc->vd);
 			} else {
 				mxc_sdma_handle_channel_normal(sdmac);
 				vchan_cookie_complete(&desc->vd);
@@ -878,6 +1013,9 @@
 		__clear_bit(channel, &stat);
 	}
 
+	clk_disable(sdma->clk_ipg);
+	clk_disable(sdma->clk_ahb);
+
 	return IRQ_HANDLED;
 }
 
@@ -925,6 +1063,10 @@
 		emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
 		break;
 	case IMX_DMATYPE_CSPI:
+		per_2_emi = sdma->script_addrs->app_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr;
+		sdmac->is_ram_script = true;
+		break;
 	case IMX_DMATYPE_EXT:
 	case IMX_DMATYPE_SSI:
 	case IMX_DMATYPE_SAI:
@@ -934,6 +1076,7 @@
 	case IMX_DMATYPE_SSI_DUAL:
 		per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
 		emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
+		sdmac->is_ram_script = true;
 		break;
 	case IMX_DMATYPE_SSI_SP:
 	case IMX_DMATYPE_MMC:
@@ -948,11 +1091,13 @@
 		per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
 		emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
 		per_2_per = sdma->script_addrs->per_2_per_addr;
+		sdmac->is_ram_script = true;
 		break;
 	case IMX_DMATYPE_ASRC_SP:
 		per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
 		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
 		per_2_per = sdma->script_addrs->per_2_per_addr;
+		sdmac->is_ram_script = true;
 		break;
 	case IMX_DMATYPE_MSHC:
 		per_2_emi = sdma->script_addrs->mshc_2_mcu_addr;
@@ -968,6 +1113,14 @@
 	case IMX_DMATYPE_IPU_MEMORY:
 		emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
 		break;
+	case IMX_DMATYPE_HDMI:
+		emi_2_per = sdma->script_addrs->hdmi_dma_addr;
+		sdmac->is_ram_script = true;
+		break;
+	case IMX_DMATYPE_MULTI_SAI:
+		per_2_emi = sdma->script_addrs->sai_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_sai_addr;
+		sdmac->is_ram_script = true;
 	default:
 		break;
 	}
@@ -988,9 +1141,6 @@
 	int ret;
 	unsigned long flags;
 
-	if (sdmac->context_loaded)
-		return 0;
-
 	if (sdmac->direction == DMA_DEV_TO_MEM)
 		load_address = sdmac->pc_from_device;
 	else if (sdmac->direction == DMA_DEV_TO_DEV)
@@ -1018,11 +1168,16 @@
 	/* Send by context the event mask,base address for peripheral
 	 * and watermark level
 	 */
-	context->gReg[0] = sdmac->event_mask[1];
-	context->gReg[1] = sdmac->event_mask[0];
-	context->gReg[2] = sdmac->per_addr;
-	context->gReg[6] = sdmac->shp_addr;
-	context->gReg[7] = sdmac->watermark_level;
+	if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+		context->gReg[4] = sdmac->per_addr;
+		context->gReg[6] = sdmac->shp_addr;
+	} else {
+		context->gReg[0] = sdmac->event_mask[1];
+		context->gReg[1] = sdmac->event_mask[0];
+		context->gReg[2] = sdmac->per_addr;
+		context->gReg[6] = sdmac->shp_addr;
+		context->gReg[7] = sdmac->watermark_level;
+	}
 
 	bd0->mode.command = C0_SETDM;
 	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
@@ -1033,7 +1188,30 @@
 
 	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
 
-	sdmac->context_loaded = true;
+	return ret;
+}
+
+static int sdma_save_restore_context(struct sdma_engine *sdma, bool save)
+{
+	struct sdma_context_data *context = sdma->context;
+	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&sdma->channel_0_lock, flags);
+
+	if (save)
+		bd0->mode.command = C0_GETDM;
+	else
+		bd0->mode.command = C0_SETDM;
+
+	bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
+	bd0->mode.count = MAX_DMA_CHANNELS * sizeof(*context) / 4;
+	bd0->buffer_addr = sdma->context_phys;
+	bd0->ext_buffer_addr = 2048;
+	ret = sdma_run_channel0(sdma);
+
+	spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
 
 	return ret;
 }
@@ -1058,9 +1236,6 @@
 {
 	struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
 						  terminate_worker);
-	unsigned long flags;
-	LIST_HEAD(head);
-
 	/*
 	 * 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
@@ -1069,22 +1244,25 @@
 	 */
 	usleep_range(1000, 2000);
 
-	spin_lock_irqsave(&sdmac->vc.lock, flags);
-	vchan_get_all_descriptors(&sdmac->vc, &head);
-	sdmac->desc = NULL;
-	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
-	vchan_dma_desc_free_list(&sdmac->vc, &head);
-	sdmac->context_loaded = false;
+	vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated_node);
 }
 
 static int sdma_disable_channel_async(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	unsigned long flags;
 
 	sdma_disable_channel(chan);
 
-	if (sdmac->desc)
+	spin_lock_irqsave(&sdmac->vc.lock, flags);
+	if (sdmac->desc) {
+		vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated_node);
+		sdmac->desc = NULL;
+		spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 		schedule_work(&sdmac->terminate_worker);
+		return 0;
+	}
+	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 
 	return 0;
 }
@@ -1136,12 +1314,36 @@
 		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP;
 
 	sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
+
+	if (sdmac->src_dualfifo)
+		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SD;
+	if (sdmac->dst_dualfifo)
+		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DD;
+}
+
+static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
+{
+	sdmac->watermark_level &= ~(0xFF << SDMA_WATERMARK_LEVEL_FIFOS_OFF |
+				    SDMA_WATERMARK_LEVEL_SW_DONE |
+				    0xf << SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF);
+
+	if (sdmac->sw_done)
+		sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE |
+			sdmac->sw_done_sel <<
+			SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF;
+
+	/* For fifo_num
+	 * bit 12-15 is the fifo number;
+	 * bit 16-19 is the fifo offset,
+	 * so here only need to shift left fifo_num 12 bit for watermake_level
+	 */
+	sdmac->watermark_level |= sdmac->fifo_num<<
+				SDMA_WATERMARK_LEVEL_FIFOS_OFF;
 }
 
 static int sdma_config_channel(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
-	int ret;
 
 	sdma_disable_channel(chan);
 
@@ -1171,8 +1373,21 @@
 			if (sdmac->peripheral_type == IMX_DMATYPE_ASRC_SP ||
 			    sdmac->peripheral_type == IMX_DMATYPE_ASRC)
 				sdma_set_watermarklevel_for_p2p(sdmac);
-		} else
+		} else {
+			/*
+			 * ERR009165 fixed from i.mx6ul, no errata need,
+			 * set bit31 to let sdma script skip the errata.
+			 */
+			if (sdmac->peripheral_type == IMX_DMATYPE_CSPI &&
+			    sdmac->direction == DMA_MEM_TO_DEV &&
+			    sdmac->sdma->drvdata->ecspi_fixed)
+				__set_bit(31, &sdmac->watermark_level);
+			else if (sdmac->peripheral_type ==
+					IMX_DMATYPE_MULTI_SAI)
+				sdma_set_watermarklevel_for_sais(sdmac);
+
 			__set_bit(sdmac->event_id0, sdmac->event_mask);
+		}
 
 		/* Address */
 		sdmac->shp_addr = sdmac->per_address;
@@ -1181,9 +1396,7 @@
 		sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
 	}
 
-	ret = sdma_load_context(sdmac);
-
-	return ret;
+	return 0;
 }
 
 static int sdma_set_channel_priority(struct sdma_channel *sdmac,
@@ -1206,8 +1419,14 @@
 {
 	int ret = -EBUSY;
 
-	sdma->bd0 = dma_alloc_coherent(sdma->dev, PAGE_SIZE, &sdma->bd0_phys,
-					GFP_NOWAIT);
+	if (sdma->iram_pool)
+		sdma->bd0 = gen_pool_dma_alloc(sdma->iram_pool,
+					sizeof(struct sdma_buffer_descriptor),
+					&sdma->bd0_phys);
+	else
+		sdma->bd0 = dma_alloc_coherent(sdma->dev,
+					sizeof(struct sdma_buffer_descriptor),
+					&sdma->bd0_phys, GFP_NOWAIT);
 	if (!sdma->bd0) {
 		ret = -ENOMEM;
 		goto out;
@@ -1227,10 +1446,15 @@
 static int sdma_alloc_bd(struct sdma_desc *desc)
 {
 	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+	struct sdma_engine *sdma = desc->sdmac->sdma;
 	int ret = 0;
 
-	desc->bd = dma_alloc_coherent(desc->sdmac->sdma->dev, bd_size,
-				       &desc->bd_phys, GFP_NOWAIT);
+	if (sdma->iram_pool)
+		desc->bd = gen_pool_dma_alloc(sdma->iram_pool, bd_size,
+					      &desc->bd_phys);
+	else
+		desc->bd = dma_alloc_coherent(sdma->dev, bd_size,
+					      &desc->bd_phys, GFP_NOWAIT);
 	if (!desc->bd) {
 		ret = -ENOMEM;
 		goto out;
@@ -1242,9 +1466,14 @@
 static void sdma_free_bd(struct sdma_desc *desc)
 {
 	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+	struct sdma_engine *sdma = desc->sdmac->sdma;
 
-	dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd,
-			  desc->bd_phys);
+	if (sdma->iram_pool)
+		gen_pool_free(sdma->iram_pool, (unsigned long)desc->bd,
+			      bd_size);
+	else
+		dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd,
+				  desc->bd_phys);
 }
 
 static void sdma_desc_free(struct virt_dma_desc *vd)
@@ -1255,6 +1484,91 @@
 	kfree(desc);
 }
 
+static int sdma_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sdma_engine *sdma = platform_get_drvdata(pdev);
+
+	sdma->fw_loaded = false;
+	sdma->is_on = false;
+
+	clk_disable(sdma->clk_ipg);
+	clk_disable(sdma->clk_ahb);
+
+	/* free channel0 bd */
+	if (sdma->iram_pool)
+		gen_pool_free(sdma->iram_pool, (unsigned long)sdma->bd0,
+			      sizeof(struct sdma_buffer_descriptor));
+	else
+		dma_free_coherent(sdma->dev,
+				  sizeof(struct sdma_buffer_descriptor),
+				  sdma->bd0, sdma->bd0_phys);
+
+	return 0;
+}
+
+static int sdma_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sdma_engine *sdma = platform_get_drvdata(pdev);
+	int i, ret;
+
+	ret = clk_enable(sdma->clk_ipg);
+	if (ret)
+		return ret;
+	ret = clk_enable(sdma->clk_ahb);
+	if (ret)
+		goto disable_clk_ipg;
+
+	/* Be sure SDMA has not started yet */
+	writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
+
+	/* disable all channels */
+	for (i = 0; i < sdma->drvdata->num_events; i++)
+		writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
+
+	/* All channels have priority 0 */
+	for (i = 0; i < MAX_DMA_CHANNELS; i++)
+		writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+
+	ret = sdma_request_channel0(sdma);
+	if (ret)
+		return ret;
+
+	sdma_config_ownership(&sdma->channel[0], false, true, false);
+
+	/* Set Command Channel (Channel Zero) */
+	writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
+
+	/* Set bits of CONFIG register but with static context switching */
+	if (sdma->clk_ratio)
+		writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG);
+	else
+		writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
+
+	writel_relaxed(sdma->ccb_phys, sdma->regs + SDMA_H_C0PTR);
+
+	/* Initializes channel's priorities */
+	sdma_set_channel_priority(&sdma->channel[0], 7);
+
+	if (sdma->drvdata->pm_runtime)
+		ret = sdma_get_firmware_wait(sdma, sdma->fw_name);
+	else
+		ret = sdma_get_firmware(sdma, sdma->fw_name);
+	if (ret)
+		dev_warn(sdma->dev, "failed to get firmware.\n");
+
+	sdma->is_on = true;
+
+	return 0;
+
+disable_clk_ipg:
+	clk_disable(sdma->clk_ipg);
+	dev_err(sdma->dev, "initialisation failed with %d\n", ret);
+
+	return ret;
+}
+
 static int sdma_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
@@ -1298,25 +1612,21 @@
 	sdmac->peripheral_type = data->peripheral_type;
 	sdmac->event_id0 = data->dma_request;
 	sdmac->event_id1 = data->dma_request2;
+	sdmac->src_dualfifo = data->src_dualfifo;
+	sdmac->dst_dualfifo = data->dst_dualfifo;
+	/* Get software done selector if sw_done enabled */
+	if (data->done_sel & BIT(31)) {
+		sdmac->sw_done = true;
+		sdmac->sw_done_sel = (data->done_sel >> 8) & 0xff;
+	}
 
-	ret = clk_enable(sdmac->sdma->clk_ipg);
-	if (ret)
-		return ret;
-	ret = clk_enable(sdmac->sdma->clk_ahb);
-	if (ret)
-		goto disable_clk_ipg;
+	pm_runtime_get_sync(sdmac->sdma->dev);
 
 	ret = sdma_set_channel_priority(sdmac, prio);
 	if (ret)
-		goto disable_clk_ahb;
+		return ret;
 
 	return 0;
-
-disable_clk_ahb:
-	clk_disable(sdmac->sdma->clk_ahb);
-disable_clk_ipg:
-	clk_disable(sdmac->sdma->clk_ipg);
-	return ret;
 }
 
 static void sdma_free_chan_resources(struct dma_chan *chan)
@@ -1328,8 +1638,9 @@
 
 	sdma_channel_synchronize(chan);
 
-	if (sdmac->event_id0)
+	if (sdmac->event_id0 >= 0)
 		sdma_event_disable(sdmac, sdmac->event_id0);
+
 	if (sdmac->event_id1)
 		sdma_event_disable(sdmac, sdmac->event_id1);
 
@@ -1338,8 +1649,7 @@
 
 	sdma_set_channel_priority(sdmac, 0);
 
-	clk_disable(sdma->clk_ipg);
-	clk_disable(sdma->clk_ahb);
+	pm_runtime_put_sync(sdma->dev);
 }
 
 static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
@@ -1347,6 +1657,11 @@
 {
 	struct sdma_desc *desc;
 
+	if (!sdmac->sdma->fw_loaded && sdmac->is_ram_script) {
+		dev_err(sdmac->sdma->dev, "sdma firmware not ready!\n");
+		goto err_out;
+	}
+
 	desc = kzalloc((sizeof(*desc)), GFP_NOWAIT);
 	if (!desc)
 		goto err_out;
@@ -1362,7 +1677,7 @@
 	desc->sdmac = sdmac;
 	desc->num_bd = bds;
 
-	if (sdma_alloc_bd(desc))
+	if (bds && sdma_alloc_bd(desc))
 		goto err_desc_out;
 
 	/* No slave_config called in MEMCPY case, so do here */
@@ -1370,10 +1685,12 @@
 		sdma_config_ownership(sdmac, false, true, false);
 
 	if (sdma_load_context(sdmac))
-		goto err_desc_out;
+		goto err_bd_out;
 
 	return desc;
 
+err_bd_out:
+	sdma_free_bd(desc);
 err_desc_out:
 	kfree(desc);
 err_out:
@@ -1483,6 +1800,9 @@
 			if (count & 3 || sg->dma_address & 3)
 				goto err_bd_out;
 			break;
+		case DMA_SLAVE_BUSWIDTH_3_BYTES:
+			bd->mode.command = 3;
+			break;
 		case DMA_SLAVE_BUSWIDTH_2_BYTES:
 			bd->mode.command = 2;
 			if (count & 1 || sg->dma_address & 1)
@@ -1527,13 +1847,16 @@
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
-	int num_periods = buf_len / period_len;
+	int num_periods = 0;
 	int channel = sdmac->channel;
 	int i = 0, buf = 0;
 	struct sdma_desc *desc;
 
 	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
 
+	if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+		num_periods = buf_len / period_len;
+
 	sdma_config_write(chan, &sdmac->slave_config, direction);
 
 	desc = sdma_transfer_init(sdmac, direction, num_periods);
@@ -1550,6 +1873,9 @@
 		goto err_bd_out;
 	}
 
+	if (sdmac->peripheral_type == IMX_DMATYPE_HDMI)
+		return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+
 	while (buf < buf_len) {
 		struct sdma_buffer_descriptor *bd = &desc->bd[i];
 		int param;
@@ -1597,11 +1923,15 @@
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 
+	sdmac->watermark_level = 0;
+	sdmac->is_ram_script = false;
+
 	if (direction == DMA_DEV_TO_MEM) {
 		sdmac->per_address = dmaengine_cfg->src_addr;
 		sdmac->watermark_level = dmaengine_cfg->src_maxburst *
 			dmaengine_cfg->src_addr_width;
 		sdmac->word_size = dmaengine_cfg->src_addr_width;
+		sdmac->fifo_num =  dmaengine_cfg->src_fifo_num;
 	} else if (direction == DMA_DEV_TO_DEV) {
 		sdmac->per_address2 = dmaengine_cfg->src_addr;
 		sdmac->per_address = dmaengine_cfg->dst_addr;
@@ -1610,11 +1940,16 @@
 		sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
 			SDMA_WATERMARK_LEVEL_HWML;
 		sdmac->word_size = dmaengine_cfg->dst_addr_width;
+	} else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+			sdmac->per_address = dmaengine_cfg->dst_addr;
+			sdmac->per_address2 = dmaengine_cfg->src_addr;
+			sdmac->watermark_level = 0;
 	} else {
 		sdmac->per_address = dmaengine_cfg->dst_addr;
 		sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
 			dmaengine_cfg->dst_addr_width;
 		sdmac->word_size = dmaengine_cfg->dst_addr_width;
+		sdmac->fifo_num =  dmaengine_cfg->dst_fifo_num;
 	}
 	sdmac->direction = direction;
 	return sdma_config_channel(chan);
@@ -1628,7 +1963,7 @@
 	memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
 
 	/* Set ENBLn earlier to make sure dma request triggered after that */
-	if (sdmac->event_id0) {
+	if (sdmac->event_id0 >= 0) {
 		if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
 			return -EINVAL;
 		sdma_event_enable(sdmac, sdmac->event_id0);
@@ -1693,8 +2028,8 @@
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2	38
-#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3	41
-#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4	42
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3	45
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4	46
 
 static void sdma_add_scripts(struct sdma_engine *sdma,
 		const struct sdma_script_start_addrs *addr)
@@ -1728,12 +2063,21 @@
 	unsigned short *ram_code;
 
 	if (!fw) {
-		dev_info(sdma->dev, "external firmware not found, using ROM firmware\n");
-		/* In this case we just use the ROM firmware. */
+		/* Load firmware once more time if timeout */
+		if (sdma->fw_fail)
+			dev_info(sdma->dev, "external firmware not found, using ROM firmware\n");
+		else {
+			request_firmware_nowait(THIS_MODULE,
+					FW_ACTION_HOTPLUG, sdma->fw_name,
+					sdma->dev, GFP_KERNEL, sdma,
+					sdma_load_firmware);
+			sdma->fw_fail++;
+		}
+
 		return;
 	}
 
-	if (fw->size < sizeof(*header))
+	if (fw->size < sizeof(*header) || sdma->fw_loaded)
 		goto err_firmware;
 
 	header = (struct sdma_firmware_header *)fw->data;
@@ -1762,19 +2106,18 @@
 
 	addr = (void *)header + header->script_addrs_start;
 	ram_code = (void *)header + header->ram_code_start;
+	sdma->ram_code_start = header->ram_code_start;
 
-	clk_enable(sdma->clk_ipg);
-	clk_enable(sdma->clk_ahb);
 	/* download the RAM image for SDMA */
 	sdma_load_script(sdma, ram_code,
 			header->ram_code_size,
 			addr->ram_code_start_addr);
-	clk_disable(sdma->clk_ipg);
-	clk_disable(sdma->clk_ahb);
 
 	sdma_add_scripts(sdma, addr);
 
-	dev_info(sdma->dev, "loaded firmware %d.%d\n",
+	sdma->fw_loaded = true;
+
+	dev_info_once(sdma->dev, "loaded firmware %d.%d\n",
 			header->version_major,
 			header->version_minor);
 
@@ -1794,7 +2137,7 @@
 	u32 reg, val, shift, num_map, i;
 	int ret = 0;
 
-	if (IS_ERR(np) || IS_ERR(gpr_np))
+	if (IS_ERR(np) || !gpr_np)
 		goto out;
 
 	event_remap = of_find_property(np, propname, NULL);
@@ -1842,7 +2185,7 @@
 	}
 
 out:
-	if (!IS_ERR(gpr_np))
+	if (gpr_np)
 		of_node_put(gpr_np);
 
 	return ret;
@@ -1860,79 +2203,51 @@
 	return ret;
 }
 
-static int sdma_init(struct sdma_engine *sdma)
+static int sdma_get_firmware_wait(struct sdma_engine *sdma,
+		const char *fw_name)
 {
-	int i, ret;
-	dma_addr_t ccb_phys;
+	const struct firmware *fw = NULL;
+	int ret;
 
-	ret = clk_enable(sdma->clk_ipg);
-	if (ret)
+	ret = request_firmware(&fw, fw_name, sdma->dev);
+	if (ret < 0 || !fw) {
+		dev_err(sdma->dev, "unable to find firmware\n");
 		return ret;
-	ret = clk_enable(sdma->clk_ahb);
-	if (ret)
-		goto disable_clk_ipg;
+	}
+
+	sdma_load_firmware(fw, (void *)sdma);
+
+	return 0;
+}
+
+static int sdma_init_sw(struct sdma_engine *sdma)
+{
+	int ret, ccbsize;
 
 	if (sdma->drvdata->check_ratio &&
 	    (clk_get_rate(sdma->clk_ahb) == clk_get_rate(sdma->clk_ipg)))
 		sdma->clk_ratio = 1;
 
-	/* Be sure SDMA has not started yet */
-	writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
-
-	sdma->channel_control = dma_alloc_coherent(sdma->dev,
-			MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
-			sizeof(struct sdma_context_data),
-			&ccb_phys, GFP_KERNEL);
+	ccbsize = MAX_DMA_CHANNELS * (sizeof(struct sdma_channel_control)
+		+ sizeof(struct sdma_context_data));
 
+	if (sdma->iram_pool)
+		sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool,
+							   ccbsize, &sdma->ccb_phys);
+	else
+		sdma->channel_control = dma_alloc_coherent(sdma->dev, ccbsize,
+						&sdma->ccb_phys, GFP_KERNEL);
 	if (!sdma->channel_control) {
 		ret = -ENOMEM;
-		goto err_dma_alloc;
+		return ret;
 	}
 
 	sdma->context = (void *)sdma->channel_control +
 		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
-	sdma->context_phys = ccb_phys +
+	sdma->context_phys = sdma->ccb_phys +
 		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
 
-	/* disable all channels */
-	for (i = 0; i < sdma->drvdata->num_events; i++)
-		writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
-
-	/* All channels have priority 0 */
-	for (i = 0; i < MAX_DMA_CHANNELS; i++)
-		writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
-
-	ret = sdma_request_channel0(sdma);
-	if (ret)
-		goto err_dma_alloc;
-
-	sdma_config_ownership(&sdma->channel[0], false, true, false);
-
-	/* Set Command Channel (Channel Zero) */
-	writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
-
-	/* Set bits of CONFIG register but with static context switching */
-	if (sdma->clk_ratio)
-		writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG);
-	else
-		writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
-
-	writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
-
-	/* Initializes channel's priorities */
-	sdma_set_channel_priority(&sdma->channel[0], 7);
-
-	clk_disable(sdma->clk_ipg);
-	clk_disable(sdma->clk_ahb);
-
 	return 0;
-
-err_dma_alloc:
-	clk_disable(sdma->clk_ahb);
-disable_clk_ipg:
-	clk_disable(sdma->clk_ipg);
-	dev_err(sdma->dev, "initialisation failed with %d\n", ret);
-	return ret;
 }
 
 static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
@@ -1959,9 +2274,14 @@
 	if (dma_spec->args_count != 3)
 		return NULL;
 
+	memset(&data, 0, sizeof(data));
+
 	data.dma_request = dma_spec->args[0];
 	data.peripheral_type = dma_spec->args[1];
-	data.priority = dma_spec->args[2];
+	/* Get sw_done setting if sw_done enabled */
+	if (dma_spec->args[2] & BIT(31))
+		data.done_sel = dma_spec->args[2];
+	data.priority = dma_spec->args[2] & 0xff;
 	/*
 	 * init dma_request2 to zero, which is not used by the dts.
 	 * For P2P, dma_request2 is init from dma_request_channel(),
@@ -2071,6 +2391,7 @@
 
 		sdmac->channel = i;
 		sdmac->vc.desc_free = sdma_desc_free;
+		INIT_LIST_HEAD(&sdmac->terminated_node);
 		INIT_WORK(&sdmac->terminate_worker,
 				sdma_channel_terminate_work);
 		/*
@@ -2082,7 +2403,13 @@
 			vchan_init(&sdmac->vc, &sdma->dma_device);
 	}
 
-	ret = sdma_init(sdma);
+	if (np) {
+		sdma->iram_pool = of_gen_pool_get(np, "iram", 0);
+		if (sdma->iram_pool)
+			dev_info(&pdev->dev, "alloc bd from iram.\n");
+	}
+
+	ret = sdma_init_sw(sdma);
 	if (ret)
 		goto err_init;
 
@@ -2139,16 +2466,8 @@
 		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");
+		sdma->fw_name = pdata->fw_name;
 	} else {
 		/*
 		 * Because that device tree does not encode ROM script address,
@@ -2157,15 +2476,16 @@
 		 */
 		ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
 					      &fw_name);
-		if (ret) {
+		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");
-		}
+		else
+			sdma->fw_name = fw_name;
 	}
 
+	pm_runtime_enable(&pdev->dev);
+	if (!sdma->drvdata->pm_runtime)
+		pm_runtime_get_sync(&pdev->dev);
+
 	return 0;
 
 err_register:
@@ -2187,6 +2507,7 @@
 	devm_free_irq(&pdev->dev, sdma->irq, sdma);
 	dma_async_device_unregister(&sdma->dma_device);
 	kfree(sdma->script_addrs);
+	pm_runtime_put_sync_suspend(sdma->dev);
 	clk_unprepare(sdma->clk_ahb);
 	clk_unprepare(sdma->clk_ipg);
 	/* Kill the tasklet */
@@ -2201,10 +2522,131 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sdma_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sdma_engine *sdma = platform_get_drvdata(pdev);
+	int i, ret = 0;
+
+	/* Do nothing if not i.MX6SX or i.MX7D, i.MX8MP */
+	if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
+	   && sdma->drvdata != &sdma_imx6ul && sdma->drvdata != &sdma_imx8mp)
+		return 0;
+
+	if (!sdma->is_on)
+		return 0;
+
+	ret = sdma_save_restore_context(sdma, true);
+	if (ret) {
+		dev_err(sdma->dev, "save context error!\n");
+		return ret;
+	}
+
+	/* save regs */
+	for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
+		/*
+		 * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
+		 * reserved and can't be touched. Skip these regs.
+		 */
+		if (i > SDMA_XTRIG_CONF2 / 4)
+			sdma->save_regs[i] = readl_relaxed(sdma->regs +
+							   MXC_SDMA_RESERVED_REG
+							   + 4 * i);
+		else
+			sdma->save_regs[i] = readl_relaxed(sdma->regs + 4 * i);
+	}
+
+	if (sdma->drvdata->has_done0) {
+		for (i = 0; i < 2; i++)
+			sdma->save_done0_regs[i] =
+			readl_relaxed(sdma->regs + SDMA_DONE0_CONFIG + 4 * i);
+	}
+
+	return 0;
+}
+
+static int sdma_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sdma_engine *sdma = platform_get_drvdata(pdev);
+	unsigned long timeout = jiffies + msecs_to_jiffies(2);
+	int i, ret;
+
+	/* Do nothing if not i.MX6SX or i.MX7D, i.MX8MP*/
+	if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
+	    && sdma->drvdata != &sdma_imx6ul && sdma->drvdata != &sdma_imx8mp)
+		return 0;
+
+	if (!sdma->is_on)
+		return 0;
+
+	/* Do nothing if mega/fast mix not turned off */
+	if (readl_relaxed(sdma->regs + SDMA_H_C0PTR))
+		return 0;
+
+	/* Firmware was lost, mark as "not ready" */
+	sdma->fw_loaded = false;
+
+	/* restore regs and load firmware */
+	for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
+		/*
+		 * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
+		 * reserved and can't be touched. Skip these regs.
+		 */
+		if (i > SDMA_XTRIG_CONF2 / 4)
+			writel_relaxed(sdma->save_regs[i], sdma->regs +
+				       MXC_SDMA_RESERVED_REG + 4 * i);
+		/* set static context switch  mode before channel0 running */
+		else if (i == SDMA_H_CONFIG / 4)
+			writel_relaxed(sdma->save_regs[i] & ~SDMA_H_CONFIG_CSM,
+					sdma->regs + SDMA_H_CONFIG);
+		else
+			writel_relaxed(sdma->save_regs[i], sdma->regs + 4 * i);
+	}
+
+	/* restore SDMA_DONEx_CONFIG */
+	if (sdma->drvdata->has_done0) {
+		for (i = 0; i < 2; i++)
+			writel_relaxed(sdma->save_done0_regs[i],
+				sdma->regs + SDMA_DONE0_CONFIG + 4 * i);
+	}
+
+	/* prepare priority for channel0 to start */
+	sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_MAX_PRIORITY);
+
+	ret = sdma_get_firmware(sdma, sdma->fw_name);
+	if (ret) {
+		dev_warn(&pdev->dev, "failed to get firmware\n");
+		return ret;
+	}
+	/* wait firmware loaded */
+	do {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(&pdev->dev, "failed to load firmware\n");
+			break;
+		}
+		usleep_range(50, 500);
+	} while (!sdma->fw_loaded);
+
+	ret = sdma_save_restore_context(sdma, false);
+	if (ret)
+		dev_err(sdma->dev, "restore context error!\n");
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops sdma_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(sdma_suspend, sdma_resume)
+	SET_RUNTIME_PM_OPS(sdma_runtime_suspend, sdma_runtime_resume, NULL)
+};
+
 static struct platform_driver sdma_driver = {
 	.driver		= {
 		.name	= "imx-sdma",
 		.of_match_table = sdma_dt_ids,
+		.pm = &sdma_pm_ops,
 	},
 	.id_table	= sdma_devtypes,
 	.remove		= sdma_remove,
@@ -2218,7 +2660,7 @@
 #if IS_ENABLED(CONFIG_SOC_IMX6Q)
 MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
 #endif
-#if IS_ENABLED(CONFIG_SOC_IMX7D)
+#if IS_ENABLED(CONFIG_SOC_IMX7D) || IS_ENABLED(CONFIG_SOC_IMX8M)
 MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
 #endif
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/dma/ioat/dma.c
+++ linux-ein-5.4.0/drivers/dma/ioat/dma.c
@@ -26,6 +26,18 @@
 
 #include "../dmaengine.h"
 
+int completion_timeout = 200;
+module_param(completion_timeout, int, 0644);
+MODULE_PARM_DESC(completion_timeout,
+		"set ioat completion timeout [msec] (default 200 [msec])");
+int idle_timeout = 2000;
+module_param(idle_timeout, int, 0644);
+MODULE_PARM_DESC(idle_timeout,
+		"set ioat idel timeout [msec] (default 2000 [msec])");
+
+#define IDLE_TIMEOUT msecs_to_jiffies(idle_timeout)
+#define COMPLETION_TIMEOUT msecs_to_jiffies(completion_timeout)
+
 static char *chanerr_str[] = {
 	"DMA Transfer Source Address Error",
 	"DMA Transfer Destination Address Error",
@@ -377,10 +389,11 @@
 
 		descs->virt = dma_alloc_coherent(to_dev(ioat_chan),
 						 SZ_2M, &descs->hw, flags);
-		if (!descs->virt && (i > 0)) {
+		if (!descs->virt) {
 			int idx;
 
 			for (idx = 0; idx < i; idx++) {
+				descs = &ioat_chan->descs[idx];
 				dma_free_coherent(to_dev(ioat_chan), SZ_2M,
 						  descs->virt, descs->hw);
 				descs->virt = NULL;
@@ -640,7 +653,7 @@
 	if (active - i == 0) {
 		dev_dbg(to_dev(ioat_chan), "%s: cancel completion timeout\n",
 			__func__);
-		mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
+		mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
 	}
 
 	/* microsecond delay by sysfs variable  per pending descriptor */
@@ -666,7 +679,7 @@
 
 		if (chanerr &
 		    (IOAT_CHANERR_HANDLE_MASK | IOAT_CHANERR_RECOVER_MASK)) {
-			mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
+			mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
 			ioat_eh(ioat_chan);
 		}
 	}
@@ -863,7 +876,7 @@
 	}
 
 	if (test_and_clear_bit(IOAT_CHAN_ACTIVE, &ioat_chan->state))
-		mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
+		mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
 }
 
 void ioat_timer_event(struct timer_list *t)
--- linux-ein-5.4.0.orig/drivers/dma/ioat/dma.h
+++ linux-ein-5.4.0/drivers/dma/ioat/dma.h
@@ -99,8 +99,6 @@
 	#define IOAT_RUN 5
 	#define IOAT_CHAN_ACTIVE 6
 	struct timer_list timer;
-	#define COMPLETION_TIMEOUT msecs_to_jiffies(100)
-	#define IDLE_TIMEOUT msecs_to_jiffies(2000)
 	#define RESET_DELAY msecs_to_jiffies(100)
 	struct ioatdma_device *ioat_dma;
 	dma_addr_t completion_dma;
--- linux-ein-5.4.0.orig/drivers/dma/k3dma.c
+++ linux-ein-5.4.0/drivers/dma/k3dma.c
@@ -229,9 +229,11 @@
 			c = p->vchan;
 			if (c && (tc1 & BIT(i))) {
 				spin_lock_irqsave(&c->vc.lock, flags);
-				vchan_cookie_complete(&p->ds_run->vd);
-				p->ds_done = p->ds_run;
-				p->ds_run = NULL;
+				if (p->ds_run != NULL) {
+					vchan_cookie_complete(&p->ds_run->vd);
+					p->ds_done = p->ds_run;
+					p->ds_run = NULL;
+				}
 				spin_unlock_irqrestore(&c->vc.lock, flags);
 			}
 			if (c && (tc2 & BIT(i))) {
@@ -271,6 +273,10 @@
 	if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d))
 		return -EAGAIN;
 
+	/* Avoid losing track of  ds_run if a transaction is in flight */
+	if (c->phy->ds_run)
+		return -EAGAIN;
+
 	if (vd) {
 		struct k3_dma_desc_sw *ds =
 			container_of(vd, struct k3_dma_desc_sw, vd);
--- linux-ein-5.4.0.orig/drivers/dma/mcf-edma.c
+++ linux-ein-5.4.0/drivers/dma/mcf-edma.c
@@ -35,6 +35,13 @@
 			mcf_chan = &mcf_edma->chans[ch];
 
 			spin_lock(&mcf_chan->vchan.lock);
+
+			if (!mcf_chan->edesc) {
+				/* terminate_all called before */
+				spin_unlock(&mcf_chan->vchan.lock);
+				continue;
+			}
+
 			if (!mcf_chan->edesc->iscyclic) {
 				list_del(&mcf_chan->edesc->vdesc.node);
 				vchan_cookie_complete(&mcf_chan->edesc->vdesc);
@@ -184,7 +191,13 @@
 		return -EINVAL;
 	}
 
-	chans = pdata->dma_channels;
+	if (!pdata->dma_channels) {
+		dev_info(&pdev->dev, "setting default channel number to 64");
+		chans = 64;
+	} else {
+		chans = pdata->dma_channels;
+	}
+
 	len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans;
 	mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
 	if (!mcf_edma)
@@ -196,11 +209,6 @@
 	mcf_edma->drvdata = &mcf_data;
 	mcf_edma->big_endian = 1;
 
-	if (!mcf_edma->n_chans) {
-		dev_info(&pdev->dev, "setting default channel number to 64");
-		mcf_edma->n_chans = 64;
-	}
-
 	mutex_init(&mcf_edma->fsl_edma_mutex);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--- linux-ein-5.4.0.orig/drivers/dma/mediatek/mtk-hsdma.c
+++ linux-ein-5.4.0/drivers/dma/mediatek/mtk-hsdma.c
@@ -997,7 +997,7 @@
 	if (err) {
 		dev_err(&pdev->dev,
 			"request_irq failed with err %d\n", err);
-		goto err_unregister;
+		goto err_free;
 	}
 
 	platform_set_drvdata(pdev, hsdma);
@@ -1006,6 +1006,9 @@
 
 	return 0;
 
+err_free:
+	mtk_hsdma_hw_deinit(hsdma);
+	of_dma_controller_free(pdev->dev.of_node);
 err_unregister:
 	dma_async_device_unregister(dd);
 
--- linux-ein-5.4.0.orig/drivers/dma/mediatek/mtk-uart-apdma.c
+++ linux-ein-5.4.0/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -131,10 +131,7 @@
 
 static void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
 {
-	struct dma_chan *chan = vd->tx.chan;
-	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
-
-	kfree(c->desc);
+	kfree(container_of(vd, struct mtk_uart_apdma_desc, vd));
 }
 
 static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
@@ -207,14 +204,9 @@
 
 static void mtk_uart_apdma_tx_handler(struct mtk_chan *c)
 {
-	struct mtk_uart_apdma_desc *d = c->desc;
-
 	mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
 	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
 	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
-
-	list_del(&d->vd.node);
-	vchan_cookie_complete(&d->vd);
 }
 
 static void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
@@ -245,9 +237,17 @@
 
 	c->rx_status = d->avail_len - cnt;
 	mtk_uart_apdma_write(c, VFF_RPT, wg);
+}
+
+static void mtk_uart_apdma_chan_complete_handler(struct mtk_chan *c)
+{
+	struct mtk_uart_apdma_desc *d = c->desc;
 
-	list_del(&d->vd.node);
-	vchan_cookie_complete(&d->vd);
+	if (d) {
+		list_del(&d->vd.node);
+		vchan_cookie_complete(&d->vd);
+		c->desc = NULL;
+	}
 }
 
 static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
@@ -261,6 +261,7 @@
 		mtk_uart_apdma_rx_handler(c);
 	else if (c->dir == DMA_MEM_TO_DEV)
 		mtk_uart_apdma_tx_handler(c);
+	mtk_uart_apdma_chan_complete_handler(c);
 	spin_unlock_irqrestore(&c->vc.lock, flags);
 
 	return IRQ_HANDLED;
@@ -273,7 +274,7 @@
 	unsigned int status;
 	int ret;
 
-	ret = pm_runtime_get_sync(mtkd->ddev.dev);
+	ret = pm_runtime_resume_and_get(mtkd->ddev.dev);
 	if (ret < 0) {
 		pm_runtime_put_noidle(chan->device->dev);
 		return ret;
@@ -287,18 +288,21 @@
 	ret = readx_poll_timeout(readl, c->base + VFF_EN,
 			  status, !status, 10, 100);
 	if (ret)
-		return ret;
+		goto err_pm;
 
 	ret = request_irq(c->irq, mtk_uart_apdma_irq_handler,
 			  IRQF_TRIGGER_NONE, KBUILD_MODNAME, chan);
 	if (ret < 0) {
 		dev_err(chan->device->dev, "Can't request dma IRQ\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_pm;
 	}
 
 	if (mtkd->support_33bits)
 		mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
 
+err_pm:
+	pm_runtime_put_noidle(mtkd->ddev.dev);
 	return ret;
 }
 
@@ -348,7 +352,7 @@
 		return NULL;
 
 	/* Now allocate and setup the descriptor */
-	d = kzalloc(sizeof(*d), GFP_ATOMIC);
+	d = kzalloc(sizeof(*d), GFP_NOWAIT);
 	if (!d)
 		return NULL;
 
@@ -366,7 +370,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&c->vc.lock, flags);
-	if (vchan_issue_pending(&c->vc)) {
+	if (vchan_issue_pending(&c->vc) && !c->desc) {
 		vd = vchan_next_desc(&c->vc);
 		c->desc = to_mtk_uart_apdma_desc(&vd->tx);
 
@@ -446,9 +450,8 @@
 	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
 	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
 
-	synchronize_irq(c->irq);
-
 	spin_unlock_irqrestore(&c->vc.lock, flags);
+	synchronize_irq(c->irq);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/dma/mmp_pdma.c
+++ linux-ein-5.4.0/drivers/dma/mmp_pdma.c
@@ -728,12 +728,6 @@
 
 	chan->dir = direction;
 	chan->dev_addr = addr;
-	/* FIXME: drivers should be ported over to use the filter
-	 * function. Once that's done, the following two lines can
-	 * be removed.
-	 */
-	if (cfg->slave_id)
-		chan->drcmr = cfg->slave_id;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/dma/mmp_tdma.c
+++ linux-ein-5.4.0/drivers/dma/mmp_tdma.c
@@ -363,6 +363,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;
 }
@@ -443,7 +445,8 @@
 	if (!desc)
 		goto err_out;
 
-	mmp_tdma_config_write(chan, direction, &tdmac->slave_config);
+	if (mmp_tdma_config_write(chan, direction, &tdmac->slave_config))
+		goto err_out;
 
 	while (buf < buf_len) {
 		desc = &tdmac->desc_arr[i];
--- linux-ein-5.4.0.orig/drivers/dma/mv_xor_v2.c
+++ linux-ein-5.4.0/drivers/dma/mv_xor_v2.c
@@ -751,7 +751,7 @@
 
 	xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) {
-		ret = EPROBE_DEFER;
+		ret = -EPROBE_DEFER;
 		goto disable_reg_clk;
 	}
 	if (!IS_ERR(xor_dev->clk)) {
@@ -766,8 +766,10 @@
 		goto disable_clk;
 
 	msi_desc = first_msi_entry(&pdev->dev);
-	if (!msi_desc)
+	if (!msi_desc) {
+		ret = -ENODEV;
 		goto free_msi_irqs;
+	}
 	xor_dev->msi_desc = msi_desc;
 
 	ret = devm_request_irq(&pdev->dev, msi_desc->irq,
@@ -893,6 +895,7 @@
 	tasklet_kill(&xor_dev->irq_tasklet);
 
 	clk_disable_unprepare(xor_dev->clk);
+	clk_disable_unprepare(xor_dev->reg_clk);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/dma/of-dma.c
+++ linux-ein-5.4.0/drivers/dma/of-dma.c
@@ -65,18 +65,23 @@
 		return NULL;
 
 	ofdma_target = of_dma_find_controller(&dma_spec_target);
-	if (!ofdma_target)
-		return NULL;
+	if (!ofdma_target) {
+		ofdma->dma_router->route_free(ofdma->dma_router->dev,
+					      route_data);
+		chan = ERR_PTR(-EPROBE_DEFER);
+		goto err;
+	}
 
 	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;
 	}
 
+err:
 	/*
 	 * Need to put the node back since the ofdma->of_dma_route_allocate
 	 * has taken it for generating the new, translated dma_spec
--- linux-ein-5.4.0.orig/drivers/dma/owl-dma.c
+++ linux-ein-5.4.0/drivers/dma/owl-dma.c
@@ -175,13 +175,11 @@
  * @id: physical index to this channel
  * @base: virtual memory base for the dma channel
  * @vchan: the virtual channel currently being served by this physical channel
- * @lock: a lock to use when altering an instance of this struct
  */
 struct owl_dma_pchan {
 	u32			id;
 	void __iomem		*base;
 	struct owl_dma_vchan	*vchan;
-	spinlock_t		lock;
 };
 
 /**
@@ -437,14 +435,14 @@
 	for (i = 0; i < od->nr_pchans; i++) {
 		pchan = &od->pchans[i];
 
-		spin_lock_irqsave(&pchan->lock, flags);
+		spin_lock_irqsave(&od->lock, flags);
 		if (!pchan->vchan) {
 			pchan->vchan = vchan;
-			spin_unlock_irqrestore(&pchan->lock, flags);
+			spin_unlock_irqrestore(&od->lock, flags);
 			break;
 		}
 
-		spin_unlock_irqrestore(&pchan->lock, flags);
+		spin_unlock_irqrestore(&od->lock, flags);
 	}
 
 	return pchan;
@@ -1203,6 +1201,7 @@
 	owl_dma_free(od);
 
 	clk_disable_unprepare(od->clk);
+	dma_pool_destroy(od->lli_pool);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/dma/pch_dma.c
+++ linux-ein-5.4.0/drivers/dma/pch_dma.c
@@ -865,6 +865,7 @@
 	}
 
 	pci_set_master(pdev);
+	pd->dma.dev = &pdev->dev;
 
 	err = request_irq(pdev->irq, pd_irq, IRQF_SHARED, DRV_NAME, pd);
 	if (err) {
@@ -880,7 +881,6 @@
 		goto err_free_irq;
 	}
 
-	pd->dma.dev = &pdev->dev;
 
 	INIT_LIST_HEAD(&pd->dma.channels);
 
--- linux-ein-5.4.0.orig/drivers/dma/pl330.c
+++ linux-ein-5.4.0/drivers/dma/pl330.c
@@ -403,6 +403,12 @@
 	 */
 	BUSY,
 	/*
+	 * Pause was called while descriptor was BUSY. Due to hardware
+	 * limitations, only termination is possible for descriptors
+	 * that have been paused.
+	 */
+	PAUSED,
+	/*
 	 * Sitting on the channel work_list but xfer done
 	 * by PL330 core
 	 */
@@ -1048,7 +1054,7 @@
 	return true;
 }
 
-static bool _start(struct pl330_thread *thrd)
+static bool pl330_start_thread(struct pl330_thread *thrd)
 {
 	switch (_state(thrd)) {
 	case PL330_STATE_FAULT_COMPLETING:
@@ -1696,7 +1702,7 @@
 			thrd->req_running = -1;
 
 			/* Get going again ASAP */
-			_start(thrd);
+			pl330_start_thread(thrd);
 
 			/* For now, just make a list of callbacks to be done */
 			list_add_tail(&descdone->rqd, &pl330->req_done);
@@ -2035,7 +2041,7 @@
 	list_for_each_entry(desc, &pch->work_list, node) {
 
 		/* If already submitted */
-		if (desc->status == BUSY)
+		if (desc->status == BUSY || desc->status == PAUSED)
 			continue;
 
 		ret = pl330_submit_req(pch->thread, desc);
@@ -2083,7 +2089,7 @@
 	} else {
 		/* Make sure the PL330 Channel thread is active */
 		spin_lock(&pch->thread->dmac->lock);
-		_start(pch->thread);
+		pl330_start_thread(pch->thread);
 		spin_unlock(&pch->thread->dmac->lock);
 	}
 
@@ -2101,7 +2107,7 @@
 			if (power_down) {
 				pch->active = true;
 				spin_lock(&pch->thread->dmac->lock);
-				_start(pch->thread);
+				pl330_start_thread(pch->thread);
 				spin_unlock(&pch->thread->dmac->lock);
 				power_down = false;
 			}
@@ -2322,6 +2328,7 @@
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
 	struct pl330_dmac *pl330 = pch->dmac;
+	struct dma_pl330_desc *desc;
 	unsigned long flags;
 
 	pm_runtime_get_sync(pl330->ddma.dev);
@@ -2331,6 +2338,10 @@
 	_stop(pch->thread);
 	spin_unlock(&pl330->lock);
 
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY)
+			desc->status = PAUSED;
+	}
 	spin_unlock_irqrestore(&pch->lock, flags);
 	pm_runtime_mark_last_busy(pl330->ddma.dev);
 	pm_runtime_put_autosuspend(pl330->ddma.dev);
@@ -2421,7 +2432,7 @@
 		else if (running && desc == running)
 			transferred =
 				pl330_get_current_xferred_count(pch, desc);
-		else if (desc->status == BUSY)
+		else if (desc->status == BUSY || desc->status == PAUSED)
 			/*
 			 * Busy but not running means either just enqueued,
 			 * or finished and not yet marked done
@@ -2438,6 +2449,9 @@
 			case DONE:
 				ret = DMA_COMPLETE;
 				break;
+			case PAUSED:
+				ret = DMA_PAUSED;
+				break;
 			case PREP:
 			case BUSY:
 				ret = DMA_IN_PROGRESS;
@@ -2585,7 +2599,7 @@
 
 	/* If the DMAC pool is empty, alloc new */
 	if (!desc) {
-		DEFINE_SPINLOCK(lock);
+		static DEFINE_SPINLOCK(lock);
 		LIST_HEAD(pool);
 
 		if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
@@ -2690,13 +2704,15 @@
 	for (i = 0; i < len / period_len; i++) {
 		desc = pl330_get_desc(pch);
 		if (!desc) {
+			unsigned long iflags;
+
 			dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n",
 				__func__, __LINE__);
 
 			if (!first)
 				return NULL;
 
-			spin_lock_irqsave(&pl330->pool_lock, flags);
+			spin_lock_irqsave(&pl330->pool_lock, iflags);
 
 			while (!list_empty(&first->node)) {
 				desc = list_entry(first->node.next,
@@ -2706,7 +2722,7 @@
 
 			list_move_tail(&first->node, &pl330->desc_pool);
 
-			spin_unlock_irqrestore(&pl330->pool_lock, flags);
+			spin_unlock_irqrestore(&pl330->pool_lock, iflags);
 
 			return NULL;
 		}
@@ -2788,14 +2804,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-ein-5.4.0.orig/drivers/dma/pxa_dma.c
+++ linux-ein-5.4.0/drivers/dma/pxa_dma.c
@@ -723,7 +723,6 @@
 	dma_addr_t dma;
 	struct pxad_desc_sw *sw_desc = to_pxad_sw_desc(vd);
 
-	BUG_ON(sw_desc->nb_desc == 0);
 	for (i = sw_desc->nb_desc - 1; i >= 0; i--) {
 		if (i > 0)
 			dma = sw_desc->hw_desc[i - 1]->ddadr;
@@ -911,13 +910,6 @@
 		*dcmd |= PXA_DCMD_BURST16;
 	else if (maxburst == 32)
 		*dcmd |= PXA_DCMD_BURST32;
-
-	/* FIXME: drivers should be ported over to use the filter
-	 * function. Once that's done, the following two lines can
-	 * be removed.
-	 */
-	if (chan->cfg.slave_id)
-		chan->drcmr = chan->cfg.slave_id;
 }
 
 static struct dma_async_tx_descriptor *
@@ -1256,14 +1248,14 @@
 		return -ENOMEM;
 
 	for (i = 0; i < nb_phy_chans; i++)
-		if (platform_get_irq(op, i) > 0)
+		if (platform_get_irq_optional(op, i) > 0)
 			nr_irq++;
 
 	for (i = 0; i < nb_phy_chans; i++) {
 		phy = &pdev->phys[i];
 		phy->base = pdev->base;
 		phy->idx = i;
-		irq = platform_get_irq(op, i);
+		irq = platform_get_irq_optional(op, i);
 		if ((nr_irq > 1) && (irq > 0))
 			ret = devm_request_irq(&op->dev, irq,
 					       pxad_chan_handler,
--- linux-ein-5.4.0.orig/drivers/dma/qcom/Kconfig
+++ linux-ein-5.4.0/drivers/dma/qcom/Kconfig
@@ -10,6 +10,7 @@
 
 config QCOM_HIDMA_MGMT
 	tristate "Qualcomm Technologies HIDMA Management support"
+	depends on HAS_IOMEM
 	select DMA_ENGINE
 	help
 	  Enable support for the Qualcomm Technologies HIDMA Management.
--- linux-ein-5.4.0.orig/drivers/dma/qcom/hidma_mgmt.c
+++ linux-ein-5.4.0/drivers/dma/qcom/hidma_mgmt.c
@@ -418,8 +418,23 @@
 		hidma_mgmt_of_populate_channels(child);
 	}
 #endif
-	return platform_driver_register(&hidma_mgmt_driver);
+	/*
+	 * We do not check for return value here, as it is assumed that
+	 * platform_driver_register must not fail. The reason for this is that
+	 * the (potential) hidma_mgmt_of_populate_channels calls above are not
+	 * cleaned up if it does fail, and to do this work is quite
+	 * complicated. In particular, various calls of of_address_to_resource,
+	 * of_irq_to_resource, platform_device_register_full, of_dma_configure,
+	 * and of_msi_configure which then call other functions and so on, must
+	 * be cleaned up - this is not a trivial exercise.
+	 *
+	 * Currently, this module is not intended to be unloaded, and there is
+	 * no module_exit function defined which does the needed cleanup. For
+	 * this reason, we have to assume success here.
+	 */
+	platform_driver_register(&hidma_mgmt_driver);
 
+	return 0;
 }
 module_init(hidma_mgmt_init);
 MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/dma/sh/rcar-dmac.c
+++ linux-ein-5.4.0/drivers/dma/sh/rcar-dmac.c
@@ -1824,8 +1824,13 @@
 	dmac->dev = &pdev->dev;
 	platform_set_drvdata(pdev, dmac);
 	dmac->dev->dma_parms = &dmac->parms;
-	dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
-	dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
+	ret = dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
+	if (ret)
+		return ret;
+
+	ret = dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
+	if (ret)
+		return ret;
 
 	ret = rcar_dmac_parse_of(&pdev->dev, dmac);
 	if (ret < 0)
@@ -1855,7 +1860,7 @@
 
 	/* Enable runtime PM and initialize the device. */
 	pm_runtime_enable(&pdev->dev);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
 		return ret;
--- linux-ein-5.4.0.orig/drivers/dma/sh/shdma.h
+++ linux-ein-5.4.0/drivers/dma/sh/shdma.h
@@ -25,7 +25,7 @@
 	const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
 	int xmit_shift;			/* log_2(bytes_per_xfer) */
 	void __iomem *base;
-	char dev_id[16];		/* unique name per DMAC of channel */
+	char dev_id[32];		/* unique name per DMAC of channel */
 	int pm_error;
 	dma_addr_t slave_addr;
 };
--- linux-ein-5.4.0.orig/drivers/dma/sh/usb-dmac.c
+++ linux-ein-5.4.0/drivers/dma/sh/usb-dmac.c
@@ -586,6 +586,8 @@
 		desc->residue = usb_dmac_get_current_residue(chan, desc,
 							desc->sg_index - 1);
 		desc->done_cookie = desc->vd.tx.cookie;
+		desc->vd.tx_result.result = DMA_TRANS_NOERROR;
+		desc->vd.tx_result.residue = desc->residue;
 		vchan_cookie_complete(&desc->vd);
 
 		/* Restart the next transfer if this driver has a next desc */
@@ -853,8 +855,8 @@
 
 error:
 	of_dma_controller_free(pdev->dev.of_node);
-	pm_runtime_put(&pdev->dev);
 error_pm:
+	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/dma/sprd-dma.c
+++ linux-ein-5.4.0/drivers/dma/sprd-dma.c
@@ -1201,11 +1201,8 @@
 {
 	struct sprd_dma_dev *sdev = platform_get_drvdata(pdev);
 	struct sprd_dma_chn *c, *cn;
-	int ret;
 
-	ret = pm_runtime_get_sync(&pdev->dev);
-	if (ret < 0)
-		return ret;
+	pm_runtime_get_sync(&pdev->dev);
 
 	/* explicitly free the irq */
 	if (sdev->irq > 0)
@@ -1230,6 +1227,7 @@
 	{ .compatible = "sprd,sc9860-dma", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, sprd_dma_match);
 
 static int __maybe_unused sprd_dma_runtime_suspend(struct device *dev)
 {
--- linux-ein-5.4.0.orig/drivers/dma/st_fdma.c
+++ linux-ein-5.4.0/drivers/dma/st_fdma.c
@@ -873,4 +873,4 @@
 MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver");
 MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>");
 MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
-MODULE_ALIAS("platform: " DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/dma/ste_dma40.c
+++ linux-ein-5.4.0/drivers/dma/ste_dma40.c
@@ -3599,6 +3599,10 @@
 	spin_lock_init(&base->lcla_pool.lock);
 
 	base->irq = platform_get_irq(pdev, 0);
+	if (base->irq < 0) {
+		ret = base->irq;
+		goto destroy_cache;
+	}
 
 	ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
 	if (ret) {
@@ -3678,6 +3682,9 @@
 
 	kfree(base->lcla_pool.base_unaligned);
 
+	if (base->lcpa_base)
+		iounmap(base->lcpa_base);
+
 	if (base->phy_lcpa)
 		release_mem_region(base->phy_lcpa,
 				   base->lcpa_size);
@@ -3693,6 +3700,7 @@
 		regulator_disable(base->lcpa_regulator);
 		regulator_put(base->lcpa_regulator);
 	}
+	pm_runtime_disable(base->dev);
 
 	kfree(base->lcla_pool.alloc_map);
 	kfree(base->lookup_log_chans);
--- linux-ein-5.4.0.orig/drivers/dma/stm32-dma.c
+++ linux-ein-5.4.0/drivers/dma/stm32-dma.c
@@ -488,8 +488,10 @@
 
 	spin_lock_irqsave(&chan->vchan.lock, flags);
 
-	if (chan->busy) {
-		stm32_dma_stop(chan);
+	if (chan->desc) {
+		vchan_terminate_vdesc(&chan->desc->vdesc);
+		if (chan->busy)
+			stm32_dma_stop(chan);
 		chan->desc = NULL;
 	}
 
@@ -545,6 +547,8 @@
 		if (!vdesc)
 			return;
 
+		list_del(&vdesc->node);
+
 		chan->desc = to_stm32_dma_desc(vdesc);
 		chan->next_sg = 0;
 	}
@@ -622,7 +626,6 @@
 		} else {
 			chan->busy = false;
 			if (chan->next_sg == chan->desc->num_sgs) {
-				list_del(&chan->desc->vdesc.node);
 				vchan_cookie_complete(&chan->desc->vdesc);
 				chan->desc = NULL;
 			}
--- linux-ein-5.4.0.orig/drivers/dma/stm32-mdma.c
+++ linux-ein-5.4.0/drivers/dma/stm32-mdma.c
@@ -40,7 +40,6 @@
 					 STM32_MDMA_SHIFT(mask))
 
 #define STM32_MDMA_GISR0		0x0000 /* MDMA Int Status Reg 1 */
-#define STM32_MDMA_GISR1		0x0004 /* MDMA Int Status Reg 2 */
 
 /* MDMA Channel x interrupt/status register */
 #define STM32_MDMA_CISR(x)		(0x40 + 0x40 * (x)) /* x = 0..62 */
@@ -184,7 +183,7 @@
 #define STM32_MDMA_CTBR(x)		(0x68 + 0x40 * (x))
 #define STM32_MDMA_CTBR_DBUS		BIT(17)
 #define STM32_MDMA_CTBR_SBUS		BIT(16)
-#define STM32_MDMA_CTBR_TSEL_MASK	GENMASK(7, 0)
+#define STM32_MDMA_CTBR_TSEL_MASK	GENMASK(5, 0)
 #define STM32_MDMA_CTBR_TSEL(n)		STM32_MDMA_SET(n, \
 						      STM32_MDMA_CTBR_TSEL_MASK)
 
@@ -196,7 +195,7 @@
 
 #define STM32_MDMA_MAX_BUF_LEN		128
 #define STM32_MDMA_MAX_BLOCK_LEN	65536
-#define STM32_MDMA_MAX_CHANNELS		63
+#define STM32_MDMA_MAX_CHANNELS		32
 #define STM32_MDMA_MAX_REQUESTS		256
 #define STM32_MDMA_MAX_BURST		128
 #define STM32_MDMA_VERY_HIGH_PRIORITY	0x11
@@ -511,7 +510,7 @@
 	src_maxburst = chan->dma_config.src_maxburst;
 	dst_maxburst = chan->dma_config.dst_maxburst;
 
-	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id));
+	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN;
 	ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id));
 	ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id));
 
@@ -939,7 +938,7 @@
 	if (!desc)
 		return NULL;
 
-	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id));
+	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN;
 	ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id));
 	ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id));
 	cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id));
@@ -1127,6 +1126,8 @@
 		return;
 	}
 
+	list_del(&vdesc->node);
+
 	chan->desc = to_stm32_mdma_desc(vdesc);
 	hwdesc = chan->desc->node[0].hwdesc;
 	chan->curr_hwdesc = 0;
@@ -1206,6 +1207,10 @@
 	unsigned long flags;
 	u32 status, reg;
 
+	/* Transfer can be terminated */
+	if (!chan->desc || (stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & STM32_MDMA_CCR_EN))
+		return -EPERM;
+
 	hwdesc = chan->desc->node[chan->curr_hwdesc].hwdesc;
 
 	spin_lock_irqsave(&chan->vchan.lock, flags);
@@ -1242,8 +1247,10 @@
 	LIST_HEAD(head);
 
 	spin_lock_irqsave(&chan->vchan.lock, flags);
-	if (chan->busy) {
-		stm32_mdma_stop(chan);
+	if (chan->desc) {
+		vchan_terminate_vdesc(&chan->desc->vdesc);
+		if (chan->busy)
+			stm32_mdma_stop(chan);
 		chan->desc = NULL;
 	}
 	vchan_get_all_descriptors(&chan->vchan, &head);
@@ -1331,7 +1338,6 @@
 
 static void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan)
 {
-	list_del(&chan->desc->vdesc.node);
 	vchan_cookie_complete(&chan->desc->vdesc);
 	chan->desc = NULL;
 	chan->busy = false;
@@ -1348,21 +1354,11 @@
 
 	/* Find out which channel generates the interrupt */
 	status = readl_relaxed(dmadev->base + STM32_MDMA_GISR0);
-	if (status) {
-		id = __ffs(status);
-	} else {
-		status = readl_relaxed(dmadev->base + STM32_MDMA_GISR1);
-		if (!status) {
-			dev_dbg(mdma2dev(dmadev), "spurious it\n");
-			return IRQ_NONE;
-		}
-		id = __ffs(status);
-		/*
-		 * As GISR0 provides status for channel id from 0 to 31,
-		 * so GISR1 provides status for channel id from 32 to 62
-		 */
-		id += 32;
+	if (!status) {
+		dev_dbg(mdma2dev(dmadev), "spurious it\n");
+		return IRQ_NONE;
 	}
+	id = __ffs(status);
 
 	chan = &dmadev->chan[id];
 	if (!chan) {
--- linux-ein-5.4.0.orig/drivers/dma/tegra20-apb-dma.c
+++ linux-ein-5.4.0/drivers/dma/tegra20-apb-dma.c
@@ -281,7 +281,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;
@@ -756,10 +756,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;
@@ -1291,8 +1287,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-ein-5.4.0.orig/drivers/dma/tegra210-adma.c
+++ linux-ein-5.4.0/drivers/dma/tegra210-adma.c
@@ -224,7 +224,7 @@
 	int ret;
 
 	/* Clear any interrupts */
-	tdma_write(tdma, tdma->cdata->global_int_clear, 0x1);
+	tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1);
 
 	/* Assert soft reset */
 	tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1);
@@ -658,6 +658,7 @@
 
 	ret = pm_runtime_get_sync(tdc2dev(tdc));
 	if (ret < 0) {
+		pm_runtime_put_noidle(tdc2dev(tdc));
 		free_irq(tdc->irq, tdc);
 		return ret;
 	}
@@ -869,8 +870,10 @@
 	pm_runtime_enable(&pdev->dev);
 
 	ret = pm_runtime_get_sync(&pdev->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(&pdev->dev);
 		goto rpm_disable;
+	}
 
 	ret = tegra_adma_init(tdma);
 	if (ret)
@@ -900,7 +903,7 @@
 	ret = dma_async_device_register(&tdma->dma_dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "ADMA registration failed: %d\n", ret);
-		goto irq_dispose;
+		goto rpm_put;
 	}
 
 	ret = of_dma_controller_register(pdev->dev.of_node,
--- linux-ein-5.4.0.orig/drivers/dma/ti/dma-crossbar.c
+++ linux-ein-5.4.0/drivers/dma/ti/dma-crossbar.c
@@ -247,6 +247,7 @@
 	if (dma_spec->args[0] >= xbar->xbar_requests) {
 		dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
 			dma_spec->args[0]);
+		put_device(&pdev->dev);
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -254,12 +255,14 @@
 	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
 	if (!dma_spec->np) {
 		dev_err(&pdev->dev, "Can't get DMA master\n");
+		put_device(&pdev->dev);
 		return ERR_PTR(-EINVAL);
 	}
 
 	map = kzalloc(sizeof(*map), GFP_KERNEL);
 	if (!map) {
 		of_node_put(dma_spec->np);
+		put_device(&pdev->dev);
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -270,6 +273,8 @@
 		mutex_unlock(&xbar->mutex);
 		dev_err(&pdev->dev, "Run out of free DMA requests\n");
 		kfree(map);
+		of_node_put(dma_spec->np);
+		put_device(&pdev->dev);
 		return ERR_PTR(-ENOMEM);
 	}
 	set_bit(map->xbar_out, xbar->dma_inuse);
--- linux-ein-5.4.0.orig/drivers/dma/ti/edma.c
+++ linux-ein-5.4.0/drivers/dma/ti/edma.c
@@ -2361,7 +2361,7 @@
 	if (irq < 0 && node)
 		irq = irq_of_parse_and_map(node, 0);
 
-	if (irq >= 0) {
+	if (irq > 0) {
 		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint",
 					  dev_name(dev));
 		ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name,
@@ -2377,7 +2377,7 @@
 	if (irq < 0 && node)
 		irq = irq_of_parse_and_map(node, 2);
 
-	if (irq >= 0) {
+	if (irq > 0) {
 		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint",
 					  dev_name(dev));
 		ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name,
@@ -2403,8 +2403,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",
--- linux-ein-5.4.0.orig/drivers/dma/virt-dma.c
+++ linux-ein-5.4.0/drivers/dma/virt-dma.c
@@ -104,9 +104,8 @@
 		dmaengine_desc_get_callback(&vd->tx, &cb);
 
 		list_del(&vd->node);
-		vchan_vdesc_fini(vd);
-
 		dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
+		vchan_vdesc_fini(vd);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/dma/xilinx/xilinx_dma.c
+++ linux-ein-5.4.0/drivers/dma/xilinx/xilinx_dma.c
@@ -333,6 +333,7 @@
  * @genlock: Support genlock mode
  * @err: Channel has errors
  * @idle: Check for channel idle
+ * @terminating: Check for channel being synchronized by user
  * @tasklet: Cleanup work after irq
  * @config: Device configuration info
  * @flush_on_fsync: Flush on Frame sync
@@ -370,6 +371,7 @@
 	bool genlock;
 	bool err;
 	bool idle;
+	bool terminating;
 	struct tasklet_struct tasklet;
 	struct xilinx_vdma_config config;
 	bool flush_on_fsync;
@@ -454,8 +456,8 @@
 #define to_dma_tx_descriptor(tx) \
 	container_of(tx, struct xilinx_dma_tx_descriptor, async_tx)
 #define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \
-	readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \
-			   cond, delay_us, timeout_us)
+	readl_poll_timeout_atomic(chan->xdev->regs + chan->ctrl_offset + reg, \
+				  val, cond, delay_us, timeout_us)
 
 /* IO accessors */
 static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
@@ -844,6 +846,13 @@
 		/* Run any dependencies, then free the descriptor */
 		dma_run_dependencies(&desc->async_tx);
 		xilinx_dma_free_tx_descriptor(chan, desc);
+
+		/*
+		 * While we ran a callback the user called a terminate function,
+		 * which takes care of cleaning up any remaining descriptors
+		 */
+		if (chan->terminating)
+			break;
 	}
 
 	spin_unlock_irqrestore(&chan->lock, flags);
@@ -1433,6 +1442,7 @@
 
 	chan->err = false;
 	chan->idle = true;
+	chan->desc_pendingcount = 0;
 	chan->desc_submitcount = 0;
 
 	return err;
@@ -1617,6 +1627,8 @@
 	if (desc->cyclic)
 		chan->cyclic = true;
 
+	chan->terminating = false;
+
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	return cookie;
@@ -2073,6 +2085,7 @@
 	}
 
 	/* Remove and free all of the descriptors in the lists */
+	chan->terminating = true;
 	xilinx_dma_free_descriptors(chan);
 	chan->idle = true;
 
@@ -2430,7 +2443,7 @@
 		has_dre = false;
 
 	if (!has_dre)
-		xdev->common.copy_align = fls(width - 1);
+		xdev->common.copy_align = (enum dmaengine_alignment)fls(width - 1);
 
 	if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") ||
 	    of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") ||
@@ -2542,7 +2555,8 @@
 static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
 				    struct device_node *node)
 {
-	int ret, i, nr_channels = 1;
+	int ret, i;
+	u32 nr_channels = 1;
 
 	ret = of_property_read_u32(node, "dma-channels", &nr_channels);
 	if ((ret < 0) && xdev->mcdma)
@@ -2612,7 +2626,6 @@
 	struct device_node *node = pdev->dev.of_node;
 	struct xilinx_dma_device *xdev;
 	struct device_node *child, *np = pdev->dev.of_node;
-	struct resource *io;
 	u32 num_frames, addr_width, len_width;
 	int i, err;
 
@@ -2638,11 +2651,11 @@
 		return err;
 
 	/* Request and map I/O memory */
-	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	xdev->regs = devm_ioremap_resource(&pdev->dev, io);
-	if (IS_ERR(xdev->regs))
-		return PTR_ERR(xdev->regs);
-
+	xdev->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(xdev->regs)) {
+		err = PTR_ERR(xdev->regs);
+		goto disable_clks;
+	}
 	/* Retrieve the DMA engine properties from the device tree */
 	xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
 
@@ -2669,7 +2682,7 @@
 		if (err < 0) {
 			dev_err(xdev->dev,
 				"missing xlnx,num-fstores property\n");
-			return err;
+			goto disable_clks;
 		}
 
 		err = of_property_read_u32(node, "xlnx,flush-fsync",
@@ -2689,7 +2702,11 @@
 		xdev->ext_addr = false;
 
 	/* Set the dma mask bits */
-	dma_set_mask(xdev->dev, DMA_BIT_MASK(addr_width));
+	err = dma_set_mask_and_coherent(xdev->dev, DMA_BIT_MASK(addr_width));
+	if (err < 0) {
+		dev_err(xdev->dev, "DMA mask error %d\n", err);
+		goto disable_clks;
+	}
 
 	/* Initialize the DMA engine */
 	xdev->common.dev = &pdev->dev;
@@ -2730,8 +2747,10 @@
 	/* Initialize the channels */
 	for_each_child_of_node(node, child) {
 		err = xilinx_dma_child_probe(xdev, child);
-		if (err < 0)
-			goto disable_clks;
+		if (err < 0) {
+			of_node_put(child);
+			goto error;
+		}
 	}
 
 	if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
@@ -2741,7 +2760,11 @@
 	}
 
 	/* Register the DMA engine with the core */
-	dma_async_device_register(&xdev->common);
+	err = dma_async_device_register(&xdev->common);
+	if (err) {
+		dev_err(xdev->dev, "failed to register the dma device\n");
+		goto error;
+	}
 
 	err = of_dma_controller_register(node, of_dma_xilinx_xlate,
 					 xdev);
@@ -2760,12 +2783,12 @@
 
 	return 0;
 
-disable_clks:
-	xdma_disable_allclks(xdev);
 error:
 	for (i = 0; i < xdev->nr_channels; i++)
 		if (xdev->chan[i])
 			xilinx_dma_chan_remove(xdev->chan[i]);
+disable_clks:
+	xdma_disable_allclks(xdev);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/dma/xilinx/zynqmp_dma.c
+++ linux-ein-5.4.0/drivers/dma/xilinx/zynqmp_dma.c
@@ -123,10 +123,12 @@
 /* Max transfer size per descriptor */
 #define ZYNQMP_DMA_MAX_TRANS_LEN	0x40000000
 
+/* Max burst lengths */
+#define ZYNQMP_DMA_MAX_DST_BURST_LEN    32768U
+#define ZYNQMP_DMA_MAX_SRC_BURST_LEN    32768U
+
 /* Reset values for data attributes */
 #define ZYNQMP_DMA_AXCACHE_VAL		0xF
-#define ZYNQMP_DMA_ARLEN_RST_VAL	0xF
-#define ZYNQMP_DMA_AWLEN_RST_VAL	0xF
 
 #define ZYNQMP_DMA_SRC_ISSUE_RST_VAL	0x1F
 
@@ -230,7 +232,7 @@
 	bool is_dmacoherent;
 	struct tasklet_struct tasklet;
 	bool idle;
-	u32 desc_size;
+	size_t desc_size;
 	bool err;
 	u32 bus_width;
 	u32 src_burst_len;
@@ -465,7 +467,7 @@
 	struct zynqmp_dma_desc_sw *desc;
 	int i, ret;
 
-	ret = pm_runtime_get_sync(chan->dev);
+	ret = pm_runtime_resume_and_get(chan->dev);
 	if (ret < 0)
 		return ret;
 
@@ -487,7 +489,8 @@
 	}
 
 	chan->desc_pool_v = dma_alloc_coherent(chan->dev,
-					       (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS),
+					       (2 * ZYNQMP_DMA_DESC_SIZE(chan) *
+					       ZYNQMP_DMA_NUM_DESCS),
 					       &chan->desc_pool_p, GFP_KERNEL);
 	if (!chan->desc_pool_v)
 		return -ENOMEM;
@@ -534,17 +537,19 @@
 
 static void zynqmp_dma_config(struct zynqmp_dma_chan *chan)
 {
-	u32 val;
+	u32 val, burst_val;
 
 	val = readl(chan->regs + ZYNQMP_DMA_CTRL0);
 	val |= ZYNQMP_DMA_POINT_TYPE_SG;
 	writel(val, chan->regs + ZYNQMP_DMA_CTRL0);
 
 	val = readl(chan->regs + ZYNQMP_DMA_DATA_ATTR);
+	burst_val = __ilog2_u32(chan->src_burst_len);
 	val = (val & ~ZYNQMP_DMA_ARLEN) |
-		(chan->src_burst_len << ZYNQMP_DMA_ARLEN_OFST);
+		((burst_val << ZYNQMP_DMA_ARLEN_OFST) & ZYNQMP_DMA_ARLEN);
+	burst_val = __ilog2_u32(chan->dst_burst_len);
 	val = (val & ~ZYNQMP_DMA_AWLEN) |
-		(chan->dst_burst_len << ZYNQMP_DMA_AWLEN_OFST);
+		((burst_val << ZYNQMP_DMA_AWLEN_OFST) & ZYNQMP_DMA_AWLEN);
 	writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR);
 }
 
@@ -560,8 +565,10 @@
 {
 	struct zynqmp_dma_chan *chan = to_chan(dchan);
 
-	chan->src_burst_len = config->src_maxburst;
-	chan->dst_burst_len = config->dst_maxburst;
+	chan->src_burst_len = clamp(config->src_maxburst, 1U,
+		ZYNQMP_DMA_MAX_SRC_BURST_LEN);
+	chan->dst_burst_len = clamp(config->dst_maxburst, 1U,
+		ZYNQMP_DMA_MAX_DST_BURST_LEN);
 
 	return 0;
 }
@@ -887,8 +894,8 @@
 		return PTR_ERR(chan->regs);
 
 	chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
-	chan->dst_burst_len = ZYNQMP_DMA_AWLEN_RST_VAL;
-	chan->src_burst_len = ZYNQMP_DMA_ARLEN_RST_VAL;
+	chan->dst_burst_len = ZYNQMP_DMA_MAX_DST_BURST_LEN;
+	chan->src_burst_len = ZYNQMP_DMA_MAX_SRC_BURST_LEN;
 	err = of_property_read_u32(node, "xlnx,bus-width", &chan->bus_width);
 	if (err < 0) {
 		dev_err(&pdev->dev, "missing xlnx,bus-width property\n");
--- linux-ein-5.4.0.orig/drivers/edac/altera_edac.c
+++ linux-ein-5.4.0/drivers/edac/altera_edac.c
@@ -349,7 +349,7 @@
 	if (irq < 0) {
 		edac_printk(KERN_ERR, EDAC_MC,
 			    "No irq %d in DT\n", irq);
-		return -ENODEV;
+		return irq;
 	}
 
 	/* Arria10 has a 2nd IRQ */
@@ -560,6 +560,7 @@
 	.reg_write = s10_protected_reg_write,
 	.use_single_read = true,
 	.use_single_write = true,
+	.fast_io = true,
 };
 
 /************** </Stratix10 EDAC Memory Controller Functions> ***********/
--- linux-ein-5.4.0.orig/drivers/edac/amd64_edac.c
+++ linux-ein-5.4.0/drivers/edac/amd64_edac.c
@@ -22,6 +22,9 @@
 /* Number of Unified Memory Controllers */
 static u8 num_umcs;
 
+/* Device for the PCI component */
+static struct device *pci_ctl_dev;
+
 /*
  * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
  * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
@@ -215,7 +218,7 @@
 
 	scrubval = scrubrates[i].scrubval;
 
-	if (pvt->fam == 0x17 || pvt->fam == 0x18) {
+	if (pvt->umc) {
 		__f17h_set_scrubval(pvt, scrubval);
 	} else if (pvt->fam == 0x15 && pvt->model == 0x60) {
 		f15h_select_dct(pvt, 0);
@@ -257,18 +260,7 @@
 	int i, retval = -EINVAL;
 	u32 scrubval = 0;
 
-	switch (pvt->fam) {
-	case 0x15:
-		/* Erratum #505 */
-		if (pvt->model < 0x10)
-			f15h_select_dct(pvt, 0);
-
-		if (pvt->model == 0x60)
-			amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval);
-		break;
-
-	case 0x17:
-	case 0x18:
+	if (pvt->umc) {
 		amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
 		if (scrubval & BIT(0)) {
 			amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
@@ -277,11 +269,17 @@
 		} else {
 			scrubval = 0;
 		}
-		break;
+	} else if (pvt->fam == 0x15) {
+		/* Erratum #505 */
+		if (pvt->model < 0x10)
+			f15h_select_dct(pvt, 0);
 
-	default:
+		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);
-		break;
 	}
 
 	scrubval = scrubval & 0x001F;
@@ -792,12 +790,14 @@
 #define CS_ODD_PRIMARY		BIT(1)
 #define CS_EVEN_SECONDARY	BIT(2)
 #define CS_ODD_SECONDARY	BIT(3)
+#define CS_3R_INTERLEAVE	BIT(4)
 
 #define CS_EVEN			(CS_EVEN_PRIMARY | CS_EVEN_SECONDARY)
 #define CS_ODD			(CS_ODD_PRIMARY | CS_ODD_SECONDARY)
 
 static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
 {
+	u8 base, count = 0;
 	int cs_mode = 0;
 
 	if (csrow_enabled(2 * dimm, ctrl, pvt))
@@ -810,6 +810,20 @@
 	if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt))
 		cs_mode |= CS_ODD_SECONDARY;
 
+	/*
+	 * 3 Rank inteleaving support.
+	 * There should be only three bases enabled and their two masks should
+	 * be equal.
+	 */
+	for_each_chip_select(base, ctrl, pvt)
+		count += csrow_enabled(base, ctrl, pvt);
+
+	if (count == 3 &&
+	    pvt->csels[ctrl].csmasks[0] == pvt->csels[ctrl].csmasks[1]) {
+		edac_dbg(1, "3R interleaving in use.\n");
+		cs_mode |= CS_3R_INTERLEAVE;
+	}
+
 	return cs_mode;
 }
 
@@ -1056,6 +1070,16 @@
 {
 	u32 dram_ctrl, dcsm;
 
+	if (pvt->umc) {
+		if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
+			pvt->dram_type = MEM_LRDDR4;
+		else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
+			pvt->dram_type = MEM_RDDR4;
+		else
+			pvt->dram_type = MEM_DDR4;
+		return;
+	}
+
 	switch (pvt->fam) {
 	case 0xf:
 		if (pvt->ext_model >= K8_REV_F)
@@ -1101,16 +1125,6 @@
 	case 0x16:
 		goto ddr3;
 
-	case 0x17:
-	case 0x18:
-		if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
-			pvt->dram_type = MEM_LRDDR4;
-		else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
-			pvt->dram_type = MEM_RDDR4;
-		else
-			pvt->dram_type = MEM_DDR4;
-		return;
-
 	default:
 		WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam);
 		pvt->dram_type = MEM_EMPTY;
@@ -1618,10 +1632,14 @@
 	 *
 	 * The MSB is the number of bits in the full mask because BIT[0] is
 	 * always 0.
+	 *
+	 * In the special 3 Rank interleaving case, a single bit is flipped
+	 * without swapping with the most significant bit. This can be handled
+	 * by keeping the MSB where it is and ignoring the single zero bit.
 	 */
 	msb = fls(addr_mask_orig) - 1;
 	weight = hweight_long(addr_mask_orig);
-	num_zero_bits = msb - weight;
+	num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE);
 
 	/* Take the number of zero bits off from the top of the mask. */
 	addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1);
@@ -2317,6 +2335,15 @@
 			.dbam_to_cs		= f17_addr_mask_to_cs_size,
 		}
 	},
+	[F17_M60H_CPUS] = {
+		.ctl_name = "F17h_M60h",
+		.f0_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F0,
+		.f6_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F6,
+		.ops = {
+			.early_channel_count	= f17_early_channel_count,
+			.dbam_to_cs		= f17_addr_mask_to_cs_size,
+		}
+	},
 	[F17_M70H_CPUS] = {
 		.ctl_name = "F17h_M70h",
 		.f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0,
@@ -2326,6 +2353,15 @@
 			.dbam_to_cs		= f17_addr_mask_to_cs_size,
 		}
 	},
+	[F19_CPUS] = {
+		.ctl_name = "F19h",
+		.f0_id = PCI_DEVICE_ID_AMD_19H_DF_F0,
+		.f6_id = PCI_DEVICE_ID_AMD_19H_DF_F6,
+		.ops = {
+			.early_channel_count	= f17_early_channel_count,
+			.dbam_to_cs		= f17_addr_mask_to_cs_size,
+		}
+	},
 };
 
 /*
@@ -2661,6 +2697,9 @@
 			return -ENODEV;
 		}
 
+		if (!pci_ctl_dev)
+			pci_ctl_dev = &pvt->F0->dev;
+
 		edac_dbg(1, "F0: %s\n", pci_name(pvt->F0));
 		edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
 		edac_dbg(1, "F6: %s\n", pci_name(pvt->F6));
@@ -2685,6 +2724,9 @@
 		return -ENODEV;
 	}
 
+	if (!pci_ctl_dev)
+		pci_ctl_dev = &pvt->F2->dev;
+
 	edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
 	edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
 	edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
@@ -2936,6 +2978,7 @@
 			dimm->mtype = pvt->dram_type;
 			dimm->edac_mode = edac_mode;
 			dimm->dtype = dev_type;
+			dimm->grain = 64;
 		}
 	}
 
@@ -3012,6 +3055,7 @@
 			dimm = csrow->channels[j]->dimm;
 			dimm->mtype = pvt->dram_type;
 			dimm->edac_mode = edac_mode;
+			dimm->grain = 64;
 		}
 	}
 
@@ -3364,6 +3408,10 @@
 			fam_type = &family_types[F17_M30H_CPUS];
 			pvt->ops = &family_types[F17_M30H_CPUS].ops;
 			break;
+		} else if (pvt->model >= 0x60 && pvt->model <= 0x6f) {
+			fam_type = &family_types[F17_M60H_CPUS];
+			pvt->ops = &family_types[F17_M60H_CPUS].ops;
+			break;
 		} else if (pvt->model >= 0x70 && pvt->model <= 0x7f) {
 			fam_type = &family_types[F17_M70H_CPUS];
 			pvt->ops = &family_types[F17_M70H_CPUS].ops;
@@ -3378,6 +3426,12 @@
 			family_types[F17_CPUS].ctl_name = "F18h";
 		break;
 
+	case 0x19:
+		fam_type	= &family_types[F19_CPUS];
+		pvt->ops	= &family_types[F19_CPUS].ops;
+		family_types[F19_CPUS].ctl_name = "F19h";
+		break;
+
 	default:
 		amd64_err("Unsupported family!\n");
 		return NULL;
@@ -3609,21 +3663,10 @@
 
 static void setup_pci_device(void)
 {
-	struct mem_ctl_info *mci;
-	struct amd64_pvt *pvt;
-
 	if (pci_ctl)
 		return;
 
-	mci = edac_mc_find(0);
-	if (!mci)
-		return;
-
-	pvt = mci->pvt_info;
-	if (pvt->umc)
-		pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
-	else
-		pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
+	pci_ctl = edac_pci_create_generic_ctl(pci_ctl_dev, EDAC_MOD_STR);
 	if (!pci_ctl) {
 		pr_warn("%s(): Unable to create PCI control\n", __func__);
 		pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
@@ -3637,6 +3680,7 @@
 	{ X86_VENDOR_AMD, 0x16, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
 	{ X86_VENDOR_AMD, 0x17, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
 	{ X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
+	{ X86_VENDOR_AMD, 0x19, X86_MODEL_ANY,	X86_FEATURE_ANY, 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
@@ -3706,6 +3750,8 @@
 	return 0;
 
 err_pci:
+	pci_ctl_dev = NULL;
+
 	msrs_free(msrs);
 	msrs = NULL;
 
@@ -3737,6 +3783,8 @@
 	kfree(ecc_stngs);
 	ecc_stngs = NULL;
 
+	pci_ctl_dev = NULL;
+
 	msrs_free(msrs);
 	msrs = NULL;
 }
--- linux-ein-5.4.0.orig/drivers/edac/amd64_edac.h
+++ linux-ein-5.4.0/drivers/edac/amd64_edac.h
@@ -120,8 +120,12 @@
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496
+#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F0 0x1448
+#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F6 0x144e
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F6 0x1446
+#define PCI_DEVICE_ID_AMD_19H_DF_F0	0x1650
+#define PCI_DEVICE_ID_AMD_19H_DF_F6	0x1656
 
 /*
  * Function 1 - Address Map
@@ -291,7 +295,9 @@
 	F17_CPUS,
 	F17_M10H_CPUS,
 	F17_M30H_CPUS,
+	F17_M60H_CPUS,
 	F17_M70H_CPUS,
+	F19_CPUS,
 	NUM_FAMILIES,
 };
 
--- linux-ein-5.4.0.orig/drivers/edac/armada_xp_edac.c
+++ linux-ein-5.4.0/drivers/edac/armada_xp_edac.c
@@ -178,7 +178,7 @@
 				     "details unavailable (multiple errors)");
 	if (cnt_dbe)
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-				     cnt_sbe, /* error count */
+				     cnt_dbe, /* error count */
 				     0, 0, 0, /* pfn, offset, syndrome */
 				     -1, -1, -1, /* top, mid, low layer */
 				     mci->ctl_name,
--- linux-ein-5.4.0.orig/drivers/edac/aspeed_edac.c
+++ linux-ein-5.4.0/drivers/edac/aspeed_edac.c
@@ -209,8 +209,8 @@
 	/* register interrupt handler */
 	irq = platform_get_irq(pdev, 0);
 	dev_dbg(&pdev->dev, "got irq %d\n", irq);
-	if (!irq)
-		return -ENODEV;
+	if (irq < 0)
+		return irq;
 
 	rc = devm_request_irq(&pdev->dev, irq, mcr_isr, IRQF_TRIGGER_HIGH,
 			      DRV_NAME, ctx);
--- linux-ein-5.4.0.orig/drivers/edac/edac_device.c
+++ linux-ein-5.4.0/drivers/edac/edac_device.c
@@ -34,6 +34,9 @@
 static DEFINE_MUTEX(device_ctls_mutex);
 static LIST_HEAD(edac_device_list);
 
+/* Default workqueue processing interval on this instance, in msecs */
+#define DEFAULT_POLL_INTERVAL 1000
+
 #ifdef CONFIG_EDAC_DEBUG
 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
 {
@@ -366,7 +369,7 @@
 	 * whole one second to save timers firing all over the period
 	 * between integral seconds
 	 */
-	if (edac_dev->poll_msec == 1000)
+	if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
 		edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
 	else
 		edac_queue_work(&edac_dev->work, edac_dev->delay);
@@ -396,7 +399,7 @@
 	 * timers firing on sub-second basis, while they are happy
 	 * to fire together on the 1 second exactly
 	 */
-	if (edac_dev->poll_msec == 1000)
+	if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
 		edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
 	else
 		edac_queue_work(&edac_dev->work, edac_dev->delay);
@@ -424,17 +427,16 @@
  *	Then restart the workq on the new delay
  */
 void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
-					unsigned long value)
+				    unsigned long msec)
 {
-	unsigned long jiffs = msecs_to_jiffies(value);
-
-	if (value == 1000)
-		jiffs = round_jiffies_relative(value);
-
-	edac_dev->poll_msec = value;
-	edac_dev->delay	    = jiffs;
+	edac_dev->poll_msec = msec;
+	edac_dev->delay	    = msecs_to_jiffies(msec);
 
-	edac_mod_work(&edac_dev->work, jiffs);
+	/* See comment in edac_device_workq_setup() above */
+	if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
+		edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
+	else
+		edac_mod_work(&edac_dev->work, edac_dev->delay);
 }
 
 int edac_device_alloc_index(void)
@@ -473,11 +475,7 @@
 		/* This instance is NOW RUNNING */
 		edac_dev->op_state = OP_RUNNING_POLL;
 
-		/*
-		 * enable workq processing on this instance,
-		 * default = 1000 msec
-		 */
-		edac_device_workq_setup(edac_dev, 1000);
+		edac_device_workq_setup(edac_dev, edac_dev->poll_msec ?: DEFAULT_POLL_INTERVAL);
 	} else {
 		edac_dev->op_state = OP_RUNNING_INTERRUPT;
 	}
--- linux-ein-5.4.0.orig/drivers/edac/edac_device_sysfs.c
+++ linux-ein-5.4.0/drivers/edac/edac_device_sysfs.c
@@ -275,6 +275,7 @@
 
 	/* Error exit stack */
 err_kobj_reg:
+	kobject_put(&edac_dev->kobj);
 	module_put(edac_dev->owner);
 
 err_out:
--- linux-ein-5.4.0.orig/drivers/edac/edac_mc.c
+++ linux-ein-5.4.0/drivers/edac/edac_mc.c
@@ -263,7 +263,7 @@
 	else
 		return (char *)ptr;
 
-	r = (unsigned long)p % align;
+	r = (unsigned long)ptr % align;
 
 	if (r == 0)
 		return (char *)ptr;
@@ -503,16 +503,10 @@
 {
 	edac_dbg(1, "\n");
 
-	/* If we're not yet registered with sysfs free only what was allocated
-	 * in edac_mc_alloc().
-	 */
-	if (!device_is_registered(&mci->dev)) {
-		_edac_mc_free(mci);
-		return;
-	}
+	if (device_is_registered(&mci->dev))
+		edac_unregister_sysfs(mci);
 
-	/* the mci instance is freed here, when the sysfs object is dropped */
-	edac_unregister_sysfs(mci);
+	_edac_mc_free(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
--- linux-ein-5.4.0.orig/drivers/edac/edac_mc_sysfs.c
+++ linux-ein-5.4.0/drivers/edac/edac_mc_sysfs.c
@@ -276,10 +276,7 @@
 
 static void csrow_attr_release(struct device *dev)
 {
-	struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
-
-	edac_dbg(1, "device %s released\n", dev_name(dev));
-	kfree(csrow);
+	/* release device with _edac_mc_free() */
 }
 
 static const struct device_type csrow_attr_type = {
@@ -447,8 +444,7 @@
 		csrow = mci->csrows[i];
 		if (!nr_pages_per_csrow(csrow))
 			continue;
-
-		device_del(&mci->csrows[i]->dev);
+		device_unregister(&mci->csrows[i]->dev);
 	}
 
 	return err;
@@ -620,10 +616,7 @@
 
 static void dimm_attr_release(struct device *dev)
 {
-	struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
-
-	edac_dbg(1, "device %s released\n", dev_name(dev));
-	kfree(dimm);
+	/* release device with _edac_mc_free() */
 }
 
 static const struct device_type dimm_attr_type = {
@@ -906,10 +899,7 @@
 
 static void mci_attr_release(struct device *dev)
 {
-	struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
-
-	edac_dbg(1, "device %s released\n", dev_name(dev));
-	kfree(mci);
+	/* release device with _edac_mc_free() */
 }
 
 static const struct device_type mci_attr_type = {
--- linux-ein-5.4.0.orig/drivers/edac/edac_module.h
+++ linux-ein-5.4.0/drivers/edac/edac_module.h
@@ -57,7 +57,7 @@
 bool edac_mod_work(struct delayed_work *work, unsigned long delay);
 
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
-					   *edac_dev, unsigned long value);
+					   *edac_dev, unsigned long msec);
 extern void edac_mc_reset_delay_period(unsigned long value);
 
 extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
--- linux-ein-5.4.0.orig/drivers/edac/edac_pci_sysfs.c
+++ linux-ein-5.4.0/drivers/edac/edac_pci_sysfs.c
@@ -386,7 +386,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-ein-5.4.0.orig/drivers/edac/ghes_edac.c
+++ linux-ein-5.4.0/drivers/edac/ghes_edac.c
@@ -26,9 +26,18 @@
 	char msg[80];
 };
 
-static atomic_t ghes_init = ATOMIC_INIT(0);
+static refcount_t ghes_refcount = REFCOUNT_INIT(0);
+
+/*
+ * Access to ghes_pvt must be protected by ghes_lock. The spinlock
+ * also provides the necessary (implicit) memory barrier for the SMP
+ * case to make the pointer visible on another CPU.
+ */
 static struct ghes_edac_pvt *ghes_pvt;
 
+/* GHES registration mutex */
+static DEFINE_MUTEX(ghes_reg_mutex);
+
 /*
  * Sync with other, potentially concurrent callers of
  * ghes_edac_report_mem_error(). We don't know what the
@@ -79,9 +88,8 @@
 		(*num_dimm)++;
 }
 
-static int get_dimm_smbios_index(u16 handle)
+static int get_dimm_smbios_index(struct mem_ctl_info *mci, u16 handle)
 {
-	struct mem_ctl_info *mci = ghes_pvt->mci;
 	int i;
 
 	for (i = 0; i < mci->tot_dimms; i++) {
@@ -198,14 +206,11 @@
 	enum hw_event_mc_err_type type;
 	struct edac_raw_error_desc *e;
 	struct mem_ctl_info *mci;
-	struct ghes_edac_pvt *pvt = ghes_pvt;
+	struct ghes_edac_pvt *pvt;
 	unsigned long flags;
 	char *p;
 	u8 grain_bits;
 
-	if (!pvt)
-		return;
-
 	/*
 	 * We can do the locking below because GHES defers error processing
 	 * from NMI to IRQ context. Whenever that changes, we'd at least
@@ -216,12 +221,17 @@
 
 	spin_lock_irqsave(&ghes_lock, flags);
 
+	pvt = ghes_pvt;
+	if (!pvt)
+		goto unlock;
+
 	mci = pvt->mci;
 	e = &mci->error_desc;
 
 	/* 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;
@@ -317,7 +327,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;
@@ -348,7 +358,7 @@
 			p += sprintf(p, "DIMM DMI handle: 0x%.4x ",
 				     mem_err->mem_dev_handle);
 
-		index = get_dimm_smbios_index(mem_err->mem_dev_handle);
+		index = get_dimm_smbios_index(mci, mem_err->mem_dev_handle);
 		if (index >= 0) {
 			e->top_layer = index;
 			e->enable_per_layer_report = true;
@@ -433,8 +443,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,
@@ -443,6 +458,8 @@
 		       grain_bits, e->syndrome, pvt->detail_location);
 
 	edac_raw_mc_handle_error(type, mci, e);
+
+unlock:
 	spin_unlock_irqrestore(&ghes_lock, flags);
 }
 
@@ -457,10 +474,12 @@
 int ghes_edac_register(struct ghes *ghes, struct device *dev)
 {
 	bool fake = false;
-	int rc, num_dimm = 0;
+	int rc = 0, num_dimm = 0;
 	struct mem_ctl_info *mci;
+	struct ghes_edac_pvt *pvt;
 	struct edac_mc_layer layers[1];
 	struct ghes_edac_dimm_fill dimm_fill;
+	unsigned long flags;
 	int idx = -1;
 
 	if (IS_ENABLED(CONFIG_X86)) {
@@ -469,14 +488,18 @@
 		if (!force_load && idx < 0)
 			return -ENODEV;
 	} else {
+		force_load = true;
 		idx = 0;
 	}
 
+	/* finish another registration/unregistration instance first */
+	mutex_lock(&ghes_reg_mutex);
+
 	/*
 	 * We have only one logical memory controller to which all DIMMs belong.
 	 */
-	if (atomic_inc_return(&ghes_init) > 1)
-		return 0;
+	if (refcount_inc_not_zero(&ghes_refcount))
+		goto unlock;
 
 	/* Get the number of DIMMs */
 	dmi_walk(ghes_edac_count_dimms, &num_dimm);
@@ -494,12 +517,13 @@
 	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(struct ghes_edac_pvt));
 	if (!mci) {
 		pr_info("Can't allocate memory for EDAC data\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto unlock;
 	}
 
-	ghes_pvt	= mci->pvt_info;
-	ghes_pvt->ghes	= ghes;
-	ghes_pvt->mci	= mci;
+	pvt		= mci->pvt_info;
+	pvt->ghes	= ghes;
+	pvt->mci	= mci;
 
 	mci->pdev = dev;
 	mci->mtype_cap = MEM_FLAG_EMPTY;
@@ -541,23 +565,51 @@
 	if (rc < 0) {
 		pr_info("Can't register at EDAC core\n");
 		edac_mc_free(mci);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto unlock;
 	}
-	return 0;
+
+	spin_lock_irqsave(&ghes_lock, flags);
+	ghes_pvt = pvt;
+	spin_unlock_irqrestore(&ghes_lock, flags);
+
+	/* only set on success */
+	refcount_set(&ghes_refcount, 1);
+
+unlock:
+	mutex_unlock(&ghes_reg_mutex);
+
+	return rc;
 }
 
 void ghes_edac_unregister(struct ghes *ghes)
 {
 	struct mem_ctl_info *mci;
+	unsigned long flags;
 
-	if (!ghes_pvt)
+	if (!force_load)
 		return;
 
-	if (atomic_dec_return(&ghes_init))
-		return;
+	mutex_lock(&ghes_reg_mutex);
 
-	mci = ghes_pvt->mci;
+	if (!refcount_dec_and_test(&ghes_refcount))
+		goto unlock;
+
+	/*
+	 * Wait for the irq handler being finished.
+	 */
+	spin_lock_irqsave(&ghes_lock, flags);
+	mci = ghes_pvt ? ghes_pvt->mci : NULL;
 	ghes_pvt = NULL;
-	edac_mc_del_mc(mci->pdev);
-	edac_mc_free(mci);
+	spin_unlock_irqrestore(&ghes_lock, flags);
+
+	if (!mci)
+		goto unlock;
+
+	mci = edac_mc_del_mc(mci->pdev);
+	if (mci)
+		edac_mc_free(mci);
+
+unlock:
+	mutex_unlock(&ghes_reg_mutex);
 }
--- linux-ein-5.4.0.orig/drivers/edac/highbank_mc_edac.c
+++ linux-ein-5.4.0/drivers/edac/highbank_mc_edac.c
@@ -174,8 +174,10 @@
 	drvdata = mci->pvt_info;
 	platform_set_drvdata(pdev, mci);
 
-	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
-		return -ENOMEM;
+	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+		res = -ENOMEM;
+		goto free;
+	}
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r) {
@@ -243,6 +245,7 @@
 	edac_mc_del_mc(&pdev->dev);
 err:
 	devres_release_group(&pdev->dev, NULL);
+free:
 	edac_mc_free(mci);
 	return res;
 }
--- linux-ein-5.4.0.orig/drivers/edac/i10nm_base.c
+++ linux-ein-5.4.0/drivers/edac/i10nm_base.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/mce.h>
@@ -19,14 +20,16 @@
 #define i10nm_printk(level, fmt, arg...)	\
 	edac_printk(level, "i10nm", fmt, ##arg)
 
-#define I10NM_GET_SCK_BAR(d, reg)		\
+#define I10NM_GET_SCK_BAR(d, reg)	\
 	pci_read_config_dword((d)->uracu, 0xd0, &(reg))
 #define I10NM_GET_IMC_BAR(d, i, reg)	\
 	pci_read_config_dword((d)->uracu, 0xd8 + (i) * 4, &(reg))
 #define I10NM_GET_DIMMMTR(m, i, j)	\
-	(*(u32 *)((m)->mbase + 0x2080c + (i) * 0x4000 + (j) * 4))
-#define I10NM_GET_MCDDRTCFG(m, i, j)	\
-	(*(u32 *)((m)->mbase + 0x20970 + (i) * 0x4000 + (j) * 4))
+	readl((m)->mbase + 0x2080c + (i) * 0x4000 + (j) * 4)
+#define I10NM_GET_MCDDRTCFG(m, i)	\
+	readl((m)->mbase + 0x20970 + (i) * 0x4000)
+#define I10NM_GET_MCMTR(m, i)		\
+	readl((m)->mbase + 0x20ef8 + (i) * 0x4000)
 
 #define I10NM_GET_SCK_MMIO_BASE(reg)	(GET_BITFIELD(reg, 0, 28) << 23)
 #define I10NM_GET_IMC_MMIO_OFFSET(reg)	(GET_BITFIELD(reg, 0, 10) << 12)
@@ -50,11 +53,10 @@
 	if (unlikely(pci_enable_device(pdev) < 0)) {
 		edac_dbg(2, "Failed to enable device %02x:%02x.%x\n",
 			 bus, dev, fun);
+		pci_dev_put(pdev);
 		return NULL;
 	}
 
-	pci_dev_get(pdev);
-
 	return pdev;
 }
 
@@ -134,7 +136,7 @@
 {
 	u32 mcmtr;
 
-	mcmtr = *(u32 *)(imc->mbase + 0x20ef8 + chan * 0x4000);
+	mcmtr = I10NM_GET_MCMTR(imc, chan);
 	edac_dbg(1, "ch%d mcmtr reg %x\n", chan, mcmtr);
 
 	return !!GET_BITFIELD(mcmtr, 2, 2);
@@ -153,16 +155,16 @@
 			continue;
 
 		ndimms = 0;
+		mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i);
 		for (j = 0; j < I10NM_NUM_DIMMS; j++) {
 			dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
 					     mci->n_layers, i, j, 0);
 			mtr = I10NM_GET_DIMMMTR(imc, i, j);
-			mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i, j);
 			edac_dbg(1, "dimmmtr 0x%x mcddrtcfg 0x%x (mc%d ch%d dimm%d)\n",
 				 mtr, mcddrtcfg, imc->mc, i, j);
 
 			if (IS_DIMM_PRESENT(mtr))
-				ndimms += skx_get_dimm_info(mtr, 0, dimm,
+				ndimms += skx_get_dimm_info(mtr, 0, 0, dimm,
 							    imc, i, j);
 			else if (IS_NVDIMM_PRESENT(mcddrtcfg, j))
 				ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
@@ -246,6 +248,9 @@
 	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
 		return -EBUSY;
 
+	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+		return -ENODEV;
+
 	id = x86_match_cpu(i10nm_cpuids);
 	if (!id)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/edac/i5100_edac.c
+++ linux-ein-5.4.0/drivers/edac/i5100_edac.c
@@ -1074,16 +1074,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;
@@ -1149,14 +1148,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-ein-5.4.0.orig/drivers/edac/i7core_edac.c
+++ linux-ein-5.4.0/drivers/edac/i7core_edac.c
@@ -1711,9 +1711,9 @@
 	if (uncorrected_error) {
 		core_err_cnt = 1;
 		if (ripv)
-			tp_event = HW_EVENT_ERR_FATAL;
-		else
 			tp_event = HW_EVENT_ERR_UNCORRECTED;
+		else
+			tp_event = HW_EVENT_ERR_FATAL;
 	} else {
 		tp_event = HW_EVENT_ERR_CORRECTED;
 	}
--- linux-ein-5.4.0.orig/drivers/edac/ie31200_edac.c
+++ linux-ein-5.4.0/drivers/edac/ie31200_edac.c
@@ -170,6 +170,8 @@
 	(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;
@@ -541,12 +543,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)
@@ -555,6 +561,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;
@@ -596,17 +604,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-ein-5.4.0.orig/drivers/edac/mce_amd.c
+++ linux-ein-5.4.0/drivers/edac/mce_amd.c
@@ -175,6 +175,33 @@
 	"L2 Fill Data error",
 };
 
+static const char * const smca_ls2_mce_desc[] = {
+	"An ECC error was detected on a data cache read by a probe or victimization",
+	"An ECC error or L2 poison was detected on a data cache read by a load",
+	"An ECC error was detected on a data cache read-modify-write by a store",
+	"An ECC error or poison bit mismatch was detected on a tag read by a probe or victimization",
+	"An ECC error or poison bit mismatch was detected on a tag read by a load",
+	"An ECC error or poison bit mismatch was detected on a tag read by a store",
+	"An ECC error was detected on an EMEM read by a load",
+	"An ECC error was detected on an EMEM read-modify-write by a store",
+	"A parity error was detected in an L1 TLB entry by any access",
+	"A parity error was detected in an L2 TLB entry by any access",
+	"A parity error was detected in a PWC entry by any access",
+	"A parity error was detected in an STQ entry by any access",
+	"A parity error was detected in an LDQ entry by any access",
+	"A parity error was detected in a MAB entry by any access",
+	"A parity error was detected in an SCB entry state field by any access",
+	"A parity error was detected in an SCB entry address field by any access",
+	"A parity error was detected in an SCB entry data field by any access",
+	"A parity error was detected in a WCB entry by any access",
+	"A poisoned line was detected in an SCB entry by any access",
+	"A SystemReadDataError error was reported on read data returned from L2 for a load",
+	"A SystemReadDataError error was reported on read data returned from L2 for an SCB store",
+	"A SystemReadDataError error was reported on read data returned from L2 for a WCB store",
+	"A hardware assertion error was reported",
+	"A parity error was detected in an STLF, SCB EMEM entry or SRB store data by any access",
+};
+
 static const char * const smca_if_mce_desc[] = {
 	"Op Cache Microtag Probe Port Parity Error",
 	"IC Microtag or Full Tag Multi-hit Error",
@@ -378,6 +405,7 @@
 
 static struct smca_mce_desc smca_mce_descs[] = {
 	[SMCA_LS]	= { smca_ls_mce_desc,	ARRAY_SIZE(smca_ls_mce_desc)	},
+	[SMCA_LS_V2]	= { smca_ls2_mce_desc,	ARRAY_SIZE(smca_ls2_mce_desc)	},
 	[SMCA_IF]	= { smca_if_mce_desc,	ARRAY_SIZE(smca_if_mce_desc)	},
 	[SMCA_L2_CACHE]	= { smca_l2_mce_desc,	ARRAY_SIZE(smca_l2_mce_desc)	},
 	[SMCA_DE]	= { smca_de_mce_desc,	ARRAY_SIZE(smca_de_mce_desc)	},
@@ -975,7 +1003,7 @@
 	}
 
 	if (bank_type == SMCA_UMC && xec == 0 && decode_dram_ecc)
-		decode_dram_ecc(cpu_to_node(m->extcpu), m);
+		decode_dram_ecc(topology_die_id(m->extcpu), m);
 }
 
 static inline void amd_decode_err_code(u16 ec)
@@ -1161,6 +1189,11 @@
 	if (!fam_ops)
 		return -ENOMEM;
 
+	if (boot_cpu_has(X86_FEATURE_SMCA)) {
+		xec_mask = 0x3f;
+		goto out;
+	}
+
 	switch (c->x86) {
 	case 0xf:
 		fam_ops->mc0_mce = k8_mc0_mce;
@@ -1209,11 +1242,8 @@
 
 	case 0x17:
 	case 0x18:
-		xec_mask = 0x3f;
-		if (!boot_cpu_has(X86_FEATURE_SMCA)) {
-			printk(KERN_WARNING "Decoding supported only on Scalable MCA processors.\n");
-			goto err_out;
-		}
+		pr_warn("Decoding supported only on Scalable MCA processors.\n");
+		goto err_out;
 		break;
 
 	default:
@@ -1221,6 +1251,7 @@
 		goto err_out;
 	}
 
+out:
 	pr_info("MCE: In-kernel MCE decoding enabled.\n");
 
 	mce_register_decode_chain(&amd_mce_dec_nb);
--- linux-ein-5.4.0.orig/drivers/edac/pnd2_edac.c
+++ linux-ein-5.4.0/drivers/edac/pnd2_edac.c
@@ -1155,7 +1155,7 @@
 	u32 optypenum = GET_BITFIELD(m->status, 4, 6);
 	int rc;
 
-	tp_event = uc_err ? (ripv ? HW_EVENT_ERR_FATAL : HW_EVENT_ERR_UNCORRECTED) :
+	tp_event = uc_err ? (ripv ? HW_EVENT_ERR_UNCORRECTED : HW_EVENT_ERR_FATAL) :
 						 HW_EVENT_ERR_CORRECTED;
 
 	/*
@@ -1555,6 +1555,9 @@
 	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
 		return -EBUSY;
 
+	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+		return -ENODEV;
+
 	id = x86_match_cpu(pnd2_cpuids);
 	if (!id)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/edac/qcom_edac.c
+++ linux-ein-5.4.0/drivers/edac/qcom_edac.c
@@ -252,7 +252,7 @@
 static int
 dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
 {
-	struct llcc_drv_data *drv = edev_ctl->pvt_info;
+	struct llcc_drv_data *drv = edev_ctl->dev->platform_data;
 	int ret;
 
 	ret = dump_syn_reg_values(drv, bank, err_type);
@@ -289,7 +289,7 @@
 llcc_ecc_irq_handler(int irq, void *edev_ctl)
 {
 	struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
-	struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
+	struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data;
 	irqreturn_t irq_rc = IRQ_NONE;
 	u32 drp_error, trp_error, i;
 	int ret;
@@ -358,7 +358,6 @@
 	edev_ctl->dev_name = dev_name(dev);
 	edev_ctl->ctl_name = "llcc";
 	edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
-	edev_ctl->pvt_info = llcc_driv_data;
 
 	rc = edac_device_add_device(edev_ctl);
 	if (rc)
--- linux-ein-5.4.0.orig/drivers/edac/sb_edac.c
+++ linux-ein-5.4.0/drivers/edac/sb_edac.c
@@ -254,18 +254,20 @@
  * FIXME: Implement the error count reads directly
  */
 
-static const u32 correrrcnt[] = {
-	0x104, 0x108, 0x10c, 0x110,
-};
-
 #define RANK_ODD_OV(reg)		GET_BITFIELD(reg, 31, 31)
 #define RANK_ODD_ERR_CNT(reg)		GET_BITFIELD(reg, 16, 30)
 #define RANK_EVEN_OV(reg)		GET_BITFIELD(reg, 15, 15)
 #define RANK_EVEN_ERR_CNT(reg)		GET_BITFIELD(reg,  0, 14)
 
+#if 0 /* Currently unused*/
+static const u32 correrrcnt[] = {
+	0x104, 0x108, 0x10c, 0x110,
+};
+
 static const u32 correrrthrsld[] = {
 	0x11c, 0x120, 0x124, 0x128,
 };
+#endif
 
 #define RANK_ODD_ERR_THRSLD(reg)	GET_BITFIELD(reg, 16, 30)
 #define RANK_EVEN_ERR_THRSLD(reg)	GET_BITFIELD(reg,  0, 14)
@@ -1053,7 +1055,7 @@
 	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, &reg);
 	rc = ((reg << 6) | rc) << 26;
 
-	return rc | 0x1ffffff;
+	return rc | 0x3ffffff;
 }
 
 static u64 knl_get_tolm(struct sbridge_pvt *pvt)
@@ -1340,7 +1342,7 @@
  */
 static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
 {
-	u64 sad_base, sad_size, sad_limit = 0;
+	u64 sad_base, sad_limit = 0;
 	u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace;
 	int sad_rule = 0;
 	int tad_rule = 0;
@@ -1427,7 +1429,6 @@
 		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);
@@ -2952,7 +2953,7 @@
 	struct mem_ctl_info *new_mci;
 	struct sbridge_pvt *pvt = mci->pvt_info;
 	enum hw_event_mc_err_type tp_event;
-	char *type, *optype, msg[256];
+	char *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);
@@ -2981,14 +2982,11 @@
 	if (uncorrected_error) {
 		core_err_cnt = 1;
 		if (ripv) {
-			type = "FATAL";
-			tp_event = HW_EVENT_ERR_FATAL;
-		} else {
-			type = "NON_FATAL";
 			tp_event = HW_EVENT_ERR_UNCORRECTED;
+		} else {
+			tp_event = HW_EVENT_ERR_FATAL;
 		}
 	} else {
-		type = "CORRECTED";
 		tp_event = HW_EVENT_ERR_CORRECTED;
 	}
 
@@ -3200,7 +3198,6 @@
 static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 {
 	struct mem_ctl_info *mci = sbridge_dev->mci;
-	struct sbridge_pvt *pvt;
 
 	if (unlikely(!mci || !mci->pvt_info)) {
 		edac_dbg(0, "MC: dev = %p\n", &sbridge_dev->pdev[0]->dev);
@@ -3209,8 +3206,6 @@
 		return;
 	}
 
-	pvt = mci->pvt_info;
-
 	edac_dbg(0, "MC: mci = %p, dev = %p\n",
 		 mci, &sbridge_dev->pdev[0]->dev);
 
@@ -3517,6 +3512,9 @@
 	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
 		return -EBUSY;
 
+	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+		return -ENODEV;
+
 	id = x86_match_cpu(sbridge_cpuids);
 	if (!id)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/edac/sifive_edac.c
+++ linux-ein-5.4.0/drivers/edac/sifive_edac.c
@@ -54,8 +54,8 @@
 	p->dci = edac_device_alloc_ctl_info(0, "sifive_ecc", 1, "sifive_ecc",
 					    1, 1, NULL, 0,
 					    edac_device_alloc_index());
-	if (IS_ERR(p->dci))
-		return PTR_ERR(p->dci);
+	if (!p->dci)
+		return -ENOMEM;
 
 	p->dci->dev = &pdev->dev;
 	p->dci->mod_name = "Sifive ECC Manager";
--- linux-ein-5.4.0.orig/drivers/edac/skx_base.c
+++ linux-ein-5.4.0/drivers/edac/skx_base.c
@@ -151,27 +151,23 @@
 };
 MODULE_DEVICE_TABLE(x86cpu, skx_cpuids);
 
-#define SKX_GET_MTMTR(dev, reg) \
-	pci_read_config_dword((dev), 0x87c, &(reg))
-
-static bool skx_check_ecc(struct pci_dev *pdev)
+static bool skx_check_ecc(u32 mcmtr)
 {
-	u32 mtmtr;
-
-	SKX_GET_MTMTR(pdev, mtmtr);
-
-	return !!GET_BITFIELD(mtmtr, 2, 2);
+	return !!GET_BITFIELD(mcmtr, 2, 2);
 }
 
 static int skx_get_dimm_config(struct mem_ctl_info *mci)
 {
 	struct skx_pvt *pvt = mci->pvt_info;
+	u32 mtr, mcmtr, amap, mcddrtcfg;
 	struct skx_imc *imc = pvt->imc;
-	u32 mtr, amap, mcddrtcfg;
 	struct dimm_info *dimm;
 	int i, j;
 	int ndimms;
 
+	/* Only the mcmtr on the first channel is effective */
+	pci_read_config_dword(imc->chan[0].cdev, 0x87c, &mcmtr);
+
 	for (i = 0; i < SKX_NUM_CHANNELS; i++) {
 		ndimms = 0;
 		pci_read_config_dword(imc->chan[i].cdev, 0x8C, &amap);
@@ -182,14 +178,14 @@
 			pci_read_config_dword(imc->chan[i].cdev,
 					      0x80 + 4 * j, &mtr);
 			if (IS_DIMM_PRESENT(mtr)) {
-				ndimms += skx_get_dimm_info(mtr, amap, dimm, imc, i, j);
+				ndimms += skx_get_dimm_info(mtr, mcmtr, amap, dimm, imc, i, j);
 			} else if (IS_NVDIMM_PRESENT(mcddrtcfg, j)) {
 				ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
 							      EDAC_MOD_STR);
 				nvdimm_count++;
 			}
 		}
-		if (ndimms && !skx_check_ecc(imc->chan[0].cdev)) {
+		if (ndimms && !skx_check_ecc(mcmtr)) {
 			skx_printk(KERN_ERR, "ECC is disabled on imc %d\n", imc->mc);
 			return -ENODEV;
 		}
@@ -463,7 +459,7 @@
 }
 
 static u8 skx_close_row[] = {
-	15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33
+	15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33, 34
 };
 
 static u8 skx_close_column[] = {
@@ -471,7 +467,7 @@
 };
 
 static u8 skx_open_row[] = {
-	14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33
+	14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34
 };
 
 static u8 skx_open_column[] = {
@@ -609,6 +605,9 @@
 	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
 		return -EBUSY;
 
+	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+		return -ENODEV;
+
 	id = x86_match_cpu(skx_cpuids);
 	if (!id)
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/edac/skx_common.c
+++ linux-ein-5.4.0/drivers/edac/skx_common.c
@@ -235,7 +235,7 @@
 
 	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, did, NULL);
 	if (!pdev) {
-		skx_printk(KERN_ERR, "Can't get tolm/tohm\n");
+		edac_dbg(2, "Can't get tolm/tohm\n");
 		return -ENODEV;
 	}
 
@@ -283,7 +283,7 @@
 #define numrow(reg)	skx_get_dimm_attr(reg, 2, 4, 12, 1, 6, "rows")
 #define numcol(reg)	skx_get_dimm_attr(reg, 0, 1, 10, 0, 2, "cols")
 
-int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
+int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
 		      struct skx_imc *imc, int chan, int dimmno)
 {
 	int  banks = 16, ranks, rows, cols, npages;
@@ -303,8 +303,8 @@
 		 imc->mc, chan, dimmno, size, npages,
 		 banks, 1 << 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].close_pg = GET_BITFIELD(mcmtr, 0, 0);
+	imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mcmtr, 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;
@@ -475,7 +475,7 @@
 				 struct decoded_addr *res)
 {
 	enum hw_event_mc_err_type tp_event;
-	char *type, *optype;
+	char *optype;
 	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);
@@ -490,14 +490,11 @@
 	if (uncorrected_error) {
 		core_err_cnt = 1;
 		if (ripv) {
-			type = "FATAL";
-			tp_event = HW_EVENT_ERR_FATAL;
-		} else {
-			type = "NON_FATAL";
 			tp_event = HW_EVENT_ERR_UNCORRECTED;
+		} else {
+			tp_event = HW_EVENT_ERR_FATAL;
 		}
 	} else {
-		type = "CORRECTED";
 		tp_event = HW_EVENT_ERR_CORRECTED;
 	}
 
--- linux-ein-5.4.0.orig/drivers/edac/skx_common.h
+++ linux-ein-5.4.0/drivers/edac/skx_common.h
@@ -126,7 +126,7 @@
 
 int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm);
 
-int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
+int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
 		      struct skx_imc *imc, int chan, int dimmno);
 
 int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,
--- linux-ein-5.4.0.orig/drivers/edac/synopsys_edac.c
+++ linux-ein-5.4.0/drivers/edac/synopsys_edac.c
@@ -163,6 +163,11 @@
 #define ECC_STAT_CECNT_SHIFT		8
 #define ECC_STAT_BITNUM_MASK		0x7F
 
+/* ECC error count register definitions */
+#define ECC_ERRCNT_UECNT_MASK		0xFFFF0000
+#define ECC_ERRCNT_UECNT_SHIFT		16
+#define ECC_ERRCNT_CECNT_MASK		0xFFFF
+
 /* DDR QOS Interrupt register definitions */
 #define DDR_QOS_IRQ_STAT_OFST		0x20200
 #define DDR_QOSUE_MASK			0x4
@@ -418,15 +423,16 @@
 	base = priv->baseaddr;
 	p = &priv->stat;
 
+	regval = readl(base + ECC_ERRCNT_OFST);
+	p->ce_cnt = regval & ECC_ERRCNT_CECNT_MASK;
+	p->ue_cnt = (regval & ECC_ERRCNT_UECNT_MASK) >> ECC_ERRCNT_UECNT_SHIFT;
+	if (!p->ce_cnt)
+		goto ue_err;
+
 	regval = readl(base + ECC_STAT_OFST);
 	if (!regval)
 		return 1;
 
-	p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT;
-	p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT;
-	if (!p->ce_cnt)
-		goto ue_err;
-
 	p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK);
 
 	regval = readl(base + ECC_CEADDR0_OFST);
@@ -479,20 +485,14 @@
 		pinf = &p->ceinfo;
 		if (!priv->p_data->quirks) {
 			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "DDR ECC error type:%s Row %d Bank %d Col %d ",
-				  "CE", pinf->row, pinf->bank, pinf->col);
-			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "Bit Position: %d Data: 0x%08x\n",
+				 "DDR ECC error type:%s Row %d Bank %d Col %d Bit Position: %d Data: 0x%08x",
+				 "CE", pinf->row, pinf->bank, pinf->col,
 				 pinf->bitpos, pinf->data);
 		} else {
 			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "DDR ECC error type:%s Row %d Bank %d Col %d ",
-				  "CE", pinf->row, pinf->bank, pinf->col);
-			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "BankGroup Number %d Block Number %d ",
-				 pinf->bankgrpnr, pinf->blknr);
-			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "Bit Position: %d Data: 0x%08x\n",
+				 "DDR ECC error type:%s Row %d Bank %d Col %d BankGroup Number %d Block Number %d Bit Position: %d Data: 0x%08x",
+				 "CE", pinf->row, pinf->bank, pinf->col,
+				 pinf->bankgrpnr, pinf->blknr,
 				 pinf->bitpos, pinf->data);
 		}
 
@@ -509,10 +509,8 @@
 				"UE", pinf->row, pinf->bank, pinf->col);
 		} else {
 			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "DDR ECC error type :%s Row %d Bank %d Col %d ",
-				 "UE", pinf->row, pinf->bank, pinf->col);
-			snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-				 "BankGroup Number %d Block Number %d",
+				 "DDR ECC error type :%s Row %d Bank %d Col %d BankGroup Number %d Block Number %d",
+				 "UE", pinf->row, pinf->bank, pinf->col,
 				 pinf->bankgrpnr, pinf->blknr);
 		}
 
@@ -790,7 +788,7 @@
 
 		for (j = 0; j < csi->nr_channels; j++) {
 			dimm		= csi->channels[j]->dimm;
-			dimm->edac_mode	= EDAC_FLAG_SECDED;
+			dimm->edac_mode	= EDAC_SECDED;
 			dimm->mtype	= p_data->get_mtype(priv->baseaddr);
 			dimm->nr_pages	= (size >> PAGE_SHIFT) / csi->nr_channels;
 			dimm->grain	= SYNPS_EDAC_ERR_GRAIN;
@@ -1359,8 +1357,7 @@
 		}
 	}
 
-	if (of_device_is_compatible(pdev->dev.of_node,
-				    "xlnx,zynqmp-ddrc-2.40a"))
+	if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT)
 		setup_address_map(priv);
 #endif
 
--- linux-ein-5.4.0.orig/drivers/edac/thunderx_edac.c
+++ linux-ein-5.4.0/drivers/edac/thunderx_edac.c
@@ -1133,7 +1133,7 @@
 		decode_register(other, OCX_OTHER_SIZE,
 				ocx_com_errors, ctx->reg_com_int);
 
-		strncat(msg, other, OCX_MESSAGE_SIZE);
+		strlcat(msg, other, OCX_MESSAGE_SIZE);
 
 		for (lane = 0; lane < OCX_RX_LANES; lane++)
 			if (ctx->reg_com_int & BIT(lane)) {
@@ -1142,12 +1142,12 @@
 					 lane, ctx->reg_lane_int[lane],
 					 lane, ctx->reg_lane_stat11[lane]);
 
-				strncat(msg, other, OCX_MESSAGE_SIZE);
+				strlcat(msg, other, OCX_MESSAGE_SIZE);
 
 				decode_register(other, OCX_OTHER_SIZE,
 						ocx_lane_errors,
 						ctx->reg_lane_int[lane]);
-				strncat(msg, other, OCX_MESSAGE_SIZE);
+				strlcat(msg, other, OCX_MESSAGE_SIZE);
 			}
 
 		if (ctx->reg_com_int & OCX_COM_INT_CE)
@@ -1217,7 +1217,7 @@
 		decode_register(other, OCX_OTHER_SIZE,
 				ocx_com_link_errors, ctx->reg_com_link_int);
 
-		strncat(msg, other, OCX_MESSAGE_SIZE);
+		strlcat(msg, other, OCX_MESSAGE_SIZE);
 
 		if (ctx->reg_com_link_int & OCX_COM_LINK_INT_UE)
 			edac_device_handle_ue(ocx->edac_dev, 0, 0, msg);
@@ -1896,7 +1896,7 @@
 
 		decode_register(other, L2C_OTHER_SIZE, l2_errors, ctx->reg_int);
 
-		strncat(msg, other, L2C_MESSAGE_SIZE);
+		strlcat(msg, other, L2C_MESSAGE_SIZE);
 
 		if (ctx->reg_int & mask_ue)
 			edac_device_handle_ue(l2c->edac_dev, 0, 0, msg);
--- linux-ein-5.4.0.orig/drivers/edac/ti_edac.c
+++ linux-ein-5.4.0/drivers/edac/ti_edac.c
@@ -197,6 +197,7 @@
 	{ .compatible = "ti,emif-dra7xx", .data = (void *)EMIF_TYPE_DRA7 },
 	{},
 };
+MODULE_DEVICE_TABLE(of, ti_edac_of_match);
 
 static int _emif_get_id(struct device_node *node)
 {
@@ -278,7 +279,8 @@
 
 	/* add EMIF ECC error handler */
 	error_irq = platform_get_irq(pdev, 0);
-	if (!error_irq) {
+	if (error_irq < 0) {
+		ret = error_irq;
 		edac_printk(KERN_ERR, EDAC_MOD_NAME,
 			    "EMIF irq number not defined.\n");
 		goto err;
--- linux-ein-5.4.0.orig/drivers/edac/xgene_edac.c
+++ linux-ein-5.4.0/drivers/edac/xgene_edac.c
@@ -1922,7 +1922,7 @@
 			irq = platform_get_irq(pdev, i);
 			if (irq < 0) {
 				dev_err(&pdev->dev, "No IRQ resource\n");
-				rc = -EINVAL;
+				rc = irq;
 				goto out_err;
 			}
 			rc = devm_request_irq(&pdev->dev, irq,
--- linux-ein-5.4.0.orig/drivers/extcon/Kconfig
+++ linux-ein-5.4.0/drivers/extcon/Kconfig
@@ -142,6 +142,14 @@
 	  Say Y here to enable support for USB peripheral and USB host
 	  detection by NXP PTN5150 CC (Configuration Channel) logic chip.
 
+config EXTCON_IT5201
+	tristate "ITE IT5201 CC Logic For Type-C Applications"
+	depends on I2C && GPIOLIB
+	select REGMAP_I2C
+	help
+	  Say Y here to enable ITE IT5201 CC logic for Type-C applications,
+	  this chip can supply the CC flip, attach and detach detection.
+
 config EXTCON_QCOM_SPMI_MISC
 	tristate "Qualcomm USB extcon support"
 	depends on ARCH_QCOM || COMPILE_TEST
--- linux-ein-5.4.0.orig/drivers/extcon/Makefile
+++ linux-ein-5.4.0/drivers/extcon/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
 obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
 obj-$(CONFIG_EXTCON_PTN5150)	+= extcon-ptn5150.o
+obj-$(CONFIG_EXTCON_IT5201)	+= extcon-it5201.o
 obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o
 obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
 obj-$(CONFIG_EXTCON_SM5502)	+= extcon-sm5502.o
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-adc-jack.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-adc-jack.c
@@ -124,7 +124,7 @@
 	for (i = 0; data->adc_conditions[i].id != EXTCON_NONE; i++);
 	data->num_conditions = i;
 
-	data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel);
+	data->chan = devm_iio_channel_get(&pdev->dev, pdata->consumer_channel);
 	if (IS_ERR(data->chan))
 		return PTR_ERR(data->chan);
 
@@ -164,7 +164,6 @@
 
 	free_irq(data->irq, data);
 	cancel_work_sync(&data->handler.work);
-	iio_channel_release(data->chan);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-arizona.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-arizona.c
@@ -597,7 +597,7 @@
 	struct arizona *arizona = info->arizona;
 	int id_gpio = arizona->pdata.hpdet_id_gpio;
 	unsigned int report = EXTCON_JACK_HEADPHONE;
-	int ret, reading;
+	int ret, reading, state;
 	bool mic = false;
 
 	mutex_lock(&info->lock);
@@ -610,12 +610,11 @@
 	}
 
 	/* If the cable was removed while measuring ignore the result */
-	ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
-	if (ret < 0) {
-		dev_err(arizona->dev, "Failed to check cable state: %d\n",
-			ret);
+	state = extcon_get_state(info->edev, EXTCON_MECHANICAL);
+	if (state < 0) {
+		dev_err(arizona->dev, "Failed to check cable state: %d\n", state);
 		goto out;
-	} else if (!ret) {
+	} else if (!state) {
 		dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
 		goto done;
 	}
@@ -668,7 +667,7 @@
 			   ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
 
 	/* If we have a mic then reenable MICDET */
-	if (mic || info->mic)
+	if (state && (mic || info->mic))
 		arizona_start_mic(info);
 
 	if (info->hpdet_active) {
@@ -676,7 +675,9 @@
 		info->hpdet_active = false;
 	}
 
-	info->hpdet_done = true;
+	/* Do not set hp_det done when the cable has been unplugged */
+	if (state)
+		info->hpdet_done = true;
 
 out:
 	mutex_unlock(&info->lock);
@@ -1724,25 +1725,6 @@
 	bool change;
 	int ret;
 
-	ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-				       ARIZONA_MICD_ENA, 0,
-				       &change);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
-			ret);
-	} else if (change) {
-		regulator_disable(info->micvdd);
-		pm_runtime_put(info->dev);
-	}
-
-	gpiod_put(info->micd_pol_gpio);
-
-	pm_runtime_disable(&pdev->dev);
-
-	regmap_update_bits(arizona->regmap,
-			   ARIZONA_MICD_CLAMP_CONTROL,
-			   ARIZONA_MICD_CLAMP_MODE_MASK, 0);
-
 	if (info->micd_clamp) {
 		jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
 		jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
@@ -1758,10 +1740,31 @@
 	arizona_free_irq(arizona, jack_irq_rise, info);
 	arizona_free_irq(arizona, jack_irq_fall, info);
 	cancel_delayed_work_sync(&info->hpdet_work);
+	cancel_delayed_work_sync(&info->micd_detect_work);
+	cancel_delayed_work_sync(&info->micd_timeout_work);
+
+	ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+				       ARIZONA_MICD_ENA, 0,
+				       &change);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
+			ret);
+	} else if (change) {
+		regulator_disable(info->micvdd);
+		pm_runtime_put(info->dev);
+	}
+
+	regmap_update_bits(arizona->regmap,
+			   ARIZONA_MICD_CLAMP_CONTROL,
+			   ARIZONA_MICD_CLAMP_MODE_MASK, 0);
 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
 			   ARIZONA_JD1_ENA, 0);
 	arizona_clk32k_disable(arizona);
 
+	gpiod_put(info->micd_pol_gpio);
+
+	pm_runtime_disable(&pdev->dev);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-axp288.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-axp288.c
@@ -423,9 +423,40 @@
 	/* Start charger cable type detection */
 	axp288_extcon_enable(info);
 
+	device_init_wakeup(dev, true);
+	platform_set_drvdata(pdev, info);
+
+	return 0;
+}
+
+static int __maybe_unused axp288_extcon_suspend(struct device *dev)
+{
+	struct axp288_extcon_info *info = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(info->irq[VBUS_RISING_IRQ]);
+
 	return 0;
 }
 
+static int __maybe_unused axp288_extcon_resume(struct device *dev)
+{
+	struct axp288_extcon_info *info = dev_get_drvdata(dev);
+
+	/*
+	 * Wakeup when a charger is connected to do charger-type
+	 * connection and generate an extcon event which makes the
+	 * axp288 charger driver set the input current limit.
+	 */
+	if (device_may_wakeup(dev))
+		disable_irq_wake(info->irq[VBUS_RISING_IRQ]);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(axp288_extcon_pm_ops, axp288_extcon_suspend,
+			 axp288_extcon_resume);
+
 static const struct platform_device_id axp288_extcon_table[] = {
 	{ .name = "axp288_extcon" },
 	{},
@@ -437,6 +468,7 @@
 	.id_table = axp288_extcon_table,
 	.driver = {
 		.name = "axp288_extcon",
+		.pm = &axp288_extcon_pm_ops,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-intel-cht-wc.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-intel-cht-wc.c
@@ -338,6 +338,7 @@
 	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
 	struct cht_wc_extcon_data *ext;
 	unsigned long mask = ~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_USBID_MASK);
+	int pwrsrc_sts, id;
 	int irq, ret;
 
 	irq = platform_get_irq(pdev, 0);
@@ -387,8 +388,19 @@
 		goto disable_sw_control;
 	}
 
-	/* Route D+ and D- to PMIC for initial charger detection */
-	cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
+	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
+	if (ret) {
+		dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
+		goto disable_sw_control;
+	}
+
+	/*
+	 * If no USB host or device connected, route D+ and D- to PMIC for
+	 * initial charger detection
+	 */
+	id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
+	if (id != INTEL_USB_ID_GND)
+		cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
 
 	/* Get initial state */
 	cht_wc_extcon_pwrsrc_event(ext);
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-intel-mrfld.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-intel-mrfld.c
@@ -197,6 +197,7 @@
 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
 	struct regmap *regmap = pmic->regmap;
 	struct mrfld_extcon_data *data;
+	unsigned int status;
 	unsigned int id;
 	int irq, ret;
 
@@ -244,6 +245,14 @@
 	/* Get initial state */
 	mrfld_extcon_role_detect(data);
 
+	/*
+	 * Cached status value is used for cable detection, see comments
+	 * in mrfld_extcon_cable_detect(), we need to sync cached value
+	 * with a real state of the hardware.
+	 */
+	regmap_read(regmap, BCOVE_SCHGRIRQ1, &status);
+	data->status = status;
+
 	mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR);
 	mrfld_extcon_clear(data, BCOVE_MCHGRIRQ1, BCOVE_CHGRIRQ_ALL);
 
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-it5201.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-it5201.c
@@ -0,0 +1,290 @@
+/*
+ * extcon-it5201.c - ITE CC logic for USB Type-C applications
+ *
+ * Copyright 2017 NXP
+ * Author: Peter Chen <peter.chen@nxp.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  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/extcon-provider.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/usb/typec.h>
+
+
+/* IT5201_REG_GCR */
+#define VBUS_INTERRUPT (1 << 6)
+/* IT5201_REG_IOCPCR */
+#define TYPEC_INTERRUPT (1 << 7)
+/* IT5201_REG_CC_STATUS */
+#define IS_NOT_CONNECTED(val) (val == 0)
+#define IS_UFP_ATTATCHED(val) (val&0x1)
+#define IS_DFP_ATTATCHED(val) (val&0x2)
+
+struct it5201_info {
+	struct device *dev;
+	struct extcon_dev *edev;
+	struct work_struct wq_detect_cable;
+	struct regmap *regmap;
+	struct mutex mutex;
+};
+
+/* List of detectable cables */
+static const unsigned int it5201_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_NONE,
+};
+
+enum it5201_reg {
+	IT5201_REG_CID7R = 0x0,
+	IT5201_REG_CID6R = 0x1,
+	IT5201_REG_CID5R = 0x2,
+	IT5201_REG_CID4R = 0x3,
+	IT5201_REG_CID3R = 0x4,
+	IT5201_REG_CID2R = 0x5,
+	IT5201_REG_CID1R = 0x6,
+	IT5201_REG_CID0R = 0x7,
+	IT5201_REG_CVR = 0xf,
+	IT5201_REG_GCR = 0x10,
+	IT5201_REG_VCR = 0x13,
+	IT5201_REG_TCFSMCR0 = 0x14,
+	IT5201_REG_TCFSMCR1 = 0x15,
+	IT5201_REG_TCASR = 0x16,
+	IT5201_REG_CCSRCVR = 0x18,
+	IT5201_REG_CCSNKVR = 0x19,
+	IT5201_REG_IOCPCR = 0x1a,
+	IT5201_REG_SPSR = 0x1b,
+};
+
+static const struct regmap_config it5201_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = IT5201_REG_SPSR,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int it5201_clear_interrupt(struct it5201_info *info)
+{
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&info->mutex);
+
+	ret = regmap_write(info->regmap, IT5201_REG_IOCPCR, TYPEC_INTERRUPT);
+	if (ret) {
+		dev_err(info->dev, "failed to clear interrupt status:%d\n",
+			ret);
+	}
+
+	ret = regmap_read(info->regmap, IT5201_REG_IOCPCR, &val);
+	if (ret) {
+		dev_err(info->dev, "failed to get interrupt status:%d\n",
+			ret);
+	}
+	dev_info(info->dev, "ITE IT5201: clear IOCPCR status:0x%x\n", val);
+
+	mutex_unlock(&info->mutex);
+
+	return (ret < 0) ? ret : (int)val;
+}
+
+static irqreturn_t it5201_i2c_irq_handler(int irq, void *dev_id)
+{
+	struct it5201_info *info = dev_id;
+
+	queue_work(system_power_efficient_wq, &info->wq_detect_cable);
+
+	it5201_clear_interrupt(info);
+
+	return IRQ_HANDLED;
+}
+
+static void it5201_detect_cable(struct work_struct *work)
+{
+	struct it5201_info *info =
+		container_of(work, struct it5201_info, wq_detect_cable);
+	int ret;
+	unsigned int val;
+
+	mutex_lock(&info->mutex);
+	ret = regmap_read(info->regmap, IT5201_REG_TCASR, &val);
+	if (ret) {
+		dev_err(info->dev, "failed to get CC status:%d\n", ret);
+	}
+	dev_info(info->dev, "ITE IT5201: CC status in detect_cable:0x%x\n", val);
+
+	if (IS_UFP_ATTATCHED(val)) {
+		dev_info(info->dev, "ITE IT5201: UFP_ATTATCHED\n");
+		extcon_set_state_sync(info->edev, EXTCON_USB, false);
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
+	} else if (IS_DFP_ATTATCHED(val)) {
+		dev_info(info->dev, "ITE IT5201: DFP_ATTATCHED\n");
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
+		extcon_set_state_sync(info->edev, EXTCON_USB, true);
+	} else if (IS_NOT_CONNECTED(val)) {
+		dev_info(info->dev, "ITE IT5201: NOT_CONNECTED\n");
+		extcon_set_state_sync(info->edev, EXTCON_USB, false);
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
+	} else {
+		dev_dbg(info->dev, "other CC status is :0x%x\n", val);
+	}
+	mutex_unlock(&info->mutex);
+}
+
+static int it5201_setup_i2c_det(
+	struct it5201_info *info, struct i2c_client *i2c)
+{
+	int ret;
+	unsigned int val = 0;
+
+	/* Set VBUS detect */
+	ret = regmap_update_bits(info->regmap, IT5201_REG_GCR,
+		VBUS_INTERRUPT, VBUS_INTERRUPT);
+	if (ret) {
+		dev_err(info->dev, "failed to enable vbus interrupt:%d\n", ret);
+	}
+
+	ret = regmap_read(info->regmap, IT5201_REG_GCR, &val);
+	if (ret) {
+		dev_err(info->dev, "failed to get General Control Reg:%d\n", ret);
+		return ret;
+	}
+        dev_info(info->dev, "ITE IT5201: General Control Reg:0x%x\n", val);
+
+	/* Clear chip interrupt status */
+	ret = it5201_clear_interrupt(info);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to clear interrupt: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_request_threaded_irq(info->dev, i2c->irq, NULL,
+		it5201_i2c_irq_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+		dev_name(info->dev), info);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to register i2c interrupt: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int it5201_i2c_probe(
+	struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+
+	struct device_node *np = i2c->dev.of_node;
+	struct it5201_info *info;
+	int ret;
+	struct gpio_desc *connect_gpiod;
+
+	if (!np) {
+		return -EINVAL;
+	}
+
+	info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(i2c, info);
+	info->dev = &i2c->dev;
+
+	info->regmap = devm_regmap_init_i2c(i2c, &it5201_regmap_config);
+	if (IS_ERR(info->regmap)) {
+		ret = PTR_ERR(info->regmap);
+		dev_err(info->dev, "failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* Allocate extcon device */
+	info->edev = devm_extcon_dev_allocate(info->dev, it5201_extcon_cable);
+	if (IS_ERR(info->edev)) {
+		dev_err(info->dev, "failed to allocate memory for extcon\n");
+		return -ENOMEM;
+	}
+
+	/* Register extcon device */
+	ret = devm_extcon_dev_register(info->dev, info->edev);
+	if (ret) {
+		dev_err(info->dev, "failed to register extcon device\n");
+		return ret;
+	}
+
+	mutex_init(&info->mutex);
+	INIT_WORK(&info->wq_detect_cable, it5201_detect_cable);
+
+	/* Register interrupt */
+	if (i2c->irq) {
+		ret = it5201_setup_i2c_det(info, i2c);
+		if (ret) {
+			dev_err(info->dev,
+				"Failed to configure i2c interrupts: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	device_set_wakeup_capable(info->dev, true);
+
+	/* Do cable detect now */
+	it5201_detect_cable(&info->wq_detect_cable);
+
+	return ret;
+}
+
+static int it5201_i2c_remove(struct i2c_client *i2c)
+{
+	return 0;
+}
+
+static const struct i2c_device_id it5201_id[] = {
+	{ "it5201", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, it5201_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id it5201_of_match[] = {
+	{
+		.compatible = "ite,it5201",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, it5201_of_match);
+#endif
+
+static struct i2c_driver it5201_i2c_driver = {
+    .driver =
+        {
+            .name = "it5201",
+            .of_match_table = of_match_ptr(it5201_of_match),
+        },
+    .probe = it5201_i2c_probe,
+    .remove = it5201_i2c_remove,
+    .id_table = it5201_id,
+};
+module_i2c_driver(it5201_i2c_driver);
+
+MODULE_DESCRIPTION("ITE IT5201 CC logic driver for USB Type-C");
+MODULE_AUTHOR("TzuWen Chang <TzuWen_Chang@asus.com>");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-max77693.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-max77693.c
@@ -1277,4 +1277,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-ein-5.4.0.orig/drivers/extcon/extcon-max8997.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-max8997.c
@@ -729,7 +729,7 @@
 				2, info->status);
 	if (ret) {
 		dev_err(info->dev, "failed to read MUIC register\n");
-		return ret;
+		goto err_irq;
 	}
 	cable_type = max8997_muic_get_cable_type(info,
 					   MAX8997_CABLE_GROUP_ADC, &attached);
@@ -784,3 +784,4 @@
 MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8997-muic");
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-ptn5150.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-ptn5150.c
@@ -5,6 +5,7 @@
 // Based on extcon-sm5502.c driver
 // Copyright (c) 2018-2019 by Vijai Kumar K
 // Author: Vijai Kumar K <vijaikumar.kanagarajan@gmail.com>
+// Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
 
 #include <linux/err.h>
 #include <linux/i2c.h>
@@ -17,18 +18,16 @@
 #include <linux/gpio/consumer.h>
 
 /* PTN5150 registers */
-enum ptn5150_reg {
-	PTN5150_REG_DEVICE_ID = 0x01,
-	PTN5150_REG_CONTROL,
-	PTN5150_REG_INT_STATUS,
-	PTN5150_REG_CC_STATUS,
-	PTN5150_REG_CON_DET = 0x09,
-	PTN5150_REG_VCONN_STATUS,
-	PTN5150_REG_RESET,
-	PTN5150_REG_INT_MASK = 0x18,
-	PTN5150_REG_INT_REG_STATUS,
-	PTN5150_REG_END,
-};
+#define PTN5150_REG_DEVICE_ID			0x01
+#define PTN5150_REG_CONTROL			0x02
+#define PTN5150_REG_INT_STATUS			0x03
+#define PTN5150_REG_CC_STATUS			0x04
+#define PTN5150_REG_CON_DET			0x09
+#define PTN5150_REG_VCONN_STATUS		0x0a
+#define PTN5150_REG_RESET			0x0b
+#define PTN5150_REG_INT_MASK			0x18
+#define PTN5150_REG_INT_REG_STATUS		0x19
+#define PTN5150_REG_END				PTN5150_REG_INT_REG_STATUS
 
 #define PTN5150_DFP_ATTACHED			0x1
 #define PTN5150_UFP_ATTACHED			0x2
@@ -58,6 +57,8 @@
 #define PTN5150_REG_INT_CABLE_DETACH_MASK	\
 	(0x1 << PTN5150_REG_CC_CABLE_DETACH_SHIFT)
 
+#define CABLE_ATTACH_TIMEOUT 1000
+
 struct ptn5150_info {
 	struct device *dev;
 	struct extcon_dev *edev;
@@ -66,6 +67,7 @@
 	struct gpio_desc *int_gpiod;
 	struct gpio_desc *vbus_gpiod;
 	int irq;
+	struct timer_list timer;
 	struct work_struct irq_work;
 	struct mutex mutex;
 };
@@ -83,12 +85,49 @@
 	.max_register	= PTN5150_REG_END,
 };
 
+static void ptn5150_check_state(struct ptn5150_info *info)
+{
+	unsigned int port_status, reg_data, vbus;
+	int ret;
+
+	ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, &reg_data);
+	if (ret) {
+		dev_err(info->dev, "failed to read CC STATUS %d\n", ret);
+		return;
+	}
+
+	port_status = ((reg_data &
+			PTN5150_REG_CC_PORT_ATTACHMENT_MASK) >>
+			PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT);
+
+	switch (port_status) {
+	case PTN5150_DFP_ATTACHED:
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
+		gpiod_set_value_cansleep(info->vbus_gpiod, 0);
+		extcon_set_state_sync(info->edev, EXTCON_USB, true);
+		break;
+	case PTN5150_UFP_ATTACHED:
+		extcon_set_state_sync(info->edev, EXTCON_USB, false);
+		vbus = ((reg_data & PTN5150_REG_CC_VBUS_DETECTION_MASK) >>
+			PTN5150_REG_CC_VBUS_DETECTION_SHIFT);
+		if (vbus)
+			gpiod_set_value_cansleep(info->vbus_gpiod, 0);
+		else
+			gpiod_set_value_cansleep(info->vbus_gpiod, 1);
+
+		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
+		break;
+	default:
+		dev_err(info->dev, "Unknown Port status : %x\n", port_status);
+		break;
+	}
+}
+
 static void ptn5150_irq_work(struct work_struct *work)
 {
 	struct ptn5150_info *info = container_of(work,
 			struct ptn5150_info, irq_work);
 	int ret = 0;
-	unsigned int reg_data;
 	unsigned int int_status;
 
 	if (!info->edev)
@@ -96,13 +135,6 @@
 
 	mutex_lock(&info->mutex);
 
-	ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, &reg_data);
-	if (ret) {
-		dev_err(info->dev, "failed to read CC STATUS %d\n", ret);
-		mutex_unlock(&info->mutex);
-		return;
-	}
-
 	/* Clear interrupt. Read would clear the register */
 	ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, &int_status);
 	if (ret) {
@@ -116,47 +148,13 @@
 
 		cable_attach = int_status & PTN5150_REG_INT_CABLE_ATTACH_MASK;
 		if (cable_attach) {
-			unsigned int port_status;
-			unsigned int vbus;
-
-			port_status = ((reg_data &
-					PTN5150_REG_CC_PORT_ATTACHMENT_MASK) >>
-					PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT);
-
-			switch (port_status) {
-			case PTN5150_DFP_ATTACHED:
-				extcon_set_state_sync(info->edev,
-						EXTCON_USB_HOST, false);
-				gpiod_set_value(info->vbus_gpiod, 0);
-				extcon_set_state_sync(info->edev, EXTCON_USB,
-						true);
-				break;
-			case PTN5150_UFP_ATTACHED:
-				extcon_set_state_sync(info->edev, EXTCON_USB,
-						false);
-				vbus = ((reg_data &
-					PTN5150_REG_CC_VBUS_DETECTION_MASK) >>
-					PTN5150_REG_CC_VBUS_DETECTION_SHIFT);
-				if (vbus)
-					gpiod_set_value(info->vbus_gpiod, 0);
-				else
-					gpiod_set_value(info->vbus_gpiod, 1);
-
-				extcon_set_state_sync(info->edev,
-						EXTCON_USB_HOST, true);
-				break;
-			default:
-				dev_err(info->dev,
-					"Unknown Port status : %x\n",
-					port_status);
-				break;
-			}
+			ptn5150_check_state(info);
 		} else {
 			extcon_set_state_sync(info->edev,
 					EXTCON_USB_HOST, false);
 			extcon_set_state_sync(info->edev,
 					EXTCON_USB, false);
-			gpiod_set_value(info->vbus_gpiod, 0);
+			gpiod_set_value_cansleep(info->vbus_gpiod, 0);
 		}
 	}
 
@@ -183,6 +181,17 @@
 	return IRQ_HANDLED;
 }
 
+static void ptn5150_conn_poll(struct timer_list *t)
+{
+	struct ptn5150_info *info = from_timer(info, t , timer);
+	unsigned long flags;
+
+	schedule_work(&info->irq_work);
+
+	mod_timer(&info->timer,
+		jiffies + msecs_to_jiffies(CABLE_ATTACH_TIMEOUT));
+}
+
 static int ptn5150_init_dev_type(struct ptn5150_info *info)
 {
 	unsigned int reg_data, vendor_id, version_id;
@@ -199,8 +208,8 @@
 	version_id = ((reg_data & PTN5150_REG_DEVICE_ID_VERSION_MASK) >>
 				PTN5150_REG_DEVICE_ID_VERSION_SHIFT);
 
-	dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
-			    version_id, vendor_id);
+	dev_dbg(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
+		version_id, vendor_id);
 
 	/* Clear any existing interrupts */
 	ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, &reg_data);
@@ -239,25 +248,22 @@
 
 	info->dev = &i2c->dev;
 	info->i2c = i2c;
-	info->int_gpiod = devm_gpiod_get(&i2c->dev, "int", GPIOD_IN);
-	if (IS_ERR(info->int_gpiod)) {
-		dev_err(dev, "failed to get INT GPIO\n");
-		return PTR_ERR(info->int_gpiod);
-	}
-	info->vbus_gpiod = devm_gpiod_get(&i2c->dev, "vbus", GPIOD_IN);
+	info->vbus_gpiod = devm_gpiod_get(&i2c->dev, "vbus", GPIOD_OUT_LOW);
 	if (IS_ERR(info->vbus_gpiod)) {
-		dev_err(dev, "failed to get VBUS GPIO\n");
-		return PTR_ERR(info->vbus_gpiod);
-	}
-	ret = gpiod_direction_output(info->vbus_gpiod, 0);
-	if (ret) {
-		dev_err(dev, "failed to set VBUS GPIO direction\n");
-		return -EINVAL;
+		ret = PTR_ERR(info->vbus_gpiod);
+		if (ret == -ENOENT) {
+			dev_info(dev, "No VBUS GPIO, ignoring VBUS control\n");
+			info->vbus_gpiod = NULL;
+		} else {
+			dev_err(dev, "failed to get VBUS GPIO\n");
+			return ret;
+		}
 	}
 
 	mutex_init(&info->mutex);
 
 	INIT_WORK(&info->irq_work, ptn5150_irq_work);
+	timer_setup(&info->timer, ptn5150_conn_poll, 0);
 
 	info->regmap = devm_regmap_init_i2c(i2c, &ptn5150_regmap_config);
 	if (IS_ERR(info->regmap)) {
@@ -267,13 +273,25 @@
 		return ret;
 	}
 
-	if (info->int_gpiod) {
-		info->irq = gpiod_to_irq(info->int_gpiod);
-		if (info->irq < 0) {
-			dev_err(dev, "failed to get INTB IRQ\n");
-			return info->irq;
+	if (i2c->irq > 0) {
+		info->irq = i2c->irq;
+	} else {
+		info->int_gpiod = devm_gpiod_get_optional(&i2c->dev, "int", GPIOD_IN);
+		if (IS_ERR(info->int_gpiod)) {
+			dev_err(dev, "failed to get INT GPIO\n");
+			return PTR_ERR(info->int_gpiod);
+		}
+
+		if (info->int_gpiod > 0) {
+			info->irq = gpiod_to_irq(info->int_gpiod);
+			if (info->irq < 0) {
+				dev_err(dev, "failed to get INTB IRQ\n");
+				return info->irq;
+			}
 		}
+	}
 
+	if (info->irq > 0) {
 		ret = devm_request_threaded_irq(dev, info->irq, NULL,
 						ptn5150_irq_handler,
 						IRQF_TRIGGER_FALLING |
@@ -283,28 +301,54 @@
 			dev_err(dev, "failed to request handler for INTB IRQ\n");
 			return ret;
 		}
+	} else {
+		dev_warn(dev, "No IRQ configured, switch to polling\n");
+		mod_timer(&info->timer,
+			jiffies + jiffies_to_msecs(CABLE_ATTACH_TIMEOUT));
 	}
 
 	/* Allocate extcon device */
 	info->edev = devm_extcon_dev_allocate(info->dev, ptn5150_extcon_cable);
 	if (IS_ERR(info->edev)) {
 		dev_err(info->dev, "failed to allocate memory for extcon\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_fail;
 	}
 
 	/* Register extcon device */
 	ret = devm_extcon_dev_register(info->dev, info->edev);
 	if (ret) {
 		dev_err(info->dev, "failed to register extcon device\n");
-		return ret;
+		goto err_fail;
 	}
 
+	extcon_set_property_capability(info->edev, EXTCON_USB,
+					EXTCON_PROP_USB_VBUS);
+	extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
+					EXTCON_PROP_USB_VBUS);
+	extcon_set_property_capability(info->edev, EXTCON_USB_HOST,
+					EXTCON_PROP_USB_TYPEC_POLARITY);
+
 	/* Initialize PTN5150 device and print vendor id and version id */
 	ret = ptn5150_init_dev_type(info);
-	if (ret)
-		return -EINVAL;
+	if (ret) {
+		ret = -EINVAL;
+		goto err_fail;
+	}
+
+	/*
+	 * Update current extcon state if for example OTG connection was there
+	 * before the probe
+	 */
+	mutex_lock(&info->mutex);
+	ptn5150_check_state(info);
+	mutex_unlock(&info->mutex);
 
 	return 0;
+
+err_fail:
+	del_timer_sync(&info->timer);
+	return ret;
 }
 
 static const struct of_device_id ptn5150_dt_match[] = {
@@ -327,13 +371,9 @@
 	.probe	= ptn5150_i2c_probe,
 	.id_table = ptn5150_i2c_id,
 };
-
-static int __init ptn5150_i2c_init(void)
-{
-	return i2c_add_driver(&ptn5150_i2c_driver);
-}
-subsys_initcall(ptn5150_i2c_init);
+module_i2c_driver(ptn5150_i2c_driver);
 
 MODULE_DESCRIPTION("NXP PTN5150 CC logic Extcon driver");
 MODULE_AUTHOR("Vijai Kumar K <vijaikumar.kanagarajan@gmail.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
 MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-sm5502.c
+++ linux-ein-5.4.0/drivers/extcon/extcon-sm5502.c
@@ -65,6 +65,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,
@@ -84,7 +88,6 @@
 			| SM5502_REG_INTM2_MHL_MASK,
 		.invert = true,
 	},
-	{ }
 };
 
 /* List of detectable cables */
--- linux-ein-5.4.0.orig/drivers/extcon/extcon-sm5502.h
+++ linux-ein-5.4.0/drivers/extcon/extcon-sm5502.h
@@ -237,6 +237,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-ein-5.4.0.orig/drivers/extcon/extcon.c
+++ linux-ein-5.4.0/drivers/extcon/extcon.c
@@ -196,6 +196,14 @@
  * @attr_name:		"name" sysfs entry
  * @attr_state:		"state" sysfs entry
  * @attrs:		the array pointing to attr_name and attr_state for attr_g
+ * @usb_propval:	the array of USB connector properties
+ * @chg_propval:	the array of charger connector properties
+ * @jack_propval:	the array of jack connector properties
+ * @disp_propval:	the array of display connector properties
+ * @usb_bits:		the bit array of the USB connector property capabilities
+ * @chg_bits:		the bit array of the charger connector property capabilities
+ * @jack_bits:		the bit array of the jack connector property capabilities
+ * @disp_bits:		the bit array of the display connector property capabilities
  */
 struct extcon_cable {
 	struct extcon_dev *edev;
@@ -1230,18 +1238,14 @@
 		edev->dev.type = &edev->extcon_dev_type;
 	}
 
-	ret = device_register(&edev->dev);
-	if (ret) {
-		put_device(&edev->dev);
-		goto err_dev;
-	}
-
 	spin_lock_init(&edev->lock);
-	edev->nh = devm_kcalloc(&edev->dev, edev->max_supported,
-				sizeof(*edev->nh), GFP_KERNEL);
-	if (!edev->nh) {
-		ret = -ENOMEM;
-		goto err_dev;
+	if (edev->max_supported) {
+		edev->nh = kcalloc(edev->max_supported, sizeof(*edev->nh),
+				GFP_KERNEL);
+		if (!edev->nh) {
+			ret = -ENOMEM;
+			goto err_alloc_nh;
+		}
 	}
 
 	for (index = 0; index < edev->max_supported; index++)
@@ -1252,6 +1256,12 @@
 	dev_set_drvdata(&edev->dev, edev);
 	edev->state = 0;
 
+	ret = device_register(&edev->dev);
+	if (ret) {
+		put_device(&edev->dev);
+		goto err_dev;
+	}
+
 	mutex_lock(&extcon_dev_list_lock);
 	list_add(&edev->entry, &extcon_dev_list);
 	mutex_unlock(&extcon_dev_list_lock);
@@ -1260,6 +1270,9 @@
 
 err_dev:
 	if (edev->max_supported)
+		kfree(edev->nh);
+err_alloc_nh:
+	if (edev->max_supported)
 		kfree(edev->extcon_dev_type.groups);
 err_alloc_groups:
 	if (edev->max_supported && edev->mutually_exclusive) {
@@ -1319,6 +1332,7 @@
 	if (edev->max_supported) {
 		kfree(edev->extcon_dev_type.groups);
 		kfree(edev->cables);
+		kfree(edev->nh);
 	}
 
 	put_device(&edev->dev);
--- linux-ein-5.4.0.orig/drivers/firewire/core-card.c
+++ linux-ein-5.4.0/drivers/firewire/core-card.c
@@ -429,7 +429,23 @@
 	 */
 	card->bm_generation = generation;
 
-	if (root_device == NULL) {
+	if (card->gap_count == 0) {
+		/*
+		 * If self IDs have inconsistent gap counts, do a
+		 * bus reset ASAP. The config rom read might never
+		 * complete, so don't wait for it. However, still
+		 * send a PHY configuration packet prior to the
+		 * bus reset. The PHY configuration packet might
+		 * fail, but 1394-2008 8.4.5.2 explicitly permits
+		 * it in this case, so it should be safe to try.
+		 */
+		new_root_id = local_id;
+		/*
+		 * We must always send a bus reset if the gap count
+		 * is inconsistent, so bypass the 5-reset limit.
+		 */
+		card->bm_retries = 0;
+	} else if (root_device == NULL) {
 		/*
 		 * Either link_on is false, or we failed to read the
 		 * config rom.  In either case, pick another root.
@@ -668,6 +684,7 @@
 void fw_core_remove_card(struct fw_card *card)
 {
 	struct fw_card_driver dummy_driver = dummy_driver_template;
+	unsigned long flags;
 
 	card->driver->update_phy_reg(card, 4,
 				     PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
@@ -682,7 +699,9 @@
 	dummy_driver.stop_iso		= card->driver->stop_iso;
 	card->driver = &dummy_driver;
 
+	spin_lock_irqsave(&card->lock, flags);
 	fw_destroy_nodes(card);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	/* Wait for all users, especially device workqueue jobs, to finish. */
 	fw_card_put(card);
--- linux-ein-5.4.0.orig/drivers/firewire/core-cdev.c
+++ linux-ein-5.4.0/drivers/firewire/core-cdev.c
@@ -818,8 +818,10 @@
 
 	r = container_of(resource, struct inbound_transaction_resource,
 			 resource);
-	if (is_fcp_request(r->request))
+	if (is_fcp_request(r->request)) {
+		kfree(r->data);
 		goto out;
+	}
 
 	if (a->length != fw_get_response_length(r->request)) {
 		ret = -EINVAL;
@@ -1482,6 +1484,7 @@
 {
 	struct outbound_phy_packet_event *e =
 		container_of(packet, struct outbound_phy_packet_event, p);
+	struct client *e_client;
 
 	switch (status) {
 	/* expected: */
@@ -1498,9 +1501,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-ein-5.4.0.orig/drivers/firewire/core-device.c
+++ linux-ein-5.4.0/drivers/firewire/core-device.c
@@ -100,10 +100,9 @@
  * @buf:	where to put the string
  * @size:	size of @buf, in bytes
  *
- * The string is taken from a minimal ASCII text descriptor leaf after
- * the immediate entry with @key.  The string is zero-terminated.
- * An overlong string is silently truncated such that it and the
- * zero byte fit into @size.
+ * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the
+ * @key. The string is zero-terminated. An overlong string is silently truncated such that it
+ * and the zero byte fit into @size.
  *
  * Returns strlen(buf) or a negative error code.
  */
@@ -719,14 +718,11 @@
 					fw_unit_attributes,
 					&unit->attribute_group);
 
-		if (device_register(&unit->device) < 0)
-			goto skip_unit;
-
 		fw_device_get(device);
-		continue;
-
-	skip_unit:
-		kfree(unit);
+		if (device_register(&unit->device) < 0) {
+			put_device(&unit->device);
+			continue;
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/firewire/core-topology.c
+++ linux-ein-5.4.0/drivers/firewire/core-topology.c
@@ -374,16 +374,13 @@
 	card->bm_retries = 0;
 }
 
+/* Must be called with card->lock held */
 void fw_destroy_nodes(struct fw_card *card)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&card->lock, flags);
 	card->color++;
 	if (card->local_node != NULL)
 		for_each_fw_node(card, card->local_node, report_lost_node);
 	card->local_node = NULL;
-	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
@@ -509,6 +506,8 @@
 	struct fw_node *local_node;
 	unsigned long flags;
 
+	spin_lock_irqsave(&card->lock, flags);
+
 	/*
 	 * If the selfID buffer is not the immediate successor of the
 	 * previously processed one, we cannot reliably compare the
@@ -520,8 +519,6 @@
 		card->bm_retries = 0;
 	}
 
-	spin_lock_irqsave(&card->lock, flags);
-
 	card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
 	card->node_id = node_id;
 	/*
--- linux-ein-5.4.0.orig/drivers/firewire/core-transaction.c
+++ linux-ein-5.4.0/drivers/firewire/core-transaction.c
@@ -73,24 +73,25 @@
 static int close_transaction(struct fw_transaction *transaction,
 			     struct fw_card *card, int rcode)
 {
-	struct fw_transaction *t;
+	struct fw_transaction *t = NULL, *iter;
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->lock, flags);
-	list_for_each_entry(t, &card->transaction_list, link) {
-		if (t == transaction) {
-			if (!try_cancel_split_timeout(t)) {
+	list_for_each_entry(iter, &card->transaction_list, link) {
+		if (iter == transaction) {
+			if (!try_cancel_split_timeout(iter)) {
 				spin_unlock_irqrestore(&card->lock, flags);
 				goto timed_out;
 			}
-			list_del_init(&t->link);
-			card->tlabel_mask &= ~(1ULL << t->tlabel);
+			list_del_init(&iter->link);
+			card->tlabel_mask &= ~(1ULL << iter->tlabel);
+			t = iter;
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	if (&t->link != &card->transaction_list) {
+	if (t) {
 		t->callback(card, rcode, NULL, 0, t->callback_data);
 		return 0;
 	}
@@ -935,7 +936,7 @@
 
 void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
 {
-	struct fw_transaction *t;
+	struct fw_transaction *t = NULL, *iter;
 	unsigned long flags;
 	u32 *data;
 	size_t data_length;
@@ -947,20 +948,21 @@
 	rcode	= HEADER_GET_RCODE(p->header[1]);
 
 	spin_lock_irqsave(&card->lock, flags);
-	list_for_each_entry(t, &card->transaction_list, link) {
-		if (t->node_id == source && t->tlabel == tlabel) {
-			if (!try_cancel_split_timeout(t)) {
+	list_for_each_entry(iter, &card->transaction_list, link) {
+		if (iter->node_id == source && iter->tlabel == tlabel) {
+			if (!try_cancel_split_timeout(iter)) {
 				spin_unlock_irqrestore(&card->lock, flags);
 				goto timed_out;
 			}
-			list_del_init(&t->link);
-			card->tlabel_mask &= ~(1ULL << t->tlabel);
+			list_del_init(&iter->link);
+			card->tlabel_mask &= ~(1ULL << iter->tlabel);
+			t = iter;
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	if (&t->link == &card->transaction_list) {
+	if (!t) {
  timed_out:
 		fw_notice(card, "unsolicited response (source %x, tlabel %x)\n",
 			  source, tlabel);
--- linux-ein-5.4.0.orig/drivers/firewire/net.c
+++ linux-ein-5.4.0/drivers/firewire/net.c
@@ -250,7 +250,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;
 }
--- linux-ein-5.4.0.orig/drivers/firewire/nosy.c
+++ linux-ein-5.4.0/drivers/firewire/nosy.c
@@ -346,6 +346,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:
@@ -360,11 +361,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-ein-5.4.0.orig/drivers/firewire/ohci.c
+++ linux-ein-5.4.0/drivers/firewire/ohci.c
@@ -279,6 +279,51 @@
 #define QUIRK_TI_SLLZ059		0x20
 #define QUIRK_IR_WAKE			0x40
 
+// On PCI Express Root Complex in any type of AMD Ryzen machine, VIA VT6306/6307/6308 with Asmedia
+// ASM1083/1085 brings an inconvenience that the read accesses to 'Isochronous Cycle Timer' register
+// (at offset 0xf0 in PCI I/O space) often causes unexpected system reboot. The mechanism is not
+// clear, since the read access to the other registers is enough safe; e.g. 'Node ID' register,
+// while it is probable due to detection of any type of PCIe error.
+#define QUIRK_REBOOT_BY_CYCLE_TIMER_READ	0x80000000
+
+#if IS_ENABLED(CONFIG_X86)
+
+static bool has_reboot_by_cycle_timer_read_quirk(const struct fw_ohci *ohci)
+{
+	return !!(ohci->quirks & QUIRK_REBOOT_BY_CYCLE_TIMER_READ);
+}
+
+#define PCI_DEVICE_ID_ASMEDIA_ASM108X	0x1080
+
+static bool detect_vt630x_with_asm1083_on_amd_ryzen_machine(const struct pci_dev *pdev)
+{
+	const struct pci_dev *pcie_to_pci_bridge;
+
+	// Detect any type of AMD Ryzen machine.
+	if (!static_cpu_has(X86_FEATURE_ZEN))
+		return false;
+
+	// Detect VIA VT6306/6307/6308.
+	if (pdev->vendor != PCI_VENDOR_ID_VIA)
+		return false;
+	if (pdev->device != PCI_DEVICE_ID_VIA_VT630X)
+		return false;
+
+	// Detect Asmedia ASM1083/1085.
+	pcie_to_pci_bridge = pdev->bus->self;
+	if (pcie_to_pci_bridge->vendor != PCI_VENDOR_ID_ASMEDIA)
+		return false;
+	if (pcie_to_pci_bridge->device != PCI_DEVICE_ID_ASMEDIA_ASM108X)
+		return false;
+
+	return true;
+}
+
+#else
+#define has_reboot_by_cycle_timer_read_quirk(ohci) false
+#define detect_vt630x_with_asm1083_on_amd_ryzen_machine(pdev)	false
+#endif
+
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
 	unsigned short vendor, device, revision, flags;
@@ -1099,7 +1144,7 @@
 static int context_add_buffer(struct context *ctx)
 {
 	struct descriptor_buffer *desc;
-	dma_addr_t uninitialized_var(bus_addr);
+	dma_addr_t bus_addr;
 	int offset;
 
 	/*
@@ -1289,7 +1334,7 @@
 				   struct fw_packet *packet)
 {
 	struct fw_ohci *ohci = ctx->ohci;
-	dma_addr_t d_bus, uninitialized_var(payload_bus);
+	dma_addr_t d_bus, payload_bus;
 	struct driver_data *driver_data;
 	struct descriptor *d, *last;
 	__le32 *header;
@@ -1717,6 +1762,9 @@
 	s32 diff01, diff12;
 	int i;
 
+	if (has_reboot_by_cycle_timer_read_quirk(ohci))
+		return 0;
+
 	c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 
 	if (ohci->quirks & QUIRK_CYCLE_TIMER) {
@@ -2445,7 +2493,7 @@
 {
 	struct fw_ohci *ohci;
 	__be32 *next_config_rom;
-	dma_addr_t uninitialized_var(next_config_rom_bus);
+	dma_addr_t next_config_rom_bus;
 
 	ohci = fw_ohci(card);
 
@@ -2933,10 +2981,10 @@
 				int type, int channel, size_t header_size)
 {
 	struct fw_ohci *ohci = fw_ohci(card);
-	struct iso_context *uninitialized_var(ctx);
-	descriptor_callback_t uninitialized_var(callback);
-	u64 *uninitialized_var(channels);
-	u32 *uninitialized_var(mask), uninitialized_var(regs);
+	struct iso_context *ctx;
+	descriptor_callback_t callback;
+	u64 *channels;
+	u32 *mask, regs;
 	int index, ret = -EBUSY;
 
 	spin_lock_irq(&ohci->lock);
@@ -3619,6 +3667,9 @@
 	if (param_quirks)
 		ohci->quirks = param_quirks;
 
+	if (detect_vt630x_with_asm1083_on_amd_ryzen_machine(dev))
+		ohci->quirks |= QUIRK_REBOOT_BY_CYCLE_TIMER_READ;
+
 	/*
 	 * Because dma_alloc_coherent() allocates at least one page,
 	 * we save space by using a common buffer for the AR request/
--- linux-ein-5.4.0.orig/drivers/firewire/sbp2.c
+++ linux-ein-5.4.0/drivers/firewire/sbp2.c
@@ -408,7 +408,7 @@
 			      void *payload, size_t length, void *callback_data)
 {
 	struct sbp2_logical_unit *lu = callback_data;
-	struct sbp2_orb *orb;
+	struct sbp2_orb *orb = NULL, *iter;
 	struct sbp2_status status;
 	unsigned long flags;
 
@@ -433,17 +433,18 @@
 
 	/* Lookup the orb corresponding to this status write. */
 	spin_lock_irqsave(&lu->tgt->lock, flags);
-	list_for_each_entry(orb, &lu->orb_list, link) {
+	list_for_each_entry(iter, &lu->orb_list, link) {
 		if (STATUS_GET_ORB_HIGH(status) == 0 &&
-		    STATUS_GET_ORB_LOW(status) == orb->request_bus) {
-			orb->rcode = RCODE_COMPLETE;
-			list_del(&orb->link);
+		    STATUS_GET_ORB_LOW(status) == iter->request_bus) {
+			iter->rcode = RCODE_COMPLETE;
+			list_del(&iter->link);
+			orb = iter;
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&lu->tgt->lock, flags);
 
-	if (&orb->link != &lu->orb_list) {
+	if (orb) {
 		orb->callback(orb, &status);
 		kref_put(&orb->kref, free_orb); /* orb callback reference */
 	} else {
--- linux-ein-5.4.0.orig/drivers/firmware/Kconfig
+++ linux-ein-5.4.0/drivers/firmware/Kconfig
@@ -237,6 +237,7 @@
 config QCOM_SCM
 	bool
 	depends on ARM || ARM64
+	depends on HAVE_ARM_SMCCC
 	select RESET_CONTROLLER
 
 config QCOM_SCM_32
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/base.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/base.c
@@ -164,7 +164,7 @@
 			break;
 
 		loop_num_ret = le32_to_cpu(*num_ret);
-		if (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) {
+		if (loop_num_ret > MAX_PROTOCOLS_IMP - tot_num_ret) {
 			dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP");
 			break;
 		}
@@ -173,6 +173,8 @@
 			protocols_imp[tot_num_ret + loop] = *(list + loop);
 
 		tot_num_ret += loop_num_ret;
+
+		scmi_reset_rx_to_maxsz(handle, t);
 	} while (loop_num_ret);
 
 	scmi_xfer_put(handle, t);
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/bus.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/bus.c
@@ -100,6 +100,9 @@
 {
 	int retval;
 
+	if (!driver->probe)
+		return -EINVAL;
+
 	driver->driver.bus = &scmi_bus_type;
 	driver->driver.name = driver->name;
 	driver->driver.owner = owner;
@@ -135,8 +138,10 @@
 		return NULL;
 
 	id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
-	if (id < 0)
-		goto free_mem;
+	if (id < 0) {
+		kfree(scmi_dev);
+		return NULL;
+	}
 
 	scmi_dev->id = id;
 	scmi_dev->protocol_id = protocol;
@@ -154,8 +159,6 @@
 put_dev:
 	put_device(&scmi_dev->dev);
 	ida_simple_remove(&scmi_bus_id, id);
-free_mem:
-	kfree(scmi_dev);
 	return NULL;
 }
 
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/clock.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/clock.c
@@ -177,6 +177,8 @@
 		}
 
 		tot_rate_cnt += num_returned;
+
+		scmi_reset_rx_to_maxsz(handle, t);
 		/*
 		 * check for both returned and remaining to avoid infinite
 		 * loop due to buggy firmware
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/common.h
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/common.h
@@ -103,6 +103,8 @@
 			       struct scmi_xfer *xfer);
 int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
 		       size_t tx_size, size_t rx_size, struct scmi_xfer **p);
+void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle,
+			    struct scmi_xfer *xfer);
 int scmi_handle_put(const struct scmi_handle *handle);
 struct scmi_handle *scmi_handle_get(struct device *dev);
 void scmi_set_handle(struct scmi_device *scmi_dev);
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/driver.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/driver.c
@@ -54,7 +54,6 @@
 	SCMI_ERR_GENERIC = -8,	/* Generic Error */
 	SCMI_ERR_HARDWARE = -9,	/* Hardware Error */
 	SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
-	SCMI_ERR_MAX
 };
 
 /* List of all SCMI devices active in system */
@@ -176,8 +175,10 @@
 
 static inline int scmi_to_linux_errno(int errno)
 {
-	if (errno < SCMI_SUCCESS && errno > SCMI_ERR_MAX)
-		return scmi_linux_errmap[-errno];
+	int err_idx = -errno;
+
+	if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap))
+		return scmi_linux_errmap[err_idx];
 	return -EIO;
 }
 
@@ -370,6 +371,10 @@
 
 	xfer = &minfo->xfer_block[xfer_id];
 
+	/* rx.len could be shrunk in the sync do_xfer, so reset to maxsz */
+	if (msg_type == MSG_TYPE_DELAYED_RESP)
+		xfer->rx.len = info->desc->max_msg_size;
+
 	scmi_dump_header_dbg(dev, &xfer->hdr);
 
 	scmi_fetch_response(xfer, mem);
@@ -481,6 +486,14 @@
 	return ret;
 }
 
+void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle,
+			    struct scmi_xfer *xfer)
+{
+	struct scmi_info *info = handle_to_scmi_info(handle);
+
+	xfer->rx.len = info->desc->max_msg_size;
+}
+
 #define SCMI_MAX_RESPONSE_TIMEOUT	(2 * MSEC_PER_SEC)
 
 /**
@@ -502,8 +515,12 @@
 	xfer->async_done = &async_response;
 
 	ret = scmi_do_xfer(handle, xfer);
-	if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout))
-		ret = -ETIMEDOUT;
+	if (!ret) {
+		if (!wait_for_completion_timeout(xfer->async_done, timeout))
+			ret = -ETIMEDOUT;
+		else if (xfer->hdr.status)
+			ret = scmi_to_linux_errno(xfer->hdr.status);
+	}
 
 	xfer->async_done = NULL;
 	return ret;
@@ -681,8 +698,9 @@
 	struct scmi_xfers_info *info = &sinfo->tx_minfo;
 
 	/* Pre-allocated messages, no more than what hdr.seq can support */
-	if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {
-		dev_err(dev, "Maximum message of %d exceeds supported %ld\n",
+	if (WARN_ON(!desc->max_msg || desc->max_msg > MSG_TOKEN_MAX)) {
+		dev_err(dev,
+			"Invalid maximum messages %d, not in range [1 - %lu]\n",
 			desc->max_msg, MSG_TOKEN_MAX);
 		return -EINVAL;
 	}
@@ -719,6 +737,39 @@
 					  idx, NULL);
 }
 
+static int scmi_mailbox_chan_validate(struct device *cdev)
+{
+	int num_mb, num_sh, ret = 0;
+	struct device_node *np = cdev->of_node;
+
+	num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
+	num_sh = of_count_phandle_with_args(np, "shmem", NULL);
+	/* Bail out if mboxes and shmem descriptors are inconsistent */
+	if (num_mb <= 0 || num_sh > 2 || num_mb != num_sh) {
+		dev_warn(cdev, "Invalid channel descriptor for '%s'\n",
+			 of_node_full_name(np));
+		return -EINVAL;
+	}
+
+	if (num_sh > 1) {
+		struct device_node *np_tx, *np_rx;
+
+		np_tx = of_parse_phandle(np, "shmem", 0);
+		np_rx = of_parse_phandle(np, "shmem", 1);
+		/* SCMI Tx and Rx shared mem areas have to be distinct */
+		if (!np_tx || !np_rx || np_tx == np_rx) {
+			dev_warn(cdev, "Invalid shmem descriptor for '%s'\n",
+				 of_node_full_name(np));
+			ret = -EINVAL;
+		}
+
+		of_node_put(np_tx);
+		of_node_put(np_rx);
+	}
+
+	return ret;
+}
+
 static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev,
 				int prot_id, bool tx)
 {
@@ -742,6 +793,10 @@
 		goto idr_alloc;
 	}
 
+	ret = scmi_mailbox_chan_validate(dev);
+	if (ret)
+		return ret;
+
 	cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL);
 	if (!cinfo)
 		return -ENOMEM;
@@ -965,7 +1020,7 @@
 
 module_platform_driver(scmi_driver);
 
-MODULE_ALIAS("platform: arm-scmi");
+MODULE_ALIAS("platform:arm-scmi");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("ARM SCMI protocol driver");
 MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/perf.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/perf.c
@@ -281,6 +281,8 @@
 		}
 
 		tot_opp_cnt += num_returned;
+
+		scmi_reset_rx_to_maxsz(handle, t);
 		/*
 		 * check for both returned and remaining to avoid infinite
 		 * loop due to buggy firmware
@@ -323,7 +325,7 @@
 
 		if (db->mask)
 			val = ioread64_hi_lo(db->addr) & db->mask;
-		iowrite64_hi_lo(db->set, db->addr);
+		iowrite64_hi_lo(db->set | val, db->addr);
 	}
 #endif
 }
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/reset.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/reset.c
@@ -35,9 +35,7 @@
 #define EXPLICIT_RESET_ASSERT	BIT(1)
 #define ASYNCHRONOUS_RESET	BIT(2)
 	__le32 reset_state;
-#define ARCH_RESET_TYPE		BIT(31)
-#define COLD_RESET_STATE	BIT(0)
-#define ARCH_COLD_RESET		(ARCH_RESET_TYPE | COLD_RESET_STATE)
+#define ARCH_COLD_RESET		0
 };
 
 struct reset_dom_info {
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/scmi_pm_domain.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/scmi_pm_domain.c
@@ -85,7 +85,10 @@
 	for (i = 0; i < num_domains; i++, scmi_pd++) {
 		u32 state;
 
-		domains[i] = &scmi_pd->genpd;
+		if (handle->power_ops->state_get(handle, i, &state)) {
+			dev_warn(dev, "failed to get state for domain %d\n", i);
+			continue;
+		}
 
 		scmi_pd->domain = i;
 		scmi_pd->handle = handle;
@@ -94,21 +97,35 @@
 		scmi_pd->genpd.power_off = scmi_pd_power_off;
 		scmi_pd->genpd.power_on = scmi_pd_power_on;
 
-		if (handle->power_ops->state_get(handle, i, &state)) {
-			dev_warn(dev, "failed to get state for domain %d\n", i);
-			continue;
-		}
-
 		pm_genpd_init(&scmi_pd->genpd, NULL,
 			      state == SCMI_POWER_STATE_GENERIC_OFF);
+
+		domains[i] = &scmi_pd->genpd;
 	}
 
 	scmi_pd_data->domains = domains;
 	scmi_pd_data->num_domains = num_domains;
 
-	of_genpd_add_provider_onecell(np, scmi_pd_data);
+	dev_set_drvdata(dev, scmi_pd_data);
 
-	return 0;
+	return of_genpd_add_provider_onecell(np, scmi_pd_data);
+}
+
+static void scmi_pm_domain_remove(struct scmi_device *sdev)
+{
+	int i;
+	struct genpd_onecell_data *scmi_pd_data;
+	struct device *dev = &sdev->dev;
+	struct device_node *np = dev->of_node;
+
+	of_genpd_del_provider(np);
+
+	scmi_pd_data = dev_get_drvdata(dev);
+	for (i = 0; i < scmi_pd_data->num_domains; i++) {
+		if (!scmi_pd_data->domains[i])
+			continue;
+		pm_genpd_remove(scmi_pd_data->domains[i]);
+	}
 }
 
 static const struct scmi_device_id scmi_id_table[] = {
@@ -120,6 +137,7 @@
 static struct scmi_driver scmi_power_domain_driver = {
 	.name = "scmi-power-domain",
 	.probe = scmi_pm_domain_probe,
+	.remove = scmi_pm_domain_remove,
 	.id_table = scmi_id_table,
 };
 module_scmi_driver(scmi_power_domain_driver);
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scmi/sensors.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scmi/sensors.c
@@ -154,6 +154,8 @@
 		}
 
 		desc_index += num_returned;
+
+		scmi_reset_rx_to_maxsz(handle, t);
 		/*
 		 * check for both returned and remaining to avoid infinite
 		 * loop due to buggy firmware
--- linux-ein-5.4.0.orig/drivers/firmware/arm_scpi.c
+++ linux-ein-5.4.0/drivers/firmware/arm_scpi.c
@@ -552,8 +552,10 @@
 
 	ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
 				sizeof(le_clk_id), &rate, sizeof(rate));
+	if (ret)
+		return 0;
 
-	return ret ? ret : le32_to_cpu(rate);
+	return le32_to_cpu(rate);
 }
 
 static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
@@ -813,7 +815,7 @@
 		info->firmware_version = le32_to_cpu(caps.platform_version);
 	}
 	/* Ignore error if not implemented */
-	if (scpi_info->is_legacy && ret == -EOPNOTSUPP)
+	if (info->is_legacy && ret == -EOPNOTSUPP)
 		return 0;
 
 	return ret;
@@ -903,13 +905,14 @@
 	struct resource res;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	struct scpi_drvinfo *scpi_drvinfo;
 
-	scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
-	if (!scpi_info)
+	scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL);
+	if (!scpi_drvinfo)
 		return -ENOMEM;
 
 	if (of_match_device(legacy_scpi_of_match, &pdev->dev))
-		scpi_info->is_legacy = true;
+		scpi_drvinfo->is_legacy = true;
 
 	count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
 	if (count < 0) {
@@ -917,19 +920,19 @@
 		return -ENODEV;
 	}
 
-	scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
-					   GFP_KERNEL);
-	if (!scpi_info->channels)
+	scpi_drvinfo->channels =
+		devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL);
+	if (!scpi_drvinfo->channels)
 		return -ENOMEM;
 
-	ret = devm_add_action(dev, scpi_free_channels, scpi_info);
+	ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo);
 	if (ret)
 		return ret;
 
-	for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
+	for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) {
 		resource_size_t size;
-		int idx = scpi_info->num_chans;
-		struct scpi_chan *pchan = scpi_info->channels + idx;
+		int idx = scpi_drvinfo->num_chans;
+		struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
 		struct mbox_client *cl = &pchan->cl;
 		struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
 
@@ -973,45 +976,53 @@
 		return ret;
 	}
 
-	scpi_info->commands = scpi_std_commands;
+	scpi_drvinfo->commands = scpi_std_commands;
 
-	platform_set_drvdata(pdev, scpi_info);
+	platform_set_drvdata(pdev, scpi_drvinfo);
 
-	if (scpi_info->is_legacy) {
+	if (scpi_drvinfo->is_legacy) {
 		/* Replace with legacy variants */
 		scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
-		scpi_info->commands = scpi_legacy_commands;
+		scpi_drvinfo->commands = scpi_legacy_commands;
 
 		/* Fill priority bitmap */
 		for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
 			set_bit(legacy_hpriority_cmds[idx],
-				scpi_info->cmd_priority);
+				scpi_drvinfo->cmd_priority);
 	}
 
-	ret = scpi_init_versions(scpi_info);
+	scpi_info = scpi_drvinfo;
+
+	ret = scpi_init_versions(scpi_drvinfo);
 	if (ret) {
 		dev_err(dev, "incorrect or no SCP firmware found\n");
+		scpi_info = NULL;
 		return ret;
 	}
 
-	if (scpi_info->is_legacy && !scpi_info->protocol_version &&
-	    !scpi_info->firmware_version)
+	if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version &&
+	    !scpi_drvinfo->firmware_version)
 		dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
 	else
 		dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
 			 FIELD_GET(PROTO_REV_MAJOR_MASK,
-				   scpi_info->protocol_version),
+				   scpi_drvinfo->protocol_version),
 			 FIELD_GET(PROTO_REV_MINOR_MASK,
-				   scpi_info->protocol_version),
+				   scpi_drvinfo->protocol_version),
 			 FIELD_GET(FW_REV_MAJOR_MASK,
-				   scpi_info->firmware_version),
+				   scpi_drvinfo->firmware_version),
 			 FIELD_GET(FW_REV_MINOR_MASK,
-				   scpi_info->firmware_version),
+				   scpi_drvinfo->firmware_version),
 			 FIELD_GET(FW_REV_PATCH_MASK,
-				   scpi_info->firmware_version));
-	scpi_info->scpi_ops = &scpi_ops;
+				   scpi_drvinfo->firmware_version));
+
+	scpi_drvinfo->scpi_ops = &scpi_ops;
 
-	return devm_of_platform_populate(dev);
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		scpi_info = NULL;
+
+	return ret;
 }
 
 static const struct of_device_id scpi_of_match[] = {
--- linux-ein-5.4.0.orig/drivers/firmware/arm_sdei.c
+++ linux-ein-5.4.0/drivers/firmware/arm_sdei.c
@@ -44,6 +44,8 @@
 /* entry point from firmware to arch asm code */
 static unsigned long sdei_entry_point;
 
+static int sdei_hp_state;
+
 struct sdei_event {
 	/* These three are protected by the sdei_list_lock */
 	struct list_head	list;
@@ -305,8 +307,6 @@
 {
 	int err;
 
-	WARN_ON_ONCE(preemptible());
-
 	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL);
 	if (err && err != -EIO) {
 		pr_warn_once("failed to mask CPU[%u]: %d\n",
@@ -319,6 +319,7 @@
 
 static void _ipi_mask_cpu(void *ignored)
 {
+	WARN_ON_ONCE(preemptible());
 	sdei_mask_local_cpu();
 }
 
@@ -326,8 +327,6 @@
 {
 	int err;
 
-	WARN_ON_ONCE(preemptible());
-
 	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL);
 	if (err && err != -EIO) {
 		pr_warn_once("failed to unmask CPU[%u]: %d\n",
@@ -340,6 +339,7 @@
 
 static void _ipi_unmask_cpu(void *ignored)
 {
+	WARN_ON_ONCE(preemptible());
 	sdei_unmask_local_cpu();
 }
 
@@ -347,6 +347,8 @@
 {
 	int err;
 
+	WARN_ON_ONCE(preemptible());
+
 	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0,
 			     NULL);
 	if (err && err != -EIO)
@@ -393,8 +395,6 @@
 	int err;
 	struct sdei_crosscall_args *arg = data;
 
-	WARN_ON_ONCE(preemptible());
-
 	err = sdei_api_event_enable(arg->event->event_num);
 
 	sdei_cross_call_return(arg, err);
@@ -412,14 +412,19 @@
 		return -ENOENT;
 	}
 
-	spin_lock(&sdei_list_lock);
-	event->reenable = true;
-	spin_unlock(&sdei_list_lock);
 
+	cpus_read_lock();
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		err = sdei_api_event_enable(event->event_num);
 	else
 		err = sdei_do_cross_call(_local_event_enable, event);
+
+	if (!err) {
+		spin_lock(&sdei_list_lock);
+		event->reenable = true;
+		spin_unlock(&sdei_list_lock);
+	}
+	cpus_read_unlock();
 	mutex_unlock(&sdei_events_lock);
 
 	return err;
@@ -480,8 +485,6 @@
 	int err;
 	struct sdei_crosscall_args *arg = data;
 
-	WARN_ON_ONCE(preemptible());
-
 	err = sdei_api_event_unregister(arg->event->event_num);
 
 	sdei_cross_call_return(arg, err);
@@ -491,11 +494,6 @@
 {
 	lockdep_assert_held(&sdei_events_lock);
 
-	spin_lock(&sdei_list_lock);
-	event->reregister = false;
-	event->reenable = false;
-	spin_unlock(&sdei_list_lock);
-
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		return sdei_api_event_unregister(event->event_num);
 
@@ -518,6 +516,11 @@
 			break;
 		}
 
+		spin_lock(&sdei_list_lock);
+		event->reregister = false;
+		event->reenable = false;
+		spin_unlock(&sdei_list_lock);
+
 		err = _sdei_event_unregister(event);
 		if (err)
 			break;
@@ -570,8 +573,6 @@
 	struct sdei_registered_event *reg;
 	struct sdei_crosscall_args *arg = data;
 
-	WARN_ON(preemptible());
-
 	reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id());
 	err = sdei_api_event_register(arg->event->event_num, sdei_entry_point,
 				      reg, 0, 0);
@@ -585,26 +586,15 @@
 
 	lockdep_assert_held(&sdei_events_lock);
 
-	spin_lock(&sdei_list_lock);
-	event->reregister = true;
-	spin_unlock(&sdei_list_lock);
-
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		return sdei_api_event_register(event->event_num,
 					       sdei_entry_point,
 					       event->registered,
 					       SDEI_EVENT_REGISTER_RM_ANY, 0);
 
-
 	err = sdei_do_cross_call(_local_event_register, event);
-	if (err) {
-		spin_lock(&sdei_list_lock);
-		event->reregister = false;
-		event->reenable = false;
-		spin_unlock(&sdei_list_lock);
-
+	if (err)
 		sdei_do_cross_call(_local_event_unregister, event);
-	}
 
 	return err;
 }
@@ -632,12 +622,18 @@
 			break;
 		}
 
+		cpus_read_lock();
 		err = _sdei_event_register(event);
 		if (err) {
 			sdei_event_destroy(event);
 			pr_warn("Failed to register event %u: %d\n", event_num,
 				err);
+		} else {
+			spin_lock(&sdei_list_lock);
+			event->reregister = true;
+			spin_unlock(&sdei_list_lock);
 		}
+		cpus_read_unlock();
 	} while (0);
 	mutex_unlock(&sdei_events_lock);
 
@@ -756,6 +752,8 @@
 {
 	int rv;
 
+	WARN_ON_ONCE(preemptible());
+
 	switch (action) {
 	case CPU_PM_ENTER:
 		rv = sdei_mask_local_cpu();
@@ -804,7 +802,7 @@
 	int err;
 
 	/* unregister private events */
-	cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
+	cpuhp_remove_state(sdei_entry_point);
 
 	err = sdei_unregister_shared();
 	if (err)
@@ -825,12 +823,15 @@
 		return err;
 	}
 
-	err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
+	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI",
 				&sdei_cpuhp_up, &sdei_cpuhp_down);
-	if (err)
+	if (err < 0) {
 		pr_warn("Failed to re-register CPU hotplug notifier...\n");
+		return err;
+	}
 
-	return err;
+	sdei_hp_state = err;
+	return 0;
 }
 
 static int sdei_device_restore(struct device *dev)
@@ -862,7 +863,7 @@
 	 * We are going to reset the interface, after this there is no point
 	 * doing work when we take CPUs offline.
 	 */
-	cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
+	cpuhp_remove_state(sdei_hp_state);
 
 	sdei_platform_reset();
 
@@ -1044,13 +1045,15 @@
 		goto remove_cpupm;
 	}
 
-	err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
+	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI",
 				&sdei_cpuhp_up, &sdei_cpuhp_down);
-	if (err) {
+	if (err < 0) {
 		pr_warn("Failed to register CPU hotplug notifier...\n");
 		goto remove_reboot;
 	}
 
+	sdei_hp_state = err;
+
 	return 0;
 
 remove_reboot:
--- linux-ein-5.4.0.orig/drivers/firmware/dmi-sysfs.c
+++ linux-ein-5.4.0/drivers/firmware/dmi-sysfs.c
@@ -603,7 +603,7 @@
 				    "%d-%d", dh->type, entry->instance);
 
 	if (*ret) {
-		kfree(entry);
+		kobject_put(&entry->kobj);
 		return;
 	}
 
--- linux-ein-5.4.0.orig/drivers/firmware/efi/Kconfig
+++ linux-ein-5.4.0/drivers/firmware/efi/Kconfig
@@ -216,6 +216,17 @@
 
 config EFI_EARLYCON
 	def_bool y
-	depends on SERIAL_EARLYCON && !ARM && !IA64
+	depends on EFI && SERIAL_EARLYCON && !ARM && !IA64
 	select FONT_SUPPORT
 	select ARCH_USE_MEMREMAP_PROT
+
+config EFI_CUSTOM_SSDT_OVERLAYS
+	bool "Load custom ACPI SSDT overlay from an EFI variable"
+	depends on EFI_VARS && ACPI
+	default ACPI_TABLE_UPGRADE
+	help
+	  Allow loading of an ACPI SSDT overlay from an EFI variable specified
+	  by a kernel command line option.
+
+	  See Documentation/admin-guide/acpi/ssdt-overlays.rst for more
+	  information.
--- linux-ein-5.4.0.orig/drivers/firmware/efi/Makefile
+++ linux-ein-5.4.0/drivers/firmware/efi/Makefile
@@ -24,8 +24,10 @@
 obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)	+= efibc.o
 obj-$(CONFIG_EFI_TEST)			+= test/
 obj-$(CONFIG_EFI_DEV_PATH_PARSER)	+= dev-path-parser.o
+obj-$(CONFIG_EFI)			+= secureboot.o
 obj-$(CONFIG_APPLE_PROPERTIES)		+= apple-properties.o
 obj-$(CONFIG_EFI_RCI2_TABLE)		+= rci2-table.o
+obj-$(CONFIG_LOAD_UEFI_KEYS)		+= mokvar-table.o
 
 arm-obj-$(CONFIG_EFI)			:= arm-init.o arm-runtime.o
 obj-$(CONFIG_ARM)			+= $(arm-obj-y)
--- linux-ein-5.4.0.orig/drivers/firmware/efi/apple-properties.c
+++ linux-ein-5.4.0/drivers/firmware/efi/apple-properties.c
@@ -23,7 +23,7 @@
 static int __init dump_properties_enable(char *arg)
 {
 	dump_properties = true;
-	return 0;
+	return 1;
 }
 
 __setup("dump_apple_properties", dump_properties_enable);
--- linux-ein-5.4.0.orig/drivers/firmware/efi/arm-init.c
+++ linux-ein-5.4.0/drivers/firmware/efi/arm-init.c
@@ -17,6 +17,7 @@
 #include <linux/of_fdt.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
+#include <linux/security.h>
 
 #include <asm/efi.h>
 
@@ -253,8 +254,16 @@
 		return;
 	}
 
+	efi_set_secure_boot(params.secure_boot);
+
+#ifdef CONFIG_LOCK_DOWN_IN_SECURE_BOOT
+	if (efi_enabled(EFI_SECURE_BOOT))
+		security_lock_kernel_down("EFI Secure Boot mode", LOCKDOWN_INTEGRITY_MAX);
+#endif
+
 	reserve_regions();
 	efi_esrt_init();
+	efi_mokvar_table_init();
 
 	memblock_reserve(params.mmap & PAGE_MASK,
 			 PAGE_ALIGN(params.mmap_size +
--- linux-ein-5.4.0.orig/drivers/firmware/efi/capsule-loader.c
+++ linux-ein-5.4.0/drivers/firmware/efi/capsule-loader.c
@@ -242,29 +242,6 @@
 }
 
 /**
- * efi_capsule_flush - called by file close or file flush
- * @file: file pointer
- * @id: not used
- *
- *	If a capsule is being partially uploaded then calling this function
- *	will be treated as upload termination and will free those completed
- *	buffer pages and -ECANCELED will be returned.
- **/
-static int efi_capsule_flush(struct file *file, fl_owner_t id)
-{
-	int ret = 0;
-	struct capsule_info *cap_info = file->private_data;
-
-	if (cap_info->index > 0) {
-		pr_err("capsule upload not complete\n");
-		efi_free_all_buff_pages(cap_info);
-		ret = -ECANCELED;
-	}
-
-	return ret;
-}
-
-/**
  * efi_capsule_release - called by file close
  * @inode: not used
  * @file: file pointer
@@ -276,6 +253,13 @@
 {
 	struct capsule_info *cap_info = file->private_data;
 
+	if (cap_info->index > 0 &&
+	    (cap_info->header.headersize == 0 ||
+	     cap_info->count < cap_info->total_size)) {
+		pr_err("capsule upload not complete\n");
+		efi_free_all_buff_pages(cap_info);
+	}
+
 	kfree(cap_info->pages);
 	kfree(cap_info->phys);
 	kfree(file->private_data);
@@ -307,7 +291,7 @@
 		return -ENOMEM;
 	}
 
-	cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL);
+	cap_info->phys = kzalloc(sizeof(phys_addr_t), GFP_KERNEL);
 	if (!cap_info->phys) {
 		kfree(cap_info->pages);
 		kfree(cap_info);
@@ -323,7 +307,6 @@
 	.owner = THIS_MODULE,
 	.open = efi_capsule_open,
 	.write = efi_capsule_write,
-	.flush = efi_capsule_flush,
 	.release = efi_capsule_release,
 	.llseek = no_llseek,
 };
--- linux-ein-5.4.0.orig/drivers/firmware/efi/cper.c
+++ linux-ein-5.4.0/drivers/firmware/efi/cper.c
@@ -25,8 +25,6 @@
 #include <acpi/ghes.h>
 #include <ras/ras_event.h>
 
-static char rcd_decode_str[CPER_REC_LEN];
-
 /*
  * CPER record ID need to be unique even after reboot, because record
  * ID is used as index for ERST storage, while CPER records from
@@ -263,8 +261,7 @@
 	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
 		return 0;
 
-	n = 0;
-	len = CPER_REC_LEN - 1;
+	len = CPER_REC_LEN;
 	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
 	if (bank && device)
 		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
@@ -273,7 +270,6 @@
 			     "DIMM location: not present. DMI handle: 0x%.4x ",
 			     mem->mem_dev_handle);
 
-	msg[n] = '\0';
 	return n;
 }
 
@@ -301,6 +297,7 @@
 				struct cper_mem_err_compact *cmem)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
+	char rcd_decode_str[CPER_REC_LEN];
 
 	if (cper_mem_err_location(cmem, rcd_decode_str))
 		trace_seq_printf(p, "%s", rcd_decode_str);
@@ -315,6 +312,7 @@
 	int len)
 {
 	struct cper_mem_err_compact cmem;
+	char rcd_decode_str[CPER_REC_LEN];
 
 	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
 	if (len == sizeof(struct cper_sec_mem_err_old) &&
--- linux-ein-5.4.0.orig/drivers/firmware/efi/earlycon.c
+++ linux-ein-5.4.0/drivers/firmware/efi/earlycon.c
@@ -13,18 +13,58 @@
 
 #include <asm/early_ioremap.h>
 
+static const struct console *earlycon_console __initdata;
 static const struct font_desc *font;
 static u32 efi_x, efi_y;
 static u64 fb_base;
-static pgprot_t fb_prot;
+static bool fb_wb;
+static void *efi_fb;
+
+/*
+ * EFI earlycon needs to use early_memremap() to map the framebuffer.
+ * But early_memremap() is not usable for 'earlycon=efifb keep_bootcon',
+ * memremap() should be used instead. memremap() will be available after
+ * paging_init() which is earlier than initcall callbacks. Thus adding this
+ * early initcall function early_efi_map_fb() to map the whole EFI framebuffer.
+ */
+static int __init efi_earlycon_remap_fb(void)
+{
+	/* bail if there is no bootconsole or it has been disabled already */
+	if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
+		return 0;
+
+	efi_fb = memremap(fb_base, screen_info.lfb_size,
+			  fb_wb ? MEMREMAP_WB : MEMREMAP_WC);
+
+	return efi_fb ? 0 : -ENOMEM;
+}
+early_initcall(efi_earlycon_remap_fb);
+
+static int __init efi_earlycon_unmap_fb(void)
+{
+	/* unmap the bootconsole fb unless keep_bootcon has left it enabled */
+	if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
+		memunmap(efi_fb);
+	return 0;
+}
+late_initcall(efi_earlycon_unmap_fb);
 
 static __ref void *efi_earlycon_map(unsigned long start, unsigned long len)
 {
+	pgprot_t fb_prot;
+
+	if (efi_fb)
+		return efi_fb + start;
+
+	fb_prot = fb_wb ? PAGE_KERNEL : pgprot_writecombine(PAGE_KERNEL);
 	return early_memremap_prot(fb_base + start, len, pgprot_val(fb_prot));
 }
 
 static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
 {
+	if (efi_fb)
+		return;
+
 	early_memunmap(addr, len);
 }
 
@@ -176,10 +216,7 @@
 	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
 		fb_base |= (u64)screen_info.ext_lfb_base << 32;
 
-	if (opt && !strcmp(opt, "ram"))
-		fb_prot = PAGE_KERNEL;
-	else
-		fb_prot = pgprot_writecombine(PAGE_KERNEL);
+	fb_wb = opt && !strcmp(opt, "ram");
 
 	si = &screen_info;
 	xres = si->lfb_width;
@@ -201,6 +238,7 @@
 		efi_earlycon_scroll_up();
 
 	device->con->write = efi_earlycon_write;
+	earlycon_console = device->con;
 	return 0;
 }
 EARLYCON_DECLARE(efifb, efi_earlycon_setup);
--- linux-ein-5.4.0.orig/drivers/firmware/efi/efi.c
+++ linux-ein-5.4.0/drivers/firmware/efi/efi.c
@@ -31,6 +31,7 @@
 #include <linux/ucs2_string.h>
 #include <linux/memblock.h>
 #include <linux/security.h>
+#include <linux/bsearch.h>
 
 #include <asm/early_ioremap.h>
 
@@ -52,6 +53,9 @@
 	.rng_seed		= EFI_INVALID_TABLE_ADDR,
 	.tpm_log		= EFI_INVALID_TABLE_ADDR,
 	.tpm_final_log		= EFI_INVALID_TABLE_ADDR,
+#ifdef CONFIG_LOAD_UEFI_KEYS
+	.mokvar_table		= EFI_INVALID_TABLE_ADDR,
+#endif
 	.mem_reserve		= EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
@@ -217,7 +221,7 @@
 	efivars_unregister(&generic_efivars);
 }
 
-#if IS_ENABLED(CONFIG_ACPI)
+#ifdef CONFIG_EFI_CUSTOM_SSDT_OVERLAYS
 #define EFIVAR_SSDT_NAME_MAX	16
 static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
 static int __init efivar_ssdt_setup(char *str)
@@ -231,7 +235,7 @@
 		memcpy(efivar_ssdt, str, strlen(str));
 	else
 		pr_warn("efivar_ssdt: name too long: %s\n", str);
-	return 0;
+	return 1;
 }
 __setup("efivar_ssdt=", efivar_ssdt_setup);
 
@@ -345,7 +349,8 @@
 	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
 	if (!efi_kobj) {
 		pr_err("efi: Firmware registration failed.\n");
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto err_destroy_wq;
 	}
 
 	error = generic_ops_register();
@@ -381,6 +386,10 @@
 	generic_ops_unregister();
 err_put:
 	kobject_put(efi_kobj);
+err_destroy_wq:
+	if (efi_rts_wq)
+		destroy_workqueue(efi_rts_wq);
+
 	return error;
 }
 
@@ -477,6 +486,9 @@
 #ifdef CONFIG_EFI_RCI2_TABLE
 	{DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
 #endif
+#ifdef CONFIG_LOAD_UEFI_KEYS
+	{LINUX_EFI_MOK_VARIABLE_TABLE_GUID, "MOKvar", &efi.mokvar_table},
+#endif
 	{NULL_GUID, NULL, NULL},
 };
 
@@ -544,7 +556,7 @@
 
 		seed = early_memremap(efi.rng_seed, sizeof(*seed));
 		if (seed != NULL) {
-			size = seed->size;
+			size = min(seed->size, EFI_RANDOM_SEED_SIZE);
 			early_memunmap(seed, sizeof(*seed));
 		} else {
 			pr_err("Could not map UEFI random seed!\n");
@@ -554,7 +566,7 @@
 					      sizeof(*seed) + size);
 			if (seed != NULL) {
 				pr_notice("seeding entropy pool\n");
-				add_bootloader_randomness(seed->bits, seed->size);
+				add_bootloader_randomness(seed->bits, size);
 				early_memunmap(seed, sizeof(*seed) + size);
 			} else {
 				pr_err("Could not map UEFI random seed!\n");
@@ -562,7 +574,7 @@
 		}
 	}
 
-	if (efi_enabled(EFI_MEMMAP))
+	if (!IS_ENABLED(CONFIG_X86_32) && efi_enabled(EFI_MEMMAP))
 		efi_memattr_init();
 
 	efi_tpm_eventlog_init();
@@ -688,7 +700,8 @@
 	UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
 	UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
 	UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
-	UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
+	UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver),
+	UEFI_PARAM("Secure Boot Enabled", "linux,uefi-secure-boot", secure_boot)
 };
 
 static __initdata struct params xen_fdt_params[] = {
@@ -918,40 +931,101 @@
 }
 #endif
 
+struct efi_error_code {
+	efi_status_t status;
+	int errno;
+	const char *description;
+};
+
+static const struct efi_error_code efi_error_codes[] = {
+	{ EFI_SUCCESS, 0, "Success"},
+#if 0
+	{ EFI_LOAD_ERROR, -EPICK_AN_ERRNO, "Load Error"},
+#endif
+	{ EFI_INVALID_PARAMETER, -EINVAL, "Invalid Parameter"},
+	{ EFI_UNSUPPORTED, -ENOSYS, "Unsupported"},
+	{ EFI_BAD_BUFFER_SIZE, -ENOSPC, "Bad Buffer Size"},
+	{ EFI_BUFFER_TOO_SMALL, -ENOSPC, "Buffer Too Small"},
+	{ EFI_NOT_READY, -EAGAIN, "Not Ready"},
+	{ EFI_DEVICE_ERROR, -EIO, "Device Error"},
+	{ EFI_WRITE_PROTECTED, -EROFS, "Write Protected"},
+	{ EFI_OUT_OF_RESOURCES, -ENOMEM, "Out of Resources"},
+#if 0
+	{ EFI_VOLUME_CORRUPTED, -EPICK_AN_ERRNO, "Volume Corrupt"},
+	{ EFI_VOLUME_FULL, -EPICK_AN_ERRNO, "Volume Full"},
+	{ EFI_NO_MEDIA, -EPICK_AN_ERRNO, "No Media"},
+	{ EFI_MEDIA_CHANGED, -EPICK_AN_ERRNO, "Media changed"},
+#endif
+	{ EFI_NOT_FOUND, -ENOENT, "Not Found"},
+#if 0
+	{ EFI_ACCESS_DENIED, -EPICK_AN_ERRNO, "Access Denied"},
+	{ EFI_NO_RESPONSE, -EPICK_AN_ERRNO, "No Response"},
+	{ EFI_NO_MAPPING, -EPICK_AN_ERRNO, "No mapping"},
+	{ EFI_TIMEOUT, -EPICK_AN_ERRNO, "Time out"},
+	{ EFI_NOT_STARTED, -EPICK_AN_ERRNO, "Not started"},
+	{ EFI_ALREADY_STARTED, -EPICK_AN_ERRNO, "Already started"},
+#endif
+	{ EFI_ABORTED, -EINTR, "Aborted"},
+#if 0
+	{ EFI_ICMP_ERROR, -EPICK_AN_ERRNO, "ICMP Error"},
+	{ EFI_TFTP_ERROR, -EPICK_AN_ERRNO, "TFTP Error"},
+	{ EFI_PROTOCOL_ERROR, -EPICK_AN_ERRNO, "Protocol Error"},
+	{ EFI_INCOMPATIBLE_VERSION, -EPICK_AN_ERRNO, "Incompatible Version"},
+#endif
+	{ EFI_SECURITY_VIOLATION, -EACCES, "Security Policy Violation"},
+#if 0
+	{ EFI_CRC_ERROR, -EPICK_AN_ERRNO, "CRC Error"},
+	{ EFI_END_OF_MEDIA, -EPICK_AN_ERRNO, "End of Media"},
+	{ EFI_END_OF_FILE, -EPICK_AN_ERRNO, "End of File"},
+	{ EFI_INVALID_LANGUAGE, -EPICK_AN_ERRNO, "Invalid Languages"},
+	{ EFI_COMPROMISED_DATA, -EPICK_AN_ERRNO, "Compromised Data"},
+
+	// warnings
+	{ EFI_WARN_UNKOWN_GLYPH, -EPICK_AN_ERRNO, "Warning Unknown Glyph"},
+	{ EFI_WARN_DELETE_FAILURE, -EPICK_AN_ERRNO, "Warning Delete Failure"},
+	{ EFI_WARN_WRITE_FAILURE, -EPICK_AN_ERRNO, "Warning Write Failure"},
+	{ EFI_WARN_BUFFER_TOO_SMALL, -EPICK_AN_ERRNO, "Warning Buffer Too Small"},
+#endif
+};
+
+static int
+efi_status_cmp_bsearch(const void *key, const void *item)
+{
+	u64 status = (u64)(uintptr_t)key;
+	struct efi_error_code *code = (struct efi_error_code *)item;
+
+	if (status < code->status)
+		return -1;
+	if (status > code->status)
+		return 1;
+	return 0;
+}
+
 int efi_status_to_err(efi_status_t status)
 {
-	int err;
+	struct efi_error_code *found;
+	size_t num = sizeof(efi_error_codes) / sizeof(struct efi_error_code);
 
-	switch (status) {
-	case EFI_SUCCESS:
-		err = 0;
-		break;
-	case EFI_INVALID_PARAMETER:
-		err = -EINVAL;
-		break;
-	case EFI_OUT_OF_RESOURCES:
-		err = -ENOSPC;
-		break;
-	case EFI_DEVICE_ERROR:
-		err = -EIO;
-		break;
-	case EFI_WRITE_PROTECTED:
-		err = -EROFS;
-		break;
-	case EFI_SECURITY_VIOLATION:
-		err = -EACCES;
-		break;
-	case EFI_NOT_FOUND:
-		err = -ENOENT;
-		break;
-	case EFI_ABORTED:
-		err = -EINTR;
-		break;
-	default:
-		err = -EINVAL;
-	}
+	found = bsearch((void *)(uintptr_t)status, efi_error_codes,
+			sizeof(struct efi_error_code), num,
+			efi_status_cmp_bsearch);
+	if (!found)
+		return -EINVAL;
+	return found->errno;
+}
+
+const char *
+efi_status_to_str(efi_status_t status)
+{
+	struct efi_error_code *found;
+	size_t num = sizeof(efi_error_codes) / sizeof(struct efi_error_code);
 
-	return err;
+	found = bsearch((void *)(uintptr_t)status, efi_error_codes,
+			sizeof(struct efi_error_code), num,
+			efi_status_cmp_bsearch);
+	if (!found)
+		return "Unknown error code";
+	return found->description;
 }
 
 static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
@@ -970,6 +1044,35 @@
 	return 0;
 }
 
+static int efi_mem_reserve_iomem(phys_addr_t addr, u64 size)
+{
+	struct resource *res, *parent;
+	int ret;
+
+	res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
+	if (!res)
+		return -ENOMEM;
+
+	res->name	= "reserved";
+	res->flags	= IORESOURCE_MEM;
+	res->start	= addr;
+	res->end	= addr + size - 1;
+
+	/* we expect a conflict with a 'System RAM' region */
+	parent = request_resource_conflict(&iomem_resource, res);
+	ret = parent ? request_resource(parent, res) : 0;
+
+	/*
+	 * Given that efi_mem_reserve_iomem() can be called at any
+	 * time, only call memblock_reserve() if the architecture
+	 * keeps the infrastructure around.
+	 */
+	if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK) && !ret)
+		memblock_reserve(addr, size);
+
+	return ret;
+}
+
 int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
 {
 	struct linux_efi_memreserve *rsv;
@@ -986,16 +1089,19 @@
 	}
 
 	/* first try to find a slot in an existing linked list entry */
-	for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
+	for (prsv = efi_memreserve_root->next; prsv; ) {
 		rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
+		if (!rsv)
+			return -ENOMEM;
 		index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
 		if (index < rsv->size) {
 			rsv->entry[index].base = addr;
 			rsv->entry[index].size = size;
 
 			memunmap(rsv);
-			return 0;
+			return efi_mem_reserve_iomem(addr, size);
 		}
+		prsv = rsv->next;
 		memunmap(rsv);
 	}
 
@@ -1004,6 +1110,12 @@
 	if (!rsv)
 		return -ENOMEM;
 
+	rc = efi_mem_reserve_iomem(__pa(rsv), SZ_4K);
+	if (rc) {
+		free_page((unsigned long)rsv);
+		return rc;
+	}
+
 	/*
 	 * The memremap() call above assumes that a linux_efi_memreserve entry
 	 * never crosses a page boundary, so let's ensure that this remains true
@@ -1020,7 +1132,7 @@
 	efi_memreserve_root->next = __pa(rsv);
 	spin_unlock(&efi_mem_reserve_persistent_lock);
 
-	return 0;
+	return efi_mem_reserve_iomem(addr, size);
 }
 
 static int __init efi_memreserve_root_init(void)
--- linux-ein-5.4.0.orig/drivers/firmware/efi/efivars.c
+++ linux-ein-5.4.0/drivers/firmware/efi/efivars.c
@@ -83,13 +83,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)
@@ -116,13 +119,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);
@@ -133,12 +139,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);
@@ -199,6 +208,9 @@
 	u8 *data;
 	int err;
 
+	if (!entry || !buf)
+		return -EINVAL;
+
 	if (in_compat_syscall()) {
 		struct compat_efi_variable *compat;
 
@@ -250,14 +262,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 (in_compat_syscall()) {
@@ -508,8 +522,10 @@
 	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);
 	if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
--- linux-ein-5.4.0.orig/drivers/firmware/efi/esrt.c
+++ linux-ein-5.4.0/drivers/firmware/efi/esrt.c
@@ -181,7 +181,7 @@
 		rc = kobject_init_and_add(&entry->kobj, &esre1_ktype, NULL,
 					  "entry%d", entry_num);
 		if (rc) {
-			kfree(entry);
+			kobject_put(&entry->kobj);
 			return rc;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/Makefile
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/Makefile
@@ -28,6 +28,7 @@
 				   -D__NO_FORTIFY \
 				   $(call cc-option,-ffreestanding) \
 				   $(call cc-option,-fno-stack-protector) \
+				   $(call cc-option,-fno-addrsig) \
 				   -D__DISABLE_EXPORTS
 
 GCOV_PROFILE			:= n
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/arm-stub.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/arm-stub.c
@@ -189,6 +189,8 @@
 		goto fail_free_cmdline;
 	}
 
+	efi_retrieve_tpm2_eventlog(sys_table);
+
 	/* Ask the firmware to clear memory on unclean shutdown */
 	efi_enable_reset_attack_mitigation(sys_table);
 
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -46,7 +46,7 @@
 	return __novamap;
 }
 
-#define EFI_MMAP_NR_SLACK_SLOTS	8
+#define EFI_MMAP_NR_SLACK_SLOTS	16
 
 struct file_info {
 	efi_file_handle_t *handle;
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/fdt.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/fdt.c
@@ -151,6 +151,12 @@
 		}
 	}
 
+	fdt_val32 = cpu_to_fdt32(efi_get_secureboot(sys_table));
+	status = fdt_setprop(fdt, node, "linux,uefi-secure-boot",
+			     &fdt_val32, sizeof(fdt_val32));
+	if (status)
+		goto fdt_set_fail;
+
 	/* Shrink the FDT back to its minimum size: */
 	fdt_pack(fdt);
 
@@ -291,14 +297,6 @@
 		goto fail;
 	}
 
-	/*
-	 * Now that we have done our final memory allocation (and free)
-	 * we can get the memory map key needed for exit_boot_services().
-	 */
-	status = efi_get_memory_map(sys_table, &map);
-	if (status != EFI_SUCCESS)
-		goto fail_free_new_fdt;
-
 	status = update_fdt(sys_table, (void *)fdt_addr, fdt_size,
 			    (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr,
 			    initrd_addr, initrd_size);
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/gop.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/gop.c
@@ -84,30 +84,6 @@
 }
 
 static efi_status_t
-__gop_query32(efi_system_table_t *sys_table_arg,
-	      struct efi_graphics_output_protocol_32 *gop32,
-	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
-{
-	struct efi_graphics_output_protocol_mode_32 *mode;
-	efi_graphics_output_protocol_query_mode query_mode;
-	efi_status_t status;
-	unsigned long m;
-
-	m = gop32->mode;
-	mode = (struct efi_graphics_output_protocol_mode_32 *)m;
-	query_mode = (void *)(unsigned long)gop32->query_mode;
-
-	status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
-				  info);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	*fb_base = mode->frame_buffer_base;
-	return status;
-}
-
-static efi_status_t
 setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
             efi_guid_t *proto, unsigned long size, void **gop_handle)
 {
@@ -119,7 +95,7 @@
 	u64 fb_base;
 	struct efi_pixel_bitmask pixel_info;
 	int pixel_format;
-	efi_status_t status = EFI_NOT_FOUND;
+	efi_status_t status;
 	u32 *handles = (u32 *)(unsigned long)gop_handle;
 	int i;
 
@@ -128,6 +104,7 @@
 
 	nr_gops = size / sizeof(u32);
 	for (i = 0; i < nr_gops; i++) {
+		struct efi_graphics_output_protocol_mode_32 *mode;
 		struct efi_graphics_output_mode_info *info = NULL;
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 		bool conout_found = false;
@@ -145,9 +122,11 @@
 		if (status == EFI_SUCCESS)
 			conout_found = true;
 
-		status = __gop_query32(sys_table_arg, gop32, &info, &size,
-				       &current_fb_base);
-		if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+		mode = (void *)(unsigned long)gop32->mode;
+		info = (void *)(unsigned long)mode->info;
+		current_fb_base = mode->frame_buffer_base;
+
+		if ((!first_gop || conout_found) &&
 		    info->pixel_format != PIXEL_BLT_ONLY) {
 			/*
 			 * Systems that use the UEFI Console Splitter may
@@ -175,7 +154,7 @@
 
 	/* Did we find any GOPs? */
 	if (!first_gop)
-		goto out;
+		return EFI_NOT_FOUND;
 
 	/* EFI framebuffer */
 	si->orig_video_isVGA = VIDEO_TYPE_EFI;
@@ -197,32 +176,8 @@
 	si->lfb_size = si->lfb_linelength * si->lfb_height;
 
 	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
-	return status;
-}
-
-static efi_status_t
-__gop_query64(efi_system_table_t *sys_table_arg,
-	      struct efi_graphics_output_protocol_64 *gop64,
-	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
-{
-	struct efi_graphics_output_protocol_mode_64 *mode;
-	efi_graphics_output_protocol_query_mode query_mode;
-	efi_status_t status;
-	unsigned long m;
 
-	m = gop64->mode;
-	mode = (struct efi_graphics_output_protocol_mode_64 *)m;
-	query_mode = (void *)(unsigned long)gop64->query_mode;
-
-	status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
-				  info);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	*fb_base = mode->frame_buffer_base;
-	return status;
+	return EFI_SUCCESS;
 }
 
 static efi_status_t
@@ -237,7 +192,7 @@
 	u64 fb_base;
 	struct efi_pixel_bitmask pixel_info;
 	int pixel_format;
-	efi_status_t status = EFI_NOT_FOUND;
+	efi_status_t status;
 	u64 *handles = (u64 *)(unsigned long)gop_handle;
 	int i;
 
@@ -246,6 +201,7 @@
 
 	nr_gops = size / sizeof(u64);
 	for (i = 0; i < nr_gops; i++) {
+		struct efi_graphics_output_protocol_mode_64 *mode;
 		struct efi_graphics_output_mode_info *info = NULL;
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 		bool conout_found = false;
@@ -263,9 +219,11 @@
 		if (status == EFI_SUCCESS)
 			conout_found = true;
 
-		status = __gop_query64(sys_table_arg, gop64, &info, &size,
-				       &current_fb_base);
-		if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+		mode = (void *)(unsigned long)gop64->mode;
+		info = (void *)(unsigned long)mode->info;
+		current_fb_base = mode->frame_buffer_base;
+
+		if ((!first_gop || conout_found) &&
 		    info->pixel_format != PIXEL_BLT_ONLY) {
 			/*
 			 * Systems that use the UEFI Console Splitter may
@@ -293,7 +251,7 @@
 
 	/* Did we find any GOPs? */
 	if (!first_gop)
-		goto out;
+		return EFI_NOT_FOUND;
 
 	/* EFI framebuffer */
 	si->orig_video_isVGA = VIDEO_TYPE_EFI;
@@ -315,8 +273,8 @@
 	si->lfb_size = si->lfb_linelength * si->lfb_height;
 
 	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
-	return status;
+
+	return EFI_SUCCESS;
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/secureboot.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/secureboot.c
@@ -19,7 +19,7 @@
 
 /* SHIM variables */
 static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
-static const efi_char16_t shim_MokSBState_name[] = L"MokSBState";
+static const efi_char16_t shim_MokSBState_name[] = L"MokSBStateRT";
 
 #define get_efi_var(name, vendor, ...) \
 	efi_call_runtime(get_variable, \
@@ -58,8 +58,8 @@
 
 	/*
 	 * See if a user has put the shim into insecure mode. If so, and if the
-	 * variable doesn't have the runtime attribute set, we might as well
-	 * honor that.
+	 * variable doesn't have the non-volatile attribute set, we might as
+	 * well honor that.
 	 */
 	size = sizeof(moksbstate);
 	status = get_efi_var(shim_MokSBState_name, &shim_guid,
@@ -68,7 +68,7 @@
 	/* If it fails, we don't care why. Default to secure */
 	if (status != EFI_SUCCESS)
 		goto secure_boot_enabled;
-	if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS) && moksbstate == 1)
+	if (!(attr & EFI_VARIABLE_NON_VOLATILE) && moksbstate == 1)
 		return efi_secureboot_mode_disabled;
 
 secure_boot_enabled:
--- linux-ein-5.4.0.orig/drivers/firmware/efi/libstub/tpm.c
+++ linux-ein-5.4.0/drivers/firmware/efi/libstub/tpm.c
@@ -64,7 +64,7 @@
 	efi_status_t status;
 	efi_physical_addr_t log_location = 0, log_last_entry = 0;
 	struct linux_efi_tpm_eventlog *log_tbl = NULL;
-	struct efi_tcg2_final_events_table *final_events_table;
+	struct efi_tcg2_final_events_table *final_events_table = NULL;
 	unsigned long first_entry_addr, last_entry_addr;
 	size_t log_size, last_entry_size;
 	efi_bool_t truncated;
@@ -140,7 +140,8 @@
 	 * Figure out whether any events have already been logged to the
 	 * final events structure, and if so how much space they take up
 	 */
-	final_events_table = get_efi_config_table(sys_table_arg,
+	if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+		final_events_table = get_efi_config_table(sys_table_arg,
 						LINUX_EFI_TPM_FINAL_LOG_GUID);
 	if (final_events_table && final_events_table->nr_events) {
 		struct tcg_pcr_event2_head *header;
--- linux-ein-5.4.0.orig/drivers/firmware/efi/memattr.c
+++ linux-ein-5.4.0/drivers/firmware/efi/memattr.c
@@ -32,7 +32,7 @@
 		return -ENOMEM;
 	}
 
-	if (tbl->version > 1) {
+	if (tbl->version > 2) {
 		pr_warn("Unexpected EFI Memory Attributes table version %d\n",
 			tbl->version);
 		goto unmap;
@@ -66,11 +66,6 @@
 		return false;
 	}
 
-	if (!(in->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))) {
-		pr_warn("Entry attributes invalid: RO and XP bits both cleared\n");
-		return false;
-	}
-
 	if (PAGE_SIZE > EFI_PAGE_SIZE &&
 	    (!PAGE_ALIGNED(in->phys_addr) ||
 	     !PAGE_ALIGNED(in->num_pages << EFI_PAGE_SHIFT))) {
--- linux-ein-5.4.0.orig/drivers/firmware/efi/mokvar-table.c
+++ linux-ein-5.4.0/drivers/firmware/efi/mokvar-table.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mokvar-table.c
+ *
+ * Copyright (c) 2020 Red Hat
+ * Author: Lenny Szubowicz <lszubowi@redhat.com>
+ *
+ * This module contains the kernel support for the Linux EFI Machine
+ * Owner Key (MOK) variable configuration table, which is identified by
+ * the LINUX_EFI_MOK_VARIABLE_TABLE_GUID.
+ *
+ * This EFI configuration table provides a more robust alternative to
+ * EFI volatile variables by which an EFI boot loader can pass the
+ * contents of the Machine Owner Key (MOK) certificate stores to the
+ * kernel during boot. If both the EFI MOK config table and corresponding
+ * EFI MOK variables are present, the table should be considered as
+ * more authoritative.
+ *
+ * This module includes code that validates and maps the EFI MOK table,
+ * if it's presence was detected very early in boot.
+ *
+ * Kernel interface routines are provided to walk through all the
+ * entries in the MOK config table or to search for a specific named
+ * entry.
+ *
+ * The contents of the individual named MOK config table entries are
+ * made available to user space via read-only sysfs binary files under:
+ *
+ * /sys/firmware/efi/mok-variables/
+ *
+ */
+#define pr_fmt(fmt) "mokvar: " fmt
+
+#include <linux/capability.h>
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <asm/early_ioremap.h>
+
+/*
+ * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed
+ * sequence of struct efi_mokvar_table_entry, one for each named
+ * MOK variable. The sequence is terminated by an entry with a
+ * completely NULL name and 0 data size.
+ *
+ * efi_mokvar_table_size is set to the computed size of the
+ * MOK config table by efi_mokvar_table_init(). This will be
+ * non-zero if and only if the table if present and has been
+ * validated by efi_mokvar_table_init().
+ */
+static size_t efi_mokvar_table_size;
+
+/*
+ * efi_mokvar_table_va is the kernel virtual address at which the
+ * EFI MOK config table has been mapped by efi_mokvar_sysfs_init().
+ */
+static struct efi_mokvar_table_entry *efi_mokvar_table_va;
+
+/*
+ * Each /sys/firmware/efi/mok-variables/ sysfs file is represented by
+ * an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list.
+ * bin_attr.private points to the associated EFI MOK config table entry.
+ *
+ * This list is created during boot and then remains unchanged.
+ * So no synchronization is currently required to walk the list.
+ */
+struct efi_mokvar_sysfs_attr {
+	struct bin_attribute bin_attr;
+	struct list_head node;
+};
+
+static LIST_HEAD(efi_mokvar_sysfs_list);
+static struct kobject *mokvar_kobj;
+
+/*
+ * efi_mokvar_table_init() - Early boot validation of EFI MOK config table
+ *
+ * If present, validate and compute the size of the EFI MOK variable
+ * configuration table. This table may be provided by an EFI boot loader
+ * as an alternative to ordinary EFI variables, due to platform-dependent
+ * limitations. The memory occupied by this table is marked as reserved.
+ *
+ * This routine must be called before efi_free_boot_services() in order
+ * to guarantee that it can mark the table as reserved.
+ *
+ * Implicit inputs:
+ * efi.mokvar_table:	Physical address of EFI MOK variable config table
+ *			or special value that indicates no such table.
+ *
+ * Implicit outputs:
+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
+ *			The table is considered present and valid if this
+ *			is non-zero.
+ */
+void __init efi_mokvar_table_init(void)
+{
+	efi_memory_desc_t md;
+	void *va = NULL;
+	unsigned long cur_offset = 0;
+	unsigned long offset_limit;
+	unsigned long map_size = 0;
+	unsigned long map_size_needed = 0;
+	unsigned long size;
+	struct efi_mokvar_table_entry *mokvar_entry;
+	int err;
+
+	if (!efi_enabled(EFI_MEMMAP))
+		return;
+
+	if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
+		return;
+	/*
+	 * The EFI MOK config table must fit within a single EFI memory
+	 * descriptor range.
+	 */
+	err = efi_mem_desc_lookup(efi.mokvar_table, &md);
+	if (err) {
+		pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
+		return;
+	}
+
+	offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
+
+	/*
+	 * Validate the MOK config table. Since there is no table header
+	 * from which we could get the total size of the MOK config table,
+	 * we compute the total size as we validate each variably sized
+	 * entry, remapping as necessary.
+	 */
+	err = -EINVAL;
+	while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
+		mokvar_entry = va + cur_offset;
+		map_size_needed = cur_offset + sizeof(*mokvar_entry);
+		if (map_size_needed > map_size) {
+			if (va)
+				early_memunmap(va, map_size);
+			/*
+			 * Map a little more than the fixed size entry
+			 * header, anticipating some data. It's safe to
+			 * do so as long as we stay within current memory
+			 * descriptor.
+			 */
+			map_size = min(map_size_needed + 2*EFI_PAGE_SIZE,
+				       offset_limit);
+			va = early_memremap(efi.mokvar_table, map_size);
+			if (!va) {
+				pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n",
+				       efi.mokvar_table, map_size);
+				return;
+			}
+			mokvar_entry = va + cur_offset;
+		}
+
+		/* Check for last sentinel entry */
+		if (mokvar_entry->name[0] == '\0') {
+			if (mokvar_entry->data_size != 0)
+				break;
+			err = 0;
+			break;
+		}
+
+		/* Sanity check that the name is null terminated */
+		size = strnlen(mokvar_entry->name,
+			       sizeof(mokvar_entry->name));
+		if (size >= sizeof(mokvar_entry->name))
+			break;
+
+		/* Advance to the next entry */
+		cur_offset = map_size_needed + mokvar_entry->data_size;
+	}
+
+	if (va)
+		early_memunmap(va, map_size);
+	if (err) {
+		pr_err("EFI MOKvar config table is not valid\n");
+		return;
+	}
+
+	if (md.type == EFI_BOOT_SERVICES_DATA)
+		efi_mem_reserve(efi.mokvar_table, map_size_needed);
+
+	efi_mokvar_table_size = map_size_needed;
+}
+
+/*
+ * efi_mokvar_entry_next() - Get next entry in the EFI MOK config table
+ *
+ * mokvar_entry:	Pointer to current EFI MOK config table entry
+ *			or null. Null indicates get first entry.
+ *			Passed by reference. This is updated to the
+ *			same value as the return value.
+ *
+ * Returns:		Pointer to next EFI MOK config table entry
+ *			or null, if there are no more entries.
+ *			Same value is returned in the mokvar_entry
+ *			parameter.
+ *
+ * This routine depends on the EFI MOK config table being entirely
+ * mapped with it's starting virtual address in efi_mokvar_table_va.
+ */
+struct efi_mokvar_table_entry *efi_mokvar_entry_next(
+			struct efi_mokvar_table_entry **mokvar_entry)
+{
+	struct efi_mokvar_table_entry *mokvar_cur;
+	struct efi_mokvar_table_entry *mokvar_next;
+	size_t size_cur;
+
+	mokvar_cur = *mokvar_entry;
+	*mokvar_entry = NULL;
+
+	if (efi_mokvar_table_va == NULL)
+		return NULL;
+
+	if (mokvar_cur == NULL) {
+		mokvar_next = efi_mokvar_table_va;
+	} else {
+		if (mokvar_cur->name[0] == '\0')
+			return NULL;
+		size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
+		mokvar_next = (void *)mokvar_cur + size_cur;
+	}
+
+	if (mokvar_next->name[0] == '\0')
+		return NULL;
+
+	*mokvar_entry = mokvar_next;
+	return mokvar_next;
+}
+
+/*
+ * efi_mokvar_entry_find() - Find EFI MOK config entry by name
+ *
+ * name:	Name of the entry to look for.
+ *
+ * Returns:	Pointer to EFI MOK config table entry if found;
+ *		null otherwise.
+ *
+ * This routine depends on the EFI MOK config table being entirely
+ * mapped with it's starting virtual address in efi_mokvar_table_va.
+ */
+struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
+{
+	struct efi_mokvar_table_entry *mokvar_entry = NULL;
+
+	while (efi_mokvar_entry_next(&mokvar_entry)) {
+		if (!strncmp(name, mokvar_entry->name,
+			     sizeof(mokvar_entry->name)))
+			return mokvar_entry;
+	}
+	return NULL;
+}
+
+/*
+ * efi_mokvar_sysfs_read() - sysfs binary file read routine
+ *
+ * Returns:	Count of bytes read.
+ *
+ * Copy EFI MOK config table entry data for this mokvar sysfs binary file
+ * to the supplied buffer, starting at the specified offset into mokvar table
+ * entry data, for the specified count bytes. The copy is limited by the
+ * amount of data in this mokvar config table entry.
+ */
+static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
+				 struct bin_attribute *bin_attr, char *buf,
+				 loff_t off, size_t count)
+{
+	struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return 0;
+
+	if (off >= mokvar_entry->data_size)
+		return 0;
+	if (count >  mokvar_entry->data_size - off)
+		count = mokvar_entry->data_size - off;
+
+	memcpy(buf, mokvar_entry->data + off, count);
+	return count;
+}
+
+/*
+ * efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs
+ *
+ * Map the EFI MOK variable config table for run-time use by the kernel
+ * and create the sysfs entries in /sys/firmware/efi/mok-variables/
+ *
+ * This routine just returns if a valid EFI MOK variable config table
+ * was not found earlier during boot.
+ *
+ * This routine must be called during a "middle" initcall phase, i.e.
+ * after efi_mokvar_table_init() but before UEFI certs are loaded
+ * during late init.
+ *
+ * Implicit inputs:
+ * efi.mokvar_table:	Physical address of EFI MOK variable config table
+ *			or special value that indicates no such table.
+ *
+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
+ *			The table is considered present and valid if this
+ *			is non-zero.
+ *
+ * Implicit outputs:
+ * efi_mokvar_table_va:	Start virtual address of the EFI MOK config table.
+ */
+static int __init efi_mokvar_sysfs_init(void)
+{
+	void *config_va;
+	struct efi_mokvar_table_entry *mokvar_entry = NULL;
+	struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
+	int err = 0;
+
+	if (efi_mokvar_table_size == 0)
+		return -ENOENT;
+
+	config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
+			     MEMREMAP_WB);
+	if (!config_va) {
+		pr_err("Failed to map EFI MOKvar config table\n");
+		return -ENOMEM;
+	}
+	efi_mokvar_table_va = config_va;
+
+	mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
+	if (!mokvar_kobj) {
+		pr_err("Failed to create EFI mok-variables sysfs entry\n");
+		return -ENOMEM;
+	}
+
+	while (efi_mokvar_entry_next(&mokvar_entry)) {
+		mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
+		if (!mokvar_sysfs) {
+			err = -ENOMEM;
+			break;
+		}
+
+		sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
+		mokvar_sysfs->bin_attr.private = mokvar_entry;
+		mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
+		mokvar_sysfs->bin_attr.attr.mode = 0400;
+		mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
+		mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
+
+		err = sysfs_create_bin_file(mokvar_kobj,
+					   &mokvar_sysfs->bin_attr);
+		if (err)
+			break;
+
+		list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
+	}
+
+	if (err) {
+		pr_err("Failed to create some EFI mok-variables sysfs entries\n");
+		kfree(mokvar_sysfs);
+	}
+	return err;
+}
+device_initcall(efi_mokvar_sysfs_init);
--- linux-ein-5.4.0.orig/drivers/firmware/efi/rci2-table.c
+++ linux-ein-5.4.0/drivers/firmware/efi/rci2-table.c
@@ -81,6 +81,9 @@
 	struct kobject *tables_kobj;
 	int ret = -ENOMEM;
 
+	if (rci2_table_phys == EFI_INVALID_TABLE_ADDR)
+		return 0;
+
 	rci2_base = memremap(rci2_table_phys,
 			     sizeof(struct rci2_table_global_hdr),
 			     MEMREMAP_WB);
--- linux-ein-5.4.0.orig/drivers/firmware/efi/runtime-wrappers.c
+++ linux-ein-5.4.0/drivers/firmware/efi/runtime-wrappers.c
@@ -62,6 +62,7 @@
 									\
 	if (!efi_enabled(EFI_RUNTIME_SERVICES)) {			\
 		pr_warn_once("EFI Runtime Services are disabled!\n");	\
+		efi_rts_work.status = EFI_DEVICE_ERROR;			\
 		goto exit;						\
 	}								\
 									\
@@ -414,7 +415,7 @@
 				  unsigned long data_size,
 				  efi_char16_t *data)
 {
-	if (down_interruptible(&efi_runtime_lock)) {
+	if (down_trylock(&efi_runtime_lock)) {
 		pr_warn("failed to invoke the reset_system() runtime service:\n"
 			"could not get exclusive access to the firmware\n");
 		return;
--- linux-ein-5.4.0.orig/drivers/firmware/efi/secureboot.c
+++ linux-ein-5.4.0/drivers/firmware/efi/secureboot.c
@@ -0,0 +1,38 @@
+/* Core kernel secure boot support.
+ *
+ * Copyright (C) 2017 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) KBUILD_MODNAME ": " fmt
+
+#include <linux/efi.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+
+/*
+ * Decide what to do when UEFI secure boot mode is enabled.
+ */
+void __init efi_set_secure_boot(enum efi_secureboot_mode mode)
+{
+	if (efi_enabled(EFI_BOOT)) {
+		switch (mode) {
+		case efi_secureboot_mode_disabled:
+			pr_info("Secure boot disabled\n");
+			break;
+		case efi_secureboot_mode_enabled:
+			set_bit(EFI_SECURE_BOOT, &efi.flags);
+			pr_info("Secure boot enabled\n");
+			break;
+		default:
+			pr_warning("Secure boot could not be determined (mode %u)\n",
+				   mode);
+			break;
+		}
+	}
+}
--- linux-ein-5.4.0.orig/drivers/firmware/efi/tpm.c
+++ linux-ein-5.4.0/drivers/firmware/efi/tpm.c
@@ -16,7 +16,7 @@
 int efi_tpm_final_log_size;
 EXPORT_SYMBOL(efi_tpm_final_log_size);
 
-static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
+static int __init tpm2_calc_event_log_size(void *data, int count, void *size_info)
 {
 	struct tcg_pcr_event2_head *header;
 	int event_size, size = 0;
@@ -62,8 +62,13 @@
 	tbl_size = sizeof(*log_tbl) + log_tbl->size;
 	memblock_reserve(efi.tpm_log, tbl_size);
 
-	if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
+	if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) {
+		pr_info("TPM Final Events table not present\n");
 		goto out;
+	} else if (log_tbl->version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
+		pr_warn(FW_BUG "TPM Final Events table invalid\n");
+		goto out;
+	}
 
 	final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
 
--- linux-ein-5.4.0.orig/drivers/firmware/efi/vars.c
+++ linux-ein-5.4.0/drivers/firmware/efi/vars.c
@@ -750,6 +750,7 @@
 {
 	const struct efivar_operations *ops;
 	efi_status_t status;
+	unsigned long varsize;
 
 	if (!__efivars)
 		return -EINVAL;
@@ -772,15 +773,17 @@
 		return efivar_entry_set_nonblocking(name, vendor, attributes,
 						    size, data);
 
+	varsize = size + ucs2_strsize(name, 1024);
 	if (!block) {
 		if (down_trylock(&efivars_lock))
 			return -EBUSY;
+		status = check_var_size_nonblocking(attributes, varsize);
 	} else {
 		if (down_interruptible(&efivars_lock))
 			return -EINTR;
+		status = check_var_size(attributes, varsize);
 	}
 
-	status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
 	if (status != EFI_SUCCESS) {
 		up(&efivars_lock);
 		return -ENOSPC;
--- linux-ein-5.4.0.orig/drivers/firmware/google/Kconfig
+++ linux-ein-5.4.0/drivers/firmware/google/Kconfig
@@ -3,9 +3,9 @@
 	bool "Google Firmware Drivers"
 	default n
 	help
-	  These firmware drivers are used by Google's servers.  They are
-	  only useful if you are working directly on one of their
-	  proprietary servers.  If in doubt, say "N".
+	  These firmware drivers are used by Google servers,
+	  Chromebooks and other devices using coreboot firmware.
+	  If in doubt, say "N".
 
 if GOOGLE_FIRMWARE
 
@@ -21,7 +21,7 @@
 
 config GOOGLE_COREBOOT_TABLE
 	tristate "Coreboot Table Access"
-	depends on ACPI || OF
+	depends on HAS_IOMEM && (ACPI || OF)
 	help
 	  This option enables the coreboot_table module, which provides other
 	  firmware modules access to the coreboot table. The coreboot table
--- linux-ein-5.4.0.orig/drivers/firmware/google/coreboot_table.c
+++ linux-ein-5.4.0/drivers/firmware/google/coreboot_table.c
@@ -152,20 +152,22 @@
 	if (!ptr)
 		return -ENOMEM;
 
-	ret = bus_register(&coreboot_bus_type);
-	if (!ret) {
-		ret = coreboot_table_populate(dev, ptr);
-		if (ret)
-			bus_unregister(&coreboot_bus_type);
-	}
+	ret = coreboot_table_populate(dev, ptr);
+
 	memunmap(ptr);
 
 	return ret;
 }
 
+static int __cb_dev_unregister(struct device *dev, void *dummy)
+{
+	device_unregister(dev);
+	return 0;
+}
+
 static int coreboot_table_remove(struct platform_device *pdev)
 {
-	bus_unregister(&coreboot_bus_type);
+	bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister);
 	return 0;
 }
 
@@ -195,6 +197,32 @@
 		.of_match_table = of_match_ptr(coreboot_of_match),
 	},
 };
-module_platform_driver(coreboot_table_driver);
+
+static int __init coreboot_table_driver_init(void)
+{
+	int ret;
+
+	ret = bus_register(&coreboot_bus_type);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&coreboot_table_driver);
+	if (ret) {
+		bus_unregister(&coreboot_bus_type);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit coreboot_table_driver_exit(void)
+{
+	platform_driver_unregister(&coreboot_table_driver);
+	bus_unregister(&coreboot_bus_type);
+}
+
+module_init(coreboot_table_driver_init);
+module_exit(coreboot_table_driver_exit);
+
 MODULE_AUTHOR("Google, Inc.");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/firmware/google/framebuffer-coreboot.c
+++ linux-ein-5.4.0/drivers/firmware/google/framebuffer-coreboot.c
@@ -43,9 +43,7 @@
 		    fb->green_mask_pos     == formats[i].green.offset &&
 		    fb->green_mask_size    == formats[i].green.length &&
 		    fb->blue_mask_pos      == formats[i].blue.offset &&
-		    fb->blue_mask_size     == formats[i].blue.length &&
-		    fb->reserved_mask_pos  == formats[i].transp.offset &&
-		    fb->reserved_mask_size == formats[i].transp.length)
+		    fb->blue_mask_size     == formats[i].blue.length)
 			pdata.format = formats[i].name;
 	}
 	if (!pdata.format)
--- linux-ein-5.4.0.orig/drivers/firmware/google/gsmi.c
+++ linux-ein-5.4.0/drivers/firmware/google/gsmi.c
@@ -359,9 +359,10 @@
 		memcpy(data, gsmi_dev.data_buf->start, *data_size);
 
 		/* All variables are have the following attributes */
-		*attr = EFI_VARIABLE_NON_VOLATILE |
-			EFI_VARIABLE_BOOTSERVICE_ACCESS |
-			EFI_VARIABLE_RUNTIME_ACCESS;
+		if (attr)
+			*attr = EFI_VARIABLE_NON_VOLATILE |
+				EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				EFI_VARIABLE_RUNTIME_ACCESS;
 	}
 
 	spin_unlock_irqrestore(&gsmi_dev.lock, flags);
@@ -679,6 +680,15 @@
 static int gsmi_panic_callback(struct notifier_block *nb,
 			       unsigned long reason, void *arg)
 {
+
+	/*
+	 * Panic callbacks are executed with all other CPUs stopped,
+	 * so we must not attempt to spin waiting for gsmi_dev.lock
+	 * to be released.
+	 */
+	if (spin_is_locked(&gsmi_dev.lock))
+		return NOTIFY_DONE;
+
 	gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC);
 	return NOTIFY_DONE;
 }
--- linux-ein-5.4.0.orig/drivers/firmware/imx/Kconfig
+++ linux-ein-5.4.0/drivers/firmware/imx/Kconfig
@@ -13,6 +13,7 @@
 config IMX_SCU
 	bool "IMX SCU Protocol driver"
 	depends on IMX_MBOX
+	select SOC_BUS
 	help
 	  The System Controller Firmware (SCFW) is a low-level system function
 	  which runs on a dedicated Cortex-M core to provide power, clock, and
--- linux-ein-5.4.0.orig/drivers/firmware/imx/imx-dsp.c
+++ linux-ein-5.4.0/drivers/firmware/imx/imx-dsp.c
@@ -114,7 +114,7 @@
 
 	dev_info(dev, "NXP i.MX DSP IPC initialized\n");
 
-	return devm_of_platform_populate(dev);
+	return 0;
 out:
 	kfree(chan_name);
 	for (j = 0; j < i; j++) {
--- linux-ein-5.4.0.orig/drivers/firmware/imx/imx-scu.c
+++ linux-ein-5.4.0/drivers/firmware/imx/imx-scu.c
@@ -8,7 +8,6 @@
  */
 
 #include <linux/err.h>
-#include <linux/firmware/imx/types.h>
 #include <linux/firmware/imx/ipc.h>
 #include <linux/firmware/imx/sci.h>
 #include <linux/interrupt.h>
@@ -29,6 +28,7 @@
 	struct mbox_client cl;
 	struct mbox_chan *ch;
 	int idx;
+	struct completion tx_done;
 };
 
 struct imx_sc_ipc {
@@ -37,6 +37,7 @@
 	struct device *dev;
 	struct mutex lock;
 	struct completion done;
+	bool fast_ipc;
 
 	/* temporarily store the SCU msg */
 	u32 *msg;
@@ -100,12 +101,40 @@
 }
 EXPORT_SYMBOL(imx_scu_get_handle);
 
+/* Callback called when the word of a message is ack-ed, eg read by SCU */
+static void imx_scu_tx_done(struct mbox_client *cl, void *mssg, int r)
+{
+	struct imx_sc_chan *sc_chan = container_of(cl, struct imx_sc_chan, cl);
+
+	complete(&sc_chan->tx_done);
+}
+
 static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
 {
 	struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl);
 	struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc;
 	struct imx_sc_rpc_msg *hdr;
 	u32 *data = msg;
+	int i;
+
+	if (!sc_ipc->msg) {
+		dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n",
+				sc_chan->idx, *data);
+		return;
+	}
+
+	if (sc_ipc->fast_ipc) {
+		hdr = msg;
+		sc_ipc->rx_size = hdr->size;
+		sc_ipc->msg[0] = *data++;
+
+		for (i = 1; i < sc_ipc->rx_size; i++)
+			sc_ipc->msg[i] = *data++;
+
+		complete(&sc_ipc->done);
+
+		return;
+	}
 
 	if (sc_chan->idx == 0) {
 		hdr = msg;
@@ -128,21 +157,38 @@
 
 static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
 {
-	struct imx_sc_rpc_msg *hdr = msg;
+	struct imx_sc_rpc_msg hdr = *(struct imx_sc_rpc_msg *)msg;
 	struct imx_sc_chan *sc_chan;
 	u32 *data = msg;
 	int ret;
+	int size;
 	int i;
 
 	/* Check size */
-	if (hdr->size > IMX_SC_RPC_MAX_MSG)
+	if (hdr.size > IMX_SC_RPC_MAX_MSG)
 		return -EINVAL;
 
-	dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc,
-		hdr->func, hdr->size);
+	dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr.svc,
+		hdr.func, hdr.size);
 
-	for (i = 0; i < hdr->size; i++) {
+	size = sc_ipc->fast_ipc ? 1 : hdr.size;
+	for (i = 0; i < size; i++) {
 		sc_chan = &sc_ipc->chans[i % 4];
+
+		/*
+		 * SCU requires that all messages words are written
+		 * sequentially but linux MU driver implements multiple
+		 * independent channels for each register so ordering between
+		 * different channels must be ensured by SCU API interface.
+		 *
+		 * Wait for tx_done before every send to ensure that no
+		 * queueing happens at the mailbox channel level.
+		 */
+		if (!sc_ipc->fast_ipc) {
+			wait_for_completion(&sc_chan->tx_done);
+			reinit_completion(&sc_chan->tx_done);
+		}
+
 		ret = mbox_send_message(sc_chan->ch, &data[i]);
 		if (ret < 0)
 			return ret;
@@ -165,7 +211,8 @@
 	mutex_lock(&sc_ipc->lock);
 	reinit_completion(&sc_ipc->done);
 
-	sc_ipc->msg = msg;
+	if (have_resp)
+		sc_ipc->msg = msg;
 	sc_ipc->count = 0;
 	ret = imx_scu_ipc_write(sc_ipc, msg);
 	if (ret < 0) {
@@ -187,6 +234,7 @@
 	}
 
 out:
+	sc_ipc->msg = NULL;
 	mutex_unlock(&sc_ipc->lock);
 
 	dev_dbg(sc_ipc->dev, "RPC SVC done\n");
@@ -202,6 +250,8 @@
 	struct imx_sc_chan *sc_chan;
 	struct mbox_client *cl;
 	char *chan_name;
+	struct of_phandle_args args;
+	int num_channel;
 	int ret;
 	int i;
 
@@ -209,11 +259,20 @@
 	if (!sc_ipc)
 		return -ENOMEM;
 
-	for (i = 0; i < SCU_MU_CHAN_NUM; i++) {
-		if (i < 4)
+	ret = of_parse_phandle_with_args(pdev->dev.of_node, "mboxes",
+					 "#mbox-cells", 0, &args);
+	if (ret)
+		return ret;
+
+	sc_ipc->fast_ipc = of_device_is_compatible(args.np, "fsl,imx8-mu-scu");
+
+	num_channel = sc_ipc->fast_ipc ? 2 : SCU_MU_CHAN_NUM;
+	for (i = 0; i < num_channel; i++) {
+		if (i < num_channel / 2)
 			chan_name = kasprintf(GFP_KERNEL, "tx%d", i);
 		else
-			chan_name = kasprintf(GFP_KERNEL, "rx%d", i - 4);
+			chan_name = kasprintf(GFP_KERNEL, "rx%d",
+					      i - num_channel / 2);
 
 		if (!chan_name)
 			return -ENOMEM;
@@ -225,14 +284,22 @@
 		cl->knows_txdone = true;
 		cl->rx_callback = imx_scu_rx_callback;
 
+		if (!sc_ipc->fast_ipc) {
+			/* Initial tx_done completion as "done" */
+			cl->tx_done = imx_scu_tx_done;
+			init_completion(&sc_chan->tx_done);
+			complete(&sc_chan->tx_done);
+		}
+
 		sc_chan->sc_ipc = sc_ipc;
-		sc_chan->idx = i % 4;
+		sc_chan->idx = i % (num_channel / 2);
 		sc_chan->ch = mbox_request_channel_byname(cl, chan_name);
 		if (IS_ERR(sc_chan->ch)) {
 			ret = PTR_ERR(sc_chan->ch);
 			if (ret != -EPROBE_DEFER)
 				dev_err(dev, "Failed to request mbox chan %s ret %d\n",
 					chan_name, ret);
+			kfree(chan_name);
 			return ret;
 		}
 
--- linux-ein-5.4.0.orig/drivers/firmware/imx/misc.c
+++ linux-ein-5.4.0/drivers/firmware/imx/misc.c
@@ -16,7 +16,7 @@
 	u32 ctrl;
 	u32 val;
 	u16 resource;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_req_cpu_start {
 	struct imx_sc_rpc_msg hdr;
@@ -24,18 +24,18 @@
 	u32 address_lo;
 	u16 resource;
 	u8 enable;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_req_misc_get_ctrl {
 	struct imx_sc_rpc_msg hdr;
 	u32 ctrl;
 	u16 resource;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_resp_misc_get_ctrl {
 	struct imx_sc_rpc_msg hdr;
 	u32 val;
-} __packed;
+} __packed __aligned(4);
 
 /*
  * This function sets a miscellaneous control value.
--- linux-ein-5.4.0.orig/drivers/firmware/imx/scu-pd.c
+++ linux-ein-5.4.0/drivers/firmware/imx/scu-pd.c
@@ -61,7 +61,7 @@
 	struct imx_sc_rpc_msg hdr;
 	u16 resource;
 	u8 mode;
-} __packed;
+} __packed __aligned(4);
 
 #define IMX_SCU_PD_NAME_SIZE 20
 struct imx_sc_pm_domain {
--- linux-ein-5.4.0.orig/drivers/firmware/psci/psci.c
+++ linux-ein-5.4.0/drivers/firmware/psci/psci.c
@@ -57,6 +57,21 @@
 	.smccc_version = SMCCC_VERSION_1_0,
 };
 
+enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
+{
+	if (psci_ops.smccc_version < SMCCC_VERSION_1_1)
+		return SMCCC_CONDUIT_NONE;
+
+	switch (psci_ops.conduit) {
+	case PSCI_CONDUIT_SMC:
+		return SMCCC_CONDUIT_SMC;
+	case PSCI_CONDUIT_HVC:
+		return SMCCC_CONDUIT_HVC;
+	default:
+		return SMCCC_CONDUIT_NONE;
+	}
+}
+
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
 static psci_fn *invoke_psci_fn;
--- linux-ein-5.4.0.orig/drivers/firmware/psci/psci_checker.c
+++ linux-ein-5.4.0/drivers/firmware/psci/psci_checker.c
@@ -155,10 +155,12 @@
 	if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
 		return -ENOMEM;
 
-	cpu_groups = kcalloc(nb_available_cpus, sizeof(cpu_groups),
+	cpu_groups = kcalloc(nb_available_cpus, sizeof(*cpu_groups),
 			     GFP_KERNEL);
-	if (!cpu_groups)
+	if (!cpu_groups) {
+		free_cpumask_var(tmp);
 		return -ENOMEM;
+	}
 
 	cpumask_copy(tmp, cpu_online_mask);
 
@@ -167,6 +169,7 @@
 			topology_core_cpumask(cpumask_any(tmp));
 
 		if (!alloc_cpumask_var(&cpu_groups[num_groups], GFP_KERNEL)) {
+			free_cpumask_var(tmp);
 			free_cpu_groups(num_groups, &cpu_groups);
 			return -ENOMEM;
 		}
--- linux-ein-5.4.0.orig/drivers/firmware/qcom_scm-64.c
+++ linux-ein-5.4.0/drivers/firmware/qcom_scm-64.c
@@ -150,7 +150,7 @@
 		kfree(args_virt);
 	}
 
-	if (res->a0 < 0)
+	if ((long)res->a0 < 0)
 		return qcom_scm_remap_error(res->a0);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/firmware/qcom_scm.c
+++ linux-ein-5.4.0/drivers/firmware/qcom_scm.c
@@ -9,7 +9,6 @@
 #include <linux/init.h>
 #include <linux/cpumask.h>
 #include <linux/export.h>
-#include <linux/dma-direct.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -441,8 +440,7 @@
 	struct qcom_scm_mem_map_info *mem_to_map;
 	phys_addr_t mem_to_map_phys;
 	phys_addr_t dest_phys;
-	phys_addr_t ptr_phys;
-	dma_addr_t ptr_dma;
+	dma_addr_t ptr_phys;
 	size_t mem_to_map_sz;
 	size_t dest_sz;
 	size_t src_sz;
@@ -459,10 +457,9 @@
 	ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
 			ALIGN(dest_sz, SZ_64);
 
-	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_dma, GFP_KERNEL);
+	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
 	if (!ptr)
 		return -ENOMEM;
-	ptr_phys = dma_to_phys(__scm->dev, ptr_dma);
 
 	/* Fill source vmid detail */
 	src = ptr;
@@ -490,7 +487,7 @@
 
 	ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
 				    ptr_phys, src_sz, dest_phys, dest_sz);
-	dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_dma);
+	dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_phys);
 	if (ret) {
 		dev_err(__scm->dev,
 			"Assign memory protection call failed %d\n", ret);
@@ -588,8 +585,7 @@
 static void qcom_scm_shutdown(struct platform_device *pdev)
 {
 	/* Clean shutdown, disable download mode to allow normal restart */
-	if (download_mode)
-		qcom_scm_set_download_mode(false);
+	qcom_scm_set_download_mode(false);
 }
 
 static const struct of_device_id qcom_scm_dt_match[] = {
--- linux-ein-5.4.0.orig/drivers/firmware/qemu_fw_cfg.c
+++ linux-ein-5.4.0/drivers/firmware/qemu_fw_cfg.c
@@ -296,15 +296,13 @@
 	return 0;
 }
 
-static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
+static ssize_t fw_cfg_showrev(struct kobject *k, struct kobj_attribute *a,
+			      char *buf)
 {
 	return sprintf(buf, "%u\n", fw_cfg_rev);
 }
 
-static const struct {
-	struct attribute attr;
-	ssize_t (*show)(struct kobject *k, struct attribute *a, char *buf);
-} fw_cfg_rev_attr = {
+static const struct kobj_attribute fw_cfg_rev_attr = {
 	.attr = { .name = "rev", .mode = S_IRUSR },
 	.show = fw_cfg_showrev,
 };
@@ -387,9 +385,7 @@
 	struct fw_cfg_sysfs_entry *entry, *next;
 
 	list_for_each_entry_safe(entry, next, &fw_cfg_entry_cache, list) {
-		/* will end up invoking fw_cfg_sysfs_cache_delist()
-		 * via each object's release() method (i.e. destructor)
-		 */
+		fw_cfg_sysfs_cache_delist(entry);
 		kobject_put(&entry->kobj);
 	}
 }
@@ -447,7 +443,6 @@
 {
 	struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-	fw_cfg_sysfs_cache_delist(entry);
 	kfree(entry);
 }
 
@@ -600,18 +595,18 @@
 	/* set file entry information */
 	entry->size = be32_to_cpu(f->size);
 	entry->select = be16_to_cpu(f->select);
-	memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
+	strscpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
 	/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
 	err = kobject_init_and_add(&entry->kobj, &fw_cfg_sysfs_entry_ktype,
 				   fw_cfg_sel_ko, "%d", entry->select);
 	if (err)
-		goto err_register;
+		goto err_put_entry;
 
 	/* add raw binary content access */
 	err = sysfs_create_bin_file(&entry->kobj, &fw_cfg_sysfs_attr_raw);
 	if (err)
-		goto err_add_raw;
+		goto err_del_entry;
 
 	/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
 	fw_cfg_build_symlink(fw_cfg_fname_kset, &entry->kobj, entry->name);
@@ -620,10 +615,10 @@
 	fw_cfg_sysfs_cache_enlist(entry);
 	return 0;
 
-err_add_raw:
+err_del_entry:
 	kobject_del(&entry->kobj);
-err_register:
-	kfree(entry);
+err_put_entry:
+	kobject_put(&entry->kobj);
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/firmware/raspberrypi.c
+++ linux-ein-5.4.0/drivers/firmware/raspberrypi.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/dma-mapping.h>
+#include <linux/kref.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
@@ -27,6 +28,8 @@
 	struct mbox_chan *chan; /* The property channel. */
 	struct completion c;
 	u32 enabled;
+
+	struct kref consumers;
 };
 
 static DEFINE_MUTEX(transaction_lock);
@@ -214,12 +217,38 @@
 						-1, NULL, 0);
 }
 
+static void rpi_firmware_delete(struct kref *kref)
+{
+	struct rpi_firmware *fw = container_of(kref, struct rpi_firmware,
+					       consumers);
+
+	mbox_free_channel(fw->chan);
+	kfree(fw);
+}
+
+void rpi_firmware_put(struct rpi_firmware *fw)
+{
+	kref_put(&fw->consumers, rpi_firmware_delete);
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_put);
+
+static void devm_rpi_firmware_put(void *data)
+{
+	struct rpi_firmware *fw = data;
+
+	rpi_firmware_put(fw);
+}
+
 static int rpi_firmware_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rpi_firmware *fw;
 
-	fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
+	/*
+	 * Memory will be freed by rpi_firmware_delete() once all users have
+	 * released their firmware handles. Don't use devm_kzalloc() here.
+	 */
+	fw = kzalloc(sizeof(*fw), GFP_KERNEL);
 	if (!fw)
 		return -ENOMEM;
 
@@ -232,10 +261,12 @@
 		int ret = PTR_ERR(fw->chan);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get mbox channel: %d\n", ret);
+		kfree(fw);
 		return ret;
 	}
 
 	init_completion(&fw->c);
+	kref_init(&fw->consumers);
 
 	platform_set_drvdata(pdev, fw);
 
@@ -264,7 +295,8 @@
 	rpi_hwmon = NULL;
 	platform_device_unregister(rpi_clk);
 	rpi_clk = NULL;
-	mbox_free_channel(fw->chan);
+
+	rpi_firmware_put(fw);
 
 	return 0;
 }
@@ -273,19 +305,51 @@
  * rpi_firmware_get - Get pointer to rpi_firmware structure.
  * @firmware_node:    Pointer to the firmware Device Tree node.
  *
+ * The reference to rpi_firmware has to be released with rpi_firmware_put().
+ *
  * Returns NULL is the firmware device is not ready.
  */
 struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
 {
 	struct platform_device *pdev = of_find_device_by_node(firmware_node);
+	struct rpi_firmware *fw;
 
 	if (!pdev)
 		return NULL;
 
-	return platform_get_drvdata(pdev);
+	fw = platform_get_drvdata(pdev);
+	if (!fw)
+		return NULL;
+
+	if (!kref_get_unless_zero(&fw->consumers))
+		return NULL;
+
+	return fw;
 }
 EXPORT_SYMBOL_GPL(rpi_firmware_get);
 
+/**
+ * devm_rpi_firmware_get - Get pointer to rpi_firmware structure.
+ * @firmware_node:    Pointer to the firmware Device Tree node.
+ *
+ * Returns NULL is the firmware device is not ready.
+ */
+struct rpi_firmware *devm_rpi_firmware_get(struct device *dev,
+					   struct device_node *firmware_node)
+{
+	struct rpi_firmware *fw;
+
+	fw = rpi_firmware_get(firmware_node);
+	if (!fw)
+		return NULL;
+
+	if (devm_add_action_or_reset(dev, devm_rpi_firmware_put, fw))
+		return NULL;
+
+	return fw;
+}
+EXPORT_SYMBOL_GPL(devm_rpi_firmware_get);
+
 static const struct of_device_id rpi_firmware_of_match[] = {
 	{ .compatible = "raspberrypi,bcm2835-firmware", },
 	{},
--- linux-ein-5.4.0.orig/drivers/firmware/scpi_pm_domain.c
+++ linux-ein-5.4.0/drivers/firmware/scpi_pm_domain.c
@@ -16,7 +16,6 @@
 	struct generic_pm_domain genpd;
 	struct scpi_ops *ops;
 	u32 domain;
-	char name[30];
 };
 
 /*
@@ -110,8 +109,13 @@
 
 		scpi_pd->domain = i;
 		scpi_pd->ops = scpi_ops;
-		sprintf(scpi_pd->name, "%pOFn.%d", np, i);
-		scpi_pd->genpd.name = scpi_pd->name;
+		scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL,
+						     "%pOFn.%d", np, i);
+		if (!scpi_pd->genpd.name) {
+			dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n",
+				np, i);
+			continue;
+		}
 		scpi_pd->genpd.power_off = scpi_pd_power_off;
 		scpi_pd->genpd.power_on = scpi_pd_power_on;
 
--- linux-ein-5.4.0.orig/drivers/firmware/stratix10-svc.c
+++ linux-ein-5.4.0/drivers/firmware/stratix10-svc.c
@@ -615,8 +615,8 @@
 	end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE);
 	paddr = begin;
 	size = end - begin;
-	va = memremap(paddr, size, MEMREMAP_WC);
-	if (!va) {
+	va = devm_memremap(dev, paddr, size, MEMREMAP_WC);
+	if (IS_ERR(va)) {
 		dev_err(dev, "fail to remap shared memory\n");
 		return ERR_PTR(-EINVAL);
 	}
@@ -934,17 +934,17 @@
 void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
 {
 	struct stratix10_svc_data_mem *pmem;
-	size_t size = 0;
 
 	list_for_each_entry(pmem, &svc_data_mem, node)
 		if (pmem->vaddr == kaddr) {
-			size = pmem->size;
-			break;
+			gen_pool_free(chan->ctrl->genpool,
+				       (unsigned long)kaddr, pmem->size);
+			pmem->vaddr = NULL;
+			list_del(&pmem->node);
+			return;
 		}
 
-	gen_pool_free(chan->ctrl->genpool, (unsigned long)kaddr, size);
-	pmem->vaddr = NULL;
-	list_del(&pmem->node);
+	list_del(&svc_data_mem);
 }
 EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
 
@@ -981,8 +981,8 @@
 		return ret;
 
 	genpool = svc_create_memory_pool(pdev, sh_memory);
-	if (!genpool)
-		return -ENOMEM;
+	if (IS_ERR(genpool))
+		return PTR_ERR(genpool);
 
 	/* allocate service controller and supporting channel */
 	controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
@@ -1026,24 +1026,32 @@
 
 	/* add svc client device(s) */
 	svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
-	if (!svc)
-		return -ENOMEM;
+	if (!svc) {
+		ret = -ENOMEM;
+		goto err_free_kfifo;
+	}
 
 	svc->stratix10_svc_rsu = platform_device_alloc(STRATIX10_RSU, 0);
 	if (!svc->stratix10_svc_rsu) {
 		dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_free_kfifo;
 	}
 
 	ret = platform_device_add(svc->stratix10_svc_rsu);
-	if (ret) {
-		platform_device_put(svc->stratix10_svc_rsu);
-		return ret;
-	}
+	if (ret)
+		goto err_put_device;
+
 	dev_set_drvdata(dev, svc);
 
 	pr_info("Intel Service Layer Driver Initialized\n");
 
+	return 0;
+
+err_put_device:
+	platform_device_put(svc->stratix10_svc_rsu);
+err_free_kfifo:
+	kfifo_free(&controller->svc_fifo);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/firmware/tegra/Makefile
+++ linux-ein-5.4.0/drivers/firmware/tegra/Makefile
@@ -3,6 +3,7 @@
 tegra-bpmp-$(CONFIG_ARCH_TEGRA_210_SOC)	+= bpmp-tegra210.o
 tegra-bpmp-$(CONFIG_ARCH_TEGRA_186_SOC)	+= bpmp-tegra186.o
 tegra-bpmp-$(CONFIG_ARCH_TEGRA_194_SOC)	+= bpmp-tegra186.o
+tegra-bpmp-$(CONFIG_ARCH_TEGRA_234_SOC)	+= bpmp-tegra186.o
 tegra-bpmp-$(CONFIG_DEBUG_FS)	+= bpmp-debugfs.o
 obj-$(CONFIG_TEGRA_BPMP)	+= tegra-bpmp.o
 obj-$(CONFIG_TEGRA_IVC)		+= ivc.o
--- linux-ein-5.4.0.orig/drivers/firmware/tegra/bpmp-private.h
+++ linux-ein-5.4.0/drivers/firmware/tegra/bpmp-private.h
@@ -24,7 +24,8 @@
 };
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
-    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
 extern const struct tegra_bpmp_ops tegra186_bpmp_ops;
 #endif
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
--- linux-ein-5.4.0.orig/drivers/firmware/tegra/bpmp-tegra210.c
+++ linux-ein-5.4.0/drivers/firmware/tegra/bpmp-tegra210.c
@@ -210,7 +210,7 @@
 	priv->tx_irq_data = irq_get_irq_data(err);
 	if (!priv->tx_irq_data) {
 		dev_err(&pdev->dev, "failed to get IRQ data for TX IRQ\n");
-		return err;
+		return -ENOENT;
 	}
 
 	err = platform_get_irq_byname(pdev, "rx");
--- linux-ein-5.4.0.orig/drivers/firmware/tegra/bpmp.c
+++ linux-ein-5.4.0/drivers/firmware/tegra/bpmp.c
@@ -808,7 +808,8 @@
 };
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
-    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
 static const struct tegra_bpmp_soc tegra186_soc = {
 	.channels = {
 		.cpu_tx = {
--- linux-ein-5.4.0.orig/drivers/firmware/ti_sci.c
+++ linux-ein-5.4.0/drivers/firmware/ti_sci.c
@@ -2,7 +2,7 @@
 /*
  * Texas Instruments System Control Interface Protocol Driver
  *
- * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
  *	Nishanth Menon
  */
 
@@ -179,7 +179,7 @@
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
-	char debug_name[50] = "ti_sci_debug@";
+	char debug_name[50];
 
 	/* Debug region is optional */
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -196,10 +196,10 @@
 	/* Setup NULL termination */
 	info->debug_buffer[info->debug_region_size] = 0;
 
-	info->d = debugfs_create_file(strncat(debug_name, dev_name(dev),
-					      sizeof(debug_name) -
-					      sizeof("ti_sci_debug@")),
-				      0444, NULL, info, &ti_sci_debug_fops);
+	snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s",
+		 dev_name(dev));
+	info->d = debugfs_create_file(debug_name, 0444, NULL, info,
+				      &ti_sci_debug_fops);
 	if (IS_ERR(info->d))
 		return PTR_ERR(info->d);
 
@@ -208,19 +208,6 @@
 	return 0;
 }
 
-/**
- * ti_sci_debugfs_destroy() - clean up log debug file
- * @pdev:	platform device pointer
- * @info:	Pointer to SCI entity information
- */
-static void ti_sci_debugfs_destroy(struct platform_device *pdev,
-				   struct ti_sci_info *info)
-{
-	if (IS_ERR(info->debug_region))
-		return;
-
-	debugfs_remove(info->d);
-}
 #else /* CONFIG_DEBUG_FS */
 static inline int ti_sci_debugfs_create(struct platform_device *dev,
 					struct ti_sci_info *info)
@@ -3527,43 +3514,12 @@
 	return ret;
 }
 
-static int ti_sci_remove(struct platform_device *pdev)
-{
-	struct ti_sci_info *info;
-	struct device *dev = &pdev->dev;
-	int ret = 0;
-
-	of_platform_depopulate(dev);
-
-	info = platform_get_drvdata(pdev);
-
-	if (info->nb.notifier_call)
-		unregister_restart_handler(&info->nb);
-
-	mutex_lock(&ti_sci_list_mutex);
-	if (info->users)
-		ret = -EBUSY;
-	else
-		list_del(&info->node);
-	mutex_unlock(&ti_sci_list_mutex);
-
-	if (!ret) {
-		ti_sci_debugfs_destroy(pdev, info);
-
-		/* Safe to free channels since no more users */
-		mbox_free_channel(info->chan_tx);
-		mbox_free_channel(info->chan_rx);
-	}
-
-	return ret;
-}
-
 static struct platform_driver ti_sci_driver = {
 	.probe = ti_sci_probe,
-	.remove = ti_sci_remove,
 	.driver = {
 		   .name = "ti-sci",
 		   .of_match_table = of_match_ptr(ti_sci_of_match),
+		   .suppress_bind_attrs = true,
 	},
 };
 module_platform_driver(ti_sci_driver);
--- linux-ein-5.4.0.orig/drivers/firmware/ti_sci.h
+++ linux-ein-5.4.0/drivers/firmware/ti_sci.h
@@ -6,7 +6,7 @@
  * The system works in a message response protocol
  * See: http://processors.wiki.ti.com/index.php/TISCI for details
  *
- * Copyright (C)  2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C)  2015-2016 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #ifndef __TI_SCI_H
--- linux-ein-5.4.0.orig/drivers/firmware/turris-mox-rwtm.c
+++ linux-ein-5.4.0/drivers/firmware/turris-mox-rwtm.c
@@ -134,11 +134,14 @@
 
 static int mox_get_status(enum mbox_cmd cmd, u32 retval)
 {
-	if (MBOX_STS_CMD(retval) != cmd ||
-	    MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
+	if (MBOX_STS_CMD(retval) != cmd)
 		return -EIO;
 	else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL)
 		return -(int)MBOX_STS_VALUE(retval);
+	else if (MBOX_STS_ERROR(retval) == MBOX_STS_BADCMD)
+		return -ENOSYS;
+	else if (MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
+		return -EIO;
 	else
 		return MBOX_STS_VALUE(retval);
 }
@@ -188,11 +191,14 @@
 		return ret;
 
 	ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval);
-	if (ret < 0 && ret != -ENODATA) {
-		return ret;
-	} else if (ret == -ENODATA) {
+	if (ret == -ENODATA) {
 		dev_warn(rwtm->dev,
 			 "Board does not have manufacturing information burned!\n");
+	} else if (ret == -ENOSYS) {
+		dev_notice(rwtm->dev,
+			   "Firmware does not support the BOARD_INFO command\n");
+	} else if (ret < 0) {
+		return ret;
 	} else {
 		rwtm->serial_number = reply->status[1];
 		rwtm->serial_number <<= 32;
@@ -221,10 +227,13 @@
 		return ret;
 
 	ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval);
-	if (ret < 0 && ret != -ENODATA) {
-		return ret;
-	} else if (ret == -ENODATA) {
+	if (ret == -ENODATA) {
 		dev_warn(rwtm->dev, "Board has no public key burned!\n");
+	} else if (ret == -ENOSYS) {
+		dev_notice(rwtm->dev,
+			   "Firmware does not support the ECDSA_PUB_KEY command\n");
+	} else if (ret < 0) {
+		return ret;
 	} else {
 		u32 *s = reply->status;
 
@@ -238,6 +247,27 @@
 	return 0;
 }
 
+static int check_get_random_support(struct mox_rwtm *rwtm)
+{
+	struct armada_37xx_rwtm_tx_msg msg;
+	int ret;
+
+	msg.command = MBOX_CMD_GET_RANDOM;
+	msg.args[0] = 1;
+	msg.args[1] = rwtm->buf_phys;
+	msg.args[2] = 4;
+
+	ret = mbox_send_message(rwtm->mbox, &msg);
+	if (ret < 0)
+		return ret;
+
+	ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
+	if (ret < 0)
+		return ret;
+
+	return mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval);
+}
+
 static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 {
 	struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv;
@@ -329,6 +359,13 @@
 	if (ret < 0)
 		dev_warn(dev, "Cannot read board information: %i\n", ret);
 
+	ret = check_get_random_support(rwtm);
+	if (ret < 0) {
+		dev_notice(dev,
+			   "Firmware does not support the GET_RANDOM command\n");
+		goto free_channel;
+	}
+
 	rwtm->hwrng.name = DRIVER_NAME "_hwrng";
 	rwtm->hwrng.read = mox_hwrng_read;
 	rwtm->hwrng.priv = (unsigned long) rwtm;
@@ -364,6 +401,7 @@
 
 static const struct of_device_id turris_mox_rwtm_match[] = {
 	{ .compatible = "cznic,turris-mox-rwtm", },
+	{ .compatible = "marvell,armada-3700-rwtm-firmware", },
 	{ },
 };
 
--- linux-ein-5.4.0.orig/drivers/fpga/altera-pr-ip-core.c
+++ linux-ein-5.4.0/drivers/fpga/altera-pr-ip-core.c
@@ -108,7 +108,7 @@
 	u32 *buffer_32 = (u32 *)buf;
 	size_t i = 0;
 
-	if (count <= 0)
+	if (!count)
 		return -EINVAL;
 
 	/* Write out the complete 32-bit chunks */
--- linux-ein-5.4.0.orig/drivers/fpga/dfl-afu-dma-region.c
+++ linux-ein-5.4.0/drivers/fpga/dfl-afu-dma-region.c
@@ -61,10 +61,10 @@
 				     region->pages);
 	if (pinned < 0) {
 		ret = pinned;
-		goto put_pages;
+		goto free_pages;
 	} else if (pinned != npages) {
 		ret = -EFAULT;
-		goto free_pages;
+		goto put_pages;
 	}
 
 	dev_dbg(dev, "%d pages pinned\n", pinned);
--- linux-ein-5.4.0.orig/drivers/fpga/dfl-afu-main.c
+++ linux-ein-5.4.0/drivers/fpga/dfl-afu-main.c
@@ -83,7 +83,8 @@
 	 * on this port and minimum soft reset pulse width has elapsed.
 	 * Driver polls port_soft_reset_ack to determine if reset done by HW.
 	 */
-	if (readq_poll_timeout(base + PORT_HDR_CTRL, v, v & PORT_CTRL_SFTRST,
+	if (readq_poll_timeout(base + PORT_HDR_CTRL, v,
+			       v & PORT_CTRL_SFTRST_ACK,
 			       RST_POLL_INVL, RST_POLL_TIMEOUT)) {
 		dev_err(&pdev->dev, "timeout, fail to reset device\n");
 		return -ETIMEDOUT;
--- linux-ein-5.4.0.orig/drivers/fpga/dfl-pci.c
+++ linux-ein-5.4.0/drivers/fpga/dfl-pci.c
@@ -227,7 +227,6 @@
 {
 	struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
 	struct dfl_fpga_cdev *cdev = drvdata->cdev;
-	int ret = 0;
 
 	if (!num_vfs) {
 		/*
@@ -239,6 +238,8 @@
 		dfl_fpga_cdev_config_ports_pf(cdev);
 
 	} else {
+		int ret;
+
 		/*
 		 * before enable SRIOV, put released ports into VF access mode
 		 * first of all.
@@ -248,11 +249,13 @@
 			return ret;
 
 		ret = pci_enable_sriov(pcidev, num_vfs);
-		if (ret)
+		if (ret) {
 			dfl_fpga_cdev_config_ports_pf(cdev);
+			return ret;
+		}
 	}
 
-	return ret;
+	return num_vfs;
 }
 
 static void cci_pci_remove(struct pci_dev *pcidev)
--- linux-ein-5.4.0.orig/drivers/fpga/fpga-bridge.c
+++ linux-ein-5.4.0/drivers/fpga/fpga-bridge.c
@@ -115,7 +115,7 @@
 /**
  * fpga_bridge_get - get an exclusive reference to a fpga bridge
  * @dev:	parent device that fpga bridge was registered with
- * @info:	fpga manager info
+ * @info:	fpga image specific information
  *
  * Given a device, get an exclusive reference to a fpga bridge.
  *
--- linux-ein-5.4.0.orig/drivers/fpga/machxo2-spi.c
+++ linux-ein-5.4.0/drivers/fpga/machxo2-spi.c
@@ -223,8 +223,10 @@
 		goto fail;
 
 	get_status(spi, &status);
-	if (test_bit(FAIL, &status))
+	if (test_bit(FAIL, &status)) {
+		ret = -EINVAL;
 		goto fail;
+	}
 	dump_status_reg(&status);
 
 	spi_message_init(&msg);
@@ -310,6 +312,7 @@
 	dump_status_reg(&status);
 	if (!test_bit(DONE, &status)) {
 		machxo2_cleanup(mgr);
+		ret = -EINVAL;
 		goto fail;
 	}
 
@@ -331,6 +334,7 @@
 			break;
 		if (++refreshloop == MACHXO2_MAX_REFRESH_LOOP) {
 			machxo2_cleanup(mgr);
+			ret = -EINVAL;
 			goto fail;
 		}
 	} while (1);
--- linux-ein-5.4.0.orig/drivers/fpga/stratix10-soc.c
+++ linux-ein-5.4.0/drivers/fpga/stratix10-soc.c
@@ -218,9 +218,9 @@
 	/* Allocate buffers from the service layer's pool. */
 	for (i = 0; i < NUM_SVC_BUFS; i++) {
 		kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
-		if (!kbuf) {
+		if (IS_ERR(kbuf)) {
 			s10_free_buffers(mgr);
-			ret = -ENOMEM;
+			ret = PTR_ERR(kbuf);
 			goto init_done;
 		}
 
@@ -476,6 +476,7 @@
 	struct s10_priv *priv = mgr->priv;
 
 	fpga_mgr_unregister(mgr);
+	fpga_mgr_free(mgr);
 	stratix10_svc_free_channel(priv->chan);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/fsi/fsi-core.c
+++ linux-ein-5.4.0/drivers/fsi/fsi-core.c
@@ -544,6 +544,31 @@
 	return 0;
 }
 
+static unsigned long aligned_access_size(size_t offset, size_t count)
+{
+	unsigned long offset_unit, count_unit;
+
+	/* Criteria:
+	 *
+	 * 1. Access size must be less than or equal to the maximum access
+	 *    width or the highest power-of-two factor of offset
+	 * 2. Access size must be less than or equal to the amount specified by
+	 *    count
+	 *
+	 * The access width is optimal if we can calculate 1 to be strictly
+	 * equal while still satisfying 2.
+	 */
+
+	/* Find 1 by the bottom bit of offset (with a 4 byte access cap) */
+	offset_unit = BIT(__builtin_ctzl(offset | 4));
+
+	/* Find 2 by the top bit of count */
+	count_unit = BIT(8 * sizeof(unsigned long) - 1 - __builtin_clzl(count));
+
+	/* Constrain the maximum access width to the minimum of both criteria */
+	return BIT(__builtin_ctzl(offset_unit | count_unit));
+}
+
 static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count)
@@ -559,8 +584,7 @@
 		return -EINVAL;
 
 	for (total_len = 0; total_len < count; total_len += read_len) {
-		read_len = min_t(size_t, count, 4);
-		read_len -= off & 0x3;
+		read_len = aligned_access_size(off, count - total_len);
 
 		rc = fsi_slave_read(slave, off, buf + total_len, read_len);
 		if (rc)
@@ -587,8 +611,7 @@
 		return -EINVAL;
 
 	for (total_len = 0; total_len < count; total_len += write_len) {
-		write_len = min_t(size_t, count, 4);
-		write_len -= off & 0x3;
+		write_len = aligned_access_size(off, count - total_len);
 
 		rc = fsi_slave_write(slave, off, buf + total_len, write_len);
 		if (rc)
@@ -695,7 +718,7 @@
 	rc = count;
  fail:
 	*offset = off;
-	return count;
+	return rc;
 }
 
 static ssize_t cfam_write(struct file *filep, const char __user *buf,
@@ -732,7 +755,7 @@
 	rc = count;
  fail:
 	*offset = off;
-	return count;
+	return rc;
 }
 
 static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
@@ -1248,6 +1271,9 @@
 
 	mutex_init(&master->scan_lock);
 	master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
+	if (master->idx < 0)
+		return master->idx;
+
 	dev_set_name(&master->dev, "fsi%d", master->idx);
 
 	rc = device_register(&master->dev);
--- linux-ein-5.4.0.orig/drivers/fsi/fsi-master-ast-cf.c
+++ linux-ein-5.4.0/drivers/fsi/fsi-master-ast-cf.c
@@ -1438,3 +1438,4 @@
 
 module_platform_driver(fsi_master_acf);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FW_FILE_NAME);
--- linux-ein-5.4.0.orig/drivers/fsi/fsi-occ.c
+++ linux-ein-5.4.0/drivers/fsi/fsi-occ.c
@@ -445,6 +445,7 @@
 			goto done;
 
 		if (resp->return_status == OCC_RESP_CMD_IN_PRG ||
+		    resp->return_status == OCC_RESP_CRIT_INIT ||
 		    resp->seq_no != seq_no) {
 			rc = -ETIMEDOUT;
 
--- linux-ein-5.4.0.orig/drivers/fsi/fsi-sbefifo.c
+++ linux-ein-5.4.0/drivers/fsi/fsi-sbefifo.c
@@ -325,7 +325,8 @@
 static int sbefifo_request_reset(struct sbefifo *sbefifo)
 {
 	struct device *dev = &sbefifo->fsi_dev->dev;
-	u32 status, timeout;
+	unsigned long end_time;
+	u32 status;
 	int rc;
 
 	dev_dbg(dev, "Requesting FIFO reset\n");
@@ -341,7 +342,8 @@
 	}
 
 	/* Wait for it to complete */
-	for (timeout = 0; timeout < SBEFIFO_RESET_TIMEOUT; timeout++) {
+	end_time = jiffies + msecs_to_jiffies(SBEFIFO_RESET_TIMEOUT);
+	while (!time_after(jiffies, end_time)) {
 		rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &status);
 		if (rc) {
 			dev_err(dev, "Failed to read UP fifo status during reset"
@@ -355,7 +357,7 @@
 			return 0;
 		}
 
-		msleep(1);
+		cond_resched();
 	}
 	dev_err(dev, "FIFO reset timed out\n");
 
@@ -400,7 +402,7 @@
 	/* The FIFO already contains a reset request from the SBE ? */
 	if (down_status & SBEFIFO_STS_RESET_REQ) {
 		dev_info(dev, "Cleanup: FIFO reset request set, resetting\n");
-		rc = sbefifo_regw(sbefifo, SBEFIFO_UP, SBEFIFO_PERFORM_RESET);
+		rc = sbefifo_regw(sbefifo, SBEFIFO_DOWN, SBEFIFO_PERFORM_RESET);
 		if (rc) {
 			sbefifo->broken = true;
 			dev_err(dev, "Cleanup: Reset reg write failed, rc=%d\n", rc);
@@ -638,7 +640,7 @@
 	}
         ffdc_iov.iov_base = ffdc;
 	ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
-        iov_iter_kvec(&ffdc_iter, WRITE, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
+        iov_iter_kvec(&ffdc_iter, READ, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
 	cmd[0] = cpu_to_be32(2);
 	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
 	rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
@@ -735,7 +737,7 @@
 	rbytes = (*resp_len) * sizeof(__be32);
 	resp_iov.iov_base = response;
 	resp_iov.iov_len = rbytes;
-        iov_iter_kvec(&resp_iter, WRITE, &resp_iov, 1, rbytes);
+        iov_iter_kvec(&resp_iter, READ, &resp_iov, 1, rbytes);
 
 	/* Perform the command */
 	mutex_lock(&sbefifo->lock);
@@ -815,7 +817,7 @@
 	/* Prepare iov iterator */
 	resp_iov.iov_base = buf;
 	resp_iov.iov_len = len;
-	iov_iter_init(&resp_iter, WRITE, &resp_iov, 1, len);
+	iov_iter_init(&resp_iter, READ, &resp_iov, 1, len);
 
 	/* Perform the command */
 	mutex_lock(&sbefifo->lock);
--- linux-ein-5.4.0.orig/drivers/fsi/fsi-scom.c
+++ linux-ein-5.4.0/drivers/fsi/fsi-scom.c
@@ -38,9 +38,10 @@
 #define SCOM_STATUS_PIB_RESP_MASK	0x00007000
 #define SCOM_STATUS_PIB_RESP_SHIFT	12
 
-#define SCOM_STATUS_ANY_ERR		(SCOM_STATUS_PROTECTION | \
-					 SCOM_STATUS_PARITY |	  \
-					 SCOM_STATUS_PIB_ABORT | \
+#define SCOM_STATUS_FSI2PIB_ERROR	(SCOM_STATUS_PROTECTION |	\
+					 SCOM_STATUS_PARITY |		\
+					 SCOM_STATUS_PIB_ABORT)
+#define SCOM_STATUS_ANY_ERR		(SCOM_STATUS_FSI2PIB_ERROR |	\
 					 SCOM_STATUS_PIB_RESP_MASK)
 /* SCOM address encodings */
 #define XSCOM_ADDR_IND_FLAG		BIT_ULL(63)
@@ -240,13 +241,14 @@
 {
 	uint32_t dummy = -1;
 
-	if (status & SCOM_STATUS_PROTECTION)
-		return -EPERM;
-	if (status & SCOM_STATUS_PARITY) {
+	if (status & SCOM_STATUS_FSI2PIB_ERROR)
 		fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
 				 sizeof(uint32_t));
+
+	if (status & SCOM_STATUS_PROTECTION)
+		return -EPERM;
+	if (status & SCOM_STATUS_PARITY)
 		return -EIO;
-	}
 	/* Return -EBUSY on PIB abort to force a retry */
 	if (status & SCOM_STATUS_PIB_ABORT)
 		return -EBUSY;
--- linux-ein-5.4.0.orig/drivers/gnss/sirf.c
+++ linux-ein-5.4.0/drivers/gnss/sirf.c
@@ -439,14 +439,18 @@
 
 	data->on_off = devm_gpiod_get_optional(dev, "sirf,onoff",
 			GPIOD_OUT_LOW);
-	if (IS_ERR(data->on_off))
+	if (IS_ERR(data->on_off)) {
+		ret = PTR_ERR(data->on_off);
 		goto err_put_device;
+	}
 
 	if (data->on_off) {
 		data->wakeup = devm_gpiod_get_optional(dev, "sirf,wakeup",
 				GPIOD_IN);
-		if (IS_ERR(data->wakeup))
+		if (IS_ERR(data->wakeup)) {
+			ret = PTR_ERR(data->wakeup);
 			goto err_put_device;
+		}
 
 		ret = regulator_enable(data->vcc);
 		if (ret)
--- linux-ein-5.4.0.orig/drivers/gpio/Kconfig
+++ linux-ein-5.4.0/drivers/gpio/Kconfig
@@ -378,7 +378,7 @@
 	select REGMAP_MMIO
 
 config GPIO_MXC
-	def_bool y
+	tristate "i.MX GPIO support"
 	depends on ARCH_MXC
 	select GPIO_GENERIC
 	select GENERIC_IRQ_CHIP
@@ -546,7 +546,6 @@
 	tristate "Cavium ThunderX/OCTEON-TX GPIO"
 	depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
 	depends on PCI_MSI
-	select GPIOLIB_IRQCHIP
 	select IRQ_DOMAIN_HIERARCHY
 	select IRQ_FASTEOI_HIERARCHY_HANDLERS
 	help
@@ -1121,6 +1120,7 @@
 config GPIO_MAX77620
 	tristate "GPIO support for PMIC MAX77620 and MAX20024"
 	depends on MFD_MAX77620
+	select GPIOLIB_IRQCHIP
 	help
 	  GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor.
 	  MAX77620 PMIC has 8 pins that can be configured as GPIOs. The
@@ -1232,6 +1232,7 @@
 config GPIO_TQMX86
 	tristate "TQ-Systems QTMX86 GPIO"
 	depends on MFD_TQMX86 || COMPILE_TEST
+	depends on HAS_IOPORT_MAP
 	select GPIOLIB_IRQCHIP
 	help
 	  This driver supports GPIO on the TQMX86 IO controller.
@@ -1299,6 +1300,7 @@
 config GPIO_AMD8111
 	tristate "AMD 8111 GPIO driver"
 	depends on X86 || COMPILE_TEST
+	depends on HAS_IOPORT_MAP
 	help
 	  The AMD 8111 south bridge contains 32 GPIO pins which can be used.
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-74x164.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-74x164.c
@@ -128,8 +128,6 @@
 	if (IS_ERR(chip->gpiod_oe))
 		return PTR_ERR(chip->gpiod_oe);
 
-	gpiod_set_value_cansleep(chip->gpiod_oe, 1);
-
 	spi_set_drvdata(spi, chip);
 
 	chip->gpio_chip.label = spi->modalias;
@@ -154,6 +152,8 @@
 		goto exit_destroy;
 	}
 
+	gpiod_set_value_cansleep(chip->gpiod_oe, 1);
+
 	ret = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (!ret)
 		return 0;
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-amd8111.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-amd8111.c
@@ -231,7 +231,10 @@
 		ioport_unmap(gp.pm);
 		goto out;
 	}
+	return 0;
+
 out:
+	pci_dev_put(pdev);
 	return err;
 }
 
@@ -239,6 +242,7 @@
 {
 	gpiochip_remove(&gp.chip);
 	ioport_unmap(gp.pm);
+	pci_dev_put(gp.pdev);
 }
 
 module_init(amd_gpio_init);
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-arizona.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-arizona.c
@@ -64,6 +64,7 @@
 		ret = pm_runtime_get_sync(chip->parent);
 		if (ret < 0) {
 			dev_err(chip->parent, "Failed to resume: %d\n", ret);
+			pm_runtime_put_autosuspend(chip->parent);
 			return ret;
 		}
 
@@ -72,12 +73,15 @@
 		if (ret < 0) {
 			dev_err(chip->parent, "Failed to drop cache: %d\n",
 				ret);
+			pm_runtime_put_autosuspend(chip->parent);
 			return ret;
 		}
 
 		ret = regmap_read(arizona->regmap, reg, &val);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put_autosuspend(chip->parent);
 			return ret;
+		}
 
 		pm_runtime_mark_last_busy(chip->parent);
 		pm_runtime_put_autosuspend(chip->parent);
@@ -106,6 +110,7 @@
 		ret = pm_runtime_get_sync(chip->parent);
 		if (ret < 0) {
 			dev_err(chip->parent, "Failed to resume: %d\n", ret);
+			pm_runtime_put(chip->parent);
 			return ret;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-aspeed.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-aspeed.c
@@ -53,7 +53,7 @@
 struct aspeed_gpio {
 	struct gpio_chip chip;
 	struct irq_chip irqc;
-	spinlock_t lock;
+	raw_spinlock_t lock;
 	void __iomem *base;
 	int irq;
 	const struct aspeed_gpio_config *config;
@@ -413,14 +413,14 @@
 	unsigned long flags;
 	bool copro;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 	copro = aspeed_gpio_copro_request(gpio, offset);
 
 	__aspeed_gpio_set(gc, offset, val);
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 }
 
 static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
@@ -435,7 +435,7 @@
 	if (!have_input(gpio, offset))
 		return -ENOTSUPP;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	reg = ioread32(addr);
 	reg &= ~GPIO_BIT(offset);
@@ -445,7 +445,7 @@
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
 
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return 0;
 }
@@ -463,7 +463,7 @@
 	if (!have_output(gpio, offset))
 		return -ENOTSUPP;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	reg = ioread32(addr);
 	reg |= GPIO_BIT(offset);
@@ -474,7 +474,7 @@
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return 0;
 }
@@ -492,11 +492,11 @@
 	if (!have_output(gpio, offset))
 		return 1;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset);
 
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return !val;
 
@@ -540,14 +540,14 @@
 
 	status_addr = bank_reg(gpio, bank, reg_irq_status);
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 	copro = aspeed_gpio_copro_request(gpio, offset);
 
 	iowrite32(bit, status_addr);
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 }
 
 static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
@@ -566,7 +566,7 @@
 
 	addr = bank_reg(gpio, bank, reg_irq_enable);
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 	copro = aspeed_gpio_copro_request(gpio, offset);
 
 	reg = ioread32(addr);
@@ -578,7 +578,7 @@
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 }
 
 static void aspeed_gpio_irq_mask(struct irq_data *d)
@@ -630,7 +630,7 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 	copro = aspeed_gpio_copro_request(gpio, offset);
 
 	addr = bank_reg(gpio, bank, reg_irq_type0);
@@ -650,7 +650,7 @@
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	irq_set_handler_locked(d, handler);
 
@@ -720,7 +720,7 @@
 
 	treg = bank_reg(gpio, to_bank(offset), reg_tolerance);
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 	copro = aspeed_gpio_copro_request(gpio, offset);
 
 	val = readl(treg);
@@ -734,7 +734,7 @@
 
 	if (copro)
 		aspeed_gpio_copro_release(gpio, offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return 0;
 }
@@ -860,7 +860,7 @@
 		return rc;
 	}
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	if (timer_allocation_registered(gpio, offset)) {
 		rc = unregister_allocated_timer(gpio, offset);
@@ -920,7 +920,7 @@
 	configure_timer(gpio, offset, i);
 
 out:
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return rc;
 }
@@ -931,13 +931,13 @@
 	unsigned long flags;
 	int rc;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	rc = unregister_allocated_timer(gpio, offset);
 	if (!rc)
 		configure_timer(gpio, offset, 0);
 
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 
 	return rc;
 }
@@ -967,7 +967,7 @@
 	else if (param == PIN_CONFIG_BIAS_DISABLE ||
 			param == PIN_CONFIG_BIAS_PULL_DOWN ||
 			param == PIN_CONFIG_DRIVE_STRENGTH)
-		return pinctrl_gpio_set_config(offset, config);
+		return pinctrl_gpio_set_config(chip->base + offset, config);
 	else if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN ||
 			param == PIN_CONFIG_DRIVE_OPEN_SOURCE)
 		/* Return -ENOTSUPP to trigger emulation, as per datasheet */
@@ -1019,7 +1019,7 @@
 		return -EINVAL;
 	bindex = offset >> 3;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	/* Sanity check, this shouldn't happen */
 	if (gpio->cf_copro_bankmap[bindex] == 0xff) {
@@ -1040,7 +1040,7 @@
 	if (bit)
 		*bit = GPIO_OFFSET(offset);
  bail:
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio);
@@ -1064,7 +1064,7 @@
 		return -EINVAL;
 	bindex = offset >> 3;
 
-	spin_lock_irqsave(&gpio->lock, flags);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
 
 	/* Sanity check, this shouldn't happen */
 	if (gpio->cf_copro_bankmap[bindex] == 0) {
@@ -1078,7 +1078,7 @@
 		aspeed_gpio_change_cmd_source(gpio, bank, bindex,
 					      GPIO_CMDSRC_ARM);
  bail:
-	spin_unlock_irqrestore(&gpio->lock, flags);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio);
@@ -1115,8 +1115,8 @@
 
 static const struct aspeed_bank_props ast2600_bank_props[] = {
 	/*     input	  output   */
-	{5, 0xffffffff,  0x0000ffff}, /* U/V/W/X */
-	{6, 0xffff0000,  0x0fff0000}, /* Y/Z */
+	{5, 0xffffffff,  0xffffff00}, /* U/V/W/X */
+	{6, 0x0000ffff,  0x0000ffff}, /* Y/Z */
 	{ },
 };
 
@@ -1151,7 +1151,7 @@
 	if (IS_ERR(gpio->base))
 		return PTR_ERR(gpio->base);
 
-	spin_lock_init(&gpio->lock);
+	raw_spin_lock_init(&gpio->lock);
 
 	gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
 	if (!gpio_id)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-bcm-kona.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-bcm-kona.c
@@ -619,7 +619,7 @@
 
 	kona_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(kona_gpio->reg_base)) {
-		ret = -ENXIO;
+		ret = PTR_ERR(kona_gpio->reg_base);
 		goto err_irq_domain;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-cadence.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-cadence.c
@@ -278,6 +278,7 @@
 	{ .compatible = "cdns,gpio-r1p02" },
 	{ /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, cdns_of_ids);
 
 static struct platform_driver cdns_gpio_driver = {
 	.driver = {
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-davinci.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-davinci.c
@@ -333,7 +333,7 @@
 	.irq_enable	= gpio_irq_enable,
 	.irq_disable	= gpio_irq_disable,
 	.irq_set_type	= gpio_irq_type,
-	.flags		= IRQCHIP_SET_TYPE_MASKED,
+	.flags		= IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE,
 };
 
 static void gpio_irq_handler(struct irq_desc *desc)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-dwapb.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-dwapb.c
@@ -49,7 +49,9 @@
 #define GPIO_EXT_PORTC		0x58
 #define GPIO_EXT_PORTD		0x5c
 
+#define DWAPB_DRIVER_NAME	"gpio-dwapb"
 #define DWAPB_MAX_PORTS		4
+
 #define GPIO_EXT_PORT_STRIDE	0x04 /* register stride 32 bits */
 #define GPIO_SWPORT_DR_STRIDE	0x0c /* register stride 3*32 bits */
 #define GPIO_SWPORT_DDR_STRIDE	0x0c /* register stride 3*32 bits */
@@ -398,7 +400,7 @@
 		return;
 
 	err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
-					     "gpio-dwapb", handle_level_irq,
+					     DWAPB_DRIVER_NAME, handle_level_irq,
 					     IRQ_NOREQUEST, 0,
 					     IRQ_GC_INIT_NESTED_LOCK);
 	if (err) {
@@ -455,7 +457,7 @@
 		 */
 		err = devm_request_irq(gpio->dev, pp->irq[0],
 				       dwapb_irq_handler_mfd,
-				       IRQF_SHARED, "gpio-dwapb-mfd", gpio);
+				       IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
 		if (err) {
 			dev_err(gpio->dev, "error requesting IRQ\n");
 			irq_domain_remove(gpio->domain);
@@ -533,26 +535,33 @@
 		dwapb_configure_irqs(gpio, port, pp);
 
 	err = gpiochip_add_data(&port->gc, port);
-	if (err)
+	if (err) {
 		dev_err(gpio->dev, "failed to register gpiochip for port%d\n",
 			port->idx);
-	else
-		port->is_registered = true;
+		return err;
+	}
 
 	/* Add GPIO-signaled ACPI event support */
-	if (pp->has_irq)
-		acpi_gpiochip_request_interrupts(&port->gc);
+	acpi_gpiochip_request_interrupts(&port->gc);
 
-	return err;
+	port->is_registered = true;
+
+	return 0;
 }
 
 static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
 {
 	unsigned int m;
 
-	for (m = 0; m < gpio->nr_ports; ++m)
-		if (gpio->ports[m].is_registered)
-			gpiochip_remove(&gpio->ports[m].gc);
+	for (m = 0; m < gpio->nr_ports; ++m) {
+		struct dwapb_gpio_port *port = &gpio->ports[m];
+
+		if (!port->is_registered)
+			continue;
+
+		acpi_gpiochip_free_interrupts(&port->gc);
+		gpiochip_remove(&port->gc);
+	}
 }
 
 static struct dwapb_platform_data *
@@ -836,7 +845,7 @@
 
 static struct platform_driver dwapb_gpio_driver = {
 	.driver		= {
-		.name	= "gpio-dwapb",
+		.name	= DWAPB_DRIVER_NAME,
 		.pm	= &dwapb_gpio_pm_ops,
 		.of_match_table = of_match_ptr(dwapb_of_match),
 		.acpi_match_table = ACPI_PTR(dwapb_acpi_match),
@@ -850,3 +859,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jamie Iles");
 MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
+MODULE_ALIAS("platform:" DWAPB_DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-eic-sprd.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-eic-sprd.c
@@ -318,20 +318,27 @@
 		switch (flow_type) {
 		case IRQ_TYPE_LEVEL_HIGH:
 			sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
 			break;
 		case IRQ_TYPE_LEVEL_LOW:
 			sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
 			break;
 		case IRQ_TYPE_EDGE_RISING:
 		case IRQ_TYPE_EDGE_FALLING:
 		case IRQ_TYPE_EDGE_BOTH:
 			state = sprd_eic_get(chip, offset);
-			if (state)
+			if (state) {
 				sprd_eic_update(chip, offset,
 						SPRD_EIC_DBNC_IEV, 0);
-			else
+				sprd_eic_update(chip, offset,
+						SPRD_EIC_DBNC_IC, 1);
+			} else {
 				sprd_eic_update(chip, offset,
 						SPRD_EIC_DBNC_IEV, 1);
+				sprd_eic_update(chip, offset,
+						SPRD_EIC_DBNC_IC, 1);
+			}
 			break;
 		default:
 			return -ENOTSUPP;
@@ -343,20 +350,27 @@
 		switch (flow_type) {
 		case IRQ_TYPE_LEVEL_HIGH:
 			sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
 			break;
 		case IRQ_TYPE_LEVEL_LOW:
 			sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
 			break;
 		case IRQ_TYPE_EDGE_RISING:
 		case IRQ_TYPE_EDGE_FALLING:
 		case IRQ_TYPE_EDGE_BOTH:
 			state = sprd_eic_get(chip, offset);
-			if (state)
+			if (state) {
 				sprd_eic_update(chip, offset,
 						SPRD_EIC_LATCH_INTPOL, 0);
-			else
+				sprd_eic_update(chip, offset,
+						SPRD_EIC_LATCH_INTCLR, 1);
+			} else {
 				sprd_eic_update(chip, offset,
 						SPRD_EIC_LATCH_INTPOL, 1);
+				sprd_eic_update(chip, offset,
+						SPRD_EIC_LATCH_INTCLR, 1);
+			}
 			break;
 		default:
 			return -ENOTSUPP;
@@ -370,29 +384,34 @@
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_EDGE_FALLING:
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_EDGE_BOTH:
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_LEVEL_HIGH:
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_level_irq);
 			break;
 		case IRQ_TYPE_LEVEL_LOW:
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
 			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_level_irq);
 			break;
 		default:
@@ -405,29 +424,34 @@
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_EDGE_FALLING:
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_EDGE_BOTH:
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_edge_irq);
 			break;
 		case IRQ_TYPE_LEVEL_HIGH:
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
+			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_level_irq);
 			break;
 		case IRQ_TYPE_LEVEL_LOW:
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
 			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
+			sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
 			irq_set_handler_locked(data, handle_level_irq);
 			break;
 		default:
@@ -569,6 +593,7 @@
 	const struct sprd_eic_variant_data *pdata;
 	struct gpio_irq_chip *irq;
 	struct sprd_eic *sprd_eic;
+	struct resource *res;
 	int ret, i;
 
 	pdata = of_device_get_match_data(&pdev->dev);
@@ -595,9 +620,13 @@
 		 * have one bank EIC, thus base[1] and base[2] can be
 		 * optional.
 		 */
-		sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i);
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			break;
+
+		sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
 		if (IS_ERR(sprd_eic->base[i]))
-			continue;
+			return PTR_ERR(sprd_eic->base[i]);
 	}
 
 	sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-ep93xx.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-ep93xx.c
@@ -25,6 +25,9 @@
 /* Maximum value for gpio line identifiers */
 #define EP93XX_GPIO_LINE_MAX 63
 
+/* Number of GPIO chips in EP93XX */
+#define EP93XX_GPIO_CHIP_NUM 8
+
 /* Maximum value for irq capable line identifiers */
 #define EP93XX_GPIO_LINE_MAX_IRQ 23
 
@@ -34,74 +37,75 @@
  */
 #define EP93XX_GPIO_F_IRQ_BASE 80
 
+struct ep93xx_gpio_irq_chip {
+	struct irq_chip ic;
+	u8 irq_offset;
+	u8 int_unmasked;
+	u8 int_enabled;
+	u8 int_type1;
+	u8 int_type2;
+	u8 int_debounce;
+};
+
+struct ep93xx_gpio_chip {
+	struct gpio_chip		gc;
+	struct ep93xx_gpio_irq_chip	*eic;
+};
+
 struct ep93xx_gpio {
 	void __iomem		*base;
-	struct gpio_chip	gc[8];
+	struct ep93xx_gpio_chip	gc[EP93XX_GPIO_CHIP_NUM];
 };
 
-/*************************************************************************
- * Interrupt handling for EP93xx on-chip GPIOs
- *************************************************************************/
-static unsigned char gpio_int_unmasked[3];
-static unsigned char gpio_int_enabled[3];
-static unsigned char gpio_int_type1[3];
-static unsigned char gpio_int_type2[3];
-static unsigned char gpio_int_debounce[3];
-
-/* Port ordering is: A B F */
-static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c };
-static const u8 int_type2_register_offset[3]	= { 0x94, 0xb0, 0x50 };
-static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
-static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x58 };
-static const u8 int_debounce_register_offset[3]	= { 0xa8, 0xc4, 0x64 };
+#define to_ep93xx_gpio_chip(x) container_of(x, struct ep93xx_gpio_chip, gc)
 
-static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port)
+static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc)
 {
-	BUG_ON(port > 2);
-
-	writeb_relaxed(0, epg->base + int_en_register_offset[port]);
+	struct ep93xx_gpio_chip *egc = to_ep93xx_gpio_chip(gc);
 
-	writeb_relaxed(gpio_int_type2[port],
-		       epg->base + int_type2_register_offset[port]);
-
-	writeb_relaxed(gpio_int_type1[port],
-		       epg->base + int_type1_register_offset[port]);
-
-	writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
-	       epg->base + int_en_register_offset[port]);
+	return egc->eic;
 }
 
-static int ep93xx_gpio_port(struct gpio_chip *gc)
-{
-	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = 0;
+/*************************************************************************
+ * Interrupt handling for EP93xx on-chip GPIOs
+ *************************************************************************/
+#define EP93XX_INT_TYPE1_OFFSET		0x00
+#define EP93XX_INT_TYPE2_OFFSET		0x04
+#define EP93XX_INT_EOI_OFFSET		0x08
+#define EP93XX_INT_EN_OFFSET		0x0c
+#define EP93XX_INT_STATUS_OFFSET	0x10
+#define EP93XX_INT_RAW_STATUS_OFFSET	0x14
+#define EP93XX_INT_DEBOUNCE_OFFSET	0x18
+
+static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg,
+					  struct ep93xx_gpio_irq_chip *eic)
+{
+	writeb_relaxed(0, epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET);
 
-	while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port])
-		port++;
+	writeb_relaxed(eic->int_type2,
+		       epg->base + eic->irq_offset + EP93XX_INT_TYPE2_OFFSET);
 
-	/* This should not happen but is there as a last safeguard */
-	if (port == ARRAY_SIZE(epg->gc)) {
-		pr_crit("can't find the GPIO port\n");
-		return 0;
-	}
+	writeb_relaxed(eic->int_type1,
+		       epg->base + eic->irq_offset + EP93XX_INT_TYPE1_OFFSET);
 
-	return port;
+	writeb_relaxed(eic->int_unmasked & eic->int_enabled,
+		       epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET);
 }
 
 static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
 				     unsigned int offset, bool enable)
 {
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	int port_mask = BIT(offset);
 
 	if (enable)
-		gpio_int_debounce[port] |= port_mask;
+		eic->int_debounce |= port_mask;
 	else
-		gpio_int_debounce[port] &= ~port_mask;
+		eic->int_debounce &= ~port_mask;
 
-	writeb(gpio_int_debounce[port],
-	       epg->base + int_debounce_register_offset[port]);
+	writeb(eic->int_debounce,
+	       epg->base + eic->irq_offset + EP93XX_INT_DEBOUNCE_OFFSET);
 }
 
 static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
@@ -122,12 +126,12 @@
 	 */
 	stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
 	for_each_set_bit(offset, &stat, 8)
-		generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain,
+		generic_handle_irq(irq_find_mapping(epg->gc[0].gc.irq.domain,
 						    offset));
 
 	stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
 	for_each_set_bit(offset, &stat, 8)
-		generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain,
+		generic_handle_irq(irq_find_mapping(epg->gc[1].gc.irq.domain,
 						    offset));
 
 	chained_irq_exit(irqchip, desc);
@@ -153,52 +157,52 @@
 static void ep93xx_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
 	int port_mask = BIT(d->irq & 7);
 
 	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
-		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
-		ep93xx_gpio_update_int_params(epg, port);
+		eic->int_type2 ^= port_mask; /* switch edge direction */
+		ep93xx_gpio_update_int_params(epg, eic);
 	}
 
-	writeb(port_mask, epg->base + eoi_register_offset[port]);
+	writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET);
 }
 
 static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
 	int port_mask = BIT(d->irq & 7);
 
 	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
-		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
+		eic->int_type2 ^= port_mask; /* switch edge direction */
 
-	gpio_int_unmasked[port] &= ~port_mask;
-	ep93xx_gpio_update_int_params(epg, port);
+	eic->int_unmasked &= ~port_mask;
+	ep93xx_gpio_update_int_params(epg, eic);
 
-	writeb(port_mask, epg->base + eoi_register_offset[port]);
+	writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET);
 }
 
 static void ep93xx_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
 
-	gpio_int_unmasked[port] &= ~BIT(d->irq & 7);
-	ep93xx_gpio_update_int_params(epg, port);
+	eic->int_unmasked &= ~BIT(d->irq & 7);
+	ep93xx_gpio_update_int_params(epg, eic);
 }
 
 static void ep93xx_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
 
-	gpio_int_unmasked[port] |= BIT(d->irq & 7);
-	ep93xx_gpio_update_int_params(epg, port);
+	eic->int_unmasked |= BIT(d->irq & 7);
+	ep93xx_gpio_update_int_params(epg, eic);
 }
 
 /*
@@ -209,8 +213,8 @@
 static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
 	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
-	int port = ep93xx_gpio_port(gc);
 	int offset = d->irq & 7;
 	int port_mask = BIT(offset);
 	irq_flow_handler_t handler;
@@ -219,32 +223,32 @@
 
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
-		gpio_int_type1[port] |= port_mask;
-		gpio_int_type2[port] |= port_mask;
+		eic->int_type1 |= port_mask;
+		eic->int_type2 |= port_mask;
 		handler = handle_edge_irq;
 		break;
 	case IRQ_TYPE_EDGE_FALLING:
-		gpio_int_type1[port] |= port_mask;
-		gpio_int_type2[port] &= ~port_mask;
+		eic->int_type1 |= port_mask;
+		eic->int_type2 &= ~port_mask;
 		handler = handle_edge_irq;
 		break;
 	case IRQ_TYPE_LEVEL_HIGH:
-		gpio_int_type1[port] &= ~port_mask;
-		gpio_int_type2[port] |= port_mask;
+		eic->int_type1 &= ~port_mask;
+		eic->int_type2 |= port_mask;
 		handler = handle_level_irq;
 		break;
 	case IRQ_TYPE_LEVEL_LOW:
-		gpio_int_type1[port] &= ~port_mask;
-		gpio_int_type2[port] &= ~port_mask;
+		eic->int_type1 &= ~port_mask;
+		eic->int_type2 &= ~port_mask;
 		handler = handle_level_irq;
 		break;
 	case IRQ_TYPE_EDGE_BOTH:
-		gpio_int_type1[port] |= port_mask;
+		eic->int_type1 |= port_mask;
 		/* set initial polarity based on current input level */
 		if (gc->get(gc, offset))
-			gpio_int_type2[port] &= ~port_mask; /* falling */
+			eic->int_type2 &= ~port_mask; /* falling */
 		else
-			gpio_int_type2[port] |= port_mask; /* rising */
+			eic->int_type2 |= port_mask; /* rising */
 		handler = handle_edge_irq;
 		break;
 	default:
@@ -253,22 +257,13 @@
 
 	irq_set_handler_locked(d, handler);
 
-	gpio_int_enabled[port] |= port_mask;
+	eic->int_enabled |= port_mask;
 
-	ep93xx_gpio_update_int_params(epg, port);
+	ep93xx_gpio_update_int_params(epg, eic);
 
 	return 0;
 }
 
-static struct irq_chip ep93xx_gpio_irq_chip = {
-	.name		= "GPIO",
-	.irq_ack	= ep93xx_gpio_irq_ack,
-	.irq_mask_ack	= ep93xx_gpio_irq_mask_ack,
-	.irq_mask	= ep93xx_gpio_irq_mask,
-	.irq_unmask	= ep93xx_gpio_irq_unmask,
-	.irq_set_type	= ep93xx_gpio_irq_type,
-};
-
 /*************************************************************************
  * gpiolib interface for EP93xx on-chip GPIOs
  *************************************************************************/
@@ -276,17 +271,19 @@
 	const char	*label;
 	int		data;
 	int		dir;
+	int		irq;
 	int		base;
 	bool		has_irq;
 	bool		has_hierarchical_irq;
 	unsigned int	irq_base;
 };
 
-#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \
+#define EP93XX_GPIO_BANK(_label, _data, _dir, _irq, _base, _has_irq, _has_hier, _irq_base) \
 	{							\
 		.label		= _label,			\
 		.data		= _data,			\
 		.dir		= _dir,				\
+		.irq		= _irq,				\
 		.base		= _base,			\
 		.has_irq	= _has_irq,			\
 		.has_hierarchical_irq = _has_hier,		\
@@ -295,16 +292,16 @@
 
 static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
 	/* Bank A has 8 IRQs */
-	EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64),
+	EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, 64),
 	/* Bank B has 8 IRQs */
-	EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72),
-	EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0),
-	EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0),
-	EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0),
+	EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, 72),
+	EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0),
+	EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0),
+	EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0),
 	/* Bank F has 8 IRQs */
-	EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0),
-	EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0),
-	EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0),
+	EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, 0),
+	EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0),
+	EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0),
 };
 
 static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
@@ -326,13 +323,23 @@
 	return EP93XX_GPIO_F_IRQ_BASE + offset;
 }
 
-static int ep93xx_gpio_add_bank(struct gpio_chip *gc,
+static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic)
+{
+	ic->irq_ack = ep93xx_gpio_irq_ack;
+	ic->irq_mask_ack = ep93xx_gpio_irq_mask_ack;
+	ic->irq_mask = ep93xx_gpio_irq_mask;
+	ic->irq_unmask = ep93xx_gpio_irq_unmask;
+	ic->irq_set_type = ep93xx_gpio_irq_type;
+}
+
+static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
 				struct platform_device *pdev,
 				struct ep93xx_gpio *epg,
 				struct ep93xx_gpio_bank *bank)
 {
 	void __iomem *data = epg->base + bank->data;
 	void __iomem *dir = epg->base + bank->dir;
+	struct gpio_chip *gc = &egc->gc;
 	struct device *dev = &pdev->dev;
 	struct gpio_irq_chip *girq;
 	int err;
@@ -346,8 +353,21 @@
 
 	girq = &gc->irq;
 	if (bank->has_irq || bank->has_hierarchical_irq) {
+		struct irq_chip *ic;
+
 		gc->set_config = ep93xx_gpio_set_config;
-		girq->chip = &ep93xx_gpio_irq_chip;
+		egc->eic = devm_kcalloc(dev, 1,
+					sizeof(*egc->eic),
+					GFP_KERNEL);
+		if (!egc->eic)
+			return -ENOMEM;
+		egc->eic->irq_offset = bank->irq;
+		ic = &egc->eic->ic;
+		ic->name = devm_kasprintf(dev, GFP_KERNEL, "gpio-irq-%s", bank->label);
+		if (!ic->name)
+			return -ENOMEM;
+		ep93xx_init_irq_chip(dev, ic);
+		girq->chip = ic;
 	}
 
 	if (bank->has_irq) {
@@ -389,7 +409,7 @@
 			gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
 			irq_set_chip_data(gpio_irq, &epg->gc[5]);
 			irq_set_chip_and_handler(gpio_irq,
-						 &ep93xx_gpio_irq_chip,
+						 girq->chip,
 						 handle_level_irq);
 			irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
 		}
@@ -415,7 +435,7 @@
 		return PTR_ERR(epg->base);
 
 	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
-		struct gpio_chip *gc = &epg->gc[i];
+		struct ep93xx_gpio_chip *gc = &epg->gc[i];
 		struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
 
 		if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-exar.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-exar.c
@@ -145,8 +145,10 @@
 	mutex_init(&exar_gpio->lock);
 
 	index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
-	if (index < 0)
-		goto err_destroy;
+	if (index < 0) {
+		ret = index;
+		goto err_mutex_destroy;
+	}
 
 	sprintf(exar_gpio->name, "exar_gpio%d", index);
 	exar_gpio->gpio_chip.label = exar_gpio->name;
@@ -173,6 +175,7 @@
 
 err_destroy:
 	ida_simple_remove(&ida_index, index);
+err_mutex_destroy:
 	mutex_destroy(&exar_gpio->lock);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-grgpio.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-grgpio.c
@@ -253,17 +253,16 @@
 	lirq->irq = irq;
 	uirq = &priv->uirqs[lirq->index];
 	if (uirq->refcnt == 0) {
+		spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 		ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
 				  dev_name(priv->dev), priv);
 		if (ret) {
 			dev_err(priv->dev,
 				"Could not request underlying irq %d\n",
 				uirq->uirq);
-
-			spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
-
 			return ret;
 		}
+		spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 	}
 	uirq->refcnt++;
 
@@ -309,8 +308,11 @@
 	if (index >= 0) {
 		uirq = &priv->uirqs[lirq->index];
 		uirq->refcnt--;
-		if (uirq->refcnt == 0)
+		if (uirq->refcnt == 0) {
+			spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 			free_irq(uirq->uirq, priv);
+			return;
+		}
 	}
 
 	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-lynxpoint.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-lynxpoint.c
@@ -164,6 +164,12 @@
 		value |= TRIG_SEL_BIT | INT_INV_BIT;
 
 	outl(value, reg);
+
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		irq_set_handler_locked(d, handle_edge_irq);
+	else if (type & IRQ_TYPE_LEVEL_MASK)
+		irq_set_handler_locked(d, handle_level_irq);
+
 	spin_unlock_irqrestore(&lg->lock, flags);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-mockup.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-mockup.c
@@ -339,7 +339,7 @@
 		priv->offset = i;
 		priv->desc = &gc->gpiodev->descs[i];
 
-		debugfs_create_file(name, 0200, chip->dbg_dir, priv,
+		debugfs_create_file(name, 0600, chip->dbg_dir, priv,
 				    &gpio_mockup_debugfs_ops);
 	}
 
@@ -497,6 +497,7 @@
 	err = platform_driver_register(&gpio_mockup_driver);
 	if (err) {
 		gpio_mockup_err("error registering platform driver\n");
+		debugfs_remove_recursive(gpio_mockup_dbg_dir);
 		return err;
 	}
 
@@ -527,6 +528,7 @@
 			gpio_mockup_err("error registering device");
 			platform_driver_unregister(&gpio_mockup_driver);
 			gpio_mockup_unregister_pdevs();
+			debugfs_remove_recursive(gpio_mockup_dbg_dir);
 			return PTR_ERR(pdev);
 		}
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-mpc8xxx.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-mpc8xxx.c
@@ -190,6 +190,7 @@
 
 	switch (flow_type) {
 	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_LEVEL_LOW:
 		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
 		gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
 			gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
@@ -346,6 +347,7 @@
 		return -ENOMEM;
 
 	gc = &mpc8xxx_gc->gc;
+	gc->parent = &pdev->dev;
 
 	if (of_property_read_bool(np, "little-endian")) {
 		ret = bgpio_init(gc, &pdev->dev, 4,
@@ -377,7 +379,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;
 
 	if (devtype->gpio_dir_out)
 		gc->direction_output = devtype->gpio_dir_out;
@@ -386,6 +389,9 @@
 
 	gc->to_irq = mpc8xxx_gpio_to_irq;
 
+	if (of_device_is_compatible(np, "fsl,qoriq-gpio"))
+		gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
+
 	ret = gpiochip_add_data(gc, mpc8xxx_gc);
 	if (ret) {
 		pr_err("%pOF: GPIO chip registration failed with status %d\n",
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-mvebu.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-mvebu.c
@@ -657,9 +657,8 @@
 
 	spin_lock_irqsave(&mvpwm->lock, flags);
 
-	val = (unsigned long long)
-		readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
-	val *= NSEC_PER_SEC;
+	u = readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
+	val = (unsigned long long) u * NSEC_PER_SEC;
 	do_div(val, mvpwm->clk_rate);
 	if (val > UINT_MAX)
 		state->duty_cycle = UINT_MAX;
@@ -668,21 +667,17 @@
 	else
 		state->duty_cycle = 1;
 
-	val = (unsigned long long)
-		readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
+	val = (unsigned long long) u; /* on duration */
+	/* period = on + off duration */
+	val += readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
 	val *= NSEC_PER_SEC;
 	do_div(val, mvpwm->clk_rate);
-	if (val < state->duty_cycle) {
+	if (val > UINT_MAX)
+		state->period = UINT_MAX;
+	else if (val)
+		state->period = val;
+	else
 		state->period = 1;
-	} else {
-		val -= state->duty_cycle;
-		if (val > UINT_MAX)
-			state->period = UINT_MAX;
-		else if (val)
-			state->period = val;
-		else
-			state->period = 1;
-	}
 
 	regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
 	if (u)
@@ -702,6 +697,9 @@
 	unsigned long flags;
 	unsigned int on, off;
 
+	if (state->polarity != PWM_POLARITY_NORMAL)
+		return -EINVAL;
+
 	val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle;
 	do_div(val, NSEC_PER_SEC);
 	if (val > UINT_MAX)
@@ -1196,6 +1194,13 @@
 
 	devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
 
+	/* Some MVEBU SoCs have simple PWM support for GPIO lines */
+	if (IS_ENABLED(CONFIG_PWM)) {
+		err = mvebu_pwm_probe(pdev, mvchip, id);
+		if (err)
+			return err;
+	}
+
 	/* Some gpio controllers do not provide irq support */
 	if (!have_irqs)
 		return 0;
@@ -1205,7 +1210,8 @@
 	if (!mvchip->domain) {
 		dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
 			mvchip->chip.label);
-		return -ENODEV;
+		err = -ENODEV;
+		goto err_pwm;
 	}
 
 	err = irq_alloc_domain_generic_chips(
@@ -1253,14 +1259,12 @@
 						 mvchip);
 	}
 
-	/* Some MVEBU SoCs have simple PWM support for GPIO lines */
-	if (IS_ENABLED(CONFIG_PWM))
-		return mvebu_pwm_probe(pdev, mvchip, id);
-
 	return 0;
 
 err_domain:
 	irq_domain_remove(mvchip->domain);
+err_pwm:
+	pwmchip_remove(&mvchip->mvpwm->chip);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-mxc.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-mxc.c
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/syscore_ops.h>
@@ -158,6 +159,7 @@
 	{ .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
 	{ /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids);
 
 /*
  * MX2 has one interrupt *for all* gpio ports. The list is used
@@ -229,7 +231,7 @@
 
 	writel(1 << gpio_idx, port->base + GPIO_ISR);
 
-	return 0;
+	return port->gc.direction_input(&port->gc, gpio_idx);
 }
 
 static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
@@ -411,6 +413,7 @@
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct mxc_gpio_port *port;
+	int irq_count;
 	int irq_base;
 	int err;
 
@@ -426,9 +429,15 @@
 	if (IS_ERR(port->base))
 		return PTR_ERR(port->base);
 
-	port->irq_high = platform_get_irq(pdev, 1);
-	if (port->irq_high < 0)
-		port->irq_high = 0;
+	irq_count = platform_irq_count(pdev);
+	if (irq_count < 0)
+		return irq_count;
+
+	if (irq_count > 1) {
+		port->irq_high = platform_get_irq(pdev, 1);
+		if (port->irq_high < 0)
+			port->irq_high = 0;
+	}
 
 	port->irq = platform_get_irq(pdev, 0);
 	if (port->irq < 0)
@@ -600,3 +609,7 @@
 	return platform_driver_register(&mxc_gpio_driver);
 }
 subsys_initcall(gpio_mxc_init);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("i.MX GPIO Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-omap.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-omap.c
@@ -29,6 +29,7 @@
 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
 
 struct gpio_regs {
+	u32 sysconfig;
 	u32 irqenable1;
 	u32 irqenable2;
 	u32 wake_en;
@@ -1058,6 +1059,7 @@
 	const struct omap_gpio_reg_offs *regs = p->regs;
 	void __iomem *base = p->base;
 
+	p->context.sysconfig	= readl_relaxed(base + regs->sysconfig);
 	p->context.ctrl		= readl_relaxed(base + regs->ctrl);
 	p->context.oe		= readl_relaxed(base + regs->direction);
 	p->context.wake_en	= readl_relaxed(base + regs->wkup_en);
@@ -1077,6 +1079,7 @@
 	const struct omap_gpio_reg_offs *regs = bank->regs;
 	void __iomem *base = bank->base;
 
+	writel_relaxed(bank->context.sysconfig, base + regs->sysconfig);
 	writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
 	writel_relaxed(bank->context.ctrl, base + regs->ctrl);
 	writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
@@ -1104,6 +1107,10 @@
 
 	bank->saved_datain = readl_relaxed(base + bank->regs->datain);
 
+	/* Save syconfig, it's runtime value can be different from init value */
+	if (bank->loses_context)
+		bank->context.sysconfig = readl_relaxed(base + bank->regs->sysconfig);
+
 	if (!bank->enabled_non_wakeup_gpios)
 		goto update_gpio_context_count;
 
@@ -1259,6 +1266,7 @@
 
 static const struct omap_gpio_reg_offs omap2_gpio_regs = {
 	.revision =		OMAP24XX_GPIO_REVISION,
+	.sysconfig =		OMAP24XX_GPIO_SYSCONFIG,
 	.direction =		OMAP24XX_GPIO_OE,
 	.datain =		OMAP24XX_GPIO_DATAIN,
 	.dataout =		OMAP24XX_GPIO_DATAOUT,
@@ -1282,6 +1290,7 @@
 
 static const struct omap_gpio_reg_offs omap4_gpio_regs = {
 	.revision =		OMAP4_GPIO_REVISION,
+	.sysconfig =		OMAP4_GPIO_SYSCONFIG,
 	.direction =		OMAP4_GPIO_OE,
 	.datain =		OMAP4_GPIO_DATAIN,
 	.dataout =		OMAP4_GPIO_DATAOUT,
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-pca953x.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-pca953x.c
@@ -20,6 +20,7 @@
 #include <linux/platform_data/pca953x.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 
 #include <asm/unaligned.h>
@@ -107,6 +108,84 @@
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
+#ifdef CONFIG_GPIO_PCA953X_IRQ
+
+#include <linux/dmi.h>
+#include <linux/gpio.h>
+#include <linux/list.h>
+
+static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
+	{
+		/*
+		 * On Intel Galileo Gen 2 board the IRQ pin of one of
+		 * the I²C GPIO expanders, which has GpioInt() resource,
+		 * is provided as an absolute number instead of being
+		 * relative. Since first controller (gpio-sch.c) and
+		 * second (gpio-dwapb.c) are at the fixed bases, we may
+		 * safely refer to the number in the global space to get
+		 * an IRQ out of it.
+		 */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
+		},
+	},
+	{}
+};
+
+#ifdef CONFIG_ACPI
+static int pca953x_acpi_get_pin(struct acpi_resource *ares, void *data)
+{
+	struct acpi_resource_gpio *agpio;
+	int *pin = data;
+
+	if (acpi_gpio_get_irq_resource(ares, &agpio))
+		*pin = agpio->pin_table[0];
+	return 1;
+}
+
+static int pca953x_acpi_find_pin(struct device *dev)
+{
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+	int pin = -ENOENT, ret;
+	LIST_HEAD(r);
+
+	ret = acpi_dev_get_resources(adev, &r, pca953x_acpi_get_pin, &pin);
+	acpi_dev_free_resource_list(&r);
+	if (ret < 0)
+		return ret;
+
+	return pin;
+}
+#else
+static inline int pca953x_acpi_find_pin(struct device *dev) { return -ENXIO; }
+#endif
+
+static int pca953x_acpi_get_irq(struct device *dev)
+{
+	int pin, ret;
+
+	pin = pca953x_acpi_find_pin(dev);
+	if (pin < 0)
+		return pin;
+
+	dev_info(dev, "Applying ACPI interrupt quirk (GPIO %d)\n", pin);
+
+	if (!gpio_is_valid(pin))
+		return -EINVAL;
+
+	ret = gpio_request(pin, "pca953x interrupt");
+	if (ret)
+		return ret;
+
+	ret = gpio_to_irq(pin);
+
+	/* When pin is used as an IRQ, no need to keep it requested */
+	gpio_free(pin);
+
+	return ret;
+}
+#endif
+
 static const struct acpi_device_id pca953x_acpi_ids[] = {
 	{ "INT3491", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
 	{ }
@@ -301,13 +380,31 @@
 	.reg_bits = 8,
 	.val_bits = 8,
 
+	.use_single_read = true,
+	.use_single_write = true,
+
+	.readable_reg = pca953x_readable_register,
+	.writeable_reg = pca953x_writeable_register,
+	.volatile_reg = pca953x_volatile_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = 0x7f,
+};
+
+static const struct regmap_config pca953x_ai_i2c_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.read_flag_mask = REG_ADDR_AI,
+	.write_flag_mask = REG_ADDR_AI,
+
 	.readable_reg = pca953x_readable_register,
 	.writeable_reg = pca953x_writeable_register,
 	.volatile_reg = pca953x_volatile_register,
 
+	.disable_locking = true,
 	.cache_type = REGCACHE_RBTREE,
-	/* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */
-	.max_register = 0xff,
+	.max_register = 0x7f,
 };
 
 static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
@@ -318,18 +415,6 @@
 	int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
 	u8 regaddr = pinctrl | addr | (off / BANK_SZ);
 
-	/* Single byte read doesn't need AI bit set. */
-	if (!addrinc)
-		return regaddr;
-
-	/* Chips with 24 and more GPIOs always support Auto Increment */
-	if (write && NBANK(chip) > 2)
-		regaddr |= REG_ADDR_AI;
-
-	/* PCA9575 needs address-increment on multi-byte writes */
-	if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
-		regaddr |= REG_ADDR_AI;
-
 	return regaddr;
 }
 
@@ -502,21 +587,21 @@
 
 	mutex_lock(&chip->i2c_lock);
 
-	/* Disable pull-up/pull-down */
-	ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
-	if (ret)
-		goto exit;
-
 	/* Configure pull-up/pull-down */
 	if (config == PIN_CONFIG_BIAS_PULL_UP)
 		ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
 	else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
 		ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
+	else
+		ret = 0;
 	if (ret)
 		goto exit;
 
-	/* Enable pull-up/pull-down */
-	ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
+	/* Disable/Enable pull-up/pull-down */
+	if (config == PIN_CONFIG_BIAS_DISABLE)
+		ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
+	else
+		ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
 
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -528,9 +613,11 @@
 {
 	struct pca953x_chip *chip = gpiochip_get_data(gc);
 
-	switch (config) {
+	switch (pinconf_to_config_param(config)) {
 	case PIN_CONFIG_BIAS_PULL_UP:
+	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
 	case PIN_CONFIG_BIAS_PULL_DOWN:
+	case PIN_CONFIG_BIAS_DISABLE:
 		return pca953x_gpio_set_pull_up_down(chip, offset, config);
 	default:
 		return -ENOTSUPP;
@@ -770,6 +857,12 @@
 	u8 reg_direction[MAX_BANK];
 	int ret, i;
 
+	if (dmi_first_match(pca953x_dmi_acpi_irq_info)) {
+		ret = pca953x_acpi_get_irq(&client->dev);
+		if (ret > 0)
+			client->irq = ret;
+	}
+
 	if (!client->irq)
 		return 0;
 
@@ -897,6 +990,7 @@
 	int ret;
 	u32 invert = 0;
 	struct regulator *reg;
+	const struct regmap_config *regmap_config;
 
 	chip = devm_kzalloc(&client->dev,
 			sizeof(struct pca953x_chip), GFP_KERNEL);
@@ -930,17 +1024,21 @@
 
 	chip->client = client;
 
-	reg = devm_regulator_get(&client->dev, "vcc");
+	reg = devm_regulator_get_optional(&client->dev, "vcc");
 	if (IS_ERR(reg)) {
 		ret = PTR_ERR(reg);
-		if (ret != -EPROBE_DEFER)
-			dev_err(&client->dev, "reg get err: %d\n", ret);
-		return ret;
+		if (ret == -EPROBE_DEFER)
+			return ret;
+		dev_dbg(&client->dev, "reg get err: %d\n", ret);
+		reg = NULL;
 	}
-	ret = regulator_enable(reg);
-	if (ret) {
-		dev_err(&client->dev, "reg en err: %d\n", ret);
-		return ret;
+
+	if (reg) {
+		ret = regulator_enable(reg);
+		if (ret) {
+			dev_err(&client->dev, "reg en err: %d\n", ret);
+			return ret;
+		}
 	}
 	chip->regulator = reg;
 
@@ -960,7 +1058,17 @@
 
 	i2c_set_clientdata(client, chip);
 
-	chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap);
+	pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
+
+	if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
+		dev_info(&client->dev, "using AI\n");
+		regmap_config = &pca953x_ai_i2c_regmap;
+	} else {
+		dev_info(&client->dev, "using no AI\n");
+		regmap_config = &pca953x_i2c_regmap;
+	}
+
+	chip->regmap = devm_regmap_init_i2c(client, regmap_config);
 	if (IS_ERR(chip->regmap)) {
 		ret = PTR_ERR(chip->regmap);
 		goto err_exit;
@@ -988,10 +1096,13 @@
 	lockdep_set_subclass(&chip->i2c_lock,
 			     i2c_adapter_depth(client->adapter));
 
+	ret = device_reset(&client->dev);
+	if (ret == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
 	/* initialize cached registers from their original values.
 	 * we can't share this chip with another i2c master.
 	 */
-	pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
 
 	if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
 		chip->regs = &pca953x_regs;
@@ -1021,7 +1132,8 @@
 	return 0;
 
 err_exit:
-	regulator_disable(chip->regulator);
+	if (chip->regulator)
+		regulator_disable(chip->regulator);
 	return ret;
 }
 
@@ -1040,7 +1152,8 @@
 		ret = 0;
 	}
 
-	regulator_disable(chip->regulator);
+	if (chip->regulator)
+		regulator_disable(chip->regulator);
 
 	return ret;
 }
@@ -1096,12 +1209,15 @@
 {
 	struct pca953x_chip *chip = dev_get_drvdata(dev);
 
+	mutex_lock(&chip->i2c_lock);
 	regcache_cache_only(chip->regmap, true);
+	mutex_unlock(&chip->i2c_lock);
 
 	if (atomic_read(&chip->wakeup_path))
 		device_set_wakeup_path(dev);
 	else
-		regulator_disable(chip->regulator);
+		if (chip->regulator)
+			regulator_disable(chip->regulator);
 
 	return 0;
 }
@@ -1111,21 +1227,30 @@
 	struct pca953x_chip *chip = dev_get_drvdata(dev);
 	int ret;
 
+	regcache_cache_only(chip->regmap, false);
+
 	if (!atomic_read(&chip->wakeup_path)) {
-		ret = regulator_enable(chip->regulator);
-		if (ret) {
-			dev_err(dev, "Failed to enable regulator: %d\n", ret);
+		if (chip->regulator) {
+			ret = regulator_enable(chip->regulator);
+			if (ret) {
+				dev_err(dev, "Failed to enable regulator: %d\n", ret);
+				return 0;
+			}
+		} else {
 			return 0;
 		}
 	}
 
-	regcache_cache_only(chip->regmap, false);
+	mutex_lock(&chip->i2c_lock);
 	regcache_mark_dirty(chip->regmap);
 	ret = pca953x_regcache_sync(dev);
-	if (ret)
+	if (ret) {
+		mutex_unlock(&chip->i2c_lock);
 		return ret;
+	}
 
 	ret = regcache_sync(chip->regmap);
+	mutex_unlock(&chip->i2c_lock);
 	if (ret) {
 		dev_err(dev, "Failed to restore register map: %d\n", ret);
 		return ret;
@@ -1175,6 +1300,7 @@
 
 	{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
 	{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "onnn,pca9655", .data = OF_953X(16, PCA_INT), },
 
 	{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
 	{ }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-pcf857x.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-pcf857x.c
@@ -332,7 +332,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 = devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
 	if (status < 0)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-pcie-idio-24.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-pcie-idio-24.c
@@ -28,6 +28,47 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
+/*
+ * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status
+ *
+ * Bit: Description
+ *   0: Enable Interrupt Sources (Bit 0)
+ *   1: Enable Interrupt Sources (Bit 1)
+ *   2: Generate Internal PCI Bus Internal SERR# Interrupt
+ *   3: Mailbox Interrupt Enable
+ *   4: Power Management Interrupt Enable
+ *   5: Power Management Interrupt
+ *   6: Slave Read Local Data Parity Check Error Enable
+ *   7: Slave Read Local Data Parity Check Error Status
+ *   8: Internal PCI Wire Interrupt Enable
+ *   9: PCI Express Doorbell Interrupt Enable
+ *  10: PCI Abort Interrupt Enable
+ *  11: Local Interrupt Input Enable
+ *  12: Retry Abort Enable
+ *  13: PCI Express Doorbell Interrupt Active
+ *  14: PCI Abort Interrupt Active
+ *  15: Local Interrupt Input Active
+ *  16: Local Interrupt Output Enable
+ *  17: Local Doorbell Interrupt Enable
+ *  18: DMA Channel 0 Interrupt Enable
+ *  19: DMA Channel 1 Interrupt Enable
+ *  20: Local Doorbell Interrupt Active
+ *  21: DMA Channel 0 Interrupt Active
+ *  22: DMA Channel 1 Interrupt Active
+ *  23: Built-In Self-Test (BIST) Interrupt Active
+ *  24: Direct Master was the Bus Master during a Master or Target Abort
+ *  25: DMA Channel 0 was the Bus Master during a Master or Target Abort
+ *  26: DMA Channel 1 was the Bus Master during a Master or Target Abort
+ *  27: Target Abort after internal 256 consecutive Master Retrys
+ *  28: PCI Bus wrote data to LCS_MBOX0
+ *  29: PCI Bus wrote data to LCS_MBOX1
+ *  30: PCI Bus wrote data to LCS_MBOX2
+ *  31: PCI Bus wrote data to LCS_MBOX3
+ */
+#define PLX_PEX8311_PCI_LCS_INTCSR  0x68
+#define INTCSR_INTERNAL_PCI_WIRE    BIT(8)
+#define INTCSR_LOCAL_INPUT          BIT(11)
+
 /**
  * struct idio_24_gpio_reg - GPIO device registers structure
  * @out0_7:	Read: FET Outputs 0-7
@@ -92,6 +133,7 @@
 struct idio_24_gpio {
 	struct gpio_chip chip;
 	raw_spinlock_t lock;
+	__u8 __iomem *plx;
 	struct idio_24_gpio_reg __iomem *reg;
 	unsigned long irq_mask;
 };
@@ -360,13 +402,13 @@
 	unsigned long flags;
 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
 	unsigned char new_irq_mask;
-	const unsigned long bank_offset = bit_offset/8 * 8;
+	const unsigned long bank_offset = bit_offset / 8;
 	unsigned char cos_enable_state;
 
 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 
-	idio24gpio->irq_mask &= BIT(bit_offset);
-	new_irq_mask = idio24gpio->irq_mask >> bank_offset;
+	idio24gpio->irq_mask &= ~BIT(bit_offset);
+	new_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
 
 	if (!new_irq_mask) {
 		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
@@ -389,12 +431,12 @@
 	unsigned long flags;
 	unsigned char prev_irq_mask;
 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
-	const unsigned long bank_offset = bit_offset/8 * 8;
+	const unsigned long bank_offset = bit_offset / 8;
 	unsigned char cos_enable_state;
 
 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 
-	prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
+	prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
 	idio24gpio->irq_mask |= BIT(bit_offset);
 
 	if (!prev_irq_mask) {
@@ -481,6 +523,7 @@
 	struct device *const dev = &pdev->dev;
 	struct idio_24_gpio *idio24gpio;
 	int err;
+	const size_t pci_plx_bar_index = 1;
 	const size_t pci_bar_index = 2;
 	const char *const name = pci_name(pdev);
 
@@ -494,12 +537,13 @@
 		return err;
 	}
 
-	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
+	err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name);
 	if (err) {
 		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
 		return err;
 	}
 
+	idio24gpio->plx = pcim_iomap_table(pdev)[pci_plx_bar_index];
 	idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
 
 	idio24gpio->chip.label = name;
@@ -520,6 +564,12 @@
 
 	/* Software board reset */
 	iowrite8(0, &idio24gpio->reg->soft_reset);
+	/*
+	 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt
+	 * input
+	 */
+	iowrite8((INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT) >> 8,
+		 idio24gpio->plx + PLX_PEX8311_PCI_LCS_INTCSR + 1);
 
 	err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
 	if (err) {
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-pmic-eic-sprd.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-pmic-eic-sprd.c
@@ -338,6 +338,7 @@
 	pmic_eic->chip.set_config = sprd_pmic_eic_set_config;
 	pmic_eic->chip.set = sprd_pmic_eic_set;
 	pmic_eic->chip.get = sprd_pmic_eic_get;
+	pmic_eic->chip.can_sleep = true;
 
 	pmic_eic->intc.name = dev_name(&pdev->dev);
 	pmic_eic->intc.irq_mask = sprd_pmic_eic_irq_mask;
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-pxa.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-pxa.c
@@ -243,6 +243,7 @@
 	switch (gpio_type) {
 	case PXA3XX_GPIO:
 	case MMP2_GPIO:
+	case MMP_GPIO:
 		return false;
 
 	default:
@@ -663,8 +664,8 @@
 	pchip->irq1 = irq1;
 
 	gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
-	if (!gpio_reg_base)
-		return -EINVAL;
+	if (IS_ERR(gpio_reg_base))
+		return PTR_ERR(gpio_reg_base);
 
 	clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-rcar.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-rcar.c
@@ -250,8 +250,10 @@
 	int error;
 
 	error = pm_runtime_get_sync(p->dev);
-	if (error < 0)
+	if (error < 0) {
+		pm_runtime_put(p->dev);
 		return error;
+	}
 
 	error = pinctrl_gpio_request(chip->base + offset);
 	if (error)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-siox.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-siox.c
@@ -245,6 +245,7 @@
 	girq->chip = &ddata->ichip;
 	girq->default_type = IRQ_TYPE_NONE;
 	girq->handler = handle_level_irq;
+	girq->threaded = true;
 
 	ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-sprd.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-sprd.c
@@ -149,17 +149,20 @@
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
+		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
 		irq_set_handler_locked(data, handle_edge_irq);
 		break;
 	case IRQ_TYPE_EDGE_FALLING:
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
+		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
 		irq_set_handler_locked(data, handle_edge_irq);
 		break;
 	case IRQ_TYPE_EDGE_BOTH:
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
 		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1);
+		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
 		irq_set_handler_locked(data, handle_edge_irq);
 		break;
 	case IRQ_TYPE_LEVEL_HIGH:
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-tb10x.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tb10x.c
@@ -195,7 +195,7 @@
 				handle_edge_irq, IRQ_NOREQUEST, IRQ_NOPROBE,
 				IRQ_GC_INIT_MASK_CACHE);
 		if (ret)
-			return ret;
+			goto err_remove_domain;
 
 		gc = tb10x_gpio->domain->gc->gc[0];
 		gc->reg_base                         = tb10x_gpio->base;
@@ -209,6 +209,10 @@
 	}
 
 	return 0;
+
+err_remove_domain:
+	irq_domain_remove(tb10x_gpio->domain);
+	return ret;
 }
 
 static int tb10x_gpio_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-tc3589x.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tc3589x.c
@@ -209,7 +209,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-ein-5.4.0.orig/drivers/gpio/gpio-tegra.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tegra.c
@@ -365,6 +365,7 @@
 	struct tegra_gpio_info *tgi = bank->tgi;
 	unsigned int gpio = d->hwirq;
 
+	tegra_gpio_irq_mask(d);
 	gpiochip_unlock_as_irq(&tgi->gc, gpio);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-tegra186.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tegra186.c
@@ -234,9 +234,12 @@
 	return offset + pin;
 }
 
+#define to_tegra_gpio(x) container_of((x), struct tegra_gpio, gpio)
+
 static void tegra186_irq_ack(struct irq_data *data)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = to_tegra_gpio(gc);
 	void __iomem *base;
 
 	base = tegra186_gpio_get_base(gpio, data->hwirq);
@@ -248,7 +251,8 @@
 
 static void tegra186_irq_mask(struct irq_data *data)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = to_tegra_gpio(gc);
 	void __iomem *base;
 	u32 value;
 
@@ -263,7 +267,8 @@
 
 static void tegra186_irq_unmask(struct irq_data *data)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = to_tegra_gpio(gc);
 	void __iomem *base;
 	u32 value;
 
@@ -278,7 +283,8 @@
 
 static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
 {
-	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct tegra_gpio *gpio = to_tegra_gpio(gc);
 	void __iomem *base;
 	u32 value;
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-thunderx.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-thunderx.c
@@ -53,6 +53,7 @@
 struct thunderx_gpio {
 	struct gpio_chip	chip;
 	u8 __iomem		*register_base;
+	struct irq_domain	*irqd;
 	struct msix_entry	*msix_entries;	/* per line MSI-X */
 	struct thunderx_line	*line_entries;	/* per line irq info */
 	raw_spinlock_t		lock;
@@ -282,60 +283,54 @@
 	}
 }
 
-static void thunderx_gpio_irq_ack(struct irq_data *d)
+static void thunderx_gpio_irq_ack(struct irq_data *data)
 {
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
 
 	writeq(GPIO_INTR_INTR,
-	       txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
+	       txline->txgpio->register_base + intr_reg(txline->line));
 }
 
-static void thunderx_gpio_irq_mask(struct irq_data *d)
+static void thunderx_gpio_irq_mask(struct irq_data *data)
 {
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
 
 	writeq(GPIO_INTR_ENA_W1C,
-	       txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
+	       txline->txgpio->register_base + intr_reg(txline->line));
 }
 
-static void thunderx_gpio_irq_mask_ack(struct irq_data *d)
+static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
 {
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
 
 	writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
-	       txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
+	       txline->txgpio->register_base + intr_reg(txline->line));
 }
 
-static void thunderx_gpio_irq_unmask(struct irq_data *d)
+static void thunderx_gpio_irq_unmask(struct irq_data *data)
 {
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
 
 	writeq(GPIO_INTR_ENA_W1S,
-	       txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
+	       txline->txgpio->register_base + intr_reg(txline->line));
 }
 
-static int thunderx_gpio_irq_set_type(struct irq_data *d,
+static int thunderx_gpio_irq_set_type(struct irq_data *data,
 				      unsigned int flow_type)
 {
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
-	struct thunderx_line *txline =
-		&txgpio->line_entries[irqd_to_hwirq(d)];
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+	struct thunderx_gpio *txgpio = txline->txgpio;
 	u64 bit_cfg;
 
-	irqd_set_trigger_type(d, flow_type);
+	irqd_set_trigger_type(data, flow_type);
 
 	bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN;
 
 	if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-		irq_set_handler_locked(d, handle_fasteoi_ack_irq);
+		irq_set_handler_locked(data, handle_fasteoi_ack_irq);
 		bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
 	} else {
-		irq_set_handler_locked(d, handle_fasteoi_mask_irq);
+		irq_set_handler_locked(data, handle_fasteoi_mask_irq);
 	}
 
 	raw_spin_lock(&txgpio->lock);
@@ -364,6 +359,33 @@
 	irq_chip_disable_parent(data);
 }
 
+static int thunderx_gpio_irq_request_resources(struct irq_data *data)
+{
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+	struct thunderx_gpio *txgpio = txline->txgpio;
+	int r;
+
+	r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
+	if (r)
+		return r;
+
+	r = irq_chip_request_resources_parent(data);
+	if (r)
+		gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
+
+	return r;
+}
+
+static void thunderx_gpio_irq_release_resources(struct irq_data *data)
+{
+	struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+	struct thunderx_gpio *txgpio = txline->txgpio;
+
+	irq_chip_release_resources_parent(data);
+
+	gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
+}
+
 /*
  * Interrupts are chained from underlying MSI-X vectors.  We have
  * these irq_chip functions to be able to handle level triggering
@@ -380,22 +402,48 @@
 	.irq_unmask		= thunderx_gpio_irq_unmask,
 	.irq_eoi		= irq_chip_eoi_parent,
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_request_resources	= thunderx_gpio_irq_request_resources,
+	.irq_release_resources	= thunderx_gpio_irq_release_resources,
 	.irq_set_type		= thunderx_gpio_irq_set_type,
 
 	.flags			= IRQCHIP_SET_TYPE_MASKED
 };
 
-static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
-					       unsigned int child,
-					       unsigned int child_type,
-					       unsigned int *parent,
-					       unsigned int *parent_type)
+static int thunderx_gpio_irq_translate(struct irq_domain *d,
+				       struct irq_fwspec *fwspec,
+				       irq_hw_number_t *hwirq,
+				       unsigned int *type)
+{
+	struct thunderx_gpio *txgpio = d->host_data;
+
+	if (WARN_ON(fwspec->param_count < 2))
+		return -EINVAL;
+	if (fwspec->param[0] >= txgpio->chip.ngpio)
+		return -EINVAL;
+	*hwirq = fwspec->param[0];
+	*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+	return 0;
+}
+
+static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
+				   unsigned int nr_irqs, void *arg)
 {
-	struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+	struct thunderx_line *txline = arg;
 
-	*parent = txgpio->base_msi + (2 * child);
-	*parent_type = IRQ_TYPE_LEVEL_HIGH;
-	return 0;
+	return irq_domain_set_hwirq_and_chip(d, virq, txline->line,
+					     &thunderx_gpio_irq_chip, txline);
+}
+
+static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
+	.alloc		= thunderx_gpio_irq_alloc,
+	.translate	= thunderx_gpio_irq_translate
+};
+
+static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+	struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
+
+	return irq_find_mapping(txgpio->irqd, offset);
 }
 
 static int thunderx_gpio_probe(struct pci_dev *pdev,
@@ -405,7 +453,6 @@
 	struct device *dev = &pdev->dev;
 	struct thunderx_gpio *txgpio;
 	struct gpio_chip *chip;
-	struct gpio_irq_chip *girq;
 	int ngpio, i;
 	int err = 0;
 
@@ -450,8 +497,8 @@
 	}
 
 	txgpio->msix_entries = devm_kcalloc(dev,
-					    ngpio, sizeof(struct msix_entry),
-					    GFP_KERNEL);
+					  ngpio, sizeof(struct msix_entry),
+					  GFP_KERNEL);
 	if (!txgpio->msix_entries) {
 		err = -ENOMEM;
 		goto out;
@@ -492,6 +539,27 @@
 	if (err < 0)
 		goto out;
 
+	/*
+	 * Push GPIO specific irqdomain on hierarchy created as a side
+	 * effect of the pci_enable_msix()
+	 */
+	txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain,
+						   0, 0, of_node_to_fwnode(dev->of_node),
+						   &thunderx_gpio_irqd_ops, txgpio);
+	if (!txgpio->irqd) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* Push on irq_data and the domain for each line. */
+	for (i = 0; i < ngpio; i++) {
+		err = irq_domain_push_irq(txgpio->irqd,
+					  txgpio->msix_entries[i].vector,
+					  &txgpio->line_entries[i]);
+		if (err < 0)
+			dev_err(dev, "irq_domain_push_irq: %d\n", err);
+	}
+
 	chip->label = KBUILD_MODNAME;
 	chip->parent = dev;
 	chip->owner = THIS_MODULE;
@@ -506,28 +574,11 @@
 	chip->set = thunderx_gpio_set;
 	chip->set_multiple = thunderx_gpio_set_multiple;
 	chip->set_config = thunderx_gpio_set_config;
-	girq = &chip->irq;
-	girq->chip = &thunderx_gpio_irq_chip;
-	girq->fwnode = of_node_to_fwnode(dev->of_node);
-	girq->parent_domain =
-		irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
-	girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq;
-	girq->handler = handle_bad_irq;
-	girq->default_type = IRQ_TYPE_NONE;
-
+	chip->to_irq = thunderx_gpio_to_irq;
 	err = devm_gpiochip_add_data(dev, chip, txgpio);
 	if (err)
 		goto out;
 
-	/* Push on irq_data and the domain for each line. */
-	for (i = 0; i < ngpio; i++) {
-		err = irq_domain_push_irq(chip->irq.domain,
-					  txgpio->msix_entries[i].vector,
-					  chip);
-		if (err < 0)
-			dev_err(dev, "irq_domain_push_irq: %d\n", err);
-	}
-
 	dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
 		 ngpio, chip->base);
 	return 0;
@@ -542,10 +593,10 @@
 	struct thunderx_gpio *txgpio = pci_get_drvdata(pdev);
 
 	for (i = 0; i < txgpio->chip.ngpio; i++)
-		irq_domain_pop_irq(txgpio->chip.irq.domain,
+		irq_domain_pop_irq(txgpio->irqd,
 				   txgpio->msix_entries[i].vector);
 
-	irq_domain_remove(txgpio->chip.irq.domain);
+	irq_domain_remove(txgpio->irqd);
 
 	pci_set_drvdata(pdev, NULL);
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-timberdale.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-timberdale.c
@@ -43,9 +43,10 @@
 	unsigned offset, bool enabled)
 {
 	struct timbgpio *tgpio = gpiochip_get_data(gpio);
+	unsigned long flags;
 	u32 reg;
 
-	spin_lock(&tgpio->lock);
+	spin_lock_irqsave(&tgpio->lock, flags);
 	reg = ioread32(tgpio->membase + offset);
 
 	if (enabled)
@@ -54,7 +55,7 @@
 		reg &= ~(1 << index);
 
 	iowrite32(reg, tgpio->membase + offset);
-	spin_unlock(&tgpio->lock);
+	spin_unlock_irqrestore(&tgpio->lock, flags);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-tps68470.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tps68470.c
@@ -91,13 +91,13 @@
 	struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
 	struct regmap *regmap = tps68470_gpio->tps68470_regmap;
 
+	/* Set the initial value */
+	tps68470_gpio_set(gc, offset, value);
+
 	/* rest are always outputs */
 	if (offset >= TPS68470_N_REGULAR_GPIO)
 		return 0;
 
-	/* Set the initial value */
-	tps68470_gpio_set(gc, offset, value);
-
 	return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
 				 TPS68470_GPIO_MODE_MASK,
 				 TPS68470_GPIO_MODE_OUT_CMOS);
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-tqmx86.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-tqmx86.c
@@ -235,8 +235,8 @@
 	struct resource *res;
 	int ret, irq;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq < 0 && irq != -ENXIO)
 		return irq;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -275,7 +275,7 @@
 
 	pm_runtime_enable(&pdev->dev);
 
-	if (irq) {
+	if (irq > 0) {
 		struct irq_chip *irq_chip = &gpio->irq_chip;
 		u8 irq_status;
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-ts4900.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-ts4900.c
@@ -1,7 +1,7 @@
 /*
  * Digital I/O driver for Technologic Systems I2C FPGA Core
  *
- * Copyright (C) 2015 Technologic Systems
+ * Copyright (C) 2015, 2018 Technologic Systems
  * Copyright (C) 2016 Savoir-Faire Linux
  *
  * This program is free software; you can redistribute it and/or
@@ -52,19 +52,33 @@
 {
 	struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
 
-	/*
-	 * This will clear the output enable bit, the other bits are
-	 * dontcare when this is cleared
+	/* Only clear the OE bit here, requires a RMW. Prevents potential issue
+	 * with OE and data getting to the physical pin at different times.
 	 */
-	return regmap_write(priv->regmap, offset, 0);
+	return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);
 }
 
 static int ts4900_gpio_direction_output(struct gpio_chip *chip,
 					unsigned int offset, int value)
 {
 	struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+	unsigned int reg;
 	int ret;
 
+	/* If changing from an input to an output, we need to first set the
+	 * proper data bit to what is requested and then set OE bit. This
+	 * prevents a glitch that can occur on the IO line
+	 */
+	regmap_read(priv->regmap, offset, &reg);
+	if (!(reg & TS4900_GPIO_OE)) {
+		if (value)
+			reg = TS4900_GPIO_OUT;
+		else
+			reg &= ~TS4900_GPIO_OUT;
+
+		regmap_write(priv->regmap, offset, reg);
+	}
+
 	if (value)
 		ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
 							 TS4900_GPIO_OUT);
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-uniphier.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-uniphier.c
@@ -188,7 +188,7 @@
 
 	uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0);
 
-	return irq_chip_mask_parent(data);
+	irq_chip_mask_parent(data);
 }
 
 static void uniphier_gpio_irq_unmask(struct irq_data *data)
@@ -198,7 +198,7 @@
 
 	uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask);
 
-	return irq_chip_unmask_parent(data);
+	irq_chip_unmask_parent(data);
 }
 
 static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-vf610.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-vf610.c
@@ -125,12 +125,16 @@
 {
 	struct vf610_gpio_port *port = gpiochip_get_data(chip);
 	unsigned long mask = BIT(gpio);
-
-	if (port->sdata && port->sdata->have_paddr)
-		vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR);
+	u32 val;
 
 	vf610_gpio_set(chip, gpio, value);
 
+	if (port->sdata && port->sdata->have_paddr) {
+		val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
+		val |= mask;
+		vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
+	}
+
 	return pinctrl_gpio_direction_output(chip->base + gpio);
 }
 
@@ -300,7 +304,7 @@
 	gc = &port->gc;
 	gc->of_node = np;
 	gc->parent = dev;
-	gc->label = "vf610-gpio";
+	gc->label = dev_name(dev);
 	gc->ngpio = VF610_GPIO_PER_PORT;
 	gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-vr41xx.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-vr41xx.c
@@ -217,8 +217,6 @@
 	printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
 	       maskl, pendl, maskh, pendh);
 
-	atomic_inc(&irq_err_count);
-
 	return -EINVAL;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-winbond.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-winbond.c
@@ -385,12 +385,13 @@
 	unsigned long *base = gpiochip_get_data(gc);
 	const struct winbond_gpio_info *info;
 	bool val;
+	int ret;
 
 	winbond_gpio_get_info(&offset, &info);
 
-	val = winbond_sio_enter(*base);
-	if (val)
-		return val;
+	ret = winbond_sio_enter(*base);
+	if (ret)
+		return ret;
 
 	winbond_sio_select_logical(*base, info->dev);
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-xilinx.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-xilinx.c
@@ -147,9 +147,10 @@
 	for (i = 0; i < gc->ngpio; i++) {
 		if (*mask == 0)
 			break;
+		/* Once finished with an index write it out to the register */
 		if (index !=  xgpio_index(chip, i)) {
 			xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
-				       xgpio_regoffset(chip, i),
+				       index * XGPIO_CHANNEL_OFFSET,
 				       chip->gpio_state[index]);
 			spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
 			index =  xgpio_index(chip, i);
@@ -165,7 +166,7 @@
 	}
 
 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
-		       xgpio_regoffset(chip, i), chip->gpio_state[index]);
+		       index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]);
 
 	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-xtensa.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-xtensa.c
@@ -44,15 +44,14 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	RSR_CPENABLE(*cpenable);
-	WSR_CPENABLE(*cpenable | BIT(XCHAL_CP_ID_XTIOP));
-
+	*cpenable = xtensa_get_sr(cpenable);
+	xtensa_set_sr(*cpenable | BIT(XCHAL_CP_ID_XTIOP), cpenable);
 	return flags;
 }
 
 static inline void disable_cp(unsigned long flags, unsigned long cpenable)
 {
-	WSR_CPENABLE(cpenable);
+	xtensa_set_sr(cpenable, cpenable);
 	local_irq_restore(flags);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpio-zynq.c
+++ linux-ein-5.4.0/drivers/gpio/gpio-zynq.c
@@ -556,7 +556,7 @@
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 	int ret;
 
-	ret = pm_runtime_get_sync(chip->parent);
+	ret = pm_runtime_resume_and_get(chip->parent);
 	if (ret < 0)
 		return ret;
 
@@ -681,6 +681,8 @@
 	unsigned int bank_num;
 
 	for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
+		writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
+				ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
 		writel_relaxed(gpio->context.datalsw[bank_num],
 			       gpio->base_addr +
 			       ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num));
@@ -690,9 +692,6 @@
 		writel_relaxed(gpio->context.dirm[bank_num],
 			       gpio->base_addr +
 			       ZYNQ_GPIO_DIRM_OFFSET(bank_num));
-		writel_relaxed(gpio->context.int_en[bank_num],
-			       gpio->base_addr +
-			       ZYNQ_GPIO_INTEN_OFFSET(bank_num));
 		writel_relaxed(gpio->context.int_type[bank_num],
 			       gpio->base_addr +
 			       ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
@@ -702,6 +701,9 @@
 		writel_relaxed(gpio->context.int_any[bank_num],
 			       gpio->base_addr +
 			       ZYNQ_GPIO_INTANY_OFFSET(bank_num));
+		writel_relaxed(~(gpio->context.int_en[bank_num]),
+			       gpio->base_addr +
+			       ZYNQ_GPIO_INTEN_OFFSET(bank_num));
 	}
 }
 
@@ -882,7 +884,7 @@
 
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0)
 		goto err_pm_dis;
 
@@ -936,8 +938,11 @@
 static int zynq_gpio_remove(struct platform_device *pdev)
 {
 	struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+	int ret;
 
-	pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
+		dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n");
 	gpiochip_remove(&gpio->chip);
 	clk_disable_unprepare(gpio->clk);
 	device_set_wakeup_capable(&pdev->dev, 0);
--- linux-ein-5.4.0.orig/drivers/gpio/gpiolib-acpi.c
+++ linux-ein-5.4.0/drivers/gpio/gpiolib-acpi.c
@@ -26,6 +26,17 @@
 MODULE_PARM_DESC(run_edge_events_on_boot,
 		 "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
 
+static char *ignore_wake;
+module_param(ignore_wake, charp, 0444);
+MODULE_PARM_DESC(ignore_wake,
+		 "controller@pin combos on which to ignore the ACPI wake flag "
+		 "ignore_wake=controller@pin[,controller@pin[,...]]");
+
+struct acpi_gpiolib_dmi_quirk {
+	bool no_edge_events_on_boot;
+	char *ignore_wake;
+};
+
 /**
  * struct acpi_gpio_event - ACPI GPIO event handler data
  *
@@ -163,7 +174,7 @@
 	int ret, value;
 
 	ret = request_threaded_irq(event->irq, NULL, event->handler,
-				   event->irqflags, "ACPI:Event", event);
+				   event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
 	if (ret) {
 		dev_err(acpi_gpio->chip->parent,
 			"Failed to setup interrupt handler for %d\n",
@@ -194,6 +205,57 @@
 		acpi_gpiochip_request_irq(acpi_gpio, event);
 }
 
+static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
+{
+	const char *controller, *pin_str;
+	int len, pin;
+	char *endp;
+
+	controller = ignore_wake;
+	while (controller) {
+		pin_str = strchr(controller, '@');
+		if (!pin_str)
+			goto err;
+
+		len = pin_str - controller;
+		if (len == strlen(controller_in) &&
+		    strncmp(controller, controller_in, len) == 0) {
+			pin = simple_strtoul(pin_str + 1, &endp, 10);
+			if (*endp != 0 && *endp != ',')
+				goto err;
+
+			if (pin == pin_in)
+				return true;
+		}
+
+		controller = strchr(controller, ',');
+		if (controller)
+			controller++;
+	}
+
+	return false;
+err:
+	pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n",
+		    ignore_wake);
+	return false;
+}
+
+static bool acpi_gpio_irq_is_wake(struct device *parent,
+				  struct acpi_resource_gpio *agpio)
+{
+	int pin = agpio->pin_table[0];
+
+	if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
+		return false;
+
+	if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) {
+		dev_info(parent, "Ignoring wakeup on pin %d\n", pin);
+		return false;
+	}
+
+	return true;
+}
+
 static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 					     void *context)
 {
@@ -213,8 +275,8 @@
 	pin = agpio->pin_table[0];
 
 	if (pin <= 255) {
-		char ev_name[5];
-		sprintf(ev_name, "_%c%02hhX",
+		char ev_name[8];
+		sprintf(ev_name, "_%c%02X",
 			agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
 			pin);
 		if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
@@ -274,7 +336,7 @@
 	event->handle = evt_handle;
 	event->handler = handler;
 	event->irq = irq;
-	event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE;
+	event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
 	event->pin = pin;
 	event->desc = desc;
 
@@ -891,10 +953,17 @@
 			irq_flags = acpi_dev_get_irq_type(info.triggering,
 							  info.polarity);
 
-			/* Set type if specified and different than the current one */
-			if (irq_flags != IRQ_TYPE_NONE &&
-			    irq_flags != irq_get_trigger_type(irq))
-				irq_set_irq_type(irq, irq_flags);
+			/*
+			 * If the IRQ is not already in use then set type
+			 * if specified and different than the current one.
+			 */
+			if (can_request_irq(irq, irq_flags)) {
+				if (irq_flags != IRQ_TYPE_NONE &&
+				    irq_flags != irq_get_trigger_type(irq))
+					irq_set_irq_type(irq, irq_flags);
+			} else {
+				dev_dbg(&adev->dev, "IRQ %d already in use\n", irq);
+			}
 
 			return irq;
 		}
@@ -1302,7 +1371,7 @@
 /* We must use _sync so that this runs after the first deferred_probe run */
 late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
 
-static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = {
+static const struct dmi_system_id gpiolib_acpi_quirks[] = {
 	{
 		/*
 		 * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for
@@ -1312,7 +1381,10 @@
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
-		}
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.no_edge_events_on_boot = true,
+		},
 	},
 	{
 		/*
@@ -1324,20 +1396,112 @@
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
-		}
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.no_edge_events_on_boot = true,
+		},
+	},
+	{
+		/*
+		 * The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
+		 * external embedded-controller connected via I2C + an ACPI GPIO
+		 * event handler on INT33FFC:02 pin 12, causing spurious wakeups.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.ignore_wake = "INT33FC:02@12",
+		},
+	},
+	{
+		/*
+		 * HP X2 10 models with Cherry Trail SoC + TI PMIC use an
+		 * external embedded-controller connected via I2C + an ACPI GPIO
+		 * event handler on INT33FF:01 pin 0, causing spurious wakeups.
+		 * When suspending by closing the LID, the power to the USB
+		 * keyboard is turned off, causing INT0002 ACPI events to
+		 * trigger once the XHCI controller notices the keyboard is
+		 * gone. So INT0002 events cause spurious wakeups too. Ignoring
+		 * EC wakes breaks wakeup when opening the lid, the user needs
+		 * to press the power-button to wakeup the system. The
+		 * alternative is suspend simply not working, which is worse.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.ignore_wake = "INT33FF:01@0,INT0002:00@2",
+		},
+	},
+	{
+		/*
+		 * HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
+		 * external embedded-controller connected via I2C + an ACPI GPIO
+		 * event handler on INT33FC:02 pin 28, causing spurious wakeups.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+			DMI_MATCH(DMI_BOARD_NAME, "815D"),
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.ignore_wake = "INT33FC:02@28",
+		},
+	},
+	{
+		/*
+		 * HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
+		 * external embedded-controller connected via I2C + an ACPI GPIO
+		 * event handler on INT33FF:01 pin 0, causing spurious wakeups.
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+			DMI_MATCH(DMI_BOARD_NAME, "813E"),
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.ignore_wake = "INT33FF:01@0",
+		},
+	},
+	{
+		/*
+		 * Spurious wakeups from TP_ATTN# pin
+		 * Found in BIOS 0.35
+		 * https://gitlab.freedesktop.org/drm/amd/-/issues/3073
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
+		},
+		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+			.ignore_wake = "PNP0C50:00@8",
+		},
 	},
 	{} /* Terminating entry */
 };
 
 static int acpi_gpio_setup_params(void)
 {
+	const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
+	const struct dmi_system_id *id;
+
+	id = dmi_first_match(gpiolib_acpi_quirks);
+	if (id)
+		quirk = id->driver_data;
+
 	if (run_edge_events_on_boot < 0) {
-		if (dmi_check_system(run_edge_events_on_boot_blacklist))
+		if (quirk && quirk->no_edge_events_on_boot)
 			run_edge_events_on_boot = 0;
 		else
 			run_edge_events_on_boot = 1;
 	}
 
+	if (ignore_wake == NULL && quirk && quirk->ignore_wake)
+		ignore_wake = quirk->ignore_wake;
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpio/gpiolib-of.c
+++ linux-ein-5.4.0/drivers/gpio/gpiolib-of.c
@@ -23,6 +23,29 @@
 #include "gpiolib.h"
 #include "gpiolib-of.h"
 
+/**
+ * of_gpio_spi_cs_get_count() - special GPIO counting for SPI
+ * Some elder GPIO controllers need special quirks. Currently we handle
+ * the Freescale GPIO controller with bindings that doesn't use the
+ * established "cs-gpios" for chip selects but instead rely on
+ * "gpios" for the chip select lines. If we detect this, we redirect
+ * the counting of "cs-gpios" to count "gpios" transparent to the
+ * driver.
+ */
+int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
+{
+	struct device_node *np = dev->of_node;
+
+	if (!IS_ENABLED(CONFIG_SPI_MASTER))
+		return 0;
+	if (!con_id || strcmp(con_id, "cs"))
+		return 0;
+	if (!of_device_is_compatible(np, "fsl,spi") &&
+	    !of_device_is_compatible(np, "aeroflexgaisler,spictrl"))
+		return 0;
+	return of_gpio_named_count(np, "gpios");
+}
+
 /*
  * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
  *
@@ -35,6 +58,10 @@
 	char propname[32];
 	unsigned int i;
 
+	ret = of_gpio_spi_cs_get_count(dev, con_id);
+	if (ret > 0)
+		return ret;
+
 	for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
 		if (con_id)
 			snprintf(propname, sizeof(propname), "%s-%s",
@@ -119,10 +146,6 @@
 			if (of_property_read_bool(np, "cd-inverted"))
 				*flags ^= OF_GPIO_ACTIVE_LOW;
 		}
-		if (!strcmp(propname, "wp-gpios")) {
-			if (of_property_read_bool(np, "wp-inverted"))
-				*flags ^= OF_GPIO_ACTIVE_LOW;
-		}
 	}
 	/*
 	 * Some GPIO fixed regulator quirks.
@@ -711,7 +734,8 @@
 	if (mm_gc->save_regs)
 		mm_gc->save_regs(mm_gc);
 
-	mm_gc->gc.of_node = np;
+	of_node_put(mm_gc->gc.of_node);
+	mm_gc->gc.of_node = of_node_get(np);
 
 	ret = gpiochip_add_data(gc, data);
 	if (ret)
@@ -719,6 +743,7 @@
 
 	return 0;
 err2:
+	of_node_put(np);
 	iounmap(mm_gc->regs);
 err1:
 	kfree(gc->label);
@@ -760,7 +785,7 @@
 					   i, &start);
 		of_property_read_u32_index(np, "gpio-reserved-ranges",
 					   i + 1, &count);
-		if (start >= chip->ngpio || start + count >= chip->ngpio)
+		if (start >= chip->ngpio || start + count > chip->ngpio)
 			continue;
 
 		bitmap_clear(chip->valid_mask, start, count);
@@ -882,16 +907,13 @@
 	of_node_get(chip->of_node);
 
 	ret = of_gpiochip_scan_gpios(chip);
-	if (ret) {
+	if (ret)
 		of_node_put(chip->of_node);
-		gpiochip_remove_pin_ranges(chip);
-	}
 
 	return ret;
 }
 
 void of_gpiochip_remove(struct gpio_chip *chip)
 {
-	gpiochip_remove_pin_ranges(chip);
 	of_node_put(chip->of_node);
 }
--- linux-ein-5.4.0.orig/drivers/gpio/gpiolib-sysfs.c
+++ linux-ein-5.4.0/drivers/gpio/gpiolib-sysfs.c
@@ -457,6 +457,8 @@
 	long			gpio;
 	struct gpio_desc	*desc;
 	int			status;
+	struct gpio_chip	*gc;
+	int			offset;
 
 	status = kstrtol(buf, 0, &gpio);
 	if (status < 0)
@@ -468,6 +470,12 @@
 		pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
 		return -EINVAL;
 	}
+	gc = desc->gdev->chip;
+	offset = gpio_chip_hwgpio(desc);
+	if (!gpiochip_line_is_valid(gc, offset)) {
+		pr_warn("%s: GPIO %ld masked\n", __func__, gpio);
+		return -EINVAL;
+	}
 
 	/* No extra locking here; FLAG_SYSFS just signifies that the
 	 * request and export were done by on behalf of userspace, so
@@ -482,14 +490,17 @@
 	}
 
 	status = gpiod_set_transitory(desc, false);
-	if (!status) {
-		status = gpiod_export(desc, true);
-		if (status < 0)
-			gpiod_free(desc);
-		else
-			set_bit(FLAG_SYSFS, &desc->flags);
+	if (status) {
+		gpiod_free(desc);
+		goto done;
 	}
 
+	status = gpiod_export(desc, true);
+	if (status < 0)
+		gpiod_free(desc);
+	else
+		set_bit(FLAG_SYSFS, &desc->flags);
+
 done:
 	if (status)
 		pr_debug("%s: status %d\n", __func__, status);
--- linux-ein-5.4.0.orig/drivers/gpio/gpiolib.c
+++ linux-ein-5.4.0/drivers/gpio/gpiolib.c
@@ -220,6 +220,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 -ENOTSUPP;
 
@@ -1444,6 +1452,7 @@
 	gpiochip_free_hogs(chip);
 	of_gpiochip_remove(chip);
 err_free_gpiochip_mask:
+	gpiochip_remove_pin_ranges(chip);
 	gpiochip_free_valid_mask(chip);
 err_remove_from_list:
 	spin_lock_irqsave(&gpio_lock, flags);
@@ -1499,8 +1508,8 @@
 	gdev->chip = NULL;
 	gpiochip_irqchip_remove(chip);
 	acpi_gpiochip_remove(chip);
-	gpiochip_remove_pin_ranges(chip);
 	of_gpiochip_remove(chip);
+	gpiochip_remove_pin_ranges(chip);
 	gpiochip_free_valid_mask(chip);
 	/*
 	 * We accept no more calls into the driver from this point, so
@@ -1915,6 +1924,7 @@
 				     parent_type);
 	chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
 		  irq, parent_hwirq);
+	irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
 	ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec);
 	if (ret)
 		chip_err(gc,
@@ -2184,9 +2194,16 @@
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
+	/*
+	 * Since we override .irq_disable() we need to mimic the
+	 * behaviour of __irq_disable() in irq/chip.c.
+	 * First call .irq_disable() if it exists, else mimic the
+	 * behaviour of mask_irq() which calls .irq_mask() if
+	 * it exists.
+	 */
 	if (chip->irq.irq_disable)
 		chip->irq.irq_disable(d);
-	else
+	else if (chip->irq.chip->irq_mask)
 		chip->irq.chip->irq_mask(d);
 	gpiochip_disable_irq(chip, d->hwirq);
 }
@@ -3211,6 +3228,17 @@
 }
 EXPORT_SYMBOL_GPL(gpiod_is_active_low);
 
+/**
+ * gpiod_toggle_active_low - toggle whether a GPIO is active-low or not
+ * @desc: the gpio descriptor to change
+ */
+void gpiod_toggle_active_low(struct gpio_desc *desc)
+{
+	VALIDATE_DESC_VOID(desc);
+	change_bit(FLAG_ACTIVE_LOW, &desc->flags);
+}
+EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
+
 /* I/O calls are only valid after configuration completed; the relevant
  * "is this a valid GPIO" error checks should already have been done.
  *
@@ -3866,7 +3894,9 @@
 		}
 	}
 
-	if (test_bit(FLAG_IS_OUT, &desc->flags)) {
+	/* To be valid for IRQ the line needs to be input or open drain */
+	if (test_bit(FLAG_IS_OUT, &desc->flags) &&
+	    !test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
 		chip_err(chip,
 			 "%s: tried to flag a GPIO set as output for IRQ\n",
 			 __func__);
@@ -3929,7 +3959,12 @@
 
 	if (!IS_ERR(desc) &&
 	    !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) {
-		WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags));
+		/*
+		 * We must not be output when using IRQ UNLESS we are
+		 * open drain.
+		 */
+		WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags) &&
+			!test_bit(FLAG_OPEN_DRAIN, &desc->flags));
 		set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
 	}
 }
@@ -4320,8 +4355,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);
 		}
 
--- linux-ein-5.4.0.orig/drivers/gpio/sgpio-aspeed.c
+++ linux-ein-5.4.0/drivers/gpio/sgpio-aspeed.c
@@ -17,7 +17,17 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
-#define MAX_NR_SGPIO			80
+/*
+ * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
+ * slots within the clocked serial GPIO data). Since each HW GPIO is both an
+ * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
+ * device.
+ *
+ * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
+ * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
+ */
+#define MAX_NR_HW_SGPIO			80
+#define SGPIO_OUTPUT_OFFSET		MAX_NR_HW_SGPIO
 
 #define ASPEED_SGPIO_CTRL		0x54
 
@@ -30,8 +40,8 @@
 	struct clk *pclk;
 	spinlock_t lock;
 	void __iomem *base;
-	uint32_t dir_in[3];
 	int irq;
+	int n_sgpio;
 };
 
 struct aspeed_sgpio_bank {
@@ -107,35 +117,73 @@
 		return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
 	default:
 		/* acturally if code runs to here, it's an error case */
-		BUG_ON(1);
+		BUG();
 	}
 }
 
-#define GPIO_BANK(x)    ((x) >> 5)
-#define GPIO_OFFSET(x)  ((x) & 0x1f)
+#define GPIO_BANK(x)    ((x % SGPIO_OUTPUT_OFFSET) >> 5)
+#define GPIO_OFFSET(x)  ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
 #define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
 
 static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
 {
-	unsigned int bank = GPIO_BANK(offset);
+	unsigned int bank;
+
+	bank = GPIO_BANK(offset);
 
 	WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
 	return &aspeed_sgpio_banks[bank];
 }
 
+static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
+		unsigned long *valid_mask, unsigned int ngpios)
+{
+	struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+	int n = sgpio->n_sgpio;
+	int c = SGPIO_OUTPUT_OFFSET - n;
+
+	WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+	/* input GPIOs in the lower range */
+	bitmap_set(valid_mask, 0, n);
+	bitmap_clear(valid_mask, n, c);
+
+	/* output GPIOS above SGPIO_OUTPUT_OFFSET */
+	bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
+	bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
+
+	return 0;
+}
+
+static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
+		unsigned long *valid_mask, unsigned int ngpios)
+{
+	struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+	int n = sgpio->n_sgpio;
+
+	WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+	/* input GPIOs in the lower range */
+	bitmap_set(valid_mask, 0, n);
+	bitmap_clear(valid_mask, n, ngpios - n);
+}
+
+static bool aspeed_sgpio_is_input(unsigned int offset)
+{
+	return offset < SGPIO_OUTPUT_OFFSET;
+}
+
 static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
 {
 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
 	const struct aspeed_sgpio_bank *bank = to_bank(offset);
 	unsigned long flags;
 	enum aspeed_sgpio_reg reg;
-	bool is_input;
 	int rc = 0;
 
 	spin_lock_irqsave(&gpio->lock, flags);
 
-	is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-	reg = is_input ? reg_val : reg_rdata;
+	reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
 	rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
 
 	spin_unlock_irqrestore(&gpio->lock, flags);
@@ -143,22 +191,31 @@
 	return rc;
 }
 
-static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
 {
 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
 	const struct aspeed_sgpio_bank *bank = to_bank(offset);
-	void __iomem *addr;
+	void __iomem *addr_r, *addr_w;
 	u32 reg = 0;
 
-	addr = bank_reg(gpio, bank, reg_val);
-	reg = ioread32(addr);
+	if (aspeed_sgpio_is_input(offset))
+		return -EINVAL;
+
+	/* Since this is an output, read the cached value from rdata, then
+	 * update val. */
+	addr_r = bank_reg(gpio, bank, reg_rdata);
+	addr_w = bank_reg(gpio, bank, reg_val);
+
+	reg = ioread32(addr_r);
 
 	if (val)
 		reg |= GPIO_BIT(offset);
 	else
 		reg &= ~GPIO_BIT(offset);
 
-	iowrite32(reg, addr);
+	iowrite32(reg, addr_w);
+
+	return 0;
 }
 
 static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
@@ -175,43 +232,28 @@
 
 static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
 {
-	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-	unsigned long flags;
-
-	spin_lock_irqsave(&gpio->lock, flags);
-	gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
-
-	return 0;
+	return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
 }
 
 static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
 {
 	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
 	unsigned long flags;
+	int rc;
 
-	spin_lock_irqsave(&gpio->lock, flags);
-
-	gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
-	sgpio_set_value(gc, offset, val);
+	/* No special action is required for setting the direction; we'll
+	 * error-out in sgpio_set_value if this isn't an output GPIO */
 
+	spin_lock_irqsave(&gpio->lock, flags);
+	rc = sgpio_set_value(gc, offset, val);
 	spin_unlock_irqrestore(&gpio->lock, flags);
 
-	return 0;
+	return rc;
 }
 
 static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
 {
-	int dir_status;
-	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-	unsigned long flags;
-
-	spin_lock_irqsave(&gpio->lock, flags);
-	dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-	spin_unlock_irqrestore(&gpio->lock, flags);
-
-	return dir_status;
-
+	return !!aspeed_sgpio_is_input(offset);
 }
 
 static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
@@ -402,6 +444,7 @@
 
 	irq = &gpio->chip.irq;
 	irq->chip = &aspeed_sgpio_irqchip;
+	irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
 	irq->handler = handle_bad_irq;
 	irq->default_type = IRQ_TYPE_NONE;
 	irq->parent_handler = aspeed_sgpio_irq_handler;
@@ -409,17 +452,15 @@
 	irq->parents = &gpio->irq;
 	irq->num_parents = 1;
 
-	/* set IRQ settings and Enable Interrupt */
+	/* Apply default IRQ settings */
 	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
 		bank = &aspeed_sgpio_banks[i];
 		/* set falling or level-low irq */
 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
 		/* trigger type is edge */
 		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
-		/* dual edge trigger mode. */
-		iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
-		/* enable irq */
-		iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+		/* single edge trigger */
+		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
 	}
 
 	return 0;
@@ -452,11 +493,12 @@
 	if (rc < 0) {
 		dev_err(&pdev->dev, "Could not read ngpios property\n");
 		return -EINVAL;
-	} else if (nr_gpios > MAX_NR_SGPIO) {
+	} else if (nr_gpios > MAX_NR_HW_SGPIO) {
 		dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
-			MAX_NR_SGPIO, nr_gpios);
+			MAX_NR_HW_SGPIO, nr_gpios);
 		return -EINVAL;
 	}
+	gpio->n_sgpio = nr_gpios;
 
 	rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
 	if (rc < 0) {
@@ -497,7 +539,8 @@
 	spin_lock_init(&gpio->lock);
 
 	gpio->chip.parent = &pdev->dev;
-	gpio->chip.ngpio = nr_gpios;
+	gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
+	gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
 	gpio->chip.direction_input = aspeed_sgpio_dir_in;
 	gpio->chip.direction_output = aspeed_sgpio_dir_out;
 	gpio->chip.get_direction = aspeed_sgpio_get_direction;
@@ -509,9 +552,6 @@
 	gpio->chip.label = dev_name(&pdev->dev);
 	gpio->chip.base = -1;
 
-	/* set all SGPIO pins as input (1). */
-	memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
-
 	aspeed_sgpio_setup_irqs(gpio, pdev);
 
 	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
--- linux-ein-5.4.0.orig/drivers/gpu/Makefile
+++ linux-ein-5.4.0/drivers/gpu/Makefile
@@ -3,5 +3,6 @@
 # taken to initialize them in the correct order. Link order is the only way
 # to ensure this currently.
 obj-$(CONFIG_TEGRA_HOST1X)	+= host1x/
+obj-y			+= imx/
 obj-y			+= drm/ vga/
 obj-$(CONFIG_IMX_IPUV3_CORE)	+= ipu-v3/
--- linux-ein-5.4.0.orig/drivers/gpu/drm/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/Kconfig
@@ -27,6 +27,7 @@
 config DRM_MIPI_DBI
 	tristate
 	depends on DRM
+	select DRM_KMS_HELPER
 
 config DRM_MIPI_DSI
 	bool
@@ -206,6 +207,7 @@
 config DRM_RADEON
 	tristate "ATI Radeon"
 	depends on DRM && PCI && MMU
+	depends on AGP || !AGP
 	select FW_LOADER
         select DRM_KMS_HELPER
         select DRM_TTM
--- linux-ein-5.4.0.orig/drivers/gpu/drm/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/Makefile
@@ -98,7 +98,7 @@
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STM) += stm/
 obj-$(CONFIG_DRM_STI) += sti/
-obj-$(CONFIG_DRM_IMX) += imx/
+obj-y 			+= imx/
 obj-$(CONFIG_DRM_INGENIC) += ingenic/
 obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
 obj-$(CONFIG_DRM_MESON)	+= meson/
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/ObjectID.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/ObjectID.h
@@ -119,6 +119,7 @@
 #define CONNECTOR_OBJECT_ID_eDP                   0x14
 #define CONNECTOR_OBJECT_ID_MXM                   0x15
 #define CONNECTOR_OBJECT_ID_LVDS_eDP              0x16
+#define CONNECTOR_OBJECT_ID_USBC                  0x17
 
 /* deleted */
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -762,7 +762,7 @@
 	MAX_HWIP
 };
 
-#define HWIP_MAX_INSTANCE	8
+#define HWIP_MAX_INSTANCE	10
 
 struct amd_powerplay {
 	void *pp_handle;
@@ -813,6 +813,7 @@
 	uint8_t				*bios;
 	uint32_t			bios_size;
 	struct amdgpu_bo		*stolen_vga_memory;
+	struct amdgpu_bo		*discovery_memory;
 	uint32_t			bios_scratch_reg_offset;
 	uint32_t			bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -163,17 +163,28 @@
 	return 0;
 }
 
-static struct device *get_mfd_cell_dev(const char *device_name, int r)
+static int acp_genpd_add_device(struct device *dev, void *data)
 {
-	char auto_dev_name[25];
-	struct device *dev;
+	struct generic_pm_domain *gpd = data;
+	int ret;
 
-	snprintf(auto_dev_name, sizeof(auto_dev_name),
-		 "%s.%d.auto", device_name, r);
-	dev = bus_find_device_by_name(&platform_bus_type, NULL, auto_dev_name);
-	dev_info(dev, "device %s added to pm domain\n", auto_dev_name);
+	ret = pm_genpd_add_device(gpd, dev);
+	if (ret)
+		dev_err(dev, "Failed to add dev to genpd %d\n", ret);
 
-	return dev;
+	return ret;
+}
+
+static int acp_genpd_remove_device(struct device *dev, void *data)
+{
+	int ret;
+
+	ret = pm_genpd_remove_device(dev);
+	if (ret)
+		dev_err(dev, "Failed to remove dev from genpd %d\n", ret);
+
+	/* Continue to remove */
+	return 0;
 }
 
 /**
@@ -184,11 +195,10 @@
  */
 static int acp_hw_init(void *handle)
 {
-	int r, i;
+	int r;
 	uint64_t acp_base;
 	u32 val = 0;
 	u32 count = 0;
-	struct device *dev;
 	struct i2s_platform_data *i2s_pdata = NULL;
 
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -344,15 +354,10 @@
 	if (r)
 		goto failure;
 
-	for (i = 0; i < ACP_DEVS ; i++) {
-		dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i);
-		r = pm_genpd_add_device(&adev->acp.acp_genpd->gpd, dev);
-		if (r) {
-			dev_err(dev, "Failed to add dev to genpd\n");
-			goto failure;
-		}
-	}
-
+	r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
+				  acp_genpd_add_device);
+	if (r)
+		goto failure;
 
 	/* Assert Soft reset of ACP */
 	val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
@@ -413,10 +418,8 @@
  */
 static int acp_hw_fini(void *handle)
 {
-	int i, ret;
 	u32 val = 0;
 	u32 count = 0;
-	struct device *dev;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
 	/* return early if no ACP */
@@ -461,13 +464,8 @@
 		udelay(100);
 	}
 
-	for (i = 0; i < ACP_DEVS ; i++) {
-		dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i);
-		ret = pm_genpd_remove_device(dev);
-		/* If removal fails, dont giveup and try rest */
-		if (ret)
-			dev_err(dev, "remove dev from genpd failed\n");
-	}
+	device_for_each_child(adev->acp.parent, NULL,
+			      acp_genpd_remove_device);
 
 	mfd_remove_devices(adev->acp.parent);
 	kfree(adev->acp.acp_res);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
@@ -88,7 +88,7 @@
 		return NULL;
 
 	fence = container_of(f, struct amdgpu_amdkfd_fence, base);
-	if (fence && f->ops == &amdkfd_fence_ops)
+	if (f->ops == &amdkfd_fence_ops)
 		return fence;
 
 	return NULL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
@@ -165,7 +165,7 @@
 	.get_tile_config = amdgpu_amdkfd_get_tile_config,
 };
 
-struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions()
+struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void)
 {
 	return (struct kfd2kgd_calls *)&kfd2kgd;
 }
@@ -644,6 +644,9 @@
 	uint32_t temp;
 	struct v10_compute_mqd *m = get_mqd(mqd);
 
+	if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset)
+		return 0;
+
 #if 0
 	unsigned long flags;
 	int retry;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
@@ -540,6 +540,9 @@
 	uint32_t temp;
 	struct v9_mqd *m = get_mqd(mqd);
 
+	if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset)
+		return 0;
+
 	if (adev->in_gpu_reset)
 		return -EIO;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -55,12 +55,6 @@
 	spinlock_t mem_limit_lock;
 } kfd_mem_limit;
 
-/* Struct used for amdgpu_amdkfd_bo_validate */
-struct amdgpu_vm_parser {
-	uint32_t        domain;
-	bool            wait;
-};
-
 static const char * const domain_bit_to_string[] = {
 		"CPU",
 		"GTT",
@@ -293,11 +287,9 @@
 	return ret;
 }
 
-static int amdgpu_amdkfd_validate(void *param, struct amdgpu_bo *bo)
+static int amdgpu_amdkfd_validate_vm_bo(void *_unused, struct amdgpu_bo *bo)
 {
-	struct amdgpu_vm_parser *p = param;
-
-	return amdgpu_amdkfd_bo_validate(bo, p->domain, p->wait);
+	return amdgpu_amdkfd_bo_validate(bo, bo->allowed_domains, false);
 }
 
 /* vm_validate_pt_pd_bos - Validate page table and directory BOs
@@ -311,20 +303,15 @@
 {
 	struct amdgpu_bo *pd = vm->root.base.bo;
 	struct amdgpu_device *adev = amdgpu_ttm_adev(pd->tbo.bdev);
-	struct amdgpu_vm_parser param;
 	int ret;
 
-	param.domain = AMDGPU_GEM_DOMAIN_VRAM;
-	param.wait = false;
-
-	ret = amdgpu_vm_validate_pt_bos(adev, vm, amdgpu_amdkfd_validate,
-					&param);
+	ret = amdgpu_vm_validate_pt_bos(adev, vm, amdgpu_amdkfd_validate_vm_bo, NULL);
 	if (ret) {
 		pr_err("amdgpu: failed to validate PT BOs\n");
 		return ret;
 	}
 
-	ret = amdgpu_amdkfd_validate(&param, pd);
+	ret = amdgpu_amdkfd_validate_vm_bo(NULL, pd);
 	if (ret) {
 		pr_err("amdgpu: failed to validate PD\n");
 		return ret;
@@ -964,11 +951,15 @@
 					   struct dma_fence **ef)
 {
 	struct amdgpu_device *adev = get_amdgpu_device(kgd);
-	struct drm_file *drm_priv = filp->private_data;
-	struct amdgpu_fpriv *drv_priv = drm_priv->driver_priv;
-	struct amdgpu_vm *avm = &drv_priv->vm;
+	struct amdgpu_fpriv *drv_priv;
+	struct amdgpu_vm *avm;
 	int ret;
 
+	ret = amdgpu_file_to_fpriv(filp, &drv_priv);
+	if (ret)
+		return ret;
+	avm = &drv_priv->vm;
+
 	/* Already a compute VM? */
 	if (avm->process_info)
 		return -EINVAL;
@@ -1247,15 +1238,15 @@
 	 * be freed anyway
 	 */
 
-	/* No more MMU notifiers */
-	amdgpu_mn_unregister(mem->bo);
-
 	/* Make sure restore workers don't access the BO any more */
 	bo_list_entry = &mem->validate_list;
 	mutex_lock(&process_info->lock);
 	list_del(&bo_list_entry->head);
 	mutex_unlock(&process_info->lock);
 
+	/* No more MMU notifiers */
+	amdgpu_mn_unregister(mem->bo);
+
 	ret = reserve_bo_and_cond_vms(mem, NULL, BO_VM_ALL, &ctx);
 	if (unlikely(ret))
 		return ret;
@@ -1288,7 +1279,7 @@
 	}
 
 	/* Free the BO*/
-	amdgpu_bo_unref(&mem->bo);
+	drm_gem_object_put_unlocked(&mem->bo->tbo.base);
 	mutex_destroy(&mem->lock);
 	kfree(mem);
 
@@ -1630,7 +1621,8 @@
 		AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
 		AMDGPU_VM_PAGE_EXECUTABLE | AMDGPU_VM_MTYPE_NC;
 
-	(*mem)->bo = amdgpu_bo_ref(bo);
+	drm_gem_object_get(&bo->tbo.base);
+	(*mem)->bo = bo;
 	(*mem)->va = va;
 	(*mem)->domain = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
 		AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
@@ -338,17 +338,9 @@
 		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) ==
@@ -373,15 +365,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;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
@@ -150,6 +150,7 @@
 				(mode_info->atom_context->bios + data_offset);
 			switch (crev) {
 			case 11:
+			case 12:
 				mem_channel_number = igp_info->v11.umachannelnumber;
 				/* channel width is 64 */
 				return mem_channel_number * 64;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -192,30 +192,35 @@
 
 static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
 {
-	uint8_t __iomem *bios;
-	size_t size;
+	phys_addr_t rom = adev->pdev->rom;
+	size_t romlen = adev->pdev->romlen;
+	void __iomem *bios;
 
 	adev->bios = NULL;
 
-	bios = pci_platform_rom(adev->pdev, &size);
-	if (!bios) {
+	if (!rom || romlen == 0)
 		return false;
-	}
 
-	adev->bios = kzalloc(size, GFP_KERNEL);
-	if (adev->bios == NULL)
+	adev->bios = kzalloc(romlen, GFP_KERNEL);
+	if (!adev->bios)
 		return false;
 
-	memcpy_fromio(adev->bios, bios, size);
+	bios = ioremap(rom, romlen);
+	if (!bios)
+		goto free_bios;
 
-	if (!check_atom_bios(adev->bios, size)) {
-		kfree(adev->bios);
-		return false;
-	}
+	memcpy_fromio(adev->bios, bios, romlen);
+	iounmap(bios);
+
+	if (!check_atom_bios(adev->bios, romlen))
+		goto free_bios;
 
-	adev->bios_size = size;
+	adev->bios_size = romlen;
 
 	return true;
+free_bios:
+	kfree(adev->bios);
+	return false;
 }
 
 #ifdef CONFIG_ACPI
@@ -308,6 +313,7 @@
 
 	if (!found)
 		return false;
+	pci_dev_put(pdev);
 
 	adev->bios = kmalloc(size, GFP_KERNEL);
 	if (!adev->bios) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -61,7 +61,7 @@
 
 int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
 			  struct drm_amdgpu_bo_list_entry *info,
-			  unsigned num_entries, struct amdgpu_bo_list **result)
+			  size_t num_entries, struct amdgpu_bo_list **result)
 {
 	unsigned last_entry = 0, first_userptr = num_entries;
 	struct amdgpu_bo_list_entry *array;
@@ -178,6 +178,7 @@
 	}
 
 	rcu_read_unlock();
+	*result = NULL;
 	return -ENOENT;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
@@ -60,7 +60,7 @@
 int amdgpu_bo_list_create(struct amdgpu_device *adev,
 				 struct drm_file *filp,
 				 struct drm_amdgpu_bo_list_entry *info,
-				 unsigned num_entries,
+				 size_t num_entries,
 				 struct amdgpu_bo_list **list);
 
 static inline struct amdgpu_bo_list_entry *
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -316,8 +316,10 @@
 	if (!amdgpu_connector->edid) {
 		/* some laptops provide a hardcoded edid in rom for LCDs */
 		if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
-		     (connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
+		     (connector->connector_type == DRM_MODE_CONNECTOR_eDP))) {
 			amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev);
+			drm_connector_update_edid_property(connector, amdgpu_connector->edid);
+		}
 	}
 }
 
@@ -389,6 +391,9 @@
 	    native_mode->vdisplay != 0 &&
 	    native_mode->clock != 0) {
 		mode = drm_mode_duplicate(dev, native_mode);
+		if (!mode)
+			return NULL;
+
 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
 		drm_mode_set_name(mode);
 
@@ -403,6 +408,9 @@
 		 * simpler.
 		 */
 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
+		if (!mode)
+			return NULL;
+
 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
 	}
@@ -719,8 +727,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (encoder) {
@@ -827,6 +837,7 @@
 
 	amdgpu_connector_get_edid(connector);
 	ret = amdgpu_connector_ddc_get_modes(connector);
+	amdgpu_get_native_mode(connector);
 
 	return ret;
 }
@@ -857,8 +868,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	encoder = amdgpu_connector_best_single_encoder(connector);
@@ -980,8 +993,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
@@ -1330,8 +1345,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
@@ -1631,10 +1648,12 @@
 						   adev->mode_info.dither_property,
 						   AMDGPU_FMT_DITHER_DISABLE);
 
-			if (amdgpu_audio != 0)
+			if (amdgpu_audio != 0) {
 				drm_object_attach_property(&amdgpu_connector->base.base,
 							   adev->mode_info.audio_property,
 							   AMDGPU_AUDIO_AUTO);
+				amdgpu_connector->audio = AMDGPU_AUDIO_AUTO;
+			}
 
 			subpixel_order = SubPixelHorizontalRGB;
 			connector->interlace_allowed = true;
@@ -1756,6 +1775,7 @@
 				drm_object_attach_property(&amdgpu_connector->base.base,
 							   adev->mode_info.audio_property,
 							   AMDGPU_AUDIO_AUTO);
+				amdgpu_connector->audio = AMDGPU_AUDIO_AUTO;
 			}
 			drm_object_attach_property(&amdgpu_connector->base.base,
 						   adev->mode_info.dither_property,
@@ -1809,6 +1829,7 @@
 				drm_object_attach_property(&amdgpu_connector->base.base,
 							   adev->mode_info.audio_property,
 							   AMDGPU_AUDIO_AUTO);
+				amdgpu_connector->audio = AMDGPU_AUDIO_AUTO;
 			}
 			drm_object_attach_property(&amdgpu_connector->base.base,
 						   adev->mode_info.dither_property,
@@ -1859,6 +1880,7 @@
 				drm_object_attach_property(&amdgpu_connector->base.base,
 							   adev->mode_info.audio_property,
 							   AMDGPU_AUDIO_AUTO);
+				amdgpu_connector->audio = AMDGPU_AUDIO_AUTO;
 			}
 			drm_object_attach_property(&amdgpu_connector->base.base,
 						   adev->mode_info.dither_property,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -43,7 +43,6 @@
 	struct drm_gem_object *gobj;
 	struct amdgpu_bo *bo;
 	unsigned long size;
-	int r;
 
 	gobj = drm_gem_object_lookup(p->filp, data->handle);
 	if (gobj == NULL)
@@ -58,23 +57,14 @@
 	drm_gem_object_put_unlocked(gobj);
 
 	size = amdgpu_bo_size(bo);
-	if (size != PAGE_SIZE || (data->offset + 8) > size) {
-		r = -EINVAL;
-		goto error_unref;
-	}
+	if (size != PAGE_SIZE || data->offset > (size - 8))
+		return -EINVAL;
 
-	if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) {
-		r = -EINVAL;
-		goto error_unref;
-	}
+	if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm))
+		return -EINVAL;
 
 	*offset = data->offset;
-
 	return 0;
-
-error_unref:
-	amdgpu_bo_unref(&bo);
-	return r;
 }
 
 static int amdgpu_cs_bo_handles_chunk(struct amdgpu_cs_parser *p,
@@ -114,7 +104,7 @@
 	int ret;
 
 	if (cs->in.num_chunks == 0)
-		return 0;
+		return -EINVAL;
 
 	chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
 	if (!chunk_array)
@@ -151,7 +141,7 @@
 	}
 
 	for (i = 0; i < p->nchunks; i++) {
-		struct drm_amdgpu_cs_chunk __user **chunk_ptr = NULL;
+		struct drm_amdgpu_cs_chunk __user *chunk_ptr = NULL;
 		struct drm_amdgpu_cs_chunk user_chunk;
 		uint32_t __user *cdata;
 
@@ -1542,6 +1532,7 @@
 		return 0;
 
 	default:
+		dma_fence_put(fence);
 		return -EINVAL;
 	}
 }
@@ -1574,15 +1565,15 @@
 			continue;
 
 		r = dma_fence_wait_timeout(fence, true, timeout);
+		if (r > 0 && fence->error)
+			r = fence->error;
+
 		dma_fence_put(fence);
 		if (r < 0)
 			return r;
 
 		if (r == 0)
 			break;
-
-		if (fence->error)
-			return fence->error;
 	}
 
 	memset(wait, 0, sizeof(*wait));
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -351,7 +351,6 @@
 {
 	struct amdgpu_ctx *ctx;
 	struct amdgpu_ctx_mgr *mgr;
-	unsigned long ras_counter;
 
 	if (!fpriv)
 		return -EINVAL;
@@ -376,21 +375,6 @@
 	if (atomic_read(&ctx->guilty))
 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY;
 
-	/*query ue count*/
-	ras_counter = amdgpu_ras_query_error_count(adev, false);
-	/*ras counter is monotonic increasing*/
-	if (ras_counter != ctx->ras_counter_ue) {
-		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_UE;
-		ctx->ras_counter_ue = ras_counter;
-	}
-
-	/*query ce count*/
-	ras_counter = amdgpu_ras_query_error_count(adev, true);
-	if (ras_counter != ctx->ras_counter_ce) {
-		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_CE;
-		ctx->ras_counter_ce = ras_counter;
-	}
-
 	mutex_unlock(&mgr->lock);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -240,7 +240,7 @@
 	while (size) {
 		uint32_t value;
 
-		value = RREG32_PCIE(*pos >> 2);
+		value = RREG32_PCIE(*pos);
 		r = put_user(value, (uint32_t *)buf);
 		if (r)
 			return r;
@@ -283,7 +283,7 @@
 		if (r)
 			return r;
 
-		WREG32_PCIE(*pos >> 2, value);
+		WREG32_PCIE(*pos, value);
 
 		result += 4;
 		buf += 4;
@@ -392,6 +392,9 @@
 	ssize_t result = 0;
 	int r;
 
+	if (!adev->smc_rreg)
+		return -EOPNOTSUPP;
+
 	if (size & 0x3 || *pos & 0x3)
 		return -EINVAL;
 
@@ -431,6 +434,9 @@
 	ssize_t result = 0;
 	int r;
 
+	if (!adev->smc_wreg)
+		return -EOPNOTSUPP;
+
 	if (size & 0x3 || *pos & 0x3)
 		return -EINVAL;
 
@@ -694,11 +700,11 @@
 	ssize_t result = 0;
 	uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
 
-	if (size & 3 || *pos & 3)
+	if (size > 4096 || size & 3 || *pos & 3)
 		return -EINVAL;
 
 	/* decode offset */
-	offset = *pos & GENMASK_ULL(11, 0);
+	offset = (*pos & GENMASK_ULL(11, 0)) >> 2;
 	se = (*pos & GENMASK_ULL(19, 12)) >> 12;
 	sh = (*pos & GENMASK_ULL(27, 20)) >> 20;
 	cu = (*pos & GENMASK_ULL(35, 28)) >> 28;
@@ -729,7 +735,7 @@
 	while (size) {
 		uint32_t value;
 
-		value = data[offset++];
+		value = data[result >> 2];
 		r = put_user(value, (uint32_t *)buf);
 		if (r) {
 			result = r;
@@ -859,6 +865,9 @@
 	struct amdgpu_device *adev = dev->dev_private;
 	int r = 0, i;
 
+	/* Avoid accidently unparking the sched thread during GPU reset */
+	mutex_lock(&adev->lock_reset);
+
 	/* hold on the scheduler */
 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
 		struct amdgpu_ring *ring = adev->rings[i];
@@ -884,6 +893,8 @@
 		kthread_unpark(ring->sched.thread);
 	}
 
+	mutex_unlock(&adev->lock_reset);
+
 	return 0;
 }
 
@@ -985,27 +996,37 @@
 static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring)
 {
 	struct amdgpu_job *job;
-	struct drm_sched_job *s_job;
+	struct drm_sched_job *s_job, *tmp;
 	uint32_t preempt_seq;
 	struct dma_fence *fence, **ptr;
 	struct amdgpu_fence_driver *drv = &ring->fence_drv;
 	struct drm_gpu_scheduler *sched = &ring->sched;
+	bool preempted = true;
 
 	if (ring->funcs->type != AMDGPU_RING_TYPE_GFX)
 		return;
 
 	preempt_seq = le32_to_cpu(*(drv->cpu_addr + 2));
-	if (preempt_seq <= atomic_read(&drv->last_seq))
-		return;
+	if (preempt_seq <= atomic_read(&drv->last_seq)) {
+		preempted = false;
+		goto no_preempt;
+	}
 
 	preempt_seq &= drv->num_fences_mask;
 	ptr = &drv->fences[preempt_seq];
 	fence = rcu_dereference_protected(*ptr, 1);
 
+no_preempt:
 	spin_lock(&sched->job_list_lock);
-	list_for_each_entry(s_job, &sched->ring_mirror_list, node) {
+	list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
+		if (dma_fence_is_signaled(&s_job->s_fence->finished)) {
+			/* remove job from ring_mirror_list */
+			list_del_init(&s_job->node);
+			sched->ops->free_job(s_job);
+			continue;
+		}
 		job = to_amdgpu_job(s_job);
-		if (job->fence == fence)
+		if (preempted && job->fence == fence)
 			/* mark the job as preempted */
 			job->preemption_status |= AMDGPU_IB_PREEMPTED;
 	}
@@ -1036,6 +1057,9 @@
 	if (!fences)
 		return -ENOMEM;
 
+	/* Avoid accidently unparking the sched thread during GPU reset */
+	mutex_lock(&adev->lock_reset);
+
 	/* stop the scheduler */
 	kthread_park(ring->sched.thread);
 
@@ -1075,6 +1099,8 @@
 	/* restart the scheduler */
 	kthread_unpark(ring->sched.thread);
 
+	mutex_unlock(&adev->lock_reset);
+
 	ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
 
 	if (fences)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -70,11 +70,9 @@
 MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/raven2_gpu_info.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/renoir_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");
-MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
 
 #define AMDGPU_RESUME_MS		2000
 
@@ -759,6 +757,9 @@
 	u16 cmd;
 	int r;
 
+	if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
+		return 0;
+
 	/* Bypass for VF */
 	if (amdgpu_sriov_vf(adev))
 		return 0;
@@ -844,6 +845,7 @@
 				return true;
 
 			fw_ver = *((uint32_t *)adev->pm.fw->data + 69);
+			release_firmware(adev->pm.fw);
 			if (fw_ver < 0x00160e00)
 				return true;
 		}
@@ -2057,11 +2059,11 @@
 	if (adev->gmc.xgmi.num_physical_nodes > 1)
 		amdgpu_xgmi_remove_device(adev);
 
-	amdgpu_amdkfd_device_fini(adev);
-
 	amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
 	amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
 
+	amdgpu_amdkfd_device_fini(adev);
+
 	/* need to disable SMC first */
 	for (i = 0; i < adev->num_ip_blocks; i++) {
 		if (!adev->ip_blocks[i].status.hw)
@@ -2291,7 +2293,7 @@
 		AMD_IP_BLOCK_TYPE_IH,
 	};
 
-	for (i = 0; i < ARRAY_SIZE(ip_order); i++) {
+	for (i = 0; i < adev->num_ip_blocks; i++) {
 		int j;
 		struct amdgpu_ip_block *block;
 
@@ -3070,12 +3072,12 @@
 		}
 	}
 
-	amdgpu_amdkfd_suspend(adev);
-
 	amdgpu_ras_suspend(adev);
 
 	r = amdgpu_device_ip_suspend_phase1(adev);
 
+	amdgpu_amdkfd_suspend(adev);
+
 	/* evict vram memory */
 	amdgpu_bo_evict_vram(adev);
 
@@ -3704,7 +3706,6 @@
 			r = amdgpu_ib_ring_tests(tmp_adev);
 			if (r) {
 				dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r);
-				r = amdgpu_device_ip_suspend(tmp_adev);
 				need_full_reset = true;
 				r = -EAGAIN;
 				goto end;
@@ -3890,7 +3891,7 @@
 
 		amdgpu_device_lock_adev(tmp_adev, false);
 		r = amdgpu_device_pre_asic_reset(tmp_adev,
-						 NULL,
+						 (tmp_adev == adev) ? job : NULL,
 						 &need_full_reset);
 		/*TODO Should we stop ?*/
 		if (r) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -136,7 +136,7 @@
 {
 	uint32_t *p = (uint32_t *)binary;
 	uint64_t vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20;
-	uint64_t pos = vram_size - BINARY_MAX_SIZE;
+	uint64_t pos = vram_size - DISCOVERY_TMR_SIZE;
 	unsigned long flags;
 
 	while (pos < vram_size) {
@@ -179,7 +179,7 @@
 	uint16_t checksum;
 	int r;
 
-	adev->discovery = kzalloc(BINARY_MAX_SIZE, GFP_KERNEL);
+	adev->discovery = kzalloc(DISCOVERY_TMR_SIZE, GFP_KERNEL);
 	if (!adev->discovery)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h
@@ -24,6 +24,8 @@
 #ifndef __AMDGPU_DISCOVERY__
 #define __AMDGPU_DISCOVERY__
 
+#define DISCOVERY_TMR_SIZE  (64 << 10)
+
 int amdgpu_discovery_init(struct amdgpu_device *adev);
 void amdgpu_discovery_fini(struct amdgpu_device *adev);
 int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -282,7 +282,7 @@
 
 	ret = pm_runtime_get_sync(dev->dev);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	ret = drm_crtc_helper_set_config(set, ctx);
 
@@ -306,6 +306,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;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -145,7 +145,7 @@
 int amdgpu_mcbp = 0;
 int amdgpu_discovery = -1;
 int amdgpu_mes = 0;
-int amdgpu_noretry = 1;
+int amdgpu_noretry;
 
 struct amdgpu_mgpu_info mgpu_info = {
 	.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
@@ -613,7 +613,7 @@
 module_param_named(mes, amdgpu_mes, int, 0444);
 
 MODULE_PARM_DESC(noretry,
-	"Disable retry faults (0 = retry enabled, 1 = retry disabled (default))");
+	"Disable retry faults (0 = retry enabled (default), 1 = retry disabled)");
 module_param_named(noretry, amdgpu_noretry, int, 0644);
 
 #ifdef CONFIG_HSA_AMD
@@ -633,7 +633,7 @@
  * Maximum number of processes that HWS can schedule concurrently. The maximum is the
  * number of VMIDs assigned to the HWS, which is also the default.
  */
-int hws_max_conc_proc = 8;
+int hws_max_conc_proc = -1;
 module_param(hws_max_conc_proc, int, 0444);
 MODULE_PARM_DESC(hws_max_conc_proc,
 	"Max # processes HWS can execute concurrently when sched_policy=0 (0 = no concurrency, #VMIDs for KFD = Maximum(default))");
@@ -1011,6 +1011,7 @@
 	{0x1002, 0x7319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
 	{0x1002, 0x731A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
 	{0x1002, 0x731B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
+	{0x1002, 0x731E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
 	{0x1002, 0x731F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
 	/* Navi14 */
 	{0x1002, 0x7340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI14},
@@ -1023,6 +1024,7 @@
 
 	/* Navi12 */
 	{0x1002, 0x7360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12|AMD_EXP_HW_SUPPORT},
+	{0x1002, 0x7362, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12|AMD_EXP_HW_SUPPORT},
 
 	{0, 0, 0}
 };
@@ -1285,11 +1287,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;
 }
@@ -1420,7 +1423,7 @@
 
 static struct drm_driver kms_driver = {
 	.driver_features =
-	    DRIVER_USE_AGP | DRIVER_ATOMIC |
+	    DRIVER_ATOMIC |
 	    DRIVER_GEM |
 	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ,
 	.load = amdgpu_driver_load_kms,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -133,8 +133,7 @@
 	u32 cpp;
 	u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
 			       AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS     |
-			       AMDGPU_GEM_CREATE_VRAM_CLEARED 	     |
-			       AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+			       AMDGPU_GEM_CREATE_VRAM_CLEARED;
 
 	info = drm_get_format_info(adev->ddev, mode_cmd);
 	cpp = info->cpp[0];
@@ -147,7 +146,7 @@
 	size = mode_cmd->pitches[0] * height;
 	aligned_size = ALIGN(size, PAGE_SIZE);
 	ret = amdgpu_gem_object_create(adev, aligned_size, 0, domain, flags,
-				       ttm_bo_type_kernel, NULL, &gobj);
+				       ttm_bo_type_device, NULL, &gobj);
 	if (ret) {
 		pr_err("failed to allocate framebuffer (%d)\n", aligned_size);
 		return -ENOMEM;
@@ -290,10 +289,13 @@
 static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev)
 {
 	struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
+	int i;
 
 	drm_fb_helper_unregister_fbi(&rfbdev->helper);
 
 	if (rfb->base.obj[0]) {
+		for (i = 0; i < rfb->base.format->num_planes; i++)
+			drm_gem_object_put(rfb->base.obj[0]);
 		amdgpufb_destroy_pinned_object(rfb->base.obj[0]);
 		rfb->base.obj[0] = NULL;
 		drm_framebuffer_unregister_private(&rfb->base);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -404,7 +404,9 @@
 		ring->fence_drv.gpu_addr = adev->uvd.inst[ring->me].gpu_addr + index;
 	}
 	amdgpu_fence_write(ring, atomic_read(&ring->fence_drv.last_seq));
-	amdgpu_irq_get(adev, irq_src, irq_type);
+
+	if (irq_src)
+		amdgpu_irq_get(adev, irq_src, irq_type);
 
 	ring->fence_drv.irq_src = irq_src;
 	ring->fence_drv.irq_type = irq_type;
@@ -539,8 +541,9 @@
 			/* no need to trigger GPU reset as we are unloading */
 			amdgpu_fence_driver_force_completion(ring);
 		}
-		amdgpu_irq_put(adev, ring->fence_drv.irq_src,
-			       ring->fence_drv.irq_type);
+		if (ring->fence_drv.irq_src)
+			amdgpu_irq_put(adev, ring->fence_drv.irq_src,
+				       ring->fence_drv.irq_type);
 		drm_sched_fini(&ring->sched);
 		del_timer_sync(&ring->fence_drv.fallback_timer);
 		for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
@@ -576,8 +579,9 @@
 		}
 
 		/* disable the interrupt */
-		amdgpu_irq_put(adev, ring->fence_drv.irq_src,
-			       ring->fence_drv.irq_type);
+		if (ring->fence_drv.irq_src)
+			amdgpu_irq_put(adev, ring->fence_drv.irq_src,
+				       ring->fence_drv.irq_type);
 	}
 }
 
@@ -603,8 +607,9 @@
 			continue;
 
 		/* enable the interrupt */
-		amdgpu_irq_get(adev, ring->fence_drv.irq_src,
-			       ring->fence_drv.irq_type);
+		if (ring->fence_drv.irq_src)
+			amdgpu_irq_get(adev, ring->fence_drv.irq_src,
+				       ring->fence_drv.irq_type);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -161,16 +161,17 @@
 
 	struct amdgpu_bo_list_entry vm_pd;
 	struct list_head list, duplicates;
+	struct dma_fence *fence = NULL;
 	struct ttm_validate_buffer tv;
 	struct ww_acquire_ctx ticket;
 	struct amdgpu_bo_va *bo_va;
-	int r;
+	long r;
 
 	INIT_LIST_HEAD(&list);
 	INIT_LIST_HEAD(&duplicates);
 
 	tv.bo = &bo->tbo;
-	tv.num_shared = 1;
+	tv.num_shared = 2;
 	list_add(&tv.head, &list);
 
 	amdgpu_vm_get_pd_bo(vm, &list, &vm_pd);
@@ -178,28 +179,34 @@
 	r = ttm_eu_reserve_buffers(&ticket, &list, false, &duplicates, false);
 	if (r) {
 		dev_err(adev->dev, "leaking bo va because "
-			"we fail to reserve bo (%d)\n", r);
+			"we fail to reserve bo (%ld)\n", r);
 		return;
 	}
 	bo_va = amdgpu_vm_bo_find(vm, bo);
-	if (bo_va && --bo_va->ref_count == 0) {
-		amdgpu_vm_bo_rmv(adev, bo_va);
+	if (!bo_va || --bo_va->ref_count)
+		goto out_unlock;
 
-		if (amdgpu_vm_ready(vm)) {
-			struct dma_fence *fence = NULL;
+	amdgpu_vm_bo_rmv(adev, bo_va);
+	if (!amdgpu_vm_ready(vm))
+		goto out_unlock;
 
-			r = amdgpu_vm_clear_freed(adev, vm, &fence);
-			if (unlikely(r)) {
-				dev_err(adev->dev, "failed to clear page "
-					"tables on GEM object close (%d)\n", r);
-			}
-
-			if (fence) {
-				amdgpu_bo_fence(bo, fence, true);
-				dma_fence_put(fence);
-			}
-		}
+	fence = dma_resv_get_excl(bo->tbo.base.resv);
+	if (fence) {
+		amdgpu_bo_fence(bo, fence, true);
+		fence = NULL;
 	}
+
+	r = amdgpu_vm_clear_freed(adev, vm, &fence);
+	if (r || !fence)
+		goto out_unlock;
+
+	amdgpu_bo_fence(bo, fence, true);
+	dma_fence_put(fence);
+
+out_unlock:
+	if (unlikely(r < 0))
+		dev_err(adev->dev, "failed to clear page "
+			"tables on GEM object close (%ld)\n", r);
 	ttm_eu_backoff_reservation(&ticket, &list);
 }
 
@@ -322,11 +329,9 @@
 	if (r)
 		goto release_object;
 
-	if (args->flags & AMDGPU_GEM_USERPTR_REGISTER) {
-		r = amdgpu_mn_register(bo, args->addr);
-		if (r)
-			goto release_object;
-	}
+	r = amdgpu_mn_register(bo, args->addr);
+	if (r)
+		goto release_object;
 
 	if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) {
 		r = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages);
@@ -554,6 +559,7 @@
 	struct ww_acquire_ctx ticket;
 	struct list_head list, duplicates;
 	uint64_t va_flags;
+	uint64_t vm_size;
 	int r = 0;
 
 	if (args->va_address < AMDGPU_VA_RESERVED_SIZE) {
@@ -574,6 +580,15 @@
 
 	args->va_address &= AMDGPU_GMC_HOLE_MASK;
 
+	vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
+	vm_size -= AMDGPU_VA_RESERVED_SIZE;
+	if (args->va_address + args->map_size > vm_size) {
+		dev_dbg(&dev->pdev->dev,
+			"va_address 0x%llx is in top reserved area 0x%llx\n",
+			args->va_address + args->map_size, vm_size);
+		return -EINVAL;
+	}
+
 	if ((args->flags & ~valid_flags) && (args->flags & ~prt_flags)) {
 		dev_dbg(&dev->pdev->dev, "invalid flags combination 0x%08X\n",
 			args->flags);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -263,7 +263,7 @@
 		    * adev->gfx.mec.num_pipe_per_mec
 		    * adev->gfx.mec.num_queue_per_pipe;
 
-	while (queue_bit-- >= 0) {
+	while (--queue_bit >= 0) {
 		if (test_bit(queue_bit, adev->gfx.mec.queue_bitmap))
 			continue;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
@@ -77,6 +77,7 @@
 struct amdgpu_vmhub {
 	uint32_t	ctx0_ptb_addr_lo32;
 	uint32_t	ctx0_ptb_addr_hi32;
+	uint32_t	vm_inv_eng0_sem;
 	uint32_t	vm_inv_eng0_req;
 	uint32_t	vm_inv_eng0_ack;
 	uint32_t	vm_context0_cntl;
@@ -156,6 +157,7 @@
 	uint32_t                srbm_soft_reset;
 	bool			prt_warning;
 	uint64_t		stolen_size;
+	uint32_t		sdpif_register;
 	/* apertures */
 	u64			shared_aperture_start;
 	u64			shared_aperture_end;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
@@ -339,7 +339,7 @@
 void
 amdgpu_i2c_router_select_ddc_port(const struct amdgpu_connector *amdgpu_connector)
 {
-	u8 val;
+	u8 val = 0;
 
 	if (!amdgpu_connector->router.ddc_valid)
 		return;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -469,7 +469,7 @@
 		for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
 			struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
 
-			if (!src)
+			if (!src || !src->funcs || !src->funcs->set)
 				continue;
 			for (k = 0; k < src->num_types; k++)
 				amdgpu_irq_update(adev, src, k);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -36,7 +36,8 @@
 
 	memset(&ti, 0, sizeof(struct amdgpu_task_info));
 
-	if (amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) {
+	if (amdgpu_gpu_recovery &&
+	    amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) {
 		DRM_ERROR("ring %s timeout, but soft recovered\n",
 			  s_job->sched->name);
 		return;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -471,6 +471,7 @@
 			crtc = (struct drm_crtc *)minfo->crtcs[i];
 			if (crtc && crtc->base.id == info->mode_crtc.id) {
 				struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
 				ui32 = amdgpu_crtc->crtc_id;
 				found = 1;
 				break;
@@ -489,7 +490,7 @@
 		if (ret)
 			return ret;
 
-		ret = copy_to_user(out, &ip, min((size_t)size, sizeof(ip)));
+		ret = copy_to_user(out, &ip, min_t(size_t, size, sizeof(ip)));
 		return ret ? -EFAULT : 0;
 	}
 	case AMDGPU_INFO_HW_IP_COUNT: {
@@ -625,21 +626,29 @@
 				    ? -EFAULT : 0;
 	}
 	case AMDGPU_INFO_READ_MMR_REG: {
-		unsigned n, alloc_size;
+		unsigned int n, alloc_size;
 		uint32_t *regs;
-		unsigned se_num = (info->read_mmr_reg.instance >>
+		unsigned int se_num = (info->read_mmr_reg.instance >>
 				   AMDGPU_INFO_MMR_SE_INDEX_SHIFT) &
 				  AMDGPU_INFO_MMR_SE_INDEX_MASK;
-		unsigned sh_num = (info->read_mmr_reg.instance >>
+		unsigned int sh_num = (info->read_mmr_reg.instance >>
 				   AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
 				  AMDGPU_INFO_MMR_SH_INDEX_MASK;
 
 		/* set full masks if the userspace set all bits
-		 * in the bitfields */
+		 * in the bitfields
+		 */
 		if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
 			se_num = 0xffffffff;
+		else if (se_num >= AMDGPU_GFX_MAX_SE)
+			return -EINVAL;
 		if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
 			sh_num = 0xffffffff;
+		else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
+			return -EINVAL;
+
+		if (info->read_mmr_reg.count > 128)
+			return -EINVAL;
 
 		if (info->read_mmr_reg.count > 128)
 			return -EINVAL;
@@ -667,9 +676,10 @@
 		return n ? -EFAULT : 0;
 	}
 	case AMDGPU_INFO_DEV_INFO: {
-		struct drm_amdgpu_info_device dev_info = {};
+		struct drm_amdgpu_info_device dev_info;
 		uint64_t vm_size;
 
+		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;
@@ -761,7 +771,7 @@
 				    min((size_t)size, sizeof(dev_info))) ? -EFAULT : 0;
 	}
 	case AMDGPU_INFO_VCE_CLOCK_TABLE: {
-		unsigned i;
+		unsigned int i;
 		struct drm_amdgpu_info_vce_clock_table vce_clk_table = {};
 		struct amd_vce_state *vce_state;
 
@@ -975,7 +985,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)) {
@@ -1026,6 +1036,7 @@
 
 out_suspend:
 	pm_runtime_mark_last_busy(dev->dev);
+pm_put:
 	pm_runtime_put_autosuspend(dev->dev);
 
 	return r;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -200,7 +200,7 @@
 		c++;
 	}
 
-	BUG_ON(c >= AMDGPU_BO_MAX_PLACEMENTS);
+	BUG_ON(c > AMDGPU_BO_MAX_PLACEMENTS);
 
 	placement->num_placement = c;
 	placement->placement = places;
@@ -343,6 +343,67 @@
 }
 
 /**
+ * amdgpu_bo_create_kernel_at - create BO for kernel use at specific location
+ *
+ * @adev: amdgpu device object
+ * @offset: offset of the BO
+ * @size: size of the BO
+ * @domain: where to place it
+ * @bo_ptr:  used to initialize BOs in structures
+ * @cpu_addr: optional CPU address mapping
+ *
+ * Creates a kernel BO at a specific offset in the address space of the domain.
+ *
+ * Returns:
+ * 0 on success, negative error code otherwise.
+ */
+int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
+			       uint64_t offset, uint64_t size, uint32_t domain,
+			       struct amdgpu_bo **bo_ptr, void **cpu_addr)
+{
+	struct ttm_operation_ctx ctx = { false, false };
+	unsigned int i;
+	int r;
+
+	offset &= PAGE_MASK;
+	size = ALIGN(size, PAGE_SIZE);
+
+	r = amdgpu_bo_create_reserved(adev, size, PAGE_SIZE, domain, bo_ptr,
+				      NULL, NULL);
+	if (r)
+		return r;
+
+	/*
+	 * Remove the original mem node and create a new one at the request
+	 * position.
+	 */
+	for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) {
+		(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
+		(*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
+	}
+
+	ttm_bo_mem_put(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
+	r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement,
+			     &(*bo_ptr)->tbo.mem, &ctx);
+	if (r)
+		goto error;
+
+	if (cpu_addr) {
+		r = amdgpu_bo_kmap(*bo_ptr, cpu_addr);
+		if (r)
+			goto error;
+	}
+
+	amdgpu_bo_unreserve(*bo_ptr);
+	return 0;
+
+error:
+	amdgpu_bo_unreserve(*bo_ptr);
+	amdgpu_bo_unref(bo_ptr);
+	return r;
+}
+
+/**
  * amdgpu_bo_free_kernel - free BO for kernel use
  *
  * @bo: amdgpu BO to free
@@ -831,6 +892,10 @@
 	if (WARN_ON_ONCE(min_offset > max_offset))
 		return -EINVAL;
 
+	/* Check domain to be pinned to against preferred domains */
+	if (bo->preferred_domains & domain)
+		domain = bo->preferred_domains & domain;
+
 	/* A shared bo cannot be migrated to VRAM */
 	if (bo->prime_shared_count) {
 		if (domain & AMDGPU_GEM_DOMAIN_GTT)
@@ -1244,7 +1309,8 @@
 	    !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE))
 		return;
 
-	dma_resv_lock(bo->base.resv, NULL);
+	if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv)))
+		return;
 
 	r = amdgpu_fill_buffer(abo, AMDGPU_POISON, bo->base.resv, &fence);
 	if (!WARN_ON(r)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -237,6 +237,9 @@
 			    unsigned long size, int align,
 			    u32 domain, struct amdgpu_bo **bo_ptr,
 			    u64 *gpu_addr, void **cpu_addr);
+int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
+			       uint64_t offset, uint64_t size, uint32_t domain,
+			       struct amdgpu_bo **bo_ptr, void **cpu_addr);
 void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
 			   void **cpu_addr);
 int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -90,7 +90,8 @@
 			adev->pm.ac_power = true;
 		else
 			adev->pm.ac_power = false;
-		if (adev->powerplay.pp_funcs->enable_bapm)
+		if (adev->powerplay.pp_funcs &&
+		    adev->powerplay.pp_funcs->enable_bapm)
 			amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
 		mutex_unlock(&adev->pm.mutex);
 	}
@@ -369,6 +370,15 @@
 	if (current_level == level)
 		return count;
 
+	if (adev->asic_type == CHIP_RAVEN) {
+		if (adev->rev_id < 8) {
+			if (current_level != AMD_DPM_FORCED_LEVEL_MANUAL && level == AMD_DPM_FORCED_LEVEL_MANUAL)
+				amdgpu_gfx_off_ctrl(adev, false);
+			else if (current_level == AMD_DPM_FORCED_LEVEL_MANUAL && level != AMD_DPM_FORCED_LEVEL_MANUAL)
+				amdgpu_gfx_off_ctrl(adev, true);
+		}
+	}
+
 	/* profile_exit setting is valid only when current mode is in profile mode */
 	if (!(current_level & (AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
 	    AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
@@ -415,8 +425,11 @@
 		ret = smu_get_power_num_states(&adev->smu, &data);
 		if (ret)
 			return ret;
-	} else if (adev->powerplay.pp_funcs->get_pp_num_states)
+	} else if (adev->powerplay.pp_funcs->get_pp_num_states) {
 		amdgpu_dpm_get_pp_num_states(adev, &data);
+	} else {
+		memset(&data, 0, sizeof(data));
+	}
 
 	buf_len = snprintf(buf, PAGE_SIZE, "states: %d\n", data.nums);
 	for (i = 0; i < data.nums; i++)
@@ -857,7 +870,7 @@
 static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask)
 {
 	int ret;
-	long level;
+	unsigned long level;
 	char *sub_str = NULL;
 	char *tmp;
 	char buf_cpy[AMDGPU_MASK_BUF_MAX + 1];
@@ -873,8 +886,8 @@
 	while (tmp[0]) {
 		sub_str = strsep(&tmp, delimiter);
 		if (strlen(sub_str)) {
-			ret = kstrtol(sub_str, 0, &level);
-			if (ret)
+			ret = kstrtoul(sub_str, 0, &level);
+			if (ret || level > 31)
 				return -EINVAL;
 			*mask |= 1 << level;
 		} else
@@ -2088,7 +2101,7 @@
 	if (r)
 		return r;
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", sclk * 10 * 1000);
+	return snprintf(buf, PAGE_SIZE, "%u\n", sclk * 10 * 1000);
 }
 
 static ssize_t amdgpu_hwmon_show_sclk_label(struct device *dev,
@@ -2118,7 +2131,7 @@
 	if (r)
 		return r;
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", mclk * 10 * 1000);
+	return snprintf(buf, PAGE_SIZE, "%u\n", mclk * 10 * 1000);
 }
 
 static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -65,12 +65,6 @@
 /* inject address is 52 bits */
 #define	RAS_UMC_INJECT_ADDR_LIMIT	(0x1ULL << 52)
 
-static int amdgpu_ras_reserve_vram(struct amdgpu_device *adev,
-		uint64_t offset, uint64_t size,
-		struct amdgpu_bo **bo_ptr);
-static int amdgpu_ras_release_vram(struct amdgpu_device *adev,
-		struct amdgpu_bo **bo_ptr);
-
 static ssize_t amdgpu_ras_debugfs_read(struct file *f, char __user *buf,
 					size_t size, loff_t *pos)
 {
@@ -1214,75 +1208,6 @@
 	atomic_set(&ras->in_recovery, 0);
 }
 
-static int amdgpu_ras_release_vram(struct amdgpu_device *adev,
-		struct amdgpu_bo **bo_ptr)
-{
-	/* no need to free it actually. */
-	amdgpu_bo_free_kernel(bo_ptr, NULL, NULL);
-	return 0;
-}
-
-/* reserve vram with size@offset */
-static int amdgpu_ras_reserve_vram(struct amdgpu_device *adev,
-		uint64_t offset, uint64_t size,
-		struct amdgpu_bo **bo_ptr)
-{
-	struct ttm_operation_ctx ctx = { false, false };
-	struct amdgpu_bo_param bp;
-	int r = 0;
-	int i;
-	struct amdgpu_bo *bo;
-
-	if (bo_ptr)
-		*bo_ptr = NULL;
-	memset(&bp, 0, sizeof(bp));
-	bp.size = size;
-	bp.byte_align = PAGE_SIZE;
-	bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
-	bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
-		AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
-	bp.type = ttm_bo_type_kernel;
-	bp.resv = NULL;
-
-	r = amdgpu_bo_create(adev, &bp, &bo);
-	if (r)
-		return -EINVAL;
-
-	r = amdgpu_bo_reserve(bo, false);
-	if (r)
-		goto error_reserve;
-
-	offset = ALIGN(offset, PAGE_SIZE);
-	for (i = 0; i < bo->placement.num_placement; ++i) {
-		bo->placements[i].fpfn = offset >> PAGE_SHIFT;
-		bo->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
-	}
-
-	ttm_bo_mem_put(&bo->tbo, &bo->tbo.mem);
-	r = ttm_bo_mem_space(&bo->tbo, &bo->placement, &bo->tbo.mem, &ctx);
-	if (r)
-		goto error_pin;
-
-	r = amdgpu_bo_pin_restricted(bo,
-			AMDGPU_GEM_DOMAIN_VRAM,
-			offset,
-			offset + size);
-	if (r)
-		goto error_pin;
-
-	if (bo_ptr)
-		*bo_ptr = bo;
-
-	amdgpu_bo_unreserve(bo);
-	return r;
-
-error_pin:
-	amdgpu_bo_unreserve(bo);
-error_reserve:
-	amdgpu_bo_unref(&bo);
-	return r;
-}
-
 /* alloc/realloc bps array */
 static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev,
 		struct ras_err_handler_data *data, int pages)
@@ -1345,7 +1270,7 @@
 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
 	struct ras_err_handler_data *data;
 	uint64_t bp;
-	struct amdgpu_bo *bo;
+	struct amdgpu_bo *bo = NULL;
 	int i;
 
 	if (!con || !con->eh_data)
@@ -1359,12 +1284,14 @@
 	for (i = data->last_reserved; i < data->count; i++) {
 		bp = data->bps[i].bp;
 
-		if (amdgpu_ras_reserve_vram(adev, bp << PAGE_SHIFT,
-					PAGE_SIZE, &bo))
+		if (amdgpu_bo_create_kernel_at(adev, bp << PAGE_SHIFT, PAGE_SIZE,
+					       AMDGPU_GEM_DOMAIN_VRAM,
+					       &bo, NULL))
 			DRM_ERROR("RAS ERROR: reserve vram %llx fail\n", bp);
 
 		data->bps[i].bo = bo;
 		data->last_reserved = i + 1;
+		bo = NULL;
 	}
 out:
 	mutex_unlock(&con->recovery_lock);
@@ -1390,7 +1317,7 @@
 	for (i = data->last_reserved - 1; i >= 0; i--) {
 		bo = data->bps[i].bo;
 
-		amdgpu_ras_release_vram(adev, &bo);
+		amdgpu_bo_free_kernel(&bo, NULL, NULL);
 
 		data->bps[i].bo = bo;
 		data->last_reserved = i;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
@@ -138,7 +138,7 @@
 		return ret;
 	}
 
-	__decode_table_header_from_buff(hdr, &buff[2]);
+	__decode_table_header_from_buff(hdr, buff);
 
 	if (hdr->header == EEPROM_TABLE_HDR_VAL) {
 		control->num_recs = (hdr->tbl_size - EEPROM_TABLE_HEADER_SIZE) /
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
@@ -124,13 +124,12 @@
  */
 int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
 {
-	volatile u32 *dst_ptr;
 	u32 dws;
 	int r;
 
 	/* allocate clear state block */
 	adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
-	r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
+	r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE,
 				      AMDGPU_GEM_DOMAIN_VRAM,
 				      &adev->gfx.rlc.clear_state_obj,
 				      &adev->gfx.rlc.clear_state_gpu_addr,
@@ -141,13 +140,6 @@
 		return r;
 	}
 
-	/* set up the cs buffer */
-	dst_ptr = adev->gfx.rlc.cs_ptr;
-	adev->gfx.rlc.funcs->get_csb_buffer(adev, dst_ptr);
-	amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
-	amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
-	amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
@@ -58,6 +58,7 @@
 {
 	struct fd f = fdget(fd);
 	struct amdgpu_fpriv *fpriv;
+	struct amdgpu_ctx_mgr *mgr;
 	struct amdgpu_ctx *ctx;
 	uint32_t id;
 	int r;
@@ -71,8 +72,11 @@
 		return r;
 	}
 
-	idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id)
+	mgr = &fpriv->ctx_mgr;
+	mutex_lock(&mgr->lock);
+	idr_for_each_entry(&mgr->ctx_handles, ctx, id)
 		amdgpu_ctx_priority_override(ctx, priority);
+	mutex_unlock(&mgr->lock);
 
 	fdput(f);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -218,7 +218,8 @@
 		 */
 		fence_owner = amdgpu_sync_get_owner(f);
 		if (fence_owner == AMDGPU_FENCE_OWNER_KFD &&
-		    owner != AMDGPU_FENCE_OWNER_UNDEFINED)
+		    owner != AMDGPU_FENCE_OWNER_UNDEFINED &&
+	    owner != AMDGPU_FENCE_OWNER_KFD)
 			continue;
 
 		if (amdgpu_sync_same_dev(adev, f)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
@@ -138,6 +138,7 @@
 		}
 
 		dma_fence_put(fence);
+		fence = NULL;
 
 		r = amdgpu_bo_kmap(vram_obj, &vram_map);
 		if (r) {
@@ -183,6 +184,7 @@
 		}
 
 		dma_fence_put(fence);
+		fence = NULL;
 
 		r = amdgpu_bo_kmap(gtt_obj[i], &gtt_map);
 		if (r) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -21,7 +21,7 @@
  *
  */
 
-#if !defined(_AMDGPU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#if !defined(_AMDGPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
 #define _AMDGPU_TRACE_H_
 
 #include <linux/stringify.h>
@@ -170,7 +170,7 @@
 			     __field(unsigned int, context)
 			     __field(unsigned int, seqno)
 			     __field(struct dma_fence *, fence)
-			     __field(char *, ring_name)
+			     __string(ring, to_amdgpu_ring(job->base.sched)->name)
 			     __field(u32, num_ibs)
 			     ),
 
@@ -179,12 +179,12 @@
 			   __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
 			   __entry->context = job->base.s_fence->finished.context;
 			   __entry->seqno = job->base.s_fence->finished.seqno;
-			   __entry->ring_name = to_amdgpu_ring(job->base.sched)->name;
+			   __assign_str(ring, to_amdgpu_ring(job->base.sched)->name)
 			   __entry->num_ibs = job->num_ibs;
 			   ),
 	    TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
 		      __entry->sched_job_id, __get_str(timeline), __entry->context,
-		      __entry->seqno, __entry->ring_name, __entry->num_ibs)
+		      __entry->seqno, __get_str(ring), __entry->num_ibs)
 );
 
 TRACE_EVENT(amdgpu_sched_run_job,
@@ -195,7 +195,7 @@
 			     __string(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
 			     __field(unsigned int, context)
 			     __field(unsigned int, seqno)
-			     __field(char *, ring_name)
+			     __string(ring, to_amdgpu_ring(job->base.sched)->name)
 			     __field(u32, num_ibs)
 			     ),
 
@@ -204,12 +204,12 @@
 			   __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
 			   __entry->context = job->base.s_fence->finished.context;
 			   __entry->seqno = job->base.s_fence->finished.seqno;
-			   __entry->ring_name = to_amdgpu_ring(job->base.sched)->name;
+			   __assign_str(ring, to_amdgpu_ring(job->base.sched)->name)
 			   __entry->num_ibs = job->num_ibs;
 			   ),
 	    TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
 		      __entry->sched_job_id, __get_str(timeline), __entry->context,
-		      __entry->seqno, __entry->ring_name, __entry->num_ibs)
+		      __entry->seqno, __get_str(ring), __entry->num_ibs)
 );
 
 
@@ -468,7 +468,7 @@
 	    TP_PROTO(struct amdgpu_job *sched_job, struct dma_fence *fence),
 	    TP_ARGS(sched_job, fence),
 	    TP_STRUCT__entry(
-			     __field(const char *,name)
+			     __string(ring, sched_job->base.sched->name);
 			     __field(uint64_t, id)
 			     __field(struct dma_fence *, fence)
 			     __field(uint64_t, ctx)
@@ -476,14 +476,14 @@
 			     ),
 
 	    TP_fast_assign(
-			   __entry->name = sched_job->base.sched->name;
+			   __assign_str(ring, sched_job->base.sched->name)
 			   __entry->id = sched_job->base.id;
 			   __entry->fence = fence;
 			   __entry->ctx = fence->context;
 			   __entry->seqno = fence->seqno;
 			   ),
 	    TP_printk("job ring=%s, id=%llu, need pipe sync to fence=%p, context=%llu, seq=%u",
-		      __entry->name, __entry->id,
+		      __get_str(ring), __entry->id,
 		      __entry->fence, __entry->ctx,
 		      __entry->seqno)
 );
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -35,6 +35,7 @@
 #include <linux/hmm.h>
 #include <linux/pagemap.h>
 #include <linux/sched/task.h>
+#include <linux/sched/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
@@ -788,7 +789,7 @@
 	struct hmm_mirror *mirror = bo->mn ? &bo->mn->mirror : NULL;
 	struct ttm_tt *ttm = bo->tbo.ttm;
 	struct amdgpu_ttm_tt *gtt = (void *)ttm;
-	struct mm_struct *mm = gtt->usertask->mm;
+	struct mm_struct *mm;
 	unsigned long start = gtt->userptr;
 	struct vm_area_struct *vma;
 	struct hmm_range *range;
@@ -796,25 +797,14 @@
 	uint64_t *pfns;
 	int r = 0;
 
-	if (!mm) /* Happens during process shutdown */
-		return -ESRCH;
-
 	if (unlikely(!mirror)) {
 		DRM_DEBUG_DRIVER("Failed to get hmm_mirror\n");
-		r = -EFAULT;
-		goto out;
+		return -EFAULT;
 	}
 
-	vma = find_vma(mm, start);
-	if (unlikely(!vma || start < vma->vm_start)) {
-		r = -EFAULT;
-		goto out;
-	}
-	if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
-		vma->vm_file)) {
-		r = -EPERM;
-		goto out;
-	}
+	mm = mirror->hmm->mmu_notifier.mm;
+	if (!mmget_not_zero(mm)) /* Happens during process shutdown */
+		return -ESRCH;
 
 	range = kzalloc(sizeof(*range), GFP_KERNEL);
 	if (unlikely(!range)) {
@@ -847,6 +837,17 @@
 	hmm_range_wait_until_valid(range, HMM_RANGE_DEFAULT_TIMEOUT);
 
 	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, start);
+	if (unlikely(!vma || start < vma->vm_start)) {
+		r = -EFAULT;
+		goto out_unlock;
+	}
+	if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
+		vma->vm_file)) {
+		r = -EPERM;
+		goto out_unlock;
+	}
+
 	r = hmm_range_fault(range, 0);
 	up_read(&mm->mmap_sem);
 
@@ -865,15 +866,19 @@
 	}
 
 	gtt->range = range;
+	mmput(mm);
 
 	return 0;
 
+out_unlock:
+	up_read(&mm->mmap_sem);
 out_free_pfns:
 	hmm_range_unregister(range);
 	kvfree(pfns);
 out_free_ranges:
 	kfree(range);
 out:
+	mmput(mm);
 	return r;
 }
 
@@ -962,6 +967,7 @@
 
 release_sg:
 	kfree(ttm->sg);
+	ttm->sg = NULL;
 	return r;
 }
 
@@ -978,7 +984,7 @@
 		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 
 	/* double check that we don't free the table twice */
-	if (!ttm->sg->sgl)
+	if (!ttm->sg || !ttm->sg->sgl)
 		return;
 
 	/* unmap the pages mapped to the device */
@@ -1294,6 +1300,7 @@
 	if (gtt && gtt->userptr) {
 		amdgpu_ttm_tt_set_user_pages(ttm, NULL);
 		kfree(ttm->sg);
+		ttm->sg = NULL;
 		ttm->page_flags &= ~TTM_PAGE_FLAG_SG;
 		return;
 	}
@@ -1634,81 +1641,25 @@
  */
 static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
 {
-	struct ttm_operation_ctx ctx = { false, false };
-	struct amdgpu_bo_param bp;
-	int r = 0;
-	int i;
-	u64 vram_size = adev->gmc.visible_vram_size;
-	u64 offset = adev->fw_vram_usage.start_offset;
-	u64 size = adev->fw_vram_usage.size;
-	struct amdgpu_bo *bo;
-
-	memset(&bp, 0, sizeof(bp));
-	bp.size = adev->fw_vram_usage.size;
-	bp.byte_align = PAGE_SIZE;
-	bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
-	bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
-		AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
-	bp.type = ttm_bo_type_kernel;
-	bp.resv = NULL;
+	uint64_t vram_size = adev->gmc.visible_vram_size;
+	int r;
+
 	adev->fw_vram_usage.va = NULL;
 	adev->fw_vram_usage.reserved_bo = NULL;
 
-	if (adev->fw_vram_usage.size > 0 &&
-		adev->fw_vram_usage.size <= vram_size) {
-
-		r = amdgpu_bo_create(adev, &bp,
-				     &adev->fw_vram_usage.reserved_bo);
-		if (r)
-			goto error_create;
-
-		r = amdgpu_bo_reserve(adev->fw_vram_usage.reserved_bo, false);
-		if (r)
-			goto error_reserve;
-
-		/* remove the original mem node and create a new one at the
-		 * request position
-		 */
-		bo = adev->fw_vram_usage.reserved_bo;
-		offset = ALIGN(offset, PAGE_SIZE);
-		for (i = 0; i < bo->placement.num_placement; ++i) {
-			bo->placements[i].fpfn = offset >> PAGE_SHIFT;
-			bo->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
-		}
-
-		ttm_bo_mem_put(&bo->tbo, &bo->tbo.mem);
-		r = ttm_bo_mem_space(&bo->tbo, &bo->placement,
-				     &bo->tbo.mem, &ctx);
-		if (r)
-			goto error_pin;
-
-		r = amdgpu_bo_pin_restricted(adev->fw_vram_usage.reserved_bo,
-			AMDGPU_GEM_DOMAIN_VRAM,
-			adev->fw_vram_usage.start_offset,
-			(adev->fw_vram_usage.start_offset +
-			adev->fw_vram_usage.size));
-		if (r)
-			goto error_pin;
-		r = amdgpu_bo_kmap(adev->fw_vram_usage.reserved_bo,
-			&adev->fw_vram_usage.va);
-		if (r)
-			goto error_kmap;
-
-		amdgpu_bo_unreserve(adev->fw_vram_usage.reserved_bo);
-	}
-	return r;
+	if (adev->fw_vram_usage.size == 0 ||
+	    adev->fw_vram_usage.size > vram_size)
+		return 0;
 
-error_kmap:
-	amdgpu_bo_unpin(adev->fw_vram_usage.reserved_bo);
-error_pin:
-	amdgpu_bo_unreserve(adev->fw_vram_usage.reserved_bo);
-error_reserve:
-	amdgpu_bo_unref(&adev->fw_vram_usage.reserved_bo);
-error_create:
-	adev->fw_vram_usage.va = NULL;
-	adev->fw_vram_usage.reserved_bo = NULL;
+	return amdgpu_bo_create_kernel_at(adev,
+					  adev->fw_vram_usage.start_offset,
+					  adev->fw_vram_usage.size,
+					  AMDGPU_GEM_DOMAIN_VRAM,
+					  &adev->fw_vram_usage.reserved_bo,
+					  &adev->fw_vram_usage.va);
 	return r;
 }
+
 /**
  * amdgpu_ttm_init - Init the memory management (ttm) as well as various
  * gtt/vram related fields.
@@ -1781,6 +1732,20 @@
 				    NULL, &stolen_vga_buf);
 	if (r)
 		return r;
+
+	/*
+	 * reserve one TMR (64K) memory at the top of VRAM which holds
+	 * IP Discovery data and is protected by PSP.
+	 */
+	r = amdgpu_bo_create_kernel_at(adev,
+				       adev->gmc.real_vram_size - DISCOVERY_TMR_SIZE,
+				       DISCOVERY_TMR_SIZE,
+				       AMDGPU_GEM_DOMAIN_VRAM,
+				       &adev->discovery_memory,
+				       NULL);
+	if (r)
+		return r;
+
 	DRM_INFO("amdgpu: %uM of VRAM memory ready\n",
 		 (unsigned) (adev->gmc.real_vram_size / (1024 * 1024)));
 
@@ -1845,6 +1810,9 @@
 	void *stolen_vga_buf;
 	/* return the VGA stolen memory (if any) back to VRAM */
 	amdgpu_bo_free_kernel(&adev->stolen_vga_memory, NULL, &stolen_vga_buf);
+
+	/* return the IP Discovery TMR memory back to VRAM */
+	amdgpu_bo_free_kernel(&adev->discovery_memory, NULL, NULL);
 }
 
 /**
@@ -2008,7 +1976,7 @@
 	unsigned i;
 	int r;
 
-	if (direct_submit && !ring->sched.ready) {
+	if (!direct_submit && !ring->sched.ready) {
 		DRM_ERROR("Trying to move memory with ring turned off.\n");
 		return -EINVAL;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -568,8 +568,7 @@
 
 void amdgpu_ucode_free_bo(struct amdgpu_device *adev)
 {
-	if (adev->firmware.load_type != AMDGPU_FW_LOAD_DIRECT)
-		amdgpu_bo_free_kernel(&adev->firmware.fw_buf,
+	amdgpu_bo_free_kernel(&adev->firmware.fw_buf,
 		&adev->firmware.fw_buf_mc,
 		&adev->firmware.fw_buf_ptr);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -231,7 +231,7 @@
 		if ((adev->asic_type == CHIP_POLARIS10 ||
 		     adev->asic_type == CHIP_POLARIS11) &&
 		    (adev->uvd.fw_version < FW_1_66_16))
-			DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n",
+			DRM_ERROR("POLARIS10/11 UVD firmware version %u.%u is too old.\n",
 				  version_major, version_minor);
 	} else {
 		unsigned int enc_major, enc_minor, dec_minor;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -55,11 +55,9 @@
 MODULE_FIRMWARE(FIRMWARE_RAVEN);
 MODULE_FIRMWARE(FIRMWARE_PICASSO);
 MODULE_FIRMWARE(FIRMWARE_RAVEN2);
-MODULE_FIRMWARE(FIRMWARE_ARCTURUS);
 MODULE_FIRMWARE(FIRMWARE_RENOIR);
 MODULE_FIRMWARE(FIRMWARE_NAVI10);
 MODULE_FIRMWARE(FIRMWARE_NAVI14);
-MODULE_FIRMWARE(FIRMWARE_NAVI12);
 
 static void amdgpu_vcn_idle_work_handler(struct work_struct *work);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -48,6 +48,8 @@
 	uint64_t data[AMDGPU_VF_ERROR_ENTRY_SIZE];
 };
 
+enum idh_request;
+
 /**
  * struct amdgpu_virt_ops - amdgpu device virt operations
  */
@@ -56,7 +58,8 @@
 	int (*rel_full_gpu)(struct amdgpu_device *adev, bool init);
 	int (*reset_gpu)(struct amdgpu_device *adev);
 	int (*wait_reset)(struct amdgpu_device *adev);
-	void (*trans_msg)(struct amdgpu_device *adev, u32 req, u32 data1, u32 data2, u32 data3);
+	void (*trans_msg)(struct amdgpu_device *adev, enum idh_request req,
+			  u32 data1, u32 data2, u32 data3);
 	int (*get_pp_clk)(struct amdgpu_device *adev, u32 type, char *buf);
 	int (*force_dpm_level)(struct amdgpu_device *adev, u32 level);
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1034,10 +1034,8 @@
 		id->oa_base != job->oa_base ||
 		id->oa_size != job->oa_size);
 	bool vm_flush_needed = job->vm_needs_flush;
-	bool pasid_mapping_needed = id->pasid != job->pasid ||
-		!id->pasid_mapping ||
-		!dma_fence_is_signaled(id->pasid_mapping);
 	struct dma_fence *fence = NULL;
+	bool pasid_mapping_needed = false;
 	unsigned patch_offset = 0;
 	int r;
 
@@ -1047,6 +1045,12 @@
 		pasid_mapping_needed = true;
 	}
 
+	mutex_lock(&id_mgr->lock);
+	if (id->pasid != job->pasid || !id->pasid_mapping ||
+	    !dma_fence_is_signaled(id->pasid_mapping))
+		pasid_mapping_needed = true;
+	mutex_unlock(&id_mgr->lock);
+
 	gds_switch_needed &= !!ring->funcs->emit_gds_switch;
 	vm_flush_needed &= !!ring->funcs->emit_vm_flush  &&
 			job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET;
@@ -1086,9 +1090,11 @@
 	}
 
 	if (pasid_mapping_needed) {
+		mutex_lock(&id_mgr->lock);
 		id->pasid = job->pasid;
 		dma_fence_put(id->pasid_mapping);
 		id->pasid_mapping = dma_fence_get(fence);
+		mutex_unlock(&id_mgr->lock);
 	}
 	dma_fence_put(fence);
 
@@ -2117,8 +2123,8 @@
 	uint64_t eaddr;
 
 	/* validate the parameters */
-	if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
-	    size == 0 || size & AMDGPU_GPU_PAGE_MASK)
+	if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK ||
+	    size == 0 || size & ~PAGE_MASK)
 		return -EINVAL;
 
 	/* make sure object fit at this offset */
@@ -2182,8 +2188,8 @@
 	int r;
 
 	/* validate the parameters */
-	if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
-	    size == 0 || size & AMDGPU_GPU_PAGE_MASK)
+	if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK ||
+	    size == 0 || size & ~PAGE_MASK)
 		return -EINVAL;
 
 	/* make sure object fit at this offset */
@@ -2327,7 +2333,7 @@
 			after->start = eaddr + 1;
 			after->last = tmp->last;
 			after->offset = tmp->offset;
-			after->offset += after->start - tmp->start;
+			after->offset += (after->start - tmp->start) << PAGE_SHIFT;
 			after->flags = tmp->flags;
 			after->bo_va = tmp->bo_va;
 			list_add(&after->list, &tmp->bo_va->invalids);
@@ -2861,10 +2867,17 @@
 	WARN_ONCE((vm->use_cpu_for_update && !amdgpu_gmc_vram_full_visible(&adev->gmc)),
 		  "CPU update of VM recommended only for large BAR system\n");
 
-	if (vm->use_cpu_for_update)
+	if (vm->use_cpu_for_update) {
+		/* Sync with last SDMA update/clear before switching to CPU */
+		r = amdgpu_bo_sync_wait(vm->root.base.bo,
+					AMDGPU_FENCE_OWNER_UNDEFINED, true);
+		if (r)
+			goto free_idr;
+
 		vm->update_funcs = &amdgpu_vm_cpu_funcs;
-	else
+	} else {
 		vm->update_funcs = &amdgpu_vm_sdma_funcs;
+	}
 	dma_fence_put(vm->last_update);
 	vm->last_update = NULL;
 
@@ -3063,6 +3076,10 @@
 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
 	int r;
 
+	/* No valid flags defined yet */
+	if (args->in.flags)
+		return -EINVAL;
+
 	switch (args->in.op) {
 	case AMDGPU_VM_OP_RESERVE_VMID:
 		/* current, we only have requirement to reserve vmid from gfxhub */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -105,8 +105,8 @@
 #define AMDGPU_MMHUB_0				1
 #define AMDGPU_MMHUB_1				2
 
-/* hardcode that limit for now */
-#define AMDGPU_VA_RESERVED_SIZE			(1ULL << 20)
+/* Reserve 2MB at top/bottom of address space for kernel use */
+#define AMDGPU_VA_RESERVED_SIZE			(2ULL << 20)
 
 /* max vmids dedicated for process */
 #define AMDGPU_VM_MAX_RESERVED_VMID	1
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -311,15 +311,22 @@
 }
 
 
+/*
+ * NOTE psp_xgmi_node_info.num_hops layout is as follows:
+ * num_hops[7:6] = link type (0 = xGMI2, 1 = xGMI3, 2/3 = reserved)
+ * num_hops[5:3] = reserved
+ * num_hops[2:0] = number of hops
+ */
 int amdgpu_xgmi_get_hops_count(struct amdgpu_device *adev,
 		struct amdgpu_device *peer_adev)
 {
 	struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info;
+	uint8_t num_hops_mask = 0x7;
 	int i;
 
 	for (i = 0 ; i < top->num_nodes; ++i)
 		if (top->nodes[i].node_id == peer_adev->gmc.xgmi.node_id)
-			return top->nodes[i].num_hops;
+			return top->nodes[i].num_hops & num_hops_mask;
 	return	-EINVAL;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/atom.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/atom.c
@@ -744,8 +744,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-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/cik.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -1384,7 +1384,6 @@
 static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
 {
 	struct pci_dev *root = adev->pdev->bus->self;
-	int bridge_pos, gpu_pos;
 	u32 speed_cntl, current_data_rate;
 	int i;
 	u16 tmp16;
@@ -1419,12 +1418,7 @@
 		DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
 	}
 
-	bridge_pos = pci_pcie_cap(root);
-	if (!bridge_pos)
-		return;
-
-	gpu_pos = pci_pcie_cap(adev->pdev);
-	if (!gpu_pos)
+	if (!pci_is_pcie(root) || !pci_is_pcie(adev->pdev))
 		return;
 
 	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
@@ -1434,14 +1428,8 @@
 			u16 bridge_cfg2, gpu_cfg2;
 			u32 max_lw, current_lw, tmp;
 
-			pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-			pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
+			pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
 
 			tmp = RREG32_PCIE(ixPCIE_LC_STATUS1);
 			max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >>
@@ -1465,15 +1453,23 @@
 
 			for (i = 0; i < 10; i++) {
 				/* check status */
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_DEVSTA,
+							  &tmp16);
 				if (tmp16 & PCI_EXP_DEVSTA_TRPND)
 					break;
 
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+							  &bridge_cfg);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL,
+							  &gpu_cfg);
+
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &bridge_cfg2);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &gpu_cfg2);
 
 				tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
 				tmp |= PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
@@ -1486,26 +1482,38 @@
 				msleep(100);
 
 				/* linkctl */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   bridge_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
+				pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   gpu_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
 
 				/* linkctl2 */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (bridge_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(root,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
+
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (gpu_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(adev->pdev,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
 
 				tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
 				tmp &= ~PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
@@ -1520,15 +1528,16 @@
 	speed_cntl &= ~PCIE_LC_SPEED_CNTL__LC_FORCE_DIS_SW_SPEED_CHANGE_MASK;
 	WREG32_PCIE(ixPCIE_LC_SPEED_CNTL, speed_cntl);
 
-	pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-	tmp16 &= ~0xf;
+	pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+	tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
+
 	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-		tmp16 |= 3; /* gen3 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
 	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
-		tmp16 |= 2; /* gen2 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
 	else
-		tmp16 |= 1; /* gen1 */
-	pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+	pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
 	speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
 	speed_cntl |= PCIE_LC_SPEED_CNTL__LC_INITIATE_LINK_SPEED_CHANGE_MASK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -228,7 +228,7 @@
 	u32 extra_bits = vmid & 0xf;
 
 	/* IB packet must end on a 8 DW boundary */
-	cik_sdma_ring_insert_nop(ring, (12 - (lower_32_bits(ring->wptr) & 7)) % 8);
+	cik_sdma_ring_insert_nop(ring, (4 - lower_32_bits(ring->wptr)) & 7);
 
 	amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));
 	amdgpu_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */
@@ -811,7 +811,7 @@
 	u32 pad_count;
 	int i;
 
-	pad_count = (8 - (ib->length_dw & 0x7)) % 8;
+	pad_count = (-ib->length_dw) & 7;
 	for (i = 0; i < pad_count; i++)
 		if (sdma && sdma->burst_nop && (i == 0))
 			ib->ptr[ib->length_dw++] =
@@ -1071,22 +1071,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) {
 		tmp = RREG32(mmSRBM_SOFT_RESET);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -193,19 +193,30 @@
 
 	wptr = le32_to_cpu(*ih->wptr_cpu);
 
-	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, ih->rptr, (wptr + 16) & ih->ptr_mask);
-		ih->rptr = (wptr + 16) & 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, ih->rptr, (wptr + 16) & ih->ptr_mask);
+	ih->rptr = (wptr + 16) & 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);
+
+
+out:
 	return (wptr & ih->ptr_mask);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/df_v3_6.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/df_v3_6.c
@@ -261,23 +261,29 @@
 {
 	u32 tmp;
 
-	/* Put DF on broadcast mode */
-	adev->df_funcs->enable_broadcast_mode(adev, true);
+	if (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG) {
+		/* Put DF on broadcast mode */
+		adev->df_funcs->enable_broadcast_mode(adev, true);
 
-	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG)) {
-		tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater);
-		tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
-		tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY;
-		WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp);
-	} else {
-		tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater);
-		tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
-		tmp |= DF_V3_6_MGCG_DISABLE;
-		WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp);
-	}
+		if (enable) {
+			tmp = RREG32_SOC15(DF, 0,
+					mmDF_PIE_AON0_DfGlobalClkGater);
+			tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
+			tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY;
+			WREG32_SOC15(DF, 0,
+					mmDF_PIE_AON0_DfGlobalClkGater, tmp);
+		} else {
+			tmp = RREG32_SOC15(DF, 0,
+					mmDF_PIE_AON0_DfGlobalClkGater);
+			tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK;
+			tmp |= DF_V3_6_MGCG_DISABLE;
+			WREG32_SOC15(DF, 0,
+					mmDF_PIE_AON0_DfGlobalClkGater, tmp);
+		}
 
-	/* Exit broadcast mode */
-	adev->df_funcs->enable_broadcast_mode(adev, false);
+		/* Exit broadcast mode */
+		adev->df_funcs->enable_broadcast_mode(adev, false);
+	}
 }
 
 static void df_v3_6_get_clockgating_state(struct amdgpu_device *adev,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -82,13 +82,6 @@
 MODULE_FIRMWARE("amdgpu/navi14_mec2.bin");
 MODULE_FIRMWARE("amdgpu/navi14_rlc.bin");
 
-MODULE_FIRMWARE("amdgpu/navi12_ce.bin");
-MODULE_FIRMWARE("amdgpu/navi12_pfp.bin");
-MODULE_FIRMWARE("amdgpu/navi12_me.bin");
-MODULE_FIRMWARE("amdgpu/navi12_mec.bin");
-MODULE_FIRMWARE("amdgpu/navi12_mec2.bin");
-MODULE_FIRMWARE("amdgpu/navi12_rlc.bin");
-
 static const struct soc15_reg_golden golden_settings_gc_10_1[] =
 {
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_4, 0xffffffff, 0x00400014),
@@ -190,9 +183,10 @@
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG, 0xffffffff, 0x20000000),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG2, 0xffffffff, 0x00000420),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0xffffffff, 0x00000200),
-	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x04800000),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x04900000),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DFSM_TILES_IN_FLIGHT, 0x0000ffff, 0x0000003f),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_LAST_OF_BURST_CONFIG, 0xffffffff, 0x03860204),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0x0c1800ff, 0x00000044),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x1ff0ffff, 0x00000500),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmGE_PRIV_CONTROL, 0x00007fff, 0x000001fe),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL1_PIPE_STEER, 0xffffffff, 0xe4e4e4e4),
@@ -210,12 +204,13 @@
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_2, 0x00000820, 0x00000820),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_SPARE, 0xffffffff, 0xffff3101),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL_1, 0x001f0000, 0x00070104),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ALU_CLK_CTRL, 0xffffffff, 0xffffffff),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ARB_CONFIG, 0x00000133, 0x00000130),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_LDS_CLK_CTRL, 0xffffffff, 0xffffffff),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmTA_CNTL_AUX, 0xfff7ffff, 0x01030000),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CNTL, 0xffdf80ff, 0x479c0010),
-	SOC15_REG_GOLDEN_VALUE(GC, 0, mmUTCL1_CTRL, 0xffffffff, 0x00800000)
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmUTCL1_CTRL, 0xffffffff, 0x00c00000)
 };
 
 static const struct soc15_reg_golden golden_settings_gc_10_1_nv14[] =
@@ -993,39 +988,6 @@
 	return 0;
 }
 
-static int gfx_v10_0_csb_vram_pin(struct amdgpu_device *adev)
-{
-	int r;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
-	if (unlikely(r != 0))
-		return r;
-
-	r = amdgpu_bo_pin(adev->gfx.rlc.clear_state_obj,
-			AMDGPU_GEM_DOMAIN_VRAM);
-	if (!r)
-		adev->gfx.rlc.clear_state_gpu_addr =
-			amdgpu_bo_gpu_offset(adev->gfx.rlc.clear_state_obj);
-
-	amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-
-	return r;
-}
-
-static void gfx_v10_0_csb_vram_unpin(struct amdgpu_device *adev)
-{
-	int r;
-
-	if (!adev->gfx.rlc.clear_state_obj)
-		return;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, true);
-	if (likely(r == 0)) {
-		amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
-		amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-	}
-}
-
 static void gfx_v10_0_mec_fini(struct amdgpu_device *adev)
 {
 	amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL);
@@ -1785,27 +1747,34 @@
 	WREG32_SOC15(GC, 0, mmCP_INT_CNTL_RING0, tmp);
 }
 
-static void gfx_v10_0_init_csb(struct amdgpu_device *adev)
+static int gfx_v10_0_init_csb(struct amdgpu_device *adev)
 {
+	adev->gfx.rlc.funcs->get_csb_buffer(adev, adev->gfx.rlc.cs_ptr);
+
 	/* csib */
 	WREG32_SOC15(GC, 0, mmRLC_CSIB_ADDR_HI,
 		     adev->gfx.rlc.clear_state_gpu_addr >> 32);
 	WREG32_SOC15(GC, 0, mmRLC_CSIB_ADDR_LO,
 		     adev->gfx.rlc.clear_state_gpu_addr & 0xfffffffc);
 	WREG32_SOC15(GC, 0, mmRLC_CSIB_LENGTH, adev->gfx.rlc.clear_state_size);
+
+	return 0;
 }
 
-static void gfx_v10_0_init_pg(struct amdgpu_device *adev)
+static int gfx_v10_0_init_pg(struct amdgpu_device *adev)
 {
 	int i;
+	int r;
 
-	gfx_v10_0_init_csb(adev);
+	r = gfx_v10_0_init_csb(adev);
+	if (r)
+		return r;
 
 	for (i = 0; i < adev->num_vmhubs; i++)
 		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);
 
 	/* TODO: init power gating */
-	return;
+	return 0;
 }
 
 void gfx_v10_0_rlc_stop(struct amdgpu_device *adev)
@@ -1907,7 +1876,10 @@
 		r = gfx_v10_0_wait_for_rlc_autoload_complete(adev);
 		if (r)
 			return r;
-		gfx_v10_0_init_pg(adev);
+
+		r = gfx_v10_0_init_pg(adev);
+		if (r)
+			return r;
 
 		/* enable RLC SRM */
 		gfx_v10_0_rlc_enable_srm(adev);
@@ -1933,7 +1905,10 @@
 				return r;
 		}
 
-		gfx_v10_0_init_pg(adev);
+		r = gfx_v10_0_init_pg(adev);
+		if (r)
+			return r;
+
 		adev->gfx.rlc.funcs->start(adev);
 
 		if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) {
@@ -2400,7 +2375,7 @@
 	return 0;
 }
 
-static void gfx_v10_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
+static int gfx_v10_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
 {
 	int i;
 	u32 tmp = RREG32_SOC15(GC, 0, mmCP_ME_CNTL);
@@ -2413,7 +2388,17 @@
 			adev->gfx.gfx_ring[i].sched.ready = false;
 	}
 	WREG32_SOC15(GC, 0, mmCP_ME_CNTL, tmp);
-	udelay(50);
+
+	for (i = 0; i < adev->usec_timeout; i++) {
+		if (RREG32_SOC15(GC, 0, mmCP_STAT) == 0)
+			break;
+		udelay(1);
+	}
+
+	if (i >= adev->usec_timeout)
+		DRM_ERROR("failed to %s cp gfx\n", enable ? "unhalt" : "halt");
+
+	return 0;
 }
 
 static int gfx_v10_0_cp_gfx_load_pfp_microcode(struct amdgpu_device *adev)
@@ -3514,6 +3499,7 @@
 
 		/* reset ring buffer */
 		ring->wptr = 0;
+		atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
 		amdgpu_ring_clear_ring(ring);
 	} else {
 		amdgpu_ring_clear_ring(ring);
@@ -3534,8 +3520,10 @@
 		return r;
 
 	r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
-	if (unlikely(r != 0))
+	if (unlikely(r != 0)) {
+		amdgpu_bo_unreserve(ring->mqd_obj);
 		return r;
+	}
 
 	gfx_v10_0_kiq_init_queue(ring);
 	amdgpu_bo_kunmap(ring->mqd_obj);
@@ -3732,10 +3720,6 @@
 	int r;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-	r = gfx_v10_0_csb_vram_pin(adev);
-	if (r)
-		return r;
-
 	if (!amdgpu_emu_mode)
 		gfx_v10_0_init_golden_registers(adev);
 
@@ -3823,7 +3807,6 @@
 	}
 	gfx_v10_0_cp_enable(adev, false);
 	gfx_v10_0_enable_gui_idle_interrupt(adev, false);
-	gfx_v10_0_csb_vram_unpin(adev);
 
 	return 0;
 }
@@ -3936,11 +3919,13 @@
 {
 	uint64_t clock;
 
+	amdgpu_gfx_off_ctrl(adev, false);
 	mutex_lock(&adev->gfx.gpu_clock_mutex);
 	WREG32_SOC15(GC, 0, mmRLC_CAPTURE_GPU_CLOCK_COUNT, 1);
 	clock = (uint64_t)RREG32_SOC15(GC, 0, mmRLC_GPU_CLOCK_COUNT_LSB) |
 		((uint64_t)RREG32_SOC15(GC, 0, mmRLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
 	mutex_unlock(&adev->gfx.gpu_clock_mutex);
+	amdgpu_gfx_off_ctrl(adev, true);
 	return clock;
 }
 
@@ -4050,10 +4035,8 @@
 		def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
 		data &= ~(RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK |
 			  RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK |
-			  RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK);
-
-		/* only for Vega10 & Raven1 */
-		data |= RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK;
+			  RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK |
+			  RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK);
 
 		if (def != data)
 			WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
@@ -4246,11 +4229,7 @@
 	switch (adev->asic_type) {
 	case CHIP_NAVI10:
 	case CHIP_NAVI14:
-		if (!enable) {
-			amdgpu_gfx_off_ctrl(adev, false);
-			cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
-		} else
-			amdgpu_gfx_off_ctrl(adev, true);
+		amdgpu_gfx_off_ctrl(adev, enable);
 		break;
 	default:
 		break;
@@ -4643,12 +4622,17 @@
 	struct amdgpu_device *adev = ring->adev;
 	struct amdgpu_kiq *kiq = &adev->gfx.kiq;
 	struct amdgpu_ring *kiq_ring = &kiq->ring;
+	unsigned long flags;
 
 	if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
 		return -EINVAL;
 
-	if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size))
+	spin_lock_irqsave(&kiq->ring_lock, flags);
+
+	if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size)) {
+		spin_unlock_irqrestore(&kiq->ring_lock, flags);
 		return -ENOMEM;
+	}
 
 	/* assert preemption condition */
 	amdgpu_ring_set_preempt_cond_exec(ring, false);
@@ -4659,6 +4643,8 @@
 				   ++ring->trail_seq);
 	amdgpu_ring_commit(kiq_ring);
 
+	spin_unlock_irqrestore(&kiq->ring_lock, flags);
+
 	/* poll the trailing fence */
 	for (i = 0; i < adev->usec_timeout; i++) {
 		if (ring->trail_seq ==
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -4554,6 +4554,8 @@
 
 	gfx_v7_0_constants_init(adev);
 
+	/* init CSB */
+	adev->gfx.rlc.funcs->get_csb_buffer(adev, adev->gfx.rlc.cs_ptr);
 	/* init rlc */
 	r = adev->gfx.rlc.funcs->resume(adev);
 	if (r)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -1321,39 +1321,6 @@
 	return 0;
 }
 
-static int gfx_v8_0_csb_vram_pin(struct amdgpu_device *adev)
-{
-	int r;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
-	if (unlikely(r != 0))
-		return r;
-
-	r = amdgpu_bo_pin(adev->gfx.rlc.clear_state_obj,
-			AMDGPU_GEM_DOMAIN_VRAM);
-	if (!r)
-		adev->gfx.rlc.clear_state_gpu_addr =
-			amdgpu_bo_gpu_offset(adev->gfx.rlc.clear_state_obj);
-
-	amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-
-	return r;
-}
-
-static void gfx_v8_0_csb_vram_unpin(struct amdgpu_device *adev)
-{
-	int r;
-
-	if (!adev->gfx.rlc.clear_state_obj)
-		return;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, true);
-	if (likely(r == 0)) {
-		amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
-		amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-	}
-}
-
 static void gfx_v8_0_mec_fini(struct amdgpu_device *adev)
 {
 	amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL);
@@ -3917,6 +3884,7 @@
 
 static void gfx_v8_0_init_csb(struct amdgpu_device *adev)
 {
+	adev->gfx.rlc.funcs->get_csb_buffer(adev, adev->gfx.rlc.cs_ptr);
 	/* csib */
 	WREG32(mmRLC_CSIB_ADDR_HI,
 			adev->gfx.rlc.clear_state_gpu_addr >> 32);
@@ -4837,10 +4805,6 @@
 	gfx_v8_0_init_golden_registers(adev);
 	gfx_v8_0_constants_init(adev);
 
-	r = gfx_v8_0_csb_vram_pin(adev);
-	if (r)
-		return r;
-
 	r = adev->gfx.rlc.funcs->resume(adev);
 	if (r)
 		return r;
@@ -4958,8 +4922,6 @@
 		pr_err("rlc is busy, skip halt rlc\n");
 	amdgpu_gfx_rlc_exit_safe_mode(adev);
 
-	gfx_v8_0_csb_vram_unpin(adev);
-
 	return 0;
 }
 
@@ -6184,7 +6146,23 @@
 	bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
 	bool int_sel = flags & AMDGPU_FENCE_FLAG_INT;
 
-	/* EVENT_WRITE_EOP - flush caches, send int */
+	/* Workaround for cache flush problems. First send a dummy EOP
+	 * event down the pipe with seq one below.
+	 */
+	amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+	amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EOP_TC_WB_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	amdgpu_ring_write(ring, addr & 0xfffffffc);
+	amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+				DATA_SEL(1) | INT_SEL(0));
+	amdgpu_ring_write(ring, lower_32_bits(seq - 1));
+	amdgpu_ring_write(ring, upper_32_bits(seq - 1));
+
+	/* Then send the real EOP event down the pipe:
+	 * EVENT_WRITE_EOP - flush caches, send int */
 	amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
 	amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN |
 				 EOP_TC_ACTION_EN |
@@ -6926,7 +6904,7 @@
 		5 +  /* COND_EXEC */
 		7 +  /* PIPELINE_SYNC */
 		VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 9 + /* VM_FLUSH */
-		8 +  /* FENCE for VM_FLUSH */
+		12 +  /* FENCE for VM_FLUSH */
 		20 + /* GDS switch */
 		4 + /* double SWITCH_BUFFER,
 		       the first COND_EXEC jump to the place just
@@ -6938,7 +6916,7 @@
 		31 + /*	DE_META */
 		3 + /* CNTX_CTRL */
 		5 + /* HDP_INVL */
-		8 + 8 + /* FENCE x2 */
+		12 + 12 + /* FENCE x2 */
 		2, /* SWITCH_BUFFER */
 	.emit_ib_size =	4, /* gfx_v8_0_ring_emit_ib_gfx */
 	.emit_ib = gfx_v8_0_ring_emit_ib_gfx,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -107,10 +107,6 @@
 MODULE_FIRMWARE("amdgpu/raven2_rlc.bin");
 MODULE_FIRMWARE("amdgpu/raven_kicker_rlc.bin");
 
-MODULE_FIRMWARE("amdgpu/arcturus_mec.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_mec2.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_rlc.bin");
-
 MODULE_FIRMWARE("amdgpu/renoir_ce.bin");
 MODULE_FIRMWARE("amdgpu/renoir_pfp.bin");
 MODULE_FIRMWARE("amdgpu/renoir_me.bin");
@@ -1026,6 +1022,8 @@
 			adev->gfx.mec_fw_write_wait = true;
 		break;
 	default:
+		adev->gfx.me_fw_write_wait = true;
+		adev->gfx.mec_fw_write_wait = true;
 		break;
 	}
 }
@@ -1038,17 +1036,10 @@
 	case CHIP_VEGA20:
 		break;
 	case CHIP_RAVEN:
-		/* Disable GFXOFF on original raven.  There are combinations
-		 * of sbios and platforms that are not stable.
-		 */
-		if (!(adev->rev_id >= 0x8 || adev->pdev->device == 0x15d8))
-			adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
-		else if (!(adev->rev_id >= 0x8 || adev->pdev->device == 0x15d8)
-			 &&((adev->gfx.rlc_fw_version != 106 &&
-			     adev->gfx.rlc_fw_version < 531) ||
-			    (adev->gfx.rlc_fw_version == 53815) ||
-			    (adev->gfx.rlc_feature_version < 1) ||
-			    !adev->gfx.rlc.is_rlc_v2_1))
+		if (!(adev->rev_id >= 0x8 ||
+		      adev->pdev->device == 0x15d8) &&
+		    (adev->pm.fw_version < 0x41e2b || /* not raven1 fresh */
+		     !adev->gfx.rlc.is_rlc_v2_1)) /* without rlc save restore ucodes */
 			adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
 
 		if (adev->pm.pp_feature & PP_GFXOFF_MASK)
@@ -1680,39 +1671,6 @@
 	return 0;
 }
 
-static int gfx_v9_0_csb_vram_pin(struct amdgpu_device *adev)
-{
-	int r;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
-	if (unlikely(r != 0))
-		return r;
-
-	r = amdgpu_bo_pin(adev->gfx.rlc.clear_state_obj,
-			AMDGPU_GEM_DOMAIN_VRAM);
-	if (!r)
-		adev->gfx.rlc.clear_state_gpu_addr =
-			amdgpu_bo_gpu_offset(adev->gfx.rlc.clear_state_obj);
-
-	amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-
-	return r;
-}
-
-static void gfx_v9_0_csb_vram_unpin(struct amdgpu_device *adev)
-{
-	int r;
-
-	if (!adev->gfx.rlc.clear_state_obj)
-		return;
-
-	r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, true);
-	if (likely(r == 0)) {
-		amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
-		amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
-	}
-}
-
 static void gfx_v9_0_mec_fini(struct amdgpu_device *adev)
 {
 	amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL);
@@ -2510,7 +2468,8 @@
 
 	gfx_v9_0_tiling_mode_table_init(adev);
 
-	gfx_v9_0_setup_rb(adev);
+	if (adev->gfx.num_gfx_rings)
+		gfx_v9_0_setup_rb(adev);
 	gfx_v9_0_get_cu_info(adev, &adev->gfx.cu_info);
 	adev->gfx.config.db_debug2 = RREG32_SOC15(GC, 0, mmDB_DEBUG2);
 
@@ -2601,6 +2560,7 @@
 
 static void gfx_v9_0_init_csb(struct amdgpu_device *adev)
 {
+	adev->gfx.rlc.funcs->get_csb_buffer(adev, adev->gfx.rlc.cs_ptr);
 	/* csib */
 	WREG32_RLC(SOC15_REG_OFFSET(GC, 0, mmRLC_CSIB_ADDR_HI),
 			adev->gfx.rlc.clear_state_gpu_addr >> 32);
@@ -2930,7 +2890,10 @@
 	 * And it's needed by gfxoff feature.
 	 */
 	if (adev->gfx.rlc.is_rlc_v2_1) {
-		gfx_v9_1_init_rlc_save_restore_list(adev);
+		if (adev->asic_type == CHIP_VEGA12 ||
+		    (adev->asic_type == CHIP_RAVEN &&
+		     adev->rev_id >= 8))
+			gfx_v9_1_init_rlc_save_restore_list(adev);
 		gfx_v9_0_enable_save_restore_machine(adev);
 	}
 
@@ -2940,8 +2903,8 @@
 			      AMD_PG_SUPPORT_CP |
 			      AMD_PG_SUPPORT_GDS |
 			      AMD_PG_SUPPORT_RLC_SMU_HS)) {
-		WREG32(mmRLC_JUMP_TABLE_RESTORE,
-		       adev->gfx.rlc.cp_table_gpu_addr >> 8);
+		WREG32_SOC15(GC, 0, mmRLC_JUMP_TABLE_RESTORE,
+			     adev->gfx.rlc.cp_table_gpu_addr >> 8);
 		gfx_v9_0_init_gfx_power_gating(adev);
 	}
 }
@@ -3760,6 +3723,7 @@
 
 		/* reset ring buffer */
 		ring->wptr = 0;
+		atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
 		amdgpu_ring_clear_ring(ring);
 	} else {
 		amdgpu_ring_clear_ring(ring);
@@ -3780,8 +3744,10 @@
 		return r;
 
 	r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
-	if (unlikely(r != 0))
+	if (unlikely(r != 0)) {
+		amdgpu_bo_unreserve(ring->mqd_obj);
 		return r;
+	}
 
 	gfx_v9_0_kiq_init_queue(ring);
 	amdgpu_bo_kunmap(ring->mqd_obj);
@@ -3889,10 +3855,6 @@
 
 	gfx_v9_0_constants_init(adev);
 
-	r = gfx_v9_0_csb_vram_pin(adev);
-	if (r)
-		return r;
-
 	r = adev->gfx.rlc.funcs->resume(adev);
 	if (r)
 		return r;
@@ -3944,7 +3906,8 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-	amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
+	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX))
+		amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
 	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
 	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
 
@@ -3978,8 +3941,6 @@
 	gfx_v9_0_cp_enable(adev, false);
 	adev->gfx.rlc.funcs->stop(adev);
 
-	gfx_v9_0_csb_vram_unpin(adev);
-
 	return 0;
 }
 
@@ -4084,11 +4045,13 @@
 {
 	uint64_t clock;
 
+	amdgpu_gfx_off_ctrl(adev, false);
 	mutex_lock(&adev->gfx.gpu_clock_mutex);
 	WREG32_SOC15(GC, 0, mmRLC_CAPTURE_GPU_CLOCK_COUNT, 1);
 	clock = (uint64_t)RREG32_SOC15(GC, 0, mmRLC_GPU_CLOCK_COUNT_LSB) |
 		((uint64_t)RREG32_SOC15(GC, 0, mmRLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
 	mutex_unlock(&adev->gfx.gpu_clock_mutex);
+	amdgpu_gfx_off_ctrl(adev, true);
 	return clock;
 }
 
@@ -4698,7 +4661,7 @@
 	amdgpu_gfx_rlc_enter_safe_mode(adev);
 
 	/* Enable 3D CGCG/CGLS */
-	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+	if (enable) {
 		/* write cmd to clear cgcg/cgls ov */
 		def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
 		/* unset CGCG override */
@@ -4710,8 +4673,12 @@
 		/* enable 3Dcgcg FSM(0x0000363f) */
 		def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D);
 
-		data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
-			RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK;
+		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)
+			data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
+				RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK;
+		else
+			data = 0x0 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT;
+
 		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS)
 			data |= (0x000F << RLC_CGCG_CGLS_CTRL_3D__CGLS_REP_COMPANSAT_DELAY__SHIFT) |
 				RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK;
@@ -4838,10 +4805,9 @@
 	switch (adev->asic_type) {
 	case CHIP_RAVEN:
 	case CHIP_RENOIR:
-		if (!enable) {
+		if (!enable)
 			amdgpu_gfx_off_ctrl(adev, false);
-			cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
-		}
+
 		if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) {
 			gfx_v9_0_enable_sck_slow_down_on_power_up(adev, true);
 			gfx_v9_0_enable_sck_slow_down_on_power_down(adev, true);
@@ -4867,12 +4833,7 @@
 			amdgpu_gfx_off_ctrl(adev, true);
 		break;
 	case CHIP_VEGA12:
-		if (!enable) {
-			amdgpu_gfx_off_ctrl(adev, false);
-			cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
-		} else {
-			amdgpu_gfx_off_ctrl(adev, true);
-		}
+		amdgpu_gfx_off_ctrl(adev, enable);
 		break;
 	default:
 		break;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
@@ -365,6 +365,8 @@
 	hub->ctx0_ptb_addr_hi32 =
 		SOC15_REG_OFFSET(GC, 0,
 				 mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
+	hub->vm_inv_eng0_sem =
+		SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG0_SEM);
 	hub->vm_inv_eng0_req =
 		SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG0_REQ);
 	hub->vm_inv_eng0_ack =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
@@ -350,6 +350,8 @@
 	hub->ctx0_ptb_addr_hi32 =
 		SOC15_REG_OFFSET(GC, 0,
 				 mmGCVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
+	hub->vm_inv_eng0_sem =
+		SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_SEM);
 	hub->vm_inv_eng0_req =
 		SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_REQ);
 	hub->vm_inv_eng0_ack =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -230,12 +230,36 @@
 				   unsigned int vmhub, uint32_t flush_type)
 {
 	struct amdgpu_vmhub *hub = &adev->vmhub[vmhub];
-	u32 tmp = gmc_v10_0_get_invalidate_req(vmid, flush_type);
+	u32 inv_req = gmc_v10_0_get_invalidate_req(vmid, flush_type);
+	u32 tmp;
 	/* Use register 17 for GART */
 	const unsigned eng = 17;
 	unsigned int i;
 
-	WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
+	spin_lock(&adev->gmc.invalidate_lock);
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (vmhub == AMDGPU_MMHUB_0 ||
+	    vmhub == AMDGPU_MMHUB_1) {
+		for (i = 0; i < adev->usec_timeout; i++) {
+			/* a read return value of 1 means semaphore acuqire */
+			tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
+			if (tmp & 0x1)
+				break;
+			udelay(1);
+		}
+
+		if (i >= adev->usec_timeout)
+			DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
+	}
+
+	WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, inv_req);
 
 	/*
 	 * Issue a dummy read to wait for the ACK register to be cleared
@@ -254,6 +278,17 @@
 		udelay(1);
 	}
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (vmhub == AMDGPU_MMHUB_0 ||
+	    vmhub == AMDGPU_MMHUB_1)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
+
+	spin_unlock(&adev->gmc.invalidate_lock);
+
 	if (i < adev->usec_timeout)
 		return;
 
@@ -338,6 +373,20 @@
 	uint32_t req = gmc_v10_0_get_invalidate_req(vmid, 0);
 	unsigned eng = ring->vm_inv_eng;
 
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/* a read return value of 1 means semaphore acuqire */
+		amdgpu_ring_emit_reg_wait(ring,
+					  hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
+
 	amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
 			      lower_32_bits(pd_addr));
 
@@ -348,6 +397,15 @@
 					    hub->vm_inv_eng0_ack + eng,
 					    req, 1 << vmid);
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
+	    ring->funcs->vmhub == AMDGPU_MMHUB_1)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
+
 	return pd_addr;
 }
 
@@ -845,6 +903,8 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	gmc_v10_0_gart_disable(adev);
+
 	if (amdgpu_sriov_vf(adev)) {
 		/* full access mode, so don't touch any GMC register */
 		DRM_DEBUG("For SRIOV client, shouldn't do anything.\n");
@@ -852,7 +912,6 @@
 	}
 
 	amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0);
-	gmc_v10_0_gart_disable(adev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -863,12 +863,12 @@
 
 	adev->gmc.mc_mask = 0xffffffffffULL;
 
-	r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(44));
+	r = dma_set_mask_and_coherent(adev->dev, DMA_BIT_MASK(40));
 	if (r) {
 		dev_warn(adev->dev, "amdgpu: No suitable DMA available.\n");
 		return r;
 	}
-	adev->need_swiotlb = drm_need_swiotlb(44);
+	adev->need_swiotlb = drm_need_swiotlb(40);
 
 	r = gmc_v6_0_init_microcode(adev);
 	if (r) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -524,10 +524,10 @@
 static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
 {
 	int r;
+	u32 tmp;
 
 	adev->gmc.vram_width = amdgpu_atombios_get_vram_width(adev);
 	if (!adev->gmc.vram_width) {
-		u32 tmp;
 		int chansize, numchan;
 
 		/* Get VRAM informations */
@@ -571,8 +571,15 @@
 		adev->gmc.vram_width = numchan * chansize;
 	}
 	/* size in MB on si */
-	adev->gmc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
-	adev->gmc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+	tmp = RREG32(mmCONFIG_MEMSIZE);
+	/* some boards may have garbage in the upper 16 bits */
+	if (tmp & 0xffff0000) {
+		DRM_INFO("Probable bad vram size: 0x%08x\n", tmp);
+		if (tmp & 0xffff)
+			tmp &= 0xffff;
+	}
+	adev->gmc.mc_vram_size = tmp * 1024ULL * 1024ULL;
+	adev->gmc.real_vram_size = adev->gmc.mc_vram_size;
 
 	if (!(adev->flags & AMD_IS_APU)) {
 		r = amdgpu_device_resize_fb_bar(adev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -448,6 +448,24 @@
 	return req;
 }
 
+/**
+ * gmc_v9_0_use_invalidate_semaphore - judge whether to use semaphore
+ *
+ * @adev: amdgpu_device pointer
+ * @vmhub: vmhub type
+ *
+ */
+static bool gmc_v9_0_use_invalidate_semaphore(struct amdgpu_device *adev,
+				       uint32_t vmhub)
+{
+	return ((vmhub == AMDGPU_MMHUB_0 ||
+		 vmhub == AMDGPU_MMHUB_1) &&
+		(!amdgpu_sriov_vf(adev)) &&
+		(!(adev->asic_type == CHIP_RAVEN &&
+		   adev->rev_id < 0x8 &&
+		   adev->pdev->device == 0x15d8)));
+}
+
 /*
  * GART
  * VMID 0 is the physical GPU addresses as used by the kernel.
@@ -467,14 +485,15 @@
 static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
 					uint32_t vmhub, uint32_t flush_type)
 {
+	bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(adev, vmhub);
 	const unsigned eng = 17;
-	u32 j, tmp;
+	u32 j, inv_req, tmp;
 	struct amdgpu_vmhub *hub;
 
 	BUG_ON(vmhub >= adev->num_vmhubs);
 
 	hub = &adev->vmhub[vmhub];
-	tmp = gmc_v9_0_get_invalidate_req(vmid, flush_type);
+	inv_req = gmc_v9_0_get_invalidate_req(vmid, flush_type);
 
 	/* This is necessary for a HW workaround under SRIOV as well
 	 * as GFXOFF under bare metal
@@ -485,13 +504,35 @@
 		uint32_t req = hub->vm_inv_eng0_req + eng;
 		uint32_t ack = hub->vm_inv_eng0_ack + eng;
 
-		amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, tmp,
+		amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, inv_req,
 				1 << vmid);
 		return;
 	}
 
 	spin_lock(&adev->gmc.invalidate_lock);
-	WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
+
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (use_semaphore) {
+		for (j = 0; j < adev->usec_timeout; j++) {
+			/* a read return value of 1 means semaphore acuqire */
+			tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
+			if (tmp & 0x1)
+				break;
+			udelay(1);
+		}
+
+		if (j >= adev->usec_timeout)
+			DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
+	}
+
+	WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, inv_req);
 
 	/*
 	 * Issue a dummy read to wait for the ACK register to be cleared
@@ -506,7 +547,17 @@
 			break;
 		udelay(1);
 	}
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (use_semaphore)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
+
 	spin_unlock(&adev->gmc.invalidate_lock);
+
 	if (j < adev->usec_timeout)
 		return;
 
@@ -516,11 +567,25 @@
 static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
 					    unsigned vmid, uint64_t pd_addr)
 {
+	bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub);
 	struct amdgpu_device *adev = ring->adev;
 	struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub];
 	uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0);
 	unsigned eng = ring->vm_inv_eng;
 
+	/*
+	 * It may lose gpuvm invalidate acknowldege state across power-gating
+	 * off cycle, add semaphore acquire before invalidation and semaphore
+	 * release after invalidation to avoid entering power gated state
+	 * to WA the Issue
+	 */
+
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (use_semaphore)
+		/* a read return value of 1 means semaphore acuqire */
+		amdgpu_ring_emit_reg_wait(ring,
+					  hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
+
 	amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
 			      lower_32_bits(pd_addr));
 
@@ -531,6 +596,14 @@
 					    hub->vm_inv_eng0_ack + eng,
 					    req, 1 << vmid);
 
+	/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
+	if (use_semaphore)
+		/*
+		 * add semaphore release after invalidation,
+		 * write with 0 means semaphore release
+		 */
+		amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
+
 	return pd_addr;
 }
 
@@ -1310,6 +1383,19 @@
 }
 
 /**
+ * gmc_v9_0_restore_registers - restores regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This restores register values, saved at suspend.
+ */
+static void gmc_v9_0_restore_registers(struct amdgpu_device *adev)
+{
+	if (adev->asic_type == CHIP_RAVEN)
+		WREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0, adev->gmc.sdpif_register);
+}
+
+/**
  * gmc_v9_0_gart_enable - gart enable
  *
  * @adev: amdgpu_device pointer
@@ -1406,6 +1492,20 @@
 }
 
 /**
+ * gmc_v9_0_save_registers - saves regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This saves potential register values that should be
+ * restored upon resume
+ */
+static void gmc_v9_0_save_registers(struct amdgpu_device *adev)
+{
+	if (adev->asic_type == CHIP_RAVEN)
+		adev->gmc.sdpif_register = RREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0);
+}
+
+/**
  * gmc_v9_0_gart_disable - gart disable
  *
  * @adev: amdgpu_device pointer
@@ -1426,24 +1526,31 @@
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	gmc_v9_0_gart_disable(adev);
+
 	if (amdgpu_sriov_vf(adev)) {
 		/* full access mode, so don't touch any GMC register */
 		DRM_DEBUG("For SRIOV client, shouldn't do anything.\n");
 		return 0;
 	}
 
-	amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);
 	amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0);
-	gmc_v9_0_gart_disable(adev);
 
 	return 0;
 }
 
 static int gmc_v9_0_suspend(void *handle)
 {
+	int r;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-	return gmc_v9_0_hw_fini(adev);
+	r = gmc_v9_0_hw_fini(adev);
+	if (r)
+		return r;
+
+	gmc_v9_0_save_registers(adev);
+
+	return 0;
 }
 
 static int gmc_v9_0_resume(void *handle)
@@ -1451,6 +1558,7 @@
 	int r;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+	gmc_v9_0_restore_registers(adev);
 	r = gmc_v9_0_hw_init(adev);
 	if (r)
 		return r;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -193,19 +193,29 @@
 
 	wptr = le32_to_cpu(*ih->wptr_cpu);
 
-	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, ih->rptr, (wptr + 16) & ih->ptr_mask);
-		ih->rptr = (wptr + 16) & 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, ih->rptr, (wptr + 16) & ih->ptr_mask);
+	ih->rptr = (wptr + 16) & 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);
+
+
+out:
 	return (wptr & ih->ptr_mask);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
@@ -1609,19 +1609,7 @@
 
 static u8 kv_get_acp_boot_level(struct amdgpu_device *adev)
 {
-	u8 i;
-	struct amdgpu_clock_voltage_dependency_table *table =
-		&adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
-
-	for (i = 0; i < table->count; i++) {
-		if (table->entries[i].clk >= 0) /* XXX */
-			break;
-	}
-
-	if (i >= table->count)
-		i = table->count - 1;
-
-	return i;
+	return 0;
 }
 
 static void kv_update_acp_boot_level(struct amdgpu_device *adev)
@@ -2745,10 +2733,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];
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
@@ -29,8 +29,6 @@
 #include "gc/gc_10_1_0_offset.h"
 #include "gc/gc_10_1_0_sh_mask.h"
 
-MODULE_FIRMWARE("amdgpu/navi10_mes.bin");
-
 static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes,
 				  struct mes_add_queue_input *input)
 {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
@@ -182,6 +182,7 @@
 	tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1);
 	WREG32_SOC15(MMHUB, 0, mmVM_L2_CNTL2, tmp);
 
+	tmp = mmVM_L2_CNTL3_DEFAULT;
 	if (adev->gmc.translate_further) {
 		tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, BANK_SELECT, 12);
 		tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3,
@@ -418,6 +419,8 @@
 	hub->ctx0_ptb_addr_hi32 =
 		SOC15_REG_OFFSET(MMHUB, 0,
 				 mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
+	hub->vm_inv_eng0_sem =
+		SOC15_REG_OFFSET(MMHUB, 0, mmVM_INVALIDATE_ENG0_SEM);
 	hub->vm_inv_eng0_req =
 		SOC15_REG_OFFSET(MMHUB, 0, mmVM_INVALIDATE_ENG0_REQ);
 	hub->vm_inv_eng0_ack =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@ -341,6 +341,8 @@
 	hub->ctx0_ptb_addr_hi32 =
 		SOC15_REG_OFFSET(MMHUB, 0,
 				 mmMMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
+	hub->vm_inv_eng0_sem =
+		SOC15_REG_OFFSET(MMHUB, 0, mmMMVM_INVALIDATE_ENG0_SEM);
 	hub->vm_inv_eng0_req =
 		SOC15_REG_OFFSET(MMHUB, 0, mmMMVM_INVALIDATE_ENG0_REQ);
 	hub->vm_inv_eng0_ack =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
@@ -502,6 +502,10 @@
 			SOC15_REG_OFFSET(MMHUB, 0,
 			    mmVML2VC0_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) +
 			    i * MMHUB_INSTANCE_REGISTER_OFFSET;
+		hub[i]->vm_inv_eng0_sem =
+			SOC15_REG_OFFSET(MMHUB, 0,
+					 mmVML2VC0_VM_INVALIDATE_ENG0_SEM) +
+					 i * MMHUB_INSTANCE_REGISTER_OFFSET;
 		hub[i]->vm_inv_eng0_req =
 			SOC15_REG_OFFSET(MMHUB, 0,
 					 mmVML2VC0_VM_INVALIDATE_ENG0_REQ) +
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h
@@ -73,6 +73,22 @@
 #define SDMA_OP_AQL_COPY  0
 #define SDMA_OP_AQL_BARRIER_OR  0
 
+#define SDMA_GCR_RANGE_IS_PA		(1 << 18)
+#define SDMA_GCR_SEQ(x)			(((x) & 0x3) << 16)
+#define SDMA_GCR_GL2_WB			(1 << 15)
+#define SDMA_GCR_GL2_INV		(1 << 14)
+#define SDMA_GCR_GL2_DISCARD		(1 << 13)
+#define SDMA_GCR_GL2_RANGE(x)		(((x) & 0x3) << 11)
+#define SDMA_GCR_GL2_US			(1 << 10)
+#define SDMA_GCR_GL1_INV		(1 << 9)
+#define SDMA_GCR_GLV_INV		(1 << 8)
+#define SDMA_GCR_GLK_INV		(1 << 7)
+#define SDMA_GCR_GLK_WB			(1 << 6)
+#define SDMA_GCR_GLM_INV		(1 << 5)
+#define SDMA_GCR_GLM_WB			(1 << 4)
+#define SDMA_GCR_GL1_RANGE(x)		(((x) & 0x3) << 2)
+#define SDMA_GCR_GLI_INV(x)		(((x) & 0x3) << 0)
+
 /*define for op field*/
 #define SDMA_PKT_HEADER_op_offset 0
 #define SDMA_PKT_HEADER_op_mask   0x000000FF
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/nv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -660,6 +660,12 @@
 		adev->pg_flags = AMD_PG_SUPPORT_VCN |
 			AMD_PG_SUPPORT_VCN_DPG |
 			AMD_PG_SUPPORT_ATHUB;
+		/* guest vm gets 0xffffffff when reading RCC_DEV0_EPF0_STRAP0,
+		 * as a consequence, the rev_id and external_rev_id are wrong.
+		 * workaround it by hardcoding rev_id to 0 (default value).
+		 */
+		if (amdgpu_sriov_vf(adev))
+			adev->rev_id = 0;
 		adev->external_rev_id = adev->rev_id + 0xa;
 		break;
 	default:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
@@ -44,7 +44,7 @@
     GFX_CTRL_CMD_ID_DISABLE_INT     = 0x00060000,   /* disable PSP-to-Gfx interrupt */
     GFX_CTRL_CMD_ID_MODE1_RST       = 0x00070000,   /* trigger the Mode 1 reset */
     GFX_CTRL_CMD_ID_GBR_IH_SET      = 0x00080000,   /* set Gbr IH_RB_CNTL registers */
-    GFX_CTRL_CMD_ID_CONSUME_CMD     = 0x000A0000,   /* send interrupt to psp for updating write pointer of vf */
+    GFX_CTRL_CMD_ID_CONSUME_CMD     = 0x00090000,   /* send interrupt to psp for updating write pointer of vf */
     GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING = 0x000C0000, /* destroy GPCOM ring */
 
     GFX_CTRL_CMD_ID_MAX             = 0x000F0000,   /* max command ID */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -40,15 +40,10 @@
 
 MODULE_FIRMWARE("amdgpu/vega20_sos.bin");
 MODULE_FIRMWARE("amdgpu/vega20_asd.bin");
-MODULE_FIRMWARE("amdgpu/vega20_ta.bin");
 MODULE_FIRMWARE("amdgpu/navi10_sos.bin");
 MODULE_FIRMWARE("amdgpu/navi10_asd.bin");
 MODULE_FIRMWARE("amdgpu/navi14_sos.bin");
 MODULE_FIRMWARE("amdgpu/navi14_asd.bin");
-MODULE_FIRMWARE("amdgpu/navi12_sos.bin");
-MODULE_FIRMWARE("amdgpu/navi12_asd.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_sos.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_asd.bin");
 
 /* address block */
 #define smnMP1_FIRMWARE_FLAGS		0x3010024
@@ -398,6 +393,34 @@
 	return false;
 }
 
+static int psp_v11_0_ring_stop(struct psp_context *psp,
+			      enum psp_ring_type ring_type)
+{
+	int ret = 0;
+	struct amdgpu_device *adev = psp->adev;
+
+	/* Write the ring destroy command*/
+	if (psp_v11_0_support_vmr_ring(psp))
+		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101,
+				     GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING);
+	else
+		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64,
+				     GFX_CTRL_CMD_ID_DESTROY_RINGS);
+
+	/* there might be handshake issue with hardware which needs delay */
+	mdelay(20);
+
+	/* Wait for response flag (bit 31) */
+	if (psp_v11_0_support_vmr_ring(psp))
+		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+				   0x80000000, 0x80000000, false);
+	else
+		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+				   0x80000000, 0x80000000, false);
+
+	return ret;
+}
+
 static int psp_v11_0_ring_create(struct psp_context *psp,
 				enum psp_ring_type ring_type)
 {
@@ -407,6 +430,12 @@
 	struct amdgpu_device *adev = psp->adev;
 
 	if (psp_v11_0_support_vmr_ring(psp)) {
+		ret = psp_v11_0_ring_stop(psp, ring_type);
+		if (ret) {
+			DRM_ERROR("psp_v11_0_ring_stop_sriov failed!\n");
+			return ret;
+		}
+
 		/* Write low address of the ring to C2PMSG_102 */
 		psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
 		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_ring_reg);
@@ -451,33 +480,6 @@
 	return ret;
 }
 
-static int psp_v11_0_ring_stop(struct psp_context *psp,
-			      enum psp_ring_type ring_type)
-{
-	int ret = 0;
-	struct amdgpu_device *adev = psp->adev;
-
-	/* Write the ring destroy command*/
-	if (psp_v11_0_support_vmr_ring(psp))
-		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101,
-				     GFX_CTRL_CMD_ID_DESTROY_GPCOM_RING);
-	else
-		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64,
-				     GFX_CTRL_CMD_ID_DESTROY_RINGS);
-
-	/* there might be handshake issue with hardware which needs delay */
-	mdelay(20);
-
-	/* Wait for response flag (bit 31) */
-	if (psp_v11_0_support_vmr_ring(psp))
-		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
-				   0x80000000, 0x80000000, false);
-	else
-		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
-				   0x80000000, 0x80000000, false);
-
-	return ret;
-}
 
 static int psp_v11_0_ring_destroy(struct psp_context *psp,
 				 enum psp_ring_type ring_type)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -255,7 +255,7 @@
 	unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
 	/* IB packet must end on a 8 DW boundary */
-	sdma_v2_4_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
+	sdma_v2_4_ring_insert_nop(ring, (2 - lower_32_bits(ring->wptr)) & 7);
 
 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |
 			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid & 0xf));
@@ -750,7 +750,7 @@
 	u32 pad_count;
 	int i;
 
-	pad_count = (8 - (ib->length_dw & 0x7)) % 8;
+	pad_count = (-ib->length_dw) & 7;
 	for (i = 0; i < pad_count; i++)
 		if (sdma && sdma->burst_nop && (i == 0))
 			ib->ptr[ib->length_dw++] =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -429,7 +429,7 @@
 	unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
 	/* IB packet must end on a 8 DW boundary */
-	sdma_v3_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
+	sdma_v3_0_ring_insert_nop(ring, (2 - lower_32_bits(ring->wptr)) & 7);
 
 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |
 			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid & 0xf));
@@ -1021,7 +1021,7 @@
 	u32 pad_count;
 	int i;
 
-	pad_count = (8 - (ib->length_dw & 0x7)) % 8;
+	pad_count = (-ib->length_dw) & 7;
 	for (i = 0; i < pad_count; i++)
 		if (sdma && sdma->burst_nop && (i == 0))
 			ib->ptr[ib->length_dw++] =
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -67,7 +67,6 @@
 MODULE_FIRMWARE("amdgpu/raven_sdma.bin");
 MODULE_FIRMWARE("amdgpu/picasso_sdma.bin");
 MODULE_FIRMWARE("amdgpu/raven2_sdma.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_sdma.bin");
 MODULE_FIRMWARE("amdgpu/renoir_sdma.bin");
 
 #define SDMA0_POWER_CNTL__ON_OFF_CONDITION_HOLD_TIME_MASK  0x000000F8L
@@ -698,7 +697,7 @@
 	unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 
 	/* IB packet must end on a 8 DW boundary */
-	sdma_v4_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
+	sdma_v4_0_ring_insert_nop(ring, (2 - lower_32_bits(ring->wptr)) & 7);
 
 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |
 			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid & 0xf));
@@ -1579,7 +1578,7 @@
 	u32 pad_count;
 	int i;
 
-	pad_count = (8 - (ib->length_dw & 0x7)) % 8;
+	pad_count = (-ib->length_dw) & 7;
 	for (i = 0; i < pad_count; i++)
 		if (sdma && sdma->burst_nop && (i == 0))
 			ib->ptr[ib->length_dw++] =
@@ -1911,9 +1910,11 @@
 	if (amdgpu_sriov_vf(adev))
 		return 0;
 
-	for (i = 0; i < adev->sdma.num_instances; i++) {
-		amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
-			       AMDGPU_SDMA_IRQ_INSTANCE0 + i);
+	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) {
+		for (i = 0; i < adev->sdma.num_instances; i++) {
+			amdgpu_irq_put(adev, &adev->sdma.ecc_irq,
+				       AMDGPU_SDMA_IRQ_INSTANCE0 + i);
+		}
 	}
 
 	sdma_v4_0_ctx_switch_enable(adev, false);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -48,9 +48,6 @@
 MODULE_FIRMWARE("amdgpu/navi14_sdma.bin");
 MODULE_FIRMWARE("amdgpu/navi14_sdma1.bin");
 
-MODULE_FIRMWARE("amdgpu/navi12_sdma.bin");
-MODULE_FIRMWARE("amdgpu/navi12_sdma1.bin");
-
 #define SDMA1_REG_OFFSET 0x600
 #define SDMA0_HYP_DEC_REG_START 0x5880
 #define SDMA0_HYP_DEC_REG_END 0x5893
@@ -100,6 +97,10 @@
 
 static const struct soc15_reg_golden golden_settings_sdma_nv12[] = {
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA0_RLC3_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA0_GB_ADDR_CONFIG, 0x001877ff, 0x00000044),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA0_GB_ADDR_CONFIG_READ, 0x001877ff, 0x00000044),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA1_GB_ADDR_CONFIG, 0x001877ff, 0x00000044),
+	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA1_GB_ADDR_CONFIG_READ, 0x001877ff, 0x00000044),
 	SOC15_REG_GOLDEN_VALUE(GC, 0, mmSDMA1_RLC3_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
 };
 
@@ -286,30 +287,20 @@
 static uint64_t sdma_v5_0_ring_get_wptr(struct amdgpu_ring *ring)
 {
 	struct amdgpu_device *adev = ring->adev;
-	u64 *wptr = NULL;
-	uint64_t local_wptr = 0;
+	u64 wptr;
 
 	if (ring->use_doorbell) {
 		/* XXX check if swapping is necessary on BE */
-		wptr = ((u64 *)&adev->wb.wb[ring->wptr_offs]);
-		DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", *wptr);
-		*wptr = (*wptr) >> 2;
-		DRM_DEBUG("wptr/doorbell after shift == 0x%016llx\n", *wptr);
+		wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
+		DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr);
 	} else {
-		u32 lowbit, highbit;
-
-		wptr = &local_wptr;
-		lowbit = RREG32(sdma_v5_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR)) >> 2;
-		highbit = RREG32(sdma_v5_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2;
-
-		DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n",
-				ring->me, highbit, lowbit);
-		*wptr = highbit;
-		*wptr = (*wptr) << 32;
-		*wptr |= lowbit;
+		wptr = RREG32(sdma_v5_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI));
+		wptr = wptr << 32;
+		wptr |= RREG32(sdma_v5_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR));
+		DRM_DEBUG("wptr before shift [%i] wptr == 0x%016llx\n", ring->me, wptr);
 	}
 
-	return *wptr;
+	return wptr >> 2;
 }
 
 /**
@@ -382,8 +373,27 @@
 	unsigned vmid = AMDGPU_JOB_GET_VMID(job);
 	uint64_t csa_mc_addr = amdgpu_sdma_get_csa_mc_addr(ring, vmid);
 
-	/* IB packet must end on a 8 DW boundary */
-	sdma_v5_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
+	/* Invalidate L2, because if we don't do it, we might get stale cache
+	 * lines from previous IBs.
+	 */
+	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_GCR_REQ));
+	amdgpu_ring_write(ring, 0);
+	amdgpu_ring_write(ring, (SDMA_GCR_GL2_INV |
+				 SDMA_GCR_GL2_WB |
+				 SDMA_GCR_GLM_INV |
+				 SDMA_GCR_GLM_WB) << 16);
+	amdgpu_ring_write(ring, 0xffffff80);
+	amdgpu_ring_write(ring, 0xffff);
+
+	/* An IB packet must end on a 8 DW boundary--the next dword
+	 * must be on a 8-dword boundary. Our IB packet below is 6
+	 * dwords long, thus add x number of NOPs, such that, in
+	 * modular arithmetic,
+	 * wptr + 6 + x = 8k, k >= 0, which in C is,
+	 * (wptr + 6 + x) % 8 = 0.
+	 * The expression below, is a solution of x.
+	 */
+	sdma_v5_0_ring_insert_nop(ring, (2 - lower_32_bits(ring->wptr)) & 7);
 
 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) |
 			  SDMA_PKT_INDIRECT_HEADER_VMID(vmid & 0xf));
@@ -1086,10 +1096,10 @@
 }
 
 /**
- * sdma_v5_0_ring_pad_ib - pad the IB to the required number of dw
- *
+ * sdma_v5_0_ring_pad_ib - pad the IB
  * @ib: indirect buffer to fill with padding
  *
+ * Pad the IB with NOPs to a boundary multiple of 8.
  */
 static void sdma_v5_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
 {
@@ -1097,7 +1107,7 @@
 	u32 pad_count;
 	int i;
 
-	pad_count = (8 - (ib->length_dw & 0x7)) % 8;
+	pad_count = (-ib->length_dw) & 0x7;
 	for (i = 0; i < pad_count; i++)
 		if (sdma && sdma->burst_nop && (i == 0))
 			ib->ptr[ib->length_dw++] =
@@ -1254,8 +1264,12 @@
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 	int i;
 
-	for (i = 0; i < adev->sdma.num_instances; i++)
+	for (i = 0; i < adev->sdma.num_instances; i++) {
+		if (adev->sdma.instance[i].fw != NULL)
+			release_firmware(adev->sdma.instance[i].fw);
+
 		amdgpu_ring_fini(&adev->sdma.instance[i].ring);
+	}
 
 	return 0;
 }
@@ -1600,7 +1614,7 @@
 		SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
 		SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 * 2 +
 		10 + 10 + 10, /* sdma_v5_0_ring_emit_fence x3 for user fence, vm fence */
-	.emit_ib_size = 7 + 6, /* sdma_v5_0_ring_emit_ib */
+	.emit_ib_size = 5 + 7 + 6, /* sdma_v5_0_ring_emit_ib */
 	.emit_ib = sdma_v5_0_ring_emit_ib,
 	.emit_fence = sdma_v5_0_ring_emit_fence,
 	.emit_pipeline_sync = sdma_v5_0_ring_emit_pipeline_sync,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/si.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/si.c
@@ -1633,7 +1633,6 @@
 static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 {
 	struct pci_dev *root = adev->pdev->bus->self;
-	int bridge_pos, gpu_pos;
 	u32 speed_cntl, current_data_rate;
 	int i;
 	u16 tmp16;
@@ -1668,12 +1667,7 @@
 		DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
 	}
 
-	bridge_pos = pci_pcie_cap(root);
-	if (!bridge_pos)
-		return;
-
-	gpu_pos = pci_pcie_cap(adev->pdev);
-	if (!gpu_pos)
+	if (!pci_is_pcie(root) || !pci_is_pcie(adev->pdev))
 		return;
 
 	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
@@ -1682,14 +1676,8 @@
 			u16 bridge_cfg2, gpu_cfg2;
 			u32 max_lw, current_lw, tmp;
 
-			pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-			pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
+			pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
 
 			tmp = RREG32_PCIE(PCIE_LC_STATUS1);
 			max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -1706,15 +1694,23 @@
 			}
 
 			for (i = 0; i < 10; i++) {
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_DEVSTA,
+							  &tmp16);
 				if (tmp16 & PCI_EXP_DEVSTA_TRPND)
 					break;
 
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+							  &bridge_cfg);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL,
+							  &gpu_cfg);
+
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &bridge_cfg2);
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &gpu_cfg2);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp |= LC_SET_QUIESCE;
@@ -1726,25 +1722,37 @@
 
 				mdelay(100);
 
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
-
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-				pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   bridge_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
+				pcie_capability_clear_and_set_word(adev->pdev, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   gpu_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
+
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (bridge_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(root,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
+
+				pcie_capability_read_word(adev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (gpu_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(adev->pdev,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp &= ~LC_SET_QUIESCE;
@@ -1757,15 +1765,16 @@
 	speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
 	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-	pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-	tmp16 &= ~0xf;
+	pcie_capability_read_word(adev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+	tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
+
 	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-		tmp16 |= 3;
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
 	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
-		tmp16 |= 2;
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
 	else
-		tmp16 |= 1;
-	pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+	pcie_capability_write_word(adev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
 	speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
 	speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -7250,17 +7250,15 @@
 	if (!adev->pm.dpm.ps)
 		return -ENOMEM;
 	power_state_offset = (u8 *)state_array->states;
-	for (i = 0; i < state_array->ucNumEntries; i++) {
+	for (adev->pm.dpm.num_ps = 0, i = 0; i < state_array->ucNumEntries; i++) {
 		u8 *idx;
 		power_state = (union pplib_power_state *)power_state_offset;
 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
 		ps = kzalloc(sizeof(struct  si_ps), GFP_KERNEL);
-		if (ps == NULL) {
-			kfree(adev->pm.dpm.ps);
+		if (ps == NULL)
 			return -ENOMEM;
-		}
 		adev->pm.dpm.ps[i].ps_priv = ps;
 		si_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
 					      non_clock_info,
@@ -7282,8 +7280,8 @@
 			k++;
 		}
 		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+		adev->pm.dpm.num_ps++;
 	}
-	adev->pm.dpm.num_ps = state_array->ucNumEntries;
 
 	/* fill in the vce power states */
 	for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) {
@@ -7351,10 +7349,9 @@
 		kcalloc(4,
 			sizeof(struct amdgpu_clock_voltage_dependency_entry),
 			GFP_KERNEL);
-	if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
-		amdgpu_free_extended_power_table(adev);
+	if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries)
 		return -ENOMEM;
-	}
+
 	adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
 	adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
 	adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/si_ih.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/si_ih.c
@@ -64,7 +64,8 @@
 	u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
 
 	si_ih_disable_interrupts(adev);
-	WREG32(INTERRUPT_CNTL2, adev->irq.ih.gpu_addr >> 8);
+	/* set dummy read address to dummy page address */
+	WREG32(INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
 	interrupt_cntl = RREG32(INTERRUPT_CNTL);
 	interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
 	interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/soc15.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/soc15.c
@@ -84,6 +84,13 @@
 #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK	0x00010000L
 #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK		0x00020000L
 #define mmHDP_MEM_POWER_CTRL_BASE_IDX	0
+
+/* for Vega20/arcturus regiter offset change */
+#define	mmROM_INDEX_VG20				0x00e4
+#define	mmROM_INDEX_VG20_BASE_IDX			0
+#define	mmROM_DATA_VG20					0x00e5
+#define	mmROM_DATA_VG20_BASE_IDX			0
+
 /*
  * Indirect registers accessor
  */
@@ -267,7 +274,14 @@
 
 static u32 soc15_get_xclk(struct amdgpu_device *adev)
 {
-	return adev->clock.spll.reference_freq;
+	u32 reference_clock = adev->clock.spll.reference_freq;
+
+	if (adev->asic_type == CHIP_RENOIR)
+		return 10000;
+	if (adev->asic_type == CHIP_RAVEN)
+		return reference_clock / 4;
+
+	return reference_clock;
 }
 
 
@@ -299,6 +313,8 @@
 {
 	u32 *dw_ptr;
 	u32 i, length_dw;
+	uint32_t rom_index_offset;
+	uint32_t rom_data_offset;
 
 	if (bios == NULL)
 		return false;
@@ -311,11 +327,23 @@
 	dw_ptr = (u32 *)bios;
 	length_dw = ALIGN(length_bytes, 4) / 4;
 
+	switch (adev->asic_type) {
+	case CHIP_VEGA20:
+	case CHIP_ARCTURUS:
+		rom_index_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX_VG20);
+		rom_data_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA_VG20);
+		break;
+	default:
+		rom_index_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX);
+		rom_data_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA);
+		break;
+	}
+
 	/* set rom index to 0 */
-	WREG32(SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX), 0);
+	WREG32(rom_index_offset, 0);
 	/* read out the rom data */
 	for (i = 0; i < length_dw; i++)
-		dw_ptr[i] = RREG32(SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA));
+		dw_ptr[i] = RREG32(rom_data_offset);
 
 	return true;
 }
@@ -1104,7 +1132,6 @@
 			adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
 				AMD_CG_SUPPORT_GFX_MGLS |
 				AMD_CG_SUPPORT_GFX_CP_LS |
-				AMD_CG_SUPPORT_GFX_3D_CGCG |
 				AMD_CG_SUPPORT_GFX_3D_CGLS |
 				AMD_CG_SUPPORT_GFX_CGCG |
 				AMD_CG_SUPPORT_GFX_CGLS |
@@ -1116,16 +1143,17 @@
 				AMD_CG_SUPPORT_SDMA_MGCG |
 				AMD_CG_SUPPORT_SDMA_LS;
 
+			/*
+			 * MMHUB PG needs to be disabled for Picasso for
+			 * stability reasons.
+			 */
 			adev->pg_flags = AMD_PG_SUPPORT_SDMA |
-				AMD_PG_SUPPORT_MMHUB |
-				AMD_PG_SUPPORT_VCN |
-				AMD_PG_SUPPORT_VCN_DPG;
+				AMD_PG_SUPPORT_VCN;
 		} else {
 			adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
 				AMD_CG_SUPPORT_GFX_MGLS |
 				AMD_CG_SUPPORT_GFX_RLC_LS |
 				AMD_CG_SUPPORT_GFX_CP_LS |
-				AMD_CG_SUPPORT_GFX_3D_CGCG |
 				AMD_CG_SUPPORT_GFX_3D_CGLS |
 				AMD_CG_SUPPORT_GFX_CGCG |
 				AMD_CG_SUPPORT_GFX_CGLS |
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/soc15.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/soc15.h
@@ -28,8 +28,8 @@
 #include "nbio_v7_0.h"
 #include "nbio_v7_4.h"
 
-#define SOC15_FLUSH_GPU_TLB_NUM_WREG		4
-#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT	1
+#define SOC15_FLUSH_GPU_TLB_NUM_WREG		6
+#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT	3
 
 extern const struct amd_ip_funcs soc15_common_ip_funcs;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/soc15_common.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/soc15_common.h
@@ -52,6 +52,7 @@
 		uint32_t old_ = 0;	\
 		uint32_t tmp_ = RREG32(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg); \
 		uint32_t loop = adev->usec_timeout;		\
+		ret = 0;					\
 		while ((tmp_ & (mask)) != (expected_value)) {	\
 			if (old_ != tmp_) {			\
 				loop = adev->usec_timeout;	\
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -195,19 +195,30 @@
 
 	wptr = le32_to_cpu(*ih->wptr_cpu);
 
-	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, ih->rptr, (wptr + 16) & ih->ptr_mask);
-		ih->rptr = (wptr + 16) & 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, ih->rptr, (wptr + 16) & ih->ptr_mask);
+	ih->rptr = (wptr + 16) & 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);
+
+out:
 	return (wptr & ih->ptr_mask);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -354,6 +354,7 @@
 
 error:
 	dma_fence_put(fence);
+	amdgpu_bo_unpin(bo);
 	amdgpu_bo_unreserve(bo);
 	amdgpu_bo_unref(&bo);
 	return r;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -233,9 +233,13 @@
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 	struct amdgpu_ring *ring = &adev->vcn.inst->ring_dec;
 
+	cancel_delayed_work_sync(&adev->vcn.idle_work);
+
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-		RREG32_SOC15(VCN, 0, mmUVD_STATUS))
+		(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
+		 RREG32_SOC15(VCN, 0, mmUVD_STATUS))) {
 		vcn_v1_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+	}
 
 	ring->sched.ready = false;
 
@@ -1375,7 +1379,7 @@
 
 	if (enable) {
 		/* wait for STATUS to clear */
-		if (vcn_v1_0_is_idle(handle))
+		if (!vcn_v1_0_is_idle(handle))
 			return -EBUSY;
 		vcn_v1_0_enable_clock_gating(adev);
 	} else {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -293,6 +293,8 @@
 	struct amdgpu_ring *ring = &adev->vcn.inst->ring_dec;
 	int i;
 
+	cancel_delayed_work_sync(&adev->vcn.idle_work);
+
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 	    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(VCN, 0, mmUVD_STATUS)))
@@ -1026,6 +1028,10 @@
 	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
 	WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_CNTL, tmp);
 
+	/* Stall DPG before WPTR/RPTR reset */
+	WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS),
+		UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
+		~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
 	/* set the write pointer delay */
 	WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR_CNTL, 0);
 
@@ -1048,6 +1054,9 @@
 	WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
 		lower_32_bits(ring->wptr));
 
+	/* Unstall DPG */
+	WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS),
+		0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
 	return 0;
 }
 
@@ -1357,8 +1366,13 @@
 					   UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
 					   UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK, ret_code);
 
+				/* Stall DPG before WPTR/RPTR reset */
+				WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS),
+					   UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
+					   ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
 				/* Restore */
 				ring = &adev->vcn.inst->ring_enc[0];
+				ring->wptr = 0;
 				WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_LO, ring->gpu_addr);
 				WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
 				WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE, ring->ring_size / 4);
@@ -1366,6 +1380,7 @@
 				WREG32_SOC15(UVD, 0, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
 
 				ring = &adev->vcn.inst->ring_enc[1];
+				ring->wptr = 0;
 				WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_LO2, ring->gpu_addr);
 				WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
 				WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4);
@@ -1374,6 +1389,9 @@
 
 				WREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR,
 					   RREG32_SOC15(UVD, 0, mmUVD_SCRATCH2) & 0x7FFFFFFF);
+				/* Unstall DPG */
+				WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS),
+					   0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
 
 				SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_POWER_STATUS,
 					   UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -302,6 +302,8 @@
 	struct amdgpu_ring *ring;
 	int i;
 
+	cancel_delayed_work_sync(&adev->vcn.idle_work);
+
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
 			continue;
@@ -423,7 +425,6 @@
  * vcn_v2_5_disable_clock_gating - disable VCN clock gating
  *
  * @adev: amdgpu_device pointer
- * @sw: enable SW clock gating
  *
  * Disable clock gating for VCN block
  */
@@ -542,7 +543,6 @@
  * vcn_v2_5_enable_clock_gating - enable VCN clock gating
  *
  * @adev: amdgpu_device pointer
- * @sw: enable SW clock gating
  *
  * Enable clock gating for VCN block
  */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdgpu/vi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -329,8 +329,15 @@
 	u32 reference_clock = adev->clock.spll.reference_freq;
 	u32 tmp;
 
-	if (adev->flags & AMD_IS_APU)
-		return reference_clock;
+	if (adev->flags & AMD_IS_APU) {
+		switch (adev->asic_type) {
+		case CHIP_STONEY:
+			/* vbios says 48Mhz, but the actual freq is 100Mhz */
+			return 10000;
+		default:
+			return reference_clock;
+		}
+	}
 
 	tmp = RREG32_SMC(ixCG_CLKPIN_CNTL_2);
 	if (REG_GET_FIELD(tmp, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK))
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
@@ -905,7 +905,7 @@
 	0x7a5d0000, 0x807c817c,
 	0x807aff7a, 0x00000080,
 	0xbf0a717c, 0xbf85fff8,
-	0xbf820141, 0xbef4037e,
+	0xbf820142, 0xbef4037e,
 	0x8775ff7f, 0x0000ffff,
 	0x8875ff75, 0x00040000,
 	0xbef60380, 0xbef703ff,
@@ -967,7 +967,7 @@
 	0x725d0000, 0xe0304080,
 	0x725d0100, 0xe0304100,
 	0x725d0200, 0xe0304180,
-	0x725d0300, 0xbf820031,
+	0x725d0300, 0xbf820032,
 	0xbef603ff, 0x01000000,
 	0xbef20378, 0x8078ff78,
 	0x00000400, 0xbefc0384,
@@ -992,83 +992,84 @@
 	0x725d0000, 0xe0304100,
 	0x725d0100, 0xe0304200,
 	0x725d0200, 0xe0304300,
-	0x725d0300, 0xb9782a05,
-	0x80788178, 0x907c9973,
-	0x877c817c, 0xbf06817c,
-	0xbf850002, 0x8f788978,
-	0xbf820001, 0x8f788a78,
-	0xb9721e06, 0x8f728a72,
-	0x80787278, 0x8078ff78,
-	0x00000200, 0x80f8ff78,
-	0x00000050, 0xbef603ff,
-	0x01000000, 0xbefc03ff,
-	0x0000006c, 0x80f89078,
-	0xf429003a, 0xf0000000,
-	0xbf8cc07f, 0x80fc847c,
-	0xbf800000, 0xbe803100,
-	0xbe823102, 0x80f8a078,
-	0xf42d003a, 0xf0000000,
-	0xbf8cc07f, 0x80fc887c,
-	0xbf800000, 0xbe803100,
-	0xbe823102, 0xbe843104,
-	0xbe863106, 0x80f8c078,
-	0xf431003a, 0xf0000000,
-	0xbf8cc07f, 0x80fc907c,
-	0xbf800000, 0xbe803100,
-	0xbe823102, 0xbe843104,
-	0xbe863106, 0xbe883108,
-	0xbe8a310a, 0xbe8c310c,
-	0xbe8e310e, 0xbf06807c,
-	0xbf84fff0, 0xb9782a05,
-	0x80788178, 0x907c9973,
-	0x877c817c, 0xbf06817c,
-	0xbf850002, 0x8f788978,
-	0xbf820001, 0x8f788a78,
-	0xb9721e06, 0x8f728a72,
-	0x80787278, 0x8078ff78,
-	0x00000200, 0xbef603ff,
-	0x01000000, 0xf4211bfa,
+	0x725d0300, 0xbf8c3f70,
+	0xb9782a05, 0x80788178,
+	0x907c9973, 0x877c817c,
+	0xbf06817c, 0xbf850002,
+	0x8f788978, 0xbf820001,
+	0x8f788a78, 0xb9721e06,
+	0x8f728a72, 0x80787278,
+	0x8078ff78, 0x00000200,
+	0x80f8ff78, 0x00000050,
+	0xbef603ff, 0x01000000,
+	0xbefc03ff, 0x0000006c,
+	0x80f89078, 0xf429003a,
+	0xf0000000, 0xbf8cc07f,
+	0x80fc847c, 0xbf800000,
+	0xbe803100, 0xbe823102,
+	0x80f8a078, 0xf42d003a,
+	0xf0000000, 0xbf8cc07f,
+	0x80fc887c, 0xbf800000,
+	0xbe803100, 0xbe823102,
+	0xbe843104, 0xbe863106,
+	0x80f8c078, 0xf431003a,
+	0xf0000000, 0xbf8cc07f,
+	0x80fc907c, 0xbf800000,
+	0xbe803100, 0xbe823102,
+	0xbe843104, 0xbe863106,
+	0xbe883108, 0xbe8a310a,
+	0xbe8c310c, 0xbe8e310e,
+	0xbf06807c, 0xbf84fff0,
+	0xb9782a05, 0x80788178,
+	0x907c9973, 0x877c817c,
+	0xbf06817c, 0xbf850002,
+	0x8f788978, 0xbf820001,
+	0x8f788a78, 0xb9721e06,
+	0x8f728a72, 0x80787278,
+	0x8078ff78, 0x00000200,
+	0xbef603ff, 0x01000000,
+	0xf4211bfa, 0xf0000000,
+	0x80788478, 0xf4211b3a,
 	0xf0000000, 0x80788478,
-	0xf4211b3a, 0xf0000000,
-	0x80788478, 0xf4211b7a,
+	0xf4211b7a, 0xf0000000,
+	0x80788478, 0xf4211eba,
 	0xf0000000, 0x80788478,
-	0xf4211eba, 0xf0000000,
-	0x80788478, 0xf4211efa,
+	0xf4211efa, 0xf0000000,
+	0x80788478, 0xf4211c3a,
 	0xf0000000, 0x80788478,
-	0xf4211c3a, 0xf0000000,
-	0x80788478, 0xf4211c7a,
+	0xf4211c7a, 0xf0000000,
+	0x80788478, 0xf4211e7a,
 	0xf0000000, 0x80788478,
-	0xf4211e7a, 0xf0000000,
-	0x80788478, 0xf4211cfa,
+	0xf4211cfa, 0xf0000000,
+	0x80788478, 0xf4211bba,
 	0xf0000000, 0x80788478,
+	0xbf8cc07f, 0xb9eef814,
 	0xf4211bba, 0xf0000000,
 	0x80788478, 0xbf8cc07f,
-	0xb9eef814, 0xf4211bba,
-	0xf0000000, 0x80788478,
-	0xbf8cc07f, 0xb9eef815,
-	0xbef2036d, 0x876dff72,
-	0x0000ffff, 0xbefc036f,
-	0xbefe037a, 0xbeff037b,
-	0x876f71ff, 0x000003ff,
-	0xb9ef4803, 0xb9f9f816,
-	0x876f71ff, 0xfffff800,
-	0x906f8b6f, 0xb9efa2c3,
-	0xb9f3f801, 0x876fff72,
-	0xfc000000, 0x906f9a6f,
-	0x8f6f906f, 0xbef30380,
+	0xb9eef815, 0xbef2036d,
+	0x876dff72, 0x0000ffff,
+	0xbefc036f, 0xbefe037a,
+	0xbeff037b, 0x876f71ff,
+	0x000003ff, 0xb9ef4803,
+	0xb9f9f816, 0x876f71ff,
+	0xfffff800, 0x906f8b6f,
+	0xb9efa2c3, 0xb9f3f801,
+	0x876fff72, 0xfc000000,
+	0x906f9a6f, 0x8f6f906f,
+	0xbef30380, 0x88736f73,
+	0x876fff72, 0x02000000,
+	0x906f996f, 0x8f6f8f6f,
 	0x88736f73, 0x876fff72,
-	0x02000000, 0x906f996f,
-	0x8f6f8f6f, 0x88736f73,
-	0x876fff72, 0x01000000,
-	0x906f986f, 0x8f6f996f,
-	0x88736f73, 0x876fff70,
-	0x00800000, 0x906f976f,
-	0xb9f3f807, 0x87fe7e7e,
-	0x87ea6a6a, 0xb9f0f802,
-	0xbf8a0000, 0xbe80226c,
-	0xbf810000, 0xbf9f0000,
+	0x01000000, 0x906f986f,
+	0x8f6f996f, 0x88736f73,
+	0x876fff70, 0x00800000,
+	0x906f976f, 0xb9f3f807,
+	0x87fe7e7e, 0x87ea6a6a,
+	0xb9f0f802, 0xbf8a0000,
+	0xbe80226c, 0xbf810000,
 	0xbf9f0000, 0xbf9f0000,
 	0xbf9f0000, 0xbf9f0000,
+	0xbf9f0000, 0x00000000,
 };
 static const uint32_t cwsr_trap_arcturus_hex[] = {
 	0xbf820001, 0xbf8202c4,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm
@@ -758,6 +758,7 @@
 	buffer_load_dword	v1, v0, s_restore_buf_rsrc0, s_restore_mem_offset_save slc:1 glc:1 offset:256
 	buffer_load_dword	v2, v0, s_restore_buf_rsrc0, s_restore_mem_offset_save slc:1 glc:1 offset:256*2
 	buffer_load_dword	v3, v0, s_restore_buf_rsrc0, s_restore_mem_offset_save slc:1 glc:1 offset:256*3
+	s_waitcnt	vmcnt(0)
 
 	/* restore SGPRs */
 	//will be 2+8+16*6
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1664,6 +1664,7 @@
 	}
 
 	mutex_unlock(&p->mutex);
+	dma_buf_put(dmabuf);
 
 	args->handle = MAKE_HANDLE(args->gpu_id, idr_handle);
 
@@ -1673,6 +1674,7 @@
 	amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
 err_unlock:
 	mutex_unlock(&p->mutex);
+	dma_buf_put(dmabuf);
 	return r;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -407,6 +407,9 @@
 			return -ENODEV;
 		/* same everything but the other direction */
 		props2 = kmemdup(props, sizeof(*props2), GFP_KERNEL);
+		if (!props2)
+			return -ENOMEM;
+
 		props2->node_from = id_to;
 		props2->node_to = id_from;
 		props2->kobj = NULL;
@@ -758,7 +761,7 @@
 	/* Fetch the CRAT table from ACPI */
 	status = acpi_get_table(CRAT_SIGNATURE, 0, &crat_table);
 	if (status == AE_NOT_FOUND) {
-		pr_warn("CRAT table not found\n");
+		pr_info("CRAT table not found\n");
 		return -ENODATA;
 	} else if (ACPI_FAILURE(status)) {
 		const char *err = acpi_format_exception(status);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c
@@ -33,6 +33,11 @@
 
 	return single_open(file, show, NULL);
 }
+static int kfd_debugfs_hang_hws_read(struct seq_file *m, void *data)
+{
+	seq_printf(m, "echo gpu_id > hang_hws\n");
+	return 0;
+}
 
 static ssize_t kfd_debugfs_hang_hws_write(struct file *file,
 	const char __user *user_buf, size_t size, loff_t *ppos)
@@ -93,8 +98,8 @@
 			    kfd_debugfs_hqds_by_device, &kfd_debugfs_fops);
 	debugfs_create_file("rls", S_IFREG | 0444, debugfs_root,
 			    kfd_debugfs_rls_by_device, &kfd_debugfs_fops);
-	debugfs_create_file("hang_hws", S_IFREG | 0644, debugfs_root,
-			    NULL, &kfd_debugfs_hang_hws_fops);
+	debugfs_create_file("hang_hws", S_IFREG | 0200, debugfs_root,
+			    kfd_debugfs_hang_hws_read, &kfd_debugfs_hang_hws_fops);
 }
 
 void kfd_debugfs_fini(void)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -609,15 +609,10 @@
 			- kfd->vm_info.first_vmid_kfd + 1;
 
 	/* Verify module parameters regarding mapped process number*/
-	if ((hws_max_conc_proc < 0)
-			|| (hws_max_conc_proc > kfd->vm_info.vmid_num_kfd)) {
-		dev_err(kfd_device,
-			"hws_max_conc_proc %d must be between 0 and %d, use %d instead\n",
-			hws_max_conc_proc, kfd->vm_info.vmid_num_kfd,
-			kfd->vm_info.vmid_num_kfd);
+	if (hws_max_conc_proc >= 0)
+		kfd->max_proc_per_quantum = min((u32)hws_max_conc_proc, kfd->vm_info.vmid_num_kfd);
+	else
 		kfd->max_proc_per_quantum = kfd->vm_info.vmid_num_kfd;
-	} else
-		kfd->max_proc_per_quantum = hws_max_conc_proc;
 
 	/* Allocate global GWS that is shared by all KFD processes */
 	if (hws_gws_support && amdgpu_amdkfd_alloc_gws(kfd->kgd,
@@ -1112,9 +1107,9 @@
 	return 0;
 
 kfd_gtt_no_free_chunk:
-	pr_debug("Allocation failed with mem_obj = %p\n", mem_obj);
+	pr_debug("Allocation failed with mem_obj = %p\n", *mem_obj);
 	mutex_unlock(&kfd->gtt_sa_lock);
-	kfree(mem_obj);
+	kfree(*mem_obj);
 	return -ENOMEM;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -1011,6 +1011,9 @@
 
 static int initialize_cpsch(struct device_queue_manager *dqm)
 {
+	uint64_t num_sdma_queues;
+	uint64_t num_xgmi_sdma_queues;
+
 	pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm));
 
 	mutex_init(&dqm->lock_hidden);
@@ -1019,8 +1022,18 @@
 	dqm->sdma_queue_count = 0;
 	dqm->xgmi_sdma_queue_count = 0;
 	dqm->active_runlist = false;
-	dqm->sdma_bitmap = ~0ULL >> (64 - get_num_sdma_queues(dqm));
-	dqm->xgmi_sdma_bitmap = ~0ULL >> (64 - get_num_xgmi_sdma_queues(dqm));
+
+	num_sdma_queues = get_num_sdma_queues(dqm);
+	if (num_sdma_queues >= BITS_PER_TYPE(dqm->sdma_bitmap))
+		dqm->sdma_bitmap = ULLONG_MAX;
+	else
+		dqm->sdma_bitmap = (BIT_ULL(num_sdma_queues) - 1);
+
+	num_xgmi_sdma_queues = get_num_xgmi_sdma_queues(dqm);
+	if (num_xgmi_sdma_queues >= BITS_PER_TYPE(dqm->xgmi_sdma_bitmap))
+		dqm->xgmi_sdma_bitmap = ULLONG_MAX;
+	else
+		dqm->xgmi_sdma_bitmap = (BIT_ULL(num_xgmi_sdma_queues) - 1);
 
 	INIT_WORK(&dqm->hw_exception_work, kfd_process_hw_exception);
 
@@ -1075,6 +1088,8 @@
 	unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0);
 	dqm_unlock(dqm);
 
+	pm_release_ib(&dqm->packets);
+
 	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
 	pm_uninit(&dqm->packets);
 
@@ -1181,16 +1196,18 @@
 
 	list_add(&q->list, &qpd->queues_list);
 	qpd->queue_count++;
+
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+		dqm->sdma_queue_count++;
+	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
+		dqm->xgmi_sdma_queue_count++;
+
 	if (q->properties.is_active) {
 		dqm->queue_count++;
 		retval = execute_queues_cpsch(dqm,
 				KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0);
 	}
 
-	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
-		dqm->sdma_queue_count++;
-	else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
-		dqm->xgmi_sdma_queue_count++;
 	/*
 	 * Unconditionally increment this counter, regardless of the queue's
 	 * type or whether the queue is active.
@@ -1567,7 +1584,7 @@
 		struct qcm_process_device *qpd)
 {
 	int retval;
-	struct queue *q, *next;
+	struct queue *q;
 	struct kernel_queue *kq, *kq_next;
 	struct mqd_manager *mqd_mgr;
 	struct device_process_node *cur, *next_dpn;
@@ -1622,24 +1639,26 @@
 		qpd->reset_wavefronts = false;
 	}
 
-	dqm_unlock(dqm);
-
-	/* Outside the DQM lock because under the DQM lock we can't do
-	 * reclaim or take other locks that others hold while reclaiming.
-	 */
-	if (found)
-		kfd_dec_compute_active(dqm->dev);
-
 	/* Lastly, free mqd resources.
 	 * Do free_mqd() after dqm_unlock to avoid circular locking.
 	 */
-	list_for_each_entry_safe(q, next, &qpd->queues_list, list) {
+	while (!list_empty(&qpd->queues_list)) {
+		q = list_first_entry(&qpd->queues_list, struct queue, list);
 		mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
 				q->properties.type)];
 		list_del(&q->list);
 		qpd->queue_count--;
+		dqm_unlock(dqm);
 		mqd_mgr->free_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj);
+		dqm_lock(dqm);
 	}
+	dqm_unlock(dqm);
+
+	/* Outside the DQM lock because under the DQM lock we can't do
+	 * reclaim or take other locks that others hold while reclaiming.
+	 */
+	if (found)
+		kfd_dec_compute_active(dqm->dev);
 
 	return retval;
 }
@@ -1676,7 +1695,8 @@
 	struct kfd_dev *dev = dqm->dev;
 	struct kfd_mem_obj *mem_obj = &dqm->hiq_sdma_mqd;
 	uint32_t size = dqm->mqd_mgrs[KFD_MQD_TYPE_SDMA]->mqd_size *
-		dev->device_info->num_sdma_engines *
+		(dev->device_info->num_sdma_engines +
+		dev->device_info->num_xgmi_sdma_engines) *
 		dev->device_info->num_sdma_queues_per_engine +
 		dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v10.c
@@ -58,8 +58,9 @@
 	/* check if sh_mem_config register already configured */
 	if (qpd->sh_mem_config == 0) {
 		qpd->sh_mem_config =
-				SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
-					SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
+			(SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+				SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) |
+			(3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT);
 #if 0
 		/* TODO:
 		 *    This shouldn't be an issue with Navi10.  Verify.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -529,14 +529,13 @@
 	struct kfd_event_waiter *event_waiters;
 	uint32_t i;
 
-	event_waiters = kmalloc_array(num_events,
-					sizeof(struct kfd_event_waiter),
-					GFP_KERNEL);
+	event_waiters = kcalloc(num_events, sizeof(struct kfd_event_waiter),
+				GFP_KERNEL);
+	if (!event_waiters)
+		return NULL;
 
-	for (i = 0; (event_waiters) && (i < num_events) ; i++) {
+	for (i = 0; i < num_events; i++)
 		init_wait(&event_waiters[i].wait);
-		event_waiters[i].activated = false;
-	}
 
 	return event_waiters;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
@@ -62,6 +62,11 @@
 	}
 
 	kfd->ih_wq = alloc_workqueue("KFD IH", WQ_HIGHPRI, 1);
+	if (unlikely(!kfd->ih_wq)) {
+		kfifo_free(&kfd->ih_fifo);
+		dev_err(kfd_chardev(), "Failed to allocate KFD IH workqueue\n");
+		return -ENOMEM;
+	}
 	spin_lock_init(&kfd->interrupt_lock);
 
 	INIT_WORK(&kfd->interrupt_work, interrupt_wq);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
@@ -20,6 +20,10 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/kconfig.h>
+
+#if IS_REACHABLE(CONFIG_AMD_IOMMU_V2)
+
 #include <linux/printk.h>
 #include <linux/device.h>
 #include <linux/slab.h>
@@ -358,3 +362,5 @@
 
 	return 0;
 }
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_iommu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_iommu.h
@@ -23,7 +23,9 @@
 #ifndef __KFD_IOMMU_H__
 #define __KFD_IOMMU_H__
 
-#if defined(CONFIG_AMD_IOMMU_V2_MODULE) || defined(CONFIG_AMD_IOMMU_V2)
+#include <linux/kconfig.h>
+
+#if IS_REACHABLE(CONFIG_AMD_IOMMU_V2)
 
 #define KFD_SUPPORT_IOMMU_V2
 
@@ -46,6 +48,9 @@
 }
 static inline int kfd_iommu_device_init(struct kfd_dev *kfd)
 {
+#if IS_MODULE(CONFIG_AMD_IOMMU_V2)
+	WARN_ONCE(1, "iommu_v2 module is not usable by built-in KFD");
+#endif
 	return 0;
 }
 
@@ -73,6 +78,6 @@
 	return 0;
 }
 
-#endif /* defined(CONFIG_AMD_IOMMU_V2) */
+#endif /* IS_REACHABLE(CONFIG_AMD_IOMMU_V2) */
 
 #endif /* __KFD_IOMMU_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_module.c
@@ -82,7 +82,7 @@
 	kfd_chardev_exit();
 }
 
-int kgd2kfd_init()
+int kgd2kfd_init(void)
 {
 	return kfd_init();
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
@@ -98,36 +98,78 @@
 		uint32_t *se_mask)
 {
 	struct kfd_cu_info cu_info;
-	uint32_t cu_per_se[KFD_MAX_NUM_SE] = {0};
-	int i, se, sh, cu = 0;
-
+	uint32_t cu_per_sh[KFD_MAX_NUM_SE][KFD_MAX_NUM_SH_PER_SE] = {0};
+	int i, se, sh, cu;
 	amdgpu_amdkfd_get_cu_info(mm->dev->kgd, &cu_info);
 
 	if (cu_mask_count > cu_info.cu_active_number)
 		cu_mask_count = cu_info.cu_active_number;
 
+	/* Exceeding these bounds corrupts the stack and indicates a coding error.
+	 * Returning with no CU's enabled will hang the queue, which should be
+	 * attention grabbing.
+	 */
+	if (cu_info.num_shader_engines > KFD_MAX_NUM_SE) {
+		pr_err("Exceeded KFD_MAX_NUM_SE, chip reports %d\n", cu_info.num_shader_engines);
+		return;
+	}
+	if (cu_info.num_shader_arrays_per_engine > KFD_MAX_NUM_SH_PER_SE) {
+		pr_err("Exceeded KFD_MAX_NUM_SH, chip reports %d\n",
+			cu_info.num_shader_arrays_per_engine * cu_info.num_shader_engines);
+		return;
+	}
+	/* Count active CUs per SH.
+	 *
+	 * Some CUs in an SH may be disabled.	HW expects disabled CUs to be
+	 * represented in the high bits of each SH's enable mask (the upper and lower
+	 * 16 bits of se_mask) and will take care of the actual distribution of
+	 * disabled CUs within each SH automatically.
+	 * Each half of se_mask must be filled only on bits 0-cu_per_sh[se][sh]-1.
+	 *
+	 * See note on Arcturus cu_bitmap layout in gfx_v9_0_get_cu_info.
+	 */
 	for (se = 0; se < cu_info.num_shader_engines; se++)
 		for (sh = 0; sh < cu_info.num_shader_arrays_per_engine; sh++)
-			cu_per_se[se] += hweight32(cu_info.cu_bitmap[se % 4][sh + (se / 4)]);
+			cu_per_sh[se][sh] = hweight32(cu_info.cu_bitmap[se % 4][sh + (se / 4)]);
 
-	/* Symmetrically map cu_mask to all SEs:
-	 * cu_mask[0] bit0 -> se_mask[0] bit0;
-	 * cu_mask[0] bit1 -> se_mask[1] bit0;
-	 * ... (if # SE is 4)
-	 * cu_mask[0] bit4 -> se_mask[0] bit1;
+	/* Symmetrically map cu_mask to all SEs & SHs:
+	 * se_mask programs up to 2 SH in the upper and lower 16 bits.
+	 *
+	 * Examples
+	 * Assuming 1 SH/SE, 4 SEs:
+	 * cu_mask[0] bit0 -> se_mask[0] bit0
+	 * cu_mask[0] bit1 -> se_mask[1] bit0
+	 * ...
+	 * cu_mask[0] bit4 -> se_mask[0] bit1
+	 * ...
+	 *
+	 * Assuming 2 SH/SE, 4 SEs
+	 * cu_mask[0] bit0 -> se_mask[0] bit0 (SE0,SH0,CU0)
+	 * cu_mask[0] bit1 -> se_mask[1] bit0 (SE1,SH0,CU0)
+	 * ...
+	 * cu_mask[0] bit4 -> se_mask[0] bit16 (SE0,SH1,CU0)
+	 * cu_mask[0] bit5 -> se_mask[1] bit16 (SE1,SH1,CU0)
+	 * ...
+	 * cu_mask[0] bit8 -> se_mask[0] bit1 (SE0,SH0,CU1)
 	 * ...
+	 *
+	 * First ensure all CUs are disabled, then enable user specified CUs.
 	 */
-	se = 0;
-	for (i = 0; i < cu_mask_count; i++) {
-		if (cu_mask[i / 32] & (1 << (i % 32)))
-			se_mask[se] |= 1 << cu;
+	for (i = 0; i < cu_info.num_shader_engines; i++)
+		se_mask[i] = 0;
 
-		do {
-			se++;
-			if (se == cu_info.num_shader_engines) {
-				se = 0;
-				cu++;
+	i = 0;
+	for (cu = 0; cu < 16; cu++) {
+		for (sh = 0; sh < cu_info.num_shader_arrays_per_engine; sh++) {
+			for (se = 0; se < cu_info.num_shader_engines; se++) {
+				if (cu_per_sh[se][sh] > cu) {
+					if (cu_mask[i / 32] & (1 << (i % 32)))
+						se_mask[se] |= 1 << (cu + sh * 16);
+					i++;
+					if (i == cu_mask_count)
+						return;
+				}
 			}
-		} while (cu >= cu_per_se[se] && cu < 32);
+		}
 	}
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
@@ -27,6 +27,7 @@
 #include "kfd_priv.h"
 
 #define KFD_MAX_NUM_SE 8
+#define KFD_MAX_NUM_SH_PER_SE 2
 
 /**
  * struct mqd_manager
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -101,18 +101,19 @@
 			&(mqd_mem_obj->gtt_mem),
 			&(mqd_mem_obj->gpu_addr),
 			(void *)&(mqd_mem_obj->cpu_ptr), true);
+
+		if (retval) {
+			kfree(mqd_mem_obj);
+			return NULL;
+		}
 	} else {
 		retval = kfd_gtt_sa_allocate(kfd, sizeof(struct v9_mqd),
 				&mqd_mem_obj);
-	}
-
-	if (retval) {
-		kfree(mqd_mem_obj);
-		return NULL;
+		if (retval)
+			return NULL;
 	}
 
 	return mqd_mem_obj;
-
 }
 
 static void init_mqd(struct mqd_manager *mm, void **mqd,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -312,6 +312,7 @@
 					   (int)process->lead_thread->pid);
 		if (ret) {
 			pr_warn("Creating procfs pid directory failed");
+			kobject_put(process->kobj);
 			goto out;
 		}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -612,8 +612,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)
@@ -660,8 +662,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;
@@ -679,8 +683,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;
@@ -698,8 +704,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;
@@ -779,8 +787,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-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -664,6 +664,7 @@
 
 	init_data.asic_id.pci_revision_id = adev->rev_id;
 	init_data.asic_id.hw_internal_rev = adev->external_rev_id;
+	init_data.asic_id.chip_id = adev->pdev->device;
 
 	init_data.asic_id.vram_width = adev->gmc.vram_width;
 	/* TODO: initialize init_data.asic_id.vram_type here!!!! */
@@ -928,8 +929,13 @@
 	struct dmcu_iram_parameters params;
 	unsigned int linear_lut[16];
 	int i;
-	struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
-	bool ret = false;
+	struct dmcu *dmcu = NULL;
+	bool ret;
+
+	if (!adev->dm.fw_dmcu)
+		return detect_mst_link_for_all_connectors(adev->ddev);
+
+	dmcu = adev->dm.dc->res_pool->dmcu;
 
 	for (i = 0; i < 16; i++)
 		linear_lut[i] = 0xFFFF * i / 15;
@@ -940,13 +946,15 @@
 	params.backlight_lut_array_size = 16;
 	params.backlight_lut_array = linear_lut;
 
-	/* todo will enable for navi10 */
-	if (adev->asic_type <= CHIP_RAVEN) {
-		ret = dmcu_load_iram(dmcu, params);
+	/* Min backlight level after ABM reduction,  Don't allow below 1%
+	 * 0xFFFF x 0.01 = 0x28F
+	 */
+	params.min_abm_backlight = 0x28F;
 
-		if (!ret)
-			return -EINVAL;
-	}
+	ret = dmcu_load_iram(dmcu, params);
+
+	if (!ret)
+		return -EINVAL;
 
 	return detect_mst_link_for_all_connectors(adev->ddev);
 }
@@ -1086,8 +1094,8 @@
 	link->type = dc_connection_none;
 	prev_sink = link->local_sink;
 
-	if (prev_sink != NULL)
-		dc_sink_retain(prev_sink);
+	if (prev_sink)
+		dc_sink_release(prev_sink);
 
 	switch (link->connector_signal) {
 	case SIGNAL_TYPE_HDMI_TYPE_A: {
@@ -1198,11 +1206,14 @@
 	list_for_each_entry(connector, &ddev->mode_config.connector_list, head) {
 		aconnector = to_amdgpu_dm_connector(connector);
 
+		if (!aconnector->dc_link)
+			continue;
+
 		/*
 		 * this is the case when traversing through already created
 		 * MST connectors, should be skipped
 		 */
-		if (aconnector->mst_port)
+		if (aconnector->dc_link->type == dc_connection_mst_branch)
 			continue;
 
 		mutex_lock(&aconnector->hpd_lock);
@@ -1410,24 +1421,29 @@
 		 * TODO: check if we still need the S3 mode update workaround.
 		 * If yes, put it here.
 		 */
-		if (aconnector->dc_sink)
+		if (aconnector->dc_sink) {
 			amdgpu_dm_update_freesync_caps(connector, NULL);
+			dc_sink_release(aconnector->dc_sink);
+		}
 
 		aconnector->dc_sink = sink;
 		dc_sink_retain(aconnector->dc_sink);
 		if (sink->dc_edid.length == 0) {
 			aconnector->edid = NULL;
-			drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
+			if (aconnector->dc_link->aux_mode) {
+				drm_dp_cec_unset_edid(
+					&aconnector->dm_dp_aux.aux);
+			}
 		} else {
 			aconnector->edid =
-				(struct edid *) sink->dc_edid.raw_edid;
-
+				(struct edid *)sink->dc_edid.raw_edid;
 
-			drm_connector_update_edid_property(connector,
-					aconnector->edid);
-			drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
-					    aconnector->edid);
+			if (aconnector->dc_link->aux_mode)
+				drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
+						    aconnector->edid);
 		}
+
+		drm_connector_update_edid_property(connector, aconnector->edid);
 		amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
 
 	} else {
@@ -2030,12 +2046,18 @@
 				    &dm_atomic_state_funcs);
 
 	r = amdgpu_display_modeset_create_props(adev);
-	if (r)
+	if (r) {
+		dc_release_state(state->context);
+		kfree(state);
 		return r;
+	}
 
 	r = amdgpu_dm_audio_init(adev);
-	if (r)
+	if (r) {
+		dc_release_state(state->context);
+		kfree(state);
 		return r;
+	}
 
 	return 0;
 }
@@ -2051,6 +2073,8 @@
 #if defined(CONFIG_ACPI)
 	struct amdgpu_dm_backlight_caps caps;
 
+	memset(&caps, 0, sizeof(caps));
+
 	if (dm->backlight_caps.caps_valid)
 		return;
 
@@ -2611,6 +2635,23 @@
 	scaling_info->src_rect.x = state->src_x >> 16;
 	scaling_info->src_rect.y = state->src_y >> 16;
 
+	/*
+	 * For reasons we don't (yet) fully understand a non-zero
+	 * src_y coordinate into an NV12 buffer can cause a
+	 * system hang. To avoid hangs (and maybe be overly cautious)
+	 * let's reject both non-zero src_x and src_y.
+	 *
+	 * We currently know of only one use-case to reproduce a
+	 * scenario with non-zero src_x and src_y for NV12, which
+	 * is to gesture the YouTube Android app into full screen
+	 * on ChromeOS.
+	 */
+	if (state->fb &&
+	    state->fb->format->format == DRM_FORMAT_NV12 &&
+	    (scaling_info->src_rect.x != 0 ||
+	     scaling_info->src_rect.y != 0))
+		return -EINVAL;
+
 	scaling_info->src_rect.width = state->src_w >> 16;
 	if (scaling_info->src_rect.width == 0)
 		return -EINVAL;
@@ -2693,7 +2734,8 @@
 			  const union dc_tiling_info *tiling_info,
 			  const uint64_t info,
 			  struct dc_plane_dcc_param *dcc,
-			  struct dc_plane_address *address)
+			  struct dc_plane_address *address,
+			  bool force_disable_dcc)
 {
 	struct dc *dc = adev->dm.dc;
 	struct dc_dcc_surface_param input;
@@ -2705,6 +2747,9 @@
 	memset(&input, 0, sizeof(input));
 	memset(&output, 0, sizeof(output));
 
+	if (force_disable_dcc)
+		return 0;
+
 	if (!offset)
 		return 0;
 
@@ -2754,7 +2799,8 @@
 			     union dc_tiling_info *tiling_info,
 			     struct plane_size *plane_size,
 			     struct dc_plane_dcc_param *dcc,
-			     struct dc_plane_address *address)
+			     struct dc_plane_address *address,
+			     bool force_disable_dcc)
 {
 	const struct drm_framebuffer *fb = &afb->base;
 	int ret;
@@ -2864,7 +2910,8 @@
 
 		ret = fill_plane_dcc_attributes(adev, afb, format, rotation,
 						plane_size, tiling_info,
-						tiling_flags, dcc, address);
+						tiling_flags, dcc, address,
+						force_disable_dcc);
 		if (ret)
 			return ret;
 	}
@@ -2956,7 +3003,8 @@
 			    const struct drm_plane_state *plane_state,
 			    const uint64_t tiling_flags,
 			    struct dc_plane_info *plane_info,
-			    struct dc_plane_address *address)
+			    struct dc_plane_address *address,
+			    bool force_disable_dcc)
 {
 	const struct drm_framebuffer *fb = plane_state->fb;
 	const struct amdgpu_framebuffer *afb =
@@ -3035,7 +3083,8 @@
 					   plane_info->rotation, tiling_flags,
 					   &plane_info->tiling_info,
 					   &plane_info->plane_size,
-					   &plane_info->dcc, address);
+					   &plane_info->dcc, address,
+					   force_disable_dcc);
 	if (ret)
 		return ret;
 
@@ -3058,6 +3107,7 @@
 	struct dc_plane_info plane_info;
 	uint64_t tiling_flags;
 	int ret;
+	bool force_disable_dcc = false;
 
 	ret = fill_dc_scaling_info(plane_state, &scaling_info);
 	if (ret)
@@ -3072,9 +3122,11 @@
 	if (ret)
 		return ret;
 
+	force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
 	ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags,
 					  &plane_info,
-					  &dc_plane_state->address);
+					  &dc_plane_state->address,
+					  force_disable_dcc);
 	if (ret)
 		return ret;
 
@@ -3261,27 +3313,21 @@
 	return color_space;
 }
 
-static void reduce_mode_colour_depth(struct dc_crtc_timing *timing_out)
-{
-	if (timing_out->display_color_depth <= COLOR_DEPTH_888)
-		return;
-
-	timing_out->display_color_depth--;
-}
-
-static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
-						const struct drm_display_info *info)
+static bool adjust_colour_depth_from_display_info(
+	struct dc_crtc_timing *timing_out,
+	const struct drm_display_info *info)
 {
+	enum dc_color_depth depth = timing_out->display_color_depth;
 	int normalized_clk;
-	if (timing_out->display_color_depth <= COLOR_DEPTH_888)
-		return;
 	do {
 		normalized_clk = timing_out->pix_clk_100hz / 10;
 		/* YCbCr 4:2:0 requires additional adjustment of 1/2 */
 		if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)
 			normalized_clk /= 2;
 		/* Adjusting pix clock following on HDMI spec based on colour depth */
-		switch (timing_out->display_color_depth) {
+		switch (depth) {
+		case COLOR_DEPTH_888:
+			break;
 		case COLOR_DEPTH_101010:
 			normalized_clk = (normalized_clk * 30) / 24;
 			break;
@@ -3292,14 +3338,15 @@
 			normalized_clk = (normalized_clk * 48) / 24;
 			break;
 		default:
-			return;
+			/* The above depths are the only ones valid for HDMI. */
+			return false;
 		}
-		if (normalized_clk <= info->max_tmds_clock)
-			return;
-		reduce_mode_colour_depth(timing_out);
-
-	} while (timing_out->display_color_depth > COLOR_DEPTH_888);
-
+		if (normalized_clk <= info->max_tmds_clock) {
+			timing_out->display_color_depth = depth;
+			return true;
+		}
+	} while (--depth > COLOR_DEPTH_666);
+	return false;
 }
 
 static void fill_stream_properties_from_drm_display_mode(
@@ -3365,8 +3412,14 @@
 
 	stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
 	stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
-	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
-		adjust_colour_depth_from_display_info(timing_out, info);
+	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+		if (!adjust_colour_depth_from_display_info(timing_out, info) &&
+		    drm_mode_is_420_also(info, mode_in) &&
+		    timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) {
+			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+			adjust_colour_depth_from_display_info(timing_out, info);
+		}
+	}
 }
 
 static void fill_audio_info(struct audio_info *audio_info,
@@ -3923,6 +3976,13 @@
 	struct amdgpu_device *adev = connector->dev->dev_private;
 	struct amdgpu_display_manager *dm = &adev->dm;
 
+	/*
+	 * Call only if mst_mgr was iniitalized before since it's not done
+	 * for all connector types.
+	 */
+	if (aconnector->mst_mgr.dev)
+		drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
+
 #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
 	defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
 
@@ -4266,19 +4326,6 @@
 {
 }
 
-static bool does_crtc_have_active_cursor(struct drm_crtc_state *new_crtc_state)
-{
-	struct drm_device *dev = new_crtc_state->crtc->dev;
-	struct drm_plane *plane;
-
-	drm_for_each_plane_mask(plane, dev, new_crtc_state->plane_mask) {
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
-			return true;
-	}
-
-	return false;
-}
-
 static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
 {
 	struct drm_atomic_state *state = new_crtc_state->state;
@@ -4358,19 +4405,20 @@
 		return ret;
 	}
 
-	/* In some use cases, like reset, no stream is attached */
-	if (!dm_crtc_state->stream)
-		return 0;
-
 	/*
-	 * We want at least one hardware plane enabled to use
-	 * the stream with a cursor enabled.
+	 * We require the primary plane to be enabled whenever the CRTC is, otherwise
+	 * drm_mode_cursor_universal may end up trying to enable the cursor plane while all other
+	 * planes are disabled, which is not supported by the hardware. And there is legacy
+	 * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
 	 */
-	if (state->enable && state->active &&
-	    does_crtc_have_active_cursor(state) &&
-	    dm_crtc_state->active_planes == 0)
+	if (state->enable &&
+	    !(state->plane_mask & drm_plane_mask(crtc->primary)))
 		return -EINVAL;
 
+	/* In some use cases, like reset, no stream is attached */
+	if (!dm_crtc_state->stream)
+		return 0;
+
 	if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
 		return 0;
 
@@ -4475,6 +4523,7 @@
 	uint64_t tiling_flags;
 	uint32_t domain;
 	int r;
+	bool force_disable_dcc = false;
 
 	dm_plane_state_old = to_dm_plane_state(plane->state);
 	dm_plane_state_new = to_dm_plane_state(new_state);
@@ -4533,11 +4582,13 @@
 			dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
 		struct dc_plane_state *plane_state = dm_plane_state_new->dc_state;
 
+		force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
 		fill_plane_buffer_attributes(
 			adev, afb, plane_state->format, plane_state->rotation,
 			tiling_flags, &plane_state->tiling_info,
 			&plane_state->plane_size, &plane_state->dcc,
-			&plane_state->address);
+			&plane_state->address,
+			force_disable_dcc);
 	}
 
 	return 0;
@@ -4947,6 +4998,9 @@
 		mode = amdgpu_dm_create_common_mode(encoder,
 				common_modes[i].name, common_modes[i].w,
 				common_modes[i].h);
+		if (!mode)
+			continue;
+
 		drm_mode_probed_add(connector, mode);
 		amdgpu_dm_connector->num_modes++;
 	}
@@ -5341,10 +5395,6 @@
 	int x, y;
 	int xorigin = 0, yorigin = 0;
 
-	position->enable = false;
-	position->x = 0;
-	position->y = 0;
-
 	if (!crtc || !plane->state->fb)
 		return 0;
 
@@ -5396,7 +5446,7 @@
 	struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	uint64_t address = afb ? afb->address : 0;
-	struct dc_cursor_position position;
+	struct dc_cursor_position position = {0};
 	struct dc_cursor_attributes attributes;
 	int ret;
 
@@ -5709,6 +5759,8 @@
 			continue;
 
 		dc_plane = dm_new_plane_state->dc_state;
+		if (!dc_plane)
+			continue;
 
 		bundle->surface_updates[planes_count].surface = dc_plane;
 		if (new_pcrtc_state->color_mgmt_changed) {
@@ -5761,7 +5813,12 @@
 		fill_dc_plane_info_and_addr(
 			dm->adev, new_plane_state, tiling_flags,
 			&bundle->plane_infos[planes_count],
-			&bundle->flip_addrs[planes_count].address);
+			&bundle->flip_addrs[planes_count].address,
+			false);
+
+		DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n",
+				 new_plane_state->plane->index,
+				 bundle->plane_infos[planes_count].dcc.enable);
 
 		bundle->surface_updates[planes_count].plane_info =
 			&bundle->plane_infos[planes_count];
@@ -6429,14 +6486,14 @@
 
 	ret = PTR_ERR_OR_ZERO(conn_state);
 	if (ret)
-		goto err;
+		goto out;
 
 	/* Attach crtc to drm_atomic_state*/
 	crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
 
 	ret = PTR_ERR_OR_ZERO(crtc_state);
 	if (ret)
-		goto err;
+		goto out;
 
 	/* force a restore */
 	crtc_state->mode_changed = true;
@@ -6446,17 +6503,15 @@
 
 	ret = PTR_ERR_OR_ZERO(plane_state);
 	if (ret)
-		goto err;
-
+		goto out;
 
 	/* Call commit internally with the state we just constructed */
 	ret = drm_atomic_commit(state);
-	if (!ret)
-		return 0;
 
-err:
-	DRM_ERROR("Restoring old state failed with %i\n", ret);
+out:
 	drm_atomic_state_put(state);
+	if (ret)
+		DRM_ERROR("Restoring old state failed with %i\n", ret);
 
 	return ret;
 }
@@ -6785,7 +6840,8 @@
 	BUG_ON(dm_new_crtc_state->stream == NULL);
 
 	/* Scaling or underscan settings */
-	if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state))
+	if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) ||
+				drm_atomic_crtc_needs_modeset(new_crtc_state))
 		update_stream_scaling_settings(
 			&new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
 
@@ -6896,6 +6952,7 @@
 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
 	struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
 	struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
+	struct amdgpu_crtc *new_acrtc;
 	bool needs_reset;
 	int ret = 0;
 
@@ -6905,9 +6962,23 @@
 	dm_new_plane_state = to_dm_plane_state(new_plane_state);
 	dm_old_plane_state = to_dm_plane_state(old_plane_state);
 
-	/*TODO Implement atomic check for cursor plane */
-	if (plane->type == DRM_PLANE_TYPE_CURSOR)
+	/*TODO Implement better atomic check for cursor plane */
+	if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+		if (!enable || !new_plane_crtc ||
+			drm_atomic_plane_disabling(plane->state, new_plane_state))
+			return 0;
+
+		new_acrtc = to_amdgpu_crtc(new_plane_crtc);
+
+		if ((new_plane_state->crtc_w > new_acrtc->max_cursor_width) ||
+			(new_plane_state->crtc_h > new_acrtc->max_cursor_height)) {
+			DRM_DEBUG_ATOMIC("Bad cursor size %d x %d\n",
+							 new_plane_state->crtc_w, new_plane_state->crtc_h);
+			return -EINVAL;
+		}
+
 		return 0;
+	}
 
 	needs_reset = should_reset_plane(state, plane, old_plane_state,
 					 new_plane_state);
@@ -6940,12 +7011,12 @@
 				dm_old_plane_state->dc_state,
 				dm_state->context)) {
 
-			ret = EINVAL;
-			return ret;
+			return -EINVAL;
 		}
 
+		if (dm_old_plane_state->dc_state)
+			dc_plane_state_release(dm_old_plane_state->dc_state);
 
-		dc_plane_state_release(dm_old_plane_state->dc_state);
 		dm_new_plane_state->dc_state = NULL;
 
 		*lock_and_validation_needed = true;
@@ -7132,7 +7203,8 @@
 				ret = fill_dc_plane_info_and_addr(
 					dm->adev, new_plane_state, tiling_flags,
 					&plane_info,
-					&flip_addr.address);
+					&flip_addr.address,
+					false);
 				if (ret)
 					goto cleanup;
 
@@ -7180,6 +7252,80 @@
 	*out_type = update_type;
 	return ret;
 }
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc)
+{
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state, *old_conn_state;
+	struct amdgpu_dm_connector *aconnector = NULL;
+	int i;
+	for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) {
+		if (!conn_state->crtc)
+			conn_state = old_conn_state;
+
+		if (conn_state->crtc != crtc)
+			continue;
+
+		aconnector = to_amdgpu_dm_connector(connector);
+		if (!aconnector->port || !aconnector->mst_port)
+			aconnector = NULL;
+		else
+			break;
+	}
+
+	if (!aconnector)
+		return 0;
+
+	return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_port->mst_mgr);
+}
+#endif
+
+static int validate_overlay(struct drm_atomic_state *state)
+{
+	int i;
+	struct drm_plane *plane;
+	struct drm_plane_state *old_plane_state, *new_plane_state;
+	struct drm_plane_state *primary_state, *overlay_state = NULL;
+
+	/* Check if primary plane is contained inside overlay */
+	for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
+		if (plane->type == DRM_PLANE_TYPE_OVERLAY) {
+			if (drm_atomic_plane_disabling(plane->state, new_plane_state))
+				return 0;
+
+			overlay_state = new_plane_state;
+			continue;
+		}
+	}
+
+	/* check if we're making changes to the overlay plane */
+	if (!overlay_state)
+		return 0;
+
+	/* check if overlay plane is enabled */
+	if (!overlay_state->crtc)
+		return 0;
+
+	/* find the primary plane for the CRTC that the overlay is enabled on */
+	primary_state = drm_atomic_get_plane_state(state, overlay_state->crtc->primary);
+	if (IS_ERR(primary_state))
+		return PTR_ERR(primary_state);
+
+	/* check if primary plane is enabled */
+	if (!primary_state->crtc)
+		return 0;
+
+	/* Perform the bounds check to ensure the overlay plane covers the primary */
+	if (primary_state->crtc_x < overlay_state->crtc_x ||
+	    primary_state->crtc_y < overlay_state->crtc_y ||
+	    primary_state->crtc_x + primary_state->crtc_w > overlay_state->crtc_x + overlay_state->crtc_w ||
+	    primary_state->crtc_y + primary_state->crtc_h > overlay_state->crtc_y + overlay_state->crtc_h) {
+		DRM_DEBUG_ATOMIC("Overlay plane is enabled with hardware cursor but does not fully cover primary plane\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 /**
  * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
@@ -7233,12 +7379,50 @@
 	if (ret)
 		goto fail;
 
+	/* Check connector changes */
+	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
+		struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
+		struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
+
+		/* Skip connectors that are disabled or part of modeset already. */
+		if (!old_con_state->crtc && !new_con_state->crtc)
+			continue;
+
+		if (!new_con_state->crtc)
+			continue;
+
+		new_crtc_state = drm_atomic_get_crtc_state(state, new_con_state->crtc);
+		if (IS_ERR(new_crtc_state)) {
+			ret = PTR_ERR(new_crtc_state);
+			goto fail;
+		}
+
+		if (dm_old_con_state->abm_level != dm_new_con_state->abm_level ||
+		    dm_old_con_state->scaling != dm_new_con_state->scaling)
+			new_crtc_state->connectors_changed = true;
+	}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+	if (dc_resource_is_dsc_encoding_supported(dc)) {
+		for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+			if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
+				ret = add_affected_mst_dsc_crtcs(state, crtc);
+				if (ret)
+					goto fail;
+			}
+		}
+	}
+#endif
 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
 		    !new_crtc_state->color_mgmt_changed &&
 		    old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled)
 			continue;
 
+		ret = amdgpu_dm_verify_lut_sizes(new_crtc_state);
+		if (ret)
+			goto fail;
+
 		if (!new_crtc_state->enable)
 			continue;
 
@@ -7320,6 +7504,10 @@
 			goto fail;
 	}
 
+	ret = validate_overlay(state);
+	if (ret)
+		goto fail;
+
 	/* Add new/modified planes */
 	for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
 		ret = dm_update_plane_state(dc, state, plane,
@@ -7416,20 +7604,38 @@
 		 * the same resource. If we have a new DC context as part of
 		 * the DM atomic state from validation we need to free it and
 		 * retain the existing one instead.
+		 *
+		 * Furthermore, since the DM atomic state only contains the DC
+		 * context and can safely be annulled, we can free the state
+		 * and clear the associated private object now to free
+		 * some memory and avoid a possible use-after-free later.
 		 */
-		struct dm_atomic_state *new_dm_state, *old_dm_state;
 
-		new_dm_state = dm_atomic_get_new_state(state);
-		old_dm_state = dm_atomic_get_old_state(state);
+		for (i = 0; i < state->num_private_objs; i++) {
+			struct drm_private_obj *obj = state->private_objs[i].ptr;
 
-		if (new_dm_state && old_dm_state) {
-			if (new_dm_state->context)
-				dc_release_state(new_dm_state->context);
+			if (obj->funcs == adev->dm.atomic_obj.funcs) {
+				int j = state->num_private_objs-1;
 
-			new_dm_state->context = old_dm_state->context;
+				dm_atomic_destroy_state(obj,
+						state->private_objs[i].state);
 
-			if (old_dm_state->context)
-				dc_retain_state(old_dm_state->context);
+				/* If i is not at the end of the array then the
+				 * last element needs to be moved to where i was
+				 * before the array can safely be truncated.
+				 */
+				if (i != j)
+					state->private_objs[i] =
+						state->private_objs[j];
+
+				state->private_objs[j].ptr = NULL;
+				state->private_objs[j].state = NULL;
+				state->private_objs[j].old_state = NULL;
+				state->private_objs[j].new_state = NULL;
+
+				state->num_private_objs = j;
+				break;
+			}
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -387,6 +387,7 @@
 #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
 
 void amdgpu_dm_init_color_mod(void);
+int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state);
 int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc);
 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
 				      struct dc_plane_state *dc_plane_state);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -210,6 +210,8 @@
 	res = mod_color_calculate_regamma_params(func, gamma, true, has_rom,
 						 NULL);
 
+	dc_gamma_release(&gamma);
+
 	return res ? 0 : -ENOMEM;
 }
 
@@ -276,6 +278,37 @@
 }
 
 /**
+ * Verifies that the Degamma and Gamma LUTs attached to the |crtc_state| are of
+ * the expected size.
+ * Returns 0 on success.
+ */
+int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)
+{
+	const struct drm_color_lut *lut = NULL;
+	uint32_t size = 0;
+
+	lut = __extract_blob_lut(crtc_state->degamma_lut, &size);
+	if (lut && size != MAX_COLOR_LUT_ENTRIES) {
+		DRM_DEBUG_DRIVER(
+			"Invalid Degamma LUT size. Should be %u but got %u.\n",
+			MAX_COLOR_LUT_ENTRIES, size);
+		return -EINVAL;
+	}
+
+	lut = __extract_blob_lut(crtc_state->gamma_lut, &size);
+	if (lut && size != MAX_COLOR_LUT_ENTRIES &&
+	    size != MAX_COLOR_LEGACY_LUT_ENTRIES) {
+		DRM_DEBUG_DRIVER(
+			"Invalid Gamma LUT size. Should be %u (or %u for legacy) but got %u.\n",
+			MAX_COLOR_LUT_ENTRIES, MAX_COLOR_LEGACY_LUT_ENTRIES,
+			size);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
  * amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream.
  * @crtc: amdgpu_dm crtc state
  *
@@ -309,14 +342,12 @@
 	bool is_legacy;
 	int r;
 
-	degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, &degamma_size);
-	if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES)
-		return -EINVAL;
+	r = amdgpu_dm_verify_lut_sizes(&crtc->base);
+	if (r)
+		return r;
 
+	degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, &degamma_size);
 	regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, &regamma_size);
-	if (regamma_lut && regamma_size != MAX_COLOR_LUT_ENTRIES &&
-	    regamma_size != MAX_COLOR_LEGACY_LUT_ENTRIES)
-		return -EINVAL;
 
 	has_degamma =
 		degamma_lut && !__is_lut_linear(degamma_lut, degamma_size);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -113,7 +113,7 @@
 	mutex_lock(&adev->dm.dc_lock);
 
 	/* Enable CRTC CRC generation if necessary. */
-	if (dm_is_crc_source_crtc(source)) {
+	if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
 		if (!dc_stream_configure_crc(stream_state->ctx->dc,
 					     stream_state, enable, enable)) {
 			ret = -EINVAL;
@@ -221,6 +221,14 @@
 			ret = -EINVAL;
 			goto cleanup;
 		}
+
+		if ((aconn->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
+				(aconn->base.connector_type != DRM_MODE_CONNECTOR_eDP)) {
+			DRM_DEBUG_DRIVER("No DP connector available for CRC source\n");
+			ret = -EINVAL;
+			goto cleanup;
+		}
+
 	}
 
 	if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -95,29 +95,29 @@
 
 	rd_buf_ptr = rd_buf;
 
-	str_len = strlen("Current:  %d  %d  %d  ");
-	snprintf(rd_buf_ptr, str_len, "Current:  %d  %d  %d  ",
+	str_len = strlen("Current:  %d  0x%x  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Current:  %d  0x%x  %d  ",
 			link->cur_link_settings.lane_count,
 			link->cur_link_settings.link_rate,
 			link->cur_link_settings.link_spread);
 	rd_buf_ptr += str_len;
 
-	str_len = strlen("Verified:  %d  %d  %d  ");
-	snprintf(rd_buf_ptr, str_len, "Verified:  %d  %d  %d  ",
+	str_len = strlen("Verified:  %d  0x%x  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Verified:  %d  0x%x  %d  ",
 			link->verified_link_cap.lane_count,
 			link->verified_link_cap.link_rate,
 			link->verified_link_cap.link_spread);
 	rd_buf_ptr += str_len;
 
-	str_len = strlen("Reported:  %d  %d  %d  ");
-	snprintf(rd_buf_ptr, str_len, "Reported:  %d  %d  %d  ",
+	str_len = strlen("Reported:  %d  0x%x  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Reported:  %d  0x%x  %d  ",
 			link->reported_link_cap.lane_count,
 			link->reported_link_cap.link_rate,
 			link->reported_link_cap.link_spread);
 	rd_buf_ptr += str_len;
 
-	str_len = strlen("Preferred:  %d  %d  %d  ");
-	snprintf(rd_buf_ptr, str_len, "Preferred:  %d  %d  %d\n",
+	str_len = strlen("Preferred:  %d  0x%x  %d  ");
+	snprintf(rd_buf_ptr, str_len, "Preferred:  %d  0x%x  %d\n",
 			link->preferred_link_setting.lane_count,
 			link->preferred_link_setting.link_rate,
 			link->preferred_link_setting.link_spread);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -247,7 +247,8 @@
 		drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
 	}
 
-	ret = drm_dp_update_payload_part1(mst_mgr);
+	/* It's OK for this to fail */
+	drm_dp_update_payload_part1(mst_mgr);
 
 	/* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
 	 * AUX message. The sequence is slot 1-63 allocated sequence for each
@@ -256,9 +257,6 @@
 
 	get_payload_table(aconnector, proposed_table);
 
-	if (ret)
-		return false;
-
 	return true;
 }
 
@@ -316,7 +314,6 @@
 	struct amdgpu_dm_connector *aconnector;
 	struct drm_dp_mst_topology_mgr *mst_mgr;
 	struct drm_dp_mst_port *mst_port;
-	int ret;
 
 	aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
@@ -330,10 +327,8 @@
 	if (!mst_mgr->mst_state)
 		return false;
 
-	ret = drm_dp_update_payload_part2(mst_mgr);
-
-	if (ret)
-		return false;
+	/* It's OK for this to fail */
+	drm_dp_update_payload_part2(mst_mgr);
 
 	if (!enable)
 		drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -101,7 +101,7 @@
 	result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
 				      &operation_result);
 
-	if (payload.write)
+	if (payload.write && result >= 0)
 		result = msg->size;
 
 	if (result < 0)
@@ -379,6 +379,7 @@
 					   aconnector->dc_sink);
 		dc_sink_release(aconnector->dc_sink);
 		aconnector->dc_sink = NULL;
+		aconnector->dc_link->cur_link_settings.lane_count = 0;
 	}
 
 	drm_connector_unregister(connector);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
@@ -342,7 +342,8 @@
 	if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_clock_by_type) {
 		if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle,
 			dc_to_pp_clock_type(clk_type), &pp_clks)) {
-		/* Error in pplib. Provide default values. */
+			/* Error in pplib. Provide default values. */
+			get_default_clock_levels(clk_type, dc_clks);
 			return true;
 		}
 	} else if (adev->smu.funcs && adev->smu.funcs->get_clock_by_type) {
@@ -529,6 +530,8 @@
 			&pp_clk_info);
 	else if (adev->smu.funcs)
 		ret = smu_get_current_clocks(&adev->smu, &pp_clk_info);
+	else
+		return false;
 	if (ret)
 		return false;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -2543,7 +2543,6 @@
 
 	/* Sort voltage table from low to high*/
 	if (result == BP_RESULT_OK) {
-		struct clock_voltage_caps temp = {0, 0};
 		uint32_t i;
 		uint32_t j;
 
@@ -2553,10 +2552,8 @@
 						info->disp_clk_voltage[j].max_supported_clk <
 						info->disp_clk_voltage[j-1].max_supported_clk) {
 					/* swap j and j - 1*/
-					temp = info->disp_clk_voltage[j-1];
-					info->disp_clk_voltage[j-1] =
-							info->disp_clk_voltage[j];
-					info->disp_clk_voltage[j] = temp;
+					swap(info->disp_clk_voltage[j - 1],
+					     info->disp_clk_voltage[j]);
 				}
 			}
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -1613,8 +1613,6 @@
 
 	struct atom_common_table_header *header;
 	struct atom_data_revision revision;
-
-	struct clock_voltage_caps temp = {0, 0};
 	uint32_t i;
 	uint32_t j;
 
@@ -1644,10 +1642,8 @@
 				info->disp_clk_voltage[j-1].max_supported_clk
 				) {
 				/* swap j and j - 1*/
-				temp = info->disp_clk_voltage[j-1];
-				info->disp_clk_voltage[j-1] =
-					info->disp_clk_voltage[j];
-				info->disp_clk_voltage[j] = temp;
+				swap(info->disp_clk_voltage[j - 1],
+				     info->disp_clk_voltage[j]);
 			}
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/bios/command_table.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/bios/command_table.c
@@ -245,6 +245,23 @@
 					cntl->enable_dp_audio);
 	params.ucLaneNum = (uint8_t)(cntl->lanes_number);
 
+	switch (cntl->color_depth) {
+	case COLOR_DEPTH_888:
+		params.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_101010:
+		params.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_121212:
+		params.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_161616:
+		params.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+		break;
+	default:
+		break;
+	}
+
 	if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
 		result = BP_RESULT_OK;
 
@@ -274,6 +291,23 @@
 					cntl->enable_dp_audio));
 	params.ucLaneNum = (uint8_t)(cntl->lanes_number);
 
+	switch (cntl->color_depth) {
+	case COLOR_DEPTH_888:
+		params.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_101010:
+		params.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_121212:
+		params.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_161616:
+		params.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+		break;
+	default:
+		break;
+	}
+
 	if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
 		result = BP_RESULT_OK;
 
@@ -1057,6 +1091,19 @@
 		 * driver choose program it itself, i.e. here we program it
 		 * to 888 by default.
 		 */
+		if (bp_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
+			switch (bp_params->color_depth) {
+			case TRANSMITTER_COLOR_DEPTH_30:
+				/* yes this is correct, the atom define is wrong */
+				clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
+				break;
+			case TRANSMITTER_COLOR_DEPTH_36:
+				/* yes this is correct, the atom define is wrong */
+				clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
+				break;
+			default:
+				break;
+			}
 
 		if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
 			result = BP_RESULT_OK;
@@ -1135,6 +1182,20 @@
 		 * driver choose program it itself, i.e. here we pass required
 		 * target rate that includes deep color.
 		 */
+		if (bp_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
+			switch (bp_params->color_depth) {
+			case TRANSMITTER_COLOR_DEPTH_30:
+				clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
+				break;
+			case TRANSMITTER_COLOR_DEPTH_36:
+				clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
+				break;
+			case TRANSMITTER_COLOR_DEPTH_48:
+				clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
+				break;
+			default:
+				break;
+			}
 
 		if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
 			result = BP_RESULT_OK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c
@@ -26,12 +26,12 @@
 #include "bw_fixed.h"
 
 
-#define MIN_I64 \
-	(int64_t)(-(1LL << 63))
-
 #define MAX_I64 \
 	(int64_t)((1ULL << 63) - 1)
 
+#define MIN_I64 \
+	(-MAX_I64 - 1)
+
 #define FRACTIONAL_PART_MASK \
 	((1ULL << BW_FIXED_BITS_PER_FRACTIONAL_PART) - 1)
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
@@ -1438,6 +1438,7 @@
 	struct dc_context *ctx = dc->ctx;
 	struct dm_pp_clock_levels_with_voltage fclks = {0}, dcfclks = {0};
 	bool res;
+	unsigned vmin0p65_idx, vmid0p72_idx, vnom0p8_idx, vmax0p9_idx;
 
 	/* TODO: This is not the proper way to obtain fabric_and_dram_bandwidth, should be min(fclk, memclk) */
 	res = dm_pp_get_clock_levels_by_type_with_voltage(
@@ -1449,17 +1450,28 @@
 		res = verify_clock_values(&fclks);
 
 	if (res) {
-		ASSERT(fclks.num_levels >= 3);
-		dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 32 * (fclks.data[0].clocks_in_khz / 1000.0) / 1000.0;
-		dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = dc->dcn_soc->number_of_channels *
-				(fclks.data[fclks.num_levels - (fclks.num_levels > 2 ? 3 : 2)].clocks_in_khz / 1000.0)
-				* ddr4_dram_factor_single_Channel / 1000.0;
-		dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = dc->dcn_soc->number_of_channels *
-				(fclks.data[fclks.num_levels - 2].clocks_in_khz / 1000.0)
-				* ddr4_dram_factor_single_Channel / 1000.0;
-		dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = dc->dcn_soc->number_of_channels *
-				(fclks.data[fclks.num_levels - 1].clocks_in_khz / 1000.0)
-				* ddr4_dram_factor_single_Channel / 1000.0;
+		ASSERT(fclks.num_levels);
+
+		vmin0p65_idx = 0;
+		vmid0p72_idx = fclks.num_levels -
+			(fclks.num_levels > 2 ? 3 : (fclks.num_levels > 1 ? 2 : 1));
+		vnom0p8_idx = fclks.num_levels - (fclks.num_levels > 1 ? 2 : 1);
+		vmax0p9_idx = fclks.num_levels - 1;
+
+		dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 =
+			32 * (fclks.data[vmin0p65_idx].clocks_in_khz / 1000.0) / 1000.0;
+		dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 =
+			dc->dcn_soc->number_of_channels *
+			(fclks.data[vmid0p72_idx].clocks_in_khz / 1000.0)
+			* ddr4_dram_factor_single_Channel / 1000.0;
+		dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 =
+			dc->dcn_soc->number_of_channels *
+			(fclks.data[vnom0p8_idx].clocks_in_khz / 1000.0)
+			* ddr4_dram_factor_single_Channel / 1000.0;
+		dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 =
+			dc->dcn_soc->number_of_channels *
+			(fclks.data[vmax0p9_idx].clocks_in_khz / 1000.0)
+			* ddr4_dram_factor_single_Channel / 1000.0;
 	} else
 		BREAK_TO_DEBUGGER();
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
@@ -91,6 +91,12 @@
 ###############################################################################
 CLK_MGR_DCN21 = rn_clk_mgr.o rn_clk_mgr_vbios_smu.o
 
+# prevent build errors regarding soft-float vs hard-float FP ABI tags
+# this code is currently unused on ppc64, as it applies to Renoir APUs only
+ifdef CONFIG_PPC64
+CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := $(call cc-option,-mno-gnu-attribute)
+endif
+
 AMD_DAL_CLK_MGR_DCN21 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn21/,$(CLK_MGR_DCN21))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN21)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
@@ -85,12 +85,77 @@
 	return disp_clk_threshold;
 }
 
-static void ramp_up_dispclk_with_dpp(struct clk_mgr_internal *clk_mgr, struct dc *dc, struct dc_clocks *new_clocks)
+static void ramp_up_dispclk_with_dpp(
+		struct clk_mgr_internal *clk_mgr,
+		struct dc *dc,
+		struct dc_clocks *new_clocks,
+		bool safe_to_lower)
 {
 	int i;
 	int dispclk_to_dpp_threshold = rv1_determine_dppclk_threshold(clk_mgr, new_clocks);
 	bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
 
+	/* this function is to change dispclk, dppclk and dprefclk according to
+	 * bandwidth requirement. Its call stack is rv1_update_clocks -->
+	 * update_clocks --> dcn10_prepare_bandwidth / dcn10_optimize_bandwidth
+	 * --> prepare_bandwidth / optimize_bandwidth. before change dcn hw,
+	 * prepare_bandwidth will be called first to allow enough clock,
+	 * watermark for change, after end of dcn hw change, optimize_bandwidth
+	 * is executed to lower clock to save power for new dcn hw settings.
+	 *
+	 * below is sequence of commit_planes_for_stream:
+	 *
+	 * step 1: prepare_bandwidth - raise clock to have enough bandwidth
+	 * step 2: lock_doublebuffer_enable
+	 * step 3: pipe_control_lock(true) - make dchubp register change will
+	 * not take effect right way
+	 * step 4: apply_ctx_for_surface - program dchubp
+	 * step 5: pipe_control_lock(false) - dchubp register change take effect
+	 * step 6: optimize_bandwidth --> dc_post_update_surfaces_to_stream
+	 * for full_date, optimize clock to save power
+	 *
+	 * at end of step 1, dcn clocks (dprefclk, dispclk, dppclk) may be
+	 * changed for new dchubp configuration. but real dcn hub dchubps are
+	 * still running with old configuration until end of step 5. this need
+	 * clocks settings at step 1 should not less than that before step 1.
+	 * this is checked by two conditions: 1. if (should_set_clock(safe_to_lower
+	 * , new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) ||
+	 * new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz)
+	 * 2. request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz
+	 *
+	 * the second condition is based on new dchubp configuration. dppclk
+	 * for new dchubp may be different from dppclk before step 1.
+	 * for example, before step 1, dchubps are as below:
+	 * pipe 0: recout=(0,40,1920,980) viewport=(0,0,1920,979)
+	 * pipe 1: recout=(0,0,1920,1080) viewport=(0,0,1920,1080)
+	 * for dppclk for pipe0 need dppclk = dispclk
+	 *
+	 * new dchubp pipe split configuration:
+	 * pipe 0: recout=(0,0,960,1080) viewport=(0,0,960,1080)
+	 * pipe 1: recout=(960,0,960,1080) viewport=(960,0,960,1080)
+	 * dppclk only needs dppclk = dispclk /2.
+	 *
+	 * dispclk, dppclk are not lock by otg master lock. they take effect
+	 * after step 1. during this transition, dispclk are the same, but
+	 * dppclk is changed to half of previous clock for old dchubp
+	 * configuration between step 1 and step 6. This may cause p-state
+	 * warning intermittently.
+	 *
+	 * for new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz, we
+	 * need make sure dppclk are not changed to less between step 1 and 6.
+	 * for new_clocks->dispclk_khz > clk_mgr_base->clks.dispclk_khz,
+	 * new display clock is raised, but we do not know ratio of
+	 * new_clocks->dispclk_khz and clk_mgr_base->clks.dispclk_khz,
+	 * new_clocks->dispclk_khz /2 does not guarantee equal or higher than
+	 * old dppclk. we could ignore power saving different between
+	 * dppclk = displck and dppclk = dispclk / 2 between step 1 and step 6.
+	 * as long as safe_to_lower = false, set dpclk = dispclk to simplify
+	 * condition check.
+	 * todo: review this change for other asic.
+	 **/
+	if (!safe_to_lower)
+		request_dpp_div = false;
+
 	/* set disp clk to dpp clk threshold */
 
 	clk_mgr->funcs->set_dispclk(clk_mgr, dispclk_to_dpp_threshold);
@@ -206,7 +271,7 @@
 	/* program dispclk on = as a w/a for sleep resume clock ramping issues */
 	if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)
 			|| new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz) {
-		ramp_up_dispclk_with_dpp(clk_mgr, dc, new_clocks);
+		ramp_up_dispclk_with_dpp(clk_mgr, dc, new_clocks, safe_to_lower);
 		clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
 		send_request_to_lower = true;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
@@ -320,6 +320,8 @@
 		struct dc_state *context,
 		bool safe_to_lower)
 {
+	struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr);
+
 	struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
 	/* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */
 	int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000;
@@ -357,14 +359,18 @@
 		clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
 	}
 
-	/* Both fclk and dppclk ref are run on the same scemi clock so we
-	 * need to keep the same value for both
+	/* Both fclk and ref_dppclk run on the same scemi clock.
+	 * So take the higher value since the DPP DTO is typically programmed
+	 * such that max dppclk is 1:1 with ref_dppclk.
 	 */
 	if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz)
 		clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz;
 	if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz)
 		clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz;
 
+	// Both fclk and ref_dppclk run on the same scemi clock.
+	clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz;
+
 	dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
@@ -91,8 +91,23 @@
 		rn_vbios_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
 	}
 
-	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
-		if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
+	// workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
+	if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
+		if (new_clocks->dppclk_khz < 100000)
+			new_clocks->dppclk_khz = 100000;
+	}
+
+	/*
+	 * Temporally ignore thew 0 cases for disp and dpp clks.
+	 * We may have a new feature that requires 0 clks in the future.
+	 */
+	if (new_clocks->dppclk_khz == 0 || new_clocks->dispclk_khz == 0) {
+		new_clocks->dppclk_khz = clk_mgr_base->clks.dppclk_khz;
+		new_clocks->dispclk_khz = clk_mgr_base->clks.dispclk_khz;
+	}
+
+	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
+		if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
 			dpp_clock_lowered = true;
 		clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
 		update_dppclk = true;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
@@ -33,7 +33,7 @@
 #include "mp/mp_12_0_0_sh_mask.h"
 
 #define REG(reg_name) \
-	(MP1_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
+	(MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
 
 #define FN(reg_name, field) \
 	FD(reg_name##__##field)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -283,6 +283,8 @@
 	int i = 0;
 	bool ret = false;
 
+	stream->adjust = *adjust;
+
 	for (i = 0; i < MAX_PIPES; i++) {
 		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 
@@ -905,15 +907,11 @@
 
 		/* set first pipe with plane as master */
 		for (j = 0; j < group_size; j++) {
-			struct pipe_ctx *temp;
-
 			if (pipe_set[j]->plane_state) {
 				if (j == 0)
 					break;
 
-				temp = pipe_set[0];
-				pipe_set[0] = pipe_set[j];
-				pipe_set[j] = temp;
+				swap(pipe_set[0], pipe_set[j]);
 				break;
 			}
 		}
@@ -1180,6 +1178,26 @@
 	return (result == DC_OK);
 }
 
+static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context)
+{
+	int i;
+	struct pipe_ctx *pipe;
+
+	for (i = 0; i < MAX_PIPES; i++) {
+		pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (!pipe->plane_state)
+			continue;
+
+		/* Must set to false to start with, due to OR in update function */
+		pipe->plane_state->status.is_flip_pending = false;
+		dc->hwss.update_pending_status(pipe);
+		if (pipe->plane_state->status.is_flip_pending)
+			return true;
+	}
+	return false;
+}
+
 bool dc_post_update_surfaces_to_stream(struct dc *dc)
 {
 	int i;
@@ -1190,6 +1208,9 @@
 
 	post_surface_trace(dc);
 
+	if (is_flip_pending_in_pipes(dc, context))
+		return true;
+
 	for (i = 0; i < dc->res_pool->pipe_count; i++)
 		if (context->res_ctx.pipe_ctx[i].stream == NULL ||
 		    context->res_ctx.pipe_ctx[i].plane_state == NULL) {
@@ -1940,7 +1961,8 @@
 					if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only)
 						pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
 
-					dc->hwss.optimize_bandwidth(dc, dc->current_state);
+					dc->optimized_required = true;
+
 				} else {
 					if (!dc->optimize_seamless_boot)
 						dc->hwss.prepare_bandwidth(dc, dc->current_state);
@@ -2028,6 +2050,10 @@
 						plane_state->triplebuffer_flips = true;
 				}
 			}
+			if (update_type == UPDATE_TYPE_FULL) {
+				/* force vsync flip when reconfiguring pipes to prevent underflow */
+				plane_state->flip_immediate = false;
+			}
 		}
 	}
 #endif
@@ -2152,7 +2178,7 @@
 	enum surface_update_type update_type;
 	struct dc_state *context;
 	struct dc_context *dc_ctx = dc->ctx;
-	int i;
+	int i, j;
 
 	stream_status = dc_stream_get_status(stream);
 	context = dc->current_state;
@@ -2190,10 +2216,29 @@
 
 		copy_surface_update_to_plane(surface, &srf_updates[i]);
 
+		if (update_type >= UPDATE_TYPE_MED) {
+			for (j = 0; j < dc->res_pool->pipe_count; j++) {
+				struct pipe_ctx *pipe_ctx =
+					&context->res_ctx.pipe_ctx[j];
+
+				if (pipe_ctx->plane_state != surface)
+					continue;
+
+				resource_build_scaling_params(pipe_ctx);
+			}
+		}
 	}
 
 	copy_stream_update_to_stream(dc, context, stream, stream_update);
 
+	if (update_type > UPDATE_TYPE_FAST) {
+		if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) {
+			DC_ERROR("Mode validation failed for stream update!\n");
+			dc_release_state(context);
+			return;
+		}
+	}
+
 	commit_planes_for_stream(
 				dc,
 				srf_updates,
@@ -2267,12 +2312,7 @@
 	enum dc_acpi_cm_power_state power_state)
 {
 	struct kref refcount;
-	struct display_mode_lib *dml = kzalloc(sizeof(struct display_mode_lib),
-						GFP_KERNEL);
-
-	ASSERT(dml);
-	if (!dml)
-		return;
+	struct display_mode_lib *dml;
 
 	switch (power_state) {
 	case DC_ACPI_CM_POWER_STATE_D0:
@@ -2294,6 +2334,12 @@
 		 * clean state, and dc hw programming optimizations will not
 		 * cause any trouble.
 		 */
+		dml = kzalloc(sizeof(struct display_mode_lib),
+				GFP_KERNEL);
+
+		ASSERT(dml);
+		if (!dml)
+			return;
 
 		/* Preserve refcount */
 		refcount = dc->current_state->refcount;
@@ -2307,10 +2353,10 @@
 		dc->current_state->refcount = refcount;
 		dc->current_state->bw_ctx.dml = *dml;
 
+		kfree(dml);
+
 		break;
 	}
-
-	kfree(dml);
 }
 
 void dc_resume(struct dc *dc)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -92,8 +92,8 @@
 		{ 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
 				0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
 	{ COLOR_SPACE_YCBCR2020_TYPE,
-		{ 0x1000, 0xF149, 0xFEB7, 0x0000, 0x0868, 0x15B2,
-				0x01E6, 0x0000, 0xFB88, 0xF478, 0x1000, 0x0000} },
+		{ 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
+				0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
 	{ COLOR_SPACE_YCBCR709_BLACK_TYPE,
 		{ 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000,
 				0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x1000} },
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -373,7 +373,7 @@
 
 	if (GPIO_RESULT_OK != dal_ddc_open(
 		ddc, GPIO_MODE_INPUT, GPIO_DDC_CONFIG_TYPE_MODE_I2C)) {
-		dal_gpio_destroy_ddc(&ddc);
+		dal_ddc_close(ddc);
 
 		return present;
 	}
@@ -809,8 +809,8 @@
 		}
 
 		case SIGNAL_TYPE_EDP: {
-			read_edp_current_link_settings_on_detect(link);
 			detect_edp_sink_caps(link);
+			read_edp_current_link_settings_on_detect(link);
 			sink_caps.transaction_type =
 				DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
 			sink_caps.signal = SIGNAL_TYPE_EDP;
@@ -936,6 +936,24 @@
 			    dc_is_dvi_signal(link->connector_signal)) {
 				if (prev_sink != NULL)
 					dc_sink_release(prev_sink);
+				link_disconnect_sink(link);
+
+				return false;
+			}
+			/*
+			 * Abort detection for DP connectors if we have
+			 * no EDID and connector is active converter
+			 * as there are no display downstream
+			 *
+			 */
+			if (dc_is_dp_sst_signal(link->connector_signal) &&
+				(link->dpcd_caps.dongle_type ==
+						DISPLAY_DONGLE_DP_VGA_CONVERTER ||
+				link->dpcd_caps.dongle_type ==
+						DISPLAY_DONGLE_DP_DVI_CONVERTER)) {
+				if (prev_sink)
+					dc_sink_release(prev_sink);
+				link_disconnect_sink(link);
 
 				return false;
 			}
@@ -948,8 +966,7 @@
 			same_edid = is_same_edid(&prev_sink->dc_edid, &sink->dc_edid);
 
 		if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
-			sink_caps.transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX &&
-			reason != DETECT_REASON_HPDRX) {
+			sink_caps.transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
 			/*
 			 * TODO debug why Dell 2413 doesn't like
 			 *  two link trainings
@@ -1304,6 +1321,11 @@
 		goto ddc_create_fail;
 	}
 
+	if (!link->ddc->ddc_pin) {
+		DC_ERROR("Failed to get I2C info for connector!\n");
+		goto ddc_create_fail;
+	}
+
 	link->ddc_hw_inst =
 		dal_ddc_get_line(
 			dal_ddc_service_get_ddc_pin(link->ddc));
@@ -1734,8 +1756,7 @@
 				slave_address, buffer[0], buffer[1], i2c_success?1:0);
 
 			if (!i2c_success)
-				/* Write failure */
-				ASSERT(i2c_success);
+				goto i2c_write_fail;
 
 			/* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
 			 * needs to be set to 1 on every 0xA-0xC write.
@@ -1753,8 +1774,7 @@
 						pipe_ctx->stream->link->ddc,
 						slave_address, &offset, 1, &value, 1);
 					if (!i2c_success)
-						/* Write failure */
-						ASSERT(i2c_success);
+						goto i2c_write_fail;
 				}
 
 				buffer[0] = offset;
@@ -1766,8 +1786,7 @@
 					offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 					slave_address, buffer[0], buffer[1], i2c_success?1:0);
 				if (!i2c_success)
-					/* Write failure */
-					ASSERT(i2c_success);
+					goto i2c_write_fail;
 			}
 		}
 	}
@@ -1787,8 +1806,7 @@
 					slave_address, buffer[0], buffer[1], i2c_success?1:0);
 
 				if (!i2c_success)
-					/* Write failure */
-					ASSERT(i2c_success);
+					goto i2c_write_fail;
 
 				/* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
 				 * needs to be set to 1 on every 0xA-0xC write.
@@ -1806,8 +1824,7 @@
 								pipe_ctx->stream->link->ddc,
 								slave_address, &offset, 1, &value, 1);
 						if (!i2c_success)
-							/* Write failure */
-							ASSERT(i2c_success);
+							goto i2c_write_fail;
 					}
 
 					buffer[0] = offset;
@@ -1819,8 +1836,7 @@
 						offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 						slave_address, buffer[0], buffer[1], i2c_success?1:0);
 					if (!i2c_success)
-						/* Write failure */
-						ASSERT(i2c_success);
+						goto i2c_write_fail;
 				}
 			}
 		}
@@ -1838,8 +1854,7 @@
 				offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 				slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 
 		/* Write offset 0x00 to 0x23 */
 		buffer[0] = 0x00;
@@ -1850,8 +1865,7 @@
 			offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 			slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 
 		/* Write offset 0xff to 0x00 */
 		buffer[0] = 0xff;
@@ -1862,10 +1876,14 @@
 			offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 			slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 
 	}
+
+	return;
+
+i2c_write_fail:
+	DC_LOG_DEBUG("Set retimer failed");
 }
 
 static void write_i2c_default_retimer_setting(
@@ -1890,8 +1908,7 @@
 		offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 	/* Write offset 0x0A to 0x17 */
 	buffer[0] = 0x0A;
@@ -1902,8 +1919,7 @@
 		offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 	/* Write offset 0x0B to 0xDA or 0xD8 */
 	buffer[0] = 0x0B;
@@ -1914,8 +1930,7 @@
 		offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 	/* Write offset 0x0A to 0x17 */
 	buffer[0] = 0x0A;
@@ -1926,8 +1941,7 @@
 		offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 	/* Write offset 0x0C to 0x1D or 0x91 */
 	buffer[0] = 0x0C;
@@ -1938,8 +1952,7 @@
 		offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 	/* Write offset 0x0A to 0x17 */
 	buffer[0] = 0x0A;
@@ -1950,8 +1963,7 @@
 		offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 		slave_address, buffer[0], buffer[1], i2c_success?1:0);
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		goto i2c_write_fail;
 
 
 	if (is_vga_mode) {
@@ -1966,8 +1978,7 @@
 			offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
 			slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 
 		/* Write offset 0x00 to 0x23 */
 		buffer[0] = 0x00;
@@ -1978,8 +1989,7 @@
 			offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
 			slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 
 		/* Write offset 0xff to 0x00 */
 		buffer[0] = 0xff;
@@ -1990,9 +2000,13 @@
 			offset = 0x%x, reg_val= 0x%x, i2c_success = %d end here\n",
 			slave_address, buffer[0], buffer[1], i2c_success?1:0);
 		if (!i2c_success)
-			/* Write failure */
-			ASSERT(i2c_success);
+			goto i2c_write_fail;
 	}
+
+	return;
+
+i2c_write_fail:
+	DC_LOG_DEBUG("Set default retimer failed");
 }
 
 static void write_i2c_redriver_setting(
@@ -2021,8 +2035,7 @@
 		slave_address, buffer[3], buffer[4], buffer[5], buffer[6], i2c_success?1:0);
 
 	if (!i2c_success)
-		/* Write failure */
-		ASSERT(i2c_success);
+		DC_LOG_DEBUG("Set redriver failed");
 }
 
 static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
@@ -2169,8 +2182,10 @@
 			dp_set_fec_ready(link, false);
 		}
 #endif
-	} else
-		link->link_enc->funcs->disable_output(link->link_enc, signal);
+	} else {
+		if (signal != SIGNAL_TYPE_VIRTUAL)
+			link->link_enc->funcs->disable_output(link->link_enc, signal);
+	}
 
 	if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
 		/* MST disable link only when no stream use the link */
@@ -2217,7 +2232,7 @@
 		break;
 	}
 
-	if (dongle_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
+	if (dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
 		dongle_caps->extendedCapValid == false)
 		return true;
 
@@ -2276,7 +2291,7 @@
 	/* A hack to avoid failing any modes for EDID override feature on
 	 * topology change such as lower quality cable for DP or different dongle
 	 */
-	if (link->remote_sinks[0])
+	if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL)
 		return DC_OK;
 
 	/* Passive Dongle */
@@ -2917,8 +2932,12 @@
 
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
 	if (timing->flags.DSC) {
-		kbps = (timing->pix_clk_100hz * timing->dsc_cfg.bits_per_pixel);
-		kbps = kbps / 160 + ((kbps % 160) ? 1 : 0);
+		struct fixed31_32 link_bw_kbps;
+
+		link_bw_kbps = dc_fixpt_from_int(timing->pix_clk_100hz);
+		link_bw_kbps = dc_fixpt_div_int(link_bw_kbps, 160);
+		link_bw_kbps = dc_fixpt_mul_int(link_bw_kbps, timing->dsc_cfg.bits_per_pixel);
+		kbps = dc_fixpt_ceil(link_bw_kbps);
 		return kbps;
 	}
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
@@ -126,22 +126,16 @@
 	struct vector payloads;
 };
 
-static struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count)
+static bool dal_ddc_i2c_payloads_create(
+		struct dc_context *ctx,
+		struct i2c_payloads *payloads,
+		uint32_t count)
 {
-	struct i2c_payloads *payloads;
-
-	payloads = kzalloc(sizeof(struct i2c_payloads), GFP_KERNEL);
-
-	if (!payloads)
-		return NULL;
-
 	if (dal_vector_construct(
 		&payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
-		return payloads;
-
-	kfree(payloads);
-	return NULL;
+		return true;
 
+	return false;
 }
 
 static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
@@ -154,14 +148,12 @@
 	return p->payloads.count;
 }
 
-static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p)
+static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads *p)
 {
-	if (!p || !*p)
+	if (!p)
 		return;
-	dal_vector_destruct(&(*p)->payloads);
-	kfree(*p);
-	*p = NULL;
 
+	dal_vector_destruct(&p->payloads);
 }
 
 #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -521,9 +513,13 @@
 
 	uint32_t payloads_num = write_payloads + read_payloads;
 
+
 	if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE)
 		return false;
 
+	if (!payloads_num)
+		return false;
+
 	/*TODO: len of payload data for i2c and aux is uint8!!!!,
 	 *  but we want to read 256 over i2c!!!!*/
 	if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
@@ -556,23 +552,25 @@
 
 		ret = dc_link_aux_transfer_with_retries(ddc, &read_payload);
 	} else {
-		struct i2c_payloads *payloads =
-			dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num);
+		struct i2c_command command = {0};
+		struct i2c_payloads payloads;
+
+		if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num))
+			return false;
 
-		struct i2c_command command = {
-			.payloads = dal_ddc_i2c_payloads_get(payloads),
-			.number_of_payloads = 0,
-			.engine = DDC_I2C_COMMAND_ENGINE,
-			.speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
+		command.payloads = dal_ddc_i2c_payloads_get(&payloads);
+		command.number_of_payloads = 0;
+		command.engine = DDC_I2C_COMMAND_ENGINE;
+		command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
 
 		dal_ddc_i2c_payloads_add(
-			payloads, address, write_size, write_buf, true);
+			&payloads, address, write_size, write_buf, true);
 
 		dal_ddc_i2c_payloads_add(
-			payloads, address, read_size, read_buf, false);
+			&payloads, address, read_size, read_buf, false);
 
 		command.number_of_payloads =
-			dal_ddc_i2c_payloads_get_count(payloads);
+			dal_ddc_i2c_payloads_get_count(&payloads);
 
 		ret = dm_helpers_submit_i2c(
 				ddc->ctx,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -1284,6 +1284,8 @@
 		link->type = dc_connection_single;
 		link->local_sink = link->remote_sinks[0];
 		link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
+		dc_sink_retain(link->local_sink);
+		dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
 	} else if (mst_enable == true &&
 			link->type == dc_connection_single &&
 			link->remote_sinks[0] != NULL) {
@@ -1914,6 +1916,9 @@
 			initial_link_setting;
 	uint32_t link_bw;
 
+	if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+		return false;
+
 	/* search for the minimum link setting that:
 	 * 1. is supported according to the link training result
 	 * 2. could support the b/w requested by the timing
@@ -2545,6 +2550,7 @@
 	uint8_t data, struct dc_link *link)
 {
 	union dp_downstream_port_present ds_port = { .byte = data };
+	memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
 
 	/* decode converter info*/
 	if (!ds_port.fields.PORT_PRESENT) {
@@ -2691,6 +2697,7 @@
 		 * keep receiver powered all the time.*/
 		case DP_BRANCH_DEVICE_ID_0010FA:
 		case DP_BRANCH_DEVICE_ID_0080E1:
+		case DP_BRANCH_DEVICE_ID_00E04C:
 			link->wa_flags.dp_keep_receiver_powered = true;
 			break;
 
@@ -2877,6 +2884,17 @@
 		sink_id.ieee_device_id,
 		sizeof(sink_id.ieee_device_id));
 
+	/* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */
+	{
+		uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 };
+
+		if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+		    !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,
+			    sizeof(str_mbp_2017))) {
+			link->reported_link_cap.link_rate = 0x0c;
+		}
+	}
+
 	core_link_read_dpcd(
 		link,
 		DP_SINK_HW_REVISION_START,
@@ -3365,7 +3383,7 @@
 
 		if (edp_config_set.bits.PANEL_MODE_EDP
 			!= panel_mode_edp) {
-			enum ddc_result result = DDC_RESULT_UNKNOWN;
+			enum dc_status result = DC_ERROR_UNEXPECTED;
 
 			edp_config_set.bits.PANEL_MODE_EDP =
 			panel_mode_edp;
@@ -3375,7 +3393,7 @@
 				&edp_config_set.raw,
 				sizeof(edp_config_set.raw));
 
-			ASSERT(result == DDC_RESULT_SUCESSFULL);
+			ASSERT(result == DC_OK);
 		}
 	}
 	DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
@@ -3490,7 +3508,14 @@
 	if (link_enc->funcs->fec_set_enable &&
 			link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
 		if (link->fec_state == dc_link_fec_ready && enable) {
-			msleep(1);
+			/* Accord to DP spec, FEC enable sequence can first
+			 * be transmitted anytime after 1000 LL codes have
+			 * been transmitted on the link after link training
+			 * completion. Using 1 lane RBR should have the maximum
+			 * time for transmitting 1000 LL codes which is 6.173 us.
+			 * So use 7 microseconds delay instead.
+			 */
+			udelay(7);
 			link_enc->funcs->fec_set_enable(link_enc, true);
 			link->fec_state = dc_link_fec_enabled;
 		} else if (link->fec_state == dc_link_fec_enabled && !enable) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -277,7 +277,8 @@
 		if (pipes[i].stream != NULL &&
 			!pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
 			pipes[i].stream->link != NULL &&
-			pipes[i].stream_res.stream_enc != NULL) {
+			pipes[i].stream_res.stream_enc != NULL &&
+			pipes[i].stream->link == link) {
 			udelay(100);
 
 			pipes[i].stream_res.stream_enc->funcs->dp_blank(
@@ -399,6 +400,7 @@
 		dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
 		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
 		dsc_cfg.color_depth = stream->timing.display_color_depth;
+		dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
 		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
 		ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
 		dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
@@ -495,11 +497,15 @@
 		struct dsc_config dsc_cfg;
 		uint8_t dsc_packed_pps[128];
 
+		memset(&dsc_cfg, 0, sizeof(dsc_cfg));
+		memset(dsc_packed_pps, 0, 128);
+
 		/* Enable DSC hw block */
 		dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
 		dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
 		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
 		dsc_cfg.color_depth = stream->timing.display_color_depth;
+		dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
 		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
 
 		DC_LOG_DSC(" ");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -1315,6 +1315,9 @@
 	struct dc_stream_status *stream_status = NULL;
 	struct resource_pool *pool = dc->res_pool;
 
+	if (!plane_state)
+		return true;
+
 	for (i = 0; i < context->stream_count; i++)
 		if (context->streams[i] == stream) {
 			stream_status = &context->stream_status[i];
@@ -1546,6 +1549,10 @@
 	if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
 		return false;
 
+	/*compare audio info*/
+	if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
+		return false;
+
 	return true;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -423,10 +423,10 @@
 
 		if (dwb->funcs->is_enabled(dwb)) {
 			/* writeback pipe already enabled, only need to update */
-			dc->hwss.update_writeback(dc, stream_status, wb_info);
+			dc->hwss.update_writeback(dc, stream_status, wb_info, dc->current_state);
 		} else {
 			/* Enable writeback pipe from scratch*/
-			dc->hwss.enable_writeback(dc, stream_status, wb_info);
+			dc->hwss.enable_writeback(dc, stream_status, wb_info, dc->current_state);
 		}
 	}
 
@@ -492,7 +492,7 @@
 	for (i = 0; i < MAX_PIPES; i++) {
 		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
 
-		if (res_ctx->pipe_ctx[i].stream != stream)
+		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
 			continue;
 
 		return tg->funcs->get_frame_count(tg);
@@ -551,7 +551,7 @@
 	for (i = 0; i < MAX_PIPES; i++) {
 		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
 
-		if (res_ctx->pipe_ctx[i].stream != stream)
+		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
 			continue;
 
 		tg->funcs->get_scanoutpos(tg,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
@@ -77,6 +77,9 @@
 	/* notifyDMCUMsg */
 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
 
+	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
+			1, 80000);
+
 	return true;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
@@ -386,7 +386,7 @@
 {
 	enum gpio_result result;
 
-	if (!is_engine_available(engine))
+	if ((engine == NULL) || !is_engine_available(engine))
 		return false;
 
 	result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -546,9 +546,11 @@
 		switch (pix_clk_params->color_depth) {
 		case COLOR_DEPTH_101010:
 			actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
+			actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
 			break;
 		case COLOR_DEPTH_121212:
 			actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
+			actual_pixel_clock_100hz -= actual_pixel_clock_100hz % 10;
 			break;
 		case COLOR_DEPTH_161616:
 			actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
@@ -871,6 +873,20 @@
 	bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
 					pll_settings->use_external_clk;
 
+	switch (pix_clk_params->color_depth) {
+	case COLOR_DEPTH_101010:
+		bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_30;
+		break;
+	case COLOR_DEPTH_121212:
+		bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_36;
+		break;
+	case COLOR_DEPTH_161616:
+		bp_pc_params.color_depth = TRANSMITTER_COLOR_DEPTH_48;
+		break;
+	default:
+		break;
+	}
+
 	if (clk_src->bios->funcs->set_pixel_clock(
 			clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
 		return false;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
@@ -563,6 +563,7 @@
 	cntl.enable_dp_audio = enable_audio;
 	cntl.pixel_clock = actual_pix_clk_khz;
 	cntl.lanes_number = LANE_COUNT_FOUR;
+	cntl.color_depth = crtc_timing->display_color_depth;
 
 	if (enc110->base.bp->funcs->encoder_control(
 			enc110->base.bp, &cntl) != BP_RESULT_OK)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
@@ -429,12 +429,12 @@
 		clamp_max = 0x3FC0;
 		break;
 	case COLOR_DEPTH_101010:
-		/* 10bit MSB aligned on 14 bit bus '11 1111 1111 1100' */
-		clamp_max = 0x3FFC;
+		/* 10bit MSB aligned on 14 bit bus '11 1111 1111 0000' */
+		clamp_max = 0x3FF0;
 		break;
 	case COLOR_DEPTH_121212:
-		/* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */
-		clamp_max = 0x3FFF;
+		/* 12bit MSB aligned on 14 bit bus '11 1111 1111 1100' */
+		clamp_max = 0x3FFC;
 		break;
 	default:
 		clamp_max = 0x3FC0;
@@ -778,7 +778,7 @@
 		color_depth = COLOR_DEPTH_101010;
 		pixel_depth = 0;
 		expan_mode  = 1;
-		BREAK_TO_DEBUGGER();
+		DC_LOG_DC("The pixel depth %d is not valid, set COLOR_DEPTH_101010 instead.", depth);
 		break;
 	}
 
@@ -792,8 +792,7 @@
 	if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
 		/*we should use unsupported capabilities
 		 *  unless it is required by w/a*/
-		DC_LOG_WARNING("%s: Capability not supported",
-			__func__);
+		DC_LOG_DC("%s: Capability not supported", __func__);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -340,7 +340,8 @@
 	audio_regs(2),
 	audio_regs(3),
 	audio_regs(4),
-	audio_regs(5)
+	audio_regs(5),
+	audio_regs(6),
 };
 
 #define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
@@ -484,10 +484,13 @@
 	int vtaps_c = scl_data->taps.v_taps_c;
 	int ceil_vratio = dc_fixpt_ceil(scl_data->ratios.vert);
 	int ceil_vratio_c = dc_fixpt_ceil(scl_data->ratios.vert_c);
-	enum lb_memory_config mem_cfg = LB_MEMORY_CONFIG_0;
 
-	if (dpp->base.ctx->dc->debug.use_max_lb)
-		return mem_cfg;
+	if (dpp->base.ctx->dc->debug.use_max_lb) {
+		if (scl_data->format == PIXEL_FORMAT_420BPP8
+				|| scl_data->format == PIXEL_FORMAT_420BPP10)
+			return LB_MEMORY_CONFIG_3;
+		return LB_MEMORY_CONFIG_0;
+	}
 
 	dpp->base.caps->dscl_calc_lb_num_partitions(
 			scl_data, LB_MEMORY_CONFIG_1, &num_part_y, &num_part_c);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
@@ -840,8 +840,8 @@
 
 	hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
 
-	swath_bytes_horz_wc = height * blk256_height * bpe;
-	swath_bytes_vert_wc = width * blk256_width * bpe;
+	swath_bytes_horz_wc = width * blk256_height * bpe;
+	swath_bytes_vert_wc = height * blk256_width * bpe;
 
 	*req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
 			false : /* full 256B request */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -2202,14 +2202,18 @@
 				&blnd_cfg.black_color);
 	}
 
-	if (per_pixel_alpha)
-		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
-	else
-		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
-
 	blnd_cfg.overlap_only = false;
 	blnd_cfg.global_gain = 0xff;
 
+	if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
+		blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
+	} else if (per_pixel_alpha) {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
+	} else {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
+	}
+
 	if (pipe_ctx->plane_state->global_alpha)
 		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
 	else
@@ -2898,7 +2902,9 @@
 		if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
 			struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
 
-			res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
+			if (pipe_ctx->stream_res.tg &&
+				pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg))
+				res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
 			pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
 			hubp->funcs->set_blank(hubp, true);
 		}
@@ -3264,13 +3270,12 @@
 	struct dc_clock_config clock_cfg = {0};
 	struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk;
 
-	if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock)
-				dc->clk_mgr->funcs->get_clock(dc->clk_mgr,
-						context, clock_type, &clock_cfg);
-
-	if (!dc->clk_mgr->funcs->get_clock)
+	if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock)
 		return DC_FAIL_UNSUPPORTED_1;
 
+	dc->clk_mgr->funcs->get_clock(dc->clk_mgr,
+		context, clock_type, &clock_cfg);
+
 	if (clk_khz > clock_cfg.max_clock_khz)
 		return DC_FAIL_CLK_EXCEED_MAX;
 
@@ -3288,7 +3293,7 @@
 	else
 		return DC_ERROR_UNEXPECTED;
 
-	if (dc->clk_mgr && dc->clk_mgr->funcs->update_clocks)
+	if (dc->clk_mgr->funcs->update_clocks)
 				dc->clk_mgr->funcs->update_clocks(dc->clk_mgr,
 				context, true);
 	return DC_OK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c
@@ -118,6 +118,12 @@
 	while (tmp_mpcc != NULL) {
 		if (tmp_mpcc->dpp_id == dpp_id)
 			return tmp_mpcc;
+
+		/* avoid circular linked list */
+		ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot);
+		if (tmp_mpcc == tmp_mpcc->mpcc_bot)
+			break;
+
 		tmp_mpcc = tmp_mpcc->mpcc_bot;
 	}
 	return NULL;
@@ -193,8 +199,9 @@
 		/* check insert_above_mpcc exist in tree->opp_list */
 		struct mpcc *temp_mpcc = tree->opp_list;
 
-		while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
-			temp_mpcc = temp_mpcc->mpcc_bot;
+		if (temp_mpcc != insert_above_mpcc)
+			while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
+				temp_mpcc = temp_mpcc->mpcc_bot;
 		if (temp_mpcc == NULL)
 			return NULL;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -425,6 +425,11 @@
 				OTG_CLOCK_ON, 1,
 				1, 1000);
 	} else  {
+
+		//last chance to clear underflow, otherwise, it will always there due to clock is off.
+		if (optc->funcs->is_optc_underflow_occurred(optc) == true)
+			optc->funcs->clear_optc_underflow(optc);
+
 		REG_UPDATE_2(OTG_CLOCK_CONTROL,
 				OTG_CLOCK_GATE_DIS, 0,
 				OTG_CLOCK_EN, 0);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
@@ -1151,6 +1151,7 @@
 	bool video_large = false;
 	bool desktop_large = false;
 	bool dcc_disabled = false;
+	bool mpo_enabled = false;
 
 	for (i = 0; i < context->stream_count; i++) {
 		if (context->stream_status[i].plane_count == 0)
@@ -1159,6 +1160,9 @@
 		if (context->stream_status[i].plane_count > 2)
 			return DC_FAIL_UNSUPPORTED_1;
 
+		if (context->stream_status[i].plane_count > 1)
+			mpo_enabled = true;
+
 		for (j = 0; j < context->stream_status[i].plane_count; j++) {
 			struct dc_plane_state *plane =
 				context->stream_status[i].plane_states[j];
@@ -1182,6 +1186,10 @@
 		}
 	}
 
+	/* Disable MPO in multi-display configurations. */
+	if (context->stream_count > 1 && mpo_enabled)
+		return DC_FAIL_UNSUPPORTED_1;
+
 	/*
 	 * Workaround: On DCN10 there is UMC issue that causes underflow when
 	 * playing 4k video on 4k desktop with video downscaled and single channel
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
@@ -121,35 +121,35 @@
 	switch (packet_index) {
 	case 0:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC0_FRAME_UPDATE, 1);
+				AFMT_GENERIC0_IMMEDIATE_UPDATE, 1);
 		break;
 	case 1:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC1_FRAME_UPDATE, 1);
+				AFMT_GENERIC1_IMMEDIATE_UPDATE, 1);
 		break;
 	case 2:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC2_FRAME_UPDATE, 1);
+				AFMT_GENERIC2_IMMEDIATE_UPDATE, 1);
 		break;
 	case 3:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC3_FRAME_UPDATE, 1);
+				AFMT_GENERIC3_IMMEDIATE_UPDATE, 1);
 		break;
 	case 4:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC4_FRAME_UPDATE, 1);
+				AFMT_GENERIC4_IMMEDIATE_UPDATE, 1);
 		break;
 	case 5:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC5_FRAME_UPDATE, 1);
+				AFMT_GENERIC5_IMMEDIATE_UPDATE, 1);
 		break;
 	case 6:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC6_FRAME_UPDATE, 1);
+				AFMT_GENERIC6_IMMEDIATE_UPDATE, 1);
 		break;
 	case 7:
 		REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-				AFMT_GENERIC7_FRAME_UPDATE, 1);
+				AFMT_GENERIC7_IMMEDIATE_UPDATE, 1);
 		break;
 	default:
 		break;
@@ -898,10 +898,10 @@
 	 */
 	REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2);
 	/* Larger delay to wait until VBLANK - use max retry of
-	 * 10us*5000=50ms. This covers 41.7ms of minimum 24 Hz mode +
+	 * 10us*10200=102ms. This covers 100.0ms of minimum 10 Hz mode +
 	 * a little more because we may not trust delay accuracy.
 	 */
-	max_retries = DP_BLANK_MAX_RETRY * 250;
+	max_retries = DP_BLANK_MAX_RETRY * 501;
 
 	/* disable DP stream */
 	REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
@@ -275,7 +275,14 @@
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_FRAME_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_FRAME_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_FRAME_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC0_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC1_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_IMMEDIATE_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_IMMEDIATE_UPDATE, mask_sh),\
+	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_IMMEDIATE_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_FRAME_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_FRAME_UPDATE, mask_sh),\
 	SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE, mask_sh),\
@@ -339,7 +346,14 @@
 	type AFMT_GENERIC2_FRAME_UPDATE;\
 	type AFMT_GENERIC3_FRAME_UPDATE;\
 	type AFMT_GENERIC4_FRAME_UPDATE;\
+	type AFMT_GENERIC0_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC1_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC2_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC3_IMMEDIATE_UPDATE;\
 	type AFMT_GENERIC4_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC5_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC6_IMMEDIATE_UPDATE;\
+	type AFMT_GENERIC7_IMMEDIATE_UPDATE;\
 	type AFMT_GENERIC5_FRAME_UPDATE;\
 	type AFMT_GENERIC6_FRAME_UPDATE;\
 	type AFMT_GENERIC7_FRAME_UPDATE;\
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c
@@ -119,32 +119,6 @@
 
 void dccg2_init(struct dccg *dccg)
 {
-	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-
-	// Fallthrough intentional to program all available dpp_dto's
-	switch (dccg_dcn->base.ctx->dc->res_pool->pipe_count) {
-	case 6:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[5], 1);
-		/* Fall through */
-	case 5:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[4], 1);
-		/* Fall through */
-	case 4:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[3], 1);
-		/* Fall through */
-	case 3:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[2], 1);
-		/* Fall through */
-	case 2:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[1], 1);
-		/* Fall through */
-	case 1:
-		REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[0], 1);
-		break;
-	default:
-		ASSERT(false);
-		break;
-	}
 }
 
 static const struct dccg_funcs dccg2_funcs = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
@@ -207,6 +207,9 @@
 	struct dsc_reg_values dsc_reg_vals;
 	struct dsc_optc_config dsc_optc_cfg;
 
+	memset(&dsc_reg_vals, 0, sizeof(dsc_reg_vals));
+	memset(&dsc_optc_cfg, 0, sizeof(dsc_optc_cfg));
+
 	DC_LOG_DSC("Getting packed DSC PPS for DSC Config:");
 	dsc_config_log(dsc, dsc_cfg);
 	DC_LOG_DSC("DSC Picture Parameter Set (PPS):");
@@ -348,6 +351,7 @@
 	dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable;
 	dsc_reg_vals->pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth;
 	dsc_reg_vals->alternate_ich_encoding_en = dsc_reg_vals->pps.dsc_version_minor == 1 ? 0 : 1;
+	dsc_reg_vals->ich_reset_at_eol = (dsc_cfg->is_odm || dsc_reg_vals->num_slices_h > 1) ? 0xF : 0;
 
 	// TODO: in addition to validating slice height (pic height must be divisible by slice height),
 	// see what happens when the same condition doesn't apply for slice_width/pic_width.
@@ -510,7 +514,6 @@
 		reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6;
 
 	reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size;
-	reg_vals->ich_reset_at_eol = reg_vals->num_slices_h == 1 ? 0 : 0xf;
 }
 
 static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-17 Advanced Micro Devices, Inc.
+ * Copyright 2012-2021 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"),
@@ -179,11 +179,14 @@
 	else
 		Set HUBP_VREADY_AT_OR_AFTER_VSYNC = 0
 	*/
-	if ((pipe_dest->vstartup_start - (pipe_dest->vready_offset+pipe_dest->vupdate_width
-		+ pipe_dest->vupdate_offset) / pipe_dest->htotal) <= pipe_dest->vblank_end) {
-		value = 1;
-	} else
-		value = 0;
+	if (pipe_dest->htotal != 0) {
+		if ((pipe_dest->vstartup_start - (pipe_dest->vready_offset+pipe_dest->vupdate_width
+			+ pipe_dest->vupdate_offset) / pipe_dest->htotal) <= pipe_dest->vblank_end) {
+			value = 1;
+		} else
+			value = 0;
+	}
+
 	REG_UPDATE(DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, value);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -126,7 +126,7 @@
 	REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);
 
 	/* This value is dependent on the hardware pipeline delay so set once per SOC */
-	REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c);
+	REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c);
 }
 void dcn20_display_init(struct dc *dc)
 {
@@ -493,7 +493,6 @@
 	dpp->funcs->dpp_dppclk_control(dpp, false, false);
 
 	hubp->power_gated = true;
-	dc->optimized_required = false; /* We're powering off, no need to optimize */
 
 	dc->hwss.plane_atomic_power_down(dc,
 			pipe_ctx->plane_res.dpp,
@@ -1103,6 +1102,25 @@
 	if (pipe->plane_state != NULL)
 		flip_immediate = pipe->plane_state->flip_immediate;
 
+	if (flip_immediate && lock) {
+		const int TIMEOUT_FOR_FLIP_PENDING = 100000;
+		int i;
+
+		for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
+			if (!pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->plane_res.hubp))
+				break;
+			udelay(1);
+		}
+
+		if (pipe->bottom_pipe != NULL) {
+			for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
+				if (!pipe->bottom_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->bottom_pipe->plane_res.hubp))
+					break;
+				udelay(1);
+			}
+		}
+	}
+
 	/* In flip immediate and pipe splitting case, we need to use GSL
 	 * for synchronization. Only do setup on locking and on flip type change.
 	 */
@@ -1337,7 +1355,8 @@
 static void dcn20_enable_writeback(
 		struct dc *dc,
 		const struct dc_stream_status *stream_status,
-		struct dc_writeback_info *wb_info)
+		struct dc_writeback_info *wb_info,
+		struct dc_state *context)
 {
 	struct dwbc *dwb;
 	struct mcif_wb *mcif_wb;
@@ -1354,7 +1373,7 @@
 	optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);
 	/* set MCIF_WB buffer and arbitration configuration */
 	mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
-	mcif_wb->funcs->config_mcif_arb(mcif_wb, &dc->current_state->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
+	mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
 	/* Enable MCIF_WB */
 	mcif_wb->funcs->enable_mcif(mcif_wb);
 	/* Enable DWB */
@@ -1721,14 +1740,18 @@
 				pipe_ctx, &blnd_cfg.black_color);
 	}
 
-	if (per_pixel_alpha)
-		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
-	else
-		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
-
 	blnd_cfg.overlap_only = false;
 	blnd_cfg.global_gain = 0xff;
 
+	if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
+		blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
+	} else if (per_pixel_alpha) {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
+	} else {
+		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
+	}
+
 	if (pipe_ctx->plane_state->global_alpha)
 		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
 	else
@@ -1996,7 +2019,8 @@
 
 	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
 	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
-	REG_WRITE(REFCLK_CNTL, 0);
+	if (REG(REFCLK_CNTL))
+		REG_WRITE(REFCLK_CNTL, 0);
 	//
 
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
@@ -488,6 +488,12 @@
 	while (tmp_mpcc != NULL) {
 		if (tmp_mpcc->dpp_id == 0xf || tmp_mpcc->dpp_id == dpp_id)
 			return tmp_mpcc;
+
+		/* avoid circular linked list */
+		ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot);
+		if (tmp_mpcc == tmp_mpcc->mpcc_bot)
+			break;
+
 		tmp_mpcc = tmp_mpcc->mpcc_bot;
 	}
 	return NULL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
@@ -233,12 +233,13 @@
 		struct dc_crtc_timing *timing)
 {
 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
-	/* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */
 	int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
 			/ opp_cnt;
-	int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf;
+	uint32_t memory_mask;
 	uint32_t data_fmt = 0;
 
+	ASSERT(opp_cnt == 2);
+
 	/* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic
 	 * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1);
 	 * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start
@@ -246,9 +247,17 @@
 	 *		MASTER_UPDATE_LOCK_DB_X, 160,
 	 *		MASTER_UPDATE_LOCK_DB_Y, 240);
 	 */
+
+	/* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192,
+	 * however, for ODM combine we can simplify by always using 4.
+	 * To make sure there's no overlap, each instance "reserves" 2 memories and
+	 * they are uniquely combined here.
+	 */
+	memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2);
+
 	if (REG(OPTC_MEMORY_CONFIG))
 		REG_SET(OPTC_MEMORY_CONFIG, 0,
-			OPTC_MEM_SEL, memory_mask << (optc->inst * 4));
+			OPTC_MEM_SEL, memory_mask);
 
 	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
 		data_fmt = 1;
@@ -257,7 +266,6 @@
 
 	REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt);
 
-	ASSERT(opp_cnt == 2);
 	REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0,
 			OPTC_NUM_OF_INPUT_SEGMENT, 1,
 			OPTC_SEG0_SRC_SEL, opp_id[0],
@@ -287,6 +295,10 @@
 		*num_of_src_opp = 2;
 	else
 		*num_of_src_opp = 1;
+
+	/* Work around VBIOS not updating OPTC_NUM_OF_INPUT_SEGMENT */
+	if (*src_opp_id_1 == 0xf)
+		*num_of_src_opp = 1;
 }
 
 void optc2_set_dwb_source(struct timing_generator *optc,
@@ -350,7 +362,7 @@
 
 	REG_UPDATE_2(OTG_GLOBAL_CONTROL1,
 			MASTER_UPDATE_LOCK_DB_X,
-			h_blank_start - 200 - 1,
+			(h_blank_start - 200 - 1) / optc1->opp_count,
 			MASTER_UPDATE_LOCK_DB_Y,
 			v_blank_start - 1);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -269,6 +269,117 @@
 	.use_urgent_burst_bw = 0
 };
 
+struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = {
+	.clock_limits = {
+			{
+				.state = 0,
+				.dcfclk_mhz = 560.0,
+				.fabricclk_mhz = 560.0,
+				.dispclk_mhz = 513.0,
+				.dppclk_mhz = 513.0,
+				.phyclk_mhz = 540.0,
+				.socclk_mhz = 560.0,
+				.dscclk_mhz = 171.0,
+				.dram_speed_mts = 8960.0,
+			},
+			{
+				.state = 1,
+				.dcfclk_mhz = 694.0,
+				.fabricclk_mhz = 694.0,
+				.dispclk_mhz = 642.0,
+				.dppclk_mhz = 642.0,
+				.phyclk_mhz = 600.0,
+				.socclk_mhz = 694.0,
+				.dscclk_mhz = 214.0,
+				.dram_speed_mts = 11104.0,
+			},
+			{
+				.state = 2,
+				.dcfclk_mhz = 875.0,
+				.fabricclk_mhz = 875.0,
+				.dispclk_mhz = 734.0,
+				.dppclk_mhz = 734.0,
+				.phyclk_mhz = 810.0,
+				.socclk_mhz = 875.0,
+				.dscclk_mhz = 245.0,
+				.dram_speed_mts = 14000.0,
+			},
+			{
+				.state = 3,
+				.dcfclk_mhz = 1000.0,
+				.fabricclk_mhz = 1000.0,
+				.dispclk_mhz = 1100.0,
+				.dppclk_mhz = 1100.0,
+				.phyclk_mhz = 810.0,
+				.socclk_mhz = 1000.0,
+				.dscclk_mhz = 367.0,
+				.dram_speed_mts = 16000.0,
+			},
+			{
+				.state = 4,
+				.dcfclk_mhz = 1200.0,
+				.fabricclk_mhz = 1200.0,
+				.dispclk_mhz = 1284.0,
+				.dppclk_mhz = 1284.0,
+				.phyclk_mhz = 810.0,
+				.socclk_mhz = 1200.0,
+				.dscclk_mhz = 428.0,
+				.dram_speed_mts = 16000.0,
+			},
+			/*Extra state, no dispclk ramping*/
+			{
+				.state = 5,
+				.dcfclk_mhz = 1200.0,
+				.fabricclk_mhz = 1200.0,
+				.dispclk_mhz = 1284.0,
+				.dppclk_mhz = 1284.0,
+				.phyclk_mhz = 810.0,
+				.socclk_mhz = 1200.0,
+				.dscclk_mhz = 428.0,
+				.dram_speed_mts = 16000.0,
+			},
+		},
+	.num_states = 5,
+	.sr_exit_time_us = 11.6,
+	.sr_enter_plus_exit_time_us = 13.9,
+	.urgent_latency_us = 4.0,
+	.urgent_latency_pixel_data_only_us = 4.0,
+	.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+	.urgent_latency_vm_data_only_us = 4.0,
+	.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+	.max_avg_sdp_bw_use_normal_percent = 40.0,
+	.max_avg_dram_bw_use_normal_percent = 40.0,
+	.writeback_latency_us = 12.0,
+	.ideal_dram_bw_after_urgent_percent = 40.0,
+	.max_request_size_bytes = 256,
+	.dram_channel_width_bytes = 2,
+	.fabric_datapath_to_dcn_data_return_bytes = 64,
+	.dcn_downspread_percent = 0.5,
+	.downspread_percent = 0.38,
+	.dram_page_open_time_ns = 50.0,
+	.dram_rw_turnaround_time_ns = 17.5,
+	.dram_return_buffer_per_channel_bytes = 8192,
+	.round_trip_ping_latency_dcfclk_cycles = 131,
+	.urgent_out_of_order_return_per_channel_bytes = 256,
+	.channel_interleave_bytes = 256,
+	.num_banks = 8,
+	.num_chans = 8,
+	.vmm_page_size_bytes = 4096,
+	.dram_clock_change_latency_us = 404.0,
+	.dummy_pstate_latency_us = 5.0,
+	.writeback_dram_clock_change_latency_us = 23.0,
+	.return_bus_width_bytes = 64,
+	.dispclk_dppclk_vco_speed_mhz = 3850,
+	.xfc_bus_transport_time_us = 20,
+	.xfc_xbuf_latency_tolerance_us = 4,
+	.use_urgent_burst_bw = 0
+};
+
 struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 };
 
 #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
@@ -1419,13 +1530,20 @@
 
 static void acquire_dsc(struct resource_context *res_ctx,
 			const struct resource_pool *pool,
-			struct display_stream_compressor **dsc)
+			struct display_stream_compressor **dsc,
+			int pipe_idx)
 {
 	int i;
 
 	ASSERT(*dsc == NULL);
 	*dsc = NULL;
 
+	if (pool->res_cap->num_dsc == pool->res_cap->num_opp) {
+		*dsc = pool->dscs[pipe_idx];
+		res_ctx->is_dsc_acquired[pipe_idx] = true;
+		return;
+	}
+
 	/* Find first free DSC */
 	for (i = 0; i < pool->res_cap->num_dsc; i++)
 		if (!res_ctx->is_dsc_acquired[i]) {
@@ -1468,7 +1586,7 @@
 		if (pipe_ctx->stream != dc_stream)
 			continue;
 
-		acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc);
+		acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc, i);
 
 		/* The number of DSCs can be less than the number of pipes */
 		if (!pipe_ctx->stream_res.dsc) {
@@ -1669,7 +1787,7 @@
 	next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx];
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
 	if (next_odm_pipe->stream->timing.flags.DSC == 1) {
-		acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc);
+		acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx);
 		ASSERT(next_odm_pipe->stream_res.dsc);
 		if (next_odm_pipe->stream_res.dsc == NULL)
 			return false;
@@ -1765,7 +1883,7 @@
 			pipe_cnt = i;
 			continue;
 		}
-		if (!resource_are_streams_timing_synchronizable(
+		if (dc->debug.disable_timing_sync || !resource_are_streams_timing_synchronizable(
 				res_ctx->pipe_ctx[pipe_cnt].stream,
 				res_ctx->pipe_ctx[i].stream)) {
 			synchronized_vblank = false;
@@ -2114,7 +2232,7 @@
 				wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
 				wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
 			}
-			wb_arb_params->time_per_pixel = 16.0 / context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; /* 4 bit fraction, ms */
+			wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */
 			wb_arb_params->slice_lines = 32;
 			wb_arb_params->arbitration_slice = 2;
 			wb_arb_params->max_scaled_time = dcn20_calc_max_scaled_time(wb_arb_params->time_per_pixel,
@@ -2157,6 +2275,7 @@
 				+ stream->timing.v_border_bottom;
 		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
 		dsc_cfg.color_depth = stream->timing.display_color_depth;
+		dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
 		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
 		dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
 
@@ -2474,6 +2593,7 @@
 							&context->res_ctx, dc->res_pool,
 							pipe, hsplit_pipe))
 						goto validate_fail;
+					dcn20_build_mapped_resource(dc, context, pipe->stream);
 				} else
 					dcn20_split_stream_for_mpc(
 						&context->res_ctx, dc->res_pool,
@@ -2726,7 +2846,7 @@
 	int vlevel = 0;
 	int pipe_split_from[MAX_PIPES];
 	int pipe_cnt = 0;
-	display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
+	display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
 	DC_LOGGER_INIT(dc->ctx->logger);
 
 	BW_VAL_TRACE_COUNT();
@@ -2797,7 +2917,7 @@
 	voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
 	dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
 
-	if (voltage_supported && dummy_pstate_supported) {
+	if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) {
 		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
 		goto restore_dml_state;
 	}
@@ -3040,7 +3160,7 @@
 static void update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb,
 		struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states)
 {
-	struct _vcs_dpi_voltage_scaling_st calculated_states[MAX_CLOCK_LIMIT_STATES] = {0};
+	struct _vcs_dpi_voltage_scaling_st calculated_states[MAX_CLOCK_LIMIT_STATES];
 	int i;
 	int num_calculated_states = 0;
 	int min_dcfclk = 0;
@@ -3048,6 +3168,8 @@
 	if (num_states == 0)
 		return;
 
+	memset(calculated_states, 0, sizeof(calculated_states));
+
 	if (dc->bb_overrides.min_dcfclk_mhz > 0)
 		min_dcfclk = dc->bb_overrides.min_dcfclk_mhz;
 	else
@@ -3125,6 +3247,9 @@
 static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb(
 	uint32_t hw_internal_rev)
 {
+	if (ASICREV_IS_NAVI14_M(hw_internal_rev))
+		return &dcn2_0_nv14_soc;
+
 	if (ASICREV_IS_NAVI12_P(hw_internal_rev))
 		return &dcn2_0_nv12_soc;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
@@ -492,15 +492,23 @@
 				DP_VID_N_MUL, n_multiply);
 	}
 
-	/* set DIG_START to 0x1 to reset FIFO */
+	/* make sure stream is disabled before resetting steer fifo */
+	REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, false);
+	REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, 0, 10, 5000);
 
+	/* set DIG_START to 0x1 to reset FIFO */
 	REG_UPDATE(DIG_FE_CNTL, DIG_START, 1);
+	udelay(1);
 
 	/* write 0 to take the FIFO out of reset */
 
 	REG_UPDATE(DIG_FE_CNTL, DIG_START, 0);
 
-	/* switch DP encoder to CRTC data */
+	/* switch DP encoder to CRTC data, but reset it the fifo first. It may happen
+	 * that it overflows during mode transition, and sometimes doesn't recover.
+	 */
+	REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 1);
+	udelay(10);
 
 	REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 0);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c
@@ -22,6 +22,7 @@
  * Authors: AMD
  *
  */
+#include <linux/delay.h>
 #include "dm_services.h"
 #include "dcn20/dcn20_hubbub.h"
 #include "dcn21_hubbub.h"
@@ -71,30 +72,39 @@
 void dcn21_dchvm_init(struct hubbub *hubbub)
 {
 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
+	uint32_t riommu_active;
+	int i;
 
 	//Init DCHVM block
 	REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
 
 	//Poll until RIOMMU_ACTIVE = 1
-	//TODO: Figure out interval us and retry count
-	REG_WAIT(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, 1, 5, 100);
+	for (i = 0; i < 100; i++) {
+		REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active);
 
-	//Reflect the power status of DCHUBBUB
-	REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
-
-	//Start rIOMMU prefetching
-	REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
-
-	// Enable dynamic clock gating
-	REG_UPDATE_4(DCHVM_CLK_CTRL,
-					HVM_DISPCLK_R_GATE_DIS, 0,
-					HVM_DISPCLK_G_GATE_DIS, 0,
-					HVM_DCFCLK_R_GATE_DIS, 0,
-					HVM_DCFCLK_G_GATE_DIS, 0);
-
-	//Poll until HOSTVM_PREFETCH_DONE = 1
-	//TODO: Figure out interval us and retry count
-	REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
+		if (riommu_active)
+			break;
+		else
+			udelay(5);
+	}
+
+	if (riommu_active) {
+		//Reflect the power status of DCHUBBUB
+		REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
+
+		//Start rIOMMU prefetching
+		REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
+
+		// Enable dynamic clock gating
+		REG_UPDATE_4(DCHVM_CLK_CTRL,
+						HVM_DISPCLK_R_GATE_DIS, 0,
+						HVM_DISPCLK_G_GATE_DIS, 0,
+						HVM_DCFCLK_R_GATE_DIS, 0,
+						HVM_DCFCLK_G_GATE_DIS, 0);
+
+		//Poll until HOSTVM_PREFETCH_DONE = 1
+		REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
+	}
 }
 
 static int hubbub21_init_dchub(struct hubbub *hubbub,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c
@@ -73,32 +73,47 @@
 		struct _vcs_dpi_display_dlg_regs_st *dlg_attr)
 {
 	struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp);
-	uint32_t cur_value;
+	uint32_t refcyc_per_vm_group_vblank;
+	uint32_t refcyc_per_vm_req_vblank;
+	uint32_t refcyc_per_vm_group_flip;
+	uint32_t refcyc_per_vm_req_flip;
+	const uint32_t uninitialized_hw_default = 0;
 
-	REG_GET(VBLANK_PARAMETERS_5, REFCYC_PER_VM_GROUP_VBLANK, &cur_value);
-	if (cur_value > dlg_attr->refcyc_per_vm_group_vblank)
+	REG_GET(VBLANK_PARAMETERS_5,
+			REFCYC_PER_VM_GROUP_VBLANK, &refcyc_per_vm_group_vblank);
+
+	if (refcyc_per_vm_group_vblank == uninitialized_hw_default ||
+			refcyc_per_vm_group_vblank > dlg_attr->refcyc_per_vm_group_vblank)
 		REG_SET(VBLANK_PARAMETERS_5, 0,
 				REFCYC_PER_VM_GROUP_VBLANK, dlg_attr->refcyc_per_vm_group_vblank);
 
 	REG_GET(VBLANK_PARAMETERS_6,
-			REFCYC_PER_VM_REQ_VBLANK,
-			&cur_value);
-	if (cur_value > dlg_attr->refcyc_per_vm_req_vblank)
+			REFCYC_PER_VM_REQ_VBLANK, &refcyc_per_vm_req_vblank);
+
+	if (refcyc_per_vm_req_vblank == uninitialized_hw_default ||
+			refcyc_per_vm_req_vblank > dlg_attr->refcyc_per_vm_req_vblank)
 		REG_SET(VBLANK_PARAMETERS_6, 0,
 				REFCYC_PER_VM_REQ_VBLANK, dlg_attr->refcyc_per_vm_req_vblank);
 
-	REG_GET(FLIP_PARAMETERS_3, REFCYC_PER_VM_GROUP_FLIP, &cur_value);
-	if (cur_value > dlg_attr->refcyc_per_vm_group_flip)
+	REG_GET(FLIP_PARAMETERS_3,
+			REFCYC_PER_VM_GROUP_FLIP, &refcyc_per_vm_group_flip);
+
+	if (refcyc_per_vm_group_flip == uninitialized_hw_default ||
+			refcyc_per_vm_group_flip > dlg_attr->refcyc_per_vm_group_flip)
 		REG_SET(FLIP_PARAMETERS_3, 0,
 				REFCYC_PER_VM_GROUP_FLIP, dlg_attr->refcyc_per_vm_group_flip);
 
-	REG_GET(FLIP_PARAMETERS_4, REFCYC_PER_VM_REQ_FLIP, &cur_value);
-	if (cur_value > dlg_attr->refcyc_per_vm_req_flip)
+	REG_GET(FLIP_PARAMETERS_4,
+			REFCYC_PER_VM_REQ_FLIP, &refcyc_per_vm_req_flip);
+
+	if (refcyc_per_vm_req_flip == uninitialized_hw_default ||
+			refcyc_per_vm_req_flip > dlg_attr->refcyc_per_vm_req_flip)
 		REG_SET(FLIP_PARAMETERS_4, 0,
 					REFCYC_PER_VM_REQ_FLIP, dlg_attr->refcyc_per_vm_req_flip);
 
 	REG_SET(FLIP_PARAMETERS_5, 0,
 			REFCYC_PER_PTE_GROUP_FLIP_C, dlg_attr->refcyc_per_pte_group_flip_c);
+
 	REG_SET(FLIP_PARAMETERS_6, 0,
 			REFCYC_PER_META_CHUNK_FLIP_C, dlg_attr->refcyc_per_meta_chunk_flip_c);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
@@ -57,6 +57,7 @@
 #include "dcn20/dcn20_dccg.h"
 #include "dcn21_hubbub.h"
 #include "dcn10/dcn10_resource.h"
+#include "dce110/dce110_resource.h"
 
 #include "dcn20/dcn20_dwb.h"
 #include "dcn20/dcn20_mmhubbub.h"
@@ -246,7 +247,7 @@
 	.dram_channel_width_bytes = 4,
 	.fabric_datapath_to_dcn_data_return_bytes = 32,
 	.dcn_downspread_percent = 0.5,
-	.downspread_percent = 0.5,
+	.downspread_percent = 0.38,
 	.dram_page_open_time_ns = 50.0,
 	.dram_rw_turnaround_time_ns = 17.5,
 	.dram_return_buffer_per_channel_bytes = 8192,
@@ -258,7 +259,7 @@
 	.vmm_page_size_bytes = 4096,
 	.dram_clock_change_latency_us = 23.84,
 	.return_bus_width_bytes = 64,
-	.dispclk_dppclk_vco_speed_mhz = 3550,
+	.dispclk_dppclk_vco_speed_mhz = 3600,
 	.xfc_bus_transport_time_us = 4,
 	.xfc_xbuf_latency_tolerance_us = 4,
 	.use_urgent_burst_bw = 1,
@@ -824,6 +825,9 @@
 enum dcn20_clk_src_array_id {
 	DCN20_CLK_SRC_PLL0,
 	DCN20_CLK_SRC_PLL1,
+	DCN20_CLK_SRC_PLL2,
+	DCN20_CLK_SRC_PLL3,
+	DCN20_CLK_SRC_PLL4,
 	DCN20_CLK_SRC_TOTAL_DCN21
 };
 
@@ -1136,6 +1140,7 @@
 		return &clk_src->base;
 	}
 
+	kfree(clk_src);
 	BREAK_TO_DEBUGGER();
 	return NULL;
 }
@@ -1492,6 +1497,18 @@
 			dcn21_clock_source_create(ctx, ctx->dc_bios,
 				CLOCK_SOURCE_COMBO_PHY_PLL1,
 				&clk_src_regs[1], false);
+	pool->base.clock_sources[DCN20_CLK_SRC_PLL2] =
+			dcn21_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL2,
+				&clk_src_regs[2], false);
+	pool->base.clock_sources[DCN20_CLK_SRC_PLL3] =
+			dcn21_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL3,
+				&clk_src_regs[3], false);
+	pool->base.clock_sources[DCN20_CLK_SRC_PLL4] =
+			dcn21_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL4,
+				&clk_src_regs[4], false);
 
 	pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN21;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c
@@ -3435,6 +3435,7 @@
 			mode_lib->vba.DCCEnabledInAnyPlane = true;
 		}
 	}
+	mode_lib->vba.UrgentLatency = mode_lib->vba.UrgentLatencyPixelDataOnly;
 	for (i = 0; i <= mode_lib->vba.soc.num_states; i++) {
 		locals->FabricAndDRAMBandwidthPerState[i] = dml_min(
 				mode_lib->vba.DRAMSpeedPerState[i] * mode_lib->vba.NumberOfChannels
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c
@@ -3467,6 +3467,7 @@
 			mode_lib->vba.DCCEnabledInAnyPlane = true;
 		}
 	}
+	mode_lib->vba.UrgentLatency = mode_lib->vba.UrgentLatencyPixelDataOnly;
 	for (i = 0; i <= mode_lib->vba.soc.num_states; i++) {
 		locals->FabricAndDRAMBandwidthPerState[i] = dml_min(
 				mode_lib->vba.DRAMSpeedPerState[i] * mode_lib->vba.NumberOfChannels
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.c
@@ -24,7 +24,7 @@
  */
 
 #include "dml_common_defs.h"
-#include "../calcs/dcn_calc_math.h"
+#include "dcn_calc_math.h"
 
 #include "dml_inline_defs.h"
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h
@@ -27,7 +27,7 @@
 #define __DML_INLINE_DEFS_H__
 
 #include "dml_common_defs.h"
-#include "../calcs/dcn_calc_math.h"
+#include "dcn_calc_math.h"
 #include "dml_logger.h"
 
 static inline double dml_min(double a, double b)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
@@ -63,13 +63,13 @@
 	enum gpio_mode mode)
 {
 	if (gpio->pin) {
-		ASSERT_CRITICAL(false);
+		BREAK_TO_DEBUGGER();
 		return GPIO_RESULT_ALREADY_OPENED;
 	}
 
 	// No action if allocation failed during gpio construct
 	if (!gpio->hw_container.ddc) {
-		ASSERT_CRITICAL(false);
+		BREAK_TO_DEBUGGER();
 		return GPIO_RESULT_NON_SPECIFIC_ERROR;
 	}
 	gpio->mode = mode;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
@@ -53,8 +53,8 @@
  */
 
 struct gpio_service *dal_gpio_service_create(
-	enum dce_version dce_version_major,
-	enum dce_version dce_version_minor,
+	enum dce_version dce_version,
+	enum dce_environment dce_environment,
 	struct dc_context *ctx)
 {
 	struct gpio_service *service;
@@ -67,14 +67,14 @@
 		return NULL;
 	}
 
-	if (!dal_hw_translate_init(&service->translate, dce_version_major,
-			dce_version_minor)) {
+	if (!dal_hw_translate_init(&service->translate, dce_version,
+			dce_environment)) {
 		BREAK_TO_DEBUGGER();
 		goto failure_1;
 	}
 
-	if (!dal_hw_factory_init(&service->factory, dce_version_major,
-			dce_version_minor)) {
+	if (!dal_hw_factory_init(&service->factory, dce_version,
+			dce_environment)) {
 		BREAK_TO_DEBUGGER();
 		goto failure_1;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/inc/dcn_calc_math.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/inc/dcn_calc_math.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 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 _DCN_CALC_MATH_H_
+#define _DCN_CALC_MATH_H_
+
+float dcn_bw_mod(const float arg1, const float arg2);
+float dcn_bw_min2(const float arg1, const float arg2);
+unsigned int dcn_bw_max(const unsigned int arg1, const unsigned int arg2);
+float dcn_bw_max2(const float arg1, const float arg2);
+float dcn_bw_floor2(const float arg, const float significance);
+float dcn_bw_floor(const float arg);
+float dcn_bw_ceil2(const float arg, const float significance);
+float dcn_bw_ceil(const float arg);
+float dcn_bw_max3(float v1, float v2, float v3);
+float dcn_bw_max5(float v1, float v2, float v3, float v4, float v5);
+float dcn_bw_pow(float a, float exp);
+float dcn_bw_log(float a, float b);
+double dcn_bw_fabs(double a);
+
+#endif /* _DCN_CALC_MATH_H_ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
@@ -36,6 +36,7 @@
 	uint32_t pic_height;
 	enum dc_pixel_encoding pixel_encoding;
 	enum dc_color_depth color_depth;  /* Bits per component */
+	bool is_odm;
 	struct dc_dsc_config dc_dsc_cfg;
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -321,10 +321,12 @@
 			struct dc_state *context);
 	void (*update_writeback)(struct dc *dc,
 			const struct dc_stream_status *stream_status,
-			struct dc_writeback_info *wb_info);
+			struct dc_writeback_info *wb_info,
+			struct dc_state *context);
 	void (*enable_writeback)(struct dc *dc,
 			const struct dc_stream_status *stream_status,
-			struct dc_writeback_info *wb_info);
+			struct dc_writeback_info *wb_info,
+			struct dc_state *context);
 	void (*disable_writeback)(struct dc *dc,
 			unsigned int dwb_pipe_inst);
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
@@ -299,8 +299,8 @@
 	pflip_int_entry(1),
 	pflip_int_entry(2),
 	pflip_int_entry(3),
-	[DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(),
-	[DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(),
+	pflip_int_entry(4),
+	pflip_int_entry(5),
 	[DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
 	gpio_pad_int_entry(0),
 	gpio_pad_int_entry(1),
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
@@ -168,6 +168,11 @@
 	.ack = NULL
 };
 
+static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
 
@@ -222,12 +227,15 @@
 		.funcs = &pflip_irq_info_funcs\
 	}
 
-#define vupdate_int_entry(reg_num)\
+/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
+ * of DCE's DC_IRQ_SOURCE_VUPDATEx.
+ */
+#define vupdate_no_lock_int_entry(reg_num)\
 	[DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
 		IRQ_REG_ENTRY(OTG, reg_num,\
-			OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\
-			OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\
-		.funcs = &vblank_irq_info_funcs\
+			OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
+			OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
+		.funcs = &vupdate_no_lock_irq_info_funcs\
 	}
 
 #define vblank_int_entry(reg_num)\
@@ -332,12 +340,12 @@
 	dc_underflow_int_entry(6),
 	[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
 	[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
-	vupdate_int_entry(0),
-	vupdate_int_entry(1),
-	vupdate_int_entry(2),
-	vupdate_int_entry(3),
-	vupdate_int_entry(4),
-	vupdate_int_entry(5),
+	vupdate_no_lock_int_entry(0),
+	vupdate_no_lock_int_entry(1),
+	vupdate_no_lock_int_entry(2),
+	vupdate_no_lock_int_entry(3),
+	vupdate_no_lock_int_entry(4),
+	vupdate_no_lock_int_entry(5),
 	vblank_int_entry(0),
 	vblank_int_entry(1),
 	vblank_int_entry(2),
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/irq_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/irq_types.h
@@ -163,7 +163,7 @@
 };
 
 #define DAL_VALID_IRQ_SRC_NUM(src) \
-	((src) <= DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)
+	((src) < DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)
 
 /* Number of Page Flip IRQ Sources. */
 #define DAL_PFLIP_IRQ_SRC_NUM \
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/dc/os_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -57,7 +57,7 @@
  * general debug capabilities
  *
  */
-#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB)
+#if defined(CONFIG_DEBUG_KERNEL_DC) && (defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB))
 #define ASSERT_CRITICAL(expr) do {	\
 	if (WARN_ON(!(expr))) { \
 		kgdb_breakpoint(); \
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/include/ddc_service_types.h
@@ -31,6 +31,8 @@
 #define DP_BRANCH_DEVICE_ID_0022B9 0x0022B9
 #define DP_BRANCH_DEVICE_ID_00001A 0x00001A
 #define DP_BRANCH_DEVICE_ID_0080E1 0x0080e1
+#define DP_BRANCH_DEVICE_ID_90CC24 0x90CC24
+#define DP_BRANCH_DEVICE_ID_00E04C 0x00E04C
 
 enum ddc_result {
 	DDC_RESULT_UNKNOWN = 0,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/include/fixed31_32.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/include/fixed31_32.h
@@ -431,6 +431,9 @@
  */
 static inline struct fixed31_32 dc_fixpt_pow(struct fixed31_32 arg1, struct fixed31_32 arg2)
 {
+	if (arg1.value == 0)
+		return arg2.value == 0 ? dc_fixpt_one : dc_fixpt_zero;
+
 	return dc_fixpt_exp(
 		dc_fixpt_mul(
 			dc_fixpt_log(arg1),
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/include/gpio_service_interface.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/include/gpio_service_interface.h
@@ -42,8 +42,8 @@
 	struct gpio **ptr);
 
 struct gpio_service *dal_gpio_service_create(
-	enum dce_version dce_version_major,
-	enum dce_version dce_version_minor,
+	enum dce_version dce_version,
+	enum dce_environment dce_environment,
 	struct dc_context *ctx);
 
 struct gpio *dal_gpio_service_create_irq(
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -799,7 +799,7 @@
 	pow_buffer_ptr = -1; // reset back to no optimize
 	ret = true;
 release:
-	kfree(coeff);
+	kvfree(coeff);
 	return ret;
 }
 
@@ -1486,6 +1486,7 @@
 	struct fixed31_32 lut2;
 	struct fixed31_32 delta_lut;
 	struct fixed31_32 delta_index;
+	const struct fixed31_32 one = dc_fixpt_from_int(1);
 
 	i = 0;
 	/* fixed_pt library has problems handling too small values */
@@ -1514,6 +1515,9 @@
 			} else
 				hw_x = coordinates_x[i].x;
 
+			if (dc_fixpt_le(one, hw_x))
+				hw_x = one;
+
 			norm_x = dc_fixpt_mul(norm_factor, hw_x);
 			index = dc_fixpt_floor(norm_x);
 			if (index < 0 || index > 255)
@@ -1576,7 +1580,7 @@
 	struct pwl_float_data_ex *rgb = rgb_regamma;
 	const struct hw_x_point *coord_x = coordinates_x;
 
-	build_coefficients(&coeff, true);
+	build_coefficients(&coeff, TRANSFER_FUNCTION_SRGB);
 
 	i = 0;
 	while (i != hw_points_num + 1) {
@@ -1862,7 +1866,7 @@
 
 	kfree(rgb_regamma);
 rgb_regamma_alloc_fail:
-	kvfree(rgb_user);
+	kfree(rgb_user);
 rgb_user_alloc_fail:
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -37,8 +37,8 @@
 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65)
 /* Number of elements in the render times cache array */
 #define RENDER_TIMES_MAX_COUNT 10
-/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
-#define BTR_EXIT_MARGIN 2000
+/* Threshold to exit/exit BTR (to avoid frequent enter-exits at the lower limit) */
+#define BTR_MAX_MARGIN 2500
 /* Threshold to change BTR multiplier (to avoid frequent changes) */
 #define BTR_DRIFT_MARGIN 2000
 /*Threshold to exit fixed refresh rate*/
@@ -250,24 +250,22 @@
 	unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF;
 	unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF;
 	unsigned int frames_to_insert = 0;
-	unsigned int min_frame_duration_in_ns = 0;
-	unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
 	unsigned int delta_from_mid_point_delta_in_us;
-
-	min_frame_duration_in_ns = ((unsigned int) (div64_u64(
-		(1000000000ULL * 1000000),
-		in_out_vrr->max_refresh_in_uhz)));
+	unsigned int max_render_time_in_us =
+			in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us;
 
 	/* Program BTR */
-	if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
+	if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) {
 		/* Exit Below the Range */
 		if (in_out_vrr->btr.btr_active) {
 			in_out_vrr->btr.frame_counter = 0;
 			in_out_vrr->btr.btr_active = false;
 		}
-	} else if (last_render_time_in_us > max_render_time_in_us) {
+	} else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) {
 		/* Enter Below the Range */
-		in_out_vrr->btr.btr_active = true;
+		if (!in_out_vrr->btr.btr_active) {
+			in_out_vrr->btr.btr_active = true;
+		}
 	}
 
 	/* BTR set to "not active" so disengage */
@@ -322,24 +320,50 @@
 
 		/* Choose number of frames to insert based on how close it
 		 * can get to the mid point of the variable range.
+		 *  - Delta for CEIL: delta_from_mid_point_in_us_1
+		 *  - Delta for FLOOR: delta_from_mid_point_in_us_2
 		 */
-		if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
+		if (mid_point_frames_ceil &&
+		    (last_render_time_in_us / mid_point_frames_ceil) <
+		    in_out_vrr->min_duration_in_us) {
+			/* Check for out of range.
+			 * If using CEIL produces a value that is out of range,
+			 * then we are forced to use FLOOR.
+			 */
+			frames_to_insert = mid_point_frames_floor;
+		} else if (mid_point_frames_floor < 2) {
+			/* Check if FLOOR would result in non-LFC. In this case
+			 * choose to use CEIL
+			 */
+			frames_to_insert = mid_point_frames_ceil;
+		} else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
+			/* If choosing CEIL results in a frame duration that is
+			 * closer to the mid point of the range.
+			 * Choose CEIL
+			 */
 			frames_to_insert = mid_point_frames_ceil;
-			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
-					delta_from_mid_point_in_us_1;
 		} else {
+			/* If choosing FLOOR results in a frame duration that is
+			 * closer to the mid point of the range.
+			 * Choose FLOOR
+			 */
 			frames_to_insert = mid_point_frames_floor;
-			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
-					delta_from_mid_point_in_us_2;
 		}
 
 		/* Prefer current frame multiplier when BTR is enabled unless it drifts
 		 * too far from the midpoint
 		 */
+		if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
+			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
+					delta_from_mid_point_in_us_1;
+		} else {
+			delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
+					delta_from_mid_point_in_us_2;
+		}
 		if (in_out_vrr->btr.frames_to_insert != 0 &&
 				delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
 			if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
-					in_out_vrr->max_duration_in_us) &&
+					max_render_time_in_us) &&
 				((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) >
 					in_out_vrr->min_duration_in_us))
 				frames_to_insert = in_out_vrr->btr.frames_to_insert;
@@ -348,8 +372,9 @@
 		/* Either we've calculated the number of frames to insert,
 		 * or we need to insert min duration frames
 		 */
-		if (last_render_time_in_us / frames_to_insert <
-				in_out_vrr->min_duration_in_us){
+		if (frames_to_insert &&
+		    (last_render_time_in_us / frames_to_insert) <
+		    in_out_vrr->min_duration_in_us){
 			frames_to_insert -= (frames_to_insert > 1) ?
 					1 : 0;
 		}
@@ -743,6 +768,10 @@
 	nominal_field_rate_in_uhz =
 			mod_freesync_calc_nominal_field_rate(stream);
 
+	/* Rounded to the nearest Hz */
+	nominal_field_rate_in_uhz = 1000000ULL *
+			div_u64(nominal_field_rate_in_uhz + 500000, 1000000);
+
 	min_refresh_in_uhz = in_config->min_refresh_in_uhz;
 	max_refresh_in_uhz = in_config->max_refresh_in_uhz;
 
@@ -788,6 +817,11 @@
 		refresh_range = in_out_vrr->max_refresh_in_uhz -
 				in_out_vrr->min_refresh_in_uhz;
 
+		in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
+				2 * in_out_vrr->min_duration_in_us;
+		if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
+			in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
+
 		in_out_vrr->supported = true;
 	}
 
@@ -799,10 +833,12 @@
 			2 * in_out_vrr->min_refresh_in_uhz)
 		in_out_vrr->btr.btr_enabled = false;
 
+	in_out_vrr->fixed.fixed_active = false;
 	in_out_vrr->btr.btr_active = false;
 	in_out_vrr->btr.inserted_duration_in_us = 0;
 	in_out_vrr->btr.frames_to_insert = 0;
 	in_out_vrr->btr.frame_counter = 0;
+
 	in_out_vrr->btr.mid_point_in_us =
 				(in_out_vrr->min_duration_in_us +
 				 in_out_vrr->max_duration_in_us) / 2;
@@ -818,6 +854,7 @@
 		in_out_vrr->adjust.v_total_max = stream->timing.v_total;
 	} else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
 			refresh_range >= MIN_REFRESH_RANGE_IN_US) {
+
 		in_out_vrr->adjust.v_total_min =
 			calc_v_total_from_refresh(stream,
 				in_out_vrr->max_refresh_in_uhz);
@@ -996,14 +1033,13 @@
 			const struct dc_stream_state *stream)
 {
 	unsigned long long nominal_field_rate_in_uhz = 0;
+	unsigned int total = stream->timing.h_total * stream->timing.v_total;
 
-	/* Calculate nominal field rate for stream */
+	/* Calculate nominal field rate for stream, rounded up to nearest integer */
 	nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10;
 	nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
-	nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
-						stream->timing.h_total);
-	nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz,
-						stream->timing.v_total);
+
+	nominal_field_rate_in_uhz =	div_u64(nominal_field_rate_in_uhz, total);
 
 	return nominal_field_rate_in_uhz;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
@@ -92,6 +92,7 @@
 	uint32_t inserted_duration_in_us;
 	uint32_t frames_to_insert;
 	uint32_t frame_counter;
+	uint32_t margin_in_us;
 };
 
 struct mod_vrr_params_fixed_refresh {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -85,7 +85,8 @@
 //PB7 = MD0
 #define MASK_VTEM_MD0__VRR_EN         0x01
 #define MASK_VTEM_MD0__M_CONST        0x02
-#define MASK_VTEM_MD0__RESERVED2      0x0C
+#define MASK_VTEM_MD0__QMS_EN         0x04
+#define MASK_VTEM_MD0__RESERVED2      0x08
 #define MASK_VTEM_MD0__FVA_FACTOR_M1  0xF0
 
 //MD1
@@ -94,7 +95,7 @@
 //MD2
 #define MASK_VTEM_MD2__BASE_REFRESH_RATE_98  0x03
 #define MASK_VTEM_MD2__RB                    0x04
-#define MASK_VTEM_MD2__RESERVED3             0xF8
+#define MASK_VTEM_MD2__NEXT_TFR              0xF8
 
 //MD3
 #define MASK_VTEM_MD3__BASE_REFRESH_RATE_07  0xFF
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -115,7 +115,7 @@
 /* NOTE: iRAM is 256B in size */
 struct iram_table_v_2 {
 	/* flags                      */
-	uint16_t flags;							/* 0x00 U16  */
+	uint16_t min_abm_backlight;					/* 0x00 U16  */
 
 	/* parameters for ABM2.0 algorithm */
 	uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];		/* 0x02 U0.8 */
@@ -140,10 +140,10 @@
 
 	/* For reading PSR State directly from IRAM */
 	uint8_t psr_state;						/* 0xf0       */
-	uint8_t dmcu_mcp_interface_version;							/* 0xf1       */
-	uint8_t dmcu_abm_feature_version;							/* 0xf2       */
-	uint8_t dmcu_psr_feature_version;							/* 0xf3       */
-	uint16_t dmcu_version;										/* 0xf4       */
+	uint8_t dmcu_mcp_interface_version;				/* 0xf1       */
+	uint8_t dmcu_abm_feature_version;				/* 0xf2       */
+	uint8_t dmcu_psr_feature_version;				/* 0xf3       */
+	uint16_t dmcu_version;						/* 0xf4       */
 	uint8_t dmcu_state;						/* 0xf6       */
 
 	uint16_t blRampReduction;					/* 0xf7       */
@@ -164,42 +164,43 @@
 	uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];		/* 0x16 U0.8 */
 	uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];	/* 0x2a U2.6 */
 	uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL];		/* 0x3e U2.6 */
-	uint8_t hybrid_factor[NUM_AGGR_LEVEL];						/* 0x52 U0.8 */
-	uint8_t contrast_factor[NUM_AGGR_LEVEL];					/* 0x56 U0.8 */
-	uint8_t deviation_gain[NUM_AGGR_LEVEL];						/* 0x5a U0.8 */
-	uint8_t iir_curve[NUM_AMBI_LEVEL];							/* 0x5e U0.8 */
-	uint8_t min_knee[NUM_AGGR_LEVEL];							/* 0x63 U0.8 */
-	uint8_t max_knee[NUM_AGGR_LEVEL];							/* 0x67 U0.8 */
-	uint8_t pad[21];											/* 0x6b U0.8 */
+	uint8_t hybrid_factor[NUM_AGGR_LEVEL];				/* 0x52 U0.8 */
+	uint8_t contrast_factor[NUM_AGGR_LEVEL];			/* 0x56 U0.8 */
+	uint8_t deviation_gain[NUM_AGGR_LEVEL];				/* 0x5a U0.8 */
+	uint8_t iir_curve[NUM_AMBI_LEVEL];				/* 0x5e U0.8 */
+	uint8_t min_knee[NUM_AGGR_LEVEL];				/* 0x63 U0.8 */
+	uint8_t max_knee[NUM_AGGR_LEVEL];				/* 0x67 U0.8 */
+	uint16_t min_abm_backlight;					/* 0x6b U16  */
+	uint8_t pad[19];						/* 0x6d U0.8 */
 
 	/* parameters for crgb conversion */
-	uint16_t crgb_thresh[NUM_POWER_FN_SEGS];					/* 0x80 U3.13 */
-	uint16_t crgb_offset[NUM_POWER_FN_SEGS];					/* 0x90 U1.15 */
-	uint16_t crgb_slope[NUM_POWER_FN_SEGS];						/* 0xa0 U4.12 */
+	uint16_t crgb_thresh[NUM_POWER_FN_SEGS];			/* 0x80 U3.13 */
+	uint16_t crgb_offset[NUM_POWER_FN_SEGS];			/* 0x90 U1.15 */
+	uint16_t crgb_slope[NUM_POWER_FN_SEGS];				/* 0xa0 U4.12 */
 
 	/* parameters for custom curve */
 	/* thresholds for brightness --> backlight */
-	uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS];			/* 0xb0 U16.0 */
+	uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS];		/* 0xb0 U16.0 */
 	/* offsets for brightness --> backlight */
-	uint16_t backlight_offsets[NUM_BL_CURVE_SEGS];				/* 0xd0 U16.0 */
+	uint16_t backlight_offsets[NUM_BL_CURVE_SEGS];			/* 0xd0 U16.0 */
 
 	/* For reading PSR State directly from IRAM */
-	uint8_t psr_state;											/* 0xf0       */
-	uint8_t dmcu_mcp_interface_version;							/* 0xf1       */
-	uint8_t dmcu_abm_feature_version;							/* 0xf2       */
-	uint8_t dmcu_psr_feature_version;							/* 0xf3       */
-	uint16_t dmcu_version;										/* 0xf4       */
-	uint8_t dmcu_state;											/* 0xf6       */
-
-	uint8_t dummy1;												/* 0xf7       */
-	uint8_t dummy2;												/* 0xf8       */
-	uint8_t dummy3;												/* 0xf9       */
-	uint8_t dummy4;												/* 0xfa       */
-	uint8_t dummy5;												/* 0xfb       */
-	uint8_t dummy6;												/* 0xfc       */
-	uint8_t dummy7;												/* 0xfd       */
-	uint8_t dummy8;												/* 0xfe       */
-	uint8_t dummy9;												/* 0xff       */
+	uint8_t psr_state;						/* 0xf0       */
+	uint8_t dmcu_mcp_interface_version;				/* 0xf1       */
+	uint8_t dmcu_abm_feature_version;				/* 0xf2       */
+	uint8_t dmcu_psr_feature_version;				/* 0xf3       */
+	uint16_t dmcu_version;						/* 0xf4       */
+	uint8_t dmcu_state;						/* 0xf6       */
+
+	uint8_t dummy1;							/* 0xf7       */
+	uint8_t dummy2;							/* 0xf8       */
+	uint8_t dummy3;							/* 0xf9       */
+	uint8_t dummy4;							/* 0xfa       */
+	uint8_t dummy5;							/* 0xfb       */
+	uint8_t dummy6;							/* 0xfc       */
+	uint8_t dummy7;							/* 0xfd       */
+	uint8_t dummy8;							/* 0xfe       */
+	uint8_t dummy9;							/* 0xff       */
 };
 #pragma pack(pop)
 
@@ -271,7 +272,8 @@
 {
 	unsigned int set = params.set;
 
-	ram_table->flags = 0x0;
+	ram_table->min_abm_backlight =
+			cpu_to_be16(params.min_abm_backlight);
 	ram_table->deviation_gain = 0xb3;
 
 	ram_table->blRampReduction =
@@ -445,6 +447,9 @@
 
 	ram_table->flags = 0x0;
 
+	ram_table->min_abm_backlight =
+			cpu_to_be16(params.min_abm_backlight);
+
 	ram_table->deviation_gain[0] = 0xb3;
 	ram_table->deviation_gain[1] = 0xa8;
 	ram_table->deviation_gain[2] = 0x98;
@@ -588,6 +593,10 @@
 	unsigned int set = params.set;
 
 	ram_table->flags = 0x0;
+
+	ram_table->min_abm_backlight =
+			cpu_to_be16(params.min_abm_backlight);
+
 	for (i = 0; i < NUM_AGGR_LEVEL; i++) {
 		ram_table->hybrid_factor[i] = abm_settings[set][i].brightness_gain;
 		ram_table->contrast_factor[i] = abm_settings[set][i].contrast_factor;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
@@ -38,6 +38,7 @@
 	unsigned int backlight_lut_array_size;
 	unsigned int backlight_ramping_reduction;
 	unsigned int backlight_ramping_start;
+	unsigned int min_abm_backlight;
 	unsigned int set;
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h
@@ -7376,6 +7376,8 @@
 #define mmCRTC4_CRTC_DRR_CONTROL                                                                       0x0f3e
 #define mmCRTC4_CRTC_DRR_CONTROL_BASE_IDX                                                              2
 
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0                                                                  0x395d
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX                                                         2
 
 // addressBlock: dce_dc_fmt4_dispdec
 // base address: 0x2000
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/include/discovery.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/include/discovery.h
@@ -25,7 +25,6 @@
 #define _DISCOVERY_H_
 
 #define PSP_HEADER_SIZE                 256
-#define BINARY_MAX_SIZE                 (64 << 10)
 #define BINARY_SIGNATURE                0x28211407
 #define DISCOVERY_TABLE_SIGNATURE       0x53445049
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/include/navi10_enum.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/include/navi10_enum.h
@@ -430,7 +430,7 @@
  */
 
 typedef enum ENUM_NUM_SIMD_PER_CU {
-NUM_SIMD_PER_CU                          = 0x00000004,
+NUM_SIMD_PER_CU                          = 0x00000002,
 } ENUM_NUM_SIMD_PER_CU;
 
 /*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/include/pptable.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/include/pptable.h
@@ -78,7 +78,7 @@
 typedef struct _ATOM_PPLIB_STATE
 {
     UCHAR ucNonClockStateIndex;
-    UCHAR ucClockStateIndices[1]; // variable-sized
+    UCHAR ucClockStateIndices[]; // variable-sized
 } ATOM_PPLIB_STATE;
 
 
@@ -473,7 +473,7 @@
       /**
       * Driver will read the first ucNumDPMLevels in this array
       */
-      UCHAR clockInfoIndex[1];
+      UCHAR clockInfoIndex[];
 } ATOM_PPLIB_STATE_V2;
 
 typedef struct _StateArray{
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -320,12 +320,12 @@
 		if (*level & profile_mode_mask) {
 			hwmgr->saved_dpm_level = hwmgr->dpm_level;
 			hwmgr->en_umd_pstate = true;
-			amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
-						AMD_IP_BLOCK_TYPE_GFX,
-						AMD_CG_STATE_UNGATE);
 			amdgpu_device_ip_set_powergating_state(hwmgr->adev,
 					AMD_IP_BLOCK_TYPE_GFX,
 					AMD_PG_STATE_UNGATE);
+			amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
+						AMD_IP_BLOCK_TYPE_GFX,
+						AMD_CG_STATE_UNGATE);
 		}
 	} else {
 		/* exit umd pstate, restore level, enable gfx cg*/
@@ -1421,10 +1421,12 @@
 {
 	struct pp_hwmgr *hwmgr = handle;
 
+	*cap = false;
 	if (!hwmgr)
 		return -EINVAL;
 
-	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_capability)
+	if (!(hwmgr->not_vf && amdgpu_dpm) ||
+		!hwmgr->hwmgr_func->get_asic_baco_capability)
 		return 0;
 
 	mutex_lock(&hwmgr->smu_lock);
@@ -1458,7 +1460,8 @@
 	if (!hwmgr)
 		return -EINVAL;
 
-	if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_asic_baco_state)
+	if (!(hwmgr->not_vf && amdgpu_dpm) ||
+		!hwmgr->hwmgr_func->set_asic_baco_state)
 		return 0;
 
 	mutex_lock(&hwmgr->smu_lock);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
@@ -844,6 +844,7 @@
 	smu->smu_baco.platform_support = false;
 
 	mutex_init(&smu->sensor_lock);
+	mutex_init(&smu->metrics_lock);
 
 	smu->watermarks_bitmap = 0;
 	smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
@@ -1344,7 +1345,10 @@
 	int ret;
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 	struct smu_context *smu = &adev->smu;
-	bool baco_feature_is_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT);
+	bool baco_feature_is_enabled = false;
+
+	if(!(adev->flags & AMD_IS_APU))
+		baco_feature_is_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT);
 
 	ret = smu_system_features_control(smu, false);
 	if (ret)
@@ -1537,12 +1541,12 @@
 		if (*level & profile_mode_mask) {
 			smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level;
 			smu_dpm_ctx->enable_umd_pstate = true;
-			amdgpu_device_ip_set_clockgating_state(smu->adev,
-							       AMD_IP_BLOCK_TYPE_GFX,
-							       AMD_CG_STATE_UNGATE);
 			amdgpu_device_ip_set_powergating_state(smu->adev,
 							       AMD_IP_BLOCK_TYPE_GFX,
 							       AMD_PG_STATE_UNGATE);
+			amdgpu_device_ip_set_clockgating_state(smu->adev,
+							       AMD_IP_BLOCK_TYPE_GFX,
+							       AMD_CG_STATE_UNGATE);
 		}
 	} else {
 		/* exit umd pstate, restore level, enable gfx cg*/
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
@@ -910,18 +910,21 @@
 	struct smu_table_context *smu_table= &smu->smu_table;
 	int ret = 0;
 
+	mutex_lock(&smu->metrics_lock);
 	if (!smu_table->metrics_time ||
 	     time_after(jiffies, smu_table->metrics_time + HZ / 1000)) {
 		ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
 				(void *)smu_table->metrics_table, false);
 		if (ret) {
 			pr_info("Failed to export SMU metrics table!\n");
+			mutex_unlock(&smu->metrics_lock);
 			return ret;
 		}
 		smu_table->metrics_time = jiffies;
 	}
 
 	memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
+	mutex_unlock(&smu->metrics_lock);
 
 	return ret;
 }
@@ -1388,12 +1391,17 @@
 					"VR",
 					"COMPUTE",
 					"CUSTOM"};
+	static const char *title[] = {
+			"PROFILE_INDEX(NAME)"};
 	uint32_t i, size = 0;
 	int16_t workload_type = 0;
 
 	if (!smu->pm_enabled || !buf)
 		return -EINVAL;
 
+	size += sprintf(buf + size, "%16s\n",
+			title[0]);
+
 	for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
 		/*
 		 * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h
@@ -164,7 +164,7 @@
 typedef struct _ATOM_Tonga_State_Array {
 	UCHAR ucRevId;
 	UCHAR ucNumEntries;		/* Number of entries. */
-	ATOM_Tonga_State entries[1];	/* Dynamically allocate entries. */
+	ATOM_Tonga_State entries[];	/* Dynamically allocate entries. */
 } ATOM_Tonga_State_Array;
 
 typedef struct _ATOM_Tonga_MCLK_Dependency_Record {
@@ -179,7 +179,7 @@
 typedef struct _ATOM_Tonga_MCLK_Dependency_Table {
 	UCHAR ucRevId;
 	UCHAR ucNumEntries; 										/* Number of entries. */
-	ATOM_Tonga_MCLK_Dependency_Record entries[1];				/* Dynamically allocate entries. */
+	ATOM_Tonga_MCLK_Dependency_Record entries[];				/* Dynamically allocate entries. */
 } ATOM_Tonga_MCLK_Dependency_Table;
 
 typedef struct _ATOM_Tonga_SCLK_Dependency_Record {
@@ -194,7 +194,7 @@
 typedef struct _ATOM_Tonga_SCLK_Dependency_Table {
 	UCHAR ucRevId;
 	UCHAR ucNumEntries; 										/* Number of entries. */
-	ATOM_Tonga_SCLK_Dependency_Record entries[1];				 /* Dynamically allocate entries. */
+	ATOM_Tonga_SCLK_Dependency_Record entries[];				 /* Dynamically allocate entries. */
 } ATOM_Tonga_SCLK_Dependency_Table;
 
 typedef struct _ATOM_Polaris_SCLK_Dependency_Record {
@@ -210,7 +210,7 @@
 typedef struct _ATOM_Polaris_SCLK_Dependency_Table {
 	UCHAR ucRevId;
 	UCHAR ucNumEntries;							/* Number of entries. */
-	ATOM_Polaris_SCLK_Dependency_Record entries[1];				 /* Dynamically allocate entries. */
+	ATOM_Polaris_SCLK_Dependency_Record entries[];				 /* Dynamically allocate entries. */
 } ATOM_Polaris_SCLK_Dependency_Table;
 
 typedef struct _ATOM_Tonga_PCIE_Record {
@@ -222,7 +222,7 @@
 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_Record entries[];							/* Dynamically allocate entries. */
 } ATOM_Tonga_PCIE_Table;
 
 typedef struct _ATOM_Polaris10_PCIE_Record {
@@ -235,7 +235,7 @@
 typedef struct _ATOM_Polaris10_PCIE_Table {
 	UCHAR ucRevId;
 	UCHAR ucNumEntries;                                         /* Number of entries. */
-	ATOM_Polaris10_PCIE_Record entries[1];                      /* Dynamically allocate entries. */
+	ATOM_Polaris10_PCIE_Record entries[];                      /* Dynamically allocate entries. */
 } ATOM_Polaris10_PCIE_Table;
 
 
@@ -252,7 +252,7 @@
 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_Record entries[]; 			   /* Dynamically allocate entries. */
 } ATOM_Tonga_MM_Dependency_Table;
 
 typedef struct _ATOM_Tonga_Voltage_Lookup_Record {
@@ -265,7 +265,7 @@
 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_Record entries[];				/* Dynamically allocate entries. */
 } ATOM_Tonga_Voltage_Lookup_Table;
 
 typedef struct _ATOM_Tonga_Fan_Table {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
@@ -984,6 +984,32 @@
 			struct pp_hwmgr *hwmgr,
 			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 {
+	hwmgr->thermal_controller.ucType =
+			powerplay_table->sThermalController.ucType;
+	hwmgr->thermal_controller.ucI2cLine =
+			powerplay_table->sThermalController.ucI2cLine;
+	hwmgr->thermal_controller.ucI2cAddress =
+			powerplay_table->sThermalController.ucI2cAddress;
+
+	hwmgr->thermal_controller.fanInfo.bNoFan =
+		(0 != (powerplay_table->sThermalController.ucFanParameters &
+			ATOM_PP_FANPARAMETERS_NOFAN));
+
+	hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
+		powerplay_table->sThermalController.ucFanParameters &
+		ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+
+	hwmgr->thermal_controller.fanInfo.ulMinRPM
+		= powerplay_table->sThermalController.ucFanMinRPM * 100UL;
+	hwmgr->thermal_controller.fanInfo.ulMaxRPM
+		= powerplay_table->sThermalController.ucFanMaxRPM * 100UL;
+
+	set_hw_cap(hwmgr,
+		   ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
+		   PHM_PlatformCaps_ThermalController);
+
+	hwmgr->thermal_controller.use_hw_fan_control = 1;
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
@@ -209,8 +209,7 @@
 {
 	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-	if (smu10_data->need_min_deep_sleep_dcefclk &&
-		smu10_data->deep_sleep_dcefclk != clock) {
+	if (clock && smu10_data->deep_sleep_dcefclk != clock) {
 		smu10_data->deep_sleep_dcefclk = clock;
 		smum_send_msg_to_smc_with_parameter(hwmgr,
 					PPSMC_MSG_SetMinDeepSleepDcefclk,
@@ -223,8 +222,7 @@
 {
 	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-	if (smu10_data->dcf_actual_hard_min_freq &&
-		smu10_data->dcf_actual_hard_min_freq != clock) {
+	if (clock && smu10_data->dcf_actual_hard_min_freq != clock) {
 		smu10_data->dcf_actual_hard_min_freq = clock;
 		smum_send_msg_to_smc_with_parameter(hwmgr,
 					PPSMC_MSG_SetHardMinDcefclkByFreq,
@@ -237,8 +235,7 @@
 {
 	struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-	if (smu10_data->f_actual_hard_min_freq &&
-		smu10_data->f_actual_hard_min_freq != clock) {
+	if (clock && smu10_data->f_actual_hard_min_freq != clock) {
 		smu10_data->f_actual_hard_min_freq = clock;
 		smum_send_msg_to_smc_with_parameter(hwmgr,
 					PPSMC_MSG_SetHardMinFclkByFreq,
@@ -1026,12 +1023,15 @@
 
 	clocks->num_levels = 0;
 	for (i = 0; i < pclk_vol_table->count; i++) {
-		clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10;
-		clocks->data[i].latency_in_us = latency_required ?
-						smu10_get_mem_latency(hwmgr,
-						pclk_vol_table->entries[i].clk) :
-						0;
-		clocks->num_levels++;
+		if (pclk_vol_table->entries[i].clk) {
+			clocks->data[clocks->num_levels].clocks_in_khz =
+				pclk_vol_table->entries[i].clk * 10;
+			clocks->data[clocks->num_levels].latency_in_us = latency_required ?
+				smu10_get_mem_latency(hwmgr,
+						      pclk_vol_table->entries[i].clk) :
+				0;
+			clocks->num_levels++;
+		}
 	}
 
 	return 0;
@@ -1077,9 +1077,11 @@
 
 	clocks->num_levels = 0;
 	for (i = 0; i < pclk_vol_table->count; i++) {
-		clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk  * 10;
-		clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol;
-		clocks->num_levels++;
+		if (pclk_vol_table->entries[i].clk) {
+			clocks->data[clocks->num_levels].clocks_in_khz = pclk_vol_table->entries[i].clk  * 10;
+			clocks->data[clocks->num_levels].voltage_in_mv = pclk_vol_table->entries[i].vol;
+			clocks->num_levels++;
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
@@ -1533,6 +1533,10 @@
 	PP_ASSERT_WITH_CODE((tmp_result == 0),
 			"Failed to reset to default!", result = tmp_result);
 
+	tmp_result = smum_stop_smc(hwmgr);
+	PP_ASSERT_WITH_CODE((tmp_result == 0),
+			"Failed to stop smc!", result = tmp_result);
+
 	tmp_result = smu7_force_switch_to_arbf0(hwmgr);
 	PP_ASSERT_WITH_CODE((tmp_result == 0),
 			"Failed to force to switch arbf0!", result = tmp_result);
@@ -2864,7 +2868,7 @@
 		if (hwmgr->is_kicker)
 			switch_limit_us = data->is_memory_gddr5 ? 450 : 150;
 		else
-			switch_limit_us = data->is_memory_gddr5 ? 190 : 150;
+			switch_limit_us = data->is_memory_gddr5 ? 200 : 150;
 		break;
 	case CHIP_VEGAM:
 		switch_limit_us = 30;
@@ -3575,7 +3579,8 @@
 	case AMDGPU_PP_SENSOR_GPU_POWER:
 		return smu7_get_gpu_power(hwmgr, (uint32_t *)value);
 	case AMDGPU_PP_SENSOR_VDDGFX:
-		if ((data->vr_config & 0xff) == 0x2)
+		if ((data->vr_config & VRCONF_VDDGFX_MASK) ==
+		    (VR_SVI2_PLANE_2 << VRCONF_VDDGFX_SHIFT))
 			val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device,
 					CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE2_VID);
 		else
@@ -3805,9 +3810,12 @@
 {
 	uint32_t i;
 
+	/* force the trim if mclk_switching is disabled to prevent flicker */
+	bool force_trim = (low_limit == high_limit);
 	for (i = 0; i < dpm_table->count; i++) {
 	/*skip the trim if od is enabled*/
-		if (!hwmgr->od_enabled && (dpm_table->dpm_levels[i].value < low_limit
+		if ((!hwmgr->od_enabled || force_trim)
+			&& (dpm_table->dpm_levels[i].value < low_limit
 			|| dpm_table->dpm_levels[i].value > high_limit))
 			dpm_table->dpm_levels[i].enabled = false;
 		else
@@ -3983,6 +3991,13 @@
 			"Failed to populate and upload SCLK MCLK DPM levels!",
 			result = tmp_result);
 
+	/*
+	 * If a custom pp table is loaded, set DPMTABLE_OD_UPDATE_VDDC flag.
+	 * That effectively disables AVFS feature.
+	 */
+	if (hwmgr->hardcode_pp_table != NULL)
+		data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC;
+
 	tmp_result = smu7_update_avfs(hwmgr);
 	PP_ASSERT_WITH_CODE((0 == tmp_result),
 			"Failed to update avfs voltages!",
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
@@ -3691,6 +3691,13 @@
 	PP_ASSERT_WITH_CODE(!result,
 			"Failed to upload PPtable!", return result);
 
+	/*
+	 * If a custom pp table is loaded, set DPMTABLE_OD_UPDATE_VDDC flag.
+	 * That effectively disables AVFS feature.
+	 */
+	if(hwmgr->hardcode_pp_table != NULL)
+		data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC;
+
 	vega10_update_avfs(hwmgr);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
@@ -364,17 +364,29 @@
 static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 		struct PP_TemperatureRange *range)
 {
+	struct phm_ppt_v2_information *pp_table_info =
+		(struct phm_ppt_v2_information *)(hwmgr->pptable);
+	struct phm_tdp_table *tdp_table = pp_table_info->tdp_table;
 	struct amdgpu_device *adev = hwmgr->adev;
-	int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-	int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP;
+	int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP;
 	uint32_t val;
 
-	if (low < range->min)
-		low = range->min;
-	if (high > range->max)
-		high = range->max;
+	/* compare them in unit celsius degree */
+	if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+		low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+	/*
+	 * As a common sense, usSoftwareShutdownTemp should be bigger
+	 * than ThotspotLimit. For any invalid usSoftwareShutdownTemp,
+	 * we will just use the max possible setting VEGA10_THERMAL_MAXIMUM_ALERT_TEMP
+	 * to avoid false alarms.
+	 */
+	if ((tdp_table->usSoftwareShutdownTemp >
+	     range->hotspot_crit_max / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)) {
+		if (high > tdp_table->usSoftwareShutdownTemp)
+			high = tdp_table->usSoftwareShutdownTemp;
+	}
 
 	if (low > high)
 		return -EINVAL;
@@ -383,8 +395,8 @@
 
 	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
 	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
 	val &= (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK) &
 			(~THM_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK) &
 			(~THM_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c
@@ -170,17 +170,18 @@
 static int vega12_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 		struct PP_TemperatureRange *range)
 {
+	struct phm_ppt_v3_information *pptable_information =
+		(struct phm_ppt_v3_information *)hwmgr->pptable;
 	struct amdgpu_device *adev = hwmgr->adev;
-	int low = VEGA12_THERMAL_MINIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-	int high = VEGA12_THERMAL_MAXIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	int low = VEGA12_THERMAL_MINIMUM_ALERT_TEMP;
+	int high = VEGA12_THERMAL_MAXIMUM_ALERT_TEMP;
 	uint32_t val;
 
-	if (low < range->min)
-		low = range->min;
-	if (high > range->max)
-		high = range->max;
+	/* compare them in unit celsius degree */
+	if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+		low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	if (high > pptable_information->us_software_shutdown_temp)
+		high = pptable_information->us_software_shutdown_temp;
 
 	if (low > high)
 		return -EINVAL;
@@ -189,8 +190,8 @@
 
 	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
 	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+	val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
 	val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
 
 	WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c
@@ -29,7 +29,7 @@
 #include "vega20_baco.h"
 #include "vega20_smumgr.h"
 
-
+#include "amdgpu_ras.h"
 
 static const struct soc15_baco_cmd_entry clean_baco_tbl[] =
 {
@@ -74,6 +74,7 @@
 int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+	struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
 	enum BACO_STATE cur_state;
 	uint32_t data;
 
@@ -84,10 +85,11 @@
 		return 0;
 
 	if (state == BACO_STATE_IN) {
-		data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL);
-		data |= 0x80000000;
-		WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data);
-
+		if (!ras || !ras->supported) {
+			data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL);
+			data |= 0x80000000;
+			WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data);
+		}
 
 		if(smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnterBaco, 0))
 			return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
@@ -981,27 +981,15 @@
 {
 	struct vega20_hwmgr *data =
 			(struct vega20_hwmgr *)(hwmgr->backend);
-	uint64_t features_enabled;
-	int i;
-	bool enabled;
-	int ret = 0;
+	int i, ret = 0;
 
 	PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
 			PPSMC_MSG_DisableAllSmuFeatures)) == 0,
 			"[DisableAllSMUFeatures] Failed to disable all smu features!",
 			return ret);
 
-	ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
-	PP_ASSERT_WITH_CODE(!ret,
-			"[DisableAllSMUFeatures] Failed to get enabled smc features!",
-			return ret);
-
-	for (i = 0; i < GNLD_FEATURES_MAX; i++) {
-		enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
-			true : false;
-		data->smu_features[i].enabled = enabled;
-		data->smu_features[i].supported = enabled;
-	}
+	for (i = 0; i < GNLD_FEATURES_MAX; i++)
+		data->smu_features[i].enabled = 0;
 
 	return 0;
 }
@@ -1652,12 +1640,6 @@
 
 	data->uvd_power_gated = true;
 	data->vce_power_gated = true;
-
-	if (data->smu_features[GNLD_DPM_UVD].enabled)
-		data->uvd_power_gated = false;
-
-	if (data->smu_features[GNLD_DPM_VCE].enabled)
-		data->vce_power_gated = false;
 }
 
 static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
@@ -2912,7 +2894,8 @@
 			data->od8_settings.od8_settings_array;
 	OverDriveTable_t *od_table =
 			&(data->smc_state_table.overdrive_table);
-	int32_t input_index, input_clk, input_vol, i;
+	int32_t input_clk, input_vol, i;
+	uint32_t input_index;
 	int od8_id;
 	int ret;
 
@@ -3211,10 +3194,11 @@
 
 static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
 {
-	uint64_t features_enabled;
-	uint64_t features_to_enable;
-	uint64_t features_to_disable;
-	int ret = 0;
+	struct vega20_hwmgr *data =
+			(struct vega20_hwmgr *)(hwmgr->backend);
+	uint64_t features_enabled, features_to_enable, features_to_disable;
+	int i, ret = 0;
+	bool enabled;
 
 	if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
 		return -EINVAL;
@@ -3243,6 +3227,17 @@
 			return ret;
 	}
 
+	/* Update the cached feature enablement state */
+	ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+		enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
+			true : false;
+		data->smu_features[i].enabled = enabled;
+	}
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c
@@ -240,17 +240,18 @@
 static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 		struct PP_TemperatureRange *range)
 {
+	struct phm_ppt_v3_information *pptable_information =
+		(struct phm_ppt_v3_information *)hwmgr->pptable;
 	struct amdgpu_device *adev = hwmgr->adev;
-	int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-	int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP *
-			PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP;
+	int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP;
 	uint32_t val;
 
-	if (low < range->min)
-		low = range->min;
-	if (high > range->max)
-		high = range->max;
+	/* compare them in unit celsius degree */
+	if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+		low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+	if (high > pptable_information->us_software_shutdown_temp)
+		high = pptable_information->us_software_shutdown_temp;
 
 	if (low > high)
 		return -EINVAL;
@@ -259,8 +260,8 @@
 
 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
 	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+	val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
 	val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
 
 	WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
@@ -345,6 +345,7 @@
 	const struct pptable_funcs	*ppt_funcs;
 	struct mutex			mutex;
 	struct mutex			sensor_lock;
+	struct mutex			metrics_lock;
 	uint64_t pool_size;
 
 	struct smu_table_context	smu_table;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -229,6 +229,7 @@
 	bool (*is_hw_avfs_present)(struct pp_hwmgr  *hwmgr);
 	int (*update_dpm_settings)(struct pp_hwmgr *hwmgr, void *profile_setting);
 	int (*smc_table_manager)(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw); /*rw: true for read, false for write */
+	int (*stop_smc)(struct pp_hwmgr *hwmgr);
 };
 
 struct pp_hwmgr_func {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/inc/smumgr.h
@@ -114,4 +114,6 @@
 
 extern int smum_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw);
 
+extern int smum_stop_smc(struct pp_hwmgr *hwmgr);
+
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
@@ -547,17 +547,20 @@
 	struct smu_table_context *smu_table= &smu->smu_table;
 	int ret = 0;
 
+	mutex_lock(&smu->metrics_lock);
 	if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) {
 		ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
 				(void *)smu_table->metrics_table, false);
 		if (ret) {
 			pr_info("Failed to export SMU metrics table!\n");
+			mutex_unlock(&smu->metrics_lock);
 			return ret;
 		}
 		smu_table->metrics_time = jiffies;
 	}
 
 	memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
+	mutex_unlock(&smu->metrics_lock);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/renoir_ppt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/renoir_ppt.c
@@ -183,11 +183,14 @@
 	int i, size = 0, ret = 0;
 	uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
 	DpmClocks_t *clk_table = smu->smu_table.clocks_table;
-	SmuMetrics_t metrics = {0};
+	SmuMetrics_t metrics;
+	bool cur_value_match_level = false;
 
 	if (!clk_table || clk_type >= SMU_CLK_COUNT)
 		return -EINVAL;
 
+	memset(&metrics, 0, sizeof(metrics));
+
 	ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
 			       (void *)&metrics, false);
 	if (ret)
@@ -241,8 +244,13 @@
 		GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
 		size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
 				cur_value == value ? "*" : "");
+		if (cur_value == value)
+			cur_value_match_level = true;
 	}
 
+	if (!cur_value_match_level)
+		size += sprintf(buf + size, "   %uMhz *\n", cur_value);
+
 	return size;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/renoir_ppt.h
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/renoir_ppt.h
@@ -37,7 +37,7 @@
 			freq = table->SocClocks[dpm_level].Freq;	\
 			break;						\
 		case SMU_MCLK:						\
-			freq = table->MemClocks[dpm_level].Freq;	\
+			freq = table->FClocks[dpm_level].Freq;	\
 			break;						\
 		case SMU_DCEFCLK:					\
 			freq = table->DcfClocks[dpm_level].Freq;	\
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
@@ -46,10 +46,8 @@
 #include "asic_reg/smuio/smuio_11_0_0_sh_mask.h"
 
 MODULE_FIRMWARE("amdgpu/vega20_smc.bin");
-MODULE_FIRMWARE("amdgpu/arcturus_smc.bin");
 MODULE_FIRMWARE("amdgpu/navi10_smc.bin");
 MODULE_FIRMWARE("amdgpu/navi14_smc.bin");
-MODULE_FIRMWARE("amdgpu/navi12_smc.bin");
 
 #define SMU11_VOLTAGE_SCALE 4
 
@@ -171,7 +169,8 @@
 		chip_name = "navi12";
 		break;
 	default:
-		BUG();
+		dev_err(adev->dev, "Unsupported ASIC type %d\n", adev->asic_type);
+		return -EINVAL;
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name);
@@ -988,8 +987,12 @@
 	struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks;
 	int ret = 0;
 
-	max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
+	if (!smu->smu_table.max_sustainable_clocks)
+		max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
 					 GFP_KERNEL);
+	else
+		max_sustainable_clocks = smu->smu_table.max_sustainable_clocks;
+
 	smu->smu_table.max_sustainable_clocks = (void *)max_sustainable_clocks;
 
 	max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
@@ -239,7 +239,7 @@
 
 	switch (dev_id) {
 	case 0x67BA:
-	case 0x66B1:
+	case 0x67B1:
 		smu_data->power_tune_defaults = &defaults_hawaii_pro;
 		break;
 	case 0x67B8:
@@ -2933,6 +2933,29 @@
 	return 0;
 }
 
+static void ci_reset_smc(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				  SMC_SYSCON_RESET_CNTL,
+				  rst_reg, 1);
+}
+
+
+static void ci_stop_smc_clock(struct pp_hwmgr *hwmgr)
+{
+	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+				  SMC_SYSCON_CLOCK_CNTL_0,
+				  ck_disable, 1);
+}
+
+static int ci_stop_smc(struct pp_hwmgr *hwmgr)
+{
+	ci_reset_smc(hwmgr);
+	ci_stop_smc_clock(hwmgr);
+
+	return 0;
+}
+
 const struct pp_smumgr_func ci_smu_funcs = {
 	.name = "ci_smu",
 	.smu_init = ci_smu_init,
@@ -2957,4 +2980,5 @@
 	.is_dpm_running = ci_is_dpm_running,
 	.update_dpm_settings = ci_update_dpm_settings,
 	.update_smc_table = ci_update_smc_table,
+	.stop_smc = ci_stop_smc,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
@@ -217,3 +217,11 @@
 
 	return -EINVAL;
 }
+
+int smum_stop_smc(struct pp_hwmgr *hwmgr)
+{
+	if (hwmgr->smumgr_funcs->stop_smc)
+		return hwmgr->smumgr_funcs->stop_smc(hwmgr);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
@@ -642,9 +642,6 @@
 
 	/* sclk is bigger than max sclk in the dependence table */
 	*voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT;
-	vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
-			(dep_table->entries[i - 1].vddc -
-					(uint16_t)VDDC_VDDCI_DELTA));
 
 	if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control)
 		*voltage |= (data->vbios_boot_state.vddci_bootup_value *
@@ -652,8 +649,13 @@
 	else if (dep_table->entries[i - 1].vddci)
 		*voltage |= (dep_table->entries[i - 1].vddci *
 				VOLTAGE_SCALE) << VDDC_SHIFT;
-	else
+	else {
+		vddci = phm_find_closest_vddci(&(data->vddci_voltage_table),
+				(dep_table->entries[i - 1].vddc -
+						(uint16_t)VDDC_VDDCI_DELTA));
+
 		*voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT;
+	}
 
 	if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control)
 		*mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
@@ -1691,17 +1691,20 @@
 	struct smu_table_context *smu_table= &smu->smu_table;
 	int ret = 0;
 
+	mutex_lock(&smu->metrics_lock);
 	if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + HZ / 1000)) {
 		ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
 				(void *)smu_table->metrics_table, false);
 		if (ret) {
 			pr_info("Failed to export SMU metrics table!\n");
+			mutex_unlock(&smu->metrics_lock);
 			return ret;
 		}
 		smu_table->metrics_time = jiffies;
 	}
 
 	memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
+	mutex_unlock(&smu->metrics_lock);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -250,6 +250,7 @@
 {
 	komeda_crtc_prepare(to_kcrtc(crtc));
 	drm_crtc_vblank_on(crtc);
+	WARN_ON(drm_crtc_vblank_get(crtc));
 	komeda_crtc_do_flush(crtc, old);
 }
 
@@ -319,6 +320,7 @@
 		}
 	}
 
+	drm_crtc_vblank_put(crtc);
 	drm_crtc_vblank_off(crtc);
 	komeda_crtc_unprepare(kcrtc);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -1171,7 +1171,7 @@
 	return 0;
 }
 
-static void
+static int
 komeda_pipeline_unbound_components(struct komeda_pipeline *pipe,
 				   struct komeda_pipeline_state *new)
 {
@@ -1190,8 +1190,12 @@
 		c = komeda_pipeline_get_component(pipe, id);
 		c_st = komeda_component_get_state_and_set_user(c,
 				drm_st, NULL, new->crtc);
+		if (PTR_ERR(c_st) == -EDEADLK)
+			return -EDEADLK;
 		WARN_ON(IS_ERR(c_st));
 	}
+
+	return 0;
 }
 
 /* release unclaimed pipeline resource */
@@ -1213,9 +1217,8 @@
 	if (WARN_ON(IS_ERR_OR_NULL(st)))
 		return -EINVAL;
 
-	komeda_pipeline_unbound_components(pipe, st);
+	return komeda_pipeline_unbound_components(pipe, st);
 
-	return 0;
 }
 
 void komeda_pipeline_disable(struct komeda_pipeline *pipe,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -264,6 +264,10 @@
 
 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
 					       layer->layer_type, &n_formats);
+	if (!formats) {
+		kfree(kplane);
+		return -ENOMEM;
+	}
 
 	err = drm_universal_plane_init(&kms->base, plane,
 			get_possible_crtcs(kms, c->pipeline),
@@ -274,8 +278,10 @@
 
 	komeda_put_fourcc_list(formats);
 
-	if (err)
-		goto cleanup;
+	if (err) {
+		kfree(kplane);
+		return err;
+	}
 
 	drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/malidp_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/malidp_crtc.c
@@ -483,7 +483,10 @@
 	if (crtc->state)
 		malidp_crtc_destroy_state(crtc, crtc->state);
 
-	__drm_atomic_helper_crtc_reset(crtc, &state->base);
+	if (state)
+		__drm_atomic_helper_crtc_reset(crtc, &state->base);
+	else
+		__drm_atomic_helper_crtc_reset(crtc, NULL);
 }
 
 static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/malidp_mw.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/malidp_mw.c
@@ -56,7 +56,7 @@
 	return MODE_OK;
 }
 
-const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = {
 	.get_modes = malidp_mw_connector_get_modes,
 	.mode_valid = malidp_mw_connector_mode_valid,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/arm/malidp_planes.c
+++ linux-ein-5.4.0/drivers/gpu/drm/arm/malidp_planes.c
@@ -348,7 +348,7 @@
 		else
 			sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
 
-		if (!sgt)
+		if (IS_ERR(sgt))
 			return false;
 
 		sgl = sgt->sgl;
@@ -922,13 +922,18 @@
 	.atomic_disable = malidp_de_plane_disable,
 };
 
+static const uint64_t linear_only_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
 int malidp_de_planes_init(struct drm_device *drm)
 {
 	struct malidp_drm *malidp = drm->dev_private;
 	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
 	struct malidp_plane *plane = NULL;
 	enum drm_plane_type plane_type;
-	unsigned long crtcs = 1 << drm->mode_config.num_crtc;
+	unsigned long crtcs = BIT(drm->mode_config.num_crtc);
 	unsigned long flags = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
 			      DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
 	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
@@ -985,8 +990,8 @@
 		 */
 		ret = drm_universal_plane_init(drm, &plane->base, crtcs,
 				&malidp_de_plane_funcs, formats, n,
-				(id == DE_SMART) ? NULL : modifiers, plane_type,
-				NULL);
+				(id == DE_SMART) ? linear_only_modifiers : modifiers,
+				plane_type, NULL);
 
 		if (ret < 0)
 			goto cleanup;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/armada/armada_overlay.c
+++ linux-ein-5.4.0/drivers/gpu/drm/armada/armada_overlay.c
@@ -4,6 +4,8 @@
  *  Rewritten from the dovefb driver, and Armada510 manuals.
  */
 
+#include <linux/bitfield.h>
+
 #include <drm/armada_drm.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -446,8 +448,8 @@
 			     drm_to_overlay_state(state)->colorkey_ug,
 			     drm_to_overlay_state(state)->colorkey_vb, 0);
 	} else if (property == priv->colorkey_mode_prop) {
-		*val = (drm_to_overlay_state(state)->colorkey_mode &
-			CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK);
+		*val = FIELD_GET(CFG_CKMODE_MASK,
+				 drm_to_overlay_state(state)->colorkey_mode);
 	} else if (property == priv->brightness_prop) {
 		*val = drm_to_overlay_state(state)->brightness + 256;
 	} else if (property == priv->contrast_prop) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/aspeed/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/aspeed/Kconfig
@@ -3,6 +3,7 @@
 	tristate "ASPEED BMC Display Controller"
 	depends on DRM && OF
 	depends on (COMPILE_TEST || ARCH_ASPEED)
+	depends on MMU
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DMA_CMA if HAVE_DMA_CONTIGUOUS
--- linux-ein-5.4.0.orig/drivers/gpu/drm/ast/ast_post.c
+++ linux-ein-5.4.0/drivers/gpu/drm/ast/ast_post.c
@@ -294,7 +294,7 @@
 				;
 			} while (ast_read32(ast, 0x10100) != 0xa8);
 		} else {/* AST2100/1100 */
-			if (ast->chip == AST2100 || ast->chip == 2200)
+			if (ast->chip == AST2100 || ast->chip == AST2200)
 				dram_reg_info = ast2100_dram_table_data;
 			else
 				dram_reg_info = ast1100_dram_table_data;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -73,7 +73,11 @@
 	unsigned long prate;
 	unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
 	unsigned int cfg = 0;
-	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;
@@ -95,14 +99,14 @@
 		     (adj->crtc_hdisplay - 1) |
 		     ((adj->crtc_vdisplay - 1) << 16));
 
+	prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
+	mode_rate = adj->crtc_clock * 1000;
 	if (!crtc->dc->desc->fixed_clksrc) {
+		prate *= 2;
 		cfg |= ATMEL_HLCDC_CLKSEL;
 		mask |= ATMEL_HLCDC_CLKSEL;
 	}
 
-	prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk);
-	mode_rate = adj->crtc_clock * 1000;
-
 	div = DIV_ROUND_UP(prate, mode_rate);
 	if (div < 2) {
 		div = 2;
@@ -117,8 +121,8 @@
 		int div_low = prate / mode_rate;
 
 		if (div_low >= 2 &&
-		    ((prate / div_low - mode_rate) <
-		     10 * (mode_rate - prate / div)))
+		    (10 * (prate / div_low - mode_rate) <
+		     (mode_rate - prate / div)))
 			/*
 			 * At least 10 times better when using a higher
 			 * frequency than requested, instead of a lower.
@@ -147,6 +151,8 @@
 			   ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
 			   ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK,
 			   cfg);
+
+	clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
 }
 
 static enum drm_mode_status
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bochs/bochs_hw.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bochs/bochs_hw.c
@@ -156,10 +156,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-ein-5.4.0.orig/drivers/gpu/drm/bochs/bochs_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bochs/bochs_kms.c
@@ -194,6 +194,7 @@
 	bochs->dev->mode_config.preferred_depth = 24;
 	bochs->dev->mode_config.prefer_shadow = 0;
 	bochs->dev->mode_config.prefer_shadow_fbdev = 1;
+	bochs->dev->mode_config.fbdev_use_iomem = true;
 	bochs->dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
 
 	bochs->dev->mode_config.funcs = &bochs_mode_funcs;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/Kconfig
@@ -45,6 +45,15 @@
 	  Support for non-programmable RGB to VGA DAC bridges, such as ADI
 	  ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
 
+config DRM_FSL_IMX_LVDS_BRIDGE
+	tristate "Freescale i.MX LVDS display bridge"
+	depends on MFD_SYSCON
+	depends on OF
+	select DRM_PANEL_BRIDGE
+	help
+	  Support Freescale i.MX parallel to LVDS Display Bridge (LDB).
+	  This bridge is embedded in a SoC.
+
 config DRM_LVDS_ENCODER
 	tristate "Transparent parallel to LVDS encoder support"
 	depends on OF
@@ -65,6 +74,20 @@
           to DP++. This is used with the i.MX6 imx-ldb
           driver. You are likely to say N here.
 
+config DRM_SEC_MIPI_DSIM
+	tristate "Samsung MIPI DSIM Bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	  The Samsung MPI DSIM Bridge driver.
+
+config DRM_NXP_SEIKO_43WVFIG
+	tristate "Legacy Freescale Seiko 43WVFIG panel DPI adapter bridge"
+	select DRM_KMS_HELPER
+	select DRM_PANEL
+
 config DRM_NXP_PTN3460
 	tristate "NXP PTN3460 DP/LVDS bridge"
 	depends on OF
@@ -154,6 +177,19 @@
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
 
+source "drivers/gpu/drm/bridge/nwl-dsi/Kconfig"
+
+source "drivers/gpu/drm/bridge/cadence/Kconfig"
+
 source "drivers/gpu/drm/bridge/synopsys/Kconfig"
 
+config DRM_ITE_IT6263
+	tristate "ITE IT6263 LVDS/HDMI bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select REGMAP_I2C
+	select OF_DYNAMIC
+	---help---
+	  ITE IT6263 bridge chip driver.
+
 endmenu
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
 obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
+obj-$(CONFIG_DRM_FSL_IMX_LVDS_BRIDGE) += fsl-imx-ldb.o
 obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
@@ -16,4 +17,9 @@
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
 obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
 obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
+obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-dsi/
+obj-y += cadence/
 obj-y += synopsys/
+obj-$(CONFIG_DRM_ITE_IT6263) += it6263.o
+obj-$(CONFIG_DRM_SEC_MIPI_DSIM) += sec-dsim.o
+obj-$(CONFIG_DRM_NXP_SEIKO_43WVFIG) += nxp-seiko-43wvfig.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/Kconfig
@@ -4,6 +4,7 @@
 	depends on OF
 	select DRM_KMS_HELPER
 	select REGMAP_I2C
+	select OF_DYNAMIC
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
-adv7511-y := adv7511_drv.o
-adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
-adv7511-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
-adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
-obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
+adv7511_drm-y := adv7511_drv.o
+adv7511_drm-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
+adv7511_drm-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
+adv7511_drm-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511_drm.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -219,6 +219,9 @@
 #define ADV7511_REG_CEC_SOFT_RESET	0x50
 
 #define ADV7533_REG_CEC_OFFSET		0x70
+#define FORMAT_RATIO(x, y) (((x) * 100) / (y))
+#define RATIO_16_9 FORMAT_RATIO(16, 9)
+#define RATIO_4_3  FORMAT_RATIO(4, 3)
 
 enum adv7511_input_clock {
 	ADV7511_INPUT_CLOCK_1X,
@@ -320,6 +323,7 @@
 enum adv7511_type {
 	ADV7511,
 	ADV7533,
+	ADV7535,
 };
 
 #define ADV7511_MAX_ADDRS 3
@@ -330,6 +334,10 @@
 	struct i2c_client *i2c_packet;
 	struct i2c_client *i2c_cec;
 
+	u32 addr_cec;
+	u32 addr_edid;
+	u32 addr_pkt;
+
 	struct regmap *regmap;
 	struct regmap *regmap_cec;
 	enum drm_connector_status status;
@@ -365,6 +373,7 @@
 	struct device_node *host_node;
 	struct mipi_dsi_device *dsi;
 	u8 num_dsi_lanes;
+	u8 channel_id;
 	bool use_timing_gen;
 
 	enum adv7511_type type;
@@ -384,10 +393,7 @@
 #else
 static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 {
-	unsigned int offset = adv7511->type == ADV7533 ?
-						ADV7533_REG_CEC_OFFSET : 0;
-
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
 		     ADV7511_CEC_CTRL_POWER_DOWN);
 	return 0;
 }
@@ -396,7 +402,6 @@
 #ifdef CONFIG_DRM_I2C_ADV7533
 void adv7533_dsi_power_on(struct adv7511 *adv);
 void adv7533_dsi_power_off(struct adv7511 *adv);
-void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
 int adv7533_patch_registers(struct adv7511 *adv);
 int adv7533_patch_cec_registers(struct adv7511 *adv);
 int adv7533_attach_dsi(struct adv7511 *adv);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
@@ -19,13 +19,15 @@
 {
 	switch (fs) {
 	case 32000:
-		*n = 4096;
+	case 48000:
+	case 96000:
+	case 192000:
+		*n = fs * 128 / 1000;
 		break;
 	case 44100:
-		*n = 6272;
-		break;
-	case 48000:
-		*n = 6144;
+	case 88200:
+	case 176400:
+		*n = fs * 128 / 900;
 		break;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
@@ -302,7 +302,8 @@
 
 int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
 {
-	unsigned int offset = adv7511->type == ADV7533 ?
+	unsigned int offset = (adv7511->type == ADV7533 ||
+			       adv7511->type == ADV7535) ?
 						ADV7533_REG_CEC_OFFSET : 0;
 	int ret = adv7511_cec_parse_dt(dev, adv7511);
 
@@ -316,7 +317,7 @@
 		goto err_cec_alloc;
 	}
 
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0);
 	/* cec soft reset */
 	regmap_write(adv7511->regmap_cec,
 		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
@@ -343,7 +344,7 @@
 	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
 		 ret);
 err_cec_parse_dt:
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
 		     ADV7511_CEC_CTRL_POWER_DOWN);
 	return ret == -EPROBE_DEFER ? ret : 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -9,7 +9,9 @@
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 #include <linux/slab.h>
 
 #include <media/cec.h>
@@ -74,6 +76,26 @@
 	0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+/*
+ * TODO: Currently, filter-out unsupported modes by their clocks.
+ * Need to find a better way to do this.
+ * These are the pixel clocks that the converter can handle successfully.
+ */
+
+static const int valid_clocks[] = {
+	148500,
+	135000,
+	132000,
+	119000,
+	108000,
+	78750,
+	74250,
+	65000,
+	49500,
+	40000,
+	31500,
+};
+
 static bool adv7511_register_volatile(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -329,6 +351,7 @@
 {
 	adv7511->current_edid_segment = -1;
 
+	/* 01-02 Power */
 	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
 			   ADV7511_POWER_POWER_DOWN, 0);
 	if (adv7511->i2c_main->irq) {
@@ -346,6 +369,7 @@
 	}
 
 	/*
+	 * 01-01 HPD Manual Override
 	 * Per spec it is allowed to pulse the HPD signal to indicate that the
 	 * EDID information has changed. Some monitors do this when they wakeup
 	 * from standby or are enabled. When the HPD goes low the adv7511 is
@@ -367,7 +391,7 @@
 	 */
 	regcache_sync(adv7511->regmap);
 
-	if (adv7511->type == ADV7533)
+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
 		adv7533_dsi_power_on(adv7511);
 	adv7511->powered = true;
 }
@@ -387,7 +411,7 @@
 static void adv7511_power_off(struct adv7511 *adv7511)
 {
 	__adv7511_power_off(adv7511);
-	if (adv7511->type == ADV7533)
+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
 		adv7533_dsi_power_off(adv7511);
 	adv7511->powered = false;
 }
@@ -417,17 +441,16 @@
 static void adv7511_hpd_work(struct work_struct *work)
 {
 	struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
-	enum drm_connector_status status;
+	enum drm_connector_status status = connector_status_disconnected;
 	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)
+	if (ret >= 0 && (val & ADV7511_STATUS_HPD))
 		status = connector_status_connected;
-	else
-		status = connector_status_disconnected;
+
+	DRM_DEV_DEBUG_DRIVER(adv7511->connector.kdev, "HDMI HPD event: %s\n",
+		drm_get_connector_status_name(status));
 
 	/*
 	 * The bridge resets its registers on unplug. So when we get a plug
@@ -594,6 +617,8 @@
 {
 	struct edid *edid;
 	unsigned int count;
+	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	int ret;
 
 	/* Reading the EDID only works if the device is powered */
 	if (!adv7511->powered) {
@@ -623,6 +648,14 @@
 
 	kfree(edid);
 
+	connector->display_info.bus_flags = DRM_BUS_FLAG_DE_LOW |
+					    DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+	ret = drm_display_info_set_bus_formats(&connector->display_info,
+					       &bus_format, 1);
+	if (ret)
+		return ret;
+
 	return count;
 }
 
@@ -669,9 +702,21 @@
 static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
 			      struct drm_display_mode *mode)
 {
+	size_t i, num_modes = ARRAY_SIZE(valid_clocks);
+	bool clock_ok = false;
+
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
 
+	for (i = 0; i < num_modes; i++)
+		if (mode->clock == valid_clocks[i]) {
+			clock_ok = true;
+			break;
+		}
+
+	if (!clock_ok)
+		return MODE_NOCLOCK;
+
 	return MODE_OK;
 }
 
@@ -756,14 +801,16 @@
 	else
 		low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
 
-	regmap_update_bits(adv7511->regmap, 0xfb,
-		0x6, low_refresh_rate << 1);
+	if (adv7511->type == ADV7511)
+		regmap_update_bits(adv7511->regmap, 0xfb,
+				   0x6, low_refresh_rate << 1);
+	else
+		regmap_update_bits(adv7511->regmap, 0x4a,
+				   0xc, low_refresh_rate << 2);
+
 	regmap_update_bits(adv7511->regmap, 0x17,
 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
 
-	if (adv7511->type == ADV7533)
-		adv7533_mode_set(adv7511, adj_mode);
-
 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
 
 	/*
@@ -874,7 +921,7 @@
 				 &adv7511_connector_helper_funcs);
 	drm_connector_attach_encoder(&adv->connector, bridge->encoder);
 
-	if (adv->type == ADV7533)
+	if (adv->type == ADV7533 || adv->type == ADV7535)
 		ret = adv7533_attach_dsi(adv);
 
 	if (adv->i2c_main->irq)
@@ -982,9 +1029,13 @@
 	int ret;
 
 	adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec",
-						ADV7511_CEC_I2C_ADDR_DEFAULT);
+						adv->addr_cec);
 	if (IS_ERR(adv->i2c_cec))
 		return PTR_ERR(adv->i2c_cec);
+
+	regmap_write(adv->regmap, ADV7511_REG_CEC_I2C_ADDR,
+		     adv->i2c_cec->addr << 1);
+
 	i2c_set_clientdata(adv->i2c_cec, adv);
 
 	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
@@ -994,7 +1045,7 @@
 		goto err;
 	}
 
-	if (adv->type == ADV7533) {
+	if (adv->type == ADV7533 || adv->type == ADV7535) {
 		ret = adv7533_patch_cec_registers(adv);
 		if (ret)
 			goto err;
@@ -1094,6 +1145,12 @@
 	struct adv7511_link_config link_config;
 	struct adv7511 *adv7511;
 	struct device *dev = &i2c->dev;
+	struct device_node *remote_node = NULL, *endpoint = NULL;
+	struct of_changeset ocs;
+	unsigned int main_i2c_addr = i2c->addr << 1;
+	unsigned int edid_i2c_addr = main_i2c_addr + 4;
+	unsigned int cec_i2c_addr = main_i2c_addr - 2;
+	unsigned int pkt_i2c_addr = main_i2c_addr - 0xa;
 	unsigned int val;
 	int ret;
 
@@ -1128,6 +1185,21 @@
 		return ret;
 	}
 
+	if (adv7511->addr_cec != 0)
+		cec_i2c_addr = adv7511->addr_cec << 1;
+	else
+		adv7511->addr_cec = cec_i2c_addr >> 1;
+
+	if (adv7511->addr_edid != 0)
+		edid_i2c_addr = adv7511->addr_edid << 1;
+	else
+		adv7511->addr_edid = edid_i2c_addr >> 1;
+
+	if (adv7511->addr_pkt != 0)
+		pkt_i2c_addr = adv7511->addr_pkt << 1;
+	else
+		adv7511->addr_pkt = pkt_i2c_addr >> 1;
+
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
 	 * inactive to wake up the encoder.
@@ -1165,33 +1237,33 @@
 
 	adv7511_packet_disable(adv7511, 0xffff);
 
+	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+			edid_i2c_addr);
+
 	adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
-					ADV7511_EDID_I2C_ADDR_DEFAULT);
+					adv7511->addr_edid);
 	if (IS_ERR(adv7511->i2c_edid)) {
 		ret = PTR_ERR(adv7511->i2c_edid);
 		goto uninit_regulators;
 	}
 
-	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
-		     adv7511->i2c_edid->addr << 1);
+	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+			pkt_i2c_addr);
 
 	adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",
-					ADV7511_PACKET_I2C_ADDR_DEFAULT);
+					adv7511->addr_pkt);
 	if (IS_ERR(adv7511->i2c_packet)) {
 		ret = PTR_ERR(adv7511->i2c_packet);
 		goto err_i2c_unregister_edid;
 	}
 
-	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
-		     adv7511->i2c_packet->addr << 1);
+	regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
+			cec_i2c_addr);
 
 	ret = adv7511_init_cec_regmap(adv7511);
 	if (ret)
 		goto err_i2c_unregister_packet;
 
-	regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
-		     adv7511->i2c_cec->addr << 1);
-
 	INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
 
 	if (i2c->irq) {
@@ -1225,6 +1297,7 @@
 	return 0;
 
 err_unregister_cec:
+	cec_unregister_adapter(adv7511->cec_adap);
 	i2c_unregister_device(adv7511->i2c_cec);
 	if (adv7511->cec_clk)
 		clk_disable_unprepare(adv7511->cec_clk);
@@ -1234,6 +1307,35 @@
 	i2c_unregister_device(adv7511->i2c_edid);
 uninit_regulators:
 	adv7511_uninit_regulators(adv7511);
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint)
+		remote_node = of_graph_get_remote_port_parent(endpoint);
+
+	if (!remote_node)
+		return ret;
+
+	/* Find remote's endpoint connected to us and detach it */
+	endpoint = NULL;
+	while ((endpoint = of_graph_get_next_endpoint(remote_node,
+						      endpoint))) {
+		struct device_node *us;
+
+		us = of_graph_get_remote_port_parent(endpoint);
+		if (us == dev->of_node)
+			break;
+	}
+	of_node_put(remote_node);
+
+	if (!endpoint)
+		return ret;
+
+	of_changeset_init(&ocs);
+	of_changeset_detach_node(&ocs, endpoint);
+	ret = of_changeset_apply(&ocs);
+	if (!ret)
+		dev_warn(dev,
+			 "Probe failed. Remote port '%s' disabled\n",
+			 remote_node->full_name);
 
 	return ret;
 }
@@ -1242,7 +1344,7 @@
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
-	if (adv7511->type == ADV7533)
+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
 		adv7533_detach_dsi(adv7511);
 	i2c_unregister_device(adv7511->i2c_cec);
 	if (adv7511->cec_clk)
@@ -1268,6 +1370,7 @@
 	{ "adv7513", ADV7511 },
 #ifdef CONFIG_DRM_I2C_ADV7533
 	{ "adv7533", ADV7533 },
+	{ "adv7535", ADV7535 },
 #endif
 	{ }
 };
@@ -1279,6 +1382,7 @@
 	{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
 #ifdef CONFIG_DRM_I2C_ADV7533
 	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+	{ .compatible = "adi,adv7535", .data = (void *)ADV7535 },
 #endif
 	{ }
 };
@@ -1300,10 +1404,21 @@
 
 static int __init adv7511_init(void)
 {
-	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
-		mipi_dsi_driver_register(&adv7533_dsi_driver);
+	int ret;
 
-	return i2c_add_driver(&adv7511_driver);
+	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
+		ret = mipi_dsi_driver_register(&adv7533_dsi_driver);
+		if (ret)
+			return ret;
+	}
+
+	ret = i2c_add_driver(&adv7511_driver);
+	if (ret) {
+		if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+			mipi_dsi_driver_unregister(&adv7533_dsi_driver);
+	}
+
+	return ret;
 }
 module_init(adv7511_init);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -26,10 +26,8 @@
 
 static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
 {
-	struct mipi_dsi_device *dsi = adv->dsi;
 	struct drm_display_mode *mode = &adv->curr_mode;
 	unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
-	u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */
 
 	hsw = mode->hsync_end - mode->hsync_start;
 	hfp = mode->hsync_start - mode->hdisplay;
@@ -38,9 +36,10 @@
 	vfp = mode->vsync_start - mode->vdisplay;
 	vbp = mode->vtotal - mode->vsync_end;
 
-	/* set pixel clock divider mode */
-	regmap_write(adv->regmap_cec, 0x16,
-		     clock_div_by_lanes[dsi->lanes - 2] << 3);
+	/* 03-01 Enable Internal Timing Generator */
+	regmap_write(adv->regmap_cec, 0x27, 0xcb);
+
+	/* 03-08 Timing Configuration */
 
 	/* horizontal porch params */
 	regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
@@ -61,35 +60,66 @@
 	regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
 	regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
 	regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
+
+	/* 03-03 Reset Internal Timing Generator */
+	regmap_write(adv->regmap_cec, 0x27, 0xcb);
+	regmap_write(adv->regmap_cec, 0x27, 0x8b);
+	regmap_write(adv->regmap_cec, 0x27, 0xcb);
+
 }
 
 void adv7533_dsi_power_on(struct adv7511 *adv)
 {
 	struct mipi_dsi_device *dsi = adv->dsi;
+	struct drm_display_mode *mode = &adv->curr_mode;
+	u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */
 
-	if (adv->use_timing_gen)
-		adv7511_dsi_config_timing_gen(adv);
+	/* Gate DSI LP Oscillator */
+	regmap_update_bits(adv->regmap_cec, 0x03, 0x02, 0x00);
 
-	/* set number of dsi lanes */
+	/* 01-03 Initialisation (Fixed) Registers */
+	regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
+			      ARRAY_SIZE(adv7533_cec_fixed_registers));
+
+	/* 02-04 DSI Lanes */
 	regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
 
-	if (adv->use_timing_gen) {
-		/* reset internal timing generator */
-		regmap_write(adv->regmap_cec, 0x27, 0xcb);
-		regmap_write(adv->regmap_cec, 0x27, 0x8b);
-		regmap_write(adv->regmap_cec, 0x27, 0xcb);
-	} else {
-		/* disable internal timing generator */
+	/* 02-05 DSI Pixel Clock Divider */
+	regmap_write(adv->regmap_cec, 0x16,
+		     clock_div_by_lanes[dsi->lanes - 2] << 3);
+
+	if (adv->use_timing_gen)
+		adv7511_dsi_config_timing_gen(adv);
+	else
 		regmap_write(adv->regmap_cec, 0x27, 0x0b);
-	}
 
-	/* enable hdmi */
+	/* 04-01 HDMI Output */
+	regmap_write(adv->regmap, 0xaf, 0x16);
+
+	/* 09-03 AVI Infoframe - RGB - 16-9 Aspect Ratio */
+	regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(0), 0x10);
+	if (FORMAT_RATIO(mode->hdisplay, mode->vdisplay) == RATIO_16_9)
+		regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(1), 0x28);
+	else if (FORMAT_RATIO(mode->hdisplay, mode->vdisplay) == RATIO_4_3)
+		regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(1), 0x18);
+
+	/* 04-04 GC Packet Enable */
+	regmap_write(adv->regmap, ADV7511_REG_PACKET_ENABLE0, 0x80);
+
+	/* 04-06 GC Colour Depth - 24 Bit */
+	regmap_write(adv->regmap, 0x4c, 0x04);
+
+	/* 04-09 Down Dither Output Colour Depth - 8 Bit (default) */
+	regmap_write(adv->regmap, 0x49, 0x00);
+
+	/* 07-01 CEC Power Mode - Always Active */
+	regmap_write(adv->regmap_cec, 0xbe, 0x3d);
+
+	/* 04-03 HDMI Output Enable  */
 	regmap_write(adv->regmap_cec, 0x03, 0x89);
 	/* disable test mode */
 	regmap_write(adv->regmap_cec, 0x55, 0x00);
 
-	regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
-			      ARRAY_SIZE(adv7533_cec_fixed_registers));
 }
 
 void adv7533_dsi_power_off(struct adv7511 *adv)
@@ -100,28 +130,6 @@
 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
 }
 
-void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
-{
-	struct mipi_dsi_device *dsi = adv->dsi;
-	int lanes, ret;
-
-	if (adv->num_dsi_lanes != 4)
-		return;
-
-	if (mode->clock > 80000)
-		lanes = 4;
-	else
-		lanes = 3;
-
-	if (lanes != dsi->lanes) {
-		mipi_dsi_detach(dsi);
-		dsi->lanes = lanes;
-		ret = mipi_dsi_attach(dsi);
-		if (ret)
-			dev_err(&dsi->dev, "failed to change host lanes\n");
-	}
-}
-
 int adv7533_patch_registers(struct adv7511 *adv)
 {
 	return regmap_register_patch(adv->regmap,
@@ -143,7 +151,7 @@
 	struct mipi_dsi_device *dsi;
 	int ret = 0;
 	const struct mipi_dsi_device_info info = { .type = "adv7533",
-						   .channel = 0,
+						   .channel = adv->channel_id,
 						   .node = NULL,
 						 };
 
@@ -189,14 +197,24 @@
 
 int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
 {
-	u32 num_lanes;
+	struct device *dev = &adv->i2c_main->dev;
+	u32 num_lanes = 0, channel_id = 0;
 
+	of_property_read_u32(np, "adi,dsi-channel", &channel_id);
 	of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
 
-	if (num_lanes < 1 || num_lanes > 4)
+	if (num_lanes < 1 || num_lanes > 4) {
+		dev_err(dev, "Invalid dsi-lanes: %d\n", num_lanes);
 		return -EINVAL;
+	}
+
+	if (channel_id > 3) {
+		dev_err(dev, "Invalid dsi-channel: %d\n", channel_id);
+		return -EINVAL;
+	}
 
 	adv->num_dsi_lanes = num_lanes;
+	adv->channel_id = channel_id;
 
 	adv->host_node = of_graph_get_remote_node(np, 0, 0);
 	if (!adv->host_node)
@@ -207,6 +225,10 @@
 	adv->use_timing_gen = !of_property_read_bool(np,
 						"adi,disable-timing-generator");
 
+	of_property_read_u32(np, "adi,addr-cec", &adv->addr_cec);
+	of_property_read_u32(np, "adi,addr-edid", &adv->addr_edid);
+	of_property_read_u32(np, "adi,addr-pkt", &adv->addr_pkt);
+
 	/* TODO: Check if these need to be parsed by DT or not */
 	adv->rgb = true;
 	adv->embedded_sync = false;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/analogix-anx78xx.c
@@ -715,7 +715,9 @@
 	/* 1.0V digital core power regulator  */
 	pdata->dvdd10 = devm_regulator_get(dev, "dvdd10");
 	if (IS_ERR(pdata->dvdd10)) {
-		DRM_ERROR("DVDD10 regulator not found\n");
+		if (PTR_ERR(pdata->dvdd10) != -EPROBE_DEFER)
+			DRM_ERROR("DVDD10 regulator not found\n");
+
 		return PTR_ERR(pdata->dvdd10);
 	}
 
@@ -1332,7 +1334,9 @@
 
 	err = anx78xx_init_pdata(anx78xx);
 	if (err) {
-		DRM_ERROR("Failed to initialize pdata: %d\n", err);
+		if (err != -EPROBE_DEFER)
+			DRM_ERROR("Failed to initialize pdata: %d\n", err);
+
 		return err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1630,13 +1630,23 @@
 				       struct drm_dp_aux_msg *msg)
 {
 	struct analogix_dp_device *dp = to_dp(aux);
+	int ret;
+
+	pm_runtime_get_sync(dp->dev);
+
+	ret = analogix_dp_detect_hpd(dp);
+	if (ret)
+		goto out;
+
+	ret = analogix_dp_transfer(dp, msg);
+out:
+	pm_runtime_put(dp->dev);
 
-	return analogix_dp_transfer(dp, msg);
+	return ret;
 }
 
 struct analogix_dp_device *
-analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		 struct analogix_dp_plat_data *plat_data)
+analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1697,8 +1707,10 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(dp->reg_base))
-		return ERR_CAST(dp->reg_base);
+	if (IS_ERR(dp->reg_base)) {
+		ret = PTR_ERR(dp->reg_base);
+		goto err_disable_clk;
+	}
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1710,7 +1722,8 @@
 	if (IS_ERR(dp->hpd_gpiod)) {
 		dev_err(dev, "error getting HDP GPIO: %ld\n",
 			PTR_ERR(dp->hpd_gpiod));
-		return ERR_CAST(dp->hpd_gpiod);
+		ret = PTR_ERR(dp->hpd_gpiod);
+		goto err_disable_clk;
 	}
 
 	if (dp->hpd_gpiod) {
@@ -1730,7 +1743,8 @@
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return ERR_PTR(-ENODEV);
+		ret = -ENODEV;
+		goto err_disable_clk;
 	}
 
 	ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
@@ -1739,22 +1753,34 @@
 					irq_flags, "analogix-dp", dp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
-		goto err_disable_pm_runtime;
+		goto err_disable_clk;
 	}
 	disable_irq(dp->irq);
 
+	return dp;
+
+err_disable_clk:
+	clk_disable_unprepare(dp->clock);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(analogix_dp_probe);
+
+int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
+{
+	int ret;
+
 	dp->drm_dev = drm_dev;
 	dp->encoder = dp->plat_data->encoder;
 
 	dp->aux.name = "DP-AUX";
 	dp->aux.transfer = analogix_dpaux_transfer;
-	dp->aux.dev = &pdev->dev;
+	dp->aux.dev = dp->dev;
 
 	ret = drm_dp_aux_register(&dp->aux);
 	if (ret)
-		return ERR_PTR(ret);
+		return ret;
 
-	pm_runtime_enable(dev);
+	pm_runtime_enable(dp->dev);
 
 	ret = analogix_dp_create_bridge(drm_dev, dp);
 	if (ret) {
@@ -1762,13 +1788,12 @@
 		goto err_disable_pm_runtime;
 	}
 
-	return dp;
+	return 0;
 
 err_disable_pm_runtime:
+	pm_runtime_disable(dp->dev);
 
-	pm_runtime_disable(dev);
-
-	return ERR_PTR(ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
@@ -1785,20 +1810,19 @@
 
 	drm_dp_aux_unregister(&dp->aux);
 	pm_runtime_disable(dp->dev);
-	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
+void analogix_dp_remove(struct analogix_dp_device *dp)
+{
+	clk_disable_unprepare(dp->clock);
+}
+EXPORT_SYMBOL_GPL(analogix_dp_remove);
+
 #ifdef CONFIG_PM
 int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
 	clk_disable_unprepare(dp->clock);
-
-	if (dp->plat_data->panel) {
-		if (drm_panel_unprepare(dp->plat_data->panel))
-			DRM_ERROR("failed to turnoff the panel\n");
-	}
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
@@ -1813,13 +1837,6 @@
 		return ret;
 	}
 
-	if (dp->plat_data->panel) {
-		if (drm_panel_prepare(dp->plat_data->panel)) {
-			DRM_ERROR("failed to setup the panel\n");
-			return -EBUSY;
-		}
-	}
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_resume);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1086,11 +1086,21 @@
 	if (!blocking)
 		return 0;
 
+	/*
+	 * db[1]!=0: entering PSR, wait for fully active remote frame buffer.
+	 * db[1]==0: exiting PSR, wait for either
+	 *  (a) ACTIVE_RESYNC - the sink "must display the
+	 *      incoming active frames from the Source device with no visible
+	 *      glitches and/or artifacts", even though timings may still be
+	 *      re-synchronizing; or
+	 *  (b) INACTIVE - the transition is fully complete.
+	 */
 	ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status,
 		psr_status >= 0 &&
 		((vsc->db[1] && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||
-		(!vsc->db[1] && psr_status == DP_PSR_SINK_INACTIVE)), 1500,
-		DP_TIMEOUT_PSR_LOOP_MS * 1000);
+		(!vsc->db[1] && (psr_status == DP_PSR_SINK_ACTIVE_RESYNC ||
+				 psr_status == DP_PSR_SINK_INACTIVE))),
+		1500, DP_TIMEOUT_PSR_LOOP_MS * 1000);
 	if (ret) {
 		dev_warn(dp->dev, "Failed to apply PSR %d\n", ret);
 		return ret;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -0,0 +1,25 @@
+config DRM_CDNS_MHDP
+	tristate "Cadence MHDP COMMON API driver"
+	select DRM_KMS_HELPER
+	select DRM_PANEL_BRIDGE
+	depends on OF
+	help
+	  Support Cadence MHDP API library.
+
+config DRM_CDNS_HDMI
+	tristate "Cadence HDMI DRM driver"
+	depends on DRM_CDNS_MHDP
+
+config DRM_CDNS_DP
+	tristate "Cadence DP DRM driver"
+	depends on DRM_CDNS_MHDP
+
+config DRM_CDNS_AUDIO
+	tristate "Cadence MHDP Audio driver"
+	depends on DRM_CDNS_MHDP
+
+config DRM_CDNS_HDMI_CEC
+	tristate "Cadence MHDP HDMI CEC driver"
+	depends on DRM_CDNS_HDMI
+	select CEC_CORE
+	select CEC_NOTIFIER
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/Makefile
@@ -0,0 +1,9 @@
+
+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-dp.o cdns-mhdp-hdmi.o
+
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o
+
+obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
@@ -0,0 +1,654 @@
+/*
+ * Cadence Display Port Interface (DP) driver
+ *
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+/*
+ * This function only implements native DPDC reads and writes
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
+	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	int ret;
+
+	/* Ignore address only message , for native */
+	if ((native == true) && ((msg->size == 0) || (msg->buffer == NULL))) {
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+
+	/* msg sanity check */
+	if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
+		dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
+			__func__, msg->size, (unsigned int)msg->request);
+		return -EINVAL;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_WRITE) {
+		const u8 *buf = msg->buffer;
+		int i;
+		for (i = 0; i < msg->size; ++i) {
+			ret = cdns_mhdp_dpcd_write(mhdp,
+						   msg->address + i, buf[i]);
+			if (!ret)
+				continue;
+
+			DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
+
+			return ret;
+		}
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_READ) {
+		ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer,
+					  msg->size);
+		if (ret < 0)
+			return -EIO;
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE)
+	    || ((msg->request & ~DP_AUX_I2C_MOT) ==
+		DP_AUX_I2C_WRITE_STATUS_UPDATE)) {
+
+		u8 i2c_status = 0u;
+		u16 respSize = 0u;
+
+		ret =  cdns_mhdp_i2c_write(mhdp, msg->address,
+					   msg->buffer,
+					   !!(msg->request & DP_AUX_I2C_MOT),
+					   msg->size, &respSize);
+
+		if (ret < 0) {
+			dev_err(aux->dev, "cdns_mhdp_i2c_write status %d\n",
+				ret);
+			return -EIO;
+		}
+
+		ret = cdns_mhdp_get_last_i2c_status(mhdp, &i2c_status);
+		if (ret < 0) {
+			dev_err(aux->dev,
+				"cdns_mhdp_get_last_i2c_status status %d\n",
+				ret);
+			return -EIO;
+		}
+
+		switch (i2c_status) {
+		case 0u:
+			msg->reply = DP_AUX_I2C_REPLY_ACK;
+			break;
+		case 1u:
+			msg->reply = DP_AUX_I2C_REPLY_NACK;
+			break;
+		case 2u:
+			msg->reply = DP_AUX_I2C_REPLY_DEFER;
+			break;
+		default:
+			msg->reply = DP_AUX_I2C_REPLY_NACK;
+			break;
+		}
+
+		return respSize;
+	}
+
+	if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) {
+
+		u8 i2c_status = 0u;
+		u16 respSize = 0u;
+
+		ret = cdns_mhdp_i2c_read(mhdp, msg->address, msg->buffer,
+					 msg->size,
+					 !!(msg->request & DP_AUX_I2C_MOT),
+					 &respSize);
+		if (ret < 0)
+			return -EIO;
+
+		ret = cdns_mhdp_get_last_i2c_status(mhdp, &i2c_status);
+
+		if (ret < 0) {
+			dev_err(aux->dev,
+				"cdns_mhdp_get_last_i2c_status ret %d\n", ret);
+			return -EIO;
+		}
+
+		switch (i2c_status) {
+		case 0u:
+			msg->reply = DP_AUX_I2C_REPLY_ACK;
+			break;
+		case 1u:
+			msg->reply = DP_AUX_I2C_REPLY_NACK;
+			break;
+		case 2u:
+			msg->reply = DP_AUX_I2C_REPLY_DEFER;
+			break;
+		default:
+			msg->reply = DP_AUX_I2C_REPLY_NACK;
+			break;
+		}
+
+		return respSize;
+	}
+
+	return 0;
+}
+
+static int dp_aux_init(struct cdns_mhdp_device *mhdp,
+		  struct device *dev)
+{
+	int ret;
+
+	mhdp->dp.aux.name = "imx_dp_aux";
+	mhdp->dp.aux.dev = dev;
+	mhdp->dp.aux.transfer = dp_aux_transfer;
+
+	ret = drm_dp_aux_register(&mhdp->dp.aux);
+
+	return ret;
+}
+
+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
+{
+	drm_dp_aux_unregister(&mhdp->dp.aux);
+	return 0;
+}
+
+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	/* reset pixel clk */
+	val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
+}
+
+static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp)
+{
+	u32 lane_mapping = mhdp->lane_mapping;
+	int ret;
+
+	cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+	/* delay for DP FW stable after pixel clock relock */
+	msleep(50);
+
+	dp_pixel_clk_reset(mhdp);
+
+	/* Get DP Caps  */
+	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
+			       DP_RECEIVER_CAP_SIZE);
+	if (ret < 0) {
+		DRM_ERROR("Failed to get caps %d\n", ret);
+		return;
+	}
+
+	mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
+	mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
+
+	/* check the max link rate */
+	if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
+		mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
+
+	/* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Video off */
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+
+	/* Line swaping */
+	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
+
+	/* Set DP host capability */
+	ret = cdns_mhdp_set_host_cap(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_config_video(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
+		return;
+	}
+
+	return;
+}
+
+/* -----------------------------------------------------------------------------
+ * dp TX Setup
+ */
+static enum drm_connector_status
+cdns_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	u8 hpd = 0xf;
+
+	hpd = cdns_mhdp_read_hpd(mhdp);
+	if (hpd == 1)
+		/* Cable Connected */
+		return connector_status_connected;
+	else if (hpd == 0)
+		/* Cable Disconnedted */
+		return connector_status_disconnected;
+	else {
+		/* Cable status unknown */
+		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+		return connector_status_unknown;
+	}
+}
+
+static int cdns_dp_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	int num_modes = 0;
+	struct edid *edid;
+
+	edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_mhdp_get_edid_block, mhdp);
+	if (edid) {
+		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+			 edid->header[0], edid->header[1],
+			 edid->header[2], edid->header[3],
+			 edid->header[4], edid->header[5],
+			 edid->header[6], edid->header[7]);
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	if (num_modes == 0)
+		DRM_ERROR("Invalid edid\n");
+	return num_modes;
+}
+
+static const struct drm_connector_funcs cdns_dp_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = cdns_dp_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
+	.get_modes = cdns_dp_connector_get_modes,
+};
+
+static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	connector->interlace_allowed = 1;
+
+	if (mhdp->is_hpd)
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+	else
+		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+		DRM_CONNECTOR_POLL_DISCONNECT;
+
+	drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
+
+	drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
+			   DRM_MODE_CONNECTOR_DisplayPort);
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static enum drm_mode_status
+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	enum drm_mode_status mode_status = MODE_OK;
+
+	/* We don't support double-clocked modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	/* MAX support pixel clock rate 594MHz */
+	if (mode->clock > 594000)
+		return MODE_CLOCK_HIGH;
+
+	/* 5120 x 2160 is the maximum supported resulution */
+	if (mode->hdisplay > 5120)
+		return MODE_BAD_HVALUE;
+
+	if (mode->vdisplay > 2160)
+		return MODE_BAD_VVALUE;
+
+	return mode_status;
+}
+
+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *orig_mode,
+				    const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_display_info *display_info = &mhdp->connector.base.display_info;
+	struct video_info *video = &mhdp->video_info;
+
+	switch (display_info->bpc) {
+	case 10:
+		video->color_depth = 10;
+		break;
+	case 6:
+		video->color_depth = 6;
+		break;
+	default:
+		video->color_depth = 8;
+		break;
+	}
+
+	video->color_fmt = PXL_RGB;
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
+	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+	mutex_lock(&mhdp->lock);
+	cdns_dp_mode_set(mhdp);
+	mutex_unlock(&mhdp->lock);
+
+	/* reset force mode set flag */
+	mhdp->force_mode_set = false;
+}
+
+static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	int ret;
+
+	/* Link trainning */
+	ret = cdns_mhdp_train_link(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+}
+
+static void cdn_dp_bridge_disable(struct drm_bridge *bridge)
+{	
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+
+	cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+}
+
+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
+	.attach = cdns_dp_bridge_attach,
+	.enable = cdn_dp_bridge_enable,
+	.disable = cdn_dp_bridge_disable,
+	.mode_set = cdns_dp_bridge_mode_set,
+	.mode_valid = cdns_dp_bridge_mode_valid,
+};
+
+static void hotplug_work_func(struct work_struct *work)
+{
+	struct cdns_mhdp_device *mhdp = container_of(work,
+					   struct cdns_mhdp_device, hotplug_work.work);
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	if (connector->status == connector_status_connected) {
+		/* Cable connedted  */
+		DRM_INFO("HDMI/DP Cable Plug In\n");
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	} else if (connector->status == connector_status_disconnected) {
+		/* Cable Disconnedted  */
+		DRM_INFO("HDMI/DP Cable Plug Out\n");
+		/* force mode set for cable replugin to recovery DP video modes */
+		mhdp->force_mode_set = true;
+		enable_irq(mhdp->irq[IRQ_IN]);
+	}
+}
+
+static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
+{
+	struct cdns_mhdp_device *mhdp = data;
+
+	disable_irq_nosync(irq);
+
+	mod_delayed_work(system_wq, &mhdp->hotplug_work,
+			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+	return IRQ_HANDLED;
+}
+
+static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp)
+{
+	struct device_node *of_node = mhdp->dev->of_node;
+	int ret;
+
+	ret = of_property_read_u32(of_node, "lane-mapping",
+						&mhdp->lane_mapping);
+	if (ret) {
+		mhdp->lane_mapping = 0xc6;
+		dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
+	}
+	dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
+}
+
+static int __cdns_dp_probe(struct platform_device *pdev,
+		struct cdns_mhdp_device *mhdp)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iores = NULL;
+	int ret;
+
+	mutex_init(&mhdp->lock);
+	mutex_init(&mhdp->iolock);
+
+	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (iores) {
+		mhdp->regs_base = devm_ioremap(dev, iores->start,
+					       resource_size(iores));
+		if (IS_ERR(mhdp->regs_base))
+			return -ENOMEM;
+	}
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (iores) {
+		mhdp->regs_sec = devm_ioremap(dev, iores->start,
+					      resource_size(iores));
+		if (IS_ERR(mhdp->regs_sec))
+			return -ENOMEM;
+	}
+
+	mhdp->is_hpd = true;
+	mhdp->is_ls1028a = false;
+
+	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+	if (mhdp->irq[IRQ_IN] < 0) {
+		mhdp->is_hpd = false;
+		dev_info(dev, "No plug_in irq number\n");
+	}
+
+	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+	if (mhdp->irq[IRQ_OUT] < 0) {
+		mhdp->is_hpd = false;
+		dev_info(dev, "No plug_out irq number\n");
+	}
+
+	cdns_dp_parse_dt(mhdp);
+
+	if (of_device_is_compatible(dev->of_node, "cdn,ls1028a-dp"))
+		mhdp->is_ls1028a = true;
+
+	cdns_mhdp_plat_call(mhdp, power_on);
+
+	cdns_mhdp_plat_call(mhdp, firmware_init);
+
+	/* DP FW alive check */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO dp FW running\n");
+		return -ENXIO;
+	}
+
+	/* DP PHY init before AUX init */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Enable Hotplug Detect IRQ thread */
+	if (mhdp->is_hpd) {
+		irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+						NULL, cdns_dp_irq_thread,
+						IRQF_ONESHOT, dev_name(dev),
+						mhdp);
+	
+		if (ret) {
+			dev_err(dev, "can't claim irq %d\n",
+					mhdp->irq[IRQ_IN]);
+			return -EINVAL;
+		}
+
+		irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+						NULL, cdns_dp_irq_thread,
+						IRQF_ONESHOT, dev_name(dev),
+						mhdp);
+
+		if (ret) {
+			dev_err(dev, "can't claim irq %d\n",
+					mhdp->irq[IRQ_OUT]);
+			return -EINVAL;
+		}
+
+		if (cdns_mhdp_read_hpd(mhdp))
+			enable_irq(mhdp->irq[IRQ_OUT]);
+		else
+			enable_irq(mhdp->irq[IRQ_IN]);
+	}
+
+	mhdp->bridge.base.driver_private = mhdp;
+	mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
+#ifdef CONFIG_OF
+	mhdp->bridge.base.of_node = dev->of_node;
+#endif
+
+	dev_set_drvdata(dev, mhdp);
+	
+	/* register audio driver */
+	cdns_mhdp_register_audio_driver(dev);
+
+	dp_aux_init(mhdp, dev);
+
+	return 0;
+}
+
+static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+{
+	cdns_mhdp_plat_call(mhdp, power_off);
+	dp_aux_destroy(mhdp);
+	cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_dp_probe(struct platform_device *pdev,
+		  struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret)
+		return ret;
+
+	drm_bridge_add(&mhdp->bridge.base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_probe);
+
+void cdns_dp_remove(struct platform_device *pdev)
+{
+	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&mhdp->bridge.base);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL);
+	if (ret) {
+		cdns_dp_remove(pdev);
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_bind);
+
+void cdns_dp_unbind(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_unbind);
+
+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdn-dp");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
@@ -0,0 +1,755 @@
+/*
+ * Cadence High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_print.h>
+#include <drm/drm_scdc_helper.h>
+#include <drm/drm_vblank.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+	u8 buff = 0;
+
+	/* return if hdmi work in DVI mode */
+	if (mhdp->hdmi.hdmi_type == MODE_DVI)
+		return;
+
+	/* check sink support SCDC or not */
+	if (scdc->supported != true) {
+		DRM_INFO("Sink Not Support SCDC\n");
+		return;
+	}
+
+	if (mhdp->hdmi.char_rate > 340000) {
+		/*
+		 * TMDS Character Rate above 340MHz should working in HDMI2.0
+		 * Enable scrambling and TMDS_Bit_Clock_Ratio
+		 */
+		buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE;
+		mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+	} else  if (scdc->scrambling.low_rates) {
+		/*
+		 * Enable scrambling and HDMI2.0 when scrambling capability of sink
+		 * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
+		 */
+		buff = SCDC_SCRAMBLING_ENABLE;
+		mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+	}
+
+	/* TMDS config */
+	cdns_hdmi_scdc_write(mhdp, 0x20, buff);
+}
+
+static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+{
+	/* Line swaping */
+	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+}
+
+static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
+			     struct drm_display_mode *mode)
+{
+	struct hdmi_avi_infoframe frame;
+	int format = mhdp->video_info.color_fmt;
+	struct drm_connector_state *conn_state = mhdp->connector.base.state;
+	struct drm_display_mode *adj_mode;
+	enum hdmi_quantization_range qr;
+	u8 buf[32];
+	int ret;
+
+	/* Initialise info frame from DRM mode */
+	drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base,
+						 mode);
+
+	switch (format) {
+	case YCBCR_4_4_4:
+		frame.colorspace = HDMI_COLORSPACE_YUV444;
+		break;
+	case YCBCR_4_2_2:
+		frame.colorspace = HDMI_COLORSPACE_YUV422;
+		break;
+	case YCBCR_4_2_0:
+		frame.colorspace = HDMI_COLORSPACE_YUV420;
+		break;
+	default:
+		frame.colorspace = HDMI_COLORSPACE_RGB;
+		break;
+	}
+
+	drm_hdmi_avi_infoframe_colorspace(&frame, conn_state);
+
+	adj_mode = &mhdp->bridge.base.encoder->crtc->state->adjusted_mode;
+
+	qr = drm_default_rgb_quant_range(adj_mode);
+
+	drm_hdmi_avi_infoframe_quant_range(&frame, &mhdp->connector.base,
+					   adj_mode, qr);
+
+	ret = hdmi_avi_infoframe_check(&frame);
+	if (WARN_ON(ret))
+		return false;
+
+	ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
+		return -1;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
+	return 0;
+}
+
+static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
+				struct drm_display_mode *mode)
+{
+	struct hdmi_vendor_infoframe frame;
+	u8 buf[32];
+	int ret;
+
+	/* Initialise vendor frame from DRM mode */
+	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
+	if (ret < 0) {
+		DRM_INFO("No vendor infoframe\n");
+		return;
+	}
+
+	ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
+		return;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
+}
+
+static void hdmi_drm_info_set(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_connector_state *conn_state;
+	struct hdmi_drm_infoframe frame;
+	u8 buf[32];
+	int ret;
+
+	conn_state = mhdp->connector.base.state;
+
+	if (!conn_state->hdr_output_metadata)
+		return;
+
+	ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n");
+		return;
+	}
+
+	ret = hdmi_drm_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("couldn't pack HDR infoframe\n");
+		return;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf),
+				buf, HDMI_INFOFRAME_TYPE_DRM);
+}
+
+void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	int ret;
+
+	/* video mode valid check */
+	if (mode->clock == 0 || mode->hdisplay == 0 ||  mode->vdisplay == 0)
+		return;
+
+	hdmi_lanes_config(mhdp);
+
+	cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+	/* delay for HDMI FW stable after pixel clock relock */
+	msleep(20);
+
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	hdmi_sink_config(mhdp);
+
+	ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
+	if (ret < 0) {
+		DRM_ERROR("%s, ret = %d\n", __func__, ret);
+		return;
+	}
+
+	/* Config GCP */
+	if (mhdp->video_info.color_depth == 8)
+		cdns_hdmi_disable_gcp(mhdp);
+	else
+		cdns_hdmi_enable_gcp(mhdp);
+
+	ret = hdmi_avi_info_set(mhdp, mode);
+	if (ret < 0) {
+		DRM_ERROR("%s ret = %d\n", __func__, ret);
+		return;
+	}
+
+	/* vendor info frame is enable only  when HDMI1.4 4K mode */
+	hdmi_vendor_info_set(mhdp, mode);
+
+	hdmi_drm_info_set(mhdp);
+
+	ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
+	if (ret < 0) {
+		DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+		return;
+	}
+}
+
+static void handle_plugged_change(struct cdns_mhdp_device *mhdp, bool plugged)
+{
+	if (mhdp->plugged_cb && mhdp->codec_dev)
+		mhdp->plugged_cb(mhdp->codec_dev, plugged);
+}
+
+int cdns_hdmi_set_plugged_cb(struct cdns_mhdp_device *mhdp,
+			     hdmi_codec_plugged_cb fn,
+			     struct device *codec_dev)
+{
+	bool plugged;
+
+	mutex_lock(&mhdp->lock);
+	mhdp->plugged_cb = fn;
+	mhdp->codec_dev = codec_dev;
+	plugged = mhdp->last_connector_result == connector_status_connected;
+	handle_plugged_change(mhdp, plugged);
+	mutex_unlock(&mhdp->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_set_plugged_cb);
+
+static enum drm_connector_status
+cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdns_mhdp_device *mhdp =
+				container_of(connector, struct cdns_mhdp_device, connector.base);
+	enum drm_connector_status result;
+
+	u8 hpd = 0xf;
+
+	hpd = cdns_mhdp_read_hpd(mhdp);
+
+	if (hpd == 1)
+		/* Cable Connected */
+		result = connector_status_connected;
+	else if (hpd == 0)
+		/* Cable Disconnedted */
+		result = connector_status_disconnected;
+	else {
+		/* Cable status unknown */
+		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+		result = connector_status_unknown;
+	}
+
+	mutex_lock(&mhdp->lock);
+	if (result != mhdp->last_connector_result) {
+		handle_plugged_change(mhdp,
+				      result == connector_status_connected);
+		mhdp->last_connector_result = result;
+	}
+	mutex_unlock(&mhdp->lock);
+
+	return result;
+}
+
+static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdns_mhdp_device *mhdp =
+				container_of(connector, struct cdns_mhdp_device, connector.base);
+	int num_modes = 0;
+	struct edid *edid;
+	struct cec_adapter *adap;
+	bool set_pa = false;
+	u16 pa = CEC_PHYS_ADDR_INVALID;
+
+	if (of_get_property(mhdp->dev->of_node, "init-cec-pa-from-edid", NULL))
+		set_pa = true;
+
+	edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_hdmi_get_edid_block, mhdp);
+	if (edid) {
+		if (set_pa)
+			pa = cec_get_edid_phys_addr((const u8 *)edid, EDID_LENGTH * (edid->extensions + 1), NULL);
+		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+			 edid->header[0], edid->header[1],
+			 edid->header[2], edid->header[3],
+			 edid->header[4], edid->header[5],
+			 edid->header[6], edid->header[7]);
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		mhdp->hdmi.hdmi_type = drm_detect_hdmi_monitor(edid) ?
+						MODE_HDMI_1_4 : MODE_DVI;
+		kfree(edid);
+	}
+
+	if (num_modes == 0)
+		DRM_ERROR("Invalid edid\n");
+
+	if (set_pa) {
+		DRM_INFO("HDMI/DP physical address: %x.%x.%x.%x\n",cec_phys_addr_exp(pa));
+		adap = mhdp->hdmi.cec.adap;
+		if (PTR_ERR_OR_ZERO(adap))
+			DRM_INFO("Get cec adapter fail!\n");
+		else
+			cec_s_phys_addr(adap, pa, false);
+	}
+
+	return num_modes;
+}
+
+static bool blob_equal(const struct drm_property_blob *a,
+		       const struct drm_property_blob *b)
+{
+	if (a && b)
+		return a->length == b->length &&
+			!memcmp(a->data, b->data, a->length);
+
+	return !a == !b;
+}
+
+static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector,
+					    struct drm_atomic_state *state)
+{
+	struct drm_connector_state *new_con_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct drm_connector_state *old_con_state =
+		drm_atomic_get_old_connector_state(state, connector);
+	struct drm_crtc *crtc = new_con_state->crtc;
+	struct drm_crtc_state *new_crtc_state;
+
+	if (!blob_equal(new_con_state->hdr_output_metadata,
+			old_con_state->hdr_output_metadata) ||
+	    new_con_state->colorspace != old_con_state->colorspace) {
+		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(new_crtc_state))
+			return PTR_ERR(new_crtc_state);
+
+		new_crtc_state->mode_changed =
+			!new_con_state->hdr_output_metadata ||
+			!old_con_state->hdr_output_metadata ||
+			new_con_state->colorspace != old_con_state->colorspace;
+	}
+
+	return 0;
+}
+
+static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = cdns_hdmi_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
+	.get_modes = cdns_hdmi_connector_get_modes,
+	.atomic_check = cdns_hdmi_connector_atomic_check,
+};
+
+static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_mode_config *config = &bridge->dev->mode_config;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	connector->interlace_allowed = 1;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
+
+	drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+
+	if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
+		drm_object_attach_property(&connector->base,
+					   config->hdr_output_metadata_property,
+					   0);
+
+		if (!drm_mode_create_colorspace_property(connector))
+			drm_object_attach_property(&connector->base,
+						connector->colorspace_property,
+						0);
+	}
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static enum drm_mode_status
+cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	enum drm_mode_status mode_status = MODE_OK;
+	u32 vic;
+	int ret;
+
+	/* We don't support double-clocked and Interlaced modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	/* MAX support pixel clock rate 594MHz */
+	if (mode->clock > 594000)
+		return MODE_CLOCK_HIGH;
+
+	/* 5120 x 2160 is the maximum supported resolution */
+	if (mode->hdisplay > 5120 || mode->vdisplay > 2160)
+		return MODE_BAD_HVALUE;
+
+	/* imx8mq-hdmi does not support non CEA modes */
+	if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
+		vic = drm_match_cea_mode(mode);
+		if (vic == 0)
+			return MODE_BAD;
+	}
+
+	mhdp->valid_mode = mode;
+	ret = cdns_mhdp_plat_call(mhdp, phy_video_valid);
+	if (ret == false)
+		return MODE_CLOCK_RANGE;
+
+	return mode_status;
+}
+
+static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *orig_mode,
+				    const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct video_info *video = &mhdp->video_info;
+
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
+	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+	mutex_lock(&mhdp->lock);
+	cdns_hdmi_mode_set(mhdp);
+	mutex_unlock(&mhdp->lock);
+	/* reset force mode set flag */
+	mhdp->force_mode_set = false;
+}
+
+bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_display_info *di = &mhdp->connector.base.display_info;
+	struct video_info *video = &mhdp->video_info;
+	int vic = drm_match_cea_mode(mode);
+
+	video->color_depth = 8;
+	video->color_fmt = PXL_RGB;
+
+	/* for all other platforms, other than imx8mq */
+	if (strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
+		if (di->bpc == 10 || di->bpc == 6)
+			video->color_depth = di->bpc;
+
+		return true;
+	}
+
+	/* imx8mq */
+	if (vic == 97 || vic == 96) {
+		if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
+			video->color_depth = 12;
+		else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
+			video->color_depth = 10;
+
+		if (drm_mode_is_420_only(di, mode) ||
+		    (drm_mode_is_420_also(di, mode) &&
+		     video->color_depth > 8)) {
+			video->color_fmt = YCBCR_4_2_0;
+
+			adjusted_mode->private_flags = 1;
+			return true;
+		}
+
+		video->color_depth = 8;
+		return true;
+	}
+
+	/* Any defined maximum tmds clock limit we must not exceed*/
+	if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36) &&
+	    (mode->clock * 3 / 2 <= di->max_tmds_clock))
+		video->color_depth = 12;
+	else if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
+		 (mode->clock * 5 / 4 <= di->max_tmds_clock))
+		video->color_depth = 10;
+
+	/* 10-bit color depth for the following modes is not supported */
+	if ((vic == 95 || vic == 94 || vic == 93) && video->color_depth == 10)
+		video->color_depth = 8;
+
+	return true;
+}
+
+static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
+	.attach = cdns_hdmi_bridge_attach,
+	.mode_set = cdns_hdmi_bridge_mode_set,
+	.mode_valid = cdns_hdmi_bridge_mode_valid,
+	.mode_fixup = cdns_hdmi_bridge_mode_fixup,
+};
+
+static void hotplug_work_func(struct work_struct *work)
+{
+	struct cdns_mhdp_device *mhdp = container_of(work,
+					   struct cdns_mhdp_device, hotplug_work.work);
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	if (connector->status == connector_status_connected) {
+		DRM_INFO("HDMI Cable Plug In\n");
+		mhdp->force_mode_set = true;
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	} else if (connector->status == connector_status_disconnected) {
+		/* Cable Disconnedted  */
+		DRM_INFO("HDMI Cable Plug Out\n");
+		/* force mode set for cable replugin to recovery HDMI2.0 video modes */
+		mhdp->force_mode_set = true;
+		enable_irq(mhdp->irq[IRQ_IN]);
+	}
+}
+
+static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
+{
+	struct cdns_mhdp_device *mhdp = data;
+
+	disable_irq_nosync(irq);
+
+	mod_delayed_work(system_wq, &mhdp->hotplug_work,
+			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+	return IRQ_HANDLED;
+}
+
+static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp)
+{
+	struct device_node *of_node = mhdp->dev->of_node;
+	int ret;
+
+	ret = of_property_read_u32(of_node, "lane-mapping", &mhdp->lane_mapping);
+	if (ret) {
+		mhdp->lane_mapping = 0xc6;
+		dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
+	}
+	dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping);
+}
+
+static int __cdns_hdmi_probe(struct platform_device *pdev,
+		  struct cdns_mhdp_device *mhdp)
+{
+	struct device *dev = &pdev->dev;
+	struct platform_device_info pdevinfo;
+	struct resource *iores = NULL;
+	int ret;
+
+	mutex_init(&mhdp->lock);
+	mutex_init(&mhdp->iolock);
+
+	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores));
+	if (IS_ERR(mhdp->regs_base)) {
+		dev_err(dev, "No regs_base memory\n");
+		return -ENOMEM;
+	}
+
+	/* sec register base */
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	mhdp->regs_sec = devm_ioremap(dev, iores->start, resource_size(iores));
+	if (IS_ERR(mhdp->regs_sec)) {
+		dev_err(dev, "No regs_sec memory\n");
+		return -ENOMEM;
+	}
+
+	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+	if (mhdp->irq[IRQ_IN] < 0) {
+		dev_info(dev, "No plug_in irq number\n");
+		return -EPROBE_DEFER;
+	}
+
+	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+	if (mhdp->irq[IRQ_OUT] < 0) {
+		dev_info(dev, "No plug_out irq number\n");
+		return -EPROBE_DEFER;
+	}
+
+	cdns_mhdp_plat_call(mhdp, power_on);
+
+	/* Initialize FW */
+	cdns_mhdp_plat_call(mhdp, firmware_init);
+
+	/* HDMI FW alive check */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		dev_err(dev, "NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* Enable Hotplug Detect thread */
+	irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+					NULL, cdns_hdmi_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+	if (ret < 0) {
+		dev_err(dev, "can't claim irq %d\n",
+						mhdp->irq[IRQ_IN]);
+		return -EINVAL;
+	}
+	
+	irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+					NULL, cdns_hdmi_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+	if (ret < 0) {
+		dev_err(dev, "can't claim irq %d\n",
+						mhdp->irq[IRQ_OUT]);
+		return -EINVAL;
+	}
+
+	cdns_hdmi_parse_dt(mhdp);
+
+	if (cdns_mhdp_read_hpd(mhdp))
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	else
+		enable_irq(mhdp->irq[IRQ_IN]);
+
+	mhdp->bridge.base.driver_private = mhdp;
+	mhdp->bridge.base.funcs = &cdns_hdmi_bridge_funcs;
+#ifdef CONFIG_OF
+	mhdp->bridge.base.of_node = dev->of_node;
+#endif
+	mhdp->last_connector_result = connector_status_disconnected;
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent = dev;
+	pdevinfo.id = PLATFORM_DEVID_AUTO;
+
+	dev_set_drvdata(dev, mhdp);
+
+	/* register audio driver */
+	cdns_mhdp_register_audio_driver(dev);
+
+	/* register cec driver */
+#if IS_ENABLED(CONFIG_DRM_CDNS_HDMI_CEC)
+	cdns_mhdp_register_cec_driver(dev);
+#endif
+
+	return 0;
+}
+
+static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+{
+	cdns_mhdp_plat_call(mhdp, power_off);
+
+	/* unregister cec driver */
+#if IS_ENABLED(CONFIG_DRM_CDNS_HDMI_CEC)
+	cdns_mhdp_unregister_cec_driver(mhdp->dev);
+#endif
+	cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_hdmi_probe(struct platform_device *pdev,
+		struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret  = __cdns_hdmi_probe(pdev, mhdp);
+	if (ret < 0)
+		return ret;
+
+	drm_bridge_add(&mhdp->bridge.base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
+
+void cdns_hdmi_remove(struct platform_device *pdev)
+{
+	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&mhdp->bridge.base);
+
+	__cdns_hdmi_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+			struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_hdmi_probe(pdev, mhdp);
+	if (ret)
+		return ret;
+
+	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL);
+	if (ret) {
+		cdns_hdmi_remove(pdev);
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
+
+void cdns_hdmi_unbind(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	__cdns_hdmi_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
+
+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdn-hdmi");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include <sound/hdmi-codec.h>
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+
+#define CDNS_DP_SPDIF_CLK		200000000
+
+static u32 TMDS_rate_table[7] = {
+	25200, 27000, 54000, 74250, 148500, 297000, 594000,
+};
+
+static u32 N_table_32k[7] = {
+/* 25200/27000/54000/74250/148500/297000/594000 */
+	4096, 4096, 4096, 4096, 4096, 3072, 3072,
+};
+
+static u32 N_table_44k[7] = {
+	6272, 6272, 6272, 6272, 6272, 4704, 9408,
+};
+
+static u32 N_table_48k[7] = {
+	6144, 6144, 6144, 6144, 6144, 5120, 6144,
+};
+
+static int select_N_index(u32 pclk)
+{
+	int num = sizeof(TMDS_rate_table)/sizeof(int);
+	int i = 0;
+
+	for (i = 0; i < num ; i++)
+		if (pclk == TMDS_rate_table[i])
+			break;
+
+	if (i == num) {
+		DRM_WARN("pclkc %d is not supported!\n", pclk);
+		return num-1;
+	}
+
+	return i;
+}
+
+static void hdmi_audio_avi_set(struct cdns_mhdp_device *mhdp,
+						u32 channels)
+{
+	struct hdmi_audio_infoframe frame;
+	u8 buf[32];
+	int ret;
+
+	hdmi_audio_infoframe_init(&frame);
+
+	frame.channels = channels;
+	frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+
+	if (channels == 2)
+		frame.channel_allocation = 0;
+	else if (channels == 4)
+		frame.channel_allocation = 0x3;
+	else if (channels == 6)
+		frame.channel_allocation = 0xB;
+	else if (channels == 8)
+		frame.channel_allocation = 0x13;
+
+	ret = hdmi_audio_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
+		return;
+	}
+
+	buf[0] = 0;
+
+	cdns_mhdp_infoframe_set(mhdp, 1, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AUDIO);
+}
+
+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+			 struct audio_info *audio)
+{
+	int ret;
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+		ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
+		if (ret) {
+			DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
+
+	/* clearn the audio config and reset */
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+
+	/* reset smpl2pckt component  */
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+
+	/* reset FIFO */
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
+
+	if (audio->format == AFMT_SPDIF_INT)
+		clk_disable_unprepare(mhdp->spdif_clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_stop);
+
+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
+{
+	struct audio_info *audio = &mhdp->audio_info;
+	int ret = true;
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+		ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
+		if (ret)
+			DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_mute);
+
+static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
+				       struct audio_info *audio)
+{
+	int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
+	int idx = select_N_index(mhdp->mode.clock);
+	int numofchannels = audio->channels;
+	u32 val, ncts;
+	u32 disable_port3 = 0;
+	u32 audio_type = 0x2; /* L-PCM */
+	u32 transmission_type = 0; /* not required for L-PCM */
+
+	if (numofchannels == 2) {
+		if (mhdp->dp.num_lanes == 1)
+			sub_pckt_num = 2;
+		else
+			sub_pckt_num = 4;
+
+		i2s_port_en_val = 1;
+	} else if (numofchannels == 4) {
+		i2s_port_en_val = 3;
+	} else if (numofchannels == 6) {
+		numofchannels = 8;
+		disable_port3 = 1;
+	} else if ((numofchannels == 8) && (audio->non_pcm)) {
+		audio_type = 0x9;         /* HBR packet type */
+		transmission_type = 0x9;  /* HBR packet type */
+	}
+
+	cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
+
+	val = SYNC_WR_TO_CH_ZERO;
+	val |= disable_port3 << 4;
+	cdns_mhdp_bus_write(val, mhdp, FIFO_CNTL);
+
+	val = MAX_NUM_CH(numofchannels);
+	val |= NUM_OF_I2S_PORTS(numofchannels);
+	val |= audio_type << 7;
+	val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+
+	if (audio->sample_width == 16)
+		val = 0;
+	else if (audio->sample_width == 24)
+		val = 1 << 9;
+	else
+		val = 2 << 9;
+
+	val |= AUDIO_CH_NUM(numofchannels);
+	val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+	val |= TRANS_SMPL_WIDTH_32;
+	val |= transmission_type << 13;
+	cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
+
+	for (i = 0; i < (numofchannels + 1) / 2; i++) {
+		if (audio->sample_width == 16)
+			val = (0x02 << 8) | (0x02 << 20);
+		else if (audio->sample_width == 24)
+			val = (0x0b << 8) | (0x0b << 20);
+
+		val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+		cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
+	}
+
+	switch (audio->sample_rate) {
+	case 32000:
+		val = SAMPLING_FREQ(3) |
+		      ORIGINAL_SAMP_FREQ(0xc);
+		ncts = N_table_32k[idx];
+		break;
+	case 44100:
+		val = SAMPLING_FREQ(0) |
+		      ORIGINAL_SAMP_FREQ(0xf);
+		ncts = N_table_44k[idx];
+		break;
+	case 48000:
+		val = SAMPLING_FREQ(2) |
+		      ORIGINAL_SAMP_FREQ(0xd);
+		ncts = N_table_48k[idx];
+		break;
+	case 88200:
+		val = SAMPLING_FREQ(8) |
+		      ORIGINAL_SAMP_FREQ(0x7);
+		ncts = N_table_44k[idx] * 2;
+		break;
+	case 96000:
+		val = SAMPLING_FREQ(0xa) |
+		      ORIGINAL_SAMP_FREQ(5);
+		ncts = N_table_48k[idx] * 2;
+		break;
+	case 176400:
+		val = SAMPLING_FREQ(0xc) |
+		      ORIGINAL_SAMP_FREQ(3);
+		ncts = N_table_44k[idx] * 4;
+		break;
+	case 192000:
+	default:
+		val = SAMPLING_FREQ(0xe) |
+		      ORIGINAL_SAMP_FREQ(1);
+		ncts = N_table_48k[idx] * 4;
+		break;
+	}
+	val |= 4;
+	cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		cdns_mhdp_reg_write(mhdp, CM_I2S_CTRL, ncts | 0x4000000);
+
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
+}
+
+static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+
+	val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+
+	val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+	cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
+
+	clk_prepare_enable(mhdp->spdif_clk);
+	clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+}
+
+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+			   struct audio_info *audio)
+{
+	int ret;
+
+	/* reset the spdif clk before config */
+	if (audio->format == AFMT_SPDIF_INT) {
+		reset_control_assert(mhdp->spdif_rst);
+		reset_control_deassert(mhdp->spdif_rst);
+	}
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+		ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
+		if (ret)
+			goto err_audio_config;
+
+		ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
+		if (ret)
+			goto err_audio_config;
+	} else {
+		/* HDMI Mode */
+		ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 8);
+		if (ret)
+			goto err_audio_config;
+	}
+
+	if (audio->format == AFMT_I2S)
+		cdns_mhdp_audio_config_i2s(mhdp, audio);
+	else if (audio->format == AFMT_SPDIF_INT)
+		cdns_mhdp_audio_config_spdif(mhdp);
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
+		ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+
+	if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		hdmi_audio_avi_set(mhdp, audio->channels);
+
+err_audio_config:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_config);
+
+static int audio_hw_params(struct device *dev,  void *data,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct audio_info audio = {
+		.sample_width = params->sample_width,
+		.sample_rate = params->sample_rate,
+		.channels = params->channels,
+		.connector_type = mhdp->connector.base.connector_type,
+	};
+	int ret;
+
+	switch (daifmt->fmt) {
+	case HDMI_I2S:
+		audio.format = AFMT_I2S;
+		break;
+	case HDMI_SPDIF:
+		audio.format = AFMT_SPDIF_EXT;
+		break;
+	default:
+		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	audio.non_pcm = params->iec.status[0] & IEC958_AES0_NONAUDIO;
+
+	ret = cdns_mhdp_audio_config(mhdp, &audio);
+	if (!ret)
+		mhdp->audio_info = audio;
+
+out:
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
+	if (!ret)
+		mhdp->audio_info.format = AFMT_UNUSED;
+}
+
+static int audio_digital_mute(struct device *dev, void *data,
+				     bool enable)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_mute(mhdp, enable);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+				u8 *buf, size_t len)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	memcpy(buf, mhdp->connector.base.eld,
+	       min(sizeof(mhdp->connector.base.eld), len));
+
+	return 0;
+}
+
+static int audio_hook_plugged_cb(struct device *dev, void *data,
+				 hdmi_codec_plugged_cb fn,
+				 struct device *codec_dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	return cdns_hdmi_set_plugged_cb(mhdp, fn, codec_dev);
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.digital_mute = audio_digital_mute,
+	.get_eld = audio_get_eld,
+	.hook_plugged_cb = audio_hook_plugged_cb,
+};
+
+int cdns_mhdp_register_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 1,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+	};
+
+	mhdp->audio_pdev = platform_device_register_data(
+			      dev, HDMI_CODEC_DRV_NAME, 1,
+			      &codec_data, sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
+}
+
+void cdns_mhdp_unregister_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	platform_device_unregister(mhdp->audio_pdev);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/workqueue.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <drm/bridge/cdns-mhdp.h>
+
+#define CEC_NAME	"cdns-mhdp-cec"
+
+#define REG_ADDR_OFF 4
+
+/* regsiter define */
+#define TX_MSG_HEADER 0x33800
+#define TX_MSG_LENGTH 0x33840
+#define TX_MSG_CMD 0x33844
+#define RX_MSG_CMD 0x33850
+#define RX_CLEAR_BUF 0x33854
+#define LOGICAL_ADDRESS_LA0 0x33858
+
+#define CLK_DIV_MSB 0x3386c
+#define CLK_DIV_LSB 0x33870
+#define RX_MSG_DATA1 0x33900
+#define RX_MSG_LENGTH 0x33940
+#define RX_MSG_STATUS 0x33944
+#define NUM_OF_MSG_RX_BUF 0x33948
+#define TX_MSG_STATUS 0x3394c
+#define DB_L_TIMER 0x33980
+
+/**
+ * CEC Transceiver operation.
+ */
+enum {
+	CEC_TX_STOP,
+	CEC_TX_TRANSMIT,
+	CEC_TX_ABORT,
+	CEC_TX_ABORT_AND_TRANSMIT
+};
+
+/**
+ * CEC Transceiver status.
+ */
+enum {
+	CEC_STS_IDLE,
+	CEC_STS_BUSY,
+	CEC_STS_SUCCESS,
+	CEC_STS_ERROR
+};
+
+/**
+ * CEC Receiver operation.
+ */
+enum {
+	CEC_RX_STOP,
+	CEC_RX_READ,
+	CEC_RX_DISABLE,
+	CEC_RX_ABORT_AND_CLR_FIFO
+};
+/**
+ * Maximum number of Messages in the RX Buffers.
+ */
+#define CEC_MAX_RX_MSGS 2
+
+static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset)
+{
+	struct cdns_mhdp_device *mhdp =
+			container_of(cec, struct cdns_mhdp_device, hdmi.cec);
+	return cdns_mhdp_bus_read(mhdp, offset);
+}
+
+static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val)
+{
+	struct cdns_mhdp_device *mhdp =
+			container_of(cec, struct cdns_mhdp_device, hdmi.cec);
+	cdns_mhdp_bus_write(val, mhdp, offset);
+}
+
+static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec)
+{
+	mhdp_cec_write(cec, RX_CLEAR_BUF, 1);
+	mhdp_cec_write(cec, RX_CLEAR_BUF, 0);
+}
+
+static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec)
+{
+	struct cdns_mhdp_device *mhdp =
+			container_of(cec, struct cdns_mhdp_device, hdmi.cec);
+	u32 clk_div;
+
+	/* Set clock divider */
+	clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10;
+
+	mhdp_cec_write(cec, CLK_DIV_MSB,
+			  (clk_div >> 8) & 0xFF);
+	mhdp_cec_write(cec, CLK_DIV_LSB, clk_div & 0xFF);
+}
+
+static u32 mhdp_cec_read_message(struct cdns_mhdp_cec *cec)
+{
+	struct cec_msg *msg = &cec->msg;
+	int len;
+	int i;
+
+	mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
+
+	len = mhdp_cec_read(cec, RX_MSG_LENGTH);
+	msg->len = len + 1;
+	dev_dbg(cec->dev, "RX MSG len =%d\n", len);
+
+	/* Read RX MSG bytes */
+	for (i = 0; i < msg->len; ++i) {
+		msg->msg[i] = (u8) mhdp_cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
+		dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
+	}
+
+	mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
+
+	return true;
+}
+
+static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg)
+{
+	u8 i;
+
+	mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+
+	if (msg->len > CEC_MAX_MSG_SIZE) {
+		dev_err(cec->dev, "Invalid MSG size!\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < msg->len; ++i)
+		printk("msg[%d]=0x%x\n",i, msg->msg[i]);
+
+	/* Write Message to register */
+	for (i = 0; i < msg->len; ++i) {
+		mhdp_cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
+			  msg->msg[i]);
+	}
+	/* Write Message Length (payload + opcode) */
+	mhdp_cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
+
+	mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
+
+	return true;
+}
+
+static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la)
+{
+	u8 la_reg;
+	u8 i;
+
+	if (la == CEC_LOG_ADDR_INVALID)
+		/* invalid all LA address */
+		for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) {
+			mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), 0);
+			return 0;
+		}
+
+	/* In fact cdns mhdp cec could support max 5 La address */
+	for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) {
+		la_reg = mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
+		/* Check LA already used */
+		if (la_reg & 0x10)
+			continue;
+
+		if ((la_reg & 0xF) == la) {
+			dev_warn(cec->dev, "Warning. LA already in use.\n");
+			return 0;
+		}
+
+		la = (la & 0xF) | (1 << 4);
+
+		mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
+		return 0;
+	}
+
+	dev_warn(cec->dev, "All LA in use\n");
+
+	return -ENXIO;
+}
+
+static int mhdp_cec_poll_worker(void *_cec)
+{
+	struct cdns_mhdp_cec *cec = (struct cdns_mhdp_cec *)_cec;
+	int num_rx_msgs, i;
+	int sts;
+
+	set_freezable();
+
+	for (;;) {
+		if (kthread_freezable_should_stop(NULL))
+			break;
+
+		/* Check TX State */
+		sts = mhdp_cec_read(cec, TX_MSG_STATUS);
+		switch (sts) {
+		case CEC_STS_SUCCESS:
+			cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0,
+					  0);
+			mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+			break;
+		case CEC_STS_ERROR:
+			mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+			cec_transmit_done(cec->adap,
+					  CEC_TX_STATUS_MAX_RETRIES |
+					  CEC_TX_STATUS_NACK, 0, 1, 0, 0);
+			break;
+		case CEC_STS_BUSY:
+		default:
+			break;
+		}
+
+		/* Check RX State */
+		sts = mhdp_cec_read(cec, RX_MSG_STATUS);
+		num_rx_msgs = mhdp_cec_read(cec, NUM_OF_MSG_RX_BUF);
+		switch (sts) {
+		case CEC_STS_SUCCESS:
+			if (num_rx_msgs == 0xf)
+				num_rx_msgs = CEC_MAX_RX_MSGS;
+
+			if (num_rx_msgs > CEC_MAX_RX_MSGS) {
+				dev_err(cec->dev, "Error rx msg num %d\n",
+					num_rx_msgs);
+				mhdp_cec_clear_rx_buffer(cec);
+				break;
+			}
+
+			/* Rx FIFO Depth 2 RX MSG */
+			for (i = 0; i < num_rx_msgs; i++) {
+				mhdp_cec_read_message(cec);
+				cec->msg.rx_status = CEC_RX_STATUS_OK;
+				cec_received_msg(cec->adap, &cec->msg);
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (!kthread_should_stop())
+			schedule_timeout_idle(20);
+	}
+
+	return 0;
+}
+
+static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+	struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+
+	if (enable) {
+		mhdp_cec_write(cec, DB_L_TIMER, 0x10);
+		mhdp_cec_set_divider(cec);
+	} else
+		mhdp_cec_set_divider(cec);
+
+	return 0;
+}
+
+static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
+{
+	struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+
+	return mhdp_cec_set_logical_addr(cec, addr);
+}
+
+static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+				 u32 signal_free_time, struct cec_msg *msg)
+{
+	struct cdns_mhdp_cec *cec = cec_get_drvdata(adap);
+
+	mhdp_cec_write_message(cec, msg);
+
+	return 0;
+}
+
+static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = {
+	.adap_enable = mhdp_cec_adap_enable,
+	.adap_log_addr = mhdp_cec_adap_log_addr,
+	.adap_transmit = mhdp_cec_adap_transmit,
+};
+
+int cdns_mhdp_register_cec_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
+	int ret;
+	u32 caps = CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
+		   CEC_CAP_PASSTHROUGH | CEC_CAP_RC;
+
+	if (of_get_property(mhdp->dev->of_node, "init-cec-pa-from-edid", NULL))
+		caps &= (~CEC_CAP_PHYS_ADDR);
+
+	cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec,
+					 CEC_NAME, caps, CEC_MAX_LOG_ADDRS);
+	ret = PTR_ERR_OR_ZERO(cec->adap);
+	if (ret)
+		return ret;
+	ret = cec_register_adapter(cec->adap, dev);
+	if (ret) {
+		cec_delete_adapter(cec->adap);
+		return ret;
+	}
+
+	cec->dev = dev;
+
+	cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec");
+	if (IS_ERR(cec->cec_worker))
+		dev_err(cec->dev, "failed  create hdp cec thread\n");
+
+	wake_up_process(cec->cec_worker);
+
+	dev_dbg(dev, "CEC successfuly probed\n");
+	return 0;
+}
+
+int cdns_mhdp_unregister_cec_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
+
+	if (cec->cec_worker) {
+		kthread_stop(cec->cec_worker);
+		cec->cec_worker = NULL;
+	}
+	cec_unregister_adapter(cec->adap);
+	return 0;
+}
+
+MODULE_AUTHOR("Sandor.Yu@NXP.com");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NXP CDNS MHDP HDMI CEC driver");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
@@ -0,0 +1,795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include <asm/unaligned.h>
+
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
+#include <linux/regmap.h>
+
+#define CDNS_DP_SPDIF_CLK		200000000
+#define FW_ALIVE_TIMEOUT_US		1000000
+#define MAILBOX_RETRY_US		1000
+#define MAILBOX_TIMEOUT_US		5000000
+
+#define mhdp_readx_poll_timeout(op, addr, offset, val, cond, sleep_us, timeout_us)	\
+({ \
+	u64 __timeout_us = (timeout_us); \
+	unsigned long __sleep_us = (sleep_us); \
+	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
+	might_sleep_if((__sleep_us) != 0); \
+	for (;;) { \
+		(val) = op(addr, offset); \
+		if (cond) \
+			break; \
+		if (__timeout_us && \
+		    ktime_compare(ktime_get(), __timeout) > 0) { \
+			(val) = op(addr, offset); \
+			break; \
+		} \
+		if (__sleep_us) \
+			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset)
+{
+	u32 val;
+
+	mutex_lock(&mhdp->iolock);
+
+	if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
+		/* Remap address to low 4K SAPB bus */
+		writel(offset >> 12, mhdp->regs_sec + 0xc);
+		val = readl((offset & 0xfff) + mhdp->regs_base);
+	} else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) {
+		/* Remap address to low 4K memory */
+		writel(offset >> 12, mhdp->regs_sec + 8);
+		val = readl((offset & 0xfff) + mhdp->regs_base);
+	} else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB)
+		val = readl(mhdp->regs_sec + offset);
+	else
+		val = readl(mhdp->regs_base + offset);
+
+	mutex_unlock(&mhdp->iolock);
+
+	return val;
+}
+EXPORT_SYMBOL(cdns_mhdp_bus_read);
+
+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset)
+{
+	mutex_lock(&mhdp->iolock);
+
+	if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) {
+		/* Remap address to low 4K SAPB bus */
+		writel(offset >> 12, mhdp->regs_sec + 0xc);
+		writel(val, (offset & 0xfff) + mhdp->regs_base);
+	} else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) {
+		/* Remap address to low 4K memory */
+		writel(offset >> 12, mhdp->regs_sec + 8);
+		writel(val, (offset & 0xfff) + mhdp->regs_base);
+	} else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB)
+		writel(val, mhdp->regs_sec + offset);
+	else
+		writel(val, mhdp->regs_base + offset);
+
+	mutex_unlock(&mhdp->iolock);
+}
+EXPORT_SYMBOL(cdns_mhdp_bus_write);
+
+u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp)
+{
+	return cdns_mhdp_bus_read(mhdp, SW_CLK_H);
+}
+EXPORT_SYMBOL(cdns_mhdp_get_fw_clk);
+
+void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
+{
+	cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H);
+}
+EXPORT_SYMBOL(cdns_mhdp_set_fw_clk);
+
+void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	val = DPTX_FRMR_DATA_CLK_RSTN_EN |
+	      DPTX_FRMR_DATA_CLK_EN |
+	      DPTX_PHY_DATA_RSTN_EN |
+	      DPTX_PHY_DATA_CLK_EN |
+	      DPTX_PHY_CHAR_RSTN_EN |
+	      DPTX_PHY_CHAR_CLK_EN |
+	      SOURCE_AUX_SYS_CLK_RSTN_EN |
+	      SOURCE_AUX_SYS_CLK_EN |
+	      DPTX_SYS_CLK_RSTN_EN |
+	      DPTX_SYS_CLK_EN |
+	      CFG_DPTX_VIF_CLK_RSTN_EN |
+	      CFG_DPTX_VIF_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_DPTX_CAR);
+
+	val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PHY_CAR);
+
+	val = SOURCE_PKT_SYS_RSTN_EN |
+	      SOURCE_PKT_SYS_CLK_EN |
+	      SOURCE_PKT_DATA_RSTN_EN |
+	      SOURCE_PKT_DATA_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PKT_CAR);
+
+	val = SPDIF_CDR_CLK_RSTN_EN |
+	      SPDIF_CDR_CLK_EN |
+	      SOURCE_AIF_SYS_RSTN_EN |
+	      SOURCE_AIF_SYS_CLK_EN |
+	      SOURCE_AIF_CLK_RSTN_EN |
+	      SOURCE_AIF_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_AIF_CAR);
+
+	val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
+	      SOURCE_CIPHER_SYS_CLK_EN |
+	      SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
+	      SOURCE_CIPHER_CHAR_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_CIPHER_CAR);
+
+	val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
+	      SOURCE_CRYPTO_SYS_CLK_EN;
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_CRYPTO_CAR);
+
+	/* enable Mailbox and PIF interrupt */
+	cdns_mhdp_bus_write(0, mhdp, APB_INT_MASK);
+}
+EXPORT_SYMBOL(cdns_mhdp_clock_reset);
+
+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp)
+{
+	u32  alive, newalive;
+	u8 retries_left = 50;
+
+	alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+
+	while (retries_left--) {
+		udelay(2);
+
+		newalive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+		if (alive == newalive)
+			continue;
+		return true;
+	}
+	return false;
+}
+EXPORT_SYMBOL(cdns_mhdp_check_alive);
+
+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
+{
+	int val, ret;
+
+	ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_EMPTY_ADDR,
+				 val, !val, MAILBOX_RETRY_US,
+				 MAILBOX_TIMEOUT_US);
+	if (ret < 0)
+		return ret;
+
+	return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
+{
+	int ret, full;
+
+	ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_FULL_ADDR,
+				 full, !full, MAILBOX_RETRY_US,
+				 MAILBOX_TIMEOUT_US);
+	if (ret < 0)
+		return ret;
+
+	cdns_mhdp_bus_write(val, mhdp, MAILBOX0_WR_DATA);
+
+	return 0;
+}
+
+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
+					      u8 module_id, u8 opcode,
+					      u16 req_size)
+{
+	u32 mbox_size, i;
+	u8 header[4];
+	int ret;
+
+	/* read the header of the message */
+	for (i = 0; i < 4; i++) {
+		ret = mhdp_mailbox_read(mhdp);
+		if (ret < 0)
+			return ret;
+
+		header[i] = ret;
+	}
+
+	mbox_size = get_unaligned_be16(header + 2);
+
+	if (opcode != header[0] || module_id != header[1] ||
+	    req_size != mbox_size) {
+		/*
+		 * If the message in mailbox is not what we want, we need to
+		 * clear the mailbox by reading its contents.
+		 */
+		for (i = 0; i < mbox_size; i++)
+			if (mhdp_mailbox_read(mhdp) < 0)
+				break;
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_mailbox_validate_receive);
+
+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
+					  u8 *buff, u16 buff_size)
+{
+	u32 i;
+	int ret;
+
+	for (i = 0; i < buff_size; i++) {
+		ret = mhdp_mailbox_read(mhdp);
+		if (ret < 0)
+			return ret;
+
+		buff[i] = ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_mailbox_read_receive);
+
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
+				  u8 opcode, u16 size, u8 *message)
+{
+	u8 header[4];
+	int ret, i;
+
+	header[0] = opcode;
+	header[1] = module_id;
+	put_unaligned_be16(size, header + 2);
+
+	for (i = 0; i < 4; i++) {
+		ret = mhdp_mailbox_write(mhdp, header[i]);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < size; i++) {
+		ret = mhdp_mailbox_write(mhdp, message[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_mailbox_send);
+
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
+{
+	u8 msg[4], resp[8];
+	u32 val;
+	int ret;
+
+	if (addr == 0) {
+		ret = -EINVAL;
+		goto err_reg_read;
+	}
+
+	put_unaligned_be32(addr, msg);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
+				     GENERAL_READ_REGISTER,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_reg_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
+						 GENERAL_READ_REGISTER,
+						 sizeof(resp));
+	if (ret)
+		goto err_reg_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, resp, sizeof(resp));
+	if (ret)
+		goto err_reg_read;
+
+	/* Returned address value should be the same as requested */
+	if (memcmp(msg, resp, sizeof(msg))) {
+		ret = -EINVAL;
+		goto err_reg_read;
+	}
+
+	val = get_unaligned_be32(resp + 4);
+
+	return val;
+err_reg_read:
+	DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n");
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_reg_read);
+
+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
+{
+	u8 msg[8];
+
+	put_unaligned_be32(addr, msg);
+	put_unaligned_be32(val, msg + 4);
+
+	return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
+				      GENERAL_WRITE_REGISTER, sizeof(msg), msg);
+}
+EXPORT_SYMBOL(cdns_mhdp_reg_write);
+
+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
+				   u8 start_bit, u8 bits_no, u32 val)
+{
+	u8 field[8];
+
+	put_unaligned_be16(addr, field);
+	field[2] = start_bit;
+	field[3] = bits_no;
+	put_unaligned_be32(val, field + 4);
+
+	return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				      DPTX_WRITE_FIELD, sizeof(field), field);
+}
+EXPORT_SYMBOL(cdns_mhdp_reg_write_bit);
+
+int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+			    u32 i_size, const u32 *d_mem, u32 d_size)
+{
+	u32 reg;
+	int i, ret;
+
+	/* reset ucpu before load firmware*/
+	cdns_mhdp_bus_write(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+	       mhdp, APB_CTRL);
+
+	for (i = 0; i < i_size; i += 4)
+		cdns_mhdp_bus_write(*i_mem++, mhdp, ADDR_IMEM + i);
+
+	for (i = 0; i < d_size; i += 4)
+		cdns_mhdp_bus_write(*d_mem++, mhdp, ADDR_DMEM + i);
+
+	/* un-reset ucpu */
+	cdns_mhdp_bus_write(0, mhdp, APB_CTRL);
+
+	/* check the keep alive register to make sure fw working */
+	ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, KEEP_ALIVE,
+				 reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+	if (ret < 0) {
+		DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
+			      reg);
+		return -EINVAL;
+	}
+
+	reg = cdns_mhdp_bus_read(mhdp, VER_L) & 0xff;
+	mhdp->fw_version = reg;
+	reg = cdns_mhdp_bus_read(mhdp, VER_H) & 0xff;
+	mhdp->fw_version |= reg << 8;
+	reg = cdns_mhdp_bus_read(mhdp, VER_LIB_L_ADDR) & 0xff;
+	mhdp->fw_version |= reg << 16;
+	reg = cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) & 0xff;
+	mhdp->fw_version |= reg << 24;
+
+	DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_load_firmware);
+
+int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
+{
+	u8 msg[5];
+	int ret, i;
+
+	msg[0] = GENERAL_MAIN_CONTROL;
+	msg[1] = MB_MODULE_ID_GENERAL;
+	msg[2] = 0;
+	msg[3] = 1;
+	msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
+
+	for (i = 0; i < sizeof(msg); i++) {
+		ret = mhdp_mailbox_write(mhdp, msg[i]);
+		if (ret)
+			goto err_set_firmware_active;
+	}
+
+	/* read the firmware state */
+	for (i = 0; i < sizeof(msg); i++)  {
+		ret = mhdp_mailbox_read(mhdp);
+		if (ret < 0)
+			goto err_set_firmware_active;
+
+		msg[i] = ret;
+	}
+
+	ret = 0;
+
+err_set_firmware_active:
+	if (ret < 0)
+		DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
+
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp)
+{
+	u8 msg[8];
+	int ret;
+
+	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
+	msg[2] = VOLTAGE_LEVEL_3;
+	msg[3] = PRE_EMPHASIS_LEVEL_2;
+	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = mhdp->lane_mapping;
+	msg[7] = ENHANCED;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_HOST_CAPABILITIES,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_set_host_cap;
+
+/* TODO Sandor */
+//	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+//				  AUX_HOST_INVERT);
+
+err_set_host_cap:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
+
+int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
+{
+	u8 msg[5];
+	int ret;
+
+	memset(msg, 0, sizeof(msg));
+
+	msg[0] = MHDP_EVENT_ENABLE_HPD | MHDP_EVENT_ENABLE_TRAINING;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_ENABLE_EVENT, sizeof(msg), msg);
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_event_config);
+
+u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
+{
+	return cdns_mhdp_bus_read(mhdp, SW_EVENTS0);
+}
+EXPORT_SYMBOL(cdns_mhdp_get_event);
+
+int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp)
+{
+	u8 status;
+	int ret;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE,
+				  0, NULL);
+	if (ret)
+		goto err_get_hpd;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
+							GENERAL_GET_HPD_STATE, sizeof(status));
+	if (ret)
+		goto err_get_hpd;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
+	if (ret)
+		goto err_get_hpd;
+
+	return status;
+
+err_get_hpd:
+	DRM_ERROR("read hpd  failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_read_hpd);
+
+int cdns_mhdp_get_edid_block(void *data, u8 *edid,
+			  unsigned int block, size_t length)
+{
+	struct cdns_mhdp_device *mhdp = data;
+	u8 msg[2], reg[2], i;
+	int ret;
+
+	for (i = 0; i < 4; i++) {
+		msg[0] = block / 2;
+		msg[1] = block % 2;
+
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+					     DPTX_GET_EDID, sizeof(msg), msg);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+							 MB_MODULE_ID_DP_TX,
+							 DPTX_GET_EDID,
+							 sizeof(reg) + length);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
+		if (ret)
+			continue;
+
+		if (reg[0] == length && reg[1] == block / 2)
+			break;
+	}
+
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
+			      block, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_get_edid_block);
+
+int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
+{
+	u8 msg;
+	int ret;
+
+	msg = !!active;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_VIDEO, sizeof(msg), &msg);
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_video_status);
+
+static int mhdp_get_msa_misc(struct video_info *video,
+				  struct drm_display_mode *mode)
+{
+	u32 msa_misc;
+	u8 val[2] = {0};
+
+	switch (video->color_fmt) {
+	case PXL_RGB:
+	case Y_ONLY:
+		val[0] = 0;
+		break;
+	/* set YUV default color space conversion to BT601 */
+	case YCBCR_4_4_4:
+		val[0] = 6 + BT_601 * 8;
+		break;
+	case YCBCR_4_2_2:
+		val[0] = 5 + BT_601 * 8;
+		break;
+	case YCBCR_4_2_0:
+		val[0] = 5;
+		break;
+	}
+
+	switch (video->color_depth) {
+	case 6:
+		val[1] = 0;
+		break;
+	case 8:
+		val[1] = 1;
+		break;
+	case 10:
+		val[1] = 2;
+		break;
+	case 12:
+		val[1] = 3;
+		break;
+	case 16:
+		val[1] = 4;
+		break;
+	}
+
+	msa_misc = 2 * val[0] + 32 * val[1] +
+		   ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
+
+	return msa_misc;
+}
+
+int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
+{
+	struct video_info *video = &mhdp->video_info;
+	struct drm_display_mode *mode = &mhdp->mode;
+	u64 symbol;
+	u32 val, link_rate, rem;
+	u8 bit_per_pix, tu_size_reg = TU_SIZE;
+	int ret;
+
+	bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
+		      (video->color_depth * 2) : (video->color_depth * 3);
+
+	link_rate = mhdp->dp.rate / 1000;
+
+	ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
+	if (ret)
+		goto err_config_video;
+
+	ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0);
+	if (ret)
+		goto err_config_video;
+
+	/*
+	 * get a best tu_size and valid symbol:
+	 * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32
+	 * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes)
+	 * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set
+	 *    TU += 2 and repeat 2nd step.
+	 */
+	do {
+		tu_size_reg += 2;
+		symbol = (u64) tu_size_reg * mode->clock * bit_per_pix;
+		do_div(symbol, mhdp->dp.num_lanes * link_rate * 8);
+		rem = do_div(symbol, 1000);
+		if (tu_size_reg > 64) {
+			ret = -EINVAL;
+			DRM_DEV_ERROR(mhdp->dev,
+				      "tu error, clk:%d, lanes:%d, rate:%d\n",
+				      mode->clock, mhdp->dp.num_lanes,
+				      link_rate);
+			goto err_config_video;
+		}
+	} while ((symbol <= 1) || (tu_size_reg - symbol < 4) ||
+		 (rem > 850) || (rem < 100));
+
+	val = symbol + (tu_size_reg << 8);
+	val |= TU_CNT_RST_EN;
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val);
+	if (ret)
+		goto err_config_video;
+
+	/* set the FIFO Buffer size */
+	val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate;
+	val /= (mhdp->dp.num_lanes * link_rate);
+	val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
+	val += 2;
+	ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val);
+
+	switch (video->color_depth) {
+	case 6:
+		val = BCS_6;
+		break;
+	case 8:
+		val = BCS_8;
+		break;
+	case 10:
+		val = BCS_10;
+		break;
+	case 12:
+		val = BCS_12;
+		break;
+	case 16:
+		val = BCS_16;
+		break;
+	}
+
+	val += video->color_fmt << 8;
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val);
+	if (ret)
+		goto err_config_video;
+
+	val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
+	val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val);
+	if (ret)
+		goto err_config_video;
+
+	val = (mode->hsync_start - mode->hdisplay) << 16;
+	val |= mode->htotal - mode->hsync_end;
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->hdisplay * bit_per_pix / 8;
+	ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->vtotal;
+	val |= (mode->vtotal - mode->vsync_start) << 16;
+	ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->vsync_end - mode->vsync_start;
+	val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mhdp_get_msa_misc(video, mode);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val);
+	if (ret)
+		goto err_config_video;
+
+	ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= mode->hdisplay << 16;
+	ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->vdisplay;
+	val |= (mode->vtotal - mode->vsync_start) << 16;
+	ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val);
+	if (ret)
+		goto err_config_video;
+
+	val = mode->vtotal;
+	ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val);
+	if (ret)
+		goto err_config_video;
+
+	ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0);
+
+err_config_video:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_config_video);
+
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
+{
+	return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val);
+}
+EXPORT_SYMBOL(cdns_phy_reg_write);
+
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
+{
+	return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2));
+}
+EXPORT_SYMBOL(cdns_phy_reg_read);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <asm/unaligned.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_print.h>
+#include <linux/io.h>
+
+#define LINK_TRAINING_TIMEOUT_MS	500
+#define LINK_TRAINING_RETRY_MS		20
+
+static inline u32 get_unaligned_be24(const void *p)
+{
+       const u8 *_p = p;
+
+       return _p[0] << 16 | _p[1] << 8 | _p[2];
+}
+
+static inline void put_unaligned_be24(u32 val, void *p)
+{
+       u8 *_p = p;
+
+       _p[0] = val >> 16;
+       _p[1] = val >> 8;
+       _p[2] = val;
+}
+
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+			u32 addr, u8 *data, u16 len)
+{
+	u8 msg[5], reg[5];
+	int ret;
+
+	put_unaligned_be16(len, msg);
+	put_unaligned_be24(addr, msg + 2);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_READ_DPCD, sizeof(msg), msg);
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_DPCD,
+						 sizeof(reg) + len);
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
+
+err_dpcd_read:
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_dpcd_read);
+
+int cdns_mhdp_i2c_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data,
+	 u16 len, u8 mot, u16 *respLength)
+{
+	u8 msg[5], reg[3];
+	int ret;
+
+	put_unaligned_be16(len, msg);
+	msg[2] = addr;
+	msg[3] = mot;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_I2C_READ, sizeof(msg), msg);
+	if (ret)
+		goto err_i2c_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_I2C_READ,
+						 sizeof(reg) + len);
+	if (ret)
+		goto err_i2c_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_i2c_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
+	*respLength = (reg[0] << 8u) + reg[1];
+
+err_i2c_read:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "i2c read failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_i2c_read);
+
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
+{
+	u8 msg[6], reg[5];
+	int ret;
+
+	put_unaligned_be16(1, msg);
+	put_unaligned_be24(addr, msg + 2);
+	msg[5] = value;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_WRITE_DPCD, sizeof(msg), msg);
+	if (ret)
+		goto err_dpcd_write;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_WRITE_DPCD, sizeof(reg));
+	if (ret)
+		goto err_dpcd_write;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_dpcd_write;
+
+	if (addr != get_unaligned_be24(reg + 2))
+		ret = -EINVAL;
+
+err_dpcd_write:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_dpcd_write);
+
+int cdns_mhdp_i2c_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 *value,
+	 u8 mot, u16 len, u16 *respLength)
+{
+	u8 msg[4+DP_AUX_MAX_PAYLOAD_BYTES], reg[3];
+	int ret;
+
+	put_unaligned_be16(len, msg);
+	msg[2] = addr;
+	msg[3] = mot;
+	memcpy(&msg[4], value, len);
+
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_I2C_WRITE, sizeof(msg), msg);
+	if (ret)
+		goto err_i2c_write;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_I2C_WRITE, sizeof(reg));
+	if (ret)
+		goto err_i2c_write;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_i2c_write;
+
+	if (addr != reg[2])
+		ret = -EINVAL;
+
+	*respLength = (reg[0]<<8u) + reg[1];
+
+err_i2c_write:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "i2c write failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_i2c_write);
+
+
+int cdns_mhdp_get_last_i2c_status(struct cdns_mhdp_device *mhdp, u8 *resp)
+{
+	u8 status[1];
+	int ret;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_GET_LAST_I2C_STATUS, 0, NULL);
+	if (ret)
+		goto err_get_i2c_status;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_GET_LAST_I2C_STATUS,
+						 sizeof(status));
+	if (ret)
+		goto err_get_i2c_status;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
+	if (ret)
+		goto err_get_i2c_status;
+
+	*resp = status[0];
+
+err_get_i2c_status:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "get i2c status failed: %d\n",
+			      ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_get_last_i2c_status);
+
+static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
+{
+	unsigned long timeout;
+	u8 msg, event[2];
+	int ret;
+
+	msg = LINK_TRAINING_RUN;
+
+	/* start training */
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_TRAINING_CONTROL, sizeof(msg), &msg);
+	if (ret)
+		goto err_training_start;
+
+	timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
+	while (time_before(jiffies, timeout)) {
+		msleep(LINK_TRAINING_RETRY_MS);
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+					     DPTX_READ_EVENT, 0, NULL);
+		if (ret)
+			goto err_training_start;
+
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+							 MB_MODULE_ID_DP_TX,
+							 DPTX_READ_EVENT,
+							 sizeof(event));
+		if (ret)
+			goto err_training_start;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, event,
+						     sizeof(event));
+		if (ret)
+			goto err_training_start;
+
+		if (event[1] & CLK_RECOVERY_FAILED)
+			DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n");
+		else if (event[1] & EQ_PHASE_FINISHED)
+			return 0;
+	}
+
+	ret = -ETIMEDOUT;
+
+err_training_start:
+	DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
+	return ret;
+}
+
+static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
+{
+	u8 status[10];
+	int ret;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_READ_LINK_STAT, 0, NULL);
+	if (ret)
+		goto err_get_training_status;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_LINK_STAT,
+						 sizeof(status));
+	if (ret)
+		goto err_get_training_status;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
+	if (ret)
+		goto err_get_training_status;
+
+	mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]);
+	mhdp->dp.num_lanes = status[1];
+
+err_get_training_status:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n",
+			      ret);
+	return ret;
+}
+
+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = cdns_mhdp_training_start(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n",
+			      ret);
+		return ret;
+	}
+
+	ret = cdns_mhdp_get_training_status(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n",
+			      ret);
+		return ret;
+	}
+
+	DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate,
+			  mhdp->dp.num_lanes);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_train_link);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/io.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include <linux/regmap.h>
+
+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
+					u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
+{
+	u32 *packet32, len32;
+	u32 val, i;
+
+	/* invalidate entry */
+	val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
+	cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
+
+	/* flush fifo 1 */
+	cdns_mhdp_bus_write(F_FIFO1_FLUSH(1), mhdp, SOURCE_PIF_FIFO1_FLUSH);
+
+	/* write packet into memory */
+	packet32 = (u32 *)packet;
+	len32 = packet_len / 4;
+	for (i = 0; i < len32; i++)
+		cdns_mhdp_bus_write(F_DATA_WR(packet32[i]), mhdp, SOURCE_PIF_DATA_WR);
+
+	/* write entry id */
+	cdns_mhdp_bus_write(F_WR_ADDR(entry_id), mhdp, SOURCE_PIF_WR_ADDR);
+
+	/* write request */
+	cdns_mhdp_bus_write(F_HOST_WR(1), mhdp, SOURCE_PIF_WR_REQ);
+
+	/* update entry */
+	val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
+			F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
+
+	cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
+}
+
+int cdns_hdmi_get_edid_block(void *data, u8 *edid,
+			  u32 block, size_t length)
+{
+	struct cdns_mhdp_device *mhdp = data;
+	u8 msg[2], reg[5], i;
+	int ret;
+
+	for (i = 0; i < 4; i++) {
+		msg[0] = block / 2;
+		msg[1] = block % 2;
+
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID,
+					  sizeof(msg), msg);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+						      HDMI_TX_EDID, sizeof(reg) + length);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
+		if (ret)
+			continue;
+
+		if ((reg[3] << 8 | reg[4]) == length)
+			break;
+	}
+
+	if (ret)
+		DRM_ERROR("get block[%d] edid failed: %d\n", block, ret);
+	return ret;
+}
+
+int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data)
+{
+	u8 msg[4], reg[6];
+	int ret;
+
+	msg[0] = 0x54;
+	msg[1] = addr;
+	msg[2] = 0;
+	msg[3] = 1;
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ,
+				  sizeof(msg), msg);
+	if (ret)
+		goto err_scdc_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+					      HDMI_TX_READ, sizeof(reg));
+	if (ret)
+		goto err_scdc_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_scdc_read;
+
+	*data = reg[5];
+
+err_scdc_read:
+	if (ret)
+		DRM_ERROR("scdc read failed: %d\n", ret);
+	return ret;
+}
+
+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value)
+{
+	u8 msg[5], reg[5];
+	int ret;
+
+	msg[0] = 0x54;
+	msg[1] = addr;
+	msg[2] = 0;
+	msg[3] = 1;
+	msg[4] = value;
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE,
+				  sizeof(msg), msg);
+	if (ret)
+		goto err_scdc_write;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+					      HDMI_TX_WRITE, sizeof(reg));
+	if (ret)
+		goto err_scdc_write;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_scdc_write;
+
+	if (reg[0] != 0)
+		ret = -EINVAL;
+
+err_scdc_write:
+	if (ret)
+		DRM_ERROR("scdc write failed: %d\n", ret);
+	return ret;
+}
+
+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
+				 int protocol,
+				 u32 char_rate)
+{
+	u32 reg0;
+	u32 reg1;
+	u32 val;
+	int ret;
+
+	/* Set PHY to HDMI data */
+	ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1));
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD,
+					F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0));
+	if (ret < 0)
+		return ret;
+
+	/* open CARS */
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3);
+	if (ret < 0)
+		return ret;
+
+	reg0 = reg1 = 0x7c1f;
+	if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) {
+		reg0 = 0;
+		reg1 = 0xFFFFF;
+	}
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1);
+	if (ret < 0)
+		return ret;
+
+	/* set hdmi mode and preemble mode data enable */
+	val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) |  F_DATA_EN(1) |
+			F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+
+	return ret;
+}
+
+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
+					      struct drm_display_mode *mode,
+						  struct video_info *video_info)
+{
+	int ret;
+	u32 val;
+	u32 vsync_lines = mode->vsync_end - mode->vsync_start;
+	u32 eof_lines = mode->vsync_start - mode->vdisplay;
+	u32 sof_lines = mode->vtotal - mode->vsync_end;
+	u32 hblank = mode->htotal - mode->hdisplay;
+	u32 hactive = mode->hdisplay;
+	u32 vblank = mode->vtotal - mode->vdisplay;
+	u32 vactive = mode->vdisplay;
+	u32 hfront = mode->hsync_start - mode->hdisplay;
+	u32 hback = mode->htotal - mode->hsync_end;
+	u32 vfront = eof_lines;
+	u32 hsync = hblank - hfront - hback;
+	u32 vsync = vsync_lines;
+	u32 vback = sof_lines;
+	u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) +
+						((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2);
+
+	ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive << 16) + hblank);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive << 16) + vblank);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, v_h_polarity);
+	if (ret < 0)
+		return ret;
+
+	/* Reset Data Enable */
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val &= ~F_DATA_EN(1);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+	if (ret < 0)
+		return ret;
+
+	/* Set bpc */
+	val &= ~F_VIF_DATA_WIDTH(3);
+	switch (video_info->color_depth) {
+	case 10:
+		val |= F_VIF_DATA_WIDTH(1);
+		break;
+	case 12:
+		val |= F_VIF_DATA_WIDTH(2);
+		break;
+	case 16:
+		val |= F_VIF_DATA_WIDTH(3);
+		break;
+	case 8:
+	default:
+		val |= F_VIF_DATA_WIDTH(0);
+		break;
+	}
+
+	/* select color encoding */
+	val &= ~F_HDMI_ENCODING(3);
+	switch (video_info->color_fmt) {
+	case YCBCR_4_4_4:
+		val |= F_HDMI_ENCODING(2);
+		break;
+	case YCBCR_4_2_2:
+		val |= F_HDMI_ENCODING(1);
+		break;
+	case YCBCR_4_2_0:
+		val |= F_HDMI_ENCODING(3);
+		break;
+	case PXL_RGB:
+	default:
+		val |= F_HDMI_ENCODING(0);
+		break;
+	}
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+	if (ret < 0)
+		return ret;
+
+	/* set data enable */
+	val |= F_DATA_EN(1);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+
+	return ret;
+}
+
+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val &= ~F_GCP_EN(1);
+
+	return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+}
+
+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val |= F_GCP_EN(1);
+
+	return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence MHDP DP MST bridge driver.
+ *
+ * Copyright: 2018 Cadence Design Systems, Inc.
+ *
+ * Author: Quentin Schulz <quentin.schulz@free-electrons.com>
+ */
+
+
+#ifndef CDNS_MHDP_H
+#define CDNS_MHDP_H
+
+#include <drm/drm_dp_mst_helper.h>
+
+#define CDNS_APB_CFG				0x00000
+#define CDNS_APB_CTRL				(CDNS_APB_CFG + 0x00)
+#define CDNS_MAILBOX_FULL			(CDNS_APB_CFG + 0x08)
+#define CDNS_MAILBOX_EMPTY			(CDNS_APB_CFG + 0x0c)
+#define CDNS_MAILBOX_TX_DATA			(CDNS_APB_CFG + 0x10)
+#define CDNS_MAILBOX_RX_DATA			(CDNS_APB_CFG + 0x14)
+#define CDNS_KEEP_ALIVE				(CDNS_APB_CFG + 0x18)
+#define CDNS_KEEP_ALIVE_MASK			GENMASK(7, 0)
+
+#define CDNS_MB_INT_MASK			(CDNS_APB_CFG + 0x34)
+
+#define CDNS_SW_CLK_L				(CDNS_APB_CFG + 0x3c)
+#define CDNS_SW_CLK_H				(CDNS_APB_CFG + 0x40)
+#define CDNS_SW_EVENT0				(CDNS_APB_CFG + 0x44)
+#define CDNS_DPTX_HPD				BIT(0)
+
+#define CDNS_SW_EVENT1				(CDNS_APB_CFG + 0x48)
+#define CDNS_SW_EVENT2				(CDNS_APB_CFG + 0x4c)
+#define CDNS_SW_EVENT3				(CDNS_APB_CFG + 0x50)
+
+#define CDNS_APB_INT_MASK			(CDNS_APB_CFG + 0x6C)
+#define CDNS_APB_INT_MASK_MAILBOX_INT		BIT(0)
+#define CDNS_APB_INT_MASK_SW_EVENT_INT		BIT(1)
+
+#define CDNS_DPTX_CAR				(CDNS_APB_CFG + 0x904)
+#define CDNS_VIF_CLK_EN				BIT(0)
+#define CDNS_VIF_CLK_RSTN			BIT(1)
+
+#define CDNS_SOURCE_VIDEO_IF(s)			(0x00b00 + (s * 0x20))
+#define CDNS_BND_HSYNC2VSYNC(s)			(CDNS_SOURCE_VIDEO_IF(s) + \
+						 0x00)
+#define CDNS_IP_DTCT_WIN			GENMASK(11, 0)
+#define CDNS_IP_DET_INTERLACE_FORMAT		BIT(12)
+#define CDNS_IP_BYPASS_V_INTERFACE		BIT(13)
+
+#define CDNS_HSYNC2VSYNC_POL_CTRL(s)		(CDNS_SOURCE_VIDEO_IF(s) + \
+						 0x10)
+#define CDNS_H2V_HSYNC_POL_ACTIVE_LOW		BIT(1)
+#define CDNS_H2V_VSYNC_POL_ACTIVE_LOW		BIT(2)
+
+#define CDNS_DPTX_PHY_CONFIG			0x02000
+#define CDNS_PHY_TRAINING_EN			BIT(0)
+#define CDNS_PHY_TRAINING_TYPE(x)		(((x) & GENMASK(3, 0)) << 1)
+#define CDNS_PHY_SCRAMBLER_BYPASS		BIT(5)
+#define CDNS_PHY_ENCODER_BYPASS			BIT(6)
+#define CDNS_PHY_SKEW_BYPASS			BIT(7)
+#define CDNS_PHY_TRAINING_AUTO			BIT(8)
+#define CDNS_PHY_LANE0_SKEW(x)			(((x) & GENMASK(2, 0)) << 9)
+#define CDNS_PHY_LANE1_SKEW(x)			(((x) & GENMASK(2, 0)) << 12)
+#define CDNS_PHY_LANE2_SKEW(x)			(((x) & GENMASK(2, 0)) << 15)
+#define CDNS_PHY_LANE3_SKEW(x)			(((x) & GENMASK(2, 0)) << 18)
+#define CDNS_PHY_COMMON_CONFIG			(CDNS_PHY_LANE1_SKEW(1) | \
+						CDNS_PHY_LANE2_SKEW(2) |  \
+						CDNS_PHY_LANE3_SKEW(3))
+#define CDNS_PHY_10BIT_EN			BIT(21)
+
+#define CDNS_DPTX_FRAMER			0x02200
+#define CDNS_DP_FRAMER_GLOBAL_CONFIG		(CDNS_DPTX_FRAMER + 0x00)
+#define CDNS_DP_NUM_LANES(x)			(x - 1)
+#define CDNS_DP_MST_EN				BIT(2)
+#define CDNS_DP_FRAMER_EN			BIT(3)
+#define CDNS_DP_RATE_GOVERNOR_EN		BIT(4)
+#define CDNS_DP_NO_VIDEO_MODE			BIT(5)
+#define CDNS_DP_DISABLE_PHY_RST			BIT(6)
+#define CDNS_DP_WR_FAILING_EDGE_VSYNC		BIT(7)
+
+#define CDNS_DP_SW_RESET			(CDNS_DPTX_FRAMER + 0x04)
+#define CDNS_DP_FRAMER_TU			(CDNS_DPTX_FRAMER + 0x08)
+#define CDNS_DP_FRAMER_TU_SIZE(x)		(((x) & GENMASK(6, 0)) << 8)
+#define CDNS_DP_FRAMER_TU_VS(x)			((x) & GENMASK(5, 0))
+#define CDNS_DP_FRAMER_TU_CNT_RST_EN		BIT(15)
+
+#define CDNS_DPTX_STREAM(s)			(0x03000 + s * 0x80)
+#define CDNS_DP_MSA_HORIZONTAL_0(s)		(CDNS_DPTX_STREAM(s) + 0x00)
+#define CDNS_DP_MSAH0_H_TOTAL(x)		(x)
+#define CDNS_DP_MSAH0_HSYNC_START(x)		((x) << 16)
+
+#define CDNS_DP_MSA_HORIZONTAL_1(s)		(CDNS_DPTX_STREAM(s) + 0x04)
+#define CDNS_DP_MSAH1_HSYNC_WIDTH(x)		(x)
+#define CDNS_DP_MSAH1_HSYNC_POL_LOW		BIT(15)
+#define CDNS_DP_MSAH1_HDISP_WIDTH(x)		((x) << 16)
+
+#define CDNS_DP_MSA_VERTICAL_0(s)		(CDNS_DPTX_STREAM(s) + 0x08)
+#define CDNS_DP_MSAV0_V_TOTAL(x)		(x)
+#define CDNS_DP_MSAV0_VSYNC_START(x)		((x) << 16)
+
+#define CDNS_DP_MSA_VERTICAL_1(s)		(CDNS_DPTX_STREAM(s) + 0x0c)
+#define CDNS_DP_MSAV1_VSYNC_WIDTH(x)		(x)
+#define CDNS_DP_MSAV1_VSYNC_POL_LOW		BIT(15)
+#define CDNS_DP_MSAV1_VDISP_WIDTH(x)		((x) << 16)
+
+#define CDNS_DP_MSA_MISC(s)			(CDNS_DPTX_STREAM(s) + 0x10)
+#define CDNS_DP_STREAM_CONFIGs(s)		(CDNS_DPTX_STREAM(s) + 0x14)
+#define CDNS_DP_STREAM_CONFIG_2(s)		(CDNS_DPTX_STREAM(s) + 0x2c)
+#define CDNS_DP_SC2_TU_VS_DIFF(x)		((x) << 8)
+
+#define CDNS_DP_HORIZONTAL(s)			(CDNS_DPTX_STREAM(s) + 0x30)
+#define CDNS_DP_H_HSYNC_WIDTH(x)		(x)
+#define CDNS_DP_H_H_TOTAL(x)			((x) << 16)
+
+#define CDNS_DP_VERTICAL_0(s)			(CDNS_DPTX_STREAM(s) + 0x34)
+#define CDNS_DP_V0_VHEIGHT(x)			(x)
+#define CDNS_DP_V0_VSTART(x)			((x) << 16)
+
+#define CDNS_DP_VERTICAL_1(s)			(CDNS_DPTX_STREAM(s) + 0x38)
+#define CDNS_DP_V1_VTOTAL(x)			(x)
+#define CDNS_DP_V1_VTOTAL_EVEN			BIT(16)
+
+#define CDNS_DP_FRAMER_PXL_REPR(s)		(CDNS_DPTX_STREAM(s) + 0x4c)
+#define CDNS_DP_FRAMER_6_BPC			BIT(0)
+#define CDNS_DP_FRAMER_8_BPC			BIT(1)
+#define CDNS_DP_FRAMER_10_BPC			BIT(2)
+#define CDNS_DP_FRAMER_12_BPC			BIT(3)
+#define CDNS_DP_FRAMER_16_BPC			BIT(4)
+#define CDNS_DP_FRAMER_PXL_FORMAT		0x8
+#define CDNS_DP_FRAMER_RGB			BIT(0)
+#define CDNS_DP_FRAMER_YCBCR444			BIT(1)
+#define CDNS_DP_FRAMER_YCBCR422			BIT(2)
+#define CDNS_DP_FRAMER_YCBCR420			BIT(3)
+#define CDNS_DP_FRAMER_Y_ONLY			BIT(4)
+
+#define CDNS_DP_FRAMER_SP(s)			(CDNS_DPTX_STREAM(s) + 0x10)
+#define CDNS_DP_FRAMER_VSYNC_POL_LOW		BIT(0)
+#define CDNS_DP_FRAMER_HSYNC_POL_LOW		BIT(1)
+#define CDNS_DP_FRAMER_INTERLACE		BIT(2)
+
+#define CDNS_DP_LINE_THRESH(s)			(CDNS_DPTX_STREAM(s) + 0x64)
+#define CDNS_DP_ACTIVE_LINE_THRESH(x)		(x)
+
+#define CDNS_DP_VB_ID(s)			(CDNS_DPTX_STREAM(s) + 0x68)
+#define CDNS_DP_VB_ID_INTERLACED		BIT(2)
+#define CDNS_DP_VB_ID_COMPRESSED		BIT(6)
+
+#define CDNS_DP_FRONT_BACK_PORCH(s)		(CDNS_DPTX_STREAM(s) + 0x78)
+#define CDNS_DP_BACK_PORCH(x)			(x)
+#define CDNS_DP_FRONT_PORCH(x)			((x) << 16)
+
+#define CDNS_DP_BYTE_COUNT(s)			(CDNS_DPTX_STREAM(s) + 0x7c)
+#define CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT	16
+
+#define CDNS_DP_MST_STREAM_CONFIG(s)		(CDNS_DPTX_STREAM(s) + 0x14)
+#define CDNS_DP_MST_STRM_CFG_STREAM_EN		BIT(0)
+#define CDNS_DP_MST_STRM_CFG_NO_VIDEO		BIT(1)
+
+#define CDNS_DP_MST_SLOT_ALLOCATE(s)		(CDNS_DPTX_STREAM(s) + 0x44)
+#define CDNS_DP_S_ALLOC_START_SLOT(x)		(x)
+#define CDNS_DP_S_ALLOC_END_SLOT(x)		((x) << 8)
+
+#define CDNS_DP_RATE_GOVERNING(s)		(CDNS_DPTX_STREAM(s) + 0x48)
+#define CDNS_DP_RG_TARG_AV_SLOTS_Y(x)		(x)
+#define CDNS_DP_RG_TARG_AV_SLOTS_X(x)		(x << 4)
+#define CDNS_DP_RG_ENABLE			BIT(10)
+
+#define CDNS_DP_MTPH_CONTROL			0x2264
+#define CDNS_DP_MTPH_ECF_EN			BIT(0)
+#define CDNS_DP_MTPH_ACT_EN			BIT(1)
+#define CDNS_DP_MTPH_LVP_EN			BIT(2)
+
+#define CDNS_DP_MTPH_STATUS			0x226C
+#define CDNS_DP_MTPH_ACT_STATUS			BIT(0)
+
+
+#define CDNS_DPTX_GLOBAL			0x02300
+#define CDNS_DP_LANE_EN				(CDNS_DPTX_GLOBAL + 0x00)
+#define CDNS_DP_LANE_EN_LANES(x)		GENMASK(x - 1, 0)
+#define CDNS_DP_ENHNCD				(CDNS_DPTX_GLOBAL + 0x04)
+
+
+#define to_mhdp_connector(x) container_of(x, struct cdns_mhdp_connector, base)
+#define to_mhdp_bridge(x) container_of(x, struct cdns_mhdp_bridge, base)
+#define mgr_to_mhdp(x) container_of(x, struct cdns_mhdp_device, mst_mgr)
+
+#define CDNS_MHDP_MAX_STREAMS   4
+
+enum pixel_format {
+	PIXEL_FORMAT_RGB = 1,
+	PIXEL_FORMAT_YCBCR_444 = 2,
+	PIXEL_FORMAT_YCBCR_422 = 4,
+	PIXEL_FORMAT_YCBCR_420 = 8,
+	PIXEL_FORMAT_Y_ONLY = 16,
+};
+
+
+int cdns_mhdp_mst_init(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_mst_deinit(struct cdns_mhdp_device *mhdp);
+bool cdns_mhdp_mst_probe(struct cdns_mhdp_device *mhdp);
+enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats);
+u32 cdns_mhdp_get_bpp(u32 bpc, u32 color_formats);
+void cdns_mhdp_configure_video(struct drm_bridge *bridge);
+void cdns_mhdp_mst_enable(struct drm_bridge *bridge);
+void cdns_mhdp_mst_disable(struct drm_bridge *bridge);
+void cdns_mhdp_enable(struct drm_bridge *bridge);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/cdns-dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/cdns-dsi.c
@@ -1026,7 +1026,7 @@
 	struct mipi_dsi_packet packet;
 	int ret, i, tx_len, rx_len;
 
-	ret = pm_runtime_get_sync(host->dev);
+	ret = pm_runtime_resume_and_get(host->dev);
 	if (ret < 0)
 		return ret;
 
@@ -1284,6 +1284,7 @@
 	{ .compatible = "cdns,dsi" },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
 
 static struct platform_driver cdns_dsi_platform_driver = {
 	.probe  = cdns_dsi_drm_probe,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/fsl-imx-ldb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/fsl-imx-ldb.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ * Copyright 2020 NXP
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <drm/bridge/fsl_imx_ldb.h>
+#include <drm/drmP.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+
+#define LDB_CH0_MODE_EN_TO_DI0		(1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1		(3 << 0)
+#define LDB_CH0_MODE_EN_MASK		(3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0		(1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1		(3 << 2)
+#define LDB_CH1_MODE_EN_MASK		(3 << 2)
+#define LDB_SPLIT_MODE_EN		(1 << 4)
+#define LDB_DATA_WIDTH_CH0_24		(1 << 5)
+#define LDB_BIT_MAP_CH0_JEIDA		(1 << 6)
+#define LDB_DATA_WIDTH_CH1_24		(1 << 7)
+#define LDB_BIT_MAP_CH1_JEIDA		(1 << 8)
+#define LDB_DI0_VS_POL_ACT_LOW		(1 << 9)
+#define LDB_DI1_VS_POL_ACT_LOW		(1 << 10)
+
+struct ldb_bit_mapping {
+	u32 bus_format;
+	u32 datawidth;
+	const char * const mapping;
+};
+
+static const struct ldb_bit_mapping ldb_bit_mappings[] = {
+	{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,  18, "spwg" },
+	{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,  24, "spwg" },
+	{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
+};
+
+static u32 of_get_bus_format(struct device *dev, struct device_node *np)
+{
+	const char *bm;
+	u32 datawidth = 0;
+	int ret, i;
+
+	ret = of_property_read_string(np, "fsl,data-mapping", &bm);
+	if (ret < 0)
+		return ret;
+
+	of_property_read_u32(np, "fsl,data-width", &datawidth);
+
+	for (i = 0; i < ARRAY_SIZE(ldb_bit_mappings); i++) {
+		if (!strcasecmp(bm, ldb_bit_mappings[i].mapping) &&
+		    datawidth == ldb_bit_mappings[i].datawidth)
+			return ldb_bit_mappings[i].bus_format;
+	}
+
+	dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm);
+
+	return -ENOENT;
+}
+
+static inline struct ldb_channel *bridge_to_ldb_ch(struct drm_bridge *b)
+{
+	return container_of(b, struct ldb_channel, bridge);
+}
+
+static void ldb_ch_set_bus_format(struct ldb_channel *ldb_ch, u32 bus_format)
+{
+	struct ldb *ldb = ldb_ch->ldb;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+					 LDB_BIT_MAP_CH0_JEIDA;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+					 LDB_BIT_MAP_CH1_JEIDA;
+		break;
+	}
+}
+
+static void ldb_bridge_mode_set(struct drm_bridge *bridge,
+				const struct drm_display_mode *mode,
+				const struct drm_display_mode *adjusted_mode)
+{
+	struct ldb_channel *ldb_ch = bridge_to_ldb_ch(bridge);
+	struct ldb *ldb = ldb_ch->ldb;
+
+	/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
+	if (ldb_ch == ldb->channel[0] || ldb->dual) {
+		if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+			ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
+		else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+			ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
+	}
+	if (ldb_ch == ldb->channel[1] || ldb->dual) {
+		if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+			ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
+		else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+			ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
+	}
+
+	ldb_ch_set_bus_format(ldb_ch, ldb_ch->bus_format);
+}
+
+static void ldb_bridge_enable(struct drm_bridge *bridge)
+{
+	struct ldb_channel *ldb_ch = bridge_to_ldb_ch(bridge);
+	struct ldb *ldb = ldb_ch->ldb;
+
+	if (pm_runtime_enabled(ldb->dev))
+		pm_runtime_get_sync(ldb->dev);
+
+	regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
+}
+
+static void ldb_bridge_disable(struct drm_bridge *bridge)
+{
+	struct ldb_channel *ldb_ch = bridge_to_ldb_ch(bridge);
+	struct ldb *ldb = ldb_ch->ldb;
+
+	if (ldb_ch == ldb->channel[0] || ldb->dual)
+		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+	if (ldb_ch == ldb->channel[1] || ldb->dual)
+		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+
+	regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
+
+	if (pm_runtime_enabled(ldb->dev))
+		pm_runtime_put(ldb->dev);
+}
+
+static int ldb_bridge_attach(struct drm_bridge *bridge)
+{
+	struct ldb_channel *ldb_ch = bridge_to_ldb_ch(bridge);
+	struct ldb *ldb = ldb_ch->ldb;
+
+	if (!bridge->encoder) {
+		dev_err(ldb->dev, "failed to find encoder object\n");
+		return -ENODEV;
+	}
+
+	if (!ldb_ch->next_bridge)
+		return 0;
+
+	return drm_bridge_attach(bridge->encoder,
+				ldb_ch->next_bridge, &ldb_ch->bridge);
+}
+
+static const struct drm_bridge_funcs ldb_bridge_funcs = {
+	.mode_set   = ldb_bridge_mode_set,
+	.enable	    = ldb_bridge_enable,
+	.disable    = ldb_bridge_disable,
+	.attach	    = ldb_bridge_attach,
+};
+
+int ldb_bind(struct ldb *ldb, struct drm_encoder **encoder)
+{
+	struct device *dev = ldb->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int ret = 0;
+	int i;
+
+	ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+	if (IS_ERR(ldb->regmap)) {
+		dev_err(dev, "failed to get parent regmap\n");
+		return PTR_ERR(ldb->regmap);
+	}
+
+	if (pm_runtime_enabled(dev))
+		pm_runtime_get_sync(dev);
+
+	/* disable LDB by resetting the control register to POR default */
+	regmap_write(ldb->regmap, ldb->ctrl_reg, 0);
+
+	if (pm_runtime_enabled(dev))
+		pm_runtime_put(dev);
+
+	ldb->dual = of_property_read_bool(np, "fsl,dual-channel");
+	if (ldb->dual)
+		ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
+
+	for_each_child_of_node(np, child) {
+		struct ldb_channel *ldb_ch;
+		int bus_format;
+
+		ret = of_property_read_u32(child, "reg", &i);
+		if (ret || i < 0 || i > 1) {
+			ret = -EINVAL;
+			goto free_child;
+		}
+
+		if (!of_device_is_available(child))
+			continue;
+
+		if (ldb->dual && i > 0) {
+			dev_warn(dev, "dual-channel mode, ignoring second output\n");
+			continue;
+		}
+
+		ldb_ch = ldb->channel[i];
+		ldb_ch->ldb = ldb;
+		ldb_ch->chno = i;
+		ldb_ch->is_valid = false;
+
+		ret = drm_of_find_panel_or_bridge(child,
+						  ldb->output_port, 0,
+						  &ldb_ch->panel,
+						  &ldb_ch->next_bridge);
+		if (ret && ret != -ENODEV)
+			goto free_child;
+
+		bus_format = of_get_bus_format(dev, child);
+		if (bus_format == -EINVAL) {
+			/*
+			 * If no bus format was specified in the device tree,
+			 * we can still get it from the connected panel later.
+			 */
+			if (ldb_ch->panel && ldb_ch->panel->funcs &&
+			    ldb_ch->panel->funcs->get_modes)
+				bus_format = 0;
+		}
+		if (bus_format < 0) {
+			dev_err(dev, "could not determine data mapping: %d\n",
+				bus_format);
+			ret = bus_format;
+			goto free_child;
+		}
+		ldb_ch->bus_format = bus_format;
+		ldb_ch->child = child;
+
+		if (ldb_ch->panel) {
+			ldb_ch->next_bridge =
+					devm_drm_panel_bridge_add(dev,
+						ldb_ch->panel,
+						DRM_MODE_CONNECTOR_LVDS);
+			if (IS_ERR(ldb_ch->next_bridge)) {
+				ret = PTR_ERR(ldb_ch->next_bridge);
+				goto free_child;
+			}
+		}
+
+		ldb_ch->bridge.driver_private = ldb_ch;
+		ldb_ch->bridge.funcs = &ldb_bridge_funcs;
+		ldb_ch->bridge.of_node = child;
+
+		ret = drm_bridge_attach(encoder[i], &ldb_ch->bridge, NULL);
+		if (ret) {
+			dev_err(dev,
+				"failed to attach bridge with encoder: %d\n",
+				ret);
+			goto free_child;
+		}
+
+		ldb_ch->is_valid = true;
+	}
+
+	return 0;
+
+free_child:
+	of_node_put(child);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ldb_bind);
+
+MODULE_DESCRIPTION("Freescale i.MX LVDS display bridge driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: fsl-imx-ldb");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/it6263.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/it6263.c
@@ -0,0 +1,1027 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/regmap.h>
+
+#define REG_VENDOR_ID(n)	(0x00 + (n))	/* n: 0/1 */
+#define REG_DEVICE_ID(n)	(0x02 + (n))	/* n: 0/1 */
+#define LVDS_VENDER_ID_LOW	0x15
+#define LVDS_VENDER_ID_HIGH	0xCA
+#define LVDS_DEVICE_ID_LOW	0x61
+#define LVDS_DEVICE_ID_HIGH	0x62
+#define HDMI_VENDER_ID_LOW	0x01
+#define HDMI_VENDER_ID_HIGH	0xCA
+#define HDMI_DEVICE_ID_LOW	0x13
+#define HDMI_DEVICE_ID_HIGH	0x76
+
+/* LVDS registers */
+#define LVDS_REG_SW_RST		0x05
+#define SOFT_REFCLK_DM_RST	BIT(0)
+#define SOFT_PCLK_DM_RST	BIT(1)
+
+#define LVDS_REG_MODE		0x2C
+#define LVDS_COLOR_DEPTH	0x3
+enum {
+	LVDS_COLOR_DEPTH_18,
+	LVDS_COLOR_DEPTH_24,
+	LVDS_COLOR_DEPTH_30,
+	LVDS_COLOR_DEPTH_36,
+};
+#define LVDS_OUT_MAP		BIT(4)
+#define VESA			BIT(4)
+#define JEIDA			0
+#define DMODE			BIT(7)
+#define SPLIT_MODE		BIT(7)
+#define SINGLE_MODE		0
+
+#define LVDS_REG_STABLE		0x30
+#define VIDEO_STABLE		BIT(0)
+#define PCLK_LOCK		BIT(1)
+
+#define LVDS_REG_39		0x39
+
+#define LVDS_REG_PLL		0x3C
+#define LVDS_REG_AFE_3E		0x3E
+#define LVDS_REG_AFE_3F		0x3F
+#define LVDS_REG_AFE_47		0x47
+#define LVDS_REG_AFE_48		0x48
+#define LVDS_REG_AFE_4F		0x4F
+#define LVDS_REG_52		0x52
+#define LVDS_REG_PCLK_CNT_HIGH	0x57
+#define LVDS_REG_PCLK_CNT_LOW	0x58
+
+/*
+ * HDMI registers
+ *
+ * Registers are separated into three banks:
+ * 1) common bank: 0x00 ~ 0x2F
+ * 2) bank0: 0x30  ~ 0xFF
+ * 3) bank1: 0x130 ~ 0x1FF	(HDMI packet registers)
+ *
+ * Use register HDMI_REG_BANK_CTRL @ 0x0F[1:0] to select bank0/1:
+ * 2b'00 - bank0
+ * 2b'01 - bank1
+ */
+
+/******************************/
+/* HDMI register common bank  */
+/******************************/
+
+/* HDMI genernal registers */
+#define HDMI_REG_SW_RST		0x04
+#define SOFTREF_RST		BIT(5)
+#define SOFTA_RST		BIT(4)
+#define SOFTV_RST		BIT(3)
+#define AUD_RST			BIT(2)
+#define HDCP_RST		BIT(0)
+#define HDMI_RST_ALL		(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
+				 AUD_RST | HDCP_RST)
+
+#define HDMI_REG_INT_CTRL	0x05
+#define INTPOL_ACTH		BIT(7)
+#define INTPOL_ACTL		0
+#define INTIOMODE_OPENDRAIN	BIT(6)
+#define INTIOMODE_PUSHPULL	0
+#define SELXTAL			BIT(5)	/* REFCLK <= XTALCLK */
+#define SELXTAL_QUARTER		0	/* REFCLK <= OSCCLK/4 */
+#define PDREFCNT(n)		(((n) >> 2) << 2)	/* REFCLK Div(n) */
+#define PDREFCLK		BIT(1)
+#define PDTXCLK_GATED		BIT(0)
+#define PDTXCLK_ACTIVE		0
+
+#define HDMI_REG_INT_STAT(n)	(0x05 + (n))	/* n: 1/2/3 */
+#define HDMI_REG_INT_MASK(n)	(0x08 + (n))	/* n: 1/2/3 */
+
+/* INT1 */
+#define INT_AUD_OVERFLOW	BIT(7)
+#define INT_RDDC_NOACK		BIT(5)
+#define INT_DDCFIFO_ERR		BIT(4)
+#define INT_DDC_BUS_HANG	BIT(2)
+#define INT_RX_SENSE		BIT(1)
+#define INT_HPD			BIT(0)
+
+/* INT2 */
+#define INT_VID_UNSTABLE	BIT(6)
+#define INT_PKTACP		BIT(5)
+#define INT_PKTNULL		BIT(4)
+#define INT_PKTGEN		BIT(3)
+#define INT_KSVLIST_CHK		BIT(2)
+#define INT_AUTH_DONE		BIT(1)
+#define INT_AUTH_FAIL		BIT(0)
+
+/* INT3 */
+#define INT_AUD_CTS		BIT(6)
+#define INT_VSYNC		BIT(5)
+#define INT_VIDSTABLE		BIT(4)
+#define INT_PKTMPG		BIT(3)
+#define INT_PKTGBD		BIT(2)
+#define INT_PKTAUD		BIT(1)
+#define INT_PKTAVI		BIT(0)
+
+#define INT_MASK_AUD_CTS	BIT(5)
+#define INT_MASK_VSYNC		BIT(4)
+#define INT_MASK_VIDSTABLE	BIT(3)
+#define INT_MASK_PKTMPG		BIT(2)
+#define INT_MASK_PKTGBD		BIT(1)
+#define INT_MASK_PKTAUD		BIT(0)
+
+#define HDMI_REG_INT_CLR(n)	(0x0C + (n))	/* n: 0/1 */
+
+/* CLR0 */
+#define INT_CLR_PKTACP		BIT(7)
+#define INT_CLR_PKTNULL		BIT(6)
+#define INT_CLR_PKTGEN		BIT(5)
+#define INT_CLR_KSVLIST_CHK	BIT(4)
+#define INT_CLR_AUTH_DONE	BIT(3)
+#define INT_CLR_AUTH_FAIL	BIT(2)
+#define INT_CLR_RXSENSE		BIT(1)
+#define INT_CLR_HPD		BIT(0)
+
+/* CLR1 */
+#define INT_CLR_VSYNC		BIT(7)
+#define INT_CLR_VIDSTABLE	BIT(6)
+#define INT_CLR_PKTMPG		BIT(5)
+#define INT_CLR_PKTGBD		BIT(4)
+#define INT_CLR_PKTAUD		BIT(3)
+#define INT_CLR_PKTAVI		BIT(2)
+#define INT_CLR_VID_UNSTABLE	BIT(0)
+
+#define HDMI_REG_SYS_STATUS	0x0E
+#define INT_ACTIVE		BIT(7)
+#define HPDETECT		BIT(6)
+#define RXSENDETECT		BIT(5)
+#define TXVIDSTABLE		BIT(4)
+#define CTSINTSTEP		0xC
+#define CLR_AUD_CTS		BIT(1)
+#define INTACTDONE		BIT(0)
+
+#define HDMI_REG_BANK_CTRL	0x0F
+#define BANK_SEL(n)		((n) ? 1 : 0)
+
+/* HDMI System DDC control registers */
+#define HDMI_REG_DDC_MASTER_CTRL	0x10
+#define MASTER_SEL_HOST			BIT(0)
+#define MASTER_SEL_HDCP			0
+
+#define HDMI_REG_DDC_HEADER		0x11
+#define DDC_HDCP_ADDRESS		0x74
+
+#define HDMI_REG_DDC_REQOFF		0x12
+#define HDMI_REG_DDC_REQCOUNT		0x13
+#define HDMI_REG_DDC_EDIDSEG		0x14
+
+#define HDMI_REG_DDC_CMD		0x15
+#define DDC_CMD_SEQ_BURSTREAD		0x0
+#define DDC_CMD_LINK_CHKREAD		0x2
+#define DDC_CMD_EDID_READ		0x3
+#define DDC_CMD_FIFO_CLR		0x9
+#define DDC_CMD_GEN_SCLCLK		0xA
+#define DDC_CMD_ABORT			0xF
+
+#define HDMI_REG_DDC_STATUS		0x16
+#define DDC_DONE			BIT(7)
+#define DDC_ACT				BIT(6)
+#define DDC_NOACK			BIT(5)
+#define DDC_WAITBUS			BIT(4)
+#define DDC_ARBILOSE			BIT(3)
+#define DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
+#define DDC_FIFOFULL			BIT(2)
+#define DDC_FIFOEMPTY			BIT(1)
+
+#define HDMI_DDC_FIFO_SIZE		32	/* bytes */
+#define HDMI_REG_DDC_READFIFO		0x17
+#define HDMI_REG_ROM_STAT		0x1C
+#define HDMI_REG_LVDS_PORT		0x1D	/* LVDS input ctrl i2c addr */
+#define HDMI_REG_LVDS_PORT_EN		0x1E	/* and to enable */
+#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
+
+/***********************/
+/* HDMI register bank0 */
+/***********************/
+
+/* HDMI clock control registers */
+#define HDMI_REG_CLK_CTRL1		0x59
+#define EN_TXCLK_COUNT			BIT(5)
+#define VDO_LATCH_EDGE			BIT(3)
+
+/* HDMI AFE registers */
+#define HDMI_REG_AFE_DRV_CTRL		0x61
+#define AFE_DRV_PWD			BIT(5)
+#define AFE_DRV_RST			BIT(4)
+#define AFE_DRV_PDRXDET			BIT(2)
+#define AFE_DRV_TERMON			BIT(1)
+#define AFE_DRV_ENCAL			BIT(0)
+
+#define HDMI_REG_AFE_XP_CTRL		0x62
+#define AFE_XP_GAINBIT			BIT(7)
+#define AFE_XP_PWDPLL			BIT(6)
+#define AFE_XP_ENI			BIT(5)
+#define AFE_XP_ER0			BIT(4)
+#define AFE_XP_RESETB			BIT(3)
+#define AFE_XP_PWDI			BIT(2)
+#define AFE_XP_DEI			BIT(1)
+#define AFE_XP_DER			BIT(0)
+
+#define HDMI_REG_AFE_ISW_CTRL		0x63
+#define AFE_RTERM_SEL			BIT(7)
+#define AFE_IP_BYPASS			BIT(6)
+#define AFE_DRV_ISW			0x38
+#define AFE_DRV_ISWK			7
+
+#define HDMI_REG_AFE_IP_CTRL		0x64
+#define AFE_IP_GAINBIT			BIT(7)
+#define AFE_IP_PWDPLL			BIT(6)
+#define AFE_IP_CKSEL			0x30
+#define AFE_IP_ER0			BIT(3)
+#define AFE_IP_RESETB			BIT(2)
+#define AFE_IP_ENC			BIT(1)
+#define AFE_IP_EC1			BIT(0)
+
+/* HDMI input data format registers */
+#define HDMI_REG_INPUT_MODE		0x70
+#define IN_RGB				0x00
+#define IN_YUV422			0x40
+#define IN_YUV444			0x80
+
+#define HDMI_REG_TXFIFO_RST		0x71
+#define ENAVMUTERST			BIT(0)
+#define TXFFRST				BIT(1)
+
+/* HDMI pattern generation SYNC/DE registers */
+#define HDMI_REG_9X(n)			(0x90 + (n))	/* n: 0x0 ~ 0xF */
+#define HDMI_REG_AX(n)			(0xA0 + (n))	/* n: 0x0 ~ 0xF */
+#define HDMI_REG_B0			0xB0
+
+/* HDMI general control registers */
+#define HDMI_REG_HDMI_MODE		0xC0
+#define TX_HDMI_MODE			1
+#define TX_DVI_MODE			0
+
+#define HDMI_REG_GCP			0xC1
+#define AVMUTE				BIT(0)
+#define BLUE_SCR_MUTE			BIT(1)
+#define NODEF_PHASE			BIT(2)
+#define PHASE_RESYNC			BIT(3)
+#define HDMI_COLOR_DEPTH		0x70
+enum {
+	HDMI_COLOR_DEPTH_DEF = 0x0,	/* default as 24bit */
+	HDMI_COLOR_DEPTH_24  = 0x40,
+	HDMI_COLOR_DEPTH_30  = 0x50,
+	HDMI_COLOR_DEPTH_36  = 0x60,
+	HDMI_COLOR_DEPTH_48  = 0x70,
+};
+
+#define HDMI_REG_OESS_CYCLE		0xC3
+#define HDMI_REG_ENCRYPTION		0xC4	/* HDCP */
+
+#define HDMI_REG_PKT_SINGLE_CTRL	0xC5
+#define SINGLE_PKT			BIT(0)
+#define BURST_PKT			0
+
+#define HDMI_REG_PKT_GENERAL_CTRL	0xC6
+#define HDMI_REG_NULL_CTRL		0xC9
+#define HDMI_REG_ACP_CTRL		0xCA
+#define HDMI_REG_ISRC1_CTRL		0xCB
+#define HDMI_REG_ISRC2_CTRL		0xCC
+#define HDMI_REG_AVI_INFOFRM_CTRL	0xCD
+#define HDMI_REG_AUD_INFOFRM_CTRL	0xCE
+#define HDMI_REG_SPD_INFOFRM_CTRL	0xCF
+#define HDMI_REG_MPG_INFOFRM_CTRL	0xD0
+#define ENABLE_PKT			BIT(0)
+#define REPEAT_PKT			BIT(1)
+
+/***********************/
+/* HDMI register bank1 */
+/***********************/
+
+/* AVI packet registers */
+#define HDMI_REG_AVI_DB1		0x58
+#define AVI_DB1_COLOR_SPACE		0x60
+enum {
+	AVI_COLOR_SPACE_RGB    = 0x00,
+	AVI_COLOR_SPACE_YUV422 = 0x20,
+	AVI_COLOR_SPACE_YUV444 = 0x40,
+};
+
+struct it6263 {
+	struct i2c_client *hdmi_i2c;
+	struct i2c_client *lvds_i2c;
+	struct regmap *hdmi_regmap;
+	struct regmap *lvds_regmap;
+	struct drm_bridge bridge;
+	struct drm_connector connector;
+	struct gpio_desc *reset_gpio;
+	bool is_hdmi;
+	bool split_mode;
+};
+
+struct it6263_minimode {
+	int hdisplay;
+	int vdisplay;
+	int vrefresh;
+};
+
+static const struct it6263_minimode it6263_bad_mode_db[] = {
+	{1600, 900,  60},
+	{1280, 1024, 60},
+	{1280, 720,  30},
+	{1280, 720,  25},
+	{1280, 720,  24},
+	{1152, 864,  75},
+};
+
+static inline struct it6263 *bridge_to_it6263(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct it6263, bridge);
+}
+
+static inline struct it6263 *connector_to_it6263(struct drm_connector *con)
+{
+	return container_of(con, struct it6263, connector);
+}
+
+static inline void lvds_update_bits(struct it6263 *it6263, unsigned int reg,
+				    unsigned int mask, unsigned int val)
+{
+	regmap_update_bits(it6263->lvds_regmap, reg, mask, val);
+}
+
+static inline void hdmi_update_bits(struct it6263 *it6263, unsigned int reg,
+				    unsigned int mask, unsigned int val)
+{
+	regmap_update_bits(it6263->hdmi_regmap, reg, mask, val);
+}
+
+static void it6263_reset(struct it6263 *it6263)
+{
+	if (!it6263->reset_gpio)
+		return;
+
+	gpiod_set_value_cansleep(it6263->reset_gpio, 0);
+
+	usleep_range(1000, 2000);
+
+	gpiod_set_value_cansleep(it6263->reset_gpio, 1);
+
+	/*
+	 * The chip maker says the low pulse should be at least 40ms,
+	 * so 41ms is sure to be enough.
+	 */
+	usleep_range(41000, 45000);
+
+	gpiod_set_value_cansleep(it6263->reset_gpio, 0);
+
+	/* somehow, addtional time to wait the high voltage to be stable */
+	usleep_range(5000, 6000);
+}
+
+static void it6263_lvds_reset(struct it6263 *it6263)
+{
+	/* AFE PLL reset */
+	lvds_update_bits(it6263, LVDS_REG_PLL, 0x1, 0x0);
+	usleep_range(1000, 2000);
+	lvds_update_bits(it6263, LVDS_REG_PLL, 0x1, 0x1);
+
+	/* pclk reset */
+	lvds_update_bits(it6263, LVDS_REG_SW_RST,
+				SOFT_PCLK_DM_RST, SOFT_PCLK_DM_RST);
+	usleep_range(1000, 2000);
+	lvds_update_bits(it6263, LVDS_REG_SW_RST, SOFT_PCLK_DM_RST, 0x0);
+
+	usleep_range(1000, 2000);
+}
+
+static void it6263_lvds_set_interface(struct it6263 *it6263)
+{
+	/* color depth */
+	lvds_update_bits(it6263, LVDS_REG_MODE, LVDS_COLOR_DEPTH,
+						LVDS_COLOR_DEPTH_24);
+
+	/* jeida mapping */
+	lvds_update_bits(it6263, LVDS_REG_MODE, LVDS_OUT_MAP, JEIDA);
+
+	if (it6263->split_mode) {
+		lvds_update_bits(it6263, LVDS_REG_MODE, DMODE, SPLIT_MODE);
+		lvds_update_bits(it6263, LVDS_REG_52, BIT(1), BIT(1));
+	} else {
+		lvds_update_bits(it6263, LVDS_REG_MODE, DMODE, SINGLE_MODE);
+		lvds_update_bits(it6263, LVDS_REG_52, BIT(1), 0);
+	}
+}
+
+static void it6263_lvds_set_afe(struct it6263 *it6263)
+{
+	struct regmap *regmap = it6263->lvds_regmap;
+
+	regmap_write(regmap, LVDS_REG_AFE_3E, 0xaa);
+	regmap_write(regmap, LVDS_REG_AFE_3F, 0x02);
+	regmap_write(regmap, LVDS_REG_AFE_47, 0xaa);
+	regmap_write(regmap, LVDS_REG_AFE_48, 0x02);
+	regmap_write(regmap, LVDS_REG_AFE_4F, 0x11);
+
+	lvds_update_bits(it6263, LVDS_REG_PLL, 0x07, 0);
+}
+
+static void it6263_lvds_config(struct it6263 *it6263)
+{
+	it6263_lvds_reset(it6263);
+	it6263_lvds_set_interface(it6263);
+	it6263_lvds_set_afe(it6263);
+}
+
+static void it6263_hdmi_config(struct it6263 *it6263)
+{
+	regmap_write(it6263->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
+
+	hdmi_update_bits(it6263, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
+						HDMI_COLOR_DEPTH_24);
+}
+
+static bool it6263_hpd_is_connected(struct it6263 *it6263)
+{
+	unsigned int status;
+
+	regmap_read(it6263->hdmi_regmap, HDMI_REG_SYS_STATUS, &status);
+
+	return !!(status & HPDETECT);
+}
+
+static enum drm_connector_status
+it6263_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct it6263 *it6263 = connector_to_it6263(connector);
+	int i;
+
+	if (force) {
+		/*
+		 * FIXME: We read status tens of times to workaround
+		 * cable detection failure issue at boot time on some
+		 * platforms.
+		 * Spin on this for up to one second.
+		 */
+		for (i = 0; i < 100; i++) {
+			if (it6263_hpd_is_connected(it6263))
+				return connector_status_connected;
+			usleep_range(5000, 10000);
+		}
+	} else {
+		if (it6263_hpd_is_connected(it6263))
+			return connector_status_connected;
+	}
+
+	return connector_status_disconnected;
+}
+
+static const struct drm_connector_funcs it6263_connector_funcs = {
+	.detect = it6263_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int
+it6263_read_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+	struct it6263 *it6263 = data;
+	struct regmap *regmap = it6263->hdmi_regmap;
+	unsigned long timeout;
+	unsigned int status, count, val;
+	unsigned int segment = block >> 1;
+	unsigned int start = (block % 2) * EDID_LENGTH;
+
+	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
+	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
+	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
+
+	while (len) {
+		/* clear DDC FIFO */
+		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
+
+		timeout = jiffies + msecs_to_jiffies(10);
+		do {
+			regmap_read(regmap, HDMI_REG_DDC_STATUS, &status);
+		} while (!(status & DDC_DONE) && time_before(jiffies, timeout));
+
+		if (!(status & DDC_DONE)) {
+			dev_err(&it6263->hdmi_i2c->dev,
+						"failed to clear DDC FIFO\n");
+			return -ETIMEDOUT;
+		}
+
+		count = len > HDMI_DDC_FIFO_SIZE ? HDMI_DDC_FIFO_SIZE : len;
+
+		/* fire the read command */
+		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
+		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
+		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
+
+		start += count;
+		len -= count;
+
+		/* wait for reading done */
+		timeout = jiffies + msecs_to_jiffies(250);
+		do {
+			regmap_read(regmap, HDMI_REG_DDC_STATUS, &status);
+			if (status & DDC_ERROR) {
+				dev_err(&it6263->hdmi_i2c->dev, "DDC error\n");
+				return -EIO;
+			}
+		} while (!(status & DDC_DONE) && time_before(jiffies, timeout));
+
+		if (!(status & DDC_DONE)) {
+			dev_err(&it6263->hdmi_i2c->dev,
+						"failed to read EDID\n");
+			return -ETIMEDOUT;
+		}
+
+		/* cache to buffer */
+		for (; count > 0; count--) {
+			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
+			*(buf++) = val;
+		}
+	}
+
+	return 0;
+}
+
+static int it6263_get_modes(struct drm_connector *connector)
+{
+	struct it6263 *it6263 = connector_to_it6263(connector);
+	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	struct edid *edid;
+	int num = 0;
+	int ret;
+
+	edid = drm_do_get_edid(connector, it6263_read_edid, it6263);
+	drm_connector_update_edid_property(connector, edid);
+	if (edid) {
+		num = drm_add_edid_modes(connector, edid);
+		it6263->is_hdmi = drm_detect_hdmi_monitor(edid);
+		kfree(edid);
+	}
+
+	ret = drm_display_info_set_bus_formats(&connector->display_info,
+					       &bus_format, 1);
+	if (ret)
+		dev_dbg(&it6263->hdmi_i2c->dev,
+			"failed to set the supported bus format %d\n", ret);
+
+	return num;
+}
+
+static enum drm_mode_status it6263_mode_valid(struct drm_connector *connector,
+					      struct drm_display_mode *mode)
+{
+	const struct it6263_minimode *m;
+	int i, vrefresh = drm_mode_vrefresh(mode);
+
+	if (mode->clock > 150000)
+		return MODE_CLOCK_HIGH;
+
+	for (i = 0; i < ARRAY_SIZE(it6263_bad_mode_db); i++) {
+		m = &it6263_bad_mode_db[i];
+		if ((mode->hdisplay == m->hdisplay) &&
+		    (mode->vdisplay == m->vdisplay) &&
+		    (vrefresh == m->vrefresh))
+			return MODE_BAD;
+	}
+
+	return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
+	.get_modes = it6263_get_modes,
+	.mode_valid = it6263_mode_valid,
+};
+
+static void it6263_bridge_disable(struct drm_bridge *bridge)
+{
+	struct it6263 *it6263 = bridge_to_it6263(bridge);
+	struct regmap *regmap = it6263->hdmi_regmap;
+
+	/* AV mute */
+	hdmi_update_bits(it6263, HDMI_REG_GCP, AVMUTE, AVMUTE);
+
+	if (it6263->is_hdmi)
+		regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
+
+	hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
+	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST | AFE_DRV_PWD);
+}
+
+static void it6263_bridge_enable(struct drm_bridge *bridge)
+{
+	struct it6263 *it6263 = bridge_to_it6263(bridge);
+	struct regmap *regmap = it6263->hdmi_regmap;
+	unsigned long timeout;
+	unsigned int status;
+	bool is_stable = false;
+	int i;
+
+	regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL, BANK_SEL(1));
+	/* set the color space to RGB in the AVI packet */
+	hdmi_update_bits(it6263, HDMI_REG_AVI_DB1, AVI_DB1_COLOR_SPACE,
+							AVI_COLOR_SPACE_RGB);
+	regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL, BANK_SEL(0));
+
+	/* software video reset */
+	hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
+	usleep_range(1000, 2000);
+	hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, 0);
+
+	/* reconfigure LVDS and retry several times in case video is instable */
+	for (i = 0; i < 3; i++) {
+		timeout = jiffies + msecs_to_jiffies(500);
+		do {
+			regmap_read(regmap, HDMI_REG_SYS_STATUS, &status);
+		} while (!(status & TXVIDSTABLE) &&
+					time_before(jiffies, timeout));
+
+		if (status & TXVIDSTABLE) {
+			is_stable = true;
+			break;
+		}
+
+		it6263_lvds_config(it6263);
+
+		dev_dbg(&it6263->hdmi_i2c->dev,
+					"retry to lock input video %d\n", i);
+	}
+
+	if (!is_stable)
+		dev_warn(&it6263->hdmi_i2c->dev,
+				"failed to wait for video stable\n");
+
+	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
+
+	/* AV unmute */
+	hdmi_update_bits(it6263, HDMI_REG_GCP, AVMUTE, 0);
+
+	if (it6263->is_hdmi)
+		regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL,
+						ENABLE_PKT | REPEAT_PKT);
+}
+
+static void it6263_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *mode,
+				    const struct drm_display_mode *adj)
+{
+	struct it6263 *it6263 = bridge_to_it6263(bridge);
+	struct regmap *regmap = it6263->hdmi_regmap;
+	bool pclk_high = adj->clock > 80000 ? true : false;
+
+	regmap_write(regmap, HDMI_REG_HDMI_MODE,
+				it6263->is_hdmi ? TX_HDMI_MODE : TX_DVI_MODE);
+
+	dev_dbg(&it6263->hdmi_i2c->dev, "%s mode\n",
+				it6263->is_hdmi ? "HDMI" : "DVI");
+
+	/* setup AFE */
+	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
+	if (pclk_high)
+		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+						AFE_XP_GAINBIT | AFE_XP_RESETB);
+	else
+		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+						AFE_XP_ER0 | AFE_XP_RESETB);
+	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
+	if (pclk_high)
+		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+						AFE_IP_GAINBIT | AFE_IP_RESETB);
+	else
+		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+						AFE_IP_ER0 | AFE_IP_RESETB);
+}
+
+static int it6263_bridge_attach(struct drm_bridge *bridge)
+{
+	struct it6263 *it6263 = bridge_to_it6263(bridge);
+	struct drm_device *drm = bridge->dev;
+	int ret;
+
+	if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
+		dev_err(&it6263->hdmi_i2c->dev,
+			"it6263 driver only copes with atomic updates\n");
+		return -ENOTSUPP;
+	}
+
+	it6263->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
+				   DRM_CONNECTOR_POLL_DISCONNECT;
+	ret = drm_connector_init(drm, &it6263->connector,
+				 &it6263_connector_funcs,
+				 DRM_MODE_CONNECTOR_HDMIA);
+	if (ret) {
+		dev_err(&it6263->hdmi_i2c->dev,
+				"Failed to initialize connector with drm\n");
+		return ret;
+	}
+
+	drm_connector_helper_add(&it6263->connector,
+				 &it6263_connector_helper_funcs);
+	drm_connector_attach_encoder(&it6263->connector, bridge->encoder);
+
+	return ret;
+}
+
+static const struct drm_bridge_funcs it6263_bridge_funcs = {
+	.attach = it6263_bridge_attach,
+	.mode_set = it6263_bridge_mode_set,
+	.disable = it6263_bridge_disable,
+	.enable = it6263_bridge_enable,
+};
+
+static int it6263_check_chipid(struct it6263 *it6263)
+{
+	struct device *dev = &it6263->hdmi_i2c->dev;
+	u8 vendor_id[2], device_id[2];
+	int ret;
+
+	ret = regmap_bulk_read(it6263->hdmi_regmap, REG_VENDOR_ID(0),
+				&vendor_id, 2);
+	if (ret) {
+		dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+		return ret;
+	}
+
+	if (vendor_id[0] != HDMI_VENDER_ID_LOW ||
+	    vendor_id[1] != HDMI_VENDER_ID_HIGH) {
+		dev_err(dev,
+			"Invalid hdmi vendor id %02x %02x(expect 0x01 0xca)\n",
+			vendor_id[0], vendor_id[1]);
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(it6263->hdmi_regmap, REG_DEVICE_ID(0),
+				&device_id, 2);
+	if (ret) {
+		dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+		return ret;
+	}
+
+	if (device_id[0] != HDMI_DEVICE_ID_LOW ||
+	    device_id[1] != HDMI_DEVICE_ID_HIGH) {
+		dev_err(dev,
+			"Invalid hdmi device id %02x %02x(expect 0x13 0x76)\n",
+			device_id[0], device_id[1]);
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(it6263->lvds_regmap, REG_VENDOR_ID(0),
+				&vendor_id, 2);
+	if (ret) {
+		dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+		return ret;
+	}
+
+	if (vendor_id[0] != LVDS_VENDER_ID_LOW ||
+	    vendor_id[1] != LVDS_VENDER_ID_HIGH) {
+		dev_err(dev,
+			"Invalid lvds vendor id %02x %02x(expect 0x15 0xca)\n",
+			vendor_id[0], vendor_id[1]);
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(it6263->lvds_regmap, REG_DEVICE_ID(0),
+				&device_id, 2);
+	if (ret) {
+		dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+		return ret;
+	}
+
+	if (device_id[0] != LVDS_DEVICE_ID_LOW ||
+	    device_id[1] != LVDS_DEVICE_ID_HIGH) {
+		dev_err(dev,
+			"Invalid lvds device id %02x %02x(expect 0x61 0x62)\n",
+			device_id[0], device_id[1]);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct regmap_range it6263_hdmi_volatile_ranges[] = {
+	{ .range_min = 0, .range_max = 0x1ff },
+};
+
+static const struct regmap_access_table it6263_hdmi_volatile_table = {
+	.yes_ranges = it6263_hdmi_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(it6263_hdmi_volatile_ranges),
+};
+
+static const struct regmap_config it6263_hdmi_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_table = &it6263_hdmi_volatile_table,
+	.cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_range it6263_lvds_volatile_ranges[] = {
+	{ .range_min = 0, .range_max = 0xff },
+};
+
+static const struct regmap_access_table it6263_lvds_volatile_table = {
+	.yes_ranges = it6263_lvds_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(it6263_lvds_volatile_ranges),
+};
+
+static const struct regmap_config it6263_lvds_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_table = &it6263_lvds_volatile_table,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int it6263_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *remote_node = NULL, *endpoint = NULL;
+	struct of_changeset ocs;
+	struct property *prop;
+	struct it6263 *it6263;
+	int ret;
+
+	it6263 = devm_kzalloc(dev, sizeof(*it6263), GFP_KERNEL);
+	if (!it6263)
+		return -ENOMEM;
+
+	it6263->split_mode = of_property_read_bool(np, "split-mode");
+
+	it6263->hdmi_i2c = client;
+	it6263->lvds_i2c = i2c_new_dummy(client->adapter,
+						LVDS_INPUT_CTRL_I2C_ADDR);
+	if (!it6263->lvds_i2c) {
+		ret = -ENODEV;
+		goto of_reconfig;
+	}
+
+	it6263->hdmi_regmap = devm_regmap_init_i2c(client,
+						&it6263_hdmi_regmap_config);
+	if (IS_ERR(it6263->hdmi_regmap)) {
+		ret = PTR_ERR(it6263->hdmi_regmap);
+		goto unregister_lvds_i2c;
+	}
+
+	it6263->lvds_regmap = devm_regmap_init_i2c(it6263->lvds_i2c,
+						&it6263_lvds_regmap_config);
+	if (IS_ERR(it6263->lvds_regmap)) {
+		ret = PTR_ERR(it6263->lvds_regmap);
+		goto unregister_lvds_i2c;
+	}
+
+	it6263->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+							GPIOD_OUT_LOW);
+	if (IS_ERR(it6263->reset_gpio)) {
+		ret = PTR_ERR(it6263->reset_gpio);
+
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get reset gpio: %d\n", ret);
+
+		goto unregister_lvds_i2c;
+	}
+
+	it6263_reset(it6263);
+
+	ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
+	if (ret)
+		goto unregister_lvds_i2c;
+
+	usleep_range(1000, 2000);
+
+	ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_LVDS_PORT,
+				LVDS_INPUT_CTRL_I2C_ADDR << 1);
+	if (ret)
+		goto unregister_lvds_i2c;
+
+	ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, 0x01);
+	if (ret)
+		goto unregister_lvds_i2c;
+
+	/* select HDMI bank0 */
+	ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL,
+				BANK_SEL(0));
+	if (ret)
+		goto unregister_lvds_i2c;
+
+	ret = it6263_check_chipid(it6263);
+	if (ret)
+		goto unregister_lvds_i2c;
+
+	it6263_lvds_config(it6263);
+	it6263_hdmi_config(it6263);
+
+	it6263->bridge.funcs = &it6263_bridge_funcs;
+	it6263->bridge.of_node = np;
+	drm_bridge_add(&it6263->bridge);
+
+	i2c_set_clientdata(client, it6263);
+
+	return ret;
+
+unregister_lvds_i2c:
+	i2c_unregister_device(it6263->lvds_i2c);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+
+of_reconfig:
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint)
+		remote_node = of_graph_get_remote_port_parent(endpoint);
+
+	if (remote_node) {
+		int num_endpoints = 0;
+
+		/*
+		 * Remote node should have two endpoints (input and output: us)
+		 * If remote node has more than two endpoints, probably that it
+		 * has more outputs, so there is no need to disable it.
+		 */
+		endpoint = NULL;
+		while ((endpoint = of_graph_get_next_endpoint(remote_node,
+							      endpoint)))
+			num_endpoints++;
+
+		if (num_endpoints > 2) {
+			of_node_put(remote_node);
+			return ret;
+		}
+
+		prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+		prop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+		prop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+		prop->length = 9;
+		of_changeset_init(&ocs);
+		of_changeset_update_property(&ocs, remote_node, prop);
+		ret = of_changeset_apply(&ocs);
+		if (!ret)
+			dev_warn(dev,
+				"Probe failed. Remote port '%s' disabled\n",
+				remote_node->full_name);
+
+		of_node_put(remote_node);
+	};
+
+	return ret;
+}
+
+static int it6263_remove(struct i2c_client *client)
+
+{
+	struct it6263 *it6263 = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&it6263->bridge);
+	i2c_unregister_device(it6263->lvds_i2c);
+
+	return 0;
+}
+
+static const struct of_device_id it6263_dt_ids[] = {
+	{ .compatible = "ite,it6263", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, it6263_dt_ids);
+
+static const struct i2c_device_id it6263_i2c_ids[] = {
+	{ "it6263", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
+
+static struct i2c_driver it6263_driver = {
+	.probe = it6263_probe,
+	.remove = it6263_remove,
+	.driver = {
+		.name = "it6263",
+		.of_match_table = it6263_dt_ids,
+	},
+	.id_table = it6263_i2c_ids,
+};
+module_i2c_driver(it6263_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS->HDMI bridge");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -279,7 +279,9 @@
 	 * This check is to avoid both the drivers
 	 * removing the bridge in their remove() function
 	 */
-	if (!ge_b850v3_lvds_ptr)
+	if (!ge_b850v3_lvds_ptr ||
+	    !ge_b850v3_lvds_ptr->stdp2690_i2c ||
+		!ge_b850v3_lvds_ptr->stdp4028_i2c)
 		goto out;
 
 	drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
@@ -291,16 +293,11 @@
 	mutex_unlock(&ge_b850v3_lvds_dev_mutex);
 }
 
-static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
-				       const struct i2c_device_id *id)
+static int ge_b850v3_register(void)
 {
+	struct i2c_client *stdp4028_i2c = ge_b850v3_lvds_ptr->stdp4028_i2c;
 	struct device *dev = &stdp4028_i2c->dev;
 
-	ge_b850v3_lvds_init(dev);
-
-	ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c;
-	i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr);
-
 	/* drm bridge initialization */
 	ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
 	ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node;
@@ -321,6 +318,27 @@
 			"ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
 }
 
+static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
+				       const struct i2c_device_id *id)
+{
+	struct device *dev = &stdp4028_i2c->dev;
+	int ret;
+
+	ret = ge_b850v3_lvds_init(dev);
+
+	if (ret)
+		return ret;
+
+	ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c;
+	i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr);
+
+	/* Only register after both bridges are probed */
+	if (!ge_b850v3_lvds_ptr->stdp2690_i2c)
+		return 0;
+
+	return ge_b850v3_register();
+}
+
 static int stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c)
 {
 	ge_b850v3_lvds_remove();
@@ -354,13 +372,21 @@
 				       const struct i2c_device_id *id)
 {
 	struct device *dev = &stdp2690_i2c->dev;
+	int ret;
 
-	ge_b850v3_lvds_init(dev);
+	ret = ge_b850v3_lvds_init(dev);
+
+	if (ret)
+		return ret;
 
 	ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c;
 	i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr);
 
-	return 0;
+	/* Only register after both bridges are probed */
+	if (!ge_b850v3_lvds_ptr->stdp4028_i2c)
+		return 0;
+
+	return ge_b850v3_register();
 }
 
 static int stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c)
@@ -400,7 +426,11 @@
 	if (ret)
 		return ret;
 
-	return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
+	ret = i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
+	if (ret)
+		i2c_del_driver(&stdp4028_ge_b850v3_fw_driver);
+
+	return ret;
 }
 module_init(stdpxxxx_ge_b850v3_init);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/Kconfig
@@ -0,0 +1,16 @@
+config DRM_NWL_MIPI_DSI
+	tristate "Support for Northwest Logic MIPI DSI Host controller"
+	depends on DRM
+	depends on COMMON_CLK
+	depends on OF && HAS_IOMEM
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL_BRIDGE
+	select GENERIC_PHY_MIPI_DPHY
+	select MFD_SYSCON
+	select MULTIPLEXER
+	select REGMAP_MMIO
+	help
+	  This enables the Northwest Logic MIPI DSI Host controller as
+	  for example found on NXP's i.MX8 Processors.
+
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+nwl-mipi-dsi-y := nwl-drv.o nwl-dsi.o
+obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-mipi-dsi.o
+header-test-y += nwl-drv.h nwl-dsi.h
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.c
@@ -0,0 +1,1285 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX8 NWL MIPI DSI host driver
+ *
+ * Copyright (C) 2017 NXP
+ * Copyright (C) 2019 Purism SPC
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/irq.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/sys_soc.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+
+#include "nwl-drv.h"
+#include "nwl-dsi.h"
+
+#define DRV_NAME "nwl-dsi"
+
+/* Possible platform specific clocks */
+#define NWL_DSI_CLK_CORE	"core"
+#define NWL_DSI_CLK_BYPASS	"bypass"
+#define NWL_DSI_CLK_PIXEL	"pixel"
+
+/* Maximum Video PLL frequency */
+#define MAX_PLL_FREQ 1200000000
+
+#define MBPS(x) ((x) * 1000000)
+#define MIN_PHY_RATE MBPS(24)
+#define MAX_PHY_RATE MBPS(30)
+
+#define DC_ID(x)	IMX_SC_R_DC_ ## x
+#define MIPI_ID(x)	IMX_SC_R_MIPI_ ## x
+#define SYNC_CTRL(x)	IMX_SC_C_SYNC_CTRL ## x
+#define PXL_VLD(x)	IMX_SC_C_PXL_LINK_MST ## x ## _VLD
+#define PXL_ADDR(x)	IMX_SC_C_PXL_LINK_MST ## x ## _ADDR
+
+/* Possible valid PHY reference clock rates*/
+static u32 phyref_rates[] = {
+	27000000,
+	25000000,
+	24000000,
+};
+
+/*
+ * TODO: find a better way to access imx_crtc_state
+ */
+struct imx_crtc_state {
+	struct drm_crtc_state			base;
+	u32					bus_format;
+	u32					bus_flags;
+	int					di_hsync_pin;
+	int					di_vsync_pin;
+};
+
+static inline struct imx_crtc_state *to_imx_crtc_state(struct drm_crtc_state *s)
+{
+	return container_of(s, struct imx_crtc_state, base);
+}
+
+enum nwl_dsi_ext_regs {
+       NWL_DSI_IMX_REG_GPR = BIT(1),
+};
+
+static const struct regmap_config nwl_dsi_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = NWL_DSI_IRQ_MASK2,
+	.name = DRV_NAME,
+};
+
+struct nwl_dsi_platform_data {
+	int (*pclk_reset)(struct nwl_dsi *dsi, bool reset);
+	int (*mipi_reset)(struct nwl_dsi *dsi, bool reset);
+	int (*dpi_reset)(struct nwl_dsi *dsi, bool reset);
+	int (*select_input)(struct nwl_dsi *dsi);
+	int (*deselect_input)(struct nwl_dsi *dsi);
+	struct nwl_dsi_plat_clk_config clk_config[NWL_DSI_MAX_PLATFORM_CLOCKS];
+	u32 reg_tx_ulps;
+	u32 reg_pxl2dpi;
+	u32 max_instances;
+	u32 tx_clk_rate;
+	u32 rx_clk_rate;
+	bool mux_present;
+	bool shared_phy;
+};
+
+static inline struct nwl_dsi *bridge_to_dsi(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct nwl_dsi, bridge);
+}
+
+static unsigned long nwl_dsi_get_bit_clock(struct nwl_dsi *dsi,
+		unsigned long pixclock, u32 lanes)
+{
+	int bpp;
+
+	if (lanes < 1 || lanes > 4)
+		return 0;
+
+	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+
+	return (pixclock * bpp) / lanes;
+}
+
+/*
+ * Utility function to calculate least commom multiple, using an improved
+ * version of the Euclidean algorithm for greatest common factor.
+ */
+static unsigned long nwl_dsi_get_lcm(unsigned long a, unsigned long b)
+{
+	u32 gcf = 0; /* greatest common factor */
+	unsigned long tmp_a = a;
+	unsigned long tmp_b = b;
+
+	if (!a || !b)
+		return 0;
+
+	while (tmp_a % tmp_b) {
+		gcf = tmp_a % tmp_b;
+		tmp_a = tmp_b;
+		tmp_b = gcf;
+	}
+
+	if (!gcf)
+		return a;
+
+	return ((unsigned long long)a * b) / gcf;
+}
+
+/*
+ * This function tries to adjust the crtc_clock for a DSI device in such a way
+ * that the video pll will be able to satisfy both Display Controller pixel
+ * clock (feeding out DPI interface) and our input phy_ref clock.
+ * Also, the DC pixel clock must be lower than the actual clock in order to
+ * have enough blanking space to send DSI commands, if the device is a panel.
+ */
+static void nwl_dsi_setup_pll_config(struct mode_config *config, u32 lvl)
+{
+	unsigned long pll_rate;
+	int div;
+	size_t i, num_rates = ARRAY_SIZE(config->phy_rates);
+
+	config->crtc_clock = 0;
+
+	for (i = 0; i < num_rates; i++) {
+		int crtc_clock;
+
+		if (!config->phy_rates[i])
+			break;
+		/*
+		 * First, we need to check if phy_ref can actually be obtained
+		 * from pixel clock. To do this, we check their lowest common
+		 * multiple, which has to be in PLL range.
+		 */
+		pll_rate = nwl_dsi_get_lcm(config->clock, config->phy_rates[i]);
+		if (pll_rate > MAX_PLL_FREQ) {
+			/* Drop pll_rate to a realistic value */
+			while (pll_rate > MAX_PLL_FREQ)
+				pll_rate >>= 1;
+			/* Make sure pll_rate can provide phy_ref rate */
+			div = DIV_ROUND_UP(pll_rate, config->phy_rates[i]);
+			pll_rate = config->phy_rates[i] * div;
+		} else {
+			/*
+			 * Increase the pll rate to highest possible rate for
+			 * better accuracy.
+			 */
+			while (pll_rate <= MAX_PLL_FREQ)
+				pll_rate <<= 1;
+			pll_rate >>= 1;
+		}
+
+		/*
+		 * Next, we need to tweak the pll_rate to a value that can also
+		 * satisfy the crtc_clock.
+		 */
+		div = DIV_ROUND_CLOSEST(pll_rate, config->clock);
+		if (lvl)
+			pll_rate -= config->phy_rates[i] * lvl;
+		crtc_clock = pll_rate / div;
+		config->pll_rates[i] = pll_rate;
+
+		/*
+		 * Pick a crtc_clock which is closest to pixel clock.
+		 * Also, make sure that the pixel clock is a multiply of
+		 * 50Hz.
+		 */
+		if (!(crtc_clock % 50) &&
+		    abs(config->clock - crtc_clock) <
+		    abs(config->clock - config->crtc_clock)) {
+			config->crtc_clock = crtc_clock;
+			config->phy_rate_idx = i;
+		}
+	}
+}
+
+/*
+ * This function will try the required phy speed for current mode
+ * If the phy speed can be achieved, the phy will save the speed
+ * configuration
+ */
+static struct mode_config *nwl_dsi_mode_probe(struct nwl_dsi *dsi,
+			    const struct drm_display_mode *mode)
+{
+	struct device *dev = dsi->dev;
+	struct mode_config *config;
+	union phy_configure_opts phy_opts;
+	unsigned long clock = mode->clock * 1000;
+	unsigned long bit_clk = 0;
+	unsigned long phy_rates[3] = {0};
+	int match_rates = 0;
+	u32 lanes = dsi->lanes;
+	size_t i = 0, num_rates = ARRAY_SIZE(phyref_rates);
+
+	list_for_each_entry(config, &dsi->valid_modes, list)
+		if (config->clock == clock)
+			return config;
+
+	phy_mipi_dphy_get_default_config(clock,
+			mipi_dsi_pixel_format_to_bpp(dsi->format),
+			lanes, &phy_opts.mipi_dphy);
+	phy_opts.mipi_dphy.lp_clk_rate = clk_get_rate(dsi->tx_esc_clk);
+
+	while (i < num_rates) {
+		int ret;
+
+		bit_clk = nwl_dsi_get_bit_clock(dsi, clock, lanes);
+
+		clk_set_rate(dsi->pll_clk, phyref_rates[i] * 32);
+		clk_set_rate(dsi->phy_ref_clk, phyref_rates[i]);
+		ret = phy_validate(dsi->phy, PHY_MODE_MIPI_DPHY, 0, &phy_opts);
+
+		/* Pick the non-failing rate, and search for more */
+		if (!ret) {
+			phy_rates[match_rates++] = phyref_rates[i++];
+			continue;
+		}
+
+		if (match_rates)
+			break;
+
+		/* Reached the end of phyref_rates, try another lane config */
+		if ((i++ == num_rates - 1) && (--lanes > 2)) {
+			i = 0;
+			continue;
+		}
+	}
+
+	/*
+	 * Try swinging between min and max pll rates and see what rate (in terms
+	 * of kHz) we can custom use to get the required bit-clock.
+	 */
+	if (!match_rates) {
+		int min_div, max_div;
+		int bit_clk_khz;
+
+		lanes = dsi->lanes;
+		bit_clk = nwl_dsi_get_bit_clock(dsi, clock, lanes);
+
+		min_div = DIV_ROUND_UP(bit_clk, MAX_PHY_RATE);
+		max_div = DIV_ROUND_DOWN_ULL(bit_clk, MIN_PHY_RATE);
+		bit_clk_khz = bit_clk / 1000;
+
+		for (i = max_div; i > min_div; i--) {
+			if (!(bit_clk_khz % i)) {
+				phy_rates[0] = bit_clk / i;
+				match_rates = 1;
+				break;
+			}
+		}
+	}
+
+	if (!match_rates) {
+		DRM_DEV_DEBUG_DRIVER(dev,
+			"Cannot setup PHY for mode: %ux%u @%d kHz\n",
+			mode->hdisplay,
+			mode->vdisplay,
+			mode->clock);
+
+		return NULL;
+	}
+
+	config = devm_kzalloc(dsi->dev, sizeof(struct mode_config), GFP_KERNEL);
+	config->clock = clock;
+	config->lanes = lanes;
+	config->bitclock = bit_clk;
+	memcpy(&config->phy_rates, &phy_rates, sizeof(phy_rates));
+	list_add(&config->list, &dsi->valid_modes);
+
+	return config;
+}
+
+static int nwl_dsi_set_platform_clocks(struct nwl_dsi *dsi, bool enable)
+{
+	struct device *dev = dsi->dev;
+	const char *id;
+	struct clk *clk;
+	size_t i;
+	unsigned long rate;
+	int ret, result = 0;
+
+	DRM_DEV_DEBUG_DRIVER(dev, "%s platform clocks\n",
+			     enable ? "enabling" : "disabling");
+	for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) {
+		if (!dsi->clk_config[i].present)
+			continue;
+		id = dsi->clk_config[i].id;
+		clk = dsi->clk_config[i].clk;
+
+		if (enable) {
+			ret = clk_prepare_enable(clk);
+			if (ret < 0) {
+				DRM_DEV_ERROR(dev,
+					      "Failed to enable %s clk: %d\n",
+					      id, ret);
+				result = result ?: ret;
+			}
+			rate = clk_get_rate(clk);
+			DRM_DEV_DEBUG_DRIVER(dev, "Enabled %s clk @%lu Hz\n",
+					     id, rate);
+		} else {
+			clk_disable_unprepare(clk);
+			DRM_DEV_DEBUG_DRIVER(dev, "Disabled %s clk\n", id);
+		}
+	}
+
+	return result;
+}
+
+static void nwl_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+	int ret;
+
+	pm_runtime_get_sync(dsi->dev);
+
+	dsi->pdata->dpi_reset(dsi, true);
+	dsi->pdata->mipi_reset(dsi, true);
+	dsi->pdata->pclk_reset(dsi, true);
+
+	if (dsi->lcdif_clk)
+		clk_prepare_enable(dsi->lcdif_clk);
+
+	if (nwl_dsi_set_platform_clocks(dsi, true) < 0)
+		return;
+
+	/* Perform Step 1 from DSI reset-out instructions */
+	ret = dsi->pdata->pclk_reset(dsi, false);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to deassert PCLK: %d\n", ret);
+		return;
+	}
+
+	/* Perform Step 2 from DSI reset-out instructions */
+	nwl_dsi_enable(dsi);
+
+	/* Perform Step 3 from DSI reset-out instructions */
+	ret = dsi->pdata->mipi_reset(dsi, false);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to deassert MIPI: %d\n", ret);
+		return;
+	}
+
+	/*
+	 * We need to force call enable for the panel here, in order to
+	 * make the panel initialization execute before our call to
+	 * bridge_enable, where we will enable the DPI and start streaming
+	 * pixels on the data lanes.
+	 */
+	drm_bridge_chain_enable(dsi->panel_bridge);
+}
+
+static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+	int ret;
+
+	/* Perform Step 5 from DSI reset-out instructions */
+	ret = dsi->pdata->dpi_reset(dsi, false);
+	if (ret < 0)
+		DRM_DEV_ERROR(dsi->dev, "Failed to deassert DPI: %d\n", ret);
+
+}
+
+static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+
+	nwl_dsi_disable(dsi);
+
+	dsi->pdata->dpi_reset(dsi, true);
+	dsi->pdata->mipi_reset(dsi, true);
+	dsi->pdata->pclk_reset(dsi, true);
+
+	nwl_dsi_set_platform_clocks(dsi, false);
+
+	if (dsi->lcdif_clk)
+		clk_disable_unprepare(dsi->lcdif_clk);
+
+	pm_runtime_put(dsi->dev);
+}
+
+static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,
+				   const struct drm_display_mode *mode,
+				   union phy_configure_opts *phy_opts)
+{
+	unsigned long rate;
+	int ret;
+
+	if (dsi->lanes < 1 || dsi->lanes > 4)
+		return -EINVAL;
+
+	/*
+	 * So far the DPHY spec minimal timings work for both mixel
+	 * dphy and nwl dsi host
+	 */
+	ret = phy_mipi_dphy_get_default_config(
+		mode->clock * 1000,
+		mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes,
+		&phy_opts->mipi_dphy);
+	if (ret < 0)
+		return ret;
+
+	rate = clk_get_rate(dsi->tx_esc_clk);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "LP clk is @%lu Hz\n", rate);
+	phy_opts->mipi_dphy.lp_clk_rate = rate;
+
+	return 0;
+}
+
+static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
+				      const struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+	struct mode_config *config;
+	unsigned long pll_rate;
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "Fixup mode:\n");
+	drm_mode_debug_printmodeline(adjusted);
+
+	config = nwl_dsi_mode_probe(dsi, adjusted);
+	if (!config)
+		return false;
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "lanes=%u, data_rate=%lu\n",
+			     config->lanes, config->bitclock);
+	if (config->lanes < 2 || config->lanes > 4)
+		return false;
+
+	/* Max data rate for this controller is 1.5Gbps */
+	if (config->bitclock > 1500000000)
+		return false;
+
+	pll_rate = config->pll_rates[config->phy_rate_idx];
+	if (dsi->pll_clk && pll_rate) {
+		clk_set_rate(dsi->pll_clk, pll_rate);
+		DRM_DEV_DEBUG_DRIVER(dsi->dev,
+				     "Video pll rate: %lu (actual: %lu)",
+				     pll_rate, clk_get_rate(dsi->pll_clk));
+	}
+	/* Update the crtc_clock to be used by display controller */
+	if (config->crtc_clock)
+		adjusted->crtc_clock = config->crtc_clock / 1000;
+	else if (dsi->clk_drop_lvl) {
+		int div;
+		unsigned long phy_ref_rate;
+
+		phy_ref_rate = config->phy_rates[config->phy_rate_idx];
+		pll_rate = config->bitclock;
+		div = DIV_ROUND_CLOSEST(pll_rate, config->clock);
+		pll_rate -= phy_ref_rate * dsi->clk_drop_lvl;
+		adjusted->crtc_clock = (pll_rate / div) / 1000;
+	}
+
+	if (!dsi->use_dcss) {
+		/* LCDIF + NWL needs active high sync */
+		adjusted->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+		adjusted->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
+	} else {
+		adjusted->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+		adjusted->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
+	}
+
+	return true;
+}
+
+static enum drm_mode_status
+nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+	struct mode_config *config;
+	unsigned long pll_rate;
+	int bit_rate;
+
+	bit_rate = nwl_dsi_get_bit_clock(dsi, mode->clock * 1000, dsi->lanes);
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "Validating mode:");
+	drm_mode_debug_printmodeline(mode);
+
+	if (bit_rate > MBPS(1500))
+		return MODE_CLOCK_HIGH;
+
+	if (bit_rate < MBPS(80))
+		return MODE_CLOCK_LOW;
+
+	config = nwl_dsi_mode_probe(dsi, mode);
+	if (!config)
+		return MODE_NOCLOCK;
+
+	pll_rate = config->pll_rates[config->phy_rate_idx];
+	if (dsi->pll_clk && !pll_rate)
+		nwl_dsi_setup_pll_config(config, dsi->clk_drop_lvl);
+
+	return MODE_OK;
+}
+
+static void
+nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
+			const struct drm_display_mode *mode,
+			const struct drm_display_mode *adjusted)
+{
+	struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+	struct device *dev = dsi->dev;
+	union phy_configure_opts new_cfg;
+	unsigned long phy_ref_rate;
+	struct mode_config *config;
+	size_t i;
+	const char *id;
+	struct clk *clk;
+	int ret;
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "Setting mode:\n");
+	drm_mode_debug_printmodeline(adjusted);
+
+	config = nwl_dsi_mode_probe(dsi, adjusted);
+	/* New mode? This should NOT happen */
+	if (!config) {
+		DRM_DEV_ERROR(dsi->dev, "Unsupported mode provided:\n");
+		drm_mode_debug_printmodeline(adjusted);
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) {
+		if (!dsi->clk_config[i].present)
+			continue;
+		id = dsi->clk_config[i].id;
+		clk = dsi->clk_config[i].clk;
+
+		/* Set bypass and pixel clocks to mode clock rate */
+		if (!strcmp(id, NWL_DSI_CLK_BYPASS) ||
+		    !strcmp(id, NWL_DSI_CLK_PIXEL))
+			clk_set_rate(clk, adjusted->crtc_clock * 1000);
+	}
+
+	memcpy(&dsi->mode, adjusted, sizeof(dsi->mode));
+
+	phy_ref_rate = config->phy_rates[config->phy_rate_idx];
+	clk_set_rate(dsi->phy_ref_clk, phy_ref_rate);
+	ret = nwl_dsi_get_dphy_params(dsi, adjusted, &new_cfg);
+	if (ret < 0)
+		return;
+
+	/*
+	 * If hs clock is unchanged, we're all good - all parameters are
+	 * derived from it atm.
+	 */
+	if (new_cfg.mipi_dphy.hs_clk_rate == dsi->phy_cfg.mipi_dphy.hs_clk_rate)
+		return;
+
+	DRM_DEV_DEBUG_DRIVER(dev,
+			     "PHY at ref rate: %lu (actual: %lu)\n",
+			     phy_ref_rate, clk_get_rate(dsi->phy_ref_clk));
+	/* Save the new desired phy config */
+	memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg));
+
+}
+
+static int nwl_dsi_bridge_attach(struct drm_bridge *bridge)
+{
+	struct nwl_dsi *dsi = bridge->driver_private;
+	struct drm_bridge *panel_bridge;
+	struct drm_panel *panel;
+	struct clk *phy_parent;
+	int ret;
+
+	ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
+					  &panel_bridge);
+	if (ret)
+		return ret;
+
+	if (panel) {
+		panel_bridge = drm_panel_bridge_add(panel,
+						    DRM_MODE_CONNECTOR_DSI);
+		if (IS_ERR(panel_bridge))
+			return PTR_ERR(panel_bridge);
+	}
+
+	dsi->panel_bridge = panel_bridge;
+
+	if (!dsi->panel_bridge)
+		return -EPROBE_DEFER;
+
+	phy_parent = devm_clk_get(dsi->dev, "phy_parent");
+	if (!IS_ERR_OR_NULL(phy_parent)) {
+		ret = clk_set_parent(dsi->phy_ref_clk, phy_parent);
+		ret |= clk_set_parent(dsi->tx_esc_clk, phy_parent);
+		ret |= clk_set_parent(dsi->rx_esc_clk, phy_parent);
+
+		if (ret) {
+			dev_err(dsi->dev,
+				 "Error re-parenting phy/tx/rx clocks: %d",
+				 ret);
+
+			return ret;
+		}
+
+		if (dsi->pdata->tx_clk_rate)
+			clk_set_rate(dsi->tx_esc_clk, dsi->pdata->tx_clk_rate);
+
+		if (dsi->pdata->rx_clk_rate)
+			clk_set_rate(dsi->rx_esc_clk, dsi->pdata->rx_clk_rate);
+	}
+
+	return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge);
+}
+
+static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
+{
+	struct nwl_dsi *dsi = bridge->driver_private;
+
+	drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
+}
+
+static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
+	.pre_enable = nwl_dsi_bridge_pre_enable,
+	.enable     = nwl_dsi_bridge_enable,
+	.disable    = nwl_dsi_bridge_disable,
+	.mode_fixup = nwl_dsi_bridge_mode_fixup,
+	.mode_set   = nwl_dsi_bridge_mode_set,
+	.mode_valid = nwl_dsi_bridge_mode_valid,
+	.attach	    = nwl_dsi_bridge_attach,
+	.detach	    = nwl_dsi_bridge_detach,
+};
+
+static void nwl_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs nwl_dsi_encoder_funcs = {
+	.destroy = nwl_dsi_encoder_destroy,
+};
+
+static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
+{
+	struct device_node *np = dsi->dev->of_node;
+	struct platform_device *pdev = to_platform_device(dsi->dev);
+	struct clk *clk;
+	const char *clk_id;
+	void __iomem *base;
+	int i, ret, id;
+
+	dsi->phy = devm_phy_get(dsi->dev, "dphy");
+	if (IS_ERR(dsi->phy)) {
+		ret = PTR_ERR(dsi->phy);
+		if (ret != -EPROBE_DEFER)
+			DRM_DEV_ERROR(dsi->dev, "Could not get PHY: %d\n", ret);
+		return ret;
+	}
+
+	id = of_alias_get_id(np, "mipi_dsi");
+	if (id > 0) {
+		if (id > dsi->pdata->max_instances - 1) {
+			dev_err(dsi->dev,
+				"Too many instances! (cur: %d, max: %d)\n",
+				id, dsi->pdata->max_instances);
+			return -ENODEV;
+		}
+		dsi->instance = id;
+	}
+
+	/* Platform dependent clocks */
+	memcpy(dsi->clk_config, dsi->pdata->clk_config,
+	       sizeof(dsi->pdata->clk_config));
+
+	for (i = 0; i < ARRAY_SIZE(dsi->pdata->clk_config); i++) {
+		if (!dsi->clk_config[i].present)
+			continue;
+
+		clk_id = dsi->clk_config[i].id;
+		clk = devm_clk_get(dsi->dev, clk_id);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			DRM_DEV_ERROR(dsi->dev, "Failed to get %s clock: %d\n",
+				      clk_id, ret);
+			return ret;
+		}
+		DRM_DEV_DEBUG_DRIVER(dsi->dev, "Setup clk %s (rate: %lu)\n",
+				     clk_id, clk_get_rate(clk));
+		dsi->clk_config[i].clk = clk;
+	}
+
+	/* DSI clocks */
+	clk = devm_clk_get(dsi->dev, "phy_ref");
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		DRM_DEV_ERROR(dsi->dev, "Failed to get phy_ref clock: %d\n",
+			      ret);
+		return ret;
+	}
+	dsi->phy_ref_clk = clk;
+
+	clk = devm_clk_get(dsi->dev, "rx_esc");
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		DRM_DEV_ERROR(dsi->dev, "Failed to get rx_esc clock: %d\n",
+			      ret);
+		return ret;
+	}
+	dsi->rx_esc_clk = clk;
+
+	clk = devm_clk_get(dsi->dev, "tx_esc");
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		DRM_DEV_ERROR(dsi->dev, "Failed to get tx_esc clock: %d\n",
+			      ret);
+		return ret;
+	}
+	dsi->tx_esc_clk = clk;
+
+	/* The video_pll clock is optional */
+	clk = devm_clk_get(dsi->dev, "video_pll");
+	if (!IS_ERR(clk))
+		dsi->pll_clk = clk;
+
+	/*
+	 * Usually, we don't need this clock here, but due to a design issue,
+	 * the MIPI Reset Synchronizer block depends on this clock. So, we will
+	 * use this clock when we need to reset (or take out of reset) MIPI PHY
+	 */
+	dsi->lcdif_clk = devm_clk_get(dsi->dev, "lcdif");
+	if (IS_ERR(dsi->lcdif_clk))
+		dsi->lcdif_clk = NULL;
+
+	if (dsi->pdata->mux_present) {
+		dsi->mux = devm_mux_control_get(dsi->dev, NULL);
+		if (IS_ERR(dsi->mux)) {
+			ret = PTR_ERR(dsi->mux);
+			if (ret != -EPROBE_DEFER)
+				DRM_DEV_ERROR(dsi->dev,
+					      "Failed to get mux: %d\n", ret);
+			return ret;
+		}
+	}
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	dsi->regmap =
+		devm_regmap_init_mmio(dsi->dev, base, &nwl_dsi_regmap_config);
+	if (IS_ERR(dsi->regmap)) {
+		ret = PTR_ERR(dsi->regmap);
+		DRM_DEV_ERROR(dsi->dev, "Failed to create NWL DSI regmap: %d\n",
+			      ret);
+		return ret;
+	}
+
+	/* For these two regs we need a mapping to MIPI-DSI CSR */
+	if (dsi->pdata->reg_tx_ulps || dsi->pdata->reg_pxl2dpi) {
+		dsi->csr = syscon_regmap_lookup_by_phandle(np, "csr");
+		if (IS_ERR(dsi->csr)) {
+			ret = PTR_ERR(dsi->csr);
+			dev_err(dsi->dev,
+				"Failed to get CSR regmap: %d\n", ret);
+			return ret;
+		}
+	}
+
+	dsi->irq = platform_get_irq(pdev, 0);
+	if (dsi->irq < 0) {
+		if (dsi->irq != -EPROBE_DEFER)
+			DRM_DEV_ERROR(dsi->dev,
+				      "Failed to get device IRQ: %d\n",
+				      dsi->irq);
+		return dsi->irq;
+	}
+
+	/*
+	 * Wee need to manage individual resets, since the order of their usage
+	 * really matters to DSI Host Controller. The order of operation,
+	 * should be like this:
+	 * 1. Deassert pclk reset (this is needed to have access to DSI regs)
+	 * 2. Configure DSI Host and DPHY and enable DPHY
+	 * 3. Deassert ESC and BYTE resets (needed for Host TX operations)
+	 * 4. Send DSI cmds (if the DSI peripheral needs configuration)
+	 * 5. Deassert DPI reset (deasserting DPI reset, enables DPI to receive
+	 *    DPI pixels and start streamming DSI data)
+	 */
+	dsi->rst_pclk = __devm_reset_control_get(dsi->dev,
+						 "pclk", 0, false, true, true);
+	if (IS_ERR(dsi->rst_pclk)) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to get pclk reset: %ld\n",
+			      PTR_ERR(dsi->rst_pclk));
+		return PTR_ERR(dsi->rst_pclk);
+	}
+	dsi->rst_byte = __devm_reset_control_get(dsi->dev,
+						 "byte", 0, false, true, true);
+	if (IS_ERR(dsi->rst_byte)) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to get byte reset: %ld\n",
+			      PTR_ERR(dsi->rst_byte));
+		return PTR_ERR(dsi->rst_byte);
+	}
+	dsi->rst_esc = __devm_reset_control_get(dsi->dev,
+						"esc", 0, false, true, true);
+	if (IS_ERR(dsi->rst_esc)) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to get esc reset: %ld\n",
+			      PTR_ERR(dsi->rst_esc));
+		return PTR_ERR(dsi->rst_esc);
+	}
+	dsi->rst_dpi = __devm_reset_control_get(dsi->dev,
+						"dpi", 0, false, true, true);
+	if (IS_ERR(dsi->rst_dpi)) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to get dpi reset: %ld\n",
+			      PTR_ERR(dsi->rst_dpi));
+		return PTR_ERR(dsi->rst_dpi);
+	}
+
+	of_property_read_u32(np, "fsl,clock-drop-level", &dsi->clk_drop_lvl);
+
+	return 0;
+}
+
+static int imx8mq_dsi_pclk_reset(struct nwl_dsi *dsi, bool reset)
+{
+	int ret = 0;
+
+	if (dsi->rst_pclk) {
+		if (reset)
+			ret = reset_control_assert(dsi->rst_pclk);
+		else
+			ret = reset_control_deassert(dsi->rst_pclk);
+	}
+
+	return ret;
+
+}
+
+static int imx8mq_dsi_mipi_reset(struct nwl_dsi *dsi, bool reset)
+{
+	int ret = 0;
+
+	if (dsi->rst_esc) {
+		if (reset)
+			ret = reset_control_assert(dsi->rst_esc);
+		else
+			ret = reset_control_deassert(dsi->rst_esc);
+	}
+
+	if (dsi->rst_byte) {
+		if (reset)
+			ret = reset_control_assert(dsi->rst_byte);
+		else
+			ret = reset_control_deassert(dsi->rst_byte);
+	}
+
+	return ret;
+
+}
+
+static int imx8mq_dsi_dpi_reset(struct nwl_dsi *dsi, bool reset)
+{
+	int ret = 0;
+
+	if (dsi->rst_dpi) {
+		if (reset)
+			ret = reset_control_assert(dsi->rst_dpi);
+		else
+			ret = reset_control_deassert(dsi->rst_dpi);
+	}
+
+	return ret;
+
+}
+
+static int imx8mq_dsi_select_input(struct nwl_dsi *dsi)
+{
+	struct device_node *remote;
+	u32 use_dcss = 1;
+	int ret;
+
+	remote = of_graph_get_remote_node(dsi->dev->of_node, 0, 0);
+	if (remote && strcmp(remote->name, "lcdif") == 0)
+		use_dcss = 0;
+
+	DRM_DEV_INFO(dsi->dev, "Using %s as input source\n",
+		     (use_dcss) ? "DCSS" : "LCDIF");
+
+	ret = mux_control_try_select(dsi->mux, use_dcss);
+	if (ret < 0)
+		DRM_DEV_ERROR(dsi->dev, "Failed to select input: %d\n", ret);
+
+	of_node_put(remote);
+
+	dsi->use_dcss = use_dcss;
+
+	return ret;
+}
+
+static int imx8mq_dsi_deselect_input(struct nwl_dsi *dsi)
+{
+	int ret;
+
+	ret = mux_control_deselect(dsi->mux);
+	if (ret < 0)
+		DRM_DEV_ERROR(dsi->dev, "Failed to deselect input: %d\n", ret);
+
+	return ret;
+}
+
+static int imx8q_dsi_pclk_reset(struct nwl_dsi *dsi, bool reset)
+{
+	struct imx_sc_ipc *handle;
+	u32 mipi_id, dc_id;
+	u8 ctrl;
+	bool shared_phy = dsi->pdata->shared_phy;
+	int ret = 0;
+
+	ret = imx_scu_get_handle(&handle);
+	if (ret) {
+		DRM_DEV_ERROR(dsi->dev,
+			      "Failed to get scu ipc handle (%d)\n", ret);
+		return ret;
+	}
+
+	mipi_id = (dsi->instance)?MIPI_ID(1):MIPI_ID(0);
+	dc_id = (!shared_phy && dsi->instance)?DC_ID(1):DC_ID(0);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev,
+			     "Power %s PCLK MIPI:%u DC:%u\n",
+			     (reset)?"OFF":"ON", mipi_id, dc_id);
+
+	if (shared_phy) {
+		ret |= imx_sc_misc_set_control(handle,
+				mipi_id, IMX_SC_C_MODE, reset);
+		ret |= imx_sc_misc_set_control(handle,
+				mipi_id, IMX_SC_C_DUAL_MODE, reset);
+		ret |= imx_sc_misc_set_control(handle,
+				mipi_id, IMX_SC_C_PXL_LINK_SEL, reset);
+	}
+
+	/* Initialize Pixel Link */
+	ctrl = (shared_phy && dsi->instance)?PXL_ADDR(2):PXL_ADDR(1);
+	ret |= imx_sc_misc_set_control(handle, dc_id, ctrl, reset);
+
+	ctrl = (shared_phy && dsi->instance)?PXL_VLD(2):PXL_VLD(1);
+	ret |= imx_sc_misc_set_control(handle, dc_id, ctrl, !reset);
+
+	ctrl = (shared_phy && dsi->instance)?SYNC_CTRL(1):SYNC_CTRL(0);
+	ret |= imx_sc_misc_set_control(handle, dc_id, ctrl, !reset);
+
+	return ret;
+}
+
+static int imx8q_dsi_mipi_reset(struct nwl_dsi *dsi, bool reset)
+{
+	struct imx_sc_ipc *handle;
+	u32 mipi_id;
+	int ret = 0;
+
+	ret = imx_scu_get_handle(&handle);
+	if (ret) {
+		DRM_DEV_ERROR(dsi->dev,
+			      "Failed to get scu ipc handle (%d)\n", ret);
+		return ret;
+	}
+
+	mipi_id = (dsi->instance)?MIPI_ID(1):MIPI_ID(0);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev,
+			     "Power %s HOST MIPI:%u\n",
+			     (reset)?"OFF":"ON", mipi_id);
+
+	ret |= imx_sc_misc_set_control(handle, mipi_id,
+				       IMX_SC_C_PHY_RESET, !reset);
+	ret |= imx_sc_misc_set_control(handle, mipi_id,
+				       IMX_SC_C_MIPI_RESET, !reset);
+
+	return ret;
+}
+
+static int imx8q_dsi_dpi_reset(struct nwl_dsi *dsi, bool reset)
+{
+	struct imx_sc_ipc *handle;
+	u32 mipi_id;
+	int ret = 0;
+
+	ret = imx_scu_get_handle(&handle);
+	if (ret) {
+		DRM_DEV_ERROR(dsi->dev,
+			      "Failed to get scu ipc handle (%d)\n", ret);
+		return ret;
+	}
+
+	mipi_id = (dsi->instance)?MIPI_ID(1):MIPI_ID(0);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev,
+			     "Power %s DPI MIPI:%u\n",
+			     (reset)?"OFF":"ON", mipi_id);
+
+	regmap_write(dsi->csr, dsi->pdata->reg_tx_ulps, 0);
+	regmap_write(dsi->csr, dsi->pdata->reg_pxl2dpi, NWL_DSI_DPI_24_BIT);
+
+	ret |= imx_sc_misc_set_control(handle, mipi_id,
+				       IMX_SC_C_DPI_RESET, !reset);
+
+	return ret;
+}
+
+static const struct drm_bridge_timings nwl_dsi_timings = {
+	.input_bus_flags = DRM_BUS_FLAG_DE_LOW,
+};
+
+static const struct nwl_dsi_platform_data imx8mq_dev = {
+	.pclk_reset = &imx8mq_dsi_pclk_reset,
+	.mipi_reset = &imx8mq_dsi_mipi_reset,
+	.dpi_reset = &imx8mq_dsi_dpi_reset,
+	.select_input = &imx8mq_dsi_select_input,
+	.deselect_input = &imx8mq_dsi_deselect_input,
+	.clk_config = {
+		{ .id = NWL_DSI_CLK_CORE, .present = true },
+	},
+	.mux_present = true,
+};
+
+static const struct nwl_dsi_platform_data imx8qm_dev = {
+	.pclk_reset = &imx8q_dsi_pclk_reset,
+	.mipi_reset = &imx8q_dsi_mipi_reset,
+	.dpi_reset = &imx8q_dsi_dpi_reset,
+	.clk_config = {
+		{ .id = NWL_DSI_CLK_BYPASS, .present = true },
+		{ .id = NWL_DSI_CLK_PIXEL, .present = true },
+	},
+	.reg_tx_ulps = 0x00,
+	.reg_pxl2dpi = 0x04,
+	.max_instances = 2,
+	.tx_clk_rate = 18000000,
+	.rx_clk_rate = 72000000,
+	.shared_phy = false,
+};
+
+static const struct nwl_dsi_platform_data imx8qx_dev = {
+	.pclk_reset = &imx8q_dsi_pclk_reset,
+	.mipi_reset = &imx8q_dsi_mipi_reset,
+	.dpi_reset = &imx8q_dsi_dpi_reset,
+	.clk_config = {
+		{ .id = NWL_DSI_CLK_BYPASS, .present = true },
+		{ .id = NWL_DSI_CLK_PIXEL, .present = true },
+	},
+	.reg_tx_ulps = 0x30,
+	.reg_pxl2dpi = 0x40,
+	.max_instances = 2,
+	.tx_clk_rate = 18000000,
+	.rx_clk_rate = 72000000,
+	.shared_phy = true,
+};
+
+static const struct of_device_id nwl_dsi_dt_ids[] = {
+	{ .compatible = "fsl,imx8mq-nwl-dsi", .data = &imx8mq_dev, },
+	{ .compatible = "fsl,imx8qm-nwl-dsi", .data = &imx8qm_dev, },
+	{ .compatible = "fsl,imx8qx-nwl-dsi", .data = &imx8qx_dev, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids);
+
+static const struct soc_device_attribute nwl_dsi_quirks_match[] = {
+	{ .soc_id = "i.MX8MQ", .revision = "2.0",
+	  .data = (void *)(E11418_HS_MODE_QUIRK | SRC_RESET_QUIRK) },
+	{ /* sentinel. */ },
+};
+
+static int nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+
+	imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs nwl_dsi_encoder_helper_funcs = {
+	.atomic_check = nwl_dsi_encoder_atomic_check,
+};
+
+static int nwl_dsi_bind(struct device *dev,
+			struct device *master,
+			void *data)
+{
+	struct drm_device *drm = data;
+	uint32_t crtc_mask;
+	struct nwl_dsi *dsi = dev_get_drvdata(dev);
+	int ret = 0;
+
+	crtc_mask = drm_of_find_possible_crtcs(drm, dev->of_node);
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (crtc_mask == 0)
+		return -EPROBE_DEFER;
+
+	DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+	dsi->encoder.possible_crtcs = crtc_mask;
+	dsi->encoder.possible_clones = ~0;
+
+	drm_encoder_helper_add(&dsi->encoder,
+			       &nwl_dsi_encoder_helper_funcs);
+	ret = drm_encoder_init(drm,
+			       &dsi->encoder,
+			       &nwl_dsi_encoder_funcs,
+			       DRM_MODE_ENCODER_DSI,
+			       NULL);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to init DSI encoder (%d)\n", ret);
+		return ret;
+	}
+
+	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL);
+	if (ret)
+		drm_encoder_cleanup(&dsi->encoder);
+
+	/*
+	 *  -ENODEV is returned when there is no node connected to us. Since
+	 *  it might be disabled because the device is not actually connected,
+	 *  just cleanup and return 0.
+	 */
+	if (ret == -ENODEV)
+		return 0;
+
+	return ret;
+}
+
+static void nwl_dsi_unbind(struct device *dev,
+			   struct device *master,
+			   void *data)
+{
+	struct nwl_dsi *dsi = dev_get_drvdata(dev);
+
+	DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+	if (dsi->encoder.dev)
+		drm_encoder_cleanup(&dsi->encoder);
+}
+
+static const struct component_ops nwl_dsi_component_ops = {
+	.bind	= nwl_dsi_bind,
+	.unbind	= nwl_dsi_unbind,
+};
+
+static int nwl_dsi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(nwl_dsi_dt_ids, dev);
+	const struct soc_device_attribute *attr;
+	struct nwl_dsi *dsi;
+	int ret;
+
+	if (!of_id || !of_id->data)
+		return -ENODEV;
+
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+
+	dsi->dev = dev;
+	dsi->pdata = of_id->data;
+
+	attr = soc_device_match(nwl_dsi_quirks_match);
+	if (attr)
+		dsi->quirks = (uintptr_t)attr->data;
+
+	ret = nwl_dsi_parse_dt(dsi);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(dev, dsi->irq, nwl_dsi_irq_handler, 0,
+			       dev_name(dev), dsi);
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			DRM_DEV_ERROR(dev, "Failed to request IRQ %d: %d\n",
+				      dsi->irq, ret);
+		return ret;
+	}
+
+	dsi->dsi_host.ops = &nwl_dsi_host_ops;
+	dsi->dsi_host.dev = dev;
+	ret = mipi_dsi_host_register(&dsi->dsi_host);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
+		return ret;
+	}
+
+	dsi->bridge.driver_private = dsi;
+	dsi->bridge.funcs = &nwl_dsi_bridge_funcs;
+	dsi->bridge.of_node = dev->of_node;
+	dsi->bridge.timings = &nwl_dsi_timings;
+
+	if (dsi->pdata->select_input)
+		dsi->pdata->select_input(dsi);
+
+	drm_bridge_add(&dsi->bridge);
+
+	INIT_LIST_HEAD(&dsi->valid_modes);
+
+	dev_set_drvdata(dev, dsi);
+	pm_runtime_enable(dev);
+
+	if (of_property_read_bool(dev->of_node, "use-disp-ss"))
+		ret = component_add(&pdev->dev, &nwl_dsi_component_ops);
+
+	if (ret) {
+		pm_runtime_disable(dev);
+		drm_bridge_remove(&dsi->bridge);
+		mipi_dsi_host_unregister(&dsi->dsi_host);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int nwl_dsi_remove(struct platform_device *pdev)
+{
+	struct nwl_dsi *dsi = platform_get_drvdata(pdev);
+	struct mode_config *config;
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &dsi->valid_modes) {
+		config = list_entry(pos, struct mode_config, list);
+		list_del(pos);
+		devm_kfree(dsi->dev, config);
+	}
+
+	pm_runtime_disable(&pdev->dev);
+	drm_bridge_remove(&dsi->bridge);
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+
+	return 0;
+}
+
+static struct platform_driver nwl_dsi_driver = {
+	.probe		= nwl_dsi_probe,
+	.remove		= nwl_dsi_remove,
+	.driver		= {
+		.of_match_table = nwl_dsi_dt_ids,
+		.name	= DRV_NAME,
+	},
+};
+
+module_platform_driver(nwl_dsi_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_AUTHOR("Purism SPC");
+MODULE_DESCRIPTION("Northwest Logic MIPI-DSI driver");
+MODULE_LICENSE("GPL"); /* GPLv2 or later */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/nwl-drv.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * NWL MIPI DSI host driver
+ *
+ * Copyright (C) 2017 NXP
+ * Copyright (C) 2019 Purism SPC
+ */
+
+#ifndef __NWL_DRV_H__
+#define __NWL_DRV_H__
+
+#include <linux/mux/consumer.h>
+#include <linux/phy/phy.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+
+struct nwl_dsi_platform_data;
+
+/* i.MX8 NWL quirks */
+/* i.MX8MQ errata E11418 */
+#define E11418_HS_MODE_QUIRK	    BIT(0)
+/* Skip DSI bits in SRC on disable to avoid blank display on enable */
+#define SRC_RESET_QUIRK		    BIT(1)
+
+/* * DPI color coding */
+#define NWL_DSI_DPI_16_BIT_565_PACKED	0
+#define NWL_DSI_DPI_16_BIT_565_ALIGNED	1
+#define NWL_DSI_DPI_16_BIT_565_SHIFTED	2
+#define NWL_DSI_DPI_18_BIT_PACKED	3
+#define NWL_DSI_DPI_18_BIT_ALIGNED	4
+#define NWL_DSI_DPI_24_BIT		5
+
+
+#define NWL_DSI_MAX_PLATFORM_CLOCKS 2
+struct nwl_dsi_plat_clk_config {
+	const char *id;
+	struct clk *clk;
+	bool present;
+};
+
+struct mode_config {
+	int				clock;
+	int				crtc_clock;
+	unsigned int			lanes;
+	unsigned long			bitclock;
+	unsigned long			phy_rates[3];
+	unsigned long			pll_rates[3];
+	int				phy_rate_idx;
+	struct list_head		list;
+};
+
+struct nwl_dsi {
+	struct drm_encoder encoder;
+	struct drm_bridge bridge;
+	struct mipi_dsi_host dsi_host;
+	struct drm_bridge *panel_bridge;
+	struct device *dev;
+	struct phy *phy;
+	union phy_configure_opts phy_cfg;
+	unsigned int quirks;
+	unsigned int instance;
+
+	struct regmap *regmap;
+	struct regmap *csr;
+	int irq;
+	struct reset_control *rst_byte;
+	struct reset_control *rst_esc;
+	struct reset_control *rst_dpi;
+	struct reset_control *rst_pclk;
+	struct mux_control *mux;
+
+	/* DSI clocks */
+	struct clk *phy_ref_clk;
+	struct clk *rx_esc_clk;
+	struct clk *tx_esc_clk;
+	struct clk *pll_clk;
+	struct clk *lcdif_clk;
+	/* Platform dependent clocks */
+	struct nwl_dsi_plat_clk_config clk_config[NWL_DSI_MAX_PLATFORM_CLOCKS];
+
+	struct list_head valid_modes;
+	/* dsi lanes */
+	u32 lanes;
+	u32 clk_drop_lvl;
+	enum mipi_dsi_pixel_format format;
+	struct drm_display_mode mode;
+	unsigned long dsi_mode_flags;
+
+	struct nwl_dsi_transfer *xfer;
+
+	const struct nwl_dsi_platform_data *pdata;
+
+	bool use_dcss;
+};
+
+#endif /* __NWL_DRV_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.c
@@ -0,0 +1,684 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NWL MIPI DSI host driver
+ *
+ * Copyright (C) 2017 NXP
+ * Copyright (C) 2019 Purism SPC
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <linux/time64.h>
+
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include "nwl-drv.h"
+#include "nwl-dsi.h"
+
+#define NWL_DSI_MIPI_FIFO_TIMEOUT msecs_to_jiffies(500)
+
+/*
+ * PKT_CONTROL format:
+ * [15: 0] - word count
+ * [17:16] - virtual channel
+ * [23:18] - data type
+ * [24]	   - LP or HS select (0 - LP, 1 - HS)
+ * [25]	   - perform BTA after packet is sent
+ * [26]	   - perform BTA only, no packet tx
+ */
+#define NWL_DSI_WC(x)		FIELD_PREP(GENMASK(15, 0), (x))
+#define NWL_DSI_TX_VC(x)	FIELD_PREP(GENMASK(17, 16), (x))
+#define NWL_DSI_TX_DT(x)	FIELD_PREP(GENMASK(23, 18), (x))
+#define NWL_DSI_HS_SEL(x)	FIELD_PREP(GENMASK(24, 24), (x))
+#define NWL_DSI_BTA_TX(x)	FIELD_PREP(GENMASK(25, 25), (x))
+#define NWL_DSI_BTA_NO_TX(x)	FIELD_PREP(GENMASK(26, 26), (x))
+
+/*
+ * RX_PKT_HEADER format:
+ * [15: 0] - word count
+ * [21:16] - data type
+ * [23:22] - virtual channel
+ */
+#define NWL_DSI_RX_DT(x)	FIELD_GET(GENMASK(21, 16), (x))
+#define NWL_DSI_RX_VC(x)	FIELD_GET(GENMASK(23, 22), (x))
+
+/* DSI Video mode */
+#define NWL_DSI_VM_BURST_MODE_WITH_SYNC_PULSES		0
+#define NWL_DSI_VM_NON_BURST_MODE_WITH_SYNC_EVENTS	BIT(0)
+#define NWL_DSI_VM_BURST_MODE				BIT(1)
+
+/* * DPI color coding */
+#define NWL_DSI_DPI_16_BIT_565_PACKED	0
+#define NWL_DSI_DPI_16_BIT_565_ALIGNED	1
+#define NWL_DSI_DPI_16_BIT_565_SHIFTED	2
+#define NWL_DSI_DPI_18_BIT_PACKED	3
+#define NWL_DSI_DPI_18_BIT_ALIGNED	4
+#define NWL_DSI_DPI_24_BIT		5
+
+/* * DPI Pixel format */
+#define NWL_DSI_PIXEL_FORMAT_16  0
+#define NWL_DSI_PIXEL_FORMAT_18  BIT(0)
+#define NWL_DSI_PIXEL_FORMAT_18L BIT(1)
+#define NWL_DSI_PIXEL_FORMAT_24  (BIT(0) | BIT(1))
+
+enum transfer_direction {
+	DSI_PACKET_SEND,
+	DSI_PACKET_RECEIVE,
+};
+
+struct nwl_dsi_transfer {
+	const struct mipi_dsi_msg *msg;
+	struct mipi_dsi_packet packet;
+	struct completion completed;
+
+	int status; /* status of transmission */
+	enum transfer_direction direction;
+	bool need_bta;
+	u8 cmd;
+	u16 rx_word_count;
+	size_t tx_len; /* in bytes */
+	size_t rx_len; /* in bytes */
+};
+
+static int nwl_dsi_write(struct nwl_dsi *dsi, unsigned int reg, u32 val)
+{
+	int ret;
+
+	ret = regmap_write(dsi->regmap, reg, val);
+	if (ret < 0)
+		DRM_DEV_ERROR(dsi->dev,
+			      "Failed to write NWL DSI reg 0x%x: %d\n", reg,
+			      ret);
+	return ret;
+}
+
+static u32 nwl_dsi_read(struct nwl_dsi *dsi, u32 reg)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(dsi->regmap, reg, &val);
+	if (ret < 0)
+		DRM_DEV_ERROR(dsi->dev, "Failed to read NWL DSI reg 0x%x: %d\n",
+			      reg, ret);
+
+	return val;
+}
+
+static u32 nwl_dsi_get_dpi_pixel_format(enum mipi_dsi_pixel_format format)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB565:
+		return NWL_DSI_PIXEL_FORMAT_16;
+	case MIPI_DSI_FMT_RGB666:
+		return NWL_DSI_PIXEL_FORMAT_18L;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return NWL_DSI_PIXEL_FORMAT_18;
+	case MIPI_DSI_FMT_RGB888:
+		return NWL_DSI_PIXEL_FORMAT_24;
+	default:
+		return -EINVAL;
+	}
+}
+
+#define PSEC_PER_SEC 1000000000000LL
+/*
+ * ps2bc - Picoseconds to byte clock cycles
+ */
+static u32 ps2bc(struct nwl_dsi *dsi, unsigned long long ps)
+{
+	int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+
+	return DIV_ROUND_UP(ps * dsi->mode.clock * 1000 * bpp,
+			    dsi->lanes * 8 * PSEC_PER_SEC);
+}
+
+/*
+ * ui2bc - UI time periods to byte clock cycles
+ */
+static u32 ui2bc(struct nwl_dsi *dsi, unsigned long long ui)
+{
+	int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+
+	return DIV_ROUND_UP(ui * dsi->lanes, dsi->mode.clock * 1000 * bpp);
+}
+
+/*
+ * us2bc - micro seconds to lp clock cycles
+ */
+static u32 us2lp(u32 lp_clk_rate, unsigned long us)
+{
+	return DIV_ROUND_UP(us * lp_clk_rate, USEC_PER_SEC);
+}
+
+static int nwl_dsi_config_host(struct nwl_dsi *dsi)
+{
+	u32 cycles;
+	struct phy_configure_opts_mipi_dphy *cfg = &dsi->phy_cfg.mipi_dphy;
+
+	if (dsi->lanes < 1 || dsi->lanes > 4)
+		return -EINVAL;
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "DSI Lanes %d\n", dsi->lanes);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_NUM_LANES, dsi->lanes - 1);
+
+	if (dsi->dsi_mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+		nwl_dsi_write(dsi, NWL_DSI_CFG_NONCONTINUOUS_CLK, 0x01);
+		nwl_dsi_write(dsi, NWL_DSI_CFG_AUTOINSERT_EOTP, 0x01);
+	} else {
+		nwl_dsi_write(dsi, NWL_DSI_CFG_NONCONTINUOUS_CLK, 0x00);
+		nwl_dsi_write(dsi, NWL_DSI_CFG_AUTOINSERT_EOTP, 0x00);
+	}
+
+	/* values in byte clock cycles */
+	cycles = ui2bc(dsi, cfg->clk_pre);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_pre: 0x%x\n", cycles);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_T_PRE, cycles);
+	cycles = ps2bc(dsi, cfg->lpx + cfg->clk_prepare + cfg->clk_zero);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap (pre): 0x%x\n", cycles);
+	cycles += ui2bc(dsi, cfg->clk_pre);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap: 0x%x\n", cycles);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_T_POST, cycles);
+	cycles = ps2bc(dsi, cfg->hs_exit);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap: 0x%x\n", cycles);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_TX_GAP, cycles);
+
+	nwl_dsi_write(dsi, NWL_DSI_CFG_EXTRA_CMDS_AFTER_EOTP, 0x01);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_HTX_TO_COUNT, 0x00);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_LRX_H_TO_COUNT, 0x00);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_BTA_H_TO_COUNT, 0x00);
+	/* In LP clock cycles */
+	cycles = us2lp(cfg->lp_clk_rate, cfg->wakeup);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_twakeup: 0x%x\n", cycles);
+	nwl_dsi_write(dsi, NWL_DSI_CFG_TWAKEUP, cycles);
+
+	return 0;
+}
+
+static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)
+{
+	u32 color_format, mode;
+	bool burst_mode;
+	int hfront_porch, hback_porch, vfront_porch, vback_porch;
+	int hsync_len, vsync_len;
+
+	hfront_porch = dsi->mode.hsync_start - dsi->mode.hdisplay;
+	hsync_len = dsi->mode.hsync_end - dsi->mode.hsync_start;
+	hback_porch = dsi->mode.htotal - dsi->mode.hsync_end;
+
+	vfront_porch = dsi->mode.vsync_start - dsi->mode.vdisplay;
+	vsync_len = dsi->mode.vsync_end - dsi->mode.vsync_start;
+	vback_porch = dsi->mode.vtotal - dsi->mode.vsync_end;
+
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "hfront_porch = %d\n", hfront_porch);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "hback_porch = %d\n", hback_porch);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "hsync_len = %d\n", hsync_len);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "hdisplay = %d\n", dsi->mode.hdisplay);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "vfront_porch = %d\n", vfront_porch);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "vback_porch = %d\n", vback_porch);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "vsync_len = %d\n", vsync_len);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "vactive = %d\n", dsi->mode.vdisplay);
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "clock = %d kHz\n", dsi->mode.clock);
+
+	color_format = nwl_dsi_get_dpi_pixel_format(dsi->format);
+	if (color_format < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Invalid color format 0x%x\n",
+			      dsi->format);
+		return color_format;
+	}
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "pixel fmt = %d\n", dsi->format);
+
+	nwl_dsi_write(dsi, NWL_DSI_INTERFACE_COLOR_CODING, NWL_DSI_DPI_24_BIT);
+	nwl_dsi_write(dsi, NWL_DSI_PIXEL_FORMAT, color_format);
+	/*
+	 * Adjusting input polarity based on the video mode results in
+	 * a black screen so always pick active low:
+	 */
+	nwl_dsi_write(dsi, NWL_DSI_VSYNC_POLARITY,
+		      NWL_DSI_VSYNC_POLARITY_ACTIVE_LOW);
+	nwl_dsi_write(dsi, NWL_DSI_HSYNC_POLARITY,
+		      NWL_DSI_HSYNC_POLARITY_ACTIVE_LOW);
+
+	burst_mode = (dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
+		     !(dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE);
+
+	if (burst_mode) {
+		nwl_dsi_write(dsi, NWL_DSI_VIDEO_MODE, NWL_DSI_VM_BURST_MODE);
+		nwl_dsi_write(dsi, NWL_DSI_PIXEL_FIFO_SEND_LEVEL, 256);
+	} else {
+		mode = ((dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ?
+				NWL_DSI_VM_BURST_MODE_WITH_SYNC_PULSES :
+				NWL_DSI_VM_NON_BURST_MODE_WITH_SYNC_EVENTS);
+		nwl_dsi_write(dsi, NWL_DSI_VIDEO_MODE, mode);
+		nwl_dsi_write(dsi, NWL_DSI_PIXEL_FIFO_SEND_LEVEL,
+			      dsi->mode.hdisplay);
+	}
+
+	nwl_dsi_write(dsi, NWL_DSI_HFP, hfront_porch);
+	nwl_dsi_write(dsi, NWL_DSI_HBP, hback_porch);
+	nwl_dsi_write(dsi, NWL_DSI_HSA, hsync_len);
+
+	nwl_dsi_write(dsi, NWL_DSI_ENABLE_MULT_PKTS, 0x0);
+	nwl_dsi_write(dsi, NWL_DSI_BLLP_MODE, 0x1);
+	nwl_dsi_write(dsi, NWL_DSI_ENABLE_MULT_PKTS, 0x0);
+	nwl_dsi_write(dsi, NWL_DSI_USE_NULL_PKT_BLLP, 0x0);
+	nwl_dsi_write(dsi, NWL_DSI_VC, 0x0);
+
+	nwl_dsi_write(dsi, NWL_DSI_PIXEL_PAYLOAD_SIZE, dsi->mode.hdisplay);
+	nwl_dsi_write(dsi, NWL_DSI_VACTIVE, dsi->mode.vdisplay - 1);
+	nwl_dsi_write(dsi, NWL_DSI_VBP, vback_porch);
+	nwl_dsi_write(dsi, NWL_DSI_VFP, vfront_porch);
+
+	return 0;
+}
+
+static void nwl_dsi_init_interrupts(struct nwl_dsi *dsi)
+{
+	u32 irq_enable;
+
+	nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, 0xffffffff);
+	nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
+
+	irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
+			    NWL_DSI_RX_PKT_HDR_RCVD_MASK |
+			    NWL_DSI_TX_FIFO_OVFLW_MASK |
+			    NWL_DSI_HS_TX_TIMEOUT_MASK);
+
+	nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, irq_enable);
+}
+
+static int nwl_dsi_host_attach(struct mipi_dsi_host *dsi_host,
+			       struct mipi_dsi_device *device)
+{
+	struct nwl_dsi *dsi = container_of(dsi_host, struct nwl_dsi, dsi_host);
+	struct device *dev = dsi->dev;
+
+	DRM_DEV_INFO(dev, "lanes=%u, format=0x%x flags=0x%lx\n", device->lanes,
+		     device->format, device->mode_flags);
+
+	if (device->lanes < 1 || device->lanes > 4)
+		return -EINVAL;
+
+	dsi->lanes = device->lanes;
+	dsi->format = device->format;
+	dsi->dsi_mode_flags = device->mode_flags;
+
+	return 0;
+}
+
+static int nwl_dsi_host_detach(struct mipi_dsi_host *dsi_host,
+			       struct mipi_dsi_device *device)
+{
+	struct nwl_dsi *dsi = container_of(dsi_host, struct nwl_dsi, dsi_host);
+
+	dsi->lanes = 0;
+	dsi->format = 0;
+	dsi->dsi_mode_flags = 0;
+
+	return 0;
+}
+
+static bool nwl_dsi_read_packet(struct nwl_dsi *dsi, u32 status)
+{
+	struct device *dev = dsi->dev;
+	struct nwl_dsi_transfer *xfer = dsi->xfer;
+	u8 *payload = xfer->msg->rx_buf;
+	u32 val;
+	u16 word_count;
+	u8 channel;
+	u8 data_type;
+
+	xfer->status = 0;
+
+	if (xfer->rx_word_count == 0) {
+		if (!(status & NWL_DSI_RX_PKT_HDR_RCVD))
+			return false;
+		/* Get the RX header and parse it */
+		val = nwl_dsi_read(dsi, NWL_DSI_RX_PKT_HEADER);
+		word_count = NWL_DSI_WC(val);
+		channel = NWL_DSI_RX_VC(val);
+		data_type = NWL_DSI_RX_DT(val);
+
+		if (channel != xfer->msg->channel) {
+			DRM_DEV_ERROR(dev,
+				      "[%02X] Channel mismatch (%u != %u)\n",
+				      xfer->cmd, channel, xfer->msg->channel);
+			return true;
+		}
+
+		switch (data_type) {
+		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+			/* Fall through */
+		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+			if (xfer->msg->rx_len > 1) {
+				/* read second byte */
+				payload[1] = word_count >> 8;
+				++xfer->rx_len;
+			}
+			/* Fall through */
+		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+			/* Fall through */
+		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+			if (xfer->msg->rx_len > 0) {
+				/* read first byte */
+				payload[0] = word_count & 0xff;
+				++xfer->rx_len;
+			}
+			xfer->status = xfer->rx_len;
+			return true;
+		case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+			word_count &= 0xff;
+			DRM_DEV_ERROR(dev, "[%02X] DSI error report: 0x%02x\n",
+				      xfer->cmd, word_count);
+			xfer->status = -EPROTO;
+			return true;
+		}
+
+		if (word_count > xfer->msg->rx_len) {
+			DRM_DEV_ERROR(
+				dev,
+				"[%02X] Receive buffer too small: %lu (< %u)\n",
+				xfer->cmd, xfer->msg->rx_len, word_count);
+			return true;
+		}
+
+		xfer->rx_word_count = word_count;
+	} else {
+		/* Set word_count from previous header read */
+		word_count = xfer->rx_word_count;
+	}
+
+	/* If RX payload is not yet received, wait for it */
+	if (!(status & NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD))
+		return false;
+
+	/* Read the RX payload */
+	while (word_count >= 4) {
+		val = nwl_dsi_read(dsi, NWL_DSI_RX_PAYLOAD);
+		payload[0] = (val >> 0) & 0xff;
+		payload[1] = (val >> 8) & 0xff;
+		payload[2] = (val >> 16) & 0xff;
+		payload[3] = (val >> 24) & 0xff;
+		payload += 4;
+		xfer->rx_len += 4;
+		word_count -= 4;
+	}
+
+	if (word_count > 0) {
+		val = nwl_dsi_read(dsi, NWL_DSI_RX_PAYLOAD);
+		switch (word_count) {
+		case 3:
+			payload[2] = (val >> 16) & 0xff;
+			++xfer->rx_len;
+			/* Fall through */
+		case 2:
+			payload[1] = (val >> 8) & 0xff;
+			++xfer->rx_len;
+			/* Fall through */
+		case 1:
+			payload[0] = (val >> 0) & 0xff;
+			++xfer->rx_len;
+			break;
+		}
+	}
+
+	xfer->status = xfer->rx_len;
+
+	return true;
+}
+
+static void nwl_dsi_finish_transmission(struct nwl_dsi *dsi, u32 status)
+{
+	struct nwl_dsi_transfer *xfer = dsi->xfer;
+	bool end_packet = false;
+
+	if (!xfer)
+		return;
+
+	if (status & NWL_DSI_TX_FIFO_OVFLW) {
+		DRM_DEV_ERROR_RATELIMITED(dsi->dev, "tx fifo overflow\n");
+		return;
+	}
+
+	if (status & NWL_DSI_HS_TX_TIMEOUT) {
+		DRM_DEV_ERROR_RATELIMITED(dsi->dev, "HS tx timeout\n");
+		return;
+	}
+
+	if (xfer->direction == DSI_PACKET_SEND &&
+	    status & NWL_DSI_TX_PKT_DONE) {
+		xfer->status = xfer->tx_len;
+		end_packet = true;
+	} else if (status & NWL_DSI_DPHY_DIRECTION &&
+		   ((status & (NWL_DSI_RX_PKT_HDR_RCVD |
+			       NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD)))) {
+		end_packet = nwl_dsi_read_packet(dsi, status);
+	}
+
+	if (end_packet)
+		complete(&xfer->completed);
+}
+
+static void nwl_dsi_begin_transmission(struct nwl_dsi *dsi)
+{
+	struct nwl_dsi_transfer *xfer = dsi->xfer;
+	struct mipi_dsi_packet *pkt = &xfer->packet;
+	const u8 *payload;
+	size_t length;
+	u16 word_count;
+	u8 hs_mode;
+	u32 val;
+	u32 hs_workaround = 0;
+
+	/* Send the payload, if any */
+	length = pkt->payload_length;
+	payload = pkt->payload;
+
+	while (length >= 4) {
+		val = *(u32 *)payload;
+		hs_workaround |= !(val & 0xFFFF00);
+		nwl_dsi_write(dsi, NWL_DSI_TX_PAYLOAD, val);
+		payload += 4;
+		length -= 4;
+	}
+	/* Send the rest of the payload */
+	val = 0;
+	switch (length) {
+	case 3:
+		val |= payload[2] << 16;
+		/* Fall through */
+	case 2:
+		val |= payload[1] << 8;
+		hs_workaround |= !(val & 0xFFFF00);
+		/* Fall through */
+	case 1:
+		val |= payload[0];
+		nwl_dsi_write(dsi, NWL_DSI_TX_PAYLOAD, val);
+		break;
+	}
+	xfer->tx_len = pkt->payload_length;
+
+	/*
+	 * Send the header
+	 * header[0] = Virtual Channel + Data Type
+	 * header[1] = Word Count LSB (LP) or first param (SP)
+	 * header[2] = Word Count MSB (LP) or second param (SP)
+	 */
+	word_count = pkt->header[1] | (pkt->header[2] << 8);
+	if (hs_workaround && (dsi->quirks & E11418_HS_MODE_QUIRK)) {
+		DRM_DEV_DEBUG_DRIVER(dsi->dev,
+				     "Using hs mode workaround for cmd 0x%x\n",
+				     xfer->cmd);
+		hs_mode = 1;
+	} else {
+		hs_mode = (xfer->msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : 1;
+	}
+	val = NWL_DSI_WC(word_count) | NWL_DSI_TX_VC(xfer->msg->channel) |
+	      NWL_DSI_TX_DT(xfer->msg->type) | NWL_DSI_HS_SEL(hs_mode) |
+	      NWL_DSI_BTA_TX(xfer->need_bta);
+	nwl_dsi_write(dsi, NWL_DSI_PKT_CONTROL, val);
+
+	/* Send packet command */
+	nwl_dsi_write(dsi, NWL_DSI_SEND_PACKET, 0x1);
+}
+
+static ssize_t nwl_dsi_host_transfer(struct mipi_dsi_host *dsi_host,
+				     const struct mipi_dsi_msg *msg)
+{
+	struct nwl_dsi *dsi = container_of(dsi_host, struct nwl_dsi, dsi_host);
+	struct nwl_dsi_transfer xfer;
+	ssize_t ret = 0;
+
+	/* Create packet to be sent */
+	dsi->xfer = &xfer;
+	ret = mipi_dsi_create_packet(&xfer.packet, msg);
+	if (ret < 0) {
+		dsi->xfer = NULL;
+		return ret;
+	}
+
+	if ((msg->type & MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM ||
+	     msg->type & MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM ||
+	     msg->type & MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM ||
+	     msg->type & MIPI_DSI_DCS_READ) &&
+	    msg->rx_len > 0 && msg->rx_buf != NULL)
+		xfer.direction = DSI_PACKET_RECEIVE;
+	else
+		xfer.direction = DSI_PACKET_SEND;
+
+	xfer.need_bta = (xfer.direction == DSI_PACKET_RECEIVE);
+	xfer.need_bta |= (msg->flags & MIPI_DSI_MSG_REQ_ACK) ? 1 : 0;
+	xfer.msg = msg;
+	xfer.status = -ETIMEDOUT;
+	xfer.rx_word_count = 0;
+	xfer.rx_len = 0;
+	xfer.cmd = 0x00;
+	if (msg->tx_len > 0)
+		xfer.cmd = ((u8 *)(msg->tx_buf))[0];
+	init_completion(&xfer.completed);
+
+	ret = clk_prepare_enable(dsi->rx_esc_clk);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to enable rx_esc clk: %zd\n",
+			      ret);
+		return ret;
+	}
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "Enabled rx_esc clk @%lu Hz\n",
+			     clk_get_rate(dsi->rx_esc_clk));
+
+	/* Initiate the DSI packet transmision */
+	nwl_dsi_begin_transmission(dsi);
+
+	if (!wait_for_completion_timeout(&xfer.completed,
+					 NWL_DSI_MIPI_FIFO_TIMEOUT)) {
+		DRM_DEV_ERROR(dsi_host->dev, "[%02X] DSI transfer timed out\n",
+			      xfer.cmd);
+		ret = -ETIMEDOUT;
+	} else {
+		ret = xfer.status;
+	}
+
+	clk_disable_unprepare(dsi->rx_esc_clk);
+
+	return ret;
+}
+
+const struct mipi_dsi_host_ops nwl_dsi_host_ops = {
+	.attach = nwl_dsi_host_attach,
+	.detach = nwl_dsi_host_detach,
+	.transfer = nwl_dsi_host_transfer,
+};
+
+irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
+{
+	u32 irq_status;
+	struct nwl_dsi *dsi = data;
+
+	irq_status = nwl_dsi_read(dsi, NWL_DSI_IRQ_STATUS);
+
+	if (irq_status & NWL_DSI_TX_PKT_DONE ||
+	    irq_status & NWL_DSI_RX_PKT_HDR_RCVD ||
+	    irq_status & NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD)
+		nwl_dsi_finish_transmission(dsi, irq_status);
+
+	return IRQ_HANDLED;
+}
+
+int nwl_dsi_enable(struct nwl_dsi *dsi)
+{
+	struct device *dev = dsi->dev;
+	union phy_configure_opts *phy_cfg = &dsi->phy_cfg;
+	int ret;
+
+	if (!dsi->lanes) {
+		DRM_DEV_ERROR(dev, "Need DSI lanes: %d\n", dsi->lanes);
+		return -EINVAL;
+	}
+
+	ret = phy_init(dsi->phy);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "Failed to init DSI phy: %d\n", ret);
+		return ret;
+	}
+
+	ret = phy_configure(dsi->phy, phy_cfg);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "Failed to configure DSI phy: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(dsi->tx_esc_clk);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to enable tx_esc clk: %d\n",
+			      ret);
+		return ret;
+	}
+	DRM_DEV_DEBUG_DRIVER(dsi->dev, "Enabled tx_esc clk @%lu Hz\n",
+			     clk_get_rate(dsi->tx_esc_clk));
+
+	ret = nwl_dsi_config_host(dsi);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "Failed to set up DSI: %d", ret);
+		return ret;
+	}
+
+	ret = nwl_dsi_config_dpi(dsi);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "Failed to set up DPI: %d", ret);
+		return ret;
+	}
+
+	ret = phy_power_on(dsi->phy);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "Failed to power on DPHY (%d)\n", ret);
+		return ret;
+	}
+
+	nwl_dsi_init_interrupts(dsi);
+
+	return 0;
+}
+
+int nwl_dsi_disable(struct nwl_dsi *dsi)
+{
+	struct device *dev = dsi->dev;
+
+	DRM_DEV_DEBUG_DRIVER(dev, "Disabling clocks and phy\n");
+
+	phy_power_off(dsi->phy);
+	phy_exit(dsi->phy);
+
+	/* Disabling the clock before the phy breaks enabling dsi again */
+	clk_disable_unprepare(dsi->tx_esc_clk);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.h
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nwl-dsi/nwl-dsi.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * NWL MIPI DSI host driver
+ *
+ * Copyright (C) 2017 NXP
+ * Copyright (C) 2019 Purism SPC
+ */
+#ifndef __NWL_DSI_H__
+#define __NWL_DSI_H__
+
+#include <linux/irqreturn.h>
+
+#include <drm/drm_mipi_dsi.h>
+
+#include "nwl-drv.h"
+
+/* DSI HOST registers */
+#define NWL_DSI_CFG_NUM_LANES			0x0
+#define NWL_DSI_CFG_NONCONTINUOUS_CLK		0x4
+#define NWL_DSI_CFG_T_PRE			0x8
+#define NWL_DSI_CFG_T_POST			0xc
+#define NWL_DSI_CFG_TX_GAP			0x10
+#define NWL_DSI_CFG_AUTOINSERT_EOTP		0x14
+#define NWL_DSI_CFG_EXTRA_CMDS_AFTER_EOTP	0x18
+#define NWL_DSI_CFG_HTX_TO_COUNT		0x1c
+#define NWL_DSI_CFG_LRX_H_TO_COUNT		0x20
+#define NWL_DSI_CFG_BTA_H_TO_COUNT		0x24
+#define NWL_DSI_CFG_TWAKEUP			0x28
+#define NWL_DSI_CFG_STATUS_OUT			0x2c
+#define NWL_DSI_RX_ERROR_STATUS			0x30
+
+/* DSI DPI registers */
+#define NWL_DSI_PIXEL_PAYLOAD_SIZE		0x200
+#define NWL_DSI_PIXEL_FIFO_SEND_LEVEL		0x204
+#define NWL_DSI_INTERFACE_COLOR_CODING		0x208
+#define NWL_DSI_PIXEL_FORMAT			0x20c
+#define NWL_DSI_VSYNC_POLARITY			0x210
+#define NWL_DSI_VSYNC_POLARITY_ACTIVE_LOW	0
+#define NWL_DSI_VSYNC_POLARITY_ACTIVE_HIGH	BIT(1)
+
+#define NWL_DSI_HSYNC_POLARITY			0x214
+#define NWL_DSI_HSYNC_POLARITY_ACTIVE_LOW	0
+#define NWL_DSI_HSYNC_POLARITY_ACTIVE_HIGH	BIT(1)
+
+#define NWL_DSI_VIDEO_MODE			0x218
+#define NWL_DSI_HFP				0x21c
+#define NWL_DSI_HBP				0x220
+#define NWL_DSI_HSA				0x224
+#define NWL_DSI_ENABLE_MULT_PKTS		0x228
+#define NWL_DSI_VBP				0x22c
+#define NWL_DSI_VFP				0x230
+#define NWL_DSI_BLLP_MODE			0x234
+#define NWL_DSI_USE_NULL_PKT_BLLP		0x238
+#define NWL_DSI_VACTIVE				0x23c
+#define NWL_DSI_VC				0x240
+
+/* DSI APB PKT control */
+#define NWL_DSI_TX_PAYLOAD			0x280
+#define NWL_DSI_PKT_CONTROL			0x284
+#define NWL_DSI_SEND_PACKET			0x288
+#define NWL_DSI_PKT_STATUS			0x28c
+#define NWL_DSI_PKT_FIFO_WR_LEVEL		0x290
+#define NWL_DSI_PKT_FIFO_RD_LEVEL		0x294
+#define NWL_DSI_RX_PAYLOAD			0x298
+#define NWL_DSI_RX_PKT_HEADER			0x29c
+
+/* DSI IRQ handling */
+#define NWL_DSI_IRQ_STATUS			0x2a0
+#define NWL_DSI_SM_NOT_IDLE			BIT(0)
+#define NWL_DSI_TX_PKT_DONE			BIT(1)
+#define NWL_DSI_DPHY_DIRECTION			BIT(2)
+#define NWL_DSI_TX_FIFO_OVFLW			BIT(3)
+#define NWL_DSI_TX_FIFO_UDFLW			BIT(4)
+#define NWL_DSI_RX_FIFO_OVFLW			BIT(5)
+#define NWL_DSI_RX_FIFO_UDFLW			BIT(6)
+#define NWL_DSI_RX_PKT_HDR_RCVD			BIT(7)
+#define NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD	BIT(8)
+#define NWL_DSI_BTA_TIMEOUT			BIT(29)
+#define NWL_DSI_LP_RX_TIMEOUT			BIT(30)
+#define NWL_DSI_HS_TX_TIMEOUT			BIT(31)
+
+#define NWL_DSI_IRQ_STATUS2			0x2a4
+#define NWL_DSI_SINGLE_BIT_ECC_ERR		BIT(0)
+#define NWL_DSI_MULTI_BIT_ECC_ERR		BIT(1)
+#define NWL_DSI_CRC_ERR				BIT(2)
+
+#define NWL_DSI_IRQ_MASK			0x2a8
+#define NWL_DSI_SM_NOT_IDLE_MASK		BIT(0)
+#define NWL_DSI_TX_PKT_DONE_MASK		BIT(1)
+#define NWL_DSI_DPHY_DIRECTION_MASK		BIT(2)
+#define NWL_DSI_TX_FIFO_OVFLW_MASK		BIT(3)
+#define NWL_DSI_TX_FIFO_UDFLW_MASK		BIT(4)
+#define NWL_DSI_RX_FIFO_OVFLW_MASK		BIT(5)
+#define NWL_DSI_RX_FIFO_UDFLW_MASK		BIT(6)
+#define NWL_DSI_RX_PKT_HDR_RCVD_MASK		BIT(7)
+#define NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD_MASK	BIT(8)
+#define NWL_DSI_BTA_TIMEOUT_MASK		BIT(29)
+#define NWL_DSI_LP_RX_TIMEOUT_MASK		BIT(30)
+#define NWL_DSI_HS_TX_TIMEOUT_MASK		BIT(31)
+
+#define NWL_DSI_IRQ_MASK2			0x2ac
+#define NWL_DSI_SINGLE_BIT_ECC_ERR_MASK		BIT(0)
+#define NWL_DSI_MULTI_BIT_ECC_ERR_MASK		BIT(1)
+#define NWL_DSI_CRC_ERR_MASK			BIT(2)
+
+extern const struct mipi_dsi_host_ops nwl_dsi_host_ops;
+
+irqreturn_t nwl_dsi_irq_handler(int irq, void *data);
+int nwl_dsi_enable(struct nwl_dsi *dsi);
+int nwl_dsi_disable(struct nwl_dsi *dsi);
+
+#endif /* __NWL_DSI_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -54,13 +54,13 @@
 	int ret;
 
 	ret = i2c_master_send(ptn_bridge->client, &addr, 1);
-	if (ret <= 0) {
+	if (ret < 0) {
 		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
 		return ret;
 	}
 
 	ret = i2c_master_recv(ptn_bridge->client, buf, len);
-	if (ret <= 0) {
+	if (ret < 0) {
 		DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
 		return ret;
 	}
@@ -78,7 +78,7 @@
 	buf[1] = val;
 
 	ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
-	if (ret <= 0) {
+	if (ret < 0) {
 		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
 		return ret;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/nxp-seiko-43wvfig.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/nxp-seiko-43wvfig.c
@@ -0,0 +1,245 @@
+/*
+ * DRM driver for the legacy Freescale adapter card holding
+ * Seiko RA169Z20 43WVFIG LCD panel
+ *
+ * Copyright (C) 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+
+struct seiko_adapter {
+	struct device		*dev;
+	struct drm_panel	*panel;
+	struct drm_bridge	bridge;
+	struct drm_connector	connector;
+
+	u32			bpc;
+	u32			bus_format;
+};
+
+static enum drm_connector_status seiko_adapter_connector_detect(
+	struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static int seiko_adapter_connector_get_modes(struct drm_connector *connector)
+{
+	int num_modes;
+
+	struct seiko_adapter *adap = container_of(connector,
+						struct seiko_adapter,
+						connector);
+
+	num_modes = drm_panel_get_modes(adap->panel);
+
+	/*
+	 * The panel will populate the connector display_info properties with
+	 * fixed numbers, but we need to change them according to our
+	 * configuration.
+	 */
+	connector->display_info.bpc = adap->bpc;
+	drm_display_info_set_bus_formats(&connector->display_info,
+						 &adap->bus_format, 1);
+
+	return num_modes;
+}
+
+static const struct drm_connector_funcs seiko_adapter_connector_funcs = {
+	.detect = seiko_adapter_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs
+	seiko_adapter_connector_helper_funcs = {
+	.get_modes = seiko_adapter_connector_get_modes,
+};
+
+static int seiko_adapter_bridge_attach(struct drm_bridge *bridge)
+{
+	struct seiko_adapter *adap = bridge->driver_private;
+	struct device *dev = adap->dev;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_device *drm;
+	int ret = 0;
+
+	if (!encoder) {
+		DRM_DEV_ERROR(dev, "Parent encoder object not found\n");
+		return -ENODEV;
+	}
+
+	drm = encoder->dev;
+
+	/*
+	 * Create the connector for our panel
+	 */
+
+	ret = drm_connector_init(drm, &adap->connector,
+				 &seiko_adapter_connector_funcs,
+				 DRM_MODE_CONNECTOR_DPI);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to init drm connector: %d\n", ret);
+		return ret;
+	}
+
+	drm_connector_helper_add(&adap->connector,
+				 &seiko_adapter_connector_helper_funcs);
+
+	adap->connector.dpms = DRM_MODE_DPMS_OFF;
+	drm_connector_attach_encoder(&adap->connector, encoder);
+
+	ret = drm_panel_attach(adap->panel, &adap->connector);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to attach panel: %d\n", ret);
+		drm_connector_cleanup(&adap->connector);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void seiko_adapter_bridge_detach(struct drm_bridge *bridge)
+{
+	struct seiko_adapter *adap = bridge->driver_private;
+
+	drm_panel_detach(adap->panel);
+	drm_connector_cleanup(&adap->connector);
+}
+
+static void seiko_adapter_bridge_enable(struct drm_bridge *bridge)
+{
+	struct seiko_adapter *adap = bridge->driver_private;
+	struct device *dev = adap->dev;
+
+	if (drm_panel_prepare(adap->panel)) {
+		DRM_DEV_ERROR(dev, "Failed to prepare panel\n");
+		return;
+	}
+
+	if (drm_panel_enable(adap->panel)) {
+		DRM_DEV_ERROR(dev, "Failed to enable panel\n");
+		drm_panel_unprepare(adap->panel);
+	}
+}
+
+static void seiko_adapter_bridge_disable(struct drm_bridge *bridge)
+{
+	struct seiko_adapter *adap = bridge->driver_private;
+	struct device *dev = adap->dev;
+
+	if (drm_panel_disable(adap->panel)) {
+		DRM_DEV_ERROR(dev, "failed to disable panel\n");
+		return;
+	}
+
+	if (drm_panel_unprepare(adap->panel))
+		DRM_DEV_ERROR(dev, "failed to unprepare panel\n");
+}
+
+static const struct drm_bridge_funcs seiko_adapter_bridge_funcs = {
+	.enable = seiko_adapter_bridge_enable,
+	.disable = seiko_adapter_bridge_disable,
+	.attach = seiko_adapter_bridge_attach,
+	.detach = seiko_adapter_bridge_detach,
+};
+
+static int seiko_adapter_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct seiko_adapter *adap;
+	struct device_node *remote;
+	u32 bus_mode;
+	int port;
+
+	adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
+	if (!adap)
+		return -ENOMEM;
+
+	of_property_read_u32(dev->of_node, "bus_mode", &bus_mode);
+	if (bus_mode != 18 && bus_mode != 24) {
+		dev_err(dev, "Invalid bus_mode: %d\n", bus_mode);
+		return -EINVAL;
+	}
+
+	switch (bus_mode) {
+	case 18:
+		adap->bpc = 6;
+		adap->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+		break;
+	case 24:
+		adap->bpc = 8;
+		adap->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	}
+
+	for (port = 0; port < 2; port++) {
+		remote = of_graph_get_remote_node(dev->of_node, port, -1);
+		if (!remote) {
+			dev_err(dev, "No remote for port %d\n", port);
+			return -ENODEV;
+		}
+		adap->panel = of_drm_find_panel(remote);
+		if (!IS_ERR(adap->panel))
+			break;
+	}
+	if (IS_ERR(adap->panel)) {
+		dev_err(dev, "No panel found: %ld\n", PTR_ERR(adap->panel));
+		return PTR_ERR(adap->panel);
+	}
+
+	adap->dev = dev;
+	adap->bridge.driver_private = adap;
+	adap->bridge.funcs = &seiko_adapter_bridge_funcs;
+	adap->bridge.of_node = dev->of_node;
+
+	drm_bridge_add(&adap->bridge);
+
+	return 0;
+}
+
+static int seiko_adapter_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id seiko_adapter_dt_ids[] = {
+	{ .compatible = "nxp,seiko-43wvfig" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, seiko_adapter_dt_ids);
+
+static struct platform_driver seiko_adapter_driver = {
+	.probe		= seiko_adapter_probe,
+	.remove		= seiko_adapter_remove,
+	.driver		= {
+		.of_match_table = seiko_adapter_dt_ids,
+		.name	= "nxp-seiko-adapter",
+	},
+};
+
+module_platform_driver(seiko_adapter_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Seiko 43WVFIG adapter card driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/panel.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/panel.c
@@ -87,8 +87,17 @@
 static void panel_bridge_detach(struct drm_bridge *bridge)
 {
 	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+	struct drm_connector *connector = &panel_bridge->connector;
 
-	drm_panel_detach(panel_bridge->panel);
+	/*
+	 * Cleanup the connector if we know it was initialized.
+	 *
+	 * FIXME: This wouldn't be needed if the panel_bridge structure was
+	 * allocated with drmm_kzalloc(). This might be tricky since the
+	 * drm_device pointer can only be retrieved when the bridge is attached.
+	 */
+	if (connector->dev)
+		drm_connector_cleanup(connector);
 }
 
 static void panel_bridge_pre_enable(struct drm_bridge *bridge)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/sec-dsim.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/sec-dsim.c
@@ -0,0 +1,2013 @@
+/*
+ * Samsung MIPI DSIM Bridge
+ *
+ * Copyright 2018-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <asm/unaligned.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <drm/bridge/sec_mipi_dsim.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <video/videomode.h>
+#include <video/mipi_display.h>
+
+/* dsim registers */
+#define DSIM_VERSION			0x00
+#define DSIM_STATUS			0x04
+#define DSIM_RGB_STATUS			0x08
+#define DSIM_SWRST			0x0c
+#define DSIM_CLKCTRL			0x10
+#define DSIM_TIMEOUT			0x14
+#define DSIM_CONFIG			0x18
+#define DSIM_ESCMODE			0x1c
+#define DSIM_MDRESOL			0x20
+#define DSIM_MVPORCH			0x24
+#define DSIM_MHPORCH			0x28
+#define DSIM_MSYNC			0x2c
+#define DSIM_SDRESOL			0x30
+#define DSIM_INTSRC			0x34
+#define DSIM_INTMSK			0x38
+
+/* packet */
+#define DSIM_PKTHDR			0x3c
+#define DSIM_PAYLOAD			0x40
+#define DSIM_RXFIFO			0x44
+#define DSIM_FIFOTHLD			0x48
+#define DSIM_FIFOCTRL			0x4c
+#define DSIM_MEMACCHR			0x50
+#define DSIM_MULTI_PKT			0x78
+
+/* pll control */
+#define DSIM_PLLCTRL_1G			0x90
+#define DSIM_PLLCTRL			0x94
+#define DSIM_PLLCTRL1			0x98
+#define DSIM_PLLCTRL2			0x9c
+#define DSIM_PLLTMR			0xa0
+
+/* dphy */
+#define DSIM_PHYTIMING			0xb4
+#define DSIM_PHYTIMING1			0xb8
+#define DSIM_PHYTIMING2			0xbc
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/* register bit fields */
+#define STATUS_PLLSTABLE		BIT(31)
+#define STATUS_SWRSTRLS			BIT(20)
+#define STATUS_TXREADYHSCLK		BIT(10)
+#define STATUS_ULPSCLK			BIT(9)
+#define STATUS_STOPSTATECLK		BIT(8)
+#define STATUS_GET_ULPSDAT(x)		REG_GET(x,  7,  4)
+#define STATUS_GET_STOPSTATEDAT(x)	REG_GET(x,  3,  0)
+
+#define RGB_STATUS_CMDMODE_INSEL	BIT(31)
+#define RGB_STATUS_GET_RGBSTATE(x)	REG_GET(x, 12,  0)
+
+#define CLKCTRL_TXREQUESTHSCLK		BIT(31)
+#define CLKCTRL_DPHY_SEL_1G		BIT(29)
+#define CLKCTRL_DPHY_SEL_1P5G		(0x0 << 29)
+#define CLKCTRL_ESCCLKEN		BIT(28)
+#define CLKCTRL_PLLBYPASS		BIT(29)
+#define CLKCTRL_BYTECLKSRC_DPHY_PLL	REG_PUT(0, 26, 25)
+#define CLKCTRL_BYTECLKEN		BIT(24)
+#define CLKCTRL_SET_LANEESCCLKEN(x)	REG_PUT(x, 23, 19)
+#define CLKCTRL_SET_ESCPRESCALER(x)	REG_PUT(x, 15,  0)
+
+#define TIMEOUT_SET_BTAOUT(x)		REG_PUT(x, 23, 16)
+#define TIMEOUT_SET_LPDRTOUT(x)		REG_PUT(x, 15,  0)
+
+#define CONFIG_NON_CONTINUOUS_CLOCK_LANE	BIT(31)
+#define CONFIG_CLKLANE_STOP_START	BIT(30)
+#define CONFIG_MFLUSH_VS		BIT(29)
+#define CONFIG_EOT_R03			BIT(28)
+#define CONFIG_SYNCINFORM		BIT(27)
+#define CONFIG_BURSTMODE		BIT(26)
+#define CONFIG_VIDEOMODE		BIT(25)
+#define CONFIG_AUTOMODE			BIT(24)
+#define CONFIG_HSEDISABLEMODE		BIT(23)
+#define CONFIG_HFPDISABLEMODE		BIT(22)
+#define CONFIG_HBPDISABLEMODE		BIT(21)
+#define CONFIG_HSADISABLEMODE		BIT(20)
+#define CONFIG_SET_MAINVC(x)		REG_PUT(x, 19, 18)
+#define CONFIG_SET_SUBVC(x)		REG_PUT(x, 17, 16)
+#define CONFIG_SET_MAINPIXFORMAT(x)	REG_PUT(x, 14, 12)
+#define CONFIG_SET_SUBPIXFORMAT(x)	REG_PUT(x, 10,  8)
+#define CONFIG_SET_NUMOFDATLANE(x)	REG_PUT(x,  6,  5)
+#define CONFIG_SET_LANEEN(x)		REG_PUT(x,  4,  0)
+
+#define ESCMODE_SET_STOPSTATE_CNT(X)	REG_PUT(x, 31, 21)
+#define ESCMODE_FORCESTOPSTATE		BIT(20)
+#define ESCMODE_FORCEBTA		BIT(16)
+#define ESCMODE_CMDLPDT			BIT(7)
+#define ESCMODE_TXLPDT			BIT(6)
+#define ESCMODE_TXTRIGGERRST		BIT(5)
+
+#define MDRESOL_MAINSTANDBY		BIT(31)
+#define MDRESOL_SET_MAINVRESOL(x)	REG_PUT(x, 27, 16)
+#define MDRESOL_SET_MAINHRESOL(x)	REG_PUT(x, 11,  0)
+
+#define MVPORCH_SET_CMDALLOW(x)		REG_PUT(x, 31, 28)
+#define MVPORCH_SET_STABLEVFP(x)	REG_PUT(x, 26, 16)
+#define MVPORCH_SET_MAINVBP(x)		REG_PUT(x, 10,  0)
+
+#define MHPORCH_SET_MAINHFP(x)		REG_PUT(x, 31, 16)
+#define MHPORCH_SET_MAINHBP(x)		REG_PUT(x, 15,  0)
+
+#define MSYNC_SET_MAINVSA(x)		REG_PUT(x, 31, 22)
+#define MSYNC_SET_MAINHSA(x)		REG_PUT(x, 15,  0)
+
+#define INTSRC_PLLSTABLE		BIT(31)
+#define INTSRC_SWRSTRELEASE		BIT(30)
+#define INTSRC_SFRPLFIFOEMPTY		BIT(29)
+#define INTSRC_SFRPHFIFOEMPTY		BIT(28)
+#define INTSRC_FRAMEDONE		BIT(24)
+#define INTSRC_LPDRTOUT			BIT(21)
+#define INTSRC_TATOUT			BIT(20)
+#define INTSRC_RXDATDONE		BIT(18)
+#define INTSRC_RXTE			BIT(17)
+#define INTSRC_RXACK			BIT(16)
+#define INTSRC_MASK			(INTSRC_PLLSTABLE	|	\
+					 INTSRC_SWRSTRELEASE	|	\
+					 INTSRC_SFRPLFIFOEMPTY	|	\
+					 INTSRC_SFRPHFIFOEMPTY	|	\
+					 INTSRC_FRAMEDONE	|	\
+					 INTSRC_LPDRTOUT	|	\
+					 INTSRC_TATOUT		|	\
+					 INTSRC_RXDATDONE	|	\
+					 INTSRC_RXTE		|	\
+					 INTSRC_RXACK)
+
+#define INTMSK_MSKPLLSTABLE		BIT(31)
+#define INTMSK_MSKSWRELEASE		BIT(30)
+#define INTMSK_MSKSFRPLFIFOEMPTY	BIT(29)
+#define INTMSK_MSKSFRPHFIFOEMPTY	BIT(28)
+#define INTMSK_MSKFRAMEDONE		BIT(24)
+#define INTMSK_MSKLPDRTOUT		BIT(21)
+#define INTMSK_MSKTATOUT		BIT(20)
+#define INTMSK_MSKRXDATDONE		BIT(18)
+#define INTMSK_MSKRXTE			BIT(17)
+#define INTMSK_MSKRXACK			BIT(16)
+
+#define PKTHDR_SET_DATA1(x)		REG_PUT(x, 23, 16)
+#define PKTHDR_GET_DATA1(x)		REG_GET(x, 23, 16)
+#define PKTHDR_SET_DATA0(x)		REG_PUT(x, 15,  8)
+#define PKTHDR_GET_DATA0(x)		REG_GET(x, 15,  8)
+#define PKTHDR_GET_WC(x)		REG_GET(x, 23,  8)
+#define PKTHDR_SET_DI(x)		REG_PUT(x,  7,  0)
+#define PKTHDR_GET_DI(x)		REG_GET(x,  7,  0)
+#define PKTHDR_SET_DT(x)		REG_PUT(x,  5,  0)
+#define PKTHDR_GET_DT(x)		REG_GET(x,  5,  0)
+#define PKTHDR_SET_VC(x)		REG_PUT(x,  7,  6)
+#define PKTHDR_GET_VC(x)		REG_GET(x,  7,  6)
+
+#define FIFOCTRL_FULLRX			BIT(25)
+#define FIFOCTRL_EMPTYRX		BIT(24)
+#define FIFOCTRL_FULLHSFR		BIT(23)
+#define FIFOCTRL_EMPTYHSFR		BIT(22)
+#define FIFOCTRL_FULLLSFR		BIT(21)
+#define FIFOCTRL_EMPTYLSFR		BIT(20)
+#define FIFOCTRL_FULLHMAIN		BIT(11)
+#define FIFOCTRL_EMPTYHMAIN		BIT(10)
+#define FIFOCTRL_FULLLMAIN		BIT(9)
+#define FIFOCTRL_EMPTYLMAIN		BIT(8)
+#define FIFOCTRL_NINITRX		BIT(4)
+#define FIFOCTRL_NINITSFR		BIT(3)
+#define FIFOCTRL_NINITI80		BIT(2)
+#define FIFOCTRL_NINITSUB		BIT(1)
+#define FIFOCTRL_NINITMAIN		BIT(0)
+
+#define PLLCTRL_DPDNSWAP_CLK		BIT(25)
+#define PLLCTRL_DPDNSWAP_DAT		BIT(24)
+#define PLLCTRL_PLLEN			BIT(23)
+#define PLLCTRL_SET_PMS(x)		REG_PUT(x, 19,  1)
+   #define PLLCTRL_SET_P(x)		REG_PUT(x, 18, 13)
+   #define PLLCTRL_SET_M(x)		REG_PUT(x, 12,  3)
+   #define PLLCTRL_SET_S(x)		REG_PUT(x,  2,  0)
+
+#define PHYTIMING_SET_M_TLPXCTL(x)	REG_PUT(x, 15,  8)
+#define PHYTIMING_SET_M_THSEXITCTL(x)	REG_PUT(x,  7,  0)
+
+#define PHYTIMING1_SET_M_TCLKPRPRCTL(x)	 REG_PUT(x, 31, 24)
+#define PHYTIMING1_SET_M_TCLKZEROCTL(x)	 REG_PUT(x, 23, 16)
+#define PHYTIMING1_SET_M_TCLKPOSTCTL(x)	 REG_PUT(x, 15,  8)
+#define PHYTIMING1_SET_M_TCLKTRAILCTL(x) REG_PUT(x,  7,  0)
+
+#define PHYTIMING2_SET_M_THSPRPRCTL(x)	REG_PUT(x, 23, 16)
+#define PHYTIMING2_SET_M_THSZEROCTL(x)	REG_PUT(x, 15,  8)
+#define PHYTIMING2_SET_M_THSTRAILCTL(x)	REG_PUT(x,  7,  0)
+
+#define dsim_read(dsim, reg)		readl(dsim->base + reg)
+#define dsim_write(dsim, val, reg)	writel(val, dsim->base + reg)
+
+/* fixed phy ref clk rate */
+#define PHY_REF_CLK		12000
+
+#define MAX_MAIN_HRESOL		2047
+#define MAX_MAIN_VRESOL		2047
+#define MAX_SUB_HRESOL		1024
+#define MAX_SUB_VRESOL		1024
+
+/* in KHZ */
+#define MAX_ESC_CLK_FREQ	20000
+
+/* dsim all irqs index */
+#define PLLSTABLE		1
+#define SWRSTRELEASE		2
+#define SFRPLFIFOEMPTY		3
+#define SFRPHFIFOEMPTY		4
+#define SYNCOVERRIDE		5
+#define BUSTURNOVER		6
+#define FRAMEDONE		7
+#define LPDRTOUT		8
+#define TATOUT			9
+#define RXDATDONE		10
+#define RXTE			11
+#define RXACK			12
+#define ERRRXECC		13
+#define ERRRXCRC		14
+#define ERRESC3			15
+#define ERRESC2			16
+#define ERRESC1			17
+#define ERRESC0			18
+#define ERRSYNC3		19
+#define ERRSYNC2		20
+#define ERRSYNC1		21
+#define ERRSYNC0		22
+#define ERRCONTROL3		23
+#define ERRCONTROL2		24
+#define ERRCONTROL1		25
+#define ERRCONTROL0		26
+
+#define MIPI_FIFO_TIMEOUT	msecs_to_jiffies(250)
+
+#define MIPI_HFP_PKT_OVERHEAD	6
+#define MIPI_HBP_PKT_OVERHEAD	6
+#define MIPI_HSA_PKT_OVERHEAD	6
+
+#define to_sec_mipi_dsim(dsi) container_of(dsi, struct sec_mipi_dsim, dsi_host)
+#define conn_to_sec_mipi_dsim(conn)		\
+	container_of(conn, struct sec_mipi_dsim, connector)
+
+/* used for CEA standard modes */
+struct dsim_hblank_par {
+	char *name;		/* drm display mode name */
+	int vrefresh;
+	int hfp_wc;
+	int hbp_wc;
+	int hsa_wc;
+	int lanes;
+};
+
+struct dsim_pll_pms {
+	uint32_t bit_clk;	/* kHz */
+	uint32_t p;
+	uint32_t m;
+	uint32_t s;
+	uint32_t k;
+};
+
+struct sec_mipi_dsim {
+	struct mipi_dsi_host dsi_host;
+	struct drm_connector connector;
+	struct drm_encoder *encoder;
+	struct drm_bridge *bridge;
+	struct drm_bridge *next;
+	struct drm_panel *panel;
+	struct device *dev;
+
+	void __iomem *base;
+	int irq;
+
+	struct clk *clk_cfg;
+	struct clk *clk_pllref;
+	struct clk *pclk;			/* pixel clock */
+
+	/* kHz clocks */
+	uint32_t pix_clk;
+	uint32_t bit_clk;
+	uint32_t pref_clk;			/* phy ref clock rate in KHz */
+
+	unsigned int lanes;
+	unsigned int channel;			/* virtual channel */
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+	const struct dsim_hblank_par *hpar;
+	unsigned int pms;
+	unsigned int p;
+	unsigned int m;
+	unsigned int s;
+	unsigned long long lp_data_rate;
+	unsigned long long hs_data_rate;
+	struct videomode vmode;
+
+	struct completion pll_stable;
+	struct completion ph_tx_done;
+	struct completion pl_tx_done;
+	struct completion rx_done;
+	const struct sec_mipi_dsim_plat_data *pdata;
+};
+
+#define DSIM_HBLANK_PARAM(nm, vf, hfp, hbp, hsa, num)	\
+	.name	  = (nm),				\
+	.vrefresh = (vf),				\
+	.hfp_wc   = (hfp),				\
+	.hbp_wc   = (hbp),				\
+	.hsa_wc   = (hsa),				\
+	.lanes	  = (num)
+
+#define DSIM_PLL_PMS(c, pp, mm, ss)			\
+	.bit_clk = (c),					\
+	.p = (pp),					\
+	.m = (mm),					\
+	.s = (ss)
+
+static const struct dsim_hblank_par hblank_4lanes[] = {
+	/* {  88, 148, 44 } */
+	{ DSIM_HBLANK_PARAM("1920x1080", 60,  60, 105,  27, 4), },
+	/* { 528, 148, 44 } */
+	{ DSIM_HBLANK_PARAM("1920x1080", 50, 390, 105,  27, 4), },
+	/* {  88, 148, 44 } */
+	{ DSIM_HBLANK_PARAM("1920x1080", 30,  60, 105,  27, 4), },
+	/* { 110, 220, 40 } */
+	{ DSIM_HBLANK_PARAM("1280x720" , 60,  78, 159,  24, 4), },
+	/* { 440, 220, 40 } */
+	{ DSIM_HBLANK_PARAM("1280x720" , 50, 324, 159,  24, 4), },
+	/* {  16,  60, 62 } */
+	{ DSIM_HBLANK_PARAM("720x480"  , 60,   6,  39,  40, 4), },
+	/* {  12,  68, 64 } */
+	{ DSIM_HBLANK_PARAM("720x576"  , 50,   3,  45,  42, 4), },
+	/* {  16,  48, 96 } */
+	{ DSIM_HBLANK_PARAM("640x480"  , 60,   6,  30,  66, 4), },
+};
+
+static const struct dsim_hblank_par hblank_2lanes[] = {
+	/* {  88, 148, 44 } */
+	{ DSIM_HBLANK_PARAM("1920x1080", 30, 114, 210,  60, 2), },
+	/* { 110, 220, 40 } */
+	{ DSIM_HBLANK_PARAM("1280x720" , 60, 159, 320,  40, 2), },
+	/* { 440, 220, 40 } */
+	{ DSIM_HBLANK_PARAM("1280x720" , 50, 654, 320,  40, 2), },
+	/* {  16,  60, 62 } */
+	{ DSIM_HBLANK_PARAM("720x480"  , 60,  16,  66,  88, 2), },
+	/* {  12,  68, 64 } */
+	{ DSIM_HBLANK_PARAM("720x576"  , 50,  12,  96,  72, 2), },
+	/* {  16,  48, 96 } */
+	{ DSIM_HBLANK_PARAM("640x480"  , 60,  18,  66, 138, 2), },
+};
+
+static const struct dsim_hblank_par *sec_mipi_dsim_get_hblank_par(const char *name,
+								  int vrefresh,
+								  int lanes)
+{
+	int i, size;
+	const struct dsim_hblank_par *hpar, *hblank;
+
+	if (unlikely(!name))
+		return NULL;
+
+	switch (lanes) {
+	case 2:
+		hblank = hblank_2lanes;
+		size   = ARRAY_SIZE(hblank_2lanes);
+		break;
+	case 4:
+		hblank = hblank_4lanes;
+		size   = ARRAY_SIZE(hblank_4lanes);
+		break;
+	default:
+		pr_err("No hblank data for mode %s with %d lanes\n",
+		       name, lanes);
+		return NULL;
+	}
+
+	for (i = 0; i < size; i++) {
+		hpar = &hblank[i];
+
+		if (!strcmp(name, hpar->name)) {
+			if (vrefresh != hpar->vrefresh)
+				continue;
+
+			/* found */
+			return hpar;
+		}
+	}
+
+	return NULL;
+}
+
+static int sec_mipi_dsim_set_pref_rate(struct sec_mipi_dsim *dsim)
+{
+	int ret;
+	uint32_t rate;
+	struct device *dev = dsim->dev;
+	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+	const struct sec_mipi_dsim_pll *dpll = pdata->dphy_pll;
+	const struct sec_mipi_dsim_range *fin_range = &dpll->fin;
+
+	ret = of_property_read_u32(dev->of_node, "pref-rate", &rate);
+	if (ret < 0) {
+		dev_dbg(dev, "no valid rate assigned for pref clock\n");
+		dsim->pref_clk = PHY_REF_CLK;
+	} else {
+		if (unlikely(rate < fin_range->min || rate > fin_range->max)) {
+			dev_warn(dev, "pref-rate get is invalid: %uKHz\n",
+				 rate);
+			dsim->pref_clk = PHY_REF_CLK;
+		} else
+			dsim->pref_clk = rate;
+	}
+
+set_rate:
+	ret = clk_set_rate(dsim->clk_pllref,
+			   ((unsigned long)dsim->pref_clk) * 1000);
+	if (ret) {
+		dev_err(dev, "failed to set pll ref clock rate\n");
+		return ret;
+	}
+
+	rate = clk_get_rate(dsim->clk_pllref) / 1000;
+	if (unlikely(!rate)) {
+		dev_err(dev, "failed to get pll ref clock rate\n");
+		return -EINVAL;
+	}
+
+	if (rate != dsim->pref_clk) {
+		if (unlikely(dsim->pref_clk == PHY_REF_CLK)) {
+			/* set default rate failed */
+			dev_err(dev, "no valid pll ref clock rate\n");
+			return -EINVAL;
+		}
+
+		dev_warn(dev, "invalid assigned rate for pref: %uKHz\n",
+			 dsim->pref_clk);
+		dev_warn(dev, "use default pref rate instead: %uKHz\n",
+			 PHY_REF_CLK);
+
+		dsim->pref_clk = PHY_REF_CLK;
+		goto set_rate;
+	}
+
+	return 0;
+}
+
+static void sec_mipi_dsim_irq_init(struct sec_mipi_dsim *dsim);
+
+/* For now, dsim only support one device attached */
+static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
+				     struct mipi_dsi_device *dsi)
+{
+	struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+	struct device *dev = dsim->dev;
+	struct drm_panel *panel;
+
+	if (!dsi->lanes || dsi->lanes > pdata->max_data_lanes) {
+		dev_err(dev, "invalid data lanes number\n");
+		return -EINVAL;
+	}
+
+	if (dsim->channel)
+		return -EINVAL;
+
+	if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)		||
+	    !((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)	||
+	      (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))) {
+		dev_err(dev, "unsupported dsi mode\n");
+		return -EINVAL;
+	}
+
+	if (dsi->format != MIPI_DSI_FMT_RGB888 &&
+	    dsi->format != MIPI_DSI_FMT_RGB565 &&
+	    dsi->format != MIPI_DSI_FMT_RGB666 &&
+	    dsi->format != MIPI_DSI_FMT_RGB666_PACKED) {
+		dev_err(dev, "unsupported pixel format: %#x\n", dsi->format);
+		return -EINVAL;
+	}
+
+	if (!dsim->next) {
+		/* 'dsi' must be panel device */
+		panel = of_drm_find_panel(dsi->dev.of_node);
+
+		if (!panel) {
+			dev_err(dev, "refuse unknown dsi device attach\n");
+			WARN_ON(!panel);
+			return -ENODEV;
+		}
+
+		/* Don't support multiple panels */
+		if (dsim->panel && panel && dsim->panel != panel) {
+			dev_err(dev, "don't support multiple panels\n");
+			return -EBUSY;
+		}
+
+		dsim->panel = panel;
+	}
+
+	/* TODO: DSIM 3 lanes has some display issue, so
+	 * avoid 3 lanes enable, and force data lanes to
+	 * be 2.
+	 */
+	if (dsi->lanes == 3)
+		dsi->lanes = 2;
+
+	dsim->lanes	 = dsi->lanes;
+	dsim->channel	 = dsi->channel;
+	dsim->format	 = dsi->format;
+	dsim->mode_flags = dsi->mode_flags;
+
+	/* TODO: support later */
+#if 0
+	if (dsim->connector.dev)
+		drm_helper_hpd_irq_event(dsim->connector.dev);
+#endif
+
+	return 0;
+}
+
+static int sec_mipi_dsim_host_detach(struct mipi_dsi_host *host,
+				     struct mipi_dsi_device *dsi)
+{
+	struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+
+	if (WARN_ON(!dsim->next && !dsim->panel))
+		return -ENODEV;
+
+	/* clear the saved dsi parameters */
+	dsim->lanes	 = 0;
+	dsim->channel	 = 0;
+	dsim->format	 = 0;
+	dsim->mode_flags = 0;
+
+	/* detached panel should be NULL */
+	dsim->panel = NULL;
+
+	return 0;
+}
+
+static void sec_mipi_dsim_config_cmd_lpm(struct sec_mipi_dsim *dsim,
+					 bool enable)
+{
+	uint32_t escmode;
+
+	escmode = dsim_read(dsim, DSIM_ESCMODE);
+
+	if (enable)
+		escmode |= ESCMODE_CMDLPDT;
+	else
+		escmode &= ~ESCMODE_CMDLPDT;
+
+	dsim_write(dsim, escmode, DSIM_ESCMODE);
+}
+
+static void sec_mipi_dsim_write_pl_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+					       const void *payload,
+					       size_t length)
+{
+	uint32_t pl_data;
+
+	if (!length)
+		return;
+
+	while (length >= 4) {
+		pl_data = get_unaligned_le32(payload);
+		dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+		payload += 4;
+		length -= 4;
+	}
+
+	pl_data = 0;
+	switch (length) {
+	case 3:
+		pl_data |= ((u8 *)payload)[2] << 16;
+		/* fall through */
+	case 2:
+		pl_data |= ((u8 *)payload)[1] << 8;
+		/* fall through */
+	case 1:
+		pl_data |= ((u8 *)payload)[0];
+		dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+		break;
+	}
+}
+
+static void sec_mipi_dsim_write_ph_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+					       void *header,
+					       bool use_lpm)
+{
+	uint32_t pkthdr;
+
+	pkthdr = PKTHDR_SET_DATA1(((u8 *)header)[2])	| /* WC MSB  */
+		 PKTHDR_SET_DATA0(((u8 *)header)[1])	| /* WC LSB  */
+		 PKTHDR_SET_DI(((u8 *)header)[0]);	  /* Data ID */
+
+	dsim_write(dsim, pkthdr, DSIM_PKTHDR);
+}
+
+static int sec_mipi_dsim_read_pl_from_sfr_fifo(struct sec_mipi_dsim *dsim,
+					       void *payload,
+					       size_t length)
+{
+	uint8_t data_type;
+	uint16_t word_count = 0;
+	uint32_t fifoctrl, ph, pl;
+
+	fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+	if (WARN_ON(fifoctrl & FIFOCTRL_EMPTYRX))
+		return -EINVAL;
+
+	ph = dsim_read(dsim, DSIM_RXFIFO);
+	data_type = PKTHDR_GET_DT(ph);
+	switch (data_type) {
+	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+		dev_err(dsim->dev, "peripheral report error: (0-7)%x, (8-15)%x\n",
+			PKTHDR_GET_DATA0(ph), PKTHDR_GET_DATA1(ph));
+		return -EPROTO;
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+		if (!WARN_ON(length < 2)) {
+			((u8 *)payload)[1] = PKTHDR_GET_DATA1(ph);
+			word_count++;
+		}
+		/* fall through */
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+		((u8 *)payload)[0] = PKTHDR_GET_DATA0(ph);
+		word_count++;
+		length = word_count;
+		break;
+	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+		word_count = PKTHDR_GET_WC(ph);
+		if (word_count > length) {
+			dev_err(dsim->dev, "invalid receive buffer length\n");
+			return -EINVAL;
+		}
+
+		length = word_count;
+
+		while (word_count >= 4) {
+			pl = dsim_read(dsim, DSIM_RXFIFO);
+			((u8 *)payload)[0] = pl & 0xff;
+			((u8 *)payload)[1] = (pl >> 8)  & 0xff;
+			((u8 *)payload)[2] = (pl >> 16) & 0xff;
+			((u8 *)payload)[3] = (pl >> 24) & 0xff;
+			payload += 4;
+			word_count -= 4;
+		}
+
+		if (word_count > 0) {
+			pl = dsim_read(dsim, DSIM_RXFIFO);
+
+			switch (word_count) {
+			case 3:
+				((u8 *)payload)[2] = (pl >> 16) & 0xff;
+				/* fall through */
+			case 2:
+				((u8 *)payload)[1] = (pl >> 8) & 0xff;
+				/* fall through */
+			case 1:
+				((u8 *)payload)[0] = pl & 0xff;
+				break;
+			}
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return length;
+}
+
+static ssize_t sec_mipi_dsim_host_transfer(struct mipi_dsi_host *host,
+					   const struct mipi_dsi_msg *msg)
+{
+	int ret;
+	bool use_lpm;
+	struct mipi_dsi_packet packet;
+	struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+
+	if ((msg->rx_buf && !msg->rx_len) || (msg->rx_len && !msg->rx_buf))
+		return -EINVAL;
+
+	ret = mipi_dsi_create_packet(&packet, msg);
+	if (ret) {
+		dev_err(dsim->dev, "failed to create dsi packet: %d\n", ret);
+		return ret;
+	}
+
+	/* need to read data from peripheral */
+	if (unlikely(msg->rx_buf))
+		reinit_completion(&dsim->rx_done);
+
+	/* config LPM for CMD TX */
+	use_lpm = msg->flags & MIPI_DSI_MSG_USE_LPM ? true : false;
+	sec_mipi_dsim_config_cmd_lpm(dsim, use_lpm);
+
+	if (packet.payload_length) {		/* Long Packet case */
+		reinit_completion(&dsim->pl_tx_done);
+
+		/* write packet payload */
+		sec_mipi_dsim_write_pl_to_sfr_fifo(dsim,
+						   packet.payload,
+						   packet.payload_length);
+
+		/* write packet header */
+		sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+						   packet.header,
+						   use_lpm);
+
+		ret = wait_for_completion_timeout(&dsim->ph_tx_done,
+						  MIPI_FIFO_TIMEOUT);
+		if (!ret) {
+			dev_err(dsim->dev, "wait payload tx done time out\n");
+			return -EBUSY;
+		}
+	} else {
+		reinit_completion(&dsim->ph_tx_done);
+
+		/* write packet header */
+		sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+						   packet.header,
+						   use_lpm);
+
+		ret = wait_for_completion_timeout(&dsim->ph_tx_done,
+						  MIPI_FIFO_TIMEOUT);
+		if (!ret) {
+			dev_err(dsim->dev, "wait pkthdr tx done time out\n");
+			return -EBUSY;
+		}
+	}
+
+	/* read packet payload */
+	if (unlikely(msg->rx_buf)) {
+		ret = wait_for_completion_timeout(&dsim->rx_done,
+						  MIPI_FIFO_TIMEOUT);
+		if (!ret) {
+			dev_err(dsim->dev, "wait rx done time out\n");
+			return -EBUSY;
+		}
+
+		ret = sec_mipi_dsim_read_pl_from_sfr_fifo(dsim,
+							  msg->rx_buf,
+							  msg->rx_len);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct mipi_dsi_host_ops sec_mipi_dsim_host_ops = {
+	.attach   = sec_mipi_dsim_host_attach,
+	.detach   = sec_mipi_dsim_host_detach,
+	.transfer = sec_mipi_dsim_host_transfer,
+};
+
+static int sec_mipi_dsim_bridge_attach(struct drm_bridge *bridge)
+{
+	int ret;
+	bool attach_bridge = false;
+	struct sec_mipi_dsim *dsim = bridge->driver_private;
+	struct device *dev = dsim->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *endpoint, *remote = NULL;
+	struct drm_bridge *next = ERR_PTR(-ENODEV);
+	struct drm_encoder *encoder = dsim->encoder;
+
+	/* TODO: All bridges and planes should have already been added */
+
+	/* A panel has been found, ignor other dsi devices */
+	if (dsim->panel)
+		return 0;
+
+	/* find next bridge */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	/* At least one endpoint should be existed */
+	if (!endpoint)
+		return -ENODEV;
+
+	while (endpoint) {
+		/* check the endpoint can attach bridge or not */
+		attach_bridge = of_property_read_bool(endpoint, "attach-bridge");
+		if (!attach_bridge) {
+			endpoint = of_graph_get_next_endpoint(np, endpoint);
+			continue;
+		}
+
+		remote = of_graph_get_remote_port_parent(endpoint);
+
+		if (!remote || !of_device_is_available(remote)) {
+			of_node_put(remote);
+			endpoint = of_graph_get_next_endpoint(np, endpoint);
+			continue;
+		}
+
+		next = of_drm_find_bridge(remote);
+		if (next) {
+			/* Found */
+			of_node_put(endpoint);
+			break;
+		}
+
+		endpoint = of_graph_get_next_endpoint(np, endpoint);
+	}
+
+	/* No workable bridge exists */
+	if (IS_ERR(next))
+		return PTR_ERR(next);
+
+	/* For the panel driver loading is after dsim bridge,
+	 * defer bridge binding to wait for panel driver ready.
+	 * The disadvantage of probe defer is endless probing
+	 * in some cases.
+	 */
+	if (!next)
+		return -EPROBE_DEFER;
+
+	/* duplicate bridges or next bridge exists */
+	WARN_ON(bridge == next || bridge->next || dsim->next);
+
+	dsim->next = next;
+	next->encoder = encoder;
+	ret = drm_bridge_attach(encoder, next, bridge);
+	if (ret) {
+		dev_err(dev, "Unable to attach bridge %s: %d\n",
+			remote->name, ret);
+		dsim->next = NULL;
+		return ret;
+	}
+
+	/* bridge chains */
+	bridge->next = next;
+
+	return 0;
+}
+
+static int sec_mipi_dsim_config_pll(struct sec_mipi_dsim *dsim)
+{
+	int ret;
+	uint32_t pllctrl = 0, status, data_lanes_en, stop;
+
+	dsim_write(dsim, 0x8000, DSIM_PLLTMR);
+
+	/* TODO: config dp/dn swap if requires */
+
+	pllctrl |= PLLCTRL_SET_PMS(dsim->pms) | PLLCTRL_PLLEN;
+	dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+
+	ret = wait_for_completion_timeout(&dsim->pll_stable, HZ / 10);
+	if (!ret) {
+		dev_err(dsim->dev, "wait for pll stable time out\n");
+		return -EBUSY;
+	}
+
+	/* wait for clk & data lanes to go to stop state */
+	mdelay(1);
+
+	data_lanes_en = (0x1 << dsim->lanes) - 1;
+	status = dsim_read(dsim, DSIM_STATUS);
+	if (!(status & STATUS_STOPSTATECLK)) {
+		dev_err(dsim->dev, "clock is not in stop state\n");
+		return -EBUSY;
+	}
+
+	stop = STATUS_GET_STOPSTATEDAT(status);
+	if ((stop & data_lanes_en) != data_lanes_en) {
+		dev_err(dsim->dev,
+			"one or more data lanes is not in stop state\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
+{
+	uint32_t bpp, hfp_wc, hbp_wc, hsa_wc, wc;
+	uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
+	struct videomode *vmode = &dsim->vmode;
+
+	mdresol |= MDRESOL_SET_MAINVRESOL(vmode->vactive) |
+		   MDRESOL_SET_MAINHRESOL(vmode->hactive);
+	dsim_write(dsim, mdresol, DSIM_MDRESOL);
+
+	mvporch |= MVPORCH_SET_MAINVBP(vmode->vback_porch)    |
+		   MVPORCH_SET_STABLEVFP(vmode->vfront_porch) |
+		   MVPORCH_SET_CMDALLOW(0x0);
+	dsim_write(dsim, mvporch, DSIM_MVPORCH);
+
+	bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
+
+	/* calculate hfp & hbp word counts */
+	if (!dsim->hpar) {
+		wc = DIV_ROUND_UP(vmode->hfront_porch * (bpp >> 3),
+				  dsim->lanes);
+		hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
+			 wc - MIPI_HFP_PKT_OVERHEAD : vmode->hfront_porch;
+		wc = DIV_ROUND_UP(vmode->hback_porch * (bpp >> 3),
+				  dsim->lanes);
+		hbp_wc = wc > MIPI_HBP_PKT_OVERHEAD ?
+			 wc - MIPI_HBP_PKT_OVERHEAD : vmode->hback_porch;
+	} else {
+		hfp_wc = dsim->hpar->hfp_wc;
+		hbp_wc = dsim->hpar->hbp_wc;
+	}
+
+	mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
+		   MHPORCH_SET_MAINHBP(hbp_wc);
+
+	dsim_write(dsim, mhporch, DSIM_MHPORCH);
+
+	/* calculate hsa word counts */
+	if (!dsim->hpar) {
+		wc = DIV_ROUND_UP(vmode->hsync_len * (bpp >> 3),
+				  dsim->lanes);
+		hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
+			 wc - MIPI_HSA_PKT_OVERHEAD : vmode->hsync_len;
+	} else
+		hsa_wc = dsim->hpar->hsa_wc;
+
+	msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
+		 MSYNC_SET_MAINHSA(hsa_wc);
+
+	dsim_write(dsim, msync, DSIM_MSYNC);
+}
+
+static void sec_mipi_dsim_config_dpi(struct sec_mipi_dsim *dsim)
+{
+	uint32_t config = 0, rgb_status = 0, data_lanes_en;
+
+	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO)
+		rgb_status &= ~RGB_STATUS_CMDMODE_INSEL;
+	else
+		rgb_status |= RGB_STATUS_CMDMODE_INSEL;
+
+	dsim_write(dsim, rgb_status, DSIM_RGB_STATUS);
+
+	if (dsim->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+		config |= CONFIG_NON_CONTINUOUS_CLOCK_LANE;
+		config |= CONFIG_CLKLANE_STOP_START;
+	}
+
+	if (dsim->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)
+		config |= CONFIG_MFLUSH_VS;
+
+	/* disable EoT packets in HS mode */
+	if (dsim->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
+		config |= CONFIG_EOT_R03;
+
+	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		config |= CONFIG_VIDEOMODE;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+			config |= CONFIG_BURSTMODE;
+
+		else if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+			config |= CONFIG_SYNCINFORM;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
+			config |= CONFIG_AUTOMODE;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
+			config |= CONFIG_HSEDISABLEMODE;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)
+			config |= CONFIG_HFPDISABLEMODE;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)
+			config |= CONFIG_HBPDISABLEMODE;
+
+		if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)
+			config |= CONFIG_HSADISABLEMODE;
+	}
+
+	config |= CONFIG_SET_MAINVC(dsim->channel);
+
+	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		switch (dsim->format) {
+		case MIPI_DSI_FMT_RGB565:
+			config |= CONFIG_SET_MAINPIXFORMAT(0x4);
+			break;
+		case MIPI_DSI_FMT_RGB666_PACKED:
+			config |= CONFIG_SET_MAINPIXFORMAT(0x5);
+			break;
+		case MIPI_DSI_FMT_RGB666:
+			config |= CONFIG_SET_MAINPIXFORMAT(0x6);
+			break;
+		case MIPI_DSI_FMT_RGB888:
+			config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+			break;
+		default:
+			config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+			break;
+		}
+	}
+
+	/* config data lanes number and enable lanes */
+	data_lanes_en = (0x1 << dsim->lanes) - 1;
+	config |= CONFIG_SET_NUMOFDATLANE(dsim->lanes - 1);
+	config |= CONFIG_SET_LANEEN(0x1 | data_lanes_en << 1);
+
+	dsim_write(dsim, config, DSIM_CONFIG);
+}
+
+static void sec_mipi_dsim_config_dphy(struct sec_mipi_dsim *dsim)
+{
+	struct sec_mipi_dsim_dphy_timing key = { 0 };
+	const struct sec_mipi_dsim_dphy_timing *match = NULL;
+	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+	uint32_t phytiming = 0, phytiming1 = 0, phytiming2 = 0, timeout = 0;
+	uint32_t hactive, vactive;
+	struct videomode *vmode = &dsim->vmode;
+	struct drm_display_mode mode;
+
+	key.bit_clk = DIV_ROUND_CLOSEST_ULL(dsim->bit_clk, 1000);
+
+	/* '1280x720@60Hz' mode with 2 data lanes
+	 * requires special fine tuning for DPHY
+	 * TIMING config according to the tests.
+	 */
+	if (dsim->lanes == 2) {
+		hactive = vmode->hactive;
+		vactive = vmode->vactive;
+
+		if (hactive == 1280 && vactive == 720) {
+			memset(&mode, 0x0, sizeof(mode));
+			drm_display_mode_from_videomode(vmode, &mode);
+
+			if (drm_mode_vrefresh(&mode) == 60)
+				key.bit_clk >>= 1;
+		}
+	}
+
+	match = bsearch(&key, pdata->dphy_timing, pdata->num_dphy_timing,
+			sizeof(struct sec_mipi_dsim_dphy_timing),
+			pdata->dphy_timing_cmp);
+	if (WARN_ON(!match))
+		return;
+
+	phytiming  |= PHYTIMING_SET_M_TLPXCTL(match->lpx)	|
+		      PHYTIMING_SET_M_THSEXITCTL(match->hs_exit);
+	dsim_write(dsim, phytiming, DSIM_PHYTIMING);
+
+	phytiming1 |= PHYTIMING1_SET_M_TCLKPRPRCTL(match->clk_prepare)	|
+		      PHYTIMING1_SET_M_TCLKZEROCTL(match->clk_zero)	|
+		      PHYTIMING1_SET_M_TCLKPOSTCTL(match->clk_post)	|
+		      PHYTIMING1_SET_M_TCLKTRAILCTL(match->clk_trail);
+	dsim_write(dsim, phytiming1, DSIM_PHYTIMING1);
+
+	phytiming2 |= PHYTIMING2_SET_M_THSPRPRCTL(match->hs_prepare)	|
+		      PHYTIMING2_SET_M_THSZEROCTL(match->hs_zero)	|
+		      PHYTIMING2_SET_M_THSTRAILCTL(match->hs_trail);
+	dsim_write(dsim, phytiming2, DSIM_PHYTIMING2);
+
+	timeout |= TIMEOUT_SET_BTAOUT(0xff)	|
+		   TIMEOUT_SET_LPDRTOUT(0xff);
+	dsim_write(dsim, timeout, DSIM_TIMEOUT);
+}
+
+static void sec_mipi_dsim_init_fifo_pointers(struct sec_mipi_dsim *dsim)
+{
+	uint32_t fifoctrl, fifo_ptrs;
+
+	fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+	fifo_ptrs = FIFOCTRL_NINITRX	|
+		    FIFOCTRL_NINITSFR	|
+		    FIFOCTRL_NINITI80	|
+		    FIFOCTRL_NINITSUB	|
+		    FIFOCTRL_NINITMAIN;
+
+	fifoctrl &= ~fifo_ptrs;
+	dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+	udelay(500);
+
+	fifoctrl |= fifo_ptrs;
+	dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+	udelay(500);
+}
+
+static void sec_mipi_dsim_config_clkctrl(struct sec_mipi_dsim *dsim)
+{
+	uint32_t clkctrl = 0, data_lanes_en;
+	uint32_t byte_clk, esc_prescaler;
+
+	clkctrl |= CLKCTRL_TXREQUESTHSCLK;
+
+	/* using 1.5Gbps PHY */
+	clkctrl |= CLKCTRL_DPHY_SEL_1P5G;
+
+	clkctrl |= CLKCTRL_ESCCLKEN;
+
+	clkctrl &= ~CLKCTRL_PLLBYPASS;
+
+	clkctrl |= CLKCTRL_BYTECLKSRC_DPHY_PLL;
+
+	clkctrl |= CLKCTRL_BYTECLKEN;
+
+	data_lanes_en = (0x1 << dsim->lanes) - 1;
+	clkctrl |= CLKCTRL_SET_LANEESCCLKEN(0x1 | data_lanes_en << 1);
+
+	/* calculate esc prescaler from byte clock:
+	 * EscClk = ByteClk / EscPrescaler;
+	 */
+	byte_clk = dsim->bit_clk >> 3;
+	esc_prescaler = DIV_ROUND_UP(byte_clk, MAX_ESC_CLK_FREQ);
+	clkctrl |= CLKCTRL_SET_ESCPRESCALER(esc_prescaler);
+
+	dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_set_standby(struct sec_mipi_dsim *dsim,
+				      bool standby)
+{
+	uint32_t mdresol = 0;
+
+	mdresol = dsim_read(dsim, DSIM_MDRESOL);
+
+	if (standby)
+		mdresol |= MDRESOL_MAINSTANDBY;
+	else
+		mdresol &= ~MDRESOL_MAINSTANDBY;
+
+	dsim_write(dsim, mdresol, DSIM_MDRESOL);
+}
+
+struct dsim_pll_pms *sec_mipi_dsim_calc_pmsk(struct sec_mipi_dsim *dsim)
+{
+	uint32_t p, m, s;
+	uint32_t best_p = 0, best_m = 0, best_s = 0;
+	uint32_t fin, fout;
+	uint32_t s_pow_2, raw_s;
+	uint64_t mfin, pfvco, pfout, psfout;
+	uint32_t delta, best_delta = ~0U;
+	struct dsim_pll_pms *pll_pms;
+	struct device *dev = dsim->dev;
+	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+	struct sec_mipi_dsim_pll dpll = *pdata->dphy_pll;
+	struct sec_mipi_dsim_range *prange = &dpll.p;
+	struct sec_mipi_dsim_range *mrange = &dpll.m;
+	struct sec_mipi_dsim_range *srange = &dpll.s;
+	struct sec_mipi_dsim_range *krange = &dpll.k;
+	struct sec_mipi_dsim_range *fvco_range  = &dpll.fvco;
+	struct sec_mipi_dsim_range *fpref_range = &dpll.fpref;
+	struct sec_mipi_dsim_range pr_new = *prange;
+	struct sec_mipi_dsim_range sr_new = *srange;
+
+	pll_pms = devm_kzalloc(dev, sizeof(*pll_pms), GFP_KERNEL);
+	if (!pll_pms) {
+		dev_err(dev, "Unable to allocate 'pll_pms'\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	fout = dsim->bit_clk;
+	fin  = dsim->pref_clk;
+
+	/* TODO: ignore 'k' for PMS calculation,
+	 * only use 'p', 'm' and 's' to generate
+	 * the requested PLL output clock.
+	 */
+	krange->min = 0;
+	krange->max = 0;
+
+	/* narrow 'p' range via 'Fpref' limitation:
+	 * Fpref : [2MHz ~ 30MHz] (Fpref = Fin / p)
+	 */
+	prange->min = max(prange->min, DIV_ROUND_UP(fin, fpref_range->max));
+	prange->max = min(prange->max, fin / fpref_range->min);
+
+	/* narrow 'm' range via 'Fvco' limitation:
+	 * Fvco: [1050MHz ~ 2100MHz] (Fvco = ((m + k / 65536) * Fin) / p)
+	 * So, m = Fvco * p / Fin and Fvco > Fin;
+	 */
+	pfvco = (uint64_t)fvco_range->min * prange->min;
+	mrange->min = max_t(uint32_t, mrange->min,
+			    DIV_ROUND_UP_ULL(pfvco, fin));
+	pfvco = (uint64_t)fvco_range->max * prange->max;
+	mrange->max = min_t(uint32_t, mrange->max,
+			    DIV_ROUND_UP_ULL(pfvco, fin));
+
+	dev_dbg(dev, "p: min = %u, max = %u, "
+		     "m: min = %u, max = %u, "
+		     "s: min = %u, max = %u\n",
+		prange->min, prange->max, mrange->min,
+		mrange->max, srange->min, srange->max);
+
+	/* first determine 'm', then can determine 'p', last determine 's' */
+	for (m = mrange->min; m <= mrange->max; m++) {
+		/* p = m * Fin / Fvco */
+		mfin = (uint64_t)m * fin;
+		pr_new.min = max_t(uint32_t, prange->min,
+				   DIV_ROUND_UP_ULL(mfin, fvco_range->max));
+		pr_new.max = min_t(uint32_t, prange->max,
+				   (mfin / fvco_range->min));
+
+		if (pr_new.max < pr_new.min || pr_new.min < prange->min)
+			continue;
+
+		for (p = pr_new.min; p <= pr_new.max; p++) {
+			/* s = order_pow_of_two((m * Fin) / (p * Fout)) */
+			pfout = (uint64_t)p * fout;
+			raw_s = DIV_ROUND_CLOSEST_ULL(mfin, pfout);
+
+			s_pow_2 = rounddown_pow_of_two(raw_s);
+			sr_new.min = max_t(uint32_t, srange->min,
+					   order_base_2(s_pow_2));
+
+			s_pow_2 = roundup_pow_of_two(DIV_ROUND_CLOSEST_ULL(mfin, pfout));
+			sr_new.max = min_t(uint32_t, srange->max,
+					   order_base_2(s_pow_2));
+
+			if (sr_new.max < sr_new.min || sr_new.min < srange->min)
+				continue;
+
+			for (s = sr_new.min; s <= sr_new.max; s++) {
+				/* fout = m * Fin / (p * 2^s) */
+				psfout = pfout * (1 << s);
+				delta = abs(psfout - mfin);
+				if (delta < best_delta) {
+					best_p = p;
+					best_m = m;
+					best_s = s;
+					best_delta = delta;
+				}
+			}
+		}
+	}
+
+	if (best_delta == ~0U) {
+		devm_kfree(dev, pll_pms);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pll_pms->p = best_p;
+	pll_pms->m = best_m;
+	pll_pms->s = best_s;
+
+	dev_dbg(dev, "fout = %u, fin = %u, m = %u, "
+		     "p = %u, s = %u, best_delta = %u\n",
+		fout, fin, pll_pms->m, pll_pms->p, pll_pms->s, best_delta);
+
+	return pll_pms;
+}
+
+int sec_mipi_dsim_check_pll_out(void *driver_private,
+				const struct drm_display_mode *mode)
+{
+	int bpp;
+	uint32_t pix_clk, bit_clk;
+	struct sec_mipi_dsim *dsim = driver_private;
+	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+	const struct dsim_hblank_par *hpar;
+	const struct dsim_pll_pms *pmsk;
+
+	bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
+	if (bpp < 0)
+		return -EINVAL;
+
+	pix_clk = mode->clock;
+	bit_clk = DIV_ROUND_UP(pix_clk * bpp, dsim->lanes);
+
+	if (bit_clk * 1000 > pdata->max_data_rate) {
+		dev_err(dsim->dev,
+			"reuest bit clk freq exceeds lane's maximum value\n");
+		return -EINVAL;
+	}
+
+	dsim->pix_clk = pix_clk;
+	dsim->bit_clk = bit_clk;
+	dsim->hpar = NULL;
+
+	pmsk = sec_mipi_dsim_calc_pmsk(dsim);
+	if (IS_ERR(pmsk)) {
+		dev_err(dsim->dev,
+			"failed to get pmsk for: fin = %u, fout = %u\n",
+			dsim->pref_clk, dsim->bit_clk);
+		return -EINVAL;
+	}
+
+	dsim->pms = PLLCTRL_SET_P(pmsk->p) |
+		    PLLCTRL_SET_M(pmsk->m) |
+		    PLLCTRL_SET_S(pmsk->s);
+
+	/* free 'dsim_pll_pms' structure data which is
+	 * allocated in 'sec_mipi_dsim_calc_pmsk()'.
+	 */
+	devm_kfree(dsim->dev, (void *)pmsk);
+
+	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+		hpar = sec_mipi_dsim_get_hblank_par(mode->name,
+						    mode->vrefresh,
+						    dsim->lanes);
+		dsim->hpar = hpar;
+		if (!hpar)
+			dev_dbg(dsim->dev, "no pre-exist hpar can be used\n");
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sec_mipi_dsim_check_pll_out);
+
+static void sec_mipi_dsim_bridge_enable(struct drm_bridge *bridge)
+{
+	int ret;
+	struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+	/* At this moment, the dsim bridge's preceding encoder has
+	 * already been enabled. So the dsim can be configed here
+	 */
+
+	/* config main display mode */
+	sec_mipi_dsim_set_main_mode(dsim);
+
+	/* config dsim dpi */
+	sec_mipi_dsim_config_dpi(dsim);
+
+	/* config dsim pll */
+	ret = sec_mipi_dsim_config_pll(dsim);
+	if (ret) {
+		dev_err(dsim->dev, "dsim pll config failed: %d\n", ret);
+		return;
+	}
+
+	/* config dphy timings */
+	sec_mipi_dsim_config_dphy(dsim);
+
+	/* initialize FIFO pointers */
+	sec_mipi_dsim_init_fifo_pointers(dsim);
+
+	/* prepare panel if exists */
+	if (dsim->panel) {
+		ret = drm_panel_prepare(dsim->panel);
+		if (unlikely(ret)) {
+			dev_err(dsim->dev, "panel prepare failed: %d\n", ret);
+			return;
+		}
+	}
+
+	/* config esc clock, byte clock and etc */
+	sec_mipi_dsim_config_clkctrl(dsim);
+
+	/* enable panel if exists */
+	if (dsim->panel) {
+		ret = drm_panel_enable(dsim->panel);
+		if (unlikely(ret)) {
+			dev_err(dsim->dev, "panel enable failed: %d\n", ret);
+			goto panel_unprepare;
+		}
+	}
+
+	/* enable data transfer of dsim */
+	sec_mipi_dsim_set_standby(dsim, true);
+
+	return;
+
+panel_unprepare:
+	ret = drm_panel_unprepare(dsim->panel);
+	if (unlikely(ret))
+		dev_err(dsim->dev, "panel unprepare failed: %d\n", ret);
+}
+
+static void sec_mipi_dsim_disable_clkctrl(struct sec_mipi_dsim *dsim)
+{
+	uint32_t clkctrl;
+
+	clkctrl = dsim_read(dsim, DSIM_CLKCTRL);
+
+	clkctrl &= ~CLKCTRL_TXREQUESTHSCLK;
+
+	clkctrl &= ~CLKCTRL_ESCCLKEN;
+
+	clkctrl &= ~CLKCTRL_BYTECLKEN;
+
+	dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_disable_pll(struct sec_mipi_dsim *dsim)
+{
+	uint32_t pllctrl;
+
+	pllctrl  = dsim_read(dsim, DSIM_PLLCTRL);
+
+	pllctrl &= ~PLLCTRL_PLLEN;
+
+	dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+}
+
+static void sec_mipi_dsim_bridge_disable(struct drm_bridge *bridge)
+{
+	int ret;
+	struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+	/* disable panel if exists */
+	if (dsim->panel) {
+		ret = drm_panel_disable(dsim->panel);
+		if (unlikely(ret))
+			dev_err(dsim->dev, "panel disable failed: %d\n", ret);
+	}
+
+	/* disable data transfer of dsim */
+	sec_mipi_dsim_set_standby(dsim, false);
+
+	/* disable esc clock & byte clock */
+	sec_mipi_dsim_disable_clkctrl(dsim);
+
+	/* disable dsim pll */
+	sec_mipi_dsim_disable_pll(dsim);
+
+	/* unprepare panel if exists */
+	if (dsim->panel) {
+		ret = drm_panel_unprepare(dsim->panel);
+		if (unlikely(ret))
+			dev_err(dsim->dev, "panel unprepare failed: %d\n", ret);
+	}
+}
+
+static bool sec_mipi_dsim_bridge_mode_fixup(struct drm_bridge *bridge,
+					    const struct drm_display_mode *mode,
+					    struct drm_display_mode *adjusted_mode)
+{
+	int private_flags;
+	struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+	/* Since mipi dsi cannot do color conversion,
+	 * so the pixel format output by mipi dsi should
+	 * be the same with the pixel format recieved by
+	 * mipi dsi. And the pixel format information needs
+	 * to be passed to CRTC to be checked with the CRTC
+	 * attached plane fb pixel format.
+	 */
+	switch (dsim->format) {
+	case MIPI_DSI_FMT_RGB888:
+		private_flags = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		private_flags = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		private_flags = MEDIA_BUS_FMT_RGB666_1X18;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+		private_flags = MEDIA_BUS_FMT_RGB565_1X16;
+		break;
+	default:
+		return false;
+	}
+
+	adjusted_mode->private_flags = private_flags;
+
+	/* the 'bus_flags' in connector's display_info is useless
+	 * for mipi dsim, since dsim only sends packets with no
+	 * polarities information in the packets. But the dsim
+	 * host has some polarities requirements for the CRTC:
+	 * dsim only can accpet active high Vsync, Hsync and DE
+	 * signals.
+	 */
+	if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) {
+		adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
+		adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	}
+
+	if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) {
+		adjusted_mode->flags &= ~DRM_MODE_FLAG_NVSYNC;
+		adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+	}
+
+	/* workaround for CEA standard mode "1280x720@60"
+	 * display on 4 data lanes with Non-burst with sync
+	 * pulse DSI mode, since use the standard horizontal
+	 * timings cannot display correctly. And this code
+	 * cannot be put into the dsim Bridge's mode_fixup,
+	 * since the DSI device lane number change always
+	 * happens after that.
+	 */
+	if (!strcmp(mode->name, "1280x720") &&
+	    mode->vrefresh == 60	    &&
+	    dsim->lanes == 4		    &&
+	    dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+		adjusted_mode->hsync_start += 2;
+		adjusted_mode->hsync_end   += 2;
+		adjusted_mode->htotal      += 2;
+	}
+
+	return true;
+}
+
+static void sec_mipi_dsim_bridge_mode_set(struct drm_bridge *bridge,
+					  const struct drm_display_mode *mode,
+					  const struct drm_display_mode *adjusted_mode)
+{
+	struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+	/* This hook is called when the display pipe is completely
+	 * off. And since the pm runtime is implemented, the dsim
+	 * hardware cannot be accessed at this moment. So move all
+	 * the mode_set config to ->enable() hook.
+	 * And this hook is called only when 'mode_changed' is true,
+	 * so it is called not every time atomic commit.
+	 */
+
+	drm_display_mode_to_videomode(adjusted_mode, &dsim->vmode);
+}
+
+static const struct drm_bridge_funcs sec_mipi_dsim_bridge_funcs = {
+	.attach     = sec_mipi_dsim_bridge_attach,
+	.enable     = sec_mipi_dsim_bridge_enable,
+	.disable    = sec_mipi_dsim_bridge_disable,
+	.mode_set   = sec_mipi_dsim_bridge_mode_set,
+	.mode_fixup = sec_mipi_dsim_bridge_mode_fixup,
+};
+
+void sec_mipi_dsim_suspend(struct device *dev)
+{
+	struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+	/* TODO: add dsim reset */
+
+	clk_disable_unprepare(dsim->clk_cfg);
+
+	clk_disable_unprepare(dsim->clk_pllref);
+}
+EXPORT_SYMBOL(sec_mipi_dsim_suspend);
+
+void sec_mipi_dsim_resume(struct device *dev)
+{
+	struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+	clk_prepare_enable(dsim->clk_pllref);
+
+	clk_prepare_enable(dsim->clk_cfg);
+
+	sec_mipi_dsim_irq_init(dsim);
+
+	/* TODO: add dsim de-reset */
+}
+EXPORT_SYMBOL(sec_mipi_dsim_resume);
+
+static void __maybe_unused sec_mipi_dsim_irq_mask(struct sec_mipi_dsim *dsim,
+						  int irq_idx)
+{
+	uint32_t intmsk;
+
+	intmsk = dsim_read(dsim, DSIM_INTMSK);
+
+	switch (irq_idx) {
+	case PLLSTABLE:
+		intmsk |= INTMSK_MSKPLLSTABLE;
+		break;
+	case SWRSTRELEASE:
+		intmsk |= INTMSK_MSKSWRELEASE;
+		break;
+	case SFRPLFIFOEMPTY:
+		intmsk |= INTMSK_MSKSFRPLFIFOEMPTY;
+		break;
+	case SFRPHFIFOEMPTY:
+		intmsk |= INTMSK_MSKSFRPHFIFOEMPTY;
+		break;
+	case FRAMEDONE:
+		intmsk |= INTMSK_MSKFRAMEDONE;
+		break;
+	case LPDRTOUT:
+		intmsk |= INTMSK_MSKLPDRTOUT;
+		break;
+	case TATOUT:
+		intmsk |= INTMSK_MSKTATOUT;
+		break;
+	case RXDATDONE:
+		intmsk |= INTMSK_MSKRXDATDONE;
+		break;
+	case RXTE:
+		intmsk |= INTMSK_MSKRXTE;
+		break;
+	case RXACK:
+		intmsk |= INTMSK_MSKRXACK;
+		break;
+	default:
+		/* unsupported irq */
+		return;
+	}
+
+	writel(intmsk, dsim->base + DSIM_INTMSK);
+}
+
+static void sec_mipi_dsim_irq_unmask(struct sec_mipi_dsim *dsim,
+				     int irq_idx)
+{
+	uint32_t intmsk;
+
+	intmsk = dsim_read(dsim, DSIM_INTMSK);
+
+	switch (irq_idx) {
+	case PLLSTABLE:
+		intmsk &= ~INTMSK_MSKPLLSTABLE;
+		break;
+	case SWRSTRELEASE:
+		intmsk &= ~INTMSK_MSKSWRELEASE;
+		break;
+	case SFRPLFIFOEMPTY:
+		intmsk &= ~INTMSK_MSKSFRPLFIFOEMPTY;
+		break;
+	case SFRPHFIFOEMPTY:
+		intmsk &= ~INTMSK_MSKSFRPHFIFOEMPTY;
+		break;
+	case FRAMEDONE:
+		intmsk &= ~INTMSK_MSKFRAMEDONE;
+		break;
+	case LPDRTOUT:
+		intmsk &= ~INTMSK_MSKLPDRTOUT;
+		break;
+	case TATOUT:
+		intmsk &= ~INTMSK_MSKTATOUT;
+		break;
+	case RXDATDONE:
+		intmsk &= ~INTMSK_MSKRXDATDONE;
+		break;
+	case RXTE:
+		intmsk &= ~INTMSK_MSKRXTE;
+		break;
+	case RXACK:
+		intmsk &= ~INTMSK_MSKRXACK;
+		break;
+	default:
+		/* unsupported irq */
+		return;
+	}
+
+	dsim_write(dsim, intmsk, DSIM_INTMSK);
+}
+
+/* write 1 clear irq */
+static void sec_mipi_dsim_irq_clear(struct sec_mipi_dsim *dsim,
+				    int irq_idx)
+{
+	uint32_t intsrc = 0;
+
+	switch (irq_idx) {
+	case PLLSTABLE:
+		intsrc |= INTSRC_PLLSTABLE;
+		break;
+	case SWRSTRELEASE:
+		intsrc |= INTSRC_SWRSTRELEASE;
+		break;
+	case SFRPLFIFOEMPTY:
+		intsrc |= INTSRC_SFRPLFIFOEMPTY;
+		break;
+	case SFRPHFIFOEMPTY:
+		intsrc |= INTSRC_SFRPHFIFOEMPTY;
+		break;
+	case FRAMEDONE:
+		intsrc |= INTSRC_FRAMEDONE;
+		break;
+	case LPDRTOUT:
+		intsrc |= INTSRC_LPDRTOUT;
+		break;
+	case TATOUT:
+		intsrc |= INTSRC_TATOUT;
+		break;
+	case RXDATDONE:
+		intsrc |= INTSRC_RXDATDONE;
+		break;
+	case RXTE:
+		intsrc |= INTSRC_RXTE;
+		break;
+	case RXACK:
+		intsrc |= INTSRC_RXACK;
+		break;
+	default:
+		/* unsupported irq */
+		return;
+	}
+
+	dsim_write(dsim, intsrc, DSIM_INTSRC);
+}
+
+static void sec_mipi_dsim_irq_init(struct sec_mipi_dsim *dsim)
+{
+	sec_mipi_dsim_irq_unmask(dsim, PLLSTABLE);
+	sec_mipi_dsim_irq_unmask(dsim, SWRSTRELEASE);
+
+	if (dsim->panel) {
+		sec_mipi_dsim_irq_unmask(dsim, SFRPLFIFOEMPTY);
+		sec_mipi_dsim_irq_unmask(dsim, SFRPHFIFOEMPTY);
+		sec_mipi_dsim_irq_unmask(dsim, LPDRTOUT);
+		sec_mipi_dsim_irq_unmask(dsim, TATOUT);
+		sec_mipi_dsim_irq_unmask(dsim, RXDATDONE);
+		sec_mipi_dsim_irq_unmask(dsim, RXTE);
+		sec_mipi_dsim_irq_unmask(dsim, RXACK);
+	}
+}
+
+static irqreturn_t sec_mipi_dsim_irq_handler(int irq, void *data)
+{
+	uint32_t intsrc, status;
+	struct sec_mipi_dsim *dsim = data;
+
+	intsrc = dsim_read(dsim, DSIM_INTSRC);
+	status = dsim_read(dsim, DSIM_STATUS);
+
+	if (WARN_ON(!intsrc)) {
+		dev_err(dsim->dev, "interrupt is not from dsim\n");
+		return IRQ_NONE;
+	}
+
+	if (WARN_ON(!(intsrc & INTSRC_MASK))) {
+		dev_warn(dsim->dev, "unenable irq happens: %#x\n", intsrc);
+		/* just clear irqs */
+		dsim_write(dsim, intsrc, DSIM_INTSRC);
+		return IRQ_NONE;
+	}
+
+	if (intsrc & INTSRC_PLLSTABLE) {
+		WARN_ON(!(status & STATUS_PLLSTABLE));
+		sec_mipi_dsim_irq_clear(dsim, PLLSTABLE);
+		complete(&dsim->pll_stable);
+	}
+
+	if (intsrc & INTSRC_SWRSTRELEASE)
+		sec_mipi_dsim_irq_clear(dsim, SWRSTRELEASE);
+
+	if (intsrc & INTSRC_SFRPLFIFOEMPTY) {
+		sec_mipi_dsim_irq_clear(dsim, SFRPLFIFOEMPTY);
+		complete(&dsim->pl_tx_done);
+	}
+
+	if (intsrc & INTSRC_SFRPHFIFOEMPTY) {
+		sec_mipi_dsim_irq_clear(dsim, SFRPHFIFOEMPTY);
+		complete(&dsim->ph_tx_done);
+	}
+
+	if (WARN_ON(intsrc & INTSRC_LPDRTOUT)) {
+		sec_mipi_dsim_irq_clear(dsim, LPDRTOUT);
+		dev_warn(dsim->dev, "LP RX timeout\n");
+	}
+
+	if (WARN_ON(intsrc & INTSRC_TATOUT)) {
+		sec_mipi_dsim_irq_clear(dsim, TATOUT);
+		dev_warn(dsim->dev, "Turns around Acknowledge timeout\n");
+	}
+
+	if (intsrc & INTSRC_RXDATDONE) {
+		sec_mipi_dsim_irq_clear(dsim, RXDATDONE);
+		complete(&dsim->rx_done);
+	}
+
+	if (intsrc & INTSRC_RXTE) {
+		sec_mipi_dsim_irq_clear(dsim, RXTE);
+		dev_dbg(dsim->dev, "TE Rx trigger received\n");
+	}
+
+	if (intsrc & INTSRC_RXACK) {
+		sec_mipi_dsim_irq_clear(dsim, RXACK);
+		dev_dbg(dsim->dev, "ACK Rx trigger received\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int sec_mipi_dsim_connector_get_modes(struct drm_connector *connector)
+{
+	struct sec_mipi_dsim *dsim = conn_to_sec_mipi_dsim(connector);
+
+	if (WARN_ON(!dsim->panel))
+		return -ENODEV;
+
+	return drm_panel_get_modes(dsim->panel);
+}
+
+static const struct drm_connector_helper_funcs
+	sec_mipi_dsim_connector_helper_funcs = {
+	.get_modes = sec_mipi_dsim_connector_get_modes,
+};
+
+static enum drm_connector_status
+	sec_mipi_dsim_connector_detect(struct drm_connector *connector,
+				       bool force)
+{
+	/* TODO: add support later */
+
+	return connector_status_connected;
+}
+
+static const struct drm_connector_funcs sec_mipi_dsim_connector_funcs = {
+	.detect     = sec_mipi_dsim_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy    = drm_connector_cleanup,
+	.reset      = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
+};
+
+int sec_mipi_dsim_bind(struct device *dev, struct device *master, void *data,
+		       struct drm_encoder *encoder, struct resource *res,
+		       int irq, const struct sec_mipi_dsim_plat_data *pdata)
+{
+	int ret, version;
+	struct drm_device *drm_dev = data;
+	struct drm_bridge *bridge;
+	struct drm_connector *connector;
+	struct sec_mipi_dsim *dsim;
+	struct device_node *node = NULL;
+
+	dev_dbg(dev, "sec-dsim bridge bind begin\n");
+
+	dsim = devm_kzalloc(dev, sizeof(*dsim), GFP_KERNEL);
+	if (!dsim) {
+		dev_err(dev, "Unable to allocate 'dsim'\n");
+		return -ENOMEM;
+	}
+
+	dsim->dev = dev;
+	dsim->irq = irq;
+	dsim->pdata = pdata;
+	dsim->encoder = encoder;
+
+	dsim->dsi_host.ops = &sec_mipi_dsim_host_ops;
+	dsim->dsi_host.dev = dev;
+
+	dsim->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dsim->base))
+		return PTR_ERR(dsim->base);
+
+	dsim->clk_pllref = devm_clk_get(dev, "pll-ref");
+	if (IS_ERR(dsim->clk_pllref)) {
+		ret = PTR_ERR(dsim->clk_pllref);
+		dev_err(dev, "Unable to get phy pll reference clock: %d\n", ret);
+		return ret;
+	}
+
+	dsim->clk_cfg = devm_clk_get(dev, "cfg");
+	if (IS_ERR(dsim->clk_cfg)) {
+		ret = PTR_ERR(dsim->clk_cfg);
+		dev_err(dev, "Unable to get configuration clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, dsim);
+
+	pm_runtime_get_sync(dev);
+	version = dsim_read(dsim, DSIM_VERSION);
+	WARN_ON(version != pdata->version);
+	pm_runtime_put_sync(dev);
+
+	dev_info(dev, "version number is %#x\n", version);
+
+	/* set suitable rate for phy ref clock */
+	ret = sec_mipi_dsim_set_pref_rate(dsim);
+	if (ret) {
+		dev_err(dev, "failed to set pll ref clock rate\n");
+		return ret;
+	}
+
+	ret = devm_request_irq(dev, dsim->irq,
+			       sec_mipi_dsim_irq_handler,
+			       0, dev_name(dev), dsim);
+	if (ret) {
+		dev_err(dev, "failed to request dsim irq: %d\n", ret);
+		return ret;
+	}
+
+	init_completion(&dsim->pll_stable);
+	init_completion(&dsim->ph_tx_done);
+	init_completion(&dsim->pl_tx_done);
+	init_completion(&dsim->rx_done);
+
+	/* Initialize and attach sec dsim bridge */
+	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+	if (!bridge) {
+		dev_err(dev, "Unable to allocate 'bridge'\n");
+		return -ENOMEM;
+	}
+
+	/* mipi dsi host needs to be registered before bridge attach, since:
+	 * 1. Have Panel
+	 *    The 'mipi_dsi_host_register' will allocate a mipi_dsi_device
+	 *    if the dsi host node has a panel child node in DTB. And dsi
+	 *    host ->attach() will be called in panel's probe().
+	 *
+	 * 2. Have Bridge
+	 *    The dsi host ->attach() will be called through the below
+	 *    'drm_bridge_attach()' which will attach next bridge in a
+	 *    chain.
+	 */
+	ret = mipi_dsi_host_register(&dsim->dsi_host);
+	if (ret) {
+		dev_err(dev, "Unable to register mipi dsi host: %d\n", ret);
+		return ret;
+	}
+
+	dsim->bridge = bridge;
+	bridge->driver_private = dsim;
+	bridge->funcs = &sec_mipi_dsim_bridge_funcs;
+	bridge->of_node = dev->of_node;
+	bridge->encoder = encoder;
+
+	/* attach sec dsim bridge and its next bridge if exists */
+	ret = drm_bridge_attach(encoder, bridge, NULL);
+	if (ret) {
+		dev_err(dev, "Failed to attach bridge: %s\n", dev_name(dev));
+
+		/* no bridge exists, so defer probe to wait
+		 * panel driver loading
+		 */
+		if (ret != -EPROBE_DEFER) {
+			for_each_available_child_of_node(dev->of_node, node) {
+				/* skip nodes without reg property */
+				if (!of_find_property(node, "reg", NULL))
+					continue;
+
+				/* error codes only ENODEV or EPROBE_DEFER */
+				dsim->panel = of_drm_find_panel(node);
+				if (!IS_ERR(dsim->panel))
+					goto panel;
+
+				ret = PTR_ERR(dsim->panel);
+			}
+		}
+
+		mipi_dsi_host_unregister(&dsim->dsi_host);
+		return ret;
+	}
+
+panel:
+	if (dsim->panel) {
+		/* A panel has been attached */
+		connector = &dsim->connector;
+
+		drm_connector_helper_add(connector,
+					 &sec_mipi_dsim_connector_helper_funcs);
+		ret = drm_connector_init(drm_dev, connector,
+					 &sec_mipi_dsim_connector_funcs,
+					 DRM_MODE_CONNECTOR_DSI);
+		if (ret)
+			goto host_unregister;
+
+		/* TODO */
+		connector->dpms = DRM_MODE_DPMS_OFF;
+
+		ret = drm_connector_attach_encoder(connector, encoder);
+		if (ret)
+			goto cleanup_connector;
+
+		ret = drm_panel_attach(dsim->panel, connector);
+		if (ret)
+			goto cleanup_connector;
+	}
+
+	dev_dbg(dev, "sec-dsim bridge bind end\n");
+
+	return 0;
+
+cleanup_connector:
+	drm_connector_cleanup(connector);
+host_unregister:
+	mipi_dsi_host_unregister(&dsim->dsi_host);
+	return ret;
+}
+EXPORT_SYMBOL(sec_mipi_dsim_bind);
+
+void sec_mipi_dsim_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+	if (dsim->panel) {
+		drm_panel_detach(dsim->panel);
+		drm_connector_cleanup(&dsim->connector);
+	}
+
+	mipi_dsi_host_unregister(&dsim->dsi_host);
+}
+EXPORT_SYMBOL(sec_mipi_dsim_unbind);
+
+MODULE_DESCRIPTION("Samsung MIPI DSI Host Controller bridge driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/sil-sii8620.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -177,7 +177,7 @@
 
 static u8 sii8620_readb(struct sii8620 *ctx, u16 addr)
 {
-	u8 ret;
+	u8 ret = 0;
 
 	sii8620_read_buf(ctx, addr, &ret, 1);
 	return ret;
@@ -604,7 +604,7 @@
 	u8 *buf = &ctx->burst.tx_buf[ctx->burst.tx_count];
 	int size = len + 2;
 
-	if (ctx->burst.tx_count + size > ARRAY_SIZE(ctx->burst.tx_buf)) {
+	if (ctx->burst.tx_count + size >= ARRAY_SIZE(ctx->burst.tx_buf)) {
 		dev_err(ctx->dev, "TX-BLK buffer exhausted\n");
 		ctx->error = -EINVAL;
 		return NULL;
@@ -621,7 +621,7 @@
 	u8 *buf = &ctx->burst.rx_buf[ctx->burst.rx_count];
 	int size = len + 1;
 
-	if (ctx->burst.tx_count + size > ARRAY_SIZE(ctx->burst.tx_buf)) {
+	if (ctx->burst.rx_count + size >= ARRAY_SIZE(ctx->burst.rx_buf)) {
 		dev_err(ctx->dev, "RX-BLK buffer exhausted\n");
 		ctx->error = -EINVAL;
 		return NULL;
@@ -985,7 +985,7 @@
 
 static void sii8620_stop_video(struct sii8620 *ctx)
 {
-	u8 uninitialized_var(val);
+	u8 val;
 
 	sii8620_write_seq_static(ctx,
 		REG_TPI_INTR_EN, 0,
@@ -2118,7 +2118,7 @@
 	if (ret) {
 		dev_err(ctx->dev, "Failed to register RC device\n");
 		ctx->error = ret;
-		rc_free_device(ctx->rc_dev);
+		rc_free_device(rc_dev);
 		return;
 	}
 	ctx->rc_dev = rc_dev;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/Kconfig
@@ -25,6 +25,17 @@
 	  Support the I2S Audio interface which is part of the Synopsys
 	  Designware HDMI block.
 
+config DRM_DW_HDMI_GP_AUDIO
+	tristate "Synopsys Designware GP Audio interface"
+	depends on DRM_DW_HDMI && SND
+	select SND_PCM
+	select SND_PCM_ELD
+	select SND_PCM_IEC958
+	help
+	  Support the GP Audio interface which is part of the Synopsys
+	  Designware HDMI block.  This is used in conjunction with
+	  the i.MX865 HDMI driver.
+
 config DRM_DW_HDMI_CEC
 	tristate "Synopsis Designware CEC interface"
 	depends on DRM_DW_HDMI
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -18,6 +18,8 @@
 
 #include "dw-hdmi-cec.h"
 
+static u8 cec_saved_regs[5];
+
 enum {
 	HDMI_IH_CEC_STAT0	= 0x0106,
 	HDMI_IH_MUTE_CEC_STAT0	= 0x0186,
@@ -308,11 +310,44 @@
 	return 0;
 }
 
+static int __maybe_unused dw_hdmi_cec_resume(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* Restore logical address and interrupt status/mask register */
+	dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
+	dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);
+	dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
+	dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
+	dw_hdmi_write(cec, cec_saved_regs[4], HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* store logical address and interrupt status/mask register */
+	cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
+	cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
+	cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
+	cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
+	cec_saved_regs[4] = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_hdmi_cec_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume)
+};
+
 static struct platform_driver dw_hdmi_cec_driver = {
 	.probe	= dw_hdmi_cec_probe,
 	.remove	= dw_hdmi_cec_remove,
 	.driver = {
 		.name = "dw-hdmi-cec",
+		.pm = &dw_hdmi_cec_pm,
 	},
 };
 module_platform_driver(dw_hdmi_cec_driver);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2020 NXP
+/*
+ * This program is free software; you can 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/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_connector.h>
+
+#include <sound/hdmi-codec.h>
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_drm_eld.h>
+#include <sound/pcm_iec958.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-gp-audio"
+#define DRV_NAME    "hdmi-gp-audio"
+
+struct snd_dw_hdmi {
+	struct dw_hdmi_audio_data data;
+	struct platform_device  *audio_pdev;
+	unsigned int pos;
+};
+
+struct dw_hdmi_channel_conf {
+	u8 conf1;
+	u8 ca;
+};
+
+/*
+ * The default mapping of ALSA channels to HDMI channels and speaker
+ * allocation bits.  Note that we can't do channel remapping here -
+ * channels must be in the same order.
+ *
+ * Mappings for alsa-lib pcm/surround*.conf files:
+ *
+ *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
+ * Channels	2	4	6	6	6	8
+ *
+ * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
+ *
+ *				Number of ALSA channels
+ * ALSA Channel	2	3	4	5	6	7	8
+ * 0		FL:0	=	=	=	=	=	=
+ * 1		FR:1	=	=	=	=	=	=
+ * 2			FC:3	RL:4	LFE:2	=	=	=
+ * 3				RR:5	RL:4	FC:3	=	=
+ * 4					RR:5	RL:4	=	=
+ * 5						RR:5	=	=
+ * 6							RC:6	=
+ * 7							RLC/FRC	RLC/FRC
+ */
+static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
+	{ 0x03, 0x00 },	/* FL,FR */
+	{ 0x0b, 0x02 },	/* FL,FR,FC */
+	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
+	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
+	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
+	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
+	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
+};
+
+static int audio_hw_params(struct device *dev,  void *data,
+			   struct hdmi_codec_daifmt *daifmt,
+			   struct hdmi_codec_params *params)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+	u8 ca;
+
+	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
+
+	ca = default_hdmi_channel_config[params->channels - 2].ca;
+
+	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
+	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
+
+	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
+				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
+	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
+
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+}
+
+static int audio_digital_mute(struct device *dev, void *data,
+			      bool enable)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (!enable)
+		dw_hdmi_audio_enable(dw->data.hdmi);
+	else
+		dw_hdmi_audio_disable(dw->data.hdmi);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+			 u8 *buf, size_t len)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	memcpy(buf, dw->data.eld, min_t(size_t, MAX_ELD_BYTES, len));
+
+	return 0;
+}
+
+static int audio_hook_plugged_cb(struct device *dev, void *data,
+				 hdmi_codec_plugged_cb fn,
+				 struct device *codec_dev)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.digital_mute = audio_digital_mute,
+	.get_eld = audio_get_eld,
+	.hook_plugged_cb = audio_hook_plugged_cb,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
+	struct snd_dw_hdmi *dw;
+
+	struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 0,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+	};
+
+	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	dw->data = *data;
+
+	platform_set_drvdata(pdev, dw);
+
+	dw->audio_pdev = platform_device_register_data(&pdev->dev,
+						       HDMI_CODEC_DRV_NAME, 1,
+						       &codec_data,
+						       sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(dw->audio_pdev);
+}
+
+static int snd_dw_hdmi_remove(struct platform_device *pdev)
+{
+	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
+
+	platform_device_unregister(dw->audio_pdev);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.remove	= snd_dw_hdmi_remove,
+	.driver	= {
+		.name = DRIVER_NAME,
+	},
+};
+
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
@@ -151,11 +151,22 @@
 	return -EINVAL;
 }
 
+static int dw_hdmi_i2s_hook_plugged_cb(struct device *dev, void *data,
+				       hdmi_codec_plugged_cb fn,
+				       struct device *codec_dev)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev);
+}
+
 static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
 	.hw_params	= dw_hdmi_i2s_hw_params,
 	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
 	.get_eld	= dw_hdmi_i2s_get_eld,
 	.get_dai_id	= dw_hdmi_i2s_get_dai_id,
+	.hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
 };
 
 static int snd_dw_hdmi_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -36,6 +36,7 @@
 #include "dw-hdmi-cec.h"
 #include "dw-hdmi.h"
 
+#define DDC_CI_ADDR		0x37
 #define DDC_SEGMENT_ADDR	0x30
 
 #define HDMI_EDID_LEN		512
@@ -179,7 +180,10 @@
 
 	spinlock_t audio_lock;
 	struct mutex audio_mutex;
+	unsigned int sample_non_pcm;
+	unsigned int sample_width;
 	unsigned int sample_rate;
+	unsigned int channels;
 	unsigned int audio_cts;
 	unsigned int audio_n;
 	bool audio_enable;
@@ -191,6 +195,10 @@
 
 	struct mutex cec_notifier_mutex;
 	struct cec_notifier *cec_notifier;
+
+	hdmi_codec_plugged_cb plugged_cb;
+	struct device *codec_dev;
+	enum drm_connector_status last_connector_result;
 };
 
 #define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -215,6 +223,28 @@
 	return val;
 }
 
+static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged)
+{
+	if (hdmi->plugged_cb && hdmi->codec_dev)
+		hdmi->plugged_cb(hdmi->codec_dev, plugged);
+}
+
+int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
+			   struct device *codec_dev)
+{
+	bool plugged;
+
+	mutex_lock(&hdmi->mutex);
+	hdmi->plugged_cb = fn;
+	hdmi->codec_dev = codec_dev;
+	plugged = hdmi->last_connector_result == connector_status_connected;
+	handle_plugged_change(hdmi, plugged);
+	mutex_unlock(&hdmi->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_plugged_cb);
+
 static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
 {
 	regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
@@ -398,6 +428,15 @@
 	u8 addr = msgs[0].addr;
 	int i, ret = 0;
 
+	if (addr == DDC_CI_ADDR)
+		/*
+		 * The internal I2C controller does not support the multi-byte
+		 * read and write operations needed for DDC/CI.
+		 * TOFIX: Blacklist the DDC/CI address until we filter out
+		 * unsupported I2C operations.
+		 */
+		return -EOPNOTSUPP;
+
 	dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr);
 
 	for (i = 0; i < num; i++) {
@@ -542,6 +581,8 @@
 			n = 4096;
 		else if (pixel_clk == 74176000 || pixel_clk == 148352000)
 			n = 11648;
+		else if (pixel_clk == 297000000)
+			n = 3072;
 		else
 			n = 4096;
 		n *= mult;
@@ -554,6 +595,8 @@
 			n = 17836;
 		else if (pixel_clk == 148352000)
 			n = 8918;
+		else if (pixel_clk == 297000000)
+			n = 4704;
 		else
 			n = 6272;
 		n *= mult;
@@ -568,6 +611,8 @@
 			n = 11648;
 		else if (pixel_clk == 148352000)
 			n = 5824;
+		else if (pixel_clk == 297000000)
+			n = 5120;
 		else
 			n = 6144;
 		n *= mult;
@@ -593,7 +638,7 @@
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
 	/* Only compute CTS when using internal AHB audio */
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) {
 		/*
 		 * Compute the CTS value from the N value.  Note that CTS and N
 		 * can be up to 20 bits in total, so we need 64-bit math.  Also
@@ -635,6 +680,22 @@
 	mutex_unlock(&hdmi->audio_mutex);
 }
 
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_width = width;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
+
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_non_pcm = non_pcm;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
+
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
 {
 	mutex_lock(&hdmi->audio_mutex);
@@ -650,6 +711,7 @@
 	u8 layout;
 
 	mutex_lock(&hdmi->audio_mutex);
+	hdmi->channels = cnt;
 
 	/*
 	 * For >2 channel PCM audio, we need to select layout 1
@@ -690,6 +752,87 @@
 	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
 }
 
+static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
+{
+	int sample_freq = 0x2, org_sample_freq = 0xD;
+	int ch_mask = BIT(hdmi->channels) - 1;
+
+	switch (hdmi->sample_rate) {
+	case 32000:
+		sample_freq = 0x03;
+		org_sample_freq = 0x0C;
+		break;
+	case 44100:
+		sample_freq = 0x00;
+		org_sample_freq = 0x0F;
+		break;
+	case 48000:
+		sample_freq = 0x02;
+		org_sample_freq = 0x0D;
+		break;
+	case 88200:
+		sample_freq = 0x08;
+		org_sample_freq = 0x07;
+		break;
+	case 96000:
+		sample_freq = 0x0A;
+		org_sample_freq = 0x05;
+		break;
+	case 176400:
+		sample_freq = 0x0C;
+		org_sample_freq = 0x03;
+		break;
+	case 192000:
+		sample_freq = 0x0E;
+		org_sample_freq = 0x01;
+		break;
+	default:
+		break;
+        }
+
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
+	hdmi_enable_audio_clk(hdmi, true);
+
+	hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNL0);
+	hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNL2);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNL3);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNL4);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNL5);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNL6);
+	hdmi_writeb(hdmi, (0x3 << 4) | sample_freq, HDMI_FC_AUDSCHNL7);
+	hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb, HDMI_FC_AUDSCHNL8);
+
+	hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
+	hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
+	hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
+
+	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
+
+	/* hbr */
+	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
+	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
+		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
+	}
+
+	if (hdmi->phy.ops->enable_audio)
+		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
+					    hdmi->channels,
+					    hdmi->sample_width,
+					    hdmi->sample_rate,
+					    hdmi->sample_non_pcm);
+}
+
+static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
+{
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
+
+	hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
+	if (hdmi->phy.ops->disable_audio)
+		hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
+
+	hdmi_enable_audio_clk(hdmi, false);
+}
+
 static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
 {
 	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
@@ -1069,6 +1212,14 @@
 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
 	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
 
+	val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
+	if (color_depth == 4)
+		/* disable Auto GCP when bpp 24 */
+		val &= ~0x4;
+	else
+		val |= 0x4;
+	hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
+
 	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
 		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
 
@@ -1268,11 +1419,19 @@
 
 void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
 {
+	/* PHY reset. The reset signal is active high on Gen1 PHYs. */
+	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+
+void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi)
+{
 	/* PHY reset. The reset signal is active high on Gen2 PHYs. */
 	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
 	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
 }
-EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_reset);
 
 void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
 {
@@ -1425,7 +1584,7 @@
 	if (phy->has_svsret)
 		dw_hdmi_phy_enable_svsret(hdmi, 1);
 
-	dw_hdmi_phy_reset(hdmi);
+	dw_hdmi_phy_gen2_reset(hdmi);
 
 	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
 
@@ -1566,28 +1725,34 @@
 		frame.colorspace = HDMI_COLORSPACE_RGB;
 
 	/* Set up colorimetry */
-	switch (hdmi->hdmi_data.enc_out_encoding) {
-	case V4L2_YCBCR_ENC_601:
-		if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
-			frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
-		else
+	if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+		switch (hdmi->hdmi_data.enc_out_encoding) {
+		case V4L2_YCBCR_ENC_601:
+			if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
+				frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+			else
+				frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+			frame.extended_colorimetry =
+					HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+			break;
+		case V4L2_YCBCR_ENC_709:
+			if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
+				frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+			else
+				frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
+			frame.extended_colorimetry =
+					HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+			break;
+		default: /* Carries no data */
 			frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+			frame.extended_colorimetry =
+					HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+			break;
+		}
+	} else {
+		frame.colorimetry = HDMI_COLORIMETRY_NONE;
 		frame.extended_colorimetry =
-				HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
-		break;
-	case V4L2_YCBCR_ENC_709:
-		if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
-			frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
-		else
-			frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
-		frame.extended_colorimetry =
-				HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-		break;
-	default: /* Carries no data */
-		frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
-		frame.extended_colorimetry =
-				HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
-		break;
+			HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
 	}
 
 	frame.scan_mode = HDMI_SCAN_MODE_NONE;
@@ -2023,7 +2188,7 @@
 
 		/* HDMI Initialization Step E - Configure audio */
 		hdmi_clk_regenerator_update_pixel_clock(hdmi);
-		hdmi_enable_audio_clk(hdmi, true);
+		hdmi_enable_audio_clk(hdmi, hdmi->audio_enable);
 	}
 
 	/* not for DVI mode */
@@ -2161,6 +2326,7 @@
 {
 	struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
 					     connector);
+	enum drm_connector_status result;
 
 	mutex_lock(&hdmi->mutex);
 	hdmi->force = DRM_FORCE_UNSPECIFIED;
@@ -2168,7 +2334,18 @@
 	dw_hdmi_update_phy_mask(hdmi);
 	mutex_unlock(&hdmi->mutex);
 
-	return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+	result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+
+	mutex_lock(&hdmi->mutex);
+	if (result != hdmi->last_connector_result) {
+		dev_dbg(hdmi->dev, "read_hpd result: %d", result);
+		handle_plugged_change(hdmi,
+				      result == connector_status_connected);
+		hdmi->last_connector_result = result;
+	}
+	mutex_unlock(&hdmi->mutex);
+
+	return result;
 }
 
 static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -2615,10 +2792,12 @@
 	hdmi->plat_data = plat_data;
 	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
+	hdmi->channels = 2;
 	hdmi->disabled = true;
 	hdmi->rxsense = true;
 	hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
 	hdmi->mc_clkdis = 0x7f;
+	hdmi->last_connector_result = connector_status_disconnected;
 
 	mutex_init(&hdmi->mutex);
 	mutex_init(&hdmi->audio_mutex);
@@ -2829,6 +3008,24 @@
 		pdevinfo.data = &audio;
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
+		struct dw_hdmi_audio_data audio;
+
+		audio.phys = iores->start;
+		audio.base = hdmi->regs;
+		audio.irq = irq;
+		audio.hdmi = hdmi;
+		audio.eld = hdmi->connector.eld;
+
+		hdmi->enable_audio = dw_hdmi_gp_audio_enable;
+		hdmi->disable_audio = dw_hdmi_gp_audio_disable;
+
+		pdevinfo.name = "dw-hdmi-gp-audio";
+		pdevinfo.id = PLATFORM_DEVID_NONE;
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -158,6 +158,17 @@
 #define HDMI_FC_SPDDEVICEINF                    0x1062
 #define HDMI_FC_AUDSCONF                        0x1063
 #define HDMI_FC_AUDSSTAT                        0x1064
+#define HDMI_FC_AUDSV                           0x1065
+#define HDMI_FC_AUDSU                           0x1066
+#define HDMI_FC_AUDSCHNL0                       0x1067
+#define HDMI_FC_AUDSCHNL1                       0x1068
+#define HDMI_FC_AUDSCHNL2                       0x1069
+#define HDMI_FC_AUDSCHNL3                       0x106A
+#define HDMI_FC_AUDSCHNL4                       0x106B
+#define HDMI_FC_AUDSCHNL5                       0x106C
+#define HDMI_FC_AUDSCHNL6                       0x106D
+#define HDMI_FC_AUDSCHNL7                       0x106E
+#define HDMI_FC_AUDSCHNL8                       0x106F
 #define HDMI_FC_DATACH0FILL                     0x1070
 #define HDMI_FC_DATACH1FILL                     0x1071
 #define HDMI_FC_DATACH2FILL                     0x1072
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -365,7 +365,6 @@
 	if (lpm)
 		val |= CMD_MODE_ALL_LP;
 
-	dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
 	dsi_write(dsi, DSI_CMD_MODE_CFG, val);
 }
 
@@ -541,16 +540,22 @@
 static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
 				 unsigned long mode_flags)
 {
+	u32 val;
+
 	dsi_write(dsi, DSI_PWR_UP, RESET);
 
 	if (mode_flags & MIPI_DSI_MODE_VIDEO) {
 		dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
 		dw_mipi_dsi_video_mode_config(dsi);
-		dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
 	} else {
 		dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
 	}
 
+	val = PHY_TXREQUESTCLKHS;
+	if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+		val |= AUTO_CLKLANE_CTRL;
+	dsi_write(dsi, DSI_LPCLK_CTRL, val);
+
 	dsi_write(dsi, DSI_PWR_UP, POWERUP);
 }
 
@@ -1052,6 +1057,7 @@
 	ret = mipi_dsi_host_register(&dsi->dsi_host);
 	if (ret) {
 		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
+		pm_runtime_disable(dev);
 		dw_mipi_dsi_debugfs_remove(dsi);
 		return ERR_PTR(ret);
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/tc358764.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/tc358764.c
@@ -180,7 +180,7 @@
 	if (ret >= 0)
 		le32_to_cpus(val);
 
-	dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
+	dev_dbg(ctx->dev, "read: addr=0x%04x data=0x%08x\n", addr, *val);
 }
 
 static void tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/tc358767.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/tc358767.c
@@ -294,7 +294,7 @@
 
 static int tc_aux_wait_busy(struct tc_data *tc)
 {
-	return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 100000);
+	return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 100, 100000);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -637,7 +637,7 @@
 	if (ret)
 		goto err;
 
-	ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+	ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 100, 100000);
 	if (ret == -ETIMEDOUT) {
 		dev_err(tc->dev, "Timeout waiting for PHY to become ready");
 		return ret;
@@ -861,7 +861,7 @@
 	int ret;
 
 	ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
-			      LT_LOOPDONE, 1, 1000);
+			      LT_LOOPDONE, 500, 100000);
 	if (ret) {
 		dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
 		return ret;
@@ -934,7 +934,7 @@
 	dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
 	ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
 
-	ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+	ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 500, 100000);
 	if (ret) {
 		dev_err(dev, "timeout waiting for phy become ready");
 		return ret;
@@ -1574,7 +1574,7 @@
 	} else {
 		if (tc->hpd_pin < 0 || tc->hpd_pin > 1) {
 			dev_err(dev, "failed to parse HPD number\n");
-			return ret;
+			return -EINVAL;
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ linux-ein-5.4.0/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -115,6 +115,7 @@
 	.val_bits = 8,
 	.volatile_table = &ti_sn_bridge_volatile_table,
 	.cache_type = REGCACHE_NONE,
+	.max_register = 0xFF,
 };
 
 static void ti_sn_bridge_write_u16(struct ti_sn_bridge *pdata,
@@ -459,9 +460,9 @@
 		&pdata->bridge.encoder->crtc->state->adjusted_mode;
 	u8 hsync_polarity = 0, vsync_polarity = 0;
 
-	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 		hsync_polarity = CHA_HSYNC_POLARITY;
-	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 		vsync_polarity = CHA_VSYNC_POLARITY;
 
 	ti_sn_bridge_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
@@ -647,6 +648,12 @@
 				     buf[i]);
 	}
 
+	/* Clear old status bits before start so we don't get confused */
+	regmap_write(pdata->regmap, SN_AUX_CMD_STATUS_REG,
+		     AUX_IRQ_STATUS_NAT_I2C_FAIL |
+		     AUX_IRQ_STATUS_AUX_RPLY_TOUT |
+		     AUX_IRQ_STATUS_AUX_SHORT);
+
 	regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND);
 
 	ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_atomic.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_atomic.c
@@ -97,6 +97,12 @@
 	if (!state->planes)
 		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_get(dev);
 	state->dev = dev;
 
 	DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
@@ -256,7 +262,8 @@
 void __drm_atomic_state_free(struct kref *ref)
 {
 	struct drm_atomic_state *state = container_of(ref, typeof(*state), ref);
-	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_device *dev = state->dev;
+	struct drm_mode_config *config = &dev->mode_config;
 
 	drm_atomic_state_clear(state);
 
@@ -268,6 +275,8 @@
 		drm_atomic_state_default_release(state);
 		kfree(state);
 	}
+
+	drm_dev_put(dev);
 }
 EXPORT_SYMBOL(__drm_atomic_state_free);
 
@@ -1006,6 +1015,7 @@
 	drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
 	drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
 	drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
+	drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
 
 	if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
 		if (state->writeback_job && state->writeback_job->fb)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_atomic_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_atomic_helper.c
@@ -445,8 +445,9 @@
 		encoder = new_conn_state->best_encoder;
 		funcs = encoder->helper_private;
 
-		ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode,
-				&new_crtc_state->adjusted_mode);
+		ret = drm_bridge_chain_mode_fixup(encoder->bridge,
+					&new_crtc_state->mode,
+					&new_crtc_state->adjusted_mode);
 		if (!ret) {
 			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
 			return -EINVAL;
@@ -511,7 +512,7 @@
 		return ret;
 	}
 
-	ret = drm_bridge_mode_valid(encoder->bridge, mode);
+	ret = drm_bridge_chain_mode_valid(encoder->bridge, mode);
 	if (ret != MODE_OK) {
 		DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
 		return ret;
@@ -588,6 +589,7 @@
  * &drm_crtc_state.connectors_changed is set when a connector is added or
  * removed from the crtc.  &drm_crtc_state.active_changed is set when
  * &drm_crtc_state.active changes, which is used for DPMS.
+ * &drm_crtc_state.no_vblank is set from the result of drm_dev_has_vblank().
  * See also: drm_atomic_crtc_needs_modeset()
  *
  * IMPORTANT:
@@ -654,6 +656,11 @@
 
 			return -EINVAL;
 		}
+
+		if (drm_dev_has_vblank(dev))
+			new_crtc_state->no_vblank = false;
+		else
+			new_crtc_state->no_vblank = true;
 	}
 
 	ret = handle_conflicting_encoders(state, false);
@@ -1030,7 +1037,7 @@
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call disable hooks twice.
 		 */
-		drm_atomic_bridge_disable(encoder->bridge, old_state);
+		drm_atomic_bridge_chain_disable(encoder->bridge, old_state);
 
 		/* Right function depends upon target state. */
 		if (funcs) {
@@ -1044,7 +1051,8 @@
 				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
 		}
 
-		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
+		drm_atomic_bridge_chain_post_disable(encoder->bridge,
+						     old_state);
 	}
 
 	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -1078,7 +1086,16 @@
 			continue;
 
 		ret = drm_crtc_vblank_get(crtc);
-		WARN_ONCE(ret != -EINVAL, "driver forgot to call drm_crtc_vblank_off()\n");
+		/*
+		 * Self-refresh is not a true "disable"; ensure vblank remains
+		 * enabled.
+		 */
+		if (new_crtc_state->self_refresh_active)
+			WARN_ONCE(ret != 0,
+				  "driver disabled vblank in self-refresh\n");
+		else
+			WARN_ONCE(ret != -EINVAL,
+				  "driver forgot to call drm_crtc_vblank_off()\n");
 		if (ret == 0)
 			drm_crtc_vblank_put(crtc);
 	}
@@ -1225,7 +1242,8 @@
 			funcs->mode_set(encoder, mode, adjusted_mode);
 		}
 
-		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
+		drm_bridge_chain_mode_set(encoder->bridge, mode,
+					  adjusted_mode);
 	}
 }
 
@@ -1342,7 +1360,7 @@
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call enable hooks twice.
 		 */
-		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
+		drm_atomic_bridge_chain_pre_enable(encoder->bridge, old_state);
 
 		if (funcs) {
 			if (funcs->atomic_enable)
@@ -1353,7 +1371,7 @@
 				funcs->commit(encoder);
 		}
 
-		drm_atomic_bridge_enable(encoder->bridge, old_state);
+		drm_atomic_bridge_chain_enable(encoder->bridge, old_state);
 	}
 
 	drm_atomic_helper_commit_writebacks(dev, old_state);
@@ -2202,7 +2220,9 @@
  * when a job is queued, and any change to the pipeline that does not touch the
  * connector is leading to timeouts when calling
  * drm_atomic_helper_wait_for_vblanks() or
- * drm_atomic_helper_wait_for_flip_done().
+ * drm_atomic_helper_wait_for_flip_done(). In addition to writeback
+ * connectors, this function can also fake VBLANK events for CRTCs without
+ * VBLANK interrupt.
  *
  * This is part of the atomic helper support for nonblocking commits, see
  * drm_atomic_helper_setup_commit() for an overview.
@@ -2948,7 +2968,7 @@
 
 	ret = handle_conflicting_encoders(state, true);
 	if (ret)
-		return ret;
+		goto fail;
 
 	ret = drm_atomic_commit(state);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_atomic_uapi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_atomic_uapi.c
@@ -75,15 +75,17 @@
 	state->mode_blob = NULL;
 
 	if (mode) {
+		struct drm_property_blob *blob;
+
 		drm_mode_convert_to_umode(&umode, mode);
-		state->mode_blob =
-			drm_property_create_blob(state->crtc->dev,
-		                                 sizeof(umode),
-		                                 &umode);
-		if (IS_ERR(state->mode_blob))
-			return PTR_ERR(state->mode_blob);
+		blob = drm_property_create_blob(crtc->dev,
+						sizeof(umode), &umode);
+		if (IS_ERR(blob))
+			return PTR_ERR(blob);
 
 		drm_mode_copy(&state->mode, mode);
+
+		state->mode_blob = blob;
 		state->enable = true;
 		DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
 				 mode->name, crtc->base.id, crtc->name, state);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_auth.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_auth.c
@@ -268,9 +268,10 @@
 void drm_master_release(struct drm_file *file_priv)
 {
 	struct drm_device *dev = file_priv->minor->dev;
-	struct drm_master *master = file_priv->master;
+	struct drm_master *master;
 
 	mutex_lock(&dev->master_mutex);
+	master = file_priv->master;
 	if (file_priv->magic)
 		idr_remove(&file_priv->master->magic_map, file_priv->magic);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_bridge.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_bridge.c
@@ -172,8 +172,8 @@
  */
 
 /**
- * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the
- *			   encoder chain
+ * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
+ *				 encoder chain
  * @bridge: bridge control structure
  * @mode: desired mode to be set for the bridge
  * @adjusted_mode: updated mode that works for this bridge
@@ -186,9 +186,9 @@
  * RETURNS:
  * true on success, false on failure
  */
-bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
-			const struct drm_display_mode *mode,
-			struct drm_display_mode *adjusted_mode)
+bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
 {
 	bool ret = true;
 
@@ -198,15 +198,16 @@
 	if (bridge->funcs->mode_fixup)
 		ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode);
 
-	ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode);
+	ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode,
+						 adjusted_mode);
 
 	return ret;
 }
-EXPORT_SYMBOL(drm_bridge_mode_fixup);
+EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
 
 /**
- * drm_bridge_mode_valid - validate the mode against all bridges in the
- * 			   encoder chain.
+ * drm_bridge_chain_mode_valid - validate the mode against all bridges in the
+ *				 encoder chain.
  * @bridge: bridge control structure
  * @mode: desired mode to be validated
  *
@@ -219,8 +220,9 @@
  * RETURNS:
  * MODE_OK on success, drm_mode_status Enum error code on failure
  */
-enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
-					   const struct drm_display_mode *mode)
+enum drm_mode_status
+drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
+			    const struct drm_display_mode *mode)
 {
 	enum drm_mode_status ret = MODE_OK;
 
@@ -233,12 +235,12 @@
 	if (ret != MODE_OK)
 		return ret;
 
-	return drm_bridge_mode_valid(bridge->next, mode);
+	return drm_bridge_chain_mode_valid(bridge->next, mode);
 }
-EXPORT_SYMBOL(drm_bridge_mode_valid);
+EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
 
 /**
- * drm_bridge_disable - disables all bridges in the encoder chain
+ * drm_bridge_chain_disable - disables all bridges in the encoder chain
  * @bridge: bridge control structure
  *
  * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
@@ -247,20 +249,21 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_bridge_disable(struct drm_bridge *bridge)
+void drm_bridge_chain_disable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
 
-	drm_bridge_disable(bridge->next);
+	drm_bridge_chain_disable(bridge->next);
 
 	if (bridge->funcs->disable)
 		bridge->funcs->disable(bridge);
 }
-EXPORT_SYMBOL(drm_bridge_disable);
+EXPORT_SYMBOL(drm_bridge_chain_disable);
 
 /**
- * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain
+ * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
+ *				   encoder chain
  * @bridge: bridge control structure
  *
  * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
@@ -269,7 +272,7 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_bridge_post_disable(struct drm_bridge *bridge)
+void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -277,25 +280,25 @@
 	if (bridge->funcs->post_disable)
 		bridge->funcs->post_disable(bridge);
 
-	drm_bridge_post_disable(bridge->next);
+	drm_bridge_chain_post_disable(bridge->next);
 }
-EXPORT_SYMBOL(drm_bridge_post_disable);
+EXPORT_SYMBOL(drm_bridge_chain_post_disable);
 
 /**
- * drm_bridge_mode_set - set proposed mode for all bridges in the
- *			 encoder chain
+ * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
+ *			       encoder chain
  * @bridge: bridge control structure
- * @mode: desired mode to be set for the bridge
- * @adjusted_mode: updated mode that works for this bridge
+ * @mode: desired mode to be set for the encoder chain
+ * @adjusted_mode: updated mode that works for this encoder chain
  *
  * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
  * encoder chain, starting from the first bridge to the last.
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_bridge_mode_set(struct drm_bridge *bridge,
-			 const struct drm_display_mode *mode,
-			 const struct drm_display_mode *adjusted_mode)
+void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
+			       const struct drm_display_mode *mode,
+			       const struct drm_display_mode *adjusted_mode)
 {
 	if (!bridge)
 		return;
@@ -303,13 +306,13 @@
 	if (bridge->funcs->mode_set)
 		bridge->funcs->mode_set(bridge, mode, adjusted_mode);
 
-	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
+	drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode);
 }
-EXPORT_SYMBOL(drm_bridge_mode_set);
+EXPORT_SYMBOL(drm_bridge_chain_mode_set);
 
 /**
- * drm_bridge_pre_enable - prepares for enabling all
- *			   bridges in the encoder chain
+ * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
+ *				 encoder chain
  * @bridge: bridge control structure
  *
  * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
@@ -318,20 +321,20 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_bridge_pre_enable(struct drm_bridge *bridge)
+void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
 
-	drm_bridge_pre_enable(bridge->next);
+	drm_bridge_chain_pre_enable(bridge->next);
 
 	if (bridge->funcs->pre_enable)
 		bridge->funcs->pre_enable(bridge);
 }
-EXPORT_SYMBOL(drm_bridge_pre_enable);
+EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
 
 /**
- * drm_bridge_enable - enables all bridges in the encoder chain
+ * drm_bridge_chain_enable - enables all bridges in the encoder chain
  * @bridge: bridge control structure
  *
  * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
@@ -340,7 +343,7 @@
  *
  * Note that the bridge passed should be the one closest to the encoder
  */
-void drm_bridge_enable(struct drm_bridge *bridge)
+void drm_bridge_chain_enable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -348,12 +351,12 @@
 	if (bridge->funcs->enable)
 		bridge->funcs->enable(bridge);
 
-	drm_bridge_enable(bridge->next);
+	drm_bridge_chain_enable(bridge->next);
 }
-EXPORT_SYMBOL(drm_bridge_enable);
+EXPORT_SYMBOL(drm_bridge_chain_enable);
 
 /**
- * drm_atomic_bridge_disable - disables all bridges in the encoder chain
+ * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
  * @bridge: bridge control structure
  * @state: atomic state being committed
  *
@@ -364,24 +367,24 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_atomic_bridge_disable(struct drm_bridge *bridge,
-			       struct drm_atomic_state *state)
+void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
+				     struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
 
-	drm_atomic_bridge_disable(bridge->next, state);
+	drm_atomic_bridge_chain_disable(bridge->next, state);
 
 	if (bridge->funcs->atomic_disable)
 		bridge->funcs->atomic_disable(bridge, state);
 	else if (bridge->funcs->disable)
 		bridge->funcs->disable(bridge);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_disable);
+EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 
 /**
- * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the
- *				    encoder chain
+ * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
+ *					  in the encoder chain
  * @bridge: bridge control structure
  * @state: atomic state being committed
  *
@@ -392,8 +395,8 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
-				    struct drm_atomic_state *state)
+void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
+					  struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -403,13 +406,13 @@
 	else if (bridge->funcs->post_disable)
 		bridge->funcs->post_disable(bridge);
 
-	drm_atomic_bridge_post_disable(bridge->next, state);
+	drm_atomic_bridge_chain_post_disable(bridge->next, state);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_post_disable);
+EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
 
 /**
- * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the
- *				  encoder chain
+ * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
+ *					the encoder chain
  * @bridge: bridge control structure
  * @state: atomic state being committed
  *
@@ -420,23 +423,23 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
-				  struct drm_atomic_state *state)
+void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
+					struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
 
-	drm_atomic_bridge_pre_enable(bridge->next, state);
+	drm_atomic_bridge_chain_pre_enable(bridge->next, state);
 
 	if (bridge->funcs->atomic_pre_enable)
 		bridge->funcs->atomic_pre_enable(bridge, state);
 	else if (bridge->funcs->pre_enable)
 		bridge->funcs->pre_enable(bridge);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_pre_enable);
+EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
 
 /**
- * drm_atomic_bridge_enable - enables all bridges in the encoder chain
+ * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
  * @bridge: bridge control structure
  * @state: atomic state being committed
  *
@@ -447,8 +450,8 @@
  *
  * Note: the bridge passed should be the one closest to the encoder
  */
-void drm_atomic_bridge_enable(struct drm_bridge *bridge,
-			      struct drm_atomic_state *state)
+void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
+				    struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -458,9 +461,9 @@
 	else if (bridge->funcs->enable)
 		bridge->funcs->enable(bridge);
 
-	drm_atomic_bridge_enable(bridge->next, state);
+	drm_atomic_bridge_chain_enable(bridge->next, state);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_enable);
+EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
 #ifdef CONFIG_OF
 /**
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_client_modeset.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_client_modeset.c
@@ -281,6 +281,9 @@
 	can_clone = true;
 	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
 
+	if (!dmt_mode)
+		goto fail;
+
 	for (i = 0; i < connector_count; i++) {
 		if (!enabled[i])
 			continue;
@@ -296,11 +299,13 @@
 		if (!modes[i])
 			can_clone = false;
 	}
+	kfree(dmt_mode);
 
 	if (can_clone) {
 		DRM_DEBUG_KMS("can clone using 1024x768\n");
 		return true;
 	}
+fail:
 	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
 	return false;
 }
@@ -785,6 +790,7 @@
 				break;
 			}
 
+			kfree(modeset->mode);
 			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
 			modeset->connectors[modeset->num_connectors++] = connector;
@@ -880,7 +886,8 @@
 	 * depending on the hardware this may require the framebuffer
 	 * to be in a specific tiling format.
 	 */
-	if ((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180 ||
+	if (((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0 &&
+	     (*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180) ||
 	    !plane->rotation_property)
 		return false;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_connector.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_connector.c
@@ -27,6 +27,7 @@
 #include <drm/drm_print.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
+#include <drm/drm_sysfs.h>
 
 #include <linux/uaccess.h>
 
@@ -473,6 +474,9 @@
 	mutex_destroy(&connector->mutex);
 
 	memset(connector, 0, sizeof(*connector));
+
+	if (dev->registered)
+		drm_sysfs_hotplug_event(dev);
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -511,6 +515,10 @@
 	drm_mode_object_register(connector->dev, &connector->base);
 
 	connector->registration_state = DRM_CONNECTOR_REGISTERED;
+
+	/* Let userspace know we have a new connector */
+	drm_sysfs_hotplug_event(connector->dev);
+
 	goto unlock;
 
 err_debugfs:
@@ -1979,6 +1987,9 @@
 void drm_connector_set_vrr_capable_property(
 		struct drm_connector *connector, bool capable)
 {
+	if (!connector->vrr_capable_property)
+		return;
+
 	drm_object_property_set_value(&connector->base,
 				      connector->vrr_capable_property,
 				      capable);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_crtc.c
@@ -535,8 +535,7 @@
 	struct drm_mode_set set;
 	uint32_t __user *set_connectors_ptr;
 	struct drm_modeset_acquire_ctx ctx;
-	int ret;
-	int i;
+	int ret, i, num_connectors = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EOPNOTSUPP;
@@ -694,6 +693,7 @@
 					connector->name);
 
 			connector_set[i] = connector;
+			num_connectors++;
 		}
 	}
 
@@ -702,7 +702,7 @@
 	set.y = crtc_req->y;
 	set.mode = mode;
 	set.connectors = connector_set;
-	set.num_connectors = crtc_req->count_connectors;
+	set.num_connectors = num_connectors;
 	set.fb = fb;
 
 	if (drm_drv_uses_atomic_modeset(dev))
@@ -715,7 +715,7 @@
 		drm_framebuffer_put(fb);
 
 	if (connector_set) {
-		for (i = 0; i < crtc_req->count_connectors; i++) {
+		for (i = 0; i < num_connectors; i++) {
 			if (connector_set[i])
 				drm_connector_put(connector_set[i]);
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_crtc_helper_internal.h
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_crtc_helper_internal.h
@@ -32,16 +32,6 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_modes.h>
 
-/* drm_fb_helper.c */
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-int drm_fb_helper_modinit(void);
-#else
-static inline int drm_fb_helper_modinit(void)
-{
-	return 0;
-}
-#endif
-
 /* drm_dp_aux_dev.c */
 #ifdef CONFIG_DRM_DP_AUX_CHARDEV
 int drm_dp_aux_dev_init(void);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_crtc_internal.h
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_crtc_internal.h
@@ -216,6 +216,8 @@
 			void *data, struct drm_file *file_priv);
 int drm_mode_getfb(struct drm_device *dev,
 		   void *data, struct drm_file *file_priv);
+int drm_mode_getfb2_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv);
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 			   void *data, struct drm_file *file_priv);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_damage_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_damage_helper.c
@@ -212,8 +212,14 @@
 	drm_for_each_plane(plane, fb->dev) {
 		struct drm_plane_state *plane_state;
 
-		if (plane->state->fb != fb)
+		ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
+		if (ret)
+			goto out;
+
+		if (plane->state->fb != fb) {
+			drm_modeset_unlock(&plane->mutex);
 			continue;
+		}
 
 		plane_state = drm_atomic_get_plane_state(state, plane);
 		if (IS_ERR(plane_state)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_debugfs.c
@@ -91,6 +91,7 @@
 	mutex_lock(&dev->filelist_mutex);
 	list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
 		struct task_struct *task;
+		bool is_current_master = drm_is_current_master(priv);
 
 		rcu_read_lock(); /* locks pid_task()->comm */
 		task = pid_task(priv->pid, PIDTYPE_PID);
@@ -99,7 +100,7 @@
 			   task ? task->comm : "<unknown>",
 			   pid_vnr(priv->pid),
 			   priv->minor->index,
-			   drm_is_current_master(priv) ? 'y' : 'n',
+			   is_current_master ? 'y' : 'n',
 			   priv->authenticated ? 'y' : 'n',
 			   from_kuid_munged(seq_user_ns(m), uid),
 			   priv->magic);
@@ -337,13 +338,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-ein-5.4.0.orig/drivers/gpu/drm/drm_debugfs_crc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_debugfs_crc.c
@@ -140,12 +140,14 @@
 	if (IS_ERR(source))
 		return PTR_ERR(source);
 
-	if (source[len] == '\n')
-		source[len] = '\0';
+	if (source[len - 1] == '\n')
+		source[len - 1] = '\0';
 
 	ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt);
-	if (ret)
+	if (ret) {
+		kfree(source);
 		return ret;
+	}
 
 	spin_lock_irq(&crc->lock);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_dp_aux_dev.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_dp_aux_dev.c
@@ -63,7 +63,7 @@
 
 	mutex_lock(&aux_idr_mutex);
 	aux_dev = idr_find(&aux_idr, index);
-	if (!kref_get_unless_zero(&aux_dev->refcount))
+	if (aux_dev && !kref_get_unless_zero(&aux_dev->refcount))
 		aux_dev = NULL;
 	mutex_unlock(&aux_idr_mutex);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_dp_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_dp_helper.c
@@ -1302,6 +1302,99 @@
 #undef DEVICE_ID_ANY
 #undef DEVICE_ID
 
+struct edid_quirk {
+	u8 mfg_id[2];
+	u8 prod_id[2];
+	u32 quirks;
+};
+
+#define MFG(first, second) { (first), (second) }
+#define PROD_ID(first, second) { (first), (second) }
+
+/*
+ * Some devices have unreliable OUIDs where they don't set the device ID
+ * correctly, and as a result we need to use the EDID for finding additional
+ * DP quirks in such cases.
+ */
+static const struct edid_quirk edid_quirk_list[] = {
+	/* Optional 4K AMOLED panel in the ThinkPad X1 Extreme 2nd Generation
+	 * only supports DPCD backlight controls
+	 */
+	{ MFG(0x4c, 0x83), PROD_ID(0x41, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	/* HP Spectre x360 Convertible 13t-aw100 */
+	{ MFG(0x4c, 0x83), PROD_ID(0x42, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	/* HP CML 2020 system */
+	{ MFG(0x4c, 0x83), PROD_ID(0x45, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	/*
+	 * Some Dell CML 2020 systems have panels support both AUX and PWM
+	 * backlight control, and some only support AUX backlight control. All
+	 * said panels start up in AUX mode by default, and we don't have any
+	 * support for disabling HDR mode on these panels which would be
+	 * required to switch to PWM backlight control mode (plus, I'm not
+	 * even sure we want PWM backlight controls over DPCD backlight
+	 * controls anyway...). Until we have a better way of detecting these,
+	 * force DPCD backlight mode on all of them.
+	 */
+	{ MFG(0x06, 0xaf), PROD_ID(0x8c, 0xcd), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x06, 0xaf), PROD_ID(0x9b, 0x32), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x06, 0xaf), PROD_ID(0xeb, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x30, 0xe4), PROD_ID(0x61, 0x06), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x4d, 0x10), PROD_ID(0xc7, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x4d, 0x10), PROD_ID(0xe6, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x4c, 0x83), PROD_ID(0x47, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x4c, 0x83), PROD_ID(0x4f, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	{ MFG(0x4c, 0x83), PROD_ID(0x4d, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
+	/*
+	 * Some HP ZBook Studio G7 systems have panels support and relies on
+	 * PSR being enabled.
+	 */
+	{ MFG(0x0d, 0xae), PROD_ID(0x19, 0x15), BIT(DP_QUIRK_FORCE_PSR_CHIP_DEFAULT) },
+};
+
+#undef MFG
+#undef PROD_ID
+
+/**
+ * drm_dp_get_edid_quirks() - Check the EDID of a DP device to find additional
+ * DP-specific quirks
+ * @edid: The EDID to check
+ *
+ * While OUIDs are meant to be used to recognize a DisplayPort device, a lot
+ * of manufacturers don't seem to like following standards and neglect to fill
+ * the dev-ID in, making it impossible to only use OUIDs for determining
+ * quirks in some cases. This function can be used to check the EDID and look
+ * up any additional DP quirks. The bits returned by this function correspond
+ * to the quirk bits in &drm_dp_quirk.
+ *
+ * Returns: a bitmask of quirks, if any. The driver can check this using
+ * drm_dp_has_quirk().
+ */
+u32 drm_dp_get_edid_quirks(const struct edid *edid)
+{
+	const struct edid_quirk *quirk;
+	u32 quirks = 0;
+	int i;
+
+	if (!edid)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
+		quirk = &edid_quirk_list[i];
+		if (memcmp(quirk->mfg_id, edid->mfg_id,
+			   sizeof(edid->mfg_id)) == 0 &&
+		    memcmp(quirk->prod_id, edid->prod_code,
+			   sizeof(edid->prod_code)) == 0)
+			quirks |= quirk->quirks;
+	}
+
+	DRM_DEBUG_KMS("DP sink: EDID mfg %*phD prod-ID %*phD quirks: 0x%04x\n",
+		      (int)sizeof(edid->mfg_id), edid->mfg_id,
+		      (int)sizeof(edid->prod_code), edid->prod_code, quirks);
+
+	return quirks;
+}
+EXPORT_SYMBOL(drm_dp_get_edid_quirks);
+
 /**
  * drm_dp_read_desc - read sink/branch descriptor from DPCD
  * @aux: DisplayPort AUX channel
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_dp_mst_topology.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
+#include <linux/iopoll.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -339,7 +340,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++;
 		}
@@ -1805,14 +1806,14 @@
 	struct drm_dp_mst_branch *found_mstb;
 	struct drm_dp_mst_port *port;
 
+	if (!mstb)
+		return NULL;
+
 	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)
@@ -2465,9 +2466,11 @@
 			drm_dp_mst_topology_put_port(port);
 	}
 
-	for (i = 0; i < mgr->max_payloads; i++) {
-		if (mgr->payloads[i].payload_state != DP_PAYLOAD_DELETE_LOCAL)
+	for (i = 0; i < mgr->max_payloads; /* do nothing */) {
+		if (mgr->payloads[i].payload_state != DP_PAYLOAD_DELETE_LOCAL) {
+			i++;
 			continue;
+		}
 
 		DRM_DEBUG_KMS("removing payload %d\n", i);
 		for (j = i; j < mgr->max_payloads - 1; j++) {
@@ -2694,6 +2697,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;
@@ -2752,7 +2756,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;
@@ -2760,6 +2767,7 @@
 
 out_unlock:
 	mutex_unlock(&mgr->lock);
+	mutex_unlock(&mgr->payload_lock);
 	if (mstb)
 		drm_dp_mst_topology_put_mstb(mstb);
 	return ret;
@@ -3361,11 +3369,11 @@
 {
 	int ret;
 
-	port = drm_dp_mst_topology_get_port_validated(mgr, port);
-	if (!port)
+	if (slots < 0)
 		return false;
 
-	if (slots < 0)
+	port = drm_dp_mst_topology_get_port_validated(mgr, port);
+	if (!port)
 		return false;
 
 	if (port->vcpi.vcpi > 0) {
@@ -3381,6 +3389,7 @@
 	if (ret) {
 		DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n",
 			      DIV_ROUND_UP(pbn, mgr->pbn_div), ret);
+		drm_dp_mst_topology_put_port(port);
 		goto out;
 	}
 	DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n",
@@ -3491,6 +3500,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.
@@ -3500,33 +3520,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);
 
@@ -3641,6 +3657,7 @@
 
 	mst_edid = drm_dp_mst_get_edid(port->connector, mgr, port);
 	drm_edid_get_monitor_name(mst_edid, name, namelen);
+	kfree(mst_edid);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_drv.c
@@ -984,8 +984,11 @@
 			goto err_minors;
 	}
 
-	if (drm_core_check_feature(dev, DRIVER_MODESET))
-		drm_modeset_register_all(dev);
+	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		ret = drm_modeset_register_all(dev);
+		if (ret)
+			goto err_unload;
+	}
 
 	ret = 0;
 
@@ -997,6 +1000,9 @@
 
 	goto out_unlock;
 
+err_unload:
+	if (dev->driver->unload)
+		dev->driver->unload(dev);
 err_minors:
 	remove_compat_control_link(dev);
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_edid.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_edid.c
@@ -191,10 +191,11 @@
 	{ "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
 	{ "HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP },
 
-	/* Oculus Rift DK1, DK2, and CV1 VR Headsets */
+	/* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
 	{ "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
 	{ "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
 	{ "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
+	{ "OVR", 0x0012, EDID_QUIRK_NON_DESKTOP },
 
 	/* Windows Mixed Reality Headsets */
 	{ "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
@@ -574,6 +575,22 @@
 	{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 556188, 4096, 4104,
 		   4136, 4176, 0, 2160, 2208, 2216, 2222, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 3 - 720x480@60Hz */
+	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
+		   798, 858, 0, 480, 489, 495, 525, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 16 - 1920x1080@60Hz */
+	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 19 - 1280x720@50Hz */
+	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
+		   1760, 1980, 0, 720, 725, 730, 750, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 31 - 1920x1080@50Hz */
+	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
+		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
 
 /*
@@ -1701,9 +1718,6 @@
 
 		connector_bad_edid(connector, edid, edid[0x7e] + 1);
 
-		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
-		edid[0x7e] = valid_extensions;
-
 		new = kmalloc_array(valid_extensions + 1, EDID_LENGTH,
 				    GFP_KERNEL);
 		if (!new)
@@ -1720,6 +1734,9 @@
 			base += EDID_LENGTH;
 		}
 
+		new[EDID_LENGTH - 1] += new[0x7e] - valid_extensions;
+		new[0x7e] = valid_extensions;
+
 		kfree(edid);
 		edid = new;
 	}
@@ -2770,7 +2787,7 @@
 	const u8 empty[3] = { 0, 0, 0 };
 
 	for (i = 0; i < 4; i++) {
-		int uninitialized_var(width), height;
+		int width, height;
 		cvt = &(timing->data.other_data.data.cvt[i]);
 
 		if (!memcmp(cvt->code, empty, 3))
@@ -2778,6 +2795,8 @@
 
 		height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
 		switch (cvt->code[1] & 0x0c) {
+		/* default - because compiler doesn't see that we've enumerated all cases */
+		default:
 		case 0x00:
 			width = height * 4 / 3;
 			break;
@@ -3722,7 +3741,7 @@
 		if (*end < 4 || *end > 127)
 			return -ERANGE;
 	} else {
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
 
 	return 0;
@@ -4191,7 +4210,7 @@
 
 	if (cea_revision(cea) < 3) {
 		DRM_DEBUG_KMS("SAD: wrong CEA revision\n");
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
 
 	if (cea_db_offsets(cea, &start, &end)) {
@@ -4252,7 +4271,7 @@
 
 	if (cea_revision(cea) < 3) {
 		DRM_DEBUG_KMS("SAD: wrong CEA revision\n");
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
 
 	if (cea_db_offsets(cea, &start, &end)) {
@@ -4379,7 +4398,8 @@
 	if (!edid_ext)
 		goto end;
 
-	has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0);
+	has_audio = (edid_ext[0] == CEA_EXT &&
+		    (edid_ext[3] & EDID_BASIC_AUDIO) != 0);
 
 	if (has_audio) {
 		DRM_DEBUG_KMS("Monitor has basic audio support\n");
@@ -4532,16 +4552,8 @@
 		  connector->name, dc_bpc);
 	info->bpc = dc_bpc;
 
-	/*
-	 * Deep color support mandates RGB444 support for all video
-	 * modes and forbids YCRCB422 support for all video modes per
-	 * HDMI 1.3 spec.
-	 */
-	info->color_formats = DRM_COLOR_FORMAT_RGB444;
-
 	/* YCRCB444 is optional according to spec. */
 	if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
-		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 		DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
 			  connector->name);
 	}
@@ -4658,6 +4670,7 @@
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
 		return quirks;
 
+	info->color_formats |= DRM_COLOR_FORMAT_RGB444;
 	drm_parse_cea_ext(connector, edid);
 
 	/*
@@ -4706,7 +4719,6 @@
 	DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
 			  connector->name, info->bpc);
 
-	info->color_formats |= DRM_COLOR_FORMAT_RGB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
@@ -4743,7 +4755,7 @@
 	struct drm_display_mode *mode;
 	unsigned pixel_clock = (timings->pixel_clock[0] |
 				(timings->pixel_clock[1] << 8) |
-				(timings->pixel_clock[2] << 16));
+				(timings->pixel_clock[2] << 16)) + 1;
 	unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
 	unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1;
 	unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_encoder.c
@@ -170,7 +170,7 @@
 		struct drm_bridge *next;
 
 		while (bridge) {
-			next = bridge->next;
+			next = drm_bridge_get_next_bridge(bridge);
 			drm_bridge_detach(bridge);
 			bridge = next;
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_encoder_slave.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/gpu/drm/drm_fb_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_fb_helper.c
@@ -390,7 +390,11 @@
 	unsigned int y;
 
 	for (y = clip->y1; y < clip->y2; y++) {
-		memcpy(dst, src, len);
+		if (!fb_helper->dev->mode_config.fbdev_use_iomem)
+			memcpy(dst, src, len);
+		else
+			memcpy_toio((void __iomem *)dst, src, len);
+
 		src += fb->pitches[0];
 		dst += fb->pitches[0];
 	}
@@ -961,11 +965,15 @@
 	drm_modeset_lock_all(fb_helper->dev);
 	drm_client_for_each_modeset(modeset, &fb_helper->client) {
 		crtc = modeset->crtc;
-		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
-			return -EINVAL;
+		if (!crtc->funcs->gamma_set || !crtc->gamma_size) {
+			ret = -EINVAL;
+			goto out;
+		}
 
-		if (cmap->start + cmap->len > crtc->gamma_size)
-			return -EINVAL;
+		if (cmap->start + cmap->len > crtc->gamma_size) {
+			ret = -EINVAL;
+			goto out;
+		}
 
 		r = crtc->gamma_store;
 		g = r + crtc->gamma_size;
@@ -978,8 +986,9 @@
 		ret = crtc->funcs->gamma_set(crtc, r, g, b,
 					     crtc->gamma_size, NULL);
 		if (ret)
-			return ret;
+			goto out;
 	}
+out:
 	drm_modeset_unlock_all(fb_helper->dev);
 
 	return ret;
@@ -1320,7 +1329,7 @@
 	 * Changes struct fb_var_screeninfo are currently not pushed back
 	 * to KMS, hence fail if different settings are requested.
 	 */
-	if (var->bits_per_pixel != fb->format->cpp[0] * 8 ||
+	if (var->bits_per_pixel > fb->format->cpp[0] * 8 ||
 	    var->xres > fb->width || var->yres > fb->height ||
 	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
 		DRM_DEBUG("fb requested width/height/bpp can't fit in current fb "
@@ -1331,6 +1340,9 @@
 		return -EINVAL;
 	}
 
+	var->xres_virtual = fb->width;
+	var->yres_virtual = fb->height;
+
 	/*
 	 * Workaround for SDL 1.2, which is known to be setting all pixel format
 	 * fields values to zero in some cases. We treat this situation as a
@@ -1346,6 +1358,11 @@
 	}
 
 	/*
+	 * Likewise, bits_per_pixel should be rounded up to a supported value.
+	 */
+	var->bits_per_pixel = fb->format->cpp[0] * 8;
+
+	/*
 	 * drm fbdev emulation doesn't support changing the pixel format at all,
 	 * so reject all pixel format changing requests.
 	 */
@@ -2401,24 +2418,3 @@
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbdev_generic_setup);
-
-/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
- * 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.
- */
-int __init drm_fb_helper_modinit(void)
-{
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
-	const char name[] = "fbcon";
-	struct module *fbcon;
-
-	mutex_lock(&module_mutex);
-	fbcon = find_module(name);
-	mutex_unlock(&module_mutex);
-
-	if (!fbcon)
-		request_module_nowait(name);
-#endif
-	return 0;
-}
-EXPORT_SYMBOL(drm_fb_helper_modinit);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_file.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_file.c
@@ -369,7 +369,7 @@
 {
 	struct drm_device *dev;
 	struct drm_minor *minor;
-	int retcode;
+	int retcode = 0;
 	int need_setup = 0;
 
 	minor = drm_minor_acquire(iminor(inode));
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_fourcc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_fourcc.c
@@ -178,6 +178,10 @@
 		{ .format = DRM_FORMAT_BGRA5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 		{ .format = DRM_FORMAT_RGB565,		.depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGR565,		.depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+#ifdef __BIG_ENDIAN
+		{ .format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+#endif
 		{ .format = DRM_FORMAT_RGB888,		.depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGR888,		.depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_XRGB8888,	.depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
@@ -261,6 +265,9 @@
 		{ .format = DRM_FORMAT_P016,		.depth = 0,  .num_planes = 2,
 		  .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
 		  .hsub = 2, .vsub = 2, .is_yuv = true},
+		{ .format = DRM_FORMAT_NV12_10LE40,	.depth = 0,  .num_planes = 2,
+		  .char_per_block = { 5, 5, 0 }, .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 },
+		  .hsub = 2, .vsub = 2, .is_yuv = true },
 		{ .format = DRM_FORMAT_P210,		.depth = 0,
 		  .num_planes = 2, .char_per_block = { 2, 4, 0 },
 		  .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, .hsub = 2,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_framebuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_framebuffer.c
@@ -31,6 +31,7 @@
 #include <drm/drm_file.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_gem.h>
 #include <drm/drm_print.h>
 #include <drm/drm_util.h>
 
@@ -548,7 +549,128 @@
 
 out:
 	drm_framebuffer_put(fb);
+	return ret;
+}
+
+/**
+ * drm_mode_getfb2 - get extended FB info
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_getfb2_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_fb_cmd2 *r = data;
+	struct drm_framebuffer *fb;
+	unsigned int i;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return -EINVAL;
+
+	fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
+	if (!fb)
+		return -ENOENT;
+
+	/* For multi-plane framebuffers, we require the driver to place the
+	 * GEM objects directly in the drm_framebuffer. For single-plane
+	 * framebuffers, we can fall back to create_handle.
+	 */
+	if (!fb->obj[0] &&
+	    (fb->format->num_planes > 1 || !fb->funcs->create_handle)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	r->height = fb->height;
+	r->width = fb->width;
+	r->pixel_format = fb->format->format;
+
+	r->flags = 0;
+	if (dev->mode_config.allow_fb_modifiers)
+		r->flags |= DRM_MODE_FB_MODIFIERS;
+
+	for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
+		r->handles[i] = 0;
+		r->pitches[i] = 0;
+		r->offsets[i] = 0;
+		r->modifier[i] = 0;
+	}
+
+	for (i = 0; i < fb->format->num_planes; i++) {
+		r->pitches[i] = fb->pitches[i];
+		r->offsets[i] = fb->offsets[i];
+		if (dev->mode_config.allow_fb_modifiers)
+			r->modifier[i] = fb->modifier;
+	}
+
+	/* GET_FB2() is an unprivileged ioctl so we must not return a
+	 * buffer-handle to non master/root processes! To match GET_FB()
+	 * just return invalid handles (0) for non masters/root
+	 * rather than making GET_FB2() privileged.
+	 */
+	if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) {
+		ret = 0;
+		goto out;
+	}
+
+	for (i = 0; i < fb->format->num_planes; i++) {
+		int j;
+
+		/* If we reuse the same object for multiple planes, also
+		 * return the same handle.
+		 */
+		for (j = 0; j < i; j++) {
+			if (fb->obj[i] == fb->obj[j]) {
+				r->handles[i] = r->handles[j];
+				break;
+			}
+		}
 
+		if (r->handles[i])
+			continue;
+
+		if (fb->obj[i]) {
+			ret = drm_gem_handle_create(file_priv, fb->obj[i],
+						    &r->handles[i]);
+		} else {
+			WARN_ON(i > 0);
+			ret = fb->funcs->create_handle(fb, file_priv,
+						       &r->handles[i]);
+		}
+
+		if (ret != 0)
+			goto out;
+	}
+
+out:
+	if (ret != 0) {
+		/* Delete any previously-created handles on failure. */
+		for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
+			int j;
+
+			if (r->handles[i])
+				drm_gem_handle_delete(file_priv, r->handles[i]);
+
+			/* Zero out any handles identical to the one we just
+			 * deleted.
+			 */
+			for (j = i + 1; j < ARRAY_SIZE(r->handles); j++) {
+				if (r->handles[j] == r->handles[i])
+					r->handles[j] = 0;
+			}
+		}
+	}
+
+	drm_framebuffer_put(fb);
 	return ret;
 }
 
@@ -580,7 +702,7 @@
 	struct drm_framebuffer *fb;
 	unsigned flags;
 	int num_clips;
-	int ret;
+	int ret = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EOPNOTSUPP;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_gem.c
@@ -167,21 +167,6 @@
 }
 EXPORT_SYMBOL(drm_gem_private_object_init);
 
-static void
-drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
-{
-	/*
-	 * Note: obj->dma_buf can't disappear as long as we still hold a
-	 * handle reference in obj->handle_count.
-	 */
-	mutex_lock(&filp->prime.lock);
-	if (obj->dma_buf) {
-		drm_prime_remove_buf_handle_locked(&filp->prime,
-						   obj->dma_buf);
-	}
-	mutex_unlock(&filp->prime.lock);
-}
-
 /**
  * drm_gem_object_handle_free - release resources bound to userspace handles
  * @obj: GEM object to clean up.
@@ -255,7 +240,7 @@
 	else if (dev->driver->gem_close_object)
 		dev->driver->gem_close_object(obj, file_priv);
 
-	drm_gem_remove_prime_handles(obj, file_priv);
+	drm_prime_remove_buf_handle(&file_priv->prime, id);
 	drm_vma_node_revoke(&obj->vma_node, file_priv);
 
 	drm_gem_object_handle_put_unlocked(obj);
@@ -710,6 +695,8 @@
 	if (!objs)
 		return -ENOMEM;
 
+	*objs_out = objs;
+
 	handles = kvmalloc_array(count, sizeof(u32), GFP_KERNEL);
 	if (!handles) {
 		ret = -ENOMEM;
@@ -723,8 +710,6 @@
 	}
 
 	ret = objects_lookup(filp, handles, count, objs);
-	*objs_out = objs;
-
 out:
 	kvfree(handles);
 	return ret;
@@ -872,9 +857,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,
@@ -899,14 +881,15 @@
 
 	/* drm_gem_handle_create_tail unlocks dev->object_name_lock. */
 	ret = drm_gem_handle_create_tail(file_priv, obj, &handle);
-	drm_gem_object_put_unlocked(obj);
 	if (ret)
-		return ret;
+		goto err;
 
 	args->handle = handle;
 	args->size = obj->size;
 
-	return 0;
+err:
+	drm_gem_object_put_unlocked(obj);
+	return ret;
 }
 
 /**
@@ -1294,7 +1277,7 @@
 		ret = dma_resv_lock_slow_interruptible(obj->resv,
 								 acquire_ctx);
 		if (ret) {
-			ww_acquire_done(acquire_ctx);
+			ww_acquire_fini(acquire_ctx);
 			return ret;
 		}
 	}
@@ -1319,7 +1302,7 @@
 				goto retry;
 			}
 
-			ww_acquire_done(acquire_ctx);
+			ww_acquire_fini(acquire_ctx);
 			return ret;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -474,14 +474,28 @@
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
 	loff_t num_pages = obj->size >> PAGE_SHIFT;
+	vm_fault_t ret;
 	struct page *page;
+	pgoff_t page_offset;
 
-	if (vmf->pgoff >= num_pages || WARN_ON_ONCE(!shmem->pages))
-		return VM_FAULT_SIGBUS;
+	/* We don't use vmf->pgoff since that has the fake offset */
+	page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
 
-	page = shmem->pages[vmf->pgoff];
+	mutex_lock(&shmem->pages_lock);
 
-	return vmf_insert_page(vma, vmf->address, page);
+	if (page_offset >= num_pages ||
+	    WARN_ON_ONCE(!shmem->pages) ||
+	    shmem->madv < 0) {
+		ret = VM_FAULT_SIGBUS;
+	} else {
+		page = shmem->pages[page_offset];
+
+		ret = vmf_insert_page(vma, vmf->address, page);
+	}
+
+	mutex_unlock(&shmem->pages_lock);
+
+	return ret;
 }
 
 static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
@@ -540,18 +554,13 @@
 	shmem = to_drm_gem_shmem_obj(vma->vm_private_data);
 
 	ret = drm_gem_shmem_get_pages(shmem);
-	if (ret) {
-		drm_gem_vm_close(vma);
+	if (ret)
 		return ret;
-	}
 
 	/* VM_PFNMAP was set by drm_gem_mmap() */
 	vma->vm_flags &= ~VM_PFNMAP;
 	vma->vm_flags |= VM_MIXEDMAP;
 
-	/* Remove the fake offset */
-	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_gem_vram_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -73,6 +73,10 @@
 	}
 }
 
+/*
+ * Note that on error, drm_gem_vram_init will free the buffer object.
+ */
+
 static int drm_gem_vram_init(struct drm_device *dev,
 			     struct ttm_bo_device *bdev,
 			     struct drm_gem_vram_object *gbo,
@@ -86,8 +90,10 @@
 		gbo->bo.base.funcs = &drm_gem_vram_object_funcs;
 
 	ret = drm_gem_object_init(dev, &gbo->bo.base, size);
-	if (ret)
+	if (ret) {
+		kfree(gbo);
 		return ret;
+	}
 
 	acc_size = ttm_bo_dma_acc_size(bdev, size, sizeof(*gbo));
 
@@ -98,13 +104,13 @@
 			  &gbo->placement, pg_align, interruptible, acc_size,
 			  NULL, NULL, ttm_buffer_object_destroy);
 	if (ret)
-		goto err_drm_gem_object_release;
+		/*
+		 * A failing ttm_bo_init will call ttm_buffer_object_destroy
+		 * to release gbo->bo.base and kfree gbo.
+		 */
+		return ret;
 
 	return 0;
-
-err_drm_gem_object_release:
-	drm_gem_object_release(&gbo->bo.base);
-	return ret;
 }
 
 /**
@@ -134,13 +140,9 @@
 
 	ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible);
 	if (ret < 0)
-		goto err_kfree;
+		return ERR_PTR(ret);
 
 	return gbo;
-
-err_kfree:
-	kfree(gbo);
-	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(drm_gem_vram_create);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_internal.h
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_internal.h
@@ -59,8 +59,8 @@
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-					struct dma_buf *dma_buf);
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+				 uint32_t handle);
 
 /* drm_drv.c */
 struct drm_minor *drm_minor_acquire(unsigned int minor_id);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_ioc32.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_ioc32.c
@@ -99,6 +99,8 @@
 	if (copy_from_user(&v32, (void __user *)arg, sizeof(v32)))
 		return -EFAULT;
 
+	memset(&v, 0, sizeof(v));
+
 	v = (struct drm_version) {
 		.name_len = v32.name_len,
 		.name = compat_ptr(v32.name),
@@ -137,6 +139,9 @@
 
 	if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
 		return -EFAULT;
+
+	memset(&uq, 0, sizeof(uq));
+
 	uq = (struct drm_unique){
 		.unique_len = uq32.unique_len,
 		.unique = compat_ptr(uq32.unique),
@@ -265,6 +270,8 @@
 	if (copy_from_user(&c32, argp, sizeof(c32)))
 		return -EFAULT;
 
+	memset(&client, 0, sizeof(client));
+
 	client.idx = c32.idx;
 
 	err = drm_ioctl_kernel(file, drm_getclient, &client, 0);
@@ -850,12 +857,12 @@
 	if (copy_from_user(&req32, argp, sizeof(req32)))
 		return -EFAULT;
 
+	memset(&req, 0, sizeof(req));
+
 	req.request.type = req32.request.type;
 	req.request.sequence = req32.request.sequence;
 	req.request.signal = req32.request.signal;
 	err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED);
-	if (err)
-		return err;
 
 	req32.reply.type = req.reply.type;
 	req32.reply.sequence = req.reply.sequence;
@@ -864,7 +871,7 @@
 	if (copy_to_user(argp, &req32, sizeof(req32)))
 		return -EFAULT;
 
-	return 0;
+	return err;
 }
 
 #if defined(CONFIG_X86)
@@ -887,6 +894,8 @@
 	struct drm_mode_fb_cmd2 req64;
 	int err;
 
+	memset(&req64, 0, sizeof(req64));
+
 	if (copy_from_user(&req64, argp,
 			   offsetof(drm_mode_fb_cmd232_t, modifier)))
 		return -EFAULT;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_ioctl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_ioctl.c
@@ -118,17 +118,18 @@
 		  struct drm_file *file_priv)
 {
 	struct drm_unique *u = data;
-	struct drm_master *master = file_priv->master;
+	struct drm_master *master;
 
-	mutex_lock(&master->dev->master_mutex);
+	mutex_lock(&dev->master_mutex);
+	master = file_priv->master;
 	if (u->unique_len >= master->unique_len) {
 		if (copy_to_user(u->unique, master->unique, master->unique_len)) {
-			mutex_unlock(&master->dev->master_mutex);
+			mutex_unlock(&dev->master_mutex);
 			return -EFAULT;
 		}
 	}
 	u->unique_len = master->unique_len;
-	mutex_unlock(&master->dev->master_mutex);
+	mutex_unlock(&dev->master_mutex);
 
 	return 0;
 }
@@ -472,7 +473,13 @@
  */
 static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value)
 {
-	int len;
+	size_t len;
+
+	/* don't attempt to copy a NULL pointer */
+	if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) {
+		*buf_len = 0;
+		return 0;
+	}
 
 	/* don't overflow userbuf */
 	len = strlen(value);
@@ -671,6 +678,7 @@
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, 0),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, 0),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB2, drm_mode_getfb2_ioctl, 0),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0),
@@ -825,6 +833,9 @@
 	if (drm_dev_is_unplugged(dev))
 		return -ENODEV;
 
+       if (DRM_IOCTL_TYPE(cmd) != DRM_IOCTL_BASE)
+               return -ENOTTY;
+
 	is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END;
 
 	if (is_driver_ioctl) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_kms_helper_common.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_kms_helper_common.c
@@ -64,19 +64,18 @@
 
 static int __init drm_kms_helper_init(void)
 {
-	int ret;
+	/*
+	 * The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
+	 * 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 (IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) &&
+	    IS_MODULE(CONFIG_FRAMEBUFFER_CONSOLE) &&
+	    !IS_ENABLED(CONFIG_EXPERT))
+		request_module_nowait("fbcon");
 
-	/* 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;
+	return drm_dp_aux_dev_init();
 }
 
 static void __exit drm_kms_helper_exit(void)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_lease.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_lease.c
@@ -542,10 +542,12 @@
 	}
 
 	DRM_DEBUG_LEASE("Creating lease\n");
+	/* lessee will take the ownership of leases */
 	lessee = drm_lease_create(lessor, &leases);
 
 	if (IS_ERR(lessee)) {
 		ret = PTR_ERR(lessee);
+		idr_destroy(&leases);
 		goto out_leases;
 	}
 
@@ -580,7 +582,6 @@
 
 out_leases:
 	put_unused_fd(fd);
-	idr_destroy(&leases);
 
 	DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_mipi_dbi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_mipi_dbi.c
@@ -367,9 +367,9 @@
 	memset(dbidev->tx_buf, 0, len);
 
 	mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0,
-			 (width >> 8) & 0xFF, (width - 1) & 0xFF);
+			 ((width - 1) >> 8) & 0xFF, (width - 1) & 0xFF);
 	mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0,
-			 (height >> 8) & 0xFF, (height - 1) & 0xFF);
+			 ((height - 1) >> 8) & 0xFF, (height - 1) & 0xFF);
 	mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START,
 			     (u8 *)dbidev->tx_buf, len);
 
@@ -937,7 +937,7 @@
 			}
 		}
 
-		tr.len = chunk;
+		tr.len = chunk * 2;
 		len -= chunk;
 
 		ret = spi_sync(spi, &m);
@@ -955,7 +955,7 @@
 	int ret;
 
 	if (mipi_dbi_command_is_read(dbi, *cmd))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	MIPI_DBI_DEBUG_COMMAND(*cmd, parameters, num);
 
@@ -1156,6 +1156,13 @@
 	size_t chunk;
 	int ret;
 
+	/* In __spi_validate, there's a validation that no partial transfers
+	 * are accepted (xfer->len % w_size must be zero).
+	 * Here we align max_chunk to multiple of 2 (16bits),
+	 * to prevent transfers from being rejected.
+	 */
+	max_chunk = ALIGN_DOWN(max_chunk, 2);
+
 	spi_message_init_with_transfers(&m, &tr, 1);
 
 	while (len) {
@@ -1187,8 +1194,7 @@
 	struct mipi_dbi_dev *dbidev = m->private;
 	u8 val, cmd = 0, parameters[64];
 	char *buf, *pos, *token;
-	unsigned int i;
-	int ret, idx;
+	int i, ret, idx;
 
 	if (!drm_dev_enter(&dbidev->drm, &idx))
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_mipi_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_mipi_dsi.c
@@ -221,7 +221,7 @@
 		return dsi;
 	}
 
-	dsi->dev.of_node = info->node;
+	device_set_node(&dsi->dev, of_fwnode_handle(info->node));
 	dsi->channel = info->channel;
 	strlcpy(dsi->name, info->type, sizeof(dsi->name));
 
@@ -300,6 +300,8 @@
 {
 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
 
+	if (dsi->attached)
+		mipi_dsi_detach(dsi);
 	mipi_dsi_device_unregister(dsi);
 
 	return 0;
@@ -322,11 +324,18 @@
 int mipi_dsi_attach(struct mipi_dsi_device *dsi)
 {
 	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+	int ret;
 
 	if (!ops || !ops->attach)
 		return -ENOSYS;
 
-	return ops->attach(dsi->host, dsi);
+	ret = ops->attach(dsi->host, dsi);
+	if (ret)
+		return ret;
+
+	dsi->attached = true;
+
+	return 0;
 }
 EXPORT_SYMBOL(mipi_dsi_attach);
 
@@ -338,9 +347,14 @@
 {
 	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
 
+	if (WARN_ON(!dsi->attached))
+		return -EINVAL;
+
 	if (!ops || !ops->detach)
 		return -ENOSYS;
 
+	dsi->attached = false;
+
 	return ops->detach(dsi->host, dsi);
 }
 EXPORT_SYMBOL(mipi_dsi_detach);
@@ -1029,11 +1043,11 @@
  */
 int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)
 {
-	u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8,
-			  scanline & 0xff };
+	u8 payload[2] = { scanline >> 8, scanline & 0xff };
 	ssize_t err;
 
-	err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_SCANLINE, payload,
+				 sizeof(payload));
 	if (err < 0)
 		return err;
 
@@ -1090,6 +1104,58 @@
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);
 
+/**
+ * mipi_dsi_dcs_set_display_brightness_large() - sets the 16-bit brightness value
+ *    of the display
+ * @dsi: DSI peripheral device
+ * @brightness: brightness value
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi,
+					     u16 brightness)
+{
+	u8 payload[2] = { brightness >> 8, brightness & 0xff };
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
+				 payload, sizeof(payload));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_large);
+
+/**
+ * mipi_dsi_dcs_get_display_brightness_large() - gets the current 16-bit
+ *    brightness value of the display
+ * @dsi: DSI peripheral device
+ * @brightness: brightness value
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi,
+					     u16 *brightness)
+{
+	u8 brightness_be[2];
+	ssize_t err;
+
+	err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+				brightness_be, sizeof(brightness_be));
+	if (err <= 0) {
+		if (err == 0)
+			err = -ENODATA;
+
+		return err;
+	}
+
+	*brightness = (brightness_be[0] << 8) | brightness_be[1];
+
+	return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large);
+
 static int mipi_dsi_drv_probe(struct device *dev)
 {
 	struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_modes.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_modes.c
@@ -1672,6 +1672,13 @@
 		}
 	}
 
+	if (!(rotation & DRM_MODE_ROTATE_MASK))
+		rotation |= DRM_MODE_ROTATE_0;
+
+	/* Make sure there is exactly one rotation defined */
+	if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
+		return -EINVAL;
+
 	mode->rotation_reflection = rotation;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_of.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_of.c
@@ -100,8 +100,10 @@
 EXPORT_SYMBOL_GPL(drm_of_component_match_add);
 
 /**
- * drm_of_component_probe - Generic probe function for a component based master
+ * drm_of_component_probe_with_match - Generic probe function with match
+ *                                     entries for a component based master
  * @dev: master device containing the OF node
+ * @match: component match pointer provided to store matches
  * @compare_of: compare function used for matching components
  * @m_ops: component master ops to be used
  *
@@ -112,12 +114,12 @@
  *
  * Returns zero if successful, or one of the standard error codes if it fails.
  */
-int drm_of_component_probe(struct device *dev,
+int drm_of_component_probe_with_match(struct device *dev,
+			   struct component_match *match,
 			   int (*compare_of)(struct device *, void *),
 			   const struct component_master_ops *m_ops)
 {
 	struct device_node *ep, *port, *remote;
-	struct component_match *match = NULL;
 	int i;
 
 	if (!dev->of_node)
@@ -183,6 +185,29 @@
 
 	return component_master_add_with_match(dev, m_ops, match);
 }
+EXPORT_SYMBOL(drm_of_component_probe_with_match);
+
+/**
+ * drm_of_component_probe - Generic probe function for a component based master
+ * @dev: master device containing the OF node
+ * @compare_of: compare function used for matching components
+ * @master_ops: component master ops to be used
+ *
+ * Parse the platform device OF node and bind all the components associated
+ * with the master. Interface ports are added before the encoders in order to
+ * satisfy their .bind requirements
+ * See Documentation/devicetree/bindings/graph.txt for the bindings.
+ *
+ * Returns zero if successful, or one of the standard error codes if it fails.
+ */
+int drm_of_component_probe(struct device *dev,
+			   int (*compare_of)(struct device *, void *),
+			   const struct component_master_ops *m_ops)
+{
+	struct component_match *match = NULL;
+
+	return drm_of_component_probe_with_match(dev, match, compare_of, m_ops);
+}
 EXPORT_SYMBOL(drm_of_component_probe);
 
 /*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_panel.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_panel.c
@@ -21,11 +21,13 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/backlight.h>
 #include <linux/err.h>
 #include <linux/module.h>
 
 #include <drm/drm_crtc.h>
 #include <drm/drm_panel.h>
+#include <drm/drm_print.h>
 
 static DEFINE_MUTEX(panel_lock);
 static LIST_HEAD(panel_list);
@@ -44,13 +46,21 @@
 /**
  * drm_panel_init - initialize a panel
  * @panel: DRM panel
+ * @dev: parent device of the panel
+ * @funcs: panel operations
+ * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to
+ *	the panel interface
  *
- * Sets up internal fields of the panel so that it can subsequently be added
- * to the registry.
+ * Initialize the panel structure for subsequent registration with
+ * drm_panel_add().
  */
-void drm_panel_init(struct drm_panel *panel)
+void drm_panel_init(struct drm_panel *panel, struct device *dev,
+		    const struct drm_panel_funcs *funcs, int connector_type)
 {
 	INIT_LIST_HEAD(&panel->list);
+	panel->dev = dev;
+	panel->funcs = funcs;
+	panel->connector_type = connector_type;
 }
 EXPORT_SYMBOL(drm_panel_init);
 
@@ -143,10 +153,13 @@
  */
 int drm_panel_prepare(struct drm_panel *panel)
 {
-	if (panel && panel->funcs && panel->funcs->prepare)
+	if (!panel)
+		return -EINVAL;
+
+	if (panel->funcs && panel->funcs->prepare)
 		return panel->funcs->prepare(panel);
 
-	return panel ? -ENOSYS : -EINVAL;
+	return 0;
 }
 EXPORT_SYMBOL(drm_panel_prepare);
 
@@ -163,10 +176,13 @@
  */
 int drm_panel_unprepare(struct drm_panel *panel)
 {
-	if (panel && panel->funcs && panel->funcs->unprepare)
+	if (!panel)
+		return -EINVAL;
+
+	if (panel->funcs && panel->funcs->unprepare)
 		return panel->funcs->unprepare(panel);
 
-	return panel ? -ENOSYS : -EINVAL;
+	return 0;
 }
 EXPORT_SYMBOL(drm_panel_unprepare);
 
@@ -182,10 +198,23 @@
  */
 int drm_panel_enable(struct drm_panel *panel)
 {
-	if (panel && panel->funcs && panel->funcs->enable)
-		return panel->funcs->enable(panel);
+	int ret;
+
+	if (!panel)
+		return -EINVAL;
+
+	if (panel->funcs && panel->funcs->enable) {
+		ret = panel->funcs->enable(panel);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = backlight_enable(panel->backlight);
+	if (ret < 0)
+		DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
+			     ret);
 
-	return panel ? -ENOSYS : -EINVAL;
+	return 0;
 }
 EXPORT_SYMBOL(drm_panel_enable);
 
@@ -201,10 +230,20 @@
  */
 int drm_panel_disable(struct drm_panel *panel)
 {
-	if (panel && panel->funcs && panel->funcs->disable)
+	int ret;
+
+	if (!panel)
+		return -EINVAL;
+
+	ret = backlight_disable(panel->backlight);
+	if (ret < 0)
+		DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
+			     ret);
+
+	if (panel->funcs && panel->funcs->disable)
 		return panel->funcs->disable(panel);
 
-	return panel ? -ENOSYS : -EINVAL;
+	return 0;
 }
 EXPORT_SYMBOL(drm_panel_disable);
 
@@ -220,10 +259,13 @@
  */
 int drm_panel_get_modes(struct drm_panel *panel)
 {
-	if (panel && panel->funcs && panel->funcs->get_modes)
+	if (!panel)
+		return -EINVAL;
+
+	if (panel->funcs && panel->funcs->get_modes)
 		return panel->funcs->get_modes(panel);
 
-	return panel ? -ENOSYS : -EINVAL;
+	return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL(drm_panel_get_modes);
 
@@ -266,6 +308,45 @@
 EXPORT_SYMBOL(of_drm_find_panel);
 #endif
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+/**
+ * drm_panel_of_backlight - use backlight device node for backlight
+ * @panel: DRM panel
+ *
+ * Use this function to enable backlight handling if your panel
+ * uses device tree and has a backlight phandle.
+ *
+ * When the panel is enabled backlight will be enabled after a
+ * successful call to &drm_panel_funcs.enable()
+ *
+ * When the panel is disabled backlight will be disabled before the
+ * call to &drm_panel_funcs.disable().
+ *
+ * A typical implementation for a panel driver supporting device tree
+ * will call this function at probe time. Backlight will then be handled
+ * transparently without requiring any intervention from the driver.
+ * drm_panel_of_backlight() must be called after the call to drm_panel_init().
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int drm_panel_of_backlight(struct drm_panel *panel)
+{
+	struct backlight_device *backlight;
+
+	if (!panel || !panel->dev)
+		return -EINVAL;
+
+	backlight = devm_of_find_backlight(panel->dev);
+
+	if (IS_ERR(backlight))
+		return PTR_ERR(backlight);
+
+	panel->backlight = backlight;
+	return 0;
+}
+EXPORT_SYMBOL(drm_panel_of_backlight);
+#endif
+
 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
 MODULE_DESCRIPTION("DRM panel infrastructure");
 MODULE_LICENSE("GPL and additional rights");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -30,12 +30,6 @@
 	int orientation;
 };
 
-static const struct drm_dmi_panel_orientation_data acer_s1003 = {
-	.width = 800,
-	.height = 1280,
-	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
-};
-
 static const struct drm_dmi_panel_orientation_data asus_t100ha = {
 	.width = 800,
 	.height = 1280,
@@ -50,6 +44,14 @@
 	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data gpd_onemix2s = {
+	.width = 1200,
+	.height = 1920,
+	.bios_dates = (const char * const []){ "05/21/2018", "10/26/2018",
+		"03/04/2019", NULL },
+	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
 static const struct drm_dmi_panel_orientation_data gpd_pocket = {
 	.width = 1200,
 	.height = 1920,
@@ -90,6 +92,13 @@
 	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data onegx1_pro = {
+	.width = 1200,
+	.height = 1920,
+	.bios_dates = (const char * const []){ "12/17/2020", NULL },
+	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
 static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = {
 	.width = 720,
 	.height = 1280,
@@ -108,19 +117,61 @@
 	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data lcd1280x1920_rightside_up = {
+	.width = 1280,
+	.height = 1920,
+	.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
+static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = {
+	.width = 1600,
+	.height = 2560,
+	.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
+};
+
 static const struct dmi_system_id orientation_data[] = {
 	{	/* Acer One 10 (S1003) */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
 		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
 		},
-		.driver_data = (void *)&acer_s1003,
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* Acer Switch V 10 (SW5-017) */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* Anbernic Win600 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Win600"),
+		},
+		.driver_data = (void *)&lcd720x1280_rightside_up,
 	}, {	/* Asus T100HA */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
 		},
 		.driver_data = (void *)&asus_t100ha,
+	}, {	/* Asus T101HA */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T101HA"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* Asus T103HAF */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* AYA NEO 2021 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYADEVICE"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYA NEO 2021"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
 	}, {	/* GPD MicroPC (generic strings, also match on bios date) */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
@@ -135,6 +186,12 @@
 		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC"),
 		},
 		.driver_data = (void *)&lcd720x1280_rightside_up,
+	}, {	/* GPD Win Max */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1619-01"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
 	}, {	/*
 		 * GPD Pocket, note that the the DMI data is less generic then
 		 * it seems, devices with a board-vendor of "AMI Corporation"
@@ -172,6 +229,12 @@
 		  DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
 		},
 		.driver_data = (void *)&gpd_win2,
+	}, {	/* GPD Win 3 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1618-03")
+		},
+		.driver_data = (void *)&lcd720x1280_rightside_up,
 	}, {	/* I.T.Works TW891 */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
@@ -180,6 +243,13 @@
 		  DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
 		},
 		.driver_data = (void *)&itworks_tw891,
+	}, {	/* KD Kurio Smart C15200 2-in-1 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "KD Interactive"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Kurio Smart"),
+		  DMI_EXACT_MATCH(DMI_BOARD_NAME, "KDM960BCP"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
 	}, {	/*
 		 * Lenovo Ideapad Miix 310 laptop, only some production batches
 		 * have a portrait screen, the resolution checks makes the quirk
@@ -198,19 +268,83 @@
 		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
 		},
 		.driver_data = (void *)&lcd800x1280_rightside_up,
-	}, {	/* Lenovo Ideapad D330 */
+	}, {	/* Lenovo Ideapad D330-10IGM (HD) */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* Lenovo Ideapad D330-10IGM (FHD) */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81H3"),
 		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"),
 		},
 		.driver_data = (void *)&lcd1200x1920_rightside_up,
+	}, {	/* Lenovo Ideapad D330-10IGL (HD) */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* Lenovo IdeaPad Duet 3 10IGL5 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5"),
+		},
+		.driver_data = (void *)&lcd1200x1920_rightside_up,
+	}, {	/* Lenovo Yoga Book X90F / X90L */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
+		},
+		.driver_data = (void *)&lcd1200x1920_rightside_up,
+	}, {	/* Lenovo Yoga Book X91F / X91L */
+		.matches = {
+		  /* Non exact match to match F + L versions */
+		  DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
+		},
+		.driver_data = (void *)&lcd1200x1920_rightside_up,
+	}, {	/* OneGX1 Pro */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SYSTEM_PRODUCT_NAME"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Default string"),
+		},
+		.driver_data = (void *)&onegx1_pro,
+	}, {	/* OneXPlayer */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK TECHNOLOGY CO., LTD."),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"),
+		},
+		.driver_data = (void *)&lcd1600x2560_leftside_up,
+	}, {	/* Samsung GalaxyBook 10.6 */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galaxy Book 10.6"),
+		},
+		.driver_data = (void *)&lcd1280x1920_rightside_up,
+	}, {	/* Valve Steam Deck */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"),
+		},
+		.driver_data = (void *)&lcd800x1280_rightside_up,
 	}, {	/* VIOS LTH17 */
 		.matches = {
 		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"),
 		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
 		},
 		.driver_data = (void *)&lcd800x1280_rightside_up,
+	}, {	/* One Mix 2S (generic strings, also match on bios date) */
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+		  DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
+		  DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+		},
+		.driver_data = (void *)&gpd_onemix2s,
 	},
 	{}
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_pci.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_pci.c
@@ -51,8 +51,6 @@
 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
 {
 	drm_dma_handle_t *dmah;
-	unsigned long addr;
-	size_t sz;
 
 	/* pci_alloc_consistent only guarantees alignment to the smallest
 	 * PAGE_SIZE order which is greater than or equal to the requested size.
@@ -68,20 +66,13 @@
 	dmah->size = size;
 	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size,
 					 &dmah->busaddr,
-					 GFP_KERNEL | __GFP_COMP);
+					 GFP_KERNEL);
 
 	if (dmah->vaddr == NULL) {
 		kfree(dmah);
 		return NULL;
 	}
 
-	/* XXX - Is virt_to_page() legal for consistent mem? */
-	/* Reserve */
-	for (addr = (unsigned long)dmah->vaddr, sz = size;
-	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-		SetPageReserved(virt_to_page((void *)addr));
-	}
-
 	return dmah;
 }
 
@@ -94,19 +85,9 @@
  */
 void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 {
-	unsigned long addr;
-	size_t sz;
-
-	if (dmah->vaddr) {
-		/* XXX - Is virt_to_page() legal for consistent mem? */
-		/* Unreserve */
-		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
-		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-			ClearPageReserved(virt_to_page((void *)addr));
-		}
+	if (dmah->vaddr)
 		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
 				  dmah->busaddr);
-	}
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_plane.c
@@ -186,6 +186,13 @@
 	if (WARN_ON(config->num_total_plane >= 32))
 		return -EINVAL;
 
+	/*
+	 * First driver to need more than 64 formats needs to fix this. Each
+	 * format is encoded as a bit and the current code only supports a u64.
+	 */
+	if (WARN_ON(format_count > 64))
+		return -EINVAL;
+
 	WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
 		(!funcs->atomic_destroy_state ||
 		 !funcs->atomic_duplicate_state));
@@ -207,13 +214,6 @@
 		return -ENOMEM;
 	}
 
-	/*
-	 * First driver to need more than 64 formats needs to fix this. Each
-	 * format is encoded as a bit and the current code only supports a u64.
-	 */
-	if (WARN_ON(format_count > 64))
-		return -EINVAL;
-
 	if (format_modifiers) {
 		const uint64_t *temp_modifiers = format_modifiers;
 		while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
@@ -1203,6 +1203,7 @@
 out:
 	if (fb)
 		drm_framebuffer_put(fb);
+	fb = NULL;
 	if (plane->old_fb)
 		drm_framebuffer_put(plane->old_fb);
 	plane->old_fb = NULL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_plane_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_plane_helper.c
@@ -123,7 +123,6 @@
 		.crtc_w = drm_rect_width(dst),
 		.crtc_h = drm_rect_height(dst),
 		.rotation = rotation,
-		.visible = *visible,
 	};
 	struct drm_crtc_state crtc_state = {
 		.crtc = crtc,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_prime.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_prime.c
@@ -187,29 +187,33 @@
 	return -ENOENT;
 }
 
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
-					struct dma_buf *dma_buf)
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
+				 uint32_t handle)
 {
 	struct rb_node *rb;
 
-	rb = prime_fpriv->dmabufs.rb_node;
+	mutex_lock(&prime_fpriv->lock);
+
+	rb = prime_fpriv->handles.rb_node;
 	while (rb) {
 		struct drm_prime_member *member;
 
-		member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
-		if (member->dma_buf == dma_buf) {
+		member = rb_entry(rb, struct drm_prime_member, handle_rb);
+		if (member->handle == handle) {
 			rb_erase(&member->handle_rb, &prime_fpriv->handles);
 			rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
 
-			dma_buf_put(dma_buf);
+			dma_buf_put(member->dma_buf);
 			kfree(member);
-			return;
-		} else if (member->dma_buf < dma_buf) {
+			break;
+		} else if (member->handle < handle) {
 			rb = rb->rb_right;
 		} else {
 			rb = rb->rb_left;
 		}
 	}
+
+	mutex_unlock(&prime_fpriv->lock);
 }
 
 void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_probe_helper.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_probe_helper.c
@@ -112,7 +112,7 @@
 			continue;
 		}
 
-		ret = drm_bridge_mode_valid(encoder->bridge, mode);
+		ret = drm_bridge_chain_mode_valid(encoder->bridge, mode);
 		if (ret != MODE_OK) {
 			/* There is also no point in continuing for crtc check
 			 * here. */
@@ -460,8 +460,9 @@
 		 */
 		dev->mode_config.delayed_event = true;
 		if (dev->mode_config.poll_enabled)
-			schedule_delayed_work(&dev->mode_config.output_poll_work,
-					      0);
+			mod_delayed_work(system_wq,
+					 &dev->mode_config.output_poll_work,
+					 0);
 	}
 
 	/* Re-enable polling in case the global poll config changed. */
@@ -488,7 +489,7 @@
 		count = drm_add_override_edid_modes(connector);
 
 	if (count == 0 && connector->status == connector_status_connected)
-		count = drm_add_modes_noedid(connector, 1024, 768);
+		count = drm_add_modes_noedid(connector, 1920, 1080);
 	count += drm_helper_probe_add_cmdline_mode(connector);
 	if (count == 0)
 		goto prune;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_property.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_property.c
@@ -561,7 +561,7 @@
 	struct drm_property_blob *blob;
 	int ret;
 
-	if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
+	if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
 		return ERR_PTR(-EINVAL);
 
 	blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_rect.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_rect.c
@@ -54,7 +54,12 @@
 
 static u32 clip_scaled(u32 src, u32 dst, u32 clip)
 {
-	u64 tmp = mul_u32_u32(src, dst - clip);
+	u64 tmp;
+
+	if (dst == 0)
+		return 0;
+
+	tmp = mul_u32_u32(src, dst - clip);
 
 	/*
 	 * Round toward 1.0 when clipping so that we don't accidentally
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_syncobj.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_syncobj.c
@@ -325,20 +325,37 @@
 	if (!syncobj)
 		return -ENOENT;
 
+	/* Waiting for userspace with locks help is illegal cause that can
+	 * trivial deadlock with page faults for example. Make lockdep complain
+	 * about it early on.
+	 */
+	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+		might_sleep();
+		lockdep_assert_none_held_once();
+	}
+
 	*fence = drm_syncobj_fence_get(syncobj);
-	drm_syncobj_put(syncobj);
 
 	if (*fence) {
 		ret = dma_fence_chain_find_seqno(fence, point);
-		if (!ret)
-			return 0;
+		if (!ret) {
+			/* If the requested seqno is already signaled
+			 * drm_syncobj_find_fence may return a NULL
+			 * fence. To make sure the recipient gets
+			 * signalled, use a new fence instead.
+			 */
+			if (!*fence)
+				*fence = dma_fence_get_stub();
+
+			goto out;
+		}
 		dma_fence_put(*fence);
 	} else {
 		ret = -EINVAL;
 	}
 
 	if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
-		return ret;
+		goto out;
 
 	memset(&wait, 0, sizeof(wait));
 	wait.task = current;
@@ -370,6 +387,9 @@
 	if (wait.node.next)
 		drm_syncobj_remove_wait(syncobj, &wait);
 
+out:
+	drm_syncobj_put(syncobj);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_syncobj_find_fence);
@@ -878,6 +898,10 @@
 	uint64_t *points;
 	uint32_t signaled_count, i;
 
+	if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+		     DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
+		lockdep_assert_none_held_once();
+
 	points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
 	if (points == NULL)
 		return -ENOMEM;
@@ -910,7 +934,8 @@
 		fence = drm_syncobj_fence_get(syncobjs[i]);
 		if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) {
 			dma_fence_put(fence);
-			if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+			if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+				     DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) {
 				continue;
 			} else {
 				timeout = -EINVAL;
@@ -943,7 +968,8 @@
 	 * fallthough and try a 0 timeout wait!
 	 */
 
-	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+	if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+		     DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) {
 		for (i = 0; i < count; ++i)
 			drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_sysfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_sysfs.c
@@ -293,9 +293,6 @@
 		return PTR_ERR(connector->kdev);
 	}
 
-	/* Let userspace know we have a new connector */
-	drm_sysfs_hotplug_event(dev);
-
 	if (connector->ddc)
 		return sysfs_create_link(&connector->kdev->kobj,
 				 &connector->ddc->dev.kobj, "ddc");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/drm_vblank.c
+++ linux-ein-5.4.0/drivers/gpu/drm/drm_vblank.c
@@ -69,6 +69,12 @@
  * &drm_driver.max_vblank_count. In that case the vblank core only disables the
  * vblanks after a timer has expired, which can be configured through the
  * ``vblankoffdelay`` module parameter.
+ *
+ * Drivers for hardware without support for vertical-blanking interrupts
+ * must not call drm_vblank_init(). For such drivers, atomic helpers will
+ * automatically generate fake vblank events as part of the display update.
+ * This functionality also can be controlled by the driver by enabling and
+ * disabling struct drm_crtc_state.no_vblank.
  */
 
 /* Retry timestamp calculation up to 3 times to satisfy
@@ -489,6 +495,28 @@
 EXPORT_SYMBOL(drm_vblank_init);
 
 /**
+ * drm_dev_has_vblank - test if vblanking has been initialized for
+ *                      a device
+ * @dev: the device
+ *
+ * Drivers may call this function to test if vblank support is
+ * initialized for a device. For most hardware this means that vblanking
+ * can also be enabled.
+ *
+ * Atomic helpers use this function to initialize
+ * &drm_crtc_state.no_vblank. See also drm_atomic_helper_check_modeset().
+ *
+ * Returns:
+ * True if vblanking has been initialized for the given device, false
+ * otherwise.
+ */
+bool drm_dev_has_vblank(const struct drm_device *dev)
+{
+	return dev->num_crtcs != 0;
+}
+EXPORT_SYMBOL(drm_dev_has_vblank);
+
+/**
  * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC
  * @crtc: which CRTC's vblank waitqueue to retrieve
  *
@@ -1581,7 +1609,7 @@
 	unsigned int flags, pipe, high_pipe;
 
 	if (!dev->irq_enabled)
-		return -EINVAL;
+		return -EOPNOTSUPP;
 
 	if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
 		return -EINVAL;
@@ -1838,7 +1866,7 @@
 		return -EOPNOTSUPP;
 
 	if (!dev->irq_enabled)
-		return -EINVAL;
+		return -EOPNOTSUPP;
 
 	crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id);
 	if (!crtc)
@@ -1896,7 +1924,7 @@
 		return -EOPNOTSUPP;
 
 	if (!dev->irq_enabled)
-		return -EINVAL;
+		return -EOPNOTSUPP;
 
 	crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id);
 	if (!crtc)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
@@ -12,6 +12,7 @@
 
 #include "common.xml.h"
 #include "state.xml.h"
+#include "state_blt.xml.h"
 #include "state_hi.xml.h"
 #include "state_3d.xml.h"
 #include "cmdstream.xml.h"
@@ -233,6 +234,8 @@
 	struct etnaviv_cmdbuf *buffer = &gpu->buffer;
 	unsigned int waitlink_offset = buffer->user_size - 16;
 	u32 link_target, flush = 0;
+	bool has_blt = !!(gpu->identity.minor_features5 &
+			  chipMinorFeatures5_BLT_ENGINE);
 
 	lockdep_assert_held(&gpu->lock);
 
@@ -248,16 +251,38 @@
 	if (flush) {
 		unsigned int dwords = 7;
 
+		if (has_blt)
+			dwords += 10;
+
 		link_target = etnaviv_buffer_reserve(gpu, buffer, dwords);
 
 		CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
 		CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+		if (has_blt) {
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+			CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+			CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+		}
 		CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
-		if (gpu->exec_state == ETNA_PIPE_3D)
-			CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
-				       VIVS_TS_FLUSH_CACHE_FLUSH);
+		if (gpu->exec_state == ETNA_PIPE_3D) {
+			if (has_blt) {
+				CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+				CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
+				CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+			} else {
+				CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
+					       VIVS_TS_FLUSH_CACHE_FLUSH);
+			}
+		}
 		CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
 		CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+		if (has_blt) {
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+			CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+			CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+		}
 		CMD_END(buffer);
 
 		etnaviv_buffer_replace_wait(buffer, waitlink_offset,
@@ -323,6 +348,8 @@
 	bool switch_mmu_context = gpu->mmu_context != mmu_context;
 	unsigned int new_flush_seq = READ_ONCE(gpu->mmu_context->flush_seq);
 	bool need_flush = switch_mmu_context || gpu->flush_seq != new_flush_seq;
+	bool has_blt = !!(gpu->identity.minor_features5 &
+			  chipMinorFeatures5_BLT_ENGINE);
 
 	lockdep_assert_held(&gpu->lock);
 
@@ -370,8 +397,7 @@
 		if (switch_mmu_context) {
 			struct etnaviv_iommu_context *old_context = gpu->mmu_context;
 
-			etnaviv_iommu_context_get(mmu_context);
-			gpu->mmu_context = mmu_context;
+			gpu->mmu_context = etnaviv_iommu_context_get(mmu_context);
 			etnaviv_iommu_context_put(old_context);
 		}
 
@@ -433,6 +459,15 @@
 	 * 2 semaphore stall + 1 event + 1 wait + 1 link.
 	 */
 	return_dwords = 7;
+
+	/*
+	 * When the BLT engine is present we need 6 more dwords in the return
+	 * target: 3 enable/flush/disable + 4 enable/semaphore stall/disable,
+	 * but we don't need the normal TS flush state.
+	 */
+	if (has_blt)
+		return_dwords += 6;
+
 	return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords);
 	CMD_LINK(cmdbuf, return_dwords, return_target);
 
@@ -447,11 +482,25 @@
 		CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE,
 				       VIVS_GL_FLUSH_CACHE_DEPTH |
 				       VIVS_GL_FLUSH_CACHE_COLOR);
-		CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
-				       VIVS_TS_FLUSH_CACHE_FLUSH);
+		if (has_blt) {
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+			CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
+			CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+		} else {
+			CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
+					       VIVS_TS_FLUSH_CACHE_FLUSH);
+		}
 	}
 	CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
 	CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+
+	if (has_blt) {
+		CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+		CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+		CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+		CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+	}
+
 	CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
 		       VIVS_GL_EVENT_FROM_PE);
 	CMD_WAIT(buffer);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -232,19 +232,11 @@
 
 static int etnaviv_debugfs_init(struct drm_minor *minor)
 {
-	struct drm_device *dev = minor->dev;
-	int ret;
-
-	ret = drm_debugfs_create_files(etnaviv_debugfs_list,
-			ARRAY_SIZE(etnaviv_debugfs_list),
-			minor->debugfs_root, minor);
-
-	if (ret) {
-		dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
-		return ret;
-	}
+	drm_debugfs_create_files(etnaviv_debugfs_list,
+				 ARRAY_SIZE(etnaviv_debugfs_list),
+				 minor->debugfs_root, minor);
 
-	return ret;
+	return 0;
 }
 #endif
 
@@ -282,11 +274,6 @@
 			args->flags, &args->handle);
 }
 
-#define TS(t) ((struct timespec){ \
-	.tv_sec = (t).tv_sec, \
-	.tv_nsec = (t).tv_nsec \
-})
-
 static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 		struct drm_file *file)
 {
@@ -301,9 +288,9 @@
 	if (!obj)
 		return -ENOENT;
 
-	ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+	ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout);
 
-	drm_gem_object_put_unlocked(obj);
+	drm_gem_object_put(obj);
 
 	return ret;
 }
@@ -324,7 +311,7 @@
 
 	ret = etnaviv_gem_cpu_fini(obj);
 
-	drm_gem_object_put_unlocked(obj);
+	drm_gem_object_put(obj);
 
 	return ret;
 }
@@ -344,7 +331,7 @@
 		return -ENOENT;
 
 	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
-	drm_gem_object_put_unlocked(obj);
+	drm_gem_object_put(obj);
 
 	return ret;
 }
@@ -354,7 +341,7 @@
 {
 	struct drm_etnaviv_wait_fence *args = data;
 	struct etnaviv_drm_private *priv = dev->dev_private;
-	struct timespec *timeout = &TS(args->timeout);
+	struct drm_etnaviv_timespec *timeout = &args->timeout;
 	struct etnaviv_gpu *gpu;
 
 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
@@ -403,7 +390,7 @@
 {
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_etnaviv_gem_wait *args = data;
-	struct timespec *timeout = &TS(args->timeout);
+	struct drm_etnaviv_timespec *timeout = &args->timeout;
 	struct drm_gem_object *obj;
 	struct etnaviv_gpu *gpu;
 	int ret;
@@ -427,7 +414,7 @@
 
 	ret = etnaviv_gem_wait_bo(gpu, obj, timeout);
 
-	drm_gem_object_put_unlocked(obj);
+	drm_gem_object_put(obj);
 
 	return ret;
 }
@@ -555,6 +542,7 @@
 	mutex_init(&priv->gem_lock);
 	INIT_LIST_HEAD(&priv->gem_list);
 	priv->num_gpus = 0;
+	priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
 
 	priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
 	if (IS_ERR(priv->cmdbuf_suballoc)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -35,6 +35,7 @@
 	int num_gpus;
 	struct device_dma_parameters dma_parms;
 	struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
+	gfp_t shm_gfp_mask;
 
 	struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc;
 	struct etnaviv_iommu_global *mmu_global;
@@ -61,7 +62,7 @@
 void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
 void *etnaviv_gem_vmap(struct drm_gem_object *obj);
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
-		struct timespec *timeout);
+		struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
 void etnaviv_gem_free_object(struct drm_gem_object *obj);
 int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
@@ -107,11 +108,12 @@
  * between the specified timeout and the current CLOCK_MONOTONIC time.
  */
 static inline unsigned long etnaviv_timeout_to_jiffies(
-	const struct timespec *timeout)
+	const struct drm_etnaviv_timespec *timeout)
 {
-	struct timespec64 ts, to;
-
-	to = timespec_to_timespec64(*timeout);
+	struct timespec64 ts, to = {
+		.tv_sec = timeout->tv_sec,
+		.tv_nsec = timeout->tv_nsec,
+	};
 
 	ktime_get_ts64(&ts);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -125,9 +125,9 @@
 		return;
 	etnaviv_dump_core = false;
 
-	mutex_lock(&gpu->mmu_context->lock);
+	mutex_lock(&submit->mmu_context->lock);
 
-	mmu_size = etnaviv_iommu_dump_size(gpu->mmu_context);
+	mmu_size = etnaviv_iommu_dump_size(submit->mmu_context);
 
 	/* We always dump registers, mmu, ring, hanging cmdbuf and end marker */
 	n_obj = 5;
@@ -157,7 +157,7 @@
 	iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY,
 			       PAGE_KERNEL);
 	if (!iter.start) {
-		mutex_unlock(&gpu->mmu_context->lock);
+		mutex_unlock(&submit->mmu_context->lock);
 		dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
 		return;
 	}
@@ -169,18 +169,18 @@
 	memset(iter.hdr, 0, iter.data - iter.start);
 
 	etnaviv_core_dump_registers(&iter, gpu);
-	etnaviv_core_dump_mmu(&iter, gpu->mmu_context, mmu_size);
+	etnaviv_core_dump_mmu(&iter, submit->mmu_context, mmu_size);
 	etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer.vaddr,
 			      gpu->buffer.size,
 			      etnaviv_cmdbuf_get_va(&gpu->buffer,
-					&gpu->mmu_context->cmdbuf_mapping));
+					&submit->mmu_context->cmdbuf_mapping));
 
 	etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD,
 			      submit->cmdbuf.vaddr, submit->cmdbuf.size,
 			      etnaviv_cmdbuf_get_va(&submit->cmdbuf,
-					&gpu->mmu_context->cmdbuf_mapping));
+					&submit->mmu_context->cmdbuf_mapping));
 
-	mutex_unlock(&gpu->mmu_context->lock);
+	mutex_unlock(&submit->mmu_context->lock);
 
 	/* Reserve space for the bomap */
 	if (n_bomap_pages) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -27,7 +27,7 @@
 	 * because display controller, GPU, etc. are not coherent.
 	 */
 	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+		dma_map_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
 }
 
 static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
@@ -51,7 +51,7 @@
 	 * discard those writes.
 	 */
 	if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK)
-		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+		dma_unmap_sgtable(dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
 }
 
 /* called with etnaviv_obj->lock held */
@@ -244,7 +244,7 @@
 	mapping->use -= 1;
 	mutex_unlock(&etnaviv_obj->lock);
 
-	drm_gem_object_put_unlocked(&etnaviv_obj->base);
+	drm_gem_object_put(&etnaviv_obj->base);
 }
 
 struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
@@ -304,8 +304,7 @@
 		list_del(&mapping->obj_node);
 	}
 
-	etnaviv_iommu_context_get(mmu_context);
-	mapping->context = mmu_context;
+	mapping->context = etnaviv_iommu_context_get(mmu_context);
 	mapping->use = 1;
 
 	ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,
@@ -373,7 +372,7 @@
 }
 
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
-		struct timespec *timeout)
+		struct drm_etnaviv_timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 	struct drm_device *dev = obj->dev;
@@ -404,9 +403,8 @@
 	}
 
 	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
-		dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl,
-				    etnaviv_obj->sgt->nents,
-				    etnaviv_op_to_dma_dir(op));
+		dma_sync_sgtable_for_cpu(dev->dev, etnaviv_obj->sgt,
+					 etnaviv_op_to_dma_dir(op));
 		etnaviv_obj->last_cpu_prep_op = op;
 	}
 
@@ -421,8 +419,7 @@
 	if (etnaviv_obj->flags & ETNA_BO_CACHED) {
 		/* fini without a prep is almost certainly a userspace error */
 		WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
-		dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl,
-			etnaviv_obj->sgt->nents,
+		dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,
 			etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
 		etnaviv_obj->last_cpu_prep_op = 0;
 	}
@@ -431,7 +428,7 @@
 }
 
 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	struct timespec *timeout)
+	struct drm_etnaviv_timespec *timeout)
 {
 	struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
 
@@ -602,6 +599,7 @@
 int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
 	u32 size, u32 flags, u32 *handle)
 {
+	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_gem_object *obj = NULL;
 	int ret;
 
@@ -624,8 +622,7 @@
 	 * above new_inode() why this is required _and_ expected if you're
 	 * going to pin these pages.
 	 */
-	mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER |
-			     __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
+	mapping_set_gfp_mask(obj->filp->f_mapping, priv->shm_gfp_mask);
 
 	etnaviv_gem_obj_add(dev, obj);
 
@@ -633,7 +630,7 @@
 
 	/* drop reference from allocate - handle holds it now */
 fail:
-	drm_gem_object_put_unlocked(obj);
+	drm_gem_object_put(obj);
 
 	return ret;
 }
@@ -742,6 +739,6 @@
 	ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
 
 	/* drop reference from allocate - handle holds it now */
-	drm_gem_object_put_unlocked(&etnaviv_obj->base);
+	drm_gem_object_put(&etnaviv_obj->base);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -105,14 +105,14 @@
 	unsigned int nr_pmrs;
 	struct etnaviv_perfmon_request *pmrs;
 	unsigned int nr_bos;
-	struct etnaviv_gem_submit_bo bos[0];
+	struct etnaviv_gem_submit_bo bos[];
 	/* No new members here, the previous one is variable-length! */
 };
 
 void etnaviv_submit_put(struct etnaviv_gem_submit * submit);
 
 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
-	struct timespec *timeout);
+	struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
 	const struct etnaviv_gem_ops *ops, struct etnaviv_gem_object **res);
 void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -93,7 +93,15 @@
 static int etnaviv_gem_prime_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
 		struct vm_area_struct *vma)
 {
-	return dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0);
+	int ret;
+
+	ret = dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0);
+	if (!ret) {
+		/* Drop the reference acquired by drm_gem_mmap_obj(). */
+		drm_gem_object_put_unlocked(&etnaviv_obj->base);
+	}
+
+	return ret;
 }
 
 static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = {
@@ -136,7 +144,7 @@
 	return &etnaviv_obj->base;
 
 fail:
-	drm_gem_object_put_unlocked(&etnaviv_obj->base);
+	drm_gem_object_put(&etnaviv_obj->base);
 
 	return ERR_PTR(ret);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -113,7 +113,7 @@
 	if (submit->bos[i].flags & BO_LOCKED) {
 		struct drm_gem_object *obj = &submit->bos[i].obj->base;
 
-		ww_mutex_unlock(&obj->resv->lock);
+		dma_resv_unlock(obj->resv);
 		submit->bos[i].flags &= ~BO_LOCKED;
 	}
 }
@@ -133,8 +133,7 @@
 		contended = i;
 
 		if (!(submit->bos[i].flags & BO_LOCKED)) {
-			ret = ww_mutex_lock_interruptible(&obj->resv->lock,
-							  ticket);
+			ret = dma_resv_lock_interruptible(obj->resv, ticket);
 			if (ret == -EALREADY)
 				DRM_ERROR("BO at index %u already on submit list\n",
 					  i);
@@ -161,8 +160,7 @@
 		obj = &submit->bos[contended].obj->base;
 
 		/* we lost out in a seqno race, lock and retry.. */
-		ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock,
-						       ticket);
+		ret = dma_resv_lock_slow_interruptible(obj->resv, ticket);
 		if (!ret) {
 			submit->bos[contended].flags |= BO_LOCKED;
 			slow_locked = contended;
@@ -240,8 +238,10 @@
 		}
 
 		if ((submit->flags & ETNA_SUBMIT_SOFTPIN) &&
-		     submit->bos[i].va != mapping->iova)
+		     submit->bos[i].va != mapping->iova) {
+			etnaviv_gem_mapping_unreference(mapping);
 			return -EINVAL;
+		}
 
 		atomic_inc(&etnaviv_obj->gpu_active);
 
@@ -398,7 +398,7 @@
 
 		/* if the GPU submit failed, objects might still be locked */
 		submit_unlock_object(submit, i);
-		drm_gem_object_put_unlocked(&etnaviv_obj->base);
+		drm_gem_object_put(&etnaviv_obj->base);
 	}
 
 	wake_up_all(&submit->gpu->fence_event);
@@ -469,6 +469,12 @@
 		return -EINVAL;
 	}
 
+	if (args->stream_size > SZ_128K || args->nr_relocs > SZ_128K ||
+	    args->nr_bos > SZ_128K || args->nr_pmrs > 128) {
+		DRM_ERROR("submit arguments out of size limits\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * Copy the command submission and bo array to kernel space in
 	 * one go, and do this outside of any locks.
@@ -532,8 +538,7 @@
 		goto err_submit_objects;
 
 	submit->ctx = file->driver_priv;
-	etnaviv_iommu_context_get(submit->ctx->mmu);
-	submit->mmu_context = submit->ctx->mmu;
+	submit->mmu_context = etnaviv_iommu_context_get(submit->ctx->mmu);
 	submit->exec_state = args->exec_state;
 	submit->flags = args->flags;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -333,9 +333,20 @@
 		gpu->identity.revision = etnaviv_field(chipIdentity,
 					 VIVS_HI_CHIP_IDENTITY_REVISION);
 	} else {
+		u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
 
 		gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
 		gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
+		gpu->identity.customer_id = gpu_read(gpu, VIVS_HI_CHIP_CUSTOMER_ID);
+
+		/*
+		 * Reading these two registers on GC600 rev 0x19 result in a
+		 * unhandled fault: external abort on non-linefetch
+		 */
+		if (!etnaviv_is_model_rev(gpu, GC600, 0x19)) {
+			gpu->identity.product_id = gpu_read(gpu, VIVS_HI_CHIP_PRODUCT_ID);
+			gpu->identity.eco_id = gpu_read(gpu, VIVS_HI_CHIP_ECO_ID);
+		}
 
 		/*
 		 * !!!! HACK ALERT !!!!
@@ -350,7 +361,6 @@
 
 		/* Another special case */
 		if (etnaviv_is_model_rev(gpu, GC300, 0x2201)) {
-			u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE);
 			u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME);
 
 			if (chipDate == 0x20080814 && chipTime == 0x12051100) {
@@ -373,6 +383,12 @@
 			gpu->identity.model = chipModel_GC3000;
 			gpu->identity.revision &= 0xffff;
 		}
+
+		if (etnaviv_is_model_rev(gpu, GC1000, 0x5037) && (chipDate == 0x20120617))
+			gpu->identity.eco_id = 1;
+
+		if (etnaviv_is_model_rev(gpu, GC320, 0x5303) && (chipDate == 0x20140511))
+			gpu->identity.eco_id = 1;
 	}
 
 	dev_info(gpu->dev, "model: GC%x, revision: %x\n",
@@ -392,6 +408,12 @@
 	if (gpu->identity.model == chipModel_GC700)
 		gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
 
+	/* These models/revisions don't have the 2D pipe bit */
+	if ((gpu->identity.model == chipModel_GC500 &&
+	     gpu->identity.revision <= 2) ||
+	    gpu->identity.model == chipModel_GC300)
+		gpu->identity.features |= chipFeatures_PIPE_2D;
+
 	if ((gpu->identity.model == chipModel_GC500 &&
 	     gpu->identity.revision < 2) ||
 	    (gpu->identity.model == chipModel_GC300 &&
@@ -425,8 +447,9 @@
 				gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5);
 	}
 
-	/* GC600 idle register reports zero bits where modules aren't present */
-	if (gpu->identity.model == chipModel_GC600)
+	/* GC600/300 idle register reports zero bits where modules aren't present */
+	if (gpu->identity.model == chipModel_GC600 ||
+	    gpu->identity.model == chipModel_GC300)
 		gpu->idle_mask = VIVS_HI_IDLE_STATE_TX |
 				 VIVS_HI_IDLE_STATE_RA |
 				 VIVS_HI_IDLE_STATE_SE |
@@ -506,7 +529,7 @@
 		/* read idle register. */
 		idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
 
-		/* try reseting again if FE it not idle */
+		/* try resetting again if FE is not idle */
 		if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
 			dev_dbg(gpu->dev, "FE is not idle\n");
 			continue;
@@ -545,6 +568,12 @@
 	/* We rely on the GPU running, so program the clock */
 	etnaviv_gpu_update_clock(gpu);
 
+	gpu->fe_running = false;
+	gpu->exec_state = -1;
+	if (gpu->mmu_context)
+		etnaviv_iommu_context_put(gpu->mmu_context);
+	gpu->mmu_context = NULL;
+
 	return 0;
 }
 
@@ -607,19 +636,23 @@
 			  VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE |
 			  VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch));
 	}
+
+	gpu->fe_running = true;
 }
 
-static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu)
+static void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu,
+					  struct etnaviv_iommu_context *context)
 {
-	u32 address = etnaviv_cmdbuf_get_va(&gpu->buffer,
-				&gpu->mmu_context->cmdbuf_mapping);
 	u16 prefetch;
+	u32 address;
 
 	/* setup the MMU */
-	etnaviv_iommu_restore(gpu, gpu->mmu_context);
+	etnaviv_iommu_restore(gpu, context);
 
 	/* Start command processor */
 	prefetch = etnaviv_buffer_init(gpu);
+	address = etnaviv_cmdbuf_get_va(&gpu->buffer,
+					&gpu->mmu_context->cmdbuf_mapping);
 
 	etnaviv_gpu_start_fe(gpu, address, prefetch);
 }
@@ -713,7 +746,7 @@
 	ret = pm_runtime_get_sync(gpu->dev);
 	if (ret < 0) {
 		dev_err(gpu->dev, "Failed to enable GPU power domain\n");
-		return ret;
+		goto pm_put;
 	}
 
 	etnaviv_hw_identify(gpu);
@@ -772,6 +805,14 @@
 		gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
 	}
 
+	/*
+	 * If the GPU is part of a system with DMA addressing limitations,
+	 * request pages for our SHM backend buffers from the DMA32 zone to
+	 * hopefully avoid performance killing SWIOTLB bounce buffering.
+	 */
+	if (dma_addressing_limited(gpu->dev))
+		priv->shm_gfp_mask |= GFP_DMA32;
+
 	/* Create buffer: */
 	ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer,
 				  PAGE_SIZE);
@@ -790,7 +831,6 @@
 	/* Now program the hardware */
 	mutex_lock(&gpu->lock);
 	etnaviv_gpu_hw_init(gpu);
-	gpu->exec_state = -1;
 	mutex_unlock(&gpu->lock);
 
 	pm_runtime_mark_last_busy(gpu->dev);
@@ -802,6 +842,7 @@
 
 fail:
 	pm_runtime_mark_last_busy(gpu->dev);
+pm_put:
 	pm_runtime_put_autosuspend(gpu->dev);
 
 	return ret;
@@ -842,7 +883,7 @@
 
 	ret = pm_runtime_get_sync(gpu->dev);
 	if (ret < 0)
-		return ret;
+		goto pm_put;
 
 	dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW);
 	dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH);
@@ -851,6 +892,13 @@
 
 	verify_dma(gpu, &debug);
 
+	seq_puts(m, "\tidentity\n");
+	seq_printf(m, "\t model: 0x%x\n", gpu->identity.model);
+	seq_printf(m, "\t revision: 0x%x\n", gpu->identity.revision);
+	seq_printf(m, "\t product_id: 0x%x\n", gpu->identity.product_id);
+	seq_printf(m, "\t customer_id: 0x%x\n", gpu->identity.customer_id);
+	seq_printf(m, "\t eco_id: 0x%x\n", gpu->identity.eco_id);
+
 	seq_puts(m, "\tfeatures\n");
 	seq_printf(m, "\t major_features: 0x%08x\n",
 		   gpu->identity.features);
@@ -930,6 +978,20 @@
 		seq_puts(m, "\t FP is not idle\n");
 	if ((idle & VIVS_HI_IDLE_STATE_TS) == 0)
 		seq_puts(m, "\t TS is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_BL) == 0)
+		seq_puts(m, "\t BL is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_ASYNCFE) == 0)
+		seq_puts(m, "\t ASYNCFE is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_MC) == 0)
+		seq_puts(m, "\t MC is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_PPA) == 0)
+		seq_puts(m, "\t PPA is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_WD) == 0)
+		seq_puts(m, "\t WD is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_NN) == 0)
+		seq_puts(m, "\t NN is not idle\n");
+	if ((idle & VIVS_HI_IDLE_STATE_TP) == 0)
+		seq_puts(m, "\t TP is not idle\n");
 	if (idle & VIVS_HI_IDLE_STATE_AXI_LP)
 		seq_puts(m, "\t AXI low power mode\n");
 
@@ -965,6 +1027,7 @@
 	ret = 0;
 
 	pm_runtime_mark_last_busy(gpu->dev);
+pm_put:
 	pm_runtime_put_autosuspend(gpu->dev);
 
 	return ret;
@@ -978,7 +1041,7 @@
 	dev_err(gpu->dev, "recover hung GPU!\n");
 
 	if (pm_runtime_get_sync(gpu->dev) < 0)
-		return;
+		goto pm_put;
 
 	mutex_lock(&gpu->lock);
 
@@ -992,11 +1055,10 @@
 	spin_unlock(&gpu->event_spinlock);
 
 	etnaviv_gpu_hw_init(gpu);
-	gpu->exec_state = -1;
-	gpu->mmu_context = NULL;
 
 	mutex_unlock(&gpu->lock);
 	pm_runtime_mark_last_busy(gpu->dev);
+pm_put:
 	pm_runtime_put_autosuspend(gpu->dev);
 }
 
@@ -1132,7 +1194,7 @@
  * Cmdstream submission/retirement:
  */
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	u32 id, struct timespec *timeout)
+	u32 id, struct drm_etnaviv_timespec *timeout)
 {
 	struct dma_fence *fence;
 	int ret;
@@ -1179,7 +1241,8 @@
  * that lock in this function while waiting.
  */
 int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout)
+	struct etnaviv_gem_object *etnaviv_obj,
+	struct drm_etnaviv_timespec *timeout)
 {
 	unsigned long remaining;
 	long ret;
@@ -1269,8 +1332,10 @@
 
 	if (!submit->runtime_resumed) {
 		ret = pm_runtime_get_sync(gpu->dev);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put_noidle(gpu->dev);
 			return NULL;
+		}
 		submit->runtime_resumed = true;
 	}
 
@@ -1287,6 +1352,7 @@
 	ret = event_alloc(gpu, nr_events, event);
 	if (ret) {
 		DRM_ERROR("no free events\n");
+		pm_runtime_put_noidle(gpu->dev);
 		return NULL;
 	}
 
@@ -1300,14 +1366,12 @@
 		goto out_unlock;
 	}
 
-	if (!gpu->mmu_context) {
-		etnaviv_iommu_context_get(submit->mmu_context);
-		gpu->mmu_context = submit->mmu_context;
-		etnaviv_gpu_start_fe_idleloop(gpu);
-	} else {
-		etnaviv_iommu_context_get(gpu->mmu_context);
-		submit->prev_mmu_context = gpu->mmu_context;
-	}
+	if (!gpu->fe_running)
+		etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context);
+
+	if (submit->prev_mmu_context)
+		etnaviv_iommu_context_put(submit->prev_mmu_context);
+	submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context);
 
 	if (submit->nr_pmrs) {
 		gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre;
@@ -1448,52 +1512,40 @@
 {
 	int ret;
 
-	if (gpu->clk_reg) {
-		ret = clk_prepare_enable(gpu->clk_reg);
-		if (ret)
-			return ret;
-	}
+	ret = clk_prepare_enable(gpu->clk_reg);
+	if (ret)
+		return ret;
 
-	if (gpu->clk_bus) {
-		ret = clk_prepare_enable(gpu->clk_bus);
-		if (ret)
-			return ret;
-	}
+	ret = clk_prepare_enable(gpu->clk_bus);
+	if (ret)
+		goto disable_clk_reg;
 
-	if (gpu->clk_core) {
-		ret = clk_prepare_enable(gpu->clk_core);
-		if (ret)
-			goto disable_clk_bus;
-	}
+	ret = clk_prepare_enable(gpu->clk_core);
+	if (ret)
+		goto disable_clk_bus;
 
-	if (gpu->clk_shader) {
-		ret = clk_prepare_enable(gpu->clk_shader);
-		if (ret)
-			goto disable_clk_core;
-	}
+	ret = clk_prepare_enable(gpu->clk_shader);
+	if (ret)
+		goto disable_clk_core;
 
 	return 0;
 
 disable_clk_core:
-	if (gpu->clk_core)
-		clk_disable_unprepare(gpu->clk_core);
+	clk_disable_unprepare(gpu->clk_core);
 disable_clk_bus:
-	if (gpu->clk_bus)
-		clk_disable_unprepare(gpu->clk_bus);
+	clk_disable_unprepare(gpu->clk_bus);
+disable_clk_reg:
+	clk_disable_unprepare(gpu->clk_reg);
 
 	return ret;
 }
 
 static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu)
 {
-	if (gpu->clk_shader)
-		clk_disable_unprepare(gpu->clk_shader);
-	if (gpu->clk_core)
-		clk_disable_unprepare(gpu->clk_core);
-	if (gpu->clk_bus)
-		clk_disable_unprepare(gpu->clk_bus);
-	if (gpu->clk_reg)
-		clk_disable_unprepare(gpu->clk_reg);
+	clk_disable_unprepare(gpu->clk_shader);
+	clk_disable_unprepare(gpu->clk_core);
+	clk_disable_unprepare(gpu->clk_bus);
+	clk_disable_unprepare(gpu->clk_reg);
 
 	return 0;
 }
@@ -1521,7 +1573,7 @@
 
 static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
 {
-	if (gpu->initialized && gpu->mmu_context) {
+	if (gpu->initialized && gpu->fe_running) {
 		/* Replace the last WAIT with END */
 		mutex_lock(&gpu->lock);
 		etnaviv_buffer_end(gpu);
@@ -1534,8 +1586,7 @@
 		 */
 		etnaviv_gpu_wait_idle(gpu, 100);
 
-		etnaviv_iommu_context_put(gpu->mmu_context);
-		gpu->mmu_context = NULL;
+		gpu->fe_running = false;
 	}
 
 	gpu->exec_state = -1;
@@ -1683,6 +1734,9 @@
 	etnaviv_gpu_hw_suspend(gpu);
 #endif
 
+	if (gpu->mmu_context)
+		etnaviv_iommu_context_put(gpu->mmu_context);
+
 	if (gpu->initialized) {
 		etnaviv_cmdbuf_free(&gpu->buffer);
 		etnaviv_iommu_global_fini(gpu);
@@ -1744,26 +1798,26 @@
 	}
 
 	/* Get Clocks: */
-	gpu->clk_reg = devm_clk_get(&pdev->dev, "reg");
+	gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg");
 	DBG("clk_reg: %p", gpu->clk_reg);
 	if (IS_ERR(gpu->clk_reg))
-		gpu->clk_reg = NULL;
+		return PTR_ERR(gpu->clk_reg);
 
-	gpu->clk_bus = devm_clk_get(&pdev->dev, "bus");
+	gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus");
 	DBG("clk_bus: %p", gpu->clk_bus);
 	if (IS_ERR(gpu->clk_bus))
-		gpu->clk_bus = NULL;
+		return PTR_ERR(gpu->clk_bus);
 
 	gpu->clk_core = devm_clk_get(&pdev->dev, "core");
 	DBG("clk_core: %p", gpu->clk_core);
 	if (IS_ERR(gpu->clk_core))
-		gpu->clk_core = NULL;
+		return PTR_ERR(gpu->clk_core);
 	gpu->base_rate_core = clk_get_rate(gpu->clk_core);
 
-	gpu->clk_shader = devm_clk_get(&pdev->dev, "shader");
+	gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader");
 	DBG("clk_shader: %p", gpu->clk_shader);
 	if (IS_ERR(gpu->clk_shader))
-		gpu->clk_shader = NULL;
+		return PTR_ERR(gpu->clk_shader);
 	gpu->base_rate_shader = clk_get_rate(gpu->clk_shader);
 
 	/* TODO: figure out max mapped size */
@@ -1804,11 +1858,15 @@
 	if (atomic_read(&gpu->sched.hw_rq_count))
 		return -EBUSY;
 
-	/* Check whether the hardware (except FE) is idle */
-	mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE;
+	/* Check whether the hardware (except FE and MC) is idle */
+	mask = gpu->idle_mask & ~(VIVS_HI_IDLE_STATE_FE |
+				  VIVS_HI_IDLE_STATE_MC);
 	idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask;
-	if (idle != mask)
+	if (idle != mask) {
+		dev_warn_ratelimited(dev, "GPU not yet idle, mask: 0x%08x\n",
+				     idle);
 		return -EBUSY;
+	}
 
 	return etnaviv_gpu_hw_suspend(gpu);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -15,11 +15,11 @@
 struct etnaviv_vram_mapping;
 
 struct etnaviv_chip_identity {
-	/* Chip model. */
 	u32 model;
-
-	/* Revision value.*/
 	u32 revision;
+	u32 product_id;
+	u32 customer_id;
+	u32 eco_id;
 
 	/* Supported feature fields. */
 	u32 features;
@@ -101,6 +101,7 @@
 	struct workqueue_struct *wq;
 	struct drm_gpu_scheduler sched;
 	bool initialized;
+	bool fe_running;
 
 	/* 'ring'-buffer: */
 	struct etnaviv_cmdbuf buffer;
@@ -169,9 +170,10 @@
 void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	u32 fence, struct timespec *timeout);
+	u32 fence, struct drm_etnaviv_timespec *timeout);
 int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
+	struct etnaviv_gem_object *etnaviv_obj,
+	struct drm_etnaviv_timespec *timeout);
 struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
@@ -7,8 +7,42 @@
 
 static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
 	{
+		.model = 0x400,
+		.revision = 0x4652,
+		.product_id = 0x70001,
+		.customer_id = 0x100,
+		.eco_id = 0,
+		.stream_count = 4,
+		.register_max = 64,
+		.thread_count = 128,
+		.shader_core_count = 1,
+		.vertex_cache_size = 8,
+		.vertex_output_buffer_size = 1024,
+		.pixel_pipes = 1,
+		.instruction_count = 256,
+		.num_constants = 320,
+		.buffer_size = 0,
+		.varyings_count = 8,
+		.features = 0xa0e9e004,
+		.minor_features0 = 0xe1299fff,
+		.minor_features1 = 0xbe13b219,
+		.minor_features2 = 0xce110010,
+		.minor_features3 = 0x8000001,
+		.minor_features4 = 0x20102,
+		.minor_features5 = 0x120000,
+		.minor_features6 = 0x0,
+		.minor_features7 = 0x0,
+		.minor_features8 = 0x0,
+		.minor_features9 = 0x0,
+		.minor_features10 = 0x0,
+		.minor_features11 = 0x0,
+	},
+	{
 		.model = 0x7000,
 		.revision = 0x6214,
+		.product_id = ~0U,
+		.customer_id = ~0U,
+		.eco_id = ~0U,
 		.stream_count = 16,
 		.register_max = 64,
 		.thread_count = 1024,
@@ -43,7 +77,13 @@
 
 	for (i = 0; i < ARRAY_SIZE(etnaviv_chip_identities); i++) {
 		if (etnaviv_chip_identities[i].model == ident->model &&
-		    etnaviv_chip_identities[i].revision == ident->revision) {
+		    etnaviv_chip_identities[i].revision == ident->revision &&
+		    (etnaviv_chip_identities[i].product_id == ident->product_id ||
+			 etnaviv_chip_identities[i].product_id == ~0U) &&
+		    (etnaviv_chip_identities[i].customer_id == ident->customer_id ||
+			 etnaviv_chip_identities[i].customer_id == ~0U) &&
+		    (etnaviv_chip_identities[i].eco_id == ident->eco_id ||
+			 etnaviv_chip_identities[i].eco_id == ~0U)) {
 			memcpy(ident, &etnaviv_chip_identities[i],
 			       sizeof(*ident));
 			return true;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
@@ -92,6 +92,10 @@
 	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);
 	u32 pgtable;
 
+	if (gpu->mmu_context)
+		etnaviv_iommu_context_put(gpu->mmu_context);
+	gpu->mmu_context = etnaviv_iommu_context_get(context);
+
 	/* set base addresses */
 	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, context->global->memory_base);
 	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, context->global->memory_base);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
@@ -172,6 +172,10 @@
 	if (gpu_read(gpu, VIVS_MMUv2_CONTROL) & VIVS_MMUv2_CONTROL_ENABLE)
 		return;
 
+	if (gpu->mmu_context)
+		etnaviv_iommu_context_put(gpu->mmu_context);
+	gpu->mmu_context = etnaviv_iommu_context_get(context);
+
 	prefetch = etnaviv_buffer_config_mmuv2(gpu,
 				(u32)v2_context->mtlb_dma,
 				(u32)context->global->bad_page_dma);
@@ -192,6 +196,10 @@
 	if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) & VIVS_MMUv2_SEC_CONTROL_ENABLE)
 		return;
 
+	if (gpu->mmu_context)
+		etnaviv_iommu_context_put(gpu->mmu_context);
+	gpu->mmu_context = etnaviv_iommu_context_get(context);
+
 	gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_LOW,
 		  lower_32_bits(context->global->v2.pta_dma));
 	gpu_write(gpu, VIVS_MMUv2_PTA_ADDRESS_HIGH,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -73,17 +73,17 @@
 			     struct sg_table *sgt, unsigned len, int prot)
 {	struct scatterlist *sg;
 	unsigned int da = iova;
-	unsigned int i, j;
+	unsigned int i;
 	int ret;
 
 	if (!context || !sgt)
 		return -EINVAL;
 
-	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-		u32 pa = sg_dma_address(sg) - sg->offset;
+	for_each_sgtable_dma_sg(sgt, sg, i) {
+		phys_addr_t pa = sg_dma_address(sg) - sg->offset;
 		size_t bytes = sg_dma_len(sg) + sg->offset;
 
-		VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
+		VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes);
 
 		ret = etnaviv_context_map(context, da, pa, bytes, prot);
 		if (ret)
@@ -95,14 +95,7 @@
 	return 0;
 
 fail:
-	da = iova;
-
-	for_each_sg(sgt->sgl, sg, i, j) {
-		size_t bytes = sg_dma_len(sg) + sg->offset;
-
-		etnaviv_context_unmap(context, da, bytes);
-		da += bytes;
-	}
+	etnaviv_context_unmap(context, iova, da - iova);
 	return ret;
 }
 
@@ -113,7 +106,7 @@
 	unsigned int da = iova;
 	int i;
 
-	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+	for_each_sgtable_dma_sg(sgt, sg, i) {
 		size_t bytes = sg_dma_len(sg) + sg->offset;
 
 		etnaviv_context_unmap(context, da, bytes);
@@ -204,6 +197,7 @@
 		 */
 		list_for_each_entry_safe(m, n, &list, scan_node) {
 			etnaviv_iommu_remove_mapping(context, m);
+			etnaviv_iommu_context_put(m->context);
 			m->context = NULL;
 			list_del_init(&m->mmu_node);
 			list_del_init(&m->scan_node);
@@ -288,6 +282,12 @@
 
 	mutex_lock(&context->lock);
 
+	/* Bail if the mapping has been reaped by another thread */
+	if (!mapping->context) {
+		mutex_unlock(&context->lock);
+		return;
+	}
+
 	/* If the vram node is on the mm, unmap and remove the node */
 	if (mapping->vram_node.mm == &context->mm)
 		etnaviv_iommu_remove_mapping(context, mapping);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
@@ -105,9 +105,11 @@
 struct etnaviv_iommu_context *
 etnaviv_iommu_context_init(struct etnaviv_iommu_global *global,
 			   struct etnaviv_cmdbuf_suballoc *suballoc);
-static inline void etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx)
+static inline struct etnaviv_iommu_context *
+etnaviv_iommu_context_get(struct etnaviv_iommu_context *ctx)
 {
 	kref_get(&ctx->refcount);
+	return ctx;
 }
 void etnaviv_iommu_context_put(struct etnaviv_iommu_context *ctx);
 void etnaviv_iommu_restore(struct etnaviv_gpu *gpu,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
@@ -32,6 +32,7 @@
 };
 
 struct etnaviv_pm_domain_meta {
+	unsigned int feature;
 	const struct etnaviv_pm_domain *domains;
 	u32 nr_domains;
 };
@@ -410,36 +411,78 @@
 
 static const struct etnaviv_pm_domain_meta doms_meta[] = {
 	{
+		.feature = chipFeatures_PIPE_3D,
 		.nr_domains = ARRAY_SIZE(doms_3d),
 		.domains = &doms_3d[0]
 	},
 	{
+		.feature = chipFeatures_PIPE_2D,
 		.nr_domains = ARRAY_SIZE(doms_2d),
 		.domains = &doms_2d[0]
 	},
 	{
+		.feature = chipFeatures_PIPE_VG,
 		.nr_domains = ARRAY_SIZE(doms_vg),
 		.domains = &doms_vg[0]
 	}
 };
 
+static unsigned int num_pm_domains(const struct etnaviv_gpu *gpu)
+{
+	unsigned int num = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(doms_meta); i++) {
+		const struct etnaviv_pm_domain_meta *meta = &doms_meta[i];
+
+		if (gpu->identity.features & meta->feature)
+			num += meta->nr_domains;
+	}
+
+	return num;
+}
+
+static const struct etnaviv_pm_domain *pm_domain(const struct etnaviv_gpu *gpu,
+	unsigned int index)
+{
+	const struct etnaviv_pm_domain *domain = NULL;
+	unsigned int offset = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(doms_meta); i++) {
+		const struct etnaviv_pm_domain_meta *meta = &doms_meta[i];
+
+		if (!(gpu->identity.features & meta->feature))
+			continue;
+
+		if (index - offset >= meta->nr_domains) {
+			offset += meta->nr_domains;
+			continue;
+		}
+
+		domain = meta->domains + (index - offset);
+	}
+
+	return domain;
+}
+
 int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
 	struct drm_etnaviv_pm_domain *domain)
 {
-	const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe];
+	const unsigned int nr_domains = num_pm_domains(gpu);
 	const struct etnaviv_pm_domain *dom;
 
-	if (domain->iter >= meta->nr_domains)
+	if (domain->iter >= nr_domains)
 		return -EINVAL;
 
-	dom = meta->domains + domain->iter;
+	dom = pm_domain(gpu, domain->iter);
+	if (!dom)
+		return -EINVAL;
 
 	domain->id = domain->iter;
 	domain->nr_signals = dom->nr_signals;
 	strncpy(domain->name, dom->name, sizeof(domain->name));
 
 	domain->iter++;
-	if (domain->iter == meta->nr_domains)
+	if (domain->iter == nr_domains)
 		domain->iter = 0xff;
 
 	return 0;
@@ -448,14 +491,16 @@
 int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
 	struct drm_etnaviv_pm_signal *signal)
 {
-	const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe];
+	const unsigned int nr_domains = num_pm_domains(gpu);
 	const struct etnaviv_pm_domain *dom;
 	const struct etnaviv_pm_signal *sig;
 
-	if (signal->domain >= meta->nr_domains)
+	if (signal->domain >= nr_domains)
 		return -EINVAL;
 
-	dom = meta->domains + signal->domain;
+	dom = pm_domain(gpu, signal->domain);
+	if (!dom)
+		return -EINVAL;
 
 	if (signal->iter >= dom->nr_signals)
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -89,12 +89,15 @@
 	u32 dma_addr;
 	int change;
 
+	/* block scheduler */
+	drm_sched_stop(&gpu->sched, sched_job);
+
 	/*
 	 * If the GPU managed to complete this jobs fence, the timout is
 	 * spurious. Bail out.
 	 */
 	if (dma_fence_is_signaled(submit->out_fence))
-		return;
+		goto out_no_timeout;
 
 	/*
 	 * If the GPU is still making forward progress on the front-end (which
@@ -105,12 +108,9 @@
 	change = dma_addr - gpu->hangcheck_dma_addr;
 	if (change < 0 || change > 16) {
 		gpu->hangcheck_dma_addr = dma_addr;
-		return;
+		goto out_no_timeout;
 	}
 
-	/* block scheduler */
-	drm_sched_stop(&gpu->sched, sched_job);
-
 	if(sched_job)
 		drm_sched_increase_karma(sched_job);
 
@@ -120,6 +120,7 @@
 
 	drm_sched_resubmit_jobs(&gpu->sched);
 
+out_no_timeout:
 	/* restart scheduler after GPU is usable again */
 	drm_sched_start(&gpu->sched, true);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/state_blt.xml.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/state_blt.xml.h
@@ -46,6 +46,8 @@
 
 /* This is a cut-down version of the state_blt.xml.h file */
 
+#define VIVS_BLT_SET_COMMAND					0x000140ac
+
 #define VIVS_BLT_ENABLE						0x000140b8
 #define VIVS_BLT_ENABLE_ENABLE					0x00000001
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/etnaviv/state_hi.xml.h
+++ linux-ein-5.4.0/drivers/gpu/drm/etnaviv/state_hi.xml.h
@@ -8,17 +8,17 @@
 git clone git://0x04.net/rules-ng-ng
 
 The rules-ng-ng source files this header was generated from are:
-- state.xml     (  26087 bytes, from 2017-12-18 16:51:59)
-- common.xml    (  35468 bytes, from 2018-01-22 13:48:54)
-- common_3d.xml (  14615 bytes, from 2017-12-18 16:51:59)
-- state_hi.xml  (  30232 bytes, from 2018-02-15 15:48:01)
-- copyright.xml (   1597 bytes, from 2016-12-08 16:37:56)
-- state_2d.xml  (  51552 bytes, from 2016-12-08 16:37:56)
-- state_3d.xml  (  79992 bytes, from 2017-12-18 16:51:59)
-- state_blt.xml (  13405 bytes, from 2017-12-18 16:51:59)
-- state_vg.xml  (   5975 bytes, from 2016-12-08 16:37:56)
+- state.xml     (  26666 bytes, from 2019-12-20 21:20:35)
+- common.xml    (  35468 bytes, from 2018-02-10 13:09:26)
+- common_3d.xml (  15058 bytes, from 2019-12-28 20:02:03)
+- state_hi.xml  (  30552 bytes, from 2019-12-28 20:02:48)
+- copyright.xml (   1597 bytes, from 2018-02-10 13:09:26)
+- state_2d.xml  (  51552 bytes, from 2018-02-10 13:09:26)
+- state_3d.xml  (  83098 bytes, from 2019-12-28 20:02:03)
+- state_blt.xml (  14252 bytes, from 2019-10-20 19:59:15)
+- state_vg.xml  (   5975 bytes, from 2018-02-10 13:09:26)
 
-Copyright (C) 2012-2018 by the following authors:
+Copyright (C) 2012-2019 by the following authors:
 - Wladimir J. van der Laan <laanwj@gmail.com>
 - Christian Gmeiner <christian.gmeiner@gmail.com>
 - Lucas Stach <l.stach@pengutronix.de>
@@ -48,6 +48,9 @@
 #define MMU_EXCEPTION_SLAVE_NOT_PRESENT				0x00000001
 #define MMU_EXCEPTION_PAGE_NOT_PRESENT				0x00000002
 #define MMU_EXCEPTION_WRITE_VIOLATION				0x00000003
+#define MMU_EXCEPTION_OUT_OF_BOUND				0x00000004
+#define MMU_EXCEPTION_READ_SECURITY_VIOLATION			0x00000005
+#define MMU_EXCEPTION_WRITE_SECURITY_VIOLATION			0x00000006
 #define VIVS_HI							0x00000000
 
 #define VIVS_HI_CLOCK_CONTROL					0x00000000
@@ -81,6 +84,13 @@
 #define VIVS_HI_IDLE_STATE_IM					0x00000200
 #define VIVS_HI_IDLE_STATE_FP					0x00000400
 #define VIVS_HI_IDLE_STATE_TS					0x00000800
+#define VIVS_HI_IDLE_STATE_BL					0x00001000
+#define VIVS_HI_IDLE_STATE_ASYNCFE				0x00002000
+#define VIVS_HI_IDLE_STATE_MC					0x00004000
+#define VIVS_HI_IDLE_STATE_PPA					0x00008000
+#define VIVS_HI_IDLE_STATE_WD					0x00010000
+#define VIVS_HI_IDLE_STATE_NN					0x00020000
+#define VIVS_HI_IDLE_STATE_TP					0x00040000
 #define VIVS_HI_IDLE_STATE_AXI_LP				0x80000000
 
 #define VIVS_HI_AXI_CONFIG					0x00000008
@@ -140,6 +150,8 @@
 
 #define VIVS_HI_CHIP_TIME					0x0000002c
 
+#define VIVS_HI_CHIP_CUSTOMER_ID				0x00000030
+
 #define VIVS_HI_CHIP_MINOR_FEATURE_0				0x00000034
 
 #define VIVS_HI_CACHE_CONTROL					0x00000038
@@ -237,6 +249,8 @@
 
 #define VIVS_HI_BLT_INTR					0x000000d4
 
+#define VIVS_HI_CHIP_ECO_ID					0x000000e8
+
 #define VIVS_HI_AUXBIT						0x000000ec
 
 #define VIVS_PM							0x00000000
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -55,6 +55,7 @@
 struct decon_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
+	void				*dma_priv;
 	struct exynos_drm_crtc		*crtc;
 	struct exynos_drm_plane		planes[WINDOWS_NR];
 	struct exynos_drm_plane_config	configs[WINDOWS_NR];
@@ -317,9 +318,9 @@
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
 				 struct drm_framebuffer *fb)
 {
-	struct exynos_drm_plane plane = ctx->planes[win];
+	struct exynos_drm_plane *plane = &ctx->planes[win];
 	struct exynos_drm_plane_state *state =
-		to_exynos_plane_state(plane.base.state);
+		to_exynos_plane_state(plane->base.state);
 	unsigned int alpha = state->base.alpha;
 	unsigned int pixel_alpha;
 	unsigned long val;
@@ -644,7 +645,7 @@
 
 	decon_clear_channels(ctx->crtc);
 
-	return exynos_drm_register_dma(drm_dev, dev);
+	return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static void decon_unbind(struct device *dev, struct device *master, void *data)
@@ -654,7 +655,7 @@
 	decon_disable(ctx->crtc);
 
 	/* detach this sub driver from iommu mapping if supported. */
-	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static const struct component_ops decon_component_ops = {
@@ -774,8 +775,8 @@
 			return irq;
 		}
 	}
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = devm_request_irq(ctx->dev, irq, handler, flags, "drm_decon", ctx);
+	ret = devm_request_irq(ctx->dev, irq, handler,
+			       flags | IRQF_NO_AUTOEN, "drm_decon", ctx);
 	if (ret < 0) {
 		dev_err(ctx->dev, "IRQ %s request failed\n", name);
 		return ret;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -40,6 +40,7 @@
 struct decon_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
+	void				*dma_priv;
 	struct exynos_drm_crtc		*crtc;
 	struct exynos_drm_plane		planes[WINDOWS_NR];
 	struct exynos_drm_plane_config	configs[WINDOWS_NR];
@@ -127,13 +128,13 @@
 
 	decon_clear_channels(ctx->crtc);
 
-	return exynos_drm_register_dma(drm_dev, ctx->dev);
+	return exynos_drm_register_dma(drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static void decon_ctx_remove(struct decon_context *ctx)
 {
 	/* detach this sub driver from iommu mapping if supported. */
-	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static u32 decon_calc_clkdiv(struct decon_context *ctx,
@@ -799,31 +800,40 @@
 	if (ret < 0) {
 		DRM_DEV_ERROR(dev, "Failed to prepare_enable the pclk [%d]\n",
 			      ret);
-		return ret;
+		goto err_pclk_enable;
 	}
 
 	ret = clk_prepare_enable(ctx->aclk);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dev, "Failed to prepare_enable the aclk [%d]\n",
 			      ret);
-		return ret;
+		goto err_aclk_enable;
 	}
 
 	ret = clk_prepare_enable(ctx->eclk);
 	if  (ret < 0) {
 		DRM_DEV_ERROR(dev, "Failed to prepare_enable the eclk [%d]\n",
 			      ret);
-		return ret;
+		goto err_eclk_enable;
 	}
 
 	ret = clk_prepare_enable(ctx->vclk);
 	if  (ret < 0) {
 		DRM_DEV_ERROR(dev, "Failed to prepare_enable the vclk [%d]\n",
 			      ret);
-		return ret;
+		goto err_vclk_enable;
 	}
 
 	return 0;
+
+err_vclk_enable:
+	clk_disable_unprepare(ctx->eclk);
+err_eclk_enable:
+	clk_disable_unprepare(ctx->aclk);
+err_aclk_enable:
+	clk_disable_unprepare(ctx->pclk);
+err_pclk_enable:
+	return ret;
 }
 #endif
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_dp.c
@@ -109,7 +109,6 @@
 		if (ret) {
 			DRM_DEV_ERROR(dp->dev,
 				      "Failed to attach bridge to drm\n");
-			bridge->next = NULL;
 			return ret;
 		}
 	}
@@ -158,15 +157,8 @@
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
-	dp->plat_data.dev_type = EXYNOS_DP;
-	dp->plat_data.power_on_start = exynos_dp_poweron;
-	dp->plat_data.power_off = exynos_dp_poweroff;
-	dp->plat_data.attach = exynos_dp_bridge_attach;
-	dp->plat_data.get_modes = exynos_dp_get_modes;
-
 	if (!dp->plat_data.panel && !dp->ptn_bridge) {
 		ret = exynos_dp_dt_parse_panel(dp);
 		if (ret)
@@ -184,13 +176,11 @@
 
 	dp->plat_data.encoder = encoder;
 
-	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp)) {
+	ret = analogix_dp_bind(dp->adp, dp->drm_dev);
+	if (ret)
 		dp->encoder.funcs->destroy(&dp->encoder);
-		return PTR_ERR(dp->adp);
-	}
 
-	return 0;
+	return ret;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -221,6 +211,7 @@
 	if (!dp)
 		return -ENOMEM;
 
+	dp->dev = dev;
 	/*
 	 * We just use the drvdata until driver run into component
 	 * add function, and then we would set drvdata to null, so
@@ -246,16 +237,29 @@
 
 	/* The remote port can be either a panel or a bridge */
 	dp->plat_data.panel = panel;
+	dp->plat_data.dev_type = EXYNOS_DP;
+	dp->plat_data.power_on_start = exynos_dp_poweron;
+	dp->plat_data.power_off = exynos_dp_poweroff;
+	dp->plat_data.attach = exynos_dp_bridge_attach;
+	dp->plat_data.get_modes = exynos_dp_get_modes;
 	dp->plat_data.skip_connector = !!bridge;
+
 	dp->ptn_bridge = bridge;
 
 out:
+	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
 	return component_add(&pdev->dev, &exynos_dp_ops);
 }
 
 static int exynos_dp_remove(struct platform_device *pdev)
 {
+	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
 	component_del(&pdev->dev, &exynos_dp_ops);
+	analogix_dp_remove(dp->adp);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -39,13 +39,12 @@
 	if (exynos_crtc->ops->disable)
 		exynos_crtc->ops->disable(exynos_crtc);
 
+	spin_lock_irq(&crtc->dev->event_lock);
 	if (crtc->state->event && !crtc->state->active) {
-		spin_lock_irq(&crtc->dev->event_lock);
 		drm_crtc_send_vblank_event(crtc, crtc->state->event);
-		spin_unlock_irq(&crtc->dev->event_lock);
-
 		crtc->state->event = NULL;
 	}
+	spin_unlock_irq(&crtc->dev->event_lock);
 }
 
 static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_dma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_dma.c
@@ -58,10 +58,10 @@
  * mapping.
  */
 static int drm_iommu_attach_device(struct drm_device *drm_dev,
-				struct device *subdrv_dev)
+				struct device *subdrv_dev, void **dma_priv)
 {
 	struct exynos_drm_private *priv = drm_dev->dev_private;
-	int ret;
+	int ret = 0;
 
 	if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
 		DRM_DEV_ERROR(subdrv_dev, "Device %s lacks support for IOMMU\n",
@@ -74,7 +74,14 @@
 		return ret;
 
 	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
-		if (to_dma_iommu_mapping(subdrv_dev))
+		/*
+		 * Keep the original DMA mapping of the sub-device and
+		 * restore it on Exynos DRM detach, otherwise the DMA
+		 * framework considers it as IOMMU-less during the next
+		 * probe (in case of deferred probe or modular build)
+		 */
+		*dma_priv = to_dma_iommu_mapping(subdrv_dev);
+		if (*dma_priv)
 			arm_iommu_detach_device(subdrv_dev);
 
 		ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
@@ -85,7 +92,7 @@
 	if (ret)
 		clear_dma_max_seg_size(subdrv_dev);
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -98,19 +105,21 @@
  * mapping
  */
 static void drm_iommu_detach_device(struct drm_device *drm_dev,
-				struct device *subdrv_dev)
+				    struct device *subdrv_dev, void **dma_priv)
 {
 	struct exynos_drm_private *priv = drm_dev->dev_private;
 
-	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
 		arm_iommu_detach_device(subdrv_dev);
-	else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+		arm_iommu_attach_device(subdrv_dev, *dma_priv);
+	} else if (IS_ENABLED(CONFIG_IOMMU_DMA))
 		iommu_detach_device(priv->mapping, subdrv_dev);
 
 	clear_dma_max_seg_size(subdrv_dev);
 }
 
-int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
+			    void **dma_priv)
 {
 	struct exynos_drm_private *priv = drm->dev_private;
 
@@ -124,7 +133,7 @@
 		return 0;
 
 	if (!priv->mapping) {
-		void *mapping;
+		void *mapping = NULL;
 
 		if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
 			mapping = arm_iommu_create_mapping(&platform_bus_type,
@@ -132,18 +141,19 @@
 		else if (IS_ENABLED(CONFIG_IOMMU_DMA))
 			mapping = iommu_get_domain_for_dev(priv->dma_dev);
 
-		if (IS_ERR(mapping))
-			return PTR_ERR(mapping);
+		if (!mapping)
+			return -ENODEV;
 		priv->mapping = mapping;
 	}
 
-	return drm_iommu_attach_device(drm, dev);
+	return drm_iommu_attach_device(drm, dev, dma_priv);
 }
 
-void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
+			       void **dma_priv)
 {
 	if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
-		drm_iommu_detach_device(drm, dev);
+		drm_iommu_detach_device(drm, dev, dma_priv);
 }
 
 void exynos_drm_cleanup_dma(struct drm_device *drm)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -346,6 +346,7 @@
 	drm_mode_config_cleanup(drm);
 	exynos_drm_cleanup_dma(drm);
 	kfree(private);
+	dev_set_drvdata(dev, NULL);
 err_free_drm:
 	drm_dev_put(drm);
 
@@ -360,6 +361,7 @@
 
 	exynos_drm_fbdev_fini(drm);
 	drm_kms_helper_poll_fini(drm);
+	drm_atomic_helper_shutdown(drm);
 
 	component_unbind_all(drm->dev, drm);
 	drm_mode_config_cleanup(drm);
@@ -397,9 +399,18 @@
 	return 0;
 }
 
+static void exynos_drm_platform_shutdown(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+
+	if (drm)
+		drm_atomic_helper_shutdown(drm);
+}
+
 static struct platform_driver exynos_drm_platform_driver = {
 	.probe	= exynos_drm_platform_probe,
 	.remove	= exynos_drm_platform_remove,
+	.shutdown = exynos_drm_platform_shutdown,
 	.driver	= {
 		.name	= "exynos-drm",
 		.pm	= &exynos_drm_pm_ops,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -223,8 +223,10 @@
 	return priv->mapping ? true : false;
 }
 
-int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
-void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
+			    void **dma_priv);
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
+			       void **dma_priv);
 void exynos_drm_cleanup_dma(struct drm_device *drm);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -544,9 +544,9 @@
 	unsigned long best_freq = 0;
 	u32 min_delta = 0xffffffff;
 	u8 p_min, p_max;
-	u8 _p, uninitialized_var(best_p);
-	u16 _m, uninitialized_var(best_m);
-	u8 _s, uninitialized_var(best_s);
+	u8 _p, best_p;
+	u16 _m, best_m;
+	u8 _s, best_s;
 
 	p_min = DIV_ROUND_UP(fin, (12 * MHZ));
 	p_max = fin / (6 * MHZ);
@@ -1350,10 +1350,9 @@
 	}
 
 	te_gpio_irq = gpio_to_irq(dsi->te_gpio);
-	irq_set_status_flags(te_gpio_irq, IRQ_NOAUTOEN);
 
 	ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL,
-					IRQF_TRIGGER_RISING, "TE", dsi);
+				   IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, "TE", dsi);
 	if (ret) {
 		dev_err(dsi->dev, "request interrupt failed with %d\n", ret);
 		gpio_free(dsi->te_gpio);
@@ -1389,7 +1388,7 @@
 		if (ret < 0)
 			goto err_put_sync;
 	} else {
-		drm_bridge_pre_enable(dsi->out_bridge);
+		drm_bridge_chain_pre_enable(dsi->out_bridge);
 	}
 
 	exynos_dsi_set_display_mode(dsi);
@@ -1400,7 +1399,7 @@
 		if (ret < 0)
 			goto err_display_disable;
 	} else {
-		drm_bridge_enable(dsi->out_bridge);
+		drm_bridge_chain_enable(dsi->out_bridge);
 	}
 
 	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
@@ -1425,10 +1424,10 @@
 	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
 
 	drm_panel_disable(dsi->panel);
-	drm_bridge_disable(dsi->out_bridge);
+	drm_bridge_chain_disable(dsi->out_bridge);
 	exynos_dsi_set_display_enable(dsi, false);
 	drm_panel_unprepare(dsi->panel);
-	drm_bridge_post_disable(dsi->out_bridge);
+	drm_bridge_chain_post_disable(dsi->out_bridge);
 	dsi->state &= ~DSIM_STATE_ENABLED;
 	pm_runtime_put_sync(dsi->dev);
 }
@@ -1741,17 +1740,14 @@
 	dsi->dev = dev;
 	dsi->driver_data = of_device_get_match_data(dev);
 
-	ret = exynos_dsi_parse_dt(dsi);
-	if (ret)
-		return ret;
-
 	dsi->supplies[0].supply = "vddcore";
 	dsi->supplies[1].supply = "vddio";
 	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_kcalloc(dev,
@@ -1764,9 +1760,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",
@@ -1794,20 +1791,34 @@
 		return dsi->irq;
 	}
 
-	irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
 	ret = devm_request_threaded_irq(dev, dsi->irq, NULL,
-					exynos_dsi_irq, IRQF_ONESHOT,
+					exynos_dsi_irq,
+					IRQF_ONESHOT | IRQF_NO_AUTOEN,
 					dev_name(dev), dsi);
 	if (ret) {
 		dev_err(dev, "failed to request dsi irq\n");
 		return ret;
 	}
 
+	ret = exynos_dsi_parse_dt(dsi);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, &dsi->encoder);
 
 	pm_runtime_enable(dev);
 
-	return component_add(dev, &exynos_dsi_component_ops);
+	ret = component_add(dev, &exynos_dsi_component_ops);
+	if (ret)
+		goto err_disable_runtime;
+
+	return 0;
+
+err_disable_runtime:
+	pm_runtime_disable(dev);
+	of_node_put(dsi->in_bridge_node);
+
+	return ret;
 }
 
 static int exynos_dsi_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -97,6 +97,7 @@
 struct fimc_context {
 	struct exynos_drm_ipp ipp;
 	struct drm_device *drm_dev;
+	void		*dma_priv;
 	struct device	*dev;
 	struct exynos_drm_ipp_task	*task;
 	struct exynos_drm_ipp_formats	*formats;
@@ -1133,7 +1134,7 @@
 
 	ctx->drm_dev = drm_dev;
 	ipp->drm_dev = drm_dev;
-	exynos_drm_register_dma(drm_dev, dev);
+	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 
 	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
 			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1153,7 +1154,7 @@
 	struct exynos_drm_ipp *ipp = &ctx->ipp;
 
 	exynos_drm_ipp_unregister(dev, ipp);
-	exynos_drm_unregister_dma(drm_dev, dev);
+	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static const struct component_ops fimc_component_ops = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -167,6 +167,7 @@
 struct fimd_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
+	void				*dma_priv;
 	struct exynos_drm_crtc		*crtc;
 	struct exynos_drm_plane		planes[WINDOWS_NR];
 	struct exynos_drm_plane_config	configs[WINDOWS_NR];
@@ -636,9 +637,9 @@
 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
 				struct drm_framebuffer *fb, int width)
 {
-	struct exynos_drm_plane plane = ctx->planes[win];
+	struct exynos_drm_plane *plane = &ctx->planes[win];
 	struct exynos_drm_plane_state *state =
-		to_exynos_plane_state(plane.base.state);
+		to_exynos_plane_state(plane->base.state);
 	uint32_t pixel_format = fb->format->format;
 	unsigned int alpha = state->base.alpha;
 	u32 val = WINCONx_ENWIN;
@@ -1090,7 +1091,7 @@
 	if (is_drm_iommu_supported(drm_dev))
 		fimd_clear_channels(ctx->crtc);
 
-	return exynos_drm_register_dma(drm_dev, dev);
+	return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static void fimd_unbind(struct device *dev, struct device *master,
@@ -1100,7 +1101,7 @@
 
 	fimd_disable(ctx->crtc);
 
-	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 
 	if (ctx->encoder)
 		exynos_dpi_remove(ctx->encoder);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -232,6 +232,7 @@
 
 struct g2d_data {
 	struct device			*dev;
+	void				*dma_priv;
 	struct clk			*gate_clk;
 	void __iomem			*regs;
 	int				irq;
@@ -1331,7 +1332,7 @@
 	/* Let the runqueue know that there is work to do. */
 	queue_work(g2d->g2d_workq, &g2d->runqueue_work);
 
-	if (runqueue_node->async)
+	if (req->async)
 		goto out;
 
 	wait_for_completion(&runqueue_node->complete);
@@ -1409,7 +1410,7 @@
 		return ret;
 	}
 
-	ret = exynos_drm_register_dma(drm_dev, dev);
+	ret = exynos_drm_register_dma(drm_dev, dev, &g2d->dma_priv);
 	if (ret < 0) {
 		dev_err(dev, "failed to enable iommu.\n");
 		g2d_fini_cmdlist(g2d);
@@ -1434,7 +1435,7 @@
 	priv->g2d_dev = NULL;
 
 	cancel_work_sync(&g2d->runqueue_work);
-	exynos_drm_unregister_dma(g2d->drm_dev, dev);
+	exynos_drm_unregister_dma(g2d->drm_dev, dev, &g2d->dma_priv);
 }
 
 static const struct component_ops g2d_component_ops = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_g2d.h
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_g2d.h
@@ -34,11 +34,11 @@
 	return -ENODEV;
 }
 
-int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
+static inline int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
 {
 	return 0;
 }
 
-void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
+static inline void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
 { }
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -97,6 +97,7 @@
 struct gsc_context {
 	struct exynos_drm_ipp ipp;
 	struct drm_device *drm_dev;
+	void		*dma_priv;
 	struct device	*dev;
 	struct exynos_drm_ipp_task	*task;
 	struct exynos_drm_ipp_formats	*formats;
@@ -1169,7 +1170,7 @@
 
 	ctx->drm_dev = drm_dev;
 	ctx->drm_dev = drm_dev;
-	exynos_drm_register_dma(drm_dev, dev);
+	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 
 	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
 			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1189,7 +1190,7 @@
 	struct exynos_drm_ipp *ipp = &ctx->ipp;
 
 	exynos_drm_ipp_unregister(dev, ipp);
-	exynos_drm_unregister_dma(drm_dev, dev);
+	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static const struct component_ops gsc_component_ops = {
@@ -1313,6 +1314,7 @@
 {
 	struct device *dev = &pdev->dev;
 
+	component_del(dev, &gsc_component_ops);
 	pm_runtime_dont_use_autosuspend(dev);
 	pm_runtime_disable(dev);
 
@@ -1342,7 +1344,7 @@
 	for (i = 0; i < ctx->num_clocks; i++) {
 		ret = clk_prepare_enable(ctx->clocks[i]);
 		if (ret) {
-			while (--i > 0)
+			while (--i >= 0)
 				clk_disable_unprepare(ctx->clocks[i]);
 			return ret;
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -268,8 +268,10 @@
 		goto unlock;
 
 	ret = pm_runtime_get_sync(mic->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(mic->dev);
 		goto unlock;
+	}
 
 	mic_set_path(mic, 1);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -56,6 +56,7 @@
 struct rot_context {
 	struct exynos_drm_ipp ipp;
 	struct drm_device *drm_dev;
+	void		*dma_priv;
 	struct device	*dev;
 	void __iomem	*regs;
 	struct clk	*clock;
@@ -243,7 +244,7 @@
 
 	rot->drm_dev = drm_dev;
 	ipp->drm_dev = drm_dev;
-	exynos_drm_register_dma(drm_dev, dev);
+	exynos_drm_register_dma(drm_dev, dev, &rot->dma_priv);
 
 	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
 			   DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
@@ -261,7 +262,7 @@
 	struct exynos_drm_ipp *ipp = &rot->ipp;
 
 	exynos_drm_ipp_unregister(dev, ipp);
-	exynos_drm_unregister_dma(rot->drm_dev, rot->dev);
+	exynos_drm_unregister_dma(rot->drm_dev, rot->dev, &rot->dma_priv);
 }
 
 static const struct component_ops rotator_component_ops = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_scaler.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_scaler.c
@@ -39,6 +39,7 @@
 struct scaler_context {
 	struct exynos_drm_ipp		ipp;
 	struct drm_device		*drm_dev;
+	void				*dma_priv;
 	struct device			*dev;
 	void __iomem			*regs;
 	struct clk			*clock[SCALER_MAX_CLK];
@@ -450,7 +451,7 @@
 
 	scaler->drm_dev = drm_dev;
 	ipp->drm_dev = drm_dev;
-	exynos_drm_register_dma(drm_dev, dev);
+	exynos_drm_register_dma(drm_dev, dev, &scaler->dma_priv);
 
 	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
 			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -470,7 +471,8 @@
 	struct exynos_drm_ipp *ipp = &scaler->ipp;
 
 	exynos_drm_ipp_unregister(dev, ipp);
-	exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev);
+	exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev,
+				  &scaler->dma_priv);
 }
 
 static const struct component_ops scaler_component_ops = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -483,8 +483,6 @@
 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 		kfree(ctx->raw_edid);
 		ctx->raw_edid = NULL;
-
-		return -EINVAL;
 	}
 
 	component_del(&pdev->dev, &vidi_component_ops);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -852,6 +852,10 @@
 
 static void hdmi_connector_destroy(struct drm_connector *connector)
 {
+	struct hdmi_context *hdata = connector_to_hdmi(connector);
+
+	cec_notifier_conn_unregister(hdata->notifier);
+
 	drm_connector_unregister(connector);
 	drm_connector_cleanup(connector);
 }
@@ -935,6 +939,7 @@
 {
 	struct hdmi_context *hdata = encoder_to_hdmi(encoder);
 	struct drm_connector *connector = &hdata->connector;
+	struct cec_connector_info conn_info;
 	int ret;
 
 	connector->interlace_allowed = true;
@@ -957,6 +962,15 @@
 			DRM_DEV_ERROR(hdata->dev, "Failed to attach bridge\n");
 	}
 
+	cec_fill_conn_info_from_drm(&conn_info, connector);
+
+	hdata->notifier = cec_notifier_conn_register(hdata->dev, NULL,
+						     &conn_info);
+	if (!hdata->notifier) {
+		ret = -ENOMEM;
+		DRM_DEV_ERROR(hdata->dev, "Failed to allocate CEC notifier\n");
+	}
+
 	return ret;
 }
 
@@ -1528,8 +1542,8 @@
 		 */
 		mutex_unlock(&hdata->mutex);
 		cancel_delayed_work(&hdata->hotplug_work);
-		cec_notifier_set_phys_addr(hdata->notifier,
-					   CEC_PHYS_ADDR_INVALID);
+		if (hdata->notifier)
+			cec_notifier_phys_addr_invalidate(hdata->notifier);
 		return;
 	}
 
@@ -1788,18 +1802,10 @@
 
 	hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
 
-	if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) {
+	if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV)
 		if (IS_ERR(hdata->reg_hdmi_en))
 			return PTR_ERR(hdata->reg_hdmi_en);
 
-		ret = regulator_enable(hdata->reg_hdmi_en);
-		if (ret) {
-			DRM_DEV_ERROR(dev,
-				      "failed to enable hdmi-en regulator\n");
-			return ret;
-		}
-	}
-
 	return hdmi_bridge_init(hdata);
 }
 
@@ -1844,6 +1850,8 @@
 		return ret;
 
 	crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI);
+	if (IS_ERR(crtc))
+		return PTR_ERR(crtc);
 	crtc->pipe_clk = &hdata->phy_clk;
 
 	ret = hdmi_create_connector(encoder);
@@ -2006,10 +2014,13 @@
 		}
 	}
 
-	hdata->notifier = cec_notifier_get(&pdev->dev);
-	if (hdata->notifier == NULL) {
-		ret = -ENOMEM;
-		goto err_hdmiphy;
+	if (!IS_ERR(hdata->reg_hdmi_en)) {
+		ret = regulator_enable(hdata->reg_hdmi_en);
+		if (ret) {
+			DRM_DEV_ERROR(dev,
+			      "failed to enable hdmi-en regulator\n");
+			goto err_hdmiphy;
+		}
 	}
 
 	pm_runtime_enable(dev);
@@ -2023,7 +2034,7 @@
 
 	ret = hdmi_register_audio_device(hdata);
 	if (ret)
-		goto err_notifier_put;
+		goto err_rpm_disable;
 
 	ret = component_add(&pdev->dev, &hdmi_component_ops);
 	if (ret)
@@ -2034,10 +2045,10 @@
 err_unregister_audio:
 	platform_device_unregister(hdata->audio.pdev);
 
-err_notifier_put:
-	cec_notifier_put(hdata->notifier);
+err_rpm_disable:
 	pm_runtime_disable(dev);
-
+	if (!IS_ERR(hdata->reg_hdmi_en))
+		regulator_disable(hdata->reg_hdmi_en);
 err_hdmiphy:
 	if (hdata->hdmiphy_port)
 		put_device(&hdata->hdmiphy_port->dev);
@@ -2054,12 +2065,10 @@
 	struct hdmi_context *hdata = platform_get_drvdata(pdev);
 
 	cancel_delayed_work_sync(&hdata->hotplug_work);
-	cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID);
 
 	component_del(&pdev->dev, &hdmi_component_ops);
 	platform_device_unregister(hdata->audio.pdev);
 
-	cec_notifier_put(hdata->notifier);
 	pm_runtime_disable(&pdev->dev);
 
 	if (!IS_ERR(hdata->reg_hdmi_en))
--- linux-ein-5.4.0.orig/drivers/gpu/drm/exynos/exynos_mixer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -94,6 +94,7 @@
 	struct platform_device *pdev;
 	struct device		*dev;
 	struct drm_device	*drm_dev;
+	void			*dma_priv;
 	struct exynos_drm_crtc	*crtc;
 	struct exynos_drm_plane	planes[MIXER_WIN_NR];
 	unsigned long		flags;
@@ -894,12 +895,14 @@
 		}
 	}
 
-	return exynos_drm_register_dma(drm_dev, mixer_ctx->dev);
+	return exynos_drm_register_dma(drm_dev, mixer_ctx->dev,
+				       &mixer_ctx->dma_priv);
 }
 
 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
 {
-	exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev);
+	exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev,
+				  &mixer_ctx->dma_priv);
 }
 
 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -12,19 +12,11 @@
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
 
 #include "fsl_dcu_drm_drv.h"
 #include "fsl_tcon.h"
 
-static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
-{
-	drm_encoder_cleanup(encoder);
-}
-
-static const struct drm_encoder_funcs encoder_funcs = {
-	.destroy = fsl_dcu_drm_encoder_destroy,
-};
-
 int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
 			       struct drm_crtc *crtc)
 {
@@ -37,8 +29,8 @@
 	if (fsl_dev->tcon)
 		fsl_tcon_bypass_enable(fsl_dev->tcon);
 
-	ret = drm_encoder_init(fsl_dev->drm, encoder, &encoder_funcs,
-			       DRM_MODE_ENCODER_LVDS, NULL);
+	ret = drm_simple_encoder_init(fsl_dev->drm, encoder,
+				      DRM_MODE_ENCODER_LVDS);
 	if (ret < 0)
 		return ret;
 
@@ -70,8 +62,9 @@
 	return drm_panel_get_modes(fsl_connector->panel);
 }
 
-static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector,
-					    struct drm_display_mode *mode)
+static enum drm_mode_status
+fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector,
+				 struct drm_display_mode *mode)
 {
 	if (mode->hdisplay & 0xf)
 		return MODE_ERROR;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -405,6 +405,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-ein-5.4.0.orig/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -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-ein-5.4.0.orig/drivers/gpu/drm/gma500/framebuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/framebuffer.c
@@ -462,6 +462,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;
@@ -471,8 +472,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-ein-5.4.0.orig/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -129,6 +129,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;
@@ -185,6 +186,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-ein-5.4.0.orig/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/gpu/drm/gma500/psb_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/psb_drv.c
@@ -313,6 +313,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;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/gma500/psb_intel_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -532,14 +532,15 @@
 
 struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
 {
-	struct drm_crtc *crtc = NULL;
+	struct drm_crtc *crtc;
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
+
 		if (gma_crtc->pipe == pipe)
-			break;
+			return crtc;
 	}
-	return crtc;
+	return NULL;
 }
 
 int gma_connector_clones(struct drm_device *dev, int type_mask)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/gma500/psb_irq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/gma500/psb_irq.c
@@ -337,6 +337,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
+	unsigned int i;
 
 	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
@@ -349,20 +350,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);
@@ -375,6 +368,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
+	unsigned int i;
 
 	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
@@ -383,14 +377,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-ein-5.4.0.orig/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -376,7 +376,6 @@
 
 	drm_dev_unregister(dev);
 	hibmc_unload(dev);
-	drm_dev_put(dev);
 }
 
 static struct pci_device_id hibmc_pci_table[] = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
+++ linux-ein-5.4.0/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
@@ -83,7 +83,6 @@
 #define VSIZE_OFST			20
 #define LDI_INT_EN			0x741C
 #define FRAME_END_INT_EN_OFST		1
-#define UNDERFLOW_INT_EN_OFST		2
 #define LDI_CTRL			0x7420
 #define BPP_OFST			3
 #define DATA_GATE_EN			BIT(2)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ linux-ein-5.4.0/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -46,7 +46,6 @@
 	struct clk *media_noc_clk;
 	struct clk *ade_pix_clk;
 	struct reset_control *reset;
-	struct work_struct display_reset_wq;
 	bool power_on;
 	int irq;
 
@@ -136,7 +135,6 @@
 	 */
 	ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
 			FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
-	ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1);
 }
 
 static bool ade_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -304,17 +302,6 @@
 			MASK(1), 0);
 }
 
-static void drm_underflow_wq(struct work_struct *work)
-{
-	struct ade_hw_ctx *ctx = container_of(work, struct ade_hw_ctx,
-					      display_reset_wq);
-	struct drm_device *drm_dev = ctx->crtc->dev;
-	struct drm_atomic_state *state;
-
-	state = drm_atomic_helper_suspend(drm_dev);
-	drm_atomic_helper_resume(drm_dev, state);
-}
-
 static irqreturn_t ade_irq_handler(int irq, void *data)
 {
 	struct ade_hw_ctx *ctx = data;
@@ -331,12 +318,6 @@
 				MASK(1), 1);
 		drm_crtc_handle_vblank(crtc);
 	}
-	if (status & BIT(UNDERFLOW_INT_EN_OFST)) {
-		ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST,
-				MASK(1), 1);
-		DRM_ERROR("LDI underflow!");
-		schedule_work(&ctx->display_reset_wq);
-	}
 
 	return IRQ_HANDLED;
 }
@@ -919,7 +900,6 @@
 	if (ret)
 		return ERR_PTR(-EIO);
 
-	INIT_WORK(&ctx->display_reset_wq, drm_underflow_wq);
 	ctx->crtc = crtc;
 
 	return ctx;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i810/i810_dma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i810/i810_dma.c
@@ -728,7 +728,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)
@@ -1048,7 +1048,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-ein-5.4.0.orig/drivers/gpu/drm/i915/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/Kconfig
@@ -75,9 +75,8 @@
 	help
 	  This option enables capturing the GPU state when a hang is detected.
 	  This information is vital for triaging hangs and assists in debugging.
-	  Please report any hang to
-            https://bugs.freedesktop.org/enter_bug.cgi?product=DRI
-	  for triaging.
+	  Please report any hang for triaging according to:
+	    https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
 
 	  If in doubt, say "Y".
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/Kconfig.debug
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/Kconfig.debug
@@ -7,7 +7,6 @@
         # We use the dependency on !COMPILE_TEST to not be enabled in
         # allmodconfig or allyesconfig configurations
         depends on !COMPILE_TEST
-	select HEADER_TEST
         default n
         help
           Add -Werror to the build flags for (and only for) i915.ko.
@@ -22,7 +21,6 @@
         depends on DRM_I915
         select DEBUG_FS
         select PREEMPT_COUNT
-        select REFCOUNT_FULL
         select I2C_CHARDEV
         select STACKDEPOT
         select DRM_DP_AUX_CHARDEV
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/Makefile
@@ -83,6 +83,7 @@
 	gt/intel_gt_irq.o \
 	gt/intel_gt_pm.o \
 	gt/intel_gt_pm_irq.o \
+	gt/intel_gt_requests.o \
 	gt/intel_hangcheck.o \
 	gt/intel_lrc.o \
 	gt/intel_renderstate.o \
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_acpi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_acpi.c
@@ -83,13 +83,31 @@
 		return;
 	}
 
+	if (!pkg->package.count) {
+		DRM_DEBUG_DRIVER("no connection in _DSM\n");
+		return;
+	}
+
 	connector_count = &pkg->package.elements[0];
 	DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
 		  (unsigned long long)connector_count->integer.value);
 	for (i = 1; i < pkg->package.count; i++) {
 		union acpi_object *obj = &pkg->package.elements[i];
-		union acpi_object *connector_id = &obj->package.elements[0];
-		union acpi_object *info = &obj->package.elements[1];
+		union acpi_object *connector_id;
+		union acpi_object *info;
+
+		if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
+			DRM_DEBUG_DRIVER("Invalid object for MUX #%d\n", i);
+			continue;
+		}
+
+		connector_id = &obj->package.elements[0];
+		info = &obj->package.elements[1];
+		if (info->type != ACPI_TYPE_BUFFER || info->buffer.length < 4) {
+			DRM_DEBUG_DRIVER("Invalid info for MUX obj #%d\n", i);
+			continue;
+		}
+
 		DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
 			  (unsigned long long)connector_id->integer.value);
 		DRM_DEBUG_DRIVER("  port id: %s\n",
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_audio.c
@@ -851,10 +851,16 @@
 	ret = intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
 
 	/* Force CDCLK to 2*BCLK as long as we need audio to be powered. */
-	if (dev_priv->audio_power_refcount++ == 0)
-		if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+	if (dev_priv->audio_power_refcount++ == 0) {
+		if (IS_GEMINILAKE(dev_priv))
 			glk_force_audio_cdclk(dev_priv, true);
 
+		if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+			I915_WRITE(AUD_PIN_BUF_CTL,
+				   (I915_READ(AUD_PIN_BUF_CTL) |
+				    AUD_PIN_BUF_ENABLE));
+	}
+
 	return ret;
 }
 
@@ -865,7 +871,7 @@
 
 	/* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */
 	if (--dev_priv->audio_power_refcount == 0)
-		if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+		if (IS_GEMINILAKE(dev_priv))
 			glk_force_audio_cdclk(dev_priv, false);
 
 	intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO, cookie);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_bios.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_bios.c
@@ -32,6 +32,7 @@
 #include "display/intel_gmbus.h"
 
 #include "i915_drv.h"
+#include <linux/dmi.h>
 
 #define _INTEL_BIOS_PRIVATE
 #include "intel_vbt_defs.h"
@@ -1828,6 +1829,22 @@
 	return NULL;
 }
 
+#define DRM_DMI_PRODUCT_VERSION 0x6
+
+static void parse_product_info(struct drm_i915_private *dev_priv)
+{
+	const char *product_ver = dmi_get_system_info(DRM_DMI_PRODUCT_VERSION);
+	if (!product_ver)
+		return;
+
+	if (!strncmp(product_ver, "ThinkPad X1", 11)) {
+		DRM_DEBUG_KMS("dmi: %s, Bypassing TMDS_OE write\n", product_ver);
+		dev_priv->bypass_tmds_oe = true;
+	}
+
+	return;
+}
+
 /**
  * intel_bios_init - find VBT and initialize settings from the BIOS
  * @dev_priv: i915 device instance
@@ -1886,6 +1903,8 @@
 	parse_sdvo_device_mapping(dev_priv, bdb->version);
 	parse_ddi_ports(dev_priv, bdb->version);
 
+	parse_product_info(dev_priv);
+
 out:
 	if (!vbt) {
 		DRM_INFO("Failed to find VBIOS tables (VBT)\n");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_ddi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -2124,7 +2124,11 @@
 		return;
 
 	dig_port = enc_to_dig_port(&encoder->base);
-	intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
+
+	if (!intel_phy_is_tc(dev_priv, phy) ||
+	    dig_port->tc_mode != TC_PORT_TBT_ALT)
+		intel_display_power_get(dev_priv,
+					dig_port->ddi_io_power_domain);
 
 	/*
 	 * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_display.c
@@ -6753,20 +6753,30 @@
 	    dig_port->tc_mode == TC_PORT_TBT_ALT) {
 		switch (dig_port->aux_ch) {
 		case AUX_CH_C:
-			return POWER_DOMAIN_AUX_TBT1;
+			return POWER_DOMAIN_AUX_C_TBT;
 		case AUX_CH_D:
-			return POWER_DOMAIN_AUX_TBT2;
+			return POWER_DOMAIN_AUX_D_TBT;
 		case AUX_CH_E:
-			return POWER_DOMAIN_AUX_TBT3;
+			return POWER_DOMAIN_AUX_E_TBT;
 		case AUX_CH_F:
-			return POWER_DOMAIN_AUX_TBT4;
+			return POWER_DOMAIN_AUX_F_TBT;
 		default:
 			MISSING_CASE(dig_port->aux_ch);
-			return POWER_DOMAIN_AUX_TBT1;
+			return POWER_DOMAIN_AUX_C_TBT;
 		}
 	}
 
-	switch (dig_port->aux_ch) {
+	return intel_legacy_aux_to_power_domain(dig_port->aux_ch);
+}
+
+/*
+ * Converts aux_ch to power_domain without caring about TBT ports for that use
+ * intel_aux_power_domain()
+ */
+enum intel_display_power_domain
+intel_legacy_aux_to_power_domain(enum aux_ch aux_ch)
+{
+	switch (aux_ch) {
 	case AUX_CH_A:
 		return POWER_DOMAIN_AUX_A;
 	case AUX_CH_B:
@@ -6780,7 +6790,7 @@
 	case AUX_CH_F:
 		return POWER_DOMAIN_AUX_F;
 	default:
-		MISSING_CASE(dig_port->aux_ch);
+		MISSING_CASE(aux_ch);
 		return POWER_DOMAIN_AUX_A;
 	}
 }
@@ -10510,7 +10520,7 @@
 	u32 base;
 
 	if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
-		base = obj->phys_handle->busaddr;
+		base = sg_dma_address(obj->mm.pages->sgl);
 	else
 		base = intel_plane_ggtt_offset(plane_state);
 
@@ -11893,10 +11903,11 @@
 	case 10 ... 11:
 		bpp = 10 * 3;
 		break;
-	case 12:
+	case 12 ... 16:
 		bpp = 12 * 3;
 		break;
 	default:
+		MISSING_CASE(conn_state->max_bpc);
 		return -EINVAL;
 	}
 
@@ -14429,7 +14440,7 @@
 		return ret;
 
 	fb_obj_bump_render_priority(obj);
-	intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_DIRTYFB);
+	i915_gem_object_flush_frontbuffer(obj, ORIGIN_DIRTYFB);
 
 	if (!new_state->fence) { /* implicit fencing */
 		struct dma_fence *fence;
@@ -16860,8 +16871,11 @@
 
 static void intel_early_display_was(struct drm_i915_private *dev_priv)
 {
-	/* Display WA #1185 WaDisableDARBFClkGating:cnl,glk */
-	if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+	/*
+	 * Display WA #1185 WaDisableDARBFClkGating:cnl,glk,icl,ehl,tgl
+	 * Also known as Wa_14010480278.
+	 */
+	if (IS_GEN_RANGE(dev_priv, 10, 12) || IS_GEMINILAKE(dev_priv))
 		I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
 			   DARBF_GATING_DIS);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_display.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_display.h
@@ -513,6 +513,8 @@
 enum intel_display_power_domain intel_port_to_power_domain(enum port port);
 enum intel_display_power_domain
 intel_aux_power_domain(struct intel_digital_port *dig_port);
+enum intel_display_power_domain
+intel_legacy_aux_to_power_domain(enum aux_ch aux_ch);
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 				 struct intel_crtc_state *pipe_config);
 void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_display_power.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -20,15 +20,14 @@
 #include "intel_sideband.h"
 #include "intel_tc.h"
 
+static const struct i915_power_well_ops icl_tc_phy_aux_power_well_ops;
+
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 					 enum i915_power_well_id power_well_id);
 
 const char *
-intel_display_power_domain_str(struct drm_i915_private *i915,
-			       enum intel_display_power_domain domain)
+intel_display_power_domain_str(enum intel_display_power_domain domain)
 {
-	bool ddi_tc_ports = IS_GEN(i915, 12);
-
 	switch (domain) {
 	case POWER_DOMAIN_DISPLAY_CORE:
 		return "DISPLAY_CORE";
@@ -71,23 +70,17 @@
 	case POWER_DOMAIN_PORT_DDI_C_LANES:
 		return "PORT_DDI_C_LANES";
 	case POWER_DOMAIN_PORT_DDI_D_LANES:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_D_LANES !=
-			     POWER_DOMAIN_PORT_DDI_TC1_LANES);
-		return ddi_tc_ports ? "PORT_DDI_TC1_LANES" : "PORT_DDI_D_LANES";
+		return "PORT_DDI_D_LANES";
 	case POWER_DOMAIN_PORT_DDI_E_LANES:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_E_LANES !=
-			     POWER_DOMAIN_PORT_DDI_TC2_LANES);
-		return ddi_tc_ports ? "PORT_DDI_TC2_LANES" : "PORT_DDI_E_LANES";
+		return "PORT_DDI_E_LANES";
 	case POWER_DOMAIN_PORT_DDI_F_LANES:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_F_LANES !=
-			     POWER_DOMAIN_PORT_DDI_TC3_LANES);
-		return ddi_tc_ports ? "PORT_DDI_TC3_LANES" : "PORT_DDI_F_LANES";
-	case POWER_DOMAIN_PORT_DDI_TC4_LANES:
-		return "PORT_DDI_TC4_LANES";
-	case POWER_DOMAIN_PORT_DDI_TC5_LANES:
-		return "PORT_DDI_TC5_LANES";
-	case POWER_DOMAIN_PORT_DDI_TC6_LANES:
-		return "PORT_DDI_TC6_LANES";
+		return "PORT_DDI_F_LANES";
+	case POWER_DOMAIN_PORT_DDI_G_LANES:
+		return "PORT_DDI_G_LANES";
+	case POWER_DOMAIN_PORT_DDI_H_LANES:
+		return "PORT_DDI_H_LANES";
+	case POWER_DOMAIN_PORT_DDI_I_LANES:
+		return "PORT_DDI_I_LANES";
 	case POWER_DOMAIN_PORT_DDI_A_IO:
 		return "PORT_DDI_A_IO";
 	case POWER_DOMAIN_PORT_DDI_B_IO:
@@ -95,23 +88,17 @@
 	case POWER_DOMAIN_PORT_DDI_C_IO:
 		return "PORT_DDI_C_IO";
 	case POWER_DOMAIN_PORT_DDI_D_IO:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_D_IO !=
-			     POWER_DOMAIN_PORT_DDI_TC1_IO);
-		return ddi_tc_ports ? "PORT_DDI_TC1_IO" : "PORT_DDI_D_IO";
+		return "PORT_DDI_D_IO";
 	case POWER_DOMAIN_PORT_DDI_E_IO:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_E_IO !=
-			     POWER_DOMAIN_PORT_DDI_TC2_IO);
-		return ddi_tc_ports ? "PORT_DDI_TC2_IO" : "PORT_DDI_E_IO";
+		return "PORT_DDI_E_IO";
 	case POWER_DOMAIN_PORT_DDI_F_IO:
-		BUILD_BUG_ON(POWER_DOMAIN_PORT_DDI_F_IO !=
-			     POWER_DOMAIN_PORT_DDI_TC3_IO);
-		return ddi_tc_ports ? "PORT_DDI_TC3_IO" : "PORT_DDI_F_IO";
-	case POWER_DOMAIN_PORT_DDI_TC4_IO:
-		return "PORT_DDI_TC4_IO";
-	case POWER_DOMAIN_PORT_DDI_TC5_IO:
-		return "PORT_DDI_TC5_IO";
-	case POWER_DOMAIN_PORT_DDI_TC6_IO:
-		return "PORT_DDI_TC6_IO";
+		return "PORT_DDI_F_IO";
+	case POWER_DOMAIN_PORT_DDI_G_IO:
+		return "PORT_DDI_G_IO";
+	case POWER_DOMAIN_PORT_DDI_H_IO:
+		return "PORT_DDI_H_IO";
+	case POWER_DOMAIN_PORT_DDI_I_IO:
+		return "PORT_DDI_I_IO";
 	case POWER_DOMAIN_PORT_DSI:
 		return "PORT_DSI";
 	case POWER_DOMAIN_PORT_CRT:
@@ -129,34 +116,33 @@
 	case POWER_DOMAIN_AUX_C:
 		return "AUX_C";
 	case POWER_DOMAIN_AUX_D:
-		BUILD_BUG_ON(POWER_DOMAIN_AUX_D != POWER_DOMAIN_AUX_TC1);
-		return ddi_tc_ports ? "AUX_TC1" : "AUX_D";
+		return "AUX_D";
 	case POWER_DOMAIN_AUX_E:
-		BUILD_BUG_ON(POWER_DOMAIN_AUX_E != POWER_DOMAIN_AUX_TC2);
-		return ddi_tc_ports ? "AUX_TC2" : "AUX_E";
+		return "AUX_E";
 	case POWER_DOMAIN_AUX_F:
-		BUILD_BUG_ON(POWER_DOMAIN_AUX_F != POWER_DOMAIN_AUX_TC3);
-		return ddi_tc_ports ? "AUX_TC3" : "AUX_F";
-	case POWER_DOMAIN_AUX_TC4:
-		return "AUX_TC4";
-	case POWER_DOMAIN_AUX_TC5:
-		return "AUX_TC5";
-	case POWER_DOMAIN_AUX_TC6:
-		return "AUX_TC6";
+		return "AUX_F";
+	case POWER_DOMAIN_AUX_G:
+		return "AUX_G";
+	case POWER_DOMAIN_AUX_H:
+		return "AUX_H";
+	case POWER_DOMAIN_AUX_I:
+		return "AUX_I";
 	case POWER_DOMAIN_AUX_IO_A:
 		return "AUX_IO_A";
-	case POWER_DOMAIN_AUX_TBT1:
-		return "AUX_TBT1";
-	case POWER_DOMAIN_AUX_TBT2:
-		return "AUX_TBT2";
-	case POWER_DOMAIN_AUX_TBT3:
-		return "AUX_TBT3";
-	case POWER_DOMAIN_AUX_TBT4:
-		return "AUX_TBT4";
-	case POWER_DOMAIN_AUX_TBT5:
-		return "AUX_TBT5";
-	case POWER_DOMAIN_AUX_TBT6:
-		return "AUX_TBT6";
+	case POWER_DOMAIN_AUX_C_TBT:
+		return "AUX_C_TBT";
+	case POWER_DOMAIN_AUX_D_TBT:
+		return "AUX_D_TBT";
+	case POWER_DOMAIN_AUX_E_TBT:
+		return "AUX_E_TBT";
+	case POWER_DOMAIN_AUX_F_TBT:
+		return "AUX_F_TBT";
+	case POWER_DOMAIN_AUX_G_TBT:
+		return "AUX_G_TBT";
+	case POWER_DOMAIN_AUX_H_TBT:
+		return "AUX_H_TBT";
+	case POWER_DOMAIN_AUX_I_TBT:
+		return "AUX_I_TBT";
 	case POWER_DOMAIN_GMBUS:
 		return "GMBUS";
 	case POWER_DOMAIN_INIT:
@@ -167,6 +153,8 @@
 		return "GT_IRQ";
 	case POWER_DOMAIN_DPLL_DC_OFF:
 		return "DPLL_DC_OFF";
+	case POWER_DOMAIN_TC_COLD_OFF:
+		return "TC_COLD_OFF";
 	default:
 		MISSING_CASE(domain);
 		return "?";
@@ -312,6 +300,70 @@
 		gen8_irq_power_well_pre_disable(dev_priv, irq_pipe_mask);
 }
 
+#define ICL_AUX_PW_TO_CH(pw_idx)	\
+	((pw_idx) - ICL_PW_CTL_IDX_AUX_A + AUX_CH_A)
+
+#define ICL_TBT_AUX_PW_TO_CH(pw_idx)	\
+	((pw_idx) - ICL_PW_CTL_IDX_AUX_TBT1 + AUX_CH_C)
+
+static enum aux_ch icl_tc_phy_aux_ch(struct drm_i915_private *dev_priv,
+				     struct i915_power_well *power_well)
+{
+	int pw_idx = power_well->desc->hsw.idx;
+
+	return power_well->desc->hsw.is_tc_tbt ? ICL_TBT_AUX_PW_TO_CH(pw_idx) :
+						 ICL_AUX_PW_TO_CH(pw_idx);
+}
+
+static struct intel_digital_port *
+aux_ch_to_digital_port(struct drm_i915_private *dev_priv,
+		       enum aux_ch aux_ch)
+{
+	struct intel_digital_port *dig_port = NULL;
+	struct intel_encoder *encoder;
+
+	for_each_intel_encoder(&dev_priv->drm, encoder) {
+		/* We'll check the MST primary port */
+		if (encoder->type == INTEL_OUTPUT_DP_MST)
+			continue;
+
+		dig_port = enc_to_dig_port(&encoder->base);
+		if (!dig_port)
+			continue;
+
+		if (dig_port->aux_ch != aux_ch) {
+			dig_port = NULL;
+			continue;
+		}
+
+		break;
+	}
+
+	return dig_port;
+}
+
+static bool tc_phy_aux_timeout_expected(struct drm_i915_private *dev_priv,
+					struct i915_power_well *power_well)
+{
+	/* An AUX timeout is expected if the TBT DP tunnel is down. */
+	if (power_well->desc->hsw.is_tc_tbt)
+		return true;
+
+	/*
+	 * An AUX timeout is expected because we enable TC legacy port aux
+	 * to hold port out of TC cold
+	 */
+	if (INTEL_GEN(dev_priv) == 11 &&
+	    power_well->desc->ops == &icl_tc_phy_aux_power_well_ops) {
+		enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
+		struct intel_digital_port *dig_port = aux_ch_to_digital_port(dev_priv, aux_ch);
+
+		return dig_port->tc_legacy_port;
+	}
+
+	return false;
+}
+
 static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv,
 					   struct i915_power_well *power_well)
 {
@@ -324,8 +376,8 @@
 		DRM_DEBUG_KMS("%s power well enable timeout\n",
 			      power_well->desc->name);
 
-		/* An AUX timeout is expected if the TBT DP tunnel is down. */
-		WARN_ON(!power_well->desc->hsw.is_tc_tbt);
+		WARN_ON(!tc_phy_aux_timeout_expected(dev_priv, power_well));
+
 	}
 }
 
@@ -381,16 +433,16 @@
 				      SKL_FUSE_PG_DIST_STATUS(pg), 1));
 }
 
-static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
-				  struct i915_power_well *power_well)
+static void hsw_power_well_enable_prepare(struct drm_i915_private *dev_priv,
+					  struct i915_power_well *power_well)
 {
 	const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
 	int pw_idx = power_well->desc->hsw.idx;
-	bool wait_fuses = power_well->desc->hsw.has_fuses;
-	enum skl_power_gate uninitialized_var(pg);
 	u32 val;
 
-	if (wait_fuses) {
+	if (power_well->desc->hsw.has_fuses) {
+		enum skl_power_gate pg;
+
 		pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) :
 						 SKL_PW_CTL_IDX_TO_PG(pw_idx);
 		/*
@@ -406,25 +458,46 @@
 
 	val = I915_READ(regs->driver);
 	I915_WRITE(regs->driver, val | HSW_PWR_WELL_CTL_REQ(pw_idx));
+}
+
+static void hsw_power_well_enable_complete(struct drm_i915_private *dev_priv,
+					   struct i915_power_well *power_well)
+{
+	int pw_idx = power_well->desc->hsw.idx;
+
 	hsw_wait_for_power_well_enable(dev_priv, power_well);
 
 	/* Display WA #1178: cnl */
 	if (IS_CANNONLAKE(dev_priv) &&
 	    pw_idx >= GLK_PW_CTL_IDX_AUX_B &&
 	    pw_idx <= CNL_PW_CTL_IDX_AUX_F) {
+		u32 val;
+
 		val = I915_READ(CNL_AUX_ANAOVRD1(pw_idx));
 		val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS;
 		I915_WRITE(CNL_AUX_ANAOVRD1(pw_idx), val);
 	}
 
-	if (wait_fuses)
+	if (power_well->desc->hsw.has_fuses) {
+		enum skl_power_gate pg;
+
+		pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) :
+						 SKL_PW_CTL_IDX_TO_PG(pw_idx);
 		gen9_wait_for_power_well_fuses(dev_priv, pg);
+	}
 
 	hsw_power_well_post_enable(dev_priv,
 				   power_well->desc->hsw.irq_pipe_mask,
 				   power_well->desc->hsw.has_vga);
 }
 
+static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
+				  struct i915_power_well *power_well)
+{
+	hsw_power_well_enable_prepare(dev_priv, power_well);
+	hsw_power_well_enable_complete(dev_priv, power_well);
+}
+
 static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
 				   struct i915_power_well *power_well)
 {
@@ -497,21 +570,6 @@
 	hsw_wait_for_power_well_disable(dev_priv, power_well);
 }
 
-#define ICL_AUX_PW_TO_CH(pw_idx)	\
-	((pw_idx) - ICL_PW_CTL_IDX_AUX_A + AUX_CH_A)
-
-#define ICL_TBT_AUX_PW_TO_CH(pw_idx)	\
-	((pw_idx) - ICL_PW_CTL_IDX_AUX_TBT1 + AUX_CH_C)
-
-static enum aux_ch icl_tc_phy_aux_ch(struct drm_i915_private *dev_priv,
-				     struct i915_power_well *power_well)
-{
-	int pw_idx = power_well->desc->hsw.idx;
-
-	return power_well->desc->hsw.is_tc_tbt ? ICL_TBT_AUX_PW_TO_CH(pw_idx) :
-						 ICL_AUX_PW_TO_CH(pw_idx);
-}
-
 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
 
 static u64 async_put_domains_mask(struct i915_power_domains *power_domains);
@@ -528,64 +586,63 @@
 }
 
 static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv,
-					struct i915_power_well *power_well)
+					struct i915_power_well *power_well,
+					struct intel_digital_port *dig_port)
 {
-	enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
-	struct intel_digital_port *dig_port = NULL;
-	struct intel_encoder *encoder;
-
 	/* Bypass the check if all references are released asynchronously */
 	if (power_well_async_ref_count(dev_priv, power_well) ==
 	    power_well->count)
 		return;
 
-	aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
-
-	for_each_intel_encoder(&dev_priv->drm, encoder) {
-		enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
-
-		if (!intel_phy_is_tc(dev_priv, phy))
-			continue;
-
-		/* We'll check the MST primary port */
-		if (encoder->type == INTEL_OUTPUT_DP_MST)
-			continue;
-
-		dig_port = enc_to_dig_port(&encoder->base);
-		if (WARN_ON(!dig_port))
-			continue;
-
-		if (dig_port->aux_ch != aux_ch) {
-			dig_port = NULL;
-			continue;
-		}
-
-		break;
-	}
-
 	if (WARN_ON(!dig_port))
 		return;
 
+	if (INTEL_GEN(dev_priv) == 11 && dig_port->tc_legacy_port)
+		return;
+
 	WARN_ON(!intel_tc_port_ref_held(dig_port));
 }
 
 #else
 
 static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv,
-					struct i915_power_well *power_well)
+					struct i915_power_well *power_well,
+					struct intel_digital_port *dig_port)
 {
 }
 
 #endif
 
+static void icl_tc_cold_exit(struct drm_i915_private *i915)
+{
+	int ret, tries = 0;
+
+	while (1) {
+		ret = sandybridge_pcode_write_timeout(i915,
+						      ICL_PCODE_EXIT_TCCOLD,
+						      0, 250, 1);
+		if (ret != -EAGAIN || ++tries == 3)
+			break;
+		msleep(1);
+	}
+
+	/* Spec states that TC cold exit can take up to 1ms to complete */
+	if (!ret)
+		msleep(1);
+
+	/* TODO: turn failure into a error as soon i915 CI updates ICL IFWI */
+	DRM_DEBUG_KMS("TC cold block %s\n", ret ? "failed" : "succeeded");
+}
+
 static void
 icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
 				 struct i915_power_well *power_well)
 {
 	enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
+	struct intel_digital_port *dig_port = aux_ch_to_digital_port(dev_priv, aux_ch);
 	u32 val;
 
-	icl_tc_port_assert_ref_held(dev_priv, power_well);
+	icl_tc_port_assert_ref_held(dev_priv, power_well, dig_port);
 
 	val = I915_READ(DP_AUX_CH_CTL(aux_ch));
 	val &= ~DP_AUX_CH_CTL_TBT_IO;
@@ -593,14 +650,22 @@
 		val |= DP_AUX_CH_CTL_TBT_IO;
 	I915_WRITE(DP_AUX_CH_CTL(aux_ch), val);
 
-	hsw_power_well_enable(dev_priv, power_well);
+	hsw_power_well_enable_prepare(dev_priv, power_well);
+
+	if (INTEL_GEN(dev_priv) == 11 && dig_port->tc_legacy_port)
+		icl_tc_cold_exit(dev_priv);
+
+	hsw_power_well_enable_complete(dev_priv, power_well);
 }
 
 static void
 icl_tc_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
 				  struct i915_power_well *power_well)
 {
-	icl_tc_port_assert_ref_held(dev_priv, power_well);
+	enum aux_ch aux_ch = icl_tc_phy_aux_ch(dev_priv, power_well);
+	struct intel_digital_port *dig_port = aux_ch_to_digital_port(dev_priv, aux_ch);
+
+	icl_tc_port_assert_ref_held(dev_priv, power_well, dig_port);
 
 	hsw_power_well_disable(dev_priv, power_well);
 }
@@ -1718,15 +1783,12 @@
 static void print_power_domains(struct i915_power_domains *power_domains,
 				const char *prefix, u64 mask)
 {
-	struct drm_i915_private *i915 =
-		container_of(power_domains, struct drm_i915_private,
-			     power_domains);
 	enum intel_display_power_domain domain;
 
 	DRM_DEBUG_DRIVER("%s (%lu):\n", prefix, hweight64(mask));
 	for_each_power_domain(domain, mask)
 		DRM_DEBUG_DRIVER("%s use_count %d\n",
-				 intel_display_power_domain_str(i915, domain),
+				 intel_display_power_domain_str(domain),
 				 power_domains->domain_use_count[domain]);
 }
 
@@ -1896,7 +1958,7 @@
 {
 	struct i915_power_domains *power_domains;
 	struct i915_power_well *power_well;
-	const char *name = intel_display_power_domain_str(dev_priv, domain);
+	const char *name = intel_display_power_domain_str(domain);
 
 	power_domains = &dev_priv->power_domains;
 
@@ -2487,10 +2549,10 @@
 	BIT_ULL(POWER_DOMAIN_AUX_D) |			\
 	BIT_ULL(POWER_DOMAIN_AUX_E) |			\
 	BIT_ULL(POWER_DOMAIN_AUX_F) |			\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT1) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT2) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT3) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT4) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_C_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_D_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_E_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_F_TBT) |		\
 	BIT_ULL(POWER_DOMAIN_VGA) |			\
 	BIT_ULL(POWER_DOMAIN_AUDIO) |			\
 	BIT_ULL(POWER_DOMAIN_INIT))
@@ -2530,22 +2592,22 @@
 	BIT_ULL(POWER_DOMAIN_AUX_A))
 #define ICL_AUX_B_IO_POWER_DOMAINS (			\
 	BIT_ULL(POWER_DOMAIN_AUX_B))
-#define ICL_AUX_C_IO_POWER_DOMAINS (			\
+#define ICL_AUX_C_TC1_IO_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_AUX_C))
-#define ICL_AUX_D_IO_POWER_DOMAINS (			\
+#define ICL_AUX_D_TC2_IO_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_AUX_D))
-#define ICL_AUX_E_IO_POWER_DOMAINS (			\
+#define ICL_AUX_E_TC3_IO_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_AUX_E))
-#define ICL_AUX_F_IO_POWER_DOMAINS (			\
+#define ICL_AUX_F_TC4_IO_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_AUX_F))
-#define ICL_AUX_TBT1_IO_POWER_DOMAINS (			\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT1))
-#define ICL_AUX_TBT2_IO_POWER_DOMAINS (			\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT2))
-#define ICL_AUX_TBT3_IO_POWER_DOMAINS (			\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT3))
-#define ICL_AUX_TBT4_IO_POWER_DOMAINS (			\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT4))
+#define ICL_AUX_C_TBT1_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_C_TBT))
+#define ICL_AUX_D_TBT2_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_D_TBT))
+#define ICL_AUX_E_TBT3_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_E_TBT))
+#define ICL_AUX_F_TBT4_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_F_TBT))
 
 #define TGL_PW_5_POWER_DOMAINS (			\
 	BIT_ULL(POWER_DOMAIN_PIPE_D) |			\
@@ -2565,24 +2627,24 @@
 	BIT_ULL(POWER_DOMAIN_PIPE_B) |			\
 	BIT_ULL(POWER_DOMAIN_TRANSCODER_B) |		\
 	BIT_ULL(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC1_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC2_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC3_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC4_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC5_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC6_LANES) |	\
-	BIT_ULL(POWER_DOMAIN_AUX_TC1) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC2) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC3) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC4) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC5) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC6) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT1) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT2) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT3) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT4) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT5) |		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT6) |		\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_E_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_G_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_H_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_I_LANES) |	\
+	BIT_ULL(POWER_DOMAIN_AUX_D) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_E) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_F) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_G) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_H) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_I) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_D_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_E_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_F_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_G_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_H_TBT) |		\
+	BIT_ULL(POWER_DOMAIN_AUX_I_TBT) |		\
 	BIT_ULL(POWER_DOMAIN_VGA) |			\
 	BIT_ULL(POWER_DOMAIN_AUDIO) |			\
 	BIT_ULL(POWER_DOMAIN_INIT))
@@ -2598,35 +2660,65 @@
 	BIT_ULL(POWER_DOMAIN_AUX_A) |			\
 	BIT_ULL(POWER_DOMAIN_INIT))
 
-#define TGL_DDI_IO_TC1_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC1_IO))
-#define TGL_DDI_IO_TC2_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC2_IO))
-#define TGL_DDI_IO_TC3_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC3_IO))
-#define TGL_DDI_IO_TC4_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC4_IO))
-#define TGL_DDI_IO_TC5_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC5_IO))
-#define TGL_DDI_IO_TC6_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_PORT_DDI_TC6_IO))
-
-#define TGL_AUX_TC1_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC1))
-#define TGL_AUX_TC2_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC2))
-#define TGL_AUX_TC3_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC3))
-#define TGL_AUX_TC4_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC4))
-#define TGL_AUX_TC5_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC5))
-#define TGL_AUX_TC6_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TC6))
-#define TGL_AUX_TBT5_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT5))
-#define TGL_AUX_TBT6_IO_POWER_DOMAINS (		\
-	BIT_ULL(POWER_DOMAIN_AUX_TBT6))
+#define TGL_DDI_IO_D_TC1_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_D_IO))
+#define TGL_DDI_IO_E_TC2_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_E_IO))
+#define TGL_DDI_IO_F_TC3_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO))
+#define TGL_DDI_IO_G_TC4_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_G_IO))
+#define TGL_DDI_IO_H_TC5_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_H_IO))
+#define TGL_DDI_IO_I_TC6_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_I_IO))
+
+#define TGL_AUX_A_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_IO_A) |	\
+	BIT_ULL(POWER_DOMAIN_AUX_A))
+#define TGL_AUX_B_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_B))
+#define TGL_AUX_C_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_C))
+#define TGL_AUX_D_TC1_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_D))
+#define TGL_AUX_E_TC2_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_E))
+#define TGL_AUX_F_TC3_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_F))
+#define TGL_AUX_G_TC4_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_G))
+#define TGL_AUX_H_TC5_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_H))
+#define TGL_AUX_I_TC6_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_I))
+#define TGL_AUX_D_TBT1_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_D_TBT))
+#define TGL_AUX_E_TBT2_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_E_TBT))
+#define TGL_AUX_F_TBT3_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_F_TBT))
+#define TGL_AUX_G_TBT4_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_G_TBT))
+#define TGL_AUX_H_TBT5_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_H_TBT))
+#define TGL_AUX_I_TBT6_IO_POWER_DOMAINS (	\
+	BIT_ULL(POWER_DOMAIN_AUX_I_TBT))
+
+#define TGL_TC_COLD_OFF_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_D)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_E)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_F)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_G)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_H)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_I)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_D_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_E_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_F_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_G_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_H_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_AUX_I_TBT)	|	\
+	BIT_ULL(POWER_DOMAIN_TC_COLD_OFF))
 
 static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
 	.sync_hw = i9xx_power_well_sync_hw_noop,
@@ -3484,8 +3576,8 @@
 		},
 	},
 	{
-		.name = "AUX C",
-		.domains = ICL_AUX_C_IO_POWER_DOMAINS,
+		.name = "AUX C TC1",
+		.domains = ICL_AUX_C_TC1_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3495,8 +3587,8 @@
 		},
 	},
 	{
-		.name = "AUX D",
-		.domains = ICL_AUX_D_IO_POWER_DOMAINS,
+		.name = "AUX D TC2",
+		.domains = ICL_AUX_D_TC2_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3506,8 +3598,8 @@
 		},
 	},
 	{
-		.name = "AUX E",
-		.domains = ICL_AUX_E_IO_POWER_DOMAINS,
+		.name = "AUX E TC3",
+		.domains = ICL_AUX_E_TC3_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3517,8 +3609,8 @@
 		},
 	},
 	{
-		.name = "AUX F",
-		.domains = ICL_AUX_F_IO_POWER_DOMAINS,
+		.name = "AUX F TC4",
+		.domains = ICL_AUX_F_TC4_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3528,8 +3620,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT1",
-		.domains = ICL_AUX_TBT1_IO_POWER_DOMAINS,
+		.name = "AUX C TBT1",
+		.domains = ICL_AUX_C_TBT1_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3539,8 +3631,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT2",
-		.domains = ICL_AUX_TBT2_IO_POWER_DOMAINS,
+		.name = "AUX D TBT2",
+		.domains = ICL_AUX_D_TBT2_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3550,8 +3642,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT3",
-		.domains = ICL_AUX_TBT3_IO_POWER_DOMAINS,
+		.name = "AUX E TBT3",
+		.domains = ICL_AUX_E_TBT3_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3561,8 +3653,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT4",
-		.domains = ICL_AUX_TBT4_IO_POWER_DOMAINS,
+		.name = "AUX F TBT4",
+		.domains = ICL_AUX_F_TBT4_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3585,6 +3677,89 @@
 	},
 };
 
+static void
+tgl_tc_cold_request(struct drm_i915_private *i915, bool block)
+{
+	u8 tries = 0;
+	int ret;
+
+	while (1) {
+		u32 low_val = 0, high_val;
+
+		if (block)
+			high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ;
+		else
+			high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ;
+
+		/*
+		 * Spec states that we should timeout the request after 200us
+		 * but the function below will timeout after 500us
+		 */
+		ret = sandybridge_pcode_read(i915, TGL_PCODE_TCCOLD, &low_val,
+					     &high_val);
+		if (ret == 0) {
+			if (block &&
+			    (low_val & TGL_PCODE_EXIT_TCCOLD_DATA_L_EXIT_FAILED))
+				ret = -EIO;
+			else
+				break;
+		}
+
+		if (++tries == 3)
+			break;
+
+		if (ret == -EAGAIN)
+			msleep(1);
+	}
+
+	if (ret)
+		DRM_ERROR("TC cold %sblock failed\n", block ? "" : "un");
+	else
+		DRM_DEBUG_KMS("TC cold %sblock succeeded\n", block ? "" : "un");
+}
+
+static void
+tgl_tc_cold_off_power_well_enable(struct drm_i915_private *i915,
+				  struct i915_power_well *power_well)
+{
+	tgl_tc_cold_request(i915, true);
+}
+
+static void
+tgl_tc_cold_off_power_well_disable(struct drm_i915_private *i915,
+				   struct i915_power_well *power_well)
+{
+	tgl_tc_cold_request(i915, false);
+}
+
+static void
+tgl_tc_cold_off_power_well_sync_hw(struct drm_i915_private *i915,
+				   struct i915_power_well *power_well)
+{
+	if (power_well->count > 0)
+		tgl_tc_cold_off_power_well_enable(i915, power_well);
+	else
+		tgl_tc_cold_off_power_well_disable(i915, power_well);
+}
+
+static bool
+tgl_tc_cold_off_power_well_is_enabled(struct drm_i915_private *dev_priv,
+				      struct i915_power_well *power_well)
+{
+	/*
+	 * Not the correctly implementation but there is no way to just read it
+	 * from PCODE, so returning count to avoid state mismatch errors
+	 */
+	return power_well->count;
+}
+
+static const struct i915_power_well_ops tgl_tc_cold_off_ops = {
+	.sync_hw = tgl_tc_cold_off_power_well_sync_hw,
+	.enable = tgl_tc_cold_off_power_well_enable,
+	.disable = tgl_tc_cold_off_power_well_disable,
+	.is_enabled = tgl_tc_cold_off_power_well_is_enabled,
+};
+
 static const struct i915_power_well_desc tgl_power_wells[] = {
 	{
 		.name = "always-on",
@@ -3667,8 +3842,8 @@
 		}
 	},
 	{
-		.name = "DDI TC1 IO",
-		.domains = TGL_DDI_IO_TC1_POWER_DOMAINS,
+		.name = "DDI D TC1 IO",
+		.domains = TGL_DDI_IO_D_TC1_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3677,8 +3852,8 @@
 		},
 	},
 	{
-		.name = "DDI TC2 IO",
-		.domains = TGL_DDI_IO_TC2_POWER_DOMAINS,
+		.name = "DDI E TC2 IO",
+		.domains = TGL_DDI_IO_E_TC2_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3687,8 +3862,8 @@
 		},
 	},
 	{
-		.name = "DDI TC3 IO",
-		.domains = TGL_DDI_IO_TC3_POWER_DOMAINS,
+		.name = "DDI F TC3 IO",
+		.domains = TGL_DDI_IO_F_TC3_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3697,8 +3872,8 @@
 		},
 	},
 	{
-		.name = "DDI TC4 IO",
-		.domains = TGL_DDI_IO_TC4_POWER_DOMAINS,
+		.name = "DDI G TC4 IO",
+		.domains = TGL_DDI_IO_G_TC4_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3707,8 +3882,8 @@
 		},
 	},
 	{
-		.name = "DDI TC5 IO",
-		.domains = TGL_DDI_IO_TC5_POWER_DOMAINS,
+		.name = "DDI H TC5 IO",
+		.domains = TGL_DDI_IO_H_TC5_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3717,8 +3892,8 @@
 		},
 	},
 	{
-		.name = "DDI TC6 IO",
-		.domains = TGL_DDI_IO_TC6_POWER_DOMAINS,
+		.name = "DDI I TC6 IO",
+		.domains = TGL_DDI_IO_I_TC6_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3728,7 +3903,7 @@
 	},
 	{
 		.name = "AUX A",
-		.domains = ICL_AUX_A_IO_POWER_DOMAINS,
+		.domains = TGL_AUX_A_IO_POWER_DOMAINS,
 		.ops = &icl_combo_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3738,7 +3913,7 @@
 	},
 	{
 		.name = "AUX B",
-		.domains = ICL_AUX_B_IO_POWER_DOMAINS,
+		.domains = TGL_AUX_B_IO_POWER_DOMAINS,
 		.ops = &icl_combo_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3748,7 +3923,7 @@
 	},
 	{
 		.name = "AUX C",
-		.domains = ICL_AUX_C_IO_POWER_DOMAINS,
+		.domains = TGL_AUX_C_IO_POWER_DOMAINS,
 		.ops = &icl_combo_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3757,8 +3932,8 @@
 		},
 	},
 	{
-		.name = "AUX TC1",
-		.domains = TGL_AUX_TC1_IO_POWER_DOMAINS,
+		.name = "AUX D TC1",
+		.domains = TGL_AUX_D_TC1_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3768,8 +3943,8 @@
 		},
 	},
 	{
-		.name = "AUX TC2",
-		.domains = TGL_AUX_TC2_IO_POWER_DOMAINS,
+		.name = "AUX E TC2",
+		.domains = TGL_AUX_E_TC2_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3779,8 +3954,8 @@
 		},
 	},
 	{
-		.name = "AUX TC3",
-		.domains = TGL_AUX_TC3_IO_POWER_DOMAINS,
+		.name = "AUX F TC3",
+		.domains = TGL_AUX_F_TC3_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3790,8 +3965,8 @@
 		},
 	},
 	{
-		.name = "AUX TC4",
-		.domains = TGL_AUX_TC4_IO_POWER_DOMAINS,
+		.name = "AUX G TC4",
+		.domains = TGL_AUX_G_TC4_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3801,8 +3976,8 @@
 		},
 	},
 	{
-		.name = "AUX TC5",
-		.domains = TGL_AUX_TC5_IO_POWER_DOMAINS,
+		.name = "AUX H TC5",
+		.domains = TGL_AUX_H_TC5_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3812,8 +3987,8 @@
 		},
 	},
 	{
-		.name = "AUX TC6",
-		.domains = TGL_AUX_TC6_IO_POWER_DOMAINS,
+		.name = "AUX I TC6",
+		.domains = TGL_AUX_I_TC6_IO_POWER_DOMAINS,
 		.ops = &icl_tc_phy_aux_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3823,8 +3998,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT1",
-		.domains = ICL_AUX_TBT1_IO_POWER_DOMAINS,
+		.name = "AUX D TBT1",
+		.domains = TGL_AUX_D_TBT1_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3834,8 +4009,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT2",
-		.domains = ICL_AUX_TBT2_IO_POWER_DOMAINS,
+		.name = "AUX E TBT2",
+		.domains = TGL_AUX_E_TBT2_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3845,8 +4020,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT3",
-		.domains = ICL_AUX_TBT3_IO_POWER_DOMAINS,
+		.name = "AUX F TBT3",
+		.domains = TGL_AUX_F_TBT3_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3856,8 +4031,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT4",
-		.domains = ICL_AUX_TBT4_IO_POWER_DOMAINS,
+		.name = "AUX G TBT4",
+		.domains = TGL_AUX_G_TBT4_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3867,8 +4042,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT5",
-		.domains = TGL_AUX_TBT5_IO_POWER_DOMAINS,
+		.name = "AUX H TBT5",
+		.domains = TGL_AUX_H_TBT5_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3878,8 +4053,8 @@
 		},
 	},
 	{
-		.name = "AUX TBT6",
-		.domains = TGL_AUX_TBT6_IO_POWER_DOMAINS,
+		.name = "AUX I TBT6",
+		.domains = TGL_AUX_I_TBT6_IO_POWER_DOMAINS,
 		.ops = &hsw_power_well_ops,
 		.id = DISP_PW_ID_NONE,
 		{
@@ -3912,6 +4087,12 @@
 			.hsw.irq_pipe_mask = BIT(PIPE_D),
 		},
 	},
+	{
+		.name = "TC cold off",
+		.domains = TGL_TC_COLD_OFF_POWER_DOMAINS,
+		.ops = &tgl_tc_cold_off_ops,
+		.id = DISP_PW_ID_NONE,
+	},
 };
 
 static int
@@ -4205,13 +4386,19 @@
 
 static void icl_mbus_init(struct drm_i915_private *dev_priv)
 {
-	u32 val;
+	u32 mask, val;
 
-	val = MBUS_ABOX_BT_CREDIT_POOL1(16) |
-	      MBUS_ABOX_BT_CREDIT_POOL2(16) |
-	      MBUS_ABOX_B_CREDIT(1) |
-	      MBUS_ABOX_BW_CREDIT(1);
+	mask = MBUS_ABOX_BT_CREDIT_POOL1_MASK |
+		MBUS_ABOX_BT_CREDIT_POOL2_MASK |
+		MBUS_ABOX_B_CREDIT_MASK |
+		MBUS_ABOX_BW_CREDIT_MASK;
 
+	val = I915_READ(MBUS_ABOX_CTL);
+	val &= ~mask;
+	val |= MBUS_ABOX_BT_CREDIT_POOL1(16) |
+		MBUS_ABOX_BT_CREDIT_POOL2(16) |
+		MBUS_ABOX_B_CREDIT(1) |
+		MBUS_ABOX_BW_CREDIT(1);
 	I915_WRITE(MBUS_ABOX_CTL, val);
 }
 
@@ -5107,8 +5294,7 @@
 
 		for_each_power_domain(domain, power_well->desc->domains)
 			DRM_DEBUG_DRIVER("  %-23s %d\n",
-					 intel_display_power_domain_str(i915,
-									domain),
+					 intel_display_power_domain_str(domain),
 					 power_domains->domain_use_count[domain]);
 	}
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_display_power.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -36,29 +36,20 @@
 	POWER_DOMAIN_PORT_DDI_B_LANES,
 	POWER_DOMAIN_PORT_DDI_C_LANES,
 	POWER_DOMAIN_PORT_DDI_D_LANES,
-	POWER_DOMAIN_PORT_DDI_TC1_LANES = POWER_DOMAIN_PORT_DDI_D_LANES,
 	POWER_DOMAIN_PORT_DDI_E_LANES,
-	POWER_DOMAIN_PORT_DDI_TC2_LANES = POWER_DOMAIN_PORT_DDI_E_LANES,
 	POWER_DOMAIN_PORT_DDI_F_LANES,
-	POWER_DOMAIN_PORT_DDI_TC3_LANES = POWER_DOMAIN_PORT_DDI_F_LANES,
-	POWER_DOMAIN_PORT_DDI_TC4_LANES,
-	POWER_DOMAIN_PORT_DDI_TC5_LANES,
-	POWER_DOMAIN_PORT_DDI_TC6_LANES,
+	POWER_DOMAIN_PORT_DDI_G_LANES,
+	POWER_DOMAIN_PORT_DDI_H_LANES,
+	POWER_DOMAIN_PORT_DDI_I_LANES,
 	POWER_DOMAIN_PORT_DDI_A_IO,
 	POWER_DOMAIN_PORT_DDI_B_IO,
 	POWER_DOMAIN_PORT_DDI_C_IO,
 	POWER_DOMAIN_PORT_DDI_D_IO,
-	POWER_DOMAIN_PORT_DDI_TC1_IO = POWER_DOMAIN_PORT_DDI_D_IO,
 	POWER_DOMAIN_PORT_DDI_E_IO,
-	POWER_DOMAIN_PORT_DDI_TC2_IO = POWER_DOMAIN_PORT_DDI_E_IO,
 	POWER_DOMAIN_PORT_DDI_F_IO,
-	POWER_DOMAIN_PORT_DDI_TC3_IO = POWER_DOMAIN_PORT_DDI_F_IO,
 	POWER_DOMAIN_PORT_DDI_G_IO,
-	POWER_DOMAIN_PORT_DDI_TC4_IO = POWER_DOMAIN_PORT_DDI_G_IO,
 	POWER_DOMAIN_PORT_DDI_H_IO,
-	POWER_DOMAIN_PORT_DDI_TC5_IO = POWER_DOMAIN_PORT_DDI_H_IO,
 	POWER_DOMAIN_PORT_DDI_I_IO,
-	POWER_DOMAIN_PORT_DDI_TC6_IO = POWER_DOMAIN_PORT_DDI_I_IO,
 	POWER_DOMAIN_PORT_DSI,
 	POWER_DOMAIN_PORT_CRT,
 	POWER_DOMAIN_PORT_OTHER,
@@ -68,25 +59,24 @@
 	POWER_DOMAIN_AUX_B,
 	POWER_DOMAIN_AUX_C,
 	POWER_DOMAIN_AUX_D,
-	POWER_DOMAIN_AUX_TC1 = POWER_DOMAIN_AUX_D,
 	POWER_DOMAIN_AUX_E,
-	POWER_DOMAIN_AUX_TC2 = POWER_DOMAIN_AUX_E,
 	POWER_DOMAIN_AUX_F,
-	POWER_DOMAIN_AUX_TC3 = POWER_DOMAIN_AUX_F,
-	POWER_DOMAIN_AUX_TC4,
-	POWER_DOMAIN_AUX_TC5,
-	POWER_DOMAIN_AUX_TC6,
+	POWER_DOMAIN_AUX_G,
+	POWER_DOMAIN_AUX_H,
+	POWER_DOMAIN_AUX_I,
 	POWER_DOMAIN_AUX_IO_A,
-	POWER_DOMAIN_AUX_TBT1,
-	POWER_DOMAIN_AUX_TBT2,
-	POWER_DOMAIN_AUX_TBT3,
-	POWER_DOMAIN_AUX_TBT4,
-	POWER_DOMAIN_AUX_TBT5,
-	POWER_DOMAIN_AUX_TBT6,
+	POWER_DOMAIN_AUX_C_TBT,
+	POWER_DOMAIN_AUX_D_TBT,
+	POWER_DOMAIN_AUX_E_TBT,
+	POWER_DOMAIN_AUX_F_TBT,
+	POWER_DOMAIN_AUX_G_TBT,
+	POWER_DOMAIN_AUX_H_TBT,
+	POWER_DOMAIN_AUX_I_TBT,
 	POWER_DOMAIN_GMBUS,
 	POWER_DOMAIN_MODESET,
 	POWER_DOMAIN_GT_IRQ,
 	POWER_DOMAIN_DPLL_DC_OFF,
+	POWER_DOMAIN_TC_COLD_OFF,
 	POWER_DOMAIN_INIT,
 
 	POWER_DOMAIN_NUM,
@@ -269,8 +259,7 @@
 void intel_display_power_resume(struct drm_i915_private *i915);
 
 const char *
-intel_display_power_domain_str(struct drm_i915_private *i915,
-			       enum intel_display_power_domain domain);
+intel_display_power_domain_str(enum intel_display_power_domain domain);
 
 bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
 				    enum intel_display_power_domain domain);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_display_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -214,6 +214,9 @@
 		u8 controller;		/* bxt+ only */
 		struct pwm_device *pwm;
 
+		/* DPCD backlight */
+		u8 pwmgen_bit_count;
+
 		struct backlight_device *device;
 
 		/* Connector and platform specific backlight functions */
@@ -1176,6 +1179,7 @@
 	int max_link_rate;
 	/* sink or branch descriptor */
 	struct drm_dp_desc desc;
+	u32 edid_quirks;
 	struct drm_dp_aux aux;
 	u8 train_set[4];
 	int panel_power_up_delay;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_dp.c
@@ -166,6 +166,12 @@
 				      enum pipe pipe);
 static void intel_dp_unset_edid(struct intel_dp *intel_dp);
 
+static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp)
+{
+	intel_dp->sink_rates[0] = 162000;
+	intel_dp->num_sink_rates = 1;
+}
+
 /* update sink rates from dpcd */
 static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
 {
@@ -567,7 +573,7 @@
 		return 0;
 	}
 	/* Also take into account max slice width */
-	min_slice_count = min_t(u8, min_slice_count,
+	min_slice_count = max_t(u8, min_slice_count,
 				DIV_ROUND_UP(mode_hdisplay,
 					     max_slice_width));
 
@@ -1292,8 +1298,7 @@
 	bool is_tc_port = intel_phy_is_tc(i915, phy);
 	i915_reg_t ch_ctl, ch_data[5];
 	u32 aux_clock_divider;
-	enum intel_display_power_domain aux_domain =
-		intel_aux_power_domain(intel_dig_port);
+	enum intel_display_power_domain aux_domain;
 	intel_wakeref_t aux_wakeref;
 	intel_wakeref_t pps_wakeref;
 	int i, ret, recv_bytes;
@@ -1308,6 +1313,8 @@
 	if (is_tc_port)
 		intel_tc_port_lock(intel_dig_port);
 
+	aux_domain = intel_aux_power_domain(intel_dig_port);
+
 	aux_wakeref = intel_display_power_get(i915, aux_domain);
 	pps_wakeref = pps_lock(intel_dp);
 
@@ -2251,7 +2258,7 @@
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
 	struct intel_digital_connector_state *intel_conn_state =
 		to_intel_digital_connector_state(conn_state);
-	bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
+	bool constant_n = drm_dp_has_quirk(&intel_dp->desc, 0,
 					   DP_DPCD_QUIRK_CONSTANT_N);
 	int ret = 0, output_bpp;
 
@@ -3633,7 +3640,7 @@
  * link status information
  */
 bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status)
 {
 	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
 				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
@@ -4260,6 +4267,9 @@
 	 */
 	intel_psr_init_dpcd(intel_dp);
 
+	/* Clear the default sink rates */
+	intel_dp->num_sink_rates = 0;
+
 	/* Read the eDP 1.4+ supported link rates. */
 	if (intel_dp->edp_dpcd[0] >= DP_EDP_14) {
 		__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
@@ -4327,7 +4337,8 @@
 	 * it don't care about read it here and in intel_edp_init_dpcd().
 	 */
 	if (!intel_dp_is_edp(intel_dp) &&
-	    !drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_SINK_COUNT)) {
+	    !drm_dp_has_quirk(&intel_dp->desc, 0,
+			      DP_DPCD_QUIRK_NO_SINK_COUNT)) {
 		u8 count;
 		ssize_t r;
 
@@ -4705,7 +4716,18 @@
 	bool bret;
 
 	if (intel_dp->is_mst) {
-		u8 esi[DP_DPRX_ESI_LEN] = { 0 };
+		/*
+		 * The +2 is because DP_DPRX_ESI_LEN is 14, but we then
+		 * pass in "esi+10" to drm_dp_channel_eq_ok(), which
+		 * takes a 6-byte array. So we actually need 16 bytes
+		 * here.
+		 *
+		 * Somebody who knows what the limits actually are
+		 * should check this, but for now this is at least
+		 * harmless and avoids a valid compiler warning about
+		 * using more of the array than we have allocated.
+		 */
+		u8 esi[DP_DPRX_ESI_LEN+2] = {};
 		int ret = 0;
 		int retry;
 		bool handled;
@@ -5328,6 +5350,7 @@
 
 	intel_dp->has_audio = drm_detect_monitor_audio(edid);
 	drm_dp_cec_set_edid(&intel_dp->aux, edid);
+	intel_dp->edid_quirks = drm_dp_get_edid_quirks(edid);
 }
 
 static void
@@ -5340,6 +5363,7 @@
 	intel_connector->detect_edid = NULL;
 
 	intel_dp->has_audio = false;
+	intel_dp->edid_quirks = 0;
 }
 
 static int
@@ -7046,8 +7070,8 @@
 	edid = drm_get_edid(connector, &intel_dp->aux.ddc);
 	if (edid) {
 		if (drm_add_edid_modes(connector, edid)) {
-			drm_connector_update_edid_property(connector,
-								edid);
+			drm_connector_update_edid_property(connector, edid);
+			intel_dp->edid_quirks = drm_dp_get_edid_quirks(edid);
 		} else {
 			kfree(edid);
 			edid = ERR_PTR(-EINVAL);
@@ -7155,6 +7179,8 @@
 		return false;
 
 	intel_dp_set_source_rates(intel_dp);
+	intel_dp_set_default_sink_rates(intel_dp);
+	intel_dp_set_common_rates(intel_dp);
 
 	intel_dp->reset_link_params = true;
 	intel_dp->pps_pipe = INVALID_PIPE;
@@ -7218,11 +7244,8 @@
 		intel_connector->get_hw_state = intel_connector_get_hw_state;
 
 	/* init MST on ports that can support it */
-	if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) &&
-	    (port == PORT_B || port == PORT_C ||
-	     port == PORT_D || port == PORT_F))
-		intel_dp_mst_encoder_init(intel_dig_port,
-					  intel_connector->base.base.id);
+	intel_dp_mst_encoder_init(intel_dig_port,
+				  intel_connector->base.base.id);
 
 	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
 		intel_dp_aux_fini(intel_dp);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -59,8 +59,23 @@
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
 	u8 read_val[2] = { 0x0 };
+	u8 control_reg;
 	u16 level = 0;
 
+	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER,
+			      &control_reg) != 1) {
+		DRM_DEBUG_KMS("Failed to read the DPCD register 0x%x\n",
+			      DP_EDP_DISPLAY_CONTROL_REGISTER);
+		return 0;
+	}
+
+	/*
+	 * If we're not in DPCD control mode yet, the programmed brightness
+	 * value is meaningless and we should assume max brightness
+	 */
+	if (!(control_reg & DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD))
+		return connector->panel.backlight.max;
+
 	if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
 			     &read_val, sizeof(read_val)) < 0) {
 		DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
@@ -111,61 +126,28 @@
 {
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
-	int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1;
-	u8 pn, pn_min, pn_max;
+	const u8 pn = connector->panel.backlight.pwmgen_bit_count;
+	int freq, fxp, f, fxp_actual, fxp_min, fxp_max;
 
-	/* Find desired value of (F x P)
-	 * Note that, if F x P is out of supported range, the maximum value or
-	 * minimum value will applied automatically. So no need to check that.
-	 */
 	freq = dev_priv->vbt.backlight.pwm_freq_hz;
-	DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq);
 	if (!freq) {
 		DRM_DEBUG_KMS("Use panel default backlight frequency\n");
 		return false;
 	}
 
 	fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq);
+	f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255);
+	fxp_actual = f << pn;
 
-	/* Use highest possible value of Pn for more granularity of brightness
-	 * adjustment while satifying the conditions below.
-	 * - Pn is in the range of Pn_min and Pn_max
-	 * - F is in the range of 1 and 255
-	 * - FxP is within 25% of desired value.
-	 *   Note: 25% is arbitrary value and may need some tweak.
-	 */
-	if (drm_dp_dpcd_readb(&intel_dp->aux,
-			       DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) {
-		DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
-		return false;
-	}
-	if (drm_dp_dpcd_readb(&intel_dp->aux,
-			       DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) {
-		DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
-		return false;
-	}
-	pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
-	pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
-
+	/* Ensure frequency is within 25% of desired value */
 	fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4);
 	fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4);
-	if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) {
-		DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
-		return false;
-	}
-
-	for (pn = pn_max; pn >= pn_min; pn--) {
-		f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255);
-		fxp_actual = f << pn;
-		if (fxp_min <= fxp_actual && fxp_actual <= fxp_max)
-			break;
-	}
 
-	if (drm_dp_dpcd_writeb(&intel_dp->aux,
-			       DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) {
-		DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
+	if (fxp_min > fxp_actual || fxp_actual > fxp_max) {
+		DRM_DEBUG_KMS("Actual frequency out of range\n");
 		return false;
 	}
+
 	if (drm_dp_dpcd_writeb(&intel_dp->aux,
 			       DP_EDP_BACKLIGHT_FREQ_SET, (u8) f) < 0) {
 		DRM_DEBUG_KMS("Failed to write aux backlight freq\n");
@@ -178,6 +160,7 @@
 					  const struct drm_connector_state *conn_state)
 {
 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	struct intel_panel *panel = &connector->panel;
 	struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
 	u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode;
 
@@ -197,6 +180,12 @@
 	case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT:
 		new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
 		new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD;
+
+		if (drm_dp_dpcd_writeb(&intel_dp->aux,
+				       DP_EDP_PWMGEN_BIT_COUNT,
+				       panel->backlight.pwmgen_bit_count) < 0)
+			DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
+
 		break;
 
 	/* Do nothing when it is already DPCD mode */
@@ -216,8 +205,9 @@
 		}
 	}
 
+	intel_dp_aux_set_backlight(conn_state,
+				   connector->panel.backlight.level);
 	set_aux_backlight_enable(intel_dp, true);
-	intel_dp_aux_set_backlight(conn_state, connector->panel.backlight.level);
 }
 
 static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state)
@@ -225,20 +215,91 @@
 	set_aux_backlight_enable(enc_to_intel_dp(old_conn_state->best_encoder), false);
 }
 
+static u32 intel_dp_aux_calc_max_backlight(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
+	struct intel_panel *panel = &connector->panel;
+	u32 max_backlight = 0;
+	int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1;
+	u8 pn, pn_min, pn_max;
+
+	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT, &pn)) {
+		pn &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
+		max_backlight = (1 << pn) - 1;
+	}
+
+	/* Find desired value of (F x P)
+	 * Note that, if F x P is out of supported range, the maximum value or
+	 * minimum value will applied automatically. So no need to check that.
+	 */
+	freq = dev_priv->vbt.backlight.pwm_freq_hz;
+	DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq);
+	if (!freq) {
+		DRM_DEBUG_KMS("Use panel default backlight frequency\n");
+		return max_backlight;
+	}
+
+	fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq);
+
+	/* Use highest possible value of Pn for more granularity of brightness
+	 * adjustment while satifying the conditions below.
+	 * - Pn is in the range of Pn_min and Pn_max
+	 * - F is in the range of 1 and 255
+	 * - FxP is within 25% of desired value.
+	 *   Note: 25% is arbitrary value and may need some tweak.
+	 */
+	if (drm_dp_dpcd_readb(&intel_dp->aux,
+			      DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) {
+		DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
+		return max_backlight;
+	}
+	if (drm_dp_dpcd_readb(&intel_dp->aux,
+			      DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) {
+		DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
+		return max_backlight;
+	}
+	pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
+	pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK;
+
+	fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4);
+	fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4);
+	if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) {
+		DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
+		return max_backlight;
+	}
+
+	for (pn = pn_max; pn >= pn_min; pn--) {
+		f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255);
+		fxp_actual = f << pn;
+		if (fxp_min <= fxp_actual && fxp_actual <= fxp_max)
+			break;
+	}
+
+	DRM_DEBUG_KMS("Using eDP pwmgen bit count of %d\n", pn);
+	if (drm_dp_dpcd_writeb(&intel_dp->aux,
+			       DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) {
+		DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
+		return max_backlight;
+	}
+	panel->backlight.pwmgen_bit_count = pn;
+
+	max_backlight = (1 << pn) - 1;
+
+	return max_backlight;
+}
+
 static int intel_dp_aux_setup_backlight(struct intel_connector *connector,
 					enum pipe pipe)
 {
-	struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base);
 	struct intel_panel *panel = &connector->panel;
 
-	if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
-		panel->backlight.max = 0xFFFF;
-	else
-		panel->backlight.max = 0xFF;
+	panel->backlight.max = intel_dp_aux_calc_max_backlight(connector);
+	if (!panel->backlight.max)
+		return -ENODEV;
 
 	panel->backlight.min = 0;
 	panel->backlight.level = intel_dp_aux_get_backlight(connector);
-
 	panel->backlight.enabled = panel->backlight.level != 0;
 
 	return 0;
@@ -264,15 +325,35 @@
 int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector)
 {
 	struct intel_panel *panel = &intel_connector->panel;
-	struct drm_i915_private *dev_priv = to_i915(intel_connector->base.dev);
+	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_connector->encoder->base);
+	struct drm_device *dev = intel_connector->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	bool force_dpcd;
+
+	force_dpcd = drm_dp_has_quirk(&intel_dp->desc, intel_dp->edid_quirks,
+				      DP_QUIRK_FORCE_DPCD_BACKLIGHT);
 
 	if (i915_modparams.enable_dpcd_backlight == 0 ||
-	    (i915_modparams.enable_dpcd_backlight == -1 &&
-	    dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE))
+	    (!force_dpcd && !intel_dp_aux_display_control_capable(intel_connector)))
 		return -ENODEV;
 
-	if (!intel_dp_aux_display_control_capable(intel_connector))
+	/*
+	 * There are a lot of machines that don't advertise the backlight
+	 * control interface to use properly in their VBIOS, :\
+	 */
+	if (dev_priv->vbt.backlight.type !=
+	    INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE &&
+	    i915_modparams.enable_dpcd_backlight != 1 && !force_dpcd) {
+		DRM_DEV_INFO(dev->dev,
+			     "Panel advertises DPCD backlight support, but "
+			     "VBT disagrees. If your backlight controls "
+			     "don't work try booting with "
+			     "i915.enable_dpcd_backlight=1. If your machine "
+			     "needs this, please file a _new_ bug report on "
+			     "bugs.freedesktop.org against DRI -> "
+			     "DRM/Intel\n");
 		return -ENODEV;
+	}
 
 	panel->backlight.setup = intel_dp_aux_setup_backlight;
 	panel->backlight.enable = intel_dp_aux_enable_backlight;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -50,7 +50,7 @@
 	const struct drm_display_mode *adjusted_mode =
 		&crtc_state->base.adjusted_mode;
 	void *port = connector->port;
-	bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
+	bool constant_n = drm_dp_has_quirk(&intel_dp->desc, 0,
 					   DP_DPCD_QUIRK_CONSTANT_N);
 	int bpp, slots = -EINVAL;
 
@@ -520,6 +520,7 @@
 	ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
 				 DRM_MODE_CONNECTOR_DisplayPort);
 	if (ret) {
+		drm_dp_mst_put_port_malloc(port);
 		intel_connector_free(intel_connector);
 		return NULL;
 	}
@@ -653,21 +654,31 @@
 int
 intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
 {
+	struct drm_i915_private *i915 = to_i915(intel_dig_port->base.base.dev);
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
-	struct drm_device *dev = intel_dig_port->base.base.dev;
+	enum port port = intel_dig_port->base.port;
 	int ret;
 
-	intel_dp->can_mst = true;
+	if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp))
+		return 0;
+
+	if (INTEL_GEN(i915) < 12 && port == PORT_A)
+		return 0;
+
+	if (INTEL_GEN(i915) < 11 && port == PORT_E)
+		return 0;
+
 	intel_dp->mst_mgr.cbs = &mst_cbs;
 
 	/* create encoders */
 	intel_dp_create_fake_mst_encoders(intel_dig_port);
-	ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
+	ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm,
 					   &intel_dp->aux, 16, 3, conn_base_id);
-	if (ret) {
-		intel_dp->can_mst = false;
+	if (ret)
 		return ret;
-	}
+
+	intel_dp->can_mst = true;
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_fbc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -504,8 +504,7 @@
 	if (!ret)
 		goto err_llb;
 	else if (ret > 1) {
-		DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n");
-
+		DRM_INFO_ONCE("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n");
 	}
 
 	fbc->threshold = ret;
@@ -1284,7 +1283,7 @@
 		return 0;
 
 	/* https://bugs.freedesktop.org/show_bug.cgi?id=108085 */
-	if (IS_GEMINILAKE(dev_priv))
+	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
 		return 0;
 
 	if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_frontbuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_frontbuffer.c
@@ -221,11 +221,11 @@
 	struct intel_frontbuffer *front =
 		container_of(ref, typeof(*front), ref);
 
-	front->obj->frontbuffer = NULL;
+	RCU_INIT_POINTER(front->obj->frontbuffer, NULL);
 	spin_unlock(&to_i915(front->obj->base.dev)->fb_tracking.lock);
 
 	i915_gem_object_put(front->obj);
-	kfree(front);
+	kfree_rcu(front, rcu);
 }
 
 struct intel_frontbuffer *
@@ -234,11 +234,7 @@
 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
 	struct intel_frontbuffer *front;
 
-	spin_lock(&i915->fb_tracking.lock);
-	front = obj->frontbuffer;
-	if (front)
-		kref_get(&front->ref);
-	spin_unlock(&i915->fb_tracking.lock);
+	front = __intel_frontbuffer_get(obj);
 	if (front)
 		return front;
 
@@ -253,13 +249,13 @@
 			 frontbuffer_active, frontbuffer_retire);
 
 	spin_lock(&i915->fb_tracking.lock);
-	if (obj->frontbuffer) {
+	if (rcu_access_pointer(obj->frontbuffer)) {
 		kfree(front);
-		front = obj->frontbuffer;
+		front = rcu_dereference_protected(obj->frontbuffer, true);
 		kref_get(&front->ref);
 	} else {
 		i915_gem_object_get(obj);
-		obj->frontbuffer = front;
+		rcu_assign_pointer(obj->frontbuffer, front);
 	}
 	spin_unlock(&i915->fb_tracking.lock);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_frontbuffer.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_frontbuffer.h
@@ -27,10 +27,10 @@
 #include <linux/atomic.h>
 #include <linux/kref.h>
 
+#include "gem/i915_gem_object_types.h"
 #include "i915_active.h"
 
 struct drm_i915_private;
-struct drm_i915_gem_object;
 
 enum fb_op_origin {
 	ORIGIN_GTT,
@@ -45,6 +45,7 @@
 	atomic_t bits;
 	struct i915_active write;
 	struct drm_i915_gem_object *obj;
+	struct rcu_head rcu;
 };
 
 void intel_frontbuffer_flip_prepare(struct drm_i915_private *i915,
@@ -54,6 +55,35 @@
 void intel_frontbuffer_flip(struct drm_i915_private *i915,
 			    unsigned frontbuffer_bits);
 
+void intel_frontbuffer_put(struct intel_frontbuffer *front);
+
+static inline struct intel_frontbuffer *
+__intel_frontbuffer_get(const struct drm_i915_gem_object *obj)
+{
+	struct intel_frontbuffer *front;
+
+	if (likely(!rcu_access_pointer(obj->frontbuffer)))
+		return NULL;
+
+	rcu_read_lock();
+	do {
+		front = rcu_dereference(obj->frontbuffer);
+		if (!front)
+			break;
+
+		if (unlikely(!kref_get_unless_zero(&front->ref)))
+			continue;
+
+		if (likely(front == rcu_access_pointer(obj->frontbuffer)))
+			break;
+
+		intel_frontbuffer_put(front);
+	} while (1);
+	rcu_read_unlock();
+
+	return front;
+}
+
 struct intel_frontbuffer *
 intel_frontbuffer_get(struct drm_i915_gem_object *obj);
 
@@ -119,6 +149,4 @@
 			     struct intel_frontbuffer *new,
 			     unsigned int frontbuffer_bits);
 
-void intel_frontbuffer_put(struct intel_frontbuffer *front);
-
 #endif /* __INTEL_FRONTBUFFER_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1232,6 +1232,11 @@
 	if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
 		return;
 
+	if (dev_priv->bypass_tmds_oe) {
+		DRM_DEBUG_KMS("Bypassing TMDS_OE setting\n");
+		return;
+	}
+
 	DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
 		      enable ? "Enabling" : "Disabling");
 
@@ -2129,7 +2134,11 @@
 	if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits, force_dvi))
 		return MODE_CLOCK_HIGH;
 
-	/* BXT DPLL can't generate 223-240 MHz */
+	/* GLK DPLL can't generate 446-480 MHz */
+	if (IS_GEMINILAKE(dev_priv) && clock > 446666 && clock < 480000)
+		return MODE_CLOCK_RANGE;
+
+	/* BXT/GLK DPLL can't generate 223-240 MHz */
 	if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000)
 		return MODE_CLOCK_RANGE;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_lpe_audio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_lpe_audio.c
@@ -172,6 +172,14 @@
 				handle_simple_irq,
 				"hdmi_lpe_audio_irq_handler");
 
+	static const struct pci_device_id irq_quirk_ids[] = {
+		/* Dell Wyse 3040 */
+		{PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x22b0, 0x1028, 0x07c1)},
+		{}
+	};
+
+	if (pci_dev_present(irq_quirk_ids))
+		return 0;
 	return irq_set_chip_data(irq, dev_priv);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_overlay.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_overlay.c
@@ -278,12 +278,21 @@
 				       struct i915_vma *vma)
 {
 	enum pipe pipe = overlay->crtc->pipe;
+	struct intel_frontbuffer *from = NULL, *to = NULL;
 
 	WARN_ON(overlay->old_vma);
 
-	intel_frontbuffer_track(overlay->vma ? overlay->vma->obj->frontbuffer : NULL,
-				vma ? vma->obj->frontbuffer : NULL,
-				INTEL_FRONTBUFFER_OVERLAY(pipe));
+	if (overlay->vma)
+		from = intel_frontbuffer_get(overlay->vma->obj);
+	if (vma)
+		to = intel_frontbuffer_get(vma->obj);
+
+	intel_frontbuffer_track(from, to, INTEL_FRONTBUFFER_OVERLAY(pipe));
+
+	if (to)
+		intel_frontbuffer_put(to);
+	if (from)
+		intel_frontbuffer_put(from);
 
 	intel_frontbuffer_flip_prepare(overlay->i915,
 				       INTEL_FRONTBUFFER_OVERLAY(pipe));
@@ -768,7 +777,7 @@
 		ret = PTR_ERR(vma);
 		goto out_pin_section;
 	}
-	intel_frontbuffer_flush(new_bo->frontbuffer, ORIGIN_DIRTYFB);
+	i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB);
 
 	if (!overlay->active) {
 		u32 oconfig;
@@ -913,6 +922,9 @@
 	const struct intel_crtc_state *pipe_config =
 		overlay->crtc->config;
 
+	if (rec->dst_height == 0 || rec->dst_width == 0)
+		return -EINVAL;
+
 	if (rec->dst_x < pipe_config->pipe_src_w &&
 	    rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
 	    rec->dst_y < pipe_config->pipe_src_h &&
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_panel.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1603,20 +1603,21 @@
 		val = pch_get_backlight(connector);
 	else
 		val = lpt_get_backlight(connector);
-	val = intel_panel_compute_brightness(connector, val);
-	panel->backlight.level = clamp(val, panel->backlight.min,
-				       panel->backlight.max);
 
 	if (cpu_mode) {
 		DRM_DEBUG_KMS("CPU backlight register was enabled, switching to PCH override\n");
 
 		/* Write converted CPU PWM value to PCH override register */
-		lpt_set_backlight(connector->base.state, panel->backlight.level);
+		lpt_set_backlight(connector->base.state, val);
 		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
 
 		I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 & ~BLM_PWM_ENABLE);
 	}
 
+	val = intel_panel_compute_brightness(connector, val);
+	panel->backlight.level = clamp(val, panel->backlight.min,
+				       panel->backlight.max);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_psr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_psr.c
@@ -291,7 +291,7 @@
 	DRM_DEBUG_KMS("eDP panel supports PSR version %x\n",
 		      intel_dp->psr_dpcd[0]);
 
-	if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) {
+	if (drm_dp_has_quirk(&intel_dp->desc, 0, DP_DPCD_QUIRK_NO_PSR)) {
 		DRM_DEBUG_KMS("PSR support not currently available for this panel\n");
 		return;
 	}
@@ -1219,6 +1219,14 @@
 	if (!dev_priv->psr.sink_support)
 		return;
 
+	/*
+	 * PSR was disabled by module parameters but the underlying panel is
+	 * depending on it, so use per-chip default to probe that automatically.
+	 */
+	if ((dev_priv->psr.dp->edid_quirks & BIT(DP_QUIRK_FORCE_PSR_CHIP_DEFAULT)) &&
+	    i915_modparams.enable_psr == 0)
+		i915_modparams.enable_psr = -1;
+
 	if (i915_modparams.enable_psr == -1)
 		if (INTEL_GEN(dev_priv) < 9 || !dev_priv->vbt.psr.enable)
 			i915_modparams.enable_psr = 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_quirks.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -146,6 +146,11 @@
 	/* ASRock ITX*/
 	{ 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
 	{ 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time },
+	/* ECS Liva Q2 */
+	{ 0x3185, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
+	{ 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
+	/* HP Notebook - 14-r206nv */
+	{ 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
 };
 
 void intel_init_quirks(struct drm_i915_private *i915)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2693,13 +2693,10 @@
 	if (!intel_sdvo_connector)
 		return false;
 
-	if (device == 0) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0;
+	if (device == 0)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
-	} else if (device == 1) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1;
+	else if (device == 1)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
-	}
 
 	intel_connector = &intel_sdvo_connector->base;
 	connector = &intel_connector->base;
@@ -2753,7 +2750,6 @@
 	encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
 	connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 
-	intel_sdvo->controlled_output |= type;
 	intel_sdvo_connector->output_flag = type;
 
 	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
@@ -2794,13 +2790,10 @@
 	encoder->encoder_type = DRM_MODE_ENCODER_DAC;
 	connector->connector_type = DRM_MODE_CONNECTOR_VGA;
 
-	if (device == 0) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+	if (device == 0)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-	} else if (device == 1) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+	else if (device == 1)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-	}
 
 	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
 		kfree(intel_sdvo_connector);
@@ -2830,13 +2823,10 @@
 	encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
 	connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
 
-	if (device == 0) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+	if (device == 0)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-	} else if (device == 1) {
-		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+	else if (device == 1)
 		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-	}
 
 	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
 		kfree(intel_sdvo_connector);
@@ -2869,16 +2859,39 @@
 	return false;
 }
 
+static u16 intel_sdvo_filter_output_flags(u16 flags)
+{
+	flags &= SDVO_OUTPUT_MASK;
+
+	/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
+	if (!(flags & SDVO_OUTPUT_TMDS0))
+		flags &= ~SDVO_OUTPUT_TMDS1;
+
+	if (!(flags & SDVO_OUTPUT_RGB0))
+		flags &= ~SDVO_OUTPUT_RGB1;
+
+	if (!(flags & SDVO_OUTPUT_LVDS0))
+		flags &= ~SDVO_OUTPUT_LVDS1;
+
+	return flags;
+}
+
 static bool
 intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags)
 {
-	/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
+	struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
+
+	flags = intel_sdvo_filter_output_flags(flags);
+
+	intel_sdvo->controlled_output = flags;
+
+	intel_sdvo_select_ddc_bus(i915, intel_sdvo);
 
 	if (flags & SDVO_OUTPUT_TMDS0)
 		if (!intel_sdvo_dvi_init(intel_sdvo, 0))
 			return false;
 
-	if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
+	if (flags & SDVO_OUTPUT_TMDS1)
 		if (!intel_sdvo_dvi_init(intel_sdvo, 1))
 			return false;
 
@@ -2899,7 +2912,7 @@
 		if (!intel_sdvo_analog_init(intel_sdvo, 0))
 			return false;
 
-	if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
+	if (flags & SDVO_OUTPUT_RGB1)
 		if (!intel_sdvo_analog_init(intel_sdvo, 1))
 			return false;
 
@@ -2907,14 +2920,13 @@
 		if (!intel_sdvo_lvds_init(intel_sdvo, 0))
 			return false;
 
-	if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
+	if (flags & SDVO_OUTPUT_LVDS1)
 		if (!intel_sdvo_lvds_init(intel_sdvo, 1))
 			return false;
 
-	if ((flags & SDVO_OUTPUT_MASK) == 0) {
+	if (flags == 0) {
 		unsigned char bytes[2];
 
-		intel_sdvo->controlled_output = 0;
 		memcpy(bytes, &intel_sdvo->caps.output_flags, 2);
 		DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
 			      SDVO_NAME(intel_sdvo),
@@ -3321,8 +3333,6 @@
 	 */
 	intel_sdvo->base.cloneable = 0;
 
-	intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo);
-
 	/* Set the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		goto err_output;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/intel_tc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/intel_tc.c
@@ -45,6 +45,62 @@
 	return tc_port / 2;
 }
 
+static enum intel_display_power_domain
+tc_cold_get_power_domain(struct intel_digital_port *dig_port)
+{
+	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+	if (INTEL_GEN(i915) == 11)
+		return intel_legacy_aux_to_power_domain(dig_port->aux_ch);
+	else
+		return POWER_DOMAIN_TC_COLD_OFF;
+}
+
+static intel_wakeref_t
+tc_cold_block(struct intel_digital_port *dig_port)
+{
+	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+	enum intel_display_power_domain domain;
+
+	if (INTEL_GEN(i915) == 11 && !dig_port->tc_legacy_port)
+		return 0;
+
+	domain = tc_cold_get_power_domain(dig_port);
+	return intel_display_power_get(i915, domain);
+}
+
+static void
+tc_cold_unblock(struct intel_digital_port *dig_port, intel_wakeref_t wakeref)
+{
+	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+	enum intel_display_power_domain domain;
+
+	/*
+	 * wakeref == -1, means some error happened saving save_depot_stack but
+	 * power should still be put down and 0 is a invalid save_depot_stack
+	 * id so can be used to skip it for non TC legacy ports.
+	 */
+	if (wakeref == 0)
+		return;
+
+	domain = tc_cold_get_power_domain(dig_port);
+	intel_display_power_put_async(i915, domain, wakeref);
+}
+
+static void
+assert_tc_cold_blocked(struct intel_digital_port *dig_port)
+{
+	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+	bool enabled;
+
+	if (INTEL_GEN(i915) == 11 && !dig_port->tc_legacy_port)
+		return;
+
+	enabled = intel_display_power_is_enabled(i915,
+						 tc_cold_get_power_domain(dig_port));
+	WARN_ON(!enabled);
+}
+
 u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port)
 {
 	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
@@ -56,6 +112,7 @@
 				      PORT_TX_DFLEXDPSP(dig_port->tc_phy_fia));
 
 	WARN_ON(lane_mask == 0xffffffff);
+	assert_tc_cold_blocked(dig_port);
 
 	return (lane_mask & DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
 	       DP_LANE_ASSIGNMENT_SHIFT(tc_port);
@@ -70,6 +127,8 @@
 	if (dig_port->tc_mode != TC_PORT_DP_ALT)
 		return 4;
 
+	assert_tc_cold_blocked(dig_port);
+
 	lane_mask = 0;
 	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref)
 		lane_mask = intel_tc_port_get_lane_mask(dig_port);
@@ -102,6 +161,8 @@
 
 	WARN_ON(lane_reversal && dig_port->tc_mode != TC_PORT_LEGACY);
 
+	assert_tc_cold_blocked(dig_port);
+
 	val = intel_uncore_read(uncore,
 				PORT_TX_DFLEXDPMLE1(dig_port->tc_phy_fia));
 	val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc_port);
@@ -390,8 +451,14 @@
 	enum tc_port_mode old_tc_mode = dig_port->tc_mode;
 
 	intel_display_power_flush_work(i915);
-	WARN_ON(intel_display_power_is_enabled(i915,
-					       intel_aux_power_domain(dig_port)));
+	if (INTEL_GEN(i915) != 11 || !dig_port->tc_legacy_port) {
+		enum intel_display_power_domain aux_domain;
+		bool aux_powered;
+
+		aux_domain = intel_aux_power_domain(dig_port);
+		aux_powered = intel_display_power_is_enabled(i915, aux_domain);
+		WARN_ON(aux_powered);
+	}
 
 	icl_tc_phy_disconnect(dig_port);
 	icl_tc_phy_connect(dig_port, required_lanes);
@@ -413,9 +480,11 @@
 void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 {
 	struct intel_encoder *encoder = &dig_port->base;
+	intel_wakeref_t tc_cold_wref;
 	int active_links = 0;
 
 	mutex_lock(&dig_port->tc_lock);
+	tc_cold_wref = tc_cold_block(dig_port);
 
 	dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
 	if (dig_port->dp.is_mst)
@@ -440,6 +509,7 @@
 		      dig_port->tc_port_name,
 		      tc_port_mode_name(dig_port->tc_mode));
 
+	tc_cold_unblock(dig_port, tc_cold_wref);
 	mutex_unlock(&dig_port->tc_lock);
 }
 
@@ -461,10 +531,15 @@
 bool intel_tc_port_connected(struct intel_digital_port *dig_port)
 {
 	bool is_connected;
+	intel_wakeref_t tc_cold_wref;
 
 	intel_tc_port_lock(dig_port);
+	tc_cold_wref = tc_cold_block(dig_port);
+
 	is_connected = tc_port_live_status_mask(dig_port) &
 		       BIT(dig_port->tc_mode);
+
+	tc_cold_unblock(dig_port, tc_cold_wref);
 	intel_tc_port_unlock(dig_port);
 
 	return is_connected;
@@ -480,9 +555,16 @@
 
 	mutex_lock(&dig_port->tc_lock);
 
-	if (!dig_port->tc_link_refcount &&
-	    intel_tc_port_needs_reset(dig_port))
-		intel_tc_port_reset_mode(dig_port, required_lanes);
+	if (!dig_port->tc_link_refcount) {
+		intel_wakeref_t tc_cold_wref;
+
+		tc_cold_wref = tc_cold_block(dig_port);
+
+		if (intel_tc_port_needs_reset(dig_port))
+			intel_tc_port_reset_mode(dig_port, required_lanes);
+
+		tc_cold_unblock(dig_port, tc_cold_wref);
+	}
 
 	WARN_ON(dig_port->tc_lock_wakeref);
 	dig_port->tc_lock_wakeref = wakeref;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -797,10 +797,20 @@
 	if (intel_dsi->gpio_panel)
 		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
 	intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
-	intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
 
-	/* Deassert reset */
-	intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+	/*
+	 * Give the panel time to power-on and then deassert its reset.
+	 * Depending on the VBT MIPI sequences version the deassert-seq
+	 * may contain the necessary delay, intel_dsi_msleep() will skip
+	 * the delay in that case. If there is no deassert-seq, then an
+	 * unconditional msleep is used to give the panel time to power-on.
+	 */
+	if (dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) {
+		intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
+		intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+	} else {
+		msleep(intel_dsi->panel_on_delay);
+	}
 
 	if (IS_GEMINILAKE(dev_priv)) {
 		glk_cold_boot = glk_dsi_enable_io(encoder);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_busy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_busy.c
@@ -9,16 +9,16 @@
 #include "i915_gem_ioctls.h"
 #include "i915_gem_object.h"
 
-static __always_inline u32 __busy_read_flag(u8 id)
+static __always_inline u32 __busy_read_flag(u16 id)
 {
-	if (id == (u8)I915_ENGINE_CLASS_INVALID)
+	if (id == (u16)I915_ENGINE_CLASS_INVALID)
 		return 0xffff0000u;
 
 	GEM_BUG_ON(id >= 16);
 	return 0x10000u << id;
 }
 
-static __always_inline u32 __busy_write_id(u8 id)
+static __always_inline u32 __busy_write_id(u16 id)
 {
 	/*
 	 * The uABI guarantees an active writer is also amongst the read
@@ -29,14 +29,14 @@
 	 * last_read - hence we always set both read and write busy for
 	 * last_write.
 	 */
-	if (id == (u8)I915_ENGINE_CLASS_INVALID)
+	if (id == (u16)I915_ENGINE_CLASS_INVALID)
 		return 0xffffffffu;
 
 	return (id + 1) | __busy_read_flag(id);
 }
 
 static __always_inline unsigned int
-__busy_set_if_active(const struct dma_fence *fence, u32 (*flag)(u8 id))
+__busy_set_if_active(const struct dma_fence *fence, u32 (*flag)(u16 id))
 {
 	const struct i915_request *rq;
 
@@ -57,7 +57,7 @@
 		return 0;
 
 	/* Beware type-expansion follies! */
-	BUILD_BUG_ON(!typecheck(u8, rq->engine->uabi_class));
+	BUILD_BUG_ON(!typecheck(u16, rq->engine->uabi_class));
 	return flag(rq->engine->uabi_class);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
@@ -20,7 +20,8 @@
 {
 	GEM_BUG_ON(!i915_gem_object_has_pages(obj));
 	drm_clflush_sg(obj->mm.pages);
-	intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+
+	i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 }
 
 static int clflush_work(struct dma_fence_work *base)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -2094,8 +2094,7 @@
 	ext_data.fpriv = file->driver_priv;
 	if (client_is_banned(ext_data.fpriv)) {
 		DRM_DEBUG("client %s[%d] banned from creating ctx\n",
-			  current->comm,
-			  pid_nr(get_task_pid(current, PIDTYPE_PID)));
+			  current->comm, task_pid_nr(current));
 		return -EIO;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -36,13 +36,13 @@
 		goto err_unpin_pages;
 	}
 
-	ret = sg_alloc_table(st, obj->mm.pages->nents, GFP_KERNEL);
+	ret = sg_alloc_table(st, obj->mm.pages->orig_nents, GFP_KERNEL);
 	if (ret)
 		goto err_free;
 
 	src = obj->mm.pages->sgl;
 	dst = st->sgl;
-	for (i = 0; i < obj->mm.pages->nents; i++) {
+	for (i = 0; i < obj->mm.pages->orig_nents; i++) {
 		sg_set_page(dst, sg_page(src), src->length, 0);
 		dst = sg_next(dst);
 		src = sg_next(src);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_domain.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_domain.c
@@ -606,21 +606,6 @@
 		return -ENOENT;
 
 	/*
-	 * Already in the desired write domain? Nothing for us to do!
-	 *
-	 * We apply a little bit of cunning here to catch a broader set of
-	 * no-ops. If obj->write_domain is set, we must be in the same
-	 * obj->read_domains, and only that domain. Therefore, if that
-	 * obj->write_domain matches the request read_domains, we are
-	 * already in the same read/write domain and can skip the operation,
-	 * without having to further check the requested write_domain.
-	 */
-	if (READ_ONCE(obj->write_domain) == read_domains) {
-		err = 0;
-		goto out;
-	}
-
-	/*
 	 * Try to flush the object off the GPU without holding the lock.
 	 * We will repeat the flush holding the lock in the normal manner
 	 * to catch cases where we are gazumped.
@@ -657,6 +642,19 @@
 	if (err)
 		goto out;
 
+	/*
+	 * Already in the desired write domain? Nothing for us to do!
+	 *
+	 * We apply a little bit of cunning here to catch a broader set of
+	 * no-ops. If obj->write_domain is set, we must be in the same
+	 * obj->read_domains, and only that domain. Therefore, if that
+	 * obj->write_domain matches the request read_domains, we are
+	 * already in the same read/write domain and can skip the operation,
+	 * without having to further check the requested write_domain.
+	 */
+	if (READ_ONCE(obj->write_domain) == read_domains)
+		goto out_unpin;
+
 	err = i915_gem_object_lock_interruptible(obj);
 	if (err)
 		goto out_unpin;
@@ -674,7 +672,7 @@
 	i915_gem_object_unlock(obj);
 
 	if (write_domain)
-		intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+		i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
 out_unpin:
 	i915_gem_object_unpin_pages(obj);
@@ -794,7 +792,7 @@
 	}
 
 out:
-	intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 	obj->mm.dirty = true;
 	/* return with the pages pinned */
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -367,7 +367,7 @@
 		return true;
 
 	if (!(flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) &&
-	    (vma->node.start + vma->node.size - 1) >> 32)
+	    (vma->node.start + vma->node.size + 4095) >> 32)
 		return true;
 
 	if (flags & __EXEC_OBJECT_NEEDS_MAP &&
@@ -439,7 +439,8 @@
 	if (unlikely(entry->flags & eb->invalid_flags))
 		return -EINVAL;
 
-	if (unlikely(entry->alignment && !is_power_of_2(entry->alignment)))
+	if (unlikely(entry->alignment &&
+		     !is_power_of_2_u64(entry->alignment)))
 		return -EINVAL;
 
 	/*
@@ -930,11 +931,13 @@
 
 static void reloc_gpu_flush(struct reloc_cache *cache)
 {
-	GEM_BUG_ON(cache->rq_size >= cache->rq->batch->obj->base.size / sizeof(u32));
+	struct drm_i915_gem_object *obj = cache->rq->batch->obj;
+
+	GEM_BUG_ON(cache->rq_size >= obj->base.size / sizeof(u32));
 	cache->rq_cmd[cache->rq_size] = MI_BATCH_BUFFER_END;
 
-	__i915_gem_object_flush_map(cache->rq->batch->obj, 0, cache->rq_size);
-	i915_gem_object_unpin_map(cache->rq->batch->obj);
+	i915_gem_object_flush_map(obj);
+	i915_gem_object_unpin_map(obj);
 
 	intel_gt_chipset_flush(cache->rq->engine->gt);
 
@@ -1160,6 +1163,8 @@
 		goto out_pool;
 	}
 
+	memset32(cmd, 0, pool->obj->base.size / sizeof(u32));
+
 	batch = i915_vma_instance(pool->obj, vma->vm, NULL);
 	if (IS_ERR(batch)) {
 		err = PTR_ERR(batch);
@@ -1447,7 +1452,7 @@
 
 	urelocs = u64_to_user_ptr(entry->relocs_ptr);
 	remain = entry->relocation_count;
-	if (unlikely(remain > N_RELOC(ULONG_MAX)))
+	if (unlikely((unsigned long)remain > N_RELOC(ULONG_MAX)))
 		return -EINVAL;
 
 	/*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_mman.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_mman.c
@@ -181,7 +181,7 @@
 	struct i915_ggtt_view view;
 
 	if (i915_gem_object_is_tiled(obj))
-		chunk = roundup(chunk, tile_row_pages(obj));
+		chunk = roundup(chunk, tile_row_pages(obj) ?: 1);
 
 	view.type = I915_GGTT_VIEW_PARTIAL;
 	view.partial.offset = rounddown(page_offset, chunk);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -270,7 +270,7 @@
 		for_each_ggtt_vma(vma, obj)
 			intel_gt_flush_ggtt_writes(vma->vm->gt);
 
-		intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+		i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 
 		for_each_ggtt_vma(vma, obj) {
 			if (vma->iomap)
@@ -298,6 +298,30 @@
 	obj->write_domain = 0;
 }
 
+void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+					 enum fb_op_origin origin)
+{
+	struct intel_frontbuffer *front;
+
+	front = __intel_frontbuffer_get(obj);
+	if (front) {
+		intel_frontbuffer_flush(front, origin);
+		intel_frontbuffer_put(front);
+	}
+}
+
+void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+					      enum fb_op_origin origin)
+{
+	struct intel_frontbuffer *front;
+
+	front = __intel_frontbuffer_get(obj);
+	if (front) {
+		intel_frontbuffer_invalidate(front, origin);
+		intel_frontbuffer_put(front);
+	}
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -13,8 +13,8 @@
 
 #include <drm/i915_drm.h>
 
+#include "display/intel_frontbuffer.h"
 #include "i915_gem_object_types.h"
-
 #include "i915_gem_gtt.h"
 
 void i915_gem_init__objects(struct drm_i915_private *i915);
@@ -431,4 +431,25 @@
 				  const struct i915_sched_attr *attr);
 #define I915_PRIORITY_DISPLAY I915_USER_PRIORITY(I915_PRIORITY_MAX)
 
+void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+					 enum fb_op_origin origin);
+void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+					      enum fb_op_origin origin);
+
+static inline void
+i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+				  enum fb_op_origin origin)
+{
+	if (unlikely(rcu_access_pointer(obj->frontbuffer)))
+		__i915_gem_object_flush_frontbuffer(obj, origin);
+}
+
+static inline void
+i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+				       enum fb_op_origin origin)
+{
+	if (unlikely(rcu_access_pointer(obj->frontbuffer)))
+		__i915_gem_object_invalidate_frontbuffer(obj, origin);
+}
+
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -118,6 +118,9 @@
 
 	I915_SELFTEST_DECLARE(struct list_head st_link);
 
+	unsigned long flags;
+#define I915_BO_WAS_BOUND_BIT    0
+
 	/*
 	 * Is the object to be mapped as read-only to the GPU
 	 * Only honoured if hardware has relevant pte bit
@@ -143,7 +146,7 @@
 	 */
 	u16 write_domain;
 
-	struct intel_frontbuffer *frontbuffer;
+	struct intel_frontbuffer __rcu *frontbuffer;
 
 	/** Current tiling stride for the object, if it's tiled. */
 	unsigned int tiling_and_stride;
@@ -240,9 +243,6 @@
 
 		void *gvt_info;
 	};
-
-	/** for phys allocated objects */
-	struct drm_dma_handle *phys_handle;
 };
 
 static inline struct drm_i915_gem_object *
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -8,6 +8,8 @@
 #include "i915_gem_object.h"
 #include "i915_scatterlist.h"
 
+#include "gt/intel_gt.h"
+
 void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
 				 struct sg_table *pages,
 				 unsigned int sg_page_sizes)
@@ -176,6 +178,14 @@
 	__i915_gem_object_reset_page_iter(obj);
 	obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
 
+	if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
+		struct drm_i915_private *i915 = to_i915(obj->base.dev);
+		intel_wakeref_t wakeref;
+
+		with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref)
+			intel_gt_invalidate_tlbs(&i915->gt);
+	}
+
 	return pages;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_phys.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_phys.c
@@ -21,88 +21,87 @@
 static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
 {
 	struct address_space *mapping = obj->base.filp->f_mapping;
-	struct drm_dma_handle *phys;
-	struct sg_table *st;
 	struct scatterlist *sg;
-	char *vaddr;
+	struct sg_table *st;
+	dma_addr_t dma;
+	void *vaddr;
+	void *dst;
 	int i;
-	int err;
 
 	if (WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
 		return -EINVAL;
 
-	/* Always aligning to the object size, allows a single allocation
+	/*
+	 * Always aligning to the object size, allows a single allocation
 	 * to handle all possible callers, and given typical object sizes,
 	 * the alignment of the buddy allocation will naturally match.
 	 */
-	phys = drm_pci_alloc(obj->base.dev,
-			     roundup_pow_of_two(obj->base.size),
-			     roundup_pow_of_two(obj->base.size));
-	if (!phys)
+	vaddr = dma_alloc_coherent(&obj->base.dev->pdev->dev,
+				   roundup_pow_of_two(obj->base.size),
+				   &dma, GFP_KERNEL);
+	if (!vaddr)
 		return -ENOMEM;
 
-	vaddr = phys->vaddr;
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		goto err_pci;
+
+	if (sg_alloc_table(st, 1, GFP_KERNEL))
+		goto err_st;
+
+	sg = st->sgl;
+	sg->offset = 0;
+	sg->length = obj->base.size;
+
+	sg_assign_page(sg, (struct page *)vaddr);
+	sg_dma_address(sg) = dma;
+	sg_dma_len(sg) = obj->base.size;
+
+	dst = vaddr;
 	for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
 		struct page *page;
-		char *src;
+		void *src;
 
 		page = shmem_read_mapping_page(mapping, i);
-		if (IS_ERR(page)) {
-			err = PTR_ERR(page);
-			goto err_phys;
-		}
+		if (IS_ERR(page))
+			goto err_st;
 
 		src = kmap_atomic(page);
-		memcpy(vaddr, src, PAGE_SIZE);
-		drm_clflush_virt_range(vaddr, PAGE_SIZE);
+		memcpy(dst, src, PAGE_SIZE);
+		drm_clflush_virt_range(dst, PAGE_SIZE);
 		kunmap_atomic(src);
 
 		put_page(page);
-		vaddr += PAGE_SIZE;
+		dst += PAGE_SIZE;
 	}
 
 	intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt);
 
-	st = kmalloc(sizeof(*st), GFP_KERNEL);
-	if (!st) {
-		err = -ENOMEM;
-		goto err_phys;
-	}
-
-	if (sg_alloc_table(st, 1, GFP_KERNEL)) {
-		kfree(st);
-		err = -ENOMEM;
-		goto err_phys;
-	}
-
-	sg = st->sgl;
-	sg->offset = 0;
-	sg->length = obj->base.size;
-
-	sg_dma_address(sg) = phys->busaddr;
-	sg_dma_len(sg) = obj->base.size;
-
-	obj->phys_handle = phys;
-
 	__i915_gem_object_set_pages(obj, st, sg->length);
 
 	return 0;
 
-err_phys:
-	drm_pci_free(obj->base.dev, phys);
-
-	return err;
+err_st:
+	kfree(st);
+err_pci:
+	dma_free_coherent(&obj->base.dev->pdev->dev,
+			  roundup_pow_of_two(obj->base.size),
+			  vaddr, dma);
+	return -ENOMEM;
 }
 
 static void
 i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
 			       struct sg_table *pages)
 {
+	dma_addr_t dma = sg_dma_address(pages->sgl);
+	void *vaddr = sg_page(pages->sgl);
+
 	__i915_gem_object_release_shmem(obj, pages, false);
 
 	if (obj->mm.dirty) {
 		struct address_space *mapping = obj->base.filp->f_mapping;
-		char *vaddr = obj->phys_handle->vaddr;
+		void *src = vaddr;
 		int i;
 
 		for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
@@ -114,15 +113,16 @@
 				continue;
 
 			dst = kmap_atomic(page);
-			drm_clflush_virt_range(vaddr, PAGE_SIZE);
-			memcpy(dst, vaddr, PAGE_SIZE);
+			drm_clflush_virt_range(src, PAGE_SIZE);
+			memcpy(dst, src, PAGE_SIZE);
 			kunmap_atomic(dst);
 
 			set_page_dirty(page);
 			if (obj->mm.madv == I915_MADV_WILLNEED)
 				mark_page_accessed(page);
 			put_page(page);
-			vaddr += PAGE_SIZE;
+
+			src += PAGE_SIZE;
 		}
 		obj->mm.dirty = false;
 	}
@@ -130,7 +130,9 @@
 	sg_free_table(pages);
 	kfree(pages);
 
-	drm_pci_free(obj->base.dev, obj->phys_handle);
+	dma_free_coherent(&obj->base.dev->pdev->dev,
+			  roundup_pow_of_two(obj->base.size),
+			  vaddr, dma);
 }
 
 static void phys_release(struct drm_i915_gem_object *obj)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -36,7 +36,6 @@
 	unsigned long last_pfn = 0;	/* suppress gcc warning */
 	unsigned int max_segment = i915_sg_segment_size();
 	unsigned int sg_page_sizes;
-	struct pagevec pvec;
 	gfp_t noreclaim;
 	int ret;
 
@@ -188,13 +187,17 @@
 	sg_mark_end(sg);
 err_pages:
 	mapping_clear_unevictable(mapping);
-	pagevec_init(&pvec);
-	for_each_sgt_page(page, sgt_iter, st) {
-		if (!pagevec_add(&pvec, page))
+	if (sg != st->sgl) {
+		struct pagevec pvec;
+
+		pagevec_init(&pvec);
+		for_each_sgt_page(page, sgt_iter, st) {
+			if (!pagevec_add(&pvec, page))
+				check_release_pagevec(&pvec);
+		}
+		if (pagevec_count(&pvec))
 			check_release_pagevec(&pvec);
 	}
-	if (pagevec_count(&pvec))
-		check_release_pagevec(&pvec);
 	sg_free_table(st);
 	kfree(st);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -357,8 +357,7 @@
 				sc->nr_to_scan,
 				&sc->nr_scanned,
 				I915_SHRINK_BOUND |
-				I915_SHRINK_UNBOUND |
-				I915_SHRINK_WRITEBACK);
+				I915_SHRINK_UNBOUND);
 	if (sc->nr_scanned < sc->nr_to_scan && current_is_kswapd()) {
 		intel_wakeref_t wakeref;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
@@ -427,7 +427,7 @@
 
 static struct sg_table *
 __i915_gem_userptr_alloc_pages(struct drm_i915_gem_object *obj,
-			       struct page **pvec, int num_pages)
+			       struct page **pvec, unsigned long num_pages)
 {
 	unsigned int max_segment = i915_sg_segment_size();
 	struct sg_table *st;
@@ -473,9 +473,10 @@
 {
 	struct get_pages_work *work = container_of(_work, typeof(*work), work);
 	struct drm_i915_gem_object *obj = work->obj;
-	const int npages = obj->base.size >> PAGE_SHIFT;
+	const unsigned long npages = obj->base.size >> PAGE_SHIFT;
+	unsigned long pinned;
 	struct page **pvec;
-	int pinned, ret;
+	int ret;
 
 	ret = -ENOMEM;
 	pinned = 0;
@@ -578,7 +579,7 @@
 
 static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 {
-	const int num_pages = obj->base.size >> PAGE_SHIFT;
+	const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
 	struct mm_struct *mm = obj->userptr.mm->mm;
 	struct page **pvec;
 	struct sg_table *pages;
@@ -618,6 +619,14 @@
 				      GFP_KERNEL |
 				      __GFP_NORETRY |
 				      __GFP_NOWARN);
+		/*
+		 * 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.
+		 */
 		if (pvec) /* defer to worker if malloc fails */
 			pinned = __get_user_pages_fast(obj->userptr.ptr,
 						       num_pages,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -375,7 +375,7 @@
 
 	obj = i915_gem_object_create_internal(i915, size);
 	if (IS_ERR(obj))
-		return PTR_ERR(obj);
+		return false;
 
 	err = create_mmap_offset(obj);
 	i915_gem_object_put(obj);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_engine.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_engine.h
@@ -250,6 +250,14 @@
 	return pos & (ring->size - 1);
 }
 
+static inline int intel_ring_direction(const struct intel_ring *ring,
+				       u32 next, u32 prev)
+{
+	typecheck(typeof(ring->size), next);
+	typecheck(typeof(ring->size), prev);
+	return (next - prev) << ring->wrap;
+}
+
 static inline bool
 intel_ring_offset_valid(const struct intel_ring *ring,
 			unsigned int pos)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -28,13 +28,13 @@
 
 #include "i915_drv.h"
 
-#include "gt/intel_gt.h"
-
+#include "intel_context.h"
 #include "intel_engine.h"
 #include "intel_engine_pm.h"
 #include "intel_engine_pool.h"
 #include "intel_engine_user.h"
-#include "intel_context.h"
+#include "intel_gt.h"
+#include "intel_gt_requests.h"
 #include "intel_lrc.h"
 #include "intel_reset.h"
 
@@ -354,7 +354,8 @@
 		 * instances.
 		 */
 		if ((INTEL_GEN(i915) >= 11 &&
-		     RUNTIME_INFO(i915)->vdbox_sfc_access & engine->mask) ||
+		     (RUNTIME_INFO(i915)->vdbox_sfc_access &
+		      BIT(engine->instance))) ||
 		    (INTEL_GEN(i915) >= 9 && engine->instance == 0))
 			engine->uabi_capabilities |=
 				I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC;
@@ -600,6 +601,7 @@
 	intel_engine_init_hangcheck(engine);
 	intel_engine_init_cmd_parser(engine);
 	intel_engine_init__pm(engine);
+	intel_engine_init_retire(engine);
 
 	intel_engine_pool_init(&engine->pool);
 
@@ -807,6 +809,7 @@
 
 	cleanup_status_page(engine);
 
+	intel_engine_fini_retire(engine);
 	intel_engine_pool_fini(&engine->pool);
 	intel_engine_fini_breadcrumbs(engine);
 	intel_engine_cleanup_cmd_parser(engine);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_engine_pm.c
@@ -70,8 +70,43 @@
 
 #endif /* !IS_ENABLED(CONFIG_LOCKDEP) */
 
+static void
+__queue_and_release_pm(struct i915_request *rq,
+		       struct intel_timeline *tl,
+		       struct intel_engine_cs *engine)
+{
+	struct intel_gt_timelines *timelines = &engine->gt->timelines;
+	unsigned long flags;
+
+	GEM_TRACE("%s\n", engine->name);
+
+	/*
+	 * We have to serialise all potential retirement paths with our
+	 * submission, as we don't want to underflow either the
+	 * engine->wakeref.counter or our timeline->active_count.
+	 *
+	 * Equally, we cannot allow a new submission to start until
+	 * after we finish queueing, nor could we allow that submitter
+	 * to retire us before we are ready!
+	 */
+	spin_lock_irqsave(&timelines->lock, flags);
+
+	/* Let intel_gt_retire_requests() retire us (acquired under lock) */
+	if (!atomic_fetch_inc(&tl->active_count))
+		list_add_tail(&tl->link, &timelines->active_list);
+
+	/* Hand the request over to HW and so engine_retire() */
+	__i915_request_queue(rq, NULL);
+
+	/* Let new submissions commence (and maybe retire this timeline) */
+	__intel_wakeref_defer_park(&engine->wakeref);
+
+	spin_unlock_irqrestore(&timelines->lock, flags);
+}
+
 static bool switch_to_kernel_context(struct intel_engine_cs *engine)
 {
+	struct intel_context *ce = engine->kernel_context;
 	struct i915_request *rq;
 	unsigned long flags;
 	bool result = true;
@@ -96,15 +131,13 @@
 	 * retiring the last request, thus all rings should be empty and
 	 * all timelines idle.
 	 */
-	flags = __timeline_mark_lock(engine->kernel_context);
+	flags = __timeline_mark_lock(ce);
 
-	rq = __i915_request_create(engine->kernel_context, GFP_NOWAIT);
+	rq = __i915_request_create(ce, GFP_NOWAIT);
 	if (IS_ERR(rq))
 		/* Context switch failed, hope for the best! Maybe reset? */
 		goto out_unlock;
 
-	intel_timeline_enter(rq->timeline);
-
 	/* Check again on the next retirement. */
 	engine->wakeref_serial = engine->serial + 1;
 	i915_request_add_active_barriers(rq);
@@ -113,13 +146,12 @@
 	rq->sched.attr.priority = I915_PRIORITY_UNPREEMPTABLE;
 	__i915_request_commit(rq);
 
-	/* Release our exclusive hold on the engine */
-	__intel_wakeref_defer_park(&engine->wakeref);
-	__i915_request_queue(rq, NULL);
+	/* Expose ourselves to the world */
+	__queue_and_release_pm(rq, ce->timeline, engine);
 
 	result = false;
 out_unlock:
-	__timeline_mark_unlock(engine->kernel_context, flags);
+	__timeline_mark_unlock(ce, flags);
 	return result;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -107,6 +107,7 @@
 
 	u32 space;
 	u32 size;
+	u32 wrap;
 	u32 effective_size;
 };
 
@@ -300,8 +301,8 @@
 	u8 class;
 	u8 instance;
 
-	u8 uabi_class;
-	u8 uabi_instance;
+	u16 uabi_class;
+	u16 uabi_instance;
 
 	u32 context_size;
 	u32 mmio_base;
@@ -470,6 +471,14 @@
 
 	struct intel_engine_execlists execlists;
 
+	/*
+	 * Keep track of completed timelines on this engine for early
+	 * retirement with the goal of quickly enabling powersaving as
+	 * soon as the engine is idle.
+	 */
+	struct intel_timeline *retire;
+	struct work_struct retire_work;
+
 	/* status_notifier: list of callbacks for context-switch changes */
 	struct atomic_notifier_head context_status_notifier;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_gt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -15,6 +15,8 @@
 
 	spin_lock_init(&gt->irq_lock);
 
+	mutex_init(&gt->tlb_invalidate_lock);
+
 	INIT_LIST_HEAD(&gt->closed_vma);
 	spin_lock_init(&gt->closed_lock);
 
@@ -266,3 +268,117 @@
 	intel_uc_driver_late_release(&gt->uc);
 	intel_gt_fini_reset(gt);
 }
+
+struct reg_and_bit {
+	i915_reg_t reg;
+	u32 bit;
+};
+
+static struct reg_and_bit
+get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
+		const i915_reg_t *regs, const unsigned int num)
+{
+	const unsigned int class = engine->class;
+	struct reg_and_bit rb = { };
+
+	if (WARN_ON_ONCE(class >= num || !regs[class].reg))
+		return rb;
+
+	rb.reg = regs[class];
+	if (gen8 && class == VIDEO_DECODE_CLASS)
+		rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
+	else
+		rb.bit = engine->instance;
+
+	rb.bit = BIT(rb.bit);
+
+	return rb;
+}
+
+void intel_gt_invalidate_tlbs(struct intel_gt *gt)
+{
+	static const i915_reg_t gen8_regs[] = {
+		[RENDER_CLASS]			= GEN8_RTCR,
+		[VIDEO_DECODE_CLASS]		= GEN8_M1TCR, /* , GEN8_M2TCR */
+		[VIDEO_ENHANCEMENT_CLASS]	= GEN8_VTCR,
+		[COPY_ENGINE_CLASS]		= GEN8_BTCR,
+	};
+	static const i915_reg_t gen12_regs[] = {
+		[RENDER_CLASS]			= GEN12_GFX_TLB_INV_CR,
+		[VIDEO_DECODE_CLASS]		= GEN12_VD_TLB_INV_CR,
+		[VIDEO_ENHANCEMENT_CLASS]	= GEN12_VE_TLB_INV_CR,
+		[COPY_ENGINE_CLASS]		= GEN12_BLT_TLB_INV_CR,
+	};
+	struct drm_i915_private *i915 = gt->i915;
+	struct intel_uncore *uncore = gt->uncore;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+	const i915_reg_t *regs;
+	unsigned int num = 0;
+
+	if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
+		return;
+
+	if (INTEL_GEN(i915) == 12) {
+		regs = gen12_regs;
+		num = ARRAY_SIZE(gen12_regs);
+	} else if (INTEL_GEN(i915) >= 8 && INTEL_GEN(i915) <= 11) {
+		regs = gen8_regs;
+		num = ARRAY_SIZE(gen8_regs);
+	} else if (INTEL_GEN(i915) < 8) {
+		return;
+	}
+
+	if (WARN_ONCE(!num, "Platform does not implement TLB invalidation!"))
+		return;
+
+	GEM_TRACE("\n");
+
+	assert_rpm_wakelock_held(&i915->runtime_pm);
+
+	mutex_lock(&gt->tlb_invalidate_lock);
+	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
+
+	spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
+
+	for_each_engine(engine, gt, id) {
+		struct reg_and_bit rb;
+
+		rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+		if (!i915_mmio_reg_offset(rb.reg))
+			continue;
+
+		if (INTEL_GEN(i915) == 12 && (engine->class == VIDEO_DECODE_CLASS ||
+		    engine->class == VIDEO_ENHANCEMENT_CLASS))
+			rb.bit = _MASKED_BIT_ENABLE(rb.bit);
+
+		intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+	}
+
+	spin_unlock_irq(&uncore->lock);
+
+	for_each_engine(engine, gt, 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;
+		struct reg_and_bit rb;
+
+		rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+		if (!i915_mmio_reg_offset(rb.reg))
+			continue;
+
+		if (__intel_wait_for_register_fw(uncore,
+						 rb.reg, rb.bit, 0,
+						 timeout_us, timeout_ms,
+						 NULL))
+			DRM_ERROR_RATELIMITED("%s TLB invalidation did not complete in %ums!\n",
+					      engine->name, timeout_ms);
+	}
+
+	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
+	mutex_unlock(&gt->tlb_invalidate_lock);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_gt.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_gt.h
@@ -57,4 +57,6 @@
 
 void intel_gt_queue_hangcheck(struct intel_gt *gt);
 
+void intel_gt_invalidate_tlbs(struct intel_gt *gt);
+
 #endif /* __INTEL_GT_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_gt_requests.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_gt_requests.c
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include <linux/workqueue.h>
+
+#include "i915_drv.h" /* for_each_engine() */
+#include "i915_request.h"
+#include "intel_gt.h"
+#include "intel_gt_pm.h"
+#include "intel_gt_requests.h"
+#include "intel_timeline.h"
+
+static void retire_requests(struct intel_timeline *tl)
+{
+	struct i915_request *rq, *rn;
+
+	list_for_each_entry_safe(rq, rn, &tl->requests, link)
+		if (!i915_request_retire(rq))
+			break;
+}
+
+static void engine_retire(struct work_struct *work)
+{
+	struct intel_engine_cs *engine =
+		container_of(work, typeof(*engine), retire_work);
+	struct intel_timeline *tl = xchg(&engine->retire, NULL);
+
+	mutex_lock(&engine->i915->drm.struct_mutex);
+	do {
+		struct intel_timeline *next = xchg(&tl->retire, NULL);
+
+		/*
+		 * Our goal here is to retire _idle_ timelines as soon as
+		 * possible (as they are idle, we do not expect userspace
+		 * to be cleaning up anytime soon).
+		 *
+		 * If the timeline is currently locked, either it is being
+		 * retired elsewhere or about to be!
+		 */
+		if (mutex_trylock(&tl->mutex)) {
+			retire_requests(tl);
+			mutex_unlock(&tl->mutex);
+		}
+		intel_timeline_put(tl);
+
+		GEM_BUG_ON(!next);
+		tl = ptr_mask_bits(next, 1);
+	} while (tl);
+	mutex_unlock(&engine->i915->drm.struct_mutex);
+}
+
+static bool add_retire(struct intel_engine_cs *engine,
+		       struct intel_timeline *tl)
+{
+	struct intel_timeline *first;
+
+	/*
+	 * We open-code a llist here to include the additional tag [BIT(0)]
+	 * so that we know when the timeline is already on a
+	 * retirement queue: either this engine or another.
+	 *
+	 * However, we rely on that a timeline can only be active on a single
+	 * engine at any one time and that add_retire() is called before the
+	 * engine releases the timeline and transferred to another to retire.
+	 */
+
+	if (READ_ONCE(tl->retire)) /* already queued */
+		return false;
+
+	intel_timeline_get(tl);
+	first = READ_ONCE(engine->retire);
+	do
+		tl->retire = ptr_pack_bits(first, 1, 1);
+	while (!try_cmpxchg(&engine->retire, &first, tl));
+
+	return !first;
+}
+
+void intel_engine_add_retire(struct intel_engine_cs *engine,
+			     struct intel_timeline *tl)
+{
+	if (add_retire(engine, tl))
+		schedule_work(&engine->retire_work);
+}
+
+void intel_engine_init_retire(struct intel_engine_cs *engine)
+{
+	INIT_WORK(&engine->retire_work, engine_retire);
+}
+
+void intel_engine_fini_retire(struct intel_engine_cs *engine)
+{
+	flush_work(&engine->retire_work);
+	GEM_BUG_ON(engine->retire);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_gt_requests.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_gt_requests.h
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef INTEL_GT_REQUESTS_H
+#define INTEL_GT_REQUESTS_H
+
+struct intel_engine_cs;
+struct intel_timeline;
+
+void intel_engine_init_retire(struct intel_engine_cs *engine);
+void intel_engine_add_retire(struct intel_engine_cs *engine,
+			     struct intel_timeline *tl);
+void intel_engine_fini_retire(struct intel_engine_cs *engine);
+
+#endif /* INTEL_GT_REQUESTS_H */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_gt_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_gt_types.h
@@ -40,6 +40,8 @@
 
 	struct intel_uc uc;
 
+	struct mutex tlb_invalidate_lock;
+
 	struct intel_gt_timelines {
 		spinlock_t lock; /* protects active_list */
 		struct list_head active_list;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -142,6 +142,7 @@
 #include "intel_engine_pm.h"
 #include "intel_gt.h"
 #include "intel_gt_pm.h"
+#include "intel_gt_requests.h"
 #include "intel_lrc_reg.h"
 #include "intel_mocs.h"
 #include "intel_reset.h"
@@ -471,17 +472,11 @@
 	return desc;
 }
 
-static void unwind_wa_tail(struct i915_request *rq)
-{
-	rq->tail = intel_ring_wrap(rq->ring, rq->wa_tail - WA_TAIL_BYTES);
-	assert_ring_tail_valid(rq->ring, rq->tail);
-}
-
 static struct i915_request *
 __unwind_incomplete_requests(struct intel_engine_cs *engine)
 {
 	struct i915_request *rq, *rn, *active = NULL;
-	struct list_head *uninitialized_var(pl);
+	struct list_head *pl;
 	int prio = I915_PRIORITY_INVALID;
 
 	lockdep_assert_held(&engine->active.lock);
@@ -495,7 +490,6 @@
 			continue; /* XXX */
 
 		__i915_request_unsubmit(rq);
-		unwind_wa_tail(rq);
 
 		/*
 		 * Push the request back into the queue for later resubmission.
@@ -525,7 +519,8 @@
 			 */
 			if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
 				     &rq->fence.flags)) {
-				spin_lock(&rq->lock);
+				spin_lock_nested(&rq->lock,
+						 SINGLE_DEPTH_NESTING);
 				i915_request_cancel_breadcrumb(rq);
 				spin_unlock(&rq->lock);
 			}
@@ -612,6 +607,20 @@
 {
 	struct intel_context * const ce = rq->hw_context;
 
+	/*
+	 * NB process_csb() is not under the engine->active.lock and hence
+	 * schedule_out can race with schedule_in meaning that we should
+	 * refrain from doing non-trivial work here.
+	 */
+
+	/*
+	 * If we have just completed this context, the engine may now be
+	 * idle and we want to re-enter powersaving.
+	 */
+	if (list_is_last(&rq->link, &ce->timeline->requests) &&
+	    i915_request_completed(rq))
+		intel_engine_add_retire(engine, ce->timeline);
+
 	intel_engine_context_out(engine);
 	execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT);
 	intel_gt_pm_put(engine->gt);
@@ -649,13 +658,35 @@
 	i915_request_put(rq);
 }
 
-static u64 execlists_update_context(const struct i915_request *rq)
+static u64 execlists_update_context(struct i915_request *rq)
 {
 	struct intel_context *ce = rq->hw_context;
-	u64 desc;
+	u64 desc = ce->lrc_desc;
+	u32 tail, prev;
 
-	ce->lrc_reg_state[CTX_RING_TAIL + 1] =
-		intel_ring_set_tail(rq->ring, rq->tail);
+	/*
+	 * WaIdleLiteRestore:bdw,skl
+	 *
+	 * We should never submit the context with the same RING_TAIL twice
+	 * just in case we submit an empty ring, which confuses the HW.
+	 *
+	 * We append a couple of NOOPs (gen8_emit_wa_tail) after the end of
+	 * the normal request to be able to always advance the RING_TAIL on
+	 * subsequent resubmissions (for lite restore). Should that fail us,
+	 * and we try and submit the same tail again, force the context
+	 * reload.
+	 *
+	 * If we need to return to a preempted context, we need to skip the
+	 * lite-restore and force it to reload the RING_TAIL. Otherwise, the
+	 * HW has a tendency to ignore us rewinding the TAIL to the end of
+	 * an earlier request.
+	 */
+	tail = intel_ring_set_tail(rq->ring, rq->tail);
+	prev = ce->lrc_reg_state[CTX_RING_TAIL + 1];
+	if (unlikely(intel_ring_direction(rq->ring, tail, prev) <= 0))
+		desc |= CTX_DESC_FORCE_RESTORE;
+	ce->lrc_reg_state[CTX_RING_TAIL + 1] = tail;
+	rq->tail = rq->wa_tail;
 
 	/*
 	 * Make sure the context image is complete before we submit it to HW.
@@ -674,7 +705,6 @@
 	 */
 	mb();
 
-	desc = ce->lrc_desc;
 	ce->lrc_desc &= ~CTX_DESC_FORCE_RESTORE;
 
 	return desc;
@@ -918,6 +948,11 @@
 	return *last;
 }
 
+#define for_each_waiter(p__, rq__) \
+	list_for_each_entry_lockless(p__, \
+				     &(rq__)->sched.waiters_list, \
+				     wait_link)
+
 static void defer_request(struct i915_request *rq, struct list_head * const pl)
 {
 	LIST_HEAD(list);
@@ -935,7 +970,7 @@
 		GEM_BUG_ON(i915_request_is_active(rq));
 		list_move_tail(&rq->sched.link, pl);
 
-		list_for_each_entry(p, &rq->sched.waiters_list, wait_link) {
+		for_each_waiter(p, rq) {
 			struct i915_request *w =
 				container_of(p->waiter, typeof(*w), sched);
 
@@ -1101,14 +1136,6 @@
 			 */
 			__unwind_incomplete_requests(engine);
 
-			/*
-			 * If we need to return to the preempted context, we
-			 * need to skip the lite-restore and force it to
-			 * reload the RING_TAIL. Otherwise, the HW has a
-			 * tendency to ignore us rewinding the TAIL to the
-			 * end of an earlier request.
-			 */
-			last->hw_context->lrc_desc |= CTX_DESC_FORCE_RESTORE;
 			last = NULL;
 		} else if (need_timeslice(engine, last) &&
 			   !timer_pending(&engine->execlists.timer)) {
@@ -1149,16 +1176,6 @@
 			if (!list_is_last(&last->sched.link,
 					  &engine->active.requests))
 				return;
-
-			/*
-			 * WaIdleLiteRestore:bdw,skl
-			 * Apply the wa NOOPs to prevent
-			 * ring:HEAD == rq:TAIL as we resubmit the
-			 * request. See gen8_emit_fini_breadcrumb() for
-			 * where we prepare the padding after the
-			 * end of the request.
-			 */
-			last->tail = last->wa_tail;
 		}
 	}
 
@@ -1572,6 +1589,9 @@
 			if (!inject_preempt_hang(execlists))
 				ring_set_paused(engine, 0);
 
+			/* XXX Magic delay for tgl */
+			ENGINE_POSTING_READ(engine, RING_CONTEXT_STATUS_PTR);
+
 			WRITE_ONCE(execlists->pending[0], NULL);
 			break;
 
@@ -2131,6 +2151,14 @@
 	/* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt,glk */
 	batch = gen8_emit_flush_coherentl3_wa(engine, batch);
 
+	/* WaClearSlmSpaceAtContextSwitch:skl,bxt,kbl,glk,cfl */
+	batch = gen8_emit_pipe_control(batch,
+				       PIPE_CONTROL_FLUSH_L3 |
+				       PIPE_CONTROL_GLOBAL_GTT_IVB |
+				       PIPE_CONTROL_CS_STALL |
+				       PIPE_CONTROL_QW_WRITE,
+				       slm_offset(engine));
+
 	batch = emit_lri(batch, lri, ARRAY_SIZE(lri));
 
 	/* WaMediaPoolStateCmdInWABB:bxt,glk */
@@ -2232,6 +2260,9 @@
 static void lrc_destroy_wa_ctx(struct intel_engine_cs *engine)
 {
 	i915_vma_unpin_and_release(&engine->wa_ctx.vma, 0);
+
+	/* Called on error unwind, clear all flags to prevent further use */
+	memset(&engine->wa_ctx, 0, sizeof(engine->wa_ctx));
 }
 
 typedef u32 *(*wa_bb_func_t)(struct intel_engine_cs *engine, u32 *batch);
@@ -3715,9 +3746,11 @@
 	ve->base.i915 = ctx->i915;
 	ve->base.gt = siblings[0]->gt;
 	ve->base.id = -1;
+
 	ve->base.class = OTHER_CLASS;
 	ve->base.uabi_class = I915_ENGINE_CLASS_INVALID;
 	ve->base.instance = I915_ENGINE_CLASS_INVALID_VIRTUAL;
+	ve->base.uabi_instance = I915_ENGINE_CLASS_INVALID_VIRTUAL;
 
 	/*
 	 * The decision on whether to submit a request using semaphores
@@ -3739,6 +3772,7 @@
 	intel_engine_init_active(&ve->base, ENGINE_VIRTUAL);
 
 	intel_engine_init_execlists(&ve->base);
+	ve->base.breadcrumbs.irq_armed = true; /* fake HW, used for irq_work */
 
 	ve->base.cops = &virtual_context_ops;
 	ve->base.request_alloc = execlists_request_alloc;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_mocs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_mocs.c
@@ -130,7 +130,19 @@
 	GEN9_MOCS_ENTRIES,
 	MOCS_ENTRY(I915_MOCS_CACHED,
 		   LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3),
-		   L3_3_WB)
+		   L3_3_WB),
+
+	/*
+	 * mocs:63
+	 * - used by the L3 for all of its evictions.
+	 *   Thus it is expected to allow LLC cacheability to enable coherent
+	 *   flows to be maintained.
+	 * - used to force L3 uncachable cycles.
+	 *   Thus it is expected to make the surface L3 uncacheable.
+	 */
+	MOCS_ENTRY(63,
+		   LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
+		   L3_1_UC)
 };
 
 /* NOTE: the LE_TGT_CACHE is not used on Broxton */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_reset.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -257,6 +257,7 @@
 static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
 {
 	struct intel_uncore *uncore = gt->uncore;
+	int loops = 2;
 	int err;
 
 	/*
@@ -264,17 +265,38 @@
 	 * for fifo space for the write or forcewake the chip for
 	 * the read
 	 */
-	intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
+	do {
+		intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
 
-	/* Wait for the device to ack the reset requests */
-	err = __intel_wait_for_register_fw(uncore,
-					   GEN6_GDRST, hw_domain_mask, 0,
-					   500, 0,
-					   NULL);
+		/*
+		 * Wait for the device to ack the reset requests.
+		 *
+		 * On some platforms, e.g. Jasperlake, we see that the
+		 * engine register state is not cleared until shortly after
+		 * GDRST reports completion, causing a failure as we try
+		 * to immediately resume while the internal state is still
+		 * in flux. If we immediately repeat the reset, the second
+		 * reset appears to serialise with the first, and since
+		 * it is a no-op, the registers should retain their reset
+		 * value. However, there is still a concern that upon
+		 * leaving the second reset, the internal engine state
+		 * is still in flux and not ready for resuming.
+		 */
+		err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
+						   hw_domain_mask, 0,
+						   2000, 0,
+						   NULL);
+	} while (err == 0 && --loops);
 	if (err)
 		DRM_DEBUG_DRIVER("Wait for 0x%08x engines reset failed\n",
 				 hw_domain_mask);
 
+	/*
+	 * As we have observed that the engine state is still volatile
+	 * after GDRST is acked, impose a small delay to let everything settle.
+	 */
+	udelay(50);
+
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_ringbuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_ringbuffer.c
@@ -1208,7 +1208,7 @@
 	if (unlikely(ret))
 		goto err_unpin;
 
-	if (i915_vma_is_map_and_fenceable(vma))
+	if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915))
 		addr = (void __force *)i915_vma_pin_iomap(vma);
 	else
 		addr = i915_gem_object_pin_map(vma->obj,
@@ -1220,9 +1220,10 @@
 
 	i915_vma_make_unshrinkable(vma);
 
-	GEM_BUG_ON(ring->vaddr);
-	ring->vaddr = addr;
+	/* Discard any unused bytes beyond that submitted to hw. */
+	intel_ring_reset(ring, ring->emit);
 
+	ring->vaddr = addr;
 	return 0;
 
 err_ring:
@@ -1248,30 +1249,25 @@
 	if (!atomic_dec_and_test(&ring->pin_count))
 		return;
 
-	/* Discard any unused bytes beyond that submitted to hw. */
-	intel_ring_reset(ring, ring->emit);
-
 	i915_vma_unset_ggtt_write(vma);
-	if (i915_vma_is_map_and_fenceable(vma))
+	if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915))
 		i915_vma_unpin_iomap(vma);
 	else
 		i915_gem_object_unpin_map(vma->obj);
 
-	GEM_BUG_ON(!ring->vaddr);
-	ring->vaddr = NULL;
-
-	i915_vma_unpin(vma);
 	i915_vma_make_purgeable(vma);
+	i915_vma_unpin(vma);
 }
 
 static struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size)
 {
 	struct i915_address_space *vm = &ggtt->vm;
 	struct drm_i915_private *i915 = vm->i915;
-	struct drm_i915_gem_object *obj;
+	struct drm_i915_gem_object *obj = NULL;
 	struct i915_vma *vma;
 
-	obj = i915_gem_object_create_stolen(i915, size);
+	if (!HAS_LLC(i915))
+		obj = i915_gem_object_create_stolen(i915, size);
 	if (!obj)
 		obj = i915_gem_object_create_internal(i915, size);
 	if (IS_ERR(obj))
@@ -1310,8 +1306,9 @@
 		return ERR_PTR(-ENOMEM);
 
 	kref_init(&ring->ref);
-
 	ring->size = size;
+	ring->wrap = BITS_PER_TYPE(ring->size) - ilog2(size);
+
 	/* Workaround an erratum on the i830 which causes a hang if
 	 * the TAIL pointer points to within the last 2 cachelines
 	 * of the buffer.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_timeline.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_timeline.c
@@ -282,6 +282,7 @@
 {
 	GEM_BUG_ON(atomic_read(&timeline->pin_count));
 	GEM_BUG_ON(!list_empty(&timeline->requests));
+	GEM_BUG_ON(timeline->retire);
 
 	if (timeline->hwsp_cacheline)
 		cacheline_free(timeline->hwsp_cacheline);
@@ -289,6 +290,14 @@
 		i915_gem_object_unpin_map(timeline->hwsp_ggtt->obj);
 
 	i915_vma_put(timeline->hwsp_ggtt);
+
+	/*
+	 * A small race exists between intel_gt_retire_requests_timeout and
+	 * intel_timeline_exit which could result in the syncmap not getting
+	 * free'd. Rather than work to hard to seal this race, simply cleanup
+	 * the syncmap on fini.
+	 */
+	i915_syncmap_free(&timeline->sync);
 }
 
 struct intel_timeline *
@@ -339,15 +348,33 @@
 	struct intel_gt_timelines *timelines = &tl->gt->timelines;
 	unsigned long flags;
 
+	/*
+	 * Pretend we are serialised by the timeline->mutex.
+	 *
+	 * While generally true, there are a few exceptions to the rule
+	 * for the engine->kernel_context being used to manage power
+	 * transitions. As the engine_park may be called from under any
+	 * timeline, it uses the power mutex as a global serialisation
+	 * lock to prevent any other request entering its timeline.
+	 *
+	 * The rule is generally tl->mutex, otherwise engine->wakeref.mutex.
+	 *
+	 * However, intel_gt_retire_request() does not know which engine
+	 * it is retiring along and so cannot partake in the engine-pm
+	 * barrier, and there we use the tl->active_count as a means to
+	 * pin the timeline in the active_list while the locks are dropped.
+	 * Ergo, as that is outside of the engine-pm barrier, we need to
+	 * use atomic to manipulate tl->active_count.
+	 */
 	lockdep_assert_held(&tl->mutex);
-
 	GEM_BUG_ON(!atomic_read(&tl->pin_count));
-	if (tl->active_count++)
+
+	if (atomic_add_unless(&tl->active_count, 1, 0))
 		return;
-	GEM_BUG_ON(!tl->active_count); /* overflow? */
 
 	spin_lock_irqsave(&timelines->lock, flags);
-	list_add(&tl->link, &timelines->active_list);
+	if (!atomic_fetch_inc(&tl->active_count))
+		list_add_tail(&tl->link, &timelines->active_list);
 	spin_unlock_irqrestore(&timelines->lock, flags);
 }
 
@@ -356,14 +383,16 @@
 	struct intel_gt_timelines *timelines = &tl->gt->timelines;
 	unsigned long flags;
 
+	/* See intel_timeline_enter() */
 	lockdep_assert_held(&tl->mutex);
 
-	GEM_BUG_ON(!tl->active_count);
-	if (--tl->active_count)
+	GEM_BUG_ON(!atomic_read(&tl->active_count));
+	if (atomic_add_unless(&tl->active_count, -1, 1))
 		return;
 
 	spin_lock_irqsave(&timelines->lock, flags);
-	list_del(&tl->link);
+	if (atomic_dec_and_test(&tl->active_count))
+		list_del(&tl->link);
 	spin_unlock_irqrestore(&timelines->lock, flags);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gt/intel_timeline_types.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gt/intel_timeline_types.h
@@ -42,7 +42,7 @@
 	 * from the intel_context caller plus internal atomicity.
 	 */
 	atomic_t pin_count;
-	unsigned int active_count;
+	atomic_t active_count;
 
 	const u32 *hwsp_seqno;
 	struct i915_vma *hwsp_ggtt;
@@ -65,6 +65,9 @@
 	 */
 	struct i915_active_request last_request;
 
+	/** A chain of completed timelines ready for early retirement. */
+	struct intel_timeline *retire;
+
 	/**
 	 * We track the most recent seqno that we wait on in every context so
 	 * that we only have to emit a new await and dependency on a more
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/cmd_parser.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/cmd_parser.c
@@ -963,18 +963,6 @@
 	int i, ret = 0;
 	int cmd_len = cmd_length(s);
 	struct intel_gvt *gvt = s->vgpu->gvt;
-	u32 valid_len = CMD_LEN(1);
-
-	/*
-	 * Official intel docs are somewhat sloppy , check the definition of
-	 * MI_LOAD_REGISTER_IMM.
-	 */
-	#define MAX_VALID_LEN 127
-	if ((cmd_len < valid_len) || (cmd_len > MAX_VALID_LEN)) {
-		gvt_err("len is not valid:  len=%u  valid_len=%u\n",
-			cmd_len, valid_len);
-		return -EFAULT;
-	}
 
 	for (i = 1; i < cmd_len; i += 2) {
 		if (IS_BROADWELL(gvt->dev_priv) && s->ring_id != RCS0) {
@@ -1597,9 +1585,9 @@
 	if (!(cmd_val(s, 0) & (1 << 22)))
 		return ret;
 
-	/* check if QWORD */
-	if (DWORD_FIELD(0, 20, 19) == 1)
-		valid_len += 8;
+	/* check inline data */
+	if (cmd_val(s, 0) & BIT(18))
+		valid_len = CMD_LEN(9);
 	ret = gvt_check_valid_cmd_length(cmd_length(s),
 			valid_len);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/display.c
@@ -172,21 +172,176 @@
 	int pipe;
 
 	if (IS_BROXTON(dev_priv)) {
+		enum transcoder trans;
+		enum port port;
+
+		/* Clear PIPE, DDI, PHY, HPD before setting new */
 		vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= ~(BXT_DE_PORT_HP_DDIA |
 			BXT_DE_PORT_HP_DDIB |
 			BXT_DE_PORT_HP_DDIC);
 
+		for_each_pipe(dev_priv, pipe) {
+			vgpu_vreg_t(vgpu, PIPECONF(pipe)) &=
+				~(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE);
+			vgpu_vreg_t(vgpu, DSPCNTR(pipe)) &= ~DISPLAY_PLANE_ENABLE;
+			vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE;
+			vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~MCURSOR_MODE;
+			vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= MCURSOR_MODE_DISABLE;
+		}
+
+		for (trans = TRANSCODER_A; trans <= TRANSCODER_EDP; trans++) {
+			vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(trans)) &=
+				~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+				  TRANS_DDI_PORT_MASK | TRANS_DDI_FUNC_ENABLE);
+		}
+		vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
+			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+			  TRANS_DDI_PORT_MASK);
+
+		for (port = PORT_A; port <= PORT_C; port++) {
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) &=
+				~BXT_PHY_LANE_ENABLED;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) |=
+				(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+				 BXT_PHY_LANE_POWERDOWN_ACK);
+
+			vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port)) &=
+				~(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+				  PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+				  PORT_PLL_ENABLE);
+
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) &=
+				~(DDI_INIT_DISPLAY_DETECTED |
+				  DDI_BUF_CTL_ENABLE);
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) |= DDI_BUF_IS_IDLE;
+		}
+		vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+			~(PORTA_HOTPLUG_ENABLE | PORTA_HOTPLUG_STATUS_MASK);
+		vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+			~(PORTB_HOTPLUG_ENABLE | PORTB_HOTPLUG_STATUS_MASK);
+		vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+			~(PORTC_HOTPLUG_ENABLE | PORTC_HOTPLUG_STATUS_MASK);
+		/* No hpd_invert set in vgpu vbt, need to clear invert mask */
+		vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &= ~BXT_DDI_HPD_INVERT_MASK;
+		vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= ~BXT_DE_PORT_HOTPLUG_MASK;
+
+		vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= ~(BIT(0) | BIT(1));
+		vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &=
+			~PHY_POWER_GOOD;
+		vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &=
+			~PHY_POWER_GOOD;
+		vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= ~BIT(30);
+		vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= ~BIT(30);
+
+		vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIB_DETECTED;
+		vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIC_DETECTED;
+
+		/*
+		 * Only 1 PIPE enabled in current vGPU display and PIPE_A is
+		 *  tied to TRANSCODER_A in HW, so it's safe to assume PIPE_A,
+		 *   TRANSCODER_A can be enabled. PORT_x depends on the input of
+		 *   setup_virtual_dp_monitor.
+		 */
+		vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;
+		vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= I965_PIPECONF_ACTIVE;
+
+		/*
+		 * Golden M/N are calculated based on:
+		 *   24 bpp, 4 lanes, 154000 pixel clk (from virtual EDID),
+		 *   DP link clk 1620 MHz and non-constant_n.
+		 * TODO: calculate DP link symbol clk and stream clk m/n.
+		 */
+		vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) = 63 << TU_SIZE_SHIFT;
+		vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) |= 0x5b425e;
+		vgpu_vreg_t(vgpu, PIPE_DATA_N1(TRANSCODER_A)) = 0x800000;
+		vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)) = 0x3cd6e;
+		vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)) = 0x80000;
+
+		/* Enable per-DDI/PORT vreg */
 		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+			vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(1);
+			vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) |=
+				PHY_POWER_GOOD;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) |=
+				BIT(30);
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |=
+				BXT_PHY_LANE_ENABLED;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &=
+				~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+				  BXT_PHY_LANE_POWERDOWN_ACK);
+			vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_A)) |=
+				(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+				 PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+				 PORT_PLL_ENABLE);
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) |=
+				(DDI_BUF_CTL_ENABLE | DDI_INIT_DISPLAY_DETECTED);
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) &=
+				~DDI_BUF_IS_IDLE;
+			vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)) |=
+				(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+				 TRANS_DDI_FUNC_ENABLE);
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTA_HOTPLUG_ENABLE;
 			vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
 				BXT_DE_PORT_HP_DDIA;
 		}
 
 		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+			vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED;
+			vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+			vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+				PHY_POWER_GOOD;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+				BIT(30);
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |=
+				BXT_PHY_LANE_ENABLED;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &=
+				~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+				  BXT_PHY_LANE_POWERDOWN_ACK);
+			vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_B)) |=
+				(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+				 PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+				 PORT_PLL_ENABLE);
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) |=
+				DDI_BUF_CTL_ENABLE;
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) &=
+				~DDI_BUF_IS_IDLE;
+			vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+				(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+				 (PORT_B << TRANS_DDI_PORT_SHIFT) |
+				 TRANS_DDI_FUNC_ENABLE);
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTB_HOTPLUG_ENABLE;
 			vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
 				BXT_DE_PORT_HP_DDIB;
 		}
 
 		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+			vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED;
+			vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+			vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+				PHY_POWER_GOOD;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+				BIT(30);
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
+				BXT_PHY_LANE_ENABLED;
+			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &=
+				~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+				  BXT_PHY_LANE_POWERDOWN_ACK);
+			vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_C)) |=
+				(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+				 PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+				 PORT_PLL_ENABLE);
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) |=
+				DDI_BUF_CTL_ENABLE;
+			vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) &=
+				~DDI_BUF_IS_IDLE;
+			vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+				(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+				 (PORT_B << TRANS_DDI_PORT_SHIFT) |
+				 TRANS_DDI_FUNC_ENABLE);
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTC_HOTPLUG_ENABLE;
 			vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
 				BXT_DE_PORT_HP_DDIC;
 		}
@@ -207,14 +362,41 @@
 				SKL_FUSE_PG_DIST_STATUS(SKL_PG0) |
 				SKL_FUSE_PG_DIST_STATUS(SKL_PG1) |
 				SKL_FUSE_PG_DIST_STATUS(SKL_PG2);
-		vgpu_vreg_t(vgpu, LCPLL1_CTL) |=
-				LCPLL_PLL_ENABLE |
-				LCPLL_PLL_LOCK;
-		vgpu_vreg_t(vgpu, LCPLL2_CTL) |= LCPLL_PLL_ENABLE;
-
+		/*
+		 * Only 1 PIPE enabled in current vGPU display and PIPE_A is
+		 *  tied to TRANSCODER_A in HW, so it's safe to assume PIPE_A,
+		 *   TRANSCODER_A can be enabled. PORT_x depends on the input of
+		 *   setup_virtual_dp_monitor, we can bind DPLL0 to any PORT_x
+		 *   so we fixed to DPLL0 here.
+		 * Setup DPLL0: DP link clk 1620 MHz, non SSC, DP Mode
+		 */
+		vgpu_vreg_t(vgpu, DPLL_CTRL1) =
+			DPLL_CTRL1_OVERRIDE(DPLL_ID_SKL_DPLL0);
+		vgpu_vreg_t(vgpu, DPLL_CTRL1) |=
+			DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, DPLL_ID_SKL_DPLL0);
+		vgpu_vreg_t(vgpu, LCPLL1_CTL) =
+			LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK;
+		vgpu_vreg_t(vgpu, DPLL_STATUS) = DPLL_LOCK(DPLL_ID_SKL_DPLL0);
+		/*
+		 * Golden M/N are calculated based on:
+		 *   24 bpp, 4 lanes, 154000 pixel clk (from virtual EDID),
+		 *   DP link clk 1620 MHz and non-constant_n.
+		 * TODO: calculate DP link symbol clk and stream clk m/n.
+		 */
+		vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) = 63 << TU_SIZE_SHIFT;
+		vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) |= 0x5b425e;
+		vgpu_vreg_t(vgpu, PIPE_DATA_N1(TRANSCODER_A)) = 0x800000;
+		vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)) = 0x3cd6e;
+		vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)) = 0x80000;
 	}
 
 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) &=
+			~DPLL_CTRL2_DDI_CLK_OFF(PORT_B);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_CLK_SEL(DPLL_ID_SKL_DPLL0, PORT_B);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_SEL_OVERRIDE(PORT_B);
 		vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED;
 		vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
@@ -235,6 +417,12 @@
 	}
 
 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) &=
+			~DPLL_CTRL2_DDI_CLK_OFF(PORT_C);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_CLK_SEL(DPLL_ID_SKL_DPLL0, PORT_C);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_SEL_OVERRIDE(PORT_C);
 		vgpu_vreg_t(vgpu, SDEISR) |= SDE_PORTC_HOTPLUG_CPT;
 		vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
@@ -255,6 +443,12 @@
 	}
 
 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_D)) {
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) &=
+			~DPLL_CTRL2_DDI_CLK_OFF(PORT_D);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_CLK_SEL(DPLL_ID_SKL_DPLL0, PORT_D);
+		vgpu_vreg_t(vgpu, DPLL_CTRL2) |=
+			DPLL_CTRL2_DDI_SEL_OVERRIDE(PORT_D);
 		vgpu_vreg_t(vgpu, SDEISR) |= SDE_PORTD_HOTPLUG_CPT;
 		vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
@@ -457,7 +651,8 @@
 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
 
 	/* TODO: add more platforms support */
-	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ||
+		IS_COFFEELAKE(dev_priv)) {
 		if (connected) {
 			vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
 				SFUSE_STRAP_DDID_DETECTED;
@@ -471,6 +666,63 @@
 		vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
 				PORTD_HOTPLUG_STATUS_MASK;
 		intel_vgpu_trigger_virtual_event(vgpu, DP_D_HOTPLUG);
+	} else if (IS_BROXTON(dev_priv)) {
+		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+			if (connected) {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+					BXT_DE_PORT_HP_DDIA;
+			} else {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+					~BXT_DE_PORT_HP_DDIA;
+			}
+			vgpu_vreg_t(vgpu, GEN8_DE_PORT_IIR) |=
+				BXT_DE_PORT_HP_DDIA;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+				~PORTA_HOTPLUG_STATUS_MASK;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTA_HOTPLUG_LONG_DETECT;
+			intel_vgpu_trigger_virtual_event(vgpu, DP_A_HOTPLUG);
+		}
+		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+			if (connected) {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+					BXT_DE_PORT_HP_DDIB;
+				vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+					SFUSE_STRAP_DDIB_DETECTED;
+			} else {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+					~BXT_DE_PORT_HP_DDIB;
+				vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+					~SFUSE_STRAP_DDIB_DETECTED;
+			}
+			vgpu_vreg_t(vgpu, GEN8_DE_PORT_IIR) |=
+				BXT_DE_PORT_HP_DDIB;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+				~PORTB_HOTPLUG_STATUS_MASK;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTB_HOTPLUG_LONG_DETECT;
+			intel_vgpu_trigger_virtual_event(vgpu, DP_B_HOTPLUG);
+		}
+		if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+			if (connected) {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+					BXT_DE_PORT_HP_DDIC;
+				vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+					SFUSE_STRAP_DDIC_DETECTED;
+			} else {
+				vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+					~BXT_DE_PORT_HP_DDIC;
+				vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+					~SFUSE_STRAP_DDIC_DETECTED;
+			}
+			vgpu_vreg_t(vgpu, GEN8_DE_PORT_IIR) |=
+				BXT_DE_PORT_HP_DDIC;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) &=
+				~PORTC_HOTPLUG_STATUS_MASK;
+			vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+				PORTC_HOTPLUG_LONG_DETECT;
+			intel_vgpu_trigger_virtual_event(vgpu, DP_C_HOTPLUG);
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/dmabuf.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/dmabuf.c
@@ -96,12 +96,12 @@
 			dmabuf_obj = container_of(pos,
 					struct intel_vgpu_dmabuf_obj, list);
 			if (dmabuf_obj == obj) {
+				list_del(pos);
 				intel_gvt_hypervisor_put_vfio_device(vgpu);
 				idr_remove(&vgpu->object_idr,
 					   dmabuf_obj->dmabuf_id);
 				kfree(dmabuf_obj->info);
 				kfree(dmabuf_obj);
-				list_del(pos);
 				break;
 			}
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/gtt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/gtt.c
@@ -1186,10 +1186,8 @@
 	for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
 		ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
 				start_gfn + sub_index, PAGE_SIZE, &dma_addr);
-		if (ret) {
-			ppgtt_invalidate_spt(spt);
-			return ret;
-		}
+		if (ret)
+			goto err;
 		sub_se.val64 = se->val64;
 
 		/* Copy the PAT field from PDE. */
@@ -1208,6 +1206,17 @@
 	ops->set_pfn(se, sub_spt->shadow_page.mfn);
 	ppgtt_set_shadow_entry(spt, se, index);
 	return 0;
+err:
+	/* Cancel the existing addess mappings of DMA addr. */
+	for_each_present_shadow_entry(sub_spt, &sub_se, sub_index) {
+		gvt_vdbg_mm("invalidate 4K entry\n");
+		ppgtt_invalidate_pte(sub_spt, &sub_se);
+	}
+	/* Release the new allocated spt. */
+	trace_spt_change(sub_spt->vgpu->id, "release", sub_spt,
+		sub_spt->guest_page.gfn, sub_spt->shadow_page.type);
+	ppgtt_free_spt(sub_spt);
+	return ret;
 }
 
 static int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
@@ -1956,7 +1965,11 @@
 
 	if (mm->type == INTEL_GVT_MM_PPGTT) {
 		list_del(&mm->ppgtt_mm.list);
+
+		mutex_lock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
 		list_del(&mm->ppgtt_mm.lru_list);
+		mutex_unlock(&mm->vgpu->gvt->gtt.ppgtt_mm_lock);
+
 		invalidate_ppgtt_mm(mm);
 	} else {
 		vfree(mm->ggtt_mm.virtual_ggtt);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/gvt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/gvt.c
@@ -128,7 +128,7 @@
 	return true;
 }
 
-static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
+static int intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
 {
 	int i, j;
 	struct intel_vgpu_type *type;
@@ -146,7 +146,7 @@
 		gvt_vgpu_type_groups[i] = group;
 	}
 
-	return true;
+	return 0;
 
 unwind:
 	for (j = 0; j < i; j++) {
@@ -154,7 +154,7 @@
 		kfree(group);
 	}
 
-	return false;
+	return -ENOMEM;
 }
 
 static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
@@ -362,7 +362,7 @@
 		goto out_clean_thread;
 
 	ret = intel_gvt_init_vgpu_type_groups(gvt);
-	if (ret == false) {
+	if (ret) {
 		gvt_err("failed to init vgpu type groups: %d\n", ret);
 		goto out_clean_types;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/handlers.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/handlers.c
@@ -654,7 +654,7 @@
 	else if (FDI_RX_IMR_TO_PIPE(offset) != INVALID_INDEX)
 		index = FDI_RX_IMR_TO_PIPE(offset);
 	else {
-		gvt_vgpu_err("Unsupport registers %x\n", offset);
+		gvt_vgpu_err("Unsupported registers %x\n", offset);
 		return -EINVAL;
 	}
 
@@ -1632,6 +1632,34 @@
 	return 0;
 }
 
+/**
+ * FixMe:
+ * If guest fills non-priv batch buffer on ApolloLake/Broxton as Mesa i965 did:
+ * 717e7539124d (i965: Use a WC map and memcpy for the batch instead of pwrite.)
+ * Due to the missing flush of bb filled by VM vCPU, host GPU hangs on executing
+ * these MI_BATCH_BUFFER.
+ * Temporarily workaround this by setting SNOOP bit for PAT3 used by PPGTT
+ * PML4 PTE: PAT(0) PCD(1) PWT(1).
+ * The performance is still expected to be low, will need further improvement.
+ */
+static int bxt_ppat_low_write(struct intel_vgpu *vgpu, unsigned int offset,
+			      void *p_data, unsigned int bytes)
+{
+	u64 pat =
+		GEN8_PPAT(0, CHV_PPAT_SNOOP) |
+		GEN8_PPAT(1, 0) |
+		GEN8_PPAT(2, 0) |
+		GEN8_PPAT(3, CHV_PPAT_SNOOP) |
+		GEN8_PPAT(4, CHV_PPAT_SNOOP) |
+		GEN8_PPAT(5, CHV_PPAT_SNOOP) |
+		GEN8_PPAT(6, CHV_PPAT_SNOOP) |
+		GEN8_PPAT(7, CHV_PPAT_SNOOP);
+
+	vgpu_vreg(vgpu, offset) = lower_32_bits(pat);
+
+	return 0;
+}
+
 static int mmio_read_from_hw(struct intel_vgpu *vgpu,
 		unsigned int offset, void *p_data, unsigned int bytes)
 {
@@ -2778,7 +2806,7 @@
 
 	MMIO_DH(GEN6_PCODE_MAILBOX, D_BDW_PLUS, NULL, mailbox_write);
 
-	MMIO_D(GEN8_PRIVATE_PAT_LO, D_BDW_PLUS);
+	MMIO_D(GEN8_PRIVATE_PAT_LO, D_BDW_PLUS & ~D_BXT);
 	MMIO_D(GEN8_PRIVATE_PAT_HI, D_BDW_PLUS);
 
 	MMIO_D(GAMTARBMODE, D_BDW_PLUS);
@@ -3103,8 +3131,8 @@
 	MMIO_DFH(GEN9_WM_CHICKEN3, D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS,
 		 NULL, NULL);
 
-	MMIO_D(GAMT_CHKN_BIT_REG, D_KBL);
-	MMIO_D(GEN9_CTX_PREEMPT_REG, D_KBL | D_SKL);
+	MMIO_D(GAMT_CHKN_BIT_REG, D_KBL | D_CFL);
+	MMIO_D(GEN9_CTX_PREEMPT_REG, D_SKL_PLUS & ~D_BXT);
 
 	return 0;
 }
@@ -3278,9 +3306,17 @@
 	MMIO_D(GEN8_PUSHBUS_SHIFT, D_BXT);
 	MMIO_D(GEN6_GFXPAUSE, D_BXT);
 	MMIO_DFH(GEN8_L3SQCREG1, D_BXT, F_CMD_ACCESS, NULL, NULL);
+	MMIO_DFH(GEN8_L3CNTLREG, D_BXT, F_CMD_ACCESS, NULL, NULL);
+	MMIO_DFH(_MMIO(0x20D8), D_BXT, F_CMD_ACCESS, NULL, NULL);
+	MMIO_F(HSW_CS_GPR(0), 0x40, F_CMD_ACCESS, 0, 0, D_BXT, NULL, NULL);
+	MMIO_F(_MMIO(0x12600), 0x40, F_CMD_ACCESS, 0, 0, D_BXT, NULL, NULL);
+	MMIO_F(BCS_GPR(0), 0x40, F_CMD_ACCESS, 0, 0, D_BXT, NULL, NULL);
+	MMIO_F(_MMIO(0x1a600), 0x40, F_CMD_ACCESS, 0, 0, D_BXT, NULL, NULL);
 
 	MMIO_DFH(GEN9_CTX_PREEMPT_REG, D_BXT, F_CMD_ACCESS, NULL, NULL);
 
+	MMIO_DH(GEN8_PRIVATE_PAT_LO, D_BXT, NULL, bxt_ppat_low_write);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/mmio.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/mmio.c
@@ -271,6 +271,11 @@
 			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
 				    BXT_PHY_CMNLANE_POWERDOWN_ACK |
 				    BXT_PHY_LANE_POWERDOWN_ACK;
+			vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |=
+				SKL_FUSE_DOWNLOAD_STATUS |
+				SKL_FUSE_PG_DIST_STATUS(SKL_PG0) |
+				SKL_FUSE_PG_DIST_STATUS(SKL_PG1) |
+				SKL_FUSE_PG_DIST_STATUS(SKL_PG2);
 		}
 	} else {
 #define GVT_GEN8_MMIO_RESET_OFFSET		(0x44200)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/scheduler.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -374,7 +374,11 @@
 		for (i = 0; i < GVT_RING_CTX_NR_PDPS; i++) {
 			struct i915_page_directory * const pd =
 				i915_pd_entry(ppgtt->pd, i);
-
+			/* skip now as current i915 ppgtt alloc won't allocate
+			   top level pdp for non 4-level table, won't impact
+			   shadow ppgtt. */
+			if (!pd)
+				break;
 			px_dma(pd) = mm->ppgtt_mm.shadow_pdps[i];
 		}
 	}
@@ -628,6 +632,7 @@
 
 	if (workload->shadow_mm->type != INTEL_GVT_MM_PPGTT ||
 	    !workload->shadow_mm->ppgtt_mm.shadowed) {
+		intel_vgpu_unpin_mm(workload->shadow_mm);
 		gvt_vgpu_err("workload shadow ppgtt isn't ready\n");
 		return -EINVAL;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/gvt/vgpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -272,10 +272,17 @@
 {
 	struct intel_gvt *gvt = vgpu->gvt;
 
-	mutex_lock(&vgpu->vgpu_lock);
-
 	WARN(vgpu->active, "vGPU is still active!\n");
 
+	/*
+	 * remove idr first so later clean can judge if need to stop
+	 * service if no active vgpu.
+	 */
+	mutex_lock(&gvt->lock);
+	idr_remove(&gvt->vgpu_idr, vgpu->id);
+	mutex_unlock(&gvt->lock);
+
+	mutex_lock(&vgpu->vgpu_lock);
 	intel_gvt_debugfs_remove_vgpu(vgpu);
 	intel_vgpu_clean_sched_policy(vgpu);
 	intel_vgpu_clean_submission(vgpu);
@@ -290,7 +297,6 @@
 	mutex_unlock(&vgpu->vgpu_lock);
 
 	mutex_lock(&gvt->lock);
-	idr_remove(&gvt->vgpu_idr, vgpu->id);
 	if (idr_is_empty(&gvt->vgpu_idr))
 		intel_gvt_clean_irq(gvt);
 	intel_gvt_update_vgpu_types(gvt);
@@ -426,8 +432,9 @@
 	if (ret)
 		goto out_clean_sched_policy;
 
-	/*TODO: add more platforms support */
-	if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv))
+	if (IS_BROADWELL(gvt->dev_priv) || IS_BROXTON(gvt->dev_priv))
+		ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_B);
+	else
 		ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D);
 	if (ret)
 		goto out_clean_sched_policy;
@@ -560,9 +567,9 @@
 
 		intel_vgpu_reset_mmio(vgpu, dmlr);
 		populate_pvinfo_page(vgpu);
-		intel_vgpu_reset_display(vgpu);
 
 		if (dmlr) {
+			intel_vgpu_reset_display(vgpu);
 			intel_vgpu_reset_cfg_space(vgpu);
 			/* only reset the failsafe mode when dmlr reset */
 			vgpu->failsafe = false;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_active.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_active.c
@@ -121,7 +121,7 @@
 #endif
 
 static void
-__active_retire(struct i915_active *ref)
+__active_retire(struct i915_active *ref, bool lock)
 {
 	struct active_node *it, *n;
 	struct rb_root root;
@@ -138,7 +138,8 @@
 		retire = true;
 	}
 
-	mutex_unlock(&ref->mutex);
+	if (likely(lock))
+		mutex_unlock(&ref->mutex);
 	if (!retire)
 		return;
 
@@ -153,21 +154,28 @@
 }
 
 static void
-active_retire(struct i915_active *ref)
+active_retire(struct i915_active *ref, bool lock)
 {
 	GEM_BUG_ON(!atomic_read(&ref->count));
 	if (atomic_add_unless(&ref->count, -1, 1))
 		return;
 
 	/* One active may be flushed from inside the acquire of another */
-	mutex_lock_nested(&ref->mutex, SINGLE_DEPTH_NESTING);
-	__active_retire(ref);
+	if (likely(lock))
+		mutex_lock_nested(&ref->mutex, SINGLE_DEPTH_NESTING);
+	__active_retire(ref, lock);
 }
 
 static void
 node_retire(struct i915_active_request *base, struct i915_request *rq)
 {
-	active_retire(node_from_active(base)->ref);
+	active_retire(node_from_active(base)->ref, true);
+}
+
+static void
+node_retire_nolock(struct i915_active_request *base, struct i915_request *rq)
+{
+	active_retire(node_from_active(base)->ref, false);
 }
 
 static struct i915_active_request *
@@ -364,7 +372,7 @@
 void i915_active_release(struct i915_active *ref)
 {
 	debug_active_assert(ref);
-	active_retire(ref);
+	active_retire(ref, true);
 }
 
 static void __active_ungrab(struct i915_active *ref)
@@ -391,7 +399,7 @@
 {
 	GEM_BUG_ON(!test_bit(I915_ACTIVE_GRAB_BIT, &ref->flags));
 
-	active_retire(ref);
+	active_retire(ref, true);
 	__active_ungrab(ref);
 }
 
@@ -421,12 +429,13 @@
 			break;
 		}
 
-		err = i915_active_request_retire(&it->base, BKL(ref));
+		err = i915_active_request_retire(&it->base, BKL(ref),
+						 node_retire_nolock);
 		if (err)
 			break;
 	}
 
-	__active_retire(ref);
+	__active_retire(ref, true);
 	if (err)
 		return err;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_active.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_active.h
@@ -309,7 +309,7 @@
  */
 static inline int __must_check
 i915_active_request_retire(struct i915_active_request *active,
-			   struct mutex *mutex)
+			   struct mutex *mutex, i915_active_retire_fn retire)
 {
 	struct i915_request *request;
 	long ret;
@@ -327,7 +327,7 @@
 	list_del_init(&active->link);
 	RCU_INIT_POINTER(active->request, NULL);
 
-	active->retire(active, request);
+	retire(active, request);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -572,6 +572,9 @@
 #define REG32(_reg, ...) \
 	{ .addr = (_reg), __VA_ARGS__ }
 
+#define REG32_IDX(_reg, idx) \
+	{ .addr = _reg(idx) }
+
 /*
  * Convenience macro for adding 64-bit registers.
  *
@@ -669,6 +672,7 @@
 	REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE),
 	REG32(BCS_SWCTRL),
 	REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
+	REG32_IDX(RING_CTX_TIMESTAMP, BLT_RING_BASE),
 	REG64_IDX(BCS_GPR, 0),
 	REG64_IDX(BCS_GPR, 1),
 	REG64_IDX(BCS_GPR, 2),
@@ -1203,6 +1207,12 @@
 	return dst;
 }
 
+static inline bool cmd_desc_is(const struct drm_i915_cmd_descriptor * const desc,
+			       const u32 cmd)
+{
+	return desc->cmd.value == (cmd & desc->cmd.mask);
+}
+
 static bool check_cmd(const struct intel_engine_cs *engine,
 		      const struct drm_i915_cmd_descriptor *desc,
 		      const u32 *cmd, u32 length)
@@ -1241,19 +1251,19 @@
 			 * allowed mask/value pair given in the whitelist entry.
 			 */
 			if (reg->mask) {
-				if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
+				if (cmd_desc_is(desc, MI_LOAD_REGISTER_MEM)) {
 					DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n",
 							 reg_addr);
 					return false;
 				}
 
-				if (desc->cmd.value == MI_LOAD_REGISTER_REG) {
+				if (cmd_desc_is(desc, MI_LOAD_REGISTER_REG)) {
 					DRM_DEBUG_DRIVER("CMD: Rejected LRR to masked register 0x%08X\n",
 							 reg_addr);
 					return false;
 				}
 
-				if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) &&
+				if (cmd_desc_is(desc, MI_LOAD_REGISTER_IMM(1)) &&
 				    (offset + 2 > length ||
 				     (cmd[offset + 1] & reg->mask) != reg->value)) {
 					DRM_DEBUG_DRIVER("CMD: Rejected LRI to masked register 0x%08X\n",
@@ -1484,7 +1494,7 @@
 			goto err;
 		}
 
-		if (desc->cmd.value == MI_BATCH_BUFFER_START) {
+		if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) {
 			ret = check_bbstart(ctx, cmd, offset, length,
 					    batch_len, batch_start,
 					    shadow_batch_start);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2360,8 +2360,7 @@
 
 		for_each_power_domain(power_domain, power_well->desc->domains)
 			seq_printf(m, "  %-23s %d\n",
-				 intel_display_power_domain_str(dev_priv,
-								power_domain),
+				 intel_display_power_domain_str(power_domain),
 				 power_domains->domain_use_count[power_domain]);
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_drv.h
@@ -33,6 +33,8 @@
 #include <uapi/drm/i915_drm.h>
 #include <uapi/drm/drm_fourcc.h>
 
+#include <asm/hypervisor.h>
+
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -1740,6 +1742,9 @@
 
 	bool ipc_enabled;
 
+	/* Hack to bypass TMDS_OE write on DP->HDMI dongle */
+	bool bypass_tmds_oe;
+
 	/* Used to save the pipe-to-encoder mapping for audio */
 	struct intel_encoder *av_enc_map[I915_MAX_PIPES];
 
@@ -1892,7 +1897,7 @@
 {
 	const unsigned int pi = __platform_mask_index(info, p);
 
-	return info->platform_mask[pi] & INTEL_SUBPLATFORM_BITS;
+	return info->platform_mask[pi] & ((1 << INTEL_SUBPLATFORM_BITS) - 1);
 }
 
 static __always_inline bool
@@ -2197,7 +2202,9 @@
 	if (intel_iommu_gfx_mapped)
 		return true;
 #endif
-	return false;
+
+	/* Running as a guest, we assume the host is enforcing VT'd */
+	return !hypervisor_is_type(X86_HYPER_NATIVE);
 }
 
 static inline bool intel_scanout_needs_vtd_wa(struct drm_i915_private *dev_priv)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_gem.c
@@ -136,14 +136,14 @@
 		     struct drm_i915_gem_pwrite *args,
 		     struct drm_file *file)
 {
-	void *vaddr = obj->phys_handle->vaddr + args->offset;
+	void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset;
 	char __user *user_data = u64_to_user_ptr(args->data_ptr);
 
 	/*
 	 * We manually control the domain here and pretend that it
 	 * remains coherent i.e. in the GTT domain, like shmem_pwrite.
 	 */
-	intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
 	if (copy_from_user(vaddr, user_data, args->size))
 		return -EFAULT;
@@ -151,7 +151,7 @@
 	drm_clflush_virt_range(vaddr, args->size);
 	intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt);
 
-	intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 	return 0;
 }
 
@@ -588,7 +588,7 @@
 		goto out_unpin;
 	}
 
-	intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
 	user_data = u64_to_user_ptr(args->data_ptr);
 	offset = args->offset;
@@ -630,7 +630,7 @@
 		user_data += page_length;
 		offset += page_length;
 	}
-	intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 
 	i915_gem_object_unlock_fence(obj, fence);
 out_unpin:
@@ -723,7 +723,7 @@
 		offset = 0;
 	}
 
-	intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+	i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 	i915_gem_object_unlock_fence(obj, fence);
 
 	return ret;
@@ -802,10 +802,10 @@
 		ret = i915_gem_gtt_pwrite_fast(obj, args);
 
 	if (ret == -EFAULT || ret == -ENOSPC) {
-		if (obj->phys_handle)
-			ret = i915_gem_phys_pwrite(obj, args, file);
-		else
+		if (i915_gem_object_has_struct_page(obj))
 			ret = i915_gem_shmem_pwrite(obj, args);
+		else
+			ret = i915_gem_phys_pwrite(obj, args, file);
 	}
 
 	i915_gem_object_unpin_pages(obj);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -1178,6 +1178,7 @@
 	pd = i915_pd_entry(pdp, gen8_pd_index(idx, 2));
 	vaddr = kmap_atomic_px(i915_pt_entry(pd, gen8_pd_index(idx, 1)));
 	do {
+		GEM_BUG_ON(iter->sg->length < I915_GTT_PAGE_SIZE);
 		vaddr[gen8_pd_index(idx, 0)] = pte_encode | iter->dma;
 
 		iter->dma += I915_GTT_PAGE_SIZE;
@@ -1657,6 +1658,7 @@
 
 	vaddr = kmap_atomic_px(i915_pt_entry(pd, act_pt));
 	do {
+		GEM_BUG_ON(iter.sg->length < I915_GTT_PAGE_SIZE);
 		vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
 
 		iter.dma += I915_GTT_PAGE_SIZE;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_gpu_error.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -307,6 +307,8 @@
 
 		if (zlib_deflate(zstream, Z_NO_FLUSH) != Z_OK)
 			return -EIO;
+
+		cond_resched();
 	} while (zstream->avail_in);
 
 	/* Fallback to uncompressed if we increase size? */
@@ -392,6 +394,7 @@
 	if (!i915_memcpy_from_wc(ptr, src, PAGE_SIZE))
 		memcpy(ptr, src, PAGE_SIZE);
 	dst->pages[dst->page_count++] = ptr;
+	cond_resched();
 
 	return 0;
 }
@@ -1768,7 +1771,8 @@
 	if (!xchg(&warned, true) &&
 	    ktime_get_real_seconds() - DRIVER_TIMESTAMP < DAY_AS_SECONDS(180)) {
 		pr_info("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n");
-		pr_info("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n");
+		pr_info("Please file a _new_ bug report at https://gitlab.freedesktop.org/drm/intel/issues/new.\n");
+		pr_info("Please see https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs for details.\n");
 		pr_info("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n");
 		pr_info("The GPU crash dump is required to analyze GPU hangs, so please always attach it.\n");
 		pr_info("GPU crash dump saved to /sys/class/drm/card%d/error\n",
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_irq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_irq.c
@@ -3500,6 +3500,7 @@
 
 	val = I915_READ(GEN11_DE_HPD_IMR);
 	val &= ~hotplug_irqs;
+	val |= ~enabled_irqs & hotplug_irqs;
 	I915_WRITE(GEN11_DE_HPD_IMR, val);
 	POSTING_READ(GEN11_DE_HPD_IMR);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_params.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_params.c
@@ -84,8 +84,7 @@
 
 i915_param_named_unsafe(enable_psr, int, 0600,
 	"Enable PSR "
-	"(0=disabled, 1=enabled) "
-	"Default: -1 (use per-chip default)");
+	"(-1=use per-chip default, 0=disabled [default], 1=enabled) ");
 
 i915_param_named_unsafe(force_probe, charp, 0400,
 	"Force probe the driver for specified devices. "
@@ -171,7 +170,7 @@
 
 i915_param_named(enable_dpcd_backlight, int, 0600,
 	"Enable support for DPCD backlight control"
-	"(-1=use per-VBT LFP backlight type setting, 0=disabled [default], 1=enabled)");
+	"(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enabled)");
 
 #if IS_ENABLED(CONFIG_DRM_I915_GVT)
 i915_param_named(enable_gvt, bool, 0400,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_params.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_params.h
@@ -50,7 +50,7 @@
 	param(int, vbt_sdvo_panel_type, -1) \
 	param(int, enable_dc, -1) \
 	param(int, enable_fbc, -1) \
-	param(int, enable_psr, -1) \
+	param(int, enable_psr, 0) \
 	param(int, disable_power_well, -1) \
 	param(int, enable_ips, 1) \
 	param(int, invert_brightness, 0) \
@@ -64,7 +64,7 @@
 	param(int, reset, 2) \
 	param(unsigned int, inject_load_failure, 0) \
 	param(int, fastboot, -1) \
-	param(int, enable_dpcd_backlight, 0) \
+	param(int, enable_dpcd_backlight, -1) \
 	param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE) \
 	/* leave bools at the end to not create holes */ \
 	param(bool, alpha_support, IS_ENABLED(CONFIG_DRM_I915_ALPHA_SUPPORT)) \
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_pci.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_pci.c
@@ -418,7 +418,8 @@
 	.has_coherent_ggtt = true, \
 	.has_llc = 1, \
 	.has_rc6 = 1, \
-	.has_rc6p = 1, \
+	/* snb does support rc6p, but enabling it causes various issues */ \
+	.has_rc6p = 0, \
 	.has_rps = true, \
 	.ppgtt_type = INTEL_PPGTT_FULL, \
 	.ppgtt_size = 31, \
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_perf.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_perf.c
@@ -2313,49 +2313,6 @@
 }
 
 /**
- * i915_perf_read_locked - &i915_perf_stream_ops->read with error normalisation
- * @stream: An i915 perf stream
- * @file: An i915 perf stream file
- * @buf: destination buffer given by userspace
- * @count: the number of bytes userspace wants to read
- * @ppos: (inout) file seek position (unused)
- *
- * Besides wrapping &i915_perf_stream_ops->read this provides a common place to
- * ensure that if we've successfully copied any data then reporting that takes
- * precedence over any internal error status, so the data isn't lost.
- *
- * For example ret will be -ENOSPC whenever there is more buffered data than
- * can be copied to userspace, but that's only interesting if we weren't able
- * to copy some data because it implies the userspace buffer is too small to
- * receive a single record (and we never split records).
- *
- * Another case with ret == -EFAULT is more of a grey area since it would seem
- * like bad form for userspace to ask us to overrun its buffer, but the user
- * knows best:
- *
- *   http://yarchive.net/comp/linux/partial_reads_writes.html
- *
- * Returns: The number of bytes copied or a negative error code on failure.
- */
-static ssize_t i915_perf_read_locked(struct i915_perf_stream *stream,
-				     struct file *file,
-				     char __user *buf,
-				     size_t count,
-				     loff_t *ppos)
-{
-	/* Note we keep the offset (aka bytes read) separate from any
-	 * error status so that the final check for whether we return
-	 * the bytes read with a higher precedence than any error (see
-	 * comment below) doesn't need to be handled/duplicated in
-	 * stream->ops->read() implementations.
-	 */
-	size_t offset = 0;
-	int ret = stream->ops->read(stream, buf, count, &offset);
-
-	return offset ?: (ret ?: -EAGAIN);
-}
-
-/**
  * i915_perf_read - handles read() FOP for i915 perf stream FDs
  * @file: An i915 perf stream file
  * @buf: destination buffer given by userspace
@@ -2380,7 +2337,8 @@
 {
 	struct i915_perf_stream *stream = file->private_data;
 	struct drm_i915_private *dev_priv = stream->dev_priv;
-	ssize_t ret;
+	size_t offset = 0;
+	int ret;
 
 	/* To ensure it's handled consistently we simply treat all reads of a
 	 * disabled stream as an error. In particular it might otherwise lead
@@ -2403,13 +2361,12 @@
 				return ret;
 
 			mutex_lock(&dev_priv->perf.lock);
-			ret = i915_perf_read_locked(stream, file,
-						    buf, count, ppos);
+			ret = stream->ops->read(stream, buf, count, &offset);
 			mutex_unlock(&dev_priv->perf.lock);
-		} while (ret == -EAGAIN);
+		} while (!offset && !ret);
 	} else {
 		mutex_lock(&dev_priv->perf.lock);
-		ret = i915_perf_read_locked(stream, file, buf, count, ppos);
+		ret = stream->ops->read(stream, buf, count, &offset);
 		mutex_unlock(&dev_priv->perf.lock);
 	}
 
@@ -2420,15 +2377,15 @@
 	 * and read() returning -EAGAIN. Clearing the oa.pollin state here
 	 * effectively ensures we back off until the next hrtimer callback
 	 * before reporting another EPOLLIN event.
+	 * The exception to this is if ops->read() returned -ENOSPC which means
+	 * that more OA data is available than could fit in the user provided
+	 * buffer. In this case we want the next poll() call to not block.
 	 */
-	if (ret >= 0 || ret == -EAGAIN) {
-		/* Maybe make ->pollin per-stream state if we support multiple
-		 * concurrent streams in the future.
-		 */
+	if (ret != -ENOSPC)
 		stream->pollin = false;
-	}
 
-	return ret;
+	/* Possible values for ret are 0, -EFAULT, -ENOSPC, -EIO, ... */
+	return offset ?: (ret ?: -EAGAIN);
 }
 
 static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_reg.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_reg.h
@@ -2519,6 +2519,12 @@
 #define   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING	(1 << 28)
 #define   GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT	(1 << 24)
 
+#define GEN8_RTCR	_MMIO(0x4260)
+#define GEN8_M1TCR	_MMIO(0x4264)
+#define GEN8_M2TCR	_MMIO(0x4268)
+#define GEN8_BTCR	_MMIO(0x426c)
+#define GEN8_VTCR	_MMIO(0x4270)
+
 #if 0
 #define PRB0_TAIL	_MMIO(0x2030)
 #define PRB0_HEAD	_MMIO(0x2034)
@@ -2602,6 +2608,11 @@
 #define   FAULT_VA_HIGH_BITS		(0xf << 0)
 #define   FAULT_GTT_SEL			(1 << 4)
 
+#define GEN12_GFX_TLB_INV_CR	_MMIO(0xced8)
+#define GEN12_VD_TLB_INV_CR	_MMIO(0xcedc)
+#define GEN12_VE_TLB_INV_CR	_MMIO(0xcee0)
+#define GEN12_BLT_TLB_INV_CR	_MMIO(0xcee4)
+
 #define FPGA_DBG		_MMIO(0x42300)
 #define   FPGA_DBG_RM_NOCLAIM	(1 << 31)
 
@@ -4049,7 +4060,13 @@
 #define  GWUNIT_CLKGATE_DIS		(1 << 16)
 
 #define UNSLICE_UNIT_LEVEL_CLKGATE	_MMIO(0x9434)
-#define  VFUNIT_CLKGATE_DIS		(1 << 20)
+#define   VFUNIT_CLKGATE_DIS		REG_BIT(20)
+#define   HSUNIT_CLKGATE_DIS		REG_BIT(8)
+#define   VSUNIT_CLKGATE_DIS		REG_BIT(3)
+
+#define UNSLICE_UNIT_LEVEL_CLKGATE2	_MMIO(0x94e4)
+#define   VSUNIT_CLKGATE_DIS_TGL	REG_BIT(19)
+#define   PSDUNIT_CLKGATE_DIS		REG_BIT(5)
 
 #define INF_UNIT_LEVEL_CLKGATE		_MMIO(0x9560)
 #define   CGPSF_CLKGATE_DIS		(1 << 3)
@@ -8832,8 +8849,13 @@
 #define     ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point)	(((point) << 16) | (0x1 << 8))
 #define   GEN6_PCODE_READ_D_COMP		0x10
 #define   GEN6_PCODE_WRITE_D_COMP		0x11
+#define   ICL_PCODE_EXIT_TCCOLD			0x12
 #define   HSW_PCODE_DE_WRITE_FREQ_REQ		0x17
 #define   DISPLAY_IPS_CONTROL			0x19
+#define   TGL_PCODE_TCCOLD			0x26
+#define     TGL_PCODE_EXIT_TCCOLD_DATA_L_EXIT_FAILED	REG_BIT(0)
+#define     TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ	0
+#define     TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ	REG_BIT(0)
             /* See also IPS_CTL */
 #define     IPS_PCODE_CONTROL			(1 << 30)
 #define   HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL	0x1A
@@ -9104,6 +9126,9 @@
 #define HSW_AUD_CHICKENBIT			_MMIO(0x65f10)
 #define   SKL_AUD_CODEC_WAKE_SIGNAL		(1 << 15)
 
+#define AUD_PIN_BUF_CTL		_MMIO(0x48414)
+#define   AUD_PIN_BUF_ENABLE		REG_BIT(31)
+
 /*
  * HSW - ICL power wells
  *
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_request.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_request.c
@@ -215,7 +215,7 @@
 	spin_unlock(&locked->active.lock);
 }
 
-static bool i915_request_retire(struct i915_request *rq)
+bool i915_request_retire(struct i915_request *rq)
 {
 	struct i915_active_request *active, *next;
 
@@ -560,19 +560,31 @@
 	return NOTIFY_DONE;
 }
 
+static void irq_semaphore_cb(struct irq_work *wrk)
+{
+	struct i915_request *rq =
+		container_of(wrk, typeof(*rq), semaphore_work);
+
+	i915_schedule_bump_priority(rq, I915_PRIORITY_NOSEMAPHORE);
+	i915_request_put(rq);
+}
+
 static int __i915_sw_fence_call
 semaphore_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 {
-	struct i915_request *request =
-		container_of(fence, typeof(*request), semaphore);
+	struct i915_request *rq = container_of(fence, typeof(*rq), semaphore);
 
 	switch (state) {
 	case FENCE_COMPLETE:
-		i915_schedule_bump_priority(request, I915_PRIORITY_NOSEMAPHORE);
+		if (!(READ_ONCE(rq->sched.attr.priority) & I915_PRIORITY_NOSEMAPHORE)) {
+			i915_request_get(rq);
+			init_irq_work(&rq->semaphore_work, irq_semaphore_cb);
+			irq_work_queue(&rq->semaphore_work);
+		}
 		break;
 
 	case FENCE_FREE:
-		i915_request_put(request);
+		i915_request_put(rq);
 		break;
 	}
 
@@ -882,8 +894,10 @@
 	GEM_BUG_ON(to == from);
 	GEM_BUG_ON(to->timeline == from->timeline);
 
-	if (i915_request_completed(from))
+	if (i915_request_completed(from)) {
+		i915_sw_fence_set_error_once(&to->submit, from->fence.error);
 		return 0;
+	}
 
 	if (to->engine->schedule) {
 		ret = i915_sched_node_add_dependency(&to->sched, &from->sched);
@@ -1215,9 +1229,9 @@
 	 * decide whether to preempt the entire chain so that it is ready to
 	 * run at the earliest possible convenience.
 	 */
-	i915_sw_fence_commit(&rq->semaphore);
 	if (attr && rq->engine->schedule)
 		rq->engine->schedule(rq, attr);
+	i915_sw_fence_commit(&rq->semaphore);
 	i915_sw_fence_commit(&rq->submit);
 }
 
@@ -1513,8 +1527,8 @@
 			continue;
 
 		intel_timeline_get(tl);
-		GEM_BUG_ON(!tl->active_count);
-		tl->active_count++; /* pin the list element */
+		GEM_BUG_ON(!atomic_read(&tl->active_count));
+		atomic_inc(&tl->active_count); /* pin the list element */
 		spin_unlock_irqrestore(&timelines->lock, flags);
 
 		retire_requests(tl);
@@ -1523,14 +1537,14 @@
 
 		/* Resume iteration after dropping lock */
 		list_safe_reset_next(tl, tn, link);
-		if (!--tl->active_count)
+		if (atomic_dec_and_test(&tl->active_count))
 			list_del(&tl->link);
 
 		mutex_unlock(&tl->mutex);
 
 		/* Defer the final release to after the spinlock */
 		if (refcount_dec_and_test(&tl->kref.refcount)) {
-			GEM_BUG_ON(tl->active_count);
+			GEM_BUG_ON(atomic_read(&tl->active_count));
 			list_add(&tl->link, &free);
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_request.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_request.h
@@ -26,6 +26,7 @@
 #define I915_REQUEST_H
 
 #include <linux/dma-fence.h>
+#include <linux/irq_work.h>
 #include <linux/lockdep.h>
 
 #include "gt/intel_context_types.h"
@@ -147,6 +148,7 @@
 	};
 	struct list_head execute_cb;
 	struct i915_sw_fence semaphore;
+	struct irq_work semaphore_work;
 
 	/*
 	 * A list of everyone we wait upon, and everyone who waits upon us.
@@ -251,6 +253,7 @@
 void __i915_request_queue(struct i915_request *rq,
 			  const struct i915_sched_attr *attr);
 
+bool i915_request_retire(struct i915_request *rq);
 void i915_request_retire_upto(struct i915_request *rq);
 
 static inline struct i915_request *
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_scheduler.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_scheduler.c
@@ -418,8 +418,6 @@
 
 	if (!node_signaled(signal)) {
 		INIT_LIST_HEAD(&dep->dfs_link);
-		list_add(&dep->wait_link, &signal->waiters_list);
-		list_add(&dep->signal_link, &node->signalers_list);
 		dep->signaler = signal;
 		dep->waiter = node;
 		dep->flags = flags;
@@ -429,6 +427,10 @@
 		    !node_started(signal))
 			node->flags |= I915_SCHED_HAS_SEMAPHORE_CHAIN;
 
+		/* All set, now publish. Beware the lockless walkers. */
+		list_add(&dep->signal_link, &node->signalers_list);
+		list_add_rcu(&dep->wait_link, &signal->waiters_list);
+
 		/*
 		 * As we do not allow WAIT to preempt inflight requests,
 		 * once we have executed a request, along with triggering
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_sw_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -158,9 +158,13 @@
 
 		do {
 			list_for_each_entry_safe(pos, next, &x->head, entry) {
-				pos->func(pos,
-					  TASK_NORMAL, fence->error,
-					  &extra);
+				int wake_flags;
+
+				wake_flags = fence->error;
+				if (pos->func == autoremove_wake_function)
+					wake_flags = 0;
+
+				pos->func(pos, TASK_NORMAL, wake_flags, &extra);
 			}
 
 			if (list_empty(&extra))
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_utils.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_utils.c
@@ -8,9 +8,8 @@
 #include "i915_drv.h"
 #include "i915_utils.h"
 
-#define FDO_BUG_URL "https://bugs.freedesktop.org/enter_bug.cgi?product=DRI"
-#define FDO_BUG_MSG "Please file a bug at " FDO_BUG_URL " against DRM/Intel " \
-		    "providing the dmesg log by booting with drm.debug=0xf"
+#define FDO_BUG_URL "https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs"
+#define FDO_BUG_MSG "Please file a bug on drm/i915; see " FDO_BUG_URL " for details."
 
 void
 __i915_printk(struct drm_i915_private *dev_priv, const char *level,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_utils.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_utils.h
@@ -233,6 +233,11 @@
 	__idx;								\
 })
 
+static inline bool is_power_of_2_u64(u64 n)
+{
+	return (n != 0 && ((n & (n - 1)) == 0));
+}
+
 static inline void __list_del_many(struct list_head *head,
 				   struct list_head *first)
 {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/i915_vma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/i915_vma.c
@@ -341,6 +341,10 @@
 		return ret;
 
 	vma->flags |= bind_flags;
+
+	if (vma->obj)
+		set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
+
 	return 0;
 }
 
@@ -907,10 +911,16 @@
 		return err;
 
 	if (flags & EXEC_OBJECT_WRITE) {
-		if (intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CS))
-			i915_active_ref(&obj->frontbuffer->write,
-					rq->timeline,
-					rq);
+		struct intel_frontbuffer *front;
+
+		front = __intel_frontbuffer_get(obj);
+		if (unlikely(front)) {
+			if (intel_frontbuffer_invalidate(front, ORIGIN_CS))
+				i915_active_ref(&front->write,
+						rq->timeline,
+						rq);
+			intel_frontbuffer_put(front);
+		}
 
 		dma_resv_add_excl_fence(vma->resv, &rq->fence);
 		obj->write_domain = I915_GEM_DOMAIN_RENDER;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/intel_pch.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/intel_pch.c
@@ -74,6 +74,11 @@
 		WARN_ON(!IS_COFFEELAKE(dev_priv));
 		/* CometPoint is CNP Compatible */
 		return PCH_CNP;
+	case INTEL_PCH_CMP_V_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Comet Lake V PCH (CMP-V)\n");
+		WARN_ON(!IS_COFFEELAKE(dev_priv));
+		/* Comet Lake V PCH is based on KBP, which is SPT compatible */
+		return PCH_SPT;
 	case INTEL_PCH_ICP_DEVICE_ID_TYPE:
 		DRM_DEBUG_KMS("Found Ice Lake PCH\n");
 		WARN_ON(!IS_ICELAKE(dev_priv));
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/intel_pch.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/intel_pch.h
@@ -42,6 +42,7 @@
 #define INTEL_PCH_CNP_LP_DEVICE_ID_TYPE		0x9D80
 #define INTEL_PCH_CMP_DEVICE_ID_TYPE		0x0280
 #define INTEL_PCH_CMP2_DEVICE_ID_TYPE		0x0680
+#define INTEL_PCH_CMP_V_DEVICE_ID_TYPE		0xA380
 #define INTEL_PCH_ICP_DEVICE_ID_TYPE		0x3480
 #define INTEL_PCH_MCC_DEVICE_ID_TYPE		0x4B00
 #define INTEL_PCH_MCC2_DEVICE_ID_TYPE		0x3880
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/intel_pm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/intel_pm.c
@@ -2822,7 +2822,7 @@
 }
 
 static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
-				  u16 wm[8])
+				  u16 wm[])
 {
 	struct intel_uncore *uncore = &dev_priv->uncore;
 
@@ -2966,7 +2966,7 @@
 
 static void intel_print_wm_latency(struct drm_i915_private *dev_priv,
 				   const char *name,
-				   const u16 wm[8])
+				   const u16 wm[])
 {
 	int level, max_level = ilk_wm_max_level(dev_priv);
 
@@ -3017,9 +3017,9 @@
 	 * The BIOS provided WM memory latency values are often
 	 * inadequate for high resolution displays. Adjust them.
 	 */
-	changed = ilk_increase_wm_latency(dev_priv, dev_priv->wm.pri_latency, 12) |
-		ilk_increase_wm_latency(dev_priv, dev_priv->wm.spr_latency, 12) |
-		ilk_increase_wm_latency(dev_priv, dev_priv->wm.cur_latency, 12);
+	changed = ilk_increase_wm_latency(dev_priv, dev_priv->wm.pri_latency, 12);
+	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->wm.spr_latency, 12);
+	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->wm.cur_latency, 12);
 
 	if (!changed)
 		return;
@@ -4784,7 +4784,7 @@
 	 * WaIncreaseLatencyIPCEnabled: kbl,cfl
 	 * Display WA #1141: kbl,cfl
 	 */
-	if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) ||
+	if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) &&
 	    dev_priv->ipc_enabled)
 		latency += 4;
 
@@ -9194,6 +9194,17 @@
 	/* WaEnable32PlaneMode:icl */
 	I915_WRITE(GEN9_CSFE_CHICKEN1_RCS,
 		   _MASKED_BIT_ENABLE(GEN11_ENABLE_32_PLANE_MODE));
+
+	/*
+	 * Wa_1408615072:icl,ehl  (vsunit)
+	 * Wa_1407596294:icl,ehl  (hsunit)
+	 */
+	intel_uncore_rmw(&dev_priv->uncore, UNSLICE_UNIT_LEVEL_CLKGATE,
+			 0, VSUNIT_CLKGATE_DIS | HSUNIT_CLKGATE_DIS);
+
+	/* Wa_1407352427:icl,ehl */
+	intel_uncore_rmw(&dev_priv->uncore, UNSLICE_UNIT_LEVEL_CLKGATE2,
+			 0, PSDUNIT_CLKGATE_DIS);
 }
 
 static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/intel_uncore.c
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/intel_uncore.c
@@ -1124,6 +1124,18 @@
 		spin_unlock(&uncore->debug->lock);
 }
 
+#define __vgpu_read(x) \
+static u##x \
+vgpu_read##x(struct intel_uncore *uncore, i915_reg_t reg, bool trace) { \
+	u##x val = __raw_uncore_read##x(uncore, reg); \
+	trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+	return val; \
+}
+__vgpu_read(8)
+__vgpu_read(16)
+__vgpu_read(32)
+__vgpu_read(64)
+
 #define GEN2_READ_HEADER(x) \
 	u##x val = 0; \
 	assert_rpm_wakelock_held(uncore->rpm);
@@ -1327,6 +1339,16 @@
 #undef GEN6_WRITE_FOOTER
 #undef GEN6_WRITE_HEADER
 
+#define __vgpu_write(x) \
+static void \
+vgpu_write##x(struct intel_uncore *uncore, i915_reg_t reg, u##x val, bool trace) { \
+	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+	__raw_uncore_write##x(uncore, reg, val); \
+}
+__vgpu_write(8)
+__vgpu_write(16)
+__vgpu_write(32)
+
 #define ASSIGN_RAW_WRITE_MMIO_VFUNCS(uncore, x) \
 do { \
 	(uncore)->funcs.mmio_writeb = x##_write8; \
@@ -1647,7 +1669,10 @@
 {
 	GEM_BUG_ON(intel_uncore_has_forcewake(uncore));
 
-	if (IS_GEN(uncore->i915, 5)) {
+	if (intel_vgpu_active(uncore->i915)) {
+		ASSIGN_RAW_WRITE_MMIO_VFUNCS(uncore, vgpu);
+		ASSIGN_RAW_READ_MMIO_VFUNCS(uncore, vgpu);
+	} else if (IS_GEN(uncore->i915, 5)) {
 		ASSIGN_RAW_WRITE_MMIO_VFUNCS(uncore, gen5);
 		ASSIGN_RAW_READ_MMIO_VFUNCS(uncore, gen5);
 	} else {
@@ -1901,13 +1926,14 @@
 				 unsigned int slow_timeout_ms,
 				 u32 *out_value)
 {
-	u32 uninitialized_var(reg_value);
+	u32 reg_value = 0;
 #define done (((reg_value = intel_uncore_read_fw(uncore, reg)) & mask) == value)
 	int ret;
 
 	/* Catch any overuse of this function */
 	might_sleep_if(slow_timeout_ms);
 	GEM_BUG_ON(fast_timeout_us > 20000);
+	GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms);
 
 	ret = -ETIMEDOUT;
 	if (fast_timeout_us && fast_timeout_us <= 20000)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/i915/selftests/i915_random.h
+++ linux-ein-5.4.0/drivers/gpu/drm/i915/selftests/i915_random.h
@@ -25,6 +25,7 @@
 #ifndef __I915_SELFTESTS_RANDOM_H__
 #define __I915_SELFTESTS_RANDOM_H__
 
+#include <linux/math64.h>
 #include <linux/random.h>
 
 #include "../i915_selftest.h"
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/Kconfig
@@ -6,10 +6,15 @@
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_CMA_HELPER
 	depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
-	depends on IMX_IPUV3_CORE
+	depends on IMX_IPUV3_CORE || IMX_DPU_CORE || IMX_LCDIF_CORE
 	help
 	  enable i.MX graphics support
 
+config DRM_IMX_LCDIF_MUX_DISPLAY
+	tristate "Support for LCDIF mux displays"
+	select DRM_PANEL_BRIDGE
+	depends on DRM_IMX && OF && MFD_SYSCON
+
 config DRM_IMX_PARALLEL_DISPLAY
 	tristate "Support for parallel displays"
 	select DRM_PANEL
@@ -26,16 +31,68 @@
 	  found on i.MX53 processors.
 
 config DRM_IMX_LDB
-	tristate "Support for LVDS displays"
-	depends on DRM_IMX && MFD_SYSCON
-	select DRM_PANEL
+	tristate "Support for i.MX6 LVDS displays"
+	depends on DRM_IMX && DRM_FSL_IMX_LVDS_BRIDGE
 	help
 	  Choose this to enable the internal LVDS Display Bridge (LDB)
 	  found on i.MX53 and i.MX6 processors.
 
+config DRM_IMX8QM_LDB
+	tristate "Support for i.MX8qm LVDS displays"
+	depends on DRM_IMX && DRM_FSL_IMX_LVDS_BRIDGE
+	depends on PHY_MIXEL_LVDS
+	help
+	  Choose this to enable the internal LVDS Display Bridge (LDB)
+	  found on i.MX8qm processors.
+
+config DRM_IMX8QXP_LDB
+	tristate "Support for i.MX8qxp LVDS displays"
+	depends on DRM_IMX && DRM_FSL_IMX_LVDS_BRIDGE
+	depends on PHY_MIXEL_LVDS_COMBO
+	help
+	  Choose this to enable the internal LVDS Display Bridge (LDB)
+	  found on i.MX8qxp processors.
+
+config DRM_IMX8MP_LDB
+	tristate "Support for i.MX8mp LVDS displays"
+	depends on DRM_IMX && DRM_FSL_IMX_LVDS_BRIDGE
+	depends on PHY_FSL_IMX8MP_LVDS
+	help
+	  Choose this to enable the internal LVDS Display Bridge (LDB)
+	  found on i.MX8mp processors.
+
+config DRM_IMX_IPUV3
+	tristate
+	depends on DRM_IMX
+	depends on IMX_IPUV3_CORE
+	default y if DRM_IMX=y
+	default m if DRM_IMX=m
+
+config IMX8MP_HDMI_PAVI
+	tristate "NXP i.MX8MP HDMI Audio Video (PVI/PAI)"
+	help
+	  Choose this if you want to use HDMI PAI/PVI on i.MX8MP.
+
 config DRM_IMX_HDMI
 	tristate "Freescale i.MX DRM HDMI"
 	select DRM_DW_HDMI
+	select IMX8MP_HDMI_PAVI
 	depends on DRM_IMX
 	help
-	  Choose this if you want to use HDMI on i.MX6.
+	  Choose this if you want to use HDMI on i.MX6/i.MX8.
+
+config DRM_IMX_SEC_DSIM
+	tristate "Support for Samsung MIPI DSIM displays"
+	depends on DRM_IMX
+	select MFD_SYSCON
+	select DRM_SEC_MIPI_DSIM
+	help
+	  Choose this to enable the internal SEC MIPI DSIM controller
+	  found on i.MX platform.
+
+source "drivers/gpu/drm/imx/dpu/Kconfig"
+source "drivers/gpu/drm/imx/ipuv3/Kconfig"
+source "drivers/gpu/drm/imx/lcdif/Kconfig"
+source "drivers/gpu/drm/imx/lcdifv3/Kconfig"
+source "drivers/gpu/drm/imx/dcss/Kconfig"
+source "drivers/gpu/drm/imx/mhdp/Kconfig"
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/Makefile
@@ -1,11 +1,23 @@
 # SPDX-License-Identifier: GPL-2.0
 
-imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
+imxdrm-objs := imx-drm-core.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
+obj-$(CONFIG_DRM_IMX_LCDIF_MUX_DISPLAY) += lcdif-mux-display.o
 obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
 obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+obj-$(CONFIG_DRM_IMX8QM_LDB) += imx8qm-ldb.o
+obj-$(CONFIG_DRM_IMX8QXP_LDB) += imx8qxp-ldb.o
+obj-$(CONFIG_DRM_IMX8MP_LDB) += imx8mp-ldb.o
 
+obj-$(CONFIG_DRM_IMX_DPU) += dpu/
+obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3/
 obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+obj-$(CONFIG_IMX8MP_HDMI_PAVI) += imx8mp-hdmi-pavi.o
+obj-$(CONFIG_DRM_IMX_LCDIF) += lcdif/
+obj-$(CONFIG_DRM_IMX_LCDIFV3) += lcdifv3/
+obj-$(CONFIG_DRM_IMX_SEC_DSIM) += sec_mipi_dsim-imx.o
+obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += mhdp/
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/Kconfig
@@ -0,0 +1,7 @@
+config DRM_IMX_DCSS
+	tristate "i.MX8MQ DCSS"
+	select RESET_CONTROLLER
+	select IMX_IRQSTEER
+	help
+	  Choose this if you have a NXP i.MX8MQ based system and want to use the
+	  Display Controller Subsystem. This option enables DCSS support.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/Makefile
@@ -0,0 +1,7 @@
+imx-dcss-objs := dcss-drv.o dcss-dev.o dcss-blkctl.o dcss-ctxld.o dcss-dtg.o \
+				 dcss-ss.o dcss-dpr.o dcss-scaler.o dcss-kms.o dcss-crtc.o \
+				 dcss-plane.o dcss-dec400d.o dcss-hdr10.o dcss-wrscl.o \
+				 dcss-rdsrc.o dcss-dtrc.o
+
+obj-$(CONFIG_DRM_IMX_DCSS) += imx-dcss.o
+
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-blkctl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-blkctl.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/of.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_BLKCTL_RESET_CTRL		0x00
+#define   B_CLK_RESETN			BIT(0)
+#define   APB_CLK_RESETN		BIT(1)
+#define   P_CLK_RESETN			BIT(2)
+#define   RTR_CLK_RESETN		BIT(3)
+#define DCSS_BLKCTL_CONTROL0		0x10
+#define   HDMI_MIPI_CLK_SEL		BIT(0)
+#define   DISPMIX_REFCLK_SEL_POS	4
+#define   DISPMIX_REFCLK_SEL_MASK	GENMASK(5, 4)
+#define   DISPMIX_PIXCLK_SEL		BIT(8)
+#define   HDMI_SRC_SECURE_EN		BIT(16)
+
+struct dcss_blkctl {
+	struct device *dev;
+	void __iomem *base_reg;
+
+	bool hdmi_output;
+};
+
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl)
+{
+	if (blkctl->hdmi_output)
+		dcss_writel(0, blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+	else
+		dcss_writel(DISPMIX_PIXCLK_SEL,
+			    blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+
+	dcss_set(B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN | RTR_CLK_RESETN,
+		 blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+}
+
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base)
+{
+	struct dcss_blkctl *blkctl;
+
+	blkctl = devm_kzalloc(dcss->dev, sizeof(*blkctl), GFP_KERNEL);
+	if (!blkctl)
+		return -ENOMEM;
+
+	blkctl->base_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K);
+	if (!blkctl->base_reg) {
+		dev_err(dcss->dev, "unable to remap BLK CTRL base\n");
+		devm_kfree(dcss->dev, blkctl);
+		return -ENOMEM;
+	}
+
+	dcss->blkctl = blkctl;
+	blkctl->dev = dcss->dev;
+	blkctl->hdmi_output = dcss->hdmi_output;
+
+	dcss_blkctl_cfg(blkctl);
+
+	return 0;
+}
+
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl)
+{
+	dcss_clr(P_CLK_RESETN | RTR_CLK_RESETN,
+		 blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+
+	if (blkctl->base_reg)
+		devm_iounmap(blkctl->dev, blkctl->base_reg);
+
+	devm_kfree(blkctl->dev, blkctl);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-crtc.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static int dcss_enable_vblank(struct drm_crtc *crtc)
+{
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct dcss_dev *dcss = crtc->dev->dev_private;
+
+	if (dcss_crtc->irq_enabled)
+		return 0;
+
+	dcss_crtc->irq_enabled = true;
+
+	dcss_dtg_vblank_irq_enable(dcss->dtg, true);
+
+	dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+	enable_irq(dcss_crtc->irq);
+
+	return 0;
+}
+
+static void dcss_disable_vblank(struct drm_crtc *crtc)
+{
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+	disable_irq_nosync(dcss_crtc->irq);
+
+	dcss_dtg_vblank_irq_enable(dcss->dtg, false);
+
+	if (!dcss_dtrc_is_running(dcss->dtrc))
+		dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);
+
+	dcss_crtc->irq_enabled = false;
+}
+
+static const struct drm_crtc_funcs dcss_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.enable_vblank = dcss_enable_vblank,
+	.disable_vblank = dcss_disable_vblank,
+};
+
+static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	drm_crtc_vblank_on(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+	if (dcss_dtg_is_enabled(dcss->dtg))
+		dcss_ctxld_enable(dcss->ctxld);
+}
+
+static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct videomode vm;
+
+	drm_display_mode_to_videomode(mode, &vm);
+
+	pm_runtime_get_sync(dcss->dev);
+
+	vm.pixelclock = mode->crtc_clock * 1000;
+
+	dcss_dtg_sync_set(dcss->dtg, &vm);
+
+	dcss_ss_subsam_set(dcss->ss, dcss_crtc->output_is_yuv);
+	dcss_ss_sync_set(dcss->ss, &vm, mode->flags & DRM_MODE_FLAG_PHSYNC,
+			 mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	dcss_dtg_css_set(dcss->dtg, dcss_crtc->output_is_yuv);
+
+	dcss_ss_enable(dcss->ss);
+	dcss_dtg_enable(dcss->dtg, true, NULL);
+	dcss_ctxld_enable(dcss->ctxld);
+
+	dcss_enable_vblank(crtc);
+
+	reinit_completion(&dcss_crtc->en_completion);
+	wait_for_completion_timeout(&dcss_crtc->en_completion,
+				    msecs_to_jiffies(500));
+}
+
+static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_crtc_state *old_crtc_state)
+{
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+
+	dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+	dcss_ss_disable(dcss->ss);
+	dcss_dtg_enable(dcss->dtg, false, &dcss_crtc->dis_completion);
+	dcss_ctxld_enable(dcss->ctxld);
+
+	reinit_completion(&dcss_crtc->dis_completion);
+	wait_for_completion_timeout(&dcss_crtc->dis_completion,
+				    msecs_to_jiffies(100));
+
+	drm_crtc_vblank_off(crtc);
+
+	dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);
+
+	pm_runtime_put_sync(dcss->dev);
+}
+
+static enum drm_mode_status dcss_crtc_mode_valid(struct drm_crtc *crtc,
+                        const struct drm_display_mode *mode)
+{
+   /*
+    * From DCSS perspective, dissallow any mode higher than
+    * 3840x2160 or 2160x3840.
+    */
+   if (mode->hdisplay * mode->vdisplay > 3840 * 2160)
+       return MODE_BAD;
+
+   return MODE_OK;
+}
+
+static const struct drm_crtc_helper_funcs dcss_helper_funcs = {
+	.atomic_begin = dcss_crtc_atomic_begin,
+	.atomic_flush = dcss_crtc_atomic_flush,
+	.atomic_enable = dcss_crtc_atomic_enable,
+	.atomic_disable = dcss_crtc_atomic_disable,
+	.mode_valid = dcss_crtc_mode_valid,
+};
+
+static irqreturn_t dcss_crtc_irq_handler(int irq, void *dev_id)
+{
+	struct dcss_crtc *dcss_crtc = dev_id;
+	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+	if (!dcss_dtg_vblank_irq_valid(dcss->dtg))
+		return IRQ_HANDLED;
+
+	complete(&dcss_crtc->en_completion);
+
+	if (dcss_ctxld_is_flushed(dcss->ctxld))
+		drm_crtc_handle_vblank(&dcss_crtc->base);
+
+	dcss_dtg_vblank_irq_clear(dcss->dtg);
+
+	return IRQ_HANDLED;
+}
+
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+	struct dcss_dev *dcss = drm->dev_private;
+	struct platform_device *pdev = to_platform_device(dcss->dev);
+	int ret;
+
+	crtc->plane[0] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+					 DRM_PLANE_TYPE_PRIMARY, 2);
+	if (IS_ERR(crtc->plane[0]))
+		return PTR_ERR(crtc->plane[0]);
+
+	crtc->base.port = dcss->of_port;
+
+	drm_crtc_helper_add(&crtc->base, &dcss_helper_funcs);
+	ret = drm_crtc_init_with_planes(drm, &crtc->base, &crtc->plane[0]->base,
+					NULL, &dcss_crtc_funcs, NULL);
+	if (ret) {
+		dev_err(dcss->dev, "failed to init crtc\n");
+		return ret;
+	}
+
+	crtc->plane[1] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+					 DRM_PLANE_TYPE_OVERLAY, 1);
+	if (IS_ERR(crtc->plane[1]))
+		crtc->plane[1] = NULL;
+
+	crtc->plane[2] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+					 DRM_PLANE_TYPE_OVERLAY, 0);
+	if (IS_ERR(crtc->plane[2]))
+		crtc->plane[2] = NULL;
+
+	drm_plane_create_alpha_property(&crtc->plane[0]->base);
+
+	crtc->irq = platform_get_irq_byname(pdev, "vblank");
+	if (crtc->irq < 0) {
+		dev_err(dcss->dev, "unable to get vblank interrupt\n");
+		return crtc->irq;
+	}
+
+	init_completion(&crtc->en_completion);
+	init_completion(&crtc->dis_completion);
+
+	ret = devm_request_irq(dcss->dev, crtc->irq, dcss_crtc_irq_handler,
+			       IRQF_TRIGGER_RISING, "dcss_drm", crtc);
+	if (ret) {
+		dev_err(dcss->dev, "irq request failed with %d.\n", ret);
+		return ret;
+	}
+
+	disable_irq(crtc->irq);
+
+	return 0;
+}
+
+void dcss_crtc_attach_color_mgmt_properties(struct dcss_crtc *crtc)
+{
+	int i;
+
+	/* create color management properties only for video planes */
+	for (i = 1; i < 3; i++) {
+		if (crtc->plane[i]->type == DRM_PLANE_TYPE_PRIMARY)
+			return;
+
+		drm_plane_create_color_properties(&crtc->plane[i]->base,
+					BIT(DRM_COLOR_YCBCR_BT601) |
+					BIT(DRM_COLOR_YCBCR_BT709) |
+					BIT(DRM_COLOR_YCBCR_BT2020),
+					BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
+					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+					DRM_COLOR_YCBCR_BT709,
+					DRM_COLOR_YCBCR_FULL_RANGE);
+	}
+}
+
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+	struct dcss_dev *dcss = drm->dev_private;
+
+	devm_free_irq(dcss->dev, crtc->irq, crtc);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-ctxld.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-ctxld.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_CTXLD_DEVNAME		"dcss_ctxld"
+
+#define DCSS_CTXLD_CONTROL_STATUS	0x0
+#define   CTXLD_ENABLE			BIT(0)
+#define   ARB_SEL			BIT(1)
+#define   RD_ERR_EN			BIT(2)
+#define   DB_COMP_EN			BIT(3)
+#define   SB_HP_COMP_EN			BIT(4)
+#define   SB_LP_COMP_EN			BIT(5)
+#define   DB_PEND_SB_REC_EN		BIT(6)
+#define   SB_PEND_DISP_ACTIVE_EN	BIT(7)
+#define   AHB_ERR_EN			BIT(8)
+#define   RD_ERR			BIT(16)
+#define   DB_COMP			BIT(17)
+#define   SB_HP_COMP			BIT(18)
+#define   SB_LP_COMP			BIT(19)
+#define   DB_PEND_SB_REC		BIT(20)
+#define   SB_PEND_DISP_ACTIVE		BIT(21)
+#define   AHB_ERR			BIT(22)
+#define DCSS_CTXLD_DB_BASE_ADDR		0x10
+#define DCSS_CTXLD_DB_COUNT		0x14
+#define DCSS_CTXLD_SB_BASE_ADDR		0x18
+#define DCSS_CTXLD_SB_COUNT		0x1C
+#define   SB_HP_COUNT_POS		0
+#define   SB_HP_COUNT_MASK		0xffff
+#define   SB_LP_COUNT_POS		16
+#define   SB_LP_COUNT_MASK		0xffff0000
+#define DCSS_AHB_ERR_ADDR		0x20
+
+#define CTXLD_IRQ_NAME			"ctx_ld"
+#define CTXLD_IRQ_COMPLETION		(DB_COMP | SB_HP_COMP | SB_LP_COMP)
+#define CTXLD_IRQ_ERROR			(RD_ERR | DB_PEND_SB_REC | AHB_ERR)
+
+/* The following sizes are in context loader entries, 8 bytes each. */
+#define CTXLD_DB_CTX_ENTRIES		1024	/* max 65536 */
+#define CTXLD_SB_LP_CTX_ENTRIES		10240	/* max 65536 */
+#define CTXLD_SB_HP_CTX_ENTRIES		20000	/* max 65536 */
+#define CTXLD_SB_CTX_ENTRIES		(CTXLD_SB_LP_CTX_ENTRIES + \
+					 CTXLD_SB_HP_CTX_ENTRIES)
+
+/* Sizes, in entries, of the DB, SB_HP and SB_LP context regions. */
+static u16 dcss_ctxld_ctx_size[3] = {
+	CTXLD_DB_CTX_ENTRIES,
+	CTXLD_SB_HP_CTX_ENTRIES,
+	CTXLD_SB_LP_CTX_ENTRIES
+};
+
+/* this represents an entry in the context loader map */
+struct dcss_ctxld_item {
+	u32 val;
+	u32 ofs;
+};
+
+#define CTX_ITEM_SIZE			sizeof(struct dcss_ctxld_item)
+
+struct dcss_ctxld {
+	struct device *dev;
+	void __iomem *ctxld_reg;
+	int irq;
+	bool irq_en;
+
+	struct dcss_ctxld_item *db[2];
+	struct dcss_ctxld_item *sb_hp[2];
+	struct dcss_ctxld_item *sb_lp[2];
+
+	dma_addr_t db_paddr[2];
+	dma_addr_t sb_paddr[2];
+
+	u16 ctx_size[2][3]; /* holds the sizes of DB, SB_HP and SB_LP ctx */
+	u8 current_ctx;
+
+	bool in_use;
+	bool armed;
+
+	spinlock_t lock; /* protects concurent access to private data */
+
+	void (*dtg_disable_cb)(void *data);
+	void *dtg_disable_data;
+};
+
+static int __dcss_ctxld_enable(struct dcss_ctxld *ctxld);
+
+static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data)
+{
+	struct dcss_ctxld *ctxld = data;
+	u32 irq_status;
+
+	irq_status = dcss_readl(ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+	if (irq_status & CTXLD_IRQ_COMPLETION &&
+	    !(irq_status & CTXLD_ENABLE) && ctxld->in_use) {
+		ctxld->in_use = false;
+
+		if (ctxld->dtg_disable_cb) {
+			ctxld->dtg_disable_cb(ctxld->dtg_disable_data);
+			ctxld->dtg_disable_cb = NULL;
+			ctxld->dtg_disable_data = NULL;
+		}
+	} else if (irq_status & CTXLD_IRQ_ERROR) {
+		/*
+		 * Except for throwing an error message and clearing the status
+		 * register, there's not much we can do here.
+		 */
+		dev_err(ctxld->dev, "ctxld: error encountered: %08x\n",
+			irq_status);
+		dev_err(ctxld->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n",
+			ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_DB],
+			ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_HP],
+			ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_LP]);
+	}
+
+	dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION),
+		 ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+	return IRQ_HANDLED;
+}
+
+static int dcss_ctxld_irq_config(struct dcss_ctxld *ctxld,
+				 struct platform_device *pdev)
+{
+	int ret;
+
+	ctxld->irq = platform_get_irq_byname(pdev, CTXLD_IRQ_NAME);
+	if (ctxld->irq < 0) {
+		dev_err(ctxld->dev, "ctxld: can't get irq number\n");
+		return ctxld->irq;
+	}
+
+	ret = devm_request_irq(ctxld->dev, ctxld->irq,
+			       dcss_ctxld_irq_handler,
+			       IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+			       DCSS_CTXLD_DEVNAME, ctxld);
+	if (ret) {
+		dev_err(ctxld->dev, "ctxld: irq request failed.\n");
+		return ret;
+	}
+
+	ctxld->irq_en = true;
+
+	return 0;
+}
+
+void dcss_ctxld_hw_cfg(struct dcss_ctxld *ctxld)
+{
+	dcss_writel(RD_ERR_EN | SB_HP_COMP_EN |
+		    DB_PEND_SB_REC_EN | AHB_ERR_EN | RD_ERR | AHB_ERR,
+		    ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+}
+
+static void dcss_ctxld_free_ctx(struct dcss_ctxld *ctxld)
+{
+	struct dcss_ctxld_item *ctx;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (ctxld->db[i]) {
+			dmam_free_coherent(ctxld->dev,
+					   CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+					   ctxld->db[i], ctxld->db_paddr[i]);
+			ctxld->db[i] = NULL;
+			ctxld->db_paddr[i] = 0;
+		}
+
+		if (ctxld->sb_hp[i]) {
+			dmam_free_coherent(ctxld->dev,
+					   CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+					   ctxld->sb_hp[i], ctxld->sb_paddr[i]);
+			ctxld->sb_hp[i] = NULL;
+			ctxld->sb_paddr[i] = 0;
+		}
+	}
+}
+
+static int dcss_ctxld_alloc_ctx(struct dcss_ctxld *ctxld)
+{
+	struct dcss_ctxld_item *ctx;
+	int i;
+	dma_addr_t dma_handle;
+
+	for (i = 0; i < 2; i++) {
+		ctx = dmam_alloc_coherent(ctxld->dev,
+					  CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+					  &dma_handle, GFP_KERNEL);
+		if (!ctx)
+			return -ENOMEM;
+
+		ctxld->db[i] = ctx;
+		ctxld->db_paddr[i] = dma_handle;
+
+		ctx = dmam_alloc_coherent(ctxld->dev,
+					  CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+					  &dma_handle, GFP_KERNEL);
+		if (!ctx)
+			return -ENOMEM;
+
+		ctxld->sb_hp[i] = ctx;
+		ctxld->sb_lp[i] = ctx + CTXLD_SB_HP_CTX_ENTRIES;
+
+		ctxld->sb_paddr[i] = dma_handle;
+	}
+
+	return 0;
+}
+
+int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base)
+{
+	struct dcss_ctxld *ctxld;
+	int ret;
+
+	ctxld = devm_kzalloc(dcss->dev, sizeof(struct dcss_ctxld),
+			     GFP_KERNEL);
+	if (!ctxld)
+		return -ENOMEM;
+
+	dcss->ctxld = ctxld;
+	ctxld->dev = dcss->dev;
+
+	spin_lock_init(&ctxld->lock);
+
+	ret = dcss_ctxld_alloc_ctx(ctxld);
+	if (ret) {
+		dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n");
+		goto err;
+	}
+
+	ctxld->ctxld_reg = devm_ioremap(dcss->dev, ctxld_base, SZ_4K);
+	if (!ctxld->ctxld_reg) {
+		dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = dcss_ctxld_irq_config(ctxld, to_platform_device(dcss->dev));
+	if (ret)
+		goto err_irq;
+
+	dcss_ctxld_hw_cfg(ctxld);
+
+	return 0;
+
+err_irq:
+	devm_iounmap(ctxld->dev, ctxld->ctxld_reg);
+
+err:
+	dcss_ctxld_free_ctx(ctxld);
+	devm_kfree(ctxld->dev, ctxld);
+
+	return ret;
+}
+
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld)
+{
+	devm_free_irq(ctxld->dev, ctxld->irq, ctxld);
+
+	if (ctxld->ctxld_reg)
+		devm_iounmap(ctxld->dev, ctxld->ctxld_reg);
+
+	dcss_ctxld_free_ctx(ctxld);
+	devm_kfree(ctxld->dev, ctxld);
+}
+
+static int __dcss_ctxld_enable(struct dcss_ctxld *ctxld)
+{
+	int curr_ctx = ctxld->current_ctx;
+	u32 db_base, sb_base, sb_count;
+	u32 sb_hp_cnt, sb_lp_cnt, db_cnt;
+	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev);
+
+	if (!dcss)
+		return 0;
+
+	dcss_dpr_write_sysctrl(dcss->dpr);
+
+	dcss_scaler_write_sclctrl(dcss->scaler);
+
+	if (dcss_dtrc_is_running(dcss->dtrc)) {
+		dcss_dtrc_switch_banks(dcss->dtrc);
+		ctxld->armed = true;
+	}
+
+	sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP];
+	sb_lp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_LP];
+	db_cnt = ctxld->ctx_size[curr_ctx][CTX_DB];
+
+	/* make sure SB_LP context area comes after SB_HP */
+	if (sb_lp_cnt &&
+	    ctxld->sb_lp[curr_ctx] != ctxld->sb_hp[curr_ctx] + sb_hp_cnt) {
+		struct dcss_ctxld_item *sb_lp_adjusted;
+
+		sb_lp_adjusted = ctxld->sb_hp[curr_ctx] + sb_hp_cnt;
+
+		memcpy(sb_lp_adjusted, ctxld->sb_lp[curr_ctx],
+		       sb_lp_cnt * CTX_ITEM_SIZE);
+	}
+
+	db_base = db_cnt ? ctxld->db_paddr[curr_ctx] : 0;
+
+	dcss_writel(db_base, ctxld->ctxld_reg + DCSS_CTXLD_DB_BASE_ADDR);
+	dcss_writel(db_cnt, ctxld->ctxld_reg + DCSS_CTXLD_DB_COUNT);
+
+	if (sb_hp_cnt)
+		sb_count = ((sb_hp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK) |
+			   ((sb_lp_cnt << SB_LP_COUNT_POS) & SB_LP_COUNT_MASK);
+	else
+		sb_count = (sb_lp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK;
+
+	sb_base = sb_count ? ctxld->sb_paddr[curr_ctx] : 0;
+
+	dcss_writel(sb_base, ctxld->ctxld_reg + DCSS_CTXLD_SB_BASE_ADDR);
+	dcss_writel(sb_count, ctxld->ctxld_reg + DCSS_CTXLD_SB_COUNT);
+
+	/* enable the context loader */
+	dcss_set(CTXLD_ENABLE, ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+	ctxld->in_use = true;
+
+	/*
+	 * Toggle the current context to the alternate one so that any updates
+	 * in the modules' settings take place there.
+	 */
+	ctxld->current_ctx ^= 1;
+
+	ctxld->ctx_size[ctxld->current_ctx][CTX_DB] = 0;
+	ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] = 0;
+	ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] = 0;
+
+	return 0;
+}
+
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctxld->lock, flags);
+	ctxld->armed = true;
+	spin_unlock_irqrestore(&ctxld->lock, flags);
+
+	return 0;
+}
+
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctxld->lock, flags);
+	if (ctxld->armed && !ctxld->in_use) {
+		ctxld->armed = false;
+		__dcss_ctxld_enable(ctxld);
+	}
+	spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctxld, u32 ctx_id, u32 val,
+			      u32 reg_ofs)
+{
+	int curr_ctx = ctxld->current_ctx;
+	struct dcss_ctxld_item *ctx[] = {
+		[CTX_DB] = ctxld->db[curr_ctx],
+		[CTX_SB_HP] = ctxld->sb_hp[curr_ctx],
+		[CTX_SB_LP] = ctxld->sb_lp[curr_ctx]
+	};
+	int item_idx = ctxld->ctx_size[curr_ctx][ctx_id];
+
+	if (item_idx + 1 > dcss_ctxld_ctx_size[ctx_id]) {
+		WARN_ON(1);
+		return;
+	}
+
+	ctx[ctx_id][item_idx].val = val;
+	ctx[ctx_id][item_idx].ofs = reg_ofs;
+	ctxld->ctx_size[curr_ctx][ctx_id] += 1;
+}
+
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+		      u32 val, u32 reg_ofs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctxld->lock, flags);
+	dcss_ctxld_write_irqsafe(ctxld, ctx_id, val, reg_ofs);
+	spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld)
+{
+	return ctxld->ctx_size[ctxld->current_ctx][CTX_DB] == 0 &&
+		ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] == 0 &&
+		ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] == 0;
+}
+
+int dcss_ctxld_resume(struct dcss_ctxld *ctxld)
+{
+	dcss_ctxld_hw_cfg(ctxld);
+
+	if (!ctxld->irq_en) {
+		enable_irq(ctxld->irq);
+		ctxld->irq_en = true;
+	}
+
+	return 0;
+}
+
+int dcss_ctxld_suspend(struct dcss_ctxld *ctxld)
+{
+	int ret = 0;
+	int wait_time_ms = 0;
+	unsigned long flags;
+
+	dcss_ctxld_kick(ctxld);
+
+	while (ctxld->in_use && wait_time_ms < 500) {
+		msleep(20);
+		wait_time_ms += 20;
+	}
+
+	if (wait_time_ms > 500)
+		return -ETIMEDOUT;
+
+	spin_lock_irqsave(&ctxld->lock, flags);
+
+	if (ctxld->irq_en) {
+		disable_irq_nosync(ctxld->irq);
+		ctxld->irq_en = false;
+	}
+
+	/* reset context region and sizes */
+	ctxld->current_ctx = 0;
+	ctxld->ctx_size[0][CTX_DB] = 0;
+	ctxld->ctx_size[0][CTX_SB_HP] = 0;
+	ctxld->ctx_size[0][CTX_SB_LP] = 0;
+
+	spin_unlock_irqrestore(&ctxld->lock, flags);
+
+	return ret;
+}
+
+void dcss_ctxld_register_dtg_disable_cb(struct dcss_ctxld *ctxld,
+					void (*cb)(void *),
+					void *data)
+{
+	ctxld->dtg_disable_cb = cb;
+	ctxld->dtg_disable_data = data;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dec400d.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dec400d.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+
+#include "dcss-dev.h"
+
+/* DEC400D registers offsets */
+#define DEC400D_READCONFIG_BASE		0x800
+#define DEC400D_READCONFIG(i)		(DEC400D_READCONFIG_BASE + ((i) << 2))
+#define   COMPRESSION_ENABLE_BIT	BIT(0)
+#define   COMPRESSION_FORMAT_POS	3
+#define   COMPRESSION_ALIGN_MODE_POS	16
+#define   TILE_ALIGN_MODE_POS		22
+#define   TILE_MODE_POS			25
+#define DEC400D_READBUFFERBASE0		0x900
+#define DEC400D_READCACHEBASE0		0x980
+#define DEC400D_CONTROL			0xB00
+#define DEC400D_CLEAR			0xB80
+#define DEC400D_READBUFFERBASE0		0x900
+#define DEC400D_READCACHEBASE0		0x980
+#define DEC400D_CONTROL			0xB00
+#define   DISABLE_COMPRESSION_BIT	BIT(1)
+#define   SHADOW_TRIGGER_BIT		BIT(29)
+#define DEC400_CFMT_ARGB8		0x0
+#define DEC400_CFMT_XRGB8		0x1
+#define DEC400_CFMT_AYUV		0x2
+#define DEC400_CFMT_UYVY		0x3
+#define DEC400_CFMT_YUY2		0x4
+#define DEC400_CFMT_YUV_ONLY		0x5
+#define DEC400_CFMT_UV_MIX		0x6
+#define DEC400_CFMT_ARGB4		0x7
+#define DEC400_CFMT_XRGB4		0x8
+#define DEC400_CFMT_A1R5G5B5		0x9
+#define DEC400_CFMT_X1R5G5B5		0xA
+#define DEC400_CFMT_R5G6B5		0xB
+#define DEC400_CFMT_Z24S8		0xC
+#define DEC400_CFMT_Z24			0xD
+#define DEC400_CFMT_Z16			0xE
+#define DEC400_CFMT_A2R10G10B10		0xF
+#define DEC400_CFMT_BAYER		0x10
+#define DEC400_CFMT_SIGNED_BAYER	0x11
+
+struct dcss_dec400d {
+	struct device *dev;
+	void __iomem *base_reg;
+	u32 base_ofs;
+	struct dcss_ctxld *ctxld;
+	u32 ctx_id;
+	bool bypass;		/* bypass or decompress */
+};
+
+static void dcss_dec400d_write(struct dcss_dec400d *dec400d,
+			       u32 value,
+			       u32 offset)
+{
+	dcss_ctxld_write(dec400d->ctxld, dec400d->ctx_id,
+			 value, dec400d->base_ofs + offset);
+}
+
+int dcss_dec400d_init(struct dcss_dev *dcss, unsigned long dec400d_base)
+{
+	struct dcss_dec400d *dec400d;
+	int ret;
+
+	dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
+	if (!dec400d)
+		return -ENOMEM;
+
+	dcss->dec400d = dec400d;
+	dec400d->dev = dcss->dev;
+	dec400d->ctxld = dcss->ctxld;
+
+	dec400d->base_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
+	if (!dec400d->base_reg) {
+		dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
+		ret = -ENOMEM;
+		goto free_mem;
+	}
+
+	dec400d->base_ofs = dec400d_base;
+
+	dec400d->ctx_id = CTX_SB_HP;
+
+	return 0;
+
+free_mem:
+	devm_kfree(dcss->dev, dcss->dec400d);
+	return ret;
+}
+
+void dcss_dec400d_exit(struct dcss_dec400d *dec400d)
+{
+	if (dec400d->base_reg)
+		devm_iounmap(dec400d->dev, dec400d->base_reg);
+
+	devm_kfree(dec400d->dev, dec400d);
+}
+
+void dcss_dec400d_read_config(struct dcss_dec400d *dec400d,
+			      u32 read_id,
+			      bool compress_en,
+			      u32 compress_format)
+{
+	u32 cformat = 0;
+	u32 read_config = 0x0;
+
+	/* TODO: using 'read_id' 0 by default */
+	if (read_id) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (!compress_en)
+		goto config;
+
+	switch (compress_format) {
+	case _VIV_CFMT_ARGB8:
+		cformat = DEC400_CFMT_ARGB8;
+		break;
+	case _VIV_CFMT_XRGB8:
+		cformat = DEC400_CFMT_XRGB8;
+		break;
+	case _VIV_CFMT_AYUV:
+		cformat = DEC400_CFMT_AYUV;
+		break;
+	case _VIV_CFMT_UYVY:
+		cformat = DEC400_CFMT_UYVY;
+		break;
+	case _VIV_CFMT_YUY2:
+		cformat = DEC400_CFMT_YUY2;
+		break;
+	case _VIV_CFMT_YUV_ONLY:
+		cformat = DEC400_CFMT_YUV_ONLY;
+		break;
+	case _VIV_CFMT_UV_MIX:
+		cformat = DEC400_CFMT_UV_MIX;
+		break;
+	case _VIV_CFMT_ARGB4:
+		cformat = DEC400_CFMT_ARGB4;
+		break;
+	case _VIV_CFMT_XRGB4:
+		cformat = DEC400_CFMT_XRGB4;
+		break;
+	case _VIV_CFMT_A1R5G5B5:
+		cformat = DEC400_CFMT_A1R5G5B5;
+		break;
+	case _VIV_CFMT_X1R5G5B5:
+		cformat = DEC400_CFMT_X1R5G5B5;
+		break;
+	case _VIV_CFMT_R5G6B5:
+		cformat = DEC400_CFMT_R5G6B5;
+		break;
+	case _VIV_CFMT_Z24S8:
+		cformat = DEC400_CFMT_Z24S8;
+		break;
+	case _VIV_CFMT_Z24:
+		cformat = DEC400_CFMT_Z24;
+		break;
+	case _VIV_CFMT_Z16:
+		cformat = DEC400_CFMT_Z16;
+		break;
+	case _VIV_CFMT_A2R10G10B10:
+		cformat = DEC400_CFMT_A2R10G10B10;
+		break;
+	case _VIV_CFMT_BAYER:
+		cformat = DEC400_CFMT_BAYER;
+		break;
+	case _VIV_CFMT_SIGNED_BAYER:
+		cformat = DEC400_CFMT_SIGNED_BAYER;
+		break;
+	default:
+		/* TODO: not support yet */
+		WARN_ON(1);
+		return;
+	}
+
+	/* Dec compress format */
+	read_config |= cformat << COMPRESSION_FORMAT_POS;
+
+	/* ALIGN32_BYTE */
+	read_config |= 0x2 << COMPRESSION_ALIGN_MODE_POS;
+
+	/* TILE1_ALIGN */
+	read_config |= 0x0 << TILE_ALIGN_MODE_POS;
+
+	/* TILE8x4 */
+	read_config |= 0x3 << TILE_MODE_POS;
+
+	/* Compression Enable */
+	read_config |= COMPRESSION_ENABLE_BIT;
+
+config:
+	dcss_dec400d_write(dec400d, read_config, DEC400D_READCONFIG(read_id));
+}
+
+void dcss_dec400d_bypass(struct dcss_dec400d *dec400d)
+{
+	u32 control;
+
+	dcss_dec400d_read_config(dec400d, 0, false, 0);
+
+	control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+	dev_dbg(dec400d->dev, "%s: dec400d control = %#x\n", __func__, control);
+
+	control |= DISABLE_COMPRESSION_BIT;
+	dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+	/* Trigger shadow registers */
+	control |= SHADOW_TRIGGER_BIT;
+	dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+	dec400d->bypass = true;
+}
+
+void dcss_dec400d_shadow_trig(struct dcss_dec400d *dec400d)
+{
+	u32 control;
+
+	/* do nothing */
+	if (dec400d->bypass)
+		return;
+
+	control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+
+	/* Trigger shadow registers */
+	control |= SHADOW_TRIGGER_BIT;
+	dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
+
+void dcss_dec400d_addr_set(struct dcss_dec400d *dec400d, u32 baddr, u32 caddr)
+{
+	/* set frame buffer base addr */
+	dcss_dec400d_write(dec400d, baddr, DEC400D_READBUFFERBASE0);
+
+	/* set tile status cache addr */
+	dcss_dec400d_write(dec400d, caddr, DEC400D_READCACHEBASE0);
+
+	dec400d->bypass = false;
+}
+
+void dcss_dec400d_fast_clear_config(struct dcss_dec400d *dec400d,
+				    u32 fc_value,
+				    bool enable)
+{
+	dcss_dec400d_write(dec400d, fc_value, DEC400D_CLEAR);
+}
+
+void dcss_dec400d_enable(struct dcss_dec400d *dec400d)
+{
+	u32 control;
+
+	if (dec400d->bypass)
+		return;
+
+	control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+
+	/* enable compression */
+	control &= ~(DISABLE_COMPRESSION_BIT);
+	dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+	/* Trigger shadow registers */
+	control |= SHADOW_TRIGGER_BIT;
+	dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dev.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dev.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/busfreq-imx.h>
+#include <drm/drm_modeset_helper.h>
+
+#include "dcss-dev.h"
+
+static void dcss_clocks_enable(struct dcss_dev *dcss)
+{
+	if (dcss->clks_on)
+		return;
+
+	if (dcss->hdmi_output) {
+		clk_prepare_enable(dcss->pll_phy_ref_clk);
+		clk_prepare_enable(dcss->pll_src_clk);
+	}
+
+	clk_prepare_enable(dcss->axi_clk);
+	clk_prepare_enable(dcss->apb_clk);
+	clk_prepare_enable(dcss->rtrm_clk);
+	clk_prepare_enable(dcss->dtrc_clk);
+	clk_prepare_enable(dcss->pix_clk);
+
+	dcss->clks_on = true;
+}
+
+static void dcss_clocks_disable(struct dcss_dev *dcss)
+{
+	if (!dcss->clks_on)
+		return;
+
+	clk_disable_unprepare(dcss->pix_clk);
+	clk_disable_unprepare(dcss->dtrc_clk);
+	clk_disable_unprepare(dcss->rtrm_clk);
+	clk_disable_unprepare(dcss->apb_clk);
+	clk_disable_unprepare(dcss->axi_clk);
+
+	if (dcss->hdmi_output) {
+		clk_disable_unprepare(dcss->pll_src_clk);
+		clk_disable_unprepare(dcss->pll_phy_ref_clk);
+	}
+
+	dcss->clks_on = false;
+}
+
+static void dcss_busfreq_enable(struct dcss_dev *dcss)
+{
+	if (dcss->bus_freq_on)
+		return;
+
+	request_bus_freq(BUS_FREQ_HIGH);
+
+	dcss->bus_freq_on = true;
+}
+
+static void dcss_busfreq_disable(struct dcss_dev *dcss)
+{
+	if (!dcss->bus_freq_on)
+		return;
+
+	release_bus_freq(BUS_FREQ_HIGH);
+
+	dcss->bus_freq_on = false;
+}
+
+static int dcss_submodules_init(struct dcss_dev *dcss)
+{
+	int ret = 0;
+	u32 base_addr = dcss->start_addr;
+	const struct dcss_type_data *devtype = dcss->devtype;
+
+	dcss_clocks_enable(dcss);
+
+	ret = dcss_blkctl_init(dcss, base_addr + devtype->blkctl_ofs);
+	if (ret)
+		return ret;
+
+	ret = dcss_ctxld_init(dcss, base_addr + devtype->ctxld_ofs);
+	if (ret)
+		goto ctxld_err;
+
+	ret = dcss_dtg_init(dcss, base_addr + devtype->dtg_ofs);
+	if (ret)
+		goto dtg_err;
+
+	ret = dcss_ss_init(dcss, base_addr + devtype->ss_ofs);
+	if (ret)
+		goto ss_err;
+
+	ret = dcss_dtrc_init(dcss, base_addr + devtype->dtrc_ofs);
+	if (ret)
+		goto dtrc_err;
+
+	ret = dcss_dpr_init(dcss, base_addr + devtype->dpr_ofs);
+	if (ret)
+		goto dpr_err;
+
+	ret = dcss_wrscl_init(dcss, base_addr + devtype->wrscl_ofs);
+	if (ret)
+		goto wrscl_err;
+
+	ret = dcss_rdsrc_init(dcss, base_addr + devtype->rdsrc_ofs);
+	if (ret)
+		goto rdsrc_err;
+
+	ret = dcss_scaler_init(dcss, base_addr + devtype->scaler_ofs);
+	if (ret)
+		goto scaler_err;
+
+	ret = dcss_dec400d_init(dcss, base_addr + devtype->dec400d_ofs);
+	if (ret)
+		goto dec400d_err;
+
+	ret = dcss_hdr10_init(dcss, base_addr + devtype->hdr10_ofs);
+	if (ret)
+		goto hdr10_err;
+
+	return 0;
+
+hdr10_err:
+	dcss_dec400d_exit(dcss->dec400d);
+
+dec400d_err:
+	dcss_scaler_exit(dcss->scaler);
+
+scaler_err:
+	dcss_rdsrc_exit(dcss->rdsrc);
+
+rdsrc_err:
+	dcss_wrscl_exit(dcss->wrscl);
+
+wrscl_err:
+	dcss_dpr_exit(dcss->dpr);
+
+dpr_err:
+	dcss_dtrc_exit(dcss->dtrc);
+
+dtrc_err:
+	dcss_ss_exit(dcss->ss);
+
+ss_err:
+	dcss_dtg_exit(dcss->dtg);
+
+dtg_err:
+	dcss_ctxld_exit(dcss->ctxld);
+
+ctxld_err:
+	dcss_blkctl_exit(dcss->blkctl);
+
+	dcss_clocks_disable(dcss);
+
+	return ret;
+}
+
+static void dcss_submodules_stop(struct dcss_dev *dcss)
+{
+	dcss_clocks_enable(dcss);
+	dcss_hdr10_exit(dcss->hdr10);
+	dcss_dec400d_exit(dcss->dec400d);
+	dcss_scaler_exit(dcss->scaler);
+	dcss_rdsrc_exit(dcss->rdsrc);
+	dcss_wrscl_exit(dcss->wrscl);
+	dcss_dpr_exit(dcss->dpr);
+	dcss_dtrc_exit(dcss->dtrc);
+	dcss_ss_exit(dcss->ss);
+	dcss_dtg_exit(dcss->dtg);
+	dcss_ctxld_exit(dcss->ctxld);
+	dcss_blkctl_exit(dcss->blkctl);
+	dcss_clocks_disable(dcss);
+}
+
+static int dcss_clks_init(struct dcss_dev *dcss)
+{
+	int i;
+	struct {
+		const char *id;
+		struct clk **clk;
+		bool required;
+	} clks[] = {
+		{"apb",   &dcss->apb_clk, true},
+		{"axi",   &dcss->axi_clk, true},
+		{"pix",   &dcss->pix_clk, true},
+		{"rtrm",  &dcss->rtrm_clk, true},
+		{"dtrc",  &dcss->dtrc_clk, true},
+		{"pll_src",  &dcss->pll_src_clk, dcss->hdmi_output},
+		{"pll_phy_ref",  &dcss->pll_phy_ref_clk, dcss->hdmi_output},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(clks); i++) {
+		*clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
+		if (IS_ERR(*clks[i].clk) && clks[i].required) {
+			dev_err(dcss->dev, "failed to get %s clock\n",
+				clks[i].id);
+			return PTR_ERR(*clks[i].clk);
+		}
+	}
+
+	dcss->clks_on = false;
+
+	return 0;
+}
+
+static void dcss_clks_release(struct dcss_dev *dcss)
+{
+	devm_clk_put(dcss->dev, dcss->dtrc_clk);
+	devm_clk_put(dcss->dev, dcss->rtrm_clk);
+	devm_clk_put(dcss->dev, dcss->pix_clk);
+	devm_clk_put(dcss->dev, dcss->axi_clk);
+	devm_clk_put(dcss->dev, dcss->apb_clk);
+}
+
+struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int ret;
+	struct resource *res;
+	struct dcss_dev *dcss;
+	const struct dcss_type_data *devtype;
+
+	devtype = of_device_get_match_data(dev);
+	if (!devtype) {
+		dev_err(dev, "no device match found\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "cannot get memory resource\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	dcss = devm_kzalloc(dev, sizeof(struct dcss_dev), GFP_KERNEL);
+	if (!dcss)
+		return ERR_PTR(-ENOMEM);
+
+	dcss->dev = dev;
+	dcss->devtype = devtype;
+	dcss->hdmi_output = hdmi_output;
+
+	ret = dcss_clks_init(dcss);
+	if (ret) {
+		dev_err(dev, "clocks initialization failed\n");
+		goto err;
+	}
+
+	dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0);
+	if (!dcss->of_port) {
+		dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
+		ret = -ENODEV;
+		goto clks_err;
+	}
+
+	dcss->start_addr = res->start;
+
+	ret = dcss_submodules_init(dcss);
+	if (ret) {
+		dev_err(dev, "submodules initialization failed\n");
+		goto clks_err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return dcss;
+
+clks_err:
+	dcss_clks_release(dcss);
+
+err:
+	devm_kfree(dcss->dev, dcss);
+
+	return ERR_PTR(ret);
+}
+
+void dcss_dev_destroy(struct dcss_dev *dcss)
+{
+	pm_runtime_disable(dcss->dev);
+
+	dcss_submodules_stop(dcss);
+
+	dcss_clks_release(dcss);
+
+	devm_kfree(dcss->dev, dcss);
+}
+
+#ifdef CONFIG_PM_SLEEP
+int dcss_dev_suspend(struct device *dev)
+{
+	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+	int ret;
+
+	if (!dcss)
+		return 0;
+
+	drm_mode_config_helper_suspend(dcss_drv_dev_to_drm(dev));
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	ret = dcss_ctxld_suspend(dcss->ctxld);
+	if (ret)
+		return ret;
+
+	dcss_clocks_disable(dcss);
+
+	dcss_busfreq_disable(dcss);
+
+	return 0;
+}
+
+int dcss_dev_resume(struct device *dev)
+{
+	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+
+	if (!dcss)
+		return 0;
+
+	if (pm_runtime_suspended(dev)) {
+		drm_mode_config_helper_resume(dcss_drv_dev_to_drm(dev));
+		return 0;
+	}
+
+	dcss_busfreq_enable(dcss);
+
+	dcss_clocks_enable(dcss);
+
+	dcss_blkctl_cfg(dcss->blkctl);
+
+	dcss_ctxld_resume(dcss->ctxld);
+
+	drm_mode_config_helper_resume(dcss_drv_dev_to_drm(dev));
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+int dcss_dev_runtime_suspend(struct device *dev)
+{
+	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+	int ret;
+
+	if (!dcss)
+		return 0;
+
+	ret = dcss_ctxld_suspend(dcss->ctxld);
+	if (ret)
+		return ret;
+
+	dcss_clocks_disable(dcss);
+
+	dcss_busfreq_disable(dcss);
+
+	return 0;
+}
+
+int dcss_dev_runtime_resume(struct device *dev)
+{
+	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+
+	if (!dcss)
+		return 0;
+
+	dcss_busfreq_enable(dcss);
+
+	dcss_clocks_enable(dcss);
+
+	dcss_blkctl_cfg(dcss->blkctl);
+
+	dcss_ctxld_resume(dcss->ctxld);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dev.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dev.h
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef __DCSS_PRV_H__
+#define __DCSS_PRV_H__
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_fourcc.h>
+#include <linux/io.h>
+#include <video/videomode.h>
+
+#define SET			0x04
+#define CLR			0x08
+#define TGL			0x0C
+
+#define dcss_writel(v, c)	writel((v), (c))
+#define dcss_readl(c)		readl(c)
+#define dcss_set(v, c)		writel((v), (c) + SET)
+#define dcss_clr(v, c)		writel((v), (c) + CLR)
+#define dcss_toggle(v, c)	writel((v), (c) + TGL)
+
+static inline void dcss_update(u32 v, u32 m, void __iomem *c)
+{
+	writel((readl(c) & ~(m)) | (v), (c));
+}
+
+#define DCSS_DBG_REG(reg)	{.name = #reg, .ofs = reg}
+
+enum {
+	DCSS_IMX8MQ = 0,
+};
+
+struct dcss_type_data {
+	const char *name;
+	u32 blkctl_ofs;
+	u32 ctxld_ofs;
+	u32 rdsrc_ofs;
+	u32 wrscl_ofs;
+	u32 dtg_ofs;
+	u32 scaler_ofs;
+	u32 ss_ofs;
+	u32 dpr_ofs;
+	u32 dtrc_ofs;
+	u32 dec400d_ofs;
+	u32 hdr10_ofs;
+};
+
+struct dcss_debug_reg {
+	char *name;
+	u32 ofs;
+};
+
+enum dcss_ctxld_ctx_type {
+	CTX_DB,
+	CTX_SB_HP, /* high-priority */
+	CTX_SB_LP, /* low-priority  */
+};
+
+struct dcss_dev {
+	struct device *dev;
+	const struct dcss_type_data *devtype;
+	struct device_node *of_port;
+
+	u32 start_addr;
+
+	struct dcss_blkctl *blkctl;
+	struct dcss_ctxld *ctxld;
+	struct dcss_dpr *dpr;
+	struct dcss_dtg *dtg;
+	struct dcss_ss *ss;
+	struct dcss_hdr10 *hdr10;
+	struct dcss_scaler *scaler;
+	struct dcss_dtrc *dtrc;
+	struct dcss_dec400d *dec400d;
+	struct dcss_wrscl *wrscl;
+	struct dcss_rdsrc *rdsrc;
+
+	struct clk *apb_clk;
+	struct clk *axi_clk;
+	struct clk *pix_clk;
+	struct clk *rtrm_clk;
+	struct clk *dtrc_clk;
+	struct clk *pll_src_clk;
+	struct clk *pll_phy_ref_clk;
+
+	void (*dcss_disable_callback)(void *data);
+
+	bool clks_on;
+	bool bus_freq_on;
+	bool hdmi_output;
+};
+
+enum dcss_color_space {
+	DCSS_COLORSPACE_RGB,
+	DCSS_COLORSPACE_YUV,
+	DCSS_COLORSPACE_UNKNOWN,
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev);
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev);
+struct dcss_dev *dcss_dev_create(struct device *dev, bool mipi_output);
+void dcss_dev_destroy(struct dcss_dev *dcss);
+int dcss_dev_runtime_suspend(struct device *dev);
+int dcss_dev_runtime_resume(struct device *dev);
+int dcss_dev_suspend(struct device *dev);
+int dcss_dev_resume(struct device *dev);
+
+/* BLKCTL */
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base);
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl);
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl);
+
+/* CTXLD */
+int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base);
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld);
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+		      u32 val, u32 reg_idx);
+int dcss_ctxld_resume(struct dcss_ctxld *dcss_ctxld);
+int dcss_ctxld_suspend(struct dcss_ctxld *dcss_ctxld);
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctlxd, u32 ctx_id, u32 val,
+			      u32 reg_ofs);
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld);
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld);
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld);
+void dcss_ctxld_register_dtg_disable_cb(struct dcss_ctxld *ctxld,
+					void (*cb)(void *),
+					void *data);
+void dcss_ctxld_register_dtrc_cb(struct dcss_ctxld *ctxld,
+				 bool (*cb)(void *),
+				 void *data);
+
+/* DPR */
+enum dcss_tile_type {
+	TILE_LINEAR = 0,
+	TILE_GPU_STANDARD,
+	TILE_GPU_SUPER,
+	TILE_VPU_YUV420,
+	TILE_VPU_VP9,
+};
+
+enum dcss_pix_size {
+	PIX_SIZE_8,
+	PIX_SIZE_16,
+	PIX_SIZE_32,
+};
+
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base);
+void dcss_dpr_exit(struct dcss_dpr *dpr);
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr);
+void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres);
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+		       u32 chroma_base_addr, u16 pitch);
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en);
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+			 const struct drm_format_info *format, u64 modifier);
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation);
+
+/* DTG */
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base);
+void dcss_dtg_exit(struct dcss_dtg *dtg);
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg);
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en);
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg);
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm);
+void dcss_dtg_css_set(struct dcss_dtg *dtg, bool out_is_yuv);
+void dcss_dtg_enable(struct dcss_dtg *dtg, bool en,
+		     struct completion *dis_completion);
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg);
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en);
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha);
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+			      const struct drm_format_info *format, int alpha);
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+			    int px, int py, int pw, int ph);
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en);
+
+/* SUBSAM */
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long subsam_base);
+void dcss_ss_exit(struct dcss_ss *ss);
+void dcss_ss_enable(struct dcss_ss *ss);
+void dcss_ss_disable(struct dcss_ss *ss);
+void dcss_ss_subsam_set(struct dcss_ss *ss, bool output_is_yuv);
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+		      bool phsync, bool pvsync);
+
+/* SCALER */
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base);
+void dcss_scaler_exit(struct dcss_scaler *scl);
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+		       const struct drm_format_info *format,
+		       int src_xres, int src_yres, int dst_xres, int dst_yres,
+		       u32 vrefresh_hz);
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en);
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+				   int *min, int *max);
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl);
+
+/* DEC400D */
+
+#define VIV_VIDMEM_METADATA_MAGIC fourcc_code('v', 'i', 'v', 'm')
+
+/* Compressed format now was defined same as dec400d, should be general. */
+typedef enum _VIV_COMPRESS_FMT
+{
+    _VIV_CFMT_ARGB8 = 0,
+    _VIV_CFMT_XRGB8,
+    _VIV_CFMT_AYUV,
+    _VIV_CFMT_UYVY,
+    _VIV_CFMT_YUY2,
+    _VIV_CFMT_YUV_ONLY,
+    _VIV_CFMT_UV_MIX,
+    _VIV_CFMT_ARGB4,
+    _VIV_CFMT_XRGB4,
+    _VIV_CFMT_A1R5G5B5,
+    _VIV_CFMT_X1R5G5B5,
+    _VIV_CFMT_R5G6B5,
+    _VIV_CFMT_Z24S8,
+    _VIV_CFMT_Z24,
+    _VIV_CFMT_Z16,
+    _VIV_CFMT_A2R10G10B10,
+    _VIV_CFMT_BAYER,
+    _VIV_CFMT_SIGNED_BAYER,
+    _VIV_CFMT_VAA16,
+    _VIV_CFMT_S8,
+
+    _VIV_CFMT_MAX,
+} _VIV_COMPRESS_FMT;
+
+/* Metadata for cross-device fd share with additional (ts) info. */
+typedef struct _VIV_VIDMEM_METADATA
+{
+    uint32_t magic;
+
+    int32_t  ts_fd;
+    void *   ts_dma_buf;
+
+    uint32_t fc_enabled;
+    uint32_t fc_value;
+    uint32_t fc_value_upper;
+
+    uint32_t compressed;
+    uint32_t compress_format;
+} _VIV_VIDMEM_METADATA;
+
+int dcss_dec400d_init(struct dcss_dev *dcss, unsigned long dec400d_base);
+void dcss_dec400d_exit(struct dcss_dec400d *dec400d);
+void dcss_dec400d_bypass(struct dcss_dec400d *dec400d);
+void dcss_dec400d_shadow_trig(struct dcss_dec400d *dec400d);
+void dcss_dec400d_enable(struct dcss_dec400d *dec400d);
+void dcss_dec400d_fast_clear_config(struct dcss_dec400d *dec400d,
+				    u32 fc_value,
+				    bool enable);
+void dcss_dec400d_read_config(struct dcss_dec400d *dec400d,
+			      u32 read_id,
+			      bool compress_en,
+			      u32 compress_format);
+void dcss_dec400d_addr_set(struct dcss_dec400d *dec400d, u32 baddr, u32 caddr);
+
+/* HDR10 */
+enum dcss_hdr10_nonlinearity {
+	NL_REC2084,
+	NL_REC709,
+	NL_BT1886,
+	NL_2100HLG,
+	NL_SRGB,
+};
+
+enum dcss_hdr10_pixel_range {
+	PR_LIMITED,
+	PR_FULL,
+};
+
+enum dcss_hdr10_gamut {
+	G_REC2020,
+	G_REC709,
+	G_REC601_NTSC,
+	G_REC601_PAL,
+	G_ADOBE_ARGB,
+};
+
+struct dcss_hdr10_pipe_cfg {
+	bool is_yuv;
+	enum dcss_hdr10_nonlinearity nl;
+	enum dcss_hdr10_pixel_range pr;
+	enum dcss_hdr10_gamut g;
+};
+
+int dcss_hdr10_init(struct dcss_dev *dcss, unsigned long hdr10_base);
+void dcss_hdr10_exit(struct dcss_hdr10 *hdr10);
+void dcss_hdr10_setup(struct dcss_hdr10 *hdr10, int ch_num,
+		      struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+		      struct dcss_hdr10_pipe_cfg *opipe_cfg);
+
+/* enums common to both WRSCL and RDSRC */
+enum dcss_wrscl_rdsrc_psize {
+	PSIZE_64,
+	PSIZE_128,
+	PSIZE_256,
+	PSIZE_512,
+	PSIZE_1024,
+	PSIZE_2048,
+	PSIZE_4096,
+};
+
+enum dcss_wrscl_rdsrc_tsize {
+	TSIZE_64,
+	TSIZE_128,
+	TSIZE_256,
+	TSIZE_512,
+};
+
+enum dcss_wrscl_rdsrc_fifo_size {
+	FIFO_512,
+	FIFO_1024,
+	FIFO_2048,
+	FIFO_4096,
+};
+
+enum dcss_wrscl_rdsrc_bpp {
+	BPP_38, /* 38 bit unpacked components */
+	BPP_32_UPCONVERT,
+	BPP_32_10BIT_OUTPUT,
+	BPP_20, /* 10-bit YUV422 */
+	BPP_16, /* 8-bit YUV422 */
+};
+
+/* WRSCL */
+int dcss_wrscl_init(struct dcss_dev *dcss, unsigned long wrscl_base);
+void dcss_wrscl_exit(struct dcss_wrscl *wrscl);
+u32 dcss_wrscl_setup(struct dcss_wrscl *wrscl, u32 pix_format, u32 pix_clk_hz,
+		     u32 dst_xres, u32 dst_yres);
+void dcss_wrscl_enable(struct dcss_wrscl *wrscl);
+void dcss_wrscl_disable(struct dcss_wrscl *wrscl);
+
+/* RDSRC */
+int dcss_rdsrc_init(struct dcss_dev *dcss, unsigned long rdsrc_base);
+void dcss_rdsrc_exit(struct dcss_rdsrc *rdsrc);
+void dcss_rdsrc_setup(struct dcss_rdsrc *rdsrc, u32 pix_format, u32 dst_xres,
+		      u32 dst_yres, u32 base_addr);
+void dcss_rdsrc_enable(struct dcss_rdsrc *rdsrc);
+void dcss_rdsrc_disable(struct dcss_rdsrc *rdsrc);
+
+/* DTRC */
+int dcss_dtrc_init(struct dcss_dev *dcss, unsigned long dtrc_base);
+void dcss_dtrc_exit(struct dcss_dtrc *dtrc);
+void dcss_dtrc_bypass(struct dcss_dtrc *dtrc, int ch_num);
+void dcss_dtrc_set_format_mod(struct dcss_dtrc *dtrc, int ch_num, u64 modifier);
+void dcss_dtrc_addr_set(struct dcss_dtrc *dtrc, int ch_num,
+			u32 p1_ba, u32 p2_ba, uint64_t dec_table_ofs);
+bool dcss_dtrc_ch_running(struct dcss_dtrc *dtrc, int ch_num);
+bool dcss_dtrc_is_running(struct dcss_dtrc *dtrc);
+void dcss_dtrc_enable(struct dcss_dtrc *dtrc, int ch_num, bool enable);
+void dcss_dtrc_set_res(struct dcss_dtrc *dtrc, int ch_num,
+		       struct drm_plane_state *state, u32 *dtrc_w, u32 *dtrc_h);
+void dcss_dtrc_switch_banks(struct dcss_dtrc *dtrc);
+
+#endif /* __DCSS_PRV_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dpr.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dpr.c
@@ -0,0 +1,573 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_DPR_SYSTEM_CTRL0			0x000
+#define   RUN_EN				BIT(0)
+#define   SOFT_RESET				BIT(1)
+#define   REPEAT_EN				BIT(2)
+#define   SHADOW_LOAD_EN			BIT(3)
+#define   SW_SHADOW_LOAD_SEL			BIT(4)
+#define   BCMD2AXI_MSTR_ID_CTRL			BIT(16)
+#define DCSS_DPR_IRQ_MASK			0x020
+#define DCSS_DPR_IRQ_MASK_STATUS		0x030
+#define DCSS_DPR_IRQ_NONMASK_STATUS		0x040
+#define   IRQ_DPR_CTRL_DONE			BIT(0)
+#define   IRQ_DPR_RUN				BIT(1)
+#define   IRQ_DPR_SHADOW_LOADED			BIT(2)
+#define   IRQ_AXI_READ_ERR			BIT(3)
+#define   DPR2RTR_YRGB_FIFO_OVFL		BIT(4)
+#define   DPR2RTR_UV_FIFO_OVFL			BIT(5)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR	BIT(6)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR	BIT(7)
+#define DCSS_DPR_MODE_CTRL0			0x050
+#define   RTR_3BUF_EN				BIT(0)
+#define   RTR_4LINE_BUF_EN			BIT(1)
+#define   TILE_TYPE_POS				2
+#define   TILE_TYPE_MASK			GENMASK(4, 2)
+#define   YUV_EN				BIT(6)
+#define   COMP_2PLANE_EN			BIT(7)
+#define   PIX_SIZE_POS				8
+#define   PIX_SIZE_MASK				GENMASK(9, 8)
+#define   PIX_LUMA_UV_SWAP			BIT(10)
+#define   PIX_UV_SWAP				BIT(11)
+#define   B_COMP_SEL_POS			12
+#define   B_COMP_SEL_MASK			GENMASK(13, 12)
+#define   G_COMP_SEL_POS			14
+#define   G_COMP_SEL_MASK			GENMASK(15, 14)
+#define   R_COMP_SEL_POS			16
+#define   R_COMP_SEL_MASK			GENMASK(17, 16)
+#define   A_COMP_SEL_POS			18
+#define   A_COMP_SEL_MASK			GENMASK(19, 18)
+#define DCSS_DPR_FRAME_CTRL0			0x070
+#define   HFLIP_EN				BIT(0)
+#define   VFLIP_EN				BIT(1)
+#define   ROT_ENC_POS				2
+#define   ROT_ENC_MASK				GENMASK(3, 2)
+#define   ROT_FLIP_ORDER_EN			BIT(4)
+#define   PITCH_POS				16
+#define   PITCH_MASK				GENMASK(31, 16)
+#define DCSS_DPR_FRAME_1P_CTRL0			0x090
+#define DCSS_DPR_FRAME_1P_PIX_X_CTRL		0x0A0
+#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL		0x0B0
+#define DCSS_DPR_FRAME_1P_BASE_ADDR		0x0C0
+#define DCSS_DPR_FRAME_2P_CTRL0			0x0E0
+#define DCSS_DPR_FRAME_2P_PIX_X_CTRL		0x0F0
+#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL		0x100
+#define DCSS_DPR_FRAME_2P_BASE_ADDR		0x110
+#define DCSS_DPR_STATUS_CTRL0			0x130
+#define   STATUS_MUX_SEL_MASK			GENMASK(2, 0)
+#define   STATUS_SRC_SEL_POS			16
+#define   STATUS_SRC_SEL_MASK			GENMASK(18, 16)
+#define DCSS_DPR_STATUS_CTRL1			0x140
+#define DCSS_DPR_RTRAM_CTRL0			0x200
+#define   NUM_ROWS_ACTIVE			BIT(0)
+#define   THRES_HIGH_POS			1
+#define   THRES_HIGH_MASK			GENMASK(3, 1)
+#define   THRES_LOW_POS				4
+#define   THRES_LOW_MASK			GENMASK(6, 4)
+#define   ABORT_SEL				BIT(7)
+
+struct dcss_dpr_ch {
+	struct dcss_dpr *dpr;
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	struct drm_format_info format;
+	enum dcss_pix_size pix_size;
+	enum dcss_tile_type tile;
+	bool rtram_4line_en;
+	bool rtram_3buf_en;
+
+	u32 frame_ctrl;
+	u32 mode_ctrl;
+	u32 sys_ctrl;
+	u32 rtram_ctrl;
+
+	bool sys_ctrl_chgd;
+
+	u32 pitch;
+
+	int ch_num;
+	int irq;
+
+	bool use_dtrc;
+};
+
+struct dcss_dpr {
+	struct device *dev;
+	struct dcss_dtrc *dtrc;
+	struct dcss_ctxld *ctxld;
+	u32  ctx_id;
+
+	struct dcss_dpr_ch ch[3];
+};
+
+static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
+{
+	struct dcss_dpr *dpr = ch->dpr;
+
+	dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
+{
+	struct dcss_dpr_ch *ch;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ch = &dpr->ch[i];
+
+		ch->base_ofs = dpr_base + i * 0x1000;
+
+		ch->base_reg = devm_ioremap(dpr->dev, ch->base_ofs, SZ_4K);
+		if (!ch->base_reg) {
+			dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
+				i);
+			return -ENOMEM;
+		}
+
+		ch->dpr = dpr;
+		ch->ch_num = i;
+
+		dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
+	}
+
+	return 0;
+}
+
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
+{
+	struct dcss_dpr *dpr;
+
+	dpr = devm_kzalloc(dcss->dev, sizeof(struct dcss_dpr), GFP_KERNEL);
+	if (!dpr)
+		return -ENOMEM;
+
+	dcss->dpr = dpr;
+	dpr->dev = dcss->dev;
+	dpr->ctxld = dcss->ctxld;
+	dpr->ctx_id = CTX_SB_HP;
+	dpr->dtrc = dcss->dtrc;
+
+	if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
+		int i;
+
+		for (i = 0; i < 3; i++) {
+			if (dpr->ch[i].base_reg)
+				devm_iounmap(dpr->dev, dpr->ch[i].base_reg);
+		}
+
+		devm_kfree(dpr->dev, dpr);
+
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dcss_dpr_exit(struct dcss_dpr *dpr)
+{
+	int ch_no;
+
+	/* stop DPR on all channels */
+	for (ch_no = 0; ch_no < 3; ch_no++) {
+		struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
+
+		dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
+
+		if (ch->base_reg)
+			devm_iounmap(dpr->dev, ch->base_reg);
+	}
+
+	devm_kfree(dpr->dev, dpr);
+}
+
+static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
+				      u32 pix_format)
+{
+	u8 pix_in_64byte_map[3][5] = {
+		/* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
+		{   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
+		{   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
+		{   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
+	};
+	u32 offset;
+	u32 div_64byte_mod, pix_in_64byte;
+
+	pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
+
+	if (pix_format == DRM_FORMAT_NV12_10LE40)
+		pix_wide = pix_wide * 10 / 8;
+
+	div_64byte_mod = pix_wide % pix_in_64byte;
+	offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
+
+	return pix_wide + offset;
+}
+
+static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
+				      u32 pix_format)
+{
+	u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
+	u32 offset, pix_y_mod;
+
+	pix_y_mod = pix_high % num_rows_buf;
+	offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
+
+	return pix_high + offset;
+}
+
+void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres)
+{
+	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+	u32 pix_format = ch->format.format;
+	u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
+	int plane, max_planes = 1;
+	u32 pix_x_wide, pix_y_high;
+
+	if (pix_format == DRM_FORMAT_NV12 ||
+	    pix_format == DRM_FORMAT_NV21 ||
+	    pix_format == DRM_FORMAT_NV12_10LE40)
+		max_planes = 2;
+
+	for (plane = 0; plane < max_planes; plane++) {
+		yres = plane == 1 ? yres >> 1 : yres;
+
+		pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
+		pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
+
+		if (plane == 0)
+			ch->pitch = pix_x_wide;
+
+		dcss_dpr_write(ch, pix_x_wide,
+			       DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
+		dcss_dpr_write(ch, pix_y_high,
+			       DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
+
+		dcss_dpr_write(ch, ch->use_dtrc ? 7 : 2,
+			       DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
+	}
+}
+
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+		       u32 chroma_base_addr, u16 pitch)
+{
+	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+	if (ch->use_dtrc) {
+		luma_base_addr = 0x0;
+		chroma_base_addr = 0x10000000;
+	}
+
+	if (!dcss_dtrc_ch_running(dpr->dtrc, ch_num)) {
+		dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
+		dcss_dpr_write(ch, chroma_base_addr,
+			       DCSS_DPR_FRAME_2P_BASE_ADDR);
+	}
+
+	if (ch->use_dtrc)
+		pitch = ch->pitch;
+
+	ch->frame_ctrl &= ~PITCH_MASK;
+	ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
+}
+
+static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
+				   int g_sel, int b_sel)
+{
+	u32 sel;
+
+	sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
+	      ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
+	      ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
+	      ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
+
+	ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
+			   G_COMP_SEL_MASK | B_COMP_SEL_MASK);
+	ch->mode_ctrl |= sel;
+}
+
+static void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch,
+				  const struct drm_format_info *format)
+{
+	u32 val;
+
+	switch (format->format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV12_10LE40:
+		val = 0;
+		break;
+
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		val = 1;
+		break;
+
+	default:
+		val = 2;
+		break;
+	}
+
+	ch->pix_size = val;
+
+	ch->mode_ctrl &= ~PIX_SIZE_MASK;
+	ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
+}
+
+static void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap)
+{
+	ch->mode_ctrl &= ~PIX_UV_SWAP;
+	ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
+}
+
+static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
+{
+	ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
+	ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
+}
+
+static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
+{
+	ch->mode_ctrl &= ~COMP_2PLANE_EN;
+	ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
+}
+
+static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
+{
+	ch->mode_ctrl &= ~YUV_EN;
+	ch->mode_ctrl |= (en ? YUV_EN : 0);
+}
+
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
+{
+	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+	u32 sys_ctrl;
+
+	sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
+
+	if (en) {
+		dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
+		dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
+		dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
+	}
+
+	if (ch->sys_ctrl != sys_ctrl)
+		ch->sys_ctrl_chgd = true;
+
+	ch->sys_ctrl = sys_ctrl;
+}
+
+struct rgb_comp_sel {
+	u32 drm_format;
+	int a_sel;
+	int r_sel;
+	int g_sel;
+	int b_sel;
+};
+
+static struct rgb_comp_sel comp_sel_map[] = {
+	{DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
+	{DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
+	{DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
+	{DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
+	{DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
+	{DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
+	{DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
+	{DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
+};
+
+static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
+		       int *b_sel)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
+		if (comp_sel_map[i].drm_format == pix_fmt) {
+			*a_sel = comp_sel_map[i].a_sel;
+			*r_sel = comp_sel_map[i].r_sel;
+			*g_sel = comp_sel_map[i].g_sel;
+			*b_sel = comp_sel_map[i].b_sel;
+
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format)
+{
+	u32 val, mask;
+
+	switch (pix_format) {
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV12_10LE40:
+		ch->rtram_3buf_en = true;
+		ch->rtram_4line_en = false;
+		break;
+
+	default:
+		ch->rtram_3buf_en = true;
+		ch->rtram_4line_en = true;
+		break;
+	}
+
+	val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
+	val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
+	mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
+
+	ch->mode_ctrl &= ~mask;
+	ch->mode_ctrl |= (val & mask);
+
+	val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
+	val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
+	val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
+	mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
+
+	ch->rtram_ctrl &= ~mask;
+	ch->rtram_ctrl |= (val & mask);
+}
+
+static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
+				      const struct drm_format_info *format)
+{
+	int a_sel, r_sel, g_sel, b_sel;
+	bool uv_swap, y_uv_swap;
+
+	switch (format->format) {
+	case DRM_FORMAT_YVYU:
+		uv_swap = true;
+		y_uv_swap = true;
+		break;
+
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_NV21:
+		uv_swap = true;
+		y_uv_swap = false;
+		break;
+
+	case DRM_FORMAT_YUYV:
+		uv_swap = false;
+		y_uv_swap = true;
+		break;
+
+	default:
+		uv_swap = false;
+		y_uv_swap = false;
+		break;
+	}
+
+	dcss_dpr_uv_swap(ch, uv_swap);
+
+	dcss_dpr_y_uv_swap(ch, y_uv_swap);
+
+	if (!format->is_yuv) {
+		if (!to_comp_sel(format->format, &a_sel, &r_sel,
+				 &g_sel, &b_sel)) {
+			dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
+		} else {
+			dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
+		}
+	} else {
+		dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
+	}
+}
+
+static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
+{
+	switch (ch->ch_num) {
+	case 0:
+		switch (modifier) {
+		case DRM_FORMAT_MOD_LINEAR:
+			ch->tile = TILE_LINEAR;
+			break;
+		case DRM_FORMAT_MOD_VIVANTE_TILED:
+			ch->tile = TILE_GPU_STANDARD;
+			break;
+		case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC:
+			ch->tile = TILE_GPU_SUPER;
+			break;
+		default:
+			WARN_ON(1);
+			break;
+		}
+		break;
+	case 1:
+	case 2:
+		ch->tile = TILE_LINEAR;
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	ch->mode_ctrl &= ~TILE_TYPE_MASK;
+	ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
+}
+
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+			 const struct drm_format_info *format, u64 modifier)
+{
+	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+	ch->format = *format;
+	ch->use_dtrc = ch_num && modifier != DRM_FORMAT_MOD_LINEAR;
+
+	dcss_dpr_yuv_en(ch, format->is_yuv);
+
+	dcss_dpr_pix_size_set(ch, format);
+
+	dcss_dpr_setup_components(ch, format);
+
+	dcss_dpr_2plane_en(ch, format->num_planes == 2);
+
+	dcss_dpr_rtram_set(ch, format->format);
+
+	dcss_dpr_tile_set(ch, modifier);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
+{
+	int chnum;
+
+	for (chnum = 0; chnum < 3; chnum++) {
+		struct dcss_dpr_ch *ch = &dpr->ch[chnum];
+
+		if (ch->sys_ctrl_chgd) {
+			dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
+						 ch->sys_ctrl,
+						 ch->base_ofs +
+						 DCSS_DPR_SYSTEM_CTRL0);
+			ch->sys_ctrl_chgd = false;
+		}
+	}
+}
+
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
+{
+	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+	ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
+
+	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
+	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
+
+	if (rotation & DRM_MODE_ROTATE_90)
+		ch->frame_ctrl |= 1 << ROT_ENC_POS;
+	else if (rotation & DRM_MODE_ROTATE_180)
+		ch->frame_ctrl |= 2 << ROT_ENC_POS;
+	else if (rotation & DRM_MODE_ROTATE_270)
+		ch->frame_ctrl |= 3 << ROT_ENC_POS;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-drv.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+struct dcss_drv {
+	struct dcss_dev *dcss;
+	struct dcss_kms_dev *kms;
+
+	bool is_componentized;
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev)
+{
+	struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+	return mdrv ? mdrv->dcss : NULL;
+}
+
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev)
+{
+	struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+	return mdrv ? &mdrv->kms->base : NULL;
+}
+
+static int dcss_drv_init(struct device *dev, bool componentized)
+{
+	struct dcss_drv *mdrv;
+	int err = 0;
+
+	mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
+	if (!mdrv)
+		return -ENOMEM;
+
+	mdrv->is_componentized = componentized;
+
+	mdrv->dcss = dcss_dev_create(dev, componentized);
+	if (IS_ERR(mdrv->dcss)) {
+		err = PTR_ERR(mdrv->dcss);
+		goto err;
+	}
+
+	dev_set_drvdata(dev, mdrv);
+
+	mdrv->kms = dcss_kms_attach(mdrv->dcss, componentized);
+	if (IS_ERR(mdrv->kms)) {
+		err = PTR_ERR(mdrv->kms);
+		goto dcss_shutoff;
+	}
+
+	return 0;
+
+dcss_shutoff:
+	dcss_dev_destroy(mdrv->dcss);
+
+	dev_set_drvdata(dev, NULL);
+
+err:
+	devm_kfree(dev, mdrv);
+	return err;
+}
+
+static void dcss_drv_deinit(struct device *dev, bool componentized)
+{
+	struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+	if (!mdrv)
+		return;
+
+	dcss_kms_detach(mdrv->kms, componentized);
+	dcss_dev_destroy(mdrv->dcss);
+
+	dev_set_drvdata(dev, NULL);
+}
+
+static int dcss_drv_bind(struct device *dev)
+{
+	return dcss_drv_init(dev, true);
+}
+
+static void dcss_drv_unbind(struct device *dev)
+{
+	return dcss_drv_deinit(dev, true);
+}
+
+static const struct component_master_ops dcss_master_ops = {
+	.bind	= dcss_drv_bind,
+	.unbind	= dcss_drv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int dcss_drv_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct component_match *match = NULL;
+	struct device_node *remote;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	remote = of_graph_get_remote_node(dev->of_node, 0, 0);
+	if (!remote)
+		return -ENODEV;
+
+	if (of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi")) {
+		of_node_put(remote);
+		return dcss_drv_init(dev, false);
+	}
+
+	drm_of_component_match_add(dev, &match, compare_of, remote);
+	of_node_put(remote);
+
+	return component_master_add_with_match(dev, &dcss_master_ops, match);
+}
+
+static int dcss_drv_platform_remove(struct platform_device *pdev)
+{
+	struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
+
+	if (mdrv->is_componentized)
+		component_master_del(&pdev->dev, &dcss_master_ops);
+	else
+		dcss_drv_deinit(&pdev->dev, false);
+
+	return 0;
+}
+
+static struct dcss_type_data dcss_types[] = {
+	[DCSS_IMX8MQ] = {
+		.name = "DCSS_IMX8MQ",
+		.blkctl_ofs = 0x2F000,
+		.ctxld_ofs = 0x23000,
+		.dtg_ofs = 0x20000,
+		.rdsrc_ofs = 0x22000,
+		.wrscl_ofs = 0x21000,
+		.scaler_ofs = 0x1C000,
+		.ss_ofs = 0x1B000,
+		.dpr_ofs = 0x18000,
+		.dec400d_ofs = 0x15000,
+		.hdr10_ofs = 0x00000,
+		.dtrc_ofs = 0x16000,
+	},
+};
+
+static const struct of_device_id dcss_of_match[] = {
+	{ .compatible = "nxp,imx8mq-dcss", .data = &dcss_types[DCSS_IMX8MQ], },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, dcss_of_match);
+
+static const struct dev_pm_ops dcss_dev_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(dcss_dev_suspend, dcss_dev_resume)
+	SET_RUNTIME_PM_OPS(dcss_dev_runtime_suspend,
+			   dcss_dev_runtime_resume, NULL)
+};
+
+static struct platform_driver dcss_platform_driver = {
+	.probe	= dcss_drv_platform_probe,
+	.remove	= dcss_drv_platform_remove,
+	.driver	= {
+		.name = "imx-dcss",
+		.of_match_table	= dcss_of_match,
+		.pm = &dcss_dev_pm,
+	},
+};
+
+module_platform_driver(dcss_platform_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_DESCRIPTION("DCSS driver for i.MX8MQ");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dtg.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dtg.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_DTG_TC_CONTROL_STATUS			0x00
+#define   CH3_EN					BIT(0)
+#define   CH2_EN					BIT(1)
+#define   CH1_EN					BIT(2)
+#define   OVL_DATA_MODE					BIT(3)
+#define   BLENDER_VIDEO_ALPHA_SEL			BIT(7)
+#define   DTG_START					BIT(8)
+#define   DBY_MODE_EN					BIT(9)
+#define   CH1_ALPHA_SEL					BIT(10)
+#define   CSS_PIX_COMP_SWAP_POS				12
+#define   CSS_PIX_COMP_SWAP_MASK			GENMASK(14, 12)
+#define   DEFAULT_FG_ALPHA_POS				24
+#define   DEFAULT_FG_ALPHA_MASK				GENMASK(31, 24)
+#define DCSS_DTG_TC_DTG					0x04
+#define DCSS_DTG_TC_DISP_TOP				0x08
+#define DCSS_DTG_TC_DISP_BOT				0x0C
+#define DCSS_DTG_TC_CH1_TOP				0x10
+#define DCSS_DTG_TC_CH1_BOT				0x14
+#define DCSS_DTG_TC_CH2_TOP				0x18
+#define DCSS_DTG_TC_CH2_BOT				0x1C
+#define DCSS_DTG_TC_CH3_TOP				0x20
+#define DCSS_DTG_TC_CH3_BOT				0x24
+#define   TC_X_POS					0
+#define   TC_X_MASK					GENMASK(12, 0)
+#define   TC_Y_POS					16
+#define   TC_Y_MASK					GENMASK(28, 16)
+#define DCSS_DTG_TC_CTXLD				0x28
+#define   TC_CTXLD_DB_Y_POS				0
+#define   TC_CTXLD_DB_Y_MASK				GENMASK(12, 0)
+#define   TC_CTXLD_SB_Y_POS				16
+#define   TC_CTXLD_SB_Y_MASK				GENMASK(28, 16)
+#define DCSS_DTG_TC_CH1_BKRND				0x2C
+#define DCSS_DTG_TC_CH2_BKRND				0x30
+#define   BKRND_R_Y_COMP_POS				20
+#define   BKRND_R_Y_COMP_MASK				GENMASK(29, 20)
+#define   BKRND_G_U_COMP_POS				10
+#define   BKRND_G_U_COMP_MASK				GENMASK(19, 10)
+#define   BKRND_B_V_COMP_POS				0
+#define   BKRND_B_V_COMP_MASK				GENMASK(9, 0)
+#define DCSS_DTG_BLENDER_DBY_RANGEINV			0x38
+#define DCSS_DTG_BLENDER_DBY_RANGEMIN			0x3C
+#define DCSS_DTG_BLENDER_DBY_BDP			0x40
+#define DCSS_DTG_BLENDER_BKRND_I			0x44
+#define DCSS_DTG_BLENDER_BKRND_P			0x48
+#define DCSS_DTG_BLENDER_BKRND_T			0x4C
+#define DCSS_DTG_LINE0_INT				0x50
+#define DCSS_DTG_LINE1_INT				0x54
+#define DCSS_DTG_BG_ALPHA_DEFAULT			0x58
+#define DCSS_DTG_INT_STATUS				0x5C
+#define DCSS_DTG_INT_CONTROL				0x60
+#define DCSS_DTG_TC_CH3_BKRND				0x64
+#define DCSS_DTG_INT_MASK				0x68
+#define   LINE0_IRQ					BIT(0)
+#define   LINE1_IRQ					BIT(1)
+#define   LINE2_IRQ					BIT(2)
+#define   LINE3_IRQ					BIT(3)
+#define DCSS_DTG_LINE2_INT				0x6C
+#define DCSS_DTG_LINE3_INT				0x70
+#define DCSS_DTG_DBY_OL					0x74
+#define DCSS_DTG_DBY_BL					0x78
+#define DCSS_DTG_DBY_EL					0x7C
+
+struct dcss_dtg {
+	struct device *dev;
+	struct dcss_ctxld *ctxld;
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	u32 ctx_id;
+
+	bool in_use;
+	bool hdmi_output;
+
+	u32 dis_ulc_x;
+	u32 dis_ulc_y;
+
+	u32 control_status;
+	u32 alpha;
+
+	int ctxld_kick_irq;
+	bool ctxld_kick_irq_en;
+
+	struct clk *pix_clk;
+	struct clk *pll_src_clk;
+	struct clk *pll_phy_ref_clk;
+
+	/*
+	 * This will be passed on by DRM CRTC so that we can signal when DTG has
+	 * been successfully stopped. Otherwise, any modesetting while DTG is
+	 * still ON may result in unpredictable behavior.
+	 */
+	struct completion *dis_completion;
+};
+
+static void dcss_dtg_write(struct dcss_dtg *dtg, u32 val, u32 ofs)
+{
+	if (!dtg->in_use)
+		dcss_writel(val, dtg->base_reg + ofs);
+
+	dcss_ctxld_write(dtg->ctxld, dtg->ctx_id, val, dtg->base_ofs + ofs);
+}
+
+static irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
+{
+	struct dcss_dtg *dtg = data;
+	u32 status;
+
+	status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+	if (!(status & LINE0_IRQ))
+		return IRQ_HANDLED;
+
+	dcss_ctxld_kick(dtg->ctxld);
+
+	dcss_writel(status & LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+
+	return IRQ_HANDLED;
+}
+
+static int dcss_dtg_irq_config(struct dcss_dtg *dtg,
+			       struct platform_device *pdev)
+{
+	int ret;
+
+	dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
+	if (dtg->ctxld_kick_irq < 0) {
+		dev_err(dtg->dev, "dtg: can't get line2 irq number\n");
+		return dtg->ctxld_kick_irq;
+	}
+
+	dcss_update(0, LINE0_IRQ | LINE1_IRQ,
+		    dtg->base_reg + DCSS_DTG_INT_MASK);
+
+	ret = devm_request_irq(dtg->dev, dtg->ctxld_kick_irq,
+			       dcss_dtg_irq_handler,
+			       IRQF_TRIGGER_HIGH,
+			       "dcss_ctxld_kick", dtg);
+	if (ret) {
+		dev_err(dtg->dev, "dtg: irq request failed.\n");
+		return ret;
+	}
+
+	disable_irq(dtg->ctxld_kick_irq);
+
+	dtg->ctxld_kick_irq_en = false;
+
+	return 0;
+}
+
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base)
+{
+	int ret = 0;
+	struct dcss_dtg *dtg;
+
+	dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL);
+	if (!dtg)
+		return -ENOMEM;
+
+	dcss->dtg = dtg;
+	dtg->dev = dcss->dev;
+	dtg->ctxld = dcss->ctxld;
+	dtg->hdmi_output = dcss->hdmi_output;
+
+	dtg->base_reg = devm_ioremap(dcss->dev, dtg_base, SZ_4K);
+	if (!dtg->base_reg) {
+		dev_err(dcss->dev, "dtg: unable to remap dtg base\n");
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	dtg->base_ofs = dtg_base;
+	dtg->ctx_id = CTX_DB;
+
+	dtg->pix_clk = dcss->pix_clk;
+	dtg->pll_src_clk = dcss->pll_src_clk;
+	dtg->pll_phy_ref_clk = dcss->pll_phy_ref_clk;
+
+	dtg->alpha = 255;
+
+	dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
+		((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
+
+	ret = dcss_dtg_irq_config(dtg, to_platform_device(dcss->dev));
+	if (ret)
+		goto err_irq;
+
+	return 0;
+
+err_irq:
+	devm_iounmap(dtg->dev, dtg->base_reg);
+
+err_ioremap:
+	devm_kfree(dtg->dev, dtg);
+
+	return ret;
+}
+
+void dcss_dtg_exit(struct dcss_dtg *dtg)
+{
+	/* stop DTG */
+	dcss_writel(DTG_START, dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+	devm_free_irq(dtg->dev, dtg->ctxld_kick_irq, dtg);
+
+	if (dtg->base_reg)
+		devm_iounmap(dtg->dev, dtg->base_reg);
+
+	devm_kfree(dtg->dev, dtg);
+}
+
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm)
+{
+	u16 dtg_lrc_x, dtg_lrc_y;
+	u16 dis_ulc_x, dis_ulc_y;
+	u16 dis_lrc_x, dis_lrc_y;
+	u32 sb_ctxld_trig, db_ctxld_trig;
+	u32 pixclock = vm->pixelclock;
+	u32 actual_clk;
+
+	dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+		    vm->hactive - 1;
+	dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+		    vm->vactive - 1;
+	dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+	dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
+	dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+	dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+		    vm->vactive - 1;
+
+	clk_disable_unprepare(dtg->pix_clk);
+	if (dtg->hdmi_output) {
+		int err;
+
+		clk_disable_unprepare(dtg->pll_src_clk);
+		err = clk_set_parent(dtg->pll_src_clk, dtg->pll_phy_ref_clk);
+		if (err < 0)
+			dev_warn(dtg->dev, "clk_set_parent() returned %d", err);
+		clk_prepare_enable(dtg->pll_src_clk);
+	}
+	clk_set_rate(dtg->pix_clk, vm->pixelclock);
+	clk_prepare_enable(dtg->pix_clk);
+
+	actual_clk = clk_get_rate(dtg->pix_clk);
+	if (pixclock != actual_clk) {
+		dev_info(dtg->dev,
+			 "Pixel clock set to %u kHz instead of %u kHz.\n",
+			 (actual_clk / 1000), (pixclock / 1000));
+	}
+
+	dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
+		       DCSS_DTG_TC_DTG);
+	dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
+		       DCSS_DTG_TC_DISP_TOP);
+	dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
+		       DCSS_DTG_TC_DISP_BOT);
+
+	dtg->dis_ulc_x = dis_ulc_x;
+	dtg->dis_ulc_y = dis_ulc_y;
+
+	sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
+							TC_CTXLD_SB_Y_MASK;
+	db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
+							TC_CTXLD_DB_Y_MASK;
+
+	dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);
+
+	/* vblank trigger */
+	dcss_dtg_write(dtg, 0, DCSS_DTG_LINE1_INT);
+
+	/* CTXLD trigger */
+	dcss_dtg_write(dtg, ((90 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE0_INT);
+}
+
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+			    int px, int py, int pw, int ph)
+{
+	u16 p_ulc_x, p_ulc_y;
+	u16 p_lrc_x, p_lrc_y;
+
+	p_ulc_x = dtg->dis_ulc_x + px;
+	p_ulc_y = dtg->dis_ulc_y + py;
+	p_lrc_x = p_ulc_x + pw;
+	p_lrc_y = p_ulc_y + ph;
+
+	if (!px && !py && !pw && !ph) {
+		dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+		dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+	} else {
+		dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
+			       DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+		dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
+			       DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+	}
+}
+
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha)
+{
+	if (ch_num)
+		return false;
+
+	return alpha != dtg->alpha;
+}
+
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+			      const struct drm_format_info *format, int alpha)
+{
+	u32 alpha_val;
+
+	/* we care about alpha only when channel 0 is concerned */
+	if (ch_num)
+		return;
+
+	alpha_val = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
+
+	/*
+	 * Use global alpha if pixel format does not have alpha channel or the
+	 * user explicitly chose to use global alpha (i.e. alpha is not OPAQUE).
+	 */
+	if (!format->has_alpha || alpha != 255) {
+		dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+		dtg->control_status |= alpha_val;
+	} else { /* use per-pixel alpha otherwise */
+		dtg->control_status |= CH1_ALPHA_SEL;
+	}
+
+	dtg->alpha = alpha;
+}
+
+void dcss_dtg_css_set(struct dcss_dtg *dtg, bool out_is_yuv)
+{
+	dtg->control_status &= ~CSS_PIX_COMP_SWAP_MASK;
+
+	if (out_is_yuv)
+		return;
+
+	dtg->control_status |=
+			(0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
+}
+
+static void dcss_dtg_disable_callback(void *data)
+{
+	struct dcss_dtg *dtg = data;
+
+	dtg->control_status &= ~DTG_START;
+
+	dcss_writel(dtg->control_status,
+		    dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+	dtg->in_use = false;
+
+	complete(dtg->dis_completion);
+}
+
+void dcss_dtg_enable(struct dcss_dtg *dtg, bool en,
+		     struct completion *dis_completion)
+{
+	if (!en) {
+		dtg->dis_completion = dis_completion;
+		dcss_ctxld_register_dtg_disable_cb(dtg->ctxld,
+						   dcss_dtg_disable_callback,
+						   dtg);
+		return;
+	}
+
+	dtg->dis_completion = NULL;
+
+	dtg->control_status |= DTG_START;
+
+	dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+	dtg->in_use = true;
+}
+
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg)
+{
+	return dtg->in_use;
+}
+
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en)
+{
+	u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
+	u32 control_status;
+
+	control_status = dtg->control_status & ~ch_en_map[ch_num];
+	control_status |= en ? ch_en_map[ch_num] : 0;
+
+	if (dtg->control_status != control_status)
+		dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+	dtg->control_status = control_status;
+}
+
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+	u32 status;
+	u32 mask = en ? LINE1_IRQ : 0;
+
+	if (en) {
+		status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+		dcss_writel(status & LINE1_IRQ,
+			    dtg->base_reg + DCSS_DTG_INT_CONTROL);
+	}
+
+	dcss_update(mask, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+}
+
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+	u32 status;
+	u32 mask = en ? LINE0_IRQ : 0;
+
+	if (en) {
+		status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+		if (!dtg->ctxld_kick_irq_en) {
+			dcss_writel(status & LINE0_IRQ,
+				    dtg->base_reg + DCSS_DTG_INT_CONTROL);
+			enable_irq(dtg->ctxld_kick_irq);
+			dtg->ctxld_kick_irq_en = true;
+			goto mask_unmask;
+		}
+
+		return;
+	}
+
+	if (!dtg->ctxld_kick_irq_en)
+		return;
+
+	disable_irq_nosync(dtg->ctxld_kick_irq);
+	dtg->ctxld_kick_irq_en = false;
+
+mask_unmask:
+	dcss_update(mask, LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+}
+
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg)
+{
+	dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+}
+
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg)
+{
+	return !!(dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS) & LINE1_IRQ);
+}
+
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-dtrc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-dtrc.c
@@ -0,0 +1,514 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_rect.h>
+
+#include "dcss-dev.h"
+
+#define DTRC_F0_OFS			0x00
+#define DTRC_F1_OFS			0x60
+
+#define DCSS_DTRC_DYDSADDR			0x00
+#define DCSS_DTRC_DCDSADDR			0x04
+#define DCSS_DTRC_DYTSADDR			0x08
+#define DCSS_DTRC_DCTSADDR			0x0C
+#define DCSS_DTRC_SIZE				0x10
+#define   FRAME_WIDTH_POS			0
+#define   FRAME_WIDTH_MASK			GENMASK(9, 0)
+#define   FRAME_HEIGHT_POS			16
+#define   FRAME_HEIGHT_MASK			GENMASK(25, 16)
+#define DCSS_DTRC_SYSSA				0x14
+#define DCSS_DTRC_SYSEA				0x18
+#define DCSS_DTRC_SUVSSA			0x1C
+#define DCSS_DTRC_SUVSEA			0x20
+#define DCSS_DTRC_CROPORIG			0x24
+#define DCSS_DTRC_CROPSIZE			0x28
+#define   CROP_HEIGHT_POS			16
+#define   CROP_HEIGHT_MASK			GENMASK(28, 16)
+#define   CROP_WIDTH_POS			0
+#define   CROP_WIDTH_MASK			GENMASK(12, 0)
+#define DCSS_DTRC_DCTL				0x2C
+#define   CROPPING_EN				BIT(18)
+#define   COMPRESSION_DIS			BIT(17)
+#define   PIX_DEPTH_8BIT_EN			BIT(1)
+#define   CONFIG_READY				BIT(0)
+#define DCSS_DTRC_DYDSADDR_EXT			0x30
+#define DCSS_DTRC_DCDSADDR_EXT			0x34
+#define DCSS_DTRC_DYTSADDR_EXT			0x38
+#define DCSS_DTRC_DCTSADDR_EXT			0x3C
+#define DCSS_DTRC_SYSSA_EXT			0x40
+#define DCSS_DTRC_SYSEA_EXT			0x44
+#define DCSS_DTRC_SUVSSA_EXT			0x48
+#define DCSS_DTRC_SUVSEA_EXT			0x4C
+
+#define DCSS_DTRC_INTEN				0xC0
+#define DCSS_DTRC_FDINTR			0xC4
+#define DCSS_DTRC_DTCTRL			0xC8
+#define   CURRENT_FRAME				BIT(31)
+#define   ADDRESS_ID_ENABLE			BIT(30)
+#define   ENDIANNESS_10BIT			BIT(29)
+#define   MERGE_ARID_ENABLE			BIT(28)
+#define   NON_G1_2_SWAP_MODE_POS		24
+#define   NON_G1_2_SWAP_MODE_MASK		GENMASK(27, 24)
+#define   TABLE_DATA_SWAP_POS			20
+#define   TABLE_DATA_SWAP_MASK			GENMASK(23, 20)
+#define   TILED_SWAP_POS			16
+#define   TILED_SWAP_MASK			GENMASK(19, 16)
+#define   RASTER_SWAP_POS			12
+#define   RASTER_SWAP_MASK			GENMASK(15, 12)
+#define   BURST_LENGTH_POS			4
+#define   BURST_LENGTH_MASK			GENMASK(11, 4)
+#define   G1_TILED_DATA_EN			BIT(3)
+#define   HOT_RESET				BIT(2)
+#define   ARIDR_MODE_DETILE			0
+#define   ARIDR_MODE_BYPASS			2
+#define DCSS_DTRC_ARIDR				0xCC
+#define DCSS_DTRC_DTID2DDR			0xD0
+#define DCSS_DTRC_CONFIG			0xD4
+#define DCSS_DTRC_VER				0xD8
+#define DCSS_DTRC_PFCTRL			0xF0
+#define DCSS_DTRC_PFCR				0xF4
+#define DCSS_DTRC_TOCR				0xF8
+
+struct dcss_dtrc_ch {
+	struct dcss_dtrc *dtrc;
+
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	u32 xres;
+	u32 yres;
+	u32 pix_format;
+	u64 format_modifier;
+	u32 y_dec_ofs;
+	u32 uv_dec_ofs;
+
+	int curr_frame;
+
+	u32 dctl;
+
+	bool bypass;
+	bool running;
+
+	int irq;
+	int ch_num;
+};
+
+struct dcss_dtrc {
+	struct device *dev;
+
+	struct dcss_dtrc_ch ch[2];
+
+	u32 ctx_id;
+	struct dcss_ctxld *ctxld;
+};
+
+static irqreturn_t dcss_dtrc_irq_handler(int irq, void *data)
+{
+	struct dcss_dtrc_ch *ch = data;
+	u32 b0, b1, curr_bank;
+
+	b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+	b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+	curr_bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+	dcss_update(1, 1, ch->base_reg + DCSS_DTRC_FDINTR);
+
+	return IRQ_HANDLED;
+}
+
+static int dcss_dtrc_irq_config(struct dcss_dtrc *dtrc, int ch_num)
+{
+	struct platform_device *pdev = to_platform_device(dtrc->dev);
+	struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num];
+	char irq_name[20];
+	int ret;
+
+	sprintf(irq_name, "dtrc_ch%d", ch_num + 1);
+	irq_name[8] = 0;
+
+	ch->irq = platform_get_irq_byname(pdev, irq_name);
+	if (ch->irq < 0) {
+		dev_err(dtrc->dev, "dtrc: can't get DTRC irq\n");
+		return ch->irq;
+	}
+
+	ret = devm_request_irq(dtrc->dev, ch->irq,
+			       dcss_dtrc_irq_handler,
+			       IRQF_TRIGGER_HIGH,
+			       "dcss-dtrc", ch);
+	if (ret) {
+		dev_err(dtrc->dev, "dtrc: irq request failed.\n");
+		return ret;
+	}
+
+	dcss_writel(1, ch->base_reg + DCSS_DTRC_INTEN);
+
+	return 0;
+}
+
+static int dcss_dtrc_ch_init_all(struct dcss_dtrc *dtrc, u32 dtrc_base)
+{
+	struct dcss_dtrc_ch *ch;
+	int i, ret;
+
+	for (i = 0; i < 2; i++) {
+		ch = &dtrc->ch[i];
+
+		ch->base_ofs = dtrc_base + i * 0x1000;
+
+		ch->base_reg = devm_ioremap(dtrc->dev, ch->base_ofs, SZ_4K);
+		if (!ch->base_reg) {
+			dev_err(dtrc->dev, "dtrc: unable to remap ch base\n");
+			return -ENOMEM;
+		}
+
+		ch->ch_num = i;
+		ch->dtrc = dtrc;
+
+		ret = dcss_dtrc_irq_config(dtrc, i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void dcss_dtrc_write(struct dcss_dtrc_ch *ch, u32 val, u32 ofs)
+{
+	dcss_ctxld_write(ch->dtrc->ctxld, ch->dtrc->ctx_id,
+			 val, ch->base_ofs + ofs);
+}
+
+static void dcss_dtrc_write_irqsafe(struct dcss_dtrc_ch *ch, u32 val, u32 ofs)
+{
+	dcss_ctxld_write_irqsafe(ch->dtrc->ctxld, ch->dtrc->ctx_id,
+				 val, ch->base_ofs + ofs);
+}
+
+int dcss_dtrc_init(struct dcss_dev *dcss, unsigned long dtrc_base)
+{
+	struct dcss_dtrc *dtrc;
+
+	dtrc = devm_kzalloc(dcss->dev, sizeof(*dtrc), GFP_KERNEL);
+	if (!dtrc)
+		return -ENOMEM;
+
+	dcss->dtrc = dtrc;
+	dtrc->dev = dcss->dev;
+	dtrc->ctxld = dcss->ctxld;
+	dtrc->ctx_id = CTX_SB_HP;
+
+	if (dcss_dtrc_ch_init_all(dtrc, dtrc_base)) {
+		struct dcss_dtrc_ch *ch;
+		int i;
+
+		for (i = 0; i < 2; i++) {
+			ch = &dtrc->ch[i];
+
+			if (ch->irq)
+				devm_free_irq(dtrc->dev, ch->irq, ch);
+
+			if (ch->base_reg)
+				devm_iounmap(dtrc->dev, ch->base_reg);
+		}
+
+		devm_kfree(dtrc->dev, dtrc);
+
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dcss_dtrc_exit(struct dcss_dtrc *dtrc)
+{
+	int ch_no;
+
+	for (ch_no = 0; ch_no < 2; ch_no++) {
+		struct dcss_dtrc_ch *ch = &dtrc->ch[ch_no];
+
+		if (ch->base_reg) {
+			/* reset the module to default */
+			dcss_writel(HOT_RESET,
+				    ch->base_reg + DCSS_DTRC_DTCTRL);
+			devm_iounmap(dtrc->dev, ch->base_reg);
+		}
+	}
+
+	devm_kfree(dtrc->dev, dtrc);
+}
+
+void dcss_dtrc_bypass(struct dcss_dtrc *dtrc, int ch_num)
+{
+	struct dcss_dtrc_ch *ch;
+
+	if (ch_num == 0)
+		return;
+
+	ch = &dtrc->ch[ch_num - 1];
+
+	if (ch->bypass)
+		return;
+
+	dcss_dtrc_write(ch, ARIDR_MODE_BYPASS, DCSS_DTRC_DTCTRL);
+	dcss_dtrc_write(ch, 0, DCSS_DTRC_DYTSADDR);
+	dcss_dtrc_write(ch, 0, DCSS_DTRC_DCTSADDR);
+	dcss_dtrc_write(ch, 0x0f0e0100, DCSS_DTRC_ARIDR);
+	dcss_dtrc_write(ch, 0x0f0e, DCSS_DTRC_DTID2DDR);
+
+	ch->bypass = true;
+}
+
+void dcss_dtrc_addr_set(struct dcss_dtrc *dtrc, int ch_num,
+			u32 p1_ba, u32 p2_ba, uint64_t dec_table_ofs)
+{
+	struct dcss_dtrc_ch *ch;
+
+	if (ch_num == 0)
+		return;
+
+	ch = &dtrc->ch[ch_num - 1];
+
+	dcss_dtrc_write(ch, p1_ba, DCSS_DTRC_DYDSADDR);
+	dcss_dtrc_write(ch, p2_ba, DCSS_DTRC_DCDSADDR);
+
+	dcss_dtrc_write(ch, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
+	dcss_dtrc_write(ch, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
+
+	if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) {
+		ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
+		ch->uv_dec_ofs = dec_table_ofs >> 32;
+
+		dcss_dtrc_write(ch, p1_ba + ch->y_dec_ofs,
+				DCSS_DTRC_DYTSADDR);
+		dcss_dtrc_write(ch, p1_ba + ch->uv_dec_ofs,
+				DCSS_DTRC_DCTSADDR);
+		dcss_dtrc_write(ch, p1_ba + ch->y_dec_ofs,
+				DTRC_F1_OFS + DCSS_DTRC_DYTSADDR);
+		dcss_dtrc_write(ch, p1_ba + ch->uv_dec_ofs,
+				DTRC_F1_OFS + DCSS_DTRC_DCTSADDR);
+	}
+
+	ch->bypass = false;
+}
+
+void dcss_dtrc_set_res(struct dcss_dtrc *dtrc, int ch_num,
+		       struct drm_plane_state *state, u32 *dtrc_w, u32 *dtrc_h)
+{
+	struct drm_framebuffer *fb = state->fb;
+	u32 pixel_format = fb->format->format;
+	struct dcss_dtrc_ch *ch;
+	u32 frame_height, frame_width;
+	u32 crop_w, crop_h, crop_orig_w, crop_orig_h;
+	int bank;
+	u32 old_xres, old_yres, xres, yres;
+	u32 x1, y1, x2, y2;
+	u32 pix_depth;
+	u16 width_align = 0;
+
+	if (ch_num == 0)
+		return;
+
+	ch = &dtrc->ch[ch_num - 1];
+
+	bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+	ch->pix_format = pixel_format;
+	ch->format_modifier = fb->modifier;
+
+	pix_depth = ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 10 : 8;
+
+	old_xres = state->src_w >> 16;
+	old_yres = state->src_h >> 16;
+
+	x1 = (state->src.x1 >> 16) & ~1;
+	y1 = (state->src.y1 >> 16) & ~1;
+	x2 = state->src.x2 >> 16;
+	y2 = state->src.y2 >> 16;
+
+	xres = x2 - x1;
+	yres = y2 - y1;
+
+	frame_height = ((old_yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
+	frame_width = ((old_xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
+
+	dcss_dtrc_write(ch, frame_height | frame_width,
+			DTRC_F1_OFS * bank + DCSS_DTRC_SIZE);
+
+	dcss_dtrc_write(ch, frame_height | frame_width,
+			DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_SIZE);
+
+	/*
+	 * Image original size is aligned:
+	 *   - 128 pixels for width (8-bit) or 256 (10-bit);
+	 *   - 8 lines for height;
+	 */
+	width_align = ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 0xff : 0x7f;
+
+	if (xres == old_xres && !(xres & width_align) &&
+	    yres == old_yres && !(yres & 0xf)) {
+		ch->dctl &= ~CROPPING_EN;
+		goto exit;
+	}
+
+	/* align the image size: down align for compressed formats */
+	if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && x1)
+		xres = xres & ~width_align;
+	else
+		xres = (xres + width_align) & ~width_align;
+
+	if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && y1)
+		yres = yres & ~0xf;
+	else
+		yres = (yres + 0xf) & ~0xf;
+
+	crop_orig_w = (x1 << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+	crop_orig_h = (y1 << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+	dcss_dtrc_write(ch, crop_orig_w | crop_orig_h,
+			DCSS_DTRC_CROPORIG);
+	dcss_dtrc_write(ch, crop_orig_w | crop_orig_h,
+			DTRC_F1_OFS + DCSS_DTRC_CROPORIG);
+
+	crop_w = (xres << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+	crop_h = (yres << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+	dcss_dtrc_write(ch, crop_w | crop_h,
+			DTRC_F1_OFS * bank + DCSS_DTRC_CROPSIZE);
+	dcss_dtrc_write(ch, crop_w | crop_h,
+			DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_CROPSIZE);
+
+	ch->dctl |= CROPPING_EN;
+
+exit:
+	dcss_dtrc_write(ch, xres * yres * pix_depth / 8,
+			DCSS_DTRC_SYSEA);
+	dcss_dtrc_write(ch, xres * yres * pix_depth / 8,
+			DTRC_F1_OFS + DCSS_DTRC_SYSEA);
+
+	dcss_dtrc_write(ch, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+			DCSS_DTRC_SUVSEA);
+	dcss_dtrc_write(ch, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+			DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
+
+	*dtrc_w = xres;
+	*dtrc_h = yres;
+
+	if (ch->running)
+		return;
+
+	dcss_dtrc_write(ch, 0x0, DCSS_DTRC_SYSSA);
+	dcss_dtrc_write(ch, 0x0, DTRC_F1_OFS + DCSS_DTRC_SYSSA);
+
+	dcss_dtrc_write(ch, 0x10000000, DCSS_DTRC_SUVSSA);
+	dcss_dtrc_write(ch, 0x10000000, DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
+}
+
+void dcss_dtrc_enable(struct dcss_dtrc *dtrc, int ch_num, bool enable)
+{
+	struct dcss_dtrc_ch *ch;
+	int curr_frame;
+	u32 fdctl, dtctrl;
+
+	if (ch_num == 0)
+		return;
+
+	ch = &dtrc->ch[ch_num - 1];
+
+	if (ch->bypass)
+		return;
+
+	if (!enable) {
+		ch->running = false;
+		return;
+	}
+
+	if (ch->running)
+		return;
+
+	dcss_update(HOT_RESET, HOT_RESET, ch->base_reg + DCSS_DTRC_DTCTRL);
+	while (dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) & HOT_RESET)
+		usleep_range(100, 200);
+
+	dcss_dtrc_write(ch, 0x0f0e0100,
+			DCSS_DTRC_ARIDR);
+	dcss_dtrc_write(ch, 0x0f0e,
+			DCSS_DTRC_DTID2DDR);
+
+	dtctrl = ADDRESS_ID_ENABLE | MERGE_ARID_ENABLE |
+		 ((0xF << TABLE_DATA_SWAP_POS) & TABLE_DATA_SWAP_MASK) |
+		 ((0x10 << BURST_LENGTH_POS) & BURST_LENGTH_MASK);
+
+	if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G1_TILED)
+		dtctrl |= G1_TILED_DATA_EN;
+
+	dcss_dtrc_write(ch, dtctrl, DCSS_DTRC_DTCTRL);
+
+	curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+	fdctl = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS);
+
+	fdctl |= ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 0 : PIX_DEPTH_8BIT_EN;
+
+	if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
+		fdctl |= COMPRESSION_DIS;
+
+	dcss_dtrc_write(ch, fdctl,
+			(curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+	dcss_dtrc_write(ch, fdctl | CONFIG_READY,
+			curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+
+	ch->curr_frame = curr_frame;
+	ch->dctl = fdctl;
+	ch->running = true;
+}
+
+bool dcss_dtrc_ch_running(struct dcss_dtrc *dtrc, int ch_num)
+{
+	struct dcss_dtrc_ch *ch;
+
+	if (ch_num == 0)
+		return false;
+
+	ch = &dtrc->ch[ch_num - 1];
+
+	return ch->running;
+}
+
+bool dcss_dtrc_is_running(struct dcss_dtrc *dtrc)
+{
+	return dtrc->ch[0].running || dtrc->ch[1].running;
+}
+
+static void dcss_dtrc_ch_switch_banks(struct dcss_dtrc *dtrc, int dtrc_ch)
+{
+	struct dcss_dtrc_ch *ch = &dtrc->ch[dtrc_ch];
+	u32 b0, b1;
+
+	if (!ch->running)
+		return;
+
+	b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+	b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+
+	ch->curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+	dcss_dtrc_write_irqsafe(ch, ch->dctl | CONFIG_READY,
+				(ch->curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+}
+
+void dcss_dtrc_switch_banks(struct dcss_dtrc *dtrc)
+{
+	dcss_dtrc_ch_switch_banks(dtrc, 0);
+	dcss_dtrc_ch_switch_banks(dtrc, 1);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __DCSS_HDR10_TABLES_H__
+#define __DCSS_HDR10_TABLES_H__
+
+/*
+ * Table descriptor (64 bit) contains flags with identify to which
+ * input/output configurations' combinations the table is applied. Choosing the
+ * right CSC depends on both output/input pipe configuration.
+ *
+ * Bit 0-2: Table type
+ *	* LUT  - bit 0
+ *	* CSCA - bit 1 (CSC for output pipe)
+ *	* CSCB - bit 2 (not used for output pipe)
+ * Bit 3: Pipe type
+ *	* Input - unset
+ *	* Output - set
+ * Bit 4-5: Input pipe bits-per-component
+ *	* 8 bpc  - bit 4
+ *	* 10 bpc - bit 5
+ * Bit 6-7: Input pipe colorspace
+ *	* RGB - bit 6
+ *	* YUV - bit 7
+ * Bit 8-12: Input pipe nonlinearity
+ *	* REC2084    - bit 8
+ *	* REC709     - bit 9
+ *	* BT1886     - bit 10
+ *	* REC2100HLG - bit 11
+ *	* SRGB       - bit 12
+ * Bit 13-14: Input pipe pixel range
+ *	* Limited - bit 13
+ *	* Full    - bit 14
+ * Bit 15-19: Input pipe gamut
+ *	* REC2020 - bit 15
+ *	* REC709  - bit 16
+ *	* REC601_NTSC - bit 17
+ *	* REC601_PAL  - bit 18
+ *	* ADOBE_RGB   - bit 19
+ * Bit 20-21: Output pipe bits-per-component (see above)
+ * Bit 22-23: Output pipe colorspace (see above)
+ * Bit 24-28: Output pipe nonlinearity (see above)
+ * Bit 29-30: Ouptut pipe pixel range (see above)
+ * Bit 31-35: Output pipe gamut (see above)
+ */
+
+static u32 dcss_hdr10_tables[] = {
+	/* table descriptor */
+	0x68effbe9, 0xf,
+	/* table length */
+	0x400,
+	/* table data */
+	0x552, 0x153, 0x10ef, 0x54, 0x2fd, 0x92d, 0x208d, 0x14, 0xbe, 0x213, 0x412,
+	0x6ea, 0xc62, 0x1764, 0x2d8d, 0x5, 0x2f, 0x83, 0x103, 0x1ad, 0x282, 0x382,
+	0x4ad, 0x60c, 0x7f2, 0xaa4, 0xe76, 0x13e1, 0x1b92, 0x267c, 0x35f8, 0x1,
+	0xb, 0x20, 0x40, 0x6a, 0x9f, 0xdf, 0x12a, 0x17f, 0x1df, 0x249, 0x2be,
+	0x33e, 0x3c9, 0x45e, 0x4fe, 0x5ab, 0x676, 0x768, 0x889, 0x9e0, 0xb79,
+	0xd60, 0xfa4, 0x1258, 0x158f, 0x1964, 0x1df4, 0x2364, 0x29dd, 0x3193,
+	0x3ac3, 0x0, 0x2, 0x7, 0xf, 0x1a, 0x27, 0x37, 0x49, 0x5f, 0x76, 0x91, 0xae,
+	0xce, 0xf1, 0x116, 0x13e, 0x168, 0x196, 0x1c6, 0x1f8, 0x22d, 0x265, 0x2a0,
+	0x2dd, 0x31d, 0x360, 0x3a5, 0x3ed, 0x438, 0x485, 0x4d5, 0x528, 0x57e,
+	0x5db, 0x640, 0x6af, 0x728, 0x7ac, 0x83c, 0x8d9, 0x984, 0xa40, 0xb0c,
+	0xbeb, 0xcde, 0xde8, 0xf0a, 0x1046, 0x119f, 0x1318, 0x14b4, 0x1674, 0x185e,
+	0x1a75, 0x1cbd, 0x1f39, 0x21f1, 0x24e7, 0x2823, 0x2bab, 0x2f85, 0x33b9,
+	0x3850, 0x3d52, 0x0, 0x0, 0x1, 0x3, 0x6, 0x9, 0xd, 0x12, 0x17, 0x1d, 0x23,
+	0x2b, 0x33, 0x3b, 0x45, 0x4e, 0x59, 0x64, 0x70, 0x7d, 0x8a, 0x98, 0xa7,
+	0xb6, 0xc6, 0xd7, 0xe8, 0xfa, 0x10c, 0x120, 0x134, 0x148, 0x15e, 0x174,
+	0x18a, 0x1a1, 0x1b9, 0x1d2, 0x1eb, 0x205, 0x220, 0x23b, 0x257, 0x274,
+	0x291, 0x2af, 0x2ce, 0x2ed, 0x30d, 0x32e, 0x34f, 0x371, 0x394, 0x3b7,
+	0x3db, 0x400, 0x425, 0x44b, 0x472, 0x499, 0x4c1, 0x4ea, 0x513, 0x53d,
+	0x568, 0x594, 0x5c3, 0x5f3, 0x626, 0x65b, 0x692, 0x6cc, 0x709, 0x748,
+	0x78a, 0x7cf, 0x817, 0x862, 0x8b0, 0x902, 0x958, 0x9b2, 0xa0f, 0xa71,
+	0xad7, 0xb42, 0xbb1, 0xc26, 0xc9f, 0xd1e, 0xda3, 0xe2e, 0xebf, 0xf56,
+	0xff4, 0x109a, 0x1146, 0x11fb, 0x12b7, 0x137c, 0x1449, 0x1520, 0x1600,
+	0x16eb, 0x17e0, 0x18e0, 0x19eb, 0x1b02, 0x1c26, 0x1d57, 0x1e95, 0x1fe2,
+	0x213d, 0x22a8, 0x2423, 0x25af, 0x274d, 0x28fe, 0x2ac1, 0x2c99, 0x2e86,
+	0x3089, 0x32a3, 0x34d5, 0x3721, 0x3986, 0x3c07, 0x3ea5, 0x0, 0x0, 0x0, 0x0,
+	0x1, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8, 0xa, 0xc, 0xe, 0x10, 0x13, 0x16, 0x18,
+	0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35, 0x39, 0x3d, 0x42, 0x47,
+	0x4c, 0x51, 0x56, 0x5c, 0x61, 0x67, 0x6d, 0x73, 0x7a, 0x80, 0x87, 0x8e,
+	0x95, 0x9c, 0xa3, 0xaa, 0xb2, 0xba, 0xc2, 0xca, 0xd2, 0xdb, 0xe3, 0xec,
+	0xf5, 0xfe, 0x108, 0x111, 0x11b, 0x125, 0x12f, 0x139, 0x143, 0x14e, 0x158,
+	0x163, 0x16e, 0x179, 0x184, 0x190, 0x19c, 0x1a7, 0x1b3, 0x1bf, 0x1cc,
+	0x1d8, 0x1e5, 0x1f2, 0x1ff, 0x20c, 0x219, 0x227, 0x234, 0x242, 0x250,
+	0x25e, 0x26d, 0x27b, 0x28a, 0x299, 0x2a8, 0x2b7, 0x2c6, 0x2d6, 0x2e5,
+	0x2f5, 0x305, 0x315, 0x325, 0x336, 0x347, 0x357, 0x368, 0x37a, 0x38b,
+	0x39c, 0x3ae, 0x3c0, 0x3d2, 0x3e4, 0x3f6, 0x409, 0x41b, 0x42e, 0x441,
+	0x454, 0x468, 0x47b, 0x48f, 0x4a3, 0x4b7, 0x4cb, 0x4df, 0x4f4, 0x508,
+	0x51d, 0x532, 0x547, 0x55d, 0x573, 0x589, 0x5a0, 0x5b7, 0x5cf, 0x5e7,
+	0x600, 0x619, 0x633, 0x64d, 0x669, 0x684, 0x6a0, 0x6bd, 0x6db, 0x6f9,
+	0x718, 0x738, 0x758, 0x779, 0x79b, 0x7bd, 0x7e0, 0x804, 0x829, 0x84f,
+	0x875, 0x89c, 0x8c4, 0x8ed, 0x917, 0x942, 0x96e, 0x99b, 0x9c9, 0x9f7,
+	0xa27, 0xa58, 0xa8a, 0xabd, 0xaf1, 0xb27, 0xb5d, 0xb95, 0xbce, 0xc08,
+	0xc44, 0xc80, 0xcbf, 0xcfe, 0xd3f, 0xd82, 0xdc5, 0xe0b, 0xe52, 0xe9a,
+	0xee4, 0xf30, 0xf7d, 0xfcc, 0x101d, 0x1070, 0x10c4, 0x111a, 0x1173, 0x11cd,
+	0x1229, 0x1287, 0x12e7, 0x134a, 0x13ae, 0x1415, 0x147e, 0x14ea, 0x1557,
+	0x15c7, 0x163a, 0x16af, 0x1727, 0x17a2, 0x181f, 0x189f, 0x1921, 0x19a7,
+	0x1a30, 0x1abb, 0x1b4a, 0x1bdc, 0x1c71, 0x1d09, 0x1da5, 0x1e44, 0x1ee7,
+	0x1f8d, 0x2037, 0x20e5, 0x2196, 0x224c, 0x2305, 0x23c3, 0x2485, 0x254b,
+	0x2615, 0x26e4, 0x27b8, 0x2890, 0x296d, 0x2a4f, 0x2b35, 0x2c21, 0x2d13,
+	0x2e09, 0x2f05, 0x3006, 0x310e, 0x321b, 0x332e, 0x3447, 0x3566, 0x368b,
+	0x37b8, 0x38ea, 0x3a24, 0x3b64, 0x3cac, 0x3dfa, 0x3f51, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x6, 0x6,
+	0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x14, 0x15,
+	0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x1f, 0x21, 0x23, 0x24, 0x26, 0x28,
+	0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3f, 0x41,
+	0x43, 0x46, 0x48, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, 0x5a, 0x5d, 0x60,
+	0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x82, 0x85,
+	0x88, 0x8c, 0x8f, 0x93, 0x96, 0x9a, 0x9d, 0xa1, 0xa5, 0xa9, 0xac, 0xb0,
+	0xb4, 0xb8, 0xbc, 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd9, 0xdd, 0xe1,
+	0xe6, 0xea, 0xee, 0xf3, 0xf7, 0xfc, 0x101, 0x105, 0x10a, 0x10f, 0x114,
+	0x118, 0x11d, 0x122, 0x127, 0x12c, 0x131, 0x136, 0x13b, 0x140, 0x146,
+	0x14b, 0x150, 0x155, 0x15b, 0x160, 0x166, 0x16b, 0x171, 0x176, 0x17c,
+	0x182, 0x187, 0x18d, 0x193, 0x199, 0x19e, 0x1a4, 0x1aa, 0x1b0, 0x1b6,
+	0x1bc, 0x1c3, 0x1c9, 0x1cf, 0x1d5, 0x1db, 0x1e2, 0x1e8, 0x1ef, 0x1f5,
+	0x1fb, 0x202, 0x209, 0x20f, 0x216, 0x21d, 0x223, 0x22a, 0x231, 0x238,
+	0x23f, 0x246, 0x24d, 0x254, 0x25b, 0x262, 0x269, 0x270, 0x277, 0x27f,
+	0x286, 0x28d, 0x295, 0x29c, 0x2a4, 0x2ab, 0x2b3, 0x2bb, 0x2c2, 0x2ca,
+	0x2d2, 0x2d9, 0x2e1, 0x2e9, 0x2f1, 0x2f9, 0x301, 0x309, 0x311, 0x319,
+	0x321, 0x32a, 0x332, 0x33a, 0x342, 0x34b, 0x353, 0x35c, 0x364, 0x36d,
+	0x375, 0x37e, 0x387, 0x38f, 0x398, 0x3a1, 0x3aa, 0x3b2, 0x3bb, 0x3c4,
+	0x3cd, 0x3d6, 0x3df, 0x3e9, 0x3f2, 0x3fb, 0x404, 0x40d, 0x417, 0x420,
+	0x42a, 0x433, 0x43d, 0x446, 0x450, 0x459, 0x463, 0x46d, 0x476, 0x480,
+	0x48a, 0x494, 0x49e, 0x4a8, 0x4b2, 0x4bc, 0x4c6, 0x4d0, 0x4da, 0x4e4,
+	0x4ef, 0x4f9, 0x503, 0x50e, 0x518, 0x523, 0x52d, 0x538, 0x542, 0x54d,
+	0x557, 0x562, 0x56d, 0x578, 0x583, 0x58e, 0x59a, 0x5a5, 0x5b1, 0x5bd,
+	0x5c9, 0x5d5, 0x5e1, 0x5ed, 0x5f9, 0x606, 0x613, 0x61f, 0x62c, 0x639,
+	0x647, 0x654, 0x662, 0x66f, 0x67d, 0x68b, 0x699, 0x6a8, 0x6b6, 0x6c5,
+	0x6d4, 0x6e2, 0x6f2, 0x701, 0x710, 0x720, 0x730, 0x740, 0x750, 0x760,
+	0x771, 0x781, 0x792, 0x7a3, 0x7b4, 0x7c6, 0x7d7, 0x7e9, 0x7fb, 0x80d,
+	0x820, 0x832, 0x845, 0x858, 0x86b, 0x87f, 0x892, 0x8a6, 0x8ba, 0x8cf,
+	0x8e3, 0x8f8, 0x90d, 0x922, 0x937, 0x94d, 0x963, 0x979, 0x990, 0x9a6,
+	0x9bd, 0x9d4, 0x9ec, 0xa03, 0xa1b, 0xa33, 0xa4c, 0xa65, 0xa7e, 0xa97,
+	0xab0, 0xaca, 0xae4, 0xaff, 0xb19, 0xb34, 0xb50, 0xb6b, 0xb87, 0xba3,
+	0xbc0, 0xbdc, 0xbf9, 0xc17, 0xc35, 0xc53, 0xc71, 0xc90, 0xcaf, 0xcce,
+	0xcee, 0xd0e, 0xd2f, 0xd50, 0xd71, 0xd92, 0xdb4, 0xdd7, 0xdf9, 0xe1c,
+	0xe40, 0xe64, 0xe88, 0xeac, 0xed1, 0xef7, 0xf1d, 0xf43, 0xf6a, 0xf91,
+	0xfb8, 0xfe0, 0x1009, 0x1032, 0x105b, 0x1085, 0x10af, 0x10d9, 0x1105,
+	0x1130, 0x115c, 0x1189, 0x11b6, 0x11e4, 0x1212, 0x1240, 0x126f, 0x129f,
+	0x12cf, 0x1300, 0x1331, 0x1363, 0x1395, 0x13c8, 0x13fb, 0x142f, 0x1464,
+	0x1499, 0x14ce, 0x1505, 0x153c, 0x1573, 0x15ab, 0x15e4, 0x161d, 0x1657,
+	0x1692, 0x16cd, 0x1709, 0x1745, 0x1783, 0x17c1, 0x17ff, 0x183e, 0x187e,
+	0x18bf, 0x1900, 0x1943, 0x1985, 0x19c9, 0x1a0d, 0x1a52, 0x1a98, 0x1adf,
+	0x1b26, 0x1b6e, 0x1bb7, 0x1c01, 0x1c4b, 0x1c97, 0x1ce3, 0x1d30, 0x1d7e,
+	0x1dcc, 0x1e1c, 0x1e6c, 0x1ebe, 0x1f10, 0x1f63, 0x1fb7, 0x200c, 0x2062,
+	0x20b9, 0x2111, 0x216a, 0x21c3, 0x221e, 0x227a, 0x22d7, 0x2334, 0x2393,
+	0x23f3, 0x2454, 0x24b6, 0x2519, 0x257d, 0x25e2, 0x2649, 0x26b0, 0x2719,
+	0x2782, 0x27ed, 0x2859, 0x28c7, 0x2935, 0x29a5, 0x2a16, 0x2a88, 0x2afb,
+	0x2b70, 0x2be6, 0x2c5d, 0x2cd6, 0x2d50, 0x2dcb, 0x2e47, 0x2ec5, 0x2f45,
+	0x2fc6, 0x3048, 0x30cb, 0x3150, 0x31d7, 0x325f, 0x32e8, 0x3373, 0x3400,
+	0x348e, 0x351d, 0x35af, 0x3641, 0x36d6, 0x376c, 0x3804, 0x389d, 0x3938,
+	0x39d5, 0x3a73, 0x3b13, 0x3bb5, 0x3c59, 0x3cff, 0x3da6, 0x3e4f, 0x3efa,
+	0x3fa7, 0x6,
+	/* table descriptor */
+	0xe8effbe9, 0x0,
+	/* table length */
+	0x400,
+	/* table data */
+	0x32a8, 0x2ea6, 0x361d, 0x2aa0, 0x30fc, 0x344a, 0x3808, 0x2696, 0x2cf8,
+	0x3012, 0x3208, 0x3374, 0x3517, 0x36eb, 0x38d8, 0x2281, 0x28f0, 0x2c0f,
+	0x2e06, 0x2f5a, 0x3082, 0x3181, 0x3256, 0x3305, 0x33f8, 0x34a8, 0x359c,
+	0x367b, 0x3771, 0x3867, 0x395e, 0x1e58, 0x24e1, 0x2808, 0x2a01, 0x2b54,
+	0x2c7e, 0x2d7d, 0x2e53, 0x2efd, 0x2fbd, 0x3049, 0x30be, 0x313d, 0x31c8,
+	0x322e, 0x327e, 0x32d5, 0x333a, 0x33b3, 0x3421, 0x3477, 0x34dd, 0x3557,
+	0x35e8, 0x364a, 0x36b1, 0x372b, 0x37bd, 0x3835, 0x389d, 0x3918, 0x39ab,
+	0x1a0b, 0x20c2, 0x23f6, 0x25f1, 0x2748, 0x2877, 0x2974, 0x2a4e, 0x2af8,
+	0x2bb6, 0x2c45, 0x2cba, 0x2d39, 0x2dc3, 0x2e2c, 0x2e7c, 0x2ed1, 0x2f2b,
+	0x2f8b, 0x2ff0, 0x302d, 0x3065, 0x309f, 0x30dd, 0x311d, 0x315f, 0x31a4,
+	0x31ec, 0x321b, 0x3242, 0x326a, 0x3293, 0x32be, 0x32ec, 0x331f, 0x3356,
+	0x3393, 0x33d5, 0x340e, 0x3435, 0x3460, 0x348f, 0x34c2, 0x34fa, 0x3536,
+	0x3579, 0x35c1, 0x3608, 0x3633, 0x3662, 0x3695, 0x36cd, 0x370b, 0x374d,
+	0x3796, 0x37e6, 0x381e, 0x384d, 0x3881, 0x38ba, 0x38f7, 0x393a, 0x3984,
+	0x39d4, 0x1500, 0x1c85, 0x1fc3, 0x21cc, 0x2331, 0x2468, 0x2563, 0x2644,
+	0x26ec, 0x27aa, 0x283e, 0x28b2, 0x2931, 0x29bb, 0x2a27, 0x2a76, 0x2acb,
+	0x2b25, 0x2b85, 0x2bea, 0x2c2a, 0x2c61, 0x2c9c, 0x2cd9, 0x2d18, 0x2d5b,
+	0x2da0, 0x2de8, 0x2e19, 0x2e3f, 0x2e67, 0x2e90, 0x2ebb, 0x2ee7, 0x2f14,
+	0x2f43, 0x2f72, 0x2fa4, 0x2fd6, 0x3005, 0x301f, 0x303b, 0x3057, 0x3073,
+	0x3091, 0x30ae, 0x30cd, 0x30ec, 0x310c, 0x312d, 0x314e, 0x3170, 0x3193,
+	0x31b6, 0x31da, 0x31ff, 0x3212, 0x3225, 0x3238, 0x324c, 0x3260, 0x3274,
+	0x3289, 0x329e, 0x32b3, 0x32c9, 0x32e0, 0x32f9, 0x3312, 0x332c, 0x3348,
+	0x3365, 0x3383, 0x33a3, 0x33c4, 0x33e6, 0x3405, 0x3418, 0x342b, 0x3440,
+	0x3455, 0x346b, 0x3483, 0x349b, 0x34b5, 0x34cf, 0x34eb, 0x3508, 0x3527,
+	0x3546, 0x3568, 0x358a, 0x35ae, 0x35d4, 0x35fc, 0x3612, 0x3628, 0x363e,
+	0x3656, 0x366e, 0x3688, 0x36a3, 0x36bf, 0x36dc, 0x36fb, 0x371b, 0x373c,
+	0x375f, 0x3783, 0x37aa, 0x37d1, 0x37fb, 0x3813, 0x382a, 0x3841, 0x385a,
+	0x3874, 0x388f, 0x38ab, 0x38c8, 0x38e7, 0x3907, 0x3929, 0x394c, 0x3971,
+	0x3997, 0x39bf, 0x39e9, 0xea8, 0x1815, 0x1b60, 0x1d86, 0x1f03, 0x204c,
+	0x2142, 0x2231, 0x22d6, 0x2391, 0x2430, 0x24a3, 0x2521, 0x25a9, 0x261e,
+	0x266c, 0x26c0, 0x271a, 0x2779, 0x27dd, 0x2823, 0x285a, 0x2894, 0x28d1,
+	0x2910, 0x2952, 0x2997, 0x29df, 0x2a14, 0x2a3a, 0x2a62, 0x2a8b, 0x2ab6,
+	0x2ae1, 0x2b0e, 0x2b3d, 0x2b6c, 0x2b9d, 0x2bd0, 0x2c02, 0x2c1c, 0x2c37,
+	0x2c53, 0x2c70, 0x2c8d, 0x2cab, 0x2cc9, 0x2ce8, 0x2d08, 0x2d29, 0x2d4a,
+	0x2d6c, 0x2d8e, 0x2db2, 0x2dd5, 0x2dfa, 0x2e0f, 0x2e22, 0x2e36, 0x2e49,
+	0x2e5d, 0x2e71, 0x2e86, 0x2e9b, 0x2eb0, 0x2ec6, 0x2edc, 0x2ef2, 0x2f09,
+	0x2f20, 0x2f37, 0x2f4e, 0x2f66, 0x2f7f, 0x2f97, 0x2fb0, 0x2fc9, 0x2fe3,
+	0x2ffd, 0x300b, 0x3019, 0x3026, 0x3034, 0x3042, 0x3050, 0x305e, 0x306c,
+	0x307b, 0x3089, 0x3098, 0x30a7, 0x30b6, 0x30c5, 0x30d5, 0x30e4, 0x30f4,
+	0x3104, 0x3114, 0x3125, 0x3135, 0x3146, 0x3157, 0x3168, 0x3179, 0x318a,
+	0x319c, 0x31ad, 0x31bf, 0x31d1, 0x31e3, 0x31f5, 0x3204, 0x320d, 0x3216,
+	0x3220, 0x3229, 0x3233, 0x323d, 0x3247, 0x3251, 0x325b, 0x3265, 0x326f,
+	0x3279, 0x3283, 0x328e, 0x3298, 0x32a3, 0x32ae, 0x32b8, 0x32c4, 0x32cf,
+	0x32da, 0x32e6, 0x32f2, 0x32ff, 0x330c, 0x3318, 0x3326, 0x3333, 0x3341,
+	0x334f, 0x335e, 0x336c, 0x337c, 0x338b, 0x339b, 0x33ab, 0x33bb, 0x33cc,
+	0x33dd, 0x33ef, 0x3400, 0x3409, 0x3413, 0x341c, 0x3426, 0x3430, 0x343a,
+	0x3445, 0x3450, 0x345b, 0x3466, 0x3471, 0x347d, 0x3489, 0x3495, 0x34a2,
+	0x34ae, 0x34bb, 0x34c9, 0x34d6, 0x34e4, 0x34f2, 0x3501, 0x3510, 0x351f,
+	0x352f, 0x353e, 0x354f, 0x355f, 0x3570, 0x3581, 0x3593, 0x35a5, 0x35b8,
+	0x35cb, 0x35de, 0x35f2, 0x3603, 0x360d, 0x3618, 0x3622, 0x362d, 0x3639,
+	0x3644, 0x3650, 0x365c, 0x3668, 0x3675, 0x3682, 0x368f, 0x369c, 0x36aa,
+	0x36b8, 0x36c6, 0x36d5, 0x36e4, 0x36f3, 0x3703, 0x3713, 0x3723, 0x3734,
+	0x3745, 0x3756, 0x3768, 0x377a, 0x378d, 0x37a0, 0x37b3, 0x37c7, 0x37dc,
+	0x37f0, 0x3802, 0x380d, 0x3818, 0x3824, 0x382f, 0x383b, 0x3847, 0x3854,
+	0x3860, 0x386d, 0x387a, 0x3888, 0x3896, 0x38a4, 0x38b2, 0x38c1, 0x38d0,
+	0x38df, 0x38ef, 0x38ff, 0x3910, 0x3920, 0x3932, 0x3943, 0x3955, 0x3967,
+	0x397a, 0x398d, 0x39a1, 0x39b5, 0x39c9, 0x39de, 0x39f4, 0x0, 0x12aa,
+	0x16ab, 0x1900, 0x1aab, 0x1c15, 0x1d00, 0x1e0b, 0x1eab, 0x1f60, 0x2015,
+	0x2085, 0x2100, 0x2186, 0x220b, 0x2258, 0x22ab, 0x2303, 0x2360, 0x23c3,
+	0x2415, 0x244c, 0x2485, 0x24c2, 0x2500, 0x2542, 0x2586, 0x25cc, 0x260b,
+	0x2631, 0x2658, 0x2681, 0x26ab, 0x26d6, 0x2703, 0x2731, 0x2760, 0x2791,
+	0x27c3, 0x27f6, 0x2815, 0x2830, 0x284c, 0x2868, 0x2885, 0x28a3, 0x28c2,
+	0x28e1, 0x2900, 0x2921, 0x2942, 0x2963, 0x2986, 0x29a9, 0x29cc, 0x29f1,
+	0x2a0b, 0x2a1e, 0x2a31, 0x2a44, 0x2a58, 0x2a6c, 0x2a81, 0x2a96, 0x2aab,
+	0x2ac0, 0x2ad6, 0x2aec, 0x2b03, 0x2b1a, 0x2b31, 0x2b48, 0x2b60, 0x2b79,
+	0x2b91, 0x2baa, 0x2bc3, 0x2bdd, 0x2bf6, 0x2c08, 0x2c15, 0x2c23, 0x2c30,
+	0x2c3e, 0x2c4c, 0x2c5a, 0x2c68, 0x2c77, 0x2c85, 0x2c94, 0x2ca3, 0x2cb2,
+	0x2cc2, 0x2cd1, 0x2ce1, 0x2cf0, 0x2d00, 0x2d10, 0x2d21, 0x2d31, 0x2d42,
+	0x2d52, 0x2d63, 0x2d74, 0x2d86, 0x2d97, 0x2da9, 0x2dbb, 0x2dcc, 0x2ddf,
+	0x2df1, 0x2e01, 0x2e0b, 0x2e14, 0x2e1e, 0x2e27, 0x2e31, 0x2e3a, 0x2e44,
+	0x2e4e, 0x2e58, 0x2e62, 0x2e6c, 0x2e76, 0x2e81, 0x2e8b, 0x2e96, 0x2ea0,
+	0x2eab, 0x2eb6, 0x2ec0, 0x2ecb, 0x2ed6, 0x2ee1, 0x2eec, 0x2ef8, 0x2f03,
+	0x2f0e, 0x2f1a, 0x2f25, 0x2f31, 0x2f3d, 0x2f48, 0x2f54, 0x2f60, 0x2f6c,
+	0x2f79, 0x2f85, 0x2f91, 0x2f9d, 0x2faa, 0x2fb6, 0x2fc3, 0x2fd0, 0x2fdd,
+	0x2fea, 0x2ff6, 0x3002, 0x3008, 0x300f, 0x3015, 0x301c, 0x3023, 0x302a,
+	0x3030, 0x3037, 0x303e, 0x3045, 0x304c, 0x3053, 0x305a, 0x3061, 0x3068,
+	0x3070, 0x3077, 0x307e, 0x3085, 0x308d, 0x3094, 0x309c, 0x30a3, 0x30ab,
+	0x30b2, 0x30ba, 0x30c2, 0x30c9, 0x30d1, 0x30d9, 0x30e1, 0x30e8, 0x30f0,
+	0x30f8, 0x3100, 0x3108, 0x3110, 0x3118, 0x3121, 0x3129, 0x3131, 0x3139,
+	0x3142, 0x314a, 0x3152, 0x315b, 0x3163, 0x316c, 0x3174, 0x317d, 0x3186,
+	0x318e, 0x3197, 0x31a0, 0x31a9, 0x31b2, 0x31bb, 0x31c3, 0x31cc, 0x31d5,
+	0x31df, 0x31e8, 0x31f1, 0x31fa, 0x3201, 0x3206, 0x320b, 0x320f, 0x3214,
+	0x3219, 0x321e, 0x3222, 0x3227, 0x322c, 0x3231, 0x3236, 0x323a, 0x323f,
+	0x3244, 0x3249, 0x324e, 0x3253, 0x3258, 0x325d, 0x3262, 0x3267, 0x326c,
+	0x3271, 0x3276, 0x327c, 0x3281, 0x3286, 0x328b, 0x3290, 0x3296, 0x329b,
+	0x32a0, 0x32a6, 0x32ab, 0x32b0, 0x32b6, 0x32bb, 0x32c1, 0x32c6, 0x32cc,
+	0x32d2, 0x32d8, 0x32dd, 0x32e3, 0x32e9, 0x32ef, 0x32f6, 0x32fc, 0x3302,
+	0x3308, 0x330f, 0x3315, 0x331c, 0x3322, 0x3329, 0x3330, 0x3337, 0x333e,
+	0x3345, 0x334c, 0x3353, 0x335a, 0x3361, 0x3369, 0x3370, 0x3378, 0x337f,
+	0x3387, 0x338f, 0x3397, 0x339f, 0x33a7, 0x33af, 0x33b7, 0x33bf, 0x33c8,
+	0x33d0, 0x33d9, 0x33e2, 0x33eb, 0x33f3, 0x33fc, 0x3402, 0x3407, 0x340c,
+	0x3410, 0x3415, 0x341a, 0x341f, 0x3424, 0x3429, 0x342e, 0x3433, 0x3438,
+	0x343d, 0x3442, 0x3448, 0x344d, 0x3452, 0x3458, 0x345d, 0x3463, 0x3469,
+	0x346e, 0x3474, 0x347a, 0x3480, 0x3486, 0x348c, 0x3492, 0x3498, 0x349e,
+	0x34a5, 0x34ab, 0x34b2, 0x34b8, 0x34bf, 0x34c5, 0x34cc, 0x34d3, 0x34da,
+	0x34e1, 0x34e8, 0x34ef, 0x34f6, 0x34fd, 0x3505, 0x350c, 0x3514, 0x351b,
+	0x3523, 0x352b, 0x3532, 0x353a, 0x3542, 0x354b, 0x3553, 0x355b, 0x3563,
+	0x356c, 0x3574, 0x357d, 0x3586, 0x358f, 0x3598, 0x35a1, 0x35aa, 0x35b3,
+	0x35bc, 0x35c6, 0x35cf, 0x35d9, 0x35e3, 0x35ed, 0x35f7, 0x3600, 0x3605,
+	0x360a, 0x3610, 0x3615, 0x361a, 0x3620, 0x3625, 0x362b, 0x3630, 0x3636,
+	0x363b, 0x3641, 0x3647, 0x364d, 0x3653, 0x3659, 0x365f, 0x3665, 0x366b,
+	0x3672, 0x3678, 0x367e, 0x3685, 0x368b, 0x3692, 0x3699, 0x36a0, 0x36a6,
+	0x36ad, 0x36b4, 0x36bb, 0x36c3, 0x36ca, 0x36d1, 0x36d9, 0x36e0, 0x36e8,
+	0x36ef, 0x36f7, 0x36ff, 0x3707, 0x370f, 0x3717, 0x371f, 0x3727, 0x372f,
+	0x3738, 0x3740, 0x3749, 0x3752, 0x375b, 0x3764, 0x376d, 0x3776, 0x377f,
+	0x3788, 0x3792, 0x379b, 0x37a5, 0x37ae, 0x37b8, 0x37c2, 0x37cc, 0x37d6,
+	0x37e1, 0x37eb, 0x37f6, 0x3800, 0x3805, 0x380b, 0x3810, 0x3816, 0x381b,
+	0x3821, 0x3827, 0x382c, 0x3832, 0x3838, 0x383e, 0x3844, 0x384a, 0x3851,
+	0x3857, 0x385d, 0x3864, 0x386a, 0x3870, 0x3877, 0x387e, 0x3885, 0x388b,
+	0x3892, 0x3899, 0x38a0, 0x38a7, 0x38af, 0x38b6, 0x38bd, 0x38c5, 0x38cc,
+	0x38d4, 0x38dc, 0x38e3, 0x38eb, 0x38f3, 0x38fb, 0x3903, 0x390c, 0x3914,
+	0x391c, 0x3925, 0x392d, 0x3936, 0x393f, 0x3948, 0x3951, 0x395a, 0x3963,
+	0x396c, 0x3975, 0x397f, 0x3989, 0x3992, 0x399c, 0x39a6, 0x39b0, 0x39ba,
+	0x39c4, 0x39cf, 0x39d9, 0x39e4, 0x39ee, 0x39f9, 0xc,
+	/* table descriptor */
+	0xe1effbe9, 0x0,
+	/* table length */
+	0x400,
+	/* table data */
+	0x2c59, 0x2416, 0x3322, 0x1dd0, 0x287e, 0x2ff0, 0x3679, 0x188b, 0x2131,
+	0x2661, 0x2a78, 0x2e2b, 0x3186, 0x34c8, 0x3836, 0x141d, 0x1b81, 0x1fa3,
+	0x22a3, 0x2531, 0x277a, 0x2988, 0x2b6b, 0x2d33, 0x2eed, 0x30a3, 0x325a,
+	0x3416, 0x35b5, 0x374e, 0x38f8, 0xff8, 0x1698, 0x1a32, 0x1ca3, 0x1eab,
+	0x206e, 0x2210, 0x2355, 0x2497, 0x25e9, 0x26e2, 0x2816, 0x28f9, 0x2a17,
+	0x2ae8, 0x2c01, 0x2cbe, 0x2dbb, 0x2e85, 0x2f65, 0x3047, 0x310d, 0x3209,
+	0x32b7, 0x339e, 0x3469, 0x3536, 0x3624, 0x36db, 0x37d2, 0x388f, 0x3971,
+	0xbe0, 0x124a, 0x1572, 0x17b5, 0x1962, 0x1acc, 0x1c29, 0x1d30, 0x1e43,
+	0x1f20, 0x201b, 0x20ca, 0x21a2, 0x2256, 0x22f8, 0x23bc, 0x2454, 0x24e1,
+	0x2589, 0x2629, 0x269f, 0x272b, 0x27d0, 0x2848, 0x28b9, 0x293d, 0x29d8,
+	0x2a45, 0x2aae, 0x2b27, 0x2bb4, 0x2c2b, 0x2c89, 0x2cf6, 0x2d74, 0x2e03,
+	0x2e57, 0x2eb8, 0x2f27, 0x2fa8, 0x301e, 0x3073, 0x30d6, 0x3147, 0x31ca,
+	0x3230, 0x3287, 0x32eb, 0x335e, 0x33e3, 0x343e, 0x3497, 0x34fd, 0x3573,
+	0x35fc, 0x364d, 0x36a8, 0x3712, 0x378d, 0x380e, 0x3861, 0x38c1, 0x3932,
+	0x39b5, 0x700, 0xe30, 0x1120, 0x132c, 0x14bb, 0x1621, 0x171f, 0x182e,
+	0x18f2, 0x19de, 0x1a7c, 0x1b23, 0x1be6, 0x1c64, 0x1ce7, 0x1d7d, 0x1e14,
+	0x1e75, 0x1ee3, 0x1f60, 0x1feb, 0x2043, 0x209b, 0x20fc, 0x2168, 0x21e0,
+	0x2232, 0x227b, 0x22cc, 0x2325, 0x2387, 0x23f3, 0x2434, 0x2475, 0x24bb,
+	0x2508, 0x255d, 0x25b8, 0x260e, 0x2644, 0x2680, 0x26c0, 0x2706, 0x2752,
+	0x27a4, 0x27fd, 0x282f, 0x2863, 0x289b, 0x28d8, 0x291a, 0x2962, 0x29af,
+	0x2a01, 0x2a2e, 0x2a5e, 0x2a92, 0x2aca, 0x2b07, 0x2b48, 0x2b8f, 0x2bda,
+	0x2c16, 0x2c41, 0x2c70, 0x2ca3, 0x2cda, 0x2d14, 0x2d53, 0x2d97, 0x2de0,
+	0x2e17, 0x2e41, 0x2e6e, 0x2e9e, 0x2ed2, 0x2f0a, 0x2f46, 0x2f86, 0x2fcb,
+	0x300a, 0x3032, 0x305d, 0x308b, 0x30bc, 0x30f1, 0x3129, 0x3166, 0x31a8,
+	0x31ee, 0x321c, 0x3245, 0x3270, 0x329f, 0x32d1, 0x3306, 0x3340, 0x337e,
+	0x33c0, 0x3404, 0x342a, 0x3453, 0x347f, 0x34af, 0x34e2, 0x3519, 0x3554,
+	0x3593, 0x35d8, 0x3610, 0x3638, 0x3662, 0x3690, 0x36c1, 0x36f6, 0x372f,
+	0x376d, 0x37af, 0x37f7, 0x3821, 0x384b, 0x3878, 0x38a8, 0x38dc, 0x3914,
+	0x3951, 0x3992, 0x39d9, 0x200, 0xa20, 0xd00, 0xf00, 0x1084, 0x11d0, 0x12b6,
+	0x13ae, 0x1469, 0x1513, 0x15d7, 0x165b, 0x16da, 0x1768, 0x1803, 0x185b,
+	0x18bd, 0x1929, 0x199f, 0x1a10, 0x1a56, 0x1aa3, 0x1af6, 0x1b51, 0x1bb2,
+	0x1c0e, 0x1c46, 0x1c83, 0x1cc5, 0x1d0b, 0x1d56, 0x1da6, 0x1dfc, 0x1e2b,
+	0x1e5c, 0x1e90, 0x1ec7, 0x1f01, 0x1f3f, 0x1f81, 0x1fc7, 0x2008, 0x202f,
+	0x2058, 0x2084, 0x20b2, 0x20e3, 0x2116, 0x214c, 0x2185, 0x21c1, 0x2200,
+	0x2221, 0x2244, 0x2268, 0x228f, 0x22b7, 0x22e2, 0x230e, 0x233d, 0x236e,
+	0x23a1, 0x23d7, 0x2407, 0x2425, 0x2444, 0x2464, 0x2486, 0x24a9, 0x24ce,
+	0x24f4, 0x251d, 0x2547, 0x2573, 0x25a1, 0x25d1, 0x2601, 0x261b, 0x2636,
+	0x2653, 0x2670, 0x268f, 0x26af, 0x26d1, 0x26f4, 0x2718, 0x273e, 0x2766,
+	0x278f, 0x27b9, 0x27e6, 0x280a, 0x2822, 0x283b, 0x2855, 0x2870, 0x288d,
+	0x28aa, 0x28c9, 0x28e8, 0x2909, 0x292c, 0x294f, 0x2975, 0x299b, 0x29c3,
+	0x29ed, 0x2a0c, 0x2a22, 0x2a39, 0x2a52, 0x2a6b, 0x2a85, 0x2aa0, 0x2abc,
+	0x2ad9, 0x2af7, 0x2b17, 0x2b38, 0x2b59, 0x2b7d, 0x2ba1, 0x2bc7, 0x2bee,
+	0x2c0b, 0x2c20, 0x2c36, 0x2c4d, 0x2c64, 0x2c7d, 0x2c96, 0x2cb0, 0x2ccc,
+	0x2ce8, 0x2d05, 0x2d24, 0x2d43, 0x2d64, 0x2d85, 0x2da9, 0x2dcd, 0x2df3,
+	0x2e0d, 0x2e21, 0x2e36, 0x2e4c, 0x2e62, 0x2e79, 0x2e92, 0x2eab, 0x2ec5,
+	0x2ee0, 0x2efb, 0x2f18, 0x2f36, 0x2f55, 0x2f76, 0x2f97, 0x2fb9, 0x2fdd,
+	0x3001, 0x3014, 0x3028, 0x303d, 0x3052, 0x3068, 0x307f, 0x3097, 0x30af,
+	0x30c9, 0x30e3, 0x30ff, 0x311b, 0x3138, 0x3157, 0x3176, 0x3197, 0x31b9,
+	0x31dc, 0x3200, 0x3213, 0x3226, 0x323a, 0x324f, 0x3265, 0x327b, 0x3293,
+	0x32ab, 0x32c4, 0x32de, 0x32f8, 0x3314, 0x3331, 0x334f, 0x336e, 0x338e,
+	0x33af, 0x33d2, 0x33f5, 0x340d, 0x3420, 0x3434, 0x3448, 0x345e, 0x3474,
+	0x348b, 0x34a3, 0x34bb, 0x34d5, 0x34ef, 0x350b, 0x3527, 0x3545, 0x3563,
+	0x3583, 0x35a4, 0x35c6, 0x35ea, 0x3607, 0x361a, 0x362e, 0x3642, 0x3657,
+	0x366d, 0x3684, 0x369c, 0x36b5, 0x36ce, 0x36e9, 0x3704, 0x3721, 0x373e,
+	0x375d, 0x377d, 0x379e, 0x37c1, 0x37e4, 0x3804, 0x3818, 0x382c, 0x3840,
+	0x3856, 0x386c, 0x3883, 0x389b, 0x38b5, 0x38cf, 0x38ea, 0x3906, 0x3923,
+	0x3941, 0x3961, 0x3981, 0x39a3, 0x39c7, 0x39ec, 0x0, 0x500, 0x8c0, 0xae0,
+	0xc70, 0xdb0, 0xe98, 0xf78, 0x103c, 0x10d0, 0x1178, 0x1218, 0x127e, 0x12f0,
+	0x136c, 0x13f2, 0x1442, 0x1491, 0x14e6, 0x1542, 0x15a4, 0x1606, 0x163e,
+	0x1679, 0x16b9, 0x16fc, 0x1743, 0x178e, 0x17dd, 0x1818, 0x1844, 0x1873,
+	0x18a4, 0x18d7, 0x190d, 0x1945, 0x1980, 0x19be, 0x19ff, 0x1a21, 0x1a44,
+	0x1a69, 0x1a8f, 0x1ab7, 0x1ae1, 0x1b0c, 0x1b39, 0x1b68, 0x1b99, 0x1bcc,
+	0x1c00, 0x1c1b, 0x1c38, 0x1c55, 0x1c74, 0x1c93, 0x1cb4, 0x1cd6, 0x1cf9,
+	0x1d1d, 0x1d42, 0x1d69, 0x1d91, 0x1dbb, 0x1de6, 0x1e09, 0x1e20, 0x1e37,
+	0x1e4f, 0x1e69, 0x1e82, 0x1e9d, 0x1eb9, 0x1ed5, 0x1ef2, 0x1f10, 0x1f2f,
+	0x1f4f, 0x1f70, 0x1f92, 0x1fb5, 0x1fd9, 0x1ffe, 0x2012, 0x2025, 0x2039,
+	0x204e, 0x2063, 0x2079, 0x208f, 0x20a6, 0x20be, 0x20d6, 0x20ef, 0x2109,
+	0x2123, 0x213e, 0x215a, 0x2176, 0x2194, 0x21b2, 0x21d0, 0x21f0, 0x2208,
+	0x2218, 0x2229, 0x223b, 0x224d, 0x225f, 0x2272, 0x2285, 0x2299, 0x22ad,
+	0x22c2, 0x22d7, 0x22ed, 0x2303, 0x231a, 0x2331, 0x2349, 0x2361, 0x237a,
+	0x2394, 0x23ae, 0x23c9, 0x23e5, 0x2400, 0x240f, 0x241d, 0x242c, 0x243c,
+	0x244c, 0x245c, 0x246c, 0x247d, 0x248e, 0x24a0, 0x24b2, 0x24c4, 0x24d7,
+	0x24eb, 0x24fe, 0x2512, 0x2527, 0x253c, 0x2552, 0x2568, 0x257e, 0x2595,
+	0x25ac, 0x25c4, 0x25dd, 0x25f6, 0x2607, 0x2614, 0x2622, 0x262f, 0x263d,
+	0x264c, 0x265a, 0x2669, 0x2678, 0x2687, 0x2697, 0x26a7, 0x26b8, 0x26c8,
+	0x26d9, 0x26eb, 0x26fd, 0x270f, 0x2722, 0x2734, 0x2748, 0x275c, 0x2770,
+	0x2784, 0x2799, 0x27af, 0x27c4, 0x27db, 0x27f1, 0x2804, 0x2810, 0x281c,
+	0x2828, 0x2835, 0x2842, 0x284f, 0x285c, 0x286a, 0x2877, 0x2886, 0x2894,
+	0x28a3, 0x28b2, 0x28c1, 0x28d0, 0x28e0, 0x28f1, 0x2901, 0x2912, 0x2923,
+	0x2935, 0x2946, 0x2959, 0x296b, 0x297e, 0x2991, 0x29a5, 0x29b9, 0x29cd,
+	0x29e2, 0x29f7, 0x2a06, 0x2a11, 0x2a1c, 0x2a28, 0x2a33, 0x2a3f, 0x2a4b,
+	0x2a58, 0x2a64, 0x2a71, 0x2a7e, 0x2a8b, 0x2a99, 0x2aa7, 0x2ab5, 0x2ac3,
+	0x2ad2, 0x2ae1, 0x2af0, 0x2aff, 0x2b0f, 0x2b1f, 0x2b2f, 0x2b40, 0x2b51,
+	0x2b62, 0x2b74, 0x2b86, 0x2b98, 0x2baa, 0x2bbd, 0x2bd0, 0x2be4, 0x2bf8,
+	0x2c06, 0x2c10, 0x2c1b, 0x2c26, 0x2c31, 0x2c3c, 0x2c47, 0x2c53, 0x2c5e,
+	0x2c6a, 0x2c77, 0x2c83, 0x2c90, 0x2c9d, 0x2caa, 0x2cb7, 0x2cc5, 0x2cd3,
+	0x2ce1, 0x2cef, 0x2cfe, 0x2d0d, 0x2d1c, 0x2d2b, 0x2d3b, 0x2d4b, 0x2d5b,
+	0x2d6c, 0x2d7d, 0x2d8e, 0x2da0, 0x2db2, 0x2dc4, 0x2dd6, 0x2de9, 0x2dfc,
+	0x2e08, 0x2e12, 0x2e1c, 0x2e26, 0x2e30, 0x2e3b, 0x2e46, 0x2e51, 0x2e5c,
+	0x2e68, 0x2e73, 0x2e7f, 0x2e8b, 0x2e98, 0x2ea4, 0x2eb1, 0x2ebe, 0x2ecb,
+	0x2ed9, 0x2ee6, 0x2ef4, 0x2f03, 0x2f11, 0x2f20, 0x2f2f, 0x2f3e, 0x2f4e,
+	0x2f5d, 0x2f6d, 0x2f7e, 0x2f8e, 0x2f9f, 0x2fb1, 0x2fc2, 0x2fd4, 0x2fe6,
+	0x2ff9, 0x3006, 0x300f, 0x3019, 0x3023, 0x302d, 0x3037, 0x3042, 0x304d,
+	0x3057, 0x3062, 0x306e, 0x3079, 0x3085, 0x3091, 0x309d, 0x30a9, 0x30b6,
+	0x30c2, 0x30cf, 0x30dd, 0x30ea, 0x30f8, 0x3106, 0x3114, 0x3122, 0x3131,
+	0x3140, 0x314f, 0x315e, 0x316e, 0x317e, 0x318f, 0x319f, 0x31b0, 0x31c1,
+	0x31d3, 0x31e5, 0x31f7, 0x3204, 0x320e, 0x3217, 0x3221, 0x322b, 0x3235,
+	0x323f, 0x324a, 0x3255, 0x325f, 0x326a, 0x3276, 0x3281, 0x328d, 0x3299,
+	0x32a5, 0x32b1, 0x32bd, 0x32ca, 0x32d7, 0x32e4, 0x32f2, 0x32ff, 0x330d,
+	0x331b, 0x332a, 0x3338, 0x3347, 0x3357, 0x3366, 0x3376, 0x3386, 0x3396,
+	0x33a7, 0x33b8, 0x33c9, 0x33da, 0x33ec, 0x33fe, 0x3408, 0x3412, 0x341b,
+	0x3425, 0x342f, 0x3439, 0x3443, 0x344e, 0x3458, 0x3463, 0x346e, 0x347a,
+	0x3485, 0x3491, 0x349d, 0x34a9, 0x34b5, 0x34c2, 0x34ce, 0x34db, 0x34e9,
+	0x34f6, 0x3504, 0x3512, 0x3520, 0x352f, 0x353d, 0x354c, 0x355c, 0x356b,
+	0x357b, 0x358b, 0x359c, 0x35ad, 0x35be, 0x35cf, 0x35e1, 0x35f3, 0x3602,
+	0x360c, 0x3615, 0x361f, 0x3629, 0x3633, 0x363d, 0x3647, 0x3652, 0x365d,
+	0x3668, 0x3673, 0x367f, 0x368a, 0x3696, 0x36a2, 0x36ae, 0x36bb, 0x36c8,
+	0x36d5, 0x36e2, 0x36f0, 0x36fd, 0x370b, 0x371a, 0x3728, 0x3737, 0x3746,
+	0x3755, 0x3765, 0x3775, 0x3785, 0x3796, 0x37a7, 0x37b8, 0x37c9, 0x37db,
+	0x37ed, 0x3800, 0x3809, 0x3813, 0x381d, 0x3826, 0x3831, 0x383b, 0x3846,
+	0x3850, 0x385b, 0x3866, 0x3872, 0x387d, 0x3889, 0x3895, 0x38a2, 0x38ae,
+	0x38bb, 0x38c8, 0x38d5, 0x38e3, 0x38f1, 0x38ff, 0x390d, 0x391b, 0x392a,
+	0x3939, 0x3949, 0x3959, 0x3969, 0x3979, 0x398a, 0x399b, 0x39ac, 0x39be,
+	0x39d0, 0x39e2, 0x39f5, 0xc,
+	/* table descriptor */
+	0xe2effbe9, 0xf,
+	/* table length */
+	0x400,
+	/* table data */
+	0x1095, 0x4fa, 0x240a, 0x1d9, 0x9d8, 0x1949, 0x30eb, 0xe0, 0x334, 0x72f,
+	0xcf9, 0x14ae, 0x1e66, 0x2a35, 0x382e, 0x6e, 0x152, 0x27a, 0x409, 0x606,
+	0x875, 0xb5a, 0xeb7, 0x1291, 0x16eb, 0x1bc7, 0x2127, 0x270e, 0x2d7f,
+	0x347b, 0x3c04, 0x35, 0xa7, 0x119, 0x193, 0x226, 0x2d4, 0x39b, 0x47e,
+	0x57d, 0x697, 0x7cf, 0x923, 0xa95, 0xc25, 0xdd4, 0xfa2, 0x118f, 0x139c,
+	0x15c9, 0x1816, 0x1a84, 0x1d12, 0x1fc2, 0x2294, 0x2588, 0x289e, 0x2bd6,
+	0x2f31, 0x32af, 0x3650, 0x3a15, 0x3dfd, 0x18, 0x51, 0x8a, 0xc3, 0xfc,
+	0x134, 0x172, 0x1b5, 0x1ff, 0x24f, 0x2a6, 0x303, 0x367, 0x3d2, 0x443,
+	0x4bb, 0x53a, 0x5c1, 0x64e, 0x6e2, 0x77e, 0x821, 0x8cb, 0x97d, 0xa36,
+	0xaf6, 0xbbf, 0xc8e, 0xd66, 0xe45, 0xf2c, 0x101a, 0x1111, 0x120f, 0x1316,
+	0x1424, 0x153a, 0x1659, 0x177f, 0x18ae, 0x19e5, 0x1b24, 0x1c6c, 0x1dbb,
+	0x1f13, 0x2074, 0x21dd, 0x234e, 0x24c8, 0x264a, 0x27d5, 0x2968, 0x2b05,
+	0x2ca9, 0x2e57, 0x300d, 0x31cc, 0x3394, 0x3564, 0x373e, 0x3920, 0x3b0b,
+	0x3cff, 0x3efd, 0xa, 0x27, 0x43, 0x60, 0x7c, 0x99, 0xb5, 0xd1, 0xee, 0x10a,
+	0x126, 0x143, 0x162, 0x182, 0x1a4, 0x1c7, 0x1ec, 0x213, 0x23b, 0x264,
+	0x290, 0x2bd, 0x2eb, 0x31c, 0x34d, 0x381, 0x3b6, 0x3ed, 0x426, 0x460,
+	0x49c, 0x4da, 0x51a, 0x55b, 0x59e, 0x5e3, 0x62a, 0x672, 0x6bd, 0x709,
+	0x756, 0x7a6, 0x7f7, 0x84b, 0x8a0, 0x8f7, 0x950, 0x9aa, 0xa07, 0xa65,
+	0xac6, 0xb28, 0xb8c, 0xbf2, 0xc5a, 0xcc3, 0xd2f, 0xd9d, 0xe0c, 0xe7e,
+	0xef1, 0xf67, 0xfde, 0x1057, 0x10d3, 0x1150, 0x11cf, 0x1250, 0x12d3,
+	0x1359, 0x13e0, 0x1469, 0x14f4, 0x1581, 0x1610, 0x16a2, 0x1735, 0x17ca,
+	0x1862, 0x18fb, 0x1996, 0x1a34, 0x1ad4, 0x1b75, 0x1c19, 0x1cbf, 0x1d67,
+	0x1e10, 0x1ebd, 0x1f6b, 0x201b, 0x20cd, 0x2182, 0x2238, 0x22f1, 0x23ac,
+	0x2469, 0x2528, 0x25e9, 0x26ac, 0x2771, 0x2839, 0x2903, 0x29cf, 0x2a9d,
+	0x2b6d, 0x2c3f, 0x2d14, 0x2deb, 0x2ec4, 0x2f9f, 0x307c, 0x315b, 0x323d,
+	0x3321, 0x3407, 0x34ef, 0x35da, 0x36c7, 0x37b6, 0x38a7, 0x399a, 0x3a90,
+	0x3b87, 0x3c82, 0x3d7e, 0x3e7c, 0x3f7d, 0x3, 0x11, 0x20, 0x2e, 0x3c, 0x4a,
+	0x58, 0x67, 0x75, 0x83, 0x91, 0xa0, 0xae, 0xbc, 0xca, 0xd9, 0xe7, 0xf5,
+	0x103, 0x112, 0x120, 0x12d, 0x13c, 0x14b, 0x15a, 0x16a, 0x17a, 0x18a,
+	0x19b, 0x1ad, 0x1be, 0x1d0, 0x1e3, 0x1f6, 0x209, 0x21c, 0x230, 0x245,
+	0x25a, 0x26f, 0x285, 0x29b, 0x2b1, 0x2c8, 0x2df, 0x2f7, 0x30f, 0x328,
+	0x341, 0x35a, 0x374, 0x38e, 0x3a9, 0x3c4, 0x3df, 0x3fb, 0x418, 0x434,
+	0x452, 0x46f, 0x48d, 0x4ac, 0x4cb, 0x4ea, 0x50a, 0x52a, 0x54b, 0x56c,
+	0x58d, 0x5af, 0x5d2, 0x5f5, 0x618, 0x63c, 0x660, 0x685, 0x6aa, 0x6cf,
+	0x6f5, 0x71c, 0x743, 0x76a, 0x792, 0x7ba, 0x7e3, 0x80c, 0x836, 0x860,
+	0x88a, 0x8b5, 0x8e1, 0x90d, 0x939, 0x966, 0x993, 0x9c1, 0x9f0, 0xa1e,
+	0xa4e, 0xa7d, 0xaad, 0xade, 0xb0f, 0xb41, 0xb73, 0xba5, 0xbd8, 0xc0c,
+	0xc40, 0xc74, 0xca9, 0xcde, 0xd14, 0xd4a, 0xd81, 0xdb8, 0xdf0, 0xe29,
+	0xe61, 0xe9a, 0xed4, 0xf0e, 0xf49, 0xf84, 0xfc0, 0xffc, 0x1039, 0x1076,
+	0x10b4, 0x10f2, 0x1130, 0x116f, 0x11af, 0x11ef, 0x1230, 0x1271, 0x12b2,
+	0x12f4, 0x1337, 0x137a, 0x13be, 0x1402, 0x1446, 0x148b, 0x14d1, 0x1517,
+	0x155e, 0x15a5, 0x15ec, 0x1635, 0x167d, 0x16c6, 0x1710, 0x175a, 0x17a5,
+	0x17f0, 0x183c, 0x1888, 0x18d5, 0x1922, 0x196f, 0x19be, 0x1a0c, 0x1a5c,
+	0x1aab, 0x1afc, 0x1b4d, 0x1b9e, 0x1bf0, 0x1c42, 0x1c95, 0x1ce8, 0x1d3c,
+	0x1d91, 0x1de6, 0x1e3b, 0x1e91, 0x1ee8, 0x1f3f, 0x1f96, 0x1fef, 0x2047,
+	0x20a0, 0x20fa, 0x2154, 0x21af, 0x220a, 0x2266, 0x22c2, 0x231f, 0x237d,
+	0x23db, 0x2439, 0x2498, 0x24f8, 0x2558, 0x25b8, 0x2619, 0x267b, 0x26dd,
+	0x2740, 0x27a3, 0x2807, 0x286b, 0x28d0, 0x2936, 0x299c, 0x2a02, 0x2a69,
+	0x2ad1, 0x2b39, 0x2ba1, 0x2c0b, 0x2c74, 0x2cdf, 0x2d49, 0x2db5, 0x2e21,
+	0x2e8d, 0x2efa, 0x2f68, 0x2fd6, 0x3044, 0x30b4, 0x3123, 0x3194, 0x3205,
+	0x3276, 0x32e8, 0x335a, 0x33cd, 0x3441, 0x34b5, 0x352a, 0x359f, 0x3615,
+	0x368b, 0x3702, 0x377a, 0x37f2, 0x386a, 0x38e3, 0x395d, 0x39d7, 0x3a52,
+	0x3acd, 0x3b49, 0x3bc6, 0x3c43, 0x3cc0, 0x3d3f, 0x3dbd, 0x3e3d, 0x3ebc,
+	0x3f3d, 0x3fbe, 0x0, 0x7, 0xe, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x40,
+	0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x80, 0x87, 0x8e, 0x95,
+	0x9c, 0xa3, 0xaa, 0xb1, 0xb9, 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea,
+	0xf1, 0xf9, 0x100, 0x107, 0x10e, 0x115, 0x11c, 0x123, 0x12a, 0x131, 0x138,
+	0x13f, 0x147, 0x14e, 0x156, 0x15e, 0x166, 0x16e, 0x176, 0x17e, 0x186,
+	0x18f, 0x197, 0x1a0, 0x1a8, 0x1b1, 0x1ba, 0x1c3, 0x1cc, 0x1d5, 0x1de,
+	0x1e7, 0x1f1, 0x1fa, 0x204, 0x20e, 0x217, 0x221, 0x22b, 0x236, 0x240,
+	0x24a, 0x255, 0x25f, 0x26a, 0x274, 0x27f, 0x28a, 0x295, 0x2a0, 0x2ac,
+	0x2b7, 0x2c2, 0x2ce, 0x2da, 0x2e5, 0x2f1, 0x2fd, 0x309, 0x315, 0x322,
+	0x32e, 0x33b, 0x347, 0x354, 0x361, 0x36d, 0x37a, 0x388, 0x395, 0x3a2,
+	0x3b0, 0x3bd, 0x3cb, 0x3d8, 0x3e6, 0x3f4, 0x402, 0x411, 0x41f, 0x42d,
+	0x43c, 0x44a, 0x459, 0x468, 0x477, 0x486, 0x495, 0x4a4, 0x4b3, 0x4c3,
+	0x4d3, 0x4e2, 0x4f2, 0x502, 0x512, 0x522, 0x532, 0x543, 0x553, 0x564,
+	0x574, 0x585, 0x596, 0x5a7, 0x5b8, 0x5c9, 0x5db, 0x5ec, 0x5fe, 0x60f,
+	0x621, 0x633, 0x645, 0x657, 0x669, 0x67b, 0x68e, 0x6a0, 0x6b3, 0x6c6,
+	0x6d9, 0x6ec, 0x6ff, 0x712, 0x726, 0x739, 0x74d, 0x760, 0x774, 0x788,
+	0x79c, 0x7b0, 0x7c4, 0x7d9, 0x7ed, 0x802, 0x816, 0x82b, 0x840, 0x855,
+	0x86a, 0x880, 0x895, 0x8ab, 0x8c0, 0x8d6, 0x8ec, 0x902, 0x918, 0x92e,
+	0x944, 0x95b, 0x971, 0x988, 0x99f, 0x9b6, 0x9cd, 0x9e4, 0x9fb, 0xa13,
+	0xa2a, 0xa42, 0xa59, 0xa71, 0xa89, 0xaa1, 0xab9, 0xad2, 0xaea, 0xb03,
+	0xb1b, 0xb34, 0xb4d, 0xb66, 0xb7f, 0xb98, 0xbb2, 0xbcb, 0xbe5, 0xbff,
+	0xc19, 0xc32, 0xc4d, 0xc67, 0xc81, 0xc9c, 0xcb6, 0xcd1, 0xcec, 0xd07,
+	0xd22, 0xd3d, 0xd58, 0xd73, 0xd8f, 0xdab, 0xdc6, 0xde2, 0xdfe, 0xe1a,
+	0xe37, 0xe53, 0xe70, 0xe8c, 0xea9, 0xec6, 0xee3, 0xf00, 0xf1d, 0xf3a,
+	0xf58, 0xf75, 0xf93, 0xfb1, 0xfcf, 0xfed, 0x100b, 0x102a, 0x1048, 0x1067,
+	0x1085, 0x10a4, 0x10c3, 0x10e2, 0x1101, 0x1121, 0x1140, 0x1160, 0x117f,
+	0x119f, 0x11bf, 0x11df, 0x11ff, 0x121f, 0x1240, 0x1260, 0x1281, 0x12a2,
+	0x12c3, 0x12e4, 0x1305, 0x1326, 0x1348, 0x1369, 0x138b, 0x13ad, 0x13cf,
+	0x13f1, 0x1413, 0x1435, 0x1458, 0x147a, 0x149d, 0x14c0, 0x14e3, 0x1506,
+	0x1529, 0x154c, 0x156f, 0x1593, 0x15b7, 0x15db, 0x15fe, 0x1623, 0x1647,
+	0x166b, 0x168f, 0x16b4, 0x16d9, 0x16fe, 0x1722, 0x1748, 0x176d, 0x1792,
+	0x17b8, 0x17dd, 0x1803, 0x1829, 0x184f, 0x1875, 0x189b, 0x18c1, 0x18e8,
+	0x190e, 0x1935, 0x195c, 0x1983, 0x19aa, 0x19d1, 0x19f9, 0x1a20, 0x1a48,
+	0x1a70, 0x1a97, 0x1ac0, 0x1ae8, 0x1b10, 0x1b38, 0x1b61, 0x1b8a, 0x1bb2,
+	0x1bdb, 0x1c04, 0x1c2e, 0x1c57, 0x1c80, 0x1caa, 0x1cd4, 0x1cfd, 0x1d27,
+	0x1d51, 0x1d7c, 0x1da6, 0x1dd1, 0x1dfb, 0x1e26, 0x1e51, 0x1e7c, 0x1ea7,
+	0x1ed2, 0x1efe, 0x1f29, 0x1f55, 0x1f81, 0x1fac, 0x1fd9, 0x2005, 0x2031,
+	0x205d, 0x208a, 0x20b7, 0x20e4, 0x2111, 0x213e, 0x216b, 0x2198, 0x21c6,
+	0x21f3, 0x2221, 0x224f, 0x227d, 0x22ab, 0x22da, 0x2308, 0x2337, 0x2365,
+	0x2394, 0x23c3, 0x23f2, 0x2421, 0x2451, 0x2480, 0x24b0, 0x24e0, 0x2510,
+	0x2540, 0x2570, 0x25a0, 0x25d0, 0x2601, 0x2632, 0x2663, 0x2693, 0x26c5,
+	0x26f6, 0x2727, 0x2759, 0x278a, 0x27bc, 0x27ee, 0x2820, 0x2852, 0x2884,
+	0x28b7, 0x28e9, 0x291c, 0x294f, 0x2982, 0x29b5, 0x29e8, 0x2a1c, 0x2a4f,
+	0x2a83, 0x2ab7, 0x2aeb, 0x2b1f, 0x2b53, 0x2b87, 0x2bbc, 0x2bf0, 0x2c25,
+	0x2c5a, 0x2c8f, 0x2cc4, 0x2cf9, 0x2d2f, 0x2d64, 0x2d9a, 0x2dd0, 0x2e06,
+	0x2e3c, 0x2e72, 0x2ea8, 0x2edf, 0x2f16, 0x2f4c, 0x2f83, 0x2fba, 0x2ff1,
+	0x3029, 0x3060, 0x3098, 0x30d0, 0x3107, 0x313f, 0x3178, 0x31b0, 0x31e8,
+	0x3221, 0x325a, 0x3292, 0x32cb, 0x3304, 0x333e, 0x3377, 0x33b1, 0x33ea,
+	0x3424, 0x345e, 0x3498, 0x34d2, 0x350d, 0x3547, 0x3582, 0x35bc, 0x35f7,
+	0x3632, 0x366e, 0x36a9, 0x36e4, 0x3720, 0x375c, 0x3798, 0x37d4, 0x3810,
+	0x384c, 0x3888, 0x38c5, 0x3902, 0x393f, 0x397c, 0x39b9, 0x39f6, 0x3a33,
+	0x3a71, 0x3aaf, 0x3aec, 0x3b2a, 0x3b68, 0x3ba7, 0x3be5, 0x3c24, 0x3c62,
+	0x3ca1, 0x3ce0, 0x3d1f, 0x3d5e, 0x3d9e, 0x3ddd, 0x3e1d, 0x3e5d, 0x3e9c,
+	0x3edc, 0x3f1d, 0x3f5d, 0x3f9e, 0x3fde, 0x6,
+	/* table descriptor */
+	0x61effbe9, 0xf,
+	/* table length */
+	0x400,
+	/* table data */
+	0x96, 0x8, 0x647, 0x0, 0x27, 0x1f8, 0x13cf, 0x0, 0x3, 0x13, 0x4f, 0x116,
+	0x387, 0xb24, 0x236d, 0x0, 0x0, 0x1, 0x5, 0xc, 0x1b, 0x38, 0x6d, 0xcd,
+	0x177, 0x2a4, 0x4b5, 0x85d, 0xed9, 0x1a77, 0x2f8b, 0x0, 0x0, 0x0, 0x0, 0x1,
+	0x2, 0x4, 0x6, 0xa, 0xf, 0x17, 0x21, 0x2f, 0x42, 0x5d, 0x80, 0xaf, 0xee,
+	0x143, 0x1b3, 0x248, 0x30d, 0x414, 0x570, 0x73f, 0x9a7, 0xcdc, 0x1126,
+	0x16e4, 0x1e9c, 0x2906, 0x3723, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x1, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x7, 0x9, 0xb, 0xe, 0x11, 0x15, 0x19,
+	0x1e, 0x24, 0x2b, 0x33, 0x3d, 0x48, 0x55, 0x65, 0x76, 0x8b, 0xa2, 0xbd,
+	0xdd, 0x101, 0x12b, 0x15c, 0x194, 0x1d4, 0x21e, 0x274, 0x2d7, 0x348, 0x3cb,
+	0x462, 0x50f, 0x5d8, 0x6be, 0x7c9, 0x8fc, 0xa5f, 0xbf8, 0xdd1, 0xff5,
+	0x126e, 0x154b, 0x189c, 0x1c76, 0x20ed, 0x261f, 0x2c29, 0x3331, 0x3b65,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x6,
+	0x7, 0x7, 0x8, 0x9, 0xa, 0xc, 0xd, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a,
+	0x1d, 0x1f, 0x22, 0x26, 0x29, 0x2d, 0x31, 0x36, 0x3b, 0x40, 0x45, 0x4b,
+	0x52, 0x59, 0x61, 0x69, 0x71, 0x7b, 0x85, 0x90, 0x9c, 0xa9, 0xb6, 0xc5,
+	0xd5, 0xe6, 0xf8, 0x10b, 0x120, 0x137, 0x14f, 0x169, 0x185, 0x1a3, 0x1c3,
+	0x1e6, 0x20b, 0x233, 0x25d, 0x28b, 0x2bd, 0x2f1, 0x32a, 0x367, 0x3a8,
+	0x3ef, 0x43a, 0x48b, 0x4e2, 0x53f, 0x5a3, 0x60e, 0x682, 0x6fe, 0x783,
+	0x811, 0x8ab, 0x950, 0xa01, 0xabf, 0xb8c, 0xc68, 0xd55, 0xe53, 0xf64,
+	0x108a, 0x11c7, 0x131b, 0x1489, 0x1613, 0x17bc, 0x1985, 0x1b71, 0x1d84,
+	0x1fbf, 0x2227, 0x24bf, 0x278b, 0x2a90, 0x2dd1, 0x3155, 0x3520, 0x3939,
+	0x3da6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2,
+	0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
+	0x6, 0x6, 0x6, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd,
+	0xd, 0xe, 0xf, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+	0x19, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x27, 0x28, 0x2a,
+	0x2c, 0x2e, 0x30, 0x32, 0x35, 0x37, 0x39, 0x3c, 0x3e, 0x41, 0x44, 0x47,
+	0x4a, 0x4d, 0x50, 0x54, 0x57, 0x5b, 0x5f, 0x63, 0x67, 0x6b, 0x6f, 0x74,
+	0x79, 0x7d, 0x83, 0x88, 0x8d, 0x93, 0x99, 0x9f, 0xa5, 0xac, 0xb3, 0xba,
+	0xc1, 0xc9, 0xd1, 0xd9, 0xe1, 0xea, 0xf3, 0xfc, 0x106, 0x110, 0x11b, 0x126,
+	0x131, 0x13d, 0x149, 0x155, 0x162, 0x170, 0x17e, 0x18c, 0x19b, 0x1ab,
+	0x1bb, 0x1cc, 0x1dd, 0x1ef, 0x201, 0x215, 0x228, 0x23d, 0x252, 0x269,
+	0x280, 0x297, 0x2b0, 0x2c9, 0x2e4, 0x2ff, 0x31c, 0x339, 0x357, 0x377,
+	0x398, 0x3ba, 0x3dd, 0x401, 0x427, 0x44e, 0x476, 0x4a0, 0x4cb, 0x4f8,
+	0x527, 0x557, 0x589, 0x5bd, 0x5f3, 0x62a, 0x664, 0x6a0, 0x6de, 0x71e,
+	0x760, 0x7a5, 0x7ed, 0x837, 0x884, 0x8d3, 0x926, 0x97b, 0x9d4, 0xa2f,
+	0xa8f, 0xaf1, 0xb58, 0xbc2, 0xc30, 0xca2, 0xd18, 0xd92, 0xe11, 0xe95,
+	0xf1e, 0xfac, 0x103f, 0x10d7, 0x1175, 0x1219, 0x12c3, 0x1374, 0x142b,
+	0x14e9, 0x15ae, 0x167b, 0x174f, 0x182b, 0x1910, 0x19fd, 0x1af3, 0x1bf2,
+	0x1cfb, 0x1e0f, 0x1f2c, 0x2055, 0x2189, 0x22c9, 0x2415, 0x256d, 0x26d3,
+	0x2847, 0x29c9, 0x2b5a, 0x2cfb, 0x2eac, 0x306e, 0x3241, 0x3426, 0x361f,
+	0x382b, 0x3a4c, 0x3c83, 0x3ecf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1,
+	0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
+	0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3,
+	0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
+	0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8,
+	0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc,
+	0xc, 0xc, 0xd, 0xd, 0xd, 0xe, 0xe, 0xf, 0xf, 0xf, 0x10, 0x10, 0x11, 0x11,
+	0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17,
+	0x17, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1c, 0x1d, 0x1e, 0x1e,
+	0x1f, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24, 0x25, 0x26, 0x27, 0x28,
+	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+	0x35, 0x36, 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, 0x42, 0x43,
+	0x45, 0x46, 0x48, 0x49, 0x4b, 0x4c, 0x4e, 0x4f, 0x51, 0x53, 0x54, 0x56,
+	0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
+	0x70, 0x73, 0x75, 0x77, 0x7a, 0x7c, 0x7f, 0x81, 0x84, 0x86, 0x89, 0x8c,
+	0x8f, 0x92, 0x94, 0x97, 0x9a, 0x9d, 0xa1, 0xa4, 0xa7, 0xaa, 0xae, 0xb1,
+	0xb4, 0xb8, 0xbc, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xdf,
+	0xe3, 0xe8, 0xec, 0xf1, 0xf5, 0xfa, 0xff, 0x104, 0x109, 0x10e, 0x113,
+	0x118, 0x11e, 0x123, 0x129, 0x12e, 0x134, 0x13a, 0x140, 0x146, 0x14c,
+	0x152, 0x159, 0x15f, 0x166, 0x16c, 0x173, 0x17a, 0x181, 0x189, 0x190,
+	0x197, 0x19f, 0x1a7, 0x1af, 0x1b7, 0x1bf, 0x1c7, 0x1d0, 0x1d8, 0x1e1,
+	0x1ea, 0x1f3, 0x1fd, 0x206, 0x210, 0x219, 0x223, 0x22e, 0x238, 0x242,
+	0x24d, 0x258, 0x263, 0x26e, 0x27a, 0x285, 0x291, 0x29d, 0x2aa, 0x2b6,
+	0x2c3, 0x2d0, 0x2dd, 0x2eb, 0x2f8, 0x306, 0x314, 0x323, 0x332, 0x341,
+	0x350, 0x35f, 0x36f, 0x37f, 0x38f, 0x3a0, 0x3b1, 0x3c2, 0x3d4, 0x3e6,
+	0x3f8, 0x40a, 0x41d, 0x430, 0x444, 0x458, 0x46c, 0x480, 0x495, 0x4ab,
+	0x4c0, 0x4d6, 0x4ed, 0x504, 0x51b, 0x533, 0x54b, 0x564, 0x57d, 0x596,
+	0x5b0, 0x5ca, 0x5e5, 0x600, 0x61c, 0x639, 0x655, 0x673, 0x691, 0x6af,
+	0x6ce, 0x6ee, 0x70e, 0x72e, 0x750, 0x771, 0x794, 0x7b7, 0x7db, 0x7ff,
+	0x824, 0x84a, 0x870, 0x897, 0x8bf, 0x8e7, 0x911, 0x93b, 0x965, 0x991,
+	0x9bd, 0x9ea, 0xa18, 0xa47, 0xa76, 0xaa7, 0xad8, 0xb0a, 0xb3e, 0xb72,
+	0xba7, 0xbdd, 0xc14, 0xc4c, 0xc85, 0xcbf, 0xcfa, 0xd36, 0xd73, 0xdb2,
+	0xdf1, 0xe32, 0xe74, 0xeb7, 0xefb, 0xf41, 0xf88, 0xfd0, 0x1019, 0x1064,
+	0x10b1, 0x10fe, 0x114d, 0x119e, 0x11f0, 0x1243, 0x1298, 0x12ef, 0x1347,
+	0x13a1, 0x13fd, 0x145a, 0x14b9, 0x151a, 0x157c, 0x15e1, 0x1647, 0x16af,
+	0x1719, 0x1785, 0x17f3, 0x1863, 0x18d6, 0x194a, 0x19c1, 0x1a39, 0x1ab4,
+	0x1b32, 0x1bb1, 0x1c34, 0x1cb8, 0x1d3f, 0x1dc9, 0x1e55, 0x1ee4, 0x1f75,
+	0x200a, 0x20a1, 0x213b, 0x21d8, 0x2277, 0x231a, 0x23c0, 0x2469, 0x2516,
+	0x25c6, 0x2679, 0x272f, 0x27e9, 0x28a6, 0x2967, 0x2a2c, 0x2af5, 0x2bc1,
+	0x2c91, 0x2d66, 0x2e3e, 0x2f1b, 0x2ffc, 0x30e1, 0x31ca, 0x32b9, 0x33ab,
+	0x34a3, 0x359f, 0x36a0, 0x37a6, 0x38b2, 0x39c2, 0x3ad8, 0x3bf3, 0x3d14,
+	0x3e3a, 0x3f66, 0x6,
+	/* table descriptor */
+	0xf0effbe9, 0xf,
+	/* table length */
+	0x400,
+	/* table data */
+	0xdab, 0x33c, 0x216a, 0xe8, 0x766, 0x1646, 0x2f44, 0x52, 0x1dc, 0x512,
+	0xa41, 0x11aa, 0x1b84, 0x27fd, 0x3743, 0x26, 0x92, 0x155, 0x27e, 0x418,
+	0x62b, 0x8c2, 0xbe4, 0xf97, 0x13e4, 0x18d0, 0x1e61, 0x249e, 0x2b8a, 0x332c,
+	0x3b89, 0x12, 0x3a, 0x70, 0xba, 0x11c, 0x196, 0x22a, 0x2da, 0x3a6, 0x491,
+	0x59a, 0x6c4, 0x810, 0x97d, 0xb0e, 0xcc3, 0xe9c, 0x109c, 0x12c2, 0x1510,
+	0x1786, 0x1a25, 0x1ced, 0x1fe0, 0x22fe, 0x2648, 0x29be, 0x2d61, 0x3132,
+	0x3532, 0x3960, 0x3dbe, 0x8, 0x1c, 0x30, 0x46, 0x60, 0x80, 0xa5, 0xd0,
+	0x101, 0x138, 0x175, 0x1b8, 0x202, 0x253, 0x2ab, 0x30a, 0x370, 0x3de,
+	0x453, 0x4d0, 0x555, 0x5e2, 0x677, 0x714, 0x7ba, 0x868, 0x91e, 0x9de,
+	0xaa6, 0xb77, 0xc52, 0xd35, 0xe22, 0xf19, 0x1018, 0x1122, 0x1235, 0x1352,
+	0x1479, 0x15aa, 0x16e4, 0x182a, 0x1979, 0x1ad3, 0x1c37, 0x1da6, 0x1f1f,
+	0x20a4, 0x2233, 0x23cc, 0x2571, 0x2721, 0x28dc, 0x2aa3, 0x2c74, 0x2e51,
+	0x303a, 0x322e, 0x342e, 0x3639, 0x3850, 0x3a73, 0x3ca2, 0x3edd, 0x3, 0xd,
+	0x17, 0x21, 0x2b, 0x35, 0x40, 0x4c, 0x59, 0x68, 0x78, 0x89, 0x9c, 0xb0,
+	0xc5, 0xdc, 0xf4, 0x10e, 0x12a, 0x146, 0x165, 0x185, 0x1a7, 0x1ca, 0x1ef,
+	0x216, 0x23e, 0x269, 0x294, 0x2c2, 0x2f2, 0x323, 0x356, 0x38b, 0x3c2,
+	0x3fb, 0x435, 0x472, 0x4b0, 0x4f1, 0x533, 0x577, 0x5be, 0x606, 0x651,
+	0x69d, 0x6ec, 0x73d, 0x78f, 0x7e4, 0x83b, 0x895, 0x8f0, 0x94d, 0x9ad,
+	0xa0f, 0xa73, 0xada, 0xb42, 0xbad, 0xc1a, 0xc8a, 0xcfc, 0xd70, 0xde6,
+	0xe5f, 0xeda, 0xf58, 0xfd8, 0x105a, 0x10df, 0x1166, 0x11ef, 0x127b, 0x130a,
+	0x139b, 0x142e, 0x14c4, 0x155c, 0x15f7, 0x1695, 0x1735, 0x17d7, 0x187d,
+	0x1924, 0x19cf, 0x1a7b, 0x1b2b, 0x1bdd, 0x1c92, 0x1d49, 0x1e03, 0x1ec0,
+	0x1f7f, 0x2042, 0x2106, 0x21ce, 0x2298, 0x2365, 0x2435, 0x2507, 0x25dc,
+	0x26b4, 0x278f, 0x286d, 0x294d, 0x2a30, 0x2b16, 0x2bff, 0x2ceb, 0x2dd9,
+	0x2eca, 0x2fbf, 0x30b6, 0x31b0, 0x32ad, 0x33ac, 0x34af, 0x35b5, 0x36bd,
+	0x37c9, 0x38d8, 0x39e9, 0x3afd, 0x3c15, 0x3d2f, 0x3e4d, 0x3f6d, 0x1, 0x6,
+	0xb, 0x10, 0x15, 0x1a, 0x1e, 0x23, 0x28, 0x2d, 0x32, 0x37, 0x3d, 0x43,
+	0x49, 0x4f, 0x56, 0x5d, 0x64, 0x6c, 0x74, 0x7c, 0x85, 0x8e, 0x97, 0xa0,
+	0xaa, 0xb5, 0xc0, 0xcb, 0xd6, 0xe2, 0xee, 0xfb, 0x108, 0x115, 0x123, 0x131,
+	0x13f, 0x14e, 0x15d, 0x16d, 0x17d, 0x18d, 0x19e, 0x1af, 0x1c1, 0x1d3,
+	0x1e6, 0x1f9, 0x20c, 0x220, 0x234, 0x249, 0x25e, 0x273, 0x289, 0x2a0,
+	0x2b7, 0x2ce, 0x2e6, 0x2fe, 0x316, 0x32f, 0x349, 0x363, 0x37e, 0x398,
+	0x3b4, 0x3d0, 0x3ec, 0x409, 0x426, 0x444, 0x462, 0x481, 0x4a0, 0x4c0,
+	0x4e0, 0x501, 0x522, 0x544, 0x566, 0x589, 0x5ac, 0x5d0, 0x5f4, 0x619,
+	0x63e, 0x664, 0x68a, 0x6b1, 0x6d8, 0x700, 0x728, 0x751, 0x77a, 0x7a4,
+	0x7cf, 0x7fa, 0x825, 0x851, 0x87e, 0x8ab, 0x8d9, 0x907, 0x936, 0x965,
+	0x995, 0x9c5, 0x9f6, 0xa28, 0xa5a, 0xa8d, 0xac0, 0xaf4, 0xb28, 0xb5d,
+	0xb92, 0xbc8, 0xbff, 0xc36, 0xc6e, 0xca6, 0xcdf, 0xd19, 0xd53, 0xd8d,
+	0xdc8, 0xe04, 0xe41, 0xe7e, 0xebb, 0xef9, 0xf38, 0xf77, 0xfb7, 0xff8,
+	0x1039, 0x107b, 0x10bd, 0x1100, 0x1144, 0x1188, 0x11cd, 0x1212, 0x1258,
+	0x129f, 0x12e6, 0x132e, 0x1376, 0x13bf, 0x1409, 0x1453, 0x149e, 0x14ea,
+	0x1536, 0x1583, 0x15d0, 0x161e, 0x166d, 0x16bd, 0x170d, 0x175d, 0x17af,
+	0x1800, 0x1853, 0x18a6, 0x18fa, 0x194f, 0x19a4, 0x19fa, 0x1a50, 0x1aa7,
+	0x1aff, 0x1b57, 0x1bb0, 0x1c0a, 0x1c64, 0x1cbf, 0x1d1b, 0x1d78, 0x1dd5,
+	0x1e32, 0x1e91, 0x1ef0, 0x1f4f, 0x1fb0, 0x2011, 0x2072, 0x20d5, 0x2138,
+	0x219c, 0x2200, 0x2265, 0x22cb, 0x2331, 0x2399, 0x2401, 0x2469, 0x24d2,
+	0x253c, 0x25a7, 0x2612, 0x267e, 0x26eb, 0x2758, 0x27c6, 0x2835, 0x28a4,
+	0x2915, 0x2985, 0x29f7, 0x2a69, 0x2adc, 0x2b50, 0x2bc4, 0x2c3a, 0x2caf,
+	0x2d26, 0x2d9d, 0x2e15, 0x2e8e, 0x2f07, 0x2f81, 0x2ffc, 0x3078, 0x30f4,
+	0x3171, 0x31ef, 0x326d, 0x32ec, 0x336c, 0x33ed, 0x346e, 0x34f0, 0x3573,
+	0x35f7, 0x367b, 0x3700, 0x3786, 0x380c, 0x3894, 0x391c, 0x39a4, 0x3a2e,
+	0x3ab8, 0x3b43, 0x3bcf, 0x3c5b, 0x3ce8, 0x3d76, 0x3e05, 0x3e95, 0x3f25,
+	0x3fb6, 0x0, 0x2, 0x4, 0x7, 0x9, 0xc, 0xe, 0x11, 0x13, 0x16, 0x18, 0x1b,
+	0x1d, 0x20, 0x22, 0x25, 0x27, 0x2a, 0x2c, 0x2f, 0x31, 0x34, 0x36, 0x39,
+	0x3c, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d, 0x51, 0x54, 0x57, 0x5b, 0x5f,
+	0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76, 0x7a, 0x7e, 0x82, 0x87, 0x8b, 0x90,
+	0x94, 0x99, 0x9e, 0xa3, 0xa8, 0xad, 0xb2, 0xb7, 0xbd, 0xc2, 0xc8, 0xcd,
+	0xd3, 0xd9, 0xdf, 0xe5, 0xeb, 0xf1, 0xf7, 0xfe, 0x104, 0x10b, 0x111, 0x118,
+	0x11f, 0x126, 0x12d, 0x134, 0x13b, 0x143, 0x14a, 0x152, 0x159, 0x161,
+	0x169, 0x171, 0x179, 0x181, 0x189, 0x192, 0x19a, 0x1a2, 0x1ab, 0x1b4,
+	0x1bd, 0x1c6, 0x1cf, 0x1d8, 0x1e1, 0x1ea, 0x1f4, 0x1fe, 0x207, 0x211,
+	0x21b, 0x225, 0x22f, 0x239, 0x244, 0x24e, 0x258, 0x263, 0x26e, 0x279,
+	0x284, 0x28f, 0x29a, 0x2a5, 0x2b1, 0x2bc, 0x2c8, 0x2d4, 0x2e0, 0x2ec,
+	0x2f8, 0x304, 0x310, 0x31d, 0x329, 0x336, 0x343, 0x350, 0x35d, 0x36a,
+	0x377, 0x384, 0x392, 0x39f, 0x3ad, 0x3bb, 0x3c9, 0x3d7, 0x3e5, 0x3f3,
+	0x402, 0x410, 0x41f, 0x42e, 0x43d, 0x44c, 0x45b, 0x46a, 0x479, 0x489,
+	0x499, 0x4a8, 0x4b8, 0x4c8, 0x4d8, 0x4e8, 0x4f9, 0x509, 0x51a, 0x52b,
+	0x53b, 0x54c, 0x55e, 0x56f, 0x580, 0x592, 0x5a3, 0x5b5, 0x5c7, 0x5d9,
+	0x5eb, 0x5fd, 0x60f, 0x622, 0x635, 0x647, 0x65a, 0x66d, 0x680, 0x694,
+	0x6a7, 0x6bb, 0x6ce, 0x6e2, 0x6f6, 0x70a, 0x71e, 0x732, 0x747, 0x75b,
+	0x770, 0x785, 0x79a, 0x7af, 0x7c4, 0x7da, 0x7ef, 0x805, 0x81a, 0x830,
+	0x846, 0x85d, 0x873, 0x889, 0x8a0, 0x8b7, 0x8cd, 0x8e4, 0x8fb, 0x913,
+	0x92a, 0x942, 0x959, 0x971, 0x989, 0x9a1, 0x9b9, 0x9d2, 0x9ea, 0xa03,
+	0xa1c, 0xa34, 0xa4d, 0xa67, 0xa80, 0xa99, 0xab3, 0xacd, 0xae7, 0xb01,
+	0xb1b, 0xb35, 0xb50, 0xb6a, 0xb85, 0xba0, 0xbbb, 0xbd6, 0xbf1, 0xc0d,
+	0xc28, 0xc44, 0xc60, 0xc7c, 0xc98, 0xcb4, 0xcd1, 0xced, 0xd0a, 0xd27,
+	0xd44, 0xd61, 0xd7e, 0xd9c, 0xdba, 0xdd7, 0xdf5, 0xe13, 0xe31, 0xe50,
+	0xe6e, 0xe8d, 0xeac, 0xecb, 0xeea, 0xf09, 0xf28, 0xf48, 0xf68, 0xf87,
+	0xfa7, 0xfc7, 0xfe8, 0x1008, 0x1029, 0x1049, 0x106a, 0x108b, 0x10ad,
+	0x10ce, 0x10ef, 0x1111, 0x1133, 0x1155, 0x1177, 0x1199, 0x11bb, 0x11de,
+	0x1201, 0x1223, 0x1246, 0x126a, 0x128d, 0x12b0, 0x12d4, 0x12f8, 0x131c,
+	0x1340, 0x1364, 0x1388, 0x13ad, 0x13d2, 0x13f6, 0x141c, 0x1441, 0x1466,
+	0x148b, 0x14b1, 0x14d7, 0x14fd, 0x1523, 0x1549, 0x1570, 0x1596, 0x15bd,
+	0x15e4, 0x160b, 0x1632, 0x1659, 0x1681, 0x16a9, 0x16d1, 0x16f9, 0x1721,
+	0x1749, 0x1771, 0x179a, 0x17c3, 0x17ec, 0x1815, 0x183e, 0x1868, 0x1891,
+	0x18bb, 0x18e5, 0x190f, 0x1939, 0x1964, 0x198e, 0x19b9, 0x19e4, 0x1a0f,
+	0x1a3a, 0x1a66, 0x1a91, 0x1abd, 0x1ae9, 0x1b15, 0x1b41, 0x1b6d, 0x1b9a,
+	0x1bc7, 0x1bf4, 0x1c21, 0x1c4e, 0x1c7b, 0x1ca9, 0x1cd6, 0x1d04, 0x1d32,
+	0x1d60, 0x1d8f, 0x1dbd, 0x1dec, 0x1e1b, 0x1e4a, 0x1e79, 0x1ea8, 0x1ed8,
+	0x1f07, 0x1f37, 0x1f67, 0x1f98, 0x1fc8, 0x1ff8, 0x2029, 0x205a, 0x208b,
+	0x20bc, 0x20ee, 0x211f, 0x2151, 0x2183, 0x21b5, 0x21e7, 0x2219, 0x224c,
+	0x227f, 0x22b2, 0x22e5, 0x2318, 0x234b, 0x237f, 0x23b3, 0x23e6, 0x241b,
+	0x244f, 0x2483, 0x24b8, 0x24ed, 0x2522, 0x2557, 0x258c, 0x25c2, 0x25f7,
+	0x262d, 0x2663, 0x2699, 0x26cf, 0x2706, 0x273d, 0x2774, 0x27ab, 0x27e2,
+	0x2819, 0x2851, 0x2888, 0x28c0, 0x28f8, 0x2931, 0x2969, 0x29a2, 0x29db,
+	0x2a14, 0x2a4d, 0x2a86, 0x2ac0, 0x2af9, 0x2b33, 0x2b6d, 0x2ba7, 0x2be2,
+	0x2c1c, 0x2c57, 0x2c92, 0x2ccd, 0x2d08, 0x2d44, 0x2d7f, 0x2dbb, 0x2df7,
+	0x2e33, 0x2e70, 0x2eac, 0x2ee9, 0x2f26, 0x2f63, 0x2fa0, 0x2fdd, 0x301b,
+	0x3059, 0x3097, 0x30d5, 0x3113, 0x3152, 0x3190, 0x31cf, 0x320e, 0x324e,
+	0x328d, 0x32cd, 0x330c, 0x334c, 0x338c, 0x33cd, 0x340d, 0x344e, 0x348f,
+	0x34d0, 0x3511, 0x3552, 0x3594, 0x35d6, 0x3618, 0x365a, 0x369c, 0x36df,
+	0x3721, 0x3764, 0x37a7, 0x37eb, 0x382e, 0x3872, 0x38b6, 0x38fa, 0x393e,
+	0x3982, 0x39c7, 0x3a0b, 0x3a50, 0x3a95, 0x3adb, 0x3b20, 0x3b66, 0x3bac,
+	0x3bf2, 0x3c38, 0x3c7e, 0x3cc5, 0x3d0c, 0x3d53, 0x3d9a, 0x3de1, 0x3e29,
+	0x3e71, 0x3eb9, 0x3f01, 0x3f49, 0x3f91, 0x3fda, 0x6,
+	/* table descriptor */
+	0x7baffbea, 0x6,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x2646, 0x4b23, 0xe98, 0xffffea68, 0xffffd59b, 0x4000, 0x4000,
+	0xffffca6a, 0xfffff599, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0x7baffbea, 0x8,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0,
+	0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbaffbea, 0x0,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x21a1, 0x56c9, 0x798, 0xffffee22, 0xffffd1e1, 0x4000, 0x4000,
+	0xffffc527, 0xfffffadc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0x7baffbea, 0x1,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x1b37, 0x5b8c, 0x93e, 0xfffff157, 0xffffceac, 0x4000, 0x4000,
+	0xffffc5e0, 0xfffffa23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfb6ffbea, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x8000, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbefe8e1, 0xf,
+	/* table length */
+	0x402,
+	/* table data */
+	0x3, 0x0, 0xea8, 0x12aa, 0x1500, 0x16ab, 0x1815, 0x1900, 0x1a0b, 0x1aab,
+	0x1b60, 0x1c15, 0x1c85, 0x1d00, 0x1d86, 0x1e0b, 0x1e58, 0x1eab, 0x1f03,
+	0x1f60, 0x1fc3, 0x2015, 0x204c, 0x2085, 0x20c2, 0x2100, 0x2142, 0x2186,
+	0x21cc, 0x220b, 0x2231, 0x2258, 0x2281, 0x22ab, 0x22d6, 0x2303, 0x2331,
+	0x2360, 0x2391, 0x23c3, 0x23f6, 0x2415, 0x2430, 0x244c, 0x2468, 0x2485,
+	0x24a3, 0x24c2, 0x24e1, 0x2500, 0x2521, 0x2542, 0x2563, 0x2586, 0x25a9,
+	0x25cc, 0x25f1, 0x260b, 0x261e, 0x2631, 0x2644, 0x2658, 0x266c, 0x2681,
+	0x2696, 0x26ab, 0x26c0, 0x26d6, 0x26ec, 0x2703, 0x271a, 0x2731, 0x2748,
+	0x2760, 0x2779, 0x2791, 0x27aa, 0x27c3, 0x27dd, 0x27f6, 0x2808, 0x2815,
+	0x2823, 0x2830, 0x283e, 0x284c, 0x285a, 0x2868, 0x2877, 0x2885, 0x2894,
+	0x28a3, 0x28b2, 0x28c2, 0x28d1, 0x28e1, 0x28f0, 0x2900, 0x2910, 0x2921,
+	0x2931, 0x2942, 0x2952, 0x2963, 0x2974, 0x2986, 0x2997, 0x29a9, 0x29bb,
+	0x29cc, 0x29df, 0x29f1, 0x2a01, 0x2a0b, 0x2a14, 0x2a1e, 0x2a27, 0x2a31,
+	0x2a3a, 0x2a44, 0x2a4e, 0x2a58, 0x2a62, 0x2a6c, 0x2a76, 0x2a81, 0x2a8b,
+	0x2a96, 0x2aa0, 0x2aab, 0x2ab6, 0x2ac0, 0x2acb, 0x2ad6, 0x2ae1, 0x2aec,
+	0x2af8, 0x2b03, 0x2b0e, 0x2b1a, 0x2b25, 0x2b31, 0x2b3d, 0x2b48, 0x2b54,
+	0x2b60, 0x2b6c, 0x2b79, 0x2b85, 0x2b91, 0x2b9d, 0x2baa, 0x2bb6, 0x2bc3,
+	0x2bd0, 0x2bdd, 0x2bea, 0x2bf6, 0x2c02, 0x2c08, 0x2c0f, 0x2c15, 0x2c1c,
+	0x2c23, 0x2c2a, 0x2c30, 0x2c37, 0x2c3e, 0x2c45, 0x2c4c, 0x2c53, 0x2c5a,
+	0x2c61, 0x2c68, 0x2c70, 0x2c77, 0x2c7e, 0x2c85, 0x2c8d, 0x2c94, 0x2c9c,
+	0x2ca3, 0x2cab, 0x2cb2, 0x2cba, 0x2cc2, 0x2cc9, 0x2cd1, 0x2cd9, 0x2ce1,
+	0x2ce8, 0x2cf0, 0x2cf8, 0x2d00, 0x2d08, 0x2d10, 0x2d18, 0x2d21, 0x2d29,
+	0x2d31, 0x2d39, 0x2d42, 0x2d4a, 0x2d52, 0x2d5b, 0x2d63, 0x2d6c, 0x2d74,
+	0x2d7d, 0x2d86, 0x2d8e, 0x2d97, 0x2da0, 0x2da9, 0x2db2, 0x2dbb, 0x2dc3,
+	0x2dcc, 0x2dd5, 0x2ddf, 0x2de8, 0x2df1, 0x2dfa, 0x2e01, 0x2e06, 0x2e0b,
+	0x2e0f, 0x2e14, 0x2e19, 0x2e1e, 0x2e22, 0x2e27, 0x2e2c, 0x2e31, 0x2e36,
+	0x2e3a, 0x2e3f, 0x2e44, 0x2e49, 0x2e4e, 0x2e53, 0x2e58, 0x2e5d, 0x2e62,
+	0x2e67, 0x2e6c, 0x2e71, 0x2e76, 0x2e7c, 0x2e81, 0x2e86, 0x2e8b, 0x2e90,
+	0x2e96, 0x2e9b, 0x2ea0, 0x2ea6, 0x2eab, 0x2eb0, 0x2eb6, 0x2ebb, 0x2ec0,
+	0x2ec6, 0x2ecb, 0x2ed1, 0x2ed6, 0x2edc, 0x2ee1, 0x2ee7, 0x2eec, 0x2ef2,
+	0x2ef8, 0x2efd, 0x2f03, 0x2f09, 0x2f0e, 0x2f14, 0x2f1a, 0x2f20, 0x2f25,
+	0x2f2b, 0x2f31, 0x2f37, 0x2f3d, 0x2f43, 0x2f48, 0x2f4e, 0x2f54, 0x2f5a,
+	0x2f60, 0x2f66, 0x2f6c, 0x2f72, 0x2f79, 0x2f7f, 0x2f85, 0x2f8b, 0x2f91,
+	0x2f97, 0x2f9d, 0x2fa4, 0x2faa, 0x2fb0, 0x2fb6, 0x2fbd, 0x2fc3, 0x2fc9,
+	0x2fd0, 0x2fd6, 0x2fdd, 0x2fe3, 0x2fea, 0x2ff0, 0x2ff6, 0x2ffd, 0x3002,
+	0x3005, 0x3008, 0x300b, 0x300f, 0x3012, 0x3015, 0x3019, 0x301c, 0x301f,
+	0x3023, 0x3026, 0x302a, 0x302d, 0x3030, 0x3034, 0x3037, 0x303b, 0x303e,
+	0x3042, 0x3045, 0x3049, 0x304c, 0x3050, 0x3053, 0x3057, 0x305a, 0x305e,
+	0x3061, 0x3065, 0x3068, 0x306c, 0x3070, 0x3073, 0x3077, 0x307b, 0x307e,
+	0x3082, 0x3085, 0x3089, 0x308d, 0x3091, 0x3094, 0x3098, 0x309c, 0x309f,
+	0x30a3, 0x30a7, 0x30ab, 0x30ae, 0x30b2, 0x30b6, 0x30ba, 0x30be, 0x30c2,
+	0x30c5, 0x30c9, 0x30cd, 0x30d1, 0x30d5, 0x30d9, 0x30dd, 0x30e1, 0x30e4,
+	0x30e8, 0x30ec, 0x30f0, 0x30f4, 0x30f8, 0x30fc, 0x3100, 0x3104, 0x3108,
+	0x310c, 0x3110, 0x3114, 0x3118, 0x311d, 0x3121, 0x3125, 0x3129, 0x312d,
+	0x3131, 0x3135, 0x3139, 0x313d, 0x3142, 0x3146, 0x314a, 0x314e, 0x3152,
+	0x3157, 0x315b, 0x315f, 0x3163, 0x3168, 0x316c, 0x3170, 0x3174, 0x3179,
+	0x317d, 0x3181, 0x3186, 0x318a, 0x318e, 0x3193, 0x3197, 0x319c, 0x31a0,
+	0x31a4, 0x31a9, 0x31ad, 0x31b2, 0x31b6, 0x31bb, 0x31bf, 0x31c3, 0x31c8,
+	0x31cc, 0x31d1, 0x31d5, 0x31da, 0x31df, 0x31e3, 0x31e8, 0x31ec, 0x31f1,
+	0x31f5, 0x31fa, 0x31ff, 0x3201, 0x3204, 0x3206, 0x3208, 0x320b, 0x320d,
+	0x320f, 0x3212, 0x3214, 0x3216, 0x3219, 0x321b, 0x321e, 0x3220, 0x3222,
+	0x3225, 0x3227, 0x3229, 0x322c, 0x322e, 0x3231, 0x3233, 0x3236, 0x3238,
+	0x323a, 0x323d, 0x323f, 0x3242, 0x3244, 0x3247, 0x3249, 0x324c, 0x324e,
+	0x3251, 0x3253, 0x3256, 0x3258, 0x325b, 0x325d, 0x3260, 0x3262, 0x3265,
+	0x3267, 0x326a, 0x326c, 0x326f, 0x3271, 0x3274, 0x3276, 0x3279, 0x327c,
+	0x327e, 0x3281, 0x3283, 0x3286, 0x3289, 0x328b, 0x328e, 0x3290, 0x3293,
+	0x3296, 0x3298, 0x329b, 0x329e, 0x32a0, 0x32a3, 0x32a6, 0x32a8, 0x32ab,
+	0x32ae, 0x32b0, 0x32b3, 0x32b6, 0x32b8, 0x32bb, 0x32be, 0x32c1, 0x32c4,
+	0x32c6, 0x32c9, 0x32cc, 0x32cf, 0x32d2, 0x32d5, 0x32d8, 0x32da, 0x32dd,
+	0x32e0, 0x32e3, 0x32e6, 0x32e9, 0x32ec, 0x32ef, 0x32f2, 0x32f6, 0x32f9,
+	0x32fc, 0x32ff, 0x3302, 0x3305, 0x3308, 0x330c, 0x330f, 0x3312, 0x3315,
+	0x3318, 0x331c, 0x331f, 0x3322, 0x3326, 0x3329, 0x332c, 0x3330, 0x3333,
+	0x3337, 0x333a, 0x333e, 0x3341, 0x3345, 0x3348, 0x334c, 0x334f, 0x3353,
+	0x3356, 0x335a, 0x335e, 0x3361, 0x3365, 0x3369, 0x336c, 0x3370, 0x3374,
+	0x3378, 0x337c, 0x337f, 0x3383, 0x3387, 0x338b, 0x338f, 0x3393, 0x3397,
+	0x339b, 0x339f, 0x33a3, 0x33a7, 0x33ab, 0x33af, 0x33b3, 0x33b7, 0x33bb,
+	0x33bf, 0x33c4, 0x33c8, 0x33cc, 0x33d0, 0x33d5, 0x33d9, 0x33dd, 0x33e2,
+	0x33e6, 0x33eb, 0x33ef, 0x33f3, 0x33f8, 0x33fc, 0x3400, 0x3402, 0x3405,
+	0x3407, 0x3409, 0x340c, 0x340e, 0x3410, 0x3413, 0x3415, 0x3418, 0x341a,
+	0x341c, 0x341f, 0x3421, 0x3424, 0x3426, 0x3429, 0x342b, 0x342e, 0x3430,
+	0x3433, 0x3435, 0x3438, 0x343a, 0x343d, 0x3440, 0x3442, 0x3445, 0x3448,
+	0x344a, 0x344d, 0x3450, 0x3452, 0x3455, 0x3458, 0x345b, 0x345d, 0x3460,
+	0x3463, 0x3466, 0x3469, 0x346b, 0x346e, 0x3471, 0x3474, 0x3477, 0x347a,
+	0x347d, 0x3480, 0x3483, 0x3486, 0x3489, 0x348c, 0x348f, 0x3492, 0x3495,
+	0x3498, 0x349b, 0x349e, 0x34a2, 0x34a5, 0x34a8, 0x34ab, 0x34ae, 0x34b2,
+	0x34b5, 0x34b8, 0x34bb, 0x34bf, 0x34c2, 0x34c5, 0x34c9, 0x34cc, 0x34cf,
+	0x34d3, 0x34d6, 0x34da, 0x34dd, 0x34e1, 0x34e4, 0x34e8, 0x34eb, 0x34ef,
+	0x34f2, 0x34f6, 0x34fa, 0x34fd, 0x3501, 0x3505, 0x3508, 0x350c, 0x3510,
+	0x3514, 0x3517, 0x351b, 0x351f, 0x3523, 0x3527, 0x352b, 0x352f, 0x3532,
+	0x3536, 0x353a, 0x353e, 0x3542, 0x3546, 0x354b, 0x354f, 0x3553, 0x3557,
+	0x355b, 0x355f, 0x3563, 0x3568, 0x356c, 0x3570, 0x3574, 0x3579, 0x357d,
+	0x3581, 0x3586, 0x358a, 0x358f, 0x3593, 0x3598, 0x359c, 0x35a1, 0x35a5,
+	0x35aa, 0x35ae, 0x35b3, 0x35b8, 0x35bc, 0x35c1, 0x35c6, 0x35cb, 0x35cf,
+	0x35d4, 0x35d9, 0x35de, 0x35e3, 0x35e8, 0x35ed, 0x35f2, 0x35f7, 0x35fc,
+	0x3600, 0x3603, 0x3605, 0x3608, 0x360a, 0x360d, 0x3610, 0x3612, 0x3615,
+	0x3618, 0x361a, 0x361d, 0x3620, 0x3622, 0x3625, 0x3628, 0x362b, 0x362d,
+	0x3630, 0x3633, 0x3636, 0x3639, 0x363b, 0x363e, 0x3641, 0x3644, 0x3647,
+	0x364a, 0x364d, 0x3650, 0x3653, 0x3656, 0x3659, 0x365c, 0x365f, 0x3662,
+	0x3665, 0x3668, 0x366b, 0x366e, 0x3672, 0x3675, 0x3678, 0x367b, 0x367e,
+	0x3682, 0x3685, 0x3688, 0x368b, 0x368f, 0x3692, 0x3695, 0x3699, 0x369c,
+	0x36a0, 0x36a3, 0x36a6, 0x36aa, 0x36ad, 0x36b1, 0x36b4, 0x36b8, 0x36bb,
+	0x36bf, 0x36c3, 0x36c6, 0x36ca, 0x36cd, 0x36d1, 0x36d5, 0x36d9, 0x36dc,
+	0x36e0, 0x36e4, 0x36e8, 0x36eb, 0x36ef, 0x36f3, 0x36f7, 0x36fb, 0x36ff,
+	0x3703, 0x3707, 0x370b, 0x370f, 0x3713, 0x3717, 0x371b, 0x371f, 0x3723,
+	0x3727, 0x372b, 0x372f, 0x3734, 0x3738, 0x373c, 0x3740, 0x3745, 0x3749,
+	0x374d, 0x3752, 0x3756, 0x375b, 0x375f, 0x3764, 0x3768, 0x376d, 0x3771,
+	0x3776, 0x377a, 0x377f, 0x3783, 0x3788, 0x378d, 0x3792, 0x3796, 0x379b,
+	0x37a0, 0x37a5, 0x37aa, 0x37ae, 0x37b3, 0x37b8, 0x37bd, 0x37c2, 0x37c7,
+	0x37cc, 0x37d1, 0x37d6, 0x37dc, 0x37e1, 0x37e6, 0x37eb, 0x37f0, 0x37f6,
+	0x37fb, 0x3800, 0x3802, 0x3805, 0x3808, 0x380b, 0x380d, 0x3810, 0x3813,
+	0x3816, 0x3818, 0x381b, 0x381e, 0x3821, 0x3824, 0x3827, 0x382a, 0x382c,
+	0x382f, 0x3832, 0x3835, 0x3838, 0x383b, 0x383e, 0x3841, 0x3844, 0x3847,
+	0x384a, 0x384d, 0x3851, 0x3854, 0x3857, 0x385a, 0x385d, 0x3860, 0x3864,
+	0x3867, 0x386a, 0x386d, 0x3870, 0x3874, 0x3877, 0x387a, 0x387e, 0x3881,
+	0x3885, 0x3888, 0x388b, 0x388f, 0x3892, 0x3896, 0x3899, 0x389d, 0x38a0,
+	0x38a4, 0x38a7, 0x38ab, 0x38af, 0x38b2, 0x38b6, 0x38ba, 0x38bd, 0x38c1,
+	0x38c5, 0x38c8, 0x38cc, 0x38d0, 0x38d4, 0x38d8, 0x38dc, 0x38df, 0x38e3,
+	0x38e7, 0x38eb, 0x38ef, 0x38f3, 0x38f7, 0x38fb, 0x38ff, 0x3903, 0x3907,
+	0x390c, 0x3910, 0x3914, 0x3918, 0x391c, 0x3920, 0x3925, 0x3929, 0x392d,
+	0x3932, 0x3936, 0x393a, 0x393f, 0x3943, 0x3948, 0x394c, 0x3951, 0x3955,
+	0x395a, 0x395e, 0x3963, 0x3967, 0x396c, 0x3971, 0x3975, 0x397a, 0x397f,
+	0x3984, 0x3989, 0x398d, 0x3992, 0x3997, 0x399c, 0x39a1, 0x39a6, 0x39ab,
+	0x39b0, 0x39b5, 0x39ba, 0x39bf, 0x39c4, 0x39c9, 0x39cf, 0x39d4, 0x39d9,
+	0x39de, 0x39e4, 0x39e9, 0x39ee, 0x39f4, 0x39f9, 0x39ff, 0x3,
+	/* table descriptor */
+	0xfbeff0e1, 0xf,
+	/* table length */
+	0x402,
+	/* table data */
+	0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x6, 0x7, 0x8, 0x9, 0xb, 0xc, 0xd, 0xe, 0x10,
+	0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+	0x20, 0x21, 0x22, 0x23, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2b, 0x2c, 0x2d,
+	0x2f, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3c, 0x3d,
+	0x3e, 0x40, 0x41, 0x43, 0x44, 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4d, 0x4f,
+	0x51, 0x52, 0x54, 0x56, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x60, 0x62, 0x64,
+	0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c,
+	0x7e, 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8e, 0x90, 0x92, 0x94, 0x97,
+	0x99, 0x9c, 0x9e, 0xa0, 0xa3, 0xa5, 0xa8, 0xaa, 0xad, 0xb0, 0xb2, 0xb5,
+	0xb7, 0xba, 0xbd, 0xc0, 0xc2, 0xc5, 0xc8, 0xcb, 0xcd, 0xd0, 0xd3, 0xd6,
+	0xd9, 0xdc, 0xdf, 0xe2, 0xe5, 0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfb,
+	0xfe, 0x101, 0x104, 0x108, 0x10b, 0x10e, 0x111, 0x115, 0x118, 0x11c, 0x11f,
+	0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13b, 0x13f, 0x143,
+	0x146, 0x14a, 0x14e, 0x152, 0x155, 0x159, 0x15d, 0x161, 0x165, 0x169,
+	0x16d, 0x171, 0x175, 0x179, 0x17d, 0x181, 0x185, 0x189, 0x18d, 0x192,
+	0x196, 0x19a, 0x19e, 0x1a2, 0x1a7, 0x1ab, 0x1af, 0x1b4, 0x1b8, 0x1bd,
+	0x1c1, 0x1c6, 0x1ca, 0x1cf, 0x1d3, 0x1d8, 0x1dc, 0x1e1, 0x1e6, 0x1ea,
+	0x1ef, 0x1f4, 0x1f9, 0x1fe, 0x202, 0x207, 0x20c, 0x211, 0x216, 0x21b,
+	0x220, 0x225, 0x22a, 0x22f, 0x234, 0x239, 0x23e, 0x244, 0x249, 0x24e,
+	0x253, 0x258, 0x25e, 0x263, 0x269, 0x26e, 0x273, 0x279, 0x27e, 0x284,
+	0x289, 0x28f, 0x294, 0x29a, 0x2a0, 0x2a5, 0x2ab, 0x2b1, 0x2b7, 0x2bc,
+	0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2e0, 0x2e6, 0x2ec, 0x2f2, 0x2f8,
+	0x2fe, 0x304, 0x30a, 0x310, 0x316, 0x31d, 0x323, 0x329, 0x32f, 0x336,
+	0x33c, 0x343, 0x349, 0x350, 0x356, 0x35d, 0x363, 0x36a, 0x370, 0x377,
+	0x37e, 0x384, 0x38b, 0x392, 0x398, 0x39f, 0x3a6, 0x3ad, 0x3b4, 0x3bb,
+	0x3c2, 0x3c9, 0x3d0, 0x3d7, 0x3de, 0x3e5, 0x3ec, 0x3f3, 0x3fb, 0x402,
+	0x409, 0x410, 0x418, 0x41f, 0x426, 0x42e, 0x435, 0x43d, 0x444, 0x44c,
+	0x453, 0x45b, 0x462, 0x46a, 0x472, 0x479, 0x481, 0x489, 0x491, 0x499,
+	0x4a0, 0x4a8, 0x4b0, 0x4b8, 0x4c0, 0x4c8, 0x4d0, 0x4d8, 0x4e0, 0x4e8,
+	0x4f1, 0x4f9, 0x501, 0x509, 0x512, 0x51a, 0x522, 0x52b, 0x533, 0x53b,
+	0x544, 0x54c, 0x555, 0x55e, 0x566, 0x56f, 0x577, 0x580, 0x589, 0x592,
+	0x59a, 0x5a3, 0x5ac, 0x5b5, 0x5be, 0x5c7, 0x5d0, 0x5d9, 0x5e2, 0x5eb,
+	0x5f4, 0x5fd, 0x606, 0x60f, 0x619, 0x622, 0x62b, 0x635, 0x63e, 0x647,
+	0x651, 0x65a, 0x664, 0x66d, 0x677, 0x680, 0x68a, 0x694, 0x69d, 0x6a7,
+	0x6b1, 0x6bb, 0x6c4, 0x6ce, 0x6d8, 0x6e2, 0x6ec, 0x6f6, 0x700, 0x70a,
+	0x714, 0x71e, 0x728, 0x732, 0x73d, 0x747, 0x751, 0x75b, 0x766, 0x770,
+	0x77a, 0x785, 0x78f, 0x79a, 0x7a4, 0x7af, 0x7ba, 0x7c4, 0x7cf, 0x7da,
+	0x7e4, 0x7ef, 0x7fa, 0x805, 0x810, 0x81a, 0x825, 0x830, 0x83b, 0x846,
+	0x851, 0x85d, 0x868, 0x873, 0x87e, 0x889, 0x895, 0x8a0, 0x8ab, 0x8b7,
+	0x8c2, 0x8cd, 0x8d9, 0x8e4, 0x8f0, 0x8fb, 0x907, 0x913, 0x91e, 0x92a,
+	0x936, 0x942, 0x94d, 0x959, 0x965, 0x971, 0x97d, 0x989, 0x995, 0x9a1,
+	0x9ad, 0x9b9, 0x9c5, 0x9d2, 0x9de, 0x9ea, 0x9f6, 0xa03, 0xa0f, 0xa1c,
+	0xa28, 0xa34, 0xa41, 0xa4d, 0xa5a, 0xa67, 0xa73, 0xa80, 0xa8d, 0xa99,
+	0xaa6, 0xab3, 0xac0, 0xacd, 0xada, 0xae7, 0xaf4, 0xb01, 0xb0e, 0xb1b,
+	0xb28, 0xb35, 0xb42, 0xb50, 0xb5d, 0xb6a, 0xb77, 0xb85, 0xb92, 0xba0,
+	0xbad, 0xbbb, 0xbc8, 0xbd6, 0xbe4, 0xbf1, 0xbff, 0xc0d, 0xc1a, 0xc28,
+	0xc36, 0xc44, 0xc52, 0xc60, 0xc6e, 0xc7c, 0xc8a, 0xc98, 0xca6, 0xcb4,
+	0xcc3, 0xcd1, 0xcdf, 0xced, 0xcfc, 0xd0a, 0xd19, 0xd27, 0xd35, 0xd44,
+	0xd53, 0xd61, 0xd70, 0xd7e, 0xd8d, 0xd9c, 0xdab, 0xdba, 0xdc8, 0xdd7,
+	0xde6, 0xdf5, 0xe04, 0xe13, 0xe22, 0xe31, 0xe41, 0xe50, 0xe5f, 0xe6e,
+	0xe7e, 0xe8d, 0xe9c, 0xeac, 0xebb, 0xecb, 0xeda, 0xeea, 0xef9, 0xf09,
+	0xf19, 0xf28, 0xf38, 0xf48, 0xf58, 0xf68, 0xf77, 0xf87, 0xf97, 0xfa7,
+	0xfb7, 0xfc7, 0xfd8, 0xfe8, 0xff8, 0x1008, 0x1018, 0x1029, 0x1039, 0x1049,
+	0x105a, 0x106a, 0x107b, 0x108b, 0x109c, 0x10ad, 0x10bd, 0x10ce, 0x10df,
+	0x10ef, 0x1100, 0x1111, 0x1122, 0x1133, 0x1144, 0x1155, 0x1166, 0x1177,
+	0x1188, 0x1199, 0x11aa, 0x11bb, 0x11cd, 0x11de, 0x11ef, 0x1201, 0x1212,
+	0x1223, 0x1235, 0x1246, 0x1258, 0x126a, 0x127b, 0x128d, 0x129f, 0x12b0,
+	0x12c2, 0x12d4, 0x12e6, 0x12f8, 0x130a, 0x131c, 0x132e, 0x1340, 0x1352,
+	0x1364, 0x1376, 0x1388, 0x139b, 0x13ad, 0x13bf, 0x13d2, 0x13e4, 0x13f6,
+	0x1409, 0x141c, 0x142e, 0x1441, 0x1453, 0x1466, 0x1479, 0x148b, 0x149e,
+	0x14b1, 0x14c4, 0x14d7, 0x14ea, 0x14fd, 0x1510, 0x1523, 0x1536, 0x1549,
+	0x155c, 0x1570, 0x1583, 0x1596, 0x15aa, 0x15bd, 0x15d0, 0x15e4, 0x15f7,
+	0x160b, 0x161e, 0x1632, 0x1646, 0x1659, 0x166d, 0x1681, 0x1695, 0x16a9,
+	0x16bd, 0x16d1, 0x16e4, 0x16f9, 0x170d, 0x1721, 0x1735, 0x1749, 0x175d,
+	0x1771, 0x1786, 0x179a, 0x17af, 0x17c3, 0x17d7, 0x17ec, 0x1800, 0x1815,
+	0x182a, 0x183e, 0x1853, 0x1868, 0x187d, 0x1891, 0x18a6, 0x18bb, 0x18d0,
+	0x18e5, 0x18fa, 0x190f, 0x1924, 0x1939, 0x194f, 0x1964, 0x1979, 0x198e,
+	0x19a4, 0x19b9, 0x19cf, 0x19e4, 0x19fa, 0x1a0f, 0x1a25, 0x1a3a, 0x1a50,
+	0x1a66, 0x1a7b, 0x1a91, 0x1aa7, 0x1abd, 0x1ad3, 0x1ae9, 0x1aff, 0x1b15,
+	0x1b2b, 0x1b41, 0x1b57, 0x1b6d, 0x1b84, 0x1b9a, 0x1bb0, 0x1bc7, 0x1bdd,
+	0x1bf4, 0x1c0a, 0x1c21, 0x1c37, 0x1c4e, 0x1c64, 0x1c7b, 0x1c92, 0x1ca9,
+	0x1cbf, 0x1cd6, 0x1ced, 0x1d04, 0x1d1b, 0x1d32, 0x1d49, 0x1d60, 0x1d78,
+	0x1d8f, 0x1da6, 0x1dbd, 0x1dd5, 0x1dec, 0x1e03, 0x1e1b, 0x1e32, 0x1e4a,
+	0x1e61, 0x1e79, 0x1e91, 0x1ea8, 0x1ec0, 0x1ed8, 0x1ef0, 0x1f07, 0x1f1f,
+	0x1f37, 0x1f4f, 0x1f67, 0x1f7f, 0x1f98, 0x1fb0, 0x1fc8, 0x1fe0, 0x1ff8,
+	0x2011, 0x2029, 0x2042, 0x205a, 0x2072, 0x208b, 0x20a4, 0x20bc, 0x20d5,
+	0x20ee, 0x2106, 0x211f, 0x2138, 0x2151, 0x216a, 0x2183, 0x219c, 0x21b5,
+	0x21ce, 0x21e7, 0x2200, 0x2219, 0x2233, 0x224c, 0x2265, 0x227f, 0x2298,
+	0x22b2, 0x22cb, 0x22e5, 0x22fe, 0x2318, 0x2331, 0x234b, 0x2365, 0x237f,
+	0x2399, 0x23b3, 0x23cc, 0x23e6, 0x2401, 0x241b, 0x2435, 0x244f, 0x2469,
+	0x2483, 0x249e, 0x24b8, 0x24d2, 0x24ed, 0x2507, 0x2522, 0x253c, 0x2557,
+	0x2571, 0x258c, 0x25a7, 0x25c2, 0x25dc, 0x25f7, 0x2612, 0x262d, 0x2648,
+	0x2663, 0x267e, 0x2699, 0x26b4, 0x26cf, 0x26eb, 0x2706, 0x2721, 0x273d,
+	0x2758, 0x2774, 0x278f, 0x27ab, 0x27c6, 0x27e2, 0x27fd, 0x2819, 0x2835,
+	0x2851, 0x286d, 0x2888, 0x28a4, 0x28c0, 0x28dc, 0x28f8, 0x2915, 0x2931,
+	0x294d, 0x2969, 0x2985, 0x29a2, 0x29be, 0x29db, 0x29f7, 0x2a14, 0x2a30,
+	0x2a4d, 0x2a69, 0x2a86, 0x2aa3, 0x2ac0, 0x2adc, 0x2af9, 0x2b16, 0x2b33,
+	0x2b50, 0x2b6d, 0x2b8a, 0x2ba7, 0x2bc4, 0x2be2, 0x2bff, 0x2c1c, 0x2c3a,
+	0x2c57, 0x2c74, 0x2c92, 0x2caf, 0x2ccd, 0x2ceb, 0x2d08, 0x2d26, 0x2d44,
+	0x2d61, 0x2d7f, 0x2d9d, 0x2dbb, 0x2dd9, 0x2df7, 0x2e15, 0x2e33, 0x2e51,
+	0x2e70, 0x2e8e, 0x2eac, 0x2eca, 0x2ee9, 0x2f07, 0x2f26, 0x2f44, 0x2f63,
+	0x2f81, 0x2fa0, 0x2fbf, 0x2fdd, 0x2ffc, 0x301b, 0x303a, 0x3059, 0x3078,
+	0x3097, 0x30b6, 0x30d5, 0x30f4, 0x3113, 0x3132, 0x3152, 0x3171, 0x3190,
+	0x31b0, 0x31cf, 0x31ef, 0x320e, 0x322e, 0x324e, 0x326d, 0x328d, 0x32ad,
+	0x32cd, 0x32ec, 0x330c, 0x332c, 0x334c, 0x336c, 0x338c, 0x33ac, 0x33cd,
+	0x33ed, 0x340d, 0x342e, 0x344e, 0x346e, 0x348f, 0x34af, 0x34d0, 0x34f0,
+	0x3511, 0x3532, 0x3552, 0x3573, 0x3594, 0x35b5, 0x35d6, 0x35f7, 0x3618,
+	0x3639, 0x365a, 0x367b, 0x369c, 0x36bd, 0x36df, 0x3700, 0x3721, 0x3743,
+	0x3764, 0x3786, 0x37a7, 0x37c9, 0x37eb, 0x380c, 0x382e, 0x3850, 0x3872,
+	0x3894, 0x38b6, 0x38d8, 0x38fa, 0x391c, 0x393e, 0x3960, 0x3982, 0x39a4,
+	0x39c7, 0x39e9, 0x3a0b, 0x3a2e, 0x3a50, 0x3a73, 0x3a95, 0x3ab8, 0x3adb,
+	0x3afd, 0x3b20, 0x3b43, 0x3b66, 0x3b89, 0x3bac, 0x3bcf, 0x3bf2, 0x3c15,
+	0x3c38, 0x3c5b, 0x3c7e, 0x3ca2, 0x3cc5, 0x3ce8, 0x3d0c, 0x3d2f, 0x3d53,
+	0x3d76, 0x3d9a, 0x3dbe, 0x3de1, 0x3e05, 0x3e29, 0x3e4d, 0x3e71, 0x3e95,
+	0x3eb9, 0x3edd, 0x3f01, 0x3f25, 0x3f49, 0x3f6d, 0x3f91, 0x3fb6, 0x3fda,
+	0x3fff, 0x0,
+	/* table descriptor */
+	0xfbefe1e1, 0xf,
+	/* table length */
+	0x402,
+	/* table data */
+	0x3, 0x0, 0x200, 0x500, 0x700, 0x8c0, 0xa20, 0xae0, 0xbe0, 0xc70, 0xd00,
+	0xdb0, 0xe30, 0xe98, 0xf00, 0xf78, 0xff8, 0x103c, 0x1084, 0x10d0, 0x1120,
+	0x1178, 0x11d0, 0x1218, 0x124a, 0x127e, 0x12b6, 0x12f0, 0x132c, 0x136c,
+	0x13ae, 0x13f2, 0x141d, 0x1442, 0x1469, 0x1491, 0x14bb, 0x14e6, 0x1513,
+	0x1542, 0x1572, 0x15a4, 0x15d7, 0x1606, 0x1621, 0x163e, 0x165b, 0x1679,
+	0x1698, 0x16b9, 0x16da, 0x16fc, 0x171f, 0x1743, 0x1768, 0x178e, 0x17b5,
+	0x17dd, 0x1803, 0x1818, 0x182e, 0x1844, 0x185b, 0x1873, 0x188b, 0x18a4,
+	0x18bd, 0x18d7, 0x18f2, 0x190d, 0x1929, 0x1945, 0x1962, 0x1980, 0x199f,
+	0x19be, 0x19de, 0x19ff, 0x1a10, 0x1a21, 0x1a32, 0x1a44, 0x1a56, 0x1a69,
+	0x1a7c, 0x1a8f, 0x1aa3, 0x1ab7, 0x1acc, 0x1ae1, 0x1af6, 0x1b0c, 0x1b23,
+	0x1b39, 0x1b51, 0x1b68, 0x1b81, 0x1b99, 0x1bb2, 0x1bcc, 0x1be6, 0x1c00,
+	0x1c0e, 0x1c1b, 0x1c29, 0x1c38, 0x1c46, 0x1c55, 0x1c64, 0x1c74, 0x1c83,
+	0x1c93, 0x1ca3, 0x1cb4, 0x1cc5, 0x1cd6, 0x1ce7, 0x1cf9, 0x1d0b, 0x1d1d,
+	0x1d30, 0x1d42, 0x1d56, 0x1d69, 0x1d7d, 0x1d91, 0x1da6, 0x1dbb, 0x1dd0,
+	0x1de6, 0x1dfc, 0x1e09, 0x1e14, 0x1e20, 0x1e2b, 0x1e37, 0x1e43, 0x1e4f,
+	0x1e5c, 0x1e69, 0x1e75, 0x1e82, 0x1e90, 0x1e9d, 0x1eab, 0x1eb9, 0x1ec7,
+	0x1ed5, 0x1ee3, 0x1ef2, 0x1f01, 0x1f10, 0x1f20, 0x1f2f, 0x1f3f, 0x1f4f,
+	0x1f60, 0x1f70, 0x1f81, 0x1f92, 0x1fa3, 0x1fb5, 0x1fc7, 0x1fd9, 0x1feb,
+	0x1ffe, 0x2008, 0x2012, 0x201b, 0x2025, 0x202f, 0x2039, 0x2043, 0x204e,
+	0x2058, 0x2063, 0x206e, 0x2079, 0x2084, 0x208f, 0x209b, 0x20a6, 0x20b2,
+	0x20be, 0x20ca, 0x20d6, 0x20e3, 0x20ef, 0x20fc, 0x2109, 0x2116, 0x2123,
+	0x2131, 0x213e, 0x214c, 0x215a, 0x2168, 0x2176, 0x2185, 0x2194, 0x21a2,
+	0x21b2, 0x21c1, 0x21d0, 0x21e0, 0x21f0, 0x2200, 0x2208, 0x2210, 0x2218,
+	0x2221, 0x2229, 0x2232, 0x223b, 0x2244, 0x224d, 0x2256, 0x225f, 0x2268,
+	0x2272, 0x227b, 0x2285, 0x228f, 0x2299, 0x22a3, 0x22ad, 0x22b7, 0x22c2,
+	0x22cc, 0x22d7, 0x22e2, 0x22ed, 0x22f8, 0x2303, 0x230e, 0x231a, 0x2325,
+	0x2331, 0x233d, 0x2349, 0x2355, 0x2361, 0x236e, 0x237a, 0x2387, 0x2394,
+	0x23a1, 0x23ae, 0x23bc, 0x23c9, 0x23d7, 0x23e5, 0x23f3, 0x2400, 0x2407,
+	0x240f, 0x2416, 0x241d, 0x2425, 0x242c, 0x2434, 0x243c, 0x2444, 0x244c,
+	0x2454, 0x245c, 0x2464, 0x246c, 0x2475, 0x247d, 0x2486, 0x248e, 0x2497,
+	0x24a0, 0x24a9, 0x24b2, 0x24bb, 0x24c4, 0x24ce, 0x24d7, 0x24e1, 0x24eb,
+	0x24f4, 0x24fe, 0x2508, 0x2512, 0x251d, 0x2527, 0x2531, 0x253c, 0x2547,
+	0x2552, 0x255d, 0x2568, 0x2573, 0x257e, 0x2589, 0x2595, 0x25a1, 0x25ac,
+	0x25b8, 0x25c4, 0x25d1, 0x25dd, 0x25e9, 0x25f6, 0x2601, 0x2607, 0x260e,
+	0x2614, 0x261b, 0x2622, 0x2629, 0x262f, 0x2636, 0x263d, 0x2644, 0x264c,
+	0x2653, 0x265a, 0x2661, 0x2669, 0x2670, 0x2678, 0x2680, 0x2687, 0x268f,
+	0x2697, 0x269f, 0x26a7, 0x26af, 0x26b8, 0x26c0, 0x26c8, 0x26d1, 0x26d9,
+	0x26e2, 0x26eb, 0x26f4, 0x26fd, 0x2706, 0x270f, 0x2718, 0x2722, 0x272b,
+	0x2734, 0x273e, 0x2748, 0x2752, 0x275c, 0x2766, 0x2770, 0x277a, 0x2784,
+	0x278f, 0x2799, 0x27a4, 0x27af, 0x27b9, 0x27c4, 0x27d0, 0x27db, 0x27e6,
+	0x27f1, 0x27fd, 0x2804, 0x280a, 0x2810, 0x2816, 0x281c, 0x2822, 0x2828,
+	0x282f, 0x2835, 0x283b, 0x2842, 0x2848, 0x284f, 0x2855, 0x285c, 0x2863,
+	0x286a, 0x2870, 0x2877, 0x287e, 0x2886, 0x288d, 0x2894, 0x289b, 0x28a3,
+	0x28aa, 0x28b2, 0x28b9, 0x28c1, 0x28c9, 0x28d0, 0x28d8, 0x28e0, 0x28e8,
+	0x28f1, 0x28f9, 0x2901, 0x2909, 0x2912, 0x291a, 0x2923, 0x292c, 0x2935,
+	0x293d, 0x2946, 0x294f, 0x2959, 0x2962, 0x296b, 0x2975, 0x297e, 0x2988,
+	0x2991, 0x299b, 0x29a5, 0x29af, 0x29b9, 0x29c3, 0x29cd, 0x29d8, 0x29e2,
+	0x29ed, 0x29f7, 0x2a01, 0x2a06, 0x2a0c, 0x2a11, 0x2a17, 0x2a1c, 0x2a22,
+	0x2a28, 0x2a2e, 0x2a33, 0x2a39, 0x2a3f, 0x2a45, 0x2a4b, 0x2a52, 0x2a58,
+	0x2a5e, 0x2a64, 0x2a6b, 0x2a71, 0x2a78, 0x2a7e, 0x2a85, 0x2a8b, 0x2a92,
+	0x2a99, 0x2aa0, 0x2aa7, 0x2aae, 0x2ab5, 0x2abc, 0x2ac3, 0x2aca, 0x2ad2,
+	0x2ad9, 0x2ae1, 0x2ae8, 0x2af0, 0x2af7, 0x2aff, 0x2b07, 0x2b0f, 0x2b17,
+	0x2b1f, 0x2b27, 0x2b2f, 0x2b38, 0x2b40, 0x2b48, 0x2b51, 0x2b59, 0x2b62,
+	0x2b6b, 0x2b74, 0x2b7d, 0x2b86, 0x2b8f, 0x2b98, 0x2ba1, 0x2baa, 0x2bb4,
+	0x2bbd, 0x2bc7, 0x2bd0, 0x2bda, 0x2be4, 0x2bee, 0x2bf8, 0x2c01, 0x2c06,
+	0x2c0b, 0x2c10, 0x2c16, 0x2c1b, 0x2c20, 0x2c26, 0x2c2b, 0x2c31, 0x2c36,
+	0x2c3c, 0x2c41, 0x2c47, 0x2c4d, 0x2c53, 0x2c59, 0x2c5e, 0x2c64, 0x2c6a,
+	0x2c70, 0x2c77, 0x2c7d, 0x2c83, 0x2c89, 0x2c90, 0x2c96, 0x2c9d, 0x2ca3,
+	0x2caa, 0x2cb0, 0x2cb7, 0x2cbe, 0x2cc5, 0x2ccc, 0x2cd3, 0x2cda, 0x2ce1,
+	0x2ce8, 0x2cef, 0x2cf6, 0x2cfe, 0x2d05, 0x2d0d, 0x2d14, 0x2d1c, 0x2d24,
+	0x2d2b, 0x2d33, 0x2d3b, 0x2d43, 0x2d4b, 0x2d53, 0x2d5b, 0x2d64, 0x2d6c,
+	0x2d74, 0x2d7d, 0x2d85, 0x2d8e, 0x2d97, 0x2da0, 0x2da9, 0x2db2, 0x2dbb,
+	0x2dc4, 0x2dcd, 0x2dd6, 0x2de0, 0x2de9, 0x2df3, 0x2dfc, 0x2e03, 0x2e08,
+	0x2e0d, 0x2e12, 0x2e17, 0x2e1c, 0x2e21, 0x2e26, 0x2e2b, 0x2e30, 0x2e36,
+	0x2e3b, 0x2e41, 0x2e46, 0x2e4c, 0x2e51, 0x2e57, 0x2e5c, 0x2e62, 0x2e68,
+	0x2e6e, 0x2e73, 0x2e79, 0x2e7f, 0x2e85, 0x2e8b, 0x2e92, 0x2e98, 0x2e9e,
+	0x2ea4, 0x2eab, 0x2eb1, 0x2eb8, 0x2ebe, 0x2ec5, 0x2ecb, 0x2ed2, 0x2ed9,
+	0x2ee0, 0x2ee6, 0x2eed, 0x2ef4, 0x2efb, 0x2f03, 0x2f0a, 0x2f11, 0x2f18,
+	0x2f20, 0x2f27, 0x2f2f, 0x2f36, 0x2f3e, 0x2f46, 0x2f4e, 0x2f55, 0x2f5d,
+	0x2f65, 0x2f6d, 0x2f76, 0x2f7e, 0x2f86, 0x2f8e, 0x2f97, 0x2f9f, 0x2fa8,
+	0x2fb1, 0x2fb9, 0x2fc2, 0x2fcb, 0x2fd4, 0x2fdd, 0x2fe6, 0x2ff0, 0x2ff9,
+	0x3001, 0x3006, 0x300a, 0x300f, 0x3014, 0x3019, 0x301e, 0x3023, 0x3028,
+	0x302d, 0x3032, 0x3037, 0x303d, 0x3042, 0x3047, 0x304d, 0x3052, 0x3057,
+	0x305d, 0x3062, 0x3068, 0x306e, 0x3073, 0x3079, 0x307f, 0x3085, 0x308b,
+	0x3091, 0x3097, 0x309d, 0x30a3, 0x30a9, 0x30af, 0x30b6, 0x30bc, 0x30c2,
+	0x30c9, 0x30cf, 0x30d6, 0x30dd, 0x30e3, 0x30ea, 0x30f1, 0x30f8, 0x30ff,
+	0x3106, 0x310d, 0x3114, 0x311b, 0x3122, 0x3129, 0x3131, 0x3138, 0x3140,
+	0x3147, 0x314f, 0x3157, 0x315e, 0x3166, 0x316e, 0x3176, 0x317e, 0x3186,
+	0x318f, 0x3197, 0x319f, 0x31a8, 0x31b0, 0x31b9, 0x31c1, 0x31ca, 0x31d3,
+	0x31dc, 0x31e5, 0x31ee, 0x31f7, 0x3200, 0x3204, 0x3209, 0x320e, 0x3213,
+	0x3217, 0x321c, 0x3221, 0x3226, 0x322b, 0x3230, 0x3235, 0x323a, 0x323f,
+	0x3245, 0x324a, 0x324f, 0x3255, 0x325a, 0x325f, 0x3265, 0x326a, 0x3270,
+	0x3276, 0x327b, 0x3281, 0x3287, 0x328d, 0x3293, 0x3299, 0x329f, 0x32a5,
+	0x32ab, 0x32b1, 0x32b7, 0x32bd, 0x32c4, 0x32ca, 0x32d1, 0x32d7, 0x32de,
+	0x32e4, 0x32eb, 0x32f2, 0x32f8, 0x32ff, 0x3306, 0x330d, 0x3314, 0x331b,
+	0x3322, 0x332a, 0x3331, 0x3338, 0x3340, 0x3347, 0x334f, 0x3357, 0x335e,
+	0x3366, 0x336e, 0x3376, 0x337e, 0x3386, 0x338e, 0x3396, 0x339e, 0x33a7,
+	0x33af, 0x33b8, 0x33c0, 0x33c9, 0x33d2, 0x33da, 0x33e3, 0x33ec, 0x33f5,
+	0x33fe, 0x3404, 0x3408, 0x340d, 0x3412, 0x3416, 0x341b, 0x3420, 0x3425,
+	0x342a, 0x342f, 0x3434, 0x3439, 0x343e, 0x3443, 0x3448, 0x344e, 0x3453,
+	0x3458, 0x345e, 0x3463, 0x3469, 0x346e, 0x3474, 0x347a, 0x347f, 0x3485,
+	0x348b, 0x3491, 0x3497, 0x349d, 0x34a3, 0x34a9, 0x34af, 0x34b5, 0x34bb,
+	0x34c2, 0x34c8, 0x34ce, 0x34d5, 0x34db, 0x34e2, 0x34e9, 0x34ef, 0x34f6,
+	0x34fd, 0x3504, 0x350b, 0x3512, 0x3519, 0x3520, 0x3527, 0x352f, 0x3536,
+	0x353d, 0x3545, 0x354c, 0x3554, 0x355c, 0x3563, 0x356b, 0x3573, 0x357b,
+	0x3583, 0x358b, 0x3593, 0x359c, 0x35a4, 0x35ad, 0x35b5, 0x35be, 0x35c6,
+	0x35cf, 0x35d8, 0x35e1, 0x35ea, 0x35f3, 0x35fc, 0x3602, 0x3607, 0x360c,
+	0x3610, 0x3615, 0x361a, 0x361f, 0x3624, 0x3629, 0x362e, 0x3633, 0x3638,
+	0x363d, 0x3642, 0x3647, 0x364d, 0x3652, 0x3657, 0x365d, 0x3662, 0x3668,
+	0x366d, 0x3673, 0x3679, 0x367f, 0x3684, 0x368a, 0x3690, 0x3696, 0x369c,
+	0x36a2, 0x36a8, 0x36ae, 0x36b5, 0x36bb, 0x36c1, 0x36c8, 0x36ce, 0x36d5,
+	0x36db, 0x36e2, 0x36e9, 0x36f0, 0x36f6, 0x36fd, 0x3704, 0x370b, 0x3712,
+	0x371a, 0x3721, 0x3728, 0x372f, 0x3737, 0x373e, 0x3746, 0x374e, 0x3755,
+	0x375d, 0x3765, 0x376d, 0x3775, 0x377d, 0x3785, 0x378d, 0x3796, 0x379e,
+	0x37a7, 0x37af, 0x37b8, 0x37c1, 0x37c9, 0x37d2, 0x37db, 0x37e4, 0x37ed,
+	0x37f7, 0x3800, 0x3804, 0x3809, 0x380e, 0x3813, 0x3818, 0x381d, 0x3821,
+	0x3826, 0x382c, 0x3831, 0x3836, 0x383b, 0x3840, 0x3846, 0x384b, 0x3850,
+	0x3856, 0x385b, 0x3861, 0x3866, 0x386c, 0x3872, 0x3878, 0x387d, 0x3883,
+	0x3889, 0x388f, 0x3895, 0x389b, 0x38a2, 0x38a8, 0x38ae, 0x38b5, 0x38bb,
+	0x38c1, 0x38c8, 0x38cf, 0x38d5, 0x38dc, 0x38e3, 0x38ea, 0x38f1, 0x38f8,
+	0x38ff, 0x3906, 0x390d, 0x3914, 0x391b, 0x3923, 0x392a, 0x3932, 0x3939,
+	0x3941, 0x3949, 0x3951, 0x3959, 0x3961, 0x3969, 0x3971, 0x3979, 0x3981,
+	0x398a, 0x3992, 0x399b, 0x39a3, 0x39ac, 0x39b5, 0x39be, 0x39c7, 0x39d0,
+	0x39d9, 0x39e2, 0x39ec, 0x39f5, 0x39ff, 0x3,
+	/* table descriptor */
+	0xfbefe2e1, 0xf,
+	/* table length */
+	0x402,
+	/* table data */
+	0x3, 0x0, 0x3, 0x7, 0xa, 0xe, 0x11, 0x15, 0x18, 0x1c, 0x20, 0x23, 0x27,
+	0x2a, 0x2e, 0x31, 0x35, 0x38, 0x3c, 0x40, 0x43, 0x47, 0x4a, 0x4e, 0x51,
+	0x55, 0x58, 0x5c, 0x60, 0x63, 0x67, 0x6a, 0x6e, 0x71, 0x75, 0x78, 0x7c,
+	0x80, 0x83, 0x87, 0x8a, 0x8e, 0x91, 0x95, 0x99, 0x9c, 0xa0, 0xa3, 0xa7,
+	0xaa, 0xae, 0xb1, 0xb5, 0xb9, 0xbc, 0xc0, 0xc3, 0xc7, 0xca, 0xce, 0xd1,
+	0xd5, 0xd9, 0xdc, 0xe0, 0xe3, 0xe7, 0xea, 0xee, 0xf1, 0xf5, 0xf9, 0xfc,
+	0x100, 0x103, 0x107, 0x10a, 0x10e, 0x112, 0x115, 0x119, 0x11c, 0x120,
+	0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13c, 0x13f, 0x143,
+	0x147, 0x14b, 0x14e, 0x152, 0x156, 0x15a, 0x15e, 0x162, 0x166, 0x16a,
+	0x16e, 0x172, 0x176, 0x17a, 0x17e, 0x182, 0x186, 0x18a, 0x18f, 0x193,
+	0x197, 0x19b, 0x1a0, 0x1a4, 0x1a8, 0x1ad, 0x1b1, 0x1b5, 0x1ba, 0x1be,
+	0x1c3, 0x1c7, 0x1cc, 0x1d0, 0x1d5, 0x1d9, 0x1de, 0x1e3, 0x1e7, 0x1ec,
+	0x1f1, 0x1f6, 0x1fa, 0x1ff, 0x204, 0x209, 0x20e, 0x213, 0x217, 0x21c,
+	0x221, 0x226, 0x22b, 0x230, 0x236, 0x23b, 0x240, 0x245, 0x24a, 0x24f,
+	0x255, 0x25a, 0x25f, 0x264, 0x26a, 0x26f, 0x274, 0x27a, 0x27f, 0x285,
+	0x28a, 0x290, 0x295, 0x29b, 0x2a0, 0x2a6, 0x2ac, 0x2b1, 0x2b7, 0x2bd,
+	0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2df, 0x2e5, 0x2eb, 0x2f1, 0x2f7,
+	0x2fd, 0x303, 0x309, 0x30f, 0x315, 0x31c, 0x322, 0x328, 0x32e, 0x334,
+	0x33b, 0x341, 0x347, 0x34d, 0x354, 0x35a, 0x361, 0x367, 0x36d, 0x374,
+	0x37a, 0x381, 0x388, 0x38e, 0x395, 0x39b, 0x3a2, 0x3a9, 0x3b0, 0x3b6,
+	0x3bd, 0x3c4, 0x3cb, 0x3d2, 0x3d8, 0x3df, 0x3e6, 0x3ed, 0x3f4, 0x3fb,
+	0x402, 0x409, 0x411, 0x418, 0x41f, 0x426, 0x42d, 0x434, 0x43c, 0x443,
+	0x44a, 0x452, 0x459, 0x460, 0x468, 0x46f, 0x477, 0x47e, 0x486, 0x48d,
+	0x495, 0x49c, 0x4a4, 0x4ac, 0x4b3, 0x4bb, 0x4c3, 0x4cb, 0x4d3, 0x4da,
+	0x4e2, 0x4ea, 0x4f2, 0x4fa, 0x502, 0x50a, 0x512, 0x51a, 0x522, 0x52a,
+	0x532, 0x53a, 0x543, 0x54b, 0x553, 0x55b, 0x564, 0x56c, 0x574, 0x57d,
+	0x585, 0x58d, 0x596, 0x59e, 0x5a7, 0x5af, 0x5b8, 0x5c1, 0x5c9, 0x5d2,
+	0x5db, 0x5e3, 0x5ec, 0x5f5, 0x5fe, 0x606, 0x60f, 0x618, 0x621, 0x62a,
+	0x633, 0x63c, 0x645, 0x64e, 0x657, 0x660, 0x669, 0x672, 0x67b, 0x685,
+	0x68e, 0x697, 0x6a0, 0x6aa, 0x6b3, 0x6bd, 0x6c6, 0x6cf, 0x6d9, 0x6e2,
+	0x6ec, 0x6f5, 0x6ff, 0x709, 0x712, 0x71c, 0x726, 0x72f, 0x739, 0x743,
+	0x74d, 0x756, 0x760, 0x76a, 0x774, 0x77e, 0x788, 0x792, 0x79c, 0x7a6,
+	0x7b0, 0x7ba, 0x7c4, 0x7cf, 0x7d9, 0x7e3, 0x7ed, 0x7f7, 0x802, 0x80c,
+	0x816, 0x821, 0x82b, 0x836, 0x840, 0x84b, 0x855, 0x860, 0x86a, 0x875,
+	0x880, 0x88a, 0x895, 0x8a0, 0x8ab, 0x8b5, 0x8c0, 0x8cb, 0x8d6, 0x8e1,
+	0x8ec, 0x8f7, 0x902, 0x90d, 0x918, 0x923, 0x92e, 0x939, 0x944, 0x950,
+	0x95b, 0x966, 0x971, 0x97d, 0x988, 0x993, 0x99f, 0x9aa, 0x9b6, 0x9c1,
+	0x9cd, 0x9d8, 0x9e4, 0x9f0, 0x9fb, 0xa07, 0xa13, 0xa1e, 0xa2a, 0xa36,
+	0xa42, 0xa4e, 0xa59, 0xa65, 0xa71, 0xa7d, 0xa89, 0xa95, 0xaa1, 0xaad,
+	0xab9, 0xac6, 0xad2, 0xade, 0xaea, 0xaf6, 0xb03, 0xb0f, 0xb1b, 0xb28,
+	0xb34, 0xb41, 0xb4d, 0xb5a, 0xb66, 0xb73, 0xb7f, 0xb8c, 0xb98, 0xba5,
+	0xbb2, 0xbbf, 0xbcb, 0xbd8, 0xbe5, 0xbf2, 0xbff, 0xc0c, 0xc19, 0xc25,
+	0xc32, 0xc40, 0xc4d, 0xc5a, 0xc67, 0xc74, 0xc81, 0xc8e, 0xc9c, 0xca9,
+	0xcb6, 0xcc3, 0xcd1, 0xcde, 0xcec, 0xcf9, 0xd07, 0xd14, 0xd22, 0xd2f,
+	0xd3d, 0xd4a, 0xd58, 0xd66, 0xd73, 0xd81, 0xd8f, 0xd9d, 0xdab, 0xdb8,
+	0xdc6, 0xdd4, 0xde2, 0xdf0, 0xdfe, 0xe0c, 0xe1a, 0xe29, 0xe37, 0xe45,
+	0xe53, 0xe61, 0xe70, 0xe7e, 0xe8c, 0xe9a, 0xea9, 0xeb7, 0xec6, 0xed4,
+	0xee3, 0xef1, 0xf00, 0xf0e, 0xf1d, 0xf2c, 0xf3a, 0xf49, 0xf58, 0xf67,
+	0xf75, 0xf84, 0xf93, 0xfa2, 0xfb1, 0xfc0, 0xfcf, 0xfde, 0xfed, 0xffc,
+	0x100b, 0x101a, 0x102a, 0x1039, 0x1048, 0x1057, 0x1067, 0x1076, 0x1085,
+	0x1095, 0x10a4, 0x10b4, 0x10c3, 0x10d3, 0x10e2, 0x10f2, 0x1101, 0x1111,
+	0x1121, 0x1130, 0x1140, 0x1150, 0x1160, 0x116f, 0x117f, 0x118f, 0x119f,
+	0x11af, 0x11bf, 0x11cf, 0x11df, 0x11ef, 0x11ff, 0x120f, 0x121f, 0x1230,
+	0x1240, 0x1250, 0x1260, 0x1271, 0x1281, 0x1291, 0x12a2, 0x12b2, 0x12c3,
+	0x12d3, 0x12e4, 0x12f4, 0x1305, 0x1316, 0x1326, 0x1337, 0x1348, 0x1359,
+	0x1369, 0x137a, 0x138b, 0x139c, 0x13ad, 0x13be, 0x13cf, 0x13e0, 0x13f1,
+	0x1402, 0x1413, 0x1424, 0x1435, 0x1446, 0x1458, 0x1469, 0x147a, 0x148b,
+	0x149d, 0x14ae, 0x14c0, 0x14d1, 0x14e3, 0x14f4, 0x1506, 0x1517, 0x1529,
+	0x153a, 0x154c, 0x155e, 0x156f, 0x1581, 0x1593, 0x15a5, 0x15b7, 0x15c9,
+	0x15db, 0x15ec, 0x15fe, 0x1610, 0x1623, 0x1635, 0x1647, 0x1659, 0x166b,
+	0x167d, 0x168f, 0x16a2, 0x16b4, 0x16c6, 0x16d9, 0x16eb, 0x16fe, 0x1710,
+	0x1722, 0x1735, 0x1748, 0x175a, 0x176d, 0x177f, 0x1792, 0x17a5, 0x17b8,
+	0x17ca, 0x17dd, 0x17f0, 0x1803, 0x1816, 0x1829, 0x183c, 0x184f, 0x1862,
+	0x1875, 0x1888, 0x189b, 0x18ae, 0x18c1, 0x18d5, 0x18e8, 0x18fb, 0x190e,
+	0x1922, 0x1935, 0x1949, 0x195c, 0x196f, 0x1983, 0x1996, 0x19aa, 0x19be,
+	0x19d1, 0x19e5, 0x19f9, 0x1a0c, 0x1a20, 0x1a34, 0x1a48, 0x1a5c, 0x1a70,
+	0x1a84, 0x1a97, 0x1aab, 0x1ac0, 0x1ad4, 0x1ae8, 0x1afc, 0x1b10, 0x1b24,
+	0x1b38, 0x1b4d, 0x1b61, 0x1b75, 0x1b8a, 0x1b9e, 0x1bb2, 0x1bc7, 0x1bdb,
+	0x1bf0, 0x1c04, 0x1c19, 0x1c2e, 0x1c42, 0x1c57, 0x1c6c, 0x1c80, 0x1c95,
+	0x1caa, 0x1cbf, 0x1cd4, 0x1ce8, 0x1cfd, 0x1d12, 0x1d27, 0x1d3c, 0x1d51,
+	0x1d67, 0x1d7c, 0x1d91, 0x1da6, 0x1dbb, 0x1dd1, 0x1de6, 0x1dfb, 0x1e10,
+	0x1e26, 0x1e3b, 0x1e51, 0x1e66, 0x1e7c, 0x1e91, 0x1ea7, 0x1ebd, 0x1ed2,
+	0x1ee8, 0x1efe, 0x1f13, 0x1f29, 0x1f3f, 0x1f55, 0x1f6b, 0x1f81, 0x1f96,
+	0x1fac, 0x1fc2, 0x1fd9, 0x1fef, 0x2005, 0x201b, 0x2031, 0x2047, 0x205d,
+	0x2074, 0x208a, 0x20a0, 0x20b7, 0x20cd, 0x20e4, 0x20fa, 0x2111, 0x2127,
+	0x213e, 0x2154, 0x216b, 0x2182, 0x2198, 0x21af, 0x21c6, 0x21dd, 0x21f3,
+	0x220a, 0x2221, 0x2238, 0x224f, 0x2266, 0x227d, 0x2294, 0x22ab, 0x22c2,
+	0x22da, 0x22f1, 0x2308, 0x231f, 0x2337, 0x234e, 0x2365, 0x237d, 0x2394,
+	0x23ac, 0x23c3, 0x23db, 0x23f2, 0x240a, 0x2421, 0x2439, 0x2451, 0x2469,
+	0x2480, 0x2498, 0x24b0, 0x24c8, 0x24e0, 0x24f8, 0x2510, 0x2528, 0x2540,
+	0x2558, 0x2570, 0x2588, 0x25a0, 0x25b8, 0x25d0, 0x25e9, 0x2601, 0x2619,
+	0x2632, 0x264a, 0x2663, 0x267b, 0x2693, 0x26ac, 0x26c5, 0x26dd, 0x26f6,
+	0x270e, 0x2727, 0x2740, 0x2759, 0x2771, 0x278a, 0x27a3, 0x27bc, 0x27d5,
+	0x27ee, 0x2807, 0x2820, 0x2839, 0x2852, 0x286b, 0x2884, 0x289e, 0x28b7,
+	0x28d0, 0x28e9, 0x2903, 0x291c, 0x2936, 0x294f, 0x2968, 0x2982, 0x299c,
+	0x29b5, 0x29cf, 0x29e8, 0x2a02, 0x2a1c, 0x2a35, 0x2a4f, 0x2a69, 0x2a83,
+	0x2a9d, 0x2ab7, 0x2ad1, 0x2aeb, 0x2b05, 0x2b1f, 0x2b39, 0x2b53, 0x2b6d,
+	0x2b87, 0x2ba1, 0x2bbc, 0x2bd6, 0x2bf0, 0x2c0b, 0x2c25, 0x2c3f, 0x2c5a,
+	0x2c74, 0x2c8f, 0x2ca9, 0x2cc4, 0x2cdf, 0x2cf9, 0x2d14, 0x2d2f, 0x2d49,
+	0x2d64, 0x2d7f, 0x2d9a, 0x2db5, 0x2dd0, 0x2deb, 0x2e06, 0x2e21, 0x2e3c,
+	0x2e57, 0x2e72, 0x2e8d, 0x2ea8, 0x2ec4, 0x2edf, 0x2efa, 0x2f16, 0x2f31,
+	0x2f4c, 0x2f68, 0x2f83, 0x2f9f, 0x2fba, 0x2fd6, 0x2ff1, 0x300d, 0x3029,
+	0x3044, 0x3060, 0x307c, 0x3098, 0x30b4, 0x30d0, 0x30eb, 0x3107, 0x3123,
+	0x313f, 0x315b, 0x3178, 0x3194, 0x31b0, 0x31cc, 0x31e8, 0x3205, 0x3221,
+	0x323d, 0x325a, 0x3276, 0x3292, 0x32af, 0x32cb, 0x32e8, 0x3304, 0x3321,
+	0x333e, 0x335a, 0x3377, 0x3394, 0x33b1, 0x33cd, 0x33ea, 0x3407, 0x3424,
+	0x3441, 0x345e, 0x347b, 0x3498, 0x34b5, 0x34d2, 0x34ef, 0x350d, 0x352a,
+	0x3547, 0x3564, 0x3582, 0x359f, 0x35bc, 0x35da, 0x35f7, 0x3615, 0x3632,
+	0x3650, 0x366e, 0x368b, 0x36a9, 0x36c7, 0x36e4, 0x3702, 0x3720, 0x373e,
+	0x375c, 0x377a, 0x3798, 0x37b6, 0x37d4, 0x37f2, 0x3810, 0x382e, 0x384c,
+	0x386a, 0x3888, 0x38a7, 0x38c5, 0x38e3, 0x3902, 0x3920, 0x393f, 0x395d,
+	0x397c, 0x399a, 0x39b9, 0x39d7, 0x39f6, 0x3a15, 0x3a33, 0x3a52, 0x3a71,
+	0x3a90, 0x3aaf, 0x3acd, 0x3aec, 0x3b0b, 0x3b2a, 0x3b49, 0x3b68, 0x3b87,
+	0x3ba7, 0x3bc6, 0x3be5, 0x3c04, 0x3c24, 0x3c43, 0x3c62, 0x3c82, 0x3ca1,
+	0x3cc0, 0x3ce0, 0x3cff, 0x3d1f, 0x3d3f, 0x3d5e, 0x3d7e, 0x3d9e, 0x3dbd,
+	0x3ddd, 0x3dfd, 0x3e1d, 0x3e3d, 0x3e5d, 0x3e7c, 0x3e9c, 0x3ebc, 0x3edc,
+	0x3efd, 0x3f1d, 0x3f3d, 0x3f5d, 0x3f7d, 0x3f9e, 0x3fbe, 0x3fde, 0x3fff,
+	0x0,
+	/* table descriptor */
+	0xfbe83ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0xffffff80,
+	0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f, 0x7f, 0xc, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe65ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4000, 0x0, 0x59bb, 0x4000, 0xffffe9fb, 0xffffd24d, 0x4000, 0x7169,
+	0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+	0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbefbb62, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x1, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff,
+	0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbefdb62, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	/* table descriptor */
+	0xfbe0bba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4031, 0x0, 0x5ea7, 0x4031, 0xfffff571, 0xffffdb55, 0x4031, 0x78c4,
+	0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+	0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe63ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4031, 0x0, 0x59fe, 0x4031, 0xffffe9ea, 0xffffd22b, 0x4031, 0x71be,
+	0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+	0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe15ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4000, 0x0, 0x64ca, 0x4000, 0xfffff404, 0xffffe20c, 0x4000, 0x76c3,
+	0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+	0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe13ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4031, 0x0, 0x6516, 0x4031, 0xfffff3fb, 0xffffe1f5, 0x4031, 0x771c,
+	0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+	0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe0dba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4000, 0x0, 0x5e60, 0x4000, 0xfffff579, 0xffffdb70, 0x4000, 0x7869,
+	0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+	0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbe85ba2, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0xfffffe00,
+	0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff, 0x1ff, 0x1ff, 0xe, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+	/* table descriptor */
+	0xfbeffbe4, 0xf,
+	/* table length */
+	0x1d,
+	/* table data */
+	0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+#endif /* __DCSS_HDR10_TABLES_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-hdr10.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-hdr10.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <linux/firmware.h>
+#include <drm/drm_fourcc.h>
+
+#include "dcss-dev.h"
+
+#define USE_TBL_HEADER
+
+#ifdef USE_TBL_HEADER
+#include "dcss-hdr10-tables.h"
+#endif
+
+#define USE_CTXLD
+
+#define DCSS_HDR10_A0_LUT		0x0000
+#define DCSS_HDR10_A1_LUT		0x1000
+#define DCSS_HDR10_A2_LUT		0x2000
+/* one CSCA and CSCB for each channel(pipe) */
+#define DCSS_HDR10_CSCA_BASE		0x3000
+#define DCSS_HDR10_CSCB_BASE		0x3800
+
+/* one CSCO for all channels(pipes) */
+#define DCSS_HDR10_CSCO_BASE		0x3000
+
+#define DCSS_HDR10_LUT_CONTROL		(DCSS_HDR10_CSCA_BASE + 0x80)
+#define   LUT_ENABLE			BIT(0)
+#define   LUT_EN_FOR_ALL_PELS		BIT(1)
+#define   LUT_BYPASS			BIT(15)
+#define DCSS_HDR10_FL2FX		(DCSS_HDR10_CSCB_BASE + 0x74)
+#define DCSS_HDR10_LTNL			(DCSS_HDR10_CSCO_BASE + 0x74)
+#define   LTNL_PASS_THRU		BIT(0)
+#define   FIX2FLT_DISABLE		BIT(1)
+#define   LTNL_EN_FOR_ALL_PELS		BIT(2)
+#define   FIX2FLT_EN_FOR_ALL_PELS	BIT(3)
+
+/* following offsets are relative to CSC(A|B|O)_BASE */
+#define DCSS_HDR10_CSC_CONTROL		0x00
+#define   CSC_EN			BIT(0)
+#define   CSC_ALL_PIX_EN		BIT(1)
+#define   CSC_BYPASS			BIT(15)
+#define DCSS_HDR10_CSC_H00		0x04
+#define DCSS_HDR10_CSC_H10		0x08
+#define DCSS_HDR10_CSC_H20		0x0C
+#define DCSS_HDR10_CSC_H01		0x10
+#define DCSS_HDR10_CSC_H11		0x14
+#define DCSS_HDR10_CSC_H21		0x18
+#define DCSS_HDR10_CSC_H02		0x1C
+#define DCSS_HDR10_CSC_H12		0x20
+#define DCSS_HDR10_CSC_H22		0x24
+#define   H_COEF_MASK			GENMASK(15, 0)
+#define DCSS_HDR10_CSC_IO0		0x28
+#define DCSS_HDR10_CSC_IO1		0x2C
+#define DCSS_HDR10_CSC_IO2		0x30
+#define   PRE_OFFSET_MASK		GENMASK(9, 0)
+#define DCSS_HDR10_CSC_IO_MIN0		0x34
+#define DCSS_HDR10_CSC_IO_MIN1		0x38
+#define DCSS_HDR10_CSC_IO_MIN2		0x3C
+#define DCSS_HDR10_CSC_IO_MAX0		0x40
+#define DCSS_HDR10_CSC_IO_MAX1		0x44
+#define DCSS_HDR10_CSC_IO_MAX2		0x48
+#define   IO_CLIP_MASK			GENMASK(9, 0)
+#define DCSS_HDR10_CSC_NORM		0x4C
+#define   NORM_MASK			GENMASK(4, 0)
+#define DCSS_HDR10_CSC_OO0		0x50
+#define DCSS_HDR10_CSC_OO1		0x54
+#define DCSS_HDR10_CSC_OO2		0x58
+#define   POST_OFFSET_MASK		GENMASK(27, 0)
+#define DCSS_HDR10_CSC_OMIN0		0x5C
+#define DCSS_HDR10_CSC_OMIN1		0x60
+#define DCSS_HDR10_CSC_OMIN2		0x64
+#define DCSS_HDR10_CSC_OMAX0		0x68
+#define DCSS_HDR10_CSC_OMAX1		0x6C
+#define DCSS_HDR10_CSC_OMAX2		0x70
+#define   POST_CLIP_MASK		GENMASK(9, 0)
+
+#define HDR10_IPIPE_LUT_MAX_ENTRIES	1024
+#define HDR10_OPIPE_LUT_MAX_ENTRIES	1023
+#define HDR10_CSC_MAX_REGS		29
+
+#define OPIPE_CH_NO			3
+
+/* Pipe config descriptor */
+
+/* bits per component */
+#define HDR10_BPC_POS			0
+#define HDR10_BPC_MASK			GENMASK(1, 0)
+/* colorspace */
+#define HDR10_CS_POS			2
+#define HDR10_CS_MASK			GENMASK(3, 2)
+/* nonlinearity type */
+#define HDR10_NL_POS			4
+#define HDR10_NL_MASK			GENMASK(8, 4)
+/* pixel range */
+#define HDR10_PR_POS			9
+#define HDR10_PR_MASK			GENMASK(10, 9)
+/* gamut type */
+#define HDR10_G_POS			11
+#define HDR10_G_MASK			GENMASK(15, 11)
+
+/* FW Table Type Descriptor */
+#define HDR10_TT_LUT			BIT(0)
+#define HDR10_TT_CSCA			BIT(1)
+#define HDR10_TT_CSCB			BIT(2)
+/* Pipe type */
+#define HDR10_PT_OUTPUT			BIT(3)
+/* Output pipe config descriptor */
+#define HDR10_IPIPE_DESC_POS		4
+#define HDR10_IPIPE_DESC_MASK		GENMASK(19, 4)
+/* Input pipe config descriptor */
+#define HDR10_OPIPE_DESC_POS		20
+#define HDR10_OPIPE_DESC_MASK		GENMASK(35, 20)
+
+/* config invalid */
+#define HDR10_DESC_INVALID		BIT(63)
+
+enum dcss_hdr10_csc {
+	HDR10_CSCA,
+	HDR10_CSCB,
+};
+
+struct dcss_hdr10_tbl_node {
+	struct list_head node;
+
+	u64 tbl_descriptor;
+	u32 *tbl_data;
+};
+
+struct dcss_hdr10_opipe_tbls {
+	struct list_head lut;
+	struct list_head csc;
+};
+
+struct dcss_hdr10_ipipe_tbls {
+	struct list_head lut;
+	struct list_head csca;
+	struct list_head cscb;
+};
+
+struct dcss_hdr10_ch {
+	struct dcss_hdr10 *hdr10;
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	u64 old_cfg_desc;
+
+	u32 id;
+};
+
+struct dcss_hdr10 {
+	struct device *dev;
+	struct dcss_ctxld *ctxld;
+
+	u32 ctx_id;
+
+	struct dcss_hdr10_ch ch[4]; /* 4th channel is, actually, OPIPE */
+
+	struct dcss_hdr10_ipipe_tbls *ipipe_tbls;
+	struct dcss_hdr10_opipe_tbls *opipe_tbls;
+
+	u8 *fw_data;
+	u32 fw_size;
+};
+
+static void dcss_hdr10_write(struct dcss_hdr10_ch *ch, u32 val, u32 ofs)
+{
+	struct dcss_hdr10 *hdr10 = ch->hdr10;
+
+	dcss_ctxld_write(hdr10->ctxld, hdr10->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static void dcss_hdr10_csc_fill(struct dcss_hdr10_ch *ch,
+				enum dcss_hdr10_csc csc_to_use,
+				u32 *map)
+{
+	int i;
+	u32 csc_base_ofs[] = {
+		DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
+		DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
+	};
+
+	for (i = 0; i < HDR10_CSC_MAX_REGS; i++) {
+		u32 reg_ofs = csc_base_ofs[csc_to_use] + i * sizeof(u32);
+
+		dcss_hdr10_write(ch, map[i], reg_ofs);
+	}
+}
+
+static void dcss_hdr10_lut_fill(struct dcss_hdr10_ch *ch, u32 *map)
+{
+	int i, comp;
+	u32 lut_base_ofs, ctrl_ofs, lut_entries;
+
+	if (ch->id == OPIPE_CH_NO) {
+		ctrl_ofs = DCSS_HDR10_LTNL;
+		lut_entries = HDR10_OPIPE_LUT_MAX_ENTRIES;
+	} else {
+		ctrl_ofs = DCSS_HDR10_LUT_CONTROL;
+		lut_entries = HDR10_IPIPE_LUT_MAX_ENTRIES;
+	}
+
+	if (ch->id != OPIPE_CH_NO)
+		dcss_hdr10_write(ch, *map++, ctrl_ofs);
+
+	for (comp = 0; comp < 3; comp++) {
+		lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
+
+		if (ch->id == OPIPE_CH_NO) {
+			dcss_hdr10_write(ch, map[0], lut_base_ofs);
+			lut_base_ofs += 4;
+		}
+
+		for (i = 0; i < lut_entries; i++) {
+			u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
+
+			dcss_hdr10_write(ch, map[i], reg_ofs);
+		}
+	}
+
+	map += lut_entries;
+
+	if (ch->id != OPIPE_CH_NO)
+		dcss_hdr10_write(ch, *map, DCSS_HDR10_FL2FX);
+	else
+		dcss_hdr10_write(ch, *map, ctrl_ofs);
+}
+
+static int dcss_hdr10_ch_init_all(struct dcss_hdr10 *hdr10,
+				  unsigned long hdr10_base)
+{
+	struct dcss_hdr10_ch *ch;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		ch = &hdr10->ch[i];
+
+		ch->base_ofs = hdr10_base + i * 0x4000;
+
+		ch->base_reg = devm_ioremap(hdr10->dev, ch->base_ofs, SZ_16K);
+		if (!ch->base_reg) {
+			dev_err(hdr10->dev, "hdr10: unable to remap ch base\n");
+			return -ENOMEM;
+		}
+
+		ch->old_cfg_desc = HDR10_DESC_INVALID;
+
+		ch->id = i;
+		ch->hdr10 = hdr10;
+	}
+
+	return 0;
+}
+
+static u32 *dcss_hdr10_find_tbl(u64 desc, struct list_head *head)
+{
+	struct list_head *node;
+	struct dcss_hdr10_tbl_node *tbl_node;
+
+	list_for_each(node, head) {
+		tbl_node = container_of(node, struct dcss_hdr10_tbl_node, node);
+
+		if ((tbl_node->tbl_descriptor & desc) == desc)
+			return tbl_node->tbl_data;
+	}
+
+	return NULL;
+}
+
+static int dcss_hdr10_get_tbls(struct dcss_hdr10 *hdr10, bool input,
+			       u64 desc, u32 **lut, u32 **csca, u32 **cscb)
+{
+	struct list_head *lut_list, *csca_list, *cscb_list;
+
+	lut_list = input ? &hdr10->ipipe_tbls->lut : &hdr10->opipe_tbls->lut;
+	csca_list = input ? &hdr10->ipipe_tbls->csca : &hdr10->opipe_tbls->csc;
+	cscb_list = input ? &hdr10->ipipe_tbls->cscb : NULL;
+
+	*lut = dcss_hdr10_find_tbl(desc, lut_list);
+	*csca = dcss_hdr10_find_tbl(desc, csca_list);
+
+	*cscb = NULL;
+	if (cscb_list)
+		*cscb = dcss_hdr10_find_tbl(desc, cscb_list);
+
+	return 0;
+}
+
+static void dcss_hdr10_write_pipe_tbls(struct dcss_hdr10_ch *ch,
+				       u32 *lut, u32 *csca, u32 *cscb)
+{
+	if (csca)
+		dcss_hdr10_csc_fill(ch, HDR10_CSCA, csca);
+
+	if (ch->id != OPIPE_CH_NO && cscb)
+		dcss_hdr10_csc_fill(ch, HDR10_CSCB, cscb);
+
+	if (lut)
+		dcss_hdr10_lut_fill(ch, lut);
+}
+
+static int dcss_hdr10_tbl_add(struct dcss_hdr10 *hdr10, u64 desc, u32 sz,
+			      u32 *data)
+{
+	struct device *dev = hdr10->dev;
+	struct dcss_hdr10_tbl_node *node;
+
+	node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	/* we don't need to store the table type and pipe type */
+	node->tbl_descriptor = desc >> 4;
+	node->tbl_data = data;
+
+	if (!(desc & HDR10_PT_OUTPUT)) {
+		if (desc & HDR10_TT_LUT)
+			list_add(&node->node, &hdr10->ipipe_tbls->lut);
+		else if (desc & HDR10_TT_CSCA)
+			list_add(&node->node, &hdr10->ipipe_tbls->csca);
+		else if (desc & HDR10_TT_CSCB)
+			list_add(&node->node, &hdr10->ipipe_tbls->cscb);
+
+		return 0;
+	}
+
+	if (desc & HDR10_TT_LUT)
+		list_add(&node->node, &hdr10->opipe_tbls->lut);
+	else if (desc & HDR10_TT_CSCA)
+		list_add(&node->node, &hdr10->opipe_tbls->csc);
+
+	return 0;
+}
+
+static int dcss_hdr10_parse_fw_data(struct dcss_hdr10 *hdr10)
+{
+	u32 *data = (u32 *)hdr10->fw_data;
+	u32 remaining = hdr10->fw_size / sizeof(u32);
+	u64 tbl_desc;
+	u32 tbl_size;
+	int ret;
+
+	while (remaining) {
+		tbl_desc = *((u64 *)data);
+		data += 2;
+		tbl_size = *data++;
+
+		ret = dcss_hdr10_tbl_add(hdr10, tbl_desc, tbl_size, data);
+		if (ret)
+			return ret;
+
+		data += tbl_size;
+		remaining -= tbl_size + 3;
+	}
+
+	return 0;
+}
+
+static void dcss_hdr10_cleanup_tbls(struct dcss_hdr10 *hdr10)
+{
+	int i;
+	struct dcss_hdr10_tbl_node *tbl_node, *next;
+	struct list_head *tbls[] = {
+		&hdr10->ipipe_tbls->lut,
+		&hdr10->ipipe_tbls->csca,
+		&hdr10->ipipe_tbls->cscb,
+		&hdr10->opipe_tbls->lut,
+		&hdr10->opipe_tbls->csc,
+	};
+
+	for (i = 0; i < 5; i++) {
+		list_for_each_entry_safe(tbl_node, next, tbls[i], node) {
+			list_del(&tbl_node->node);
+			devm_kfree(hdr10->dev, tbl_node);
+		}
+	}
+
+	devm_kfree(hdr10->dev, hdr10->opipe_tbls);
+	devm_kfree(hdr10->dev, hdr10->ipipe_tbls);
+}
+
+#ifndef USE_TBL_HEADER
+static void dcss_hdr10_fw_handler(const struct firmware *fw, void *context)
+{
+	struct dcss_hdr10 *hdr10 = context;
+	int i;
+
+	if (!fw) {
+		dev_err(hdr10->dev, "hdr10: DCSS FW load failed.\n");
+		return;
+	}
+
+	/* we need to keep the tables for the entire life of the driver */
+	hdr10->fw_data = devm_kzalloc(hdr10->dev, fw->size, GFP_KERNEL);
+	if (!hdr10->fw_data)
+		return;
+
+	memcpy(hdr10->fw_data, fw->data, fw->size);
+	hdr10->fw_size = fw->size;
+
+	release_firmware(fw);
+
+	if (dcss_hdr10_parse_fw_data(hdr10)) {
+		dcss_hdr10_cleanup_tbls(hdr10);
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		u32 *lut, *csca, *cscb;
+		struct dcss_hdr10_ch *ch = &hdr10->ch[i];
+		bool is_input_pipe = i != OPIPE_CH_NO ? true : false;
+
+		if (ch->old_cfg_desc != HDR10_DESC_INVALID) {
+			dcss_hdr10_get_tbls(hdr10, is_input_pipe,
+					    ch->old_cfg_desc, &lut,
+					    &csca, &cscb);
+			dcss_hdr10_write_pipe_tbls(ch, lut, csca, cscb);
+		}
+	}
+
+	dev_info(hdr10->dev, "hdr10: DCSS FW loaded successfully\n");
+}
+#endif
+
+static int dcss_hdr10_tbls_init(struct dcss_hdr10 *hdr10)
+{
+	struct device *dev = hdr10->dev;
+
+	hdr10->ipipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->ipipe_tbls),
+					 GFP_KERNEL);
+	if (!hdr10->ipipe_tbls)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&hdr10->ipipe_tbls->lut);
+	INIT_LIST_HEAD(&hdr10->ipipe_tbls->csca);
+	INIT_LIST_HEAD(&hdr10->ipipe_tbls->cscb);
+
+	hdr10->opipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->opipe_tbls),
+					 GFP_KERNEL);
+	if (!hdr10->opipe_tbls) {
+		devm_kfree(dev, hdr10->ipipe_tbls);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&hdr10->opipe_tbls->lut);
+	INIT_LIST_HEAD(&hdr10->opipe_tbls->csc);
+
+	return 0;
+}
+
+int dcss_hdr10_init(struct dcss_dev *dcss, unsigned long hdr10_base)
+{
+	int ret;
+	struct dcss_hdr10 *hdr10;
+
+	hdr10 = devm_kzalloc(dcss->dev, sizeof(*hdr10), GFP_KERNEL);
+	if (!hdr10)
+		return -ENOMEM;
+
+	dcss->hdr10 = hdr10;
+	hdr10->dev = dcss->dev;
+	hdr10->ctx_id = CTX_SB_HP;
+	hdr10->ctxld = dcss->ctxld;
+
+	ret = dcss_hdr10_tbls_init(hdr10);
+	if (ret < 0) {
+		dev_err(dcss->dev, "hdr10: Cannot init table lists.\n");
+		goto cleanup;
+	}
+
+#ifndef USE_TBL_HEADER
+	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "dcss.fw",
+				      dcss->dev, GFP_KERNEL, hdr10,
+				      dcss_hdr10_fw_handler);
+	if (ret < 0) {
+		dev_err(dcss->dev, "hdr10: Cannot async load DCSS FW.\n");
+		goto cleanup_tbls;
+	}
+#else
+	hdr10->fw_data = (u8 *)dcss_hdr10_tables;
+	hdr10->fw_size = sizeof(dcss_hdr10_tables);
+
+	ret = dcss_hdr10_parse_fw_data(hdr10);
+	if (ret)
+		goto cleanup_tbls;
+#endif
+
+	ret = dcss_hdr10_ch_init_all(hdr10, hdr10_base);
+	if (ret) {
+		int i;
+
+		for (i = 0; i < 4; i++) {
+			if (hdr10->ch[i].base_reg)
+				devm_iounmap(hdr10->dev, hdr10->ch[i].base_reg);
+		}
+
+		goto cleanup_tbls;
+	}
+
+	return 0;
+
+cleanup_tbls:
+	dcss_hdr10_cleanup_tbls(hdr10);
+
+cleanup:
+	devm_kfree(hdr10->dev, hdr10);
+
+	return ret;
+}
+
+void dcss_hdr10_exit(struct dcss_hdr10 *hdr10)
+{
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if (hdr10->ch[i].base_reg)
+			devm_iounmap(hdr10->dev, hdr10->ch[i].base_reg);
+	}
+
+	dcss_hdr10_cleanup_tbls(hdr10);
+
+	devm_kfree(hdr10->dev, hdr10);
+}
+
+static u32 dcss_hdr10_pipe_desc(struct dcss_hdr10_pipe_cfg *pipe_cfg)
+{
+	u32 desc;
+
+	desc = 2 << HDR10_BPC_POS;
+	desc |= pipe_cfg->is_yuv ? 2 << HDR10_CS_POS : 1 << HDR10_CS_POS;
+	desc |= ((1 << pipe_cfg->nl) << HDR10_NL_POS) & HDR10_NL_MASK;
+	desc |= ((1 << pipe_cfg->pr) << HDR10_PR_POS) & HDR10_PR_MASK;
+	desc |= ((1 << pipe_cfg->g) << HDR10_G_POS) & HDR10_G_MASK;
+
+	return desc;
+}
+
+static u64 dcss_hdr10_get_desc(struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+			       struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+	u32 ipipe_desc, opipe_desc;
+
+	ipipe_desc = dcss_hdr10_pipe_desc(ipipe_cfg);
+	opipe_desc = dcss_hdr10_pipe_desc(opipe_cfg);
+
+	return (ipipe_desc & 0xFFFF) | ((opipe_desc & 0xFFFF) << 16);
+}
+
+static void dcss_hdr10_pipe_setup(struct dcss_hdr10_ch *ch, u64 desc)
+{
+	bool pipe_cfg_chgd;
+	u32 *csca, *cscb, *lut;
+
+	pipe_cfg_chgd = ch->old_cfg_desc != desc;
+
+	if (!pipe_cfg_chgd)
+		return;
+
+	dcss_hdr10_get_tbls(ch->hdr10, ch->id != OPIPE_CH_NO,
+			    desc, &lut, &csca, &cscb);
+	dcss_hdr10_write_pipe_tbls(ch, lut, csca, cscb);
+
+	ch->old_cfg_desc = desc;
+}
+
+void dcss_hdr10_setup(struct dcss_hdr10 *hdr10, int ch_num,
+		      struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+		      struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+	u64 desc = dcss_hdr10_get_desc(ipipe_cfg, opipe_cfg);
+
+	dcss_hdr10_pipe_setup(&hdr10->ch[ch_num], desc);
+
+	/*
+	 * Input pipe configuration doesn't matter for configuring the output
+	 * pipe. So, will just mask off the input part of the descriptor.
+	 */
+	dcss_hdr10_pipe_setup(&hdr10->ch[OPIPE_CH_NO], desc & ~0xffff);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <linux/component.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops);
+
+struct dcss_drm_commit {
+	struct work_struct work;
+	struct drm_device *drm;
+	struct drm_atomic_state *state;
+};
+
+static void dcss_kms_setup_opipe_gamut(u32 colorspace,
+				       const struct drm_display_mode *mode,
+				       enum dcss_hdr10_gamut *g,
+				       enum dcss_hdr10_nonlinearity *nl)
+{
+	u8 vic;
+
+	switch (colorspace) {
+	case DRM_MODE_COLORIMETRY_BT709_YCC:
+	case DRM_MODE_COLORIMETRY_XVYCC_709:
+		*g = G_REC709;
+		*nl = NL_REC709;
+		return;
+	case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC:
+	case DRM_MODE_COLORIMETRY_XVYCC_601:
+	case DRM_MODE_COLORIMETRY_SYCC_601:
+	case DRM_MODE_COLORIMETRY_OPYCC_601:
+		*g = G_REC601_NTSC;
+		*nl = NL_REC709;
+		return;
+	case DRM_MODE_COLORIMETRY_BT2020_CYCC:
+	case DRM_MODE_COLORIMETRY_BT2020_RGB:
+	case DRM_MODE_COLORIMETRY_BT2020_YCC:
+		*g = G_REC2020;
+		*nl = NL_REC2084;
+		return;
+	case DRM_MODE_COLORIMETRY_OPRGB:
+		*g = G_ADOBE_ARGB;
+		*nl = NL_SRGB;
+		return;
+	default:
+		break;
+	}
+
+	/*
+	 * If we reached this point, it means the default colorimetry is used.
+	 */
+
+	/* non-CEA mode, sRGB is used */
+	vic = drm_match_cea_mode(mode);
+	if (vic == 0) {
+		*g = G_ADOBE_ARGB;
+		*nl = NL_SRGB;
+		return;
+	}
+
+	if (mode->vdisplay == 480 || mode->vdisplay == 576 ||
+	    mode->vdisplay == 240 || mode->vdisplay == 288) {
+		*g = G_REC601_NTSC;
+		*nl = NL_REC709;
+		return;
+	}
+
+	/* 2160p, 1080p, 720p */
+	*g = G_REC709;
+	*nl = NL_REC709;
+}
+
+#define YUV_MODE		BIT(0)
+
+void dcss_kms_setup_opipe(struct drm_connector_state *conn_state)
+{
+	struct drm_crtc *crtc = conn_state->crtc;
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	int mode_flags = crtc->state->adjusted_mode.private_flags;
+	enum hdmi_quantization_range qr;
+
+	qr = drm_default_rgb_quant_range(&crtc->state->adjusted_mode);
+
+	dcss_kms_setup_opipe_gamut(conn_state->colorspace,
+				   &crtc->state->adjusted_mode,
+				   &dcss_crtc->opipe_g,
+				   &dcss_crtc->opipe_nl);
+
+	dcss_crtc->opipe_pr = qr == HDMI_QUANTIZATION_RANGE_FULL ? PR_FULL :
+								   PR_LIMITED;
+
+	dcss_crtc->output_is_yuv = !!(mode_flags & YUV_MODE);
+}
+
+static void dcss_kms_setup_output_pipe(struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	struct drm_display_info *di;
+	int i;
+
+	for_each_new_connector_in_state(state, connector, conn_state, i) {
+		if (!conn_state->best_encoder)
+			continue;
+
+		if (!conn_state->crtc->state->active ||
+		    !drm_atomic_crtc_needs_modeset(conn_state->crtc->state))
+			continue;
+
+		crtc = connector->state->crtc;
+		di = &connector->display_info;
+
+		dcss_kms_setup_opipe(conn_state);
+	}
+}
+
+static void dcss_drm_atomic_commit_tail(struct dcss_drm_commit *commit)
+{
+	struct drm_atomic_state *state = commit->state;
+	struct drm_device *drm = commit->drm;
+	struct dcss_kms_dev *kms = container_of(drm, struct dcss_kms_dev, base);
+
+	drm_atomic_helper_wait_for_fences(drm, state, false);
+
+	drm_atomic_helper_wait_for_dependencies(state);
+
+	drm_atomic_helper_commit_modeset_disables(drm, state);
+
+	dcss_kms_setup_output_pipe(state);
+
+	drm_atomic_helper_commit_modeset_enables(drm, state);
+
+	drm_atomic_helper_commit_planes(drm, state,
+					DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+	drm_atomic_helper_commit_hw_done(state);
+
+	drm_atomic_helper_wait_for_vblanks(drm, state);
+
+	drm_atomic_helper_cleanup_planes(drm, state);
+
+	drm_atomic_helper_commit_cleanup_done(state);
+
+	drm_atomic_state_put(state);
+
+	spin_lock(&kms->commit.wait.lock);
+	kms->commit.pending = false;
+	wake_up_all_locked(&kms->commit.wait);
+	spin_unlock(&kms->commit.wait.lock);
+
+	kfree(commit);
+}
+
+static void dcss_commit_work(struct work_struct *work)
+{
+	struct dcss_drm_commit *commit = container_of(work,
+						      struct dcss_drm_commit,
+						      work);
+
+	dcss_drm_atomic_commit_tail(commit);
+}
+
+static int dcss_drm_atomic_commit(struct drm_device *drm,
+				  struct drm_atomic_state *state,
+				  bool nonblock)
+{
+	int ret;
+	struct dcss_kms_dev *kms = container_of(drm, struct dcss_kms_dev, base);
+	struct dcss_drm_commit *commit;
+
+	if (state->async_update) {
+		ret = drm_atomic_helper_prepare_planes(drm, state);
+		if (ret)
+			return ret;
+
+		drm_atomic_helper_async_commit(drm, state);
+		drm_atomic_helper_cleanup_planes(drm, state);
+
+		return 0;
+	}
+
+	commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+	if (!commit)
+		return -ENOMEM;
+
+	commit->drm = drm;
+	commit->state = state;
+
+	ret = drm_atomic_helper_setup_commit(state, nonblock);
+	if (ret)
+		goto err_free;
+
+	INIT_WORK(&commit->work, dcss_commit_work);
+
+	ret = drm_atomic_helper_prepare_planes(drm, state);
+	if (ret)
+		goto err_free;
+
+	if (!nonblock) {
+		ret = drm_atomic_helper_wait_for_fences(drm, state, true);
+		if (ret)
+			goto err;
+	}
+
+	spin_lock(&kms->commit.wait.lock);
+	ret = wait_event_interruptible_locked(kms->commit.wait,
+					      !kms->commit.pending);
+	if (ret == 0)
+		kms->commit.pending = true;
+	spin_unlock(&kms->commit.wait.lock);
+
+	if (ret)
+		goto err;
+
+	ret = drm_atomic_helper_swap_state(state, true);
+	if (ret)
+		goto err;
+
+	drm_atomic_state_get(state);
+	if (nonblock)
+		queue_work(kms->commit_wq, &commit->work);
+	else
+		dcss_drm_atomic_commit_tail(commit);
+
+	return 0;
+
+err:
+	drm_atomic_helper_cleanup_planes(drm, state);
+
+err_free:
+	kfree(commit);
+	return ret;
+}
+
+const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = dcss_drm_atomic_commit,
+};
+
+static struct drm_driver dcss_kms_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+	.gem_free_object_unlocked = drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= drm_gem_cma_dumb_create,
+
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+	.fops			= &dcss_cma_fops,
+	.name			= "imx-dcss",
+	.desc			= "i.MX8MQ Display Subsystem",
+	.date			= "20190917",
+	.major			= 1,
+	.minor			= 0,
+	.patchlevel		= 0,
+};
+
+static const struct drm_mode_config_helper_funcs dcss_mode_config_helpers = {
+	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
+static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms)
+{
+	struct drm_mode_config *config = &kms->base.mode_config;
+
+	drm_mode_config_init(&kms->base);
+
+	config->min_width = 1;
+	config->min_height = 1;
+	config->max_width = 4096;
+	config->max_height = 4096;
+	config->allow_fb_modifiers = true;
+	config->normalize_zpos = true;
+
+	config->funcs = &dcss_drm_mode_config_funcs;
+	config->helper_private = &dcss_mode_config_helpers;
+}
+
+static const struct drm_encoder_funcs dcss_kms_simple_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int dcss_kms_setup_encoder(struct dcss_kms_dev *kms)
+{
+	struct drm_device *ddev = &kms->base;
+	struct drm_encoder *encoder = &kms->encoder;
+	struct drm_crtc *crtc = (struct drm_crtc *)&kms->crtc;
+	struct drm_panel *panel;
+	struct drm_bridge *bridge;
+	int ret;
+
+	ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0,
+					  &panel, &bridge);
+	if (ret)
+		return ret;
+
+	if (!bridge) {
+		dev_err(ddev->dev, "No bridge found %d.\n", ret);
+		return -ENODEV;
+	}
+
+	encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+	ret = drm_encoder_init(&kms->base, encoder,
+			       &dcss_kms_simple_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
+	if (ret) {
+		dev_err(ddev->dev, "Failed initializing encoder %d.\n", ret);
+		return ret;
+	}
+
+	return drm_bridge_attach(encoder, bridge, NULL);
+}
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized)
+{
+	struct dcss_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
+	struct drm_device *drm;
+	struct dcss_crtc *crtc;
+	int ret;
+
+	if (!kms)
+		return ERR_PTR(-ENOMEM);
+
+	drm = &kms->base;
+	crtc = &kms->crtc;
+	ret = drm_dev_init(drm, &dcss_kms_driver, dcss->dev);
+	if (ret)
+		goto free_kms;
+
+	drm->dev_private = dcss;
+
+	dcss_kms_mode_config_init(kms);
+
+	ret = drm_vblank_init(drm, 1);
+	if (ret)
+		goto cleanup_mode_config;
+
+	drm->irq_enabled = true;
+
+	ret = dcss_crtc_init(crtc, drm);
+	if (ret)
+		goto cleanup_mode_config;
+
+	kms->commit_wq = alloc_ordered_workqueue("dcss_nonblock_commit_wq", 0);
+	if (!kms->commit_wq) {
+		ret = -ENOMEM;
+		goto cleanup_crtc;
+	}
+
+	init_waitqueue_head(&kms->commit.wait);
+
+	if (componentized)
+		ret = component_bind_all(dcss->dev, kms);
+	else
+		ret = dcss_kms_setup_encoder(kms);
+
+	if (ret)
+		goto cleanup_wq;
+
+	drm_mode_config_reset(drm);
+
+	dcss_crtc_attach_color_mgmt_properties(crtc);
+
+	drm_kms_helper_poll_init(drm);
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto cleanup_wq;
+
+	drm_fbdev_generic_setup(drm, 32);
+
+	return kms;
+
+cleanup_wq:
+	drm_kms_helper_poll_fini(drm);
+	destroy_workqueue(kms->commit_wq);
+
+cleanup_crtc:
+	dcss_crtc_deinit(crtc, drm);
+
+cleanup_mode_config:
+	drm_mode_config_cleanup(drm);
+
+free_kms:
+	kfree(kms);
+	return ERR_PTR(ret);
+}
+
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized)
+{
+	struct drm_device *drm = &kms->base;
+	struct dcss_dev *dcss = drm->dev_private;
+
+	drm_dev_unregister(drm);
+	drm_kms_helper_poll_fini(drm);
+	drm_atomic_helper_shutdown(drm);
+	drm_crtc_vblank_off(&kms->crtc.base);
+	drm->irq_enabled = false;
+	drm_mode_config_cleanup(drm);
+	destroy_workqueue(kms->commit_wq);
+	dcss_crtc_deinit(&kms->crtc, drm);
+	if (componentized)
+		component_unbind_all(dcss->dev, drm);
+	drm->dev_private = NULL;
+	drm_dev_put(drm);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-kms.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef _DCSS_KMS_H_
+#define _DCSS_KMS_H_
+
+#include <drm/drm_encoder.h>
+
+struct dcss_plane {
+	struct drm_plane base;
+
+	uint64_t dtrc_table_ofs_val;
+	struct drm_property *dtrc_table_ofs_prop;
+
+	int ch_num;
+
+	enum drm_plane_type type;
+	bool use_dtrc;
+};
+
+struct dcss_crtc {
+	struct drm_crtc		base;
+	struct drm_crtc_state	*state;
+
+	struct dcss_plane	*plane[3];
+
+	int			irq;
+	bool			irq_enabled;
+
+	struct completion en_completion;
+	struct completion dis_completion;
+
+	bool output_is_yuv;
+	enum dcss_hdr10_nonlinearity opipe_nl;
+	enum dcss_hdr10_gamut opipe_g;
+	enum dcss_hdr10_pixel_range opipe_pr;
+};
+
+struct commit {
+	wait_queue_head_t wait;
+	bool pending;
+};
+
+struct dcss_kms_dev {
+	struct drm_device base;
+	struct dcss_crtc crtc;
+	struct drm_encoder encoder;
+	struct workqueue_struct *commit_wq;
+	struct commit commit;
+};
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized);
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized);
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm);
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm);
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+				   unsigned int possible_crtcs,
+				   enum drm_plane_type type,
+				   unsigned int zpos);
+void dcss_crtc_attach_color_mgmt_properties(struct dcss_crtc *crtc);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-plane.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <linux/dma-buf.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static const u32 dcss_fb_formats[] = {
+	/* RGB */
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_RGBX1010102,
+	DRM_FORMAT_BGRX1010102,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_RGBA1010102,
+	DRM_FORMAT_BGRA1010102,
+
+	/* YUV444 */
+	DRM_FORMAT_AYUV,
+
+	/* YUV422 */
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+
+	/* YUV420 */
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV12_10LE40,
+};
+
+static const u64 dcss_video_format_modifiers[] = {
+	DRM_FORMAT_MOD_VSI_G1_TILED,
+	DRM_FORMAT_MOD_VSI_G2_TILED,
+	DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const u64 dcss_graphics_format_modifiers[] = {
+	DRM_FORMAT_MOD_VIVANTE_TILED,
+	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
+{
+	return container_of(p, struct dcss_plane, base);
+}
+
+static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
+{
+	return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
+	       ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
+		fb->modifier == DRM_FORMAT_MOD_LINEAR);
+}
+
+static void dcss_plane_destroy(struct drm_plane *plane)
+{
+	struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
+						     base);
+
+	drm_plane_cleanup(plane);
+	kfree(dcss_plane);
+}
+
+static int dcss_plane_atomic_set_property(struct drm_plane *plane,
+					  struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t val)
+{
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+	if (property == dcss_plane->dtrc_table_ofs_prop)
+		dcss_plane->dtrc_table_ofs_val = val;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dcss_plane_atomic_get_property(struct drm_plane *plane,
+					  const struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t *val)
+{
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+	if (property == dcss_plane->dtrc_table_ofs_prop)
+		*val = dcss_plane->dtrc_table_ofs_val;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
+					    u32 format,
+					    u64 modifier)
+{
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		switch (format) {
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_XRGB8888:
+		case DRM_FORMAT_ARGB2101010:
+			return modifier == DRM_FORMAT_MOD_LINEAR ||
+			       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+			       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+			       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC;
+		default:
+			return modifier == DRM_FORMAT_MOD_LINEAR;
+		}
+		break;
+	case DRM_PLANE_TYPE_OVERLAY:
+		switch (format) {
+		case DRM_FORMAT_NV12:
+		case DRM_FORMAT_NV21:
+		case DRM_FORMAT_NV12_10LE40:
+			return modifier == DRM_FORMAT_MOD_LINEAR ||
+			       modifier == DRM_FORMAT_MOD_VSI_G1_TILED ||
+			       modifier == DRM_FORMAT_MOD_VSI_G2_TILED ||
+			       modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED;
+		default:
+			return modifier == DRM_FORMAT_MOD_LINEAR;
+		}
+		break;
+	default:
+		return false;
+	}
+
+	return false;
+}
+
+static const struct drm_plane_funcs dcss_plane_funcs = {
+	.update_plane		= drm_atomic_helper_update_plane,
+	.disable_plane		= drm_atomic_helper_disable_plane,
+	.destroy		= dcss_plane_destroy,
+	.reset			= drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
+	.atomic_set_property	= dcss_plane_atomic_set_property,
+	.atomic_get_property	= dcss_plane_atomic_get_property,
+	.format_mod_supported	= dcss_plane_format_mod_supported,
+};
+
+static bool dcss_plane_can_rotate(const struct drm_format_info *format,
+				  bool mod_present, u64 modifier,
+				  unsigned int rotation)
+{
+	bool linear_format = !mod_present ||
+			     (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
+	u32 supported_rotation = DRM_MODE_ROTATE_0;
+
+	if (!format->is_yuv && linear_format)
+		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+				     DRM_MODE_REFLECT_MASK;
+	else if (!format->is_yuv &&
+		 modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+		supported_rotation = DRM_MODE_ROTATE_MASK |
+				     DRM_MODE_REFLECT_MASK;
+	else if (format->is_yuv && linear_format &&
+		 (format->format == DRM_FORMAT_NV12 ||
+		  format->format == DRM_FORMAT_NV21))
+		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+				     DRM_MODE_REFLECT_MASK;
+	else if (format->is_yuv && linear_format &&
+		 format->format == DRM_FORMAT_NV12_10LE40)
+		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
+
+	return !!(rotation & supported_rotation);
+}
+
+static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
+{
+	if (src_w < 64 &&
+	    (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21 ||
+	     pix_fmt == DRM_FORMAT_NV12_10LE40))
+		return false;
+	else if (src_w < 32 &&
+		 (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
+		  pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
+		return false;
+
+	return src_w >= 16 && src_h >= 8;
+}
+
+static inline bool dcss_plane_use_dtrc(struct drm_framebuffer *fb,
+				       enum drm_plane_type type)
+{
+	u64 pix_format = fb->format->format;
+
+	return !dcss_plane_fb_is_linear(fb) &&
+		type == DRM_PLANE_TYPE_OVERLAY &&
+		(pix_format == DRM_FORMAT_NV12 ||
+		pix_format == DRM_FORMAT_NV21 ||
+		pix_format == DRM_FORMAT_NV12_10LE40);
+}
+
+static int dcss_plane_atomic_check(struct drm_plane *plane,
+				   struct drm_plane_state *state)
+{
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+	struct dcss_dev *dcss = plane->dev->dev_private;
+	struct drm_framebuffer *fb = state->fb;
+	bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
+	struct drm_gem_cma_object *cma_obj;
+	struct drm_crtc_state *crtc_state;
+	int hdisplay, vdisplay;
+	int min, max;
+	int ret;
+
+	if (!fb || !state->crtc)
+		return 0;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	WARN_ON(!cma_obj);
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+							state->crtc);
+
+	hdisplay = crtc_state->adjusted_mode.hdisplay;
+	vdisplay = crtc_state->adjusted_mode.vdisplay;
+
+	if (!dcss_plane_is_source_size_allowed(state->src_w >> 16,
+					       state->src_h >> 16,
+					       fb->format->format)) {
+		DRM_DEBUG_KMS("Source plane size is not allowed!\n");
+		return -EINVAL;
+	}
+
+	dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
+				       &min, &max);
+
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+						  min, max, !is_primary_plane,
+						  false);
+	if (ret)
+		return ret;
+
+	if (!state->visible)
+		return 0;
+
+	if (!dcss_plane_can_rotate(fb->format,
+				   !!(fb->flags & DRM_MODE_FB_MODIFIERS),
+				   fb->modifier,
+				   state->rotation)) {
+		DRM_DEBUG_KMS("requested rotation is not allowed!\n");
+		return -EINVAL;
+	}
+
+	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+	    !plane->funcs->format_mod_supported(plane,
+				fb->format->format,
+				fb->modifier)) {
+		DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
+		return -EINVAL;
+	}
+
+	dcss_plane->use_dtrc = dcss_plane_use_dtrc(fb, plane->type);
+
+	return 0;
+}
+
+static struct drm_gem_object *dcss_plane_gem_import(struct drm_device *dev,
+						    struct dma_buf *dma_buf)
+{
+	struct drm_gem_object *obj;
+
+	if (IS_ERR(dma_buf))
+		return ERR_CAST(dma_buf);
+
+	mutex_lock(&dev->object_name_lock);
+
+	obj = dev->driver->gem_prime_import(dev, dma_buf);
+
+	mutex_unlock(&dev->object_name_lock);
+
+	return obj;
+}
+
+static void dcss_plane_set_primary_base(struct dcss_plane *dcss_plane,
+					u32 baddr)
+{
+	struct drm_plane *plane = &dcss_plane->base;
+	struct dcss_dev *dcss = plane->dev->dev_private;
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct dma_buf *dma_buf = cma_obj->base.dma_buf;
+	struct drm_gem_object *gem_obj;
+	dma_addr_t caddr;
+	bool compressed = true;
+	u32 compressed_format = _VIV_CFMT_ARGB8;
+	_VIV_VIDMEM_METADATA *mdata;
+
+	if (dcss_plane_fb_is_linear(fb) ||
+	    ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+	     (fb->modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+	      fb->modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))) {
+		dcss_dec400d_bypass(dcss->dec400d);
+		return;
+	}
+
+	if (!dma_buf) {
+		caddr = cma_obj->paddr + ALIGN(fb->height, 64) * fb->pitches[0];
+	} else {
+		mdata = dma_buf->priv;
+		if (!mdata || mdata->magic != VIV_VIDMEM_METADATA_MAGIC)
+			return;
+
+		gem_obj = dcss_plane_gem_import(plane->dev, mdata->ts_dma_buf);
+		if (IS_ERR(gem_obj))
+			return;
+
+		caddr = to_drm_gem_cma_obj(gem_obj)->paddr;
+
+		/* release gem_obj */
+		drm_gem_object_put_unlocked(gem_obj);
+
+		dcss_dec400d_fast_clear_config(dcss->dec400d, mdata->fc_value,
+					       mdata->fc_enabled);
+
+		compressed = !!mdata->compressed;
+		compressed_format = mdata->compress_format;
+	}
+
+	dcss_dec400d_read_config(dcss->dec400d, 0, compressed,
+				 compressed_format);
+	dcss_dec400d_addr_set(dcss->dec400d, baddr, caddr);
+}
+
+static void dcss_plane_set_dtrc_base(struct dcss_plane *dcss_plane,
+				     u32 p1_ba, u32 p2_ba)
+{
+	struct drm_plane *plane = &dcss_plane->base;
+	struct dcss_dev *dcss = plane->dev->dev_private;
+
+	if (!dcss_plane->use_dtrc) {
+		dcss_dtrc_bypass(dcss->dtrc, dcss_plane->ch_num);
+		return;
+	}
+
+	dcss_dtrc_addr_set(dcss->dtrc, dcss_plane->ch_num,
+			   p1_ba, p2_ba, dcss_plane->dtrc_table_ofs_val);
+}
+
+static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
+{
+	struct drm_plane *plane = &dcss_plane->base;
+	struct drm_plane_state *state = plane->state;
+	struct dcss_dev *dcss = plane->dev->dev_private;
+	struct drm_framebuffer *fb = state->fb;
+	const struct drm_format_info *format = fb->format;
+	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	unsigned long p1_ba = 0, p2_ba = 0;
+	u16 x1, y1;
+
+	x1 = state->src.x1 >> 16;
+	y1 = state->src.y1 >> 16;
+
+	if (!format->is_yuv ||
+	    format->format == DRM_FORMAT_NV12 ||
+	    format->format == DRM_FORMAT_NV21)
+		p1_ba = cma_obj->paddr + fb->offsets[0] +
+			fb->pitches[0] * y1 +
+			format->char_per_block[0] * x1;
+	else if (format->format == DRM_FORMAT_NV12_10LE40)
+		p1_ba = cma_obj->paddr + fb->offsets[0] +
+			fb->pitches[0] * y1 +
+			format->char_per_block[0] * (x1 >> 2);
+	else if (format->format == DRM_FORMAT_UYVY ||
+		 format->format == DRM_FORMAT_VYUY ||
+		 format->format == DRM_FORMAT_YUYV ||
+		 format->format == DRM_FORMAT_YVYU)
+		p1_ba = cma_obj->paddr + fb->offsets[0] +
+			fb->pitches[0] * y1 +
+			2 * format->char_per_block[0] * (x1 >> 1);
+
+	if (format->format == DRM_FORMAT_NV12 ||
+	    format->format == DRM_FORMAT_NV21)
+		p2_ba = cma_obj->paddr + fb->offsets[1] +
+			(((fb->pitches[1] >> 1) * (y1 >> 1) +
+			(x1 >> 1)) << 1);
+	else if (format->format == DRM_FORMAT_NV12_10LE40)
+		p2_ba = cma_obj->paddr + fb->offsets[1] +
+			(((fb->pitches[1] >> 1) * (y1 >> 1)) << 1) +
+			format->char_per_block[1] * (x1 >> 2);
+
+	dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
+			  fb->pitches[0]);
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+		dcss_plane_set_primary_base(dcss_plane, p1_ba);
+	else
+		dcss_plane_set_dtrc_base(dcss_plane,
+					 cma_obj->paddr + fb->offsets[0],
+					 cma_obj->paddr + fb->offsets[1]);
+}
+
+static bool dcss_plane_needs_setup(struct drm_plane_state *state,
+				   struct drm_plane_state *old_state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_framebuffer *old_fb = old_state->fb;
+
+	return state->crtc_x != old_state->crtc_x ||
+	       state->crtc_y != old_state->crtc_y ||
+	       state->crtc_w != old_state->crtc_w ||
+	       state->crtc_h != old_state->crtc_h ||
+	       state->src_x  != old_state->src_x  ||
+	       state->src_y  != old_state->src_y  ||
+	       state->src_w  != old_state->src_w  ||
+	       state->src_h  != old_state->src_h  ||
+	       fb->format->format != old_fb->format->format ||
+	       fb->modifier  != old_fb->modifier ||
+	       state->rotation != old_state->rotation;
+}
+
+static void dcss_plane_setup_hdr10_pipes(struct drm_plane *plane)
+{
+	struct dcss_dev *dcss = plane->dev->dev_private;
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+	struct drm_plane_state *state = plane->state;
+	struct drm_crtc *crtc = state->crtc;
+	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+						   base);
+	struct drm_framebuffer *fb = state->fb;
+	struct dcss_hdr10_pipe_cfg ipipe_cfg, opipe_cfg;
+
+	opipe_cfg.is_yuv = dcss_crtc->output_is_yuv;
+	opipe_cfg.g = dcss_crtc->opipe_g;
+	opipe_cfg.nl = dcss_crtc->opipe_nl;
+	opipe_cfg.pr = dcss_crtc->opipe_pr;
+
+	ipipe_cfg.is_yuv = fb->format->is_yuv;
+
+	if (!fb->format->is_yuv) {
+		ipipe_cfg.nl = NL_SRGB;
+		ipipe_cfg.pr = PR_FULL;
+		ipipe_cfg.g = G_ADOBE_ARGB;
+		goto setup;
+	}
+
+	switch (state->color_encoding) {
+	case DRM_COLOR_YCBCR_BT709:
+		ipipe_cfg.nl = NL_REC709;
+		ipipe_cfg.g = G_REC709;
+		break;
+
+	case DRM_COLOR_YCBCR_BT2020:
+		ipipe_cfg.nl = NL_REC2084;
+		ipipe_cfg.g = G_REC2020;
+		break;
+
+	default:
+		ipipe_cfg.nl = NL_REC709;
+		ipipe_cfg.g = G_REC601_PAL;
+		break;
+	}
+
+	ipipe_cfg.pr = state->color_range;
+
+setup:
+	dcss_hdr10_setup(dcss->hdr10, dcss_plane->ch_num,
+			 &ipipe_cfg, &opipe_cfg);
+}
+
+static void dcss_plane_atomic_update(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+	struct dcss_dev *dcss = plane->dev->dev_private;
+	struct drm_framebuffer *fb = state->fb;
+	u32 pixel_format;
+	struct drm_crtc_state *crtc_state;
+	bool modifiers_present;
+	u32 src_w, src_h, dst_w, dst_h;
+	struct drm_rect src, dst;
+	bool enable = true;
+
+	if (!fb || !state->crtc || !state->visible)
+		return;
+
+	pixel_format = fb->format->format;
+	crtc_state = state->crtc->state;
+	modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
+
+	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
+	    !dcss_plane_needs_setup(state, old_state) &&
+	    !dcss_dtg_global_alpha_changed(dcss->dtg, dcss_plane->ch_num,
+					   state->alpha >> 8)) {
+		dcss_plane_atomic_set_base(dcss_plane);
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			dcss_dec400d_shadow_trig(dcss->dec400d);
+		return;
+	}
+
+	src = plane->state->src;
+	dst = plane->state->dst;
+
+	/*
+	 * The width and height after clipping.
+	 */
+	src_w = drm_rect_width(&src) >> 16;
+	src_h = drm_rect_height(&src) >> 16;
+	dst_w = drm_rect_width(&dst);
+	dst_h = drm_rect_height(&dst);
+
+	dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, state->fb->format,
+			    modifiers_present ? fb->modifier :
+						DRM_FORMAT_MOD_LINEAR);
+
+	if (dcss_plane->use_dtrc) {
+		u32 dtrc_w, dtrc_h;
+
+		dcss_dtrc_set_res(dcss->dtrc, dcss_plane->ch_num, state,
+				  &dtrc_w, &dtrc_h);
+		dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, dtrc_w, dtrc_h);
+	} else {
+		dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
+	}
+
+	dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
+			      state->rotation);
+
+	dcss_plane_atomic_set_base(dcss_plane);
+
+	dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
+			  state->fb->format, src_w, src_h,
+			  dst_w, dst_h,
+			  drm_mode_vrefresh(&crtc_state->mode));
+
+	dcss_plane_setup_hdr10_pipes(plane);
+
+	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+			       dst.x1, dst.y1, dst_w, dst_h);
+	dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
+				 fb->format, state->alpha >> 8);
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+		dcss_dec400d_enable(dcss->dec400d);
+	else if (dcss_plane->use_dtrc)
+		dcss_dtrc_enable(dcss->dtrc, dcss_plane->ch_num, true);
+
+	if (!dcss_plane->ch_num && (state->alpha >> 8) == 0)
+		enable = false;
+
+	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
+	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
+
+	if (!enable)
+		dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+				       0, 0, 0, 0);
+
+	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
+}
+
+static void dcss_plane_atomic_disable(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+	struct dcss_dev *dcss = plane->dev->dev_private;
+
+	if (dcss_plane->use_dtrc)
+		dcss_dtrc_enable(dcss->dtrc, dcss_plane->ch_num, false);
+	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
+	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
+	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
+	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
+}
+
+static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
+	.prepare_fb = drm_gem_fb_prepare_fb,
+	.atomic_check = dcss_plane_atomic_check,
+	.atomic_update = dcss_plane_atomic_update,
+	.atomic_disable = dcss_plane_atomic_disable,
+};
+
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+				   unsigned int possible_crtcs,
+				   enum drm_plane_type type,
+				   unsigned int zpos)
+{
+	struct dcss_plane *dcss_plane;
+	const u64 *format_modifiers = dcss_video_format_modifiers;
+	struct drm_property *prop;
+	int ret;
+
+	if (zpos > 2)
+		return ERR_PTR(-EINVAL);
+
+	dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
+	if (!dcss_plane) {
+		DRM_ERROR("failed to allocate plane\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (type == DRM_PLANE_TYPE_PRIMARY)
+		format_modifiers = dcss_graphics_format_modifiers;
+
+	ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
+				       &dcss_plane_funcs, dcss_fb_formats,
+				       ARRAY_SIZE(dcss_fb_formats),
+				       format_modifiers, type, NULL);
+	if (ret) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(dcss_plane);
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
+
+	ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drm_plane_create_rotation_property(&dcss_plane->base,
+					   DRM_MODE_ROTATE_0,
+					   DRM_MODE_ROTATE_0   |
+					   DRM_MODE_ROTATE_90  |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X  |
+					   DRM_MODE_REFLECT_Y);
+
+	dcss_plane->ch_num = 2 - zpos;
+	dcss_plane->type = type;
+
+	if (type == DRM_PLANE_TYPE_PRIMARY)
+		return dcss_plane;
+
+	prop = drm_property_create_range(drm, 0, "dtrc_table_ofs",
+					 0, ULLONG_MAX);
+	if (!prop) {
+		DRM_ERROR("cannot create dtrc_table_ofs property\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dcss_plane->dtrc_table_ofs_prop = prop;
+	drm_object_attach_property(&dcss_plane->base.base, prop, 0);
+
+	return dcss_plane;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-rdsrc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-rdsrc.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/seq_file.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_RDSRC_CTRL_STATUS			0x00
+#define   RDSRC_RD_ERR				BIT(31)
+#define   RDSRC_FRAME_COMP			BIT(30)
+#define   RDSRC_FIFO_SIZE_POS			16
+#define   RDSRC_FIFO_SIZE_MASK			GENMASK(22, 16)
+#define   RDSRC_RD_ERR_EN			BIT(15)
+#define   RDSRC_FRAME_COMP_EN			BIT(14)
+#define   RDSRC_P_SIZE_POS			7
+#define   RDSRC_P_SIZE_MASK			GENMASK(9, 7)
+#define   RDSRC_T_SIZE_POS			5
+#define   RDSRC_T_SIZE_MASK			GENMASK(6, 5)
+#define   RDSRC_BPP_POS				2
+#define   RDSRC_BPP_MASK			GENMASK(4, 2)
+#define   RDSRC_ENABLE				BIT(0)
+#define DCSS_RDSRC_BASE_ADDR			0x10
+#define DCSS_RDSRC_PITCH			0x14
+#define DCSS_RDSRC_WIDTH			0x18
+#define DCSS_RDSRC_HEIGHT			0x1C
+
+struct dcss_rdsrc {
+	struct device *dev;
+
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	struct dcss_ctxld *ctxld;
+	u32 ctx_id;
+
+	u32 buf_addr;
+
+	u32 ctrl_status;
+};
+
+static void dcss_rdsrc_write(struct dcss_rdsrc *rdsrc, u32 val, u32 ofs)
+{
+	dcss_ctxld_write(rdsrc->ctxld, rdsrc->ctx_id, val,
+			 rdsrc->base_ofs + ofs);
+}
+
+int dcss_rdsrc_init(struct dcss_dev *dcss, unsigned long rdsrc_base)
+{
+	struct dcss_rdsrc *rdsrc;
+
+	rdsrc = devm_kzalloc(dcss->dev, sizeof(*rdsrc), GFP_KERNEL);
+	if (!rdsrc)
+		return -ENOMEM;
+
+	rdsrc->base_reg = devm_ioremap(dcss->dev, rdsrc_base, SZ_4K);
+	if (!rdsrc->base_reg) {
+		dev_err(dcss->dev, "rdsrc: unable to remap base\n");
+		devm_kfree(dcss->dev, rdsrc);
+		return -ENOMEM;
+	}
+
+	dcss->rdsrc = rdsrc;
+
+	rdsrc->dev = dcss->dev;
+	rdsrc->base_ofs = rdsrc_base;
+	rdsrc->ctxld = dcss->ctxld;
+	rdsrc->ctx_id = CTX_SB_HP;
+
+	return 0;
+}
+
+void dcss_rdsrc_exit(struct dcss_rdsrc *rdsrc)
+{
+	devm_iounmap(rdsrc->dev, rdsrc->base_reg);
+	devm_kfree(rdsrc->dev, rdsrc);
+}
+
+void dcss_rdsrc_setup(struct dcss_rdsrc *rdsrc, u32 pix_format, u32 dst_xres,
+		      u32 dst_yres, u32 base_addr)
+{
+	u32 buf_size, pitch, bpp;
+
+	/* since the scaler output is YUV444, the RDSRC output has to match */
+	bpp = 4;
+
+	rdsrc->ctrl_status = FIFO_512 << RDSRC_FIFO_SIZE_POS;
+	rdsrc->ctrl_status |= PSIZE_256 << RDSRC_P_SIZE_POS;
+	rdsrc->ctrl_status |= TSIZE_256 << RDSRC_T_SIZE_POS;
+	rdsrc->ctrl_status |= BPP_32_10BIT_OUTPUT << RDSRC_BPP_POS;
+
+	buf_size = dst_xres * dst_yres * bpp;
+	pitch = dst_xres * bpp;
+
+	rdsrc->buf_addr = base_addr;
+
+	dcss_rdsrc_write(rdsrc, rdsrc->buf_addr, DCSS_RDSRC_BASE_ADDR);
+	dcss_rdsrc_write(rdsrc, pitch, DCSS_RDSRC_PITCH);
+	dcss_rdsrc_write(rdsrc, dst_xres, DCSS_RDSRC_WIDTH);
+	dcss_rdsrc_write(rdsrc, dst_yres, DCSS_RDSRC_HEIGHT);
+}
+
+void dcss_rdsrc_enable(struct dcss_rdsrc *rdsrc)
+{
+	dcss_rdsrc_write(rdsrc, rdsrc->ctrl_status, DCSS_RDSRC_CTRL_STATUS);
+}
+
+void dcss_rdsrc_disable(struct dcss_rdsrc *rdsrc)
+{
+	/* RDSRC is turned off by setting the width and height to 0 */
+	dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_WIDTH);
+	dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_HEIGHT);
+
+	dcss_rdsrc_write(rdsrc, rdsrc->ctrl_status, DCSS_RDSRC_CTRL_STATUS);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-scaler.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-scaler.c
@@ -0,0 +1,911 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ *
+ * Scaling algorithms were contributed by Dzung Hoang <dzung.hoang@nxp.com>
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_SCALER_CTRL			0x00
+#define   SCALER_EN				BIT(0)
+#define   REPEAT_EN				BIT(4)
+#define   SCALE2MEM_EN				BIT(8)
+#define   MEM2OFIFO_EN				BIT(12)
+#define DCSS_SCALER_OFIFO_CTRL			0x04
+#define   OFIFO_LOW_THRES_POS			0
+#define   OFIFO_LOW_THRES_MASK			GENMASK(9, 0)
+#define   OFIFO_HIGH_THRES_POS			16
+#define   OFIFO_HIGH_THRES_MASK			GENMASK(25, 16)
+#define   UNDERRUN_DETECT_CLR			BIT(26)
+#define   LOW_THRES_DETECT_CLR			BIT(27)
+#define   HIGH_THRES_DETECT_CLR			BIT(28)
+#define   UNDERRUN_DETECT_EN			BIT(29)
+#define   LOW_THRES_DETECT_EN			BIT(30)
+#define   HIGH_THRES_DETECT_EN			BIT(31)
+#define DCSS_SCALER_SDATA_CTRL			0x08
+#define   YUV_EN				BIT(0)
+#define   RTRAM_8LINES				BIT(1)
+#define   Y_UV_BYTE_SWAP			BIT(4)
+#define   A2R10G10B10_FORMAT_POS		8
+#define   A2R10G10B10_FORMAT_MASK		GENMASK(11, 8)
+#define DCSS_SCALER_BIT_DEPTH			0x0C
+#define   LUM_BIT_DEPTH_POS			0
+#define   LUM_BIT_DEPTH_MASK			GENMASK(1, 0)
+#define   CHR_BIT_DEPTH_POS			4
+#define   CHR_BIT_DEPTH_MASK			GENMASK(5, 4)
+#define DCSS_SCALER_SRC_FORMAT			0x10
+#define DCSS_SCALER_DST_FORMAT			0x14
+#define   FORMAT_MASK				GENMASK(1, 0)
+#define DCSS_SCALER_SRC_LUM_RES			0x18
+#define DCSS_SCALER_SRC_CHR_RES			0x1C
+#define DCSS_SCALER_DST_LUM_RES			0x20
+#define DCSS_SCALER_DST_CHR_RES			0x24
+#define   WIDTH_POS				0
+#define   WIDTH_MASK				GENMASK(11, 0)
+#define   HEIGHT_POS				16
+#define   HEIGHT_MASK				GENMASK(27, 16)
+#define DCSS_SCALER_V_LUM_START			0x48
+#define   V_START_MASK				GENMASK(15, 0)
+#define DCSS_SCALER_V_LUM_INC			0x4C
+#define   V_INC_MASK				GENMASK(15, 0)
+#define DCSS_SCALER_H_LUM_START			0x50
+#define   H_START_MASK				GENMASK(18, 0)
+#define DCSS_SCALER_H_LUM_INC			0x54
+#define   H_INC_MASK				GENMASK(15, 0)
+#define DCSS_SCALER_V_CHR_START			0x58
+#define DCSS_SCALER_V_CHR_INC			0x5C
+#define DCSS_SCALER_H_CHR_START			0x60
+#define DCSS_SCALER_H_CHR_INC			0x64
+#define DCSS_SCALER_COEF_VLUM			0x80
+#define DCSS_SCALER_COEF_HLUM			0x140
+#define DCSS_SCALER_COEF_VCHR			0x200
+#define DCSS_SCALER_COEF_HCHR			0x300
+
+struct dcss_scaler_ch {
+	void __iomem *base_reg;
+	u32 base_ofs;
+	struct dcss_scaler *scl;
+
+	u32 sdata_ctrl;
+	u32 scaler_ctrl;
+
+	bool scaler_ctrl_chgd;
+
+	u32 c_vstart;
+	u32 c_hstart;
+
+	int ch_num;
+};
+
+struct dcss_scaler {
+	struct device *dev;
+
+	struct dcss_ctxld *ctxld;
+	u32 ctx_id;
+
+	struct dcss_scaler_ch ch[3];
+
+	struct dcss_wrscl *wrscl;
+	struct dcss_rdsrc *rdsrc;
+	int ch_using_wrscl;
+};
+
+/* scaler coefficients generator */
+#define PSC_FRAC_BITS 30
+#define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
+#define PSC_BITS_FOR_PHASE 4
+#define PSC_NUM_PHASES 16
+#define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
+#define PSC_NUM_TAPS 7
+#define PSC_NUM_TAPS_RGBA 5
+#define PSC_COEFF_PRECISION 10
+#define PSC_PHASE_FRACTION_BITS 13
+#define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
+#define PSC_Q_FRACTION 19
+#define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
+
+/**
+ * mult_q() - Performs fixed-point multiplication.
+ * @A: multiplier
+ * @B: multiplicand
+ */
+static int mult_q(int A, int B)
+{
+	int result;
+	s64 temp;
+
+	temp = (int64_t)A * (int64_t)B;
+	temp += PSC_Q_ROUND_OFFSET;
+	result = (int)(temp >> PSC_Q_FRACTION);
+	return result;
+}
+
+/**
+ * div_q() - Performs fixed-point division.
+ * @A: dividend
+ * @B: divisor
+ */
+static int div_q(int A, int B)
+{
+	int result;
+	s64 temp;
+
+	temp = (int64_t)A << PSC_Q_FRACTION;
+	if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
+		temp += B / 2;
+	else
+		temp -= B / 2;
+
+	result = (int)(temp / B);
+	return result;
+}
+
+/**
+ * exp_approx_q() - Compute approximation to exp(x) function using Taylor
+ *		    series.
+ * @x: fixed-point argument of exp function
+ */
+static int exp_approx_q(int x)
+{
+	int sum = 1 << PSC_Q_FRACTION;
+	int term = 1 << PSC_Q_FRACTION;
+
+	term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
+	sum += term;
+	term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
+	sum += term;
+	term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
+	sum += term;
+	term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
+	sum += term;
+
+	return sum;
+}
+
+/**
+ * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
+ * @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
+ * @use_5_taps: indicates whether to use 5 taps or 7 taps
+ * @coef: output filter coefficients
+ */
+static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
+					bool phase0_identity,
+					int coef[][PSC_NUM_TAPS])
+{
+	int sigma_q, g0_q, g1_q, g2_q;
+	int tap_cnt1, tap_cnt2, tap_idx, phase_cnt;
+	int mid;
+	int phase;
+	int i;
+	int taps;
+
+	if (use_5_taps)
+		for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+			coef[phase][0] = 0;
+			coef[phase][PSC_NUM_TAPS - 1] = 0;
+		}
+
+	/* seed coefficient scanner */
+	taps = use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS;
+	mid = (PSC_NUM_PHASES * taps) / 2 - 1;
+	phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
+	tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+	tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+
+	/* seed gaussian filter generator */
+	sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
+	g0_q = 1 << PSC_Q_FRACTION;
+	g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET,
+				  mult_q(sigma_q, sigma_q)));
+	g2_q = mult_q(g1_q, g1_q);
+	coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
+
+	for (i = 0; i < mid; i++) {
+		phase_cnt++;
+		tap_cnt1--;
+		tap_cnt2++;
+
+		g0_q = mult_q(g0_q, g1_q);
+		g1_q = mult_q(g1_q, g2_q);
+
+		if ((phase_cnt & PSC_PHASE_MASK) <= 8) {
+			tap_idx = tap_cnt1 >> PSC_BITS_FOR_PHASE;
+			coef[phase_cnt & PSC_PHASE_MASK][tap_idx] = g0_q;
+		}
+		if (((-phase_cnt) & PSC_PHASE_MASK) <= 8) {
+			tap_idx = tap_cnt2 >> PSC_BITS_FOR_PHASE;
+			coef[(-phase_cnt) & PSC_PHASE_MASK][tap_idx] = g0_q;
+		}
+	}
+
+	phase_cnt++;
+	tap_cnt1--;
+	coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
+
+	/* override phase 0 with identity filter if specified */
+	if (phase0_identity)
+		for (i = 0; i < PSC_NUM_TAPS; i++)
+			coef[0][i] = i == (PSC_NUM_TAPS >> 1) ?
+						(1 << PSC_COEFF_PRECISION) : 0;
+
+	/* normalize coef */
+	for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+		int sum = 0;
+		s64 ll_temp;
+
+		for (i = 0; i < PSC_NUM_TAPS; i++)
+			sum += coef[phase][i];
+		for (i = 0; i < PSC_NUM_TAPS; i++) {
+			ll_temp = coef[phase][i];
+			ll_temp <<= PSC_COEFF_PRECISION;
+			ll_temp += sum >> 1;
+			ll_temp /= sum;
+			coef[phase][i] = (int)ll_temp;
+		}
+	}
+}
+
+/**
+ * dcss_scaler_filter_design() - Compute filter coefficients using
+ *				 Gaussian filter.
+ * @src_length: length of input
+ * @dst_length: length of output
+ * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
+ * @coef: output coefficients
+ */
+static void dcss_scaler_filter_design(int src_length, int dst_length,
+				      bool use_5_taps, bool phase0_identity,
+				      int coef[][PSC_NUM_TAPS])
+{
+	int fc_q;
+
+	/* compute cutoff frequency */
+	if (dst_length >= src_length)
+		fc_q = div_q(1, PSC_NUM_PHASES);
+	else
+		fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
+
+	/* compute gaussian filter coefficients */
+	dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
+}
+
+static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
+{
+	struct dcss_scaler *scl = ch->scl;
+
+	dcss_ctxld_write(scl->ctxld, scl->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_scaler_ch_init_all(struct dcss_scaler *scl,
+				   unsigned long scaler_base)
+{
+	struct dcss_scaler_ch *ch;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ch = &scl->ch[i];
+
+		ch->base_ofs = scaler_base + i * 0x400;
+
+		ch->base_reg = devm_ioremap(scl->dev, ch->base_ofs, SZ_4K);
+		if (!ch->base_reg) {
+			dev_err(scl->dev, "scaler: unable to remap ch base\n");
+			return -ENOMEM;
+		}
+
+		ch->scl = scl;
+		ch->ch_num = i;
+	}
+
+	return 0;
+}
+
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base)
+{
+	struct dcss_scaler *scaler;
+
+	scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
+	if (!scaler)
+		return -ENOMEM;
+
+	dcss->scaler = scaler;
+	scaler->dev = dcss->dev;
+	scaler->ctxld = dcss->ctxld;
+	scaler->ctx_id = CTX_SB_HP;
+	scaler->wrscl = dcss->wrscl;
+	scaler->rdsrc = dcss->rdsrc;
+	scaler->ch_using_wrscl = -1;
+
+	if (dcss_scaler_ch_init_all(scaler, scaler_base)) {
+		int i;
+
+		for (i = 0; i < 3; i++) {
+			if (scaler->ch[i].base_reg)
+				devm_iounmap(scaler->dev,
+					     scaler->ch[i].base_reg);
+		}
+
+		devm_kfree(scaler->dev, scaler);
+
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dcss_scaler_exit(struct dcss_scaler *scl)
+{
+	int ch_no;
+
+	for (ch_no = 0; ch_no < 3; ch_no++) {
+		struct dcss_scaler_ch *ch = &scl->ch[ch_no];
+
+		dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
+
+		if (ch->base_reg)
+			devm_iounmap(scl->dev, ch->base_reg);
+	}
+
+	devm_kfree(scl->dev, scl);
+}
+
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en)
+{
+	struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+	u32 scaler_ctrl;
+
+	if (scl->ch_using_wrscl == ch_num) {
+		if (en) {
+			scaler_ctrl = SCALE2MEM_EN | MEM2OFIFO_EN | REPEAT_EN;
+		} else {
+			dcss_wrscl_disable(scl->wrscl);
+			dcss_rdsrc_disable(scl->rdsrc);
+
+			scl->ch_using_wrscl = -1;
+			scaler_ctrl = 0;
+		}
+	} else {
+		scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
+	}
+
+	if (en)
+		dcss_scaler_write(ch, ch->sdata_ctrl, DCSS_SCALER_SDATA_CTRL);
+
+	if (ch->scaler_ctrl != scaler_ctrl)
+		ch->scaler_ctrl_chgd = true;
+
+	ch->scaler_ctrl = scaler_ctrl;
+}
+
+static void dcss_scaler_yuv_enable(struct dcss_scaler_ch *ch, bool en)
+{
+	ch->sdata_ctrl &= ~YUV_EN;
+	ch->sdata_ctrl |= en ? YUV_EN : 0;
+}
+
+static void dcss_scaler_rtr_8lines_enable(struct dcss_scaler_ch *ch, bool en)
+{
+	ch->sdata_ctrl &= ~RTRAM_8LINES;
+	ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
+}
+
+static void dcss_scaler_bit_depth_set(struct dcss_scaler_ch *ch, int depth)
+{
+	u32 val;
+
+	val = depth == 30 ? 2 : 0;
+
+	dcss_scaler_write(ch,
+			  ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
+			  ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
+			  DCSS_SCALER_BIT_DEPTH);
+}
+
+enum buffer_format {
+	BUF_FMT_YUV420,
+	BUF_FMT_YUV422,
+	BUF_FMT_ARGB8888_YUV444,
+};
+
+enum chroma_location {
+	PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
+	PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
+	PSC_LOC_HORZ_0_VERT_0 = 2,
+	PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
+	PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
+	PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
+};
+
+static void dcss_scaler_format_set(struct dcss_scaler_ch *ch,
+				   enum buffer_format src_fmt,
+				   enum buffer_format dst_fmt)
+{
+	dcss_scaler_write(ch, src_fmt, DCSS_SCALER_SRC_FORMAT);
+	dcss_scaler_write(ch, dst_fmt, DCSS_SCALER_DST_FORMAT);
+}
+
+static void dcss_scaler_res_set(struct dcss_scaler_ch *ch,
+				int src_xres, int src_yres,
+				int dst_xres, int dst_yres,
+				u32 pix_format, enum buffer_format dst_format)
+{
+	u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
+	u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
+	bool src_is_444 = true;
+
+	lsrc_xres = src_xres;
+	csrc_xres = src_xres;
+	lsrc_yres = src_yres;
+	csrc_yres = src_yres;
+	ldst_xres = dst_xres;
+	cdst_xres = dst_xres;
+	ldst_yres = dst_yres;
+	cdst_yres = dst_yres;
+
+	if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
+	    pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
+		csrc_xres >>= 1;
+		src_is_444 = false;
+	} else if (pix_format == DRM_FORMAT_NV12 ||
+		   pix_format == DRM_FORMAT_NV21 ||
+		   pix_format == DRM_FORMAT_NV12_10LE40) {
+		csrc_xres >>= 1;
+		csrc_yres >>= 1;
+		src_is_444 = false;
+	}
+
+	if (dst_format == BUF_FMT_YUV422)
+		cdst_xres >>= 1;
+
+	/* for 4:4:4 to 4:2:2 conversion, source height should be 1 less */
+	if (src_is_444 && dst_format == BUF_FMT_YUV422) {
+		lsrc_yres--;
+		csrc_yres--;
+	}
+
+	dcss_scaler_write(ch, (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+			       (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+			  DCSS_SCALER_SRC_LUM_RES);
+	dcss_scaler_write(ch, (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+			       (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+			  DCSS_SCALER_SRC_CHR_RES);
+	dcss_scaler_write(ch, (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+			       (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+			  DCSS_SCALER_DST_LUM_RES);
+	dcss_scaler_write(ch, (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+			       (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+			  DCSS_SCALER_DST_CHR_RES);
+}
+
+#define downscale_fp(factor, fp_pos)		((factor) << (fp_pos))
+#define upscale_fp(factor, fp_pos)		((1 << (fp_pos)) / (factor))
+
+struct dcss_scaler_factors {
+	int downscale;
+	int upscale;
+};
+
+static const struct dcss_scaler_factors dcss_scaler_factors[] = {
+	{3, 8}, {5, 8}, {5, 8},
+};
+
+static const struct dcss_scaler_factors dcss_scaler_wrscl_factors[] = {
+	{5, 8}, {7, 8}, {7, 8},
+};
+
+static bool dcss_scaler_fractions_set(struct dcss_scaler_ch *ch,
+				      int src_xres, int src_yres,
+				      int dst_xres, int dst_yres,
+				      u32 src_format, u32 dst_format,
+				      enum chroma_location src_chroma_loc)
+{
+	int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
+	u32 l_vinc, l_hinc, c_vinc, c_hinc;
+	u32 c_vstart, c_hstart;
+	u8 upscale_factor, downscale_factor;
+
+	src_c_xres = src_xres;
+	src_c_yres = src_yres;
+	dst_c_xres = dst_xres;
+	dst_c_yres = dst_yres;
+
+	c_vstart = 0;
+	c_hstart = 0;
+
+	/* adjustments for source chroma location */
+	if (src_format == BUF_FMT_YUV420) {
+		/* vertical input chroma position adjustment */
+		switch (src_chroma_loc) {
+		case PSC_LOC_HORZ_0_VERT_1_OVER_4:
+		case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+			/*
+			 * move chroma up to first luma line
+			 * (1/4 chroma input line spacing)
+			 */
+			c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+			break;
+		case PSC_LOC_HORZ_0_VERT_1_OVER_2:
+		case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+			/*
+			 * move chroma up to first luma line
+			 * (1/2 chroma input line spacing)
+			 */
+			c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
+			break;
+		default:
+			break;
+		}
+		/* horizontal input chroma position adjustment */
+		switch (src_chroma_loc) {
+		case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+		case PSC_LOC_HORZ_1_OVER_4_VERT_0:
+		case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+			/* move chroma left 1/4 chroma input sample spacing */
+			c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* adjustments to chroma resolution */
+	if (src_format == BUF_FMT_YUV420) {
+		src_c_xres >>= 1;
+		src_c_yres >>= 1;
+	} else if (src_format == BUF_FMT_YUV422) {
+		src_c_xres >>= 1;
+	}
+
+	if (dst_format == BUF_FMT_YUV422)
+		dst_c_xres >>= 1;
+
+	l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
+	c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
+	l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
+	c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
+
+	/* save chroma start phase */
+	ch->c_vstart = c_vstart;
+	ch->c_hstart = c_hstart;
+
+	dcss_scaler_write(ch, 0, DCSS_SCALER_V_LUM_START);
+	dcss_scaler_write(ch, l_vinc, DCSS_SCALER_V_LUM_INC);
+
+	dcss_scaler_write(ch, 0, DCSS_SCALER_H_LUM_START);
+	dcss_scaler_write(ch, l_hinc, DCSS_SCALER_H_LUM_INC);
+
+	dcss_scaler_write(ch, c_vstart, DCSS_SCALER_V_CHR_START);
+	dcss_scaler_write(ch, c_vinc, DCSS_SCALER_V_CHR_INC);
+
+	dcss_scaler_write(ch, c_hstart, DCSS_SCALER_H_CHR_START);
+	dcss_scaler_write(ch, c_hinc, DCSS_SCALER_H_CHR_INC);
+
+	downscale_factor = dcss_scaler_factors[ch->ch_num].downscale;
+	upscale_factor = dcss_scaler_factors[ch->ch_num].upscale;
+
+	/* return if WR_SCL/RD_SRC is needed to scale */
+	return l_vinc > downscale_fp(downscale_factor, 13)  ||
+	       l_vinc < upscale_fp(upscale_factor, 13)	    ||
+	       l_hinc > downscale_fp(downscale_factor, 13)  ||
+	       l_hinc < upscale_fp(upscale_factor, 13);
+}
+
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+				   int *min, int *max)
+{
+	const struct dcss_scaler_factors *factors_map = dcss_scaler_factors;
+
+	if (scl->ch_using_wrscl == -1 || scl->ch_using_wrscl == ch_num)
+		factors_map = dcss_scaler_wrscl_factors;
+
+	*min = upscale_fp(factors_map[ch_num].upscale, 16);
+	*max = downscale_fp(factors_map[ch_num].downscale, 16);
+
+	return 0;
+}
+
+static void dcss_scaler_program_5_coef_set(struct dcss_scaler_ch *ch,
+					   int base_addr,
+					   int coef[][PSC_NUM_TAPS])
+{
+	int i, phase;
+
+	for (i = 0; i < PSC_STORED_PHASES; i++) {
+		dcss_scaler_write(ch, ((coef[i][1] & 0xfff) << 16 |
+				       (coef[i][2] & 0xfff) << 4  |
+				       (coef[i][3] & 0xf00) >> 8),
+				  base_addr + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[i][3] & 0x0ff) << 20 |
+				       (coef[i][4] & 0xfff) << 8  |
+				       (coef[i][5] & 0xff0) >> 4),
+				  base_addr + 0x40 + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[i][5] & 0x00f) << 24),
+				  base_addr + 0x80 + i * sizeof(u32));
+	}
+
+	/* reverse both phase and tap orderings */
+	for (phase = (PSC_NUM_PHASES >> 1) - 1;
+			i < PSC_NUM_PHASES; i++, phase--) {
+		dcss_scaler_write(ch, ((coef[phase][5] & 0xfff) << 16 |
+				       (coef[phase][4] & 0xfff) << 4  |
+				       (coef[phase][3] & 0xf00) >> 8),
+				  base_addr + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[phase][3] & 0x0ff) << 20 |
+				       (coef[phase][2] & 0xfff) << 8  |
+				       (coef[phase][1] & 0xff0) >> 4),
+				  base_addr + 0x40 + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[phase][1] & 0x00f) << 24),
+				  base_addr + 0x80 + i * sizeof(u32));
+	}
+}
+
+static void dcss_scaler_program_7_coef_set(struct dcss_scaler_ch *ch,
+					   int base_addr,
+					   int coef[][PSC_NUM_TAPS])
+{
+	int i, phase;
+
+	for (i = 0; i < PSC_STORED_PHASES; i++) {
+		dcss_scaler_write(ch, ((coef[i][0] & 0xfff) << 16 |
+				       (coef[i][1] & 0xfff) << 4  |
+				       (coef[i][2] & 0xf00) >> 8),
+				  base_addr + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[i][2] & 0x0ff) << 20 |
+				       (coef[i][3] & 0xfff) << 8  |
+				       (coef[i][4] & 0xff0) >> 4),
+				  base_addr + 0x40 + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[i][4] & 0x00f) << 24 |
+				       (coef[i][5] & 0xfff) << 12 |
+				       (coef[i][6] & 0xfff)),
+				  base_addr + 0x80 + i * sizeof(u32));
+	}
+
+	/* reverse both phase and tap orderings */
+	for (phase = (PSC_NUM_PHASES >> 1) - 1;
+			i < PSC_NUM_PHASES; i++, phase--) {
+		dcss_scaler_write(ch, ((coef[phase][6] & 0xfff) << 16 |
+				       (coef[phase][5] & 0xfff) << 4  |
+				       (coef[phase][4] & 0xf00) >> 8),
+				  base_addr + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[phase][4] & 0x0ff) << 20 |
+				       (coef[phase][3] & 0xfff) << 8  |
+				       (coef[phase][2] & 0xff0) >> 4),
+				  base_addr + 0x40 + i * sizeof(u32));
+		dcss_scaler_write(ch, ((coef[phase][2] & 0x00f) << 24 |
+				       (coef[phase][1] & 0xfff) << 12 |
+				       (coef[phase][0] & 0xfff)),
+				  base_addr + 0x80 + i * sizeof(u32));
+	}
+}
+
+static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
+				     enum buffer_format src_format,
+				     enum buffer_format dst_format,
+				     bool use_5_taps,
+				     int src_xres, int src_yres, int dst_xres,
+				     int dst_yres)
+{
+	int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+	bool program_5_taps = use_5_taps ||
+			      (dst_format == BUF_FMT_YUV422 &&
+			       src_format == BUF_FMT_ARGB8888_YUV444);
+
+	/* horizontal luma */
+	dcss_scaler_filter_design(src_xres, dst_xres, false,
+				  src_xres == dst_xres, coef);
+	dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+	/* vertical luma */
+	dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+				  src_yres == dst_yres, coef);
+
+	if (program_5_taps)
+		dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+	else
+		dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+
+	/* adjust chroma resolution */
+	if (src_format != BUF_FMT_ARGB8888_YUV444)
+		src_xres >>= 1;
+	if (src_format == BUF_FMT_YUV420)
+		src_yres >>= 1;
+	if (dst_format != BUF_FMT_ARGB8888_YUV444)
+		dst_xres >>= 1;
+	if (dst_format == BUF_FMT_YUV420) /* should not happen */
+		dst_yres >>= 1;
+
+	/* horizontal chroma */
+	dcss_scaler_filter_design(src_xres, dst_xres, false,
+				  (src_xres == dst_xres) && (ch->c_hstart == 0),
+				  coef);
+
+	dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
+
+	/* vertical chroma */
+	dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+				  (src_yres == dst_yres) && (ch->c_vstart == 0),
+				  coef);
+	if (program_5_taps)
+		dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+	else
+		dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+}
+
+static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
+				     int src_xres, int src_yres, int dst_xres,
+				     int dst_yres)
+{
+	int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+
+	/* horizontal RGB */
+	dcss_scaler_filter_design(src_xres, dst_xres, false,
+				  src_xres == dst_xres, coef);
+	dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+	/* vertical RGB */
+	dcss_scaler_filter_design(src_yres, dst_yres, false,
+				  src_yres == dst_yres, coef);
+	dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+}
+
+static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
+					const struct drm_format_info *format)
+{
+	u32 a2r10g10b10_format;
+
+	if (format->is_yuv)
+		return;
+
+	ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
+
+	if (format->depth != 30)
+		return;
+
+	switch (format->format) {
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_XRGB2101010:
+		a2r10g10b10_format = 0;
+		break;
+
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_XBGR2101010:
+		a2r10g10b10_format = 5;
+		break;
+
+	case DRM_FORMAT_RGBA1010102:
+	case DRM_FORMAT_RGBX1010102:
+		a2r10g10b10_format = 6;
+		break;
+
+	case DRM_FORMAT_BGRA1010102:
+	case DRM_FORMAT_BGRX1010102:
+		a2r10g10b10_format = 11;
+		break;
+
+	default:
+		a2r10g10b10_format = 0;
+		break;
+	}
+
+	ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
+}
+
+static void dcss_scaler_setup_path(struct dcss_scaler_ch *ch,
+				   u32 pix_format, int dst_xres,
+				   int dst_yres, u32 vrefresh_hz,
+				   bool wrscl_needed)
+{
+	struct dcss_scaler *scl = ch->scl;
+	u32 base_addr;
+
+	/* nothing to do if WRSCL path is needed but it's already used */
+	if (wrscl_needed && scl->ch_using_wrscl != -1 &&
+	    scl->ch_using_wrscl != ch->ch_num)
+		return;
+
+	if (!wrscl_needed) {
+		/* Channel has finished using WRSCL. Release WRSCL/RDSRC. */
+		if (scl->ch_using_wrscl == ch->ch_num) {
+			dcss_wrscl_disable(scl->wrscl);
+			dcss_rdsrc_disable(scl->rdsrc);
+
+			scl->ch_using_wrscl = -1;
+		}
+
+		return;
+	}
+
+	base_addr = dcss_wrscl_setup(scl->wrscl, pix_format, vrefresh_hz,
+				     dst_xres, dst_yres);
+
+	dcss_rdsrc_setup(scl->rdsrc, pix_format, dst_xres, dst_yres,
+			 base_addr);
+
+	dcss_wrscl_enable(scl->wrscl);
+	dcss_rdsrc_enable(scl->rdsrc);
+
+	scl->ch_using_wrscl = ch->ch_num;
+}
+
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+		       const struct drm_format_info *format,
+		       int src_xres, int src_yres, int dst_xres, int dst_yres,
+		       u32 vrefresh_hz)
+{
+	struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+	unsigned int pixel_depth = 0;
+	bool rtr_8line_en = false;
+	bool use_5_taps = false;
+	enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
+	enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
+	u32 pix_format = format->format;
+	bool use_wrscl;
+
+	if (format->is_yuv) {
+		dcss_scaler_yuv_enable(ch, true);
+
+		if (pix_format == DRM_FORMAT_NV12 ||
+		    pix_format == DRM_FORMAT_NV21 ||
+		    pix_format == DRM_FORMAT_NV12_10LE40) {
+			rtr_8line_en = true;
+			src_format = BUF_FMT_YUV420;
+		} else if (pix_format == DRM_FORMAT_UYVY ||
+			   pix_format == DRM_FORMAT_VYUY ||
+			   pix_format == DRM_FORMAT_YUYV ||
+			   pix_format == DRM_FORMAT_YVYU) {
+			src_format = BUF_FMT_YUV422;
+		}
+
+		use_5_taps = !rtr_8line_en;
+
+		if (pix_format == DRM_FORMAT_NV12_10LE40)
+			pixel_depth = 30;
+	} else {
+		dcss_scaler_yuv_enable(ch, false);
+
+		pixel_depth = format->depth;
+	}
+
+	use_wrscl = dcss_scaler_fractions_set(ch, src_xres, src_yres, dst_xres,
+					      dst_yres, src_format, dst_format,
+					      PSC_LOC_HORZ_0_VERT_1_OVER_4);
+
+	if (format->is_yuv)
+		dcss_scaler_yuv_coef_set(ch, src_format, dst_format,
+					 use_5_taps, src_xres, src_yres,
+					 dst_xres, dst_yres);
+	else
+		dcss_scaler_rgb_coef_set(ch, src_xres, src_yres,
+					 dst_xres, dst_yres);
+
+	dcss_scaler_rtr_8lines_enable(ch, rtr_8line_en);
+	dcss_scaler_bit_depth_set(ch, pixel_depth);
+	dcss_scaler_set_rgb10_order(ch, format);
+	dcss_scaler_format_set(ch, src_format, dst_format);
+	dcss_scaler_res_set(ch, src_xres, src_yres, dst_xres, dst_yres,
+			    pix_format, dst_format);
+
+	dcss_scaler_setup_path(ch, pix_format, dst_xres,
+			       dst_yres, vrefresh_hz, use_wrscl);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl)
+{
+	int chnum;
+
+	for (chnum = 0; chnum < 3; chnum++) {
+		struct dcss_scaler_ch *ch = &scl->ch[chnum];
+
+		if (ch->scaler_ctrl_chgd) {
+			dcss_ctxld_write_irqsafe(scl->ctxld, scl->ctx_id,
+						 ch->scaler_ctrl,
+						 ch->base_ofs +
+						 DCSS_SCALER_CTRL);
+			ch->scaler_ctrl_chgd = false;
+		}
+	}
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-ss.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-ss.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_SS_SYS_CTRL			0x00
+#define   RUN_EN				BIT(0)
+#define DCSS_SS_DISPLAY				0x10
+#define   LRC_X_POS				0
+#define   LRC_X_MASK				GENMASK(12, 0)
+#define   LRC_Y_POS				16
+#define   LRC_Y_MASK				GENMASK(28, 16)
+#define DCSS_SS_HSYNC				0x20
+#define DCSS_SS_VSYNC				0x30
+#define   SYNC_START_POS			0
+#define   SYNC_START_MASK			GENMASK(12, 0)
+#define   SYNC_END_POS				16
+#define   SYNC_END_MASK				GENMASK(28, 16)
+#define   SYNC_POL				BIT(31)
+#define DCSS_SS_DE_ULC				0x40
+#define   ULC_X_POS				0
+#define   ULC_X_MASK				GENMASK(12, 0)
+#define   ULC_Y_POS				16
+#define   ULC_Y_MASK				GENMASK(28, 16)
+#define   ULC_POL				BIT(31)
+#define DCSS_SS_DE_LRC				0x50
+#define DCSS_SS_MODE				0x60
+#define   PIPE_MODE_POS				0
+#define   PIPE_MODE_MASK			GENMASK(1, 0)
+#define DCSS_SS_COEFF				0x70
+#define   HORIZ_A_POS				0
+#define   HORIZ_A_MASK				GENMASK(3, 0)
+#define   HORIZ_B_POS				4
+#define   HORIZ_B_MASK				GENMASK(7, 4)
+#define   HORIZ_C_POS				8
+#define   HORIZ_C_MASK				GENMASK(11, 8)
+#define   HORIZ_H_NORM_POS			12
+#define   HORIZ_H_NORM_MASK			GENMASK(14, 12)
+#define   VERT_A_POS				16
+#define   VERT_A_MASK				GENMASK(19, 16)
+#define   VERT_B_POS				20
+#define   VERT_B_MASK				GENMASK(23, 20)
+#define   VERT_C_POS				24
+#define   VERT_C_MASK				GENMASK(27, 24)
+#define   VERT_H_NORM_POS			28
+#define   VERT_H_NORM_MASK			GENMASK(30, 28)
+#define DCSS_SS_CLIP_CB				0x80
+#define DCSS_SS_CLIP_CR				0x90
+#define   CLIP_MIN_POS				0
+#define   CLIP_MIN_MASK				GENMASK(9, 0)
+#define   CLIP_MAX_POS				0
+#define   CLIP_MAX_MASK				GENMASK(23, 16)
+#define DCSS_SS_INTER_MODE			0xA0
+#define   INT_EN				BIT(0)
+#define   VSYNC_SHIFT				BIT(1)
+
+struct dcss_ss {
+	struct device *dev;
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	struct dcss_ctxld *ctxld;
+	u32 ctx_id;
+
+	bool in_use;
+};
+
+static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
+{
+	if (!ss->in_use)
+		dcss_writel(val, ss->base_reg + ofs);
+
+	dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
+			 ss->base_ofs + ofs);
+}
+
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
+{
+	struct dcss_ss *ss;
+
+	ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
+	if (!ss)
+		return -ENOMEM;
+
+	dcss->ss = ss;
+	ss->dev = dcss->dev;
+	ss->ctxld = dcss->ctxld;
+
+	ss->base_reg = devm_ioremap(dcss->dev, ss_base, SZ_4K);
+	if (!ss->base_reg) {
+		dev_err(dcss->dev, "ss: unable to remap ss base\n");
+		devm_kfree(ss->dev, ss);
+		return -ENOMEM;
+	}
+
+	ss->base_ofs = ss_base;
+	ss->ctx_id = CTX_SB_HP;
+
+	return 0;
+}
+
+void dcss_ss_exit(struct dcss_ss *ss)
+{
+	/* stop SS */
+	dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
+
+	if (ss->base_reg)
+		devm_iounmap(ss->dev, ss->base_reg);
+
+	devm_kfree(ss->dev, ss);
+}
+
+void dcss_ss_subsam_set(struct dcss_ss *ss, bool out_is_yuv)
+{
+	dcss_ss_write(ss, out_is_yuv ? 0x21612161 : 0x41614161, DCSS_SS_COEFF);
+	dcss_ss_write(ss, out_is_yuv ? 2 : 0, DCSS_SS_MODE);
+	dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
+	dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
+}
+
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+		      bool phsync, bool pvsync)
+{
+	u16 lrc_x, lrc_y;
+	u16 hsync_start, hsync_end;
+	u16 vsync_start, vsync_end;
+	u16 de_ulc_x, de_ulc_y;
+	u16 de_lrc_x, de_lrc_y;
+
+	lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+		vm->hactive - 1;
+	lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+		vm->vactive - 1;
+
+	dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
+
+	hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+		      vm->hactive - 1;
+	hsync_end = vm->hsync_len - 1;
+
+	dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
+		      ((u32)hsync_end << SYNC_END_POS) | hsync_start,
+		      DCSS_SS_HSYNC);
+
+	vsync_start = vm->vfront_porch - 1;
+	vsync_end = vm->vfront_porch + vm->vsync_len - 1;
+
+	dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
+		      ((u32)vsync_end << SYNC_END_POS) | vsync_start,
+		      DCSS_SS_VSYNC);
+
+	de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+	de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
+
+	dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
+		      DCSS_SS_DE_ULC);
+
+	de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+	de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+		   vm->vactive - 1;
+
+	dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
+}
+
+void dcss_ss_enable(struct dcss_ss *ss)
+{
+	dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
+	ss->in_use = true;
+}
+
+void dcss_ss_disable(struct dcss_ss *ss)
+{
+	dcss_ss_write(ss, 0, DCSS_SS_SYS_CTRL);
+	ss->in_use = false;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dcss/dcss-wrscl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dcss/dcss-wrscl.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/seq_file.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_WRSCL_CTRL_STATUS			0x00
+#define   WRSCL_ERR				BIT(31)
+#define   WRSCL_ERR_EN				BIT(30)
+#define   WRSCL_FRAME_COMP			BIT(29)
+#define   WRSCL_FRAME_COMP_EN			BIT(28)
+#define   WRSCL_FIFO_SIZE_POS			18
+#define   WRSCL_FIFO_SIZE_MASK			GENMAK(24, 18)
+#define   WRSCL_P_FREQ_POS			10
+#define   WRSCL_P_FREQ_MASK			GENMASK(17, 10)
+#define   WRSCL_P_SIZE_POS			7
+#define   WRSCL_P_SIZE_MASK			GENMASK(9, 7)
+#define   WRSCL_T_SIZE_POS			5
+#define   WRSCL_T_SIZE_MASK			GENMASK(6, 5)
+#define   WRSCL_BPP_POS				2
+#define   WRSCL_BPP_MASK			GENMASK(4, 2)
+#define   WRSCL_REPEAT				BIT(1)
+#define   WRSCL_ENABLE				BIT(0)
+#define DCSS_WRSCL_BASE_ADDR			0x10
+#define DCSS_WRSCL_PITCH			0x14
+
+struct dcss_wrscl {
+	struct device *dev;
+
+	void __iomem *base_reg;
+	u32 base_ofs;
+
+	struct dcss_ctxld *ctxld;
+	u32 ctx_id;
+
+	u32 buf_size;
+	u32 buf_addr;
+	void *buf_vaddr;
+
+	struct clk *bclk;
+
+	u32 ctrl_status;
+};
+
+static void dcss_wrscl_write(struct dcss_wrscl *wrscl, u32 val, u32 ofs)
+{
+	dcss_ctxld_write(wrscl->ctxld, wrscl->ctx_id,
+			 val, wrscl->base_ofs + ofs);
+}
+
+int dcss_wrscl_init(struct dcss_dev *dcss, unsigned long wrscl_base)
+{
+	struct dcss_wrscl *wrscl;
+
+	wrscl = devm_kzalloc(dcss->dev, sizeof(*wrscl), GFP_KERNEL);
+	if (!wrscl)
+		return -ENOMEM;
+
+	wrscl->base_reg = devm_ioremap(dcss->dev, wrscl_base, SZ_4K);
+	if (!wrscl->base_reg) {
+		dev_err(dcss->dev, "wrscl: unable to remap base\n");
+		devm_kfree(dcss->dev, wrscl);
+		return -ENOMEM;
+	}
+
+	dcss->wrscl = wrscl;
+
+	wrscl->dev = dcss->dev;
+	wrscl->base_ofs = wrscl_base;
+	wrscl->ctxld = dcss->ctxld;
+	wrscl->ctx_id = CTX_SB_HP;
+	wrscl->bclk = dcss->axi_clk;
+
+	return 0;
+}
+
+void dcss_wrscl_exit(struct dcss_wrscl *wrscl)
+{
+	devm_iounmap(wrscl->dev, wrscl->base_reg);
+	devm_kfree(wrscl->dev, wrscl);
+}
+
+static const u16 dcss_wrscl_psize_map[] = {64, 128, 256, 512, 1024, 2048, 4096};
+
+u32 dcss_wrscl_setup(struct dcss_wrscl *wrscl, u32 pix_format, u32 vrefresh_hz,
+		     u32 dst_xres, u32 dst_yres)
+{
+	u32 pitch, p_size, p_freq, bpp;
+	dma_addr_t dma_handle;
+	u32 bclk_rate = clk_get_rate(wrscl->bclk);
+
+	/* we'd better release the old buffer */
+	if (wrscl->buf_addr)
+		dmam_free_coherent(wrscl->dev, wrscl->buf_size,
+				   wrscl->buf_vaddr, wrscl->buf_addr);
+
+	p_size = PSIZE_256;
+
+	/* scaler output is YUV444 */
+	bpp = 4;
+
+	/* spread the load over the entire frame */
+	p_freq = ((u64)bclk_rate * dcss_wrscl_psize_map[p_size]) /
+		 ((u64)dst_xres * dst_yres * vrefresh_hz * bpp * 8);
+
+	/* choose a slightly smaller p_freq */
+	p_freq = p_freq - 3 > 255 ? 255 : p_freq - 3;
+
+	wrscl->ctrl_status = FIFO_512 << WRSCL_FIFO_SIZE_POS;
+	wrscl->ctrl_status |= p_size << WRSCL_P_SIZE_POS;
+	wrscl->ctrl_status |= TSIZE_256 << WRSCL_T_SIZE_POS;
+	wrscl->ctrl_status |= BPP_32_10BIT_OUTPUT << WRSCL_BPP_POS;
+	wrscl->ctrl_status |= p_freq << WRSCL_P_FREQ_POS;
+
+	wrscl->buf_size = dst_xres * dst_yres * bpp;
+	pitch = dst_xres * bpp;
+
+	wrscl->buf_vaddr = dmam_alloc_coherent(wrscl->dev, wrscl->buf_size,
+					       &dma_handle, GFP_KERNEL);
+	if (!wrscl->buf_vaddr) {
+		dev_err(wrscl->dev, "wrscl: cannot alloc buf mem\n");
+		return 0;
+	}
+
+	wrscl->buf_addr = dma_handle;
+
+	dcss_wrscl_write(wrscl, wrscl->buf_addr, DCSS_WRSCL_BASE_ADDR);
+	dcss_wrscl_write(wrscl, pitch, DCSS_WRSCL_PITCH);
+
+	return wrscl->buf_addr;
+}
+
+void dcss_wrscl_enable(struct dcss_wrscl *wrscl)
+{
+	wrscl->ctrl_status |= WRSCL_ENABLE | WRSCL_REPEAT;
+
+	dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
+}
+
+void dcss_wrscl_disable(struct dcss_wrscl *wrscl)
+{
+	wrscl->ctrl_status &= ~(WRSCL_ENABLE | WRSCL_REPEAT);
+
+	dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
+
+	if (wrscl->buf_addr) {
+		dmam_free_coherent(wrscl->dev, wrscl->buf_size,
+				   wrscl->buf_vaddr, wrscl->buf_addr);
+		wrscl->buf_addr = 0;
+	}
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/Kconfig
@@ -0,0 +1,6 @@
+config DRM_IMX_DPU
+	tristate "Freescale i.MX DPU DRM support"
+	depends on DRM_IMX
+	depends on IMX_DPU_CORE
+	default y if DRM_IMX=y
+	default m if DRM_IMX=m
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -I $(srctree)/$(src)/../
+
+imx-dpu-crtc-objs := dpu-crtc.o dpu-kms.o dpu-plane.o
+imx-dpu-crtc-$(CONFIG_DEBUG_FS) := dpu-crc.o
+obj-$(CONFIG_DRM_IMX_DPU) += imx-dpu-crtc.o
+
+imx-dpu-render-objs := dpu-blit.o
+obj-$(CONFIG_DRM_IMX_DPU) += imx-dpu-render.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-blit.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-blit.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/imx_drm.h>
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <video/dpu.h>
+
+#include "imx-drm.h"
+
+struct imx_drm_dpu_bliteng {
+	struct dpu_bliteng *dpu_be;
+	struct list_head list;
+};
+
+static DEFINE_MUTEX(imx_drm_dpu_bliteng_lock);
+static LIST_HEAD(imx_drm_dpu_bliteng_list);
+
+static int imx_dpu_num;
+
+int dpu_be_get(struct dpu_bliteng *dpu_be);
+void dpu_be_put(struct dpu_bliteng *dpu_be);
+s32 dpu_bliteng_get_id(struct dpu_bliteng *dpu_be);
+void dpu_be_configure_prefetch(struct dpu_bliteng *dpu_be,
+                   u32 width, u32 height,
+                   u32 x_offset, u32 y_offset,
+                   u32 stride, u32 format, u64 modifier,
+                   u64 baddr, u64 uv_addr);
+u32 *dpu_bliteng_get_cmd_list(struct dpu_bliteng *dpu_be);
+void dpu_be_wait(struct dpu_bliteng *dpu_be);
+int dpu_bliteng_get_empty_instance(struct dpu_bliteng **dpu_be,
+    struct device *dev);
+void dpu_bliteng_set_id(struct dpu_bliteng *dpu_be, int id);
+void dpu_bliteng_set_dev(struct dpu_bliteng *dpu_be, struct device *dev);
+int dpu_bliteng_init(struct dpu_bliteng *dpu_bliteng);
+void dpu_bliteng_fini(struct dpu_bliteng *dpu_bliteng);
+int dpu_be_blit(struct dpu_bliteng *dpu_be,
+    u32 *cmdlist, u32 cmdnum);
+
+static struct imx_drm_dpu_bliteng *imx_drm_dpu_bliteng_find_by_id(s32 id)
+{
+	struct imx_drm_dpu_bliteng *bliteng;
+
+	mutex_lock(&imx_drm_dpu_bliteng_lock);
+
+	list_for_each_entry(bliteng, &imx_drm_dpu_bliteng_list, list) {
+		if (id == dpu_bliteng_get_id(bliteng->dpu_be)) {
+			mutex_unlock(&imx_drm_dpu_bliteng_lock);
+			return bliteng;
+		}
+	}
+
+	mutex_unlock(&imx_drm_dpu_bliteng_lock);
+
+	return NULL;
+}
+
+static int imx_drm_dpu_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
+					  struct drm_file *file)
+{
+	struct drm_imx_dpu_set_cmdlist *req;
+	struct imx_drm_dpu_bliteng *bliteng;
+	struct dpu_bliteng *dpu_be;
+	u32 cmd_nr, *cmd, *cmd_list;
+	void *user_data;
+	s32 id = 0;
+	struct drm_imx_dpu_frame_info frame_info;
+	int ret;
+
+	req = data;
+	user_data = (void *)(unsigned long)req->user_data;
+	if (copy_from_user(&id, (void __user *)user_data,
+		sizeof(id))) {
+		return -EFAULT;
+	}
+
+	if (id != 0 && id != 1)
+		return -EINVAL;
+
+	user_data += sizeof(id);
+	if (copy_from_user(&frame_info, (void __user *)user_data,
+		sizeof(frame_info))) {
+		return -EFAULT;
+	}
+
+	bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+	if (!bliteng) {
+		DRM_ERROR("Failed to get dpu_bliteng\n");
+		return -ENODEV;
+	}
+
+	dpu_be = bliteng->dpu_be;
+
+	ret = dpu_be_get(dpu_be);
+
+	cmd_nr = req->cmd_nr;
+	cmd = (u32 *)(unsigned long)req->cmd;
+	cmd_list = dpu_bliteng_get_cmd_list(dpu_be);
+
+	if (copy_from_user(cmd_list, (void __user *)cmd,
+			sizeof(*cmd) * cmd_nr)) {
+		ret = -EFAULT;
+		goto err;
+	}
+
+	dpu_be_configure_prefetch(dpu_be, frame_info.width, frame_info.height,
+				  frame_info.x_offset, frame_info.y_offset,
+				  frame_info.stride, frame_info.format,
+				  frame_info.modifier, frame_info.baddr,
+				  frame_info.uv_addr);
+
+	ret = dpu_be_blit(dpu_be, cmd_list, cmd_nr);
+
+err:
+	dpu_be_put(dpu_be);
+
+	return ret;
+}
+
+static int imx_drm_dpu_wait_ioctl(struct drm_device *drm_dev, void *data,
+				  struct drm_file *file)
+{
+	struct drm_imx_dpu_wait *wait;
+	struct imx_drm_dpu_bliteng *bliteng;
+	struct dpu_bliteng *dpu_be;
+	void *user_data;
+	s32 id = 0;
+	int ret;
+
+	wait = data;
+	user_data = (void *)(unsigned long)wait->user_data;
+	if (copy_from_user(&id, (void __user *)user_data,
+		sizeof(id))) {
+		return -EFAULT;
+	}
+
+	if (id != 0 && id != 1)
+		return -EINVAL;
+
+	bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+	if (!bliteng) {
+		DRM_ERROR("Failed to get dpu_bliteng\n");
+		return -ENODEV;
+	}
+
+	dpu_be = bliteng->dpu_be;
+
+	ret = dpu_be_get(dpu_be);
+
+	dpu_be_wait(dpu_be);
+
+	dpu_be_put(dpu_be);
+
+	return ret;
+}
+
+static int imx_drm_dpu_get_param_ioctl(struct drm_device *drm_dev, void *data,
+				       struct drm_file *file)
+{
+	enum drm_imx_dpu_param *param = data;
+	int ret;
+
+	switch (*param) {
+	case (DRM_IMX_MAX_DPUS):
+		ret = imx_dpu_num;
+		break;
+	default:
+		ret = -EINVAL;
+		DRM_ERROR("Unknown param![%d]\n", *param);
+		break;
+	}
+
+	return ret;
+}
+
+static struct drm_ioctl_desc imx_drm_dpu_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(IMX_DPU_SET_CMDLIST, imx_drm_dpu_set_cmdlist_ioctl,
+			DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(IMX_DPU_WAIT, imx_drm_dpu_wait_ioctl,
+			DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(IMX_DPU_GET_PARAM, imx_drm_dpu_get_param_ioctl,
+			DRM_RENDER_ALLOW),
+};
+
+static int dpu_bliteng_bind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct drm_device *drm = (struct drm_device *)data;
+	struct imx_drm_dpu_bliteng *bliteng;
+	struct dpu_bliteng *dpu_bliteng = NULL;
+	int ret;
+
+	bliteng = devm_kzalloc(dev, sizeof(*bliteng), GFP_KERNEL);
+	if (!bliteng)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&bliteng->list);
+
+	ret = dpu_bliteng_get_empty_instance(&dpu_bliteng, dev);
+	if (ret)
+		return ret;
+
+	dpu_bliteng_set_id(dpu_bliteng, imx_dpu_num);
+	dpu_bliteng_set_dev(dpu_bliteng, dev);
+
+	ret = dpu_bliteng_init(dpu_bliteng);
+	if (ret)
+		return ret;
+
+	mutex_lock(&imx_drm_dpu_bliteng_lock);
+	bliteng->dpu_be = dpu_bliteng;
+	list_add_tail(&bliteng->list, &imx_drm_dpu_bliteng_list);
+	mutex_unlock(&imx_drm_dpu_bliteng_lock);
+
+	dev_set_drvdata(dev, dpu_bliteng);
+
+	imx_dpu_num++;
+
+	if (drm->driver->num_ioctls == 0) {
+		drm->driver->ioctls = imx_drm_dpu_ioctls;
+		drm->driver->num_ioctls = ARRAY_SIZE(imx_drm_dpu_ioctls);
+	}
+
+	return 0;
+}
+
+static void dpu_bliteng_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	struct drm_device *drm = (struct drm_device *)data;
+	struct imx_drm_dpu_bliteng *bliteng;
+	struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+	s32 id = dpu_bliteng_get_id(dpu_bliteng);
+
+	bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+	list_del(&bliteng->list);
+
+	dpu_bliteng_fini(dpu_bliteng);
+	dev_set_drvdata(dev, NULL);
+
+	imx_dpu_num--;
+
+	if (drm->driver->num_ioctls != 0) {
+		drm->driver->ioctls = NULL;
+		drm->driver->num_ioctls = 0;
+	}
+}
+
+static const struct component_ops dpu_bliteng_ops = {
+	.bind = dpu_bliteng_bind,
+	.unbind = dpu_bliteng_unbind,
+};
+
+static int dpu_bliteng_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	if (!dev->platform_data)
+		return -EINVAL;
+
+	return component_add(dev, &dpu_bliteng_ops);
+}
+
+static int dpu_bliteng_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dpu_bliteng_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dpu_bliteng_suspend(struct device *dev)
+{
+	struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+	int ret;
+
+	if (dpu_bliteng == NULL)
+		return 0;
+
+	ret = dpu_be_get(dpu_bliteng);
+
+	dpu_be_wait(dpu_bliteng);
+
+	dpu_be_put(dpu_bliteng);
+
+	dpu_bliteng_fini(dpu_bliteng);
+
+	return 0;
+}
+
+static int dpu_bliteng_resume(struct device *dev)
+{
+	struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+
+	if (dpu_bliteng != NULL)
+		dpu_bliteng_init(dpu_bliteng);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dpu_bliteng_pm_ops,
+			 dpu_bliteng_suspend, dpu_bliteng_resume);
+
+struct platform_driver dpu_bliteng_driver = {
+	.driver = {
+		.name = "imx-drm-dpu-bliteng",
+		.pm = &dpu_bliteng_pm_ops,
+	},
+	.probe = dpu_bliteng_probe,
+	.remove = dpu_bliteng_remove,
+};
+
+module_platform_driver(dpu_bliteng_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DRM DPU BLITENG");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-crc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-crc.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2019,2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_plane.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-crc.h"
+#include "dpu-crtc.h"
+
+static inline void get_left(struct drm_rect *r, struct drm_display_mode *m)
+{
+	r->x1 = 0;
+	r->y1 = 0;
+	r->x2 = m->hdisplay >> 1;
+	r->y2 = m->vdisplay;
+}
+
+static inline void get_right(struct drm_rect *r, struct drm_display_mode *m)
+{
+	r->x1 = m->hdisplay >> 1;
+	r->y1 = 0;
+	r->x2 = m->hdisplay;
+	r->y2 = m->vdisplay;
+}
+
+static void
+dpu_enable_signature_roi(struct dpu_signature *sig, struct drm_rect *roi)
+{
+	signature_continuous_mode(sig, true);
+	signature_win(sig, 0, roi->x1, roi->y1, roi->x2, roi->y2);
+	signature_eval_win(sig, 0, true);
+	signature_shdldreq(sig, 0x1);
+}
+
+static void dpu_disable_signature(struct dpu_signature *sig)
+{
+	signature_continuous_mode(sig, false);
+	signature_wait_for_idle(sig);
+	signature_eval_win(sig, 0, false);
+}
+
+/*
+ * Supported modes and source names:
+ * 1) auto mode:
+ *    "auto" should be selected as the source name.
+ *    The evaluation window is the same to the display region as
+ *    indicated by drm_crtc_state->adjusted_mode.
+ *
+ * 2) region of interest(ROI) mode:
+ *    "roi:x1,y1,x2,y2" should be selected as the source name.
+ *    The region of interest is defined by the inclusive upper left
+ *    position at (x1, y1) and the exclusive lower right position
+ *    at (x2, y2), see struct drm_rect for the same idea.
+ *    The evaluation window is the region of interest.
+ */
+static int
+dpu_crc_parse_source(const char *source_name, enum dpu_crc_source *s,
+		     struct drm_rect *roi)
+{
+	static const char roi_prefix[] = "roi:";
+
+	if (!source_name) {
+		*s = DPU_CRC_SRC_NONE;
+	} else if (!strcmp(source_name, "auto")) {
+		*s = DPU_CRC_SRC_FRAMEGEN;
+	} else if (strstarts(source_name, roi_prefix)) {
+		char *options, *opt;
+		int len = strlen(roi_prefix);
+		int params[4];
+		int i = 0, ret;
+
+		options = kstrdup(source_name + len, GFP_KERNEL);
+
+		while ((opt = strsep(&options, ",")) != NULL) {
+			if (i > 4)
+				return -EINVAL;
+
+			ret = kstrtouint(opt, 10, &params[i]);
+			if (ret < 0)
+				return ret;
+
+			if (params[i] < 0)
+				return -EINVAL;
+
+			i++;
+		}
+
+		if (i != 4)
+			return -EINVAL;
+
+		roi->x1 = params[0];
+		roi->y1 = params[1];
+		roi->x2 = params[2];
+		roi->y2 = params[3];
+
+		if (!drm_rect_visible(roi))
+			return -EINVAL;
+
+		*s = DPU_CRC_SRC_FRAMEGEN_ROI;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
+			       size_t *values_cnt)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct imx_crtc_state *imx_crtc_state;
+	struct dpu_crtc_state *dcstate;
+	struct drm_rect roi;
+	enum dpu_crc_source source;
+	int ret;
+
+	if (dpu_crc_parse_source(source_name, &source, &roi) < 0) {
+		dev_dbg(dpu_crtc->dev, "unknown source %s\n", source_name);
+		return -EINVAL;
+	}
+
+	ret = drm_modeset_lock_single_interruptible(&crtc->mutex);
+	if (ret)
+		return ret;
+
+	imx_crtc_state = to_imx_crtc_state(crtc->state);
+	dcstate = to_dpu_crtc_state(imx_crtc_state);
+	*values_cnt = dcstate->use_pc ? 6 : 3;
+
+	drm_modeset_unlock(&crtc->mutex);
+
+	return ret;
+}
+
+int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_state *state;
+	struct drm_rect roi = {0, 0, 0, 0};
+	enum dpu_crc_source source;
+	int ret;
+
+	if (dpu_crc_parse_source(source_name, &source, &roi) < 0) {
+		dev_dbg(dpu_crtc->dev, "unknown source %s\n", source_name);
+		return -EINVAL;
+	}
+
+	/* Perform an atomic commit to set the CRC source. */
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	state->acquire_ctx = &ctx;
+
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (!IS_ERR(crtc_state)) {
+		struct imx_crtc_state *imx_crtc_state;
+		struct dpu_crtc_state *dcstate;
+
+		imx_crtc_state = to_imx_crtc_state(crtc_state);
+		dcstate = to_dpu_crtc_state(imx_crtc_state);
+
+		if ((dcstate->use_pc && crtc->crc.values_cnt != 6) ||
+		    (!dcstate->use_pc && crtc->crc.values_cnt != 3)) {
+			ret = -EINVAL;
+			goto put;
+		}
+
+		dcstate->crc.source = source;
+		dpu_copy_roi(&roi, &dcstate->crc.roi);
+		dpu_crtc->use_dual_crc = dcstate->use_pc;
+
+		ret = drm_atomic_commit(state);
+	} else {
+		ret = PTR_ERR(crtc_state);
+	}
+
+	if (ret == -EDEADLK) {
+		drm_atomic_state_clear(state);
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+
+put:
+	drm_atomic_state_put(state);
+
+unlock:
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return ret;
+}
+
+irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+	struct dpu_signature *sig = dpu_crtc->sig;
+	struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+	bool dual_crc = dpu_crtc->use_dual_crc;
+	unsigned long ret;
+	uint32_t crcs[6] = {0, 0, 0, 0, 0, 0};
+
+	dev_dbg(dpu_crtc->dev, "CRC valid irq threaded handler\n");
+
+	signature_crc_value(sig, 0, &dpu_crtc->crc_red,
+				    &dpu_crtc->crc_green,
+				    &dpu_crtc->crc_blue);
+
+	if (dual_crc && dpu_crtc->stream_id == 1) {
+		complete(&aux_dpu_crtc->aux_crc_done);
+		return IRQ_HANDLED;
+	}
+
+	if (!dual_crc ||
+	    (dual_crc && dpu_crtc->dual_crc_flag != DPU_DUAL_CRC_FLAG_RIGHT)) {
+		crcs[2] = dpu_crtc->crc_red;
+		crcs[1] = dpu_crtc->crc_green;
+		crcs[0] = dpu_crtc->crc_blue;
+	}
+
+	if (dual_crc && dpu_crtc->stream_id == 0) {
+		ret = wait_for_completion_timeout(&dpu_crtc->aux_crc_done,
+						  HZ / 20);
+		if (ret == 0)
+			dev_warn(dpu_crtc->dev,
+				"wait for auxiliary CRC done timeout\n");
+
+		if (dpu_crtc->dual_crc_flag != DPU_DUAL_CRC_FLAG_LEFT) {
+			crcs[5] = aux_dpu_crtc->crc_red;
+			crcs[4] = aux_dpu_crtc->crc_green;
+			crcs[3] = aux_dpu_crtc->crc_blue;
+		}
+	}
+
+	drm_crtc_add_crc_entry(&dpu_crtc->base, false, 0, crcs);
+
+	return IRQ_HANDLED;
+}
+
+void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
+				enum dpu_crc_source source,
+				struct drm_rect *roi)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct completion *shdld_done;
+	struct drm_rect left, right;
+	struct drm_rect r, aux_r, clip;
+	bool dual_crc = dpu_crtc->use_dual_crc;
+	bool use_left, use_right;
+	int half_hdisplay;
+	unsigned long ret;
+
+	if (source == DPU_CRC_SRC_NONE)
+		return;
+
+	if (dual_crc != dcstate->use_pc)
+		return;
+
+	if (dpu_crtc->crc_is_enabled)
+		return;
+
+	if (dual_crc) {
+		half_hdisplay = mode->hdisplay >> 1;
+
+		get_left(&left, mode);
+		get_right(&right, mode);
+
+		dpu_copy_roi(&left, &clip);
+		if (drm_rect_intersect(&clip, roi)) {
+			dpu_copy_roi(&clip, &r);
+			use_left = true;
+		} else {
+			dpu_copy_roi(&left, &r);
+			use_left = false;
+		}
+
+		if (drm_rect_intersect(&right, roi)) {
+			right.x1 -= half_hdisplay;
+			right.x2 -= half_hdisplay;
+			dpu_copy_roi(&right, &aux_r);
+			use_right = true;
+		} else {
+			dpu_copy_roi(&left, &aux_r);
+			use_right = false;
+		}
+
+		if (use_left && !use_right) {
+			dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_LEFT;
+		} else if (!use_left && use_right) {
+			dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_RIGHT;
+		} else if (use_left && use_right) {
+			dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_DUAL;
+		} else {
+			dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_ERR_NONE;
+			dev_err(dpu_crtc->dev, "error flag for dual CRC\n");
+			return;
+		}
+	} else {
+		dpu_copy_roi(roi, &r);
+	}
+
+	enable_irq(dpu_crtc->crc_valid_irq);
+	enable_irq(dpu_crtc->crc_shdld_irq);
+	disengcfg_sig_select(dpu_crtc->dec, DEC_SIG_SEL_FRAMEGEN);
+	dpu_enable_signature_roi(dpu_crtc->sig, &r);
+
+	if (dual_crc) {
+		aux_dpu_crtc->use_dual_crc = dual_crc;
+		enable_irq(aux_dpu_crtc->crc_valid_irq);
+		enable_irq(aux_dpu_crtc->crc_shdld_irq);
+		disengcfg_sig_select(dpu_crtc->aux_dec, DEC_SIG_SEL_FRAMEGEN);
+		dpu_enable_signature_roi(dpu_crtc->aux_sig, &aux_r);
+	}
+
+	shdld_done = &dpu_crtc->crc_shdld_done;
+	ret = wait_for_completion_timeout(shdld_done, HZ);
+	if (ret == 0)
+		dev_warn(dpu_crtc->dev, "wait for CRC shdld done timeout\n");
+
+	if (dual_crc) {
+		shdld_done = &aux_dpu_crtc->crc_shdld_done;
+		ret = wait_for_completion_timeout(shdld_done, HZ);
+		if (ret == 0)
+			dev_warn(dpu_crtc->dev,
+				 "wait for auxiliary CRC shdld done timeout\n");
+	}
+
+	disable_irq(dpu_crtc->crc_shdld_irq);
+	if (dual_crc)
+		disable_irq(aux_dpu_crtc->crc_shdld_irq);
+
+	dpu_crtc->crc_is_enabled = true;
+
+	dev_dbg(dpu_crtc->dev, "enable CRC source %d, ROI:" DRM_RECT_FMT "\n",
+		source, DRM_RECT_ARG(roi));
+}
+
+void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+
+	if (!dpu_crtc->crc_is_enabled)
+		return;
+
+	dpu_disable_signature(dpu_crtc->sig);
+	if (dual_crc)
+		dpu_disable_signature(dpu_crtc->aux_sig);
+
+	disable_irq(dpu_crtc->crc_valid_irq);
+	if (dual_crc) {
+		disable_irq(aux_dpu_crtc->crc_valid_irq);
+		reinit_completion(&dpu_crtc->aux_crc_done);
+	}
+
+	dpu_crtc->crc_is_enabled = false;
+
+	dev_dbg(dpu_crtc->dev, "disable CRC source\n");
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-crc.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-crc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019,2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _DPU_CRC_H_
+#define _DPU_CRC_H_
+
+#include "dpu-crtc.h"
+
+enum {
+	DPU_DUAL_CRC_FLAG_DUAL,
+	DPU_DUAL_CRC_FLAG_LEFT,
+	DPU_DUAL_CRC_FLAG_RIGHT,
+	DPU_DUAL_CRC_FLAG_ERR_NONE,
+};
+
+static inline bool to_enable_dpu_crc(struct dpu_crtc_state *new_dcstate,
+				     struct dpu_crtc_state *old_dcstate)
+{
+	return old_dcstate->crc.source == DPU_CRC_SRC_NONE &&
+	       new_dcstate->crc.source != DPU_CRC_SRC_NONE;
+}
+
+static inline bool to_disable_dpu_crc(struct dpu_crtc_state *new_dcstate,
+				      struct dpu_crtc_state *old_dcstate)
+{
+	return old_dcstate->crc.source != DPU_CRC_SRC_NONE &&
+	       new_dcstate->crc.source == DPU_CRC_SRC_NONE;
+}
+
+static inline void dpu_copy_roi(struct drm_rect *from, struct drm_rect *to)
+{
+	to->x1 = from->x1;
+	to->y1 = from->y1;
+	to->x2 = from->x2;
+	to->y2 = from->y2;
+}
+
+#ifdef CONFIG_DEBUG_FS
+int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
+			       size_t *values_cnt);
+int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name);
+irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id);
+void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
+				enum dpu_crc_source source,
+				struct drm_rect *roi);
+void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc);
+#else
+#define dpu_crtc_verify_crc_source NULL
+#define dpu_crtc_set_crc_source	NULL
+irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
+				enum dpu_crc_source source,
+				struct drm_rect *roi)
+{
+}
+void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc)
+{
+}
+#endif
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-crtc.c
@@ -0,0 +1,1442 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <video/dpu.h>
+#include <video/imx8-pc.h>
+#include <video/imx8-prefetch.h>
+#include "dpu-crc.h"
+#include "dpu-crtc.h"
+#include "dpu-kms.h"
+#include "dpu-plane.h"
+#include "../imx-drm.h"
+
+static inline struct dpu_plane_state **
+alloc_dpu_plane_states(struct dpu_crtc *dpu_crtc)
+{
+	struct dpu_plane_state **states;
+
+	states = kcalloc(dpu_crtc->hw_plane_num, sizeof(*states), GFP_KERNEL);
+	if (!states)
+		return ERR_PTR(-ENOMEM);
+
+	return states;
+}
+
+static void dpu_crtc_queue_state_event(struct drm_crtc *crtc)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		WARN_ON(dpu_crtc->event);
+		dpu_crtc->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+struct dpu_plane_state **
+crtc_state_get_dpu_plane_states(struct drm_crtc_state *state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+
+	return dcstate->dpu_plane_states;
+}
+
+struct dpu_crtc *dpu_crtc_get_aux_dpu_crtc(struct dpu_crtc *dpu_crtc)
+{
+	struct drm_crtc *crtc = &dpu_crtc->base, *tmp_crtc;
+	struct drm_device *dev = crtc->dev;
+	struct dpu_crtc *aux_dpu_crtc = NULL;
+
+	drm_for_each_crtc(tmp_crtc, dev) {
+		if (tmp_crtc == crtc)
+			continue;
+
+		aux_dpu_crtc = to_dpu_crtc(tmp_crtc);
+
+		if (dpu_crtc->crtc_grp_id == aux_dpu_crtc->crtc_grp_id)
+			break;
+	}
+
+	BUG_ON(!aux_dpu_crtc);
+
+	return aux_dpu_crtc;
+}
+
+static void dpu_crtc_atomic_enable(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct dpu_extdst *plane_ed = res->ed[dplane->stream_id];
+	struct dpu_extdst *aux_plane_ed = dpu_aux_ed_peek(plane_ed);
+	struct dpu_extdst *m_plane_ed = NULL, *s_plane_ed;
+	struct completion *shdld_done;
+	struct completion *m_safety_shdld_done, *s_safety_shdld_done;
+	struct completion *m_content_shdld_done, *s_content_shdld_done;
+	struct completion *m_dec_shdld_done, *s_dec_shdld_done;
+	unsigned long ret, flags;
+
+	drm_crtc_vblank_on(crtc);
+
+	if (dcstate->use_pc) {
+		tcon_enable_pc(dpu_crtc->tcon);
+
+		if (extdst_is_master(plane_ed)) {
+			m_plane_ed = plane_ed;
+			s_plane_ed = aux_plane_ed;
+		} else {
+			m_plane_ed = aux_plane_ed;
+			s_plane_ed = plane_ed;
+		}
+		extdst_pixengcfg_syncmode_master(m_plane_ed, true);
+		extdst_pixengcfg_syncmode_master(s_plane_ed, false);
+	} else {
+		extdst_pixengcfg_syncmode_master(plane_ed, false);
+	}
+
+	enable_irq(dpu_crtc->safety_shdld_irq);
+	enable_irq(dpu_crtc->content_shdld_irq);
+	enable_irq(dpu_crtc->dec_shdld_irq);
+	if (dcstate->use_pc) {
+		enable_irq(aux_dpu_crtc->safety_shdld_irq);
+		enable_irq(aux_dpu_crtc->content_shdld_irq);
+		enable_irq(aux_dpu_crtc->dec_shdld_irq);
+	}
+
+	if (dcstate->use_pc) {
+		framegen_enable_clock(dpu_crtc->stream_id ?
+					dpu_crtc->aux_fg : dpu_crtc->fg);
+		extdst_pixengcfg_sync_trigger(m_plane_ed);
+		framegen_shdtokgen(dpu_crtc->m_fg);
+
+		/* don't relinquish CPU until TCONs are set to operation mode */
+		local_irq_save(flags);
+		preempt_disable();
+		/* First turn on the slave stream, second the master stream. */
+		framegen_enable(dpu_crtc->s_fg);
+		framegen_enable(dpu_crtc->m_fg);
+		/*
+		 * TKT320590:
+		 * Turn TCONs into operation mode as soon as the first dumb
+		 * frame is generated by DPU from the master stream(we don't
+		 * relinquish CPU to ensure this).  This makes DPRs/PRGs of
+		 * the dual stream be able to evade the dumb frames of the
+		 * dual stream respectively.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->m_fg);
+		/* again, slave first, then master */
+		tcon_set_operation_mode(dpu_crtc->s_tcon);
+		tcon_set_operation_mode(dpu_crtc->m_tcon);
+		local_irq_restore(flags);
+		preempt_enable();
+
+		framegen_enable_pixel_link(dpu_crtc->s_fg);
+		framegen_enable_pixel_link(dpu_crtc->m_fg);
+
+		if (dpu_crtc->aux_is_master) {
+			m_safety_shdld_done  = &aux_dpu_crtc->safety_shdld_done;
+			m_content_shdld_done = &aux_dpu_crtc->content_shdld_done;
+			m_dec_shdld_done     = &aux_dpu_crtc->dec_shdld_done;
+			s_safety_shdld_done  = &dpu_crtc->safety_shdld_done;
+			s_content_shdld_done = &dpu_crtc->content_shdld_done;
+			s_dec_shdld_done     = &dpu_crtc->dec_shdld_done;
+		} else {
+			m_safety_shdld_done  = &dpu_crtc->safety_shdld_done;
+			m_content_shdld_done = &dpu_crtc->content_shdld_done;
+			m_dec_shdld_done     = &dpu_crtc->dec_shdld_done;
+			s_safety_shdld_done  = &aux_dpu_crtc->safety_shdld_done;
+			s_content_shdld_done = &aux_dpu_crtc->content_shdld_done;
+			s_dec_shdld_done     = &aux_dpu_crtc->dec_shdld_done;
+		}
+
+		ret = wait_for_completion_timeout(m_safety_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for master safety shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		ret = wait_for_completion_timeout(m_content_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for master content shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		ret = wait_for_completion_timeout(m_dec_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for master DEC shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+
+		ret = wait_for_completion_timeout(s_safety_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for slave safety shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		ret = wait_for_completion_timeout(s_content_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for slave content shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		ret = wait_for_completion_timeout(s_dec_shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for slave DEC shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+	} else {
+		framegen_enable_clock(dpu_crtc->fg);
+		extdst_pixengcfg_sync_trigger(plane_ed);
+		extdst_pixengcfg_sync_trigger(dpu_crtc->ed);
+		framegen_shdtokgen(dpu_crtc->fg);
+
+		/* don't relinquish CPU until TCON is set to operation mode */
+		local_irq_save(flags);
+		preempt_disable();
+		framegen_enable(dpu_crtc->fg);
+		/*
+		 * TKT320590:
+		 * Turn TCON into operation mode as soon as the first dumb
+		 * frame is generated by DPU(we don't relinquish CPU to ensure
+		 * this).  This makes DPR/PRG be able to evade the frame.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->fg);
+		tcon_set_operation_mode(dpu_crtc->tcon);
+		local_irq_restore(flags);
+		preempt_enable();
+
+		framegen_enable_pixel_link(dpu_crtc->fg);
+
+		shdld_done = &dpu_crtc->safety_shdld_done;
+		ret = wait_for_completion_timeout(shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for safety shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		shdld_done = &dpu_crtc->content_shdld_done;
+		ret = wait_for_completion_timeout(shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for content shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+		shdld_done = &dpu_crtc->dec_shdld_done;
+		ret = wait_for_completion_timeout(shdld_done, HZ);
+		if (ret == 0)
+			DRM_WARN("[CRTC:%d:%s] %s: wait for DEC shdld done timeout\n",
+					crtc->base.id, crtc->name, __func__);
+	}
+
+	disable_irq(dpu_crtc->safety_shdld_irq);
+	disable_irq(dpu_crtc->content_shdld_irq);
+	disable_irq(dpu_crtc->dec_shdld_irq);
+	if (dcstate->use_pc) {
+		disable_irq(aux_dpu_crtc->safety_shdld_irq);
+		disable_irq(aux_dpu_crtc->content_shdld_irq);
+		disable_irq(aux_dpu_crtc->dec_shdld_irq);
+	}
+
+	dpu_crtc_queue_state_event(crtc);
+
+	if (dcstate->use_pc) {
+		framegen_wait_for_secondary_syncup(dpu_crtc->m_fg);
+		framegen_wait_for_secondary_syncup(dpu_crtc->s_fg);
+
+		if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->m_fg)) {
+			framegen_secondary_clear_channel_status(dpu_crtc->m_fg);
+			DRM_WARN("[CRTC:%d:%s] %s: master FrameGen requests to read empty FIFO\n",
+					crtc->base.id, crtc->name, __func__);
+		}
+		if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->s_fg)) {
+			framegen_secondary_clear_channel_status(dpu_crtc->s_fg);
+			DRM_WARN("[CRTC:%d:%s] %s: slave FrameGen requests to read empty FIFO\n",
+					crtc->base.id, crtc->name, __func__);
+		}
+	} else {
+		framegen_wait_for_secondary_syncup(dpu_crtc->fg);
+
+		if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->fg)) {
+			framegen_secondary_clear_channel_status(dpu_crtc->fg);
+			DRM_WARN("[CRTC:%d:%s] %s: FrameGen requests to read empty FIFO\n",
+					crtc->base.id, crtc->name, __func__);
+		}
+	}
+
+	if (dcstate->crc.source != DPU_CRC_SRC_NONE)
+		dpu_crtc_enable_crc_source(crtc,
+				dcstate->crc.source, &dcstate->crc.roi);
+}
+
+static void dpu_crtc_atomic_disable(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct imx_crtc_state *imx_crtc_state =
+					to_imx_crtc_state(old_crtc_state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct drm_display_mode *adjusted_mode = &old_crtc_state->adjusted_mode;
+	struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct dpu_plane_state *dpstate;
+	struct dpu_fetchunit *fu;
+	unsigned long flags;
+	int i;
+
+	if (dcstate->crc.source != DPU_CRC_SRC_NONE)
+		dpu_crtc_disable_crc_source(crtc, dcstate->use_pc);
+
+	if (dcstate->use_pc) {
+		tcon_disable_pc(dpu_crtc->tcon);
+
+		framegen_disable_pixel_link(dpu_crtc->m_fg);
+		framegen_disable_pixel_link(dpu_crtc->s_fg);
+
+		/* don't relinquish CPU until DPRC repeat_en is disabled */
+		local_irq_save(flags);
+		preempt_disable();
+		/*
+		 * Sync to FrameGen frame counter moving so that
+		 * FrameGen can be disabled in the next frame.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->m_fg);
+
+		/* First turn off the master stream, second the slave stream. */
+		framegen_disable(dpu_crtc->m_fg);
+		framegen_disable(dpu_crtc->s_fg);
+
+		/*
+		 * There is one frame leftover after FrameGen disablement.
+		 * Sync to FrameGen frame counter moving so that
+		 * DPRC repeat_en can be disabled in the next frame.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->m_fg);
+
+		for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+			dpu_block_id_t source;
+			bool aux_source_flag;
+			bool use_prefetch;
+
+			dpstate = dcstate->dpu_plane_states[i];
+			if (!dpstate)
+				continue;
+
+			aux_source_flag = false;
+again:
+			source = aux_source_flag ? dpstate->aux_source :
+						   dpstate->source;
+			use_prefetch = aux_source_flag ?
+						dpstate->use_aux_prefetch :
+						dpstate->use_prefetch;
+			fu = source_to_fu(res, source);
+			if (!fu) {
+				local_irq_restore(flags);
+				preempt_enable();
+				return;
+			}
+
+			if (fu->dprc && use_prefetch)
+				dprc_disable_repeat_en(fu->dprc);
+
+			if (dpstate->need_aux_source && !aux_source_flag) {
+				aux_source_flag = true;
+				goto again;
+			}
+		}
+		local_irq_restore(flags);
+		preempt_enable();
+
+		framegen_wait_done(dpu_crtc->m_fg, adjusted_mode);
+		framegen_wait_done(dpu_crtc->s_fg, adjusted_mode);
+
+		framegen_disable_clock(dpu_crtc->stream_id ?
+					dpu_crtc->aux_fg : dpu_crtc->fg);
+	} else {
+		framegen_disable_pixel_link(dpu_crtc->fg);
+
+		/* don't relinquish CPU until DPRC repeat_en is disabled */
+		local_irq_save(flags);
+		preempt_disable();
+		/*
+		 * Sync to FrameGen frame counter moving so that
+		 * FrameGen can be disabled in the next frame.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->fg);
+		framegen_disable(dpu_crtc->fg);
+		/*
+		 * There is one frame leftover after FrameGen disablement.
+		 * Sync to FrameGen frame counter moving so that
+		 * DPRC repeat_en can be disabled in the next frame.
+		 */
+		framegen_wait_for_frame_counter_moving(dpu_crtc->fg);
+
+		for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+			dpstate = dcstate->dpu_plane_states[i];
+			if (!dpstate)
+				continue;
+
+			fu = source_to_fu(res, dpstate->source);
+			if (!fu) {
+				local_irq_restore(flags);
+				preempt_enable();
+				return;
+			}
+
+			if (fu->dprc && dpstate->use_prefetch)
+				dprc_disable_repeat_en(fu->dprc);
+		}
+		local_irq_restore(flags);
+		preempt_enable();
+
+		framegen_wait_done(dpu_crtc->fg, adjusted_mode);
+		framegen_disable_clock(dpu_crtc->fg);
+	}
+
+	drm_crtc_vblank_off(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event && !crtc->state->active) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void dpu_drm_crtc_reset(struct drm_crtc *crtc)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct imx_crtc_state *imx_crtc_state;
+	struct dpu_crtc_state *state;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+		imx_crtc_state = to_imx_crtc_state(crtc->state);
+		state = to_dpu_crtc_state(imx_crtc_state);
+		kfree(state->dpu_plane_states);
+		kfree(state);
+		crtc->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		state->crc.source = DPU_CRC_SRC_NONE;
+		state->crc.roi.x1 = 0;
+		state->crc.roi.y1 = 0;
+		state->crc.roi.x2 = 0;
+		state->crc.roi.y2 = 0;
+
+		crtc->state = &state->imx_crtc_state.base;
+		crtc->state->crtc = crtc;
+
+		state->dpu_plane_states = alloc_dpu_plane_states(dpu_crtc);
+		if (IS_ERR(state->dpu_plane_states))
+			kfree(state);
+	}
+}
+
+static struct drm_crtc_state *
+dpu_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *imx_crtc_state;
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct dpu_crtc_state *state, *copy;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	copy->dpu_plane_states = alloc_dpu_plane_states(dpu_crtc);
+	if (IS_ERR(copy->dpu_plane_states)) {
+		kfree(copy);
+		return NULL;
+	}
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc,
+					&copy->imx_crtc_state.base);
+	imx_crtc_state = to_imx_crtc_state(crtc->state);
+	state = to_dpu_crtc_state(imx_crtc_state);
+	copy->use_pc = state->use_pc;
+	copy->crc.source = state->crc.source;
+	dpu_copy_roi(&state->crc.roi, &copy->crc.roi);
+
+	return &copy->imx_crtc_state.base;
+}
+
+static void dpu_drm_crtc_destroy_state(struct drm_crtc *crtc,
+				       struct drm_crtc_state *state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+	struct dpu_crtc_state *dcstate;
+
+	if (state) {
+		__drm_atomic_helper_crtc_destroy_state(state);
+		dcstate = to_dpu_crtc_state(imx_crtc_state);
+		kfree(dcstate->dpu_plane_states);
+		kfree(dcstate);
+	}
+}
+
+static int dpu_enable_vblank(struct drm_crtc *crtc)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+	enable_irq(dpu_crtc->vbl_irq);
+
+	return 0;
+}
+
+static void dpu_disable_vblank(struct drm_crtc *crtc)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+	disable_irq_nosync(dpu_crtc->vbl_irq);
+}
+
+static const struct drm_crtc_funcs dpu_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = dpu_drm_crtc_reset,
+	.atomic_duplicate_state = dpu_drm_crtc_duplicate_state,
+	.atomic_destroy_state = dpu_drm_crtc_destroy_state,
+	.enable_vblank = dpu_enable_vblank,
+	.disable_vblank = dpu_disable_vblank,
+	.set_crc_source = dpu_crtc_set_crc_source,
+	.verify_crc_source = dpu_crtc_verify_crc_source,
+};
+
+static irqreturn_t dpu_vbl_irq_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+	struct drm_crtc *crtc = &dpu_crtc->base;
+	unsigned long flags;
+
+	drm_crtc_handle_vblank(crtc);
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	if (dpu_crtc->event) {
+		drm_crtc_send_vblank_event(crtc, dpu_crtc->event);
+		dpu_crtc->event = NULL;
+		drm_crtc_vblank_put(crtc);
+	}
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_safety_shdld_irq_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+
+	complete(&dpu_crtc->safety_shdld_done);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_content_shdld_irq_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+
+	complete(&dpu_crtc->content_shdld_done);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_dec_shdld_irq_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+
+	complete(&dpu_crtc->dec_shdld_done);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_crc_shdld_irq_handler(int irq, void *dev_id)
+{
+	struct dpu_crtc *dpu_crtc = dev_id;
+
+	complete(&dpu_crtc->crc_shdld_done);
+
+	return IRQ_HANDLED;
+}
+
+static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
+				 struct drm_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	struct dpu_plane_state *dpstate;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct imx_crtc_state *old_imx_crtc_state =
+					to_imx_crtc_state(crtc->state);
+	struct dpu_crtc_state *old_dcstate =
+					to_dpu_crtc_state(old_imx_crtc_state);
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	struct videomode vm;
+	unsigned long encoder_type = DRM_MODE_ENCODER_NONE;
+	u32 encoder_mask;
+	int i = 0;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		encoder_mask = 1 << drm_encoder_index(encoder);
+
+		if (!(crtc_state->encoder_mask & encoder_mask))
+			continue;
+
+		encoder_type = encoder->encoder_type;
+	}
+
+	if (crtc_state->enable && dcstate->use_pc) {
+		if (encoder_type != DRM_MODE_ENCODER_TMDS) {
+			DRM_DEBUG_KMS("[CRTC:%d:%s] enc type %lu doesn't support pc\n",
+					crtc->base.id, crtc->name, encoder_type);
+			return -EINVAL;
+		}
+
+		drm_display_mode_to_videomode(mode, &vm);
+		if ((vm.hactive % 2)   || (vm.hfront_porch % 2) ||
+		    (vm.hsync_len % 2) || (vm.hback_porch % 2)) {
+			DRM_DEBUG_KMS("[CRTC:%d:%s] video mode is invalid\n",
+					crtc->base.id, crtc->name);
+			return -EINVAL;
+		}
+	}
+
+	/* disallow to enable CRC when CRTC keeps at inactive status */
+	if (!crtc->state->active && !crtc_state->enable &&
+	    to_enable_dpu_crc(dcstate, old_dcstate))
+		return -EINVAL;
+
+	if (crtc_state->enable && dcstate->crc.source == DPU_CRC_SRC_FRAMEGEN) {
+		dcstate->crc.roi.x1 = 0;
+		dcstate->crc.roi.y1 = 0;
+		dcstate->crc.roi.x2 = mode->hdisplay;
+		dcstate->crc.roi.y2 = mode->vdisplay;
+	}
+
+	if (crtc_state->enable && dcstate->crc.source != DPU_CRC_SRC_NONE) {
+		if (dcstate->crc.roi.x1 < 0 || dcstate->crc.roi.y1 < 0)
+			return -EINVAL;
+
+		if (dcstate->crc.roi.x2 > mode->hdisplay ||
+		    dcstate->crc.roi.y2 > mode->vdisplay)
+			return -EINVAL;
+
+		if (!drm_rect_visible(&dcstate->crc.roi))
+			return -EINVAL;
+	}
+
+	/*
+	 * cache the plane states so that the planes can be disabled in
+	 * ->atomic_begin.
+	 */
+	drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
+		plane_state =
+			drm_atomic_get_plane_state(crtc_state->state, plane);
+		if (IS_ERR(plane_state))
+			return PTR_ERR(plane_state);
+
+		dpstate = to_dpu_plane_state(plane_state);
+		dcstate->dpu_plane_states[i++] = dpstate;
+	}
+
+	return 0;
+}
+
+static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_crtc_state)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct imx_crtc_state *old_imx_crtc_state =
+					to_imx_crtc_state(old_crtc_state);
+	struct dpu_crtc_state *old_dcstate =
+					to_dpu_crtc_state(old_imx_crtc_state);
+	int i;
+
+	/*
+	 * Disable all planes' resources in SHADOW only.
+	 * Whether any of them would be disabled or kept running depends
+	 * on new plane states' commit.
+	 */
+	for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+		struct dpu_plane_state *old_dpstate;
+		struct drm_plane_state *plane_state;
+		struct dpu_plane *dplane;
+		struct dpu_plane_res *res;
+		struct dpu_fetchunit *fu;
+		struct dpu_fetchunit *fe = NULL;
+		struct dpu_hscaler *hs = NULL;
+		struct dpu_vscaler *vs = NULL;
+		struct dpu_layerblend *lb;
+		struct dpu_extdst *ed;
+		extdst_src_sel_t ed_src;
+		dpu_block_id_t blend, source;
+		unsigned int stream_id;
+		int lb_id;
+		bool release_aux_source;
+
+		old_dpstate = old_dcstate->dpu_plane_states[i];
+		if (!old_dpstate)
+			continue;
+
+		plane_state = &old_dpstate->base;
+		dplane = to_dpu_plane(plane_state->plane);
+		res = &dplane->grp->res;
+
+		release_aux_source = false;
+again:
+		if (old_dcstate->use_pc) {
+			if (release_aux_source) {
+				source = old_dpstate->aux_source;
+				blend = old_dpstate->aux_blend;
+				stream_id = 1;
+			} else {
+				source = old_dpstate->source;
+				blend = old_dpstate->blend;
+				stream_id = old_dpstate->left_src_w ? 0 : 1;
+			}
+		} else {
+			source = old_dpstate->source;
+			blend = old_dpstate->blend;
+			stream_id = dplane->stream_id;
+		}
+
+		fu = source_to_fu(res, source);
+		if (!fu)
+			return;
+
+		lb_id = blend_to_id(blend);
+		if (lb_id < 0)
+			return;
+
+		lb = res->lb[lb_id];
+
+		layerblend_pixengcfg_clken(lb, CLKEN__DISABLE);
+		if (fetchunit_is_fetchdecode(fu)) {
+			fe = fetchdecode_get_fetcheco(fu);
+			hs = fetchdecode_get_hscaler(fu);
+			vs = fetchdecode_get_vscaler(fu);
+			hscaler_pixengcfg_clken(hs, CLKEN__DISABLE);
+			vscaler_pixengcfg_clken(vs, CLKEN__DISABLE);
+			hscaler_mode(hs, SCALER_NEUTRAL);
+			vscaler_mode(vs, SCALER_NEUTRAL);
+		}
+		if ((!old_dcstate->use_pc && old_dpstate->is_top) ||
+		     (old_dcstate->use_pc &&
+		      ((!stream_id && old_dpstate->is_left_top) ||
+			(stream_id && old_dpstate->is_right_top)))) {
+			ed = res->ed[stream_id];
+			ed_src = stream_id ?
+				ED_SRC_CONSTFRAME1 : ED_SRC_CONSTFRAME0;
+			extdst_pixengcfg_src_sel(ed, ed_src);
+		}
+
+		fu->ops->disable_src_buf(fu);
+		if (fetchunit_is_fetchdecode(fu)) {
+			fetchdecode_pixengcfg_dynamic_src_sel(fu,
+							FD_SRC_DISABLE);
+			fe->ops->disable_src_buf(fe);
+		}
+
+		if (old_dpstate->need_aux_source && !release_aux_source) {
+			release_aux_source = true;
+			goto again;
+		}
+	}
+}
+
+static void dpu_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_crtc_state)
+{
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc), *aux_dpu_crtc = NULL;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct imx_crtc_state *old_imx_crtc_state =
+					to_imx_crtc_state(old_crtc_state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct dpu_crtc_state *old_dcstate =
+					to_dpu_crtc_state(old_imx_crtc_state);
+	struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+	struct dpu_plane_state *old_dpstate;
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct dpu_extdst *ed = res->ed[dplane->stream_id], *aux_ed;
+	struct dpu_fetchunit *fu;
+	dpu_block_id_t source;
+	struct completion *shdld_done;
+	struct completion *m_content_shdld_done = NULL;
+	struct completion *s_content_shdld_done = NULL;
+	unsigned long ret;
+	int i;
+	bool need_modeset = drm_atomic_crtc_needs_modeset(crtc->state);
+	bool need_wait4fgfcm = false, need_aux_wait4fgfcm = false;
+	bool use_prefetch;
+
+	if (!crtc->state->active && !old_crtc_state->active)
+		return;
+
+	if (!need_modeset && to_disable_dpu_crc(dcstate, old_dcstate))
+		dpu_crtc_disable_crc_source(crtc, old_dcstate->use_pc);
+
+	/*
+	 * Scan over old plane fetchunits to determine if we
+	 * need to wait for FrameGen frame counter moving in
+	 * the next loop prior to DPRC repeat_en disablement
+	 * or not.
+	 */
+	for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+		bool aux_source_flag;
+
+		old_dpstate = old_dcstate->dpu_plane_states[i];
+		if (!old_dpstate)
+			continue;
+
+		aux_source_flag = false;
+again1:
+		source = aux_source_flag ?
+				old_dpstate->aux_source : old_dpstate->source;
+		use_prefetch = aux_source_flag ?
+					old_dpstate->use_aux_prefetch :
+					old_dpstate->use_prefetch;
+		fu = source_to_fu(res, source);
+		if (!fu)
+			return;
+
+		if (!fu->ops->is_enabled(fu) && use_prefetch && !need_modeset) {
+			if (aux_source_flag)
+				need_aux_wait4fgfcm = true;
+			else
+				need_wait4fgfcm = true;
+		}
+
+		if (old_dpstate->need_aux_source && !aux_source_flag) {
+			aux_source_flag = true;
+			goto again1;
+		}
+	}
+
+	for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+		struct dpu_fetchunit *fe;
+		struct dpu_hscaler *hs;
+		struct dpu_vscaler *vs;
+		bool aux_source_disable;
+
+		old_dpstate = old_dcstate->dpu_plane_states[i];
+		if (!old_dpstate)
+			continue;
+
+		/*
+		 * Sync with FrameGen frame counter moving so that
+		 * we may disable DPRC repeat_en correctly.
+		 * FIXME: to disable preemption and irq to make sure
+		 *        DPRC repeat_en will be disabled ASAP.
+		 */
+		if (need_wait4fgfcm || need_aux_wait4fgfcm)
+			framegen_wait_for_frame_counter_moving(
+					dcstate->use_pc ?
+						dpu_crtc->m_fg : dpu_crtc->fg);
+
+		aux_source_disable = false;
+again2:
+		source = aux_source_disable ?
+				old_dpstate->aux_source : old_dpstate->source;
+		use_prefetch = aux_source_disable ?
+					old_dpstate->use_aux_prefetch :
+					old_dpstate->use_prefetch;
+		fu = source_to_fu(res, source);
+		if (!fu)
+			return;
+
+		if (!fu->ops->is_enabled(fu)) {
+			fu->ops->set_stream_id(fu, DPU_PLANE_SRC_DISABLED);
+			if (fu->dprc && use_prefetch)
+				dprc_disable_repeat_en(fu->dprc);
+		}
+
+		if (!fetchunit_is_fetchdecode(fu))
+			continue;
+
+		fe = fetchdecode_get_fetcheco(fu);
+		if (!fe->ops->is_enabled(fe))
+			fe->ops->set_stream_id(fe, DPU_PLANE_SRC_DISABLED);
+
+		hs = fetchdecode_get_hscaler(fu);
+		if (!hscaler_is_enabled(hs))
+			hscaler_set_stream_id(hs, DPU_PLANE_SRC_DISABLED);
+
+		vs = fetchdecode_get_vscaler(fu);
+		if (!vscaler_is_enabled(vs))
+			vscaler_set_stream_id(vs, DPU_PLANE_SRC_DISABLED);
+
+		if (old_dpstate->need_aux_source && !aux_source_disable) {
+			aux_source_disable = true;
+			goto again2;
+		}
+	}
+
+	if (dcstate->use_pc) {
+		aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+
+		if (dpu_crtc->aux_is_master) {
+			m_content_shdld_done = &aux_dpu_crtc->content_shdld_done;
+			s_content_shdld_done = &dpu_crtc->content_shdld_done;
+		} else {
+			m_content_shdld_done = &dpu_crtc->content_shdld_done;
+			s_content_shdld_done = &aux_dpu_crtc->content_shdld_done;
+		}
+	}
+
+	if (!need_modeset) {
+		enable_irq(dpu_crtc->content_shdld_irq);
+		if (dcstate->use_pc)
+			enable_irq(aux_dpu_crtc->content_shdld_irq);
+
+		if (dcstate->use_pc) {
+			if (extdst_is_master(ed)) {
+				extdst_pixengcfg_sync_trigger(ed);
+			} else {
+				aux_ed = dpu_aux_ed_peek(ed);
+				extdst_pixengcfg_sync_trigger(aux_ed);
+			}
+		} else {
+			extdst_pixengcfg_sync_trigger(ed);
+		}
+
+		if (dcstate->use_pc) {
+			shdld_done = m_content_shdld_done;
+			ret = wait_for_completion_timeout(shdld_done, HZ);
+			if (ret == 0)
+				DRM_WARN("[CRTC:%d:%s] %s: wait for master content shdld done timeout\n",
+						crtc->base.id, crtc->name, __func__);
+
+			shdld_done = s_content_shdld_done;
+			ret = wait_for_completion_timeout(shdld_done, HZ);
+			if (ret == 0)
+				DRM_WARN("[CRTC:%d:%s] %s: wait for slave content shdld done timeout\n",
+						crtc->base.id, crtc->name, __func__);
+		} else {
+			shdld_done = &dpu_crtc->content_shdld_done;
+			ret = wait_for_completion_timeout(shdld_done, HZ);
+			if (ret == 0)
+				DRM_WARN("[CRTC:%d:%s] %s: wait for content shdld done timeout\n",
+						crtc->base.id, crtc->name, __func__);
+		}
+
+		disable_irq(dpu_crtc->content_shdld_irq);
+		if (dcstate->use_pc)
+			disable_irq(aux_dpu_crtc->content_shdld_irq);
+
+		if (dcstate->use_pc) {
+			if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->m_fg)) {
+				framegen_secondary_clear_channel_status(dpu_crtc->m_fg);
+				DRM_WARN("[CRTC:%d:%s] %s: master FrameGen requests to read empty FIFO\n",
+						crtc->base.id, crtc->name, __func__);
+			}
+			if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->s_fg)) {
+				framegen_secondary_clear_channel_status(dpu_crtc->s_fg);
+				DRM_WARN("[CRTC:%d:%s] %s: slave FrameGen requests to read empty FIFO\n",
+						crtc->base.id, crtc->name, __func__);
+			}
+		} else {
+			if (framegen_secondary_requests_to_read_empty_fifo(dpu_crtc->fg)) {
+				framegen_secondary_clear_channel_status(dpu_crtc->fg);
+				DRM_WARN("[CRTC:%d:%s] %s: FrameGen requests to read empty FIFO\n",
+						crtc->base.id, crtc->name, __func__);
+			}
+		}
+
+		dpu_crtc_queue_state_event(crtc);
+	} else if (!crtc->state->active) {
+		if (old_dcstate->use_pc) {
+			if (extdst_is_master(ed)) {
+				extdst_pixengcfg_sync_trigger(ed);
+			} else {
+				aux_ed = dpu_aux_ed_peek(ed);
+				extdst_pixengcfg_sync_trigger(aux_ed);
+			}
+		} else {
+			extdst_pixengcfg_sync_trigger(ed);
+		}
+	}
+
+	if (!need_modeset && to_enable_dpu_crc(dcstate, old_dcstate))
+		dpu_crtc_enable_crc_source(crtc,
+				dcstate->crc.source, &dcstate->crc.roi);
+}
+
+static void dpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+	struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct dpu_constframe *pa_cf, *sa_cf;
+	struct dpu_disengcfg *dec;
+	struct dpu_extdst *ed, *plane_ed;
+	struct dpu_framegen *fg;
+	struct dpu_tcon *tcon;
+	struct dpu_store *st;
+	struct drm_encoder *encoder;
+	unsigned long encoder_type = DRM_MODE_ENCODER_NONE;
+	unsigned int stream_id;
+	int crtc_hdisplay = dcstate->use_pc ?
+			(mode->crtc_hdisplay >> 1) : mode->crtc_hdisplay;
+	extdst_src_sel_t ed_src;
+	bool cfg_aux_pipe = false;
+
+	DRM_DEBUG_KMS("[CRTC:%d:%s] %s: mode->hdisplay: %d\n",
+			crtc->base.id, crtc->name, __func__, mode->hdisplay);
+	DRM_DEBUG_KMS("[CRTC:%d:%s] %s: mode->vdisplay: %d\n",
+			crtc->base.id, crtc->name, __func__, mode->vdisplay);
+	DRM_DEBUG_KMS("[CRTC:%d:%s] %s: mode->clock: %dKHz\n",
+			crtc->base.id, crtc->name, __func__, mode->clock);
+	DRM_DEBUG_KMS("[CRTC:%d:%s] %s: mode->vrefresh: %dHz\n",
+			crtc->base.id, crtc->name, __func__,
+			drm_mode_vrefresh(mode));
+	if (dcstate->use_pc)
+		DRM_DEBUG_KMS("[CRTC:%d:%s] %s: use pixel combiner\n",
+				crtc->base.id, crtc->name, __func__);
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->crtc == crtc) {
+			encoder_type = encoder->encoder_type;
+			break;
+		}
+	}
+
+again:
+	if (cfg_aux_pipe) {
+		pa_cf = dpu_crtc->aux_pa_cf;
+		sa_cf = dpu_crtc->aux_sa_cf;
+		dec = dpu_crtc->aux_dec;
+		ed = dpu_crtc->aux_ed;
+		fg = dpu_crtc->aux_fg;
+		tcon = dpu_crtc->aux_tcon;
+		st = aux_dpu_crtc->st;
+		stream_id = dpu_crtc->stream_id ^ 1;
+	} else {
+		pa_cf = dpu_crtc->pa_cf;
+		sa_cf = dpu_crtc->sa_cf;
+		dec = dpu_crtc->dec;
+		ed = dpu_crtc->ed;
+		fg = dpu_crtc->fg;
+		tcon = dpu_crtc->tcon;
+		st = dpu_crtc->st;
+		stream_id = dpu_crtc->stream_id;
+	}
+
+	if (dcstate->use_pc) {
+		store_pixengcfg_syncmode_fixup(st, true);
+		framegen_syncmode_fixup(fg,
+				framegen_is_master(fg) ? false : true);
+		framegen_syncmode(fg, framegen_is_master(fg) ?
+				FGSYNCMODE__MASTER : FGSYNCMODE__SLAVE_ONCE);
+	} else {
+		store_pixengcfg_syncmode_fixup(st, false);
+		framegen_syncmode_fixup(fg, false);
+		framegen_syncmode(fg, FGSYNCMODE__OFF);
+	}
+
+	framegen_cfg_videomode(fg, mode, dcstate->use_pc, encoder_type);
+	framegen_displaymode(fg, FGDM__SEC_ON_TOP);
+
+	framegen_panic_displaymode(fg, FGDM__TEST);
+
+	tcon_cfg_videomode(tcon, mode, dcstate->use_pc);
+	tcon_set_fmt(tcon, imx_crtc_state->bus_format);
+	tcon_configure_pc(tcon, stream_id, mode->crtc_hdisplay,
+				dcstate->use_pc ? PC_COMBINE : PC_BYPASS, 0);
+
+	constframe_framedimensions(pa_cf, crtc_hdisplay, mode->crtc_vdisplay);
+	constframe_framedimensions(sa_cf, crtc_hdisplay, mode->crtc_vdisplay);
+	constframe_constantcolor(sa_cf, 0, 0, 0, 0);
+
+	ed_src = stream_id ? ED_SRC_CONSTFRAME5 : ED_SRC_CONSTFRAME4;
+	extdst_pixengcfg_src_sel(ed, ed_src);
+
+	plane_ed = res->ed[stream_id];
+	ed_src = stream_id ? ED_SRC_CONSTFRAME1 : ED_SRC_CONSTFRAME0;
+	extdst_pixengcfg_src_sel(plane_ed, ed_src);
+
+	if (dcstate->use_pc && !cfg_aux_pipe) {
+		cfg_aux_pipe = true;
+		goto again;
+	}
+}
+
+static const struct drm_crtc_helper_funcs dpu_helper_funcs = {
+	.mode_set_nofb = dpu_crtc_mode_set_nofb,
+	.atomic_check = dpu_crtc_atomic_check,
+	.atomic_begin = dpu_crtc_atomic_begin,
+	.atomic_flush = dpu_crtc_atomic_flush,
+	.atomic_enable = dpu_crtc_atomic_enable,
+	.atomic_disable = dpu_crtc_atomic_disable,
+};
+
+static void dpu_crtc_put_resources(struct dpu_crtc *dpu_crtc)
+{
+	if (!IS_ERR_OR_NULL(dpu_crtc->pa_cf))
+		dpu_cf_put(dpu_crtc->pa_cf);
+	if (!IS_ERR_OR_NULL(dpu_crtc->sa_cf))
+		dpu_cf_put(dpu_crtc->sa_cf);
+	if (!IS_ERR_OR_NULL(dpu_crtc->dec))
+		dpu_dec_put(dpu_crtc->dec);
+	if (!IS_ERR_OR_NULL(dpu_crtc->ed))
+		dpu_ed_put(dpu_crtc->ed);
+	if (!IS_ERR_OR_NULL(dpu_crtc->fg))
+		dpu_fg_put(dpu_crtc->fg);
+	if (!IS_ERR_OR_NULL(dpu_crtc->sig))
+		dpu_sig_put(dpu_crtc->sig);
+	if (!IS_ERR_OR_NULL(dpu_crtc->tcon))
+		dpu_tcon_put(dpu_crtc->tcon);
+}
+
+static int dpu_crtc_get_resources(struct dpu_crtc *dpu_crtc)
+{
+	struct dpu_soc *dpu = dev_get_drvdata(dpu_crtc->dev->parent);
+	unsigned int stream_id = dpu_crtc->stream_id;
+	int ret;
+
+	dpu_crtc->pa_cf = dpu_cf_get(dpu, stream_id + 4);
+	if (IS_ERR(dpu_crtc->pa_cf)) {
+		ret = PTR_ERR(dpu_crtc->pa_cf);
+		goto err_out;
+	}
+	dpu_crtc->aux_pa_cf = dpu_aux_cf_peek(dpu_crtc->pa_cf);
+
+	dpu_crtc->sa_cf = dpu_cf_get(dpu, stream_id);
+	if (IS_ERR(dpu_crtc->sa_cf)) {
+		ret = PTR_ERR(dpu_crtc->sa_cf);
+		goto err_out;
+	}
+	dpu_crtc->aux_sa_cf = dpu_aux_cf_peek(dpu_crtc->sa_cf);
+
+	dpu_crtc->dec = dpu_dec_get(dpu, stream_id);
+	if (IS_ERR(dpu_crtc->dec)) {
+		ret = PTR_ERR(dpu_crtc->dec);
+		goto err_out;
+	}
+	dpu_crtc->aux_dec = dpu_aux_dec_peek(dpu_crtc->dec);
+
+	dpu_crtc->ed = dpu_ed_get(dpu, stream_id + 4);
+	if (IS_ERR(dpu_crtc->ed)) {
+		ret = PTR_ERR(dpu_crtc->ed);
+		goto err_out;
+	}
+	dpu_crtc->aux_ed = dpu_aux_ed_peek(dpu_crtc->ed);
+
+	dpu_crtc->fg = dpu_fg_get(dpu, stream_id);
+	if (IS_ERR(dpu_crtc->fg)) {
+		ret = PTR_ERR(dpu_crtc->fg);
+		goto err_out;
+	}
+	dpu_crtc->aux_fg = dpu_aux_fg_peek(dpu_crtc->fg);
+
+	dpu_crtc->sig = dpu_sig_get(dpu, stream_id);
+	if (IS_ERR(dpu_crtc->sig)) {
+		ret = PTR_ERR(dpu_crtc->sig);
+		goto err_out;
+	}
+	dpu_crtc->aux_sig = dpu_aux_sig_peek(dpu_crtc->sig);
+
+	dpu_crtc->tcon = dpu_tcon_get(dpu, stream_id);
+	if (IS_ERR(dpu_crtc->tcon)) {
+		ret = PTR_ERR(dpu_crtc->tcon);
+		goto err_out;
+	}
+	dpu_crtc->aux_tcon = dpu_aux_tcon_peek(dpu_crtc->tcon);
+
+	if (dpu_crtc->aux_is_master) {
+		dpu_crtc->m_pa_cf = dpu_crtc->aux_pa_cf;
+		dpu_crtc->m_sa_cf = dpu_crtc->aux_sa_cf;
+		dpu_crtc->m_dec  = dpu_crtc->aux_dec;
+		dpu_crtc->m_ed   = dpu_crtc->aux_ed;
+		dpu_crtc->m_fg   = dpu_crtc->aux_fg;
+		dpu_crtc->m_tcon = dpu_crtc->aux_tcon;
+
+		dpu_crtc->s_pa_cf = dpu_crtc->pa_cf;
+		dpu_crtc->s_sa_cf = dpu_crtc->sa_cf;
+		dpu_crtc->s_dec  = dpu_crtc->dec;
+		dpu_crtc->s_ed   = dpu_crtc->ed;
+		dpu_crtc->s_fg   = dpu_crtc->fg;
+		dpu_crtc->s_tcon = dpu_crtc->tcon;
+	} else {
+		dpu_crtc->m_pa_cf = dpu_crtc->pa_cf;
+		dpu_crtc->m_sa_cf = dpu_crtc->sa_cf;
+		dpu_crtc->m_dec  = dpu_crtc->dec;
+		dpu_crtc->m_ed   = dpu_crtc->ed;
+		dpu_crtc->m_fg   = dpu_crtc->fg;
+		dpu_crtc->m_tcon = dpu_crtc->tcon;
+
+		dpu_crtc->s_pa_cf = dpu_crtc->aux_pa_cf;
+		dpu_crtc->s_sa_cf = dpu_crtc->aux_sa_cf;
+		dpu_crtc->s_dec  = dpu_crtc->aux_dec;
+		dpu_crtc->s_ed   = dpu_crtc->aux_ed;
+		dpu_crtc->s_fg   = dpu_crtc->aux_fg;
+		dpu_crtc->s_tcon = dpu_crtc->aux_tcon;
+	}
+
+	return 0;
+err_out:
+	dpu_crtc_put_resources(dpu_crtc);
+
+	return ret;
+}
+
+static int dpu_crtc_init(struct dpu_crtc *dpu_crtc,
+	struct dpu_client_platformdata *pdata, struct drm_device *drm)
+{
+	struct dpu_soc *dpu = dev_get_drvdata(dpu_crtc->dev->parent);
+	struct device *dev = dpu_crtc->dev;
+	struct drm_crtc *crtc = &dpu_crtc->base;
+	struct dpu_plane_grp *plane_grp = pdata->plane_grp;
+	unsigned int stream_id = pdata->stream_id;
+	int i, ret;
+
+	init_completion(&dpu_crtc->safety_shdld_done);
+	init_completion(&dpu_crtc->content_shdld_done);
+	init_completion(&dpu_crtc->dec_shdld_done);
+	init_completion(&dpu_crtc->crc_shdld_done);
+	init_completion(&dpu_crtc->aux_crc_done);
+
+	dpu_crtc->stream_id = stream_id;
+	dpu_crtc->crtc_grp_id = pdata->di_grp_id;
+	dpu_crtc->hw_plane_num = plane_grp->hw_plane_num;
+	dpu_crtc->syncmode_min_prate = dpu_get_syncmode_min_prate(dpu);
+	dpu_crtc->singlemode_max_width = dpu_get_singlemode_max_width(dpu);
+	dpu_crtc->master_stream_id = dpu_get_master_stream_id(dpu);
+	dpu_crtc->aux_is_master = !(dpu_crtc->master_stream_id == stream_id);
+	dpu_crtc->st = pdata->st9;
+
+	dpu_crtc->plane = devm_kcalloc(dev, dpu_crtc->hw_plane_num,
+					sizeof(*dpu_crtc->plane), GFP_KERNEL);
+	if (!dpu_crtc->plane)
+		return -ENOMEM;
+
+	ret = dpu_crtc_get_resources(dpu_crtc);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "getting resources failed with %d.\n", ret);
+		return ret;
+	}
+
+	plane_grp->res.fg[stream_id] = dpu_crtc->fg;
+	dpu_crtc->plane[0] = dpu_plane_create(drm, 0, stream_id, plane_grp,
+					DRM_PLANE_TYPE_PRIMARY);
+	if (IS_ERR(dpu_crtc->plane[0])) {
+		ret = PTR_ERR(dpu_crtc->plane[0]);
+		DRM_DEV_ERROR(dev,
+				"initializing plane0 failed with %d.\n", ret);
+		goto err_put_resources;
+	}
+
+	crtc->port = pdata->of_node;
+	drm_crtc_helper_add(crtc, &dpu_helper_funcs);
+	ret = drm_crtc_init_with_planes(drm, crtc, &dpu_crtc->plane[0]->base, NULL,
+			&dpu_crtc_funcs, NULL);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "adding crtc failed with %d.\n", ret);
+		goto err_put_resources;
+	}
+
+	for (i = 1; i < dpu_crtc->hw_plane_num; i++) {
+		dpu_crtc->plane[i] = dpu_plane_create(drm,
+					drm_crtc_mask(&dpu_crtc->base),
+					stream_id, plane_grp,
+					DRM_PLANE_TYPE_OVERLAY);
+		if (IS_ERR(dpu_crtc->plane[i])) {
+			ret = PTR_ERR(dpu_crtc->plane[i]);
+			DRM_DEV_ERROR(dev,
+				"initializing plane%d failed with %d.\n",
+								i, ret);
+			goto err_put_resources;
+		}
+	}
+
+	dpu_crtc->vbl_irq = dpu_map_irq(dpu, stream_id ?
+				IRQ_DISENGCFG_FRAMECOMPLETE1 :
+				IRQ_DISENGCFG_FRAMECOMPLETE0);
+	irq_set_status_flags(dpu_crtc->vbl_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_irq(dev, dpu_crtc->vbl_irq, dpu_vbl_irq_handler, 0,
+				"imx_drm", dpu_crtc);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "vblank irq request failed with %d.\n", ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->vbl_irq);
+
+	dpu_crtc->safety_shdld_irq = dpu_map_irq(dpu, stream_id ?
+			IRQ_EXTDST5_SHDLOAD : IRQ_EXTDST4_SHDLOAD);
+	irq_set_status_flags(dpu_crtc->safety_shdld_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_irq(dev, dpu_crtc->safety_shdld_irq,
+				dpu_safety_shdld_irq_handler, 0, "imx_drm",
+				dpu_crtc);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev,
+			"safety shadow load irq request failed with %d.\n",
+									ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->safety_shdld_irq);
+
+	dpu_crtc->content_shdld_irq = dpu_map_irq(dpu, stream_id ?
+			IRQ_EXTDST1_SHDLOAD : IRQ_EXTDST0_SHDLOAD);
+	irq_set_status_flags(dpu_crtc->content_shdld_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_irq(dev, dpu_crtc->content_shdld_irq,
+				dpu_content_shdld_irq_handler, 0, "imx_drm",
+				dpu_crtc);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev,
+			"content shadow load irq request failed with %d.\n",
+									ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->content_shdld_irq);
+
+	dpu_crtc->dec_shdld_irq = dpu_map_irq(dpu, stream_id ?
+			IRQ_DISENGCFG_SHDLOAD1 : IRQ_DISENGCFG_SHDLOAD0);
+	irq_set_status_flags(dpu_crtc->dec_shdld_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_irq(dev, dpu_crtc->dec_shdld_irq,
+				dpu_dec_shdld_irq_handler, 0, "imx_drm",
+				dpu_crtc);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev,
+			"DEC shadow load irq request failed with %d.\n",
+									ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->dec_shdld_irq);
+
+	dpu_crtc->crc_valid_irq = dpu_map_irq(dpu, stream_id ?
+					IRQ_SIG1_VALID : IRQ_SIG0_VALID);
+	irq_set_status_flags(dpu_crtc->crc_valid_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_threaded_irq(dev, dpu_crtc->crc_valid_irq, NULL,
+					dpu_crc_valid_irq_threaded_handler,
+					IRQF_ONESHOT, "imx_drm", dpu_crtc);
+	if (ret < 0) {
+		dev_err(dev,
+			"CRC valid irq request failed with %d.\n",
+			ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->crc_valid_irq);
+
+	dpu_crtc->crc_shdld_irq = dpu_map_irq(dpu, stream_id ?
+					IRQ_SIG1_SHDLOAD : IRQ_SIG0_SHDLOAD);
+	irq_set_status_flags(dpu_crtc->crc_shdld_irq, IRQ_DISABLE_UNLAZY);
+	ret = devm_request_irq(dev, dpu_crtc->crc_shdld_irq,
+				dpu_crc_shdld_irq_handler, 0, "imx_drm",
+				dpu_crtc);
+	if (ret < 0) {
+		dev_err(dev,
+			"CRC shadow load irq request failed with %d.\n",
+			ret);
+		goto err_put_resources;
+	}
+	disable_irq(dpu_crtc->crc_shdld_irq);
+
+	return 0;
+
+err_put_resources:
+	dpu_crtc_put_resources(dpu_crtc);
+
+	return ret;
+}
+
+static int dpu_crtc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dpu_client_platformdata *pdata = dev->platform_data;
+	struct drm_device *drm = data;
+	struct dpu_crtc *dpu_crtc = dev_get_drvdata(dev);
+	int ret;
+
+	dpu_crtc->dev = dev;
+
+	drm->mode_config.max_width = 5120;
+	drm->mode_config.max_height = 4096;
+
+	ret = dpu_crtc_init(dpu_crtc, pdata, drm);
+	if (ret)
+		return ret;
+
+	if (!drm->mode_config.funcs)
+		drm->mode_config.funcs = &dpu_drm_mode_config_funcs;
+
+	return 0;
+}
+
+static void dpu_crtc_unbind(struct device *dev, struct device *master,
+				void *data)
+{
+	struct dpu_crtc *dpu_crtc = dev_get_drvdata(dev);
+
+	dpu_crtc_put_resources(dpu_crtc);
+}
+
+static const struct component_ops dpu_crtc_ops = {
+	.bind = dpu_crtc_bind,
+	.unbind = dpu_crtc_unbind,
+};
+
+static int dpu_crtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct dpu_crtc *dpu_crtc;
+
+	if (!dev->platform_data)
+		return -EINVAL;
+
+	dpu_crtc = devm_kzalloc(dev, sizeof(*dpu_crtc), GFP_KERNEL);
+	if (!dpu_crtc)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, dpu_crtc);
+
+	return component_add(dev, &dpu_crtc_ops);
+}
+
+static int dpu_crtc_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dpu_crtc_ops);
+	return 0;
+}
+
+static struct platform_driver dpu_crtc_driver = {
+	.driver = {
+		.name = "imx-dpu-crtc",
+	},
+	.probe = dpu_crtc_probe,
+	.remove = dpu_crtc_remove,
+};
+module_platform_driver(dpu_crtc_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DPU CRTC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-dpu-crtc");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-crtc.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-crtc.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _DPU_CRTC_H_
+#define _DPU_CRTC_H_
+
+#include <drm/drm_vblank.h>
+#include <video/dpu.h>
+#include "dpu-plane.h"
+#include "../imx-drm.h"
+
+struct dpu_crtc {
+	struct device		*dev;
+	struct drm_crtc		base;
+	struct imx_drm_crtc	*imx_crtc;
+	struct dpu_constframe	*pa_cf;
+	struct dpu_constframe	*sa_cf;
+	struct dpu_disengcfg	*dec;
+	struct dpu_extdst	*ed;
+	struct dpu_framegen	*fg;
+	struct dpu_signature	*sig;
+	struct dpu_tcon		*tcon;
+	struct dpu_store	*st;
+	struct dpu_constframe	*aux_pa_cf;
+	struct dpu_constframe	*aux_sa_cf;
+	struct dpu_disengcfg	*aux_dec;
+	struct dpu_extdst	*aux_ed;
+	struct dpu_framegen	*aux_fg;
+	struct dpu_signature	*aux_sig;
+	struct dpu_tcon		*aux_tcon;
+	/* master */
+	struct dpu_constframe	*m_pa_cf;
+	struct dpu_constframe	*m_sa_cf;
+	struct dpu_disengcfg	*m_dec;
+	struct dpu_extdst	*m_ed;
+	struct dpu_framegen	*m_fg;
+	struct dpu_tcon		*m_tcon;
+	/* slave */
+	struct dpu_constframe	*s_pa_cf;
+	struct dpu_constframe	*s_sa_cf;
+	struct dpu_disengcfg	*s_dec;
+	struct dpu_extdst	*s_ed;
+	struct dpu_framegen	*s_fg;
+	struct dpu_tcon		*s_tcon;
+	struct dpu_plane	**plane;
+	unsigned int		hw_plane_num;
+	unsigned int		stream_id;
+	unsigned int		crtc_grp_id;
+	unsigned int		syncmode_min_prate;
+	unsigned int		singlemode_max_width;
+	unsigned int		master_stream_id;
+	int			vbl_irq;
+	int			safety_shdld_irq;
+	int			content_shdld_irq;
+	int			dec_shdld_irq;
+	int			crc_valid_irq;
+	int			crc_shdld_irq;
+
+	bool			aux_is_master;
+	bool			use_dual_crc;
+	bool			crc_is_enabled;
+
+	struct completion	safety_shdld_done;
+	struct completion	content_shdld_done;
+	struct completion	dec_shdld_done;
+	struct completion	crc_shdld_done;
+	struct completion	aux_crc_done;
+
+	struct drm_pending_vblank_event *event;
+
+	u32			crc_red;
+	u32			crc_green;
+	u32			crc_blue;
+	u32			dual_crc_flag;
+};
+
+struct dpu_crc {
+	enum dpu_crc_source	source;
+	struct drm_rect		roi;
+};
+
+struct dpu_crtc_state {
+	struct imx_crtc_state	imx_crtc_state;
+	struct dpu_plane_state	**dpu_plane_states;
+	struct dpu_crc		crc;
+	bool			use_pc;
+};
+
+static inline struct dpu_crtc_state *to_dpu_crtc_state(struct imx_crtc_state *s)
+{
+	return container_of(s, struct dpu_crtc_state, imx_crtc_state);
+}
+
+static inline struct dpu_crtc *to_dpu_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct dpu_crtc, base);
+}
+
+struct dpu_plane_state **
+crtc_state_get_dpu_plane_states(struct drm_crtc_state *state);
+
+struct dpu_crtc *dpu_crtc_get_aux_dpu_crtc(struct dpu_crtc *dpu_crtc);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-kms.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <linux/sort.h>
+#include <video/dpu.h>
+#include "dpu-crtc.h"
+#include "dpu-plane.h"
+#include "../imx-drm.h"
+
+static struct drm_plane_state **
+dpu_atomic_alloc_tmp_planes_per_crtc(struct drm_device *dev)
+{
+	int total_planes = dev->mode_config.num_total_plane;
+	struct drm_plane_state **states;
+
+	states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
+	if (!states)
+		return ERR_PTR(-ENOMEM);
+
+	return states;
+}
+
+static int zpos_cmp(const void *a, const void *b)
+{
+	const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
+	const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
+
+	return sa->normalized_zpos - sb->normalized_zpos;
+}
+
+static int dpu_atomic_sort_planes_per_crtc(struct drm_crtc_state *crtc_state,
+					   struct drm_plane_state **states)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_device *dev = state->dev;
+	struct drm_plane *plane;
+	int n = 0;
+
+	drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
+		struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
+		if (IS_ERR(plane_state))
+			return PTR_ERR(plane_state);
+		states[n++] = plane_state;
+	}
+
+	sort(states, n, sizeof(*states), zpos_cmp, NULL);
+
+	return n;
+}
+
+static void
+dpu_atomic_compute_plane_lrx_per_crtc(struct drm_crtc_state *crtc_state,
+				      struct drm_plane_state **states, int n)
+{
+	struct dpu_plane_state *dpstate;
+	struct drm_plane_state *plane_state;
+	int i;
+	int half_hdisplay = crtc_state->adjusted_mode.hdisplay >> 1;
+	bool lo, ro, bo;
+
+	/* compute left/right_crtc_x if pixel combiner is needed */
+	for (i = 0; i < n; i++) {
+		plane_state = states[i];
+		dpstate = to_dpu_plane_state(plane_state);
+
+		lo =  dpstate->left_src_w && !dpstate->right_src_w;
+		ro = !dpstate->left_src_w &&  dpstate->right_src_w;
+		bo =  dpstate->left_src_w &&  dpstate->right_src_w;
+
+		if (lo || bo) {
+			dpstate->left_crtc_x = plane_state->crtc_x;
+			dpstate->right_crtc_x = 0;
+		} else if (ro) {
+			dpstate->left_crtc_x = 0;
+			dpstate->right_crtc_x =
+					plane_state->crtc_x - half_hdisplay;
+		}
+	}
+}
+
+static void
+dpu_atomic_set_top_plane_per_crtc(struct drm_plane_state **states, int n,
+				  bool use_pc)
+{
+	struct dpu_plane_state *dpstate;
+	bool found_l_top = false, found_r_top = false;
+	int i;
+
+	for (i = n - 1; i >= 0; i--) {
+		dpstate = to_dpu_plane_state(states[i]);
+		if (use_pc) {
+			if (dpstate->left_src_w && !found_l_top) {
+				dpstate->is_left_top = true;
+				found_l_top = true;
+			} else {
+				dpstate->is_left_top = false;
+			}
+
+			if (dpstate->right_src_w && !found_r_top) {
+				dpstate->is_right_top = true;
+				found_r_top = true;
+			} else {
+				dpstate->is_right_top = false;
+			}
+		} else {
+			dpstate->is_top = (i == (n - 1)) ? true : false;
+		}
+	}
+}
+
+static int
+dpu_atomic_assign_plane_source_per_crtc(struct drm_plane_state **states,
+					int n, bool use_pc)
+{
+	struct dpu_plane_state *dpstate;
+	struct dpu_plane *dplane;
+	struct dpu_plane_grp *grp;
+	struct drm_framebuffer *fb;
+	struct dpu_fetchunit *fu;
+	struct dpu_fetchunit *fe;
+	struct dpu_hscaler *hs;
+	struct dpu_vscaler *vs;
+	lb_prim_sel_t stage;
+	dpu_block_id_t blend;
+	unsigned int sid, src_sid;
+	unsigned int num_planes;
+	int bit;
+	int i, j, k = 0, m;
+	int total_asrc_num;
+	int s0_layer_cnt = 0, s1_layer_cnt = 0;
+	int s0_n = 0, s1_n = 0;
+	u32 src_a_mask, cap_mask, fe_mask, hs_mask, vs_mask;
+	bool need_fetcheco, need_hscaler, need_vscaler;
+	bool fmt_is_yuv;
+	bool alloc_aux_source;
+
+	if (use_pc) {
+		for (i = 0; i < n; i++) {
+			dpstate = to_dpu_plane_state(states[i]);
+
+			if (dpstate->left_src_w)
+				s0_n++;
+
+			if (dpstate->right_src_w)
+				s1_n++;
+		}
+	} else {
+		s0_n = n;
+		s1_n = n;
+	}
+
+	/* for active planes only */
+	for (i = 0; i < n; i++) {
+		dpstate = to_dpu_plane_state(states[i]);
+		dplane = to_dpu_plane(states[i]->plane);
+		fb = states[i]->fb;
+		num_planes = fb->format->num_planes;
+		fmt_is_yuv = drm_format_is_yuv(fb->format->format);
+		grp = dplane->grp;
+		alloc_aux_source = false;
+
+		if (use_pc)
+			sid = dpstate->left_src_w ? 0 : 1;
+		else
+			sid = dplane->stream_id;
+
+again:
+		if (alloc_aux_source)
+			sid ^= 1;
+
+		need_fetcheco = (num_planes > 1);
+		need_hscaler = (states[i]->src_w >> 16 != states[i]->crtc_w);
+		need_vscaler = (states[i]->src_h >> 16 != states[i]->crtc_h);
+
+		total_asrc_num = 0;
+		src_a_mask = grp->src_a_mask;
+		fe_mask = 0;
+		hs_mask = 0;
+		vs_mask = 0;
+
+		for_each_set_bit(bit, (unsigned long *)&src_a_mask, 32)
+			total_asrc_num++;
+
+		/* assign source */
+		mutex_lock(&grp->mutex);
+		for (j = 0; j < total_asrc_num; j++) {
+			k = ffs(src_a_mask) - 1;
+			if (k < 0)
+				return -EINVAL;
+
+			fu = source_to_fu(&grp->res, sources[k]);
+			if (!fu)
+				return -EINVAL;
+
+			/* avoid on-the-fly/hot migration */
+			src_sid = fu->ops->get_stream_id(fu);
+			if (src_sid && src_sid != BIT(sid))
+				goto next;
+
+			if (fetchunit_is_fetchdecode(fu)) {
+				cap_mask = fetchdecode_get_vproc_mask(fu);
+
+				if (need_fetcheco) {
+					fe = fetchdecode_get_fetcheco(fu);
+
+					/* avoid on-the-fly/hot migration */
+					src_sid = fu->ops->get_stream_id(fe);
+					if (src_sid && src_sid != BIT(sid))
+						goto next;
+
+					/* fetch unit has the fetcheco cap? */
+					if (!dpu_vproc_has_fetcheco_cap(cap_mask))
+						goto next;
+
+					fe_mask =
+					   dpu_vproc_get_fetcheco_cap(cap_mask);
+
+					/* fetcheco available? */
+					if (grp->src_use_vproc_mask & fe_mask)
+						goto next;
+				}
+
+				if (need_hscaler) {
+					hs = fetchdecode_get_hscaler(fu);
+
+					/* avoid on-the-fly/hot migration */
+					src_sid = hscaler_get_stream_id(hs);
+					if (src_sid && src_sid != BIT(sid))
+						goto next;
+
+					/* fetch unit has the hscale cap */
+					if (!dpu_vproc_has_hscale_cap(cap_mask))
+						goto next;
+
+					hs_mask =
+					     dpu_vproc_get_hscale_cap(cap_mask);
+
+					/* hscaler available? */
+					if (grp->src_use_vproc_mask & hs_mask)
+						goto next;
+				}
+
+				if (need_vscaler) {
+					vs = fetchdecode_get_vscaler(fu);
+
+					/* avoid on-the-fly/hot migration */
+					src_sid = vscaler_get_stream_id(vs);
+					if (src_sid && src_sid != BIT(sid))
+						goto next;
+
+					/* fetch unit has the vscale cap? */
+					if (!dpu_vproc_has_vscale_cap(cap_mask))
+						goto next;
+
+					vs_mask =
+					     dpu_vproc_get_vscale_cap(cap_mask);
+
+					/* vscaler available? */
+					if (grp->src_use_vproc_mask & vs_mask)
+						goto next;
+				}
+			} else {
+				if (fmt_is_yuv || need_fetcheco ||
+				    need_hscaler || need_vscaler)
+					goto next;
+			}
+
+			grp->src_a_mask &= ~BIT(k);
+			grp->src_use_vproc_mask |= fe_mask | hs_mask | vs_mask;
+			break;
+next:
+			src_a_mask &= ~BIT(k);
+			fe_mask = 0;
+			hs_mask = 0;
+			vs_mask = 0;
+		}
+		mutex_unlock(&grp->mutex);
+
+		if (j == total_asrc_num)
+			return -EINVAL;
+
+		if (alloc_aux_source)
+			dpstate->aux_source = sources[k];
+		else
+			dpstate->source = sources[k];
+
+		/* assign stage and blend */
+		if (sid) {
+			m = grp->hw_plane_num - (s1_n - s1_layer_cnt);
+			stage = s1_layer_cnt ? stages[m - 1] : cf_stages[sid];
+			blend = blends[m];
+
+			s1_layer_cnt++;
+		} else {
+			stage = s0_layer_cnt ?
+				stages[s0_layer_cnt - 1] : cf_stages[sid];
+			blend = blends[s0_layer_cnt];
+
+			s0_layer_cnt++;
+		}
+
+		if (alloc_aux_source) {
+			dpstate->aux_stage = stage;
+			dpstate->aux_blend = blend;
+		} else {
+			dpstate->stage = stage;
+			dpstate->blend = blend;
+		}
+
+		if (dpstate->need_aux_source && !alloc_aux_source) {
+			alloc_aux_source = true;
+			goto again;
+		}
+	}
+
+	return 0;
+}
+
+static void
+dpu_atomic_mark_pipe_states_prone_to_put_per_crtc(struct drm_crtc *crtc,
+						u32 crtc_mask,
+						struct drm_atomic_state *state,
+						bool *puts)
+{
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	bool found_pstate = false;
+	int i;
+
+	if ((crtc_mask & drm_crtc_mask(crtc)) == 0) {
+		for_each_new_plane_in_state(state, plane, plane_state, i) {
+			if (plane->possible_crtcs & drm_crtc_mask(crtc)) {
+				found_pstate = true;
+				break;
+			}
+		}
+
+		if (!found_pstate)
+			puts[drm_crtc_index(crtc)] = true;
+	}
+}
+
+static void
+dpu_atomic_put_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane)
+{
+	int index = drm_plane_index(plane);
+
+	plane->funcs->atomic_destroy_state(plane, state->planes[index].state);
+	state->planes[index].ptr = NULL;
+	state->planes[index].state = NULL;
+
+	drm_modeset_unlock(&plane->mutex);
+}
+
+static void
+dpu_atomic_put_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int index = drm_crtc_index(crtc);
+
+	crtc->funcs->atomic_destroy_state(crtc, state->crtcs[index].state);
+	state->crtcs[index].ptr = NULL;
+	state->crtcs[index].state = NULL;
+
+	drm_modeset_unlock(&crtc->mutex);
+}
+
+static void
+dpu_atomic_put_possible_states_per_crtc(struct drm_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_crtc *crtc = crtc_state->crtc;
+	struct drm_crtc_state *old_crtc_state = crtc->state;
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+	struct dpu_plane_state **old_dpstates;
+	struct dpu_plane_state *old_dpstate, *new_dpstate;
+	u32 active_mask = 0;
+	int i;
+
+	old_dpstates = crtc_state_get_dpu_plane_states(old_crtc_state);
+	if (WARN_ON(!old_dpstates))
+		return;
+
+	for (i = 0; i < dplane->grp->hw_plane_num; i++) {
+		old_dpstate = old_dpstates[i];
+		if (!old_dpstate)
+			continue;
+
+		active_mask |= BIT(i);
+
+		drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
+			if (drm_plane_index(plane) !=
+			    drm_plane_index(old_dpstate->base.plane))
+				continue;
+
+			plane_state =
+				drm_atomic_get_existing_plane_state(state,
+									plane);
+			if (WARN_ON(!plane_state))
+				return;
+
+			new_dpstate = to_dpu_plane_state(plane_state);
+
+			active_mask &= ~BIT(i);
+
+			/*
+			 * Should be enough to check the below real HW plane
+			 * resources only.
+			 * Things like vproc resources should be fine.
+			 */
+			if (old_dpstate->stage  != new_dpstate->stage  ||
+			    old_dpstate->source != new_dpstate->source ||
+			    old_dpstate->blend  != new_dpstate->blend  ||
+			    old_dpstate->aux_stage  != new_dpstate->aux_stage  ||
+			    old_dpstate->aux_source != new_dpstate->aux_source ||
+			    old_dpstate->aux_blend  != new_dpstate->aux_blend)
+				return;
+		}
+	}
+
+	/* pure software check */
+	if (WARN_ON(active_mask))
+		return;
+
+	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+		dpu_atomic_put_plane_state(state, plane);
+
+	dpu_atomic_put_crtc_state(state, crtc);
+}
+
+static int dpu_drm_atomic_check(struct drm_device *dev,
+				struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane *plane;
+	struct dpu_plane *dpu_plane;
+	struct drm_plane_state *plane_state;
+	struct dpu_plane_state *dpstate;
+	struct drm_framebuffer *fb;
+	struct dpu_plane_grp *grp[MAX_DPU_PLANE_GRP];
+	int ret, i, grp_id;
+	int active_plane[MAX_DPU_PLANE_GRP];
+	int active_plane_fetcheco[MAX_DPU_PLANE_GRP];
+	int active_plane_hscale[MAX_DPU_PLANE_GRP];
+	int active_plane_vscale[MAX_DPU_PLANE_GRP];
+	int half_hdisplay = 0;
+	bool pipe_states_prone_to_put[MAX_CRTC];
+	bool use_pc[MAX_DPU_PLANE_GRP];
+	u32 crtc_mask_in_state = 0;
+
+	ret = drm_atomic_helper_check_modeset(dev, state);
+	if (ret) {
+		DRM_DEBUG_KMS("%s: failed to check modeset\n", __func__);
+		return ret;
+	}
+
+	for (i = 0; i < MAX_CRTC; i++)
+		pipe_states_prone_to_put[i] = false;
+
+	for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+		active_plane[i] = 0;
+		active_plane_fetcheco[i] = 0;
+		active_plane_hscale[i] = 0;
+		active_plane_vscale[i] = 0;
+		use_pc[i] = false;
+		grp[i] = NULL;
+	}
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
+		crtc_mask_in_state |= drm_crtc_mask(crtc);
+
+	drm_for_each_crtc(crtc, dev) {
+		struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+		struct imx_crtc_state *imx_crtc_state;
+		struct dpu_crtc_state *dcstate;
+		bool need_left, need_right, need_aux_source, use_pc_per_crtc;
+
+		use_pc_per_crtc = false;
+
+		dpu_atomic_mark_pipe_states_prone_to_put_per_crtc(crtc,
+						crtc_mask_in_state, state,
+						pipe_states_prone_to_put);
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+
+		imx_crtc_state = to_imx_crtc_state(crtc_state);
+		dcstate = to_dpu_crtc_state(imx_crtc_state);
+
+		if (crtc_state->enable) {
+			if (use_pc[dpu_crtc->crtc_grp_id]) {
+				DRM_DEBUG_KMS("other crtc needs pixel combiner\n");
+				return -EINVAL;
+			}
+
+			if (crtc_state->adjusted_mode.clock >
+					dpu_crtc->syncmode_min_prate ||
+			    crtc_state->adjusted_mode.hdisplay >
+					dpu_crtc->singlemode_max_width)
+				use_pc_per_crtc = true;
+		}
+
+		if (use_pc_per_crtc) {
+			use_pc[dpu_crtc->crtc_grp_id] = true;
+			half_hdisplay = crtc_state->adjusted_mode.hdisplay >> 1;
+		}
+
+		dcstate->use_pc = use_pc_per_crtc;
+
+		drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
+			plane_state = drm_atomic_get_plane_state(state, plane);
+			if (IS_ERR(plane_state)) {
+				DRM_DEBUG_KMS("failed to get plane state\n");
+				return PTR_ERR(plane_state);
+			}
+
+			dpstate = to_dpu_plane_state(plane_state);
+			fb = plane_state->fb;
+			dpu_plane = to_dpu_plane(plane);
+			grp_id = dpu_plane->grp->id;
+			active_plane[grp_id]++;
+
+			need_left = false;
+			need_right = false;
+			need_aux_source = false;
+
+			if (use_pc_per_crtc) {
+				if (plane_state->crtc_x < half_hdisplay)
+					need_left = true;
+
+				if ((plane_state->crtc_w +
+				     plane_state->crtc_x) > half_hdisplay)
+					need_right = true;
+
+				if (need_left && need_right) {
+					need_aux_source = true;
+					active_plane[grp_id]++;
+				}
+			}
+
+			if (need_left && need_right) {
+				dpstate->left_crtc_w = half_hdisplay;
+				dpstate->left_crtc_w -= plane_state->crtc_x;
+
+				dpstate->left_src_w = dpstate->left_crtc_w;
+			} else if (need_left) {
+				dpstate->left_crtc_w = plane_state->crtc_w;
+				dpstate->left_src_w = plane_state->src_w >> 16;
+			} else {
+				dpstate->left_crtc_w = 0;
+				dpstate->left_src_w = 0;
+			}
+
+			if (need_right && need_left) {
+				dpstate->right_crtc_w = plane_state->crtc_x +
+					plane_state->crtc_w;
+				dpstate->right_crtc_w -= half_hdisplay;
+
+				dpstate->right_src_w = dpstate->right_crtc_w;
+			} else if (need_right) {
+				dpstate->right_crtc_w = plane_state->crtc_w;
+				dpstate->right_src_w = plane_state->src_w >> 16;
+			} else {
+				dpstate->right_crtc_w = 0;
+				dpstate->right_src_w = 0;
+			}
+
+			if (fb->format->num_planes > 1) {
+				active_plane_fetcheco[grp_id]++;
+				if (need_aux_source)
+					active_plane_fetcheco[grp_id]++;
+			}
+
+			if (plane_state->src_w >> 16 != plane_state->crtc_w) {
+				if (use_pc_per_crtc)
+					return -EINVAL;
+
+				active_plane_hscale[grp_id]++;
+			}
+
+			if (plane_state->src_h >> 16 != plane_state->crtc_h) {
+				if (use_pc_per_crtc)
+					return -EINVAL;
+
+				active_plane_vscale[grp_id]++;
+			}
+
+			if (grp[grp_id] == NULL)
+				grp[grp_id] = dpu_plane->grp;
+
+			dpstate->need_aux_source = need_aux_source;
+		}
+	}
+
+	/* enough resources? */
+	for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+		if (!grp[i])
+			continue;
+
+		if (active_plane[i] > grp[i]->hw_plane_num) {
+			DRM_DEBUG_KMS("no enough fetch units\n");
+			return -EINVAL;
+		}
+
+		if (active_plane_fetcheco[i] > grp[i]->hw_plane_fetcheco_num) {
+			DRM_DEBUG_KMS("no enough FetchEcos\n");
+			return -EINVAL;
+		}
+
+		if (active_plane_hscale[i] > grp[i]->hw_plane_hscaler_num) {
+			DRM_DEBUG_KMS("no enough Hscalers\n");
+			return -EINVAL;
+		}
+
+		if (active_plane_vscale[i] > grp[i]->hw_plane_vscaler_num) {
+			DRM_DEBUG_KMS("no enough Vscalers\n");
+			return -EINVAL;
+		}
+	}
+
+	/* initialize resource mask */
+	for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+		if (!grp[i])
+			continue;
+
+		mutex_lock(&grp[i]->mutex);
+		grp[i]->src_a_mask = grp[i]->src_mask;
+		grp[i]->src_use_vproc_mask = 0;
+		mutex_unlock(&grp[i]->mutex);
+	}
+
+	ret = drm_atomic_normalize_zpos(dev, state);
+	if (ret)
+		return ret;
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+		struct drm_plane_state **states;
+		int n;
+
+		states = dpu_atomic_alloc_tmp_planes_per_crtc(dev);
+		if (IS_ERR(states)) {
+			DRM_DEBUG_KMS(
+				"[CRTC:%d:%s] cannot alloc plane state ptrs\n",
+					crtc->base.id, crtc->name);
+			return PTR_ERR(states);
+		}
+
+		n = dpu_atomic_sort_planes_per_crtc(crtc_state, states);
+		if (n < 0) {
+			DRM_DEBUG_KMS("[CRTC:%d:%s] failed to sort planes\n",
+					crtc->base.id, crtc->name);
+			kfree(states);
+			return n;
+		}
+
+		/* no active planes? */
+		if (n == 0) {
+			kfree(states);
+			continue;
+		}
+
+		if (use_pc[dpu_crtc->crtc_grp_id])
+			dpu_atomic_compute_plane_lrx_per_crtc(crtc_state,
+								states, n);
+
+		dpu_atomic_set_top_plane_per_crtc(states, n,
+					use_pc[dpu_crtc->crtc_grp_id]);
+
+		ret = dpu_atomic_assign_plane_source_per_crtc(states, n,
+						use_pc[dpu_crtc->crtc_grp_id]);
+		if (ret) {
+			DRM_DEBUG_KMS("[CRTC:%d:%s] cannot assign plane rscs\n",
+					crtc->base.id, crtc->name);
+			kfree(states);
+			return ret;
+		}
+
+		kfree(states);
+	}
+
+	drm_for_each_crtc(crtc, dev) {
+		if (pipe_states_prone_to_put[drm_crtc_index(crtc)]) {
+			crtc_state = drm_atomic_get_crtc_state(state, crtc);
+			if (WARN_ON(IS_ERR(crtc_state)))
+				return PTR_ERR(crtc_state);
+
+			dpu_atomic_put_possible_states_per_crtc(crtc_state);
+		}
+	}
+
+	ret = drm_atomic_helper_check_planes(dev, state);
+	if (ret) {
+		DRM_DEBUG_KMS("%s: failed to check planes\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+const struct drm_mode_config_funcs dpu_drm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create,
+	.atomic_check = dpu_drm_atomic_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-kms.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _DPU_KMS_H_
+#define _DPU_KMS_H_
+
+extern const struct drm_mode_config_funcs dpu_drm_mode_config_funcs;
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-plane.c
@@ -0,0 +1,1010 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_color_mgmt.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <video/dpu.h>
+#include <video/imx8-prefetch.h>
+#include "dpu-plane.h"
+#include "../imx-drm.h"
+
+#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
+
+static const uint32_t dpu_formats[] = {
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_RGB565,
+
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+};
+
+static const uint64_t dpu_format_modifiers[] = {
+	DRM_FORMAT_MOD_VIVANTE_TILED,
+	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+	DRM_FORMAT_MOD_AMPHION_TILED,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static unsigned int dpu_plane_get_default_zpos(enum drm_plane_type type)
+{
+	if (type == DRM_PLANE_TYPE_PRIMARY)
+		return 0;
+	else if (type == DRM_PLANE_TYPE_OVERLAY)
+		return 1;
+
+	return 0;
+}
+
+static void dpu_plane_destroy(struct drm_plane *plane)
+{
+	struct dpu_plane *dpu_plane = to_dpu_plane(plane);
+
+	drm_plane_cleanup(plane);
+	kfree(dpu_plane);
+}
+
+static void dpu_plane_reset(struct drm_plane *plane)
+{
+	struct dpu_plane_state *state;
+
+	if (plane->state) {
+		__drm_atomic_helper_plane_destroy_state(plane->state);
+		kfree(to_dpu_plane_state(plane->state));
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	__drm_atomic_helper_plane_reset(plane, &state->base);
+
+	plane->state->zpos = dpu_plane_get_default_zpos(plane->type);
+	plane->state->color_encoding = DRM_COLOR_YCBCR_BT601;
+	plane->state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
+}
+
+static struct drm_plane_state *
+dpu_drm_atomic_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct dpu_plane_state *state, *copy;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	copy = kmalloc(sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+	state = to_dpu_plane_state(plane->state);
+	copy->stage = state->stage;
+	copy->source = state->source;
+	copy->blend = state->blend;
+	copy->aux_stage = state->aux_stage;
+	copy->aux_source = state->aux_source;
+	copy->aux_blend = state->aux_blend;
+	copy->is_top = state->is_top;
+	copy->use_prefetch = state->use_prefetch;
+	copy->use_aux_prefetch = state->use_aux_prefetch;
+	copy->need_aux_source = state->need_aux_source;
+	copy->left_src_w = state->left_src_w;
+	copy->left_crtc_w = state->left_crtc_w;
+	copy->left_crtc_x = state->left_crtc_x;
+	copy->right_src_w = state->right_src_w;
+	copy->right_crtc_w = state->right_crtc_w;
+	copy->right_crtc_x = state->right_crtc_x;
+	copy->is_left_top = state->is_left_top;
+	copy->is_right_top = state->is_right_top;
+
+	return &copy->base;
+}
+
+static bool dpu_drm_plane_format_mod_supported(struct drm_plane *plane,
+					       uint32_t format,
+					       uint64_t modifier)
+{
+	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+		return false;
+
+	switch (format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		return modifier == DRM_FORMAT_MOD_LINEAR;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_RGB565:
+		return modifier == DRM_FORMAT_MOD_LINEAR ||
+		       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+		       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		return modifier == DRM_FORMAT_MOD_LINEAR ||
+		       modifier == DRM_FORMAT_MOD_AMPHION_TILED;
+	default:
+		return false;
+	}
+}
+
+static void dpu_drm_atomic_plane_destroy_state(struct drm_plane *plane,
+					       struct drm_plane_state *state)
+{
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(to_dpu_plane_state(state));
+}
+
+static const struct drm_plane_funcs dpu_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy	= dpu_plane_destroy,
+	.reset		= dpu_plane_reset,
+	.atomic_duplicate_state	= dpu_drm_atomic_plane_duplicate_state,
+	.atomic_destroy_state	= dpu_drm_atomic_plane_destroy_state,
+	.format_mod_supported	= dpu_drm_plane_format_mod_supported,
+};
+
+static inline dma_addr_t
+drm_plane_state_to_baseaddr(struct drm_plane_state *state, bool aux_source)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+	unsigned int x = (state->src.x1 >> 16) +
+				(aux_source ? dpstate->left_src_w : 0);
+	unsigned int y = state->src.y1 >> 16;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	BUG_ON(!cma_obj);
+
+	if (fb->modifier)
+		return cma_obj->paddr + fb->offsets[0];
+
+	if (fb->flags & DRM_MODE_FB_INTERLACED)
+		y /= 2;
+
+	return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
+	       fb->format->cpp[0] * x;
+}
+
+static inline dma_addr_t
+drm_plane_state_to_uvbaseaddr(struct drm_plane_state *state, bool aux_source)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+	int x = (state->src.x1 >> 16) + (aux_source ? dpstate->left_src_w : 0);
+	int y = state->src.y1 >> 16;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
+	BUG_ON(!cma_obj);
+
+	if (fb->modifier)
+		return cma_obj->paddr + fb->offsets[1];
+
+	x /= fb->format->hsub;
+	y /= fb->format->vsub;
+
+	if (fb->flags & DRM_MODE_FB_INTERLACED)
+		y /= 2;
+
+	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
+	       fb->format->cpp[1] * x;
+}
+
+static inline bool dpu_plane_fb_format_is_yuv(u32 fmt)
+{
+	return fmt == DRM_FORMAT_YUYV || fmt == DRM_FORMAT_UYVY ||
+	       fmt == DRM_FORMAT_NV12 || fmt == DRM_FORMAT_NV21;
+}
+
+static int dpu_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct dpu_plane *dplane = to_dpu_plane(plane);
+	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct drm_crtc_state *crtc_state;
+	struct drm_framebuffer *fb = state->fb;
+	struct dpu_fetchunit *fu;
+	struct dprc *dprc;
+	dma_addr_t baseaddr, uv_baseaddr = 0;
+	u32 src_w, src_h, src_x, src_y;
+	unsigned int frame_width;
+	int min_scale, bpp, ret;
+	bool fb_is_interlaced;
+	bool check_aux_source = false;
+
+	/* ok to disable */
+	if (!fb) {
+		dpstate->stage = LB_PRIM_SEL__DISABLE;
+		dpstate->source = LB_SEC_SEL__DISABLE;
+		dpstate->blend = ID_NONE;
+		dpstate->aux_stage = LB_PRIM_SEL__DISABLE;
+		dpstate->aux_source = LB_SEC_SEL__DISABLE;
+		dpstate->aux_blend = ID_NONE;
+		dpstate->is_top = false;
+		dpstate->use_prefetch = false;
+		dpstate->use_aux_prefetch = false;
+		dpstate->need_aux_source = false;
+		dpstate->left_src_w = 0;
+		dpstate->left_crtc_w = 0;
+		dpstate->left_crtc_x = 0;
+		dpstate->right_src_w = 0;
+		dpstate->right_crtc_w = 0;
+		dpstate->right_crtc_x = 0;
+		dpstate->is_left_top = false;
+		dpstate->is_right_top = false;
+		return 0;
+	}
+
+	if (!state->crtc) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] has no CRTC in plane state\n",
+				plane->base.id, plane->name);
+		return -EINVAL;
+	}
+
+	src_w = drm_rect_width(&state->src) >> 16;
+	src_h = drm_rect_height(&state->src) >> 16;
+	src_x = state->src.x1 >> 16;
+	src_y = state->src.y1 >> 16;
+
+	fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
+
+	if (fb->modifier &&
+	    fb->modifier != DRM_FORMAT_MOD_AMPHION_TILED &&
+	    fb->modifier != DRM_FORMAT_MOD_VIVANTE_TILED &&
+	    fb->modifier != DRM_FORMAT_MOD_VIVANTE_SUPER_TILED) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] unsupported fb modifier\n",
+				plane->base.id, plane->name);
+		return -EINVAL;
+	}
+
+	crtc_state =
+		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+	if (WARN_ON(!crtc_state))
+		return -EINVAL;
+
+	min_scale = dplane->grp->has_vproc ?
+				FRAC_16_16(min(src_w, src_h), 8192) :
+				DRM_PLANE_HELPER_NO_SCALING;
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+						  min_scale,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  true, false);
+	if (ret) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] failed to check plane state\n",
+				plane->base.id, plane->name);
+		return ret;
+	}
+
+	/* no off screen */
+	if (state->dst.x1 < 0 || state->dst.y1 < 0 ||
+	    (state->dst.x2 > crtc_state->adjusted_mode.hdisplay) ||
+	    (state->dst.y2 > crtc_state->adjusted_mode.vdisplay)) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] no off screen\n",
+				plane->base.id, plane->name);
+		return -EINVAL;
+	}
+
+	/* pixel/line count and position parameters check */
+	if (fb->format->hsub == 2) {
+		if (dpstate->left_src_w || dpstate->right_src_w) {
+			if ((dpstate->left_src_w % 2) ||
+			    (dpstate->right_src_w % 2) || (src_x % 2)) {
+				DRM_DEBUG_KMS("[PLANE:%d:%s] bad left/right uv width or xoffset\n",
+						plane->base.id, plane->name);
+				return -EINVAL;
+			}
+		} else {
+			if ((src_w % 2) || (src_x % 2)) {
+				DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv width or xoffset\n",
+						plane->base.id, plane->name);
+				return -EINVAL;
+			}
+		}
+	}
+	if (fb->format->vsub == 2) {
+		if (src_h % (fb_is_interlaced ? 4 : 2)) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv height\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		if (src_y % (fb_is_interlaced ? 4 : 2)) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv yoffset\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+	}
+
+	/* for tile formats, framebuffer has to be tile aligned */
+	switch (fb->modifier) {
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		if (fb->width % 8) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb width for AMPHION tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		if (fb->height % 256) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb height for AMPHION tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+		if (fb->width % 4) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb width for VIVANTE tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		if (fb->height % 4) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb height for VIVANTE tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		if (fb->width % 64) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb width for VIVANTE super tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		if (fb->height % 64) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad fb height for VIVANTE super tile\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* do not support BT709 full range */
+	if (dpu_plane_fb_format_is_yuv(fb->format->format) &&
+	    state->color_encoding == DRM_COLOR_YCBCR_BT709 &&
+	    state->color_range == DRM_COLOR_YCBCR_FULL_RANGE)
+		return -EINVAL;
+
+again:
+	fu = source_to_fu(res,
+		check_aux_source ? dpstate->aux_source : dpstate->source);
+	if (!fu) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] cannot get fetch unit\n",
+				plane->base.id, plane->name);
+		return -EINVAL;
+	}
+
+	dprc = fu->dprc;
+
+	if (dpstate->need_aux_source)
+		frame_width = check_aux_source ?
+				dpstate->right_src_w : dpstate->left_src_w;
+	else
+		frame_width = src_w;
+
+	if (dprc &&
+	    dprc_format_supported(dprc, fb->format->format, fb->modifier) &&
+	    dprc_stride_supported(dprc, fb->pitches[0], fb->pitches[1],
+				  frame_width, fb->format->format)) {
+		if (check_aux_source)
+			dpstate->use_aux_prefetch = true;
+		else
+			dpstate->use_prefetch = true;
+	} else {
+		if (check_aux_source)
+			dpstate->use_aux_prefetch = false;
+		else
+			dpstate->use_prefetch = false;
+	}
+
+	if (fb->modifier) {
+		if (check_aux_source && !dpstate->use_aux_prefetch) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] cannot do tile resolving wo prefetch\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		} else if (!check_aux_source && !dpstate->use_prefetch) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] cannot do tile resolving wo prefetch\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+	}
+
+	/* base address alignment check */
+	baseaddr = drm_plane_state_to_baseaddr(state, check_aux_source);
+	switch (fb->format->format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		bpp = 16;
+		break;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		bpp = 8;
+		break;
+	default:
+		bpp = fb->format->cpp[0] * 8;
+		break;
+	}
+	switch (bpp) {
+	case 32:
+		if (baseaddr & 0x3) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] 32bpp fb bad baddr alignment\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+		break;
+	case 16:
+		if (fb->modifier) {
+			if (baseaddr & 0x1) {
+				DRM_DEBUG_KMS("[PLANE:%d:%s] 16bpp tile fb bad baddr alignment\n",
+						plane->base.id, plane->name);
+				return -EINVAL;
+			}
+		} else {
+			if (check_aux_source) {
+				if (baseaddr &
+				    (dpstate->use_aux_prefetch ? 0x7 : 0x1)) {
+					DRM_DEBUG_KMS("[PLANE:%d:%s] 16bpp fb bad baddr alignment\n",
+							plane->base.id, plane->name);
+					return -EINVAL;
+				}
+			} else {
+				if (baseaddr &
+				    (dpstate->use_prefetch ? 0x7 : 0x1)) {
+					DRM_DEBUG_KMS("[PLANE:%d:%s] 16bpp fb bad baddr alignment\n",
+							plane->base.id, plane->name);
+					return -EINVAL;
+				}
+			}
+		}
+		break;
+	}
+
+	if (fb->pitches[0] > 0x10000) {
+		DRM_DEBUG_KMS("[PLANE:%d:%s] fb pitch[0] is too big\n",
+				plane->base.id, plane->name);
+		return -EINVAL;
+	}
+
+	/* UV base address alignment check, assuming 16bpp */
+	if (fb->format->num_planes > 1) {
+		uv_baseaddr = drm_plane_state_to_uvbaseaddr(state,
+							check_aux_source);
+		if (fb->modifier) {
+			if (uv_baseaddr & 0x1) {
+				DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv baddr alignment for tile fb\n",
+						plane->base.id, plane->name);
+				return -EINVAL;
+			}
+		} else {
+			if (check_aux_source) {
+				if (uv_baseaddr &
+				    (dpstate->use_aux_prefetch ? 0x7 : 0x1)) {
+					DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv baddr alignment\n",
+							plane->base.id, plane->name);
+					return -EINVAL;
+				}
+			} else {
+				if (uv_baseaddr &
+				    (dpstate->use_prefetch ? 0x7 : 0x1)) {
+					DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv baddr alignment\n",
+							plane->base.id, plane->name);
+					return -EINVAL;
+				}
+			}
+		}
+
+		if (fb->pitches[1] > 0x10000) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] fb pitch[1] is too big\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+	}
+
+	if (!check_aux_source && dpstate->use_prefetch &&
+	    !dprc_stride_double_check(dprc, frame_width, src_x,
+					fb->format->format,
+					fb->modifier,
+					baseaddr, uv_baseaddr)) {
+		if (fb->modifier) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad pitch\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		if (bpp == 16 && (baseaddr & 0x1)) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad baddr alignment\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		if (uv_baseaddr & 0x1) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv baddr alignment\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		dpstate->use_prefetch = false;
+	} else if (check_aux_source && dpstate->use_aux_prefetch &&
+		   !dprc_stride_double_check(dprc, frame_width, src_x,
+					fb->format->format,
+					fb->modifier,
+					baseaddr, uv_baseaddr)) {
+		if (fb->modifier) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad pitch\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		if (bpp == 16 && (baseaddr & 0x1)) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad baddr alignment\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		if (uv_baseaddr & 0x1) {
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bad uv baddr alignment\n",
+					plane->base.id, plane->name);
+			return -EINVAL;
+		}
+
+		dpstate->use_aux_prefetch = false;
+	}
+
+	if (dpstate->need_aux_source && !check_aux_source) {
+		check_aux_source = true;
+		goto again;
+	}
+
+	return 0;
+}
+
+static void dpu_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct dpu_plane *dplane = to_dpu_plane(plane);
+	struct drm_plane_state *state = plane->state;
+	struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+	struct drm_framebuffer *fb = state->fb;
+	struct dpu_plane_res *res = &dplane->grp->res;
+	struct dpu_fetchunit *fu;
+	struct dpu_fetchunit *fe = NULL;
+	struct dprc *dprc;
+	struct dpu_hscaler *hs = NULL;
+	struct dpu_vscaler *vs = NULL;
+	struct dpu_layerblend *lb;
+	struct dpu_extdst *ed;
+	struct dpu_framegen *fg;
+	dma_addr_t baseaddr, uv_baseaddr = 0;
+	dpu_block_id_t blend, fe_id, vs_id = ID_NONE, hs_id;
+	lb_sec_sel_t source;
+	lb_prim_sel_t stage;
+	unsigned int stream_id;
+	unsigned int src_w, src_h, src_x, src_y, dst_w, dst_h;
+	unsigned int crtc_x;
+	unsigned int mt_w = 0, mt_h = 0;	/* w/h in a micro-tile */
+	int bpp, lb_id;
+	bool need_fetcheco, need_hscaler = false, need_vscaler = false;
+	bool prefetch_start, uv_prefetch_start;
+	bool crtc_use_pc = dpstate->left_src_w || dpstate->right_src_w;
+	bool update_aux_source = false;
+	bool use_prefetch;
+	bool need_modeset;
+	bool fb_is_interlaced;
+
+	/*
+	 * Do nothing since the plane is disabled by
+	 * crtc_func->atomic_begin/flush.
+	 */
+	if (!fb)
+		return;
+
+	need_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state);
+	fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
+
+again:
+	need_fetcheco = false;
+	prefetch_start = false;
+	uv_prefetch_start = false;
+
+	source = update_aux_source ? dpstate->aux_source : dpstate->source;
+	blend = update_aux_source ? dpstate->aux_blend : dpstate->blend;
+	stage = update_aux_source ? dpstate->aux_stage : dpstate->stage;
+	use_prefetch = update_aux_source ?
+			dpstate->use_aux_prefetch : dpstate->use_prefetch;
+
+	if (crtc_use_pc) {
+		if (update_aux_source) {
+			stream_id = 1;
+			crtc_x = dpstate->right_crtc_x;
+		} else {
+			stream_id = dpstate->left_src_w ? 0 : 1;
+			crtc_x = dpstate->left_src_w ?
+				 dpstate->left_crtc_x : dpstate->right_crtc_x;
+		}
+	} else {
+		stream_id = dplane->stream_id;
+		crtc_x = state->crtc_x;
+	}
+
+	fg = res->fg[stream_id];
+
+	fu = source_to_fu(res, source);
+	if (!fu)
+		return;
+
+	dprc = fu->dprc;
+
+	lb_id = blend_to_id(blend);
+	if (lb_id < 0)
+		return;
+
+	lb = res->lb[lb_id];
+
+	if (crtc_use_pc) {
+		if (update_aux_source || !dpstate->left_src_w)
+			src_w = dpstate->right_src_w;
+		else
+			src_w = dpstate->left_src_w;
+	} else {
+		src_w = drm_rect_width(&state->src) >> 16;
+	}
+	src_h = drm_rect_height(&state->src) >> 16;
+	if (crtc_use_pc && update_aux_source) {
+		if (fb->modifier)
+			src_x = (state->src_x >> 16) + dpstate->left_src_w;
+		else
+			src_x = 0;
+	} else {
+		src_x = fb->modifier ? (state->src_x >> 16) : 0;
+	}
+	src_y = fb->modifier ? (state->src_y >> 16) : 0;
+	dst_w = drm_rect_width(&state->dst);
+	dst_h = drm_rect_height(&state->dst);
+
+	if (fetchunit_is_fetchdecode(fu)) {
+		if (fetchdecode_need_fetcheco(fu, fb->format->format)) {
+			need_fetcheco = true;
+			fe = fetchdecode_get_fetcheco(fu);
+			if (IS_ERR(fe))
+				return;
+		}
+
+		/* assume pixel combiner is unused */
+		if ((src_w != dst_w) && !crtc_use_pc) {
+			need_hscaler = true;
+			hs = fetchdecode_get_hscaler(fu);
+			if (IS_ERR(hs))
+				return;
+		}
+
+		if ((src_h != dst_h) || fb_is_interlaced) {
+			need_vscaler = true;
+			vs = fetchdecode_get_vscaler(fu);
+			if (IS_ERR(vs))
+				return;
+		}
+	}
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		bpp = 16;
+		break;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		bpp = 8;
+		break;
+	default:
+		bpp = fb->format->cpp[0] * 8;
+		break;
+	}
+
+	switch (fb->modifier) {
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		mt_w = 8;
+		mt_h = 8;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		mt_w = (bpp == 16) ? 8 : 4;
+		mt_h = 4;
+		break;
+	default:
+		break;
+	}
+
+	baseaddr = drm_plane_state_to_baseaddr(state, update_aux_source);
+	if (need_fetcheco)
+		uv_baseaddr = drm_plane_state_to_uvbaseaddr(state,
+							update_aux_source);
+
+	if (use_prefetch &&
+	    (fu->ops->get_stream_id(fu) == DPU_PLANE_SRC_DISABLED ||
+	     need_modeset))
+		prefetch_start = true;
+
+	fu->ops->set_burstlength(fu, src_x, mt_w, bpp, baseaddr, use_prefetch);
+	fu->ops->set_src_bpp(fu, bpp);
+	fu->ops->set_src_stride(fu, src_w, src_w, mt_w, bpp, fb->pitches[0],
+				baseaddr, use_prefetch);
+	fu->ops->set_src_buf_dimensions(fu, src_w, src_h, 0, fb_is_interlaced);
+	fu->ops->set_pixel_blend_mode(fu, state->pixel_blend_mode,
+					state->alpha, fb->format->format);
+	fu->ops->set_fmt(fu, fb->format->format, state->color_encoding,
+					state->color_range, fb_is_interlaced);
+	fu->ops->enable_src_buf(fu);
+	fu->ops->set_framedimensions(fu, src_w, src_h, fb_is_interlaced);
+	fu->ops->set_baseaddress(fu, src_w, src_x, src_y, mt_w, mt_h, bpp,
+				 baseaddr);
+	fu->ops->set_stream_id(fu, stream_id ?
+					DPU_PLANE_SRC_TO_DISP_STREAM1 :
+					DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+	DRM_DEBUG_KMS("[PLANE:%d:%s] %s-0x%02x\n",
+				plane->base.id, plane->name, fu->name, fu->id);
+
+	if (need_fetcheco) {
+		fe_id = fetcheco_get_block_id(fe);
+		if (fe_id == ID_NONE)
+			return;
+
+		if (use_prefetch &&
+		    (fe->ops->get_stream_id(fe) == DPU_PLANE_SRC_DISABLED ||
+		     need_modeset))
+			uv_prefetch_start = true;
+
+		fetchdecode_pixengcfg_dynamic_src_sel(fu,
+						(fd_dynamic_src_sel_t)fe_id);
+		fe->ops->set_burstlength(fe, src_w, mt_w, bpp, uv_baseaddr,
+					 use_prefetch);
+		fe->ops->set_src_bpp(fe, 16);
+		fe->ops->set_src_stride(fe, src_w, src_x, mt_w, bpp,
+					fb->pitches[1],
+					uv_baseaddr, use_prefetch);
+		fe->ops->set_fmt(fe, fb->format->format, state->color_encoding,
+					state->color_range, fb_is_interlaced);
+		fe->ops->set_src_buf_dimensions(fe, src_w, src_h,
+						fb->format->format,
+						fb_is_interlaced);
+		fe->ops->set_framedimensions(fe, src_w, src_h,
+						fb_is_interlaced);
+		fe->ops->set_baseaddress(fe, src_w, src_x, src_y / 2,
+					 mt_w, mt_h, bpp, uv_baseaddr);
+		fe->ops->enable_src_buf(fe);
+		fe->ops->set_stream_id(fe, stream_id ?
+					DPU_PLANE_SRC_TO_DISP_STREAM1 :
+					DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+		DRM_DEBUG_KMS("[PLANE:%d:%s] %s-0x%02x\n",
+				plane->base.id, plane->name, fe->name, fe_id);
+	} else {
+		if (fetchunit_is_fetchdecode(fu))
+			fetchdecode_pixengcfg_dynamic_src_sel(fu,
+								FD_SRC_DISABLE);
+	}
+
+	/* vscaler comes first */
+	if (need_vscaler) {
+		vs_id = vscaler_get_block_id(vs);
+		if (vs_id == ID_NONE)
+			return;
+
+		vscaler_pixengcfg_dynamic_src_sel(vs, (vs_src_sel_t)source);
+		vscaler_pixengcfg_clken(vs, CLKEN__AUTOMATIC);
+		vscaler_setup1(vs, src_h, state->crtc_h, fb_is_interlaced);
+		vscaler_setup2(vs, fb_is_interlaced);
+		vscaler_setup3(vs, fb_is_interlaced);
+		vscaler_output_size(vs, dst_h);
+		vscaler_field_mode(vs, fb_is_interlaced ?
+						SCALER_ALWAYS0 : SCALER_INPUT);
+		vscaler_filter_mode(vs, SCALER_LINEAR);
+		vscaler_scale_mode(vs, SCALER_UPSCALE);
+		vscaler_mode(vs, SCALER_ACTIVE);
+		vscaler_set_stream_id(vs, dplane->stream_id ?
+					DPU_PLANE_SRC_TO_DISP_STREAM1 :
+					DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+		source = (lb_sec_sel_t)vs_id;
+
+		DRM_DEBUG_KMS("[PLANE:%d:%s] vscaler-0x%02x\n",
+					plane->base.id, plane->name, vs_id);
+	}
+
+	/* and then, hscaler */
+	if (need_hscaler) {
+		hs_id = hscaler_get_block_id(hs);
+		if (hs_id == ID_NONE)
+			return;
+
+		hscaler_pixengcfg_dynamic_src_sel(hs, need_vscaler ?
+							(hs_src_sel_t)vs_id :
+							(hs_src_sel_t)source);
+		hscaler_pixengcfg_clken(hs, CLKEN__AUTOMATIC);
+		hscaler_setup1(hs, src_w, dst_w);
+		hscaler_output_size(hs, dst_w);
+		hscaler_filter_mode(hs, SCALER_LINEAR);
+		hscaler_scale_mode(hs, SCALER_UPSCALE);
+		hscaler_mode(hs, SCALER_ACTIVE);
+		hscaler_set_stream_id(hs, dplane->stream_id ?
+					DPU_PLANE_SRC_TO_DISP_STREAM1 :
+					DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+		source = (lb_sec_sel_t)hs_id;
+
+		DRM_DEBUG_KMS("[PLANE:%d:%s] hscaler-0x%02x\n",
+					plane->base.id, plane->name, hs_id);
+	}
+
+	if (use_prefetch) {
+		dprc_configure(dprc, stream_id,
+			       src_w, src_h, src_x, src_y,
+			       fb->pitches[0], fb->format->format,
+			       fb->modifier, baseaddr, uv_baseaddr,
+			       prefetch_start, uv_prefetch_start,
+			       fb_is_interlaced);
+
+		dprc_enable(dprc);
+
+		dprc_reg_update(dprc);
+
+		if (prefetch_start || uv_prefetch_start) {
+			dprc_first_frame_handle(dprc);
+
+			if (!need_modeset && state->normalized_zpos != 0)
+				framegen_wait_for_frame_counter_moving(fg);
+		}
+
+		if (update_aux_source)
+			DRM_DEBUG_KMS("[PLANE:%d:%s] use aux prefetch\n",
+						plane->base.id, plane->name);
+		else
+			DRM_DEBUG_KMS("[PLANE:%d:%s] use prefetch\n",
+						plane->base.id, plane->name);
+	} else if (dprc) {
+		dprc_disable(dprc);
+
+		if (update_aux_source)
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bypass aux prefetch\n",
+						plane->base.id, plane->name);
+		else
+			DRM_DEBUG_KMS("[PLANE:%d:%s] bypass prefetch\n",
+						plane->base.id, plane->name);
+	}
+
+	layerblend_pixengcfg_dynamic_prim_sel(lb, stage);
+	layerblend_pixengcfg_dynamic_sec_sel(lb, source);
+	layerblend_control(lb, LB_BLEND);
+	layerblend_blendcontrol(lb, state->normalized_zpos,
+				state->pixel_blend_mode, state->alpha);
+	layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
+	layerblend_position(lb, crtc_x, state->crtc_y);
+
+	if (crtc_use_pc) {
+		if ((!stream_id && dpstate->is_left_top) ||
+		     (stream_id && dpstate->is_right_top)) {
+			ed = res->ed[stream_id];
+			extdst_pixengcfg_src_sel(ed, (extdst_src_sel_t)blend);
+		}
+	} else {
+		if (dpstate->is_top) {
+			ed = res->ed[stream_id];
+			extdst_pixengcfg_src_sel(ed, (extdst_src_sel_t)blend);
+		}
+	}
+
+	if (update_aux_source)
+		DRM_DEBUG_KMS("[PLANE:%d:%s] *aux* source-0x%02x stage-0x%02x blend-0x%02x\n",
+				plane->base.id, plane->name,
+				source, dpstate->stage, dpstate->blend);
+	else
+		DRM_DEBUG_KMS("[PLANE:%d:%s] source-0x%02x stage-0x%02x blend-0x%02x\n",
+				plane->base.id, plane->name,
+				source, dpstate->stage, dpstate->blend);
+
+	if (dpstate->need_aux_source && !update_aux_source) {
+		update_aux_source = true;
+		goto again;
+	}
+}
+
+static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
+	.prepare_fb = drm_gem_fb_prepare_fb,
+	.atomic_check = dpu_plane_atomic_check,
+	.atomic_update = dpu_plane_atomic_update,
+};
+
+struct dpu_plane *dpu_plane_create(struct drm_device *drm,
+				   unsigned int possible_crtcs,
+				   unsigned int stream_id,
+				   struct dpu_plane_grp *grp,
+				   enum drm_plane_type type)
+{
+	struct dpu_plane *dpu_plane;
+	struct drm_plane *plane;
+	unsigned int zpos = dpu_plane_get_default_zpos(type);
+	int ret;
+
+	dpu_plane = kzalloc(sizeof(*dpu_plane), GFP_KERNEL);
+	if (!dpu_plane)
+		return ERR_PTR(-ENOMEM);
+
+	dpu_plane->stream_id = stream_id;
+	dpu_plane->grp = grp;
+
+	plane = &dpu_plane->base;
+
+	ret = drm_universal_plane_init(drm, plane, possible_crtcs,
+				       &dpu_plane_funcs,
+				       dpu_formats, ARRAY_SIZE(dpu_formats),
+				       dpu_format_modifiers, type, NULL);
+	if (ret)
+		goto err;
+
+	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
+
+	ret = drm_plane_create_zpos_property(plane,
+					     zpos, 0, grp->hw_plane_num - 1);
+	if (ret)
+		goto err;
+
+	ret = drm_plane_create_alpha_property(plane);
+	if (ret)
+		goto err;
+
+	ret = drm_plane_create_blend_mode_property(plane,
+					BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					BIT(DRM_MODE_BLEND_PREMULTI)   |
+					BIT(DRM_MODE_BLEND_COVERAGE));
+	if (ret)
+		goto err;
+
+	ret = drm_plane_create_color_properties(plane,
+					BIT(DRM_COLOR_YCBCR_BT601) |
+					BIT(DRM_COLOR_YCBCR_BT709),
+					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+					DRM_COLOR_YCBCR_BT601,
+					DRM_COLOR_YCBCR_FULL_RANGE);
+	if (ret)
+		goto err;
+
+	return dpu_plane;
+
+err:
+	kfree(dpu_plane);
+	return ERR_PTR(ret);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dpu/dpu-plane.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dpu/dpu-plane.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __DPU_PLANE_H__
+#define __DPU_PLANE_H__
+
+#include <video/dpu.h>
+#include "../imx-drm.h"
+
+#define MAX_DPU_PLANE_GRP	(MAX_CRTC / 2)
+
+enum dpu_plane_src_type {
+	DPU_PLANE_SRC_FL,
+	DPU_PLANE_SRC_FW,
+	DPU_PLANE_SRC_FD,
+};
+
+struct dpu_plane {
+	struct drm_plane	base;
+	struct dpu_plane_grp	*grp;
+	struct list_head	head;
+	unsigned int		stream_id;
+};
+
+struct dpu_plane_state {
+	struct drm_plane_state	base;
+	lb_prim_sel_t		stage;
+	lb_sec_sel_t		source;
+	dpu_block_id_t		blend;
+	lb_prim_sel_t		aux_stage;
+	lb_sec_sel_t		aux_source;
+	dpu_block_id_t		aux_blend;
+
+	bool			is_top;
+	bool			use_prefetch;
+	bool			use_aux_prefetch;
+	bool			need_aux_source;
+
+	/* used when pixel combiner is needed */
+	unsigned int		left_src_w;
+	unsigned int		left_crtc_w;
+	unsigned int		left_crtc_x;
+	unsigned int		right_src_w;
+	unsigned int		right_crtc_w;
+	unsigned int		right_crtc_x;
+
+	bool			is_left_top;
+	bool			is_right_top;
+};
+
+static const lb_prim_sel_t cf_stages[] = {LB_PRIM_SEL__CONSTFRAME0,
+					  LB_PRIM_SEL__CONSTFRAME1};
+static const lb_prim_sel_t stages[] = {LB_PRIM_SEL__LAYERBLEND0,
+				       LB_PRIM_SEL__LAYERBLEND1,
+				       LB_PRIM_SEL__LAYERBLEND2,
+				       LB_PRIM_SEL__LAYERBLEND3};
+/* TODO: Add source entries for subsidiary layers. */
+static const lb_sec_sel_t sources[] = {LB_SEC_SEL__FETCHLAYER0,
+				       LB_SEC_SEL__FETCHWARP2,
+				       LB_SEC_SEL__FETCHDECODE0,
+				       LB_SEC_SEL__FETCHDECODE1};
+static const dpu_block_id_t blends[] = {ID_LAYERBLEND0, ID_LAYERBLEND1,
+					ID_LAYERBLEND2, ID_LAYERBLEND3};
+
+static inline struct dpu_plane *to_dpu_plane(struct drm_plane *plane)
+{
+	return container_of(plane, struct dpu_plane, base);
+}
+
+static inline struct dpu_plane_state *
+to_dpu_plane_state(struct drm_plane_state *plane_state)
+{
+	return container_of(plane_state, struct dpu_plane_state, base);
+}
+
+static inline int source_to_type(lb_sec_sel_t source)
+{
+	switch (source) {
+	case LB_SEC_SEL__FETCHLAYER0:
+		return DPU_PLANE_SRC_FL;
+	case LB_SEC_SEL__FETCHWARP2:
+		return DPU_PLANE_SRC_FW;
+	case LB_SEC_SEL__FETCHDECODE0:
+	case LB_SEC_SEL__FETCHDECODE1:
+		return DPU_PLANE_SRC_FD;
+	default:
+		break;
+	}
+
+	WARN_ON(1);
+	return -EINVAL;
+}
+
+static inline int source_to_id(lb_sec_sel_t source)
+{
+	int i, offset = 0;
+	int type = source_to_type(source);
+
+	for (i = 0; i < ARRAY_SIZE(sources); i++) {
+		if (source != sources[i])
+			continue;
+
+		/* FetchLayer */
+		if (type == DPU_PLANE_SRC_FL)
+			return i;
+
+		/* FetchWarp or FetchDecode */
+		while (offset < ARRAY_SIZE(sources)) {
+			if (source_to_type(sources[offset]) == type)
+				break;
+			offset++;
+		}
+		return i - offset;
+	}
+
+	WARN_ON(1);
+	return -EINVAL;
+}
+
+static inline struct dpu_fetchunit *
+source_to_fu(struct dpu_plane_res *res, lb_sec_sel_t source)
+{
+	int fu_type = source_to_type(source);
+	int fu_id = source_to_id(source);
+
+	if (fu_type < 0 || fu_id < 0)
+		return NULL;
+
+	switch (fu_type) {
+	case DPU_PLANE_SRC_FD:
+		return res->fd[fu_id];
+	case DPU_PLANE_SRC_FL:
+		return res->fl[fu_id];
+	case DPU_PLANE_SRC_FW:
+		return res->fw[fu_id];
+	}
+
+	return NULL;
+}
+
+static inline struct dpu_fetchunit *
+dpstate_to_fu(struct dpu_plane_state *dpstate)
+{
+	struct drm_plane *plane = dpstate->base.plane;
+	struct dpu_plane *dplane = to_dpu_plane(plane);
+	struct dpu_plane_res *res = &dplane->grp->res;
+
+	return source_to_fu(res, dpstate->source);
+}
+
+static inline int blend_to_id(dpu_block_id_t blend)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(blends); i++) {
+		if (blend == blends[i])
+			return i;
+	}
+
+	WARN_ON(1);
+	return -EINVAL;
+}
+
+static inline bool drm_format_is_yuv(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		return true;
+	default:
+		break;
+	}
+
+	return false;
+}
+
+struct dpu_plane *dpu_plane_create(struct drm_device *drm,
+				   unsigned int possible_crtcs,
+				   unsigned int stream_id,
+				   struct dpu_plane_grp *grp,
+				   enum drm_plane_type type);
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -9,7 +9,9 @@
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/phy/phy.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 
 #include <video/imx-ipu-v3.h>
 
@@ -19,13 +21,23 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_of.h>
 
+#include "imx8mp-hdmi-pavi.h"
 #include "imx-drm.h"
 
+/* GPR reg */
+struct imx_hdmi_chip_data {
+	int	reg_offset;
+	u32	mask_bits;
+	u32	shift_bit;
+};
+
 struct imx_hdmi {
 	struct device *dev;
 	struct drm_encoder encoder;
 	struct dw_hdmi *hdmi;
 	struct regmap *regmap;
+	const struct imx_hdmi_chip_data *chip_data;
+	struct phy *phy;
 };
 
 static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
@@ -33,6 +45,19 @@
 	return container_of(e, struct imx_hdmi, encoder);
 }
 
+struct clk_bulk_data imx8mp_clocks[] = {
+	{ .id = "pix_clk"  },
+	{ .id = "phy_int"  },
+	{ .id = "prep_clk" },
+	{ .id = "skp_clk"  },
+	{ .id = "sfr_clk"  },
+	{ .id = "cec_clk"  },
+	{ .id = "apb_clk"  },
+	{ .id = "hpi_clk"  },
+	{ .id = "fdcc_ref" },
+	{ .id = "pipe_clk" },
+};
+
 static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
 	{
 		45250000, {
@@ -91,7 +116,7 @@
  * PREEMP config 0.00
  * TX/CK level 10
  */
-static const struct dw_hdmi_phy_config imx_phy_config[] = {
+static const struct dw_hdmi_phy_config imx6_phy_config[] = {
 	/*pixelclk   symbol   term   vlev */
 	{ 216000000, 0x800d, 0x0005, 0x01ad},
 	{ ~0UL,      0x0000, 0x0000, 0x0000}
@@ -100,6 +125,7 @@
 static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
 {
 	struct device_node *np = hdmi->dev->of_node;
+	int ret;
 
 	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
 	if (IS_ERR(hdmi->regmap)) {
@@ -107,6 +133,14 @@
 		return PTR_ERR(hdmi->regmap);
 	}
 
+	hdmi->phy = devm_phy_optional_get(hdmi->dev, "hdmi");
+	if (IS_ERR(hdmi->phy)) {
+		ret = PTR_ERR(hdmi->phy);
+		if (ret != -EPROBE_DEFER)
+			dev_err(hdmi->dev, "failed to get phy\n");
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -119,9 +153,11 @@
 	struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
 	int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder);
 
-	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
-			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
-			   mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+	if (hdmi->chip_data->reg_offset < 0)
+		return;
+
+	regmap_update_bits(hdmi->regmap, hdmi->chip_data->reg_offset,
+			   hdmi->chip_data->mask_bits, mux << hdmi->chip_data->shift_bit);
 }
 
 static int dw_hdmi_imx_atomic_check(struct drm_encoder *encoder,
@@ -131,6 +167,7 @@
 	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 
 	imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	imx_crtc_state->bus_flags = DRM_BUS_FLAG_DE_HIGH;
 	imx_crtc_state->di_hsync_pin = 2;
 	imx_crtc_state->di_vsync_pin = 3;
 
@@ -173,18 +210,167 @@
 	return MODE_OK;
 }
 
+static bool imx8mp_hdmi_check_clk_rate(int rate_khz)
+{
+	int rate = rate_khz * 1000;
+
+	/* Check hdmi phy pixel clock support rate */
+	if (rate != clk_round_rate(imx8mp_clocks[0].clk, rate))
+		return  false;
+	return true;
+}
+
+static enum drm_mode_status
+imx8mp_hdmi_mode_valid(struct drm_connector *con,
+		       const struct drm_display_mode *mode)
+{
+	if (mode->clock < 13500)
+		return MODE_CLOCK_LOW;
+	if (mode->clock > 297000)
+		return MODE_CLOCK_HIGH;
+
+	if (!imx8mp_hdmi_check_clk_rate(mode->clock))
+		return MODE_CLOCK_RANGE;
+
+	/* We don't support double-clocked and Interlaced modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+struct imx_hdmi_chip_data imx6_chip_data = {
+	.reg_offset = IOMUXC_GPR3,
+	.mask_bits = IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+	.shift_bit = IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT,
+};
+
 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
 	.mpll_cfg   = imx_mpll_cfg,
 	.cur_ctr    = imx_cur_ctr,
-	.phy_config = imx_phy_config,
+	.phy_config = imx6_phy_config,
 	.mode_valid = imx6q_hdmi_mode_valid,
+	.phy_data   = &imx6_chip_data,
 };
 
 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
 	.mpll_cfg = imx_mpll_cfg,
 	.cur_ctr  = imx_cur_ctr,
-	.phy_config = imx_phy_config,
+	.phy_config = imx6_phy_config,
 	.mode_valid = imx6dl_hdmi_mode_valid,
+	.phy_data   = &imx6_chip_data,
+};
+
+static int imx8mp_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,
+			     struct drm_display_mode *mode)
+{
+	struct imx_hdmi *hdmi = (struct imx_hdmi *)data;
+	int val;
+
+	dev_dbg(hdmi->dev, "%s\n", __func__);
+
+	dw_hdmi_phy_reset(dw_hdmi);
+
+	/* enable PVI */
+	imx8mp_hdmi_pavi_powerup();
+	imx8mp_hdmi_pvi_enable(mode);
+
+	regmap_read(hdmi->regmap, 0x200, &val);
+	/* HDMI PHY power off */
+	val |= 0x8;
+	regmap_write(hdmi->regmap, 0x200, val);
+	/* HDMI PHY power on */
+	val &= ~0x8;
+	/* Enable CEC */
+	val |= 0x2;
+	regmap_write(hdmi->regmap, 0x200, val);
+
+	if (!hdmi->phy)
+		return 0;
+
+	phy_power_on(hdmi->phy);
+
+	return 0;
+}
+
+static void imx8mp_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data)
+{
+	struct imx_hdmi *hdmi = (struct imx_hdmi *)data;
+	int val;
+
+	dev_dbg(hdmi->dev, "%s\n", __func__);
+	if (!hdmi->phy)
+		return;
+
+	/* disable PVI */
+	imx8mp_hdmi_pvi_disable();
+	imx8mp_hdmi_pavi_powerdown();
+
+	/* TODO */
+	regmap_read(hdmi->regmap, 0x200, &val);
+	/* Disable CEC */
+	val &= ~0x2;
+	/* Power down HDMI PHY
+	 * TODO move PHY power off to hdmi phy driver
+	 * val |= 0x8;
+	 * regmap_write(hdmi->regmap, 0x200, val);
+	*/
+}
+
+static int imx8mp_hdmimix_setup(struct imx_hdmi *hdmi)
+{
+	int ret;
+
+	if (NULL == imx8mp_hdmi_pavi_init()) {
+		dev_err(hdmi->dev, "No pavi info found\n");
+		return -EPROBE_DEFER;
+	}
+
+	ret = device_reset(hdmi->dev);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+
+	ret = devm_clk_bulk_get(hdmi->dev, ARRAY_SIZE(imx8mp_clocks), imx8mp_clocks);
+	if (ret < 0) {
+		dev_err(hdmi->dev, "No hdmimix bulk clk got\n");
+		return -EPROBE_DEFER;
+	}
+
+	return clk_bulk_prepare_enable(ARRAY_SIZE(imx8mp_clocks), imx8mp_clocks);
+}
+
+void imx8mp_hdmi_enable_audio(struct dw_hdmi *dw_hdmi, void *data, int channel,
+			      int width, int rate, int non_pcm)
+{
+	imx8mp_hdmi_pai_enable(channel, width, rate, non_pcm);
+}
+
+void imx8mp_hdmi_disable_audio(struct dw_hdmi *dw_hdmi, void *data)
+{
+	imx8mp_hdmi_pai_disable();
+}
+
+static const struct dw_hdmi_phy_ops imx8mp_hdmi_phy_ops = {
+	.init		= imx8mp_hdmi_phy_init,
+	.disable	= imx8mp_hdmi_phy_disable,
+	.read_hpd = dw_hdmi_phy_read_hpd,
+	.update_hpd = dw_hdmi_phy_update_hpd,
+	.setup_hpd = dw_hdmi_phy_setup_hpd,
+	.enable_audio	= imx8mp_hdmi_enable_audio,
+	.disable_audio  = imx8mp_hdmi_disable_audio,
+};
+
+struct imx_hdmi_chip_data imx8mp_chip_data = {
+	.reg_offset = -1,
+};
+
+static const struct dw_hdmi_plat_data imx8mp_hdmi_drv_data = {
+	.mode_valid = imx8mp_hdmi_mode_valid,
+	.phy_data   = &imx8mp_chip_data,
+	.phy_ops    = &imx8mp_hdmi_phy_ops,
+	.phy_name   = "samsung_dw_hdmi_phy2",
+	.phy_force_vendor = true,
 };
 
 static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
@@ -193,6 +379,9 @@
 	}, {
 	  .compatible = "fsl,imx6dl-hdmi",
 	  .data = &imx6dl_hdmi_drv_data
+	}, {
+	  .compatible = "fsl,imx8mp-hdmi",
+	  .data = &imx8mp_hdmi_drv_data
 	},
 	{},
 };
@@ -202,7 +391,7 @@
 			    void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	const struct dw_hdmi_plat_data *plat_data;
+	struct dw_hdmi_plat_data *plat_data;
 	const struct of_device_id *match;
 	struct drm_device *drm = data;
 	struct drm_encoder *encoder;
@@ -212,24 +401,26 @@
 	if (!pdev->dev.of_node)
 		return -ENODEV;
 
-	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
-	if (!hdmi)
-		return -ENOMEM;
+	hdmi = dev_get_drvdata(dev);
+	memset(hdmi, 0, sizeof(*hdmi));
 
 	match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
-	plat_data = match->data;
+	if (!match)
+		return -ENODEV;
+
+	plat_data = devm_kmemdup(&pdev->dev, match->data,
+					     sizeof(*plat_data), GFP_KERNEL);
+	if (!plat_data)
+		return -ENOMEM;
+
 	hdmi->dev = &pdev->dev;
 	encoder = &hdmi->encoder;
+	hdmi->chip_data = plat_data->phy_data;
+	plat_data->phy_data = hdmi;
 
-	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-	/*
-	 * If we failed to find the CRTC(s) which this encoder is
-	 * supposed to be connected to, it's because the CRTC has
-	 * not been registered yet.  Defer probing, and hope that
-	 * the required CRTC is added later.
-	 */
-	if (encoder->possible_crtcs == 0)
-		return -EPROBE_DEFER;
+	ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node);
+	if (ret)
+		return ret;
 
 	ret = dw_hdmi_imx_parse_dt(hdmi);
 	if (ret < 0)
@@ -239,7 +430,11 @@
 	drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
 
-	platform_set_drvdata(pdev, hdmi);
+	if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx8mp-hdmi")) {
+		ret = imx8mp_hdmimix_setup(hdmi);
+		if (ret < 0)
+			return ret;
+	}
 
 	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 
@@ -270,6 +465,14 @@
 
 static int dw_hdmi_imx_probe(struct platform_device *pdev)
 {
+	struct imx_hdmi *hdmi;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, hdmi);
+
 	return component_add(&pdev->dev, &dw_hdmi_imx_ops);
 }
 
@@ -280,11 +483,25 @@
 	return 0;
 }
 
+static int __maybe_unused dw_hdmi_imx_resume(struct device *dev)
+{
+	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_resume(hdmi->hdmi);
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_hdmi_imx_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_imx_resume)
+};
+
 static struct platform_driver dw_hdmi_imx_platform_driver = {
 	.probe  = dw_hdmi_imx_probe,
 	.remove = dw_hdmi_imx_remove,
 	.driver = {
 		.name = "dwhdmi-imx",
+		.pm = &dw_hdmi_imx_pm,
 		.of_match_table = dw_hdmi_imx_dt_ids,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx-drm-core.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx-drm-core.c
@@ -12,6 +12,8 @@
 #include <linux/platform_device.h>
 
 #include <video/imx-ipu-v3.h>
+#include <video/imx-lcdif.h>
+#include <video/imx-lcdifv3.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -24,11 +26,9 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
+#include <video/dpu.h>
 
 #include "imx-drm.h"
-#include "ipuv3-plane.h"
-
-#define MAX_CRTC	4
 
 static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
@@ -48,81 +48,6 @@
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
 
-static int imx_drm_atomic_check(struct drm_device *dev,
-				struct drm_atomic_state *state)
-{
-	int ret;
-
-	ret = drm_atomic_helper_check(dev, state);
-	if (ret)
-		return ret;
-
-	/*
-	 * Check modeset again in case crtc_state->mode_changed is
-	 * updated in plane's ->atomic_check callback.
-	 */
-	ret = drm_atomic_helper_check_modeset(dev, state);
-	if (ret)
-		return ret;
-
-	/* Assign PRG/PRE channels and check if all constrains are satisfied. */
-	ret = ipu_planes_assign_pre(dev, state);
-	if (ret)
-		return ret;
-
-	return ret;
-}
-
-static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
-	.fb_create = drm_gem_fb_create,
-	.atomic_check = imx_drm_atomic_check,
-	.atomic_commit = drm_atomic_helper_commit,
-};
-
-static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
-{
-	struct drm_device *dev = state->dev;
-	struct drm_plane *plane;
-	struct drm_plane_state *old_plane_state, *new_plane_state;
-	bool plane_disabling = false;
-	int i;
-
-	drm_atomic_helper_commit_modeset_disables(dev, state);
-
-	drm_atomic_helper_commit_planes(dev, state,
-				DRM_PLANE_COMMIT_ACTIVE_ONLY |
-				DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
-
-	drm_atomic_helper_commit_modeset_enables(dev, state);
-
-	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
-		if (drm_atomic_plane_disabling(old_plane_state, new_plane_state))
-			plane_disabling = true;
-	}
-
-	/*
-	 * The flip done wait is only strictly required by imx-drm if a deferred
-	 * plane disable is in-flight. As the core requires blocking commits
-	 * to wait for the flip it is done here unconditionally. This keeps the
-	 * workitem around a bit longer than required for the majority of
-	 * non-blocking commits, but we accept that for the sake of simplicity.
-	 */
-	drm_atomic_helper_wait_for_flip_done(dev, state);
-
-	if (plane_disabling) {
-		for_each_old_plane_in_state(state, plane, old_plane_state, i)
-			ipu_plane_disable_deferred(plane);
-
-	}
-
-	drm_atomic_helper_commit_hw_done(state);
-}
-
-static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
-	.atomic_commit_tail = imx_drm_atomic_commit_tail,
-};
-
-
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np)
 {
@@ -139,8 +64,8 @@
 
 	encoder->possible_crtcs = crtc_mask;
 
-	/* FIXME: this is the mask of outputs which can clone this output. */
-	encoder->possible_clones = ~0;
+	/* FIXME: cloning support not clear, disable it all for now */
+	encoder->possible_clones = 0;
 
 	return 0;
 }
@@ -183,6 +108,30 @@
 		struct ipu_client_platformdata *pdata = dev->platform_data;
 
 		return pdata->of_node == np;
+	} else if (strcmp(dev->driver->name, "imx-dpu-crtc") == 0) {
+		struct dpu_client_platformdata *pdata = dev->platform_data;
+
+		return pdata->of_node == np;
+	} else if (strcmp(dev->driver->name, "imx-lcdif-crtc") == 0 ||
+		   strcmp(dev->driver->name, "imx-lcdifv3-crtc") == 0) {
+		struct lcdif_client_platformdata *pdata = dev->platform_data;
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
+		/* set legacyfb_depth to be 32 for lcdif, since
+		 * default format of the connectors attached to
+		 * lcdif is usually RGB888
+		 */
+		if (pdata->of_node == np)
+			legacyfb_depth = 32;
+#endif
+
+		return pdata->of_node == np;
+	}
+
+	/* This is a special case for dpu bliteng. */
+	if (strcmp(dev->driver->name, "imx-drm-dpu-bliteng") == 0) {
+		struct dpu_client_platformdata *pdata = dev->platform_data;
+
+		return pdata->of_node == np;
 	}
 
 	/* Special case for LDB, one device for two channels */
@@ -194,11 +143,104 @@
 	return dev->of_node == np;
 }
 
+static const char *const imx_drm_dpu_comp_parents[] = {
+	"fsl,imx8qm-dpu",
+	"fsl,imx8qxp-dpu",
+};
+
+static bool imx_drm_parent_is_compatible(struct device *dev,
+					 const char *const comp_parents[],
+					 int comp_parents_size)
+{
+	struct device_node *port, *parent;
+	bool ret = false;
+	int i;
+
+	port = of_parse_phandle(dev->of_node, "ports", 0);
+	if (!port)
+		return ret;
+
+	parent = of_get_parent(port);
+
+	for (i = 0; i < comp_parents_size; i++) {
+		if (of_device_is_compatible(parent, comp_parents[i])) {
+			ret = true;
+			break;
+		}
+	}
+
+	of_node_put(parent);
+
+	of_node_put(port);
+
+	return ret;
+}
+
+static inline bool has_dpu(struct device *dev)
+{
+	return imx_drm_parent_is_compatible(dev, imx_drm_dpu_comp_parents,
+					ARRAY_SIZE(imx_drm_dpu_comp_parents));
+}
+
+static void add_dpu_bliteng_components(struct device *dev,
+				       struct component_match **matchptr)
+{
+	/*
+	 * As there may be two dpu bliteng device,
+	 * so need add something in compare data to distinguish.
+	 * Use its parent dpu's of_node as the data here.
+	 */
+	struct device_node *port, *parent;
+	/* assume max dpu number is 8 */
+	struct device_node *dpu[8];
+	int num_dpu = 0;
+	int i, j;
+	bool found = false;
+
+	for (i = 0; ; i++) {
+		port = of_parse_phandle(dev->of_node, "ports", i);
+		if (!port)
+			break;
+
+		parent = of_get_parent(port);
+
+		for (j = 0; j < num_dpu; j++) {
+			if (dpu[j] == parent) {
+				found = true;
+				break;
+			}
+		}
+
+		if (found) {
+			found = false;
+		} else {
+			if (num_dpu >= ARRAY_SIZE(dpu)) {
+				dev_err(dev, "The number of found dpu is greater than max [%ld].\n",
+					ARRAY_SIZE(dpu));
+				of_node_put(parent);
+				of_node_put(port);
+				break;
+			}
+
+			dpu[num_dpu] = parent;
+			num_dpu++;
+
+			component_match_add(dev, matchptr, compare_of, parent);
+		}
+
+		of_node_put(parent);
+		of_node_put(port);
+	}
+}
+
 static int imx_drm_bind(struct device *dev)
 {
 	struct drm_device *drm;
 	int ret;
 
+	if (has_dpu(dev))
+		imx_drm_driver.driver_features |= DRIVER_RENDER;
+
 	drm = drm_dev_alloc(&imx_drm_driver, dev);
 	if (IS_ERR(drm))
 		return PTR_ERR(drm);
@@ -223,9 +265,6 @@
 	drm->mode_config.min_height = 1;
 	drm->mode_config.max_width = 4096;
 	drm->mode_config.max_height = 4096;
-	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
-	drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
-	drm->mode_config.allow_fb_modifiers = true;
 	drm->mode_config.normalize_zpos = true;
 
 	drm_mode_config_init(drm);
@@ -234,8 +273,6 @@
 	if (ret)
 		goto err_kms;
 
-	dev_set_drvdata(dev, drm);
-
 	/* Now try and bind all our sub-components */
 	ret = component_bind_all(dev, drm);
 	if (ret)
@@ -261,6 +298,8 @@
 
 	drm_fbdev_generic_setup(drm, legacyfb_depth);
 
+	dev_set_drvdata(dev, drm);
+
 	return 0;
 
 err_poll_fini:
@@ -277,13 +316,17 @@
 {
 	struct drm_device *drm = dev_get_drvdata(dev);
 
+	if (has_dpu(dev))
+		imx_drm_driver.driver_features &= ~DRIVER_RENDER;
+
 	drm_dev_unregister(drm);
 
 	drm_kms_helper_poll_fini(drm);
 
+	component_unbind_all(drm->dev, drm);
+
 	drm_mode_config_cleanup(drm);
 
-	component_unbind_all(drm->dev, drm);
 	dev_set_drvdata(dev, NULL);
 
 	drm_dev_put(drm);
@@ -296,7 +339,14 @@
 
 static int imx_drm_platform_probe(struct platform_device *pdev)
 {
-	int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
+	struct component_match *match = NULL;
+	int ret;
+
+	if (has_dpu(&pdev->dev))
+		add_dpu_bliteng_components(&pdev->dev, &match);
+
+	ret = drm_of_component_probe_with_match(&pdev->dev, match, compare_of,
+						&imx_drm_ops);
 
 	if (!ret)
 		ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
@@ -343,23 +393,7 @@
 		.of_match_table = imx_drm_dt_ids,
 	},
 };
-
-static struct platform_driver * const drivers[] = {
-	&imx_drm_pdrv,
-	&ipu_drm_driver,
-};
-
-static int __init imx_drm_init(void)
-{
-	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
-}
-module_init(imx_drm_init);
-
-static void __exit imx_drm_exit(void)
-{
-	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
-}
-module_exit(imx_drm_exit);
+module_platform_driver(imx_drm_pdrv);
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("i.MX drm driver core");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx-drm.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx-drm.h
@@ -2,6 +2,8 @@
 #ifndef _IMX_DRM_H_
 #define _IMX_DRM_H_
 
+#define MAX_CRTC	4
+
 struct device_node;
 struct drm_crtc;
 struct drm_connector;
@@ -28,8 +30,6 @@
 		int preferred_bpp);
 int imx_drm_exit_drm(void);
 
-extern struct platform_driver ipu_drm_driver;
-
 void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
@@ -40,7 +40,4 @@
 void imx_drm_connector_destroy(struct drm_connector *connector);
 void imx_drm_encoder_destroy(struct drm_encoder *encoder);
 
-int ipu_planes_assign_pre(struct drm_device *dev,
-			  struct drm_atomic_state *state);
-
 #endif /* _IMX_DRM_H_ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx-ldb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx-ldb.c
@@ -7,7 +7,6 @@
 
 #include <linux/clk.h>
 #include <linux/component.h>
-#include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -18,12 +17,11 @@
 #include <video/of_display_timing.h>
 #include <video/of_videomode.h>
 
+#include <drm/bridge/fsl_imx_ldb.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
 #include "imx-drm.h"
@@ -36,34 +34,22 @@
 #define LDB_CH1_MODE_EN_TO_DI0		(1 << 2)
 #define LDB_CH1_MODE_EN_TO_DI1		(3 << 2)
 #define LDB_CH1_MODE_EN_MASK		(3 << 2)
-#define LDB_SPLIT_MODE_EN		(1 << 4)
-#define LDB_DATA_WIDTH_CH0_24		(1 << 5)
-#define LDB_BIT_MAP_CH0_JEIDA		(1 << 6)
-#define LDB_DATA_WIDTH_CH1_24		(1 << 7)
-#define LDB_BIT_MAP_CH1_JEIDA		(1 << 8)
-#define LDB_DI0_VS_POL_ACT_LOW		(1 << 9)
-#define LDB_DI1_VS_POL_ACT_LOW		(1 << 10)
 #define LDB_BGREF_RMODE_INT		(1 << 15)
 
 struct imx_ldb;
 
 struct imx_ldb_channel {
-	struct imx_ldb *ldb;
+	struct ldb_channel base;
+	struct imx_ldb *imx_ldb;
+
 	struct drm_connector connector;
 	struct drm_encoder encoder;
 
-	/* Defines what is connected to the ldb, only one at a time */
-	struct drm_panel *panel;
-	struct drm_bridge *bridge;
-
-	struct device_node *child;
 	struct i2c_adapter *ddc;
-	int chno;
 	void *edid;
 	int edid_len;
 	struct drm_display_mode mode;
 	int mode_valid;
-	u32 bus_format;
 	u32 bus_flags;
 };
 
@@ -84,51 +70,19 @@
 };
 
 struct imx_ldb {
-	struct regmap *regmap;
-	struct device *dev;
+	struct ldb base;
 	struct imx_ldb_channel channel[2];
 	struct clk *clk[2]; /* our own clock */
 	struct clk *clk_sel[4]; /* parent of display clock */
 	struct clk *clk_parent[4]; /* original parent of clk_sel */
 	struct clk *clk_pll[2]; /* upstream clock we can adjust */
-	u32 ldb_ctrl;
 	const struct bus_mux *lvds_mux;
 };
 
-static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch,
-				      u32 bus_format)
-{
-	struct imx_ldb *ldb = imx_ldb_ch->ldb;
-	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
-
-	switch (bus_format) {
-	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
-		break;
-	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
-		if (imx_ldb_ch->chno == 0 || dual)
-			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
-		if (imx_ldb_ch->chno == 1 || dual)
-			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
-		break;
-	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
-		if (imx_ldb_ch->chno == 0 || dual)
-			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
-					 LDB_BIT_MAP_CH0_JEIDA;
-		if (imx_ldb_ch->chno == 1 || dual)
-			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
-					 LDB_BIT_MAP_CH1_JEIDA;
-		break;
-	}
-}
-
 static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
-	int num_modes;
-
-	num_modes = drm_panel_get_modes(imx_ldb_ch->panel);
-	if (num_modes > 0)
-		return num_modes;
+	int num_modes = 0;
 
 	if (!imx_ldb_ch->edid && imx_ldb_ch->ddc)
 		imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc);
@@ -162,28 +116,29 @@
 	return &imx_ldb_ch->encoder;
 }
 
-static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
+static void imx_ldb_set_clock(struct imx_ldb *imx_ldb, int mux, int chno,
 		unsigned long serial_clk, unsigned long di_clk)
 {
+	struct ldb *ldb = &imx_ldb->base;
 	int ret;
 
 	dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
-			clk_get_rate(ldb->clk_pll[chno]), serial_clk);
-	clk_set_rate(ldb->clk_pll[chno], serial_clk);
+			clk_get_rate(imx_ldb->clk_pll[chno]), serial_clk);
+	clk_set_rate(imx_ldb->clk_pll[chno], serial_clk);
 
 	dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
-			clk_get_rate(ldb->clk_pll[chno]));
+			clk_get_rate(imx_ldb->clk_pll[chno]));
 
 	dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
-			clk_get_rate(ldb->clk[chno]),
+			clk_get_rate(imx_ldb->clk[chno]),
 			(long int)di_clk);
-	clk_set_rate(ldb->clk[chno], di_clk);
+	clk_set_rate(imx_ldb->clk[chno], di_clk);
 
 	dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
-			clk_get_rate(ldb->clk[chno]));
+			clk_get_rate(imx_ldb->clk[chno]));
 
 	/* set display clock mux to LDB input clock */
-	ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
+	ret = clk_set_parent(imx_ldb->clk_sel[mux], imx_ldb->clk[chno]);
 	if (ret)
 		dev_err(ldb->dev,
 			"unable to set di%d parent clock to ldb_di%d\n", mux,
@@ -193,52 +148,53 @@
 static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
 {
 	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 = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder);
-
-	drm_panel_prepare(imx_ldb_ch->panel);
-
-	if (dual) {
-		clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]);
-		clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]);
+	struct imx_ldb *imx_ldb = imx_ldb_ch->imx_ldb;
+	struct ldb_channel *ldb_ch = &imx_ldb_ch->base;
+	struct ldb *ldb = &imx_ldb->base;
+	int mux = drm_of_encoder_active_port_id(ldb_ch->child, encoder);
+
+	if (mux < 0 || mux >= ARRAY_SIZE(imx_ldb->clk_sel)) {
+		dev_warn(ldb->dev, "%s: invalid mux %d\n", __func__, mux);
+		return;
+	}
+
+	if (ldb->dual) {
+		clk_set_parent(imx_ldb->clk_sel[mux], imx_ldb->clk[0]);
+		clk_set_parent(imx_ldb->clk_sel[mux], imx_ldb->clk[1]);
 
-		clk_prepare_enable(ldb->clk[0]);
-		clk_prepare_enable(ldb->clk[1]);
+		clk_prepare_enable(imx_ldb->clk[0]);
+		clk_prepare_enable(imx_ldb->clk[1]);
 	} else {
-		clk_set_parent(ldb->clk_sel[mux], ldb->clk[imx_ldb_ch->chno]);
+		clk_set_parent(imx_ldb->clk_sel[mux],
+			       imx_ldb->clk[ldb_ch->chno]);
 	}
 
-	if (imx_ldb_ch == &ldb->channel[0] || dual) {
+	if (imx_ldb_ch == &imx_ldb->channel[0] || ldb->dual) {
 		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
-		if (mux == 0 || ldb->lvds_mux)
+		if (mux == 0 || imx_ldb->lvds_mux)
 			ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
 		else if (mux == 1)
 			ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI1;
 	}
-	if (imx_ldb_ch == &ldb->channel[1] || dual) {
+	if (imx_ldb_ch == &imx_ldb->channel[1] || ldb->dual) {
 		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
-		if (mux == 1 || ldb->lvds_mux)
+		if (mux == 1 || imx_ldb->lvds_mux)
 			ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1;
 		else if (mux == 0)
 			ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0;
 	}
 
-	if (ldb->lvds_mux) {
+	if (imx_ldb->lvds_mux) {
 		const struct bus_mux *lvds_mux = NULL;
 
-		if (imx_ldb_ch == &ldb->channel[0])
-			lvds_mux = &ldb->lvds_mux[0];
-		else if (imx_ldb_ch == &ldb->channel[1])
-			lvds_mux = &ldb->lvds_mux[1];
+		if (imx_ldb_ch == &imx_ldb->channel[0])
+			lvds_mux = &imx_ldb->lvds_mux[0];
+		else if (imx_ldb_ch == &imx_ldb->channel[1])
+			lvds_mux = &imx_ldb->lvds_mux[1];
 
 		regmap_update_bits(ldb->regmap, lvds_mux->reg, lvds_mux->mask,
 				   mux << lvds_mux->shift);
 	}
-
-	regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
-
-	drm_panel_enable(imx_ldb_ch->panel);
 }
 
 static void
@@ -247,100 +203,80 @@
 				struct drm_connector_state *connector_state)
 {
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+	struct imx_ldb *imx_ldb = imx_ldb_ch->imx_ldb;
+	struct ldb_channel *ldb_ch = &imx_ldb_ch->base;
+	struct ldb *ldb = &imx_ldb->base;
 	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
-	struct imx_ldb *ldb = imx_ldb_ch->ldb;
-	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
 	unsigned long serial_clk;
 	unsigned long di_clk = mode->clock * 1000;
-	int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder);
-	u32 bus_format = imx_ldb_ch->bus_format;
+	int mux = drm_of_encoder_active_port_id(ldb_ch->child, encoder);
+
+	if (mux < 0 || mux >= ARRAY_SIZE(imx_ldb->clk_sel)) {
+		dev_warn(ldb->dev, "%s: invalid mux %d\n", __func__, mux);
+		return;
+	}
 
 	if (mode->clock > 170000) {
 		dev_warn(ldb->dev,
 			 "%s: mode exceeds 170 MHz pixel clock\n", __func__);
 	}
-	if (mode->clock > 85000 && !dual) {
+	if (mode->clock > 85000 && !ldb->dual) {
 		dev_warn(ldb->dev,
 			 "%s: mode exceeds 85 MHz pixel clock\n", __func__);
 	}
 
-	if (dual) {
+	if (ldb->dual) {
 		serial_clk = 3500UL * mode->clock;
-		imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
-		imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+		imx_ldb_set_clock(imx_ldb, mux, 0, serial_clk, di_clk);
+		imx_ldb_set_clock(imx_ldb, mux, 1, serial_clk, di_clk);
 	} else {
 		serial_clk = 7000UL * mode->clock;
-		imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+		imx_ldb_set_clock(imx_ldb, mux, ldb_ch->chno, serial_clk,
 				  di_clk);
 	}
 
-	/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
-	if (imx_ldb_ch == &ldb->channel[0] || dual) {
-		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-			ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
-		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-			ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
-	}
-	if (imx_ldb_ch == &ldb->channel[1] || dual) {
-		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-			ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
-		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-			ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
-	}
-
-	if (!bus_format) {
+	if (!ldb_ch->bus_format) {
 		struct drm_connector *connector = connector_state->connector;
 		struct drm_display_info *di = &connector->display_info;
 
 		if (di->num_bus_formats)
-			bus_format = di->bus_formats[0];
+			ldb_ch->bus_format = di->bus_formats[0];
 	}
-	imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format);
 }
 
 static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
 {
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
-	struct imx_ldb *ldb = imx_ldb_ch->ldb;
+	struct imx_ldb *imx_ldb = imx_ldb_ch->imx_ldb;
+	struct ldb *ldb = &imx_ldb->base;
 	int mux, ret;
 
-	drm_panel_disable(imx_ldb_ch->panel);
-
-	if (imx_ldb_ch == &ldb->channel[0])
-		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
-	else if (imx_ldb_ch == &ldb->channel[1])
-		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) {
-		clk_disable_unprepare(ldb->clk[0]);
-		clk_disable_unprepare(ldb->clk[1]);
+	if (ldb->dual) {
+		clk_disable_unprepare(imx_ldb->clk[0]);
+		clk_disable_unprepare(imx_ldb->clk[1]);
 	}
 
-	if (ldb->lvds_mux) {
+	if (imx_ldb->lvds_mux) {
 		const struct bus_mux *lvds_mux = NULL;
 
-		if (imx_ldb_ch == &ldb->channel[0])
-			lvds_mux = &ldb->lvds_mux[0];
-		else if (imx_ldb_ch == &ldb->channel[1])
-			lvds_mux = &ldb->lvds_mux[1];
+		if (imx_ldb_ch == &imx_ldb->channel[0])
+			lvds_mux = &imx_ldb->lvds_mux[0];
+		else if (imx_ldb_ch == &imx_ldb->channel[1])
+			lvds_mux = &imx_ldb->lvds_mux[1];
 
 		regmap_read(ldb->regmap, lvds_mux->reg, &mux);
 		mux &= lvds_mux->mask;
 		mux >>= lvds_mux->shift;
 	} else {
-		mux = (imx_ldb_ch == &ldb->channel[0]) ? 0 : 1;
+		mux = (imx_ldb_ch == &imx_ldb->channel[0]) ? 0 : 1;
 	}
 
 	/* set display clock mux back to original input clock */
-	ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk_parent[mux]);
+	ret = clk_set_parent(imx_ldb->clk_sel[mux], imx_ldb->clk_parent[mux]);
 	if (ret)
 		dev_err(ldb->dev,
 			"unable to set di%d parent clock to original parent\n",
 			mux);
-
-	drm_panel_unprepare(imx_ldb_ch->panel);
 }
 
 static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
@@ -349,15 +285,16 @@
 {
 	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+	struct ldb_channel *ldb_ch = &imx_ldb_ch->base;
 	struct drm_display_info *di = &conn_state->connector->display_info;
-	u32 bus_format = imx_ldb_ch->bus_format;
+	u32 bus_format = ldb_ch->bus_format;
 
 	/* Bus format description in DT overrides connector display info. */
 	if (!bus_format && di->num_bus_formats) {
 		bus_format = di->bus_formats[0];
 		imx_crtc_state->bus_flags = di->bus_flags;
 	} else {
-		bus_format = imx_ldb_ch->bus_format;
+		bus_format = ldb_ch->bus_format;
 		imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags;
 	}
 	switch (bus_format) {
@@ -378,7 +315,6 @@
 	return 0;
 }
 
-
 static const struct drm_connector_funcs imx_ldb_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = imx_drm_connector_destroy,
@@ -389,7 +325,6 @@
 
 static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
 	.get_modes = imx_ldb_connector_get_modes,
-	.best_encoder = imx_ldb_connector_best_encoder,
 };
 
 static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
@@ -403,117 +338,22 @@
 	.atomic_check = imx_ldb_encoder_atomic_check,
 };
 
-static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
+static int imx_ldb_get_clk(struct imx_ldb *imx_ldb, int chno)
 {
+	struct ldb *ldb = &imx_ldb->base;
+	struct device *dev = ldb->dev;
 	char clkname[16];
 
 	snprintf(clkname, sizeof(clkname), "di%d", chno);
-	ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
-	if (IS_ERR(ldb->clk[chno]))
-		return PTR_ERR(ldb->clk[chno]);
+	imx_ldb->clk[chno] = devm_clk_get(dev, clkname);
+	if (IS_ERR(imx_ldb->clk[chno]))
+		return PTR_ERR(imx_ldb->clk[chno]);
 
 	snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
-	ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
-
-	return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
-}
-
-static int imx_ldb_register(struct drm_device *drm,
-	struct imx_ldb_channel *imx_ldb_ch)
-{
-	struct imx_ldb *ldb = imx_ldb_ch->ldb;
-	struct drm_encoder *encoder = &imx_ldb_ch->encoder;
-	int ret;
-
-	ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child);
-	if (ret)
-		return ret;
-
-	ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
-	if (ret)
-		return ret;
-
-	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-		ret = imx_ldb_get_clk(ldb, 1);
-		if (ret)
-			return ret;
-	}
-
-	drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs);
-	drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
-			 DRM_MODE_ENCODER_LVDS, NULL);
-
-	if (imx_ldb_ch->bridge) {
-		ret = drm_bridge_attach(&imx_ldb_ch->encoder,
-					imx_ldb_ch->bridge, NULL);
-		if (ret) {
-			DRM_ERROR("Failed to initialize bridge with drm\n");
-			return ret;
-		}
-	} else {
-		/*
-		 * We want to add the connector whenever there is no bridge
-		 * that brings its own, not only when there is a panel. For
-		 * historical reasons, the ldb driver can also work without
-		 * a panel.
-		 */
-		drm_connector_helper_add(&imx_ldb_ch->connector,
-				&imx_ldb_connector_helper_funcs);
-		drm_connector_init_with_ddc(drm, &imx_ldb_ch->connector,
-					    &imx_ldb_connector_funcs,
-					    DRM_MODE_CONNECTOR_LVDS,
-					    imx_ldb_ch->ddc);
-		drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
-	}
-
-	if (imx_ldb_ch->panel) {
-		ret = drm_panel_attach(imx_ldb_ch->panel,
-				       &imx_ldb_ch->connector);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-enum {
-	LVDS_BIT_MAP_SPWG,
-	LVDS_BIT_MAP_JEIDA
-};
-
-struct imx_ldb_bit_mapping {
-	u32 bus_format;
-	u32 datawidth;
-	const char * const mapping;
-};
-
-static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = {
-	{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,  18, "spwg" },
-	{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,  24, "spwg" },
-	{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
-};
-
-static u32 of_get_bus_format(struct device *dev, struct device_node *np)
-{
-	const char *bm;
-	u32 datawidth = 0;
-	int ret, i;
-
-	ret = of_property_read_string(np, "fsl,data-mapping", &bm);
-	if (ret < 0)
-		return ret;
-
-	of_property_read_u32(np, "fsl,data-width", &datawidth);
 
-	for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) {
-		if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) &&
-		    datawidth == imx_ldb_bit_mappings[i].datawidth)
-			return imx_ldb_bit_mappings[i].bus_format;
-	}
-
-	dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm);
+	imx_ldb->clk_pll[chno] = devm_clk_get(dev, clkname);
 
-	return -ENOENT;
+	return PTR_ERR_OR_ZERO(imx_ldb->clk_pll[chno]);
 }
 
 static struct bus_mux imx6q_lvds_mux[2] = {
@@ -529,8 +369,8 @@
 };
 
 /*
- * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb",
- * of_match_device will walk through this list and take the first entry
+ * For a device declaring compatible = "fsl,imx6q-ldb",  "fsl,imx53-ldb",
+ * of_match_device will walk through this  list and take the first entry
  * matching any of its compatible values. Therefore, the more generic
  * entries (in this case fsl,imx53-ldb) need to be ordered last.
  */
@@ -542,83 +382,125 @@
 MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
 static int imx_ldb_panel_ddc(struct device *dev,
-		struct imx_ldb_channel *channel, struct device_node *child)
+		struct imx_ldb_channel *imx_ldb_ch, struct device_node *child)
 {
+	struct ldb_channel *ldb_ch = &imx_ldb_ch->base;
 	struct device_node *ddc_node;
 	const u8 *edidp;
 	int ret;
 
 	ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
 	if (ddc_node) {
-		channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
+		imx_ldb_ch->ddc = of_find_i2c_adapter_by_node(ddc_node);
 		of_node_put(ddc_node);
-		if (!channel->ddc) {
+		if (!imx_ldb_ch->ddc) {
 			dev_warn(dev, "failed to get ddc i2c adapter\n");
 			return -EPROBE_DEFER;
 		}
 	}
 
-	if (!channel->ddc) {
+	if (!imx_ldb_ch->ddc) {
 		/* if no DDC available, fallback to hardcoded EDID */
 		dev_dbg(dev, "no ddc available\n");
 
 		edidp = of_get_property(child, "edid",
-					&channel->edid_len);
+					&imx_ldb_ch->edid_len);
 		if (edidp) {
-			channel->edid = kmemdup(edidp,
-						channel->edid_len,
+			imx_ldb_ch->edid = kmemdup(edidp,
+						imx_ldb_ch->edid_len,
 						GFP_KERNEL);
-		} else if (!channel->panel) {
+		} else if (!ldb_ch->panel) {
 			/* fallback to display-timings node */
 			ret = of_get_drm_display_mode(child,
-						      &channel->mode,
-						      &channel->bus_flags,
+						      &imx_ldb_ch->mode,
+						      &imx_ldb_ch->bus_flags,
 						      OF_USE_NATIVE_MODE);
 			if (!ret)
-				channel->mode_valid = 1;
+				imx_ldb_ch->mode_valid = 1;
 		}
 	}
 	return 0;
 }
 
+static int imx_ldb_register(struct drm_device *drm,
+	struct imx_ldb_channel *imx_ldb_ch)
+{
+	struct imx_ldb *imx_ldb = imx_ldb_ch->imx_ldb;
+	struct ldb *ldb = &imx_ldb->base;
+	struct ldb_channel *ldb_ch = &imx_ldb_ch->base;
+	struct drm_encoder *encoder = &imx_ldb_ch->encoder;
+	int ret;
+
+	ret = imx_drm_encoder_parse_of(drm, encoder, ldb_ch->child);
+	if (ret)
+		return ret;
+
+	ret = imx_ldb_get_clk(imx_ldb, ldb_ch->chno);
+	if (ret)
+		return ret;
+
+	if (ldb->dual) {
+		ret = imx_ldb_get_clk(imx_ldb, 1);
+		if (ret)
+			return ret;
+	}
+
+	if (!ldb_ch->next_bridge) {
+		/* panel ddc only if there is no bridge */
+		ret = imx_ldb_panel_ddc(ldb->dev, imx_ldb_ch, ldb_ch->child);
+		if (ret)
+			return ret;
+
+		/*
+		 * We want to add the connector whenever there is no bridge
+		 * that brings its own, not only when there is a panel. For
+		 * historical reasons, the ldb driver can also work without
+		 * a panel.
+		 */
+		drm_connector_helper_add(&imx_ldb_ch->connector,
+				&imx_ldb_connector_helper_funcs);
+		drm_connector_init(drm, &imx_ldb_ch->connector,
+				&imx_ldb_connector_funcs,
+				DRM_MODE_CONNECTOR_LVDS);
+		drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
+	}
+
+	return 0;
+}
+
 static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
 	struct drm_device *drm = data;
-	struct device_node *np = dev->of_node;
 	const struct of_device_id *of_id =
 			of_match_device(imx_ldb_dt_ids, dev);
-	struct device_node *child;
-	struct imx_ldb *imx_ldb;
-	int dual;
+	struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb;
+	struct ldb_channel *ldb_ch;
+	struct drm_encoder *encoder[LDB_CH_NUM];
 	int ret;
 	int i;
 
-	imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
-	if (!imx_ldb)
-		return -ENOMEM;
-
-	imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
-	if (IS_ERR(imx_ldb->regmap)) {
-		dev_err(dev, "failed to get parent regmap\n");
-		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;
+	imx_ldb->lvds_mux = of_id ? of_id->data : NULL;
 
-	if (of_id)
-		imx_ldb->lvds_mux = of_id->data;
+	ldb = &imx_ldb->base;
+	ldb->dev = dev;
+	ldb->ctrl_reg = IOMUXC_GPR2;
+	/*
+	 * The output port is port@4 with an external 4-port mux or
+	 * port@2 with the internal 2-port mux or port@1 without mux.
+	 */
+	ldb->output_port = imx_ldb->lvds_mux ? 4 : 2;
 
-	dual = of_property_read_bool(np, "fsl,dual-channel");
-	if (dual)
-		imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		imx_ldb->channel[i].imx_ldb = imx_ldb;
+		ldb->channel[i] = &imx_ldb->channel[i].base;
+	}
 
 	/*
 	 * There are three different possible clock mux configurations:
 	 * i.MX53:  ipu1_di0_sel, ipu1_di1_sel
-	 * i.MX6q:  ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
+	 * i.MX6q:  ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel,
+	 *          ipu2_di1_sel
 	 * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
 	 * Map them all to di0_sel...di3_sel.
 	 */
@@ -626,90 +508,45 @@
 		char clkname[16];
 
 		sprintf(clkname, "di%d_sel", i);
-		imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname);
+		imx_ldb->clk_sel[i] = devm_clk_get(dev, clkname);
 		if (IS_ERR(imx_ldb->clk_sel[i])) {
 			ret = PTR_ERR(imx_ldb->clk_sel[i]);
 			imx_ldb->clk_sel[i] = NULL;
 			break;
 		}
 
-		imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]);
+		imx_ldb->clk_parent[i] =
+				clk_get_parent(imx_ldb->clk_sel[i]);
 	}
 	if (i == 0)
 		return ret;
 
-	for_each_child_of_node(np, child) {
-		struct imx_ldb_channel *channel;
-		int bus_format;
-
-		ret = of_property_read_u32(child, "reg", &i);
-		if (ret || i < 0 || i > 1) {
-			ret = -EINVAL;
-			goto free_child;
-		}
-
-		if (!of_device_is_available(child))
-			continue;
-
-		if (dual && i > 0) {
-			dev_warn(dev, "dual-channel mode, ignoring second output\n");
-			continue;
-		}
-
-		channel = &imx_ldb->channel[i];
-		channel->ldb = imx_ldb;
-		channel->chno = i;
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		encoder[i] = &imx_ldb->channel[i].encoder;
 
-		/*
-		 * The output port is port@4 with an external 4-port mux or
-		 * port@2 with the internal 2-port mux.
-		 */
-		ret = drm_of_find_panel_or_bridge(child,
-						  imx_ldb->lvds_mux ? 4 : 2, 0,
-						  &channel->panel, &channel->bridge);
-		if (ret && ret != -ENODEV)
-			goto free_child;
+		drm_encoder_helper_add(encoder[i],
+				      &imx_ldb_encoder_helper_funcs);
+		drm_encoder_init(drm, encoder[i], &imx_ldb_encoder_funcs,
+				 DRM_MODE_ENCODER_LVDS, NULL);
+	}
 
-		/* panel ddc only if there is no bridge */
-		if (!channel->bridge) {
-			ret = imx_ldb_panel_ddc(dev, channel, child);
-			if (ret)
-				goto free_child;
-		}
+	ret = ldb_bind(ldb, encoder);
+	if (ret)
+		return ret;
 
-		bus_format = of_get_bus_format(dev, child);
-		if (bus_format == -EINVAL) {
-			/*
-			 * If no bus format was specified in the device tree,
-			 * we can still get it from the connected panel later.
-			 */
-			if (channel->panel && channel->panel->funcs &&
-			    channel->panel->funcs->get_modes)
-				bus_format = 0;
-		}
-		if (bus_format < 0) {
-			dev_err(dev, "could not determine data mapping: %d\n",
-				bus_format);
-			ret = bus_format;
-			goto free_child;
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		ldb_ch = &imx_ldb->channel[i].base;
+		if (!ldb_ch->is_valid) {
+			drm_encoder_cleanup(encoder[i]);
+			continue;
 		}
-		channel->bus_format = bus_format;
-		channel->child = child;
 
-		ret = imx_ldb_register(drm, channel);
-		if (ret) {
-			channel->child = NULL;
-			goto free_child;
-		}
+		ret = imx_ldb_register(drm, &imx_ldb->channel[i]);
+		if (ret)
+			return ret;
 	}
 
-	dev_set_drvdata(dev, imx_ldb);
-
 	return 0;
-
-free_child:
-	of_node_put(child);
-	return ret;
 }
 
 static void imx_ldb_unbind(struct device *dev, struct device *master,
@@ -718,14 +555,11 @@
 	struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
 	int i;
 
-	for (i = 0; i < 2; i++) {
-		struct imx_ldb_channel *channel = &imx_ldb->channel[i];
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		struct imx_ldb_channel *imx_ldb_ch = &imx_ldb->channel[i];
 
-		if (channel->panel)
-			drm_panel_detach(channel->panel);
-
-		kfree(channel->edid);
-		i2c_put_adapter(channel->ddc);
+		kfree(imx_ldb_ch->edid);
+		i2c_put_adapter(imx_ldb_ch->ddc);
 	}
 }
 
@@ -736,7 +570,16 @@
 
 static int imx_ldb_probe(struct platform_device *pdev)
 {
-	return component_add(&pdev->dev, &imx_ldb_ops);
+	struct device *dev = &pdev->dev;
+	struct imx_ldb *imx_ldb;
+
+	imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
+	if (!imx_ldb)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, imx_ldb);
+
+	return component_add(dev, &imx_ldb_ops);
 }
 
 static int imx_ldb_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx-tve.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx-tve.c
@@ -237,8 +237,9 @@
 	return ret;
 }
 
-static int imx_tve_connector_mode_valid(struct drm_connector *connector,
-					struct drm_display_mode *mode)
+static enum drm_mode_status
+imx_tve_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
 {
 	struct imx_tve *tve = con_to_tve(connector);
 	unsigned long rate;
@@ -259,14 +260,6 @@
 	return MODE_BAD;
 }
 
-static struct drm_encoder *imx_tve_connector_best_encoder(
-		struct drm_connector *connector)
-{
-	struct imx_tve *tve = con_to_tve(connector);
-
-	return &tve->encoder;
-}
-
 static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
 				     struct drm_display_mode *orig_mode,
 				     struct drm_display_mode *mode)
@@ -344,7 +337,6 @@
 
 static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
 	.get_modes = imx_tve_connector_get_modes,
-	.best_encoder = imx_tve_connector_best_encoder,
 	.mode_valid = imx_tve_connector_mode_valid,
 };
 
@@ -494,6 +486,13 @@
 	return 0;
 }
 
+static void imx_tve_disable_regulator(void *data)
+{
+	struct imx_tve *tve = data;
+
+	regulator_disable(tve->dac_reg);
+}
+
 static bool imx_tve_readable_reg(struct device *dev, unsigned int reg)
 {
 	return (reg % 4 == 0) && (reg <= 0xdc);
@@ -546,9 +545,8 @@
 	int irq;
 	int ret;
 
-	tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
-	if (!tve)
-		return -ENOMEM;
+	tve = dev_get_drvdata(dev);
+	memset(tve, 0, sizeof(*tve));
 
 	tve->dev = dev;
 	spin_lock_init(&tve->lock);
@@ -598,10 +596,8 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "failed to get irq\n");
+	if (irq < 0)
 		return irq;
-	}
 
 	ret = devm_request_threaded_irq(dev, irq, NULL,
 					imx_tve_irq_handler, IRQF_ONESHOT,
@@ -618,6 +614,9 @@
 		ret = regulator_enable(tve->dac_reg);
 		if (ret)
 			return ret;
+		ret = devm_add_action_or_reset(dev, imx_tve_disable_regulator, tve);
+		if (ret)
+			return ret;
 	}
 
 	tve->clk = devm_clk_get(dev, "tve");
@@ -659,27 +658,23 @@
 	if (ret)
 		return ret;
 
-	dev_set_drvdata(dev, tve);
-
 	return 0;
 }
 
-static void imx_tve_unbind(struct device *dev, struct device *master,
-	void *data)
-{
-	struct imx_tve *tve = dev_get_drvdata(dev);
-
-	if (!IS_ERR(tve->dac_reg))
-		regulator_disable(tve->dac_reg);
-}
-
 static const struct component_ops imx_tve_ops = {
 	.bind	= imx_tve_bind,
-	.unbind	= imx_tve_unbind,
 };
 
 static int imx_tve_probe(struct platform_device *pdev)
 {
+	struct imx_tve *tve;
+
+	tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+	if (!tve)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, tve);
+
 	return component_add(&pdev->dev, &imx_tve_ops);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020 NXP
+ *
+ * Programe Video/Audio Interface between LCDIF and HDMI Ctrl in HDMIMIX
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <drm/drm_fourcc.h>
+
+#include "imx8mp-hdmi-pavi.h"
+
+#define DRIVER_NAME "imx-hdmi-pavi"
+
+#define HTX_PVI_CTRL         0x0
+#define HTX_PVI_IRQ_MASK     0x04
+#define HTX_TMG_GEN_DISP_LRC 0x10
+#define HTX_TMG_GEN_DE_ULC   0x14
+#define HTX_TMG_GEN_DE_LRC   0x18
+#define HTX_TMG_GEN_HSYNC    0x1c
+#define HTX_TMG_GEN_VSYNC    0x20
+#define HTX_TMG_GEN_IRQ0     0x24
+#define HTX_TMG_GEN_IRQ1     0x28
+#define HTX_TMG_GEN_IRQ2     0x2c
+#define HTX_TMG_GEN_IRQ3     0x30
+#define HTX_TMG_GEN_CFG      0x40
+
+#define HTX_PAI_CTRL        0x800
+#define HTX_PAI_CTRL_EXT    0x804
+#define HTX_PAI_FIELD_CTRL  0x808
+
+#define HTX_PAI_CTRL_ENABLE 1
+
+
+static struct imx8mp_hdmi_pavi *gpavi;
+
+/* PAI APIs  */
+void imx8mp_hdmi_pai_enable(int channel, int width, int rate, int non_pcm)
+{
+	/* PAI set */
+	writel((0x3030000 | ((channel-1) << 8)),
+			gpavi->base + HTX_PAI_CTRL_EXT);
+
+	/* hbr */
+	if (non_pcm && width == 32 && channel == 8 && rate == 192000)
+		writel(0x004e77df, gpavi->base + HTX_PAI_FIELD_CTRL);
+	else if (width == 32)
+		writel(0x1c8c675b, gpavi->base + HTX_PAI_FIELD_CTRL);
+	else
+		writel(0x1c0c675b, gpavi->base + HTX_PAI_FIELD_CTRL);
+
+	/* PAI start running */
+	writel(HTX_PAI_CTRL_ENABLE, gpavi->base + HTX_PAI_CTRL);
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pai_enable);
+
+void imx8mp_hdmi_pai_disable(void)
+{
+	/* stop PAI */
+	writel(0, gpavi->base + HTX_PAI_CTRL);
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pai_disable);
+
+/* PVI APIs  */
+void imx8mp_hdmi_pvi_enable(struct drm_display_mode *mode)
+{
+	writel(0x00000003, gpavi->base + HTX_PVI_IRQ_MASK);
+	writel(0x08970464, gpavi->base + HTX_TMG_GEN_DISP_LRC);
+	writel(0x00bf0029, gpavi->base + HTX_TMG_GEN_DE_ULC);
+	writel(0x083f0460, gpavi->base + HTX_TMG_GEN_DE_LRC);
+	writel(0x0897002b, gpavi->base + HTX_TMG_GEN_HSYNC);
+	writel(0x04640004, gpavi->base + HTX_TMG_GEN_VSYNC);
+	writel(0x000100ff, gpavi->base + HTX_TMG_GEN_IRQ0);
+	writel(0x000100f0, gpavi->base + HTX_TMG_GEN_IRQ1);
+	writel(0x00010315, gpavi->base + HTX_TMG_GEN_IRQ2);
+	writel(0x00010207, gpavi->base + HTX_TMG_GEN_IRQ3);
+	writel(0x84640000, gpavi->base + HTX_TMG_GEN_CFG);
+
+	/* DE/VSYN/HSYNC pol */
+	if ((mode->flags & DRM_MODE_FLAG_PVSYNC) &&
+			(mode->flags & DRM_MODE_FLAG_PHSYNC)) {
+		writel(0x00377004, gpavi->base + HTX_PVI_CTRL);
+		writel(0x00377005, gpavi->base + HTX_PVI_CTRL);
+	} else {
+		writel(0x00311004, gpavi->base + HTX_PVI_CTRL);
+		writel(0x00311005, gpavi->base + HTX_PVI_CTRL);
+	}
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pvi_enable);
+
+void imx8mp_hdmi_pvi_disable(void)
+{
+	/* Stop PVI */
+	writel(0x0, gpavi->base + HTX_PVI_CTRL);
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pvi_disable);
+
+void imx8mp_hdmi_pavi_powerup(void)
+{
+	clk_prepare_enable(gpavi->clk_pvi);
+	clk_prepare_enable(gpavi->clk_pai);
+
+	/* deassert pai reset */
+	if (!gpavi->reset_pai)
+		reset_control_deassert(gpavi->reset_pai);
+
+	/* deassert pvi reset */
+	if (!gpavi->reset_pvi)
+		reset_control_deassert(gpavi->reset_pvi);
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pavi_powerup);
+
+void imx8mp_hdmi_pavi_powerdown(void)
+{
+	/* set pvi reset */
+	if (!gpavi->reset_pvi)
+		reset_control_assert(gpavi->reset_pvi);
+
+	/* set pai reset */
+	if (!gpavi->reset_pai)
+		reset_control_assert(gpavi->reset_pai);
+
+	clk_disable_unprepare(gpavi->clk_pai);
+	clk_disable_unprepare(gpavi->clk_pvi);
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pavi_powerdown);
+
+struct imx8mp_hdmi_pavi *imx8mp_hdmi_pavi_init(void)
+{
+	return gpavi;
+}
+EXPORT_SYMBOL(imx8mp_hdmi_pavi_init);
+
+static int imx8mp_hdmi_pavi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx8mp_hdmi_pavi *pavi;
+	struct resource *res;
+
+	dev_dbg(dev, "%s: probe begin\n", __func__);
+
+	pavi = devm_kzalloc(dev, sizeof(*pavi), GFP_KERNEL);
+	if (!pavi) {
+		dev_err(dev, "Can't allocate 'imx8mp pavi' structure\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pavi->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(pavi->base))
+		return PTR_ERR(pavi->base);
+
+	pavi->clk_pvi = devm_clk_get(dev, "pvi_clk");
+	if (IS_ERR(pavi->clk_pvi)) {
+		dev_err(dev, "No pvi clock get\n");
+		return -EPROBE_DEFER;
+	}
+
+	pavi->clk_pai = devm_clk_get(dev, "pai_clk");
+	if (IS_ERR(pavi->clk_pai)) {
+		dev_err(dev, "No pai clock get\n");
+		return -EPROBE_DEFER;
+	}
+
+	pavi->reset_pai = devm_reset_control_get(dev, "pai_rst");
+	if (IS_ERR(pavi->reset_pai)) {
+		dev_err(pavi->dev, "No PAI reset\n");
+		return -EPROBE_DEFER;
+	}
+
+	pavi->reset_pvi = devm_reset_control_get(dev, "pvi_rst");
+	if (IS_ERR(pavi->reset_pvi)) {
+		dev_err(pavi->dev, "No PVI reset\n");
+		return -EPROBE_DEFER;
+	}
+
+	platform_set_drvdata(pdev, pavi);
+
+	gpavi = pavi;
+
+	dev_dbg(dev, "%s: probe success\n", __func__);
+	return 0;
+}
+
+static int imx8mp_hdmi_pavi_remove(struct platform_device *pdev)
+{
+	gpavi = NULL;
+	return 0;
+}
+
+static const struct of_device_id imx8mp_hdmi_pavi_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-hdmi-pavi", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8mp_hdmi_pavi_dt_ids);
+
+struct platform_driver imx8mp_hdmi_pavi_driver = {
+	.probe    = imx8mp_hdmi_pavi_probe,
+	.remove   = imx8mp_hdmi_pavi_remove,
+	.driver   = {
+		.name = DRIVER_NAME,
+		.of_match_table = imx8mp_hdmi_pavi_dt_ids,
+	},
+};
+
+module_platform_driver(imx8mp_hdmi_pavi_driver);
+
+MODULE_DESCRIPTION("NXP i.MX8MP HDMI PAI/PVI Mix driver");
+MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2020 NXP
+ *
+ * PAI/PVI Head file
+ *
+ */
+#ifndef _IMX8MP_HDMI_AV_CTL_H_
+#define _IMX8MP_HDMI_AV_CTL_H_
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <drm/drm_modes.h>
+
+struct imx8mp_hdmi_pavi {
+	struct device *dev;
+
+	void __iomem *base;
+	atomic_t rpm_suspended;
+
+	struct clk *clk_pai;
+	struct clk *clk_pvi;
+	struct reset_control *reset_pai;
+	struct reset_control *reset_pvi;
+};
+
+void imx8mp_hdmi_pai_enable(int channel, int width, int rate, int non_pcm);
+void imx8mp_hdmi_pai_disable(void);
+
+void imx8mp_hdmi_pvi_enable(struct drm_display_mode *mode);
+void imx8mp_hdmi_pvi_disable(void);
+
+void imx8mp_hdmi_pavi_powerup(void);
+void imx8mp_hdmi_pavi_powerdown(void);
+
+struct imx8mp_hdmi_pavi *imx8mp_hdmi_pavi_init(void);
+
+#endif /* _IMX8MP_HDMI_PAVI_H_ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx8mp-ldb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx8mp-ldb.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+
+#include <drm/bridge/fsl_imx_ldb.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "imx8mp-ldb"
+
+#define LDB_CH0_MODE_EN_TO_DI0		(1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1		(3 << 0)
+#define LDB_CH0_MODE_EN_MASK		(3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0		(1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1		(3 << 2)
+#define LDB_CH1_MODE_EN_MASK		(3 << 2)
+#define LDB_REG_CH0_FIFO_RESET		(1 << 11)
+#define LDB_REG_CH1_FIFO_RESET		(1 << 12)
+#define LDB_REG_ASYNC_FIFO_EN		(1 << 24)
+#define LDB_FIFO_THRESHOLD		(4 << 25)
+
+struct imx8mp_ldb;
+
+struct imx8mp_ldb_channel {
+	struct ldb_channel base;
+	struct imx8mp_ldb *imx8mp_ldb;
+
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+
+	struct phy *phy;
+	bool phy_is_on;
+
+	u32 bus_flags;
+};
+
+static inline struct imx8mp_ldb_channel *
+con_to_imx8mp_ldb_ch(struct drm_connector *c)
+{
+	return container_of(c, struct imx8mp_ldb_channel, connector);
+}
+
+static inline struct imx8mp_ldb_channel *
+enc_to_imx8mp_ldb_ch(struct drm_encoder *e)
+{
+	return container_of(e, struct imx8mp_ldb_channel, encoder);
+}
+
+struct imx8mp_ldb {
+	struct ldb base;
+	struct imx8mp_ldb_channel channel[LDB_CH_NUM];
+	struct clk *clk_root;
+};
+
+static struct drm_encoder *imx8mp_ldb_connector_best_encoder(
+		struct drm_connector *connector)
+{
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						con_to_imx8mp_ldb_ch(connector);
+
+	return &imx8mp_ldb_ch->encoder;
+}
+
+static void imx8mp_ldb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						enc_to_imx8mp_ldb_ch(encoder);
+	struct imx8mp_ldb *imx8mp_ldb = imx8mp_ldb_ch->imx8mp_ldb;
+	struct ldb *ldb = &imx8mp_ldb->base;
+
+	clk_prepare_enable(imx8mp_ldb->clk_root);
+
+	if (imx8mp_ldb_ch == &imx8mp_ldb->channel[0] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+		ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
+	}
+	if (imx8mp_ldb_ch == &imx8mp_ldb->channel[1] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+		ldb->ldb_ctrl |= ldb->dual ?
+				LDB_CH1_MODE_EN_TO_DI0 : LDB_CH1_MODE_EN_TO_DI1;
+	}
+
+	if (ldb->dual) {
+		phy_power_on(imx8mp_ldb->channel[0].phy);
+		phy_power_on(imx8mp_ldb->channel[1].phy);
+
+		imx8mp_ldb->channel[0].phy_is_on = true;
+		imx8mp_ldb->channel[1].phy_is_on = true;
+	} else {
+		phy_power_on(imx8mp_ldb_ch->phy);
+
+		imx8mp_ldb_ch->phy_is_on = true;
+	}
+}
+
+static void
+imx8mp_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *connector_state)
+{
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						enc_to_imx8mp_ldb_ch(encoder);
+	struct imx8mp_ldb *imx8mp_ldb = imx8mp_ldb_ch->imx8mp_ldb;
+	struct ldb_channel *ldb_ch = &imx8mp_ldb_ch->base;
+	struct ldb *ldb = &imx8mp_ldb->base;
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	unsigned long serial_clk;
+
+	if (mode->clock > 160000) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 160 MHz pixel clock\n", __func__);
+	}
+	if (mode->clock > 80000 && !ldb->dual) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 80 MHz pixel clock\n", __func__);
+	}
+
+	serial_clk = mode->clock * (ldb->dual ? 3500UL : 7000UL);
+	clk_set_rate(imx8mp_ldb->clk_root, serial_clk);
+
+	if (!ldb_ch->bus_format) {
+		struct drm_connector *connector = connector_state->connector;
+		struct drm_display_info *di = &connector->display_info;
+
+		if (di->num_bus_formats)
+			ldb_ch->bus_format = di->bus_formats[0];
+	}
+}
+
+static void imx8mp_ldb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						enc_to_imx8mp_ldb_ch(encoder);
+	struct imx8mp_ldb *imx8mp_ldb = imx8mp_ldb_ch->imx8mp_ldb;
+	struct ldb *ldb = &imx8mp_ldb->base;
+
+	if (ldb->dual) {
+		phy_power_off(imx8mp_ldb->channel[0].phy);
+		phy_power_off(imx8mp_ldb->channel[1].phy);
+
+		imx8mp_ldb->channel[0].phy_is_on = false;
+		imx8mp_ldb->channel[1].phy_is_on = false;
+	} else {
+		phy_power_off(imx8mp_ldb_ch->phy);
+
+		imx8mp_ldb_ch->phy_is_on = false;
+	}
+
+	clk_disable_unprepare(imx8mp_ldb->clk_root);
+}
+
+static int
+imx8mp_ldb_encoder_atomic_check(struct drm_encoder *encoder,
+				struct drm_crtc_state *crtc_state,
+				struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						enc_to_imx8mp_ldb_ch(encoder);
+	struct ldb_channel *ldb_ch = &imx8mp_ldb_ch->base;
+	struct imx8mp_ldb *imx8mp_ldb = imx8mp_ldb_ch->imx8mp_ldb;
+	struct ldb *ldb = &imx8mp_ldb->base;
+	struct drm_display_info *di = &conn_state->connector->display_info;
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	u32 bus_format = ldb_ch->bus_format;
+
+	/* Bus format description in DT overrides connector display info. */
+	if (!bus_format && di->num_bus_formats) {
+		bus_format = di->bus_formats[0];
+		imx_crtc_state->bus_flags = di->bus_flags;
+	} else {
+		bus_format = ldb_ch->bus_format;
+		imx_crtc_state->bus_flags = imx8mp_ldb_ch->bus_flags;
+	}
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Due to limited video PLL frequency points on i.MX8mp,
+	 * we do mode fixup here in case any mode is unsupported.
+	 */
+	if (ldb->dual)
+		mode->clock = mode->clock > 100000 ? 148500 : 74250;
+	else
+		mode->clock = 74250;
+
+	return 0;
+}
+
+static enum drm_mode_status
+imx8mp_ldb_encoder_mode_valid(struct drm_encoder *encoder,
+			      const struct drm_display_mode *mode)
+{
+	struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						enc_to_imx8mp_ldb_ch(encoder);
+	struct ldb_channel *ldb_ch = &imx8mp_ldb_ch->base;
+	struct imx8mp_ldb *imx8mp_ldb = imx8mp_ldb_ch->imx8mp_ldb;
+	struct ldb *ldb = &imx8mp_ldb->base;
+
+	/* it should be okay with a panel */
+	if (ldb_ch->panel)
+		return MODE_OK;
+
+	/*
+	 * Due to limited video PLL frequency points on i.MX8mp,
+	 * we do mode valid check here.
+	 */
+	if (ldb->dual && mode->clock != 74250 && mode->clock != 148500)
+		return MODE_NOCLOCK;
+
+	if (!ldb->dual && mode->clock != 74250)
+		return MODE_NOCLOCK;
+
+	return MODE_OK;
+}
+
+static const struct drm_connector_funcs imx8mp_ldb_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = imx_drm_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs
+imx8mp_ldb_connector_helper_funcs = {
+	.best_encoder = imx8mp_ldb_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs imx8mp_ldb_encoder_funcs = {
+	.destroy = imx_drm_encoder_destroy,
+};
+
+static const struct drm_encoder_helper_funcs imx8mp_ldb_encoder_helper_funcs = {
+	.atomic_mode_set = imx8mp_ldb_encoder_atomic_mode_set,
+	.enable = imx8mp_ldb_encoder_enable,
+	.disable = imx8mp_ldb_encoder_disable,
+	.atomic_check = imx8mp_ldb_encoder_atomic_check,
+	.mode_valid = imx8mp_ldb_encoder_mode_valid,
+};
+
+static const struct of_device_id imx8mp_ldb_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-ldb", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, imx8mp_ldb_dt_ids);
+
+static int
+imx8mp_ldb_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	struct imx8mp_ldb *imx8mp_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb;
+	struct ldb_channel *ldb_ch;
+	struct drm_encoder *encoder[LDB_CH_NUM];
+	int ret;
+	int i;
+
+	ldb = &imx8mp_ldb->base;
+	ldb->dev = dev;
+	ldb->ctrl_reg = 0x5c,
+	ldb->output_port = 1;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		imx8mp_ldb->channel[i].imx8mp_ldb = imx8mp_ldb;
+		ldb->channel[i] = &imx8mp_ldb->channel[i].base;
+	}
+
+	imx8mp_ldb->clk_root = devm_clk_get(dev, "ldb");
+	if (IS_ERR(imx8mp_ldb->clk_root))
+		return PTR_ERR(imx8mp_ldb->clk_root);
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		encoder[i] = &imx8mp_ldb->channel[i].encoder;
+
+		drm_encoder_helper_add(encoder[i],
+				      &imx8mp_ldb_encoder_helper_funcs);
+		drm_encoder_init(drm, encoder[i], &imx8mp_ldb_encoder_funcs,
+				 DRM_MODE_ENCODER_LVDS, NULL);
+	}
+
+	pm_runtime_enable(dev);
+
+	ret = ldb_bind(ldb, encoder);
+	if (ret)
+		goto disable_pm_runtime;
+
+	for_each_child_of_node(np, child) {
+		struct imx8mp_ldb_channel *imx8mp_ldb_ch;
+		bool auxiliary_ch = false;
+
+		ret = of_property_read_u32(child, "reg", &i);
+		if (ret || i < 0 || i > 1) {
+			ret = -EINVAL;
+			goto free_child;
+		}
+
+		if (ldb->dual && i > 0) {
+			auxiliary_ch = true;
+			imx8mp_ldb_ch = &imx8mp_ldb->channel[i];
+			goto get_phy;
+		}
+
+		if (!of_device_is_available(child))
+			continue;
+
+		imx8mp_ldb_ch = &imx8mp_ldb->channel[i];
+get_phy:
+		imx8mp_ldb_ch->phy = devm_of_phy_get(dev, child, "ldb_phy");
+		if (IS_ERR(imx8mp_ldb_ch->phy)) {
+			ret = PTR_ERR(imx8mp_ldb_ch->phy);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "can't get channel%d phy: %d\n",
+					i, ret);
+			goto free_child;
+		}
+
+		ret = phy_init(imx8mp_ldb_ch->phy);
+		if (ret < 0) {
+			dev_err(dev, "failed to initialize channel%d phy: %d\n",
+				i, ret);
+			goto free_child;
+		}
+
+		if (auxiliary_ch)
+			continue;
+	}
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		ldb_ch = &imx8mp_ldb->channel[i].base;
+		if (!ldb_ch->is_valid) {
+			drm_encoder_cleanup(encoder[i]);
+			continue;
+		}
+
+		ret = imx_drm_encoder_parse_of(drm, encoder[i], ldb_ch->child);
+		if (ret)
+			goto disable_pm_runtime;
+	}
+
+	return 0;
+
+free_child:
+	of_node_put(child);
+disable_pm_runtime:
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static void imx8mp_ldb_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct imx8mp_ldb *imx8mp_ldb = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		struct imx8mp_ldb_channel *imx8mp_ldb_ch =
+						&imx8mp_ldb->channel[i];
+
+		if (imx8mp_ldb_ch->phy_is_on)
+			phy_power_off(imx8mp_ldb_ch->phy);
+
+		phy_exit(imx8mp_ldb_ch->phy);
+	}
+
+	pm_runtime_disable(dev);
+}
+
+static const struct component_ops imx8mp_ldb_ops = {
+	.bind	= imx8mp_ldb_bind,
+	.unbind	= imx8mp_ldb_unbind,
+};
+
+static int imx8mp_ldb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx8mp_ldb *imx8mp_ldb;
+
+	imx8mp_ldb = devm_kzalloc(dev, sizeof(*imx8mp_ldb), GFP_KERNEL);
+	if (!imx8mp_ldb)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, imx8mp_ldb);
+
+	return component_add(dev, &imx8mp_ldb_ops);
+}
+
+static int imx8mp_ldb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx8mp_ldb_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx8mp_ldb_suspend(struct device *dev)
+{
+	struct imx8mp_ldb *imx8mp_ldb = dev_get_drvdata(dev);
+	int i;
+
+	if (imx8mp_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++)
+		phy_exit(imx8mp_ldb->channel[i].phy);
+
+	return 0;
+}
+
+static int imx8mp_ldb_resume(struct device *dev)
+{
+	struct imx8mp_ldb *imx8mp_ldb = dev_get_drvdata(dev);
+	int i;
+
+	if (imx8mp_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++)
+		phy_init(imx8mp_ldb->channel[i].phy);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx8mp_ldb_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(imx8mp_ldb_suspend, imx8mp_ldb_resume)
+};
+
+static struct platform_driver imx8mp_ldb_driver = {
+	.probe		= imx8mp_ldb_probe,
+	.remove		= imx8mp_ldb_remove,
+	.driver		= {
+		.of_match_table = imx8mp_ldb_dt_ids,
+		.name	= DRIVER_NAME,
+		.pm	= &imx8mp_ldb_pm_ops,
+	},
+};
+
+module_platform_driver(imx8mp_ldb_driver);
+
+MODULE_DESCRIPTION("i.MX8MP LVDS driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx8qm-ldb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx8qm-ldb.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mixel-lvds.h>
+
+#include <drm/bridge/fsl_imx_ldb.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "imx8qm-ldb"
+
+#define LDB_CH0_MODE_EN_TO_DI0		(1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1		(3 << 0)
+#define LDB_CH0_MODE_EN_MASK		(3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0		(1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1		(3 << 2)
+#define LDB_CH1_MODE_EN_MASK		(3 << 2)
+#define LDB_BIT_MAP_CH0_JEIDA		(1 << 6)
+#define LDB_BIT_MAP_CH1_JEIDA		(1 << 8)
+#define LDB_CH0_10BIT_EN		(1 << 22)
+#define LDB_CH1_10BIT_EN		(1 << 23)
+#define LDB_CH0_DATA_WIDTH_24BIT	(1 << 24)
+#define LDB_CH1_DATA_WIDTH_24BIT	(1 << 26)
+#define LDB_CH0_DATA_WIDTH_30BIT	(2 << 24)
+#define LDB_CH1_DATA_WIDTH_30BIT	(2 << 26)
+
+struct imx8qm_ldb;
+
+struct imx8qm_ldb_channel {
+	struct ldb_channel base;
+	struct imx8qm_ldb *imx8qm_ldb;
+
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+
+	struct phy *phy;
+	bool phy_is_on;
+
+	u32 bus_flags;
+};
+
+static inline struct imx8qm_ldb_channel *
+con_to_imx8qm_ldb_ch(struct drm_connector *c)
+{
+	return container_of(c, struct imx8qm_ldb_channel, connector);
+}
+
+static inline struct imx8qm_ldb_channel *
+enc_to_imx8qm_ldb_ch(struct drm_encoder *e)
+{
+	return container_of(e, struct imx8qm_ldb_channel, encoder);
+}
+
+struct imx8qm_ldb {
+	struct ldb base;
+	struct imx8qm_ldb_channel channel[LDB_CH_NUM];
+	struct clk *clk_pixel;
+	struct clk *clk_bypass;
+	struct imx_sc_ipc *handle;
+
+	int id;
+};
+
+static void
+imx8qm_ldb_ch_set_bus_format(struct imx8qm_ldb_channel *imx8qm_ldb_ch,
+			     u32 bus_format)
+{
+	struct imx8qm_ldb *imx8qm_ldb = imx8qm_ldb_ch->imx8qm_ldb;
+	struct ldb *ldb = &imx8qm_ldb->base;
+	struct ldb_channel *ldb_ch = &imx8qm_ldb_ch->base;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+					 LDB_CH0_DATA_WIDTH_30BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+					 LDB_CH1_DATA_WIDTH_30BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+					 LDB_CH0_DATA_WIDTH_30BIT |
+					 LDB_BIT_MAP_CH0_JEIDA;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+					 LDB_CH1_DATA_WIDTH_30BIT |
+					 LDB_BIT_MAP_CH1_JEIDA;
+		break;
+	}
+}
+
+static struct drm_encoder *imx8qm_ldb_connector_best_encoder(
+		struct drm_connector *connector)
+{
+	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						con_to_imx8qm_ldb_ch(connector);
+
+	return &imx8qm_ldb_ch->encoder;
+}
+
+static void imx8qm_ldb_pxlink_set_mst_valid(struct imx8qm_ldb *imx8qm_ldb,
+					    int dc_id, bool enable)
+{
+	u32 rsc = dc_id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+
+	imx_sc_misc_set_control(imx8qm_ldb->handle,
+				rsc, IMX_SC_C_PXL_LINK_MST2_VLD, enable);
+}
+
+static void imx8qm_ldb_pxlink_set_sync_ctrl(struct imx8qm_ldb *imx8qm_ldb,
+					    int dc_id, bool enable)
+{
+	u32 rsc = dc_id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+
+	imx_sc_misc_set_control(imx8qm_ldb->handle,
+				rsc, IMX_SC_C_SYNC_CTRL1, enable);
+}
+
+static void imx8qm_ldb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						enc_to_imx8qm_ldb_ch(encoder);
+	struct imx8qm_ldb *imx8qm_ldb = imx8qm_ldb_ch->imx8qm_ldb;
+	struct ldb *ldb = &imx8qm_ldb->base;
+
+	clk_prepare_enable(imx8qm_ldb->clk_pixel);
+	clk_prepare_enable(imx8qm_ldb->clk_bypass);
+
+	if (imx8qm_ldb_ch == &imx8qm_ldb->channel[0] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+		ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
+	}
+	if (imx8qm_ldb_ch == &imx8qm_ldb->channel[1] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+		ldb->ldb_ctrl |= ldb->dual ?
+				LDB_CH1_MODE_EN_TO_DI0 : LDB_CH1_MODE_EN_TO_DI1;
+	}
+
+	if (ldb->dual) {
+		phy_power_on(imx8qm_ldb->channel[0].phy);
+		phy_power_on(imx8qm_ldb->channel[1].phy);
+
+		imx8qm_ldb->channel[0].phy_is_on = true;
+		imx8qm_ldb->channel[1].phy_is_on = true;
+	} else {
+		phy_power_on(imx8qm_ldb_ch->phy);
+
+		imx8qm_ldb_ch->phy_is_on = true;
+	}
+
+	imx8qm_ldb_pxlink_set_mst_valid(imx8qm_ldb, imx8qm_ldb->id, true);
+	imx8qm_ldb_pxlink_set_sync_ctrl(imx8qm_ldb, imx8qm_ldb->id, true);
+}
+
+static void
+imx8qm_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *connector_state)
+{
+	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						enc_to_imx8qm_ldb_ch(encoder);
+	struct imx8qm_ldb *imx8qm_ldb = imx8qm_ldb_ch->imx8qm_ldb;
+	struct ldb_channel *ldb_ch = &imx8qm_ldb_ch->base;
+	struct ldb *ldb = &imx8qm_ldb->base;
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	unsigned long di_clk = mode->clock * 1000;
+
+	if (mode->clock > 300000) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 300 MHz pixel clock\n", __func__);
+	}
+	if (mode->clock > 150000 && !ldb->dual) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 150 MHz pixel clock\n", __func__);
+	}
+
+	clk_set_rate(imx8qm_ldb->clk_bypass, di_clk);
+	clk_set_rate(imx8qm_ldb->clk_pixel, di_clk);
+
+	if (ldb->dual) {
+		mixel_phy_lvds_set_phy_speed(imx8qm_ldb->channel[0].phy,
+								di_clk / 2);
+		mixel_phy_lvds_set_phy_speed(imx8qm_ldb->channel[1].phy,
+								di_clk / 2);
+	} else {
+		mixel_phy_lvds_set_phy_speed(imx8qm_ldb_ch->phy, di_clk);
+	}
+
+	if (ldb->dual) {
+		/* VSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC) {
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb->channel[0].phy,
+						     false);
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb->channel[1].phy,
+						     false);
+		} else if (mode->flags & DRM_MODE_FLAG_PVSYNC) {
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb->channel[0].phy,
+						     true);
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb->channel[1].phy,
+						     true);
+		}
+		/* HSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb->channel[0].phy,
+						     false);
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb->channel[1].phy,
+						     false);
+		} else if (mode->flags & DRM_MODE_FLAG_PHSYNC) {
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb->channel[0].phy,
+						     true);
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb->channel[1].phy,
+						     true);
+		}
+	} else {
+		/* VSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb_ch->phy, false);
+		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			mixel_phy_lvds_set_vsync_pol(imx8qm_ldb_ch->phy, true);
+		/* HSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb_ch->phy, false);
+		else if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+			mixel_phy_lvds_set_hsync_pol(imx8qm_ldb_ch->phy, true);
+	}
+
+	if (!ldb_ch->bus_format) {
+		struct drm_connector *connector = connector_state->connector;
+		struct drm_display_info *di = &connector->display_info;
+
+		if (di->num_bus_formats)
+			ldb_ch->bus_format = di->bus_formats[0];
+	}
+	imx8qm_ldb_ch_set_bus_format(imx8qm_ldb_ch, ldb_ch->bus_format);
+}
+
+static void imx8qm_ldb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						enc_to_imx8qm_ldb_ch(encoder);
+	struct imx8qm_ldb *imx8qm_ldb = imx8qm_ldb_ch->imx8qm_ldb;
+	struct ldb *ldb = &imx8qm_ldb->base;
+
+	imx8qm_ldb_pxlink_set_mst_valid(imx8qm_ldb, imx8qm_ldb->id, false);
+	imx8qm_ldb_pxlink_set_sync_ctrl(imx8qm_ldb, imx8qm_ldb->id, false);
+
+	if (ldb->dual) {
+		phy_power_off(imx8qm_ldb->channel[0].phy);
+		phy_power_off(imx8qm_ldb->channel[1].phy);
+
+		imx8qm_ldb->channel[0].phy_is_on = false;
+		imx8qm_ldb->channel[1].phy_is_on = false;
+	} else {
+		phy_power_off(imx8qm_ldb_ch->phy);
+
+		imx8qm_ldb_ch->phy_is_on = false;
+	}
+
+	clk_disable_unprepare(imx8qm_ldb->clk_bypass);
+	clk_disable_unprepare(imx8qm_ldb->clk_pixel);
+}
+
+static int
+imx8qm_ldb_encoder_atomic_check(struct drm_encoder *encoder,
+				struct drm_crtc_state *crtc_state,
+				struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						enc_to_imx8qm_ldb_ch(encoder);
+	struct ldb_channel *ldb_ch = &imx8qm_ldb_ch->base;
+	struct drm_display_info *di = &conn_state->connector->display_info;
+	u32 bus_format = ldb_ch->bus_format;
+
+	/* Bus format description in DT overrides connector display info. */
+	if (!bus_format && di->num_bus_formats) {
+		bus_format = di->bus_formats[0];
+		imx_crtc_state->bus_flags = di->bus_flags;
+	} else {
+		bus_format = ldb_ch->bus_format;
+		imx_crtc_state->bus_flags = imx8qm_ldb_ch->bus_flags;
+	}
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X30_PADLO;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X30_PADLO;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct drm_connector_funcs imx8qm_ldb_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = imx_drm_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs
+imx8qm_ldb_connector_helper_funcs = {
+	.best_encoder = imx8qm_ldb_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs imx8qm_ldb_encoder_funcs = {
+	.destroy = imx_drm_encoder_destroy,
+};
+
+static const struct drm_encoder_helper_funcs imx8qm_ldb_encoder_helper_funcs = {
+	.atomic_mode_set = imx8qm_ldb_encoder_atomic_mode_set,
+	.enable = imx8qm_ldb_encoder_enable,
+	.disable = imx8qm_ldb_encoder_disable,
+	.atomic_check = imx8qm_ldb_encoder_atomic_check,
+};
+
+static const struct of_device_id imx8qm_ldb_dt_ids[] = {
+	{ .compatible = "fsl,imx8qm-ldb", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, imx8qm_ldb_dt_ids);
+
+static int
+imx8qm_ldb_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb;
+	struct ldb_channel *ldb_ch;
+	struct drm_encoder *encoder[LDB_CH_NUM];
+	int ret;
+	int i;
+
+	ldb = &imx8qm_ldb->base;
+	ldb->dev = dev;
+	ldb->ctrl_reg = 0xe0;
+	ldb->output_port = 1;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		imx8qm_ldb->channel[i].imx8qm_ldb = imx8qm_ldb;
+		ldb->channel[i] = &imx8qm_ldb->channel[i].base;
+	}
+
+	ret = imx_scu_get_handle(&imx8qm_ldb->handle);
+	if (ret) {
+		dev_err(dev, "failed to get scu ipc handle %d\n", ret);
+		return ret;
+	}
+
+	imx8qm_ldb->id = of_alias_get_id(np, "ldb");
+
+	imx8qm_ldb->clk_pixel = devm_clk_get(dev, "pixel");
+	if (IS_ERR(imx8qm_ldb->clk_pixel))
+		return PTR_ERR(imx8qm_ldb->clk_pixel);
+
+	imx8qm_ldb->clk_bypass = devm_clk_get(dev, "bypass");
+	if (IS_ERR(imx8qm_ldb->clk_bypass))
+		return PTR_ERR(imx8qm_ldb->clk_bypass);
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		encoder[i] = &imx8qm_ldb->channel[i].encoder;
+
+		drm_encoder_helper_add(encoder[i],
+				      &imx8qm_ldb_encoder_helper_funcs);
+		drm_encoder_init(drm, encoder[i], &imx8qm_ldb_encoder_funcs,
+				 DRM_MODE_ENCODER_LVDS, NULL);
+	}
+
+	pm_runtime_enable(dev);
+
+	ret = ldb_bind(ldb, encoder);
+	if (ret)
+		goto disable_pm_runtime;
+
+	for_each_child_of_node(np, child) {
+		struct imx8qm_ldb_channel *imx8qm_ldb_ch;
+		bool auxiliary_ch = false;
+
+		ret = of_property_read_u32(child, "reg", &i);
+		if (ret || i < 0 || i > 1) {
+			ret = -EINVAL;
+			goto free_child;
+		}
+
+		if (ldb->dual && i > 0) {
+			auxiliary_ch = true;
+			imx8qm_ldb_ch = &imx8qm_ldb->channel[i];
+			goto get_phy;
+		}
+
+		if (!of_device_is_available(child))
+			continue;
+
+		imx8qm_ldb_ch = &imx8qm_ldb->channel[i];
+get_phy:
+		imx8qm_ldb_ch->phy = devm_of_phy_get(dev, child, "ldb_phy");
+		if (IS_ERR(imx8qm_ldb_ch->phy)) {
+			ret = PTR_ERR(imx8qm_ldb_ch->phy);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "can't get channel%d phy: %d\n",
+					i, ret);
+			goto free_child;
+		}
+
+		ret = phy_init(imx8qm_ldb_ch->phy);
+		if (ret < 0) {
+			dev_err(dev, "failed to initialize channel%d phy: %d\n",
+				i, ret);
+			goto free_child;
+		}
+
+		if (auxiliary_ch)
+			continue;
+	}
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		ldb_ch = &imx8qm_ldb->channel[i].base;
+		if (!ldb_ch->is_valid) {
+			drm_encoder_cleanup(encoder[i]);
+			continue;
+		}
+
+		ret = imx_drm_encoder_parse_of(drm, encoder[i], ldb_ch->child);
+		if (ret)
+			goto disable_pm_runtime;
+	}
+
+	return 0;
+
+free_child:
+	of_node_put(child);
+disable_pm_runtime:
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static void imx8qm_ldb_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		struct imx8qm_ldb_channel *imx8qm_ldb_ch =
+						&imx8qm_ldb->channel[i];
+
+		if (imx8qm_ldb_ch->phy_is_on)
+			phy_power_off(imx8qm_ldb_ch->phy);
+
+		phy_exit(imx8qm_ldb_ch->phy);
+	}
+
+	pm_runtime_disable(dev);
+}
+
+static const struct component_ops imx8qm_ldb_ops = {
+	.bind	= imx8qm_ldb_bind,
+	.unbind	= imx8qm_ldb_unbind,
+};
+
+static int imx8qm_ldb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx8qm_ldb *imx8qm_ldb;
+
+	imx8qm_ldb = devm_kzalloc(dev, sizeof(*imx8qm_ldb), GFP_KERNEL);
+	if (!imx8qm_ldb)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, imx8qm_ldb);
+
+	return component_add(dev, &imx8qm_ldb_ops);
+}
+
+static int imx8qm_ldb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx8qm_ldb_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx8qm_ldb_suspend(struct device *dev)
+{
+	struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev);
+	int i;
+
+	if (imx8qm_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++)
+		phy_exit(imx8qm_ldb->channel[i].phy);
+
+	return 0;
+}
+
+static int imx8qm_ldb_resume(struct device *dev)
+{
+	struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev);
+	int i;
+
+	if (imx8qm_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++)
+		phy_init(imx8qm_ldb->channel[i].phy);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx8qm_ldb_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(imx8qm_ldb_suspend, imx8qm_ldb_resume)
+};
+
+static struct platform_driver imx8qm_ldb_driver = {
+	.probe		= imx8qm_ldb_probe,
+	.remove		= imx8qm_ldb_remove,
+	.driver		= {
+		.of_match_table = imx8qm_ldb_dt_ids,
+		.name	= DRIVER_NAME,
+		.pm	= &imx8qm_ldb_pm_ops,
+	},
+};
+
+module_platform_driver(imx8qm_ldb_driver);
+
+MODULE_DESCRIPTION("i.MX8QM LVDS driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/imx8qxp-ldb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/imx8qxp-ldb.c
@@ -0,0 +1,880 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mixel-lvds-combo.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+
+#include <drm/bridge/fsl_imx_ldb.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "imx8qxp-ldb"
+
+#define LDB_CH0_MODE_EN_TO_DI0		(1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1		(3 << 0)
+#define LDB_CH0_MODE_EN_MASK		(3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0		(1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1		(3 << 2)
+#define LDB_CH1_MODE_EN_MASK		(3 << 2)
+#define LDB_BIT_MAP_CH0_JEIDA		(1 << 6)
+#define LDB_BIT_MAP_CH1_JEIDA		(1 << 8)
+#define LDB_DI0_VS_POL_ACT_LOW		(1 << 9)
+#define LDB_DI1_VS_POL_ACT_LOW		(1 << 10)
+#define LDB_CH0_10BIT_EN		(1 << 22)
+#define LDB_CH1_10BIT_EN		(1 << 23)
+#define LDB_CH0_DATA_WIDTH_24BIT	(1 << 24)
+#define LDB_CH1_DATA_WIDTH_24BIT	(1 << 26)
+#define LDB_CH0_DATA_WIDTH_30BIT	(2 << 24)
+#define LDB_CH1_DATA_WIDTH_30BIT	(2 << 26)
+#define LDB_CH_SEL			(1 << 28)
+
+struct imx8qxp_ldb;
+
+struct imx8qxp_ldb_channel {
+	struct ldb_channel base;
+	struct imx8qxp_ldb *imx8qxp_ldb;
+
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+
+	struct phy *phy;
+	struct phy *aux_phy;
+	bool phy_is_on;
+
+	u32 bus_flags;
+};
+
+static inline struct imx8qxp_ldb_channel *
+con_to_imx8qxp_ldb_ch(struct drm_connector *c)
+{
+	return container_of(c, struct imx8qxp_ldb_channel, connector);
+}
+
+static inline struct imx8qxp_ldb_channel *
+enc_to_imx8qxp_ldb_ch(struct drm_encoder *e)
+{
+	return container_of(e, struct imx8qxp_ldb_channel, encoder);
+}
+
+struct imx8qxp_ldb {
+	struct ldb base;
+	struct regmap *aux_regmap;
+	struct imx8qxp_ldb_channel channel[LDB_CH_NUM];
+	struct clk *clk_pixel;
+	struct clk *clk_bypass;
+	struct clk *clk_aux_pixel;
+	struct clk *clk_aux_bypass;
+	struct imx_sc_ipc *handle;
+
+	struct device *pd_main_dev;
+	struct device *pd_aux_dev;
+	struct device_link *pd_main_link;
+	struct device_link *pd_aux_link;
+
+	int id;
+};
+
+static void
+imx8qxp_ldb_ch_set_bus_format(struct imx8qxp_ldb_channel *imx8qxp_ldb_ch,
+			      u32 bus_format)
+{
+	struct imx8qxp_ldb *imx8qxp_ldb = imx8qxp_ldb_ch->imx8qxp_ldb;
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+					 LDB_CH0_DATA_WIDTH_30BIT;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+					 LDB_CH1_DATA_WIDTH_30BIT;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+		if (ldb_ch->chno == 0 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+					 LDB_CH0_DATA_WIDTH_30BIT |
+					 LDB_BIT_MAP_CH0_JEIDA;
+		if (ldb_ch->chno == 1 || ldb->dual)
+			ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+					 LDB_CH1_DATA_WIDTH_30BIT |
+					 LDB_BIT_MAP_CH1_JEIDA;
+		break;
+	}
+}
+
+static struct drm_encoder *imx8qxp_ldb_connector_best_encoder(
+		struct drm_connector *connector)
+{
+	struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+					con_to_imx8qxp_ldb_ch(connector);
+
+	return &imx8qxp_ldb_ch->encoder;
+}
+
+static void imx8qxp_ldb_pxlink_enable(struct imx8qxp_ldb *imx8qxp_ldb,
+				      int stream_id, bool enable)
+{
+	u8 ctrl = stream_id ?
+		IMX_SC_C_PXL_LINK_MST2_ENB : IMX_SC_C_PXL_LINK_MST1_ENB;
+
+	imx_sc_misc_set_control(imx8qxp_ldb->handle,
+				IMX_SC_R_DC_0, ctrl, enable);
+}
+
+static void imx8qxp_ldb_pxlink_set_mst_valid(struct imx8qxp_ldb *imx8qxp_ldb,
+					     int stream_id, bool enable)
+{
+	u8 ctrl = stream_id ?
+		IMX_SC_C_PXL_LINK_MST2_VLD : IMX_SC_C_PXL_LINK_MST1_VLD;
+
+	imx_sc_misc_set_control(imx8qxp_ldb->handle,
+					IMX_SC_R_DC_0, ctrl, enable);
+}
+
+static void imx8qxp_ldb_pxlink_set_sync_ctrl(struct imx8qxp_ldb *imx8qxp_ldb,
+					     int stream_id, bool enable)
+{
+	u8 ctrl = stream_id ? IMX_SC_C_SYNC_CTRL1 : IMX_SC_C_SYNC_CTRL0;
+
+	imx_sc_misc_set_control(imx8qxp_ldb->handle,
+					IMX_SC_R_DC_0, ctrl, enable);
+}
+
+static void imx8qxp_ldb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+						enc_to_imx8qxp_ldb_ch(encoder);
+	struct imx8qxp_ldb *imx8qxp_ldb = imx8qxp_ldb_ch->imx8qxp_ldb;
+	struct ldb *ldb = &imx8qxp_ldb->base;
+
+	clk_prepare_enable(imx8qxp_ldb->clk_pixel);
+	clk_prepare_enable(imx8qxp_ldb->clk_bypass);
+
+	if (ldb->dual) {
+		clk_prepare_enable(imx8qxp_ldb->clk_aux_pixel);
+		clk_prepare_enable(imx8qxp_ldb->clk_aux_bypass);
+	}
+
+	/*
+	 * LDB frontend doesn't know if the auxiliary LDB is used or not.
+	 * Enable pixel link after dual or single LDB clocks are enabled
+	 * so that the dual LDBs are synchronized.
+	 */
+	imx8qxp_ldb_pxlink_enable(imx8qxp_ldb, imx8qxp_ldb->id, true);
+
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[0] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+		ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
+	}
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[1] || ldb->dual) {
+		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+		ldb->ldb_ctrl |= ldb->dual ?
+				LDB_CH1_MODE_EN_TO_DI0 : LDB_CH1_MODE_EN_TO_DI1;
+	}
+
+	pm_runtime_get_sync(ldb->dev);
+
+	regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
+	if (ldb->dual)
+		regmap_write(imx8qxp_ldb->aux_regmap, ldb->ctrl_reg,
+						ldb->ldb_ctrl | LDB_CH_SEL);
+
+	if (ldb->dual) {
+		phy_power_on(imx8qxp_ldb->channel[0].phy);
+		phy_power_on(imx8qxp_ldb->channel[0].aux_phy);
+
+		imx8qxp_ldb->channel[0].phy_is_on = true;
+	} else {
+		phy_power_on(imx8qxp_ldb_ch->phy);
+
+		imx8qxp_ldb_ch->phy_is_on = true;
+	}
+
+	imx8qxp_ldb_pxlink_set_mst_valid(imx8qxp_ldb, imx8qxp_ldb->id, true);
+	imx8qxp_ldb_pxlink_set_sync_ctrl(imx8qxp_ldb, imx8qxp_ldb->id, true);
+}
+
+static void
+imx8qxp_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *connector_state)
+{
+	struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+						enc_to_imx8qxp_ldb_ch(encoder);
+	struct imx8qxp_ldb *imx8qxp_ldb = imx8qxp_ldb_ch->imx8qxp_ldb;
+	struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	unsigned long di_clk = mode->clock * 1000;
+
+	if (mode->clock > 300000) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 300 MHz pixel clock\n", __func__);
+	}
+	if (mode->clock > 150000 && !ldb->dual) {
+		dev_warn(ldb->dev,
+			 "%s: mode exceeds 150 MHz pixel clock\n", __func__);
+	}
+
+	clk_set_rate(imx8qxp_ldb->clk_bypass, di_clk);
+	clk_set_rate(imx8qxp_ldb->clk_pixel, di_clk);
+
+	if (ldb->dual) {
+		clk_set_rate(imx8qxp_ldb->clk_aux_bypass, di_clk);
+		clk_set_rate(imx8qxp_ldb->clk_aux_pixel, di_clk);
+	}
+
+	if (ldb->dual) {
+		mixel_phy_combo_lvds_set_phy_speed(imx8qxp_ldb->channel[0].phy,
+								di_clk / 2);
+		mixel_phy_combo_lvds_set_phy_speed(imx8qxp_ldb->channel[0].aux_phy,
+								di_clk / 2);
+	} else {
+		mixel_phy_combo_lvds_set_phy_speed(imx8qxp_ldb_ch->phy, di_clk);
+	}
+
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[0])
+		ldb->ldb_ctrl &= ~LDB_CH_SEL;
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[1])
+		ldb->ldb_ctrl |= LDB_CH_SEL;
+
+	/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[0] || ldb->dual) {
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
+		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
+	}
+	if (imx8qxp_ldb_ch == &imx8qxp_ldb->channel[1] || ldb->dual) {
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
+		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
+	}
+
+	pm_runtime_get_sync(ldb->dev);
+
+	/* settle vsync polarity and channel selection down early */
+	if (ldb->dual) {
+		regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
+		regmap_write(imx8qxp_ldb->aux_regmap, ldb->ctrl_reg,
+						ldb->ldb_ctrl | LDB_CH_SEL);
+	}
+
+	pm_runtime_put(ldb->dev);
+
+	if (ldb->dual) {
+		/* VSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC) {
+			mixel_phy_combo_lvds_set_vsync_pol(
+				imx8qxp_ldb->channel[0].phy, false);
+			mixel_phy_combo_lvds_set_vsync_pol(
+				imx8qxp_ldb->channel[0].aux_phy, false);
+		} else {
+			mixel_phy_combo_lvds_set_vsync_pol(
+				imx8qxp_ldb->channel[0].phy, true);
+			mixel_phy_combo_lvds_set_vsync_pol(
+				imx8qxp_ldb->channel[0].aux_phy, true);
+		}
+		/* HSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
+			mixel_phy_combo_lvds_set_hsync_pol(
+				imx8qxp_ldb->channel[0].phy, false);
+			mixel_phy_combo_lvds_set_hsync_pol(
+				imx8qxp_ldb->channel[0].aux_phy, false);
+		} else {
+			mixel_phy_combo_lvds_set_hsync_pol(
+				imx8qxp_ldb->channel[0].phy, true);
+			mixel_phy_combo_lvds_set_hsync_pol(
+				imx8qxp_ldb->channel[0].aux_phy, true);
+		}
+	} else {
+		/* VSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			mixel_phy_combo_lvds_set_vsync_pol(imx8qxp_ldb_ch->phy,
+							   false);
+		else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			mixel_phy_combo_lvds_set_vsync_pol(imx8qxp_ldb_ch->phy,
+							   true);
+		/* HSYNC */
+		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			mixel_phy_combo_lvds_set_hsync_pol(imx8qxp_ldb_ch->phy,
+							   false);
+		else if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+			mixel_phy_combo_lvds_set_hsync_pol(imx8qxp_ldb_ch->phy,
+							   true);
+	}
+
+	if (!ldb_ch->bus_format) {
+		struct drm_connector *connector = connector_state->connector;
+		struct drm_display_info *di = &connector->display_info;
+
+		if (di->num_bus_formats)
+			ldb_ch->bus_format = di->bus_formats[0];
+	}
+	imx8qxp_ldb_ch_set_bus_format(imx8qxp_ldb_ch, ldb_ch->bus_format);
+}
+
+static void imx8qxp_ldb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+						enc_to_imx8qxp_ldb_ch(encoder);
+	struct imx8qxp_ldb *imx8qxp_ldb = imx8qxp_ldb_ch->imx8qxp_ldb;
+	struct ldb *ldb = &imx8qxp_ldb->base;
+
+	imx8qxp_ldb_pxlink_set_mst_valid(imx8qxp_ldb, imx8qxp_ldb->id, false);
+	imx8qxp_ldb_pxlink_set_sync_ctrl(imx8qxp_ldb, imx8qxp_ldb->id, false);
+
+	if (ldb->dual) {
+		phy_power_off(imx8qxp_ldb->channel[0].phy);
+		phy_power_off(imx8qxp_ldb->channel[0].aux_phy);
+
+		imx8qxp_ldb->channel[0].phy_is_on = false;
+	} else {
+		phy_power_off(imx8qxp_ldb_ch->phy);
+
+		imx8qxp_ldb_ch->phy_is_on = false;
+	}
+
+	if (ldb->dual)
+		regmap_write(imx8qxp_ldb->aux_regmap,
+					ldb->ctrl_reg, ldb->ldb_ctrl);
+
+	pm_runtime_put(ldb->dev);
+
+	clk_disable_unprepare(imx8qxp_ldb->clk_bypass);
+	clk_disable_unprepare(imx8qxp_ldb->clk_pixel);
+
+	if (ldb->dual) {
+		clk_disable_unprepare(imx8qxp_ldb->clk_aux_bypass);
+		clk_disable_unprepare(imx8qxp_ldb->clk_aux_pixel);
+	}
+
+	imx8qxp_ldb_pxlink_enable(imx8qxp_ldb, imx8qxp_ldb->id, false);
+}
+
+static int
+imx8qxp_ldb_encoder_atomic_check(struct drm_encoder *encoder,
+				 struct drm_crtc_state *crtc_state,
+				 struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+						enc_to_imx8qxp_ldb_ch(encoder);
+	struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
+	struct drm_display_info *di = &conn_state->connector->display_info;
+	u32 bus_format = ldb_ch->bus_format;
+
+	/* Bus format description in DT overrides connector display info. */
+	if (!bus_format && di->num_bus_formats) {
+		bus_format = di->bus_formats[0];
+		imx_crtc_state->bus_flags = di->bus_flags;
+	} else {
+		bus_format = ldb_ch->bus_format;
+		imx_crtc_state->bus_flags = imx8qxp_ldb_ch->bus_flags;
+	}
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X30_PADLO;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X30_PADLO;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+	case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct drm_connector_funcs imx8qxp_ldb_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = imx_drm_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs
+imx8qxp_ldb_connector_helper_funcs = {
+	.best_encoder = imx8qxp_ldb_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs imx8qxp_ldb_encoder_funcs = {
+	.destroy = imx_drm_encoder_destroy,
+};
+
+static const struct drm_encoder_helper_funcs
+imx8qxp_ldb_encoder_helper_funcs = {
+	.atomic_mode_set = imx8qxp_ldb_encoder_atomic_mode_set,
+	.enable = imx8qxp_ldb_encoder_enable,
+	.disable = imx8qxp_ldb_encoder_disable,
+	.atomic_check = imx8qxp_ldb_encoder_atomic_check,
+};
+
+static const struct of_device_id imx8qxp_ldb_dt_ids[] = {
+	{ .compatible = "fsl,imx8qxp-ldb", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, imx8qxp_ldb_dt_ids);
+
+static void imx8qxp_ldb_detach_pm_domains(struct imx8qxp_ldb *imx8qxp_ldb)
+{
+	if (imx8qxp_ldb->pd_aux_link && !IS_ERR(imx8qxp_ldb->pd_aux_link))
+		device_link_del(imx8qxp_ldb->pd_aux_link);
+	if (imx8qxp_ldb->pd_aux_dev && !IS_ERR(imx8qxp_ldb->pd_aux_dev))
+		dev_pm_domain_detach(imx8qxp_ldb->pd_aux_dev, true);
+
+	if (imx8qxp_ldb->pd_main_link && !IS_ERR(imx8qxp_ldb->pd_main_link))
+		device_link_del(imx8qxp_ldb->pd_main_link);
+	if (imx8qxp_ldb->pd_main_dev && !IS_ERR(imx8qxp_ldb->pd_main_dev))
+		dev_pm_domain_detach(imx8qxp_ldb->pd_main_dev, true);
+
+	imx8qxp_ldb->pd_aux_dev = NULL;
+	imx8qxp_ldb->pd_aux_link = NULL;
+	imx8qxp_ldb->pd_main_dev = NULL;
+	imx8qxp_ldb->pd_main_link = NULL;
+}
+
+static int
+imx8qxp_ldb_attach_pm_domains(struct imx8qxp_ldb *imx8qxp_ldb, bool dual)
+{
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	struct device *dev = ldb->dev;
+	u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
+	int ret = 0;
+
+	imx8qxp_ldb->pd_main_dev = dev_pm_domain_attach_by_name(dev, "main");
+	if (IS_ERR(imx8qxp_ldb->pd_main_dev)) {
+		ret = PTR_ERR(imx8qxp_ldb->pd_main_dev);
+		dev_err(dev, "Failed to attach main pd dev: %d\n", ret);
+		goto fail;
+	}
+	imx8qxp_ldb->pd_main_link = device_link_add(dev,
+					imx8qxp_ldb->pd_main_dev, flags);
+	if (IS_ERR(imx8qxp_ldb->pd_main_link)) {
+		ret = PTR_ERR(imx8qxp_ldb->pd_main_link);
+		dev_err(dev, "Failed to add device link to main pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	if (!dual)
+		goto out;
+
+	imx8qxp_ldb->pd_aux_dev = dev_pm_domain_attach_by_name(dev, "aux");
+	if (IS_ERR(imx8qxp_ldb->pd_aux_dev)) {
+		ret = PTR_ERR(imx8qxp_ldb->pd_aux_dev);
+		dev_err(dev, "Failed to attach aux pd dev: %d\n", ret);
+		goto fail;
+	}
+	imx8qxp_ldb->pd_aux_link = device_link_add(dev,
+					imx8qxp_ldb->pd_aux_dev, flags);
+	if (IS_ERR(imx8qxp_ldb->pd_aux_link)) {
+		ret = PTR_ERR(imx8qxp_ldb->pd_aux_link);
+		dev_err(dev, "Failed to add device link to aux pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+out:
+	return ret;
+fail:
+	imx8qxp_ldb_detach_pm_domains(imx8qxp_ldb);
+	return ret;
+}
+
+static int imx8qxp_ldb_init_sc_misc(int ldb_id, bool dual)
+{
+	struct imx_sc_ipc *handle;
+	u32 rsc;
+	bool is_aux = false;
+	int ret = 0;
+
+	imx_scu_get_handle(&handle);
+
+again:
+	rsc = ldb_id ? IMX_SC_R_MIPI_1 : IMX_SC_R_MIPI_0;
+
+	ret |= imx_sc_misc_set_control(handle,
+				       rsc, IMX_SC_C_MODE, 1);
+	ret |= imx_sc_misc_set_control(handle,
+				       rsc, IMX_SC_C_DUAL_MODE, is_aux);
+	ret |= imx_sc_misc_set_control(handle,
+				       rsc, IMX_SC_C_PXL_LINK_SEL, is_aux);
+
+	if (dual && !is_aux) {
+		ldb_id ^= 1;
+		is_aux = true;
+		goto again;
+	}
+
+	return ret;
+}
+
+static struct phy *imx8qxp_ldb_get_aux_phy(struct device_node *auxldb_np)
+{
+	struct device_node *child;
+	struct phy *phy = NULL;
+	int ret, i;
+
+	for_each_child_of_node(auxldb_np, child) {
+		ret = of_property_read_u32(child, "reg", &i);
+		if (ret || i < 0) {
+			of_node_put(child);
+			return ERR_PTR(-ENODEV);
+		}
+
+		if (i != 1)
+			continue;
+
+		phy = of_phy_get(child, "ldb_phy");
+	}
+
+	of_node_put(child);
+
+	return phy;
+}
+
+static int
+imx8qxp_ldb_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+	struct device_node *np = dev->of_node;
+	struct device_node *auxldb_np = NULL, *child;
+	struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb;
+	struct ldb_channel *ldb_ch;
+	struct drm_encoder *encoder[LDB_CH_NUM];
+	bool dual;
+	int ret;
+	int i;
+
+	ldb = &imx8qxp_ldb->base;
+	ldb->dev = dev;
+	ldb->ctrl_reg = 0xe0;
+	ldb->output_port = 1;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		imx8qxp_ldb->channel[i].imx8qxp_ldb = imx8qxp_ldb;
+		ldb->channel[i] = &imx8qxp_ldb->channel[i].base;
+	}
+
+	ret = imx_scu_get_handle(&imx8qxp_ldb->handle);
+	if (ret) {
+		dev_err(dev, "failed to get scu ipc handle %d\n", ret);
+		return ret;
+	}
+
+	imx8qxp_ldb->id = of_alias_get_id(np, "ldb");
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		encoder[i] = &imx8qxp_ldb->channel[i].encoder;
+
+		drm_encoder_helper_add(encoder[i],
+				      &imx8qxp_ldb_encoder_helper_funcs);
+		drm_encoder_init(drm, encoder[i], &imx8qxp_ldb_encoder_funcs,
+				 DRM_MODE_ENCODER_LVDS, NULL);
+	}
+
+	dual = of_property_read_bool(np, "fsl,dual-channel");
+
+	ret = imx8qxp_ldb_attach_pm_domains(imx8qxp_ldb, dual);
+	if (ret) {
+		dev_err(dev, "failed to attach pm domains %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	ret = ldb_bind(ldb, encoder);
+	if (ret)
+		goto disable_pm_runtime;
+
+	ret = imx8qxp_ldb_init_sc_misc(imx8qxp_ldb->id, ldb->dual);
+	if (ret) {
+		dev_err(dev, "failed to initialize sc misc %d\n", ret);
+		goto disable_pm_runtime;
+	}
+
+	imx8qxp_ldb->clk_pixel = devm_clk_get(dev, "pixel");
+	if (IS_ERR(imx8qxp_ldb->clk_pixel)) {
+		ret = PTR_ERR(imx8qxp_ldb->clk_pixel);
+		goto disable_pm_runtime;
+	}
+
+	imx8qxp_ldb->clk_bypass = devm_clk_get(dev, "bypass");
+	if (IS_ERR(imx8qxp_ldb->clk_bypass)) {
+		ret = PTR_ERR(imx8qxp_ldb->clk_bypass);
+		goto disable_pm_runtime;
+	}
+
+	if (ldb->dual) {
+		imx8qxp_ldb->clk_aux_pixel = devm_clk_get(dev, "aux_pixel");
+		if (IS_ERR(imx8qxp_ldb->clk_aux_pixel)) {
+			ret = PTR_ERR(imx8qxp_ldb->clk_aux_pixel);
+			goto disable_pm_runtime;
+		}
+
+		imx8qxp_ldb->clk_aux_bypass = devm_clk_get(dev, "aux_bypass");
+		if (IS_ERR(imx8qxp_ldb->clk_aux_bypass)) {
+			ret = PTR_ERR(imx8qxp_ldb->clk_aux_bypass);
+			goto disable_pm_runtime;
+		}
+
+		auxldb_np = of_parse_phandle(np, "fsl,auxldb", 0);
+		if (!auxldb_np) {
+			dev_err(dev,
+				"failed to find aux LDB node in device tree\n");
+			ret = -ENODEV;
+			goto disable_pm_runtime;
+		}
+
+		if (of_device_is_available(auxldb_np)) {
+			dev_err(dev, "aux LDB node is already in use\n");
+			of_node_put(auxldb_np);
+			ret = -ENODEV;
+			goto disable_pm_runtime;
+		}
+
+		imx8qxp_ldb->aux_regmap =
+			syscon_regmap_lookup_by_phandle(auxldb_np, "gpr");
+		if (IS_ERR(imx8qxp_ldb->aux_regmap)) {
+			ret = PTR_ERR(imx8qxp_ldb->aux_regmap);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to get aux regmap\n");
+			of_node_put(auxldb_np);
+			goto disable_pm_runtime;
+		}
+
+		pm_runtime_get_sync(dev);
+		regmap_write(imx8qxp_ldb->aux_regmap, ldb->ctrl_reg, 0);
+		pm_runtime_put(dev);
+	}
+
+	for_each_child_of_node(np, child) {
+		struct imx8qxp_ldb_channel *imx8qxp_ldb_ch;
+
+		ret = of_property_read_u32(child, "reg", &i);
+		if (ret || i < 0 || i > 1) {
+			ret = -EINVAL;
+			goto free_child;
+		}
+
+		if (!of_device_is_available(child))
+			continue;
+
+		imx8qxp_ldb_ch = &imx8qxp_ldb->channel[i];
+
+		imx8qxp_ldb_ch->phy = devm_of_phy_get(dev, child, "ldb_phy");
+		if (IS_ERR(imx8qxp_ldb_ch->phy)) {
+			ret = PTR_ERR(imx8qxp_ldb_ch->phy);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "can't get channel%d phy: %d\n",
+					i, ret);
+			goto free_child;
+		}
+
+		ret = phy_init(imx8qxp_ldb_ch->phy);
+		if (ret < 0) {
+			dev_err(dev, "failed to initialize channel%d phy: %d\n",
+				i, ret);
+			goto free_child;
+		}
+
+		if (ldb->dual) {
+			imx8qxp_ldb_ch->aux_phy =
+					imx8qxp_ldb_get_aux_phy(auxldb_np);
+			if (IS_ERR(imx8qxp_ldb_ch->aux_phy)) {
+				ret = PTR_ERR(imx8qxp_ldb_ch->aux_phy);
+				if (ret != -EPROBE_DEFER)
+					dev_err(dev,
+						"can't get channel0 aux phy: %d\n",
+						ret);
+				goto free_child;
+			}
+
+			ret = phy_init(imx8qxp_ldb_ch->aux_phy);
+			if (ret < 0) {
+				dev_err(dev,
+					"failed to initialize channel0 aux phy: %d\n",
+					ret);
+				goto free_child;
+			}
+		}
+	}
+
+	if (ldb->dual)
+		of_node_put(auxldb_np);
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		ldb_ch = &imx8qxp_ldb->channel[i].base;
+		if (!ldb_ch->is_valid) {
+			drm_encoder_cleanup(encoder[i]);
+			continue;
+		}
+
+		ret = imx_drm_encoder_parse_of(drm, encoder[i], ldb_ch->child);
+		if (ret)
+			goto disable_pm_runtime;
+	}
+
+	return 0;
+
+free_child:
+	of_node_put(child);
+	if (ldb->dual)
+		of_node_put(auxldb_np);
+disable_pm_runtime:
+	pm_runtime_disable(dev);
+	imx8qxp_ldb_detach_pm_domains(imx8qxp_ldb);
+
+	return ret;
+}
+
+static void imx8qxp_ldb_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	int i;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
+						&imx8qxp_ldb->channel[i];
+
+		if (imx8qxp_ldb_ch->phy_is_on) {
+			phy_power_off(imx8qxp_ldb_ch->phy);
+			if (ldb->dual)
+				phy_power_off(imx8qxp_ldb_ch->aux_phy);
+		}
+
+		phy_exit(imx8qxp_ldb_ch->phy);
+		if (ldb->dual && i == 0)
+			phy_exit(imx8qxp_ldb_ch->aux_phy);
+	}
+
+	imx8qxp_ldb_detach_pm_domains(imx8qxp_ldb);
+}
+
+static const struct component_ops imx8qxp_ldb_ops = {
+	.bind	= imx8qxp_ldb_bind,
+	.unbind	= imx8qxp_ldb_unbind,
+};
+
+static int imx8qxp_ldb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx8qxp_ldb *imx8qxp_ldb;
+
+	imx8qxp_ldb = devm_kzalloc(dev, sizeof(*imx8qxp_ldb), GFP_KERNEL);
+	if (!imx8qxp_ldb)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, imx8qxp_ldb);
+
+	return component_add(dev, &imx8qxp_ldb_ops);
+}
+
+static int imx8qxp_ldb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx8qxp_ldb_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx8qxp_ldb_suspend(struct device *dev)
+{
+	struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	int i;
+
+	if (imx8qxp_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		phy_exit(imx8qxp_ldb->channel[i].phy);
+
+		if (ldb->dual && i == 0)
+			phy_exit(imx8qxp_ldb->channel[i].aux_phy);
+	}
+
+	return 0;
+}
+
+static int imx8qxp_ldb_resume(struct device *dev)
+{
+	struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev);
+	struct ldb *ldb = &imx8qxp_ldb->base;
+	int i;
+
+	if (imx8qxp_ldb == NULL)
+		return 0;
+
+	for (i = 0; i < LDB_CH_NUM; i++) {
+		phy_init(imx8qxp_ldb->channel[i].phy);
+
+		if (ldb->dual && i == 0)
+			phy_init(imx8qxp_ldb->channel[i].aux_phy);
+	}
+
+	imx8qxp_ldb_init_sc_misc(imx8qxp_ldb->id, ldb->dual);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx8qxp_ldb_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(imx8qxp_ldb_suspend, imx8qxp_ldb_resume)
+};
+
+static struct platform_driver imx8qxp_ldb_driver = {
+	.probe		= imx8qxp_ldb_probe,
+	.remove		= imx8qxp_ldb_remove,
+	.driver		= {
+		.of_match_table = imx8qxp_ldb_dt_ids,
+		.name	= DRIVER_NAME,
+		.pm	= &imx8qxp_ldb_pm_ops,
+	},
+};
+
+module_platform_driver(imx8qxp_ldb_driver);
+
+MODULE_DESCRIPTION("i.MX8QXP LVDS driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -0,0 +1,6 @@
+config DRM_IMX_IPUV3
+	tristate
+	depends on DRM_IMX
+	depends on IMX_IPUV3_CORE
+	default y if DRM_IMX=y
+	default m if DRM_IMX=m
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -I $(srctree)/$(src)/../
+
+imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o ipuv3-kms.o
+obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX IPUv3 Graphics driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <video/imx-ipu-v3.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "imx-drm.h"
+#include "ipuv3-kms.h"
+#include "ipuv3-plane.h"
+
+#define DRIVER_DESC		"i.MX IPUv3 Graphics"
+
+struct ipu_crtc {
+	struct device		*dev;
+	struct drm_crtc		base;
+
+	/* plane[0] is the full plane, plane[1] is the partial plane */
+	struct ipu_plane	*plane[2];
+
+	struct ipu_dc		*dc;
+	struct ipu_di		*di;
+	int			irq;
+	struct drm_pending_vblank_event *event;
+};
+
+static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct ipu_crtc, base);
+}
+
+static void ipu_crtc_atomic_enable(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_state)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
+	ipu_prg_enable(ipu);
+	ipu_dc_enable(ipu);
+	ipu_dc_enable_channel(ipu_crtc->dc);
+	ipu_di_enable(ipu_crtc->di);
+}
+
+static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	bool disable_partial = false;
+	bool disable_full = false;
+	struct drm_plane *plane;
+
+	drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
+		if (plane == &ipu_crtc->plane[0]->base)
+			disable_full = true;
+		if (ipu_crtc->plane[1] && plane == &ipu_crtc->plane[1]->base)
+			disable_partial = true;
+	}
+
+	if (disable_partial)
+		ipu_plane_disable(ipu_crtc->plane[1], true);
+	if (disable_full)
+		ipu_plane_disable(ipu_crtc->plane[0], true);
+}
+
+static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
+	ipu_dc_disable_channel(ipu_crtc->dc);
+	ipu_di_disable(ipu_crtc->di);
+	/*
+	 * Planes must be disabled before DC clock is removed, as otherwise the
+	 * attached IDMACs will be left in undefined state, possibly hanging
+	 * the IPU or even system.
+	 */
+	ipu_crtc_disable_planes(ipu_crtc, old_crtc_state);
+	ipu_dc_disable(ipu);
+	ipu_prg_disable(ipu);
+
+	drm_crtc_vblank_off(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event && !crtc->state->active) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void ipu_drm_crtc_reset(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state;
+
+	if (crtc->state)
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+	kfree(to_imx_crtc_state(crtc->state));
+	crtc->state = NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state)
+		__drm_atomic_helper_crtc_reset(crtc, &state->base);
+}
+
+static struct drm_crtc_state *ipu_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	WARN_ON(state->base.crtc != crtc);
+	state->base.crtc = crtc;
+
+	return &state->base;
+}
+
+static void ipu_drm_crtc_destroy_state(struct drm_crtc *crtc,
+				       struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(state);
+	kfree(to_imx_crtc_state(state));
+}
+
+static int ipu_enable_vblank(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	enable_irq(ipu_crtc->irq);
+
+	return 0;
+}
+
+static void ipu_disable_vblank(struct drm_crtc *crtc)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	disable_irq_nosync(ipu_crtc->irq);
+}
+
+static const struct drm_crtc_funcs ipu_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = ipu_drm_crtc_reset,
+	.atomic_duplicate_state = ipu_drm_crtc_duplicate_state,
+	.atomic_destroy_state = ipu_drm_crtc_destroy_state,
+	.enable_vblank = ipu_enable_vblank,
+	.disable_vblank = ipu_disable_vblank,
+};
+
+static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_crtc *ipu_crtc = dev_id;
+	struct drm_crtc *crtc = &ipu_crtc->base;
+	unsigned long flags;
+	int i;
+
+	drm_crtc_handle_vblank(crtc);
+
+	if (ipu_crtc->event) {
+		for (i = 0; i < ARRAY_SIZE(ipu_crtc->plane); i++) {
+			struct ipu_plane *plane = ipu_crtc->plane[i];
+
+			if (!plane)
+				continue;
+
+			if (ipu_plane_atomic_update_pending(&plane->base))
+				break;
+		}
+
+		if (i == ARRAY_SIZE(ipu_crtc->plane)) {
+			spin_lock_irqsave(&crtc->dev->event_lock, flags);
+			drm_crtc_send_vblank_event(crtc, ipu_crtc->event);
+			ipu_crtc->event = NULL;
+			drm_crtc_vblank_put(crtc);
+			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct videomode vm;
+	int ret;
+
+	drm_display_mode_to_videomode(adjusted_mode, &vm);
+
+	ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
+	if (ret)
+		return false;
+
+	if ((vm.vsync_len == 0) || (vm.hsync_len == 0))
+		return false;
+
+	drm_display_mode_from_videomode(&vm, adjusted_mode);
+
+	return true;
+}
+
+static int ipu_crtc_atomic_check(struct drm_crtc *crtc,
+				 struct drm_crtc_state *state)
+{
+	u32 primary_plane_mask = drm_plane_mask(crtc->primary);
+
+	if (state->active && (primary_plane_mask & state->plane_mask) == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ipu_crtc_atomic_begin(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_crtc_state)
+{
+	drm_crtc_vblank_on(crtc);
+}
+
+static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_crtc_state)
+{
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		ipu_crtc->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct ipu_di_signal_cfg sig_cfg = {};
+	unsigned long encoder_types = 0;
+
+	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
+			mode->hdisplay);
+	dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
+			mode->vdisplay);
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->crtc == crtc)
+			encoder_types |= BIT(encoder->encoder_type);
+	}
+
+	dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
+		__func__, encoder_types);
+
+	/*
+	 * If we have DAC or LDB, then we need the IPU DI clock to be
+	 * the same as the LDB DI clock. For TVDAC, derive the IPU DI
+	 * clock from 27 MHz TVE_DI clock, but allow to divide it.
+	 */
+	if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
+			     BIT(DRM_MODE_ENCODER_LVDS)))
+		sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
+	else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
+		sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
+	else
+		sig_cfg.clkflags = 0;
+
+	sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW);
+	/* Default to driving pixel data on negative clock edges */
+	sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags &
+			     DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE);
+	sig_cfg.bus_format = imx_crtc_state->bus_format;
+	sig_cfg.v_to_h_sync = 0;
+	sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin;
+	sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin;
+
+	drm_display_mode_to_videomode(mode, &sig_cfg.mode);
+
+	ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
+			 mode->flags & DRM_MODE_FLAG_INTERLACE,
+			 imx_crtc_state->bus_format, mode->hdisplay);
+	ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
+}
+
+static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
+	.mode_fixup = ipu_crtc_mode_fixup,
+	.mode_set_nofb = ipu_crtc_mode_set_nofb,
+	.atomic_check = ipu_crtc_atomic_check,
+	.atomic_begin = ipu_crtc_atomic_begin,
+	.atomic_flush = ipu_crtc_atomic_flush,
+	.atomic_disable = ipu_crtc_atomic_disable,
+	.atomic_enable = ipu_crtc_atomic_enable,
+};
+
+static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
+{
+	if (!IS_ERR_OR_NULL(ipu_crtc->dc))
+		ipu_dc_put(ipu_crtc->dc);
+	if (!IS_ERR_OR_NULL(ipu_crtc->di))
+		ipu_di_put(ipu_crtc->di);
+}
+
+static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
+		struct ipu_client_platformdata *pdata)
+{
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+	int ret;
+
+	ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
+	if (IS_ERR(ipu_crtc->dc)) {
+		ret = PTR_ERR(ipu_crtc->dc);
+		goto err_out;
+	}
+
+	ipu_crtc->di = ipu_di_get(ipu, pdata->di);
+	if (IS_ERR(ipu_crtc->di)) {
+		ret = PTR_ERR(ipu_crtc->di);
+		goto err_out;
+	}
+
+	return 0;
+err_out:
+	ipu_put_resources(ipu_crtc);
+
+	return ret;
+}
+
+static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
+	struct ipu_client_platformdata *pdata, struct drm_device *drm)
+{
+	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+	struct drm_crtc *crtc = &ipu_crtc->base;
+	int dp = -EINVAL;
+	int ret;
+
+	ret = ipu_get_resources(ipu_crtc, pdata);
+	if (ret) {
+		dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
+				ret);
+		return ret;
+	}
+
+	if (pdata->dp >= 0)
+		dp = IPU_DP_FLOW_SYNC_BG;
+	ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
+					    DRM_PLANE_TYPE_PRIMARY);
+	if (IS_ERR(ipu_crtc->plane[0])) {
+		ret = PTR_ERR(ipu_crtc->plane[0]);
+		goto err_put_resources;
+	}
+
+	crtc->port = pdata->of_node;
+	drm_crtc_helper_add(crtc, &ipu_helper_funcs);
+	drm_crtc_init_with_planes(drm, crtc, &ipu_crtc->plane[0]->base, NULL,
+				  &ipu_crtc_funcs, NULL);
+
+	ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
+	if (ret) {
+		dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
+			ret);
+		goto err_put_resources;
+	}
+
+	/* If this crtc is using the DP, add an overlay plane */
+	if (pdata->dp >= 0 && pdata->dma[1] > 0) {
+		ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
+						IPU_DP_FLOW_SYNC_FG,
+						drm_crtc_mask(&ipu_crtc->base),
+						DRM_PLANE_TYPE_OVERLAY);
+		if (IS_ERR(ipu_crtc->plane[1])) {
+			ipu_crtc->plane[1] = NULL;
+		} else {
+			ret = ipu_plane_get_resources(ipu_crtc->plane[1]);
+			if (ret) {
+				dev_err(ipu_crtc->dev, "getting plane 1 "
+					"resources failed with %d.\n", ret);
+				goto err_put_plane0_res;
+			}
+		}
+	}
+
+	ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
+	ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
+			"imx_drm", ipu_crtc);
+	if (ret < 0) {
+		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
+		goto err_put_plane1_res;
+	}
+	/* Only enable IRQ when we actually need it to trigger work. */
+	disable_irq(ipu_crtc->irq);
+
+	return 0;
+
+err_put_plane1_res:
+	if (ipu_crtc->plane[1])
+		ipu_plane_put_resources(ipu_crtc->plane[1]);
+err_put_plane0_res:
+	ipu_plane_put_resources(ipu_crtc->plane[0]);
+err_put_resources:
+	ipu_put_resources(ipu_crtc);
+
+	return ret;
+}
+
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
+{
+	struct ipu_client_platformdata *pdata = dev->platform_data;
+	struct drm_device *drm = data;
+	struct ipu_crtc *ipu_crtc;
+	int ret;
+
+	ipu_crtc = dev_get_drvdata(dev);
+	memset(ipu_crtc, 0, sizeof(*ipu_crtc));
+
+	ipu_crtc->dev = dev;
+
+	ret = ipu_crtc_init(ipu_crtc, pdata, drm);
+	if (ret)
+		return ret;
+
+	drm->mode_config.funcs = &ipuv3_drm_mode_config_funcs;
+	drm->mode_config.helper_private = &ipuv3_drm_mode_config_helpers;
+	drm->mode_config.allow_fb_modifiers = true;
+
+	dev_set_drvdata(dev, ipu_crtc);
+
+	return 0;
+}
+
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+	struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
+
+	ipu_put_resources(ipu_crtc);
+	if (ipu_crtc->plane[1])
+		ipu_plane_put_resources(ipu_crtc->plane[1]);
+	ipu_plane_put_resources(ipu_crtc->plane[0]);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+	.bind = ipu_drm_bind,
+	.unbind = ipu_drm_unbind,
+};
+
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ipu_crtc *ipu_crtc;
+	int ret;
+
+	if (!dev->platform_data)
+		return -EINVAL;
+
+	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
+	if (!ipu_crtc)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, ipu_crtc);
+
+	return component_add(dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ipu_crtc_ops);
+	return 0;
+}
+
+static struct platform_driver ipu_drm_driver = {
+	.driver = {
+		.name = "imx-ipuv3-crtc",
+	},
+	.probe = ipu_drm_probe,
+	.remove = ipu_drm_remove,
+};
+module_platform_driver(ipu_drm_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ipuv3-crtc");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include "imx-drm.h"
+#include "ipuv3-plane.h"
+
+static int ipuv3_drm_atomic_check(struct drm_device *dev,
+				   struct drm_atomic_state *state)
+{
+	int ret;
+
+	ret = drm_atomic_helper_check(dev, state);
+	if (ret)
+		return ret;
+
+	/*
+	 * Check modeset again in case crtc_state->mode_changed is
+	 * updated in plane's ->atomic_check callback.
+	 */
+	ret = drm_atomic_helper_check_modeset(dev, state);
+	if (ret)
+		return ret;
+
+	/* Assign PRG/PRE channels and check if all constrains are satisfied. */
+	ret = ipu_planes_assign_pre(dev, state);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+const struct drm_mode_config_funcs ipuv3_drm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create,
+	.atomic_check = ipuv3_drm_atomic_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static void ipuv3_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	struct drm_plane *plane;
+	struct drm_plane_state *old_plane_state, *new_plane_state;
+	bool plane_disabling = false;
+	int i;
+
+	drm_atomic_helper_commit_modeset_disables(dev, state);
+
+	drm_atomic_helper_commit_planes(dev, state,
+				DRM_PLANE_COMMIT_ACTIVE_ONLY |
+				DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
+
+	drm_atomic_helper_commit_modeset_enables(dev, state);
+
+	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+		if (drm_atomic_plane_disabling(old_plane_state, new_plane_state))
+			plane_disabling = true;
+	}
+
+	/*
+	 * The flip done wait is only strictly required by imx-drm if a deferred
+	 * plane disable is in-flight. As the core requires blocking commits
+	 * to wait for the flip it is done here unconditionally. This keeps the
+	 * workitem around a bit longer than required for the majority of
+	 * non-blocking commits, but we accept that for the sake of simplicity.
+	 */
+	drm_atomic_helper_wait_for_flip_done(dev, state);
+
+	if (plane_disabling) {
+		for_each_old_plane_in_state(state, plane, old_plane_state, i)
+			ipu_plane_disable_deferred(plane);
+
+	}
+
+	drm_atomic_helper_commit_hw_done(state);
+}
+
+const struct drm_mode_config_helper_funcs ipuv3_drm_mode_config_helpers = {
+	.atomic_commit_tail = ipuv3_drm_atomic_commit_tail,
+};
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _IPUV3_KMS_H_
+#define _IPUV3_KMS_H_
+
+extern const struct drm_mode_config_funcs ipuv3_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs ipuv3_drm_mode_config_helpers;
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX IPUv3 DP Overlay Planes
+ *
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include <video/imx-ipu-v3.h>
+
+#include "imx-drm.h"
+#include "ipuv3-plane.h"
+
+struct ipu_plane_state {
+	struct drm_plane_state base;
+	bool use_pre;
+};
+
+static inline struct ipu_plane_state *
+to_ipu_plane_state(struct drm_plane_state *p)
+{
+	return container_of(p, struct ipu_plane_state, base);
+}
+
+static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
+{
+	return container_of(p, struct ipu_plane, base);
+}
+
+static const uint32_t ipu_plane_formats[] = {
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_RGBA5551,
+	DRM_FORMAT_BGRA5551,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_YVU420,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YVU422,
+	DRM_FORMAT_YUV444,
+	DRM_FORMAT_YVU444,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB565_A8,
+	DRM_FORMAT_BGR565_A8,
+	DRM_FORMAT_RGB888_A8,
+	DRM_FORMAT_BGR888_A8,
+	DRM_FORMAT_RGBX8888_A8,
+	DRM_FORMAT_BGRX8888_A8,
+};
+
+static const uint64_t ipu_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const uint64_t pre_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_VIVANTE_TILED,
+	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+	DRM_FORMAT_MOD_INVALID
+};
+
+int ipu_plane_irq(struct ipu_plane *ipu_plane)
+{
+	return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
+				     IPU_IRQ_EOF);
+}
+
+static inline unsigned long
+drm_plane_state_to_eba(struct drm_plane_state *state, int plane)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	int x = state->src.x1 >> 16;
+	int y = state->src.y1 >> 16;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, plane);
+	BUG_ON(!cma_obj);
+
+	return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y +
+	       fb->format->cpp[plane] * x;
+}
+
+static inline unsigned long
+drm_plane_state_to_ubo(struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	unsigned long eba = drm_plane_state_to_eba(state, 0);
+	int x = state->src.x1 >> 16;
+	int y = state->src.y1 >> 16;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
+	BUG_ON(!cma_obj);
+
+	x /= fb->format->hsub;
+	y /= fb->format->vsub;
+
+	return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
+	       fb->format->cpp[1] * x - eba;
+}
+
+static inline unsigned long
+drm_plane_state_to_vbo(struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	unsigned long eba = drm_plane_state_to_eba(state, 0);
+	int x = state->src.x1 >> 16;
+	int y = state->src.y1 >> 16;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
+	BUG_ON(!cma_obj);
+
+	x /= fb->format->hsub;
+	y /= fb->format->vsub;
+
+	return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
+	       fb->format->cpp[2] * x - eba;
+}
+
+void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
+{
+	if (!IS_ERR_OR_NULL(ipu_plane->dp))
+		ipu_dp_put(ipu_plane->dp);
+	if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
+		ipu_dmfc_put(ipu_plane->dmfc);
+	if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
+		ipu_idmac_put(ipu_plane->ipu_ch);
+	if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
+		ipu_idmac_put(ipu_plane->alpha_ch);
+}
+
+int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
+{
+	int ret;
+	int alpha_ch;
+
+	ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
+	if (IS_ERR(ipu_plane->ipu_ch)) {
+		ret = PTR_ERR(ipu_plane->ipu_ch);
+		DRM_ERROR("failed to get idmac channel: %d\n", ret);
+		return ret;
+	}
+
+	alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
+	if (alpha_ch >= 0) {
+		ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
+		if (IS_ERR(ipu_plane->alpha_ch)) {
+			ret = PTR_ERR(ipu_plane->alpha_ch);
+			DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
+				  alpha_ch, ret);
+			return ret;
+		}
+	}
+
+	ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
+	if (IS_ERR(ipu_plane->dmfc)) {
+		ret = PTR_ERR(ipu_plane->dmfc);
+		DRM_ERROR("failed to get dmfc: ret %d\n", ret);
+		goto err_out;
+	}
+
+	if (ipu_plane->dp_flow >= 0) {
+		ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
+		if (IS_ERR(ipu_plane->dp)) {
+			ret = PTR_ERR(ipu_plane->dp);
+			DRM_ERROR("failed to get dp flow: %d\n", ret);
+			goto err_out;
+		}
+	}
+
+	return 0;
+err_out:
+	ipu_plane_put_resources(ipu_plane);
+
+	return ret;
+}
+
+static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
+{
+	switch (ipu_plane->base.state->fb->format->format) {
+	case DRM_FORMAT_RGB565_A8:
+	case DRM_FORMAT_BGR565_A8:
+	case DRM_FORMAT_RGB888_A8:
+	case DRM_FORMAT_BGR888_A8:
+	case DRM_FORMAT_RGBX8888_A8:
+	case DRM_FORMAT_BGRX8888_A8:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ipu_plane_enable(struct ipu_plane *ipu_plane)
+{
+	if (ipu_plane->dp)
+		ipu_dp_enable(ipu_plane->ipu);
+	ipu_dmfc_enable_channel(ipu_plane->dmfc);
+	ipu_idmac_enable_channel(ipu_plane->ipu_ch);
+	if (ipu_plane_separate_alpha(ipu_plane))
+		ipu_idmac_enable_channel(ipu_plane->alpha_ch);
+	if (ipu_plane->dp)
+		ipu_dp_enable_channel(ipu_plane->dp);
+}
+
+void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
+{
+	int ret;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
+	if (ret == -ETIMEDOUT) {
+		DRM_ERROR("[PLANE:%d] IDMAC timeout\n",
+			  ipu_plane->base.base.id);
+	}
+
+	if (ipu_plane->dp && disable_dp_channel)
+		ipu_dp_disable_channel(ipu_plane->dp, false);
+	ipu_idmac_disable_channel(ipu_plane->ipu_ch);
+	if (ipu_plane->alpha_ch)
+		ipu_idmac_disable_channel(ipu_plane->alpha_ch);
+	ipu_dmfc_disable_channel(ipu_plane->dmfc);
+	if (ipu_plane->dp)
+		ipu_dp_disable(ipu_plane->ipu);
+	if (ipu_prg_present(ipu_plane->ipu))
+		ipu_prg_channel_disable(ipu_plane->ipu_ch);
+}
+
+void ipu_plane_disable_deferred(struct drm_plane *plane)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+	if (ipu_plane->disabling) {
+		ipu_plane->disabling = false;
+		ipu_plane_disable(ipu_plane, false);
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
+
+static void ipu_plane_destroy(struct drm_plane *plane)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	drm_plane_cleanup(plane);
+	kfree(ipu_plane);
+}
+
+static void ipu_plane_state_reset(struct drm_plane *plane)
+{
+	unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
+	struct ipu_plane_state *ipu_state;
+
+	if (plane->state) {
+		ipu_state = to_ipu_plane_state(plane->state);
+		__drm_atomic_helper_plane_destroy_state(plane->state);
+		kfree(ipu_state);
+		plane->state = NULL;
+	}
+
+	ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
+
+	if (ipu_state) {
+		__drm_atomic_helper_plane_reset(plane, &ipu_state->base);
+		ipu_state->base.zpos = zpos;
+		ipu_state->base.normalized_zpos = zpos;
+	}
+}
+
+static struct drm_plane_state *
+ipu_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct ipu_plane_state *state;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	if (state)
+		__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+
+	return &state->base;
+}
+
+static void ipu_plane_destroy_state(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(ipu_state);
+}
+
+static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
+					   uint32_t format, uint64_t modifier)
+{
+	struct ipu_soc *ipu = to_ipu_plane(plane)->ipu;
+
+	/* linear is supported for all planes and formats */
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	/* without a PRG there are no supported modifiers */
+	if (!ipu_prg_present(ipu))
+		return false;
+
+	return ipu_prg_format_supported(ipu, format, modifier);
+}
+
+static const struct drm_plane_funcs ipu_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy	= ipu_plane_destroy,
+	.reset		= ipu_plane_state_reset,
+	.atomic_duplicate_state	= ipu_plane_duplicate_state,
+	.atomic_destroy_state	= ipu_plane_destroy_state,
+	.format_mod_supported = ipu_plane_format_mod_supported,
+};
+
+static int ipu_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct drm_plane_state *old_state = plane->state;
+	struct drm_crtc_state *crtc_state;
+	struct device *dev = plane->dev->dev;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_framebuffer *old_fb = old_state->fb;
+	unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
+	bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
+	int ret;
+
+	/* Ok to disable */
+	if (!fb)
+		return 0;
+
+	if (WARN_ON(!state->crtc))
+		return -EINVAL;
+
+	crtc_state =
+		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+	if (WARN_ON(!crtc_state))
+		return -EINVAL;
+
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  can_position, true);
+	if (ret)
+		return ret;
+
+	/* nothing to check when disabling or disabled */
+	if (!crtc_state->enable)
+		return 0;
+
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		/* full plane minimum width is 13 pixels */
+		if (drm_rect_width(&state->dst) < 13)
+			return -EINVAL;
+		break;
+	case DRM_PLANE_TYPE_OVERLAY:
+		break;
+	default:
+		dev_warn(dev, "Unsupported plane type %d\n", plane->type);
+		return -EINVAL;
+	}
+
+	if (drm_rect_height(&state->dst) < 2)
+		return -EINVAL;
+
+	/*
+	 * We support resizing active plane or changing its format by
+	 * forcing CRTC mode change in plane's ->atomic_check callback
+	 * and disabling all affected active planes in CRTC's ->atomic_disable
+	 * callback.  The planes will be reenabled in plane's ->atomic_update
+	 * callback.
+	 */
+	if (old_fb &&
+	    (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
+	     drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
+	     fb->format != old_fb->format))
+		crtc_state->mode_changed = true;
+
+	eba = drm_plane_state_to_eba(state, 0);
+
+	if (eba & 0x7)
+		return -EINVAL;
+
+	if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
+		return -EINVAL;
+
+	if (old_fb && fb->pitches[0] != old_fb->pitches[0])
+		crtc_state->mode_changed = true;
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YVU422:
+	case DRM_FORMAT_YUV444:
+	case DRM_FORMAT_YVU444:
+		/*
+		 * Multiplanar formats have to meet the following restrictions:
+		 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
+		 * - EBA, UBO and VBO are a multiple of 8
+		 * - UBO and VBO are unsigned and not larger than 0xfffff8
+		 * - Only EBA may be changed while scanout is active
+		 * - The strides of U and V planes must be identical.
+		 */
+		vbo = drm_plane_state_to_vbo(state);
+
+		if (vbo & 0x7 || vbo > 0xfffff8)
+			return -EINVAL;
+
+		if (old_fb && (fb->format == old_fb->format)) {
+			old_vbo = drm_plane_state_to_vbo(old_state);
+			if (vbo != old_vbo)
+				crtc_state->mode_changed = true;
+		}
+
+		if (fb->pitches[1] != fb->pitches[2])
+			return -EINVAL;
+
+		/* fall-through */
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+		ubo = drm_plane_state_to_ubo(state);
+
+		if (ubo & 0x7 || ubo > 0xfffff8)
+			return -EINVAL;
+
+		if (old_fb && (fb->format == old_fb->format)) {
+			old_ubo = drm_plane_state_to_ubo(old_state);
+			if (ubo != old_ubo)
+				crtc_state->mode_changed = true;
+		}
+
+		if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
+			return -EINVAL;
+
+		if (old_fb && old_fb->pitches[1] != fb->pitches[1])
+			crtc_state->mode_changed = true;
+
+		/*
+		 * The x/y offsets must be even in case of horizontal/vertical
+		 * chroma subsampling.
+		 */
+		if (((state->src.x1 >> 16) & (fb->format->hsub - 1)) ||
+		    ((state->src.y1 >> 16) & (fb->format->vsub - 1)))
+			return -EINVAL;
+		break;
+	case DRM_FORMAT_RGB565_A8:
+	case DRM_FORMAT_BGR565_A8:
+	case DRM_FORMAT_RGB888_A8:
+	case DRM_FORMAT_BGR888_A8:
+	case DRM_FORMAT_RGBX8888_A8:
+	case DRM_FORMAT_BGRX8888_A8:
+		alpha_eba = drm_plane_state_to_eba(state, 1);
+		if (alpha_eba & 0x7)
+			return -EINVAL;
+
+		if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
+			return -EINVAL;
+
+		if (old_fb && old_fb->pitches[1] != fb->pitches[1])
+			crtc_state->mode_changed = true;
+		break;
+	}
+
+	return 0;
+}
+
+static void ipu_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+	if (ipu_plane->dp)
+		ipu_dp_disable_channel(ipu_plane->dp, true);
+	ipu_plane->disabling = true;
+}
+
+static int ipu_chan_assign_axi_id(int ipu_chan)
+{
+	switch (ipu_chan) {
+	case IPUV3_CHANNEL_MEM_BG_SYNC:
+		return 1;
+	case IPUV3_CHANNEL_MEM_FG_SYNC:
+		return 2;
+	case IPUV3_CHANNEL_MEM_DC_SYNC:
+		return 3;
+	default:
+		return 0;
+	}
+}
+
+static void ipu_calculate_bursts(u32 width, u32 cpp, u32 stride,
+				 u8 *burstsize, u8 *num_bursts)
+{
+	const unsigned int width_bytes = width * cpp;
+	unsigned int npb, bursts;
+
+	/* Maximum number of pixels per burst without overshooting stride */
+	for (npb = 64 / cpp; npb > 0; --npb) {
+		if (round_up(width_bytes, npb * cpp) <= stride)
+			break;
+	}
+	*burstsize = npb;
+
+	/* Maximum number of consecutive bursts without overshooting stride */
+	for (bursts = 8; bursts > 1; bursts /= 2) {
+		if (round_up(width_bytes, npb * cpp * bursts) <= stride)
+			break;
+	}
+	*num_bursts = bursts;
+}
+
+static void ipu_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+	struct drm_plane_state *state = plane->state;
+	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
+	struct drm_crtc_state *crtc_state = state->crtc->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_rect *dst = &state->dst;
+	unsigned long eba, ubo, vbo;
+	unsigned long alpha_eba = 0;
+	enum ipu_color_space ics;
+	unsigned int axi_id = 0;
+	const struct drm_format_info *info;
+	u8 burstsize, num_bursts;
+	u32 width, height;
+	int active;
+
+	if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
+		ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
+
+	switch (ipu_plane->dp_flow) {
+	case IPU_DP_FLOW_SYNC_BG:
+		if (state->normalized_zpos == 1) {
+			ipu_dp_set_global_alpha(ipu_plane->dp,
+						!fb->format->has_alpha, 0xff,
+						true);
+		} else {
+			ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
+		}
+		break;
+	case IPU_DP_FLOW_SYNC_FG:
+		if (state->normalized_zpos == 1) {
+			ipu_dp_set_global_alpha(ipu_plane->dp,
+						!fb->format->has_alpha, 0xff,
+						false);
+		}
+		break;
+	}
+
+	eba = drm_plane_state_to_eba(state, 0);
+
+	/*
+	 * Configure PRG channel and attached PRE, this changes the EBA to an
+	 * internal SRAM location.
+	 */
+	if (ipu_state->use_pre) {
+		axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
+		ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
+					  drm_rect_width(&state->src) >> 16,
+					  drm_rect_height(&state->src) >> 16,
+					  fb->pitches[0], fb->format->format,
+					  fb->modifier, &eba);
+	}
+
+	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
+		/* nothing to do if PRE is used */
+		if (ipu_state->use_pre)
+			return;
+		active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
+		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
+		ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
+		if (ipu_plane_separate_alpha(ipu_plane)) {
+			active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
+			ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
+					     alpha_eba);
+			ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
+		}
+		return;
+	}
+
+	ics = ipu_drm_fourcc_to_colorspace(fb->format->format);
+	switch (ipu_plane->dp_flow) {
+	case IPU_DP_FLOW_SYNC_BG:
+		ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
+		break;
+	case IPU_DP_FLOW_SYNC_FG:
+		ipu_dp_setup_channel(ipu_plane->dp, ics,
+					IPUV3_COLORSPACE_UNKNOWN);
+		break;
+	}
+
+	ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
+
+	width = drm_rect_width(&state->src) >> 16;
+	height = drm_rect_height(&state->src) >> 16;
+	info = drm_format_info(fb->format->format);
+	ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
+			     &burstsize, &num_bursts);
+
+	ipu_cpmem_zero(ipu_plane->ipu_ch);
+	ipu_cpmem_set_resolution(ipu_plane->ipu_ch, width, height);
+	ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format);
+	ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize);
+	ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
+	ipu_idmac_enable_watermark(ipu_plane->ipu_ch, true);
+	ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
+	ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
+	ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YVU422:
+	case DRM_FORMAT_YUV444:
+	case DRM_FORMAT_YVU444:
+		ubo = drm_plane_state_to_ubo(state);
+		vbo = drm_plane_state_to_vbo(state);
+		if (fb->format->format == DRM_FORMAT_YVU420 ||
+		    fb->format->format == DRM_FORMAT_YVU422 ||
+		    fb->format->format == DRM_FORMAT_YVU444)
+			swap(ubo, vbo);
+
+		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
+					      fb->pitches[1], ubo, vbo);
+
+		dev_dbg(ipu_plane->base.dev->dev,
+			"phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
+			state->src.x1 >> 16, state->src.y1 >> 16);
+		break;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV16:
+		ubo = drm_plane_state_to_ubo(state);
+
+		ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
+					      fb->pitches[1], ubo, ubo);
+
+		dev_dbg(ipu_plane->base.dev->dev,
+			"phy = %lu %lu, x = %d, y = %d", eba, ubo,
+			state->src.x1 >> 16, state->src.y1 >> 16);
+		break;
+	case DRM_FORMAT_RGB565_A8:
+	case DRM_FORMAT_BGR565_A8:
+	case DRM_FORMAT_RGB888_A8:
+	case DRM_FORMAT_BGR888_A8:
+	case DRM_FORMAT_RGBX8888_A8:
+	case DRM_FORMAT_BGRX8888_A8:
+		alpha_eba = drm_plane_state_to_eba(state, 1);
+		num_bursts = 0;
+
+		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
+			eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
+
+		ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
+
+		ipu_cpmem_zero(ipu_plane->alpha_ch);
+		ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
+					 drm_rect_width(&state->src) >> 16,
+					 drm_rect_height(&state->src) >> 16);
+		ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
+		ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
+		ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
+		ipu_cpmem_set_stride(ipu_plane->alpha_ch, fb->pitches[1]);
+		ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
+		ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
+		ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
+		break;
+	default:
+		dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
+			eba, state->src.x1 >> 16, state->src.y1 >> 16);
+		break;
+	}
+	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
+	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
+	ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
+	ipu_plane_enable(ipu_plane);
+}
+
+static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
+	.prepare_fb = drm_gem_fb_prepare_fb,
+	.atomic_check = ipu_plane_atomic_check,
+	.atomic_disable = ipu_plane_atomic_disable,
+	.atomic_update = ipu_plane_atomic_update,
+};
+
+bool ipu_plane_atomic_update_pending(struct drm_plane *plane)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+	struct drm_plane_state *state = plane->state;
+	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
+
+	/* disabled crtcs must not block the update */
+	if (!state->crtc)
+		return false;
+
+	if (ipu_state->use_pre)
+		return ipu_prg_channel_configure_pending(ipu_plane->ipu_ch);
+
+	/*
+	 * Pretend no update is pending in the non-PRE/PRG case. For this to
+	 * happen, an atomic update would have to be deferred until after the
+	 * start of the next frame and simultaneously interrupt latency would
+	 * have to be high enough to let the atomic update finish and issue an
+	 * event before the previous end of frame interrupt handler can be
+	 * executed.
+	 */
+	return false;
+}
+int ipu_planes_assign_pre(struct drm_device *dev,
+			  struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *old_crtc_state, *crtc_state;
+	struct drm_plane_state *plane_state;
+	struct ipu_plane_state *ipu_state;
+	struct ipu_plane *ipu_plane;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	int available_pres = ipu_prg_max_active_channels();
+	int ret, i;
+
+	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
+		ret = drm_atomic_add_affected_planes(state, crtc);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * We are going over the planes in 2 passes: first we assign PREs to
+	 * planes with a tiling modifier, which need the PREs to resolve into
+	 * linear. Any failure to assign a PRE there is fatal. In the second
+	 * pass we try to assign PREs to linear FBs, to improve memory access
+	 * patterns for them. Failure at this point is non-fatal, as we can
+	 * scan out linear FBs without a PRE.
+	 */
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		ipu_state = to_ipu_plane_state(plane_state);
+		ipu_plane = to_ipu_plane(plane);
+
+		if (!plane_state->fb) {
+			ipu_state->use_pre = false;
+			continue;
+		}
+
+		if (!(plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) ||
+		    plane_state->fb->modifier == DRM_FORMAT_MOD_LINEAR)
+			continue;
+
+		if (!ipu_prg_present(ipu_plane->ipu) || !available_pres)
+			return -EINVAL;
+
+		if (!ipu_prg_format_supported(ipu_plane->ipu,
+					      plane_state->fb->format->format,
+					      plane_state->fb->modifier))
+			return -EINVAL;
+
+		ipu_state->use_pre = true;
+		available_pres--;
+	}
+
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		ipu_state = to_ipu_plane_state(plane_state);
+		ipu_plane = to_ipu_plane(plane);
+
+		if (!plane_state->fb) {
+			ipu_state->use_pre = false;
+			continue;
+		}
+
+		if ((plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) &&
+		    plane_state->fb->modifier != DRM_FORMAT_MOD_LINEAR)
+			continue;
+
+		/* make sure that modifier is initialized */
+		plane_state->fb->modifier = DRM_FORMAT_MOD_LINEAR;
+
+		if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
+		    ipu_prg_format_supported(ipu_plane->ipu,
+					     plane_state->fb->format->format,
+					     plane_state->fb->modifier)) {
+			ipu_state->use_pre = true;
+			available_pres--;
+		} else {
+			ipu_state->use_pre = false;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+				 int dma, int dp, unsigned int possible_crtcs,
+				 enum drm_plane_type type)
+{
+	struct ipu_plane *ipu_plane;
+	const uint64_t *modifiers = ipu_format_modifiers;
+	unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
+	int ret;
+
+	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
+		      dma, dp, possible_crtcs);
+
+	ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
+	if (!ipu_plane) {
+		DRM_ERROR("failed to allocate plane\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ipu_plane->ipu = ipu;
+	ipu_plane->dma = dma;
+	ipu_plane->dp_flow = dp;
+
+	if (ipu_prg_present(ipu))
+		modifiers = pre_format_modifiers;
+
+	ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
+				       &ipu_plane_funcs, ipu_plane_formats,
+				       ARRAY_SIZE(ipu_plane_formats),
+				       modifiers, type, NULL);
+	if (ret) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(ipu_plane);
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
+
+	if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
+		drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1);
+	else
+		drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0);
+
+	return ipu_plane;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __IPUV3_PLANE_H__
+#define __IPUV3_PLANE_H__
+
+#include <drm/drm_crtc.h> /* drm_plane */
+
+struct drm_plane;
+struct drm_device;
+struct ipu_soc;
+struct drm_crtc;
+struct drm_framebuffer;
+
+struct ipuv3_channel;
+struct dmfc_channel;
+struct ipu_dp;
+
+struct ipu_plane {
+	struct drm_plane	base;
+
+	struct ipu_soc		*ipu;
+	struct ipuv3_channel	*ipu_ch;
+	struct ipuv3_channel	*alpha_ch;
+	struct dmfc_channel	*dmfc;
+	struct ipu_dp		*dp;
+
+	int			dma;
+	int			dp_flow;
+
+	bool			disabling;
+};
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+				 int dma, int dp, unsigned int possible_crtcs,
+				 enum drm_plane_type type);
+
+/* Init IDMAC, DMFC, DP */
+int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
+		       struct drm_display_mode *mode,
+		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+		       unsigned int crtc_w, unsigned int crtc_h,
+		       uint32_t src_x, uint32_t src_y, uint32_t src_w,
+		       uint32_t src_h, bool interlaced);
+
+int ipu_plane_get_resources(struct ipu_plane *plane);
+void ipu_plane_put_resources(struct ipu_plane *plane);
+
+int ipu_plane_irq(struct ipu_plane *plane);
+
+void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
+void ipu_plane_disable_deferred(struct drm_plane *plane);
+bool ipu_plane_atomic_update_pending(struct drm_plane *plane);
+
+int ipu_planes_assign_pre(struct drm_device *dev,
+			  struct drm_atomic_state *state);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif-mux-display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif-mux-display.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/clk.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_of.h>
+
+#include "imx-drm.h"
+
+#define LCDIF_MUX_MODE_MASK	0x3
+
+enum lcdif_mux_mode {
+	LCDIF_MUX_MODE_LCDIF,
+	LCDIF_MUX_MODE_PL_RGB888,
+	LCDIF_MUX_MODE_PL_RGB666,
+	LCDIF_MUX_MODE_PL_RGB565,
+};
+
+struct imx_lcdif_mux_display {
+	struct drm_encoder encoder;
+	struct device *dev;
+	struct regmap *regmap;
+	struct clk *clk_bypass_div;
+	struct clk *clk_pixel;
+	struct drm_bridge *bridge;
+	u32 bus_format;
+	enum lcdif_mux_mode mux_mode;
+};
+
+static inline struct imx_lcdif_mux_display *enc_to_lmuxd(struct drm_encoder *e)
+{
+	return container_of(e, struct imx_lcdif_mux_display, encoder);
+}
+
+static void imx_lmuxd_encoder_enable(struct drm_encoder *encoder)
+{
+	struct imx_lcdif_mux_display *lmuxd = enc_to_lmuxd(encoder);
+
+	clk_prepare_enable(lmuxd->clk_pixel);
+}
+
+static void imx_lmuxd_encoder_disable(struct drm_encoder *encoder)
+{
+	struct imx_lcdif_mux_display *lmuxd = enc_to_lmuxd(encoder);
+
+	clk_disable_unprepare(lmuxd->clk_pixel);
+}
+
+static void
+imx_lmuxd_encoder_atomic_mode_set(struct drm_encoder *encoder,
+				  struct drm_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state)
+{
+	struct imx_lcdif_mux_display *lmuxd = enc_to_lmuxd(encoder);
+	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+	unsigned long pixel_clk = mode->clock * 1000;
+
+	clk_set_rate(lmuxd->clk_bypass_div, pixel_clk);
+	clk_set_rate(lmuxd->clk_pixel, pixel_clk);
+
+	regmap_update_bits(lmuxd->regmap,
+			   0x0, LCDIF_MUX_MODE_MASK, lmuxd->mux_mode);
+}
+
+static int
+imx_lmuxd_encoder_atomic_check(struct drm_encoder *encoder,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
+{
+	struct imx_lcdif_mux_display *lmuxd = enc_to_lmuxd(encoder);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct drm_display_info *di = &conn_state->connector->display_info;
+	u32 bus_format;
+
+	imx_crtc_state->bus_flags = di->bus_flags;
+
+	if (!lmuxd->bus_format)
+		lmuxd->bus_format = di->bus_formats[0];
+
+	switch (lmuxd->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		bus_format = MEDIA_BUS_FMT_RGB565_1X30_PADLO;
+		lmuxd->mux_mode = LCDIF_MUX_MODE_PL_RGB565;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		bus_format = MEDIA_BUS_FMT_RGB666_1X30_PADLO;
+		lmuxd->mux_mode = LCDIF_MUX_MODE_PL_RGB666;
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		bus_format = MEDIA_BUS_FMT_RGB888_1X30_PADLO;
+		lmuxd->mux_mode = LCDIF_MUX_MODE_PL_RGB888;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	imx_crtc_state->bus_format = bus_format;
+
+	return 0;
+}
+
+static const struct drm_encoder_funcs imx_lmuxd_encoder_funcs = {
+	.destroy = imx_drm_encoder_destroy,
+};
+
+static const struct drm_encoder_helper_funcs imx_lmuxd_encoder_helper_funcs = {
+	.enable = imx_lmuxd_encoder_enable,
+	.disable = imx_lmuxd_encoder_disable,
+	.atomic_mode_set = imx_lmuxd_encoder_atomic_mode_set,
+	.atomic_check = imx_lmuxd_encoder_atomic_check,
+};
+
+static int imx_lmuxd_register(struct drm_device *drm,
+	struct imx_lcdif_mux_display *lmuxd)
+{
+	struct drm_encoder *encoder = &lmuxd->encoder;
+	int ret;
+
+	ret = imx_drm_encoder_parse_of(drm, encoder, lmuxd->dev->of_node);
+	if (ret)
+		return ret;
+
+	drm_encoder_helper_add(encoder, &imx_lmuxd_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &imx_lmuxd_encoder_funcs,
+			 DRM_MODE_ENCODER_DPI, NULL);
+
+	ret = drm_bridge_attach(encoder, lmuxd->bridge, NULL);
+	if (ret < 0) {
+		dev_err(lmuxd->dev, "failed to attach bridge: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int imx_lmuxd_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+	struct device_node *np = dev->of_node;
+	struct imx_lcdif_mux_display *lmuxd = dev_get_drvdata(dev);
+	struct drm_panel *panel;
+	const char *fmt;
+	u32 bus_format = 0;
+	int ret;
+
+	lmuxd->regmap =
+		syscon_regmap_lookup_by_phandle(np, "fsl,lcdif-mux-regs");
+	if (IS_ERR(lmuxd->regmap)) {
+		dev_err(dev, "failed to get lcdif mux regmap\n");
+		return PTR_ERR(lmuxd->regmap);
+	}
+
+	lmuxd->clk_bypass_div = devm_clk_get(dev, "bypass_div");
+	if (IS_ERR(lmuxd->clk_bypass_div))
+		return PTR_ERR(lmuxd->clk_bypass_div);
+
+	lmuxd->clk_pixel = devm_clk_get(dev, "pixel");
+	if (IS_ERR(lmuxd->clk_bypass_div))
+		return PTR_ERR(lmuxd->clk_bypass_div);
+
+	ret = of_property_read_string(np, "fsl,interface-pix-fmt", &fmt);
+	if (!ret) {
+		if (!strcmp(fmt, "rgb565"))
+			bus_format = MEDIA_BUS_FMT_RGB565_1X16;
+		else if (!strcmp(fmt, "rgb666"))
+			bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+		else if (!strcmp(fmt, "rgb888"))
+			bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	}
+	lmuxd->bus_format = bus_format;
+
+	/* port@1 is the output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, &lmuxd->bridge);
+	if (ret)
+		return ret;
+
+	if (panel) {
+		lmuxd->bridge = devm_drm_panel_bridge_add(dev, panel,
+							DRM_MODE_CONNECTOR_DPI);
+		if (IS_ERR(lmuxd->bridge)) {
+			ret = PTR_ERR(lmuxd->bridge);
+			dev_err(dev, "failed to add panel bridge %d\n", ret);
+			return ret;
+		}
+	}
+
+	lmuxd->dev = dev;
+
+	return imx_lmuxd_register(drm, lmuxd);
+}
+
+static void imx_lmuxd_unbind(struct device *dev, struct device *master,
+	void *data)
+{
+}
+
+static const struct component_ops imx_lmuxd_ops = {
+	.bind	= imx_lmuxd_bind,
+	.unbind	= imx_lmuxd_unbind,
+};
+
+static int imx_lmuxd_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imx_lcdif_mux_display *lmuxd;
+
+	lmuxd = devm_kzalloc(dev, sizeof(*lmuxd), GFP_KERNEL);
+	if (!lmuxd)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, lmuxd);
+
+	return component_add(dev, &imx_lmuxd_ops);
+}
+
+static int imx_lmuxd_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_lmuxd_ops);
+
+	return 0;
+}
+
+static const struct of_device_id imx_lmuxd_dt_ids[] = {
+	{ .compatible = "fsl,imx-lcdif-mux-display", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_lmuxd_dt_ids);
+
+static struct platform_driver imx_lmuxd_driver = {
+	.probe		= imx_lmuxd_probe,
+	.remove		= imx_lmuxd_remove,
+	.driver		= {
+		.of_match_table = imx_lmuxd_dt_ids,
+		.name	= "imx-lcdif-mux-display",
+	},
+};
+
+module_platform_driver(imx_lmuxd_driver);
+
+MODULE_DESCRIPTION("i.MX LCDIF mux display driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-lcdif-mux-display");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/Kconfig
@@ -0,0 +1,8 @@
+config DRM_IMX_LCDIF
+	tristate "i.MX LCDIF controller DRM driver"
+	depends on DRM_IMX
+	depends on IMX_LCDIF_CORE
+	default y if DRM_IMX=y
+	default m if DRM_IMX=m
+	help
+	  enable i.MX LCDIF controller DRM driver under DRM_IMX.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -I $(srctree)/$(src)/../
+
+imx-lcdif-crtc-objs := lcdif-crtc.o lcdif-plane.o lcdif-kms.o
+obj-$(CONFIG_DRM_IMX_LCDIF) += imx-lcdif-crtc.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/lcdif-crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/lcdif-crtc.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/component.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <video/imx-lcdif.h>
+#include <video/videomode.h>
+
+#include "imx-drm.h"
+#include "lcdif-plane.h"
+#include "lcdif-kms.h"
+
+struct lcdif_crtc {
+	struct device *dev;
+
+	struct drm_crtc base;
+	struct lcdif_plane *plane[2];
+
+	int vbl_irq;
+	u32 pix_fmt;		/* drm fourcc */
+};
+
+#define to_lcdif_crtc(crtc) container_of(crtc, struct lcdif_crtc, base)
+
+static void lcdif_crtc_reset(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+		state = to_imx_crtc_state(crtc->state);
+		kfree(state);
+		crtc->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	crtc->state = &state->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *lcdif_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state, *orig_state;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	orig_state = to_imx_crtc_state(crtc->state);
+	state->bus_format = orig_state->bus_format;
+	state->bus_flags = orig_state->bus_flags;
+	state->di_hsync_pin = orig_state->di_hsync_pin;
+	state->di_vsync_pin = orig_state->di_vsync_pin;
+
+	return &state->base;
+}
+
+static void lcdif_crtc_destroy_state(struct drm_crtc *crtc,
+				     struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(state);
+	kfree(to_imx_crtc_state(state));
+}
+
+static int lcdif_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
+{
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+
+	/* Don't check 'bus_format' when CRTC is
+	 * going to be disabled.
+	 */
+	if (!state->enable)
+		return 0;
+
+	/* For the commit that the CRTC is active
+	 * without planes attached to it should be
+	 * invalid.
+	 */
+	if (state->active && !state->plane_mask)
+		return -EINVAL;
+
+	/* check the requested bus format can be
+	 * supported by LCDIF CTRC or not
+	 */
+	switch (imx_crtc_state->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		break;
+	default:
+		dev_err(lcdif_crtc->dev,
+			"unsupported bus format: %#x\n",
+			imx_crtc_state->bus_format);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void lcdif_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	drm_crtc_vblank_on(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	/* LCDIF doesn't have command buffer */
+	return;
+}
+
+static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc,
+				     struct drm_crtc_state *old_crtc_state)
+{
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct videomode vm;
+
+	drm_display_mode_to_videomode(mode, &vm);
+
+	if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_HIGH)
+		vm.flags |= DISPLAY_FLAGS_DE_HIGH;
+	else
+		vm.flags |= DISPLAY_FLAGS_DE_LOW;
+
+	if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+		vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+	else
+		vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+
+	pm_runtime_get_sync(lcdif_crtc->dev->parent);
+
+	lcdif_set_mode(lcdif, &vm);
+
+	/* config LCDIF output bus format */
+	lcdif_set_bus_fmt(lcdif, imx_crtc_state->bus_format);
+
+	/* defer the lcdif controller enable to plane update,
+	 * since until then the lcdif config is complete to
+	 * enable the controller to run actually.
+	 */
+}
+
+static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc,
+				      struct drm_crtc_state *old_crtc_state)
+{
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+
+	drm_crtc_vblank_off(crtc);
+
+	lcdif_disable_controller(lcdif);
+
+	pm_runtime_put(lcdif_crtc->dev->parent);
+}
+
+static enum drm_mode_status lcdif_crtc_mode_valid(struct drm_crtc *crtc,
+						  const struct drm_display_mode *mode)
+{
+	u8 vic;
+	long rate;
+	struct drm_display_mode *dmt, copy;
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	/* check CEA-861 mode */
+	vic = drm_match_cea_mode(mode);
+	if (vic)
+		goto check_pix_clk;
+
+       /* check DMT mode */
+	dmt = drm_mode_find_dmt(crtc->dev, mode->hdisplay, mode->vdisplay,
+				drm_mode_vrefresh(mode), false);
+	if (dmt) {
+		drm_mode_copy(&copy, dmt);
+		drm_mode_destroy(crtc->dev, dmt);
+
+		if (drm_mode_equal(mode, &copy))
+			goto check_pix_clk;
+	}
+
+	return MODE_OK;
+
+check_pix_clk:
+	rate = lcdif_pix_clk_round_rate(lcdif, mode->clock * 1000);
+
+	if (rate <= 0 || rate != mode->clock * 1000)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static const struct drm_crtc_helper_funcs lcdif_helper_funcs = {
+	.atomic_check	= lcdif_crtc_atomic_check,
+	.atomic_begin	= lcdif_crtc_atomic_begin,
+	.atomic_flush	= lcdif_crtc_atomic_flush,
+	.atomic_enable	= lcdif_crtc_atomic_enable,
+	.atomic_disable	= lcdif_crtc_atomic_disable,
+	.mode_valid     = lcdif_crtc_mode_valid,
+};
+
+static int lcdif_enable_vblank(struct drm_crtc *crtc)
+{
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	lcdif_vblank_irq_enable(lcdif);
+	enable_irq(lcdif_crtc->vbl_irq);
+
+	return 0;
+}
+
+static void lcdif_disable_vblank(struct drm_crtc *crtc)
+{
+	struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	disable_irq_nosync(lcdif_crtc->vbl_irq);
+	lcdif_vblank_irq_disable(lcdif);
+}
+
+static const struct drm_crtc_funcs lcdif_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy    = drm_crtc_cleanup,
+	.page_flip  = drm_atomic_helper_page_flip,
+	.reset      = lcdif_crtc_reset,
+	.atomic_duplicate_state = lcdif_crtc_duplicate_state,
+	.atomic_destroy_state	= lcdif_crtc_destroy_state,
+	.enable_vblank	= lcdif_enable_vblank,
+	.disable_vblank = lcdif_disable_vblank,
+};
+
+static irqreturn_t lcdif_crtc_vblank_irq_handler(int irq, void *dev_id)
+{
+	struct lcdif_crtc *lcdif_crtc = dev_id;
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	drm_crtc_handle_vblank(&lcdif_crtc->base);
+
+	lcdif_vblank_irq_clear(lcdif);
+
+	return IRQ_HANDLED;
+}
+
+static int lcdif_crtc_init(struct lcdif_crtc *lcdif_crtc,
+			   struct lcdif_client_platformdata *pdata,
+			   struct drm_device *drm)
+{
+	int ret;
+	struct lcdif_plane *primary = lcdif_crtc->plane[0];
+	struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+	/* Primary plane
+	 * The 'possible_crtcs' of primary plane will be
+	 * recalculated during the 'crtc' initialization
+	 * later.
+	 */
+	primary = lcdif_plane_init(drm, lcdif, 0, DRM_PLANE_TYPE_PRIMARY, 0);
+	if (IS_ERR(primary))
+		return PTR_ERR(primary);
+	lcdif_crtc->plane[0] = primary;
+
+	/* TODO: Overlay plane */
+
+	lcdif_crtc->base.port = pdata->of_node;
+	drm_crtc_helper_add(&lcdif_crtc->base, &lcdif_helper_funcs);
+	ret = drm_crtc_init_with_planes(drm, &lcdif_crtc->base,
+			&lcdif_crtc->plane[0]->base, NULL,
+			&lcdif_crtc_funcs, NULL);
+	if (ret) {
+		dev_err(lcdif_crtc->dev, "failed to init crtc\n");
+		goto primary_plane_deinit;
+	}
+
+	lcdif_crtc->vbl_irq = lcdif_vblank_irq_get(lcdif);
+	WARN_ON(lcdif_crtc->vbl_irq < 0);
+
+	ret = devm_request_irq(lcdif_crtc->dev, lcdif_crtc->vbl_irq,
+			       lcdif_crtc_vblank_irq_handler, 0,
+			       dev_name(lcdif_crtc->dev), lcdif_crtc);
+	if (ret) {
+		dev_err(lcdif_crtc->dev,
+			"vblank irq request failed: %d\n", ret);
+		goto primary_plane_deinit;
+	}
+
+	disable_irq(lcdif_crtc->vbl_irq);
+
+	return 0;
+
+primary_plane_deinit:
+	lcdif_plane_deinit(drm, primary);
+
+	return ret;
+}
+
+static int lcdif_crtc_bind(struct device *dev, struct device *master,
+			   void *data)
+{
+	int ret;
+	struct drm_device *drm = data;
+	struct lcdif_crtc *lcdif_crtc = dev_get_drvdata(dev);
+	struct lcdif_client_platformdata *pdata = dev->platform_data;
+
+	dev_dbg(dev, "%s: lcdif crtc bind begin\n", __func__);
+
+	ret = lcdif_crtc_init(lcdif_crtc, pdata, drm);
+	if (ret)
+		return ret;
+
+	if (!drm->mode_config.funcs)
+		drm->mode_config.funcs = &lcdif_drm_mode_config_funcs;
+
+	if (!drm->mode_config.helper_private)
+		drm->mode_config.helper_private = &lcdif_drm_mode_config_helpers;
+
+	/* limit the max width and height */
+	drm->mode_config.max_width  = 1920;
+	drm->mode_config.max_height = 1920;
+
+	dev_dbg(dev, "%s: lcdif crtc bind end\n", __func__);
+
+	return 0;
+}
+
+static void lcdif_crtc_unbind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct drm_device *drm = data;
+	struct lcdif_crtc *lcdif_crtc = dev_get_drvdata(dev);
+
+	lcdif_plane_deinit(drm, lcdif_crtc->plane[0]);
+}
+
+static const struct component_ops lcdif_crtc_ops = {
+	.bind   = lcdif_crtc_bind,
+	.unbind = lcdif_crtc_unbind,
+};
+
+static int lcdif_crtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lcdif_crtc *lcdif_crtc;
+
+	dev_dbg(&pdev->dev, "%s: lcdif crtc probe begin\n", __func__);
+
+	lcdif_crtc = devm_kzalloc(dev, sizeof(*lcdif_crtc), GFP_KERNEL);
+	if (!lcdif_crtc)
+		return -ENOMEM;
+
+	lcdif_crtc->dev = dev;
+
+	if (!dev->platform_data) {
+		dev_err(dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	dev_set_drvdata(dev, lcdif_crtc);
+
+	return component_add(dev, &lcdif_crtc_ops);
+}
+
+static int lcdif_crtc_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &lcdif_crtc_ops);
+
+	return 0;
+}
+
+static struct platform_driver lcdif_crtc_driver = {
+	.probe  = lcdif_crtc_probe,
+	.remove = lcdif_crtc_remove,
+	.driver = {
+		.name = "imx-lcdif-crtc",
+	},
+};
+module_platform_driver(lcdif_crtc_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIF DRM CRTC driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/lcdif-kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/lcdif-kms.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+static void lcdif_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+
+	drm_atomic_helper_commit_modeset_disables(dev, state);
+
+	drm_atomic_helper_commit_modeset_enables(dev, state);
+
+	drm_atomic_helper_commit_planes(dev, state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+	drm_atomic_helper_commit_hw_done(state);
+
+	drm_atomic_helper_wait_for_vblanks(dev, state);
+
+	drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+const struct drm_mode_config_funcs lcdif_drm_mode_config_funcs = {
+	.fb_create     = drm_gem_fb_create,
+	.atomic_check  = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+struct drm_mode_config_helper_funcs lcdif_drm_mode_config_helpers = {
+	.atomic_commit_tail = lcdif_drm_atomic_commit_tail,
+};
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/lcdif-kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/lcdif-kms.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __LCDIF_KMS_H
+#define __LCDIF_KMS_H
+
+extern const struct drm_mode_config_funcs lcdif_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs lcdif_drm_mode_config_helpers;
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/lcdif-plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/lcdif-plane.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_rect.h>
+#include <video/imx-lcdif.h>
+
+#include "lcdif-plane.h"
+
+static uint32_t lcdif_pixel_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_BGR565,
+};
+
+static int lcdif_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *plane_state)
+{
+	int ret;
+	struct drm_plane_state *old_state = plane->state;
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_framebuffer *old_fb = old_state->fb;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *mode;
+	struct drm_rect clip = { 0 };
+
+	/* 'fb' should also be NULL which has been checked in
+	 * the core sanity check function 'drm_atomic_plane_check()'
+	 */
+	if (!plane_state->crtc) {
+		WARN_ON(fb);
+		return 0;
+	}
+
+	/* lcdif crtc can only display from (0,0) for each plane */
+	if (plane_state->crtc_x || plane_state->crtc_y)
+		return -EINVAL;
+
+	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
+							plane_state->crtc);
+	mode = &crtc_state->adjusted_mode;
+
+	clip.x2 = mode->hdisplay;
+	clip.y2 = mode->vdisplay;
+
+	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  false, true);
+
+	if (ret)
+		return ret;
+
+	if (!plane_state->visible)
+		return -EINVAL;
+
+	/* force 'mode_changed' when fb pitches or format
+	 * changed, since the pitch and format related
+	 * registers configuration of LCDIF can not be
+	 * done when LCDIF is running and 'mode_changed'
+	 * means a full modeset is required.
+	 */
+	if (old_fb && likely(!crtc_state->mode_changed)) {
+		if (old_fb->pitches[0] != fb->pitches[0] ||
+		    old_fb->format->format != fb->format->format)
+			crtc_state->mode_changed = true;
+	}
+
+	return 0;
+}
+
+static void lcdif_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct lcdif_plane *lcdif_plane = to_lcdif_plane(plane);
+	struct lcdif_soc *lcdif = lcdif_plane->lcdif;
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem_obj = NULL;
+	u32 fb_addr, src_off, src_w, fb_idx, cpp, stride;
+	bool crop;
+
+	/* plane and crtc is disabling */
+	if (!fb)
+		return;
+
+	/* TODO: for now we just update the next buf addr
+	 * and the fb pixel format, since the mode set will
+	 * be done in crtc's ->enable() helper func
+	 */
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		/* TODO: only support RGB */
+		gem_obj = drm_fb_cma_get_gem_obj(fb, 0);
+		src_off = (state->src_y >> 16) * fb->pitches[0] +
+			  (state->src_x >> 16) * fb->format->cpp[0];
+		fb_addr = gem_obj->paddr + fb->offsets[0] + src_off;
+		fb_idx  = 0;
+		break;
+	default:
+		/* TODO: add overlay later */
+		return;
+	}
+
+	lcdif_set_fb_addr(lcdif, fb_idx, fb_addr);
+
+	/* Config pixel format and horizontal cropping
+	 * if CRTC needs a full modeset which needs to
+	 * enable LCDIF to run at the end.
+	 */
+	if (unlikely(drm_atomic_crtc_needs_modeset(state->crtc->state))) {
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			lcdif_set_pix_fmt(lcdif, fb->format->format);
+
+		cpp = fb->format->cpp[0];
+		stride = DIV_ROUND_UP(fb->pitches[0], cpp);
+
+		src_w = state->src_w >> 16;
+		WARN_ON(src_w > fb->width);
+
+		crop  = src_w != stride ? true : false;
+		lcdif_set_fb_hcrop(lcdif, src_w, stride, crop);
+
+		lcdif_enable_controller(lcdif);
+	}
+}
+
+static void lcdif_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+
+	WARN_ON(fb);
+
+	/* TODO: CRTC disabled has been done by CRTC helper function,
+	 * so it seems that no more required, the only possible thing
+	 * is to set next buf addr to 0 in CRTC
+	 */
+}
+
+static const struct drm_plane_helper_funcs lcdif_plane_helper_funcs = {
+	.atomic_check	= lcdif_plane_atomic_check,
+	.atomic_update	= lcdif_plane_atomic_update,
+	.atomic_disable	= lcdif_plane_atomic_disable,
+};
+
+static void lcdif_plane_destroy(struct drm_plane *plane)
+{
+	struct lcdif_plane *lcdif_plane = to_lcdif_plane(plane);
+
+	drm_plane_cleanup(plane);
+	kfree(lcdif_plane);
+}
+
+static const struct drm_plane_funcs lcdif_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy	= lcdif_plane_destroy,
+	.reset		= drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
+};
+
+struct lcdif_plane *lcdif_plane_init(struct drm_device *dev,
+				     struct lcdif_soc *lcdif,
+				     unsigned int possible_crtcs,
+				     enum drm_plane_type type,
+				     unsigned int zpos)
+{
+	int ret;
+	struct lcdif_plane *lcdif_plane;
+
+	/* lcdif doesn't support fb modifiers */
+	if (zpos || dev->mode_config.allow_fb_modifiers)
+		return ERR_PTR(-EINVAL);
+
+	lcdif_plane = kzalloc(sizeof(*lcdif_plane), GFP_KERNEL);
+	if (!lcdif_plane)
+		return ERR_PTR(-ENOMEM);
+
+	lcdif_plane->lcdif = lcdif;
+
+	drm_plane_helper_add(&lcdif_plane->base, &lcdif_plane_helper_funcs);
+	ret = drm_universal_plane_init(dev, &lcdif_plane->base, possible_crtcs,
+				       &lcdif_plane_funcs, lcdif_pixel_formats,
+				       ARRAY_SIZE(lcdif_pixel_formats), NULL,
+				       type, NULL);
+	if (ret) {
+		kfree(lcdif_plane);
+		return ERR_PTR(ret);
+	}
+
+	ret = drm_plane_create_zpos_immutable_property(&lcdif_plane->base, zpos);
+	if (ret) {
+		kfree(lcdif_plane);
+		return ERR_PTR(ret);
+	}
+
+	return lcdif_plane;
+}
+
+void lcdif_plane_deinit(struct drm_device *dev,
+			struct lcdif_plane *lcdif_plane)
+{
+	struct drm_plane *plane = &lcdif_plane->base;
+
+	if (plane->zpos_property)
+		drm_property_destroy(dev, plane->zpos_property);
+
+	lcdif_plane_destroy(plane);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdif/lcdif-plane.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdif/lcdif-plane.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __LCDIF_PLANE_H
+#define __LCDIF_PLANE_H
+
+#include <drm/drm_plane.h>
+#include <video/imx-lcdif.h>
+
+struct lcdif_plane {
+	struct drm_plane base;
+	struct lcdif_soc *lcdif;
+};
+
+#define to_lcdif_plane(plane) container_of(plane, struct lcdif_plane, base)
+
+struct lcdif_plane *lcdif_plane_init(struct drm_device *drm,
+				     struct lcdif_soc *lcdif,
+				     unsigned int possible_crtcs,
+				     enum drm_plane_type type,
+				     unsigned int zpos);
+
+void lcdif_plane_deinit(struct drm_device *dev,
+			struct lcdif_plane *lcdif_plane);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/Kconfig
@@ -0,0 +1,8 @@
+config DRM_IMX_LCDIFV3
+	tristate "i.MX LCDIFV3 controller DRM driver"
+	depends on DRM_IMX
+	depends on IMX_LCDIFV3_CORE
+	default y if DRM_IMX=y
+	default m if DRM_IMX=m
+	help
+	  enable i.MX LCDIFV3 controller DRM driver under DRM_IMX.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -I $(srctree)/$(src)/../
+
+imx-lcdifv3-crtc-objs := lcdifv3-crtc.o lcdifv3-plane.o lcdifv3-kms.o
+obj-$(CONFIG_DRM_IMX_LCDIFV3) += imx-lcdifv3-crtc.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019,2020 NXP
+ */
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <video/imx-lcdifv3.h>
+#include <video/videomode.h>
+
+#include "imx-drm.h"
+#include "lcdifv3-plane.h"
+#include "lcdifv3-kms.h"
+
+struct lcdifv3_crtc {
+	struct device *dev;
+
+	struct drm_crtc base;
+	struct lcdifv3_plane *plane[2];
+
+	int vbl_irq;
+	u32 pix_fmt;		/* drm fourcc */
+};
+
+#define to_lcdifv3_crtc(crtc) container_of(crtc, struct lcdifv3_crtc, base)
+
+static void lcdifv3_crtc_reset(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+		state = to_imx_crtc_state(crtc->state);
+		kfree(state);
+		crtc->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	crtc->state = &state->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *lcdifv3_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct imx_crtc_state *state, *orig_state;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	orig_state = to_imx_crtc_state(crtc->state);
+	state->bus_format = orig_state->bus_format;
+	state->bus_flags = orig_state->bus_flags;
+	state->di_hsync_pin = orig_state->di_hsync_pin;
+	state->di_vsync_pin = orig_state->di_vsync_pin;
+
+	return &state->base;
+}
+
+static void lcdifv3_crtc_destroy_state(struct drm_crtc *crtc,
+				     struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(state);
+	kfree(to_imx_crtc_state(state));
+}
+
+static int lcdifv3_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+
+	/* Don't check 'bus_format' when CRTC is
+	 * going to be disabled.
+	 */
+	if (!state->enable)
+		return 0;
+
+	/* For the commit that the CRTC is active
+	 * without planes attached to it should be
+	 * invalid.
+	 */
+	if (state->active && !state->plane_mask)
+		return -EINVAL;
+
+	/* check the requested bus format can be
+	 * supported by LCDIF CTRC or not
+	 */
+	switch (imx_crtc_state->bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		break;
+	default:
+		dev_err(lcdifv3_crtc->dev,
+			"unsupported bus format: %#x\n",
+			imx_crtc_state->bus_format);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void lcdifv3_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	drm_crtc_vblank_on(crtc);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc));
+		drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void lcdifv3_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	/* kick shadow load for plane config */
+	lcdifv3_en_shadow_load(lcdifv3);
+}
+
+static void lcdifv3_crtc_atomic_enable(struct drm_crtc *crtc,
+				     struct drm_crtc_state *old_crtc_state)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+	struct videomode vm;
+
+	drm_display_mode_to_videomode(mode, &vm);
+
+	if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_HIGH)
+		vm.flags |= DISPLAY_FLAGS_DE_HIGH;
+	else
+		vm.flags |= DISPLAY_FLAGS_DE_LOW;
+
+	if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+		vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+	else
+		vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+
+	pm_runtime_get_sync(lcdifv3_crtc->dev->parent);
+
+	lcdifv3_set_mode(lcdifv3, &vm);
+
+	/* config LCDIF output bus format */
+	lcdifv3_set_bus_fmt(lcdifv3, imx_crtc_state->bus_format);
+
+	/* run LCDIFv3 */
+	lcdifv3_enable_controller(lcdifv3);
+}
+
+static void lcdifv3_crtc_atomic_disable(struct drm_crtc *crtc,
+				      struct drm_crtc_state *old_crtc_state)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+
+	drm_crtc_vblank_off(crtc);
+
+	lcdifv3_disable_controller(lcdifv3);
+
+	pm_runtime_put(lcdifv3_crtc->dev->parent);
+}
+
+static enum drm_mode_status lcdifv3_crtc_mode_valid(struct drm_crtc * crtc,
+						    const struct drm_display_mode *mode)
+{
+	u8 vic;
+	long rate;
+	const struct drm_display_mode *dmt;
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	/* check CEA-861 mode */
+	vic = drm_match_cea_mode(mode);
+	if (vic)
+		goto check_pix_clk;
+
+	/* check DMT mode */
+	dmt = drm_mode_find_dmt(crtc->dev, mode->hdisplay, mode->vdisplay,
+				drm_mode_vrefresh(mode), false);
+	if (dmt && drm_mode_equal(mode, dmt))
+		goto check_pix_clk;
+
+	return MODE_OK;
+
+check_pix_clk:
+	rate = lcdifv3_pix_clk_round_rate(lcdifv3, mode->clock * 1000);
+
+	if (rate <= 0 || rate != mode->clock * 1000)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static const struct drm_crtc_helper_funcs lcdifv3_helper_funcs = {
+	.atomic_check	= lcdifv3_crtc_atomic_check,
+	.atomic_begin	= lcdifv3_crtc_atomic_begin,
+	.atomic_flush	= lcdifv3_crtc_atomic_flush,
+	.atomic_enable	= lcdifv3_crtc_atomic_enable,
+	.atomic_disable	= lcdifv3_crtc_atomic_disable,
+	.mode_valid	= lcdifv3_crtc_mode_valid,
+};
+
+static int lcdifv3_enable_vblank(struct drm_crtc *crtc)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	lcdifv3_vblank_irq_enable(lcdifv3);
+	enable_irq(lcdifv3_crtc->vbl_irq);
+
+	return 0;
+}
+
+static void lcdifv3_disable_vblank(struct drm_crtc *crtc)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc);
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	disable_irq_nosync(lcdifv3_crtc->vbl_irq);
+	lcdifv3_vblank_irq_disable(lcdifv3);
+}
+
+static const struct drm_crtc_funcs lcdifv3_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy    = drm_crtc_cleanup,
+	.page_flip  = drm_atomic_helper_page_flip,
+	.reset      = lcdifv3_crtc_reset,
+	.atomic_duplicate_state = lcdifv3_crtc_duplicate_state,
+	.atomic_destroy_state	= lcdifv3_crtc_destroy_state,
+	.enable_vblank	= lcdifv3_enable_vblank,
+	.disable_vblank = lcdifv3_disable_vblank,
+};
+
+static irqreturn_t lcdifv3_crtc_vblank_irq_handler(int irq, void *dev_id)
+{
+	struct lcdifv3_crtc *lcdifv3_crtc = dev_id;
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	drm_crtc_handle_vblank(&lcdifv3_crtc->base);
+
+	lcdifv3_vblank_irq_clear(lcdifv3);
+
+	return IRQ_HANDLED;
+}
+
+static int lcdifv3_crtc_init(struct lcdifv3_crtc *lcdifv3_crtc,
+			     struct lcdifv3_client_platformdata *pdata,
+			     struct drm_device *drm)
+{
+	int ret;
+	struct lcdifv3_plane *primary = lcdifv3_crtc->plane[0];
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent);
+
+	/* Primary plane
+	 * The 'possible_crtcs' of primary plane will be
+	 * recalculated during the 'crtc' initialization
+	 * later.
+	 */
+	primary = lcdifv3_plane_init(drm, lcdifv3, 0, DRM_PLANE_TYPE_PRIMARY, 0);
+	if (IS_ERR(primary))
+		return PTR_ERR(primary);
+	lcdifv3_crtc->plane[0] = primary;
+
+	/* TODO: Overlay plane */
+
+	lcdifv3_crtc->base.port = pdata->of_node;
+	drm_crtc_helper_add(&lcdifv3_crtc->base, &lcdifv3_helper_funcs);
+	ret = drm_crtc_init_with_planes(drm, &lcdifv3_crtc->base,
+			&lcdifv3_crtc->plane[0]->base, NULL,
+			&lcdifv3_crtc_funcs, NULL);
+	if (ret) {
+		dev_err(lcdifv3_crtc->dev, "failed to init crtc\n");
+		return ret;
+	}
+
+	lcdifv3_crtc->vbl_irq = lcdifv3_vblank_irq_get(lcdifv3);
+	WARN_ON(lcdifv3_crtc->vbl_irq < 0);
+
+	ret = devm_request_irq(lcdifv3_crtc->dev, lcdifv3_crtc->vbl_irq,
+			       lcdifv3_crtc_vblank_irq_handler, 0,
+			       dev_name(lcdifv3_crtc->dev), lcdifv3_crtc);
+	if (ret) {
+		dev_err(lcdifv3_crtc->dev,
+			"vblank irq request failed: %d\n", ret);
+		return ret;
+	}
+
+	disable_irq(lcdifv3_crtc->vbl_irq);
+
+	return 0;
+}
+
+static int lcdifv3_crtc_bind(struct device *dev, struct device *master,
+			   void *data)
+{
+	int ret;
+	struct drm_device *drm = data;
+	struct lcdifv3_crtc *lcdifv3_crtc = dev_get_drvdata(dev);
+	struct lcdifv3_client_platformdata *pdata = dev->platform_data;
+
+	dev_dbg(dev, "%s: lcdifv3 crtc bind begin\n", __func__);
+
+	ret = lcdifv3_crtc_init(lcdifv3_crtc, pdata, drm);
+	if (ret)
+		return ret;
+
+	if (!drm->mode_config.funcs)
+		drm->mode_config.funcs = &lcdifv3_drm_mode_config_funcs;
+
+	if (!drm->mode_config.helper_private)
+		drm->mode_config.helper_private = &lcdifv3_drm_mode_config_helpers;
+
+	/* limit the max width and height */
+	drm->mode_config.max_width  = 4096;
+	drm->mode_config.max_height = 4096;
+
+	dev_dbg(dev, "%s: lcdifv3 crtc bind end\n", __func__);
+
+	return 0;
+}
+
+static void lcdifv3_crtc_unbind(struct device *dev, struct device *master,
+			      void *data)
+{
+	/* No special to be done */
+}
+
+static const struct component_ops lcdifv3_crtc_ops = {
+	.bind   = lcdifv3_crtc_bind,
+	.unbind = lcdifv3_crtc_unbind,
+};
+
+static int lcdifv3_crtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lcdifv3_crtc *lcdifv3_crtc;
+
+	dev_dbg(&pdev->dev, "%s: lcdifv3 crtc probe begin\n", __func__);
+
+	if (!dev->platform_data) {
+		dev_err(dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	lcdifv3_crtc = devm_kzalloc(dev, sizeof(*lcdifv3_crtc), GFP_KERNEL);
+	if (!lcdifv3_crtc)
+		return -ENOMEM;
+
+	lcdifv3_crtc->dev = dev;
+	dev_set_drvdata(dev, lcdifv3_crtc);
+
+	return component_add(dev, &lcdifv3_crtc_ops);
+}
+
+static int lcdifv3_crtc_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &lcdifv3_crtc_ops);
+
+	return 0;
+}
+
+static struct platform_driver lcdifv3_crtc_driver = {
+	.probe  = lcdifv3_crtc_probe,
+	.remove = lcdifv3_crtc_remove,
+	.driver = {
+		.name = "imx-lcdifv3-crtc",
+	},
+};
+module_platform_driver(lcdifv3_crtc_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIFV3 DRM CRTC driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-lcdifv3-crtc");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/lcdifv3-kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/lcdifv3-kms.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+static void lcdifv3_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+
+	drm_atomic_helper_commit_modeset_disables(dev, state);
+
+	drm_atomic_helper_commit_modeset_enables(dev, state);
+
+	drm_atomic_helper_commit_planes(dev, state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+	drm_atomic_helper_commit_hw_done(state);
+
+	drm_atomic_helper_wait_for_vblanks(dev, state);
+
+	drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+const struct drm_mode_config_funcs lcdifv3_drm_mode_config_funcs = {
+	.fb_create     = drm_gem_fb_create,
+	.atomic_check  = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+struct drm_mode_config_helper_funcs lcdifv3_drm_mode_config_helpers = {
+	.atomic_commit_tail = lcdifv3_drm_atomic_commit_tail,
+};
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/lcdifv3-kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/lcdifv3-kms.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#ifndef __LCDIFV3_KMS_H
+#define __LCDIFV3_KMS_H
+
+extern const struct drm_mode_config_funcs lcdifv3_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs lcdifv3_drm_mode_config_helpers;
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/lcdifv3-plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/lcdifv3-plane.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019,2020 NXP
+ */
+
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_rect.h>
+#include <video/imx-lcdifv3.h>
+
+#include "lcdifv3-plane.h"
+
+static uint32_t lcdifv3_pixel_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+};
+
+static int lcdifv3_plane_atomic_check(struct drm_plane *plane,
+				      struct drm_plane_state *plane_state)
+{
+	int ret;
+	struct drm_plane_state *old_state = plane->state;
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_framebuffer *old_fb = old_state->fb;
+	struct drm_crtc_state *crtc_state;
+	struct drm_display_mode *mode;
+
+	/* 'fb' should also be NULL which has been checked in
+	 * the core sanity check function 'drm_atomic_plane_check()'
+	 */
+	if (!plane_state->crtc) {
+		WARN_ON(fb);
+		return 0;
+	}
+
+	/* lcdifv3 crtc can only display from (0,0) for each plane */
+	if (plane_state->crtc_x || plane_state->crtc_y)
+		return -EINVAL;
+
+	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
+							plane_state->crtc);
+	mode = &crtc_state->adjusted_mode;
+
+	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  false, true);
+	if (ret)
+		return ret;
+
+	if (!plane_state->visible)
+		return -EINVAL;
+
+	/* force 'mode_changed' when fb pitches changed, since
+	 * the pitch related registers configuration of LCDIF
+	 * can not be done when LCDIF is running.
+	 */
+	if (old_fb && likely(!crtc_state->mode_changed)) {
+		if (old_fb->pitches[0] != fb->pitches[0])
+			crtc_state->mode_changed = true;
+	}
+
+	return 0;
+}
+
+static void lcdifv3_plane_atomic_update(struct drm_plane *plane,
+					struct drm_plane_state *old_state)
+{
+	struct lcdifv3_plane *lcdifv3_plane = to_lcdifv3_plane(plane);
+	struct lcdifv3_soc *lcdifv3 = lcdifv3_plane->lcdifv3;
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem_obj = NULL;
+	u32 fb_addr, src_off, src_w, fb_idx, cpp, stride;
+	bool crop;
+
+	/* plane and crtc is disabling */
+	if (!fb)
+		return;
+
+	/* TODO: for now we just update the next buf addr
+	 * and the fb pixel format, since the mode set will
+	 * be done in crtc's ->enable() helper func
+	 */
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+		lcdifv3_set_pix_fmt(lcdifv3, fb->format->format);
+
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		/* TODO: only support RGB */
+		gem_obj = drm_fb_cma_get_gem_obj(fb, 0);
+		src_off = (state->src_y >> 16) * fb->pitches[0] +
+			  (state->src_x >> 16) * fb->format->cpp[0];
+		fb_addr = gem_obj->paddr + fb->offsets[0] + src_off;
+		fb_idx  = 0;
+		break;
+	default:
+		/* TODO: add overlay later */
+		return;
+	}
+
+	lcdifv3_set_fb_addr(lcdifv3, fb_idx, fb_addr);
+
+	/* config horizontal cropping if crtc needs modeset */
+	if (unlikely(drm_atomic_crtc_needs_modeset(state->crtc->state))) {
+		cpp = fb->format->cpp[0];
+		stride = DIV_ROUND_UP(fb->pitches[0], cpp);
+
+		src_w = state->src_w >> 16;
+		WARN_ON(src_w > fb->width);
+
+		crop  = src_w != stride ? true : false;
+		lcdifv3_set_fb_hcrop(lcdifv3, src_w, fb->pitches[0], crop);
+	}
+}
+
+static void lcdifv3_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+
+	WARN_ON(fb);
+
+	/* TODO: CRTC disabled has been done by CRTC helper function,
+	 * so it seems that no more required, the only possible thing
+	 * is to set next buf addr to 0 in CRTC
+	 */
+}
+
+static const struct drm_plane_helper_funcs lcdifv3_plane_helper_funcs = {
+	.atomic_check	= lcdifv3_plane_atomic_check,
+	.atomic_update	= lcdifv3_plane_atomic_update,
+	.atomic_disable	= lcdifv3_plane_atomic_disable,
+};
+
+static void lcdifv3_plane_destroy(struct drm_plane *plane)
+{
+	struct lcdifv3_plane *lcdifv3_plane = to_lcdifv3_plane(plane);
+
+	drm_plane_cleanup(plane);
+	kfree(lcdifv3_plane);
+}
+
+static const struct drm_plane_funcs lcdifv3_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy	= lcdifv3_plane_destroy,
+	.reset		= drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
+};
+
+struct lcdifv3_plane *lcdifv3_plane_init(struct drm_device *dev,
+				     struct lcdifv3_soc *lcdifv3,
+				     unsigned int possible_crtcs,
+				     enum drm_plane_type type,
+				     unsigned int zpos)
+{
+	int ret;
+	struct lcdifv3_plane *lcdifv3_plane;
+
+	/* lcdifv3 doesn't support fb modifiers */
+	if (zpos || dev->mode_config.allow_fb_modifiers)
+		return ERR_PTR(-EINVAL);
+
+	lcdifv3_plane = kzalloc(sizeof(*lcdifv3_plane), GFP_KERNEL);
+	if (!lcdifv3_plane)
+		return ERR_PTR(-ENOMEM);
+
+	lcdifv3_plane->lcdifv3 = lcdifv3;
+
+	drm_plane_helper_add(&lcdifv3_plane->base, &lcdifv3_plane_helper_funcs);
+	ret = drm_universal_plane_init(dev, &lcdifv3_plane->base, possible_crtcs,
+				       &lcdifv3_plane_funcs, lcdifv3_pixel_formats,
+				       ARRAY_SIZE(lcdifv3_pixel_formats), NULL,
+				       type, NULL);
+	if (ret) {
+		kfree(lcdifv3_plane);
+		return ERR_PTR(ret);
+	}
+
+	ret = drm_plane_create_zpos_immutable_property(&lcdifv3_plane->base, zpos);
+	if (ret) {
+		kfree(lcdifv3_plane);
+		return ERR_PTR(ret);
+	}
+
+	return lcdifv3_plane;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/lcdifv3/lcdifv3-plane.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/lcdifv3/lcdifv3-plane.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019,2020 NXP
+ */
+
+#ifndef __LCDIFV3_PLANE_H
+#define __LCDIFV3_PLANE_H
+
+#include <drm/drm_plane.h>
+#include <video/imx-lcdifv3.h>
+
+struct lcdifv3_plane {
+	struct drm_plane base;
+	struct lcdifv3_soc *lcdifv3;
+};
+
+#define to_lcdifv3_plane(plane) container_of(plane, struct lcdifv3_plane, base)
+
+struct lcdifv3_plane *lcdifv3_plane_init(struct drm_device *drm,
+				     struct lcdifv3_soc *lcdifv3,
+				     unsigned int possible_crtcs,
+				     enum drm_plane_type type,
+				     unsigned int zpos);
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_IMX_CDNS_MHDP
+	tristate "NXP i.MX MX8 DRM HDMI/DP"
+	select DRM_CDNS_MHDP
+	select DRM_CDNS_DP
+	select DRM_CDNS_HDMI
+	select DRM_CDNS_AUDIO
+	depends on DRM_IMX
+	help
+	  Choose this if you want to use HDMI on i.MX8.
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o \
+		cdns-mhdp-hdmi-phy.o cdns-mhdp-imx8qm.o cdns-mhdp-ls1028a.o
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
@@ -0,0 +1,539 @@
+/*
+ * Cadence Display Port Interface (DP) PHY driver
+ *
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include "cdns-mhdp-phy.h"
+
+enum dp_link_rate {
+	RATE_1_6 = 162000,
+	RATE_2_1 = 216000,
+	RATE_2_4 = 243000,
+	RATE_2_7 = 270000,
+	RATE_3_2 = 324000,
+	RATE_4_3 = 432000,
+	RATE_5_4 = 540000,
+	RATE_8_1 = 810000,
+};
+
+struct phy_pll_reg {
+	u16 val[7];
+	u32 addr;
+};
+
+static const struct phy_pll_reg phy_pll_27m_cfg[] = {
+	/*  1.62    2.16    2.43    2.7     3.24    4.32    5.4      register address */
+	{{ 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E }, CMN_PLL0_VCOCAL_INIT_TMR },
+	{{ 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B }, CMN_PLL0_VCOCAL_ITER_TMR },
+	{{ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4 }, CMN_PLL0_VCOCAL_START },
+	{{ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7 }, CMN_PLL0_INTDIV },
+	{{ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1 }, CMN_PLL0_FRACDIV },
+	{{ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR },
+	{{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
+	{{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
+	{{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
+	{{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE },
+	{{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
+	{{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
+	{{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
+	{{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE},
+	{{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
+};
+
+static const struct phy_pll_reg phy_pll_24m_cfg[] = {
+	/*  1.62    2.16    2.43    2.7     3.24    4.32    5.4      register address */
+	{{ 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0 }, CMN_PLL0_VCOCAL_INIT_TMR },
+	{{ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 }, CMN_PLL0_VCOCAL_ITER_TMR },
+	{{ 0x3061, 0x3092, 0x30B3, 0x30D0, 0x3061, 0x3092, 0x30D0 }, CMN_PLL0_VCOCAL_START },
+	{{ 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0 }, CMN_PLL0_INTDIV },
+	{{ 0xF917, 0xF6C7, 0x75A1, 0xF479, 0xF917, 0xF6C7, 0xF479 }, CMN_PLL0_FRACDIV },
+	{{ 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038 }, CMN_PLL0_HIGH_THR },
+	{{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
+	{{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
+	{{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
+	{{ 0x0026, 0x0029, 0x0029, 0x0029, 0x0026, 0x0029, 0x0029 }, CMN_DIAG_PLL0_CP_TUNE },
+	{{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
+	{{ 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
+	{{ 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
+	{{ 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 }, CMN_DIAG_PLL0_TEST_MODE},
+	{{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
+};
+
+static int link_rate_index(u32 rate)
+{
+	switch (rate) {
+	case RATE_1_6:
+		return 0;
+	case RATE_2_1:
+		return 1;
+	case RATE_2_4:
+		return 2;
+	case RATE_2_7:
+		return 3;
+	case RATE_3_2:
+		return 4;
+	case RATE_4_3:
+		return 5;
+	case RATE_5_4:
+		return 6;
+	default:
+		return -1;
+	}
+}
+
+static void dp_aux_cfg(struct cdns_mhdp_device *mhdp)
+{
+	/* Power up Aux */
+	cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1);
+
+	cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_1, 0x3);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f);
+}
+
+/* PMA common configuration for 24MHz */
+static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp)
+{
+	int k;
+	u32 num_lanes = 4;
+	u16 val;
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFFF7;
+	val |= 0x0008;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	for (k = 0; k < num_lanes; k++) {
+		/* Transceiver control and diagnostic registers */
+		cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090);
+		/* Transmitter receiver detect registers */
+		cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
+		cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
+	}
+}
+
+/* Valid for 24 MHz only */
+static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp)
+{
+	u32 num_lanes = 4;
+	u32 link_rate = mhdp->dp.rate;
+	u16 val;
+	int index, i, k;
+
+	/*
+	 * PLL reference clock source select
+	 * for single ended reference clock val |= 0x0030;
+	 * for differential clock  val |= 0x0000;
+	 */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val = val & 0xFF8F;
+	val = val | 0x0030;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* DP PLL data rate 0/1 clock divider value */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= 0x00FF;
+	if (link_rate <= RATE_2_7)
+		val |= 0x2400;
+	else
+		val |= 0x1200;
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+
+	/* High speed clock 0/1 div */
+	val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
+	val &= 0xFFCC;
+	if (link_rate <= RATE_2_7)
+		val |= 0x0011;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		val &= 0xCFFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
+	}
+
+	/* DP PHY PLL 24MHz configuration */
+	index = link_rate_index(link_rate);
+	if (index < 0) {
+		dev_err(mhdp->dev, "wrong link rate index\n");
+		return;
+	}
+	for (i = 0; i < ARRAY_SIZE(phy_pll_24m_cfg); i++)
+		cdns_phy_reg_write(mhdp, phy_pll_24m_cfg[i].addr, phy_pll_24m_cfg[i].val[index]);
+
+	/* Transceiver control and diagnostic registers */
+	for (k = 0; k < num_lanes; k = k + 1) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		val &= 0x8FFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x2000;
+		else
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
+	}
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
+	}
+}
+
+/* PMA common configuration for 27MHz */
+static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp)
+{
+	u32 num_lanes = 4;
+	u16 val;
+	int k;
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFFF7;
+	val |= 0x0008;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* Startup state machine registers */
+	cdns_phy_reg_write(mhdp, CMN_SSM_BIAS_TMR, 0x0087);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLEN_TMR, 0x001B);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLPRE_TMR, 0x0036);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLVREF_TMR, 0x001B);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLLOCK_TMR, 0x006C);
+
+	/* Current calibration registers */
+	cdns_phy_reg_write(mhdp, CMN_ICAL_INIT_TMR, 0x0044);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_ITER_TMR, 0x0006);
+
+	/* Resistor calibration registers */
+	cdns_phy_reg_write(mhdp, CMN_TXPUCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPUCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPDCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPDCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_RXCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_RXCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_RX_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_RX_ADJ_ITER_TMR, 0x0006);
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		/* Power state machine registers */
+		cdns_phy_reg_write(mhdp, XCVR_PSM_CAL_TMR  | (k << 9), 0x016D);
+		cdns_phy_reg_write(mhdp, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D);
+		/* Transceiver control and diagnostic registers */
+		cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00A2);
+		cdns_phy_reg_write(mhdp, TX_DIAG_BGREF_PREDRV_DELAY    | (k << 9), 0x0097);
+		/* Transmitter receiver detect registers */
+		cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C);
+		cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0036);
+	}
+}
+
+static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp)
+{
+	u32 num_lanes = 4;
+	u32 link_rate = mhdp->dp.rate;
+	u16 val;
+	int index, i, k;
+
+	/*
+	 * PLL reference clock source select
+	 * for single ended reference clock val |= 0x0030;
+	 * for differential clock  val |= 0x0000;
+	 */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFF8F;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* for differential clock on the refclk_p and refclk_m off chip pins:
+	 * CMN_DIAG_ACYA[8]=1'b1
+	 */
+	cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
+
+	/* DP PLL data rate 0/1 clock divider value */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= 0x00FF;
+	if (link_rate <= RATE_2_7)
+		val |= 0x2400;
+	else
+		val |= 0x1200;
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+
+	/* High speed clock 0/1 div */
+	val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
+	val &= 0xFFCC;
+	if (link_rate <= RATE_2_7)
+		val |= 0x0011;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		val = val & 0xCFFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
+	}
+
+	/* DP PHY PLL 27MHz configuration */
+	index = link_rate_index(link_rate);
+	if (index < 0) {
+		dev_err(mhdp->dev, "wrong link rate index\n");
+		return;
+	}
+	for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
+		cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]);
+
+	/* Transceiver control and diagnostic registers */
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		val = val & 0x8FFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x2000;
+		else
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
+	}
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		/* Power state machine registers */
+		cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)),  0xBEFC);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
+		/* Receiver calibration power state definition register */
+		val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val);
+		val = cdns_phy_reg_read(mhdp, RX_PSC_A0  | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, (RX_PSC_A0  | (k << 9)), val);
+	}
+}
+
+static void dp_phy_power_down(struct cdns_mhdp_device *mhdp)
+{
+	u16 val;
+	int i;
+
+	if (!mhdp->power_up)
+		return;
+
+	/* Place the PHY lanes in the A3 power state. */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x8);
+	/* Wait for Power State A3 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 7))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A3 Ack failed\n");
+		return;
+	}
+
+	/* Disable HDP PLL’s data rate and full rate clocks out of PMA. */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= ~(1 << 2);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL clock gate ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (!(val & (1 << 3)))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n");
+		return;
+	}
+
+	/* Disable HDP PLL’s for high speed clocks */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= ~(1 << 0);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL disable ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (!(val & (1 << 1)))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL disable Ack failed\n");
+		return;
+	}
+}
+
+static int dp_phy_power_up(struct cdns_mhdp_device *mhdp)
+{
+	u32 val, i;
+
+	/* Enable HDP PLL’s for high speed clocks */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val |= (1 << 0);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL ready ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (val & (1 << 1))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL Ack failed\n");
+		return -1;
+	}
+
+	/* Enable HDP PLL’s data rate and full rate clocks out of PMA. */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val |= (1 << 2);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL clock enable ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (val & (1 << 3))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n");
+		return -1;
+	}
+
+	/* Configure PHY in A2 Mode */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
+	/* Wait for Power State A2 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 6))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A2 Ack failed\n");
+		return -1;
+	}
+
+	/* Configure PHY in A0 mode (PHY must be in the A0 power
+	 * state in order to transmit data)
+	 */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101);
+
+	/* Wait for Power State A0 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 4))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A0 Ack failed\n");
+		return -1;
+	}
+
+	mhdp->power_up = true;
+
+	return 0;
+}
+
+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	/* Disable phy clock if PHY in power up state */
+	dp_phy_power_down(mhdp);
+
+	dp_phy_pma_cmn_cfg_27mhz(mhdp);
+
+	dp_phy_pma_cmn_pll0_27mhz(mhdp);
+
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
+
+	/* PHY power up */
+	ret = dp_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	dp_aux_cfg(mhdp);
+
+	return ret;
+}
+
+int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	/* Disable phy clock if PHY in power up state */
+	dp_phy_power_down(mhdp);
+
+	dp_phy_pma_cmn_cfg_24mhz(mhdp);
+
+	dp_phy_pma_cmn_pll0_24mhz(mhdp);
+
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
+
+	/* PHY power up */
+	ret = dp_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	dp_aux_cfg(mhdp);
+
+	return true;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
@@ -0,0 +1,764 @@
+/*
+ * Cadence High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/io.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
+#include <linux/io.h>
+
+#include <drm/bridge/cdns-mhdp.h>
+#include "cdns-mhdp-phy.h"
+
+/* HDMI TX clock control settings */
+struct hdmi_ctrl {
+	u32 pixel_clk_freq_min;
+	u32 pixel_clk_freq_max;
+	u32 feedback_factor;
+	u32 data_range_kbps_min;
+	u32 data_range_kbps_max;
+	u32 cmnda_pll0_ip_div;
+	u32 cmn_ref_clk_dig_div;
+	u32 ref_clk_divider_scaler;
+	u32 pll_fb_div_total;
+	u32 cmnda_pll0_fb_div_low;
+	u32 cmnda_pll0_fb_div_high;
+	u32 pixel_div_total;
+	u32 cmnda_pll0_pxdiv_low;
+	u32 cmnda_pll0_pxdiv_high;
+	u32 vco_freq_min;
+	u32 vco_freq_max;
+	u32 vco_ring_select;
+	u32 cmnda_hs_clk_0_sel;
+	u32 cmnda_hs_clk_1_sel;
+	u32 hsclk_div_at_xcvr;
+	u32 hsclk_div_tx_sub_rate;
+	u32 cmnda_pll0_hs_sym_div_sel;
+	u32 cmnda_pll0_clk_freq_min;
+	u32 cmnda_pll0_clk_freq_max;
+};
+
+/* HDMI TX clock control settings, pixel clock is output */
+static const struct hdmi_ctrl imx8mq_ctrl_table[] = {
+/*Minclk  Maxclk Fdbak  DR_min   DR_max  ip_d  dig  DS    Totl */
+{ 27000,  27000, 1000,  270000,  270000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3,  27000,  27000},
+{ 27000,  27000, 1250,  337500,  337500, 0x03, 0x1, 0x1,  300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3,  33750,  33750},
+{ 27000,  27000, 1500,  405000,  405000, 0x03, 0x1, 0x1,  360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3,  40500,  40500},
+{ 27000,  27000, 2000,  540000,  540000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2,  54000,  54000},
+{ 54000,  54000, 1000,  540000,  540000, 0x03, 0x1, 0x1,  480, 0x17C, 0x060,  80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3,  54000,  54000},
+{ 54000,  54000, 1250,  675000,  675000, 0x04, 0x1, 0x1,  400, 0x13C, 0x050,  50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2,  67500,  67500},
+{ 54000,  54000, 1500,  810000,  810000, 0x04, 0x1, 0x1,  480, 0x17C, 0x060,  60, 0x01C, 0x01C, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2,  81000,  81000},
+{ 54000,  54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000},
+{ 74250,  74250, 1000,  742500,  742500, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3,  74250,  74250},
+{ 74250,  74250, 1250,  928125,  928125, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2,  92812,  92812},
+{ 74250,  74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1,  660, 0x20C, 0x084,  60, 0x01C, 0x01C, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375},
+{ 74250,  74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
+{ 99000,  99000, 1000,  990000,  990000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2,  99000,  99000},
+{ 99000,  99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1,  275, 0x0D8, 0x037,  25, 0x00B, 0x00A, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750},
+{ 99000,  99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  30, 0x00D, 0x00D, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
+{ 99000,  99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000},
+{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500},
+{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625},
+{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  30, 0x00D, 0x00D, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750},
+{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000},
+{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1,  220, 0x0AC, 0x02C,  10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000},
+{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500},
+{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
+{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000},
+{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
+{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
+{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
+{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
+{594000, 594000,  750, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
+{594000, 594000,  625, 3712500, 3712500, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250},
+{594000, 594000,  500, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000},
+};
+
+/* HDMI TX clock control settings, pixel clock is input */
+static const struct hdmi_ctrl imx8qm_ctrl_table[] = {
+/*pclk_l  pclk_h  fd    DRR_L    DRR_H   PLLD */
+{ 25000,  42500, 1000,  250000,  425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 2, 2, 2, 4, 0x03,  25000,  42500},
+{ 42500,  85000, 1000,  425000,  850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02,  42500,  85000},
+{ 85000, 170000, 1000,  850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
+{170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
+{340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
+{ 25000,  34000, 1205,  312500,  425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03,  31250,  42500},
+{ 34000,  68000, 1205,  425000,  850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02,  42500,  85000},
+{ 68000, 136000, 1205,  850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
+{136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
+{272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
+{ 25000,  28000, 1500,  375000,  420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 3000000, 3360000, 0, 2, 2, 2, 4, 0x03,  37500,  42000},
+{ 28000,  56000, 1500,  420000,  840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 1680000, 3360000, 0, 1, 1, 2, 4, 0x02,  42000,  84000},
+{ 56000, 113000, 1500,  840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1680000, 3390000, 0, 1, 1, 2, 2, 0x01,  84000, 169500},
+{113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1695000, 3390000, 0, 1, 1, 2, 1, 0x00, 169500, 339000},
+{226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 0, 0, 0, 3390000, 6000000, 1, 1, 1, 2, 1, 0x00, 339000, 600000},
+{ 25000,  42500, 2000,  500000,  850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 1, 1, 2, 4, 0x02,  50000,  85000},
+{ 42500,  85000, 2000,  850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01,  85000, 170000},
+{ 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
+{170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
+{594000, 594000, 5000, 2970000, 2970000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 5940000, 5940000, 1, 1, 1, 2, 2, 0x01, 297000, 297000},
+{594000, 594000, 6250, 3712500, 3712500, 0x3C, 0x03, 0x06, 375, 0x169, 0x00A, 0, 0, 0, 3712500, 3712500, 1, 1, 1, 2, 1, 0x00, 371250, 371250},
+{594000, 594000, 7500, 4455000, 4455000, 0x3C, 0x03, 0x06, 450, 0x1B4, 0x00A, 0, 0, 0, 4455000, 4455000, 1, 1, 1, 2, 1, 0x00, 445500, 445500},
+};
+
+/* HDMI TX PLL tuning settings */
+struct hdmi_pll_tuning {
+	u32 vco_freq_bin;
+	u32 vco_freq_min;
+	u32 vco_freq_max;
+	u32 volt_to_current_coarse;
+	u32 volt_to_current;
+	u32 ndac_ctrl;
+	u32 pmos_ctrl;
+	u32 ptat_ndac_ctrl;
+	u32 feedback_div_total;
+	u32 charge_pump_gain;
+	u32 coarse_code;
+	u32 v2i_code;
+	u32 vco_cal_code;
+};
+
+/* HDMI TX PLL tuning settings, pixel clock is output */
+static const struct hdmi_pll_tuning imx8mq_pll_table[] = {
+/*    bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain Coa V2I CAL */
+    {  1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 },
+    {  2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 },
+    {  3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 },
+    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 },
+    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230 },
+    {  5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 },
+    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 },
+    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256 },
+    {  7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257 },
+    {  8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
+    {  9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
+    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
+    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272 },
+    { 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
+    { 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
+};
+
+/* HDMI TX PLL tuning settings, pixel clock is input */
+static const struct hdmi_pll_tuning imx8qm_pll_table[] = {
+/*  bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain  pad only */
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x08D, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x08E, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x08E, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x08E, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08F, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x0A7, 0, 0, 0 },
+	{ 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0C5, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x086, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x087, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x087, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x104, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08B, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x08D, 0, 0, 0 },
+	{ 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0A6, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x04E, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04F, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04F, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x085, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x085, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x086, 0, 0, 0 },
+	{ 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x08B, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x047, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04B, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04B, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x04B, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x04D, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x04E, 0, 0, 0 },
+	{ 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x085, 0, 0, 0 },
+	{ 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 375, 0x041, 0, 0, 0 },
+	{ 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x08D, 0, 0, 0 },
+	{ 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A6, 0, 0, 0 },
+	{ 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 450, 0x041, 0, 0, 0 },
+	{ 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x087, 0, 0, 0 },
+	{ 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A4, 0, 0, 0 },
+	{ 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04F, 0, 0, 0 },
+	{ 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x086, 0, 0, 0 },
+	{ 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04D, 0, 0, 0 },
+	{ 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F, 0, 0, 0 }
+};
+
+static void hdmi_arc_config(struct cdns_mhdp_device *mhdp)
+{
+	u16 txpu_calib_code;
+	u16 txpd_calib_code;
+	u16 txpu_adj_calib_code;
+	u16 txpd_adj_calib_code;
+	u16 prev_calib_code;
+	u16 new_calib_code;
+	u16 rdata;
+
+	/* Power ARC */
+	cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 0x0001);
+
+	prev_calib_code = cdns_phy_reg_read(mhdp, TX_DIG_CTRL_REG_2);
+	txpu_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPUCAL_CTRL);
+	txpd_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPDCAL_CTRL);
+	txpu_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPU_ADJ_CTRL);
+	txpd_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPD_ADJ_CTRL);
+
+	new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2)
+		+ txpu_adj_calib_code + txpd_adj_calib_code;
+
+	if (new_calib_code != prev_calib_code) {
+		rdata = cdns_phy_reg_read(mhdp, TX_ANA_CTRL_REG_1);
+		rdata &= 0xDFFF;
+		cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
+		cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, new_calib_code);
+		mdelay(10);
+		rdata |= 0x2000;
+		cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
+		udelay(150);
+	}
+
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2098);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0010);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x4001);
+	mdelay(5);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2198);
+	mdelay(5);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030D);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030F);
+}
+
+static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
+{
+	const u32 num_lanes = 4;
+	u32 k;
+
+	for (k = 0; k < num_lanes; k++) {
+		cdns_phy_reg_write(mhdp, (TX_DIAG_TX_DRV | (k << 9)), 0x7c0);
+		cdns_phy_reg_write(mhdp, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0);
+		cdns_phy_reg_write(mhdp, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), 0x120);
+	}
+}
+
+static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp)
+{
+	u32 feedback_factor;
+
+	switch (mhdp->video_info.color_fmt) {
+	case YCBCR_4_2_2:
+		feedback_factor = 1000;
+		break;
+	case YCBCR_4_2_0:
+		switch (mhdp->video_info.color_depth) {
+		case 8:
+			feedback_factor = 500;
+			break;
+		case 10:
+			feedback_factor = 625;
+			break;
+		case 12:
+			feedback_factor = 750;
+			break;
+		case 16:
+			feedback_factor = 1000;
+			break;
+		default:
+			DRM_ERROR("Invalid ColorDepth\n");
+			return 0;
+		}
+		break;
+	default:
+		/* Assume RGB/YUV444 */
+		switch (mhdp->video_info.color_depth) {
+		case 10:
+			feedback_factor = 1250;
+			break;
+		case 12:
+			feedback_factor = 1500;
+			break;
+		case 16:
+			feedback_factor = 2000;
+			break;
+		default:
+			feedback_factor = 1000;
+		}
+	}
+	return feedback_factor;
+}
+
+static int hdmi_phy_config(struct cdns_mhdp_device *mhdp,
+					const struct hdmi_ctrl *p_ctrl_table,
+					const struct hdmi_pll_tuning *p_pll_table,
+					char pclk_in)
+{
+	const u32 num_lanes = 4;
+	u32 val, i, k;
+
+	/* enable PHY isolation mode only for CMN */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000);
+
+	/* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_PLL_CTRL1);
+	val &= 0xFF00;
+	val |= 0x0012;
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val);
+
+	/* assert PHY reset from isolation register */
+	cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0000);
+	/* assert PMA CMN reset */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0000);
+
+	/* register XCVR_DIAG_BIDI_CTRL */
+	for (k = 0; k < num_lanes; k++)
+		cdns_phy_reg_write(mhdp, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00FF);
+
+	/* Describing Task phy_cfg_hdp */
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFFF7;
+	val |= 0x0008;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* PHY Registers */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xCFFF;
+	val |= p_ctrl_table->cmn_ref_clk_dig_div << 12;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= 0x00FF;
+	val |= 0x1200;
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+
+	/* Common control module control and diagnostic registers */
+	val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL);
+	val &= 0x8FFF;
+	val |= p_ctrl_table->ref_clk_divider_scaler << 12;
+	val |= 0x00C0;
+	cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val);
+
+	/* High speed clock used */
+	val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
+	val &= 0xFF00;
+	val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 0;
+	val |= (p_ctrl_table->cmnda_hs_clk_1_sel >> 1) << 4;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		val &= 0xCFFF;
+		val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 12;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
+	}
+
+	/* PLL 0 control state machine registers */
+	val = p_ctrl_table->vco_ring_select << 12;
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_USER_DEF_CTRL, val);
+
+	if (pclk_in == true)
+		val = 0x30A0;
+	else {
+		val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START);
+		val &= 0xFE00;
+		val |= p_pll_table->vco_cal_code;
+	}
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val);
+
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064);
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A);
+
+	/* Common functions control and diagnostics registers */
+	val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8;
+	val |= p_ctrl_table->cmnda_pll0_ip_div;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_INCLK_CTRL, val);
+
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000);
+
+	val = p_ctrl_table->cmnda_pll0_fb_div_high;
+	val |= (1 << 15);
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val);
+
+	val = p_ctrl_table->cmnda_pll0_fb_div_low;
+	val |= (1 << 15);
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val);
+
+	if (pclk_in == false) {
+		val = p_ctrl_table->cmnda_pll0_pxdiv_low;
+		cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVL, val);
+
+		val = p_ctrl_table->cmnda_pll0_pxdiv_high;
+		val |= (1 << 15);
+		cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val);
+	}
+
+	val = p_pll_table->volt_to_current_coarse;
+	val |= (p_pll_table->volt_to_current) << 4;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_V2I_TUNE, val);
+
+	val = p_pll_table->charge_pump_gain;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val);
+
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+
+	val = p_pll_table->pmos_ctrl;
+	val |= (p_pll_table->ndac_ctrl) << 8;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE1, val);
+
+	val = p_pll_table->ptat_ndac_ctrl;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val);
+
+	if (pclk_in == true)
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
+	else
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
+	cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016);
+
+	/* Transceiver control and diagnostic registers */
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		val &= 0xBFFF;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
+	}
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9)));
+		val &= 0xFF3F;
+		val |= (p_ctrl_table->hsclk_div_tx_sub_rate >> 1) << 6;
+		cdns_phy_reg_write(mhdp, (TX_DIAG_TX_CTRL | (k << 9)), val);
+	}
+
+	/*
+	 * for single ended reference clock val |= 0x0030;
+	 * for differential clock  val |= 0x0000;
+	 */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFF8F;
+	if (pclk_in == true)
+		val |= 0x0030;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* for differential clock on the refclk_p and
+	 * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */
+	cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
+
+	/* Deassert PHY reset */
+	cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0001);
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0003);
+
+	/* Power state machine registers */
+	for (k = 0; k < num_lanes; k++)
+		cdns_phy_reg_write(mhdp, XCVR_PSM_RCTRL | (k << 9), 0xFEFC);
+
+	/* Assert cmn_macro_pwr_en */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013);
+
+	/* wait for cmn_macro_pwr_en_ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_CMN_CTRL);
+		if (val & (1 << 5))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		DRM_ERROR("PMA ouput macro power up failed\n");
+		return false;
+	}
+
+	/* wait for cmn_ready */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+		if (val & (1 << 0))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		DRM_ERROR("PMA output ready failed\n");
+		return false;
+	}
+
+	for (k = 0; k < num_lanes; k++) {
+		cdns_phy_reg_write(mhdp, TX_PSC_A0 | (k << 9), 0x6791);
+		cdns_phy_reg_write(mhdp, TX_PSC_A1 | (k << 9), 0x6790);
+		cdns_phy_reg_write(mhdp, TX_PSC_A2 | (k << 9), 0x0090);
+		cdns_phy_reg_write(mhdp, TX_PSC_A3 | (k << 9), 0x0090);
+
+		val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val);
+
+		val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val);
+	}
+	return true;
+}
+
+static int hdmi_phy_cfg_t28hpc(struct cdns_mhdp_device *mhdp,
+				struct drm_display_mode *mode)
+{
+	const struct hdmi_ctrl *p_ctrl_table;
+	const struct hdmi_pll_tuning *p_pll_table;
+	const u32 refclk_freq_khz = 27000;
+	const u8 pclk_in = false;
+	u32 pixel_freq = mode->clock;
+	u32 vco_freq, char_freq;
+	u32 div_total, feedback_factor;
+	u32 i, ret;
+
+	feedback_factor = hdmi_feedback_factor(mhdp);
+
+	char_freq = pixel_freq * feedback_factor / 1000;
+
+	DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
+	     pixel_freq, char_freq, mhdp->video_info.color_depth);
+
+	/* Get right row from the ctrl_table table.
+	 * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
+	 * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+	for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) {
+		if (feedback_factor == imx8mq_ctrl_table[i].feedback_factor &&
+				pixel_freq == imx8mq_ctrl_table[i].pixel_clk_freq_min) {
+			p_ctrl_table = &imx8mq_ctrl_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8mq_ctrl_table)) {
+		DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
+		     pixel_freq, mhdp->video_info.color_depth);
+		return 0;
+	}
+
+	div_total = p_ctrl_table->pll_fb_div_total;
+	vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div;
+
+	/* Get right row from the imx8mq_pll_table table.
+	 * Check if vco_freq_khz and feedback_div_total
+	 * column matching with imx8mq_pll_table. */
+	for (i = 0; i < ARRAY_SIZE(imx8mq_pll_table); i++) {
+		if (vco_freq == imx8mq_pll_table[i].vco_freq_min &&
+				div_total == imx8mq_pll_table[i].feedback_div_total) {
+			p_pll_table = &imx8mq_pll_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8mq_pll_table)) {
+		DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
+		return 0;
+	}
+	DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
+
+	ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
+	if (ret == false)
+		return 0;
+
+	return char_freq;
+}
+
+static int hdmi_phy_cfg_ss28fdsoi(struct cdns_mhdp_device *mhdp,
+				struct drm_display_mode *mode)
+{
+	const struct hdmi_ctrl *p_ctrl_table;
+	const struct hdmi_pll_tuning *p_pll_table;
+	const u8 pclk_in = true;
+	u32 pixel_freq = mode->clock;
+	u32 vco_freq, char_freq;
+	u32 div_total, feedback_factor;
+	u32 ret, i;
+
+	feedback_factor = hdmi_feedback_factor(mhdp);
+
+	char_freq = pixel_freq * feedback_factor / 1000;
+
+	DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
+	     pixel_freq, char_freq, mhdp->video_info.color_depth);
+
+	/* Get right row from the ctrl_table table.
+	 * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
+	 * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+	for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++) {
+		if (feedback_factor == imx8qm_ctrl_table[i].feedback_factor &&
+				pixel_freq >= imx8qm_ctrl_table[i].pixel_clk_freq_min &&
+				pixel_freq <= imx8qm_ctrl_table[i].pixel_clk_freq_max) {
+			p_ctrl_table = &imx8qm_ctrl_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8qm_ctrl_table)) {
+		DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
+		     pixel_freq, mhdp->video_info.color_depth);
+		return 0;
+	}
+
+	div_total = p_ctrl_table->pll_fb_div_total;
+	vco_freq = pixel_freq * div_total / p_ctrl_table->cmnda_pll0_ip_div;
+
+	/* Get right row from the imx8mq_pll_table table.
+	 * Check if vco_freq_khz and feedback_div_total
+	 * column matching with imx8mq_pll_table. */
+	for (i = 0; i < ARRAY_SIZE(imx8qm_pll_table); i++) {
+		if (vco_freq >= imx8qm_pll_table[i].vco_freq_min &&
+				vco_freq < imx8qm_pll_table[i].vco_freq_max &&
+				div_total == imx8qm_pll_table[i].feedback_div_total) {
+			p_pll_table = &imx8qm_pll_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8qm_pll_table)) {
+		DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
+		return 0;
+	}
+	DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
+
+	ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
+	if (ret == false)
+		return 0;
+
+	return char_freq;
+}
+
+static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp)
+{
+	u32 val, i;
+
+	/* set Power State to A2 */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
+
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
+
+	/* Wait for Power State A2 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 6))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A2 Ack failed\n");
+		return -1;
+	}
+
+	/* Power up ARC */
+	hdmi_arc_config(mhdp);
+
+	/* Configure PHY in A0 mode (PHY must be in the A0 power
+	 * state in order to transmit data)
+	 */
+	//cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); //imx8mq
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001);
+
+	/* Wait for Power State A0 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 4))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A0 Ack failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	u32 rate = mhdp->valid_mode->clock;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++)
+			if(rate == imx8mq_ctrl_table[i].pixel_clk_freq_min)
+				return true;
+	return false;
+}
+
+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	int ret;
+
+	/* Check HDMI FW alive before HDMI PHY init */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* Configure PHY */
+	mhdp->hdmi.char_rate = hdmi_phy_cfg_t28hpc(mhdp, mode);
+	if (mhdp->hdmi.char_rate == 0) {
+		DRM_ERROR("failed to set phy pclock\n");
+		return -EINVAL;
+	}
+
+	ret = hdmi_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	hdmi_phy_set_vswing(mhdp);
+
+	return true;
+}
+
+bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	u32 rate = mhdp->valid_mode->clock;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++)
+			if(rate >= imx8qm_ctrl_table[i].pixel_clk_freq_min &&
+				rate <= imx8qm_ctrl_table[i].pixel_clk_freq_max)
+				return true;
+	return false;
+}
+
+int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	int ret;
+
+	/* Check HDMI FW alive before HDMI PHY init */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* Configure PHY */
+	mhdp->hdmi.char_rate = hdmi_phy_cfg_ss28fdsoi(mhdp, mode);
+	if (mhdp->hdmi.char_rate == 0) {
+		DRM_ERROR("failed to set phy pclock\n");
+		return -EINVAL;
+	}
+
+	ret = hdmi_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	hdmi_phy_set_vswing(mhdp);
+
+	return true;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h
@@ -0,0 +1,76 @@
+/*
+ * Cadence High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef CDNS_MHDP_IMX_H_
+#define CDNS_MHDP_IMX_H_
+
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_encoder_slave.h>
+
+
+struct imx_mhdp_device;
+
+struct imx_hdp_clks {
+	struct clk *av_pll;
+	struct clk *dig_pll;
+	struct clk *clk_ipg;
+	struct clk *clk_core;
+	struct clk *clk_pxl;
+	struct clk *clk_pxl_mux;
+	struct clk *clk_pxl_link;
+
+	struct clk *lpcg_hdp;
+	struct clk *lpcg_msi;
+	struct clk *lpcg_pxl;
+	struct clk *lpcg_vif;
+	struct clk *lpcg_lis;
+	struct clk *lpcg_apb;
+	struct clk *lpcg_apb_csr;
+	struct clk *lpcg_apb_ctrl;
+
+	struct clk *lpcg_i2s;
+	struct clk *clk_i2s_bypass;
+};
+
+struct imx_mhdp_device {
+	struct cdns_mhdp_device mhdp;
+	struct drm_encoder encoder;
+
+	struct mutex audio_mutex;
+	spinlock_t audio_lock;
+	bool connected;
+	bool active;
+	bool suspended;
+	struct imx_hdp_clks clks;
+	const struct firmware *fw;
+	const char *firmware_name;
+
+	int bus_type;
+
+	struct device		*pd_mhdp_dev;
+	struct device		*pd_pll0_dev;
+	struct device		*pd_pll1_dev;
+	struct device_link	*pd_mhdp_link;
+	struct device_link	*pd_pll0_link;
+	struct device_link	*pd_pll1_link;
+};
+
+void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_power_off_imx8qm(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp);
+#endif /* CDNS_MHDP_IMX_H_ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license version 2 as
+ * published by the free software foundation.
+ */
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/firmware.h>
+#include <linux/pm_domain.h>
+#include <linux/clk.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+
+#include "cdns-mhdp-imx.h"
+
+#define FW_IRAM_OFFSET		0x2000
+#define FW_IRAM_SIZE		0x10000
+#define FW_DRAM_SIZE		0x8000
+
+#define PLL_800MHZ (800000000)
+
+#define HDP_DUAL_MODE_MIN_PCLK_RATE	300000	/* KHz */
+#define HDP_SINGLE_MODE_MAX_WIDTH	2560
+
+#define CSR_PIXEL_LINK_MUX_CTL		0x00
+#define CSR_PIXEL_LINK_MUX_VCP_OFFSET		5
+#define CSR_PIXEL_LINK_MUX_HCP_OFFSET		4
+
+static bool imx8qm_video_dual_mode(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
+		mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
+}
+
+static void imx8qm_pixel_link_mux(struct imx_mhdp_device *imx_mhdp)
+{
+	struct drm_display_mode *mode = &imx_mhdp->mhdp.mode;
+	bool dual_mode;
+	u32 val;
+
+	dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+
+	val = 0x4;	/* RGB */
+	if (dual_mode)
+		val |= 0x2;	/* pixel link 0 and 1 are active */
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		val |= 1 << CSR_PIXEL_LINK_MUX_VCP_OFFSET;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		val |= 1 << CSR_PIXEL_LINK_MUX_HCP_OFFSET;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		val |= 0x2;
+
+	writel(val, imx_mhdp->mhdp.regs_sec);
+}
+
+static void imx8qm_pixel_link_valid(u32 dual_mode)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 1);
+	if (dual_mode)
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 1);
+}
+
+static void imx8qm_pixel_link_invalid(u32 dual_mode)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 0);
+	if (dual_mode)
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 0);
+}
+
+static void imx8qm_pixel_link_sync_enable(u32 dual_mode)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	if (dual_mode)
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 3);
+	else
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 1);
+}
+
+static void imx8qm_pixel_link_sync_disable(u32 dual_mode)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	if (dual_mode)
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 0);
+	else
+		imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0);
+}
+
+static void imx8qm_phy_reset(u8 reset)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	/* set the pixel link mode and pixel type */
+	imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_PHY_RESET, reset);
+}
+
+static void imx8qm_clk_mux(u8 is_dp)
+{
+	struct imx_sc_ipc *handle;
+
+	imx_scu_get_handle(&handle);
+
+	if (is_dp)
+		/* Enable the 24MHz for HDP PHY */
+		imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 1);
+	else
+		imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0);
+}
+
+int imx8qm_clocks_init(struct imx_mhdp_device *imx_mhdp)
+{
+	struct device *dev = imx_mhdp->mhdp.dev;
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	clks->dig_pll = devm_clk_get(dev, "dig_pll");
+	if (IS_ERR(clks->dig_pll)) {
+		dev_warn(dev, "failed to get dig pll clk\n");
+		return PTR_ERR(clks->dig_pll);
+	}
+
+	clks->av_pll = devm_clk_get(dev, "av_pll");
+	if (IS_ERR(clks->av_pll)) {
+		dev_warn(dev, "failed to get av pll clk\n");
+		return PTR_ERR(clks->av_pll);
+	}
+
+	clks->clk_ipg = devm_clk_get(dev, "clk_ipg");
+	if (IS_ERR(clks->clk_ipg)) {
+		dev_warn(dev, "failed to get dp ipg clk\n");
+		return PTR_ERR(clks->clk_ipg);
+	}
+
+	clks->clk_core = devm_clk_get(dev, "clk_core");
+	if (IS_ERR(clks->clk_core)) {
+		dev_warn(dev, "failed to get hdp core clk\n");
+		return PTR_ERR(clks->clk_core);
+	}
+
+	clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
+	if (IS_ERR(clks->clk_pxl)) {
+		dev_warn(dev, "failed to get pxl clk\n");
+		return PTR_ERR(clks->clk_pxl);
+	}
+
+	clks->clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux");
+	if (IS_ERR(clks->clk_pxl_mux)) {
+		dev_warn(dev, "failed to get pxl mux clk\n");
+		return PTR_ERR(clks->clk_pxl_mux);
+	}
+
+	clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link");
+	if (IS_ERR(clks->clk_pxl_link)) {
+		dev_warn(dev, "failed to get pxl link clk\n");
+		return PTR_ERR(clks->clk_pxl_link);
+	}
+
+	clks->lpcg_hdp = devm_clk_get(dev, "lpcg_hdp");
+	if (IS_ERR(clks->lpcg_hdp)) {
+		dev_warn(dev, "failed to get lpcg hdp clk\n");
+		return PTR_ERR(clks->lpcg_hdp);
+	}
+
+	clks->lpcg_msi = devm_clk_get(dev, "lpcg_msi");
+	if (IS_ERR(clks->lpcg_msi)) {
+		dev_warn(dev, "failed to get lpcg msi clk\n");
+		return PTR_ERR(clks->lpcg_msi);
+	}
+
+	clks->lpcg_pxl = devm_clk_get(dev, "lpcg_pxl");
+	if (IS_ERR(clks->lpcg_pxl)) {
+		dev_warn(dev, "failed to get lpcg pxl clk\n");
+		return PTR_ERR(clks->lpcg_pxl);
+	}
+
+	clks->lpcg_vif = devm_clk_get(dev, "lpcg_vif");
+	if (IS_ERR(clks->lpcg_vif)) {
+		dev_warn(dev, "failed to get lpcg vif clk\n");
+		return PTR_ERR(clks->lpcg_vif);
+	}
+
+	clks->lpcg_lis = devm_clk_get(dev, "lpcg_lis");
+	if (IS_ERR(clks->lpcg_lis)) {
+		dev_warn(dev, "failed to get lpcg lis clk\n");
+		return PTR_ERR(clks->lpcg_lis);
+	}
+
+	clks->lpcg_apb = devm_clk_get(dev, "lpcg_apb");
+	if (IS_ERR(clks->lpcg_apb)) {
+		dev_warn(dev, "failed to get lpcg apb clk\n");
+		return PTR_ERR(clks->lpcg_apb);
+	}
+
+	clks->lpcg_apb_csr = devm_clk_get(dev, "lpcg_apb_csr");
+	if (IS_ERR(clks->lpcg_apb_csr)) {
+		dev_warn(dev, "failed to get apb csr clk\n");
+		return PTR_ERR(clks->lpcg_apb_csr);
+	}
+
+	clks->lpcg_apb_ctrl = devm_clk_get(dev, "lpcg_apb_ctrl");
+	if (IS_ERR(clks->lpcg_apb_ctrl)) {
+		dev_warn(dev, "failed to get lpcg apb ctrl clk\n");
+		return PTR_ERR(clks->lpcg_apb_ctrl);
+	}
+
+	clks->clk_i2s_bypass = devm_clk_get(dev, "clk_i2s_bypass");
+	if (IS_ERR(clks->clk_i2s_bypass)) {
+		dev_err(dev, "failed to get i2s bypass clk\n");
+		return PTR_ERR(clks->clk_i2s_bypass);
+	}
+
+	clks->lpcg_i2s = devm_clk_get(dev, "lpcg_i2s");
+	if (IS_ERR(clks->lpcg_i2s)) {
+		dev_err(dev, "failed to get lpcg i2s clk\n");
+		return PTR_ERR(clks->lpcg_i2s);
+	}
+	return true;
+}
+
+static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+	struct device *dev = imx_mhdp->mhdp.dev;
+	int ret;
+
+	ret = clk_prepare_enable(clks->av_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre av pll  error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clks->clk_pxl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->clk_pxl_mux);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clks->clk_pxl_link);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl link error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_vif);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk vif error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_pxl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre lpcg pxl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_hdp);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre lpcg hdp error\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	clk_disable_unprepare(clks->lpcg_pxl);
+	clk_disable_unprepare(clks->lpcg_hdp);
+	clk_disable_unprepare(clks->lpcg_vif);
+	clk_disable_unprepare(clks->clk_pxl);
+	clk_disable_unprepare(clks->clk_pxl_link);
+	clk_disable_unprepare(clks->clk_pxl_mux);
+	clk_disable_unprepare(clks->av_pll);
+}
+
+static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, u32 pclock)
+{
+	bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	/* pixel clock for HDMI */
+	clk_set_rate(clks->av_pll, pclock);
+
+	if (dual_mode == true) {
+		clk_set_rate(clks->clk_pxl, pclock/2);
+		clk_set_rate(clks->clk_pxl_link, pclock/2);
+	} else {
+		clk_set_rate(clks->clk_pxl_link, pclock);
+		clk_set_rate(clks->clk_pxl, pclock);
+	}
+	clk_set_rate(clks->clk_pxl_mux, pclock);
+}
+
+static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *imx_mhdp)
+{
+	int ret;
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+	struct device *dev = imx_mhdp->mhdp.dev;
+
+	ret = clk_prepare_enable(clks->dig_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre dig pll error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clks->clk_ipg);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk_ipg error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clks->clk_core);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk core error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clks->lpcg_apb);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_lis);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk lis error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_msi);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk msierror\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_apb_csr);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb csr error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_apb_ctrl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_i2s);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk i2s error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->clk_i2s_bypass);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static int imx8qm_ipg_clk_disable(struct imx_mhdp_device *imx_mhdp)
+{
+	int ret;
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+	struct device *dev = imx_mhdp->mhdp.dev;
+
+	ret = clk_prepare_enable(clks->clk_i2s_bypass);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_i2s);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk i2s error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_apb_ctrl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_apb_csr);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb csr error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_msi);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk msierror\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_lis);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk lis error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->lpcg_apb);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->clk_core);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk core error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->clk_ipg);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk_ipg error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(clks->dig_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre dig pll error\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *imx_mhdp)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	/* ipg/core clock */
+	clk_set_rate(clks->dig_pll,  PLL_800MHZ);
+	clk_set_rate(clks->clk_core, PLL_800MHZ/4);
+	clk_set_rate(clks->clk_ipg,  PLL_800MHZ/8);
+}
+
+static void imx8qm_detach_pm_domains(struct imx_mhdp_device *imx_mhdp)
+{
+	if (imx_mhdp->pd_pll1_link && !IS_ERR(imx_mhdp->pd_pll1_link))
+		device_link_del(imx_mhdp->pd_pll1_link);
+	if (imx_mhdp->pd_pll1_dev && !IS_ERR(imx_mhdp->pd_pll1_dev))
+		dev_pm_domain_detach(imx_mhdp->pd_pll1_dev, true);
+
+	if (imx_mhdp->pd_pll0_link && !IS_ERR(imx_mhdp->pd_pll0_link))
+		device_link_del(imx_mhdp->pd_pll0_link);
+	if (imx_mhdp->pd_pll0_dev && !IS_ERR(imx_mhdp->pd_pll0_dev))
+		dev_pm_domain_detach(imx_mhdp->pd_pll0_dev, true);
+
+	if (imx_mhdp->pd_mhdp_link && !IS_ERR(imx_mhdp->pd_mhdp_link))
+		device_link_del(imx_mhdp->pd_mhdp_link);
+	if (imx_mhdp->pd_mhdp_dev && !IS_ERR(imx_mhdp->pd_mhdp_dev))
+		dev_pm_domain_detach(imx_mhdp->pd_mhdp_dev, true);
+
+	imx_mhdp->pd_mhdp_dev = NULL;
+	imx_mhdp->pd_mhdp_link = NULL;
+	imx_mhdp->pd_pll0_dev = NULL;
+	imx_mhdp->pd_pll0_link = NULL;
+	imx_mhdp->pd_pll1_dev = NULL;
+	imx_mhdp->pd_pll1_link = NULL;
+}
+
+static int imx8qm_attach_pm_domains(struct imx_mhdp_device *imx_mhdp)
+{
+	struct device *dev = imx_mhdp->mhdp.dev;
+	u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
+	int ret = 0;
+
+	imx_mhdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi");
+	if (IS_ERR(imx_mhdp->pd_mhdp_dev)) {
+		ret = PTR_ERR(imx_mhdp->pd_mhdp_dev);
+		dev_err(dev, "Failed to attach dc pd dev: %d\n", ret);
+		goto fail;
+	}
+	imx_mhdp->pd_mhdp_link = device_link_add(dev, imx_mhdp->pd_mhdp_dev, flags);
+	if (IS_ERR(imx_mhdp->pd_mhdp_link)) {
+		ret = PTR_ERR(imx_mhdp->pd_mhdp_link);
+		dev_err(dev, "Failed to add device link to dc pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	imx_mhdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
+	if (IS_ERR(imx_mhdp->pd_pll0_dev)) {
+		ret = PTR_ERR(imx_mhdp->pd_pll0_dev);
+		dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+		goto fail;
+	}
+	imx_mhdp->pd_pll0_link = device_link_add(dev, imx_mhdp->pd_pll0_dev, flags);
+	if (IS_ERR(imx_mhdp->pd_pll0_link)) {
+		ret = PTR_ERR(imx_mhdp->pd_pll0_link);
+		dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	imx_mhdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
+	if (IS_ERR(imx_mhdp->pd_pll1_dev)) {
+		ret = PTR_ERR(imx_mhdp->pd_pll1_dev);
+		dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+		goto fail;
+	}
+	imx_mhdp->pd_pll1_link = device_link_add(dev, imx_mhdp->pd_pll1_dev, flags);
+	if (IS_ERR(imx_mhdp->pd_pll1_link)) {
+		ret = PTR_ERR(imx_mhdp->pd_pll1_link);
+		dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+fail:
+	imx8qm_detach_pm_domains(imx_mhdp);
+	return ret;
+}
+
+int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+
+	/* Power on PM Domains */
+
+	imx8qm_attach_pm_domains(imx_mhdp);
+
+	/* clock init and  rate set */
+	imx8qm_clocks_init(imx_mhdp);
+
+	imx8qm_ipg_clk_set_rate(imx_mhdp);
+
+	/* Init pixel clock with 148.5MHz before FW init */
+	imx8qm_pixel_clk_set_rate(imx_mhdp, 148500000);
+
+	imx8qm_ipg_clk_enable(imx_mhdp);
+
+	imx8qm_clk_mux(imx_mhdp->mhdp.plat_data->is_dp);
+
+	imx8qm_pixel_clk_enable(imx_mhdp);
+
+	imx8qm_phy_reset(1);
+
+	return 0;
+}
+
+int cdns_mhdp_power_off_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+		container_of(mhdp, struct imx_mhdp_device, mhdp);
+
+	imx8qm_phy_reset(0);
+	imx8qm_pixel_clk_disable(imx_mhdp);
+	imx8qm_ipg_clk_disable(imx_mhdp);
+
+	/* Power off PM Domains */
+	imx8qm_detach_pm_domains(imx_mhdp);
+
+	return 0;
+}
+
+void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+	bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+
+	imx8qm_pixel_link_sync_disable(dual_mode);
+	imx8qm_pixel_link_invalid(dual_mode);
+}
+
+void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+	bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp);
+
+	imx8qm_pixel_link_valid(dual_mode);
+	imx8qm_pixel_link_sync_enable(dual_mode);
+}
+
+void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+
+	/* set pixel clock before video mode setup */
+	imx8qm_pixel_clk_disable(imx_mhdp);
+
+	imx8qm_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000);
+
+	imx8qm_pixel_clk_enable(imx_mhdp);
+
+	/* Config pixel link mux */
+	imx8qm_pixel_link_mux(imx_mhdp);
+}
+
+int cdns_mhdp_firmware_write_section(struct imx_mhdp_device *imx_mhdp,
+					const u8 *data, int size, int addr)
+{
+	int i;
+
+	for (i = 0; i < size; i += 4) {
+		u32 val = (unsigned int)data[i] << 0 |
+					(unsigned int)data[i + 1] << 8 |
+					(unsigned int)data[i + 2] << 16 |
+					(unsigned int)data[i + 3] << 24;
+		cdns_mhdp_bus_write(val, &imx_mhdp->mhdp, addr + i);
+	}
+
+	return 0;
+}
+
+static void cdns_mhdp_firmware_load_cont(const struct firmware *fw, void *context)
+{
+	struct imx_mhdp_device *imx_mhdp = context;
+
+	imx_mhdp->fw = fw;
+}
+
+static int cdns_mhdp_firmware_load(struct imx_mhdp_device *imx_mhdp)
+{
+	const u8 *iram;
+	const u8 *dram;
+	u32 rate;
+	int ret;
+
+	/* configure HDMI/DP core clock */
+	rate = clk_get_rate(imx_mhdp->clks.clk_core);
+	if (imx_mhdp->mhdp.is_ls1028a)
+		rate = rate / 4;
+
+	cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
+
+	/* skip fw loading if none is specified */
+	if (!imx_mhdp->firmware_name)
+		goto out;
+
+	if (!imx_mhdp->fw) {
+		ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+						imx_mhdp->firmware_name,
+						imx_mhdp->mhdp.dev, GFP_KERNEL,
+						imx_mhdp,
+						cdns_mhdp_firmware_load_cont);
+		if (ret < 0) {
+			DRM_ERROR("failed to load firmware\n");
+			return -ENOENT;
+		}
+	} else {
+		iram = imx_mhdp->fw->data + FW_IRAM_OFFSET;
+		dram = iram + FW_IRAM_SIZE;
+
+		cdns_mhdp_firmware_write_section(imx_mhdp, iram, FW_IRAM_SIZE, ADDR_IMEM);
+		cdns_mhdp_firmware_write_section(imx_mhdp, dram, FW_DRAM_SIZE, ADDR_DMEM);
+	}
+
+out:
+	/* un-reset ucpu */
+	cdns_mhdp_bus_write(0, &imx_mhdp->mhdp, APB_CTRL);
+	DRM_INFO("Started firmware!\n");
+
+	return 0;
+}
+
+int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+	int ret;
+
+	/* load firmware */
+	ret = cdns_mhdp_firmware_load(imx_mhdp);
+	if (ret)
+		return ret;
+
+	ret = cdns_mhdp_check_alive(&imx_mhdp->mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* turn on IP activity */
+	cdns_mhdp_set_firmware_active(&imx_mhdp->mhdp, 1);
+
+	DRM_INFO("HDP FW Version - ver %d verlib %d\n",
+			cdns_mhdp_bus_read(mhdp, VER_L) + (cdns_mhdp_bus_read(mhdp, VER_H) << 8),
+			cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) + (cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) << 8));
+
+	return 0;
+}
+
+int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+
+	imx8qm_pixel_clk_disable(imx_mhdp);
+
+	return 0;
+}
+
+int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp =
+				container_of(mhdp, struct imx_mhdp_device, mhdp);
+
+	imx8qm_pixel_clk_enable(imx_mhdp);
+
+	return cdns_mhdp_firmware_init_imx8qm(mhdp);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license version 2 as
+ * published by the free software foundation.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "cdns-mhdp-imx.h"
+#include "cdns-mhdp-phy.h"
+#include "../imx-drm.h"
+
+static void cdns_mhdp_imx_encoder_disable(struct drm_encoder *encoder)
+{
+	struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
+
+	cdns_mhdp_plat_call(mhdp, plat_init);
+}
+
+static void cdns_mhdp_imx_encoder_enable(struct drm_encoder *encoder)
+{
+	struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
+
+	cdns_mhdp_plat_call(mhdp, plat_deinit);
+}
+
+static int cdns_mhdp_imx_encoder_atomic_check(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct cdns_mhdp_device *mhdp = encoder->bridge->driver_private;
+
+	if (mhdp->plat_data->video_format != 0)
+		imx_crtc_state->bus_format = mhdp->plat_data->video_format;
+
+	/* Force mode set to recovery weston  hdmi2.0 and DP dispaly */
+	if (mhdp->force_mode_set && conn_state->state->allow_modeset)
+		crtc_state->mode_changed = true;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs cdns_mhdp_imx_encoder_helper_funcs = {
+	.enable     = cdns_mhdp_imx_encoder_enable,
+	.disable    = cdns_mhdp_imx_encoder_disable,
+	.atomic_check = cdns_mhdp_imx_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static struct cdns_plat_data imx8mq_hdmi_drv_data = {
+	.plat_name = "imx8mq-hdmi",
+	.bind	= cdns_hdmi_bind,
+	.unbind	= cdns_hdmi_unbind,
+	.phy_set = cdns_hdmi_phy_set_imx8mq,
+	.phy_video_valid = cdns_hdmi_phy_video_valid_imx8mq,
+	.bus_type = BUS_TYPE_NORMAL_APB,
+};
+
+static struct cdns_plat_data imx8mq_dp_drv_data = {
+	.plat_name = "imx8mq-dp",
+	.bind	= cdns_dp_bind,
+	.unbind	= cdns_dp_unbind,
+	.phy_set = cdns_dp_phy_set_imx8mq,
+	.bus_type = BUS_TYPE_NORMAL_APB,
+};
+
+static struct cdns_plat_data imx8qm_hdmi_drv_data = {
+	.plat_name = "imx8qm-hdmi",
+	.bind	= cdns_hdmi_bind,
+	.unbind	= cdns_hdmi_unbind,
+	.phy_set = cdns_hdmi_phy_set_imx8qm,
+	.phy_video_valid = cdns_hdmi_phy_video_valid_imx8qm,
+	.power_on = cdns_mhdp_power_on_imx8qm,
+	.power_off = cdns_mhdp_power_off_imx8qm,
+	.firmware_init = cdns_mhdp_firmware_init_imx8qm,
+	.resume = cdns_mhdp_resume_imx8qm,
+	.suspend = cdns_mhdp_suspend_imx8qm,
+	.pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+	.plat_init = cdns_mhdp_plat_init_imx8qm,
+	.plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
+	.bus_type = BUS_TYPE_LOW4K_APB,
+	.video_format =  MEDIA_BUS_FMT_RGB101010_1X30,
+};
+
+static struct cdns_plat_data imx8qm_dp_drv_data = {
+	.plat_name = "imx8qm-dp",
+	.bind	= cdns_dp_bind,
+	.unbind	= cdns_dp_unbind,
+	.phy_set = cdns_dp_phy_set_imx8qm,
+	.power_on = cdns_mhdp_power_on_imx8qm,
+	.power_off = cdns_mhdp_power_off_imx8qm,
+	.firmware_init = cdns_mhdp_firmware_init_imx8qm,
+	.resume = cdns_mhdp_resume_imx8qm,
+	.suspend = cdns_mhdp_suspend_imx8qm,
+	.pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
+	.plat_init = cdns_mhdp_plat_init_imx8qm,
+	.plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
+	.bus_type = BUS_TYPE_LOW4K_APB,
+	.video_format =  MEDIA_BUS_FMT_RGB101010_1X30,
+	.is_dp = true,
+};
+
+static struct cdns_plat_data ls1028a_dp_drv_data = {
+	.bind = cdns_dp_bind,
+	.unbind = cdns_dp_unbind,
+	.phy_set = cdns_dp_phy_set_imx8mq,
+	.power_on = cdns_mhdp_power_on_ls1028a,
+	.firmware_init = cdns_mhdp_firmware_init_imx8qm,
+	.pclk_rate = cdns_mhdp_pclk_rate_ls1028a,
+	.bus_type = BUS_TYPE_NORMAL_APB,
+};
+
+static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
+	{ .compatible = "cdn,imx8mq-hdmi",
+	  .data = &imx8mq_hdmi_drv_data
+	},
+	{ .compatible = "cdn,imx8mq-dp",
+	  .data = &imx8mq_dp_drv_data
+	},
+	{ .compatible = "cdn,imx8qm-hdmi",
+	  .data = &imx8qm_hdmi_drv_data
+	},
+	{ .compatible = "cdn,imx8qm-dp",
+	  .data = &imx8qm_dp_drv_data
+	},
+	{ .compatible = "cdn,ls1028a-dp",
+	  .data = &ls1028a_dp_drv_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids);
+
+static int cdns_mhdp_imx_bind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct cdns_plat_data *plat_data;
+	const struct of_device_id *match;
+	struct drm_device *drm = data;
+	struct drm_encoder *encoder;
+	struct imx_mhdp_device *imx_mhdp;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	imx_mhdp = devm_kzalloc(&pdev->dev, sizeof(*imx_mhdp), GFP_KERNEL);
+	if (!imx_mhdp)
+		return -ENOMEM;
+
+	match = of_match_node(cdns_mhdp_imx_dt_ids, pdev->dev.of_node);
+	plat_data = match->data;
+	encoder = &imx_mhdp->encoder;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
+					&imx_mhdp->firmware_name);
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	drm_encoder_helper_add(encoder, &cdns_mhdp_imx_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &cdns_mhdp_imx_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+
+
+	imx_mhdp->mhdp.plat_data = plat_data;
+	imx_mhdp->mhdp.dev = dev;
+	imx_mhdp->mhdp.bus_type = plat_data->bus_type;
+	ret = plat_data->bind(pdev, encoder, &imx_mhdp->mhdp);
+	/*
+	 * If cdns_mhdp_bind() fails we'll never call cdns_mhdp_unbind(),
+	 * which would have called the encoder cleanup.  Do it manually.
+	 */
+	if (ret < 0)
+		drm_encoder_cleanup(encoder);
+
+	return ret;
+}
+
+static void cdns_mhdp_imx_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
+
+	imx_mhdp->mhdp.plat_data->unbind(dev);
+}
+
+static const struct component_ops cdns_mhdp_imx_ops = {
+	.bind	= cdns_mhdp_imx_bind,
+	.unbind	= cdns_mhdp_imx_unbind,
+};
+
+static int cdns_mhdp_imx_suspend(struct device *dev)
+{
+	struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
+
+	cdns_mhdp_plat_call(&imx_mhdp->mhdp, suspend);
+
+	return 0;
+}
+
+static int cdns_mhdp_imx_resume(struct device *dev)
+{
+	struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
+
+	cdns_mhdp_plat_call(&imx_mhdp->mhdp, resume);
+
+	return 0;
+}
+
+static int cdns_mhdp_imx_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &cdns_mhdp_imx_ops);
+}
+
+static int cdns_mhdp_imx_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &cdns_mhdp_imx_ops);
+
+	return 0;
+}
+
+static const struct dev_pm_ops cdns_mhdp_imx_pm_ops = {
+        SET_LATE_SYSTEM_SLEEP_PM_OPS(cdns_mhdp_imx_suspend, cdns_mhdp_imx_resume)
+};
+
+static struct platform_driver cdns_mhdp_imx_platform_driver = {
+	.probe  = cdns_mhdp_imx_probe,
+	.remove = cdns_mhdp_imx_remove,
+	.driver = {
+		.name = "cdns-mhdp-imx",
+		.of_match_table = cdns_mhdp_imx_dt_ids,
+		.pm = &cdns_mhdp_imx_pm_ops,
+	},
+};
+
+module_platform_driver(cdns_mhdp_imx_platform_driver);
+
+MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdnhdmi-imx");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ *
+ */
+#include <linux/clk.h>
+#include <drm/drm_vblank.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include "cdns-mhdp-imx.h"
+
+static const struct of_device_id scfg_device_ids[] = {
+	{ .compatible = "fsl,ls1028a-scfg", },
+	{}
+};
+
+static void ls1028a_phy_reset(u8 reset)
+{
+	struct device_node *scfg_node;
+	void __iomem *scfg_base = NULL;
+
+	scfg_node = of_find_matching_node(NULL, scfg_device_ids);
+	if (scfg_node)
+		scfg_base = of_iomap(scfg_node, 0);
+
+	iowrite32(reset, scfg_base + 0x230);
+}
+
+int ls1028a_clocks_init(struct imx_mhdp_device *imx_mhdp)
+{
+	struct device *dev = imx_mhdp->mhdp.dev;
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	clks->clk_core = devm_clk_get(dev, "clk_core");
+	if (IS_ERR(clks->clk_core)) {
+		dev_warn(dev, "failed to get hdp core clk\n");
+		return PTR_ERR(clks->clk_core);
+	}
+
+	clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
+	if (IS_ERR(clks->clk_pxl)) {
+		dev_warn(dev, "failed to get pxl clk\n");
+		return PTR_ERR(clks->clk_pxl);
+	}
+
+	return true;
+}
+
+static int ls1028a_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+	struct device *dev = imx_mhdp->mhdp.dev;
+	int ret;
+
+	ret = clk_prepare_enable(clks->clk_pxl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl error\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void ls1028a_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	clk_disable_unprepare(clks->clk_pxl);
+}
+
+static void ls1028a_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp,
+				       u32 pclock)
+{
+	struct imx_hdp_clks *clks = &imx_mhdp->clks;
+
+	clk_set_rate(clks->clk_pxl, pclock);
+}
+
+int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp = container_of
+				(mhdp, struct imx_mhdp_device, mhdp);
+
+	/* clock init and  rate set */
+	ls1028a_clocks_init(imx_mhdp);
+
+	ls1028a_pixel_clk_enable(imx_mhdp);
+
+	/* Init pixel clock with 148.5MHz before FW init */
+	ls1028a_pixel_clk_set_rate(imx_mhdp, 148500000);
+
+	ls1028a_phy_reset(1);
+
+	return 0;
+}
+
+void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp)
+{
+	struct imx_mhdp_device *imx_mhdp = container_of
+				(mhdp, struct imx_mhdp_device, mhdp);
+
+	/* set pixel clock before video mode setup */
+	ls1028a_pixel_clk_disable(imx_mhdp);
+
+	ls1028a_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000);
+
+	ls1028a_pixel_clk_enable(imx_mhdp);
+}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 NXP Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _CDN_DP_PHY_H
+#define _CDN_DP_PHY_H
+
+#include <drm/bridge/cdns-mhdp.h>
+
+#define CMN_SSM_BIAS_TMR                0x0022
+#define CMN_PLLSM0_PLLEN_TMR            0x0029
+#define CMN_PLLSM0_PLLPRE_TMR           0x002A
+#define CMN_PLLSM0_PLLVREF_TMR          0x002B
+#define CMN_PLLSM0_PLLLOCK_TMR          0x002C
+#define CMN_PLLSM0_USER_DEF_CTRL        0x002F
+#define CMN_PSM_CLK_CTRL                0x0061
+#define CMN_CDIAG_REFCLK_CTRL           0x0062
+#define CMN_PLL0_VCOCAL_START           0x0081
+#define CMN_PLL0_VCOCAL_INIT_TMR        0x0084
+#define CMN_PLL0_VCOCAL_ITER_TMR        0x0085
+#define CMN_PLL0_INTDIV                 0x0094
+#define CMN_PLL0_FRACDIV                0x0095
+#define CMN_PLL0_HIGH_THR               0x0096
+#define CMN_PLL0_DSM_DIAG               0x0097
+#define CMN_PLL0_SS_CTRL1               0x0098
+#define CMN_PLL0_SS_CTRL2               0x0099
+#define CMN_ICAL_INIT_TMR               0x00C4
+#define CMN_ICAL_ITER_TMR               0x00C5
+#define CMN_RXCAL_INIT_TMR              0x00D4
+#define CMN_RXCAL_ITER_TMR              0x00D5
+#define CMN_TXPUCAL_CTRL                0x00E0
+#define CMN_TXPUCAL_INIT_TMR            0x00E4
+#define CMN_TXPUCAL_ITER_TMR            0x00E5
+#define CMN_TXPDCAL_CTRL                0x00F0
+#define CMN_TXPDCAL_INIT_TMR            0x00F4
+#define CMN_TXPDCAL_ITER_TMR            0x00F5
+#define CMN_ICAL_ADJ_INIT_TMR           0x0102
+#define CMN_ICAL_ADJ_ITER_TMR           0x0103
+#define CMN_RX_ADJ_INIT_TMR             0x0106
+#define CMN_RX_ADJ_ITER_TMR             0x0107
+#define CMN_TXPU_ADJ_CTRL               0x0108
+#define CMN_TXPU_ADJ_INIT_TMR           0x010A
+#define CMN_TXPU_ADJ_ITER_TMR           0x010B
+#define CMN_TXPD_ADJ_CTRL               0x010c
+#define CMN_TXPD_ADJ_INIT_TMR           0x010E
+#define CMN_TXPD_ADJ_ITER_TMR           0x010F
+#define CMN_DIAG_PLL0_FBH_OVRD          0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD          0x01C1
+#define CMN_DIAG_PLL0_OVRD              0x01C2
+#define CMN_DIAG_PLL0_TEST_MODE         0x01C4
+#define CMN_DIAG_PLL0_V2I_TUNE          0x01C5
+#define CMN_DIAG_PLL0_CP_TUNE           0x01C6
+#define CMN_DIAG_PLL0_LF_PROG           0x01C7
+#define CMN_DIAG_PLL0_PTATIS_TUNE1      0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2      0x01C9
+#define CMN_DIAG_PLL0_INCLK_CTRL        0x01CA
+#define CMN_DIAG_PLL0_PXL_DIVH          0x01CB
+#define CMN_DIAG_PLL0_PXL_DIVL          0x01CC
+#define CMN_DIAG_HSCLK_SEL              0x01E0
+#define CMN_DIAG_PER_CAL_ADJ            0x01EC
+#define CMN_DIAG_CAL_CTRL               0x01ED
+#define CMN_DIAG_ACYA                   0x01FF
+#define XCVR_PSM_RCTRL                  0x4001
+#define XCVR_PSM_CAL_TMR                0x4002
+#define XCVR_PSM_A0IN_TMR               0x4003
+#define TX_TXCC_CAL_SCLR_MULT_0         0x4047
+#define TX_TXCC_CPOST_MULT_00_0         0x404C
+#define TX_TXCC_MGNFS_MULT_000_0        0x4050
+#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
+#define XCVR_DIAG_HSCLK_SEL             0x40E1
+#define XCVR_DIAG_BIDI_CTRL             0x40E8
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR   0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN       0x40F2
+#define TX_PSC_A0                       0x4100
+#define TX_PSC_A1                       0x4101
+#define TX_PSC_A2                       0x4102
+#define TX_PSC_A3                       0x4103
+#define TX_RCVDET_CTRL                  0x4120
+#define TX_RCVDET_EN_TMR                0x4122
+#define TX_RCVDET_EN_TMR                0x4122
+#define TX_RCVDET_ST_TMR                0x4123
+#define TX_RCVDET_ST_TMR                0x4123
+#define TX_BIST_CTRL                    0x4140
+#define TX_BIST_UDDWR                   0x4141
+#define TX_DIAG_TX_CTRL                 0x41E0
+#define TX_DIAG_TX_DRV                  0x41E1
+#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
+#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
+#define XCVR_PSM_RCTRL_1                0x4201
+#define TX_TXCC_CAL_SCLR_MULT_1         0x4247
+#define TX_TXCC_CPOST_MULT_00_1         0x424C
+#define TX_TXCC_MGNFS_MULT_000_1        0x4250
+#define XCVR_DIAG_PLLDRC_CTRL_1         0x42E0
+#define XCVR_DIAG_HSCLK_SEL_1           0x42E1
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
+#define TX_RCVDET_EN_TMR_1              0x4322
+#define TX_RCVDET_ST_TMR_1              0x4323
+#define TX_DIAG_ACYA_0                  0x41FF
+#define TX_DIAG_ACYA_1                  0x43FF
+#define TX_DIAG_ACYA_2                  0x45FF
+#define TX_DIAG_ACYA_3                  0x47FF
+#define TX_ANA_CTRL_REG_1               0x5020
+#define TX_ANA_CTRL_REG_2               0x5021
+#define TXDA_COEFF_CALC                 0x5022
+#define TX_DIG_CTRL_REG_1               0x5023
+#define TX_DIG_CTRL_REG_2               0x5024
+#define TXDA_CYA_AUXDA_CYA              0x5025
+#define TX_ANA_CTRL_REG_3               0x5026
+#define TX_ANA_CTRL_REG_4               0x5027
+#define TX_ANA_CTRL_REG_5               0x5029
+#define RX_PSC_A0                       0x8000
+#define RX_PSC_CAL                      0x8006
+#define PMA_LANE_CFG                    0xC000
+#define PIPE_CMN_CTRL1                  0xC001
+#define PIPE_CMN_CTRL2                  0xC002
+#define PIPE_COM_LOCK_CFG1              0xC003
+#define PIPE_COM_LOCK_CFG2              0xC004
+#define PIPE_RCV_DET_INH                0xC005
+#define PHY_HDP_MODE_CTRL               0xC008
+#define PHY_HDP_CLK_CTL                 0xC009
+#define STS                             0xC00F
+#define PHY_ISO_CMN_CTRL                0xC010
+#define PHY_ISO_CMN_CTRL                0xC010
+#define PHY_HDP_TX_CTL_L0               0xC408
+#define PHY_DP_TX_CTL                   0xC408
+#define PHY_HDP_TX_CTL_L1               0xC448
+#define PHY_HDP_TX_CTL_L2               0xC488
+#define PHY_HDP_TX_CTL_L3               0xC4C8
+#define PHY_PMA_CMN_CTRL1               0xC800
+#define PMA_CMN_CTRL1                   0xC800
+#define PHY_PMA_ISO_CMN_CTRL            0xC810
+#define PHY_PMA_ISO_PLL_CTRL1           0xC812
+#define PHY_PMA_ISOLATION_CTRL          0xC81F
+#define PHY_ISOLATION_CTRL              0xC81F
+#define PHY_PMA_ISO_XCVR_CTRL           0xCC11
+#define PHY_PMA_ISO_LINK_MODE           0xCC12
+#define PHY_PMA_ISO_PWRST_CTRL          0xCC13
+#define PHY_PMA_ISO_TX_DATA_LO          0xCC14
+#define PHY_PMA_ISO_TX_DATA_HI          0xCC15
+#define PHY_PMA_ISO_RX_DATA_LO          0xCC16
+#define PHY_PMA_ISO_RX_DATA_HI          0xCC17
+
+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
+bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *hdp);
+bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *hdp);
+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *hdp);
+#endif /* _CDNS_MHDP_PHY_H */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/parallel-display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/parallel-display.c
@@ -68,11 +68,13 @@
 		ret = of_get_drm_display_mode(np, &imxpd->mode,
 					      &imxpd->bus_flags,
 					      OF_USE_NATIVE_MODE);
-		if (ret)
+		if (ret) {
+			drm_mode_destroy(connector->dev, mode);
 			return ret;
+		}
 
 		drm_mode_copy(mode, &imxpd->mode);
-		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 		drm_mode_probed_add(connector, mode);
 		num_modes++;
 	}
@@ -135,7 +137,6 @@
 
 static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 	.get_modes = imx_pd_connector_get_modes,
-	.best_encoder = imx_pd_connector_best_encoder,
 };
 
 static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
@@ -204,9 +205,14 @@
 	u32 bus_format = 0;
 	const char *fmt;
 
-	imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
-	if (!imxpd)
-		return -ENOMEM;
+	imxpd = dev_get_drvdata(dev);
+	memset(imxpd, 0, sizeof(*imxpd));
+
+	/* port@1 is the output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
+					  &imxpd->bridge);
+	if (ret && ret != -ENODEV)
+		return ret;
 
 	edidp = of_get_property(np, "edid", &imxpd->edid_len);
 	if (edidp)
@@ -225,19 +231,12 @@
 	}
 	imxpd->bus_format = bus_format;
 
-	/* port@1 is the output port */
-	ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
-	if (ret && ret != -ENODEV)
-		return ret;
-
 	imxpd->dev = dev;
 
 	ret = imx_pd_register(drm, imxpd);
 	if (ret)
 		return ret;
 
-	dev_set_drvdata(dev, imxpd);
-
 	return 0;
 }
 
@@ -259,6 +258,14 @@
 
 static int imx_pd_probe(struct platform_device *pdev)
 {
+	struct imx_parallel_display *imxpd;
+
+	imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+	if (!imxpd)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, imxpd);
+
 	return component_add(&pdev->dev, &imx_pd_ops);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __SEC_DSIM_DPHY_LN14LPP_H__
+#define __SEC_DSIM_DPHY_LN14LPP_H__
+
+#include <drm/bridge/sec_mipi_dsim.h>
+
+/* descending order based on 'bit_clk' value */
+static const struct sec_mipi_dsim_dphy_timing dphy_timing_ln14lpp_v1p2[] = {
+	{ DSIM_DPHY_TIMING(2100, 19, 91, 22, 19, 20, 35, 22, 15, 26), },
+	{ DSIM_DPHY_TIMING(2090, 19, 91, 22, 19, 19, 35, 22, 15, 26), },
+	{ DSIM_DPHY_TIMING(2080, 19, 91, 21, 18, 19, 35, 22, 15, 26), },
+	{ DSIM_DPHY_TIMING(2070, 18, 90, 21, 18, 19, 35, 22, 15, 25), },
+	{ DSIM_DPHY_TIMING(2060, 18, 90, 21, 18, 19, 34, 22, 15, 25), },
+	{ DSIM_DPHY_TIMING(2050, 18, 89, 21, 18, 19, 34, 22, 15, 25), },
+	{ DSIM_DPHY_TIMING(2040, 18, 89, 21, 18, 19, 34, 21, 15, 25), },
+	{ DSIM_DPHY_TIMING(2030, 18, 88, 21, 18, 19, 34, 21, 15, 25), },
+	{ DSIM_DPHY_TIMING(2020, 18, 88, 21, 18, 19, 34, 21, 15, 25), },
+	{ DSIM_DPHY_TIMING(2010, 18, 87, 21, 18, 19, 34, 21, 15, 25), },
+	{ DSIM_DPHY_TIMING(2000, 18, 87, 21, 18, 19, 33, 21, 15, 25), },
+	{ DSIM_DPHY_TIMING(1990, 18, 87, 21, 18, 18, 33, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1980, 18, 86, 21, 18, 18, 33, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1970, 17, 86, 21, 17, 18, 33, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1960, 17, 85, 21, 17, 18, 33, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1950, 17, 85, 21, 17, 18, 32, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1940, 17, 84, 20, 17, 18, 32, 21, 14, 24), },
+	{ DSIM_DPHY_TIMING(1930, 17, 84, 20, 17, 18, 32, 20, 14, 24), },
+	{ DSIM_DPHY_TIMING(1920, 17, 84, 20, 17, 18, 32, 20, 14, 24), },
+	{ DSIM_DPHY_TIMING(1910, 17, 83, 20, 17, 18, 32, 20, 14, 23), },
+	{ DSIM_DPHY_TIMING(1900, 17, 83, 20, 17, 18, 32, 20, 14, 23), },
+	{ DSIM_DPHY_TIMING(1890, 17, 82, 20, 17, 18, 31, 20, 14, 23), },
+	{ DSIM_DPHY_TIMING(1880, 17, 82, 20, 17, 17, 31, 20, 14, 23), },
+	{ DSIM_DPHY_TIMING(1870, 17, 81, 20, 17, 17, 31, 20, 14, 23), },
+	{ DSIM_DPHY_TIMING(1860, 16, 81, 20, 17, 17, 31, 20, 13, 23), },
+	{ DSIM_DPHY_TIMING(1850, 16, 80, 20, 16, 17, 31, 20, 13, 23), },
+	{ DSIM_DPHY_TIMING(1840, 16, 80, 20, 16, 17, 30, 20, 13, 23), },
+	{ DSIM_DPHY_TIMING(1830, 16, 80, 20, 16, 17, 30, 20, 13, 22), },
+	{ DSIM_DPHY_TIMING(1820, 16, 79, 20, 16, 17, 30, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1810, 16, 79, 19, 16, 17, 30, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1800, 16, 78, 19, 16, 17, 30, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1790, 16, 78, 19, 16, 17, 30, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1780, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1770, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1760, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+	{ DSIM_DPHY_TIMING(1750, 15, 76, 19, 16, 16, 29, 19, 13, 21), },
+	{ DSIM_DPHY_TIMING(1740, 15, 76, 19, 15, 16, 29, 19, 13, 21), },
+	{ DSIM_DPHY_TIMING(1730, 15, 75, 19, 15, 16, 28, 19, 12, 21), },
+	{ DSIM_DPHY_TIMING(1720, 15, 75, 19, 15, 16, 28, 19, 12, 21), },
+	{ DSIM_DPHY_TIMING(1710, 15, 74, 19, 15, 16, 28, 18, 12, 21), },
+	{ DSIM_DPHY_TIMING(1700, 15, 74, 19, 15, 16, 28, 18, 12, 21), },
+	{ DSIM_DPHY_TIMING(1690, 15, 73, 19, 15, 16, 28, 18, 12, 21), },
+	{ DSIM_DPHY_TIMING(1680, 15, 73, 18, 15, 16, 28, 18, 12, 21), },
+	{ DSIM_DPHY_TIMING(1670, 15, 73, 18, 15, 15, 27, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1660, 15, 72, 18, 15, 15, 27, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1650, 14, 72, 18, 15, 15, 27, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1640, 14, 71, 18, 15, 15, 27, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1630, 14, 71, 18, 15, 15, 27, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1620, 14, 70, 18, 14, 15, 26, 18, 12, 20), },
+	{ DSIM_DPHY_TIMING(1610, 14, 70, 18, 14, 15, 26, 17, 12, 20), },
+	{ DSIM_DPHY_TIMING(1600, 14, 70, 18, 14, 15, 26, 17, 12, 20), },
+	{ DSIM_DPHY_TIMING(1590, 14, 69, 18, 14, 15, 26, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1580, 14, 69, 18, 14, 15, 26, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1570, 14, 68, 18, 14, 15, 26, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1560, 14, 68, 18, 14, 14, 25, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1550, 14, 67, 18, 14, 14, 25, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1540, 13, 67, 17, 14, 14, 25, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1530, 13, 66, 17, 14, 14, 25, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1520, 13, 66, 17, 14, 14, 25, 17, 11, 19), },
+	{ DSIM_DPHY_TIMING(1510, 13, 66, 17, 13, 14, 24, 17, 11, 18), },
+	{ DSIM_DPHY_TIMING(1500, 13, 65, 17, 13, 14, 24, 16, 11, 18), },
+	{ DSIM_DPHY_TIMING(1490, 13, 65, 17, 13, 14, 24, 16, 11, 18), },
+	{ DSIM_DPHY_TIMING(1480, 13, 64, 17, 13, 14, 24, 16, 11, 18), },
+	{ DSIM_DPHY_TIMING(1470, 13, 64, 17, 13, 14, 24, 16, 11, 18), },
+	{ DSIM_DPHY_TIMING(1460, 13, 63, 17, 13, 13, 24, 16, 10, 18), },
+	{ DSIM_DPHY_TIMING(1450, 13, 63, 17, 13, 13, 23, 16, 10, 18), },
+	{ DSIM_DPHY_TIMING(1440, 13, 63, 17, 13, 13, 23, 16, 10, 18), },
+	{ DSIM_DPHY_TIMING(1430, 12, 62, 17, 13, 13, 23, 16, 10, 17), },
+	{ DSIM_DPHY_TIMING(1420, 12, 62, 17, 13, 13, 23, 16, 10, 17), },
+	{ DSIM_DPHY_TIMING(1410, 12, 61, 16, 13, 13, 23, 16, 10, 17), },
+	{ DSIM_DPHY_TIMING(1400, 12, 61, 16, 13, 13, 23, 16, 10, 17), },
+	{ DSIM_DPHY_TIMING(1390, 12, 60, 16, 12, 13, 22, 15, 10, 17), },
+	{ DSIM_DPHY_TIMING(1380, 12, 60, 16, 12, 13, 22, 15, 10, 17), },
+	{ DSIM_DPHY_TIMING(1370, 12, 59, 16, 12, 13, 22, 15, 10, 17), },
+	{ DSIM_DPHY_TIMING(1360, 12, 59, 16, 12, 13, 22, 15, 10, 17), },
+	{ DSIM_DPHY_TIMING(1350, 12, 59, 16, 12, 12, 22, 15, 10, 16), },
+	{ DSIM_DPHY_TIMING(1340, 12, 58, 16, 12, 12, 21, 15, 10, 16), },
+	{ DSIM_DPHY_TIMING(1330, 11, 58, 16, 12, 12, 21, 15,  9, 16), },
+	{ DSIM_DPHY_TIMING(1320, 11, 57, 16, 12, 12, 21, 15,  9, 16), },
+	{ DSIM_DPHY_TIMING(1310, 11, 57, 16, 12, 12, 21, 15,  9, 16), },
+	{ DSIM_DPHY_TIMING(1300, 11, 56, 16, 12, 12, 21, 15,  9, 16), },
+	{ DSIM_DPHY_TIMING(1290, 11, 56, 16, 12, 12, 21, 15,  9, 16), },
+	{ DSIM_DPHY_TIMING(1280, 11, 56, 15, 11, 12, 20, 14,  9, 16), },
+	{ DSIM_DPHY_TIMING(1270, 11, 55, 15, 11, 12, 20, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1260, 11, 55, 15, 11, 12, 20, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1250, 11, 54, 15, 11, 11, 20, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1240, 11, 54, 15, 11, 11, 20, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1230, 11, 53, 15, 11, 11, 19, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1220, 10, 53, 15, 11, 11, 19, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1210, 10, 52, 15, 11, 11, 19, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1200, 10, 52, 15, 11, 11, 19, 14,  9, 15), },
+	{ DSIM_DPHY_TIMING(1190, 10, 52, 15, 11, 11, 19, 14,  8, 14), },
+	{ DSIM_DPHY_TIMING(1180, 10, 51, 15, 11, 11, 19, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1170, 10, 51, 15, 10, 11, 18, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1160, 10, 50, 15, 10, 11, 18, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1150, 10, 50, 15, 10, 11, 18, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1140, 10, 49, 14, 10, 10, 18, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1130, 10, 49, 14, 10, 10, 18, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1120, 10, 49, 14, 10, 10, 17, 13,  8, 14), },
+	{ DSIM_DPHY_TIMING(1110,  9, 48, 14, 10, 10, 17, 13,  8, 13), },
+	{ DSIM_DPHY_TIMING(1100,  9, 48, 14, 10, 10, 17, 13,  8, 13), },
+	{ DSIM_DPHY_TIMING(1090,  9, 47, 14, 10, 10, 17, 13,  8, 13), },
+	{ DSIM_DPHY_TIMING(1080,  9, 47, 14, 10, 10, 17, 13,  8, 13), },
+	{ DSIM_DPHY_TIMING(1070,  9, 46, 14, 10, 10, 17, 12,  8, 13), },
+	{ DSIM_DPHY_TIMING(1060,  9, 46, 14, 10, 10, 16, 12,  7, 13), },
+	{ DSIM_DPHY_TIMING(1050,  9, 45, 14,  9, 10, 16, 12,  7, 13), },
+	{ DSIM_DPHY_TIMING(1040,  9, 45, 14,  9, 10, 16, 12,  7, 13), },
+	{ DSIM_DPHY_TIMING(1030,  9, 45, 14,  9,  9, 16, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING(1020,  9, 44, 14,  9,  9, 16, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING(1010,  8, 44, 13,  9,  9, 15, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING(1000,  8, 43, 13,  9,  9, 15, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING( 990,  8, 43, 13,  9,  9, 15, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING( 980,  8, 42, 13,  9,  9, 15, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING( 970,  8, 42, 13,  9,  9, 15, 12,  7, 12), },
+	{ DSIM_DPHY_TIMING( 960,  8, 42, 13,  9,  9, 15, 11,  7, 12), },
+	{ DSIM_DPHY_TIMING( 950,  8, 41, 13,  9,  9, 14, 11,  7, 11), },
+	{ DSIM_DPHY_TIMING( 940,  8, 41, 13,  8,  9, 14, 11,  7, 11), },
+	{ DSIM_DPHY_TIMING( 930,  8, 40, 13,  8,  8, 14, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 920,  8, 40, 13,  8,  8, 14, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 910,  8, 39, 13,  8,  8, 14, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 900,  7, 39, 13,  8,  8, 13, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 890,  7, 38, 13,  8,  8, 13, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 880,  7, 38, 12,  8,  8, 13, 11,  6, 11), },
+	{ DSIM_DPHY_TIMING( 870,  7, 38, 12,  8,  8, 13, 11,  6, 10), },
+	{ DSIM_DPHY_TIMING( 860,  7, 37, 12,  8,  8, 13, 11,  6, 10), },
+	{ DSIM_DPHY_TIMING( 850,  7, 37, 12,  8,  8, 13, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 840,  7, 36, 12,  8,  8, 12, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 830,  7, 36, 12,  8,  8, 12, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 820,  7, 35, 12,  7,  7, 12, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 810,  7, 35, 12,  7,  7, 12, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 800,  7, 35, 12,  7,  7, 12, 10,  6, 10), },
+	{ DSIM_DPHY_TIMING( 790,  6, 34, 12,  7,  7, 11, 10,  5,  9), },
+	{ DSIM_DPHY_TIMING( 780,  6, 34, 12,  7,  7, 11, 10,  5,  9), },
+	{ DSIM_DPHY_TIMING( 770,  6, 33, 12,  7,  7, 11, 10,  5,  9), },
+	{ DSIM_DPHY_TIMING( 760,  6, 33, 12,  7,  7, 11, 10,  5,  9), },
+	{ DSIM_DPHY_TIMING( 750,  6, 32, 12,  7,  7, 11,  9,  5,  9), },
+	{ DSIM_DPHY_TIMING( 740,  6, 32, 11,  7,  7, 11,  9,  5,  9), },
+	{ DSIM_DPHY_TIMING( 730,  6, 31, 11,  7,  7, 10,  9,  5,  9), },
+	{ DSIM_DPHY_TIMING( 720,  6, 31, 11,  7,  6, 10,  9,  5,  9), },
+	{ DSIM_DPHY_TIMING( 710,  6, 31, 11,  6,  6, 10,  9,  5,  8), },
+	{ DSIM_DPHY_TIMING( 700,  6, 30, 11,  6,  6, 10,  9,  5,  8), },
+	{ DSIM_DPHY_TIMING( 690,  5, 30, 11,  6,  6, 10,  9,  5,  8), },
+	{ DSIM_DPHY_TIMING( 680,  5, 29, 11,  6,  6,  9,  9,  5,  8), },
+	{ DSIM_DPHY_TIMING( 670,  5, 29, 11,  6,  6,  9,  9,  5,  8), },
+	{ DSIM_DPHY_TIMING( 660,  5, 28, 11,  6,  6,  9,  9,  4,  8), },
+	{ DSIM_DPHY_TIMING( 650,  5, 28, 11,  6,  6,  9,  9,  4,  8), },
+	{ DSIM_DPHY_TIMING( 640,  5, 28, 11,  6,  6,  9,  8,  4,  8), },
+	{ DSIM_DPHY_TIMING( 630,  5, 27, 11,  6,  6,  9,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 620,  5, 27, 11,  6,  6,  8,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 610,  5, 26, 10,  6,  5,  8,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 600,  5, 26, 10,  6,  5,  8,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 590,  5, 25, 10,  5,  5,  8,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 580,  4, 25, 10,  5,  5,  8,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 570,  4, 24, 10,  5,  5,  7,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 560,  4, 24, 10,  5,  5,  7,  8,  4,  7), },
+	{ DSIM_DPHY_TIMING( 550,  4, 24, 10,  5,  5,  7,  8,  4,  6), },
+	{ DSIM_DPHY_TIMING( 540,  4, 23, 10,  5,  5,  7,  8,  4,  6), },
+	{ DSIM_DPHY_TIMING( 530,  4, 23, 10,  5,  5,  7,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 520,  4, 22, 10,  5,  5,  7,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 510,  4, 22, 10,  5,  5,  6,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 500,  4, 21, 10,  5,  4,  6,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 490,  4, 21, 10,  5,  4,  6,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 480,  4, 21,  9,  4,  4,  6,  7,  3,  6), },
+	{ DSIM_DPHY_TIMING( 470,  3, 20,  9,  4,  4,  6,  7,  3,  5), },
+	{ DSIM_DPHY_TIMING( 460,  3, 20,  9,  4,  4,  5,  7,  3,  5), },
+	{ DSIM_DPHY_TIMING( 450,  3, 19,  9,  4,  4,  5,  7,  3,  5), },
+	{ DSIM_DPHY_TIMING( 440,  3, 19,  9,  4,  4,  5,  7,  3,  5), },
+	{ DSIM_DPHY_TIMING( 430,  3, 18,  9,  4,  4,  5,  7,  3,  5), },
+	{ DSIM_DPHY_TIMING( 420,  3, 18,  9,  4,  4,  5,  6,  3,  5), },
+	{ DSIM_DPHY_TIMING( 410,  3, 17,  9,  4,  4,  5,  6,  3,  5), },
+	{ DSIM_DPHY_TIMING( 400,  3, 17,  9,  4,  3,  4,  6,  3,  5), },
+	{ DSIM_DPHY_TIMING( 390,  3, 17,  9,  4,  3,  4,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 380,  3, 16,  9,  4,  3,  4,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 370,  2, 16,  9,  3,  3,  4,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 360,  2, 15,  9,  3,  3,  4,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 350,  2, 15,  9,  3,  3,  3,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 340,  2, 14,  8,  3,  3,  3,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 330,  2, 14,  8,  3,  3,  3,  6,  2,  4), },
+	{ DSIM_DPHY_TIMING( 320,  2, 14,  8,  3,  3,  3,  5,  2,  4), },
+	{ DSIM_DPHY_TIMING( 310,  2, 13,  8,  3,  3,  3,  5,  2,  3), },
+	{ DSIM_DPHY_TIMING( 300,  2, 13,  8,  3,  3,  3,  5,  2,  3), },
+	{ DSIM_DPHY_TIMING( 290,  2, 12,  8,  3,  2,  2,  5,  2,  3), },
+	{ DSIM_DPHY_TIMING( 280,  2, 12,  8,  3,  2,  2,  5,  2,  3), },
+	{ DSIM_DPHY_TIMING( 270,  2, 11,  8,  3,  2,  2,  5,  2,  3), },
+	{ DSIM_DPHY_TIMING( 260,  1, 11,  8,  3,  2,  2,  5,  1,  3), },
+	{ DSIM_DPHY_TIMING( 250,  1, 10,  8,  2,  2,  2,  5,  1,  3), },
+	{ DSIM_DPHY_TIMING( 240,  1,  9,  8,  2,  2,  1,  5,  1,  3), },
+	{ DSIM_DPHY_TIMING( 230,  1,  8,  8,  2,  2,  1,  5,  1,  2), },
+	{ DSIM_DPHY_TIMING( 220,  1,  8,  8,  2,  2,  1,  5,  1,  2), },
+	{ DSIM_DPHY_TIMING( 210,  1,  7,  7,  2,  2,  1,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 200,  1,  7,  7,  2,  2,  1,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 190,  1,  7,  7,  2,  1,  1,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 180,  1,  6,  7,  2,  1,  0,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 170,  1,  6,  7,  2,  1,  0,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 160,  1,  6,  7,  2,  1,  0,  4,  1,  2), },
+	{ DSIM_DPHY_TIMING( 150,  0,  5,  7,  2,  1,  0,  4,  1,  1), },
+	{ DSIM_DPHY_TIMING( 140,  0,  5,  7,  1,  1,  0,  4,  1,  1), },
+	{ DSIM_DPHY_TIMING( 130,  0,  4,  7,  1,  1,  0,  4,  0,  1), },
+	{ DSIM_DPHY_TIMING( 120,  0,  4,  7,  1,  1,  0,  4,  0,  1), },
+	{ DSIM_DPHY_TIMING( 110,  0,  3,  7,  1,  0,  0,  4,  0,  1), },
+	{ DSIM_DPHY_TIMING( 100,  0,  3,  7,  1,  0,  0,  3,  0,  1), },
+	{ DSIM_DPHY_TIMING(  90,  0,  2,  7,  1,  0,  0,  3,  0,  1), },
+	{ DSIM_DPHY_TIMING(  80,  0,  2,  6,  1,  0,  0,  3,  0,  1), },
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c
@@ -0,0 +1,494 @@
+/*
+ * Samsung MIPI DSI Host Controller on IMX
+ *
+ * Copyright 2018-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <drm/bridge/sec_mipi_dsim.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include "imx-drm.h"
+#include "sec_mipi_dphy_ln14lpp.h"
+#include "sec_mipi_pll_1432x.h"
+
+#define DRIVER_NAME "imx_sec_dsim_drv"
+
+struct imx_sec_dsim_device {
+	struct device *dev;
+	struct drm_encoder encoder;
+
+	struct reset_control *soft_resetn;
+	struct reset_control *clk_enable;
+	struct reset_control *mipi_reset;
+	struct regmap *blk_ctl;
+
+	atomic_t rpm_suspended;
+};
+
+#define enc_to_dsim(enc) container_of(enc, struct imx_sec_dsim_device, encoder)
+
+static struct imx_sec_dsim_device *dsim_dev;
+
+#if CONFIG_PM
+static int imx_sec_dsim_runtime_suspend(struct device *dev);
+static int imx_sec_dsim_runtime_resume(struct device *dev);
+#else
+static int imx_sec_dsim_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+static int imx_sec_dsim_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static int sec_dsim_rstc_reset(struct reset_control *rstc, bool assert)
+{
+	int ret;
+
+	if (!rstc)
+		return 0;
+
+	ret = assert ? reset_control_assert(rstc)	:
+		       reset_control_deassert(rstc);
+
+	return ret;
+}
+
+int imx8mp_get_ldo_trim(int ldo);
+
+static void imx_sec_dsim_encoder_helper_enable(struct drm_encoder *encoder)
+{
+	int ret, reg;
+
+	struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+
+	pm_runtime_get_sync(dsim_dev->dev);
+
+	if (dsim_dev->blk_ctl) {
+		reg = imx8mp_get_ldo_trim(0);
+		if(reg >= 0)
+			regmap_write(dsim_dev->blk_ctl, 0x58, reg & 0x1f);
+	}
+
+	ret = sec_dsim_rstc_reset(dsim_dev->mipi_reset, false);
+	if (ret)
+		dev_err(dsim_dev->dev, "deassert mipi_reset failed\n");
+}
+
+static void imx_sec_dsim_encoder_helper_disable(struct drm_encoder *encoder)
+{
+	int ret;
+	struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+
+	ret = sec_dsim_rstc_reset(dsim_dev->mipi_reset, true);
+	if (ret)
+		dev_err(dsim_dev->dev, "deassert mipi_reset failed\n");
+
+	pm_runtime_put_sync(dsim_dev->dev);
+}
+
+static int imx_sec_dsim_encoder_helper_atomic_check(struct drm_encoder *encoder,
+						    struct drm_crtc_state *crtc_state,
+						    struct drm_connector_state *conn_state)
+{
+	int i, ret;
+	u32 bus_format;
+	unsigned int num_bus_formats;
+	struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+	struct drm_bridge *bridge = encoder->bridge;
+	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+	struct drm_display_info *display_info = &conn_state->connector->display_info;
+
+	num_bus_formats = display_info->num_bus_formats;
+	if (unlikely(!num_bus_formats))
+		dev_warn(dsim_dev->dev, "no bus formats assigned by connector\n");
+
+	bus_format = adjusted_mode->private_flags & 0xffff;
+
+	for (i = 0; i < num_bus_formats; i++) {
+		if (display_info->bus_formats[i] != bus_format)
+			continue;
+		break;
+	}
+
+	if (i && i == num_bus_formats) {
+		dev_err(dsim_dev->dev, "invalid bus format for connector\n");
+		return -EINVAL;
+	}
+
+	/* check pll out */
+	ret = sec_mipi_dsim_check_pll_out(bridge->driver_private,
+					  adjusted_mode);
+	if (ret)
+		return ret;
+
+	/* sec dsim can only accept active hight DE */
+	imx_crtc_state->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
+
+	/* For the dotclock polarity, default is neg edge;
+	 * and in the dsim spec, there is no explict words
+	 * to illustrate the dotclock polarity requirement.
+	 */
+	imx_crtc_state->bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+	/* set the bus format for CRTC output which should be
+	 * the same as the bus format between dsim and connector,
+	 * since dsim cannot do any pixel conversions.
+	 */
+	imx_crtc_state->bus_format = bus_format;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs imx_sec_dsim_encoder_helper_funcs = {
+	.enable  = imx_sec_dsim_encoder_helper_enable,
+	.disable = imx_sec_dsim_encoder_helper_disable,
+	.atomic_check = imx_sec_dsim_encoder_helper_atomic_check,
+};
+
+static const struct drm_encoder_funcs imx_sec_dsim_encoder_funcs = {
+	.destroy = imx_drm_encoder_destroy,
+};
+
+static const struct sec_mipi_dsim_plat_data imx8mm_mipi_dsim_plat_data = {
+	.version	= 0x1060200,
+	.max_data_lanes = 4,
+	.max_data_rate  = 1500000000ULL,
+	.dphy_pll	= &pll_1432x,
+	.dphy_timing	= dphy_timing_ln14lpp_v1p2,
+	.num_dphy_timing = ARRAY_SIZE(dphy_timing_ln14lpp_v1p2),
+	.dphy_timing_cmp = dphy_timing_default_cmp,
+	.mode_valid	= NULL,
+};
+
+static const struct of_device_id imx_sec_dsim_dt_ids[] = {
+	{
+		.compatible = "fsl,imx8mm-mipi-dsim",
+		.data = &imx8mm_mipi_dsim_plat_data,
+	},
+	{
+		.compatible = "fsl,imx8mn-mipi-dsim",
+		.data = &imx8mm_mipi_dsim_plat_data,
+	},
+	{
+		.compatible = "fsl,imx8mp-mipi-dsim",
+		.data = &imx8mm_mipi_dsim_plat_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sec_dsim_dt_ids);
+
+static int sec_dsim_of_parse_resets(struct imx_sec_dsim_device *dsim)
+{
+	int ret;
+	struct device *dev = dsim->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *parent, *child;
+	struct of_phandle_args args;
+	struct reset_control *rstc;
+	const char *compat;
+	uint32_t len, rstc_num = 0;
+
+	/* TODO: bypass resets for imx8mp platform */
+	compat = of_get_property(np, "compatible", NULL);
+	if (unlikely(!compat))
+		return -ENODEV;
+
+	len = strlen(compat);
+	if (!of_compat_cmp(compat, "fsl,imx8mp-mipi-dsim", len))
+		return 0;
+
+	ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
+					 0, &args);
+	if (ret)
+		return ret;
+
+	parent = args.np;
+	for_each_child_of_node(parent, child) {
+		compat = of_get_property(child, "compatible", NULL);
+		if (!compat)
+			continue;
+
+		rstc = of_reset_control_array_get(child, false, false, true);
+		if (IS_ERR(rstc))
+			continue;
+
+		len = strlen(compat);
+		if (!of_compat_cmp("dsi,soft-resetn", compat, len)) {
+			dsim->soft_resetn = rstc;
+			rstc_num++;
+		} else if (!of_compat_cmp("dsi,clk-enable", compat, len)) {
+			dsim->clk_enable = rstc;
+			rstc_num++;
+		} else if (!of_compat_cmp("dsi,mipi-reset", compat, len)) {
+			dsim->mipi_reset = rstc;
+			rstc_num++;
+		} else
+			dev_warn(dev, "invalid dsim reset node: %s\n", compat);
+	}
+
+	if (!rstc_num) {
+		dev_err(dev, "no invalid reset control exists\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void sec_dsim_of_put_resets(struct imx_sec_dsim_device *dsim)
+{
+	if (dsim->soft_resetn)
+		reset_control_put(dsim->soft_resetn);
+
+	if (dsim->clk_enable)
+		reset_control_put(dsim->clk_enable);
+
+	if (dsim->mipi_reset)
+		reset_control_put(dsim->mipi_reset);
+}
+
+static int imx_sec_dsim_bind(struct device *dev, struct device *master,
+			     void *data)
+{
+	int ret, irq;
+	struct resource *res;
+	struct drm_device *drm_dev = data;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *of_id = of_match_device(imx_sec_dsim_dt_ids,
+							   dev);
+	const struct sec_mipi_dsim_plat_data *pdata;
+	struct drm_encoder *encoder;
+
+	dev_dbg(dev, "%s: dsim bind begin\n", __func__);
+
+	if (!of_id)
+		return -ENODEV;
+	pdata = of_id->data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENODEV;
+
+	ret = sec_dsim_of_parse_resets(dsim_dev);
+	if (ret)
+		return ret;
+
+	encoder = &dsim_dev->encoder;
+	ret = imx_drm_encoder_parse_of(drm_dev, encoder, np);
+	if (ret)
+		return ret;
+
+	drm_encoder_helper_add(encoder, &imx_sec_dsim_encoder_helper_funcs);
+
+	dsim_dev->blk_ctl = syscon_regmap_lookup_by_phandle(np, "blk-ctl");
+	if (IS_ERR(dsim_dev->blk_ctl)) {
+		dev_warn(dev, "failed to get blk_ctl\n");
+		dsim_dev->blk_ctl = NULL;
+	}
+
+	ret = drm_encoder_init(drm_dev, encoder,
+			       &imx_sec_dsim_encoder_funcs,
+			       DRM_MODE_ENCODER_DSI, dev_name(dev));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(dev);
+
+	/* bind sec dsim bridge */
+	ret = sec_mipi_dsim_bind(dev, master, data, encoder, res, irq, pdata);
+	if (ret) {
+		dev_err(dev, "failed to bind sec dsim bridge: %d\n", ret);
+		pm_runtime_disable(dev);
+		drm_encoder_cleanup(encoder);
+		sec_dsim_of_put_resets(dsim_dev);
+
+		/* If no panel or bridge connected, just return 0
+		 * to make component core to believe it is bound
+		 * successfully to allow other components can be
+		 * bound continuously, since in component core,
+		 * it follows 'one fails, all fail'. It is useful
+		 * when there exists multiple heads display.
+		 */
+		if (ret == -ENODEV)
+			return 0;
+
+		return ret;
+	}
+
+	dev_dbg(dev, "%s: dsim bind end\n", __func__);
+
+	return 0;
+}
+
+static void imx_sec_dsim_unbind(struct device *dev, struct device *master,
+				void *data)
+{
+	if (!dsim_dev->encoder.dev)
+		return;
+
+	pm_runtime_disable(dev);
+
+	drm_encoder_cleanup(&dsim_dev->encoder);
+
+	sec_mipi_dsim_unbind(dev, master, data);
+
+	sec_dsim_of_put_resets(dsim_dev);
+}
+
+static const struct component_ops imx_sec_dsim_ops = {
+	.bind	= imx_sec_dsim_bind,
+	.unbind	= imx_sec_dsim_unbind,
+};
+
+static int imx_sec_dsim_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	dev_dbg(dev, "%s: dsim probe begin\n", __func__);
+
+	dsim_dev = devm_kzalloc(dev, sizeof(*dsim_dev), GFP_KERNEL);
+	if (!dsim_dev) {
+		dev_err(dev, "Unable to allocate 'dsim_dev'\n");
+		return -ENOMEM;
+	}
+
+	atomic_set(&dsim_dev->rpm_suspended, 1);
+
+	dsim_dev->dev = dev;
+
+	return component_add(dev, &imx_sec_dsim_ops);
+}
+
+static int imx_sec_dsim_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_sec_dsim_ops);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_sec_dsim_suspend(struct device *dev)
+{
+	return imx_sec_dsim_runtime_suspend(dev);
+}
+
+static int imx_sec_dsim_resume(struct device *dev)
+{
+	return imx_sec_dsim_runtime_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int imx_sec_dsim_runtime_suspend(struct device *dev)
+{
+	/* check sec dsim is bound or not */
+	if (unlikely(!dsim_dev->encoder.dev))
+		return 0;
+
+	if (atomic_inc_return(&dsim_dev->rpm_suspended) > 1)
+		return 0;
+
+	sec_mipi_dsim_suspend(dev);
+
+	release_bus_freq(BUS_FREQ_HIGH);
+
+	return 0;
+}
+
+static int imx_sec_dsim_runtime_resume(struct device *dev)
+{
+	int ret;
+
+	/* check sec dsim is bound or not */
+	if (unlikely(!dsim_dev->encoder.dev))
+		return 0;
+
+	if (unlikely(!atomic_read(&dsim_dev->rpm_suspended))) {
+		dev_warn(dsim_dev->dev,
+			 "Unbalanced %s!\n", __func__);
+		return 0;
+	}
+
+	if (!atomic_dec_and_test(&dsim_dev->rpm_suspended))
+		return 0;
+
+	request_bus_freq(BUS_FREQ_HIGH);
+
+	ret = sec_dsim_rstc_reset(dsim_dev->soft_resetn, false);
+	if (ret) {
+		dev_err(dev, "deassert soft_resetn failed\n");
+		return ret;
+	}
+
+	ret = sec_dsim_rstc_reset(dsim_dev->clk_enable, true);
+	if (ret) {
+		dev_err(dev, "assert clk_enable failed\n");
+		return ret;
+	}
+
+	ret = sec_dsim_rstc_reset(dsim_dev->mipi_reset, false);
+	if (ret) {
+		dev_err(dev, "deassert mipi_reset failed\n");
+		return ret;
+	}
+
+	sec_mipi_dsim_resume(dev);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx_sec_dsim_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(imx_sec_dsim_suspend,
+				     imx_sec_dsim_resume)
+	SET_RUNTIME_PM_OPS(imx_sec_dsim_runtime_suspend,
+			   imx_sec_dsim_runtime_resume,
+			   NULL)
+};
+
+struct platform_driver imx_sec_dsim_driver = {
+	.probe    = imx_sec_dsim_probe,
+	.remove   = imx_sec_dsim_remove,
+	.driver   = {
+		.name = DRIVER_NAME,
+		.of_match_table = imx_sec_dsim_dt_ids,
+		.pm = &imx_sec_dsim_pm_ops,
+	},
+};
+
+module_platform_driver(imx_sec_dsim_driver);
+
+MODULE_DESCRIPTION("NXP i.MX MIPI DSI Host Controller driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/imx/sec_mipi_pll_1432x.h
+++ linux-ein-5.4.0/drivers/gpu/drm/imx/sec_mipi_pll_1432x.h
@@ -0,0 +1,49 @@
+/*
+ * Samsung MIPI DSIM PLL_1432X
+ *
+ * Copyright 2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __SEC_DSIM_PLL_1432X_H__
+#define __SEC_DSIM_PLL_1432X_H__
+
+#include <drm/bridge/sec_mipi_dsim.h>
+/*
+ * DSIM PLL_1432X setting guide from spec:
+ *
+ * Fout(bitclk) = ((m + k / 65536) * Fin) / (p * 2^s), and
+ * p = P[5:0], m = M[9:0], s = S[2:0], k = K[15:0];
+ *
+ * Fpref = Fin / p
+ * Fin: [6MHz ~ 300MHz], Fpref: [2MHz ~ 30MHz]
+ *
+ * Fvco = ((m + k / 65536) * Fin) / p
+ * Fvco: [1050MHz ~ 2100MHz]
+ *
+ * 1 <= P[5:0] <= 63, 64 <= M[9:0] <= 1023,
+ * 0 <= S[2:0] <=  5, -32768 <= K[15:0] <= 32767
+ *
+ */
+
+const struct sec_mipi_dsim_pll pll_1432x = {
+	.p	= { .min = 1,		.max = 63,	},
+	.m	= { .min = 64,		.max = 1023,	},
+	.s	= { .min = 0,		.max = 5,	},
+	.k	= { .min = 0,		.max = 32768,	},	/* abs(k) */
+	.fin	= { .min = 6000,	.max = 300000,	},	/* in KHz */
+	.fpref	= { .min = 2000,	.max = 30000,	},	/* in KHz */
+	.fvco	= { .min = 1050000,	.max = 2100000,	},	/* in KHz */
+};
+
+#endif
+
--- linux-ein-5.4.0.orig/drivers/gpu/drm/ingenic/ingenic-drm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/ingenic/ingenic-drm.c
@@ -371,14 +371,18 @@
 	struct ingenic_drm *priv = drm_plane_get_priv(plane);
 	struct drm_plane_state *state = plane->state;
 	unsigned int width, height, cpp;
+	dma_addr_t addr;
 
-	width = state->crtc->state->adjusted_mode.hdisplay;
-	height = state->crtc->state->adjusted_mode.vdisplay;
-	cpp = state->fb->format->cpp[plane->index];
-
-	priv->dma_hwdesc->addr = drm_fb_cma_get_gem_addr(state->fb, state, 0);
-	priv->dma_hwdesc->cmd = width * height * cpp / 4;
-	priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ;
+	if (state && state->fb) {
+		addr = drm_fb_cma_get_gem_addr(state->fb, state, 0);
+		width = state->src_w >> 16;
+		height = state->src_h >> 16;
+		cpp = state->fb->format->cpp[0];
+
+		priv->dma_hwdesc->addr = addr;
+		priv->dma_hwdesc->cmd = width * height * cpp / 4;
+		priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ;
+	}
 }
 
 static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
@@ -463,7 +467,7 @@
 
 static irqreturn_t ingenic_drm_irq_handler(int irq, void *arg)
 {
-	struct ingenic_drm *priv = arg;
+	struct ingenic_drm *priv = drm_device_get_priv(arg);
 	unsigned int state;
 
 	regmap_read(priv->map, JZ_REG_LCD_STATE, &state);
@@ -820,6 +824,7 @@
 	{ .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
 	{ /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, ingenic_drm_of_match);
 
 static struct platform_driver ingenic_drm_driver = {
 	.driver = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/lima/lima_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/lima/lima_device.c
@@ -293,6 +293,7 @@
 	struct resource *res;
 
 	dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32));
+	dma_set_max_seg_size(ldev->dev, UINT_MAX);
 
 	err = lima_clk_init(ldev);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/lima/lima_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/lima/lima_drv.c
@@ -300,8 +300,10 @@
 
 	/* Allocate and initialize the DRM device. */
 	ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev);
-	if (IS_ERR(ddev))
-		return PTR_ERR(ddev);
+	if (IS_ERR(ddev)) {
+		err = PTR_ERR(ddev);
+		goto err_out0;
+	}
 
 	ddev->dev_private = ldev;
 	ldev->ddev = ddev;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mcde/mcde_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mcde/mcde_display.c
@@ -946,6 +946,7 @@
 	struct drm_crtc *crtc = &pipe->crtc;
 	struct drm_device *drm = crtc->dev;
 	struct mcde *mcde = drm->dev_private;
+	struct drm_pending_vblank_event *event;
 
 	if (mcde->te_sync)
 		drm_crtc_vblank_off(crtc);
@@ -953,6 +954,15 @@
 	/* Disable FIFO A flow */
 	mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
 
+	event = crtc->state->event;
+	if (event) {
+		crtc->state->event = NULL;
+
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
+
 	dev_info(drm->dev, "MCDE display is disabled\n");
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mcde/mcde_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mcde/mcde_drv.c
@@ -215,7 +215,6 @@
 
 	drm_mode_config_reset(drm);
 	drm_kms_helper_poll_init(drm);
-	drm_fbdev_generic_setup(drm, 32);
 
 	return 0;
 
@@ -282,6 +281,8 @@
 	if (ret < 0)
 		goto unbind;
 
+	drm_fbdev_generic_setup(drm, 32);
+
 	return 0;
 
 unbind:
@@ -409,8 +410,8 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		ret = -EINVAL;
+	if (irq < 0) {
+		ret = irq;
 		goto clk_disable;
 	}
 
@@ -484,7 +485,8 @@
 	}
 	if (!match) {
 		dev_err(dev, "no matching components\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto clk_disable;
 	}
 	if (IS_ERR(match)) {
 		dev_err(dev, "could not create component match\n");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mcde/mcde_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -935,13 +935,15 @@
 	for_each_available_child_of_node(dev->of_node, child) {
 		panel = of_drm_find_panel(child);
 		if (IS_ERR(panel)) {
-			dev_err(dev, "failed to find panel try bridge (%lu)\n",
+			dev_err(dev, "failed to find panel try bridge (%ld)\n",
 				PTR_ERR(panel));
+			panel = NULL;
+
 			bridge = of_drm_find_bridge(child);
-			if (IS_ERR(bridge)) {
-				dev_err(dev, "failed to find bridge (%lu)\n",
-					PTR_ERR(bridge));
-				return PTR_ERR(bridge);
+			if (!bridge) {
+				dev_err(dev, "failed to find bridge\n");
+				of_node_put(child);
+				return -EINVAL;
 			}
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_cec.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -84,7 +84,7 @@
 	u32 tmp = readl(cec->regs + offset) & ~mask;
 
 	tmp |= val & mask;
-	writel(val, cec->regs + offset);
+	writel(tmp, cec->regs + offset);
 }
 
 void mtk_cec_set_hpd_event(struct device *dev,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -10,7 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 
@@ -48,13 +50,7 @@
 };
 
 enum mtk_dpi_out_color_format {
-	MTK_DPI_COLOR_FORMAT_RGB,
-	MTK_DPI_COLOR_FORMAT_RGB_FULL,
-	MTK_DPI_COLOR_FORMAT_YCBCR_444,
-	MTK_DPI_COLOR_FORMAT_YCBCR_422,
-	MTK_DPI_COLOR_FORMAT_XV_YCC,
-	MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL,
-	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
+	MTK_DPI_COLOR_FORMAT_RGB
 };
 
 struct mtk_dpi {
@@ -73,6 +69,9 @@
 	enum mtk_dpi_out_yc_map yc_map;
 	enum mtk_dpi_out_bit_num bit_num;
 	enum mtk_dpi_out_channel_swap channel_swap;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pins_gpio;
+	struct pinctrl_state *pins_dpi;
 	int refcount;
 };
 
@@ -350,24 +349,11 @@
 static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
 					enum mtk_dpi_out_color_format format)
 {
-	if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) ||
-	    (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
-		mtk_dpi_config_yuv422_enable(dpi, false);
-		mtk_dpi_config_csc_enable(dpi, true);
-		mtk_dpi_config_swap_input(dpi, false);
-		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR);
-	} else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) ||
-		   (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
-		mtk_dpi_config_yuv422_enable(dpi, true);
-		mtk_dpi_config_csc_enable(dpi, true);
-		mtk_dpi_config_swap_input(dpi, true);
-		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
-	} else {
-		mtk_dpi_config_yuv422_enable(dpi, false);
-		mtk_dpi_config_csc_enable(dpi, false);
-		mtk_dpi_config_swap_input(dpi, false);
-		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
-	}
+	/* only support RGB888 */
+	mtk_dpi_config_yuv422_enable(dpi, false);
+	mtk_dpi_config_csc_enable(dpi, false);
+	mtk_dpi_config_swap_input(dpi, false);
+	mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
 }
 
 static void mtk_dpi_power_off(struct mtk_dpi *dpi)
@@ -402,7 +388,6 @@
 		goto err_pixel;
 	}
 
-	mtk_dpi_enable(dpi);
 	return 0;
 
 err_pixel:
@@ -538,14 +523,21 @@
 	struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder);
 
 	mtk_dpi_power_off(dpi);
+
+	if (dpi->pinctrl && dpi->pins_gpio)
+		pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
 }
 
 static void mtk_dpi_encoder_enable(struct drm_encoder *encoder)
 {
 	struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder);
 
+	if (dpi->pinctrl && dpi->pins_dpi)
+		pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
+
 	mtk_dpi_power_on(dpi);
 	mtk_dpi_set_display_mode(dpi, &dpi->mode);
+	mtk_dpi_enable(dpi);
 }
 
 static int mtk_dpi_atomic_check(struct drm_encoder *encoder,
@@ -689,6 +681,26 @@
 	dpi->dev = dev;
 	dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
 
+	dpi->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(dpi->pinctrl)) {
+		dpi->pinctrl = NULL;
+		dev_dbg(&pdev->dev, "Cannot find pinctrl!\n");
+	}
+	if (dpi->pinctrl) {
+		dpi->pins_gpio = pinctrl_lookup_state(dpi->pinctrl, "sleep");
+		if (IS_ERR(dpi->pins_gpio)) {
+			dpi->pins_gpio = NULL;
+			dev_dbg(&pdev->dev, "Cannot find pinctrl idle!\n");
+		}
+		if (dpi->pins_gpio)
+			pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
+
+		dpi->pins_dpi = pinctrl_lookup_state(dpi->pinctrl, "default");
+		if (IS_ERR(dpi->pins_dpi)) {
+			dpi->pins_dpi = NULL;
+			dev_dbg(&pdev->dev, "Cannot find pinctrl active!\n");
+		}
+	}
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dpi->regs = devm_ioremap_resource(dev, mem);
 	if (IS_ERR(dpi->regs)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -240,7 +240,7 @@
 		drm_connector_list_iter_end(&conn_iter);
 	}
 
-	ret = pm_runtime_get_sync(crtc->dev->dev);
+	ret = pm_runtime_resume_and_get(crtc->dev->dev);
 	if (ret < 0) {
 		DRM_ERROR("Failed to enable power domain: %d\n", ret);
 		return ret;
@@ -298,6 +298,7 @@
 static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
 {
 	struct drm_device *drm = mtk_crtc->base.dev;
+	struct drm_crtc *crtc = &mtk_crtc->base;
 	int i;
 
 	DRM_DEBUG_DRIVER("%s\n", __func__);
@@ -319,6 +320,13 @@
 	mtk_disp_mutex_unprepare(mtk_crtc->mutex);
 
 	pm_runtime_put(drm->dev);
+
+	if (crtc->state->event && !crtc->state->active) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
 }
 
 static void mtk_crtc_ddp_config(struct drm_crtc *crtc)
@@ -488,10 +496,18 @@
 
 static int mtk_drm_crtc_init(struct drm_device *drm,
 			     struct mtk_drm_crtc *mtk_crtc,
-			     struct drm_plane *primary,
-			     struct drm_plane *cursor, unsigned int pipe)
+			     unsigned int pipe)
 {
-	int ret;
+	struct drm_plane *primary = NULL;
+	struct drm_plane *cursor = NULL;
+	int i, ret;
+
+	for (i = 0; i < mtk_crtc->layer_nr; i++) {
+		if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY)
+			primary = &mtk_crtc->planes[i];
+		else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
+			cursor = &mtk_crtc->planes[i];
+	}
 
 	ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor,
 					&mtk_crtc_funcs, NULL);
@@ -529,6 +545,7 @@
 	int pipe = priv->num_pipes;
 	int ret;
 	int i;
+	uint gamma_lut_size = 0;
 
 	if (!path)
 		return 0;
@@ -579,6 +596,9 @@
 		}
 
 		mtk_crtc->ddp_comp[i] = comp;
+
+		if (comp->funcs && comp->funcs->gamma_set)
+			gamma_lut_size = MTK_LUT_SIZE;
 	}
 
 	mtk_crtc->layer_nr = mtk_ddp_comp_layer_nr(mtk_crtc->ddp_comp[0]);
@@ -596,13 +616,13 @@
 			return ret;
 	}
 
-	ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0],
-				mtk_crtc->layer_nr > 1 ? &mtk_crtc->planes[1] :
-				NULL, pipe);
+	ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe);
 	if (ret < 0)
 		return ret;
-	drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
-	drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE);
+
+	if (gamma_lut_size)
+		drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size);
+	drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, gamma_lut_size);
 	priv->num_pipes++;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -417,6 +417,7 @@
 err_deinit:
 	mtk_drm_kms_deinit(drm);
 err_free:
+	private->drm = NULL;
 	drm_dev_put(drm);
 	return ret;
 }
@@ -594,8 +595,13 @@
 	pm_runtime_disable(dev);
 err_node:
 	of_node_put(private->mutex_node);
-	for (i = 0; i < DDP_COMPONENT_ID_MAX; i++)
+	for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) {
 		of_node_put(private->comp_node[i]);
+		if (private->ddp_comp[i]) {
+			put_device(private->ddp_comp[i]->larb_dev);
+			private->ddp_comp[i] = NULL;
+		}
+	}
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -142,8 +142,6 @@
 
 	ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
 			     mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
-	if (ret)
-		drm_gem_vm_close(vma);
 
 	return ret;
 }
@@ -269,9 +267,13 @@
 	}
 	mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
 			       pgprot_writecombine(PAGE_KERNEL));
-
+	if (!mtk_gem->kvaddr) {
+		kfree(sgt);
+		kfree(mtk_gem->pages);
+		return ERR_PTR(-ENOMEM);
+	}
 out:
-	kfree((void *)sgt);
+	kfree(sgt);
 
 	return mtk_gem->kvaddr;
 }
@@ -284,6 +286,6 @@
 		return;
 
 	vunmap(vaddr);
-	mtk_gem->kvaddr = 0;
-	kfree((void *)mtk_gem->pages);
+	mtk_gem->kvaddr = NULL;
+	kfree(mtk_gem->pages);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -101,6 +101,16 @@
 						   true, true);
 }
 
+static void mtk_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
+
+	state->pending.enable = false;
+	wmb(); /* Make sure the above parameter is set before update */
+	state->pending.dirty = true;
+}
+
 static void mtk_plane_atomic_update(struct drm_plane *plane,
 				    struct drm_plane_state *old_state)
 {
@@ -115,6 +125,11 @@
 	if (!crtc || WARN_ON(!fb))
 		return;
 
+	if (!plane->state->visible) {
+		mtk_plane_atomic_disable(plane, old_state);
+		return;
+	}
+
 	gem = fb->obj[0];
 	mtk_gem = to_mtk_gem_obj(gem);
 	addr = mtk_gem->dma_addr;
@@ -136,16 +151,6 @@
 	state->pending.dirty = true;
 }
 
-static void mtk_plane_atomic_disable(struct drm_plane *plane,
-				     struct drm_plane_state *old_state)
-{
-	struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
-
-	state->pending.enable = false;
-	wmb(); /* Make sure the above parameter is set before update */
-	state->pending.dirty = true;
-}
-
 static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
 	.prepare_fb = drm_gem_fb_prepare_fb,
 	.atomic_check = mtk_plane_atomic_check,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -645,6 +645,8 @@
 	mtk_dsi_reset_engine(dsi);
 	mtk_dsi_lane0_ulp_mode_enter(dsi);
 	mtk_dsi_clk_ulp_mode_enter(dsi);
+	/* set the lane number as 0 to pull down mipi */
+	writel(0, dsi->regs + DSI_TXRX_CTRL);
 
 	mtk_dsi_disable(dsi);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1237,17 +1237,19 @@
 				    struct drm_display_mode *mode)
 {
 	struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
+	struct drm_bridge *next_bridge;
 
 	dev_dbg(hdmi->dev, "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
 		mode->hdisplay, mode->vdisplay, mode->vrefresh,
 		!!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000);
 
-	if (hdmi->bridge.next) {
+	next_bridge = drm_bridge_get_next_bridge(&hdmi->bridge);
+	if (next_bridge) {
 		struct drm_display_mode adjusted_mode;
 
 		drm_mode_copy(&adjusted_mode, mode);
-		if (!drm_bridge_mode_fixup(hdmi->bridge.next, mode,
-					   &adjusted_mode))
+		if (!drm_bridge_chain_mode_fixup(next_bridge, mode,
+						 &adjusted_mode))
 			return MODE_BAD;
 	}
 
@@ -1482,25 +1484,30 @@
 		dev_err(dev,
 			"Failed to get system configuration registers: %d\n",
 			ret);
-		return ret;
+		goto put_device;
 	}
 	hdmi->sys_regmap = regmap;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	hdmi->regs = devm_ioremap_resource(dev, mem);
-	if (IS_ERR(hdmi->regs))
-		return PTR_ERR(hdmi->regs);
+	if (IS_ERR(hdmi->regs)) {
+		ret = PTR_ERR(hdmi->regs);
+		goto put_device;
+	}
 
 	remote = of_graph_get_remote_node(np, 1, 0);
-	if (!remote)
-		return -EINVAL;
+	if (!remote) {
+		ret = -EINVAL;
+		goto put_device;
+	}
 
 	if (!of_device_is_compatible(remote, "hdmi-connector")) {
 		hdmi->next_bridge = of_drm_find_bridge(remote);
 		if (!hdmi->next_bridge) {
 			dev_err(dev, "Waiting for external bridge\n");
 			of_node_put(remote);
-			return -EPROBE_DEFER;
+			ret = -EPROBE_DEFER;
+			goto put_device;
 		}
 	}
 
@@ -1509,7 +1516,8 @@
 		dev_err(dev, "Failed to find ddc-i2c-bus node in %pOF\n",
 			remote);
 		of_node_put(remote);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto put_device;
 	}
 	of_node_put(remote);
 
@@ -1517,10 +1525,14 @@
 	of_node_put(i2c_np);
 	if (!hdmi->ddc_adpt) {
 		dev_err(dev, "Failed to get ddc i2c adapter by node\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto put_device;
 	}
 
 	return 0;
+put_device:
+	put_device(hdmi->cec_dev);
+	return ret;
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
@@ -84,8 +84,9 @@
 	    hdmi_phy->conf->hdmi_phy_disable_tmds)
 		return &mtk_hdmi_phy_dev_ops;
 
-	dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
-		return NULL;
+	if (hdmi_phy)
+		dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
+	return NULL;
 }
 
 static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_drv.c
@@ -124,8 +124,11 @@
 	for_each_endpoint_of_node(dev->of_node, ep) {
 		/* If the endpoint node exists, consider it enabled */
 		remote = of_graph_get_remote_port(ep);
-		if (remote)
+		if (remote) {
+			of_node_put(remote);
+			of_node_put(ep);
 			return true;
+		}
 	}
 
 	return false;
@@ -420,6 +423,17 @@
 	return count;
 }
 
+static void meson_drv_shutdown(struct platform_device *pdev)
+{
+	struct meson_drm *priv = dev_get_drvdata(&pdev->dev);
+
+	if (!priv)
+		return;
+
+	drm_kms_helper_poll_fini(priv->drm);
+	drm_atomic_helper_shutdown(priv->drm);
+}
+
 static int meson_drv_probe(struct platform_device *pdev)
 {
 	struct component_match *match = NULL;
@@ -469,6 +483,7 @@
 
 static struct platform_driver meson_drm_platform_driver = {
 	.probe      = meson_drv_probe,
+	.shutdown   = meson_drv_shutdown,
 	.driver     = {
 		.name	= "meson-drm",
 		.of_match_table = dt_match,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_plane.c
@@ -128,7 +128,7 @@
 
 	/* Enable OSD and BLK0, set max global alpha */
 	priv->viu.osd1_ctrl_stat = OSD_ENABLE |
-				   (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
+				   (0x100 << OSD_GLOBAL_ALPHA_SHIFT) |
 				   OSD_BLK0_ENABLE;
 
 	canvas_id_osd1 = priv->canvas_id_osd1;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_registers.h
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_registers.h
@@ -590,6 +590,11 @@
 #define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc
 #define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd
 
+/* osd1 HDR */
+#define OSD1_HDR2_CTRL 0x38a0
+#define OSD1_HDR2_CTRL_VDIN0_HDR2_TOP_EN       BIT(13)
+#define OSD1_HDR2_CTRL_REG_ONLY_MAT            BIT(16)
+
 /* osd2 scaler */
 #define OSD2_VSC_PHASE_STEP 0x3d00
 #define OSD2_VSC_INI_PHASE 0x3d01
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_vclk.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_vclk.c
@@ -638,13 +638,18 @@
 		if (frac >= HDMI_FRAC_MAX_GXBB)
 			return false;
 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
-		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL) ||
-		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 		/* Empiric supported min/max dividers */
 		if (m < 106 || m > 247)
 			return false;
 		if (frac >= HDMI_FRAC_MAX_GXL)
 			return false;
+	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+		/* Empiric supported min/max dividers */
+		if (m < 106 || m > 247)
+			return false;
+		if (frac >= HDMI_FRAC_MAX_G12A)
+			return false;
 	}
 
 	return true;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -64,6 +64,25 @@
 	},
 };
 
+static const struct meson_cvbs_mode *
+meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
+{
+	int i;
+
+	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
+		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
+
+		if (drm_mode_match(req_mode, &meson_mode->mode,
+				   DRM_MODE_MATCH_TIMINGS |
+				   DRM_MODE_MATCH_CLOCK |
+				   DRM_MODE_MATCH_FLAGS |
+				   DRM_MODE_MATCH_3D_FLAGS))
+			return meson_mode;
+	}
+
+	return NULL;
+}
+
 /* Connector */
 
 static void meson_cvbs_connector_destroy(struct drm_connector *connector)
@@ -136,14 +155,8 @@
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
 {
-	int i;
-
-	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
-		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
-
-		if (drm_mode_equal(&crtc_state->mode, &meson_mode->mode))
-			return 0;
-	}
+	if (meson_cvbs_get_mode(&crtc_state->mode))
+		return 0;
 
 	return -EINVAL;
 }
@@ -191,24 +204,17 @@
 				   struct drm_display_mode *mode,
 				   struct drm_display_mode *adjusted_mode)
 {
+	const struct meson_cvbs_mode *meson_mode = meson_cvbs_get_mode(mode);
 	struct meson_venc_cvbs *meson_venc_cvbs =
 					encoder_to_meson_venc_cvbs(encoder);
 	struct meson_drm *priv = meson_venc_cvbs->priv;
-	int i;
 
-	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
-		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
+	if (meson_mode) {
+		meson_venci_cvbs_mode_set(priv, meson_mode->enci);
 
-		if (drm_mode_equal(mode, &meson_mode->mode)) {
-			meson_venci_cvbs_mode_set(priv,
-						  meson_mode->enci);
-
-			/* Setup 27MHz vclk2 for ENCI and VDAC */
-			meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
-					 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
-					 MESON_VCLK_CVBS, true);
-			break;
-		}
+		/* Setup 27MHz vclk2 for ENCI and VDAC */
+		meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS,
+				 MESON_VCLK_CVBS, MESON_VCLK_CVBS, true);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_viu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_viu.c
@@ -91,7 +91,7 @@
 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
 	writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
-	writel((m[11] & 0x1fff) << 16,
+	writel((m[11] & 0x1fff),
 		priv->io_base +	_REG(VPP_WRAP_OSD1_MATRIX_COEF22));
 
 	writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
@@ -356,9 +356,14 @@
 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 	    meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
 		meson_viu_load_matrix(priv);
-	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
 		meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
 					       true);
+		/* fix green/pink color distortion from vendor u-boot */
+		writel_bits_relaxed(OSD1_HDR2_CTRL_REG_ONLY_MAT |
+				OSD1_HDR2_CTRL_VDIN0_HDR2_TOP_EN, 0,
+				priv->io_base + _REG(OSD1_HDR2_CTRL));
+	}
 
 	/* Initialize OSD1 fifo control register */
 	reg = VIU_OSD_DDR_PRIORITY_URGENT |
@@ -395,17 +400,17 @@
 			priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
 
 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
-		writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) |
-			       VIU_OSD_BLEND_REORDER(1, 0) |
-			       VIU_OSD_BLEND_REORDER(2, 0) |
-			       VIU_OSD_BLEND_REORDER(3, 0) |
-			       VIU_OSD_BLEND_DIN_EN(1) |
-			       VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 |
-			       VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 |
-			       VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 |
-			       VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) |
-			       VIU_OSD_BLEND_HOLD_LINES(4),
-			       priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
+		u32 val = (u32)VIU_OSD_BLEND_REORDER(0, 1) |
+			  (u32)VIU_OSD_BLEND_REORDER(1, 0) |
+			  (u32)VIU_OSD_BLEND_REORDER(2, 0) |
+			  (u32)VIU_OSD_BLEND_REORDER(3, 0) |
+			  (u32)VIU_OSD_BLEND_DIN_EN(1) |
+			  (u32)VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 |
+			  (u32)VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 |
+			  (u32)VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 |
+			  (u32)VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) |
+			  (u32)VIU_OSD_BLEND_HOLD_LINES(4);
+		writel_relaxed(val, priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
 
 		writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE,
 			       priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
--- linux-ein-5.4.0.orig/drivers/gpu/drm/meson/meson_vpp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/meson/meson_vpp.c
@@ -100,6 +100,8 @@
 			       priv->io_base + _REG(VPP_DOLBY_CTRL));
 		writel_relaxed(0x1020080,
 				priv->io_base + _REG(VPP_DUMMY_DATA1));
+		writel_relaxed(0x42020,
+				priv->io_base + _REG(VPP_DUMMY_DATA));
 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
 		writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL));
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -30,7 +30,8 @@
 static struct drm_driver driver;
 
 static const struct pci_device_id pciidlist[] = {
-	{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A },
+	{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD},
 	{ PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
 	{ PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV },
 	{ PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB },
@@ -63,6 +64,35 @@
 	DRM_VRAM_MM_FILE_OPERATIONS
 };
 
+static bool mgag200_pin_bo_at_0(const struct mga_device *mdev)
+{
+	return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD;
+}
+
+int mgag200_driver_dumb_create(struct drm_file *file,
+			       struct drm_device *dev,
+			       struct drm_mode_create_dumb *args)
+{
+	struct mga_device *mdev = dev->dev_private;
+	unsigned long pg_align;
+
+	if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
+		return -EINVAL;
+
+	pg_align = 0ul;
+
+	/*
+	 * Aligning scanout buffers to the size of the video ram forces
+	 * placement at offset 0. Works around a bug where HW does not
+	 * respect 'startadd' field.
+	 */
+	if (mgag200_pin_bo_at_0(mdev))
+		pg_align = PFN_UP(mdev->mc.vram_size);
+
+	return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev,
+					     pg_align, false, args);
+}
+
 static struct drm_driver driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET,
 	.load = mgag200_driver_load,
@@ -74,7 +104,9 @@
 	.major = DRIVER_MAJOR,
 	.minor = DRIVER_MINOR,
 	.patchlevel = DRIVER_PATCHLEVEL,
-	DRM_GEM_VRAM_DRIVER
+	.dumb_create = mgag200_driver_dumb_create,
+	.dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset,
+	.gem_prime_mmap = drm_gem_prime_mmap,
 };
 
 static struct pci_driver mgag200_pci_driver = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -159,6 +159,12 @@
 	G200_EW3,
 };
 
+/* HW does not handle 'startadd' field correct. */
+#define MGAG200_FLAG_HW_BUG_NO_STARTADD	(1ul << 8)
+
+#define MGAG200_TYPE_MASK	(0x000000ff)
+#define MGAG200_FLAG_MASK	(0x00ffff00)
+
 #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
 
 struct mga_device {
@@ -188,6 +194,18 @@
 	u32 unique_rev_id;
 };
 
+static inline enum mga_type
+mgag200_type_from_driver_data(kernel_ulong_t driver_data)
+{
+	return (enum mga_type)(driver_data & MGAG200_TYPE_MASK);
+}
+
+static inline unsigned long
+mgag200_flags_from_driver_data(kernel_ulong_t driver_data)
+{
+	return driver_data & MGAG200_FLAG_MASK;
+}
+
 				/* mgag200_mode.c */
 int mgag200_modeset_init(struct mga_device *mdev);
 void mgag200_modeset_fini(struct mga_device *mdev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mgag200/mgag200_main.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -94,7 +94,8 @@
 	struct mga_device *mdev = dev->dev_private;
 	int ret, option;
 
-	mdev->type = flags;
+	mdev->flags = mgag200_flags_from_driver_data(flags);
+	mdev->type = mgag200_type_from_driver_data(flags);
 
 	/* Hardcode the number of CRTCs to 1 */
 	mdev->num_crtc = 1;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
@@ -164,6 +164,11 @@
 	if (ret)
 		return ret;
 
+	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
+		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
 	/* NOTE: PM4/micro-engine firmware registers look to be the same
 	 * for a2xx and a3xx.. we could possibly push that part down to
 	 * adreno_gpu base class.  Or push both PM4 and PFP but
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -215,6 +215,16 @@
 	if (ret)
 		return ret;
 
+	/*
+	 * Use the default ringbuffer size and block size but disable the RPTR
+	 * shadow
+	 */
+	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
+		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+	/* Set the ringbuffer address */
+	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
 	/* setup access protection: */
 	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -265,6 +265,16 @@
 	if (ret)
 		return ret;
 
+	/*
+	 * Use the default ringbuffer size and block size but disable the RPTR
+	 * shadow
+	 */
+	gpu_write(gpu, REG_A4XX_CP_RB_CNTL,
+		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+	/* Set the ringbuffer address */
+	gpu_write(gpu, REG_A4XX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
 	/* Load PM4: */
 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
 	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -71,7 +71,7 @@
 			 * since we've already mapped it once in
 			 * submit_reloc()
 			 */
-			if (WARN_ON(!ptr))
+			if (WARN_ON(IS_ERR_OR_NULL(ptr)))
 				return;
 
 			for (i = 0; i < dwords; i++) {
@@ -135,8 +135,8 @@
 	OUT_RING(ring, 1);
 
 	/* Enable local preemption for finegrain preemption */
-	OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
-	OUT_RING(ring, 0x02);
+	OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1);
+	OUT_RING(ring, 0x1);
 
 	/* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */
 	OUT_PKT7(ring, CP_YIELD_ENABLE, 1);
@@ -581,8 +581,6 @@
 	if (adreno_gpu->info->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI)
 		gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8));
 
-	gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0xc0200100);
-
 	/* Enable USE_RETENTION_FLOPS */
 	gpu_write(gpu, REG_A5XX_CP_CHICKEN_DBG, 0x02000000);
 
@@ -677,14 +675,21 @@
 	if (ret)
 		return ret;
 
-	a5xx_preempt_hw_init(gpu);
-
 	a5xx_gpmu_ucode_init(gpu);
 
 	ret = a5xx_ucode_init(gpu);
 	if (ret)
 		return ret;
 
+	/* Set the ringbuffer address */
+	gpu_write64(gpu, REG_A5XX_CP_RB_BASE, REG_A5XX_CP_RB_BASE_HI,
+		gpu->rb[0]->iova);
+
+	gpu_write(gpu, REG_A5XX_CP_RB_CNTL,
+		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+	a5xx_preempt_hw_init(gpu);
+
 	/* Disable the interrupts through the initial bringup stage */
 	gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK, A5XX_INT_MASK);
 
@@ -726,11 +731,18 @@
 		gpu->funcs->flush(gpu, gpu->rb[0]);
 		if (!a5xx_idle(gpu, gpu->rb[0]))
 			return -EINVAL;
-	} else {
-		/* Print a warning so if we die, we know why */
+	} else if (ret == -ENODEV) {
+		/*
+		 * This device does not use zap shader (but print a warning
+		 * just in case someone got their dt wrong.. hopefully they
+		 * have a debug UART to realize the error of their ways...
+		 * if you mess this up you are about to crash horribly)
+		 */
 		dev_warn_once(gpu->dev->dev,
 			"Zap shader not enabled - using SECVID_TRUST_CNTL instead\n");
 		gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
+	} else {
+		return ret;
 	}
 
 	/* Last step - yield the ringbuffer */
@@ -1119,8 +1131,8 @@
 
 static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
 {
-	*value = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_CP_0_LO,
-		REG_A5XX_RBBM_PERFCTR_CP_0_HI);
+	*value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO,
+		REG_A5XX_RBBM_ALWAYSON_COUNTER_HI);
 
 	return 0;
 }
@@ -1352,6 +1364,10 @@
 {
 	u64 busy_cycles, busy_time;
 
+	/* Only read the gpu busy if the hardware is already active */
+	if (pm_runtime_get_if_in_use(&gpu->pdev->dev) == 0)
+		return 0;
+
 	busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
 			REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
 
@@ -1360,6 +1376,8 @@
 
 	gpu->devfreq.busy_cycles = busy_cycles;
 
+	pm_runtime_put(&gpu->pdev->dev);
+
 	if (WARN_ON(busy_time > ~0LU))
 		return ~0LU;
 
@@ -1394,18 +1412,31 @@
 static void check_speed_bin(struct device *dev)
 {
 	struct nvmem_cell *cell;
-	u32 bin, val;
+	u32 val;
+
+	/*
+	 * If the OPP table specifies a opp-supported-hw property then we have
+	 * to set something with dev_pm_opp_set_supported_hw() or the table
+	 * doesn't get populated so pick an arbitrary value that should
+	 * ensure the default frequencies are selected but not conflict with any
+	 * actual bins
+	 */
+	val = 0x80;
 
 	cell = nvmem_cell_get(dev, "speed_bin");
 
-	/* If a nvmem cell isn't defined, nothing to do */
-	if (IS_ERR(cell))
-		return;
+	if (!IS_ERR(cell)) {
+		void *buf = nvmem_cell_read(cell, NULL);
 
-	bin = *((u32 *) nvmem_cell_read(cell, NULL));
-	nvmem_cell_put(cell);
+		if (!IS_ERR(buf)) {
+			u8 bin = *((u8 *) buf);
 
-	val = (1 << bin);
+			val = (1 << bin);
+			kfree(buf);
+		}
+
+		nvmem_cell_put(cell);
+	}
 
 	dev_pm_opp_set_supported_hw(dev, &val, 1);
 }
@@ -1438,7 +1469,8 @@
 
 	check_speed_bin(&pdev->dev);
 
-	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4);
+	/* Restricting nr_rings to 1 to temporarily disable preemption */
+	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
 	if (ret) {
 		a5xx_destroy(&(a5xx_gpu->base.base));
 		return ERR_PTR(ret);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a5xx_power.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a5xx_power.c
@@ -300,7 +300,7 @@
 	/* Set up the limits management */
 	if (adreno_is_a530(adreno_gpu))
 		a530_lm_setup(gpu);
-	else
+	else if (adreno_is_a540(adreno_gpu))
 		a540_lm_setup(gpu);
 
 	/* Set up SP/TP power collpase */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -107,6 +107,13 @@
 	struct msm_gpu *gpu = &adreno_gpu->base;
 	int ret;
 
+	/*
+	 * This can get called from devfreq while the hardware is idle. Don't
+	 * bring up the power if it isn't already active
+	 */
+	if (pm_runtime_get_if_in_use(gmu->dev) == 0)
+		return;
+
 	gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0);
 
 	gmu_write(gmu, REG_A6XX_GMU_DCVS_PERF_SETTING,
@@ -133,6 +140,7 @@
 	 * for now leave it at max so that the performance is nominal.
 	 */
 	icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
+	pm_runtime_put(gmu->dev);
 }
 
 void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq)
@@ -191,12 +199,22 @@
 {
 	int ret;
 	u32 val;
+	u32 mask, reset_val;
+
+	val = gmu_read(gmu, REG_A6XX_GMU_CM3_DTCM_START + 0xff8);
+	if (val <= 0x20010004) {
+		mask = 0xffffffff;
+		reset_val = 0xbabeface;
+	} else {
+		mask = 0x1ff;
+		reset_val = 0x100;
+	}
 
 	gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
 	gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0);
 
 	ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val,
-		val == 0xbabeface, 100, 10000);
+		(val & mask) == reset_val, 100, 10000);
 
 	if (ret)
 		DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
@@ -705,10 +723,19 @@
 	/* Turn on the resources */
 	pm_runtime_get_sync(gmu->dev);
 
+	/*
+	 * "enable" the GX power domain which won't actually do anything but it
+	 * will make sure that the refcounting is correct in case we need to
+	 * bring down the GX after a GMU failure
+	 */
+	if (!IS_ERR_OR_NULL(gmu->gxpd))
+		pm_runtime_get_sync(gmu->gxpd);
+
 	/* Use a known rate to bring up the GMU */
 	clk_set_rate(gmu->core_clk, 200000000);
 	ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks);
 	if (ret) {
+		pm_runtime_put(gmu->gxpd);
 		pm_runtime_put(gmu->dev);
 		return ret;
 	}
@@ -744,19 +771,12 @@
 	/* Set the GPU to the highest power frequency */
 	__a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
 
-	/*
-	 * "enable" the GX power domain which won't actually do anything but it
-	 * will make sure that the refcounting is correct in case we need to
-	 * bring down the GX after a GMU failure
-	 */
-	if (!IS_ERR_OR_NULL(gmu->gxpd))
-		pm_runtime_get(gmu->gxpd);
-
 out:
 	/* On failure, shut down the GMU to leave it in a good state */
 	if (ret) {
 		disable_irq(gmu->gmu_irq);
 		a6xx_rpmh_stop(gmu);
+		pm_runtime_put(gmu->gxpd);
 		pm_runtime_put(gmu->dev);
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -512,6 +512,13 @@
 	if (ret)
 		goto out;
 
+	/* Set the ringbuffer address */
+	gpu_write64(gpu, REG_A6XX_CP_RB_BASE, REG_A6XX_CP_RB_BASE_HI,
+		gpu->rb[0]->iova);
+
+	gpu_write(gpu, REG_A6XX_CP_RB_CNTL,
+		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
 	/* Always come up on rb 0 */
 	a6xx_gpu->cur_ring = gpu->rb[0];
 
@@ -537,12 +544,19 @@
 		a6xx_flush(gpu, gpu->rb[0]);
 		if (!a6xx_idle(gpu, gpu->rb[0]))
 			return -EINVAL;
-	} else {
-		/* Print a warning so if we die, we know why */
+	} else if (ret == -ENODEV) {
+		/*
+		 * This device does not use zap shader (but print a warning
+		 * just in case someone got their dt wrong.. hopefully they
+		 * have a debug UART to realize the error of their ways...
+		 * if you mess this up you are about to crash horribly)
+		 */
 		dev_warn_once(gpu->dev->dev,
 			"Zap shader not enabled - using SECVID_TRUST_CNTL instead\n");
 		gpu_write(gpu, REG_A6XX_RBBM_SECVID_TRUST_CNTL, 0x0);
 		ret = 0;
+	} else {
+		return ret;
 	}
 
 out:
@@ -759,8 +773,8 @@
 	/* Force the GPU power on so we can read this register */
 	a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
 
-	*value = gpu_read64(gpu, REG_A6XX_RBBM_PERFCTR_CP_0_LO,
-		REG_A6XX_RBBM_PERFCTR_CP_0_HI);
+	*value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO,
+		REG_A6XX_CP_ALWAYS_ON_COUNTER_HI);
 
 	a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
 	return 0;
@@ -796,6 +810,11 @@
 	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
 	u64 busy_cycles, busy_time;
 
+
+	/* Only read the gpu busy if the hardware is already active */
+	if (pm_runtime_get_if_in_use(a6xx_gpu->gmu.dev) == 0)
+		return 0;
+
 	busy_cycles = gmu_read64(&a6xx_gpu->gmu,
 			REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
 			REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H);
@@ -805,6 +824,8 @@
 
 	gpu->devfreq.busy_cycles = busy_cycles;
 
+	pm_runtime_put(a6xx_gpu->gmu.dev);
+
 	if (WARN_ON(busy_time > ~0LU))
 		return ~0LU;
 
@@ -870,6 +891,7 @@
 	BUG_ON(!node);
 
 	ret = a6xx_gmu_init(a6xx_gpu, node);
+	of_node_put(node);
 	if (ret) {
 		a6xx_destroy(&(a6xx_gpu->base.base));
 		return ERR_PTR(ret);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -352,26 +352,26 @@
 		cxdbg = ioremap(res->start, resource_size(res));
 
 	if (cxdbg) {
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLT,
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_CNTLT,
 			A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT(0xf));
 
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM,
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_CNTLM,
 			A6XX_DBGC_CFG_DBGBUS_CNTLM_ENABLE(0xf));
 
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_1, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_2, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3, 0);
 
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0,
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0,
 			0x76543210);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_1,
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1,
 			0xFEDCBA98);
 
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_1, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
-		cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+		cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3, 0);
 	}
 
 	a6xx_state->debugbus = state_kcalloc(a6xx_state,
@@ -834,7 +834,7 @@
 	int i;
 
 	a6xx_state->indexed_regs = state_kcalloc(a6xx_state, count,
-		sizeof(a6xx_state->indexed_regs));
+		sizeof(*a6xx_state->indexed_regs));
 	if (!a6xx_state->indexed_regs)
 		return;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
@@ -200,7 +200,7 @@
 	SHADER(A6XX_SP_LB_3_DATA, 0x800),
 	SHADER(A6XX_SP_LB_4_DATA, 0x800),
 	SHADER(A6XX_SP_LB_5_DATA, 0x200),
-	SHADER(A6XX_SP_CB_BINDLESS_DATA, 0x2000),
+	SHADER(A6XX_SP_CB_BINDLESS_DATA, 0x800),
 	SHADER(A6XX_SP_CB_LEGACY_DATA, 0x280),
 	SHADER(A6XX_SP_UAV_DATA, 0x80),
 	SHADER(A6XX_SP_INST_TAG, 0x80),
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -233,8 +233,11 @@
 	if (ret)
 		return NULL;
 
-	/* Make sure pm runtime is active and reset any previous errors */
-	pm_runtime_set_active(&pdev->dev);
+	/*
+	 * Now that we have firmware loaded, and are ready to begin
+	 * booting the gpu, go ahead and enable runpm:
+	 */
+	pm_runtime_enable(&pdev->dev);
 
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -350,30 +350,10 @@
 		ring->next = ring->start;
 
 		/* reset completed fence seqno: */
-		ring->memptrs->fence = ring->seqno;
+		ring->memptrs->fence = ring->fctx->completed_fence;
 		ring->memptrs->rptr = 0;
 	}
 
-	/*
-	 * Setup REG_CP_RB_CNTL.  The same value is used across targets (with
-	 * the excpetion of A430 that disables the RPTR shadow) - the cacluation
-	 * for the ringbuffer size and block size is moved to msm_gpu.h for the
-	 * pre-processor to deal with and the A430 variant is ORed in here
-	 */
-	adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL,
-		MSM_GPU_RB_CNTL_DEFAULT |
-		(adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0));
-
-	/* Setup ringbuffer address - use ringbuffer[0] for GPU init */
-	adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_BASE,
-		REG_ADRENO_CP_RB_BASE_HI, gpu->rb[0]->iova);
-
-	if (!adreno_is_a430(adreno_gpu)) {
-		adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR,
-			REG_ADRENO_CP_RB_RPTR_ADDR_HI,
-			rbmemptr(gpu->rb[0], rptr));
-	}
-
 	return 0;
 }
 
@@ -381,11 +361,8 @@
 static uint32_t get_rptr(struct adreno_gpu *adreno_gpu,
 		struct msm_ringbuffer *ring)
 {
-	if (adreno_is_a430(adreno_gpu))
-		return ring->memptrs->rptr = adreno_gpu_read(
-			adreno_gpu, REG_ADRENO_CP_RB_RPTR);
-	else
-		return ring->memptrs->rptr;
+	return ring->memptrs->rptr = adreno_gpu_read(
+		adreno_gpu, REG_ADRENO_CP_RB_RPTR);
 }
 
 struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu)
@@ -922,7 +899,6 @@
 	pm_runtime_set_autosuspend_delay(&pdev->dev,
 		adreno_gpu->info->inactive_period);
 	pm_runtime_use_autosuspend(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
 
 	return msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
 			adreno_gpu->info->name, &adreno_gpu_config);
@@ -931,11 +907,15 @@
 void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
 {
 	struct msm_gpu *gpu = &adreno_gpu->base;
+	struct msm_drm_private *priv = gpu->dev ? gpu->dev->dev_private : NULL;
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++)
 		release_firmware(adreno_gpu->fw[i]);
 
+	if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev))
+		pm_runtime_disable(&priv->gpu_pdev->dev);
+
 	icc_put(gpu->icc_path);
 
 	msm_gpu_cleanup(&adreno_gpu->base);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -47,11 +47,9 @@
 	ADRENO_FW_MAX,
 };
 
-enum adreno_quirks {
-	ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
-	ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
-	ADRENO_QUIRK_LMLOADKILL_DISABLE = 3,
-};
+#define ADRENO_QUIRK_TWO_PASS_USE_WFI		BIT(0)
+#define ADRENO_QUIRK_FAULT_DETECT_MASK		BIT(1)
+#define ADRENO_QUIRK_LMLOADKILL_DISABLE		BIT(2)
 
 struct adreno_rev {
 	uint8_t  core;
@@ -74,7 +72,7 @@
 	const char *name;
 	const char *fw[ADRENO_FW_MAX];
 	uint32_t gmem;
-	enum adreno_quirks quirks;
+	u64 quirks;
 	struct msm_gpu *(*init)(struct drm_device *dev);
 	const char *zapfw;
 	u32 inactive_period;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
@@ -15,19 +15,6 @@
 #define	DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE	412500000
 
 /**
- * enum dpu_core_perf_data_bus_id - data bus identifier
- * @DPU_CORE_PERF_DATA_BUS_ID_MNOC: DPU/MNOC data bus
- * @DPU_CORE_PERF_DATA_BUS_ID_LLCC: MNOC/LLCC data bus
- * @DPU_CORE_PERF_DATA_BUS_ID_EBI: LLCC/EBI data bus
- */
-enum dpu_core_perf_data_bus_id {
-	DPU_CORE_PERF_DATA_BUS_ID_MNOC,
-	DPU_CORE_PERF_DATA_BUS_ID_LLCC,
-	DPU_CORE_PERF_DATA_BUS_ID_EBI,
-	DPU_CORE_PERF_DATA_BUS_ID_MAX,
-};
-
-/**
  * struct dpu_core_perf_params - definition of performance parameters
  * @max_per_pipe_ib: maximum instantaneous bandwidth request
  * @bw_ctl: arbitrated bandwidth request
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -381,7 +381,7 @@
 	spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags);
 
 	if (!fevent) {
-		DRM_ERROR("crtc%d event %d overflow\n", crtc->base.id, event);
+		DRM_ERROR_RATELIMITED("crtc%d event %d overflow\n", crtc->base.id, event);
 		return;
 	}
 
@@ -651,7 +651,10 @@
 	if (crtc->state)
 		dpu_crtc_destroy_state(crtc, crtc->state);
 
-	__drm_atomic_helper_crtc_reset(crtc, &cstate->base);
+	if (cstate)
+		__drm_atomic_helper_crtc_reset(crtc, &cstate->base);
+	else
+		__drm_atomic_helper_crtc_reset(crtc, NULL);
 }
 
 /**
@@ -819,7 +822,7 @@
 	struct drm_plane *plane;
 	struct drm_display_mode *mode;
 
-	int cnt = 0, rc = 0, mixer_width, i, z_pos;
+	int cnt = 0, rc = 0, mixer_width = 0, i, z_pos;
 
 	struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2];
 	int multirect_count = 0;
@@ -833,6 +836,8 @@
 	}
 
 	pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL);
+	if (!pstates)
+		return -ENOMEM;
 
 	dpu_crtc = to_dpu_crtc(crtc);
 	cstate = to_dpu_crtc_state(state);
@@ -852,9 +857,11 @@
 
 	memset(pipe_staged, 0, sizeof(pipe_staged));
 
-	mixer_width = mode->hdisplay / cstate->num_mixers;
+	if (cstate->num_mixers) {
+		mixer_width = mode->hdisplay / cstate->num_mixers;
 
-	_dpu_crtc_setup_lm_bounds(crtc, state);
+		_dpu_crtc_setup_lm_bounds(crtc, state);
+	}
 
 	crtc_rect.x2 = mode->hdisplay;
 	crtc_rect.y2 = mode->vdisplay;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -44,6 +44,9 @@
 		(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
 		##__VA_ARGS__)
 
+#define DPU_ERROR_ENC_RATELIMITED(e, fmt, ...) DPU_ERROR_RATELIMITED("enc%d " fmt,\
+		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
+
 /*
  * Two to anticipate panels that can do cmd/vid dynamic switching
  * plan is to create all possible physical encoder types, and switch between
@@ -2151,7 +2154,7 @@
 		return;
 	}
 
-	DPU_ERROR_ENC(dpu_enc, "frame done timeout\n");
+	DPU_ERROR_ENC_RATELIMITED(dpu_enc, "frame done timeout\n");
 
 	event = DPU_ENCODER_FRAME_EVENT_ERROR;
 	trace_dpu_enc_frame_done_timeout(DRMID(drm_enc), event);
@@ -2185,7 +2188,6 @@
 
 	dpu_enc = to_dpu_encoder_virt(enc);
 
-	mutex_init(&dpu_enc->enc_lock);
 	ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info);
 	if (ret)
 		goto fail;
@@ -2200,7 +2202,6 @@
 				0);
 
 
-	mutex_init(&dpu_enc->rc_lock);
 	INIT_DELAYED_WORK(&dpu_enc->delayed_off_work,
 			dpu_encoder_off_work);
 	dpu_enc->idle_timeout = IDLE_TIMEOUT;
@@ -2232,7 +2233,7 @@
 
 	dpu_enc = devm_kzalloc(dev->dev, sizeof(*dpu_enc), GFP_KERNEL);
 	if (!dpu_enc)
-		return ERR_PTR(ENOMEM);
+		return ERR_PTR(-ENOMEM);
 
 	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
 			drm_enc_mode, NULL);
@@ -2245,6 +2246,8 @@
 
 	spin_lock_init(&dpu_enc->enc_spinlock);
 	dpu_enc->enabled = false;
+	mutex_init(&dpu_enc->enc_lock);
+	mutex_init(&dpu_enc->rc_lock);
 
 	return &dpu_enc->base;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c
@@ -255,13 +255,13 @@
 
 	INTERLEAVED_RGB_FMT(RGB565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
-		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
 		false, 2, 0,
 		DPU_FETCH_LINEAR, 1),
 
 	INTERLEAVED_RGB_FMT(BGR565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
-		C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
 		false, 2, 0,
 		DPU_FETCH_LINEAR, 1),
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -281,10 +281,12 @@
 	int i;
 
 	for (i = 0; i < ctx->mixer_count; i++) {
-		DPU_REG_WRITE(c, CTL_LAYER(LM_0 + i), 0);
-		DPU_REG_WRITE(c, CTL_LAYER_EXT(LM_0 + i), 0);
-		DPU_REG_WRITE(c, CTL_LAYER_EXT2(LM_0 + i), 0);
-		DPU_REG_WRITE(c, CTL_LAYER_EXT3(LM_0 + i), 0);
+		enum dpu_lm mixer_id = ctx->mixer_hw_caps[i].id;
+
+		DPU_REG_WRITE(c, CTL_LAYER(mixer_id), 0);
+		DPU_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0);
+		DPU_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0);
+		DPU_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
@@ -137,11 +137,13 @@
 		u32 *idx)
 {
 	int rc = 0;
-	const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk;
+	const struct dpu_sspp_sub_blks *sblk;
 
-	if (!ctx)
+	if (!ctx || !ctx->cap || !ctx->cap->sblk)
 		return -EINVAL;
 
+	sblk = ctx->cap->sblk;
+
 	switch (s_id) {
 	case DPU_SSPP_SRC:
 		*idx = sblk->src_blk.base;
@@ -404,7 +406,7 @@
 
 	(void)pe;
 	if (_sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx) || !sspp
-		|| !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk)
+		|| !scaler3_cfg)
 		return;
 
 	dpu_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -88,8 +88,8 @@
 					&status);
 	} else {
 		seq_puts(s, "\nSafe signal status:\n");
-		if (kms->hw_mdp->ops.get_danger_status)
-			kms->hw_mdp->ops.get_danger_status(kms->hw_mdp,
+		if (kms->hw_mdp->ops.get_safe_status)
+			kms->hw_mdp->ops.get_safe_status(kms->hw_mdp,
 					&status);
 	}
 	pm_runtime_put_sync(&kms->pdev->dev);
@@ -596,11 +596,11 @@
 	_dpu_kms_mmu_destroy(dpu_kms);
 
 	if (dpu_kms->catalog) {
-		for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {
-			u32 vbif_idx = dpu_kms->catalog->vbif[i].id;
-
-			if ((vbif_idx < VBIF_MAX) && dpu_kms->hw_vbif[vbif_idx])
-				dpu_hw_vbif_destroy(dpu_kms->hw_vbif[vbif_idx]);
+		for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
+			if (dpu_kms->hw_vbif[i]) {
+				dpu_hw_vbif_destroy(dpu_kms->hw_vbif[i]);
+				dpu_kms->hw_vbif[i] = NULL;
+			}
 		}
 	}
 
@@ -897,7 +897,7 @@
 	for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {
 		u32 vbif_idx = dpu_kms->catalog->vbif[i].id;
 
-		dpu_kms->hw_vbif[i] = dpu_hw_vbif_init(vbif_idx,
+		dpu_kms->hw_vbif[vbif_idx] = dpu_hw_vbif_init(vbif_idx,
 				dpu_kms->vbif[vbif_idx], dpu_kms->catalog);
 		if (IS_ERR_OR_NULL(dpu_kms->hw_vbif[vbif_idx])) {
 			rc = PTR_ERR(dpu_kms->hw_vbif[vbif_idx]);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -50,6 +50,7 @@
 	} while (0)
 
 #define DPU_ERROR(fmt, ...) pr_err("[dpu error]" fmt, ##__VA_ARGS__)
+#define DPU_ERROR_RATELIMITED(fmt, ...) pr_err_ratelimited("[dpu error]" fmt, ##__VA_ARGS__)
 
 /**
  * ktime_compare_safe - compare two ktime structures
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -853,9 +853,9 @@
 		crtc_state = drm_atomic_get_new_crtc_state(state->state,
 							   state->crtc);
 
-	min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxdwnscale);
+	min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxupscale);
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale,
-					  pdpu->pipe_sblk->maxupscale << 16,
+					  pdpu->pipe_sblk->maxdwnscale << 16,
 					  true, true);
 	if (ret) {
 		DPU_ERROR_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
@@ -11,6 +11,14 @@
 #include "dpu_hw_vbif.h"
 #include "dpu_trace.h"
 
+static struct dpu_hw_vbif *dpu_get_vbif(struct dpu_kms *dpu_kms, enum dpu_vbif vbif_idx)
+{
+	if (vbif_idx < ARRAY_SIZE(dpu_kms->hw_vbif))
+		return dpu_kms->hw_vbif[vbif_idx];
+
+	return NULL;
+}
+
 /**
  * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt
  * @vbif:	Pointer to hardware vbif driver
@@ -148,11 +156,11 @@
 void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms,
 		struct dpu_vbif_set_ot_params *params)
 {
-	struct dpu_hw_vbif *vbif = NULL;
+	struct dpu_hw_vbif *vbif;
 	struct dpu_hw_mdp *mdp;
 	bool forced_on = false;
 	u32 ot_lim;
-	int ret, i;
+	int ret;
 
 	if (!dpu_kms) {
 		DPU_ERROR("invalid arguments\n");
@@ -160,12 +168,7 @@
 	}
 	mdp = dpu_kms->hw_mdp;
 
-	for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
-		if (dpu_kms->hw_vbif[i] &&
-				dpu_kms->hw_vbif[i]->idx == params->vbif_idx)
-			vbif = dpu_kms->hw_vbif[i];
-	}
-
+	vbif = dpu_get_vbif(dpu_kms, params->vbif_idx);
 	if (!vbif || !mdp) {
 		DPU_DEBUG("invalid arguments vbif %d mdp %d\n",
 				vbif != 0, mdp != 0);
@@ -208,7 +211,7 @@
 void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms,
 		struct dpu_vbif_set_qos_params *params)
 {
-	struct dpu_hw_vbif *vbif = NULL;
+	struct dpu_hw_vbif *vbif;
 	struct dpu_hw_mdp *mdp;
 	bool forced_on = false;
 	const struct dpu_vbif_qos_tbl *qos_tbl;
@@ -220,13 +223,7 @@
 	}
 	mdp = dpu_kms->hw_mdp;
 
-	for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
-		if (dpu_kms->hw_vbif[i] &&
-				dpu_kms->hw_vbif[i]->idx == params->vbif_idx) {
-			vbif = dpu_kms->hw_vbif[i];
-			break;
-		}
-	}
+	vbif = dpu_get_vbif(dpu_kms, params->vbif_idx);
 
 	if (!vbif || !vbif->cap) {
 		DPU_ERROR("invalid vbif %d\n", params->vbif_idx);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
@@ -268,6 +268,7 @@
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	unsigned long flags;
 
 	DBG("%s", mdp4_crtc->name);
 
@@ -280,6 +281,14 @@
 	mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
 	mdp4_disable(mdp4_kms);
 
+	if (crtc->state->event && !crtc->state->active) {
+		WARN_ON(mdp4_crtc->event);
+		spin_lock_irqsave(&mdp4_kms->dev->event_lock, flags);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+		spin_unlock_irqrestore(&mdp4_kms->dev->event_lock, flags);
+	}
+
 	mdp4_crtc->enabled = false;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
@@ -121,7 +121,7 @@
 	if (mdp4_dsi_encoder->enabled)
 		return;
 
-	 mdp4_crtc_set_config(encoder->crtc,
+	mdp4_crtc_set_config(encoder->crtc,
 			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
 			MDP4_DMA_CONFIG_DEFLKR_EN |
 			MDP4_DMA_CONFIG_DITHER_EN |
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -88,8 +88,6 @@
 	if (mdp4_kms->rev > 1)
 		mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1);
 
-	dev->mode_config.allow_fb_modifiers = true;
-
 out:
 	pm_runtime_put_sync(dev->dev);
 
@@ -110,13 +108,6 @@
 
 static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
 {
-	int i;
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-
-	/* see 119ecb7fd */
-	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
-		drm_crtc_vblank_get(crtc);
 }
 
 static void mdp4_flush_commit(struct msm_kms *kms, unsigned crtc_mask)
@@ -135,12 +126,6 @@
 
 static void mdp4_complete_commit(struct msm_kms *kms, unsigned crtc_mask)
 {
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	struct drm_crtc *crtc;
-
-	/* see 119ecb7fd */
-	for_each_crtc_mask(mdp4_kms->dev, crtc, crtc_mask)
-		drm_crtc_vblank_put(crtc);
 }
 
 static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
@@ -260,6 +245,7 @@
 		encoder = mdp4_lcdc_encoder_init(dev, panel_node);
 		if (IS_ERR(encoder)) {
 			DRM_DEV_ERROR(dev->dev, "failed to construct LCDC encoder\n");
+			of_node_put(panel_node);
 			return PTR_ERR(encoder);
 		}
 
@@ -269,6 +255,7 @@
 		connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
 		if (IS_ERR(connector)) {
 			DRM_DEV_ERROR(dev->dev, "failed to initialize LVDS connector\n");
+			of_node_put(panel_node);
 			return PTR_ERR(connector);
 		}
 
@@ -420,6 +407,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev->dev);
 	struct mdp4_platform_config *config = mdp4_get_config(pdev);
+	struct msm_drm_private *priv = dev->dev_private;
 	struct mdp4_kms *mdp4_kms;
 	struct msm_kms *kms = NULL;
 	struct msm_gem_address_space *aspace;
@@ -434,7 +422,8 @@
 
 	mdp_kms_init(&mdp4_kms->base, &kms_funcs);
 
-	kms = &mdp4_kms->base.base;
+	priv->kms = &mdp4_kms->base.base;
+	kms = priv->kms;
 
 	mdp4_kms->dev = dev;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
@@ -61,8 +61,9 @@
 	return ret;
 }
 
-static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
-				 struct drm_display_mode *mode)
+static enum drm_mode_status
+mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
+			       struct drm_display_mode *mode)
 {
 	struct mdp4_lvds_connector *mdp4_lvds_connector =
 			to_mdp4_lvds_connector(connector);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -347,6 +347,12 @@
 	return mdp4_plane->pipe;
 }
 
+static const uint64_t supported_format_modifiers[] = {
+	DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
 /* initialize plane */
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
 		enum mdp4_pipe pipe_id, bool private_plane)
@@ -375,7 +381,7 @@
 	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
 				 mdp4_plane->formats, mdp4_plane->nformats,
-				 NULL, type, NULL);
+				 supported_format_modifiers, type, NULL);
 	if (ret)
 		goto fail;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
@@ -41,7 +41,7 @@
 {
 	struct mdp5_kms *mdp5_kms = get_kms(encoder);
 	struct device *dev = encoder->dev->dev;
-	u32 total_lines_x100, vclks_line, cfg;
+	u32 total_lines, vclks_line, cfg;
 	long vsync_clk_speed;
 	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
 	int pp_id = mixer->pp;
@@ -51,8 +51,8 @@
 		return -EINVAL;
 	}
 
-	total_lines_x100 = mode->vtotal * drm_mode_vrefresh(mode);
-	if (!total_lines_x100) {
+	total_lines = mode->vtotal * drm_mode_vrefresh(mode);
+	if (!total_lines) {
 		DRM_DEV_ERROR(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
 			      __func__, mode->vtotal, drm_mode_vrefresh(mode));
 		return -EINVAL;
@@ -64,15 +64,23 @@
 							vsync_clk_speed);
 		return -EINVAL;
 	}
-	vclks_line = vsync_clk_speed * 100 / total_lines_x100;
+	vclks_line = vsync_clk_speed / total_lines;
 
 	cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
 		| MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
 	cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
 
+	/*
+	 * Tearcheck emits a blanking signal every vclks_line * vtotal * 2 ticks on
+	 * the vsync_clk equating to roughly half the desired panel refresh rate.
+	 * This is only necessary as stability fallback if interrupts from the
+	 * panel arrive too late or not at all, but is currently used by default
+	 * because these panel interrupts are not wired up yet.
+	 */
 	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
 	mdp5_write(mdp5_kms,
-		REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
+		REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), (2 * mode->vtotal));
+
 	mdp5_write(mdp5_kms,
 		REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
 	mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -534,9 +534,15 @@
 		if (ret)
 			return ret;
 
-		mdp5_mixer_release(new_crtc_state->state, old_mixer);
+		ret = mdp5_mixer_release(new_crtc_state->state, old_mixer);
+		if (ret)
+			return ret;
+
 		if (old_r_mixer) {
-			mdp5_mixer_release(new_crtc_state->state, old_r_mixer);
+			ret = mdp5_mixer_release(new_crtc_state->state, old_r_mixer);
+			if (ret)
+				return ret;
+
 			if (!need_right_mixer)
 				pipeline->r_mixer = NULL;
 		}
@@ -903,8 +909,10 @@
 
 	ret = msm_gem_get_and_pin_iova(cursor_bo, kms->aspace,
 			&mdp5_crtc->cursor.iova);
-	if (ret)
+	if (ret) {
+		drm_gem_object_put(cursor_bo);
 		return -EINVAL;
+	}
 
 	pm_runtime_get_sync(&pdev->dev);
 
@@ -1042,7 +1050,10 @@
 	if (crtc->state)
 		mdp5_crtc_destroy_state(crtc, crtc->state);
 
-	__drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base);
+	if (mdp5_cstate)
+		__drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base);
+	else
+		__drm_atomic_helper_crtc_reset(crtc, NULL);
 
 	drm_crtc_vblank_reset(crtc);
 }
@@ -1099,7 +1110,7 @@
 	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc,
 								pp_done);
 
-	complete(&mdp5_crtc->pp_completion);
+	complete_all(&mdp5_crtc->pp_completion);
 }
 
 static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc)
@@ -1112,8 +1123,8 @@
 	ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion,
 						msecs_to_jiffies(50));
 	if (ret == 0)
-		dev_warn(dev->dev, "pp done time out, lm=%d\n",
-			 mdp5_cstate->pipeline.mixer->lm);
+		dev_warn_ratelimited(dev->dev, "pp done time out, lm=%d\n",
+				     mdp5_cstate->pipeline.mixer->lm);
 }
 
 static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -698,9 +698,9 @@
 	pdev = mdp5_kms->pdev;
 
 	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
-	if (irq < 0) {
-		ret = irq;
-		DRM_DEV_ERROR(&pdev->dev, "failed to get irq: %d\n", ret);
+	if (!irq) {
+		ret = -EINVAL;
+		DRM_DEV_ERROR(&pdev->dev, "failed to get irq\n");
 		goto fail;
 	}
 
@@ -1037,7 +1037,8 @@
 
 	return 0;
 fail:
-	mdp5_destroy(pdev);
+	if (mdp5_kms)
+		mdp5_destroy(pdev);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
@@ -116,21 +116,28 @@
 	return 0;
 }
 
-void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
+int mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
 {
 	struct mdp5_global_state *global_state = mdp5_get_global_state(s);
-	struct mdp5_hw_mixer_state *new_state = &global_state->hwmixer;
+	struct mdp5_hw_mixer_state *new_state;
 
 	if (!mixer)
-		return;
+		return 0;
+
+	if (IS_ERR(global_state))
+		return PTR_ERR(global_state);
+
+	new_state = &global_state->hwmixer;
 
 	if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))
-		return;
+		return -EINVAL;
 
 	DBG("%s: release from crtc %s", mixer->name,
 	    new_state->hwmixer_to_crtc[mixer->idx]->name);
 
 	new_state->hwmixer_to_crtc[mixer->idx] = NULL;
+
+	return 0;
 }
 
 void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
@@ -30,7 +30,7 @@
 int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
 		      uint32_t caps, struct mdp5_hw_mixer **mixer,
 		      struct mdp5_hw_mixer **r_mixer);
-void mdp5_mixer_release(struct drm_atomic_state *s,
-			struct mdp5_hw_mixer *mixer);
+int mdp5_mixer_release(struct drm_atomic_state *s,
+		       struct mdp5_hw_mixer *mixer);
 
 #endif /* __MDP5_LM_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
@@ -119,18 +119,24 @@
 	return 0;
 }
 
-void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
+int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
 {
 	struct msm_drm_private *priv = s->dev->dev_private;
 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct mdp5_global_state *state = mdp5_get_global_state(s);
-	struct mdp5_hw_pipe_state *new_state = &state->hwpipe;
+	struct mdp5_global_state *state;
+	struct mdp5_hw_pipe_state *new_state;
 
 	if (!hwpipe)
-		return;
+		return 0;
+
+	state = mdp5_get_global_state(s);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	new_state = &state->hwpipe;
 
 	if (WARN_ON(!new_state->hwpipe_to_plane[hwpipe->idx]))
-		return;
+		return -EINVAL;
 
 	DBG("%s: release from plane %s", hwpipe->name,
 		new_state->hwpipe_to_plane[hwpipe->idx]->name);
@@ -141,6 +147,8 @@
 	}
 
 	new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
+
+	return 0;
 }
 
 void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
@@ -37,7 +37,7 @@
 		     uint32_t caps, uint32_t blkcfg,
 		     struct mdp5_hw_pipe **hwpipe,
 		     struct mdp5_hw_pipe **r_hwpipe);
-void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe);
+int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe);
 
 struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
 		uint32_t reg_offset, uint32_t caps);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -179,7 +179,10 @@
 		drm_framebuffer_put(plane->state->fb);
 
 	kfree(to_mdp5_plane_state(plane->state));
+	plane->state = NULL;
 	mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
+	if (!mdp5_state)
+		return;
 
 	/* assign default blend parameters */
 	mdp5_state->alpha = 255;
@@ -218,8 +221,7 @@
 {
 	struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
 
-	if (state->fb)
-		drm_framebuffer_put(state->fb);
+	__drm_atomic_helper_plane_destroy_state(state);
 
 	kfree(pstate);
 }
@@ -390,12 +392,24 @@
 				mdp5_state->r_hwpipe = NULL;
 
 
-			mdp5_pipe_release(state->state, old_hwpipe);
-			mdp5_pipe_release(state->state, old_right_hwpipe);
+			ret = mdp5_pipe_release(state->state, old_hwpipe);
+			if (ret)
+				return ret;
+
+			ret = mdp5_pipe_release(state->state, old_right_hwpipe);
+			if (ret)
+				return ret;
+
 		}
 	} else {
-		mdp5_pipe_release(state->state, mdp5_state->hwpipe);
-		mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
+		ret = mdp5_pipe_release(state->state, mdp5_state->hwpipe);
+		if (ret)
+			return ret;
+
+		ret = mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
+		if (ret)
+			return ret;
+
 		mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/dsi.c
@@ -26,17 +26,22 @@
 	}
 
 	phy_pdev = of_find_device_by_node(phy_node);
-	if (phy_pdev)
+	if (phy_pdev) {
 		msm_dsi->phy = platform_get_drvdata(phy_pdev);
+		msm_dsi->phy_dev = &phy_pdev->dev;
+	}
 
 	of_node_put(phy_node);
 
-	if (!phy_pdev || !msm_dsi->phy) {
+	if (!phy_pdev) {
+		DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+		return -EPROBE_DEFER;
+	}
+	if (!msm_dsi->phy) {
+		put_device(&phy_pdev->dev);
 		DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
 		return -EPROBE_DEFER;
 	}
-
-	msm_dsi->phy_dev = get_device(&phy_pdev->dev);
 
 	return 0;
 }
@@ -198,6 +203,12 @@
 		return -EINVAL;
 
 	priv = dev->dev_private;
+
+	if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
+		DRM_DEV_ERROR(dev->dev, "too many bridges\n");
+		return -ENOSPC;
+	}
+
 	msm_dsi->dev = dev;
 
 	ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
@@ -206,8 +217,10 @@
 		goto fail;
 	}
 
-	if (!msm_dsi_manager_validate_current_config(msm_dsi->id))
+	if (!msm_dsi_manager_validate_current_config(msm_dsi->id)) {
+		ret = -EINVAL;
 		goto fail;
+	}
 
 	msm_dsi->encoder = encoder;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -97,7 +97,7 @@
 static const struct msm_dsi_config msm8996_dsi_cfg = {
 	.io_offset = DSI_6G_REG_SHIFT,
 	.reg_cfg = {
-		.num = 2,
+		.num = 3,
 		.regs = {
 			{"vdda", 18160, 1 },	/* 1.25 V */
 			{"vcca", 17000, 32 },	/* 0.925 V */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -460,7 +460,7 @@
 
 	return 0;
 err:
-	for (; i > 0; i--)
+	while (--i >= 0)
 		clk_disable_unprepare(msm_host->bus_clks[i]);
 
 	return ret;
@@ -1051,9 +1051,21 @@
 
 static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host)
 {
+	u32 data;
+
 	if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
 		return;
 
+	data = dsi_read(msm_host, REG_DSI_STATUS0);
+
+	/* if video mode engine is not busy, its because
+	 * either timing engine was not turned on or the
+	 * DSI controller has finished transmitting the video
+	 * data already, so no need to wait in those cases
+	 */
+	if (!(data & DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY))
+		return;
+
 	if (msm_host->power_on && msm_host->enabled) {
 		dsi_wait4video_done(msm_host);
 		/* delay 4 ms to skip BLLP */
@@ -1348,10 +1360,10 @@
 			dsi_get_bpp(msm_host->format) / 8;
 
 	len = dsi_cmd_dma_add(msm_host, msg);
-	if (!len) {
+	if (len < 0) {
 		pr_err("%s: failed to add cmd type = 0x%x\n",
 			__func__,  msg->type);
-		return -EINVAL;
+		return len;
 	}
 
 	/* for video mode, do not send cmds more than
@@ -1370,10 +1382,14 @@
 	}
 
 	ret = dsi_cmd_dma_tx(msm_host, len);
-	if (ret < len) {
-		pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d\n",
-			__func__, msg->type, (*(u8 *)(msg->tx_buf)), len);
-		return -ECOMM;
+	if (ret < 0) {
+		pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d, ret=%d\n",
+			__func__, msg->type, (*(u8 *)(msg->tx_buf)), len, ret);
+		return ret;
+	} else if (ret < len) {
+		pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, ret=%d len=%d\n",
+			__func__, msg->type, (*(u8 *)(msg->tx_buf)), ret, len);
+		return -EIO;
 	}
 
 	return len;
@@ -1669,6 +1685,8 @@
 	if (!prop) {
 		DRM_DEV_DEBUG(dev,
 			"failed to find data lane mapping, using default\n");
+		/* Set the number of date lanes to 4 by default. */
+		msm_host->num_data_lanes = 4;
 		return 0;
 	}
 
@@ -1871,6 +1889,9 @@
 
 	/* setup workqueue */
 	msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
+	if (!msm_host->workqueue)
+		return -ENOMEM;
+
 	INIT_WORK(&msm_host->err_work, dsi_err_worker);
 	INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker);
 
@@ -2097,9 +2118,12 @@
 		}
 
 		ret = dsi_cmds2buf_tx(msm_host, msg);
-		if (ret < msg->tx_len) {
+		if (ret < 0) {
 			pr_err("%s: Read cmd Tx failed, %d\n", __func__, ret);
 			return ret;
+		} else if (ret < msg->tx_len) {
+			pr_err("%s: Read cmd Tx failed, too short: %d\n", __func__, ret);
+			return -ECOMM;
 		}
 
 		/*
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -336,7 +336,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);
@@ -479,6 +479,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;
 
@@ -519,6 +520,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);
@@ -620,7 +625,7 @@
 	return connector;
 
 fail:
-	connector->funcs->destroy(msm_dsi->connector);
+	connector->funcs->destroy(connector);
 	return ERR_PTR(ret);
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -347,7 +347,7 @@
 	} else {
 		timing->shared_timings.clk_pre =
 			linear_inter(tmax, tmin, pcnt2, 0, false);
-			timing->shared_timings.clk_pre_inc_by_2 = 0;
+		timing->shared_timings.clk_pre_inc_by_2 = 0;
 	}
 
 	timing->ta_go = 3;
@@ -464,7 +464,9 @@
 	struct device *dev = &phy->pdev->dev;
 	int ret;
 
-	pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
 
 	ret = clk_prepare_enable(phy->ahb_clk);
 	if (ret) {
@@ -604,6 +606,10 @@
 			goto fail;
 	}
 
+	ret = devm_pm_runtime_enable(&pdev->dev);
+	if (ret)
+		return ret;
+
 	/* PLL init will call into clk_register which requires
 	 * register access, so we need to enable power and ahb clock.
 	 */
@@ -665,12 +671,14 @@
 int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
 			struct msm_dsi_phy_clk_request *clk_req)
 {
-	struct device *dev = &phy->pdev->dev;
+	struct device *dev;
 	int ret;
 
 	if (!phy || !phy->cfg->ops.enable)
 		return -EINVAL;
 
+	dev = &phy->pdev->dev;
+
 	ret = dsi_phy_enable_resource(phy);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n",
@@ -724,10 +732,6 @@
 	if (!phy || !phy->cfg->ops.disable)
 		return;
 
-	/* Save PLL status if it is a clock source */
-	if (phy->usecase != MSM_DSI_PHY_SLAVE)
-		msm_dsi_pll_save_state(phy->pll);
-
 	phy->cfg->ops.disable(phy);
 
 	dsi_phy_regulator_disable(phy);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
@@ -139,7 +139,7 @@
 		.disable = dsi_20nm_phy_disable,
 		.init = msm_dsi_phy_init_common,
 	},
-	.io_start = { 0xfd998300, 0xfd9a0300 },
+	.io_start = { 0xfd998500, 0xfd9a0500 },
 	.num_dsi_phy = 2,
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
@@ -411,6 +411,12 @@
 	if (pll_10nm->slave)
 		dsi_pll_enable_pll_bias(pll_10nm->slave);
 
+	rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0);
+	if (rc) {
+		pr_err("vco_set_rate failed, rc=%d\n", rc);
+		return rc;
+	}
+
 	/* Start PLL */
 	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL,
 		  0x01);
@@ -553,6 +559,7 @@
 	struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
 	void __iomem *phy_base = pll_10nm->phy_cmn_mmio;
 	u32 val;
+	int ret;
 
 	val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
 	val &= ~0x3;
@@ -567,6 +574,13 @@
 	val |= cached->pll_mux;
 	pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val);
 
+	ret = dsi_pll_10nm_vco_set_rate(&pll->clk_hw, pll_10nm->vco_current_rate, pll_10nm->vco_ref_clk_rate);
+	if (ret) {
+		DRM_DEV_ERROR(&pll_10nm->pdev->dev,
+			"restore vco rate failed. ret=%d\n", ret);
+		return ret;
+	}
+
 	DBG("DSI PLL%d", pll_10nm->id);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/edp/edp_ctrl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/edp/edp_ctrl.c
@@ -1082,7 +1082,7 @@
 int msm_edp_ctrl_init(struct msm_edp *edp)
 {
 	struct edp_ctrl *ctrl = NULL;
-	struct device *dev = &edp->pdev->dev;
+	struct device *dev;
 	int ret;
 
 	if (!edp) {
@@ -1090,6 +1090,7 @@
 		return -EINVAL;
 	}
 
+	dev = &edp->pdev->dev;
 	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
 	if (!ctrl)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -97,10 +97,15 @@
 
 	of_node_put(phy_node);
 
-	if (!phy_pdev || !hdmi->phy) {
+	if (!phy_pdev) {
 		DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
 		return -EPROBE_DEFER;
 	}
+	if (!hdmi->phy) {
+		DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
+		put_device(&phy_pdev->dev);
+		return -EPROBE_DEFER;
+	}
 
 	hdmi->phy_dev = get_device(&phy_pdev->dev);
 
@@ -137,6 +142,10 @@
 	/* HDCP needs physical address of hdmi register */
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 		config->mmio_name);
+	if (!res) {
+		ret = -EINVAL;
+		goto fail;
+	}
 	hdmi->mmio_phy_addr = res->start;
 
 	hdmi->qfprom_mmio = msm_ioremap(pdev,
@@ -239,6 +248,10 @@
 	pm_runtime_enable(&pdev->dev);
 
 	hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
+	if (!hdmi->workq) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 
 	hdmi->i2c = msm_hdmi_i2c_init(hdmi);
 	if (IS_ERR(hdmi->i2c)) {
@@ -284,6 +297,11 @@
 	struct platform_device *pdev = hdmi->pdev;
 	int ret;
 
+	if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
+		DRM_DEV_ERROR(dev->dev, "too many bridges\n");
+		return -ENOSPC;
+	}
+
 	hdmi->dev = dev;
 	hdmi->encoder = encoder;
 
@@ -306,9 +324,9 @@
 	}
 
 	hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
-	if (hdmi->irq < 0) {
-		ret = hdmi->irq;
-		DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret);
+	if (!hdmi->irq) {
+		ret = -EINVAL;
+		DRM_DEV_ERROR(dev->dev, "failed to get irq\n");
 		goto fail;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_atomic.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_atomic.c
@@ -27,6 +27,34 @@
 	return msm_framebuffer_prepare(new_state->fb, kms->aspace);
 }
 
+/*
+ * Helpers to control vblanks while we flush.. basically just to ensure
+ * that vblank accounting is switched on, so we get valid seqn/timestamp
+ * on pageflip events (if requested)
+ */
+
+static void vblank_get(struct msm_kms *kms, unsigned crtc_mask)
+{
+	struct drm_crtc *crtc;
+
+	for_each_crtc_mask(kms->dev, crtc, crtc_mask) {
+		if (!crtc->state->active)
+			continue;
+		drm_crtc_vblank_get(crtc);
+	}
+}
+
+static void vblank_put(struct msm_kms *kms, unsigned crtc_mask)
+{
+	struct drm_crtc *crtc;
+
+	for_each_crtc_mask(kms->dev, crtc, crtc_mask) {
+		if (!crtc->state->active)
+			continue;
+		drm_crtc_vblank_put(crtc);
+	}
+}
+
 static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
 {
 	unsigned crtc_mask = BIT(crtc_idx);
@@ -44,6 +72,8 @@
 
 	kms->funcs->enable_commit(kms);
 
+	vblank_get(kms, crtc_mask);
+
 	/*
 	 * Flush hardware updates:
 	 */
@@ -58,6 +88,8 @@
 	kms->funcs->wait_flush(kms, crtc_mask);
 	trace_msm_atomic_wait_flush_finish(crtc_mask);
 
+	vblank_put(kms, crtc_mask);
+
 	mutex_lock(&kms->commit_lock);
 	kms->funcs->complete_commit(kms, crtc_mask);
 	mutex_unlock(&kms->commit_lock);
@@ -221,6 +253,8 @@
 	 */
 	kms->pending_crtc_mask &= ~crtc_mask;
 
+	vblank_get(kms, crtc_mask);
+
 	/*
 	 * Flush hardware updates:
 	 */
@@ -235,6 +269,8 @@
 	kms->funcs->wait_flush(kms, crtc_mask);
 	trace_msm_atomic_wait_flush_finish(crtc_mask);
 
+	vblank_put(kms, crtc_mask);
+
 	mutex_lock(&kms->commit_lock);
 	kms->funcs->complete_commit(kms, crtc_mask);
 	mutex_unlock(&kms->commit_lock);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_debugfs.c
@@ -47,12 +47,8 @@
 	struct msm_gpu_show_priv *show_priv = m->private;
 	struct msm_drm_private *priv = show_priv->dev->dev_private;
 	struct msm_gpu *gpu = priv->gpu;
-	int ret;
-
-	ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex);
-	if (ret)
-		return ret;
 
+	mutex_lock(&show_priv->dev->struct_mutex);
 	gpu->funcs->gpu_state_put(show_priv->state);
 	mutex_unlock(&show_priv->dev->struct_mutex);
 
@@ -81,6 +77,7 @@
 		goto free_priv;
 
 	pm_runtime_get_sync(&gpu->pdev->dev);
+	msm_gpu_hw_init(gpu);
 	show_priv->state = gpu->funcs->gpu_state_get(gpu);
 	pm_runtime_put_sync(&gpu->pdev->dev);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_drv.c
@@ -337,7 +337,7 @@
 		of_node_put(node);
 		if (ret)
 			return ret;
-		size = r.end - r.start;
+		size = r.end - r.start + 1;
 		DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
 
 		/* if we have no IOMMU, then we need to use carveout allocator.
@@ -432,14 +432,24 @@
 
 	drm_mode_config_init(ddev);
 
+	ret = msm_init_vram(ddev);
+	if (ret)
+		goto err_destroy_mdss;
+
 	/* Bind all our sub-components: */
 	ret = component_bind_all(dev, ddev);
 	if (ret)
 		goto err_destroy_mdss;
 
-	ret = msm_init_vram(ddev);
-	if (ret)
-		goto err_msm_uninit;
+	if (!dev->dma_parms) {
+		dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+					      GFP_KERNEL);
+		if (!dev->dma_parms) {
+			ret = -ENOMEM;
+			goto err_msm_uninit;
+		}
+	}
+	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
 
 	msm_gem_shrinker_init(ddev);
 
@@ -557,6 +567,7 @@
 	kfree(priv);
 err_put_drm_dev:
 	drm_dev_put(ddev);
+	platform_set_drvdata(pdev, NULL);
 	return ret;
 }
 
@@ -1313,6 +1324,17 @@
 	return 0;
 }
 
+static void msm_pdev_shutdown(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+	struct msm_drm_private *priv = drm ? drm->dev_private : NULL;
+
+	if (!priv || !priv->kms)
+		return;
+
+	drm_atomic_helper_shutdown(drm);
+}
+
 static const struct of_device_id dt_match[] = {
 	{ .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
 	{ .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
@@ -1324,6 +1346,7 @@
 static struct platform_driver msm_platform_driver = {
 	.probe      = msm_pdev_probe,
 	.remove     = msm_pdev_remove,
+	.shutdown   = msm_pdev_shutdown,
 	.driver     = {
 		.name   = "msm",
 		.of_match_table = dt_match,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_fence.c
@@ -20,7 +20,7 @@
 		return ERR_PTR(-ENOMEM);
 
 	fctx->dev = dev;
-	strncpy(fctx->name, name, sizeof(fctx->name));
+	strscpy(fctx->name, name, sizeof(fctx->name));
 	fctx->context = dma_fence_context_alloc(1);
 	init_waitqueue_head(&fctx->event);
 	spin_lock_init(&fctx->spinlock);
@@ -45,7 +45,7 @@
 	int ret;
 
 	if (fence > fctx->last_fence) {
-		DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n",
+		DRM_ERROR_RATELIMITED("%s: waiting on invalid fence: %u (of %u)\n",
 				fctx->name, fence, fctx->last_fence);
 		return -EINVAL;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_gem.c
@@ -977,10 +977,8 @@
 
 static int msm_gem_new_impl(struct drm_device *dev,
 		uint32_t size, uint32_t flags,
-		struct drm_gem_object **obj,
-		bool struct_mutex_locked)
+		struct drm_gem_object **obj)
 {
-	struct msm_drm_private *priv = dev->dev_private;
 	struct msm_gem_object *msm_obj;
 
 	switch (flags & MSM_BO_CACHE_MASK) {
@@ -1006,15 +1004,6 @@
 	INIT_LIST_HEAD(&msm_obj->submit_entry);
 	INIT_LIST_HEAD(&msm_obj->vmas);
 
-	if (struct_mutex_locked) {
-		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-		list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
-	} else {
-		mutex_lock(&dev->struct_mutex);
-		list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
-		mutex_unlock(&dev->struct_mutex);
-	}
-
 	*obj = &msm_obj->base;
 
 	return 0;
@@ -1024,6 +1013,7 @@
 		uint32_t size, uint32_t flags, bool struct_mutex_locked)
 {
 	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_gem_object *msm_obj;
 	struct drm_gem_object *obj = NULL;
 	bool use_vram = false;
 	int ret;
@@ -1044,14 +1034,15 @@
 	if (size == 0)
 		return ERR_PTR(-EINVAL);
 
-	ret = msm_gem_new_impl(dev, size, flags, &obj, struct_mutex_locked);
+	ret = msm_gem_new_impl(dev, size, flags, &obj);
 	if (ret)
-		goto fail;
+		return ERR_PTR(ret);
+
+	msm_obj = to_msm_bo(obj);
 
 	if (use_vram) {
 		struct msm_gem_vma *vma;
 		struct page **pages;
-		struct msm_gem_object *msm_obj = to_msm_bo(obj);
 
 		mutex_lock(&msm_obj->lock);
 
@@ -1086,6 +1077,15 @@
 		mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER);
 	}
 
+	if (struct_mutex_locked) {
+		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+		list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+	} else {
+		mutex_lock(&dev->struct_mutex);
+		list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+		mutex_unlock(&dev->struct_mutex);
+	}
+
 	return obj;
 
 fail:
@@ -1108,6 +1108,7 @@
 struct drm_gem_object *msm_gem_import(struct drm_device *dev,
 		struct dma_buf *dmabuf, struct sg_table *sgt)
 {
+	struct msm_drm_private *priv = dev->dev_private;
 	struct msm_gem_object *msm_obj;
 	struct drm_gem_object *obj;
 	uint32_t size;
@@ -1121,9 +1122,9 @@
 
 	size = PAGE_ALIGN(dmabuf->size);
 
-	ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj, false);
+	ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
 	if (ret)
-		goto fail;
+		return ERR_PTR(ret);
 
 	drm_gem_private_object_init(dev, obj, size);
 
@@ -1146,6 +1147,11 @@
 	}
 
 	mutex_unlock(&msm_obj->lock);
+
+	mutex_lock(&dev->struct_mutex);
+	list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+	mutex_unlock(&dev->struct_mutex);
+
 	return obj;
 
 fail:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_gem_prime.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_gem_prime.c
@@ -17,7 +17,7 @@
 	int npages = obj->size >> PAGE_SHIFT;
 
 	if (WARN_ON(!msm_obj->pages))  /* should have already pinned! */
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	return drm_prime_pages_to_sg(msm_obj->pages, npages);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_gpu.c
@@ -16,6 +16,7 @@
 #include <linux/pm_opp.h>
 #include <linux/devfreq.h>
 #include <linux/devcoredump.h>
+#include <linux/sched/task.h>
 
 /*
  * Power Management:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_rd.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_rd.c
@@ -191,6 +191,9 @@
 	file->private_data = rd;
 	rd->open = true;
 
+	/* Reset fifo to clear any previously unread data: */
+	rd->fifo.head = rd->fifo.tail = 0;
+
 	/* the parsing tools need to know gpu-id to know which
 	 * register database to load.
 	 */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -27,7 +27,8 @@
 	ring->id = id;
 
 	ring->start = msm_gem_kernel_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ,
-		MSM_BO_WC, gpu->aspace, &ring->bo, &ring->iova);
+		MSM_BO_WC | MSM_BO_GPU_READONLY, gpu->aspace, &ring->bo,
+		&ring->iova);
 
 	if (IS_ERR(ring->start)) {
 		ret = PTR_ERR(ring->start);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/msm/msm_submitqueue.c
+++ linux-ein-5.4.0/drivers/gpu/drm/msm/msm_submitqueue.c
@@ -71,8 +71,10 @@
 	queue->flags = flags;
 
 	if (priv->gpu) {
-		if (prio >= priv->gpu->nr_rings)
+		if (prio >= priv->gpu->nr_rings) {
+			kfree(queue);
 			return -EINVAL;
+		}
 
 		queue->prio = prio;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/Kconfig
@@ -8,9 +8,9 @@
 	tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
 	depends on DRM && OF
 	depends on COMMON_CLK
+	depends on ARCH_MXS || ARCH_MXC || COMPILE_TEST
 	select DRM_MXS
 	select DRM_KMS_HELPER
-	select DRM_KMS_FB_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DRM_PANEL
 	help
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
@@ -43,14 +43,17 @@
 }
 
 /* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
-static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
+static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb, bool update)
 {
 	struct drm_crtc *crtc = &mxsfb->pipe.crtc;
 	struct drm_device *drm = crtc->dev;
 	const u32 format = crtc->primary->state->fb->format->format;
-	u32 ctrl, ctrl1;
+	u32 ctrl = 0, ctrl1 = 0;
+	bool bgr_format = true;
+	struct drm_format_name_buf format_name_buf;
 
-	ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+	if (!update)
+		ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
 
 	/*
 	 * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
@@ -59,61 +62,158 @@
 	 * to arbitrary value. This limitation should not pose an issue.
 	 */
 
-	/* CTRL1 contains IRQ config and status bits, preserve those. */
-	ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
-	ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+	if (!update) {
+		/* CTRL1 contains IRQ config and status bits, preserve those. */
+		ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+		ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+	}
+
+	DRM_DEV_DEBUG_DRIVER(drm->dev, "Setting up %s mode\n",
+			     drm_get_format_name(format, &format_name_buf));
+
+	/* Do some clean-up that we might have from a previous mode */
+	ctrl &= ~CTRL_SHIFT_DIR(1);
+	ctrl &= ~CTRL_SHIFT_NUM(0x3f);
+	if (mxsfb->devdata->ipversion >= 4)
+		writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_CLR) |
+		       CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_CLR),
+		       mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
 
 	switch (format) {
-	case DRM_FORMAT_RGB565:
-		dev_dbg(drm->dev, "Setting up RGB565 mode\n");
+	case DRM_FORMAT_BGR565: /* BG16 */
+		if (mxsfb->devdata->ipversion < 4)
+			goto err;
+		writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) |
+			CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR),
+			mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+		/* Fall through */
+	case DRM_FORMAT_RGB565: /* RG16 */
 		ctrl |= CTRL_SET_WORD_LENGTH(0);
+		ctrl &= ~CTRL_DF16;
 		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
 		break;
-	case DRM_FORMAT_XRGB8888:
-		dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
+	case DRM_FORMAT_XBGR1555: /* XB15 */
+	case DRM_FORMAT_ABGR1555: /* AB15 */
+		if (mxsfb->devdata->ipversion < 4)
+			goto err;
+		writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) |
+			CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR),
+			mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+		/* Fall through */
+	case DRM_FORMAT_XRGB1555: /* XR15 */
+	case DRM_FORMAT_ARGB1555: /* AR15 */
+		ctrl |= CTRL_SET_WORD_LENGTH(0);
+		ctrl |= CTRL_DF16;
+		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+		break;
+	case DRM_FORMAT_RGBX8888: /* RX24 */
+	case DRM_FORMAT_RGBA8888: /* RA24 */
+		/* RGBX - > 0RGB */
+		ctrl |= CTRL_SHIFT_DIR(1);
+		ctrl |= CTRL_SHIFT_NUM(8);
+		bgr_format = false;
+		/* Fall through */
+	case DRM_FORMAT_XBGR8888: /* XB24 */
+	case DRM_FORMAT_ABGR8888: /* AB24 */
+		if (bgr_format) {
+			if (mxsfb->devdata->ipversion < 4)
+				goto err;
+			writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) |
+			       CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR),
+			       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+		}
+		/* Fall through */
+	case DRM_FORMAT_XRGB8888: /* XR24 */
+	case DRM_FORMAT_ARGB8888: /* AR24 */
 		ctrl |= CTRL_SET_WORD_LENGTH(3);
 		/* Do not use packed pixels = one pixel per word instead. */
 		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
 		break;
 	default:
-		dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
-		return -EINVAL;
+		goto err;
 	}
 
-	writel(ctrl1, mxsfb->base + LCDC_CTRL1);
-	writel(ctrl, mxsfb->base + LCDC_CTRL);
+	if (update) {
+		writel(ctrl, mxsfb->base + LCDC_CTRL + REG_SET);
+		writel(ctrl1, mxsfb->base + LCDC_CTRL1 + REG_SET);
+	} else {
+		writel(ctrl, mxsfb->base + LCDC_CTRL);
+		writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+	}
 
 	return 0;
+
+err:
+	DRM_DEV_ERROR(drm->dev, "Unhandled pixel format: %s\n",
+		      drm_get_format_name(format, &format_name_buf));
+
+	return -EINVAL;
+}
+
+static u32 get_bus_format_from_bpp(u32 bpp)
+{
+	switch (bpp) {
+	case 16:
+		return MEDIA_BUS_FMT_RGB565_1X16;
+	case 18:
+		return MEDIA_BUS_FMT_RGB666_1X18;
+	case 24:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	default:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	}
 }
 
 static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
 {
 	struct drm_crtc *crtc = &mxsfb->pipe.crtc;
+	unsigned int bits_per_pixel = crtc->primary->state->fb->format->depth;
 	struct drm_device *drm = crtc->dev;
 	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-	u32 reg;
+	int num_bus_formats = mxsfb->connector->display_info.num_bus_formats;
+	const u32 *bus_formats = mxsfb->connector->display_info.bus_formats;
+	u32 reg = 0;
+	int i = 0;
+
+	/* match the user requested bus_format to one supported by the panel */
+	if (num_bus_formats) {
+		u32 user_bus_format = get_bus_format_from_bpp(bits_per_pixel);
+
+		bus_format = bus_formats[0];
+		for (i = 0; i < num_bus_formats; i++) {
+			if (user_bus_format == bus_formats[i]) {
+				bus_format = user_bus_format;
+				break;
+			}
+		}
+	}
 
-	reg = readl(mxsfb->base + LCDC_CTRL);
+	/*
+	 * CRTC will dictate the bus format via private_flags[16:1]
+	 * and private_flags[0] will signal a bus format change
+	 */
+	crtc->mode.private_flags &= ~0x1FFFF; /* clear bus format */
+	crtc->mode.private_flags |= (bus_format << 1); /* set bus format */
+	crtc->mode.private_flags |= 0x1; /* bus format change indication*/
 
-	if (mxsfb->connector.display_info.num_bus_formats)
-		bus_format = mxsfb->connector.display_info.bus_formats[0];
+	DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
+			     bus_format);
 
-	reg &= ~CTRL_BUS_WIDTH_MASK;
 	switch (bus_format) {
 	case MEDIA_BUS_FMT_RGB565_1X16:
-		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
+		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
 		break;
 	case MEDIA_BUS_FMT_RGB666_1X18:
-		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
+		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
 		break;
 	case MEDIA_BUS_FMT_RGB888_1X24:
-		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
+		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
 		break;
 	default:
 		dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
 		break;
 	}
-	writel(reg, mxsfb->base + LCDC_CTRL);
+	writel(reg, mxsfb->base + LCDC_CTRL + REG_SET);
 }
 
 static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
@@ -124,6 +224,21 @@
 		clk_prepare_enable(mxsfb->clk_disp_axi);
 	clk_prepare_enable(mxsfb->clk);
 
+	if (mxsfb->devdata->ipversion >= 4) {
+		/*
+		 * On some platforms, bit 21 is defaulted to 1, which may alter
+		 * the below setting. So, to make sure we have the right setting
+		 * clear all the bits for CTRL2_OUTSTANDING_REQS.
+		 */
+		writel(CTRL2_OUTSTANDING_REQS(0x7),
+		       mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
+		writel(CTRL2_OUTSTANDING_REQS(REQ_16),
+		       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+	}
+
+	/* De-assert LCD Reset bit */
+	writel(CTRL_LCD_RESET, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
 	/* If it was disabled, re-enable the mode again */
 	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
 
@@ -133,12 +248,22 @@
 	writel(reg, mxsfb->base + LCDC_VDCTRL4);
 
 	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+	writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET);
 }
 
 static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
 {
 	u32 reg;
 
+	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+	if (mxsfb->devdata->ipversion >= 4)
+		writel(CTRL2_OUTSTANDING_REQS(0x7),
+		       mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
+
+	/* Assert LCD Reset bit */
+	writel(CTRL_LCD_RESET, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+
 	/*
 	 * Even if we disable the controller here, it will still continue
 	 * until its FIFOs are running out of data
@@ -204,8 +329,9 @@
 
 static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
 {
+	struct drm_device *drm = mxsfb->pipe.crtc.dev;
 	struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
-	const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
+	u32 bus_flags = mxsfb->connector->display_info.bus_flags;
 	u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
 	int err;
 
@@ -223,12 +349,22 @@
 	/* Clear the FIFOs */
 	writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
 
-	err = mxsfb_set_pixel_fmt(mxsfb);
+	err = mxsfb_set_pixel_fmt(mxsfb, false);
 	if (err)
 		return;
 
 	clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
 
+	if (mxsfb->bridge && mxsfb->bridge->timings)
+		bus_flags = mxsfb->bridge->timings->input_bus_flags;
+
+	DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
+			     m->crtc_clock,
+			     (int)(clk_get_rate(mxsfb->clk) / 1000));
+	DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
+			     bus_flags);
+	DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
+
 	writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
 	       TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
 	       mxsfb->base + mxsfb->devdata->transfer_count);
@@ -281,6 +417,7 @@
 	dma_addr_t paddr;
 
 	mxsfb_enable_axi_clk(mxsfb);
+	writel(0, mxsfb->base + LCDC_CTRL);
 	mxsfb_crtc_mode_set_nofb(mxsfb);
 
 	/* Write cur_buf as well to avoid an initial corrupt frame */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -26,6 +26,7 @@
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_irq.h>
@@ -43,6 +44,27 @@
 	MXSFB_V4,
 };
 
+/*
+ * When adding new formats, make sure to update the num_formats from
+ * mxsfb_devdata below.
+ */
+static const u32 mxsfb_formats[] = {
+	/* MXSFB_V3 */
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	/* MXSFB_V4 */
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_BGR565
+};
+
 static const struct mxsfb_devdata mxsfb_devdata[] = {
 	[MXSFB_V3] = {
 		.transfer_count	= LCDC_V3_TRANSFER_COUNT,
@@ -52,6 +74,7 @@
 		.hs_wdth_mask	= 0xff,
 		.hs_wdth_shift	= 24,
 		.ipversion	= 3,
+		.num_formats	= 3,
 	},
 	[MXSFB_V4] = {
 		.transfer_count	= LCDC_V4_TRANSFER_COUNT,
@@ -61,14 +84,10 @@
 		.hs_wdth_mask	= 0x3fff,
 		.hs_wdth_shift	= 18,
 		.ipversion	= 4,
+		.num_formats	= ARRAY_SIZE(mxsfb_formats),
 	},
 };
 
-static const uint32_t mxsfb_formats[] = {
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_RGB565
-};
-
 static struct mxsfb_drm_private *
 drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
 {
@@ -87,8 +106,26 @@
 		clk_disable_unprepare(mxsfb->clk_axi);
 }
 
+static struct drm_framebuffer *
+mxsfb_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+		const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	const struct drm_format_info *info;
+
+	info = drm_get_format_info(dev, mode_cmd);
+	if (!info)
+		return ERR_PTR(-EINVAL);
+
+	if (mode_cmd->width * info->cpp[0] != mode_cmd->pitches[0]) {
+		dev_dbg(dev->dev, "Invalid pitch: fb width must match pitch\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return drm_gem_fb_create(dev, file_priv, mode_cmd);
+}
+
 static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
-	.fb_create		= drm_gem_fb_create,
+	.fb_create		= mxsfb_fb_create,
 	.atomic_check		= drm_atomic_helper_check,
 	.atomic_commit		= drm_atomic_helper_commit,
 };
@@ -101,9 +138,25 @@
 			      struct drm_crtc_state *crtc_state,
 			      struct drm_plane_state *plane_state)
 {
+	struct drm_connector *connector;
 	struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
 	struct drm_device *drm = pipe->plane.dev;
 
+	if (!mxsfb->connector) {
+		list_for_each_entry(connector,
+				    &drm->mode_config.connector_list,
+				    head)
+			if (connector->encoder == &mxsfb->pipe.encoder) {
+				mxsfb->connector = connector;
+				break;
+			}
+	}
+
+	if (!mxsfb->connector) {
+		dev_warn(drm->dev, "No connector attached, using default\n");
+		mxsfb->connector = &mxsfb->panel_connector;
+	}
+
 	pm_runtime_get_sync(drm->dev);
 	drm_panel_prepare(mxsfb->panel);
 	mxsfb_crtc_enable(mxsfb);
@@ -129,6 +182,9 @@
 		drm_crtc_send_vblank_event(crtc, event);
 	}
 	spin_unlock_irq(&drm->event_lock);
+
+	if (mxsfb->connector != &mxsfb->panel_connector)
+		mxsfb->connector = NULL;
 }
 
 static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
@@ -225,17 +281,34 @@
 	}
 
 	ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
-			mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
-			&mxsfb->connector);
+			mxsfb_formats, mxsfb->devdata->num_formats, NULL,
+			mxsfb->connector);
 	if (ret < 0) {
 		dev_err(drm->dev, "Cannot setup simple display pipe\n");
 		goto err_vblank;
 	}
 
-	ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
-	if (ret) {
-		dev_err(drm->dev, "Cannot connect panel\n");
-		goto err_vblank;
+	/*
+	 * Attach panel only if there is one.
+	 * If there is no panel attach, it must be a bridge. In this case, we
+	 * need a reference to its connector for a proper initialization.
+	 * We will do this check in pipe->enable(), since the connector won't
+	 * be attached to an encoder until then.
+	 */
+
+	if (mxsfb->panel) {
+		ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
+		if (ret) {
+			dev_err(drm->dev, "Cannot connect panel: %d\n", ret);
+			goto err_vblank;
+		}
+	} else if (mxsfb->bridge) {
+		ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
+							    mxsfb->bridge);
+		if (ret) {
+			dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
+			goto err_vblank;
+		}
 	}
 
 	drm->mode_config.min_width	= MXSFB_MIN_XRES;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/mxsfb_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -16,6 +16,7 @@
 	unsigned int	 hs_wdth_mask;
 	unsigned int	 hs_wdth_shift;
 	unsigned int	 ipversion;
+	unsigned int	 num_formats;
 };
 
 struct mxsfb_drm_private {
@@ -27,8 +28,10 @@
 	struct clk			*clk_disp_axi;
 
 	struct drm_simple_display_pipe	pipe;
-	struct drm_connector		connector;
+	struct drm_connector		panel_connector;
+	struct drm_connector		*connector;
 	struct drm_panel		*panel;
+	struct drm_bridge		*bridge;
 };
 
 int mxsfb_setup_crtc(struct drm_device *dev);
@@ -40,6 +43,6 @@
 void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
 void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
 void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
-			       struct drm_plane_state *state);
+			       struct drm_plane_state *old_state);
 
 #endif /* __MXSFB_DRV_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/mxsfb_out.c
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/mxsfb_out.c
@@ -21,7 +21,8 @@
 static struct mxsfb_drm_private *
 drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
 {
-	return container_of(connector, struct mxsfb_drm_private, connector);
+	return container_of(connector, struct mxsfb_drm_private,
+			    panel_connector);
 }
 
 static int mxsfb_panel_get_modes(struct drm_connector *connector)
@@ -76,22 +77,23 @@
 int mxsfb_create_output(struct drm_device *drm)
 {
 	struct mxsfb_drm_private *mxsfb = drm->dev_private;
-	struct drm_panel *panel;
 	int ret;
 
-	ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL);
+	ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
+					  &mxsfb->panel, &mxsfb->bridge);
 	if (ret)
 		return ret;
 
-	mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
-	mxsfb->connector.polled = 0;
-	drm_connector_helper_add(&mxsfb->connector,
-			&mxsfb_panel_connector_helper_funcs);
-	ret = drm_connector_init(drm, &mxsfb->connector,
-				 &mxsfb_panel_connector_funcs,
-				 DRM_MODE_CONNECTOR_Unknown);
-	if (!ret)
-		mxsfb->panel = panel;
+	if (mxsfb->panel) {
+		mxsfb->connector = &mxsfb->panel_connector;
+		mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
+		mxsfb->connector->polled = 0;
+		drm_connector_helper_add(mxsfb->connector,
+					 &mxsfb_panel_connector_helper_funcs);
+		ret = drm_connector_init(drm, mxsfb->connector,
+					 &mxsfb_panel_connector_funcs,
+					 DRM_MODE_CONNECTOR_Unknown);
+	}
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/mxsfb/mxsfb_regs.h
+++ linux-ein-5.4.0/drivers/gpu/drm/mxsfb/mxsfb_regs.h
@@ -14,77 +14,136 @@
 
 #define LCDC_CTRL			0x00
 #define LCDC_CTRL1			0x10
+#define LCDC_V4_CTRL2			0x20
 #define LCDC_V3_TRANSFER_COUNT		0x20
 #define LCDC_V4_TRANSFER_COUNT		0x30
 #define LCDC_V4_CUR_BUF			0x40
 #define LCDC_V4_NEXT_BUF		0x50
 #define LCDC_V3_CUR_BUF			0x30
 #define LCDC_V3_NEXT_BUF		0x40
+#define LCDC_TIMING			0x60
 #define LCDC_VDCTRL0			0x70
 #define LCDC_VDCTRL1			0x80
 #define LCDC_VDCTRL2			0x90
 #define LCDC_VDCTRL3			0xa0
 #define LCDC_VDCTRL4			0xb0
+#define LCDC_DVICTRL0			0xc0
+#define LCDC_DVICTRL1			0xd0
+#define LCDC_DVICTRL2			0xe0
+#define LCDC_DVICTRL3			0xf0
+#define LCDC_DVICTRL4			0x100
+#define LCDC_V4_DATA			0x180
+#define LCDC_V3_DATA			0x1b0
 #define LCDC_V4_DEBUG0			0x1d0
 #define LCDC_V3_DEBUG0			0x1f0
+#define LCDC_AS_CTRL			0x210
+#define LCDC_AS_BUF			0x220
+#define LCDC_AS_NEXT_BUF		0x230
+
+/* reg bit manipulation */
+#define REG_PUT(x, h, l) (((x) << (l)) & GENMASK(h, l))
+#define REG_GET(x, h, l) (((x) & GENMASK(h, l)) >> (l))
+
+#define SWIZZLE_LE		0 /* Little-Endian or No swap */
+#define SWIZZLE_BE		1 /* Big-Endian or swap all */
+#define SWIZZLE_HWD		2 /* Swap half-words */
+#define SWIZZLE_HWD_BYTE	3 /* Swap bytes within each half-word */
+
+#define CTRL_SFTRST			BIT(31)
+#define CTRL_CLKGATE			BIT(30)
+#define CTRL_SHIFT_DIR(x)		REG_PUT((x), 26, 26)
+#define CTRL_SHIFT_NUM(x)		REG_PUT((x), 25, 21)
+#define CTRL_BYPASS_COUNT		BIT(19)
+#define CTRL_VSYNC_MODE			BIT(18)
+#define CTRL_DOTCLK_MODE		BIT(17)
+#define CTRL_DATA_SELECT		BIT(16)
+#define CTRL_INPUT_SWIZZLE(x)		REG_PUT((x), 15, 14)
+#define CTRL_CSC_SWIZZLE(x)		REG_PUT((x), 13, 12)
+#define CTRL_SET_BUS_WIDTH(x)		REG_PUT((x), 11, 10)
+#define CTRL_GET_BUS_WIDTH(x)		REG_GET((x), 11, 10)
+#define CTRL_BUS_WIDTH_MASK		REG_PUT((0x3), 11, 10)
+#define CTRL_SET_WORD_LENGTH(x)		REG_PUT((x), 9, 8)
+#define CTRL_GET_WORD_LENGTH(x)		REG_GET((x), 9, 8)
+#define CTRL_MASTER			BIT(5)
+#define CTRL_DF16			BIT(3)
+#define CTRL_DF18			BIT(2)
+#define CTRL_DF24			BIT(1)
+#define CTRL_RUN			BIT(0)
+
+#define CTRL1_RECOVERY_ON_UNDERFLOW	BIT(24)
+#define CTRL1_FIFO_CLEAR		BIT(21)
+
+/*
+ * BYTE_PACKAGING
+ *
+ * This bitfield is used to show which data bytes in a 32-bit word area valid.
+ * Default value 0xf indicates that all bytes are valid. For 8-bit transfers,
+ * any combination in this bitfield will mean valid data is present in the
+ * corresponding bytes. In the 16-bit mode, a 16-bit half-word is valid only if
+ * adjacent bits [1:0] or [3:2] or both are 1. A value of 0x0 will mean that
+ * none of the bytes are valid and should not be used. For example, set the bit
+ * field value to 0x7 if the display data is arranged in the 24-bit unpacked
+ * format (A-R-G-B where A value does not have be transmitted).
+ */
+#define CTRL1_SET_BYTE_PACKAGING(x)	REG_PUT((x), 19, 16)
+#define CTRL1_GET_BYTE_PACKAGING(x)	REG_GET((x), 19, 16)
+
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN	BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ	BIT(9)
+
+#define CTRL2_OUTSTANDING_REQS(x)	REG_PUT((x), 23, 21)
+#define REQ_1	0
+#define REQ_2	1
+#define REQ_4	2
+#define REQ_8	3
+#define REQ_16	4
+
+#define CTRL2_ODD_LINE_PATTERN(x)	REG_PUT((x), 18, 16)
+#define CTRL2_EVEN_LINE_PATTERN(x)	REG_PUT((x), 14, 12)
+#define CTRL2_LINE_PATTERN_RGB	0
+#define CTRL2_LINE_PATTERN_RBG	1
+#define CTRL2_LINE_PATTERN_GBR	2
+#define CTRL2_LINE_PATTERN_GRB	3
+#define CTRL2_LINE_PATTERN_BRG	4
+#define CTRL2_LINE_PATTERN_BGR	5
+#define CTRL2_LINE_PATTERN_CLR	7
+
+#define CTRL_LCD_RESET			BIT(0)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x)	REG_PUT((x), 31, 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x)	REG_GET((x), 31, 16)
+#define TRANSFER_COUNT_SET_HCOUNT(x)	REG_PUT((x), 15, 0)
+#define TRANSFER_COUNT_GET_HCOUNT(x)	REG_GET((x), 15, 0)
+
+#define VDCTRL0_ENABLE_PRESENT		BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH		BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH		BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING	BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH		BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT	BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	BIT(20)
+#define VDCTRL0_HALF_LINE		BIT(19)
+#define VDCTRL0_HALF_LINE_MODE		BIT(18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) REG_PUT((x), 17, 0)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) REG_GET((x), 17, 0)
+
+#define VDCTRL2_SET_HSYNC_PERIOD(x)	REG_PUT((x), 15, 0)
+#define VDCTRL2_GET_HSYNC_PERIOD(x)	REG_GET((x), 15, 0)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS	BIT(29)
+#define VDCTRL3_VSYNC_ONLY		BIT(28)
+#define SET_HOR_WAIT_CNT(x)		REG_PUT((x), 27, 16)
+#define GET_HOR_WAIT_CNT(x)		REG_GET((x), 27, 16)
+#define SET_VERT_WAIT_CNT(x)		REG_PUT((x), 15, 0)
+#define GET_VERT_WAIT_CNT(x)		REG_GET((x), 15, 0)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x)	REG_PUT((x), 31, 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x)	REG_GET((x), 31, 29) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON		BIT(18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x)	REG_PUT((x), 17, 0)
 
-#define CTRL_SFTRST			(1 << 31)
-#define CTRL_CLKGATE			(1 << 30)
-#define CTRL_BYPASS_COUNT		(1 << 19)
-#define CTRL_VSYNC_MODE			(1 << 18)
-#define CTRL_DOTCLK_MODE		(1 << 17)
-#define CTRL_DATA_SELECT		(1 << 16)
-#define CTRL_SET_BUS_WIDTH(x)		(((x) & 0x3) << 10)
-#define CTRL_GET_BUS_WIDTH(x)		(((x) >> 10) & 0x3)
-#define CTRL_BUS_WIDTH_MASK		(0x3 << 10)
-#define CTRL_SET_WORD_LENGTH(x)		(((x) & 0x3) << 8)
-#define CTRL_GET_WORD_LENGTH(x)		(((x) >> 8) & 0x3)
-#define CTRL_MASTER			(1 << 5)
-#define CTRL_DF16			(1 << 3)
-#define CTRL_DF18			(1 << 2)
-#define CTRL_DF24			(1 << 1)
-#define CTRL_RUN			(1 << 0)
-
-#define CTRL1_FIFO_CLEAR		(1 << 21)
-#define CTRL1_SET_BYTE_PACKAGING(x)	(((x) & 0xf) << 16)
-#define CTRL1_GET_BYTE_PACKAGING(x)	(((x) >> 16) & 0xf)
-#define CTRL1_CUR_FRAME_DONE_IRQ_EN	(1 << 13)
-#define CTRL1_CUR_FRAME_DONE_IRQ	(1 << 9)
-
-#define TRANSFER_COUNT_SET_VCOUNT(x)	(((x) & 0xffff) << 16)
-#define TRANSFER_COUNT_GET_VCOUNT(x)	(((x) >> 16) & 0xffff)
-#define TRANSFER_COUNT_SET_HCOUNT(x)	((x) & 0xffff)
-#define TRANSFER_COUNT_GET_HCOUNT(x)	((x) & 0xffff)
-
-#define VDCTRL0_ENABLE_PRESENT		(1 << 28)
-#define VDCTRL0_VSYNC_ACT_HIGH		(1 << 27)
-#define VDCTRL0_HSYNC_ACT_HIGH		(1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FALLING	(1 << 25)
-#define VDCTRL0_ENABLE_ACT_HIGH		(1 << 24)
-#define VDCTRL0_VSYNC_PERIOD_UNIT	(1 << 21)
-#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	(1 << 20)
-#define VDCTRL0_HALF_LINE		(1 << 19)
-#define VDCTRL0_HALF_LINE_MODE		(1 << 18)
-#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
-#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
-
-#define VDCTRL2_SET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
-#define VDCTRL2_GET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
-
-#define VDCTRL3_MUX_SYNC_SIGNALS	(1 << 29)
-#define VDCTRL3_VSYNC_ONLY		(1 << 28)
-#define SET_HOR_WAIT_CNT(x)		(((x) & 0xfff) << 16)
-#define GET_HOR_WAIT_CNT(x)		(((x) >> 16) & 0xfff)
-#define SET_VERT_WAIT_CNT(x)		((x) & 0xffff)
-#define GET_VERT_WAIT_CNT(x)		((x) & 0xffff)
-
-#define VDCTRL4_SET_DOTCLK_DLY(x)	(((x) & 0x7) << 29) /* v4 only */
-#define VDCTRL4_GET_DOTCLK_DLY(x)	(((x) >> 29) & 0x7) /* v4 only */
-#define VDCTRL4_SYNC_SIGNALS_ON		(1 << 18)
-#define SET_DOTCLK_H_VALID_DATA_CNT(x)	((x) & 0x3ffff)
-
-#define DEBUG0_HSYNC			(1 < 26)
-#define DEBUG0_VSYNC			(1 < 25)
+#define DEBUG0_HSYNC			BIT(26)
+#define DEBUG0_VSYNC			BIT(25)
 
 #define MXSFB_MIN_XRES			120
 #define MXSFB_MIN_YRES			120
@@ -101,7 +160,7 @@
 #define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
 #define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
 
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT	(1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT	(1 << 7) /* negative edge sampling */
+#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT	BIT(6)
+#define MXSFB_SYNC_DOTCLK_FALLING_ACT	BIT(7) /* negative edge sampling */
 
 #endif /* __MXSFB_REGS_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -179,7 +179,7 @@
 	nvif_notify_fini(&disp->flip);
 
 	nouveau_display(dev)->priv = NULL;
-	kfree(disp);
+	vfree(disp);
 
 	nvif_object_unmap(&drm->client.device.object);
 }
@@ -197,7 +197,7 @@
 	struct nv04_display *disp;
 	int i, ret;
 
-	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+	disp = vzalloc(sizeof(*disp));
 	if (!disp)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -114,6 +114,7 @@
 		u8 nhsync:1;
 		u8 nvsync:1;
 		u8 depth:4;
+		u8 bpc;
 	} or;
 
 	/* Currently only used for MST */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -132,7 +132,7 @@
 
 int
 nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
-		 const s32 *oclass, u8 head, void *data, u32 size, u64 syncbuf,
+		 const s32 *oclass, u8 head, void *data, u32 size, s64 syncbuf,
 		 struct nv50_dmac *dmac)
 {
 	struct nouveau_cli *cli = (void *)device->object.client;
@@ -167,7 +167,7 @@
 	if (ret)
 		return ret;
 
-	if (!syncbuf)
+	if (syncbuf < 0)
 		return 0;
 
 	ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
@@ -326,9 +326,9 @@
 			 * same size as the native one (e.g. different
 			 * refresh rate)
 			 */
-			if (adjusted_mode->hdisplay == native_mode->hdisplay &&
-			    adjusted_mode->vdisplay == native_mode->vdisplay &&
-			    adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
+			if (mode->hdisplay == native_mode->hdisplay &&
+			    mode->vdisplay == native_mode->vdisplay &&
+			    mode->type & DRM_MODE_TYPE_DRIVER)
 				break;
 			mode = native_mode;
 			asyc->scaler.full = true;
@@ -353,10 +353,20 @@
 		       struct drm_crtc_state *crtc_state,
 		       struct drm_connector_state *conn_state)
 {
-	struct nouveau_connector *nv_connector =
-		nouveau_connector(conn_state->connector);
-	return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
-					   nv_connector->native_mode);
+	struct drm_connector *connector = conn_state->connector;
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
+	int ret;
+
+	ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
+					  nv_connector->native_mode);
+	if (ret)
+		return ret;
+
+	if (crtc_state->mode_changed || crtc_state->connectors_changed)
+		asyh->or.bpc = connector->display_info.bpc;
+
+	return 0;
 }
 
 /******************************************************************************
@@ -770,32 +780,54 @@
 	struct nv50_mstm *mstm = mstc->mstm;
 	struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
 	int slots;
+	int ret;
+
+	ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
+					  mstc->native);
+	if (ret)
+		return ret;
+
+	if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
+		return 0;
+
+	/*
+	 * When restoring duplicated states, we need to make sure that the bw
+	 * remains the same and avoid recalculating it, as the connector's bpc
+	 * may have changed after the state was duplicated
+	 */
+	if (!state->duplicated) {
+		const int clock = crtc_state->adjusted_mode.clock;
 
-	if (crtc_state->mode_changed || crtc_state->connectors_changed) {
 		/*
-		 * When restoring duplicated states, we need to make sure that
-		 * the bw remains the same and avoid recalculating it, as the
-		 * connector's bpc may have changed after the state was
-		 * duplicated
+		 * XXX: Since we don't use HDR in userspace quite yet, limit
+		 * the bpc to 8 to save bandwidth on the topology. In the
+		 * future, we'll want to properly fix this by dynamically
+		 * selecting the highest possible bpc that would fit in the
+		 * topology
 		 */
-		if (!state->duplicated) {
-			const int bpp = connector->display_info.bpc * 3;
-			const int clock = crtc_state->adjusted_mode.clock;
+		asyh->or.bpc = min(connector->display_info.bpc, 8U);
+		asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3);
+	}
 
-			asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, bpp);
-		}
+	slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port,
+					      asyh->dp.pbn);
+	if (slots < 0)
+		return slots;
 
-		slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr,
-						      mstc->port,
-						      asyh->dp.pbn);
-		if (slots < 0)
-			return slots;
+	asyh->dp.tu = slots;
 
-		asyh->dp.tu = slots;
-	}
+	return 0;
+}
 
-	return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
-					   mstc->native);
+static u8
+nv50_dp_bpc_to_depth(unsigned int bpc)
+{
+	switch (bpc) {
+	case  6: return 0x2;
+	case  8: return 0x5;
+	case 10: /* fall-through */
+	default: return 0x6;
+	}
 }
 
 static void
@@ -808,7 +840,7 @@
 	struct nv50_mstm *mstm = NULL;
 	struct drm_connector *connector;
 	struct drm_connector_list_iter conn_iter;
-	u8 proto, depth;
+	u8 proto;
 	bool r;
 
 	drm_connector_list_iter_begin(encoder->dev, &conn_iter);
@@ -837,14 +869,8 @@
 	else
 		proto = 0x9;
 
-	switch (mstc->connector.display_info.bpc) {
-	case  6: depth = 0x2; break;
-	case  8: depth = 0x5; break;
-	case 10:
-	default: depth = 0x6; break;
-	}
-
-	mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth);
+	mstm->outp->update(mstm->outp, head->base.index, armh, proto,
+			   nv50_dp_bpc_to_depth(armh->or.bpc));
 
 	msto->head = head;
 	msto->mstc = mstc;
@@ -1006,8 +1032,10 @@
 		return connector_status_disconnected;
 
 	ret = pm_runtime_get_sync(connector->dev->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(connector->dev->dev);
 		return connector_status_disconnected;
+	}
 
 	conn_status = drm_dp_mst_detect_port(connector, mstc->port->mgr,
 					     mstc->port);
@@ -1498,20 +1526,14 @@
 					lvds.lvds.script |= 0x0200;
 			}
 
-			if (nv_connector->base.display_info.bpc == 8)
+			if (asyh->or.bpc == 8)
 				lvds.lvds.script |= 0x0200;
 		}
 
 		nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds));
 		break;
 	case DCB_OUTPUT_DP:
-		if (nv_connector->base.display_info.bpc == 6)
-			depth = 0x2;
-		else
-		if (nv_connector->base.display_info.bpc == 8)
-			depth = 0x5;
-		else
-			depth = 0x6;
+		depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
 
 		if (nv_encoder->link & 1)
 			proto = 0x8;
@@ -1662,7 +1684,7 @@
 	nv50_outp_acquire(nv_encoder);
 
 	nv_connector = nouveau_encoder_connector_get(nv_encoder);
-	switch (nv_connector->base.display_info.bpc) {
+	switch (asyh->or.bpc) {
 	case 10: asyh->or.depth = 0x6; break;
 	case  8: asyh->or.depth = 0x5; break;
 	case  6: asyh->or.depth = 0x2; break;
@@ -2012,8 +2034,10 @@
 	int ret, i;
 
 	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;
+	}
 
 	ret = drm_atomic_helper_setup_commit(state, nonblock);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/disp.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/disp.h
@@ -70,7 +70,7 @@
 
 int nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
 		     const s32 *oclass, u8 head, void *data, u32 size,
-		     u64 syncbuf, struct nv50_dmac *dmac);
+		     s64 syncbuf, struct nv50_dmac *dmac);
 void nv50_dmac_destroy(struct nv50_dmac *);
 
 u32 *evo_wait(struct nv50_dmac *, int nr);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -81,21 +81,22 @@
 			      struct nv50_head_atom *asyh,
 			      struct nouveau_conn_atom *asyc)
 {
-	struct drm_connector *connector = asyc->state.connector;
 	u32 mode = 0x00;
 
-	if (asyc->dither.mode == DITHERING_MODE_AUTO) {
-		if (asyh->base.depth > connector->display_info.bpc * 3)
-			mode = DITHERING_MODE_DYNAMIC2X2;
-	} else {
-		mode = asyc->dither.mode;
-	}
+	if (asyc->dither.mode) {
+		if (asyc->dither.mode == DITHERING_MODE_AUTO) {
+			if (asyh->base.depth > asyh->or.bpc * 3)
+				mode = DITHERING_MODE_DYNAMIC2X2;
+		} else {
+			mode = asyc->dither.mode;
+		}
 
-	if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
-		if (connector->display_info.bpc >= 8)
-			mode |= DITHERING_DEPTH_8BPC;
-	} else {
-		mode |= asyc->dither.depth;
+		if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
+			if (asyh->or.bpc >= 8)
+				mode |= DITHERING_DEPTH_8BPC;
+		} else {
+			mode |= asyc->dither.depth;
+		}
 	}
 
 	asyh->dither.enable = mode;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
@@ -68,7 +68,7 @@
 	int ret;
 
 	ret = nv50_dmac_create(&drm->client.device, &disp->disp->object,
-			       &oclass, 0, &args, sizeof(args), 0,
+			       &oclass, 0, &args, sizeof(args), -1,
 			       &wndw->wimm);
 	if (ret) {
 		NV_ERROR(drm, "wimm%04x allocation failed: %d\n", oclass, ret);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -451,6 +451,8 @@
 		asyw->clr.ntfy = armw->ntfy.handle != 0;
 		asyw->clr.sema = armw->sema.handle != 0;
 		asyw->clr.xlut = armw->xlut.handle != 0;
+		if (asyw->clr.xlut && asyw->visible)
+			asyw->set.xlut = asyw->xlut.handle != 0;
 		asyw->clr.csc  = armw->csc.valid;
 		if (wndw->func->image_clr)
 			asyw->clr.image = armw->image.handle[0] != 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
@@ -14,6 +14,7 @@
 	DCB_CONNECTOR_LVDS_SPWG = 0x41,
 	DCB_CONNECTOR_DP = 0x46,
 	DCB_CONNECTOR_eDP = 0x47,
+	DCB_CONNECTOR_mDP = 0x48,
 	DCB_CONNECTOR_HDMI_0 = 0x60,
 	DCB_CONNECTOR_HDMI_1 = 0x61,
 	DCB_CONNECTOR_HDMI_C = 0x63,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -51,8 +51,9 @@
 nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE],
 			   struct nouveau_backlight *bl)
 {
-	const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL);
-	if (nb < 0 || nb >= 100)
+	const int nb = ida_alloc_max(&bl_ida, 99, GFP_KERNEL);
+
+	if (nb < 0)
 		return false;
 	if (nb > 0)
 		snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
@@ -280,7 +281,7 @@
 					    nv_encoder, ops, &props);
 	if (IS_ERR(bl->dev)) {
 		if (bl->id >= 0)
-			ida_simple_remove(&bl_ida, bl->id);
+			ida_free(&bl_ida, bl->id);
 		ret = PTR_ERR(bl->dev);
 		goto fail_alloc;
 	}
@@ -306,7 +307,7 @@
 		return;
 
 	if (bl->id >= 0)
-		ida_simple_remove(&bl_ida, bl->id);
+		ida_free(&bl_ida, bl->id);
 
 	backlight_device_unregister(bl->dev);
 	nv_conn->backlight = NULL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -276,8 +276,10 @@
 			break;
 	}
 
-	if (WARN_ON(pi < 0))
+	if (WARN_ON(pi < 0)) {
+		kfree(nvbo);
 		return ERR_PTR(-EINVAL);
+	}
 
 	/* Disable compression if suitable settings couldn't be found. */
 	if (nvbo->comp && !vmm->page[pi].comp) {
@@ -542,7 +544,7 @@
 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
 	int i;
 
-	if (!ttm_dma)
+	if (!ttm_dma || !ttm_dma->dma_address)
 		return;
 
 	/* Don't waste time looping if the object is coherent */
@@ -562,7 +564,7 @@
 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
 	int i;
 
-	if (!ttm_dma)
+	if (!ttm_dma || !ttm_dma->dma_address)
 		return;
 
 	/* Don't waste time looping if the object is coherent */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -497,6 +497,7 @@
 	if (ret) {
 		NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
 		nouveau_channel_del(pchan);
+		goto done;
 	}
 
 	ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -245,14 +245,22 @@
 void
 nouveau_conn_reset(struct drm_connector *connector)
 {
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_conn_atom *asyc;
 
-	if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
-		return;
+	if (drm_drv_uses_atomic_modeset(connector->dev)) {
+		if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
+			return;
+
+		if (connector->state)
+			nouveau_conn_atomic_destroy_state(connector,
+							  connector->state);
+
+		__drm_atomic_helper_connector_reset(connector, &asyc->state);
+	} else {
+		asyc = &nv_connector->properties_state;
+	}
 
-	if (connector->state)
-		nouveau_conn_atomic_destroy_state(connector, connector->state);
-	__drm_atomic_helper_connector_reset(connector, &asyc->state);
 	asyc->dither.mode = DITHERING_MODE_AUTO;
 	asyc->dither.depth = DITHERING_DEPTH_AUTO;
 	asyc->scaler.mode = DRM_MODE_SCALE_NONE;
@@ -276,8 +284,14 @@
 nouveau_conn_attach_properties(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
-	struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
 	struct nouveau_display *disp = nouveau_display(dev);
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct nouveau_conn_atom *armc;
+
+	if (drm_drv_uses_atomic_modeset(connector->dev))
+		armc = nouveau_conn_atom(connector->state);
+	else
+		armc = &nv_connector->properties_state;
 
 	/* Init DVI-I specific properties. */
 	if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
@@ -524,6 +538,19 @@
 	}
 }
 
+static void
+nouveau_connector_set_edid(struct nouveau_connector *nv_connector,
+			   struct edid *edid)
+{
+	if (nv_connector->edid != edid) {
+		struct edid *old_edid = nv_connector->edid;
+
+		drm_connector_update_edid_property(&nv_connector->base, edid);
+		kfree(old_edid);
+		nv_connector->edid = edid;
+	}
+}
+
 static enum drm_connector_status
 nouveau_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -537,13 +564,6 @@
 	int ret;
 	enum drm_connector_status conn_status = connector_status_disconnected;
 
-	/* Cleanup the previous EDID block. */
-	if (nv_connector->edid) {
-		drm_connector_update_edid_property(connector, NULL);
-		kfree(nv_connector->edid);
-		nv_connector->edid = NULL;
-	}
-
 	/* 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
@@ -554,22 +574,25 @@
 		pm_runtime_get_noresume(dev->dev);
 	} else {
 		ret = pm_runtime_get_sync(dev->dev);
-		if (ret < 0 && ret != -EACCES)
+		if (ret < 0 && ret != -EACCES) {
+			pm_runtime_put_autosuspend(dev->dev);
+			nouveau_connector_set_edid(nv_connector, NULL);
 			return conn_status;
+		}
 	}
 
 	nv_encoder = nouveau_connector_ddc_detect(connector);
 	if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
+		struct edid *new_edid;
+
 		if ((vga_switcheroo_handler_flags() &
 		     VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
 		    nv_connector->type == DCB_CONNECTOR_LVDS)
-			nv_connector->edid = drm_get_edid_switcheroo(connector,
-								     i2c);
+			new_edid = drm_get_edid_switcheroo(connector, i2c);
 		else
-			nv_connector->edid = drm_get_edid(connector, i2c);
+			new_edid = drm_get_edid(connector, i2c);
 
-		drm_connector_update_edid_property(connector,
-							nv_connector->edid);
+		nouveau_connector_set_edid(nv_connector, new_edid);
 		if (!nv_connector->edid) {
 			NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
 				 connector->name);
@@ -603,6 +626,8 @@
 		conn_status = connector_status_connected;
 		drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
 		goto out;
+	} else {
+		nouveau_connector_set_edid(nv_connector, NULL);
 	}
 
 	nv_encoder = nouveau_connector_of_detect(connector);
@@ -645,24 +670,20 @@
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = NULL;
+	struct edid *edid = NULL;
 	enum drm_connector_status status = connector_status_disconnected;
 
-	/* Cleanup the previous EDID block. */
-	if (nv_connector->edid) {
-		drm_connector_update_edid_property(connector, NULL);
-		kfree(nv_connector->edid);
-		nv_connector->edid = NULL;
-	}
-
 	nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
 	if (!nv_encoder)
-		return connector_status_disconnected;
+		goto out;
 
 	/* Try retrieving EDID via DDC */
 	if (!drm->vbios.fp_no_ddc) {
 		status = nouveau_connector_detect(connector, force);
-		if (status == connector_status_connected)
+		if (status == connector_status_connected) {
+			edid = nv_connector->edid;
 			goto out;
+		}
 	}
 
 	/* On some laptops (Sony, i'm looking at you) there appears to
@@ -675,7 +696,8 @@
 	 * valid - it's not (rh#613284)
 	 */
 	if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-		if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
+		edid = nouveau_acpi_edid(dev, connector);
+		if (edid) {
 			status = connector_status_connected;
 			goto out;
 		}
@@ -695,12 +717,10 @@
 	 * stored for the panel stored in them.
 	 */
 	if (!drm->vbios.fp_no_ddc) {
-		struct edid *edid =
-			(struct edid *)nouveau_bios_embedded_edid(dev);
+		edid = (struct edid *)nouveau_bios_embedded_edid(dev);
 		if (edid) {
-			nv_connector->edid =
-					kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
-			if (nv_connector->edid)
+			edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
+			if (edid)
 				status = connector_status_connected;
 		}
 	}
@@ -713,8 +733,9 @@
 		status = connector_status_unknown;
 #endif
 
-	drm_connector_update_edid_property(connector, nv_connector->edid);
-	nouveau_connector_set_encoder(connector, nv_encoder);
+	nouveau_connector_set_edid(nv_connector, edid);
+	if (nv_encoder)
+		nouveau_connector_set_encoder(connector, nv_encoder);
 	return status;
 }
 
@@ -749,9 +770,9 @@
 nouveau_connector_set_property(struct drm_connector *connector,
 			       struct drm_property *property, uint64_t value)
 {
-	struct nouveau_conn_atom *asyc = nouveau_conn_atom(connector->state);
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+	struct nouveau_conn_atom *asyc = &nv_connector->properties_state;
 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 	int ret;
 
@@ -955,7 +976,7 @@
 	 * "native" mode as some VBIOS tables require us to use the
 	 * pixel clock as part of the lookup...
 	 */
-	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
 		nouveau_connector_detect_depth(connector);
 
 	if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
@@ -1131,6 +1152,16 @@
 	const char *name = connector->name;
 	struct nouveau_encoder *nv_encoder;
 	int ret;
+	bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
+
+	if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
+		NV_DEBUG(drm, "service %s\n", name);
+		drm_dp_cec_irq(&nv_connector->aux);
+		if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
+			nv50_mstm_service(nv_encoder->dp.mstm);
+
+		return NVIF_NOTIFY_KEEP;
+	}
 
 	ret = pm_runtime_get(drm->dev->dev);
 	if (ret == 0) {
@@ -1151,25 +1182,16 @@
 		return NVIF_NOTIFY_DROP;
 	}
 
-	if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
-		NV_DEBUG(drm, "service %s\n", name);
-		drm_dp_cec_irq(&nv_connector->aux);
-		if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP)))
-			nv50_mstm_service(nv_encoder->dp.mstm);
-	} else {
-		bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
-
+	if (!plugged)
+		drm_dp_cec_unset_edid(&nv_connector->aux);
+	NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
+	if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) {
 		if (!plugged)
-			drm_dp_cec_unset_edid(&nv_connector->aux);
-		NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
-		if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) {
-			if (!plugged)
-				nv50_mstm_remove(nv_encoder->dp.mstm);
-		}
-
-		drm_helper_hpd_irq_event(connector->dev);
+			nv50_mstm_remove(nv_encoder->dp.mstm);
 	}
 
+	drm_helper_hpd_irq_event(connector->dev);
+
 	pm_runtime_mark_last_busy(drm->dev->dev);
 	pm_runtime_put_autosuspend(drm->dev->dev);
 	return NVIF_NOTIFY_KEEP;
@@ -1223,6 +1245,7 @@
 	case DCB_CONNECTOR_DMS59_DP0:
 	case DCB_CONNECTOR_DMS59_DP1:
 	case DCB_CONNECTOR_DP       :
+	case DCB_CONNECTOR_mDP      :
 	case DCB_CONNECTOR_USB_C    : return DRM_MODE_CONNECTOR_DisplayPort;
 	case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
 	case DCB_CONNECTOR_HDMI_0   :
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -29,6 +29,7 @@
 
 #include <nvif/notify.h>
 
+#include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_dp_helper.h>
@@ -44,6 +45,60 @@
 struct nouveau_backlight;
 #endif
 
+#define nouveau_conn_atom(p)                                                   \
+	container_of((p), struct nouveau_conn_atom, state)
+
+struct nouveau_conn_atom {
+	struct drm_connector_state state;
+
+	struct {
+		/* The enum values specifically defined here match nv50/gf119
+		 * hw values, and the code relies on this.
+		 */
+		enum {
+			DITHERING_MODE_OFF = 0x00,
+			DITHERING_MODE_ON = 0x01,
+			DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
+			DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
+			DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
+			DITHERING_MODE_AUTO
+		} mode;
+		enum {
+			DITHERING_DEPTH_6BPC = 0x00,
+			DITHERING_DEPTH_8BPC = 0x02,
+			DITHERING_DEPTH_AUTO
+		} depth;
+	} dither;
+
+	struct {
+		int mode;	/* DRM_MODE_SCALE_* */
+		struct {
+			enum {
+				UNDERSCAN_OFF,
+				UNDERSCAN_ON,
+				UNDERSCAN_AUTO,
+			} mode;
+			u32 hborder;
+			u32 vborder;
+		} underscan;
+		bool full;
+	} scaler;
+
+	struct {
+		int color_vibrance;
+		int vibrant_hue;
+	} procamp;
+
+	union {
+		struct {
+			bool dither:1;
+			bool scaler:1;
+			bool procamp:1;
+		};
+		u8 mask;
+	} set;
+};
+
 struct nouveau_connector {
 	struct drm_connector base;
 	enum dcb_connector_type type;
@@ -63,6 +118,12 @@
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
 	struct nouveau_backlight *backlight;
 #endif
+	/*
+	 * Our connector property code expects a nouveau_conn_atom struct
+	 * even on pre-nv50 where we do not support atomic. This embedded
+	 * version gets used in the non atomic modeset case.
+	 */
+	struct nouveau_conn_atom properties_state;
 };
 
 static inline struct nouveau_connector *nouveau_connector(
@@ -121,61 +182,6 @@
 extern int nouveau_duallink;
 extern int nouveau_hdmimhz;
 
-#include <drm/drm_crtc.h>
-#define nouveau_conn_atom(p)                                                   \
-	container_of((p), struct nouveau_conn_atom, state)
-
-struct nouveau_conn_atom {
-	struct drm_connector_state state;
-
-	struct {
-		/* The enum values specifically defined here match nv50/gf119
-		 * hw values, and the code relies on this.
-		 */
-		enum {
-			DITHERING_MODE_OFF = 0x00,
-			DITHERING_MODE_ON = 0x01,
-			DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
-			DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
-			DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
-			DITHERING_MODE_AUTO
-		} mode;
-		enum {
-			DITHERING_DEPTH_6BPC = 0x00,
-			DITHERING_DEPTH_8BPC = 0x02,
-			DITHERING_DEPTH_AUTO
-		} depth;
-	} dither;
-
-	struct {
-		int mode;	/* DRM_MODE_SCALE_* */
-		struct {
-			enum {
-				UNDERSCAN_OFF,
-				UNDERSCAN_ON,
-				UNDERSCAN_AUTO,
-			} mode;
-			u32 hborder;
-			u32 vborder;
-		} underscan;
-		bool full;
-	} scaler;
-
-	struct {
-		int color_vibrance;
-		int vibrant_hue;
-	} procamp;
-
-	union {
-		struct {
-			bool dither:1;
-			bool scaler:1;
-			bool procamp:1;
-		};
-		u8 mask;
-	} set;
-};
-
 void nouveau_conn_attach_properties(struct drm_connector *);
 void nouveau_conn_reset(struct drm_connector *);
 struct drm_connector_state *
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -54,8 +54,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(drm->dev->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(drm->dev->dev);
 		return ret;
+	}
 
 	seq_printf(m, "0x%08x\n",
 		   nvif_rd32(&drm->client.device.object, 0x101000));
@@ -181,8 +183,11 @@
 	}
 
 	ret = pm_runtime_get_sync(drm->dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(drm->dev);
 		return ret;
+	}
+
 	ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
 	pm_runtime_put_autosuspend(drm->dev);
 	if (ret < 0)
@@ -202,6 +207,7 @@
 	.open = nouveau_debugfs_pstate_open,
 	.read = seq_read,
 	.write = nouveau_debugfs_pstate_set,
+	.release = single_release,
 };
 
 static struct drm_info_list nouveau_debugfs_list[] = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -635,10 +635,10 @@
 	unsigned long c, i;
 	int ret = -ENOMEM;
 
-	args.src = kcalloc(max, sizeof(args.src), GFP_KERNEL);
+	args.src = kcalloc(max, sizeof(*args.src), GFP_KERNEL);
 	if (!args.src)
 		goto out;
-	args.dst = kcalloc(max, sizeof(args.dst), GFP_KERNEL);
+	args.dst = kcalloc(max, sizeof(*args.dst), GFP_KERNEL);
 	if (!args.dst)
 		goto out_free_src;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -123,10 +123,16 @@
 static inline bool
 nouveau_cli_work_ready(struct dma_fence *fence)
 {
-	if (!dma_fence_is_signaled(fence))
-		return false;
-	dma_fence_put(fence);
-	return true;
+	bool ret = true;
+
+	spin_lock_irq(fence->lock);
+	if (!dma_fence_is_signaled_locked(fence))
+		ret = false;
+	spin_unlock_irq(fence->lock);
+
+	if (ret == true)
+		dma_fence_put(fence);
+	return ret;
 }
 
 static void
@@ -520,6 +526,7 @@
 		nvkm_dbgopt(nouveau_debug, "DRM");
 
 	INIT_LIST_HEAD(&drm->clients);
+	mutex_init(&drm->clients_lock);
 	spin_lock_init(&drm->tile.lock);
 
 	/* workaround an odd issue on nvc1 by disabling the device's
@@ -589,6 +596,7 @@
 static void
 nouveau_drm_device_fini(struct drm_device *dev)
 {
+	struct nouveau_cli *cli, *temp_cli;
 	struct nouveau_drm *drm = nouveau_drm(dev);
 
 	if (nouveau_pmops_runtime()) {
@@ -613,11 +621,88 @@
 	nouveau_ttm_fini(drm);
 	nouveau_vga_fini(drm);
 
+	/*
+	 * There may be existing clients from as-yet unclosed files. For now,
+	 * clean them up here rather than deferring until the file is closed,
+	 * but this likely not correct if we want to support hot-unplugging
+	 * properly.
+	 */
+	mutex_lock(&drm->clients_lock);
+	list_for_each_entry_safe(cli, temp_cli, &drm->clients, head) {
+		list_del(&cli->head);
+		mutex_lock(&cli->mutex);
+		if (cli->abi16)
+			nouveau_abi16_fini(cli->abi16);
+		mutex_unlock(&cli->mutex);
+		nouveau_cli_fini(cli);
+		kfree(cli);
+	}
+	mutex_unlock(&drm->clients_lock);
+
 	nouveau_cli_fini(&drm->client);
 	nouveau_cli_fini(&drm->master);
+	mutex_destroy(&drm->clients_lock);
 	kfree(drm);
 }
 
+/*
+ * On some Intel PCIe bridge controllers doing a
+ * D0 -> D3hot -> D3cold -> D0 sequence causes Nvidia GPUs to not reappear.
+ * Skipping the intermediate D3hot step seems to make it work again. This is
+ * probably caused by not meeting the expectation the involved AML code has
+ * when the GPU is put into D3hot state before invoking it.
+ *
+ * This leads to various manifestations of this issue:
+ *  - AML code execution to power on the GPU hits an infinite loop (as the
+ *    code waits on device memory to change).
+ *  - kernel crashes, as all PCI reads return -1, which most code isn't able
+ *    to handle well enough.
+ *
+ * In all cases dmesg will contain at least one line like this:
+ * 'nouveau 0000:01:00.0: Refused to change power state, currently in D3'
+ * followed by a lot of nouveau timeouts.
+ *
+ * In the \_SB.PCI0.PEG0.PG00._OFF code deeper down writes bit 0x80 to the not
+ * documented PCI config space register 0x248 of the Intel PCIe bridge
+ * controller (0x1901) in order to change the state of the PCIe link between
+ * the PCIe port and the GPU. There are alternative code paths using other
+ * registers, which seem to work fine (executed pre Windows 8):
+ *  - 0xbc bit 0x20 (publicly available documentation claims 'reserved')
+ *  - 0xb0 bit 0x10 (link disable)
+ * Changing the conditions inside the firmware by poking into the relevant
+ * addresses does resolve the issue, but it seemed to be ACPI private memory
+ * and not any device accessible memory at all, so there is no portable way of
+ * changing the conditions.
+ * On a XPS 9560 that means bits [0,3] on \CPEX need to be cleared.
+ *
+ * The only systems where this behavior can be seen are hybrid graphics laptops
+ * with a secondary Nvidia Maxwell, Pascal or Turing GPU. It's unclear whether
+ * this issue only occurs in combination with listed Intel PCIe bridge
+ * controllers and the mentioned GPUs or other devices as well.
+ *
+ * documentation on the PCIe bridge controller can be found in the
+ * "7th Generation Intel® Processor Families for H Platforms Datasheet Volume 2"
+ * Section "12 PCI Express* Controller (x16) Registers"
+ */
+
+static void quirk_broken_nv_runpm(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct pci_dev *bridge = pci_upstream_bridge(pdev);
+
+	if (!bridge || bridge->vendor != PCI_VENDOR_ID_INTEL)
+		return;
+
+	switch (bridge->device) {
+	case 0x1901:
+		drm->old_pm_cap = pdev->pm_cap;
+		pdev->pm_cap = 0;
+		NV_INFO(drm, "Disabling PCI power management to avoid bug\n");
+		break;
+	}
+}
+
 static int nouveau_drm_probe(struct pci_dev *pdev,
 			     const struct pci_device_id *pent)
 {
@@ -699,6 +784,7 @@
 	if (ret)
 		goto fail_drm_dev_init;
 
+	quirk_broken_nv_runpm(pdev);
 	return 0;
 
 fail_drm_dev_init:
@@ -720,7 +806,7 @@
 	struct nvkm_client *client;
 	struct nvkm_device *device;
 
-	drm_dev_unregister(dev);
+	drm_dev_unplug(dev);
 
 	dev->irq_enabled = false;
 	client = nvxx_client(&drm->client.base);
@@ -736,7 +822,11 @@
 nouveau_drm_remove(struct pci_dev *pdev)
 {
 	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct nouveau_drm *drm = nouveau_drm(dev);
 
+	/* revert our workaround */
+	if (drm->old_pm_cap)
+		pdev->pm_cap = drm->old_pm_cap;
 	nouveau_drm_device_remove(dev);
 }
 
@@ -989,8 +1079,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));
@@ -1008,9 +1100,9 @@
 
 	fpriv->driver_priv = cli;
 
-	mutex_lock(&drm->client.mutex);
+	mutex_lock(&drm->clients_lock);
 	list_add(&cli->head, &drm->clients);
-	mutex_unlock(&drm->client.mutex);
+	mutex_unlock(&drm->clients_lock);
 
 done:
 	if (ret && cli) {
@@ -1028,6 +1120,16 @@
 {
 	struct nouveau_cli *cli = nouveau_cli(fpriv);
 	struct nouveau_drm *drm = nouveau_drm(dev);
+	int dev_index;
+
+	/*
+	 * The device is gone, and as it currently stands all clients are
+	 * cleaned up in the removal codepath. In the future this may change
+	 * so that we can support hot-unplugging, but for now we immediately
+	 * return to avoid a double-free situation.
+	 */
+	if (!drm_dev_enter(dev, &dev_index))
+		return;
 
 	pm_runtime_get_sync(dev->dev);
 
@@ -1036,14 +1138,15 @@
 		nouveau_abi16_fini(cli->abi16);
 	mutex_unlock(&cli->mutex);
 
-	mutex_lock(&drm->client.mutex);
+	mutex_lock(&drm->clients_lock);
 	list_del(&cli->head);
-	mutex_unlock(&drm->client.mutex);
+	mutex_unlock(&drm->clients_lock);
 
 	nouveau_cli_fini(cli);
 	kfree(cli);
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
+	drm_dev_exit(dev_index);
 }
 
 static const struct drm_ioctl_desc
@@ -1072,8 +1175,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:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -138,6 +138,13 @@
 
 	struct list_head clients;
 
+	/**
+	 * @clients_lock: Protects access to the @clients list of &struct nouveau_cli.
+	 */
+	struct mutex clients_lock;
+
+	u8 old_pm_cap;
+
 	struct {
 		struct agp_bridge_data *bridge;
 		u32 base;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -189,8 +189,10 @@
 	struct nouveau_fbdev *fbcon = info->par;
 	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.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;
 }
 
@@ -315,7 +317,7 @@
 	struct nouveau_framebuffer *fb;
 	struct nouveau_channel *chan;
 	struct nouveau_bo *nvbo;
-	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_mode_fb_cmd2 mode_cmd = {};
 	int ret;
 
 	mode_cmd.width = sizes->surface_width;
@@ -592,6 +594,7 @@
 	drm_fb_helper_fini(&fbcon->helper);
 free:
 	kfree(fbcon);
+	drm->fbcon = NULL;
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -156,7 +156,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-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -45,8 +45,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);
@@ -76,8 +78,10 @@
 		return ret;
 
 	ret = pm_runtime_get_sync(dev);
-	if (ret < 0 && ret != -EACCES)
+	if (ret < 0 && ret != -EACCES) {
+		pm_runtime_put_autosuspend(dev);
 		goto out;
+	}
 
 	ret = nouveau_vma_new(nvbo, vmm, &vma);
 	pm_runtime_mark_last_busy(dev);
@@ -193,7 +197,8 @@
 	 * to the caller, instead of a normal nouveau_bo ttm reference. */
 	ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size);
 	if (ret) {
-		nouveau_bo_ref(NULL, &nvbo);
+		drm_gem_object_release(&nvbo->bo.base);
+		kfree(nvbo);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -176,6 +176,8 @@
 nouveau_mem_del(struct ttm_mem_reg *reg)
 {
 	struct nouveau_mem *mem = nouveau_mem(reg);
+	if (!mem)
+		return;
 	nouveau_mem_fini(mem);
 	kfree(reg->mm_node);
 	reg->mm_node = NULL;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -90,7 +90,6 @@
 
 	ret = nouveau_bo_init(nvbo, size, align, flags, sg, robj);
 	if (ret) {
-		nouveau_bo_ref(NULL, &nvbo);
 		obj = ERR_PTR(ret);
 		goto unlock;
 	}
@@ -112,7 +111,22 @@
 	if (ret)
 		return -EINVAL;
 
-	return 0;
+	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
+	if (ret)
+		goto error;
+
+	if (nvbo->bo.moving)
+		ret = dma_fence_wait(nvbo->bo.moving, true);
+
+	ttm_bo_unreserve(&nvbo->bo);
+	if (ret)
+		goto error;
+
+	return ret;
+
+error:
+	nouveau_bo_unpin(nvbo);
+	return ret;
 }
 
 void nouveau_gem_prime_unpin(struct drm_gem_object *obj)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -96,12 +96,9 @@
 	else
 		nvbe->ttm.ttm.func = &nv50_sgdma_backend;
 
-	if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags))
-		/*
-		 * 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, bo, page_flags)) {
+		kfree(nvbe);
 		return NULL;
+	}
 	return &nvbe->ttm.ttm;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -112,11 +112,11 @@
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct drm_nouveau_svm_bind *args = data;
 	unsigned target, cmd, priority;
-	unsigned long addr, end, size;
+	unsigned long addr, end;
 	struct mm_struct *mm;
 
 	args->va_start &= PAGE_MASK;
-	args->va_end &= PAGE_MASK;
+	args->va_end = ALIGN(args->va_end, PAGE_SIZE);
 
 	/* Sanity check arguments */
 	if (args->reserved0 || args->reserved1)
@@ -125,8 +125,6 @@
 		return -EINVAL;
 	if (args->va_start >= args->va_end)
 		return -EINVAL;
-	if (!args->npages)
-		return -EINVAL;
 
 	cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT;
 	cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK;
@@ -158,12 +156,6 @@
 	if (args->stride)
 		return -EINVAL;
 
-	size = ((unsigned long)args->npages) << PAGE_SHIFT;
-	if ((args->va_start + size) <= args->va_start)
-		return -EINVAL;
-	if ((args->va_start + size) > args->va_end)
-		return -EINVAL;
-
 	/*
 	 * Ok we are ask to do something sane, for now we only support migrate
 	 * commands but we will add things like memory policy (what to do on
@@ -173,7 +165,12 @@
 	mm = get_task_mm(current);
 	down_read(&mm->mmap_sem);
 
-	for (addr = args->va_start, end = args->va_start + size; addr < end;) {
+	if (!cli->svm.svmm) {
+		up_read(&mm->mmap_sem);
+		return -EINVAL;
+	}
+
+	for (addr = args->va_start, end = args->va_end; addr < end;) {
 		struct vm_area_struct *vma;
 		unsigned long next;
 
@@ -181,6 +178,7 @@
 		if (!vma)
 			break;
 
+		addr = max(addr, vma->vm_start);
 		next = min(vma->vm_end, end);
 		/* This is a best effort so we ignore errors */
 		nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
@@ -308,6 +306,10 @@
 	struct drm_nouveau_svm_init *args = data;
 	int ret;
 
+	/* We need to fail if svm is disabled */
+	if (!cli->drm->svm)
+		return -ENOSYS;
+
 	/* Allocate tracking for SVM-enabled VMM. */
 	if (!(svmm = kzalloc(sizeof(*svmm), GFP_KERNEL)))
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -63,14 +63,12 @@
 {
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
-	struct nouveau_mem *mem;
 	int ret;
 
 	if (drm->client.device.info.ram_size == 0)
 		return -ENOMEM;
 
 	ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg);
-	mem = nouveau_mem(reg);
 	if (ret)
 		return ret;
 
@@ -103,11 +101,9 @@
 {
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
-	struct nouveau_mem *mem;
 	int ret;
 
 	ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg);
-	mem = nouveau_mem(reg);
 	if (ret)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nouveau_vmm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nouveau_vmm.c
@@ -108,6 +108,9 @@
 	} else {
 		ret = nvif_vmm_get(&vmm->vmm, PTES, false, mem->mem.page, 0,
 				   mem->mem.size, &tmp);
+		if (ret)
+			goto done;
+
 		vma->addr = tmp.addr;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/core/memory.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/core/memory.c
@@ -91,8 +91,8 @@
 	}
 
 	refcount_set(&tags->refcount, 1);
+	*ptags = memory->tags = tags;
 	mutex_unlock(&fb->subdev.mutex);
-	*ptags = tags;
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
@@ -57,7 +57,7 @@
 		args->v0.count = 0;
 		args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
 		args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
-		args->v0.pwrsrc = -ENOSYS;
+		args->v0.pwrsrc = -ENODEV;
 		args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -123,7 +123,7 @@
 
 	mutex_init(&tdev->iommu.mutex);
 
-	if (iommu_present(&platform_bus_type)) {
+	if (device_iommu_mapped(dev)) {
 		tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type);
 		if (!tdev->iommu.domain)
 			goto error;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
@@ -74,6 +74,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-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -419,7 +419,7 @@
 	return ret;
 }
 
-static void
+void
 nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
 {
 	struct nvkm_dp *dp = nvkm_dp(outp);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
@@ -32,6 +32,7 @@
 
 int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *,
 		struct nvkm_outp **);
+void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
 
 /* DPCD Receiver Capabilities */
 #define DPCD_RC00_DPCD_REV                                              0x00000
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigm200.c
@@ -27,10 +27,10 @@
 gm200_hdmi_scdc(struct nvkm_ior *ior, int head, u8 scdc)
 {
 	struct nvkm_device *device = ior->disp->engine.subdev.device;
-	const u32 hoff = head * 0x800;
+	const u32 soff = nv50_ior_base(ior);
 	const u32 ctrl = scdc & 0x3;
 
-	nvkm_mask(device, 0x61c5bc + hoff, 0x00000003, ctrl);
+	nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
 
 	ior->tmds.high_speed = !!(scdc & 0x2);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c
@@ -62,7 +62,6 @@
 		nvkm_wr32(device, 0x6f0108 + hdmi, vendor_infoframe.header);
 		nvkm_wr32(device, 0x6f010c + hdmi, vendor_infoframe.subpack0_low);
 		nvkm_wr32(device, 0x6f0110 + hdmi, vendor_infoframe.subpack0_high);
-		nvkm_wr32(device, 0x6f0110 + hdmi, 0x00000000);
 		nvkm_wr32(device, 0x6f0114 + hdmi, 0x00000000);
 		nvkm_wr32(device, 0x6f0118 + hdmi, 0x00000000);
 		nvkm_wr32(device, 0x6f011c + hdmi, 0x00000000);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 #include "outp.h"
+#include "dp.h"
 #include "ior.h"
 
 #include <subdev/bios.h>
@@ -216,6 +217,14 @@
 	if (!ior->arm.head || ior->arm.proto != proto) {
 		OUTP_DBG(outp, "no heads (%x %d %d)", ior->arm.head,
 			 ior->arm.proto, proto);
+
+		/* The EFI GOP driver on Ampere can leave unused DP links routed,
+		 * which we don't expect.  The DisableLT IED script *should* get
+		 * us back to where we need to be.
+		 */
+		if (ior->func->route.get && !ior->arm.head && outp->info.type == DCB_OUTPUT_DP)
+			nvkm_dp_disable(outp, ior);
+
 		return;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
@@ -121,6 +121,7 @@
 
 extern const struct gf100_grctx_func gk110_grctx;
 void gk110_grctx_generate_r419eb0(struct gf100_gr *);
+void gk110_grctx_generate_r419f78(struct gf100_gr *);
 
 extern const struct gf100_grctx_func gk110b_grctx;
 extern const struct gf100_grctx_func gk208_grctx;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
@@ -916,7 +916,9 @@
 gk104_grctx_generate_r419f78(struct gf100_gr *gr)
 {
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000);
+
+	/* bit 3 set disables loads in fp helper invocations, we need it enabled */
+	nvkm_mask(device, 0x419f78, 0x00000009, 0x00000000);
 }
 
 void
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
@@ -820,6 +820,15 @@
 	nvkm_mask(device, 0x419eb0, 0x00001000, 0x00001000);
 }
 
+void
+gk110_grctx_generate_r419f78(struct gf100_gr *gr)
+{
+	struct nvkm_device *device = gr->base.engine.subdev.device;
+
+	/* bit 3 set disables loads in fp helper invocations, we need it enabled */
+	nvkm_mask(device, 0x419f78, 0x00000008, 0x00000000);
+}
+
 const struct gf100_grctx_func
 gk110_grctx = {
 	.main  = gf100_grctx_generate_main,
@@ -852,4 +861,5 @@
 	.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
 	.r418800 = gk104_grctx_generate_r418800,
 	.r419eb0 = gk110_grctx_generate_r419eb0,
+	.r419f78 = gk110_grctx_generate_r419f78,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
@@ -101,4 +101,5 @@
 	.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
 	.r418800 = gk104_grctx_generate_r418800,
 	.r419eb0 = gk110_grctx_generate_r419eb0,
+	.r419f78 = gk110_grctx_generate_r419f78,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
@@ -566,4 +566,5 @@
 	.dist_skip_table = gf117_grctx_generate_dist_skip_table,
 	.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
 	.r418800 = gk104_grctx_generate_r418800,
+	.r419f78 = gk110_grctx_generate_r419f78,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
@@ -991,4 +991,5 @@
 	.r406500 = gm107_grctx_generate_r406500,
 	.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
 	.r419e00 = gm107_grctx_generate_r419e00,
+	.r419f78 = gk110_grctx_generate_r419f78,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -1988,8 +1988,34 @@
 {
 	struct gf100_gr *gr = gf100_gr(base);
 	struct nvkm_subdev *subdev = &base->engine.subdev;
+	struct nvkm_device *device = subdev->device;
+	bool reset = device->chipset == 0x137 || device->chipset == 0x138;
 	u32 ret;
 
+	/* On certain GP107/GP108 boards, we trigger a weird issue where
+	 * GR will stop responding to PRI accesses after we've asked the
+	 * SEC2 RTOS to boot the GR falcons.  This happens with far more
+	 * frequency when cold-booting a board (ie. returning from D3).
+	 *
+	 * The root cause for this is not known and has proven difficult
+	 * to isolate, with many avenues being dead-ends.
+	 *
+	 * A workaround was discovered by Karol, whereby putting GR into
+	 * reset for an extended period right before initialisation
+	 * prevents the problem from occuring.
+	 *
+	 * XXX: As RM does not require any such workaround, this is more
+	 *      of a hack than a true fix.
+	 */
+	reset = nvkm_boolopt(device->cfgopt, "NvGrResetWar", reset);
+	if (reset) {
+		nvkm_mask(device, 0x000200, 0x00001000, 0x00000000);
+		nvkm_rd32(device, 0x000200);
+		msleep(50);
+		nvkm_mask(device, 0x000200, 0x00001000, 0x00001000);
+		nvkm_rd32(device, 0x000200);
+	}
+
 	nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false);
 
 	ret = nvkm_falcon_get(gr->fecs.falcon, subdev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
@@ -143,23 +143,24 @@
 
 	nent = (fuc.size / sizeof(struct gk20a_fw_av));
 
-	pack = vzalloc((sizeof(*pack) * max_classes) +
-		       (sizeof(*init) * (nent + 1)));
+	pack = vzalloc((sizeof(*pack) * (max_classes + 1)) +
+		       (sizeof(*init) * (nent + max_classes + 1)));
 	if (!pack) {
 		ret = -ENOMEM;
 		goto end;
 	}
 
-	init = (void *)(pack + max_classes);
+	init = (void *)(pack + max_classes + 1);
 
-	for (i = 0; i < nent; i++) {
-		struct gf100_gr_init *ent = &init[i];
+	for (i = 0; i < nent; i++, init++) {
 		struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc.data)[i];
 		u32 class = av->addr & 0xffff;
 		u32 addr = (av->addr & 0xffff0000) >> 14;
 
 		if (prevclass != class) {
-			pack[classidx].init = ent;
+			if (prevclass) /* Add terminator to the method list. */
+				init++;
+			pack[classidx].init = init;
 			pack[classidx].type = class;
 			prevclass = class;
 			if (++classidx >= max_classes) {
@@ -169,10 +170,10 @@
 			}
 		}
 
-		ent->addr = addr;
-		ent->data = av->data;
-		ent->count = 1;
-		ent->pitch = 1;
+		init->addr = addr;
+		init->data = av->data;
+		init->count = 1;
+		init->pitch = 1;
 	}
 
 	*ppack = pack;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
@@ -33,12 +33,12 @@
 {
 	u32 p = *addr;
 
-	if (*addr > bios->image0_size && bios->imaged_addr) {
+	if (*addr >= bios->image0_size && bios->imaged_addr) {
 		*addr -= bios->image0_size;
 		*addr += bios->imaged_addr;
 	}
 
-	if (unlikely(*addr + size >= bios->size)) {
+	if (unlikely(*addr + size > bios->size)) {
 		nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr);
 		return false;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
+++ linux-ein-5.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;
 	}
@@ -154,11 +154,17 @@
 	return (void *)fw;
 }
 
+static void
+shadow_fw_release(void *fw)
+{
+	release_firmware(fw);
+}
+
 static const struct nvbios_source
 shadow_fw = {
 	.name = "firmware",
 	.init = shadow_fw_init,
-	.fini = (void(*)(void *))release_firmware,
+	.fini = shadow_fw_release,
 	.read = shadow_fw_read,
 	.rw = false,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
@@ -101,9 +101,13 @@
 	else
 		return ERR_PTR(-ENODEV);
 
+	if (!pdev->rom || pdev->romlen == 0)
+		return ERR_PTR(-ENODEV);
+
 	if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+		priv->size = pdev->romlen;
 		if (ret = -ENODEV,
-		    (priv->rom = pci_platform_rom(pdev, &priv->size)))
+		    (priv->rom = ioremap(pdev->rom, pdev->romlen)))
 			return priv;
 		kfree(priv);
 	}
@@ -111,11 +115,20 @@
 	return ERR_PTR(ret);
 }
 
+static void
+platform_fini(void *data)
+{
+	struct priv *priv = data;
+
+	iounmap(priv->rom);
+	kfree(priv);
+}
+
 const struct nvbios_source
 nvbios_platform = {
 	.name = "PLATFORM",
 	.init = platform_init,
-	.fini = (void(*)(void *))kfree,
+	.fini = platform_fini,
 	.read = pcirom_read,
 	.rw = true,
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -135,10 +135,10 @@
 
 	list_for_each_entry_from_reverse(cstate, &pstate->list, head) {
 		if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp))
-			break;
+			return cstate;
 	}
 
-	return cstate;
+	return NULL;
 }
 
 static struct nvkm_cstate *
@@ -169,6 +169,8 @@
 	if (!list_empty(&pstate->list)) {
 		cstate = nvkm_cstate_get(clk, pstate, cstatei);
 		cstate = nvkm_cstate_find_best(clk, pstate, cstate);
+		if (!cstate)
+			return -EINVAL;
 	} else {
 		cstate = &pstate->base;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c
@@ -146,6 +146,7 @@
 	struct nvkm_fault *fault = nvkm_fault(subdev);
 	int i;
 
+	nvkm_notify_fini(&fault->nrpfb);
 	nvkm_event_fini(&fault->event);
 
 	for (i = 0; i < fault->buffer_nr; i++) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c
@@ -33,7 +33,7 @@
 gm200_i2c_aux_fini(struct gm200_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 @@
 			gm200_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-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 #include "priv.h"
+#include <subdev/timer.h>
 
 static void
 gf100_ibus_intr_hub(struct nvkm_subdev *ibus, int i)
@@ -31,7 +32,6 @@
 	u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0400));
 	u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0400));
 	nvkm_debug(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000);
 }
 
 static void
@@ -42,7 +42,6 @@
 	u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0400));
 	u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0400));
 	nvkm_debug(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000);
 }
 
 static void
@@ -53,7 +52,6 @@
 	u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0400));
 	u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0400));
 	nvkm_debug(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000);
 }
 
 void
@@ -90,6 +88,12 @@
 			intr1 &= ~stat;
 		}
 	}
+
+	nvkm_mask(device, 0x121c4c, 0x0000003f, 0x00000002);
+	nvkm_msec(device, 2000,
+		if (!(nvkm_rd32(device, 0x121c4c) & 0x0000003f))
+			break;
+	);
 }
 
 static int
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 #include "priv.h"
+#include <subdev/timer.h>
 
 static void
 gk104_ibus_intr_hub(struct nvkm_subdev *ibus, int i)
@@ -31,7 +32,6 @@
 	u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0800));
 	u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0800));
 	nvkm_debug(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000);
 }
 
 static void
@@ -42,7 +42,6 @@
 	u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0800));
 	u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0800));
 	nvkm_debug(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000);
 }
 
 static void
@@ -53,7 +52,6 @@
 	u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0800));
 	u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0800));
 	nvkm_debug(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat);
-	nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
 }
 
 void
@@ -90,6 +88,12 @@
 			intr1 &= ~stat;
 		}
 	}
+
+	nvkm_mask(device, 0x12004c, 0x0000003f, 0x00000002);
+	nvkm_msec(device, 2000,
+		if (!(nvkm_rd32(device, 0x12004c) & 0x0000003f))
+			break;
+	);
 }
 
 static int
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
@@ -316,9 +316,9 @@
 {
 	struct nvkm_device *device = mmu->subdev.device;
 	struct nvkm_mm *mm = &device->fb->ram->vram;
-	const u32 sizeN = nvkm_mm_heap_size(mm, NVKM_RAM_MM_NORMAL);
-	const u32 sizeU = nvkm_mm_heap_size(mm, NVKM_RAM_MM_NOMAP);
-	const u32 sizeM = nvkm_mm_heap_size(mm, NVKM_RAM_MM_MIXED);
+	const u64 sizeN = nvkm_mm_heap_size(mm, NVKM_RAM_MM_NORMAL);
+	const u64 sizeU = nvkm_mm_heap_size(mm, NVKM_RAM_MM_NOMAP);
+	const u64 sizeM = nvkm_mm_heap_size(mm, NVKM_RAM_MM_MIXED);
 	u8 type = NVKM_MEM_KIND * !!mmu->func->kind;
 	u8 heap = NVKM_MEM_VRAM;
 	int heapM, heapN, heapU;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c
@@ -32,7 +32,7 @@
 
 	type = 0x00000001; /* PAGE_ALL */
 	if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR]))
-		type |= 0x00000004; /* HUB_ONLY */
+		type |= 0x00000006; /* HUB_ONLY | ALL PDB (hack) */
 
 	mutex_lock(&subdev->mutex);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c
+++ linux-ein-5.4.0/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c
@@ -108,6 +108,7 @@
 	struct gm200_secboot *gsb;
 	struct nvkm_acr *acr;
 
+	*psb = NULL;
 	acr = acr_r352_new(BIT(NVKM_SECBOOT_FALCON_FECS) |
 			   BIT(NVKM_SECBOOT_FALCON_PMU));
 	if (IS_ERR(acr))
@@ -116,10 +117,8 @@
 	acr->optional_falcons = BIT(NVKM_SECBOOT_FALCON_PMU);
 
 	gsb = kzalloc(sizeof(*gsb), GFP_KERNEL);
-	if (!gsb) {
-		psb = NULL;
+	if (!gsb)
 		return -ENOMEM;
-	}
 	*psb = &gsb->base;
 
 	ret = nvkm_secboot_ctor(&gm20b_secboot, acr, device, index, &gsb->base);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -1444,22 +1444,26 @@
 {
 	struct dsi_data *dsi = s->private;
 	unsigned long flags;
-	struct dsi_irq_stats stats;
+	struct dsi_irq_stats *stats;
+
+	stats = kmalloc(sizeof(*stats), GFP_KERNEL);
+	if (!stats)
+		return -ENOMEM;
 
 	spin_lock_irqsave(&dsi->irq_stats_lock, flags);
 
-	stats = dsi->irq_stats;
+	*stats = dsi->irq_stats;
 	memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
 	dsi->irq_stats.last_reset = jiffies;
 
 	spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
 
 	seq_printf(s, "period %u ms\n",
-			jiffies_to_msecs(jiffies - stats.last_reset));
+			jiffies_to_msecs(jiffies - stats->last_reset));
 
-	seq_printf(s, "irqs %d\n", stats.irq_count);
+	seq_printf(s, "irqs %d\n", stats->irq_count);
 #define PIS(x) \
-	seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
+	seq_printf(s, "%-20s %10d\n", #x, stats->dsi_irqs[ffs(DSI_IRQ_##x)-1]);
 
 	seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
 	PIS(VC0);
@@ -1483,10 +1487,10 @@
 
 #define PIS(x) \
 	seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
-			stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
-			stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
-			stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
-			stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
+			stats->vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
+			stats->vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
+			stats->vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
+			stats->vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
 
 	seq_printf(s, "-- VC interrupts --\n");
 	PIS(CS);
@@ -1502,7 +1506,7 @@
 
 #define PIS(x) \
 	seq_printf(s, "%-20s %10d\n", #x, \
-			stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
+			stats->cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
 
 	seq_printf(s, "-- CIO interrupts --\n");
 	PIS(ERRSYNCESC1);
@@ -1527,6 +1531,8 @@
 	PIS(ULPSACTIVENOT_ALL1);
 #undef PIS
 
+	kfree(stats);
+
 	return 0;
 }
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/dss/dss.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -1151,46 +1151,39 @@
 	.has_lcd_clk_src	=	true,
 };
 
-static int dss_init_ports(struct dss_device *dss)
+static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports)
 {
 	struct platform_device *pdev = dss->pdev;
 	struct device_node *parent = pdev->dev.of_node;
 	struct device_node *port;
 	unsigned int i;
-	int r;
 
-	for (i = 0; i < dss->feat->num_ports; i++) {
+	for (i = 0; i < num_ports; i++) {
 		port = of_graph_get_port_by_id(parent, i);
 		if (!port)
 			continue;
 
 		switch (dss->feat->ports[i]) {
 		case OMAP_DISPLAY_TYPE_DPI:
-			r = dpi_init_port(dss, pdev, port, dss->feat->model);
-			if (r)
-				return r;
+			dpi_uninit_port(port);
 			break;
-
 		case OMAP_DISPLAY_TYPE_SDI:
-			r = sdi_init_port(dss, pdev, port);
-			if (r)
-				return r;
+			sdi_uninit_port(port);
 			break;
-
 		default:
 			break;
 		}
+		of_node_put(port);
 	}
-
-	return 0;
 }
 
-static void dss_uninit_ports(struct dss_device *dss)
+static int dss_init_ports(struct dss_device *dss)
 {
 	struct platform_device *pdev = dss->pdev;
 	struct device_node *parent = pdev->dev.of_node;
 	struct device_node *port;
-	int i;
+	unsigned int i;
+	int r;
 
 	for (i = 0; i < dss->feat->num_ports; i++) {
 		port = of_graph_get_port_by_id(parent, i);
@@ -1199,15 +1192,34 @@
 
 		switch (dss->feat->ports[i]) {
 		case OMAP_DISPLAY_TYPE_DPI:
-			dpi_uninit_port(port);
+			r = dpi_init_port(dss, pdev, port, dss->feat->model);
+			if (r)
+				goto error;
 			break;
+
 		case OMAP_DISPLAY_TYPE_SDI:
-			sdi_uninit_port(port);
+			r = sdi_init_port(dss, pdev, port);
+			if (r)
+				goto error;
 			break;
+
 		default:
 			break;
 		}
+		of_node_put(port);
 	}
+
+	return 0;
+
+error:
+	of_node_put(port);
+	__dss_uninit_ports(dss, i);
+	return r;
+}
+
+static void dss_uninit_ports(struct dss_device *dss)
+{
+	__dss_uninit_ports(dss, dss->feat->num_ports);
 }
 
 static int dss_video_pll_probe(struct dss_device *dss)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -192,7 +192,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);
 
@@ -217,6 +217,8 @@
 		kfree(n);
 	}
 
+put_node:
+	of_node_put(dss);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -451,11 +451,12 @@
 	if (omap_state->manually_updated)
 		return;
 
-	spin_lock_irq(&crtc->dev->event_lock);
 	drm_crtc_vblank_on(crtc);
+
 	ret = drm_crtc_vblank_get(crtc);
 	WARN_ON(ret != 0);
 
+	spin_lock_irq(&crtc->dev->event_lock);
 	omap_crtc_arm_event(crtc);
 	spin_unlock_irq(&crtc->dev->event_lock);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -891,6 +891,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-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/omap_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -216,8 +216,8 @@
 	} else if (output->bridge) {
 		struct drm_bridge *bridge = output->bridge;
 
-		while (bridge->next)
-			bridge = bridge->next;
+		while (drm_bridge_get_next_bridge(bridge))
+			bridge = drm_bridge_get_next_bridge(bridge);
 
 		node = bridge->of_node;
 	} else if (output->panel) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ linux-ein-5.4.0/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -125,7 +125,8 @@
 	for (dssdev = output; dssdev; dssdev = dssdev->next)
 		omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
 
-	for (bridge = output->bridge; bridge; bridge = bridge->next) {
+	for (bridge = output->bridge; bridge;
+	     bridge = drm_bridge_get_next_bridge(bridge)) {
 		if (!bridge->timings)
 			continue;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/Kconfig
@@ -141,6 +141,7 @@
 	depends on OF
 	depends on I2C
 	depends on BACKLIGHT_CLASS_DEVICE
+	select CRC32
 	help
 	  The panel is used with different sizes LCDs, from 480x272 to
 	  1280x800, and 24 bit per pixel.
@@ -355,4 +356,13 @@
 	help
 	  Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
 	  Video Mode panel
+
+config DRM_PANEL_AVD_TT101WX_CN
+        tristate "AVD-TT101WX-CN MIPI-DSI LCD"
+        depends on OF
+	depends on DRM_MIPI_DSI
+        depends on BACKLIGHT_CLASS_DEVICE
+        help
+          Say Y here if you want to enable support for the AVD
+          101WX-CN controller for 1280x800 LCD panel
 endmenu
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/Makefile
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/Makefile
@@ -38,3 +38,4 @@
 obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
 obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
 obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
+obj-$(CONFIG_DRM_PANEL_AVD_TT101WX_CN) += panel-avd-tt101wx-cn-101-a.o
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-arm-versatile.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-arm-versatile.c
@@ -350,9 +350,8 @@
 			dev_info(dev, "panel mounted on IB2 daughterboard\n");
 	}
 
-	drm_panel_init(&vpanel->panel);
-	vpanel->panel.dev = dev;
-	vpanel->panel.funcs = &versatile_panel_drm_funcs;
+	drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&vpanel->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-avd-tt101wx-cn-101-a.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-avd-tt101wx-cn-101-a.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for panels based on Sitronix ST7703 controller, souch as:
+ *
+ * - Rocktech jh057n00900 5.5" MIPI-DSI panel
+ *
+ * Copyright (C) Purism SPC 2019
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/display_timing.h>
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define DRV_NAME "panel-avd-tt101wx-cn-101-a"
+
+/* Manufacturer specific Commands send via DSI */
+#define ST7703_CMD_ALL_PIXEL_OFF 0x22
+#define ST7703_CMD_ALL_PIXEL_ON	 0x23
+#define ST7703_CMD_SETDISP	 0xB2
+#define ST7703_CMD_SETRGBIF	 0xB3
+#define ST7703_CMD_SETCYC	 0xB4
+#define ST7703_CMD_SETBGP	 0xB5
+#define ST7703_CMD_SETVCOM	 0xB6
+#define ST7703_CMD_SETOTP	 0xB7
+#define ST7703_CMD_SETPOWER_EXT	 0xB8
+#define ST7703_CMD_SETEXTC	 0xB9
+#define ST7703_CMD_SETMIPI	 0xBA
+#define ST7703_CMD_SETVDC	 0xBC
+#define ST7703_CMD_UNKNOWN_BF	 0xBF
+#define ST7703_CMD_SETSCR	 0xC0
+#define ST7703_CMD_SETPOWER	 0xC1
+#define ST7703_CMD_SETPANEL	 0xCC
+#define ST7703_CMD_UNKNOWN_C6	 0xC6
+#define ST7703_CMD_SETGAMMA	 0xE0
+#define ST7703_CMD_SETEQ	 0xE3
+#define ST7703_CMD_SETGIP1	 0xE9
+#define ST7703_CMD_SETGIP2	 0xEA
+
+struct st7703 {
+	struct device *dev;
+	struct drm_panel panel;
+	struct gpio_desc *reset_gpio;
+	bool prepared;
+
+	struct dentry *debugfs;
+	const struct st7703_panel_desc *desc;
+};
+
+struct st7703_panel_desc {
+	const struct drm_display_mode *mode;
+	unsigned int lanes;
+	unsigned long mode_flags;
+	enum mipi_dsi_pixel_format format;
+	int (*init_sequence)(struct st7703 *ctx);
+};
+
+static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
+{
+	return container_of(panel, struct st7703, panel);
+}
+
+#define dsi_generic_write_seq(dsi, seq...) do {				\
+		static const u8 d[] = { seq };				\
+		int ret;						\
+		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
+		if (ret < 0)						\
+			return ret;					\
+	} while (0)
+
+#define dsi_dcs_write_seq(dsi, cmd, seq...) do {			\
+		static const u8 d[] = { seq };				\
+		int ret;						\
+		ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));	\
+		if (ret < 0)						\
+			return ret;					\
+	} while (0)
+
+
+static int avd_tt101wx_cn_101_a_init_sequence(struct st7703 *ctx)
+{
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+	/*
+	 * Init sequence was supplied by the panel vendor.
+	 */
+
+	/* Magic sequence to unlock user commands below. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x84);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
+			  0x33,
+			  0x81,
+			  0x05,
+			  0xF9,
+			  0x0E,
+			  0x0E,
+			  /* The rest is undocumented in ST7703 datasheet */
+			  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			  0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x00,
+			  0x4F, 0x01, 0x00, 0x00, 0x37);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
+			  0xA8);
+
+	/* RGB I/F porch timing */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
+			  0x00,
+			  0x00,
+			  0x00,
+			  0x00,
+			  /* The rest is undocumented in ST7703 datasheet */
+			  0x07, 0x0B,
+			  0x1E, 0x1E);
+
+	/* Source driving settings. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
+			  0x73, /* N_POPON */
+			  0x73, /* N_NOPON */
+			  0x50, /* I_POPON */
+			  0x50, /* I_NOPON */
+			  0x80,
+			  0x00, /* SCR[31,24] */
+			  0x08, /* SCR[15,8] */
+			  0x70, /* SCR[7,0] */
+			  0x00  /* Undocumented */);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x82);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
+
+	/* Set display resolution. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
+			  0x40,
+			  0x08);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
+			  0x03,
+			  0x03,
+			  0x00,
+			  0x00,
+			  0x03,
+			  0x03,
+			  0x00,
+			  0x00,
+			  0x00,
+			  0xC0);
+
+	/* Undocumented command. */
+	dsi_dcs_write_seq(dsi, 0xB1, 0x22, 0x85, 0x23, 0x1E, 0x1E, 0x22, 0x77, 0x04, 0xDB, 0x4C);
+
+	/* Reference voltage. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
+			  0x0F,
+			  0x0f);
+	msleep(20);
+
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
+			  0x1C,
+			  0x1C);
+
+	/* This command is to set forward GIP timing. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
+			  0x02, 0x00, 0x01, 0x05, 0x0F, 0xA1, 0xA0, 0x12,
+			  0x31, 0x23, 0x4F, 0x03, 0xA1, 0x54, 0x47, 0x08,
+			  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
+			  0x0C, 0x00, 0x00, 0x00, 0xFF, 0x11, 0x88, 0x88,
+			  0x88, 0xFF, 0x83, 0x31, 0x17, 0x75, 0x58, 0xFF,
+			  0x00, 0x88, 0x88, 0x88, 0xFF, 0x82, 0x20, 0x06,
+			  0x64, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+	/* This command is to set backward GIP timing. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
+			  0x07, 0x1A, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00,
+			  0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x88, 0xFF,
+			  0x88, 0xFF, 0x84, 0x46, 0x60, 0x02, 0x28, 0x88,
+			  0x11, 0x88, 0xFF, 0x88, 0xFF, 0x85, 0x57, 0x71,
+			  0x13, 0x38, 0x23, 0x10, 0x00, 0x00, 0x01, 0x6C,
+			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xA1,
+			  0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B);
+
+	/* Adjust the gamma characteristics of the panel. */
+	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
+			  0x0F, 0x25, 0x29, 0x29, 0x2D, 0x3F, 0x56, 0x42,
+			  0x05, 0x0B, 0x0C, 0x12, 0x14, 0x12, 0x12, 0x10,
+			  0x18, 0x0F, 0x25, 0x29, 0x29, 0x2D, 0x3F, 0x56,
+			  0x42, 0x05, 0x0B, 0x0C, 0x12, 0x14, 0x12, 0x12,
+			  0x10, 0x18);
+
+	dsi_dcs_write_seq(dsi,0x11);
+	msleep(300);
+	dsi_dcs_write_seq(dsi,0x29);
+	msleep(50);
+
+	return 0;
+}
+
+static const struct drm_display_mode avd_tt101wx_cn_101_a_mode = {
+	.hdisplay    = 800,
+	.hsync_start = 800 + 40,
+	.hsync_end   = 800 + 40 + 40,
+	.htotal	     = 800 + 40 + 40 + 20,
+	.vdisplay    = 1280,
+	.vsync_start = 1280 + 12,
+	.vsync_end   = 1280 + 16 + 12,
+	.vtotal	     = 1280 + 16 + 12 + 3,
+	.clock	     = 65000,
+	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+	.width_mm    = 68,
+	.height_mm   = 136,
+};
+
+static const struct st7703_panel_desc avd_tt101wx_cn_101_a_desc = {
+	.mode = &avd_tt101wx_cn_101_a_mode,
+	.lanes = 4,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+	.format = MIPI_DSI_FMT_RGB888,
+	.init_sequence = avd_tt101wx_cn_101_a_init_sequence,
+};
+
+static int st7703_enable(struct drm_panel *panel)
+{
+	struct st7703 *ctx = panel_to_st7703(panel);
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+	int ret;
+
+	ret = ctx->desc->init_sequence(ctx);
+	if (ret < 0) {
+		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
+		return ret;
+	}
+
+	msleep(20);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+	if (ret < 0) {
+		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+		return ret;
+	}
+
+	/* It takes the controller 120 msec to wake up after sleep. */
+	msleep(120);
+
+	ret = mipi_dsi_dcs_set_display_on(dsi);
+	if (ret)
+		return ret;
+
+	dev_dbg(ctx->dev, "Panel init sequence done\n");
+
+	return 0;
+}
+
+static int st7703_disable(struct drm_panel *panel)
+{
+	struct st7703 *ctx = panel_to_st7703(panel);
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+	int ret;
+
+	ret = mipi_dsi_dcs_set_display_off(dsi);
+	if (ret < 0)
+		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
+
+	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+	if (ret < 0)
+		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
+	/* It takes the controller 120 msec to enter sleep mode. */
+	msleep(120);
+
+	return 0;
+}
+
+static int st7703_unprepare(struct drm_panel *panel)
+{
+	struct st7703 *ctx = panel_to_st7703(panel);
+
+	if (!ctx->prepared)
+		return 0;
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	ctx->prepared = false;
+
+	return 0;
+}
+
+static int st7703_prepare(struct drm_panel *panel)
+{
+	struct st7703 *ctx = panel_to_st7703(panel);
+	int ret;
+
+	if (ctx->prepared)
+		return 0;
+
+	dev_dbg(ctx->dev, "Resetting the panel\n");
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	/* Give power supplies time to stabilize before deasserting reset. */
+	usleep_range(10000, 20000);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(15000, 20000);
+
+	ctx->prepared = true;
+
+	return 0;
+
+}
+
+static const u32 mantix_bus_formats[] = {
+	MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static int st7703_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct st7703 *ctx = panel_to_st7703(panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
+	if (!mode) {
+		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+			drm_mode_vrefresh(ctx->desc->mode));
+		return -ENOMEM;
+	}
+
+	drm_mode_set_name(mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+	drm_mode_probed_add(connector, mode);
+	drm_display_info_set_bus_formats(&connector->display_info,
+					 mantix_bus_formats,
+					 ARRAY_SIZE(mantix_bus_formats));
+	return 1;
+}
+
+static const struct drm_panel_funcs st7703_drm_funcs = {
+	.disable   = st7703_disable,
+	.unprepare = st7703_unprepare,
+	.prepare   = st7703_prepare,
+	.enable	   = st7703_enable,
+	.get_modes = st7703_get_modes,
+};
+
+static int allpixelson_set(void *data, u64 val)
+{
+	struct st7703 *ctx = data;
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+	dev_dbg(ctx->dev, "Setting all pixels on\n");
+	dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
+	msleep(val * 1000);
+	/* Reset the panel to get video back */
+	drm_panel_disable(&ctx->panel);
+	drm_panel_unprepare(&ctx->panel);
+	drm_panel_prepare(&ctx->panel);
+	drm_panel_enable(&ctx->panel);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
+			allpixelson_set, "%llu\n");
+
+static void st7703_debugfs_init(struct st7703 *ctx)
+{
+	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
+
+	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
+			    &allpixelson_fops);
+}
+
+static void st7703_debugfs_remove(struct st7703 *ctx)
+{
+	debugfs_remove_recursive(ctx->debugfs);
+	ctx->debugfs = NULL;
+}
+
+static int st7703_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct st7703 *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio)) {
+		dev_err(dev, "cannot get reset gpio\n");
+		return PTR_ERR(ctx->reset_gpio);
+	}
+
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	ctx->dev = dev;
+	ctx->desc = of_device_get_match_data(dev);
+
+	dsi->mode_flags = ctx->desc->mode_flags;
+	dsi->format = ctx->desc->format;
+	dsi->lanes = ctx->desc->lanes;
+
+	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs, DRM_MODE_CONNECTOR_DSI);
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	drm_panel_add(&ctx->panel);
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
+		drm_panel_remove(&ctx->panel);
+		return ret;
+	}
+
+	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+		 drm_mode_vrefresh(ctx->desc->mode),
+		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+
+	st7703_debugfs_init(ctx);
+	return 0;
+}
+
+static void st7703_shutdown(struct mipi_dsi_device *dsi)
+{
+	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
+	int ret;
+
+	ret = drm_panel_unprepare(&ctx->panel);
+	if (ret < 0)
+		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
+
+	ret = drm_panel_disable(&ctx->panel);
+	if (ret < 0)
+		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
+}
+
+static int st7703_remove(struct mipi_dsi_device *dsi)
+{
+	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
+	int ret;
+
+	st7703_shutdown(dsi);
+
+	ret = mipi_dsi_detach(dsi);
+	if (ret < 0)
+		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+	drm_panel_remove(&ctx->panel);
+
+	st7703_debugfs_remove(ctx);
+
+	return 0;
+}
+
+static const struct of_device_id st7703_of_match[] = {
+	{ .compatible = "msc,avdtt101wxcn", .data = &avd_tt101wx_cn_101_a_desc },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, st7703_of_match);
+
+static struct mipi_dsi_driver st7703_driver = {
+	.probe	= st7703_probe,
+	.remove = st7703_remove,
+	.shutdown = st7703_shutdown,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = st7703_of_match,
+	},
+};
+module_mipi_dsi_driver(st7703_driver);
+
+MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
@@ -204,9 +204,8 @@
 	mipi_dsi_set_drvdata(dsi, ctx);
 	ctx->dsi = dsi;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = &dsi->dev;
-	ctx->panel.funcs = &feiyang_funcs;
+	drm_panel_init(&ctx->panel, &dsi->dev, &feiyang_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");
 	if (IS_ERR(ctx->dvdd)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
@@ -895,9 +895,8 @@
 		ili->input = ili->conf->input;
 	}
 
-	drm_panel_init(&ili->panel);
-	ili->panel.dev = dev;
-	ili->panel.funcs = &ili9322_drm_funcs;
+	drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&ili->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
@@ -433,9 +433,8 @@
 	mipi_dsi_set_drvdata(dsi, ctx);
 	ctx->dsi = dsi;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = &dsi->dev;
-	ctx->panel.funcs = &ili9881c_funcs;
+	drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ctx->power = devm_regulator_get(&dsi->dev, "power");
 	if (IS_ERR(ctx->power)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-innolux-p079zca.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-innolux-p079zca.c
@@ -487,9 +487,8 @@
 	if (IS_ERR(innolux->backlight))
 		return PTR_ERR(innolux->backlight);
 
-	drm_panel_init(&innolux->base);
-	innolux->base.funcs = &innolux_panel_funcs;
-	innolux->base.dev = dev;
+	drm_panel_init(&innolux->base, dev, &innolux_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	err = drm_panel_add(&innolux->base);
 	if (err < 0)
@@ -509,6 +508,7 @@
 static int innolux_panel_probe(struct mipi_dsi_device *dsi)
 {
 	const struct panel_desc *desc;
+	struct innolux_panel *innolux;
 	int err;
 
 	desc = of_device_get_match_data(&dsi->dev);
@@ -520,7 +520,14 @@
 	if (err < 0)
 		return err;
 
-	return mipi_dsi_attach(dsi);
+	err = mipi_dsi_attach(dsi);
+	if (err < 0) {
+		innolux = mipi_dsi_get_drvdata(dsi);
+		innolux_panel_del(innolux);
+		return err;
+	}
+
+	return 0;
 }
 
 static int innolux_panel_remove(struct mipi_dsi_device *dsi)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
@@ -437,9 +437,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&jdi->base);
-	jdi->base.funcs = &jdi_panel_funcs;
-	jdi->base.dev = &jdi->dsi->dev;
+	drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ret = drm_panel_add(&jdi->base);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
@@ -391,9 +391,8 @@
 	if (IS_ERR(kingdisplay->backlight))
 		return PTR_ERR(kingdisplay->backlight);
 
-	drm_panel_init(&kingdisplay->base);
-	kingdisplay->base.funcs = &kingdisplay_panel_funcs;
-	kingdisplay->base.dev = &kingdisplay->link->dev;
+	drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,
+		       &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI);
 
 	return drm_panel_add(&kingdisplay->base);
 }
@@ -424,7 +423,13 @@
 	if (err < 0)
 		return err;
 
-	return mipi_dsi_attach(dsi);
+	err = mipi_dsi_attach(dsi);
+	if (err < 0) {
+		kingdisplay_panel_del(kingdisplay);
+		return err;
+	}
+
+	return 0;
 }
 
 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-lg-lb035q02.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-lg-lb035q02.c
@@ -196,9 +196,8 @@
 	if (ret < 0)
 		return ret;
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &lcd->spi->dev;
-	lcd->panel.funcs = &lb035q02_funcs;
+	drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&lcd->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-lg-lg4573.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-lg-lg4573.c
@@ -259,9 +259,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = &spi->dev;
-	ctx->panel.funcs = &lg4573_drm_funcs;
+	drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&ctx->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-lvds.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-lvds.c
@@ -197,7 +197,6 @@
 static int panel_lvds_probe(struct platform_device *pdev)
 {
 	struct panel_lvds *lvds;
-	struct device_node *np;
 	int ret;
 
 	lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
@@ -243,14 +242,9 @@
 		return ret;
 	}
 
-	np = of_parse_phandle(lvds->dev->of_node, "backlight", 0);
-	if (np) {
-		lvds->backlight = of_find_backlight_by_node(np);
-		of_node_put(np);
-
-		if (!lvds->backlight)
-			return -EPROBE_DEFER;
-	}
+	lvds->backlight = devm_of_find_backlight(lvds->dev);
+	if (IS_ERR(lvds->backlight))
+		return PTR_ERR(lvds->backlight);
 
 	/*
 	 * TODO: Handle all power supplies specified in the DT node in a generic
@@ -260,20 +254,15 @@
 	 */
 
 	/* Register the panel. */
-	drm_panel_init(&lvds->panel);
-	lvds->panel.dev = lvds->dev;
-	lvds->panel.funcs = &panel_lvds_funcs;
+	drm_panel_init(&lvds->panel, lvds->dev, &panel_lvds_funcs,
+		       DRM_MODE_CONNECTOR_LVDS);
 
 	ret = drm_panel_add(&lvds->panel);
 	if (ret < 0)
-		goto error;
+		return ret;
 
 	dev_set_drvdata(lvds->dev, lvds);
 	return 0;
-
-error:
-	put_device(&lvds->backlight->dev);
-	return ret;
 }
 
 static int panel_lvds_remove(struct platform_device *pdev)
@@ -284,9 +273,6 @@
 
 	panel_lvds_disable(&lvds->panel);
 
-	if (lvds->backlight)
-		put_device(&lvds->backlight->dev);
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
@@ -205,9 +205,8 @@
 	if (ret < 0)
 		return ret;
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &lcd->spi->dev;
-	lcd->panel.funcs = &nl8048_funcs;
+	drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&lcd->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-novatek-nt39016.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-novatek-nt39016.c
@@ -292,9 +292,8 @@
 		return err;
 	}
 
-	drm_panel_init(&panel->drm_panel);
-	panel->drm_panel.dev = dev;
-	panel->drm_panel.funcs = &nt39016_funcs;
+	drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	err = drm_panel_add(&panel->drm_panel);
 	if (err < 0) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
@@ -288,9 +288,8 @@
 	if (IS_ERR(lcd->backlight))
 		return PTR_ERR(lcd->backlight);
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = dev;
-	lcd->panel.funcs = &lcd_olinuxino_funcs;
+	drm_panel_init(&lcd->panel, dev, &lcd_olinuxino_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&lcd->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -455,12 +455,11 @@
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 			  MIPI_DSI_MODE_LPM;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &otm8009a_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &otm8009a_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev),
-						     dsi->host->dev, ctx,
+						     dev, ctx,
 						     &otm8009a_backlight_ops,
 						     NULL);
 	if (IS_ERR(ctx->bl_dev)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
@@ -166,9 +166,8 @@
 	if (IS_ERR(osd101t2587->backlight))
 		return PTR_ERR(osd101t2587->backlight);
 
-	drm_panel_init(&osd101t2587->base);
-	osd101t2587->base.funcs = &osd101t2587_panel_funcs;
-	osd101t2587->base.dev = &osd101t2587->dsi->dev;
+	drm_panel_init(&osd101t2587->base, &osd101t2587->dsi->dev,
+		       &osd101t2587_panel_funcs, DRM_MODE_CONNECTOR_DSI);
 
 	return drm_panel_add(&osd101t2587->base);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -223,9 +223,8 @@
 			return -EPROBE_DEFER;
 	}
 
-	drm_panel_init(&wuxga_nt->base);
-	wuxga_nt->base.funcs = &wuxga_nt_panel_funcs;
-	wuxga_nt->base.dev = &wuxga_nt->dsi->dev;
+	drm_panel_init(&wuxga_nt->base, &wuxga_nt->dsi->dev,
+		       &wuxga_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
 
 	ret = drm_panel_add(&wuxga_nt->base);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -232,7 +232,7 @@
 
 	ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
 	if (ret)
-		dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret);
+		dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret);
 }
 
 static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val)
@@ -268,7 +268,7 @@
 	return 0;
 }
 
-static int rpi_touchscreen_enable(struct drm_panel *panel)
+static int rpi_touchscreen_prepare(struct drm_panel *panel)
 {
 	struct rpi_touchscreen *ts = panel_to_ts(panel);
 	int i;
@@ -298,6 +298,13 @@
 	rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01);
 	msleep(100);
 
+	return 0;
+}
+
+static int rpi_touchscreen_enable(struct drm_panel *panel)
+{
+	struct rpi_touchscreen *ts = panel_to_ts(panel);
+
 	/* Turn on the backlight. */
 	rpi_touchscreen_i2c_write(ts, REG_PWM, 255);
 
@@ -352,7 +359,7 @@
 static const struct drm_panel_funcs rpi_touchscreen_funcs = {
 	.disable = rpi_touchscreen_disable,
 	.unprepare = rpi_touchscreen_noop,
-	.prepare = rpi_touchscreen_noop,
+	.prepare = rpi_touchscreen_prepare,
 	.enable = rpi_touchscreen_enable,
 	.get_modes = rpi_touchscreen_get_modes,
 };
@@ -426,8 +433,8 @@
 		return PTR_ERR(ts->dsi);
 	}
 
-	ts->base.dev = dev;
-	ts->base.funcs = &rpi_touchscreen_funcs;
+	drm_panel_init(&ts->base, dev, &rpi_touchscreen_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	/* This appears last, as it's what will unblock the DSI host
 	 * driver's component bind function.
@@ -452,7 +459,6 @@
 	drm_panel_remove(&ts->base);
 
 	mipi_dsi_device_unregister(ts->dsi);
-	kfree(ts->dsi);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-raydium-rm67191.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-raydium-rm67191.c
@@ -606,9 +606,8 @@
 	if (ret)
 		return ret;
 
-	drm_panel_init(&panel->panel);
-	panel->panel.funcs = &rad_panel_funcs;
-	panel->panel.dev = dev;
+	drm_panel_init(&panel->panel, dev, &rad_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 	dev_set_drvdata(dev, panel);
 
 	ret = drm_panel_add(&panel->panel);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-raydium-rm68200.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-raydium-rm68200.c
@@ -404,9 +404,8 @@
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 			  MIPI_DSI_MODE_LPM;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &rm68200_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	drm_panel_add(&ctx->panel);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
@@ -343,9 +343,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &jh057n_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &jh057n_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	drm_panel_add(&ctx->panel);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
@@ -173,9 +173,8 @@
 	mipi_dsi_set_drvdata(dsi, ctx);
 	ctx->dsi = dsi;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = &dsi->dev;
-	ctx->panel.funcs = &rb070d30_panel_funcs;
+	drm_panel_init(&ctx->panel, &dsi->dev, &rb070d30_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(ctx->gpios.reset)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-ld9040.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-ld9040.c
@@ -351,9 +351,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &ld9040_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&ctx->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
@@ -215,9 +215,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&s6->panel);
-	s6->panel.dev = dev;
-	s6->panel.funcs = &s6d16d0_drm_funcs;
+	drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ret = drm_panel_add(&s6->panel);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -732,9 +732,8 @@
 	ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
 	ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &s6e3ha2_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ret = drm_panel_add(&ctx->panel);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
@@ -466,9 +466,8 @@
 		return PTR_ERR(ctx->reset_gpio);
 	}
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &s6e63j0x03_funcs;
+	drm_panel_init(&ctx->panel, dev, &s6e63j0x03_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx,
 						&s6e63j0x03_bl_ops, NULL);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
@@ -473,9 +473,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &s6e63m0_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	ret = s6e63m0_backlight_register(ctx);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
@@ -1017,9 +1017,8 @@
 
 	ctx->brightness = GAMMA_LEVEL_NUM - 1;
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &s6e8aa0_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	ret = drm_panel_add(&ctx->panel);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
@@ -274,9 +274,8 @@
 			return -EPROBE_DEFER;
 	}
 
-	drm_panel_init(&panel->base);
-	panel->base.dev = dev;
-	panel->base.funcs = &seiko_panel_funcs;
+	drm_panel_init(&panel->base, dev, &seiko_panel_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	err = drm_panel_add(&panel->base);
 	if (err < 0)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -329,9 +329,8 @@
 	if (IS_ERR(sharp->backlight))
 		return PTR_ERR(sharp->backlight);
 
-	drm_panel_init(&sharp->base);
-	sharp->base.funcs = &sharp_panel_funcs;
-	sharp->base.dev = &sharp->link1->dev;
+	drm_panel_init(&sharp->base, &sharp->link1->dev, &sharp_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	return drm_panel_add(&sharp->base);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
@@ -185,9 +185,8 @@
 		return PTR_ERR(lcd->ud_gpio);
 	}
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &pdev->dev;
-	lcd->panel.funcs = &ls037v7dw01_funcs;
+	drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&lcd->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
@@ -264,9 +264,8 @@
 	if (IS_ERR(sharp_nt->backlight))
 		return PTR_ERR(sharp_nt->backlight);
 
-	drm_panel_init(&sharp_nt->base);
-	sharp_nt->base.funcs = &sharp_nt_panel_funcs;
-	sharp_nt->base.dev = &sharp_nt->dsi->dev;
+	drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
+		       &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
 
 	return drm_panel_add(&sharp_nt->base);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-simple.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-simple.c
@@ -94,6 +94,7 @@
 
 	u32 bus_format;
 	u32 bus_flags;
+	int connector_type;
 };
 
 struct panel_simple {
@@ -464,9 +465,8 @@
 	if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
 		panel_simple_parse_panel_timing_node(dev, panel, &dt);
 
-	drm_panel_init(&panel->base);
-	panel->base.dev = dev;
-	panel->base.funcs = &panel_simple_funcs;
+	drm_panel_init(&panel->base, dev, &panel_simple_funcs,
+		       desc->connector_type);
 
 	err = drm_panel_add(&panel->base);
 	if (err < 0)
@@ -531,8 +531,8 @@
 	.num_modes = 1,
 	.bpc = 8,
 	.size = {
-		.width = 105,
-		.height = 67,
+		.width = 99,
+		.height = 58,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
@@ -833,6 +833,7 @@
 		.unprepare = 1000,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing auo_g185han01_timings = {
@@ -862,6 +863,7 @@
 		.unprepare = 1000,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing auo_p320hvn03_timings = {
@@ -890,6 +892,7 @@
 		.unprepare = 500,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode auo_t215hvn01_mode = {
@@ -916,7 +919,9 @@
 	.delay = {
 		.disable = 5,
 		.unprepare = 1000,
-	}
+	},
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode avic_tm070ddh03_mode = {
@@ -1178,6 +1183,31 @@
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
 };
 
+static const struct drm_display_mode dlc_dlc0430dcp10rf_2_mode = {
+	.clock = 33300,
+	.hdisplay = 800,
+	.hsync_start = 800 + 40,
+	.hsync_end = 800 + 10 + 40,
+	.htotal = 800 + 30 + 40 + 10,
+	.vdisplay = 480,
+	.vsync_start = 480 + 8,
+	.vsync_end = 480 + 5 + 8,
+	.vtotal = 480 + 31 + 8 + 5,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc dlc_dlc0430dcp10rf_2 = {
+	.modes = &dlc_dlc0430dcp10rf_2_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width = 120,
+		.height = 76,
+	},
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
+};
+
 static const struct display_timing dlc_dlc0700yzg_1_timing = {
 	.pixelclock = { 45000000, 51200000, 57000000 },
 	.hactive = { 1024, 1024, 1024 },
@@ -1205,6 +1235,7 @@
 		.disable = 200,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing dlc_dlc1010gig_timing = {
@@ -1235,6 +1266,7 @@
 		.unprepare = 60,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode edt_et035012dm6_mode = {
@@ -1501,6 +1533,7 @@
 		.height = 94,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing hannstar_hsd100pxn1_timing = {
@@ -1525,6 +1558,7 @@
 		.height = 152,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
@@ -1577,6 +1611,7 @@
 		.height = 54,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+	.connector_type = DRM_MODE_CONNECTOR_DPI,
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
 };
 
@@ -1619,7 +1654,7 @@
 static const struct panel_desc innolux_g070y2_l01 = {
 	.timings = &innolux_g070y2_l01_timing,
 	.num_timings = 1,
-	.bpc = 6,
+	.bpc = 8,
 	.size = {
 		.width = 152,
 		.height = 91,
@@ -1631,18 +1666,19 @@
 		.unprepare = 800,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing innolux_g101ice_l01_timing = {
 	.pixelclock = { 60400000, 71100000, 74700000 },
 	.hactive = { 1280, 1280, 1280 },
-	.hfront_porch = { 41, 80, 100 },
-	.hback_porch = { 40, 79, 99 },
-	.hsync_len = { 1, 1, 1 },
+	.hfront_porch = { 30, 60, 70 },
+	.hback_porch = { 30, 60, 70 },
+	.hsync_len = { 22, 40, 60 },
 	.vactive = { 800, 800, 800 },
-	.vfront_porch = { 5, 11, 14 },
-	.vback_porch = { 4, 11, 14 },
-	.vsync_len = { 1, 1, 1 },
+	.vfront_porch = { 3, 8, 14 },
+	.vback_porch = { 3, 8, 14 },
+	.vsync_len = { 4, 7, 12 },
 	.flags = DISPLAY_FLAGS_DE_HIGH,
 };
 
@@ -1659,6 +1695,8 @@
 		.disable = 200,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.bus_flags = DRM_BUS_FLAG_DE_HIGH,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing innolux_g121i1_l01_timing = {
@@ -1686,6 +1724,7 @@
 		.disable = 20,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode innolux_g121x1_l03_mode = {
@@ -1869,6 +1908,7 @@
 		.height = 109,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing kyo_tcg121xglp_timing = {
@@ -1893,6 +1933,7 @@
 		.height = 184,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode lemaker_bl035_rgb_002_mode = {
@@ -1935,12 +1976,13 @@
 static const struct panel_desc lg_lb070wv8 = {
 	.modes = &lg_lb070wv8_mode,
 	.num_modes = 1,
-	.bpc = 16,
+	.bpc = 8,
 	.size = {
 		.width = 151,
 		.height = 91,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
@@ -2048,6 +2090,40 @@
 	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 };
 
+static const struct drm_display_mode logicpd_type_28_mode = {
+	.clock = 9000,
+	.hdisplay = 480,
+	.hsync_start = 480 + 3,
+	.hsync_end = 480 + 3 + 42,
+	.htotal = 480 + 3 + 42 + 2,
+
+	.vdisplay = 272,
+	.vsync_start = 272 + 2,
+	.vsync_end = 272 + 2 + 11,
+	.vtotal = 272 + 2 + 11 + 3,
+	.vrefresh = 60,
+	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static const struct panel_desc logicpd_type_28 = {
+	.modes = &logicpd_type_28_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width = 105,
+		.height = 67,
+	},
+	.delay = {
+		.prepare = 200,
+		.enable = 200,
+		.unprepare = 200,
+		.disable = 200,
+	},
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
+		     DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE,
+};
+
 static const struct panel_desc mitsubishi_aa070mc01 = {
 	.modes = &mitsubishi_aa070mc01_mode,
 	.num_modes = 1,
@@ -2063,6 +2139,7 @@
 		.disable = 400,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH,
 };
 
@@ -2091,6 +2168,7 @@
 		.disable = 50,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode nec_nl4827hc19_05b_mode = {
@@ -2193,6 +2271,7 @@
 		.unprepare = 500,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode nvd_9128_mode = {
@@ -2216,6 +2295,7 @@
 		.height = 88,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing okaya_rs800480t_7x0gp_timing = {
@@ -2348,12 +2428,12 @@
 static const struct panel_desc ortustech_com43h4m85ulc = {
 	.modes = &ortustech_com43h4m85ulc_mode,
 	.num_modes = 1,
-	.bpc = 8,
+	.bpc = 6,
 	.size = {
 		.width = 56,
 		.height = 93,
 	},
-	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
 };
 
@@ -2628,6 +2708,7 @@
 		.height = 136,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing sharp_lq123p1jx31_timing = {
@@ -2807,6 +2888,7 @@
 		.height = 95,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct display_timing tianma_tm070rvhg71_timing = {
@@ -2831,6 +2913,7 @@
 		.height = 86,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode ti_nspire_cx_lcd_mode[] = {
@@ -2913,6 +2996,7 @@
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode tpk_f07a_0102_mode = {
@@ -2983,6 +3067,7 @@
 		.height = 91,
 	},
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+	.connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct panel_desc urt_umsh_8596md_parallel = {
@@ -3156,6 +3241,9 @@
 	}, {
 		.compatible = "dataimage,scf0700c48ggu18",
 		.data = &dataimage_scf0700c48ggu18,
+	},{
+		.compatible = "dlc,dlc0430dcp10rf-2",
+		.data = &dlc_dlc0430dcp10rf_2,
 	}, {
 		.compatible = "dlc,dlc0700yzg-1",
 		.data = &dlc_dlc0700yzg_1,
@@ -3265,6 +3353,9 @@
 		.compatible = "lg,lp129qe",
 		.data = &lg_lp129qe,
 	}, {
+		.compatible = "logicpd,type28",
+		.data = &logicpd_type_28,
+	}, {
 		.compatible = "mitsubishi,aa070mc01-ca1",
 		.data = &mitsubishi_aa070mc01,
 	}, {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sitronix-st7701.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sitronix-st7701.c
@@ -369,7 +369,8 @@
 	if (IS_ERR(st7701->backlight))
 		return PTR_ERR(st7701->backlight);
 
-	drm_panel_init(&st7701->panel);
+	drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 
 	/**
 	 * Once sleep out has been issued, ST7701 IC required to wait 120ms
@@ -381,8 +382,6 @@
 	 * ts8550b and there is no valid documentation for that.
 	 */
 	st7701->sleep_delay = 120 + desc->panel_sleep_delay;
-	st7701->panel.funcs = &st7701_funcs;
-	st7701->panel.dev = &dsi->dev;
 
 	ret = drm_panel_add(&st7701->panel);
 	if (ret < 0)
@@ -392,7 +391,15 @@
 	st7701->dsi = dsi;
 	st7701->desc = desc;
 
-	return mipi_dsi_attach(dsi);
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		goto err_attach;
+
+	return 0;
+
+err_attach:
+	drm_panel_remove(&st7701->panel);
+	return ret;
 }
 
 static int st7701_dsi_remove(struct mipi_dsi_device *dsi)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -381,8 +381,8 @@
 	spi_set_drvdata(spi, ctx);
 	ctx->spi = spi;
 
-	ctx->panel.dev = &spi->dev;
-	ctx->panel.funcs = &st7789v_drm_funcs;
+	drm_panel_init(&ctx->panel, &spi->dev, &st7789v_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	ctx->power = devm_regulator_get(&spi->dev, "power");
 	if (IS_ERR(ctx->power))
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-sony-acx565akm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-sony-acx565akm.c
@@ -648,9 +648,8 @@
 			return ret;
 	}
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &lcd->spi->dev;
-	lcd->panel.funcs = &acx565akm_funcs;
+	drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	ret = drm_panel_add(&lcd->panel);
 	if (ret < 0) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
@@ -347,9 +347,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &lcd->spi->dev;
-	lcd->panel.funcs = &td028ttec1_funcs;
+	drm_panel_init(&lcd->panel, &lcd->spi->dev, &td028ttec1_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	return drm_panel_add(&lcd->panel);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
@@ -458,9 +458,8 @@
 		return ret;
 	}
 
-	drm_panel_init(&lcd->panel);
-	lcd->panel.dev = &lcd->spi->dev;
-	lcd->panel.funcs = &td043mtea1_funcs;
+	drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 
 	ret = drm_panel_add(&lcd->panel);
 	if (ret < 0) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-tpo-tpg110.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-tpo-tpg110.c
@@ -457,9 +457,8 @@
 	if (ret)
 		return ret;
 
-	drm_panel_init(&tpg->panel);
-	tpg->panel.dev = dev;
-	tpg->panel.funcs = &tpg110_drm_funcs;
+	drm_panel_init(&tpg->panel, dev, &tpg110_drm_funcs,
+		       DRM_MODE_CONNECTOR_DPI);
 	spi_set_drvdata(spi, tpg);
 
 	return drm_panel_add(&tpg->panel);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panel/panel-truly-nt35597.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -518,9 +518,8 @@
 	/* dual port */
 	gpiod_set_value(ctx->mode_gpio, 0);
 
-	drm_panel_init(&ctx->panel);
-	ctx->panel.dev = dev;
-	ctx->panel.funcs = &truly_nt35597_drm_funcs;
+	drm_panel_init(&ctx->panel, dev, &truly_nt35597_drm_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
 	drm_panel_add(&ctx->panel);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/Kconfig
@@ -3,7 +3,8 @@
 config DRM_PANFROST
 	tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)"
 	depends on DRM
-	depends on ARM || ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64)
+	depends on ARM || ARM64 || COMPILE_TEST
+	depends on !GENERIC_ATOMIC64    # for IOMMU_IO_PGTABLE_LPAE
 	depends on MMU
 	select DRM_SCHED
 	select IOMMU_SUPPORT
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_devfreq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_devfreq.c
@@ -53,8 +53,10 @@
 	if (err) {
 		dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate,
 			err);
-		regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt,
-				      pfdev->devfreq.cur_volt);
+		if (pfdev->regulator)
+			regulator_set_voltage(pfdev->regulator,
+					      pfdev->devfreq.cur_volt,
+					      pfdev->devfreq.cur_volt);
 		return err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -59,7 +59,8 @@
 	if (IS_ERR(pfdev->bus_clock)) {
 		dev_err(pfdev->dev, "get bus_clock failed %ld\n",
 			PTR_ERR(pfdev->bus_clock));
-		return PTR_ERR(pfdev->bus_clock);
+		err = PTR_ERR(pfdev->bus_clock);
+		goto disable_clock;
 	}
 
 	if (pfdev->bus_clock) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -78,8 +78,10 @@
 static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
 		struct drm_file *file)
 {
+	struct panfrost_file_priv *priv = file->driver_priv;
 	struct panfrost_gem_object *bo;
 	struct drm_panfrost_create_bo *args = data;
+	struct panfrost_gem_mapping *mapping;
 
 	if (!args->size || args->pad ||
 	    (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP)))
@@ -95,7 +97,14 @@
 	if (IS_ERR(bo))
 		return PTR_ERR(bo);
 
-	args->offset = bo->node.start << PAGE_SHIFT;
+	mapping = panfrost_gem_mapping_get(bo, priv);
+	if (!mapping) {
+		drm_gem_object_put_unlocked(&bo->base.base);
+		return -EINVAL;
+	}
+
+	args->offset = mapping->mmnode.start << PAGE_SHIFT;
+	panfrost_gem_mapping_put(mapping);
 
 	return 0;
 }
@@ -119,6 +128,11 @@
 		  struct drm_panfrost_submit *args,
 		  struct panfrost_job *job)
 {
+	struct panfrost_file_priv *priv = file_priv->driver_priv;
+	struct panfrost_gem_object *bo;
+	unsigned int i;
+	int ret;
+
 	job->bo_count = args->bo_handle_count;
 
 	if (!job->bo_count)
@@ -130,9 +144,33 @@
 	if (!job->implicit_fences)
 		return -ENOMEM;
 
-	return drm_gem_objects_lookup(file_priv,
-				      (void __user *)(uintptr_t)args->bo_handles,
-				      job->bo_count, &job->bos);
+	ret = drm_gem_objects_lookup(file_priv,
+				     (void __user *)(uintptr_t)args->bo_handles,
+				     job->bo_count, &job->bos);
+	if (ret)
+		return ret;
+
+	job->mappings = kvmalloc_array(job->bo_count,
+				       sizeof(struct panfrost_gem_mapping *),
+				       GFP_KERNEL | __GFP_ZERO);
+	if (!job->mappings)
+		return -ENOMEM;
+
+	for (i = 0; i < job->bo_count; i++) {
+		struct panfrost_gem_mapping *mapping;
+
+		bo = to_panfrost_bo(job->bos[i]);
+		mapping = panfrost_gem_mapping_get(bo, priv);
+		if (!mapping) {
+			ret = -EINVAL;
+			break;
+		}
+
+		atomic_inc(&bo->gpu_usecount);
+		job->mappings[i] = mapping;
+	}
+
+	return ret;
 }
 
 /**
@@ -303,21 +341,26 @@
 	}
 
 	/* Don't allow mmapping of heap objects as pages are not pinned. */
-	if (to_panfrost_bo(gem_obj)->is_heap)
-		return -EINVAL;
+	if (to_panfrost_bo(gem_obj)->is_heap) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	ret = drm_gem_create_mmap_offset(gem_obj);
 	if (ret == 0)
 		args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
-	drm_gem_object_put_unlocked(gem_obj);
 
+out:
+	drm_gem_object_put_unlocked(gem_obj);
 	return ret;
 }
 
 static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data,
 			    struct drm_file *file_priv)
 {
+	struct panfrost_file_priv *priv = file_priv->driver_priv;
 	struct drm_panfrost_get_bo_offset *args = data;
+	struct panfrost_gem_mapping *mapping;
 	struct drm_gem_object *gem_obj;
 	struct panfrost_gem_object *bo;
 
@@ -328,18 +371,26 @@
 	}
 	bo = to_panfrost_bo(gem_obj);
 
-	args->offset = bo->node.start << PAGE_SHIFT;
-
+	mapping = panfrost_gem_mapping_get(bo, priv);
 	drm_gem_object_put_unlocked(gem_obj);
+
+	if (!mapping)
+		return -EINVAL;
+
+	args->offset = mapping->mmnode.start << PAGE_SHIFT;
+	panfrost_gem_mapping_put(mapping);
 	return 0;
 }
 
 static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 				  struct drm_file *file_priv)
 {
+	struct panfrost_file_priv *priv = file_priv->driver_priv;
 	struct drm_panfrost_madvise *args = data;
 	struct panfrost_device *pfdev = dev->dev_private;
 	struct drm_gem_object *gem_obj;
+	struct panfrost_gem_object *bo;
+	int ret = 0;
 
 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
 	if (!gem_obj) {
@@ -347,23 +398,48 @@
 		return -ENOENT;
 	}
 
-	args->retained = drm_gem_shmem_madvise(gem_obj, args->madv);
+	bo = to_panfrost_bo(gem_obj);
 
-	if (args->retained) {
-		struct panfrost_gem_object *bo = to_panfrost_bo(gem_obj);
+	mutex_lock(&pfdev->shrinker_lock);
+	mutex_lock(&bo->mappings.lock);
+	if (args->madv == PANFROST_MADV_DONTNEED) {
+		struct panfrost_gem_mapping *first;
+
+		first = list_first_entry(&bo->mappings.list,
+					 struct panfrost_gem_mapping,
+					 node);
+
+		/*
+		 * If we want to mark the BO purgeable, there must be only one
+		 * user: the caller FD.
+		 * We could do something smarter and mark the BO purgeable only
+		 * when all its users have marked it purgeable, but globally
+		 * visible/shared BOs are likely to never be marked purgeable
+		 * anyway, so let's not bother.
+		 */
+		if (!list_is_singular(&bo->mappings.list) ||
+		    WARN_ON_ONCE(first->mmu != &priv->mmu)) {
+			ret = -EINVAL;
+			goto out_unlock_mappings;
+		}
+	}
 
-		mutex_lock(&pfdev->shrinker_lock);
+	args->retained = drm_gem_shmem_madvise(gem_obj, args->madv);
 
+	if (args->retained) {
 		if (args->madv == PANFROST_MADV_DONTNEED)
-			list_add_tail(&bo->base.madv_list, &pfdev->shrinker_list);
+			list_move_tail(&bo->base.madv_list,
+				       &pfdev->shrinker_list);
 		else if (args->madv == PANFROST_MADV_WILLNEED)
 			list_del_init(&bo->base.madv_list);
-
-		mutex_unlock(&pfdev->shrinker_lock);
 	}
 
+out_unlock_mappings:
+	mutex_unlock(&bo->mappings.lock);
+	mutex_unlock(&pfdev->shrinker_lock);
+
 	drm_gem_object_put_unlocked(gem_obj);
-	return 0;
+	return ret;
 }
 
 int panfrost_unstable_ioctl_check(void)
@@ -443,7 +519,7 @@
 {
 	struct panfrost_file_priv *panfrost_priv = file->driver_priv;
 
-	panfrost_perfcnt_close(panfrost_priv);
+	panfrost_perfcnt_close(file);
 	panfrost_job_close(panfrost_priv);
 
 	panfrost_mmu_pgtable_free(panfrost_priv);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -19,6 +19,22 @@
 	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
 	struct panfrost_device *pfdev = obj->dev->dev_private;
 
+	/*
+	 * Make sure the BO is no longer inserted in the shrinker list before
+	 * taking care of the destruction itself. If we don't do that we have a
+	 * race condition between this function and what's done in
+	 * panfrost_gem_shrinker_scan().
+	 */
+	mutex_lock(&pfdev->shrinker_lock);
+	list_del_init(&bo->base.madv_list);
+	mutex_unlock(&pfdev->shrinker_lock);
+
+	/*
+	 * If we still have mappings attached to the BO, there's a problem in
+	 * our refcounting.
+	 */
+	WARN_ON_ONCE(!list_empty(&bo->mappings.list));
+
 	if (bo->sgts) {
 		int i;
 		int n_sgt = bo->base.base.size / SZ_2M;
@@ -30,18 +46,74 @@
 				sg_free_table(&bo->sgts[i]);
 			}
 		}
-		kfree(bo->sgts);
+		kvfree(bo->sgts);
 	}
 
-	mutex_lock(&pfdev->shrinker_lock);
-	if (!list_empty(&bo->base.madv_list))
-		list_del(&bo->base.madv_list);
-	mutex_unlock(&pfdev->shrinker_lock);
-
 	drm_gem_shmem_free_object(obj);
 }
 
-static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv)
+struct panfrost_gem_mapping *
+panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
+			 struct panfrost_file_priv *priv)
+{
+	struct panfrost_gem_mapping *iter, *mapping = NULL;
+
+	mutex_lock(&bo->mappings.lock);
+	list_for_each_entry(iter, &bo->mappings.list, node) {
+		if (iter->mmu == &priv->mmu) {
+			kref_get(&iter->refcount);
+			mapping = iter;
+			break;
+		}
+	}
+	mutex_unlock(&bo->mappings.lock);
+
+	return mapping;
+}
+
+static void
+panfrost_gem_teardown_mapping(struct panfrost_gem_mapping *mapping)
+{
+	struct panfrost_file_priv *priv;
+
+	if (mapping->active)
+		panfrost_mmu_unmap(mapping);
+
+	priv = container_of(mapping->mmu, struct panfrost_file_priv, mmu);
+	spin_lock(&priv->mm_lock);
+	if (drm_mm_node_allocated(&mapping->mmnode))
+		drm_mm_remove_node(&mapping->mmnode);
+	spin_unlock(&priv->mm_lock);
+}
+
+static void panfrost_gem_mapping_release(struct kref *kref)
+{
+	struct panfrost_gem_mapping *mapping;
+
+	mapping = container_of(kref, struct panfrost_gem_mapping, refcount);
+
+	panfrost_gem_teardown_mapping(mapping);
+	drm_gem_object_put_unlocked(&mapping->obj->base.base);
+	kfree(mapping);
+}
+
+void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping)
+{
+	if (!mapping)
+		return;
+
+	kref_put(&mapping->refcount, panfrost_gem_mapping_release);
+}
+
+void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo)
+{
+	struct panfrost_gem_mapping *mapping;
+
+	list_for_each_entry(mapping, &bo->mappings.list, node)
+		panfrost_gem_teardown_mapping(mapping);
+}
+
+int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv)
 {
 	int ret;
 	size_t size = obj->size;
@@ -49,6 +121,16 @@
 	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
 	unsigned long color = bo->noexec ? PANFROST_BO_NOEXEC : 0;
 	struct panfrost_file_priv *priv = file_priv->driver_priv;
+	struct panfrost_gem_mapping *mapping;
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&mapping->node);
+	kref_init(&mapping->refcount);
+	drm_gem_object_get(obj);
+	mapping->obj = bo;
 
 	/*
 	 * Executable buffers cannot cross a 16MB boundary as the program
@@ -61,37 +143,48 @@
 	else
 		align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0;
 
-	bo->mmu = &priv->mmu;
+	mapping->mmu = &priv->mmu;
 	spin_lock(&priv->mm_lock);
-	ret = drm_mm_insert_node_generic(&priv->mm, &bo->node,
+	ret = drm_mm_insert_node_generic(&priv->mm, &mapping->mmnode,
 					 size >> PAGE_SHIFT, align, color, 0);
 	spin_unlock(&priv->mm_lock);
 	if (ret)
-		return ret;
+		goto err;
 
 	if (!bo->is_heap) {
-		ret = panfrost_mmu_map(bo);
-		if (ret) {
-			spin_lock(&priv->mm_lock);
-			drm_mm_remove_node(&bo->node);
-			spin_unlock(&priv->mm_lock);
-		}
+		ret = panfrost_mmu_map(mapping);
+		if (ret)
+			goto err;
 	}
+
+	mutex_lock(&bo->mappings.lock);
+	WARN_ON(bo->base.madv != PANFROST_MADV_WILLNEED);
+	list_add_tail(&mapping->node, &bo->mappings.list);
+	mutex_unlock(&bo->mappings.lock);
+
+err:
+	if (ret)
+		panfrost_gem_mapping_put(mapping);
 	return ret;
 }
 
-static void panfrost_gem_close(struct drm_gem_object *obj, struct drm_file *file_priv)
+void panfrost_gem_close(struct drm_gem_object *obj, struct drm_file *file_priv)
 {
-	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
 	struct panfrost_file_priv *priv = file_priv->driver_priv;
+	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
+	struct panfrost_gem_mapping *mapping = NULL, *iter;
 
-	if (bo->is_mapped)
-		panfrost_mmu_unmap(bo);
+	mutex_lock(&bo->mappings.lock);
+	list_for_each_entry(iter, &bo->mappings.list, node) {
+		if (iter->mmu == &priv->mmu) {
+			mapping = iter;
+			list_del(&iter->node);
+			break;
+		}
+	}
+	mutex_unlock(&bo->mappings.lock);
 
-	spin_lock(&priv->mm_lock);
-	if (drm_mm_node_allocated(&bo->node))
-		drm_mm_remove_node(&bo->node);
-	spin_unlock(&priv->mm_lock);
+	panfrost_gem_mapping_put(mapping);
 }
 
 static int panfrost_gem_pin(struct drm_gem_object *obj)
@@ -131,6 +224,8 @@
 	if (!obj)
 		return NULL;
 
+	INIT_LIST_HEAD(&obj->mappings.list);
+	mutex_init(&obj->mappings.lock);
 	obj->base.base.funcs = &panfrost_gem_funcs;
 
 	return &obj->base.base;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -13,23 +13,52 @@
 	struct drm_gem_shmem_object base;
 	struct sg_table *sgts;
 
-	struct panfrost_mmu *mmu;
-	struct drm_mm_node node;
-	bool is_mapped		:1;
+	/*
+	 * Use a list for now. If searching a mapping ever becomes the
+	 * bottleneck, we should consider using an RB-tree, or even better,
+	 * let the core store drm_gem_object_mapping entries (where we
+	 * could place driver specific data) instead of drm_gem_object ones
+	 * in its drm_file->object_idr table.
+	 *
+	 * struct drm_gem_object_mapping {
+	 *	struct drm_gem_object *obj;
+	 *	void *driver_priv;
+	 * };
+	 */
+	struct {
+		struct list_head list;
+		struct mutex lock;
+	} mappings;
+
+	/*
+	 * Count the number of jobs referencing this BO so we don't let the
+	 * shrinker reclaim this object prematurely.
+	 */
+	atomic_t gpu_usecount;
+
 	bool noexec		:1;
 	bool is_heap		:1;
 };
 
+struct panfrost_gem_mapping {
+	struct list_head node;
+	struct kref refcount;
+	struct panfrost_gem_object *obj;
+	struct drm_mm_node mmnode;
+	struct panfrost_mmu *mmu;
+	bool active		:1;
+};
+
 static inline
 struct  panfrost_gem_object *to_panfrost_bo(struct drm_gem_object *obj)
 {
 	return container_of(to_drm_gem_shmem_obj(obj), struct panfrost_gem_object, base);
 }
 
-static inline
-struct  panfrost_gem_object *drm_mm_node_to_panfrost_bo(struct drm_mm_node *node)
+static inline struct panfrost_gem_mapping *
+drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
 {
-	return container_of(node, struct panfrost_gem_object, node);
+	return container_of(node, struct panfrost_gem_mapping, mmnode);
 }
 
 struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
@@ -45,6 +74,16 @@
 				u32 flags,
 				uint32_t *handle);
 
+int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv);
+void panfrost_gem_close(struct drm_gem_object *obj,
+			struct drm_file *file_priv);
+
+struct panfrost_gem_mapping *
+panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
+			 struct panfrost_file_priv *priv);
+void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
+void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
+
 void panfrost_gem_shrinker_init(struct drm_device *dev);
 void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -39,15 +39,27 @@
 static bool panfrost_gem_purge(struct drm_gem_object *obj)
 {
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
+	bool ret = false;
 
-	if (!mutex_trylock(&shmem->pages_lock))
+	if (atomic_read(&bo->gpu_usecount))
+		return false;
+
+	if (!mutex_trylock(&bo->mappings.lock))
 		return false;
 
-	panfrost_mmu_unmap(to_panfrost_bo(obj));
+	if (!mutex_trylock(&shmem->pages_lock))
+		goto unlock_mappings;
+
+	panfrost_gem_teardown_mappings_locked(bo);
 	drm_gem_shmem_purge_locked(obj);
+	ret = true;
 
 	mutex_unlock(&shmem->pages_lock);
-	return true;
+
+unlock_mappings:
+	mutex_unlock(&bo->mappings.lock);
+	return ret;
 }
 
 static unsigned long
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -75,6 +75,17 @@
 	return 0;
 }
 
+void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev)
+{
+	/*
+	 * The Amlogic integrated Mali-T820, Mali-G31 & Mali-G52 needs
+	 * these undocumented bits in GPU_PWR_OVERRIDE1 to be set in order
+	 * to operate correctly.
+	 */
+	gpu_write(pfdev, GPU_PWR_KEY, GPU_PWR_KEY_UNLOCK);
+	gpu_write(pfdev, GPU_PWR_OVERRIDE1, 0xfff | (0x20 << 16));
+}
+
 static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev)
 {
 	u32 quirks = 0;
@@ -304,6 +315,8 @@
 	int ret;
 	u32 val;
 
+	panfrost_gpu_init_quirks(pfdev);
+
 	/* Just turn on everything for now */
 	gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present);
 	ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
@@ -357,7 +370,6 @@
 		return err;
 	}
 
-	panfrost_gpu_init_quirks(pfdev);
 	panfrost_gpu_power_on(pfdev);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_gpu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_gpu.h
@@ -16,4 +16,6 @@
 void panfrost_gpu_power_on(struct panfrost_device *pfdev);
 void panfrost_gpu_power_off(struct panfrost_device *pfdev);
 
+void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev);
+
 #endif
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_job.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -269,9 +269,25 @@
 	dma_fence_put(job->done_fence);
 	dma_fence_put(job->render_done_fence);
 
+	if (job->mappings) {
+		for (i = 0; i < job->bo_count; i++) {
+			if (!job->mappings[i])
+				break;
+
+			atomic_dec(&job->mappings[i]->obj->gpu_usecount);
+			panfrost_gem_mapping_put(job->mappings[i]);
+		}
+		kvfree(job->mappings);
+	}
+
 	if (job->bos) {
-		for (i = 0; i < job->bo_count; i++)
+		struct panfrost_gem_object *bo;
+
+		for (i = 0; i < job->bo_count; i++) {
+			bo = to_panfrost_bo(job->bos[i]);
 			drm_gem_object_put_unlocked(job->bos[i]);
+		}
+
 		kvfree(job->bos);
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_job.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_job.h
@@ -32,6 +32,7 @@
 
 	/* Exclusive fences we have taken from the BOs to wait for */
 	struct dma_fence **implicit_fences;
+	struct panfrost_gem_mapping **mappings;
 	struct drm_gem_object **bos;
 	u32 bo_count;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -52,25 +52,16 @@
 }
 
 static void lock_region(struct panfrost_device *pfdev, u32 as_nr,
-			u64 iova, size_t size)
+			u64 iova, u64 size)
 {
 	u8 region_width;
 	u64 region = iova & PAGE_MASK;
-	/*
-	 * fls returns:
-	 * 1 .. 32
-	 *
-	 * 10 + fls(num_pages)
-	 * results in the range (11 .. 42)
-	 */
-
-	size = round_up(size, PAGE_SIZE);
 
-	region_width = 10 + fls(size >> PAGE_SHIFT);
-	if ((size >> PAGE_SHIFT) != (1ul << (region_width - 11))) {
-		/* not pow2, so must go up to the next pow2 */
-		region_width += 1;
-	}
+	/* The size is encoded as ceil(log2) minus(1), which may be calculated
+	 * with fls. The size must be clamped to hardware bounds.
+	 */
+	size = max_t(u64, size, AS_LOCK_REGION_MIN_SIZE);
+	region_width = fls64(size - 1) - 1;
 	region |= region_width;
 
 	/* Lock the region that needs to be updated */
@@ -81,7 +72,7 @@
 
 
 static int mmu_hw_do_operation_locked(struct panfrost_device *pfdev, int as_nr,
-				      u64 iova, size_t size, u32 op)
+				      u64 iova, u64 size, u32 op)
 {
 	if (as_nr < 0)
 		return 0;
@@ -98,7 +89,7 @@
 
 static int mmu_hw_do_operation(struct panfrost_device *pfdev,
 			       struct panfrost_mmu *mmu,
-			       u64 iova, size_t size, u32 op)
+			       u64 iova, u64 size, u32 op)
 {
 	int ret;
 
@@ -115,7 +106,7 @@
 	u64 transtab = cfg->arm_mali_lpae_cfg.transtab;
 	u64 memattr = cfg->arm_mali_lpae_cfg.memattr;
 
-	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0UL, AS_COMMAND_FLUSH_MEM);
+	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM);
 
 	mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), transtab & 0xffffffffUL);
 	mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), transtab >> 32);
@@ -131,7 +122,7 @@
 
 static void panfrost_mmu_disable(struct panfrost_device *pfdev, u32 as_nr)
 {
-	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0UL, AS_COMMAND_FLUSH_MEM);
+	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM);
 
 	mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), 0);
 	mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), 0);
@@ -151,7 +142,12 @@
 	as = mmu->as;
 	if (as >= 0) {
 		int en = atomic_inc_return(&mmu->as_count);
-		WARN_ON(en >= NUM_JOB_SLOTS);
+
+		/*
+		 * AS can be retained by active jobs or a perfcnt context,
+		 * hence the '+ 1' here.
+		 */
+		WARN_ON(en >= (NUM_JOB_SLOTS + 1));
 
 		list_move(&mmu->list, &pfdev->as_lru_list);
 		goto out;
@@ -226,7 +222,7 @@
 
 static void panfrost_mmu_flush_range(struct panfrost_device *pfdev,
 				     struct panfrost_mmu *mmu,
-				     u64 iova, size_t size)
+				     u64 iova, u64 size)
 {
 	if (mmu->as < 0)
 		return;
@@ -237,7 +233,7 @@
 	if (pm_runtime_active(pfdev->dev))
 		mmu_hw_do_operation(pfdev, mmu, iova, size, AS_COMMAND_FLUSH_PT);
 
-	pm_runtime_put_sync_autosuspend(pfdev->dev);
+	pm_runtime_put_autosuspend(pfdev->dev);
 }
 
 static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu,
@@ -269,14 +265,15 @@
 	return 0;
 }
 
-int panfrost_mmu_map(struct panfrost_gem_object *bo)
+int panfrost_mmu_map(struct panfrost_gem_mapping *mapping)
 {
+	struct panfrost_gem_object *bo = mapping->obj;
 	struct drm_gem_object *obj = &bo->base.base;
 	struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
 	struct sg_table *sgt;
 	int prot = IOMMU_READ | IOMMU_WRITE;
 
-	if (WARN_ON(bo->is_mapped))
+	if (WARN_ON(mapping->active))
 		return 0;
 
 	if (bo->noexec)
@@ -286,25 +283,28 @@
 	if (WARN_ON(IS_ERR(sgt)))
 		return PTR_ERR(sgt);
 
-	mmu_map_sg(pfdev, bo->mmu, bo->node.start << PAGE_SHIFT, prot, sgt);
-	bo->is_mapped = true;
+	mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT,
+		   prot, sgt);
+	mapping->active = true;
 
 	return 0;
 }
 
-void panfrost_mmu_unmap(struct panfrost_gem_object *bo)
+void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping)
 {
+	struct panfrost_gem_object *bo = mapping->obj;
 	struct drm_gem_object *obj = &bo->base.base;
 	struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
-	struct io_pgtable_ops *ops = bo->mmu->pgtbl_ops;
-	u64 iova = bo->node.start << PAGE_SHIFT;
-	size_t len = bo->node.size << PAGE_SHIFT;
+	struct io_pgtable_ops *ops = mapping->mmu->pgtbl_ops;
+	u64 iova = mapping->mmnode.start << PAGE_SHIFT;
+	size_t len = mapping->mmnode.size << PAGE_SHIFT;
 	size_t unmapped_len = 0;
 
-	if (WARN_ON(!bo->is_mapped))
+	if (WARN_ON(!mapping->active))
 		return;
 
-	dev_dbg(pfdev->dev, "unmap: as=%d, iova=%llx, len=%zx", bo->mmu->as, iova, len);
+	dev_dbg(pfdev->dev, "unmap: as=%d, iova=%llx, len=%zx",
+		mapping->mmu->as, iova, len);
 
 	while (unmapped_len < len) {
 		size_t unmapped_page;
@@ -318,8 +318,9 @@
 		unmapped_len += pgsize;
 	}
 
-	panfrost_mmu_flush_range(pfdev, bo->mmu, bo->node.start << PAGE_SHIFT, len);
-	bo->is_mapped = false;
+	panfrost_mmu_flush_range(pfdev, mapping->mmu,
+				 mapping->mmnode.start << PAGE_SHIFT, len);
+	mapping->active = false;
 }
 
 static void mmu_tlb_inv_context_s1(void *cookie)
@@ -394,10 +395,10 @@
 	free_io_pgtable_ops(mmu->pgtbl_ops);
 }
 
-static struct panfrost_gem_object *
-addr_to_drm_mm_node(struct panfrost_device *pfdev, int as, u64 addr)
+static struct panfrost_gem_mapping *
+addr_to_mapping(struct panfrost_device *pfdev, int as, u64 addr)
 {
-	struct panfrost_gem_object *bo = NULL;
+	struct panfrost_gem_mapping *mapping = NULL;
 	struct panfrost_file_priv *priv;
 	struct drm_mm_node *node;
 	u64 offset = addr >> PAGE_SHIFT;
@@ -418,8 +419,9 @@
 	drm_mm_for_each_node(node, &priv->mm) {
 		if (offset >= node->start &&
 		    offset < (node->start + node->size)) {
-			bo = drm_mm_node_to_panfrost_bo(node);
-			drm_gem_object_get(&bo->base.base);
+			mapping = drm_mm_node_to_panfrost_mapping(node);
+
+			kref_get(&mapping->refcount);
 			break;
 		}
 	}
@@ -427,7 +429,7 @@
 	spin_unlock(&priv->mm_lock);
 out:
 	spin_unlock(&pfdev->as_lock);
-	return bo;
+	return mapping;
 }
 
 #define NUM_FAULT_PAGES (SZ_2M / PAGE_SIZE)
@@ -436,28 +438,30 @@
 				       u64 addr)
 {
 	int ret, i;
+	struct panfrost_gem_mapping *bomapping;
 	struct panfrost_gem_object *bo;
 	struct address_space *mapping;
 	pgoff_t page_offset;
 	struct sg_table *sgt;
 	struct page **pages;
 
-	bo = addr_to_drm_mm_node(pfdev, as, addr);
-	if (!bo)
+	bomapping = addr_to_mapping(pfdev, as, addr);
+	if (!bomapping)
 		return -ENOENT;
 
+	bo = bomapping->obj;
 	if (!bo->is_heap) {
 		dev_WARN(pfdev->dev, "matching BO is not heap type (GPU VA = %llx)",
-			 bo->node.start << PAGE_SHIFT);
+			 bomapping->mmnode.start << PAGE_SHIFT);
 		ret = -EINVAL;
 		goto err_bo;
 	}
-	WARN_ON(bo->mmu->as != as);
+	WARN_ON(bomapping->mmu->as != as);
 
 	/* Assume 2MB alignment and size multiple */
 	addr &= ~((u64)SZ_2M - 1);
 	page_offset = addr >> PAGE_SHIFT;
-	page_offset -= bo->node.start;
+	page_offset -= bomapping->mmnode.start;
 
 	mutex_lock(&bo->base.pages_lock);
 
@@ -473,7 +477,7 @@
 		pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
 				       sizeof(struct page *), GFP_KERNEL | __GFP_ZERO);
 		if (!pages) {
-			kfree(bo->sgts);
+			kvfree(bo->sgts);
 			bo->sgts = NULL;
 			mutex_unlock(&bo->base.pages_lock);
 			ret = -ENOMEM;
@@ -481,8 +485,14 @@
 		}
 		bo->base.pages = pages;
 		bo->base.pages_use_count = 1;
-	} else
+	} else {
 		pages = bo->base.pages;
+		if (pages[page_offset]) {
+			/* Pages are already mapped, bail out. */
+			mutex_unlock(&bo->base.pages_lock);
+			goto out;
+		}
+	}
 
 	mapping = bo->base.base.filp->f_mapping;
 	mapping_set_unevictable(mapping);
@@ -492,6 +502,7 @@
 		if (IS_ERR(pages[i])) {
 			mutex_unlock(&bo->base.pages_lock);
 			ret = PTR_ERR(pages[i]);
+			pages[i] = NULL;
 			goto err_pages;
 		}
 	}
@@ -509,13 +520,15 @@
 		goto err_map;
 	}
 
-	mmu_map_sg(pfdev, bo->mmu, addr, IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt);
+	mmu_map_sg(pfdev, bomapping->mmu, addr,
+		   IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt);
 
-	bo->is_mapped = true;
+	bomapping->active = true;
 
 	dev_dbg(pfdev->dev, "mapped page fault @ AS%d %llx", as, addr);
 
-	drm_gem_object_put_unlocked(&bo->base.base);
+out:
+	panfrost_gem_mapping_put(bomapping);
 
 	return 0;
 
@@ -586,36 +599,30 @@
 		access_type = (fault_status >> 8) & 0x3;
 		source_id = (fault_status >> 16);
 
-		/* Page fault only */
-		if ((status & mask) == BIT(i)) {
-			WARN_ON(exception_type < 0xC1 || exception_type > 0xC4);
+		mmu_write(pfdev, MMU_INT_CLEAR, mask);
 
+		/* Page fault only */
+		ret = -1;
+		if ((status & mask) == BIT(i) && (exception_type & 0xF8) == 0xC0)
 			ret = panfrost_mmu_map_fault_addr(pfdev, i, addr);
-			if (!ret) {
-				mmu_write(pfdev, MMU_INT_CLEAR, BIT(i));
-				status &= ~mask;
-				continue;
-			}
-		}
 
-		/* terminal fault, print info about the fault */
-		dev_err(pfdev->dev,
-			"Unhandled Page fault in AS%d at VA 0x%016llX\n"
-			"Reason: %s\n"
-			"raw fault status: 0x%X\n"
-			"decoded fault status: %s\n"
-			"exception type 0x%X: %s\n"
-			"access type 0x%X: %s\n"
-			"source id 0x%X\n",
-			i, addr,
-			"TODO",
-			fault_status,
-			(fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
-			exception_type, panfrost_exception_name(pfdev, exception_type),
-			access_type, access_type_name(pfdev, fault_status),
-			source_id);
-
-		mmu_write(pfdev, MMU_INT_CLEAR, mask);
+		if (ret)
+			/* terminal fault, print info about the fault */
+			dev_err(pfdev->dev,
+				"Unhandled Page fault in AS%d at VA 0x%016llX\n"
+				"Reason: %s\n"
+				"raw fault status: 0x%X\n"
+				"decoded fault status: %s\n"
+				"exception type 0x%X: %s\n"
+				"access type 0x%X: %s\n"
+				"source id 0x%X\n",
+				i, addr,
+				"TODO",
+				fault_status,
+				(fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
+				exception_type, panfrost_exception_name(pfdev, exception_type),
+				access_type, access_type_name(pfdev, fault_status),
+				source_id);
 
 		status &= ~mask;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_mmu.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_mmu.h
@@ -4,12 +4,12 @@
 #ifndef __PANFROST_MMU_H__
 #define __PANFROST_MMU_H__
 
-struct panfrost_gem_object;
+struct panfrost_gem_mapping;
 struct panfrost_file_priv;
 struct panfrost_mmu;
 
-int panfrost_mmu_map(struct panfrost_gem_object *bo);
-void panfrost_mmu_unmap(struct panfrost_gem_object *bo);
+int panfrost_mmu_map(struct panfrost_gem_mapping *mapping);
+void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping);
 
 int panfrost_mmu_init(struct panfrost_device *pfdev);
 void panfrost_mmu_fini(struct panfrost_device *pfdev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -25,7 +25,7 @@
 #define V4_SHADERS_PER_COREGROUP	4
 
 struct panfrost_perfcnt {
-	struct panfrost_gem_object *bo;
+	struct panfrost_gem_mapping *mapping;
 	size_t bosize;
 	void *buf;
 	struct panfrost_file_priv *user;
@@ -49,7 +49,7 @@
 	int ret;
 
 	reinit_completion(&pfdev->perfcnt->dump_comp);
-	gpuva = pfdev->perfcnt->bo->node.start << PAGE_SHIFT;
+	gpuva = pfdev->perfcnt->mapping->mmnode.start << PAGE_SHIFT;
 	gpu_write(pfdev, GPU_PERFCNT_BASE_LO, gpuva);
 	gpu_write(pfdev, GPU_PERFCNT_BASE_HI, gpuva >> 32);
 	gpu_write(pfdev, GPU_INT_CLEAR,
@@ -67,12 +67,13 @@
 }
 
 static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
-					  struct panfrost_file_priv *user,
+					  struct drm_file *file_priv,
 					  unsigned int counterset)
 {
+	struct panfrost_file_priv *user = file_priv->driver_priv;
 	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
 	struct drm_gem_shmem_object *bo;
-	u32 cfg;
+	u32 cfg, as;
 	int ret;
 
 	if (user == perfcnt->user)
@@ -88,17 +89,22 @@
 	if (IS_ERR(bo))
 		return PTR_ERR(bo);
 
-	perfcnt->bo = to_panfrost_bo(&bo->base);
-
 	/* Map the perfcnt buf in the address space attached to file_priv. */
-	ret = panfrost_mmu_map(perfcnt->bo);
+	ret = panfrost_gem_open(&bo->base, file_priv);
 	if (ret)
 		goto err_put_bo;
 
+	perfcnt->mapping = panfrost_gem_mapping_get(to_panfrost_bo(&bo->base),
+						    user);
+	if (!perfcnt->mapping) {
+		ret = -EINVAL;
+		goto err_close_bo;
+	}
+
 	perfcnt->buf = drm_gem_shmem_vmap(&bo->base);
 	if (IS_ERR(perfcnt->buf)) {
 		ret = PTR_ERR(perfcnt->buf);
-		goto err_put_bo;
+		goto err_put_mapping;
 	}
 
 	/*
@@ -120,12 +126,8 @@
 
 	perfcnt->user = user;
 
-	/*
-	 * Always use address space 0 for now.
-	 * FIXME: this needs to be updated when we start using different
-	 * address space.
-	 */
-	cfg = GPU_PERFCNT_CFG_AS(0) |
+	as = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
+	cfg = GPU_PERFCNT_CFG_AS(as) |
 	      GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
 
 	/*
@@ -153,18 +155,26 @@
 	if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
 		gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
 
+	/* The BO ref is retained by the mapping. */
+	drm_gem_object_put_unlocked(&bo->base);
+
 	return 0;
 
 err_vunmap:
-	drm_gem_shmem_vunmap(&perfcnt->bo->base.base, perfcnt->buf);
+	drm_gem_shmem_vunmap(&bo->base, perfcnt->buf);
+err_put_mapping:
+	panfrost_gem_mapping_put(perfcnt->mapping);
+err_close_bo:
+	panfrost_gem_close(&bo->base, file_priv);
 err_put_bo:
 	drm_gem_object_put_unlocked(&bo->base);
 	return ret;
 }
 
 static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
-					   struct panfrost_file_priv *user)
+					   struct drm_file *file_priv)
 {
+	struct panfrost_file_priv *user = file_priv->driver_priv;
 	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
 
 	if (user != perfcnt->user)
@@ -178,10 +188,12 @@
 		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
 
 	perfcnt->user = NULL;
-	drm_gem_shmem_vunmap(&perfcnt->bo->base.base, perfcnt->buf);
+	drm_gem_shmem_vunmap(&perfcnt->mapping->obj->base.base, perfcnt->buf);
 	perfcnt->buf = NULL;
-	drm_gem_object_put_unlocked(&perfcnt->bo->base.base);
-	perfcnt->bo = NULL;
+	panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
+	panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
+	panfrost_gem_mapping_put(perfcnt->mapping);
+	perfcnt->mapping = NULL;
 	pm_runtime_mark_last_busy(pfdev->dev);
 	pm_runtime_put_autosuspend(pfdev->dev);
 
@@ -191,7 +203,6 @@
 int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
 				  struct drm_file *file_priv)
 {
-	struct panfrost_file_priv *pfile = file_priv->driver_priv;
 	struct panfrost_device *pfdev = dev->dev_private;
 	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
 	struct drm_panfrost_perfcnt_enable *req = data;
@@ -207,10 +218,10 @@
 
 	mutex_lock(&perfcnt->lock);
 	if (req->enable)
-		ret = panfrost_perfcnt_enable_locked(pfdev, pfile,
+		ret = panfrost_perfcnt_enable_locked(pfdev, file_priv,
 						     req->counterset);
 	else
-		ret = panfrost_perfcnt_disable_locked(pfdev, pfile);
+		ret = panfrost_perfcnt_disable_locked(pfdev, file_priv);
 	mutex_unlock(&perfcnt->lock);
 
 	return ret;
@@ -248,15 +259,16 @@
 	return ret;
 }
 
-void panfrost_perfcnt_close(struct panfrost_file_priv *pfile)
+void panfrost_perfcnt_close(struct drm_file *file_priv)
 {
+	struct panfrost_file_priv *pfile = file_priv->driver_priv;
 	struct panfrost_device *pfdev = pfile->pfdev;
 	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
 
 	pm_runtime_get_sync(pfdev->dev);
 	mutex_lock(&perfcnt->lock);
 	if (perfcnt->user == pfile)
-		panfrost_perfcnt_disable_locked(pfdev, pfile);
+		panfrost_perfcnt_disable_locked(pfdev, file_priv);
 	mutex_unlock(&perfcnt->lock);
 	pm_runtime_mark_last_busy(pfdev->dev);
 	pm_runtime_put_autosuspend(pfdev->dev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
@@ -9,7 +9,7 @@
 void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev);
 int panfrost_perfcnt_init(struct panfrost_device *pfdev);
 void panfrost_perfcnt_fini(struct panfrost_device *pfdev);
-void panfrost_perfcnt_close(struct panfrost_file_priv *pfile);
+void panfrost_perfcnt_close(struct drm_file *file_priv);
 int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
 				  struct drm_file *file_priv);
 int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/panfrost/panfrost_regs.h
+++ linux-ein-5.4.0/drivers/gpu/drm/panfrost/panfrost_regs.h
@@ -51,6 +51,10 @@
 #define GPU_STATUS			0x34
 #define   GPU_STATUS_PRFCNT_ACTIVE	BIT(2)
 #define GPU_LATEST_FLUSH_ID		0x38
+#define GPU_PWR_KEY			0x50	/* (WO) Power manager key register */
+#define  GPU_PWR_KEY_UNLOCK		0x2968A819
+#define GPU_PWR_OVERRIDE0		0x54	/* (RW) Power manager override settings */
+#define GPU_PWR_OVERRIDE1		0x58	/* (RW) Power manager override settings */
 #define GPU_FAULT_STATUS		0x3C
 #define GPU_FAULT_ADDRESS_LO		0x40
 #define GPU_FAULT_ADDRESS_HI		0x44
@@ -314,6 +318,8 @@
 #define AS_FAULTSTATUS_ACCESS_TYPE_READ		(0x2 << 8)
 #define AS_FAULTSTATUS_ACCESS_TYPE_WRITE	(0x3 << 8)
 
+#define AS_LOCK_REGION_MIN_SIZE                 (1ULL << 15)
+
 #define gpu_write(dev, reg, data) writel(data, dev->iomem + reg)
 #define gpu_read(dev, reg) readl(dev->iomem + reg)
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_cmd.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -480,9 +480,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;
@@ -499,8 +500,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);
@@ -542,9 +543,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-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_display.c
@@ -325,6 +325,7 @@
 
 	head.id = i;
 	head.flags = 0;
+	head.surface_id = 0;
 	oldcount = qdev->monitors_config->count;
 	if (crtc->state->active) {
 		struct drm_display_mode *mode = &crtc->mode;
@@ -523,8 +524,8 @@
 	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);
 
 	return ret;
 
@@ -665,8 +666,8 @@
 	cmd->u.position.y = plane->state->crtc_y + fb->hot_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);
 
 	if (old_cursor_bo != NULL)
 		qxl_bo_unpin(old_cursor_bo);
@@ -713,8 +714,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);
 }
 
 static void qxl_update_dumb_head(struct qxl_device *qdev,
@@ -1236,6 +1237,10 @@
 
 void qxl_modeset_fini(struct qxl_device *qdev)
 {
+	if (qdev->dumb_shadow_bo) {
+		drm_gem_object_put(&qdev->dumb_shadow_bo->tbo.base);
+		qdev->dumb_shadow_bo = NULL;
+	}
 	qxl_destroy_monitors_object(qdev);
 	drm_mode_config_cleanup(&qdev->ddev);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_draw.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_draw.c
@@ -209,9 +209,10 @@
 		goto out_release_backoff;
 
 	rects = drawable_set_clipping(qdev, 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;
@@ -242,8 +243,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)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_dumb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_dumb.c
@@ -58,6 +58,8 @@
 	surf.height = args->height;
 	surf.stride = pitch;
 	surf.format = format;
+	surf.data = 0;
+
 	r = qxl_gem_object_create_with_handle(qdev, file_priv,
 					      QXL_GEM_DOMAIN_SURFACE,
 					      args->size, &surf, &qobj,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_image.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_image.c
@@ -212,7 +212,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-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -261,11 +261,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-ein-5.4.0.orig/drivers/gpu/drm/qxl/qxl_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/qxl/qxl_kms.c
@@ -184,7 +184,7 @@
 
 	if (!qxl_check_device(qdev)) {
 		r = -ENODEV;
-		goto surface_mapping_free;
+		goto rom_unmap;
 	}
 
 	r = qxl_bo_init(qdev);
@@ -218,7 +218,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-ein-5.4.0.orig/drivers/gpu/drm/radeon/atombios_encoders.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -197,7 +197,8 @@
 	 * so don't register a backlight device
 	 */
 	if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
-	    (rdev->pdev->device == 0x6741))
+	    (rdev->pdev->device == 0x6741) &&
+	    !dmi_match(DMI_PRODUCT_NAME, "iMac12,1"))
 		return;
 
 	if (!radeon_encoder->enc_priv)
@@ -2191,11 +2192,12 @@
 
 	/*
 	 * 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,
+	 * but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb,
 	 * otherwise the internal eDP panel will stay dark.
 	 */
 	if (ASIC_IS_DCE32(rdev)) {
-		if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
+		if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
+		    dmi_match(DMI_PRODUCT_NAME, "iMac11,2"))
 			enc_idx = (dig->linkb) ? 1 : 0;
 		else
 			enc_idx = radeon_crtc->crtc_id;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/ci_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/ci_dpm.c
@@ -4366,7 +4366,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) {
@@ -5556,6 +5556,7 @@
 	u8 frev, crev;
 	u8 *power_state_offset;
 	struct ci_ps *ps;
+	int ret;
 
 	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
 				   &frev, &crev, &data_offset))
@@ -5578,18 +5579,21 @@
 	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;
 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
-		if (!rdev->pm.power_state[i].clock_info)
-			return -EINVAL;
+		if (!rdev->pm.power_state[i].clock_info) {
+			ret = -EINVAL;
+			goto err_free_ps;
+		}
 		ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
 		if (ps == NULL) {
-			kfree(rdev->pm.dpm.ps);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_free_ps;
 		}
 		rdev->pm.dpm.ps[i].ps_priv = ps;
 		ci_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
@@ -5612,8 +5616,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++) {
@@ -5630,6 +5634,12 @@
 	}
 
 	return 0;
+
+err_free_ps:
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++)
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	kfree(rdev->pm.dpm.ps);
+	return ret;
 }
 
 static int ci_get_vbios_boot_values(struct radeon_device *rdev,
@@ -5718,25 +5728,26 @@
 
 	ret = ci_get_vbios_boot_values(rdev, &pi->vbios_boot_state);
 	if (ret) {
-		ci_dpm_fini(rdev);
+		kfree(rdev->pm.dpm.priv);
 		return ret;
 	}
 
 	ret = r600_get_platform_caps(rdev);
 	if (ret) {
-		ci_dpm_fini(rdev);
+		kfree(rdev->pm.dpm.priv);
 		return ret;
 	}
 
 	ret = r600_parse_extended_power_table(rdev);
 	if (ret) {
-		ci_dpm_fini(rdev);
+		kfree(rdev->pm.dpm.priv);
 		return ret;
 	}
 
 	ret = ci_parse_power_table(rdev);
 	if (ret) {
-		ci_dpm_fini(rdev);
+		kfree(rdev->pm.dpm.priv);
+		r600_free_extended_power_table(rdev);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/cik.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/cik.c
@@ -6969,8 +6969,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
@@ -9504,7 +9504,6 @@
 {
 	struct pci_dev *root = rdev->pdev->bus->self;
 	enum pci_bus_speed speed_cap;
-	int bridge_pos, gpu_pos;
 	u32 speed_cntl, current_data_rate;
 	int i;
 	u16 tmp16;
@@ -9546,12 +9545,7 @@
 		DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n");
 	}
 
-	bridge_pos = pci_pcie_cap(root);
-	if (!bridge_pos)
-		return;
-
-	gpu_pos = pci_pcie_cap(rdev->pdev);
-	if (!gpu_pos)
+	if (!pci_is_pcie(root) || !pci_is_pcie(rdev->pdev))
 		return;
 
 	if (speed_cap == PCIE_SPEED_8_0GT) {
@@ -9561,14 +9555,8 @@
 			u16 bridge_cfg2, gpu_cfg2;
 			u32 max_lw, current_lw, tmp;
 
-			pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-			pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
+			pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
 
 			tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1);
 			max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -9586,15 +9574,23 @@
 
 			for (i = 0; i < 10; i++) {
 				/* check status */
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_DEVSTA,
+							  &tmp16);
 				if (tmp16 & PCI_EXP_DEVSTA_TRPND)
 					break;
 
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+							  &bridge_cfg);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL,
+							  &gpu_cfg);
+
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &bridge_cfg2);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &gpu_cfg2);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp |= LC_SET_QUIESCE;
@@ -9607,26 +9603,38 @@
 				msleep(100);
 
 				/* linkctl */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   bridge_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
+				pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   gpu_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
 
 				/* linkctl2 */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (bridge_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(root,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
+
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (gpu_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(rdev->pdev,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp &= ~LC_SET_QUIESCE;
@@ -9640,15 +9648,15 @@
 	speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
 	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-	pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-	tmp16 &= ~0xf;
+	pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+	tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
 	if (speed_cap == PCIE_SPEED_8_0GT)
-		tmp16 |= 3; /* gen3 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
 	else if (speed_cap == PCIE_SPEED_5_0GT)
-		tmp16 |= 2; /* gen2 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
 	else
-		tmp16 |= 1; /* gen1 */
-	pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+	pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
 	speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
 	speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/cypress_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -559,8 +559,12 @@
 						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
 			u32 reference_clock = rdev->clock.mpll.reference_freq;
 			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
-			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
-			u32 clk_v = ss.percentage *
+			u32 clk_s, clk_v;
+
+			if (!decoded_ref)
+				return -EINVAL;
+			clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+			clk_v = ss.percentage *
 				(0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
 
 			mpll_ss1 &= ~CLKV_MASK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/evergreen.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/evergreen.c
@@ -4819,14 +4819,15 @@
 			break;
 		case 44: /* hdmi */
 			afmt_idx = src_data;
-			if (!(afmt_status[afmt_idx] & AFMT_AZ_FORMAT_WTRIG))
-				DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
-
 			if (afmt_idx > 5) {
 				DRM_ERROR("Unhandled interrupt: %d %d\n",
 					  src_id, src_data);
 				break;
 			}
+
+			if (!(afmt_status[afmt_idx] & AFMT_AZ_FORMAT_WTRIG))
+				DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
 			afmt_status[afmt_idx] &= ~AFMT_AZ_FORMAT_WTRIG;
 			queue_hdmi = true;
 			DRM_DEBUG("IH: HDMI%d\n", afmt_idx + 1);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/ni_dpm.c
+++ linux-ein-5.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))
@@ -2241,8 +2241,12 @@
 						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
 			u32 reference_clock = rdev->clock.mpll.reference_freq;
 			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
-			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
-			u32 clk_v = ss.percentage *
+			u32 clk_s, clk_v;
+
+			if (!decoded_ref)
+				return -EINVAL;
+			clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+			clk_v = ss.percentage *
 				(0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
 
 			mpll_ss1 &= ~CLKV_MASK;
@@ -2740,10 +2744,10 @@
 					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
 			}
 			j++;
-			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
-				return -EINVAL;
 			break;
 		case MC_SEQ_RESERVE_M >> 2:
+			if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+				return -EINVAL;
 			temp_reg = RREG32(MC_PMG_CMD_MRS1);
 			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
 			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
@@ -2752,8 +2756,6 @@
 					(temp_reg & 0xffff0000) |
 					(table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
 			j++;
-			if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
-				return -EINVAL;
 			break;
 		default:
 			break;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/r100.c
+++ linux-ein-5.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;
@@ -2313,7 +2313,7 @@
 	switch (prim_walk) {
 	case 1:
 		for (i = 0; i < track->num_arrays; i++) {
-			size = track->arrays[i].esize * track->max_indx * 4;
+			size = track->arrays[i].esize * track->max_indx * 4UL;
 			if (track->arrays[i].robj == NULL) {
 				DRM_ERROR("(PW %u) Vertex array %u no buffer "
 					  "bound\n", prim_walk, i);
@@ -2332,7 +2332,7 @@
 		break;
 	case 2:
 		for (i = 0; i < track->num_arrays; i++) {
-			size = track->arrays[i].esize * (nverts - 1) * 4;
+			size = track->arrays[i].esize * (nverts - 1) * 4UL;
 			if (track->arrays[i].robj == NULL) {
 				DRM_ERROR("(PW %u) Vertex array %u no buffer "
 					  "bound\n", prim_walk, i);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/r200.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/gpu/drm/radeon/r600.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/r600.c
@@ -3696,8 +3696,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
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/r600_cs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/r600_cs.c
@@ -1278,7 +1278,7 @@
 			return -EINVAL;
 		}
 		tmp = (reg - CB_COLOR0_BASE) / 4;
-		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
+		track->cb_color_bo_offset[tmp] = (u64)radeon_get_ib_value(p, idx) << 8;
 		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
 		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
@@ -1305,7 +1305,7 @@
 					"0x%04X\n", reg);
 			return -EINVAL;
 		}
-		track->htile_offset = radeon_get_ib_value(p, idx) << 8;
+		track->htile_offset = (u64)radeon_get_ib_value(p, idx) << 8;
 		ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
 		track->htile_bo = reloc->robj;
 		track->db_dirty = true;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon.h
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon.h
@@ -1554,6 +1554,7 @@
 	void                    *priv;
 	u32			new_active_crtcs;
 	int			new_active_crtc_count;
+	int			high_pixelclock_count;
 	u32			current_active_crtcs;
 	int			current_active_crtc_count;
 	bool single_display;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_atombios.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2136,11 +2136,14 @@
 		return state_index;
 	/* last mode is usually default, array is low to high */
 	for (i = 0; i < num_modes; i++) {
-		rdev->pm.power_state[state_index].clock_info =
-			kcalloc(1, sizeof(struct radeon_pm_clock_info),
-				GFP_KERNEL);
+		/* avoid memory leaks from invalid modes or unknown frev. */
+		if (!rdev->pm.power_state[state_index].clock_info) {
+			rdev->pm.power_state[state_index].clock_info =
+				kzalloc(sizeof(struct radeon_pm_clock_info),
+					GFP_KERNEL);
+		}
 		if (!rdev->pm.power_state[state_index].clock_info)
-			return state_index;
+			goto out;
 		rdev->pm.power_state[state_index].num_clock_modes = 1;
 		rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
 		switch (frev) {
@@ -2259,17 +2262,24 @@
 			break;
 		}
 	}
+out:
+	/* free any unused clock_info allocation. */
+	if (state_index && state_index < num_modes) {
+		kfree(rdev->pm.power_state[state_index].clock_info);
+		rdev->pm.power_state[state_index].clock_info = NULL;
+	}
+
 	/* last mode is usually default */
-	if (rdev->pm.default_power_state_index == -1) {
+	if (state_index && rdev->pm.default_power_state_index == -1) {
 		rdev->pm.power_state[state_index - 1].type =
 			POWER_STATE_TYPE_DEFAULT;
 		rdev->pm.default_power_state_index = state_index - 1;
 		rdev->pm.power_state[state_index - 1].default_clock_mode =
 			&rdev->pm.power_state[state_index - 1].clock_info[0];
-		rdev->pm.power_state[state_index].flags &=
+		rdev->pm.power_state[state_index - 1].flags &=
 			~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
-		rdev->pm.power_state[state_index].misc = 0;
-		rdev->pm.power_state[state_index].misc2 = 0;
+		rdev->pm.power_state[state_index - 1].misc = 0;
+		rdev->pm.power_state[state_index - 1].misc2 = 0;
 	}
 	return state_index;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_bios.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_bios.c
@@ -108,25 +108,33 @@
 
 static bool radeon_read_platform_bios(struct radeon_device *rdev)
 {
-	uint8_t __iomem *bios;
-	size_t size;
+	phys_addr_t rom = rdev->pdev->rom;
+	size_t romlen = rdev->pdev->romlen;
+	void __iomem *bios;
 
 	rdev->bios = NULL;
 
-	bios = pci_platform_rom(rdev->pdev, &size);
-	if (!bios) {
+	if (!rom || romlen == 0)
 		return false;
-	}
 
-	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
-		return false;
-	}
-	rdev->bios = kmemdup(bios, size, GFP_KERNEL);
-	if (rdev->bios == NULL) {
+	rdev->bios = kzalloc(romlen, GFP_KERNEL);
+	if (!rdev->bios)
 		return false;
-	}
+
+	bios = ioremap(rom, romlen);
+	if (!bios)
+		goto free_bios;
+
+	memcpy_fromio(rdev->bios, bios, romlen);
+	iounmap(bios);
+
+	if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa)
+		goto free_bios;
 
 	return true;
+free_bios:
+	kfree(rdev->bios);
+	return false;
 }
 
 #ifdef CONFIG_ACPI
@@ -219,6 +227,7 @@
 
 	if (!found)
 		return false;
+	pci_dev_put(pdev);
 
 	rdev->bios = kmalloc(size, GFP_KERNEL);
 	if (!rdev->bios) {
@@ -604,13 +613,14 @@
 	acpi_size tbl_size;
 	UEFI_ACPI_VFCT *vfct;
 	unsigned offset;
+	bool r = false;
 
 	if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
 		return false;
 	tbl_size = hdr->length;
 	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
 		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
-		return false;
+		goto out;
 	}
 
 	vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -623,13 +633,13 @@
 		offset += sizeof(VFCT_IMAGE_HEADER);
 		if (offset > tbl_size) {
 			DRM_ERROR("ACPI VFCT image header truncated\n");
-			return false;
+			goto out;
 		}
 
 		offset += vhdr->ImageLength;
 		if (offset > tbl_size) {
 			DRM_ERROR("ACPI VFCT image truncated\n");
-			return false;
+			goto out;
 		}
 
 		if (vhdr->ImageLength &&
@@ -641,15 +651,18 @@
 			rdev->bios = kmemdup(&vbios->VbiosContent,
 					     vhdr->ImageLength,
 					     GFP_KERNEL);
+			if (rdev->bios)
+				r = true;
 
-			if (!rdev->bios)
-				return false;
-			return true;
+			goto out;
 		}
 	}
 
 	DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
-	return false;
+
+out:
+	acpi_put_table(hdr);
+	return r;
 }
 #else
 static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_connectors.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -477,6 +477,8 @@
 	    native_mode->vdisplay != 0 &&
 	    native_mode->clock != 0) {
 		mode = drm_mode_duplicate(dev, native_mode);
+		if (!mode)
+			return NULL;
 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
 		drm_mode_set_name(mode);
 
@@ -491,6 +493,8 @@
 		 * simpler.
 		 */
 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
+		if (!mode)
+			return NULL;
 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
 	}
@@ -883,8 +887,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (encoder) {
@@ -1029,8 +1035,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	encoder = radeon_best_single_encoder(connector);
@@ -1167,8 +1175,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	encoder = radeon_best_single_encoder(connector);
@@ -1251,8 +1261,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (radeon_connector->detected_hpd_without_ddc) {
@@ -1666,8 +1678,10 @@
 
 	if (!drm_kms_helper_is_poll_worker()) {
 		r = pm_runtime_get_sync(connector->dev->dev);
-		if (r < 0)
+		if (r < 0) {
+			pm_runtime_put_autosuspend(connector->dev->dev);
 			return connector_status_disconnected;
+		}
 	}
 
 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_cs.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_cs.c
@@ -271,7 +271,8 @@
 {
 	struct drm_radeon_cs *cs = data;
 	uint64_t *chunk_array_ptr;
-	unsigned size, i;
+	u64 size;
+	unsigned i;
 	u32 ring = RADEON_CS_RING_GFX;
 	s32 priority = 0;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_device.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_device.c
@@ -1022,6 +1022,7 @@
 {
 	if (rdev->mode_info.atom_context) {
 		kfree(rdev->mode_info.atom_context->scratch);
+		kfree(rdev->mode_info.atom_context->iio);
 	}
 	kfree(rdev->mode_info.atom_context);
 	rdev->mode_info.atom_context = NULL;
@@ -1623,6 +1624,9 @@
 		if (r) {
 			/* delay GPU reset to resume */
 			radeon_fence_driver_force_completion(rdev, i);
+		} else {
+			/* finish executing delayed work */
+			flush_delayed_work(&rdev->fence_drv[i].lockup_work);
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_display.c
@@ -127,6 +127,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)));
@@ -629,8 +631,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, ctx);
 
@@ -678,11 +682,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 = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0);
 	rdev->mode_info.crtcs[index] = radeon_crtc;
 
 	if (rdev->family >= CHIP_BONAIRE) {
@@ -1329,6 +1338,7 @@
 	/* 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");
+		drm_gem_object_put(obj);
 		return ERR_PTR(-EINVAL);
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_drv.c
@@ -37,6 +37,7 @@
 #include <linux/vga_switcheroo.h>
 #include <linux/mmu_notifier.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
@@ -173,12 +174,7 @@
 int radeon_modeset = -1;
 int radeon_dynclks = -1;
 int radeon_r4xx_atom = 0;
-#ifdef __powerpc__
-/* Default to PCI on PowerPC (fdo #95017) */
 int radeon_agpmode = -1;
-#else
-int radeon_agpmode = 0;
-#endif
 int radeon_vram_limit = 0;
 int radeon_gart_size = -1; /* auto */
 int radeon_benchmarking = 0;
@@ -325,6 +321,7 @@
 			    const struct pci_device_id *ent)
 {
 	unsigned long flags = 0;
+	struct drm_device *dev;
 	int ret;
 
 	if (!ent)
@@ -365,7 +362,44 @@
 	if (ret)
 		return ret;
 
-	return drm_get_pci_dev(pdev, ent, &kms_driver);
+	dev = drm_dev_alloc(&kms_driver, &pdev->dev);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto err_free;
+
+	dev->pdev = pdev;
+#ifdef __alpha__
+	dev->hose = pdev->sysdata;
+#endif
+
+	pci_set_drvdata(pdev, dev);
+
+	if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
+		dev->agp = drm_agp_init(dev);
+	if (dev->agp) {
+		dev->agp->agp_mtrr = arch_phys_wc_add(
+			dev->agp->agp_info.aper_base,
+			dev->agp->agp_info.aper_size *
+			1024 * 1024);
+	}
+
+	ret = drm_dev_register(dev, ent->driver_data);
+	if (ret)
+		goto err_agp;
+
+	return 0;
+
+err_agp:
+	if (dev->agp)
+		arch_phys_wc_del(dev->agp->agp_mtrr);
+	kfree(dev->agp);
+	pci_disable_device(pdev);
+err_free:
+	drm_dev_put(dev);
+	return ret;
 }
 
 static void
@@ -516,8 +550,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);
 	
@@ -578,7 +614,7 @@
 
 static struct drm_driver kms_driver = {
 	.driver_features =
-	    DRIVER_USE_AGP | DRIVER_GEM | DRIVER_RENDER,
+	    DRIVER_GEM | DRIVER_RENDER,
 	.load = radeon_driver_load_kms,
 	.open = radeon_driver_open_kms,
 	.postclose = radeon_driver_postclose_kms,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_gem.c
@@ -384,7 +384,6 @@
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_radeon_gem_set_domain *args = data;
 	struct drm_gem_object *gobj;
-	struct radeon_bo *robj;
 	int r;
 
 	/* for now if someone requests domain CPU -
@@ -397,13 +396,12 @@
 		up_read(&rdev->exclusive_lock);
 		return -ENOENT;
 	}
-	robj = gem_to_radeon_bo(gobj);
 
 	r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
 
 	drm_gem_object_put_unlocked(gobj);
 	up_read(&rdev->exclusive_lock);
-	r = radeon_gem_handle_lockup(robj->rdev, r);
+	r = radeon_gem_handle_lockup(rdev, r);
 	return r;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_kms.c
@@ -31,6 +31,7 @@
 #include <linux/uaccess.h>
 #include <linux/vga_switcheroo.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_file.h>
 #include <drm/drm_ioctl.h>
@@ -77,6 +78,11 @@
 	radeon_modeset_fini(rdev);
 	radeon_device_fini(rdev);
 
+	if (dev->agp)
+		arch_phys_wc_del(dev->agp->agp_mtrr);
+	kfree(dev->agp);
+	dev->agp = NULL;
+
 done_free:
 	kfree(rdev);
 	dev->dev_private = NULL;
@@ -506,6 +512,7 @@
 			*value = rdev->config.si.backend_enable_mask;
 		} else {
 			DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n");
+			return -EINVAL;
 		}
 		break;
 	case RADEON_INFO_MAX_SCLK:
@@ -627,58 +634,66 @@
 int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 {
 	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_fpriv *fpriv;
+	struct radeon_vm *vm;
 	int r;
 
 	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) {
-		struct radeon_fpriv *fpriv;
-		struct radeon_vm *vm;
 
 		fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
 		if (unlikely(!fpriv)) {
 			r = -ENOMEM;
-			goto out_suspend;
+			goto err_suspend;
 		}
 
 		if (rdev->accel_working) {
 			vm = &fpriv->vm;
 			r = radeon_vm_init(rdev, vm);
-			if (r) {
-				kfree(fpriv);
-				goto out_suspend;
-			}
+			if (r)
+				goto err_fpriv;
 
 			r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
-			if (r) {
-				radeon_vm_fini(rdev, vm);
-				kfree(fpriv);
-				goto out_suspend;
-			}
+			if (r)
+				goto err_vm_fini;
 
 			/* map the ib pool buffer read only into
 			 * virtual address space */
 			vm->ib_bo_va = radeon_vm_bo_add(rdev, vm,
 							rdev->ring_tmp_bo.bo);
+			if (!vm->ib_bo_va) {
+				r = -ENOMEM;
+				goto err_vm_fini;
+			}
+
 			r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va,
 						  RADEON_VA_IB_OFFSET,
 						  RADEON_VM_PAGE_READABLE |
 						  RADEON_VM_PAGE_SNOOPED);
-			if (r) {
-				radeon_vm_fini(rdev, vm);
-				kfree(fpriv);
-				goto out_suspend;
-			}
+			if (r)
+				goto err_vm_fini;
 		}
 		file_priv->driver_priv = fpriv;
 	}
 
-out_suspend:
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_runtime_put_autosuspend(dev->dev);
+	return 0;
+
+err_vm_fini:
+	radeon_vm_fini(rdev, vm);
+err_fpriv:
+	kfree(fpriv);
+
+err_suspend:
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
 	return r;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_pm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1720,6 +1720,7 @@
 	struct drm_device *ddev = rdev->ddev;
 	struct drm_crtc *crtc;
 	struct radeon_crtc *radeon_crtc;
+	struct radeon_connector *radeon_connector;
 
 	if (!rdev->pm.dpm_enabled)
 		return;
@@ -1729,6 +1730,7 @@
 	/* update active crtc counts */
 	rdev->pm.dpm.new_active_crtcs = 0;
 	rdev->pm.dpm.new_active_crtc_count = 0;
+	rdev->pm.dpm.high_pixelclock_count = 0;
 	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
 		list_for_each_entry(crtc,
 				    &ddev->mode_config.crtc_list, head) {
@@ -1736,6 +1738,12 @@
 			if (crtc->enabled) {
 				rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
 				rdev->pm.dpm.new_active_crtc_count++;
+				if (!radeon_crtc->connector)
+					continue;
+
+				radeon_connector = to_radeon_connector(radeon_crtc->connector);
+				if (radeon_connector->pixelclock_for_modeset > 297000)
+					rdev->pm.dpm.high_pixelclock_count++;
 			}
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_prime.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_prime.c
@@ -94,9 +94,19 @@
 
 	/* pin buffer into GTT */
 	ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
-	if (likely(ret == 0))
-		bo->prime_shared_count++;
+	if (unlikely(ret))
+		goto error;
 
+	if (bo->tbo.moving) {
+		ret = dma_fence_wait(bo->tbo.moving, false);
+		if (unlikely(ret)) {
+			radeon_bo_unpin(bo);
+			goto error;
+		}
+	}
+
+	bo->prime_shared_count++;
+error:
 	radeon_bo_unreserve(bo);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_uvd.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -286,7 +286,7 @@
 	if (rdev->uvd.vcpu_bo == NULL)
 		return -EINVAL;
 
-	memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
+	memcpy_toio((void __iomem *)rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
 
 	size = radeon_bo_size(rdev->uvd.vcpu_bo);
 	size -= rdev->uvd_fw->size;
@@ -294,7 +294,7 @@
 	ptr = rdev->uvd.cpu_addr;
 	ptr += rdev->uvd_fw->size;
 
-	memset(ptr, 0, size);
+	memset_io((void __iomem *)ptr, 0, size);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/radeon_vm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/radeon_vm.c
@@ -1206,13 +1206,17 @@
 	r = radeon_bo_create(rdev, pd_size, align, true,
 			     RADEON_GEM_DOMAIN_VRAM, 0, NULL,
 			     NULL, &vm->page_directory);
-	if (r)
+	if (r) {
+		kfree(vm->page_tables);
+		vm->page_tables = NULL;
 		return r;
-
+	}
 	r = radeon_vm_clear_bo(rdev, vm->page_directory);
 	if (r) {
 		radeon_bo_unref(&vm->page_directory);
 		vm->page_directory = NULL;
+		kfree(vm->page_tables);
+		vm->page_tables = NULL;
 		return r;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/rv740_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/rv740_dpm.c
@@ -250,8 +250,12 @@
 						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
 			u32 reference_clock = rdev->clock.mpll.reference_freq;
 			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
-			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
-			u32 clk_v = 0x40000 * ss.percentage *
+			u32 clk_s, clk_v;
+
+			if (!decoded_ref)
+				return -EINVAL;
+			clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+			clk_v = 0x40000 * ss.percentage *
 				(dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
 
 			mpll_ss1 &= ~CLKV_MASK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/si.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/si.c
@@ -3257,7 +3257,7 @@
 		/* XXX what about 12? */
 		rdev->config.si.tile_config |= (3 << 0);
 		break;
-	}	
+	}
 	switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
 	case 0: /* four banks */
 		rdev->config.si.tile_config |= 0 << 4;
@@ -3616,6 +3616,10 @@
 	for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) {
 		ring = &rdev->ring[i];
 		r = radeon_ring_lock(rdev, ring, 2);
+		if (r) {
+			DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+			return r;
+		}
 
 		/* clear the compute context state */
 		radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0));
@@ -5997,8 +6001,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
@@ -7087,7 +7091,6 @@
 {
 	struct pci_dev *root = rdev->pdev->bus->self;
 	enum pci_bus_speed speed_cap;
-	int bridge_pos, gpu_pos;
 	u32 speed_cntl, current_data_rate;
 	int i;
 	u16 tmp16;
@@ -7129,12 +7132,7 @@
 		DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n");
 	}
 
-	bridge_pos = pci_pcie_cap(root);
-	if (!bridge_pos)
-		return;
-
-	gpu_pos = pci_pcie_cap(rdev->pdev);
-	if (!gpu_pos)
+	if (!pci_is_pcie(root) || !pci_is_pcie(rdev->pdev))
 		return;
 
 	if (speed_cap == PCIE_SPEED_8_0GT) {
@@ -7144,14 +7142,8 @@
 			u16 bridge_cfg2, gpu_cfg2;
 			u32 max_lw, current_lw, tmp;
 
-			pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-			pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
-			pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
+			pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
 
 			tmp = RREG32_PCIE(PCIE_LC_STATUS1);
 			max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -7169,15 +7161,23 @@
 
 			for (i = 0; i < 10; i++) {
 				/* check status */
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_DEVSTA,
+							  &tmp16);
 				if (tmp16 & PCI_EXP_DEVSTA_TRPND)
 					break;
 
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
-
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
+							  &bridge_cfg);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL,
+							  &gpu_cfg);
+
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &bridge_cfg2);
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &gpu_cfg2);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp |= LC_SET_QUIESCE;
@@ -7190,26 +7190,38 @@
 				msleep(100);
 
 				/* linkctl */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
-
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
-				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
-				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
-				pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   bridge_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
+				pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL,
+								   PCI_EXP_LNKCTL_HAWD,
+								   gpu_cfg &
+								   PCI_EXP_LNKCTL_HAWD);
 
 				/* linkctl2 */
-				pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
-
-				pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-				tmp16 &= ~((1 << 4) | (7 << 9));
-				tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
-				pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (bridge_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(root,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
+
+				pcie_capability_read_word(rdev->pdev,
+							  PCI_EXP_LNKCTL2,
+							  &tmp16);
+				tmp16 &= ~(PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN);
+				tmp16 |= (gpu_cfg2 &
+					  (PCI_EXP_LNKCTL2_ENTER_COMP |
+					   PCI_EXP_LNKCTL2_TX_MARGIN));
+				pcie_capability_write_word(rdev->pdev,
+							   PCI_EXP_LNKCTL2,
+							   tmp16);
 
 				tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
 				tmp &= ~LC_SET_QUIESCE;
@@ -7223,15 +7235,15 @@
 	speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
 	WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
 
-	pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
-	tmp16 &= ~0xf;
+	pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL2, &tmp16);
+	tmp16 &= ~PCI_EXP_LNKCTL2_TLS;
 	if (speed_cap == PCIE_SPEED_8_0GT)
-		tmp16 |= 3; /* gen3 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_8_0GT; /* gen3 */
 	else if (speed_cap == PCIE_SPEED_5_0GT)
-		tmp16 |= 2; /* gen2 */
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_5_0GT; /* gen2 */
 	else
-		tmp16 |= 1; /* gen1 */
-	pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+		tmp16 |= PCI_EXP_LNKCTL2_TLS_2_5GT; /* gen1 */
+	pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL2, tmp16);
 
 	speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
 	speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/si_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/si_dpm.c
@@ -3002,6 +3002,9 @@
 		    (rdev->pdev->device == 0x6605)) {
 			max_sclk = 75000;
 		}
+
+		if (rdev->pm.dpm.high_pixelclock_count > 1)
+			disable_sclk_switching = true;
 	}
 
 	if (rps->vce_active) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/sumo_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1493,8 +1493,10 @@
 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
-		if (!rdev->pm.power_state[i].clock_info)
+		if (!rdev->pm.power_state[i].clock_info) {
+			kfree(rdev->pm.dpm.ps);
 			return -EINVAL;
+		}
 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
 		if (ps == NULL) {
 			kfree(rdev->pm.dpm.ps);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/radeon/trinity_dpm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -1771,8 +1771,10 @@
 		non_clock_array_index = power_state->v2.nonClockInfoIndex;
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			&non_clock_info_array->nonClockInfo[non_clock_array_index];
-		if (!rdev->pm.power_state[i].clock_info)
+		if (!rdev->pm.power_state[i].clock_info) {
+			kfree(rdev->pm.dpm.ps);
 			return -EINVAL;
+		}
 		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
 		if (ps == NULL) {
 			kfree(rdev->pm.dpm.ps);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rcar-du/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/rcar-du/Kconfig
@@ -23,6 +23,7 @@
 config DRM_RCAR_LVDS
 	tristate "R-Car DU LVDS Encoder Support"
 	depends on DRM && DRM_BRIDGE && OF
+	select DRM_KMS_HELPER
 	select DRM_PANEL
 	select OF_FLATTREE
 	select OF_OVERLAY
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -785,13 +785,15 @@
 
 		drm_plane_create_alpha_property(&plane->plane);
 
-		if (type == DRM_PLANE_TYPE_PRIMARY)
-			continue;
-
-		drm_object_attach_property(&plane->plane.base,
-					   rcdu->props.colorkey,
-					   RCAR_DU_COLORKEY_NONE);
-		drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
+		if (type == DRM_PLANE_TYPE_PRIMARY) {
+			drm_plane_create_zpos_immutable_property(&plane->plane,
+								 0);
+		} else {
+			drm_object_attach_property(&plane->plane.base,
+						   rcdu->props.colorkey,
+						   RCAR_DU_COLORKEY_NONE);
+			drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -392,12 +392,14 @@
 		drm_plane_helper_add(&plane->plane,
 				     &rcar_du_vsp_plane_helper_funcs);
 
-		if (type == DRM_PLANE_TYPE_PRIMARY)
-			continue;
-
-		drm_plane_create_alpha_property(&plane->plane);
-		drm_plane_create_zpos_property(&plane->plane, 1, 1,
-					       vsp->num_planes - 1);
+		if (type == DRM_PLANE_TYPE_PRIMARY) {
+			drm_plane_create_zpos_immutable_property(&plane->plane,
+								 0);
+		} else {
+			drm_plane_create_alpha_property(&plane->plane);
+			drm_plane_create_zpos_property(&plane->plane, 1, 1,
+						       vsp->num_planes - 1);
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -16,6 +16,7 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/sys_soc.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -842,8 +843,23 @@
 	return 0;
 }
 
+static const struct rcar_lvds_device_info rcar_lvds_r8a7790es1_info = {
+	.gen = 2,
+	.quirks = RCAR_LVDS_QUIRK_LANES,
+	.pll_setup = rcar_lvds_pll_setup_gen2,
+};
+
+static const struct soc_device_attribute lvds_quirk_matches[] = {
+	{
+		.soc_id = "r8a7790", .revision = "ES1.*",
+		.data = &rcar_lvds_r8a7790es1_info,
+	},
+	{ /* sentinel */ }
+};
+
 static int rcar_lvds_probe(struct platform_device *pdev)
 {
+	const struct soc_device_attribute *attr;
 	struct rcar_lvds *lvds;
 	struct resource *mem;
 	int ret;
@@ -857,6 +873,10 @@
 	lvds->dev = &pdev->dev;
 	lvds->info = of_device_get_match_data(&pdev->dev);
 
+	attr = soc_device_match(lvds_quirk_matches);
+	if (attr)
+		lvds->info = attr->data;
+
 	ret = rcar_lvds_parse_dt(lvds);
 	if (ret < 0)
 		return ret;
@@ -893,12 +913,6 @@
 	.pll_setup = rcar_lvds_pll_setup_gen2,
 };
 
-static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = {
-	.gen = 2,
-	.quirks = RCAR_LVDS_QUIRK_LANES,
-	.pll_setup = rcar_lvds_pll_setup_gen2,
-};
-
 static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
 	.gen = 3,
 	.quirks = RCAR_LVDS_QUIRK_PWD,
@@ -930,7 +944,7 @@
 	{ .compatible = "renesas,r8a7744-lvds", .data = &rcar_lvds_gen2_info },
 	{ .compatible = "renesas,r8a774a1-lvds", .data = &rcar_lvds_gen3_info },
 	{ .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info },
-	{ .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_r8a7790_info },
+	{ .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_gen2_info },
 	{ .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
 	{ .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
 	{ .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -325,15 +325,9 @@
 			    void *data)
 {
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
-	const struct rockchip_dp_chip_data *dp_data;
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	dp_data = of_device_get_match_data(dev);
-	if (!dp_data)
-		return -ENODEV;
-
-	dp->data = dp_data;
 	dp->drm_dev = drm_dev;
 
 	ret = rockchip_dp_drm_create_encoder(dp);
@@ -344,16 +338,9 @@
 
 	dp->plat_data.encoder = &dp->encoder;
 
-	dp->plat_data.dev_type = dp->data->chip_type;
-	dp->plat_data.power_on_start = rockchip_dp_poweron_start;
-	dp->plat_data.power_off = rockchip_dp_powerdown;
-	dp->plat_data.get_modes = rockchip_dp_get_modes;
-
-	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp)) {
-		ret = PTR_ERR(dp->adp);
+	ret = analogix_dp_bind(dp->adp, drm_dev);
+	if (ret)
 		goto err_cleanup_encoder;
-	}
 
 	return 0;
 err_cleanup_encoder:
@@ -368,8 +355,6 @@
 
 	analogix_dp_unbind(dp->adp);
 	dp->encoder.funcs->destroy(&dp->encoder);
-
-	dp->adp = ERR_PTR(-ENODEV);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -380,10 +365,15 @@
 static int rockchip_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	const struct rockchip_dp_chip_data *dp_data;
 	struct drm_panel *panel = NULL;
 	struct rockchip_dp_device *dp;
 	int ret;
 
+	dp_data = of_device_get_match_data(dev);
+	if (!dp_data)
+		return -ENODEV;
+
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
 	if (ret < 0)
 		return ret;
@@ -394,7 +384,12 @@
 
 	dp->dev = dev;
 	dp->adp = ERR_PTR(-ENODEV);
+	dp->data = dp_data;
 	dp->plat_data.panel = panel;
+	dp->plat_data.dev_type = dp->data->chip_type;
+	dp->plat_data.power_on_start = rockchip_dp_poweron_start;
+	dp->plat_data.power_off = rockchip_dp_powerdown;
+	dp->plat_data.get_modes = rockchip_dp_get_modes;
 
 	ret = rockchip_dp_of_probe(dp);
 	if (ret < 0)
@@ -402,12 +397,27 @@
 
 	platform_set_drvdata(pdev, dp);
 
-	return component_add(dev, &rockchip_dp_component_ops);
+	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	ret = component_add(dev, &rockchip_dp_component_ops);
+	if (ret)
+		goto err_dp_remove;
+
+	return 0;
+
+err_dp_remove:
+	analogix_dp_remove(dp->adp);
+	return ret;
 }
 
 static int rockchip_dp_remove(struct platform_device *pdev)
 {
+	struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
+
 	component_del(&pdev->dev, &rockchip_dp_component_ops);
+	analogix_dp_remove(dp->adp);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -72,6 +72,7 @@
 	ret = regmap_write(dp->grf, reg, val);
 	if (ret) {
 		DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
+		clk_disable_unprepare(dp->grf_clk);
 		return ret;
 	}
 
@@ -274,8 +275,9 @@
 	return ret;
 }
 
-static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
-				       struct drm_display_mode *mode)
+static enum drm_mode_status
+cdn_dp_connector_mode_valid(struct drm_connector *connector,
+			    struct drm_display_mode *mode)
 {
 	struct cdn_dp_device *dp = connector_to_dp(connector);
 	struct drm_display_info *display_info = &dp->connector.display_info;
@@ -561,7 +563,7 @@
 	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
 	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
 
-	memcpy(&dp->mode, adjusted, sizeof(*mode));
+	drm_mode_copy(&dp->mode, adjusted);
 }
 
 static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
@@ -1145,6 +1147,7 @@
 	struct cdn_dp_device *dp;
 	struct extcon_dev *extcon;
 	struct phy *phy;
+	int ret;
 	int i;
 
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
@@ -1185,9 +1188,19 @@
 	mutex_init(&dp->lock);
 	dev_set_drvdata(dev, dp);
 
-	cdn_dp_audio_codec_init(dp, dev);
+	ret = cdn_dp_audio_codec_init(dp, dev);
+	if (ret)
+		return ret;
+
+	ret = component_add(dev, &cdn_dp_component_ops);
+	if (ret)
+		goto err_audio_deinit;
+
+	return 0;
 
-	return component_add(dev, &cdn_dp_component_ops);
+err_audio_deinit:
+	platform_device_unregister(dp->audio_pdev);
+	return ret;
 }
 
 static int cdn_dp_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -231,7 +231,8 @@
 	struct dw_mipi_dsi *dmd;
 	const struct rockchip_dw_dsi_chip_data *cdata;
 	struct dw_mipi_dsi_plat_data pdata;
-	int devcnt;
+
+	bool dsi_bound;
 };
 
 struct dphy_pll_parameter_map {
@@ -480,8 +481,8 @@
 	unsigned long best_freq = 0;
 	unsigned long fvco_min, fvco_max, fin, fout;
 	unsigned int min_prediv, max_prediv;
-	unsigned int _prediv, uninitialized_var(best_prediv);
-	unsigned long _fbdiv, uninitialized_var(best_fbdiv);
+	unsigned int _prediv, best_prediv;
+	unsigned long _fbdiv, best_fbdiv;
 	unsigned long min_delta = ULONG_MAX;
 
 	dsi->format = format;
@@ -564,13 +565,8 @@
 	.get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
 };
 
-static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
-					int mux)
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
 {
-	if (dsi->cdata->lcdsel_grf_reg)
-		regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
-			mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
-
 	if (dsi->cdata->lanecfg1_grf_reg)
 		regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
 					      dsi->cdata->lanecfg1);
@@ -584,6 +580,13 @@
 					      dsi->cdata->enable);
 }
 
+static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
+					    int mux)
+{
+	regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+		mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+}
+
 static int
 dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 				 struct drm_crtc_state *crtc_state,
@@ -624,10 +627,6 @@
 	if (mux < 0)
 		return;
 
-	pm_runtime_get_sync(dsi->dev);
-	if (dsi->slave)
-		pm_runtime_get_sync(dsi->slave->dev);
-
 	/*
 	 * For the RK3399, the clk of grf must be enabled before writing grf
 	 * register. And for RK3288 or other soc, this grf_clk must be NULL,
@@ -639,27 +638,17 @@
 		return;
 	}
 
-	dw_mipi_dsi_rockchip_config(dsi, mux);
+	dw_mipi_dsi_rockchip_set_lcdsel(dsi, mux);
 	if (dsi->slave)
-		dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+		dw_mipi_dsi_rockchip_set_lcdsel(dsi->slave, mux);
 
 	clk_disable_unprepare(dsi->grf_clk);
 }
 
-static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
-{
-	struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
-
-	if (dsi->slave)
-		pm_runtime_put(dsi->slave->dev);
-	pm_runtime_put(dsi->dev);
-}
-
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi_encoder_helper_funcs = {
 	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
 	.enable = dw_mipi_dsi_encoder_enable,
-	.disable = dw_mipi_dsi_encoder_disable,
 };
 
 static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
@@ -794,25 +783,56 @@
 		put_device(second);
 	}
 
+	pm_runtime_get_sync(dsi->dev);
+	if (dsi->slave)
+		pm_runtime_get_sync(dsi->slave->dev);
+
 	ret = clk_prepare_enable(dsi->pllref_clk);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
-		return ret;
+		goto out_pm_runtime;
+	}
+
+	/*
+	 * With the GRF clock running, write lane and dual-mode configurations
+	 * that won't change immediately. If we waited until enable() to do
+	 * this, things like panel preparation would not be able to send
+	 * commands over DSI.
+	 */
+	ret = clk_prepare_enable(dsi->grf_clk);
+	if (ret) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+		goto out_pm_runtime;
 	}
 
+	dw_mipi_dsi_rockchip_config(dsi);
+	if (dsi->slave)
+		dw_mipi_dsi_rockchip_config(dsi->slave);
+
+	clk_disable_unprepare(dsi->grf_clk);
+
 	ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
-		return ret;
+		goto out_pm_runtime;
 	}
 
 	ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
-		return ret;
+		goto out_pm_runtime;
 	}
 
+	dsi->dsi_bound = true;
+
 	return 0;
+
+out_pm_runtime:
+	pm_runtime_put(dsi->dev);
+	if (dsi->slave)
+		pm_runtime_put(dsi->slave->dev);
+
+	return ret;
 }
 
 static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
@@ -824,9 +844,15 @@
 	if (dsi->is_slave)
 		return;
 
+	dsi->dsi_bound = false;
+
 	dw_mipi_dsi_unbind(dsi->dmd);
 
 	clk_disable_unprepare(dsi->pllref_clk);
+
+	pm_runtime_put(dsi->dev);
+	if (dsi->slave)
+		pm_runtime_put(dsi->slave->dev);
 }
 
 static const struct component_ops dw_mipi_dsi_rockchip_ops = {
@@ -884,6 +910,36 @@
 	.detach = dw_mipi_dsi_rockchip_host_detach,
 };
 
+static int __maybe_unused dw_mipi_dsi_rockchip_resume(struct device *dev)
+{
+	struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
+	int ret;
+
+	/*
+	 * Re-configure DSI state, if we were previously initialized. We need
+	 * to do this before rockchip_drm_drv tries to re-enable() any panels.
+	 */
+	if (dsi->dsi_bound) {
+		ret = clk_prepare_enable(dsi->grf_clk);
+		if (ret) {
+			DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+			return ret;
+		}
+
+		dw_mipi_dsi_rockchip_config(dsi);
+		if (dsi->slave)
+			dw_mipi_dsi_rockchip_config(dsi->slave);
+
+		clk_disable_unprepare(dsi->grf_clk);
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_mipi_dsi_rockchip_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, dw_mipi_dsi_rockchip_resume)
+};
+
 static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -967,23 +1023,16 @@
 		if (ret != -EPROBE_DEFER)
 			DRM_DEV_ERROR(dev,
 				      "Failed to probe dw_mipi_dsi: %d\n", ret);
-		goto err_clkdisable;
+		return ret;
 	}
 
 	return 0;
-
-err_clkdisable:
-	clk_disable_unprepare(dsi->pllref_clk);
-	return ret;
 }
 
 static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
 {
 	struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
 
-	if (dsi->devcnt == 0)
-		component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
-
 	dw_mipi_dsi_remove(dsi->dmd);
 
 	return 0;
@@ -1072,6 +1121,13 @@
 	.remove		= dw_mipi_dsi_rockchip_remove,
 	.driver		= {
 		.of_match_table = dw_mipi_dsi_rockchip_dt_ids,
+		.pm	= &dw_mipi_dsi_rockchip_pm_ops,
 		.name	= "dw-mipi-dsi-rockchip",
+		/*
+		 * For dual-DSI display, one DSI pokes at the other DSI's
+		 * drvdata in dw_mipi_dsi_rockchip_find_second(). This is not
+		 * safe for asynchronous probe.
+		 */
+		.probe_type = PROBE_FORCE_SYNCHRONOUS,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -528,13 +528,6 @@
 		return ret;
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-			      ret);
-		return ret;
-	}
-
 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
 	if (IS_ERR(hdmi->phy)) {
 		ret = PTR_ERR(hdmi->phy);
@@ -543,6 +536,13 @@
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+			      ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -487,7 +487,7 @@
 	inno_hdmi_setup(hdmi, adj_mode);
 
 	/* Store the display mode for plugin/DPMS poweron events */
-	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
+	drm_mode_copy(&hdmi->previous_mode, adj_mode);
 }
 
 static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -382,7 +382,7 @@
 	struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder);
 
 	/* Store the display mode for plugin/DPMS poweron events. */
-	memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
+	drm_mode_copy(&hdmi->previous_mode, adj_mode);
 }
 
 static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -249,9 +249,6 @@
 	else
 		ret = rockchip_drm_gem_object_mmap_dma(obj, vma);
 
-	if (ret)
-		drm_gem_vm_close(vma);
-
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ linux-ein-5.4.0/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -234,14 +234,22 @@
 	VOP_REG_SET(vop, common, cfg_done, 1);
 }
 
-static bool has_rb_swapped(uint32_t format)
+static bool has_rb_swapped(uint32_t version, uint32_t format)
 {
 	switch (format) {
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ABGR8888:
-	case DRM_FORMAT_BGR888:
 	case DRM_FORMAT_BGR565:
 		return true;
+	/*
+	 * full framework (IP version 3.x) only need rb swapped for RGB888 and
+	 * little framework (IP version 2.x) only need rb swapped for BGR888,
+	 * check for 3.x to also only rb swap BGR888 for unknown vop version
+	 */
+	case DRM_FORMAT_RGB888:
+		return VOP_MAJOR(version) == 3;
+	case DRM_FORMAT_BGR888:
+		return VOP_MAJOR(version) != 3;
 	default:
 		return false;
 	}
@@ -654,13 +662,13 @@
 	if (crtc->state->self_refresh_active)
 		rockchip_drm_set_win_enabled(crtc, false);
 
+	if (crtc->state->self_refresh_active)
+		goto out;
+
 	mutex_lock(&vop->vop_lock);
 
 	drm_crtc_vblank_off(crtc);
 
-	if (crtc->state->self_refresh_active)
-		goto out;
-
 	/*
 	 * Vop standby will take effect at end of current frame,
 	 * if dsp hold valid irq happen, it means standby complete.
@@ -692,9 +700,9 @@
 	vop_core_clks_disable(vop);
 	pm_runtime_put(vop->dev);
 
-out:
 	mutex_unlock(&vop->vop_lock);
 
+out:
 	if (crtc->state->event && !crtc->state->active) {
 		spin_lock_irq(&crtc->dev->event_lock);
 		drm_crtc_send_vblank_event(crtc, crtc->state->event);
@@ -886,7 +894,7 @@
 	VOP_WIN_SET(vop, win, dsp_info, dsp_info);
 	VOP_WIN_SET(vop, win, dsp_st, dsp_st);
 
-	rb_swap = has_rb_swapped(fb->format->format);
+	rb_swap = has_rb_swapped(vop->data->version, fb->format->format);
 	VOP_WIN_SET(vop, win, rb_swap, rb_swap);
 
 	/*
@@ -1040,10 +1048,41 @@
 				struct drm_display_mode *adjusted_mode)
 {
 	struct vop *vop = to_vop(crtc);
+	unsigned long rate;
 
-	adjusted_mode->clock =
-		DIV_ROUND_UP(clk_round_rate(vop->dclk,
-					    adjusted_mode->clock * 1000), 1000);
+	/*
+	 * Clock craziness.
+	 *
+	 * Key points:
+	 *
+	 * - DRM works in in kHz.
+	 * - Clock framework works in Hz.
+	 * - Rockchip's clock driver picks the clock rate that is the
+	 *   same _OR LOWER_ than the one requested.
+	 *
+	 * Action plan:
+	 *
+	 * 1. When DRM gives us a mode, we should add 999 Hz to it.  That way
+	 *    if the clock we need is 60000001 Hz (~60 MHz) and DRM tells us to
+	 *    make 60000 kHz then the clock framework will actually give us
+	 *    the right clock.
+	 *
+	 *    NOTE: if the PLL (maybe through a divider) could actually make
+	 *    a clock rate 999 Hz higher instead of the one we want then this
+	 *    could be a problem.  Unfortunately there's not much we can do
+	 *    since it's baked into DRM to use kHz.  It shouldn't matter in
+	 *    practice since Rockchip PLLs are controlled by tables and
+	 *    even if there is a divider in the middle I wouldn't expect PLL
+	 *    rates in the table that are just a few kHz different.
+	 *
+	 * 2. Get the clock framework to round the rate for us to tell us
+	 *    what it will actually make.
+	 *
+	 * 3. Store the rounded up rate so that we don't need to worry about
+	 *    this in the actual clk_set_rate().
+	 */
+	rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000 + 999);
+	adjusted_mode->clock = DIV_ROUND_UP(rate, 1000);
 
 	return true;
 }
@@ -1257,7 +1296,11 @@
 {
 	struct rockchip_crtc_state *rockchip_state;
 
-	rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL);
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state),
+				 sizeof(*rockchip_state), GFP_KERNEL);
 	if (!rockchip_state)
 		return NULL;
 
@@ -1282,7 +1325,10 @@
 	if (crtc->state)
 		vop_crtc_destroy_state(crtc, crtc->state);
 
-	__drm_atomic_helper_crtc_reset(crtc, &crtc_state->base);
+	if (crtc_state)
+		__drm_atomic_helper_crtc_reset(crtc, &crtc_state->base);
+	else
+		__drm_atomic_helper_crtc_reset(crtc, NULL);
 }
 
 #ifdef CONFIG_DRM_ANALOGIX_DP
@@ -1817,10 +1863,10 @@
 	vop_win_init(vop);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	vop->len = resource_size(res);
 	vop->regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(vop->regs))
 		return PTR_ERR(vop->regs);
+	vop->len = resource_size(res);
 
 	vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL);
 	if (!vop->regsbak)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/scheduler/sched_entity.c
+++ linux-ein-5.4.0/drivers/gpu/drm/scheduler/sched_entity.c
@@ -235,11 +235,16 @@
 static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity)
 {
 	struct drm_sched_job *job;
+	struct dma_fence *f;
 	int r;
 
 	while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) {
 		struct drm_sched_fence *s_fence = job->s_fence;
 
+		/* Wait for all dependencies to avoid data corruptions */
+		while ((f = job->sched->ops->dependency(job, entity)))
+			dma_fence_wait(f, false);
+
 		drm_sched_fence_scheduled(s_fence);
 		dma_fence_set_error(&s_fence->finished, -ESRCH);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/scheduler/sched_main.c
+++ linux-ein-5.4.0/drivers/gpu/drm/scheduler/sched_main.c
@@ -284,10 +284,21 @@
 	unsigned long flags;
 
 	sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
+
+	/* Protects against concurrent deletion in drm_sched_get_cleanup_job */
+	spin_lock_irqsave(&sched->job_list_lock, flags);
 	job = list_first_entry_or_null(&sched->ring_mirror_list,
 				       struct drm_sched_job, node);
 
 	if (job) {
+		/*
+		 * Remove the bad job so it cannot be freed by concurrent
+		 * drm_sched_cleanup_jobs. It will be reinserted back after sched->thread
+		 * is parked at which point it's safe.
+		 */
+		list_del_init(&job->node);
+		spin_unlock_irqrestore(&sched->job_list_lock, flags);
+
 		job->sched->ops->timedout_job(job);
 
 		/*
@@ -298,6 +309,8 @@
 			job->sched->ops->free_job(job);
 			sched->free_guilty = false;
 		}
+	} else {
+		spin_unlock_irqrestore(&sched->job_list_lock, flags);
 	}
 
 	spin_lock_irqsave(&sched->job_list_lock, flags);
@@ -370,6 +383,20 @@
 	kthread_park(sched->thread);
 
 	/*
+	 * Reinsert back the bad job here - now it's safe as
+	 * drm_sched_get_cleanup_job cannot race against us and release the
+	 * bad job at this point - we parked (waited for) any in progress
+	 * (earlier) cleanups and drm_sched_get_cleanup_job will not be called
+	 * now until the scheduler thread is unparked.
+	 */
+	if (bad && bad->sched == sched)
+		/*
+		 * Add at the head of the queue to reflect it was the earliest
+		 * job extracted.
+		 */
+		list_add(&bad->node, &sched->ring_mirror_list);
+
+	/*
 	 * Iterate the job list from later to  earlier one and either deactive
 	 * their HW callbacks or remove them from mirror list if they already
 	 * signaled.
@@ -496,8 +523,10 @@
 		fence = sched->ops->run_job(s_job);
 
 		if (IS_ERR_OR_NULL(fence)) {
+			if (IS_ERR(fence))
+				dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
+
 			s_job->s_fence->parent = NULL;
-			dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
 		} else {
 			s_job->s_fence->parent = fence;
 		}
@@ -627,48 +656,48 @@
 
 	trace_drm_sched_process_job(s_fence);
 
+	dma_fence_get(&s_fence->finished);
 	drm_sched_fence_finished(s_fence);
+	dma_fence_put(&s_fence->finished);
 	wake_up_interruptible(&sched->wake_up_worker);
 }
 
 /**
- * drm_sched_cleanup_jobs - destroy finished jobs
+ * drm_sched_get_cleanup_job - fetch the next finished job to be destroyed
  *
  * @sched: scheduler instance
  *
- * Remove all finished jobs from the mirror list and destroy them.
+ * Returns the next finished job from the mirror list (if there is one)
+ * ready for it to be destroyed.
  */
-static void drm_sched_cleanup_jobs(struct drm_gpu_scheduler *sched)
+static struct drm_sched_job *
+drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
 {
+	struct drm_sched_job *job;
 	unsigned long flags;
 
 	/* Don't destroy jobs while the timeout worker is running */
 	if (sched->timeout != MAX_SCHEDULE_TIMEOUT &&
 	    !cancel_delayed_work(&sched->work_tdr))
-		return;
-
+		return NULL;
 
-	while (!list_empty(&sched->ring_mirror_list)) {
-		struct drm_sched_job *job;
+	spin_lock_irqsave(&sched->job_list_lock, flags);
 
-		job = list_first_entry(&sched->ring_mirror_list,
+	job = list_first_entry_or_null(&sched->ring_mirror_list,
 				       struct drm_sched_job, node);
-		if (!dma_fence_is_signaled(&job->s_fence->finished))
-			break;
 
-		spin_lock_irqsave(&sched->job_list_lock, flags);
+	if (job && dma_fence_is_signaled(&job->s_fence->finished)) {
 		/* remove job from ring_mirror_list */
 		list_del_init(&job->node);
-		spin_unlock_irqrestore(&sched->job_list_lock, flags);
-
-		sched->ops->free_job(job);
+	} else {
+		job = NULL;
+		/* queue timeout for next job */
+		drm_sched_start_timeout(sched);
 	}
 
-	/* queue timeout for next job */
-	spin_lock_irqsave(&sched->job_list_lock, flags);
-	drm_sched_start_timeout(sched);
 	spin_unlock_irqrestore(&sched->job_list_lock, flags);
 
+	return job;
 }
 
 /**
@@ -708,12 +737,19 @@
 		struct drm_sched_fence *s_fence;
 		struct drm_sched_job *sched_job;
 		struct dma_fence *fence;
+		struct drm_sched_job *cleanup_job = NULL;
 
 		wait_event_interruptible(sched->wake_up_worker,
-					 (drm_sched_cleanup_jobs(sched),
+					 (cleanup_job = drm_sched_get_cleanup_job(sched)) ||
 					 (!drm_sched_blocked(sched) &&
 					  (entity = drm_sched_select_entity(sched))) ||
-					 kthread_should_stop()));
+					 kthread_should_stop());
+
+		if (cleanup_job) {
+			sched->ops->free_job(cleanup_job);
+			/* queue timeout for next job */
+			drm_sched_start_timeout(sched);
+		}
 
 		if (!entity)
 			continue;
@@ -741,8 +777,9 @@
 					  r);
 			dma_fence_put(fence);
 		} else {
+			if (IS_ERR(fence))
+				dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
 
-			dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
 			drm_sched_process_job(NULL, &sched_job->cb);
 		}
 
@@ -814,6 +851,9 @@
 	if (sched->thread)
 		kthread_stop(sched->thread);
 
+	/* Confirm no work left behind accessing device structures */
+	cancel_delayed_work_sync(&sched->work_tdr);
+
 	sched->ready = false;
 }
 EXPORT_SYMBOL(drm_sched_fini);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+++ linux-ein-5.4.0/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
@@ -53,6 +53,7 @@
 cmdline_test(drm_cmdline_test_rotate_90)
 cmdline_test(drm_cmdline_test_rotate_180)
 cmdline_test(drm_cmdline_test_rotate_270)
+cmdline_test(drm_cmdline_test_rotate_multiple)
 cmdline_test(drm_cmdline_test_rotate_invalid_val)
 cmdline_test(drm_cmdline_test_rotate_truncated)
 cmdline_test(drm_cmdline_test_hmirror)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+++ linux-ein-5.4.0/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
@@ -856,6 +856,17 @@
 	return 0;
 }
 
+static int drm_cmdline_test_rotate_multiple(void *ignored)
+{
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=0,rotate=90",
+							  &no_connector,
+							  &mode));
+
+	return 0;
+}
+
 static int drm_cmdline_test_rotate_invalid_val(void *ignored)
 {
 	struct drm_cmdline_mode mode = { };
@@ -888,7 +899,7 @@
 	FAIL_ON(!mode.specified);
 	FAIL_ON(mode.xres != 720);
 	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_X);
+	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X));
 
 	FAIL_ON(mode.refresh_specified);
 
@@ -913,7 +924,7 @@
 	FAIL_ON(!mode.specified);
 	FAIL_ON(mode.xres != 720);
 	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_Y);
+	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y));
 
 	FAIL_ON(mode.refresh_specified);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sti/sti_dvo.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sti/sti_dvo.c
@@ -287,7 +287,7 @@
 
 	DRM_DEBUG_DRIVER("\n");
 
-	memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
+	drm_mode_copy(&dvo->mode, mode);
 
 	/* According to the path used (main or aux), the dvo clocks should
 	 * have a different parent clock. */
@@ -345,8 +345,9 @@
 
 #define CLK_TOLERANCE_HZ 50
 
-static int sti_dvo_connector_mode_valid(struct drm_connector *connector,
-					struct drm_display_mode *mode)
+static enum drm_mode_status
+sti_dvo_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
 {
 	int target = mode->clock * 1000;
 	int target_min = target - CLK_TOLERANCE_HZ;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sti/sti_hda.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sti/sti_hda.c
@@ -522,7 +522,7 @@
 
 	DRM_DEBUG_DRIVER("\n");
 
-	memcpy(&hda->mode, mode, sizeof(struct drm_display_mode));
+	drm_mode_copy(&hda->mode, mode);
 
 	if (!hda_get_mode_idx(hda->mode, &mode_idx)) {
 		DRM_ERROR("Undefined mode\n");
@@ -600,8 +600,9 @@
 
 #define CLK_TOLERANCE_HZ 50
 
-static int sti_hda_connector_mode_valid(struct drm_connector *connector,
-					struct drm_display_mode *mode)
+static enum drm_mode_status
+sti_hda_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
 {
 	int target = mode->clock * 1000;
 	int target_min = target - CLK_TOLERANCE_HZ;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sti/sti_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sti/sti_hdmi.c
@@ -933,7 +933,7 @@
 	DRM_DEBUG_DRIVER("\n");
 
 	/* Copy the drm display mode in the connector local structure */
-	memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
+	drm_mode_copy(&hdmi->mode, mode);
 
 	/* Update clock framerate according to the selected mode */
 	ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
@@ -996,8 +996,9 @@
 
 #define CLK_TOLERANCE_HZ 50
 
-static int sti_hdmi_connector_mode_valid(struct drm_connector *connector,
-					struct drm_display_mode *mode)
+static enum drm_mode_status
+sti_hdmi_connector_mode_valid(struct drm_connector *connector,
+			      struct drm_display_mode *mode)
 {
 	int target = mode->clock * 1000;
 	int target_min = target - CLK_TOLERANCE_HZ;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/stm/ltdc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/stm/ltdc.c
@@ -424,9 +424,12 @@
 				    struct drm_crtc_state *old_state)
 {
 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
+	struct drm_device *ddev = crtc->dev;
 
 	DRM_DEBUG_DRIVER("\n");
 
+	pm_runtime_get_sync(ddev->dev);
+
 	/* Sets the background color value */
 	reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/Kconfig
@@ -46,6 +46,7 @@
 	default MACH_SUN8I
 	select CRC_CCITT
 	select DRM_MIPI_DSI
+	select RESET_CONTROLLER
 	select PHY_SUN6I_MIPI_DPHY
 	help
 	  Choose this option if you want have an Allwinner SoC with
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -589,8 +589,7 @@
 
 	/* We can't have an alpha plane at the lowest position */
 	if (!backend->quirks->supports_lowest_plane_alpha &&
-	    (plane_states[0]->fb->format->has_alpha ||
-	    (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)))
+	    (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE))
 		return -EINVAL;
 
 	for (i = 1; i < num_planes; i++) {
@@ -986,7 +985,6 @@
 
 static const struct sun4i_backend_quirks sun7i_backend_quirks = {
 	.needs_output_muxing = true,
-	.supports_lowest_plane_alpha = true,
 };
 
 static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -85,7 +85,6 @@
 	}
 
 	drm_mode_config_init(drm);
-	drm->mode_config.allow_fb_modifiers = true;
 
 	ret = component_bind_all(drm->dev, drm);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_frontend.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -407,6 +407,7 @@
 	struct drm_framebuffer *fb = state->fb;
 	const struct drm_format_info *format = fb->format;
 	uint64_t modifier = fb->modifier;
+	unsigned int ch1_phase_idx;
 	u32 out_fmt_val;
 	u32 in_fmt_val, in_mod_val, in_ps_val;
 	unsigned int i;
@@ -442,18 +443,19 @@
 	 * I have no idea what this does exactly, but it seems to be
 	 * related to the scaler FIR filter phase parameters.
 	 */
+	ch1_phase_idx = (format->num_planes > 1) ? 1 : 0;
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG,
-		     frontend->data->ch_phase[0].horzphase);
+		     frontend->data->ch_phase[0]);
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG,
-		     frontend->data->ch_phase[1].horzphase);
+		     frontend->data->ch_phase[ch1_phase_idx]);
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG,
-		     frontend->data->ch_phase[0].vertphase[0]);
+		     frontend->data->ch_phase[0]);
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG,
-		     frontend->data->ch_phase[1].vertphase[0]);
+		     frontend->data->ch_phase[ch1_phase_idx]);
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG,
-		     frontend->data->ch_phase[0].vertphase[1]);
+		     frontend->data->ch_phase[0]);
 	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG,
-		     frontend->data->ch_phase[1].vertphase[1]);
+		     frontend->data->ch_phase[ch1_phase_idx]);
 
 	/*
 	 * Checking the input format is sufficient since we currently only
@@ -687,30 +689,12 @@
 };
 
 static const struct sun4i_frontend_data sun4i_a10_frontend = {
-	.ch_phase		= {
-		{
-			.horzphase = 0,
-			.vertphase = { 0, 0 },
-		},
-		{
-			.horzphase = 0xfc000,
-			.vertphase = { 0xfc000, 0xfc000 },
-		},
-	},
+	.ch_phase		= { 0x000, 0xfc000 },
 	.has_coef_rdy		= true,
 };
 
 static const struct sun4i_frontend_data sun8i_a33_frontend = {
-	.ch_phase		= {
-		{
-			.horzphase = 0x400,
-			.vertphase = { 0x400, 0x400 },
-		},
-		{
-			.horzphase = 0x400,
-			.vertphase = { 0x400, 0x400 },
-		},
-	},
+	.ch_phase		= { 0x400, 0xfc400 },
 	.has_coef_access_ctrl	= true,
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_frontend.h
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -115,11 +115,7 @@
 struct sun4i_frontend_data {
 	bool	has_coef_access_ctrl;
 	bool	has_coef_rdy;
-
-	struct {
-		u32	horzphase;
-		u32	vertphase[2];
-	} ch_phase[2];
+	u32	ch_phase[2];
 };
 
 struct sun4i_frontend {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -148,7 +148,7 @@
 #define SUN4I_HDMI_DDC_CMD_IMPLICIT_WRITE	3
 
 #define SUN4I_HDMI_DDC_CLK_REG		0x528
-#define SUN4I_HDMI_DDC_CLK_M(m)			(((m) & 0x7) << 3)
+#define SUN4I_HDMI_DDC_CLK_M(m)			(((m) & 0xf) << 3)
 #define SUN4I_HDMI_DDC_CLK_N(n)			((n) & 0x7)
 
 #define SUN4I_HDMI_DDC_LINE_CTRL_REG	0x540
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -33,7 +33,7 @@
 	unsigned long best_rate = 0;
 	u8 best_m = 0, best_n = 0, _m, _n;
 
-	for (_m = 0; _m < 8; _m++) {
+	for (_m = 0; _m < 16; _m++) {
 		for (_n = 0; _n < 8; _n++) {
 			unsigned long tmp_rate;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -262,9 +262,8 @@
 	struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
 	unsigned long reg;
 
-	if (readl_poll_timeout(hdmi->base + SUN4I_HDMI_HPD_REG, reg,
-			       reg & SUN4I_HDMI_HPD_HIGH,
-			       0, 500000)) {
+	reg = readl(hdmi->base + SUN4I_HDMI_HPD_REG);
+	if (!(reg & SUN4I_HDMI_HPD_HIGH)) {
 		cec_phys_addr_invalidate(hdmi->cec_adap);
 		return connector_status_disconnected;
 	}
@@ -683,8 +682,6 @@
 	struct sun4i_hdmi *hdmi = dev_get_drvdata(dev);
 
 	cec_unregister_adapter(hdmi->cec_adap);
-	drm_connector_cleanup(&hdmi->connector);
-	drm_encoder_cleanup(&hdmi->encoder);
 	i2c_del_adapter(hdmi->i2c);
 	i2c_put_adapter(hdmi->ddc_i2c);
 	clk_disable_unprepare(hdmi->mod_clk);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -488,7 +488,7 @@
 
 	WARN_ON(!tcon->quirks->has_channel_0);
 
-	tcon->dclk_min_div = 1;
+	tcon->dclk_min_div = tcon->quirks->dclk_min_div;
 	tcon->dclk_max_div = 127;
 	sun4i_tcon0_mode_set_common(tcon, mode);
 
@@ -545,30 +545,13 @@
 	if (info->bus_flags & DRM_BUS_FLAG_DE_LOW)
 		val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE;
 
-	/*
-	 * On A20 and similar SoCs, the only way to achieve Positive Edge
-	 * (Rising Edge), is setting dclk clock phase to 2/3(240°).
-	 * By default TCON works in Negative Edge(Falling Edge),
-	 * this is why phase is set to 0 in that case.
-	 * Unfortunately there's no way to logically invert dclk through
-	 * IO_POL register.
-	 * The only acceptable way to work, triple checked with scope,
-	 * is using clock phase set to 0° for Negative Edge and set to 240°
-	 * for Positive Edge.
-	 * On A33 and similar SoCs there would be a 90° phase option,
-	 * but it divides also dclk by 2.
-	 * Following code is a way to avoid quirks all around TCON
-	 * and DOTCLOCK drivers.
-	 */
-	if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
-		clk_set_phase(tcon->dclk, 240);
-
 	if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
-		clk_set_phase(tcon->dclk, 0);
+		val |= SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE;
 
 	regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
 			   SUN4I_TCON0_IO_POL_HSYNC_POSITIVE |
 			   SUN4I_TCON0_IO_POL_VSYNC_POSITIVE |
+			   SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE |
 			   SUN4I_TCON0_IO_POL_DE_NEGATIVE,
 			   val);
 
@@ -665,6 +648,30 @@
 		     SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
 		     SUN4I_TCON1_BASIC5_H_SYNC(hsync));
 
+	/* Setup the polarity of multiple signals */
+	if (tcon->quirks->polarity_in_ch0) {
+		val = 0;
+
+		if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+			val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
+
+		if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
+
+		regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
+	} else {
+		/* according to vendor driver, this bit must be always set */
+		val = SUN4I_TCON1_IO_POL_UNKNOWN;
+
+		if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+			val |= SUN4I_TCON1_IO_POL_HSYNC_POSITIVE;
+
+		if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+			val |= SUN4I_TCON1_IO_POL_VSYNC_POSITIVE;
+
+		regmap_write(tcon->regs, SUN4I_TCON1_IO_POL_REG, val);
+	}
+
 	/* Map output pins to channel 1 */
 	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
 			   SUN4I_TCON_GCTL_IOMAP_MASK,
@@ -746,21 +753,19 @@
 static int sun4i_tcon_init_clocks(struct device *dev,
 				  struct sun4i_tcon *tcon)
 {
-	tcon->clk = devm_clk_get(dev, "ahb");
+	tcon->clk = devm_clk_get_enabled(dev, "ahb");
 	if (IS_ERR(tcon->clk)) {
 		dev_err(dev, "Couldn't get the TCON bus clock\n");
 		return PTR_ERR(tcon->clk);
 	}
-	clk_prepare_enable(tcon->clk);
 
 	if (tcon->quirks->has_channel_0) {
-		tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
+		tcon->sclk0 = devm_clk_get_enabled(dev, "tcon-ch0");
 		if (IS_ERR(tcon->sclk0)) {
 			dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
 			return PTR_ERR(tcon->sclk0);
 		}
 	}
-	clk_prepare_enable(tcon->sclk0);
 
 	if (tcon->quirks->has_channel_1) {
 		tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
@@ -773,12 +778,6 @@
 	return 0;
 }
 
-static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
-{
-	clk_disable_unprepare(tcon->sclk0);
-	clk_disable_unprepare(tcon->clk);
-}
-
 static int sun4i_tcon_init_irq(struct device *dev,
 			       struct sun4i_tcon *tcon)
 {
@@ -1195,14 +1194,14 @@
 	ret = sun4i_tcon_init_regmap(dev, tcon);
 	if (ret) {
 		dev_err(dev, "Couldn't init our TCON regmap\n");
-		goto err_free_clocks;
+		goto err_assert_reset;
 	}
 
 	if (tcon->quirks->has_channel_0) {
 		ret = sun4i_dclk_create(dev, tcon);
 		if (ret) {
 			dev_err(dev, "Couldn't create our TCON dot clock\n");
-			goto err_free_clocks;
+			goto err_assert_reset;
 		}
 	}
 
@@ -1265,8 +1264,6 @@
 err_free_dotclock:
 	if (tcon->quirks->has_channel_0)
 		sun4i_dclk_free(tcon);
-err_free_clocks:
-	sun4i_tcon_free_clocks(tcon);
 err_assert_reset:
 	reset_control_assert(tcon->lcd_rst);
 	return ret;
@@ -1280,7 +1277,6 @@
 	list_del(&tcon->list);
 	if (tcon->quirks->has_channel_0)
 		sun4i_dclk_free(tcon);
-	sun4i_tcon_free_clocks(tcon);
 }
 
 static const struct component_ops sun4i_tcon_ops = {
@@ -1409,14 +1405,18 @@
 	if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
 	    encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
 		ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
-		if (ret)
+		if (ret) {
+			put_device(&pdev->dev);
 			return ret;
+		}
 	}
 
 	if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
 		ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
-		if (ret)
+		if (ret) {
+			put_device(&pdev->dev);
 			return ret;
+		}
 	}
 
 	return 0;
@@ -1425,12 +1425,14 @@
 static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
 	.has_channel_0		= true,
 	.has_channel_1		= true,
+	.dclk_min_div		= 4,
 	.set_mux		= sun4i_a10_tcon_set_mux,
 };
 
 static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
 	.has_channel_0		= true,
 	.has_channel_1		= true,
+	.dclk_min_div		= 4,
 	.set_mux		= sun5i_a13_tcon_set_mux,
 };
 
@@ -1439,6 +1441,7 @@
 	.has_channel_1		= true,
 	.has_lvds_alt		= true,
 	.needs_de_be_mux	= true,
+	.dclk_min_div		= 1,
 	.set_mux		= sun6i_tcon_set_mux,
 };
 
@@ -1446,11 +1449,13 @@
 	.has_channel_0		= true,
 	.has_channel_1		= true,
 	.needs_de_be_mux	= true,
+	.dclk_min_div		= 1,
 };
 
 static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
 	.has_channel_0		= true,
 	.has_channel_1		= true,
+	.dclk_min_div		= 4,
 	/* Same display pipeline structure as A10 */
 	.set_mux		= sun4i_a10_tcon_set_mux,
 };
@@ -1458,11 +1463,13 @@
 static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
 	.has_channel_0		= true,
 	.has_lvds_alt		= true,
+	.dclk_min_div		= 1,
 };
 
 static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
 	.supports_lvds		= true,
 	.has_channel_0		= true,
+	.dclk_min_div		= 1,
 };
 
 static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
@@ -1471,16 +1478,19 @@
 
 static const struct sun4i_tcon_quirks sun8i_r40_tv_quirks = {
 	.has_channel_1		= true,
+	.polarity_in_ch0	= true,
 	.set_mux		= sun8i_r40_tcon_tv_set_mux,
 };
 
 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
 	.has_channel_0		= true,
+	.dclk_min_div		= 1,
 };
 
 static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
-	.has_channel_0	= true,
-	.needs_edp_reset = true,
+	.has_channel_0		= true,
+	.needs_edp_reset	= true,
+	.dclk_min_div		= 1,
 };
 
 static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
@@ -1495,6 +1505,8 @@
 	{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
 	{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
 	{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
+	{ .compatible = "allwinner,sun7i-a20-tcon0", .data = &sun7i_a20_quirks },
+	{ .compatible = "allwinner,sun7i-a20-tcon1", .data = &sun7i_a20_quirks },
 	{ .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },
 	{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
 	{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -113,6 +113,7 @@
 #define SUN4I_TCON0_IO_POL_REG			0x88
 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase)		((phase & 3) << 28)
 #define SUN4I_TCON0_IO_POL_DE_NEGATIVE			BIT(27)
+#define SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE		BIT(26)
 #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE		BIT(25)
 #define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE		BIT(24)
 
@@ -153,6 +154,11 @@
 #define SUN4I_TCON1_BASIC5_V_SYNC(height)		(((height) - 1) & 0x3ff)
 
 #define SUN4I_TCON1_IO_POL_REG			0xf0
+/* there is no documentation about this bit */
+#define SUN4I_TCON1_IO_POL_UNKNOWN			BIT(26)
+#define SUN4I_TCON1_IO_POL_HSYNC_POSITIVE		BIT(25)
+#define SUN4I_TCON1_IO_POL_VSYNC_POSITIVE		BIT(24)
+
 #define SUN4I_TCON1_IO_TRI_REG			0xf4
 
 #define SUN4I_TCON_ECC_FIFO_REG			0xf8
@@ -224,6 +230,8 @@
 	bool	needs_de_be_mux; /* sun6i needs mux to select backend */
 	bool    needs_edp_reset; /* a80 edp reset needed for tcon0 access */
 	bool	supports_lvds;   /* Does the TCON support an LVDS output? */
+	bool	polarity_in_ch0; /* some tcon1 channels have polarity bits in tcon0 pol register */
+	u8	dclk_min_div;	/* minimum divider for TCON0 DCLK */
 
 	/* callback to handle tcon muxing options */
 	int	(*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -365,8 +365,7 @@
 static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 					   struct drm_display_mode *mode)
 {
-	u16 start = clamp(mode->vtotal - mode->vdisplay - 10, 8, 100);
-	u16 delay = mode->vtotal - (mode->vsync_end - mode->vdisplay) + start;
+	u16 delay = mode->vtotal - (mode->vsync_end - mode->vdisplay) + 1;
 
 	if (delay > mode->vtotal)
 		delay = delay % mode->vtotal;
@@ -437,9 +436,9 @@
 			     SUN6I_DSI_BURST_LINE_SYNC_POINT(SUN6I_DSI_SYNC_POINT));
 
 		val = SUN6I_DSI_TCON_DRQ_ENABLE_MODE;
-	} else if ((mode->hsync_end - mode->hdisplay) > 20) {
+	} else if ((mode->hsync_start - mode->hdisplay) > 20) {
 		/* Maaaaaagic */
-		u16 drq = (mode->hsync_end - mode->hdisplay) - 20;
+		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
 
 		drq *= mipi_dsi_pixel_format_to_bpp(device->format);
 		drq /= 32;
@@ -718,7 +717,7 @@
 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
 	struct mipi_dsi_device *device = dsi->device;
-	union phy_configure_opts opts = { 0 };
+	union phy_configure_opts opts = { };
 	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
 	u16 delay;
 
@@ -867,7 +866,7 @@
 	regmap_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(0),
 		     sun6i_dsi_dcs_build_pkt_hdr(dsi, msg));
 
-	bounce = kzalloc(msg->tx_len + sizeof(crc), GFP_KERNEL);
+	bounce = kzalloc(ALIGN(msg->tx_len + sizeof(crc), 4), GFP_KERNEL);
 	if (!bounce)
 		return -ENOMEM;
 
@@ -878,7 +877,7 @@
 	memcpy((u8 *)bounce + msg->tx_len, &crc, sizeof(crc));
 	len += sizeof(crc);
 
-	regmap_bulk_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(1), bounce, len);
+	regmap_bulk_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(1), bounce, DIV_ROUND_UP(len, 4));
 	regmap_write(dsi->regs, SUN6I_DSI_CMD_CTL_REG, len + 4 - 1);
 	kfree(bounce);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -12,7 +12,7 @@
 
 /* VI channel CSC units offsets */
 #define CCSC00_OFFSET 0xAA050
-#define CCSC01_OFFSET 0xFA000
+#define CCSC01_OFFSET 0xFA050
 #define CCSC10_OFFSET 0xA0000
 #define CCSC11_OFFSET 0xF0000
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -49,11 +49,9 @@
 {
 	/*
 	 * Controller support maximum of 594 MHz, which correlates to
-	 * 4K@60Hz 4:4:4 or RGB. However, for frequencies greater than
-	 * 340 MHz scrambling has to be enabled. Because scrambling is
-	 * not yet implemented, just limit to 340 MHz for now.
+	 * 4K@60Hz 4:4:4 or RGB.
 	 */
-	if (mode->clock > 340000)
+	if (mode->clock > 594000)
 		return MODE_CLOCK_HIGH;
 
 	return MODE_OK;
@@ -209,6 +207,7 @@
 	phy_node = of_parse_phandle(dev->of_node, "phys", 0);
 	if (!phy_node) {
 		dev_err(dev, "Can't found PHY phandle\n");
+		ret = -EINVAL;
 		goto err_disable_clk_tmds;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -104,29 +104,21 @@
 
 static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
 	/* pixelclk    bpp8    bpp10   bpp12 */
-	{ 25175000,  { 0x0000, 0x0000, 0x0000 }, },
 	{ 27000000,  { 0x0012, 0x0000, 0x0000 }, },
-	{ 59400000,  { 0x0008, 0x0008, 0x0008 }, },
-	{ 72000000,  { 0x0008, 0x0008, 0x001b }, },
-	{ 74250000,  { 0x0013, 0x0013, 0x0013 }, },
-	{ 90000000,  { 0x0008, 0x001a, 0x001b }, },
-	{ 118800000, { 0x001b, 0x001a, 0x001b }, },
-	{ 144000000, { 0x001b, 0x001a, 0x0034 }, },
-	{ 180000000, { 0x001b, 0x0033, 0x0034 }, },
-	{ 216000000, { 0x0036, 0x0033, 0x0034 }, },
-	{ 237600000, { 0x0036, 0x0033, 0x001b }, },
-	{ 288000000, { 0x0036, 0x001b, 0x001b }, },
-	{ 297000000, { 0x0019, 0x001b, 0x0019 }, },
-	{ 330000000, { 0x0036, 0x001b, 0x001b }, },
-	{ 594000000, { 0x003f, 0x001b, 0x001b }, },
+	{ 74250000,  { 0x0013, 0x001a, 0x001b }, },
+	{ 148500000, { 0x0019, 0x0033, 0x0034 }, },
+	{ 297000000, { 0x0019, 0x001b, 0x001b }, },
+	{ 594000000, { 0x0010, 0x001b, 0x001b }, },
 	{ ~0UL,      { 0x0000, 0x0000, 0x0000 }, }
 };
 
 static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
 	/*pixelclk   symbol   term   vlev*/
-	{ 74250000,  0x8009, 0x0004, 0x0232},
-	{ 148500000, 0x8029, 0x0004, 0x0273},
-	{ 594000000, 0x8039, 0x0004, 0x014a},
+	{ 27000000,  0x8009, 0x0007, 0x02b0 },
+	{ 74250000,  0x8009, 0x0006, 0x022d },
+	{ 148500000, 0x8029, 0x0006, 0x0270 },
+	{ 297000000, 0x8039, 0x0005, 0x01ab },
+	{ 594000000, 0x8029, 0x0000, 0x008a },
 	{ ~0UL,	     0x0000, 0x0000, 0x0000}
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -107,48 +107,128 @@
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_XRGB4444,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_ABGR4444,
 		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_XBGR4444,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_RGBA4444,
 		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_RGBX4444,
+		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_BGRA4444,
 		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_BGRX4444,
+		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_ARGB1555,
 		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_XRGB1555,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_ABGR1555,
 		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_XBGR1555,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_RGBA5551,
 		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_RGBX5551,
+		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_BGRA5551,
 		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
 		.rgb = true,
 		.csc = SUN8I_CSC_MODE_OFF,
 	},
 	{
+		/* for DE2 VI layer which ignores alpha */
+		.drm_fmt = DRM_FORMAT_BGRX5551,
+		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
+		.drm_fmt = DRM_FORMAT_ARGB2101010,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
+		.drm_fmt = DRM_FORMAT_ABGR2101010,
+		.de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
+		.drm_fmt = DRM_FORMAT_RGBA1010102,
+		.de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
+		.drm_fmt = DRM_FORMAT_BGRA1010102,
+		.de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
+		.rgb = true,
+		.csc = SUN8I_CSC_MODE_OFF,
+	},
+	{
 		.drm_fmt = DRM_FORMAT_UYVY,
 		.de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
 		.rgb = false,
@@ -197,12 +277,6 @@
 		.csc = SUN8I_CSC_MODE_YUV2RGB,
 	},
 	{
-		.drm_fmt = DRM_FORMAT_YUV444,
-		.de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-		.rgb = true,
-		.csc = SUN8I_CSC_MODE_YUV2RGB,
-	},
-	{
 		.drm_fmt = DRM_FORMAT_YUV422,
 		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
 		.rgb = false,
@@ -221,12 +295,6 @@
 		.csc = SUN8I_CSC_MODE_YUV2RGB,
 	},
 	{
-		.drm_fmt = DRM_FORMAT_YVU444,
-		.de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-		.rgb = true,
-		.csc = SUN8I_CSC_MODE_YVU2RGB,
-	},
-	{
 		.drm_fmt = DRM_FORMAT_YVU422,
 		.de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
 		.rgb = false,
@@ -244,6 +312,18 @@
 		.rgb = false,
 		.csc = SUN8I_CSC_MODE_YVU2RGB,
 	},
+	{
+		.drm_fmt = DRM_FORMAT_P010,
+		.de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
+		.rgb = false,
+		.csc = SUN8I_CSC_MODE_YUV2RGB,
+	},
+	{
+		.drm_fmt = DRM_FORMAT_P210,
+		.de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
+		.rgb = false,
+		.csc = SUN8I_CSC_MODE_YUV2RGB,
+	},
 };
 
 const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
@@ -316,7 +396,7 @@
 	.reg_bits	= 32,
 	.val_bits	= 32,
 	.reg_stride	= 4,
-	.max_register	= 0xbfffc, /* guessed */
+	.max_register	= 0xffffc, /* guessed */
 };
 
 static int sun8i_mixer_of_get_id(struct device_node *node)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -93,6 +93,10 @@
 #define SUN8I_MIXER_FBFMT_ABGR1555	17
 #define SUN8I_MIXER_FBFMT_RGBA5551	18
 #define SUN8I_MIXER_FBFMT_BGRA5551	19
+#define SUN8I_MIXER_FBFMT_ARGB2101010	20
+#define SUN8I_MIXER_FBFMT_ABGR2101010	21
+#define SUN8I_MIXER_FBFMT_RGBA1010102	22
+#define SUN8I_MIXER_FBFMT_BGRA1010102	23
 
 #define SUN8I_MIXER_FBFMT_YUYV		0
 #define SUN8I_MIXER_FBFMT_UYVY		1
@@ -109,6 +113,13 @@
 /* format 12 is semi-planar YUV411 UVUV */
 /* format 13 is semi-planar YUV411 VUVU */
 #define SUN8I_MIXER_FBFMT_YUV411	14
+/* format 15 doesn't exist */
+#define SUN8I_MIXER_FBFMT_P010_YUV	16
+/* format 17 is P010 YVU */
+#define SUN8I_MIXER_FBFMT_P210_YUV	18
+/* format 19 is P210 YVU */
+/* format 20 is packed YVU444 10-bit */
+/* format 21 is packed YUV444 10-bit */
 
 /*
  * Sub-engines listed bellow are unused for now. The EN registers are here only
--- linux-ein-5.4.0.orig/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -398,24 +398,66 @@
 };
 
 /*
- * While all RGB formats are supported, VI planes don't support
- * alpha blending, so there is no point having formats with alpha
- * channel if their opaque analog exist.
+ * While DE2 VI layer supports same RGB formats as UI layer, alpha
+ * channel is ignored. This structure lists all unique variants
+ * where alpha channel is replaced with "don't care" (X) channel.
  */
 static const u32 sun8i_vi_layer_formats[] = {
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_BGRX4444,
+	DRM_FORMAT_BGRX5551,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_RGBX4444,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_XBGR4444,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_XRGB8888,
+
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_YUV411,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YVU411,
+	DRM_FORMAT_YVU420,
+	DRM_FORMAT_YVU422,
+};
+
+static const u32 sun8i_vi_layer_de3_formats[] = {
 	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_ABGR2101010,
 	DRM_FORMAT_ABGR4444,
+	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_ARGB2101010,
 	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_ARGB8888,
 	DRM_FORMAT_BGR565,
 	DRM_FORMAT_BGR888,
+	DRM_FORMAT_BGRA1010102,
 	DRM_FORMAT_BGRA5551,
 	DRM_FORMAT_BGRA4444,
+	DRM_FORMAT_BGRA8888,
 	DRM_FORMAT_BGRX8888,
 	DRM_FORMAT_RGB565,
 	DRM_FORMAT_RGB888,
+	DRM_FORMAT_RGBA1010102,
 	DRM_FORMAT_RGBA4444,
 	DRM_FORMAT_RGBA5551,
+	DRM_FORMAT_RGBA8888,
 	DRM_FORMAT_RGBX8888,
 	DRM_FORMAT_XBGR8888,
 	DRM_FORMAT_XRGB8888,
@@ -424,6 +466,8 @@
 	DRM_FORMAT_NV12,
 	DRM_FORMAT_NV21,
 	DRM_FORMAT_NV61,
+	DRM_FORMAT_P010,
+	DRM_FORMAT_P210,
 	DRM_FORMAT_UYVY,
 	DRM_FORMAT_VYUY,
 	DRM_FORMAT_YUYV,
@@ -431,11 +475,9 @@
 	DRM_FORMAT_YUV411,
 	DRM_FORMAT_YUV420,
 	DRM_FORMAT_YUV422,
-	DRM_FORMAT_YUV444,
 	DRM_FORMAT_YVU411,
 	DRM_FORMAT_YVU420,
 	DRM_FORMAT_YVU422,
-	DRM_FORMAT_YVU444,
 };
 
 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
@@ -443,19 +485,27 @@
 					       int index)
 {
 	u32 supported_encodings, supported_ranges;
+	unsigned int plane_cnt, format_count;
 	struct sun8i_vi_layer *layer;
-	unsigned int plane_cnt;
+	const u32 *formats;
 	int ret;
 
 	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
 	if (!layer)
 		return ERR_PTR(-ENOMEM);
 
+	if (mixer->cfg->is_de3) {
+		formats = sun8i_vi_layer_de3_formats;
+		format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+	} else {
+		formats = sun8i_vi_layer_formats;
+		format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
+	}
+
 	/* possible crtcs are set later */
 	ret = drm_universal_plane_init(drm, &layer->plane, 0,
 				       &sun8i_vi_layer_funcs,
-				       sun8i_vi_layer_formats,
-				       ARRAY_SIZE(sun8i_vi_layer_formats),
+				       formats, format_count,
 				       NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
 	if (ret) {
 		dev_err(drm->dev, "Couldn't initialize layer\n");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/dc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/dc.c
@@ -919,6 +919,11 @@
 	.atomic_disable = tegra_cursor_atomic_disable,
 };
 
+static const uint64_t linear_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
 static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
 						      struct tegra_dc *dc)
 {
@@ -947,7 +952,7 @@
 
 	err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
 				       &tegra_plane_funcs, formats,
-				       num_formats, NULL,
+				       num_formats, linear_modifiers,
 				       DRM_PLANE_TYPE_CURSOR, NULL);
 	if (err < 0) {
 		kfree(plane);
@@ -1065,7 +1070,8 @@
 
 	err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
 				       &tegra_plane_funcs, formats,
-				       num_formats, NULL, type, NULL);
+				       num_formats, linear_modifiers,
+				       type, NULL);
 	if (err < 0) {
 		kfree(plane);
 		return ERR_PTR(err);
@@ -1667,6 +1673,11 @@
 			dev_err(dc->dev,
 				"failed to set clock rate to %lu Hz\n",
 				state->pclk);
+
+		err = clk_set_rate(dc->clk, state->pclk);
+		if (err < 0)
+			dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n",
+				dc->clk, state->pclk, err);
 	}
 
 	DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk),
@@ -1677,11 +1688,6 @@
 		value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
 		tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
 	}
-
-	err = clk_set_rate(dc->clk, state->pclk);
-	if (err < 0)
-		dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n",
-			dc->clk, state->pclk, err);
 }
 
 static void tegra_dc_stop(struct tegra_dc *dc)
@@ -2452,8 +2458,10 @@
 	usleep_range(2000, 4000);
 
 	err = reset_control_assert(dc->rst);
-	if (err < 0)
+	if (err < 0) {
+		clk_disable_unprepare(dc->clk);
 		return err;
+	}
 
 	usleep_range(2000, 4000);
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/dpaux.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/dpaux.c
@@ -447,10 +447,8 @@
 		return PTR_ERR(dpaux->regs);
 
 	dpaux->irq = platform_get_irq(pdev, 0);
-	if (dpaux->irq < 0) {
-		dev_err(&pdev->dev, "failed to get IRQ\n");
-		return -ENXIO;
-	}
+	if (dpaux->irq < 0)
+		return dpaux->irq;
 
 	if (!pdev->dev.pm_domain) {
 		dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/drm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/drm.c
@@ -122,8 +122,6 @@
 	drm->mode_config.max_width = 4096;
 	drm->mode_config.max_height = 4096;
 
-	drm->mode_config.allow_fb_modifiers = true;
-
 	drm->mode_config.normalize_zpos = true;
 
 	drm->mode_config.funcs = &tegra_drm_mode_config_funcs;
@@ -201,19 +199,19 @@
 	if (tegra->hub)
 		tegra_display_hub_cleanup(tegra->hub);
 device:
-	host1x_device_exit(device);
-fbdev:
-	drm_kms_helper_poll_fini(drm);
-	tegra_drm_fb_free(drm);
-config:
-	drm_mode_config_cleanup(drm);
-
 	if (tegra->domain) {
 		mutex_destroy(&tegra->mm_lock);
 		drm_mm_takedown(&tegra->mm);
 		put_iova_domain(&tegra->carveout.domain);
 		iova_cache_put();
 	}
+
+	host1x_device_exit(device);
+fbdev:
+	drm_kms_helper_poll_fini(drm);
+	tegra_drm_fb_free(drm);
+config:
+	drm_mode_config_cleanup(drm);
 domain:
 	if (tegra->domain)
 		iommu_domain_free(tegra->domain);
@@ -256,7 +254,7 @@
 	if (!fpriv)
 		return -ENOMEM;
 
-	idr_init(&fpriv->contexts);
+	idr_init_base(&fpriv->contexts, 1);
 	mutex_init(&fpriv->lock);
 	filp->driver_priv = fpriv;
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/dsi.c
@@ -1455,8 +1455,10 @@
 		dsi->slave = platform_get_drvdata(gangster);
 		of_node_put(np);
 
-		if (!dsi->slave)
+		if (!dsi->slave) {
+			put_device(&gangster->dev);
 			return -EPROBE_DEFER;
+		}
 
 		dsi->slave->master = dsi;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/hub.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/hub.c
@@ -141,7 +141,9 @@
 	for (i = 0; i < hub->soc->num_wgrps; i++) {
 		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
 
-		tegra_windowgroup_enable(wgrp);
+		/* Skip orphaned window group whose parent DC is disabled */
+		if (wgrp->parent)
+			tegra_windowgroup_enable(wgrp);
 	}
 
 	return 0;
@@ -158,7 +160,9 @@
 	for (i = 0; i < hub->soc->num_wgrps; i++) {
 		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
 
-		tegra_windowgroup_disable(wgrp);
+		/* Skip orphaned window group whose parent DC is disabled */
+		if (wgrp->parent)
+			tegra_windowgroup_disable(wgrp);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tegra/sor.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tegra/sor.c
@@ -906,7 +906,7 @@
 				    struct drm_dp_link *link)
 {
 	const u64 f = 100000, link_rate = link->rate * 1000;
-	const u64 pclk = mode->clock * 1000;
+	const u64 pclk = (u64)mode->clock * 1000;
 	u64 input, output, watermark, num;
 	struct tegra_sor_params params;
 	u32 num_syms_per_line;
@@ -2875,21 +2875,21 @@
 		if (err < 0) {
 			dev_err(sor->dev, "failed to acquire SOR reset: %d\n",
 				err);
-			return err;
+			goto rpm_put;
 		}
 
 		err = reset_control_assert(sor->rst);
 		if (err < 0) {
 			dev_err(sor->dev, "failed to assert SOR reset: %d\n",
 				err);
-			return err;
+			goto rpm_put;
 		}
 	}
 
 	err = clk_prepare_enable(sor->clk);
 	if (err < 0) {
 		dev_err(sor->dev, "failed to enable clock: %d\n", err);
-		return err;
+		goto rpm_put;
 	}
 
 	usleep_range(1000, 3000);
@@ -2899,19 +2899,25 @@
 		if (err < 0) {
 			dev_err(sor->dev, "failed to deassert SOR reset: %d\n",
 				err);
-			return err;
+			clk_disable_unprepare(sor->clk);
+			goto rpm_put;
 		}
 
 		reset_control_release(sor->rst);
 	}
 
 	err = clk_prepare_enable(sor->clk_safe);
-	if (err < 0)
+	if (err < 0) {
+		clk_disable_unprepare(sor->clk);
 		return err;
+	}
 
 	err = clk_prepare_enable(sor->clk_dp);
-	if (err < 0)
+	if (err < 0) {
+		clk_disable_unprepare(sor->clk_safe);
+		clk_disable_unprepare(sor->clk);
 		return err;
+	}
 
 	/*
 	 * Enable and unmask the HDA codec SCRATCH0 register interrupt. This
@@ -2923,6 +2929,12 @@
 	tegra_sor_writel(sor, value, SOR_INT_MASK);
 
 	return 0;
+
+rpm_put:
+	if (sor->rst)
+		pm_runtime_put(sor->dev);
+
+	return err;
 }
 
 static int tegra_sor_exit(struct host1x_client *client)
@@ -3200,6 +3212,11 @@
 		 * earlier
 		 */
 		sor->pad = TEGRA_IO_PAD_HDMI_DP0 + sor->index;
+	} else {
+		if (sor->soc->supports_edp)
+			sor->index = 0;
+		else
+			sor->index = 1;
 	}
 
 	err = of_property_read_u32_array(np, "nvidia,xbar-cfg", xbar_cfg, 5);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -58,11 +58,13 @@
 int tilcdc_add_component_encoder(struct drm_device *ddev)
 {
 	struct tilcdc_drm_private *priv = ddev->dev_private;
-	struct drm_encoder *encoder;
+	struct drm_encoder *encoder = NULL, *iter;
 
-	list_for_each_entry(encoder, &ddev->mode_config.encoder_list, head)
-		if (encoder->possible_crtcs & (1 << priv->crtc->index))
+	list_for_each_entry(iter, &ddev->mode_config.encoder_list, head)
+		if (iter->possible_crtcs & (1 << priv->crtc->index)) {
+			encoder = iter;
 			break;
+		}
 
 	if (!encoder) {
 		dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -143,12 +143,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-ein-5.4.0.orig/drivers/gpu/drm/ttm/ttm_bo.c
+++ linux-ein-5.4.0/drivers/gpu/drm/ttm/ttm_bo.c
@@ -517,8 +517,10 @@
 
 		dma_resv_unlock(bo->base.resv);
 	}
-	if (bo->base.resv != &bo->base._resv)
+	if (bo->base.resv != &bo->base._resv) {
+		ttm_bo_flush_all_fences(bo);
 		dma_resv_unlock(&bo->base._resv);
+	}
 
 error:
 	kref_get(&bo->list_kref);
@@ -759,7 +761,7 @@
 	/* Don't evict this BO if it's outside of the
 	 * requested placement range
 	 */
-	if (place->fpfn >= (bo->mem.start + bo->mem.size) ||
+	if (place->fpfn >= (bo->mem.start + bo->mem.num_pages) ||
 	    (place->lpfn && place->lpfn <= bo->mem.start))
 		return false;
 
@@ -926,7 +928,8 @@
  */
 static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
 				 struct ttm_mem_type_manager *man,
-				 struct ttm_mem_reg *mem)
+				 struct ttm_mem_reg *mem,
+				 bool no_wait_gpu)
 {
 	struct dma_fence *fence;
 	int ret;
@@ -935,19 +938,24 @@
 	fence = dma_fence_get(man->move);
 	spin_unlock(&man->move_lock);
 
-	if (fence) {
-		dma_resv_add_shared_fence(bo->base.resv, fence);
+	if (!fence)
+		return 0;
 
-		ret = dma_resv_reserve_shared(bo->base.resv, 1);
-		if (unlikely(ret)) {
-			dma_fence_put(fence);
-			return ret;
-		}
+	if (no_wait_gpu) {
+		dma_fence_put(fence);
+		return -EBUSY;
+	}
+
+	dma_resv_add_shared_fence(bo->base.resv, fence);
 
-		dma_fence_put(bo->moving);
-		bo->moving = fence;
+	ret = dma_resv_reserve_shared(bo->base.resv, 1);
+	if (unlikely(ret)) {
+		dma_fence_put(fence);
+		return ret;
 	}
 
+	dma_fence_put(bo->moving);
+	bo->moving = fence;
 	return 0;
 }
 
@@ -978,7 +986,7 @@
 			return ret;
 	} while (1);
 
-	return ttm_bo_add_move_fence(bo, man, mem);
+	return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
 }
 
 static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
@@ -1120,14 +1128,18 @@
 		if (unlikely(ret))
 			goto error;
 
-		if (mem->mm_node) {
-			ret = ttm_bo_add_move_fence(bo, man, mem);
-			if (unlikely(ret)) {
-				(*man->func->put_node)(man, mem);
-				goto error;
-			}
-			return 0;
+		if (!mem->mm_node)
+			continue;
+
+		ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
+		if (unlikely(ret)) {
+			(*man->func->put_node)(man, mem);
+			if (ret == -EBUSY)
+				continue;
+
+			goto error;
 		}
+		return 0;
 	}
 
 	for (i = 0; i < placement->num_busy_placement; ++i) {
--- linux-ein-5.4.0.orig/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ linux-ein-5.4.0/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -358,8 +358,10 @@
 static int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
 			    void *buf, int len, int write)
 {
-	unsigned long offset = (addr) - vma->vm_start;
 	struct ttm_buffer_object *bo = vma->vm_private_data;
+	unsigned long offset = (addr) - vma->vm_start +
+		((vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node))
+		 << PAGE_SHIFT);
 	int ret;
 
 	if (len < 1 || (offset + len) >> PAGE_SHIFT > bo->num_pages)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/ttm/ttm_tt.c
+++ linux-ein-5.4.0/drivers/gpu/drm/ttm/ttm_tt.c
@@ -241,7 +241,6 @@
 	ttm_tt_init_fields(ttm, bo, page_flags);
 
 	if (ttm_tt_alloc_page_directory(ttm)) {
-		ttm_tt_destroy(ttm);
 		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
@@ -265,7 +264,6 @@
 
 	INIT_LIST_HEAD(&ttm_dma->pages_list);
 	if (ttm_dma_tt_alloc_page_directory(ttm_dma)) {
-		ttm_tt_destroy(ttm);
 		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
@@ -287,7 +285,6 @@
 	else
 		ret = ttm_dma_tt_alloc_page_directory(ttm_dma);
 	if (ret) {
-		ttm_tt_destroy(ttm);
 		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tve200/tve200_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tve200/tve200_display.c
@@ -14,6 +14,7 @@
 #include <linux/version.h>
 #include <linux/dma-buf.h>
 #include <linux/of_graph.h>
+#include <linux/delay.h>
 
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fourcc.h>
@@ -130,9 +131,25 @@
 	struct drm_connector *connector = priv->connector;
 	u32 format = fb->format->format;
 	u32 ctrl1 = 0;
+	int retries;
 
 	clk_prepare_enable(priv->clk);
 
+	/* Reset the TVE200 and wait for it to come back online */
+	writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
+	for (retries = 0; retries < 5; retries++) {
+		usleep_range(30000, 50000);
+		if (readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET)
+			continue;
+		else
+			break;
+	}
+	if (retries == 5 &&
+	    readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET) {
+		dev_err(drm->dev, "can't get hardware out of reset\n");
+		return;
+	}
+
 	/* Function 1 */
 	ctrl1 |= TVE200_CTRL_CSMODE;
 	/* Interlace mode for CCIR656: parameterize? */
@@ -230,8 +247,9 @@
 
 	drm_crtc_vblank_off(crtc);
 
-	/* Disable and Power Down */
+	/* Disable put into reset and Power Down */
 	writel(0, priv->regs + TVE200_CTRL);
+	writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
 
 	clk_disable_unprepare(priv->clk);
 }
@@ -279,6 +297,8 @@
 	struct drm_device *drm = crtc->dev;
 	struct tve200_drm_dev_private *priv = drm->dev_private;
 
+	/* Clear any IRQs and enable */
+	writel(0xFF, priv->regs + TVE200_INT_CLR);
 	writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/tve200/tve200_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/tve200/tve200_drv.c
@@ -210,8 +210,8 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		ret = -EINVAL;
+	if (irq < 0) {
+		ret = irq;
 		goto clk_disable;
 	}
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/udl/udl_connector.c
+++ linux-ein-5.4.0/drivers/gpu/drm/udl/udl_connector.c
@@ -29,7 +29,7 @@
 		ret = usb_control_msg(udl->udev,
 				      usb_rcvctrlpipe(udl->udev, 0),
 					  (0x02), (0x80 | (0x02 << 5)), bval,
-					  0xA1, read_buff, 2, HZ);
+					  0xA1, read_buff, 2, 1000);
 		if (ret < 1) {
 			DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
 			kfree(read_buff);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/v3d/v3d_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/v3d/v3d_gem.c
@@ -195,8 +195,8 @@
 
 	V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
 	if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-		       V3D_L2TCACTL_L2TFLS), 100)) {
-		DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
+		       V3D_L2TCACTL_TMUWCF), 100)) {
+		DRM_ERROR("Timeout waiting for TMU write combiner flush\n");
 	}
 
 	mutex_lock(&v3d->cache_clean_lock);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_bo.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_bo.c
@@ -389,7 +389,7 @@
 
 	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
 	if (!bo)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	bo->madv = VC4_MADV_WILLNEED;
 	refcount_set(&bo->usecnt, 0);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_dpi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -151,35 +151,45 @@
 	}
 	drm_connector_list_iter_end(&conn_iter);
 
-	if (connector && connector->display_info.num_bus_formats) {
-		u32 bus_format = connector->display_info.bus_formats[0];
+	if (connector) {
+		if (connector->display_info.num_bus_formats) {
+			u32 bus_format = connector->display_info.bus_formats[0];
 
-		switch (bus_format) {
-		case MEDIA_BUS_FMT_RGB888_1X24:
-			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
-					       DPI_FORMAT);
-			break;
-		case MEDIA_BUS_FMT_BGR888_1X24:
-			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
-					       DPI_FORMAT);
-			dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
-			break;
-		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
-			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
-					       DPI_FORMAT);
-			break;
-		case MEDIA_BUS_FMT_RGB666_1X18:
-			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
-					       DPI_FORMAT);
-			break;
-		case MEDIA_BUS_FMT_RGB565_1X16:
-			dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3,
-					       DPI_FORMAT);
-			break;
-		default:
-			DRM_ERROR("Unknown media bus format %d\n", bus_format);
-			break;
+			switch (bus_format) {
+			case MEDIA_BUS_FMT_RGB888_1X24:
+				dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
+						       DPI_FORMAT);
+				break;
+			case MEDIA_BUS_FMT_BGR888_1X24:
+				dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
+						       DPI_FORMAT);
+				dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR,
+						       DPI_ORDER);
+				break;
+			case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+				dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
+						       DPI_FORMAT);
+				break;
+			case MEDIA_BUS_FMT_RGB666_1X18:
+				dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
+						       DPI_FORMAT);
+				break;
+			case MEDIA_BUS_FMT_RGB565_1X16:
+				dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_1,
+						       DPI_FORMAT);
+				break;
+			default:
+				DRM_ERROR("Unknown media bus format %d\n",
+					  bus_format);
+				break;
+			}
 		}
+
+		if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+			dpi_c |= DPI_PIXEL_CLK_INVERT;
+
+		if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
+			dpi_c |= DPI_OUTPUT_ENABLE_INVERT;
 	} else {
 		/* Default to 24bit if no connector found. */
 		dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_drv.c
@@ -309,6 +309,7 @@
 	component_unbind_all(dev, drm);
 gem_destroy:
 	vc4_gem_destroy(drm);
+	drm_mode_config_cleanup(drm);
 	vc4_bo_cache_destroy(drm);
 dev_put:
 	drm_dev_put(drm);
@@ -391,7 +392,12 @@
 	if (ret)
 		return ret;
 
-	return platform_driver_register(&vc4_platform_driver);
+	ret = platform_driver_register(&vc4_platform_driver);
+	if (ret)
+		platform_unregister_drivers(component_drivers,
+					    ARRAY_SIZE(component_drivers));
+
+	return ret;
 }
 
 static void __exit vc4_drm_unregister(void)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_drv.h
@@ -750,7 +750,7 @@
 void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
 void vc4_crtc_txp_armed(struct drm_crtc_state *state);
 void vc4_crtc_get_margins(struct drm_crtc_state *state,
-			  unsigned int *right, unsigned int *left,
+			  unsigned int *left, unsigned int *right,
 			  unsigned int *top, unsigned int *bottom);
 
 /* vc4_debugfs.c */
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_dsi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -752,9 +752,9 @@
 	struct vc4_dsi *dsi = vc4_encoder->dsi;
 	struct device *dev = &dsi->pdev->dev;
 
-	drm_bridge_disable(dsi->bridge);
+	drm_bridge_chain_disable(dsi->bridge);
 	vc4_dsi_ulps(dsi, true);
-	drm_bridge_post_disable(dsi->bridge);
+	drm_bridge_chain_post_disable(dsi->bridge);
 
 	clk_disable_unprepare(dsi->pll_phy_clock);
 	clk_disable_unprepare(dsi->escape_clock);
@@ -791,11 +791,9 @@
 	/* Find what divider gets us a faster clock than the requested
 	 * pixel clock.
 	 */
-	for (divider = 1; divider < 8; divider++) {
-		if (parent_rate / divider < pll_clock) {
-			divider--;
+	for (divider = 1; divider < 255; divider++) {
+		if (parent_rate / (divider + 1) < pll_clock)
 			break;
-		}
 	}
 
 	/* Now that we've picked a PLL divider, calculate back to its
@@ -831,7 +829,7 @@
 	unsigned long phy_clock;
 	int ret;
 
-	ret = pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret) {
 		DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port);
 		return;
@@ -1054,7 +1052,7 @@
 
 	vc4_dsi_ulps(dsi, false);
 
-	drm_bridge_pre_enable(dsi->bridge);
+	drm_bridge_chain_pre_enable(dsi->bridge);
 
 	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
 		DSI_PORT_WRITE(DISP0_CTRL,
@@ -1071,7 +1069,7 @@
 			       DSI_DISP0_ENABLE);
 	}
 
-	drm_bridge_enable(dsi->bridge);
+	drm_bridge_chain_enable(dsi->bridge);
 
 	if (debug_dump_regs) {
 		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -681,11 +681,23 @@
 vc4_hdmi_encoder_mode_valid(struct drm_encoder *crtc,
 			    const struct drm_display_mode *mode)
 {
-	/* HSM clock must be 108% of the pixel clock.  Additionally,
-	 * the AXI clock needs to be at least 25% of pixel clock, but
-	 * HSM ends up being the limiting factor.
+	/*
+	 * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
+	 * be faster than pixel clock, infinitesimally faster, tested in
+	 * simulation. Otherwise, exact value is unimportant for HDMI
+	 * operation." This conflicts with bcm2835's vc4 documentation, which
+	 * states HSM's clock has to be at least 108% of the pixel clock.
+	 *
+	 * Real life tests reveal that vc4's firmware statement holds up, and
+	 * users are able to use pixel clocks closer to HSM's, namely for
+	 * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
+	 * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
+	 * 162MHz.
+	 *
+	 * Additionally, the AXI clock needs to be at least 25% of
+	 * pixel clock, but HSM ends up being the limiting factor.
 	 */
-	if (mode->clock > HSM_CLOCK_FREQ / (1000 * 108 / 100))
+	if (mode->clock > HSM_CLOCK_FREQ / (1000 * 101 / 100))
 		return MODE_CLOCK_HIGH;
 
 	return MODE_OK;
@@ -1113,6 +1125,7 @@
 	card->num_links = 1;
 	card->name = "vc4-hdmi";
 	card->dev = dev;
+	card->owner = THIS_MODULE;
 
 	/*
 	 * Be careful, snd_soc_register_card() calls dev_set_drvdata() and
@@ -1285,6 +1298,9 @@
 
 static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
+#ifdef CONFIG_DRM_VC4_HDMI_CEC
+	struct cec_connector_info conn_info;
+#endif
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *drm = dev_get_drvdata(master);
 	struct vc4_dev *vc4 = drm->dev_private;
@@ -1403,13 +1419,15 @@
 #ifdef CONFIG_DRM_VC4_HDMI_CEC
 	hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
 					      vc4, "vc4",
-					      CEC_CAP_TRANSMIT |
-					      CEC_CAP_LOG_ADDRS |
-					      CEC_CAP_PASSTHROUGH |
-					      CEC_CAP_RC, 1);
+					      CEC_CAP_DEFAULTS |
+					      CEC_CAP_CONNECTOR_INFO, 1);
 	ret = PTR_ERR_OR_ZERO(hdmi->cec_adap);
 	if (ret < 0)
 		goto err_destroy_conn;
+
+	cec_fill_conn_info_from_drm(&conn_info, hdmi->connector);
+	cec_s_conn_info(hdmi->cec_adap, &conn_info);
+
 	HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff);
 	value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
 	value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_plane.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_plane.c
@@ -205,7 +205,7 @@
 	__drm_atomic_helper_plane_reset(plane, &vc4_state->base);
 }
 
-static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
+static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state)
 {
 	if (vc4_state->dlist_count == vc4_state->dlist_size) {
 		u32 new_size = max(4u, vc4_state->dlist_count * 2);
@@ -220,7 +220,15 @@
 		vc4_state->dlist_size = new_size;
 	}
 
-	vc4_state->dlist[vc4_state->dlist_count++] = val;
+	vc4_state->dlist_count++;
+}
+
+static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
+{
+	unsigned int idx = vc4_state->dlist_count;
+
+	vc4_dlist_counter_increment(vc4_state);
+	vc4_state->dlist[idx] = val;
 }
 
 /* Returns the scl0/scl1 field based on whether the dimensions need to
@@ -280,16 +288,16 @@
 					       adjhdisplay,
 					       crtc_state->mode.hdisplay);
 	vc4_pstate->crtc_x += left;
-	if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
-		vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
+	if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
+		vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
 
 	adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
 	vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
 					       adjvdisplay,
 					       crtc_state->mode.vdisplay);
 	vc4_pstate->crtc_y += top;
-	if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
-		vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
+	if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
+		vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
 
 	vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
 					       adjhdisplay,
@@ -309,7 +317,6 @@
 	struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
 	struct drm_framebuffer *fb = state->fb;
 	struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-	u32 subpixel_src_mask = (1 << 16) - 1;
 	int num_planes = fb->format->num_planes;
 	struct drm_crtc_state *crtc_state;
 	u32 h_subsample = fb->format->hsub;
@@ -331,18 +338,15 @@
 	for (i = 0; i < num_planes; i++)
 		vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
 
-	/* We don't support subpixel source positioning for scaling. */
-	if ((state->src.x1 & subpixel_src_mask) ||
-	    (state->src.x2 & subpixel_src_mask) ||
-	    (state->src.y1 & subpixel_src_mask) ||
-	    (state->src.y2 & subpixel_src_mask)) {
-		return -EINVAL;
-	}
-
-	vc4_state->src_x = state->src.x1 >> 16;
-	vc4_state->src_y = state->src.y1 >> 16;
-	vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
-	vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
+	/*
+	 * We don't support subpixel source positioning for scaling,
+	 * but fractional coordinates can be generated by clipping
+	 * so just round for now
+	 */
+	vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1 << 16);
+	vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1 << 16);
+	vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x;
+	vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y;
 
 	vc4_state->crtc_x = state->dst.x1;
 	vc4_state->crtc_y = state->dst.y1;
@@ -871,8 +875,10 @@
 		 * be set when calling vc4_plane_allocate_lbm().
 		 */
 		if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
-		    vc4_state->y_scaling[1] != VC4_SCALING_NONE)
-			vc4_state->lbm_offset = vc4_state->dlist_count++;
+		    vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
+			vc4_state->lbm_offset = vc4_state->dlist_count;
+			vc4_dlist_counter_increment(vc4_state);
+		}
 
 		if (num_planes > 1) {
 			/* Emit Cb/Cr as channel 0 and Y as channel
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_txp.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_txp.c
@@ -285,12 +285,18 @@
 	if (WARN_ON(i == ARRAY_SIZE(drm_fmts)))
 		return;
 
-	ctrl = TXP_GO | TXP_VSTART_AT_EOF | TXP_EI |
+	ctrl = TXP_GO | TXP_EI |
 	       VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) |
 	       VC4_SET_FIELD(txp_fmts[i], TXP_FORMAT);
 
 	if (fb->format->has_alpha)
 		ctrl |= TXP_ALPHA_ENABLE;
+	else
+		/*
+		 * If TXP_ALPHA_ENABLE isn't set and TXP_ALPHA_INVERT is, the
+		 * hardware will force the output padding to be 0xff.
+		 */
+		ctrl |= TXP_ALPHA_INVERT;
 
 	gem = drm_fb_cma_get_gem_obj(fb, 0);
 	TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vc4/vc4_vec.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vc4/vc4_vec.c
@@ -256,7 +256,7 @@
 static const struct drm_display_mode ntsc_mode = {
 	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
-		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+		 480, 480 + 7, 480 + 7 + 6, 525, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
@@ -278,7 +278,7 @@
 static const struct drm_display_mode pal_mode = {
 	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
-		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+		 576, 576 + 4, 576 + 4 + 6, 625, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vgem/vgem_drv.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vgem/vgem_drv.c
@@ -196,9 +196,10 @@
 		return ERR_CAST(obj);
 
 	ret = drm_gem_handle_create(file, &obj->base, handle);
-	drm_gem_object_put_unlocked(&obj->base);
-	if (ret)
+	if (ret) {
+		drm_gem_object_put_unlocked(&obj->base);
 		return ERR_PTR(ret);
+	}
 
 	return &obj->base;
 }
@@ -221,35 +222,11 @@
 	args->size = gem_object->size;
 	args->pitch = pitch;
 
-	DRM_DEBUG("Created object of size %lld\n", size);
+	drm_gem_object_put_unlocked(gem_object);
 
-	return 0;
-}
-
-static int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev,
-			     uint32_t handle, uint64_t *offset)
-{
-	struct drm_gem_object *obj;
-	int ret;
+	DRM_DEBUG("Created object of size %llu\n", args->size);
 
-	obj = drm_gem_object_lookup(file, handle);
-	if (!obj)
-		return -ENOENT;
-
-	if (!obj->filp) {
-		ret = -EINVAL;
-		goto unref;
-	}
-
-	ret = drm_gem_create_mmap_offset(obj);
-	if (ret)
-		goto unref;
-
-	*offset = drm_vma_node_offset_addr(&obj->vma_node);
-unref:
-	drm_gem_object_put_unlocked(obj);
-
-	return ret;
+	return 0;
 }
 
 static struct drm_ioctl_desc vgem_ioctls[] = {
@@ -445,7 +422,6 @@
 	.fops				= &vgem_driver_fops,
 
 	.dumb_create			= vgem_gem_dumb_create,
-	.dumb_map_offset		= vgem_gem_dumb_map,
 
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vgem/vgem_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vgem/vgem_fence.c
@@ -249,4 +249,5 @@
 {
 	idr_for_each(&vfile->fence_idr, __vgem_fence_idr_fini, vfile);
 	idr_destroy(&vfile->fence_idr);
+	mutex_destroy(&vfile->fence_mutex);
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/virtio/virtgpu_display.c
+++ linux-ein-5.4.0/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -174,6 +174,8 @@
 		DRM_DEBUG("add mode: %dx%d\n", width, height);
 		mode = drm_cvt_mode(connector->dev, width, height, 60,
 				    false, false, false);
+		if (!mode)
+			return count;
 		mode->type |= DRM_MODE_TYPE_PREFERRED;
 		drm_mode_probed_add(connector, mode);
 		count++;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ linux-ein-5.4.0/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -327,10 +327,18 @@
 		drm_gem_object_release(obj);
 		return ret;
 	}
-	drm_gem_object_put_unlocked(obj);
 
 	rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
 	rc->bo_handle = handle;
+
+	/*
+	 * The handle owns the reference now.  But we must drop our
+	 * remaining reference *after* we no longer need to dereference
+	 * the obj.  Otherwise userspace could guess the handle and
+	 * race closing it from another thread.
+	 */
+	drm_gem_object_put_unlocked(obj);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -96,8 +96,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",
@@ -216,6 +218,7 @@
 err_vbufs:
 	vgdev->vdev->config->del_vqs(vgdev->vdev);
 err_vqs:
+	dev->dev_private = NULL;
 	kfree(vgdev);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/gpu/drm/virtio/virtgpu_object.c
+++ linux-ein-5.4.0/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -23,38 +23,44 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/moduleparam.h>
+
 #include <drm/ttm/ttm_execbuf_util.h>
 
 #include "virtgpu_drv.h"
 
+static int virtio_gpu_virglrenderer_workaround = 1;
+module_param_named(virglhack, virtio_gpu_virglrenderer_workaround, int, 0400);
+
 static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
 				       uint32_t *resid)
 {
-#if 0
-	int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
-
-	if (handle < 0)
-		return handle;
-#else
-	static int handle;
-
-	/*
-	 * FIXME: dirty hack to avoid re-using IDs, virglrenderer
-	 * can't deal with that.  Needs fixing in virglrenderer, also
-	 * should figure a better way to handle that in the guest.
-	 */
-	handle++;
-#endif
-
-	*resid = handle + 1;
+	if (virtio_gpu_virglrenderer_workaround) {
+		/*
+		 * Hack to avoid re-using resource IDs.
+		 *
+		 * virglrenderer versions up to (and including) 0.7.0
+		 * can't deal with that.  virglrenderer commit
+		 * "f91a9dd35715 Fix unlinking resources from hash
+		 * table." (Feb 2019) fixes the bug.
+		 */
+		static atomic_t seqno = ATOMIC_INIT(0);
+		int handle = atomic_inc_return(&seqno);
+		*resid = handle + 1;
+	} else {
+		int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
+		if (handle < 0)
+			return handle;
+		*resid = handle + 1;
+	}
 	return 0;
 }
 
 static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
 {
-#if 0
-	ida_free(&vgdev->resource_ida, id - 1);
-#endif
+	if (!virtio_gpu_virglrenderer_workaround) {
+		ida_free(&vgdev->resource_ida, id - 1);
+	}
 }
 
 static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ linux-ein-5.4.0/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -80,9 +80,7 @@
 {
 	struct virtio_gpu_vbuffer *vbuf;
 
-	vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL);
-	if (!vbuf)
-		return ERR_PTR(-ENOMEM);
+	vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL | __GFP_NOFAIL);
 
 	BUG_ON(size > MAX_INLINE_CMD_SIZE);
 	vbuf->buf = (void *)vbuf + sizeof(*vbuf);
@@ -142,10 +140,6 @@
 
 	vbuf = virtio_gpu_get_vbuf(vgdev, cmd_size,
 				   resp_size, resp_buf, cb);
-	if (IS_ERR(vbuf)) {
-		*vbuffer_p = NULL;
-		return ERR_CAST(vbuf);
-	}
 	*vbuffer_p = vbuf;
 	return (struct virtio_gpu_command *)vbuf->buf;
 }
@@ -572,9 +566,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);
 }
@@ -988,8 +986,9 @@
 	}
 
 	/* gets freed when the ring has consumed it */
-	ents = kmalloc_array(nents, sizeof(struct virtio_gpu_mem_entry),
-			     GFP_KERNEL);
+	ents = kvmalloc_array(nents,
+			      sizeof(struct virtio_gpu_mem_entry),
+			      GFP_KERNEL);
 	if (!ents) {
 		DRM_ERROR("failed to allocate ent list\n");
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vkms/vkms_composer.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vkms/vkms_composer.c
@@ -33,7 +33,7 @@
 				     + (i * composer->pitch)
 				     + (j * composer->cpp);
 			/* XRGB format ignores Alpha channel */
-			memset(vaddr_out + src_offset + 24, 0,  8);
+			bitmap_clear(vaddr_out + src_offset, 24, 8);
 			crc = crc32_le(crc, vaddr_out + src_offset,
 				       sizeof(u32));
 		}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vkms/vkms_crtc.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -20,7 +20,8 @@
 
 	ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
 					  output->period_ns);
-	WARN_ON(ret_overrun != 1);
+	if (ret_overrun != 1)
+		pr_warn("%s: vblank timer overrun\n", __func__);
 
 	ret = drm_crtc_handle_vblank(crtc);
 	if (!ret)
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vkms/vkms_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/vkms/vkms_drv.h
@@ -121,11 +121,6 @@
 				  enum drm_plane_type type, int index);
 
 /* Gem stuff */
-struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
-				       struct drm_file *file,
-				       u32 *handle,
-				       u64 size);
-
 vm_fault_t vkms_gem_fault(struct vm_fault *vmf);
 
 int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vkms/vkms_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vkms/vkms_gem.c
@@ -95,10 +95,10 @@
 	return ret;
 }
 
-struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
-				       struct drm_file *file,
-				       u32 *handle,
-				       u64 size)
+static struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
+					      struct drm_file *file,
+					      u32 *handle,
+					      u64 size)
 {
 	struct vkms_gem_object *obj;
 	int ret;
@@ -111,7 +111,6 @@
 		return ERR_CAST(obj);
 
 	ret = drm_gem_handle_create(file, &obj->gem, handle);
-	drm_gem_object_put_unlocked(&obj->gem);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -140,6 +139,8 @@
 	args->size = gem_obj->size;
 	args->pitch = pitch;
 
+	drm_gem_object_put_unlocked(gem_obj);
+
 	DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
@@ -209,8 +209,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);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -1002,15 +1002,14 @@
 				      struct vmw_private *dev_priv,
 				      struct vmw_fence_obj **p_fence,
 				      uint32_t *p_handle);
-extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
+extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
 					struct vmw_fpriv *vmw_fp,
 					int ret,
 					struct drm_vmw_fence_rep __user
 					*user_fence_rep,
 					struct vmw_fence_obj *fence,
 					uint32_t fence_handle,
-					int32_t out_fence_fd,
-					struct sync_file *sync_file);
+					int32_t out_fence_fd);
 bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
 
 /**
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1623,7 +1623,7 @@
 {
 	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdSetTextureState);
 	SVGA3dTextureState *last_state = (SVGA3dTextureState *)
-	  ((unsigned long) header + header->size + sizeof(header));
+	  ((unsigned long) header + header->size + sizeof(*header));
 	SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
 		((unsigned long) header + sizeof(*cmd));
 	struct vmw_resource *ctx;
@@ -3413,17 +3413,17 @@
  * Also if copying fails, user-space will be unable to signal the fence object
  * so we wait for it immediately, and then unreference the user-space reference.
  */
-void
+int
 vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
 			    struct vmw_fpriv *vmw_fp, int ret,
 			    struct drm_vmw_fence_rep __user *user_fence_rep,
 			    struct vmw_fence_obj *fence, uint32_t fence_handle,
-			    int32_t out_fence_fd, struct sync_file *sync_file)
+			    int32_t out_fence_fd)
 {
 	struct drm_vmw_fence_rep fence_rep;
 
 	if (user_fence_rep == NULL)
-		return;
+		return 0;
 
 	memset(&fence_rep, 0, sizeof(fence_rep));
 
@@ -3451,20 +3451,14 @@
 	 * handle.
 	 */
 	if (unlikely(ret != 0) && (fence_rep.error == 0)) {
-		if (sync_file)
-			fput(sync_file->file);
-
-		if (fence_rep.fd != -1) {
-			put_unused_fd(fence_rep.fd);
-			fence_rep.fd = -1;
-		}
-
 		ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle,
 					  TTM_REF_USAGE);
 		VMW_DEBUG_USER("Fence copy error. Syncing.\n");
 		(void) vmw_fence_obj_wait(fence, false, false,
 					  VMW_FENCE_WAIT_TIMEOUT);
 	}
+
+	return ret ? -EFAULT : 0;
 }
 
 /**
@@ -3806,16 +3800,23 @@
 
 			(void) vmw_fence_obj_wait(fence, false, false,
 						  VMW_FENCE_WAIT_TIMEOUT);
+		}
+	}
+
+	ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
+				    user_fence_rep, fence, handle, out_fence_fd);
+
+	if (sync_file) {
+		if (ret) {
+			/* usercopy of fence failed, put the file object */
+			fput(sync_file->file);
+			put_unused_fd(out_fence_fd);
 		} else {
 			/* Link the fence with the FD created earlier */
 			fd_install(out_fence_fd, sync_file->file);
 		}
 	}
 
-	vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
-				    user_fence_rep, fence, handle, out_fence_fd,
-				    sync_file);
-
 	/* Don't unreference when handing fence out */
 	if (unlikely(out_fence != NULL)) {
 		*out_fence = fence;
@@ -3833,7 +3834,7 @@
 	 */
 	vmw_validation_unref_lists(&val_ctx);
 
-	return 0;
+	return ret;
 
 out_unlock_binding:
 	mutex_unlock(&dev_priv->binding_mutex);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -498,7 +498,7 @@
 
 static int vmw_fb_kms_framebuffer(struct fb_info *info)
 {
-	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_mode_fb_cmd2 mode_cmd = {0};
 	struct vmw_fb_par *par = info->par;
 	struct fb_var_screeninfo *var = &info->var;
 	struct drm_framebuffer *cur_fb;
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -1171,7 +1171,7 @@
 	}
 
 	vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
-				    handle, -1, NULL);
+				    handle, -1);
 	vmw_fence_obj_unreference(&fence);
 	return 0;
 out_no_create:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -182,7 +182,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 */
@@ -2570,7 +2571,7 @@
 	if (file_priv)
 		vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
 					    ret, user_fence_rep, fence,
-					    handle, -1, NULL);
+					    handle, -1);
 	if (out_fence)
 		*out_fence = fence;
 	else
@@ -2666,7 +2667,7 @@
 		++i;
 	}
 
-	if (i != unit) {
+	if (&con->head == &dev_priv->dev->mode_config.connector_list) {
 		DRM_ERROR("Could not find initial display unit.\n");
 		ret = -EINVAL;
 		goto out_unlock;
@@ -2690,13 +2691,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;
 	}
 
  out_unlock:
--- linux-ein-5.4.0.orig/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ linux-ein-5.4.0/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -81,7 +81,7 @@
 	struct vmw_legacy_display_unit *entry;
 	struct drm_framebuffer *fb = NULL;
 	struct drm_crtc *crtc = NULL;
-	int i = 0;
+	int i;
 
 	/* If there is no display topology the host just assumes
 	 * that the guest will set the same layout as the host.
@@ -92,12 +92,11 @@
 			crtc = &entry->base.crtc;
 			w = max(w, crtc->x + crtc->mode.hdisplay);
 			h = max(h, crtc->y + crtc->mode.vdisplay);
-			i++;
 		}
 
 		if (crtc == NULL)
 			return 0;
-		fb = entry->base.crtc.primary->state->fb;
+		fb = crtc->primary->state->fb;
 
 		return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
 					  fb->format->cpp[0] * 8,
--- linux-ein-5.4.0.orig/drivers/gpu/drm/xen/xen_drm_front.c
+++ linux-ein-5.4.0/drivers/gpu/drm/xen/xen_drm_front.c
@@ -400,7 +400,7 @@
 	args->size = args->pitch * args->height;
 
 	obj = xen_drm_front_gem_create(dev, args->size);
-	if (IS_ERR_OR_NULL(obj)) {
+	if (IS_ERR(obj)) {
 		ret = PTR_ERR(obj);
 		goto fail;
 	}
--- linux-ein-5.4.0.orig/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ linux-ein-5.4.0/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -83,7 +83,7 @@
 
 	size = round_up(size, PAGE_SIZE);
 	xen_obj = gem_create_obj(dev, size);
-	if (IS_ERR_OR_NULL(xen_obj))
+	if (IS_ERR(xen_obj))
 		return xen_obj;
 
 	if (drm_info->front_info->cfg.be_alloc) {
@@ -117,7 +117,7 @@
 	 */
 	xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
 	xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
-	if (IS_ERR_OR_NULL(xen_obj->pages)) {
+	if (IS_ERR(xen_obj->pages)) {
 		ret = PTR_ERR(xen_obj->pages);
 		xen_obj->pages = NULL;
 		goto fail;
@@ -136,7 +136,7 @@
 	struct xen_gem_object *xen_obj;
 
 	xen_obj = gem_create(dev, size);
-	if (IS_ERR_OR_NULL(xen_obj))
+	if (IS_ERR(xen_obj))
 		return ERR_CAST(xen_obj);
 
 	return &xen_obj->base;
@@ -194,7 +194,7 @@
 
 	size = attach->dmabuf->size;
 	xen_obj = gem_create_obj(dev, size);
-	if (IS_ERR_OR_NULL(xen_obj))
+	if (IS_ERR(xen_obj))
 		return ERR_CAST(xen_obj);
 
 	ret = gem_alloc_pages_array(xen_obj, size);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/xen/xen_drm_front_kms.c
+++ linux-ein-5.4.0/drivers/gpu/drm/xen/xen_drm_front_kms.c
@@ -60,7 +60,7 @@
 	int ret;
 
 	fb = drm_gem_fb_create_with_funcs(dev, filp, mode_cmd, &fb_funcs);
-	if (IS_ERR_OR_NULL(fb))
+	if (IS_ERR(fb))
 		return fb;
 
 	gem_obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
--- linux-ein-5.4.0.orig/drivers/gpu/drm/zte/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/drm/zte/Kconfig
@@ -3,7 +3,6 @@
 	tristate "DRM Support for ZTE SoCs"
 	depends on DRM && ARCH_ZX
 	select DRM_KMS_CMA_HELPER
-	select DRM_KMS_FB_HELPER
 	select DRM_KMS_HELPER
 	select SND_SOC_HDMI_CODEC if SND_SOC
 	select VIDEOMODE_HELPERS
--- linux-ein-5.4.0.orig/drivers/gpu/host1x/bus.c
+++ linux-ein-5.4.0/drivers/gpu/host1x/bus.c
@@ -686,8 +686,17 @@
  */
 void host1x_driver_unregister(struct host1x_driver *driver)
 {
+	struct host1x *host1x;
+
 	driver_unregister(&driver->driver);
 
+	mutex_lock(&devices_lock);
+
+	list_for_each_entry(host1x, &devices, list)
+		host1x_detach_driver(host1x, driver);
+
+	mutex_unlock(&devices_lock);
+
 	mutex_lock(&drivers_lock);
 	list_del_init(&driver->list);
 	mutex_unlock(&drivers_lock);
--- linux-ein-5.4.0.orig/drivers/gpu/host1x/debug.c
+++ linux-ein-5.4.0/drivers/gpu/host1x/debug.c
@@ -16,6 +16,8 @@
 #include "debug.h"
 #include "channel.h"
 
+static DEFINE_MUTEX(debug_lock);
+
 unsigned int host1x_debug_trace_cmdbuf;
 
 static pid_t host1x_debug_force_timeout_pid;
@@ -52,12 +54,14 @@
 	struct output *o = data;
 
 	mutex_lock(&ch->cdma.lock);
+	mutex_lock(&debug_lock);
 
 	if (show_fifo)
 		host1x_hw_show_channel_fifo(m, ch, o);
 
 	host1x_hw_show_channel_cdma(m, ch, o);
 
+	mutex_unlock(&debug_lock);
 	mutex_unlock(&ch->cdma.lock);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/gpu/host1x/hw/syncpt_hw.c
+++ linux-ein-5.4.0/drivers/gpu/host1x/hw/syncpt_hw.c
@@ -106,9 +106,6 @@
 #if HOST1X_HW >= 6
 	struct host1x *host = sp->host;
 
-	if (!host->hv_regs)
-		return;
-
 	host1x_sync_writel(host,
 			   HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff),
 			   HOST1X_SYNC_SYNCPT_CH_APP(sp->id));
--- linux-ein-5.4.0.orig/drivers/gpu/host1x/job.c
+++ linux-ein-5.4.0/drivers/gpu/host1x/job.c
@@ -436,7 +436,8 @@
 	return err;
 }
 
-static inline int copy_gathers(struct host1x_job *job, struct device *dev)
+static inline int copy_gathers(struct device *host, struct host1x_job *job,
+			       struct device *dev)
 {
 	struct host1x_firewall fw;
 	size_t size = 0;
@@ -459,12 +460,12 @@
 	 * Try a non-blocking allocation from a higher priority pools first,
 	 * as awaiting for the allocation here is a major performance hit.
 	 */
-	job->gather_copy_mapped = dma_alloc_wc(dev, size, &job->gather_copy,
+	job->gather_copy_mapped = dma_alloc_wc(host, size, &job->gather_copy,
 					       GFP_NOWAIT);
 
 	/* the higher priority allocation failed, try the generic-blocking */
 	if (!job->gather_copy_mapped)
-		job->gather_copy_mapped = dma_alloc_wc(dev, size,
+		job->gather_copy_mapped = dma_alloc_wc(host, size,
 						       &job->gather_copy,
 						       GFP_KERNEL);
 	if (!job->gather_copy_mapped)
@@ -512,7 +513,7 @@
 		goto out;
 
 	if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) {
-		err = copy_gathers(job, dev);
+		err = copy_gathers(host->dev, job, dev);
 		if (err)
 			goto out;
 	}
@@ -573,7 +574,7 @@
 	job->num_unpins = 0;
 
 	if (job->gather_copy_size)
-		dma_free_wc(job->channel->dev, job->gather_copy_size,
+		dma_free_wc(host->dev, job->gather_copy_size,
 			    job->gather_copy_mapped, job->gather_copy);
 }
 EXPORT_SYMBOL(host1x_job_unpin);
--- linux-ein-5.4.0.orig/drivers/gpu/imx/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/imx/Kconfig
@@ -0,0 +1,20 @@
+config IMX8_PRG
+	tristate
+	default y if IMX_DPU_CORE=y
+	default m if IMX_DPU_CORE=m
+
+config IMX8_DPRC
+	tristate
+	default y if IMX_DPU_CORE=y
+	default m if IMX_DPU_CORE=m
+
+config IMX8_PC
+	tristate
+	default y if IMX_DPU_CORE=y
+	default m if IMX_DPU_CORE=m
+
+source "drivers/gpu/imx/dpu/Kconfig"
+source "drivers/gpu/imx/lcdif/Kconfig"
+source "drivers/gpu/imx/dpu-blit/Kconfig"
+source "drivers/gpu/imx/lcdifv3/Kconfig"
+
--- linux-ein-5.4.0.orig/drivers/gpu/imx/Makefile
+++ linux-ein-5.4.0/drivers/gpu/imx/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_IMX_DPU_CORE)	+= dpu/
+obj-$(CONFIG_IMX_DPU_BLIT)      += dpu-blit/
+obj-$(CONFIG_IMX_LCDIF_CORE)    += lcdif/
+obj-$(CONFIG_IMX_LCDIFV3_CORE)  += lcdifv3/
+obj-$(CONFIG_IMX8_PC)	+= imx8_pc.o
+
+obj-$(CONFIG_IMX8_PRG)	+= imx8_prg.o
+obj-$(CONFIG_IMX8_DPRC)	+= imx8_dprc.o
+
+
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu-blit/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu-blit/Kconfig
@@ -0,0 +1,5 @@
+config IMX_DPU_BLIT
+	tristate
+	depends on IMX_DPU_CORE
+	default y if IMX_DPU_CORE=y
+	default m if IMX_DPU_CORE=m
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu-blit/Makefile
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu-blit/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -I $(srctree)/$(src)/../dpu/
+
+imx-dpu-blit-objs := dpu-blit.o
+
+obj-$(CONFIG_IMX_DPU_BLIT) += imx-dpu-blit.o
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu-blit/dpu-blit-registers.h
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu-blit/dpu-blit-registers.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __DPU_BLIT_REGISTERS_H__
+#define __DPU_BLIT_REGISTERS_H__
+
+/* Registers Defination */
+#define COMCTRL_IPIDENTIFIER                       ((uint32_t)(0))
+
+#define PIXENGCFG_STORE9_TRIGGER                    ((uint32_t)(0x954))
+
+#define COMCTRL_USERINTERRUPTMASK0                  ((uint32_t)(0x48))
+#define COMCTRL_USERINTERRUPTMASK0_USERINTERRUPTMASK0_MASK 0xFFFFFFFFU
+#define COMCTRL_USERINTERRUPTENABLE0                ((uint32_t)(0x80))
+
+#define COMCTRL_INTERRUPTENABLE0                    ((uint32_t)(0x50))
+
+#define COMCTRL_INTERRUPTSTATUS0                    ((uint32_t)(0x68))
+#define COMCTRL_USERINTERRUPTSTATUS0                ((uint32_t)(0x98))
+
+#define COMCTRL_USERINTERRUPTCLEAR0                 ((uint32_t)(0x90))
+#define COMCTRL_USERINTERRUPTCLEAR0_USERINTERRUPTCLEAR0_MASK 0xFFFFFFFFU
+
+#define COMCTRL_INTERRUPTCLEAR0                     ((uint32_t)(0x60))
+#define COMCTRL_INTERRUPTCLEAR0_INTERRUPTCLEAR0_MASK 0xFFFFFFFFU
+
+
+#define PIXENGCFG_FETCHDECODE9_DYNAMIC              ((uint32_t)(0x828))
+#define PIXENGCFG_FETCHDECODE9_DYNAMIC_RESET_VALUE  0U
+
+#define PIXENGCFG_FETCHWARP9_DYNAMIC                ((uint32_t)(0x848))
+#define PIXENGCFG_FETCHWARP9_DYNAMIC_RESET_VALUE    0U
+
+#define PIXENGCFG_ROP9_DYNAMIC                      ((uint32_t)(0x868))
+#define PIXENGCFG_ROP9_DYNAMIC_RESET_VALUE          0x1000000U
+
+#define PIXENGCFG_MATRIX9_DYNAMIC                   ((uint32_t)(0x8A8))
+#define PIXENGCFG_MATRIX9_DYNAMIC_RESET_VALUE       0x1000000U
+
+#define PIXENGCFG_HSCALER9_DYNAMIC                  ((uint32_t)(0x8C8))
+#define PIXENGCFG_HSCALER9_DYNAMIC_RESET_VALUE      0x1000000U
+
+#define PIXENGCFG_VSCALER9_DYNAMIC                  ((uint32_t)(0x8E8))
+#define PIXENGCFG_VSCALER9_DYNAMIC_RESET_VALUE      0x1000000U
+
+#define PIXENGCFG_BLITBLEND9_DYNAMIC                ((uint32_t)(0x928))
+#define PIXENGCFG_BLITBLEND9_DYNAMIC_RESET_VALUE    0x1000000U
+
+#define PIXENGCFG_STORE9_STATIC                     ((uint32_t)(0x948))
+#define PIXENGCFG_STORE9_STATIC_RESET_VALUE         0x800010U
+#define PIXENGCFG_STORE9_STATIC_RESET_MASK          0xFFFFFFFFU
+#define PIXENGCFG_STORE9_STATIC_STORE9_SHDEN_MASK   0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SHDEN_SHIFT  0U
+#define PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN_MASK 0x10U
+#define PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN_SHIFT 4U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE_MASK 0x100U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE_SHIFT 8U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__SINGLE 0U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__AUTO 0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET_MASK 0x800U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET_SHIFT 11U
+/* Field Value: STORE9_SW_RESET__OPERATION, Normal Operation  */
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__OPERATION 0U
+/* Field Value: STORE9_SW_RESET__SWRESET, Software Reset  */
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__SWRESET 0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_DIV_MASK     0xFF0000U
+#define PIXENGCFG_STORE9_STATIC_STORE9_DIV_SHIFT    16U
+
+#define PIXENGCFG_STORE9_DYNAMIC                    ((uint32_t)(0x94C))
+
+#define FETCHDECODE9_STATICCONTROL                  ((uint32_t)(0x1008))
+#define FETCHDECODE9_STATICCONTROL_OFFSET           ((uint32_t)(0x8))
+#define FETCHDECODE9_STATICCONTROL_RESET_VALUE      0U
+#define FETCHDECODE9_STATICCONTROL_SHDEN_MASK       0x1U
+#define FETCHDECODE9_STATICCONTROL_SHDEN_SHIFT      0U
+#define FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+
+#define FETCHDECODE9_BURSTBUFFERMANAGEMENT          ((uint32_t)(0x100C))
+#define FETCHDECODE9_BASEADDRESS0                   ((uint32_t)(0x101C))
+#define FETCHDECODE9_SOURCEBUFFERATTRIBUTES0        ((uint32_t)(0x1020))
+#define FETCHDECODE9_SOURCEBUFFERDIMENSION0         ((uint32_t)(0x1024))
+#define FETCHDECODE9_COLORCOMPONENTBITS0            ((uint32_t)(0x1028))
+#define FETCHDECODE9_COLORCOMPONENTSHIFT0           ((uint32_t)(0x102C))
+#define FETCHDECODE9_LAYEROFFSET0                   ((uint32_t)(0x1030))
+#define FETCHDECODE9_CLIPWINDOWOFFSET0              ((uint32_t)(0x1034))
+#define FETCHDECODE9_CLIPWINDOWDIMENSIONS0          ((uint32_t)(0x1038))
+#define FETCHDECODE9_CONSTANTCOLOR0                 ((uint32_t)(0x103C))
+#define FETCHDECODE9_LAYERPROPERTY0                 ((uint32_t)(0x1040))
+#define FETCHDECODE9_FRAMEDIMENSIONS                ((uint32_t)(0x1044))
+#define FETCHDECODE9_FRAMERESAMPLING                ((uint32_t)(0x1048))
+#define FETCHDECODE9_CONTROL			    ((uint32_t)(0x1054))
+
+#define FETCHWARP9_STATICCONTROL                    ((uint32_t)(0x1808))
+#define FETCHWARP9_STATICCONTROL_OFFSET             ((uint32_t)(0x8))
+#define FETCHWARP9_STATICCONTROL_RESET_VALUE        0xFF000000U
+#define FETCHWARP9_STATICCONTROL_RESET_MASK         0xFFFFFFFFU
+#define FETCHWARP9_STATICCONTROL_SHDEN_MASK         0x1U
+#define FETCHWARP9_STATICCONTROL_SHDEN_SHIFT        0U
+#define FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+#define FETCHWARP9_STATICCONTROL_SHDLDREQSTICKY_MASK 0xFF000000U
+#define FETCHWARP9_STATICCONTROL_SHDLDREQSTICKY_SHIFT 24U
+
+#define FETCHWARP9_BURSTBUFFERMANAGEMENT            ((uint32_t)(0x180C))
+#define FETCHWARP9_BASEADDRESS0                     ((uint32_t)(0x1810))
+#define FETCHWARP9_SOURCEBUFFERATTRIBUTES0          ((uint32_t)(0x1814))
+#define FETCHWARP9_SOURCEBUFFERDIMENSION0           ((uint32_t)(0x1818))
+#define FETCHWARP9_COLORCOMPONENTBITS0              ((uint32_t)(0x181C))
+#define FETCHWARP9_COLORCOMPONENTSHIFT0             ((uint32_t)(0x1820))
+#define FETCHWARP9_LAYEROFFSET0                     ((uint32_t)(0x1824))
+#define FETCHWARP9_CLIPWINDOWOFFSET0                ((uint32_t)(0x1828))
+#define FETCHWARP9_CLIPWINDOWDIMENSIONS0            ((uint32_t)(0x182C))
+#define FETCHWARP9_CONSTANTCOLOR0                   ((uint32_t)(0x1830))
+#define FETCHWARP9_LAYERPROPERTY0                   ((uint32_t)(0x1834))
+#define FETCHWARP9_FRAMEDIMENSIONS                  ((uint32_t)(0x1950))
+#define FETCHWARP9_FRAMERESAMPLING                  ((uint32_t)(0x1954))
+#define FETCHWARP9_CONTROL                          ((uint32_t)(0x1970))
+
+
+#define FETCHECO9_STATICCONTROL                     ((uint32_t)(0x1C08))
+#define FETCHECO9_STATICCONTROL_OFFSET              ((uint32_t)(0x8))
+#define FETCHECO9_STATICCONTROL_RESET_VALUE         0U
+#define FETCHECO9_STATICCONTROL_RESET_MASK          0xFFFFFFFFU
+#define FETCHECO9_STATICCONTROL_SHDEN_MASK          0x1U
+#define FETCHECO9_STATICCONTROL_SHDEN_SHIFT         0U
+#define FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+
+#define FETCHECO9_BURSTBUFFERMANAGEMENT             ((uint32_t)(0x1C0C))
+#define FETCHECO9_BASEADDRESS0                      ((uint32_t)(0x1C10))
+#define FETCHECO9_SOURCEBUFFERATTRIBUTES0           ((uint32_t)(0x1C14))
+#define FETCHECO9_SOURCEBUFFERDIMENSION0            ((uint32_t)(0x1C18))
+#define FETCHECO9_COLORCOMPONENTBITS0               ((uint32_t)(0x1C1C))
+#define FETCHECO9_COLORCOMPONENTSHIFT0              ((uint32_t)(0x1C20))
+#define FETCHECO9_LAYEROFFSET0                      ((uint32_t)(0x1C24))
+#define FETCHECO9_CLIPWINDOWOFFSET0                 ((uint32_t)(0x1C28))
+#define FETCHECO9_CLIPWINDOWDIMENSIONS0             ((uint32_t)(0x1C2C))
+#define FETCHECO9_CONSTANTCOLOR0                    ((uint32_t)(0x1C30))
+#define FETCHECO9_LAYERPROPERTY0                    ((uint32_t)(0x1C34))
+#define FETCHECO9_FRAMEDIMENSIONS                   ((uint32_t)(0x1C38))
+#define FETCHECO9_FRAMERESAMPLING                   ((uint32_t)(0x1C3C))
+#define FETCHECO9_CONTROL                           ((uint32_t)(0x1C40))
+
+
+#define ROP9_STATICCONTROL                          ((uint32_t)(0x2008))
+#define ROP9_STATICCONTROL_OFFSET                   ((uint32_t)(0x8))
+#define ROP9_STATICCONTROL_RESET_VALUE              0U
+#define ROP9_STATICCONTROL_RESET_MASK               0xFFFFFFFFU
+#define ROP9_STATICCONTROL_SHDEN_MASK               0x1U
+#define ROP9_STATICCONTROL_SHDEN_SHIFT              0U
+
+#define ROP9_CONTROL                                ((uint32_t)(0x200C))
+
+#define MATRIX9_STATICCONTROL                       ((uint32_t)(0x2C08))
+#define MATRIX9_STATICCONTROL_OFFSET                ((uint32_t)(0x8))
+#define MATRIX9_STATICCONTROL_RESET_VALUE           0U
+#define MATRIX9_STATICCONTROL_RESET_MASK            0xFFFFFFFFU
+#define MATRIX9_STATICCONTROL_SHDEN_MASK            0x1U
+#define MATRIX9_STATICCONTROL_SHDEN_SHIFT           0U
+
+#define MATRIX9_CONTROL                             ((uint32_t)(0x2C0C))
+
+#define HSCALER9_SETUP1                             ((uint32_t)(0x300C))
+#define HSCALER9_SETUP2                             ((uint32_t)(0x3010))
+#define HSCALER9_CONTROL                            ((uint32_t)(0x3014))
+
+#define VSCALER9_STATICCONTROL                      ((uint32_t)(0x3408))
+#define VSCALER9_STATICCONTROL_OFFSET               ((uint32_t)(0x8))
+#define VSCALER9_STATICCONTROL_RESET_VALUE          0U
+#define VSCALER9_STATICCONTROL_RESET_MASK           0xFFFFFFFFU
+#define VSCALER9_STATICCONTROL_SHDEN_MASK           0x1U
+#define VSCALER9_STATICCONTROL_SHDEN_SHIFT          0U
+
+#define VSCALER9_SETUP1                             ((uint32_t)(0x340C))
+#define VSCALER9_SETUP2                             ((uint32_t)(0x3410))
+#define VSCALER9_SETUP3                             ((uint32_t)(0x3414))
+#define VSCALER9_SETUP4                             ((uint32_t)(0x3418))
+#define VSCALER9_SETUP5                             ((uint32_t)(0x341C))
+#define VSCALER9_CONTROL                            ((uint32_t)(0x3420))
+
+#define HSCALER9_STATICCONTROL                      ((uint32_t)(0x3008))
+#define HSCALER9_STATICCONTROL_OFFSET               ((uint32_t)(0x8))
+#define HSCALER9_STATICCONTROL_RESET_VALUE          0U
+#define HSCALER9_STATICCONTROL_RESET_MASK           0xFFFFFFFFU
+#define HSCALER9_STATICCONTROL_SHDEN_MASK           0x1U
+#define HSCALER9_STATICCONTROL_SHDEN_SHIFT          0U
+
+#define BLITBLEND9_STATICCONTROL                    ((uint32_t)(0x3C08))
+#define BLITBLEND9_STATICCONTROL_OFFSET             ((uint32_t)(0x8))
+#define BLITBLEND9_STATICCONTROL_RESET_VALUE        0U
+#define BLITBLEND9_STATICCONTROL_RESET_MASK         0xFFFFFFFFU
+#define BLITBLEND9_STATICCONTROL_SHDEN_MASK         0x1U
+#define BLITBLEND9_STATICCONTROL_SHDEN_SHIFT        0U
+
+#define BLITBLEND9_CONTROL                          ((uint32_t)(0x3C0C))
+#define BLITBLEND9_CONSTANTCOLOR                    ((uint32_t)(0x3C14))
+#define BLITBLEND9_COLORREDBLENDFUNCTION            ((uint32_t)(0x3C18))
+#define BLITBLEND9_COLORGREENBLENDFUNCTION          ((uint32_t)(0x3C1C))
+#define BLITBLEND9_COLORBLUEBLENDFUNCTION           ((uint32_t)(0x3C20))
+#define BLITBLEND9_ALPHABLENDFUNCTION               ((uint32_t)(0x3C24))
+#define BLITBLEND9_BLENDMODE1                       ((uint32_t)(0x3C28))
+#define BLITBLEND9_BLENDMODE2                       ((uint32_t)(0x3C2C))
+
+
+#define STORE9_STATICCONTROL                        ((uint32_t)(0x4008))
+#define STORE9_STATICCONTROL_OFFSET                 ((uint32_t)(0x8))
+#define STORE9_STATICCONTROL_RESET_VALUE            0U
+#define STORE9_STATICCONTROL_RESET_MASK             0xFFFFFFFFU
+#define STORE9_STATICCONTROL_SHDEN_MASK             0x1U
+#define STORE9_STATICCONTROL_SHDEN_SHIFT            0U
+#define STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0x100U
+#define STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 8U
+
+#define STORE9_BURSTBUFFERMANAGEMENT                ((uint32_t)(0x400C))
+#define STORE9_BASEADDRESS                          ((uint32_t)(0x4018))
+#define STORE9_DESTINATIONBUFFERATTRIBUTES          ((uint32_t)(0x401C))
+#define STORE9_DESTINATIONBUFFERDIMENSION           ((uint32_t)(0x4020))
+#define STORE9_FRAMEOFFSET                          ((uint32_t)(0x4024))
+#define STORE9_COLORCOMPONENTBITS                   ((uint32_t)(0x4028))
+#define STORE9_COLORCOMPONENTSHIFT                  ((uint32_t)(0x402C))
+#define STORE9_CONTROL                              ((uint32_t)(0x4030))
+
+#define STORE9_START                                ((uint32_t)(0x403C))
+
+/* pixengcfg */
+#define PIXENGCFG_CLKEN_MASK 0x3000000U
+#define PIXENGCFG_CLKEN_SHIFT 24U
+/* Field Value: _CLKEN__DISABLE, Clock for block is disabled  */
+#define PIXENGCFG_CLKEN__DISABLE 0U
+#define PIXENGCFG_CLKEN__AUTOMATIC 0x1U
+/* Field Value: _CLKEN__FULL, Clock for block is without gating  */
+#define PIXENGCFG_CLKEN__FULL 0x3U
+
+#define PIXENGCFG_DIVIDER_RESET 0x80
+
+
+/* command sequencer */
+#define CMDSEQ_HIF                                  ((uint32_t)(0x400))
+
+#define CMDSEQ_LOCKUNLOCKHIF                        ((uint32_t)(0x500))
+#define CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__LOCK_KEY 0x5651F763U
+#define CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__UNLOCK_KEY 0x691DB936U
+
+#define CMDSEQ_LOCKUNLOCK                           ((uint32_t)(0x580))
+#define CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__LOCK_KEY      0x5651F763U
+#define CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__UNLOCK_KEY    0x691DB936U
+
+#define CMDSEQ_BUFFERADDRESS                        ((uint32_t)(0x588))
+#define CMDSEQ_BUFFERSIZE                           ((uint32_t)(0x58C))
+
+#define CMDSEQ_CONTROL                              ((uint32_t)(0x594))
+#define CMDSEQ_CONTROL_OFFSET                       ((uint32_t)(0x194))
+#define CMDSEQ_CONTROL_RESET_VALUE                  0U
+#define CMDSEQ_CONTROL_RESET_MASK                   0xFFFFFFFFU
+#define CMDSEQ_CONTROL_CLRAXIW_MASK                 0x1U
+#define CMDSEQ_CONTROL_CLRAXIW_SHIFT                0U
+#define CMDSEQ_CONTROL_CLRRBUF_MASK                 0x4U
+#define CMDSEQ_CONTROL_CLRRBUF_SHIFT                2U
+#define CMDSEQ_CONTROL_CLRCMDBUF_MASK               0x8U
+#define CMDSEQ_CONTROL_CLRCMDBUF_SHIFT              3U
+#define CMDSEQ_CONTROL_CLEAR_MASK                   0x80000000U
+#define CMDSEQ_CONTROL_CLEAR_SHIFT                  31U
+
+#define CMDSEQ_STATUS                               ((uint32_t)(0x598))
+#define CMDSEQ_STATUS_OFFSET                        ((uint32_t)(0x198))
+#define CMDSEQ_STATUS_RESET_VALUE                   0x41000080U
+#define CMDSEQ_STATUS_RESET_MASK                    0xFFFFFFFFU
+#define CMDSEQ_STATUS_FIFOSPACE_MASK                0x1FFFFU
+#define CMDSEQ_STATUS_IDLE_MASK                     0x40000000U
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu-blit/dpu-blit.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu-blit/dpu-blit.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include <video/imx8-prefetch.h>
+
+#include "dpu-blit.h"
+#include "dpu-blit-registers.h"
+#include "dpu-prv.h"
+
+void dpu_be_wait(struct dpu_bliteng *dpu_be);
+
+static inline u32 dpu_be_read(struct dpu_bliteng *dpu_be, unsigned int offset)
+{
+	return readl(dpu_be->base + offset);
+}
+
+static inline void dpu_be_write(struct dpu_bliteng *dpu_be, u32 value,
+	unsigned int offset)
+{
+	writel(value, dpu_be->base + offset);
+}
+
+static void dpu_cs_wait_fifo_space(struct dpu_bliteng *dpu_be)
+{
+	while ((dpu_be_read(dpu_be, CMDSEQ_STATUS) &
+		CMDSEQ_STATUS_FIFOSPACE_MASK) < CMDSEQ_FIFO_SPACE_THRESHOLD)
+		usleep_range(30, 50);
+}
+
+static void dpu_cs_wait_idle(struct dpu_bliteng *dpu_be)
+{
+	while ((dpu_be_read(dpu_be, CMDSEQ_STATUS) &
+		CMDSEQ_STATUS_IDLE_MASK) == 0x0)
+		mdelay(1);
+}
+
+static int dpu_cs_alloc_command_buffer(struct dpu_bliteng *dpu_be)
+{
+	/* command buffer need 32 bit address */
+	dpu_be->buffer_addr_virt =
+		alloc_pages_exact(COMMAND_BUFFER_SIZE,
+			GFP_KERNEL | GFP_DMA | GFP_DMA32 | __GFP_ZERO);
+	if (!dpu_be->buffer_addr_virt) {
+		dev_err(dpu_be->dev, "memory alloc failed for dpu command buffer\n");
+		return -ENOMEM;
+	}
+
+	dpu_be->buffer_addr_phy =
+		(u32)virt_to_phys(dpu_be->buffer_addr_virt);
+
+	return 0;
+}
+
+static void dpu_cs_static_setup(struct dpu_bliteng *dpu_be)
+{
+	dpu_cs_wait_idle(dpu_be);
+
+	/* LockUnlock and LockUnlockHIF */
+	dpu_be_write(dpu_be, CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__UNLOCK_KEY,
+		CMDSEQ_LOCKUNLOCKHIF);
+	dpu_be_write(dpu_be, CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__UNLOCK_KEY,
+		CMDSEQ_LOCKUNLOCK);
+
+	/* Control */
+	dpu_be_write(dpu_be, 1 << CMDSEQ_CONTROL_CLEAR_SHIFT,
+		CMDSEQ_CONTROL);
+
+	/* BufferAddress and BufferSize */
+	dpu_be_write(dpu_be, dpu_be->buffer_addr_phy, CMDSEQ_BUFFERADDRESS);
+	dpu_be_write(dpu_be, COMMAND_BUFFER_SIZE / WORD_SIZE,
+		CMDSEQ_BUFFERSIZE);
+}
+
+static struct dprc *
+dpu_be_dprc_get(struct dpu_soc *dpu, int dprc_id)
+{
+	struct dprc *dprc;
+
+	dprc = dprc_lookup_by_phandle(dpu->dev,
+				      "fsl,dpr-channels",
+				      dprc_id);
+
+	return dprc;
+}
+
+void dpu_be_configure_prefetch(struct dpu_bliteng *dpu_be,
+			       u32 width, u32 height,
+			       u32 x_offset, u32 y_offset,
+			       u32 stride, u32 format, u64 modifier,
+			       u64 baddr, u64 uv_addr)
+{
+	struct dprc *dprc;
+	bool dprc_en=false;
+
+	/* Enable DPR, dprc1 is connected to plane0 */
+	dprc = dpu_be->dprc[1];
+
+	/*
+	 * Force sync command sequncer in conditions:
+	 * 1. tile work with dprc/prg (baddr)
+	 * 2. switch tile to linear (!start)
+	 */
+	if (!dpu_be->start || baddr) {
+		dpu_be_wait(dpu_be);
+	}
+
+	dpu_be->sync = true;
+
+	if (baddr == 0x0) {
+		if (!dpu_be->start) {
+			dprc_disable(dprc);
+			dpu_be->start = true;
+		}
+		return;
+	}
+
+	if (dpu_be->modifier != modifier && !dpu_be->start) {
+		dprc_disable(dprc);
+		dprc_en = true;
+	}
+
+	dpu_be->modifier = modifier;
+
+	dprc_configure(dprc, 0,
+		       width, height,
+		       x_offset, y_offset,
+		       stride, format, modifier,
+		       baddr, uv_addr,
+		       dpu_be->start,
+		       dpu_be->start,
+		       false);
+
+	if (dpu_be->start || dprc_en) {
+		dprc_enable(dprc);
+	}
+
+	dprc_reg_update(dprc);
+
+	dpu_be->start = false;
+}
+EXPORT_SYMBOL(dpu_be_configure_prefetch);
+
+int dpu_bliteng_get_empty_instance(struct dpu_bliteng **dpu_be,
+	struct device *dev)
+{
+	if (!dpu_be || !dev)
+		return -EINVAL;
+
+	*dpu_be = devm_kzalloc(dev, sizeof(struct dpu_bliteng), GFP_KERNEL);
+	if (!(*dpu_be))
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_empty_instance);
+
+u32 *dpu_bliteng_get_cmd_list(struct dpu_bliteng *dpu_be)
+{
+	return dpu_be->cmd_list;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_cmd_list);
+
+s32 dpu_bliteng_get_id(struct dpu_bliteng *dpu_be)
+{
+	return dpu_be->id;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_id);
+
+void dpu_bliteng_set_id(struct dpu_bliteng *dpu_be, int id)
+{
+	dpu_be->id = id;
+}
+EXPORT_SYMBOL(dpu_bliteng_set_id);
+
+void dpu_bliteng_set_dev(struct dpu_bliteng *dpu_be, struct device *dev)
+{
+	dpu_be->dev = dev;
+}
+EXPORT_SYMBOL(dpu_bliteng_set_dev);
+
+int dpu_be_get(struct dpu_bliteng *dpu_be)
+{
+	mutex_lock(&dpu_be->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(dpu_be_get);
+
+void dpu_be_put(struct dpu_bliteng *dpu_be)
+{
+	mutex_unlock(&dpu_be->mutex);
+}
+EXPORT_SYMBOL(dpu_be_put);
+
+int dpu_be_blit(struct dpu_bliteng *dpu_be,
+	u32 *cmdlist, u32 cmdnum)
+{
+	int i;
+
+	if (cmdnum > CMDSEQ_FIFO_SPACE_THRESHOLD) {
+		dev_err(dpu_be->dev, "dpu blit cmdnum[%d] should be less than %d !\n",
+			cmdnum, CMDSEQ_FIFO_SPACE_THRESHOLD);
+		return -EINVAL;
+	}
+	dpu_cs_wait_fifo_space(dpu_be);
+
+	for (i = 0; i < cmdnum; i++)
+		dpu_be_write(dpu_be, cmdlist[i], CMDSEQ_HIF);
+
+	return 0;
+}
+EXPORT_SYMBOL(dpu_be_blit);
+
+#define STORE9_SEQCOMPLETE_IRQ		2U
+#define STORE9_SEQCOMPLETE_IRQ_MASK	(1U<<STORE9_SEQCOMPLETE_IRQ)
+void dpu_be_wait(struct dpu_bliteng *dpu_be)
+{
+	if (!dpu_be->sync) return;
+
+	dpu_cs_wait_fifo_space(dpu_be);
+
+	dpu_be_write(dpu_be, 0x14000001, CMDSEQ_HIF);
+	dpu_be_write(dpu_be, PIXENGCFG_STORE9_TRIGGER, CMDSEQ_HIF);
+	dpu_be_write(dpu_be, 0x10, CMDSEQ_HIF);
+
+	while ((dpu_be_read(dpu_be, COMCTRL_INTERRUPTSTATUS0) &
+		STORE9_SEQCOMPLETE_IRQ_MASK) == 0)
+		usleep_range(30, 50);
+
+	dpu_be_write(dpu_be, STORE9_SEQCOMPLETE_IRQ_MASK,
+		COMCTRL_INTERRUPTCLEAR0);
+
+	dpu_be->sync = false;
+}
+EXPORT_SYMBOL(dpu_be_wait);
+
+static void dpu_be_init_units(struct dpu_bliteng *dpu_be)
+{
+	u32 staticcontrol;
+	u32 pixengcfg_unit_dynamic;
+
+	staticcontrol =
+	1 << FETCHDECODE9_STATICCONTROL_SHDEN_SHIFT |
+	0 << FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+	FETCHDECODE9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, FETCHDECODE9_STATICCONTROL);
+
+	staticcontrol =
+	1 << FETCHWARP9_STATICCONTROL_SHDEN_SHIFT |
+	0 << FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+	FETCHWARP9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, FETCHWARP9_STATICCONTROL);
+
+	staticcontrol =
+	1 << FETCHECO9_STATICCONTROL_SHDEN_SHIFT |
+	0 << FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+	FETCHECO9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, FETCHECO9_STATICCONTROL);
+
+	staticcontrol =
+	1 << HSCALER9_STATICCONTROL_SHDEN_SHIFT |
+	HSCALER9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, HSCALER9_STATICCONTROL);
+
+	staticcontrol =
+	1 << VSCALER9_STATICCONTROL_SHDEN_SHIFT |
+	VSCALER9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, VSCALER9_STATICCONTROL);
+
+	staticcontrol =
+	1 << ROP9_STATICCONTROL_SHDEN_SHIFT |
+	ROP9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, ROP9_STATICCONTROL);
+
+	staticcontrol =
+	1 << MATRIX9_STATICCONTROL_SHDEN_SHIFT |
+	MATRIX9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, MATRIX9_STATICCONTROL);
+
+	staticcontrol =
+	1 << BLITBLEND9_STATICCONTROL_SHDEN_SHIFT |
+	BLITBLEND9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, BLITBLEND9_STATICCONTROL);
+
+	staticcontrol =
+	1 << STORE9_STATICCONTROL_SHDEN_SHIFT |
+	0 << STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+	STORE9_STATICCONTROL_RESET_VALUE;
+	dpu_be_write(dpu_be, staticcontrol, STORE9_STATICCONTROL);
+
+	/* Safety_Pixengcfg Dynamic */
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_FETCHDECODE9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_FETCHDECODE9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_FETCHWARP9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_FETCHWARP9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_ROP9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_ROP9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_MATRIX9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_MATRIX9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_HSCALER9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_HSCALER9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_VSCALER9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_VSCALER9_DYNAMIC);
+
+	pixengcfg_unit_dynamic =
+	PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+	PIXENGCFG_BLITBLEND9_DYNAMIC_RESET_VALUE;
+	dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+		PIXENGCFG_BLITBLEND9_DYNAMIC);
+}
+
+int dpu_bliteng_init(struct dpu_bliteng *dpu_bliteng)
+{
+	struct dpu_soc *dpu = dev_get_drvdata(dpu_bliteng->dev->parent);
+	struct platform_device *dpu_pdev =
+		container_of(dpu->dev, struct platform_device, dev);
+	struct resource *res;
+	unsigned long dpu_base;
+	void __iomem *base;
+	u32 *cmd_list;
+	int ret;
+
+	cmd_list = kzalloc(sizeof(*cmd_list) * CMDSEQ_FIFO_SPACE_THRESHOLD,
+			GFP_KERNEL);
+	if (!cmd_list)
+		return -ENOMEM;
+	dpu_bliteng->cmd_list = cmd_list;
+
+	res = platform_get_resource(dpu_pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	dpu_base = res->start;
+
+	/* remap with bigger size */
+	base = devm_ioremap(dpu->dev, dpu_base, 64*SZ_1K);
+	dpu_bliteng->base = base;
+	dpu_bliteng->dpu = dpu;
+
+	mutex_init(&dpu_bliteng->mutex);
+
+	/* Init the uints used by blit engine */
+	/* Maybe this should be in dpu-common.c */
+	dpu_be_init_units(dpu_bliteng);
+
+	/* Init for command sequencer */
+	ret = dpu_cs_alloc_command_buffer(dpu_bliteng);
+	if (ret)
+		return ret;
+
+	dpu_cs_static_setup(dpu_bliteng);
+
+	/* DPR, each blit engine has two dprc, 0 & 1 */
+	dpu_bliteng->dprc[0] = dpu_be_dprc_get(dpu, 0);
+	dpu_bliteng->dprc[1] = dpu_be_dprc_get(dpu, 1);
+
+	dprc_disable(dpu_bliteng->dprc[0]);
+	dprc_disable(dpu_bliteng->dprc[1]);
+
+	dpu_bliteng->start = true;
+	dpu_bliteng->sync = false;
+
+	dpu_bliteng->modifier = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dpu_bliteng_init);
+
+void dpu_bliteng_fini(struct dpu_bliteng *dpu_bliteng)
+{
+	/* LockUnlock and LockUnlockHIF */
+	dpu_be_write(dpu_bliteng, CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__LOCK_KEY,
+		CMDSEQ_LOCKUNLOCKHIF);
+	dpu_be_write(dpu_bliteng, CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__LOCK_KEY,
+		CMDSEQ_LOCKUNLOCK);
+
+	kfree(dpu_bliteng->cmd_list);
+
+	if (dpu_bliteng->buffer_addr_virt)
+		free_pages_exact(dpu_bliteng->buffer_addr_virt,
+				 COMMAND_BUFFER_SIZE);
+}
+EXPORT_SYMBOL_GPL(dpu_bliteng_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DPU BLITENG");
+MODULE_ALIAS("platform:imx-dpu-bliteng");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu-blit/dpu-blit.h
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu-blit/dpu-blit.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __DPU_BLIT_H__
+#define __DPU_BLIT_H__
+
+#define COMMAND_BUFFER_SIZE	65536 /* up to 64k bytes */
+#define CMDSEQ_FIFO_SPACE_THRESHOLD   192
+#define WORD_SIZE   4
+
+struct dpu_bliteng {
+	struct device		*dev;
+	void __iomem *base;
+	s32 id;
+	struct mutex mutex;
+	s32 irq_store9_shdload;
+	s32 irq_store9_framecomplete;
+	s32 irq_store9_seqcomplete;
+
+	void *buffer_addr_virt;
+	u32 buffer_addr_phy;
+
+	u32 *cmd_list;
+
+	struct dpu_soc *dpu;
+
+	struct dprc *dprc[2];
+
+	bool start;
+	bool sync;
+
+	u64 modifier;
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/Kconfig
@@ -0,0 +1,8 @@
+config IMX_DPU_CORE
+	tristate "i.MX DPU core support"
+	depends on ARCH_MXC
+	select GENERIC_IRQ_CHIP
+	help
+	  Choose this if you have a Freescale i.MX8QM or i.MX8QXP system and
+	  want to use the Display Processing Unit. This option only enables
+	  DPU base support.
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/Makefile
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_IMX_DPU_CORE) += imx-dpu-core.o
+
+imx-dpu-core-objs := dpu-common.o dpu-constframe.o dpu-disengcfg.o \
+		     dpu-extdst.o dpu-fetchdecode.o dpu-fetcheco.o \
+		     dpu-fetchlayer.o dpu-fetchwarp.o dpu-fetchunit.o \
+		     dpu-framegen.o dpu-hscaler.o dpu-layerblend.o \
+		     dpu-sc-misc.o dpu-signature.o dpu-store.o dpu-tcon.o \
+		     dpu-vscaler.o
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-common.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-common.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/clk.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <video/dpu.h>
+#include <video/imx8-pc.h>
+#include <video/imx8-prefetch.h>
+#include "dpu-prv.h"
+
+#define IMX_DPU_BLITENG_NAME "imx-drm-dpu-bliteng"
+
+static bool display_plane_video_proc = true;
+module_param(display_plane_video_proc, bool, 0444);
+MODULE_PARM_DESC(display_plane_video_proc,
+		 "Enable video processing for display [default=true]");
+
+#define DPU_CM_REG_DEFINE1(name1, name2)		\
+static inline u32 name1(const struct cm_reg_ofs *ofs)	\
+{							\
+	return ofs->name2;				\
+}
+
+#define DPU_CM_REG_DEFINE2(name1, name2)		\
+static inline u32 name1(const struct cm_reg_ofs *ofs,	\
+			unsigned int n)			\
+{							\
+	return ofs->name2 + (4 * n);			\
+}
+
+DPU_CM_REG_DEFINE1(LOCKUNLOCK, lockunlock);
+DPU_CM_REG_DEFINE1(LOCKSTATUS, lockstatus);
+DPU_CM_REG_DEFINE2(USERINTERRUPTMASK, userinterruptmask);
+DPU_CM_REG_DEFINE2(INTERRUPTENABLE, interruptenable);
+DPU_CM_REG_DEFINE2(INTERRUPTPRESET, interruptpreset);
+DPU_CM_REG_DEFINE2(INTERRUPTCLEAR, interruptclear);
+DPU_CM_REG_DEFINE2(INTERRUPTSTATUS, interruptstatus);
+DPU_CM_REG_DEFINE2(USERINTERRUPTENABLE, userinterruptenable);
+DPU_CM_REG_DEFINE2(USERINTERRUPTPRESET, userinterruptpreset);
+DPU_CM_REG_DEFINE2(USERINTERRUPTCLEAR, userinterruptclear);
+DPU_CM_REG_DEFINE2(USERINTERRUPTSTATUS, userinterruptstatus);
+DPU_CM_REG_DEFINE1(GENERALPURPOSE, generalpurpose);
+
+static inline u32 dpu_cm_read(struct dpu_soc *dpu, unsigned int offset)
+{
+	return readl(dpu->cm_reg + offset);
+}
+
+static inline void dpu_cm_write(struct dpu_soc *dpu,
+				unsigned int offset, u32 value)
+{
+	writel(value, dpu->cm_reg + offset);
+}
+
+/* Constant Frame Unit */
+static const unsigned long cf_ofss[] = {0x4400, 0x5400, 0x4c00, 0x5c00};
+static const unsigned long cf_pec_ofss[] = {0x960, 0x9e0, 0x9a0, 0xa20};
+
+/* Display Engine Configuration Unit */
+static const unsigned long dec_ofss[] = {0xb400, 0xb420};
+
+/* External Destination Unit */
+static const unsigned long ed_ofss[] = {0x4800, 0x5800, 0x5000, 0x6000};
+static const unsigned long ed_pec_ofss[] = {0x980, 0xa00, 0x9c0, 0xa40};
+
+/* Fetch Decode Unit */
+static const unsigned long fd_ofss[] = {0x6c00, 0x7800};
+static const unsigned long fd_pec_ofss[] = {0xa80, 0xaa0};
+
+/* Fetch ECO Unit */
+static const unsigned long fe_ofss[] = {0x7400, 0x8000, 0x6800, 0x1c00};
+static const unsigned long fe_pec_ofss[] = {0xa90, 0xab0, 0xa70, 0x850};
+
+/* Frame Generator Unit */
+static const unsigned long fg_ofss[] = {0xb800, 0xd400};
+
+/* Fetch Layer Unit */
+static const unsigned long fl_ofss[] = {0x8400};
+static const unsigned long fl_pec_ofss[] = {0xac0};
+
+/* Fetch Warp Unit */
+static const unsigned long fw_ofss[] = {0x6400};
+static const unsigned long fw_pec_ofss[] = {0xa60};
+
+/* Horizontal Scaler Unit */
+static const unsigned long hs_ofss[] = {0x9000, 0x9c00, 0x3000};
+static const unsigned long hs_pec_ofss[] = {0xb00, 0xb60, 0x8c0};
+
+/* Layer Blend Unit */
+static const unsigned long lb_ofss[] = {0xa400, 0xa800, 0xac00, 0xb000};
+static const unsigned long lb_pec_ofss[] = {0xba0, 0xbc0, 0xbe0, 0xc00};
+
+/* Signature Unit */
+static const unsigned long sig_ofss[] = {0xd000, 0xec00};
+
+/* Store Unit */
+static const unsigned long st_ofss[] = {0x4000};
+static const unsigned long st_pec_ofss[] = {0x940};
+
+/* Timing Controller Unit */
+static const unsigned long tcon_ofss[] = {0xcc00, 0xe800};
+
+/* Vertical Scaler Unit */
+static const unsigned long vs_ofss[] = {0x9400, 0xa000, 0x3400};
+static const unsigned long vs_pec_ofss[] = {0xb20, 0xb80, 0x8e0};
+
+static const struct dpu_unit _cfs = {
+	.name = "ConstFrame",
+	.num = ARRAY_SIZE(cf_ids),
+	.ids = cf_ids,
+	.pec_ofss = cf_pec_ofss,
+	.ofss = cf_ofss,
+};
+
+static const struct dpu_unit _decs = {
+	.name = "DisEngCfg",
+	.num = ARRAY_SIZE(dec_ids),
+	.ids = dec_ids,
+	.pec_ofss = NULL,
+	.ofss = dec_ofss,
+};
+
+static const struct dpu_unit _eds = {
+	.name = "ExtDst",
+	.num = ARRAY_SIZE(ed_ids),
+	.ids = ed_ids,
+	.pec_ofss = ed_pec_ofss,
+	.ofss = ed_ofss,
+};
+
+static const struct dpu_unit _fds = {
+	.name = "FetchDecode",
+	.num = ARRAY_SIZE(fd_ids),
+	.ids = fd_ids,
+	.pec_ofss = fd_pec_ofss,
+	.ofss = fd_ofss,
+	.dprc_ids = fd_dprc_ids,
+};
+
+static const struct dpu_unit _fes = {
+	.name = "FetchECO",
+	.num = ARRAY_SIZE(fe_ids),
+	.ids = fe_ids,
+	.pec_ofss = fe_pec_ofss,
+	.ofss = fe_ofss,
+};
+
+static const struct dpu_unit _fgs = {
+	.name = "FrameGen",
+	.num = ARRAY_SIZE(fg_ids),
+	.ids = fg_ids,
+	.pec_ofss = NULL,
+	.ofss = fg_ofss,
+};
+
+static const struct dpu_unit _fls = {
+	.name = "FetchLayer",
+	.num = ARRAY_SIZE(fl_ids),
+	.ids = fl_ids,
+	.pec_ofss = fl_pec_ofss,
+	.ofss = fl_ofss,
+	.dprc_ids = fl_dprc_ids,
+};
+
+static const struct dpu_unit _fws = {
+	.name = "FetchWarp",
+	.num = ARRAY_SIZE(fw_ids),
+	.ids = fw_ids,
+	.pec_ofss = fw_pec_ofss,
+	.ofss = fw_ofss,
+	.dprc_ids = fw_dprc_ids,
+};
+
+static const struct dpu_unit _hss = {
+	.name = "HScaler",
+	.num = ARRAY_SIZE(hs_ids),
+	.ids = hs_ids,
+	.pec_ofss = hs_pec_ofss,
+	.ofss = hs_ofss,
+};
+
+static const struct dpu_unit _lbs = {
+	.name = "LayerBlend",
+	.num = ARRAY_SIZE(lb_ids),
+	.ids = lb_ids,
+	.pec_ofss = lb_pec_ofss,
+	.ofss = lb_ofss,
+};
+
+static const struct dpu_unit _sigs = {
+	.name = "Signature",
+	.num = ARRAY_SIZE(sig_ids),
+	.ids = sig_ids,
+	.pec_ofss = NULL,
+	.ofss = sig_ofss,
+};
+
+static const struct dpu_unit _sts = {
+	.name = "Store",
+	.num = ARRAY_SIZE(st_ids),
+	.ids = st_ids,
+	.pec_ofss = st_pec_ofss,
+	.ofss = st_ofss,
+};
+
+static const struct dpu_unit _tcons = {
+	.name = "TCon",
+	.num = ARRAY_SIZE(tcon_ids),
+	.ids = tcon_ids,
+	.pec_ofss = NULL,
+	.ofss = tcon_ofss,
+};
+
+static const struct dpu_unit _vss = {
+	.name = "VScaler",
+	.num = ARRAY_SIZE(vs_ids),
+	.ids = vs_ids,
+	.pec_ofss = vs_pec_ofss,
+	.ofss = vs_ofss,
+};
+
+static const struct cm_reg_ofs _cm_reg_ofs = {
+	.ipidentifier = 0,
+	.lockunlock = 0x40,
+	.lockstatus = 0x44,
+	.userinterruptmask = 0x48,
+	.interruptenable = 0x50,
+	.interruptpreset = 0x58,
+	.interruptclear = 0x60,
+	.interruptstatus = 0x68,
+	.userinterruptenable = 0x80,
+	.userinterruptpreset = 0x88,
+	.userinterruptclear = 0x90,
+	.userinterruptstatus = 0x98,
+	.generalpurpose = 0x100,
+};
+
+static const unsigned long unused_irq[] = {0x00000000, 0xfffe0008};
+
+static const struct dpu_data dpu_data_qxp = {
+	.cm_ofs = 0x0,
+	.cfs = &_cfs,
+	.decs = &_decs,
+	.eds = &_eds,
+	.fds = &_fds,
+	.fes = &_fes,
+	.fgs = &_fgs,
+	.fls = &_fls,
+	.fws = &_fws,
+	.hss = &_hss,
+	.lbs = &_lbs,
+	.sigs = &_sigs,
+	.sts = &_sts,
+	.tcons = &_tcons,
+	.vss = &_vss,
+	.cm_reg_ofs = &_cm_reg_ofs,
+	.unused_irq = unused_irq,
+	.plane_src_mask = DPU_PLANE_SRC_FL0_ID | DPU_PLANE_SRC_FW2_ID |
+			  DPU_PLANE_SRC_FD0_ID | DPU_PLANE_SRC_FD1_ID,
+	.has_dual_ldb = true,
+	.syncmode_min_prate = UINT_MAX,	/* pc is unused */
+	.singlemode_max_width = UINT_MAX, 	/* pc is unused */
+};
+
+static const struct dpu_data dpu_data_qm = {
+	.cm_ofs = 0x0,
+	.cfs = &_cfs,
+	.decs = &_decs,
+	.eds = &_eds,
+	.fds = &_fds,
+	.fes = &_fes,
+	.fgs = &_fgs,
+	.fls = &_fls,
+	.fws = &_fws,
+	.hss = &_hss,
+	.lbs = &_lbs,
+	.sigs = &_sigs,
+	.sts = &_sts,
+	.tcons = &_tcons,
+	.vss = &_vss,
+	.cm_reg_ofs = &_cm_reg_ofs,
+	.unused_irq = unused_irq,
+	.plane_src_mask = DPU_PLANE_SRC_FL0_ID | DPU_PLANE_SRC_FW2_ID |
+			  DPU_PLANE_SRC_FD0_ID | DPU_PLANE_SRC_FD1_ID,
+	.has_dual_ldb = false,
+	.syncmode_min_prate = 300000,
+	.singlemode_max_width = 2560,
+	.master_stream_id = 1,
+};
+
+static const struct of_device_id dpu_dt_ids[] = {
+	{
+		.compatible = "fsl,imx8qxp-dpu",
+		.data = &dpu_data_qxp,
+	}, {
+		.compatible = "fsl,imx8qm-dpu",
+		.data = &dpu_data_qm,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, dpu_dt_ids);
+
+unsigned int dpu_get_syncmode_min_prate(struct dpu_soc *dpu)
+{
+	return dpu->data->syncmode_min_prate;
+}
+EXPORT_SYMBOL_GPL(dpu_get_syncmode_min_prate);
+
+unsigned int dpu_get_singlemode_max_width(struct dpu_soc *dpu)
+{
+	return dpu->data->singlemode_max_width;
+}
+EXPORT_SYMBOL_GPL(dpu_get_singlemode_max_width);
+
+unsigned int dpu_get_master_stream_id(struct dpu_soc *dpu)
+{
+	return dpu->data->master_stream_id;
+}
+EXPORT_SYMBOL_GPL(dpu_get_master_stream_id);
+
+bool dpu_vproc_has_fetcheco_cap(u32 cap_mask)
+{
+	return !!(cap_mask & DPU_VPROC_CAP_FETCHECO);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_fetcheco_cap);
+
+bool dpu_vproc_has_hscale_cap(u32 cap_mask)
+{
+	return !!(cap_mask & DPU_VPROC_CAP_HSCALE);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_hscale_cap);
+
+bool dpu_vproc_has_vscale_cap(u32 cap_mask)
+{
+	return !!(cap_mask & DPU_VPROC_CAP_VSCALE);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_vscale_cap);
+
+u32 dpu_vproc_get_fetcheco_cap(u32 cap_mask)
+{
+	return cap_mask & DPU_VPROC_CAP_FETCHECO;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_fetcheco_cap);
+
+u32 dpu_vproc_get_hscale_cap(u32 cap_mask)
+{
+	return cap_mask & DPU_VPROC_CAP_HSCALE;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_hscale_cap);
+
+u32 dpu_vproc_get_vscale_cap(u32 cap_mask)
+{
+	return cap_mask & DPU_VPROC_CAP_VSCALE;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_vscale_cap);
+
+int dpu_format_horz_chroma_subsampling(u32 format)
+{
+	switch (format) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
+int dpu_format_vert_chroma_subsampling(u32 format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
+int dpu_format_num_planes(u32 format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+	case DRM_FORMAT_NV24:
+	case DRM_FORMAT_NV42:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
+int dpu_format_plane_width(int width, u32 format, int plane)
+{
+	if (plane >= dpu_format_num_planes(format))
+		return 0;
+
+	if (plane == 0)
+		return width;
+
+	return width / dpu_format_horz_chroma_subsampling(format);
+}
+
+int dpu_format_plane_height(int height, u32 format, int plane)
+{
+	if (plane >= dpu_format_num_planes(format))
+		return 0;
+
+	if (plane == 0)
+		return height;
+
+	return height / dpu_format_vert_chroma_subsampling(format);
+}
+
+static void dpu_detach_pm_domains(struct dpu_soc *dpu)
+{
+	if (dpu->pd_pll1_link && !IS_ERR(dpu->pd_pll1_link))
+		device_link_del(dpu->pd_pll1_link);
+	if (dpu->pd_pll1_dev && !IS_ERR(dpu->pd_pll1_dev))
+		dev_pm_domain_detach(dpu->pd_pll1_dev, true);
+
+	if (dpu->pd_pll0_link && !IS_ERR(dpu->pd_pll0_link))
+		device_link_del(dpu->pd_pll0_link);
+	if (dpu->pd_pll0_dev && !IS_ERR(dpu->pd_pll0_dev))
+		dev_pm_domain_detach(dpu->pd_pll0_dev, true);
+
+	if (dpu->pd_dc_link && !IS_ERR(dpu->pd_dc_link))
+		device_link_del(dpu->pd_dc_link);
+	if (dpu->pd_dc_dev && !IS_ERR(dpu->pd_dc_dev))
+		dev_pm_domain_detach(dpu->pd_dc_dev, true);
+
+	dpu->pd_dc_dev = NULL;
+	dpu->pd_dc_link = NULL;
+	dpu->pd_pll0_dev = NULL;
+	dpu->pd_pll0_link = NULL;
+	dpu->pd_pll1_dev = NULL;
+	dpu->pd_pll1_link = NULL;
+}
+
+static int dpu_attach_pm_domains(struct dpu_soc *dpu)
+{
+	struct device *dev = dpu->dev;
+	u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
+	int ret = 0;
+
+	dpu->pd_dc_dev = dev_pm_domain_attach_by_name(dev, "dc");
+	if (IS_ERR(dpu->pd_dc_dev)) {
+		ret = PTR_ERR(dpu->pd_dc_dev);
+		dev_err(dev, "Failed to attach dc pd dev: %d\n", ret);
+		goto fail;
+	}
+	dpu->pd_dc_link = device_link_add(dev, dpu->pd_dc_dev, flags);
+	if (IS_ERR(dpu->pd_dc_link)) {
+		ret = PTR_ERR(dpu->pd_dc_link);
+		dev_err(dev, "Failed to add device link to dc pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	dpu->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
+	if (IS_ERR(dpu->pd_pll0_dev)) {
+		ret = PTR_ERR(dpu->pd_pll0_dev);
+		dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+		goto fail;
+	}
+	dpu->pd_pll0_link = device_link_add(dev, dpu->pd_pll0_dev, flags);
+	if (IS_ERR(dpu->pd_pll0_link)) {
+		ret = PTR_ERR(dpu->pd_pll0_link);
+		dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	dpu->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
+	if (IS_ERR(dpu->pd_pll1_dev)) {
+		ret = PTR_ERR(dpu->pd_pll1_dev);
+		dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
+		goto fail;
+	}
+	dpu->pd_pll1_link = device_link_add(dev, dpu->pd_pll1_dev, flags);
+	if (IS_ERR(dpu->pd_pll1_link)) {
+		ret = PTR_ERR(dpu->pd_pll1_link);
+		dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n",
+			ret);
+		goto fail;
+	}
+
+	return ret;
+fail:
+	dpu_detach_pm_domains(dpu);
+	return ret;
+}
+
+#define DPU_UNITS_ADDR_DBG(unit)					\
+{									\
+	const struct dpu_unit *us = data->unit##s;			\
+	int i;								\
+	for (i = 0; i < us->num; i++) {					\
+		if (us->pec_ofss) {					\
+			dev_dbg(&pdev->dev, "%s%d: pixengcfg @ 0x%08lx,"\
+				" unit @ 0x%08lx\n", us->name,		\
+				us->ids[i],				\
+				dpu_base + us->pec_ofss[i],		\
+				dpu_base + us->ofss[i]);		\
+		} else {						\
+			dev_dbg(&pdev->dev,				\
+				"%s%d: unit @ 0x%08lx\n", us->name,	\
+				us->ids[i], dpu_base + us->ofss[i]);	\
+		}							\
+	}								\
+}
+
+static void dpu_units_addr_dbg(struct dpu_soc *dpu,
+			struct platform_device *pdev, unsigned long dpu_base)
+{
+	const struct dpu_data *data = dpu->data;
+
+	dev_dbg(dpu->dev, "Common: 0x%08lx\n", dpu_base + data->cm_ofs);
+	DPU_UNITS_ADDR_DBG(cf);
+	DPU_UNITS_ADDR_DBG(dec);
+	DPU_UNITS_ADDR_DBG(ed);
+	DPU_UNITS_ADDR_DBG(fd);
+	DPU_UNITS_ADDR_DBG(fe);
+	DPU_UNITS_ADDR_DBG(fg);
+	DPU_UNITS_ADDR_DBG(fl);
+	DPU_UNITS_ADDR_DBG(fw);
+	DPU_UNITS_ADDR_DBG(hs);
+	DPU_UNITS_ADDR_DBG(lb);
+	DPU_UNITS_ADDR_DBG(sig);
+	DPU_UNITS_ADDR_DBG(st);
+	DPU_UNITS_ADDR_DBG(tcon);
+	DPU_UNITS_ADDR_DBG(vs);
+}
+
+static int dpu_get_irq(struct platform_device *pdev, struct dpu_soc *dpu)
+{
+#define DPU_GET_IRQ(name)						\
+{									\
+	dpu->irq_##name = platform_get_irq_byname(pdev, "" #name "");	\
+	dev_dbg(dpu->dev, "irq_" #name ": %d\n", dpu->irq_##name);	\
+	if (dpu->irq_##name < 0) {					\
+		dev_err(dpu->dev, "failed to get irq " #name "\n");	\
+		return dpu->irq_##name;					\
+	}								\
+}
+
+	DPU_GET_IRQ(extdst0_shdload);
+	DPU_GET_IRQ(extdst4_shdload);
+	DPU_GET_IRQ(extdst1_shdload);
+	DPU_GET_IRQ(extdst5_shdload);
+	DPU_GET_IRQ(disengcfg_shdload0);
+	DPU_GET_IRQ(disengcfg_framecomplete0);
+	DPU_GET_IRQ(sig0_shdload);
+	DPU_GET_IRQ(sig0_valid);
+	DPU_GET_IRQ(disengcfg_shdload1);
+	DPU_GET_IRQ(disengcfg_framecomplete1);
+	DPU_GET_IRQ(sig1_shdload);
+	DPU_GET_IRQ(sig1_valid);
+
+	return 0;
+}
+
+static void dpu_irq_handle(struct irq_desc *desc, enum dpu_irq irq)
+{
+	struct dpu_soc *dpu = irq_desc_get_handler_data(desc);
+	const struct dpu_data *data = dpu->data;
+	const struct cm_reg_ofs *ofs = data->cm_reg_ofs;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int virq;
+	u32 status;
+
+	chained_irq_enter(chip, desc);
+
+	status = dpu_cm_read(dpu, USERINTERRUPTSTATUS(ofs, irq / 32));
+	status &= dpu_cm_read(dpu, USERINTERRUPTENABLE(ofs, irq / 32));
+
+	if (status & BIT(irq % 32)) {
+		virq = irq_linear_revmap(dpu->domain, irq);
+		if (virq)
+			generic_handle_irq(virq);
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+#define DPU_IRQ_HANDLER_DEFINE(name1, name2)			\
+static void dpu_##name1##_irq_handler(struct irq_desc *desc)	\
+{								\
+	dpu_irq_handle(desc, IRQ_##name2);			\
+}
+
+DPU_IRQ_HANDLER_DEFINE(extdst0_shdload, EXTDST0_SHDLOAD)
+DPU_IRQ_HANDLER_DEFINE(extdst4_shdload, EXTDST4_SHDLOAD)
+DPU_IRQ_HANDLER_DEFINE(extdst1_shdload, EXTDST1_SHDLOAD)
+DPU_IRQ_HANDLER_DEFINE(extdst5_shdload, EXTDST5_SHDLOAD)
+DPU_IRQ_HANDLER_DEFINE(disengcfg_shdload0, DISENGCFG_SHDLOAD0)
+DPU_IRQ_HANDLER_DEFINE(disengcfg_framecomplete0, DISENGCFG_FRAMECOMPLETE0)
+DPU_IRQ_HANDLER_DEFINE(sig0_shdload, SIG0_SHDLOAD);
+DPU_IRQ_HANDLER_DEFINE(sig0_valid, SIG0_VALID);
+DPU_IRQ_HANDLER_DEFINE(disengcfg_shdload1, DISENGCFG_SHDLOAD1)
+DPU_IRQ_HANDLER_DEFINE(disengcfg_framecomplete1, DISENGCFG_FRAMECOMPLETE1)
+DPU_IRQ_HANDLER_DEFINE(sig1_shdload, SIG1_SHDLOAD);
+DPU_IRQ_HANDLER_DEFINE(sig1_valid, SIG1_VALID);
+
+int dpu_map_irq(struct dpu_soc *dpu, int irq)
+{
+	int virq = irq_linear_revmap(dpu->domain, irq);
+
+	if (!virq)
+		virq = irq_create_mapping(dpu->domain, irq);
+
+	return virq;
+}
+EXPORT_SYMBOL_GPL(dpu_map_irq);
+
+static int dpu_irq_init(struct dpu_soc *dpu)
+{
+	const struct dpu_data *data = dpu->data;
+	const struct cm_reg_ofs *ofs = data->cm_reg_ofs;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	int ret, i;
+
+	dpu->domain = irq_domain_add_linear(dpu->dev->of_node,
+					    dpu->irq_line_num,
+					    &irq_generic_chip_ops, dpu);
+	if (!dpu->domain) {
+		dev_err(dpu->dev, "failed to add irq domain\n");
+		return -ENODEV;
+	}
+
+	ret = irq_alloc_domain_generic_chips(dpu->domain, 32, 1, "DPU",
+					     handle_level_irq, 0, 0, 0);
+	if (ret < 0) {
+		dev_err(dpu->dev, "failed to alloc generic irq chips\n");
+		irq_domain_remove(dpu->domain);
+		return ret;
+	}
+
+	for (i = 0; i < dpu->irq_line_num; i += 32) {
+		/* Mask and clear all interrupts */
+		dpu_cm_write(dpu, USERINTERRUPTENABLE(ofs, i / 32), 0);
+		dpu_cm_write(dpu, USERINTERRUPTCLEAR(ofs, i / 32),
+					~data->unused_irq[i / 32]);
+		dpu_cm_write(dpu, INTERRUPTENABLE(ofs, i / 32), 0);
+		dpu_cm_write(dpu, INTERRUPTCLEAR(ofs, i / 32),
+					~data->unused_irq[i / 32]);
+
+		/* Set all interrupts to user mode */
+		dpu_cm_write(dpu, USERINTERRUPTMASK(ofs, i / 32),
+					~data->unused_irq[i / 32]);
+
+		gc = irq_get_domain_generic_chip(dpu->domain, i);
+		gc->reg_base = dpu->cm_reg;
+		gc->unused = data->unused_irq[i / 32];
+		ct = gc->chip_types;
+		ct->chip.irq_ack = irq_gc_ack_set_bit;
+		ct->chip.irq_mask = irq_gc_mask_clr_bit;
+		ct->chip.irq_unmask = irq_gc_mask_set_bit;
+		ct->regs.ack = USERINTERRUPTCLEAR(ofs, i / 32);
+		ct->regs.mask = USERINTERRUPTENABLE(ofs, i / 32);
+	}
+
+#define DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(name)	\
+irq_set_chained_handler_and_data(dpu->irq_##name, dpu_##name##_irq_handler, dpu)
+
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(extdst0_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(extdst4_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(extdst1_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(extdst5_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(disengcfg_shdload0);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(disengcfg_framecomplete0);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(sig0_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(sig0_valid);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(disengcfg_shdload1);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(disengcfg_framecomplete1);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(sig1_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA1(sig1_valid);
+
+#define DPU_IRQ_CHIP_PM_GET(name)					\
+{									\
+	ret = irq_chip_pm_get(irq_get_irq_data(dpu->irq_##name));	\
+	if (ret < 0) {							\
+		dev_err(dpu->dev,					\
+			"failed to get irq chip PM for irq%d %d\n",	\
+						dpu->irq_##name, ret);	\
+		goto pm_get_rollback;					\
+	}								\
+	dpu->irq_chip_pm_get_##name = true;				\
+}
+
+#define DPU_IRQ_CHIP_PM_PUT_CHECK(name)					\
+{									\
+	if (dpu->irq_chip_pm_get_##name) {				\
+		irq_chip_pm_put(irq_get_irq_data(dpu->irq_##name));	\
+		dpu->irq_chip_pm_get_##name = false;			\
+	}								\
+}
+
+	DPU_IRQ_CHIP_PM_GET(extdst0_shdload);
+	DPU_IRQ_CHIP_PM_GET(extdst4_shdload);
+	DPU_IRQ_CHIP_PM_GET(extdst1_shdload);
+	DPU_IRQ_CHIP_PM_GET(extdst5_shdload);
+	DPU_IRQ_CHIP_PM_GET(disengcfg_shdload0);
+	DPU_IRQ_CHIP_PM_GET(disengcfg_framecomplete0);
+	DPU_IRQ_CHIP_PM_GET(sig0_shdload);
+	DPU_IRQ_CHIP_PM_GET(sig0_valid);
+	DPU_IRQ_CHIP_PM_GET(disengcfg_shdload1);
+	DPU_IRQ_CHIP_PM_GET(disengcfg_framecomplete1);
+	DPU_IRQ_CHIP_PM_GET(sig1_shdload);
+	DPU_IRQ_CHIP_PM_GET(sig1_valid);
+
+	return 0;
+
+pm_get_rollback:
+	DPU_IRQ_CHIP_PM_PUT_CHECK(extdst0_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(extdst4_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(extdst1_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(extdst5_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(disengcfg_shdload0);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(disengcfg_framecomplete0);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(sig0_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(sig0_valid);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(disengcfg_shdload1);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(disengcfg_framecomplete1);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(sig1_shdload);
+	DPU_IRQ_CHIP_PM_PUT_CHECK(sig1_valid);
+
+	return ret;
+}
+
+static void dpu_irq_exit(struct dpu_soc *dpu)
+{
+	unsigned int i, irq;
+
+#define DPU_IRQ_CHIP_PM_PUT(name)				\
+{								\
+	irq_chip_pm_put(irq_get_irq_data(dpu->irq_##name));	\
+	dpu->irq_chip_pm_get_##name = false;			\
+}
+
+	DPU_IRQ_CHIP_PM_PUT(extdst0_shdload);
+	DPU_IRQ_CHIP_PM_PUT(extdst4_shdload);
+	DPU_IRQ_CHIP_PM_PUT(extdst1_shdload);
+	DPU_IRQ_CHIP_PM_PUT(extdst5_shdload);
+	DPU_IRQ_CHIP_PM_PUT(disengcfg_shdload0);
+	DPU_IRQ_CHIP_PM_PUT(disengcfg_framecomplete0);
+	DPU_IRQ_CHIP_PM_PUT(sig0_shdload);
+	DPU_IRQ_CHIP_PM_PUT(sig0_valid);
+	DPU_IRQ_CHIP_PM_PUT(disengcfg_shdload1);
+	DPU_IRQ_CHIP_PM_PUT(disengcfg_framecomplete1);
+	DPU_IRQ_CHIP_PM_PUT(sig1_shdload);
+	DPU_IRQ_CHIP_PM_PUT(sig1_valid);
+
+#define DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(name)	\
+irq_set_chained_handler_and_data(dpu->irq_##name, NULL, NULL)
+
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(extdst0_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(extdst4_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(extdst1_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(extdst5_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(disengcfg_shdload0);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(disengcfg_framecomplete0);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(sig0_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(sig0_valid);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(disengcfg_shdload1);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(disengcfg_framecomplete1);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(sig1_shdload);
+	DPU_IRQ_SET_CHAINED_HANDLER_AND_DATA2(sig1_valid);
+
+	for (i = 0; i < dpu->irq_line_num; i++) {
+		irq = irq_linear_revmap(dpu->domain, i);
+		if (irq)
+			irq_dispose_mapping(irq);
+	}
+
+	irq_domain_remove(dpu->domain);
+}
+
+#define _DPU_UNITS_INIT(unit)						\
+{									\
+	const struct dpu_unit *us = data->unit##s;			\
+	int i;								\
+									\
+	/* software check */						\
+	if (WARN_ON(us->num > ARRAY_SIZE(unit##_ids)))			\
+		return -EINVAL;						\
+									\
+	for (i = 0; i < us->num; i++)					\
+		_dpu_##unit##_init(dpu, us->ids[i]);			\
+}
+
+static int
+_dpu_submodules_init(struct dpu_soc *dpu, struct platform_device *pdev)
+{
+	const struct dpu_data *data = dpu->data;
+
+	_DPU_UNITS_INIT(cf);
+	_DPU_UNITS_INIT(dec);
+	_DPU_UNITS_INIT(ed);
+	_DPU_UNITS_INIT(fd);
+	_DPU_UNITS_INIT(fe);
+	_DPU_UNITS_INIT(fg);
+	_DPU_UNITS_INIT(fl);
+	_DPU_UNITS_INIT(fw);
+	_DPU_UNITS_INIT(hs);
+	_DPU_UNITS_INIT(lb);
+	_DPU_UNITS_INIT(sig);
+	_DPU_UNITS_INIT(st);
+	_DPU_UNITS_INIT(tcon);
+	_DPU_UNITS_INIT(vs);
+
+	return 0;
+}
+
+#define DPU_UNIT_INIT(dpu, base, unit, name, id, pec_ofs, ofs)		\
+{									\
+	int ret;							\
+	ret = dpu_##unit##_init((dpu),	(id),				\
+				(pec_ofs) ? (base) + (pec_ofs) : 0,	\
+				(base) + (ofs));			\
+	if (ret) {							\
+		dev_err((dpu)->dev, "init %s%d failed with %d\n",	\
+						(name), (id), ret);	\
+		return ret;						\
+	}								\
+}
+
+#define DPU_UNITS_INIT(unit)						\
+{									\
+	const struct dpu_unit *us = data->unit##s;			\
+	int i;								\
+									\
+	/* software check */						\
+	if (WARN_ON(us->num > ARRAY_SIZE(unit##_ids)))			\
+		return -EINVAL;						\
+									\
+	for (i = 0; i < us->num; i++)					\
+		DPU_UNIT_INIT(dpu, dpu_base, unit, us->name,		\
+			      us->ids[i],				\
+			      us->pec_ofss ? us->pec_ofss[i] : 0,	\
+			      us->ofss[i]);				\
+}
+
+static int dpu_submodules_init(struct dpu_soc *dpu,
+		struct platform_device *pdev, unsigned long dpu_base)
+{
+	const struct dpu_data *data = dpu->data;
+	const struct dpu_unit *fds = data->fds;
+	const struct dpu_unit *fls = data->fls;
+	const struct dpu_unit *fws = data->fws;
+	const struct dpu_unit *tcons = data->tcons;
+	struct dpu_fetchunit *fu;
+	struct dprc *dprc;
+	struct dpu_tcon *tcon;
+	struct pc *pc;
+	int i;
+
+	DPU_UNITS_INIT(cf);
+	DPU_UNITS_INIT(dec);
+	DPU_UNITS_INIT(ed);
+	DPU_UNITS_INIT(fd);
+	DPU_UNITS_INIT(fe);
+	DPU_UNITS_INIT(fg);
+	DPU_UNITS_INIT(fl);
+	DPU_UNITS_INIT(fw);
+	DPU_UNITS_INIT(hs);
+	DPU_UNITS_INIT(lb);
+	DPU_UNITS_INIT(sig);
+	DPU_UNITS_INIT(st);
+	DPU_UNITS_INIT(tcon);
+	DPU_UNITS_INIT(vs);
+
+	for (i = 0; i < fds->num; i++) {
+		dprc = dprc_lookup_by_phandle(dpu->dev, "fsl,dpr-channels",
+					      fds->dprc_ids[i]);
+		if (!dprc)
+			return -EPROBE_DEFER;
+
+		fu = dpu_fd_get(dpu, i);
+		fetchunit_get_dprc(fu, dprc);
+		dpu_fd_put(fu);
+	}
+
+	for (i = 0; i < fls->num; i++) {
+		dprc = dprc_lookup_by_phandle(dpu->dev, "fsl,dpr-channels",
+					      fls->dprc_ids[i]);
+		if (!dprc)
+			return -EPROBE_DEFER;
+
+		fu = dpu_fl_get(dpu, i);
+		fetchunit_get_dprc(fu, dprc);
+		dpu_fl_put(fu);
+	}
+
+	for (i = 0; i < fws->num; i++) {
+		dprc = dprc_lookup_by_phandle(dpu->dev, "fsl,dpr-channels",
+					      fws->dprc_ids[i]);
+		if (!dprc)
+			return -EPROBE_DEFER;
+
+		fu = dpu_fw_get(dpu, fw_ids[i]);
+		fetchunit_get_dprc(fu, dprc);
+		dpu_fw_put(fu);
+	}
+
+	pc = pc_lookup_by_phandle(dpu->dev, "fsl,pixel-combiner");
+	if (!pc)
+		return -EPROBE_DEFER;
+
+	for (i = 0; i < tcons->num; i++) {
+		tcon = dpu_tcon_get(dpu, i);
+		tcon_get_pc(tcon, pc);
+		dpu_tcon_put(tcon);
+	}
+
+	return 0;
+}
+
+static int platform_remove_devices_fn(struct device *dev, void *unused)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+	device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+}
+
+struct dpu_platform_reg {
+	struct dpu_client_platformdata pdata;
+	const char *name;
+};
+
+static struct dpu_platform_reg client_reg[] = {
+	{
+		.pdata = {
+			.stream_id = 0,
+		},
+		.name = "imx-dpu-crtc",
+	}, {
+		.pdata = {
+			.stream_id = 1,
+		},
+		.name = "imx-dpu-crtc",
+	}, {
+		.pdata = { },
+		.name = IMX_DPU_BLITENG_NAME,
+	}
+};
+
+static DEFINE_MUTEX(dpu_client_id_mutex);
+static int dpu_client_id;
+
+static int dpu_get_plane_resource(struct dpu_soc *dpu,
+				  struct dpu_plane_res *res)
+{
+	const struct dpu_unit *fds = dpu->data->fds;
+	const struct dpu_unit *fls = dpu->data->fls;
+	const struct dpu_unit *fws = dpu->data->fws;
+	const struct dpu_unit *lbs = dpu->data->lbs;
+	struct dpu_plane_grp *grp = plane_res_to_grp(res);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(res->ed); i++) {
+		res->ed[i] = dpu_ed_get(dpu, i);
+		if (IS_ERR(res->ed[i]))
+			return PTR_ERR(res->ed[i]);
+	}
+	for (i = 0; i < fds->num; i++) {
+		res->fd[i] = dpu_fd_get(dpu, i);
+		if (IS_ERR(res->fd[i]))
+			return PTR_ERR(res->fd[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->fe); i++) {
+		res->fe[i] = dpu_fe_get(dpu, i);
+		if (IS_ERR(res->fe[i]))
+			return PTR_ERR(res->fe[i]);
+		grp->hw_plane_fetcheco_num = ARRAY_SIZE(res->fe);
+	}
+	for (i = 0; i < fls->num; i++) {
+		res->fl[i] = dpu_fl_get(dpu, i);
+		if (IS_ERR(res->fl[i]))
+			return PTR_ERR(res->fl[i]);
+	}
+	for (i = 0; i < fws->num; i++) {
+		res->fw[i] = dpu_fw_get(dpu, fw_ids[i]);
+		if (IS_ERR(res->fw[i]))
+			return PTR_ERR(res->fw[i]);
+	}
+	/* HScaler could be shared with capture. */
+	if (display_plane_video_proc) {
+		for (i = 0; i < ARRAY_SIZE(res->hs); i++) {
+			res->hs[i] = dpu_hs_get(dpu, hs_ids[i]);
+			if (IS_ERR(res->hs[i]))
+				return PTR_ERR(res->hs[i]);
+		}
+		grp->hw_plane_hscaler_num = ARRAY_SIZE(res->hs);
+	}
+	for (i = 0; i < lbs->num; i++) {
+		res->lb[i] = dpu_lb_get(dpu, i);
+		if (IS_ERR(res->lb[i]))
+			return PTR_ERR(res->lb[i]);
+	}
+	/* VScaler could be shared with capture. */
+	if (display_plane_video_proc) {
+		for (i = 0; i < ARRAY_SIZE(res->vs); i++) {
+			res->vs[i] = dpu_vs_get(dpu, vs_ids[i]);
+			if (IS_ERR(res->vs[i]))
+				return PTR_ERR(res->vs[i]);
+		}
+		grp->hw_plane_vscaler_num = ARRAY_SIZE(res->vs);
+	}
+
+	grp->hw_plane_num = fds->num + fls->num + fws->num;
+
+	return 0;
+}
+
+static void dpu_put_plane_resource(struct dpu_plane_res *res)
+{
+	struct dpu_plane_grp *grp = plane_res_to_grp(res);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(res->ed); i++) {
+		if (!IS_ERR_OR_NULL(res->ed[i]))
+			dpu_ed_put(res->ed[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->fd); i++) {
+		if (!IS_ERR_OR_NULL(res->fd[i]))
+			dpu_fd_put(res->fd[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->fe); i++) {
+		if (!IS_ERR_OR_NULL(res->fe[i]))
+			dpu_fe_put(res->fe[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->fl); i++) {
+		if (!IS_ERR_OR_NULL(res->fl[i]))
+			dpu_fl_put(res->fl[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->fw); i++) {
+		if (!IS_ERR_OR_NULL(res->fw[i]))
+			dpu_fw_put(res->fw[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->hs); i++) {
+		if (!IS_ERR_OR_NULL(res->hs[i]))
+			dpu_hs_put(res->hs[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->lb); i++) {
+		if (!IS_ERR_OR_NULL(res->lb[i]))
+			dpu_lb_put(res->lb[i]);
+	}
+	for (i = 0; i < ARRAY_SIZE(res->vs); i++) {
+		if (!IS_ERR_OR_NULL(res->vs[i]))
+			dpu_vs_put(res->vs[i]);
+	}
+
+	grp->hw_plane_num = 0;
+}
+
+static int dpu_add_client_devices(struct dpu_soc *dpu)
+{
+	const struct dpu_data *data = dpu->data;
+	struct device *dev = dpu->dev;
+	struct dpu_platform_reg *reg;
+	struct dpu_plane_grp *plane_grp;
+	struct dpu_store *st9 = NULL;
+	size_t client_num, reg_size;
+	int i, id, ret;
+
+	client_num = ARRAY_SIZE(client_reg);
+
+	reg = devm_kcalloc(dev, client_num, sizeof(*reg), GFP_KERNEL);
+	if (!reg)
+		return -ENODEV;
+
+	plane_grp = devm_kzalloc(dev, sizeof(*plane_grp), GFP_KERNEL);
+	if (!plane_grp)
+		return -ENODEV;
+
+	mutex_init(&plane_grp->mutex);
+
+	mutex_lock(&dpu_client_id_mutex);
+	id = dpu_client_id;
+	dpu_client_id += client_num;
+	mutex_unlock(&dpu_client_id_mutex);
+
+	reg_size = client_num * sizeof(struct dpu_platform_reg);
+	memcpy(reg, &client_reg[0], reg_size);
+
+	plane_grp->src_mask = data->plane_src_mask;
+	plane_grp->id = id / client_num;
+	plane_grp->has_vproc = display_plane_video_proc;
+
+	ret = dpu_get_plane_resource(dpu, &plane_grp->res);
+	if (ret)
+		goto err_get_plane_res;
+
+	st9 = dpu_st_get(dpu, 9);
+	if (IS_ERR(st9)) {
+		ret = PTR_ERR(st9);
+		goto err_get_plane_res;
+	}
+
+	for (i = 0; i < client_num; i++) {
+		struct platform_device *pdev;
+		struct device_node *of_node = NULL;
+
+		if (!strcmp(reg[i].name, IMX_DPU_BLITENG_NAME)) {
+			/* As bliteng has no of_node, so to use dpu's. */
+			of_node = dev->of_node;
+		} else {
+			/* 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 DISP%d\n",
+					i, dev->of_node->full_name, i);
+				continue;
+			}
+		}
+
+		reg[i].pdata.plane_grp = plane_grp;
+		reg[i].pdata.di_grp_id = plane_grp->id;
+		reg[i].pdata.st9 = st9;
+
+		pdev = platform_device_alloc(reg[i].name, id++);
+		if (!pdev) {
+			ret = -ENOMEM;
+			goto err_register;
+		}
+
+		pdev->dev.parent = dev;
+
+		reg[i].pdata.of_node = of_node;
+		ret = platform_device_add_data(pdev, &reg[i].pdata,
+					       sizeof(reg[i].pdata));
+		if (!ret)
+			ret = platform_device_add(pdev);
+		if (ret) {
+			platform_device_put(pdev);
+			goto err_register;
+		}
+	}
+
+	return 0;
+
+err_register:
+	platform_device_unregister_children(to_platform_device(dev));
+	dpu_st_put(st9);
+err_get_plane_res:
+	dpu_put_plane_resource(&plane_grp->res);
+
+	return ret;
+}
+
+static int dpu_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device_node *np = pdev->dev.of_node;
+	struct dpu_soc *dpu;
+	struct resource *res;
+	unsigned long dpu_base;
+	const struct dpu_data *data;
+	int ret;
+
+	of_id = of_match_device(dpu_dt_ids, &pdev->dev);
+	if (!of_id)
+		return -ENODEV;
+
+	data = of_id->data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	dpu_base = res->start;
+
+	dpu = devm_kzalloc(&pdev->dev, sizeof(*dpu), GFP_KERNEL);
+	if (!dpu)
+		return -ENODEV;
+
+	dpu->dev = &pdev->dev;
+	dpu->data = data;
+	dpu->id = of_alias_get_id(np, "dpu");
+	dpu->irq_line_num = platform_irq_count(pdev);
+	if (dpu->irq_line_num < 0)
+		return dpu->irq_line_num;
+
+	dpu_units_addr_dbg(dpu, pdev, dpu_base);
+
+	ret = dpu_get_irq(pdev, dpu);
+	if (ret < 0)
+		return ret;
+
+	ret = dpu_sc_misc_get_handle(dpu);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_init(&dpu->lock);
+
+	dpu->cm_reg = devm_ioremap(dpu->dev, dpu_base + data->cm_ofs, SZ_1K);
+	if (!dpu->cm_reg)
+		return -ENOMEM;
+
+	ret = dpu_attach_pm_domains(dpu);
+	if (ret)
+		return ret;
+
+	ret = dpu_irq_init(dpu);
+	if (ret)
+		goto failed_irq;
+
+	ret = dpu_submodules_init(dpu, pdev, dpu_base);
+	if (ret)
+		goto failed_submodules_init;
+
+	ret = dpu_sc_misc_init(dpu);
+	if (ret < 0) {
+		dev_err(dpu->dev,
+			"failed to initialize pixel link %d\n", ret);
+		goto failed_sc_misc_init;
+	}
+
+	platform_set_drvdata(pdev, dpu);
+
+	ret = dpu_add_client_devices(dpu);
+	if (ret) {
+		dev_err(dpu->dev,
+			"adding client devices failed with %d\n", ret);
+		goto failed_add_clients;
+	}
+
+	dev_info(dpu->dev, "driver probed\n");
+
+	return 0;
+
+failed_add_clients:
+	platform_set_drvdata(pdev, NULL);
+failed_sc_misc_init:
+failed_submodules_init:
+	dpu_irq_exit(dpu);
+failed_irq:
+	dpu_detach_pm_domains(dpu);
+	return ret;
+}
+
+static int dpu_remove(struct platform_device *pdev)
+{
+	struct dpu_soc *dpu = platform_get_drvdata(pdev);
+
+	platform_device_unregister_children(pdev);
+
+	dpu_irq_exit(dpu);
+	dpu_detach_pm_domains(dpu);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dpu_suspend(struct device *dev)
+{
+	/*
+	 * The dpu core driver currently depends on the client drivers
+	 * to do suspend operations to leave dpu a cleaned up state
+	 * machine status before the system enters sleep mode.
+	 */
+	return 0;
+}
+
+static int dpu_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dpu_soc *dpu = platform_get_drvdata(pdev);
+
+	dpu_sc_misc_init(dpu);
+
+	_dpu_submodules_init(dpu, pdev);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops dpu_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(dpu_suspend, dpu_resume)
+};
+
+static struct platform_driver dpu_driver = {
+	.driver = {
+		.pm = &dpu_pm_ops,
+		.name = "dpu-core",
+		.of_match_table = dpu_dt_ids,
+	},
+	.probe = dpu_probe,
+	.remove = dpu_remove,
+};
+
+module_platform_driver(dpu_driver);
+
+MODULE_DESCRIPTION("i.MX DPU driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-constframe.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-constframe.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+static unsigned int safety_stream_cf_color = 0x0;
+module_param(safety_stream_cf_color, uint, 0444);
+MODULE_PARM_DESC(safety_stream_cf_color,
+"Safety stream constframe color in hex(0xRRGGBBAA) [default=0x00000000]");
+
+#define FRAMEDIMENSIONS		0xC
+#define WIDTH(w)		(((w) - 1) & 0x3FFF)
+#define HEIGHT(h)		((((h) - 1) & 0x3FFF) << 16)
+#define CONSTANTCOLOR		0x10
+#define RED(r)			(((r) & 0xFF) << 24)
+#define GREEN(g)		(((g) & 0xFF) << 16)
+#define BLUE(b)			(((b) & 0xFF) << 8)
+#define ALPHA(a)		((a) & 0xFF)
+#define CONTROLTRIGGER		0x14
+#define START			0x18
+#define STATUS			0x1C
+
+struct dpu_constframe {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_cf_read(struct dpu_constframe *cf, unsigned int offset)
+{
+	return readl(cf->base + offset);
+}
+
+static inline void dpu_cf_write(struct dpu_constframe *cf,
+				unsigned int offset, u32 value)
+{
+	writel(value, cf->base + offset);
+}
+
+void constframe_shden(struct dpu_constframe *cf, bool enable)
+{
+	u32 val;
+
+	val = enable ? SHDEN : 0;
+
+	mutex_lock(&cf->mutex);
+	dpu_cf_write(cf, STATICCONTROL, val);
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_shden);
+
+void constframe_framedimensions(struct dpu_constframe *cf, unsigned int w,
+				unsigned int h)
+{
+	u32 val;
+
+	val = WIDTH(w) | HEIGHT(h);
+
+	mutex_lock(&cf->mutex);
+	dpu_cf_write(cf, FRAMEDIMENSIONS, val);
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_framedimensions);
+
+void constframe_framedimensions_copy_prim(struct dpu_constframe *cf)
+{
+	struct dpu_constframe *prim_cf = NULL;
+	unsigned int prim_id;
+	int i;
+	u32 val;
+
+	if (cf->id != 0 && cf->id != 1) {
+		dev_warn(cf->dpu->dev, "ConstFrame%d is not a secondary one\n",
+								cf->id);
+		return;
+	}
+
+	prim_id = cf->id + 4;
+
+	for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+		if (cf_ids[i] == prim_id)
+			prim_cf = cf->dpu->cf_priv[i];
+
+	if (!prim_cf) {
+		dev_warn(cf->dpu->dev, "cannot find ConstFrame%d's primary peer\n",
+								cf->id);
+		return;
+	}
+
+	mutex_lock(&cf->mutex);
+	val = dpu_cf_read(prim_cf, FRAMEDIMENSIONS);
+	dpu_cf_write(cf, FRAMEDIMENSIONS, val);
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_framedimensions_copy_prim);
+
+void constframe_constantcolor(struct dpu_constframe *cf, unsigned int r,
+			      unsigned int g, unsigned int b, unsigned int a)
+{
+	u32 val;
+
+	val = RED(r) | GREEN(g) | BLUE(b) | ALPHA(a);
+
+	mutex_lock(&cf->mutex);
+	dpu_cf_write(cf, CONSTANTCOLOR, val);
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_constantcolor);
+
+void constframe_controltrigger(struct dpu_constframe *cf, bool trigger)
+{
+	u32 val;
+
+	val = trigger ? SHDTOKGEN : 0;
+
+	mutex_lock(&cf->mutex);
+	dpu_cf_write(cf, CONTROLTRIGGER, val);
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_controltrigger);
+
+struct dpu_constframe *dpu_cf_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_constframe *cf;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+		if (cf_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(cf_ids))
+		return ERR_PTR(-EINVAL);
+
+	cf = dpu->cf_priv[i];
+
+	mutex_lock(&cf->mutex);
+
+	if (cf->inuse) {
+		mutex_unlock(&cf->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	cf->inuse = true;
+
+	mutex_unlock(&cf->mutex);
+
+	return cf;
+}
+EXPORT_SYMBOL_GPL(dpu_cf_get);
+
+void dpu_cf_put(struct dpu_constframe *cf)
+{
+	mutex_lock(&cf->mutex);
+
+	cf->inuse = false;
+
+	mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_cf_put);
+
+struct dpu_constframe *dpu_aux_cf_peek(struct dpu_constframe *cf)
+{
+	unsigned int aux_id = cf->id ^ 1;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+		if (cf_ids[i] == aux_id)
+			return cf->dpu->cf_priv[i];
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(dpu_aux_cf_peek);
+
+void _dpu_cf_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_constframe *cf;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+		if (cf_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(cf_ids)))
+		return;
+
+	cf = dpu->cf_priv[i];
+
+	constframe_shden(cf, true);
+
+	if (id == 4 || id == 5) {
+		mutex_lock(&cf->mutex);
+		dpu_cf_write(cf, CONSTANTCOLOR, safety_stream_cf_color);
+		mutex_unlock(&cf->mutex);
+	}
+}
+
+int dpu_cf_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_constframe *cf;
+	int i;
+
+	cf = devm_kzalloc(dpu->dev, sizeof(*cf), GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+		if (cf_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(cf_ids))
+		return -EINVAL;
+
+	dpu->cf_priv[i] = cf;
+
+	cf->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+	if (!cf->pec_base)
+		return -ENOMEM;
+
+	cf->base = devm_ioremap(dpu->dev, base, SZ_32);
+	if (!cf->base)
+		return -ENOMEM;
+
+	cf->dpu = dpu;
+	cf->id = id;
+
+	mutex_init(&cf->mutex);
+
+	_dpu_cf_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-disengcfg.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-disengcfg.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_mode.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include "dpu-prv.h"
+
+#define CLOCKCTRL		0x8
+typedef enum {
+	DSPCLKDIVIDE__DIV1,	/* Ext disp clk signal has pix clk freq. */
+	DSPCLKDIVIDE__DIV2,	/* Ext disp clk signal has 2x the pix clk freq. */
+} clkdivide_t;
+#define POLARITYCTRL		0xC
+#define POLHS_HIGH		BIT(0)
+#define POLVS_HIGH		BIT(1)
+#define POLEN_HIGH		BIT(2)
+#define PIXINV_INV		BIT(3)
+#define SRCSELECT		0x10
+#define SIG_SELECT_MASK		0x3
+
+struct dpu_disengcfg {
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_dec_read(struct dpu_disengcfg *dec, unsigned int offset)
+{
+	return readl(dec->base + offset);
+}
+
+static inline void dpu_dec_write(struct dpu_disengcfg *dec,
+				 unsigned int offset, u32 value)
+{
+	writel(value, dec->base + offset);
+}
+
+void disengcfg_sig_select(struct dpu_disengcfg *dec, dec_sig_sel_t sig_sel)
+{
+	u32 val;
+
+	mutex_lock(&dec->mutex);
+	val = dpu_dec_read(dec, SRCSELECT);
+	val &= ~SIG_SELECT_MASK;
+	val |= sig_sel;
+	dpu_dec_write(dec, SRCSELECT, val);
+	mutex_unlock(&dec->mutex);
+}
+EXPORT_SYMBOL_GPL(disengcfg_sig_select);
+
+struct dpu_disengcfg *dpu_dec_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_disengcfg *dec;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dec_ids); i++)
+		if (dec_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(dec_ids))
+		return ERR_PTR(-EINVAL);
+
+	dec = dpu->dec_priv[i];
+
+	mutex_lock(&dec->mutex);
+
+	if (dec->inuse) {
+		mutex_unlock(&dec->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	dec->inuse = true;
+
+	mutex_unlock(&dec->mutex);
+
+	return dec;
+}
+EXPORT_SYMBOL_GPL(dpu_dec_get);
+
+void dpu_dec_put(struct dpu_disengcfg *dec)
+{
+	mutex_lock(&dec->mutex);
+
+	dec->inuse = false;
+
+	mutex_unlock(&dec->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_dec_put);
+
+struct dpu_disengcfg *dpu_aux_dec_peek(struct dpu_disengcfg *dec)
+{
+	return dec->dpu->dec_priv[dec->id ^ 1];
+}
+EXPORT_SYMBOL_GPL(dpu_aux_dec_peek);
+
+void _dpu_dec_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_disengcfg *dec;
+	u32 val;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dec_ids); i++)
+		if (ed_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(dec_ids)))
+		return;
+
+	dec = dpu->dec_priv[i];
+
+	val = dpu_dec_read(dec, POLARITYCTRL);
+	val &= ~POLHS_HIGH;
+	val &= ~POLVS_HIGH;
+	dpu_dec_write(dec, POLARITYCTRL, val);
+
+	disengcfg_sig_select(dec, DEC_SIG_SEL_FRAMEGEN);
+}
+
+int dpu_dec_init(struct dpu_soc *dpu, unsigned int id,
+			unsigned long unused, unsigned long base)
+{
+	struct dpu_disengcfg *dec;
+
+	dec = devm_kzalloc(dpu->dev, sizeof(*dec), GFP_KERNEL);
+	if (!dec)
+		return -ENOMEM;
+
+	dpu->dec_priv[id] = dec;
+
+	dec->base = devm_ioremap(dpu->dev, base, SZ_16);
+	if (!dec->base)
+		return -ENOMEM;
+
+	dec->dpu = dpu;
+	dec->id = id;
+	mutex_init(&dec->mutex);
+
+	_dpu_dec_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-extdst.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-extdst.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATIC		0x8
+#define POWERDOWN			BIT(4)
+#define SYNC_MODE			BIT(8)
+#define SW_RESET			BIT(11)
+#define DIV(n)				(((n) & 0xFF) << 16)
+#define DIV_RESET			0x80
+#define PIXENGCFG_DYNAMIC		0xC
+#define PIXENGCFG_REQUEST		0x10
+#define SHDLDREQ(n)			BIT(n)
+#define SEL_SHDLDREQ			BIT(0)
+#define PIXENGCFG_TRIGGER		0x14
+#define SYNC_TRIGGER			BIT(0)
+#define TRIGGER_SEQUENCE_COMPLETE	BIT(4)
+#define PIXENGCFG_STATUS		0x18
+#define SYNC_BUSY			BIT(8)
+#define KICK_MODE			BIT(8)
+#define PERFCOUNTMODE			BIT(12)
+#define CONTROL				0xC
+#define GAMMAAPPLYENABLE		BIT(0)
+#define SOFTWAREKICK			0x10
+#define KICK				BIT(0)
+#define STATUS				0x14
+#define CNT_ERR_STS			BIT(0)
+#define CONTROLWORD			0x18
+#define CURPIXELCNT			0x1C
+static u16 get_xval(u32 pixel_cnt)
+{
+	return pixel_cnt & 0xFFFF;
+}
+
+static u16 get_yval(u32 pixel_cnt)
+{
+	return pixel_cnt >> 16;
+}
+#define LASTPIXELCNT			0x20
+#define PERFCOUNTER			0x24
+
+struct dpu_extdst {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_pec_ed_read(struct dpu_extdst *ed, unsigned int offset)
+{
+	return readl(ed->pec_base + offset);
+}
+
+static inline void dpu_pec_ed_write(struct dpu_extdst *ed,
+				unsigned int offset, u32 value)
+{
+	writel(value, ed->pec_base + offset);
+}
+
+static inline u32 dpu_ed_read(struct dpu_extdst *ed, unsigned int offset)
+{
+	return readl(ed->base + offset);
+}
+
+static inline void dpu_ed_write(struct dpu_extdst *ed,
+				unsigned int offset, u32 value)
+{
+	writel(value, ed->base + offset);
+}
+
+static inline bool dpu_ed_is_safety_stream(struct dpu_extdst *ed)
+{
+	if (ed->id == 4 || ed->id == 5)
+		return true;
+
+	return false;
+}
+
+void extdst_pixengcfg_shden(struct dpu_extdst *ed, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_shden);
+
+void extdst_pixengcfg_powerdown(struct dpu_extdst *ed, bool powerdown)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	if (powerdown)
+		val |= POWERDOWN;
+	else
+		val &= ~POWERDOWN;
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_powerdown);
+
+void extdst_pixengcfg_sync_mode(struct dpu_extdst *ed, ed_sync_mode_t mode)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	if (mode == AUTO)
+		val |= SYNC_MODE;
+	else
+		val &= ~SYNC_MODE;
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sync_mode);
+
+void extdst_pixengcfg_reset(struct dpu_extdst *ed, bool reset)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	if (reset)
+		val |= SW_RESET;
+	else
+		val &= ~SW_RESET;
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_reset);
+
+void extdst_pixengcfg_div(struct dpu_extdst *ed, u16 div)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	val &= ~0xFF0000;
+	val |= DIV(div);
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_div);
+
+void extdst_pixengcfg_syncmode_master(struct dpu_extdst *ed, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+	if (enable)
+		val |= BIT(16);
+	else
+		val &= ~BIT(16);
+	dpu_pec_ed_write(ed, PIXENGCFG_STATIC, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_syncmode_master);
+
+int extdst_pixengcfg_src_sel(struct dpu_extdst *ed, extdst_src_sel_t src)
+{
+	mutex_lock(&ed->mutex);
+	dpu_pec_ed_write(ed, PIXENGCFG_DYNAMIC, src);
+	mutex_unlock(&ed->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_src_sel);
+
+void extdst_pixengcfg_sel_shdldreq(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_REQUEST);
+	val |= SEL_SHDLDREQ;
+	dpu_pec_ed_write(ed, PIXENGCFG_REQUEST, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sel_shdldreq);
+
+void extdst_pixengcfg_shdldreq(struct dpu_extdst *ed, u32 req_mask)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_REQUEST);
+	val |= req_mask;
+	dpu_pec_ed_write(ed, PIXENGCFG_REQUEST, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_shdldreq);
+
+void extdst_pixengcfg_sync_trigger(struct dpu_extdst *ed)
+{
+	mutex_lock(&ed->mutex);
+	dpu_pec_ed_write(ed, PIXENGCFG_TRIGGER, SYNC_TRIGGER);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sync_trigger);
+
+void extdst_pixengcfg_trigger_sequence_complete(struct dpu_extdst *ed)
+{
+	mutex_lock(&ed->mutex);
+	dpu_pec_ed_write(ed, PIXENGCFG_TRIGGER, TRIGGER_SEQUENCE_COMPLETE);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_trigger_sequence_complete);
+
+bool extdst_pixengcfg_is_sync_busy(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATUS);
+	mutex_unlock(&ed->mutex);
+
+	return val & SYNC_BUSY;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_is_sync_busy);
+
+ed_pipeline_status_t extdst_pixengcfg_pipeline_status(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_pec_ed_read(ed, PIXENGCFG_STATUS);
+	mutex_unlock(&ed->mutex);
+
+	return val & 0x3;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_pipeline_status);
+
+void extdst_shden(struct dpu_extdst *ed, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_ed_write(ed, STATICCONTROL, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_shden);
+
+void extdst_kick_mode(struct dpu_extdst *ed, ed_kick_mode_t mode)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, STATICCONTROL);
+	val &= ~KICK_MODE;
+	val |= mode;
+	dpu_ed_write(ed, STATICCONTROL, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_kick_mode);
+
+void extdst_perfcountmode(struct dpu_extdst *ed, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, STATICCONTROL);
+	if (enable)
+		val |= PERFCOUNTMODE;
+	else
+		val &= ~PERFCOUNTMODE;
+	dpu_ed_write(ed, STATICCONTROL, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_perfcountmode);
+
+void extdst_gamma_apply_enable(struct dpu_extdst *ed, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, CONTROL);
+	if (enable)
+		val |= GAMMAAPPLYENABLE;
+	else
+		val &= ~GAMMAAPPLYENABLE;
+	dpu_ed_write(ed, CONTROL, val);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_gamma_apply_enable);
+
+void extdst_kick(struct dpu_extdst *ed)
+{
+	mutex_lock(&ed->mutex);
+	dpu_ed_write(ed, SOFTWAREKICK, KICK);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_kick);
+
+void extdst_cnt_err_clear(struct dpu_extdst *ed)
+{
+	mutex_lock(&ed->mutex);
+	dpu_ed_write(ed, STATUS, CNT_ERR_STS);
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_cnt_err_clear);
+
+bool extdst_cnt_err_status(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, STATUS);
+	mutex_unlock(&ed->mutex);
+
+	return val & CNT_ERR_STS;
+}
+EXPORT_SYMBOL_GPL(extdst_cnt_err_status);
+
+u32 extdst_last_control_word(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, CONTROLWORD);
+	mutex_unlock(&ed->mutex);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(extdst_last_control_word);
+
+void extdst_pixel_cnt(struct dpu_extdst *ed, u16 *x, u16 *y)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, CURPIXELCNT);
+	mutex_unlock(&ed->mutex);
+
+	*x = get_xval(val);
+	*y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(extdst_pixel_cnt);
+
+void extdst_last_pixel_cnt(struct dpu_extdst *ed, u16 *x, u16 *y)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, LASTPIXELCNT);
+	mutex_unlock(&ed->mutex);
+
+	*x = get_xval(val);
+	*y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(extdst_last_pixel_cnt);
+
+u32 extdst_perfresult(struct dpu_extdst *ed)
+{
+	u32 val;
+
+	mutex_lock(&ed->mutex);
+	val = dpu_ed_read(ed, PERFCOUNTER);
+	mutex_unlock(&ed->mutex);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(extdst_perfresult);
+
+bool extdst_is_master(struct dpu_extdst *ed)
+{
+	const struct dpu_data *data = ed->dpu->data;
+
+	return ed->id == data->master_stream_id;
+}
+EXPORT_SYMBOL_GPL(extdst_is_master);
+
+struct dpu_extdst *dpu_ed_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_extdst *ed;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+		if (ed_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(ed_ids))
+		return ERR_PTR(-EINVAL);
+
+	ed = dpu->ed_priv[i];
+
+	mutex_lock(&ed->mutex);
+
+	if (ed->inuse) {
+		mutex_unlock(&ed->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	ed->inuse = true;
+
+	mutex_unlock(&ed->mutex);
+
+	return ed;
+}
+EXPORT_SYMBOL_GPL(dpu_ed_get);
+
+void dpu_ed_put(struct dpu_extdst *ed)
+{
+	mutex_lock(&ed->mutex);
+
+	ed->inuse = false;
+
+	mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_ed_put);
+
+struct dpu_extdst *dpu_aux_ed_peek(struct dpu_extdst *ed)
+{
+	unsigned int aux_id = ed->id ^ 1;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+		if (ed_ids[i] == aux_id)
+			return ed->dpu->ed_priv[i];
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(dpu_aux_ed_peek);
+
+void _dpu_ed_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_extdst *ed;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+		if (ed_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(ed_ids)))
+		return;
+
+	ed = dpu->ed_priv[i];
+
+	extdst_pixengcfg_src_sel(ed, ED_SRC_DISABLE);
+	extdst_pixengcfg_shden(ed, true);
+	extdst_pixengcfg_powerdown(ed, false);
+	extdst_pixengcfg_sync_mode(ed, SINGLE);
+	extdst_pixengcfg_reset(ed, false);
+	extdst_pixengcfg_div(ed, DIV_RESET);
+	extdst_shden(ed, true);
+	extdst_perfcountmode(ed, false);
+	extdst_kick_mode(ed, EXTERNAL);
+}
+
+int dpu_ed_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_extdst *ed;
+	int ret, i;
+
+	ed = devm_kzalloc(dpu->dev, sizeof(*ed), GFP_KERNEL);
+	if (!ed)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+		if (ed_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(ed_ids))
+		return -EINVAL;
+
+	dpu->ed_priv[i] = ed;
+
+	ed->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_32);
+	if (!ed->pec_base)
+		return -ENOMEM;
+
+	ed->base = devm_ioremap(dpu->dev, base, SZ_64);
+	if (!ed->base)
+		return -ENOMEM;
+
+	ed->dpu = dpu;
+	ed->id = id;
+	mutex_init(&ed->mutex);
+
+	ret = extdst_pixengcfg_src_sel(ed, ED_SRC_DISABLE);
+	if (ret < 0)
+		return ret;
+
+	_dpu_ed_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-fetchdecode.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-fetchdecode.c
@@ -0,0 +1,673 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_blend.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+static const u32 fd_vproc_cap[2] = {
+	DPU_VPROC_CAP_HSCALER4 | DPU_VPROC_CAP_VSCALER4 |
+	DPU_VPROC_CAP_FETCHECO0,
+	DPU_VPROC_CAP_HSCALER5 | DPU_VPROC_CAP_VSCALER5 |
+	DPU_VPROC_CAP_FETCHECO1,
+};
+
+#define PIXENGCFG_DYNAMIC		0x8
+static const fd_dynamic_src_sel_t fd_srcs[2][4] = {
+	{
+	  FD_SRC_DISABLE,	FD_SRC_FETCHECO0,
+	  FD_SRC_FETCHDECODE1,	FD_SRC_FETCHWARP2
+	}, {
+	  FD_SRC_DISABLE,	FD_SRC_FETCHECO1,
+	  FD_SRC_FETCHDECODE0,	FD_SRC_FETCHWARP2
+	},
+};
+
+#define PIXENGCFG_STATUS		0xC
+
+#define RINGBUFSTARTADDR0		0x10
+#define RINGBUFWRAPADDR0		0x14
+#define FRAMEPROPERTIES0		0x18
+#define BASEADDRESS0			0x1C
+#define SOURCEBUFFERATTRIBUTES0		0x20
+#define SOURCEBUFFERDIMENSION0		0x24
+#define COLORCOMPONENTBITS0		0x28
+#define COLORCOMPONENTSHIFT0		0x2C
+#define LAYEROFFSET0			0x30
+#define CLIPWINDOWOFFSET0		0x34
+#define CLIPWINDOWDIMENSIONS0		0x38
+#define CONSTANTCOLOR0			0x3C
+#define LAYERPROPERTY0			0x40
+#define FRAMEDIMENSIONS			0x44
+#define FRAMERESAMPLING			0x48
+#define DECODECONTROL			0x4C
+#define SOURCEBUFFERLENGTH		0x50
+#define CONTROL				0x54
+#define CONTROLTRIGGER			0x58
+#define START				0x5C
+#define FETCHTYPE			0x60
+#define DECODERSTATUS			0x64
+#define READADDRESS0			0x68
+#define BURSTBUFFERPROPERTIES		0x6C
+#define STATUS				0x70
+#define HIDDENSTATUS			0x74
+
+struct dpu_fetchdecode {
+	struct dpu_fetchunit fu;
+	fetchtype_t fetchtype;
+};
+
+int fetchdecode_pixengcfg_dynamic_src_sel(struct dpu_fetchunit *fu,
+					  fd_dynamic_src_sel_t src)
+{
+	int i;
+
+	mutex_lock(&fu->mutex);
+	for (i = 0; i < 4; i++) {
+		if (fd_srcs[fu->id][i] == src) {
+			dpu_pec_fu_write(fu, PIXENGCFG_DYNAMIC, src);
+			mutex_unlock(&fu->mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&fu->mutex);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_pixengcfg_dynamic_src_sel);
+
+static void
+fetchdecode_set_baseaddress(struct dpu_fetchunit *fu, unsigned int width,
+			    unsigned int x_offset, unsigned int y_offset,
+			    unsigned int mt_w, unsigned int mt_h,
+			    int bpp, dma_addr_t baddr)
+{
+	unsigned int burst_size, stride;
+	bool nonzero_mod = !!mt_w;
+
+	if (nonzero_mod) {
+		/* consider PRG x offset to calculate buffer address */
+		baddr += (x_offset % mt_w) * (bpp / 8);
+
+		burst_size = fetchunit_burst_size_fixup_tkt343664(baddr);
+
+		stride = width * (bpp / 8);
+		stride = fetchunit_stride_fixup_tkt339017(stride, burst_size,
+							  baddr, nonzero_mod);
+
+		/* consider PRG y offset to calculate buffer address */
+		baddr += (y_offset % mt_h) * stride;
+	}
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BASEADDRESS0, baddr);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_set_src_bpp(struct dpu_fetchunit *fu, int bpp)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES0);
+	val &= ~0x3f0000;
+	val |= BITSPERPIXEL(bpp);
+	dpu_fu_write(fu, SOURCEBUFFERATTRIBUTES0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void
+fetchdecode_set_src_stride(struct dpu_fetchunit *fu,
+			   unsigned int width, unsigned int x_offset,
+			   unsigned int mt_w, int bpp, unsigned int stride,
+			   dma_addr_t baddr, bool use_prefetch)
+{
+	unsigned int burst_size;
+	bool nonzero_mod = !!mt_w;
+	u32 val;
+
+	if (use_prefetch) {
+		/* consider PRG x offset to calculate buffer address */
+		if (nonzero_mod)
+			baddr += (x_offset % mt_w) * (bpp / 8);
+
+		burst_size = fetchunit_burst_size_fixup_tkt343664(baddr);
+
+		stride = width * (bpp / 8);
+		stride = fetchunit_stride_fixup_tkt339017(stride, burst_size,
+							  baddr, nonzero_mod);
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES0);
+	val &= ~0xffff;
+	val |= STRIDE(stride);
+	dpu_fu_write(fu, SOURCEBUFFERATTRIBUTES0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void
+fetchdecode_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+				   unsigned int w, unsigned int h,
+				   u32 unused, bool deinterlace)
+{
+	u32 val;
+
+	if (deinterlace)
+		h /= 2;
+
+	val = LINEWIDTH(w) | LINECOUNT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, SOURCEBUFFERDIMENSION0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_set_fmt(struct dpu_fetchunit *fu,
+				u32 fmt,
+				enum drm_color_encoding color_encoding,
+				enum drm_color_range color_range,
+				bool deinterlace)
+{
+	u32 val, bits, shift;
+	bool is_planar_yuv = false, is_rastermode_yuv422 = false;
+	bool is_yuv422upsamplingmode_interpolate = false;
+	bool is_inputselect_compact = false;
+	bool need_csc = false;
+	int i;
+
+	switch (fmt) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		is_rastermode_yuv422 = true;
+		is_yuv422upsamplingmode_interpolate = true;
+		need_csc = true;
+		break;
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		is_yuv422upsamplingmode_interpolate = true;
+		/* fall-through */
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		if (deinterlace)
+			is_yuv422upsamplingmode_interpolate = true;
+		is_planar_yuv = true;
+		is_rastermode_yuv422 = true;
+		is_inputselect_compact = true;
+		need_csc = true;
+		break;
+	case DRM_FORMAT_NV24:
+	case DRM_FORMAT_NV42:
+		is_planar_yuv = true;
+		is_yuv422upsamplingmode_interpolate = true;
+		is_inputselect_compact = true;
+		need_csc = true;
+		break;
+	default:
+		break;
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, CONTROL);
+	val &= ~YUV422UPSAMPLINGMODE_MASK;
+	val &= ~INPUTSELECT_MASK;
+	val &= ~RASTERMODE_MASK;
+	if (is_yuv422upsamplingmode_interpolate)
+		val |= YUV422UPSAMPLINGMODE(YUV422UPSAMPLINGMODE__INTERPOLATE);
+	else
+		val |= YUV422UPSAMPLINGMODE(YUV422UPSAMPLINGMODE__REPLICATE);
+	if (is_inputselect_compact)
+		val |= INPUTSELECT(INPUTSELECT__COMPPACK);
+	else
+		val |= INPUTSELECT(INPUTSELECT__INACTIVE);
+	if (is_rastermode_yuv422)
+		val |= RASTERMODE(RASTERMODE__YUV422);
+	else
+		val |= RASTERMODE(RASTERMODE__NORMAL);
+	dpu_fu_write(fu, CONTROL, val);
+
+	val = dpu_fu_read(fu, LAYERPROPERTY0);
+	val &= ~YUVCONVERSIONMODE_MASK;
+	if (need_csc) {
+		/* assuming fetchdecode always ouputs RGB pixel formats */
+		if (color_encoding == DRM_COLOR_YCBCR_BT709)
+			val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__ITU709);
+		else if (color_encoding == DRM_COLOR_YCBCR_BT601 &&
+			 color_range == DRM_COLOR_YCBCR_FULL_RANGE)
+			val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__ITU601_FR);
+		else
+			val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__ITU601);
+	} else {
+		val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__OFF);
+	}
+	dpu_fu_write(fu, LAYERPROPERTY0, val);
+	mutex_unlock(&fu->mutex);
+
+	for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+		if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+			bits = dpu_pixel_format_matrix[i].bits;
+			shift = dpu_pixel_format_matrix[i].shift;
+
+			if (is_planar_yuv) {
+				bits &= ~(U_BITS_MASK | V_BITS_MASK);
+				shift &= ~(U_SHIFT_MASK | V_SHIFT_MASK);
+			}
+
+			mutex_lock(&fu->mutex);
+			dpu_fu_write(fu, COLORCOMPONENTBITS0, bits);
+			dpu_fu_write(fu, COLORCOMPONENTSHIFT0, shift);
+			mutex_unlock(&fu->mutex);
+			return;
+		}
+	}
+
+	WARN_ON(1);
+}
+
+void fetchdecode_layeroffset(struct dpu_fetchunit *fu, unsigned int x,
+			     unsigned int y)
+{
+	u32 val;
+
+	val = LAYERXOFFSET(x) | LAYERYOFFSET(y);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, LAYEROFFSET0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_layeroffset);
+
+void fetchdecode_clipoffset(struct dpu_fetchunit *fu, unsigned int x,
+			    unsigned int y)
+{
+	u32 val;
+
+	val = CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CLIPWINDOWOFFSET0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_clipoffset);
+
+static void
+fetchdecode_set_pixel_blend_mode(struct dpu_fetchunit *fu,
+				 unsigned int pixel_blend_mode, u16 alpha,
+				 u32 fb_format)
+{
+	u32 mode = 0, val;
+
+	if (pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
+	    pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
+		mode = ALPHACONSTENABLE;
+
+		switch (fb_format) {
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_ABGR8888:
+		case DRM_FORMAT_RGBA8888:
+		case DRM_FORMAT_BGRA8888:
+			mode |= ALPHASRCENABLE;
+			break;
+		}
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY0);
+	val &= ~(PREMULCONSTRGB | ALPHA_ENABLE_MASK | RGB_ENABLE_MASK);
+	val |= mode;
+	dpu_fu_write(fu, LAYERPROPERTY0, val);
+
+	val = dpu_fu_read(fu, CONSTANTCOLOR0);
+	val &= ~CONSTANTALPHA_MASK;
+	val |= CONSTANTALPHA(alpha >> 8);
+	dpu_fu_write(fu, CONSTANTCOLOR0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_enable_src_buf(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY0);
+	val |= SOURCEBUFFERENABLE;
+	dpu_fu_write(fu, LAYERPROPERTY0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_disable_src_buf(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY0);
+	val &= ~SOURCEBUFFERENABLE;
+	dpu_fu_write(fu, LAYERPROPERTY0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static bool fetchdecode_is_enabled(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY0);
+	mutex_unlock(&fu->mutex);
+
+	return !!(val & SOURCEBUFFERENABLE);
+}
+
+void fetchdecode_clipdimensions(struct dpu_fetchunit *fu, unsigned int w,
+				unsigned int h)
+{
+	u32 val;
+
+	val = CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CLIPWINDOWDIMENSIONS0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_clipdimensions);
+
+static void
+fetchdecode_set_framedimensions(struct dpu_fetchunit *fu,
+				unsigned int w, unsigned int h,
+				bool deinterlace)
+{
+	u32 val;
+
+	if (deinterlace)
+		h /= 2;
+
+	val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, FRAMEDIMENSIONS, val);
+	mutex_unlock(&fu->mutex);
+}
+
+void fetchdecode_rgb_constantcolor(struct dpu_fetchunit *fu,
+					u8 r, u8 g, u8 b, u8 a)
+{
+	u32 val;
+
+	val = rgb_color(r, g, b, a);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_rgb_constantcolor);
+
+void fetchdecode_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+	u32 val;
+
+	val = yuv_color(y, u, v);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_yuv_constantcolor);
+
+static void fetchdecode_set_controltrigger(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONTROLTRIGGER, SHDTOKGEN);
+	mutex_unlock(&fu->mutex);
+}
+
+int fetchdecode_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+	struct dpu_soc *dpu = fu->dpu;
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FETCHTYPE);
+	val &= FETCHTYPE_MASK;
+	mutex_unlock(&fu->mutex);
+
+	switch (val) {
+	case FETCHTYPE__DECODE:
+	case FETCHTYPE__LAYER:
+	case FETCHTYPE__WARP:
+	case FETCHTYPE__ECO:
+	case FETCHTYPE__PERSP:
+	case FETCHTYPE__ROT:
+	case FETCHTYPE__DECODEL:
+	case FETCHTYPE__LAYERL:
+	case FETCHTYPE__ROTL:
+		break;
+	default:
+		dev_warn(dpu->dev, "Invalid fetch type %u for FetchDecode%d\n",
+				val, fu->id);
+		return -EINVAL;
+	}
+
+	*type = val;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_fetchtype);
+
+u32 fetchdecode_get_vproc_mask(struct dpu_fetchunit *fu)
+{
+	return fd_vproc_cap[fu->id];
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_vproc_mask);
+
+struct dpu_fetchunit *fetchdecode_get_fetcheco(struct dpu_fetchunit *fu)
+{
+	struct dpu_soc *dpu = fu->dpu;
+
+	switch (fu->id) {
+	case 0:
+	case 1:
+		return dpu->fe_priv[fu->id];
+	default:
+		WARN_ON(1);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_fetcheco);
+
+bool fetchdecode_need_fetcheco(struct dpu_fetchunit *fu, u32 fmt)
+{
+	struct dpu_fetchunit *fe = fetchdecode_get_fetcheco(fu);
+
+	if (IS_ERR_OR_NULL(fe))
+		return false;
+
+	switch (fmt) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+	case DRM_FORMAT_NV24:
+	case DRM_FORMAT_NV42:
+		return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_need_fetcheco);
+
+struct dpu_hscaler *fetchdecode_get_hscaler(struct dpu_fetchunit *fu)
+{
+	struct dpu_soc *dpu = fu->dpu;
+
+	switch (fu->id) {
+	case 0:
+	case 2:
+		return dpu->hs_priv[0];
+	case 1:
+	case 3:
+		return dpu->hs_priv[1];
+	default:
+		WARN_ON(1);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_hscaler);
+
+struct dpu_vscaler *fetchdecode_get_vscaler(struct dpu_fetchunit *fu)
+{
+	struct dpu_soc *dpu = fu->dpu;
+
+	switch (fu->id) {
+	case 0:
+	case 2:
+		return dpu->vs_priv[0];
+	case 1:
+	case 3:
+		return dpu->vs_priv[1];
+	default:
+		WARN_ON(1);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_vscaler);
+
+struct dpu_fetchunit *dpu_fd_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fd_ids); i++)
+		if (fd_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fd_ids))
+		return ERR_PTR(-EINVAL);
+
+	fu = dpu->fd_priv[i];
+
+	mutex_lock(&fu->mutex);
+
+	if (fu->inuse) {
+		mutex_unlock(&fu->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	fu->inuse = true;
+
+	mutex_unlock(&fu->mutex);
+
+	return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fd_get);
+
+void dpu_fd_put(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+
+	fu->inuse = false;
+
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fd_put);
+
+static const struct dpu_fetchunit_ops fd_ops = {
+	.set_burstlength	= fetchunit_set_burstlength,
+	.set_baseaddress	= fetchdecode_set_baseaddress,
+	.set_src_bpp		= fetchdecode_set_src_bpp,
+	.set_src_stride		= fetchdecode_set_src_stride,
+	.set_src_buf_dimensions	= fetchdecode_set_src_buf_dimensions,
+	.set_fmt		= fetchdecode_set_fmt,
+	.set_pixel_blend_mode	= fetchdecode_set_pixel_blend_mode,
+	.enable_src_buf		= fetchdecode_enable_src_buf,
+	.disable_src_buf	= fetchdecode_disable_src_buf,
+	.is_enabled		= fetchdecode_is_enabled,
+	.set_framedimensions	= fetchdecode_set_framedimensions,
+	.set_controltrigger	= fetchdecode_set_controltrigger,
+	.get_stream_id		= fetchunit_get_stream_id,
+	.set_stream_id		= fetchunit_set_stream_id,
+};
+
+void _dpu_fd_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fd_ids); i++)
+		if (fd_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(fd_ids)))
+		return;
+
+	fu = dpu->fd_priv[i];
+
+	fetchdecode_pixengcfg_dynamic_src_sel(fu, FD_SRC_DISABLE);
+	fetchunit_baddr_autoupdate(fu, 0x0);
+	fetchunit_shden(fu, true);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BURSTBUFFERMANAGEMENT,
+			SETNUMBUFFERS(16) | SETBURSTLENGTH(16));
+	mutex_unlock(&fu->mutex);
+}
+
+int dpu_fd_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_fetchdecode *fd;
+	struct dpu_fetchunit *fu;
+	int ret;
+
+	fd = devm_kzalloc(dpu->dev, sizeof(*fd), GFP_KERNEL);
+	if (!fd)
+		return -ENOMEM;
+
+	fu = &fd->fu;
+	dpu->fd_priv[id] = fu;
+
+	fu->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+	if (!fu->pec_base)
+		return -ENOMEM;
+
+	fu->base = devm_ioremap(dpu->dev, base, SZ_1K);
+	if (!fu->base)
+		return -ENOMEM;
+
+	fu->dpu = dpu;
+	fu->id = id;
+	fu->type = FU_T_FD;
+	fu->ops = &fd_ops;
+	fu->name = "fetchdecode";
+
+	mutex_init(&fu->mutex);
+
+	ret = fetchdecode_pixengcfg_dynamic_src_sel(fu, FD_SRC_DISABLE);
+	if (ret < 0)
+		return ret;
+
+	ret = fetchdecode_fetchtype(fu, &fd->fetchtype);
+	if (ret < 0)
+		return ret;
+
+	_dpu_fd_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-fetcheco.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-fetcheco.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define BASEADDRESS0			0x10
+#define SOURCEBUFFERATTRIBUTES0		0x14
+#define SOURCEBUFFERDIMENSION0		0x18
+#define COLORCOMPONENTBITS0		0x1C
+#define COLORCOMPONENTSHIFT0		0x20
+#define LAYEROFFSET0			0x24
+#define CLIPWINDOWOFFSET0		0x28
+#define CLIPWINDOWDIMENSIONS0		0x2C
+#define CONSTANTCOLOR0			0x30
+#define LAYERPROPERTY0			0x34
+#define FRAMEDIMENSIONS			0x38
+#define FRAMERESAMPLING			0x3C
+#define CONTROL				0x40
+#define CONTROLTRIGGER			0x44
+#define START				0x48
+#define FETCHTYPE			0x4C
+#define BURSTBUFFERPROPERTIES		0x50
+#define HIDDENSTATUS			0x54
+
+struct dpu_fetcheco {
+	struct dpu_fetchunit fu;
+};
+
+static void
+fetcheco_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+				unsigned int w, unsigned int h,
+				u32 fmt, bool deinterlace)
+{
+	int width, height;
+	u32 val;
+
+	if (deinterlace) {
+		width = w;
+		height = h / 2;
+	} else {
+		width = dpu_format_plane_width(w, fmt, 1);
+		height = dpu_format_plane_height(h, fmt, 1);
+	}
+
+	switch (fmt) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+	case DRM_FORMAT_NV24:
+	case DRM_FORMAT_NV42:
+		break;
+	default:
+		WARN(1, "Unsupported FetchEco pixel format 0x%08x\n", fmt);
+		return;
+	}
+
+	val = LINEWIDTH(width) | LINECOUNT(height);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, SOURCEBUFFERDIMENSION0, val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetcheco_set_fmt(struct dpu_fetchunit *fu,
+			     u32 fmt,
+			     enum drm_color_encoding unused1,
+			     enum drm_color_range unused2,
+			     bool unused3)
+{
+	u32 val, bits, shift;
+	int i, hsub, vsub;
+	unsigned int x, y;
+
+	switch (fmt) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+	case DRM_FORMAT_NV24:
+	case DRM_FORMAT_NV42:
+		break;
+	default:
+		WARN(1, "Unsupported FetchEco pixel format 0x%08x\n", fmt);
+		return;
+	}
+
+	hsub = dpu_format_horz_chroma_subsampling(fmt);
+	switch (hsub) {
+	case 1:
+		x = 0x4;
+		break;
+	case 2:
+		x = 0x2;
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	vsub = dpu_format_vert_chroma_subsampling(fmt);
+	switch (vsub) {
+	case 1:
+		y = 0x4;
+		break;
+	case 2:
+		y = 0x2;
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FRAMERESAMPLING);
+	val &= ~(DELTAX_MASK | DELTAY_MASK);
+	val |= DELTAX(x) | DELTAY(y);
+	dpu_fu_write(fu, FRAMERESAMPLING, val);
+
+	val = dpu_fu_read(fu, CONTROL);
+	val &= ~RASTERMODE_MASK;
+	val |= RASTERMODE(RASTERMODE__NORMAL);
+	dpu_fu_write(fu, CONTROL, val);
+	mutex_unlock(&fu->mutex);
+
+	for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+		if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+			bits = dpu_pixel_format_matrix[i].bits;
+			shift = dpu_pixel_format_matrix[i].shift;
+
+			bits &= ~Y_BITS_MASK;
+			shift &= ~Y_SHIFT_MASK;
+
+			mutex_lock(&fu->mutex);
+			dpu_fu_write(fu, COLORCOMPONENTBITS0, bits);
+			dpu_fu_write(fu, COLORCOMPONENTSHIFT0, shift);
+			mutex_unlock(&fu->mutex);
+			return;
+		}
+	}
+
+	WARN_ON(1);
+}
+
+void fetcheco_layeroffset(struct dpu_fetchunit *fu, unsigned int x,
+			  unsigned int y)
+{
+	u32 val;
+
+	val = LAYERXOFFSET(x) | LAYERYOFFSET(y);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, LAYEROFFSET0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_layeroffset);
+
+void fetcheco_clipoffset(struct dpu_fetchunit *fu, unsigned int x,
+			 unsigned int y)
+{
+	u32 val;
+
+	val = CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CLIPWINDOWOFFSET0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_clipoffset);
+
+void fetcheco_clipdimensions(struct dpu_fetchunit *fu, unsigned int w,
+			     unsigned int h)
+{
+	u32 val;
+
+	val = CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CLIPWINDOWDIMENSIONS0, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_clipdimensions);
+
+static void
+fetcheco_set_framedimensions(struct dpu_fetchunit *fu,
+			     unsigned int w, unsigned int h,
+			     bool deinterlace)
+{
+	u32 val;
+
+	if (deinterlace)
+		h /= 2;
+
+	val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, FRAMEDIMENSIONS, val);
+	mutex_unlock(&fu->mutex);
+}
+
+void fetcheco_frameresampling(struct dpu_fetchunit *fu, unsigned int x,
+			      unsigned int y)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FRAMERESAMPLING);
+	val &= ~(DELTAX_MASK | DELTAY_MASK);
+	val |= DELTAX(x) | DELTAY(y);
+	dpu_fu_write(fu, FRAMERESAMPLING, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_frameresampling);
+
+static void fetcheco_set_controltrigger(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONTROLTRIGGER, SHDTOKGEN);
+	mutex_unlock(&fu->mutex);
+}
+
+int fetcheco_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+	struct dpu_soc *dpu = fu->dpu;
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FETCHTYPE);
+	val &= FETCHTYPE_MASK;
+	mutex_unlock(&fu->mutex);
+
+	switch (val) {
+	case FETCHTYPE__DECODE:
+	case FETCHTYPE__LAYER:
+	case FETCHTYPE__WARP:
+	case FETCHTYPE__ECO:
+	case FETCHTYPE__PERSP:
+	case FETCHTYPE__ROT:
+	case FETCHTYPE__DECODEL:
+	case FETCHTYPE__LAYERL:
+	case FETCHTYPE__ROTL:
+		break;
+	default:
+		dev_warn(dpu->dev, "Invalid fetch type %u for FetchEco%d\n",
+				val, fu->id);
+		return -EINVAL;
+	}
+
+	*type = val;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fetcheco_fetchtype);
+
+dpu_block_id_t fetcheco_get_block_id(struct dpu_fetchunit *fu)
+{
+	switch (fu->id) {
+	case 0:
+		return ID_FETCHECO0;
+	case 1:
+		return ID_FETCHECO1;
+	case 2:
+		return ID_FETCHECO2;
+	case 9:
+		return ID_FETCHECO9;
+	default:
+		WARN_ON(1);
+	}
+
+	return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(fetcheco_get_block_id);
+
+struct dpu_fetchunit *dpu_fe_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+		if (fe_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fe_ids))
+		return ERR_PTR(-EINVAL);
+
+	fu = dpu->fe_priv[i];
+
+	mutex_lock(&fu->mutex);
+
+	if (fu->inuse) {
+		mutex_unlock(&fu->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	fu->inuse = true;
+
+	mutex_unlock(&fu->mutex);
+
+	return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fe_get);
+
+void dpu_fe_put(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+
+	fu->inuse = false;
+
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fe_put);
+
+static const struct dpu_fetchunit_ops fe_ops = {
+	.set_burstlength	= fetchunit_set_burstlength,
+	.set_baseaddress	= fetchunit_set_baseaddress,
+	.set_src_bpp		= fetchunit_set_src_bpp,
+	.set_src_stride		= fetchunit_set_src_stride,
+	.set_src_buf_dimensions	= fetcheco_set_src_buf_dimensions,
+	.set_fmt		= fetcheco_set_fmt,
+	.enable_src_buf		= fetchunit_enable_src_buf,
+	.disable_src_buf	= fetchunit_disable_src_buf,
+	.is_enabled		= fetchunit_is_enabled,
+	.set_framedimensions	= fetcheco_set_framedimensions,
+	.set_controltrigger	= fetcheco_set_controltrigger,
+	.get_stream_id		= fetchunit_get_stream_id,
+	.set_stream_id		= fetchunit_set_stream_id,
+};
+
+void _dpu_fe_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+		if (fe_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(fe_ids)))
+		return;
+
+	fu = dpu->fe_priv[i];
+
+	fetchunit_shden(fu, true);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BURSTBUFFERMANAGEMENT,
+			SETNUMBUFFERS(16) | SETBURSTLENGTH(16));
+	mutex_unlock(&fu->mutex);
+}
+
+int dpu_fe_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_fetcheco *fe;
+	struct dpu_fetchunit *fu;
+	int i;
+
+	fe = devm_kzalloc(dpu->dev, sizeof(*fe), GFP_KERNEL);
+	if (!fe)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+		if (fe_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fe_ids))
+		return -EINVAL;
+
+	fu = &fe->fu;
+	dpu->fe_priv[i] = fu;
+
+	fu->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+	if (!fu->pec_base)
+		return -ENOMEM;
+
+	fu->base = devm_ioremap(dpu->dev, base, SZ_128);
+	if (!fu->base)
+		return -ENOMEM;
+
+	fu->dpu = dpu;
+	fu->id = id;
+	fu->type = FU_T_FE;
+	fu->ops = &fe_ops;
+	fu->name = "fetcheco";
+
+	mutex_init(&fu->mutex);
+
+	_dpu_fe_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-fetchlayer.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-fetchlayer.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATUS		0x8
+#define BASEADDRESS(n)			(0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n)	(0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n)	(0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n)		(0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n)		(0x20 + (n) * 0x28)
+#define LAYEROFFSET(n)			(0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n)		(0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n)		(0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n)		(0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n)		(0x34 + (n) * 0x28)
+#define FRAMEDIMENSIONS			0x150
+#define FRAMERESAMPLING			0x154
+#define CONTROL				0x158
+#define TRIGGERENABLE			0x15C
+#define SHDLDREQ(lm)			((lm) & 0xFF)
+#define CONTROLTRIGGER			0x160
+#define START				0x164
+#define FETCHTYPE			0x168
+#define BURSTBUFFERPROPERTIES		0x16C
+#define STATUS				0x170
+#define HIDDENSTATUS			0x174
+
+struct dpu_fetchlayer {
+	struct dpu_fetchunit fu;
+	fetchtype_t fetchtype;
+};
+
+static void
+fetchlayer_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+				  unsigned int w, unsigned int h,
+				  u32 unused1, bool unused2)
+{
+	u32 val;
+
+	val = LINEWIDTH(w) | LINECOUNT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, SOURCEBUFFERDIMENSION(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchlayer_set_fmt(struct dpu_fetchunit *fu,
+			       u32 fmt,
+			       enum drm_color_encoding color_encoding,
+			       enum drm_color_range color_range,
+			       bool unused)
+{
+	u32 val, bits, shift;
+	int i, sub_id = fu->sub_id;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(sub_id));
+	val &= ~YUVCONVERSIONMODE_MASK;
+	val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__OFF);
+	dpu_fu_write(fu, LAYERPROPERTY(sub_id), val);
+	mutex_unlock(&fu->mutex);
+
+	for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+		if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+			bits = dpu_pixel_format_matrix[i].bits;
+			shift = dpu_pixel_format_matrix[i].shift;
+
+			mutex_lock(&fu->mutex);
+			dpu_fu_write(fu, COLORCOMPONENTBITS(sub_id), bits);
+			dpu_fu_write(fu, COLORCOMPONENTSHIFT(sub_id), shift);
+			mutex_unlock(&fu->mutex);
+			return;
+		}
+	}
+
+	WARN_ON(1);
+}
+
+static void
+fetchlayer_set_framedimensions(struct dpu_fetchunit *fu, unsigned int w,
+			       unsigned int h, bool unused)
+{
+	u32 val;
+
+	val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, FRAMEDIMENSIONS, val);
+	mutex_unlock(&fu->mutex);
+}
+
+void fetchlayer_rgb_constantcolor(struct dpu_fetchunit *fu,
+					u8 r, u8 g, u8 b, u8 a)
+{
+	u32 val;
+
+	val = rgb_color(r, g, b, a);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR(fu->id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchlayer_rgb_constantcolor);
+
+void fetchlayer_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+	u32 val;
+
+	val = yuv_color(y, u, v);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR(fu->id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchlayer_yuv_constantcolor);
+
+static void fetchlayer_set_controltrigger(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONTROLTRIGGER, SHDTOKGEN);
+	mutex_unlock(&fu->mutex);
+}
+
+int fetchlayer_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+	struct dpu_soc *dpu = fu->dpu;
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FETCHTYPE);
+	val &= FETCHTYPE_MASK;
+	mutex_unlock(&fu->mutex);
+
+	switch (val) {
+	case FETCHTYPE__DECODE:
+	case FETCHTYPE__LAYER:
+	case FETCHTYPE__WARP:
+	case FETCHTYPE__ECO:
+	case FETCHTYPE__PERSP:
+	case FETCHTYPE__ROT:
+	case FETCHTYPE__DECODEL:
+	case FETCHTYPE__LAYERL:
+	case FETCHTYPE__ROTL:
+		break;
+	default:
+		dev_warn(dpu->dev, "Invalid fetch type %u for FetchLayer%d\n",
+				val, fu->id);
+		return -EINVAL;
+	}
+
+	*type = val;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fetchlayer_fetchtype);
+
+struct dpu_fetchunit *dpu_fl_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fl_ids); i++)
+		if (fl_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fl_ids))
+		return ERR_PTR(-EINVAL);
+
+	fu = dpu->fl_priv[i];
+
+	mutex_lock(&fu->mutex);
+
+	if (fu->inuse) {
+		mutex_unlock(&fu->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	fu->inuse = true;
+
+	mutex_unlock(&fu->mutex);
+
+	return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fl_get);
+
+void dpu_fl_put(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+
+	fu->inuse = false;
+
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fl_put);
+
+static const struct dpu_fetchunit_ops fl_ops = {
+	.set_burstlength	= fetchunit_set_burstlength,
+	.set_baseaddress	= fetchunit_set_baseaddress,
+	.set_src_bpp		= fetchunit_set_src_bpp,
+	.set_src_stride		= fetchunit_set_src_stride,
+	.set_src_buf_dimensions	= fetchlayer_set_src_buf_dimensions,
+	.set_fmt		= fetchlayer_set_fmt,
+	.set_pixel_blend_mode	= fetchunit_set_pixel_blend_mode,
+	.enable_src_buf		= fetchunit_enable_src_buf,
+	.disable_src_buf	= fetchunit_disable_src_buf,
+	.is_enabled		= fetchunit_is_enabled,
+	.set_framedimensions	= fetchlayer_set_framedimensions,
+	.set_controltrigger	= fetchlayer_set_controltrigger,
+	.get_stream_id		= fetchunit_get_stream_id,
+	.set_stream_id		= fetchunit_set_stream_id,
+};
+
+void _dpu_fl_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fl_ids); i++)
+		if (fl_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(fl_ids)))
+		return;
+
+	fu = dpu->fl_priv[i];
+
+	fetchunit_baddr_autoupdate(fu, 0x0);
+	fetchunit_shden(fu, true);
+	fetchunit_shdldreq_sticky(fu, 0xFF);
+	fetchunit_disable_src_buf(fu);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BURSTBUFFERMANAGEMENT,
+			SETNUMBUFFERS(16) | SETBURSTLENGTH(16));
+	mutex_unlock(&fu->mutex);
+}
+
+int dpu_fl_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_fetchlayer *fl;
+	struct dpu_fetchunit *fu;
+	int ret;
+
+	fl = devm_kzalloc(dpu->dev, sizeof(*fl), GFP_KERNEL);
+	if (!fl)
+		return -ENOMEM;
+
+	fu = &fl->fu;
+	dpu->fl_priv[id] = fu;
+
+	fu->pec_base = devm_ioremap(dpu->dev, base, SZ_16);
+	if (!fu->pec_base)
+		return -ENOMEM;
+
+	fu->base = devm_ioremap(dpu->dev, base, SZ_512);
+	if (!fu->base)
+		return -ENOMEM;
+
+	fu->dpu = dpu;
+	fu->id = id;
+	fu->sub_id = 0;
+	fu->type = FU_T_FL;
+	fu->ops = &fl_ops;
+	fu->name = "fetchlayer";
+
+	mutex_init(&fu->mutex);
+
+	ret = fetchlayer_fetchtype(fu, &fl->fetchtype);
+	if (ret < 0)
+		return ret;
+
+	_dpu_fl_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-fetchunit.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-fetchunit.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_blend.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define BASEADDRESS(n)			(0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n)	(0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n)	(0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n)		(0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n)		(0x20 + (n) * 0x28)
+#define LAYEROFFSET(n)			(0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n)		(0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n)		(0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n)		(0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n)		(0x34 + (n) * 0x28)
+
+/* base address has to align to burst size */
+unsigned int fetchunit_burst_size_fixup_tkt343664(dma_addr_t baddr)
+{
+	unsigned int burst_size;
+
+	burst_size = 1 << (ffs(baddr) - 1);
+	burst_size = round_up(burst_size, 8);
+	burst_size = min(burst_size, 128U);
+
+	return burst_size;
+}
+EXPORT_SYMBOL_GPL(fetchunit_burst_size_fixup_tkt343664);
+
+/* fixup for burst size vs stride mismatch */
+unsigned int
+fetchunit_stride_fixup_tkt339017(unsigned int stride, unsigned int burst_size,
+				 dma_addr_t baddr, bool nonzero_mod)
+{
+	if (nonzero_mod)
+		stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
+	else
+		stride = round_up(stride, burst_size);
+
+	return stride;
+}
+EXPORT_SYMBOL_GPL(fetchunit_stride_fixup_tkt339017);
+
+void fetchunit_get_dprc(struct dpu_fetchunit *fu, void *data)
+{
+	if (WARN_ON(!fu))
+		return;
+
+	fu->dprc = data;
+}
+EXPORT_SYMBOL_GPL(fetchunit_get_dprc);
+
+void fetchunit_shden(struct dpu_fetchunit *fu, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_fu_write(fu, STATICCONTROL, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_shden);
+
+void fetchunit_baddr_autoupdate(struct dpu_fetchunit *fu, u8 layer_mask)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, STATICCONTROL);
+	val &= ~BASEADDRESSAUTOUPDATE_MASK;
+	val |= BASEADDRESSAUTOUPDATE(layer_mask);
+	dpu_fu_write(fu, STATICCONTROL, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_baddr_autoupdate);
+
+void fetchunit_shdldreq_sticky(struct dpu_fetchunit *fu, u8 layer_mask)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, STATICCONTROL);
+	val &= ~SHDLDREQSTICKY_MASK;
+	val |= SHDLDREQSTICKY(layer_mask);
+	dpu_fu_write(fu, STATICCONTROL, val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_shdldreq_sticky);
+
+void fetchunit_set_burstlength(struct dpu_fetchunit *fu,
+			       unsigned int x_offset, unsigned int mt_w,
+			       int bpp, dma_addr_t baddr, bool use_prefetch)
+{
+	struct dpu_soc *dpu = fu->dpu;
+	unsigned int burst_size, burst_length;
+	bool nonzero_mod = !!mt_w;
+	u32 val;
+
+	if (use_prefetch) {
+		/* consider PRG x offset to calculate buffer address */
+		if (nonzero_mod)
+			baddr += (x_offset % mt_w) * (bpp / 8);
+
+		burst_size = fetchunit_burst_size_fixup_tkt343664(baddr);
+		burst_length = burst_size / 8;
+	} else {
+		burst_length = 16;
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, BURSTBUFFERMANAGEMENT);
+	val &= ~SETBURSTLENGTH_MASK;
+	val |= SETBURSTLENGTH(burst_length);
+	dpu_fu_write(fu, BURSTBUFFERMANAGEMENT, val);
+	mutex_unlock(&fu->mutex);
+
+	dev_dbg(dpu->dev, "%s%d burst length is %u\n",
+					fu->name, fu->id, burst_length);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_burstlength);
+
+void fetchunit_set_baseaddress(struct dpu_fetchunit *fu, unsigned int width,
+			       unsigned int x_offset, unsigned int y_offset,
+			       unsigned int mt_w, unsigned int mt_h,
+			       int bpp, dma_addr_t baddr)
+{
+	unsigned int burst_size, stride;
+	bool nonzero_mod = !!mt_w;
+
+	if (nonzero_mod) {
+		/* consider PRG x offset to calculate buffer address */
+		baddr += (x_offset % mt_w) * (bpp / 8);
+
+		burst_size = fetchunit_burst_size_fixup_tkt343664(baddr);
+
+		stride = width * (bpp / 8);
+		stride = fetchunit_stride_fixup_tkt339017(stride, burst_size,
+							  baddr, nonzero_mod);
+
+		/* consider PRG y offset to calculate buffer address */
+		baddr += (y_offset % mt_h) * stride;
+	}
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BASEADDRESS(fu->sub_id), baddr);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_baseaddress);
+
+void fetchunit_set_src_bpp(struct dpu_fetchunit *fu, int bpp)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+	val &= ~0x3f0000;
+	val |= BITSPERPIXEL(bpp);
+	dpu_fu_write(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_src_bpp);
+
+/*
+ * The arguments width and bpp are valid only when use_prefetch is true.
+ * For fetcheco, since the pixel format has to be NV12 or NV21 when
+ * use_prefetch is true, we assume width stands for how many UV we have
+ * in bytes for one line, while bpp should be 8bits for every U or V component.
+ */
+void fetchunit_set_src_stride(struct dpu_fetchunit *fu,
+			      unsigned int width, unsigned int x_offset,
+			      unsigned int mt_w, int bpp, unsigned int stride,
+			      dma_addr_t baddr, bool use_prefetch)
+{
+	unsigned int burst_size;
+	bool nonzero_mod = !!mt_w;
+	u32 val;
+
+	if (use_prefetch) {
+		/* consider PRG x offset to calculate buffer address */
+		if (nonzero_mod)
+			baddr += (x_offset % mt_w) * (bpp / 8);
+
+		burst_size = fetchunit_burst_size_fixup_tkt343664(baddr);
+
+		stride = width * (bpp / 8);
+		stride = fetchunit_stride_fixup_tkt339017(stride, burst_size,
+							  baddr, nonzero_mod);
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+	val &= ~0xffff;
+	val |= STRIDE(stride);
+	dpu_fu_write(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_src_stride);
+
+void fetchunit_set_pixel_blend_mode(struct dpu_fetchunit *fu,
+				    unsigned int pixel_blend_mode, u16 alpha,
+				    u32 fb_format)
+{
+	u32 mode = 0, val;
+
+	if (pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
+	    pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
+		mode = ALPHACONSTENABLE;
+
+		switch (fb_format) {
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_ABGR8888:
+		case DRM_FORMAT_RGBA8888:
+		case DRM_FORMAT_BGRA8888:
+			mode |= ALPHASRCENABLE;
+			break;
+		}
+	}
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+	val &= ~(PREMULCONSTRGB | ALPHA_ENABLE_MASK | RGB_ENABLE_MASK);
+	val |= mode;
+	dpu_fu_write(fu, LAYERPROPERTY(fu->sub_id), val);
+
+	val = dpu_fu_read(fu, CONSTANTCOLOR(fu->sub_id));
+	val &= ~CONSTANTALPHA_MASK;
+	val |= CONSTANTALPHA(alpha >> 8);
+	dpu_fu_write(fu, CONSTANTCOLOR(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_pixel_blend_mode);
+
+void fetchunit_enable_src_buf(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+	val |= SOURCEBUFFERENABLE;
+	dpu_fu_write(fu, LAYERPROPERTY(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_enable_src_buf);
+
+void fetchunit_disable_src_buf(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+	val &= ~SOURCEBUFFERENABLE;
+	dpu_fu_write(fu, LAYERPROPERTY(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_disable_src_buf);
+
+bool fetchunit_is_enabled(struct dpu_fetchunit *fu)
+{
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+	mutex_unlock(&fu->mutex);
+
+	return !!(val & SOURCEBUFFERENABLE);
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_enabled);
+
+unsigned int fetchunit_get_stream_id(struct dpu_fetchunit *fu)
+{
+	if (WARN_ON(!fu))
+		return DPU_PLANE_SRC_DISABLED;
+
+	return fu->stream_id;
+}
+EXPORT_SYMBOL_GPL(fetchunit_get_stream_id);
+
+void fetchunit_set_stream_id(struct dpu_fetchunit *fu, unsigned int id)
+{
+	if (WARN_ON(!fu))
+		return;
+
+	switch (id) {
+	case DPU_PLANE_SRC_TO_DISP_STREAM0:
+	case DPU_PLANE_SRC_TO_DISP_STREAM1:
+	case DPU_PLANE_SRC_DISABLED:
+		fu->stream_id = id;
+		break;
+	default:
+		WARN_ON(1);
+	}
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_stream_id);
+
+bool fetchunit_is_fetchdecode(struct dpu_fetchunit *fu)
+{
+	if (WARN_ON(!fu))
+		return false;
+
+	return fu->type == FU_T_FD;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchdecode);
+
+bool fetchunit_is_fetcheco(struct dpu_fetchunit *fu)
+{
+	if (WARN_ON(!fu))
+		return false;
+
+	return fu->type == FU_T_FE;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetcheco);
+
+bool fetchunit_is_fetchlayer(struct dpu_fetchunit *fu)
+{
+	if (WARN_ON(!fu))
+		return false;
+
+	return fu->type == FU_T_FL;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchlayer);
+
+bool fetchunit_is_fetchwarp(struct dpu_fetchunit *fu)
+{
+	if (WARN_ON(!fu))
+		return false;
+
+	return fu->type == FU_T_FW;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchwarp);
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-fetchwarp.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-fetchwarp.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATUS		0x8
+#define BASEADDRESS(n)			(0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n)	(0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n)	(0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n)		(0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n)		(0x20 + (n) * 0x28)
+#define LAYEROFFSET(n)			(0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n)		(0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n)		(0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n)		(0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n)		(0x34 + (n) * 0x28)
+#define FRAMEDIMENSIONS			0x150
+#define FRAMERESAMPLING			0x154
+#define WARPCONTROL			0x158
+#define ARBSTARTX			0x15c
+#define ARBSTARTY			0x160
+#define ARBDELTA			0x164
+#define FIRPOSITIONS			0x168
+#define FIRCOEFFICIENTS			0x16c
+#define CONTROL				0x170
+#define TRIGGERENABLE			0x174
+#define SHDLDREQ(lm)			((lm) & 0xFF)
+#define CONTROLTRIGGER			0x178
+#define START				0x17c
+#define FETCHTYPE			0x180
+#define BURSTBUFFERPROPERTIES		0x184
+#define STATUS				0x188
+#define HIDDENSTATUS			0x18c
+
+struct dpu_fetchwarp {
+	struct dpu_fetchunit fu;
+	fetchtype_t fetchtype;
+};
+
+static void
+fetchwarp_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+				 unsigned int w, unsigned int h,
+				 u32 unused1, bool unused2)
+{
+	u32 val;
+
+	val = LINEWIDTH(w) | LINECOUNT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, SOURCEBUFFERDIMENSION(fu->sub_id), val);
+	mutex_unlock(&fu->mutex);
+}
+
+static void fetchwarp_set_fmt(struct dpu_fetchunit *fu,
+			      u32 fmt,
+			      enum drm_color_encoding color_encoding,
+			      enum drm_color_range color_range,
+			      bool unused)
+{
+	u32 val, bits, shift;
+	int i, sub_id = fu->sub_id;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, LAYERPROPERTY(sub_id));
+	val &= ~YUVCONVERSIONMODE_MASK;
+	dpu_fu_write(fu, LAYERPROPERTY(sub_id), val);
+	mutex_unlock(&fu->mutex);
+
+	for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+		if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+			bits = dpu_pixel_format_matrix[i].bits;
+			shift = dpu_pixel_format_matrix[i].shift;
+
+			mutex_lock(&fu->mutex);
+			dpu_fu_write(fu, COLORCOMPONENTBITS(sub_id), bits);
+			dpu_fu_write(fu, COLORCOMPONENTSHIFT(sub_id), shift);
+			mutex_unlock(&fu->mutex);
+			return;
+		}
+	}
+
+	WARN_ON(1);
+}
+
+static void
+fetchwarp_set_framedimensions(struct dpu_fetchunit *fu,
+			      unsigned int w, unsigned int h, bool unused)
+{
+	u32 val;
+
+	val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, FRAMEDIMENSIONS, val);
+	mutex_unlock(&fu->mutex);
+}
+
+void fetchwarp_rgb_constantcolor(struct dpu_fetchunit *fu,
+				 u8 r, u8 g, u8 b, u8 a)
+{
+	u32 val;
+
+	val = rgb_color(r, g, b, a);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR(fu->id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchwarp_rgb_constantcolor);
+
+void fetchwarp_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+	u32 val;
+
+	val = yuv_color(y, u, v);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONSTANTCOLOR(fu->id), val);
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchwarp_yuv_constantcolor);
+
+static void fetchwarp_set_controltrigger(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, CONTROLTRIGGER, SHDTOKGEN);
+	mutex_unlock(&fu->mutex);
+}
+
+int fetchwarp_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+	struct dpu_soc *dpu = fu->dpu;
+	u32 val;
+
+	mutex_lock(&fu->mutex);
+	val = dpu_fu_read(fu, FETCHTYPE);
+	val &= FETCHTYPE_MASK;
+	mutex_unlock(&fu->mutex);
+
+	switch (val) {
+	case FETCHTYPE__DECODE:
+	case FETCHTYPE__LAYER:
+	case FETCHTYPE__WARP:
+	case FETCHTYPE__ECO:
+	case FETCHTYPE__PERSP:
+	case FETCHTYPE__ROT:
+	case FETCHTYPE__DECODEL:
+	case FETCHTYPE__LAYERL:
+	case FETCHTYPE__ROTL:
+		break;
+	default:
+		dev_warn(dpu->dev, "Invalid fetch type %u for FetchWarp%d\n",
+				val, fu->id);
+		return -EINVAL;
+	}
+
+	*type = val;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fetchwarp_fetchtype);
+
+struct dpu_fetchunit *dpu_fw_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+		if (fw_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fw_ids))
+		return ERR_PTR(-EINVAL);
+
+	fu = dpu->fw_priv[i];
+
+	mutex_lock(&fu->mutex);
+
+	if (fu->inuse) {
+		mutex_unlock(&fu->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	fu->inuse = true;
+
+	mutex_unlock(&fu->mutex);
+
+	return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fw_get);
+
+void dpu_fw_put(struct dpu_fetchunit *fu)
+{
+	mutex_lock(&fu->mutex);
+
+	fu->inuse = false;
+
+	mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fw_put);
+
+static const struct dpu_fetchunit_ops fw_ops = {
+	.set_burstlength	= fetchunit_set_burstlength,
+	.set_baseaddress	= fetchunit_set_baseaddress,
+	.set_src_bpp		= fetchunit_set_src_bpp,
+	.set_src_stride		= fetchunit_set_src_stride,
+	.set_src_buf_dimensions	= fetchwarp_set_src_buf_dimensions,
+	.set_fmt		= fetchwarp_set_fmt,
+	.set_pixel_blend_mode	= fetchunit_set_pixel_blend_mode,
+	.enable_src_buf		= fetchunit_enable_src_buf,
+	.disable_src_buf	= fetchunit_disable_src_buf,
+	.is_enabled		= fetchunit_is_enabled,
+	.set_framedimensions	= fetchwarp_set_framedimensions,
+	.set_controltrigger	= fetchwarp_set_controltrigger,
+	.get_stream_id		= fetchunit_get_stream_id,
+	.set_stream_id		= fetchunit_set_stream_id,
+};
+
+void _dpu_fw_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_fetchunit *fu;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+		if (fw_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(fw_ids)))
+		return;
+
+	fu = dpu->fw_priv[i];
+
+	fetchunit_baddr_autoupdate(fu, 0x0);
+	fetchunit_shden(fu, true);
+	fetchunit_shdldreq_sticky(fu, 0xFF);
+	fetchunit_disable_src_buf(fu);
+
+	mutex_lock(&fu->mutex);
+	dpu_fu_write(fu, BURSTBUFFERMANAGEMENT,
+			SETNUMBUFFERS(16) | SETBURSTLENGTH(16));
+	mutex_unlock(&fu->mutex);
+}
+
+int dpu_fw_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_fetchwarp *fw;
+	struct dpu_fetchunit *fu;
+	int i, ret;
+
+	fw = devm_kzalloc(dpu->dev, sizeof(*fw), GFP_KERNEL);
+	if (!fw)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+		if (fw_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fw_ids))
+		return -EINVAL;
+
+	fu = &fw->fu;
+	dpu->fw_priv[i] = fu;
+
+	fu->pec_base = devm_ioremap(dpu->dev, base, SZ_16);
+	if (!fu->pec_base)
+		return -ENOMEM;
+
+	fu->base = devm_ioremap(dpu->dev, base, SZ_512);
+	if (!fu->base)
+		return -ENOMEM;
+
+	fu->dpu = dpu;
+	fu->id = id;
+	fu->sub_id = 0;
+	fu->type = FU_T_FW;
+	fu->ops = &fw_ops;
+	fu->name = "fetchwarp";
+
+	mutex_init(&fu->mutex);
+
+	ret = fetchwarp_fetchtype(fu, &fw->fetchtype);
+	if (ret < 0)
+		return ret;
+
+	_dpu_fw_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-framegen.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-framegen.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <drm/drm_mode.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define FGSTCTRL		0x8
+#define FGSYNCMODE_MASK		0x6
+#define HTCFG1			0xC
+#define HTOTAL(n)		((((n) - 1) & 0x3FFF) << 16)
+#define HACT(n)			((n) & 0x3FFF)
+#define HTCFG2			0x10
+#define HSEN			BIT(31)
+#define HSBP(n)			((((n) - 1) & 0x3FFF) << 16)
+#define HSYNC(n)		(((n) - 1) & 0x3FFF)
+#define VTCFG1			0x14
+#define VTOTAL(n)		((((n) - 1) & 0x3FFF) << 16)
+#define VACT(n)			((n) & 0x3FFF)
+#define VTCFG2			0x18
+#define VSEN			BIT(31)
+#define VSBP(n)			((((n) - 1) & 0x3FFF) << 16)
+#define VSYNC(n)		(((n) - 1) & 0x3FFF)
+#define INTCONFIG(n)		(0x1C + 4 * (n))
+#define EN			BIT(31)
+#define ROW(n)			(((n) & 0x3FFF) << 16)
+#define COL(n)			((n) & 0x3FFF)
+#define PKICKCONFIG		0x2C
+#define SKICKCONFIG		0x30
+#define SECSTATCONFIG		0x34
+#define FGSRCR1			0x38
+#define FGSRCR2			0x3C
+#define FGSRCR3			0x40
+#define FGSRCR4			0x44
+#define FGSRCR5			0x48
+#define FGSRCR6			0x4C
+#define FGKSDR			0x50
+#define PACFG			0x54
+#define STARTX(n)		(((n) + 1) & 0x3FFF)
+#define STARTY(n)		(((((n) + 1) & 0x3FFF)) << 16)
+#define SACFG			0x58
+#define FGINCTRL		0x5C
+#define FGDM_MASK		0x7
+#define ENPRIMALPHA		BIT(3)
+#define ENSECALPHA		BIT(4)
+#define FGINCTRLPANIC		0x60
+#define FGCCR			0x64
+#define CCALPHA(a)		(((a) & 0x1) << 30)
+#define CCRED(r)		(((r) & 0x3FF) << 20)
+#define CCGREEN(g)		(((g) & 0x3FF) << 10)
+#define CCBLUE(b)		((b) & 0x3FF)
+#define FGENABLE		0x68
+#define FGEN			BIT(0)
+#define FGSLR			0x6C
+#define FGENSTS			0x70
+#define ENSTS			BIT(0)
+#define FGTIMESTAMP		0x74
+#define LINEINDEX_MASK		0x3FFF
+#define LINEINDEX_SHIFT		0
+#define FRAMEINDEX_MASK		0xFFFFC000
+#define FRAMEINDEX_SHIFT	14
+#define FGCHSTAT		0x78
+#define SECSYNCSTAT		BIT(24)
+#define SFIFOEMPTY		BIT(16)
+#define FGCHSTATCLR		0x7C
+#define CLRSECSTAT		BIT(16)
+#define FGSKEWMON		0x80
+#define FGSFIFOMIN		0x84
+#define FGSFIFOMAX		0x88
+#define FGSFIFOFILLCLR		0x8C
+#define FGSREPD			0x90
+#define FGSRFTD			0x94
+
+#define KHZ			1000
+#define PLL_MIN_FREQ_HZ		648000000
+
+struct dpu_framegen {
+	void __iomem *base;
+	struct clk *clk_pll;
+	struct clk *clk_bypass;
+	struct clk *clk_disp;
+	struct clk *clk_disp_lpcg;
+	struct mutex mutex;
+	int id;
+	unsigned int encoder_type;
+	bool inuse;
+	bool use_bypass_clk;
+	bool side_by_side;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_fg_read(struct dpu_framegen *fg, unsigned int offset)
+{
+	return readl(fg->base + offset);
+}
+
+static inline void dpu_fg_write(struct dpu_framegen *fg,
+				unsigned int offset, u32 value)
+{
+	writel(value, fg->base + offset);
+}
+
+void framegen_enable(struct dpu_framegen *fg)
+{
+	dpu_fg_write(fg, FGENABLE, FGEN);
+}
+EXPORT_SYMBOL_GPL(framegen_enable);
+
+void framegen_disable(struct dpu_framegen *fg)
+{
+	dpu_fg_write(fg, FGENABLE, 0);
+}
+EXPORT_SYMBOL_GPL(framegen_disable);
+
+void framegen_enable_pixel_link(struct dpu_framegen *fg)
+{
+	struct dpu_soc *dpu = fg->dpu;
+	const struct dpu_data *data = dpu->data;
+
+	if (!(data->has_dual_ldb && fg->encoder_type == DRM_MODE_ENCODER_LVDS))
+		dpu_pxlink_set_mst_enable(fg->dpu, fg->id, true);
+
+	if (fg->encoder_type == DRM_MODE_ENCODER_DPI) {
+		dpu_pxlink_set_mst_valid(fg->dpu, fg->id, true);
+		dpu_pxlink_set_sync_ctrl(fg->dpu, fg->id, true);
+	}
+}
+EXPORT_SYMBOL_GPL(framegen_enable_pixel_link);
+
+void framegen_disable_pixel_link(struct dpu_framegen *fg)
+{
+	struct dpu_soc *dpu = fg->dpu;
+	const struct dpu_data *data = dpu->data;
+
+	if (fg->encoder_type == DRM_MODE_ENCODER_DPI) {
+		dpu_pxlink_set_mst_valid(fg->dpu, fg->id, false);
+		dpu_pxlink_set_sync_ctrl(fg->dpu, fg->id, false);
+	}
+
+	if (!(data->has_dual_ldb && fg->encoder_type == DRM_MODE_ENCODER_LVDS))
+		dpu_pxlink_set_mst_enable(fg->dpu, fg->id, false);
+}
+EXPORT_SYMBOL_GPL(framegen_disable_pixel_link);
+
+void framegen_shdtokgen(struct dpu_framegen *fg)
+{
+	dpu_fg_write(fg, FGSLR, SHDTOKGEN);
+}
+EXPORT_SYMBOL_GPL(framegen_shdtokgen);
+
+void framegen_syncmode(struct dpu_framegen *fg, fgsyncmode_t mode)
+{
+	u32 val;
+
+	val = dpu_fg_read(fg, FGSTCTRL);
+	val &= ~FGSYNCMODE_MASK;
+	val |= mode;
+	dpu_fg_write(fg, FGSTCTRL, val);
+
+	dpu_pxlink_set_dc_sync_mode(fg->dpu, mode != FGSYNCMODE__OFF);
+}
+EXPORT_SYMBOL_GPL(framegen_syncmode);
+
+void framegen_cfg_videomode(struct dpu_framegen *fg, struct drm_display_mode *m,
+			    bool side_by_side, unsigned int encoder_type)
+{
+	struct dpu_soc *dpu = fg->dpu;
+	u32 hact, htotal, hsync, hsbp;
+	u32 vact, vtotal, vsync, vsbp;
+	u32 kick_row, kick_col;
+	u32 val;
+	unsigned long disp_clock_rate, pll_clock_rate = 0;
+	int div = 0;
+
+	fg->side_by_side = side_by_side;
+	fg->encoder_type = encoder_type;
+
+	hact = m->crtc_hdisplay;
+	htotal = m->crtc_htotal;
+	hsync = m->crtc_hsync_end - m->crtc_hsync_start;
+	hsbp = m->crtc_htotal - m->crtc_hsync_start;
+
+	if (side_by_side) {
+		hact /= 2;
+		htotal /= 2;
+		hsync /= 2;
+		hsbp /= 2;
+	}
+
+	vact = m->crtc_vdisplay;
+	vtotal = m->crtc_vtotal;
+	vsync = m->crtc_vsync_end - m->crtc_vsync_start;
+	vsbp = m->crtc_vtotal - m->crtc_vsync_start;
+
+	/* video mode */
+	dpu_fg_write(fg, HTCFG1, HACT(hact)   | HTOTAL(htotal));
+	dpu_fg_write(fg, HTCFG2, HSYNC(hsync) | HSBP(hsbp) | HSEN);
+	dpu_fg_write(fg, VTCFG1, VACT(vact)   | VTOTAL(vtotal));
+	dpu_fg_write(fg, VTCFG2, VSYNC(vsync) | VSBP(vsbp) | VSEN);
+
+	kick_col = hact + 1;
+	kick_row = vact;
+	/*
+	 * FrameGen as slave needs to be kicked later for
+	 * one line comparing to the master.
+	 */
+	if (side_by_side && framegen_is_slave(fg))
+		kick_row++;
+
+	/* pkickconfig */
+	dpu_fg_write(fg, PKICKCONFIG, COL(kick_col) | ROW(kick_row) | EN);
+
+	/* skikconfig */
+	dpu_fg_write(fg, SKICKCONFIG, COL(kick_col) | ROW(kick_row) | EN);
+
+	/* primary and secondary area position config */
+	dpu_fg_write(fg, PACFG, STARTX(0) | STARTY(0));
+	dpu_fg_write(fg, SACFG, STARTX(0) | STARTY(0));
+
+	/* alpha */
+	val = dpu_fg_read(fg, FGINCTRL);
+	val &= ~(ENPRIMALPHA | ENSECALPHA);
+	dpu_fg_write(fg, FGINCTRL, val);
+
+	val = dpu_fg_read(fg, FGINCTRLPANIC);
+	val &= ~(ENPRIMALPHA | ENSECALPHA);
+	dpu_fg_write(fg, FGINCTRLPANIC, val);
+
+	/* constant color */
+	dpu_fg_write(fg, FGCCR, 0);
+
+	disp_clock_rate = m->crtc_clock * 1000;
+
+	if (encoder_type == DRM_MODE_ENCODER_TMDS) {
+		if (side_by_side)
+			dpu_pxlink_set_mst_addr(dpu, fg->id, fg->id ? 2 : 1);
+		else
+			dpu_pxlink_set_mst_addr(dpu, fg->id, 1);
+
+		clk_set_parent(fg->clk_disp, fg->clk_bypass);
+
+		fg->use_bypass_clk = true;
+	} else {
+		dpu_pxlink_set_mst_addr(dpu, fg->id,
+				encoder_type == DRM_MODE_ENCODER_DPI ? 1 : 0);
+
+		clk_set_parent(fg->clk_disp, fg->clk_pll);
+
+		/* find an even divisor for PLL */
+		do {
+			div += 2;
+			pll_clock_rate = disp_clock_rate * div;
+		} while (pll_clock_rate < PLL_MIN_FREQ_HZ);
+
+		clk_set_rate(fg->clk_pll, pll_clock_rate);
+		clk_set_rate(fg->clk_disp, disp_clock_rate);
+
+		fg->use_bypass_clk = false;
+	}
+}
+EXPORT_SYMBOL_GPL(framegen_cfg_videomode);
+
+void framegen_pkickconfig(struct dpu_framegen *fg, bool enable)
+{
+	u32 val;
+
+	val = dpu_fg_read(fg, PKICKCONFIG);
+	if (enable)
+		val |= EN;
+	else
+		val &= ~EN;
+	dpu_fg_write(fg, PKICKCONFIG, val);
+}
+EXPORT_SYMBOL_GPL(framegen_pkickconfig);
+
+void framegen_syncmode_fixup(struct dpu_framegen *fg, bool enable)
+{
+	u32 val;
+
+	val = dpu_fg_read(fg, SECSTATCONFIG);
+	if (enable)
+		val |= BIT(7);
+	else
+		val &= ~BIT(7);
+	dpu_fg_write(fg, SECSTATCONFIG, val);
+}
+EXPORT_SYMBOL_GPL(framegen_syncmode_fixup);
+
+void framegen_displaymode(struct dpu_framegen *fg, fgdm_t mode)
+{
+	u32 val;
+
+	val = dpu_fg_read(fg, FGINCTRL);
+	val &= ~FGDM_MASK;
+	val |= mode;
+	dpu_fg_write(fg, FGINCTRL, val);
+}
+EXPORT_SYMBOL_GPL(framegen_displaymode);
+
+void framegen_panic_displaymode(struct dpu_framegen *fg, fgdm_t mode)
+{
+	u32 val;
+
+	val = dpu_fg_read(fg, FGINCTRLPANIC);
+	val &= ~FGDM_MASK;
+	val |= mode;
+	dpu_fg_write(fg, FGINCTRLPANIC, val);
+}
+EXPORT_SYMBOL_GPL(framegen_panic_displaymode);
+
+void framegen_wait_done(struct dpu_framegen *fg, struct drm_display_mode *m)
+{
+	unsigned long timeout, pending_framedur_jiffies;
+	int frame_size = m->crtc_htotal * m->crtc_vtotal;
+	int dotclock, pending_framedur_ns;
+	u32 val;
+
+	dotclock = clk_get_rate(fg->clk_disp) / KHZ;
+	if (dotclock == 0) {
+		/* fall back to display mode's clock */
+		dotclock = m->crtc_clock;
+	}
+
+	/*
+	 * The SoC designer indicates that there are two pending frames
+	 * to complete in the worst case.
+	 * So, three pending frames are enough for sure.
+	 */
+	pending_framedur_ns = div_u64((u64) 3 * frame_size * 1000000, dotclock);
+	pending_framedur_jiffies = nsecs_to_jiffies(pending_framedur_ns);
+	if (pending_framedur_jiffies > (3 * HZ)) {
+		pending_framedur_jiffies = 3 * HZ;
+
+		dev_warn(fg->dpu->dev,
+			 "truncate FrameGen%d pending frame duration to 3sec\n",
+			 fg->id);
+	}
+	timeout = jiffies + pending_framedur_jiffies;
+
+	do {
+		val = dpu_fg_read(fg, FGENSTS);
+	} while ((val & ENSTS) && time_before(jiffies, timeout));
+
+	dev_dbg(fg->dpu->dev, "FrameGen%d pending frame duration is %ums\n",
+			 fg->id, jiffies_to_msecs(pending_framedur_jiffies));
+
+	if (val & ENSTS)
+		dev_err(fg->dpu->dev, "failed to wait for FrameGen%d done\n",
+			fg->id);
+}
+EXPORT_SYMBOL_GPL(framegen_wait_done);
+
+static inline u32 framegen_frame_index(u32 stamp)
+{
+	return (stamp & FRAMEINDEX_MASK) >> FRAMEINDEX_SHIFT;
+}
+
+static inline u32 framegen_line_index(u32 stamp)
+{
+	return (stamp & LINEINDEX_MASK) >> LINEINDEX_SHIFT;
+}
+
+void framegen_read_timestamp(struct dpu_framegen *fg,
+			     u32 *frame_index, u32 *line_index)
+{
+	u32 stamp;
+
+	stamp = dpu_fg_read(fg, FGTIMESTAMP);
+	*frame_index = framegen_frame_index(stamp);
+	*line_index = framegen_line_index(stamp);
+}
+EXPORT_SYMBOL_GPL(framegen_read_timestamp);
+
+void framegen_wait_for_frame_counter_moving(struct dpu_framegen *fg)
+{
+	u32 frame_index, line_index, last_frame_index;
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+	framegen_read_timestamp(fg, &frame_index, &line_index);
+	do {
+		last_frame_index = frame_index;
+		framegen_read_timestamp(fg, &frame_index, &line_index);
+	} while (last_frame_index == frame_index &&
+						time_before(jiffies, timeout));
+
+	if (last_frame_index == frame_index)
+		dev_err(fg->dpu->dev,
+			"failed to wait for FrameGen%d frame counter moving\n",
+			fg->id);
+	else
+		dev_dbg(fg->dpu->dev,
+			"FrameGen%d frame counter moves - last %u, curr %d\n",
+			fg->id, last_frame_index, frame_index);
+}
+EXPORT_SYMBOL_GPL(framegen_wait_for_frame_counter_moving);
+
+bool framegen_secondary_requests_to_read_empty_fifo(struct dpu_framegen *fg)
+{
+	u32 val;
+	bool empty;
+
+	val = dpu_fg_read(fg, FGCHSTAT);
+
+	empty = !!(val & SFIFOEMPTY);
+
+	if (empty)
+		dev_dbg(fg->dpu->dev,
+			"FrameGen%d secondary requests to read empty FIFO\n",
+			fg->id);
+
+	return empty;
+}
+EXPORT_SYMBOL_GPL(framegen_secondary_requests_to_read_empty_fifo);
+
+void framegen_secondary_clear_channel_status(struct dpu_framegen *fg)
+{
+	dpu_fg_write(fg, FGCHSTATCLR, CLRSECSTAT);
+}
+EXPORT_SYMBOL_GPL(framegen_secondary_clear_channel_status);
+
+bool framegen_secondary_is_syncup(struct dpu_framegen *fg)
+{
+	u32 val = dpu_fg_read(fg, FGCHSTAT);
+
+	return val & SECSYNCSTAT;
+}
+EXPORT_SYMBOL_GPL(framegen_secondary_is_syncup);
+
+void framegen_wait_for_secondary_syncup(struct dpu_framegen *fg)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+	bool syncup;
+
+	do {
+		syncup = framegen_secondary_is_syncup(fg);
+	} while (!syncup && time_before(jiffies, timeout));
+
+	if (syncup)
+		dev_dbg(fg->dpu->dev, "FrameGen%d secondary syncup\n", fg->id);
+	else
+		dev_err(fg->dpu->dev,
+			"failed to wait for FrameGen%d secondary syncup\n",
+			fg->id);
+}
+EXPORT_SYMBOL_GPL(framegen_wait_for_secondary_syncup);
+
+void framegen_enable_clock(struct dpu_framegen *fg)
+{
+	if (!fg->use_bypass_clk)
+		clk_prepare_enable(fg->clk_pll);
+	clk_prepare_enable(fg->clk_disp);
+	clk_prepare_enable(fg->clk_disp_lpcg);
+}
+EXPORT_SYMBOL_GPL(framegen_enable_clock);
+
+void framegen_disable_clock(struct dpu_framegen *fg)
+{
+	if (!fg->use_bypass_clk)
+		clk_disable_unprepare(fg->clk_pll);
+	clk_disable_unprepare(fg->clk_disp);
+	clk_disable_unprepare(fg->clk_disp_lpcg);
+}
+EXPORT_SYMBOL_GPL(framegen_disable_clock);
+
+bool framegen_is_master(struct dpu_framegen *fg)
+{
+	const struct dpu_data *data = fg->dpu->data;
+
+	return fg->id == data->master_stream_id;
+}
+EXPORT_SYMBOL_GPL(framegen_is_master);
+
+bool framegen_is_slave(struct dpu_framegen *fg)
+{
+	return !framegen_is_master(fg);
+}
+EXPORT_SYMBOL_GPL(framegen_is_slave);
+
+struct dpu_framegen *dpu_fg_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_framegen *fg;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fg_ids); i++)
+		if (fg_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(fg_ids))
+		return ERR_PTR(-EINVAL);
+
+	fg = dpu->fg_priv[i];
+
+	mutex_lock(&fg->mutex);
+
+	if (fg->inuse) {
+		mutex_unlock(&fg->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	fg->inuse = true;
+
+	mutex_unlock(&fg->mutex);
+
+	return fg;
+}
+EXPORT_SYMBOL_GPL(dpu_fg_get);
+
+void dpu_fg_put(struct dpu_framegen *fg)
+{
+	mutex_lock(&fg->mutex);
+
+	fg->inuse = false;
+
+	mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fg_put);
+
+struct dpu_framegen *dpu_aux_fg_peek(struct dpu_framegen *fg)
+{
+	return fg->dpu->fg_priv[fg->id ^ 1];
+}
+EXPORT_SYMBOL_GPL(dpu_aux_fg_peek);
+
+void _dpu_fg_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_framegen *fg;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fg_ids); i++)
+		if (fg_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(fg_ids)))
+		return;
+
+	fg = dpu->fg_priv[i];
+
+	framegen_syncmode(fg, FGSYNCMODE__OFF);
+}
+
+int dpu_fg_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long unused, unsigned long base)
+{
+	struct dpu_framegen *fg;
+
+	fg = devm_kzalloc(dpu->dev, sizeof(*fg), GFP_KERNEL);
+	if (!fg)
+		return -ENOMEM;
+
+	dpu->fg_priv[id] = fg;
+
+	fg->base = devm_ioremap(dpu->dev, base, SZ_256);
+	if (!fg->base)
+		return -ENOMEM;
+
+	fg->clk_pll = devm_clk_get(dpu->dev, id ? "pll1" : "pll0");
+	if (IS_ERR(fg->clk_pll))
+		return PTR_ERR(fg->clk_pll);
+
+	fg->clk_bypass = devm_clk_get(dpu->dev, "bypass0");
+	if (IS_ERR(fg->clk_bypass))
+		return PTR_ERR(fg->clk_bypass);
+
+	fg->clk_disp = devm_clk_get(dpu->dev, id ? "disp1" : "disp0");
+	if (IS_ERR(fg->clk_disp))
+		return PTR_ERR(fg->clk_disp);
+
+	fg->clk_disp_lpcg = devm_clk_get(dpu->dev, id ? "disp1_lpcg" : "disp0_lpcg");
+	if (IS_ERR(fg->clk_disp_lpcg))
+		return PTR_ERR(fg->clk_disp_lpcg);
+
+	fg->dpu = dpu;
+	fg->id = id;
+	mutex_init(&fg->mutex);
+
+	_dpu_fg_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-hscaler.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-hscaler.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC		0x8
+#define PIXENGCFG_DYNAMIC_SRC_SEL_MASK	0x3F
+
+#define SETUP1				0xC
+#define SCALE_FACTOR_MASK		0xFFFFF
+#define SCALE_FACTOR(n)			((n) & 0xFFFFF)
+#define SETUP2				0x10
+#define PHASE_OFFSET_MASK		0x1FFFFF
+#define PHASE_OFFSET(n)			((n) & 0x1FFFFF)
+#define CONTROL				0x14
+#define OUTPUT_SIZE_MASK		0x3FFF0000
+#define OUTPUT_SIZE(n)			((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
+#define FILTER_MODE			0x100
+#define SCALE_MODE			0x10
+#define MODE				0x1
+
+static const hs_src_sel_t src_sels[3][6] = {
+	{
+		HS_SRC_SEL__DISABLE,
+		HS_SRC_SEL__FETCHDECODE0,
+		HS_SRC_SEL__MATRIX4,
+		HS_SRC_SEL__VSCALER4,
+	}, {
+		HS_SRC_SEL__DISABLE,
+		HS_SRC_SEL__FETCHDECODE1,
+		HS_SRC_SEL__MATRIX5,
+		HS_SRC_SEL__VSCALER5,
+	}, {
+		HS_SRC_SEL__DISABLE,
+		HS_SRC_SEL__MATRIX9,
+		HS_SRC_SEL__VSCALER9,
+		HS_SRC_SEL__FILTER9,
+	},
+};
+
+struct dpu_hscaler {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+	/* see DPU_PLANE_SRC_xxx */
+	unsigned int stream_id;
+};
+
+static inline u32 dpu_pec_hs_read(struct dpu_hscaler *hs,
+				  unsigned int offset)
+{
+	return readl(hs->pec_base + offset);
+}
+
+static inline void dpu_pec_hs_write(struct dpu_hscaler *hs,
+				    unsigned int offset, u32 value)
+{
+	writel(value, hs->pec_base + offset);
+}
+
+static inline u32 dpu_hs_read(struct dpu_hscaler *hs, unsigned int offset)
+{
+	return readl(hs->base + offset);
+}
+
+static inline void dpu_hs_write(struct dpu_hscaler *hs,
+				unsigned int offset, u32 value)
+{
+	writel(value, hs->base + offset);
+}
+
+int hscaler_pixengcfg_dynamic_src_sel(struct dpu_hscaler *hs, hs_src_sel_t src)
+{
+	struct dpu_soc *dpu = hs->dpu;
+	const unsigned int hs_id_array[] = {4, 5, 9};
+	int i, j;
+	u32 val;
+
+	for (i = 0; i < ARRAY_SIZE(hs_id_array); i++)
+		if (hs_id_array[i] == hs->id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(hs_id_array)))
+		return -EINVAL;
+
+	mutex_lock(&hs->mutex);
+	for (j = 0; j < ARRAY_SIZE(src_sels[0]); j++) {
+		if (src_sels[i][j] == src) {
+			val = dpu_pec_hs_read(hs, PIXENGCFG_DYNAMIC);
+			val &= ~PIXENGCFG_DYNAMIC_SRC_SEL_MASK;
+			val |= src;
+			dpu_pec_hs_write(hs, PIXENGCFG_DYNAMIC, val);
+			mutex_unlock(&hs->mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&hs->mutex);
+
+	dev_err(dpu->dev, "Invalid source for HScaler%d\n", hs->id);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hscaler_pixengcfg_dynamic_src_sel);
+
+void hscaler_pixengcfg_clken(struct dpu_hscaler *hs, pixengcfg_clken_t clken)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_pec_hs_read(hs, PIXENGCFG_DYNAMIC);
+	val &= ~CLKEN_MASK;
+	val |= clken << CLKEN_MASK_SHIFT;
+	dpu_pec_hs_write(hs, PIXENGCFG_DYNAMIC, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_pixengcfg_clken);
+
+void hscaler_shden(struct dpu_hscaler *hs, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_hs_write(hs, STATICCONTROL, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_shden);
+
+void hscaler_setup1(struct dpu_hscaler *hs, u32 src, u32 dst)
+{
+	struct dpu_soc *dpu = hs->dpu;
+	u32 scale_factor;
+	u64 tmp64;
+
+	if (src == dst) {
+		scale_factor = 0x80000;
+	} else {
+		if (src > dst) {
+			tmp64 = (u64)((u64)dst * 0x80000);
+			do_div(tmp64, src);
+
+		} else {
+			tmp64 = (u64)((u64)src * 0x80000);
+			do_div(tmp64, dst);
+		}
+		scale_factor = (u32)tmp64;
+	}
+
+	WARN_ON(scale_factor > 0x80000);
+
+	mutex_lock(&hs->mutex);
+	dpu_hs_write(hs, SETUP1, SCALE_FACTOR(scale_factor));
+	mutex_unlock(&hs->mutex);
+
+	dev_dbg(dpu->dev, "Hscaler%d scale factor 0x%08x\n",
+						hs->id, scale_factor);
+}
+EXPORT_SYMBOL_GPL(hscaler_setup1);
+
+void hscaler_setup2(struct dpu_hscaler *hs, u32 phase_offset)
+{
+	mutex_lock(&hs->mutex);
+	dpu_hs_write(hs, SETUP2, PHASE_OFFSET(phase_offset));
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_setup2);
+
+void hscaler_output_size(struct dpu_hscaler *hs, u32 line_num)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, CONTROL);
+	val &= ~OUTPUT_SIZE_MASK;
+	val |= OUTPUT_SIZE(line_num);
+	dpu_hs_write(hs, CONTROL, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_output_size);
+
+void hscaler_filter_mode(struct dpu_hscaler *hs, scaler_filter_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, CONTROL);
+	val &= ~FILTER_MODE;
+	val |= m;
+	dpu_hs_write(hs, CONTROL, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_filter_mode);
+
+void hscaler_scale_mode(struct dpu_hscaler *hs, scaler_scale_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, CONTROL);
+	val &= ~SCALE_MODE;
+	val |= m;
+	dpu_hs_write(hs, CONTROL, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_scale_mode);
+
+void hscaler_mode(struct dpu_hscaler *hs, scaler_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, CONTROL);
+	val &= ~MODE;
+	val |= m;
+	dpu_hs_write(hs, CONTROL, val);
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_mode);
+
+bool hscaler_is_enabled(struct dpu_hscaler *hs)
+{
+	u32 val;
+
+	mutex_lock(&hs->mutex);
+	val = dpu_hs_read(hs, CONTROL);
+	mutex_unlock(&hs->mutex);
+
+	return (val & MODE) == SCALER_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(hscaler_is_enabled);
+
+dpu_block_id_t hscaler_get_block_id(struct dpu_hscaler *hs)
+{
+	switch (hs->id) {
+	case 4:
+		return ID_HSCALER4;
+	case 5:
+		return ID_HSCALER5;
+	case 9:
+		return ID_HSCALER9;
+	default:
+		WARN_ON(1);
+	}
+
+	return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(hscaler_get_block_id);
+
+unsigned int hscaler_get_stream_id(struct dpu_hscaler *hs)
+{
+	return hs->stream_id;
+}
+EXPORT_SYMBOL_GPL(hscaler_get_stream_id);
+
+void hscaler_set_stream_id(struct dpu_hscaler *hs, unsigned int id)
+{
+	switch (id) {
+	case DPU_PLANE_SRC_TO_DISP_STREAM0:
+	case DPU_PLANE_SRC_TO_DISP_STREAM1:
+	case DPU_PLANE_SRC_DISABLED:
+		hs->stream_id = id;
+		break;
+	default:
+		WARN_ON(1);
+	}
+}
+EXPORT_SYMBOL_GPL(hscaler_set_stream_id);
+
+struct dpu_hscaler *dpu_hs_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_hscaler *hs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+		if (hs_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(hs_ids))
+		return ERR_PTR(-EINVAL);
+
+	hs = dpu->hs_priv[i];
+
+	mutex_lock(&hs->mutex);
+
+	if (hs->inuse) {
+		mutex_unlock(&hs->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	hs->inuse = true;
+
+	mutex_unlock(&hs->mutex);
+
+	return hs;
+}
+EXPORT_SYMBOL_GPL(dpu_hs_get);
+
+void dpu_hs_put(struct dpu_hscaler *hs)
+{
+	mutex_lock(&hs->mutex);
+
+	hs->inuse = false;
+
+	mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_hs_put);
+
+void _dpu_hs_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_hscaler *hs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+		if (hs_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(hs_ids)))
+		return;
+
+	hs = dpu->hs_priv[i];
+
+	hscaler_shden(hs, true);
+	hscaler_setup2(hs, 0);
+	hscaler_pixengcfg_dynamic_src_sel(hs, HS_SRC_SEL__DISABLE);
+}
+
+int dpu_hs_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_hscaler *hs;
+	int i;
+
+	hs = devm_kzalloc(dpu->dev, sizeof(*hs), GFP_KERNEL);
+	if (!hs)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+		if (hs_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(hs_ids))
+		return -EINVAL;
+
+	dpu->hs_priv[i] = hs;
+
+	hs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_8);
+	if (!hs->pec_base)
+		return -ENOMEM;
+
+	hs->base = devm_ioremap(dpu->dev, base, SZ_1K);
+	if (!hs->base)
+		return -ENOMEM;
+
+	hs->dpu = dpu;
+	hs->id = id;
+
+	mutex_init(&hs->mutex);
+
+	_dpu_hs_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-layerblend.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-layerblend.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_blend.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC			0x8
+#define PIXENGCFG_DYNAMIC_PRIM_SEL_MASK		0x3F
+#define PIXENGCFG_DYNAMIC_SEC_SEL_MASK		0x3F00
+#define PIXENGCFG_DYNAMIC_SEC_SEL_SHIFT		8
+
+static const lb_prim_sel_t prim_sels[] = {
+	LB_PRIM_SEL__DISABLE,
+	LB_PRIM_SEL__BLITBLEND9,
+	LB_PRIM_SEL__CONSTFRAME0,
+	LB_PRIM_SEL__CONSTFRAME1,
+	LB_PRIM_SEL__CONSTFRAME4,
+	LB_PRIM_SEL__CONSTFRAME5,
+	LB_PRIM_SEL__MATRIX4,
+	LB_PRIM_SEL__HSCALER4,
+	LB_PRIM_SEL__VSCALER4,
+	LB_PRIM_SEL__MATRIX5,
+	LB_PRIM_SEL__HSCALER5,
+	LB_PRIM_SEL__VSCALER5,
+	LB_PRIM_SEL__LAYERBLEND0,
+	LB_PRIM_SEL__LAYERBLEND1,
+	LB_PRIM_SEL__LAYERBLEND2,
+	LB_PRIM_SEL__LAYERBLEND3,
+};
+
+#define PIXENGCFG_STATUS			0xC
+#define SHDTOKSEL				(0x3 << 3)
+#define SHDTOKSEL_SHIFT				3
+#define SHDLDSEL				(0x3 << 1)
+#define SHDLDSEL_SHIFT				1
+#define CONTROL					0xC
+#define OPERATION_MODE_MASK			BIT(0)
+#define BLENDCONTROL				0x10
+#define ALPHA(a)				(((a) & 0xFF) << 16)
+#define PRIM_C_BLD_FUNC__ONE_MINUS_CONST_ALPHA	0x7
+#define PRIM_C_BLD_FUNC__ONE_MINUS_SEC_ALPHA	0x5
+#define PRIM_C_BLD_FUNC__ZERO			0x0
+#define SEC_C_BLD_FUNC__CONST_ALPHA		(0x6 << 4)
+#define SEC_C_BLD_FUNC__SEC_ALPHA		(0x4 << 4)
+#define PRIM_A_BLD_FUNC__ZERO			(0x0 << 8)
+#define SEC_A_BLD_FUNC__ZERO			(0x0 << 12)
+#define POSITION				0x14
+#define XPOS(x)					((x) & 0x7FFF)
+#define YPOS(y)					(((y) & 0x7FFF) << 16)
+#define PRIMCONTROLWORD				0x18
+#define SECCONTROLWORD				0x1C
+
+struct dpu_layerblend {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_pec_lb_read(struct dpu_layerblend *lb,
+				  unsigned int offset)
+{
+	return readl(lb->pec_base + offset);
+}
+
+static inline void dpu_pec_lb_write(struct dpu_layerblend *lb,
+				    unsigned int offset, u32 value)
+{
+	writel(value, lb->pec_base + offset);
+}
+
+static inline u32 dpu_lb_read(struct dpu_layerblend *lb, unsigned int offset)
+{
+	return readl(lb->base + offset);
+}
+
+static inline void dpu_lb_write(struct dpu_layerblend *lb,
+				unsigned int offset, u32 value)
+{
+	writel(value, lb->base + offset);
+}
+
+int layerblend_pixengcfg_dynamic_prim_sel(struct dpu_layerblend *lb,
+					  lb_prim_sel_t prim)
+{
+	struct dpu_soc *dpu = lb->dpu;
+	int fixed_sels_num = ARRAY_SIZE(prim_sels) - 4;
+	int i;
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	for (i = 0; i < fixed_sels_num + lb->id; i++) {
+		if (prim_sels[i] == prim) {
+			val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+			val &= ~PIXENGCFG_DYNAMIC_PRIM_SEL_MASK;
+			val |= prim;
+			dpu_pec_lb_write(lb, PIXENGCFG_DYNAMIC, val);
+			mutex_unlock(&lb->mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&lb->mutex);
+
+	dev_err(dpu->dev, "Invalid primary source for LayerBlend%d\n", lb->id);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_dynamic_prim_sel);
+
+void layerblend_pixengcfg_dynamic_sec_sel(struct dpu_layerblend *lb,
+					  lb_sec_sel_t sec)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+	val &= ~PIXENGCFG_DYNAMIC_SEC_SEL_MASK;
+	val |= sec << PIXENGCFG_DYNAMIC_SEC_SEL_SHIFT;
+	dpu_pec_lb_write(lb, PIXENGCFG_DYNAMIC, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_dynamic_sec_sel);
+
+void layerblend_pixengcfg_clken(struct dpu_layerblend *lb,
+				pixengcfg_clken_t clken)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+	val &= ~CLKEN_MASK;
+	val |= clken << CLKEN_MASK_SHIFT;
+	dpu_pec_lb_write(lb, PIXENGCFG_DYNAMIC, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_clken);
+
+void layerblend_shden(struct dpu_layerblend *lb, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_lb_read(lb, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_lb_write(lb, STATICCONTROL, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shden);
+
+void layerblend_shdtoksel(struct dpu_layerblend *lb, lb_shadow_sel_t sel)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_lb_read(lb, STATICCONTROL);
+	val &= ~SHDTOKSEL;
+	val |= (sel << SHDTOKSEL_SHIFT);
+	dpu_lb_write(lb, STATICCONTROL, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shdtoksel);
+
+void layerblend_shdldsel(struct dpu_layerblend *lb, lb_shadow_sel_t sel)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_lb_read(lb, STATICCONTROL);
+	val &= ~SHDLDSEL;
+	val |= (sel << SHDLDSEL_SHIFT);
+	dpu_lb_write(lb, STATICCONTROL, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shdldsel);
+
+void layerblend_control(struct dpu_layerblend *lb, lb_mode_t mode)
+{
+	u32 val;
+
+	mutex_lock(&lb->mutex);
+	val = dpu_lb_read(lb, CONTROL);
+	val &= ~OPERATION_MODE_MASK;
+	val |= mode;
+	dpu_lb_write(lb, CONTROL, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_control);
+
+void layerblend_blendcontrol(struct dpu_layerblend *lb, unsigned int zpos,
+			     unsigned int pixel_blend_mode, u16 alpha)
+{
+	u32 val = PRIM_A_BLD_FUNC__ZERO | SEC_A_BLD_FUNC__ZERO;
+
+	if (zpos == 0) {
+		val |= PRIM_C_BLD_FUNC__ZERO | SEC_C_BLD_FUNC__CONST_ALPHA;
+		alpha = DRM_BLEND_ALPHA_OPAQUE;
+	} else {
+		switch (pixel_blend_mode) {
+		case DRM_MODE_BLEND_PIXEL_NONE:
+			val |= PRIM_C_BLD_FUNC__ONE_MINUS_CONST_ALPHA |
+			       SEC_C_BLD_FUNC__CONST_ALPHA;
+			break;
+		case DRM_MODE_BLEND_PREMULTI:
+			val |= PRIM_C_BLD_FUNC__ONE_MINUS_SEC_ALPHA |
+			       SEC_C_BLD_FUNC__CONST_ALPHA;
+			break;
+		case DRM_MODE_BLEND_COVERAGE:
+			val |= PRIM_C_BLD_FUNC__ONE_MINUS_SEC_ALPHA |
+			       SEC_C_BLD_FUNC__SEC_ALPHA;
+			break;
+		default:
+			break;
+		}
+	}
+
+	val |= ALPHA(alpha >> 8);
+
+	mutex_lock(&lb->mutex);
+	dpu_lb_write(lb, BLENDCONTROL, val);
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_blendcontrol);
+
+void layerblend_position(struct dpu_layerblend *lb, int x, int y)
+{
+	mutex_lock(&lb->mutex);
+	dpu_lb_write(lb, POSITION, XPOS(x) | YPOS(y));
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_position);
+
+struct dpu_layerblend *dpu_lb_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_layerblend *lb;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lb_ids); i++)
+		if (lb_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(lb_ids))
+		return ERR_PTR(-EINVAL);
+
+	lb = dpu->lb_priv[i];
+
+	mutex_lock(&lb->mutex);
+
+	if (lb->inuse) {
+		mutex_unlock(&lb->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	lb->inuse = true;
+
+	mutex_unlock(&lb->mutex);
+
+	return lb;
+}
+EXPORT_SYMBOL_GPL(dpu_lb_get);
+
+void dpu_lb_put(struct dpu_layerblend *lb)
+{
+	mutex_lock(&lb->mutex);
+
+	lb->inuse = false;
+
+	mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_lb_put);
+
+void _dpu_lb_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_layerblend *lb;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lb_ids); i++)
+		if (lb_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(lb_ids)))
+		return;
+
+	lb = dpu->lb_priv[i];
+
+	layerblend_pixengcfg_dynamic_prim_sel(lb, LB_PRIM_SEL__DISABLE);
+	layerblend_pixengcfg_dynamic_sec_sel(lb, LB_SEC_SEL__DISABLE);
+	layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
+	layerblend_shdldsel(lb, BOTH);
+	layerblend_shdtoksel(lb, BOTH);
+	layerblend_shden(lb, true);
+}
+
+int dpu_lb_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_layerblend *lb;
+	int ret;
+
+	lb = devm_kzalloc(dpu->dev, sizeof(*lb), GFP_KERNEL);
+	if (!lb)
+		return -ENOMEM;
+
+	dpu->lb_priv[id] = lb;
+
+	lb->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+	if (!lb->pec_base)
+		return -ENOMEM;
+
+	lb->base = devm_ioremap(dpu->dev, base, SZ_32);
+	if (!lb->base)
+		return -ENOMEM;
+
+	lb->dpu = dpu;
+	lb->id = id;
+	mutex_init(&lb->mutex);
+
+	ret = layerblend_pixengcfg_dynamic_prim_sel(lb, LB_PRIM_SEL__DISABLE);
+	if (ret < 0)
+		return ret;
+
+	_dpu_lb_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-prv.h
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-prv.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __DPU_PRV_H__
+#define __DPU_PRV_H__
+
+#include <linux/firmware/imx/sci.h>
+#include <drm/drm_fourcc.h>
+#include <video/dpu.h>
+
+#define STATICCONTROL			0x8
+#define SHDLDREQSTICKY(lm)		(((lm) & 0xFF) << 24)
+#define SHDLDREQSTICKY_MASK		(0xFF << 24)
+#define BASEADDRESSAUTOUPDATE(lm)	(((lm) & 0xFF) << 16)
+#define BASEADDRESSAUTOUPDATE_MASK	(0xFF << 16)
+#define SHDEN				BIT(0)
+#define BURSTBUFFERMANAGEMENT		0xC
+#define SETNUMBUFFERS(n)		((n) & 0xFF)
+#define SETBURSTLENGTH(n)		(((n) & 0x1F) << 8)
+#define SETBURSTLENGTH_MASK		0x1F00
+#define LINEMODE_MASK			0x80000000U
+#define LINEMODE_SHIFT			31U
+enum linemode {
+	/*
+	 * Mandatory setting for operation in the Display Controller.
+	 * Works also for Blit Engine with marginal performance impact.
+	 */
+	LINEMODE__DISPLAY = 0,
+	/* Recommended setting for operation in the Blit Engine. */
+	LINEMODE__BLIT = 1 << LINEMODE_SHIFT,
+};
+
+#define BITSPERPIXEL(bpp)		(((bpp) & 0x3F) << 16)
+#define STRIDE(n)			(((n) - 1) & 0xFFFF)
+#define LINEWIDTH(w)			(((w) - 1) & 0x3FFF)
+#define LINECOUNT(h)			((((h) - 1) & 0x3FFF) << 16)
+#define ITUFORMAT			BIT(31)
+#define R_BITS(n)			(((n) & 0xF) << 24)
+#define G_BITS(n)			(((n) & 0xF) << 16)
+#define B_BITS(n)			(((n) & 0xF) << 8)
+#define A_BITS(n)			((n) & 0xF)
+#define R_SHIFT(n)			(((n) & 0x1F) << 24)
+#define G_SHIFT(n)			(((n) & 0x1F) << 16)
+#define B_SHIFT(n)			(((n) & 0x1F) << 8)
+#define A_SHIFT(n)			((n) & 0x1F)
+#define Y_BITS(n)			R_BITS(n)
+#define Y_BITS_MASK			0xF000000
+#define U_BITS(n)			G_BITS(n)
+#define U_BITS_MASK			0xF0000
+#define V_BITS(n)			B_BITS(n)
+#define V_BITS_MASK			0xF00
+#define Y_SHIFT(n)			R_SHIFT(n)
+#define Y_SHIFT_MASK			0x1F000000
+#define U_SHIFT(n)			G_SHIFT(n)
+#define U_SHIFT_MASK			0x1F0000
+#define V_SHIFT(n)			B_SHIFT(n)
+#define V_SHIFT_MASK			0x1F00
+#define LAYERXOFFSET(x)			((x) & 0x7FFF)
+#define LAYERYOFFSET(y)			(((y) & 0x7FFF) << 16)
+#define CLIPWINDOWXOFFSET(x)		((x) & 0x7FFF)
+#define CLIPWINDOWYOFFSET(y)		(((y) & 0x7FFF) << 16)
+#define CLIPWINDOWWIDTH(w)		(((w) - 1) & 0x3FFF)
+#define CLIPWINDOWHEIGHT(h)		((((h) - 1) & 0x3FFF) << 16)
+#define CONSTANTALPHA_MASK		0xFF
+#define CONSTANTALPHA(n)		((n) & CONSTANTALPHA_MASK)
+#define	PALETTEENABLE			BIT(0)
+typedef enum {
+	TILE_FILL_ZERO,
+	TILE_FILL_CONSTANT,
+	TILE_PAD,
+	TILE_PAD_ZERO,
+} tilemode_t;
+#define ALPHASRCENABLE			BIT(8)
+#define ALPHACONSTENABLE		BIT(9)
+#define ALPHAMASKENABLE			BIT(10)
+#define ALPHATRANSENABLE		BIT(11)
+#define ALPHA_ENABLE_MASK		(ALPHASRCENABLE  | ALPHACONSTENABLE | \
+					 ALPHAMASKENABLE | ALPHATRANSENABLE)
+#define RGBALPHASRCENABLE		BIT(12)
+#define RGBALPHACONSTENABLE		BIT(13)
+#define RGBALPHAMASKENABLE		BIT(14)
+#define RGBALPHATRANSENABLE		BIT(15)
+#define RGB_ENABLE_MASK			(RGBALPHASRCENABLE   | \
+					 RGBALPHACONSTENABLE | \
+					 RGBALPHAMASKENABLE  | \
+					 RGBALPHATRANSENABLE)
+#define PREMULCONSTRGB			BIT(16)
+typedef enum {
+	YUVCONVERSIONMODE__OFF,
+	YUVCONVERSIONMODE__ITU601,
+	YUVCONVERSIONMODE__ITU601_FR,
+	YUVCONVERSIONMODE__ITU709,
+} yuvconversionmode_t;
+#define YUVCONVERSIONMODE_MASK		0x60000
+#define YUVCONVERSIONMODE(m)		(((m) & 0x3) << 17)
+#define GAMMAREMOVEENABLE		BIT(20)
+#define CLIPWINDOWENABLE		BIT(30)
+#define SOURCEBUFFERENABLE		BIT(31)
+#define EMPTYFRAME			BIT(31)
+#define FRAMEWIDTH(w)			(((w) - 1) & 0x3FFF)
+#define FRAMEHEIGHT(h)			((((h) - 1) & 0x3FFF) << 16)
+#define DELTAX_MASK			0x3F000
+#define DELTAY_MASK			0xFC0000
+#define DELTAX(x)			(((x) & 0x3F) << 12)
+#define DELTAY(y)			(((y) & 0x3F) << 18)
+#define YUV422UPSAMPLINGMODE_MASK	BIT(5)
+#define YUV422UPSAMPLINGMODE(m)		(((m) & 0x1) << 5)
+typedef enum {
+	YUV422UPSAMPLINGMODE__REPLICATE,
+	YUV422UPSAMPLINGMODE__INTERPOLATE,
+} yuv422upsamplingmode_t;
+#define INPUTSELECT_MASK		0x18
+#define INPUTSELECT(s)			(((s) & 0x3) << 3)
+typedef enum {
+	INPUTSELECT__INACTIVE,
+	INPUTSELECT__COMPPACK,
+	INPUTSELECT__ALPHAMASK,
+	INPUTSELECT__COORDINATE,
+} inputselect_t;
+#define RASTERMODE_MASK			0x7
+#define RASTERMODE(m)			((m) & 0x7)
+typedef enum {
+	RASTERMODE__NORMAL,
+	RASTERMODE__DECODE,
+	RASTERMODE__ARBITRARY,
+	RASTERMODE__PERSPECTIVE,
+	RASTERMODE__YUV422,
+	RASTERMODE__AFFINE,
+} rastermode_t;
+#define SHDTOKGEN			BIT(0)
+#define FETCHTYPE_MASK			0xF
+
+#define DPU_FRAC_PLANE_LAYER_NUM	8
+
+#define DPU_VPROC_CAP_HSCALER4	BIT(0)
+#define DPU_VPROC_CAP_VSCALER4	BIT(1)
+#define DPU_VPROC_CAP_HSCALER5	BIT(2)
+#define DPU_VPROC_CAP_VSCALER5	BIT(3)
+#define DPU_VPROC_CAP_FETCHECO0	BIT(4)
+#define DPU_VPROC_CAP_FETCHECO1	BIT(5)
+
+#define DPU_VPROC_CAP_HSCALE	(DPU_VPROC_CAP_HSCALER4 | \
+				 DPU_VPROC_CAP_HSCALER5)
+#define DPU_VPROC_CAP_VSCALE	(DPU_VPROC_CAP_VSCALER4 | \
+				 DPU_VPROC_CAP_VSCALER5)
+#define DPU_VPROC_CAP_FETCHECO	(DPU_VPROC_CAP_FETCHECO0 | \
+				 DPU_VPROC_CAP_FETCHECO1)
+
+struct dpu_unit {
+	char *name;
+	unsigned int num;
+	const unsigned int *ids;
+	const unsigned long *pec_ofss;	/* PixEngCFG */
+	const unsigned long *ofss;
+	const unsigned int *dprc_ids;
+};
+
+struct cm_reg_ofs {
+	u32 ipidentifier;
+	u32 lockunlock;
+	u32 lockstatus;
+	u32 userinterruptmask;
+	u32 interruptenable;
+	u32 interruptpreset;
+	u32 interruptclear;
+	u32 interruptstatus;
+	u32 userinterruptenable;
+	u32 userinterruptpreset;
+	u32 userinterruptclear;
+	u32 userinterruptstatus;
+	u32 generalpurpose;
+};
+
+struct dpu_data {
+	unsigned long cm_ofs;			/* common */
+	const struct dpu_unit *cfs;
+	const struct dpu_unit *decs;
+	const struct dpu_unit *eds;
+	const struct dpu_unit *fds;
+	const struct dpu_unit *fes;
+	const struct dpu_unit *fgs;
+	const struct dpu_unit *fls;
+	const struct dpu_unit *fws;
+	const struct dpu_unit *hss;
+	const struct dpu_unit *lbs;
+	const struct dpu_unit *sigs;
+	const struct dpu_unit *sts;
+	const struct dpu_unit *tcons;
+	const struct dpu_unit *vss;
+	const struct cm_reg_ofs *cm_reg_ofs;
+	const unsigned long *unused_irq;
+
+	unsigned int syncmode_min_prate;	/* need pixel combiner, KHz */
+	unsigned int singlemode_max_width;
+	unsigned int master_stream_id;
+
+	u32 plane_src_mask;
+
+	bool has_dual_ldb;
+};
+
+struct dpu_soc {
+	struct device		*dev;
+	const struct dpu_data	*data;
+	spinlock_t		lock;
+	struct list_head	list;
+
+	struct device		*pd_dc_dev;
+	struct device		*pd_pll0_dev;
+	struct device		*pd_pll1_dev;
+	struct device_link	*pd_dc_link;
+	struct device_link	*pd_pll0_link;
+	struct device_link	*pd_pll1_link;
+
+	void __iomem		*cm_reg;
+
+	int			id;
+	int			usecount;
+
+	int			irq_extdst0_shdload;
+	int			irq_extdst4_shdload;
+	int			irq_extdst1_shdload;
+	int			irq_extdst5_shdload;
+	int			irq_disengcfg_shdload0;
+	int			irq_disengcfg_framecomplete0;
+	int			irq_sig0_shdload;
+	int			irq_sig0_valid;
+	int			irq_disengcfg_shdload1;
+	int			irq_disengcfg_framecomplete1;
+	int			irq_sig1_shdload;
+	int			irq_sig1_valid;
+	int			irq_line_num;
+
+	bool			irq_chip_pm_get_extdst0_shdload;
+	bool			irq_chip_pm_get_extdst4_shdload;
+	bool			irq_chip_pm_get_extdst1_shdload;
+	bool			irq_chip_pm_get_extdst5_shdload;
+	bool			irq_chip_pm_get_disengcfg_shdload0;
+	bool			irq_chip_pm_get_disengcfg_framecomplete0;
+	bool			irq_chip_pm_get_sig0_shdload;
+	bool			irq_chip_pm_get_sig0_valid;
+	bool			irq_chip_pm_get_disengcfg_shdload1;
+	bool			irq_chip_pm_get_disengcfg_framecomplete1;
+	bool			irq_chip_pm_get_sig1_shdload;
+	bool			irq_chip_pm_get_sig1_valid;
+
+	struct irq_domain	*domain;
+
+	struct imx_sc_ipc	*dpu_ipc_handle;
+
+	struct dpu_constframe	*cf_priv[4];
+	struct dpu_disengcfg	*dec_priv[2];
+	struct dpu_extdst	*ed_priv[4];
+	struct dpu_fetchunit	*fd_priv[2];
+	struct dpu_fetchunit	*fe_priv[4];
+	struct dpu_framegen	*fg_priv[2];
+	struct dpu_fetchunit	*fl_priv[1];
+	struct dpu_fetchunit	*fw_priv[1];
+	struct dpu_hscaler	*hs_priv[3];
+	struct dpu_layerblend	*lb_priv[4];
+	struct dpu_signature	*sig_priv[2];
+	struct dpu_store	*st_priv[1];
+	struct dpu_tcon		*tcon_priv[2];
+	struct dpu_vscaler	*vs_priv[3];
+};
+
+int dpu_format_horz_chroma_subsampling(u32 format);
+int dpu_format_vert_chroma_subsampling(u32 format);
+int dpu_format_num_planes(u32 format);
+int dpu_format_plane_width(int width, u32 format, int plane);
+int dpu_format_plane_height(int height, u32 format, int plane);
+
+#define _DECLARE_DPU_UNIT_INIT_FUNC(block)			\
+void _dpu_##block##_init(struct dpu_soc *dpu, unsigned int id)	\
+
+_DECLARE_DPU_UNIT_INIT_FUNC(cf);
+_DECLARE_DPU_UNIT_INIT_FUNC(dec);
+_DECLARE_DPU_UNIT_INIT_FUNC(ed);
+_DECLARE_DPU_UNIT_INIT_FUNC(fd);
+_DECLARE_DPU_UNIT_INIT_FUNC(fe);
+_DECLARE_DPU_UNIT_INIT_FUNC(fg);
+_DECLARE_DPU_UNIT_INIT_FUNC(fl);
+_DECLARE_DPU_UNIT_INIT_FUNC(fw);
+_DECLARE_DPU_UNIT_INIT_FUNC(hs);
+_DECLARE_DPU_UNIT_INIT_FUNC(lb);
+_DECLARE_DPU_UNIT_INIT_FUNC(sig);
+_DECLARE_DPU_UNIT_INIT_FUNC(st);
+_DECLARE_DPU_UNIT_INIT_FUNC(tcon);
+_DECLARE_DPU_UNIT_INIT_FUNC(vs);
+
+#define DECLARE_DPU_UNIT_INIT_FUNC(block)			\
+int dpu_##block##_init(struct dpu_soc *dpu, unsigned int id,	\
+			 unsigned long pec_base, unsigned long base)
+
+DECLARE_DPU_UNIT_INIT_FUNC(cf);
+DECLARE_DPU_UNIT_INIT_FUNC(dec);
+DECLARE_DPU_UNIT_INIT_FUNC(ed);
+DECLARE_DPU_UNIT_INIT_FUNC(fd);
+DECLARE_DPU_UNIT_INIT_FUNC(fe);
+DECLARE_DPU_UNIT_INIT_FUNC(fg);
+DECLARE_DPU_UNIT_INIT_FUNC(fl);
+DECLARE_DPU_UNIT_INIT_FUNC(fw);
+DECLARE_DPU_UNIT_INIT_FUNC(hs);
+DECLARE_DPU_UNIT_INIT_FUNC(lb);
+DECLARE_DPU_UNIT_INIT_FUNC(sig);
+DECLARE_DPU_UNIT_INIT_FUNC(st);
+DECLARE_DPU_UNIT_INIT_FUNC(tcon);
+DECLARE_DPU_UNIT_INIT_FUNC(vs);
+
+static inline u32 dpu_pec_fu_read(struct dpu_fetchunit *fu, unsigned int offset)
+{
+	return readl(fu->pec_base + offset);
+}
+
+static inline void dpu_pec_fu_write(struct dpu_fetchunit *fu,
+				    unsigned int offset, u32 value)
+{
+	writel(value, fu->pec_base + offset);
+}
+
+static inline u32 dpu_fu_read(struct dpu_fetchunit *fu, unsigned int offset)
+{
+	return readl(fu->base + offset);
+}
+
+static inline void dpu_fu_write(struct dpu_fetchunit *fu,
+				unsigned int offset, u32 value)
+{
+	writel(value, fu->base + offset);
+}
+
+static inline u32 rgb_color(u8 r, u8 g, u8 b, u8 a)
+{
+	return (r << 24) | (g << 16) | (b << 8) | a;
+}
+
+static inline u32 yuv_color(u8 y, u8 u, u8 v)
+{
+	return (y << 24) | (u << 16) | (v << 8);
+}
+
+void tcon_get_pc(struct dpu_tcon *tcon, void *data);
+
+static const unsigned int cf_ids[] = {0, 1, 4, 5};
+static const unsigned int dec_ids[] = {0, 1};
+static const unsigned int ed_ids[] = {0, 1, 4, 5};
+static const unsigned int fd_ids[] = {0, 1};
+static const unsigned int fe_ids[] = {0, 1, 2, 9};
+static const unsigned int fg_ids[] = {0, 1};
+static const unsigned int fl_ids[] = {0};
+static const unsigned int fw_ids[] = {2};
+static const unsigned int hs_ids[] = {4, 5, 9};
+static const unsigned int lb_ids[] = {0, 1, 2, 3};
+static const unsigned int sig_ids[] = {0, 1};
+static const unsigned int st_ids[] = {9};
+static const unsigned int tcon_ids[] = {0, 1};
+static const unsigned int vs_ids[] = {4, 5, 9};
+
+static const unsigned int fd_dprc_ids[] = {3, 4};
+static const unsigned int fl_dprc_ids[] = {2};
+static const unsigned int fw_dprc_ids[] = {5};
+
+struct dpu_pixel_format {
+	u32 pixel_format;
+	u32 bits;
+	u32 shift;
+};
+
+static const struct dpu_pixel_format dpu_pixel_format_matrix[] = {
+	{
+		DRM_FORMAT_ARGB8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(8),
+		R_SHIFT(16) | G_SHIFT(8)  | B_SHIFT(0)  | A_SHIFT(24),
+	}, {
+		DRM_FORMAT_XRGB8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(16) | G_SHIFT(8)  | B_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_ABGR8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(8),
+		R_SHIFT(0)  | G_SHIFT(8)  | B_SHIFT(16) | A_SHIFT(24),
+	}, {
+		DRM_FORMAT_XBGR8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(0)  | G_SHIFT(8)  | B_SHIFT(16) | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_RGBA8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(8),
+		R_SHIFT(24) | G_SHIFT(16) | B_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_RGBX8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(24) | G_SHIFT(16) | B_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_BGRA8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(8),
+		R_SHIFT(8)  | G_SHIFT(16) | B_SHIFT(24) | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_BGRX8888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(8)  | G_SHIFT(16) | B_SHIFT(24) | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_RGB888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(16) | G_SHIFT(8)  | B_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_BGR888,
+		R_BITS(8)   | G_BITS(8)   | B_BITS(8)   | A_BITS(0),
+		R_SHIFT(0)  | G_SHIFT(8)  | B_SHIFT(16) | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_RGB565,
+		R_BITS(5)   | G_BITS(6)   | B_BITS(5)   | A_BITS(0),
+		R_SHIFT(11) | G_SHIFT(5)  | B_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_YUYV,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(8)  | V_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_UYVY,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(8)  | U_SHIFT(0)  | V_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV12,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(0)  | V_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV21,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(8)  | V_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV16,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(0)  | V_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV61,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(8)  | V_SHIFT(0)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV24,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(0)  | V_SHIFT(8)  | A_SHIFT(0),
+	}, {
+		DRM_FORMAT_NV42,
+		Y_BITS(8)   | U_BITS(8)   | V_BITS(8)   | A_BITS(0),
+		Y_SHIFT(0)  | U_SHIFT(8)  | V_SHIFT(0)  | A_SHIFT(0),
+	},
+};
+
+int dpu_sc_misc_get_handle(struct dpu_soc *dpu);
+int dpu_pxlink_set_mst_addr(struct dpu_soc *dpu, int disp_id, u32 val);
+int dpu_pxlink_set_mst_enable(struct dpu_soc *dpu, int disp_id, bool enable);
+int dpu_pxlink_set_mst_valid(struct dpu_soc *dpu, int disp_id, bool enable);
+int dpu_pxlink_set_sync_ctrl(struct dpu_soc *dpu, int disp_id, bool enable);
+int dpu_pxlink_set_dc_sync_mode(struct dpu_soc *dpu, bool enable);
+int dpu_sc_misc_init(struct dpu_soc *dpu);
+#endif				/* __DPU_PRV_H__ */
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-sc-misc.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-sc-misc.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <dt-bindings/firmware/imx/rsrc.h>
+#include "dpu-prv.h"
+
+static inline int
+dpu_sc_misc_set_ctrl(struct dpu_soc *dpu, u32 rsc, u8 ctrl, u32 val)
+{
+	return imx_sc_misc_set_control(dpu->dpu_ipc_handle, rsc, ctrl, val);
+}
+
+int dpu_sc_misc_get_handle(struct dpu_soc *dpu)
+{
+	return imx_scu_get_handle(&dpu->dpu_ipc_handle);
+}
+
+int dpu_pxlink_set_mst_addr(struct dpu_soc *dpu, int disp_id, u32 val)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+	u8 ctrl = disp_id ?
+		IMX_SC_C_PXL_LINK_MST2_ADDR : IMX_SC_C_PXL_LINK_MST1_ADDR;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, ctrl, val);
+}
+
+int dpu_pxlink_set_mst_enable(struct dpu_soc *dpu, int disp_id, bool enable)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+	u8 ctrl = disp_id ?
+		IMX_SC_C_PXL_LINK_MST2_ENB: IMX_SC_C_PXL_LINK_MST1_ENB;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, ctrl, enable);
+}
+
+int dpu_pxlink_set_mst_valid(struct dpu_soc *dpu, int disp_id, bool enable)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+	u8 ctrl = disp_id ?
+		IMX_SC_C_PXL_LINK_MST2_VLD : IMX_SC_C_PXL_LINK_MST1_VLD;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, ctrl, enable);
+}
+
+int dpu_pxlink_set_sync_ctrl(struct dpu_soc *dpu, int disp_id, bool enable)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+	u8 ctrl = disp_id ? IMX_SC_C_SYNC_CTRL1 : IMX_SC_C_SYNC_CTRL0;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, ctrl, enable);
+}
+
+int dpu_pxlink_set_dc_sync_mode(struct dpu_soc *dpu, bool enable)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, IMX_SC_C_MODE, enable);
+}
+
+/* KACHUNK_CNT is needed for blit engine */
+int dpu_sc_misc_set_kachunk_cnt(struct dpu_soc *dpu, u32 cnt)
+{
+	u32 rsc = dpu->id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
+
+	return dpu_sc_misc_set_ctrl(dpu, rsc, IMX_SC_C_KACHUNK_CNT, cnt);
+}
+
+int dpu_sc_misc_init(struct dpu_soc *dpu)
+{
+	int disp_id, ret = 0;
+
+	for (disp_id = 0; disp_id < 2; disp_id++) {
+		ret |= dpu_pxlink_set_mst_addr(dpu, disp_id, 0);
+		ret |= dpu_pxlink_set_mst_enable(dpu, disp_id, false);
+		ret |= dpu_pxlink_set_mst_valid(dpu, disp_id, false);
+		ret |= dpu_pxlink_set_sync_ctrl(dpu, disp_id, false);
+	}
+
+	ret |= dpu_sc_misc_set_kachunk_cnt(dpu, 32);
+
+	return ret;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-signature.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-signature.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2019,2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include "dpu-prv.h"
+
+#define STATICCONTROL		0x8
+#define SHDLDSEL		BIT(4)
+#define LOCAL			0
+#define GLOBAL			BIT(4)
+#define PANICCOLOR		0xC
+#define EVALCONTRL(n)		(0x10 + (n) * 0x24)
+#define ENGLOBALPANIC		BIT(17)
+#define ENLOCALPANIC		BIT(16)
+#define ALPHAINV		BIT(9)
+#define ALPHAMASK		BIT(8)
+#define ENCRC			BIT(1)
+#define ENEVALWIN		BIT(0)
+#define EVALUPPERLEFT(n)	(0x14 + (n) * 0x24)
+#define EVALLOWERRIGHT(n)	(0x18 + (n) * 0x24)
+#define YEVAL(y)		(((y) & 0x3FFF) << 16)
+#define XEVAL(x)		((x) & 0x3FFF)
+#define SIGCRCREDREF(n)		(0x1C + (n) * 0x24)
+#define SIGCRCGREENREF(n)	(0x20 + (n) * 0x24)
+#define SIGCRCBLUEREF(n)	(0x24 + (n) * 0x24)
+#define SIGCRCRED(n)		(0x28 + (n) * 0x24)
+#define SIGCRCGREEN(n)		(0x2C + (n) * 0x24)
+#define SIGCRCBLUE(n)		(0x30 + (n) * 0x24)
+#define SHADOWLOAD		0x130
+#define SHDLDREQ(n)		BIT(n)
+#define CONTINUOUSMODE		0x134
+#define ENCONT			BIT(0)
+#define SOFTWAREKICK		0x138
+#define KICK			BIT(0)
+#define STATUS			0x13C
+#define STSSIGIDLE		BIT(20)
+#define STSSIGVALID		BIT(16)
+#define STSSIGERROR(n)		BIT(n)
+#define STSSIGERROR_MASK	0xFF
+
+struct dpu_signature {
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_sig_read(struct dpu_signature *sig, unsigned int offset)
+{
+	return readl(sig->base + offset);
+}
+
+static inline void dpu_sig_write(struct dpu_signature *sig,
+				 unsigned int offset, u32 value)
+{
+	writel(value, sig->base + offset);
+}
+
+void signature_shden(struct dpu_signature *sig, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_sig_write(sig, STATICCONTROL, val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_shden);
+
+void signature_shdldsel_local(struct dpu_signature *sig)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATICCONTROL);
+	val &= ~GLOBAL;
+	dpu_sig_write(sig, STATICCONTROL, val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_shdldsel_local);
+
+void signature_shdldsel_global(struct dpu_signature *sig)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATICCONTROL);
+	dpu_sig_write(sig, STATICCONTROL, val | GLOBAL);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_shdldsel_global);
+
+void
+signature_global_panic(struct dpu_signature *sig, unsigned int win, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, EVALCONTRL(win));
+	if (enable)
+		val |= ENGLOBALPANIC;
+	else
+		val &= ~ENGLOBALPANIC;
+	dpu_sig_write(sig, EVALCONTRL(win), val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_global_panic);
+
+void
+signature_local_panic(struct dpu_signature *sig, unsigned int win, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, EVALCONTRL(win));
+	if (enable)
+		val |= ENLOCALPANIC;
+	else
+		val &= ~ENLOCALPANIC;
+	dpu_sig_write(sig, EVALCONTRL(win), val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_local_panic);
+
+void
+signature_alpha_mask(struct dpu_signature *sig, unsigned int win, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, EVALCONTRL(win));
+	if (enable)
+		val |= ALPHAMASK;
+	else
+		val &= ~ALPHAMASK;
+	dpu_sig_write(sig, EVALCONTRL(win), val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_alpha_mask);
+
+void signature_crc(struct dpu_signature *sig, unsigned int win, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, EVALCONTRL(win));
+	if (enable)
+		val |= ENCRC;
+	else
+		val &= ~ENCRC;
+	dpu_sig_write(sig, EVALCONTRL(win), val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_crc);
+
+void
+signature_eval_win(struct dpu_signature *sig, unsigned int win, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, EVALCONTRL(win));
+	if (enable)
+		val |= ENEVALWIN;
+	else
+		val &= ~ENEVALWIN;
+	dpu_sig_write(sig, EVALCONTRL(win), val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_eval_win);
+
+void signature_win(struct dpu_signature *sig, unsigned int win,
+		   int xul, int yul, int xlr, int ylr)
+{
+	mutex_lock(&sig->mutex);
+	dpu_sig_write(sig, EVALUPPERLEFT(win),  XEVAL(xul)   | YEVAL(yul));
+	dpu_sig_write(sig, EVALLOWERRIGHT(win), XEVAL(--xlr) | YEVAL(--ylr));
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_win);
+
+void signature_crc_value(struct dpu_signature *sig, unsigned int win,
+			 u32 *red, u32 *green, u32 *blue)
+{
+	mutex_lock(&sig->mutex);
+	*red   = dpu_sig_read(sig, SIGCRCRED(win));
+	*green = dpu_sig_read(sig, SIGCRCGREEN(win));
+	*blue  = dpu_sig_read(sig, SIGCRCBLUE(win));
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_crc_value);
+
+void signature_shdldreq(struct dpu_signature *sig, u8 win_mask)
+{
+	mutex_lock(&sig->mutex);
+	dpu_sig_write(sig, SHADOWLOAD, win_mask);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_shdldreq);
+
+void signature_continuous_mode(struct dpu_signature *sig, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, CONTINUOUSMODE);
+	if (enable)
+		val |= ENCONT;
+	else
+		val &= ~ENCONT;
+	dpu_sig_write(sig, CONTINUOUSMODE, val);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_continuous_mode);
+
+void signature_kick(struct dpu_signature *sig)
+{
+	mutex_lock(&sig->mutex);
+	dpu_sig_write(sig, SOFTWAREKICK, KICK);
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(signature_kick);
+
+bool signature_is_idle(struct dpu_signature *sig)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATUS);
+	mutex_unlock(&sig->mutex);
+
+	return !!(val & STSSIGIDLE);
+}
+EXPORT_SYMBOL_GPL(signature_is_idle);
+
+void signature_wait_for_idle(struct dpu_signature *sig)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+	bool idle;
+
+	do {
+		idle = signature_is_idle(sig);
+	} while (!idle && time_before(jiffies, timeout));
+
+	if (idle)
+		dev_dbg(sig->dpu->dev, "Signature%d is idle\n", sig->id);
+	else
+		dev_err(sig->dpu->dev,
+			"failed to wait for Signature%d idle\n", sig->id);
+}
+EXPORT_SYMBOL_GPL(signature_wait_for_idle);
+
+bool signature_is_valid(struct dpu_signature *sig)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATUS);
+	mutex_unlock(&sig->mutex);
+
+	return !!(val & STSSIGVALID);
+}
+EXPORT_SYMBOL_GPL(signature_is_valid);
+
+bool signature_is_error(struct dpu_signature *sig, u8 *err_win_mask)
+{
+	u32 val;
+
+	mutex_lock(&sig->mutex);
+	val = dpu_sig_read(sig, STATUS);
+	mutex_unlock(&sig->mutex);
+
+	*err_win_mask = val & STSSIGERROR_MASK;
+
+	return !!(*err_win_mask);
+}
+EXPORT_SYMBOL_GPL(signature_is_error);
+
+struct dpu_signature *dpu_sig_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_signature *sig;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sig_ids); i++)
+		if (sig_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(sig_ids))
+		return ERR_PTR(-EINVAL);
+
+	sig = dpu->sig_priv[i];
+
+	mutex_lock(&sig->mutex);
+
+	if (sig->inuse) {
+		mutex_unlock(&sig->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	sig->inuse = true;
+
+	mutex_unlock(&sig->mutex);
+
+	return sig;
+}
+EXPORT_SYMBOL_GPL(dpu_sig_get);
+
+void dpu_sig_put(struct dpu_signature *sig)
+{
+	mutex_lock(&sig->mutex);
+
+	sig->inuse = false;
+
+	mutex_unlock(&sig->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_sig_put);
+
+struct dpu_signature *dpu_aux_sig_peek(struct dpu_signature *sig)
+{
+	return sig->dpu->sig_priv[sig->id ^ 1];
+}
+EXPORT_SYMBOL_GPL(dpu_aux_sig_peek);
+
+void _dpu_sig_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_signature *sig;
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(sig_ids); i++)
+		if (sig_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(sig_ids)))
+		return;
+
+	sig = dpu->sig_priv[i];
+
+	signature_shden(sig, true);
+	signature_shdldsel_local(sig);
+	for (j = 0; j < MAX_DPU_SIGNATURE_WIN_NUM; j++) {
+		signature_global_panic(sig, j, false);
+		signature_local_panic(sig, j, false);
+		signature_alpha_mask(sig, j, false);
+		signature_crc(sig, j, false);
+		signature_eval_win(sig, j, false);
+		signature_continuous_mode(sig, false);
+	}
+}
+
+int dpu_sig_init(struct dpu_soc *dpu, unsigned int id,
+			unsigned long unused, unsigned long base)
+{
+	struct dpu_signature *sig;
+
+	sig = devm_kzalloc(dpu->dev, sizeof(*sig), GFP_KERNEL);
+	if (!sig)
+		return -ENOMEM;
+
+	dpu->sig_priv[id] = sig;
+
+	sig->base = devm_ioremap(dpu->dev, base, SZ_512);
+	if (!sig->base)
+		return -ENOMEM;
+
+	sig->dpu = dpu;
+	sig->id = id;
+	mutex_init(&sig->mutex);
+
+	_dpu_sig_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-store.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-store.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATIC		0x8
+#define DIV(n)				(((n) & 0xFF) << 16)
+#define DIV_RESET			0x80
+
+struct dpu_store {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_pec_st_read(struct dpu_store *st, unsigned int offset)
+{
+	return readl(st->pec_base + offset);
+}
+
+static inline void dpu_pec_st_write(struct dpu_store *st,
+				    unsigned int offset, u32 value)
+{
+	writel(value, st->pec_base + offset);
+}
+
+void store_pixengcfg_syncmode_fixup(struct dpu_store *st, bool enable)
+{
+	struct dpu_soc *dpu;
+	u32 val;
+
+	if (!st)
+		return;
+
+	dpu = st->dpu;
+
+	mutex_lock(&st->mutex);
+	val = dpu_pec_st_read(st, PIXENGCFG_STATIC);
+	if (enable)
+		val |= BIT(16);
+	else
+		val &= ~BIT(16);
+	dpu_pec_st_write(st, PIXENGCFG_STATIC, val);
+	mutex_unlock(&st->mutex);
+}
+EXPORT_SYMBOL_GPL(store_pixengcfg_syncmode_fixup);
+
+struct dpu_store *dpu_st_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_store *st;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(st_ids); i++)
+		if (st_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(st_ids))
+		return ERR_PTR(-EINVAL);
+
+	st = dpu->st_priv[i];
+
+	mutex_lock(&st->mutex);
+
+	if (st->inuse) {
+		mutex_unlock(&st->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	st->inuse = true;
+
+	mutex_unlock(&st->mutex);
+
+	return st;
+}
+EXPORT_SYMBOL_GPL(dpu_st_get);
+
+void dpu_st_put(struct dpu_store *st)
+{
+	mutex_lock(&st->mutex);
+
+	st->inuse = false;
+
+	mutex_unlock(&st->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_st_put);
+
+void _dpu_st_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_store *st;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(st_ids); i++)
+		if (st_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(st_ids)))
+		return;
+
+	st = dpu->st_priv[i];
+
+	dpu_pec_st_write(st, PIXENGCFG_STATIC, SHDEN | DIV(DIV_RESET));
+}
+
+int dpu_st_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_store *st;
+	int i;
+
+	st = devm_kzalloc(dpu->dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(st_ids); i++)
+		if (st_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(st_ids))
+		return -EINVAL;
+
+	dpu->st_priv[i] = st;
+
+	st->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_32);
+	if (!st->pec_base)
+		return -ENOMEM;
+
+	st->base = devm_ioremap(dpu->dev, base, SZ_256);
+	if (!st->base)
+		return -ENOMEM;
+
+	st->dpu = dpu;
+	st->id = id;
+	mutex_init(&st->mutex);
+
+	_dpu_st_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-tcon.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-tcon.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include <video/imx8-pc.h>
+#include "dpu-prv.h"
+
+#define SSQCNTS			0
+#define SSQCYCLE		0x8
+#define SWRESET			0xC
+#define TCON_CTRL		0x10
+#define BYPASS			BIT(3)
+#define RSDSINVCTRL		0x14
+#define MAPBIT3_0		0x18
+#define MAPBIT7_4		0x1C
+#define MAPBIT11_8		0x20
+#define MAPBIT15_12		0x24
+#define MAPBIT19_16		0x28
+#define MAPBIT23_20		0x2C
+#define MAPBIT27_24		0x30
+#define MAPBIT31_28		0x34
+#define MAPBIT34_32		0x38
+#define MAPBIT3_0_DUAL		0x3C
+#define MAPBIT7_4_DUAL		0x40
+#define MAPBIT11_8_DUAL		0x44
+#define MAPBIT15_12_DUAL	0x48
+#define MAPBIT19_16_DUAL	0x4C
+#define MAPBIT23_20_DUAL	0x50
+#define MAPBIT27_24_DUAL	0x54
+#define MAPBIT31_28_DUAL	0x58
+#define MAPBIT34_32_DUAL	0x5C
+#define SPGPOSON(n)		(0x60 + (n) * 16)
+#define X(n)			(((n) & 0x7FFF) << 16)
+#define Y(n)			((n) & 0x7FFF)
+#define SPGMASKON(n)		(0x64 + (n) * 16)
+#define SPGPOSOFF(n)		(0x68 + (n) * 16)
+#define SPGMASKOFF(n)		(0x6C + (n) * 16)
+#define SMXSIGS(n)		(0x120 + (n) * 8)
+#define SMXFCTTABLE(n)		(0x124 + (n) * 8)
+#define RESET_OVER_UNFERFLOW	0x180
+#define DUAL_DEBUG		0x184
+
+struct dpu_tcon {
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+	struct pc *pc;
+};
+
+static inline u32 dpu_tcon_read(struct dpu_tcon *tcon, unsigned int offset)
+{
+	return readl(tcon->base + offset);
+}
+
+static inline void dpu_tcon_write(struct dpu_tcon *tcon,
+				  unsigned int offset, u32 value)
+{
+	writel(value, tcon->base + offset);
+}
+
+int tcon_set_fmt(struct dpu_tcon *tcon, u32 bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		dpu_tcon_write(tcon, MAPBIT3_0,   0x19181716);
+		dpu_tcon_write(tcon, MAPBIT7_4,   0x1d1c1b1a);
+		dpu_tcon_write(tcon, MAPBIT11_8,  0x0f0e0d0c);
+		dpu_tcon_write(tcon, MAPBIT15_12, 0x13121110);
+		dpu_tcon_write(tcon, MAPBIT19_16, 0x05040302);
+		dpu_tcon_write(tcon, MAPBIT23_20, 0x09080706);
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+	case MEDIA_BUS_FMT_RGB888_1X30_PADLO:
+	case MEDIA_BUS_FMT_RGB666_1X30_PADLO:
+	case MEDIA_BUS_FMT_RGB565_1X30_PADLO:
+		dpu_tcon_write(tcon, MAPBIT3_0,   0x17161514);
+		dpu_tcon_write(tcon, MAPBIT7_4,   0x1b1a1918);
+		dpu_tcon_write(tcon, MAPBIT11_8,  0x0b0a1d1c);
+		dpu_tcon_write(tcon, MAPBIT15_12, 0x0f0e0d0c);
+		dpu_tcon_write(tcon, MAPBIT19_16, 0x13121110);
+		dpu_tcon_write(tcon, MAPBIT23_20, 0x03020100);
+		dpu_tcon_write(tcon, MAPBIT27_24, 0x07060504);
+		dpu_tcon_write(tcon, MAPBIT31_28, 0x00000908);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tcon_set_fmt);
+
+/* This function is used to workaround TKT320590 which is related to DPR/PRG. */
+void tcon_set_operation_mode(struct dpu_tcon *tcon)
+{
+	u32 val;
+
+	val = dpu_tcon_read(tcon, TCON_CTRL);
+	val &= ~BYPASS;
+	dpu_tcon_write(tcon, TCON_CTRL, val);
+}
+EXPORT_SYMBOL_GPL(tcon_set_operation_mode);
+
+void tcon_cfg_videomode(struct dpu_tcon *tcon,
+			struct drm_display_mode *m, bool side_by_side)
+{
+	u32 val;
+	int hdisplay, hsync_start, hsync_end;
+	int vdisplay, vsync_start, vsync_end;
+	int y;
+
+	hdisplay = m->hdisplay;
+	vdisplay = m->vdisplay;
+	hsync_start = m->hsync_start;
+	vsync_start = m->vsync_start;
+	hsync_end = m->hsync_end;
+	vsync_end = m->vsync_end;
+
+	if (side_by_side) {
+		hdisplay /= 2;
+		hsync_start /= 2;
+		hsync_end /= 2;
+	}
+
+	/*
+	 * TKT320590:
+	 * Turn TCON into operation mode later after the first dumb frame is
+	 * generated by DPU.  This makes DPR/PRG be able to evade the frame.
+	 */
+	val = dpu_tcon_read(tcon, TCON_CTRL);
+	val |= BYPASS;
+	dpu_tcon_write(tcon, TCON_CTRL, val);
+
+	/* dsp_control[0]: hsync */
+	dpu_tcon_write(tcon, SPGPOSON(0), X(hsync_start));
+	dpu_tcon_write(tcon, SPGMASKON(0), 0xffff);
+
+	dpu_tcon_write(tcon, SPGPOSOFF(0), X(hsync_end));
+	dpu_tcon_write(tcon, SPGMASKOFF(0), 0xffff);
+
+	dpu_tcon_write(tcon, SMXSIGS(0), 0x2);
+	dpu_tcon_write(tcon, SMXFCTTABLE(0), 0x1);
+
+	/* dsp_control[1]: vsync */
+	dpu_tcon_write(tcon, SPGPOSON(1), X(hsync_start) | Y(vsync_start - 1));
+	dpu_tcon_write(tcon, SPGMASKON(1), 0x0);
+
+	dpu_tcon_write(tcon, SPGPOSOFF(1), X(hsync_start) | Y(vsync_end - 1));
+	dpu_tcon_write(tcon, SPGMASKOFF(1), 0x0);
+
+	dpu_tcon_write(tcon, SMXSIGS(1), 0x3);
+	dpu_tcon_write(tcon, SMXFCTTABLE(1), 0x1);
+
+	/* dsp_control[2]: data enable */
+	/* horizontal */
+	dpu_tcon_write(tcon, SPGPOSON(2), 0x0);
+	dpu_tcon_write(tcon, SPGMASKON(2), 0xffff);
+
+	dpu_tcon_write(tcon, SPGPOSOFF(2), X(hdisplay));
+	dpu_tcon_write(tcon, SPGMASKOFF(2), 0xffff);
+
+	/* vertical */
+	dpu_tcon_write(tcon, SPGPOSON(3), 0x0);
+	dpu_tcon_write(tcon, SPGMASKON(3), 0x7fff0000);
+
+	dpu_tcon_write(tcon, SPGPOSOFF(3), Y(vdisplay));
+	dpu_tcon_write(tcon, SPGMASKOFF(3), 0x7fff0000);
+
+	dpu_tcon_write(tcon, SMXSIGS(2), 0x2c);
+	dpu_tcon_write(tcon, SMXFCTTABLE(2), 0x8);
+
+	/* dsp_control[3]: kachuck */
+	y = vdisplay + 1;
+	/*
+	 * If sync mode fixup is present, the kachuck signal from slave tcon
+	 * should be one line later than the one from master tcon.
+	 */
+	if (side_by_side && tcon_is_slave(tcon))
+		y++;
+
+	dpu_tcon_write(tcon, SPGPOSON(4), X(0x0) | Y(y));
+	dpu_tcon_write(tcon, SPGMASKON(4), 0x0);
+
+	dpu_tcon_write(tcon, SPGPOSOFF(4), X(0x20) | Y(y));
+	dpu_tcon_write(tcon, SPGMASKOFF(4), 0x0);
+
+	dpu_tcon_write(tcon, SMXSIGS(3), 0x6);
+	dpu_tcon_write(tcon, SMXFCTTABLE(3), 0x2);
+}
+EXPORT_SYMBOL_GPL(tcon_cfg_videomode);
+
+bool tcon_is_master(struct dpu_tcon *tcon)
+{
+	const struct dpu_data *data = tcon->dpu->data;
+
+	return tcon->id == data->master_stream_id;
+}
+EXPORT_SYMBOL_GPL(tcon_is_master);
+
+bool tcon_is_slave(struct dpu_tcon *tcon)
+{
+	return !tcon_is_master(tcon);
+}
+EXPORT_SYMBOL_GPL(tcon_is_slave);
+
+void tcon_configure_pc(struct dpu_tcon *tcon, unsigned int di,
+			unsigned int frame_width, u32 mode, u32 format)
+{
+	if (WARN_ON(!tcon || !tcon->pc))
+		return;
+
+	pc_configure(tcon->pc, di, frame_width, mode, format);
+}
+EXPORT_SYMBOL_GPL(tcon_configure_pc);
+
+void tcon_enable_pc(struct dpu_tcon *tcon)
+{
+	if (WARN_ON(!tcon || !tcon->pc))
+		return;
+
+	pc_enable(tcon->pc);
+}
+EXPORT_SYMBOL_GPL(tcon_enable_pc);
+
+void tcon_disable_pc(struct dpu_tcon *tcon)
+{
+	if (WARN_ON(!tcon || !tcon->pc))
+		return;
+
+	pc_disable(tcon->pc);
+}
+EXPORT_SYMBOL_GPL(tcon_disable_pc);
+
+struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_tcon *tcon;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tcon_ids); i++)
+		if (tcon_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(tcon_ids))
+		return ERR_PTR(-EINVAL);
+
+	tcon = dpu->tcon_priv[i];
+
+	mutex_lock(&tcon->mutex);
+
+	if (tcon->inuse) {
+		mutex_unlock(&tcon->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	tcon->inuse = true;
+
+	mutex_unlock(&tcon->mutex);
+
+	return tcon;
+}
+EXPORT_SYMBOL_GPL(dpu_tcon_get);
+
+void dpu_tcon_put(struct dpu_tcon *tcon)
+{
+	mutex_lock(&tcon->mutex);
+
+	tcon->inuse = false;
+
+	mutex_unlock(&tcon->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_tcon_put);
+
+struct dpu_tcon *dpu_aux_tcon_peek(struct dpu_tcon *tcon)
+{
+	return tcon->dpu->tcon_priv[tcon->id ^ 1];
+}
+EXPORT_SYMBOL_GPL(dpu_aux_tcon_peek);
+
+void _dpu_tcon_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
+int dpu_tcon_init(struct dpu_soc *dpu, unsigned int id,
+			unsigned long unused, unsigned long base)
+{
+	struct dpu_tcon *tcon;
+
+	tcon = devm_kzalloc(dpu->dev, sizeof(*tcon), GFP_KERNEL);
+	if (!tcon)
+		return -ENOMEM;
+
+	dpu->tcon_priv[id] = tcon;
+
+	tcon->base = devm_ioremap(dpu->dev, base, SZ_512);
+	if (!tcon->base)
+		return -ENOMEM;
+
+	tcon->dpu = dpu;
+	mutex_init(&tcon->mutex);
+
+	return 0;
+}
+
+void tcon_get_pc(struct dpu_tcon *tcon, void *data)
+{
+	if (WARN_ON(!tcon))
+		return;
+
+	tcon->pc = data;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/dpu/dpu-vscaler.c
+++ linux-ein-5.4.0/drivers/gpu/imx/dpu/dpu-vscaler.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC		0x8
+#define PIXENGCFG_DYNAMIC_SRC_SEL_MASK	0x3F
+
+#define SETUP1				0xC
+#define SCALE_FACTOR_MASK		0xFFFFF
+#define SCALE_FACTOR(n)			((n) & 0xFFFFF)
+#define SETUP2				0x10
+#define SETUP3				0x14
+#define SETUP4				0x18
+#define SETUP5				0x1C
+#define PHASE_OFFSET_MASK		0x1FFFFF
+#define PHASE_OFFSET(n)			((n) & 0x1FFFFF)
+#define CONTROL				0x20
+#define OUTPUT_SIZE_MASK		0x3FFF0000
+#define OUTPUT_SIZE(n)			((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
+#define FIELD_MODE			0x3000
+#define FILTER_MODE			0x100
+#define SCALE_MODE			0x10
+#define MODE				0x1
+
+static const vs_src_sel_t src_sels[3][6] = {
+	{
+		VS_SRC_SEL__DISABLE,
+		VS_SRC_SEL__FETCHDECODE0,
+		VS_SRC_SEL__MATRIX4,
+		VS_SRC_SEL__HSCALER4,
+	}, {
+		VS_SRC_SEL__DISABLE,
+		VS_SRC_SEL__FETCHDECODE1,
+		VS_SRC_SEL__MATRIX5,
+		VS_SRC_SEL__HSCALER5,
+	}, {
+		VS_SRC_SEL__DISABLE,
+		VS_SRC_SEL__MATRIX9,
+		VS_SRC_SEL__HSCALER9,
+	},
+};
+
+struct dpu_vscaler {
+	void __iomem *pec_base;
+	void __iomem *base;
+	struct mutex mutex;
+	int id;
+	bool inuse;
+	struct dpu_soc *dpu;
+	/* see DPU_PLANE_SRC_xxx */
+	unsigned int stream_id;
+};
+
+static inline u32 dpu_pec_vs_read(struct dpu_vscaler *vs,
+				  unsigned int offset)
+{
+	return readl(vs->pec_base + offset);
+}
+
+static inline void dpu_pec_vs_write(struct dpu_vscaler *vs,
+				    unsigned int offset, u32 value)
+{
+	writel(value, vs->pec_base + offset);
+}
+
+static inline u32 dpu_vs_read(struct dpu_vscaler *vs, unsigned int offset)
+{
+	return readl(vs->base + offset);
+}
+
+static inline void dpu_vs_write(struct dpu_vscaler *vs,
+				unsigned int offset, u32 value)
+{
+	writel(value, vs->base + offset);
+}
+
+int vscaler_pixengcfg_dynamic_src_sel(struct dpu_vscaler *vs, vs_src_sel_t src)
+{
+	struct dpu_soc *dpu = vs->dpu;
+	const unsigned int vs_id_array[] = {4, 5, 9};
+	int i, j;
+	u32 val;
+
+	for (i = 0; i < ARRAY_SIZE(vs_id_array); i++)
+		if (vs_id_array[i] == vs->id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(vs_id_array)))
+		return -EINVAL;
+
+	mutex_lock(&vs->mutex);
+	for (j = 0; j < ARRAY_SIZE(src_sels[0]); j++) {
+		if (src_sels[i][j] == src) {
+			val = dpu_pec_vs_read(vs, PIXENGCFG_DYNAMIC);
+			val &= ~PIXENGCFG_DYNAMIC_SRC_SEL_MASK;
+			val |= src;
+			dpu_pec_vs_write(vs, PIXENGCFG_DYNAMIC, val);
+			mutex_unlock(&vs->mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&vs->mutex);
+
+	dev_err(dpu->dev, "Invalid source for VScaler%d\n", vs->id);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(vscaler_pixengcfg_dynamic_src_sel);
+
+void vscaler_pixengcfg_clken(struct dpu_vscaler *vs, pixengcfg_clken_t clken)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_pec_vs_read(vs, PIXENGCFG_DYNAMIC);
+	val &= ~CLKEN_MASK;
+	val |= clken << CLKEN_MASK_SHIFT;
+	dpu_pec_vs_write(vs, PIXENGCFG_DYNAMIC, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_pixengcfg_clken);
+
+void vscaler_shden(struct dpu_vscaler *vs, bool enable)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, STATICCONTROL);
+	if (enable)
+		val |= SHDEN;
+	else
+		val &= ~SHDEN;
+	dpu_vs_write(vs, STATICCONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_shden);
+
+void vscaler_setup1(struct dpu_vscaler *vs, u32 src, u32 dst, bool deinterlace)
+{
+	struct dpu_soc *dpu = vs->dpu;
+	u32 scale_factor;
+	u64 tmp64;
+
+	if (deinterlace)
+		dst *= 2;
+
+	if (src == dst) {
+		scale_factor = 0x80000;
+	} else {
+		if (src > dst) {
+			tmp64 = (u64)((u64)dst * 0x80000);
+			do_div(tmp64, src);
+
+		} else {
+			tmp64 = (u64)((u64)src * 0x80000);
+			do_div(tmp64, dst);
+		}
+		scale_factor = (u32)tmp64;
+	}
+
+	WARN_ON(scale_factor > 0x80000);
+
+	mutex_lock(&vs->mutex);
+	dpu_vs_write(vs, SETUP1, SCALE_FACTOR(scale_factor));
+	mutex_unlock(&vs->mutex);
+
+	dev_dbg(dpu->dev, "Vscaler%d scale factor 0x%08x\n",
+						vs->id, scale_factor);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup1);
+
+void vscaler_setup2(struct dpu_vscaler *vs, bool deinterlace)
+{
+	/* 0x20000: +0.25 phase offset for deinterlace */
+	u32 phase_offset = deinterlace ? 0x20000 : 0;
+
+	mutex_lock(&vs->mutex);
+	dpu_vs_write(vs, SETUP2, PHASE_OFFSET(phase_offset));
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup2);
+
+void vscaler_setup3(struct dpu_vscaler *vs, bool deinterlace)
+{
+	/* 0x1e0000: -0.25 phase offset for deinterlace */
+	u32 phase_offset = deinterlace ? 0x1e0000 : 0;
+
+	mutex_lock(&vs->mutex);
+	dpu_vs_write(vs, SETUP3, PHASE_OFFSET(phase_offset));
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup3);
+
+void vscaler_setup4(struct dpu_vscaler *vs, u32 phase_offset)
+{
+	mutex_lock(&vs->mutex);
+	dpu_vs_write(vs, SETUP4, PHASE_OFFSET(phase_offset));
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup4);
+
+void vscaler_setup5(struct dpu_vscaler *vs, u32 phase_offset)
+{
+	mutex_lock(&vs->mutex);
+	dpu_vs_write(vs, SETUP5, PHASE_OFFSET(phase_offset));
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup5);
+
+void vscaler_output_size(struct dpu_vscaler *vs, u32 line_num)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	val &= ~OUTPUT_SIZE_MASK;
+	val |= OUTPUT_SIZE(line_num);
+	dpu_vs_write(vs, CONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_output_size);
+
+void vscaler_field_mode(struct dpu_vscaler *vs, scaler_field_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	val &= ~FIELD_MODE;
+	val |= m;
+	dpu_vs_write(vs, CONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_field_mode);
+
+void vscaler_filter_mode(struct dpu_vscaler *vs, scaler_filter_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	val &= ~FILTER_MODE;
+	val |= m;
+	dpu_vs_write(vs, CONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_filter_mode);
+
+void vscaler_scale_mode(struct dpu_vscaler *vs, scaler_scale_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	val &= ~SCALE_MODE;
+	val |= m;
+	dpu_vs_write(vs, CONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_scale_mode);
+
+void vscaler_mode(struct dpu_vscaler *vs, scaler_mode_t m)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	val &= ~MODE;
+	val |= m;
+	dpu_vs_write(vs, CONTROL, val);
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_mode);
+
+bool vscaler_is_enabled(struct dpu_vscaler *vs)
+{
+	u32 val;
+
+	mutex_lock(&vs->mutex);
+	val = dpu_vs_read(vs, CONTROL);
+	mutex_unlock(&vs->mutex);
+
+	return (val & MODE) == SCALER_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(vscaler_is_enabled);
+
+dpu_block_id_t vscaler_get_block_id(struct dpu_vscaler *vs)
+{
+	switch (vs->id) {
+	case 4:
+		return ID_VSCALER4;
+	case 5:
+		return ID_VSCALER5;
+	case 9:
+		return ID_VSCALER9;
+	default:
+		WARN_ON(1);
+	}
+
+	return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(vscaler_get_block_id);
+
+unsigned int vscaler_get_stream_id(struct dpu_vscaler *vs)
+{
+	return vs->stream_id;
+}
+EXPORT_SYMBOL_GPL(vscaler_get_stream_id);
+
+void vscaler_set_stream_id(struct dpu_vscaler *vs, unsigned int id)
+{
+	switch (id) {
+	case DPU_PLANE_SRC_TO_DISP_STREAM0:
+	case DPU_PLANE_SRC_TO_DISP_STREAM1:
+	case DPU_PLANE_SRC_DISABLED:
+		vs->stream_id = id;
+		break;
+	default:
+		WARN_ON(1);
+	}
+}
+EXPORT_SYMBOL_GPL(vscaler_set_stream_id);
+
+struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, int id)
+{
+	struct dpu_vscaler *vs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+		if (vs_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(vs_ids))
+		return ERR_PTR(-EINVAL);
+
+	vs = dpu->vs_priv[i];
+
+	mutex_lock(&vs->mutex);
+
+	if (vs->inuse) {
+		mutex_unlock(&vs->mutex);
+		return ERR_PTR(-EBUSY);
+	}
+
+	vs->inuse = true;
+
+	mutex_unlock(&vs->mutex);
+
+	return vs;
+}
+EXPORT_SYMBOL_GPL(dpu_vs_get);
+
+void dpu_vs_put(struct dpu_vscaler *vs)
+{
+	mutex_lock(&vs->mutex);
+
+	vs->inuse = false;
+
+	mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_vs_put);
+
+void _dpu_vs_init(struct dpu_soc *dpu, unsigned int id)
+{
+	struct dpu_vscaler *vs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+		if (vs_ids[i] == id)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(vs_ids)))
+		return;
+
+	vs = dpu->vs_priv[i];
+
+	vscaler_shden(vs, true);
+	vscaler_setup2(vs, false);
+	vscaler_setup3(vs, false);
+	vscaler_setup4(vs, 0);
+	vscaler_setup5(vs, 0);
+	vscaler_pixengcfg_dynamic_src_sel(vs, VS_SRC_SEL__DISABLE);
+}
+
+int dpu_vs_init(struct dpu_soc *dpu, unsigned int id,
+		unsigned long pec_base, unsigned long base)
+{
+	struct dpu_vscaler *vs;
+	int i;
+
+	vs = devm_kzalloc(dpu->dev, sizeof(*vs), GFP_KERNEL);
+	if (!vs)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+		if (vs_ids[i] == id)
+			break;
+
+	if (i == ARRAY_SIZE(vs_ids))
+		return -EINVAL;
+
+	dpu->vs_priv[i] = vs;
+
+	vs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_8);
+	if (!vs->pec_base)
+		return -ENOMEM;
+
+	vs->base = devm_ioremap(dpu->dev, base, SZ_1K);
+	if (!vs->base)
+		return -ENOMEM;
+
+	vs->dpu = dpu;
+	vs->id = id;
+
+	mutex_init(&vs->mutex);
+
+	_dpu_vs_init(dpu, id);
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/gpu/imx/imx8_dprc.c
+++ linux-ein-5.4.0/drivers/gpu/imx/imx8_dprc.c
@@ -0,0 +1,889 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_fourcc.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <video/imx8-prefetch.h>
+
+#define SET					0x4
+#define CLR					0x8
+#define TOG					0xc
+
+#define SYSTEM_CTRL0				0x00
+#define BCMD2AXI_MASTR_ID_CTRL			BIT(16)
+#define SW_SHADOW_LOAD_SEL			BIT(4)
+#define SHADOW_LOAD_EN				BIT(3)
+#define REPEAT_EN				BIT(2)
+#define SOFT_RESET				BIT(1)
+#define RUN_EN					BIT(0)	/* self-clearing */
+
+#define IRQ_MASK				0x20
+#define IRQ_MASK_STATUS				0x30
+#define IRQ_NONMASK_STATUS			0x40
+#define DPR2RTR_FIFO_LOAD_BUF_RDY_UV_ERROR	BIT(7)
+#define DPR2RTR_FIFO_LOAD_BUF_RDY_YRGB_ERROR	BIT(6)
+#define DPR2RTR_UV_FIFO_OVFL			BIT(5)
+#define DPR2RTR_YRGB_FIFO_OVFL			BIT(4)
+#define IRQ_AXI_READ_ERROR			BIT(3)
+#define IRQ_DPR_SHADOW_LOADED_MASK		BIT(2)
+#define IRQ_DPR_RUN				BIT(1)
+#define IRQ_DPR_CRTL_DONE			BIT(0)
+#define IRQ_ERROR_MASK				0xf8
+#define IRQ_CTRL_MASK				0x7
+
+#define MODE_CTRL0				0x50
+#define PIX_COMP_SEL_MASK			0x3fc00
+#define A_COMP_SEL(byte)			(((byte) & 0x3) << 16)
+#define R_COMP_SEL(byte)			(((byte) & 0x3) << 14)
+#define G_COMP_SEL(byte)			(((byte) & 0x3) << 12)
+#define B_COMP_SEL(byte)			(((byte) & 0x3) << 10)
+#define PIX_UV_SWAP				BIT(9)
+#define VU					BIT(9)
+#define UV					0
+#define PIXEL_LUMA_UV_SWAP			BIT(8)
+#define UYVY					BIT(8)
+#define YUYV					0
+#define PIX_SIZE				0xc0
+enum {
+	PIX_SIZE_8BIT = (0 << 6),
+	PIX_SIZE_16BIT = (1 << 6),
+	PIX_SIZE_32BIT = (2 << 6),
+	PIX_SIZE_RESERVED = (3 << 6),
+};
+#define COMP_2PLANE_EN				BIT(5)
+#define YUV_EN					BIT(4)
+#define TILE_TYPE				0xc
+enum {
+	LINEAR_TILE = (0 << 2),
+	GPU_STANDARD_TILE = (1 << 2),
+	GPU_SUPER_TILE = (2 << 2),
+	VPU_TILE = (3 << 2),
+};
+#define RTR_4LINE_BUF_EN			BIT(1)
+#define LINE4					BIT(1)
+#define LINE8					0
+#define RTR_3BUF_EN				BIT(0)
+#define BUF3					BIT(0)
+#define BUF2					0
+
+#define FRAME_CTRL0				0x70
+#define PITCH(n)				(((n) & 0xffff) << 16)
+#define ROT_FLIP_ORDER_EN			BIT(4)
+#define ROT_FIRST				BIT(4)
+#define FLIP_FIRST				0
+#define ROT_ENC					0xc
+#define DEGREE(n)				((((n) / 90) & 0x3) << 2)
+#define VFLIP_EN				BIT(1)
+#define HFLIP_EN				BIT(0)
+
+#define FRAME_1P_CTRL0				0x90
+#define FRAME_2P_CTRL0				0xe0
+#define MAX_BYTES_PREQ				0x7
+enum {
+	BYTE_64 = 0x0,
+	BYTE_128 = 0x1,
+	BYTE_256 = 0x2,
+	BYTE_512 = 0x3,
+	BYTE_1K = 0x4,
+	BYTE_2K = 0x5,
+	BYTE_4K = 0x6,
+};
+
+#define FRAME_1P_PIX_X_CTRL			0xa0
+#define FRAME_2P_PIX_X_CTRL			0xf0
+#define NUM_X_PIX_WIDE(n)			((n) & 0xffff)
+#define FRAME_PIX_X_ULC_CTRL			0xf0
+#define CROP_ULC_X(n)				((n) & 0xffff)
+
+#define FRAME_1P_PIX_Y_CTRL			0xb0
+#define FRAME_2P_PIX_Y_CTRL			0x100
+#define NUM_Y_PIX_HIGH(n)			((n) & 0xffff)
+#define FRAME_PIX_Y_ULC_CTRL			0x100
+#define CROP_ULC_Y(n)				((n) & 0xffff)
+
+#define FRAME_1P_BASE_ADDR_CTRL0		0xc0
+#define FRAME_2P_BASE_ADDR_CTRL0		0x110
+
+#define STATUS_CTRL0				0x130
+#define STATUS_SRC_SEL				0x70000
+enum {
+	DPR_CTRL = 0x0,
+	PREFETCH_1PLANE = 0x1,
+	RESPONSE_1PLANE = 0x2,
+	PREFETCH_2PLANE = 0x3,
+	RESPONSE_2PLANE = 0x4,
+};
+#define STATUS_MUX_SEL				0x7
+
+#define STATUS_CTRL1				0x140
+
+#define RTRAM_CTRL0				0x200
+#define ABORT_SEL				BIT(7)
+#define ABORT					BIT(7)
+#define STALL					0
+#define THRES_LOW_MASK				0x70
+#define THRES_LOW(n)				(((n) & 0x7) << 4)
+#define THRES_HIGH_MASK				0xe
+#define THRES_HIGH(n)				(((n) & 0x7) << 1)
+#define NUM_ROWS_ACTIVE				BIT(0)
+#define ROWS_0_6				BIT(0)
+#define ROWS_0_4				0
+
+struct dprc {
+	struct device *dev;
+	void __iomem *base;
+	struct list_head list;
+	struct clk *clk_apb;
+	struct clk *clk_b;
+	struct clk *clk_rtram;
+	struct imx_sc_ipc *ipc_handle;
+	spinlock_t spin_lock;
+	u32 sc_resource;
+	bool is_blit_chan;
+
+	/* The second one, if non-NULL, is auxiliary for UV buffer. */
+	struct prg *prgs[2];
+	bool has_aux_prg;
+	bool use_aux_prg;
+};
+
+struct dprc_format_info {
+	u32 format;
+	u8 depth;
+	u8 num_planes;
+	u8 cpp[3];
+	u8 hsub;
+	u8 vsub;
+};
+
+static const struct dprc_format_info formats[] = {
+	{
+	  .format = DRM_FORMAT_RGB565,
+	  .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_ARGB8888,
+	  .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_XRGB8888,
+	  .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_ABGR8888,
+	  .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_XBGR8888,
+	  .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_RGBA8888,
+	  .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_RGBX8888,
+	  .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_BGRA8888,
+	  .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_BGRX8888,
+	  .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+	  .hsub = 1,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_NV12,
+	  .depth = 0,  .num_planes = 2, .cpp = { 1, 2, 0 },
+	  .hsub = 2,   .vsub = 2,
+	}, {
+	  .format = DRM_FORMAT_NV21,
+	  .depth = 0,  .num_planes = 2, .cpp = { 1, 2, 0 },
+	  .hsub = 2,   .vsub = 2,
+	}, {
+	  .format = DRM_FORMAT_YUYV,
+	  .depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 },
+	  .hsub = 2,   .vsub = 1,
+	}, {
+	  .format = DRM_FORMAT_UYVY,
+	  .depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 },
+	  .hsub = 2,   .vsub = 1,
+	}
+};
+
+static const struct dprc_format_info *dprc_format_info(u32 format)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (formats[i].format == format)
+			return &formats[i];
+	}
+
+	return NULL;
+}
+
+static DEFINE_MUTEX(dprc_list_mutex);
+static LIST_HEAD(dprc_list);
+
+static inline u32 dprc_read(struct dprc *dprc, unsigned int offset)
+{
+	return readl(dprc->base + offset);
+}
+
+static inline void dprc_write(struct dprc *dprc, u32 value, unsigned int offset)
+{
+	writel(value, dprc->base + offset);
+}
+
+static void dprc_reset(struct dprc *dprc)
+{
+	dprc_write(dprc, SOFT_RESET, SYSTEM_CTRL0 + SET);
+
+	if (dprc->is_blit_chan)
+		usleep_range(10, 20);
+	else
+		usleep_range(1000, 2000);
+
+	dprc_write(dprc, SOFT_RESET, SYSTEM_CTRL0 + CLR);
+}
+
+void dprc_enable(struct dprc *dprc)
+{
+	if (WARN_ON(!dprc))
+		return;
+
+	prg_enable(dprc->prgs[0]);
+	if (dprc->use_aux_prg)
+		prg_enable(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_enable);
+
+void dprc_disable(struct dprc *dprc)
+{
+	if (WARN_ON(!dprc))
+		return;
+
+	dprc_write(dprc, SHADOW_LOAD_EN | SW_SHADOW_LOAD_SEL, SYSTEM_CTRL0);
+
+	prg_disable(dprc->prgs[0]);
+	if (dprc->has_aux_prg)
+		prg_disable(dprc->prgs[1]);
+
+	prg_reg_update(dprc->prgs[0]);
+	if (dprc->has_aux_prg)
+		prg_reg_update(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_disable);
+
+static inline void
+dprc_dpu_gpr_configure(struct dprc *dprc, unsigned int stream_id)
+{
+	int ret;
+
+	ret = imx_sc_misc_set_control(dprc->ipc_handle,
+		dprc->sc_resource, IMX_SC_C_KACHUNK_SEL, stream_id);
+	if (ret)
+		dev_warn(dprc->dev, "failed to set KACHUNK_SEL: %d\n", ret);
+}
+
+static inline void
+dprc_prg_sel_configure(struct dprc *dprc, u32 resource, bool enable)
+{
+	int ret;
+
+	ret = imx_sc_misc_set_control(dprc->ipc_handle,
+				resource, IMX_SC_C_SEL0, enable);
+	if (ret)
+		dev_warn(dprc->dev, "failed to set SEL0: %d\n", ret);
+}
+
+void dprc_configure(struct dprc *dprc, unsigned int stream_id,
+		    unsigned int width, unsigned int height,
+		    unsigned int x_offset, unsigned int y_offset,
+		    unsigned int stride, u32 format, u64 modifier,
+		    unsigned long baddr, unsigned long uv_baddr,
+		    bool start, bool aux_start, bool interlace_frame)
+{
+	const struct dprc_format_info *info = dprc_format_info(format);
+	unsigned int dprc_width = width + x_offset;
+	unsigned int dprc_height;
+	unsigned int p1_w, p1_h, p2_w, p2_h;
+	unsigned int prg_stride = width * info->cpp[0];
+	unsigned int bpp = 8 * info->cpp[0];
+	unsigned int preq;
+	unsigned int mt_w = 0, mt_h = 0;	/* w/h in a micro-tile */
+	u32 val;
+
+	if (WARN_ON(!dprc))
+		return;
+
+	dprc->use_aux_prg = false;
+
+	if (start) {
+		dprc_reset(dprc);
+
+		if (!dprc->is_blit_chan)
+			dprc_dpu_gpr_configure(dprc, stream_id);
+	}
+
+	if (interlace_frame) {
+		height /= 2;
+		y_offset /= 2;
+	}
+
+	dprc_height = height + y_offset;
+
+	/* disable all control irqs and enable all error irqs */
+	dprc_write(dprc, IRQ_CTRL_MASK, IRQ_MASK);
+
+	if (info->num_planes > 1) {
+		p1_w = round_up(dprc_width, modifier ? 8 : 64);
+		p1_h = round_up(dprc_height, 8);
+
+		p2_w = p1_w;
+		if (modifier)
+			p2_h = dprc_height / info->vsub;
+		else
+			p2_h = round_up((dprc_height / info->vsub), 8);
+
+		preq = modifier ? BYTE_64 : BYTE_1K;
+
+		dprc_write(dprc, preq, FRAME_2P_CTRL0);
+		if (dprc->sc_resource == IMX_SC_R_DC_0_BLIT1 ||
+		    dprc->sc_resource == IMX_SC_R_DC_1_BLIT1) {
+			dprc_prg_sel_configure(dprc,
+				dprc->sc_resource == IMX_SC_R_DC_0_BLIT1 ?
+				IMX_SC_R_DC_0_BLIT0 : IMX_SC_R_DC_1_BLIT0,
+				true);
+			prg_set_auxiliary(dprc->prgs[1]);
+			dprc->has_aux_prg = true;
+		}
+		dprc_write(dprc, uv_baddr, FRAME_2P_BASE_ADDR_CTRL0);
+	} else {
+		switch (dprc->sc_resource) {
+		case IMX_SC_R_DC_0_BLIT0:
+		case IMX_SC_R_DC_1_BLIT0:
+			dprc_prg_sel_configure(dprc, dprc->sc_resource, false);
+			prg_set_primary(dprc->prgs[0]);
+			break;
+		case IMX_SC_R_DC_0_BLIT1:
+		case IMX_SC_R_DC_1_BLIT1:
+			dprc->has_aux_prg = false;
+			break;
+		default:
+			break;
+		}
+
+		switch (modifier) {
+		case DRM_FORMAT_MOD_VIVANTE_TILED:
+			p1_w = round_up(dprc_width, info->cpp[0] == 2 ? 8 : 4);
+			break;
+		case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+			if (dprc->is_blit_chan)
+				p1_w = round_up(dprc_width,
+						info->cpp[0] == 2 ? 8 : 4);
+			else
+				p1_w = round_up(dprc_width, 64);
+			break;
+		default:
+			p1_w = round_up(dprc_width,
+					info->cpp[0] == 2 ? 32 : 16);
+			break;
+		}
+		p1_h = round_up(dprc_height, 4);
+	}
+
+	dprc_write(dprc, PITCH(stride), FRAME_CTRL0);
+	switch (modifier) {
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		preq = BYTE_64;
+		mt_w = 8;
+		mt_h = 8;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		if (bpp == 16) {
+			preq = BYTE_64;
+			mt_w = 8;
+		} else {
+			preq = (x_offset % 8) ? BYTE_64 : BYTE_128;
+			mt_w = 4;
+		}
+		mt_h = 4;
+		break;
+	default:
+		preq = BYTE_1K;
+		break;
+	}
+	dprc_write(dprc, preq, FRAME_1P_CTRL0);
+	dprc_write(dprc, NUM_X_PIX_WIDE(p1_w), FRAME_1P_PIX_X_CTRL);
+	dprc_write(dprc, NUM_Y_PIX_HIGH(p1_h), FRAME_1P_PIX_Y_CTRL);
+	dprc_write(dprc, baddr, FRAME_1P_BASE_ADDR_CTRL0);
+	if (modifier) {
+		dprc_write(dprc, CROP_ULC_X(round_down(x_offset, mt_w)),
+							FRAME_PIX_X_ULC_CTRL);
+		dprc_write(dprc, CROP_ULC_Y(round_down(y_offset, mt_h)),
+							FRAME_PIX_Y_ULC_CTRL);
+	} else {
+		dprc_write(dprc, CROP_ULC_X(0), FRAME_PIX_X_ULC_CTRL);
+		dprc_write(dprc, CROP_ULC_Y(0), FRAME_PIX_Y_ULC_CTRL);
+	}
+
+	val = dprc_read(dprc, RTRAM_CTRL0);
+	val &= ~THRES_LOW_MASK;
+	val |= THRES_LOW(3);
+	val &= ~THRES_HIGH_MASK;
+	val |= THRES_HIGH(7);
+	dprc_write(dprc, val, RTRAM_CTRL0);
+
+	val = dprc_read(dprc, MODE_CTRL0);
+	val &= ~PIX_UV_SWAP;
+	val &= ~PIXEL_LUMA_UV_SWAP;
+	val &= ~COMP_2PLANE_EN;
+	val &= ~YUV_EN;
+	val &= ~TILE_TYPE;
+	switch (modifier) {
+	case DRM_FORMAT_MOD_NONE:
+		break;
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		val |= VPU_TILE;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+		val |= GPU_STANDARD_TILE;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		val |= GPU_SUPER_TILE;
+		break;
+	default:
+		dev_err(dprc->dev, "unsupported modifier 0x%016llx\n",
+								modifier);
+		return;
+	}
+	val &= ~RTR_4LINE_BUF_EN;
+	val |= info->num_planes > 1 ? LINE8 : LINE4;
+	val &= ~RTR_3BUF_EN;
+	val |= BUF2;
+	val &= ~(PIX_COMP_SEL_MASK | PIX_SIZE);
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRX8888:
+		/*
+		 * It turns out pixel components are mapped directly
+		 * without position change via DPR processing with
+		 * the following color component configurations.
+		 * Leave the pixel format to be handled by the
+		 * display controllers.
+		 */
+		val |= A_COMP_SEL(3) | R_COMP_SEL(2) |
+		       G_COMP_SEL(1) | B_COMP_SEL(0);
+		val |= PIX_SIZE_32BIT;
+		break;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		val |= YUV_EN;
+		/* fall-through */
+	case DRM_FORMAT_RGB565:
+		val |= PIX_SIZE_16BIT;
+		break;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		dprc->use_aux_prg = true;
+
+		val |= COMP_2PLANE_EN;
+		val |= YUV_EN;
+		val |= PIX_SIZE_8BIT;
+		break;
+	default:
+		dev_err(dprc->dev, "unsupported format 0x%08x\n", format);
+		return;
+	}
+	dprc_write(dprc, val, MODE_CTRL0);
+
+	if (dprc->is_blit_chan) {
+		val = SW_SHADOW_LOAD_SEL | RUN_EN | SHADOW_LOAD_EN;
+		dprc_write(dprc, val, SYSTEM_CTRL0);
+	} else if (start) {
+		/* software shadow load for the first frame */
+		val = SW_SHADOW_LOAD_SEL | SHADOW_LOAD_EN;
+		dprc_write(dprc, val, SYSTEM_CTRL0);
+
+		/* and then, run... */
+		val |= RUN_EN | REPEAT_EN;
+		dprc_write(dprc, val, SYSTEM_CTRL0);
+	}
+
+	prg_configure(dprc->prgs[0], width, height, x_offset, y_offset,
+			prg_stride, bpp, baddr, format, modifier, start);
+	if (dprc->use_aux_prg)
+		prg_configure(dprc->prgs[1], width, height, x_offset, y_offset,
+			prg_stride, 8, uv_baddr, format, modifier, aux_start);
+
+	dev_dbg(dprc->dev, "w-%u, h-%u, s-%u, fmt-0x%08x, mod-0x%016llx\n",
+				width, height, stride, format, modifier);
+}
+EXPORT_SYMBOL_GPL(dprc_configure);
+
+void dprc_disable_repeat_en(struct dprc *dprc)
+{
+	if (WARN_ON(!dprc))
+		return;
+
+	dprc_write(dprc, REPEAT_EN, SYSTEM_CTRL0 + CLR);
+}
+EXPORT_SYMBOL_GPL(dprc_disable_repeat_en);
+
+void dprc_reg_update(struct dprc *dprc)
+{
+	if (WARN_ON(!dprc))
+		return;
+
+	prg_reg_update(dprc->prgs[0]);
+	if (dprc->use_aux_prg)
+		prg_reg_update(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_reg_update);
+
+void dprc_first_frame_handle(struct dprc *dprc)
+{
+	if (WARN_ON(!dprc))
+		return;
+
+	if (dprc->is_blit_chan)
+		return;
+
+	dprc_write(dprc, REPEAT_EN, SYSTEM_CTRL0);
+
+	prg_shadow_enable(dprc->prgs[0]);
+	if (dprc->use_aux_prg)
+		prg_shadow_enable(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_first_frame_handle);
+
+void dprc_irq_handle(struct dprc *dprc)
+{
+	u32 mask, status;
+
+	if (WARN_ON(!dprc))
+		return;
+
+	spin_lock(&dprc->spin_lock);
+
+	mask = dprc_read(dprc, IRQ_MASK);
+	mask = ~mask;
+	status = dprc_read(dprc, IRQ_MASK_STATUS);
+	status &= mask;
+
+	/* disable irqs to be handled */
+	dprc_write(dprc, status, IRQ_MASK + SET);
+
+	/* clear status */
+	dprc_write(dprc, status, IRQ_MASK_STATUS);
+
+	if (status & DPR2RTR_FIFO_LOAD_BUF_RDY_UV_ERROR)
+		dev_err(dprc->dev,
+			"DPR to RTRAM FIFO load UV buffer ready error\n");
+
+	if (status & DPR2RTR_FIFO_LOAD_BUF_RDY_YRGB_ERROR)
+		dev_err(dprc->dev,
+			"DPR to RTRAM FIFO load YRGB buffer ready error\n");
+
+	if (status & DPR2RTR_UV_FIFO_OVFL)
+		dev_err(dprc->dev, "DPR to RTRAM FIFO UV FIFO overflow\n");
+
+	if (status & DPR2RTR_YRGB_FIFO_OVFL)
+		dev_err(dprc->dev, "DPR to RTRAM FIFO YRGB FIFO overflow\n");
+
+	if (status & IRQ_AXI_READ_ERROR)
+		dev_err(dprc->dev, "AXI read error\n");
+
+	if (status & IRQ_DPR_CRTL_DONE)
+		dprc_first_frame_handle(dprc);
+
+	spin_unlock(&dprc->spin_lock);
+}
+EXPORT_SYMBOL_GPL(dprc_irq_handle);
+
+void dprc_enable_ctrl_done_irq(struct dprc *dprc)
+{
+	unsigned long lock_flags;
+
+	if (WARN_ON(!dprc))
+		return;
+
+	spin_lock_irqsave(&dprc->spin_lock, lock_flags);
+	dprc_write(dprc, IRQ_DPR_CRTL_DONE, IRQ_MASK + CLR);
+	spin_unlock_irqrestore(&dprc->spin_lock, lock_flags);
+}
+EXPORT_SYMBOL_GPL(dprc_enable_ctrl_done_irq);
+
+bool dprc_format_supported(struct dprc *dprc, u32 format, u64 modifier)
+{
+	if (WARN_ON(!dprc))
+		return false;
+
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_RGB565:
+		return (modifier == DRM_FORMAT_MOD_NONE ||
+			modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+			modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED);
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		switch (dprc->sc_resource) {
+		case IMX_SC_R_DC_0_FRAC0:
+		case IMX_SC_R_DC_1_FRAC0:
+		case IMX_SC_R_DC_0_WARP:
+		case IMX_SC_R_DC_1_WARP:
+			return false;
+		}
+		return modifier == DRM_FORMAT_MOD_NONE;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		switch (dprc->sc_resource) {
+		case IMX_SC_R_DC_0_FRAC0:
+		case IMX_SC_R_DC_1_FRAC0:
+		case IMX_SC_R_DC_0_WARP:
+		case IMX_SC_R_DC_1_WARP:
+			return false;
+		case IMX_SC_R_DC_0_BLIT1:
+		case IMX_SC_R_DC_1_BLIT1:
+			return (modifier == DRM_FORMAT_MOD_NONE ||
+				modifier == DRM_FORMAT_MOD_AMPHION_TILED);
+		}
+		return (dprc->has_aux_prg &&
+			(modifier == DRM_FORMAT_MOD_NONE ||
+			 modifier == DRM_FORMAT_MOD_AMPHION_TILED));
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(dprc_format_supported);
+
+bool dprc_stride_supported(struct dprc *dprc,
+			   unsigned int stride, unsigned int uv_stride,
+			   unsigned int width, u32 format)
+{
+	const struct dprc_format_info *info = dprc_format_info(format);
+	unsigned int prg_stride = width * info->cpp[0];
+
+	if (WARN_ON(!dprc))
+		return false;
+
+	if (stride > 0xffff)
+		return false;
+
+	if (info->num_planes > 1 && stride != uv_stride)
+		return false;
+
+	return prg_stride_supported(dprc->prgs[0], prg_stride);
+}
+EXPORT_SYMBOL_GPL(dprc_stride_supported);
+
+bool dprc_stride_double_check(struct dprc *dprc,
+			      unsigned int width, unsigned int x_offset,
+			      u32 format, u64 modifier,
+			      dma_addr_t baddr, dma_addr_t uv_baddr)
+{
+	const struct dprc_format_info *info = dprc_format_info(format);
+	unsigned int bpp = 8 * info->cpp[0];
+	unsigned int prg_stride = width * info->cpp[0];
+
+	if (WARN_ON(!dprc))
+		return false;
+
+	if (!prg_stride_double_check(dprc->prgs[0], width, x_offset,
+				     bpp, modifier, prg_stride, baddr))
+		return false;
+
+	if (info->num_planes > 1 &&
+	    !prg_stride_double_check(dprc->prgs[1], width, x_offset,
+				     bpp, modifier, prg_stride, uv_baddr))
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(dprc_stride_double_check);
+
+struct dprc *
+dprc_lookup_by_phandle(struct device *dev, const char *name, int index)
+{
+	struct device_node *dprc_node = of_parse_phandle(dev->of_node,
+							 name, index);
+	struct dprc *dprc;
+
+	mutex_lock(&dprc_list_mutex);
+	list_for_each_entry(dprc, &dprc_list, list) {
+		if (dprc_node == dprc->dev->of_node) {
+			mutex_unlock(&dprc_list_mutex);
+			device_link_add(dev, dprc->dev,
+					DL_FLAG_AUTOREMOVE_CONSUMER);
+			return dprc;
+		}
+	}
+	mutex_unlock(&dprc_list_mutex);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(dprc_lookup_by_phandle);
+
+static const struct of_device_id dprc_dt_ids[] = {
+	{ .compatible = "fsl,imx8qm-dpr-channel", },
+	{ .compatible = "fsl,imx8qxp-dpr-channel", },
+	{ /* sentinel */ },
+};
+
+static int dprc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct dprc *dprc;
+	int ret, i;
+
+	dprc = devm_kzalloc(dev, sizeof(*dprc), GFP_KERNEL);
+	if (!dprc)
+		return -ENOMEM;
+
+	ret = imx_scu_get_handle(&dprc->ipc_handle);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dprc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dprc->base))
+		return PTR_ERR(dprc->base);
+
+	dprc->clk_apb = devm_clk_get(dev, "apb");
+	if (IS_ERR(dprc->clk_apb))
+		return PTR_ERR(dprc->clk_apb);
+	clk_prepare_enable(dprc->clk_apb);
+
+	dprc->clk_b = devm_clk_get(dev, "b");
+	if (IS_ERR(dprc->clk_b))
+		return PTR_ERR(dprc->clk_b);
+	clk_prepare_enable(dprc->clk_b);
+
+	dprc->clk_rtram = devm_clk_get(dev, "rtram");
+	if (IS_ERR(dprc->clk_rtram))
+		return PTR_ERR(dprc->clk_rtram);
+	clk_prepare_enable(dprc->clk_rtram);
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+					"fsl,sc-resource", &dprc->sc_resource);
+	if (ret) {
+		dev_err(dev, "cannot get SC resource %d\n", ret);
+		return ret;
+	}
+
+	switch (dprc->sc_resource) {
+	case IMX_SC_R_DC_0_BLIT1:
+	case IMX_SC_R_DC_1_BLIT1:
+		dprc->has_aux_prg = true;
+		/* fall-through */
+	case IMX_SC_R_DC_0_BLIT0:
+	case IMX_SC_R_DC_1_BLIT0:
+		dprc->is_blit_chan = true;
+		/* fall-through */
+	case IMX_SC_R_DC_0_FRAC0:
+	case IMX_SC_R_DC_1_FRAC0:
+		break;
+	case IMX_SC_R_DC_0_VIDEO0:
+	case IMX_SC_R_DC_0_VIDEO1:
+	case IMX_SC_R_DC_1_VIDEO0:
+	case IMX_SC_R_DC_1_VIDEO1:
+	case IMX_SC_R_DC_0_WARP:
+	case IMX_SC_R_DC_1_WARP:
+		dprc->has_aux_prg = true;
+		break;
+	default:
+		dev_err(dev, "wrong SC resource %u\n", dprc->sc_resource);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 2; i++) {
+		if (i == 1 && !dprc->has_aux_prg)
+			break;
+
+		dprc->prgs[i] = prg_lookup_by_phandle(dev, "fsl,prgs", i);
+		if (!dprc->prgs[i])
+			return -EPROBE_DEFER;
+
+		if (i == 1)
+			prg_set_auxiliary(dprc->prgs[i]);
+
+		if (dprc->is_blit_chan)
+			prg_set_blit(dprc->prgs[i]);
+	}
+
+	dprc->dev = dev;
+	spin_lock_init(&dprc->spin_lock);
+	platform_set_drvdata(pdev, dprc);
+	mutex_lock(&dprc_list_mutex);
+	list_add(&dprc->list, &dprc_list);
+	mutex_unlock(&dprc_list_mutex);
+
+	dprc_reset(dprc);
+
+	return 0;
+}
+
+static int dprc_remove(struct platform_device *pdev)
+{
+	struct dprc *dprc = platform_get_drvdata(pdev);
+
+	mutex_lock(&dprc_list_mutex);
+	list_del(&dprc->list);
+	mutex_unlock(&dprc_list_mutex);
+
+	clk_disable_unprepare(dprc->clk_rtram);
+	clk_disable_unprepare(dprc->clk_b);
+	clk_disable_unprepare(dprc->clk_apb);
+
+	return 0;
+}
+
+struct platform_driver dprc_drv = {
+	.probe = dprc_probe,
+	.remove = dprc_remove,
+	.driver = {
+		.name = "imx8-dpr-channel",
+		.of_match_table = dprc_dt_ids,
+	},
+};
+module_platform_driver(dprc_drv);
+
+MODULE_DESCRIPTION("i.MX8 DPRC driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/imx8_pc.c
+++ linux-ein-5.4.0/drivers/gpu/imx/imx8_pc.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2018,2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <video/imx8-pc.h>
+
+#define REG0				0x0
+#define PIX_COMBINE_ENABLE		BIT(0)
+#define DISP_PIX_COMBINE_BYPASS(n)	BIT(1 + 21 * (n))
+#define DISP_HSYNC_POLARITY(n)		BIT(2 + 11 * (n))
+#define DISP_HSYNC_POLARITY_POS(n)	DISP_HSYNC_POLARITY(n)
+#define DISP_VSYNC_POLARITY(n)		BIT(3 + 11 * (n))
+#define DISP_VSYNC_POLARITY_POS(n)	DISP_VSYNC_POLARITY(n)
+#define DISP_DVALID_POLARITY(n)		BIT(4 + 11 * (n))
+#define DISP_DVALID_POLARITY_POS(n)	DISP_DVALID_POLARITY(n)
+#define VSYNC_MASK_ENABLE		BIT(5)
+#define SKIP_MODE			BIT(6)
+#define SKIP_NUMBER(n)			(((n) & 0x3F) << 7)
+#define DISP_PIX_DATA_FORMAT_MASK(n)    (0x7 << (16 + (n) * 3))
+#define DISP_PIX_DATA_FORMAT_SHIFT(n)   (16 + (n) * 3)
+enum {
+	RGB = 0,
+	YUV444,
+	YUV422,
+	SPLIT_RGB,
+};
+
+#define REG1				0x10
+#define BUF_ACTIVE_DEPTH(n)		((n) & 0x7FF)
+
+#define REG2				0x20
+#define PC_SW_RESET_N			BIT(0)
+#define DISP_SW_RESET_N(n)		BIT(1 + (n))
+#define PC_FULL_RESET_N			(PC_SW_RESET_N |	\
+					 DISP_SW_RESET_N(0) |	\
+					 DISP_SW_RESET_N(1))
+
+struct pc {
+	struct device *dev;
+	void __iomem *base;
+	struct list_head list;
+};
+
+static DEFINE_MUTEX(pc_list_mutex);
+static LIST_HEAD(pc_list);
+
+static inline u32 pc_read(struct pc *pc, unsigned int offset)
+{
+	return readl(pc->base + offset);
+}
+
+static inline void pc_write(struct pc *pc, unsigned int offset, u32 value)
+{
+	writel(value, pc->base + offset);
+}
+
+static void pc_reset(struct pc *pc)
+{
+	pc_write(pc, REG2, 0);
+	usleep_range(1000, 2000);
+	pc_write(pc, REG2, PC_FULL_RESET_N);
+}
+
+void pc_enable(struct pc *pc)
+{
+	u32 val;
+
+	if (WARN_ON(!pc))
+		return;
+
+	val = pc_read(pc, REG0);
+	val |= PIX_COMBINE_ENABLE;
+	pc_write(pc, REG0, val);
+
+	dev_dbg(pc->dev, "enable\n");
+}
+EXPORT_SYMBOL_GPL(pc_enable);
+
+void pc_disable(struct pc *pc)
+{
+	if (WARN_ON(!pc))
+		return;
+
+	pc_reset(pc);
+
+	dev_dbg(pc->dev, "disable\n");
+}
+EXPORT_SYMBOL_GPL(pc_disable);
+
+void pc_configure(struct pc *pc, unsigned int di, unsigned int frame_width,
+		u32 mode, u32 format)
+{
+	u32 val;
+
+	if (WARN_ON(!pc))
+		return;
+
+	if (WARN_ON(di != 0 && di != 1))
+		return;
+
+	dev_dbg(pc->dev, "configure mode-0x%08x frame_width-%u\n",
+							mode, frame_width);
+
+	val = pc_read(pc, REG0);
+	if (mode == PC_BYPASS) {
+		val |= DISP_PIX_COMBINE_BYPASS(di);
+	} else if (mode == PC_COMBINE) {
+		val &= ~DISP_PIX_COMBINE_BYPASS(di);
+		frame_width /= 4;
+	}
+
+	pc_write(pc, REG0, val);
+	pc_write(pc, REG1, BUF_ACTIVE_DEPTH(frame_width));
+}
+EXPORT_SYMBOL_GPL(pc_configure);
+
+struct pc *pc_lookup_by_phandle(struct device *dev, const char *name)
+{
+	struct device_node *pc_node = of_parse_phandle(dev->of_node,
+							name, 0);
+	struct pc *pc;
+
+	mutex_lock(&pc_list_mutex);
+	list_for_each_entry(pc, &pc_list, list) {
+		if (pc_node == pc->dev->of_node) {
+			mutex_unlock(&pc_list_mutex);
+			device_link_add(dev, pc->dev,
+					DL_FLAG_AUTOREMOVE_CONSUMER);
+			return pc;
+		}
+	}
+	mutex_unlock(&pc_list_mutex);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(pc_lookup_by_phandle);
+
+static int pc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct pc *pc;
+	u32 val;
+
+	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
+	if (!pc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pc->base))
+		return PTR_ERR(pc->base);
+
+	pc->dev = dev;
+	platform_set_drvdata(pdev, pc);
+	mutex_lock(&pc_list_mutex);
+	list_add(&pc->list, &pc_list);
+	mutex_unlock(&pc_list_mutex);
+
+	pc_reset(pc);
+
+	/*
+	 * assume data enable is active high and HSYNC/VSYNC are active low
+	 * also, bypass combine at startup
+	 */
+	val = DISP_DVALID_POLARITY_POS(0) | DISP_DVALID_POLARITY_POS(1) |
+	      DISP_PIX_COMBINE_BYPASS(0)  | DISP_PIX_COMBINE_BYPASS(1)  |
+	      VSYNC_MASK_ENABLE;
+
+	pc_write(pc, REG0, val);
+
+	return 0;
+}
+
+static int pc_remove(struct platform_device *pdev)
+{
+	struct pc *pc = platform_get_drvdata(pdev);
+
+	mutex_lock(&pc_list_mutex);
+	list_del(&pc->list);
+	mutex_unlock(&pc_list_mutex);
+
+	return 0;
+}
+
+static const struct of_device_id pc_dt_ids[] = {
+	{ .compatible = "fsl,imx8qm-pixel-combiner", },
+	{ .compatible = "fsl,imx8qxp-pixel-combiner", },
+	{ /* sentinel */ },
+};
+
+struct platform_driver pc_drv = {
+	.probe = pc_probe,
+	.remove = pc_remove,
+	.driver = {
+		.name = "imx8-pixel-combiner",
+		.of_match_table = pc_dt_ids,
+	},
+};
+module_platform_driver(pc_drv);
+
+MODULE_DESCRIPTION("i.MX8 Pixel Combiner driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/imx8_prg.c
+++ linux-ein-5.4.0/drivers/gpu/imx/imx8_prg.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <drm/drm_fourcc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <video/imx8-prefetch.h>
+
+#define SET			0x4
+#define CLR			0x8
+#define TOG			0xc
+
+#define PRG_CTRL		0x00
+#define BYPASS			BIT(0)
+#define SC_DATA_TYPE		BIT(2)
+#define SC_DATA_TYPE_8BIT	0
+#define SC_DATA_TYPE_10BIT	BIT(2)
+#define UV_EN			BIT(3)
+#define HANDSHAKE_MODE		BIT(4)
+#define HANDSHAKE_MODE_4LINES	0
+#define HANDSHAKE_MODE_8LINES	BIT(4)
+#define SHADOW_LOAD_MODE	BIT(5)
+#define DES_DATA_TYPE		0x30000
+enum {
+	DES_DATA_TYPE_32BPP = (0 << 16),
+	DES_DATA_TYPE_24BPP = (1 << 16),
+	DES_DATA_TYPE_16BPP = (2 << 16),
+	DES_DATA_TYPE_8BPP = (3 << 16),
+};
+#define SOFTRST			BIT(30)
+#define SHADOW_EN		BIT(31)
+
+#define PRG_STATUS		0x10
+#define BUFFER_VALID_B		BIT(1)
+#define BUFFER_VALID_A		BIT(0)
+
+#define PRG_REG_UPDATE		0x20
+#define REG_UPDATE		BIT(0)
+
+#define PRG_STRIDE		0x30
+#define STRIDE(n)		(((n) - 1) & 0xffff)
+
+#define PRG_HEIGHT		0x40
+#define HEIGHT(n)		(((n) - 1) & 0xffff)
+
+#define PRG_BADDR		0x50
+
+#define PRG_OFFSET		0x60
+#define Y(n)			(((n) & 0x7) << 16)
+#define X(n)			((n) & 0xffff)
+
+#define PRG_WIDTH		0x70
+#define WIDTH(n)		(((n) - 1) & 0xffff)
+
+struct prg {
+	struct device *dev;
+	void __iomem *base;
+	struct list_head list;
+	struct clk *clk_apb;
+	struct clk *clk_rtram;
+	bool is_auxiliary;
+	bool is_blit;
+};
+
+static DEFINE_MUTEX(prg_list_mutex);
+static LIST_HEAD(prg_list);
+
+static inline u32 prg_read(struct prg *prg, unsigned int offset)
+{
+	return readl(prg->base + offset);
+}
+
+static inline void prg_write(struct prg *prg, u32 value, unsigned int offset)
+{
+	writel(value, prg->base + offset);
+}
+
+static void prg_reset(struct prg *prg)
+{
+	if (prg->is_blit)
+		usleep_range(10, 20);
+
+	prg_write(prg, SOFTRST, PRG_CTRL + SET);
+
+	if (prg->is_blit)
+		usleep_range(10, 20);
+	else
+		usleep_range(1000, 2000);
+
+	prg_write(prg, SOFTRST, PRG_CTRL + CLR);
+}
+
+void prg_enable(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg_write(prg, BYPASS, PRG_CTRL + CLR);
+}
+EXPORT_SYMBOL_GPL(prg_enable);
+
+void prg_disable(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg_write(prg, BYPASS, PRG_CTRL);
+}
+EXPORT_SYMBOL_GPL(prg_disable);
+
+void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
+		   unsigned int x_offset, unsigned int y_offset,
+		   unsigned int stride, unsigned int bits_per_pixel,
+		   unsigned long baddr, u32 format, u64 modifier,
+		   bool start)
+{
+	unsigned int burst_size;
+	unsigned int mt_w = 0, mt_h = 0;	/* w/h in a micro-tile */
+	unsigned long _baddr;
+	u32 val;
+
+	if (WARN_ON(!prg))
+		return;
+
+	if (start)
+		prg_reset(prg);
+
+	/* prg finer cropping into micro-tile block - top/left start point */
+	switch (modifier) {
+	case DRM_FORMAT_MOD_NONE:
+		break;
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		mt_w = 8;
+		mt_h = 8;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		mt_w = (bits_per_pixel == 16) ? 8 : 4;
+		mt_h = 4;
+		break;
+	default:
+		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
+		return;
+	}
+
+	if (modifier) {
+		x_offset %= mt_w;
+		y_offset %= mt_h;
+
+		/* consider x offset to calculate stride */
+		_baddr = baddr + (x_offset * (bits_per_pixel / 8));
+	} else {
+		x_offset = 0;
+		y_offset = 0;
+		_baddr = baddr;
+	}
+
+	/*
+	 * address TKT343664:
+	 * fetch unit base address has to align to burst_size
+	 */
+	burst_size = 1 << (ffs(_baddr) - 1);
+	burst_size = round_up(burst_size, 8);
+	burst_size = min(burst_size, 128U);
+
+	/*
+	 * address TKT339017:
+	 * fixup for burst size vs stride mismatch
+	 */
+	if (modifier)
+		stride = round_up(stride + round_up(_baddr % 8, 8), burst_size);
+	else
+		stride = round_up(stride, burst_size);
+
+	/*
+	 * address TKT342628(part 1):
+	 * when prg stride is less or equals to burst size,
+	 * the auxiliary prg height needs to be a half
+	 */
+	if (prg->is_auxiliary && stride <= burst_size) {
+		height /= 2;
+		if (modifier)
+			y_offset /= 2;
+	}
+
+	prg_write(prg, STRIDE(stride), PRG_STRIDE);
+	prg_write(prg, WIDTH(width), PRG_WIDTH);
+	prg_write(prg, HEIGHT(height), PRG_HEIGHT);
+	prg_write(prg, X(x_offset) | Y(y_offset), PRG_OFFSET);
+	prg_write(prg, baddr, PRG_BADDR);
+
+	val = prg_read(prg, PRG_CTRL);
+	val &= ~SC_DATA_TYPE;
+	val |= SC_DATA_TYPE_8BIT;
+	val &= ~HANDSHAKE_MODE;
+	if (format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) {
+		val |= HANDSHAKE_MODE_8LINES;
+		/*
+		 * address TKT342628(part 2):
+		 * when prg stride is less or equals to burst size,
+		 * we disable UV_EN bit for the auxiliary prg
+		 */
+		if (prg->is_auxiliary && stride > burst_size)
+			val |= UV_EN;
+		else
+			val &= ~UV_EN;
+	} else {
+		val |= HANDSHAKE_MODE_4LINES;
+		val &= ~UV_EN;
+	}
+	val |= SHADOW_LOAD_MODE;
+	val &= ~DES_DATA_TYPE;
+	switch (bits_per_pixel) {
+	case 32:
+		val |= DES_DATA_TYPE_32BPP;
+		break;
+	case 24:
+		val |= DES_DATA_TYPE_24BPP;
+		break;
+	case 16:
+		val |= DES_DATA_TYPE_16BPP;
+		break;
+	case 8:
+		val |= DES_DATA_TYPE_8BPP;
+		break;
+	}
+	if (start)
+		/* no shadow for the first frame */
+		val &= ~SHADOW_EN;
+	else
+		val |= SHADOW_EN;
+	prg_write(prg, val, PRG_CTRL);
+
+	dev_dbg(prg->dev, "bits per pixel %u\n", bits_per_pixel);
+}
+EXPORT_SYMBOL_GPL(prg_configure);
+
+void prg_reg_update(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg_write(prg, REG_UPDATE, PRG_REG_UPDATE);
+}
+EXPORT_SYMBOL_GPL(prg_reg_update);
+
+void prg_shadow_enable(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg_write(prg, SHADOW_EN, PRG_CTRL + SET);
+}
+EXPORT_SYMBOL_GPL(prg_shadow_enable);
+
+bool prg_stride_supported(struct prg *prg, unsigned int stride)
+{
+	return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_supported);
+
+bool prg_stride_double_check(struct prg *prg,
+			     unsigned int width, unsigned int x_offset,
+			     unsigned int bits_per_pixel, u64 modifier,
+			     unsigned int stride, dma_addr_t baddr)
+{
+	unsigned int burst_size;
+	unsigned int mt_w = 0;	/* w in a micro-tile */
+	dma_addr_t _baddr;
+
+	if (WARN_ON(!prg))
+		return false;
+
+	/* prg finer cropping into micro-tile block - top/left start point */
+	switch (modifier) {
+	case DRM_FORMAT_MOD_NONE:
+		break;
+	case DRM_FORMAT_MOD_AMPHION_TILED:
+		mt_w = 8;
+		break;
+	case DRM_FORMAT_MOD_VIVANTE_TILED:
+	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+		mt_w = (bits_per_pixel == 16) ? 8 : 4;
+		break;
+	default:
+		dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
+		return false;
+	}
+
+	if (modifier) {
+		x_offset %= mt_w;
+
+		/* consider x offset to calculate stride */
+		_baddr = baddr + (x_offset * (bits_per_pixel / 8));
+	} else {
+		_baddr = baddr;
+	}
+
+	/*
+	 * address TKT343664:
+	 * fetch unit base address has to align to burst size
+	 */
+	burst_size = 1 << (ffs(_baddr) - 1);
+	burst_size = round_up(burst_size, 8);
+	burst_size = min(burst_size, 128U);
+
+	/*
+	 * address TKT339017:
+	 * fixup for burst size vs stride mismatch
+	 */
+	if (modifier)
+		stride = round_up(stride + round_up(_baddr % 8, 8), burst_size);
+	else
+		stride = round_up(stride, burst_size);
+
+	return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_double_check);
+
+void prg_set_auxiliary(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg->is_auxiliary = true;
+}
+EXPORT_SYMBOL_GPL(prg_set_auxiliary);
+
+void prg_set_primary(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg->is_auxiliary = false;
+}
+EXPORT_SYMBOL_GPL(prg_set_primary);
+
+void prg_set_blit(struct prg *prg)
+{
+	if (WARN_ON(!prg))
+		return;
+
+	prg->is_blit = true;
+}
+EXPORT_SYMBOL_GPL(prg_set_blit);
+
+struct prg *
+prg_lookup_by_phandle(struct device *dev, const char *name, int index)
+{
+	struct device_node *prg_node = of_parse_phandle(dev->of_node,
+							name, index);
+	struct prg *prg;
+
+	mutex_lock(&prg_list_mutex);
+	list_for_each_entry(prg, &prg_list, list) {
+		if (prg_node == prg->dev->of_node) {
+			mutex_unlock(&prg_list_mutex);
+			device_link_add(dev, prg->dev,
+					DL_FLAG_AUTOREMOVE_CONSUMER);
+			return prg;
+		}
+	}
+	mutex_unlock(&prg_list_mutex);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(prg_lookup_by_phandle);
+
+static const struct of_device_id prg_dt_ids[] = {
+	{ .compatible = "fsl,imx8qm-prg", },
+	{ .compatible = "fsl,imx8qxp-prg", },
+	{ /* sentinel */ },
+};
+
+static int prg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct prg *prg;
+
+	prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
+	if (!prg)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	prg->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(prg->base))
+		return PTR_ERR(prg->base);
+
+	prg->clk_apb = devm_clk_get(dev, "apb");
+	if (IS_ERR(prg->clk_apb))
+		return PTR_ERR(prg->clk_apb);
+	clk_prepare_enable(prg->clk_apb);
+
+	prg->clk_rtram = devm_clk_get(dev, "rtram");
+	if (IS_ERR(prg->clk_rtram))
+		return PTR_ERR(prg->clk_rtram);
+	clk_prepare_enable(prg->clk_rtram);
+
+	prg->dev = dev;
+	platform_set_drvdata(pdev, prg);
+	mutex_lock(&prg_list_mutex);
+	list_add(&prg->list, &prg_list);
+	mutex_unlock(&prg_list_mutex);
+
+	prg_reset(prg);
+
+	return 0;
+}
+
+static int prg_remove(struct platform_device *pdev)
+{
+	struct prg *prg = platform_get_drvdata(pdev);
+
+	mutex_lock(&prg_list_mutex);
+	list_del(&prg->list);
+	mutex_unlock(&prg_list_mutex);
+
+	clk_disable_unprepare(prg->clk_rtram);
+	clk_disable_unprepare(prg->clk_apb);
+
+	return 0;
+}
+
+struct platform_driver prg_drv = {
+	.probe = prg_probe,
+	.remove = prg_remove,
+	.driver = {
+		.name = "imx8-prg",
+		.of_match_table = prg_dt_ids,
+	},
+};
+module_platform_driver(prg_drv);
+
+MODULE_DESCRIPTION("i.MX8 PRG driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdif/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdif/Kconfig
@@ -0,0 +1,8 @@
+config IMX_LCDIF_CORE
+	tristate "i.MX LCDIF core support"
+	depends on ARCH_MXC
+	select RESET_CONTROLLER
+	help
+	  Choose this if you have a NXP i.MX8MM platform and want to use the
+	  LCDIF display controller. This option only enables LCDIF base support.
+
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdif/Makefile
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdif/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IMX_LCDIF_CORE) += imx-lcdif-core.o
+
+imx-lcdif-core-objs := lcdif-common.o
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdif/lcdif-common.c
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdif/lcdif-common.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+#include <drm/drm_fourcc.h>
+#include <video/imx-lcdif.h>
+#include <video/videomode.h>
+
+#include "lcdif-regs.h"
+
+#define DRIVER_NAME "imx-lcdif"
+
+struct lcdif_soc {
+	struct device *dev;
+
+	int irq;
+	void __iomem *base;
+	struct reset_control *soft_resetn;
+	struct reset_control *clk_enable;
+	atomic_t rpm_suspended;
+
+	struct clk *clk_pix;
+	struct clk *clk_disp_axi;
+	struct clk *clk_disp_apb;
+};
+
+struct lcdif_soc_pdata {
+	bool hsync_invert;
+	bool vsync_invert;
+	bool de_invert;
+};
+
+struct lcdif_platform_reg {
+	struct lcdif_client_platformdata pdata;
+	char *name;
+};
+
+struct lcdif_platform_reg client_reg[] = {
+	{
+		.pdata = { },
+		.name  = "imx-lcdif-crtc",
+	},
+};
+
+struct lcdif_soc_pdata imx8mm_pdata = {
+	.hsync_invert = true,
+	.vsync_invert = true,
+	.de_invert    = true,
+};
+
+static const struct of_device_id imx_lcdif_dt_ids[] = {
+	{ .compatible = "fsl,imx8mm-lcdif", .data = &imx8mm_pdata, },
+	{ .compatible = "fsl,imx8mn-lcdif", .data = &imx8mm_pdata, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_lcdif_dt_ids);
+
+#ifdef CONFIG_PM
+static int imx_lcdif_runtime_suspend(struct device *dev);
+static int imx_lcdif_runtime_resume(struct device *dev);
+#else
+static int imx_lcdif_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+static int imx_lcdif_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static int lcdif_rstc_reset(struct reset_control *rstc, bool assert)
+{
+	int ret;
+
+	if (!rstc)
+		return 0;
+
+	ret = assert ? reset_control_assert(rstc)	:
+		       reset_control_deassert(rstc);
+
+	return ret;
+}
+
+static int lcdif_enable_clocks(struct lcdif_soc *lcdif)
+{
+	int ret;
+
+	if (lcdif->clk_disp_axi) {
+		ret = clk_prepare_enable(lcdif->clk_disp_axi);
+		if (ret)
+			return ret;
+	}
+
+	if (lcdif->clk_disp_apb) {
+		ret = clk_prepare_enable(lcdif->clk_disp_apb);
+		if (ret)
+			goto disable_disp_axi;
+	}
+
+	ret = clk_prepare_enable(lcdif->clk_pix);
+	if (ret)
+		goto disable_disp_apb;
+
+	return 0;
+
+disable_disp_apb:
+	if (lcdif->clk_disp_apb)
+		clk_disable_unprepare(lcdif->clk_disp_apb);
+disable_disp_axi:
+	if (lcdif->clk_disp_axi)
+		clk_disable_unprepare(lcdif->clk_disp_axi);
+
+	return ret;
+}
+
+static void lcdif_disable_clocks(struct lcdif_soc *lcdif)
+{
+	clk_disable_unprepare(lcdif->clk_pix);
+
+	if (lcdif->clk_disp_axi)
+		clk_disable_unprepare(lcdif->clk_disp_axi);
+
+	if (lcdif->clk_disp_apb)
+		clk_disable_unprepare(lcdif->clk_disp_apb);
+}
+
+int lcdif_vblank_irq_get(struct lcdif_soc *lcdif)
+{
+	return lcdif->irq;
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_get);
+
+void lcdif_dump_registers(struct lcdif_soc *lcdif)
+{
+	pr_info("%#x	: %#x\n", LCDIF_CTRL,
+				  readl(lcdif->base + LCDIF_CTRL));
+	pr_info("%#x	: %#x\n", LCDIF_CTRL1,
+				  readl(lcdif->base + LCDIF_CTRL1));
+	pr_info("%#x	: %#x\n", LCDIF_CTRL2,
+				  readl(lcdif->base + LCDIF_CTRL2));
+	pr_info("%#x	: %#x\n", LCDIF_TRANSFER_COUNT,
+				  readl(lcdif->base + LCDIF_TRANSFER_COUNT));
+	pr_info("%#x	: %#x\n", LCDIF_CUR_BUF,
+				  readl(lcdif->base + LCDIF_CUR_BUF));
+	pr_info("%#x	: %#x\n", LCDIF_NEXT_BUF,
+				  readl(lcdif->base + LCDIF_NEXT_BUF));
+	pr_info("%#x	: %#x\n", LCDIF_VDCTRL0,
+				  readl(lcdif->base + LCDIF_VDCTRL0));
+	pr_info("%#x	: %#x\n", LCDIF_VDCTRL1,
+				  readl(lcdif->base + LCDIF_VDCTRL1));
+	pr_info("%#x	: %#x\n", LCDIF_VDCTRL2,
+				  readl(lcdif->base + LCDIF_VDCTRL2));
+	pr_info("%#x	: %#x\n", LCDIF_VDCTRL3,
+				  readl(lcdif->base + LCDIF_VDCTRL3));
+	pr_info("%#x	: %#x\n", LCDIF_VDCTRL4,
+				  readl(lcdif->base + LCDIF_VDCTRL4));
+}
+EXPORT_SYMBOL(lcdif_dump_registers);
+
+void lcdif_vblank_irq_enable(struct lcdif_soc *lcdif)
+{
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, lcdif->base + LCDIF_CTRL1 + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_enable);
+
+void lcdif_vblank_irq_disable(struct lcdif_soc *lcdif)
+{
+	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_disable);
+
+void lcdif_vblank_irq_clear(struct lcdif_soc *lcdif)
+{
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_clear);
+
+static uint32_t lcdif_get_bpp_from_fmt(uint32_t format)
+{
+	/* TODO: only support RGB for now */
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_XBGR1555:
+		return 16;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+		return 32;
+	default:
+		/* unsupported format */
+		return 0;
+	}
+}
+
+/*
+ * Get the bus format supported by LCDIF
+ * according to drm fourcc format
+ */
+int lcdif_get_bus_fmt_from_pix_fmt(struct lcdif_soc *lcdif,
+				   uint32_t format)
+{
+	uint32_t bpp;
+
+	bpp = lcdif_get_bpp_from_fmt(format);
+	if (!bpp)
+		return -EINVAL;
+
+	switch (bpp) {
+	case 16:
+		return MEDIA_BUS_FMT_RGB565_1X16;
+	case 18:
+		return MEDIA_BUS_FMT_RGB666_1X18;
+	case 24:
+	case 32:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(lcdif_get_bus_fmt_from_pix_fmt);
+
+int lcdif_set_pix_fmt(struct lcdif_soc *lcdif, u32 format)
+{
+	struct drm_format_name_buf format_name;
+	u32 ctrl = 0, ctrl1 = 0;
+
+	/* TODO: lcdif should be disabled to set pixel format */
+
+	ctrl  = readl(lcdif->base + LCDIF_CTRL);
+	ctrl1 = readl(lcdif->base + LCDIF_CTRL1);
+
+	/* clear pixel format related bits */
+	ctrl  &= ~(CTRL_SHIFT_NUM(0x3f)  | CTRL_INPUT_SWIZZLE(0x3) |
+		   CTRL_CSC_SWIZZLE(0x3) | CTRL_SET_WORD_LENGTH(0x3));
+
+	ctrl1 &= ~CTRL1_SET_BYTE_PACKAGING(0xf);
+
+	/* default is 'RGB' order */
+	writel(CTRL2_ODD_LINE_PATTERN(0x7) |
+	       CTRL2_EVEN_LINE_PATTERN(0x7),
+	       lcdif->base + LCDIF_CTRL2 + REG_CLR);
+
+	switch (format) {
+		/* bpp 16 */
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_XBGR1555:
+		/* Data format */
+		ctrl = (format == DRM_FORMAT_RGB565 ||
+			format == DRM_FORMAT_BGR565) ?
+			(ctrl & ~CTRL_DF16) : (ctrl | CTRL_DF16);
+
+		ctrl |= CTRL_SET_WORD_LENGTH(0x0);
+
+		/* Byte packing */
+		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+
+		/* 'BGR' order */
+		if (format == DRM_FORMAT_BGR565		||
+		    format == DRM_FORMAT_ABGR1555	||
+		    format == DRM_FORMAT_XBGR1555)
+			writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+			       CTRL2_EVEN_LINE_PATTERN(0x5),
+			       lcdif->base + LCDIF_CTRL2 + REG_SET);
+		break;
+		/* bpp 32 */
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+		/*Data format */
+		ctrl &= ~CTRL_DF24;
+		ctrl |= CTRL_SET_WORD_LENGTH(3);
+
+		if (format == DRM_FORMAT_RGBA8888 ||
+		    format == DRM_FORMAT_RGBX8888)
+			ctrl |= CTRL_SHIFT_DIR(1) | CTRL_SHIFT_NUM(8);
+
+		/* Byte packing */
+		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+
+		/* 'BGR' order */
+		if (format == DRM_FORMAT_ABGR8888 ||
+		    format == DRM_FORMAT_XBGR8888)
+			writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+			       CTRL2_EVEN_LINE_PATTERN(0x5),
+			       lcdif->base + LCDIF_CTRL2 + REG_SET);
+		break;
+	default:
+		dev_err(lcdif->dev, "unsupported pixel format: %s\n",
+			drm_get_format_name(format, &format_name));
+		return -EINVAL;
+	}
+
+	writel(ctrl,  lcdif->base + LCDIF_CTRL);
+	writel(ctrl1, lcdif->base + LCDIF_CTRL1);
+
+	return 0;
+}
+EXPORT_SYMBOL(lcdif_set_pix_fmt);
+
+void lcdif_set_bus_fmt(struct lcdif_soc *lcdif, u32 bus_format)
+{
+	u32 bus_width;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
+		break;
+	default:
+		dev_err(lcdif->dev, "unknown bus format: %#x\n", bus_format);
+		return;
+	}
+
+	writel(CTRL_SET_BUS_WIDTH(0x3), lcdif->base + LCDIF_CTRL + REG_CLR);
+	writel(bus_width, lcdif->base + LCDIF_CTRL + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_set_bus_fmt);
+
+void lcdif_set_fb_addr(struct lcdif_soc *lcdif, int id, u32 addr)
+{
+	switch (id) {
+	case 0:
+		/* primary plane */
+		writel(addr, lcdif->base + LCDIF_NEXT_BUF);
+		break;
+	default:
+		/* TODO: add overlay support */
+		return;
+	}
+}
+EXPORT_SYMBOL(lcdif_set_fb_addr);
+
+void lcdif_set_fb_hcrop(struct lcdif_soc *lcdif, u32 src_w,
+			u32 fb_w, bool crop)
+{
+	u32 mask_cnt, htotal, hcount;
+	u32 vdctrl2, vdctrl3, vdctrl4, transfer_count;
+	u32 pigeon_12_0, pigeon_12_1, pigeon_12_2;
+
+	if (!crop) {
+		writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_0);
+		writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+		return;
+	}
+
+	/* transfer_count's hcount, vdctrl2's htotal and vdctrl4's
+	 * H_VALID_DATA_CNT should use fb width instead of hactive
+	 * when requires cropping.
+	 * */
+	transfer_count = readl(lcdif->base + LCDIF_TRANSFER_COUNT);
+	hcount = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+
+	transfer_count &= ~TRANSFER_COUNT_SET_HCOUNT(0xffff);
+	transfer_count |= TRANSFER_COUNT_SET_HCOUNT(fb_w);
+	writel(transfer_count, lcdif->base + LCDIF_TRANSFER_COUNT);
+
+	vdctrl2 = readl(lcdif->base + LCDIF_VDCTRL2);
+	htotal  = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2);
+	htotal  += fb_w - hcount;
+	vdctrl2 &= ~VDCTRL2_SET_HSYNC_PERIOD(0x3ffff);
+	vdctrl2 |= VDCTRL2_SET_HSYNC_PERIOD(htotal);
+	writel(vdctrl2, lcdif->base + LCDIF_VDCTRL2);
+
+	vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+	vdctrl4 &= ~SET_DOTCLK_H_VALID_DATA_CNT(0x3ffff);
+	vdctrl4 |= SET_DOTCLK_H_VALID_DATA_CNT(fb_w);
+	writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+
+	/* configure related pigeon registers */
+	vdctrl3  = readl(lcdif->base + LCDIF_VDCTRL3);
+	mask_cnt = GET_HOR_WAIT_CNT(vdctrl3) - 5;
+
+	pigeon_12_0 = PIGEON_12_0_SET_STATE_MASK(0x24)		|
+		      PIGEON_12_0_SET_MASK_CNT(mask_cnt)	|
+		      PIGEON_12_0_SET_MASK_CNT_SEL(0x6)		|
+		      PIGEON_12_0_POL_ACTIVE_LOW		|
+		      PIGEON_12_0_EN;
+	writel(pigeon_12_0, lcdif->base + HW_EPDC_PIGEON_12_0);
+
+	pigeon_12_1 = PIGEON_12_1_SET_CLR_CNT(src_w) |
+		      PIGEON_12_1_SET_SET_CNT(0x0);
+	writel(pigeon_12_1, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+	pigeon_12_2 = 0x0;
+	writel(pigeon_12_2, lcdif->base + HW_EPDC_PIGEON_12_2);
+}
+EXPORT_SYMBOL(lcdif_set_fb_hcrop);
+
+
+void lcdif_set_mode(struct lcdif_soc *lcdif, struct videomode *vmode)
+{
+	const struct of_device_id *of_id =
+			of_match_device(imx_lcdif_dt_ids, lcdif->dev);
+	const struct lcdif_soc_pdata *soc_pdata;
+	u32 vdctrl0, vdctrl1, vdctrl2, vdctrl3, vdctrl4, htotal;
+
+	if (unlikely(!of_id))
+		return;
+	soc_pdata = of_id->data;
+
+	/* Clear the FIFO */
+	writel(CTRL1_FIFO_CLEAR, lcdif->base + LCDIF_CTRL1 + REG_SET);
+	writel(CTRL1_FIFO_CLEAR, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+
+	/* set pixel clock rate */
+	clk_disable_unprepare(lcdif->clk_pix);
+	clk_set_rate(lcdif->clk_pix, vmode->pixelclock);
+	clk_prepare_enable(lcdif->clk_pix);
+
+	/* config display timings */
+	writel(TRANSFER_COUNT_SET_VCOUNT(vmode->vactive) |
+	       TRANSFER_COUNT_SET_HCOUNT(vmode->hactive),
+	       lcdif->base + LCDIF_TRANSFER_COUNT);
+
+	vdctrl0 = VDCTRL0_ENABLE_PRESENT		|
+		  VDCTRL0_VSYNC_PERIOD_UNIT 		|
+		  VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	|
+		  VDCTRL0_SET_VSYNC_PULSE_WIDTH(vmode->vsync_len);
+
+	/* Polarities */
+	if (soc_pdata) {
+		if ((soc_pdata->hsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_HSYNC_LOW) ||
+		    (!soc_pdata->hsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_HSYNC_HIGH))
+				vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+
+		if ((soc_pdata->vsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_VSYNC_LOW) ||
+		    (!soc_pdata->vsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_VSYNC_HIGH))
+				vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+
+		if ((soc_pdata->de_invert &&
+		     vmode->flags & DISPLAY_FLAGS_DE_LOW) ||
+		    (!soc_pdata->de_invert &&
+		     vmode->flags & DISPLAY_FLAGS_DE_HIGH))
+				vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+	} else {
+		if (vmode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+			vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+		if (vmode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+			vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+		if (vmode->flags & DISPLAY_FLAGS_DE_HIGH)
+			vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+	}
+
+	if (vmode->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+		vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+	writel(vdctrl0, lcdif->base + LCDIF_VDCTRL0);
+
+	vdctrl1 = vmode->vactive + vmode->vsync_len +
+		  vmode->vfront_porch + vmode->vback_porch;
+	writel(vdctrl1, lcdif->base + LCDIF_VDCTRL1);
+
+	htotal = vmode->hactive + vmode->hsync_len +
+		 vmode->hfront_porch + vmode->hback_porch;
+	vdctrl2 = VDCTRL2_SET_HSYNC_PULSE_WIDTH(vmode->hsync_len) |
+		  VDCTRL2_SET_HSYNC_PERIOD(htotal);
+	writel(vdctrl2, lcdif->base + LCDIF_VDCTRL2);
+
+	vdctrl3 = SET_HOR_WAIT_CNT(vmode->hsync_len + vmode->hback_porch) |
+		  SET_VERT_WAIT_CNT(vmode->vsync_len + vmode->vback_porch);
+	writel(vdctrl3, lcdif->base + LCDIF_VDCTRL3);
+
+	vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(vmode->hactive);
+	writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+}
+EXPORT_SYMBOL(lcdif_set_mode);
+
+void lcdif_enable_controller(struct lcdif_soc *lcdif)
+{
+	u32 ctrl2, vdctrl4;
+
+	ctrl2	= readl(lcdif->base + LCDIF_CTRL2);
+	vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+
+	ctrl2 &= ~CTRL2_OUTSTANDING_REQS(0x7);
+	ctrl2 |= CTRL2_OUTSTANDING_REQS(REQ_16);
+	writel(ctrl2, lcdif->base + LCDIF_CTRL2);
+
+	/* Continous dotclock mode */
+	writel(CTRL_BYPASS_COUNT | CTRL_DOTCLK_MODE,
+	       lcdif->base + LCDIF_CTRL + REG_SET);
+
+	/* enable the SYNC signals first, then the DMA engine */
+	vdctrl4 |= VDCTRL4_SYNC_SIGNALS_ON;
+	writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+
+	/* enable underflow recovery */
+	writel(CTRL1_RECOVERY_ON_UNDERFLOW,
+	       lcdif->base + LCDIF_CTRL1 + REG_SET);
+
+	/* run lcdif */
+	writel(CTRL_MASTER, lcdif->base + LCDIF_CTRL + REG_SET);
+	writel(CTRL_RUN, lcdif->base + LCDIF_CTRL + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_enable_controller);
+
+void lcdif_disable_controller(struct lcdif_soc *lcdif)
+{
+	int ret;
+	u32 ctrl, vdctrl4;
+
+	writel(CTRL_RUN, lcdif->base + LCDIF_CTRL + REG_CLR);
+	writel(CTRL_DOTCLK_MODE, lcdif->base + LCDIF_CTRL + REG_CLR);
+
+	ret = readl_poll_timeout(lcdif->base + LCDIF_CTRL, ctrl,
+				 !(ctrl & CTRL_RUN), 0, 1000);
+	if (WARN_ON(ret))
+		dev_err(lcdif->dev, "disable lcdif run timeout\n");
+
+	writel(CTRL_MASTER, lcdif->base + LCDIF_CTRL + REG_CLR);
+
+	vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+	vdctrl4 &= ~VDCTRL4_SYNC_SIGNALS_ON;
+	writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+}
+EXPORT_SYMBOL(lcdif_disable_controller);
+
+long lcdif_pix_clk_round_rate(struct lcdif_soc *lcdif,
+			      unsigned long rate)
+{
+	if (unlikely(!rate))
+		return -EINVAL;
+
+	return clk_round_rate(lcdif->clk_pix, rate);
+}
+EXPORT_SYMBOL(lcdif_pix_clk_round_rate);
+
+static int platform_remove_device_fn(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+	device_for_each_child(&pdev->dev, NULL, platform_remove_device_fn);
+}
+
+static int lcdif_add_client_devices(struct lcdif_soc *lcdif)
+{
+	int ret = 0, i;
+	struct device *dev = lcdif->dev;
+	struct platform_device *pdev = NULL;
+	struct device_node *of_node;
+
+	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+		of_node = of_graph_get_port_by_id(dev->of_node, i);
+		if (!of_node) {
+			dev_info(dev, "no port@%d node in %s\n",
+				 i, dev->of_node->full_name);
+			continue;
+		}
+		of_node_put(of_node);
+
+		pdev = platform_device_alloc(client_reg[i].name, i);
+		if (!pdev) {
+			dev_err(dev, "Can't allocate port pdev\n");
+			ret = -ENOMEM;
+			goto err_register;
+		}
+
+		pdev->dev.parent = dev;
+		client_reg[i].pdata.of_node = of_node;
+
+		ret = platform_device_add_data(pdev, &client_reg[i].pdata,
+					       sizeof(client_reg[i].pdata));
+		if (!ret)
+			ret = platform_device_add(pdev);
+		if (ret) {
+			platform_device_put(pdev);
+			goto err_register;
+		}
+
+		pdev->dev.of_node = of_node;
+	}
+
+	if (!pdev)
+		return -ENODEV;
+
+	return 0;
+
+err_register:
+	platform_device_unregister_children(to_platform_device(dev));
+	return ret;
+}
+
+static int lcdif_of_parse_resets(struct lcdif_soc *lcdif)
+{
+	int ret;
+	struct device *dev = lcdif->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *parent, *child;
+	struct of_phandle_args args;
+	struct reset_control *rstc;
+	const char *compat;
+	uint32_t len, rstc_num = 0;
+
+	ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
+					 0, &args);
+	if (ret)
+		return ret;
+
+	parent = args.np;
+	for_each_child_of_node(parent, child) {
+		compat = of_get_property(child, "compatible", NULL);
+		if (!compat)
+			continue;
+
+		rstc = of_reset_control_array_get(child, false, false, true);
+		if (IS_ERR(rstc))
+			continue;
+
+		len = strlen(compat);
+		if (!of_compat_cmp("lcdif,soft-resetn", compat, len)) {
+			lcdif->soft_resetn = rstc;
+			rstc_num++;
+		} else if (!of_compat_cmp("lcdif,clk-enable", compat, len)) {
+			lcdif->clk_enable = rstc;
+			rstc_num++;
+		}
+		else
+			dev_warn(dev, "invalid lcdif reset node: %s\n", compat);
+	}
+
+	if (!rstc_num) {
+		dev_err(dev, "no invalid reset control exists\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int imx_lcdif_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct lcdif_soc *lcdif;
+	struct resource *res;
+
+	dev_dbg(dev, "%s: probe begin\n", __func__);
+
+	lcdif = devm_kzalloc(dev, sizeof(*lcdif), GFP_KERNEL);
+	if (!lcdif) {
+		dev_err(dev, "Can't allocate 'lcdif_soc' structure\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	lcdif->irq = platform_get_irq(pdev, 0);
+	if (lcdif->irq < 0)
+		return -ENODEV;
+
+	lcdif->clk_pix = devm_clk_get(dev, "pix");
+	if (IS_ERR(lcdif->clk_pix))
+		return PTR_ERR(lcdif->clk_pix);
+
+	lcdif->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+	if (IS_ERR(lcdif->clk_disp_axi))
+		lcdif->clk_disp_axi = NULL;
+
+	lcdif->clk_disp_apb = devm_clk_get(dev, "disp-apb");
+	if (IS_ERR(lcdif->clk_disp_apb))
+		lcdif->clk_disp_apb = NULL;
+
+	lcdif->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(lcdif->base))
+		return PTR_ERR(lcdif->base);
+
+	lcdif->dev = dev;
+	ret = lcdif_of_parse_resets(lcdif);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, lcdif);
+
+	atomic_set(&lcdif->rpm_suspended, 0);
+	pm_runtime_enable(dev);
+	atomic_inc(&lcdif->rpm_suspended);
+
+	dev_dbg(dev, "%s: probe end\n", __func__);
+
+	return lcdif_add_client_devices(lcdif);
+}
+
+static int imx_lcdif_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_lcdif_suspend(struct device *dev)
+{
+	return imx_lcdif_runtime_suspend(dev);
+}
+
+static int imx_lcdif_resume(struct device *dev)
+{
+	return imx_lcdif_runtime_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int imx_lcdif_runtime_suspend(struct device *dev)
+{
+	struct lcdif_soc *lcdif = dev_get_drvdata(dev);
+
+	if (atomic_inc_return(&lcdif->rpm_suspended) > 1)
+		return 0;
+
+	lcdif_disable_clocks(lcdif);
+
+	release_bus_freq(BUS_FREQ_HIGH);
+
+	return 0;
+}
+
+static int imx_lcdif_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct lcdif_soc *lcdif = dev_get_drvdata(dev);
+
+	if (unlikely(!atomic_read(&lcdif->rpm_suspended))) {
+		dev_warn(lcdif->dev, "Unbalanced %s!\n", __func__);
+		return 0;
+	}
+
+	if (!atomic_dec_and_test(&lcdif->rpm_suspended))
+		return 0;
+
+	request_bus_freq(BUS_FREQ_HIGH);
+
+	ret = lcdif_enable_clocks(lcdif);
+	if (ret) {
+		release_bus_freq(BUS_FREQ_HIGH);
+		return ret;
+	}
+
+	ret = lcdif_rstc_reset(lcdif->soft_resetn, false);
+	if (ret) {
+		dev_err(dev, "deassert soft_resetn failed\n");
+		return ret;
+	}
+
+	ret = lcdif_rstc_reset(lcdif->clk_enable, true);
+	if (ret) {
+		dev_err(dev, "assert clk_enable failed\n");
+		return ret;
+	}
+
+	/* Pull LCDIF out of reset */
+	writel(0x0, lcdif->base + LCDIF_CTRL);
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops imx_lcdif_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(imx_lcdif_suspend, imx_lcdif_resume)
+	SET_RUNTIME_PM_OPS(imx_lcdif_runtime_suspend,
+			   imx_lcdif_runtime_resume, NULL)
+};
+
+struct platform_driver imx_lcdif_driver = {
+	.probe    = imx_lcdif_probe,
+	.remove   = imx_lcdif_remove,
+	.driver   = {
+		.name = DRIVER_NAME,
+		.of_match_table = imx_lcdif_dt_ids,
+		.pm = &imx_lcdif_pm_ops,
+	},
+};
+
+module_platform_driver(imx_lcdif_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIF Display Controller driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdif/lcdif-regs.h
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdif/lcdif-regs.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __LCDIF_REGS_H
+#define __LCDIF_REGS_H
+
+#define REG_SET	4
+#define REG_CLR	8
+
+/* regs offset */
+#define LCDIF_CTRL			0x00
+#define LCDIF_CTRL1			0X10
+#define LCDIF_CTRL2			0X20
+#define LCDIF_TRANSFER_COUNT		0x30
+#define LCDIF_CUR_BUF			0x40
+#define LCDIF_NEXT_BUF			0x50
+#define LCDIF_TIMING			0x60
+#define LCDIF_VDCTRL0			0x70
+#define LCDIF_VDCTRL1			0x80
+#define LCDIF_VDCTRL2			0x90
+#define LCDIF_VDCTRL3			0xa0
+#define LCDIF_VDCTRL4			0xb0
+
+/* pigeon registers for crop */
+#define HW_EPDC_PIGEON_12_0		0xb00
+#define HW_EPDC_PIGEON_12_1		0xb10
+#define HW_EPDC_PIGEON_12_2		0xb20
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+#define SWIZZLE_LE		0 /* Little-Endian or No swap */
+#define SWIZZLE_BE		1 /* Big-Endian or swap all */
+#define SWIZZLE_HWD		2 /* Swap half-words */
+#define SWIZZLE_HWD_BYTE	3 /* Swap bytes within each half-word */
+
+/* regs bit fields */
+#define CTRL_SFTRST			BIT(31)
+#define CTRL_CLKGATE			BIT(30)
+#define CTRL_SHIFT_DIR(x)		REG_PUT((x), 26, 26)
+#define CTRL_SHIFT_NUM(x)		REG_PUT((x), 25, 21)
+#define CTRL_BYPASS_COUNT		BIT(19)
+#define CTRL_VSYNC_MODE			BIT(18)
+#define CTRL_DOTCLK_MODE		BIT(17)
+#define CTRL_DATA_SELECT		BIT(16)
+#define CTRL_INPUT_SWIZZLE(x)		REG_PUT((x), 15, 14)
+#define CTRL_CSC_SWIZZLE(x)		REG_PUT((x), 13, 12)
+#define CTRL_SET_BUS_WIDTH(x)		REG_PUT((x), 11, 10)
+#define CTRL_GET_BUS_WIDTH(x)		REG_GET((x), 11, 10)
+#define CTRL_BUS_WIDTH_MASK		REG_PUT((0x3), 11, 10)
+#define CTRL_SET_WORD_LENGTH(x)		REG_PUT((x), 9, 8)
+#define CTRL_GET_WORD_LENGTH(x)		REG_GET((x), 9, 8)
+#define CTRL_MASTER			BIT(5)
+#define CTRL_DF16			BIT(3)
+#define CTRL_DF18			BIT(2)
+#define CTRL_DF24			BIT(1)
+#define CTRL_RUN			BIT(0)
+
+#define CTRL1_RECOVERY_ON_UNDERFLOW	BIT(24)
+#define CTRL1_FIFO_CLEAR		BIT(21)
+#define CTRL1_SET_BYTE_PACKAGING(x)	REG_PUT((x), 19, 16)
+#define CTRL1_GET_BYTE_PACKAGING(x)	REG_GET((x), 19, 16)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN	BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ	BIT(9)
+
+#define REQ_1	0
+#define REQ_2	1
+#define REQ_4	2
+#define REQ_8	3
+#define REQ_16	4
+
+#define CTRL2_OUTSTANDING_REQS(x)	REG_PUT((x), 23, 21)
+#define CTRL2_ODD_LINE_PATTERN(x)	REG_PUT((x), 18, 16)
+#define CTRL2_EVEN_LINE_PATTERN(x)	REG_PUT((x), 14, 12)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x)	(((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x)	(((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x)	((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x)	((x) & 0xffff)
+
+#define VDCTRL0_ENABLE_PRESENT		BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH		BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH		BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING	BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH		BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT	BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	BIT(20)
+#define VDCTRL0_HALF_LINE		BIT(19)
+#define VDCTRL0_HALF_LINE_MODE		BIT(18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PULSE_WIDTH(x) (((x) & 0x3fff) << 18)
+#define VDCTRL2_GET_HSYNC_PULSE_WIDTH(x) (((x) >> 18) & 0x3fff)
+#define VDCTRL2_SET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS	BIT(29)
+#define VDCTRL3_VSYNC_ONLY		BIT(28)
+#define SET_HOR_WAIT_CNT(x)		(((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x)		(((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x)		((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x)		((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x)	(((x) & 0x7) << 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x)	(((x) >> 29) & 0x7) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON		BIT(18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x)	((x) & 0x3ffff)
+
+#define PIGEON_12_0_SET_STATE_MASK(x)	REG_PUT((x), 31, 24)
+#define PIGEON_12_0_SET_MASK_CNT(x)	REG_PUT((x), 23, 12)
+#define PIGEON_12_0_SET_MASK_CNT_SEL(x)	REG_PUT((x), 11,  8)
+#define PIGEON_12_0_SET_OFFSET(x)	REG_PUT((x),  7,  4)
+#define PIGEON_12_0_SET_INC_SEL(x)	REG_PUT((x),  3,  2)
+#define PIGEON_12_0_POL_ACTIVE_LOW	BIT(1)
+#define PIGEON_12_0_EN			BIT(0)
+
+#define PIGEON_12_1_SET_CLR_CNT(x)	REG_PUT((x), 31, 16)
+#define PIGEON_12_1_SET_SET_CNT(x)	REG_PUT((x), 15,  0)
+
+#define STMLCDIF_8BIT  1 /* pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
+
+#define MIN_XRES			120
+#define MIN_YRES			120
+#define MAX_XRES			0xffff
+#define MAX_YRES			0xffff
+
+#endif
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdifv3/Kconfig
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdifv3/Kconfig
@@ -0,0 +1,9 @@
+config IMX_LCDIFV3_CORE
+	tristate "i.MX LCDIFV3 core support"
+	depends on ARCH_MXC
+	select RESET_CONTROLLER
+	help
+	  Choose this if you have a NXP i.MX8MP platform and want to use the
+	  LCDIFV3 display controller. This option only enables LCDIFV3 base
+	  support.
+
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdifv3/Makefile
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdifv3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IMX_LCDIFV3_CORE) += imx-lcdifv3-core.o
+
+imx-lcdifv3-core-objs := lcdifv3-common.o
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdifv3/lcdifv3-common.c
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdifv3/lcdifv3-common.c
@@ -0,0 +1,862 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+#include <drm/drm_fourcc.h>
+#include <video/imx-lcdifv3.h>
+#include <video/videomode.h>
+
+#include "lcdifv3-regs.h"
+
+#define DRIVER_NAME "imx-lcdifv3"
+
+struct lcdifv3_soc {
+	struct device *dev;
+
+	int irq;
+	void __iomem *base;
+	struct regmap *gpr;
+	atomic_t rpm_suspended;
+
+	struct clk *clk_pix;
+	struct clk *clk_disp_axi;
+	struct clk *clk_disp_apb;
+
+	u32 thres_low_mul;
+	u32 thres_low_div;
+	u32 thres_high_mul;
+	u32 thres_high_div;
+};
+
+struct lcdifv3_soc_pdata {
+	bool hsync_invert;
+	bool vsync_invert;
+	bool de_invert;
+	bool hdmimix;
+};
+
+struct lcdifv3_platform_reg {
+	struct lcdifv3_client_platformdata pdata;
+	char *name;
+};
+
+static struct lcdifv3_platform_reg client_reg[] = {
+	{
+		.pdata = { },
+		.name  = "imx-lcdifv3-crtc",
+	},
+};
+
+static struct lcdifv3_soc_pdata imx8mp_lcdif1_pdata = {
+	.hsync_invert = false,
+	.vsync_invert = false,
+	.de_invert    = false,
+	.hdmimix     = false,
+};
+
+static struct lcdifv3_soc_pdata imx8mp_lcdif2_pdata = {
+	.hsync_invert = false,
+	.vsync_invert = false,
+	.de_invert    = true,
+	.hdmimix      = false,
+};
+
+static struct lcdifv3_soc_pdata imx8mp_lcdif3_pdata = {
+	.hsync_invert = false,
+	.vsync_invert = false,
+	.de_invert    = false,
+	.hdmimix     = true,
+};
+static const struct of_device_id imx_lcdifv3_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-lcdif1", .data = &imx8mp_lcdif1_pdata, },
+	{ .compatible = "fsl,imx8mp-lcdif2", .data = &imx8mp_lcdif2_pdata, },
+	{ .compatible = "fsl,imx8mp-lcdif3", .data = &imx8mp_lcdif3_pdata,},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_lcdifv3_dt_ids);
+
+static int lcdifv3_enable_clocks(struct lcdifv3_soc *lcdifv3)
+{
+	int ret;
+
+	if (lcdifv3->clk_disp_axi) {
+		ret = clk_prepare_enable(lcdifv3->clk_disp_axi);
+		if (ret)
+			return ret;
+	}
+
+	if (lcdifv3->clk_disp_apb) {
+		ret = clk_prepare_enable(lcdifv3->clk_disp_apb);
+		if (ret)
+			goto disable_disp_axi;
+	}
+
+	ret = clk_prepare_enable(lcdifv3->clk_pix);
+	if (ret)
+		goto disable_disp_apb;
+
+	return 0;
+
+disable_disp_apb:
+	if (lcdifv3->clk_disp_apb)
+		clk_disable_unprepare(lcdifv3->clk_disp_apb);
+disable_disp_axi:
+	if (lcdifv3->clk_disp_axi)
+		clk_disable_unprepare(lcdifv3->clk_disp_axi);
+
+	return ret;
+}
+
+static void lcdifv3_disable_clocks(struct lcdifv3_soc *lcdifv3)
+{
+	clk_disable_unprepare(lcdifv3->clk_pix);
+
+	if (lcdifv3->clk_disp_axi)
+		clk_disable_unprepare(lcdifv3->clk_disp_axi);
+
+	if (lcdifv3->clk_disp_apb)
+		clk_disable_unprepare(lcdifv3->clk_disp_apb);
+}
+
+static void lcdifv3_enable_plane_panic(struct lcdifv3_soc *lcdifv3)
+{
+	u32 panic_thres, thres_low, thres_high;
+
+	/* apb clock has been enabled */
+
+	/* As suggestion, the thres_low should be 1/3 FIFO,
+	 * and thres_high should be 2/3 FIFO (The FIFO size
+	 * is 8KB = 512 * 128bit).
+	 * threshold = n * 128bit (n: 0 ~ 511)
+	 */
+	thres_low  = DIV_ROUND_UP(511 * lcdifv3->thres_low_mul,
+			lcdifv3->thres_low_div);
+	thres_high = DIV_ROUND_UP(511 * lcdifv3->thres_high_mul,
+			lcdifv3->thres_high_div);
+
+	panic_thres = PANIC0_THRES_PANIC_THRES_LOW(thres_low)	|
+		      PANIC0_THRES_PANIC_THRES_HIGH(thres_high);
+
+	writel(panic_thres, lcdifv3->base + LCDIFV3_PANIC0_THRES);
+
+	/* Enable Panic:
+	 *
+	 * As designed, the panic won't trigger an irq,
+	 * so it is unnecessary to handle this as an irq
+	 * and NoC + QoS modules will handle panic
+	 * automatically.
+	 */
+	writel(INT_ENABLE_D1_PLANE_PANIC_EN,
+	       lcdifv3->base + LCDIFV3_INT_ENABLE_D1);
+}
+
+int lcdifv3_vblank_irq_get(struct lcdifv3_soc *lcdifv3)
+{
+	return lcdifv3->irq;
+}
+EXPORT_SYMBOL(lcdifv3_vblank_irq_get);
+
+/* TODO: use VS_BLANK or VSYNC? */
+void lcdifv3_vblank_irq_enable(struct lcdifv3_soc *lcdifv3)
+{
+	uint32_t int_enable_d0;
+
+	int_enable_d0 = readl(lcdifv3->base + LCDIFV3_INT_ENABLE_D0);
+	int_enable_d0 |= INT_STATUS_D0_VS_BLANK;
+
+	/* W1C */
+	writel(INT_STATUS_D0_VS_BLANK,
+	       lcdifv3->base + LCDIFV3_INT_STATUS_D0);
+	/* enable */
+	writel(int_enable_d0,
+	       lcdifv3->base + LCDIFV3_INT_ENABLE_D0);
+}
+EXPORT_SYMBOL(lcdifv3_vblank_irq_enable);
+
+void lcdifv3_vblank_irq_disable(struct lcdifv3_soc *lcdifv3)
+{
+	uint32_t int_enable_d0;
+
+	int_enable_d0 = readl(lcdifv3->base + LCDIFV3_INT_ENABLE_D0);
+	int_enable_d0 &= ~INT_STATUS_D0_VS_BLANK;
+
+	/* disable */
+	writel(int_enable_d0,
+	       lcdifv3->base + LCDIFV3_INT_ENABLE_D0);
+	/* W1C */
+	writel(INT_STATUS_D0_VS_BLANK,
+	       lcdifv3->base + LCDIFV3_INT_STATUS_D0);
+}
+EXPORT_SYMBOL(lcdifv3_vblank_irq_disable);
+
+void lcdifv3_vblank_irq_clear(struct lcdifv3_soc *lcdifv3)
+{
+	/* W1C */
+	writel(INT_STATUS_D0_VS_BLANK,
+	       lcdifv3->base + LCDIFV3_INT_STATUS_D0);
+}
+EXPORT_SYMBOL(lcdifv3_vblank_irq_clear);
+
+static uint32_t lcdifv3_get_bpp_from_fmt(uint32_t format)
+{
+	/* TODO: only support RGB for now */
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_XBGR1555:
+		return 16;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+		return 32;
+	default:
+		/* unsupported format */
+		return 0;
+	}
+}
+
+/*
+ * Get the bus format supported by LCDIF
+ * according to drm fourcc format
+ */
+int lcdifv3_get_bus_fmt_from_pix_fmt(struct lcdifv3_soc *lcdifv3,
+				     uint32_t format)
+{
+	uint32_t bpp;
+
+	bpp = lcdifv3_get_bpp_from_fmt(format);
+	if (!bpp)
+		return -EINVAL;
+
+	switch (bpp) {
+	case 16:
+		return MEDIA_BUS_FMT_RGB565_1X16;
+	case 18:
+		return MEDIA_BUS_FMT_RGB666_1X18;
+	case 24:
+	case 32:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(lcdifv3_get_bus_fmt_from_pix_fmt);
+
+int lcdifv3_set_pix_fmt(struct lcdifv3_soc *lcdifv3, u32 format)
+{
+	struct drm_format_name_buf format_name;
+	uint32_t ctrldescl0_5 = 0;
+
+	ctrldescl0_5 = readl(lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+
+	ctrldescl0_5 &= ~(CTRLDESCL0_5_BPP(0xf) | CTRLDESCL0_5_YUV_FORMAT(0x3));
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+		ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP16_RGB565);
+		break;
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_XRGB1555:
+		ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP16_ARGB1555);
+		break;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP32_ARGB8888);
+		break;
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+		ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP32_ABGR8888);
+		break;
+	default:
+		dev_err(lcdifv3->dev, "unsupported pixel format: %s\n",
+			drm_get_format_name(format, &format_name));
+		return -EINVAL;
+	}
+
+	writel(ctrldescl0_5,  lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+
+	return 0;
+}
+EXPORT_SYMBOL(lcdifv3_set_pix_fmt);
+
+void lcdifv3_set_bus_fmt(struct lcdifv3_soc *lcdifv3, u32 bus_format)
+{
+	uint32_t disp_para = 0;
+
+	disp_para = readl(lcdifv3->base + LCDIFV3_DISP_PARA);
+
+	/* clear line pattern bits */
+	disp_para &= ~DISP_PARA_LINE_PATTERN(0xf);
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		disp_para |= DISP_PARA_LINE_PATTERN(LP_RGB565);
+		break;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		disp_para |= DISP_PARA_LINE_PATTERN(LP_RGB888_OR_YUV444);
+		break;
+	default:
+		dev_err(lcdifv3->dev, "unknown bus format: %#x\n", bus_format);
+		return;
+	}
+
+	/* config display mode: default is normal mode */
+	disp_para &= ~DISP_PARA_DISP_MODE(3);
+	disp_para |= DISP_PARA_DISP_MODE(0);
+
+	writel(disp_para, lcdifv3->base + LCDIFV3_DISP_PARA);
+}
+EXPORT_SYMBOL(lcdifv3_set_bus_fmt);
+
+void lcdifv3_set_fb_addr(struct lcdifv3_soc *lcdifv3, int id, u32 addr)
+{
+	switch (id) {
+	case 0:
+		/* primary plane */
+		writel(addr, lcdifv3->base + LCDIFV3_CTRLDESCL_LOW0_4);
+		break;
+	default:
+		/* TODO: add overlay support */
+		return;
+	}
+}
+EXPORT_SYMBOL(lcdifv3_set_fb_addr);
+
+void lcdifv3_set_fb_hcrop(struct lcdifv3_soc *lcdifv3, u32 src_w,
+			u32 pitch, bool crop)
+{
+	uint32_t ctrldescl0_3 = 0;
+
+	/* config P_SIZE and T_SIZE:
+	 * 1. P_SIZE and T_SIZE should never
+	 *    be less than AXI bus width.
+	 * 2. P_SIZE should never be less than T_SIZE.
+	 */
+	ctrldescl0_3 |= CTRLDESCL0_3_P_SIZE(2);
+	ctrldescl0_3 |= CTRLDESCL0_3_T_SIZE(2);
+
+	/* config pitch */
+	ctrldescl0_3 |= CTRLDESCL0_3_PITCH(pitch);
+
+	/* enable frame clear to clear FIFO data on
+	 * every vsync blank period to make sure no
+	 * dirty data exits to affect next frame
+	 * display, otherwise some flicker issue may
+	 * be observed in some cases.
+	 */
+	ctrldescl0_3 |= CTRLDESCL0_3_STATE_CLEAR_VSYNC;
+
+	writel(ctrldescl0_3, lcdifv3->base + LCDIFV3_CTRLDESCL0_3);
+}
+EXPORT_SYMBOL(lcdifv3_set_fb_hcrop);
+
+
+void lcdifv3_set_mode(struct lcdifv3_soc *lcdifv3, struct videomode *vmode)
+{
+	const struct of_device_id *of_id =
+			of_match_device(imx_lcdifv3_dt_ids, lcdifv3->dev);
+	const struct lcdifv3_soc_pdata *soc_pdata;
+	u32 disp_size, hsyn_para, vsyn_para, vsyn_hsyn_width, ctrldescl0_1;
+
+	if (unlikely(!of_id))
+		return;
+	soc_pdata = of_id->data;
+
+	/* set pixel clock rate */
+	clk_disable_unprepare(lcdifv3->clk_pix);
+	clk_set_rate(lcdifv3->clk_pix, vmode->pixelclock);
+	clk_prepare_enable(lcdifv3->clk_pix);
+
+	/* config display timings */
+	disp_size = DISP_SIZE_DELTA_Y(vmode->vactive) |
+		    DISP_SIZE_DELTA_X(vmode->hactive);
+	writel(disp_size, lcdifv3->base + LCDIFV3_DISP_SIZE);
+
+	WARN_ON(!vmode->hback_porch || !vmode->hfront_porch);
+	hsyn_para = HSYN_PARA_BP_H(vmode->hback_porch) |
+		    HSYN_PARA_FP_H(vmode->hfront_porch);
+	writel(hsyn_para, lcdifv3->base + LCDIFV3_HSYN_PARA);
+
+	WARN_ON(!vmode->vback_porch || !vmode->vfront_porch);
+	vsyn_para = VSYN_PARA_BP_V(vmode->vback_porch) |
+		    VSYN_PARA_FP_V(vmode->vfront_porch);
+	writel(vsyn_para, lcdifv3->base + LCDIFV3_VSYN_PARA);
+
+	WARN_ON(!vmode->vsync_len || !vmode->hsync_len);
+	vsyn_hsyn_width = VSYN_HSYN_WIDTH_PW_V(vmode->vsync_len) |
+			  VSYN_HSYN_WIDTH_PW_H(vmode->hsync_len);
+	writel(vsyn_hsyn_width, lcdifv3->base + LCDIFV3_VSYN_HSYN_WIDTH);
+
+	/* config layer size */
+	/* TODO: 32bits alignment for width */
+	ctrldescl0_1 = CTRLDESCL0_1_HEIGHT(vmode->vactive) |
+		       CTRLDESCL0_1_WIDTH(vmode->hactive);
+	writel(ctrldescl0_1, lcdifv3->base + LCDIFV3_CTRLDESCL0_1);
+
+	/* Polarities */
+	if (soc_pdata) {
+		if ((soc_pdata->hsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_HSYNC_HIGH) ||
+		    (!soc_pdata->hsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_HSYNC_LOW))
+			writel(CTRL_INV_HS, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_HS, lcdifv3->base + LCDIFV3_CTRL_CLR);
+
+		if ((soc_pdata->vsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_VSYNC_HIGH) ||
+		    (!soc_pdata->vsync_invert &&
+		     vmode->flags & DISPLAY_FLAGS_VSYNC_LOW))
+			writel(CTRL_INV_VS, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_VS, lcdifv3->base + LCDIFV3_CTRL_CLR);
+
+		if ((soc_pdata->de_invert &&
+		     vmode->flags & DISPLAY_FLAGS_DE_HIGH) ||
+		    (!soc_pdata->de_invert &&
+		     vmode->flags & DISPLAY_FLAGS_DE_LOW))
+			writel(CTRL_INV_DE, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_DE, lcdifv3->base + LCDIFV3_CTRL_CLR);
+	} else {
+		if (vmode->flags & DISPLAY_FLAGS_HSYNC_LOW)
+			writel(CTRL_INV_HS, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_HS, lcdifv3->base + LCDIFV3_CTRL_CLR);
+		if (vmode->flags & DISPLAY_FLAGS_VSYNC_LOW)
+			writel(CTRL_INV_VS, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_VS, lcdifv3->base + LCDIFV3_CTRL_CLR);
+		if (vmode->flags & DISPLAY_FLAGS_DE_LOW)
+			writel(CTRL_INV_DE, lcdifv3->base + LCDIFV3_CTRL_SET);
+		else
+			writel(CTRL_INV_DE, lcdifv3->base + LCDIFV3_CTRL_CLR);
+	}
+
+	if (vmode->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+		writel(CTRL_INV_PXCK, lcdifv3->base + LCDIFV3_CTRL_CLR);
+	else
+		writel(CTRL_INV_PXCK, lcdifv3->base + LCDIFV3_CTRL_SET);
+}
+EXPORT_SYMBOL(lcdifv3_set_mode);
+
+void lcdifv3_en_shadow_load(struct lcdifv3_soc *lcdifv3)
+{
+	u32 ctrldescl0_5;
+
+	ctrldescl0_5 = readl(lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+	ctrldescl0_5 |= CTRLDESCL0_5_SHADOW_LOAD_EN;
+
+	writel(ctrldescl0_5, lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+}
+EXPORT_SYMBOL(lcdifv3_en_shadow_load);
+
+void lcdifv3_enable_controller(struct lcdifv3_soc *lcdifv3)
+{
+	u32 disp_para, ctrldescl0_5;
+
+	disp_para = readl(lcdifv3->base + LCDIFV3_DISP_PARA);
+	ctrldescl0_5 = readl(lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+
+	/* disp on */
+	disp_para |= DISP_PARA_DISP_ON;
+	writel(disp_para, lcdifv3->base + LCDIFV3_DISP_PARA);
+
+	/* enable layer dma */
+	ctrldescl0_5 |= CTRLDESCL0_5_EN;
+	writel(ctrldescl0_5, lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+}
+EXPORT_SYMBOL(lcdifv3_enable_controller);
+
+void lcdifv3_disable_controller(struct lcdifv3_soc *lcdifv3)
+{
+	u32 disp_para, ctrldescl0_5;
+
+	disp_para = readl(lcdifv3->base + LCDIFV3_DISP_PARA);
+	ctrldescl0_5 = readl(lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+
+	/* disable dma */
+	ctrldescl0_5 &= ~CTRLDESCL0_5_EN;
+	writel(ctrldescl0_5, lcdifv3->base + LCDIFV3_CTRLDESCL0_5);
+
+	/* dma config only takes effect at the end of
+	 * one frame, so add delay to wait dma disable
+	 * done before turn off disp.
+	 */
+	usleep_range(20000, 25000);
+
+	/* disp off */
+	disp_para &= ~DISP_PARA_DISP_ON;
+	writel(disp_para, lcdifv3->base + LCDIFV3_DISP_PARA);
+}
+EXPORT_SYMBOL(lcdifv3_disable_controller);
+
+long lcdifv3_pix_clk_round_rate(struct lcdifv3_soc *lcdifv3,
+				unsigned long rate)
+{
+	if (unlikely(!rate))
+		return -EINVAL;
+
+	return clk_round_rate(lcdifv3->clk_pix, rate);
+}
+EXPORT_SYMBOL(lcdifv3_pix_clk_round_rate);
+
+static int hdmimix_lcdif3_setup(struct lcdifv3_soc *lcdifv3)
+{
+	struct device *dev = lcdifv3->dev;
+	int ret;
+
+	struct clk_bulk_data clocks[] = {
+		{ .id = "mix_apb" },
+		{ .id = "mix_axi" },
+		{ .id = "xtl_24m" },
+		{ .id = "mix_pix" },
+		{ .id = "lcdif_apb" },
+		{ .id = "lcdif_axi" },
+		{ .id = "lcdif_pdi" },
+		{ .id = "lcdif_pix" },
+		{ .id = "lcdif_spu" },
+		{ .id = "noc_hdmi"  },
+	};
+
+	/* power up hdmimix lcdif and nor */
+	ret = device_reset(dev);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+
+	/* enable lpcg of hdmimix lcdif and nor */
+	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(clocks), clocks);
+	if (ret < 0)
+		return ret;
+	ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int platform_remove_device_fn(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+	device_for_each_child(&pdev->dev, NULL, platform_remove_device_fn);
+}
+
+static DEFINE_MUTEX(lcdifv3_client_id_mutex);
+static int lcdifv3_client_id;
+
+static int lcdifv3_add_client_devices(struct lcdifv3_soc *lcdifv3)
+{
+	int ret = 0, i, id;
+	struct device *dev = lcdifv3->dev;
+	struct platform_device *pdev = NULL;
+	struct device_node *of_node;
+
+	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+		of_node = of_graph_get_port_by_id(dev->of_node, i);
+		if (!of_node) {
+			dev_info(dev, "no port@%d node in %s\n",
+				 i, dev->of_node->full_name);
+			continue;
+		}
+		of_node_put(of_node);
+
+		mutex_lock(&lcdifv3_client_id_mutex);
+		id = lcdifv3_client_id++;
+		mutex_unlock(&lcdifv3_client_id_mutex);
+
+		pdev = platform_device_alloc(client_reg[i].name, id);
+		if (!pdev) {
+			dev_err(dev, "Can't allocate port pdev\n");
+			ret = -ENOMEM;
+			goto err_register;
+		}
+
+		pdev->dev.parent = dev;
+		client_reg[i].pdata.of_node = of_node;
+
+		/* make child device 'dma_mask' to point to its
+		 * coherent dma mask, otherwise later probe will
+		 * print warning message: 'DMA mask not set'.
+		 */
+		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+		ret = platform_device_add_data(pdev, &client_reg[i].pdata,
+					       sizeof(client_reg[i].pdata));
+		if (!ret)
+			ret = platform_device_add(pdev);
+		if (ret) {
+			platform_device_put(pdev);
+			goto err_register;
+		}
+
+		pdev->dev.of_node = of_node;
+	}
+
+	if (!pdev)
+		return -ENODEV;
+
+	return 0;
+
+err_register:
+	platform_device_unregister_children(to_platform_device(dev));
+	return ret;
+}
+
+static int imx_lcdifv3_check_thres_value(u32 mul, u32 div)
+{
+	if (!div)
+		return -EINVAL;
+
+	if (mul > div)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void imx_lcdifv3_of_parse_thres(struct lcdifv3_soc *lcdifv3)
+{
+	int ret;
+	u32 thres_low[2], thres_high[2];
+	struct device_node *np = lcdifv3->dev->of_node;
+
+	/* default 'thres-low' value:  FIFO * 1/3;
+	 * default 'thres-high' value: FIFO * 2/3.
+	 */
+	lcdifv3->thres_low_mul	= 1;
+	lcdifv3->thres_low_div	= 3;
+	lcdifv3->thres_high_mul	= 2;
+	lcdifv3->thres_high_div	= 3;
+
+	ret = of_property_read_u32_array(np, "thres-low", thres_low, 2);
+	if (!ret) {
+		/* check the value effectiveness */
+		ret = imx_lcdifv3_check_thres_value(thres_low[0], thres_low[1]);
+		if (!ret) {
+			lcdifv3->thres_low_mul	= thres_low[0];
+			lcdifv3->thres_low_div	= thres_low[1];
+		}
+	}
+
+	ret = of_property_read_u32_array(np, "thres-high", thres_high, 2);
+	if (!ret) {
+		/* check the value effectiveness */
+		ret = imx_lcdifv3_check_thres_value(thres_high[0], thres_high[1]);
+		if (!ret) {
+			lcdifv3->thres_high_mul	= thres_high[0];
+			lcdifv3->thres_high_div	= thres_high[1];
+		}
+	}
+}
+
+static int imx_lcdifv3_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct lcdifv3_soc *lcdifv3;
+	struct resource *res;
+	struct regmap *blk_ctl;
+	const struct of_device_id *of_id;
+	const struct lcdifv3_soc_pdata *soc_pdata;
+
+	dev_dbg(dev, "%s: probe begin\n", __func__);
+
+	of_id = of_match_device(imx_lcdifv3_dt_ids, dev);
+	if (!of_id) {
+		dev_err(&pdev->dev, "OF data missing\n");
+		return -EINVAL;
+	}
+
+	soc_pdata = of_id->data;
+
+	lcdifv3 = devm_kzalloc(dev, sizeof(*lcdifv3), GFP_KERNEL);
+	if (!lcdifv3) {
+		dev_err(dev, "Can't allocate 'lcdifv3_soc' structure\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	lcdifv3->irq = platform_get_irq(pdev, 0);
+	if (lcdifv3->irq < 0) {
+		dev_err(dev, "No irq get\n");
+		return -EPROBE_DEFER;
+	}
+
+	lcdifv3->clk_pix = devm_clk_get(dev, "pix");
+	if (IS_ERR(lcdifv3->clk_pix)) {
+		dev_err(dev, "No pix clock get\n");
+		return -EPROBE_DEFER;
+	}
+
+	lcdifv3->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+	if (IS_ERR(lcdifv3->clk_disp_axi))
+		lcdifv3->clk_disp_axi = NULL;
+
+	lcdifv3->clk_disp_apb = devm_clk_get(dev, "disp-apb");
+	if (IS_ERR(lcdifv3->clk_disp_apb))
+		lcdifv3->clk_disp_apb = NULL;
+
+	lcdifv3->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(lcdifv3->base))
+		return PTR_ERR(lcdifv3->base);
+
+	lcdifv3->dev = dev;
+
+	/* reset controller to avoid any conflict
+	 * with uboot splash screen settings.
+	 */
+	blk_ctl = syscon_regmap_lookup_by_phandle(np, "blk-ctl");
+	if (IS_ERR(blk_ctl))
+		blk_ctl = NULL;
+
+	if (blk_ctl) {
+		clk_prepare_enable(lcdifv3->clk_disp_apb);
+		writel(CTRL_SW_RESET, lcdifv3->base + LCDIFV3_CTRL_CLR);
+
+		/* reset LCDIFv3 controller */
+		regmap_update_bits(blk_ctl, 0x0, BIT(5), 0x0);
+		regmap_update_bits(blk_ctl, 0x0, BIT(5), BIT(5));
+
+		clk_disable_unprepare(lcdifv3->clk_disp_apb);
+	}
+
+	imx_lcdifv3_of_parse_thres(lcdifv3);
+
+	platform_set_drvdata(pdev, lcdifv3);
+
+	if (soc_pdata->hdmimix) {
+		ret = hdmimix_lcdif3_setup(lcdifv3);
+		if (ret < 0) {
+			dev_err(dev, "hdmimix lcdif3 setup failed\n");
+			return ret;
+		}
+	}
+
+	atomic_set(&lcdifv3->rpm_suspended, 0);
+	pm_runtime_enable(dev);
+	atomic_inc(&lcdifv3->rpm_suspended);
+
+	dev_dbg(dev, "%s: probe end\n", __func__);
+
+	return lcdifv3_add_client_devices(lcdifv3);
+}
+
+static int imx_lcdifv3_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int imx_lcdifv3_runtime_suspend(struct device *dev)
+{
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(dev);
+
+	if (atomic_inc_return(&lcdifv3->rpm_suspended) > 1)
+		return 0;
+
+	lcdifv3_disable_clocks(lcdifv3);
+
+	release_bus_freq(BUS_FREQ_HIGH);
+
+	return 0;
+}
+
+static int imx_lcdifv3_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(dev);
+
+	if (unlikely(!atomic_read(&lcdifv3->rpm_suspended))) {
+		dev_warn(lcdifv3->dev, "Unbalanced %s!\n", __func__);
+		return 0;
+	}
+
+	if (!atomic_dec_and_test(&lcdifv3->rpm_suspended))
+		return 0;
+
+	request_bus_freq(BUS_FREQ_HIGH);
+
+	ret = lcdifv3_enable_clocks(lcdifv3);
+	if (ret) {
+		release_bus_freq(BUS_FREQ_HIGH);
+		return ret;
+	}
+
+	/* clear sw_reset */
+	writel(CTRL_SW_RESET, lcdifv3->base + LCDIFV3_CTRL_CLR);
+
+	/* enable plane FIFO panic */
+	lcdifv3_enable_plane_panic(lcdifv3);
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_lcdifv3_suspend(struct device *dev)
+{
+	return imx_lcdifv3_runtime_suspend(dev);
+}
+
+static int imx_lcdifv3_resume(struct device *dev)
+{
+	return imx_lcdifv3_runtime_resume(dev);
+}
+#endif
+
+static const struct dev_pm_ops imx_lcdifv3_pm_ops = {
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(imx_lcdifv3_suspend,
+				     imx_lcdifv3_resume)
+	SET_RUNTIME_PM_OPS(imx_lcdifv3_runtime_suspend,
+			   imx_lcdifv3_runtime_resume, NULL)
+};
+
+struct platform_driver imx_lcdifv3_driver = {
+	.probe    = imx_lcdifv3_probe,
+	.remove   = imx_lcdifv3_remove,
+	.driver   = {
+		.name = DRIVER_NAME,
+		.of_match_table = imx_lcdifv3_dt_ids,
+		.pm = &imx_lcdifv3_pm_ops,
+	},
+};
+
+module_platform_driver(imx_lcdifv3_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIFV3 Display Controller driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/gpu/imx/lcdifv3/lcdifv3-regs.h
+++ linux-ein-5.4.0/drivers/gpu/imx/lcdifv3/lcdifv3-regs.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#ifndef __LCDIFV3_REGS_H
+#define __LCDIFV3_REGS_H
+
+/* regs offset */
+#define LCDIFV3_CTRL			0x00
+#define LCDIFV3_CTRL_SET		0x04
+#define LCDIFV3_CTRL_CLR		0x08
+#define LCDIFV3_CTRL_TOG		0x0c
+#define LCDIFV3_DISP_PARA		0x10
+#define LCDIFV3_DISP_SIZE		0x14
+#define LCDIFV3_HSYN_PARA		0x18
+#define LCDIFV3_VSYN_PARA		0x1c
+#define LCDIFV3_VSYN_HSYN_WIDTH		0x20
+#define LCDIFV3_INT_STATUS_D0		0x24
+#define LCDIFV3_INT_ENABLE_D0		0x28
+#define LCDIFV3_INT_STATUS_D1		0x30
+#define LCDIFV3_INT_ENABLE_D1		0x34
+
+#define LCDIFV3_CTRLDESCL0_1		0x200
+#define LCDIFV3_CTRLDESCL0_3		0x208
+#define LCDIFV3_CTRLDESCL_LOW0_4	0x20c
+#define LCDIFV3_CTRLDESCL_HIGH0_4	0x210
+#define LCDIFV3_CTRLDESCL0_5		0x214
+#define LCDIFV3_CSC0_CTRL		0x21c
+#define LCDIFV3_CSC0_COEF0		0x220
+#define LCDIFV3_CSC0_COEF1		0x224
+#define LCDIFV3_CSC0_COEF2		0x228
+#define LCDIFV3_CSC0_COEF3		0x22c
+#define LCDIFV3_CSC0_COEF4		0x230
+#define LCDIFV3_CSC0_COEF5		0x234
+#define LCDIFV3_PANIC0_THRES		0x238
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/* regs bit fields */
+#define CTRL_SW_RESET			BIT(31)
+#define CTRL_FETCH_START_OPTION(x)	REG_PUT((x), 9, 8)
+   #define FPV		0
+   #define PWV		1
+   #define BPV		2
+   #define RESV		3
+#define CTRL_NEG			BIT(4)
+#define CTRL_INV_PXCK			BIT(3)
+#define CTRL_INV_DE			BIT(2)
+#define CTRL_INV_VS			BIT(1)
+#define CTRL_INV_HS			BIT(0)
+
+#define DISP_PARA_DISP_ON		BIT(31)
+#define DISP_PARA_SWAP_EN		BIT(30)
+#define DISP_PARA_LINE_PATTERN(x)	REG_PUT((x), 29, 26)
+   /* line pattern formats (output) */
+   #define LP_RGB888_OR_YUV444		0x0
+   #define LP_RBG888			0x1
+   #define LP_GBR888			0x2
+   #define LP_GRB888_OR_UYV444		0x3
+   #define LP_BRG888			0x4
+   #define LP_BGR888			0x5
+   #define LP_RGB555			0x6
+   #define LP_RGB565			0x7
+   #define LP_YUYV_16_0			0x8
+   #define LP_UYVY_16_0			0x9
+   #define LP_YVYU_16_0			0xa
+   #define LP_VYUY_16_0			0xb
+   #define LP_YUYV_23_8			0xc
+   #define LP_UYVY_23_8			0xd
+   #define LP_YVYU_23_8			0xe
+   #define LP_VYUY_23_8			0xf
+
+#define DISP_PARA_DISP_MODE(x)		REG_PUT((x), 25, 24)
+#define DISP_PARA_BGND_R(x)		REG_PUT((x), 23, 16)
+#define DISP_PARA_BGND_G(x)		REG_PUT((x), 15,  8)
+#define DISP_PARA_BGND_B(x)		REG_PUT((x),  7,  0)
+
+#define DISP_SIZE_DELTA_Y(x)		REG_PUT((x), 31, 16)
+#define DISP_SIZE_DELTA_X(x)		REG_PUT((x), 15,  0)
+
+#define HSYN_PARA_BP_H(x)		REG_PUT((x), 31, 16)
+#define HSYN_PARA_FP_H(x)		REG_PUT((x), 15,  0)
+
+#define VSYN_PARA_BP_V(x)		REG_PUT((x), 31, 16)
+#define VSYN_PARA_FP_V(x)		REG_PUT((x), 15,  0)
+
+#define VSYN_HSYN_WIDTH_PW_V(x)		REG_PUT((x), 31, 16)
+#define VSYN_HSYN_WIDTH_PW_H(x)		REG_PUT((x), 15,  0)
+
+#define INT_STATUS_D0_FIFO_EMPTY	BIT(24)
+#define INT_STATUS_D0_DMA_DONE		BIT(16)
+#define INT_STATUS_D0_DMA_ERR		BIT(8)
+#define INT_STATUS_D0_VS_BLANK		BIT(2)
+#define INT_STATUS_D0_UNDERRUN		BIT(1)
+#define INT_STATUS_D0_VSYNC		BIT(0)
+
+#define INT_ENABLE_D0_FIFO_EMPTY_EN	BIT(24)
+#define INT_ENABLE_D0_DMA_DONE_EN	BIT(16)
+#define INT_ENABLE_D0_DMA_ERR_EN	BIT(8)
+#define INT_ENABLE_D0_VS_BLANK_EN	BIT(2)
+#define INT_ENABLE_D0_UNDERRUN_EN	BIT(1)
+#define INT_ENABLE_D0_VSYNC_EN		BIT(0)
+
+#define INT_STATUS_D1_PLANE_PANIC	BIT(0)
+#define INT_ENABLE_D1_PLANE_PANIC_EN	BIT(0)
+
+#define CTRLDESCL0_1_HEIGHT(x)		REG_PUT((x), 31, 16)
+#define CTRLDESCL0_1_WIDTH(x)		REG_PUT((x), 15,  0)
+#define CTRLDESCL0_3_STATE_CLEAR_VSYNC	BIT(23)
+#define CTRLDESCL0_3_P_SIZE(x)		REG_PUT((x), 22, 20)
+#define CTRLDESCL0_3_T_SIZE(x)		REG_PUT((x), 17, 16)
+#define CTRLDESCL0_3_PITCH(x)		REG_PUT((x), 15,  0)
+//#define CTRLDESCL_LOW0_4_ADDR_LOW(x)	REG_PUT((x), 31,  0)
+#define CTRLDESCL_HIGH0_4_ADDR_HIGH(x)	REG_PUT((x),  3,  0)
+#define CTRLDESCL0_5_EN			BIT(31)	/* enable layer for DMA */
+#define CTRLDESCL0_5_SHADOW_LOAD_EN	BIT(30)
+#define CTRLDESCL0_5_BPP(x)		REG_PUT((x), 27, 24)
+   /* layer encoding formats (input) */
+   #define BPP16_RGB565			0x4
+   #define BPP16_ARGB1555		0x5
+   #define BPP16_ARGB4444		0x6
+   #define BPP16_YCbCr422		0x7
+   #define BPP24_RGB888			0x8
+   #define BPP32_ARGB8888		0x9
+   #define BPP32_ABGR8888		0xa
+#define CTRLDESCL0_5_YUV_FORMAT(x)	REG_PUT((x), 15, 14)
+
+#define CSC0_CTRL_CSC_MODE(x)		REG_PUT((x),  2,  1)
+#define CSC0_CTRL_BYPASS		BIT(0)
+#define CSC0_COEF0_A2(x)		REG_PUT((x), 26, 16)
+#define CSC0_COEF0_A1(x)		REG_PUT((x), 10,  0)
+#define CSC0_COEF1_B1(x)		REG_PUT((x), 26, 16)
+#define CSC0_COEF1_A3(x)		REG_PUT((x), 10,  0)
+#define CSC0_COEF2_B3(x)		REG_PUT((x), 26, 16)
+#define CSC0_COEF2_B2(x)		REG_PUT((x), 10,  0)
+#define CSC0_COEF3_C2(x)		REG_PUT((x), 26, 16)
+#define CSC0_COEF3_C1(x)		REG_PUT((x), 10,  0)
+#define CSC0_COEF4_D1(x)		REG_PUT((x), 24, 16)
+#define CSC0_COEF4_C3(x)		REG_PUT((x), 10,  0)
+#define CSC0_COEF5_D3(x)		REG_PUT((x), 24, 16)
+#define CSC0_COEF5_D2(x)		REG_PUT((x),  8,  0)
+
+#define PANIC0_THRES_PANIC_THRES_LOW(x)	REG_PUT((x), 24, 16)
+#define PANIC0_THRES_PANIC_THRES_HIGH(x)	REG_PUT((x), 8, 0)
+
+#endif /* __LCDIFV3_REGS_H */
--- linux-ein-5.4.0.orig/drivers/gpu/ipu-v3/ipu-common.c
+++ linux-ein-5.4.0/drivers/gpu/ipu-v3/ipu-common.c
@@ -124,6 +124,8 @@
 	case V4L2_PIX_FMT_RGBX32:
 	case V4L2_PIX_FMT_ARGB32:
 	case V4L2_PIX_FMT_XRGB32:
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
 		return IPUV3_COLORSPACE_RGB;
 	default:
 		return IPUV3_COLORSPACE_UNKNOWN;
@@ -1233,6 +1235,7 @@
 		pdev = platform_device_alloc(reg->name, id++);
 		if (!pdev) {
 			ret = -ENOMEM;
+			of_node_put(of_node);
 			goto err_register;
 		}
 
--- linux-ein-5.4.0.orig/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ linux-ein-5.4.0/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -585,21 +585,21 @@
 	.bits_per_pixel = 16,
 };
 
-#define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
-				 (pix->width * ((y) / 2) / 2) + (x) / 2)
-#define V_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
-				 (pix->width * pix->height / 4) +	\
-				 (pix->width * ((y) / 2) / 2) + (x) / 2)
-#define U2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
-				 (pix->width * (y) / 2) + (x) / 2)
-#define V2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
-				 (pix->width * pix->height / 2) +	\
-				 (pix->width * (y) / 2) + (x) / 2)
-#define UV_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
-				 (pix->width * ((y) / 2)) + (x))
-#define UV2_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
-				 (pix->width * y) + (x))
+#define Y_OFFSET(pix, x, y)	((x) + pix->bytesperline * (y))
+#define U_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
+#define V_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * pix->height / 4) + \
+				 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
+#define U2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * (y) / 2) + (x) / 2)
+#define V2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * pix->height / 2) + \
+				 (pix->bytesperline * (y) / 2) + (x) / 2)
+#define UV_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * ((y) / 2)) + (x))
+#define UV2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
+				 (pix->bytesperline * y) + (x))
 
 #define NUM_ALPHA_CHANNELS	7
 
--- linux-ein-5.4.0.orig/drivers/gpu/ipu-v3/ipu-di.c
+++ linux-ein-5.4.0/drivers/gpu/ipu-v3/ipu-di.c
@@ -451,8 +451,9 @@
 
 		error = rate / (sig->mode.pixelclock / 1000);
 
-		dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
-			rate, div, (signed)(error - 1000) / 10, error % 10);
+		dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %c%d.%d%%\n",
+			rate, div, error < 1000 ? '-' : '+',
+			abs(error - 1000) / 10, abs(error - 1000) % 10);
 
 		/* Allow a 1% error */
 		if (error < 1010 && error >= 990) {
--- linux-ein-5.4.0.orig/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ linux-ein-5.4.0/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -137,6 +137,17 @@
 struct ipu_image_convert_chan;
 struct ipu_image_convert_priv;
 
+enum eof_irq_mask {
+	EOF_IRQ_IN      = BIT(0),
+	EOF_IRQ_ROT_IN  = BIT(1),
+	EOF_IRQ_OUT     = BIT(2),
+	EOF_IRQ_ROT_OUT = BIT(3),
+};
+
+#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
+#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT |	\
+			      EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
+
 struct ipu_image_convert_ctx {
 	struct ipu_image_convert_chan *chan;
 
@@ -173,6 +184,9 @@
 	/* where to place converted tile in dest image */
 	unsigned int out_tile_map[MAX_TILES];
 
+	/* mask of completed EOF irqs at every tile conversion */
+	enum eof_irq_mask eof_mask;
+
 	struct list_head list;
 };
 
@@ -189,6 +203,8 @@
 	struct ipuv3_channel *rotation_out_chan;
 
 	/* the IPU end-of-frame irqs */
+	int in_eof_irq;
+	int rot_in_eof_irq;
 	int out_eof_irq;
 	int rot_out_eof_irq;
 
@@ -1380,6 +1396,9 @@
 	dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
 		__func__, chan->ic_task, ctx, run, tile, dst_tile);
 
+	/* clear EOF irq mask */
+	ctx->eof_mask = 0;
+
 	if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
 		/* swap width/height for resizer */
 		dest_width = d_image->tile[dst_tile].height;
@@ -1615,7 +1634,7 @@
 }
 
 /* hold irqlock when calling */
-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
+static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
 {
 	struct ipu_image_convert_ctx *ctx = run->ctx;
 	struct ipu_image_convert_chan *chan = ctx->chan;
@@ -1700,6 +1719,7 @@
 		ctx->cur_buf_num ^= 1;
 	}
 
+	ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
 	ctx->next_tile++;
 	return IRQ_HANDLED;
 done:
@@ -1709,13 +1729,15 @@
 	return IRQ_WAKE_THREAD;
 }
 
-static irqreturn_t norotate_irq(int irq, void *data)
+static irqreturn_t eof_irq(int irq, void *data)
 {
 	struct ipu_image_convert_chan *chan = data;
+	struct ipu_image_convert_priv *priv = chan->priv;
 	struct ipu_image_convert_ctx *ctx;
 	struct ipu_image_convert_run *run;
+	irqreturn_t ret = IRQ_HANDLED;
+	bool tile_complete = false;
 	unsigned long flags;
-	irqreturn_t ret;
 
 	spin_lock_irqsave(&chan->irqlock, flags);
 
@@ -1728,46 +1750,33 @@
 
 	ctx = run->ctx;
 
-	if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
-		/* this is a rotation operation, just ignore */
-		spin_unlock_irqrestore(&chan->irqlock, flags);
-		return IRQ_HANDLED;
-	}
-
-	ret = do_irq(run);
-out:
-	spin_unlock_irqrestore(&chan->irqlock, flags);
-	return ret;
-}
-
-static irqreturn_t rotate_irq(int irq, void *data)
-{
-	struct ipu_image_convert_chan *chan = data;
-	struct ipu_image_convert_priv *priv = chan->priv;
-	struct ipu_image_convert_ctx *ctx;
-	struct ipu_image_convert_run *run;
-	unsigned long flags;
-	irqreturn_t ret;
-
-	spin_lock_irqsave(&chan->irqlock, flags);
-
-	/* get current run and its context */
-	run = chan->current_run;
-	if (!run) {
+	if (irq == chan->in_eof_irq) {
+		ctx->eof_mask |= EOF_IRQ_IN;
+	} else if (irq == chan->out_eof_irq) {
+		ctx->eof_mask |= EOF_IRQ_OUT;
+	} else if (irq == chan->rot_in_eof_irq ||
+		   irq == chan->rot_out_eof_irq) {
+		if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
+			/* this was NOT a rotation op, shouldn't happen */
+			dev_err(priv->ipu->dev,
+				"Unexpected rotation interrupt\n");
+			goto out;
+		}
+		ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
+			EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
+	} else {
+		dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
 		ret = IRQ_NONE;
 		goto out;
 	}
 
-	ctx = run->ctx;
-
-	if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
-		/* this was NOT a rotation operation, shouldn't happen */
-		dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
-		spin_unlock_irqrestore(&chan->irqlock, flags);
-		return IRQ_HANDLED;
-	}
+	if (ipu_rot_mode_is_irt(ctx->rot_mode))
+		tile_complete =	(ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
+	else
+		tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
 
-	ret = do_irq(run);
+	if (tile_complete)
+		ret = do_tile_complete(run);
 out:
 	spin_unlock_irqrestore(&chan->irqlock, flags);
 	return ret;
@@ -1801,6 +1810,10 @@
 
 static void release_ipu_resources(struct ipu_image_convert_chan *chan)
 {
+	if (chan->in_eof_irq >= 0)
+		free_irq(chan->in_eof_irq, chan);
+	if (chan->rot_in_eof_irq >= 0)
+		free_irq(chan->rot_in_eof_irq, chan);
 	if (chan->out_eof_irq >= 0)
 		free_irq(chan->out_eof_irq, chan);
 	if (chan->rot_out_eof_irq >= 0)
@@ -1819,7 +1832,27 @@
 
 	chan->in_chan = chan->out_chan = chan->rotation_in_chan =
 		chan->rotation_out_chan = NULL;
-	chan->out_eof_irq = chan->rot_out_eof_irq = -1;
+	chan->in_eof_irq = -1;
+	chan->rot_in_eof_irq = -1;
+	chan->out_eof_irq = -1;
+	chan->rot_out_eof_irq = -1;
+}
+
+static int get_eof_irq(struct ipu_image_convert_chan *chan,
+		       struct ipuv3_channel *channel)
+{
+	struct ipu_image_convert_priv *priv = chan->priv;
+	int ret, irq;
+
+	irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF);
+
+	ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan);
+	if (ret < 0) {
+		dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq);
+		return ret;
+	}
+
+	return irq;
 }
 
 static int get_ipu_resources(struct ipu_image_convert_chan *chan)
@@ -1855,31 +1888,33 @@
 	}
 
 	/* acquire the EOF interrupts */
-	chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
-						  chan->out_chan,
-						  IPU_IRQ_EOF);
+	ret = get_eof_irq(chan, chan->in_chan);
+	if (ret < 0) {
+		chan->in_eof_irq = -1;
+		goto err;
+	}
+	chan->in_eof_irq = ret;
 
-	ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
-				   0, "ipu-ic", chan);
+	ret = get_eof_irq(chan, chan->rotation_in_chan);
 	if (ret < 0) {
-		dev_err(priv->ipu->dev, "could not acquire irq %d\n",
-			 chan->out_eof_irq);
-		chan->out_eof_irq = -1;
+		chan->rot_in_eof_irq = -1;
 		goto err;
 	}
+	chan->rot_in_eof_irq = ret;
 
-	chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
-						     chan->rotation_out_chan,
-						     IPU_IRQ_EOF);
+	ret = get_eof_irq(chan, chan->out_chan);
+	if (ret < 0) {
+		chan->out_eof_irq = -1;
+		goto err;
+	}
+	chan->out_eof_irq = ret;
 
-	ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
-				   0, "ipu-ic", chan);
+	ret = get_eof_irq(chan, chan->rotation_out_chan);
 	if (ret < 0) {
-		dev_err(priv->ipu->dev, "could not acquire irq %d\n",
-			chan->rot_out_eof_irq);
 		chan->rot_out_eof_irq = -1;
 		goto err;
 	}
+	chan->rot_out_eof_irq = ret;
 
 	return 0;
 err:
@@ -2458,6 +2493,8 @@
 		chan->ic_task = i;
 		chan->priv = priv;
 		chan->dma_ch = &image_convert_dma_chan[i];
+		chan->in_eof_irq = -1;
+		chan->rot_in_eof_irq = -1;
 		chan->out_eof_irq = -1;
 		chan->rot_out_eof_irq = -1;
 
--- linux-ein-5.4.0.orig/drivers/greybus/svc.c
+++ linux-ein-5.4.0/drivers/greybus/svc.c
@@ -866,8 +866,14 @@
 
 	gb_svc_debugfs_init(svc);
 
-	return gb_svc_queue_deferred_request(op);
+	ret = gb_svc_queue_deferred_request(op);
+	if (ret)
+		goto err_remove_debugfs;
 
+	return 0;
+
+err_remove_debugfs:
+	gb_svc_debugfs_exit(svc);
 err_unregister_device:
 	gb_svc_watchdog_destroy(svc);
 	device_del(&svc->dev);
--- linux-ein-5.4.0.orig/drivers/hid/Kconfig
+++ linux-ein-5.4.0/drivers/hid/Kconfig
@@ -149,6 +149,7 @@
 
 config HID_ASUS
 	tristate "Asus"
+	depends on USB_HID
 	depends on LEDS_CLASS
 	depends on ASUS_WMI || ASUS_WMI=n
 	select POWER_SUPPLY
@@ -206,14 +207,14 @@
 
 config HID_CHICONY
 	tristate "Chicony devices"
-	depends on HID
+	depends on USB_HID
 	default !EXPERT
 	---help---
 	Support for Chicony Tactical pad and special keys on Chicony keyboards.
 
 config HID_CORSAIR
 	tristate "Corsair devices"
-	depends on HID && USB && LEDS_CLASS
+	depends on USB_HID && LEDS_CLASS
 	---help---
 	Support for Corsair devices that are not fully compliant with the
 	HID standard.
@@ -244,7 +245,7 @@
 
 config HID_PRODIKEYS
 	tristate "Prodikeys PC-MIDI Keyboard support"
-	depends on HID && SND
+	depends on USB_HID && SND
 	select SND_RAWMIDI
 	---help---
 	Support for Prodikeys PC-MIDI Keyboard device support.
@@ -524,7 +525,7 @@
 
 config HID_LOGITECH
 	tristate "Logitech devices"
-	depends on HID
+	depends on USB_HID
 	default !EXPERT
 	---help---
 	Support for Logitech devices that are not fully compliant with HID standard.
@@ -871,7 +872,7 @@
 
 config HID_SAMSUNG
 	tristate "Samsung InfraRed remote control or keyboards"
-	depends on HID
+	depends on USB_HID
 	---help---
 	Support for Samsung InfraRed remote control or keyboards.
 
--- linux-ein-5.4.0.orig/drivers/hid/hid-alps.c
+++ linux-ein-5.4.0/drivers/hid/hid-alps.c
@@ -25,6 +25,7 @@
 
 #define U1_MOUSE_REPORT_ID			0x01 /* Mouse data ReportID */
 #define U1_ABSOLUTE_REPORT_ID		0x03 /* Absolute data ReportID */
+#define U1_ABSOLUTE_REPORT_ID_SECD  0x02 /* FW-PTP Absolute data ReportID */
 #define U1_FEATURE_REPORT_ID		0x05 /* Feature ReportID */
 #define U1_SP_ABSOLUTE_REPORT_ID	0x06 /* Feature ReportID */
 
@@ -368,6 +369,7 @@
 	case U1_FEATURE_REPORT_ID:
 		break;
 	case U1_ABSOLUTE_REPORT_ID:
+	case U1_ABSOLUTE_REPORT_ID_SECD:
 		for (i = 0; i < hdata->max_fingers; i++) {
 			u8 *contact = &data[i * 5];
 
@@ -730,7 +732,7 @@
 	if (data->has_sp) {
 		input2 = input_allocate_device();
 		if (!input2) {
-			input_free_device(input2);
+			ret = -ENOMEM;
 			goto exit;
 		}
 
@@ -760,6 +762,7 @@
 
 		if (input_register_device(data->input2)) {
 			input_free_device(input2);
+			ret = -ENOENT;
 			goto exit;
 		}
 	}
@@ -802,6 +805,7 @@
 		break;
 	case HID_DEVICE_ID_ALPS_U1_DUAL:
 	case HID_DEVICE_ID_ALPS_U1:
+	case HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY:
 		data->dev_type = U1;
 		break;
 	default:
@@ -828,6 +832,8 @@
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
 		USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) },
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+		USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY) },
+	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
 		USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) },
 	{ }
 };
--- linux-ein-5.4.0.orig/drivers/hid/hid-apple.c
+++ linux-ein-5.4.0/drivers/hid/hid-apple.c
@@ -51,9 +51,16 @@
 		"(For people who want to keep Windows PC keyboard muscle memory. "
 		"[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
 
+static unsigned int swap_fn_leftctrl;
+module_param(swap_fn_leftctrl, uint, 0644);
+MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
+		"(For people who want to keep PC keyboard muscle memory. "
+		"[0] = as-is, Mac layout, 1 = swapped, PC layout)");
+
 struct apple_sc {
 	unsigned long quirks;
 	unsigned int fn_on;
+	unsigned int fn_found;
 	DECLARE_BITMAP(pressed_numlock, KEY_CNT);
 };
 
@@ -63,6 +70,28 @@
 	u8 flags;
 };
 
+static const struct apple_key_translation apple2021_fn_keys[] = {
+	{ KEY_BACKSPACE, KEY_DELETE },
+	{ KEY_ENTER,	KEY_INSERT },
+	{ KEY_F1,	KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+	{ KEY_F2,	KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+	{ KEY_F3,	KEY_SCALE,          APPLE_FLAG_FKEY },
+	{ KEY_F4,	KEY_SEARCH,         APPLE_FLAG_FKEY },
+	{ KEY_F5,	KEY_MICMUTE,        APPLE_FLAG_FKEY },
+	{ KEY_F6,	KEY_SLEEP,          APPLE_FLAG_FKEY },
+	{ KEY_F7,	KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+	{ KEY_F8,	KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+	{ KEY_F9,	KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+	{ KEY_F10,	KEY_MUTE,           APPLE_FLAG_FKEY },
+	{ KEY_F11,	KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+	{ KEY_F12,	KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+	{ KEY_UP,	KEY_PAGEUP },
+	{ KEY_DOWN,	KEY_PAGEDOWN },
+	{ KEY_LEFT,	KEY_HOME },
+	{ KEY_RIGHT,	KEY_END },
+	{ }
+};
+
 static const struct apple_key_translation macbookair_fn_keys[] = {
 	{ KEY_BACKSPACE, KEY_DELETE },
 	{ KEY_ENTER,	KEY_INSERT },
@@ -162,6 +191,11 @@
 	{ }
 };
 
+static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
+	{ KEY_FN, KEY_LEFTCTRL },
+	{ }
+};
+
 static const struct apple_key_translation *apple_find_translation(
 		const struct apple_key_translation *table, u16 from)
 {
@@ -183,14 +217,18 @@
 	bool do_translate;
 	u16 code = 0;
 
-	if (usage->code == KEY_FN) {
+	u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
+
+	if (usage->code == fn_keycode) {
 		asc->fn_on = !!value;
-		input_event(input, usage->type, usage->code, value);
+		input_event(input, usage->type, KEY_FN, value);
 		return 1;
 	}
 
 	if (fnmode) {
-		if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+		if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021)
+			table = apple2021_fn_keys;
+		else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
 				hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
 			table = macbookair_fn_keys;
 		else if (hid->product < 0x21d || hid->product >= 0x300)
@@ -270,6 +308,14 @@
 		}
 	}
 
+	if (swap_fn_leftctrl) {
+		trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
+		if (trans) {
+			input_event(input, usage->type, trans->to, value);
+			return 1;
+		}
+	}
+
 	return 0;
 }
 
@@ -300,12 +346,19 @@
 
 /*
  * MacBook JIS keyboard has wrong logical maximum
+ * Magic Keyboard JIS has wrong logical maximum
  */
 static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
 	struct apple_sc *asc = hid_get_drvdata(hdev);
 
+	if(*rsize >=71 && rdesc[70] == 0x65 && rdesc[64] == 0x65) {
+		hid_info(hdev,
+			 "fixing up Magic Keyboard JIS report descriptor\n");
+		rdesc[64] = rdesc[70] = 0xe7;
+	}
+
 	if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
 			rdesc[53] == 0x65 && rdesc[59] == 0x65) {
 		hid_info(hdev,
@@ -333,17 +386,29 @@
 
 	for (trans = apple_iso_keyboard; trans->from; trans++)
 		set_bit(trans->to, input->keybit);
+
+	for (trans = apple2021_fn_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
+	if (swap_fn_leftctrl) {
+		for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
+			set_bit(trans->to, input->keybit);
+	}
 }
 
 static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
+	struct apple_sc *asc = hid_get_drvdata(hdev);
+
 	if (usage->hid == (HID_UP_CUSTOM | 0x0003) ||
-			usage->hid == (HID_UP_MSVENDOR | 0x0003)) {
+			usage->hid == (HID_UP_MSVENDOR | 0x0003) ||
+			usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) {
 		/* The fn key on Apple USB keyboards */
 		set_bit(EV_REP, hi->input->evbit);
 		hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+		asc->fn_found = true;
 		apple_setup_input(hi->input);
 		return 1;
 	}
@@ -370,6 +435,19 @@
 	return 0;
 }
 
+static int apple_input_configured(struct hid_device *hdev,
+		struct hid_input *hidinput)
+{
+	struct apple_sc *asc = hid_get_drvdata(hdev);
+
+	if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) {
+		hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n");
+		asc->quirks &= ~APPLE_HAS_FN;
+	}
+
+	return 0;
+}
+
 static int apple_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
@@ -571,6 +649,10 @@
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
 		.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
+		.driver_data = APPLE_HAS_FN },
+	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
+		.driver_data = APPLE_HAS_FN },
 
 	{ }
 };
@@ -584,6 +666,7 @@
 	.event = apple_event,
 	.input_mapping = apple_input_mapping,
 	.input_mapped = apple_input_mapped,
+	.input_configured = apple_input_configured,
 };
 module_hid_driver(apple_driver);
 
--- linux-ein-5.4.0.orig/drivers/hid/hid-asus.c
+++ linux-ein-5.4.0/drivers/hid/hid-asus.c
@@ -40,7 +40,9 @@
 MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
 
 #define T100_TPAD_INTF 2
+#define MEDION_E1239T_TPAD_INTF 1
 
+#define E1239T_TP_TOGGLE_REPORT_ID 0x05
 #define T100CHI_MOUSE_REPORT_ID 0x06
 #define FEATURE_REPORT_ID 0x0d
 #define INPUT_REPORT_ID 0x5d
@@ -77,6 +79,7 @@
 #define QUIRK_G752_KEYBOARD		BIT(8)
 #define QUIRK_T101HA_DOCK		BIT(9)
 #define QUIRK_T90CHI			BIT(10)
+#define QUIRK_MEDION_E1239T		BIT(11)
 
 #define I2C_KEYBOARD_QUIRKS			(QUIRK_FIX_NOTEBOOK_REPORT | \
 						 QUIRK_NO_INIT_REPORTS | \
@@ -92,6 +95,7 @@
 	struct hid_device *hdev;
 	struct work_struct work;
 	unsigned int brightness;
+	spinlock_t lock;
 	bool removed;
 };
 
@@ -102,12 +106,14 @@
 	int res_y;
 	int contact_size;
 	int max_contacts;
+	int report_size;
 };
 
 struct asus_drvdata {
 	unsigned long quirks;
 	struct hid_device *hdev;
 	struct input_dev *input;
+	struct input_dev *tp_kbd_input;
 	struct asus_kbd_leds *kbd_backlight;
 	const struct asus_touchpad_info *tp;
 	bool enable_backlight;
@@ -126,6 +132,7 @@
 	.max_y = 1758,
 	.contact_size = 5,
 	.max_contacts = 5,
+	.report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100ta_tp = {
@@ -135,6 +142,7 @@
 	.res_y = 27, /* units/mm */
 	.contact_size = 5,
 	.max_contacts = 5,
+	.report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100ha_tp = {
@@ -144,6 +152,7 @@
 	.res_y = 29, /* units/mm */
 	.contact_size = 5,
 	.max_contacts = 5,
+	.report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t200ta_tp = {
@@ -153,6 +162,7 @@
 	.res_y = 28, /* units/mm */
 	.contact_size = 5,
 	.max_contacts = 5,
+	.report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100chi_tp = {
@@ -162,6 +172,17 @@
 	.res_y = 29, /* units/mm */
 	.contact_size = 3,
 	.max_contacts = 4,
+	.report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */,
+};
+
+static const struct asus_touchpad_info medion_e1239t_tp = {
+	.max_x = 2640,
+	.max_y = 1380,
+	.res_x = 29, /* units/mm */
+	.res_y = 28, /* units/mm */
+	.contact_size = 5,
+	.max_contacts = 5,
+	.report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */,
 };
 
 static void asus_report_contact_down(struct asus_drvdata *drvdat,
@@ -229,7 +250,7 @@
 	int i, toolType = MT_TOOL_FINGER;
 	u8 *contactData = data + 2;
 
-	if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts)
+	if (size != drvdat->tp->report_size)
 		return 0;
 
 	for (i = 0; i < drvdat->tp->max_contacts; i++) {
@@ -257,11 +278,40 @@
 	return 1;
 }
 
+static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
+{
+	if (size != 3)
+		return 0;
+
+	/* Handle broken mute key which only sends press events */
+	if (!drvdat->tp &&
+	    data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) {
+		input_report_key(drvdat->input, KEY_MUTE, 1);
+		input_sync(drvdat->input);
+		input_report_key(drvdat->input, KEY_MUTE, 0);
+		input_sync(drvdat->input);
+		return 1;
+	}
+
+	/* Handle custom touchpad toggle key which only sends press events */
+	if (drvdat->tp_kbd_input &&
+	    data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) {
+		input_report_key(drvdat->tp_kbd_input, KEY_F21, 1);
+		input_sync(drvdat->tp_kbd_input);
+		input_report_key(drvdat->tp_kbd_input, KEY_F21, 0);
+		input_sync(drvdat->tp_kbd_input);
+		return 1;
+	}
+
+	return 0;
+}
+
 static int asus_event(struct hid_device *hdev, struct hid_field *field,
 		      struct hid_usage *usage, __s32 value)
 {
 	if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
-	    (usage->hid & HID_USAGE) != 0x00 && !usage->type) {
+	    (usage->hid & HID_USAGE) != 0x00 &&
+	    (usage->hid & HID_USAGE) != 0xff && !usage->type) {
 		hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
 			 usage->hid & HID_USAGE);
 	}
@@ -280,10 +330,13 @@
 	if (drvdata->tp && data[0] == INPUT_REPORT_ID)
 		return asus_report_input(drvdata, data, size);
 
+	if (drvdata->quirks & QUIRK_MEDION_E1239T)
+		return asus_e1239t_event(drvdata, data, size);
+
 	return 0;
 }
 
-static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size)
+static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
 {
 	unsigned char *dmabuf;
 	int ret;
@@ -302,7 +355,7 @@
 
 static int asus_kbd_init(struct hid_device *hdev)
 {
-	u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
+	const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
 		     0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
 	int ret;
 
@@ -316,7 +369,7 @@
 static int asus_kbd_get_functions(struct hid_device *hdev,
 				  unsigned char *kbd_func)
 {
-	u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
+	const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
 	u8 *readbuf;
 	int ret;
 
@@ -345,24 +398,42 @@
 	return ret;
 }
 
+static void asus_schedule_work(struct asus_kbd_leds *led)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&led->lock, flags);
+	if (!led->removed)
+		schedule_work(&led->work);
+	spin_unlock_irqrestore(&led->lock, flags);
+}
+
 static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
 				   enum led_brightness brightness)
 {
 	struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
 						 cdev);
-	if (led->brightness == brightness)
-		return;
+	unsigned long flags;
 
+	spin_lock_irqsave(&led->lock, flags);
 	led->brightness = brightness;
-	schedule_work(&led->work);
+	spin_unlock_irqrestore(&led->lock, flags);
+
+	asus_schedule_work(led);
 }
 
 static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
 {
 	struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
 						 cdev);
+	enum led_brightness brightness;
+	unsigned long flags;
+
+	spin_lock_irqsave(&led->lock, flags);
+	brightness = led->brightness;
+	spin_unlock_irqrestore(&led->lock, flags);
 
-	return led->brightness;
+	return brightness;
 }
 
 static void asus_kbd_backlight_work(struct work_struct *work)
@@ -370,11 +441,11 @@
 	struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
 	u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
 	int ret;
+	unsigned long flags;
 
-	if (led->removed)
-		return;
-
+	spin_lock_irqsave(&led->lock, flags);
 	buf[4] = led->brightness;
+	spin_unlock_irqrestore(&led->lock, flags);
 
 	ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
 	if (ret < 0)
@@ -436,6 +507,7 @@
 	drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
 	drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
 	INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
+	spin_lock_init(&drvdata->kbd_backlight->lock);
 
 	ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
 	if (ret < 0) {
@@ -614,6 +686,21 @@
 	    hi->report->id != T100CHI_MOUSE_REPORT_ID)
 		return 0;
 
+	/* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */
+	if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) {
+		switch (hi->report->id) {
+		case E1239T_TP_TOGGLE_REPORT_ID:
+			input_set_capability(input, EV_KEY, KEY_F21);
+			input->name = "Asus Touchpad Keys";
+			drvdata->tp_kbd_input = input;
+			return 0;
+		case INPUT_REPORT_ID:
+			break; /* Touchpad report, handled below */
+		default:
+			return 0; /* Ignore other reports */
+		}
+	}
+
 	if (drvdata->tp) {
 		int ret;
 
@@ -693,7 +780,6 @@
 
 	/* ASUS-specific keyboard hotkeys */
 	if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
-		set_bit(EV_REP, hi->input->evbit);
 		switch (usage->hid & HID_USAGE) {
 		case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN);	break;
 		case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP);		break;
@@ -736,11 +822,11 @@
 		if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
 			drvdata->enable_backlight = true;
 
+		set_bit(EV_REP, hi->input->evbit);
 		return 1;
 	}
 
 	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
-		set_bit(EV_REP, hi->input->evbit);
 		switch (usage->hid & HID_USAGE) {
 		case 0xff01: asus_map_key_clear(BTN_1);	break;
 		case 0xff02: asus_map_key_clear(BTN_2);	break;
@@ -763,6 +849,7 @@
 			return 0;
 		}
 
+		set_bit(EV_REP, hi->input->evbit);
 		return 1;
 	}
 
@@ -781,6 +868,16 @@
 		}
 	}
 
+	/*
+	 * The mute button is broken and only sends press events, we
+	 * deal with this in our raw_event handler, so do not map it.
+	 */
+	if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
+	    usage->hid == (HID_UP_CONSUMER | 0xe2)) {
+		input_set_capability(hi->input, EV_KEY, KEY_MUTE);
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -811,6 +908,24 @@
 	return 0;
 }
 
+static int __maybe_unused asus_resume(struct hid_device *hdev) {
+	struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+	int ret = 0;
+
+	if (drvdata->kbd_backlight) {
+		const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4,
+				drvdata->kbd_backlight->cdev.brightness };
+		ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
+		if (ret < 0) {
+			hid_err(hdev, "Asus failed to set keyboard backlight: %d\n", ret);
+			goto asus_resume_err;
+		}
+	}
+
+asus_resume_err:
+	return ret;
+}
+
 static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
 {
 	struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
@@ -848,7 +963,7 @@
 	if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
 		drvdata->tp = &asus_i2c_tp;
 
-	if (drvdata->quirks & QUIRK_T100_KEYBOARD) {
+	if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && hid_is_usb(hdev)) {
 		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
 		if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
@@ -876,6 +991,19 @@
 		drvdata->tp = &asus_t100chi_tp;
 	}
 
+	if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
+	    hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+		struct usb_host_interface *alt =
+			to_usb_interface(hdev->dev.parent)->altsetting;
+
+		if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) {
+			/* For separate input-devs for tp and tp toggle key */
+			hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+			drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING;
+			drvdata->tp = &medion_e1239t_tp;
+		}
+	}
+
 	if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
 		hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
 
@@ -934,9 +1062,13 @@
 static void asus_remove(struct hid_device *hdev)
 {
 	struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+	unsigned long flags;
 
 	if (drvdata->kbd_backlight) {
+		spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags);
 		drvdata->kbd_backlight->removed = true;
+		spin_unlock_irqrestore(&drvdata->kbd_backlight->lock, flags);
+
 		cancel_work_sync(&drvdata->kbd_backlight->work);
 	}
 
@@ -1055,7 +1187,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
 		USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI },
-
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T),
+		QUIRK_MEDION_E1239T },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, asus_devices);
@@ -1070,6 +1203,7 @@
 	.input_configured       = asus_input_configured,
 #ifdef CONFIG_PM
 	.reset_resume           = asus_reset_resume,
+	.resume					= asus_resume,
 #endif
 	.event			= asus_event,
 	.raw_event		= asus_raw_event
--- linux-ein-5.4.0.orig/drivers/hid/hid-betopff.c
+++ linux-ein-5.4.0/drivers/hid/hid-betopff.c
@@ -56,15 +56,21 @@
 {
 	struct betopff_device *betopff;
 	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;
-	int field_count = 0;
+	struct input_dev *dev;
 	int error;
 	int i, j;
 
+	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;
@@ -79,19 +85,21 @@
 	 * -----------------------------------------
 	 * Do init them with default value.
 	 */
+	if (report->maxfield < 4) {
+		hid_err(hid, "not enough fields in the report: %d\n",
+				report->maxfield);
+		return -ENODEV;
+	}
 	for (i = 0; i < report->maxfield; i++) {
+		if (report->field[i]->report_count < 1) {
+			hid_err(hid, "no values in the field\n");
+			return -ENODEV;
+		}
 		for (j = 0; j < report->field[i]->report_count; j++) {
 			report->field[i]->value[j] = 0x00;
-			field_count++;
 		}
 	}
 
-	if (field_count < 4) {
-		hid_err(hid, "not enough fields in the report: %d\n",
-				field_count);
-		return -ENODEV;
-	}
-
 	betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
 	if (!betopff)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/hid/hid-bigbenff.c
+++ linux-ein-5.4.0/drivers/hid/hid-bigbenff.c
@@ -174,6 +174,8 @@
 struct bigben_device {
 	struct hid_device *hid;
 	struct hid_report *report;
+	spinlock_t lock;
+	bool removed;
 	u8 led_state;         /* LED1 = 1 .. LED4 = 8 */
 	u8 right_motor_on;    /* right motor off/on 0/1 */
 	u8 left_motor_force;  /* left motor force 0-255 */
@@ -183,15 +185,39 @@
 	struct work_struct worker;
 };
 
+static inline void bigben_schedule_work(struct bigben_device *bigben)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bigben->lock, flags);
+	if (!bigben->removed)
+		schedule_work(&bigben->worker);
+	spin_unlock_irqrestore(&bigben->lock, flags);
+}
 
 static void bigben_worker(struct work_struct *work)
 {
 	struct bigben_device *bigben = container_of(work,
 		struct bigben_device, worker);
 	struct hid_field *report_field = bigben->report->field[0];
+	bool do_work_led = false;
+	bool do_work_ff = false;
+	u8 *buf;
+	u32 len;
+	unsigned long flags;
+
+	buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	len = hid_report_len(bigben->report);
+
+	/* LED work */
+	spin_lock_irqsave(&bigben->lock, flags);
 
 	if (bigben->work_led) {
 		bigben->work_led = false;
+		do_work_led = true;
 		report_field->value[0] = 0x01; /* 1 = led message */
 		report_field->value[1] = 0x08; /* reserved value, always 8 */
 		report_field->value[2] = bigben->led_state;
@@ -200,11 +226,22 @@
 		report_field->value[5] = 0x00; /* padding */
 		report_field->value[6] = 0x00; /* padding */
 		report_field->value[7] = 0x00; /* padding */
-		hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+		hid_output_report(bigben->report, buf);
 	}
 
+	spin_unlock_irqrestore(&bigben->lock, flags);
+
+	if (do_work_led) {
+		hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
+				   bigben->report->type, HID_REQ_SET_REPORT);
+	}
+
+	/* FF work */
+	spin_lock_irqsave(&bigben->lock, flags);
+
 	if (bigben->work_ff) {
 		bigben->work_ff = false;
+		do_work_ff = true;
 		report_field->value[0] = 0x02; /* 2 = rumble effect message */
 		report_field->value[1] = 0x08; /* reserved value, always 8 */
 		report_field->value[2] = bigben->right_motor_on;
@@ -213,16 +250,32 @@
 		report_field->value[5] = 0x00; /* padding */
 		report_field->value[6] = 0x00; /* padding */
 		report_field->value[7] = 0x00; /* padding */
-		hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+		hid_output_report(bigben->report, buf);
 	}
+
+	spin_unlock_irqrestore(&bigben->lock, flags);
+
+	if (do_work_ff) {
+		hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
+				   bigben->report->type, HID_REQ_SET_REPORT);
+	}
+
+	kfree(buf);
 }
 
 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
 			 struct ff_effect *effect)
 {
-	struct bigben_device *bigben = data;
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct bigben_device *bigben = hid_get_drvdata(hid);
 	u8 right_motor_on;
 	u8 left_motor_force;
+	unsigned long flags;
+
+	if (!bigben) {
+		hid_err(hid, "no device data\n");
+		return 0;
+	}
 
 	if (effect->type != FF_RUMBLE)
 		return 0;
@@ -232,10 +285,13 @@
 
 	if (right_motor_on != bigben->right_motor_on ||
 			left_motor_force != bigben->left_motor_force) {
+		spin_lock_irqsave(&bigben->lock, flags);
 		bigben->right_motor_on   = right_motor_on;
 		bigben->left_motor_force = left_motor_force;
 		bigben->work_ff = true;
-		schedule_work(&bigben->worker);
+		spin_unlock_irqrestore(&bigben->lock, flags);
+
+		bigben_schedule_work(bigben);
 	}
 
 	return 0;
@@ -249,6 +305,7 @@
 	struct bigben_device *bigben = hid_get_drvdata(hid);
 	int n;
 	bool work;
+	unsigned long flags;
 
 	if (!bigben) {
 		hid_err(hid, "no device data\n");
@@ -257,6 +314,7 @@
 
 	for (n = 0; n < NUM_LEDS; n++) {
 		if (led == bigben->leds[n]) {
+			spin_lock_irqsave(&bigben->lock, flags);
 			if (value == LED_OFF) {
 				work = (bigben->led_state & BIT(n));
 				bigben->led_state &= ~BIT(n);
@@ -264,10 +322,11 @@
 				work = !(bigben->led_state & BIT(n));
 				bigben->led_state |= BIT(n);
 			}
+			spin_unlock_irqrestore(&bigben->lock, flags);
 
 			if (work) {
 				bigben->work_led = true;
-				schedule_work(&bigben->worker);
+				bigben_schedule_work(bigben);
 			}
 			return;
 		}
@@ -297,9 +356,13 @@
 static void bigben_remove(struct hid_device *hid)
 {
 	struct bigben_device *bigben = hid_get_drvdata(hid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bigben->lock, flags);
+	bigben->removed = true;
+	spin_unlock_irqrestore(&bigben->lock, flags);
 
 	cancel_work_sync(&bigben->worker);
-	hid_hw_close(hid);
 	hid_hw_stop(hid);
 }
 
@@ -308,7 +371,6 @@
 {
 	struct bigben_device *bigben;
 	struct hid_input *hidinput;
-	struct list_head *report_list;
 	struct led_classdev *led;
 	char *name;
 	size_t name_sz;
@@ -319,6 +381,7 @@
 		return -ENOMEM;
 	hid_set_drvdata(hid, bigben);
 	bigben->hid = hid;
+	bigben->removed = false;
 
 	error = hid_parse(hid);
 	if (error) {
@@ -332,19 +395,29 @@
 		return error;
 	}
 
-	report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	bigben->report = list_entry(report_list->next,
-		struct hid_report, list);
+	bigben->report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 8);
+	if (!bigben->report) {
+		hid_err(hid, "no output report found\n");
+		error = -ENODEV;
+		goto error_hw_stop;
+	}
+
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		error = -ENODEV;
+		goto error_hw_stop;
+	}
 
 	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
 	set_bit(FF_RUMBLE, hidinput->input->ffbit);
 
 	INIT_WORK(&bigben->worker, bigben_worker);
+	spin_lock_init(&bigben->lock);
 
-	error = input_ff_create_memless(hidinput->input, bigben,
+	error = input_ff_create_memless(hidinput->input, NULL,
 		hid_bigben_play_effect);
 	if (error)
-		return error;
+		goto error_hw_stop;
 
 	name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
 
@@ -354,8 +427,10 @@
 			sizeof(struct led_classdev) + name_sz,
 			GFP_KERNEL
 		);
-		if (!led)
-			return -ENOMEM;
+		if (!led) {
+			error = -ENOMEM;
+			goto error_hw_stop;
+		}
 		name = (void *)(&led[1]);
 		snprintf(name, name_sz,
 			"%s:red:bigben%d",
@@ -369,7 +444,7 @@
 		bigben->leds[n] = led;
 		error = devm_led_classdev_register(&hid->dev, led);
 		if (error)
-			return error;
+			goto error_hw_stop;
 	}
 
 	/* initial state: LED1 is on, no rumble effect */
@@ -378,11 +453,15 @@
 	bigben->left_motor_force = 0;
 	bigben->work_led = true;
 	bigben->work_ff = true;
-	schedule_work(&bigben->worker);
+	bigben_schedule_work(bigben);
 
 	hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
 
 	return 0;
+
+error_hw_stop:
+	hid_hw_stop(hid);
+	return error;
 }
 
 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
--- linux-ein-5.4.0.orig/drivers/hid/hid-chicony.c
+++ linux-ein-5.4.0/drivers/hid/hid-chicony.c
@@ -58,8 +58,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 */
--- linux-ein-5.4.0.orig/drivers/hid/hid-core.c
+++ linux-ein-5.4.0/drivers/hid/hid-core.c
@@ -90,7 +90,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;
 
@@ -101,7 +101,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;
 
@@ -212,6 +212,18 @@
 }
 
 /*
+ * 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.
  */
 
@@ -222,6 +234,14 @@
 		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 ?
@@ -238,6 +258,7 @@
 {
 	struct hid_report *report;
 	struct hid_field *field;
+	unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
 	unsigned int usages;
 	unsigned int offset;
 	unsigned int i;
@@ -268,13 +289,22 @@
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	if (parser->device->ll_driver->max_buffer_size)
+		max_buffer_size = parser->device->ll_driver->max_buffer_size;
+
+	/* Total size check: Allow for possible report index byte */
+	if (report->size > (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;
 
@@ -543,13 +573,32 @@
  * usage value."
  */
 
-static void hid_concatenate_usage_page(struct hid_parser *parser)
+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;
 
-	for (i = 0; i < parser->local.usage_index; i++)
-		if (parser->local.usage_size[i] <= 2)
-			parser->local.usage[i] += parser->global.usage_page << 16;
+		complete_usage(parser, i);
+	}
 }
 
 /*
@@ -561,7 +610,7 @@
 	__u32 data;
 	int ret;
 
-	hid_concatenate_usage_page(parser);
+	hid_concatenate_last_usage_page(parser);
 
 	data = item_udata(item);
 
@@ -653,15 +702,22 @@
  * Free a device structure, all reports, and all fields.
  */
 
-static void hid_device_release(struct device *dev)
+void hiddev_free(struct kref *ref)
 {
-	struct hid_device *hid = to_hid_device(dev);
+	struct hid_device *hid = container_of(ref, struct hid_device, ref);
 
 	hid_close_report(hid);
 	kfree(hid->dev_rdesc);
 	kfree(hid);
 }
 
+static void hid_device_release(struct device *dev)
+{
+	struct hid_device *hid = to_hid_device(dev);
+
+	kref_put(&hid->ref, hiddev_free);
+}
+
 /*
  * Fetch a report description item from the data stream. We support long
  * items, though they are not used yet.
@@ -742,6 +798,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)
@@ -772,7 +832,7 @@
 	__u32 data;
 	int i;
 
-	hid_concatenate_usage_page(parser);
+	hid_concatenate_last_usage_page(parser);
 
 	data = item_udata(item);
 
@@ -932,8 +992,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];
@@ -1141,6 +1201,7 @@
 	__u8 *end;
 	__u8 *next;
 	int ret;
+	int i;
 	static int (*dispatch_type[])(struct hid_parser *parser,
 				      struct hid_item *item) = {
 		hid_parser_main,
@@ -1191,6 +1252,8 @@
 		goto err;
 	}
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+	for (i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++)
+		device->collection[i].parent_idx = -1;
 
 	ret = -EINVAL;
 	while ((next = fetch_item(start, end, &item)) != NULL) {
@@ -1251,6 +1314,12 @@
 
 static s32 snto32(__u32 value, unsigned n)
 {
+	if (!value || !n)
+		return 0;
+
+	if (n > 32)
+		n = 32;
+
 	switch (n) {
 	case 8:  return ((__s8)value);
 	case 16: return ((__s16)value);
@@ -1549,6 +1618,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.
  */
@@ -1560,7 +1640,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);
 }
@@ -1676,6 +1756,7 @@
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
 	struct hid_driver *hdrv;
+	int max_buffer_size = HID_MAX_BUFFER_SIZE;
 	unsigned int a;
 	u32 rsize, csize = size;
 	u8 *cdata = data;
@@ -1690,10 +1771,15 @@
 		csize--;
 	}
 
-	rsize = ((report->size - 1) >> 3) + 1;
+	rsize = hid_compute_report_size(report);
 
-	if (rsize > HID_MAX_BUFFER_SIZE)
-		rsize = HID_MAX_BUFFER_SIZE;
+	if (hid->ll_driver->max_buffer_size)
+		max_buffer_size = hid->ll_driver->max_buffer_size;
+
+	if (report_enum->numbered && rsize >= max_buffer_size)
+		rsize = max_buffer_size - 1;
+	else if (rsize > max_buffer_size)
+		rsize = max_buffer_size;
 
 	if (csize < rsize) {
 		dbg_hid("report %d is too short, (%d < %d)\n", report->id,
@@ -1933,6 +2019,9 @@
 	case BUS_I2C:
 		bus = "I2C";
 		break;
+	case BUS_VIRTUAL:
+		bus = "VIRTUAL";
+		break;
 	default:
 		bus = "<UNKNOWN>";
 	}
@@ -2231,12 +2320,8 @@
 {
 	struct hid_device *hdev = to_hid_device(dev);
 	struct hid_driver *hdrv;
-	int ret = 0;
 
-	if (down_interruptible(&hdev->driver_input_lock)) {
-		ret = -EINTR;
-		goto end;
-	}
+	down(&hdev->driver_input_lock);
 	hdev->io_started = false;
 
 	hdrv = hdev->driver;
@@ -2251,8 +2336,8 @@
 
 	if (!hdev->io_started)
 		up(&hdev->driver_input_lock);
-end:
-	return ret;
+
+	return 0;
 }
 
 static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
@@ -2359,10 +2444,12 @@
 			hid_warn(hdev, "bad device descriptor (%d)\n", ret);
 	}
 
+	hdev->id = atomic_inc_return(&id);
+
 	/* XXX hack, any other cleaner solution after the driver core
 	 * is converted to allow more than 20 bytes as the device name? */
 	dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
-		     hdev->vendor, hdev->product, atomic_inc_return(&id));
+		     hdev->vendor, hdev->product, hdev->id);
 
 	hid_debug_register(hdev, dev_name(&hdev->dev));
 	ret = device_add(&hdev->dev);
@@ -2405,6 +2492,7 @@
 	spin_lock_init(&hdev->debug_list_lock);
 	sema_init(&hdev->driver_input_lock, 1);
 	mutex_init(&hdev->ll_open_lock);
+	kref_init(&hdev->ref);
 
 	return hdev;
 }
--- linux-ein-5.4.0.orig/drivers/hid/hid-corsair.c
+++ linux-ein-5.4.0/drivers/hid/hid-corsair.c
@@ -553,7 +553,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-ein-5.4.0.orig/drivers/hid/hid-cp2112.c
+++ linux-ein-5.4.0/drivers/hid/hid-cp2112.c
@@ -787,6 +787,11 @@
 		data->word = le16_to_cpup((__le16 *)buf);
 		break;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_length > I2C_SMBUS_BLOCK_MAX) {
+			ret = -EINVAL;
+			goto power_normal;
+		}
+
 		memcpy(data->block + 1, buf, read_length);
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
@@ -1151,8 +1156,6 @@
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct cp2112_device *dev = gpiochip_get_data(gc);
 
-	INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
-
 	if (!dev->gpio_poll) {
 		dev->gpio_poll = true;
 		schedule_delayed_work(&dev->gpio_poll_worker, 0);
@@ -1235,6 +1238,7 @@
 	struct cp2112_device *dev;
 	u8 buf[3];
 	struct cp2112_smbus_config_report config;
+	struct gpio_irq_chip *girq;
 	int ret;
 
 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -1338,6 +1342,17 @@
 	dev->gc.can_sleep		= 1;
 	dev->gc.parent			= &hdev->dev;
 
+	girq = &dev->gc.irq;
+	girq->chip = &cp2112_gpio_irqchip;
+	/* The event comes from the outside so no parent handler */
+	girq->parent_handler = NULL;
+	girq->num_parents = 0;
+	girq->parents = NULL;
+	girq->default_type = IRQ_TYPE_NONE;
+	girq->handler = handle_simple_irq;
+
+	INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
+
 	ret = gpiochip_add_data(&dev->gc, dev);
 	if (ret < 0) {
 		hid_err(hdev, "error registering gpio chip\n");
@@ -1353,17 +1368,8 @@
 	chmod_sysfs_attrs(hdev);
 	hid_hw_power(hdev, PM_HINT_NORMAL);
 
-	ret = gpiochip_irqchip_add(&dev->gc, &cp2112_gpio_irqchip, 0,
-				   handle_simple_irq, IRQ_TYPE_NONE);
-	if (ret) {
-		dev_err(dev->gc.parent, "failed to add IRQ chip\n");
-		goto err_sysfs_remove;
-	}
-
 	return ret;
 
-err_sysfs_remove:
-	sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
 err_gpiochip_remove:
 	gpiochip_remove(&dev->gc);
 err_free_i2c:
--- linux-ein-5.4.0.orig/drivers/hid/hid-cypress.c
+++ linux-ein-5.4.0/drivers/hid/hid-cypress.c
@@ -23,19 +23,17 @@
 #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))
-		return rdesc;
-
 	if (*rsize < 4)
 		return rdesc;
 
@@ -48,6 +46,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 +160,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-ein-5.4.0.orig/drivers/hid/hid-debug.c
+++ linux-ein-5.4.0/drivers/hid/hid-debug.c
@@ -823,7 +823,9 @@
 	[KEY_F22] = "F22",			[KEY_F23] = "F23",
 	[KEY_F24] = "F24",			[KEY_PLAYCD] = "PlayCD",
 	[KEY_PAUSECD] = "PauseCD",		[KEY_PROG3] = "Prog3",
-	[KEY_PROG4] = "Prog4",			[KEY_SUSPEND] = "Suspend",
+	[KEY_PROG4] = "Prog4",
+	[KEY_ALL_APPLICATIONS] = "AllApplications",
+	[KEY_SUSPEND] = "Suspend",
 	[KEY_CLOSE] = "Close",			[KEY_PLAY] = "Play",
 	[KEY_FASTFORWARD] = "FastForward",	[KEY_BASSBOOST] = "BassBoost",
 	[KEY_PRINT] = "Print",			[KEY_HP] = "HP",
@@ -929,6 +931,9 @@
 	[KEY_APPSELECT] = "AppSelect",
 	[KEY_SCREENSAVER] = "ScreenSaver",
 	[KEY_VOICECOMMAND] = "VoiceCommand",
+	[KEY_EMOJI_PICKER] = "EmojiPicker",
+	[KEY_DICTATE] = "Dictate",
+	[KEY_MICMUTE] = "MicrophoneMute",
 	[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
 	[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
 	[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
@@ -1077,6 +1082,7 @@
 		goto out;
 	}
 	list->hdev = (struct hid_device *) inode->i_private;
+	kref_get(&list->hdev->ref);
 	file->private_data = list;
 	mutex_init(&list->read_mutex);
 
@@ -1169,6 +1175,8 @@
 	list_del(&list->node);
 	spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags);
 	kfifo_free(&list->hid_debug_fifo);
+
+	kref_put(&list->hdev->ref, hiddev_free);
 	kfree(list);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/hid/hid-elan.c
+++ linux-ein-5.4.0/drivers/hid/hid-elan.c
@@ -50,7 +50,7 @@
 
 static int is_not_elan_touchpad(struct hid_device *hdev)
 {
-	if (hdev->bus == BUS_USB) {
+	if (hid_is_usb(hdev)) {
 		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
 		return (intf->altsetting->desc.bInterfaceNumber !=
@@ -198,7 +198,7 @@
 	if (ret) {
 		hid_err(hdev, "Failed to register elan input device: %d\n",
 			ret);
-		input_free_device(input);
+		input_mt_destroy_slots(input);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/hid/hid-elo.c
+++ linux-ein-5.4.0/drivers/hid/hid-elo.c
@@ -229,6 +229,9 @@
 	struct elo_priv *priv;
 	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/hid/hid-google-hammer.c
+++ linux-ein-5.4.0/drivers/hid/hid-google-hammer.c
@@ -468,12 +468,20 @@
 
 static const struct hid_device_id hammer_devices[] = {
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_EEL) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_JEWEL) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) },
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) },
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MOONBALL) },
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) },
 	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
 		     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WAND) },
--- linux-ein-5.4.0.orig/drivers/hid/hid-gt683r.c
+++ linux-ein-5.4.0/drivers/hid/hid-gt683r.c
@@ -54,6 +54,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
 	{ }
 };
+MODULE_DEVICE_TABLE(hid, gt683r_led_id);
 
 static void gt683r_brightness_set(struct led_classdev *led_cdev,
 				enum led_brightness brightness)
--- linux-ein-5.4.0.orig/drivers/hid/hid-holtek-kbd.c
+++ linux-ein-5.4.0/drivers/hid/hid-holtek-kbd.c
@@ -130,6 +130,10 @@
 		return -ENODEV;
 
 	boot_hid = usb_get_intfdata(boot_interface);
+	if (list_empty(&boot_hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
 	boot_hid_input = list_first_entry(&boot_hid->inputs,
 		struct hid_input, list);
 
@@ -140,12 +144,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-ein-5.4.0.orig/drivers/hid/hid-holtek-mouse.c
+++ linux-ein-5.4.0/drivers/hid/hid-holtek-mouse.c
@@ -62,6 +62,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) },
@@ -83,6 +106,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-ein-5.4.0.orig/drivers/hid/hid-hyperv.c
+++ linux-ein-5.4.0/drivers/hid/hid-hyperv.c
@@ -492,7 +492,7 @@
 
 	ret = hid_add_device(hid_dev);
 	if (ret)
-		goto probe_err1;
+		goto probe_err2;
 
 
 	ret = hid_parse(hid_dev);
--- linux-ein-5.4.0.orig/drivers/hid/hid-ids.h
+++ linux-ein-5.4.0/drivers/hid/hid-ids.h
@@ -79,10 +79,10 @@
 #define HID_DEVICE_ID_ALPS_U1_DUAL_PTP	0x121F
 #define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP	0x1220
 #define HID_DEVICE_ID_ALPS_U1		0x1215
+#define HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY         0x121E
 #define HID_DEVICE_ID_ALPS_T4_BTNLESS	0x120C
 #define HID_DEVICE_ID_ALPS_1222		0x1222
 
-
 #define USB_VENDOR_ID_AMI		0x046b
 #define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE	0xff10
 
@@ -175,6 +175,7 @@
 #define USB_DEVICE_ID_APPLE_IRCONTROL3	0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
 #define USB_DEVICE_ID_APPLE_IRCONTROL5	0x8243
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021   0x029c
 
 #define USB_VENDOR_ID_ASUS		0x0486
 #define USB_DEVICE_ID_ASUS_T91MT	0x0185
@@ -337,6 +338,8 @@
 #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
 
@@ -348,6 +351,7 @@
 
 #define USB_VENDOR_ID_DELL				0x413c
 #define USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE	0x301a
+#define USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W		0x4503
 
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE	0x0100
@@ -363,6 +367,7 @@
 #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR	0x1803
 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1	0x1843
 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2	0x1844
+#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3	0x1846
 
 #define USB_VENDOR_ID_DWAV		0x0eef
 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER	0x0001
@@ -385,11 +390,13 @@
 #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
 #define USB_DEVICE_ID_TOSHIBA_CLICK_L9W	0x0401
 #define USB_DEVICE_ID_HP_X2		0x074d
 #define USB_DEVICE_ID_HP_X2_10_COVER	0x0755
+#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN	0x2706
 
 #define USB_VENDOR_ID_ELECOM		0x056e
 #define USB_DEVICE_ID_ELECOM_BM084	0x0061
@@ -448,6 +455,10 @@
 #define USB_VENDOR_ID_FRUCTEL	0x25B6
 #define USB_DEVICE_ID_GAMETEL_MT_MODE	0x0002
 
+#define USB_VENDOR_ID_GAMEVICE	0x27F8
+#define USB_DEVICE_ID_GAMEVICE_GV186	0x0BBE
+#define USB_DEVICE_ID_GAMEVICE_KISHI	0x0BBF
+
 #define USB_VENDOR_ID_GAMERON		0x0810
 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR	0x0001
 #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR	0x0002
@@ -478,6 +489,10 @@
 #define USB_DEVICE_ID_GOOGLE_WHISKERS	0x5030
 #define USB_DEVICE_ID_GOOGLE_MASTERBALL	0x503c
 #define USB_DEVICE_ID_GOOGLE_MAGNEMITE	0x503d
+#define USB_DEVICE_ID_GOOGLE_MOONBALL	0x5044
+#define USB_DEVICE_ID_GOOGLE_DON	0x5050
+#define USB_DEVICE_ID_GOOGLE_EEL	0x5057
+#define USB_DEVICE_ID_GOOGLE_JEWEL	0x5061
 
 #define USB_VENDOR_ID_GOTOP		0x08f2
 #define USB_DEVICE_ID_SUPER_Q2		0x007f
@@ -485,6 +500,7 @@
 #define USB_DEVICE_ID_PENPOWER		0x00f4
 
 #define USB_VENDOR_ID_GREENASIA		0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR 0x3010
 #define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD	0x3013
 
 #define USB_VENDOR_ID_GRETAGMACBETH	0x0971
@@ -567,12 +583,14 @@
 #define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
 
 #define USB_VENDOR_ID_HP		0x03f0
+#define USB_PRODUCT_ID_HP_ELITE_PRESENTER_MOUSE_464A		0x464a
 #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_094A	0x094a
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941	0x0941
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641	0x0641
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a	0x1f4a
 
 #define USB_VENDOR_ID_HUION		0x256c
 #define USB_DEVICE_ID_HUION_TABLET	0x006e
@@ -617,6 +635,7 @@
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081	0xa081
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2	0xa0c2
 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096	0xa096
+#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293	0xa293
 
 #define USB_VENDOR_ID_IMATION		0x0718
 #define USB_DEVICE_ID_DISC_STAKKA	0xd000
@@ -628,10 +647,14 @@
 #define USB_DEVICE_ID_INNEX_GENESIS_ATARI	0x4745
 
 #define USB_VENDOR_ID_ITE               0x048d
+#define I2C_VENDOR_ID_ITE		0x103c
+#define I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15	0x184f
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
+#define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720	0x837a
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA900	0x8396
 #define USB_DEVICE_ID_ITE8595		0x8595
+#define USB_DEVICE_ID_ITE_MEDION_E1239T	0xce50
 
 #define USB_VENDOR_ID_JABRA		0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410	0x0412
@@ -724,15 +747,22 @@
 #define USB_DEVICE_ID_LENOVO_X1_COVER	0x6085
 #define USB_DEVICE_ID_LENOVO_X1_TAB	0x60a3
 #define USB_DEVICE_ID_LENOVO_X1_TAB3	0x60b5
+#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E	0x600e
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D	0x608d
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019	0x6019
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E	0x602e
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093	0x6093
 
 #define USB_VENDOR_ID_LG		0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH	0x0064
 #define USB_DEVICE_ID_LG_MELFAS_MT	0x6007
 #define I2C_DEVICE_ID_LG_8001		0x8001
+#define I2C_DEVICE_ID_LG_7010		0x7010
 
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_T651	0xb00c
+#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD	0xb309
 #define USB_DEVICE_ID_LOGITECH_C007	0xc007
 #define USB_DEVICE_ID_LOGITECH_C077	0xc077
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
@@ -764,6 +794,7 @@
 #define USB_DEVICE_ID_LOGITECH_G27_WHEEL	0xc29b
 #define USB_DEVICE_ID_LOGITECH_WII_WHEEL	0xc29c
 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
+#define USB_DEVICE_ID_LOGITECH_GROUP_AUDIO	0x0882
 #define USB_DEVICE_ID_S510_RECEIVER	0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
 #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500	0xc512
@@ -792,6 +823,7 @@
 #define USB_DEVICE_ID_MADCATZ_BEATPAD	0x4540
 #define USB_DEVICE_ID_MADCATZ_RAT5	0x1705
 #define USB_DEVICE_ID_MADCATZ_RAT9	0x1709
+#define USB_DEVICE_ID_MADCATZ_MMO7  0x1713
 
 #define USB_VENDOR_ID_MCC		0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
@@ -833,8 +865,11 @@
 #define USB_DEVICE_ID_MS_TOUCH_COVER_2   0x07a7
 #define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9
 #define USB_DEVICE_ID_MS_POWER_COVER     0x07da
+#define USB_DEVICE_ID_MS_SURFACE3_COVER		0x07de
 #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER	0x02fd
 #define USB_DEVICE_ID_MS_PIXART_MOUSE    0x00cb
+#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS      0x02e0
+#define USB_DEVICE_ID_MS_MOUSE_0783      0x0783
 
 #define USB_VENDOR_ID_MOJO		0x8282
 #define USB_DEVICE_ID_RETRO_ADAPTER	0x3201
@@ -907,6 +942,10 @@
 #define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S	0x8003
 
 #define USB_VENDOR_ID_PLANTRONICS	0x047f
+#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3210_SERIES	0xc055
+#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES	0xc056
+#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3215_SERIES	0xc057
+#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3225_SERIES	0xc058
 
 #define USB_VENDOR_ID_PANASONIC		0x04da
 #define USB_DEVICE_ID_PANABOARD_UBT780	0x1044
@@ -959,6 +998,7 @@
 
 #define I2C_VENDOR_ID_RAYDIUM		0x2386
 #define I2C_PRODUCT_ID_RAYDIUM_4B33	0x4b33
+#define I2C_PRODUCT_ID_RAYDIUM_3118	0x3118
 
 #define USB_VENDOR_ID_RAZER            0x1532
 #define USB_DEVICE_ID_RAZER_BLADE_14   0x011D
@@ -988,6 +1028,8 @@
 #define USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO	0x3232
 #define USB_DEVICE_ID_ROCCAT_SAVU	0x2d5a
 
+#define USB_VENDOR_ID_SAI		0x17dd
+
 #define USB_VENDOR_ID_SAITEK		0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
 #define USB_DEVICE_ID_SAITEK_PS1000	0x0621
@@ -997,6 +1039,9 @@
 #define USB_DEVICE_ID_SAITEK_RAT9	0x0cfa
 #define USB_DEVICE_ID_SAITEK_MMO7	0x0cd0
 #define USB_DEVICE_ID_SAITEK_X52	0x075c
+#define USB_DEVICE_ID_SAITEK_X52_2	0x0255
+#define USB_DEVICE_ID_SAITEK_X52_PRO	0x0762
+#define USB_DEVICE_ID_SAITEK_X65	0x0b6a
 
 #define USB_VENDOR_ID_SAMSUNG		0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
@@ -1082,6 +1127,9 @@
 #define USB_DEVICE_ID_SYMBOL_SCANNER_2	0x1300
 #define USB_DEVICE_ID_SYMBOL_SCANNER_3	0x1200
 
+#define I2C_VENDOR_ID_SYNAPTICS     0x06cb
+#define I2C_PRODUCT_ID_SYNAPTICS_SYNA2393   0x7a13
+
 #define USB_VENDOR_ID_SYNAPTICS		0x06cb
 #define USB_DEVICE_ID_SYNAPTICS_TP	0x0001
 #define USB_DEVICE_ID_SYNAPTICS_INT_TP	0x0002
@@ -1096,7 +1144,12 @@
 #define USB_DEVICE_ID_SYNAPTICS_LTS2	0x1d10
 #define USB_DEVICE_ID_SYNAPTICS_HD	0x0ac3
 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD	0x1ac3
+#define USB_DEVICE_ID_SYNAPTICS_DELL_K12A	0x2819
+#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012	0x2968
 #define USB_DEVICE_ID_SYNAPTICS_TP_V103	0x5710
+#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002	0x73f4
+#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003	0x73f5
+#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017	0x73f6
 #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5	0x81a7
 
 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS	0x2047
@@ -1135,6 +1188,9 @@
 #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882	0x8882
 #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883	0x8883
 
+#define USB_VENDOR_ID_TRUST             0x145f
+#define USB_DEVICE_ID_TRUST_PANORA_TABLET   0x0212
+
 #define USB_VENDOR_ID_TURBOX		0x062a
 #define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
 #define USB_DEVICE_ID_ASUS_MD_5110	0x5110
@@ -1247,6 +1303,7 @@
 
 #define USB_VENDOR_ID_PRIMAX	0x0461
 #define USB_DEVICE_ID_PRIMAX_MOUSE_4D22	0x4d22
+#define USB_DEVICE_ID_PRIMAX_MOUSE_4E2A	0x4e2a
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05
 #define USB_DEVICE_ID_PRIMAX_REZEL	0x4e72
 #define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F	0x4d0f
@@ -1266,6 +1323,8 @@
 
 #define USB_VENDOR_ID_UGTIZER			0x2179
 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610	0x0053
+#define USB_DEVICE_ID_UGTIZER_TABLET_GT5040	0x0077
+#define USB_DEVICE_ID_UGTIZER_TABLET_WP5540	0x0004
 
 #define USB_VENDOR_ID_VIEWSONIC			0x0543
 #define USB_DEVICE_ID_VIEWSONIC_PD1011		0xe621
--- linux-ein-5.4.0.orig/drivers/hid/hid-input.c
+++ linux-ein-5.4.0/drivers/hid/hid-input.c
@@ -319,6 +319,11 @@
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
 		USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD),
 	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
+		USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
+	  HID_BATTERY_QUIRK_IGNORE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
+	  HID_BATTERY_QUIRK_IGNORE },
 	{}
 };
 
@@ -350,13 +355,13 @@
 	u8 *buf;
 	int ret;
 
-	buf = kmalloc(2, GFP_KERNEL);
+	buf = kmalloc(4, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
-	ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
+	ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4,
 				 dev->battery_report_type, HID_REQ_GET_REPORT);
-	if (ret != 2) {
+	if (ret < 2) {
 		kfree(buf);
 		return -ENODATA;
 	}
@@ -410,8 +415,6 @@
 
 		if (dev->battery_status == HID_BATTERY_UNKNOWN)
 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-		else if (dev->battery_capacity == 100)
-			val->intval = POWER_SUPPLY_STATUS_FULL;
 		else
 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 		break;
@@ -668,6 +671,14 @@
 			break;
 		}
 
+		if ((usage->hid & 0xf0) == 0xa0) {	/* SystemControl */
+			switch (usage->hid & 0xf) {
+			case 0x9: map_key_clear(KEY_MICMUTE); break;
+			default: goto ignore;
+			}
+			break;
+		}
+
 		if ((usage->hid & 0xf0) == 0xb0) {	/* SC - Display */
 			switch (usage->hid & 0xf) {
 			case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break;
@@ -797,7 +808,7 @@
 		case 0x3b: /* Battery Strength */
 			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
 			usage->type = EV_PWR;
-			goto ignore;
+			return;
 
 		case 0x3c: /* Invert */
 			map_key_clear(BTN_TOOL_RUBBER);
@@ -952,6 +963,10 @@
 
 		case 0x0cd: map_key_clear(KEY_PLAYPAUSE);	break;
 		case 0x0cf: map_key_clear(KEY_VOICECOMMAND);	break;
+
+		case 0x0d8: map_key_clear(KEY_DICTATE);		break;
+		case 0x0d9: map_key_clear(KEY_EMOJI_PICKER);	break;
+
 		case 0x0e0: map_abs_clear(ABS_VOLUME);		break;
 		case 0x0e2: map_key_clear(KEY_MUTE);		break;
 		case 0x0e5: map_key_clear(KEY_BASSBOOST);	break;
@@ -1041,6 +1056,8 @@
 
 		case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT);	break;
 
+		case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS);	break;
+
 		case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV);		break;
 		case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT);		break;
 		case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP);		break;
@@ -1059,7 +1076,7 @@
 		case HID_DC_BATTERYSTRENGTH:
 			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
 			usage->type = EV_PWR;
-			goto ignore;
+			return;
 		}
 		goto unknown;
 
@@ -1132,9 +1149,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);
 
@@ -1215,9 +1242,11 @@
 		set_bit(MSC_SCAN, input->mscbit);
 	}
 
-ignore:
 	return;
 
+ignore:
+	usage->type = 0;
+	usage->code = 0;
 }
 
 static void hidinput_handle_scroll(struct hid_usage *usage,
@@ -1270,6 +1299,12 @@
 
 	input = field->hidinput->input;
 
+	if (usage->type == EV_ABS &&
+	    (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
+	     ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) {
+		value = field->logical_maximum - value;
+	}
+
 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int hat_dir = usage->hat_dir;
 		if (!hat_dir)
--- linux-ein-5.4.0.orig/drivers/hid/hid-ite.c
+++ linux-ein-5.4.0/drivers/hid/hid-ite.c
@@ -11,6 +11,59 @@
 
 #include "hid-ids.h"
 
+#define QUIRK_TOUCHPAD_ON_OFF_REPORT		BIT(0)
+
+static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
+{
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) {
+		/* For Acer Aspire Switch 10 SW5-012 keyboard-dock */
+		if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) {
+			hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n");
+			rdesc[163] = HID_MAIN_ITEM_RELATIVE;
+		}
+		/* For Acer One S1002/S1003 keyboard-dock */
+		if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) {
+			hid_info(hdev, "Fixing up Acer S1002/S1003 ITE keyboard report descriptor\n");
+			rdesc[186] = HID_MAIN_ITEM_RELATIVE;
+		}
+		/* For Acer Aspire Switch 10E (SW3-016) keyboard-dock */
+		if (*rsize == 210 && rdesc[184] == 0x81 && rdesc[185] == 0x02) {
+			hid_info(hdev, "Fixing up Acer Aspire Switch 10E (SW3-016) ITE keyboard report descriptor\n");
+			rdesc[185] = HID_MAIN_ITEM_RELATIVE;
+		}
+	}
+
+	return rdesc;
+}
+
+static int ite_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit,
+		int *max)
+{
+
+	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+	if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) &&
+	    (usage->hid & HID_USAGE_PAGE) == 0x00880000) {
+		if (usage->hid == 0x00880078) {
+			/* Touchpad on, userspace expects F22 for this */
+			hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F22);
+			return 1;
+		}
+		if (usage->hid == 0x00880079) {
+			/* Touchpad off, userspace expects F23 for this */
+			hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F23);
+			return 1;
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
 static int ite_event(struct hid_device *hdev, struct hid_field *field,
 		     struct hid_usage *usage, __s32 value)
 {
@@ -37,9 +90,42 @@
 	return 0;
 }
 
+static int ite_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+
+	hid_set_drvdata(hdev, (void *)id->driver_data);
+
+	ret = hid_open_report(hdev);
+	if (ret)
+		return ret;
+
+	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
 static const struct hid_device_id ite_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) },
+	/* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_SYNAPTICS,
+		     USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012),
+	  .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
+	/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_SYNAPTICS,
+		     USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002),
+	  .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
+	/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_SYNAPTICS,
+		     USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003),
+	  .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
+	/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
+	{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+		     USB_VENDOR_ID_SYNAPTICS,
+		     USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017),
+	  .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, ite_devices);
@@ -47,6 +133,9 @@
 static struct hid_driver ite_driver = {
 	.name = "itetech",
 	.id_table = ite_devices,
+	.probe = ite_probe,
+	.report_fixup = ite_report_fixup,
+	.input_mapping = ite_input_mapping,
 	.event = ite_event,
 };
 module_hid_driver(ite_driver);
--- linux-ein-5.4.0.orig/drivers/hid/hid-led.c
+++ linux-ein-5.4.0/drivers/hid/hid-led.c
@@ -366,7 +366,7 @@
 		.type = DREAM_CHEEKY,
 		.name = "Dream Cheeky Webmail Notifier",
 		.short_name = "dream_cheeky",
-		.max_brightness = 31,
+		.max_brightness = 63,
 		.num_leds = 1,
 		.report_size = 9,
 		.report_type = RAW_REQUEST,
--- linux-ein-5.4.0.orig/drivers/hid/hid-lg.c
+++ linux-ein-5.4.0/drivers/hid/hid-lg.c
@@ -769,12 +769,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)) {
--- linux-ein-5.4.0.orig/drivers/hid/hid-lg4ff.c
+++ linux-ein-5.4.0/drivers/hid/hid-lg4ff.c
@@ -872,6 +872,12 @@
 		return -ENOMEM;
 
 	i = strlen(lbuf);
+
+	if (i == 0) {
+		kfree(lbuf);
+		return -EINVAL;
+	}
+
 	if (lbuf[i-1] == '\n') {
 		if (i == 1) {
 			kfree(lbuf);
--- linux-ein-5.4.0.orig/drivers/hid/hid-logitech-dj.c
+++ linux-ein-5.4.0/drivers/hid/hid-logitech-dj.c
@@ -328,7 +328,7 @@
 	0x25, 0x01,		/*      LOGICAL_MAX (1)                 */
 	0x75, 0x01,		/*      REPORT_SIZE (1)                 */
 	0x95, 0x04,		/*      REPORT_COUNT (4)                */
-	0x81, 0x06,		/*      INPUT                           */
+	0x81, 0x02,		/*      INPUT (Data,Var,Abs)            */
 	0xC0,			/*    END_COLLECTION                    */
 	0xC0,			/*  END_COLLECTION                      */
 };
@@ -866,11 +866,24 @@
 	schedule_work(&djrcv_dev->work);
 }
 
+/*
+ * Some quad/bluetooth keyboards have a builtin touchpad in this case we see
+ * only 1 paired device with a device_type of REPORT_TYPE_KEYBOARD. For the
+ * touchpad to work we must also forward mouse input reports to the dj_hiddev
+ * created for the keyboard (instead of forwarding them to a second paired
+ * device with a device_type of REPORT_TYPE_MOUSE as we normally would).
+ */
+static const u16 kbd_builtin_touchpad_ids[] = {
+	0xb309, /* Dinovo Edge */
+	0xb30c, /* Dinovo Mini */
+};
+
 static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
 					    struct hidpp_event *hidpp_report,
 					    struct dj_workitem *workitem)
 {
 	struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
+	int i, id;
 
 	workitem->type = WORKITEM_TYPE_PAIRED;
 	workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
@@ -882,6 +895,13 @@
 		workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA |
 					       POWER_KEYS | MEDIA_CENTER |
 					       HIDPP;
+		id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb;
+		for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) {
+			if (id == kbd_builtin_touchpad_ids[i]) {
+				workitem->reports_supported |= STD_MOUSE;
+				break;
+			}
+		}
 		break;
 	case REPORT_TYPE_MOUSE:
 		workitem->reports_supported |= STD_MOUSE | HIDPP;
@@ -960,6 +980,7 @@
 	case 0x07:
 		device_type = "eQUAD step 4 Gaming";
 		logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
+		workitem.reports_supported |= STD_KEYBOARD;
 		break;
 	case 0x08:
 		device_type = "eQUAD step 4 for gamepads";
@@ -974,7 +995,13 @@
 		workitem.reports_supported |= STD_KEYBOARD;
 		break;
 	case 0x0d:
-		device_type = "eQUAD Lightspeed 1_1";
+		device_type = "eQUAD Lightspeed 1.1";
+		logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
+		workitem.reports_supported |= STD_KEYBOARD;
+		break;
+	case 0x0f:
+	case 0x11:
+		device_type = "eQUAD Lightspeed 1.2";
 		logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
 		workitem.reports_supported |= STD_KEYBOARD;
 		break;
@@ -1185,6 +1212,9 @@
 		 * 50 msec should gives enough time to the receiver to be ready.
 		 */
 		msleep(50);
+
+		if (retval)
+			return retval;
 	}
 
 	/*
@@ -1206,7 +1236,7 @@
 	buf[5] = 0x09;
 	buf[6] = 0x00;
 
-	hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf,
+	retval = hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf,
 			HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT,
 			HID_REQ_SET_REPORT);
 
@@ -1660,7 +1690,7 @@
 	case recvr_type_27mhz:		no_dj_interfaces = 2; break;
 	case recvr_type_bluetooth:	no_dj_interfaces = 2; break;
 	}
-	if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+	if (hid_is_usb(hdev)) {
 		intf = to_usb_interface(hdev->dev.parent);
 		if (intf && intf->altsetting->desc.bInterfaceNumber >=
 							no_dj_interfaces) {
@@ -1842,6 +1872,10 @@
 	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 		0xc531),
 	 .driver_data = recvr_type_gaming_hidpp},
+	{ /* Logitech G602 receiver (0xc537) */
+	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+		0xc537),
+	 .driver_data = recvr_type_gaming_hidpp},
 	{ /* Logitech lightspeed receiver (0xc539) */
 	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
 		USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1),
--- linux-ein-5.4.0.orig/drivers/hid/hid-logitech-hidpp.c
+++ linux-ein-5.4.0/drivers/hid/hid-logitech-hidpp.c
@@ -88,6 +88,8 @@
 #define HIDPP_CAPABILITY_BATTERY_MILEAGE	BIT(2)
 #define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS	BIT(3)
 
+#define lg_map_key_clear(c)  hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
 /*
  * There are two hidpp protocols in use, the first version hidpp10 is known
  * as register access protocol or RAP, the second version hidpp20 is known as
@@ -807,8 +809,7 @@
 	if (ret)
 		return ret;
 
-	snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD",
-		 hdev->product, &serial);
+	snprintf(hdev->uniq, sizeof(hdev->uniq), "%4phD", &serial);
 	dbg_hid("HID++ Unifying: Got serial: %s\n", hdev->uniq);
 
 	name = hidpp_unifying_get_name(hidpp);
@@ -902,6 +903,54 @@
 }
 
 /* -------------------------------------------------------------------------- */
+/* 0x0003: Device Information                                                 */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_DEVICE_INFORMATION			0x0003
+
+#define CMD_GET_DEVICE_INFO				0x00
+
+static int hidpp_get_serial(struct hidpp_device *hidpp, u32 *serial)
+{
+	struct hidpp_report response;
+	u8 feature_type;
+	u8 feature_index;
+	int ret;
+
+	ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_DEVICE_INFORMATION,
+				     &feature_index,
+				     &feature_type);
+	if (ret)
+		return ret;
+
+	ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+					  CMD_GET_DEVICE_INFO,
+					  NULL, 0, &response);
+	if (ret)
+		return ret;
+
+	/* See hidpp_unifying_get_serial() */
+	*serial = *((u32 *)&response.rap.params[1]);
+	return 0;
+}
+
+static int hidpp_serial_init(struct hidpp_device *hidpp)
+{
+	struct hid_device *hdev = hidpp->hid_dev;
+	u32 serial;
+	int ret;
+
+	ret = hidpp_get_serial(hidpp, &serial);
+	if (ret)
+		return ret;
+
+	snprintf(hdev->uniq, sizeof(hdev->uniq), "%4phD", &serial);
+	dbg_hid("HID++ DeviceInformation: Got serial: %s\n", hdev->uniq);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
 /* 0x0005: GetDeviceNameType                                                  */
 /* -------------------------------------------------------------------------- */
 
@@ -1102,6 +1151,9 @@
 	ret = hidpp_send_fap_command_sync(hidpp, feature_index,
 					  CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
 					  NULL, 0, &response);
+	/* Ignore these intermittent errors */
+	if (ret == HIDPP_ERROR_RESOURCE_ERROR)
+		return -EIO;
 	if (ret > 0) {
 		hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
 			__func__, ret);
@@ -2766,6 +2818,26 @@
 }
 
 /* -------------------------------------------------------------------------- */
+/* Logitech Dinovo Mini keyboard with builtin touchpad                        */
+/* -------------------------------------------------------------------------- */
+#define DINOVO_MINI_PRODUCT_ID		0xb30c
+
+static int lg_dinovo_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+/* -------------------------------------------------------------------------- */
 /* HID++1.0 devices which use HID++ reports for their wheels                  */
 /* -------------------------------------------------------------------------- */
 static int hidpp10_wheel_connect(struct hidpp_device *hidpp)
@@ -2961,7 +3033,7 @@
 		multiplier = 1;
 
 	hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
-	hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier);
+	hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
 	return 0;
 }
 
@@ -3000,6 +3072,9 @@
 			field->application != HID_GD_MOUSE)
 		return m560_input_mapping(hdev, hi, field, usage, bit, max);
 
+	if (hdev->product == DINOVO_MINI_PRODUCT_ID)
+		return lg_dinovo_input_mapping(hdev, hi, field, usage, bit, max);
+
 	return 0;
 }
 
@@ -3623,6 +3698,8 @@
 
 	if (hidpp->quirks & HIDPP_QUIRK_UNIFYING)
 		hidpp_unifying_init(hidpp);
+	else if (hid_is_usb(hidpp->hid_dev))
+		hidpp_serial_init(hidpp);
 
 	connected = hidpp_root_get_protocol_version(hidpp) == 0;
 	atomic_set(&hidpp->connected, connected);
@@ -3646,7 +3723,8 @@
 			goto hid_hw_init_fail;
 	}
 
-	hidpp_connect_event(hidpp);
+	schedule_work(&hidpp->work);
+	flush_work(&hidpp->work);
 
 	/* Reset the HID node state */
 	hid_device_io_stop(hdev);
@@ -3738,6 +3816,7 @@
 	  LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
 	{ /* Mouse Logitech MX Anywhere 2 */
 	  LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+	{ LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
 	{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
 	{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
 	{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
@@ -3760,6 +3839,9 @@
 	{ /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */
 	  LDJ_DEVICE(0xb305),
 	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
+	{ /* Dinovo Edge (Bluetooth-receiver in HID proxy mode) */
+	  LDJ_DEVICE(0xb309),
+	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
 	{ /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */
 	  LDJ_DEVICE(0xb30b),
 	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
@@ -3802,6 +3884,9 @@
 	{ /* MX5000 keyboard over Bluetooth */
 	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
 	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
+	{ /* Dinovo Edge keyboard over Bluetooth */
+	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb309),
+	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
 	{ /* MX5500 keyboard over Bluetooth */
 	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
 	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
--- linux-ein-5.4.0.orig/drivers/hid/hid-magicmouse.c
+++ linux-ein-5.4.0/drivers/hid/hid-magicmouse.c
@@ -387,7 +387,7 @@
 		magicmouse_raw_event(hdev, report, data + 2, data[1]);
 		magicmouse_raw_event(hdev, report, data + 2 + data[1],
 			size - 2 - data[1]);
-		break;
+		return 0;
 	default:
 		return 0;
 	}
@@ -535,6 +535,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;
 }
 
@@ -591,7 +597,7 @@
 	if (id->vendor == USB_VENDOR_ID_APPLE &&
 	    id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
 	    hdev->type != HID_TYPE_USBMOUSE)
-		return 0;
+		return -ENODEV;
 
 	msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
 	if (msc == NULL) {
--- linux-ein-5.4.0.orig/drivers/hid/hid-mf.c
+++ linux-ein-5.4.0/drivers/hid/hid-mf.c
@@ -153,6 +153,8 @@
 		.driver_data = HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2),
 		.driver_data = 0 }, /* No quirk required */
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
+		.driver_data = HID_QUIRK_MULTI_INPUT },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, mf_devices);
--- linux-ein-5.4.0.orig/drivers/hid/hid-microsoft.c
+++ linux-ein-5.4.0/drivers/hid/hid-microsoft.c
@@ -451,6 +451,8 @@
 		.driver_data = MS_SURFACE_DIAL },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
 		.driver_data = MS_QUIRK_FF },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS),
+		.driver_data = MS_QUIRK_FF },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, ms_devices);
--- linux-ein-5.4.0.orig/drivers/hid/hid-multitouch.c
+++ linux-ein-5.4.0/drivers/hid/hid-multitouch.c
@@ -69,6 +69,7 @@
 #define MT_QUIRK_ASUS_CUSTOM_UP		BIT(17)
 #define MT_QUIRK_WIN8_PTP_BUTTONS	BIT(18)
 #define MT_QUIRK_SEPARATE_APP_REPORT	BIT(19)
+#define MT_QUIRK_FORCE_MULTI_INPUT	BIT(20)
 
 #define MT_INPUTMODE_TOUCHSCREEN	0x02
 #define MT_INPUTMODE_TOUCHPAD		0x03
@@ -189,6 +190,7 @@
 #define MT_CLS_WIN_8				0x0012
 #define MT_CLS_EXPORT_ALL_INPUTS		0x0013
 #define MT_CLS_WIN_8_DUAL			0x0014
+#define MT_CLS_WIN_8_FORCE_MULTI_INPUT		0x0015
 
 /* vendor specific classes */
 #define MT_CLS_3M				0x0101
@@ -279,6 +281,15 @@
 			MT_QUIRK_CONTACT_CNT_ACCURATE |
 			MT_QUIRK_WIN8_PTP_BUTTONS,
 		.export_all_inputs = true },
+	{ .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		.quirks = MT_QUIRK_ALWAYS_VALID |
+			MT_QUIRK_IGNORE_DUPLICATES |
+			MT_QUIRK_HOVERING |
+			MT_QUIRK_CONTACT_CNT_ACCURATE |
+			MT_QUIRK_STICKY_FINGERS |
+			MT_QUIRK_WIN8_PTP_BUTTONS |
+			MT_QUIRK_FORCE_MULTI_INPUT,
+		.export_all_inputs = true },
 
 	/*
 	 * vendor specific classes
@@ -600,9 +611,13 @@
 		if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
 			continue;
 
-		for (n = 0; n < field->report_count; n++) {
-			if (field->usage[n].hid == HID_DG_CONTACTID)
-				rdata->is_mt_collection = true;
+		if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) {
+			for (n = 0; n < field->report_count; n++) {
+				if (field->usage[n].hid == HID_DG_CONTACTID) {
+					rdata->is_mt_collection = true;
+					break;
+				}
+			}
 		}
 	}
 
@@ -853,6 +868,8 @@
 			code = BTN_0  + ((usage->hid - 1) & HID_USAGE);
 
 		hid_map_usage(hi, usage, bit, max, EV_KEY, code);
+		if (!*bit)
+			return -1;
 		input_set_capability(hi->input, EV_KEY, code);
 		return 1;
 
@@ -1019,7 +1036,7 @@
 		tool = MT_TOOL_DIAL;
 	else if (unlikely(!confidence_state)) {
 		tool = MT_TOOL_PALM;
-		if (!active &&
+		if (!active && mt &&
 		    input_mt_is_active(&mt->slots[slotnum])) {
 			/*
 			 * The non-confidence was reported for
@@ -1145,7 +1162,7 @@
 	int contact_count = -1;
 
 	/* sticky fingers release in progress, abort */
-	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
+	if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 		return;
 
 	scantime = *app->scantime;
@@ -1226,7 +1243,7 @@
 			del_timer(&td->release_timer);
 	}
 
-	clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
+	clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
 }
 
 static int mt_touch_input_configured(struct hid_device *hdev,
@@ -1531,7 +1548,6 @@
 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
-	char *name;
 	const char *suffix = NULL;
 	struct mt_report_data *rdata;
 	struct mt_application *mt_application = NULL;
@@ -1570,13 +1586,13 @@
 		/* we do not set suffix = "Touchscreen" */
 		hi->input->name = hdev->name;
 		break;
-	case HID_DG_STYLUS:
-		/* force BTN_STYLUS to allow tablet matching in udev */
-		__set_bit(BTN_STYLUS, hi->input->keybit);
-		break;
 	case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
 		suffix = "Custom Media Keys";
 		break;
+	case HID_DG_STYLUS:
+		/* force BTN_STYLUS to allow tablet matching in udev */
+		__set_bit(BTN_STYLUS, hi->input->keybit);
+		fallthrough;
 	case HID_DG_PEN:
 		suffix = "Stylus";
 		break;
@@ -1585,15 +1601,9 @@
 		break;
 	}
 
-	if (suffix) {
-		name = devm_kzalloc(&hi->input->dev,
-				    strlen(hdev->name) + strlen(suffix) + 2,
-				    GFP_KERNEL);
-		if (name) {
-			sprintf(name, "%s %s", hdev->name, suffix);
-			hi->input->name = name;
-		}
-	}
+	if (suffix)
+		hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+						 "%s %s", hdev->name, suffix);
 
 	return 0;
 }
@@ -1663,11 +1673,11 @@
 	 * An input report came in just before we release the sticky fingers,
 	 * it will take care of the sticky fingers.
 	 */
-	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
+	if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 		return;
 	if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
 		mt_release_contacts(hdev);
-	clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
+	clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
 }
 
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -1714,6 +1724,11 @@
 	if (id->group != HID_GROUP_MULTITOUCH_WIN_8)
 		hdev->quirks |= HID_QUIRK_MULTI_INPUT;
 
+	if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) {
+		hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP;
+		hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+	}
+
 	timer_setup(&td->release_timer, mt_expired_timeout, 0);
 
 	ret = hid_parse(hdev);
@@ -1922,6 +1937,18 @@
 	{ .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) },
+
+	/* Elan devices */
+	{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ELAN, 0x313a) },
+
+	{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_ELAN, 0x3148) },
 
 	/* Elitegroup panel */
 	{ .driver_data = MT_CLS_SERIAL,
@@ -1976,6 +2003,11 @@
 		MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
 			USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
 
+	/* HONOR GLO-GXXX panel */
+	{ .driver_data = MT_CLS_VTL,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			0x347d, 0x7853) },
+
 	/* Ilitek dual touch panel */
 	{  .driver_data = MT_CLS_NSMU,
 		MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
@@ -1985,6 +2017,9 @@
 	{ .driver_data = MT_CLS_LG,
 		HID_USB_DEVICE(USB_VENDOR_ID_LG,
 			USB_DEVICE_ID_LG_MELFAS_MT) },
+	{ .driver_data = MT_CLS_LG,
+		HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC,
+			USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) },
 
 	/* MosArt panels */
 	{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
@@ -2050,6 +2085,19 @@
 		MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
 			USB_DEVICE_ID_MTP_STM)},
 
+	/* Synaptics devices */
+	{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_SYNAPTICS, 0xcd7e) },
+
+	{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_SYNAPTICS, 0xce08) },
+
+	{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+		HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+			USB_VENDOR_ID_SYNAPTICS, 0xce09) },
+
 	/* TopSeed panels */
 	{ .driver_data = MT_CLS_TOPSEED,
 		MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
@@ -2116,6 +2164,9 @@
 	{ .driver_data = MT_CLS_GOOGLE,
 		HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
 			USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
+	{ .driver_data = MT_CLS_GOOGLE,
+		HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_GOOGLE,
+			USB_DEVICE_ID_GOOGLE_WHISKERS) },
 
 	/* Generic MT device */
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
--- linux-ein-5.4.0.orig/drivers/hid/hid-plantronics.c
+++ linux-ein-5.4.0/drivers/hid/hid-plantronics.c
@@ -13,6 +13,7 @@
 
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/jiffies.h>
 
 #define PLT_HID_1_0_PAGE	0xffa00000
 #define PLT_HID_2_0_PAGE	0xffa20000
@@ -36,6 +37,16 @@
 #define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \
 			    (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
 
+#define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0)
+
+#define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */
+
+struct plt_drv_data {
+	unsigned long device_type;
+	unsigned long last_volume_key_ts;
+	u32 quirks;
+};
+
 static int plantronics_input_mapping(struct hid_device *hdev,
 				     struct hid_input *hi,
 				     struct hid_field *field,
@@ -43,7 +54,8 @@
 				     unsigned long **bit, int *max)
 {
 	unsigned short mapped_key;
-	unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
+	struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
+	unsigned long plt_type = drv_data->device_type;
 
 	/* special case for PTT products */
 	if (field->application == HID_GD_JOYSTICK)
@@ -105,6 +117,30 @@
 	return 1;
 }
 
+static int plantronics_event(struct hid_device *hdev, struct hid_field *field,
+			     struct hid_usage *usage, __s32 value)
+{
+	struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
+
+	if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) {
+		unsigned long prev_ts, cur_ts;
+
+		/* Usages are filtered in plantronics_usages. */
+
+		if (!value) /* Handle key presses only. */
+			return 0;
+
+		prev_ts = drv_data->last_volume_key_ts;
+		cur_ts = jiffies;
+		if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT)
+			return 1; /* Ignore the repeated key. */
+
+		drv_data->last_volume_key_ts = cur_ts;
+	}
+
+	return 0;
+}
+
 static unsigned long plantronics_device_type(struct hid_device *hdev)
 {
 	unsigned i, col_page;
@@ -133,15 +169,24 @@
 static int plantronics_probe(struct hid_device *hdev,
 			     const struct hid_device_id *id)
 {
+	struct plt_drv_data *drv_data;
 	int ret;
 
+	drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
+	if (!drv_data)
+		return -ENOMEM;
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
 		goto err;
 	}
 
-	hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev));
+	drv_data->device_type = plantronics_device_type(hdev);
+	drv_data->quirks = id->driver_data;
+	drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT);
+
+	hid_set_drvdata(hdev, drv_data);
 
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
 		HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE);
@@ -153,15 +198,35 @@
 }
 
 static const struct hid_device_id plantronics_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
+					 USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3210_SERIES),
+		.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
+					 USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES),
+		.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
+					 USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3215_SERIES),
+		.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
+					 USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3225_SERIES),
+		.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, plantronics_devices);
 
+static const struct hid_usage_id plantronics_usages[] = {
+	{ HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID },
+	{ HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID },
+	{ HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR }
+};
+
 static struct hid_driver plantronics_driver = {
 	.name = "plantronics",
 	.id_table = plantronics_devices,
+	.usage_table = plantronics_usages,
 	.input_mapping = plantronics_input_mapping,
+	.event = plantronics_event,
 	.probe = plantronics_probe,
 };
 module_hid_driver(plantronics_driver);
--- linux-ein-5.4.0.orig/drivers/hid/hid-prodikeys.c
+++ linux-ein-5.4.0/drivers/hid/hid-prodikeys.c
@@ -798,12 +798,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-ein-5.4.0.orig/drivers/hid/hid-quirks.c
+++ linux-ein-5.4.0/drivers/hid/hid-quirks.c
@@ -33,6 +33,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD), HID_QUIRK_BADPAD },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM), HID_QUIRK_NOGET },
@@ -66,12 +67,14 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
@@ -83,17 +86,25 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY), HID_QUIRK_NO_INIT_REPORTS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD), HID_QUIRK_MULTI_INPUT },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_GV186),
+		HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_KISHI),
+		HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096), HID_QUIRK_NO_INIT_REPORTS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_ELITE_PRESENTER_MOUSE_464A), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
@@ -102,6 +113,11 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
@@ -109,8 +125,10 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_MOUSE_0783), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE3_COVER), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
@@ -132,6 +150,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4E2A), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
@@ -144,6 +163,9 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
@@ -161,18 +183,23 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103), HID_QUIRK_NO_INIT_REPORTS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD), HID_QUIRK_BADPAD },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET), HID_QUIRK_MULTI_INPUT | HID_QUIRK_HIDINPUT_FORCE },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_WP5540), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET },
 
 	{ 0 }
 };
@@ -281,6 +308,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) },
 #endif
 #if IS_ENABLED(CONFIG_HID_APPLEIR)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
@@ -395,9 +423,6 @@
 	{ 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) },
 #endif
-#if IS_ENABLED(CONFIG_HID_ITE)
-	{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
-#endif
 #if IS_ENABLED(CONFIG_HID_ICADE)
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
 #endif
@@ -477,6 +502,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) },
 #endif
 #if IS_ENABLED(CONFIG_HID_MICROSOFT)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
@@ -595,6 +621,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_MMO7) },
 #endif
 #if IS_ENABLED(CONFIG_HID_SAMSUNG)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
@@ -837,6 +864,7 @@
 	{ 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) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAI, USB_DEVICE_ID_CYPRESS_HIDCOM) },
 #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
--- linux-ein-5.4.0.orig/drivers/hid/hid-rmi.c
+++ linux-ein-5.4.0/drivers/hid/hid-rmi.c
@@ -744,7 +744,8 @@
 {
 	struct rmi_data *hdata = hid_get_drvdata(hdev);
 
-	if (hdata->device_flags & RMI_DEVICE) {
+	if ((hdata->device_flags & RMI_DEVICE)
+	    && test_bit(RMI_STARTED, &hdata->flags)) {
 		clear_bit(RMI_STARTED, &hdata->flags);
 		cancel_work_sync(&hdata->reset_work);
 		rmi_unregister_transport_device(&hdata->xport);
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-arvo.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-arvo.c
@@ -344,6 +344,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-isku.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-isku.c
@@ -324,6 +324,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-kone.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-kone.c
@@ -294,31 +294,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,
@@ -740,6 +749,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-koneplus.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-koneplus.c
@@ -431,6 +431,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-konepure.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-konepure.c
@@ -133,6 +133,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-kovaplus.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-kovaplus.c
@@ -501,6 +501,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-lua.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-lua.c
@@ -160,6 +160,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-pyra.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-pyra.c
@@ -449,6 +449,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-ryos.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-ryos.c
@@ -141,6 +141,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat-savu.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat-savu.c
@@ -113,6 +113,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
--- linux-ein-5.4.0.orig/drivers/hid/hid-roccat.c
+++ linux-ein-5.4.0/drivers/hid/hid-roccat.c
@@ -257,6 +257,8 @@
 	if (!new_value)
 		return -ENOMEM;
 
+	mutex_lock(&device->cbuf_lock);
+
 	report = &device->cbuf[device->cbuf_end];
 
 	/* passing NULL is safe */
@@ -276,6 +278,8 @@
 			reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
 	}
 
+	mutex_unlock(&device->cbuf_lock);
+
 	wake_up_interruptible(&device->wait);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/hid/hid-saitek.c
+++ linux-ein-5.4.0/drivers/hid/hid-saitek.c
@@ -187,6 +187,8 @@
 		.driver_data = SAITEK_RELEASE_MODE_RAT7 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
 		.driver_data = SAITEK_RELEASE_MODE_MMO7 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_MMO7),
+		.driver_data = SAITEK_RELEASE_MODE_MMO7 },
 	{ }
 };
 
--- linux-ein-5.4.0.orig/drivers/hid/hid-samsung.c
+++ linux-ein-5.4.0/drivers/hid/hid-samsung.c
@@ -152,6 +152,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-ein-5.4.0.orig/drivers/hid/hid-sensor-custom.c
+++ linux-ein-5.4.0/drivers/hid/hid-sensor-custom.c
@@ -59,7 +59,7 @@
 	u32 raw_len;
 } __packed;
 
-static struct attribute hid_custom_attrs[] = {
+static struct attribute hid_custom_attrs[HID_CUSTOM_TOTAL_ATTRS] = {
 	{.name = "name", .mode = S_IRUGO},
 	{.name = "units", .mode = S_IRUGO},
 	{.name = "unit-expo", .mode = S_IRUGO},
--- linux-ein-5.4.0.orig/drivers/hid/hid-sensor-hub.c
+++ linux-ein-5.4.0/drivers/hid/hid-sensor-hub.c
@@ -210,16 +210,21 @@
 	buffer_size = buffer_size / sizeof(__s32);
 	if (buffer_size) {
 		for (i = 0; i < buffer_size; ++i) {
-			hid_set_field(report->field[field_index], i,
-				      (__force __s32)cpu_to_le32(*buf32));
+			ret = hid_set_field(report->field[field_index], i,
+					    (__force __s32)cpu_to_le32(*buf32));
+			if (ret)
+				goto done_proc;
+
 			++buf32;
 		}
 	}
 	if (remaining_bytes) {
 		value = 0;
 		memcpy(&value, (u8 *)buf32, remaining_bytes);
-		hid_set_field(report->field[field_index], i,
-			      (__force __s32)cpu_to_le32(value));
+		ret = hid_set_field(report->field[field_index], i,
+				    (__force __s32)cpu_to_le32(value));
+		if (ret)
+			goto done_proc;
 	}
 	hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
 	hid_hw_wait(hsdev->hdev);
@@ -483,7 +488,8 @@
 		return 1;
 
 	ptr = raw_data;
-	ptr++; /* Skip report id */
+	if (report->id)
+		ptr++; /* Skip report id */
 
 	spin_lock_irqsave(&pdata->lock, flags);
 
--- linux-ein-5.4.0.orig/drivers/hid/hid-sony.c
+++ linux-ein-5.4.0/drivers/hid/hid-sony.c
@@ -867,6 +867,23 @@
 	if (sc->quirks & PS3REMOTE)
 		return ps3remote_fixup(hdev, rdesc, rsize);
 
+	/*
+	 * Some knock-off USB dongles incorrectly report their button count
+	 * as 13 instead of 16 causing three non-functional buttons.
+	 */
+	if ((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize >= 45 &&
+		/* Report Count (13) */
+		rdesc[23] == 0x95 && rdesc[24] == 0x0D &&
+		/* Usage Maximum (13) */
+		rdesc[37] == 0x29 && rdesc[38] == 0x0D &&
+		/* Report Count (3) */
+		rdesc[43] == 0x95 && rdesc[44] == 0x03) {
+		hid_info(hdev, "Fixing up USB dongle report descriptor\n");
+		rdesc[24] = 0x10;
+		rdesc[38] = 0x10;
+		rdesc[44] = 0x00;
+	}
+
 	return rdesc;
 }
 
@@ -1580,16 +1597,38 @@
 	 * of the controller, so that it sends input reports of type 0x11.
 	 */
 	if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
+		int retries;
+
 		buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
 
-		ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
-					 DS4_FEATURE_REPORT_0x02_SIZE,
-					 HID_FEATURE_REPORT,
-					 HID_REQ_GET_REPORT);
-		if (ret < 0)
-			goto err_stop;
+		/* We should normally receive the feature report data we asked
+		 * for, but hidraw applications such as Steam can issue feature
+		 * reports as well. In particular for Dongle reconnects, Steam
+		 * and this function are competing resulting in often receiving
+		 * data for a different HID report, so retry a few times.
+		 */
+		for (retries = 0; retries < 3; retries++) {
+			ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
+						 DS4_FEATURE_REPORT_0x02_SIZE,
+						 HID_FEATURE_REPORT,
+						 HID_REQ_GET_REPORT);
+			if (ret < 0)
+				goto err_stop;
+
+			if (buf[0] != 0x02) {
+				if (retries < 2) {
+					hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n");
+					continue;
+				} else {
+					ret = -EILSEQ;
+					goto err_stop;
+				}
+			} else {
+				break;
+			}
+		}
 	} else {
 		u8 bthdr = 0xA3;
 		u32 crc;
--- linux-ein-5.4.0.orig/drivers/hid/hid-steam.c
+++ linux-ein-5.4.0/drivers/hid/hid-steam.c
@@ -134,6 +134,11 @@
 	int ret;
 
 	r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
+	if (!r) {
+		hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
+		return -EINVAL;
+	}
+
 	if (hid_report_len(r) < 64)
 		return -EINVAL;
 
@@ -165,6 +170,11 @@
 	int ret;
 
 	r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
+	if (!r) {
+		hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
+		return -EINVAL;
+	}
+
 	if (hid_report_len(r) < 64)
 		return -EINVAL;
 
@@ -526,7 +536,8 @@
 			steam_battery_register(steam);
 
 		mutex_lock(&steam_devices_lock);
-		list_add(&steam->list, &steam_devices);
+		if (list_empty(&steam->list))
+			list_add(&steam->list, &steam_devices);
 		mutex_unlock(&steam_devices_lock);
 	}
 
@@ -552,7 +563,7 @@
 		hid_info(steam->hdev, "Steam Controller '%s' disconnected",
 				steam->serial_no);
 		mutex_lock(&steam_devices_lock);
-		list_del(&steam->list);
+		list_del_init(&steam->list);
 		mutex_unlock(&steam_devices_lock);
 		steam->serial_no[0] = 0;
 	}
@@ -738,6 +749,7 @@
 	mutex_init(&steam->mutex);
 	steam->quirks = id->driver_data;
 	INIT_WORK(&steam->work_connect, steam_work_connect_cb);
+	INIT_LIST_HEAD(&steam->list);
 
 	steam->client_hdev = steam_create_client_hid(hdev);
 	if (IS_ERR(steam->client_hdev)) {
@@ -768,8 +780,12 @@
 
 	if (steam->quirks & STEAM_QUIRK_WIRELESS) {
 		hid_info(hdev, "Steam wireless receiver connected");
+		/* If using a wireless adaptor ask for connection status */
+		steam->connected = false;
 		steam_request_conn_status(steam);
 	} else {
+		/* A wired connection is always present */
+		steam->connected = true;
 		ret = steam_register(steam);
 		if (ret) {
 			hid_err(hdev,
--- linux-ein-5.4.0.orig/drivers/hid/hid-u2fzero.c
+++ linux-ein-5.4.0/drivers/hid/hid-u2fzero.c
@@ -132,7 +132,7 @@
 
 	ret = (wait_for_completion_timeout(
 		&ctx.done, msecs_to_jiffies(USB_CTRL_SET_TIMEOUT)));
-	if (ret < 0) {
+	if (ret == 0) {
 		usb_kill_urb(dev->urb);
 		hid_err(hdev, "urb submission timed out");
 	} else {
@@ -191,6 +191,8 @@
 	struct u2f_hid_msg resp;
 	int ret;
 	size_t actual_length;
+	/* valid packets must have a correct header */
+	int min_length = offsetof(struct u2f_hid_msg, init.data);
 
 	if (!dev->present) {
 		hid_dbg(dev->hdev, "device not present");
@@ -198,12 +200,14 @@
 	}
 
 	ret = u2fzero_recv(dev, &req, &resp);
-	if (ret < 0)
+
+	/* ignore errors or packets without data */
+	if (ret < min_length)
 		return 0;
 
 	/* only take the minimum amount of data it is safe to take */
-	actual_length = min3((size_t)ret - offsetof(struct u2f_hid_msg,
-		init.data), U2F_HID_MSG_LEN(resp), max);
+	actual_length = min3((size_t)ret - min_length,
+		U2F_HID_MSG_LEN(resp), max);
 
 	memcpy(data, resp.init.data, actual_length);
 
@@ -286,7 +290,7 @@
 	unsigned int minor;
 	int ret;
 
-	if (!hid_is_using_ll_driver(hdev, &usb_hid_driver))
+	if (!hid_is_usb(hdev))
 		return -EINVAL;
 
 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
--- linux-ein-5.4.0.orig/drivers/hid/hid-uclogic-core.c
+++ linux-ein-5.4.0/drivers/hid/hid-uclogic-core.c
@@ -164,11 +164,15 @@
 	struct uclogic_drvdata *drvdata = NULL;
 	bool params_initialized = false;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	/*
 	 * libinput requires the pad interface to be on a different node
 	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
 	 */
 	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+	hdev->quirks |= HID_QUIRK_HIDINPUT_FORCE;
 
 	/* Allocate and assign driver data */
 	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
@@ -385,6 +389,8 @@
 				USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
 				USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
+				USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 				USB_DEVICE_ID_UGEE_TABLET_G5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
--- linux-ein-5.4.0.orig/drivers/hid/hid-uclogic-params.c
+++ linux-ein-5.4.0/drivers/hid/hid-uclogic-params.c
@@ -65,7 +65,7 @@
 					__u8 idx, size_t len)
 {
 	int rc;
-	struct usb_device *udev = hid_to_usb_dev(hdev);
+	struct usb_device *udev;
 	__u8 *buf = NULL;
 
 	/* Check arguments */
@@ -74,6 +74,8 @@
 		goto cleanup;
 	}
 
+	udev = hid_to_usb_dev(hdev);
+
 	buf = kmalloc(len, GFP_KERNEL);
 	if (buf == NULL) {
 		rc = -ENOMEM;
@@ -449,7 +451,7 @@
 {
 	int rc;
 	bool found = false;
-	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
+	struct usb_device *usb_dev;
 	char *str_buf = NULL;
 	const size_t str_len = 16;
 
@@ -459,6 +461,8 @@
 		goto cleanup;
 	}
 
+	usb_dev = hid_to_usb_dev(hdev);
+
 	/*
 	 * Enable generic button mode
 	 */
@@ -705,9 +709,9 @@
 				     struct hid_device *hdev)
 {
 	int rc;
-	struct usb_device *udev = hid_to_usb_dev(hdev);
-	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
-	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_device *udev;
+	struct usb_interface *iface;
+	__u8 bInterfaceNumber;
 	bool found;
 	/* The resulting parameters (noop) */
 	struct uclogic_params p = {0, };
@@ -721,6 +725,10 @@
 		goto cleanup;
 	}
 
+	udev = hid_to_usb_dev(hdev);
+	iface = to_usb_interface(hdev->dev.parent);
+	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
+
 	/* If it's not a pen interface */
 	if (bInterfaceNumber != 0) {
 		/* TODO: Consider marking the interface invalid */
@@ -832,21 +840,25 @@
 			struct hid_device *hdev)
 {
 	int rc;
-	struct usb_device *udev = hid_to_usb_dev(hdev);
-	__u8  bNumInterfaces = udev->config->desc.bNumInterfaces;
-	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
-	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_device *udev;
+	__u8  bNumInterfaces;
+	struct usb_interface *iface;
+	__u8 bInterfaceNumber;
 	bool found;
 	/* The resulting parameters (noop) */
 	struct uclogic_params p = {0, };
 
 	/* Check arguments */
-	if (params == NULL || hdev == NULL ||
-	    !hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+	if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
 		rc = -EINVAL;
 		goto cleanup;
 	}
 
+	udev = hid_to_usb_dev(hdev);
+	bNumInterfaces = udev->config->desc.bNumInterfaces;
+	iface = to_usb_interface(hdev->dev.parent);
+	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
+
 	/*
 	 * Set replacement report descriptor if the original matches the
 	 * specified size. Otherwise keep interface unchanged.
@@ -997,6 +1009,8 @@
 		break;
 	case VID_PID(USB_VENDOR_ID_UGTIZER,
 		     USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
+	case VID_PID(USB_VENDOR_ID_UGTIZER,
+		     USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
 	case VID_PID(USB_VENDOR_ID_UGEE,
 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
 	case VID_PID(USB_VENDOR_ID_UGEE,
--- linux-ein-5.4.0.orig/drivers/hid/hidraw.c
+++ linux-ein-5.4.0/drivers/hid/hidraw.c
@@ -249,13 +249,14 @@
 static __poll_t hidraw_poll(struct file *file, poll_table *wait)
 {
 	struct hidraw_list *list = file->private_data;
+	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* hidraw is always writable */
 
 	poll_wait(file, &list->hidraw->wait, wait);
 	if (list->head != list->tail)
-		return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
+		mask |= EPOLLIN | EPOLLRDNORM;
 	if (!list->hidraw->exist)
-		return EPOLLERR | EPOLLHUP;
-	return 0;
+		mask |= EPOLLERR | EPOLLHUP;
+	return mask;
 }
 
 static int hidraw_open(struct inode *inode, struct file *file)
@@ -345,10 +346,13 @@
 	unsigned int minor = iminor(inode);
 	struct hidraw_list *list = file->private_data;
 	unsigned long flags;
+	int i;
 
 	mutex_lock(&minors_lock);
 
 	spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
+	for (i = list->tail; i < list->head; i++)
+		kfree(list->buffer[i].value);
 	list_del(&list->node);
 	spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
 	kfree(list);
--- linux-ein-5.4.0.orig/drivers/hid/i2c-hid/i2c-hid-core.c
+++ linux-ein-5.4.0/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -48,6 +48,10 @@
 #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
 #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET	BIT(1)
 #define I2C_HID_QUIRK_BOGUS_IRQ			BIT(4)
+#define I2C_HID_QUIRK_RESET_ON_RESUME		BIT(5)
+#define I2C_HID_QUIRK_BAD_INPUT_SIZE		BIT(6)
+#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET	BIT(7)
+
 
 /* flags */
 #define I2C_HID_STARTED		0
@@ -170,7 +174,21 @@
 		I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
 	{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
 		I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
+	{ I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15,
+		I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
+	{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118,
+		I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
+	{ USB_VENDOR_ID_ALPS_JP, HID_ANY_ID,
+		 I2C_HID_QUIRK_RESET_ON_RESUME },
+	{ I2C_VENDOR_ID_SYNAPTICS, I2C_PRODUCT_ID_SYNAPTICS_SYNA2393,
+		 I2C_HID_QUIRK_RESET_ON_RESUME },
+	{ USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720,
+		I2C_HID_QUIRK_BAD_INPUT_SIZE },
+	/*
+	 * Sending the wakeup after reset actually break ELAN touchscreen controller
+	 */
 	{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
+		 I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET |
 		 I2C_HID_QUIRK_BOGUS_IRQ },
 	{ 0, 0 }
 };
@@ -411,6 +429,19 @@
 		dev_err(&client->dev, "failed to change power setting.\n");
 
 set_pwr_exit:
+
+	/*
+	 * 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.
+	 * According to Goodix Windows even waits 60 ms after (other?)
+	 * PWR_ON requests. Testing has confirmed that several devices
+	 * will not work properly without a delay after a PWR_ON request.
+	 */
+	if (!ret && power_state == I2C_HID_PWR_ON)
+		msleep(60);
+
 	return ret;
 }
 
@@ -432,15 +463,6 @@
 	if (ret)
 		goto out_unlock;
 
-	/*
-	 * 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);
@@ -451,7 +473,8 @@
 	}
 
 	/* At least some SIS devices need this after reset */
-	ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+	if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
+		ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
 
 out_unlock:
 	mutex_unlock(&ihid->reset_lock);
@@ -493,9 +516,15 @@
 	}
 
 	if ((ret_size > size) || (ret_size < 2)) {
-		dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
-			__func__, size, ret_size);
-		return;
+		if (ihid->quirks & I2C_HID_QUIRK_BAD_INPUT_SIZE) {
+			ihid->inbuf[0] = size & 0xff;
+			ihid->inbuf[1] = size >> 8;
+			ret_size = size;
+		} else {
+			dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
+				__func__, size, ret_size);
+			return;
+		}
 	}
 
 	i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf);
@@ -593,6 +622,17 @@
 	if (report_type == HID_OUTPUT_REPORT)
 		return -EINVAL;
 
+	/*
+	 * In case of unnumbered reports the response from the device will
+	 * not have the report ID that the upper layers expect, so we need
+	 * to stash it the buffer ourselves and adjust the data size.
+	 */
+	if (!report_number) {
+		buf[0] = 0;
+		buf++;
+		count--;
+	}
+
 	/* +2 bytes to include the size of the reply in the query buffer */
 	ask_count = min(count + 2, (size_t)ihid->bufsize);
 
@@ -614,6 +654,9 @@
 	count = min(count, ret_count - 2);
 	memcpy(buf, ihid->rawbuf + 2, count);
 
+	if (!report_number)
+		count++;
+
 	return count;
 }
 
@@ -630,17 +673,19 @@
 
 	mutex_lock(&ihid->reset_lock);
 
-	if (report_id) {
-		buf++;
-		count--;
-	}
-
+	/*
+	 * Note that both numbered and unnumbered reports passed here
+	 * are supposed to have report ID stored in the 1st byte of the
+	 * buffer, so we strip it off unconditionally before passing payload
+	 * to i2c_hid_set_or_send_report which takes care of encoding
+	 * everything properly.
+	 */
 	ret = i2c_hid_set_or_send_report(client,
 				report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
-				report_id, buf, count, use_data);
+				report_id, buf + 1, count - 1, use_data);
 
-	if (report_id && ret >= 0)
-		ret++; /* add report_id to the number of transfered bytes */
+	if (ret >= 0)
+		ret++; /* add report_id to the number of transferred bytes */
 
 	mutex_unlock(&ihid->reset_lock);
 
@@ -1091,8 +1136,8 @@
 	hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
 	hid->product = le16_to_cpu(ihid->hdesc.wProductID);
 
-	snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
-		 client->name, hid->vendor, hid->product);
+	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",
+		 client->name, (u16)hid->vendor, (u16)hid->product);
 	strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
 
 	ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
@@ -1212,8 +1257,15 @@
 	 * solves "incomplete reports" on Raydium devices 2386:3118 and
 	 * 2386:4B33 and fixes various SIS touchscreens no longer sending
 	 * data after a suspend/resume.
+	 *
+	 * However some ALPS touchpads generate IRQ storm without reset, so
+	 * let's still reset them here.
 	 */
-	ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+	if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
+		ret = i2c_hid_hwreset(client);
+	else
+		ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+
 	if (ret)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
+++ linux-ein-5.4.0/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -342,6 +342,14 @@
 		.driver_data = (void *)&sipodev_desc
 	},
 	{
+		.ident = "Trekstor SURFBOOK E11B",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
 		.ident = "Direkt-Tek DTLAPY116-2",
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
@@ -366,6 +374,14 @@
 		.driver_data = (void *)&sipodev_desc
 	},
 	{
+		.ident = "Mediacom FlexBook edge 13",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook_edge13-M-FBE13"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
 		.ident = "Odys Winbook 13",
 		.matches = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"),
@@ -381,6 +397,22 @@
 		},
 		.driver_data = (void *)&sipodev_desc
 	},
+	{
+		.ident = "Schneider SCL142ALM",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SCHNEIDER"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SCL142ALM"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
+	{
+		.ident = "Vero K147",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"),
+		},
+		.driver_data = (void *)&sipodev_desc
+	},
 	{ }	/* Terminate list */
 };
 
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -24,7 +24,10 @@
 #define ICL_MOBILE_DEVICE_ID	0x34FC
 #define SPT_H_DEVICE_ID		0xA135
 #define CML_LP_DEVICE_ID	0x02FC
+#define CMP_H_DEVICE_ID		0x06FC
 #define EHL_Ax_DEVICE_ID	0x4BB3
+#define TGL_LP_DEVICE_ID	0xA0FC
+#define TGL_H_DEVICE_ID		0x43FC
 
 #define	REVISION_ID_CHT_A0	0x6
 #define	REVISION_ID_CHT_Ax_SI	0x0
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -34,7 +34,10 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CMP_H_DEVICE_ID)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, EHL_Ax_DEVICE_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_LP_DEVICE_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_H_DEVICE_ID)},
 	{0, }
 };
 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
@@ -480,6 +480,7 @@
 			    sizeof(ldr_xfer_query_resp));
 	if (rv < 0) {
 		client_data->flag_retry = true;
+		*fw_info = (struct shim_fw_info){};
 		return rv;
 	}
 
@@ -489,6 +490,7 @@
 			"data size %d is not equal to size of loader_xfer_query_response %zu\n",
 			rv, sizeof(struct loader_xfer_query_response));
 		client_data->flag_retry = true;
+		*fw_info = (struct shim_fw_info){};
 		return -EMSGSIZE;
 	}
 
@@ -654,21 +656,12 @@
 	 */
 	payload_max_size &= ~(L1_CACHE_BYTES - 1);
 
-	dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32);
+	dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL);
 	if (!dma_buf) {
 		client_data->flag_retry = true;
 		return -ENOMEM;
 	}
 
-	dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size,
-				     DMA_TO_DEVICE);
-	if (dma_mapping_error(devc, dma_buf_phy)) {
-		dev_err(cl_data_to_dev(client_data), "DMA map failed\n");
-		client_data->flag_retry = true;
-		rv = -ENOMEM;
-		goto end_err_dma_buf_release;
-	}
-
 	ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT;
 	ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA;
 	ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy;
@@ -688,14 +681,7 @@
 		ldr_xfer_dma_frag.fragment.size = fragment_size;
 		memcpy(dma_buf, &fw->data[fragment_offset], fragment_size);
 
-		dma_sync_single_for_device(devc, dma_buf_phy,
-					   payload_max_size,
-					   DMA_TO_DEVICE);
-
-		/*
-		 * Flush cache here because the dma_sync_single_for_device()
-		 * does not do for x86.
-		 */
+		/* Flush cache to be sure the data is in main memory. */
 		clflush_cache_range(dma_buf, payload_max_size);
 
 		dev_dbg(cl_data_to_dev(client_data),
@@ -718,15 +704,8 @@
 		fragment_offset += fragment_size;
 	}
 
-	dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
-	kfree(dma_buf);
-	return 0;
-
 end_err_resp_buf_release:
-	/* Free ISH buffer if not done already, in error case */
-	dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
-end_err_dma_buf_release:
-	kfree(dma_buf);
+	dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy);
 	return rv;
 }
 
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ishtp-hid.h
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ishtp-hid.h
@@ -110,7 +110,7 @@
  * @multi_packet_cnt:	Count of fragmented packet count
  *
  * This structure is used to store completion flags and per client data like
- * like report description, number of HID devices etc.
+ * report description, number of HID devices etc.
  */
 struct ishtp_cl_data {
 	/* completion flags */
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ishtp/client.c
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ishtp/client.c
@@ -626,13 +626,14 @@
 }
 
 /**
- * ipc_tx_callback() - IPC tx callback function
+ * ipc_tx_send() - IPC tx send function
  * @prm: Pointer to client device instance
  *
- * Send message over IPC either first time or on callback on previous message
- * completion
+ * Send message over IPC. Message will be split into fragments
+ * if message size is bigger than IPC FIFO size, and all
+ * fragments will be sent one by one.
  */
-static void ipc_tx_callback(void *prm)
+static void ipc_tx_send(void *prm)
 {
 	struct ishtp_cl	*cl = prm;
 	struct ishtp_cl_tx_ring	*cl_msg;
@@ -677,32 +678,41 @@
 			    list);
 	rem = cl_msg->send_buf.size - cl->tx_offs;
 
-	ishtp_hdr.host_addr = cl->host_client_id;
-	ishtp_hdr.fw_addr = cl->fw_client_id;
-	ishtp_hdr.reserved = 0;
-	pmsg = cl_msg->send_buf.data + cl->tx_offs;
-
-	if (rem <= dev->mtu) {
-		ishtp_hdr.length = rem;
-		ishtp_hdr.msg_complete = 1;
-		cl->sending = 0;
-		list_del_init(&cl_msg->list);	/* Must be before write */
-		spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
-		/* Submit to IPC queue with no callback */
-		ishtp_write_message(dev, &ishtp_hdr, pmsg);
-		spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
-		list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
-		++cl->tx_ring_free_size;
-		spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
-			tx_free_flags);
-	} else {
-		/* Send IPC fragment */
-		spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
-		cl->tx_offs += dev->mtu;
-		ishtp_hdr.length = dev->mtu;
-		ishtp_hdr.msg_complete = 0;
-		ishtp_send_msg(dev, &ishtp_hdr, pmsg, ipc_tx_callback, cl);
+	while (rem > 0) {
+		ishtp_hdr.host_addr = cl->host_client_id;
+		ishtp_hdr.fw_addr = cl->fw_client_id;
+		ishtp_hdr.reserved = 0;
+		pmsg = cl_msg->send_buf.data + cl->tx_offs;
+
+		if (rem <= dev->mtu) {
+			/* Last fragment or only one packet */
+			ishtp_hdr.length = rem;
+			ishtp_hdr.msg_complete = 1;
+			/* Submit to IPC queue with no callback */
+			ishtp_write_message(dev, &ishtp_hdr, pmsg);
+			cl->tx_offs = 0;
+			cl->sending = 0;
+
+			break;
+		} else {
+			/* Send ipc fragment */
+			ishtp_hdr.length = dev->mtu;
+			ishtp_hdr.msg_complete = 0;
+			/* All fregments submitted to IPC queue with no callback */
+			ishtp_write_message(dev, &ishtp_hdr, pmsg);
+			cl->tx_offs += dev->mtu;
+			rem = cl_msg->send_buf.size - cl->tx_offs;
+		}
 	}
+
+	list_del_init(&cl_msg->list);
+	spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+
+	spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+	list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+	++cl->tx_ring_free_size;
+	spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
+		tx_free_flags);
 }
 
 /**
@@ -720,7 +730,7 @@
 		return;
 
 	cl->tx_offs = 0;
-	ipc_tx_callback(cl);
+	ipc_tx_send(cl);
 	++cl->send_msg_cnt_ipc;
 }
 
--- linux-ein-5.4.0.orig/drivers/hid/intel-ish-hid/ishtp/dma-if.c
+++ linux-ein-5.4.0/drivers/hid/intel-ish-hid/ishtp/dma-if.c
@@ -104,6 +104,11 @@
 	int required_slots = (size / DMA_SLOT_SIZE)
 		+ 1 * (size % DMA_SLOT_SIZE != 0);
 
+	if (!dev->ishtp_dma_tx_map) {
+		dev_err(dev->devc, "Fail to allocate Tx map\n");
+		return NULL;
+	}
+
 	spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
 	for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) {
 		free = 1;
@@ -150,6 +155,11 @@
 		return;
 	}
 
+	if (!dev->ishtp_dma_tx_map) {
+		dev_err(dev->devc, "Fail to allocate Tx map\n");
+		return;
+	}
+
 	i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE;
 	spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
 	for (j = 0; j < acked_slots; j++) {
--- linux-ein-5.4.0.orig/drivers/hid/uhid.c
+++ linux-ein-5.4.0/drivers/hid/uhid.c
@@ -28,11 +28,22 @@
 
 struct uhid_device {
 	struct mutex devlock;
+
+	/* This flag tracks whether the HID device is usable for commands from
+	 * userspace. The flag is already set before hid_add_device(), which
+	 * runs in workqueue context, to allow hid_add_device() to communicate
+	 * with userspace.
+	 * However, if hid_add_device() fails, the flag is cleared without
+	 * holding devlock.
+	 * We guarantee that if @running changes from true to false while you're
+	 * holding @devlock, it's still fine to access @hid.
+	 */
 	bool running;
 
 	__u8 *rd_data;
 	uint rd_size;
 
+	/* When this is NULL, userspace may use UHID_CREATE/UHID_CREATE2. */
 	struct hid_device *hid;
 	struct uhid_event input_buf;
 
@@ -63,9 +74,18 @@
 	if (ret) {
 		hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
 
-		hid_destroy_device(uhid->hid);
-		uhid->hid = NULL;
+		/* We used to call hid_destroy_device() here, but that's really
+		 * messy to get right because we have to coordinate with
+		 * concurrent writes from userspace that might be in the middle
+		 * of using uhid->hid.
+		 * Just leave uhid->hid as-is for now, and clean it up when
+		 * userspace tries to close or reinitialize the uhid instance.
+		 *
+		 * However, we do have to clear the ->running flag and do a
+		 * wakeup to make sure userspace knows that the device is gone.
+		 */
 		uhid->running = false;
+		wake_up_interruptible(&uhid->report_wait);
 	}
 }
 
@@ -375,6 +395,7 @@
 	.parse = uhid_hid_parse,
 	.raw_request = uhid_hid_raw_request,
 	.output_report = uhid_hid_output_report,
+	.max_buffer_size = UHID_DATA_MAX,
 };
 EXPORT_SYMBOL_GPL(uhid_hid_driver);
 
@@ -474,7 +495,7 @@
 	void *rd_data;
 	int ret;
 
-	if (uhid->running)
+	if (uhid->hid)
 		return -EALREADY;
 
 	rd_size = ev->u.create2.rd_size;
@@ -556,7 +577,7 @@
 
 static int uhid_dev_destroy(struct uhid_device *uhid)
 {
-	if (!uhid->running)
+	if (!uhid->hid)
 		return -EINVAL;
 
 	uhid->running = false;
@@ -565,6 +586,7 @@
 	cancel_work_sync(&uhid->worker);
 
 	hid_destroy_device(uhid->hid);
+	uhid->hid = NULL;
 	kfree(uhid->rd_data);
 
 	return 0;
@@ -766,13 +788,14 @@
 static __poll_t uhid_char_poll(struct file *file, poll_table *wait)
 {
 	struct uhid_device *uhid = file->private_data;
+	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* uhid is always writable */
 
 	poll_wait(file, &uhid->waitq, wait);
 
 	if (uhid->head != uhid->tail)
-		return EPOLLIN | EPOLLRDNORM;
+		mask |= EPOLLIN | EPOLLRDNORM;
 
-	return 0;
+	return mask;
 }
 
 static const struct file_operations uhid_fops = {
--- linux-ein-5.4.0.orig/drivers/hid/usbhid/hid-core.c
+++ linux-ein-5.4.0/drivers/hid/usbhid/hid-core.c
@@ -374,7 +374,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;
@@ -503,7 +503,7 @@
 
 	if (unplug) {
 		usbhid->ctrltail = usbhid->ctrlhead;
-	} else {
+	} else if (usbhid->ctrlhead != usbhid->ctrltail) {
 		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
 		if (usbhid->ctrlhead != usbhid->ctrltail &&
@@ -682,16 +682,21 @@
 	struct usbhid_device *usbhid = hid->driver_data;
 	int res;
 
+	mutex_lock(&usbhid->mutex);
+
 	set_bit(HID_OPENED, &usbhid->iofl);
 
-	if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
-		return 0;
+	if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
+		res = 0;
+		goto Done;
+	}
 
 	res = usb_autopm_get_interface(usbhid->intf);
 	/* the device must be awake to reliably request remote wakeup */
 	if (res < 0) {
 		clear_bit(HID_OPENED, &usbhid->iofl);
-		return -EIO;
+		res = -EIO;
+		goto Done;
 	}
 
 	usbhid->intf->needs_remote_wakeup = 1;
@@ -725,6 +730,9 @@
 		msleep(50);
 
 	clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
+
+ Done:
+	mutex_unlock(&usbhid->mutex);
 	return res;
 }
 
@@ -732,6 +740,8 @@
 {
 	struct usbhid_device *usbhid = hid->driver_data;
 
+	mutex_lock(&usbhid->mutex);
+
 	/*
 	 * Make sure we don't restart data acquisition due to
 	 * a resumption we no longer care about by avoiding racing
@@ -743,12 +753,13 @@
 		clear_bit(HID_IN_POLLING, &usbhid->iofl);
 	spin_unlock_irq(&usbhid->lock);
 
-	if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
-		return;
+	if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) {
+		hid_cancel_delayed_stuff(usbhid);
+		usb_kill_urb(usbhid->urbin);
+		usbhid->intf->needs_remote_wakeup = 0;
+	}
 
-	hid_cancel_delayed_stuff(usbhid);
-	usb_kill_urb(usbhid->urbin);
-	usbhid->intf->needs_remote_wakeup = 0;
+	mutex_unlock(&usbhid->mutex);
 }
 
 /*
@@ -1057,6 +1068,8 @@
 	unsigned int n, insize = 0;
 	int ret;
 
+	mutex_lock(&usbhid->mutex);
+
 	clear_bit(HID_DISCONNECTED, &usbhid->iofl);
 
 	usbhid->bufsize = HID_MIN_BUFFER_SIZE;
@@ -1177,6 +1190,8 @@
 		usbhid_set_leds(hid);
 		device_set_wakeup_enable(&dev->dev, 1);
 	}
+
+	mutex_unlock(&usbhid->mutex);
 	return 0;
 
 fail:
@@ -1187,6 +1202,7 @@
 	usbhid->urbout = NULL;
 	usbhid->urbctrl = NULL;
 	hid_free_buffers(dev, hid);
+	mutex_unlock(&usbhid->mutex);
 	return ret;
 }
 
@@ -1202,10 +1218,23 @@
 		usbhid->intf->needs_remote_wakeup = 0;
 	}
 
+	mutex_lock(&usbhid->mutex);
+
 	clear_bit(HID_STARTED, &usbhid->iofl);
+
 	spin_lock_irq(&usbhid->lock);	/* Sync with error and led handlers */
 	set_bit(HID_DISCONNECTED, &usbhid->iofl);
+	while (usbhid->ctrltail != usbhid->ctrlhead) {
+		if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) {
+			kfree(usbhid->ctrl[usbhid->ctrltail].raw_report);
+			usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
+		}
+
+		usbhid->ctrltail = (usbhid->ctrltail + 1) &
+			(HID_CONTROL_FIFO_SIZE - 1);
+	}
 	spin_unlock_irq(&usbhid->lock);
+
 	usb_kill_urb(usbhid->urbin);
 	usb_kill_urb(usbhid->urbout);
 	usb_kill_urb(usbhid->urbctrl);
@@ -1222,6 +1251,8 @@
 	usbhid->urbout = NULL;
 
 	hid_free_buffers(hid_to_usb_dev(hid), hid);
+
+	mutex_unlock(&usbhid->mutex);
 }
 
 static int usbhid_power(struct hid_device *hid, int lvl)
@@ -1382,6 +1413,7 @@
 	INIT_WORK(&usbhid->reset_work, hid_reset);
 	timer_setup(&usbhid->io_retry, hid_retry_timeout, 0);
 	spin_lock_init(&usbhid->lock);
+	mutex_init(&usbhid->mutex);
 
 	ret = hid_add_device(hid);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/hid/usbhid/hid-pidff.c
+++ linux-ein-5.4.0/drivers/hid/usbhid/hid-pidff.c
@@ -1292,6 +1292,7 @@
 
 	if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
 	    pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
+		error = -EPERM;
 		hid_notice(hid,
 			   "device does not support device managed pool\n");
 		goto fail;
--- linux-ein-5.4.0.orig/drivers/hid/usbhid/hiddev.c
+++ linux-ein-5.4.0/drivers/hid/usbhid/hiddev.c
@@ -241,12 +241,51 @@
 	return 0;
 }
 
+static int __hiddev_open(struct hiddev *hiddev, struct file *file)
+{
+	struct hiddev_list *list;
+	int error;
+
+	lockdep_assert_held(&hiddev->existancelock);
+
+	list = vzalloc(sizeof(*list));
+	if (!list)
+		return -ENOMEM;
+
+	mutex_init(&list->thread_lock);
+	list->hiddev = hiddev;
+
+	if (!hiddev->open++) {
+		error = hid_hw_power(hiddev->hid, PM_HINT_FULLON);
+		if (error < 0)
+			goto err_drop_count;
+
+		error = hid_hw_open(hiddev->hid);
+		if (error < 0)
+			goto err_normal_power;
+	}
+
+	spin_lock_irq(&hiddev->list_lock);
+	list_add_tail(&list->node, &hiddev->list);
+	spin_unlock_irq(&hiddev->list_lock);
+
+	file->private_data = list;
+
+	return 0;
+
+err_normal_power:
+	hid_hw_power(hiddev->hid, PM_HINT_NORMAL);
+err_drop_count:
+	hiddev->open--;
+	vfree(list);
+	return error;
+}
+
 /*
  * open file op
  */
 static int hiddev_open(struct inode *inode, struct file *file)
 {
-	struct hiddev_list *list;
 	struct usb_interface *intf;
 	struct hid_device *hid;
 	struct hiddev *hiddev;
@@ -255,66 +294,14 @@
 	intf = usbhid_find_interface(iminor(inode));
 	if (!intf)
 		return -ENODEV;
+
 	hid = usb_get_intfdata(intf);
 	hiddev = hid->hiddev;
 
-	if (!(list = vzalloc(sizeof(struct hiddev_list))))
-		return -ENOMEM;
-	mutex_init(&list->thread_lock);
-	list->hiddev = hiddev;
-	file->private_data = list;
-
-	/*
-	 * no need for locking because the USB major number
-	 * is shared which usbcore guards against disconnect
-	 */
-	if (list->hiddev->exist) {
-		if (!list->hiddev->open++) {
-			res = hid_hw_open(hiddev->hid);
-			if (res < 0)
-				goto bail;
-		}
-	} else {
-		res = -ENODEV;
-		goto bail;
-	}
-
-	spin_lock_irq(&list->hiddev->list_lock);
-	list_add_tail(&list->node, &hiddev->list);
-	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;
-			res = hid_hw_power(hid, PM_HINT_FULLON);
-			if (res < 0)
-				goto bail_unlock;
-			res = hid_hw_open(hid);
-			if (res < 0)
-				goto bail_normal_power;
-		}
-	mutex_unlock(&hiddev->existancelock);
-	return 0;
-bail_normal_power:
-	hid_hw_power(hid, PM_HINT_NORMAL);
-bail_unlock:
+	res = hiddev->exist ? __hiddev_open(hiddev, file) : -ENODEV;
 	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);
 	return res;
 }
 
@@ -532,12 +519,16 @@
 
 		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;
 
@@ -954,9 +945,9 @@
 	hiddev->exist = 0;
 
 	if (hiddev->open) {
-		mutex_unlock(&hiddev->existancelock);
 		hid_hw_close(hiddev->hid);
 		wake_up_interruptible(&hiddev->wait);
+		mutex_unlock(&hiddev->existancelock);
 	} else {
 		mutex_unlock(&hiddev->existancelock);
 		kfree(hiddev);
--- linux-ein-5.4.0.orig/drivers/hid/usbhid/usbhid.h
+++ linux-ein-5.4.0/drivers/hid/usbhid/usbhid.h
@@ -80,6 +80,7 @@
 	dma_addr_t outbuf_dma;                                          /* Output buffer dma */
 	unsigned long last_out;							/* record of last output for timeouts */
 
+	struct mutex mutex;						/* start/stop/open/close */
 	spinlock_t lock;						/* fifo spinlock */
 	unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
 	struct timer_list io_retry;                                     /* Retry timer */
--- linux-ein-5.4.0.orig/drivers/hid/wacom.h
+++ linux-ein-5.4.0/drivers/hid/wacom.h
@@ -91,6 +91,7 @@
 #include <linux/leds.h>
 #include <linux/usb/input.h>
 #include <linux/power_supply.h>
+#include <linux/timer.h>
 #include <asm/unaligned.h>
 
 /*
@@ -152,6 +153,7 @@
 		struct input_dev *input;
 		bool registered;
 		struct wacom_battery battery;
+		ktime_t active_time;
 	} remotes[WACOM_MAX_REMOTES];
 };
 
@@ -167,6 +169,7 @@
 	struct delayed_work init_work;
 	struct wacom_remote *remote;
 	struct work_struct mode_change_work;
+	struct timer_list idleprox_timer;
 	bool generic_has_leds;
 	struct wacom_leds {
 		struct wacom_group_leds *groups;
@@ -239,4 +242,5 @@
 struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
 int wacom_equivalent_usage(int usage);
 int wacom_initialize_leds(struct wacom *wacom);
+void wacom_idleprox_timeout(struct timer_list *list);
 #endif
--- linux-ein-5.4.0.orig/drivers/hid/wacom_sys.c
+++ linux-ein-5.4.0/drivers/hid/wacom_sys.c
@@ -147,9 +147,9 @@
 	}
 
 	if (flush)
-		wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
+		wacom_wac_queue_flush(hdev, wacom_wac->pen_fifo);
 	else if (insert)
-		wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo,
+		wacom_wac_queue_insert(hdev, wacom_wac->pen_fifo,
 				       raw_data, report_size);
 
 	return insert && !flush;
@@ -160,6 +160,9 @@
 {
 	struct wacom *wacom = hid_get_drvdata(hdev);
 
+	if (wacom->wacom_wac.features.type == BOOTLOADER)
+		return 0;
+
 	if (size > WACOM_PKGLEN_MAX)
 		return 1;
 
@@ -319,9 +322,11 @@
 			data[0] = field->report->id;
 			ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
 					       data, n, WAC_CMD_RETRIES);
-			if (ret == n) {
+			if (ret == n && features->type == HID_GENERIC) {
 				ret = hid_report_raw_event(hdev,
 					HID_FEATURE_REPORT, data, n, 0);
+			} else if (ret == 2 && features->type != HID_GENERIC) {
+				features->touch_max = data[1];
 			} else {
 				features->touch_max = 16;
 				hid_warn(hdev, "wacom_feature_mapping: "
@@ -724,7 +729,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
@@ -1268,6 +1273,38 @@
 					       group);
 }
 
+static void wacom_devm_kfifo_release(struct device *dev, void *res)
+{
+	struct kfifo_rec_ptr_2 *devres = res;
+
+	kfifo_free(devres);
+}
+
+static int wacom_devm_kfifo_alloc(struct wacom *wacom)
+{
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+	struct kfifo_rec_ptr_2 *pen_fifo;
+	int error;
+
+	pen_fifo = devres_alloc(wacom_devm_kfifo_release,
+			      sizeof(struct kfifo_rec_ptr_2),
+			      GFP_KERNEL);
+
+	if (!pen_fifo)
+		return -ENOMEM;
+
+	error = kfifo_alloc(pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
+	if (error) {
+		devres_free(pen_fifo);
+		return error;
+	}
+
+	devres_add(&wacom->hdev->dev, pen_fifo);
+	wacom_wac->pen_fifo = pen_fifo;
+
+	return 0;
+}
+
 enum led_brightness wacom_leds_brightness_get(struct wacom_led *led)
 {
 	struct wacom *wacom = led->wacom;
@@ -2051,7 +2088,7 @@
 	return 0;
 }
 
-static int wacom_register_inputs(struct wacom *wacom)
+static int wacom_setup_inputs(struct wacom *wacom)
 {
 	struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
 	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
@@ -2070,10 +2107,6 @@
 		input_free_device(pen_input_dev);
 		wacom_wac->pen_input = NULL;
 		pen_input_dev = NULL;
-	} else {
-		error = input_register_device(pen_input_dev);
-		if (error)
-			goto fail;
 	}
 
 	error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac);
@@ -2082,19 +2115,42 @@
 		input_free_device(touch_input_dev);
 		wacom_wac->touch_input = NULL;
 		touch_input_dev = NULL;
-	} else {
-		error = input_register_device(touch_input_dev);
-		if (error)
-			goto fail;
 	}
 
 	error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
 	if (error) {
-		/* no pad in use on this interface */
+		/* no pad events using this interface */
 		input_free_device(pad_input_dev);
 		wacom_wac->pad_input = NULL;
 		pad_input_dev = NULL;
-	} else {
+	}
+
+	return 0;
+}
+
+static int wacom_register_inputs(struct wacom *wacom)
+{
+	struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
+	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+	int error = 0;
+
+	pen_input_dev = wacom_wac->pen_input;
+	touch_input_dev = wacom_wac->touch_input;
+	pad_input_dev = wacom_wac->pad_input;
+
+	if (pen_input_dev) {
+		error = input_register_device(pen_input_dev);
+		if (error)
+			goto fail;
+	}
+
+	if (touch_input_dev) {
+		error = input_register_device(touch_input_dev);
+		if (error)
+			goto fail;
+	}
+
+	if (pad_input_dev) {
 		error = input_register_device(pad_input_dev);
 		if (error)
 			goto fail;
@@ -2183,7 +2239,7 @@
 	if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
 		char *product_name = wacom->hdev->name;
 
-		if (hid_is_using_ll_driver(wacom->hdev, &usb_hid_driver)) {
+		if (hid_is_usb(wacom->hdev)) {
 			struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
 			struct usb_device *dev = interface_to_usbdev(intf);
 			product_name = dev->product;
@@ -2344,6 +2400,20 @@
 			goto fail;
 	}
 
+	error = wacom_setup_inputs(wacom);
+	if (error)
+		goto fail;
+
+	if (features->type == HID_GENERIC)
+		connect_mask |= HID_CONNECT_DRIVER;
+
+	/* Regular HID work starts now */
+	error = hid_hw_start(hdev, connect_mask);
+	if (error) {
+		hid_err(hdev, "hw start failed\n");
+		goto fail;
+	}
+
 	error = wacom_register_inputs(wacom);
 	if (error)
 		goto fail;
@@ -2358,16 +2428,6 @@
 			goto fail;
 	}
 
-	if (features->type == HID_GENERIC)
-		connect_mask |= HID_CONNECT_DRIVER;
-
-	/* Regular HID work starts now */
-	error = hid_hw_start(hdev, connect_mask);
-	if (error) {
-		hid_err(hdev, "hw start failed\n");
-		goto fail;
-	}
-
 	if (!wireless) {
 		/* Note that if query fails it is not a hard failure */
 		wacom_query_tablet_data(wacom);
@@ -2382,8 +2442,13 @@
 		goto fail_quirks;
 	}
 
-	if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
+	if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) {
 		error = hid_hw_open(hdev);
+		if (error) {
+			hid_err(hdev, "hw open failed\n");
+			goto fail_quirks;
+		}
+	}
 
 	wacom_set_shared_values(wacom_wac);
 	devres_close_group(&hdev->dev, wacom);
@@ -2414,6 +2479,9 @@
 
 	wacom_destroy_battery(wacom);
 
+	if (!usbdev)
+		return;
+
 	/* Stylus interface */
 	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
 	wacom1 = hid_get_drvdata(hdev1);
@@ -2484,6 +2552,18 @@
 	return;
 }
 
+static void wacom_remote_destroy_battery(struct wacom *wacom, int index)
+{
+	struct wacom_remote *remote = wacom->remote;
+
+	if (remote->remotes[index].battery.battery) {
+		devres_release_group(&wacom->hdev->dev,
+				     &remote->remotes[index].battery.bat_desc);
+		remote->remotes[index].battery.battery = NULL;
+		remote->remotes[index].active_time = 0;
+	}
+}
+
 static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
 {
 	struct wacom_remote *remote = wacom->remote;
@@ -2498,9 +2578,7 @@
 			remote->remotes[i].registered = false;
 			spin_unlock_irqrestore(&remote->remote_lock, flags);
 
-			if (remote->remotes[i].battery.battery)
-				devres_release_group(&wacom->hdev->dev,
-						     &remote->remotes[i].battery.bat_desc);
+			wacom_remote_destroy_battery(wacom, i);
 
 			if (remote->remotes[i].group.name)
 				devres_release_group(&wacom->hdev->dev,
@@ -2508,7 +2586,6 @@
 
 			remote->remotes[i].serial = 0;
 			remote->remotes[i].group.name = NULL;
-			remote->remotes[i].battery.battery = NULL;
 			wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
 		}
 	}
@@ -2593,6 +2670,9 @@
 	if (remote->remotes[index].battery.battery)
 		return 0;
 
+	if (!remote->remotes[index].active_time)
+		return 0;
+
 	if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
 		return 0;
 
@@ -2608,6 +2688,7 @@
 {
 	struct wacom *wacom = container_of(work, struct wacom, remote_work);
 	struct wacom_remote *remote = wacom->remote;
+	ktime_t kt = ktime_get();
 	struct wacom_remote_data data;
 	unsigned long flags;
 	unsigned int count;
@@ -2634,6 +2715,10 @@
 		serial = data.remote[i].serial;
 		if (data.remote[i].connected) {
 
+			if (kt - remote->remotes[i].active_time > WACOM_REMOTE_BATTERY_TIMEOUT
+			    && remote->remotes[i].active_time != 0)
+				wacom_remote_destroy_battery(wacom, i);
+
 			if (remote->remotes[i].serial == serial) {
 				wacom_remote_attach_battery(wacom, i);
 				continue;
@@ -2693,8 +2778,6 @@
 static int wacom_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
-	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;
@@ -2722,21 +2805,28 @@
 	if (features->check_for_hid_type && features->hid_type != hdev->type)
 		return -ENODEV;
 
-	error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
+	error = wacom_devm_kfifo_alloc(wacom);
 	if (error)
 		return error;
 
 	wacom_wac->hid_data.inputmode = -1;
 	wacom_wac->mode_report = -1;
 
-	wacom->usbdev = dev;
-	wacom->intf = intf;
+	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_DELAYED_WORK(&wacom->init_work, wacom_init_work);
 	INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
 	INIT_WORK(&wacom->battery_work, wacom_battery_work);
 	INIT_WORK(&wacom->remote_work, wacom_remote_work);
 	INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
+	timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE);
 
 	/* ask for the report descriptor to be loaded by HID */
 	error = hid_parse(hdev);
@@ -2745,6 +2835,11 @@
 		return error;
 	}
 
+	if (features->type == BOOTLOADER) {
+		hid_warn(hdev, "Using device in hidraw-only mode");
+		return hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+	}
+
 	error = wacom_parse_and_register(wacom, false);
 	if (error)
 		return error;
@@ -2776,6 +2871,7 @@
 	cancel_work_sync(&wacom->battery_work);
 	cancel_work_sync(&wacom->remote_work);
 	cancel_work_sync(&wacom->mode_change_work);
+	del_timer_sync(&wacom->idleprox_timer);
 	if (hdev->bus == BUS_BLUETOOTH)
 		device_remove_file(&hdev->dev, &dev_attr_speed);
 
@@ -2784,8 +2880,6 @@
 
 	if (wacom->wacom_wac.features.type != REMOTE)
 		wacom_release_resources(wacom);
-
-	kfifo_free(&wacom_wac->pen_fifo);
 }
 
 #ifdef CONFIG_PM
--- linux-ein-5.4.0.orig/drivers/hid/wacom_wac.c
+++ linux-ein-5.4.0/drivers/hid/wacom_wac.c
@@ -11,6 +11,7 @@
 #include "wacom_wac.h"
 #include "wacom.h"
 #include <linux/input/mt.h>
+#include <linux/jiffies.h>
 
 /* resolution for penabled devices */
 #define WACOM_PL_RES		20
@@ -41,6 +42,43 @@
 
 static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
 			     int group);
+
+static void wacom_force_proxout(struct wacom_wac *wacom_wac)
+{
+	struct input_dev *input = wacom_wac->pen_input;
+
+	wacom_wac->shared->stylus_in_proximity = 0;
+
+	input_report_key(input, BTN_TOUCH, 0);
+	input_report_key(input, BTN_STYLUS, 0);
+	input_report_key(input, BTN_STYLUS2, 0);
+	input_report_key(input, BTN_STYLUS3, 0);
+	input_report_key(input, wacom_wac->tool[0], 0);
+	if (wacom_wac->serial[0]) {
+		input_report_abs(input, ABS_MISC, 0);
+	}
+	input_report_abs(input, ABS_PRESSURE, 0);
+
+	wacom_wac->tool[0] = 0;
+	wacom_wac->id[0] = 0;
+	wacom_wac->serial[0] = 0;
+
+	input_sync(input);
+}
+
+void wacom_idleprox_timeout(struct timer_list *list)
+{
+	struct wacom *wacom = from_timer(wacom, list, idleprox_timer);
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+	if (!wacom_wac->hid_data.sense_state) {
+		return;
+	}
+
+	hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__);
+	wacom_force_proxout(wacom_wac);
+}
+
 /*
  * Percent of battery capacity for Graphire.
  * 8th value means AC online and show 100% capacity.
@@ -638,9 +676,26 @@
 	return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF);
 }
 
+static bool wacom_is_art_pen(int tool_id)
+{
+	bool is_art_pen = false;
+
+	switch (tool_id) {
+	case 0x885:	/* Intuos3 Marker Pen */
+	case 0x804:	/* Intuos4/5 13HD/24HD Marker Pen */
+	case 0x10804:	/* Intuos4/5 13HD/24HD Art Pen */
+		is_art_pen = true;
+		break;
+	}
+	return is_art_pen;
+}
+
 static int wacom_intuos_get_tool_type(int tool_id)
 {
-	int tool_type;
+	int tool_type = BTN_TOOL_PEN;
+
+	if (wacom_is_art_pen(tool_id))
+		return tool_type;
 
 	switch (tool_id) {
 	case 0x812: /* Inking pen */
@@ -655,17 +710,17 @@
 	case 0x852:
 	case 0x823: /* Intuos3 Grip Pen */
 	case 0x813: /* Intuos3 Classic Pen */
-	case 0x885: /* Intuos3 Marker Pen */
 	case 0x802: /* Intuos4/5 13HD/24HD General Pen */
-	case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
 	case 0x8e2: /* IntuosHT2 pen */
 	case 0x022:
-	case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */
+	case 0x200: /* Pro Pen 3 */
+	case 0x04200: /* Pro Pen 3 */
 	case 0x10842: /* MobileStudio Pro Pro Pen slim */
 	case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */
 	case 0x16802: /* Cintiq 13HD Pro Pen */
 	case 0x18802: /* DTH2242 Pen */
 	case 0x10802: /* Intuos4/5 13HD/24HD General Pen */
+	case 0x80842: /* Intuos Pro and Cintiq Pro 3D Pen */
 		tool_type = BTN_TOOL_PEN;
 		break;
 
@@ -718,10 +773,6 @@
 	case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */
 		tool_type = BTN_TOOL_AIRBRUSH;
 		break;
-
-	default: /* Unknown tool */
-		tool_type = BTN_TOOL_PEN;
-		break;
 	}
 	return tool_type;
 }
@@ -780,7 +831,7 @@
 	/* Enter report */
 	if ((data[1] & 0xfc) == 0xc0) {
 		/* serial number of the tool */
-		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+		wacom->serial[idx] = ((__u64)(data[3] & 0x0f) << 28) +
 			(data[4] << 20) + (data[5] << 12) +
 			(data[6] << 4) + (data[7] >> 4);
 
@@ -1076,6 +1127,7 @@
 	if (index < 0 || !remote->remotes[index].registered)
 		goto out;
 
+	remote->remotes[i].active_time = ktime_get();
 	input = remote->remotes[index].input;
 
 	input_report_key(input, BTN_0, (data[9] & 0x01));
@@ -1255,6 +1307,9 @@
 
 	struct input_dev *pen_input = wacom->pen_input;
 	unsigned char *data = wacom->data;
+	int number_of_valid_frames = 0;
+	ktime_t time_interval = 15000000;
+	ktime_t time_packet_received = ktime_get();
 	int i;
 
 	if (wacom->features.type == INTUOSP2_BT ||
@@ -1275,12 +1330,30 @@
 		wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
 	}
 
+	/* number of valid frames */
 	for (i = 0; i < pen_frames; i++) {
 		unsigned char *frame = &data[i*pen_frame_len + 1];
 		bool valid = frame[0] & 0x80;
+
+		if (valid)
+			number_of_valid_frames++;
+	}
+
+	if (number_of_valid_frames) {
+		if (wacom->hid_data.time_delayed)
+			time_interval = ktime_get() - wacom->hid_data.time_delayed;
+		time_interval = div_u64(time_interval, number_of_valid_frames);
+		wacom->hid_data.time_delayed = time_packet_received;
+	}
+
+	for (i = 0; i < number_of_valid_frames; i++) {
+		unsigned char *frame = &data[i*pen_frame_len + 1];
+		bool valid = frame[0] & 0x80;
 		bool prox = frame[0] & 0x40;
 		bool range = frame[0] & 0x20;
 		bool invert = frame[0] & 0x10;
+		int frames_number_reversed = number_of_valid_frames - i - 1;
+		ktime_t event_timestamp = time_packet_received - frames_number_reversed * time_interval;
 
 		if (!valid)
 			continue;
@@ -1293,6 +1366,7 @@
 			wacom->tool[0] = 0;
 			wacom->id[0] = 0;
 			wacom->serial[0] = 0;
+			wacom->hid_data.time_delayed = 0;
 			return;
 		}
 
@@ -1329,6 +1403,7 @@
 						 get_unaligned_le16(&frame[11]));
 			}
 		}
+
 		if (wacom->tool[0]) {
 			input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
 			if (wacom->features.type == INTUOSP2_BT ||
@@ -1352,6 +1427,9 @@
 
 		wacom->shared->stylus_in_proximity = prox;
 
+		/* add timestamp to unpack the frames */
+		input_set_timestamp(pen_input, event_timestamp);
+
 		input_sync(pen_input);
 	}
 }
@@ -1427,11 +1505,13 @@
 {
 	struct input_dev *pad_input = wacom->pad_input;
 	unsigned char *data = wacom->data;
+	int nbuttons = wacom->features.numbered_buttons;
 
-	int buttons = data[282] | ((data[281] & 0x40) << 2);
+	int expresskeys = data[282];
+	int center = (data[281] & 0x40) >> 6;
 	int ring = data[285] & 0x7F;
 	bool ringstatus = data[285] & 0x80;
-	bool prox = buttons || ringstatus;
+	bool prox = expresskeys || center || ringstatus;
 
 	/* Fix touchring data: userspace expects 0 at left and increasing clockwise */
 	ring = 71 - ring;
@@ -1439,7 +1519,8 @@
 	if (ring > 71)
 		ring -= 72;
 
-	wacom_report_numbered_buttons(pad_input, 9, buttons);
+	wacom_report_numbered_buttons(pad_input, nbuttons,
+                                      expresskeys | (center << (nbuttons - 1)));
 
 	input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
 
@@ -1840,6 +1921,7 @@
 	int fmax = field->logical_maximum;
 	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
 	int resolution_code = code;
+	int resolution = hidinput_calc_abs_res(field, resolution_code);
 
 	if (equivalent_usage == HID_DG_TWIST) {
 		resolution_code = ABS_RZ;
@@ -1862,8 +1944,15 @@
 	switch (type) {
 	case EV_ABS:
 		input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
-		input_abs_set_res(input, code,
-				  hidinput_calc_abs_res(field, resolution_code));
+
+		/* older tablet may miss physical usage */
+		if ((code == ABS_X || code == ABS_Y) && !resolution) {
+			resolution = WACOM_INTUOS_RES;
+			hid_warn(input,
+				 "Wacom usage (%d) missing resolution \n",
+				 code);
+		}
+		input_abs_set_res(input, code, resolution);
 		break;
 	case EV_KEY:
 		input_set_capability(input, EV_KEY, code);
@@ -1880,18 +1969,7 @@
 static void wacom_wac_battery_usage_mapping(struct hid_device *hdev,
 		struct hid_field *field, struct hid_usage *usage)
 {
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-	struct wacom_features *features = &wacom_wac->features;
-	unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
-
-	switch (equivalent_usage) {
-	case HID_DG_BATTERYSTRENGTH:
-	case WACOM_HID_WD_BATTERY_LEVEL:
-	case WACOM_HID_WD_BATTERY_CHARGING:
-		features->quirks |= WACOM_QUIRK_BATTERY;
-		break;
-	}
+	return;
 }
 
 static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field,
@@ -1912,18 +1990,21 @@
 			wacom_wac->hid_data.bat_connected = 1;
 			wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
 		}
+		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
 		break;
 	case WACOM_HID_WD_BATTERY_LEVEL:
 		value = value * 100 / (field->logical_maximum - field->logical_minimum);
 		wacom_wac->hid_data.battery_capacity = value;
 		wacom_wac->hid_data.bat_connected = 1;
 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
 		break;
 	case WACOM_HID_WD_BATTERY_CHARGING:
 		wacom_wac->hid_data.bat_charging = value;
 		wacom_wac->hid_data.ps_connected = value;
 		wacom_wac->hid_data.bat_connected = 1;
 		wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+		wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY;
 		break;
 	}
 }
@@ -1939,18 +2020,15 @@
 {
 	struct wacom *wacom = hid_get_drvdata(hdev);
 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-	struct wacom_features *features = &wacom_wac->features;
 
-	if (features->quirks & WACOM_QUIRK_BATTERY) {
-		int status = wacom_wac->hid_data.bat_status;
-		int capacity = wacom_wac->hid_data.battery_capacity;
-		bool charging = wacom_wac->hid_data.bat_charging;
-		bool connected = wacom_wac->hid_data.bat_connected;
-		bool powered = wacom_wac->hid_data.ps_connected;
+	int status = wacom_wac->hid_data.bat_status;
+	int capacity = wacom_wac->hid_data.battery_capacity;
+	bool charging = wacom_wac->hid_data.bat_charging;
+	bool connected = wacom_wac->hid_data.bat_connected;
+	bool powered = wacom_wac->hid_data.ps_connected;
 
-		wacom_notify_battery(wacom_wac, status, capacity, charging,
-				     connected, powered);
-	}
+	wacom_notify_battery(wacom_wac, status, capacity, charging,
+			     connected, powered);
 }
 
 static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
@@ -2003,7 +2081,6 @@
 		wacom_wac->has_mute_touch_switch = true;
 		usage->type = EV_SW;
 		usage->code = SW_MUTE_DEVICE;
-		features->device_type |= WACOM_DEVICETYPE_PAD;
 		break;
 	case WACOM_HID_WD_TOUCHSTRIP:
 		wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0);
@@ -2083,6 +2160,30 @@
 			wacom_wac->hid_data.inrange_state |= value;
 	}
 
+	/* Process touch switch state first since it is reported through touch interface,
+	 * which is indepentent of pad interface. In the case when there are no other pad
+	 * events, the pad interface will not even be created.
+	 */
+	if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) ||
+	   (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) {
+		if (wacom_wac->shared->touch_input) {
+			bool *is_touch_on = &wacom_wac->shared->is_touch_on;
+
+			if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value)
+				*is_touch_on = !(*is_touch_on);
+			else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)
+				*is_touch_on = value;
+
+			input_report_switch(wacom_wac->shared->touch_input,
+					    SW_MUTE_DEVICE, !(*is_touch_on));
+			input_sync(wacom_wac->shared->touch_input);
+		}
+		return;
+	}
+
+	if (!input)
+		return;
+
 	switch (equivalent_usage) {
 	case WACOM_HID_WD_TOUCHRING:
 		/*
@@ -2096,14 +2197,16 @@
 		    (hdev->product == 0x34d || hdev->product == 0x34e ||  /* MobileStudio Pro */
 		     hdev->product == 0x357 || hdev->product == 0x358 ||  /* Intuos Pro 2 */
 		     hdev->product == 0x392 ||				  /* Intuos Pro 2 */
-		     hdev->product == 0x398 || hdev->product == 0x399)) { /* MobileStudio Pro */
+		     hdev->product == 0x398 || hdev->product == 0x399 ||  /* MobileStudio Pro */
+		     hdev->product == 0x3AA)) {				  /* MobileStudio Pro */
 			value = (field->logical_maximum - value);
 
 			if (hdev->product == 0x357 || hdev->product == 0x358 ||
 			    hdev->product == 0x392)
 				value = wacom_offset_rotation(input, usage, value, 3, 16);
 			else if (hdev->product == 0x34d || hdev->product == 0x34e ||
-				 hdev->product == 0x398 || hdev->product == 0x399)
+				 hdev->product == 0x398 || hdev->product == 0x399 ||
+				 hdev->product == 0x3AA)
 				value = wacom_offset_rotation(input, usage, value, 1, 2);
 		}
 		else {
@@ -2116,22 +2219,6 @@
 			input_event(input, usage->type, usage->code, 0);
 		break;
 
-	case WACOM_HID_WD_MUTE_DEVICE:
-	case WACOM_HID_WD_TOUCHONOFF:
-		if (wacom_wac->shared->touch_input) {
-			bool *is_touch_on = &wacom_wac->shared->is_touch_on;
-
-			if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value)
-				*is_touch_on = !(*is_touch_on);
-			else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)
-				*is_touch_on = value;
-
-			input_report_switch(wacom_wac->shared->touch_input,
-					    SW_MUTE_DEVICE, !(*is_touch_on));
-			input_sync(wacom_wac->shared->touch_input);
-		}
-		break;
-
 	case WACOM_HID_WD_MODE_CHANGE:
 		if (wacom_wac->is_direct_mode != value) {
 			wacom_wac->is_direct_mode = value;
@@ -2283,6 +2370,7 @@
 		value = field->logical_maximum - value;
 		break;
 	case HID_DG_INRANGE:
+		mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100));
 		wacom_wac->hid_data.inrange_state = value;
 		if (!(features->quirks & WACOM_QUIRK_SENSE))
 			wacom_wac->hid_data.sense_state = value;
@@ -2307,6 +2395,9 @@
 		}
 		return;
 	case HID_DG_TWIST:
+		/* don't modify the value if the pen doesn't support the feature */
+		if (!wacom_is_art_pen(wacom_wac->id[0])) return;
+
 		/*
 		 * Userspace expects pen twist to have its zero point when
 		 * the buttons/finger is on the tablet's left. HID values
@@ -2449,7 +2540,14 @@
 				wacom_wac->hid_data.tipswitch);
 		input_report_key(input, wacom_wac->tool[0], sense);
 		if (wacom_wac->serial[0]) {
-			input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
+			/*
+			 * xf86-input-wacom does not accept a serial number
+			 * of '0'. Report the low 32 bits if possible, but
+			 * if they are zero, report the upper ones instead.
+			 */
+			__u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu;
+			__u32 serial_hi = wacom_wac->serial[0] >> 32;
+			input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi));
 			input_report_abs(input, ABS_MISC, sense ? id : 0);
 		}
 
@@ -2521,14 +2619,14 @@
 {
 	struct hid_data *hid_data = &wacom_wac->hid_data;
 	bool mt = wacom_wac->features.touch_max > 1;
-	bool prox = hid_data->tipswitch &&
-		    report_touch_events(wacom_wac);
+	bool touch_down = hid_data->tipswitch && hid_data->confidence;
+	bool prox = touch_down && report_touch_events(wacom_wac);
 
 	if (wacom_wac->shared->has_mute_touch_switch &&
 	    !wacom_wac->shared->is_touch_on) {
 		if (!wacom_wac->shared->touch_down)
 			return;
-		prox = 0;
+		prox = false;
 	}
 
 	wacom_wac->hid_data.num_received++;
@@ -2573,6 +2671,9 @@
 		return;
 
 	switch (equivalent_usage) {
+	case HID_DG_CONFIDENCE:
+		wacom_wac->hid_data.confidence = value;
+		break;
 	case HID_GD_X:
 		wacom_wac->hid_data.x = value;
 		break;
@@ -2595,7 +2696,12 @@
 		wacom_wac->is_invalid_bt_frame = !value;
 		return;
 	case HID_DG_CONTACTMAX:
-		features->touch_max = value;
+		if (!features->touch_max) {
+			features->touch_max = value;
+		} else {
+			hid_warn(hdev, "%s: ignoring attempt to overwrite non-zero touch_max "
+				 "%d -> %d\n", __func__, features->touch_max, value);
+		}
 		return;
 	}
 
@@ -2615,6 +2721,12 @@
 
 	wacom_wac->is_invalid_bt_frame = false;
 
+	hid_data->confidence = true;
+
+	hid_data->cc_report = 0;
+	hid_data->cc_index = -1;
+	hid_data->cc_value_index = -1;
+
 	for (i = 0; i < report->maxfield; i++) {
 		struct hid_field *field = report->field[i];
 		int j;
@@ -2635,9 +2747,28 @@
 			case HID_DG_TIPSWITCH:
 				hid_data->last_slot_field = equivalent_usage;
 				break;
+			case HID_DG_CONTACTCOUNT:
+				hid_data->cc_report = report->id;
+				hid_data->cc_index = i;
+				hid_data->cc_value_index = j;
+				break;
 			}
 		}
 	}
+
+	if (hid_data->cc_report != 0 &&
+	    hid_data->cc_index >= 0) {
+		struct hid_field *field = report->field[hid_data->cc_index];
+		int value = field->value[hid_data->cc_value_index];
+		if (value) {
+			hid_data->num_expected = value;
+			hid_data->num_received = 0;
+		}
+	}
+	else {
+		hid_data->num_expected = wacom_wac->features.touch_max;
+		hid_data->num_received = 0;
+	}
 }
 
 static void wacom_wac_finger_report(struct hid_device *hdev,
@@ -2647,7 +2778,6 @@
 	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
 	struct input_dev *input = wacom_wac->touch_input;
 	unsigned touch_max = wacom_wac->features.touch_max;
-	struct hid_data *hid_data = &wacom_wac->hid_data;
 
 	/* If more packets of data are expected, give us a chance to
 	 * process them rather than immediately syncing a partial
@@ -2661,7 +2791,7 @@
 
 	input_sync(input);
 	wacom_wac->hid_data.num_received = 0;
-	hid_data->num_expected = 0;
+	wacom_wac->hid_data.num_expected = 0;
 
 	/* keep touch state for pen event */
 	wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
@@ -2702,7 +2832,7 @@
 	/* usage tests must precede field tests */
 	if (WACOM_BATTERY_USAGE(usage))
 		wacom_wac_battery_event(hdev, field, usage, value);
-	else if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+	else if (WACOM_PAD_FIELD(field))
 		wacom_wac_pad_event(hdev, field, usage, value);
 	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
 		wacom_wac_pen_event(hdev, field, usage, value);
@@ -2736,73 +2866,12 @@
 	}
 }
 
-static void wacom_set_num_expected(struct hid_device *hdev,
-				   struct hid_report *report,
-				   int collection_index,
-				   struct hid_field *field,
-				   int field_index)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-	struct hid_data *hid_data = &wacom_wac->hid_data;
-	unsigned int original_collection_level =
-		hdev->collection[collection_index].level;
-	bool end_collection = false;
-	int i;
-
-	if (hid_data->num_expected)
-		return;
-
-	// find the contact count value for this segment
-	for (i = field_index; i < report->maxfield && !end_collection; i++) {
-		struct hid_field *field = report->field[i];
-		unsigned int field_level =
-			hdev->collection[field->usage[0].collection_index].level;
-		unsigned int j;
-
-		if (field_level != original_collection_level)
-			continue;
-
-		for (j = 0; j < field->maxusage; j++) {
-			struct hid_usage *usage = &field->usage[j];
-
-			if (usage->collection_index != collection_index) {
-				end_collection = true;
-				break;
-			}
-			if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) {
-				hid_data->cc_report = report->id;
-				hid_data->cc_index = i;
-				hid_data->cc_value_index = j;
-
-				if (hid_data->cc_report != 0 &&
-				    hid_data->cc_index >= 0) {
-
-					struct hid_field *field =
-						report->field[hid_data->cc_index];
-					int value =
-						field->value[hid_data->cc_value_index];
-
-					if (value)
-						hid_data->num_expected = value;
-				}
-			}
-		}
-	}
-
-	if (hid_data->cc_report == 0 || hid_data->cc_index < 0)
-		hid_data->num_expected = wacom_wac->features.touch_max;
-}
-
 static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
 			 int collection_index, struct hid_field *field,
 			 int field_index)
 {
 	struct wacom *wacom = hid_get_drvdata(hdev);
 
-	if (WACOM_FINGER_FIELD(field))
-		wacom_set_num_expected(hdev, report, collection_index, field,
-				       field_index);
 	wacom_report_events(hdev, report, collection_index, field_index);
 
 	/*
@@ -2815,7 +2884,9 @@
 	if (report->type != HID_INPUT_REPORT)
 		return -1;
 
-	if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+	if (WACOM_PAD_FIELD(field))
+		return 0;
+	else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
 		wacom_wac_pen_report(hdev, report);
 	else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
 		wacom_wac_finger_report(hdev, report);
@@ -3609,8 +3680,6 @@
 {
 	struct wacom_features *features = &wacom_wac->features;
 
-	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
 	if (!(features->device_type & WACOM_DEVICETYPE_PEN))
 		return -ENODEV;
 
@@ -3625,6 +3694,7 @@
 		return 0;
 	}
 
+	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(ABS_MISC, input_dev->absbit);
 
@@ -3777,8 +3847,6 @@
 {
 	struct wacom_features *features = &wacom_wac->features;
 
-	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
 	if (!(features->device_type & WACOM_DEVICETYPE_TOUCH))
 		return -ENODEV;
 
@@ -3791,6 +3859,7 @@
 		/* setup has already been done */
 		return 0;
 
+	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 
 	if (features->touch_max == 1) {
@@ -3866,7 +3935,7 @@
 		    wacom_wac->shared->touch->product == 0xF6) {
 			input_dev->evbit[0] |= BIT_MASK(EV_SW);
 			__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
-			wacom_wac->shared->has_mute_touch_switch = true;
+			wacom_wac->has_mute_touch_switch = true;
 		}
 		/* fall through */
 
@@ -4752,10 +4821,23 @@
 	{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
 	  INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
 	  .touch_max = 10 };
+static const struct wacom_features wacom_features_0x3c6 =
+	{ "Wacom Intuos BT S", 15200, 9500, 4095, 63,
+	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
+static const struct wacom_features wacom_features_0x3c8 =
+	{ "Wacom Intuos BT M", 21600, 13500, 4095, 63,
+	  INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
+static const struct wacom_features wacom_features_0x3dd =
+	{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
+	  INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
+	  .touch_max = 10 };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
 	{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
 
+static const struct wacom_features wacom_features_0x94 =
+	{ "Wacom Bootloader", .type = BOOTLOADER };
+
 #define USB_DEVICE_WACOM(prod)						\
 	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
 	.driver_data = (kernel_ulong_t)&wacom_features_##prod
@@ -4829,6 +4911,7 @@
 	{ USB_DEVICE_WACOM(0x84) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x93) },
+	{ USB_DEVICE_WACOM(0x94) },
 	{ USB_DEVICE_WACOM(0x97) },
 	{ USB_DEVICE_WACOM(0x9A) },
 	{ USB_DEVICE_WACOM(0x9F) },
@@ -4925,6 +5008,9 @@
 	{ USB_DEVICE_WACOM(0x37A) },
 	{ USB_DEVICE_WACOM(0x37B) },
 	{ BT_DEVICE_WACOM(0x393) },
+	{ BT_DEVICE_WACOM(0x3c6) },
+	{ BT_DEVICE_WACOM(0x3c8) },
+	{ BT_DEVICE_WACOM(0x3dd) },
 	{ USB_DEVICE_WACOM(0x4001) },
 	{ USB_DEVICE_WACOM(0x4004) },
 	{ USB_DEVICE_WACOM(0x5000) },
--- linux-ein-5.4.0.orig/drivers/hid/wacom_wac.h
+++ linux-ein-5.4.0/drivers/hid/wacom_wac.h
@@ -15,6 +15,7 @@
 #define WACOM_NAME_MAX		64
 #define WACOM_MAX_REMOTES	5
 #define WACOM_STATUS_UNKNOWN	255
+#define WACOM_REMOTE_BATTERY_TIMEOUT	21000000000ll
 
 /* packet length for individual models */
 #define WACOM_PKGLEN_BBFUN	 9
@@ -122,7 +123,7 @@
 #define WACOM_HID_WD_TOUCHONOFF         (WACOM_HID_UP_WACOMDIGITIZER | 0x0454)
 #define WACOM_HID_WD_BATTERY_LEVEL      (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
 #define WACOM_HID_WD_EXPRESSKEY00       (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
-#define WACOM_HID_WD_EXPRESSKEYCAP00    (WACOM_HID_UP_WACOMDIGITIZER | 0x0950)
+#define WACOM_HID_WD_EXPRESSKEYCAP00    (WACOM_HID_UP_WACOMDIGITIZER | 0x0940)
 #define WACOM_HID_WD_MODE_CHANGE        (WACOM_HID_UP_WACOMDIGITIZER | 0x0980)
 #define WACOM_HID_WD_MUTE_DEVICE        (WACOM_HID_UP_WACOMDIGITIZER | 0x0981)
 #define WACOM_HID_WD_CONTROLPANEL       (WACOM_HID_UP_WACOMDIGITIZER | 0x0982)
@@ -242,6 +243,7 @@
 	MTTPC,
 	MTTPC_B,
 	HID_GENERIC,
+	BOOTLOADER,
 	MAX_TYPE
 };
 
@@ -300,6 +302,7 @@
 	bool tipswitch;
 	bool barrelswitch;
 	bool barrelswitch2;
+	bool confidence;
 	int x;
 	int y;
 	int pressure;
@@ -318,6 +321,7 @@
 	int bat_connected;
 	int ps_connected;
 	bool pad_input_event_flag;
+	ktime_t time_delayed;
 };
 
 struct wacom_remote_data {
@@ -342,7 +346,7 @@
 	struct input_dev *pen_input;
 	struct input_dev *touch_input;
 	struct input_dev *pad_input;
-	struct kfifo_rec_ptr_2 pen_fifo;
+	struct kfifo_rec_ptr_2 *pen_fifo;
 	int pid;
 	int num_contacts_left;
 	u8 bt_features;
--- linux-ein-5.4.0.orig/drivers/hsi/controllers/omap_ssi_core.c
+++ linux-ein-5.4.0/drivers/hsi/controllers/omap_ssi_core.c
@@ -355,7 +355,7 @@
 
 	err = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
 	if (err < 0)
-		goto out_err;
+		return err;
 	ssi->id = err;
 
 	ssi->owner = THIS_MODULE;
@@ -424,7 +424,7 @@
 	struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 	int err;
 
-	err = pm_runtime_get_sync(ssi->device.parent);
+	err = pm_runtime_resume_and_get(ssi->device.parent);
 	if (err < 0) {
 		dev_err(&ssi->device, "runtime PM failed %d\n", err);
 		return err;
@@ -502,8 +502,10 @@
 	platform_set_drvdata(pd, ssi);
 
 	err = ssi_add_controller(ssi, pd);
-	if (err < 0)
+	if (err < 0) {
+		hsi_put_controller(ssi);
 		goto out1;
+	}
 
 	pm_runtime_enable(&pd->dev);
 
@@ -524,6 +526,7 @@
 		if (!childpdev) {
 			err = -ENODEV;
 			dev_err(&pd->dev, "failed to create ssi controller port\n");
+			of_node_put(child);
 			goto out3;
 		}
 	}
@@ -535,9 +538,9 @@
 	device_for_each_child(&pd->dev, NULL, ssi_remove_ports);
 out2:
 	ssi_remove_controller(ssi);
+	pm_runtime_disable(&pd->dev);
 out1:
 	platform_set_drvdata(pd, NULL);
-	pm_runtime_disable(&pd->dev);
 
 	return err;
 }
@@ -628,7 +631,13 @@
 	if (ret)
 		return ret;
 
-	return platform_driver_register(&ssi_port_pdriver);
+	ret = platform_driver_register(&ssi_port_pdriver);
+	if (ret) {
+		platform_driver_unregister(&ssi_pdriver);
+		return ret;
+	}
+
+	return 0;
 }
 module_init(ssi_init);
 
--- linux-ein-5.4.0.orig/drivers/hsi/controllers/omap_ssi_port.c
+++ linux-ein-5.4.0/drivers/hsi/controllers/omap_ssi_port.c
@@ -230,10 +230,10 @@
 	if (msg->ttype == HSI_MSG_READ) {
 		err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,
 							DMA_FROM_DEVICE);
-		if (err < 0) {
+		if (!err) {
 			dev_dbg(&ssi->device, "DMA map SG failed !\n");
 			pm_runtime_put_autosuspend(omap_port->pdev);
-			return err;
+			return -EIO;
 		}
 		csdp = SSI_DST_BURST_4x32_BIT | SSI_DST_MEMORY_PORT |
 			SSI_SRC_SINGLE_ACCESS0 | SSI_SRC_PERIPHERAL_PORT |
@@ -247,10 +247,10 @@
 	} else {
 		err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,
 							DMA_TO_DEVICE);
-		if (err < 0) {
+		if (!err) {
 			dev_dbg(&ssi->device, "DMA map SG failed !\n");
 			pm_runtime_put_autosuspend(omap_port->pdev);
-			return err;
+			return -EIO;
 		}
 		csdp = SSI_SRC_BURST_4x32_BIT | SSI_SRC_MEMORY_PORT |
 			SSI_DST_SINGLE_ACCESS0 | SSI_DST_PERIPHERAL_PORT |
--- linux-ein-5.4.0.orig/drivers/hsi/hsi_core.c
+++ linux-ein-5.4.0/drivers/hsi/hsi_core.c
@@ -102,6 +102,7 @@
 	if (device_register(&cl->device) < 0) {
 		pr_err("hsi: failed to register client: %s\n", info->name);
 		put_device(&cl->device);
+		goto err;
 	}
 
 	return cl;
@@ -210,8 +211,6 @@
 	if (err)
 		goto err;
 
-	dev_set_name(&cl->device, "%s", name);
-
 	err = hsi_of_property_parse_mode(client, "hsi-mode", &mode);
 	if (err) {
 		err = hsi_of_property_parse_mode(client, "hsi-rx-mode",
@@ -293,6 +292,7 @@
 	cl->device.release = hsi_client_release;
 	cl->device.of_node = client;
 
+	dev_set_name(&cl->device, "%s", name);
 	if (device_register(&cl->device) < 0) {
 		pr_err("hsi: failed to register client: %s\n", name);
 		put_device(&cl->device);
--- linux-ein-5.4.0.orig/drivers/hv/channel_mgmt.c
+++ linux-ein-5.4.0/drivers/hv/channel_mgmt.c
@@ -493,13 +493,17 @@
 	 * 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() fails, the 'device_obj' is freed in
+	 * vmbus_device_release() as called by device_unregister() in the
+	 * error path of vmbus_device_register(). In the outside error
+	 * path, there's no need to free it.
 	 */
 	ret = vmbus_device_register(newchannel->device_obj);
 
 	if (ret != 0) {
 		pr_err("unable to add child device object (relid %d)\n",
 			newchannel->offermsg.child_relid);
-		kfree(newchannel->device_obj);
 		goto err_deq_chan;
 	}
 
@@ -763,13 +767,19 @@
 	free_cpumask_var(available_mask);
 }
 
+#define UNLOAD_DELAY_UNIT_MS	10		/* 10 milliseconds */
+#define UNLOAD_WAIT_MS		(100*1000)	/* 100 seconds */
+#define UNLOAD_WAIT_LOOPS	(UNLOAD_WAIT_MS/UNLOAD_DELAY_UNIT_MS)
+#define UNLOAD_MSG_MS		(5*1000)	/* Every 5 seconds */
+#define UNLOAD_MSG_LOOPS	(UNLOAD_MSG_MS/UNLOAD_DELAY_UNIT_MS)
+
 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;
+	u32 message_type, i;
 
 	/*
 	 * CHANNELMSG_UNLOAD_RESPONSE is always delivered to the CPU which was
@@ -779,16 +789,35 @@
 	 * 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.
+	 *
+	 * Wait up to 100 seconds since an Azure host must writeback any dirty
+	 * data in its disk cache before the VMbus UNLOAD request will
+	 * complete. This flushing has been empirically observed to take up
+	 * to 50 seconds in cases with a lot of dirty data, so allow additional
+	 * leeway and for inaccuracies in mdelay(). But eventually time out so
+	 * that the panic path can't get hung forever in case the response
+	 * message isn't seen.
 	 */
-	while (1) {
+	for (i = 1; i <= UNLOAD_WAIT_LOOPS; i++) {
 		if (completion_done(&vmbus_connection.unload_event))
-			break;
+			goto completed;
 
-		for_each_online_cpu(cpu) {
+		for_each_present_cpu(cpu) {
 			struct hv_per_cpu_context *hv_cpu
 				= per_cpu_ptr(hv_context.cpu_context, cpu);
 
+			/*
+			 * In a CoCo VM the synic_message_page is not allocated
+			 * in hv_synic_alloc(). Instead it is set/cleared in
+			 * hv_synic_enable_regs() and hv_synic_disable_regs()
+			 * such that it is set only when the CPU is online. If
+			 * not all present CPUs are online, the message page
+			 * might be NULL, so skip such CPUs.
+			 */
 			page_addr = hv_cpu->synic_message_page;
+			if (!page_addr)
+				continue;
+
 			msg = (struct hv_message *)page_addr
 				+ VMBUS_MESSAGE_SINT;
 
@@ -805,19 +834,31 @@
 			vmbus_signal_eom(msg, message_type);
 		}
 
-		mdelay(10);
+		/*
+		 * Give a notice periodically so someone watching the
+		 * serial output won't think it is completely hung.
+		 */
+		if (!(i % UNLOAD_MSG_LOOPS))
+			pr_notice("Waiting for VMBus UNLOAD to complete\n");
+
+		mdelay(UNLOAD_DELAY_UNIT_MS);
 	}
+	pr_err("Continuing even though VMBus UNLOAD did not complete\n");
 
+completed:
 	/*
 	 * 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) {
+	for_each_present_cpu(cpu) {
 		struct hv_per_cpu_context *hv_cpu
 			= per_cpu_ptr(hv_context.cpu_context, cpu);
 
 		page_addr = hv_cpu->synic_message_page;
+		if (!page_addr)
+			continue;
+
 		msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 		msg->header.message_type = HVMSG_NONE;
 	}
@@ -831,6 +872,11 @@
 	/*
 	 * This is a global event; just wakeup the waiting thread.
 	 * Once we successfully unload, we can cleanup the monitor state.
+	 *
+	 * NB.  A malicious or compromised Hyper-V could send a spurious
+	 * message of type CHANNELMSG_UNLOAD_RESPONSE, and trigger a call
+	 * of the complete() below.  Make sure that unload_event has been
+	 * initialized by the time this complete() is executed.
 	 */
 	complete(&vmbus_connection.unload_event);
 }
@@ -839,11 +885,14 @@
 {
 	struct vmbus_channel_message_header hdr;
 
+	if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED)
+		return;
+
 	/* Pre-Win2012R2 hosts don't support reconnect */
 	if (vmbus_proto_version < VERSION_WIN8_1)
 		return;
 
-	init_completion(&vmbus_connection.unload_event);
+	reinit_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),
@@ -1095,8 +1144,7 @@
 			vmbus_device_unregister(channel->device_obj);
 			put_device(dev);
 		}
-	}
-	if (channel->primary_channel != NULL) {
+	} else if (channel->primary_channel != NULL) {
 		/*
 		 * Sub-channel is being rescinded. Following is the channel
 		 * close sequence when initiated from the driveri (refer to
@@ -1351,6 +1399,8 @@
 	{ CHANNELMSG_19,			0, NULL },
 	{ CHANNELMSG_20,			0, NULL },
 	{ CHANNELMSG_TL_CONNECT_REQUEST,	0, NULL },
+	{ CHANNELMSG_22,			0, NULL },
+	{ CHANNELMSG_TL_CONNECT_RESULT,		0, NULL },
 };
 
 /*
@@ -1362,25 +1412,16 @@
 {
 	struct hv_message *msg = context;
 	struct vmbus_channel_message_header *hdr;
-	int size;
 
 	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
-	size = msg->header.payload_size;
 
 	trace_vmbus_on_message(hdr);
 
-	if (hdr->msgtype >= CHANNELMSG_COUNT) {
-		pr_err("Received invalid channel message type %d size %d\n",
-			   hdr->msgtype, size);
-		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
-				     (unsigned char *)msg->u.payload, size);
-		return;
-	}
-
-	if (channel_message_table[hdr->msgtype].message_handler)
-		channel_message_table[hdr->msgtype].message_handler(hdr);
-	else
-		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
+	/*
+	 * vmbus_on_msg_dpc() makes sure the hdr->msgtype here can not go
+	 * out of bound and the message_handler pointer can not be NULL.
+	 */
+	channel_message_table[hdr->msgtype].message_handler(hdr);
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/hv/connection.c
+++ linux-ein-5.4.0/drivers/hv/connection.c
@@ -25,6 +25,8 @@
 
 struct vmbus_connection vmbus_connection = {
 	.conn_state		= DISCONNECTED,
+	.unload_event		= COMPLETION_INITIALIZER(
+				  vmbus_connection.unload_event),
 	.next_gpadl_handle	= ATOMIC_INIT(0xE1E10),
 
 	.ready_for_suspend_event= COMPLETION_INITIALIZER(
@@ -67,7 +69,6 @@
 int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
 {
 	int ret = 0;
-	unsigned int cur_cpu;
 	struct vmbus_channel_initiate_contact *msg;
 	unsigned long flags;
 
@@ -100,24 +101,7 @@
 
 	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) {
-		cur_cpu = get_cpu();
-		msg->target_vcpu = hv_cpu_number_to_vp_number(cur_cpu);
-		vmbus_connection.connect_cpu = cur_cpu;
-		put_cpu();
-	} else {
-		msg->target_vcpu = 0;
-		vmbus_connection.connect_cpu = 0;
-	}
+	msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU);
 
 	/*
 	 * Add to list before we send the request since we may
--- linux-ein-5.4.0.orig/drivers/hv/hv.c
+++ linux-ein-5.4.0/drivers/hv/hv.c
@@ -250,6 +250,17 @@
 	unsigned long flags;
 
 	/*
+	 * Hyper-V does not provide a way to change the connect CPU once
+	 * it is set; we must prevent the connect CPU from going offline
+	 * while the VM is running normally. But in the panic or kexec()
+	 * path where the vmbus is already disconnected, the CPU must be
+	 * allowed to shut down.
+	 */
+	if (cpu == VMBUS_CONNECT_CPU &&
+	    vmbus_connection.conn_state == CONNECTED)
+		return -EBUSY;
+
+	/*
 	 * Search for channels which are bound to the CPU we're about to
 	 * cleanup. In case we find one and vmbus is still connected we need to
 	 * fail, this will effectively prevent CPU offlining. There is no way
--- linux-ein-5.4.0.orig/drivers/hv/hv_balloon.c
+++ linux-ein-5.4.0/drivers/hv/hv_balloon.c
@@ -1213,10 +1213,7 @@
 	unsigned int i, j;
 	struct page *pg;
 
-	if (num_pages < alloc_unit)
-		return 0;
-
-	for (i = 0; (i * alloc_unit) < num_pages; i++) {
+	for (i = 0; i < num_pages / alloc_unit; i++) {
 		if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) >
 			PAGE_SIZE)
 			return i * alloc_unit;
@@ -1254,7 +1251,7 @@
 
 	}
 
-	return num_pages;
+	return i * alloc_unit;
 }
 
 static void balloon_up(struct work_struct *dummy)
@@ -1269,9 +1266,6 @@
 	long avail_pages;
 	unsigned long floor;
 
-	/* The host balloons pages in 2M granularity. */
-	WARN_ON_ONCE(num_pages % PAGES_IN_2M != 0);
-
 	/*
 	 * We will attempt 2M allocations. However, if we fail to
 	 * allocate 2M chunks, we will go back to 4k allocations.
@@ -1281,14 +1275,13 @@
 	avail_pages = si_mem_available();
 	floor = compute_balloon_floor();
 
-	/* Refuse to balloon below the floor, keep the 2M granularity. */
+	/* Refuse to balloon below the floor. */
 	if (avail_pages < num_pages || avail_pages - num_pages < floor) {
-		pr_warn("Balloon request will be partially fulfilled. %s\n",
+		pr_info("Balloon request will be partially fulfilled. %s\n",
 			avail_pages < num_pages ? "Not enough memory." :
 			"Balloon floor reached.");
 
 		num_pages = avail_pages > floor ? (avail_pages - floor) : 0;
-		num_pages -= num_pages % PAGES_IN_2M;
 	}
 
 	while (!done) {
@@ -1557,7 +1550,7 @@
 			break;
 
 		default:
-			pr_warn("Unhandled message: type: %d\n", dm_hdr->type);
+			pr_warn_ratelimited("Unhandled message: type: %d\n", dm_hdr->type);
 
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/hv/hv_util.c
+++ linux-ein-5.4.0/drivers/hv/hv_util.c
@@ -537,8 +537,8 @@
 	 */
 	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));
+		pr_err("cannot register PTP clock: %d\n",
+		       PTR_ERR_OR_ZERO(hv_ptp_clock));
 		hv_ptp_clock = NULL;
 	}
 
--- linux-ein-5.4.0.orig/drivers/hv/hyperv_vmbus.h
+++ linux-ein-5.4.0/drivers/hv/hyperv_vmbus.h
@@ -13,6 +13,7 @@
 #define _HYPERV_VMBUS_H
 
 #include <linux/list.h>
+#include <linux/bitops.h>
 #include <asm/sync_bitops.h>
 #include <asm/hyperv-tlfs.h>
 #include <linux/atomic.h>
@@ -212,12 +213,13 @@
 
 #define MAX_SIZE_CHANNEL_MESSAGE	HV_MESSAGE_PAYLOAD_BYTE_COUNT
 
-struct vmbus_connection {
-	/*
-	 * CPU on which the initial host contact was made.
-	 */
-	int connect_cpu;
+/*
+ * The CPU that Hyper-V will interrupt for VMBUS messages, such as
+ * CHANNELMSG_OFFERCHANNEL and CHANNELMSG_RESCIND_CHANNELOFFER.
+ */
+#define VMBUS_CONNECT_CPU	0
 
+struct vmbus_connection {
 	u32 msg_conn_id;
 
 	atomic_t offer_in_progress;
--- linux-ein-5.4.0.orig/drivers/hv/ring_buffer.c
+++ linux-ein-5.4.0/drivers/hv/ring_buffer.c
@@ -378,7 +378,16 @@
 static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
 {
 	u32 priv_read_loc = rbi->priv_read_index;
-	u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
+	u32 write_loc;
+
+	/*
+	 * The Hyper-V host writes the packet data, then uses
+	 * store_release() to update the write_index.  Use load_acquire()
+	 * here to prevent loads of the packet data from being re-ordered
+	 * before the read of the write_index and potentially getting
+	 * stale data.
+	 */
+	write_loc = virt_load_acquire(&rbi->ring_buffer->write_index);
 
 	if (write_loc >= priv_read_loc)
 		return write_loc - priv_read_loc;
--- linux-ein-5.4.0.orig/drivers/hv/vmbus_drv.c
+++ linux-ein-5.4.0/drivers/hv/vmbus_drv.c
@@ -31,6 +31,7 @@
 #include <linux/kdebug.h>
 #include <linux/efi.h>
 #include <linux/random.h>
+#include <linux/kernel.h>
 #include <linux/syscore_ops.h>
 #include <clocksource/hyperv_timer.h>
 #include "hyperv_vmbus.h"
@@ -48,14 +49,35 @@
 
 static void *hv_panic_page;
 
+/*
+ * Boolean to control whether to report panic messages over Hyper-V.
+ *
+ * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
+ */
+static int sysctl_record_panic_msg = 1;
+
+static int hyperv_report_reg(void)
+{
+	return !sysctl_record_panic_msg || !hv_panic_page;
+}
+
 static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
 			      void *args)
 {
 	struct pt_regs *regs;
 
-	regs = current_pt_regs();
+	vmbus_initiate_unload(true);
 
-	hyperv_report_panic(regs, val);
+	/*
+	 * Hyper-V should be notified only once about a panic.  If we will be
+	 * doing hyperv_report_panic_msg() later with kmsg data, don't do
+	 * the notification here.
+	 */
+	if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
+	    && hyperv_report_reg()) {
+		regs = current_pt_regs();
+		hyperv_report_panic(regs, val, false);
+	}
 	return NOTIFY_DONE;
 }
 
@@ -65,7 +87,13 @@
 	struct die_args *die = (struct die_args *)args;
 	struct pt_regs *regs = die->regs;
 
-	hyperv_report_panic(regs, val);
+	/*
+	 * Hyper-V should be notified only once about a panic.  If we will be
+	 * doing hyperv_report_panic_msg() later with kmsg data, don't do
+	 * the notification here.
+	 */
+	if (hyperv_report_reg())
+		hyperv_report_panic(regs, val, true);
 	return NOTIFY_DONE;
 }
 
@@ -950,6 +978,9 @@
 
 	return drv->resume(dev);
 }
+#else
+#define vmbus_suspend NULL
+#define vmbus_resume NULL
 #endif /* CONFIG_PM_SLEEP */
 
 /*
@@ -967,11 +998,22 @@
 }
 
 /*
- * Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than
- * SET_SYSTEM_SLEEP_PM_OPS: see the comment before vmbus_bus_pm.
+ * Note: we must use the "noirq" ops: see the comment before vmbus_bus_pm.
+ *
+ * suspend_noirq/resume_noirq are set to NULL to support Suspend-to-Idle: we
+ * shouldn't suspend the vmbus devices upon Suspend-to-Idle, otherwise there
+ * is no way to wake up a Generation-2 VM.
+ *
+ * The other 4 ops are for hibernation.
  */
+
 static const struct dev_pm_ops vmbus_pm = {
-	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_suspend, vmbus_resume)
+	.suspend_noirq	= NULL,
+	.resume_noirq	= NULL,
+	.freeze_noirq	= vmbus_suspend,
+	.thaw_noirq	= vmbus_resume,
+	.poweroff_noirq	= vmbus_suspend,
+	.restore_noirq	= vmbus_resume,
 };
 
 /* The one and only one */
@@ -1031,6 +1073,10 @@
 	}
 
 	entry = &channel_message_table[hdr->msgtype];
+
+	if (!entry->message_handler)
+		goto msg_handled;
+
 	if (entry->handler_type	== VMHT_BLOCKING) {
 		ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
 		if (ctx == NULL)
@@ -1050,14 +1096,28 @@
 			/*
 			 * If we are handling the rescind message;
 			 * schedule the work on the global work queue.
+			 *
+			 * The OFFER message and the RESCIND message should
+			 * not be handled by the same serialized work queue,
+			 * because the OFFER handler may call vmbus_open(),
+			 * which tries to open the channel by sending an
+			 * OPEN_CHANNEL message to the host and waits for
+			 * the host's response; however, if the host has
+			 * rescinded the channel before it receives the
+			 * OPEN_CHANNEL message, the host just silently
+			 * ignores the OPEN_CHANNEL message; as a result,
+			 * the guest's OFFER handler hangs for ever, if we
+			 * handle the RESCIND message in the same serialized
+			 * work queue: the RESCIND handler can not start to
+			 * run before the OFFER handler finishes.
 			 */
-			schedule_work_on(vmbus_connection.connect_cpu,
+			schedule_work_on(VMBUS_CONNECT_CPU,
 					 &ctx->work);
 			break;
 
 		case CHANNELMSG_OFFERCHANNEL:
 			atomic_inc(&vmbus_connection.offer_in_progress);
-			queue_work_on(vmbus_connection.connect_cpu,
+			queue_work_on(VMBUS_CONNECT_CPU,
 				      vmbus_connection.work_queue,
 				      &ctx->work);
 			break;
@@ -1104,7 +1164,7 @@
 
 	INIT_WORK(&ctx->work, vmbus_onmessage_work);
 
-	queue_work_on(vmbus_connection.connect_cpu,
+	queue_work_on(VMBUS_CONNECT_CPU,
 		      vmbus_connection.work_queue,
 		      &ctx->work);
 }
@@ -1243,17 +1303,10 @@
 			tasklet_schedule(&hv_cpu->msg_dpc);
 	}
 
-	add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
+	add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR);
 }
 
 /*
- * Boolean to control whether to report panic messages over Hyper-V.
- *
- * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
- */
-static int sysctl_record_panic_msg = 1;
-
-/*
  * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg
  * buffer and call into Hyper-V to transfer the data.
  */
@@ -1380,19 +1433,29 @@
 			hv_panic_page = (void *)get_zeroed_page(GFP_KERNEL);
 			if (hv_panic_page) {
 				ret = kmsg_dump_register(&hv_kmsg_dumper);
-				if (ret)
+				if (ret) {
 					pr_err("Hyper-V: kmsg dump register "
 						"error 0x%x\n", ret);
+					hv_free_hyperv_page(
+					    (unsigned long)hv_panic_page);
+					hv_panic_page = NULL;
+				}
 			} else
 				pr_err("Hyper-V: panic message page memory "
 					"allocation failed");
 		}
 
 		register_die_notifier(&hyperv_die_block);
-		atomic_notifier_chain_register(&panic_notifier_list,
-					       &hyperv_panic_block);
 	}
 
+	/*
+	 * Always register the panic notifier because we need to unload
+	 * the VMbus channel connection to prevent any VMbus
+	 * activity after the VM panics.
+	 */
+	atomic_notifier_chain_register(&panic_notifier_list,
+			       &hyperv_panic_block);
+
 	vmbus_request_offers();
 
 	return 0;
@@ -1406,7 +1469,6 @@
 	hv_remove_vmbus_irq();
 
 	bus_unregister(&hv_bus);
-	free_page((unsigned long)hv_panic_page);
 	unregister_sysctl_table(hv_ctl_table_hdr);
 	hv_ctl_table_hdr = NULL;
 	return ret;
@@ -1725,8 +1787,10 @@
 	kobj->kset = dev->channels_kset;
 	ret = kobject_init_and_add(kobj, &vmbus_chan_ktype, NULL,
 				   "%u", relid);
-	if (ret)
+	if (ret) {
+		kobject_put(kobj);
 		return ret;
+	}
 
 	ret = sysfs_create_group(kobj, &vmbus_chan_group);
 
@@ -1735,6 +1799,7 @@
 		 * The calling functions' error handling paths will cleanup the
 		 * empty channel directory.
 		 */
+		kobject_put(kobj);
 		dev_err(device, "Unable to set up channel sysfs files\n");
 		return ret;
 	}
@@ -1798,6 +1863,7 @@
 	ret = device_register(&child_device_obj->device);
 	if (ret) {
 		pr_err("Unable to register child device\n");
+		put_device(&child_device_obj->device);
 		return ret;
 	}
 
@@ -2010,7 +2076,7 @@
 			bool fb_overlap_ok)
 {
 	struct resource *iter, *shadow;
-	resource_size_t range_min, range_max, start;
+	resource_size_t range_min, range_max, start, end;
 	const char *dev_n = dev_name(&device_obj->device);
 	int retval;
 
@@ -2045,6 +2111,14 @@
 		range_max = iter->end;
 		start = (range_min + align - 1) & ~(align - 1);
 		for (; start + size - 1 <= range_max; start += align) {
+			end = start + size - 1;
+
+			/* Skip the whole fb_mmio region if not fb_overlap_ok */
+			if (!fb_overlap_ok && fb_mmio &&
+			    (((start >= fb_mmio->start) && (start <= fb_mmio->end)) ||
+			     ((end >= fb_mmio->start) && (end <= fb_mmio->end))))
+				continue;
+
 			shadow = __request_region(iter, start, size, NULL,
 						  IORESOURCE_BUSY);
 			if (!shadow)
@@ -2169,7 +2243,10 @@
 	if (atomic_read(&vmbus_connection.nr_chan_close_on_suspend) > 0)
 		wait_for_completion(&vmbus_connection.ready_for_suspend_event);
 
-	WARN_ON(atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) != 0);
+	if (atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) != 0) {
+		pr_err("Can not suspend due to a previous failed resuming\n");
+		return -EBUSY;
+	}
 
 	mutex_lock(&vmbus_connection.channel_mutex);
 
@@ -2202,8 +2279,6 @@
 
 	vmbus_initiate_unload(false);
 
-	vmbus_connection.conn_state = DISCONNECTED;
-
 	/* Reset the event for the next resume. */
 	reinit_completion(&vmbus_connection.ready_for_resume_event);
 
@@ -2245,13 +2320,18 @@
 
 	vmbus_request_offers();
 
-	wait_for_completion(&vmbus_connection.ready_for_resume_event);
+	if (wait_for_completion_timeout(
+		&vmbus_connection.ready_for_resume_event, 10 * HZ) == 0)
+		pr_err("Some vmbus device is missing after suspending?\n");
 
 	/* Reset the event for the next suspend. */
 	reinit_completion(&vmbus_connection.ready_for_suspend_event);
 
 	return 0;
 }
+#else
+#define vmbus_bus_suspend NULL
+#define vmbus_bus_resume NULL
 #endif /* CONFIG_PM_SLEEP */
 
 static const struct acpi_device_id vmbus_acpi_device_ids[] = {
@@ -2262,16 +2342,24 @@
 MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);
 
 /*
- * Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than
- * SET_SYSTEM_SLEEP_PM_OPS, otherwise NIC SR-IOV can not work, because the
- * "pci_dev_pm_ops" uses the "noirq" callbacks: in the resume path, the
- * pci "noirq" restore callback runs before "non-noirq" callbacks (see
+ * Note: we must use the "no_irq" ops, otherwise hibernation can not work with
+ * PCI device assignment, because "pci_dev_pm_ops" uses the "noirq" ops: in
+ * the resume path, the pci "noirq" restore op runs before "non-noirq" op (see
  * resume_target_kernel() -> dpm_resume_start(), and hibernation_restore() ->
  * dpm_resume_end()). This means vmbus_bus_resume() and the pci-hyperv's
- * resume callback must also run via the "noirq" callbacks.
+ * resume callback must also run via the "noirq" ops.
+ *
+ * Set suspend_noirq/resume_noirq to NULL for Suspend-to-Idle: see the comment
+ * earlier in this file before vmbus_pm.
  */
+
 static const struct dev_pm_ops vmbus_bus_pm = {
-	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_bus_suspend, vmbus_bus_resume)
+	.suspend_noirq	= NULL,
+	.resume_noirq	= NULL,
+	.freeze_noirq	= vmbus_bus_suspend,
+	.thaw_noirq	= vmbus_bus_resume,
+	.poweroff_noirq	= vmbus_bus_suspend,
+	.restore_noirq	= vmbus_bus_resume
 };
 
 static struct acpi_driver vmbus_acpi_driver = {
@@ -2288,7 +2376,6 @@
 {
 	hv_stimer_global_cleanup();
 	vmbus_initiate_unload(false);
-	vmbus_connection.conn_state = DISCONNECTED;
 	/* Make sure conn_state is set as hv_synic_cleanup checks for it */
 	mb();
 	cpuhp_remove_state(hyperv_cpuhp_online);
@@ -2305,10 +2392,9 @@
 	 * doing the cleanup for current CPU only. This should be sufficient
 	 * for kdump.
 	 */
-	vmbus_connection.conn_state = DISCONNECTED;
 	cpu = smp_processor_id();
 	hv_stimer_cleanup(cpu);
-	hv_synic_cleanup(cpu);
+	hv_synic_disable_regs(cpu);
 	hyperv_cleanup();
 };
 
@@ -2416,10 +2502,15 @@
 	if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
 		kmsg_dump_unregister(&hv_kmsg_dumper);
 		unregister_die_notifier(&hyperv_die_block);
-		atomic_notifier_chain_unregister(&panic_notifier_list,
-						 &hyperv_panic_block);
 	}
 
+	/*
+	 * The panic notifier is always registered, hence we should
+	 * also unconditionally unregister it here as well.
+	 */
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+					 &hyperv_panic_block);
+
 	free_page((unsigned long)hv_panic_page);
 	unregister_sysctl_table(hv_ctl_table_hdr);
 	hv_ctl_table_hdr = NULL;
--- linux-ein-5.4.0.orig/drivers/hwmon/Kconfig
+++ linux-ein-5.4.0/drivers/hwmon/Kconfig
@@ -494,6 +494,15 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called f75375s.
 
+config SENSORS_GSC
+	tristate "Gateworks System Controller ADC"
+	depends on MFD_GATEWORKS_GSC
+	help
+	  Support for the Gateworks System Controller A/D converters.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called gsc-hwmon.
+
 config SENSORS_MC13783_ADC
         tristate "Freescale MC13783/MC13892 ADC"
         depends on MFD_MC13XXX
@@ -802,7 +811,7 @@
 
 config SENSORS_LTQ_CPUTEMP
 	bool "Lantiq cpu temperature sensor driver"
-	depends on LANTIQ
+	depends on SOC_XWAY
 	help
 	  If you say yes here you get support for the temperature
 	  sensor inside your CPU.
@@ -1132,10 +1141,11 @@
 	help
 	  If you say yes here you get support for National Semiconductor LM90,
 	  LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
-	  Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
-	  MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-	  Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, GMT G781, and
-	  Texas Instruments TMP451 sensor chips.
+	  Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6654, MAX6657, MAX6658,
+	  MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696,
+	  ON Semiconductor NCT1008, Winbond/Nuvoton W83L771W/G/AWG/ASG,
+	  Philips SA56004, GMT G781, Texas Instruments TMP451 and TMP461
+	  sensor chips.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called lm90.
@@ -1922,6 +1932,17 @@
 	  If you say yes here you get support for the temperature
 	  and power sensors for APM X-Gene SoC.
 
+config SENSORS_AHC1EC0_HWMON
+	tristate "Advantech AHC1EC0 Hardware Monitor Function"
+	depends on MFD_AHC1EC0
+	depends on UBUNTU_ODM_DRIVERS
+	help
+	  This driver provide support for the hardware monitoring functionality
+	  for Advantech AHC1EC0 embedded controller on the board.
+
+	  This driver provides the sysfs attributes for applications to monitor
+	  the system status, including system temperatures, voltages, current.
+
 if ACPI
 
 comment "ACPI drivers"
--- linux-ein-5.4.0.orig/drivers/hwmon/Makefile
+++ linux-ein-5.4.0/drivers/hwmon/Makefile
@@ -44,6 +44,7 @@
 obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)	+= adt7470.o
 obj-$(CONFIG_SENSORS_ADT7475)	+= adt7475.o
+obj-$(CONFIG_SENSORS_AHC1EC0_HWMON)	+= ahc1ec0-hwmon.o
 obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
 obj-$(CONFIG_SENSORS_ARM_SCMI)	+= scmi-hwmon.o
 obj-$(CONFIG_SENSORS_ARM_SCPI)	+= scpi-hwmon.o
@@ -71,6 +72,7 @@
 obj-$(CONFIG_SENSORS_G762)	+= g762.o
 obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
+obj-$(CONFIG_SENSORS_GSC)	+= gsc-hwmon.o
 obj-$(CONFIG_SENSORS_GPIO_FAN)	+= gpio-fan.o
 obj-$(CONFIG_SENSORS_HIH6130)	+= hih6130.o
 obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
--- linux-ein-5.4.0.orig/drivers/hwmon/acpi_power_meter.c
+++ linux-ein-5.4.0/drivers/hwmon/acpi_power_meter.c
@@ -32,6 +32,7 @@
 #define POWER_METER_CAN_NOTIFY	(1 << 3)
 #define POWER_METER_IS_BATTERY	(1 << 8)
 #define UNKNOWN_HYSTERESIS	0xFFFFFFFF
+#define UNKNOWN_POWER		0xFFFFFFFF
 
 #define METER_NOTIFY_CONFIG	0x80
 #define METER_NOTIFY_TRIP	0x81
@@ -343,6 +344,9 @@
 	update_meter(resource);
 	mutex_unlock(&resource->lock);
 
+	if (resource->power == UNKNOWN_POWER)
+		return -ENODATA;
+
 	return sprintf(buf, "%llu\n", resource->power * 1000);
 }
 
@@ -883,7 +887,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)) {
@@ -896,6 +900,8 @@
 
 exit_remove:
 	remove_attrs(resource);
+exit_free_capability:
+	free_capabilities(resource);
 exit_free:
 	kfree(resource);
 exit:
--- linux-ein-5.4.0.orig/drivers/hwmon/adt7462.c
+++ linux-ein-5.4.0/drivers/hwmon/adt7462.c
@@ -413,7 +413,7 @@
 			return 0x95;
 		break;
 	}
-	return -ENODEV;
+	return 0;
 }
 
 /* Provide labels for sysfs */
--- linux-ein-5.4.0.orig/drivers/hwmon/adt7470.c
+++ linux-ein-5.4.0/drivers/hwmon/adt7470.c
@@ -20,6 +20,7 @@
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/util_macros.h>
+#include <linux/sched.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
@@ -260,11 +261,10 @@
 		adt7470_read_temperatures(client, data);
 		mutex_unlock(&data->lock);
 
-		set_current_state(TASK_INTERRUPTIBLE);
 		if (kthread_should_stop())
 			break;
 
-		schedule_timeout(msecs_to_jiffies(data->auto_update_interval));
+		schedule_timeout_interruptible(msecs_to_jiffies(data->auto_update_interval));
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/hwmon/adt7475.c
+++ linux-ein-5.4.0/drivers/hwmon/adt7475.c
@@ -294,9 +294,10 @@
 	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);
 }
 
@@ -483,10 +484,10 @@
 		val = (temp - val) / 1000;
 
 		if (sattr->index != 1) {
-			data->temp[HYSTERSIS][sattr->index] &= 0xF0;
+			data->temp[HYSTERSIS][sattr->index] &= 0x0F;
 			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4;
 		} else {
-			data->temp[HYSTERSIS][sattr->index] &= 0x0F;
+			data->temp[HYSTERSIS][sattr->index] &= 0xF0;
 			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF);
 		}
 
@@ -551,11 +552,11 @@
 		val = data->enh_acoustics[0] & 0xf;
 		break;
 	case 1:
-		val = (data->enh_acoustics[1] >> 4) & 0xf;
+		val = data->enh_acoustics[1] & 0xf;
 		break;
 	case 2:
 	default:
-		val = data->enh_acoustics[1] & 0xf;
+		val = (data->enh_acoustics[1] >> 4) & 0xf;
 		break;
 	}
 
--- linux-ein-5.4.0.orig/drivers/hwmon/ahc1ec0-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/ahc1ec0-hwmon.c
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HWMON Driver for Advantech Embedded Controller chip AHC1EC0
+ *
+ * Copyright 2020, Advantech IIoT Group
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/mfd/ahc1ec0.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+struct ec_hwmon_attrs {
+	const char		*name;
+	umode_t			mode;
+	int (*read)(struct device *dev, long *val);
+};
+
+struct adv_hwmon_profile {
+	int offset;
+	unsigned long resolution, resolution_vin, resolution_sys, resolution_curr, resolution_power;
+	unsigned long r1, r1_vin, r1_sys, r1_curr, r1_power;
+	unsigned long r2, r2_vin, r2_sys, r2_curr, r2_power;
+	int hwmon_in_list_cnt;
+	int temp_list_cnt;
+	int *hwmon_in_list;
+	int *temp_list;
+};
+
+struct ec_hwmon_data {
+	struct device *dev;
+	struct device *hwmon_dev;
+	struct adv_ec_platform_data *adv_ec_data;
+	unsigned long temperature[3];
+	unsigned long ec_current[5];
+	unsigned long power[5];
+	unsigned long voltage[7];
+
+	struct ec_hw_pin_table pin_tbl;
+	struct ec_smbuso_em0 ec_smboem0;
+	struct adv_hwmon_profile *profile;
+};
+
+static int get_ec_in_vbat_input(struct device *dev, long *val);
+static int get_ec_in_v5_input(struct device *dev, long *val);
+static int get_ec_in_v12_input(struct device *dev, long *val);
+static int get_ec_in_vcore_input(struct device *dev, long *val);
+static int get_ec_current1_input(struct device *dev, long *val);
+static int get_ec_cpu_temp(struct device *dev, long *val);
+static int get_ec_sys_temp(struct device *dev, long *val);
+
+const struct ec_hwmon_attrs ec_hwmon_in_attr_template[] = {
+	{"VBAT",	0444, get_ec_in_vbat_input},	// in1
+	{"5VSB",	0444, get_ec_in_v5_input},	// in2
+	{"Vin",		0444, get_ec_in_v12_input},	// in3 (== in8)
+	{"VCORE",	0444, get_ec_in_vcore_input},	// in4
+	{"Vin1",	0444, NULL},	// in5
+	{"Vin2",	0444, NULL},	// in6
+	{"System Voltage", 0444, NULL},	// in7
+	{"Current",	0444, get_ec_current1_input},
+};
+
+const struct ec_hwmon_attrs ec_temp_attrs_template[] = {
+	{"CPU Temp",	0444, get_ec_cpu_temp},
+	{"System Temp",	0444, get_ec_sys_temp},
+};
+
+enum ec_hwmon_in_type {
+	EC_HWMON_IN_VBAT,
+	EC_HWMON_IN_5VSB,
+	EC_HWMON_IN_12V,
+	EC_HWMON_IN_VCORE,
+	EC_HWMON_IN_VIN1,
+	EC_HWMON_IN_VIN2,
+	EC_HWMON_IN_SYS_VOL,
+	EC_HWMON_IN_CURRENT,
+};
+
+enum ec_temp_type {
+	EC_TEMP_CPU,
+	EC_TEMP_SYS,
+};
+
+static int hwmon_in_list_0[] = {
+	EC_HWMON_IN_VBAT,
+	EC_HWMON_IN_5VSB,
+	EC_HWMON_IN_12V,
+	EC_HWMON_IN_VCORE,
+	EC_HWMON_IN_CURRENT,
+};
+
+static int hwmon_in_list_1[] = {
+	EC_HWMON_IN_VBAT,
+	EC_HWMON_IN_5VSB,
+	EC_HWMON_IN_12V,
+	EC_HWMON_IN_VCORE,
+};
+
+static int temp_list_0[] = {
+	EC_TEMP_CPU,
+};
+
+static int temp_list_1[] = {
+	EC_TEMP_CPU,
+	EC_TEMP_SYS,
+};
+
+static struct adv_hwmon_profile advec_profile[] = {
+	/*
+	 * TPC-8100TR, TPC-651T-E3AE, TPC-1251T-E3AE, TPC-1551T-E3AE,
+	 * TPC-1751T-E3AE, TPC-1051WP-E3AE, TPC-1551WP-E3AE, TPC-1581WP-433AE,
+	 * TPC-1782H-433AE, UNO-1483G-434AE, UNO-2483G-434AE, UNO-3483G-374AE,
+	 * UNO-2473G, UNO-2484G-6???AE, UNO-2484G-7???AE, UNO-3283G-674AE,
+	 * UNO-3285G-674AE
+	 * [0] AHC1EC0_HWMON_PRO_TEMPLATE
+	 */
+	{
+		.resolution = 2929,
+		.r1 = 1912,
+		.r2 = 1000,
+		.offset = 0,
+		.hwmon_in_list_cnt = ARRAY_SIZE(hwmon_in_list_0),
+		.temp_list_cnt = ARRAY_SIZE(temp_list_0),
+		.hwmon_in_list = hwmon_in_list_0,
+		.temp_list = temp_list_0,
+	},
+	/*
+	 * TPC-B500-6??AE, TPC-5???T-6??AE, TPC-5???W-6??AE, TPC-B200-???AE,
+	 * TPC-2???T-???AE, TPC-2???W-???AE
+	 * [1] AHC1EC0_HWMON_PRO_TPC5XXX
+	 */
+	{
+		.resolution = 2929,
+		.r1 = 1912,
+		.r2 = 1000,
+		.offset = 0,
+		.hwmon_in_list_cnt = ARRAY_SIZE(hwmon_in_list_1),
+		.temp_list_cnt = ARRAY_SIZE(temp_list_0),
+		.hwmon_in_list = hwmon_in_list_1,
+		.temp_list = temp_list_0,
+	},
+	/* PR/VR4
+	 * [2] AHC1EC0_HWMON_PRO_PRVR4
+	 */
+	{
+		.resolution = 2929,
+		.r1 = 1912,
+		.r2 = 1000,
+		.offset = 0,
+		.hwmon_in_list_cnt = ARRAY_SIZE(hwmon_in_list_1),
+		.temp_list_cnt = ARRAY_SIZE(temp_list_1),
+		.hwmon_in_list = hwmon_in_list_1,
+		.temp_list = temp_list_1,
+	},
+	/* UNO-2271G-E22AE/E23AE/E022AE/E023AE,UNO-420
+	 * [3] AHC1EC0_HWMON_PRO_UNO2271G
+	 */
+	{
+		.resolution = 2929,
+		.r1 = 1912,
+		.r2 = 1000,
+		.offset = 0,
+		.hwmon_in_list_cnt = ARRAY_SIZE(hwmon_in_list_1),
+		.temp_list_cnt = ARRAY_SIZE(temp_list_0),
+		.hwmon_in_list = hwmon_in_list_1,
+		.temp_list = temp_list_0,
+	},
+};
+
+static void adv_ec_init_hwmon_profile(u32 profile, struct ec_hwmon_data *lmsensor_data)
+{
+	int i;
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+	struct ec_dynamic_table *dym_tbl = adv_ec_data->dym_tbl;
+
+	if (profile >= ARRAY_SIZE(advec_profile))
+		return;
+
+	lmsensor_data->profile = &advec_profile[profile];
+
+	for (i = 0; i < EC_MAX_TBL_NUM ; i++) {
+		switch (dym_tbl[i].device_id) {
+		case EC_DID_CMOSBAT:
+			ptbl->vbat[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vbat[1] = 1;
+			break;
+		case EC_DID_CMOSBAT_X2:
+			ptbl->vbat[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vbat[1] = 2;
+			break;
+		case EC_DID_CMOSBAT_X10:
+			ptbl->vbat[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vbat[1] = 10;
+			break;
+		case EC_DID_5VS0:
+		case EC_DID_5VS5:
+			ptbl->v5[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v5[1] = 1;
+			break;
+		case EC_DID_5VS0_X2:
+		case EC_DID_5VS5_X2:
+			ptbl->v5[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v5[1] = 2;
+			break;
+		case EC_DID_5VS0_X10:
+		case EC_DID_5VS5_X10:
+			ptbl->v5[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v5[1] = 10;
+			break;
+		case EC_DID_12VS0:
+			ptbl->v12[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v12[1] = 1;
+			break;
+		case EC_DID_12VS0_X2:
+			ptbl->v12[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v12[1] = 2;
+			break;
+		case EC_DID_12VS0_X10:
+			ptbl->v12[0] = dym_tbl[i].hw_pin_num;
+			ptbl->v12[1] = 10;
+			break;
+		case EC_DID_VCOREA:
+		case EC_DID_VCOREB:
+			ptbl->vcore[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vcore[1] = 1;
+			break;
+		case EC_DID_VCOREA_X2:
+		case EC_DID_VCOREB_X2:
+			ptbl->vcore[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vcore[1] = 2;
+			break;
+		case EC_DID_VCOREA_X10:
+		case EC_DID_VCOREB_X10:
+			ptbl->vcore[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vcore[1] = 10;
+			break;
+		case EC_DID_DC:
+			ptbl->vdc[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vdc[1] = 1;
+			break;
+		case EC_DID_DC_X2:
+			ptbl->vdc[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vdc[1] = 2;
+			break;
+		case EC_DID_DC_X10:
+			ptbl->vdc[0] = dym_tbl[i].hw_pin_num;
+			ptbl->vdc[1] = 10;
+			break;
+		case EC_DID_CURRENT:
+			ptbl->ec_current[0] = dym_tbl[i].hw_pin_num;
+			ptbl->ec_current[1] = 1;
+			break;
+		case EC_DID_SMBOEM0:
+			lmsensor_data->ec_smboem0.hw_pin_num = dym_tbl[i].hw_pin_num;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int get_ec_in_vbat_input(struct device *dev, long *val)
+{
+	unsigned int temp = 0;
+	unsigned long voltage = 0;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_hwmon_profile *profile = lmsensor_data->profile;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	temp = read_ad_value(adv_ec_data, ptbl->vbat[0], ptbl->vbat[1]);
+
+	if (profile->r2 != 0)
+		voltage = temp * (profile->r1 + profile->r2) / profile->r2;
+
+	if (profile->resolution != 0)
+		voltage =  temp * profile->resolution / 1000 / 1000;
+
+	if (profile->offset != 0)
+		voltage += (int)profile->offset * 100;
+
+	lmsensor_data->voltage[0] = 10 * voltage;
+
+	*val = lmsensor_data->voltage[0];
+	return 0;
+}
+
+static int get_ec_in_v5_input(struct device *dev, long *val)
+{
+	unsigned int temp;
+	unsigned long voltage = 0;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_hwmon_profile *profile = lmsensor_data->profile;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	temp = read_ad_value(adv_ec_data, ptbl->v5[0], ptbl->v5[1]);
+
+	if (profile->r2 != 0)
+		voltage = temp * (profile->r1 + profile->r2) / profile->r2;
+
+	if (profile->resolution != 0)
+		voltage =  temp * profile->resolution / 1000 / 1000;
+
+	if (profile->offset != 0)
+		voltage += (int)profile->offset * 100;
+
+	lmsensor_data->voltage[1] = 10 * voltage;
+
+	*val = lmsensor_data->voltage[1];
+	return 0;
+}
+
+static int get_ec_in_v12_input(struct device *dev, long *val)
+{
+	int temp;
+	unsigned long voltage = 0;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_hwmon_profile *profile = lmsensor_data->profile;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	temp = read_ad_value(adv_ec_data, ptbl->v12[0], ptbl->v12[1]);
+	if (temp == -1)
+		temp = read_ad_value(adv_ec_data, ptbl->vdc[0], ptbl->vdc[1]);
+
+	if (profile->r2 != 0)
+		voltage = temp * (profile->r1 + profile->r2) / profile->r2;
+
+	if (profile->resolution != 0)
+		voltage =  temp * profile->resolution / 1000 / 1000;
+
+	if (profile->offset != 0)
+		voltage += profile->offset * 100;
+
+	lmsensor_data->voltage[2] = 10 * voltage;
+
+	*val = lmsensor_data->voltage[2];
+	return 0;
+}
+
+static int get_ec_in_vcore_input(struct device *dev, long *val)
+{
+	int temp;
+	unsigned int voltage = 0;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_hwmon_profile *profile = lmsensor_data->profile;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	temp = read_ad_value(adv_ec_data, ptbl->vcore[0], ptbl->vcore[1]);
+
+	if (profile->r2 != 0)
+		voltage = temp * (profile->r1 + profile->r2) / profile->r2;
+
+	if (profile->resolution != 0)
+		voltage = temp * profile->resolution / 1000 / 1000;
+
+	if (profile->offset != 0)
+		voltage += profile->offset * 100;
+
+	lmsensor_data->voltage[3] = 10 * voltage;
+
+	*val = lmsensor_data->voltage[3];
+	return 0;
+}
+
+static int get_ec_current1_input(struct device *dev, long *val)
+{
+	int temp;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	struct ec_hw_pin_table *ptbl = &lmsensor_data->pin_tbl;
+	struct adv_hwmon_profile *profile = lmsensor_data->profile;
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	temp = read_ad_value(adv_ec_data, ptbl->ec_current[0], ptbl->ec_current[1]);
+
+	if (profile->r2 != 0)
+		temp = temp * (profile->r1 + profile->r2) / profile->r2;
+
+	if (profile->resolution != 0)
+		temp = temp * profile->resolution / 1000 / 1000;
+
+	if (profile->offset != 0)
+		temp += profile->offset * 100;
+
+	lmsensor_data->ec_current[3] = 10 * temp;
+
+	*val = lmsensor_data->ec_current[3];
+	return 0;
+}
+
+static int get_ec_cpu_temp(struct device *dev, long *val)
+{
+	#define EC_ACPI_THERMAL1_REMOTE_TEMP 0x61
+
+	unsigned char value;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	read_acpi_value(adv_ec_data, EC_ACPI_THERMAL1_REMOTE_TEMP, &value);
+	*val = 1000 * value;
+	return 0;
+}
+
+static int get_ec_sys_temp(struct device *dev, long *val)
+{
+	#define EC_ACPI_THERMAL1_LOCAL_TEMP 0x60
+
+	unsigned char value;
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+	struct adv_ec_platform_data *adv_ec_data = lmsensor_data->adv_ec_data;
+
+	read_acpi_value(adv_ec_data, EC_ACPI_THERMAL1_LOCAL_TEMP, &value);
+	*val = 1000 * value;
+	return 0;
+}
+
+
+static int
+ahc1ec0_read_in(struct device *dev, u32 attr, int channel, long *val)
+{
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	if (!(lmsensor_data && lmsensor_data->profile))
+		return -EINVAL;
+
+	if (attr == hwmon_in_input &&
+		lmsensor_data->profile->hwmon_in_list_cnt > channel) {
+		int index = lmsensor_data->profile->hwmon_in_list[channel];
+		const struct ec_hwmon_attrs *ec_hwmon_attr = &ec_hwmon_in_attr_template[index];
+
+		return ec_hwmon_attr->read(dev, val);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int
+ahc1ec0_read_temp(struct device *dev, u32 attr, int channel, long *val)
+{
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	if (!(lmsensor_data && lmsensor_data->profile))
+		return -EINVAL;
+
+	switch (attr) {
+	case hwmon_temp_input:
+		if (lmsensor_data->profile->temp_list_cnt > channel) {
+			int index = lmsensor_data->profile->temp_list[channel];
+			const struct ec_hwmon_attrs *devec_hwmon_attr =
+				&ec_temp_attrs_template[index];
+
+			return devec_hwmon_attr->read(dev, val);
+		}
+		return -EOPNOTSUPP;
+	case hwmon_temp_crit:
+		// both CPU temp and System temp are all this value
+		*val = 100000;
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int
+ahc1ec0_read_string(struct device *dev,
+					enum hwmon_sensor_types type,
+					u32 attr,
+					int channel,
+					const char **str)
+{
+	struct ec_hwmon_data *lmsensor_data = dev_get_drvdata(dev);
+
+	if (!(lmsensor_data && lmsensor_data->profile))
+		return -EINVAL;
+
+	if ((type == hwmon_in && attr == hwmon_in_label) &&
+		(lmsensor_data->profile->hwmon_in_list_cnt > channel)) {
+		int index = lmsensor_data->profile->hwmon_in_list[channel];
+		const struct ec_hwmon_attrs *ec_hwmon_attr = &ec_hwmon_in_attr_template[index];
+
+		*str = ec_hwmon_attr->name;
+		return 0;
+	}
+
+	if ((type == hwmon_temp && attr == hwmon_temp_label) &&
+		(lmsensor_data->profile->temp_list_cnt > channel)) {
+		int index = lmsensor_data->profile->temp_list[channel];
+		const struct ec_hwmon_attrs *ec_hwmon_attr = &ec_temp_attrs_template[index];
+
+		*str = ec_hwmon_attr->name;
+		return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int
+ahc1ec0_read(struct device *dev,
+			enum hwmon_sensor_types type,
+			u32 attr,
+			int channel,
+			long *val)
+{
+	switch (type) {
+	case hwmon_in:
+		return ahc1ec0_read_in(dev, attr, channel, val);
+	case hwmon_temp:
+		return ahc1ec0_read_temp(dev, attr, channel, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static umode_t
+ec_hwmon_in_visible(const void *data, u32 attr, int channel)
+{
+	switch (attr) {
+	case hwmon_in_input:
+	case hwmon_in_label:
+		return 0444;
+	default:
+		return 0;
+	}
+}
+
+static umode_t
+ec_temp_in_visible(const void *data, u32 attr, int channel)
+{
+	switch (attr) {
+	case hwmon_temp_input:
+	case hwmon_temp_crit:
+	case hwmon_temp_label:
+		return 0444;
+	default:
+		return 0;
+	}
+}
+
+static umode_t
+ahc1ec0_is_visible(const void *data,
+					enum hwmon_sensor_types type, u32 attr, int channel)
+{
+	switch (type) {
+	case hwmon_in:
+		return ec_hwmon_in_visible(data, attr, channel);
+	case hwmon_temp:
+		return ec_temp_in_visible(data, attr, channel);
+	default:
+		return 0;
+	}
+}
+
+static const u32 ahc1ec0_in_config[] = {
+	HWMON_I_INPUT | HWMON_I_LABEL,
+	HWMON_I_INPUT | HWMON_I_LABEL,
+	HWMON_I_INPUT | HWMON_I_LABEL,
+	HWMON_I_INPUT | HWMON_I_LABEL,
+	0
+};
+
+static const struct hwmon_channel_info ahc1ec0_in = {
+	.type = hwmon_in,
+	.config = ahc1ec0_in_config,
+};
+
+static const u32 ahc1ec0_temp_config[] = {
+	HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
+	0
+};
+
+static const struct hwmon_channel_info ahc1ec0_temp = {
+	.type = hwmon_temp,
+	.config = ahc1ec0_temp_config,
+};
+
+static const struct hwmon_channel_info *ahc1ec0_info[] = {
+	&ahc1ec0_in,
+	&ahc1ec0_temp,
+	NULL
+};
+
+static const struct hwmon_ops ahc1ec0_hwmon_ops = {
+	.is_visible = ahc1ec0_is_visible,
+	.read = ahc1ec0_read,
+	.read_string = ahc1ec0_read_string,
+};
+
+static const struct hwmon_chip_info ahc1ec0_chip_info = {
+	.ops = &ahc1ec0_hwmon_ops,
+	.info = ahc1ec0_info,
+};
+
+static int adv_ec_hwmon_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 profile;
+	struct device *dev = &pdev->dev;
+	struct adv_ec_platform_data *adv_ec_data;
+	struct ec_hwmon_data *lmsensor_data;
+
+	adv_ec_data = dev_get_drvdata(dev->parent);
+	if (!adv_ec_data)
+		return -EINVAL;
+
+	ret = device_property_read_u32(dev->parent, "advantech,hwmon-profile", &profile);
+	if (ret < 0) {
+		dev_err(dev, "get hwmon-profile failed! (%d)", ret);
+		return ret;
+	}
+
+	if (!(profile < ARRAY_SIZE(advec_profile))) {
+		dev_err(dev, "not support hwmon profile(%d)!\n", profile);
+		return -EINVAL;
+	}
+
+	lmsensor_data = devm_kzalloc(dev, sizeof(struct ec_hwmon_data), GFP_KERNEL);
+	if (!lmsensor_data)
+		return -ENOMEM;
+
+	lmsensor_data->adv_ec_data = adv_ec_data;
+	lmsensor_data->dev = dev;
+	dev_set_drvdata(dev, lmsensor_data);
+
+	adv_ec_init_hwmon_profile(profile, lmsensor_data);
+
+	lmsensor_data->hwmon_dev  = devm_hwmon_device_register_with_info(dev,
+			"ahc1ec0.hwmon", lmsensor_data, &ahc1ec0_chip_info, NULL);
+
+	return PTR_ERR_OR_ZERO(lmsensor_data->hwmon_dev);
+}
+
+static struct platform_driver adv_hwmon_drv = {
+	.driver = {
+		.name = "ahc1ec0-hwmon",
+	},
+	.probe = adv_ec_hwmon_probe,
+};
+module_platform_driver(adv_hwmon_drv);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:ahc1ec0-hwmon");
+MODULE_DESCRIPTION("Advantech Embedded Controller HWMON Driver.");
+MODULE_AUTHOR("Campion Kang <campion.kang@advantech.com.tw>");
+MODULE_AUTHOR("Jianfeng Dai <jianfeng.dai@advantech.com.cn>");
+MODULE_VERSION("1.0");
--- linux-ein-5.4.0.orig/drivers/hwmon/applesmc.c
+++ linux-ein-5.4.0/drivers/hwmon/applesmc.c
@@ -748,15 +748,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:
@@ -805,12 +808,11 @@
 		  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,
@@ -846,12 +848,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,
@@ -867,10 +868,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
@@ -946,13 +948,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-ein-5.4.0.orig/drivers/hwmon/aspeed-pwm-tacho.c
+++ linux-ein-5.4.0/drivers/hwmon/aspeed-pwm-tacho.c
@@ -194,6 +194,8 @@
 	u8 fan_tach_ch_source[16];
 	struct aspeed_cooling_device *cdev[8];
 	const struct attribute_group *groups[3];
+	/* protects access to shared ASPEED_PTCR_RESULT */
+	struct mutex tach_lock;
 };
 
 enum type { TYPEM, TYPEN, TYPEO };
@@ -528,6 +530,8 @@
 	u8 fan_tach_ch_source, type, mode, both;
 	int ret;
 
+	mutex_lock(&priv->tach_lock);
+
 	regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
 	regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
 
@@ -545,6 +549,8 @@
 		ASPEED_RPM_STATUS_SLEEP_USEC,
 		usec);
 
+	mutex_unlock(&priv->tach_lock);
+
 	/* return -ETIMEDOUT if we didn't get an answer. */
 	if (ret)
 		return ret;
@@ -851,6 +857,8 @@
 	ret = of_property_read_u32(child, "reg", &pwm_port);
 	if (ret)
 		return ret;
+	if (pwm_port >= ARRAY_SIZE(pwm_port_params))
+		return -EINVAL;
 	aspeed_create_pwm_port(priv, (u8)pwm_port);
 
 	ret = of_property_count_u8_elems(child, "cooling-levels");
@@ -907,6 +915,7 @@
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
+	mutex_init(&priv->tach_lock);
 	priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs,
 			&aspeed_pwm_tacho_regmap_config);
 	if (IS_ERR(priv->regmap))
--- linux-ein-5.4.0.orig/drivers/hwmon/coretemp.c
+++ linux-ein-5.4.0/drivers/hwmon/coretemp.c
@@ -40,15 +40,12 @@
 
 #define PKG_SYSFS_ATTR_NO	1	/* Sysfs attribute for package temp */
 #define BASE_SYSFS_ATTR_NO	2	/* Sysfs Base attr no for coretemp */
-#define NUM_REAL_CORES		128	/* Number of Real cores per cpu */
-#define CORETEMP_NAME_LENGTH	19	/* String Length of attrs */
+#define NUM_REAL_CORES		512	/* Number of Real cores per cpu */
+#define CORETEMP_NAME_LENGTH	28	/* String Length of attrs */
 #define MAX_CORE_ATTRS		4	/* Maximum no of basic attrs */
 #define TOTAL_ATTRS		(MAX_CORE_ATTRS + 1)
 #define MAX_CORE_DATA		(NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
 
-#define TO_CORE_ID(cpu)		(cpu_data(cpu).cpu_core_id)
-#define TO_ATTR_NO(cpu)		(TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
-
 #ifdef CONFIG_SMP
 #define for_each_sibling(i, cpu) \
 	for_each_cpu(i, topology_sibling_cpumask(cpu))
@@ -91,6 +88,8 @@
 struct platform_data {
 	struct device		*hwmon_dev;
 	u16			pkg_id;
+	u16			cpu_map[NUM_REAL_CORES];
+	struct ida		ida;
 	struct cpumask		cpumask;
 	struct temp_data	*core_data[MAX_CORE_DATA];
 	struct device_attribute name_attr;
@@ -243,10 +242,13 @@
 	 */
 	if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL) {
 		for (i = 0; i < ARRAY_SIZE(tjmax_pci_table); i++) {
-			if (host_bridge->device == tjmax_pci_table[i].device)
+			if (host_bridge->device == tjmax_pci_table[i].device) {
+				pci_dev_put(host_bridge);
 				return tjmax_pci_table[i].tjmax;
+			}
 		}
 	}
+	pci_dev_put(host_bridge);
 
 	for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) {
 		if (strstr(c->x86_model_id, tjmax_table[i].id))
@@ -378,7 +380,7 @@
 }
 
 static int create_core_attrs(struct temp_data *tdata, struct device *dev,
-			     int attr_no)
+			     int index)
 {
 	int i;
 	static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
@@ -390,13 +392,20 @@
 	};
 
 	for (i = 0; i < tdata->attr_size; i++) {
+		/*
+		 * We map the attr number to core id of the CPU
+		 * The attr number is always core id + 2
+		 * The Pkgtemp will always show up as temp1_*, if available
+		 */
+		int attr_no = tdata->is_pkg_data ? 1 : tdata->cpu_core_id + 2;
+
 		snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH,
 			 "temp%d_%s", attr_no, suffixes[i]);
 		sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
 		tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
 		tdata->sd_attrs[i].dev_attr.attr.mode = 0444;
 		tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
-		tdata->sd_attrs[i].index = attr_no;
+		tdata->sd_attrs[i].index = index;
 		tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
 	}
 	tdata->attr_group.attrs = tdata->attrs;
@@ -441,7 +450,7 @@
 							MSR_IA32_THERM_STATUS;
 	tdata->is_pkg_data = pkg_flag;
 	tdata->cpu = cpu;
-	tdata->cpu_core_id = TO_CORE_ID(cpu);
+	tdata->cpu_core_id = topology_core_id(cpu);
 	tdata->attr_size = MAX_CORE_ATTRS;
 	mutex_init(&tdata->update_lock);
 	return tdata;
@@ -454,22 +463,29 @@
 	struct platform_data *pdata = platform_get_drvdata(pdev);
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	u32 eax, edx;
-	int err, attr_no;
+	int err, index;
 
 	/*
-	 * Find attr number for sysfs:
-	 * We map the attr number to core id of the CPU
-	 * The attr number is always core id + 2
-	 * The Pkgtemp will always show up as temp1_*, if available
+	 * Get the index of tdata in pdata->core_data[]
+	 * tdata for package: pdata->core_data[1]
+	 * tdata for core: pdata->core_data[2] .. pdata->core_data[NUM_REAL_CORES + 1]
 	 */
-	attr_no = pkg_flag ? PKG_SYSFS_ATTR_NO : TO_ATTR_NO(cpu);
+	if (pkg_flag) {
+		index = PKG_SYSFS_ATTR_NO;
+	} else {
+		index = ida_alloc_max(&pdata->ida, NUM_REAL_CORES - 1, GFP_KERNEL);
+		if (index < 0)
+			return index;
 
-	if (attr_no > MAX_CORE_DATA - 1)
-		return -ERANGE;
+		pdata->cpu_map[index] = topology_core_id(cpu);
+		index += BASE_SYSFS_ATTR_NO;
+	}
 
 	tdata = init_temp_data(cpu, pkg_flag);
-	if (!tdata)
-		return -ENOMEM;
+	if (!tdata) {
+		err = -ENOMEM;
+		goto ida_free;
+	}
 
 	/* Test if we can access the status register */
 	err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx);
@@ -494,17 +510,20 @@
 		}
 	}
 
-	pdata->core_data[attr_no] = tdata;
+	pdata->core_data[index] = tdata;
 
 	/* Create sysfs interfaces */
-	err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
+	err = create_core_attrs(tdata, pdata->hwmon_dev, index);
 	if (err)
 		goto exit_free;
 
 	return 0;
 exit_free:
-	pdata->core_data[attr_no] = NULL;
+	pdata->core_data[index] = NULL;
 	kfree(tdata);
+ida_free:
+	if (!pkg_flag)
+		ida_free(&pdata->ida, index - BASE_SYSFS_ATTR_NO);
 	return err;
 }
 
@@ -519,71 +538,63 @@
 {
 	struct temp_data *tdata = pdata->core_data[indx];
 
+	/* if we errored on add then this is already gone */
+	if (!tdata)
+		return;
+
 	/* Remove the sysfs attributes */
 	sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
 
 	kfree(pdata->core_data[indx]);
 	pdata->core_data[indx] = NULL;
+
+	if (indx >= BASE_SYSFS_ATTR_NO)
+		ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
 }
 
-static int coretemp_probe(struct platform_device *pdev)
+static int coretemp_device_add(int zoneid)
 {
-	struct device *dev = &pdev->dev;
+	struct platform_device *pdev;
 	struct platform_data *pdata;
+	int err;
 
 	/* Initialize the per-zone data structures */
-	pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return -ENOMEM;
 
-	pdata->pkg_id = pdev->id;
-	platform_set_drvdata(pdev, pdata);
+	pdata->pkg_id = zoneid;
+	ida_init(&pdata->ida);
 
-	pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
-								  pdata, NULL);
-	return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
-}
-
-static int coretemp_remove(struct platform_device *pdev)
-{
-	struct platform_data *pdata = platform_get_drvdata(pdev);
-	int i;
+	pdev = platform_device_alloc(DRVNAME, zoneid);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto err_free_pdata;
+	}
 
-	for (i = MAX_CORE_DATA - 1; i >= 0; --i)
-		if (pdata->core_data[i])
-			coretemp_remove_core(pdata, i);
+	err = platform_device_add(pdev);
+	if (err)
+		goto err_put_dev;
 
+	platform_set_drvdata(pdev, pdata);
+	zone_devices[zoneid] = pdev;
 	return 0;
-}
 
-static struct platform_driver coretemp_driver = {
-	.driver = {
-		.name = DRVNAME,
-	},
-	.probe = coretemp_probe,
-	.remove = coretemp_remove,
-};
+err_put_dev:
+	platform_device_put(pdev);
+err_free_pdata:
+	kfree(pdata);
+	return err;
+}
 
-static struct platform_device *coretemp_device_add(unsigned int cpu)
+static void coretemp_device_remove(int zoneid)
 {
-	int err, zoneid = topology_logical_die_id(cpu);
-	struct platform_device *pdev;
-
-	if (zoneid < 0)
-		return ERR_PTR(-ENOMEM);
-
-	pdev = platform_device_alloc(DRVNAME, zoneid);
-	if (!pdev)
-		return ERR_PTR(-ENOMEM);
-
-	err = platform_device_add(pdev);
-	if (err) {
-		platform_device_put(pdev);
-		return ERR_PTR(err);
-	}
+	struct platform_device *pdev = zone_devices[zoneid];
+	struct platform_data *pdata = platform_get_drvdata(pdev);
 
-	zone_devices[zoneid] = pdev;
-	return pdev;
+	ida_destroy(&pdata->ida);
+	kfree(pdata);
+	platform_device_unregister(pdev);
 }
 
 static int coretemp_cpu_online(unsigned int cpu)
@@ -607,7 +618,10 @@
 	if (!cpu_has(c, X86_FEATURE_DTHERM))
 		return -ENODEV;
 
-	if (!pdev) {
+	pdata = platform_get_drvdata(pdev);
+	if (!pdata->hwmon_dev) {
+		struct device *hwmon;
+
 		/* Check the microcode version of the CPU */
 		if (chk_ucode_version(cpu))
 			return -EINVAL;
@@ -618,9 +632,11 @@
 		 * online. So, initialize per-pkg data structures and
 		 * then bring this core online.
 		 */
-		pdev = coretemp_device_add(cpu);
-		if (IS_ERR(pdev))
-			return PTR_ERR(pdev);
+		hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
+							  pdata, NULL);
+		if (IS_ERR(hwmon))
+			return PTR_ERR(hwmon);
+		pdata->hwmon_dev = hwmon;
 
 		/*
 		 * Check whether pkgtemp support is available.
@@ -630,7 +646,6 @@
 			coretemp_add_core(pdev, cpu, 1);
 	}
 
-	pdata = platform_get_drvdata(pdev);
 	/*
 	 * Check whether a thread sibling is already online. If not add the
 	 * interface for this CPU core.
@@ -647,25 +662,28 @@
 	struct platform_device *pdev = coretemp_get_pdev(cpu);
 	struct platform_data *pd;
 	struct temp_data *tdata;
-	int indx, target;
+	int i, indx = -1, target;
 
-	/*
-	 * Don't execute this on suspend as the device remove locks
-	 * up the machine.
-	 */
+	/* No need to tear down any interfaces for suspend */
 	if (cpuhp_tasks_frozen)
 		return 0;
 
 	/* If the physical CPU device does not exist, just return */
-	if (!pdev)
+	pd = platform_get_drvdata(pdev);
+	if (!pd->hwmon_dev)
 		return 0;
 
-	/* The core id is too big, just return */
-	indx = TO_ATTR_NO(cpu);
-	if (indx > MAX_CORE_DATA - 1)
+	for (i = 0; i < NUM_REAL_CORES; i++) {
+		if (pd->cpu_map[i] == topology_core_id(cpu)) {
+			indx = i + BASE_SYSFS_ATTR_NO;
+			break;
+		}
+	}
+
+	/* Too many cores and this core is not populated, just return */
+	if (indx < 0)
 		return 0;
 
-	pd = platform_get_drvdata(pdev);
 	tdata = pd->core_data[indx];
 
 	cpumask_clear_cpu(cpu, &pd->cpumask);
@@ -685,13 +703,14 @@
 	}
 
 	/*
-	 * If all cores in this pkg are offline, remove the device. This
-	 * will invoke the platform driver remove function, which cleans up
-	 * the rest.
+	 * If all cores in this pkg are offline, remove the interface.
 	 */
+	tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
 	if (cpumask_empty(&pd->cpumask)) {
-		zone_devices[topology_logical_die_id(cpu)] = NULL;
-		platform_device_unregister(pdev);
+		if (tdata)
+			coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO);
+		hwmon_device_unregister(pd->hwmon_dev);
+		pd->hwmon_dev = NULL;
 		return 0;
 	}
 
@@ -699,7 +718,6 @@
 	 * Check whether this core is the target for the package
 	 * interface. We need to assign it to some other cpu.
 	 */
-	tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
 	if (tdata && tdata->cpu == cpu) {
 		target = cpumask_first(&pd->cpumask);
 		mutex_lock(&tdata->update_lock);
@@ -718,7 +736,7 @@
 
 static int __init coretemp_init(void)
 {
-	int err;
+	int i, err;
 
 	/*
 	 * CPUID.06H.EAX[0] indicates whether the CPU has thermal
@@ -734,20 +752,22 @@
 	if (!zone_devices)
 		return -ENOMEM;
 
-	err = platform_driver_register(&coretemp_driver);
-	if (err)
-		goto outzone;
+	for (i = 0; i < max_zones; i++) {
+		err = coretemp_device_add(i);
+		if (err)
+			goto outzone;
+	}
 
 	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
 				coretemp_cpu_online, coretemp_cpu_offline);
 	if (err < 0)
-		goto outdrv;
+		goto outzone;
 	coretemp_hp_online = err;
 	return 0;
 
-outdrv:
-	platform_driver_unregister(&coretemp_driver);
 outzone:
+	while (i--)
+		coretemp_device_remove(i);
 	kfree(zone_devices);
 	return err;
 }
@@ -755,8 +775,11 @@
 
 static void __exit coretemp_exit(void)
 {
+	int i;
+
 	cpuhp_remove_state(coretemp_hp_online);
-	platform_driver_unregister(&coretemp_driver);
+	for (i = 0; i < max_zones; i++)
+		coretemp_device_remove(i);
 	kfree(zone_devices);
 }
 module_exit(coretemp_exit)
--- linux-ein-5.4.0.orig/drivers/hwmon/da9052-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/da9052-hwmon.c
@@ -244,9 +244,9 @@
 	int channel = to_sensor_dev_attr(devattr)->index;
 	int ret;
 
-	mutex_lock(&hwmon->hwmon_lock);
+	mutex_lock(&hwmon->da9052->auxadc_lock);
 	ret = __da9052_read_tsi(dev, channel);
-	mutex_unlock(&hwmon->hwmon_lock);
+	mutex_unlock(&hwmon->da9052->auxadc_lock);
 
 	if (ret < 0)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/hwmon/dell-smm-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/dell-smm-hwmon.c
@@ -301,7 +301,7 @@
 }
 
 /*
- * Set the fan speed (off, low, high). Returns the new fan status.
+ * Set the fan speed (off, low, high, ...).
  */
 static int i8k_set_fan(int fan, int speed)
 {
@@ -313,7 +313,7 @@
 	speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
 	regs.ebx = (fan & 0xff) | (speed << 8);
 
-	return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
+	return i8k_smm(&regs);
 }
 
 static int i8k_get_temp_type(int sensor)
@@ -427,7 +427,7 @@
 i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)
 {
 	int val = 0;
-	int speed;
+	int speed, err;
 	unsigned char buff[16];
 	int __user *argp = (int __user *)arg;
 
@@ -488,7 +488,11 @@
 		if (copy_from_user(&speed, argp + 1, sizeof(int)))
 			return -EFAULT;
 
-		val = i8k_set_fan(val, speed);
+		err = i8k_set_fan(val, speed);
+		if (err < 0)
+			return err;
+
+		val = i8k_get_fan_status(val);
 		break;
 
 	default:
@@ -588,15 +592,18 @@
 	.unlocked_ioctl	= i8k_ioctl,
 };
 
+static struct proc_dir_entry *entry;
+
 static void __init i8k_init_procfs(void)
 {
 	/* Register the proc entry */
-	proc_create("i8k", 0, NULL, &i8k_fops);
+	entry = proc_create("i8k", 0, NULL, &i8k_fops);
 }
 
 static void __exit i8k_exit_procfs(void)
 {
-	remove_proc_entry("i8k", NULL);
+	if (entry)
+		remove_proc_entry("i8k", NULL);
 }
 
 #else
@@ -792,10 +799,10 @@
 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
 			      int index)
 {
-	if (disallow_fan_support && index >= 8)
+	if (disallow_fan_support && index >= 20)
 		return 0;
 	if (disallow_fan_type_call &&
-	    (index == 9 || index == 12 || index == 15))
+	    (index == 21 || index == 25 || index == 28))
 		return 0;
 	if (index >= 0 && index <= 1 &&
 	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
--- linux-ein-5.4.0.orig/drivers/hwmon/emc2103.c
+++ linux-ein-5.4.0/drivers/hwmon/emc2103.c
@@ -443,7 +443,7 @@
 	}
 
 	result = read_u8_from_i2c(client, REG_FAN_CONF1, &conf_reg);
-	if (result) {
+	if (result < 0) {
 		count = result;
 		goto err;
 	}
--- linux-ein-5.4.0.orig/drivers/hwmon/f71882fg.c
+++ linux-ein-5.4.0/drivers/hwmon/f71882fg.c
@@ -1577,8 +1577,9 @@
 		temp *= 125;
 		if (sign)
 			temp -= 128000;
-	} else
-		temp = data->temp[nr] * 1000;
+	} else {
+		temp = ((s8)data->temp[nr]) * 1000;
+	}
 
 	return sprintf(buf, "%d\n", temp);
 }
--- linux-ein-5.4.0.orig/drivers/hwmon/gpio-fan.c
+++ linux-ein-5.4.0/drivers/hwmon/gpio-fan.c
@@ -391,6 +391,9 @@
 	if (!fan_data)
 		return -EINVAL;
 
+	if (state >= fan_data->num_speed)
+		return -EINVAL;
+
 	set_fan_speed(fan_data, state);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/hwmon/gsc-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/gsc-hwmon.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Gateworks System Controller Hardware Monitor module
+ *
+ * Copyright (C) 2020 Gateworks Corporation
+ */
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mfd/gsc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/gsc_hwmon.h>
+
+#define GSC_HWMON_MAX_TEMP_CH	16
+#define GSC_HWMON_MAX_IN_CH	16
+#define GSC_HWMON_MAX_FAN_CH	16
+
+#define GSC_HWMON_RESOLUTION	12
+#define GSC_HWMON_VREF		2500
+
+struct gsc_hwmon_data {
+	struct gsc_dev *gsc;
+	struct gsc_hwmon_platform_data *pdata;
+	struct regmap *regmap;
+	const struct gsc_hwmon_channel *temp_ch[GSC_HWMON_MAX_TEMP_CH];
+	const struct gsc_hwmon_channel *in_ch[GSC_HWMON_MAX_IN_CH];
+	const struct gsc_hwmon_channel *fan_ch[GSC_HWMON_MAX_FAN_CH];
+	u32 temp_config[GSC_HWMON_MAX_TEMP_CH + 1];
+	u32 in_config[GSC_HWMON_MAX_IN_CH + 1];
+	u32 fan_config[GSC_HWMON_MAX_FAN_CH + 1];
+	struct hwmon_channel_info temp_info;
+	struct hwmon_channel_info in_info;
+	struct hwmon_channel_info fan_info;
+	const struct hwmon_channel_info *info[4];
+	struct hwmon_chip_info chip;
+};
+
+static struct regmap_bus gsc_hwmon_regmap_bus = {
+	.reg_read = gsc_read,
+	.reg_write = gsc_write,
+};
+
+static const struct regmap_config gsc_hwmon_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+};
+
+static ssize_t pwm_auto_point_temp_show(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	u8 reg = hwmon->pdata->fan_base + (2 * attr->index);
+	u8 regs[2];
+	int ret;
+
+	ret = regmap_bulk_read(hwmon->regmap, reg, regs, 2);
+	if (ret)
+		return ret;
+
+	ret = regs[0] | regs[1] << 8;
+	return sprintf(buf, "%d\n", ret * 10);
+}
+
+static ssize_t pwm_auto_point_temp_store(struct device *dev,
+					 struct device_attribute *devattr,
+					 const char *buf, size_t count)
+{
+	struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	u8 reg = hwmon->pdata->fan_base + (2 * attr->index);
+	u8 regs[2];
+	long temp;
+	int err;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	temp = clamp_val(temp, 0, 10000);
+	temp = DIV_ROUND_CLOSEST(temp, 10);
+
+	regs[0] = temp & 0xff;
+	regs[1] = (temp >> 8) & 0xff;
+	err = regmap_bulk_write(hwmon->regmap, reg, regs, 2);
+	if (err)
+		return err;
+
+	return count;
+}
+
+static ssize_t pwm_auto_point_pwm_show(struct device *dev,
+				       struct device_attribute *devattr,
+				       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100);
+}
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, pwm_auto_point_temp, 0);
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point2_pwm, pwm_auto_point_pwm, 1);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, pwm_auto_point_temp, 1);
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point3_pwm, pwm_auto_point_pwm, 2);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, pwm_auto_point_temp, 2);
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point4_pwm, pwm_auto_point_pwm, 3);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, pwm_auto_point_temp, 3);
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point5_pwm, pwm_auto_point_pwm, 4);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point5_temp, pwm_auto_point_temp, 4);
+
+static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point6_pwm, pwm_auto_point_pwm, 5);
+static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point6_temp, pwm_auto_point_temp, 5);
+
+static struct attribute *gsc_hwmon_attributes[] = {
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group gsc_hwmon_group = {
+	.attrs = gsc_hwmon_attributes,
+};
+__ATTRIBUTE_GROUPS(gsc_hwmon);
+
+static int
+gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+	       int channel, long *val)
+{
+	struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
+	const struct gsc_hwmon_channel *ch;
+	int sz, ret;
+	long tmp;
+	u8 buf[3];
+
+	switch (type) {
+	case hwmon_in:
+		ch = hwmon->in_ch[channel];
+		break;
+	case hwmon_temp:
+		ch = hwmon->temp_ch[channel];
+		break;
+	case hwmon_fan:
+		ch = hwmon->fan_ch[channel];
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	sz = (ch->mode == mode_voltage_24bit) ? 3 : 2;
+	ret = regmap_bulk_read(hwmon->regmap, ch->reg, buf, sz);
+	if (ret)
+		return ret;
+
+	tmp = 0;
+	while (sz-- > 0)
+		tmp |= (buf[sz] << (8 * sz));
+
+	switch (ch->mode) {
+	case mode_temperature:
+		if (tmp > 0x8000)
+			tmp -= 0xffff;
+		tmp *= 100; /* convert to millidegrees celsius */
+		break;
+	case mode_voltage_raw:
+		tmp = clamp_val(tmp, 0, BIT(GSC_HWMON_RESOLUTION));
+		/* scale based on ref voltage and ADC resolution */
+		tmp *= GSC_HWMON_VREF;
+		tmp >>= GSC_HWMON_RESOLUTION;
+		/* scale based on optional voltage divider */
+		if (ch->vdiv[0] && ch->vdiv[1]) {
+			tmp *= (ch->vdiv[0] + ch->vdiv[1]);
+			tmp /= ch->vdiv[1];
+		}
+		/* adjust by uV offset */
+		tmp += ch->mvoffset;
+		break;
+	case mode_fan:
+		tmp *= 30; /* convert to revolutions per minute */
+		break;
+	case mode_voltage_24bit:
+	case mode_voltage_16bit:
+		/* no adjustment needed */
+		break;
+	}
+
+	*val = tmp;
+
+	return 0;
+}
+
+static int
+gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
+		      u32 attr, int channel, const char **buf)
+{
+	struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_in:
+		*buf = hwmon->in_ch[channel]->name;
+		break;
+	case hwmon_temp:
+		*buf = hwmon->temp_ch[channel]->name;
+		break;
+	case hwmon_fan:
+		*buf = hwmon->fan_ch[channel]->name;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static umode_t
+gsc_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr,
+		     int ch)
+{
+	return 0444;
+}
+
+static const struct hwmon_ops gsc_hwmon_ops = {
+	.is_visible = gsc_hwmon_is_visible,
+	.read = gsc_hwmon_read,
+	.read_string = gsc_hwmon_read_string,
+};
+
+static struct gsc_hwmon_platform_data *
+gsc_hwmon_get_devtree_pdata(struct device *dev)
+{
+	struct gsc_hwmon_platform_data *pdata;
+	struct gsc_hwmon_channel *ch;
+	struct fwnode_handle *child;
+	struct device_node *fan;
+	int nchannels;
+
+	nchannels = device_get_child_node_count(dev);
+	if (nchannels == 0)
+		return ERR_PTR(-ENODEV);
+
+	pdata = devm_kzalloc(dev,
+			     sizeof(*pdata) + nchannels * sizeof(*ch),
+			     GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+	ch = (struct gsc_hwmon_channel *)(pdata + 1);
+	pdata->channels = ch;
+	pdata->nchannels = nchannels;
+
+	/* fan controller base address */
+	fan = of_find_compatible_node(dev->parent->of_node, NULL, "gw,gsc-fan");
+	if (fan && of_property_read_u32(fan, "reg", &pdata->fan_base)) {
+		dev_err(dev, "fan node without base\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* allocate structures for channels and count instances of each type */
+	device_for_each_child_node(dev, child) {
+		if (fwnode_property_read_string(child, "label", &ch->name)) {
+			dev_err(dev, "channel without label\n");
+			fwnode_handle_put(child);
+			return ERR_PTR(-EINVAL);
+		}
+		if (fwnode_property_read_u32(child, "reg", &ch->reg)) {
+			dev_err(dev, "channel without reg\n");
+			fwnode_handle_put(child);
+			return ERR_PTR(-EINVAL);
+		}
+		if (fwnode_property_read_u32(child, "gw,mode", &ch->mode)) {
+			dev_err(dev, "channel without mode\n");
+			fwnode_handle_put(child);
+			return ERR_PTR(-EINVAL);
+		}
+		if (ch->mode > mode_max) {
+			dev_err(dev, "invalid channel mode\n");
+			fwnode_handle_put(child);
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (!fwnode_property_read_u32(child,
+					      "gw,voltage-offset-microvolt",
+					      &ch->mvoffset))
+			ch->mvoffset /= 1000;
+		fwnode_property_read_u32_array(child,
+					       "gw,voltage-divider-ohms",
+					       ch->vdiv, ARRAY_SIZE(ch->vdiv));
+		ch++;
+	}
+
+	return pdata;
+}
+
+static int gsc_hwmon_probe(struct platform_device *pdev)
+{
+	struct gsc_dev *gsc = dev_get_drvdata(pdev->dev.parent);
+	struct device *dev = &pdev->dev;
+	struct device *hwmon_dev;
+	struct gsc_hwmon_platform_data *pdata = dev_get_platdata(dev);
+	struct gsc_hwmon_data *hwmon;
+	const struct attribute_group **groups;
+	int i, i_in, i_temp, i_fan;
+
+	if (!pdata) {
+		pdata = gsc_hwmon_get_devtree_pdata(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
+	hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+	hwmon->gsc = gsc;
+	hwmon->pdata = pdata;
+
+	hwmon->regmap = devm_regmap_init(dev, &gsc_hwmon_regmap_bus,
+					 gsc->i2c_hwmon,
+					 &gsc_hwmon_regmap_config);
+	if (IS_ERR(hwmon->regmap))
+		return PTR_ERR(hwmon->regmap);
+
+	for (i = 0, i_in = 0, i_temp = 0, i_fan = 0; i < hwmon->pdata->nchannels; i++) {
+		const struct gsc_hwmon_channel *ch = &pdata->channels[i];
+
+		switch (ch->mode) {
+		case mode_temperature:
+			if (i_temp == GSC_HWMON_MAX_TEMP_CH) {
+				dev_err(gsc->dev, "too many temp channels\n");
+				return -EINVAL;
+			}
+			hwmon->temp_ch[i_temp] = ch;
+			hwmon->temp_config[i_temp] = HWMON_T_INPUT |
+						     HWMON_T_LABEL;
+			i_temp++;
+			break;
+		case mode_fan:
+			if (i_fan == GSC_HWMON_MAX_FAN_CH) {
+				dev_err(gsc->dev, "too many fan channels\n");
+				return -EINVAL;
+			}
+			hwmon->fan_ch[i_fan] = ch;
+			hwmon->fan_config[i_fan] = HWMON_F_INPUT |
+						   HWMON_F_LABEL;
+			i_fan++;
+			break;
+		case mode_voltage_24bit:
+		case mode_voltage_16bit:
+		case mode_voltage_raw:
+			if (i_in == GSC_HWMON_MAX_IN_CH) {
+				dev_err(gsc->dev, "too many input channels\n");
+				return -EINVAL;
+			}
+			hwmon->in_ch[i_in] = ch;
+			hwmon->in_config[i_in] =
+				HWMON_I_INPUT | HWMON_I_LABEL;
+			i_in++;
+			break;
+		default:
+			dev_err(gsc->dev, "invalid mode: %d\n", ch->mode);
+			return -EINVAL;
+		}
+	}
+
+	/* setup config structures */
+	hwmon->chip.ops = &gsc_hwmon_ops;
+	hwmon->chip.info = hwmon->info;
+	hwmon->info[0] = &hwmon->temp_info;
+	hwmon->info[1] = &hwmon->in_info;
+	hwmon->info[2] = &hwmon->fan_info;
+	hwmon->temp_info.type = hwmon_temp;
+	hwmon->temp_info.config = hwmon->temp_config;
+	hwmon->in_info.type = hwmon_in;
+	hwmon->in_info.config = hwmon->in_config;
+	hwmon->fan_info.type = hwmon_fan;
+	hwmon->fan_info.config = hwmon->fan_config;
+
+	groups = pdata->fan_base ? gsc_hwmon_groups : NULL;
+	hwmon_dev = devm_hwmon_device_register_with_info(dev,
+							 KBUILD_MODNAME, hwmon,
+							 &hwmon->chip, groups);
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id gsc_hwmon_of_match[] = {
+	{ .compatible = "gw,gsc-adc", },
+	{}
+};
+
+static struct platform_driver gsc_hwmon_driver = {
+	.driver = {
+		.name = "gsc-hwmon",
+		.of_match_table = gsc_hwmon_of_match,
+	},
+	.probe = gsc_hwmon_probe,
+};
+
+module_platform_driver(gsc_hwmon_driver);
+
+MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
+MODULE_DESCRIPTION("GSC hardware monitor driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/hwmon/hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/hwmon.c
@@ -51,6 +51,7 @@
 
 #define to_hwmon_attr(d) \
 	container_of(d, struct hwmon_device_attribute, dev_attr)
+#define to_dev_attr(a) container_of(a, struct device_attribute, attr)
 
 /*
  * Thermal zone information
@@ -58,7 +59,7 @@
  * also provides the sensor index.
  */
 struct hwmon_thermal_data {
-	struct hwmon_device *hwdev;	/* Reference to hwmon device */
+	struct device *dev;		/* Reference to hwmon device */
 	int index;			/* sensor index */
 };
 
@@ -95,9 +96,27 @@
 	NULL
 };
 
+static void hwmon_free_attrs(struct attribute **attrs)
+{
+	int i;
+
+	for (i = 0; attrs[i]; i++) {
+		struct device_attribute *dattr = to_dev_attr(attrs[i]);
+		struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr);
+
+		kfree(hattr);
+	}
+	kfree(attrs);
+}
+
 static void hwmon_dev_release(struct device *dev)
 {
-	kfree(to_hwmon_device(dev));
+	struct hwmon_device *hwdev = to_hwmon_device(dev);
+
+	if (hwdev->group.attrs)
+		hwmon_free_attrs(hwdev->group.attrs);
+	kfree(hwdev->groups);
+	kfree(hwdev);
 }
 
 static struct class hwmon_class = {
@@ -119,11 +138,11 @@
 static int hwmon_thermal_get_temp(void *data, int *temp)
 {
 	struct hwmon_thermal_data *tdata = data;
-	struct hwmon_device *hwdev = tdata->hwdev;
+	struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
 	int ret;
 	long t;
 
-	ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input,
+	ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input,
 				     tdata->index, &t);
 	if (ret < 0)
 		return ret;
@@ -137,8 +156,7 @@
 	.get_temp = hwmon_thermal_get_temp,
 };
 
-static int hwmon_thermal_add_sensor(struct device *dev,
-				    struct hwmon_device *hwdev, int index)
+static int hwmon_thermal_add_sensor(struct device *dev, int index)
 {
 	struct hwmon_thermal_data *tdata;
 	struct thermal_zone_device *tzd;
@@ -147,10 +165,10 @@
 	if (!tdata)
 		return -ENOMEM;
 
-	tdata->hwdev = hwdev;
+	tdata->dev = dev;
 	tdata->index = index;
 
-	tzd = devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata,
+	tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata,
 						   &hwmon_thermal_ops);
 	/*
 	 * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
@@ -162,8 +180,7 @@
 	return 0;
 }
 #else
-static int hwmon_thermal_add_sensor(struct device *dev,
-				    struct hwmon_device *hwdev, int index)
+static int hwmon_thermal_add_sensor(struct device *dev, int index)
 {
 	return 0;
 }
@@ -250,8 +267,7 @@
 	       (type == hwmon_fan && attr == hwmon_fan_label);
 }
 
-static struct attribute *hwmon_genattr(struct device *dev,
-				       const void *drvdata,
+static struct attribute *hwmon_genattr(const void *drvdata,
 				       enum hwmon_sensor_types type,
 				       u32 attr,
 				       int index,
@@ -279,7 +295,7 @@
 	if ((mode & 0222) && !ops->write)
 		return ERR_PTR(-EINVAL);
 
-	hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL);
+	hattr = kzalloc(sizeof(*hattr), GFP_KERNEL);
 	if (!hattr)
 		return ERR_PTR(-ENOMEM);
 
@@ -492,8 +508,7 @@
 	return n;
 }
 
-static int hwmon_genattrs(struct device *dev,
-			  const void *drvdata,
+static int hwmon_genattrs(const void *drvdata,
 			  struct attribute **attrs,
 			  const struct hwmon_ops *ops,
 			  const struct hwmon_channel_info *info)
@@ -519,7 +534,7 @@
 			attr_mask &= ~BIT(attr);
 			if (attr >= template_size)
 				return -EINVAL;
-			a = hwmon_genattr(dev, drvdata, info->type, attr, i,
+			a = hwmon_genattr(drvdata, info->type, attr, i,
 					  templates[attr], ops);
 			if (IS_ERR(a)) {
 				if (PTR_ERR(a) != -ENOENT)
@@ -533,8 +548,7 @@
 }
 
 static struct attribute **
-__hwmon_create_attrs(struct device *dev, const void *drvdata,
-		     const struct hwmon_chip_info *chip)
+__hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip)
 {
 	int ret, i, aindex = 0, nattrs = 0;
 	struct attribute **attrs;
@@ -545,15 +559,17 @@
 	if (nattrs == 0)
 		return ERR_PTR(-EINVAL);
 
-	attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL);
+	attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL);
 	if (!attrs)
 		return ERR_PTR(-ENOMEM);
 
 	for (i = 0; chip->info[i]; i++) {
-		ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops,
+		ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops,
 				     chip->info[i]);
-		if (ret < 0)
+		if (ret < 0) {
+			hwmon_free_attrs(attrs);
 			return ERR_PTR(ret);
+		}
 		aindex += ret;
 	}
 
@@ -595,14 +611,13 @@
 			for (i = 0; groups[i]; i++)
 				ngroups++;
 
-		hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups),
-					     GFP_KERNEL);
+		hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL);
 		if (!hwdev->groups) {
 			err = -ENOMEM;
 			goto free_hwmon;
 		}
 
-		attrs = __hwmon_create_attrs(dev, drvdata, chip);
+		attrs = __hwmon_create_attrs(drvdata, chip);
 		if (IS_ERR(attrs)) {
 			err = PTR_ERR(attrs);
 			goto free_hwmon;
@@ -630,8 +645,10 @@
 	dev_set_drvdata(hdev, drvdata);
 	dev_set_name(hdev, HWMON_ID_FORMAT, id);
 	err = device_register(hdev);
-	if (err)
-		goto free_hwmon;
+	if (err) {
+		put_device(hdev);
+		goto ida_remove;
+	}
 
 	if (dev && dev->of_node && chip && chip->ops->read &&
 	    chip->info[0]->type == hwmon_chip &&
@@ -647,8 +664,7 @@
 							   hwmon_temp_input, j))
 					continue;
 				if (info[i]->config[j] & HWMON_T_INPUT) {
-					err = hwmon_thermal_add_sensor(dev,
-								hwdev, j);
+					err = hwmon_thermal_add_sensor(hdev, j);
 					if (err) {
 						device_unregister(hdev);
 						/*
@@ -667,7 +683,7 @@
 	return hdev;
 
 free_hwmon:
-	kfree(hwdev);
+	hwmon_dev_release(hdev);
 ida_remove:
 	ida_simple_remove(&hwmon_ida, id);
 	return ERR_PTR(err);
--- linux-ein-5.4.0.orig/drivers/hwmon/i5500_temp.c
+++ linux-ein-5.4.0/drivers/hwmon/i5500_temp.c
@@ -108,7 +108,7 @@
 	u32 tstimer;
 	s8 tsfsc;
 
-	err = pci_enable_device(pdev);
+	err = pcim_enable_device(pdev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to enable device\n");
 		return err;
--- linux-ein-5.4.0.orig/drivers/hwmon/ibmaem.c
+++ linux-ein-5.4.0/drivers/hwmon/ibmaem.c
@@ -550,7 +550,7 @@
 
 	res = platform_device_add(data->pdev);
 	if (res)
-		goto ipmi_err;
+		goto dev_add_err;
 
 	platform_set_drvdata(data->pdev, data);
 
@@ -598,7 +598,9 @@
 	ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
 	platform_set_drvdata(data->pdev, NULL);
-	platform_device_unregister(data->pdev);
+	platform_device_del(data->pdev);
+dev_add_err:
+	platform_device_put(data->pdev);
 dev_err:
 	ida_simple_remove(&aem_ida, data->id);
 id_err:
@@ -690,7 +692,7 @@
 
 	res = platform_device_add(data->pdev);
 	if (res)
-		goto ipmi_err;
+		goto dev_add_err;
 
 	platform_set_drvdata(data->pdev, data);
 
@@ -738,7 +740,9 @@
 	ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
 	platform_set_drvdata(data->pdev, NULL);
-	platform_device_unregister(data->pdev);
+	platform_device_del(data->pdev);
+dev_add_err:
+	platform_device_put(data->pdev);
 dev_err:
 	ida_simple_remove(&aem_ida, data->id);
 id_err:
--- linux-ein-5.4.0.orig/drivers/hwmon/ibmpex.c
+++ linux-ein-5.4.0/drivers/hwmon/ibmpex.c
@@ -502,6 +502,7 @@
 	return;
 
 out_register:
+	list_del(&data->list);
 	hwmon_device_unregister(data->hwmon_dev);
 out_user:
 	ipmi_destroy_user(data->user);
--- linux-ein-5.4.0.orig/drivers/hwmon/ina3221.c
+++ linux-ein-5.4.0/drivers/hwmon/ina3221.c
@@ -403,7 +403,7 @@
 
 	/* For enabling routine, increase refcount and resume() at first */
 	if (enable) {
-		ret = pm_runtime_get_sync(ina->pm_dev);
+		ret = pm_runtime_resume_and_get(ina->pm_dev);
 		if (ret < 0) {
 			dev_err(dev, "Failed to get PM runtime\n");
 			return ret;
@@ -672,7 +672,7 @@
 		return ret;
 	} else if (val > INA3221_CHANNEL3) {
 		dev_err(dev, "invalid reg %d of %pOFn\n", val, child);
-		return ret;
+		return -EINVAL;
 	}
 
 	input = &ina->inputs[val];
--- linux-ein-5.4.0.orig/drivers/hwmon/it87.c
+++ linux-ein-5.4.0/drivers/hwmon/it87.c
@@ -486,6 +486,8 @@
 #define has_pwm_freq2(data)	((data)->features & FEAT_PWM_FREQ2)
 #define has_six_temp(data)	((data)->features & FEAT_SIX_TEMP)
 #define has_vin3_5v(data)	((data)->features & FEAT_VIN3_5V)
+#define has_scaling(data)	((data)->features & (FEAT_12MV_ADC | \
+						     FEAT_10_9MV_ADC))
 
 struct it87_sio_data {
 	int sioaddr;
@@ -3098,7 +3100,7 @@
 			 "Detected broken BIOS defaults, disabling PWM interface\n");
 
 	/* Starting with IT8721F, we handle scaling of internal voltages */
-	if (has_12mv_adc(data)) {
+	if (has_scaling(data)) {
 		if (sio_data->internal & BIT(0))
 			data->in_scaled |= BIT(3);	/* in3 is AVCC */
 		if (sio_data->internal & BIT(1))
--- linux-ein-5.4.0.orig/drivers/hwmon/jc42.c
+++ linux-ein-5.4.0/drivers/hwmon/jc42.c
@@ -506,7 +506,7 @@
 	}
 	data->config = config;
 
-	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "jc42",
 							 data, &jc42_chip_info,
 							 NULL);
 	return PTR_ERR_OR_ZERO(hwmon_dev);
--- linux-ein-5.4.0.orig/drivers/hwmon/k10temp.c
+++ linux-ein-5.4.0/drivers/hwmon/k10temp.c
@@ -349,6 +349,7 @@
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
 	{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
 	{}
--- linux-ein-5.4.0.orig/drivers/hwmon/lm80.c
+++ linux-ein-5.4.0/drivers/hwmon/lm80.c
@@ -597,7 +597,6 @@
 	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)
@@ -610,14 +609,8 @@
 	lm80_init_client(client);
 
 	/* A few vars need to be filled upon startup */
-	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;
+	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));
 
 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 							   data, lm80_groups);
--- linux-ein-5.4.0.orig/drivers/hwmon/lm90.c
+++ linux-ein-5.4.0/drivers/hwmon/lm90.c
@@ -35,6 +35,15 @@
  * explicitly as max6659, or if its address is not 0x4c.
  * These chips lack the remote temperature offset feature.
  *
+ * This driver also supports the MAX6654 chip made by Maxim. This chip can be
+ * at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is similar
+ * to MAX6657/MAX6658/MAX6659, but does not support critical temperature
+ * limits. Extended range is available by setting the configuration register
+ * accordingly, and is done during initialization. Extended precision is only
+ * available at conversion rates of 1 Hz and slower. Note that extended
+ * precision is not enabled by default, as this driver initializes all chips
+ * to 2 Hz by design.
+ *
  * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
  * MAX6692 chips made by Maxim.  These are again similar to the LM86,
  * but they use unsigned temperature values and can report temperatures
@@ -61,10 +70,10 @@
  * This driver also supports the G781 from GMT. This device is compatible
  * with the ADM1032.
  *
- * This driver also supports TMP451 from Texas Instruments. This device is
- * supported in both compatibility and extended mode. It's mostly compatible
- * with ADT7461 except for local temperature low byte register and max
- * conversion rate.
+ * This driver also supports TMP451 and TMP461 from Texas Instruments.
+ * Those devices are supported in both compatibility and extended mode.
+ * They are mostly compatible with ADT7461 except for local temperature
+ * low byte register and max conversion rate.
  *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
@@ -94,8 +103,8 @@
  * have address 0x4d.
  * MAX6647 has address 0x4e.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e.
- * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
- * 0x4c, 0x4d or 0x4e.
+ * MAX6654, MAX6680, and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29,
+ * 0x2a, 0x2b, 0x4c, 0x4d or 0x4e.
  * SA56004 can have address 0x48 through 0x4F.
  */
 
@@ -104,7 +113,7 @@
 	0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-	max6646, w83l771, max6696, sa56004, g781, tmp451 };
+	max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 };
 
 /*
  * The LM90 registers
@@ -145,7 +154,7 @@
 #define LM90_REG_R_TCRIT_HYST		0x21
 #define LM90_REG_W_TCRIT_HYST		0x21
 
-/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */
+/* MAX6646/6647/6649/6654/6657/6658/6659/6695/6696 registers */
 
 #define MAX6657_REG_R_LOCAL_TEMPL	0x11
 #define MAX6696_REG_R_STATUS2		0x12
@@ -160,8 +169,12 @@
 
 #define LM90_MAX_CONVRATE_MS	16000	/* Maximum conversion rate in ms */
 
-/* TMP451 registers */
+/* TMP451/TMP461 registers */
 #define TMP451_REG_R_LOCAL_TEMPL	0x15
+#define TMP451_REG_CONALERT		0x22
+
+#define TMP461_REG_CHEN			0x16
+#define TMP461_REG_DFC			0x24
 
 /*
  * Device flags
@@ -174,7 +187,10 @@
 #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
 #define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
 #define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
-#define LM90_PAUSE_FOR_CONFIG	(1 << 8) /* Pause conversion for config	*/
+#define LM90_HAVE_EXTENDED_TEMP	(1 << 8) /* extended temperature support*/
+#define LM90_PAUSE_FOR_CONFIG	(1 << 9) /* Pause conversion for config	*/
+#define LM90_HAVE_CRIT		(1 << 10)/* Chip supports CRIT/OVERT register	*/
+#define LM90_HAVE_CRIT_ALRM_SWP	(1 << 11)/* critical alarm bits swapped	*/
 
 /* LM90 status */
 #define LM90_STATUS_LTHRM	(1 << 0) /* local THERM limit tripped */
@@ -184,6 +200,7 @@
 #define LM90_STATUS_RHIGH	(1 << 4) /* remote high temp limit tripped */
 #define LM90_STATUS_LLOW	(1 << 5) /* local low temp limit tripped */
 #define LM90_STATUS_LHIGH	(1 << 6) /* local high temp limit tripped */
+#define LM90_STATUS_BUSY	(1 << 7) /* conversion is ongoing */
 
 #define MAX6696_STATUS2_R2THRM	(1 << 1) /* remote2 THERM limit tripped */
 #define MAX6696_STATUS2_R2OPEN	(1 << 2) /* remote2 is an open circuit */
@@ -209,6 +226,7 @@
 	{ "max6646", max6646 },
 	{ "max6647", max6646 },
 	{ "max6649", max6646 },
+	{ "max6654", max6654 },
 	{ "max6657", max6657 },
 	{ "max6658", max6657 },
 	{ "max6659", max6659 },
@@ -220,6 +238,7 @@
 	{ "w83l771", w83l771 },
 	{ "sa56004", sa56004 },
 	{ "tmp451", tmp451 },
+	{ "tmp461", tmp461 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm90_id);
@@ -270,6 +289,10 @@
 		.data = (void *)max6646
 	},
 	{
+		.compatible = "dallas,max6654",
+		.data = (void *)max6654
+	},
+	{
 		.compatible = "dallas,max6657",
 		.data = (void *)max6657
 	},
@@ -313,6 +336,10 @@
 		.compatible = "ti,tmp451",
 		.data = (void *)tmp451
 	},
+	{
+		.compatible = "ti,tmp461",
+		.data = (void *)tmp461
+	},
 	{ },
 };
 MODULE_DEVICE_TABLE(of, lm90_of_match);
@@ -331,80 +358,99 @@
 static const struct lm90_params lm90_params[] = {
 	[adm1032] = {
 		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-		  | LM90_HAVE_BROKEN_ALERT,
+		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 10,
 	},
 	[adt7461] = {
 		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-		  | LM90_HAVE_BROKEN_ALERT,
+		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
+		  | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 10,
 	},
 	[g781] = {
 		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-		  | LM90_HAVE_BROKEN_ALERT,
+		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
-		.max_convrate = 8,
+		.max_convrate = 7,
 	},
 	[lm86] = {
-		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7b,
 		.max_convrate = 9,
 	},
 	[lm90] = {
-		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7b,
 		.max_convrate = 9,
 	},
 	[lm99] = {
-		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7b,
 		.max_convrate = 9,
 	},
 	[max6646] = {
+		.flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 6,
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
 	},
+	[max6654] = {
+		.flags = LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 7,
+		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+	},
 	[max6657] = {
-		.flags = LM90_PAUSE_FOR_CONFIG,
+		.flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 8,
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
 	},
 	[max6659] = {
-		.flags = LM90_HAVE_EMERGENCY,
+		.flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 8,
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
 	},
 	[max6680] = {
-		.flags = LM90_HAVE_OFFSET,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
+		  | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 7,
 	},
 	[max6696] = {
 		.flags = LM90_HAVE_EMERGENCY
-		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
+		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT,
 		.alert_alarms = 0x1c7c,
 		.max_convrate = 6,
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
 	},
 	[w83l771] = {
-		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 8,
 	},
 	[sa56004] = {
-		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7b,
 		.max_convrate = 9,
 		.reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
 	},
 	[tmp451] = {
 		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-		  | LM90_HAVE_BROKEN_ALERT,
+		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 9,
+		.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
+	},
+	[tmp461] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
 		.alert_alarms = 0x7c,
 		.max_convrate = 9,
 		.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
@@ -632,20 +678,22 @@
 	struct i2c_client *client = data->client;
 	int val;
 
-	val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
-	if (val < 0)
-		return val;
-	data->temp8[LOCAL_CRIT] = val;
+	if (data->flags & LM90_HAVE_CRIT) {
+		val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
+		if (val < 0)
+			return val;
+		data->temp8[LOCAL_CRIT] = val;
 
-	val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
-	if (val < 0)
-		return val;
-	data->temp8[REMOTE_CRIT] = val;
+		val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
+		if (val < 0)
+			return val;
+		data->temp8[REMOTE_CRIT] = val;
 
-	val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
-	if (val < 0)
-		return val;
-	data->temp_hyst = val;
+		val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
+		if (val < 0)
+			return val;
+		data->temp_hyst = val;
+	}
 
 	val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
 	if (val < 0)
@@ -773,7 +821,7 @@
 		val = lm90_read_reg(client, LM90_REG_R_STATUS);
 		if (val < 0)
 			return val;
-		data->alarms = val;	/* lower 8 bit of alarms */
+		data->alarms = val & ~LM90_STATUS_BUSY;
 
 		if (data->kind == max6696) {
 			val = lm90_select_remote_channel(data, 1);
@@ -979,7 +1027,7 @@
 	s16 temp11 = data->temp11[index];
 	int temp;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		temp = temp_from_u16_adt7461(data, temp11);
 	else if (data->kind == max6646)
 		temp = temp_from_u16(temp11);
@@ -1013,7 +1061,7 @@
 	if (data->kind == lm99 && index <= 2)
 		val -= 16000;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		data->temp11[index] = temp_to_u16_adt7461(data, val);
 	else if (data->kind == max6646)
 		data->temp11[index] = temp_to_u8(val) << 8;
@@ -1040,7 +1088,7 @@
 	s8 temp8 = data->temp8[index];
 	int temp;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		temp = temp_from_u8_adt7461(data, temp8);
 	else if (data->kind == max6646)
 		temp = temp_from_u8(temp8);
@@ -1073,7 +1121,7 @@
 	if (data->kind == lm99 && index == 3)
 		val -= 16000;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		data->temp8[index] = temp_to_u8_adt7461(data, val);
 	else if (data->kind == max6646)
 		data->temp8[index] = temp_to_u8(val);
@@ -1091,7 +1139,7 @@
 {
 	int temp;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		temp = temp_from_u8_adt7461(data, data->temp8[index]);
 	else if (data->kind == max6646)
 		temp = temp_from_u8(data->temp8[index]);
@@ -1111,7 +1159,7 @@
 	int temp;
 	int err;
 
-	if (data->kind == adt7461 || data->kind == tmp451)
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
 		temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
 	else if (data->kind == max6646)
 		temp = temp_from_u8(data->temp8[LOCAL_CRIT]);
@@ -1147,6 +1195,7 @@
 static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 };
 static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 };
 static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 };
+static const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 };
 static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 };
 static const u8 lm90_fault_bits[3] = { 0, 2, 10 };
 
@@ -1172,7 +1221,10 @@
 		*val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1;
 		break;
 	case hwmon_temp_crit_alarm:
-		*val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
+		if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
+			*val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1;
+		else
+			*val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
 		break;
 	case hwmon_temp_emergency_alarm:
 		*val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1;
@@ -1420,12 +1472,11 @@
 	if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
 		return -ENODEV;
 
-	if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) {
+	if (man_id == 0x01 || man_id == 0x5C || man_id == 0xA1) {
 		config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2);
 		if (config2 < 0)
 			return -ENODEV;
-	} else
-		config2 = 0;		/* Make compiler happy */
+	}
 
 	if ((address == 0x4C || address == 0x4D)
 	 && man_id == 0x01) { /* National Semiconductor */
@@ -1557,6 +1608,16 @@
 		 && (config1 & 0x3f) == 0x00
 		 && convrate <= 0x07) {
 			name = "max6646";
+		} else
+		/*
+		 * The chip_id of the MAX6654 holds the revision of the chip.
+		 * The lowest 3 bits of the config1 register are unused and
+		 * should return zero when read.
+		 */
+		if (chip_id == 0x08
+		 && (config1 & 0x07) == 0x00
+		 && convrate <= 0x07) {
+			name = "max6654";
 		}
 	} else
 	if (address == 0x4C
@@ -1589,18 +1650,26 @@
 		 && convrate <= 0x08)
 			name = "g781";
 	} else
-	if (address == 0x4C
-	 && man_id == 0x55) { /* Texas Instruments */
-		int local_ext;
+	if (man_id == 0x55 && chip_id == 0x00 &&
+	    (config1 & 0x1B) == 0x00 && convrate <= 0x09) {
+		int local_ext, conalert, chen, dfc;
 
 		local_ext = i2c_smbus_read_byte_data(client,
 						     TMP451_REG_R_LOCAL_TEMPL);
-
-		if (chip_id == 0x00 /* TMP451 */
-		 && (config1 & 0x1B) == 0x00
-		 && convrate <= 0x09
-		 && (local_ext & 0x0F) == 0x00)
-			name = "tmp451";
+		conalert = i2c_smbus_read_byte_data(client,
+						    TMP451_REG_CONALERT);
+		chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN);
+		dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC);
+
+		if ((local_ext & 0x0F) == 0x00 &&
+		    (conalert & 0xf1) == 0x01 &&
+		    (chen & 0xfc) == 0x00 &&
+		    (dfc & 0xfc) == 0x00) {
+			if (address == 0x4c && !(chen & 0x03))
+				name = "tmp451";
+			else if (address >= 0x48 && address <= 0x4f)
+				name = "tmp461";
+		}
 	}
 
 	if (!name) { /* identification failed */
@@ -1647,7 +1716,7 @@
 	lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
 
 	/* Check Temperature Range Select */
-	if (data->kind == adt7461 || data->kind == tmp451) {
+	if (data->flags & LM90_HAVE_EXTENDED_TEMP) {
 		if (config & 0x04)
 			data->flags |= LM90_FLAG_ADT7461_EXT;
 	}
@@ -1661,6 +1730,15 @@
 		config |= 0x18;
 
 	/*
+	 * Put MAX6654 into extended range (0x20, extend minimum range from
+	 * 0 degrees to -64 degrees). Note that extended resolution is not
+	 * possible on the MAX6654 unless conversion rate is set to 1 Hz or
+	 * slower, which is intentionally not done by default.
+	 */
+	if (data->kind == max6654)
+		config |= 0x20;
+
+	/*
 	 * Select external channel 0 for max6695/96
 	 */
 	if (data->kind == max6696)
@@ -1806,11 +1884,14 @@
 	info->config = data->channel_config;
 
 	data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-		HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
-		HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM;
+		HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM;
 	data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-		HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
-		HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT;
+		HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT;
+
+	if (data->flags & LM90_HAVE_CRIT) {
+		data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
+		data->channel_config[1] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
+	}
 
 	if (data->flags & LM90_HAVE_OFFSET)
 		data->channel_config[1] |= HWMON_T_OFFSET;
--- linux-ein-5.4.0.orig/drivers/hwmon/ltc2945.c
+++ linux-ein-5.4.0/drivers/hwmon/ltc2945.c
@@ -248,6 +248,8 @@
 
 	/* convert to register value, then clamp and write result */
 	regval = ltc2945_val_to_reg(dev, reg, val);
+	if (regval < 0)
+		return regval;
 	if (is_power_reg(reg)) {
 		regval = clamp_val(regval, 0, 0xffffff);
 		regbuf[0] = regval >> 16;
--- linux-ein-5.4.0.orig/drivers/hwmon/max31722.c
+++ linux-ein-5.4.0/drivers/hwmon/max31722.c
@@ -6,7 +6,6 @@
  * Copyright (c) 2016, Intel Corporation.
  */
 
-#include <linux/acpi.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
@@ -133,20 +132,12 @@
 	{"max31723", 0},
 	{}
 };
-
-static const struct acpi_device_id __maybe_unused max31722_acpi_id[] = {
-	{"MAX31722", 0},
-	{"MAX31723", 0},
-	{}
-};
-
 MODULE_DEVICE_TABLE(spi, max31722_spi_id);
 
 static struct spi_driver max31722_driver = {
 	.driver = {
 		.name = "max31722",
 		.pm = &max31722_pm_ops,
-		.acpi_match_table = ACPI_PTR(max31722_acpi_id),
 	},
 	.probe =            max31722_probe,
 	.remove =           max31722_remove,
--- linux-ein-5.4.0.orig/drivers/hwmon/max31790.c
+++ linux-ein-5.4.0/drivers/hwmon/max31790.c
@@ -27,6 +27,7 @@
 
 /* Fan Config register bits */
 #define MAX31790_FAN_CFG_RPM_MODE	0x80
+#define MAX31790_FAN_CFG_CTRL_MON	0x10
 #define MAX31790_FAN_CFG_TACH_INPUT_EN	0x08
 #define MAX31790_FAN_CFG_TACH_INPUT	0x01
 
@@ -104,7 +105,7 @@
 				data->tach[NR_CHANNEL + i] = rv;
 			} else {
 				rv = i2c_smbus_read_word_swapped(client,
-						MAX31790_REG_PWMOUT(i));
+						MAX31790_REG_PWM_DUTY_CYCLE(i));
 				if (rv < 0)
 					goto abort;
 				data->pwm[i] = rv;
@@ -170,7 +171,7 @@
 
 	switch (attr) {
 	case hwmon_fan_input:
-		sr = get_tach_period(data->fan_dynamics[channel]);
+		sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
 		rpm = RPM_FROM_REG(data->tach[channel], sr);
 		*val = rpm;
 		return 0;
@@ -271,12 +272,12 @@
 		*val = data->pwm[channel] >> 8;
 		return 0;
 	case hwmon_pwm_enable:
-		if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
+		if (fan_config & MAX31790_FAN_CFG_CTRL_MON)
+			*val = 0;
+		else if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
 			*val = 2;
-		else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN)
-			*val = 1;
 		else
-			*val = 0;
+			*val = 1;
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -299,31 +300,41 @@
 			err = -EINVAL;
 			break;
 		}
-		data->pwm[channel] = val << 8;
+		data->valid = false;
 		err = i2c_smbus_write_word_swapped(client,
 						   MAX31790_REG_PWMOUT(channel),
-						   data->pwm[channel]);
+						   val << 8);
 		break;
 	case hwmon_pwm_enable:
 		fan_config = data->fan_config[channel];
 		if (val == 0) {
-			fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN |
-					MAX31790_FAN_CFG_RPM_MODE);
+			fan_config |= MAX31790_FAN_CFG_CTRL_MON;
+			/*
+			 * Disable RPM mode; otherwise disabling fan speed
+			 * monitoring is not possible.
+			 */
+			fan_config &= ~MAX31790_FAN_CFG_RPM_MODE;
 		} else if (val == 1) {
-			fan_config = (fan_config |
-				      MAX31790_FAN_CFG_TACH_INPUT_EN) &
-				     ~MAX31790_FAN_CFG_RPM_MODE;
+			fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE);
 		} else if (val == 2) {
-			fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN |
-				      MAX31790_FAN_CFG_RPM_MODE;
+			fan_config &= ~MAX31790_FAN_CFG_CTRL_MON;
+			/*
+			 * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its
+			 * own if MAX31790_FAN_CFG_RPM_MODE is set.
+			 * Do it here as well to reflect the actual register
+			 * value in the cache.
+			 */
+			fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN);
 		} else {
 			err = -EINVAL;
 			break;
 		}
-		data->fan_config[channel] = fan_config;
-		err = i2c_smbus_write_byte_data(client,
-					MAX31790_REG_FAN_CONFIG(channel),
-					fan_config);
+		if (fan_config != data->fan_config[channel]) {
+			err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel),
+							fan_config);
+			if (!err)
+				data->fan_config[channel] = fan_config;
+		}
 		break;
 	default:
 		err = -EOPNOTSUPP;
--- linux-ein-5.4.0.orig/drivers/hwmon/max6697.c
+++ linux-ein-5.4.0/drivers/hwmon/max6697.c
@@ -38,8 +38,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))
 
@@ -562,12 +563,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-ein-5.4.0.orig/drivers/hwmon/mlxreg-fan.c
+++ linux-ein-5.4.0/drivers/hwmon/mlxreg-fan.c
@@ -127,6 +127,12 @@
 			if (err)
 				return err;
 
+			if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) {
+				/* FAN is broken - return zero for FAN speed. */
+				*val = 0;
+				return 0;
+			}
+
 			*val = MLXREG_FAN_GET_RPM(regval, fan->divider,
 						  fan->samples);
 			break;
@@ -291,8 +297,8 @@
 {
 	struct mlxreg_fan *fan = cdev->devdata;
 	unsigned long cur_state;
+	int i, config = 0;
 	u32 regval;
-	int i;
 	int err;
 
 	/*
@@ -305,6 +311,12 @@
 	 * overwritten.
 	 */
 	if (state >= MLXREG_FAN_SPEED_MIN && state <= MLXREG_FAN_SPEED_MAX) {
+		/*
+		 * This is configuration change, which is only supported through sysfs.
+		 * For configuration non-zero value is to be returned to avoid thermal
+		 * statistics update.
+		 */
+		config = 1;
 		state -= MLXREG_FAN_MAX_STATE;
 		for (i = 0; i < state; i++)
 			fan->cooling_levels[i] = state;
@@ -319,7 +331,7 @@
 
 		cur_state = MLXREG_FAN_PWM_DUTY2STATE(regval);
 		if (state < cur_state)
-			return 0;
+			return config;
 
 		state = cur_state;
 	}
@@ -335,7 +347,7 @@
 		dev_err(fan->dev, "Failed to write PWM duty\n");
 		return err;
 	}
-	return 0;
+	return config;
 }
 
 static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = {
--- linux-ein-5.4.0.orig/drivers/hwmon/nct6775.c
+++ linux-ein-5.4.0/drivers/hwmon/nct6775.c
@@ -786,13 +786,13 @@
 	"Agent1 Dimm1",
 	"BYTE_TEMP0",
 	"BYTE_TEMP1",
-	"",
-	"",
+	"PECI Agent 0 Calibration",	/* undocumented */
+	"PECI Agent 1 Calibration",	/* undocumented */
 	"",
 	"Virtual_TEMP"
 };
 
-#define NCT6798_TEMP_MASK	0x8fff0ffe
+#define NCT6798_TEMP_MASK	0xbfff0ffe
 #define NCT6798_VIRT_TEMP_MASK	0x80000c00
 
 /* NCT6102D/NCT6106D specific data */
--- linux-ein-5.4.0.orig/drivers/hwmon/nct7802.c
+++ linux-ein-5.4.0/drivers/hwmon/nct7802.c
@@ -23,8 +23,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 };
@@ -58,6 +58,8 @@
 struct nct7802_data {
 	struct regmap *regmap;
 	struct mutex access_lock; /* for multi-byte read and write operations */
+	u8 in_status;
+	struct mutex in_alarm_lock;
 };
 
 static ssize_t temp_type_show(struct device *dev,
@@ -368,6 +370,66 @@
 	return err ? : count;
 }
 
+static ssize_t in_alarm_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct7802_data *data = dev_get_drvdata(dev);
+	int volt, min, max, ret;
+	unsigned int val;
+
+	mutex_lock(&data->in_alarm_lock);
+
+	/*
+	 * The SMI Voltage status register is the only register giving a status
+	 * for voltages. A bit is set for each input crossing a threshold, in
+	 * both direction, but the "inside" or "outside" limits info is not
+	 * available. Also this register is cleared on read.
+	 * Note: this is not explicitly spelled out in the datasheet, but
+	 * from experiment.
+	 * To deal with this we use a status cache with one validity bit and
+	 * one status bit for each input. Validity is cleared at startup and
+	 * each time the register reports a change, and the status is processed
+	 * by software based on current input value and limits.
+	 */
+	ret = regmap_read(data->regmap, 0x1e, &val); /* SMI Voltage status */
+	if (ret < 0)
+		goto abort;
+
+	/* invalidate cached status for all inputs crossing a threshold */
+	data->in_status &= ~((val & 0x0f) << 4);
+
+	/* if cached status for requested input is invalid, update it */
+	if (!(data->in_status & (0x10 << sattr->index))) {
+		ret = nct7802_read_voltage(data, sattr->nr, 0);
+		if (ret < 0)
+			goto abort;
+		volt = ret;
+
+		ret = nct7802_read_voltage(data, sattr->nr, 1);
+		if (ret < 0)
+			goto abort;
+		min = ret;
+
+		ret = nct7802_read_voltage(data, sattr->nr, 2);
+		if (ret < 0)
+			goto abort;
+		max = ret;
+
+		if (volt < min || volt > max)
+			data->in_status |= (1 << sattr->index);
+		else
+			data->in_status &= ~(1 << sattr->index);
+
+		data->in_status |= 0x10 << sattr->index;
+	}
+
+	ret = sprintf(buf, "%u\n", !!(data->in_status & (1 << sattr->index)));
+abort:
+	mutex_unlock(&data->in_alarm_lock);
+	return ret;
+}
+
 static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
@@ -646,7 +708,7 @@
 	if (index >= 38 && index < 46 && !(reg & 0x01))		/* PECI 0 */
 		return 0;
 
-	if (index >= 0x46 && (!(reg & 0x02)))			/* PECI 1 */
+	if (index >= 46 && !(reg & 0x02))			/* PECI 1 */
 		return 0;
 
 	return attr->mode;
@@ -660,7 +722,7 @@
 static SENSOR_DEVICE_ATTR_2_RO(in0_input, in, 0, 0);
 static SENSOR_DEVICE_ATTR_2_RW(in0_min, in, 0, 1);
 static SENSOR_DEVICE_ATTR_2_RW(in0_max, in, 0, 2);
-static SENSOR_DEVICE_ATTR_2_RO(in0_alarm, alarm, 0x1e, 3);
+static SENSOR_DEVICE_ATTR_2_RO(in0_alarm, in_alarm, 0, 3);
 static SENSOR_DEVICE_ATTR_2_RW(in0_beep, beep, 0x5a, 3);
 
 static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, 0);
@@ -668,19 +730,19 @@
 static SENSOR_DEVICE_ATTR_2_RO(in2_input, in, 2, 0);
 static SENSOR_DEVICE_ATTR_2_RW(in2_min, in, 2, 1);
 static SENSOR_DEVICE_ATTR_2_RW(in2_max, in, 2, 2);
-static SENSOR_DEVICE_ATTR_2_RO(in2_alarm, alarm, 0x1e, 0);
+static SENSOR_DEVICE_ATTR_2_RO(in2_alarm, in_alarm, 2, 0);
 static SENSOR_DEVICE_ATTR_2_RW(in2_beep, beep, 0x5a, 0);
 
 static SENSOR_DEVICE_ATTR_2_RO(in3_input, in, 3, 0);
 static SENSOR_DEVICE_ATTR_2_RW(in3_min, in, 3, 1);
 static SENSOR_DEVICE_ATTR_2_RW(in3_max, in, 3, 2);
-static SENSOR_DEVICE_ATTR_2_RO(in3_alarm, alarm, 0x1e, 1);
+static SENSOR_DEVICE_ATTR_2_RO(in3_alarm, in_alarm, 3, 1);
 static SENSOR_DEVICE_ATTR_2_RW(in3_beep, beep, 0x5a, 1);
 
 static SENSOR_DEVICE_ATTR_2_RO(in4_input, in, 4, 0);
 static SENSOR_DEVICE_ATTR_2_RW(in4_min, in, 4, 1);
 static SENSOR_DEVICE_ATTR_2_RW(in4_max, in, 4, 2);
-static SENSOR_DEVICE_ATTR_2_RO(in4_alarm, alarm, 0x1e, 2);
+static SENSOR_DEVICE_ATTR_2_RO(in4_alarm, in_alarm, 4, 2);
 static SENSOR_DEVICE_ATTR_2_RW(in4_beep, beep, 0x5a, 2);
 
 static struct attribute *nct7802_in_attrs[] = {
@@ -1011,6 +1073,7 @@
 		return PTR_ERR(data->regmap);
 
 	mutex_init(&data->access_lock);
+	mutex_init(&data->in_alarm_lock);
 
 	ret = nct7802_init_chip(data);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/hwmon/nct7904.c
+++ linux-ein-5.4.0/drivers/hwmon/nct7904.c
@@ -197,7 +197,7 @@
 		if (ret < 0)
 			return ret;
 		cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
-		if (cnt == 0x1fff)
+		if (cnt == 0 || cnt == 0x1fff)
 			rpm = 0;
 		else
 			rpm = 1350000 / cnt;
@@ -209,7 +209,7 @@
 		if (ret < 0)
 			return ret;
 		cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
-		if (cnt == 0x1fff)
+		if (cnt == 0 || cnt == 0x1fff)
 			rpm = 0;
 		else
 			rpm = 1350000 / cnt;
@@ -356,6 +356,7 @@
 	struct nct7904_data *data = dev_get_drvdata(dev);
 	int ret, temp;
 	unsigned int reg1, reg2, reg3;
+	s8 temps;
 
 	switch (attr) {
 	case hwmon_temp_input:
@@ -461,7 +462,8 @@
 
 	if (ret < 0)
 		return ret;
-	*val = ret * 1000;
+	temps = ret;
+	*val = temps * 1000;
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/hwmon/occ/common.c
+++ linux-ein-5.4.0/drivers/hwmon/occ/common.c
@@ -209,9 +209,9 @@
 		return rc;
 
 	/* limit the maximum rate of polling the OCC */
-	if (time_after(jiffies, occ->last_update + OCC_UPDATE_FREQUENCY)) {
+	if (time_after(jiffies, occ->next_update)) {
 		rc = occ_poll(occ);
-		occ->last_update = jiffies;
+		occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
 	} else {
 		rc = occ->last_error;
 	}
@@ -1089,6 +1089,7 @@
 		return rc;
 	}
 
+	occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
 	occ_parse_poll_response(occ);
 
 	rc = occ_setup_sensor_attrs(occ);
--- linux-ein-5.4.0.orig/drivers/hwmon/occ/common.h
+++ linux-ein-5.4.0/drivers/hwmon/occ/common.h
@@ -99,7 +99,7 @@
 	u8 poll_cmd_data;		/* to perform OCC poll command */
 	int (*send_cmd)(struct occ *occ, u8 *cmd);
 
-	unsigned long last_update;
+	unsigned long next_update;
 	struct mutex lock;		/* lock OCC access */
 
 	struct device *hwmon;
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/adm1275.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/adm1275.c
@@ -454,6 +454,7 @@
 static int adm1275_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
+	s32 (*config_read_fn)(const struct i2c_client *client, u8 reg);
 	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
 	int config, device_config;
 	int ret;
@@ -499,11 +500,16 @@
 			   "Device mismatch: Configured %s, detected %s\n",
 			   id->name, mid->name);
 
-	config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+	if (mid->driver_data == adm1272 || mid->driver_data == adm1278 ||
+	    mid->driver_data == adm1293 || mid->driver_data == adm1294)
+		config_read_fn = i2c_smbus_read_word_data;
+	else
+		config_read_fn = i2c_smbus_read_byte_data;
+	config = config_read_fn(client, ADM1275_PMON_CONFIG);
 	if (config < 0)
 		return config;
 
-	device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
+	device_config = config_read_fn(client, ADM1275_DEVICE_CONFIG);
 	if (device_config < 0)
 		return device_config;
 
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/ibm-cffps.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/ibm-cffps.c
@@ -39,9 +39,13 @@
 #define CFFPS_MFR_VAUX_FAULT			BIT(6)
 #define CFFPS_MFR_CURRENT_SHARE_WARNING		BIT(7)
 
+/*
+ * LED off state actually relinquishes LED control to PSU firmware, so it can
+ * turn on the LED for faults.
+ */
+#define CFFPS_LED_OFF				0
 #define CFFPS_LED_BLINK				BIT(0)
 #define CFFPS_LED_ON				BIT(1)
-#define CFFPS_LED_OFF				BIT(2)
 #define CFFPS_BLINK_RATE_MS			250
 
 enum {
@@ -292,28 +296,38 @@
 	return rc;
 }
 
-static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
-					 enum led_brightness brightness)
+static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
+					enum led_brightness brightness)
 {
 	int rc;
+	u8 next_led_state;
 	struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
 
 	if (brightness == LED_OFF) {
-		psu->led_state = CFFPS_LED_OFF;
+		next_led_state = CFFPS_LED_OFF;
 	} else {
 		brightness = LED_FULL;
+
 		if (psu->led_state != CFFPS_LED_BLINK)
-			psu->led_state = CFFPS_LED_ON;
+			next_led_state = CFFPS_LED_ON;
+		else
+			next_led_state = CFFPS_LED_BLINK;
 	}
 
+	dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
+		brightness, next_led_state);
+
 	pmbus_set_page(psu->client, 0);
 
 	rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
-				       psu->led_state);
+				       next_led_state);
 	if (rc < 0)
-		return;
+		return rc;
 
+	psu->led_state = next_led_state;
 	led_cdev->brightness = brightness;
+
+	return 0;
 }
 
 static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
@@ -323,10 +337,7 @@
 	int rc;
 	struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
 
-	psu->led_state = CFFPS_LED_BLINK;
-
-	if (led_cdev->brightness == LED_OFF)
-		return 0;
+	dev_dbg(&psu->client->dev, "LED blink set.\n");
 
 	pmbus_set_page(psu->client, 0);
 
@@ -335,6 +346,8 @@
 	if (rc < 0)
 		return rc;
 
+	psu->led_state = CFFPS_LED_BLINK;
+	led_cdev->brightness = LED_FULL;
 	*delay_on = CFFPS_BLINK_RATE_MS;
 	*delay_off = CFFPS_BLINK_RATE_MS;
 
@@ -351,7 +364,7 @@
 		 client->addr);
 	psu->led.name = psu->led_name;
 	psu->led.max_brightness = LED_FULL;
-	psu->led.brightness_set = ibm_cffps_led_brightness_set;
+	psu->led.brightness_set_blocking = ibm_cffps_led_brightness_set;
 	psu->led.blink_set = ibm_cffps_led_blink_set;
 
 	rc = devm_led_classdev_register(dev, &psu->led);
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/lm25066.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/lm25066.c
@@ -51,26 +51,31 @@
 #define PSC_CURRENT_IN_L	(PSC_NUM_CLASSES)
 #define PSC_POWER_L		(PSC_NUM_CLASSES + 1)
 
-static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
+static struct __coeff lm25066_coeff[][PSC_NUM_CLASSES + 2] = {
 	[lm25056] = {
 		[PSC_VOLTAGE_IN] = {
 			.m = 16296,
+			.b = 1343,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN] = {
 			.m = 13797,
+			.b = -1833,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN_L] = {
 			.m = 6726,
+			.b = -537,
 			.R = -2,
 		},
 		[PSC_POWER] = {
 			.m = 5501,
+			.b = -2908,
 			.R = -3,
 		},
 		[PSC_POWER_L] = {
 			.m = 26882,
+			.b = -5646,
 			.R = -4,
 		},
 		[PSC_TEMPERATURE] = {
@@ -82,26 +87,32 @@
 	[lm25066] = {
 		[PSC_VOLTAGE_IN] = {
 			.m = 22070,
+			.b = -1800,
 			.R = -2,
 		},
 		[PSC_VOLTAGE_OUT] = {
 			.m = 22070,
+			.b = -1800,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN] = {
 			.m = 13661,
+			.b = -5200,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN_L] = {
 			.m = 6852,
+			.b = -3100,
 			.R = -2,
 		},
 		[PSC_POWER] = {
 			.m = 736,
+			.b = -3300,
 			.R = -2,
 		},
 		[PSC_POWER_L] = {
 			.m = 369,
+			.b = -1900,
 			.R = -2,
 		},
 		[PSC_TEMPERATURE] = {
@@ -111,26 +122,32 @@
 	[lm5064] = {
 		[PSC_VOLTAGE_IN] = {
 			.m = 4611,
+			.b = -642,
 			.R = -2,
 		},
 		[PSC_VOLTAGE_OUT] = {
 			.m = 4621,
+			.b = 423,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN] = {
 			.m = 10742,
+			.b = 1552,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN_L] = {
 			.m = 5456,
+			.b = 2118,
 			.R = -2,
 		},
 		[PSC_POWER] = {
 			.m = 1204,
+			.b = 8524,
 			.R = -3,
 		},
 		[PSC_POWER_L] = {
 			.m = 612,
+			.b = 11202,
 			.R = -3,
 		},
 		[PSC_TEMPERATURE] = {
@@ -140,26 +157,32 @@
 	[lm5066] = {
 		[PSC_VOLTAGE_IN] = {
 			.m = 4587,
+			.b = -1200,
 			.R = -2,
 		},
 		[PSC_VOLTAGE_OUT] = {
 			.m = 4587,
+			.b = -2400,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN] = {
 			.m = 10753,
+			.b = -1200,
 			.R = -2,
 		},
 		[PSC_CURRENT_IN_L] = {
 			.m = 5405,
+			.b = -600,
 			.R = -2,
 		},
 		[PSC_POWER] = {
 			.m = 1204,
+			.b = -6000,
 			.R = -3,
 		},
 		[PSC_POWER_L] = {
 			.m = 605,
+			.b = -8000,
 			.R = -3,
 		},
 		[PSC_TEMPERATURE] = {
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/ltc2978.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/ltc2978.c
@@ -82,8 +82,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-ein-5.4.0.orig/drivers/hwmon/pmbus/max34440.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/max34440.c
@@ -387,7 +387,6 @@
 		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-		.read_byte_data = max34440_read_byte_data,
 		.read_word_data = max34440_read_word_data,
 		.write_word_data = max34440_write_word_data,
 	},
@@ -418,7 +417,6 @@
 		.func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-		.read_byte_data = max34440_read_byte_data,
 		.read_word_data = max34440_read_word_data,
 		.write_word_data = max34440_write_word_data,
 	},
@@ -454,7 +452,6 @@
 		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
 		.func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-		.read_byte_data = max34440_read_byte_data,
 		.read_word_data = max34440_read_word_data,
 		.write_word_data = max34440_write_word_data,
 	},
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/pmbus.h
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/pmbus.h
@@ -292,6 +292,7 @@
 /*
  * STATUS_VOUT, STATUS_INPUT
  */
+#define PB_VOLTAGE_VIN_OFF		BIT(3)
 #define PB_VOLTAGE_UV_FAULT		BIT(4)
 #define PB_VOLTAGE_UV_WARNING		BIT(5)
 #define PB_VOLTAGE_OV_WARNING		BIT(6)
--- linux-ein-5.4.0.orig/drivers/hwmon/pmbus/pmbus_core.c
+++ linux-ein-5.4.0/drivers/hwmon/pmbus/pmbus_core.c
@@ -1324,7 +1324,7 @@
 		.reg = PMBUS_VIN_UV_FAULT_LIMIT,
 		.attr = "lcrit",
 		.alarm = "lcrit_alarm",
-		.sbit = PB_VOLTAGE_UV_FAULT,
+		.sbit = PB_VOLTAGE_UV_FAULT | PB_VOLTAGE_VIN_OFF,
 	}, {
 		.reg = PMBUS_VIN_OV_WARN_LIMIT,
 		.attr = "max",
@@ -2174,10 +2174,14 @@
 {
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
 	u8 page = rdev_get_id(rdev);
 	int ret;
 
+	mutex_lock(&data->update_lock);
 	ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+	mutex_unlock(&data->update_lock);
+
 	if (ret < 0)
 		return ret;
 
@@ -2188,11 +2192,17 @@
 {
 	struct device *dev = rdev_get_dev(rdev);
 	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct pmbus_data *data = i2c_get_clientdata(client);
 	u8 page = rdev_get_id(rdev);
+	int ret;
 
-	return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
-				      PB_OPERATION_CONTROL_ON,
-				      enable ? PB_OPERATION_CONTROL_ON : 0);
+	mutex_lock(&data->update_lock);
+	ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+				     PB_OPERATION_CONTROL_ON,
+				     enable ? PB_OPERATION_CONTROL_ON : 0);
+	mutex_unlock(&data->update_lock);
+
+	return ret;
 }
 
 static int pmbus_regulator_enable(struct regulator_dev *rdev)
--- linux-ein-5.4.0.orig/drivers/hwmon/pwm-fan.c
+++ linux-ein-5.4.0/drivers/hwmon/pwm-fan.c
@@ -54,16 +54,18 @@
 static void sample_timer(struct timer_list *t)
 {
 	struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer);
+	unsigned int delta = ktime_ms_delta(ktime_get(), ctx->sample_start);
 	int pulses;
-	u64 tmp;
 
-	pulses = atomic_read(&ctx->pulses);
-	atomic_sub(pulses, &ctx->pulses);
-	tmp = (u64)pulses * ktime_ms_delta(ktime_get(), ctx->sample_start) * 60;
-	do_div(tmp, ctx->pulses_per_revolution * 1000);
-	ctx->rpm = tmp;
+	if (delta) {
+		pulses = atomic_read(&ctx->pulses);
+		atomic_sub(pulses, &ctx->pulses);
+		ctx->rpm = (unsigned int)(pulses * 1000 * 60) /
+			(ctx->pulses_per_revolution * delta);
+
+		ctx->sample_start = ktime_get();
+	}
 
-	ctx->sample_start = ktime_get();
 	mod_timer(&ctx->rpm_timer, jiffies + HZ);
 }
 
@@ -328,8 +330,18 @@
 
 	ctx->pwm_value = MAX_PWM;
 
-	/* Set duty cycle to maximum allowed and enable PWM output */
 	pwm_init_state(ctx->pwm, &state);
+	/*
+	 * __set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned
+	 * long. Check this here to prevent the fan running at a too low
+	 * frequency.
+	 */
+	if (state.period > ULONG_MAX / MAX_PWM + 1) {
+		dev_err(dev, "Configured period too big\n");
+		return -EINVAL;
+	}
+
+	/* Set duty cycle to maximum allowed and enable PWM output */
 	state.duty_cycle = ctx->pwm->args.period - 1;
 	state.enabled = true;
 
--- linux-ein-5.4.0.orig/drivers/hwmon/sch56xx-common.c
+++ linux-ein-5.4.0/drivers/hwmon/sch56xx-common.c
@@ -424,7 +424,7 @@
 	if (nowayout)
 		set_bit(WDOG_NO_WAY_OUT, &data->wddev.status);
 	if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)
-		set_bit(WDOG_ACTIVE, &data->wddev.status);
+		set_bit(WDOG_HW_RUNNING, &data->wddev.status);
 
 	/* Since the watchdog uses a downcounter there is no register to read
 	   the BIOS set timeout from (if any was set at all) ->
--- linux-ein-5.4.0.orig/drivers/hwmon/scmi-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/scmi-hwmon.c
@@ -147,7 +147,7 @@
 	[ENERGY] = hwmon_energy,
 };
 
-static u32 hwmon_attributes[] = {
+static u32 hwmon_attributes[hwmon_max] = {
 	[hwmon_chip] = HWMON_C_REGISTER_TZ,
 	[hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL,
 	[hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL,
--- linux-ein-5.4.0.orig/drivers/hwmon/scpi-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/scpi-hwmon.c
@@ -99,6 +99,15 @@
 
 	scpi_scale_reading(&value, sensor);
 
+	/*
+	 * Temperature sensor values are treated as signed values based on
+	 * observation even though that is not explicitly specified, and
+	 * because an unsigned u64 temperature does not really make practical
+	 * sense especially when the temperature is below zero degrees Celsius.
+	 */
+	if (sensor->info.class == TEMPERATURE)
+		return sprintf(buf, "%lld\n", (s64)value);
+
 	return sprintf(buf, "%llu\n", value);
 }
 
--- linux-ein-5.4.0.orig/drivers/hwmon/tmp401.c
+++ linux-ein-5.4.0/drivers/hwmon/tmp401.c
@@ -731,10 +731,21 @@
 	return 0;
 }
 
+static const struct of_device_id __maybe_unused tmp4xx_of_match[] = {
+	{ .compatible = "ti,tmp401", },
+	{ .compatible = "ti,tmp411", },
+	{ .compatible = "ti,tmp431", },
+	{ .compatible = "ti,tmp432", },
+	{ .compatible = "ti,tmp435", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tmp4xx_of_match);
+
 static struct i2c_driver tmp401_driver = {
 	.class		= I2C_CLASS_HWMON,
 	.driver = {
 		.name	= "tmp401",
+		.of_match_table = of_match_ptr(tmp4xx_of_match),
 	},
 	.probe		= tmp401_probe,
 	.id_table	= tmp401_id,
--- linux-ein-5.4.0.orig/drivers/hwmon/tmp421.c
+++ linux-ein-5.4.0/drivers/hwmon/tmp421.c
@@ -100,23 +100,17 @@
 	s16 temp[4];
 };
 
-static int temp_from_s16(s16 reg)
+static int temp_from_raw(u16 reg, bool extended)
 {
 	/* Mask out status bits */
 	int temp = reg & ~0xf;
 
-	return (temp * 1000 + 128) / 256;
-}
+	if (extended)
+		temp = temp - 64 * 256;
+	else
+		temp = (s16)temp;
 
-static int temp_from_u16(u16 reg)
-{
-	/* Mask out status bits */
-	int temp = reg & ~0xf;
-
-	/* Add offset for extended temperature range. */
-	temp -= 64 * 256;
-
-	return (temp * 1000 + 128) / 256;
+	return DIV_ROUND_CLOSEST(temp * 1000, 256);
 }
 
 static struct tmp421_data *tmp421_update_device(struct device *dev)
@@ -153,17 +147,15 @@
 
 	switch (attr) {
 	case hwmon_temp_input:
-		if (tmp421->config & TMP421_CONFIG_RANGE)
-			*val = temp_from_u16(tmp421->temp[channel]);
-		else
-			*val = temp_from_s16(tmp421->temp[channel]);
+		*val = temp_from_raw(tmp421->temp[channel],
+				     tmp421->config & TMP421_CONFIG_RANGE);
 		return 0;
 	case hwmon_temp_fault:
 		/*
-		 * The OPEN bit signals a fault. This is bit 0 of the temperature
-		 * register (low byte).
+		 * Any of OPEN or /PVLD bits indicate a hardware mulfunction
+		 * and the conversion result may be incorrect
 		 */
-		*val = tmp421->temp[channel] & 0x01;
+		*val = !!(tmp421->temp[channel] & 0x03);
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -176,9 +168,6 @@
 {
 	switch (attr) {
 	case hwmon_temp_fault:
-		if (channel == 0)
-			return 0;
-		return 0444;
 	case hwmon_temp_input:
 		return 0444;
 	default:
--- linux-ein-5.4.0.orig/drivers/hwmon/w83791d.c
+++ linux-ein-5.4.0/drivers/hwmon/w83791d.c
@@ -273,9 +273,6 @@
 	char valid;			/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
-	/* array of 2 pointers to subclients */
-	struct i2c_client *lm75[2];
-
 	/* volts */
 	u8 in[NUMBER_OF_VIN];		/* Register value */
 	u8 in_max[NUMBER_OF_VIN];	/* Register value */
@@ -1258,7 +1255,6 @@
 static int w83791d_detect_subclients(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
-	struct w83791d_data *data = i2c_get_clientdata(client);
 	int address = client->addr;
 	int i, id;
 	u8 val;
@@ -1281,22 +1277,19 @@
 	}
 
 	val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
-	if (!(val & 0x08))
-		data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
-							  0x48 + (val & 0x7));
-	if (!(val & 0x80)) {
-		if (!IS_ERR(data->lm75[0]) &&
-				((val & 0x7) == ((val >> 4) & 0x7))) {
-			dev_err(&client->dev,
-				"duplicate addresses 0x%x, "
-				"use force_subclient\n",
-				data->lm75[0]->addr);
-			return -ENODEV;
-		}
-		data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
-							  0x48 + ((val >> 4) & 0x7));
+
+	if (!(val & 0x88) && (val & 0x7) == ((val >> 4) & 0x7)) {
+		dev_err(&client->dev,
+			"duplicate addresses 0x%x, use force_subclient\n", 0x48 + (val & 0x7));
+		return -ENODEV;
 	}
 
+	if (!(val & 0x08))
+		devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + (val & 0x7));
+
+	if (!(val & 0x80))
+		devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + ((val >> 4) & 0x7));
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/hwmon/w83792d.c
+++ linux-ein-5.4.0/drivers/hwmon/w83792d.c
@@ -264,9 +264,6 @@
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
-	/* array of 2 pointers to subclients */
-	struct i2c_client *lm75[2];
-
 	u8 in[9];		/* Register value */
 	u8 in_max[9];		/* Register value */
 	u8 in_min[9];		/* Register value */
@@ -928,7 +925,6 @@
 	int address = new_client->addr;
 	u8 val;
 	struct i2c_adapter *adapter = new_client->adapter;
-	struct w83792d_data *data = i2c_get_clientdata(new_client);
 
 	id = i2c_adapter_id(adapter);
 	if (force_subclients[0] == id && force_subclients[1] == address) {
@@ -947,21 +943,19 @@
 	}
 
 	val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
-	if (!(val & 0x08))
-		data->lm75[0] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
-							  0x48 + (val & 0x7));
-	if (!(val & 0x80)) {
-		if (!IS_ERR(data->lm75[0]) &&
-			((val & 0x7) == ((val >> 4) & 0x7))) {
-			dev_err(&new_client->dev,
-				"duplicate addresses 0x%x, use force_subclient\n",
-				data->lm75[0]->addr);
-			return -ENODEV;
-		}
-		data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, 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;
 	}
 
+	if (!(val & 0x08))
+		devm_i2c_new_dummy_device(&new_client->dev, adapter, 0x48 + (val & 0x7));
+
+	if (!(val & 0x80))
+		devm_i2c_new_dummy_device(&new_client->dev, adapter, 0x48 + ((val >> 4) & 0x7));
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/hwmon/w83793.c
+++ linux-ein-5.4.0/drivers/hwmon/w83793.c
@@ -202,7 +202,6 @@
 }
 
 struct w83793_data {
-	struct i2c_client *lm75[2];
 	struct device *hwmon_dev;
 	struct mutex update_lock;
 	char valid;			/* !=0 if following fields are valid */
@@ -1566,7 +1565,6 @@
 	int address = client->addr;
 	u8 tmp;
 	struct i2c_adapter *adapter = client->adapter;
-	struct w83793_data *data = i2c_get_clientdata(client);
 
 	id = i2c_adapter_id(adapter);
 	if (force_subclients[0] == id && force_subclients[1] == address) {
@@ -1586,21 +1584,19 @@
 	}
 
 	tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
-	if (!(tmp & 0x08))
-		data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
-							  0x48 + (tmp & 0x7));
-	if (!(tmp & 0x80)) {
-		if (!IS_ERR(data->lm75[0])
-		    && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
-			dev_err(&client->dev,
-				"duplicate addresses 0x%x, "
-				"use force_subclients\n", data->lm75[0]->addr);
-			return -ENODEV;
-		}
-		data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
-							  0x48 + ((tmp >> 4) & 0x7));
+
+	if (!(tmp & 0x88) && (tmp & 0x7) == ((tmp >> 4) & 0x7)) {
+		dev_err(&client->dev,
+			"duplicate addresses 0x%x, use force_subclient\n", 0x48 + (tmp & 0x7));
+		return -ENODEV;
 	}
 
+	if (!(tmp & 0x08))
+		devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + (tmp & 0x7));
+
+	if (!(tmp & 0x80))
+		devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + ((tmp >> 4) & 0x7));
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/hwmon/xgene-hwmon.c
+++ linux-ein-5.4.0/drivers/hwmon/xgene-hwmon.c
@@ -768,6 +768,7 @@
 {
 	struct xgene_hwmon_dev *ctx = platform_get_drvdata(pdev);
 
+	cancel_work_sync(&ctx->workq);
 	hwmon_device_unregister(ctx->hwmon_dev);
 	kfifo_free(&ctx->async_msg_fifo);
 	if (acpi_disabled)
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -379,9 +379,10 @@
 	int cpu;
 	struct debug_drvdata *drvdata;
 
-	mutex_lock(&debug_lock);
+	/* Bail out if we can't acquire the mutex or the functionality is off */
+	if (!mutex_trylock(&debug_lock))
+		return NOTIFY_DONE;
 
-	/* Bail out if the functionality is disabled */
 	if (!debug_enable)
 		goto skip_dump;
 
@@ -400,7 +401,7 @@
 
 skip_dump:
 	mutex_unlock(&debug_lock);
-	return 0;
+	return NOTIFY_DONE;
 }
 
 static struct notifier_block debug_notifier = {
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-etb10.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-etb10.c
@@ -176,6 +176,7 @@
 	unsigned long flags;
 	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	struct perf_output_handle *handle = data;
+	struct cs_buffers *buf = etm_perf_sink_config(handle);
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
@@ -186,7 +187,7 @@
 	}
 
 	/* Get a handle on the pid of the process to monitor */
-	pid = task_pid_nr(handle->event->owner);
+	pid = buf->pid;
 
 	if (drvdata->pid != -1 && drvdata->pid != pid) {
 		ret = -EBUSY;
@@ -383,6 +384,7 @@
 	if (!buf)
 		return NULL;
 
+	buf->pid = task_pid_nr(event->owner);
 	buf->snapshot = overwrite;
 	buf->nr_pages = nr_pages;
 	buf->data_pages = pages;
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -126,10 +126,10 @@
 	cpumask_t *mask = &event_data->mask;
 	struct coresight_device *sink;
 
-	if (WARN_ON(cpumask_empty(mask)))
+	if (!event_data->snk_config)
 		return;
 
-	if (!event_data->snk_config)
+	if (WARN_ON(cpumask_empty(mask)))
 		return;
 
 	cpu = cpumask_first(mask);
@@ -310,6 +310,16 @@
 	if (!event_data)
 		goto fail;
 
+	/*
+	 * Check if this ETM is allowed to trace, as decided
+	 * at etm_setup_aux(). This could be due to an unreachable
+	 * sink from this ETM. We can't do much in this case if
+	 * the sink was specified or hinted to the driver. For
+	 * now, simply don't record anything on this ETM.
+	 */
+	if (!cpumask_test_cpu(cpu, &event_data->mask))
+		goto fail_end_stop;
+
 	path = etm_event_cpu_path(event_data, cpu);
 	/* We need a sink, no need to continue without one */
 	sink = coresight_get_sink(path);
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -364,8 +364,12 @@
 	mode = ETM_MODE_QELEM(config->mode);
 	/* start by clearing QE bits */
 	config->cfg &= ~(BIT(13) | BIT(14));
-	/* if supported, Q elements with instruction counts are enabled */
-	if ((mode & BIT(0)) && (drvdata->q_support & BIT(0)))
+	/*
+	 * if supported, Q elements with instruction counts are enabled.
+	 * Always set the low bit for any requested mode. Valid combos are
+	 * 0b00, 0b01 and 0b11.
+	 */
+	if (mode && drvdata->q_support)
 		config->cfg |= BIT(13);
 	/*
 	 * if supported, Q elements with and without instruction
@@ -652,10 +656,13 @@
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
+
+	/* mask off max threshold before checking min value */
+	val &= ETM_CYC_THRESHOLD_MASK;
 	if (val < drvdata->ccitmin)
 		return -EINVAL;
 
-	config->ccctlr = val & ETM_CYC_THRESHOLD_MASK;
+	config->ccctlr = val;
 	return size;
 }
 static DEVICE_ATTR_RW(cyc_threshold);
@@ -686,14 +693,16 @@
 		return -EINVAL;
 	if (!drvdata->nr_addr_cmp)
 		return -EINVAL;
+
 	/*
-	 * Bit[7:0] selects which address range comparator is used for
-	 * branch broadcast control.
+	 * Bit[8] controls include(1) / exclude(0), bits[0-7] select
+	 * individual range comparators. If include then at least 1
+	 * range must be selected.
 	 */
-	if (BMVAL(val, 0, 7) > drvdata->nr_addr_cmp)
+	if ((val & BIT(8)) && (BMVAL(val, 0, 7) == 0))
 		return -EINVAL;
 
-	config->bb_ctrl = val;
+	config->bb_ctrl = val & GENMASK(8, 0);
 	return size;
 }
 static DEVICE_ATTR_RW(bb_ctrl);
@@ -1324,8 +1333,8 @@
 
 	spin_lock(&drvdata->spinlock);
 	idx = config->seq_idx;
-	/* RST, bits[7:0] */
-	config->seq_ctrl[idx] = val & 0xFF;
+	/* Seq control has two masks B[15:8] F[7:0] */
+	config->seq_ctrl[idx] = val & 0xFFFF;
 	spin_unlock(&drvdata->spinlock);
 	return size;
 }
@@ -1580,7 +1589,7 @@
 	if (idx % 2 != 0)
 		/* PAIRINV, bit[21] */
 		val &= ~BIT(21);
-	config->res_ctrl[idx] = val;
+	config->res_ctrl[idx] = val & GENMASK(21, 0);
 	spin_unlock(&drvdata->spinlock);
 	return size;
 }
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-etm4x.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -156,7 +156,7 @@
 		writel_relaxed(config->ss_pe_cmp[i],
 			       drvdata->base + TRCSSPCICRn(i));
 	}
-	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
 		writeq_relaxed(config->addr_val[i],
 			       drvdata->base + TRCACVRn(i));
 		writeq_relaxed(config->addr_acc[i],
@@ -1184,6 +1184,7 @@
 	return 0;
 
 err_arch_supported:
+	etmdrvdata[drvdata->cpu] = NULL;
 	if (--etm4_count == 0) {
 		cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
 		if (hp_online)
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-etm4x.h
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -361,7 +361,7 @@
 	u8				ctxid_size;
 	u8				vmid_size;
 	u8				ccsize;
-	u8				ccitmin;
+	u16				ccitmin;
 	u8				s_ex_level;
 	u8				ns_ex_level;
 	u8				q_support;
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-funnel.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-funnel.c
@@ -38,12 +38,14 @@
  * @atclk:	optional clock for the core parts of the funnel.
  * @csdev:	component vitals needed by the framework.
  * @priority:	port selection order.
+ * @spinlock:	serialize enable/disable operations.
  */
 struct funnel_drvdata {
 	void __iomem		*base;
 	struct clk		*atclk;
 	struct coresight_device	*csdev;
 	unsigned long		priority;
+	spinlock_t		spinlock;
 };
 
 static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
@@ -76,11 +78,21 @@
 {
 	int rc = 0;
 	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	bool first_enable = false;
 
-	if (drvdata->base)
-		rc = dynamic_funnel_enable_hw(drvdata, inport);
-
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (atomic_read(&csdev->refcnt[inport]) == 0) {
+		if (drvdata->base)
+			rc = dynamic_funnel_enable_hw(drvdata, inport);
+		if (!rc)
+			first_enable = true;
+	}
 	if (!rc)
+		atomic_inc(&csdev->refcnt[inport]);
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	if (first_enable)
 		dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
 	return rc;
 }
@@ -107,11 +119,19 @@
 			   int outport)
 {
 	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	bool last_disable = false;
 
-	if (drvdata->base)
-		dynamic_funnel_disable_hw(drvdata, inport);
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
+		if (drvdata->base)
+			dynamic_funnel_disable_hw(drvdata, inport);
+		last_disable = true;
+	}
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
+	if (last_disable)
+		dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
 }
 
 static const struct coresight_ops_link funnel_link_ops = {
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-priv.h
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-priv.h
@@ -86,6 +86,7 @@
  * struct cs_buffer - keep track of a recording session' specifics
  * @cur:	index of the current buffer
  * @nr_pages:	max number of pages granted to us
+ * @pid:	PID this cs_buffer belongs to
  * @offset:	offset within the current buffer
  * @data_size:	how much we collected in this run
  * @snapshot:	is this run in snapshot mode
@@ -94,6 +95,7 @@
 struct cs_buffers {
 	unsigned int		cur;
 	unsigned int		nr_pages;
+	pid_t			pid;
 	unsigned long		offset;
 	local_t			data_size;
 	bool			snapshot;
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-replicator.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-replicator.c
@@ -31,11 +31,13 @@
  *		whether this one is programmable or not.
  * @atclk:	optional clock for the core parts of the replicator.
  * @csdev:	component vitals needed by the framework
+ * @spinlock:	serialize enable/disable operations.
  */
 struct replicator_drvdata {
 	void __iomem		*base;
 	struct clk		*atclk;
 	struct coresight_device	*csdev;
+	spinlock_t		spinlock;
 };
 
 static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
@@ -97,10 +99,22 @@
 {
 	int rc = 0;
 	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	bool first_enable = false;
 
-	if (drvdata->base)
-		rc = dynamic_replicator_enable(drvdata, inport, outport);
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (atomic_read(&csdev->refcnt[outport]) == 0) {
+		if (drvdata->base)
+			rc = dynamic_replicator_enable(drvdata, inport,
+						       outport);
+		if (!rc)
+			first_enable = true;
+	}
 	if (!rc)
+		atomic_inc(&csdev->refcnt[outport]);
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	if (first_enable)
 		dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
 	return rc;
 }
@@ -137,10 +151,19 @@
 			       int outport)
 {
 	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	bool last_disable = false;
 
-	if (drvdata->base)
-		dynamic_replicator_disable(drvdata, inport, outport);
-	dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
+		if (drvdata->base)
+			dynamic_replicator_disable(drvdata, inport, outport);
+		last_disable = true;
+	}
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	if (last_disable)
+		dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
 }
 
 static const struct coresight_ops_link replicator_link_ops = {
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -227,6 +227,7 @@
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	struct perf_output_handle *handle = data;
+	struct cs_buffers *buf = etm_perf_sink_config(handle);
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	do {
@@ -243,7 +244,7 @@
 		}
 
 		/* Get a handle on the pid of the process to monitor */
-		pid = task_pid_nr(handle->event->owner);
+		pid = buf->pid;
 
 		if (drvdata->pid != -1 && drvdata->pid != pid) {
 			ret = -EBUSY;
@@ -334,9 +335,10 @@
 static int tmc_enable_etf_link(struct coresight_device *csdev,
 			       int inport, int outport)
 {
-	int ret;
+	int ret = 0;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	bool first_enable = false;
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (drvdata->reading) {
@@ -344,12 +346,18 @@
 		return -EBUSY;
 	}
 
-	ret = tmc_etf_enable_hw(drvdata);
+	if (atomic_read(&csdev->refcnt[0]) == 0) {
+		ret = tmc_etf_enable_hw(drvdata);
+		if (!ret) {
+			drvdata->mode = CS_MODE_SYSFS;
+			first_enable = true;
+		}
+	}
 	if (!ret)
-		drvdata->mode = CS_MODE_SYSFS;
+		atomic_inc(&csdev->refcnt[0]);
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	if (!ret)
+	if (first_enable)
 		dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
 	return ret;
 }
@@ -359,6 +367,7 @@
 {
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	bool last_disable = false;
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (drvdata->reading) {
@@ -366,11 +375,15 @@
 		return;
 	}
 
-	tmc_etf_disable_hw(drvdata);
-	drvdata->mode = CS_MODE_DISABLED;
+	if (atomic_dec_return(&csdev->refcnt[0]) == 0) {
+		tmc_etf_disable_hw(drvdata);
+		drvdata->mode = CS_MODE_DISABLED;
+		last_disable = true;
+	}
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
+	if (last_disable)
+		dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
 }
 
 static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
@@ -387,6 +400,7 @@
 	if (!buf)
 		return NULL;
 
+	buf->pid = task_pid_nr(event->owner);
 	buf->snapshot = overwrite;
 	buf->nr_pages = nr_pages;
 	buf->data_pages = pages;
@@ -412,7 +426,7 @@
 		return -EINVAL;
 
 	/* wrap head around to the amount of space we have */
-	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+	head = handle->head & (((unsigned long)buf->nr_pages << PAGE_SHIFT) - 1);
 
 	/* find the page to write to */
 	buf->cur = head / PAGE_SIZE;
@@ -514,7 +528,7 @@
 		buf_ptr = buf->data_pages[cur] + offset;
 		*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
 
-		if (lost && *barrier) {
+		if (lost && i < CORESIGHT_BARRIER_PKT_SIZE) {
 			*buf_ptr = *barrier;
 			barrier++;
 		}
@@ -584,13 +598,6 @@
 		goto out;
 	}
 
-	/* There is no point in reading a TMC in HW FIFO mode */
-	mode = readl_relaxed(drvdata->base + TMC_MODE);
-	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
-		ret = -EINVAL;
-		goto out;
-	}
-
 	/* Don't interfere if operated from Perf */
 	if (drvdata->mode == CS_MODE_PERF) {
 		ret = -EINVAL;
@@ -604,8 +611,15 @@
 	}
 
 	/* Disable the TMC if need be */
-	if (drvdata->mode == CS_MODE_SYSFS)
+	if (drvdata->mode == CS_MODE_SYSFS) {
+		/* There is no point in reading a TMC in HW FIFO mode */
+		mode = readl_relaxed(drvdata->base + TMC_MODE);
+		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+			ret = -EINVAL;
+			goto out;
+		}
 		__tmc_etb_disable_hw(drvdata);
+	}
 
 	drvdata->reading = true;
 out:
@@ -627,15 +641,14 @@
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
-	/* There is no point in reading a TMC in HW FIFO mode */
-	mode = readl_relaxed(drvdata->base + TMC_MODE);
-	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		return -EINVAL;
-	}
-
 	/* Re-enable the TMC if need be */
 	if (drvdata->mode == CS_MODE_SYSFS) {
+		/* There is no point in reading a TMC in HW FIFO mode */
+		mode = readl_relaxed(drvdata->base + TMC_MODE);
+		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+			spin_unlock_irqrestore(&drvdata->spinlock, flags);
+			return -EINVAL;
+		}
 		/*
 		 * The trace run will continue with the same allocated trace
 		 * buffer. As such zero-out the buffer so that we don't end
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -47,7 +47,8 @@
 };
 
 /* Convert the perf index to an offset within the ETR buffer */
-#define PERF_IDX2OFF(idx, buf)	((idx) % ((buf)->nr_pages << PAGE_SHIFT))
+#define PERF_IDX2OFF(idx, buf)		\
+		((idx) % ((unsigned long)(buf)->nr_pages << PAGE_SHIFT))
 
 /* Lower limit for ETR hardware buffer */
 #define TMC_ETR_PERF_MIN_BUF_SIZE	SZ_1M
@@ -217,6 +218,8 @@
 		} else {
 			page = alloc_pages_node(node,
 						GFP_KERNEL | __GFP_ZERO, 0);
+			if (!page)
+				goto err;
 		}
 		paddr = dma_map_page(real_dev, page, 0, PAGE_SIZE, dir);
 		if (dma_mapping_error(real_dev, paddr))
@@ -907,7 +910,7 @@
 
 	len = tmc_etr_buf_get_data(etr_buf, offset,
 				   CORESIGHT_BARRIER_PKT_SIZE, &bufp);
-	if (WARN_ON(len < CORESIGHT_BARRIER_PKT_SIZE))
+	if (WARN_ON(len < 0 || len < CORESIGHT_BARRIER_PKT_SIZE))
 		return -EINVAL;
 	coresight_insert_barrier_packet(bufp);
 	return offset + CORESIGHT_BARRIER_PKT_SIZE;
@@ -1213,7 +1216,7 @@
 	 * than the size requested via sysfs.
 	 */
 	if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
-		etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
+		etr_buf = tmc_alloc_etr_buf(drvdata, ((ssize_t)nr_pages << PAGE_SHIFT),
 					    0, node, NULL);
 		if (!IS_ERR(etr_buf))
 			goto done;
@@ -1533,7 +1536,7 @@
 
 	/* Insert barrier packets at the beginning, if there was an overflow */
 	if (lost)
-		tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
+		tmc_etr_buf_insert_barrier_packet(etr_buf, offset);
 	tmc_etr_sync_perf_buffer(etr_perf, offset, size);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight-tmc.h
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight-tmc.h
@@ -320,7 +320,7 @@
 static inline unsigned long
 tmc_sg_table_buf_size(struct tmc_sg_table *sg_table)
 {
-	return sg_table->data_pages.nr_pages << PAGE_SHIFT;
+	return (unsigned long)sg_table->data_pages.nr_pages << PAGE_SHIFT;
 }
 
 struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
--- linux-ein-5.4.0.orig/drivers/hwtracing/coresight/coresight.c
+++ linux-ein-5.4.0/drivers/hwtracing/coresight/coresight.c
@@ -253,9 +253,9 @@
 				 struct coresight_device *parent,
 				 struct coresight_device *child)
 {
-	int ret;
+	int ret = 0;
 	int link_subtype;
-	int refport, inport, outport;
+	int inport, outport;
 
 	if (!parent || !child)
 		return -EINVAL;
@@ -264,29 +264,17 @@
 	outport = coresight_find_link_outport(csdev, child);
 	link_subtype = csdev->subtype.link_subtype;
 
-	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
-		refport = inport;
-	else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
-		refport = outport;
-	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);
-			if (ret) {
-				atomic_dec(&csdev->refcnt[refport]);
-				return ret;
-			}
-		}
-	}
-
-	csdev->enable = true;
+	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
+		return inport;
+	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
+		return outport;
+
+	if (link_ops(csdev)->enable)
+		ret = link_ops(csdev)->enable(csdev, inport, outport);
+	if (!ret)
+		csdev->enable = true;
 
-	return 0;
+	return ret;
 }
 
 static void coresight_disable_link(struct coresight_device *csdev,
@@ -295,7 +283,7 @@
 {
 	int i, nr_conns;
 	int link_subtype;
-	int refport, inport, outport;
+	int inport, outport;
 
 	if (!parent || !child)
 		return;
@@ -305,20 +293,15 @@
 	link_subtype = csdev->subtype.link_subtype;
 
 	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
-		refport = inport;
 		nr_conns = csdev->pdata->nr_inport;
 	} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
-		refport = outport;
 		nr_conns = csdev->pdata->nr_outport;
 	} else {
-		refport = 0;
 		nr_conns = 1;
 	}
 
-	if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
-		if (link_ops(csdev)->disable)
-			link_ops(csdev)->disable(csdev, inport, outport);
-	}
+	if (link_ops(csdev)->disable)
+		link_ops(csdev)->disable(csdev, inport, outport);
 
 	for (i = 0; i < nr_conns; i++)
 		if (atomic_read(&csdev->refcnt[i]) != 0)
@@ -1090,6 +1073,7 @@
 			 * platform data.
 			 */
 			fwnode_handle_put(conn->child_fwnode);
+			conn->child_fwnode = NULL;
 			/* No need to continue */
 			break;
 		}
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/core.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/core.c
@@ -215,6 +215,22 @@
 
 static DEVICE_ATTR_RO(port);
 
+static void intel_th_trace_prepare(struct intel_th_device *thdev)
+{
+	struct intel_th_device *hub = to_intel_th_hub(thdev);
+	struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+
+	if (hub->type != INTEL_TH_SWITCH)
+		return;
+
+	if (thdev->type != INTEL_TH_OUTPUT)
+		return;
+
+	pm_runtime_get_sync(&thdev->dev);
+	hubdrv->prepare(hub, &thdev->output);
+	pm_runtime_put(&thdev->dev);
+}
+
 static int intel_th_output_activate(struct intel_th_device *thdev)
 {
 	struct intel_th_driver *thdrv =
@@ -235,6 +251,7 @@
 	if (ret)
 		goto fail_put;
 
+	intel_th_trace_prepare(thdev);
 	if (thdrv->activate)
 		ret = thdrv->activate(thdev);
 	else
@@ -649,10 +666,8 @@
 	}
 
 	err = intel_th_device_add_resources(thdev, res, subdev->nres);
-	if (err) {
-		put_device(&thdev->dev);
+	if (err)
 		goto fail_put_device;
-	}
 
 	if (subdev->type == INTEL_TH_OUTPUT) {
 		if (subdev->mknode)
@@ -667,10 +682,8 @@
 	}
 
 	err = device_add(&thdev->dev);
-	if (err) {
-		put_device(&thdev->dev);
+	if (err)
 		goto fail_free_res;
-	}
 
 	/* need switch driver to be loaded to enumerate the rest */
 	if (subdev->type == INTEL_TH_SWITCH && !req) {
@@ -838,9 +851,6 @@
 			ret |= d->irq(th->thdev[i]);
 	}
 
-	if (ret == IRQ_NONE)
-		pr_warn_ratelimited("nobody cared for irq\n");
-
 	return ret;
 }
 
@@ -891,6 +901,7 @@
 
 			if (th->irq == -1)
 				th->irq = devres[r].start;
+			th->num_irqs++;
 			break;
 		default:
 			dev_warn(dev, "Unknown resource type %lx\n",
@@ -944,6 +955,9 @@
 
 	th->num_thdevs = 0;
 
+	for (i = 0; i < th->num_irqs; i++)
+		devm_free_irq(th->dev, th->irq + i, th);
+
 	pm_runtime_get_sync(th->dev);
 	pm_runtime_forbid(th->dev);
 
@@ -1024,15 +1038,30 @@
 {
 	struct intel_th_device *hub = to_intel_th_hub(thdev);
 	struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+	int ret;
 
 	/* In host mode, this is up to the external debugger, do nothing. */
 	if (hub->host_mode)
 		return 0;
 
-	if (!hubdrv->set_output)
-		return -ENOTSUPP;
+	/*
+	 * hub is instantiated together with the source device that
+	 * calls here, so guaranteed to be present.
+	 */
+	hubdrv = to_intel_th_driver(hub->dev.driver);
+	if (!hubdrv || !try_module_get(hubdrv->driver.owner))
+		return -EINVAL;
+
+	if (!hubdrv->set_output) {
+		ret = -ENOTSUPP;
+		goto out;
+	}
+
+	ret = hubdrv->set_output(hub, master);
 
-	return hubdrv->set_output(hub, master);
+out:
+	module_put(hubdrv->driver.owner);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(intel_th_set_output);
 
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/gth.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/gth.c
@@ -543,7 +543,7 @@
 	output->active = false;
 
 	for_each_set_bit(master, gth->output[output->port].master,
-			 TH_CONFIGURABLE_MASTERS) {
+			 TH_CONFIGURABLE_MASTERS + 1) {
 		gth_master_set(gth, master, -1);
 	}
 	spin_unlock(&gth->gth_lock);
@@ -564,6 +564,21 @@
 	iowrite32(reg, gth->base + REG_TSCU_TSUCTRL);
 }
 
+static void intel_th_gth_prepare(struct intel_th_device *thdev,
+				 struct intel_th_output *output)
+{
+	struct gth_device *gth = dev_get_drvdata(&thdev->dev);
+	int count;
+
+	/*
+	 * Wait until the output port is in reset before we start
+	 * programming it.
+	 */
+	for (count = GTH_PLE_WAITLOOP_DEPTH;
+	     count && !(gth_output_get(gth, output->port) & BIT(5)); count--)
+		cpu_relax();
+}
+
 /**
  * intel_th_gth_enable() - enable tracing to an output device
  * @thdev:	GTH device
@@ -697,7 +712,7 @@
 	othdev->output.port = -1;
 	othdev->output.active = false;
 	gth->output[port].output = NULL;
-	for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++)
+	for (master = 0; master < TH_CONFIGURABLE_MASTERS + 1; master++)
 		if (gth->master[master] == port)
 			gth->master[master] = -1;
 	spin_unlock(&gth->gth_lock);
@@ -815,6 +830,7 @@
 	.assign		= intel_th_gth_assign,
 	.unassign	= intel_th_gth_unassign,
 	.set_output	= intel_th_gth_set_output,
+	.prepare	= intel_th_gth_prepare,
 	.enable		= intel_th_gth_enable,
 	.trig_switch	= intel_th_gth_switch,
 	.disable	= intel_th_gth_disable,
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/intel_th.h
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/intel_th.h
@@ -47,11 +47,13 @@
 /**
  * struct intel_th_drvdata - describes hardware capabilities and quirks
  * @tscu_enable:	device needs SW to enable time stamping unit
+ * @multi_is_broken:	device has multiblock mode is broken
  * @has_mintctl:	device has interrupt control (MINTCTL) register
  * @host_mode_only:	device can only operate in 'host debugger' mode
  */
 struct intel_th_drvdata {
 	unsigned int	tscu_enable        : 1,
+			multi_is_broken    : 1,
 			has_mintctl        : 1,
 			host_mode_only     : 1;
 };
@@ -141,6 +143,7 @@
  * @remove:	remove method
  * @assign:	match a given output type device against available outputs
  * @unassign:	deassociate an output type device from an output port
+ * @prepare:	prepare output port for tracing
  * @enable:	enable tracing for a given output device
  * @disable:	disable tracing for a given output device
  * @irq:	interrupt callback
@@ -162,6 +165,8 @@
 					  struct intel_th_device *othdev);
 	void			(*unassign)(struct intel_th_device *thdev,
 					    struct intel_th_device *othdev);
+	void			(*prepare)(struct intel_th_device *thdev,
+					   struct intel_th_output *output);
 	void			(*enable)(struct intel_th_device *thdev,
 					  struct intel_th_output *output);
 	void			(*trig_switch)(struct intel_th_device *thdev,
@@ -261,6 +266,7 @@
  * @num_thdevs:	number of devices in the @thdev array
  * @num_resources:	number of resources in the @resource array
  * @irq:	irq number
+ * @num_irqs:	number of IRQs is use
  * @id:		this Intel TH controller's device ID in the system
  * @major:	device node major for output devices
  */
@@ -277,6 +283,7 @@
 	unsigned int		num_thdevs;
 	unsigned int		num_resources;
 	int			irq;
+	int			num_irqs;
 
 	int			id;
 	int			major;
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/msu-sink.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/msu-sink.c
@@ -71,6 +71,9 @@
 		block = dma_alloc_coherent(priv->dev->parent->parent,
 					   PAGE_SIZE, &sg_dma_address(sg_ptr),
 					   GFP_KERNEL);
+		if (!block)
+			return -ENOMEM;
+
 		sg_set_buf(sg_ptr, block, PAGE_SIZE);
 	}
 
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/msu.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/msu.c
@@ -157,7 +157,8 @@
 	/* config */
 	unsigned int		enabled : 1,
 				wrap	: 1,
-				do_irq	: 1;
+				do_irq	: 1,
+				multi_is_broken : 1;
 	unsigned int		mode;
 	unsigned int		burst_len;
 	unsigned int		index;
@@ -718,9 +719,6 @@
 
 	if (old != expect) {
 		ret = -EINVAL;
-		dev_warn_ratelimited(msc_dev(win->msc),
-				     "expected lockout state %d, got %d\n",
-				     expect, old);
 		goto unlock;
 	}
 
@@ -741,6 +739,10 @@
 		/* from intel_th_msc_window_unlock(), don't warn if not locked */
 		if (expect == WIN_LOCKED && old == new)
 			return 0;
+
+		dev_warn_ratelimited(msc_dev(win->msc),
+				     "expected lockout state %d, got %d\n",
+				     expect, old);
 	}
 
 	return ret;
@@ -760,7 +762,7 @@
 	lockdep_assert_held(&msc->buf_mutex);
 
 	if (msc->mode > MSC_MODE_MULTI)
-		return -ENOTSUPP;
+		return -EINVAL;
 
 	if (msc->mode == MSC_MODE_MULTI) {
 		if (msc_win_set_lockout(msc->cur_win, WIN_READY, WIN_INUSE))
@@ -1048,6 +1050,16 @@
 static inline void msc_buffer_set_wb(struct msc_window *win) {}
 #endif /* CONFIG_X86 */
 
+static struct page *msc_sg_page(struct scatterlist *sg)
+{
+	void *addr = sg_virt(sg);
+
+	if (is_vmalloc_addr(addr))
+		return vmalloc_to_page(addr);
+
+	return sg_page(sg);
+}
+
 /**
  * msc_buffer_win_alloc() - alloc a window for a multiblock mode
  * @msc:	MSC device
@@ -1120,7 +1132,7 @@
 	int i;
 
 	for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) {
-		struct page *page = sg_page(sg);
+		struct page *page = msc_sg_page(sg);
 
 		page->mapping = NULL;
 		dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
@@ -1294,7 +1306,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) {
@@ -1382,7 +1394,7 @@
 	pgoff -= win->pgoff;
 
 	for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
-		struct page *page = sg_page(sg);
+		struct page *page = msc_sg_page(sg);
 		size_t pgsz = PFN_DOWN(sg->length);
 
 		if (pgoff < pgsz)
@@ -1530,7 +1542,7 @@
 		if (ret >= 0)
 			*ppos = iter->offset;
 	} else {
-		ret = -ENOTSUPP;
+		ret = -EINVAL;
 	}
 
 put_count:
@@ -1664,7 +1676,7 @@
 {
 	atomic_set(&msc->user_count, -1);
 
-	msc->mode = MSC_MODE_MULTI;
+	msc->mode = msc->multi_is_broken ? MSC_MODE_SINGLE : MSC_MODE_MULTI;
 	mutex_init(&msc->buf_mutex);
 	INIT_LIST_HEAD(&msc->win_list);
 	INIT_LIST_HEAD(&msc->iter_list);
@@ -1676,10 +1688,13 @@
 	return 0;
 }
 
-static void msc_win_switch(struct msc *msc)
+static int msc_win_switch(struct msc *msc)
 {
 	struct msc_window *first;
 
+	if (list_empty(&msc->win_list))
+		return -EINVAL;
+
 	first = list_first_entry(&msc->win_list, struct msc_window, entry);
 
 	if (msc_is_last_win(msc->cur_win))
@@ -1691,6 +1706,8 @@
 	msc->base_addr = msc_win_base_dma(msc->cur_win);
 
 	intel_th_trace_switch(msc->thdev);
+
+	return 0;
 }
 
 /**
@@ -1871,6 +1888,9 @@
 	return -EINVAL;
 
 found:
+	if (i == MSC_MODE_MULTI && msc->multi_is_broken)
+		return -EOPNOTSUPP;
+
 	mutex_lock(&msc->buf_mutex);
 	ret = 0;
 
@@ -2025,16 +2045,15 @@
 	if (val != 1)
 		return -EINVAL;
 
+	ret = -EINVAL;
 	mutex_lock(&msc->buf_mutex);
 	/*
 	 * Window switch can only happen in the "multi" mode.
 	 * If a external buffer is engaged, they have the full
 	 * control over window switching.
 	 */
-	if (msc->mode != MSC_MODE_MULTI || msc->mbuf)
-		ret = -ENOTSUPP;
-	else
-		msc_win_switch(msc);
+	if (msc->mode == MSC_MODE_MULTI && !msc->mbuf)
+		ret = msc_win_switch(msc);
 	mutex_unlock(&msc->buf_mutex);
 
 	return ret ? ret : size;
@@ -2078,6 +2097,9 @@
 	if (!res)
 		msc->do_irq = 1;
 
+	if (INTEL_TH_CAP(to_intel_th(thdev), multi_is_broken))
+		msc->multi_is_broken = 1;
+
 	msc->index = thdev->id;
 
 	msc->thdev = thdev;
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/pci.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/pci.c
@@ -100,8 +100,10 @@
 		}
 
 	th = intel_th_alloc(&pdev->dev, drvdata, resource, r);
-	if (IS_ERR(th))
-		return PTR_ERR(th);
+	if (IS_ERR(th)) {
+		err = PTR_ERR(th);
+		goto err_free_irq;
+	}
 
 	th->activate   = intel_th_pci_activate;
 	th->deactivate = intel_th_pci_deactivate;
@@ -109,6 +111,10 @@
 	pci_set_master(pdev);
 
 	return 0;
+
+err_free_irq:
+	pci_free_irq_vectors(pdev);
+	return err;
 }
 
 static void intel_th_pci_remove(struct pci_dev *pdev)
@@ -120,6 +126,10 @@
 	pci_free_irq_vectors(pdev);
 }
 
+static const struct intel_th_drvdata intel_th_1x_multi_is_broken = {
+	.multi_is_broken	= 1,
+};
+
 static const struct intel_th_drvdata intel_th_2x = {
 	.tscu_enable	= 1,
 	.has_mintctl	= 1,
@@ -152,7 +162,7 @@
 	{
 		/* Kaby Lake PCH-H */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
-		.driver_data = (kernel_ulong_t)0,
+		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
 	},
 	{
 		/* Denverton */
@@ -205,20 +215,90 @@
 		.driver_data = (kernel_ulong_t)&intel_th_2x,
 	},
 	{
+		/* Comet Lake PCH-V */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa3a6),
+		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
+	},
+	{
 		/* Ice Lake NNPI */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
 		.driver_data = (kernel_ulong_t)&intel_th_2x,
 	},
 	{
+		/* Ice Lake CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8a29),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Tiger Lake CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9a33),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
 		/* Tiger Lake PCH */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa0a6),
 		.driver_data = (kernel_ulong_t)&intel_th_2x,
 	},
 	{
+		/* Tiger Lake PCH-H */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x43a6),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
 		/* Jasper Lake PCH */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6),
 		.driver_data = (kernel_ulong_t)&intel_th_2x,
 	},
+	{
+		/* Jasper Lake CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4e29),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Elkhart Lake CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4529),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Elkhart Lake */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Alder Lake-P */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Emmitsburg PCH */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1bcc),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Alder Lake-M */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x54a6),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Raptor Lake-S CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa76f),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Meteor Lake-P */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7e24),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Raptor Lake-S */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7a26),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
+	{
+		/* Rocket Lake CPU */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c19),
+		.driver_data = (kernel_ulong_t)&intel_th_2x,
+	},
 	{ 0 },
 };
 
--- linux-ein-5.4.0.orig/drivers/hwtracing/intel_th/sth.c
+++ linux-ein-5.4.0/drivers/hwtracing/intel_th/sth.c
@@ -161,9 +161,7 @@
 {
 	struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
 
-	intel_th_set_output(to_intel_th_device(sth->dev), master);
-
-	return 0;
+	return intel_th_set_output(to_intel_th_device(sth->dev), master);
 }
 
 static int intel_th_sw_init(struct sth_device *sth)
--- linux-ein-5.4.0.orig/drivers/hwtracing/stm/heartbeat.c
+++ linux-ein-5.4.0/drivers/hwtracing/stm/heartbeat.c
@@ -64,7 +64,7 @@
 
 static int stm_heartbeat_init(void)
 {
-	int i, ret = -ENOMEM;
+	int i, ret;
 
 	if (nr_devs < 0 || nr_devs > STM_HEARTBEAT_MAX)
 		return -EINVAL;
@@ -72,8 +72,10 @@
 	for (i = 0; i < nr_devs; i++) {
 		stm_heartbeat[i].data.name =
 			kasprintf(GFP_KERNEL, "heartbeat.%d", i);
-		if (!stm_heartbeat[i].data.name)
+		if (!stm_heartbeat[i].data.name) {
+			ret = -ENOMEM;
 			goto fail_unregister;
+		}
 
 		stm_heartbeat[i].data.nr_chans	= 1;
 		stm_heartbeat[i].data.link	= stm_heartbeat_link;
--- linux-ein-5.4.0.orig/drivers/hwtracing/stm/p_sys-t.c
+++ linux-ein-5.4.0/drivers/hwtracing/stm/p_sys-t.c
@@ -238,7 +238,7 @@
 static inline bool sys_t_need_ts(struct sys_t_output *op)
 {
 	if (op->node.ts_interval &&
-	    time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) {
+	    time_after(jiffies, op->ts_jiffies + op->node.ts_interval)) {
 		op->ts_jiffies = jiffies;
 
 		return true;
@@ -250,8 +250,8 @@
 static bool sys_t_need_clock_sync(struct sys_t_output *op)
 {
 	if (op->node.clocksync_interval &&
-	    time_after(op->clocksync_jiffies + op->node.clocksync_interval,
-		       jiffies)) {
+	    time_after(jiffies,
+		       op->clocksync_jiffies + op->node.clocksync_interval)) {
 		op->clocksync_jiffies = jiffies;
 
 		return true;
--- linux-ein-5.4.0.orig/drivers/hwtracing/stm/policy.c
+++ linux-ein-5.4.0/drivers/hwtracing/stm/policy.c
@@ -345,7 +345,11 @@
 	stm->policy = NULL;
 	policy->stm = NULL;
 
+	/*
+	 * Drop the reference on the protocol driver and lose the link.
+	 */
 	stm_put_protocol(stm->pdrv);
+	stm->pdrv = NULL;
 	stm_put_device(stm);
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/algos/i2c-algo-pca.c
+++ linux-ein-5.4.0/drivers/i2c/algos/i2c-algo-pca.c
@@ -41,8 +41,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);
 	}
 }
 
@@ -314,7 +328,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;
@@ -422,13 +437,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;
@@ -495,19 +511,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-ein-5.4.0.orig/drivers/i2c/busses/Kconfig
+++ linux-ein-5.4.0/drivers/i2c/busses/Kconfig
@@ -483,7 +483,7 @@
 
 config I2C_CADENCE
 	tristate "Cadence I2C Controller"
-	depends on ARCH_ZYNQ || ARM64 || XTENSA
+	depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST
 	help
 	  Say yes here to select Cadence I2C Host Controller. This controller is
 	  e.g. used by Xilinx Zynq.
@@ -666,6 +666,7 @@
 config I2C_IMX
 	tristate "IMX I2C interface"
 	depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
+	select I2C_SLAVE
 	help
 	  Say Y here if you want to use the IIC bus controller on
 	  the Freescale i.MX/MXC, Layerscape or ColdFire processors.
@@ -894,7 +895,7 @@
 
 config I2C_QUP
 	tristate "Qualcomm QUP based I2C controller"
-	depends on ARCH_QCOM
+	depends on ARCH_QCOM || COMPILE_TEST
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Qualcomm SoCs.
@@ -1162,6 +1163,7 @@
 	tristate "Renesas R-Car I2C Controller"
 	depends on ARCH_RENESAS || COMPILE_TEST
 	select I2C_SLAVE
+	select RESET_CONTROLLER if ARCH_RCAR_GEN3
 	help
 	  If you say yes to this option, support will be included for the
 	  R-Car I2C controller.
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-altera.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-altera.c
@@ -70,6 +70,7 @@
  * @isr_mask: cached copy of local ISR enables.
  * @isr_status: cached copy of local ISR status.
  * @lock: spinlock for IRQ synchronization.
+ * @isr_mutex: mutex for IRQ thread.
  */
 struct altr_i2c_dev {
 	void __iomem *base;
@@ -86,6 +87,7 @@
 	u32 isr_mask;
 	u32 isr_status;
 	spinlock_t lock;	/* IRQ synchronization */
+	struct mutex isr_mutex;
 };
 
 static void
@@ -171,7 +173,7 @@
 	/* SCL Low Time */
 	writel(t_low, idev->base + ALTR_I2C_SCL_LOW);
 	/* SDA Hold Time, 300ns */
-	writel(div_u64(300 * clk_mhz, 1000), idev->base + ALTR_I2C_SDA_HOLD);
+	writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD);
 
 	/* Mask all master interrupt bits */
 	altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false);
@@ -245,10 +247,11 @@
 	struct altr_i2c_dev *idev = _dev;
 	u32 status = idev->isr_status;
 
+	mutex_lock(&idev->isr_mutex);
 	if (!idev->msg) {
 		dev_warn(idev->dev, "unexpected interrupt\n");
 		altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
-		return IRQ_HANDLED;
+		goto out;
 	}
 	read = (idev->msg->flags & I2C_M_RD) != 0;
 
@@ -301,6 +304,8 @@
 		complete(&idev->msg_complete);
 		dev_dbg(idev->dev, "Message Complete\n");
 	}
+out:
+	mutex_unlock(&idev->isr_mutex);
 
 	return IRQ_HANDLED;
 }
@@ -312,6 +317,7 @@
 	u32 value;
 	u8 addr = i2c_8bit_addr_from_msg(msg);
 
+	mutex_lock(&idev->isr_mutex);
 	idev->msg = msg;
 	idev->msg_len = msg->len;
 	idev->buf = msg->buf;
@@ -336,6 +342,7 @@
 		altr_i2c_int_enable(idev, imask, true);
 		altr_i2c_fill_tx_fifo(idev);
 	}
+	mutex_unlock(&idev->isr_mutex);
 
 	time_left = wait_for_completion_timeout(&idev->msg_complete,
 						ALTR_I2C_XFER_TIMEOUT);
@@ -384,7 +391,6 @@
 	struct altr_i2c_dev *idev = NULL;
 	struct resource *res;
 	int irq, ret;
-	u32 val;
 
 	idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
 	if (!idev)
@@ -410,18 +416,19 @@
 	idev->dev = &pdev->dev;
 	init_completion(&idev->msg_complete);
 	spin_lock_init(&idev->lock);
+	mutex_init(&idev->isr_mutex);
 
-	val = device_property_read_u32(idev->dev, "fifo-size",
+	ret = device_property_read_u32(idev->dev, "fifo-size",
 				       &idev->fifo_size);
-	if (val) {
+	if (ret) {
 		dev_err(&pdev->dev, "FIFO size set to default of %d\n",
 			ALTR_I2C_DFLT_FIFO_SZ);
 		idev->fifo_size = ALTR_I2C_DFLT_FIFO_SZ;
 	}
 
-	val = device_property_read_u32(idev->dev, "clock-frequency",
+	ret = device_property_read_u32(idev->dev, "clock-frequency",
 				       &idev->bus_clk_rate);
-	if (val) {
+	if (ret) {
 		dev_err(&pdev->dev, "Default to 100kHz\n");
 		idev->bus_clk_rate = 100000;	/* default clock rate */
 	}
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-amd-mp2-pci.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-amd-mp2-pci.c
@@ -349,12 +349,12 @@
 	if (!privdata)
 		return -ENOMEM;
 
+	privdata->pci_dev = pci_dev;
 	rc = amd_mp2_pci_init(privdata, pci_dev);
 	if (rc)
 		return rc;
 
 	mutex_init(&privdata->c2p_lock);
-	privdata->pci_dev = pci_dev;
 
 	pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);
 	pm_runtime_use_autosuspend(&pci_dev->dev);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-aspeed.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-aspeed.c
@@ -69,6 +69,7 @@
  * These share bit definitions, so use the same values for the enable &
  * status bits.
  */
+#define ASPEED_I2CD_INTR_RECV_MASK			0xf000ffff
 #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT			BIT(14)
 #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE		BIT(13)
 #define ASPEED_I2CD_INTR_SLAVE_MATCH			BIT(7)
@@ -249,18 +250,46 @@
 	if (!slave)
 		return 0;
 
-	command = readl(bus->base + ASPEED_I2C_CMD_REG);
+	/*
+	 * Handle stop conditions early, prior to SLAVE_MATCH. Some masters may drive
+	 * transfers with low enough latency between the nak/stop phase of the current
+	 * command and the start/address phase of the following command that the
+	 * interrupts are coalesced by the time we process them.
+	 */
+	if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
+		irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
+		bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+	}
+
+	if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
+	    bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
+		irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
+		bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+	}
+
+	/* Propagate any stop conditions to the slave implementation. */
+	if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
+		i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+		bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+	}
 
-	/* Slave was requested, restart state machine. */
+	/*
+	 * Now that we've dealt with any potentially coalesced stop conditions,
+	 * address any start conditions.
+	 */
 	if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
 		irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH;
 		bus->slave_state = ASPEED_I2C_SLAVE_START;
 	}
 
-	/* Slave is not currently active, irq was for someone else. */
+	/*
+	 * If the slave has been stopped and not started then slave interrupt
+	 * handling is complete.
+	 */
 	if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
 		return irq_handled;
 
+	command = readl(bus->base + ASPEED_I2C_CMD_REG);
 	dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
 		irq_status, command);
 
@@ -279,17 +308,6 @@
 		irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
 	}
 
-	/* Slave was asked to stop. */
-	if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
-		irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
-		bus->slave_state = ASPEED_I2C_SLAVE_STOP;
-	}
-	if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
-	    bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
-		irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
-		bus->slave_state = ASPEED_I2C_SLAVE_STOP;
-	}
-
 	switch (bus->slave_state) {
 	case ASPEED_I2C_SLAVE_READ_REQUESTED:
 		if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))
@@ -318,8 +336,7 @@
 		i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
 		break;
 	case ASPEED_I2C_SLAVE_STOP:
-		i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
-		bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+		/* Stop event handling is done early. Unreachable. */
 		break;
 	case ASPEED_I2C_SLAVE_START:
 		/* Slave was just started. Waiting for the next event. */;
@@ -603,6 +620,8 @@
 	/* Ack all interrupts except for Rx done */
 	writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
 	       bus->base + ASPEED_I2C_INTR_STS_REG);
+	readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+	irq_received &= ASPEED_I2CD_INTR_RECV_MASK;
 	irq_remaining = irq_received;
 
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
@@ -645,9 +664,11 @@
 			irq_received, irq_handled);
 
 	/* Ack Rx done */
-	if (irq_received & ASPEED_I2CD_INTR_RX_DONE)
+	if (irq_received & ASPEED_I2CD_INTR_RX_DONE) {
 		writel(ASPEED_I2CD_INTR_RX_DONE,
 		       bus->base + ASPEED_I2C_INTR_STS_REG);
+		readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+	}
 	spin_unlock(&bus->lock);
 	return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
 }
@@ -688,13 +709,16 @@
 
 	if (time_left == 0) {
 		/*
-		 * If timed out and bus is still busy in a multi master
-		 * environment, attempt recovery at here.
+		 * In a multi-master setup, if a timeout occurs, attempt
+		 * recovery. But if the bus is idle, we still need to reset the
+		 * i2c controller to clear the remaining interrupts.
 		 */
 		if (bus->multi_master &&
 		    (readl(bus->base + ASPEED_I2C_CMD_REG) &
 		     ASPEED_I2CD_BUS_BUSY_STS))
 			aspeed_i2c_recover_bus(bus);
+		else
+			aspeed_i2c_reset(bus);
 
 		/*
 		 * If timed out and the state is still pending, drop the pending
@@ -732,6 +756,8 @@
 	func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
 	func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
 	writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+	bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
 }
 
 static int aspeed_i2c_reg_slave(struct i2c_client *client)
@@ -748,7 +774,6 @@
 	__aspeed_i2c_reg_slave(bus, client->addr);
 
 	bus->slave = client;
-	bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
 	spin_unlock_irqrestore(&bus->lock, flags);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-at91-master.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-at91-master.c
@@ -609,6 +609,7 @@
 	unsigned int_addr_flag = 0;
 	struct i2c_msg *m_start = msg;
 	bool is_read;
+	u8 *dma_buf = NULL;
 
 	dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
 
@@ -656,7 +657,17 @@
 	dev->msg = m_start;
 	dev->recv_len_abort = false;
 
+	if (dev->use_dma) {
+		dma_buf = i2c_get_dma_safe_msg_buf(m_start, 1);
+		if (!dma_buf) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		dev->buf = dma_buf;
+	}
+
 	ret = at91_do_twi_transfer(dev);
+	i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret);
 
 	ret = (ret < 0) ? ret : num;
 out:
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-bcm-iproc.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -157,6 +157,11 @@
 
 #define IE_S_ALL_INTERRUPT_SHIFT     21
 #define IE_S_ALL_INTERRUPT_MASK      0x3f
+/*
+ * It takes ~18us to reading 10bytes of data, hence to keep tasklet
+ * running for less time, max slave read per tasklet is set to 10 bytes.
+ */
+#define MAX_SLAVE_RX_PER_INT         10
 
 enum i2c_slave_read_status {
 	I2C_SLAVE_RX_FIFO_EMPTY = 0,
@@ -203,8 +208,18 @@
 	/* bytes that have been read */
 	unsigned int rx_bytes;
 	unsigned int thld_bytes;
+
+	bool slave_rx_only;
+	bool rx_start_rcvd;
+	bool slave_read_complete;
+	u32 tx_underrun;
+	u32 slave_int_mask;
+	struct tasklet_struct slave_rx_tasklet;
 };
 
+/* tasklet to process slave rx data */
+static void slave_rx_tasklet_fn(unsigned long);
+
 /*
  * Can be expanded in the future if more interrupt status bits are utilized
  */
@@ -213,7 +228,8 @@
 
 #define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
 		| BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
-		| BIT(IS_S_TX_UNDERRUN_SHIFT))
+		| BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\
+		| BIT(IS_S_RX_THLD_SHIFT))
 
 static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave);
 static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave);
@@ -224,13 +240,14 @@
 				   u32 offset)
 {
 	u32 val;
+	unsigned long flags;
 
 	if (iproc_i2c->idm_base) {
-		spin_lock(&iproc_i2c->idm_lock);
+		spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
 		writel(iproc_i2c->ape_addr_mask,
 		       iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
 		val = readl(iproc_i2c->base + offset);
-		spin_unlock(&iproc_i2c->idm_lock);
+		spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
 	} else {
 		val = readl(iproc_i2c->base + offset);
 	}
@@ -241,12 +258,14 @@
 static inline void iproc_i2c_wr_reg(struct bcm_iproc_i2c_dev *iproc_i2c,
 				    u32 offset, u32 val)
 {
+	unsigned long flags;
+
 	if (iproc_i2c->idm_base) {
-		spin_lock(&iproc_i2c->idm_lock);
+		spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
 		writel(iproc_i2c->ape_addr_mask,
 		       iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
 		writel(val, iproc_i2c->base + offset);
-		spin_unlock(&iproc_i2c->idm_lock);
+		spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
 	} else {
 		writel(val, iproc_i2c->base + offset);
 	}
@@ -257,6 +276,7 @@
 {
 	u32 val;
 
+	iproc_i2c->tx_underrun = 0;
 	if (need_reset) {
 		/* put controller in reset */
 		val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET);
@@ -293,8 +313,11 @@
 
 	/* Enable interrupt register to indicate a valid byte in receive fifo */
 	val = BIT(IE_S_RX_EVENT_SHIFT);
+	/* Enable interrupt register to indicate a Master read transaction */
+	val |= BIT(IE_S_RD_EVENT_SHIFT);
 	/* Enable interrupt register for the Slave BUSY command */
 	val |= BIT(IE_S_START_BUSY_SHIFT);
+	iproc_i2c->slave_int_mask = val;
 	iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
 }
 
@@ -319,73 +342,176 @@
 	}
 }
 
-static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
-				    u32 status)
+static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c)
 {
+	u8 rx_data, rx_status;
+	u32 rx_bytes = 0;
 	u32 val;
-	u8 value, rx_status;
 
-	/* Slave RX byte receive */
-	if (status & BIT(IS_S_RX_EVENT_SHIFT)) {
+	while (rx_bytes < MAX_SLAVE_RX_PER_INT) {
 		val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
 		rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
-		if (rx_status == I2C_SLAVE_RX_START) {
-			/* Start of SMBUS for Master write */
-			i2c_slave_event(iproc_i2c->slave,
-					I2C_SLAVE_WRITE_REQUESTED, &value);
+		rx_data = ((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
 
-			val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
-			value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+		if (rx_status == I2C_SLAVE_RX_START) {
+			/* Start of SMBUS Master write */
 			i2c_slave_event(iproc_i2c->slave,
-					I2C_SLAVE_WRITE_RECEIVED, &value);
-		} else if (status & BIT(IS_S_RD_EVENT_SHIFT)) {
-			/* Start of SMBUS for Master Read */
+					I2C_SLAVE_WRITE_REQUESTED, &rx_data);
+			iproc_i2c->rx_start_rcvd = true;
+			iproc_i2c->slave_read_complete = false;
+		} else if (rx_status == I2C_SLAVE_RX_DATA &&
+			   iproc_i2c->rx_start_rcvd) {
+			/* Middle of SMBUS Master write */
 			i2c_slave_event(iproc_i2c->slave,
-					I2C_SLAVE_READ_REQUESTED, &value);
-			iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+					I2C_SLAVE_WRITE_RECEIVED, &rx_data);
+		} else if (rx_status == I2C_SLAVE_RX_END &&
+			   iproc_i2c->rx_start_rcvd) {
+			/* End of SMBUS Master write */
+			if (iproc_i2c->slave_rx_only)
+				i2c_slave_event(iproc_i2c->slave,
+						I2C_SLAVE_WRITE_RECEIVED,
+						&rx_data);
+
+			i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP,
+					&rx_data);
+		} else if (rx_status == I2C_SLAVE_RX_FIFO_EMPTY) {
+			iproc_i2c->rx_start_rcvd = false;
+			iproc_i2c->slave_read_complete = true;
+			break;
+		}
 
-			val = BIT(S_CMD_START_BUSY_SHIFT);
-			iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
+		rx_bytes++;
+	}
+}
 
-			/*
-			 * Enable interrupt for TX FIFO becomes empty and
-			 * less than PKT_LENGTH bytes were output on the SMBUS
-			 */
-			val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
-			val |= BIT(IE_S_TX_UNDERRUN_SHIFT);
-			iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
-		} else {
-			/* Master write other than start */
-			value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+static void slave_rx_tasklet_fn(unsigned long data)
+{
+	struct bcm_iproc_i2c_dev *iproc_i2c = (struct bcm_iproc_i2c_dev *)data;
+	u32 int_clr;
+
+	bcm_iproc_i2c_slave_read(iproc_i2c);
+
+	/* clear pending IS_S_RX_EVENT_SHIFT interrupt */
+	int_clr = BIT(IS_S_RX_EVENT_SHIFT);
+
+	if (!iproc_i2c->slave_rx_only && iproc_i2c->slave_read_complete) {
+		/*
+		 * In case of single byte master-read request,
+		 * IS_S_TX_UNDERRUN_SHIFT event is generated before
+		 * IS_S_START_BUSY_SHIFT event. Hence start slave data send
+		 * from first IS_S_TX_UNDERRUN_SHIFT event.
+		 *
+		 * This means don't send any data from slave when
+		 * IS_S_RD_EVENT_SHIFT event is generated else it will increment
+		 * eeprom or other backend slave driver read pointer twice.
+		 */
+		iproc_i2c->tx_underrun = 0;
+		iproc_i2c->slave_int_mask |= BIT(IE_S_TX_UNDERRUN_SHIFT);
+
+		/* clear IS_S_RD_EVENT_SHIFT interrupt */
+		int_clr |= BIT(IS_S_RD_EVENT_SHIFT);
+	}
+
+	/* clear slave interrupt */
+	iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, int_clr);
+	/* enable slave interrupts */
+	iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, iproc_i2c->slave_int_mask);
+}
+
+static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
+				    u32 status)
+{
+	u32 val;
+	u8 value;
+
+	/*
+	 * Slave events in case of master-write, master-write-read and,
+	 * master-read
+	 *
+	 * Master-write     : only IS_S_RX_EVENT_SHIFT event
+	 * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
+	 *                    events
+	 * Master-read      : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
+	 *                    events or only IS_S_RD_EVENT_SHIFT
+	 */
+	if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
+	    status & BIT(IS_S_RD_EVENT_SHIFT)) {
+		/* disable slave interrupts */
+		val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
+		val &= ~iproc_i2c->slave_int_mask;
+		iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
+
+		if (status & BIT(IS_S_RD_EVENT_SHIFT))
+			/* Master-write-read request */
+			iproc_i2c->slave_rx_only = false;
+		else
+			/* Master-write request only */
+			iproc_i2c->slave_rx_only = true;
+
+		/* schedule tasklet to read data later */
+		tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
+
+		/* clear only IS_S_RX_EVENT_SHIFT interrupt */
+		iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
+				 BIT(IS_S_RX_EVENT_SHIFT));
+	}
+
+	if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
+		iproc_i2c->tx_underrun++;
+		if (iproc_i2c->tx_underrun == 1)
+			/* Start of SMBUS for Master Read */
 			i2c_slave_event(iproc_i2c->slave,
-					I2C_SLAVE_WRITE_RECEIVED, &value);
-		}
-	} else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
-		/* Master read other than start */
-		i2c_slave_event(iproc_i2c->slave,
-				I2C_SLAVE_READ_PROCESSED, &value);
+					I2C_SLAVE_READ_REQUESTED,
+					&value);
+		else
+			/* Master read other than start */
+			i2c_slave_event(iproc_i2c->slave,
+					I2C_SLAVE_READ_PROCESSED,
+					&value);
 
 		iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+		/* start transfer */
 		val = BIT(S_CMD_START_BUSY_SHIFT);
 		iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
+
+		/* clear interrupt */
+		iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
+				 BIT(IS_S_TX_UNDERRUN_SHIFT));
 	}
 
-	/* Stop */
+	/* Stop received from master in case of master read transaction */
 	if (status & BIT(IS_S_START_BUSY_SHIFT)) {
-		i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
 		/*
 		 * Enable interrupt for TX FIFO becomes empty and
 		 * less than PKT_LENGTH bytes were output on the SMBUS
 		 */
-		val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
-		val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
-		iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
+		iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
+		iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET,
+				 iproc_i2c->slave_int_mask);
+
+		/* End of SMBUS for Master Read */
+		val = BIT(S_TX_WR_STATUS_SHIFT);
+		iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val);
+
+		val = BIT(S_CMD_START_BUSY_SHIFT);
+		iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
+
+		/* flush TX FIFOs */
+		val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET);
+		val |= (BIT(S_FIFO_TX_FLUSH_SHIFT));
+		iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
+
+		i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
+
+		/* clear interrupt */
+		iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
+				 BIT(IS_S_START_BUSY_SHIFT));
 	}
 
-	/* clear interrupt status */
-	iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status);
+	/* check slave transmit status only if slave is transmitting */
+	if (!iproc_i2c->slave_rx_only)
+		bcm_iproc_i2c_check_slave_status(iproc_i2c);
 
-	bcm_iproc_i2c_check_slave_status(iproc_i2c);
 	return true;
 }
 
@@ -500,12 +626,17 @@
 static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
 {
 	struct bcm_iproc_i2c_dev *iproc_i2c = data;
-	u32 status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET);
+	u32 slave_status;
+	u32 status;
 	bool ret;
-	u32 sl_status = status & ISR_MASK_SLAVE;
 
-	if (sl_status) {
-		ret = bcm_iproc_i2c_slave_isr(iproc_i2c, sl_status);
+	status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET);
+	/* process only slave interrupt which are enabled */
+	slave_status = status & iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET) &
+		       ISR_MASK_SLAVE;
+
+	if (slave_status) {
+		ret = bcm_iproc_i2c_slave_isr(iproc_i2c, slave_status);
 		if (ret)
 			return IRQ_HANDLED;
 		else
@@ -1022,6 +1153,10 @@
 		return -EAFNOSUPPORT;
 
 	iproc_i2c->slave = slave;
+
+	tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn,
+		     (unsigned long)iproc_i2c);
+
 	bcm_iproc_i2c_slave_init(iproc_i2c, false);
 	return 0;
 }
@@ -1034,7 +1169,7 @@
 	if (!iproc_i2c->slave)
 		return -EINVAL;
 
-	iproc_i2c->slave = NULL;
+	disable_irq(iproc_i2c->irq);
 
 	/* disable all slave interrupts */
 	tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
@@ -1042,11 +1177,24 @@
 			IE_S_ALL_INTERRUPT_SHIFT);
 	iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp);
 
+	tasklet_kill(&iproc_i2c->slave_rx_tasklet);
+
 	/* Erase the slave address programmed */
 	tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET);
 	tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);
 	iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp);
 
+	/* flush TX/RX FIFOs */
+	tmp = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT));
+	iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, tmp);
+
+	/* clear all pending slave interrupts */
+	iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
+
+	iproc_i2c->slave = NULL;
+
+	enable_irq(iproc_i2c->irq);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-bcm2835.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-bcm2835.c
@@ -23,6 +23,11 @@
 #define BCM2835_I2C_FIFO	0x10
 #define BCM2835_I2C_DIV		0x14
 #define BCM2835_I2C_DEL		0x18
+/*
+ * 16-bit field for the number of SCL cycles to wait after rising SCL
+ * before deciding the slave is not responding. 0 disables the
+ * timeout detection.
+ */
 #define BCM2835_I2C_CLKT	0x1c
 
 #define BCM2835_I2C_C_READ	BIT(0)
@@ -58,6 +63,7 @@
 	struct i2c_adapter adapter;
 	struct completion completion;
 	struct i2c_msg *curr_msg;
+	struct clk *bus_clk;
 	int num_msgs;
 	u32 msg_err;
 	u8 *msg_buf;
@@ -404,7 +410,6 @@
 	struct resource *mem, *irq;
 	int ret;
 	struct i2c_adapter *adap;
-	struct clk *bus_clk;
 	struct clk *mclk;
 	u32 bus_clk_rate;
 
@@ -427,11 +432,11 @@
 		return PTR_ERR(mclk);
 	}
 
-	bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
+	i2c_dev->bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
 
-	if (IS_ERR(bus_clk)) {
+	if (IS_ERR(i2c_dev->bus_clk)) {
 		dev_err(&pdev->dev, "Could not register clock\n");
-		return PTR_ERR(bus_clk);
+		return PTR_ERR(i2c_dev->bus_clk);
 	}
 
 	ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
@@ -442,13 +447,13 @@
 		bus_clk_rate = 100000;
 	}
 
-	ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
+	ret = clk_set_rate_exclusive(i2c_dev->bus_clk, bus_clk_rate);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not set clock frequency\n");
 		return ret;
 	}
 
-	ret = clk_prepare_enable(bus_clk);
+	ret = clk_prepare_enable(i2c_dev->bus_clk);
 	if (ret) {
 		dev_err(&pdev->dev, "Couldn't prepare clock");
 		return ret;
@@ -479,6 +484,12 @@
 	adap->dev.of_node = pdev->dev.of_node;
 	adap->quirks = of_device_get_match_data(&pdev->dev);
 
+	/*
+	 * Disable the hardware clock stretching timeout. SMBUS
+	 * specifies a limit for how long the device can stretch the
+	 * clock, but core I2C doesn't.
+	 */
+	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_CLKT, 0);
 	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
 
 	ret = i2c_add_adapter(adap);
@@ -491,10 +502,9 @@
 static int bcm2835_i2c_remove(struct platform_device *pdev)
 {
 	struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-	struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
 
-	clk_rate_exclusive_put(bus_clk);
-	clk_disable_unprepare(bus_clk);
+	clk_rate_exclusive_put(i2c_dev->bus_clk);
+	clk_disable_unprepare(i2c_dev->bus_clk);
 
 	free_irq(i2c_dev->irq, i2c_dev);
 	i2c_del_adapter(&i2c_dev->adapter);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-brcmstb.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-brcmstb.c
@@ -316,7 +316,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",
@@ -640,7 +640,7 @@
 
 	/* set the data in/out register size for compatible SoCs */
 	if (of_device_is_compatible(dev->device->of_node,
-				    "brcmstb,brcmper-i2c"))
+				    "brcm,brcmper-i2c"))
 		dev->data_regsz = sizeof(u8);
 	else
 		dev->data_regsz = sizeof(u32);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-cadence.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-cadence.c
@@ -198,9 +198,9 @@
  */
 static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
 {
-	unsigned int isr_status, avail_bytes, updatetx;
+	unsigned int isr_status, avail_bytes;
 	unsigned int bytes_to_send;
-	bool hold_quirk;
+	bool updatetx;
 	struct cdns_i2c *id = ptr;
 	/* Signal completion only after everything is updated */
 	int done_flag = 0;
@@ -219,11 +219,7 @@
 	 * Check if transfer size register needs to be updated again for a
 	 * large data receive operation.
 	 */
-	updatetx = 0;
-	if (id->recv_count > id->curr_recv_count)
-		updatetx = 1;
-
-	hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
+	updatetx = id->recv_count > id->curr_recv_count;
 
 	/* When receiving, handle data interrupt and completion interrupt */
 	if (id->p_recv_buf &&
@@ -246,7 +242,7 @@
 			id->recv_count--;
 			id->curr_recv_count--;
 
-			if (cdns_is_holdquirk(id, hold_quirk))
+			if (cdns_is_holdquirk(id, updatetx))
 				break;
 		}
 
@@ -257,7 +253,7 @@
 		 * maintain transfer size non-zero while performing a large
 		 * receive operation.
 		 */
-		if (cdns_is_holdquirk(id, hold_quirk)) {
+		if (cdns_is_holdquirk(id, updatetx)) {
 			/* wait while fifo is full */
 			while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
 			       (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
@@ -279,22 +275,6 @@
 						  CDNS_I2C_XFER_SIZE_OFFSET);
 				id->curr_recv_count = id->recv_count;
 			}
-		} else if (id->recv_count && !hold_quirk &&
-						!id->curr_recv_count) {
-
-			/* Set the slave address in address register*/
-			cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
-						CDNS_I2C_ADDR_OFFSET);
-
-			if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
-				cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
-						CDNS_I2C_XFER_SIZE_OFFSET);
-				id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
-			} else {
-				cdns_i2c_writereg(id->recv_count,
-						CDNS_I2C_XFER_SIZE_OFFSET);
-				id->curr_recv_count = id->recv_count;
-			}
 		}
 
 		/* Clear hold (if not repeated start) and signal completion */
@@ -368,8 +348,13 @@
 	ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
 	ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
 
+	/*
+	 * Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length
+	 * byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if
+	 * PEC is enabled, otherwise 1.
+	 */
 	if (id->p_msg->flags & I2C_M_RECV_LEN)
-		id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+		id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len;
 
 	id->curr_recv_count = id->recv_count;
 
@@ -377,10 +362,8 @@
 	 * Check for the message size against FIFO depth and set the
 	 * 'hold bus' bit if it is greater than FIFO depth.
 	 */
-	if ((id->recv_count > CDNS_I2C_FIFO_DEPTH)  || id->bus_hold_flag)
+	if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
 		ctrl_reg |= CDNS_I2C_CR_HOLD;
-	else
-		ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD;
 
 	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
 
@@ -437,11 +420,8 @@
 	 * Check for the message size against FIFO depth and set the
 	 * 'hold bus' bit if it is greater than FIFO depth.
 	 */
-	if ((id->send_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag)
+	if (id->send_count > CDNS_I2C_FIFO_DEPTH)
 		ctrl_reg |= CDNS_I2C_CR_HOLD;
-	else
-		ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD;
-
 	cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
 
 	/* Clear the interrupts in interrupt status register. */
@@ -511,7 +491,7 @@
 static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
 		struct i2c_adapter *adap)
 {
-	unsigned long time_left;
+	unsigned long time_left, msg_timeout;
 	u32 reg;
 
 	id->p_msg = msg;
@@ -536,8 +516,16 @@
 	else
 		cdns_i2c_msend(id);
 
+	/* Minimal time to execute this message */
+	msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
+	/* Plus some wiggle room */
+	msg_timeout += msecs_to_jiffies(500);
+
+	if (msg_timeout < adap->timeout)
+		msg_timeout = adap->timeout;
+
 	/* Wait for the signal of completion */
-	time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
+	time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
 	if (time_left == 0) {
 		cdns_i2c_master_reset(adap);
 		dev_err(id->adap.dev.parent,
@@ -552,6 +540,9 @@
 	if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
 		return -EAGAIN;
 
+	if (msg->flags & I2C_M_RECV_LEN)
+		msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX);
+
 	return 0;
 }
 
@@ -906,7 +897,10 @@
 	if (IS_ERR(id->membase))
 		return PTR_ERR(id->membase);
 
-	id->irq = platform_get_irq(pdev, 0);
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		return ret;
+	id->irq = ret;
 
 	id->adap.owner = THIS_MODULE;
 	id->adap.dev.of_node = pdev->dev.of_node;
@@ -979,6 +973,7 @@
 	return 0;
 
 err_clk_dis:
+	clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
 	clk_disable_unprepare(id->clk);
 	pm_runtime_set_suspended(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-cbus-gpio.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-cbus-gpio.c
@@ -195,8 +195,9 @@
 }
 
 static const struct i2c_algorithm cbus_i2c_algo = {
-	.smbus_xfer	= cbus_i2c_smbus_xfer,
-	.functionality	= cbus_i2c_func,
+	.smbus_xfer		= cbus_i2c_smbus_xfer,
+	.smbus_xfer_atomic	= cbus_i2c_smbus_xfer,
+	.functionality		= cbus_i2c_func,
 };
 
 static int cbus_i2c_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-cpm.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-cpm.c
@@ -65,6 +65,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
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-designware-common.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-designware-common.c
@@ -253,9 +253,6 @@
 {
 	int ret;
 
-	if (IS_ERR(dev->clk))
-		return PTR_ERR(dev->clk);
-
 	if (prepare) {
 		/* Optional interface clock */
 		ret = clk_prepare_enable(dev->pclk);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -37,10 +37,10 @@
 };
 
 struct dw_scl_sda_cfg {
-	u32 ss_hcnt;
-	u32 fs_hcnt;
-	u32 ss_lcnt;
-	u32 fs_lcnt;
+	u16 ss_hcnt;
+	u16 fs_hcnt;
+	u16 ss_lcnt;
+	u16 fs_lcnt;
 	u32 sda_hold;
 };
 
@@ -313,6 +313,7 @@
 	pm_runtime_get_noresume(&pdev->dev);
 
 	i2c_del_adapter(&dev->adapter);
+	devm_free_irq(&pdev->dev, dev->irq, dev);
 	pci_free_irq_vectors(pdev);
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-designware-platdrv.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -349,8 +349,17 @@
 		goto exit_reset;
 	}
 
-	dev->clk = devm_clk_get(&pdev->dev, NULL);
-	if (!i2c_dw_prepare_clk(dev, true)) {
+	dev->clk = devm_clk_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		ret = PTR_ERR(dev->clk);
+		goto exit_reset;
+	}
+
+	ret = i2c_dw_prepare_clk(dev, true);
+	if (ret)
+		goto exit_reset;
+
+	if (dev->clk) {
 		u64 clk_khz;
 
 		dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
@@ -370,10 +379,16 @@
 	adap->dev.of_node = pdev->dev.of_node;
 	adap->nr = -1;
 
-	dev_pm_set_driver_flags(&pdev->dev,
-				DPM_FLAG_SMART_PREPARE |
-				DPM_FLAG_SMART_SUSPEND |
-				DPM_FLAG_LEAVE_SUSPENDED);
+	if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
+		dev_pm_set_driver_flags(&pdev->dev,
+					DPM_FLAG_SMART_PREPARE |
+					DPM_FLAG_LEAVE_SUSPENDED);
+	} else {
+		dev_pm_set_driver_flags(&pdev->dev,
+					DPM_FLAG_SMART_PREPARE |
+					DPM_FLAG_SMART_SUSPEND |
+					DPM_FLAG_LEAVE_SUSPENDED);
+	}
 
 	/* The code below assumes runtime PM to be disabled. */
 	WARN_ON(pm_runtime_enabled(&pdev->dev));
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-eg20t.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-eg20t.c
@@ -180,6 +180,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);
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-emev2.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-emev2.c
@@ -397,7 +397,10 @@
 
 	em_i2c_reset(&priv->adap);
 
-	priv->irq = platform_get_irq(pdev, 0);
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto err_clk;
+	priv->irq = ret;
 	ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
 				"em_i2c", priv);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-fsi.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-fsi.c
@@ -98,7 +98,7 @@
 #define I2C_STAT_DAT_REQ	BIT(25)
 #define I2C_STAT_CMD_COMP	BIT(24)
 #define I2C_STAT_STOP_ERR	BIT(23)
-#define I2C_STAT_MAX_PORT	GENMASK(19, 16)
+#define I2C_STAT_MAX_PORT	GENMASK(22, 16)
 #define I2C_STAT_ANY_INT	BIT(15)
 #define I2C_STAT_SCL_IN		BIT(11)
 #define I2C_STAT_SDA_IN		BIT(10)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-gpio.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-gpio.c
@@ -348,7 +348,7 @@
 	if (ret == -ENOENT)
 		retdesc = ERR_PTR(-EPROBE_DEFER);
 
-	if (ret != -EPROBE_DEFER)
+	if (PTR_ERR(retdesc) != -EPROBE_DEFER)
 		dev_err(dev, "error trying to get descriptor: %d\n", ret);
 
 	return retdesc;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-highlander.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-highlander.c
@@ -379,7 +379,7 @@
 	platform_set_drvdata(pdev, dev);
 
 	dev->irq = platform_get_irq(pdev, 0);
-	if (iic_force_poll)
+	if (dev->irq < 0 || iic_force_poll)
 		dev->irq = 0;
 
 	if (dev->irq) {
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-hix5hd2.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-hix5hd2.c
@@ -477,6 +477,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-ein-5.4.0.orig/drivers/i2c/busses/i2c-i801.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-i801.c
@@ -64,6 +64,7 @@
  * Cedar Fork (PCH)		0x18df	32	hard	yes	yes	yes
  * Ice Lake-LP (PCH)		0x34a3	32	hard	yes	yes	yes
  * Comet Lake (PCH)		0x02a3	32	hard	yes	yes	yes
+ * Comet Lake-H (PCH)		0x06a3	32	hard	yes	yes	yes
  * Elkhart Lake (PCH)		0x4b23	32	hard	yes	yes	yes
  * Tiger Lake-LP (PCH)		0xa0a3	32	hard	yes	yes	yes
  *
@@ -129,11 +130,6 @@
 #define TCOBASE		0x050
 #define TCOCTL		0x054
 
-#define ACPIBASE		0x040
-#define ACPIBASE_SMI_OFF	0x030
-#define ACPICTRL		0x044
-#define ACPICTRL_EN		0x080
-
 #define SBREG_BAR		0x10
 #define SBREG_SMBCTRL		0xc6000c
 #define SBREG_SMBCTRL_DNV	0xcf000c
@@ -205,6 +201,7 @@
 
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS		0x02a3
+#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS		0x06a3
 #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS		0x0f12
 #define PCI_DEVICE_ID_INTEL_CDF_SMBUS			0x18df
 #define PCI_DEVICE_ID_INTEL_DNV_SMBUS			0x19df
@@ -384,11 +381,9 @@
 		dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
 		/* try to stop the current command */
 		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
-		outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
-		       SMBHSTCNT(priv));
+		outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
 		usleep_range(1000, 2000);
-		outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
-		       SMBHSTCNT(priv));
+		outb_p(0, SMBHSTCNT(priv));
 
 		/* Check if it worked */
 		status = inb_p(SMBHSTSTS(priv));
@@ -535,12 +530,13 @@
 		return -EOPNOTSUPP;
 	}
 
-	inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+	/* Set block buffer mode */
+	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
 
-	/* Use 32-byte buffer to process this transaction */
 	if (read_write == I2C_SMBUS_WRITE) {
 		len = data->block[0];
 		outb_p(len, SMBHSTDAT0(priv));
+		inb_p(SMBHSTCNT(priv));	/* reset the data buffer index */
 		for (i = 0; i < len; i++)
 			outb_p(data->block[i+1], SMBBLKDAT(priv));
 	}
@@ -556,6 +552,7 @@
 			return -EPROTO;
 
 		data->block[0] = len;
+		inb_p(SMBHSTCNT(priv));	/* reset the data buffer index */
 		for (i = 0; i < len; i++)
 			data->block[i + 1] = inb_p(SMBBLKDAT(priv));
 	}
@@ -730,15 +727,11 @@
 		return i801_check_post(priv, status);
 	}
 
-	for (i = 1; i <= len; i++) {
-		if (i == len && read_write == I2C_SMBUS_READ)
-			smbcmd |= SMBHSTCNT_LAST_BYTE;
-		outb_p(smbcmd, SMBHSTCNT(priv));
-
-		if (i == 1)
-			outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START,
-			       SMBHSTCNT(priv));
+	if (len == 1 && read_write == I2C_SMBUS_READ)
+		smbcmd |= SMBHSTCNT_LAST_BYTE;
+	outb_p(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
 
+	for (i = 1; i <= len; i++) {
 		status = i801_wait_byte_done(priv);
 		if (status)
 			goto exit;
@@ -761,9 +754,12 @@
 			data->block[0] = len;
 		}
 
-		/* Retrieve/store value in SMBBLKDAT */
-		if (read_write == I2C_SMBUS_READ)
+		if (read_write == I2C_SMBUS_READ) {
 			data->block[i] = inb_p(SMBBLKDAT(priv));
+			if (i == len - 1)
+				outb_p(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
+		}
+
 		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
 			outb_p(data->block[i+1], SMBBLKDAT(priv));
 
@@ -776,14 +772,6 @@
 	return i801_check_post(priv, status);
 }
 
-static int i801_set_block_buffer_mode(struct i801_priv *priv)
-{
-	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
-	if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
-		return -EIO;
-	return 0;
-}
-
 /* Block transaction function */
 static int i801_block_transaction(struct i801_priv *priv,
 				  union i2c_smbus_data *data, char read_write,
@@ -792,6 +780,11 @@
 	int result = 0;
 	unsigned char hostc;
 
+	if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA)
+		data->block[0] = I2C_SMBUS_BLOCK_MAX;
+	else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+		return -EPROTO;
+
 	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
 		if (read_write == I2C_SMBUS_WRITE) {
 			/* set I2C_EN bit in configuration register */
@@ -805,22 +798,11 @@
 		}
 	}
 
-	if (read_write == I2C_SMBUS_WRITE
-	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
-		if (data->block[0] < 1)
-			data->block[0] = 1;
-		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
-			data->block[0] = I2C_SMBUS_BLOCK_MAX;
-	} else {
-		data->block[0] = 32;	/* max for SMBus block reads */
-	}
-
 	/* Experience has shown that the block buffer can only be used for
 	   SMBus (not I2C) block transactions, even though the datasheet
 	   doesn't mention this limitation. */
-	if ((priv->features & FEATURE_BLOCK_BUFFER)
-	 && command != I2C_SMBUS_I2C_BLOCK_DATA
-	 && i801_set_block_buffer_mode(priv) == 0)
+	if ((priv->features & FEATURE_BLOCK_BUFFER) &&
+	    command != I2C_SMBUS_I2C_BLOCK_DATA)
 		result = i801_block_transaction_by_block(priv, data,
 							 read_write,
 							 command, hwpec);
@@ -1069,6 +1051,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
 	{ 0, }
@@ -1265,6 +1248,7 @@
 	 * Additional individual entries were added after verification.
 	 */
 	{ "Vostro V131",        0x1d },
+	{ "Vostro 5568",        0x29 },
 };
 
 static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
@@ -1429,7 +1413,7 @@
 
 	/* Register GPIO descriptor lookup table */
 	lookup = devm_kzalloc(dev,
-			      struct_size(lookup, table, mux_config->n_gpios),
+			      struct_size(lookup, table, mux_config->n_gpios + 1),
 			      GFP_KERNEL);
 	if (!lookup)
 		return -ENOMEM;
@@ -1544,7 +1528,7 @@
 		pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
 	spin_unlock(&p2sb_spinlock);
 
-	res = &tco_res[ICH_RES_MEM_OFF];
+	res = &tco_res[1];
 	if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
 		res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV;
 	else
@@ -1554,7 +1538,7 @@
 	res->flags = IORESOURCE_MEM;
 
 	return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
-					tco_res, 3, &spt_tco_platform_data,
+					tco_res, 2, &spt_tco_platform_data,
 					sizeof(spt_tco_platform_data));
 }
 
@@ -1567,17 +1551,16 @@
 i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
 		 struct resource *tco_res)
 {
-	return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
-					tco_res, 2, &cnl_tco_platform_data,
-					sizeof(cnl_tco_platform_data));
+	return platform_device_register_resndata(&pci_dev->dev,
+			"iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data,
+			sizeof(cnl_tco_platform_data));
 }
 
 static void i801_add_tco(struct i801_priv *priv)
 {
-	u32 base_addr, tco_base, tco_ctl, ctrl_val;
 	struct pci_dev *pci_dev = priv->pci_dev;
-	struct resource tco_res[3], *res;
-	unsigned int devfn;
+	struct resource tco_res[2], *res;
+	u32 tco_base, tco_ctl;
 
 	/* If we have ACPI based watchdog use that instead */
 	if (acpi_has_watchdog())
@@ -1592,30 +1575,15 @@
 		return;
 
 	memset(tco_res, 0, sizeof(tco_res));
-
-	res = &tco_res[ICH_RES_IO_TCO];
-	res->start = tco_base & ~1;
-	res->end = res->start + 32 - 1;
-	res->flags = IORESOURCE_IO;
-
 	/*
-	 * Power Management registers.
+	 * Always populate the main iTCO IO resource here. The second entry
+	 * for NO_REBOOT MMIO is filled by the SPT specific function.
 	 */
-	devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
-	pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
-
-	res = &tco_res[ICH_RES_IO_SMI];
-	res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
-	res->end = res->start + 3;
+	res = &tco_res[0];
+	res->start = tco_base & ~1;
+	res->end = res->start + 32 - 1;
 	res->flags = IORESOURCE_IO;
 
-	/*
-	 * Enable the ACPI I/O space.
-	 */
-	pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
-	ctrl_val |= ACPICTRL_EN;
-	pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
-
 	if (priv->features & FEATURE_TCO_CNL)
 		priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
 	else
@@ -1709,6 +1677,16 @@
 static inline void i801_acpi_remove(struct i801_priv *priv) { }
 #endif
 
+static unsigned char i801_setup_hstcfg(struct i801_priv *priv)
+{
+	unsigned char hstcfg = priv->original_hstcfg;
+
+	hstcfg &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
+	hstcfg |= SMBHSTCFG_HST_EN;
+	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
+	return hstcfg;
+}
+
 static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	unsigned char temp;
@@ -1750,6 +1728,7 @@
 	case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
 	case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
 	case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
+	case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS:
 	case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
 	case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
 		priv->features |= FEATURE_BLOCK_PROC;
@@ -1825,14 +1804,10 @@
 		return err;
 	}
 
-	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
-	priv->original_hstcfg = temp;
-	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
-	if (!(temp & SMBHSTCFG_HST_EN)) {
+	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
+	temp = i801_setup_hstcfg(priv);
+	if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
 		dev_info(&dev->dev, "Enabling SMBus device\n");
-		temp |= SMBHSTCFG_HST_EN;
-	}
-	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
 
 	if (temp & SMBHSTCFG_SMB_SMI_EN) {
 		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
@@ -1894,6 +1869,7 @@
 		"SMBus I801 adapter at %04lx", priv->smba);
 	err = i2c_add_adapter(&priv->adapter);
 	if (err) {
+		platform_device_unregister(priv->tco_pdev);
 		i801_acpi_remove(priv);
 		return err;
 	}
@@ -1906,6 +1882,7 @@
 
 	pci_set_drvdata(dev, priv);
 
+	dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NEVER_SKIP);
 	pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
 	pm_runtime_use_autosuspend(&dev->dev);
 	pm_runtime_put_autosuspend(&dev->dev);
@@ -1958,6 +1935,7 @@
 {
 	struct i801_priv *priv = dev_get_drvdata(dev);
 
+	i801_setup_hstcfg(priv);
 	i801_enable_host_notify(&priv->adapter);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-icy.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-icy.c
@@ -43,6 +43,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
 
+#include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <linux/zorro.h>
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-img-scb.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-img-scb.c
@@ -1057,7 +1057,7 @@
 			atomic = true;
 	}
 
-	ret = pm_runtime_get_sync(adap->dev.parent);
+	ret = pm_runtime_resume_and_get(adap->dev.parent);
 	if (ret < 0)
 		return ret;
 
@@ -1158,7 +1158,7 @@
 	u32 rev;
 	int ret;
 
-	ret = pm_runtime_get_sync(i2c->adap.dev.parent);
+	ret = pm_runtime_resume_and_get(i2c->adap.dev.parent);
 	if (ret < 0)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -206,8 +206,8 @@
 /* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
 static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
 {
-	u8 prescale, filt, sethold, clkhi, clklo, datavd;
-	unsigned int clk_rate, clk_cycle;
+	u8 prescale, filt, sethold, datavd;
+	unsigned int clk_rate, clk_cycle, clkhi, clklo;
 	enum lpi2c_imx_pincfg pincfg;
 	unsigned int temp;
 
@@ -265,7 +265,7 @@
 	unsigned int temp;
 	int ret;
 
-	ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
+	ret = pm_runtime_resume_and_get(lpi2c_imx->adapter.dev.parent);
 	if (ret < 0)
 		return ret;
 
@@ -468,6 +468,8 @@
 		if (num == 1 && msgs[0].len == 0)
 			goto stop;
 
+		lpi2c_imx->rx_buf = NULL;
+		lpi2c_imx->tx_buf = NULL;
 		lpi2c_imx->delivered = 0;
 		lpi2c_imx->msglen = msgs[i].len;
 		init_completion(&lpi2c_imx->complete);
@@ -508,10 +510,14 @@
 static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
 {
 	struct lpi2c_imx_struct *lpi2c_imx = dev_id;
+	unsigned int enabled;
 	unsigned int temp;
 
+	enabled = readl(lpi2c_imx->base + LPI2C_MIER);
+
 	lpi2c_imx_intctrl(lpi2c_imx, 0);
 	temp = readl(lpi2c_imx->base + LPI2C_MSR);
+	temp &= enabled;
 
 	if (temp & MSR_RDF)
 		lpi2c_imx_read_rxfifo(lpi2c_imx);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-imx.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-imx.c
@@ -17,6 +17,7 @@
  *	Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
  *
  *	Copyright 2013 Freescale Semiconductor, Inc.
+ *	Copyright 2020 NXP
  *
  */
 
@@ -75,6 +76,11 @@
 #define IMX_I2C_I2SR	0x03	/* i2c status */
 #define IMX_I2C_I2DR	0x04	/* i2c transfer data */
 
+/*
+ * All of the layerscape series SoCs support IBIC register.
+ */
+#define IMX_I2C_IBIC	0x05    /* i2c bus interrupt config */
+
 #define IMX_I2C_REGSHIFT	2
 #define VF610_I2C_REGSHIFT	0
 
@@ -93,6 +99,7 @@
 #define I2CR_MSTA	0x20
 #define I2CR_IIEN	0x40
 #define I2CR_IEN	0x80
+#define IBIC_BIIE	0x80 /* Bus idle interrupt enable */
 
 /* register bits different operating codes definition:
  * 1) I2SR: Interrupt flags clear operation differ between SoCs:
@@ -203,6 +210,7 @@
 	struct pinctrl_state *pinctrl_pins_gpio;
 
 	struct imx_i2c_dma	*dma;
+	struct i2c_client	*slave;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
@@ -267,6 +275,11 @@
 	return i2c_imx->hwdata->devtype == IMX1_I2C;
 }
 
+static inline int is_vf610_i2c(struct imx_i2c_struct *i2c_imx)
+{
+	return i2c_imx->hwdata->devtype == VF610_I2C;
+}
+
 static inline void imx_i2c_write_reg(unsigned int val,
 		struct imx_i2c_struct *i2c_imx, unsigned int reg)
 {
@@ -279,6 +292,27 @@
 	return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
 }
 
+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);
+}
+
+/* Set up i2c controller register and i2c status register to default value. */
+static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
+{
+	imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+			  i2c_imx, IMX_I2C_I2CR);
+	i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL);
+}
+
 /* Functions for DMA support */
 static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
 						dma_addr_t phy_addr)
@@ -426,8 +460,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;
 		}
 
@@ -458,6 +491,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;
@@ -567,6 +610,8 @@
 		/* Stop I2C transaction */
 		dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+		if (!(temp & I2CR_MSTA))
+			i2c_imx->stopped = 1;
 		temp &= ~(I2CR_MSTA | I2CR_MTX);
 		if (i2c_imx->dma)
 			temp &= ~I2CR_DMAEN;
@@ -588,20 +633,165 @@
 	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
 }
 
+/*
+ * Enable bus idle interrupts
+ * Note: IBIC register will be cleared after disabled i2c module.
+ * All of layerscape series SoCs support IBIC register.
+ */
+static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx)
+{
+	if (is_vf610_i2c(i2c_imx)) {
+		unsigned int temp;
+
+		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_IBIC);
+		temp |= IBIC_BIIE;
+		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_IBIC);
+	}
+}
+
+static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
+				     unsigned int status, unsigned int ctl)
+{
+	u8 value;
+
+	if (status & I2SR_IAL) { /* Arbitration lost */
+		i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+		if (!(status & I2SR_IAAS))
+			return IRQ_HANDLED;
+	}
+
+	if (status & I2SR_IAAS) { /* Addressed as a slave */
+		if (status & I2SR_SRW) { /* Master wants to read from us*/
+			dev_dbg(&i2c_imx->adapter.dev, "read requested");
+			i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
+
+			/* Slave transmit */
+			ctl |= I2CR_MTX;
+			imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+
+			/* Send data */
+			imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
+		} else { /* Master wants to write to us */
+			dev_dbg(&i2c_imx->adapter.dev, "write requested");
+			i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_WRITE_REQUESTED, &value);
+
+			/* Slave receive */
+			ctl &= ~I2CR_MTX;
+			imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+			/* Dummy read */
+			imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+		}
+	} else if (!(ctl & I2CR_MTX)) { /* Receive mode */
+		if (status & I2SR_IBB) { /* No STOP signal detected */
+			value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+			i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_WRITE_RECEIVED, &value);
+		} else { /* STOP signal is detected */
+			dev_dbg(&i2c_imx->adapter.dev,
+				"STOP signal detected");
+			i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
+		}
+	} else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */
+		ctl |= I2CR_MTX;
+		imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+
+		i2c_slave_event(i2c_imx->slave,	I2C_SLAVE_READ_PROCESSED, &value);
+
+		imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
+	} else { /* Transmit mode received NAK */
+		ctl &= ~I2CR_MTX;
+		imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
+		imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
+{
+	int temp;
+
+	/* Set slave addr. */
+	imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
+
+	i2c_imx_reset_regs(i2c_imx);
+
+	/* Enable module */
+	temp = i2c_imx->hwdata->i2cr_ien_opcode;
+	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+	/* Enable interrupt from i2c module */
+	temp |= I2CR_IIEN;
+	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+	i2c_imx_enable_bus_idle(i2c_imx);
+}
+
+static int i2c_imx_reg_slave(struct i2c_client *client)
+{
+	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
+	int ret;
+
+	if (i2c_imx->slave)
+		return -EBUSY;
+
+	i2c_imx->slave = client;
+
+	/* Resume */
+	ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+	if (ret < 0) {
+		dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
+		return ret;
+	}
+
+	i2c_imx_slave_init(i2c_imx);
+
+	return 0;
+}
+
+static int i2c_imx_unreg_slave(struct i2c_client *client)
+{
+	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
+	int ret;
+
+	if (!i2c_imx->slave)
+		return -EINVAL;
+
+	/* Reset slave address. */
+	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
+
+	i2c_imx_reset_regs(i2c_imx);
+
+	i2c_imx->slave = NULL;
+
+	/* Suspend */
+	ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
+	if (ret < 0)
+		dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");
+
+	return ret;
+}
+
+static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status)
+{
+	/* save status register */
+	i2c_imx->i2csr = status;
+	wake_up(&i2c_imx->queue);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
 {
 	struct imx_i2c_struct *i2c_imx = dev_id;
-	unsigned int temp;
+	unsigned int ctl, status;
 
-	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
-	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);
-		wake_up(&i2c_imx->queue);
-		return IRQ_HANDLED;
+	status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+	ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+	if (status & I2SR_IIF) {
+		i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
+		if (i2c_imx->slave && !(ctl & I2CR_MSTA))
+			return i2c_imx_slave_isr(i2c_imx, status, ctl);
+		return i2c_imx_master_isr(i2c_imx, status);
 	}
 
 	return IRQ_NONE;
@@ -732,9 +922,12 @@
 		 */
 		dev_dbg(dev, "<%s> clear MSTA\n", __func__);
 		temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+		if (!(temp & I2CR_MSTA))
+			i2c_imx->stopped = 1;
 		temp &= ~(I2CR_MSTA | I2CR_MTX);
 		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
-		i2c_imx_bus_busy(i2c_imx, 0);
+		if (!i2c_imx->stopped)
+			i2c_imx_bus_busy(i2c_imx, 0);
 	} else {
 		/*
 		 * For i2c master receiver repeat restart operation like:
@@ -857,9 +1050,12 @@
 				dev_dbg(&i2c_imx->adapter.dev,
 					"<%s> clear MSTA\n", __func__);
 				temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+				if (!(temp & I2CR_MSTA))
+					i2c_imx->stopped =  1;
 				temp &= ~(I2CR_MSTA | I2CR_MTX);
 				imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
-				i2c_imx_bus_busy(i2c_imx, 0);
+				if (!i2c_imx->stopped)
+					i2c_imx_bus_busy(i2c_imx, 0);
 			} else {
 				/*
 				 * For i2c master receiver repeat restart operation like:
@@ -974,6 +1170,10 @@
 	dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
 		(result < 0) ? "error" : "success msg",
 			(result < 0) ? result : num);
+	/* After data is transferred, switch to slave mode(as a receiver) */
+	if (i2c_imx->slave)
+		i2c_imx_slave_init(i2c_imx);
+
 	return (result < 0) ? result : num;
 }
 
@@ -1051,6 +1251,8 @@
 static const struct i2c_algorithm i2c_imx_algo = {
 	.master_xfer	= i2c_imx_xfer,
 	.functionality	= i2c_imx_func,
+	.reg_slave	= i2c_imx_reg_slave,
+	.unreg_slave	= i2c_imx_unreg_slave,
 };
 
 static int i2c_imx_probe(struct platform_device *pdev)
@@ -1112,14 +1314,6 @@
 		return ret;
 	}
 
-	/* Request IRQ */
-	ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED,
-				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);
 
@@ -1138,6 +1332,14 @@
 	if (ret < 0)
 		goto rpm_disable;
 
+	/* Request IRQ */
+	ret = request_threaded_irq(irq, i2c_imx_isr, NULL, IRQF_SHARED,
+				   pdev->name, i2c_imx);
+	if (ret) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+		goto rpm_disable;
+	}
+
 	/* Set up clock divider */
 	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
 	ret = of_property_read_u32(pdev->dev.of_node,
@@ -1148,10 +1350,7 @@
 	clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
 	i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
 
-	/* Set up chip registers to defaults */
-	imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
-			i2c_imx, IMX_I2C_I2CR);
-	imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+	i2c_imx_reset_regs(i2c_imx);
 
 	/* Init optional bus recovery function */
 	ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
@@ -1180,13 +1379,12 @@
 
 clk_notifier_unregister:
 	clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+	free_irq(irq, i2c_imx);
 rpm_disable:
 	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
-
-clk_disable:
 	clk_disable_unprepare(i2c_imx->clk);
 	return ret;
 }
@@ -1194,7 +1392,7 @@
 static int i2c_imx_remove(struct platform_device *pdev)
 {
 	struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
-	int ret;
+	int irq, ret;
 
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0)
@@ -1214,6 +1412,9 @@
 	imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
 
 	clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0)
+		free_irq(irq, i2c_imx);
 	clk_disable_unprepare(i2c_imx->clk);
 
 	pm_runtime_put_noidle(&pdev->dev);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-iop3xx.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-iop3xx.c
@@ -433,13 +433,17 @@
 	adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev,
 							 "scl",
 							 GPIOD_ASIS);
-	if (IS_ERR(adapter_data->gpio_scl))
-		return PTR_ERR(adapter_data->gpio_scl);
+	if (IS_ERR(adapter_data->gpio_scl)) {
+		ret = PTR_ERR(adapter_data->gpio_scl);
+		goto free_both;
+	}
 	adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev,
 							 "sda",
 							 GPIOD_ASIS);
-	if (IS_ERR(adapter_data->gpio_sda))
-		return PTR_ERR(adapter_data->gpio_sda);
+	if (IS_ERR(adapter_data->gpio_sda)) {
+		ret = PTR_ERR(adapter_data->gpio_sda);
+		goto free_both;
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -463,16 +467,14 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		ret = -ENXIO;
+		ret = irq;
 		goto unmap;
 	}
 	ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
 				pdev->name, adapter_data);
 
-	if (ret) {
-		ret = -EIO;
+	if (ret)
 		goto unmap;
-	}
 
 	memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
 	new_adapter->owner = THIS_MODULE;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-ismt.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-ismt.c
@@ -81,6 +81,7 @@
 
 #define ISMT_DESC_ENTRIES	2	/* number of descriptor entries */
 #define ISMT_MAX_RETRIES	3	/* number of SMBus retries to attempt */
+#define ISMT_LOG_ENTRIES	3	/* number of interrupt cause log entries */
 
 /* Hardware Descriptor Constants - Control Field */
 #define ISMT_DESC_CWRL	0x01	/* Command/Write Length */
@@ -174,6 +175,8 @@
 	u8 head;				/* ring buffer head pointer */
 	struct completion cmp;			/* interrupt completion */
 	u8 buffer[I2C_SMBUS_BLOCK_MAX + 16];	/* temp R/W data buffer */
+	dma_addr_t log_dma;
+	u32 *log;
 };
 
 /**
@@ -408,6 +411,9 @@
 	memset(desc, 0, sizeof(struct ismt_desc));
 	desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
 
+	/* Always clear the log entries */
+	memset(priv->log, 0, ISMT_LOG_ENTRIES * sizeof(u32));
+
 	/* Initialize common control bits */
 	if (likely(pci_dev_msi_enabled(priv->pci_dev)))
 		desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
@@ -500,6 +506,9 @@
 		if (read_write == I2C_SMBUS_WRITE) {
 			/* Block Write */
 			dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA:  WRITE\n");
+			if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+				return -EINVAL;
+
 			dma_size = data->block[0] + 1;
 			dma_direction = DMA_TO_DEVICE;
 			desc->wr_len_cmd = dma_size;
@@ -697,6 +706,8 @@
 	/* initialize the Master Descriptor Base Address (MDBA) */
 	writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA);
 
+	writeq(priv->log_dma, priv->smba + ISMT_GR_SMTICL);
+
 	/* initialize the Master Control Register (MCTRL) */
 	writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL);
 
@@ -784,6 +795,12 @@
 	priv->head = 0;
 	init_completion(&priv->cmp);
 
+	priv->log = dmam_alloc_coherent(&priv->pci_dev->dev,
+					ISMT_LOG_ENTRIES * sizeof(u32),
+					&priv->log_dma, GFP_KERNEL);
+	if (!priv->log)
+		return -ENOMEM;
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-jz4780.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-jz4780.c
@@ -73,25 +73,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)
@@ -529,21 +510,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,
@@ -783,7 +751,10 @@
 
 	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
 
-	i2c->irq = platform_get_irq(pdev, 0);
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto err;
+	i2c->irq = ret;
 	ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
 			       dev_name(&pdev->dev), i2c);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-meson.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-meson.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/i2c.h>
@@ -32,12 +33,17 @@
 #define REG_CTRL_ACK_IGNORE	BIT(1)
 #define REG_CTRL_STATUS		BIT(2)
 #define REG_CTRL_ERROR		BIT(3)
-#define REG_CTRL_CLKDIV_SHIFT	12
-#define REG_CTRL_CLKDIV_MASK	GENMASK(21, 12)
-#define REG_CTRL_CLKDIVEXT_SHIFT 28
-#define REG_CTRL_CLKDIVEXT_MASK	GENMASK(29, 28)
+#define REG_CTRL_CLKDIV		GENMASK(21, 12)
+#define REG_CTRL_CLKDIVEXT	GENMASK(29, 28)
+
+#define REG_SLV_ADDR		GENMASK(7, 0)
+#define REG_SLV_SDA_FILTER	GENMASK(10, 8)
+#define REG_SLV_SCL_FILTER	GENMASK(13, 11)
+#define REG_SLV_SCL_LOW		GENMASK(27, 16)
+#define REG_SLV_SCL_LOW_EN	BIT(28)
 
 #define I2C_TIMEOUT_MS		500
+#define FILTER_DELAY		15
 
 enum {
 	TOKEN_END = 0,
@@ -132,19 +138,24 @@
 	unsigned long clk_rate = clk_get_rate(i2c->clk);
 	unsigned int div;
 
-	div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
+	div = DIV_ROUND_UP(clk_rate, freq);
+	div -= FILTER_DELAY;
+	div = DIV_ROUND_UP(div, i2c->data->div_factor);
 
 	/* clock divider has 12 bits */
-	if (div >= (1 << 12)) {
+	if (div > GENMASK(11, 0)) {
 		dev_err(i2c->dev, "requested bus frequency too low\n");
-		div = (1 << 12) - 1;
+		div = GENMASK(11, 0);
 	}
 
-	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
-			   (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
+	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
+			   FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
+
+	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
+			   FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
 
-	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
-			   (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
+	/* Disable HIGH/LOW mode */
+	meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
 
 	dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
 		clk_rate, freq, div);
@@ -273,7 +284,10 @@
 	token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
 		TOKEN_SLAVE_ADDR_WRITE;
 
-	writel(msg->addr << 1, i2c->regs + REG_SLAVE_ADDR);
+
+	meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
+			   FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
+
 	meson_i2c_add_token(i2c, TOKEN_START);
 	meson_i2c_add_token(i2c, token);
 }
@@ -432,6 +446,10 @@
 		return ret;
 	}
 
+	/* Disable filtering */
+	meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
+			   REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
+
 	meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-mlxcpld.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-mlxcpld.c
@@ -337,9 +337,9 @@
 		if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {
 			mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
 					      &datalen, 1);
-			if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) {
+			if (unlikely(datalen > I2C_SMBUS_BLOCK_MAX)) {
 				dev_err(priv->dev, "Incorrect smbus block read message len\n");
-				return -E2BIG;
+				return -EPROTO;
 			}
 		} else {
 			datalen = priv->xfer.data_len;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-mpc.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-mpc.c
@@ -23,6 +23,7 @@
 
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
@@ -49,6 +50,7 @@
 #define CCR_MTX  0x10
 #define CCR_TXAK 0x08
 #define CCR_RSTA 0x04
+#define CCR_RSVD 0x02
 
 #define CSR_MCF  0x80
 #define CSR_MAAS 0x40
@@ -70,6 +72,7 @@
 	u8 fdr, dfsrr;
 #endif
 	struct clk *clk_per;
+	bool has_errata_A004447;
 };
 
 struct mpc_i2c_divider {
@@ -102,23 +105,30 @@
 /* Sometimes 9th clock pulse isn't generated, and slave doesn't release
  * the bus, because it wants to send ACK.
  * Following sequence of enabling/disabling and sending start/stop generates
- * the 9 pulses, so it's all OK.
+ * the 9 pulses, each with a START then ending with STOP, so it's all OK.
  */
 static void mpc_i2c_fixup(struct mpc_i2c *i2c)
 {
 	int k;
-	u32 delay_val = 1000000 / i2c->real_clk + 1;
-
-	if (delay_val < 2)
-		delay_val = 2;
+	unsigned long flags;
 
 	for (k = 9; k; k--) {
 		writeccr(i2c, 0);
-		writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+		writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */
+		writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */
+		readb(i2c->base + MPC_I2C_DR); /* init xfer */
+		udelay(15); /* let it hit the bus */
+		local_irq_save(flags); /* should not be delayed further */
+		writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */
 		readb(i2c->base + MPC_I2C_DR);
-		writeccr(i2c, CCR_MEN);
-		udelay(delay_val << 1);
-	}
+		if (k != 1)
+			udelay(5);
+		local_irq_restore(flags);
+	}
+	writeccr(i2c, CCR_MEN); /* Initiate STOP */
+	readb(i2c->base + MPC_I2C_DR);
+	udelay(15); /* Let STOP propagate */
+	writeccr(i2c, 0);
 }
 
 static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
@@ -176,6 +186,75 @@
 	return 0;
 }
 
+static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask)
+{
+	void __iomem *addr = i2c->base + MPC_I2C_SR;
+	u8 val;
+
+	return readb_poll_timeout(addr, val, val & mask, 0, 100);
+}
+
+/*
+ * Workaround for Erratum A004447. From the P2040CE Rev Q
+ *
+ * 1.  Set up the frequency divider and sampling rate.
+ * 2.  I2CCR - a0h
+ * 3.  Poll for I2CSR[MBB] to get set.
+ * 4.  If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to
+ *     step 5. If MAL is not set, then go to step 13.
+ * 5.  I2CCR - 00h
+ * 6.  I2CCR - 22h
+ * 7.  I2CCR - a2h
+ * 8.  Poll for I2CSR[MBB] to get set.
+ * 9.  Issue read to I2CDR.
+ * 10. Poll for I2CSR[MIF] to be set.
+ * 11. I2CCR - 82h
+ * 12. Workaround complete. Skip the next steps.
+ * 13. Issue read to I2CDR.
+ * 14. Poll for I2CSR[MIF] to be set.
+ * 15. I2CCR - 80h
+ */
+static void mpc_i2c_fixup_A004447(struct mpc_i2c *i2c)
+{
+	int ret;
+	u32 val;
+
+	writeccr(i2c, CCR_MEN | CCR_MSTA);
+	ret = i2c_mpc_wait_sr(i2c, CSR_MBB);
+	if (ret) {
+		dev_err(i2c->dev, "timeout waiting for CSR_MBB\n");
+		return;
+	}
+
+	val = readb(i2c->base + MPC_I2C_SR);
+
+	if (val & CSR_MAL) {
+		writeccr(i2c, 0x00);
+		writeccr(i2c, CCR_MSTA | CCR_RSVD);
+		writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD);
+		ret = i2c_mpc_wait_sr(i2c, CSR_MBB);
+		if (ret) {
+			dev_err(i2c->dev, "timeout waiting for CSR_MBB\n");
+			return;
+		}
+		val = readb(i2c->base + MPC_I2C_DR);
+		ret = i2c_mpc_wait_sr(i2c, CSR_MIF);
+		if (ret) {
+			dev_err(i2c->dev, "timeout waiting for CSR_MIF\n");
+			return;
+		}
+		writeccr(i2c, CCR_MEN | CCR_RSVD);
+	} else {
+		val = readb(i2c->base + MPC_I2C_DR);
+		ret = i2c_mpc_wait_sr(i2c, CSR_MIF);
+		if (ret) {
+			dev_err(i2c->dev, "timeout waiting for CSR_MIF\n");
+			return;
+		}
+		writeccr(i2c, CCR_MEN);
+	}
+}
+
 #if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
 static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
 	{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
@@ -586,7 +665,7 @@
 			if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
 				writeb(status & ~CSR_MAL,
 				       i2c->base + MPC_I2C_SR);
-				mpc_i2c_fixup(i2c);
+				i2c_recover_bus(&i2c->adap);
 			}
 			return -EIO;
 		}
@@ -622,7 +701,7 @@
 			if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
 				writeb(status & ~CSR_MAL,
 				       i2c->base + MPC_I2C_SR);
-				mpc_i2c_fixup(i2c);
+				i2c_recover_bus(&i2c->adap);
 			}
 			return -EIO;
 		}
@@ -637,6 +716,18 @@
 	  | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
 }
 
+static int fsl_i2c_bus_recovery(struct i2c_adapter *adap)
+{
+	struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+	if (i2c->has_errata_A004447)
+		mpc_i2c_fixup_A004447(i2c);
+	else
+		mpc_i2c_fixup(i2c);
+
+	return 0;
+}
+
 static const struct i2c_algorithm mpc_algo = {
 	.master_xfer = mpc_xfer,
 	.functionality = mpc_functionality,
@@ -648,6 +739,10 @@
 	.timeout = HZ,
 };
 
+static struct i2c_bus_recovery_info fsl_i2c_recovery_info = {
+	.recover_bus = fsl_i2c_bus_recovery,
+};
+
 static const struct of_device_id mpc_i2c_of_match[];
 static int fsl_i2c_probe(struct platform_device *op)
 {
@@ -732,6 +827,8 @@
 	dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
 
 	platform_set_drvdata(op, i2c);
+	if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447"))
+		i2c->has_errata_A004447 = true;
 
 	i2c->adap = mpc_ops;
 	of_address_to_resource(op->dev.of_node, 0, &res);
@@ -740,6 +837,7 @@
 	i2c_set_adapdata(&i2c->adap, i2c);
 	i2c->adap.dev.parent = &op->dev;
 	i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
+	i2c->adap.bus_recovery_info = &fsl_i2c_recovery_info;
 
 	result = i2c_add_adapter(&i2c->adap);
 	if (result < 0)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-mt65xx.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-mt65xx.c
@@ -389,6 +389,10 @@
 {
 	u16 control_reg;
 
+	writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
+	udelay(50);
+	writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
+
 	mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET);
 
 	/* Set ioconfig */
@@ -419,10 +423,6 @@
 
 	mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
 	mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
-
-	writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
-	udelay(50);
-	writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
 }
 
 /*
@@ -932,7 +932,7 @@
 		return PTR_ERR(i2c->pdmabase);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
+	if (irq < 0)
 		return irq;
 
 	init_completion(&i2c->msg_complete);
@@ -1008,7 +1008,8 @@
 	mtk_i2c_clock_disable(i2c);
 
 	ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
-			       IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
+			       IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
+			       I2C_DRV_NAME, i2c);
 	if (ret < 0) {
 		dev_err(&pdev->dev,
 			"Request I2C IRQ %d fail\n", irq);
@@ -1035,7 +1036,16 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int mtk_i2c_resume(struct device *dev)
+static int mtk_i2c_suspend_noirq(struct device *dev)
+{
+	struct mtk_i2c *i2c = dev_get_drvdata(dev);
+
+	i2c_mark_adapter_suspended(&i2c->adap);
+
+	return 0;
+}
+
+static int mtk_i2c_resume_noirq(struct device *dev)
 {
 	int ret;
 	struct mtk_i2c *i2c = dev_get_drvdata(dev);
@@ -1050,12 +1060,15 @@
 
 	mtk_i2c_clock_disable(i2c);
 
+	i2c_mark_adapter_resumed(&i2c->adap);
+
 	return 0;
 }
 #endif
 
 static const struct dev_pm_ops mtk_i2c_pm = {
-	SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq,
+				      mtk_i2c_resume_noirq)
 };
 
 static struct platform_driver mtk_i2c_driver = {
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-mt7621.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-mt7621.c
@@ -304,7 +304,8 @@
 
 	if (i2c->bus_freq == 0) {
 		dev_warn(i2c->dev, "clock-frequency 0 not supported\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_disable_clk;
 	}
 
 	adap = &i2c->adap;
@@ -322,10 +323,15 @@
 
 	ret = i2c_add_adapter(adap);
 	if (ret < 0)
-		return ret;
+		goto err_disable_clk;
 
 	dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000);
 
+	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(i2c->clk);
+
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-mxs.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-mxs.c
@@ -25,6 +25,7 @@
 #include <linux/of_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/mxs-dma.h>
 
 #define DRIVER_NAME "mxs-i2c"
 
@@ -200,7 +201,8 @@
 		dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
 		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
 					DMA_MEM_TO_DEV,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+					DMA_PREP_INTERRUPT |
+					MXS_DMA_CTRL_WAIT4END);
 		if (!desc) {
 			dev_err(i2c->dev,
 				"Failed to get DMA data write descriptor.\n");
@@ -228,7 +230,8 @@
 		dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
 		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
 					DMA_DEV_TO_MEM,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+					DMA_PREP_INTERRUPT |
+					MXS_DMA_CTRL_WAIT4END);
 		if (!desc) {
 			dev_err(i2c->dev,
 				"Failed to get DMA data write descriptor.\n");
@@ -260,7 +263,8 @@
 		dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
 		desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
 					DMA_MEM_TO_DEV,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+					DMA_PREP_INTERRUPT |
+					MXS_DMA_CTRL_WAIT4END);
 		if (!desc) {
 			dev_err(i2c->dev,
 				"Failed to get DMA data write descriptor.\n");
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -8,6 +8,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -75,20 +76,15 @@
 
 static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
 {
-	unsigned long target = jiffies + msecs_to_jiffies(1000);
 	u32 val;
+	int ret;
 
-	do {
-		val = readl(i2cd->regs + I2C_MST_CNTL);
-		if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
-			break;
-		if ((val & I2C_MST_CNTL_STATUS) !=
-				I2C_MST_CNTL_STATUS_BUS_BUSY)
-			break;
-		usleep_range(500, 600);
-	} while (time_is_after_jiffies(target));
+	ret = readl_poll_timeout(i2cd->regs + I2C_MST_CNTL, val,
+				 !(val & I2C_MST_CNTL_CYCLE_TRIGGER) ||
+				 (val & I2C_MST_CNTL_STATUS) != I2C_MST_CNTL_STATUS_BUS_BUSY,
+				 500, 1000 * USEC_PER_MSEC);
 
-	if (time_is_before_jiffies(target)) {
+	if (ret) {
 		dev_err(i2cd->dev, "i2c timeout error %x\n", val);
 		return -ETIMEDOUT;
 	}
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-ocores.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-ocores.c
@@ -343,18 +343,18 @@
  * ocores_isr(), we just add our polling code around it.
  *
  * It can run in atomic context
+ *
+ * Return: 0 on success, -ETIMEDOUT on timeout
  */
-static void ocores_process_polling(struct ocores_i2c *i2c)
+static int ocores_process_polling(struct ocores_i2c *i2c)
 {
-	while (1) {
-		irqreturn_t ret;
-		int err;
+	irqreturn_t ret;
+	int err = 0;
 
+	while (1) {
 		err = ocores_poll_wait(i2c);
-		if (err) {
-			i2c->state = STATE_ERROR;
+		if (err)
 			break; /* timeout */
-		}
 
 		ret = ocores_isr(-1, i2c);
 		if (ret == IRQ_NONE)
@@ -365,13 +365,15 @@
 					break;
 		}
 	}
+
+	return err;
 }
 
 static int ocores_xfer_core(struct ocores_i2c *i2c,
 			    struct i2c_msg *msgs, int num,
 			    bool polling)
 {
-	int ret;
+	int ret = 0;
 	u8 ctrl;
 
 	ctrl = oc_getreg(i2c, OCI2C_CONTROL);
@@ -389,15 +391,16 @@
 	oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
 
 	if (polling) {
-		ocores_process_polling(i2c);
+		ret = ocores_process_polling(i2c);
 	} else {
-		ret = wait_event_timeout(i2c->wait,
-					 (i2c->state == STATE_ERROR) ||
-					 (i2c->state == STATE_DONE), HZ);
-		if (ret == 0) {
-			ocores_process_timeout(i2c);
-			return -ETIMEDOUT;
-		}
+		if (wait_event_timeout(i2c->wait,
+				       (i2c->state == STATE_ERROR) ||
+				       (i2c->state == STATE_DONE), HZ) == 0)
+			ret = -ETIMEDOUT;
+	}
+	if (ret) {
+		ocores_process_timeout(i2c);
+		return ret;
 	}
 
 	return (i2c->state == STATE_DONE) ? num : -EIO;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-octeon-core.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-octeon-core.c
@@ -347,7 +347,7 @@
 		if (result)
 			return result;
 		if (recv_len && i == 0) {
-			if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
+			if (data[i] > I2C_SMBUS_BLOCK_MAX)
 				return -EPROTO;
 			length += data[i];
 		}
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-omap.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-omap.c
@@ -1058,7 +1058,7 @@
 	u16 stat;
 
 	stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
-	mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+	mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK;
 
 	if (stat & mask)
 		ret = IRQ_WAKE_THREAD;
@@ -1408,9 +1408,9 @@
 	pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT);
 	pm_runtime_use_autosuspend(omap->dev);
 
-	r = pm_runtime_get_sync(omap->dev);
+	r = pm_runtime_resume_and_get(omap->dev);
 	if (r < 0)
-		goto err_free_mem;
+		goto err_disable_pm;
 
 	/*
 	 * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
@@ -1518,8 +1518,8 @@
 	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
 	pm_runtime_dont_use_autosuspend(omap->dev);
 	pm_runtime_put_sync(omap->dev);
+err_disable_pm:
 	pm_runtime_disable(&pdev->dev);
-err_free_mem:
 
 	return r;
 }
@@ -1530,7 +1530,7 @@
 	int ret;
 
 	i2c_del_adapter(&omap->adapter);
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-owl.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-owl.c
@@ -179,6 +179,9 @@
 	fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
 	if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
 		i2c_dev->err = -ENXIO;
+		/* Clear NACK error bit by writing "1" */
+		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+				   OWL_I2C_FIFOSTAT_RNB, true);
 		goto stop;
 	}
 
@@ -186,6 +189,9 @@
 	stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
 	if (stat & OWL_I2C_STAT_BEB) {
 		i2c_dev->err = -EIO;
+		/* Clear BUS error bit by writing "1" */
+		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
+				   OWL_I2C_STAT_BEB, true);
 		goto stop;
 	}
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-pasemi.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-pasemi.c
@@ -137,6 +137,12 @@
 
 		TXFIFO_WR(smbus, msg->buf[msg->len-1] |
 			  (stop ? MTXFIFO_STOP : 0));
+
+		if (stop) {
+			err = pasemi_smb_waitready(smbus);
+			if (err)
+				goto reset_out;
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-pca-platform.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-pca-platform.c
@@ -140,7 +140,7 @@
 	int ret = 0;
 	int irq;
 
-	irq = platform_get_irq(pdev, 0);
+	irq = platform_get_irq_optional(pdev, 0);
 	/* If irq is 0, we do polling. */
 	if (irq < 0)
 		irq = 0;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-piix4.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-piix4.c
@@ -977,7 +977,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-ein-5.4.0.orig/drivers/i2c/busses/i2c-pxa-pci.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-pxa-pci.c
@@ -105,7 +105,7 @@
 	int i;
 	struct ce4100_devices *sds;
 
-	ret = pci_enable_device_mem(dev);
+	ret = pcim_enable_device(dev);
 	if (ret)
 		return ret;
 
@@ -114,10 +114,8 @@
 		return -EINVAL;
 	}
 	sds = kzalloc(sizeof(*sds), GFP_KERNEL);
-	if (!sds) {
-		ret = -ENOMEM;
-		goto err_mem;
-	}
+	if (!sds)
+		return -ENOMEM;
 
 	for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
 		sds->pdev[i] = add_i2c_device(dev, i);
@@ -133,8 +131,6 @@
 
 err_dev_add:
 	kfree(sds);
-err_mem:
-	pci_disable_device(dev);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-pxa.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-pxa.c
@@ -312,11 +312,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 */
@@ -706,11 +705,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-ein-5.4.0.orig/drivers/i2c/busses/i2c-qcom-geni.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-qcom-geni.c
@@ -87,6 +87,9 @@
 	u32 clk_freq_out;
 	const struct geni_i2c_clk_fld *clk_fld;
 	int suspended;
+	void *dma_buf;
+	size_t xfer_len;
+	dma_addr_t dma_addr;
 };
 
 struct geni_i2c_err_log {
@@ -350,14 +353,39 @@
 		dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
 }
 
+static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c,
+				     struct i2c_msg *cur)
+{
+	gi2c->cur_rd = 0;
+	if (gi2c->dma_buf) {
+		if (gi2c->err)
+			geni_i2c_rx_fsm_rst(gi2c);
+		geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
+		i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
+	}
+}
+
+static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
+				     struct i2c_msg *cur)
+{
+	gi2c->cur_wr = 0;
+	if (gi2c->dma_buf) {
+		if (gi2c->err)
+			geni_i2c_tx_fsm_rst(gi2c);
+		geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
+		i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
+	}
+}
+
 static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 				u32 m_param)
 {
-	dma_addr_t rx_dma;
+	dma_addr_t rx_dma = 0;
 	unsigned long time_left;
 	void *dma_buf = NULL;
 	struct geni_se *se = &gi2c->se;
 	size_t len = msg->len;
+	struct i2c_msg *cur;
 
 	if (!of_machine_is_compatible("lenovo,yoga-c630"))
 		dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
@@ -374,19 +402,18 @@
 		geni_se_select_mode(se, GENI_SE_FIFO);
 		i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
 		dma_buf = NULL;
+	} else {
+		gi2c->xfer_len = len;
+		gi2c->dma_addr = rx_dma;
+		gi2c->dma_buf = dma_buf;
 	}
 
+	cur = gi2c->cur;
 	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
 	if (!time_left)
 		geni_i2c_abort_xfer(gi2c);
 
-	gi2c->cur_rd = 0;
-	if (dma_buf) {
-		if (gi2c->err)
-			geni_i2c_rx_fsm_rst(gi2c);
-		geni_se_rx_dma_unprep(se, rx_dma, len);
-		i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
-	}
+	geni_i2c_rx_msg_cleanup(gi2c, cur);
 
 	return gi2c->err;
 }
@@ -394,11 +421,12 @@
 static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 				u32 m_param)
 {
-	dma_addr_t tx_dma;
+	dma_addr_t tx_dma = 0;
 	unsigned long time_left;
 	void *dma_buf = NULL;
 	struct geni_se *se = &gi2c->se;
 	size_t len = msg->len;
+	struct i2c_msg *cur;
 
 	if (!of_machine_is_compatible("lenovo,yoga-c630"))
 		dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
@@ -415,22 +443,21 @@
 		geni_se_select_mode(se, GENI_SE_FIFO);
 		i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
 		dma_buf = NULL;
+	} else {
+		gi2c->xfer_len = len;
+		gi2c->dma_addr = tx_dma;
+		gi2c->dma_buf = dma_buf;
 	}
 
 	if (!dma_buf) /* Get FIFO IRQ */
 		writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
 
+	cur = gi2c->cur;
 	time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
 	if (!time_left)
 		geni_i2c_abort_xfer(gi2c);
 
-	gi2c->cur_wr = 0;
-	if (dma_buf) {
-		if (gi2c->err)
-			geni_i2c_tx_fsm_rst(gi2c);
-		geni_se_tx_dma_unprep(se, tx_dma, len);
-		i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
-	}
+	geni_i2c_tx_msg_cleanup(gi2c, cur);
 
 	return gi2c->err;
 }
@@ -614,6 +641,14 @@
 	return 0;
 }
 
+static void geni_i2c_shutdown(struct platform_device *pdev)
+{
+	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
+
+	/* Make client i2c transfers start failing */
+	i2c_mark_adapter_suspended(&gi2c->adap);
+}
+
 static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
 {
 	int ret;
@@ -650,6 +685,8 @@
 {
 	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
 
+	i2c_mark_adapter_suspended(&gi2c->adap);
+
 	if (!gi2c->suspended) {
 		geni_i2c_runtime_suspend(dev);
 		pm_runtime_disable(dev);
@@ -659,8 +696,16 @@
 	return 0;
 }
 
+static int __maybe_unused geni_i2c_resume_noirq(struct device *dev)
+{
+	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+	i2c_mark_adapter_resumed(&gi2c->adap);
+	return 0;
+}
+
 static const struct dev_pm_ops geni_i2c_pm_ops = {
-	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, NULL)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, geni_i2c_resume_noirq)
 	SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume,
 									NULL)
 };
@@ -674,6 +719,7 @@
 static struct platform_driver geni_i2c_driver = {
 	.probe  = geni_i2c_probe,
 	.remove = geni_i2c_remove,
+	.shutdown = geni_i2c_shutdown,
 	.driver = {
 		.name = "geni_i2c",
 		.pm = &geni_i2c_pm_ops,
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-qup.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-qup.c
@@ -806,7 +806,8 @@
 	if (ret || qup->bus_err || qup->qup_err) {
 		reinit_completion(&qup->xfer);
 
-		if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+		if (ret) {
 			dev_err(qup->dev, "change to run state timed out");
 			goto desc_err;
 		}
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-rcar.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-rcar.c
@@ -89,7 +89,6 @@
 
 #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)
@@ -117,6 +116,7 @@
 };
 
 struct rcar_i2c_priv {
+	u32 flags;
 	void __iomem *io;
 	struct i2c_adapter adap;
 	struct i2c_msg *msg;
@@ -127,7 +127,6 @@
 
 	int pos;
 	u32 icccr;
-	u32 flags;
 	u8 recovery_icmcr;	/* protected by adapter lock */
 	enum rcar_i2c_type devtype;
 	struct i2c_client *slave;
@@ -580,13 +579,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);
 	}
 
@@ -614,7 +615,7 @@
 /*
  * This driver has a lock-free design because there are IP cores (at least
  * R-Car Gen2) which have an inherent race condition in their hardware design.
- * There, we need to clear RCAR_BUS_MASK_DATA bits as soon as possible after
+ * There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after
  * the interrupt was generated, otherwise an unwanted repeated message gets
  * generated. It turned out that taking a spinlock at the beginning of the ISR
  * was already causing repeated messages. Thus, this driver was converted to
@@ -623,13 +624,11 @@
 static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
 {
 	struct rcar_i2c_priv *priv = ptr;
-	u32 msr, val;
+	u32 msr;
 
 	/* Clear START or STOP immediately, except for REPSTART after read */
-	if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) {
-		val = rcar_i2c_read(priv, ICMCR);
-		rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
-	}
+	if (likely(!(priv->flags & ID_P_REP_AFTER_RD)))
+		rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
 
 	msr = rcar_i2c_read(priv, ICMSR);
 
@@ -850,7 +849,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;
@@ -862,11 +861,14 @@
 
 	WARN_ON(!priv->slave);
 
-	/* disable irqs and ensure none is running before clearing ptr */
+	/* ensure no irq is running before clearing ptr */
+	disable_irq(priv->irq);
 	rcar_i2c_write(priv, ICSIER, 0);
-	rcar_i2c_write(priv, ICSCR, 0);
+	rcar_i2c_write(priv, ICSSR, 0);
+	enable_irq(priv->irq);
+	rcar_i2c_write(priv, ICSCR, SDBS);
+	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
 
-	synchronize_irq(priv->irq);
 	priv->slave = NULL;
 
 	pm_runtime_put(rcar_i2c_priv_to_dev(priv));
@@ -971,6 +973,8 @@
 	if (ret < 0)
 		goto out_pm_put;
 
+	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
+
 	if (priv->devtype == I2C_RCAR_GEN3) {
 		priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 		if (!IS_ERR(priv->rstc)) {
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-rk3x.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-rk3x.c
@@ -79,7 +79,7 @@
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
- * struct i2c_spec_values:
+ * struct i2c_spec_values - I2C specification values for various modes
  * @min_hold_start_ns: min hold time (repeated) START condition
  * @min_low_ns: min LOW period of the SCL clock
  * @min_high_ns: min HIGH period of the SCL cloc
@@ -135,7 +135,7 @@
 };
 
 /**
- * struct rk3x_i2c_calced_timings:
+ * struct rk3x_i2c_calced_timings - calculated V1 timings
  * @div_low: Divider output for low
  * @div_high: Divider output for high
  * @tuning: Used to adjust setup/hold data time,
@@ -158,7 +158,7 @@
 };
 
 /**
- * struct rk3x_i2c_soc_data:
+ * struct rk3x_i2c_soc_data - SOC-specific data
  * @grf_offset: offset inside the grf regmap for setting the i2c type
  * @calc_timings: Callback function for i2c timing information calculated
  */
@@ -238,7 +238,8 @@
 }
 
 /**
- * Generate a START condition, which triggers a REG_INT_START interrupt.
+ * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
+ * @i2c: target controller data
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
@@ -257,8 +258,8 @@
 }
 
 /**
- * Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
- *
+ * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
+ * @i2c: target controller data
  * @error: Error code to return in rk3x_i2c_xfer
  */
 static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
@@ -297,7 +298,8 @@
 }
 
 /**
- * Setup a read according to i2c->msg
+ * rk3x_i2c_prepare_read - Setup a read according to i2c->msg
+ * @i2c: target controller data
  */
 static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
 {
@@ -328,7 +330,8 @@
 }
 
 /**
- * Fill the transmit buffer with data from i2c->msg
+ * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg
+ * @i2c: target controller data
  */
 static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
 {
@@ -415,15 +418,15 @@
 {
 	unsigned int i;
 	unsigned int len = i2c->msg->len - i2c->processed;
-	u32 uninitialized_var(val);
+	u32 val;
 	u8 byte;
 
 	/* we only care for MBRF here. */
 	if (!(ipd & REG_INT_MBRF))
 		return;
 
-	/* ack interrupt */
-	i2c_writel(i2c, REG_INT_MBRF, REG_IPD);
+	/* ack interrupt (read also produces a spurious START flag, clear it too) */
+	i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD);
 
 	/* Can only handle a maximum of 32 bytes at a time */
 	if (len > 32)
@@ -531,11 +534,10 @@
 }
 
 /**
- * Get timing values of I2C specification
- *
+ * rk3x_i2c_get_spec - Get timing values of I2C specification
  * @speed: Desired SCL frequency
  *
- * Returns: Matched i2c spec values.
+ * Return: Matched i2c_spec_values.
  */
 static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
@@ -548,13 +550,12 @@
 }
 
 /**
- * Calculate divider values for desired SCL frequency
- *
+ * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
  * @t_calc: Caculated rk3x private timings that would be written into regs
  *
- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
@@ -709,13 +710,12 @@
 }
 
 /**
- * Calculate timing values for desired SCL frequency
- *
+ * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
  * @t_calc: Caculated rk3x private timings that would be written into regs
  *
- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  * The following formulas are v1's method to calculate timings.
@@ -959,14 +959,14 @@
 }
 
 /**
- * Setup I2C registers for an I2C operation specified by msgs, num.
- *
- * Must be called with i2c->lock held.
- *
+ * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num.
+ * @i2c: target controller data
  * @msgs: I2C msgs to process
  * @num: Number of msgs
  *
- * returns: Number of I2C msgs processed or negative in case of error
+ * Must be called with i2c->lock held.
+ *
+ * Return: Number of I2C msgs processed or negative in case of error
  */
 static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
 {
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-robotfuzz-osif.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -83,7 +83,7 @@
 			}
 		}
 
-		ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
+		ret = osif_usb_write(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
 		if (ret) {
 			dev_err(&adapter->dev, "failure sending STOP\n");
 			return -EREMOTEIO;
@@ -153,7 +153,7 @@
 	 * Set bus frequency. The frequency is:
 	 * 120,000,000 / ( 16 + 2 * div * 4^prescale).
 	 * Using dev = 52, prescale = 0 give 100KHz */
-	ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
+	ret = osif_usb_write(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
 			    NULL, 0);
 	if (ret) {
 		dev_err(&interface->dev, "failure sending bit rate");
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-s3c2410.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-s3c2410.c
@@ -223,8 +223,17 @@
 	int tries;
 
 	for (tries = 50; tries; --tries) {
-		if (readl(i2c->regs + S3C2410_IICCON)
-			& S3C2410_IICCON_IRQPEND) {
+		unsigned long tmp = readl(i2c->regs + S3C2410_IICCON);
+
+		if (!(tmp & S3C2410_IICCON_ACKEN)) {
+			/*
+			 * Wait a bit for the bus to stabilize,
+			 * delay estimated experimentally.
+			 */
+			usleep_range(100, 200);
+			return true;
+		}
+		if (tmp & S3C2410_IICCON_IRQPEND) {
 			if (!(readl(i2c->regs + S3C2410_IICSTAT)
 				& S3C2410_IICSTAT_LASTBIT))
 				return true;
@@ -277,16 +286,6 @@
 
 	stat |= S3C2410_IICSTAT_START;
 	writel(stat, i2c->regs + S3C2410_IICSTAT);
-
-	if (i2c->quirks & QUIRK_POLL) {
-		while ((i2c->msg_num != 0) && is_ack(i2c)) {
-			i2c_s3c_irq_nextbyte(i2c, stat);
-			stat = readl(i2c->regs + S3C2410_IICSTAT);
-
-			if (stat & S3C2410_IICSTAT_ARBITR)
-				dev_err(i2c->dev, "deal with arbitration loss\n");
-		}
-	}
 }
 
 static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
@@ -484,7 +483,10 @@
 					 * forces us to send a new START
 					 * when we change direction
 					 */
+					dev_dbg(i2c->dev,
+						"missing START before write->read\n");
 					s3c24xx_i2c_stop(i2c, -EINVAL);
+					break;
 				}
 
 				goto retry_write;
@@ -691,7 +693,7 @@
 static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 			      struct i2c_msg *msgs, int num)
 {
-	unsigned long timeout;
+	unsigned long timeout = 0;
 	int ret;
 
 	ret = s3c24xx_i2c_set_master(i2c);
@@ -711,16 +713,19 @@
 	s3c24xx_i2c_message_start(i2c, msgs);
 
 	if (i2c->quirks & QUIRK_POLL) {
-		ret = i2c->msg_idx;
+		while ((i2c->msg_num != 0) && is_ack(i2c)) {
+			unsigned long stat = readl(i2c->regs + S3C2410_IICSTAT);
 
-		if (ret != num)
-			dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+			i2c_s3c_irq_nextbyte(i2c, stat);
 
-		goto out;
+			stat = readl(i2c->regs + S3C2410_IICSTAT);
+			if (stat & S3C2410_IICSTAT_ARBITR)
+				dev_err(i2c->dev, "deal with arbitration loss\n");
+		}
+	} else {
+		timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
 	}
 
-	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
-
 	ret = i2c->msg_idx;
 
 	/*
@@ -1138,7 +1143,7 @@
 	 */
 	if (!(i2c->quirks & QUIRK_POLL)) {
 		i2c->irq = ret = platform_get_irq(pdev, 0);
-		if (ret <= 0) {
+		if (ret < 0) {
 			dev_err(&pdev->dev, "cannot find IRQ\n");
 			clk_unprepare(i2c->clk);
 			return ret;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-sh7760.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-sh7760.c
@@ -471,7 +471,10 @@
 		goto out2;
 	}
 
-	id->irq = platform_get_irq(pdev, 0);
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto out3;
+	id->irq = ret;
 
 	id->adap.nr = pdev->id;
 	id->adap.algo = &sh7760_i2c_algo;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-sh_mobile.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-sh_mobile.c
@@ -129,6 +129,7 @@
 	int sr;
 	bool send_stop;
 	bool stop_after_dma;
+	bool atomic_xfer;
 
 	struct resource *res;
 	struct dma_chan *dma_tx;
@@ -333,13 +334,15 @@
 		ret = iic_rd(pd, ICDR);
 		break;
 	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
-		iic_wr(pd, ICIC,
-		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		if (!pd->atomic_xfer)
+			iic_wr(pd, ICIC,
+			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
 		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
 		break;
 	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
-		iic_wr(pd, ICIC,
-		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		if (!pd->atomic_xfer)
+			iic_wr(pd, ICIC,
+			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
 		ret = iic_rd(pd, ICDR);
 		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
 		break;
@@ -435,7 +438,8 @@
 
 	if (wakeup) {
 		pd->sr |= SW_DONE;
-		wake_up(&pd->wait);
+		if (!pd->atomic_xfer)
+			wake_up(&pd->wait);
 	}
 
 	/* defeat write posting to avoid spurious WAIT interrupts */
@@ -587,6 +591,9 @@
 	pd->pos = -1;
 	pd->sr = 0;
 
+	if (pd->atomic_xfer)
+		return;
+
 	pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
 	if (pd->dma_buf)
 		sh_mobile_i2c_xfer_dma(pd);
@@ -643,15 +650,13 @@
 	return i ? 0 : -ETIMEDOUT;
 }
 
-static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
-			      struct i2c_msg *msgs,
-			      int num)
+static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
+			 struct i2c_msg *msgs, int num)
 {
-	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
 	struct i2c_msg	*msg;
 	int err = 0;
 	int i;
-	long timeout;
+	long time_left;
 
 	/* Wake up device and enable clock */
 	pm_runtime_get_sync(pd->dev);
@@ -668,15 +673,35 @@
 		if (do_start)
 			i2c_op(pd, OP_START);
 
-		/* The interrupt handler takes care of the rest... */
-		timeout = wait_event_timeout(pd->wait,
-				       pd->sr & (ICSR_TACK | SW_DONE),
-				       adapter->timeout);
+		if (pd->atomic_xfer) {
+			unsigned long j = jiffies + pd->adap.timeout;
 
-		/* 'stop_after_dma' tells if DMA transfer was complete */
-		i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
+			time_left = time_before_eq(jiffies, j);
+			while (time_left &&
+			       !(pd->sr & (ICSR_TACK | SW_DONE))) {
+				unsigned char sr = iic_rd(pd, ICSR);
+
+				if (sr & (ICSR_AL   | ICSR_TACK |
+					  ICSR_WAIT | ICSR_DTE)) {
+					sh_mobile_i2c_isr(0, pd);
+					udelay(150);
+				} else {
+					cpu_relax();
+				}
+				time_left = time_before_eq(jiffies, j);
+			}
+		} else {
+			/* The interrupt handler takes care of the rest... */
+			time_left = wait_event_timeout(pd->wait,
+					pd->sr & (ICSR_TACK | SW_DONE),
+					pd->adap.timeout);
+
+			/* 'stop_after_dma' tells if DMA xfer was complete */
+			i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
+						 pd->stop_after_dma);
+		}
 
-		if (!timeout) {
+		if (!time_left) {
 			dev_err(pd->dev, "Transfer request timed out\n");
 			if (pd->dma_direction != DMA_NONE)
 				sh_mobile_i2c_cleanup_dma(pd);
@@ -702,14 +727,35 @@
 	return err ?: num;
 }
 
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+			      struct i2c_msg *msgs,
+			      int num)
+{
+	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+
+	pd->atomic_xfer = false;
+	return sh_mobile_xfer(pd, msgs, num);
+}
+
+static int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
+				     struct i2c_msg *msgs,
+				     int num)
+{
+	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+
+	pd->atomic_xfer = true;
+	return sh_mobile_xfer(pd, msgs, num);
+}
+
 static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
 }
 
 static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
-	.functionality	= sh_mobile_i2c_func,
-	.master_xfer	= sh_mobile_i2c_xfer,
+	.functionality = sh_mobile_i2c_func,
+	.master_xfer = sh_mobile_i2c_xfer,
+	.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
 };
 
 static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
@@ -767,7 +813,7 @@
 static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
 	{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
 	{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
-	{ .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
+	{ .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config },
 	{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
 	{ .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config },
 	{ .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config },
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-sprd.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-sprd.c
@@ -72,6 +72,8 @@
 
 /* timeout (ms) for pm runtime autosuspend */
 #define SPRD_I2C_PM_TIMEOUT	1000
+/* timeout (ms) for transfer message */
+#define I2C_XFER_TIMEOUT	1000
 
 /* SPRD i2c data structure */
 struct sprd_i2c {
@@ -244,6 +246,7 @@
 			       struct i2c_msg *msg, bool is_last_msg)
 {
 	struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
+	unsigned long time_left;
 
 	i2c_dev->msg = msg;
 	i2c_dev->buf = msg->buf;
@@ -273,7 +276,10 @@
 
 	sprd_i2c_opt_start(i2c_dev);
 
-	wait_for_completion(&i2c_dev->complete);
+	time_left = wait_for_completion_timeout(&i2c_dev->complete,
+				msecs_to_jiffies(I2C_XFER_TIMEOUT));
+	if (!time_left)
+		return -ETIMEDOUT;
 
 	return i2c_dev->err;
 }
@@ -284,7 +290,7 @@
 	struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
 	int im, ret;
 
-	ret = pm_runtime_get_sync(i2c_dev->dev);
+	ret = pm_runtime_resume_and_get(i2c_dev->dev);
 	if (ret < 0)
 		return ret;
 
@@ -573,10 +579,12 @@
 
 	ret = pm_runtime_get_sync(i2c_dev->dev);
 	if (ret < 0)
-		return ret;
+		dev_err(&pdev->dev, "Failed to resume device (%pe)\n", ERR_PTR(ret));
 
 	i2c_del_adapter(&i2c_dev->adap);
-	clk_disable_unprepare(i2c_dev->clk);
+
+	if (ret >= 0)
+		clk_disable_unprepare(i2c_dev->clk);
 
 	pm_runtime_put_noidle(i2c_dev->dev);
 	pm_runtime_disable(i2c_dev->dev);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-st.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-st.c
@@ -434,6 +434,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-ein-5.4.0.orig/drivers/i2c/busses/i2c-stm32.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-stm32.c
@@ -20,13 +20,13 @@
 
 	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
 	if (!dma)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	/* Request and configure I2C TX dma channel */
-	dma->chan_tx = dma_request_slave_channel(dev, "tx");
-	if (!dma->chan_tx) {
+	dma->chan_tx = dma_request_chan(dev, "tx");
+	if (IS_ERR(dma->chan_tx)) {
 		dev_dbg(dev, "can't request DMA tx channel\n");
-		ret = -EINVAL;
+		ret = PTR_ERR(dma->chan_tx);
 		goto fail_al;
 	}
 
@@ -42,10 +42,10 @@
 	}
 
 	/* Request and configure I2C RX dma channel */
-	dma->chan_rx = dma_request_slave_channel(dev, "rx");
-	if (!dma->chan_rx) {
+	dma->chan_rx = dma_request_chan(dev, "rx");
+	if (IS_ERR(dma->chan_rx)) {
 		dev_err(dev, "can't request DMA rx channel\n");
-		ret = -EINVAL;
+		ret = PTR_ERR(dma->chan_rx);
 		goto fail_tx;
 	}
 
@@ -75,7 +75,7 @@
 	devm_kfree(dev, dma);
 	dev_info(dev, "can't use DMA\n");
 
-	return NULL;
+	return ERR_PTR(ret);
 }
 
 void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-stm32f7.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-stm32f7.c
@@ -53,6 +53,8 @@
 #define STM32F7_I2C_CR1_RXDMAEN			BIT(15)
 #define STM32F7_I2C_CR1_TXDMAEN			BIT(14)
 #define STM32F7_I2C_CR1_ANFOFF			BIT(12)
+#define STM32F7_I2C_CR1_DNF_MASK		GENMASK(11, 8)
+#define STM32F7_I2C_CR1_DNF(n)			(((n) & 0xf) << 8)
 #define STM32F7_I2C_CR1_ERRIE			BIT(7)
 #define STM32F7_I2C_CR1_TCIE			BIT(6)
 #define STM32F7_I2C_CR1_STOPIE			BIT(5)
@@ -151,7 +153,7 @@
 #define STM32F7_I2C_MAX_SLAVE			0x2
 
 #define STM32F7_I2C_DNF_DEFAULT			0
-#define STM32F7_I2C_DNF_MAX			16
+#define STM32F7_I2C_DNF_MAX			15
 
 #define STM32F7_I2C_ANALOG_FILTER_ENABLE	1
 #define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN	50	/* ns */
@@ -657,6 +659,13 @@
 	else
 		stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
 				     STM32F7_I2C_CR1_ANFOFF);
+
+	/* Program the Digital Filter */
+	stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+			     STM32F7_I2C_CR1_DNF_MASK);
+	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
+			     STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf));
+
 	stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
 			     STM32F7_I2C_CR1_PE);
 }
@@ -965,9 +974,10 @@
 	/* Configure PEC */
 	if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
 		cr1 |= STM32F7_I2C_CR1_PECEN;
-		cr2 |= STM32F7_I2C_CR2_PECBYTE;
-		if (!f7_msg->read_write)
+		if (!f7_msg->read_write) {
+			cr2 |= STM32F7_I2C_CR2_PECBYTE;
 			f7_msg->count++;
+		}
 	} else {
 		cr1 &= ~STM32F7_I2C_CR1_PECEN;
 		cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
@@ -1055,8 +1065,10 @@
 	f7_msg->stop = true;
 
 	/* Add one byte for PEC if needed */
-	if (cr1 & STM32F7_I2C_CR1_PECEN)
+	if (cr1 & STM32F7_I2C_CR1_PECEN) {
+		cr2 |= STM32F7_I2C_CR2_PECBYTE;
 		f7_msg->count++;
+	}
 
 	/* Set number of bytes to be transferred */
 	cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
@@ -1267,8 +1279,8 @@
 	 * slave[0] supports 7-bit and 10-bit slave address
 	 * slave[1] supports 7-bit slave address only
 	 */
-	for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
-		if (i == 1 && (slave->flags & I2C_CLIENT_PEC))
+	for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) {
+		if (i == 1 && (slave->flags & I2C_CLIENT_TEN))
 			continue;
 		if (!i2c_dev->slave[i]) {
 			*id = i;
@@ -1385,6 +1397,7 @@
 {
 	struct stm32f7_i2c_dev *i2c_dev = data;
 	struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+	struct stm32_i2c_dma *dma = i2c_dev->dma;
 	void __iomem *base = i2c_dev->base;
 	u32 status, mask;
 	int ret = IRQ_HANDLED;
@@ -1409,6 +1422,10 @@
 	if (status & STM32F7_I2C_ISR_NACKF) {
 		dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
 		writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
+		if (i2c_dev->use_dma) {
+			stm32f7_i2c_disable_dma_req(i2c_dev);
+			dmaengine_terminate_all(dma->chan_using);
+		}
 		f7_msg->result = -ENXIO;
 	}
 
@@ -1424,7 +1441,7 @@
 		/* Clear STOP flag */
 		writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
 
-		if (i2c_dev->use_dma) {
+		if (i2c_dev->use_dma && !f7_msg->result) {
 			ret = IRQ_WAKE_THREAD;
 		} else {
 			i2c_dev->master_mode = false;
@@ -1437,7 +1454,7 @@
 		if (f7_msg->stop) {
 			mask = STM32F7_I2C_CR2_STOP;
 			stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
-		} else if (i2c_dev->use_dma) {
+		} else if (i2c_dev->use_dma && !f7_msg->result) {
 			ret = IRQ_WAKE_THREAD;
 		} else if (f7_msg->smbus) {
 			stm32f7_i2c_smbus_rep_start(i2c_dev);
@@ -1577,12 +1594,23 @@
 	time_left = wait_for_completion_timeout(&i2c_dev->complete,
 						i2c_dev->adap.timeout);
 	ret = f7_msg->result;
+	if (ret) {
+		/*
+		 * It is possible that some unsent data have already been
+		 * written into TXDR. To avoid sending old data in a
+		 * further transfer, flush TXDR in case of any error
+		 */
+		writel_relaxed(STM32F7_I2C_ISR_TXE,
+			       i2c_dev->base + STM32F7_I2C_ISR);
+		goto pm_free;
+	}
 
 	if (!time_left) {
 		dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
 			i2c_dev->msg->addr);
 		if (i2c_dev->use_dma)
 			dmaengine_terminate_all(dma->chan_using);
+		stm32f7_i2c_wait_free_bus(i2c_dev);
 		ret = -ETIMEDOUT;
 	}
 
@@ -1625,13 +1653,22 @@
 	timeout = wait_for_completion_timeout(&i2c_dev->complete,
 					      i2c_dev->adap.timeout);
 	ret = f7_msg->result;
-	if (ret)
+	if (ret) {
+		/*
+		 * It is possible that some unsent data have already been
+		 * written into TXDR. To avoid sending old data in a
+		 * further transfer, flush TXDR in case of any error
+		 */
+		writel_relaxed(STM32F7_I2C_ISR_TXE,
+			       i2c_dev->base + STM32F7_I2C_ISR);
 		goto pm_free;
+	}
 
 	if (!timeout) {
 		dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
 		if (i2c_dev->use_dma)
 			dmaengine_terminate_all(dma->chan_using);
+		stm32f7_i2c_wait_free_bus(i2c_dev);
 		ret = -ETIMEDOUT;
 		goto pm_free;
 	}
@@ -1955,6 +1992,15 @@
 	i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
 					     STM32F7_I2C_TXDR,
 					     STM32F7_I2C_RXDR);
+	if (PTR_ERR(i2c_dev->dma) == -ENODEV)
+		i2c_dev->dma = NULL;
+	else if (IS_ERR(i2c_dev->dma)) {
+		ret = PTR_ERR(i2c_dev->dma);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Failed to request dma error %i\n", ret);
+		goto clk_free;
+	}
 
 	platform_set_drvdata(pdev, i2c_dev);
 
@@ -1985,6 +2031,11 @@
 	pm_runtime_set_suspended(i2c_dev->dev);
 	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
 
+	if (i2c_dev->dma) {
+		stm32_i2c_dma_free(i2c_dev->dma);
+		i2c_dev->dma = NULL;
+	}
+
 clk_free:
 	clk_disable_unprepare(i2c_dev->clk);
 
@@ -1995,21 +2046,21 @@
 {
 	struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
-	if (i2c_dev->dma) {
-		stm32_i2c_dma_free(i2c_dev->dma);
-		i2c_dev->dma = NULL;
-	}
-
 	i2c_del_adapter(&i2c_dev->adap);
 	pm_runtime_get_sync(i2c_dev->dev);
 
-	clk_disable_unprepare(i2c_dev->clk);
-
 	pm_runtime_put_noidle(i2c_dev->dev);
 	pm_runtime_disable(i2c_dev->dev);
 	pm_runtime_set_suspended(i2c_dev->dev);
 	pm_runtime_dont_use_autosuspend(i2c_dev->dev);
 
+	if (i2c_dev->dma) {
+		stm32_i2c_dma_free(i2c_dev->dma);
+		i2c_dev->dma = NULL;
+	}
+
+	clk_disable_unprepare(i2c_dev->clk);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-sun6i-p2wi.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-sun6i-p2wi.c
@@ -202,6 +202,11 @@
 		return -EINVAL;
 	}
 
+	if (clk_freq == 0) {
+		dev_err(dev, "clock-frequency is set to 0 in DT\n");
+		return -EINVAL;
+	}
+
 	if (of_get_child_count(np) > 1) {
 		dev_err(dev, "P2WI only supports one slave device\n");
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-tegra-bpmp.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-tegra-bpmp.c
@@ -80,7 +80,7 @@
 		flags &= ~I2C_M_RECV_LEN;
 	}
 
-	return (flags != 0) ? -EINVAL : 0;
+	return 0;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-tegra.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-tegra.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -230,7 +231,6 @@
  * @base_phys: physical base address of the I2C controller
  * @cont_id: I2C controller ID, used for packet header
  * @irq: IRQ number of transfer complete interrupt
- * @irq_disabled: used to track whether or not the interrupt is enabled
  * @is_dvc: identifies the DVC I2C controller, has a different register layout
  * @msg_complete: transfer completion notifier
  * @msg_err: error code for completed message
@@ -240,7 +240,6 @@
  * @bus_clk_rate: current I2C bus clock rate
  * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
  * @is_multimaster_mode: track if I2C controller is in multi-master mode
- * @xfer_lock: lock to serialize transfer submission and processing
  * @tx_dma_chan: DMA transmit channel
  * @rx_dma_chan: DMA receive channel
  * @dma_phys: handle to DMA resources
@@ -260,7 +259,6 @@
 	phys_addr_t base_phys;
 	int cont_id;
 	int irq;
-	bool irq_disabled;
 	int is_dvc;
 	struct completion msg_complete;
 	int msg_err;
@@ -270,8 +268,6 @@
 	u32 bus_clk_rate;
 	u16 clk_divisor_non_hs_mode;
 	bool is_multimaster_mode;
-	/* xfer_lock: lock to serialize transfer submission and processing */
-	spinlock_t xfer_lock;
 	struct dma_chan *tx_dma_chan;
 	struct dma_chan *rx_dma_chan;
 	dma_addr_t dma_phys;
@@ -790,11 +786,6 @@
 	if (err)
 		return err;
 
-	if (i2c_dev->irq_disabled) {
-		i2c_dev->irq_disabled = false;
-		enable_irq(i2c_dev->irq);
-	}
-
 	return 0;
 }
 
@@ -825,18 +816,12 @@
 
 	status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
-	spin_lock(&i2c_dev->xfer_lock);
 	if (status == 0) {
 		dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
 			 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
 			 i2c_readl(i2c_dev, I2C_STATUS),
 			 i2c_readl(i2c_dev, I2C_CNFG));
 		i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
-
-		if (!i2c_dev->irq_disabled) {
-			disable_irq_nosync(i2c_dev->irq);
-			i2c_dev->irq_disabled = true;
-		}
 		goto err;
 	}
 
@@ -925,7 +910,6 @@
 
 	complete(&i2c_dev->msg_complete);
 done:
-	spin_unlock(&i2c_dev->xfer_lock);
 	return IRQ_HANDLED;
 }
 
@@ -999,6 +983,30 @@
 	i2c_writel(i2c_dev, val, reg);
 }
 
+static unsigned long
+tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
+				  struct completion *complete,
+				  unsigned int timeout_ms)
+{
+	unsigned long ret;
+
+	enable_irq(i2c_dev->irq);
+	ret = wait_for_completion_timeout(complete,
+					  msecs_to_jiffies(timeout_ms));
+	disable_irq(i2c_dev->irq);
+
+	/*
+	 * There is a chance that completion may happen after IRQ
+	 * synchronization, which is done by disable_irq().
+	 */
+	if (ret == 0 && completion_done(complete)) {
+		dev_warn(i2c_dev->dev, "completion done after timeout\n");
+		ret = 1;
+	}
+
+	return ret;
+}
+
 static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
 {
 	struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
@@ -1020,8 +1028,8 @@
 	i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
 	tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
 
-	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
-						msecs_to_jiffies(50));
+	time_left = tegra_i2c_wait_completion_timeout(
+			i2c_dev, &i2c_dev->msg_complete, 50);
 	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "timed out for bus clear\n");
 		return -ETIMEDOUT;
@@ -1044,7 +1052,6 @@
 	u32 packet_header;
 	u32 int_mask;
 	unsigned long time_left;
-	unsigned long flags;
 	size_t xfer_size;
 	u32 *buffer = NULL;
 	int err = 0;
@@ -1075,7 +1082,6 @@
 	 */
 	xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
 					i2c_dev->bus_clk_rate);
-	spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
 
 	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
 	tegra_i2c_unmask_irq(i2c_dev, int_mask);
@@ -1090,7 +1096,7 @@
 				dev_err(i2c_dev->dev,
 					"starting RX DMA failed, err %d\n",
 					err);
-				goto unlock;
+				return err;
 			}
 
 		} else {
@@ -1149,7 +1155,7 @@
 				dev_err(i2c_dev->dev,
 					"starting TX DMA failed, err %d\n",
 					err);
-				goto unlock;
+				return err;
 			}
 		} else {
 			tegra_i2c_fill_tx_fifo(i2c_dev);
@@ -1169,15 +1175,10 @@
 	dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
 		i2c_readl(i2c_dev, I2C_INT_MASK));
 
-unlock:
-	spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
-
 	if (dma) {
-		if (err)
-			return err;
+		time_left = tegra_i2c_wait_completion_timeout(
+				i2c_dev, &i2c_dev->dma_complete, xfer_time);
 
-		time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
-							msecs_to_jiffies(xfer_time));
 		if (time_left == 0) {
 			dev_err(i2c_dev->dev, "DMA transfer timeout\n");
 			dmaengine_terminate_sync(i2c_dev->msg_read ?
@@ -1202,13 +1203,13 @@
 					      i2c_dev->tx_dma_chan);
 	}
 
-	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
-						msecs_to_jiffies(xfer_time));
+	time_left = tegra_i2c_wait_completion_timeout(
+			i2c_dev, &i2c_dev->msg_complete, xfer_time);
+
 	tegra_i2c_mask_irq(i2c_dev, int_mask);
 
 	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
-
 		tegra_i2c_init(i2c_dev, true);
 		return -ETIMEDOUT;
 	}
@@ -1568,7 +1569,6 @@
 				I2C_PACKET_HEADER_SIZE;
 	init_completion(&i2c_dev->msg_complete);
 	init_completion(&i2c_dev->dma_complete);
-	spin_lock_init(&i2c_dev->xfer_lock);
 
 	if (!i2c_dev->hw->has_single_clk_source) {
 		fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
@@ -1608,14 +1608,18 @@
 	}
 
 	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev))
+	if (!pm_runtime_enabled(&pdev->dev)) {
 		ret = tegra_i2c_runtime_resume(&pdev->dev);
-	else
+		if (ret < 0) {
+			dev_err(&pdev->dev, "runtime resume failed\n");
+			goto unprepare_div_clk;
+		}
+	} else {
 		ret = pm_runtime_get_sync(i2c_dev->dev);
-
-	if (ret < 0) {
-		dev_err(&pdev->dev, "runtime resume failed\n");
-		goto unprepare_div_clk;
+		if (ret < 0) {
+			dev_err(&pdev->dev, "runtime resume failed\n");
+			goto disable_rpm;
+		}
 	}
 
 	if (i2c_dev->is_multimaster_mode) {
@@ -1623,7 +1627,7 @@
 		if (ret < 0) {
 			dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
 				ret);
-			goto disable_rpm;
+			goto put_rpm;
 		}
 	}
 
@@ -1640,6 +1644,8 @@
 		goto release_dma;
 	}
 
+	irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
+
 	ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
 			       tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
 	if (ret) {
@@ -1671,11 +1677,16 @@
 	if (i2c_dev->is_multimaster_mode)
 		clk_disable(i2c_dev->div_clk);
 
-disable_rpm:
-	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
+put_rpm:
+	if (pm_runtime_enabled(&pdev->dev))
+		pm_runtime_put_sync(&pdev->dev);
+	else
 		tegra_i2c_runtime_suspend(&pdev->dev);
 
+disable_rpm:
+	if (pm_runtime_enabled(&pdev->dev))
+		pm_runtime_disable(&pdev->dev);
+
 unprepare_div_clk:
 	clk_unprepare(i2c_dev->div_clk);
 
@@ -1710,10 +1721,14 @@
 static int __maybe_unused tegra_i2c_suspend(struct device *dev)
 {
 	struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+	int err = 0;
 
 	i2c_mark_adapter_suspended(&i2c_dev->adapter);
 
-	return 0;
+	if (!pm_runtime_status_suspended(dev))
+		err = tegra_i2c_runtime_suspend(dev);
+
+	return err;
 }
 
 static int __maybe_unused tegra_i2c_resume(struct device *dev)
@@ -1721,6 +1736,10 @@
 	struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
 	int err;
 
+	/*
+	 * We need to ensure that clocks are enabled so that registers can be
+	 * restored in tegra_i2c_init().
+	 */
 	err = tegra_i2c_runtime_resume(dev);
 	if (err)
 		return err;
@@ -1729,9 +1748,16 @@
 	if (err)
 		return err;
 
-	err = tegra_i2c_runtime_suspend(dev);
-	if (err)
-		return err;
+	/*
+	 * In case we are runtime suspended, disable clocks again so that we
+	 * don't unbalance the clock reference counts during the next runtime
+	 * resume transition.
+	 */
+	if (pm_runtime_status_suspended(dev)) {
+		err = tegra_i2c_runtime_suspend(dev);
+		if (err)
+			return err;
+	}
 
 	i2c_mark_adapter_resumed(&i2c_dev->adapter);
 
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-thunderx-pcidrv.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -208,6 +208,7 @@
 	i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
 	i2c->adap.dev.parent = dev;
 	i2c->adap.dev.of_node = pdev->dev.of_node;
+	i2c->adap.dev.fwnode = dev->fwnode;
 	snprintf(i2c->adap.name, sizeof(i2c->adap.name),
 		 "Cavium ThunderX i2c adapter at %s", dev_name(dev));
 	i2c_set_adapdata(&i2c->adap, i2c);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -308,6 +308,9 @@
 	u32 msg[3];
 	int rc;
 
+	if (writelen > I2C_SMBUS_BLOCK_MAX)
+		return -EINVAL;
+
 	memcpy(ctx->dma_buffer, data, writelen);
 	paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen,
 			       DMA_TO_DEVICE);
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-xiic.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-xiic.c
@@ -353,6 +353,9 @@
 	struct xiic_i2c *i2c = dev_id;
 	u32 pend, isr, ier;
 	u32 clr = 0;
+	int xfer_more = 0;
+	int wakeup_req = 0;
+	int wakeup_code = 0;
 
 	/* Get the interrupt Status from the IPIF. There is no clearing of
 	 * interrupts in the IPIF. Interrupts must be cleared at the source.
@@ -389,10 +392,16 @@
 		 */
 		xiic_reinit(i2c);
 
-		if (i2c->rx_msg)
-			xiic_wakeup(i2c, STATE_ERROR);
-		if (i2c->tx_msg)
-			xiic_wakeup(i2c, STATE_ERROR);
+		if (i2c->rx_msg) {
+			wakeup_req = 1;
+			wakeup_code = STATE_ERROR;
+		}
+		if (i2c->tx_msg) {
+			wakeup_req = 1;
+			wakeup_code = STATE_ERROR;
+		}
+		/* don't try to handle other events */
+		goto out;
 	}
 	if (pend & XIIC_INTR_RX_FULL_MASK) {
 		/* Receive register/FIFO is full */
@@ -426,8 +435,7 @@
 				i2c->tx_msg++;
 				dev_dbg(i2c->adap.dev.parent,
 					"%s will start next...\n", __func__);
-
-				__xiic_start_xfer(i2c);
+				xfer_more = 1;
 			}
 		}
 	}
@@ -441,11 +449,13 @@
 		if (!i2c->tx_msg)
 			goto out;
 
-		if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
-			xiic_tx_space(i2c) == 0)
-			xiic_wakeup(i2c, STATE_DONE);
+		wakeup_req = 1;
+
+		if (i2c->nmsgs == 1 && !i2c->rx_msg &&
+		    xiic_tx_space(i2c) == 0)
+			wakeup_code = STATE_DONE;
 		else
-			xiic_wakeup(i2c, STATE_ERROR);
+			wakeup_code = STATE_ERROR;
 	}
 	if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
 		/* Transmit register/FIFO is empty or ½ empty */
@@ -469,7 +479,7 @@
 			if (i2c->nmsgs > 1) {
 				i2c->nmsgs--;
 				i2c->tx_msg++;
-				__xiic_start_xfer(i2c);
+				xfer_more = 1;
 			} else {
 				xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
 
@@ -487,6 +497,13 @@
 	dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
 
 	xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
+	if (xfer_more)
+		__xiic_start_xfer(i2c);
+	if (wakeup_req)
+		xiic_wakeup(i2c, wakeup_code);
+
+	WARN_ON(xfer_more && wakeup_req);
+
 	mutex_unlock(&i2c->lock);
 	return IRQ_HANDLED;
 }
@@ -715,7 +732,6 @@
 
 static const struct i2c_adapter xiic_adapter = {
 	.owner = THIS_MODULE,
-	.name = DRIVER_NAME,
 	.class = I2C_CLASS_DEPRECATED,
 	.algo = &xiic_algorithm,
 	.quirks = &xiic_quirks,
@@ -752,6 +768,8 @@
 	i2c_set_adapdata(&i2c->adap, i2c);
 	i2c->adap.dev.parent = &pdev->dev;
 	i2c->adap.dev.of_node = pdev->dev.of_node;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+		 DRIVER_NAME " %s", pdev->name);
 
 	mutex_init(&i2c->lock);
 	init_waitqueue_head(&i2c->wait);
@@ -883,6 +901,7 @@
 
 module_platform_driver(xiic_i2c_driver);
 
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("info@mocean-labs.com");
 MODULE_DESCRIPTION("Xilinx I2C bus driver");
 MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/i2c/busses/i2c-xlr.c
+++ linux-ein-5.4.0/drivers/i2c/busses/i2c-xlr.c
@@ -433,11 +433,15 @@
 	i2c_set_adapdata(&priv->adap, priv);
 	ret = i2c_add_numbered_adapter(&priv->adap);
 	if (ret < 0)
-		return ret;
+		goto err_unprepare_clk;
 
 	platform_set_drvdata(pdev, priv);
 	dev_info(&priv->adap.dev, "Added I2C Bus.\n");
 	return 0;
+
+err_unprepare_clk:
+	clk_unprepare(clk);
+	return ret;
 }
 
 static int xlr_i2c_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-core-acpi.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-core-acpi.c
@@ -264,6 +264,7 @@
 void i2c_acpi_register_devices(struct i2c_adapter *adap)
 {
 	acpi_status status;
+	acpi_handle handle;
 
 	if (!has_acpi_companion(&adap->dev))
 		return;
@@ -274,6 +275,15 @@
 				     adap, NULL);
 	if (ACPI_FAILURE(status))
 		dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
+
+	if (!adap->dev.parent)
+		return;
+
+	handle = ACPI_HANDLE(adap->dev.parent);
+	if (!handle)
+		return;
+
+	acpi_walk_dep_device_list(handle);
 }
 
 const struct acpi_device_id *
@@ -394,9 +404,17 @@
 static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
 {
 	struct device *dev;
+	struct i2c_client *client;
 
 	dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev);
-	return dev ? i2c_verify_client(dev) : NULL;
+	if (!dev)
+		return NULL;
+
+	client = i2c_verify_client(dev);
+	if (!client)
+		put_device(dev);
+
+	return client;
 }
 
 static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
@@ -418,6 +436,7 @@
 			break;
 
 		i2c_acpi_register_device(adapter, adev, &info);
+		put_device(&adapter->dev);
 		break;
 	case ACPI_RECONFIG_DEVICE_REMOVE:
 		if (!acpi_device_enumerated(adev))
@@ -729,7 +748,6 @@
 		return -ENOMEM;
 	}
 
-	acpi_walk_dep_device_list(handle);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-core-base.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-core-base.c
@@ -24,6 +24,7 @@
 #include <linux/i2c-smbus.h>
 #include <linux/idr.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/irqflags.h>
 #include <linux/jump_label.h>
 #include <linux/kernel.h>
@@ -186,10 +187,11 @@
 	 * If we can set SDA, we will always create a STOP to ensure additional
 	 * pulses will do no harm. This is achieved by letting SDA follow SCL
 	 * half a cycle later. Check the 'incomplete_write_byte' fault injector
-	 * for details.
+	 * for details. Note that we must honour tsu:sto, 4us, but lets use 5us
+	 * here for simplicity.
 	 */
 	bri->set_scl(adap, scl);
-	ndelay(RECOVERY_NDELAY / 2);
+	ndelay(RECOVERY_NDELAY);
 	if (bri->set_sda)
 		bri->set_sda(adap, scl);
 	ndelay(RECOVERY_NDELAY / 2);
@@ -211,7 +213,13 @@
 		scl = !scl;
 		bri->set_scl(adap, scl);
 		/* Creating STOP again, see above */
-		ndelay(RECOVERY_NDELAY / 2);
+		if (scl)  {
+			/* Honour minimum tsu:sto */
+			ndelay(RECOVERY_NDELAY);
+		} else {
+			/* Honour minimum tf and thd:dat */
+			ndelay(RECOVERY_NDELAY / 2);
+		}
 		if (bri->set_sda)
 			bri->set_sda(adap, scl);
 		ndelay(RECOVERY_NDELAY / 2);
@@ -247,13 +255,14 @@
 static void i2c_init_recovery(struct i2c_adapter *adap)
 {
 	struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
-	char *err_str;
+	char *err_str, *err_level = KERN_ERR;
 
 	if (!bri)
 		return;
 
 	if (!bri->recover_bus) {
-		err_str = "no recover_bus() found";
+		err_str = "no suitable method provided";
+		err_level = KERN_DEBUG;
 		goto err;
 	}
 
@@ -283,7 +292,7 @@
 
 	return;
  err:
-	dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
+	dev_printk(err_level, &adap->dev, "Not using recovery: %s\n", err_str);
 	adap->bus_recovery_info = NULL;
 }
 
@@ -331,8 +340,10 @@
 		} else if (ACPI_COMPANION(dev)) {
 			irq = i2c_acpi_get_irq(client);
 		}
-		if (irq == -EPROBE_DEFER)
-			return irq;
+		if (irq == -EPROBE_DEFER) {
+			status = irq;
+			goto put_sync_adapter;
+		}
 
 		if (irq < 0)
 			irq = 0;
@@ -345,16 +356,20 @@
 	 * or ACPI ID table is supplied for the probing device.
 	 */
 	if (!driver->id_table &&
-	    !i2c_acpi_match_device(dev->driver->acpi_match_table, client) &&
-	    !i2c_of_match_device(dev->driver->of_match_table, client))
-		return -ENODEV;
+	    !acpi_driver_match_device(dev, dev->driver) &&
+	    !i2c_of_match_device(dev->driver->of_match_table, client)) {
+		status = -ENODEV;
+		goto put_sync_adapter;
+	}
 
 	if (client->flags & I2C_CLIENT_WAKE) {
 		int wakeirq;
 
 		wakeirq = of_irq_get_byname(dev->of_node, "wakeup");
-		if (wakeirq == -EPROBE_DEFER)
-			return wakeirq;
+		if (wakeirq == -EPROBE_DEFER) {
+			status = wakeirq;
+			goto put_sync_adapter;
+		}
 
 		device_init_wakeup(&client->dev, true);
 
@@ -401,6 +416,10 @@
 err_clear_wakeup_irq:
 	dev_pm_clear_wake_irq(&client->dev);
 	device_init_wakeup(&client->dev, false);
+put_sync_adapter:
+	if (client->flags & I2C_CLIENT_HOST_NOTIFY)
+		pm_runtime_put_sync(&client->adapter->dev);
+
 	return status;
 }
 
@@ -441,6 +460,8 @@
 	driver = to_i2c_driver(dev->driver);
 	if (driver->shutdown)
 		driver->shutdown(client);
+	else if (client->irq > 0)
+		disable_irq(client->irq);
 }
 
 static void i2c_client_dev_release(struct device *dev)
@@ -1368,8 +1389,8 @@
 
 	/* create pre-declared device nodes */
 	of_i2c_register_devices(adap);
-	i2c_acpi_register_devices(adap);
 	i2c_acpi_install_space_handler(adap);
+	i2c_acpi_register_devices(adap);
 
 	if (adap->nr < __i2c_first_dynamic_bus_num)
 		i2c_scan_static_board_info(adap);
@@ -2337,8 +2358,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);
 
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-core-slave.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-core-slave.c
@@ -18,10 +18,8 @@
 {
 	int ret;
 
-	if (!client || !slave_cb) {
-		WARN(1, "insufficient data\n");
+	if (WARN(IS_ERR_OR_NULL(client) || !slave_cb, "insufficient data\n"))
 		return -EINVAL;
-	}
 
 	if (!(client->flags & I2C_CLIENT_SLAVE))
 		dev_warn(&client->dev, "%s: client slave flag not set. You might see address collisions\n",
@@ -60,6 +58,9 @@
 {
 	int ret;
 
+	if (IS_ERR_OR_NULL(client))
+		return -EINVAL;
+
 	if (!client->adapter->algo->unreg_slave) {
 		dev_err(&client->dev, "%s: not supported by adapter\n", __func__);
 		return -EOPNOTSUPP;
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-core-smbus.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-core-smbus.c
@@ -495,6 +495,13 @@
 			break;
 		case I2C_SMBUS_BLOCK_DATA:
 		case I2C_SMBUS_BLOCK_PROC_CALL:
+			if (msg[1].buf[0] > I2C_SMBUS_BLOCK_MAX) {
+				dev_err(&adapter->dev,
+					"Invalid block size returned: %d\n",
+					msg[1].buf[0]);
+				status = -EPROTO;
+				goto cleanup;
+			}
 			for (i = 0; i < msg[1].buf[0] + 1; i++)
 				data->block[i] = msg[1].buf[i];
 			break;
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-core.h
+++ linux-ein-5.4.0/drivers/i2c/i2c-core.h
@@ -3,6 +3,7 @@
  * i2c-core.h - interfaces internal to the I2C framework
  */
 
+#include <linux/kconfig.h>
 #include <linux/rwsem.h>
 
 struct i2c_devinfo {
@@ -29,7 +30,8 @@
  */
 static inline bool i2c_in_atomic_xfer_mode(void)
 {
-	return system_state > SYSTEM_RUNNING && irqs_disabled();
+	return system_state > SYSTEM_RUNNING &&
+	       (IS_ENABLED(CONFIG_PREEMPT_COUNT) ? !preemptible() : irqs_disabled());
 }
 
 static inline int __i2c_lock_bus_helper(struct i2c_adapter *adap)
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-dev.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-dev.c
@@ -40,7 +40,7 @@
 struct i2c_dev {
 	struct list_head list;
 	struct i2c_adapter *adap;
-	struct device *dev;
+	struct device dev;
 	struct cdev cdev;
 };
 
@@ -84,12 +84,14 @@
 	return i2c_dev;
 }
 
-static void put_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,
@@ -139,7 +141,7 @@
 	if (count > 8192)
 		count = 8192;
 
-	tmp = kmalloc(count, GFP_KERNEL);
+	tmp = kzalloc(count, GFP_KERNEL);
 	if (tmp == NULL)
 		return -ENOMEM;
 
@@ -148,7 +150,8 @@
 
 	ret = i2c_master_recv(client, tmp, count);
 	if (ret >= 0)
-		ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
+		if (copy_to_user(buf, tmp, ret))
+			ret = -EFAULT;
 	kfree(tmp);
 	return ret;
 }
@@ -438,8 +441,13 @@
 				   sizeof(rdwr_arg)))
 			return -EFAULT;
 
-		/* Put an arbitrary limit on the number of messages that can
-		 * be sent at once */
+		if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
+			return -EINVAL;
+
+		/*
+		 * Put an arbitrary limit on the number of messages that can
+		 * be sent at once
+		 */
 		if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
 			return -EINVAL;
 
@@ -528,6 +536,9 @@
 				   sizeof(rdwr_arg)))
 			return -EFAULT;
 
+		if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
+			return -EINVAL;
+
 		if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
 			return -EINVAL;
 
@@ -628,6 +639,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;
@@ -644,27 +663,23 @@
 
 	cdev_init(&i2c_dev->cdev, &i2cdev_fops);
 	i2c_dev->cdev.owner = THIS_MODULE;
-	res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);
-	if (res)
-		goto error_cdev;
-
-	/* 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;
+
+	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:
-	cdev_del(&i2c_dev->cdev);
-error_cdev:
-	put_i2c_dev(i2c_dev);
-	return res;
 }
 
 static int i2cdev_detach_adapter(struct device *dev, void *dummy)
@@ -680,9 +695,7 @@
 	if (!i2c_dev) /* attach_adapter must have failed */
 		return 0;
 
-	cdev_del(&i2c_dev->cdev);
-	put_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;
--- linux-ein-5.4.0.orig/drivers/i2c/i2c-mux.c
+++ linux-ein-5.4.0/drivers/i2c/i2c-mux.c
@@ -340,7 +340,7 @@
 		priv->adap.lock_ops = &i2c_parent_lock_ops;
 
 	/* Sanity check on class */
-	if (i2c_mux_parent_classes(parent) & class)
+	if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED)
 		dev_err(&parent->dev,
 			"Segment %d behind mux can't share classes with ancestors\n",
 			chan_id);
--- linux-ein-5.4.0.orig/drivers/i2c/muxes/i2c-demux-pinctrl.c
+++ linux-ein-5.4.0/drivers/i2c/muxes/i2c-demux-pinctrl.c
@@ -61,7 +61,7 @@
 	if (ret)
 		goto err;
 
-	adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
+	adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
 	if (!adap) {
 		ret = -ENODEV;
 		goto err_with_revert;
@@ -243,6 +243,10 @@
 
 		props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL);
 		props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL);
+		if (!props[i].name || !props[i].value) {
+			err = -ENOMEM;
+			goto err_rollback;
+		}
 		props[i].length = 3;
 
 		of_changeset_init(&priv->chan[i].chgset);
@@ -261,7 +265,7 @@
 
 	err = device_create_file(&pdev->dev, &dev_attr_available_masters);
 	if (err)
-		goto err_rollback;
+		goto err_rollback_activation;
 
 	err = device_create_file(&pdev->dev, &dev_attr_current_master);
 	if (err)
@@ -271,6 +275,8 @@
 
 err_rollback_available:
 	device_remove_file(&pdev->dev, &dev_attr_available_masters);
+err_rollback_activation:
+	i2c_demux_deactivate_master(priv);
 err_rollback:
 	for (j = 0; j < i; j++) {
 		of_node_put(priv->chan[j].parent_np);
--- linux-ein-5.4.0.orig/drivers/i2c/muxes/i2c-mux-gpmux.c
+++ linux-ein-5.4.0/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -52,7 +52,7 @@
 		dev_err(dev, "Cannot parse i2c-parent\n");
 		return ERR_PTR(-ENODEV);
 	}
-	parent = of_find_i2c_adapter_by_node(parent_np);
+	parent = of_get_i2c_adapter_by_node(parent_np);
 	of_node_put(parent_np);
 	if (!parent)
 		return ERR_PTR(-EPROBE_DEFER);
@@ -138,6 +138,7 @@
 	return 0;
 
 err_children:
+	of_node_put(child);
 	i2c_mux_del_adapters(muxc);
 err_parent:
 	i2c_put_adapter(parent);
--- linux-ein-5.4.0.orig/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ linux-ein-5.4.0/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -62,7 +62,7 @@
 		dev_err(dev, "Cannot parse i2c-parent\n");
 		return ERR_PTR(-ENODEV);
 	}
-	parent = of_find_i2c_adapter_by_node(parent_np);
+	parent = of_get_i2c_adapter_by_node(parent_np);
 	of_node_put(parent_np);
 	if (!parent)
 		return ERR_PTR(-EPROBE_DEFER);
--- linux-ein-5.4.0.orig/drivers/i3c/master.c
+++ linux-ein-5.4.0/drivers/i3c/master.c
@@ -1469,9 +1469,11 @@
 			desc->dev->dev.of_node = desc->boardinfo->of_node;
 
 		ret = device_register(&desc->dev->dev);
-		if (ret)
+		if (ret) {
 			dev_err(&master->dev,
 				"Failed to add I3C device (err = %d)\n", ret);
+			put_device(&desc->dev->dev);
+		}
 	}
 }
 
@@ -1760,6 +1762,21 @@
 	i3c_master_detach_free_devs(master);
 }
 
+static void i3c_master_attach_boardinfo(struct i3c_dev_desc *i3cdev)
+{
+	struct i3c_master_controller *master = i3cdev->common.master;
+	struct i3c_dev_boardinfo *i3cboardinfo;
+
+	list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) {
+		if (i3cdev->info.pid != i3cboardinfo->pid)
+			continue;
+
+		i3cdev->boardinfo = i3cboardinfo;
+		i3cdev->info.static_addr = i3cboardinfo->static_addr;
+		return;
+	}
+}
+
 static struct i3c_dev_desc *
 i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev)
 {
@@ -1815,10 +1832,10 @@
 	if (ret)
 		goto err_detach_dev;
 
+	i3c_master_attach_boardinfo(newdev);
+
 	olddev = i3c_master_search_i3c_dev_duplicate(newdev);
 	if (olddev) {
-		newdev->boardinfo = olddev->boardinfo;
-		newdev->info.static_addr = olddev->info.static_addr;
 		newdev->dev = olddev->dev;
 		if (newdev->dev)
 			newdev->dev->desc = newdev;
--- linux-ein-5.4.0.orig/drivers/i3c/master/i3c-master-cdns.c
+++ linux-ein-5.4.0/drivers/i3c/master/i3c-master-cdns.c
@@ -74,7 +74,8 @@
 #define PRESCL_CTRL0			0x14
 #define PRESCL_CTRL0_I2C(x)		((x) << 16)
 #define PRESCL_CTRL0_I3C(x)		(x)
-#define PRESCL_CTRL0_MAX		GENMASK(9, 0)
+#define PRESCL_CTRL0_I3C_MAX		GENMASK(9, 0)
+#define PRESCL_CTRL0_I2C_MAX		GENMASK(15, 0)
 
 #define PRESCL_CTRL1			0x18
 #define PRESCL_CTRL1_PP_LOW_MASK	GENMASK(15, 8)
@@ -189,7 +190,7 @@
 #define SLV_STATUS1_HJ_DIS		BIT(18)
 #define SLV_STATUS1_MR_DIS		BIT(17)
 #define SLV_STATUS1_PROT_ERR		BIT(16)
-#define SLV_STATUS1_DA(x)		(((s) & GENMASK(15, 9)) >> 9)
+#define SLV_STATUS1_DA(s)		(((s) & GENMASK(15, 9)) >> 9)
 #define SLV_STATUS1_HAS_DA		BIT(8)
 #define SLV_STATUS1_DDR_RX_FULL		BIT(7)
 #define SLV_STATUS1_DDR_TX_FULL		BIT(6)
@@ -1212,7 +1213,7 @@
 		return -EINVAL;
 
 	pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
-	if (pres > PRESCL_CTRL0_MAX)
+	if (pres > PRESCL_CTRL0_I3C_MAX)
 		return -ERANGE;
 
 	bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
@@ -1225,7 +1226,7 @@
 	max_i2cfreq = bus->scl_rate.i2c;
 
 	pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
-	if (pres > PRESCL_CTRL0_MAX)
+	if (pres > PRESCL_CTRL0_I2C_MAX)
 		return -ERANGE;
 
 	bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
@@ -1580,21 +1581,23 @@
 	/* Device ID0 is reserved to describe this master. */
 	master->maxdevs = CONF_STATUS0_DEVS_NUM(val);
 	master->free_rr_slots = GENMASK(master->maxdevs, 1);
+	master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val);
+	master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val);
 
 	val = readl(master->regs + CONF_STATUS1);
 	master->caps.cmdfifodepth = CONF_STATUS1_CMD_DEPTH(val);
 	master->caps.rxfifodepth = CONF_STATUS1_RX_DEPTH(val);
 	master->caps.txfifodepth = CONF_STATUS1_TX_DEPTH(val);
-	master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val);
-	master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val);
 
 	spin_lock_init(&master->ibi.lock);
 	master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val);
 	master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
 					 sizeof(*master->ibi.slots),
 					 GFP_KERNEL);
-	if (!master->ibi.slots)
+	if (!master->ibi.slots) {
+		ret = -ENOMEM;
 		goto err_disable_sysclk;
+	}
 
 	writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
 	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
--- linux-ein-5.4.0.orig/drivers/ide/cmd64x.c
+++ linux-ein-5.4.0/drivers/ide/cmd64x.c
@@ -66,6 +66,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-ein-5.4.0.orig/drivers/ide/ide-acpi.c
+++ linux-ein-5.4.0/drivers/ide/ide-acpi.c
@@ -180,7 +180,7 @@
 static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
 {
 	struct device		*dev = hwif->gendev.parent;
-	acpi_handle		uninitialized_var(dev_handle);
+	acpi_handle		dev_handle;
 	u64			pcidevfn;
 	acpi_handle		chan_handle;
 	int			err;
--- linux-ein-5.4.0.orig/drivers/ide/ide-atapi.c
+++ linux-ein-5.4.0/drivers/ide/ide-atapi.c
@@ -223,7 +223,6 @@
 	sense_rq->rq_disk = rq->rq_disk;
 	sense_rq->cmd_flags = REQ_OP_DRV_IN;
 	ide_req(sense_rq)->type = ATA_PRIV_SENSE;
-	sense_rq->rq_flags |= RQF_PREEMPT;
 
 	req->cmd[0] = GPCMD_REQUEST_SENSE;
 	req->cmd[4] = cmd_len;
@@ -609,7 +608,7 @@
 
 static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
 {
-	struct ide_atapi_pc *uninitialized_var(pc);
+	struct ide_atapi_pc *pc;
 	ide_hwif_t *hwif = drive->hwif;
 	struct request *rq = hwif->rq;
 	ide_expiry_t *expiry;
--- linux-ein-5.4.0.orig/drivers/ide/ide-io-std.c
+++ linux-ein-5.4.0/drivers/ide/ide-io-std.c
@@ -173,7 +173,7 @@
 	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
 	if (io_32bit) {
-		unsigned long uninitialized_var(flags);
+		unsigned long flags;
 
 		if ((io_32bit & 2) && !mmio) {
 			local_irq_save(flags);
@@ -217,7 +217,7 @@
 	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
 
 	if (io_32bit) {
-		unsigned long uninitialized_var(flags);
+		unsigned long flags;
 
 		if ((io_32bit & 2) && !mmio) {
 			local_irq_save(flags);
--- linux-ein-5.4.0.orig/drivers/ide/ide-io.c
+++ linux-ein-5.4.0/drivers/ide/ide-io.c
@@ -512,11 +512,6 @@
 		 * above to return us whatever is in the queue. Since we call
 		 * ide_do_request() ourselves, we end up taking requests while
 		 * the queue is blocked...
-		 * 
-		 * We let requests forced at head of queue with ide-preempt
-		 * though. I hope that doesn't happen too much, hopefully not
-		 * unless the subdriver triggers such a thing in its own PM
-		 * state machine.
 		 */
 		if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
 		    ata_pm_request(rq) == 0 &&
@@ -619,12 +614,12 @@
 void ide_timer_expiry (struct timer_list *t)
 {
 	ide_hwif_t	*hwif = from_timer(hwif, t, timer);
-	ide_drive_t	*uninitialized_var(drive);
+	ide_drive_t	*drive;
 	ide_handler_t	*handler;
 	unsigned long	flags;
 	int		wait = -1;
 	int		plug_device = 0;
-	struct request	*uninitialized_var(rq_in_flight);
+	struct request	*rq_in_flight;
 
 	spin_lock_irqsave(&hwif->lock, flags);
 
@@ -777,13 +772,13 @@
 {
 	ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
 	struct ide_host *host = hwif->host;
-	ide_drive_t *uninitialized_var(drive);
+	ide_drive_t *drive;
 	ide_handler_t *handler;
 	unsigned long flags;
 	ide_startstop_t startstop;
 	irqreturn_t irq_ret = IRQ_NONE;
 	int plug_device = 0;
-	struct request *uninitialized_var(rq_in_flight);
+	struct request *rq_in_flight;
 
 	if (host->host_flags & IDE_HFLAG_SERIALIZE) {
 		if (hwif != host->cur_port)
--- linux-ein-5.4.0.orig/drivers/ide/ide-sysfs.c
+++ linux-ein-5.4.0/drivers/ide/ide-sysfs.c
@@ -131,7 +131,7 @@
 
 int ide_sysfs_register_port(ide_hwif_t *hwif)
 {
-	int i, uninitialized_var(rc);
+	int i, rc;
 
 	for (i = 0; ide_port_attrs[i]; i++) {
 		rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
--- linux-ein-5.4.0.orig/drivers/ide/serverworks.c
+++ linux-ein-5.4.0/drivers/ide/serverworks.c
@@ -115,6 +115,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)) {
@@ -141,6 +144,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-ein-5.4.0.orig/drivers/ide/umc8672.c
+++ linux-ein-5.4.0/drivers/ide/umc8672.c
@@ -108,7 +108,7 @@
 static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	ide_hwif_t *mate = hwif->mate;
-	unsigned long uninitialized_var(flags);
+	unsigned long flags;
 	const u8 pio = drive->pio_mode - XFER_PIO_0;
 
 	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
--- linux-ein-5.4.0.orig/drivers/idle/intel_idle.c
+++ linux-ein-5.4.0/drivers/idle/intel_idle.c
@@ -46,11 +46,13 @@
 #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/moduleparam.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
+#include <asm/nospec-branch.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
@@ -98,6 +100,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.
@@ -107,6 +115,24 @@
 #define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
 #define MWAIT2flg(eax) ((eax & 0xFF) << 24)
 
+static __cpuidle 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;
+}
+
 /*
  * States are indexed by the cstate number,
  * which is also the index into the MWAIT hint array.
@@ -605,7 +631,7 @@
 	{
 		.name = "C6",
 		.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,
@@ -613,7 +639,7 @@
 	{
 		.name = "C7s",
 		.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,
@@ -621,7 +647,7 @@
 	{
 		.name = "C8",
 		.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,
@@ -629,7 +655,7 @@
 	{
 		.name = "C9",
 		.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,
@@ -637,7 +663,7 @@
 	{
 		.name = "C10",
 		.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,
@@ -666,7 +692,7 @@
 	{
 		.name = "C6",
 		.desc = "MWAIT 0x20",
-		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
 		.exit_latency = 133,
 		.target_residency = 600,
 		.enter = &intel_idle,
@@ -1370,6 +1396,11 @@
 		drv->states[drv->state_count] =	/* structure copy */
 			cpuidle_state_table[cstate];
 
+		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->state_count += 1;
 	}
 
--- linux-ein-5.4.0.orig/drivers/iio/Kconfig
+++ linux-ein-5.4.0/drivers/iio/Kconfig
@@ -70,6 +70,7 @@
 
 source "drivers/iio/accel/Kconfig"
 source "drivers/iio/adc/Kconfig"
+source "drivers/iio/addac/Kconfig"
 source "drivers/iio/afe/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/chemical/Kconfig"
--- linux-ein-5.4.0.orig/drivers/iio/Makefile
+++ linux-ein-5.4.0/drivers/iio/Makefile
@@ -15,6 +15,7 @@
 
 obj-y += accel/
 obj-y += adc/
+obj-y += addac/
 obj-y += afe/
 obj-y += amplifiers/
 obj-y += buffer/
--- linux-ein-5.4.0.orig/drivers/iio/accel/adis16201.c
+++ linux-ein-5.4.0/drivers/iio/accel/adis16201.c
@@ -215,7 +215,7 @@
 	ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),
 	ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X,
 			BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
-	ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y,
+	ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y,
 			BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
 	IIO_CHAN_SOFT_TIMESTAMP(7)
 };
--- linux-ein-5.4.0.orig/drivers/iio/accel/adxl372.c
+++ linux-ein-5.4.0/drivers/iio/accel/adxl372.c
@@ -237,6 +237,7 @@
 		.realbits = 12,						\
 		.storagebits = 16,					\
 		.shift = 4,						\
+		.endianness = IIO_BE,					\
 	},								\
 }
 
--- linux-ein-5.4.0.orig/drivers/iio/accel/bma180.c
+++ linux-ein-5.4.0/drivers/iio/accel/bma180.c
@@ -47,7 +47,7 @@
 
 	u8 int_reset_reg, int_reset_mask;
 	u8 sleep_reg, sleep_mask;
-	u8 bw_reg, bw_mask;
+	u8 bw_reg, bw_mask, bw_offset;
 	u8 scale_reg, scale_mask;
 	u8 power_reg, power_mask, lowpower_val;
 	u8 int_enable_reg, int_enable_mask;
@@ -103,6 +103,7 @@
 
 #define BMA250_RANGE_MASK	GENMASK(3, 0) /* Range of accel values */
 #define BMA250_BW_MASK		GENMASK(4, 0) /* Accel bandwidth */
+#define BMA250_BW_OFFSET	8
 #define BMA250_SUSPEND_MASK	BIT(7) /* chip will sleep */
 #define BMA250_LOWPOWER_MASK	BIT(6)
 #define BMA250_DATA_INTEN_MASK	BIT(4)
@@ -119,7 +120,11 @@
 	int scale;
 	int bw;
 	bool pmode;
-	u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s16 chan[4];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 enum bma180_chan {
@@ -237,7 +242,8 @@
 	for (i = 0; i < data->part_info->num_bw; ++i) {
 		if (data->part_info->bw_table[i] == val) {
 			ret = bma180_set_bits(data, data->part_info->bw_reg,
-				data->part_info->bw_mask, i);
+				data->part_info->bw_mask,
+				i + data->part_info->bw_offset);
 			if (ret) {
 				dev_err(&data->client->dev,
 					"failed to set bandwidth\n");
@@ -629,32 +635,53 @@
 
 static const struct bma180_part_info bma180_part_info[] = {
 	[BMA180] = {
-		bma180_channels, ARRAY_SIZE(bma180_channels),
-		bma180_scale_table, ARRAY_SIZE(bma180_scale_table),
-		bma180_bw_table, ARRAY_SIZE(bma180_bw_table),
-		BMA180_CTRL_REG0, BMA180_RESET_INT,
-		BMA180_CTRL_REG0, BMA180_SLEEP,
-		BMA180_BW_TCS, BMA180_BW,
-		BMA180_OFFSET_LSB1, BMA180_RANGE,
-		BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER,
-		BMA180_CTRL_REG3, BMA180_NEW_DATA_INT,
-		BMA180_RESET,
-		bma180_chip_config,
-		bma180_chip_disable,
+		.channels = bma180_channels,
+		.num_channels = ARRAY_SIZE(bma180_channels),
+		.scale_table = bma180_scale_table,
+		.num_scales = ARRAY_SIZE(bma180_scale_table),
+		.bw_table = bma180_bw_table,
+		.num_bw = ARRAY_SIZE(bma180_bw_table),
+		.int_reset_reg = BMA180_CTRL_REG0,
+		.int_reset_mask = BMA180_RESET_INT,
+		.sleep_reg = BMA180_CTRL_REG0,
+		.sleep_mask = BMA180_SLEEP,
+		.bw_reg = BMA180_BW_TCS,
+		.bw_mask = BMA180_BW,
+		.scale_reg = BMA180_OFFSET_LSB1,
+		.scale_mask = BMA180_RANGE,
+		.power_reg = BMA180_TCO_Z,
+		.power_mask = BMA180_MODE_CONFIG,
+		.lowpower_val = BMA180_LOW_POWER,
+		.int_enable_reg = BMA180_CTRL_REG3,
+		.int_enable_mask = BMA180_NEW_DATA_INT,
+		.softreset_reg = BMA180_RESET,
+		.chip_config = bma180_chip_config,
+		.chip_disable = bma180_chip_disable,
 	},
 	[BMA250] = {
-		bma250_channels, ARRAY_SIZE(bma250_channels),
-		bma250_scale_table, ARRAY_SIZE(bma250_scale_table),
-		bma250_bw_table, ARRAY_SIZE(bma250_bw_table),
-		BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK,
-		BMA250_POWER_REG, BMA250_SUSPEND_MASK,
-		BMA250_BW_REG, BMA250_BW_MASK,
-		BMA250_RANGE_REG, BMA250_RANGE_MASK,
-		BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
-		BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
-		BMA250_RESET_REG,
-		bma250_chip_config,
-		bma250_chip_disable,
+		.channels = bma250_channels,
+		.num_channels = ARRAY_SIZE(bma250_channels),
+		.scale_table = bma250_scale_table,
+		.num_scales = ARRAY_SIZE(bma250_scale_table),
+		.bw_table = bma250_bw_table,
+		.num_bw = ARRAY_SIZE(bma250_bw_table),
+		.int_reset_reg = BMA250_INT_RESET_REG,
+		.int_reset_mask = BMA250_INT_RESET_MASK,
+		.sleep_reg = BMA250_POWER_REG,
+		.sleep_mask = BMA250_SUSPEND_MASK,
+		.bw_reg = BMA250_BW_REG,
+		.bw_mask = BMA250_BW_MASK,
+		.bw_offset = BMA250_BW_OFFSET,
+		.scale_reg = BMA250_RANGE_REG,
+		.scale_mask = BMA250_RANGE_MASK,
+		.power_reg = BMA250_POWER_REG,
+		.power_mask = BMA250_LOWPOWER_MASK,
+		.lowpower_val = 1,
+		.int_enable_reg = BMA250_INT_ENABLE_REG,
+		.int_enable_mask = BMA250_DATA_INTEN_MASK,
+		.softreset_reg = BMA250_RESET_REG,
+		.chip_config = bma250_chip_config,
+		.chip_disable = bma250_chip_disable,
 	},
 };
 
@@ -675,12 +702,12 @@
 			mutex_unlock(&data->mutex);
 			goto err;
 		}
-		((s16 *)data->buff)[i++] = ret;
+		data->scan.chan[i++] = ret;
 	}
 
 	mutex_unlock(&data->mutex);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -766,11 +793,12 @@
 		data->trig->dev.parent = &client->dev;
 		data->trig->ops = &bma180_trigger_ops;
 		iio_trigger_set_drvdata(data->trig, indio_dev);
-		indio_dev->trig = iio_trigger_get(data->trig);
 
 		ret = iio_trigger_register(data->trig);
 		if (ret)
 			goto err_trigger_free;
+
+		indio_dev->trig = iio_trigger_get(data->trig);
 	}
 
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
--- linux-ein-5.4.0.orig/drivers/iio/accel/bma220_spi.c
+++ linux-ein-5.4.0/drivers/iio/accel/bma220_spi.c
@@ -73,7 +73,11 @@
 struct bma220_data {
 	struct spi_device *spi_device;
 	struct mutex lock;
-	s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
+	struct {
+		s8 chans[3];
+		/* Ensure timestamp is naturally aligned. */
+		s64 timestamp __aligned(8);
+	} scan;
 	u8 tx_buf[2] ____cacheline_aligned;
 };
 
@@ -104,12 +108,12 @@
 
 	mutex_lock(&data->lock);
 	data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
-	ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
+	ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans,
 				  ARRAY_SIZE(bma220_channels) - 1);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 err:
 	mutex_unlock(&data->lock);
--- linux-ein-5.4.0.orig/drivers/iio/accel/bmc150-accel-core.c
+++ linux-ein-5.4.0/drivers/iio/accel/bmc150-accel-core.c
@@ -189,6 +189,14 @@
 	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;
@@ -922,15 +930,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;
 	}
@@ -1640,11 +1649,14 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(dev, "Unable to register iio device\n");
-		goto err_trigger_unregister;
+		goto err_pm_cleanup;
 	}
 
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(dev);
+	pm_runtime_disable(dev);
 err_trigger_unregister:
 	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 err_buffer_cleanup:
--- linux-ein-5.4.0.orig/drivers/iio/accel/hid-sensor-accel-3d.c
+++ linux-ein-5.4.0/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -29,8 +29,11 @@
 	struct hid_sensor_hub_callbacks callbacks;
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
-	/* Reserve for 3 channels + padding + timestamp */
-	u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u32 accel_val[3];
+		s64 timestamp __aligned(8);
+	} scan;
 	int scale_pre_decml;
 	int scale_post_decml;
 	int scale_precision;
@@ -241,8 +244,8 @@
 			accel_state->timestamp = iio_get_time_ns(indio_dev);
 
 		hid_sensor_push_data(indio_dev,
-				     accel_state->accel_val,
-				     sizeof(accel_state->accel_val),
+				     &accel_state->scan,
+				     sizeof(accel_state->scan),
 				     accel_state->timestamp);
 
 		accel_state->timestamp = 0;
@@ -267,7 +270,7 @@
 	case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
 	case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
 		offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
-		accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
+		accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] =
 						*(u32 *)raw_data;
 		ret = 0;
 	break;
@@ -276,6 +279,7 @@
 			hid_sensor_convert_timestamp(
 					&accel_state->common_attributes,
 					*(int64_t *)raw_data);
+		ret = 0;
 	break;
 	default:
 		break;
--- linux-ein-5.4.0.orig/drivers/iio/accel/kxcjk-1013.c
+++ linux-ein-5.4.0/drivers/iio/accel/kxcjk-1013.c
@@ -126,12 +126,29 @@
 	KX_MAX_CHIPS /* this must be last */
 };
 
+enum kx_acpi_type {
+	ACPI_GENERIC,
+	ACPI_SMO8500,
+	ACPI_KIOX010A,
+};
+
+enum kxcjk1013_axis {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+	AXIS_MAX
+};
+
 struct kxcjk1013_data {
 	struct i2c_client *client;
 	struct iio_trigger *dready_trig;
 	struct iio_trigger *motion_trig;
 	struct mutex mutex;
-	s16 buffer[8];
+	/* Ensure timestamp naturally aligned */
+	struct {
+		s16 chans[AXIS_MAX];
+		s64 timestamp __aligned(8);
+	} scan;
 	u8 odr_bits;
 	u8 range;
 	int wake_thres;
@@ -142,14 +159,7 @@
 	bool motion_trigger_on;
 	int64_t timestamp;
 	enum kx_chipset chipset;
-	bool is_smo8500_device;
-};
-
-enum kxcjk1013_axis {
-	AXIS_X,
-	AXIS_Y,
-	AXIS_Z,
-	AXIS_MAX,
+	enum kx_acpi_type acpi_type;
 };
 
 enum kxcjk1013_mode {
@@ -269,6 +279,32 @@
 			      {19163, 1, 0},
 			      {38326, 0, 1} };
 
+#ifdef CONFIG_ACPI
+enum kiox010a_fn_index {
+	KIOX010A_SET_LAPTOP_MODE = 1,
+	KIOX010A_SET_TABLET_MODE = 2,
+};
+
+static int kiox010a_dsm(struct device *dev, int fn_index)
+{
+	acpi_handle handle = ACPI_HANDLE(dev);
+	guid_t kiox010a_dsm_guid;
+	union acpi_object *obj;
+
+	if (!handle)
+		return -ENODEV;
+
+	guid_parse("1f339696-d475-4e26-8cad-2e9f8e6d7a91", &kiox010a_dsm_guid);
+
+	obj = acpi_evaluate_dsm(handle, &kiox010a_dsm_guid, 1, fn_index, NULL);
+	if (!obj)
+		return -EIO;
+
+	ACPI_FREE(obj);
+	return 0;
+}
+#endif
+
 static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
 			      enum kxcjk1013_mode mode)
 {
@@ -346,6 +382,13 @@
 {
 	int ret;
 
+#ifdef CONFIG_ACPI
+	if (data->acpi_type == ACPI_KIOX010A) {
+		/* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */
+		kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE);
+	}
+#endif
+
 	ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_WHO_AM_I);
 	if (ret < 0) {
 		dev_err(&data->client->dev, "Error reading who_am_i\n");
@@ -1039,12 +1082,12 @@
 	ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
 							KXCJK1013_REG_XOUT_L,
 							AXIS_MAX * 2,
-							(u8 *)data->buffer);
+							(u8 *)data->scan.chans);
 	mutex_unlock(&data->mutex);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   data->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -1233,7 +1276,7 @@
 
 static const char *kxcjk1013_match_acpi_device(struct device *dev,
 					       enum kx_chipset *chipset,
-					       bool *is_smo8500_device)
+					       enum kx_acpi_type *acpi_type)
 {
 	const struct acpi_device_id *id;
 
@@ -1242,7 +1285,9 @@
 		return NULL;
 
 	if (strcmp(id->id, "SMO8500") == 0)
-		*is_smo8500_device = true;
+		*acpi_type = ACPI_SMO8500;
+	else if (strcmp(id->id, "KIOX010A") == 0)
+		*acpi_type = ACPI_KIOX010A;
 
 	*chipset = (enum kx_chipset)id->driver_data;
 
@@ -1278,7 +1323,7 @@
 	} else if (ACPI_HANDLE(&client->dev)) {
 		name = kxcjk1013_match_acpi_device(&client->dev,
 						   &data->chipset,
-						   &data->is_smo8500_device);
+						   &data->acpi_type);
 	} else
 		return -ENODEV;
 
@@ -1296,7 +1341,7 @@
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &kxcjk1013_info;
 
-	if (client->irq > 0 && !data->is_smo8500_device) {
+	if (client->irq > 0 && data->acpi_type != ACPI_SMO8500) {
 		ret = devm_request_threaded_irq(&client->dev, client->irq,
 						kxcjk1013_data_rdy_trig_poll,
 						kxcjk1013_event_handler,
@@ -1364,14 +1409,16 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "unable to register iio device\n");
-		goto err_buffer_cleanup;
+		goto err_pm_cleanup;
 	}
 
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(&client->dev);
+	pm_runtime_disable(&client->dev);
 err_buffer_cleanup:
-	if (data->dready_trig)
-		iio_triggered_buffer_cleanup(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
 	if (data->dready_trig)
 		iio_trigger_unregister(data->dready_trig);
@@ -1394,8 +1441,8 @@
 	pm_runtime_set_suspended(&client->dev);
 	pm_runtime_put_noidle(&client->dev);
 
+	iio_triggered_buffer_cleanup(indio_dev);
 	if (data->dready_trig) {
-		iio_triggered_buffer_cleanup(indio_dev);
 		iio_trigger_unregister(data->dready_trig);
 		iio_trigger_unregister(data->motion_trig);
 	}
--- linux-ein-5.4.0.orig/drivers/iio/accel/kxsd9.c
+++ linux-ein-5.4.0/drivers/iio/accel/kxsd9.c
@@ -209,23 +209,29 @@
 	const struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct kxsd9_state *st = iio_priv(indio_dev);
+	/*
+	 * Ensure correct positioning and alignment of timestamp.
+	 * No need to zero initialize as all elements written.
+	 */
+	struct {
+		__be16 chan[4];
+		s64 ts __aligned(8);
+	} hw_values;
 	int ret;
-	/* 4 * 16bit values AND timestamp */
-	__be16 hw_values[8];
 
 	ret = regmap_bulk_read(st->map,
 			       KXSD9_REG_X,
-			       &hw_values,
-			       8);
+			       hw_values.chan,
+			       sizeof(hw_values.chan));
 	if (ret) {
-		dev_err(st->dev,
-			"error reading data\n");
-		return ret;
+		dev_err(st->dev, "error reading data: %d\n", ret);
+		goto out;
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev,
-					   hw_values,
+					   &hw_values,
 					   iio_get_time_ns(indio_dev));
+out:
 	iio_trigger_notify_done(indio_dev->trig);
 
 	return IRQ_HANDLED;
--- linux-ein-5.4.0.orig/drivers/iio/accel/mma7455_core.c
+++ linux-ein-5.4.0/drivers/iio/accel/mma7455_core.c
@@ -52,6 +52,14 @@
 
 struct mma7455_data {
 	struct regmap *regmap;
+	/*
+	 * Used to reorganize data.  Will ensure correct alignment of
+	 * the timestamp if present
+	 */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static int mma7455_drdy(struct mma7455_data *mma7455)
@@ -82,19 +90,19 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mma7455_data *mma7455 = iio_priv(indio_dev);
-	u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
 	int ret;
 
 	ret = mma7455_drdy(mma7455);
 	if (ret)
 		goto done;
 
-	ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
-			       sizeof(__le16) * 3);
+	ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL,
+			       mma7455->scan.channels,
+			       sizeof(mma7455->scan.channels));
 	if (ret)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
 					   iio_get_time_ns(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/accel/mma8452.c
+++ linux-ein-5.4.0/drivers/iio/accel/mma8452.c
@@ -110,6 +110,12 @@
 	int sleep_val;
 	struct regulator *vdd_reg;
 	struct regulator *vddio_reg;
+
+	/* Ensure correct alignment of time stamp when present */
+	struct {
+		__be16 channels[3];
+		s64 ts __aligned(8);
+	} buffer;
 };
 
  /**
@@ -1091,14 +1097,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(indio_dev));
 
 done:
@@ -1468,7 +1473,7 @@
 	if (ret)
 		return ret;
 
-	indio_dev->trig = trig;
+	indio_dev->trig = iio_trigger_get(trig);
 
 	return 0;
 }
@@ -1484,10 +1489,14 @@
 	int i;
 	int ret;
 
-	ret = i2c_smbus_write_byte_data(client,	MMA8452_CTRL_REG2,
+	/*
+	 * Find on fxls8471, after config reset bit, it reset immediately,
+	 * and will not give ACK, so here do not check the return value.
+	 * The following code will read the reset register, and check whether
+	 * this reset works.
+	 */
+	i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2,
 					MMA8452_CTRL_REG2_RST);
-	if (ret < 0)
-		return ret;
 
 	for (i = 0; i < 10; i++) {
 		usleep_range(100, 200);
@@ -1685,10 +1694,13 @@
 
 	ret = mma8452_set_freefall_mode(data, false);
 	if (ret < 0)
-		goto buffer_cleanup;
+		goto unregister_device;
 
 	return 0;
 
+unregister_device:
+	iio_device_unregister(indio_dev);
+
 buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
 
--- linux-ein-5.4.0.orig/drivers/iio/accel/mma9551.c
+++ linux-ein-5.4.0/drivers/iio/accel/mma9551.c
@@ -496,11 +496,14 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "unable to register iio device\n");
-		goto out_poweroff;
+		goto err_pm_cleanup;
 	}
 
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(&client->dev);
+	pm_runtime_disable(&client->dev);
 out_poweroff:
 	mma9551_set_device_state(client, false);
 
--- linux-ein-5.4.0.orig/drivers/iio/accel/mma9551_core.c
+++ linux-ein-5.4.0/drivers/iio/accel/mma9551_core.c
@@ -296,9 +296,12 @@
 
 	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
 			       reg, NULL, 0, (u8 *)&v, 2);
+	if (ret < 0)
+		return ret;
+
 	*val = be16_to_cpu(v);
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(mma9551_read_config_word);
 
@@ -354,9 +357,12 @@
 
 	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
 			       reg, NULL, 0, (u8 *)&v, 2);
+	if (ret < 0)
+		return ret;
+
 	*val = be16_to_cpu(v);
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(mma9551_read_status_word);
 
--- linux-ein-5.4.0.orig/drivers/iio/accel/mma9553.c
+++ linux-ein-5.4.0/drivers/iio/accel/mma9553.c
@@ -1135,12 +1135,15 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "unable to register iio device\n");
-		goto out_poweroff;
+		goto err_pm_cleanup;
 	}
 
 	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(&client->dev);
+	pm_runtime_disable(&client->dev);
 out_poweroff:
 	mma9551_set_device_state(client, false);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/iio/accel/mxc4005.c
+++ linux-ein-5.4.0/drivers/iio/accel/mxc4005.c
@@ -56,7 +56,11 @@
 	struct mutex mutex;
 	struct regmap *regmap;
 	struct iio_trigger *dready_trig;
-	__be16 buffer[8];
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		__be16 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 	bool trigger_enabled;
 };
 
@@ -135,7 +139,7 @@
 	int ret;
 
 	ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
-			       (u8 *) data->buffer, sizeof(data->buffer));
+			       data->scan.chans, sizeof(data->scan.chans));
 	if (ret < 0) {
 		dev_err(data->dev, "failed to read axes\n");
 		return ret;
@@ -150,7 +154,7 @@
 	__be16 reg;
 	int ret;
 
-	ret = regmap_bulk_read(data->regmap, addr, (u8 *) &reg, sizeof(reg));
+	ret = regmap_bulk_read(data->regmap, addr, &reg, sizeof(reg));
 	if (ret < 0) {
 		dev_err(data->dev, "failed to read reg %02x\n", addr);
 		return ret;
@@ -301,7 +305,7 @@
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 
 err:
@@ -458,8 +462,6 @@
 		data->dready_trig->dev.parent = &client->dev;
 		data->dready_trig->ops = &mxc4005_trigger_ops;
 		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
-		indio_dev->trig = data->dready_trig;
-		iio_trigger_get(indio_dev->trig);
 		ret = devm_iio_trigger_register(&client->dev,
 						data->dready_trig);
 		if (ret) {
@@ -467,6 +469,8 @@
 				"failed to register trigger\n");
 			return ret;
 		}
+
+		indio_dev->trig = iio_trigger_get(data->dready_trig);
 	}
 
 	return devm_iio_device_register(&client->dev, indio_dev);
--- linux-ein-5.4.0.orig/drivers/iio/accel/sca3000.c
+++ linux-ein-5.4.0/drivers/iio/accel/sca3000.c
@@ -980,7 +980,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\n");
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/iio/accel/st_accel_core.c
+++ linux-ein-5.4.0/drivers/iio/accel/st_accel_core.c
@@ -993,6 +993,7 @@
 #define ST_ACCEL_TRIGGER_OPS NULL
 #endif
 
+#ifdef CONFIG_ACPI
 static const struct iio_mount_matrix *
 get_mount_matrix(const struct iio_dev *indio_dev,
 		 const struct iio_chan_spec *chan)
@@ -1013,7 +1014,6 @@
 static int apply_acpi_orientation(struct iio_dev *indio_dev,
 				  struct iio_chan_spec *channels)
 {
-#ifdef CONFIG_ACPI
 	struct st_sensor_data *adata = iio_priv(indio_dev);
 	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	struct acpi_device *adev;
@@ -1141,10 +1141,14 @@
 out:
 	kfree(buffer.pointer);
 	return ret;
+}
 #else /* !CONFIG_ACPI */
+static int apply_acpi_orientation(struct iio_dev *indio_dev,
+				  struct iio_chan_spec *channels)
+{
 	return 0;
-#endif
 }
+#endif
 
 /*
  * st_accel_get_settings() - get sensor settings from device name
--- linux-ein-5.4.0.orig/drivers/iio/accel/st_accel_i2c.c
+++ linux-ein-5.4.0/drivers/iio/accel/st_accel_i2c.c
@@ -114,7 +114,7 @@
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id st_accel_acpi_match[] = {
-	{"SMO8840", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
+	{"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME},
 	{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
 	{ },
 };
--- linux-ein-5.4.0.orig/drivers/iio/accel/stk8312.c
+++ linux-ein-5.4.0/drivers/iio/accel/stk8312.c
@@ -103,7 +103,11 @@
 	u8 mode;
 	struct iio_trigger *dready_trig;
 	bool dready_trigger_on;
-	s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s8 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
@@ -438,7 +442,7 @@
 		ret = i2c_smbus_read_i2c_block_data(data->client,
 						    STK8312_REG_XOUT,
 						    STK8312_ALL_CHANNEL_SIZE,
-						    data->buffer);
+						    data->scan.chans);
 		if (ret < STK8312_ALL_CHANNEL_SIZE) {
 			dev_err(&data->client->dev, "register read failed\n");
 			mutex_unlock(&data->lock);
@@ -452,12 +456,12 @@
 				mutex_unlock(&data->lock);
 				goto err;
 			}
-			data->buffer[i++] = ret;
+			data->scan.chans[i++] = ret;
 		}
 	}
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/accel/stk8ba50.c
+++ linux-ein-5.4.0/drivers/iio/accel/stk8ba50.c
@@ -91,12 +91,11 @@
 	u8 sample_rate_idx;
 	struct iio_trigger *dready_trig;
 	bool dready_trigger_on;
-	/*
-	 * 3 x 16-bit channels (10-bit data, 6-bit padding) +
-	 * 1 x 16 padding +
-	 * 4 x 16 64-bit timestamp
-	 */
-	s16 buffer[8];
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s16 chans[3];
+		s64 timetamp __aligned(8);
+	} scan;
 };
 
 #define STK8BA50_ACCEL_CHANNEL(index, reg, axis) {			\
@@ -324,7 +323,7 @@
 		ret = i2c_smbus_read_i2c_block_data(data->client,
 						    STK8BA50_REG_XOUT,
 						    STK8BA50_ALL_CHANNEL_SIZE,
-						    (u8 *)data->buffer);
+						    (u8 *)data->scan.chans);
 		if (ret < STK8BA50_ALL_CHANNEL_SIZE) {
 			dev_err(&data->client->dev, "register read failed\n");
 			goto err;
@@ -337,10 +336,10 @@
 			if (ret < 0)
 				goto err;
 
-			data->buffer[i++] = ret;
+			data->scan.chans[i++] = ret;
 		}
 	}
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 err:
 	mutex_unlock(&data->lock);
--- linux-ein-5.4.0.orig/drivers/iio/adc/Kconfig
+++ linux-ein-5.4.0/drivers/iio/adc/Kconfig
@@ -784,6 +784,7 @@
 	depends on ARCH_STM32 || COMPILE_TEST
 	depends on OF
 	depends on REGULATOR
+	depends on HAS_IOMEM
 	select IIO_BUFFER
 	select MFD_STM32_TIMERS
 	select IIO_STM32_TIMER_TRIGGER
@@ -839,22 +840,6 @@
 	  Say yes here to build support for ST Microelectronics STMPE
 	  built-in ADC block (stmpe811).
 
-config STX104
-	tristate "Apex Embedded Systems STX104 driver"
-	depends on PC104 && X86
-	select ISA_BUS_API
-	select GPIOLIB
-	help
-	  Say yes here to build support for the Apex Embedded Systems STX104
-	  integrated analog PC/104 card.
-
-	  This driver supports the 16 channels of single-ended (8 channels of
-	  differential) analog inputs, 2 channels of analog output, 4 digital
-	  inputs, and 4 digital outputs provided by the STX104.
-
-	  The base port addresses for the devices may be configured via the base
-	  array module parameter.
-
 config SUN4I_GPADC
 	tristate "Support for the Allwinner SoCs GPADC"
 	depends on IIO
--- linux-ein-5.4.0.orig/drivers/iio/adc/Makefile
+++ linux-ein-5.4.0/drivers/iio/adc/Makefile
@@ -72,7 +72,6 @@
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
 obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
-obj-$(CONFIG_STX104) += stx104.o
 obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
 obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
 obj-$(CONFIG_STM32_ADC) += stm32-adc.o
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7124.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7124.c
@@ -39,6 +39,8 @@
 #define AD7124_STATUS_POR_FLAG_MSK	BIT(4)
 
 /* AD7124_ADC_CONTROL */
+#define AD7124_ADC_CTRL_REF_EN_MSK	BIT(8)
+#define AD7124_ADC_CTRL_REF_EN(x)	FIELD_PREP(AD7124_ADC_CTRL_REF_EN_MSK, x)
 #define AD7124_ADC_CTRL_PWR_MSK	GENMASK(7, 6)
 #define AD7124_ADC_CTRL_PWR(x)		FIELD_PREP(AD7124_ADC_CTRL_PWR_MSK, x)
 #define AD7124_ADC_CTRL_MODE_MSK	GENMASK(5, 2)
@@ -61,7 +63,7 @@
 #define AD7124_CONFIG_REF_SEL(x)	FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
 #define AD7124_CONFIG_PGA_MSK		GENMASK(2, 0)
 #define AD7124_CONFIG_PGA(x)		FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
-#define AD7124_CONFIG_IN_BUFF_MSK	GENMASK(7, 6)
+#define AD7124_CONFIG_IN_BUFF_MSK	GENMASK(6, 5)
 #define AD7124_CONFIG_IN_BUFF(x)	FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x)
 
 /* AD7124_FILTER_X */
@@ -140,7 +142,6 @@
 		.sign = 'u',
 		.realbits = 24,
 		.storagebits = 32,
-		.shift = 8,
 		.endianness = IIO_BE,
 	},
 };
@@ -424,7 +425,10 @@
 		break;
 	case AD7124_INT_REF:
 		st->channel_config[channel_number].vref_mv = 2500;
-		break;
+		st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK;
+		st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
+		return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL,
+				      2, st->adc_control);
 	default:
 		dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
 		return -EINVAL;
@@ -468,6 +472,13 @@
 		if (ret)
 			goto err;
 
+		if (channel >= indio_dev->num_channels) {
+			dev_err(indio_dev->dev.parent,
+				"Channel index >= number of channels\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
 		ret = of_property_read_u32_array(child, "diff-channels",
 						 ain, 2);
 		if (ret)
@@ -489,13 +500,11 @@
 		st->channel_config[channel].buf_negative =
 			of_property_read_bool(child, "adi,buffered-negative");
 
-		*chan = ad7124_channel_template;
-		chan->address = channel;
-		chan->scan_index = channel;
-		chan->channel = ain[0];
-		chan->channel2 = ain[1];
-
-		chan++;
+		chan[channel] = ad7124_channel_template;
+		chan[channel].address = channel;
+		chan[channel].scan_index = channel;
+		chan[channel].channel = ain[0];
+		chan[channel].channel2 = ain[1];
 	}
 
 	return 0;
@@ -561,6 +570,11 @@
 	return ret;
 }
 
+static void ad7124_reg_disable(void *r)
+{
+	regulator_disable(r);
+}
+
 static int ad7124_probe(struct spi_device *spi)
 {
 	const struct spi_device_id *id;
@@ -604,17 +618,20 @@
 		ret = regulator_enable(st->vref[i]);
 		if (ret)
 			return ret;
+
+		ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable,
+					       st->vref[i]);
+		if (ret)
+			return ret;
 	}
 
 	st->mclk = devm_clk_get(&spi->dev, "mclk");
-	if (IS_ERR(st->mclk)) {
-		ret = PTR_ERR(st->mclk);
-		goto error_regulator_disable;
-	}
+	if (IS_ERR(st->mclk))
+		return PTR_ERR(st->mclk);
 
 	ret = clk_prepare_enable(st->mclk);
 	if (ret < 0)
-		goto error_regulator_disable;
+		return ret;
 
 	ret = ad7124_soft_reset(st);
 	if (ret < 0)
@@ -640,11 +657,6 @@
 	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_clk_disable_unprepare:
 	clk_disable_unprepare(st->mclk);
-error_regulator_disable:
-	for (i = ARRAY_SIZE(st->vref) - 1; i >= 0; i--) {
-		if (!IS_ERR_OR_NULL(st->vref[i]))
-			regulator_disable(st->vref[i]);
-	}
 
 	return ret;
 }
@@ -653,17 +665,11 @@
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	struct ad7124_state *st = iio_priv(indio_dev);
-	int i;
 
 	iio_device_unregister(indio_dev);
 	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 	clk_disable_unprepare(st->mclk);
 
-	for (i = ARRAY_SIZE(st->vref) - 1; i >= 0; i--) {
-		if (!IS_ERR_OR_NULL(st->vref[i]))
-			regulator_disable(st->vref[i]);
-	}
-
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7606.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7606.c
@@ -85,7 +85,7 @@
 
 static int ad7606_read_samples(struct ad7606_state *st)
 {
-	unsigned int num = st->chip_info->num_channels;
+	unsigned int num = st->chip_info->num_channels - 1;
 	u16 *data = st->data;
 	int ret;
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7768-1.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7768-1.c
@@ -166,6 +166,10 @@
 	 * transfer buffers to live in their own cache lines.
 	 */
 	union {
+		struct {
+			__be32 chan;
+			s64 timestamp;
+		} scan;
 		__be32 d32;
 		u8 d8[2];
 	} data ____cacheline_aligned;
@@ -459,15 +463,15 @@
 
 	mutex_lock(&st->lock);
 
-	ret = spi_read(st->spi, &st->data.d32, 3);
+	ret = spi_read(st->spi, &st->data.scan.chan, 3);
 	if (ret < 0)
 		goto err_unlock;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, &st->data.d32,
+	iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan,
 					   iio_get_time_ns(indio_dev));
 
-	iio_trigger_notify_done(indio_dev->trig);
 err_unlock:
+	iio_trigger_notify_done(indio_dev->trig);
 	mutex_unlock(&st->lock);
 
 	return IRQ_HANDLED;
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7780.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7780.c
@@ -309,7 +309,7 @@
 
 	ret = ad7780_init_gpios(&spi->dev, st);
 	if (ret)
-		goto error_cleanup_buffer_and_trigger;
+		return ret;
 
 	st->reg = devm_regulator_get(&spi->dev, "avdd");
 	if (IS_ERR(st->reg))
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7793.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7793.c
@@ -278,6 +278,7 @@
 	id &= AD7793_ID_MASK;
 
 	if (id != st->chip_info->id) {
+		ret = -ENODEV;
 		dev_err(&st->sd.spi->dev, "device ID query failed\n");
 		goto out;
 	}
@@ -541,7 +542,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,
 };
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad7949.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad7949.c
@@ -57,29 +57,11 @@
 	u32 buffer ____cacheline_aligned;
 };
 
-static bool ad7949_spi_cfg_is_read_back(struct ad7949_adc_chip *ad7949_adc)
-{
-	if (!(ad7949_adc->cfg & AD7949_CFG_READ_BACK))
-		return true;
-
-	return false;
-}
-
-static int ad7949_spi_bits_per_word(struct ad7949_adc_chip *ad7949_adc)
-{
-	int ret = ad7949_adc->resolution;
-
-	if (ad7949_spi_cfg_is_read_back(ad7949_adc))
-		ret += AD7949_CFG_REG_SIZE_BITS;
-
-	return ret;
-}
-
 static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
 				u16 mask)
 {
 	int ret;
-	int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
+	int bits_per_word = ad7949_adc->resolution;
 	int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
@@ -107,8 +89,9 @@
 				   unsigned int channel)
 {
 	int ret;
-	int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
-	int mask = GENMASK(ad7949_adc->resolution, 0);
+	int i;
+	int bits_per_word = ad7949_adc->resolution;
+	int mask = GENMASK(ad7949_adc->resolution - 1, 0);
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
@@ -118,12 +101,23 @@
 		},
 	};
 
-	ret = ad7949_spi_write_cfg(ad7949_adc,
-				   channel << AD7949_OFFSET_CHANNEL_SEL,
-				   AD7949_MASK_CHANNEL_SEL);
-	if (ret)
-		return ret;
+	/*
+	 * 1: write CFG for sample N and read old data (sample N-2)
+	 * 2: if CFG was not changed since sample N-1 then we'll get good data
+	 *    at the next xfer, so we bail out now, otherwise we write something
+	 *    and we read garbage (sample N-1 configuration).
+	 */
+	for (i = 0; i < 2; i++) {
+		ret = ad7949_spi_write_cfg(ad7949_adc,
+					   channel << AD7949_OFFSET_CHANNEL_SEL,
+					   AD7949_MASK_CHANNEL_SEL);
+		if (ret)
+			return ret;
+		if (channel == ad7949_adc->current_channel)
+			break;
+	}
 
+	/* 3: write something and read actual data */
 	ad7949_adc->buffer = 0;
 	spi_message_init_with_transfers(&msg, tx, 1);
 	ret = spi_sync(ad7949_adc->spi, &msg);
@@ -138,10 +132,7 @@
 
 	ad7949_adc->current_channel = channel;
 
-	if (ad7949_spi_cfg_is_read_back(ad7949_adc))
-		*val = (ad7949_adc->buffer >> AD7949_CFG_REG_SIZE_BITS) & mask;
-	else
-		*val = ad7949_adc->buffer & mask;
+	*val = ad7949_adc->buffer & mask;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/iio/adc/ad_sigma_delta.c
+++ linux-ein-5.4.0/drivers/iio/adc/ad_sigma_delta.c
@@ -283,10 +283,10 @@
 	unsigned int data_reg;
 	int ret = 0;
 
-	if (iio_buffer_enabled(indio_dev))
-		return -EBUSY;
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
 
-	mutex_lock(&indio_dev->mlock);
 	ad_sigma_delta_set_channel(sigma_delta, chan->address);
 
 	spi_bus_lock(sigma_delta->spi->master);
@@ -325,7 +325,7 @@
 	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);
+	iio_device_release_direct_mode(indio_dev);
 
 	if (ret)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/iio/adc/aspeed_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/aspeed_adc.c
@@ -184,6 +184,7 @@
 
 	data = iio_priv(indio_dev);
 	data->dev = &pdev->dev;
+	platform_set_drvdata(pdev, indio_dev);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	data->base = devm_ioremap_resource(&pdev->dev, res);
--- linux-ein-5.4.0.orig/drivers/iio/adc/at91-sama5d2_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/at91-sama5d2_adc.c
@@ -73,7 +73,7 @@
 #define	AT91_SAMA5D2_MR_ANACH		BIT(23)
 /* Tracking Time */
 #define	AT91_SAMA5D2_MR_TRACKTIM(v)	((v) << 24)
-#define	AT91_SAMA5D2_MR_TRACKTIM_MAX	0xff
+#define	AT91_SAMA5D2_MR_TRACKTIM_MAX	0xf
 /* Transfer Time */
 #define	AT91_SAMA5D2_MR_TRANSFER(v)	((v) << 28)
 #define	AT91_SAMA5D2_MR_TRANSFER_MAX	0x3
@@ -399,7 +399,9 @@
 	wait_queue_head_t		wq_data_available;
 	struct at91_adc_dma		dma_st;
 	struct at91_adc_touch		touch_st;
-	u16				buffer[AT91_BUFFER_MAX_HWORDS];
+	struct iio_dev			*indio_dev;
+	/* Ensure naturally aligned timestamp */
+	u16				buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8);
 	/*
 	 * lock to prevent concurrent 'single conversion' requests through
 	 * sysfs.
@@ -624,13 +626,13 @@
 	/* first half of register is the x or y, second half is the scale */
 	val = at91_adc_readl(st, reg);
 	if (!val)
-		dev_dbg(&iio_priv_to_dev(st)->dev, "pos is 0\n");
+		dev_dbg(&st->indio_dev->dev, "pos is 0\n");
 
 	pos = val & AT91_SAMA5D2_XYZ_MASK;
 	result = (pos << AT91_SAMA5D2_MAX_POS_BITS) - pos;
 	scale = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
 	if (scale == 0) {
-		dev_err(&iio_priv_to_dev(st)->dev, "scale is 0\n");
+		dev_err(&st->indio_dev->dev, "scale is 0\n");
 		return 0;
 	}
 	result /= scale;
@@ -723,6 +725,7 @@
 
 	for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
 		struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
+		u32 cor;
 
 		if (!chan)
 			continue;
@@ -732,6 +735,20 @@
 			continue;
 
 		if (state) {
+			cor = at91_adc_readl(st, AT91_SAMA5D2_COR);
+
+			if (chan->differential)
+				cor |= (BIT(chan->channel) |
+					BIT(chan->channel2)) <<
+					AT91_SAMA5D2_COR_DIFF_OFFSET;
+			else
+				cor &= ~(BIT(chan->channel) <<
+				       AT91_SAMA5D2_COR_DIFF_OFFSET);
+
+			at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
+		}
+
+		if (state) {
 			at91_adc_writel(st, AT91_SAMA5D2_CHER,
 					BIT(chan->channel));
 			/* enable irq only if not using DMA */
@@ -966,7 +983,7 @@
 	trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name,
 				      indio->id, trigger_name);
 	if (!trig)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	trig->dev.parent = indio->dev.parent;
 	iio_trigger_set_drvdata(trig, indio);
@@ -1139,9 +1156,9 @@
 	return i;
 }
 
-static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
+static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq)
 {
-	struct iio_dev *indio_dev = iio_priv_to_dev(st);
+	struct at91_adc_state *st = iio_priv(indio_dev);
 	unsigned f_per, prescal, startup, mr;
 
 	f_per = clk_get_rate(st->per_clk);
@@ -1210,9 +1227,9 @@
 	st->touch_st.touching = true;
 }
 
-static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st)
+static void at91_adc_no_pen_detect_interrupt(struct iio_dev *indio_dev)
 {
-	struct iio_dev *indio_dev = iio_priv_to_dev(st);
+	struct at91_adc_state *st = iio_priv(indio_dev);
 
 	at91_adc_writel(st, AT91_SAMA5D2_TRGR,
 			AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
@@ -1232,7 +1249,7 @@
 					struct at91_adc_touch, workq);
 	struct at91_adc_state *st = container_of(touch_st,
 					struct at91_adc_state, touch_st);
-	struct iio_dev *indio_dev = iio_priv_to_dev(st);
+	struct iio_dev *indio_dev = st->indio_dev;
 
 	iio_push_to_buffers(indio_dev, st->buffer);
 }
@@ -1253,7 +1270,7 @@
 		at91_adc_pen_detect_interrupt(st);
 	} else if ((status & AT91_SAMA5D2_IER_NOPEN)) {
 		/* nopen detected IRQ */
-		at91_adc_no_pen_detect_interrupt(st);
+		at91_adc_no_pen_detect_interrupt(indio);
 	} else if ((status & AT91_SAMA5D2_ISR_PENS) &&
 		   ((status & rdy_mask) == rdy_mask)) {
 		/* periodic trigger IRQ - during pen sense */
@@ -1304,10 +1321,12 @@
 		ret = at91_adc_read_position(st, chan->channel,
 					     &tmp_val);
 		*val = tmp_val;
+		if (ret > 0)
+			ret = at91_adc_adjust_val_osr(st, val);
 		mutex_unlock(&st->lock);
 		iio_device_release_direct_mode(indio_dev);
 
-		return at91_adc_adjust_val_osr(st, val);
+		return ret;
 	}
 	if (chan->type == IIO_PRESSURE) {
 		ret = iio_device_claim_direct_mode(indio_dev);
@@ -1318,10 +1337,12 @@
 		ret = at91_adc_read_pressure(st, chan->channel,
 					     &tmp_val);
 		*val = tmp_val;
+		if (ret > 0)
+			ret = at91_adc_adjust_val_osr(st, val);
 		mutex_unlock(&st->lock);
 		iio_device_release_direct_mode(indio_dev);
 
-		return at91_adc_adjust_val_osr(st, val);
+		return ret;
 	}
 
 	/* in this case we have a voltage channel */
@@ -1352,7 +1373,8 @@
 		*val = st->conversion_value;
 		ret = at91_adc_adjust_val_osr(st, val);
 		if (chan->scan_type.sign == 's')
-			*val = sign_extend32(*val, 11);
+			*val = sign_extend32(*val,
+					     chan->scan_type.realbits - 1);
 		st->conversion_done = false;
 	}
 
@@ -1411,16 +1433,20 @@
 		/* if no change, optimize out */
 		if (val == st->oversampling_ratio)
 			return 0;
+		mutex_lock(&st->lock);
 		st->oversampling_ratio = val;
 		/* update ratio */
 		at91_adc_config_emr(st);
+		mutex_unlock(&st->lock);
 		return 0;
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		if (val < st->soc_info.min_sample_rate ||
 		    val > st->soc_info.max_sample_rate)
 			return -EINVAL;
 
-		at91_adc_setup_samp_freq(st, val);
+		mutex_lock(&st->lock);
+		at91_adc_setup_samp_freq(indio_dev, val);
+		mutex_unlock(&st->lock);
 		return 0;
 	default:
 		return -EINVAL;
@@ -1558,8 +1584,10 @@
 	return 0;
 }
 
-static void at91_adc_hw_init(struct at91_adc_state *st)
+static void at91_adc_hw_init(struct iio_dev *indio_dev)
 {
+	struct at91_adc_state *st = iio_priv(indio_dev);
+
 	at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
 	at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
 	/*
@@ -1569,7 +1597,7 @@
 	at91_adc_writel(st, AT91_SAMA5D2_MR,
 			AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
 
-	at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+	at91_adc_setup_samp_freq(indio_dev, st->soc_info.min_sample_rate);
 
 	/* configure extended mode register */
 	at91_adc_config_emr(st);
@@ -1652,6 +1680,7 @@
 	indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
 
 	st = iio_priv(indio_dev);
+	st->indio_dev = indio_dev;
 
 	bitmap_set(&st->touch_st.channels_bitmask,
 		   AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
@@ -1763,7 +1792,7 @@
 		goto vref_disable;
 	}
 
-	at91_adc_hw_init(st);
+	at91_adc_hw_init(indio_dev);
 
 	ret = clk_prepare_enable(st->per_clk);
 	if (ret)
@@ -1879,7 +1908,7 @@
 	if (ret)
 		goto vref_disable_resume;
 
-	at91_adc_hw_init(st);
+	at91_adc_hw_init(indio_dev);
 
 	/* reconfiguring trigger hardware state */
 	if (!iio_buffer_enabled(indio_dev))
--- linux-ein-5.4.0.orig/drivers/iio/adc/at91_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/at91_adc.c
@@ -616,8 +616,10 @@
 	trig->ops = &at91_adc_trigger_ops;
 
 	ret = iio_trigger_register(trig);
-	if (ret)
+	if (ret) {
+		iio_trigger_free(trig);
 		return NULL;
+	}
 
 	return trig;
 }
--- linux-ein-5.4.0.orig/drivers/iio/adc/axp20x_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/axp20x_adc.c
@@ -251,19 +251,8 @@
 			  struct iio_chan_spec const *chan, int *val)
 {
 	struct axp20x_adc_iio *info = iio_priv(indio_dev);
-	int size;
 
-	/*
-	 * N.B.: Unlike the Chinese datasheets tell, the charging current is
-	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
-	 * bits.
-	 */
-	if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
-		size = 13;
-	else
-		size = 12;
-
-	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
+	*val = axp20x_read_variable_width(info->regmap, chan->address, 12);
 	if (*val < 0)
 		return *val;
 
@@ -386,9 +375,8 @@
 		return IIO_VAL_INT_PLUS_MICRO;
 
 	case IIO_CURRENT:
-		*val = 0;
-		*val2 = 500000;
-		return IIO_VAL_INT_PLUS_MICRO;
+		*val = 1;
+		return IIO_VAL_INT;
 
 	case IIO_TEMP:
 		*val = 100;
--- linux-ein-5.4.0.orig/drivers/iio/adc/axp288_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/axp288_adc.c
@@ -196,6 +196,14 @@
 		},
 		.driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA,
 	},
+	{
+		/* Nuvision Solo 10 Draw */
+		.matches = {
+		  DMI_MATCH(DMI_SYS_VENDOR, "TMAX"),
+		  DMI_MATCH(DMI_PRODUCT_NAME, "TM101W610L"),
+		},
+		.driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA,
+	},
 	{}
 };
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/berlin2-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/berlin2-adc.c
@@ -289,8 +289,10 @@
 	int ret;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
-	if (!indio_dev)
+	if (!indio_dev) {
+		of_node_put(parent_np);
 		return -ENOMEM;
+	}
 
 	priv = iio_priv(indio_dev);
 	platform_set_drvdata(pdev, indio_dev);
--- linux-ein-5.4.0.orig/drivers/iio/adc/dln2-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/dln2-adc.c
@@ -248,7 +248,6 @@
 static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
 {
 	int ret, i;
-	struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
 	u16 conflict;
 	__le16 value;
 	int olen = sizeof(value);
@@ -257,13 +256,9 @@
 		.chan = channel,
 	};
 
-	ret = iio_device_claim_direct_mode(indio_dev);
-	if (ret < 0)
-		return ret;
-
 	ret = dln2_adc_set_chan_enabled(dln2, channel, true);
 	if (ret < 0)
-		goto release_direct;
+		return ret;
 
 	ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
 	if (ret < 0) {
@@ -300,8 +295,6 @@
 	dln2_adc_set_port_enabled(dln2, false, NULL);
 disable_chan:
 	dln2_adc_set_chan_enabled(dln2, channel, false);
-release_direct:
-	iio_device_release_direct_mode(indio_dev);
 
 	return ret;
 }
@@ -337,10 +330,16 @@
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret < 0)
+			return ret;
+
 		mutex_lock(&dln2->mutex);
 		ret = dln2_adc_read(dln2, chan->channel);
 		mutex_unlock(&dln2->mutex);
 
+		iio_device_release_direct_mode(indio_dev);
+
 		if (ret < 0)
 			return ret;
 
@@ -524,6 +523,10 @@
 	u16 conflict;
 	unsigned int trigger_chan;
 
+	ret = iio_triggered_buffer_postenable(indio_dev);
+	if (ret)
+		return ret;
+
 	mutex_lock(&dln2->mutex);
 
 	/* Enable ADC */
@@ -537,6 +540,7 @@
 				(int)conflict);
 			ret = -EBUSY;
 		}
+		iio_triggered_buffer_predisable(indio_dev);
 		return ret;
 	}
 
@@ -550,6 +554,7 @@
 		mutex_unlock(&dln2->mutex);
 		if (ret < 0) {
 			dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+			iio_triggered_buffer_predisable(indio_dev);
 			return ret;
 		}
 	} else {
@@ -557,12 +562,12 @@
 		mutex_unlock(&dln2->mutex);
 	}
 
-	return iio_triggered_buffer_postenable(indio_dev);
+	return 0;
 }
 
 static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
 {
-	int ret;
+	int ret, ret2;
 	struct dln2_adc *dln2 = iio_priv(indio_dev);
 
 	mutex_lock(&dln2->mutex);
@@ -577,12 +582,14 @@
 	ret = dln2_adc_set_port_enabled(dln2, false, NULL);
 
 	mutex_unlock(&dln2->mutex);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
-		return ret;
-	}
 
-	return iio_triggered_buffer_predisable(indio_dev);
+	ret2 = iio_triggered_buffer_predisable(indio_dev);
+	if (ret == 0)
+		ret = ret2;
+
+	return ret;
 }
 
 static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = {
@@ -658,7 +665,11 @@
 		return -ENOMEM;
 	}
 	iio_trigger_set_drvdata(dln2->trig, dln2);
-	devm_iio_trigger_register(dev, dln2->trig);
+	ret = devm_iio_trigger_register(dev, dln2->trig);
+	if (ret) {
+		dev_err(dev, "failed to register trigger: %d\n", ret);
+		return ret;
+	}
 	iio_trigger_set_immutable(indio_dev, dln2->trig);
 
 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
--- linux-ein-5.4.0.orig/drivers/iio/adc/exynos_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/exynos_adc.c
@@ -804,16 +804,26 @@
 		}
 	}
 
+	/* leave out any TS related code if unreachable */
+	if (IS_REACHABLE(CONFIG_INPUT)) {
+		has_ts = of_property_read_bool(pdev->dev.of_node,
+					       "has-touchscreen") || pdata;
+	}
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return irq;
 	info->irq = irq;
 
-	irq = platform_get_irq(pdev, 1);
-	if (irq == -EPROBE_DEFER)
-		return irq;
-
-	info->tsirq = irq;
+	if (has_ts) {
+		irq = platform_get_irq(pdev, 1);
+		if (irq == -EPROBE_DEFER)
+			return irq;
+
+		info->tsirq = irq;
+	} else {
+		info->tsirq = -1;
+	}
 
 	info->dev = &pdev->dev;
 
@@ -880,12 +890,6 @@
 	if (info->data->init_hw)
 		info->data->init_hw(info);
 
-	/* leave out any TS related code if unreachable */
-	if (IS_REACHABLE(CONFIG_INPUT)) {
-		has_ts = of_property_read_bool(pdev->dev.of_node,
-					       "has-touchscreen") || pdata;
-	}
-
 	if (pdata)
 		info->delay = pdata->delay;
 	else
--- linux-ein-5.4.0.orig/drivers/iio/adc/hx711.c
+++ linux-ein-5.4.0/drivers/iio/adc/hx711.c
@@ -85,9 +85,9 @@
 	struct mutex		lock;
 	/*
 	 * triggered buffer
-	 * 2x32-bit channel + 64-bit timestamp
+	 * 2x32-bit channel + 64-bit naturally aligned timestamp
 	 */
-	u32			buffer[4];
+	u32			buffer[4] __aligned(8);
 	/*
 	 * delay after a rising edge on SCK until the data is ready DOUT
 	 * this is dependent on the hx711 where the datasheet tells a
--- linux-ein-5.4.0.orig/drivers/iio/adc/ina2xx-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/ina2xx-adc.c
@@ -146,6 +146,11 @@
 	int range_vbus; /* Bus voltage maximum in V */
 	int pga_gain_vshunt; /* Shunt voltage PGA gain */
 	bool allow_async_readout;
+	/* data buffer needs space for channel data and timestamp */
+	struct {
+		u16 chan[4];
+		u64 ts __aligned(8);
+	} scan;
 };
 
 static const struct ina2xx_config ina2xx_config[] = {
@@ -738,8 +743,6 @@
 static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 {
 	struct ina2xx_chip_info *chip = iio_priv(indio_dev);
-	/* data buffer needs space for channel data and timestap */
-	unsigned short data[4 + sizeof(s64)/sizeof(short)];
 	int bit, ret, i = 0;
 	s64 time;
 
@@ -758,10 +761,10 @@
 		if (ret < 0)
 			return ret;
 
-		data[i++] = val;
+		chip->scan.chan[i++] = val;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data, time);
+	iio_push_to_buffers_with_timestamp(indio_dev, &chip->scan, time);
 
 	return 0;
 };
--- linux-ein-5.4.0.orig/drivers/iio/adc/max1027.c
+++ linux-ein-5.4.0/drivers/iio/adc/max1027.c
@@ -458,6 +458,14 @@
 		return ret;
 	}
 
+	/* 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-ein-5.4.0.orig/drivers/iio/adc/max1118.c
+++ linux-ein-5.4.0/drivers/iio/adc/max1118.c
@@ -35,6 +35,11 @@
 	struct spi_device *spi;
 	struct mutex lock;
 	struct regulator *reg;
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		u8 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 
 	u8 data ____cacheline_aligned;
 };
@@ -159,7 +164,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct max1118 *adc = iio_priv(indio_dev);
-	u8 data[16] = { }; /* 2x 8-bit ADC data + padding + 8 bytes timestamp */
 	int scan_index;
 	int i = 0;
 
@@ -177,10 +181,10 @@
 			goto out;
 		}
 
-		data[i] = ret;
+		adc->scan.channels[i] = ret;
 		i++;
 	}
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
--- linux-ein-5.4.0.orig/drivers/iio/adc/max9611.c
+++ linux-ein-5.4.0/drivers/iio/adc/max9611.c
@@ -89,6 +89,12 @@
 #define MAX9611_TEMP_SCALE_NUM		1000000
 #define MAX9611_TEMP_SCALE_DIV		2083
 
+/*
+ * Conversion time is 2 ms (typically) at Ta=25 degreeC
+ * No maximum value is known, so play it safe.
+ */
+#define MAX9611_CONV_TIME_US_RANGE	3000, 3300
+
 struct max9611_dev {
 	struct device *dev;
 	struct i2c_client *i2c_client;
@@ -236,11 +242,9 @@
 		return ret;
 	}
 
-	/*
-	 * need a delay here to make register configuration
-	 * stabilize. 1 msec at least, from empirical testing.
-	 */
-	usleep_range(1000, 2000);
+	/* need a delay here to make register configuration stabilize. */
+
+	usleep_range(MAX9611_CONV_TIME_US_RANGE);
 
 	ret = i2c_smbus_read_word_swapped(max9611->i2c_client, reg_addr);
 	if (ret < 0) {
@@ -507,7 +511,7 @@
 			MAX9611_REG_CTRL2, 0);
 		return ret;
 	}
-	usleep_range(1000, 2000);
+	usleep_range(MAX9611_CONV_TIME_US_RANGE);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/iio/adc/mcp3422.c
+++ linux-ein-5.4.0/drivers/iio/adc/mcp3422.c
@@ -95,16 +95,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;
 }
 
@@ -137,6 +133,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;
@@ -144,12 +142,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-ein-5.4.0.orig/drivers/iio/adc/mcp3911.c
+++ linux-ein-5.4.0/drivers/iio/adc/mcp3911.c
@@ -38,8 +38,8 @@
 #define MCP3911_CHANNEL(x)		(MCP3911_REG_CHANNEL0 + x * 3)
 #define MCP3911_OFFCAL(x)		(MCP3911_REG_OFFCAL_CH0 + x * 6)
 
-/* Internal voltage reference in uV */
-#define MCP3911_INT_VREF_UV		1200000
+/* Internal voltage reference in mV */
+#define MCP3911_INT_VREF_MV		1200
 
 #define MCP3911_REG_READ(reg, id)	((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
 #define MCP3911_REG_WRITE(reg, id)	((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
@@ -111,6 +111,8 @@
 		if (ret)
 			goto out;
 
+		*val = sign_extend32(*val, 23);
+
 		ret = IIO_VAL_INT;
 		break;
 
@@ -135,11 +137,18 @@
 
 			*val = ret / 1000;
 		} else {
-			*val = MCP3911_INT_VREF_UV;
+			*val = MCP3911_INT_VREF_MV;
 		}
 
-		*val2 = 24;
-		ret = IIO_VAL_FRACTIONAL_LOG2;
+		/*
+		 * For 24bit Conversion
+		 * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
+		 * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
+		 */
+
+		/* val2 = (2^23 * 1.5) */
+		*val2 = 12582912;
+		ret = IIO_VAL_FRACTIONAL;
 		break;
 	}
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/men_z188_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/men_z188_adc.c
@@ -103,6 +103,7 @@
 	struct z188_adc *adc;
 	struct iio_dev *indio_dev;
 	struct resource *mem;
+	int ret;
 
 	indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
 	if (!indio_dev)
@@ -129,8 +130,14 @@
 	adc->mem = mem;
 	mcb_set_drvdata(dev, indio_dev);
 
-	return iio_device_register(indio_dev);
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto err_unmap;
 
+	return 0;
+
+err_unmap:
+	iounmap(adc->base);
 err:
 	mcb_release_mem(mem);
 	return -ENXIO;
--- linux-ein-5.4.0.orig/drivers/iio/adc/meson_saradc.c
+++ linux-ein-5.4.0/drivers/iio/adc/meson_saradc.c
@@ -71,7 +71,7 @@
 	#define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK	GENMASK(20, 18)
 	#define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK	GENMASK(17, 16)
 	#define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT		10
-	#define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH		5
+	#define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH		6
 	#define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK		GENMASK(9, 8)
 	#define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK		GENMASK(7, 0)
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/mt6577_auxadc.c
+++ linux-ein-5.4.0/drivers/iio/adc/mt6577_auxadc.c
@@ -9,9 +9,9 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/iopoll.h>
 #include <linux/io.h>
 #include <linux/iio/iio.h>
@@ -82,6 +82,10 @@
 	MT6577_AUXADC_CHANNEL(15),
 };
 
+/* For Voltage calculation */
+#define VOLTAGE_FULL_RANGE  1500	/* VA voltage */
+#define AUXADC_PRECISE      4096	/* 12 bits */
+
 static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
 {
 	return rawdata;
@@ -191,6 +195,10 @@
 		}
 		if (adc_dev->dev_comp->sample_data_cali)
 			*val = mt_auxadc_get_cali_data(*val, true);
+
+		/* Convert adc raw data to voltage: 0 - 1500 mV */
+		*val = *val * VOLTAGE_FULL_RANGE / AUXADC_PRECISE;
+
 		return IIO_VAL_INT;
 
 	default:
@@ -279,6 +287,8 @@
 		goto err_disable_clk;
 	}
 
+	adc_dev->dev_comp = device_get_match_data(&pdev->dev);
+
 	mutex_init(&adc_dev->lock);
 
 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
--- linux-ein-5.4.0.orig/drivers/iio/adc/mxs-lradc-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/mxs-lradc-adc.c
@@ -115,7 +115,8 @@
 	struct device		*dev;
 
 	void __iomem		*base;
-	u32			buffer[10];
+	/* Maximum of 8 channels + 8 byte ts */
+	u32			buffer[10] __aligned(8);
 	struct iio_trigger	*trig;
 	struct completion	completion;
 	spinlock_t		lock;
@@ -759,13 +760,13 @@
 
 	ret = mxs_lradc_adc_trigger_init(iio);
 	if (ret)
-		goto err_trig;
+		return ret;
 
 	ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
 					 &mxs_lradc_adc_trigger_handler,
 					 &mxs_lradc_adc_buffer_ops);
 	if (ret)
-		return ret;
+		goto err_trig;
 
 	adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc];
 
@@ -803,9 +804,9 @@
 
 err_dev:
 	mxs_lradc_adc_hw_stop(adc);
-	mxs_lradc_adc_trigger_remove(iio);
-err_trig:
 	iio_triggered_buffer_cleanup(iio);
+err_trig:
+	mxs_lradc_adc_trigger_remove(iio);
 	return ret;
 }
 
@@ -816,8 +817,8 @@
 
 	iio_device_unregister(iio);
 	mxs_lradc_adc_hw_stop(adc);
-	mxs_lradc_adc_trigger_remove(iio);
 	iio_triggered_buffer_cleanup(iio);
+	mxs_lradc_adc_trigger_remove(iio);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/iio/adc/palmas_gpadc.c
+++ linux-ein-5.4.0/drivers/iio/adc/palmas_gpadc.c
@@ -630,7 +630,7 @@
 
 static int palmas_gpadc_remove(struct platform_device *pdev)
 {
-	struct iio_dev *indio_dev = dev_to_iio_dev(&pdev->dev);
+	struct iio_dev *indio_dev = dev_get_drvdata(&pdev->dev);
 	struct palmas_gpadc *adc = iio_priv(indio_dev);
 
 	if (adc->wakeup1_enable || adc->wakeup2_enable)
@@ -656,8 +656,8 @@
 
 	adc_period = adc->auto_conversion_period;
 	for (i = 0; i < 16; ++i) {
-		if (((1000 * (1 << i)) / 32) < adc_period)
-			continue;
+		if (((1000 * (1 << i)) / 32) >= adc_period)
+			break;
 	}
 	if (i > 0)
 		i--;
--- linux-ein-5.4.0.orig/drivers/iio/adc/qcom-spmi-adc5.c
+++ linux-ein-5.4.0/drivers/iio/adc/qcom-spmi-adc5.c
@@ -786,7 +786,7 @@
 
 static struct platform_driver adc5_driver = {
 	.driver = {
-		.name = "qcom-spmi-adc5.c",
+		.name = "qcom-spmi-adc5",
 		.of_match_table = adc5_match_table,
 	},
 	.probe = adc5_probe,
--- linux-ein-5.4.0.orig/drivers/iio/adc/qcom-spmi-vadc.c
+++ linux-ein-5.4.0/drivers/iio/adc/qcom-spmi-vadc.c
@@ -598,7 +598,7 @@
 	VADC_CHAN_NO_SCALE(P_MUX16_1_3, 1)
 
 	VADC_CHAN_NO_SCALE(LR_MUX1_BAT_THERM, 0)
-	VADC_CHAN_NO_SCALE(LR_MUX2_BAT_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0, SCALE_DEFAULT)
 	VADC_CHAN_NO_SCALE(LR_MUX3_XO_THERM, 0)
 	VADC_CHAN_NO_SCALE(LR_MUX4_AMUX_THM1, 0)
 	VADC_CHAN_NO_SCALE(LR_MUX5_AMUX_THM2, 0)
--- linux-ein-5.4.0.orig/drivers/iio/adc/rcar-gyroadc.c
+++ linux-ein-5.4.0/drivers/iio/adc/rcar-gyroadc.c
@@ -357,7 +357,7 @@
 			num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3);
 			break;
 		default:
-			return -EINVAL;
+			goto err_e_inval;
 		}
 
 		/*
@@ -374,7 +374,7 @@
 				dev_err(dev,
 					"Failed to get child reg property of ADC \"%pOFn\".\n",
 					child);
-				return ret;
+				goto err_of_node_put;
 			}
 
 			/* Channel number is too high. */
@@ -382,7 +382,7 @@
 				dev_err(dev,
 					"Only %i channels supported with %pOFn, but reg = <%i>.\n",
 					num_channels, child, reg);
-				return -EINVAL;
+				goto err_e_inval;
 			}
 		}
 
@@ -391,7 +391,7 @@
 			dev_err(dev,
 				"Channel %i uses different ADC mode than the rest.\n",
 				reg);
-			return -EINVAL;
+			goto err_e_inval;
 		}
 
 		/* Channel is valid, grab the regulator. */
@@ -401,7 +401,8 @@
 		if (IS_ERR(vref)) {
 			dev_dbg(dev, "Channel %i 'vref' supply not connected.\n",
 				reg);
-			return PTR_ERR(vref);
+			ret = PTR_ERR(vref);
+			goto err_of_node_put;
 		}
 
 		priv->vref[reg] = vref;
@@ -425,8 +426,10 @@
 		 * attached to the GyroADC at a time, so if we found it,
 		 * we can stop parsing here.
 		 */
-		if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
+		if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) {
+			of_node_put(child);
 			break;
+		}
 	}
 
 	if (first) {
@@ -435,6 +438,12 @@
 	}
 
 	return 0;
+
+err_e_inval:
+	ret = -EINVAL;
+err_of_node_put:
+	of_node_put(child);
+	return ret;
 }
 
 static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev)
--- linux-ein-5.4.0.orig/drivers/iio/adc/rockchip_saradc.c
+++ linux-ein-5.4.0/drivers/iio/adc/rockchip_saradc.c
@@ -372,7 +372,7 @@
 
 	ret = clk_prepare_enable(info->clk);
 	if (ret)
-		return ret;
+		clk_disable_unprepare(info->pclk);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/iio/adc/sc27xx_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/sc27xx_adc.c
@@ -36,8 +36,8 @@
 
 /* Bits and mask definition for SC27XX_ADC_CH_CFG register */
 #define SC27XX_ADC_CHN_ID_MASK		GENMASK(4, 0)
-#define SC27XX_ADC_SCALE_MASK		GENMASK(10, 8)
-#define SC27XX_ADC_SCALE_SHIFT		8
+#define SC27XX_ADC_SCALE_MASK		GENMASK(10, 9)
+#define SC27XX_ADC_SCALE_SHIFT		9
 
 /* Bits definitions for SC27XX_ADC_INT_EN registers */
 #define SC27XX_ADC_IRQ_EN		BIT(0)
@@ -103,14 +103,14 @@
 	100, 341,
 };
 
-static const struct sc27xx_adc_linear_graph big_scale_graph_calib = {
-	4200, 856,
-	3600, 733,
+static const struct sc27xx_adc_linear_graph sc2731_big_scale_graph_calib = {
+	4200, 850,
+	3600, 728,
 };
 
-static const struct sc27xx_adc_linear_graph small_scale_graph_calib = {
-	1000, 833,
-	100, 80,
+static const struct sc27xx_adc_linear_graph sc2731_small_scale_graph_calib = {
+	1000, 838,
+	100, 84,
 };
 
 static int sc27xx_adc_get_calib_data(u32 calib_data, int calib_adc)
@@ -130,11 +130,11 @@
 	size_t len;
 
 	if (big_scale) {
-		calib_graph = &big_scale_graph_calib;
+		calib_graph = &sc2731_big_scale_graph_calib;
 		graph = &big_scale_graph;
 		cell_name = "big_scale_calib";
 	} else {
-		calib_graph = &small_scale_graph_calib;
+		calib_graph = &sc2731_small_scale_graph_calib;
 		graph = &small_scale_graph;
 		cell_name = "small_scale_calib";
 	}
--- linux-ein-5.4.0.orig/drivers/iio/adc/stm32-adc-core.c
+++ linux-ein-5.4.0/drivers/iio/adc/stm32-adc-core.c
@@ -65,12 +65,14 @@
  * @clk_sel:	clock selection routine
  * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
  * @has_syscfg: SYSCFG capability flags
+ * @num_irqs:	number of interrupt lines
  */
 struct stm32_adc_priv_cfg {
 	const struct stm32_adc_common_regs *regs;
 	int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
 	u32 max_clk_rate_hz;
 	unsigned int has_syscfg;
+	unsigned int num_irqs;
 };
 
 /**
@@ -372,21 +374,15 @@
 	struct device_node *np = pdev->dev.of_node;
 	unsigned int i;
 
-	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
+	/*
+	 * Interrupt(s) must be provided, depending on the compatible:
+	 * - stm32f4/h7 shares a common interrupt line.
+	 * - stm32mp1, has one line per ADC
+	 */
+	for (i = 0; i < priv->cfg->num_irqs; i++) {
 		priv->irq[i] = platform_get_irq(pdev, i);
-		if (priv->irq[i] < 0) {
-			/*
-			 * At least one interrupt must be provided, make others
-			 * optional:
-			 * - stm32f4/h7 shares a common interrupt.
-			 * - stm32mp1, has one line per ADC (either for ADC1,
-			 *   ADC2 or both).
-			 */
-			if (i && priv->irq[i] == -ENXIO)
-				continue;
-
+		if (priv->irq[i] < 0)
 			return priv->irq[i];
-		}
 	}
 
 	priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
@@ -397,9 +393,7 @@
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
-		if (priv->irq[i] < 0)
-			continue;
+	for (i = 0; i < priv->cfg->num_irqs; i++) {
 		irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler);
 		irq_set_handler_data(priv->irq[i], priv);
 	}
@@ -417,11 +411,8 @@
 		irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
 	irq_domain_remove(priv->domain);
 
-	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
-		if (priv->irq[i] < 0)
-			continue;
+	for (i = 0; i < priv->cfg->num_irqs; i++)
 		irq_set_chained_handler(priv->irq[i], NULL);
-	}
 }
 
 static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv,
@@ -789,6 +780,13 @@
 {
 	return stm32_adc_core_hw_start(dev);
 }
+
+static int stm32_adc_core_runtime_idle(struct device *dev)
+{
+	pm_runtime_mark_last_busy(dev);
+
+	return 0;
+}
 #endif
 
 static const struct dev_pm_ops stm32_adc_core_pm_ops = {
@@ -796,13 +794,14 @@
 				pm_runtime_force_resume)
 	SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
 			   stm32_adc_core_runtime_resume,
-			   NULL)
+			   stm32_adc_core_runtime_idle)
 };
 
 static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
 	.regs = &stm32f4_adc_common_regs,
 	.clk_sel = stm32f4_adc_clk_sel,
 	.max_clk_rate_hz = 36000000,
+	.num_irqs = 1,
 };
 
 static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
@@ -810,13 +809,15 @@
 	.clk_sel = stm32h7_adc_clk_sel,
 	.max_clk_rate_hz = 36000000,
 	.has_syscfg = HAS_VBOOSTER,
+	.num_irqs = 1,
 };
 
 static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
 	.regs = &stm32h7_adc_common_regs,
 	.clk_sel = stm32h7_adc_clk_sel,
-	.max_clk_rate_hz = 40000000,
+	.max_clk_rate_hz = 36000000,
 	.has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD,
+	.num_irqs = 2,
 };
 
 static const struct of_device_id stm32_adc_of_match[] = {
--- linux-ein-5.4.0.orig/drivers/iio/adc/stm32-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/stm32-adc.c
@@ -933,6 +933,7 @@
 
 static void stm32h7_adc_unprepare(struct stm32_adc *adc)
 {
+	stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
 	stm32h7_adc_disable(adc);
 	stm32h7_adc_enter_pwr_down(adc);
 }
@@ -1367,8 +1368,30 @@
 static void stm32_adc_dma_buffer_done(void *data)
 {
 	struct iio_dev *indio_dev = data;
+	struct stm32_adc *adc = iio_priv(indio_dev);
+	int residue = stm32_adc_dma_residue(adc);
+
+	/*
+	 * In DMA mode the trigger services of IIO are not used
+	 * (e.g. no call to iio_trigger_poll).
+	 * Calling irq handler associated to the hardware trigger is not
+	 * relevant as the conversions have already been done. Data
+	 * transfers are performed directly in DMA callback instead.
+	 * This implementation avoids to call trigger irq handler that
+	 * may sleep, in an atomic context (DMA irq handler context).
+	 */
+	dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
+
+	while (residue >= indio_dev->scan_bytes) {
+		u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi];
 
-	iio_trigger_poll_chained(indio_dev->trig);
+		iio_push_to_buffers(indio_dev, buffer);
+
+		residue -= indio_dev->scan_bytes;
+		adc->bufi += indio_dev->scan_bytes;
+		if (adc->bufi >= adc->rx_buf_sz)
+			adc->bufi = 0;
+	}
 }
 
 static int stm32_adc_dma_start(struct iio_dev *indio_dev)
@@ -1735,15 +1758,27 @@
 	return 0;
 }
 
-static int stm32_adc_dma_request(struct iio_dev *indio_dev)
+static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
 {
 	struct stm32_adc *adc = iio_priv(indio_dev);
 	struct dma_slave_config config;
 	int ret;
 
-	adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
-	if (!adc->dma_chan)
+	adc->dma_chan = dma_request_chan(dev, "rx");
+	if (IS_ERR(adc->dma_chan)) {
+		ret = PTR_ERR(adc->dma_chan);
+		if (ret != -ENODEV) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev,
+					"DMA channel request failed with %d\n",
+					ret);
+			return ret;
+		}
+
+		/* DMA is optional: fall back to IRQ mode */
+		adc->dma_chan = NULL;
 		return 0;
+	}
 
 	adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
 					 STM32_DMA_BUFFER_SIZE,
@@ -1778,6 +1813,7 @@
 {
 	struct iio_dev *indio_dev;
 	struct device *dev = &pdev->dev;
+	irqreturn_t (*handler)(int irq, void *p) = NULL;
 	struct stm32_adc *adc;
 	int ret;
 
@@ -1839,13 +1875,15 @@
 	if (ret < 0)
 		return ret;
 
-	ret = stm32_adc_dma_request(indio_dev);
+	ret = stm32_adc_dma_request(dev, indio_dev);
 	if (ret < 0)
 		return ret;
 
+	if (!adc->dma_chan)
+		handler = &stm32_adc_trigger_handler;
+
 	ret = iio_triggered_buffer_setup(indio_dev,
-					 &iio_pollfunc_store_time,
-					 &stm32_adc_trigger_handler,
+					 &iio_pollfunc_store_time, handler,
 					 &stm32_adc_buffer_setup_ops);
 	if (ret) {
 		dev_err(&pdev->dev, "buffer setup failed\n");
--- linux-ein-5.4.0.orig/drivers/iio/adc/stm32-dfsdm-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -62,7 +62,7 @@
 
 struct stm32_dfsdm_dev_data {
 	int type;
-	int (*init)(struct iio_dev *indio_dev);
+	int (*init)(struct device *dev, struct iio_dev *indio_dev);
 	unsigned int num_channels;
 	const struct regmap_config *regmap_cfg;
 };
@@ -842,31 +842,6 @@
 	}
 }
 
-static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
-{
-	struct iio_poll_func *pf = p;
-	struct iio_dev *indio_dev = pf->indio_dev;
-	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
-	int available = stm32_dfsdm_adc_dma_residue(adc);
-
-	while (available >= indio_dev->scan_bytes) {
-		s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
-
-		stm32_dfsdm_process_data(adc, buffer);
-
-		iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-						   pf->timestamp);
-		available -= indio_dev->scan_bytes;
-		adc->bufi += indio_dev->scan_bytes;
-		if (adc->bufi >= adc->buf_sz)
-			adc->bufi = 0;
-	}
-
-	iio_trigger_notify_done(indio_dev->trig);
-
-	return IRQ_HANDLED;
-}
-
 static void stm32_dfsdm_dma_buffer_done(void *data)
 {
 	struct iio_dev *indio_dev = data;
@@ -874,11 +849,6 @@
 	int available = stm32_dfsdm_adc_dma_residue(adc);
 	size_t old_pos;
 
-	if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) {
-		iio_trigger_poll_chained(indio_dev->trig);
-		return;
-	}
-
 	/*
 	 * FIXME: In Kernel interface does not support cyclic DMA buffer,and
 	 * offers only an interface to push data samples per samples.
@@ -906,7 +876,15 @@
 			adc->bufi = 0;
 			old_pos = 0;
 		}
-		/* regular iio buffer without trigger */
+		/*
+		 * In DMA mode the trigger services of IIO are not used
+		 * (e.g. no call to iio_trigger_poll).
+		 * Calling irq handler associated to the hardware trigger is not
+		 * relevant as the conversions have already been done. Data
+		 * transfers are performed directly in DMA callback instead.
+		 * This implementation avoids to call trigger irq handler that
+		 * may sleep, in an atomic context (DMA irq handler context).
+		 */
 		if (adc->dev_data->type == DFSDM_IIO)
 			iio_push_to_buffers(indio_dev, buffer);
 	}
@@ -1204,6 +1182,8 @@
 
 	stm32_dfsdm_stop_conv(adc);
 
+	stm32_dfsdm_process_data(adc, res);
+
 stop_dfsdm:
 	stm32_dfsdm_stop_dfsdm(adc->dfsdm);
 
@@ -1379,13 +1359,18 @@
 	}
 }
 
-static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev)
+static int stm32_dfsdm_dma_request(struct device *dev,
+				   struct iio_dev *indio_dev)
 {
 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
 
-	adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
-	if (!adc->dma_chan)
-		return -EINVAL;
+	adc->dma_chan = dma_request_chan(dev, "rx");
+	if (IS_ERR(adc->dma_chan)) {
+		int ret = PTR_ERR(adc->dma_chan);
+
+		adc->dma_chan = NULL;
+		return ret;
+	}
 
 	adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
 					 DFSDM_DMA_BUFFER_SIZE,
@@ -1435,7 +1420,7 @@
 					  &adc->dfsdm->ch_list[ch->channel]);
 }
 
-static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev)
+static int stm32_dfsdm_audio_init(struct device *dev, struct iio_dev *indio_dev)
 {
 	struct iio_chan_spec *ch;
 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
@@ -1462,10 +1447,10 @@
 	indio_dev->num_channels = 1;
 	indio_dev->channels = ch;
 
-	return stm32_dfsdm_dma_request(indio_dev);
+	return stm32_dfsdm_dma_request(dev, indio_dev);
 }
 
-static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
+static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
 {
 	struct iio_chan_spec *ch;
 	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
@@ -1509,14 +1494,22 @@
 	init_completion(&adc->completion);
 
 	/* Optionally request DMA */
-	if (stm32_dfsdm_dma_request(indio_dev)) {
-		dev_dbg(&indio_dev->dev, "No DMA support\n");
+	ret = stm32_dfsdm_dma_request(dev, indio_dev);
+	if (ret) {
+		if (ret != -ENODEV) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev,
+					"DMA channel request failed with %d\n",
+					ret);
+			return ret;
+		}
+
+		dev_dbg(dev, "No DMA support\n");
 		return 0;
 	}
 
 	ret = iio_triggered_buffer_setup(indio_dev,
-					 &iio_pollfunc_store_time,
-					 &stm32_dfsdm_adc_trigger_handler,
+					 &iio_pollfunc_store_time, NULL,
 					 &stm32_dfsdm_buffer_setup_ops);
 	if (ret) {
 		stm32_dfsdm_dma_release(indio_dev);
@@ -1551,6 +1544,7 @@
 	},
 	{}
 };
+MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match);
 
 static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
 {
@@ -1624,7 +1618,7 @@
 		adc->dfsdm->fl_list[adc->fl_id].sync_mode = val;
 
 	adc->dev_data = dev_data;
-	ret = dev_data->init(iio);
+	ret = dev_data->init(dev, iio);
 	if (ret < 0)
 		return ret;
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/stmpe-adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/stmpe-adc.c
@@ -61,7 +61,7 @@
 static int stmpe_read_voltage(struct stmpe_adc *info,
 		struct iio_chan_spec const *chan, int *val)
 {
-	long ret;
+	unsigned long ret;
 
 	mutex_lock(&info->lock);
 
@@ -79,7 +79,7 @@
 
 	ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
 
-	if (ret <= 0) {
+	if (ret == 0) {
 		stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
 				STMPE_ADC_CH(info->channel));
 		mutex_unlock(&info->lock);
@@ -96,7 +96,7 @@
 static int stmpe_read_temp(struct stmpe_adc *info,
 		struct iio_chan_spec const *chan, int *val)
 {
-	long ret;
+	unsigned long ret;
 
 	mutex_lock(&info->lock);
 
@@ -114,7 +114,7 @@
 
 	ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
 
-	if (ret <= 0) {
+	if (ret == 0) {
 		mutex_unlock(&info->lock);
 		return -ETIMEDOUT;
 	}
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-adc081c.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-adc081c.c
@@ -33,6 +33,12 @@
 
 	/* 8, 10 or 12 */
 	int bits;
+
+	/* Ensure natural alignment of buffer elements */
+	struct {
+		u16 channel;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 #define REG_CONV_RES 0x00
@@ -128,14 +134,13 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc081c *data = iio_priv(indio_dev);
-	u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */
 	int ret;
 
 	ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);
 	if (ret < 0)
 		goto out;
-	buf[0] = ret;
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	data->scan.channel = ret;
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 out:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-adc0832.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-adc0832.c
@@ -28,6 +28,12 @@
 	struct regulator *reg;
 	struct mutex lock;
 	u8 mux_bits;
+	/*
+	 * Max size needed: 16x 1 byte ADC data + 8 bytes timestamp
+	 * May be shorter if not all channels are enabled subject
+	 * to the timestamp remaining 8 byte aligned.
+	 */
+	u8 data[24] __aligned(8);
 
 	u8 tx_buf[2] ____cacheline_aligned;
 	u8 rx_buf[2];
@@ -199,7 +205,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc0832 *adc = iio_priv(indio_dev);
-	u8 data[24] = { }; /* 16x 1 byte ADC data + 8 bytes timestamp */
 	int scan_index;
 	int i = 0;
 
@@ -217,10 +222,10 @@
 			goto out;
 		}
 
-		data[i] = ret;
+		adc->data[i] = ret;
 		i++;
 	}
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-adc084s021.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-adc084s021.c
@@ -25,6 +25,11 @@
 	struct spi_transfer spi_trans;
 	struct regulator *reg;
 	struct mutex lock;
+	/* Buffer used to align data */
+	struct {
+		__be16 channels[4];
+		s64 ts __aligned(8);
+	} scan;
 	/*
 	 * DMA (thus cache coherency maintenance) requires the
 	 * transfer buffers to live in their own cache line.
@@ -140,14 +145,13 @@
 	struct iio_poll_func *pf = pollfunc;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc084s021 *adc = iio_priv(indio_dev);
-	__be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */
 
 	mutex_lock(&adc->lock);
 
-	if (adc084s021_adc_conversion(adc, &data) < 0)
+	if (adc084s021_adc_conversion(adc, adc->scan.channels) < 0)
 		dev_err(&adc->spi->dev, "Failed to read data\n");
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
 					   iio_get_time_ns(indio_dev));
 	mutex_unlock(&adc->lock);
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-adc12138.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-adc12138.c
@@ -47,6 +47,12 @@
 	struct completion complete;
 	/* The number of cclk periods for the S/H's acquisition time */
 	unsigned int acquisition_time;
+	/*
+	 * Maximum size needed: 16x 2 bytes ADC data + 8 bytes timestamp.
+	 * Less may be need if not all channels are enabled, as long as
+	 * the 8 byte alignment of the timestamp is maintained.
+	 */
+	__be16 data[20] __aligned(8);
 
 	u8 tx_buf[2] ____cacheline_aligned;
 	u8 rx_buf[2];
@@ -329,7 +335,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adc12138 *adc = iio_priv(indio_dev);
-	__be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */
 	__be16 trash;
 	int ret;
 	int scan_index;
@@ -345,7 +350,7 @@
 		reinit_completion(&adc->complete);
 
 		ret = adc12138_start_and_read_conv(adc, scan_chan,
-						   i ? &data[i - 1] : &trash);
+					i ? &adc->data[i - 1] : &trash);
 		if (ret) {
 			dev_warn(&adc->spi->dev,
 				 "failed to start conversion\n");
@@ -362,7 +367,7 @@
 	}
 
 	if (i) {
-		ret = adc12138_read_conv_data(adc, &data[i - 1]);
+		ret = adc12138_read_conv_data(adc, &adc->data[i - 1]);
 		if (ret) {
 			dev_warn(&adc->spi->dev,
 				 "failed to get conversion data\n");
@@ -370,7 +375,7 @@
 		}
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
 					   iio_get_time_ns(indio_dev));
 out:
 	mutex_unlock(&adc->lock);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-adc128s052.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-adc128s052.c
@@ -172,7 +172,13 @@
 	mutex_init(&adc->lock);
 
 	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto err_disable_regulator;
 
+	return 0;
+
+err_disable_regulator:
+	regulator_disable(adc->reg);
 	return ret;
 }
 
@@ -188,13 +194,13 @@
 }
 
 static const struct of_device_id adc128_of_match[] = {
-	{ .compatible = "ti,adc128s052", },
-	{ .compatible = "ti,adc122s021", },
-	{ .compatible = "ti,adc122s051", },
-	{ .compatible = "ti,adc122s101", },
-	{ .compatible = "ti,adc124s021", },
-	{ .compatible = "ti,adc124s051", },
-	{ .compatible = "ti,adc124s101", },
+	{ .compatible = "ti,adc128s052", .data = (void*)0L, },
+	{ .compatible = "ti,adc122s021", .data = (void*)1L, },
+	{ .compatible = "ti,adc122s051", .data = (void*)1L, },
+	{ .compatible = "ti,adc122s101", .data = (void*)1L, },
+	{ .compatible = "ti,adc124s021", .data = (void*)2L, },
+	{ .compatible = "ti,adc124s051", .data = (void*)2L, },
+	{ .compatible = "ti,adc124s101", .data = (void*)2L, },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, adc128_of_match);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-ads1015.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-ads1015.c
@@ -309,6 +309,7 @@
 	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
 };
 
+#ifdef CONFIG_PM
 static int ads1015_set_power_state(struct ads1015_data *data, bool on)
 {
 	int ret;
@@ -326,6 +327,15 @@
 	return ret < 0 ? ret : 0;
 }
 
+#else /* !CONFIG_PM */
+
+static int ads1015_set_power_state(struct ads1015_data *data, bool on)
+{
+	return 0;
+}
+
+#endif /* !CONFIG_PM */
+
 static
 int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
 {
@@ -378,10 +388,14 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ads1015_data *data = iio_priv(indio_dev);
-	s16 buf[8]; /* 1x s16 ADC val + 3x s16 padding +  4x s16 timestamp */
+	/* Ensure natural alignment of timestamp */
+	struct {
+		s16 chan;
+		s64 timestamp __aligned(8);
+	} scan;
 	int chan, ret, res;
 
-	memset(buf, 0, sizeof(buf));
+	memset(&scan, 0, sizeof(scan));
 
 	mutex_lock(&data->lock);
 	chan = find_first_bit(indio_dev->active_scan_mask,
@@ -392,10 +406,10 @@
 		goto err;
 	}
 
-	buf[0] = res;
+	scan.chan = res;
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-ads124s08.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-ads124s08.c
@@ -97,6 +97,14 @@
 	struct gpio_desc *reset_gpio;
 	struct spi_device *spi;
 	struct mutex lock;
+	/*
+	 * Used to correctly align data.
+	 * Ensure timestamp is naturally aligned.
+	 * Note that the full buffer length may not be needed if not
+	 * all channels are enabled, as long as the alignment of the
+	 * timestamp is maintained.
+	 */
+	u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u32)] __aligned(8);
 	u8 data[5] ____cacheline_aligned;
 };
 
@@ -270,7 +278,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ads124s_private *priv = iio_priv(indio_dev);
-	u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
 	int scan_index, j = 0;
 	int ret;
 
@@ -285,7 +292,7 @@
 		if (ret)
 			dev_err(&priv->spi->dev, "Start ADC conversions failed\n");
 
-		buffer[j] = ads124s_read(indio_dev, scan_index);
+		priv->buffer[j] = ads124s_read(indio_dev, scan_index);
 		ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
 		if (ret)
 			dev_err(&priv->spi->dev, "Stop ADC conversions failed\n");
@@ -293,7 +300,7 @@
 		j++;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,
 			pf->timestamp);
 
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-ads7950.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-ads7950.c
@@ -569,7 +569,6 @@
 	st->ring_xfer.tx_buf = &st->tx_buf[0];
 	st->ring_xfer.rx_buf = &st->rx_buf[0];
 	/* len will be set later */
-	st->ring_xfer.cs_change = true;
 
 	spi_message_add_tail(&st->ring_xfer, &st->ring_msg);
 
@@ -636,6 +635,7 @@
 	st->chip.label = dev_name(&st->spi->dev);
 	st->chip.parent = &st->spi->dev;
 	st->chip.owner = THIS_MODULE;
+	st->chip.can_sleep = true;
 	st->chip.base = -1;
 	st->chip.ngpio = TI_ADS7950_NUM_GPIOS;
 	st->chip.get_direction = ti_ads7950_get_direction;
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-ads8344.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-ads8344.c
@@ -29,19 +29,20 @@
 	struct mutex lock;
 
 	u8 tx_buf ____cacheline_aligned;
-	u16 rx_buf;
+	u8 rx_buf[3];
 };
 
-#define ADS8344_VOLTAGE_CHANNEL(chan, si)				\
+#define ADS8344_VOLTAGE_CHANNEL(chan, addr)				\
 	{								\
 		.type = IIO_VOLTAGE,					\
 		.indexed = 1,						\
 		.channel = chan,					\
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+		.address = addr,					\
 	}
 
-#define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si)			\
+#define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, addr)		\
 	{								\
 		.type = IIO_VOLTAGE,					\
 		.indexed = 1,						\
@@ -50,6 +51,7 @@
 		.differential = 1,					\
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+		.address = addr,					\
 	}
 
 static const struct iio_chan_spec ads8344_channels[] = {
@@ -89,11 +91,11 @@
 
 	udelay(9);
 
-	ret = spi_read(spi, &adc->rx_buf, 2);
+	ret = spi_read(spi, adc->rx_buf, sizeof(adc->rx_buf));
 	if (ret)
 		return ret;
 
-	return adc->rx_buf;
+	return adc->rx_buf[0] << 9 | adc->rx_buf[1] << 1 | adc->rx_buf[2] >> 7;
 }
 
 static int ads8344_read_raw(struct iio_dev *iio,
@@ -105,7 +107,7 @@
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
 		mutex_lock(&adc->lock);
-		*value = ads8344_adc_conversion(adc, channel->scan_index,
+		*value = ads8344_adc_conversion(adc, channel->address,
 						channel->differential);
 		mutex_unlock(&adc->lock);
 		if (*value < 0)
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti-ads8688.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti-ads8688.c
@@ -383,7 +383,8 @@
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
-	u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
+	/* Ensure naturally aligned timestamp */
+	u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);
 	int i, j = 0;
 
 	for (i = 0; i < indio_dev->masklength; i++) {
--- linux-ein-5.4.0.orig/drivers/iio/adc/ti_am335x_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/ti_am335x_adc.c
@@ -656,8 +656,10 @@
 	platform_set_drvdata(pdev, indio_dev);
 
 	err = tiadc_request_dma(pdev, adc_dev);
-	if (err && err == -EPROBE_DEFER)
+	if (err && err != -ENODEV) {
+		dev_err_probe(&pdev->dev, err, "DMA request failed\n");
 		goto err_dma;
+	}
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/iio/adc/twl6030-gpadc.c
+++ linux-ein-5.4.0/drivers/iio/adc/twl6030-gpadc.c
@@ -57,6 +57,18 @@
 #define TWL6030_GPADCS				BIT(1)
 #define TWL6030_GPADCR				BIT(0)
 
+#define USB_VBUS_CTRL_SET			0x04
+#define USB_ID_CTRL_SET				0x06
+
+#define TWL6030_MISC1				0xE4
+#define VBUS_MEAS				0x01
+#define ID_MEAS					0x01
+
+#define VAC_MEAS                0x04
+#define VBAT_MEAS               0x02
+#define BB_MEAS                 0x01
+
+
 /**
  * struct twl6030_chnl_calib - channel calibration
  * @gain:		slope coefficient for ideal curve
@@ -911,6 +923,8 @@
 	ret = devm_request_threaded_irq(dev, irq, NULL,
 				twl6030_gpadc_irq_handler,
 				IRQF_ONESHOT, "twl6030_gpadc", indio_dev);
+	if (ret)
+		return ret;
 
 	ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
 	if (ret < 0) {
@@ -925,6 +939,26 @@
 		return ret;
 	}
 
+	ret = twl_i2c_write_u8(TWL_MODULE_USB, VBUS_MEAS, USB_VBUS_CTRL_SET);
+	if (ret < 0) {
+		dev_err(dev, "failed to wire up inputs\n");
+		return ret;
+	}
+
+	ret = twl_i2c_write_u8(TWL_MODULE_USB, ID_MEAS, USB_ID_CTRL_SET);
+	if (ret < 0) {
+		dev_err(dev, "failed to wire up inputs\n");
+		return ret;
+	}
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID0,
+				VBAT_MEAS | BB_MEAS | VAC_MEAS,
+				TWL6030_MISC1);
+	if (ret < 0) {
+		dev_err(dev, "failed to wire up inputs\n");
+		return ret;
+	}
+
 	indio_dev->name = DRIVER_NAME;
 	indio_dev->dev.parent = dev;
 	indio_dev->info = &twl6030_gpadc_iio_info;
--- linux-ein-5.4.0.orig/drivers/iio/adc/vf610_adc.c
+++ linux-ein-5.4.0/drivers/iio/adc/vf610_adc.c
@@ -167,7 +167,11 @@
 	u32 sample_freq_avail[5];
 
 	struct completion completion;
-	u16 buffer[8];
+	/* Ensure the timestamp is naturally aligned */
+	struct {
+		u16 chan;
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
@@ -579,9 +583,9 @@
 	if (coco & VF610_ADC_HS_COCO0) {
 		info->value = vf610_adc_read_data(info);
 		if (iio_buffer_enabled(indio_dev)) {
-			info->buffer[0] = info->value;
+			info->scan.chan = info->value;
 			iio_push_to_buffers_with_timestamp(indio_dev,
-					info->buffer,
+					&info->scan,
 					iio_get_time_ns(indio_dev));
 			iio_trigger_notify_done(indio_dev->trig);
 		} else
--- linux-ein-5.4.0.orig/drivers/iio/adc/xilinx-xadc-core.c
+++ linux-ein-5.4.0/drivers/iio/adc/xilinx-xadc-core.c
@@ -102,6 +102,16 @@
 
 #define XADC_FLAGS_BUFFERED BIT(0)
 
+/*
+ * The XADC hardware supports a samplerate of up to 1MSPS. Unfortunately it does
+ * not have a hardware FIFO. Which means an interrupt is generated for each
+ * conversion sequence. At 1MSPS sample rate the CPU in ZYNQ7000 is completely
+ * overloaded by the interrupts that it soft-lockups. For this reason the driver
+ * limits the maximum samplerate 150kSPS. At this rate the CPU is fairly busy,
+ * but still responsive.
+ */
+#define XADC_MAX_SAMPLERATE 150000
+
 static void xadc_write_reg(struct xadc *xadc, unsigned int reg,
 	uint32_t val)
 {
@@ -674,7 +684,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
@@ -722,13 +732,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;
 	}
 
@@ -797,6 +808,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;
@@ -823,11 +844,27 @@
 	.postdisable = &xadc_postdisable,
 };
 
+static int xadc_read_samplerate(struct xadc *xadc)
+{
+	unsigned int div;
+	uint16_t val16;
+	int ret;
+
+	ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16);
+	if (ret)
+		return ret;
+
+	div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET;
+	if (div < 2)
+		div = 2;
+
+	return xadc_get_dclk_rate(xadc) / div / 26;
+}
+
 static int xadc_read_raw(struct iio_dev *indio_dev,
 	struct iio_chan_spec const *chan, int *val, int *val2, long info)
 {
 	struct xadc *xadc = iio_priv(indio_dev);
-	unsigned int div;
 	uint16_t val16;
 	int ret;
 
@@ -880,41 +917,31 @@
 		*val = -((273150 << 12) / 503975);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16);
-		if (ret)
+		ret = xadc_read_samplerate(xadc);
+		if (ret < 0)
 			return ret;
 
-		div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET;
-		if (div < 2)
-			div = 2;
-
-		*val = xadc_get_dclk_rate(xadc) / div / 26;
-
+		*val = ret;
 		return IIO_VAL_INT;
 	default:
 		return -EINVAL;
 	}
 }
 
-static int xadc_write_raw(struct iio_dev *indio_dev,
-	struct iio_chan_spec const *chan, int val, int val2, long info)
+static int xadc_write_samplerate(struct xadc *xadc, int val)
 {
-	struct xadc *xadc = iio_priv(indio_dev);
 	unsigned long clk_rate = xadc_get_dclk_rate(xadc);
 	unsigned int div;
 
 	if (!clk_rate)
 		return -EINVAL;
 
-	if (info != IIO_CHAN_INFO_SAMP_FREQ)
-		return -EINVAL;
-
 	if (val <= 0)
 		return -EINVAL;
 
 	/* Max. 150 kSPS */
-	if (val > 150000)
-		val = 150000;
+	if (val > XADC_MAX_SAMPLERATE)
+		val = XADC_MAX_SAMPLERATE;
 
 	val *= 26;
 
@@ -927,7 +954,7 @@
 	 * limit.
 	 */
 	div = clk_rate / val;
-	if (clk_rate / div / 26 > 150000)
+	if (clk_rate / div / 26 > XADC_MAX_SAMPLERATE)
 		div++;
 	if (div < 2)
 		div = 2;
@@ -938,6 +965,17 @@
 		div << XADC_CONF2_DIV_OFFSET);
 }
 
+static int xadc_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+	struct xadc *xadc = iio_priv(indio_dev);
+
+	if (info != IIO_CHAN_INFO_SAMP_FREQ)
+		return -EINVAL;
+
+	return xadc_write_samplerate(xadc, val);
+}
+
 static const struct iio_event_spec xadc_temp_events[] = {
 	{
 		.type = IIO_EV_TYPE_THRESH,
@@ -1225,6 +1263,21 @@
 	if (ret)
 		goto err_free_samplerate_trigger;
 
+	/*
+	 * Make sure not to exceed the maximum samplerate since otherwise the
+	 * resulting interrupt storm will soft-lock the system.
+	 */
+	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
+		ret = xadc_read_samplerate(xadc);
+		if (ret < 0)
+			goto err_free_samplerate_trigger;
+		if (ret > XADC_MAX_SAMPLERATE) {
+			ret = xadc_write_samplerate(xadc, XADC_MAX_SAMPLERATE);
+			if (ret < 0)
+				goto err_free_samplerate_trigger;
+		}
+	}
+
 	ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0,
 			dev_name(&pdev->dev), indio_dev);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/iio/addac/Kconfig
+++ linux-ein-5.4.0/drivers/iio/addac/Kconfig
@@ -0,0 +1,24 @@
+#
+# ADC DAC drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Analog to digital and digital to analog converters"
+
+config STX104
+	tristate "Apex Embedded Systems STX104 driver"
+	depends on PC104 && X86
+	select ISA_BUS_API
+	select GPIOLIB
+	help
+	  Say yes here to build support for the Apex Embedded Systems STX104
+	  integrated analog PC/104 card.
+
+	  This driver supports the 16 channels of single-ended (8 channels of
+	  differential) analog inputs, 2 channels of analog output, 4 digital
+	  inputs, and 4 digital outputs provided by the STX104.
+
+	  The base port addresses for the devices may be configured via the base
+	  array module parameter.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/iio/addac/Makefile
+++ linux-ein-5.4.0/drivers/iio/addac/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for industrial I/O ADDAC drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_STX104) += stx104.o
--- linux-ein-5.4.0.orig/drivers/iio/addac/stx104.c
+++ linux-ein-5.4.0/drivers/iio/addac/stx104.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IIO driver for the Apex Embedded Systems STX104
+ * Copyright (C) 2016 William Breathitt Gray
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/isa.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define STX104_OUT_CHAN(chan) {				\
+	.type = IIO_VOLTAGE,				\
+	.channel = chan,				\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
+	.indexed = 1,					\
+	.output = 1					\
+}
+#define STX104_IN_CHAN(chan, diff) {					\
+	.type = IIO_VOLTAGE,						\
+	.channel = chan,						\
+	.channel2 = chan,						\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) |	\
+		BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),	\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
+	.indexed = 1,							\
+	.differential = diff						\
+}
+
+#define STX104_NUM_OUT_CHAN 2
+
+#define STX104_EXTENT 16
+
+static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
+static unsigned int num_stx104;
+module_param_hw_array(base, uint, ioport, &num_stx104, 0);
+MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
+
+/**
+ * struct stx104_reg - device register structure
+ * @ssr_ad:	Software Strobe Register and ADC Data
+ * @achan:	ADC Channel
+ * @dio:	Digital I/O
+ * @dac:	DAC Channels
+ * @cir_asr:	Clear Interrupts and ADC Status
+ * @acr:	ADC Control
+ * @pccr_fsh:	Pacer Clock Control and FIFO Status MSB
+ * @acfg:	ADC Configuration
+ */
+struct stx104_reg {
+	u16 ssr_ad;
+	u8 achan;
+	u8 dio;
+	u16 dac[2];
+	u8 cir_asr;
+	u8 acr;
+	u8 pccr_fsh;
+	u8 acfg;
+};
+
+/**
+ * struct stx104_iio - IIO device private data structure
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @chan_out_states:	channels' output states
+ * @reg:		I/O address offset for the device registers
+ */
+struct stx104_iio {
+	struct mutex lock;
+	unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
+	struct stx104_reg __iomem *reg;
+};
+
+/**
+ * struct stx104_gpio - GPIO device private data structure
+ * @chip:	instance of the gpio_chip
+ * @lock:	synchronization lock to prevent I/O race conditions
+ * @base:	base port address of the GPIO device
+ * @out_state:	output bits state
+ */
+struct stx104_gpio {
+	struct gpio_chip chip;
+	spinlock_t lock;
+	u8 __iomem *base;
+	unsigned int out_state;
+};
+
+static int stx104_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+	struct stx104_iio *const priv = iio_priv(indio_dev);
+	struct stx104_reg __iomem *const reg = priv->reg;
+	unsigned int adc_config;
+	int adbu;
+	int gain;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		/* get gain configuration */
+		adc_config = ioread8(&reg->acfg);
+		gain = adc_config & 0x3;
+
+		*val = 1 << gain;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_RAW:
+		if (chan->output) {
+			*val = priv->chan_out_states[chan->channel];
+			return IIO_VAL_INT;
+		}
+
+		mutex_lock(&priv->lock);
+
+		/* select ADC channel */
+		iowrite8(chan->channel | (chan->channel << 4), &reg->achan);
+
+		/* trigger ADC sample capture by writing to the 8-bit
+		 * Software Strobe Register and wait for completion
+		 */
+		iowrite8(0, &reg->ssr_ad);
+		while (ioread8(&reg->cir_asr) & BIT(7));
+
+		*val = ioread16(&reg->ssr_ad);
+
+		mutex_unlock(&priv->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		/* get ADC bipolar/unipolar configuration */
+		adc_config = ioread8(&reg->acfg);
+		adbu = !(adc_config & BIT(2));
+
+		*val = -32768 * adbu;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* get ADC bipolar/unipolar and gain configuration */
+		adc_config = ioread8(&reg->acfg);
+		adbu = !(adc_config & BIT(2));
+		gain = adc_config & 0x3;
+
+		*val = 5;
+		*val2 = 15 - adbu + gain;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	}
+
+	return -EINVAL;
+}
+
+static int stx104_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct stx104_iio *const priv = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		/* Only four gain states (x1, x2, x4, x8) */
+		switch (val) {
+		case 1:
+			iowrite8(0, &priv->reg->acfg);
+			break;
+		case 2:
+			iowrite8(1, &priv->reg->acfg);
+			break;
+		case 4:
+			iowrite8(2, &priv->reg->acfg);
+			break;
+		case 8:
+			iowrite8(3, &priv->reg->acfg);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		return 0;
+	case IIO_CHAN_INFO_RAW:
+		if (chan->output) {
+			/* DAC can only accept up to a 16-bit value */
+			if ((unsigned int)val > 65535)
+				return -EINVAL;
+
+			mutex_lock(&priv->lock);
+
+			priv->chan_out_states[chan->channel] = val;
+			iowrite16(val, &priv->reg->dac[chan->channel]);
+
+			mutex_unlock(&priv->lock);
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stx104_info = {
+	.read_raw = stx104_read_raw,
+	.write_raw = stx104_write_raw
+};
+
+/* single-ended input channels configuration */
+static const struct iio_chan_spec stx104_channels_sing[] = {
+	STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
+	STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
+	STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
+	STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
+	STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
+	STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
+	STX104_IN_CHAN(15, 0)
+};
+/* differential input channels configuration */
+static const struct iio_chan_spec stx104_channels_diff[] = {
+	STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
+	STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
+	STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
+	STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
+};
+
+static int stx104_gpio_get_direction(struct gpio_chip *chip,
+	unsigned int offset)
+{
+	/* GPIO 0-3 are input only, while the rest are output only */
+	if (offset < 4)
+		return 1;
+
+	return 0;
+}
+
+static int stx104_gpio_direction_input(struct gpio_chip *chip,
+	unsigned int offset)
+{
+	if (offset >= 4)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int stx104_gpio_direction_output(struct gpio_chip *chip,
+	unsigned int offset, int value)
+{
+	if (offset < 4)
+		return -EINVAL;
+
+	chip->set(chip, offset, value);
+	return 0;
+}
+
+static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	if (offset >= 4)
+		return -EINVAL;
+
+	return !!(ioread8(stx104gpio->base) & BIT(offset));
+}
+
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	*bits = ioread8(stx104gpio->base);
+
+	return 0;
+}
+
+static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
+	int value)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+	const unsigned int mask = BIT(offset) >> 4;
+	unsigned long flags;
+
+	if (offset < 4)
+		return;
+
+	spin_lock_irqsave(&stx104gpio->lock, flags);
+
+	if (value)
+		stx104gpio->out_state |= mask;
+	else
+		stx104gpio->out_state &= ~mask;
+
+	iowrite8(stx104gpio->out_state, stx104gpio->base);
+
+	spin_unlock_irqrestore(&stx104gpio->lock, flags);
+}
+
+#define STX104_NGPIO 8
+static const char *stx104_names[STX104_NGPIO] = {
+	"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
+};
+
+static void stx104_gpio_set_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+	unsigned long flags;
+
+	/* verify masked GPIO are output */
+	if (!(*mask & 0xF0))
+		return;
+
+	*mask >>= 4;
+	*bits >>= 4;
+
+	spin_lock_irqsave(&stx104gpio->lock, flags);
+
+	stx104gpio->out_state &= ~*mask;
+	stx104gpio->out_state |= *mask & *bits;
+	iowrite8(stx104gpio->out_state, stx104gpio->base);
+
+	spin_unlock_irqrestore(&stx104gpio->lock, flags);
+}
+
+static int stx104_probe(struct device *dev, unsigned int id)
+{
+	struct iio_dev *indio_dev;
+	struct stx104_iio *priv;
+	struct stx104_gpio *stx104gpio;
+	int err;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
+	if (!stx104gpio)
+		return -ENOMEM;
+
+	if (!devm_request_region(dev, base[id], STX104_EXTENT,
+		dev_name(dev))) {
+		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
+			base[id], base[id] + STX104_EXTENT);
+		return -EBUSY;
+	}
+
+	priv = iio_priv(indio_dev);
+	priv->reg = devm_ioport_map(dev, base[id], STX104_EXTENT);
+	if (!priv->reg)
+		return -ENOMEM;
+
+	indio_dev->info = &stx104_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	/* determine if differential inputs */
+	if (ioread8(&priv->reg->cir_asr) & BIT(5)) {
+		indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
+		indio_dev->channels = stx104_channels_diff;
+	} else {
+		indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
+		indio_dev->channels = stx104_channels_sing;
+	}
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+
+	mutex_init(&priv->lock);
+
+	/* configure device for software trigger operation */
+	iowrite8(0, &priv->reg->acr);
+
+	/* initialize gain setting to x1 */
+	iowrite8(0, &priv->reg->acfg);
+
+	/* initialize DAC output to 0V */
+	iowrite16(0, &priv->reg->dac[0]);
+	iowrite16(0, &priv->reg->dac[1]);
+
+	stx104gpio->chip.label = dev_name(dev);
+	stx104gpio->chip.parent = dev;
+	stx104gpio->chip.owner = THIS_MODULE;
+	stx104gpio->chip.base = -1;
+	stx104gpio->chip.ngpio = STX104_NGPIO;
+	stx104gpio->chip.names = stx104_names;
+	stx104gpio->chip.get_direction = stx104_gpio_get_direction;
+	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
+	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
+	stx104gpio->chip.get = stx104_gpio_get;
+	stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
+	stx104gpio->chip.set = stx104_gpio_set;
+	stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
+	stx104gpio->base = &priv->reg->dio;
+	stx104gpio->out_state = 0x0;
+
+	spin_lock_init(&stx104gpio->lock);
+
+	err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
+	if (err) {
+		dev_err(dev, "GPIO registering failed (%d)\n", err);
+		return err;
+	}
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct isa_driver stx104_driver = {
+	.probe = stx104_probe,
+	.driver = {
+		.name = "stx104"
+	},
+};
+
+module_isa_driver(stx104_driver, num_stx104);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/iio/afe/iio-rescale.c
+++ linux-ein-5.4.0/drivers/iio/afe/iio-rescale.c
@@ -38,7 +38,7 @@
 			    int *val, int *val2, long mask)
 {
 	struct rescale *rescale = iio_priv(indio_dev);
-	unsigned long long tmp;
+	s64 tmp;
 	int ret;
 
 	switch (mask) {
@@ -59,10 +59,10 @@
 			*val2 = rescale->denominator;
 			return IIO_VAL_FRACTIONAL;
 		case IIO_VAL_FRACTIONAL_LOG2:
-			tmp = *val * 1000000000LL;
-			do_div(tmp, rescale->denominator);
+			tmp = (s64)*val * 1000000000LL;
+			tmp = div_s64(tmp, rescale->denominator);
 			tmp *= rescale->numerator;
-			do_div(tmp, 1000000000LL);
+			tmp = div_s64(tmp, 1000000000LL);
 			*val = tmp;
 			return ret;
 		default:
--- linux-ein-5.4.0.orig/drivers/iio/chemical/Kconfig
+++ linux-ein-5.4.0/drivers/iio/chemical/Kconfig
@@ -65,6 +65,7 @@
 config PMS7003
 	tristate "Plantower PMS7003 particulate matter sensor"
 	depends on SERIAL_DEV_BUS
+	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
 	  Say Y here to build support for the Plantower PMS7003 particulate
@@ -90,6 +91,8 @@
 	tristate "SPS30 particulate matter sensor"
 	depends on I2C
 	select CRC8
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say Y here to build support for the Sensirion SPS30 particulate
 	  matter sensor.
--- linux-ein-5.4.0.orig/drivers/iio/chemical/ccs811.c
+++ linux-ein-5.4.0/drivers/iio/chemical/ccs811.c
@@ -75,6 +75,11 @@
 	struct ccs811_reading buffer;
 	struct iio_trigger *drdy_trig;
 	bool drdy_trig_on;
+	/* Ensures correct alignment of timestamp if present */
+	struct {
+		s16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static const struct iio_chan_spec ccs811_channels[] = {
@@ -306,17 +311,17 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ccs811_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
-	s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
 	int ret;
 
-	ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
-					    (u8 *)&buf);
+	ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA,
+					    sizeof(data->scan.channels),
+					    (u8 *)data->scan.channels);
 	if (ret != 4) {
 		dev_err(&client->dev, "cannot read sensor data\n");
 		goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
@@ -413,11 +418,11 @@
 		data->drdy_trig->dev.parent = &client->dev;
 		data->drdy_trig->ops = &ccs811_trigger_ops;
 		iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
-		indio_dev->trig = data->drdy_trig;
-		iio_trigger_get(indio_dev->trig);
 		ret = iio_trigger_register(data->drdy_trig);
 		if (ret)
 			goto err_poweroff;
+
+		indio_dev->trig = iio_trigger_get(data->drdy_trig);
 	}
 
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
--- linux-ein-5.4.0.orig/drivers/iio/chemical/pms7003.c
+++ linux-ein-5.4.0/drivers/iio/chemical/pms7003.c
@@ -73,6 +73,11 @@
 	struct pms7003_frame frame;
 	struct completion frame_ready;
 	struct mutex lock; /* must be held whenever state gets touched */
+	/* Used to construct scan to push to the IIO buffer */
+	struct {
+		u16 data[3]; /* PM1, PM2P5, PM10 */
+		s64 ts;
+	} scan;
 };
 
 static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
@@ -104,7 +109,6 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct pms7003_state *state = iio_priv(indio_dev);
 	struct pms7003_frame *frame = &state->frame;
-	u16 data[3 + 1 + 4]; /* PM1, PM2P5, PM10, padding, timestamp */
 	int ret;
 
 	mutex_lock(&state->lock);
@@ -114,12 +118,15 @@
 		goto err;
 	}
 
-	data[PM1] = pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
-	data[PM2P5] = pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
-	data[PM10] = pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
+	state->scan.data[PM1] =
+		pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
+	state->scan.data[PM2P5] =
+		pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
+	state->scan.data[PM10] =
+		pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
 	mutex_unlock(&state->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &state->scan,
 					   iio_get_time_ns(indio_dev));
 err:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/chemical/sps30.c
+++ linux-ein-5.4.0/drivers/iio/chemical/sps30.c
@@ -230,15 +230,18 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct sps30_state *state = iio_priv(indio_dev);
 	int ret;
-	s32 data[4 + 2]; /* PM1, PM2P5, PM4, PM10, timestamp */
+	struct {
+		s32 data[4]; /* PM1, PM2P5, PM4, PM10 */
+		s64 ts;
+	} scan;
 
 	mutex_lock(&state->lock);
-	ret = sps30_do_meas(state, data, 4);
+	ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data));
 	mutex_unlock(&state->lock);
 	if (ret)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 err:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ linux-ein-5.4.0/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -57,10 +57,13 @@
 {
 	switch (type) {
 	case MOTIONSENSE_TYPE_ACCEL:
-	case MOTIONSENSE_TYPE_GYRO:
 		*min_freq = 12500;
 		*max_freq = 100000;
 		break;
+	case MOTIONSENSE_TYPE_GYRO:
+		*min_freq = 25000;
+		*max_freq = 100000;
+		break;
 	case MOTIONSENSE_TYPE_MAG:
 		*min_freq = 5000;
 		*max_freq = 25000;
@@ -96,7 +99,7 @@
 	platform_set_drvdata(pdev, indio_dev);
 
 	state->ec = ec->ec_dev;
-	state->msg = devm_kzalloc(&pdev->dev,
+	state->msg = devm_kzalloc(&pdev->dev, sizeof(*state->msg) +
 				max((u16)sizeof(struct ec_params_motion_sense),
 				state->ec->max_response), GFP_KERNEL);
 	if (!state->msg)
--- linux-ein-5.4.0.orig/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
+++ linux-ein-5.4.0/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -15,8 +15,8 @@
 /* Conversion times in us */
 static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
 						       13000, 7000 };
-static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
-						       5000, 8000 };
+static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 5000,
+						       3000, 8000 };
 static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
 						     4100, 8220, 16440 };
 
--- linux-ein-5.4.0.orig/drivers/iio/common/ssp_sensors/ssp_spi.c
+++ linux-ein-5.4.0/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -137,7 +137,7 @@
 	if (length > received_len - *data_index || length <= 0) {
 		ssp_dbg("[SSP]: MSG From MCU-invalid debug length(%d/%d)\n",
 			length, received_len);
-		return length ? length : -EPROTO;
+		return -EPROTO;
 	}
 
 	ssp_dbg("[SSP]: MSG From MCU - %s\n", &data_frame[*data_index]);
@@ -273,6 +273,8 @@
 	for (idx = 0; idx < len;) {
 		switch (dataframe[idx++]) {
 		case SSP_MSG2AP_INST_BYPASS_DATA:
+			if (idx >= len)
+				return -EPROTO;
 			sd = dataframe[idx++];
 			if (sd < 0 || sd >= SSP_SENSOR_MAX) {
 				dev_err(SSP_DEV,
@@ -282,10 +284,13 @@
 
 			if (indio_devs[sd]) {
 				spd = iio_priv(indio_devs[sd]);
-				if (spd->process_data)
+				if (spd->process_data) {
+					if (idx >= len)
+						return -EPROTO;
 					spd->process_data(indio_devs[sd],
 							  &dataframe[idx],
 							  data->timestamp);
+				}
 			} else {
 				dev_err(SSP_DEV, "no client for frame\n");
 			}
@@ -293,6 +298,8 @@
 			idx += ssp_offset_map[sd];
 			break;
 		case SSP_MSG2AP_INST_DEBUG_DATA:
+			if (idx >= len)
+				return -EPROTO;
 			sd = ssp_print_mcu_debug(dataframe, &idx, len);
 			if (sd) {
 				dev_err(SSP_DEV,
--- linux-ein-5.4.0.orig/drivers/iio/common/st_sensors/st_sensors_core.c
+++ linux-ein-5.4.0/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -76,16 +76,18 @@
 
 int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
 {
-	int err;
+	int err = 0;
 	struct st_sensor_odr_avl odr_out = {0, 0};
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-	if (!sdata->sensor_settings->odr.addr)
-		return 0;
+	mutex_lock(&sdata->odr_lock);
+
+	if (!sdata->sensor_settings->odr.mask)
+		goto unlock_mutex;
 
 	err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
 	if (err < 0)
-		goto st_sensors_match_odr_error;
+		goto unlock_mutex;
 
 	if ((sdata->sensor_settings->odr.addr ==
 					sdata->sensor_settings->pw.addr) &&
@@ -108,7 +110,9 @@
 	if (err >= 0)
 		sdata->odr = odr_out.hz;
 
-st_sensors_match_odr_error:
+unlock_mutex:
+	mutex_unlock(&sdata->odr_lock);
+
 	return err;
 }
 EXPORT_SYMBOL(st_sensors_set_odr);
@@ -384,6 +388,8 @@
 	struct st_sensors_platform_data *of_pdata;
 	int err = 0;
 
+	mutex_init(&sdata->odr_lock);
+
 	/* If OF/DT pdata exists, it will take precedence of anything else */
 	of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
 	if (of_pdata)
@@ -575,18 +581,24 @@
 		err = -EBUSY;
 		goto out;
 	} else {
+		mutex_lock(&sdata->odr_lock);
 		err = st_sensors_set_enable(indio_dev, true);
-		if (err < 0)
+		if (err < 0) {
+			mutex_unlock(&sdata->odr_lock);
 			goto out;
+		}
 
 		msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
 		err = st_sensors_read_axis_data(indio_dev, ch, val);
-		if (err < 0)
+		if (err < 0) {
+			mutex_unlock(&sdata->odr_lock);
 			goto out;
+		}
 
 		*val = *val >> ch->scan_type.shift;
 
 		err = st_sensors_set_enable(indio_dev, false);
+		mutex_unlock(&sdata->odr_lock);
 	}
 out:
 	mutex_unlock(&indio_dev->mlock);
--- linux-ein-5.4.0.orig/drivers/iio/dac/Kconfig
+++ linux-ein-5.4.0/drivers/iio/dac/Kconfig
@@ -60,8 +60,8 @@
 	help
 	  Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
 	  AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
-	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
-	  AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
+	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5600, AD5601, AD5602, AD5611,
+	  AD5612, AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
 	  as well as Texas Instruments DAC081S101, DAC101S101, DAC121S101.
 
 	  To compile this driver as a module, choose M here: the
--- linux-ein-5.4.0.orig/drivers/iio/dac/Makefile
+++ linux-ein-5.4.0/drivers/iio/dac/Makefile
@@ -16,7 +16,7 @@
 obj-$(CONFIG_AD5592R) += ad5592r.o
 obj-$(CONFIG_AD5593R) += ad5593r.o
 obj-$(CONFIG_AD5755) += ad5755.o
-obj-$(CONFIG_AD5755) += ad5758.o
+obj-$(CONFIG_AD5758) += ad5758.o
 obj-$(CONFIG_AD5761) += ad5761.o
 obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5791) += ad5791.o
--- linux-ein-5.4.0.orig/drivers/iio/dac/ad5446.c
+++ linux-ein-5.4.0/drivers/iio/dac/ad5446.c
@@ -170,7 +170,7 @@
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		*val = st->cached_val;
+		*val = st->cached_val >> chan->scan_type.shift;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 		*val = st->vref_mv;
@@ -327,6 +327,7 @@
 	ID_AD5541A,
 	ID_AD5512A,
 	ID_AD5553,
+	ID_AD5600,
 	ID_AD5601,
 	ID_AD5611,
 	ID_AD5621,
@@ -381,6 +382,10 @@
 		.channel = AD5446_CHANNEL(14, 16, 0),
 		.write = ad5446_write,
 	},
+	[ID_AD5600] = {
+		.channel = AD5446_CHANNEL(16, 16, 0),
+		.write = ad5446_write,
+	},
 	[ID_AD5601] = {
 		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
 		.write = ad5446_write,
@@ -448,6 +453,7 @@
 	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
 	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
 	{"ad5553", ID_AD5553},
+	{"ad5600", ID_AD5600},
 	{"ad5601", ID_AD5601},
 	{"ad5611", ID_AD5611},
 	{"ad5621", ID_AD5621},
@@ -521,8 +527,15 @@
 {
 	struct i2c_client *client = to_i2c_client(st->dev);
 	__be16 data = cpu_to_be16(val);
+	int ret;
 
-	return i2c_master_send(client, (char *)&data, sizeof(data));
+	ret = i2c_master_send(client, (char *)&data, sizeof(data));
+	if (ret < 0)
+		return ret;
+	if (ret != sizeof(data))
+		return -EIO;
+
+	return 0;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/iio/dac/ad5504.c
+++ linux-ein-5.4.0/drivers/iio/dac/ad5504.c
@@ -188,9 +188,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-ein-5.4.0.orig/drivers/iio/dac/ad5592r-base.c
+++ linux-ein-5.4.0/drivers/iio/dac/ad5592r-base.c
@@ -416,7 +416,7 @@
 			s64 tmp = *val * (3767897513LL / 25LL);
 			*val = div_s64_rem(tmp, 1000000000LL, val2);
 
-			ret = IIO_VAL_INT_PLUS_MICRO;
+			return IIO_VAL_INT_PLUS_MICRO;
 		} else {
 			int mult;
 
@@ -447,7 +447,7 @@
 		ret =  IIO_VAL_INT;
 		break;
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
 	}
 
 unlock:
@@ -530,7 +530,7 @@
 		if (!ret)
 			st->channel_modes[reg] = tmp;
 
-		fwnode_property_read_u32(child, "adi,off-state", &tmp);
+		ret = fwnode_property_read_u32(child, "adi,off-state", &tmp);
 		if (!ret)
 			st->channel_offstate[reg] = tmp;
 	}
--- linux-ein-5.4.0.orig/drivers/iio/dac/ad5593r.c
+++ linux-ein-5.4.0/drivers/iio/dac/ad5593r.c
@@ -14,6 +14,8 @@
 #include <linux/of.h>
 #include <linux/acpi.h>
 
+#include <asm/unaligned.h>
+
 #define AD5593R_MODE_CONF		(0 << 4)
 #define AD5593R_MODE_DAC_WRITE		(1 << 4)
 #define AD5593R_MODE_ADC_READBACK	(4 << 4)
@@ -21,6 +23,24 @@
 #define AD5593R_MODE_GPIO_READBACK	(6 << 4)
 #define AD5593R_MODE_REG_READBACK	(7 << 4)
 
+static int ad5593r_read_word(struct i2c_client *i2c, u8 reg, u16 *value)
+{
+	int ret;
+	u8 buf[2];
+
+	ret = i2c_smbus_write_byte(i2c, reg);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(i2c, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	*value = get_unaligned_be16(buf);
+
+	return 0;
+}
+
 static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
 {
 	struct i2c_client *i2c = to_i2c_client(st->dev);
@@ -39,13 +59,7 @@
 	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;
+	return ad5593r_read_word(i2c, AD5593R_MODE_ADC_READBACK, value);
 }
 
 static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
@@ -59,25 +73,19 @@
 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;
+	return ad5593r_read_word(i2c, AD5593R_MODE_REG_READBACK | reg, value);
 }
 
 static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
 {
 	struct i2c_client *i2c = to_i2c_client(st->dev);
-	s32 val;
+	u16 val;
+	int ret;
 
-	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_GPIO_READBACK);
-	if (val < 0)
-		return (int) val;
+	ret = ad5593r_read_word(i2c, AD5593R_MODE_GPIO_READBACK, &val);
+	if (ret)
+		return ret;
 
 	*value = (u8) val;
 
--- linux-ein-5.4.0.orig/drivers/iio/dac/ad5624r_spi.c
+++ linux-ein-5.4.0/drivers/iio/dac/ad5624r_spi.c
@@ -229,7 +229,7 @@
 	if (!indio_dev)
 		return -ENOMEM;
 	st = iio_priv(indio_dev);
-	st->reg = devm_regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get_optional(&spi->dev, "vref");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
@@ -240,6 +240,22 @@
 			goto error_disable_reg;
 
 		voltage_uv = ret;
+	} else {
+		if (PTR_ERR(st->reg) != -ENODEV)
+			return PTR_ERR(st->reg);
+		/* Backwards compatibility. This naming is not correct */
+		st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
+		if (!IS_ERR(st->reg)) {
+			ret = regulator_enable(st->reg);
+			if (ret)
+				return ret;
+
+			ret = regulator_get_voltage(st->reg);
+			if (ret < 0)
+				goto error_disable_reg;
+
+			voltage_uv = ret;
+		}
 	}
 
 	spi_set_drvdata(spi, indio_dev);
--- linux-ein-5.4.0.orig/drivers/iio/dac/cio-dac.c
+++ linux-ein-5.4.0/drivers/iio/dac/cio-dac.c
@@ -66,8 +66,8 @@
 	if (mask != IIO_CHAN_INFO_RAW)
 		return -EINVAL;
 
-	/* DAC can only accept up to a 16-bit value */
-	if ((unsigned int)val > 65535)
+	/* DAC can only accept up to a 12-bit value */
+	if ((unsigned int)val > 4095)
 		return -EINVAL;
 
 	priv->chan_out_states[chan->channel] = val;
--- linux-ein-5.4.0.orig/drivers/iio/dac/mcp4725.c
+++ linux-ein-5.4.0/drivers/iio/dac/mcp4725.c
@@ -47,12 +47,18 @@
 	struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
 		to_i2c_client(dev)));
 	u8 outbuf[2];
+	int ret;
 
 	outbuf[0] = (data->powerdown_mode + 1) << 4;
 	outbuf[1] = 0;
 	data->powerdown = true;
 
-	return i2c_master_send(data->client, outbuf, 2);
+	ret = i2c_master_send(data->client, outbuf, 2);
+	if (ret < 0)
+		return ret;
+	else if (ret != 2)
+		return -EIO;
+	return 0;
 }
 
 static int __maybe_unused mcp4725_resume(struct device *dev)
@@ -60,13 +66,19 @@
 	struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
 		to_i2c_client(dev)));
 	u8 outbuf[2];
+	int ret;
 
 	/* restore previous DAC value */
 	outbuf[0] = (data->dac_value >> 8) & 0xf;
 	outbuf[1] = data->dac_value & 0xff;
 	data->powerdown = false;
 
-	return i2c_master_send(data->client, outbuf, 2);
+	ret = i2c_master_send(data->client, outbuf, 2);
+	if (ret < 0)
+		return ret;
+	else if (ret != 2)
+		return -EIO;
+	return 0;
 }
 static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
 
--- linux-ein-5.4.0.orig/drivers/iio/dac/ti-dac5571.c
+++ linux-ein-5.4.0/drivers/iio/dac/ti-dac5571.c
@@ -352,6 +352,7 @@
 		data->dac5571_pwrdwn = dac5571_pwrdwn_quad;
 		break;
 	default:
+		ret = -EINVAL;
 		goto err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/iio/dac/vf610_dac.c
+++ linux-ein-5.4.0/drivers/iio/dac/vf610_dac.c
@@ -225,6 +225,7 @@
 	return 0;
 
 error_iio_device_register:
+	vf610_dac_exit(info);
 	clk_disable_unprepare(info->clk);
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/iio/dummy/iio_simple_dummy.c
+++ linux-ein-5.4.0/drivers/iio/dummy/iio_simple_dummy.c
@@ -568,10 +568,9 @@
 	struct iio_sw_device *swd;
 
 	swd = kzalloc(sizeof(*swd), GFP_KERNEL);
-	if (!swd) {
-		ret = -ENOMEM;
-		goto error_kzalloc;
-	}
+	if (!swd)
+		return ERR_PTR(-ENOMEM);
+
 	/*
 	 * Allocate an IIO device.
 	 *
@@ -583,7 +582,7 @@
 	indio_dev = iio_device_alloc(sizeof(*st));
 	if (!indio_dev) {
 		ret = -ENOMEM;
-		goto error_ret;
+		goto error_free_swd;
 	}
 
 	st = iio_priv(indio_dev);
@@ -614,6 +613,10 @@
 	 *    indio_dev->name = spi_get_device_id(spi)->name;
 	 */
 	indio_dev->name = kstrdup(name, GFP_KERNEL);
+	if (!indio_dev->name) {
+		ret = -ENOMEM;
+		goto error_free_device;
+	}
 
 	/* Provide description of available channels */
 	indio_dev->channels = iio_dummy_channels;
@@ -630,7 +633,7 @@
 
 	ret = iio_simple_dummy_events_register(indio_dev);
 	if (ret < 0)
-		goto error_free_device;
+		goto error_free_name;
 
 	ret = iio_simple_dummy_configure_buffer(indio_dev);
 	if (ret < 0)
@@ -647,11 +650,12 @@
 	iio_simple_dummy_unconfigure_buffer(indio_dev);
 error_unregister_events:
 	iio_simple_dummy_events_unregister(indio_dev);
+error_free_name:
+	kfree(indio_dev->name);
 error_free_device:
 	iio_device_free(indio_dev);
-error_ret:
+error_free_swd:
 	kfree(swd);
-error_kzalloc:
 	return ERR_PTR(ret);
 }
 
--- linux-ein-5.4.0.orig/drivers/iio/gyro/bmg160_core.c
+++ linux-ein-5.4.0/drivers/iio/gyro/bmg160_core.c
@@ -96,7 +96,11 @@
 	struct iio_trigger *motion_trig;
 	struct iio_mount_matrix orientation;
 	struct mutex mutex;
-	s16 buffer[8];
+	/* Ensure naturally aligned timestamp */
+	struct {
+		s16 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 	u32 dps_range;
 	int ev_enable_state;
 	int slope_thres;
@@ -880,12 +884,12 @@
 
 	mutex_lock(&data->mutex);
 	ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L,
-			       data->buffer, AXIS_MAX * 2);
+			       data->scan.chans, AXIS_MAX * 2);
 	mutex_unlock(&data->mutex);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -1169,11 +1173,14 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(dev, "unable to register iio device\n");
-		goto err_buffer_cleanup;
+		goto err_pm_cleanup;
 	}
 
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(dev);
+	pm_runtime_disable(dev);
 err_buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
--- linux-ein-5.4.0.orig/drivers/iio/gyro/fxas21002c_core.c
+++ linux-ein-5.4.0/drivers/iio/gyro/fxas21002c_core.c
@@ -300,14 +300,7 @@
 
 static int  fxas21002c_pm_get(struct fxas21002c_data *data)
 {
-	struct device *dev = regmap_get_device(data->regmap);
-	int ret;
-
-	ret = pm_runtime_get_sync(dev);
-	if (ret < 0)
-		pm_runtime_put_noidle(dev);
-
-	return ret;
+	return pm_runtime_resume_and_get(regmap_get_device(data->regmap));
 }
 
 static int  fxas21002c_pm_put(struct fxas21002c_data *data)
@@ -333,6 +326,7 @@
 	ret = regmap_field_read(data->regmap_fields[F_TEMP], &temp);
 	if (ret < 0) {
 		dev_err(dev, "failed to read temp: %d\n", ret);
+		fxas21002c_pm_put(data);
 		goto data_unlock;
 	}
 
@@ -366,6 +360,7 @@
 			       &axis_be, sizeof(axis_be));
 	if (ret < 0) {
 		dev_err(dev, "failed to read axis: %d: %d\n", index, ret);
+		fxas21002c_pm_put(data);
 		goto data_unlock;
 	}
 
@@ -938,7 +933,6 @@
 pm_disable:
 	pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
-	pm_runtime_put_noidle(dev);
 
 	return ret;
 }
@@ -952,7 +946,6 @@
 
 	pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
-	pm_runtime_put_noidle(dev);
 }
 EXPORT_SYMBOL_GPL(fxas21002c_core_remove);
 
--- linux-ein-5.4.0.orig/drivers/iio/gyro/itg3200_buffer.c
+++ linux-ein-5.4.0/drivers/iio/gyro/itg3200_buffer.c
@@ -46,17 +46,24 @@
 	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);
 
+error_ret:
 	iio_trigger_notify_done(indio_dev->trig);
 
-error_ret:
 	return IRQ_HANDLED;
 }
 
--- linux-ein-5.4.0.orig/drivers/iio/gyro/mpu3050-core.c
+++ linux-ein-5.4.0/drivers/iio/gyro/mpu3050-core.c
@@ -271,7 +271,16 @@
 	case IIO_CHAN_INFO_OFFSET:
 		switch (chan->type) {
 		case IIO_TEMP:
-			/* The temperature scaling is (x+23000)/280 Celsius */
+			/*
+			 * The temperature scaling is (x+23000)/280 Celsius
+			 * for the "best fit straight line" temperature range
+			 * of -30C..85C.  The 23000 includes room temperature
+			 * offset of +35C, 280 is the precision scale and x is
+			 * the 16-bit signed integer reported by hardware.
+			 *
+			 * Temperature value itself represents temperature of
+			 * the sensor die.
+			 */
 			*val = 23000;
 			return IIO_VAL_INT;
 		default:
@@ -328,7 +337,7 @@
 				goto out_read_raw_unlock;
 			}
 
-			*val = be16_to_cpu(raw_val);
+			*val = (s16)be16_to_cpu(raw_val);
 			ret = IIO_VAL_INT;
 
 			goto out_read_raw_unlock;
@@ -550,6 +559,8 @@
 					       MPU3050_FIFO_R,
 					       &fifo_values[offset],
 					       toread);
+			if (ret)
+				goto out_trigger_unlock;
 
 			dev_dbg(mpu3050->dev,
 				"%04x %04x %04x %04x %04x\n",
@@ -863,6 +874,7 @@
 	ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
 				 MPU3050_PWR_MGM_SLEEP, 0);
 	if (ret) {
+		regulator_bulk_disable(ARRAY_SIZE(mpu3050->regs), mpu3050->regs);
 		dev_err(mpu3050->dev, "error setting power mode\n");
 		return ret;
 	}
--- linux-ein-5.4.0.orig/drivers/iio/gyro/st_gyro_core.c
+++ linux-ein-5.4.0/drivers/iio/gyro/st_gyro_core.c
@@ -139,7 +139,6 @@
 			[2] = LSM330DLC_GYRO_DEV_NAME,
 			[3] = L3G4IS_GYRO_DEV_NAME,
 			[4] = LSM330_GYRO_DEV_NAME,
-			[5] = LSM9DS0_GYRO_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
 		.odr = {
@@ -203,6 +202,80 @@
 			},
 		},
 		.sim = {
+			.addr = 0x23,
+			.value = BIT(0),
+		},
+		.multi_read_bit = true,
+		.bootime = 2,
+	},
+	{
+		.wai = 0xd4,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = LSM9DS0_GYRO_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
+		.odr = {
+			.addr = 0x20,
+			.mask = GENMASK(7, 6),
+			.odr_avl = {
+				{ .hz = 95, .value = 0x00, },
+				{ .hz = 190, .value = 0x01, },
+				{ .hz = 380, .value = 0x02, },
+				{ .hz = 760, .value = 0x03, },
+			},
+		},
+		.pw = {
+			.addr = 0x20,
+			.mask = BIT(3),
+			.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 = GENMASK(5, 4),
+			.fs_avl = {
+				[0] = {
+					.num = ST_GYRO_FS_AVL_245DPS,
+					.value = 0x00,
+					.gain = IIO_DEGREE_TO_RAD(8750),
+				},
+				[1] = {
+					.num = ST_GYRO_FS_AVL_500DPS,
+					.value = 0x01,
+					.gain = IIO_DEGREE_TO_RAD(17500),
+				},
+				[2] = {
+					.num = ST_GYRO_FS_AVL_2000DPS,
+					.value = 0x02,
+					.gain = IIO_DEGREE_TO_RAD(70000),
+				},
+			},
+		},
+		.bdu = {
+			.addr = 0x23,
+			.mask = BIT(7),
+		},
+		.drdy_irq = {
+			.int2 = {
+				.addr = 0x22,
+				.mask = BIT(3),
+			},
+			/*
+			 * The sensor has IHL (active low) and open
+			 * drain settings, but only for INT1 and not
+			 * for the DRDY line on INT2.
+			 */
+			.stat_drdy = {
+				.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+				.mask = GENMASK(2, 0),
+			},
+		},
+		.sim = {
 			.addr = 0x23,
 			.value = BIT(0),
 		},
--- linux-ein-5.4.0.orig/drivers/iio/health/afe4403.c
+++ linux-ein-5.4.0/drivers/iio/health/afe4403.c
@@ -63,6 +63,7 @@
  * @regulator: Pointer to the regulator for the IC
  * @trig: IIO trigger for this device
  * @irq: ADC_RDY line interrupt number
+ * @buffer: Used to construct data layout to push into IIO buffer.
  */
 struct afe4403_data {
 	struct device *dev;
@@ -72,6 +73,8 @@
 	struct regulator *regulator;
 	struct iio_trigger *trig;
 	int irq;
+	/* Ensure suitable alignment for timestamp */
+	s32 buffer[8] __aligned(8);
 };
 
 enum afe4403_chan_id {
@@ -242,14 +245,14 @@
 			    int *val, int *val2, long mask)
 {
 	struct afe4403_data *afe = iio_priv(indio_dev);
-	unsigned int reg = afe4403_channel_values[chan->address];
-	unsigned int field = afe4403_channel_leds[chan->address];
+	unsigned int reg, field;
 	int ret;
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
+			reg = afe4403_channel_values[chan->address];
 			ret = afe4403_read(afe, reg, val);
 			if (ret)
 				return ret;
@@ -259,6 +262,7 @@
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
+			field = afe4403_channel_leds[chan->address];
 			ret = regmap_field_read(afe->fields[field], val);
 			if (ret)
 				return ret;
@@ -309,7 +313,6 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct afe4403_data *afe = iio_priv(indio_dev);
 	int ret, bit, i = 0;
-	s32 buffer[8];
 	u8 tx[4] = {AFE440X_CONTROL0, 0x0, 0x0, AFE440X_CONTROL0_READ};
 	u8 rx[3];
 
@@ -326,9 +329,9 @@
 		if (ret)
 			goto err;
 
-		buffer[i++] = (rx[0] << 16) |
-				(rx[1] << 8) |
-				(rx[2]);
+		afe->buffer[i++] = (rx[0] << 16) |
+				   (rx[1] << 8) |
+				   (rx[2]);
 	}
 
 	/* Disable reading from the device */
@@ -337,7 +340,8 @@
 	if (ret)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, afe->buffer,
+					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
 
--- linux-ein-5.4.0.orig/drivers/iio/health/afe4404.c
+++ linux-ein-5.4.0/drivers/iio/health/afe4404.c
@@ -83,6 +83,7 @@
  * @regulator: Pointer to the regulator for the IC
  * @trig: IIO trigger for this device
  * @irq: ADC_RDY line interrupt number
+ * @buffer: Used to construct a scan to push to the iio buffer.
  */
 struct afe4404_data {
 	struct device *dev;
@@ -91,6 +92,7 @@
 	struct regulator *regulator;
 	struct iio_trigger *trig;
 	int irq;
+	s32 buffer[10] __aligned(8);
 };
 
 enum afe4404_chan_id {
@@ -248,20 +250,20 @@
 			    int *val, int *val2, long mask)
 {
 	struct afe4404_data *afe = iio_priv(indio_dev);
-	unsigned int value_reg = afe4404_channel_values[chan->address];
-	unsigned int led_field = afe4404_channel_leds[chan->address];
-	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
+	unsigned int value_reg, led_field, offdac_field;
 	int ret;
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
+			value_reg = afe4404_channel_values[chan->address];
 			ret = regmap_read(afe->regmap, value_reg, val);
 			if (ret)
 				return ret;
 			return IIO_VAL_INT;
 		case IIO_CHAN_INFO_OFFSET:
+			offdac_field = afe4404_channel_offdacs[chan->address];
 			ret = regmap_field_read(afe->fields[offdac_field], val);
 			if (ret)
 				return ret;
@@ -271,6 +273,7 @@
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
+			led_field = afe4404_channel_leds[chan->address];
 			ret = regmap_field_read(afe->fields[led_field], val);
 			if (ret)
 				return ret;
@@ -293,19 +296,20 @@
 			     int val, int val2, long mask)
 {
 	struct afe4404_data *afe = iio_priv(indio_dev);
-	unsigned int led_field = afe4404_channel_leds[chan->address];
-	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
+	unsigned int led_field, offdac_field;
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_OFFSET:
+			offdac_field = afe4404_channel_offdacs[chan->address];
 			return regmap_field_write(afe->fields[offdac_field], val);
 		}
 		break;
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
+			led_field = afe4404_channel_leds[chan->address];
 			return regmap_field_write(afe->fields[led_field], val);
 		}
 		break;
@@ -328,17 +332,17 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct afe4404_data *afe = iio_priv(indio_dev);
 	int ret, bit, i = 0;
-	s32 buffer[10];
 
 	for_each_set_bit(bit, indio_dev->active_scan_mask,
 			 indio_dev->masklength) {
 		ret = regmap_read(afe->regmap, afe4404_channel_values[bit],
-				  &buffer[i++]);
+				  &afe->buffer[i++]);
 		if (ret)
 			goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, afe->buffer,
+					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
 
--- linux-ein-5.4.0.orig/drivers/iio/humidity/am2315.c
+++ linux-ein-5.4.0/drivers/iio/humidity/am2315.c
@@ -33,7 +33,11 @@
 struct am2315_data {
 	struct i2c_client *client;
 	struct mutex lock;
-	s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s16 chans[2];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 struct am2315_sensor_data {
@@ -167,20 +171,20 @@
 
 	mutex_lock(&data->lock);
 	if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
-		data->buffer[0] = sensor_data.hum_data;
-		data->buffer[1] = sensor_data.temp_data;
+		data->scan.chans[0] = sensor_data.hum_data;
+		data->scan.chans[1] = sensor_data.temp_data;
 	} else {
 		i = 0;
 		for_each_set_bit(bit, indio_dev->active_scan_mask,
 				 indio_dev->masklength) {
-			data->buffer[i] = (bit ? sensor_data.temp_data :
-						 sensor_data.hum_data);
+			data->scan.chans[i] = (bit ? sensor_data.temp_data :
+					       sensor_data.hum_data);
 			i++;
 		}
 	}
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/humidity/hdc100x.c
+++ linux-ein-5.4.0/drivers/iio/humidity/hdc100x.c
@@ -24,6 +24,8 @@
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
 
+#include <linux/time.h>
+
 #define HDC100X_REG_TEMP			0x00
 #define HDC100X_REG_HUMIDITY			0x01
 
@@ -38,6 +40,11 @@
 
 	/* integration time of the sensor */
 	int adc_int_us[2];
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* integration time in us */
@@ -160,7 +167,7 @@
 				   struct iio_chan_spec const *chan)
 {
 	struct i2c_client *client = data->client;
-	int delay = data->adc_int_us[chan->address];
+	int delay = data->adc_int_us[chan->address] + 1*USEC_PER_MSEC;
 	int ret;
 	__be16 val;
 
@@ -229,7 +236,7 @@
 			*val2 = 65536;
 			return IIO_VAL_FRACTIONAL;
 		} else {
-			*val = 100;
+			*val = 100000;
 			*val2 = 65536;
 			return IIO_VAL_FRACTIONAL;
 		}
@@ -317,9 +324,8 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct hdc100x_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
-	int delay = data->adc_int_us[0] + data->adc_int_us[1];
+	int delay = data->adc_int_us[0] + data->adc_int_us[1] + 2*USEC_PER_MSEC;
 	int ret;
-	s16 buf[8];  /* 2x s16 + padding + 8 byte timestamp */
 
 	/* dual read starts at temp register */
 	mutex_lock(&data->lock);
@@ -330,13 +336,13 @@
 	}
 	usleep_range(delay, delay + 1000);
 
-	ret = i2c_master_recv(client, (u8 *)buf, 4);
+	ret = i2c_master_recv(client, (u8 *)data->scan.channels, 4);
 	if (ret < 0) {
 		dev_err(&client->dev, "cannot read sensor data\n");
 		goto err;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 err:
 	mutex_unlock(&data->lock);
--- linux-ein-5.4.0.orig/drivers/iio/humidity/hid-sensor-humidity.c
+++ linux-ein-5.4.0/drivers/iio/humidity/hid-sensor-humidity.c
@@ -17,7 +17,10 @@
 struct hid_humidity_state {
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info humidity_attr;
-	s32 humidity_data;
+	struct {
+		s32 humidity_data;
+		u64 timestamp __aligned(8);
+	} scan;
 	int scale_pre_decml;
 	int scale_post_decml;
 	int scale_precision;
@@ -127,9 +130,8 @@
 	struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 
 	if (atomic_read(&humid_st->common_attributes.data_ready))
-		iio_push_to_buffers_with_timestamp(indio_dev,
-					&humid_st->humidity_data,
-					iio_get_time_ns(indio_dev));
+		iio_push_to_buffers_with_timestamp(indio_dev, &humid_st->scan,
+						   iio_get_time_ns(indio_dev));
 
 	return 0;
 }
@@ -144,7 +146,7 @@
 
 	switch (usage_id) {
 	case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY:
-		humid_st->humidity_data = *(s32 *)raw_data;
+		humid_st->scan.humidity_data = *(s32 *)raw_data;
 
 		return 0;
 	default:
--- linux-ein-5.4.0.orig/drivers/iio/humidity/hts221.h
+++ linux-ein-5.4.0/drivers/iio/humidity/hts221.h
@@ -14,8 +14,6 @@
 
 #include <linux/iio/iio.h>
 
-#define HTS221_DATA_SIZE	2
-
 enum hts221_sensor_type {
 	HTS221_SENSOR_H,
 	HTS221_SENSOR_T,
@@ -39,6 +37,11 @@
 
 	bool enabled;
 	u8 odr;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__le16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops hts221_pm_ops;
--- linux-ein-5.4.0.orig/drivers/iio/humidity/hts221_buffer.c
+++ linux-ein-5.4.0/drivers/iio/humidity/hts221_buffer.c
@@ -162,7 +162,6 @@
 
 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);
@@ -172,18 +171,20 @@
 	/* humidity data */
 	ch = &iio_dev->channels[HTS221_SENSOR_H];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer, HTS221_DATA_SIZE);
+			       &hw->scan.channels[0],
+			       sizeof(hw->scan.channels[0]));
 	if (err < 0)
 		goto out;
 
 	/* temperature data */
 	ch = &iio_dev->channels[HTS221_SENSOR_T];
 	err = regmap_bulk_read(hw->regmap, ch->address,
-			       buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
+			       &hw->scan.channels[1],
+			       sizeof(hw->scan.channels[1]));
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
--- linux-ein-5.4.0.orig/drivers/iio/imu/adis16400.c
+++ linux-ein-5.4.0/drivers/iio/imu/adis16400.c
@@ -464,8 +464,7 @@
 		if (ret)
 			goto err_ret;
 
-		ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
-		if (ret != 1) {
+		if (sscanf(indio_dev->name, "adis%u\n", &device_id) != 1) {
 			ret = -EINVAL;
 			goto err_ret;
 		}
@@ -652,9 +651,6 @@
 	void *buffer;
 	int ret;
 
-	if (!adis->buffer)
-		return -ENOMEM;
-
 	if (!(st->variant->flags & ADIS16400_NO_BURST) &&
 		st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
 		st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
--- linux-ein-5.4.0.orig/drivers/iio/imu/adis16480.c
+++ linux-ein-5.4.0/drivers/iio/imu/adis16480.c
@@ -454,12 +454,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;
@@ -623,9 +625,13 @@
 			*val2 = (st->chip_info->temp_scale % 1000) * 1000;
 			return IIO_VAL_INT_PLUS_MICRO;
 		case IIO_PRESSURE:
-			*val = 0;
-			*val2 = 4000; /* 40ubar = 0.004 kPa */
-			return IIO_VAL_INT_PLUS_MICRO;
+			/*
+			 * max scale is 1310 mbar
+			 * max raw value is 32767 shifted for 32bits
+			 */
+			*val = 131; /* 1310mbar = 131 kPa */
+			*val2 = 32767 << 16;
+			return IIO_VAL_FRACTIONAL;
 		default:
 			return -EINVAL;
 		}
@@ -786,13 +792,14 @@
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
 		/*
-		 * storing the value in rad/degree and the scale in degree
-		 * gives us the result in rad and better precession than
-		 * storing the scale directly in rad.
+		 * Typically we do IIO_RAD_TO_DEGREE in the denominator, which
+		 * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since
+		 * it gives better approximation. However, in this case we
+		 * cannot do it since it would not fit in a 32bit variable.
 		 */
-		.gyro_max_val = IIO_RAD_TO_DEGREE(22887),
-		.gyro_max_scale = 300,
-		.accel_max_val = IIO_M_S_2_TO_G(21973),
+		.gyro_max_val = 22887 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(300),
+		.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
 		.accel_max_scale = 18,
 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
 		.int_clk = 2460000,
@@ -802,9 +809,9 @@
 	[ADIS16480] = {
 		.channels = adis16480_channels,
 		.num_channels = ARRAY_SIZE(adis16480_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
-		.gyro_max_scale = 450,
-		.accel_max_val = IIO_M_S_2_TO_G(12500),
+		.gyro_max_val = 22500 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+		.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
 		.accel_max_scale = 10,
 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
 		.int_clk = 2460000,
@@ -814,9 +821,9 @@
 	[ADIS16485] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
-		.gyro_max_scale = 450,
-		.accel_max_val = IIO_M_S_2_TO_G(20000),
+		.gyro_max_val = 22500 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+		.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
 		.accel_max_scale = 5,
 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
 		.int_clk = 2460000,
@@ -826,9 +833,9 @@
 	[ADIS16488] = {
 		.channels = adis16480_channels,
 		.num_channels = ARRAY_SIZE(adis16480_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
-		.gyro_max_scale = 450,
-		.accel_max_val = IIO_M_S_2_TO_G(22500),
+		.gyro_max_val = 22500 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+		.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
 		.accel_max_scale = 18,
 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
 		.int_clk = 2460000,
@@ -838,9 +845,9 @@
 	[ADIS16495_1] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
-		.gyro_max_scale = 125,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 20000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 8,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -851,9 +858,9 @@
 	[ADIS16495_2] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
-		.gyro_max_scale = 450,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 18000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 8,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -864,9 +871,9 @@
 	[ADIS16495_3] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
-		.gyro_max_scale = 2000,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 20000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 8,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -877,9 +884,9 @@
 	[ADIS16497_1] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
-		.gyro_max_scale = 125,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 20000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 40,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -890,9 +897,9 @@
 	[ADIS16497_2] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
-		.gyro_max_scale = 450,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 18000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 40,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -903,9 +910,9 @@
 	[ADIS16497_3] = {
 		.channels = adis16485_channels,
 		.num_channels = ARRAY_SIZE(adis16485_channels),
-		.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
-		.gyro_max_scale = 2000,
-		.accel_max_val = IIO_M_S_2_TO_G(32000),
+		.gyro_max_val = 20000 << 16,
+		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
 		.accel_max_scale = 40,
 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
 		.int_clk = 4250000,
@@ -919,6 +926,7 @@
 	.read_raw = &adis16480_read_raw,
 	.write_raw = &adis16480_write_raw,
 	.update_scan_mode = adis_update_scan_mode,
+	.debugfs_reg_access = adis_debugfs_reg_access,
 };
 
 static int adis16480_stop_device(struct iio_dev *indio_dev)
--- linux-ein-5.4.0.orig/drivers/iio/imu/adis_buffer.c
+++ linux-ein-5.4.0/drivers/iio/imu/adis_buffer.c
@@ -125,9 +125,6 @@
 	struct adis *adis = iio_device_get_drvdata(indio_dev);
 	int ret;
 
-	if (!adis->buffer)
-		return -ENOMEM;
-
 	if (adis->data->has_paging) {
 		mutex_lock(&adis->txrx_lock);
 		if (adis->current_page != 0) {
--- linux-ein-5.4.0.orig/drivers/iio/imu/bmi160/bmi160.h
+++ linux-ein-5.4.0/drivers/iio/imu/bmi160/bmi160.h
@@ -7,6 +7,13 @@
 struct bmi160_data {
 	struct regmap *regmap;
 	struct iio_trigger *trig;
+	/*
+	 * Ensure natural alignment for timestamp if present.
+	 * Max length needed: 2 * 3 channels + 4 bytes padding + 8 byte ts.
+	 * If fewer channels are enabled, less space may be needed, as
+	 * long as the timestamp is still aligned to 8 bytes.
+	 */
+	__le16 buf[12] __aligned(8);
 };
 
 extern const struct regmap_config bmi160_regmap_config;
--- linux-ein-5.4.0.orig/drivers/iio/imu/bmi160/bmi160_core.c
+++ linux-ein-5.4.0/drivers/iio/imu/bmi160/bmi160_core.c
@@ -411,8 +411,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bmi160_data *data = iio_priv(indio_dev);
-	__le16 buf[16];
-	/* 3 sens x 3 axis x __le16 + 3 x __le16 pad + 4 x __le16 tstamp */
 	int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
 	__le16 sample;
 
@@ -422,10 +420,10 @@
 				       &sample, sizeof(sample));
 		if (ret)
 			goto done;
-		buf[j++] = sample;
+		data->buf[j++] = sample;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp);
 done:
 	iio_trigger_notify_done(indio_dev->trig);
 	return IRQ_HANDLED;
--- linux-ein-5.4.0.orig/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ linux-ein-5.4.0/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -115,6 +115,7 @@
 		.reg = &reg_set_6050,
 		.config = &chip_config_6050,
 		.fifo_size = 1024,
+		.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU6500_WHOAMI_VALUE,
@@ -122,6 +123,7 @@
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 		.fifo_size = 512,
+		.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU6515_WHOAMI_VALUE,
@@ -129,6 +131,7 @@
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 		.fifo_size = 512,
+		.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU6000_WHOAMI_VALUE,
@@ -136,6 +139,7 @@
 		.reg = &reg_set_6050,
 		.config = &chip_config_6050,
 		.fifo_size = 1024,
+		.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU9150_WHOAMI_VALUE,
@@ -143,6 +147,7 @@
 		.reg = &reg_set_6050,
 		.config = &chip_config_6050,
 		.fifo_size = 1024,
+		.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU9250_WHOAMI_VALUE,
@@ -150,6 +155,7 @@
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 		.fifo_size = 512,
+		.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_MPU9255_WHOAMI_VALUE,
@@ -157,6 +163,7 @@
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 		.fifo_size = 512,
+		.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_ICM20608_WHOAMI_VALUE,
@@ -164,6 +171,7 @@
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 		.fifo_size = 512,
+		.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
 	},
 	{
 		.whoami = INV_ICM20602_WHOAMI_VALUE,
@@ -171,6 +179,7 @@
 		.reg = &reg_set_icm20602,
 		.config = &chip_config_6050,
 		.fifo_size = 1008,
+		.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
 	},
 };
 
@@ -471,12 +480,8 @@
 
 			return IIO_VAL_INT_PLUS_MICRO;
 		case IIO_TEMP:
-			*val = 0;
-			if (st->chip_type == INV_ICM20602)
-				*val2 = INV_ICM20602_TEMP_SCALE;
-			else
-				*val2 = INV_MPU6050_TEMP_SCALE;
-
+			*val = st->hw->temp.scale / 1000000;
+			*val2 = st->hw->temp.scale % 1000000;
 			return IIO_VAL_INT_PLUS_MICRO;
 		default:
 			return -EINVAL;
@@ -484,11 +489,7 @@
 	case IIO_CHAN_INFO_OFFSET:
 		switch (chan->type) {
 		case IIO_TEMP:
-			if (st->chip_type == INV_ICM20602)
-				*val = INV_ICM20602_TEMP_OFFSET;
-			else
-				*val = INV_MPU6050_TEMP_OFFSET;
-
+			*val = st->hw->temp.offset;
 			return IIO_VAL_INT;
 		default:
 			return -EINVAL;
@@ -500,13 +501,13 @@
 			ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset,
 						chan->channel2, val);
 			mutex_unlock(&st->lock);
-			return IIO_VAL_INT;
+			return ret;
 		case IIO_ACCEL:
 			mutex_lock(&st->lock);
 			ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset,
 						chan->channel2, val);
 			mutex_unlock(&st->lock);
-			return IIO_VAL_INT;
+			return ret;
 
 		default:
 			return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ linux-ein-5.4.0/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -101,6 +101,7 @@
  *  @reg:   register map of the chip.
  *  @config:    configuration of the chip.
  *  @fifo_size:	size of the FIFO in bytes.
+ *  @temp:	offset and scale to apply to raw temperature.
  */
 struct inv_mpu6050_hw {
 	u8 whoami;
@@ -108,6 +109,10 @@
 	const struct inv_mpu6050_reg_map *reg;
 	const struct inv_mpu6050_chip_config *config;
 	size_t fifo_size;
+	struct {
+		int offset;
+		int scale;
+	} temp;
 };
 
 /*
@@ -218,16 +223,19 @@
 #define INV_MPU6050_REG_UP_TIME_MIN          5000
 #define INV_MPU6050_REG_UP_TIME_MAX          10000
 
-#define INV_MPU6050_TEMP_OFFSET	             12421
-#define INV_MPU6050_TEMP_SCALE               2941
+#define INV_MPU6050_TEMP_OFFSET	             12420
+#define INV_MPU6050_TEMP_SCALE               2941176
 #define INV_MPU6050_MAX_GYRO_FS_PARAM        3
 #define INV_MPU6050_MAX_ACCL_FS_PARAM        3
 #define INV_MPU6050_THREE_AXIS               3
 #define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT    3
 #define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT    3
 
-#define INV_ICM20602_TEMP_OFFSET	     8170
-#define INV_ICM20602_TEMP_SCALE		     3060
+#define INV_MPU6500_TEMP_OFFSET              7011
+#define INV_MPU6500_TEMP_SCALE               2995178
+
+#define INV_ICM20608_TEMP_OFFSET	     8170
+#define INV_ICM20608_TEMP_SCALE		     3059976
 
 /* 6 + 6 round up and plus 8 */
 #define INV_MPU6050_OUTPUT_DATA_SIZE         24
--- linux-ein-5.4.0.orig/drivers/iio/imu/kmx61.c
+++ linux-ein-5.4.0/drivers/iio/imu/kmx61.c
@@ -1393,7 +1393,7 @@
 	ret = iio_device_register(data->acc_indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "Failed to register acc iio device\n");
-		goto err_buffer_cleanup_mag;
+		goto err_pm_cleanup;
 	}
 
 	ret = iio_device_register(data->mag_indio_dev);
@@ -1406,6 +1406,9 @@
 
 err_iio_unregister_acc:
 	iio_device_unregister(data->acc_indio_dev);
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(&client->dev);
+	pm_runtime_disable(&client->dev);
 err_buffer_cleanup_mag:
 	if (client->irq > 0)
 		iio_triggered_buffer_cleanup(data->mag_indio_dev);
--- linux-ein-5.4.0.orig/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ linux-ein-5.4.0/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -664,13 +664,29 @@
 static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
 {
 	struct st_lsm6dsx_hw *hw = private;
-	int count;
+	int fifo_len = 0, len;
 
-	mutex_lock(&hw->fifo_lock);
-	count = hw->settings->fifo_ops.read_fifo(hw);
-	mutex_unlock(&hw->fifo_lock);
+	/*
+	 * If we are using edge IRQs, new samples can arrive while
+	 * processing current interrupt since there are no hw
+	 * guarantees the irq line stays "low" long enough to properly
+	 * detect the new interrupt. In this case the new sample will
+	 * be missed.
+	 * Polling FIFO status register allow us to read new
+	 * samples even if the interrupt arrives while processing
+	 * previous data and the timeslot where the line is "low" is
+	 * too short to be properly detected.
+	 */
+	do {
+		mutex_lock(&hw->fifo_lock);
+		len = hw->settings->fifo_ops.read_fifo(hw);
+		mutex_unlock(&hw->fifo_lock);
 
-	return count ? IRQ_HANDLED : IRQ_NONE;
+		if (len > 0)
+			fifo_len += len;
+	} while (len > 0);
+
+	return fifo_len ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
--- linux-ein-5.4.0.orig/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ linux-ein-5.4.0/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -152,9 +152,10 @@
 					.addr = 0x10,
 					.mask = GENMASK(4, 3),
 				},
-				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(245), 0x0 },
-				.fs_avl[1] = {  IIO_DEGREE_TO_RAD(500), 0x1 },
-				.fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 },
+
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
 				.fs_len = 3,
 			},
 		},
@@ -910,7 +911,8 @@
 
 	for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
 		for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
-			if (id == st_lsm6dsx_sensor_settings[i].id[j].hw_id)
+			if (st_lsm6dsx_sensor_settings[i].id[j].name &&
+			    id == st_lsm6dsx_sensor_settings[i].id[j].hw_id)
 				break;
 		}
 		if (j < ST_LSM6DSX_MAX_ID)
@@ -985,8 +987,7 @@
 		return -EINVAL;
 
 	*val = odr_table->odr_avl[i].val;
-
-	return 0;
+	return odr_table->odr_avl[i].hz;
 }
 
 static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
@@ -1014,6 +1015,8 @@
 	int err;
 
 	switch (sensor->id) {
+	case ST_LSM6DSX_ID_GYRO:
+		break;
 	case ST_LSM6DSX_ID_EXT0:
 	case ST_LSM6DSX_ID_EXT1:
 	case ST_LSM6DSX_ID_EXT2:
@@ -1039,8 +1042,8 @@
 		}
 		break;
 	}
-	default:
-		break;
+	default: /* should never occur */
+		return -EINVAL;
 	}
 
 	if (req_odr > 0) {
@@ -1149,8 +1152,10 @@
 	case IIO_CHAN_INFO_SAMP_FREQ: {
 		u8 data;
 
-		err = st_lsm6dsx_check_odr(sensor, val, &data);
-		if (!err)
+		val = st_lsm6dsx_check_odr(sensor, val, &data);
+		if (val < 0)
+			err = val;
+		else
 			sensor->odr = val;
 		break;
 	}
--- linux-ein-5.4.0.orig/drivers/iio/industrialio-buffer.c
+++ linux-ein-5.4.0/drivers/iio/industrialio-buffer.c
@@ -566,7 +566,7 @@
 				const unsigned long *mask, bool timestamp)
 {
 	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,
@@ -574,13 +574,17 @@
 		length = iio_storage_bytes_for_si(indio_dev, i);
 		bytes = ALIGN(bytes, length);
 		bytes += length;
+		largest = max(largest, length);
 	}
 
 	if (timestamp) {
 		length = iio_storage_bytes_for_timestamp(indio_dev);
 		bytes = ALIGN(bytes, length);
 		bytes += length;
+		largest = max(largest, length);
 	}
+
+	bytes = ALIGN(bytes, largest);
 	return bytes;
 }
 
@@ -841,12 +845,12 @@
 				       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);
 			length = iio_storage_bytes_for_si(indio_dev, in_ind);
 			/* 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);
 		}
 		length = iio_storage_bytes_for_si(indio_dev, in_ind);
 		out_loc = roundup(out_loc, length);
--- linux-ein-5.4.0.orig/drivers/iio/industrialio-core.c
+++ linux-ein-5.4.0/drivers/iio/industrialio-core.c
@@ -130,6 +130,8 @@
 	[IIO_MOD_PM2P5] = "pm2p5",
 	[IIO_MOD_PM4] = "pm4",
 	[IIO_MOD_PM10] = "pm10",
+	[IIO_MOD_ETHANOL] = "ethanol",
+	[IIO_MOD_H2] = "h2",
 };
 
 /* relies on pairs of these shared then separate */
--- linux-ein-5.4.0.orig/drivers/iio/industrialio-sw-trigger.c
+++ linux-ein-5.4.0/drivers/iio/industrialio-sw-trigger.c
@@ -58,8 +58,12 @@
 
 	t->group = configfs_register_default_group(iio_triggers_group, t->name,
 						&iio_trigger_type_group_type);
-	if (IS_ERR(t->group))
+	if (IS_ERR(t->group)) {
+		mutex_lock(&iio_trigger_types_lock);
+		list_del(&t->list);
+		mutex_unlock(&iio_trigger_types_lock);
 		ret = PTR_ERR(t->group);
+	}
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/iio/industrialio-trigger.c
+++ linux-ein-5.4.0/drivers/iio/industrialio-trigger.c
@@ -549,7 +549,6 @@
 		irq_modify_status(trig->subirq_base + i,
 				  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
 	}
-	get_device(&trig->dev);
 
 	return trig;
 
--- linux-ein-5.4.0.orig/drivers/iio/inkern.c
+++ linux-ein-5.4.0/drivers/iio/inkern.c
@@ -136,9 +136,10 @@
 
 	idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
 			       iio_dev_node_match);
-	of_node_put(iiospec.np);
-	if (idev == NULL)
+	if (idev == NULL) {
+		of_node_put(iiospec.np);
 		return -EPROBE_DEFER;
+	}
 
 	indio_dev = dev_to_iio_dev(idev);
 	channel->indio_dev = indio_dev;
@@ -146,6 +147,7 @@
 		index = indio_dev->info->of_xlate(indio_dev, &iiospec);
 	else
 		index = __of_iio_simple_xlate(indio_dev, &iiospec);
+	of_node_put(iiospec.np);
 	if (index < 0)
 		goto err_put;
 	channel->channel = &indio_dev->channels[index];
@@ -588,28 +590,50 @@
 static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
 	int raw, int *processed, unsigned int scale)
 {
-	int scale_type, scale_val, scale_val2, offset;
+	int scale_type, scale_val, scale_val2;
+	int offset_type, offset_val, offset_val2;
 	s64 raw64 = raw;
-	int ret;
 
-	ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET);
-	if (ret >= 0)
-		raw64 += offset;
+	offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
+				       IIO_CHAN_INFO_OFFSET);
+	if (offset_type >= 0) {
+		switch (offset_type) {
+		case IIO_VAL_INT:
+			break;
+		case IIO_VAL_INT_PLUS_MICRO:
+		case IIO_VAL_INT_PLUS_NANO:
+			/*
+			 * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO
+			 * implicitely truncate the offset to it's integer form.
+			 */
+			break;
+		case IIO_VAL_FRACTIONAL:
+			offset_val /= offset_val2;
+			break;
+		case IIO_VAL_FRACTIONAL_LOG2:
+			offset_val >>= offset_val2;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		raw64 += offset_val;
+	}
 
 	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
 					IIO_CHAN_INFO_SCALE);
 	if (scale_type < 0) {
 		/*
-		 * Just pass raw values as processed if no scaling is
-		 * available.
+		 * If no channel scaling is available apply consumer scale to
+		 * raw value and return.
 		 */
-		*processed = raw;
+		*processed = raw * scale;
 		return 0;
 	}
 
 	switch (scale_type) {
 	case IIO_VAL_INT:
-		*processed = raw64 * scale_val;
+		*processed = raw64 * scale_val * scale;
 		break;
 	case IIO_VAL_INT_PLUS_MICRO:
 		if (scale_val2 < 0)
--- linux-ein-5.4.0.orig/drivers/iio/light/Kconfig
+++ linux-ein-5.4.0/drivers/iio/light/Kconfig
@@ -239,6 +239,8 @@
 	tristate "ROHM RPR0521 ALS and proximity sensor driver"
 	depends on I2C
 	select REGMAP_I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say Y here if you want to build support for ROHM's RPR0521
 	  ambient light and proximity sensor device.
@@ -485,6 +487,7 @@
 
 config VCNL4035
 	tristate "VCNL4035 combined ALS and proximity sensor"
+	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	select REGMAP_I2C
 	depends on I2C
--- linux-ein-5.4.0.orig/drivers/iio/light/apds9960.c
+++ linux-ein-5.4.0/drivers/iio/light/apds9960.c
@@ -55,9 +55,6 @@
 #define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT	2
 
 #define APDS9960_REG_CONFIG_2	0x90
-#define APDS9960_REG_CONFIG_2_GGAIN_MASK	0x60
-#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT	5
-
 #define APDS9960_REG_ID		0x92
 
 #define APDS9960_REG_STATUS	0x93
@@ -78,6 +75,9 @@
 #define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT	6
 
 #define APDS9960_REG_GCONF_2	0xa3
+#define APDS9960_REG_GCONF_2_GGAIN_MASK			0x60
+#define APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT		5
+
 #define APDS9960_REG_GOFFSET_U	0xa4
 #define APDS9960_REG_GOFFSET_D	0xa5
 #define APDS9960_REG_GPULSE	0xa6
@@ -397,9 +397,9 @@
 			}
 
 			ret = regmap_update_bits(data->regmap,
-				APDS9960_REG_CONFIG_2,
-				APDS9960_REG_CONFIG_2_GGAIN_MASK,
-				idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
+				APDS9960_REG_GCONF_2,
+				APDS9960_REG_GCONF_2_GGAIN_MASK,
+				idx << APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT);
 			if (!ret)
 				data->pxs_gain = idx;
 			mutex_unlock(&data->lock);
--- linux-ein-5.4.0.orig/drivers/iio/light/bh1750.c
+++ linux-ein-5.4.0/drivers/iio/light/bh1750.c
@@ -59,9 +59,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-ein-5.4.0.orig/drivers/iio/light/hid-sensor-prox.c
+++ linux-ein-5.4.0/drivers/iio/light/hid-sensor-prox.c
@@ -25,6 +25,9 @@
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info prox_attr;
 	u32 human_presence;
+	int scale_pre_decml;
+	int scale_post_decml;
+	int scale_precision;
 };
 
 /* Channel definitions */
@@ -95,8 +98,9 @@
 		ret_type = IIO_VAL_INT;
 		break;
 	case IIO_CHAN_INFO_SCALE:
-		*val = prox_state->prox_attr.units;
-		ret_type = IIO_VAL_INT;
+		*val = prox_state->scale_pre_decml;
+		*val2 = prox_state->scale_post_decml;
+		ret_type = prox_state->scale_precision;
 		break;
 	case IIO_CHAN_INFO_OFFSET:
 		*val = hid_sensor_convert_exponent(
@@ -236,6 +240,11 @@
 			HID_USAGE_SENSOR_HUMAN_PRESENCE,
 			&st->common_attributes.sensitivity);
 
+	st->scale_precision = hid_sensor_format_scale(
+				hsdev->usage,
+				&st->prox_attr,
+				&st->scale_pre_decml, &st->scale_post_decml);
+
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/iio/light/isl29028.c
+++ linux-ein-5.4.0/drivers/iio/light/isl29028.c
@@ -628,7 +628,7 @@
 					 ISL29028_POWER_OFF_DELAY_MS);
 	pm_runtime_use_autosuspend(&client->dev);
 
-	ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
+	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev,
 			"%s(): iio registration failed with error %d\n",
--- linux-ein-5.4.0.orig/drivers/iio/light/isl29125.c
+++ linux-ein-5.4.0/drivers/iio/light/isl29125.c
@@ -51,7 +51,11 @@
 struct isl29125_data {
 	struct i2c_client *client;
 	u8 conf1;
-	u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u16 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 #define ISL29125_CHANNEL(_color, _si) { \
@@ -184,10 +188,10 @@
 		if (ret < 0)
 			goto done;
 
-		data->buffer[j++] = ret;
+		data->scan.chans[j++] = ret;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 		iio_get_time_ns(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/light/ltr501.c
+++ linux-ein-5.4.0/drivers/iio/light/ltr501.c
@@ -32,9 +32,12 @@
 #define LTR501_PART_ID 0x86
 #define LTR501_MANUFAC_ID 0x87
 #define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
+#define LTR501_ALS_DATA1_UPPER 0x89 /* upper 8 bits of LTR501_ALS_DATA1 */
 #define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
+#define LTR501_ALS_DATA0_UPPER 0x8b /* upper 8 bits of LTR501_ALS_DATA0 */
 #define LTR501_ALS_PS_STATUS 0x8c
 #define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
+#define LTR501_PS_DATA_UPPER 0x8e /* upper 8 bits of LTR501_PS_DATA */
 #define LTR501_INTR 0x8f /* output mode, polarity, mode */
 #define LTR501_PS_THRESH_UP 0x90 /* 11 bit, ps upper threshold */
 #define LTR501_PS_THRESH_LOW 0x92 /* 11 bit, ps lower threshold */
@@ -405,18 +408,19 @@
 
 static int ltr501_read_ps(struct ltr501_data *data)
 {
-	int ret, status;
+	__le16 status;
+	int ret;
 
 	ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
 	if (ret < 0)
 		return ret;
 
 	ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
-			       &status, 2);
+			       &status, sizeof(status));
 	if (ret < 0)
 		return ret;
 
-	return status;
+	return le16_to_cpu(status);
 }
 
 static int ltr501_read_intr_prst(struct ltr501_data *data,
@@ -1204,7 +1208,7 @@
 		.als_gain_tbl_size = ARRAY_SIZE(ltr559_als_gain_tbl),
 		.ps_gain = ltr559_ps_gain_tbl,
 		.ps_gain_tbl_size = ARRAY_SIZE(ltr559_ps_gain_tbl),
-		.als_mode_active = BIT(1),
+		.als_mode_active = BIT(0),
 		.als_gain_mask = BIT(2) | BIT(3) | BIT(4),
 		.als_gain_shift = 2,
 		.info = &ltr501_info,
@@ -1242,13 +1246,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) ||
@@ -1265,11 +1272,11 @@
 		ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
 				       (u8 *)als_buf, sizeof(als_buf));
 		if (ret < 0)
-			return ret;
+			goto done;
 		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) {
@@ -1277,10 +1284,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_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 done:
@@ -1350,9 +1357,12 @@
 {
 	switch (reg) {
 	case LTR501_ALS_DATA1:
+	case LTR501_ALS_DATA1_UPPER:
 	case LTR501_ALS_DATA0:
+	case LTR501_ALS_DATA0_UPPER:
 	case LTR501_ALS_PS_STATUS:
 	case LTR501_PS_DATA:
+	case LTR501_PS_DATA_UPPER:
 		return true;
 	default:
 		return false;
--- linux-ein-5.4.0.orig/drivers/iio/light/max44000.c
+++ linux-ein-5.4.0/drivers/iio/light/max44000.c
@@ -75,6 +75,11 @@
 struct max44000_data {
 	struct mutex lock;
 	struct regmap *regmap;
+	/* Ensure naturally aligned timestamp */
+	struct {
+		u16 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */
@@ -488,7 +493,6 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct max44000_data *data = iio_priv(indio_dev);
-	u16 buf[8]; /* 2x u16 + padding + 8 bytes timestamp */
 	int index = 0;
 	unsigned int regval;
 	int ret;
@@ -498,17 +502,17 @@
 		ret = max44000_read_alsval(data);
 		if (ret < 0)
 			goto out_unlock;
-		buf[index++] = ret;
+		data->scan.channels[index++] = ret;
 	}
 	if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) {
 		ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
 		if (ret < 0)
 			goto out_unlock;
-		buf[index] = regval;
+		data->scan.channels[index] = regval;
 	}
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 	iio_trigger_notify_done(indio_dev->trig);
 	return IRQ_HANDLED;
--- linux-ein-5.4.0.orig/drivers/iio/light/max44009.c
+++ linux-ein-5.4.0/drivers/iio/light/max44009.c
@@ -529,6 +529,12 @@
 	return devm_iio_device_register(&client->dev, indio_dev);
 }
 
+static const struct of_device_id max44009_of_match[] = {
+	{ .compatible = "maxim,max44009" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max44009_of_match);
+
 static const struct i2c_device_id max44009_id[] = {
 	{ "max44009", 0 },
 	{ }
@@ -538,18 +544,13 @@
 static struct i2c_driver max44009_driver = {
 	.driver = {
 		.name = MAX44009_DRV_NAME,
+		.of_match_table = max44009_of_match,
 	},
 	.probe = max44009_probe,
 	.id_table = max44009_id,
 };
 module_i2c_driver(max44009_driver);
 
-static const struct of_device_id max44009_of_match[] = {
-	{ .compatible = "maxim,max44009" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, max44009_of_match);
-
 MODULE_AUTHOR("Robert Eshleman <bobbyeshleman@gmail.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MAX44009 ambient light sensor driver");
--- linux-ein-5.4.0.orig/drivers/iio/light/opt3001.c
+++ linux-ein-5.4.0/drivers/iio/light/opt3001.c
@@ -275,6 +275,8 @@
 		ret = wait_event_timeout(opt->result_ready_queue,
 				opt->result_ready,
 				msecs_to_jiffies(OPT3001_RESULT_READY_LONG));
+		if (ret == 0)
+			return -ETIMEDOUT;
 	} else {
 		/* Sleep for result ready time */
 		timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ?
@@ -311,9 +313,7 @@
 		/* Disallow IRQ to access the device while lock is active */
 		opt->ok_to_ignore_lock = false;
 
-	if (ret == 0)
-		return -ETIMEDOUT;
-	else if (ret < 0)
+	if (ret < 0)
 		return ret;
 
 	if (opt->use_irq) {
--- linux-ein-5.4.0.orig/drivers/iio/light/rpr0521.c
+++ linux-ein-5.4.0/drivers/iio/light/rpr0521.c
@@ -194,6 +194,17 @@
 	bool pxs_need_dis;
 
 	struct regmap *regmap;
+
+	/*
+	 * Ensure correct naturally aligned timestamp.
+	 * Note that the read will put garbage data into
+	 * the padding but this should not be a problem
+	 */
+	struct {
+		__le16 channels[3];
+		u8 garbage;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
@@ -449,8 +460,6 @@
 	struct rpr0521_data *data = iio_priv(indio_dev);
 	int err;
 
-	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
-
 	/* Use irq timestamp when reasonable. */
 	if (iio_trigger_using_own(indio_dev) && data->irq_timestamp) {
 		pf->timestamp = data->irq_timestamp;
@@ -461,11 +470,11 @@
 		pf->timestamp = iio_get_time_ns(indio_dev);
 
 	err = regmap_bulk_read(data->regmap, RPR0521_REG_PXS_DATA,
-		&buffer,
+		data->scan.channels,
 		(3 * 2) + 1);	/* 3 * 16-bit + (discarded) int clear reg. */
 	if (!err)
 		iio_push_to_buffers_with_timestamp(indio_dev,
-						   buffer, pf->timestamp);
+						   &data->scan, pf->timestamp);
 	else
 		dev_err(&data->client->dev,
 			"Trigger consumer can't read from sensor.\n");
--- linux-ein-5.4.0.orig/drivers/iio/light/si1133.c
+++ linux-ein-5.4.0/drivers/iio/light/si1133.c
@@ -102,6 +102,9 @@
 #define SI1133_INPUT_FRACTION_LOW	15
 #define SI1133_LUX_OUTPUT_FRACTION	12
 #define SI1133_LUX_BUFFER_SIZE		9
+#define SI1133_MEASURE_BUFFER_SIZE	3
+
+#define SI1133_SIGN_BIT_INDEX 23
 
 static const int si1133_scale_available[] = {
 	1, 2, 4, 8, 16, 32, 64, 128};
@@ -234,13 +237,13 @@
 	}
 };
 
-static int si1133_calculate_polynomial_inner(u32 input, u8 fraction, u16 mag,
+static int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag,
 					     s8 shift)
 {
 	return ((input << fraction) / mag) << shift;
 }
 
-static int si1133_calculate_output(u32 x, u32 y, u8 x_order, u8 y_order,
+static int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order,
 				   u8 input_fraction, s8 sign,
 				   const struct si1133_coeff *coeffs)
 {
@@ -276,7 +279,7 @@
  * The algorithm is from:
  * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716
  */
-static int si1133_calc_polynomial(u32 x, u32 y, u8 input_fraction, u8 num_coeff,
+static int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff,
 				  const struct si1133_coeff *coeffs)
 {
 	u8 x_order, y_order;
@@ -614,7 +617,7 @@
 {
 	int err;
 
-	__be16 resp;
+	u8 buffer[SI1133_MEASURE_BUFFER_SIZE];
 
 	err = si1133_set_adcmux(data, 0, chan->channel);
 	if (err)
@@ -625,12 +628,13 @@
 	if (err)
 		return err;
 
-	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(resp),
-			       (u8 *)&resp);
+	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer),
+			       buffer);
 	if (err)
 		return err;
 
-	*val = be16_to_cpu(resp);
+	*val = sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
+			     SI1133_SIGN_BIT_INDEX);
 
 	return err;
 }
@@ -704,9 +708,9 @@
 {
 	int err;
 	int lux;
-	u32 high_vis;
-	u32 low_vis;
-	u32 ir;
+	s32 high_vis;
+	s32 low_vis;
+	s32 ir;
 	u8 buffer[SI1133_LUX_BUFFER_SIZE];
 
 	/* Activate lux channels */
@@ -719,9 +723,16 @@
 	if (err)
 		return err;
 
-	high_vis = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
-	low_vis = (buffer[3] << 16) | (buffer[4] << 8) | buffer[5];
-	ir = (buffer[6] << 16) | (buffer[7] << 8) | buffer[8];
+	high_vis =
+		sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
+			      SI1133_SIGN_BIT_INDEX);
+
+	low_vis =
+		sign_extend32((buffer[3] << 16) | (buffer[4] << 8) | buffer[5],
+			      SI1133_SIGN_BIT_INDEX);
+
+	ir = sign_extend32((buffer[6] << 16) | (buffer[7] << 8) | buffer[8],
+			   SI1133_SIGN_BIT_INDEX);
 
 	if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)
 		lux = si1133_calc_polynomial(high_vis, ir,
--- linux-ein-5.4.0.orig/drivers/iio/light/si1145.c
+++ linux-ein-5.4.0/drivers/iio/light/si1145.c
@@ -169,6 +169,7 @@
  * @part_info:	Part information
  * @trig:	Pointer to iio trigger
  * @meas_rate:	Value of MEAS_RATE register. Only set in HW in auto mode
+ * @buffer:	Used to pack data read from sensor.
  */
 struct si1145_data {
 	struct i2c_client *client;
@@ -180,6 +181,14 @@
 	bool autonomous;
 	struct iio_trigger *trig;
 	int meas_rate;
+	/*
+	 * Ensure timestamp will be naturally aligned if present.
+	 * Maximum buffer size (may be only partly used if not all
+	 * channels are enabled):
+	 *   6*2 bytes channels data + 4 bytes alignment +
+	 *   8 bytes timestamp
+	 */
+	u8 buffer[24] __aligned(8);
 };
 
 /**
@@ -441,12 +450,6 @@
 	struct iio_poll_func *pf = private;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct si1145_data *data = iio_priv(indio_dev);
-	/*
-	 * Maximum buffer size:
-	 *   6*2 bytes channels data + 4 bytes alignment +
-	 *   8 bytes timestamp
-	 */
-	u8 buffer[24];
 	int i, j = 0;
 	int ret;
 	u8 irq_status = 0;
@@ -479,7 +482,7 @@
 
 		ret = i2c_smbus_read_i2c_block_data_or_emulated(
 				data->client, indio_dev->channels[i].address,
-				sizeof(u16) * run, &buffer[j]);
+				sizeof(u16) * run, &data->buffer[j]);
 		if (ret < 0)
 			goto done;
 		j += run * sizeof(u16);
@@ -494,7 +497,7 @@
 			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(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/light/st_uvis25.h
+++ linux-ein-5.4.0/drivers/iio/light/st_uvis25.h
@@ -27,6 +27,11 @@
 	struct iio_trigger *trig;
 	bool enabled;
 	int irq;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u8 chan;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 extern const struct dev_pm_ops st_uvis25_pm_ops;
--- linux-ein-5.4.0.orig/drivers/iio/light/st_uvis25_core.c
+++ linux-ein-5.4.0/drivers/iio/light/st_uvis25_core.c
@@ -234,17 +234,19 @@
 
 static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
 {
-	u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
 	struct iio_poll_func *pf = p;
 	struct iio_dev *iio_dev = pf->indio_dev;
 	struct st_uvis25_hw *hw = iio_priv(iio_dev);
+	unsigned int val;
 	int err;
 
-	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+	err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, &val);
 	if (err < 0)
 		goto out;
 
-	iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+	hw->scan.chan = val;
+
+	iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 					   iio_get_time_ns(iio_dev));
 
 out:
--- linux-ein-5.4.0.orig/drivers/iio/light/stk3310.c
+++ linux-ein-5.4.0/drivers/iio/light/stk3310.c
@@ -544,9 +544,8 @@
 	mutex_lock(&data->lock);
 	ret = regmap_field_read(data->reg_flag_nf, &dir);
 	if (ret < 0) {
-		dev_err(&data->client->dev, "register read failed\n");
-		mutex_unlock(&data->lock);
-		return ret;
+		dev_err(&data->client->dev, "register read failed: %d\n", ret);
+		goto out;
 	}
 	event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
 				     IIO_EV_TYPE_THRESH,
@@ -558,6 +557,7 @@
 	ret = regmap_field_write(data->reg_flag_psint, 0);
 	if (ret < 0)
 		dev_err(&data->client->dev, "failed to reset interrupts\n");
+out:
 	mutex_unlock(&data->lock);
 
 	return IRQ_HANDLED;
--- linux-ein-5.4.0.orig/drivers/iio/light/tcs3414.c
+++ linux-ein-5.4.0/drivers/iio/light/tcs3414.c
@@ -53,7 +53,11 @@
 	u8 control;
 	u8 gain;
 	u8 timing;
-	u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u16 chans[4];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 #define TCS3414_CHANNEL(_color, _si, _addr) { \
@@ -209,10 +213,10 @@
 		if (ret < 0)
 			goto done;
 
-		data->buffer[j++] = ret;
+		data->scan.chans[j++] = ret;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 		iio_get_time_ns(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/light/tcs3472.c
+++ linux-ein-5.4.0/drivers/iio/light/tcs3472.c
@@ -64,7 +64,11 @@
 	u8 control;
 	u8 atime;
 	u8 apers;
-	u16 buffer[8]; /* 4 16-bit channels + 64-bit timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u16 chans[4];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 static const struct iio_event_spec tcs3472_events[] = {
@@ -386,10 +390,10 @@
 		if (ret < 0)
 			goto done;
 
-		data->buffer[j++] = ret;
+		data->scan.chans[j++] = ret;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 		iio_get_time_ns(indio_dev));
 
 done:
@@ -532,7 +536,8 @@
 	return 0;
 
 free_irq:
-	free_irq(client->irq, indio_dev);
+	if (client->irq)
+		free_irq(client->irq, indio_dev);
 buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
 	return ret;
@@ -560,7 +565,8 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	free_irq(client->irq, indio_dev);
+	if (client->irq)
+		free_irq(client->irq, indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	tcs3472_powerdown(iio_priv(indio_dev));
 
--- linux-ein-5.4.0.orig/drivers/iio/light/tsl2583.c
+++ linux-ein-5.4.0/drivers/iio/light/tsl2583.c
@@ -341,6 +341,14 @@
 		return lux_val;
 	}
 
+	/* Avoid division by zero of lux_value later on */
+	if (lux_val == 0) {
+		dev_err(&chip->client->dev,
+			"%s: lux_val of 0 will produce out of range trim_value\n",
+			__func__);
+		return -ENODATA;
+	}
+
 	gain_trim_val = (unsigned int)(((chip->als_settings.als_cal_target)
 			* chip->als_settings.als_gain_trim) / lux_val);
 	if ((gain_trim_val < 250) || (gain_trim_val > 4000)) {
@@ -849,7 +857,7 @@
 					 TSL2583_POWER_OFF_DELAY_MS);
 	pm_runtime_use_autosuspend(&clientp->dev);
 
-	ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
+	ret = iio_device_register(indio_dev);
 	if (ret) {
 		dev_err(&clientp->dev, "%s: iio registration failed\n",
 			__func__);
--- linux-ein-5.4.0.orig/drivers/iio/light/tsl2772.c
+++ linux-ein-5.4.0/drivers/iio/light/tsl2772.c
@@ -606,6 +606,7 @@
 			return -EINVAL;
 		}
 	}
+	chip->settings.prox_diode = prox_diode_mask;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/iio/light/vcnl4000.c
+++ linux-ein-5.4.0/drivers/iio/light/vcnl4000.c
@@ -163,20 +163,22 @@
 	if (ret < 0)
 		return ret;
 
-	data->al_scale = 24000;
 	data->vcnl4200_al.reg = VCNL4200_AL_DATA;
 	data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
 	switch (id) {
 	case VCNL4200_PROD_ID:
-		/* Integration time is 50ms, but the experiments */
-		/* show 54ms in total. */
-		data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
-		data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
+		/* Default wait time is 50ms, add 20% tolerance. */
+		data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
+		/* Default wait time is 4.8ms, add 20% tolerance. */
+		data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
+		data->al_scale = 24000;
 		break;
 	case VCNL4040_PROD_ID:
-		/* Integration time is 80ms, add 10ms. */
-		data->vcnl4200_al.sampling_rate = ktime_set(0, 100000 * 1000);
-		data->vcnl4200_ps.sampling_rate = ktime_set(0, 100000 * 1000);
+		/* Default wait time is 80ms, add 20% tolerance. */
+		data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
+		/* Default wait time is 5ms, add 20% tolerance. */
+		data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
+		data->al_scale = 120000;
 		break;
 	}
 	data->vcnl4200_al.last_measurement = ktime_set(0, 0);
@@ -191,7 +193,6 @@
 				u8 rdy_mask, u8 data_reg, int *val)
 {
 	int tries = 20;
-	__be16 buf;
 	int ret;
 
 	mutex_lock(&data->vcnl4000_lock);
@@ -218,13 +219,12 @@
 		goto fail;
 	}
 
-	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)
 		goto fail;
 
 	mutex_unlock(&data->vcnl4000_lock);
-	*val = be16_to_cpu(buf);
+	*val = ret;
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/iio/light/vcnl4035.c
+++ linux-ein-5.4.0/drivers/iio/light/vcnl4035.c
@@ -8,6 +8,7 @@
  * TODO: Proximity
  */
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -42,6 +43,7 @@
 #define VCNL4035_ALS_PERS_MASK		GENMASK(3, 2)
 #define VCNL4035_INT_ALS_IF_H_MASK	BIT(12)
 #define VCNL4035_INT_ALS_IF_L_MASK	BIT(13)
+#define VCNL4035_DEV_ID_MASK		GENMASK(7, 0)
 
 /* Default values */
 #define VCNL4035_MODE_ALS_ENABLE	BIT(0)
@@ -102,7 +104,8 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct vcnl4035_data *data = iio_priv(indio_dev);
-	u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)];
+	/* Ensure naturally aligned timestamp */
+	u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)]  __aligned(8);
 	int ret;
 
 	ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
@@ -414,6 +417,7 @@
 		return ret;
 	}
 
+	id = FIELD_GET(VCNL4035_DEV_ID_MASK, id);
 	if (id != VCNL4035_DEV_ID_VAL) {
 		dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
 			id, VCNL4035_DEV_ID_VAL);
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/ak8974.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/ak8974.c
@@ -185,6 +185,11 @@
 	bool drdy_irq;
 	struct completion drdy_complete;
 	bool drdy_active_low;
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		__le16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static const char ak8974_reg_avdd[] = "avdd";
@@ -564,7 +569,7 @@
 		 * We read all axes and discard all but one, for optimized
 		 * reading, use the triggered buffer.
 		 */
-		*val = le16_to_cpu(hw_values[chan->address]);
+		*val = (s16)le16_to_cpu(hw_values[chan->address]);
 
 		ret = IIO_VAL_INT;
 	}
@@ -581,7 +586,6 @@
 {
 	struct ak8974 *ak8974 = iio_priv(indio_dev);
 	int ret;
-	__le16 hw_values[8]; /* Three axes + 64bit padding */
 
 	pm_runtime_get_sync(&ak8974->i2c->dev);
 	mutex_lock(&ak8974->lock);
@@ -591,13 +595,13 @@
 		dev_err(&ak8974->i2c->dev, "error triggering measure\n");
 		goto out_unlock;
 	}
-	ret = ak8974_getresult(ak8974, hw_values);
+	ret = ak8974_getresult(ak8974, ak8974->scan.channels);
 	if (ret) {
 		dev_err(&ak8974->i2c->dev, "error getting measures\n");
 		goto out_unlock;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, hw_values,
+	iio_push_to_buffers_with_timestamp(indio_dev, &ak8974->scan,
 					   iio_get_time_ns(indio_dev));
 
  out_unlock:
@@ -764,19 +768,21 @@
 	ak8974->map = devm_regmap_init_i2c(i2c, &ak8974_regmap_config);
 	if (IS_ERR(ak8974->map)) {
 		dev_err(&i2c->dev, "failed to allocate register map\n");
+		pm_runtime_put_noidle(&i2c->dev);
+		pm_runtime_disable(&i2c->dev);
 		return PTR_ERR(ak8974->map);
 	}
 
 	ret = ak8974_set_power(ak8974, AK8974_PWR_ON);
 	if (ret) {
 		dev_err(&i2c->dev, "could not power on\n");
-		goto power_off;
+		goto disable_pm;
 	}
 
 	ret = ak8974_detect(ak8974);
 	if (ret) {
 		dev_err(&i2c->dev, "neither AK8974 nor AMI30x found\n");
-		goto power_off;
+		goto disable_pm;
 	}
 
 	ret = ak8974_selftest(ak8974);
@@ -786,14 +792,9 @@
 	ret = ak8974_reset(ak8974);
 	if (ret) {
 		dev_err(&i2c->dev, "AK8974 reset failed\n");
-		goto power_off;
+		goto disable_pm;
 	}
 
-	pm_runtime_set_autosuspend_delay(&i2c->dev,
-					 AK8974_AUTOSUSPEND_DELAY);
-	pm_runtime_use_autosuspend(&i2c->dev);
-	pm_runtime_put(&i2c->dev);
-
 	indio_dev->dev.parent = &i2c->dev;
 	indio_dev->channels = ak8974_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ak8974_channels);
@@ -846,6 +847,11 @@
 		goto cleanup_buffer;
 	}
 
+	pm_runtime_set_autosuspend_delay(&i2c->dev,
+					 AK8974_AUTOSUSPEND_DELAY);
+	pm_runtime_use_autosuspend(&i2c->dev);
+	pm_runtime_put(&i2c->dev);
+
 	return 0;
 
 cleanup_buffer:
@@ -854,7 +860,6 @@
 	pm_runtime_put_noidle(&i2c->dev);
 	pm_runtime_disable(&i2c->dev);
 	ak8974_set_power(ak8974, AK8974_PWR_OFF);
-power_off:
 	regulator_bulk_disable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/ak8975.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/ak8975.c
@@ -368,6 +368,12 @@
 	struct iio_mount_matrix orientation;
 	struct regulator	*vdd;
 	struct regulator	*vid;
+
+	/* Ensure natural alignment of timestamp */
+	struct {
+		s16 channels[3];
+		s64 ts __aligned(8);
+	} scan;
 };
 
 /* Enable attached power regulator if any. */
@@ -385,6 +391,7 @@
 	if (ret) {
 		dev_warn(&data->client->dev,
 			 "Failed to enable specified Vid supply\n");
+		regulator_disable(data->vdd);
 		return ret;
 	}
 	/*
@@ -805,7 +812,6 @@
 	const struct i2c_client *client = data->client;
 	const struct ak_def *def = data->def;
 	int ret;
-	s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */
 	__le16 fval[3];
 
 	mutex_lock(&data->lock);
@@ -828,12 +834,13 @@
 	mutex_unlock(&data->lock);
 
 	/* Clamp to valid range. */
-	buff[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
-	buff[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
-	buff[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
+	data->scan.channels[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
+	data->scan.channels[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
+	data->scan.channels[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buff,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
+
 	return;
 
 unlock:
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/bmc150_magn.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/bmc150_magn.c
@@ -136,8 +136,11 @@
 	struct mutex mutex;
 	struct regmap *regmap;
 	struct iio_mount_matrix orientation;
-	/* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
-	s32 buffer[6];
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s32 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 	struct iio_trigger *dready_trig;
 	bool dready_trigger_on;
 	int max_odr;
@@ -260,7 +263,7 @@
 	int ret;
 
 	if (on) {
-		ret = pm_runtime_get_sync(data->dev);
+		ret = pm_runtime_resume_and_get(data->dev);
 	} else {
 		pm_runtime_mark_last_busy(data->dev);
 		ret = pm_runtime_put_autosuspend(data->dev);
@@ -269,9 +272,6 @@
 	if (ret < 0) {
 		dev_err(data->dev,
 			"failed to change power state to %d\n", on);
-		if (on)
-			pm_runtime_put_noidle(data->dev);
-
 		return ret;
 	}
 #endif
@@ -673,11 +673,11 @@
 	int ret;
 
 	mutex_lock(&data->mutex);
-	ret = bmc150_magn_read_xyz(data, data->buffer);
+	ret = bmc150_magn_read_xyz(data, data->scan.chans);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   pf->timestamp);
 
 err:
@@ -944,12 +944,15 @@
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(dev, "unable to register iio device\n");
-		goto err_buffer_cleanup;
+		goto err_pm_cleanup;
 	}
 
 	dev_dbg(dev, "Registered device %s\n", name);
 	return 0;
 
+err_pm_cleanup:
+	pm_runtime_dont_use_autosuspend(dev);
+	pm_runtime_disable(dev);
 err_buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
 err_free_irq:
@@ -973,7 +976,6 @@
 
 	pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
-	pm_runtime_put_noidle(dev);
 
 	iio_triggered_buffer_cleanup(indio_dev);
 
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/hmc5843.h
+++ linux-ein-5.4.0/drivers/iio/magnetometer/hmc5843.h
@@ -33,7 +33,8 @@
  * @lock:		update and read regmap data
  * @regmap:		hardware access register maps
  * @variant:		describe chip variants
- * @buffer:		3x 16-bit channels + padding + 64-bit timestamp
+ * @scan:		buffer to pack data for passing to
+ *			iio_push_to_buffers_with_timestamp()
  */
 struct hmc5843_data {
 	struct device *dev;
@@ -41,7 +42,10 @@
 	struct regmap *regmap;
 	const struct hmc5843_chip_info *variant;
 	struct iio_mount_matrix orientation;
-	__be16 buffer[8];
+	struct {
+		__be16 chans[3];
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/hmc5843_core.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/hmc5843_core.c
@@ -446,13 +446,13 @@
 	}
 
 	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
-			       data->buffer, 3 * sizeof(__be16));
+			       data->scan.chans, sizeof(data->scan.chans));
 
 	mutex_unlock(&data->lock);
 	if (ret < 0)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 					   iio_get_time_ns(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/mag3110.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/mag3110.c
@@ -56,6 +56,12 @@
 	int sleep_val;
 	struct regulator *vdd_reg;
 	struct regulator *vddio_reg;
+	/* Ensure natural alignment of timestamp */
+	struct {
+		__be16 channels[3];
+		u8 temperature;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static int mag3110_request(struct mag3110_data *data)
@@ -387,10 +393,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;
 
@@ -399,10 +404,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(indio_dev));
 
 done:
--- linux-ein-5.4.0.orig/drivers/iio/magnetometer/rm3100-core.c
+++ linux-ein-5.4.0/drivers/iio/magnetometer/rm3100-core.c
@@ -76,7 +76,8 @@
 	bool use_interrupt;
 	int conversion_time;
 	int scale;
-	u8 buffer[RM3100_SCAN_BYTES];
+	/* Ensure naturally aligned timestamp */
+	u8 buffer[RM3100_SCAN_BYTES] __aligned(8);
 	struct iio_trigger *drdy_trig;
 
 	/*
@@ -538,6 +539,7 @@
 	struct rm3100_data *data;
 	unsigned int tmp;
 	int ret;
+	int samp_rate_index;
 
 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (!indio_dev)
@@ -597,9 +599,14 @@
 	ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp);
 	if (ret < 0)
 		return ret;
+
+	samp_rate_index = tmp - RM3100_TMRC_OFFSET;
+	if (samp_rate_index < 0 || samp_rate_index >=  RM3100_SAMP_NUM) {
+		dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n");
+		return -EINVAL;
+	}
 	/* Initializing max wait time, which is double conversion time. */
-	data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2]
-				* 2;
+	data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2;
 
 	/* Cycle count values may not be what we want. */
 	if ((tmp - RM3100_TMRC_OFFSET) == 0)
--- linux-ein-5.4.0.orig/drivers/iio/potentiostat/lmp91000.c
+++ linux-ein-5.4.0/drivers/iio/potentiostat/lmp91000.c
@@ -71,8 +71,8 @@
 
 	struct completion completion;
 	u8 chan_select;
-
-	u32 buffer[4]; /* 64-bit data + 64-bit timestamp */
+	/* 64-bit data + 64-bit naturally aligned timestamp */
+	u32 buffer[4] __aligned(8);
 };
 
 static const struct iio_chan_spec lmp91000_channels[] = {
--- linux-ein-5.4.0.orig/drivers/iio/pressure/bmp280-core.c
+++ linux-ein-5.4.0/drivers/iio/pressure/bmp280-core.c
@@ -264,6 +264,8 @@
 		+ (s32)2097152) * calib->H2 + 8192) >> 14);
 	var -= ((((var >> 15) * (var >> 15)) >> 7) * (s32)calib->H1) >> 4;
 
+	var = clamp_val(var, 0, 419430400);
+
 	return var >> 12;
 };
 
@@ -706,7 +708,7 @@
 	unsigned int ctrl;
 
 	if (data->use_eoc)
-		init_completion(&data->done);
+		reinit_completion(&data->done);
 
 	ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas);
 	if (ret)
@@ -962,6 +964,9 @@
 			"trying to enforce it\n");
 		irq_trig = IRQF_TRIGGER_RISING;
 	}
+
+	init_completion(&data->done);
+
 	ret = devm_request_threaded_irq(dev,
 			irq,
 			bmp085_eoc_irq,
@@ -1108,7 +1113,7 @@
 	 * however as it happens, the BMP085 shares the chip ID of BMP180
 	 * so we look for an IRQ if we have that.
 	 */
-	if (irq > 0 || (chip_id  == BMP180_CHIP_ID)) {
+	if (irq > 0 && (chip_id  == BMP180_CHIP_ID)) {
 		ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
 		if (ret)
 			goto out_disable_vdda;
--- linux-ein-5.4.0.orig/drivers/iio/pressure/cros_ec_baro.c
+++ linux-ein-5.4.0/drivers/iio/pressure/cros_ec_baro.c
@@ -114,6 +114,7 @@
 static const struct iio_info cros_ec_baro_info = {
 	.read_raw = &cros_ec_baro_read,
 	.write_raw = &cros_ec_baro_write,
+	.read_avail = &cros_ec_sensors_core_read_avail,
 };
 
 static int cros_ec_baro_probe(struct platform_device *pdev)
@@ -149,6 +150,8 @@
 		BIT(IIO_CHAN_INFO_SCALE) |
 		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 		BIT(IIO_CHAN_INFO_FREQUENCY);
+	channel->info_mask_shared_by_all_available =
+		BIT(IIO_CHAN_INFO_SAMP_FREQ);
 	channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
 	channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
 	channel->scan_type.shift = 0;
--- linux-ein-5.4.0.orig/drivers/iio/pressure/dps310.c
+++ linux-ein-5.4.0/drivers/iio/pressure/dps310.c
@@ -57,8 +57,8 @@
 #define  DPS310_RESET_MAGIC	0x09
 #define DPS310_COEF_BASE	0x10
 
-/* Make sure sleep time is <= 20ms for usleep_range */
-#define DPS310_POLL_SLEEP_US(t)		min(20000, (t) / 8)
+/* Make sure sleep time is <= 30ms for usleep_range */
+#define DPS310_POLL_SLEEP_US(t)		min(30000, (t) / 8)
 /* Silently handle error in rate value here */
 #define DPS310_POLL_TIMEOUT_US(rc)	((rc) <= 0 ? 1000000 : 1000000 / (rc))
 
@@ -89,6 +89,7 @@
 	s32 c00, c10, c20, c30, c01, c11, c21;
 	s32 pressure_raw;
 	s32 temp_raw;
+	bool timeout_recovery_failed;
 };
 
 static const struct iio_chan_spec dps310_channels[] = {
@@ -159,6 +160,102 @@
 	return 0;
 }
 
+/*
+ * Some versions of the chip will read temperatures in the ~60C range when
+ * it's actually ~20C. This is the manufacturer recommended workaround
+ * to correct the issue. The registers used below are undocumented.
+ */
+static int dps310_temp_workaround(struct dps310_data *data)
+{
+	int rc;
+	int reg;
+
+	rc = regmap_read(data->regmap, 0x32, &reg);
+	if (rc)
+		return rc;
+
+	/*
+	 * If bit 1 is set then the device is okay, and the workaround does not
+	 * need to be applied
+	 */
+	if (reg & BIT(1))
+		return 0;
+
+	rc = regmap_write(data->regmap, 0x0e, 0xA5);
+	if (rc)
+		return rc;
+
+	rc = regmap_write(data->regmap, 0x0f, 0x96);
+	if (rc)
+		return rc;
+
+	rc = regmap_write(data->regmap, 0x62, 0x02);
+	if (rc)
+		return rc;
+
+	rc = regmap_write(data->regmap, 0x0e, 0x00);
+	if (rc)
+		return rc;
+
+	return regmap_write(data->regmap, 0x0f, 0x00);
+}
+
+static int dps310_startup(struct dps310_data *data)
+{
+	int rc;
+	int ready;
+
+	/*
+	 * Set up pressure sensor in single sample, one measurement per second
+	 * mode
+	 */
+	rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
+	if (rc)
+		return rc;
+
+	/*
+	 * Set up external (MEMS) temperature sensor in single sample, one
+	 * measurement per second mode
+	 */
+	rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
+	if (rc)
+		return rc;
+
+	/* Temp and pressure shifts are disabled when PRC <= 8 */
+	rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+			       DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
+	if (rc)
+		return rc;
+
+	/* MEAS_CFG doesn't update correctly unless first written with 0 */
+	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+			       DPS310_MEAS_CTRL_BITS, 0);
+	if (rc)
+		return rc;
+
+	/* Turn on temperature and pressure measurement in the background */
+	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+			       DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
+			       DPS310_TEMP_EN | DPS310_BACKGROUND);
+	if (rc)
+		return rc;
+
+	/*
+	 * Calibration coefficients required for reporting temperature.
+	 * They are available 40ms after the device has started
+	 */
+	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+				      ready & DPS310_COEF_RDY, 10000, 40000);
+	if (rc)
+		return rc;
+
+	rc = dps310_get_coefs(data);
+	if (rc)
+		return rc;
+
+	return dps310_temp_workaround(data);
+}
+
 static int dps310_get_pres_precision(struct dps310_data *data)
 {
 	int rc;
@@ -297,11 +394,69 @@
 	return scale_factors[ilog2(rc)];
 }
 
+static int dps310_reset_wait(struct dps310_data *data)
+{
+	int rc;
+
+	rc = regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
+	if (rc)
+		return rc;
+
+	/* Wait for device chip access: 15ms in specification */
+	usleep_range(15000, 55000);
+	return 0;
+}
+
+static int dps310_reset_reinit(struct dps310_data *data)
+{
+	int rc;
+
+	rc = dps310_reset_wait(data);
+	if (rc)
+		return rc;
+
+	return dps310_startup(data);
+}
+
+static int dps310_ready_status(struct dps310_data *data, int ready_bit, int timeout)
+{
+	int sleep = DPS310_POLL_SLEEP_US(timeout);
+	int ready;
+
+	return regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, ready & ready_bit,
+					sleep, timeout);
+}
+
+static int dps310_ready(struct dps310_data *data, int ready_bit, int timeout)
+{
+	int rc;
+
+	rc = dps310_ready_status(data, ready_bit, timeout);
+	if (rc) {
+		if (rc == -ETIMEDOUT && !data->timeout_recovery_failed) {
+			/* Reset and reinitialize the chip. */
+			if (dps310_reset_reinit(data)) {
+				data->timeout_recovery_failed = true;
+			} else {
+				/* Try again to get sensor ready status. */
+				if (dps310_ready_status(data, ready_bit, timeout))
+					data->timeout_recovery_failed = true;
+				else
+					return 0;
+			}
+		}
+
+		return rc;
+	}
+
+	data->timeout_recovery_failed = false;
+	return 0;
+}
+
 static int dps310_read_pres_raw(struct dps310_data *data)
 {
 	int rc;
 	int rate;
-	int ready;
 	int timeout;
 	s32 raw;
 	u8 val[3];
@@ -313,9 +468,7 @@
 	timeout = DPS310_POLL_TIMEOUT_US(rate);
 
 	/* Poll for sensor readiness; base the timeout upon the sample rate. */
-	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
-				      ready & DPS310_PRS_RDY,
-				      DPS310_POLL_SLEEP_US(timeout), timeout);
+	rc = dps310_ready(data, DPS310_PRS_RDY, timeout);
 	if (rc)
 		goto done;
 
@@ -352,7 +505,6 @@
 {
 	int rc;
 	int rate;
-	int ready;
 	int timeout;
 
 	if (mutex_lock_interruptible(&data->lock))
@@ -362,10 +514,8 @@
 	timeout = DPS310_POLL_TIMEOUT_US(rate);
 
 	/* Poll for sensor readiness; base the timeout upon the sample rate. */
-	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
-				      ready & DPS310_TMP_RDY,
-				      DPS310_POLL_SLEEP_US(timeout), timeout);
-	if (rc < 0)
+	rc = dps310_ready(data, DPS310_TMP_RDY, timeout);
+	if (rc)
 		goto done;
 
 	rc = dps310_read_temp_ready(data);
@@ -660,7 +810,7 @@
 {
 	struct dps310_data *data = action_data;
 
-	regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
+	dps310_reset_wait(data);
 }
 
 static const struct regmap_config dps310_regmap_config = {
@@ -677,52 +827,12 @@
 	.write_raw = dps310_write_raw,
 };
 
-/*
- * Some verions of chip will read temperatures in the ~60C range when
- * its actually ~20C. This is the manufacturer recommended workaround
- * to correct the issue. The registers used below are undocumented.
- */
-static int dps310_temp_workaround(struct dps310_data *data)
-{
-	int rc;
-	int reg;
-
-	rc = regmap_read(data->regmap, 0x32, &reg);
-	if (rc < 0)
-		return rc;
-
-	/*
-	 * If bit 1 is set then the device is okay, and the workaround does not
-	 * need to be applied
-	 */
-	if (reg & BIT(1))
-		return 0;
-
-	rc = regmap_write(data->regmap, 0x0e, 0xA5);
-	if (rc < 0)
-		return rc;
-
-	rc = regmap_write(data->regmap, 0x0f, 0x96);
-	if (rc < 0)
-		return rc;
-
-	rc = regmap_write(data->regmap, 0x62, 0x02);
-	if (rc < 0)
-		return rc;
-
-	rc = regmap_write(data->regmap, 0x0e, 0x00);
-	if (rc < 0)
-		return rc;
-
-	return regmap_write(data->regmap, 0x0f, 0x00);
-}
-
 static int dps310_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	struct dps310_data *data;
 	struct iio_dev *iio;
-	int rc, ready;
+	int rc;
 
 	iio = devm_iio_device_alloc(&client->dev,  sizeof(*data));
 	if (!iio)
@@ -748,54 +858,8 @@
 	if (rc)
 		return rc;
 
-	/*
-	 * Set up pressure sensor in single sample, one measurement per second
-	 * mode
-	 */
-	rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
-
-	/*
-	 * Set up external (MEMS) temperature sensor in single sample, one
-	 * measurement per second mode
-	 */
-	rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
-	if (rc < 0)
-		return rc;
-
-	/* Temp and pressure shifts are disabled when PRC <= 8 */
-	rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
-			       DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
-	if (rc < 0)
-		return rc;
-
-	/* MEAS_CFG doesn't update correctly unless first written with 0 */
-	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
-			       DPS310_MEAS_CTRL_BITS, 0);
-	if (rc < 0)
-		return rc;
-
-	/* Turn on temperature and pressure measurement in the background */
-	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
-			       DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
-			       DPS310_TEMP_EN | DPS310_BACKGROUND);
-	if (rc < 0)
-		return rc;
-
-	/*
-	 * Calibration coefficients required for reporting temperature.
-	 * They are available 40ms after the device has started
-	 */
-	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
-				      ready & DPS310_COEF_RDY, 10000, 40000);
-	if (rc < 0)
-		return rc;
-
-	rc = dps310_get_coefs(data);
-	if (rc < 0)
-		return rc;
-
-	rc = dps310_temp_workaround(data);
-	if (rc < 0)
+	rc = dps310_startup(data);
+	if (rc)
 		return rc;
 
 	rc = devm_iio_device_register(&client->dev, iio);
--- linux-ein-5.4.0.orig/drivers/iio/pressure/mpl3115.c
+++ linux-ein-5.4.0/drivers/iio/pressure/mpl3115.c
@@ -144,7 +144,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);
--- linux-ein-5.4.0.orig/drivers/iio/pressure/ms5611.h
+++ linux-ein-5.4.0/drivers/iio/pressure/ms5611.h
@@ -25,13 +25,6 @@
 	MS5607,
 };
 
-struct ms5611_chip_info {
-	u16 prom[MS5611_PROM_WORDS_NB];
-
-	int (*temp_and_pressure_compensate)(struct ms5611_chip_info *chip_info,
-					    s32 *temp, s32 *pressure);
-};
-
 /*
  * OverSampling Rate descriptor.
  * Warning: cmd MUST be kept aligned on a word boundary (see
@@ -50,12 +43,15 @@
 	const struct ms5611_osr *pressure_osr;
 	const struct ms5611_osr *temp_osr;
 
-	int (*reset)(struct device *dev);
-	int (*read_prom_word)(struct device *dev, int index, u16 *word);
-	int (*read_adc_temp_and_pressure)(struct device *dev,
+	u16 prom[MS5611_PROM_WORDS_NB];
+
+	int (*reset)(struct ms5611_state *st);
+	int (*read_prom_word)(struct ms5611_state *st, int index, u16 *word);
+	int (*read_adc_temp_and_pressure)(struct ms5611_state *st,
 					  s32 *temp, s32 *pressure);
 
-	struct ms5611_chip_info *chip_info;
+	int (*compensate_temp_and_pressure)(struct ms5611_state *st, s32 *temp,
+					  s32 *pressure);
 	struct regulator *vdd;
 };
 
--- linux-ein-5.4.0.orig/drivers/iio/pressure/ms5611_core.c
+++ linux-ein-5.4.0/drivers/iio/pressure/ms5611_core.c
@@ -76,7 +76,7 @@
 
 	crc = (crc >> 12) & 0x000F;
 
-	return crc_orig != 0x0000 && crc == crc_orig;
+	return crc == crc_orig;
 }
 
 static int ms5611_read_prom(struct iio_dev *indio_dev)
@@ -85,8 +85,7 @@
 	struct ms5611_state *st = iio_priv(indio_dev);
 
 	for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
-		ret = st->read_prom_word(&indio_dev->dev,
-					 i, &st->chip_info->prom[i]);
+		ret = st->read_prom_word(st, i, &st->prom[i]);
 		if (ret < 0) {
 			dev_err(&indio_dev->dev,
 				"failed to read prom at %d\n", i);
@@ -94,7 +93,7 @@
 		}
 	}
 
-	if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) {
+	if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
 		dev_err(&indio_dev->dev, "PROM integrity check failed\n");
 		return -ENODEV;
 	}
@@ -108,28 +107,27 @@
 	int ret;
 	struct ms5611_state *st = iio_priv(indio_dev);
 
-	ret = st->read_adc_temp_and_pressure(&indio_dev->dev, temp, pressure);
+	ret = st->read_adc_temp_and_pressure(st, temp, pressure);
 	if (ret < 0) {
 		dev_err(&indio_dev->dev,
 			"failed to read temperature and pressure\n");
 		return ret;
 	}
 
-	return st->chip_info->temp_and_pressure_compensate(st->chip_info,
-							   temp, pressure);
+	return st->compensate_temp_and_pressure(st, temp, pressure);
 }
 
-static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
+static int ms5611_temp_and_pressure_compensate(struct ms5611_state *st,
 					       s32 *temp, s32 *pressure)
 {
 	s32 t = *temp, p = *pressure;
 	s64 off, sens, dt;
 
-	dt = t - (chip_info->prom[5] << 8);
-	off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7);
-	sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8);
+	dt = t - (st->prom[5] << 8);
+	off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
+	sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
 
-	t = 2000 + ((chip_info->prom[6] * dt) >> 23);
+	t = 2000 + ((st->prom[6] * dt) >> 23);
 	if (t < 2000) {
 		s64 off2, sens2, t2;
 
@@ -155,17 +153,17 @@
 	return 0;
 }
 
-static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
+static int ms5607_temp_and_pressure_compensate(struct ms5611_state *st,
 					       s32 *temp, s32 *pressure)
 {
 	s32 t = *temp, p = *pressure;
 	s64 off, sens, dt;
 
-	dt = t - (chip_info->prom[5] << 8);
-	off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6);
-	sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7);
+	dt = t - (st->prom[5] << 8);
+	off = ((s64)st->prom[2] << 17) + ((st->prom[4] * dt) >> 6);
+	sens = ((s64)st->prom[1] << 16) + ((st->prom[3] * dt) >> 7);
 
-	t = 2000 + ((chip_info->prom[6] * dt) >> 23);
+	t = 2000 + ((st->prom[6] * dt) >> 23);
 	if (t < 2000) {
 		s64 off2, sens2, t2, tmp;
 
@@ -196,7 +194,7 @@
 	int ret;
 	struct ms5611_state *st = iio_priv(indio_dev);
 
-	ret = st->reset(&indio_dev->dev);
+	ret = st->reset(st);
 	if (ret < 0) {
 		dev_err(&indio_dev->dev, "failed to reset device\n");
 		return ret;
@@ -212,16 +210,21 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct ms5611_state *st = iio_priv(indio_dev);
-	s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */
+	/* Ensure buffer elements are naturally aligned */
+	struct {
+		s32 channels[2];
+		s64 ts __aligned(8);
+	} scan;
 	int ret;
 
 	mutex_lock(&st->lock);
-	ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]);
+	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
+					    &scan.channels[0]);
 	mutex_unlock(&st->lock);
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
 					   iio_get_time_ns(indio_dev));
 
 err:
@@ -338,15 +341,6 @@
 
 static const unsigned long ms5611_scan_masks[] = {0x3, 0};
 
-static struct ms5611_chip_info chip_info_tbl[] = {
-	[MS5611] = {
-		.temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
-	},
-	[MS5607] = {
-		.temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate,
-	}
-};
-
 static const struct iio_chan_spec ms5611_channels[] = {
 	{
 		.type = IIO_PRESSURE,
@@ -429,7 +423,20 @@
 	struct ms5611_state *st = iio_priv(indio_dev);
 
 	mutex_init(&st->lock);
-	st->chip_info = &chip_info_tbl[type];
+
+	switch (type) {
+	case MS5611:
+		st->compensate_temp_and_pressure =
+			ms5611_temp_and_pressure_compensate;
+		break;
+	case MS5607:
+		st->compensate_temp_and_pressure =
+			ms5607_temp_and_pressure_compensate;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	st->temp_osr =
 		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
 	st->pressure_osr =
--- linux-ein-5.4.0.orig/drivers/iio/pressure/ms5611_i2c.c
+++ linux-ein-5.4.0/drivers/iio/pressure/ms5611_i2c.c
@@ -18,17 +18,15 @@
 
 #include "ms5611.h"
 
-static int ms5611_i2c_reset(struct device *dev)
+static int ms5611_i2c_reset(struct ms5611_state *st)
 {
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
-
 	return i2c_smbus_write_byte(st->client, MS5611_RESET);
 }
 
-static int ms5611_i2c_read_prom_word(struct device *dev, int index, u16 *word)
+static int ms5611_i2c_read_prom_word(struct ms5611_state *st, int index,
+				     u16 *word)
 {
 	int ret;
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 
 	ret = i2c_smbus_read_word_swapped(st->client,
 			MS5611_READ_PROM_WORD + (index << 1));
@@ -55,11 +53,10 @@
 	return 0;
 }
 
-static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev,
+static int ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state *st,
 						 s32 *temp, s32 *pressure)
 {
 	int ret;
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 	const struct ms5611_osr *osr = st->temp_osr;
 
 	ret = i2c_smbus_write_byte(st->client, osr->cmd);
--- linux-ein-5.4.0.orig/drivers/iio/pressure/ms5611_spi.c
+++ linux-ein-5.4.0/drivers/iio/pressure/ms5611_spi.c
@@ -13,18 +13,17 @@
 
 #include "ms5611.h"
 
-static int ms5611_spi_reset(struct device *dev)
+static int ms5611_spi_reset(struct ms5611_state *st)
 {
 	u8 cmd = MS5611_RESET;
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 
 	return spi_write_then_read(st->client, &cmd, 1, NULL, 0);
 }
 
-static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word)
+static int ms5611_spi_read_prom_word(struct ms5611_state *st, int index,
+				     u16 *word)
 {
 	int ret;
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 
 	ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1));
 	if (ret < 0)
@@ -35,11 +34,10 @@
 	return 0;
 }
 
-static int ms5611_spi_read_adc(struct device *dev, s32 *val)
+static int ms5611_spi_read_adc(struct ms5611_state *st, s32 *val)
 {
 	int ret;
 	u8 buf[3] = { MS5611_READ_ADC };
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 
 	ret = spi_write_then_read(st->client, buf, 1, buf, 3);
 	if (ret < 0)
@@ -50,11 +48,10 @@
 	return 0;
 }
 
-static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev,
+static int ms5611_spi_read_adc_temp_and_pressure(struct ms5611_state *st,
 						 s32 *temp, s32 *pressure)
 {
 	int ret;
-	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
 	const struct ms5611_osr *osr = st->temp_osr;
 
 	/*
@@ -66,7 +63,7 @@
 		return ret;
 
 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
-	ret = ms5611_spi_read_adc(dev, temp);
+	ret = ms5611_spi_read_adc(st, temp);
 	if (ret < 0)
 		return ret;
 
@@ -76,7 +73,7 @@
 		return ret;
 
 	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
-	return ms5611_spi_read_adc(dev, pressure);
+	return ms5611_spi_read_adc(st, pressure);
 }
 
 static int ms5611_spi_probe(struct spi_device *spi)
@@ -92,7 +89,7 @@
 	spi_set_drvdata(spi, indio_dev);
 
 	spi->mode = SPI_MODE_0;
-	spi->max_speed_hz = 20000000;
+	spi->max_speed_hz = min(spi->max_speed_hz, 20000000U);
 	spi->bits_per_word = 8;
 	ret = spi_setup(spi);
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/iio/pressure/zpa2326.c
+++ linux-ein-5.4.0/drivers/iio/pressure/zpa2326.c
@@ -664,8 +664,10 @@
 	int err;
 
 	err = pm_runtime_get_sync(indio_dev->dev.parent);
-	if (err < 0)
+	if (err < 0) {
+		pm_runtime_put(indio_dev->dev.parent);
 		return err;
+	}
 
 	if (err > 0) {
 		/*
--- linux-ein-5.4.0.orig/drivers/iio/proximity/as3935.c
+++ linux-ein-5.4.0/drivers/iio/proximity/as3935.c
@@ -61,7 +61,11 @@
 	unsigned long noise_tripped;
 	u32 tune_cap;
 	u32 nflwdth_reg;
-	u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u8 chan;
+		s64 timestamp __aligned(8);
+	} scan;
 	u8 buf[2] ____cacheline_aligned;
 };
 
@@ -227,8 +231,8 @@
 	if (ret)
 		goto err_read;
 
-	st->buffer[0] = val & AS3935_DATA_MASK;
-	iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
+	st->scan.chan = val & AS3935_DATA_MASK;
+	iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
 					   iio_get_time_ns(indio_dev));
 err_read:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/proximity/isl29501.c
+++ linux-ein-5.4.0/drivers/iio/proximity/isl29501.c
@@ -938,7 +938,7 @@
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct isl29501_private *isl29501 = iio_priv(indio_dev);
 	const unsigned long *active_mask = indio_dev->active_scan_mask;
-	u32 buffer[4] = {}; /* 1x16-bit + ts */
+	u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */
 
 	if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
 		isl29501_register_read(isl29501, REG_DISTANCE, buffer);
--- linux-ein-5.4.0.orig/drivers/iio/proximity/mb1232.c
+++ linux-ein-5.4.0/drivers/iio/proximity/mb1232.c
@@ -40,6 +40,11 @@
 	 */
 	struct completion	ranging;
 	int			irqnr;
+	/* Ensure correct alignment of data to push to IIO buffer */
+	struct {
+		s16 distance;
+		s64 ts __aligned(8);
+	} scan;
 };
 
 static irqreturn_t mb1232_handle_irq(int irq, void *dev_id)
@@ -113,17 +118,13 @@
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mb1232_data *data = iio_priv(indio_dev);
-	/*
-	 * triggered buffer
-	 * 16-bit channel + 48-bit padding + 64-bit timestamp
-	 */
-	s16 buffer[8] = { 0 };
 
-	buffer[0] = mb1232_read_distance(data);
-	if (buffer[0] < 0)
+	data->scan.distance = mb1232_read_distance(data);
+	if (data->scan.distance < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+					   pf->timestamp);
 
 err:
 	iio_trigger_notify_done(indio_dev->trig);
--- linux-ein-5.4.0.orig/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ linux-ein-5.4.0/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -43,7 +43,11 @@
 	int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
 	int i2c_enabled;
 
-	u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		u16 chan;
+		s64 timestamp __aligned(8);
+	} scan;
 };
 
 static const struct iio_chan_spec lidar_channels[] = {
@@ -158,6 +162,7 @@
 	ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
 	if (ret < 0) {
 		dev_err(&client->dev, "cannot send start measurement command");
+		pm_runtime_put_noidle(&client->dev);
 		return ret;
 	}
 
@@ -227,9 +232,9 @@
 	struct lidar_data *data = iio_priv(indio_dev);
 	int ret;
 
-	ret = lidar_get_measurement(data, data->buffer);
+	ret = lidar_get_measurement(data, &data->scan.chan);
 	if (!ret) {
-		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+		iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
 						   iio_get_time_ns(indio_dev));
 	} else if (ret != -EINVAL) {
 		dev_err(&data->client->dev, "cannot read LIDAR measurement");
--- linux-ein-5.4.0.orig/drivers/iio/proximity/srf08.c
+++ linux-ein-5.4.0/drivers/iio/proximity/srf08.c
@@ -63,11 +63,11 @@
 	int			range_mm;
 	struct mutex		lock;
 
-	/*
-	 * triggered buffer
-	 * 1x16-bit channel + 3x16 padding + 4x16 timestamp
-	 */
-	s16			buffer[8];
+	/* Ensure timestamp is naturally aligned */
+	struct {
+		s16 chan;
+		s64 timestamp __aligned(8);
+	} scan;
 
 	/* Sensor-Type */
 	enum srf08_sensor_type	sensor_type;
@@ -190,9 +190,9 @@
 
 	mutex_lock(&data->lock);
 
-	data->buffer[0] = sensor_data;
+	data->scan.chan = sensor_data;
 	iio_push_to_buffers_with_timestamp(indio_dev,
-						data->buffer, pf->timestamp);
+					   &data->scan, pf->timestamp);
 
 	mutex_unlock(&data->lock);
 err:
--- linux-ein-5.4.0.orig/drivers/iio/temperature/hid-sensor-temperature.c
+++ linux-ein-5.4.0/drivers/iio/temperature/hid-sensor-temperature.c
@@ -17,7 +17,10 @@
 struct temperature_state {
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info temperature_attr;
-	s32 temperature_data;
+	struct {
+		s32 temperature_data;
+		u64 timestamp __aligned(8);
+	} scan;
 	int scale_pre_decml;
 	int scale_post_decml;
 	int scale_precision;
@@ -34,7 +37,7 @@
 			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 			BIT(IIO_CHAN_INFO_HYSTERESIS),
 	},
-	IIO_CHAN_SOFT_TIMESTAMP(3),
+	IIO_CHAN_SOFT_TIMESTAMP(1),
 };
 
 /* Adjust channel real bits based on report descriptor */
@@ -125,9 +128,8 @@
 	struct temperature_state *temp_st = iio_priv(indio_dev);
 
 	if (atomic_read(&temp_st->common_attributes.data_ready))
-		iio_push_to_buffers_with_timestamp(indio_dev,
-				&temp_st->temperature_data,
-				iio_get_time_ns(indio_dev));
+		iio_push_to_buffers_with_timestamp(indio_dev, &temp_st->scan,
+						   iio_get_time_ns(indio_dev));
 
 	return 0;
 }
@@ -142,7 +144,7 @@
 
 	switch (usage_id) {
 	case HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE:
-		temp_st->temperature_data = *(s32 *)raw_data;
+		temp_st->scan.temperature_data = *(s32 *)raw_data;
 		return 0;
 	default:
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/iio/temperature/max31856.c
+++ linux-ein-5.4.0/drivers/iio/temperature/max31856.c
@@ -284,6 +284,8 @@
 	spi_set_drvdata(spi, indio_dev);
 
 	indio_dev->info = &max31856_info;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = id->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = max31856_channels;
--- linux-ein-5.4.0.orig/drivers/iio/trigger/iio-trig-hrtimer.c
+++ linux-ein-5.4.0/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -102,7 +102,7 @@
 
 	if (state)
 		hrtimer_start(&trig_info->timer, trig_info->period,
-			      HRTIMER_MODE_REL);
+			      HRTIMER_MODE_REL_HARD);
 	else
 		hrtimer_cancel(&trig_info->timer);
 
@@ -132,7 +132,7 @@
 	trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops;
 	trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups;
 
-	hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
 	trig_info->timer.function = iio_hrtimer_trig_handler;
 
 	trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
--- linux-ein-5.4.0.orig/drivers/iio/trigger/iio-trig-sysfs.c
+++ linux-ein-5.4.0/drivers/iio/trigger/iio-trig-sysfs.c
@@ -196,6 +196,7 @@
 	}
 
 	iio_trigger_unregister(t->trig);
+	irq_work_sync(&t->work);
 	iio_trigger_free(t->trig);
 
 	list_del(&t->l);
@@ -208,9 +209,13 @@
 
 static int __init iio_sysfs_trig_init(void)
 {
+	int ret;
 	device_initialize(&iio_sysfs_trig_dev);
 	dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
-	return device_add(&iio_sysfs_trig_dev);
+	ret = device_add(&iio_sysfs_trig_dev);
+	if (ret)
+		put_device(&iio_sysfs_trig_dev);
+	return ret;
 }
 module_init(iio_sysfs_trig_init);
 
--- linux-ein-5.4.0.orig/drivers/iio/trigger/stm32-timer-trigger.c
+++ linux-ein-5.4.0/drivers/iio/trigger/stm32-timer-trigger.c
@@ -161,7 +161,8 @@
 	return 0;
 }
 
-static void stm32_timer_stop(struct stm32_timer_trigger *priv)
+static void stm32_timer_stop(struct stm32_timer_trigger *priv,
+			     struct iio_trigger *trig)
 {
 	u32 ccer, cr1;
 
@@ -179,6 +180,12 @@
 	regmap_write(priv->regmap, TIM_PSC, 0);
 	regmap_write(priv->regmap, TIM_ARR, 0);
 
+	/* Force disable master mode */
+	if (stm32_timer_is_trgo2_name(trig->name))
+		regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0);
+	else
+		regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0);
+
 	/* Make sure that registers are updated */
 	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
 }
@@ -197,7 +204,7 @@
 		return ret;
 
 	if (freq == 0) {
-		stm32_timer_stop(priv);
+		stm32_timer_stop(priv, trig);
 	} else {
 		ret = stm32_timer_start(priv, trig, freq);
 		if (ret)
@@ -793,6 +800,6 @@
 };
 module_platform_driver(stm32_timer_trigger_driver);
 
-MODULE_ALIAS("platform: stm32-timer-trigger");
+MODULE_ALIAS("platform:stm32-timer-trigger");
 MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver");
 MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/infiniband/Kconfig
+++ linux-ein-5.4.0/drivers/infiniband/Kconfig
@@ -80,6 +80,9 @@
 	  This allows the user to config the default GID type that the CM
 	  uses for each device, when initiaing new connections.
 
+config INFINIBAND_VIRT_DMA
+	def_bool !HIGHMEM
+
 if INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS
 source "drivers/infiniband/hw/mthca/Kconfig"
 source "drivers/infiniband/hw/qib/Kconfig"
--- linux-ein-5.4.0.orig/drivers/infiniband/core/Makefile
+++ linux-ein-5.4.0/drivers/infiniband/core/Makefile
@@ -11,7 +11,7 @@
 				device.o fmr_pool.o cache.o netlink.o \
 				roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \
 				multicast.o mad.o smi.o agent.o mad_rmpp.o \
-				nldev.o restrack.o counters.o
+				nldev.o restrack.o counters.o ib_core_uverbs.o
 
 ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o
 ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o
@@ -34,5 +34,5 @@
 				uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
 				uverbs_std_types_mr.o uverbs_std_types_counters.o \
 				uverbs_uapi.o uverbs_std_types_device.o
-ib_uverbs-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
+ib_uverbs-$(CONFIG_INFINIBAND_USER_MEM) += umem.o peer_mem.o
 ib_uverbs-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o
--- linux-ein-5.4.0.orig/drivers/infiniband/core/addr.c
+++ linux-ein-5.4.0/drivers/infiniband/core/addr.c
@@ -76,7 +76,9 @@
 
 static const struct nla_policy ib_nl_addr_policy[LS_NLA_TYPE_MAX] = {
 	[LS_NLA_TYPE_DGID] = {.type = NLA_BINARY,
-		.len = sizeof(struct rdma_nla_ls_gid)},
+		.len = sizeof(struct rdma_nla_ls_gid),
+		.validation_type = NLA_VALIDATE_MIN,
+		.min = sizeof(struct rdma_nla_ls_gid)},
 };
 
 static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh)
@@ -139,7 +141,7 @@
 	if (ib_nl_is_good_ip_resp(nlh))
 		ib_nl_process_good_ip_rsep(nlh);
 
-	return skb->len;
+	return 0;
 }
 
 static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr,
@@ -421,16 +423,15 @@
 				(const struct sockaddr_in6 *)dst_sock;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
-	int ret;
 
 	memset(&fl6, 0, sizeof fl6);
 	fl6.daddr = dst_in->sin6_addr;
 	fl6.saddr = src_in->sin6_addr;
 	fl6.flowi6_oif = addr->bound_dev_if;
 
-	ret = ipv6_stub->ipv6_dst_lookup(addr->net, NULL, &dst, &fl6);
-	if (ret < 0)
-		return ret;
+	dst = ipv6_stub->ipv6_dst_lookup_flow(addr->net, NULL, &fl6, NULL);
+	if (IS_ERR(dst))
+		return PTR_ERR(dst);
 
 	if (ipv6_addr_any(&src_in->sin6_addr))
 		src_in->sin6_addr = fl6.saddr;
@@ -646,13 +647,12 @@
 	req->callback = NULL;
 
 	spin_lock_bh(&lock);
+	/*
+	 * Although the work will normally have been canceled by the workqueue,
+	 * it can still be requeued as long as it is on the req_list.
+	 */
+	cancel_delayed_work(&req->work);
 	if (!list_empty(&req->list)) {
-		/*
-		 * Although the work will normally have been canceled by the
-		 * workqueue, it can still be requeued as long as it is on the
-		 * req_list.
-		 */
-		cancel_delayed_work(&req->work);
 		list_del_init(&req->list);
 		kfree(req);
 	}
--- linux-ein-5.4.0.orig/drivers/infiniband/core/cache.c
+++ linux-ein-5.4.0/drivers/infiniband/core/cache.c
@@ -51,9 +51,8 @@
 
 struct ib_update_work {
 	struct work_struct work;
-	struct ib_device  *device;
-	u8                 port_num;
-	bool		   enforce_security;
+	struct ib_event event;
+	bool enforce_security;
 };
 
 union ib_gid zgid;
@@ -130,7 +129,7 @@
 	event.element.port_num	= port;
 	event.event		= IB_EVENT_GID_CHANGE;
 
-	ib_dispatch_event(&event);
+	ib_dispatch_event_clients(&event);
 }
 
 static const char * const gid_type_str[] = {
@@ -1387,9 +1386,8 @@
 	return ret;
 }
 
-static void ib_cache_update(struct ib_device *device,
-			    u8                port,
-			    bool	      enforce_security)
+static int
+ib_cache_update(struct ib_device *device, u8 port, bool enforce_security)
 {
 	struct ib_port_attr       *tprops = NULL;
 	struct ib_pkey_cache      *pkey_cache = NULL, *old_pkey_cache;
@@ -1397,11 +1395,11 @@
 	int                        ret;
 
 	if (!rdma_is_port_valid(device, port))
-		return;
+		return -EINVAL;
 
 	tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
 	if (!tprops)
-		return;
+		return -ENOMEM;
 
 	ret = ib_query_port(device, port, tprops);
 	if (ret) {
@@ -1419,8 +1417,10 @@
 	pkey_cache = kmalloc(struct_size(pkey_cache, table,
 					 tprops->pkey_tbl_len),
 			     GFP_KERNEL);
-	if (!pkey_cache)
+	if (!pkey_cache) {
+		ret = -ENOMEM;
 		goto err;
+	}
 
 	pkey_cache->table_len = tprops->pkey_tbl_len;
 
@@ -1452,50 +1452,84 @@
 
 	kfree(old_pkey_cache);
 	kfree(tprops);
-	return;
+	return 0;
 
 err:
 	kfree(pkey_cache);
 	kfree(tprops);
+	return ret;
 }
 
-static void ib_cache_task(struct work_struct *_work)
+static void ib_cache_event_task(struct work_struct *_work)
 {
 	struct ib_update_work *work =
 		container_of(_work, struct ib_update_work, work);
+	int ret;
+
+	/* Before distributing the cache update event, first sync
+	 * the cache.
+	 */
+	ret = ib_cache_update(work->event.device, work->event.element.port_num,
+			      work->enforce_security);
+
+	/* GID event is notified already for individual GID entries by
+	 * dispatch_gid_change_event(). Hence, notifiy for rest of the
+	 * events.
+	 */
+	if (!ret && work->event.event != IB_EVENT_GID_CHANGE)
+		ib_dispatch_event_clients(&work->event);
 
-	ib_cache_update(work->device,
-			work->port_num,
-			work->enforce_security);
 	kfree(work);
 }
 
-static void ib_cache_event(struct ib_event_handler *handler,
-			   struct ib_event *event)
+static void ib_generic_event_task(struct work_struct *_work)
+{
+	struct ib_update_work *work =
+		container_of(_work, struct ib_update_work, work);
+
+	ib_dispatch_event_clients(&work->event);
+	kfree(work);
+}
+
+static bool is_cache_update_event(const struct ib_event *event)
+{
+	return (event->event == IB_EVENT_PORT_ERR    ||
+		event->event == IB_EVENT_PORT_ACTIVE ||
+		event->event == IB_EVENT_LID_CHANGE  ||
+		event->event == IB_EVENT_PKEY_CHANGE ||
+		event->event == IB_EVENT_CLIENT_REREGISTER ||
+		event->event == IB_EVENT_GID_CHANGE);
+}
+
+/**
+ * ib_dispatch_event - Dispatch an asynchronous event
+ * @event:Event to dispatch
+ *
+ * Low-level drivers must call ib_dispatch_event() to dispatch the
+ * event to all registered event handlers when an asynchronous event
+ * occurs.
+ */
+void ib_dispatch_event(const struct ib_event *event)
 {
 	struct ib_update_work *work;
 
-	if (event->event == IB_EVENT_PORT_ERR    ||
-	    event->event == IB_EVENT_PORT_ACTIVE ||
-	    event->event == IB_EVENT_LID_CHANGE  ||
-	    event->event == IB_EVENT_PKEY_CHANGE ||
-	    event->event == IB_EVENT_CLIENT_REREGISTER ||
-	    event->event == IB_EVENT_GID_CHANGE) {
-		work = kmalloc(sizeof *work, GFP_ATOMIC);
-		if (work) {
-			INIT_WORK(&work->work, ib_cache_task);
-			work->device   = event->device;
-			work->port_num = event->element.port_num;
-			if (event->event == IB_EVENT_PKEY_CHANGE ||
-			    event->event == IB_EVENT_GID_CHANGE)
-				work->enforce_security = true;
-			else
-				work->enforce_security = false;
+	work = kzalloc(sizeof(*work), GFP_ATOMIC);
+	if (!work)
+		return;
 
-			queue_work(ib_wq, &work->work);
-		}
-	}
+	if (is_cache_update_event(event))
+		INIT_WORK(&work->work, ib_cache_event_task);
+	else
+		INIT_WORK(&work->work, ib_generic_event_task);
+
+	work->event = *event;
+	if (event->event == IB_EVENT_PKEY_CHANGE ||
+	    event->event == IB_EVENT_GID_CHANGE)
+		work->enforce_security = true;
+
+	queue_work(ib_wq, &work->work);
 }
+EXPORT_SYMBOL(ib_dispatch_event);
 
 int ib_cache_setup_one(struct ib_device *device)
 {
@@ -1508,12 +1542,12 @@
 	if (err)
 		return err;
 
-	rdma_for_each_port (device, p)
-		ib_cache_update(device, p, true);
+	rdma_for_each_port (device, p) {
+		err = ib_cache_update(device, p, true);
+		if (err)
+			return err;
+	}
 
-	INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
-			      device, ib_cache_event);
-	ib_register_event_handler(&device->cache.event_handler);
 	return 0;
 }
 
@@ -1535,14 +1569,12 @@
 
 void ib_cache_cleanup_one(struct ib_device *device)
 {
-	/* The cleanup function unregisters the event handler,
-	 * waits for all in-progress workqueue elements and cleans
-	 * up the GID cache. This function should be called after
-	 * the device was removed from the devices list and all
-	 * clients were removed, so the cache exists but is
+	/* The cleanup function waits for all in-progress workqueue
+	 * elements and cleans up the GID cache. This function should be
+	 * called after the device was removed from the devices list and
+	 * all clients were removed, so the cache exists but is
 	 * non-functional and shouldn't be updated anymore.
 	 */
-	ib_unregister_event_handler(&device->cache.event_handler);
 	flush_workqueue(ib_wq);
 	gid_table_cleanup_one(device);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/core/cm.c
+++ linux-ein-5.4.0/drivers/infiniband/core/cm.c
@@ -597,18 +597,6 @@
 	return 0;
 }
 
-static int cm_alloc_id(struct cm_id_private *cm_id_priv)
-{
-	int err;
-	u32 id;
-
-	err = xa_alloc_cyclic_irq(&cm.local_id_table, &id, cm_id_priv,
-			xa_limit_32b, &cm.local_id_next, GFP_KERNEL);
-
-	cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand;
-	return err;
-}
-
 static u32 cm_local_id(__be32 local_id)
 {
 	return (__force u32) (local_id ^ cm.random_id_operand);
@@ -862,6 +850,7 @@
 				 void *context)
 {
 	struct cm_id_private *cm_id_priv;
+	u32 id;
 	int ret;
 
 	cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL);
@@ -873,9 +862,6 @@
 	cm_id_priv->id.cm_handler = cm_handler;
 	cm_id_priv->id.context = context;
 	cm_id_priv->id.remote_cm_qpn = 1;
-	ret = cm_alloc_id(cm_id_priv);
-	if (ret)
-		goto error;
 
 	spin_lock_init(&cm_id_priv->lock);
 	init_completion(&cm_id_priv->comp);
@@ -884,11 +870,20 @@
 	INIT_LIST_HEAD(&cm_id_priv->altr_list);
 	atomic_set(&cm_id_priv->work_count, -1);
 	atomic_set(&cm_id_priv->refcount, 1);
+
+	ret = xa_alloc_cyclic_irq(&cm.local_id_table, &id, NULL, xa_limit_32b,
+				  &cm.local_id_next, GFP_KERNEL);
+	if (ret < 0)
+		goto error;
+	cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand;
+	xa_store_irq(&cm.local_id_table, cm_local_id(cm_id_priv->id.local_id),
+		     cm_id_priv, GFP_KERNEL);
+
 	return &cm_id_priv->id;
 
 error:
 	kfree(cm_id_priv);
-	return ERR_PTR(-ENOMEM);
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(ib_create_cm_id);
 
@@ -1097,14 +1092,22 @@
 		break;
 	}
 
-	spin_lock_irq(&cm.lock);
+	spin_lock_irq(&cm_id_priv->lock);
+	spin_lock(&cm.lock);
+	/* Required for cleanup paths related cm_req_handler() */
+	if (cm_id_priv->timewait_info) {
+		cm_cleanup_timewait(cm_id_priv->timewait_info);
+		kfree(cm_id_priv->timewait_info);
+		cm_id_priv->timewait_info = NULL;
+	}
 	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);
+	spin_unlock(&cm.lock);
+	spin_unlock_irq(&cm_id_priv->lock);
 
 	cm_free_id(cm_id->local_id);
 	cm_deref_id(cm_id_priv);
@@ -1228,6 +1231,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);
@@ -1420,7 +1424,7 @@
 	/* Verify that we're not in timewait. */
 	cm_id_priv = container_of(cm_id, struct cm_id_private, id);
 	spin_lock_irqsave(&cm_id_priv->lock, flags);
-	if (cm_id->state != IB_CM_IDLE) {
+	if (cm_id->state != IB_CM_IDLE || WARN_ON(cm_id_priv->timewait_info)) {
 		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 		ret = -EINVAL;
 		goto out;
@@ -1431,6 +1435,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 out;
 	}
 
@@ -1438,12 +1443,12 @@
 				 param->ppath_sgid_attr, &cm_id_priv->av,
 				 cm_id_priv);
 	if (ret)
-		goto error1;
+		goto out;
 	if (param->alternate_path) {
 		ret = cm_init_av_by_path(param->alternate_path, NULL,
 					 &cm_id_priv->alt_av, cm_id_priv);
 		if (ret)
-			goto error1;
+			goto out;
 	}
 	cm_id->service_id = param->service_id;
 	cm_id->service_mask = ~cpu_to_be64(0);
@@ -1461,7 +1466,7 @@
 
 	ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg);
 	if (ret)
-		goto error1;
+		goto out;
 
 	req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad;
 	cm_format_req(req_msg, cm_id_priv, param);
@@ -1484,7 +1489,6 @@
 	return 0;
 
 error2:	cm_free_msg(cm_id_priv->msg);
-error1:	kfree(cm_id_priv->timewait_info);
 out:	return ret;
 }
 EXPORT_SYMBOL(ib_send_cm_req);
@@ -1958,6 +1962,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;
@@ -1969,7 +1974,7 @@
 		pr_debug("%s: local_id %d, no listen_cm_id_priv\n", __func__,
 			 be32_to_cpu(cm_id->local_id));
 		ret = -EINVAL;
-		goto free_timeinfo;
+		goto destroy;
 	}
 
 	cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
@@ -2054,8 +2059,6 @@
 rejected:
 	atomic_dec(&cm_id_priv->refcount);
 	cm_deref_id(listen_cm_id_priv);
-free_timeinfo:
-	kfree(cm_id_priv->timewait_info);
 destroy:
 	ib_destroy_cm_id(cm_id);
 	return ret;
@@ -4333,7 +4336,7 @@
 	unsigned long flags;
 	int ret;
 	int count = 0;
-	u8 i;
+	unsigned int i;
 
 	cm_dev = kzalloc(struct_size(cm_dev, port, ib_device->phys_port_cnt),
 			 GFP_KERNEL);
@@ -4345,7 +4348,7 @@
 	cm_dev->going_down = 0;
 
 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
-	for (i = 1; i <= ib_device->phys_port_cnt; i++) {
+	rdma_for_each_port (ib_device, i) {
 		if (!rdma_cap_ib_cm(ib_device, i))
 			continue;
 
@@ -4424,7 +4427,7 @@
 		.clr_port_cap_mask = IB_PORT_CM_SUP
 	};
 	unsigned long flags;
-	int i;
+	unsigned int i;
 
 	if (!cm_dev)
 		return;
@@ -4437,7 +4440,7 @@
 	cm_dev->going_down = 1;
 	spin_unlock_irq(&cm.lock);
 
-	for (i = 1; i <= ib_device->phys_port_cnt; i++) {
+	rdma_for_each_port (ib_device, i) {
 		if (!rdma_cap_ib_cm(ib_device, i))
 			continue;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/core/cma.c
+++ linux-ein-5.4.0/drivers/infiniband/core/cma.c
@@ -530,6 +530,11 @@
 	list_del(&id_priv->list);
 	cma_deref_dev(id_priv->cma_dev);
 	id_priv->cma_dev = NULL;
+	id_priv->id.device = NULL;
+	if (id_priv->id.route.addr.dev_addr.sgid_attr) {
+		rdma_put_gid_attr(id_priv->id.route.addr.dev_addr.sgid_attr);
+		id_priv->id.route.addr.dev_addr.sgid_attr = NULL;
+	}
 	mutex_unlock(&lock);
 }
 
@@ -815,6 +820,7 @@
 	u16 pkey, index;
 	u8 p;
 	enum ib_port_state port_state;
+	int ret;
 	int i;
 
 	cma_dev = NULL;
@@ -833,9 +839,14 @@
 
 			if (ib_get_cached_port_state(cur_dev->device, p, &port_state))
 				continue;
-			for (i = 0; !rdma_query_gid(cur_dev->device,
-						    p, i, &gid);
-			     i++) {
+
+			for (i = 0; i < cur_dev->device->port_data[p].immutable.gid_tbl_len;
+			     ++i) {
+				ret = rdma_query_gid(cur_dev->device, p, i,
+						     &gid);
+				if (ret)
+					continue;
+
 				if (!memcmp(&gid, dgid, sizeof(gid))) {
 					cma_dev = cur_dev;
 					sgid = gid;
@@ -1423,7 +1434,7 @@
 		return false;
 
 	memset(&fl4, 0, sizeof(fl4));
-	fl4.flowi4_iif = net_dev->ifindex;
+	fl4.flowi4_oif = net_dev->ifindex;
 	fl4.daddr = daddr;
 	fl4.saddr = saddr;
 
@@ -1631,6 +1642,8 @@
 {
 	struct rdma_id_private *id_priv, *id_priv_dev;
 
+	lockdep_assert_held(&lock);
+
 	if (!bind_list)
 		return ERR_PTR(-EINVAL);
 
@@ -1677,6 +1690,7 @@
 		}
 	}
 
+	mutex_lock(&lock);
 	/*
 	 * Net namespace might be getting deleted while route lookup,
 	 * cm_id lookup is in progress. Therefore, perform netdevice
@@ -1705,8 +1719,8 @@
 		}
 
 		if (!validate_net_dev(*net_dev,
-				 (struct sockaddr *)&req->listen_addr_storage,
-				 (struct sockaddr *)&req->src_addr_storage)) {
+				 (struct sockaddr *)&req->src_addr_storage,
+				 (struct sockaddr *)&req->listen_addr_storage)) {
 			id_priv = ERR_PTR(-EHOSTUNREACH);
 			goto err;
 		}
@@ -1718,6 +1732,7 @@
 	id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev);
 err:
 	rcu_read_unlock();
+	mutex_unlock(&lock);
 	if (IS_ERR(id_priv) && *net_dev) {
 		dev_put(*net_dev);
 		*net_dev = NULL;
@@ -1799,19 +1814,30 @@
 	mutex_unlock(&lock);
 }
 
-static void cma_leave_roce_mc_group(struct rdma_id_private *id_priv,
-				    struct cma_multicast *mc)
+static void destroy_mc(struct rdma_id_private *id_priv,
+		       struct cma_multicast *mc)
 {
-	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
-	struct net_device *ndev = NULL;
+	if (rdma_cap_ib_mcast(id_priv->id.device, id_priv->id.port_num)) {
+		ib_sa_free_multicast(mc->multicast.ib);
+		kfree(mc);
+		return;
+	}
 
-	if (dev_addr->bound_dev_if)
-		ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
-	if (ndev) {
-		cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, false);
-		dev_put(ndev);
+	if (rdma_protocol_roce(id_priv->id.device,
+				      id_priv->id.port_num)) {
+		struct rdma_dev_addr *dev_addr =
+			&id_priv->id.route.addr.dev_addr;
+		struct net_device *ndev = NULL;
+
+		if (dev_addr->bound_dev_if)
+			ndev = dev_get_by_index(dev_addr->net,
+						dev_addr->bound_dev_if);
+		if (ndev) {
+			cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, false);
+			dev_put(ndev);
+		}
+		kref_put(&mc->mcref, release_mc);
 	}
-	kref_put(&mc->mcref, release_mc);
 }
 
 static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
@@ -1819,16 +1845,10 @@
 	struct cma_multicast *mc;
 
 	while (!list_empty(&id_priv->mc_list)) {
-		mc = container_of(id_priv->mc_list.next,
-				  struct cma_multicast, list);
+		mc = list_first_entry(&id_priv->mc_list, struct cma_multicast,
+				      list);
 		list_del(&mc->list);
-		if (rdma_cap_ib_mcast(id_priv->cma_dev->device,
-				      id_priv->id.port_num)) {
-			ib_sa_free_multicast(mc->multicast.ib);
-			kfree(mc);
-		} else {
-			cma_leave_roce_mc_group(id_priv, mc);
-		}
+		destroy_mc(id_priv, mc);
 	}
 }
 
@@ -1858,6 +1878,7 @@
 				iw_destroy_cm_id(id_priv->cm_id.iw);
 		}
 		cma_leave_mc_groups(id_priv);
+		rdma_restrack_del(&id_priv->res);
 		cma_release_dev(id_priv);
 	}
 
@@ -1870,9 +1891,6 @@
 
 	kfree(id_priv->id.route.path_rec);
 
-	if (id_priv->id.route.addr.dev_addr.sgid_attr)
-		rdma_put_gid_attr(id_priv->id.route.addr.dev_addr.sgid_attr);
-
 	put_net(id_priv->id.route.addr.dev_addr.net);
 	kfree(id_priv);
 }
@@ -2473,6 +2491,8 @@
 	struct net *net = id_priv->id.route.addr.dev_addr.net;
 	int ret;
 
+	lockdep_assert_held(&lock);
+
 	if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
 		return;
 
@@ -2539,7 +2559,7 @@
 {
 	struct rdma_id_private *id_priv;
 
-	if (id->qp_type != IB_QPT_RC)
+	if (id->qp_type != IB_QPT_RC && id->qp_type != IB_QPT_XRC_INI)
 		return -EINVAL;
 
 	id_priv = container_of(id, struct rdma_id_private, id);
@@ -2705,7 +2725,8 @@
 
 	cma_init_resolve_route_work(work, id_priv);
 
-	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;
@@ -2911,6 +2932,7 @@
 err2:
 	kfree(route->path_rec);
 	route->path_rec = NULL;
+	route->num_paths = 0;
 err1:
 	kfree(work);
 	return ret;
@@ -3091,6 +3113,7 @@
 	rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
 
+	atomic_inc(&id_priv->refcount);
 	cma_init_resolve_addr_work(work, id_priv);
 	queue_work(cma_wq, &work->work);
 	return 0;
@@ -3117,6 +3140,7 @@
 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
 		&(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
 
+	atomic_inc(&id_priv->refcount);
 	cma_init_resolve_addr_work(work, id_priv);
 	queue_work(cma_wq, &work->work);
 	return 0;
@@ -3153,19 +3177,26 @@
 	int ret;
 
 	id_priv = container_of(id, struct rdma_id_private, id);
+	memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
 	if (id_priv->state == RDMA_CM_IDLE) {
 		ret = cma_bind_addr(id, src_addr, dst_addr);
-		if (ret)
+		if (ret) {
+			memset(cma_dst_addr(id_priv), 0,
+			       rdma_addr_size(dst_addr));
 			return ret;
+		}
 	}
 
-	if (cma_family(id_priv) != dst_addr->sa_family)
+	if (cma_family(id_priv) != dst_addr->sa_family) {
+		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
 		return -EINVAL;
+	}
 
-	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
+	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
+		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
 		return -EINVAL;
+	}
 
-	memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
 	if (cma_any_addr(dst_addr)) {
 		ret = cma_resolve_loopback(id_priv);
 	} else {
@@ -3235,6 +3266,8 @@
 	u64 sid, mask;
 	__be16 port;
 
+	lockdep_assert_held(&lock);
+
 	addr = cma_src_addr(id_priv);
 	port = htons(bind_list->port);
 
@@ -3263,6 +3296,8 @@
 	struct rdma_bind_list *bind_list;
 	int ret;
 
+	lockdep_assert_held(&lock);
+
 	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
 	if (!bind_list)
 		return -ENOMEM;
@@ -3289,6 +3324,8 @@
 	struct sockaddr  *saddr = cma_src_addr(id_priv);
 	__be16 dport = cma_port(daddr);
 
+	lockdep_assert_held(&lock);
+
 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
 		struct sockaddr  *cur_daddr = cma_dst_addr(cur_id);
 		struct sockaddr  *cur_saddr = cma_src_addr(cur_id);
@@ -3328,6 +3365,8 @@
 	unsigned int rover;
 	struct net *net = id_priv->id.route.addr.dev_addr.net;
 
+	lockdep_assert_held(&lock);
+
 	inet_get_local_port_range(net, &low, &high);
 	remaining = (high - low) + 1;
 	rover = prandom_u32() % remaining + low;
@@ -3375,6 +3414,8 @@
 	struct rdma_id_private *cur_id;
 	struct sockaddr *addr, *cur_addr;
 
+	lockdep_assert_held(&lock);
+
 	addr = cma_src_addr(id_priv);
 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
 		if (id_priv == cur_id)
@@ -3405,6 +3446,8 @@
 	unsigned short snum;
 	int ret;
 
+	lockdep_assert_held(&lock);
+
 	snum = ntohs(cma_port(cma_src_addr(id_priv)));
 	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
 		return -EACCES;
@@ -3546,7 +3589,7 @@
 	}
 
 	id_priv->backlog = backlog;
-	if (id->device) {
+	if (id_priv->cma_dev) {
 		if (rdma_cap_ib_cm(id->device, 1)) {
 			ret = cma_ib_listen(id_priv);
 			if (ret)
@@ -4014,14 +4057,15 @@
 int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param,
 		  const char *caller)
 {
-	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);
 
 	rdma_restrack_set_task(&id_priv->res, caller);
 
-	if (!cma_comp(id_priv, RDMA_CM_CONNECT))
+	if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT)
 		return -EINVAL;
 
 	if (!id->qp && conn_param) {
@@ -4061,6 +4105,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;
@@ -4154,16 +4216,6 @@
 	else
 		pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n",
 				     status);
-	mutex_lock(&id_priv->qp_mutex);
-	if (!status && id_priv->id.qp) {
-		status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
-					 be16_to_cpu(multicast->rec.mlid));
-		if (status)
-			pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n",
-					     status);
-	}
-	mutex_unlock(&id_priv->qp_mutex);
-
 	event.status = status;
 	event.param.ud.private_data = mc->context;
 	if (!status) {
@@ -4418,6 +4470,10 @@
 	struct cma_multicast *mc;
 	int ret;
 
+	/* Not supported for kernel QPs */
+	if (WARN_ON(id->qp))
+		return -EINVAL;
+
 	if (!id->device)
 		return -EINVAL;
 
@@ -4468,25 +4524,14 @@
 	id_priv = container_of(id, struct rdma_id_private, id);
 	spin_lock_irq(&id_priv->lock);
 	list_for_each_entry(mc, &id_priv->mc_list, list) {
-		if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
-			list_del(&mc->list);
-			spin_unlock_irq(&id_priv->lock);
-
-			if (id->qp)
-				ib_detach_mcast(id->qp,
-						&mc->multicast.ib->rec.mgid,
-						be16_to_cpu(mc->multicast.ib->rec.mlid));
-
-			BUG_ON(id_priv->cma_dev->device != id->device);
-
-			if (rdma_cap_ib_mcast(id->device, id->port_num)) {
-				ib_sa_free_multicast(mc->multicast.ib);
-				kfree(mc);
-			} else if (rdma_protocol_roce(id->device, id->port_num)) {
-				cma_leave_roce_mc_group(id_priv, mc);
-			}
-			return;
-		}
+		if (memcmp(&mc->addr, addr, rdma_addr_size(addr)) != 0)
+			continue;
+		list_del(&mc->list);
+		spin_unlock_irq(&id_priv->lock);
+
+		WARN_ON(id_priv->cma_dev->device != id->device);
+		destroy_mc(id_priv, mc);
+		return;
 	}
 	spin_unlock_irq(&id_priv->lock);
 }
@@ -4710,6 +4755,19 @@
 {
 	int ret;
 
+	/*
+	 * There is a rare lock ordering dependency in cma_netdev_callback()
+	 * that only happens when bonding is enabled. Teach lockdep that rtnl
+	 * must never be nested under lock so it can find these without having
+	 * to test with bonding.
+	 */
+	if (IS_ENABLED(CONFIG_LOCKDEP)) {
+		rtnl_lock();
+		mutex_lock(&lock);
+		mutex_unlock(&lock);
+		rtnl_unlock();
+	}
+
 	cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM);
 	if (!cma_wq)
 		return -ENOMEM;
@@ -4736,6 +4794,7 @@
 err:
 	unregister_netdevice_notifier(&cma_nb);
 	ib_sa_unregister_client(&sa_client);
+	unregister_pernet_subsys(&cma_pernet_operations);
 err_wq:
 	destroy_workqueue(cma_wq);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/cma_configfs.c
+++ linux-ein-5.4.0/drivers/infiniband/core/cma_configfs.c
@@ -218,7 +218,7 @@
 	}
 
 	for (i = 0; i < ports_num; i++) {
-		char port_str[10];
+		char port_str[11];
 
 		ports[i].port_num = i + 1;
 		snprintf(port_str, sizeof(port_str), "%u", i + 1);
@@ -322,8 +322,21 @@
 	return ERR_PTR(err);
 }
 
+static void drop_cma_dev(struct config_group *cgroup, struct config_item *item)
+{
+	struct config_group *group =
+		container_of(item, struct config_group, cg_item);
+	struct cma_dev_group *cma_dev_group =
+		container_of(group, struct cma_dev_group, device_group);
+
+	configfs_remove_default_groups(&cma_dev_group->ports_group);
+	configfs_remove_default_groups(&cma_dev_group->device_group);
+	config_item_put(item);
+}
+
 static struct configfs_group_operations cma_subsys_group_ops = {
 	.make_group	= make_cma_dev,
+	.drop_item	= drop_cma_dev,
 };
 
 static const struct config_item_type cma_subsys_type = {
--- linux-ein-5.4.0.orig/drivers/infiniband/core/core_priv.h
+++ linux-ein-5.4.0/drivers/infiniband/core/core_priv.h
@@ -149,6 +149,7 @@
 int ib_cache_setup_one(struct ib_device *device);
 void ib_cache_cleanup_one(struct ib_device *device);
 void ib_cache_release_one(struct ib_device *device);
+void ib_dispatch_event_clients(struct ib_event *event);
 
 #ifdef CONFIG_CGROUP_RDMA
 void ib_device_register_rdmacg(struct ib_device *device);
@@ -337,6 +338,21 @@
 	qp->pd = pd;
 	qp->uobject = uobj;
 	qp->real_qp = qp;
+
+	qp->qp_type = attr->qp_type;
+	qp->qp_context = attr->qp_context;
+	qp->rwq_ind_tbl = attr->rwq_ind_tbl;
+	qp->send_cq = attr->send_cq;
+	qp->recv_cq = attr->recv_cq;
+	qp->srq = attr->srq;
+	qp->rwq_ind_tbl = attr->rwq_ind_tbl;
+	qp->event_handler = attr->event_handler;
+
+	atomic_set(&qp->usecnt, 0);
+	spin_lock_init(&qp->mr_lock);
+	INIT_LIST_HEAD(&qp->rdma_mrs);
+	INIT_LIST_HEAD(&qp->sig_mrs);
+
 	/*
 	 * We don't track XRC QPs for now, because they don't have PD
 	 * and more importantly they are created internaly by driver,
@@ -388,4 +404,15 @@
 
 int rdma_nl_net_init(struct rdma_dev_net *rnet);
 void rdma_nl_net_exit(struct rdma_dev_net *rnet);
+
+struct rdma_umap_priv {
+	struct vm_area_struct *vma;
+	struct list_head list;
+	struct rdma_user_mmap_entry *entry;
+};
+
+void rdma_umap_priv_init(struct rdma_umap_priv *priv,
+			 struct vm_area_struct *vma,
+			 struct rdma_user_mmap_entry *entry);
+
 #endif /* _CORE_PRIV_H */
--- linux-ein-5.4.0.orig/drivers/infiniband/core/counters.c
+++ linux-ein-5.4.0/drivers/infiniband/core/counters.c
@@ -195,7 +195,7 @@
 	return ret;
 }
 
-static void counter_history_stat_update(const struct rdma_counter *counter)
+static void counter_history_stat_update(struct rdma_counter *counter)
 {
 	struct ib_device *dev = counter->device;
 	struct rdma_port_counter *port_counter;
@@ -205,6 +205,8 @@
 	if (!port_counter->hstats)
 		return;
 
+	rdma_counter_query_stats(counter);
+
 	for (i = 0; i < counter->stats->num_counters; i++)
 		port_counter->hstats->value[i] += counter->stats->value[i];
 }
@@ -282,6 +284,9 @@
 	struct rdma_counter *counter;
 	int ret;
 
+	if (!qp->res.valid || rdma_is_kernel_res(&qp->res))
+		return 0;
+
 	if (!rdma_is_port_valid(dev, port))
 		return -EINVAL;
 
@@ -463,10 +468,15 @@
 int rdma_counter_bind_qpn(struct ib_device *dev, u8 port,
 			  u32 qp_num, u32 counter_id)
 {
+	struct rdma_port_counter *port_counter;
 	struct rdma_counter *counter;
 	struct ib_qp *qp;
 	int ret;
 
+	port_counter = &dev->port_data[port].port_counter;
+	if (port_counter->mode.mode == RDMA_COUNTER_MODE_AUTO)
+		return -EINVAL;
+
 	qp = rdma_counter_get_qp(dev, qp_num);
 	if (!qp)
 		return -ENOENT;
@@ -477,7 +487,7 @@
 		goto err;
 	}
 
-	if (counter->res.task != qp->res.task) {
+	if (rdma_is_kernel_res(&counter->res) != rdma_is_kernel_res(&qp->res)) {
 		ret = -EINVAL;
 		goto err_task;
 	}
@@ -503,6 +513,7 @@
 int rdma_counter_bind_qpn_alloc(struct ib_device *dev, u8 port,
 				u32 qp_num, u32 *counter_id)
 {
+	struct rdma_port_counter *port_counter;
 	struct rdma_counter *counter;
 	struct ib_qp *qp;
 	int ret;
@@ -510,9 +521,13 @@
 	if (!rdma_is_port_valid(dev, port))
 		return -EINVAL;
 
-	if (!dev->port_data[port].port_counter.hstats)
+	port_counter = &dev->port_data[port].port_counter;
+	if (!port_counter->hstats)
 		return -EOPNOTSUPP;
 
+	if (port_counter->mode.mode == RDMA_COUNTER_MODE_AUTO)
+		return -EINVAL;
+
 	qp = rdma_counter_get_qp(dev, qp_num);
 	if (!qp)
 		return -ENOENT;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/device.c
+++ linux-ein-5.4.0/drivers/infiniband/core/device.c
@@ -591,6 +591,7 @@
 
 	INIT_LIST_HEAD(&device->event_handler_list);
 	spin_lock_init(&device->event_handler_lock);
+	init_rwsem(&device->event_handler_rwsem);
 	mutex_init(&device->unregistration_lock);
 	/*
 	 * client_data needs to be alloc because we don't want our mark to be
@@ -898,7 +899,9 @@
 	cdev->dev.parent = device->dev.parent;
 	rdma_init_coredev(cdev, device, read_pnet(&rnet->net));
 	cdev->dev.release = compatdev_release;
-	dev_set_name(&cdev->dev, "%s", dev_name(&device->dev));
+	ret = dev_set_name(&cdev->dev, "%s", dev_name(&device->dev));
+	if (ret)
+		goto add_err;
 
 	ret = device_add(&cdev->dev);
 	if (ret)
@@ -1199,9 +1202,21 @@
 		WARN_ON_ONCE(!parent);
 		device->dma_device = parent;
 	}
-	/* Setup default max segment size for all IB devices */
-	dma_set_max_seg_size(device->dma_device, SZ_2G);
 
+	if (!device->dev.dma_parms) {
+		if (parent) {
+			/*
+			 * The caller did not provide DMA parameters, so
+			 * 'parent' probably represents a PCI device. The PCI
+			 * core sets the maximum segment size to 64
+			 * KB. Increase this parameter to 2 GB.
+			 */
+			device->dev.dma_parms = parent->dma_parms;
+			dma_set_max_seg_size(device->dma_device, SZ_2G);
+		} else {
+			WARN_ON_ONCE(true);
+		}
+	}
 }
 
 /*
@@ -1315,6 +1330,10 @@
 	return ret;
 }
 
+static void prevent_dealloc_device(struct ib_device *ib_dev)
+{
+}
+
 /**
  * ib_register_device - Register an IB device with IB core
  * @device:Device to register
@@ -1368,9 +1387,6 @@
 	}
 
 	ret = enable_device_and_get(device);
-	dev_set_uevent_suppress(&device->dev, false);
-	/* Mark for userspace that device is ready */
-	kobject_uevent(&device->dev.kobj, KOBJ_ADD);
 	if (ret) {
 		void (*dealloc_fn)(struct ib_device *);
 
@@ -1382,16 +1398,20 @@
 		 * possibility for a parallel unregistration along with this
 		 * error flow. Since we have a refcount here we know any
 		 * parallel flow is stopped in disable_device and will see the
-		 * NULL pointers, causing the responsibility to
+		 * special dealloc_driver pointer, causing the responsibility to
 		 * ib_dealloc_device() to revert back to this thread.
 		 */
 		dealloc_fn = device->ops.dealloc_driver;
-		device->ops.dealloc_driver = NULL;
+		device->ops.dealloc_driver = prevent_dealloc_device;
 		ib_device_put(device);
 		__ib_unregister_device(device);
 		device->ops.dealloc_driver = dealloc_fn;
+		dev_set_uevent_suppress(&device->dev, false);
 		return ret;
 	}
+	dev_set_uevent_suppress(&device->dev, false);
+	/* Mark for userspace that device is ready */
+	kobject_uevent(&device->dev.kobj, KOBJ_ADD);
 	ib_device_put(device);
 
 	return 0;
@@ -1434,7 +1454,8 @@
 	 * Drivers using the new flow may not call ib_dealloc_device except
 	 * in error unwind prior to registration success.
 	 */
-	if (ib_dev->ops.dealloc_driver) {
+	if (ib_dev->ops.dealloc_driver &&
+	    ib_dev->ops.dealloc_driver != prevent_dealloc_device) {
 		WARN_ON(kref_read(&ib_dev->dev.kobj.kref) <= 1);
 		ib_dealloc_device(ib_dev);
 	}
@@ -1920,17 +1941,15 @@
  *
  * ib_register_event_handler() registers an event handler that will be
  * called back when asynchronous IB events occur (as defined in
- * chapter 11 of the InfiniBand Architecture Specification).  This
- * callback may occur in interrupt context.
+ * chapter 11 of the InfiniBand Architecture Specification). This
+ * callback occurs in workqueue context.
  */
 void ib_register_event_handler(struct ib_event_handler *event_handler)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&event_handler->device->event_handler_lock, flags);
+	down_write(&event_handler->device->event_handler_rwsem);
 	list_add_tail(&event_handler->list,
 		      &event_handler->device->event_handler_list);
-	spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags);
+	up_write(&event_handler->device->event_handler_rwsem);
 }
 EXPORT_SYMBOL(ib_register_event_handler);
 
@@ -1943,35 +1962,23 @@
  */
 void ib_unregister_event_handler(struct ib_event_handler *event_handler)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&event_handler->device->event_handler_lock, flags);
+	down_write(&event_handler->device->event_handler_rwsem);
 	list_del(&event_handler->list);
-	spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags);
+	up_write(&event_handler->device->event_handler_rwsem);
 }
 EXPORT_SYMBOL(ib_unregister_event_handler);
 
-/**
- * ib_dispatch_event - Dispatch an asynchronous event
- * @event:Event to dispatch
- *
- * Low-level drivers must call ib_dispatch_event() to dispatch the
- * event to all registered event handlers when an asynchronous event
- * occurs.
- */
-void ib_dispatch_event(struct ib_event *event)
+void ib_dispatch_event_clients(struct ib_event *event)
 {
-	unsigned long flags;
 	struct ib_event_handler *handler;
 
-	spin_lock_irqsave(&event->device->event_handler_lock, flags);
+	down_read(&event->device->event_handler_rwsem);
 
 	list_for_each_entry(handler, &event->device->event_handler_list, list)
 		handler->handler(handler, event);
 
-	spin_unlock_irqrestore(&event->device->event_handler_lock, flags);
+	up_read(&event->device->event_handler_rwsem);
 }
-EXPORT_SYMBOL(ib_dispatch_event);
 
 static int iw_query_port(struct ib_device *device,
 			   u8 port_num,
@@ -2397,8 +2404,12 @@
 		rc = device->ops.modify_port(device, port_num,
 					     port_modify_mask,
 					     port_modify);
+	else if (rdma_protocol_roce(device, port_num) &&
+		 ((port_modify->set_port_cap_mask & ~IB_PORT_CM_SUP) == 0 ||
+		  (port_modify->clr_port_cap_mask & ~IB_PORT_CM_SUP) == 0))
+		rc = 0;
 	else
-		rc = rdma_protocol_roce(device, port_num) ? 0 : -ENOSYS;
+		rc = -EOPNOTSUPP;
 	return rc;
 }
 EXPORT_SYMBOL(ib_modify_port);
@@ -2427,7 +2438,8 @@
 		     ++i) {
 			ret = rdma_query_gid(device, port, i, &tmp_gid);
 			if (ret)
-				return ret;
+				continue;
+
 			if (!memcmp(&tmp_gid, gid, sizeof *gid)) {
 				*port_num = port;
 				if (index)
@@ -2630,6 +2642,7 @@
 	SET_DEVICE_OP(dev_ops, map_mr_sg_pi);
 	SET_DEVICE_OP(dev_ops, map_phys_fmr);
 	SET_DEVICE_OP(dev_ops, mmap);
+	SET_DEVICE_OP(dev_ops, mmap_free);
 	SET_DEVICE_OP(dev_ops, modify_ah);
 	SET_DEVICE_OP(dev_ops, modify_cq);
 	SET_DEVICE_OP(dev_ops, modify_device);
@@ -2750,10 +2763,18 @@
 
 	nldev_init();
 	rdma_nl_register(RDMA_NL_LS, ibnl_ls_cb_table);
-	roce_gid_mgmt_init();
+	ret = roce_gid_mgmt_init();
+	if (ret) {
+		pr_warn("Couldn't init RoCE GID management\n");
+		goto err_parent;
+	}
 
 	return 0;
 
+err_parent:
+	rdma_nl_unregister(RDMA_NL_LS);
+	nldev_exit();
+	unregister_pernet_device(&rdma_dev_net_ops);
 err_compat:
 	unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
 err_sa:
@@ -2776,8 +2797,8 @@
 static void __exit ib_core_cleanup(void)
 {
 	roce_gid_mgmt_cleanup();
-	nldev_exit();
 	rdma_nl_unregister(RDMA_NL_LS);
+	nldev_exit();
 	unregister_pernet_device(&rdma_dev_net_ops);
 	unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
 	ib_sa_cleanup();
--- linux-ein-5.4.0.orig/drivers/infiniband/core/ib_core_uverbs.c
+++ linux-ein-5.4.0/drivers/infiniband/core/ib_core_uverbs.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2019 Marvell. All rights reserved.
+ */
+#include <linux/xarray.h>
+#include "uverbs.h"
+#include "core_priv.h"
+
+/**
+ * rdma_umap_priv_init() - Initialize the private data of a vma
+ *
+ * @priv: The already allocated private data
+ * @vma: The vm area struct that needs private data
+ * @entry: entry into the mmap_xa that needs to be linked with
+ *       this vma
+ *
+ * Each time we map IO memory into user space this keeps track of the
+ * mapping. When the device is hot-unplugged we 'zap' the mmaps in user space
+ * to point to the zero page and allow the hot unplug to proceed.
+ *
+ * This is necessary for cases like PCI physical hot unplug as the actual BAR
+ * memory may vanish after this and access to it from userspace could MCE.
+ *
+ * RDMA drivers supporting disassociation must have their user space designed
+ * to cope in some way with their IO pages going to the zero page.
+ *
+ */
+void rdma_umap_priv_init(struct rdma_umap_priv *priv,
+			 struct vm_area_struct *vma,
+			 struct rdma_user_mmap_entry *entry)
+{
+	struct ib_uverbs_file *ufile = vma->vm_file->private_data;
+
+	priv->vma = vma;
+	if (entry) {
+		kref_get(&entry->ref);
+		priv->entry = entry;
+	}
+	vma->vm_private_data = priv;
+	/* vm_ops is setup in ib_uverbs_mmap() to avoid module dependencies */
+
+	mutex_lock(&ufile->umap_lock);
+	list_add(&priv->list, &ufile->umaps);
+	mutex_unlock(&ufile->umap_lock);
+}
+EXPORT_SYMBOL(rdma_umap_priv_init);
+
+/**
+ * rdma_user_mmap_io() - Map IO memory into a process
+ *
+ * @ucontext: associated user context
+ * @vma: the vma related to the current mmap call
+ * @pfn: pfn to map
+ * @size: size to map
+ * @prot: pgprot to use in remap call
+ * @entry: mmap_entry retrieved from rdma_user_mmap_entry_get(), or NULL
+ *         if mmap_entry is not used by the driver
+ *
+ * This is to be called by drivers as part of their mmap() functions if they
+ * wish to send something like PCI-E BAR memory to userspace.
+ *
+ * Return -EINVAL on wrong flags or size, -EAGAIN on failure to map. 0 on
+ * success.
+ */
+int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma,
+		      unsigned long pfn, unsigned long size, pgprot_t prot,
+		      struct rdma_user_mmap_entry *entry)
+{
+	struct ib_uverbs_file *ufile = ucontext->ufile;
+	struct rdma_umap_priv *priv;
+
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	if (vma->vm_end - vma->vm_start != size)
+		return -EINVAL;
+
+	/* Driver is using this wrong, must be called by ib_uverbs_mmap */
+	if (WARN_ON(!vma->vm_file ||
+		    vma->vm_file->private_data != ufile))
+		return -EINVAL;
+	lockdep_assert_held(&ufile->device->disassociate_srcu);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	vma->vm_page_prot = prot;
+	if (io_remap_pfn_range(vma, vma->vm_start, pfn, size, prot)) {
+		kfree(priv);
+		return -EAGAIN;
+	}
+
+	rdma_umap_priv_init(priv, vma, entry);
+	return 0;
+}
+EXPORT_SYMBOL(rdma_user_mmap_io);
+
+/**
+ * rdma_user_mmap_entry_get_pgoff() - Get an entry from the mmap_xa
+ *
+ * @ucontext: associated user context
+ * @pgoff: The mmap offset >> PAGE_SHIFT
+ *
+ * This function is called when a user tries to mmap with an offset (returned
+ * by rdma_user_mmap_get_offset()) it initially received from the driver. The
+ * rdma_user_mmap_entry was created by the function
+ * rdma_user_mmap_entry_insert().  This function increases the refcnt of the
+ * entry so that it won't be deleted from the xarray in the meantime.
+ *
+ * Return an reference to an entry if exists or NULL if there is no
+ * match. rdma_user_mmap_entry_put() must be called to put the reference.
+ */
+struct rdma_user_mmap_entry *
+rdma_user_mmap_entry_get_pgoff(struct ib_ucontext *ucontext,
+			       unsigned long pgoff)
+{
+	struct rdma_user_mmap_entry *entry;
+
+	if (pgoff > U32_MAX)
+		return NULL;
+
+	xa_lock(&ucontext->mmap_xa);
+
+	entry = xa_load(&ucontext->mmap_xa, pgoff);
+
+	/*
+	 * If refcount is zero, entry is already being deleted, driver_removed
+	 * indicates that the no further mmaps are possible and we waiting for
+	 * the active VMAs to be closed.
+	 */
+	if (!entry || entry->start_pgoff != pgoff || entry->driver_removed ||
+	    !kref_get_unless_zero(&entry->ref))
+		goto err;
+
+	xa_unlock(&ucontext->mmap_xa);
+
+	ibdev_dbg(ucontext->device, "mmap: pgoff[%#lx] npages[%#zx] returned\n",
+		  pgoff, entry->npages);
+
+	return entry;
+
+err:
+	xa_unlock(&ucontext->mmap_xa);
+	return NULL;
+}
+EXPORT_SYMBOL(rdma_user_mmap_entry_get_pgoff);
+
+/**
+ * rdma_user_mmap_entry_get() - Get an entry from the mmap_xa
+ *
+ * @ucontext: associated user context
+ * @vma: the vma being mmap'd into
+ *
+ * This function is like rdma_user_mmap_entry_get_pgoff() except that it also
+ * checks that the VMA is correct.
+ */
+struct rdma_user_mmap_entry *
+rdma_user_mmap_entry_get(struct ib_ucontext *ucontext,
+			 struct vm_area_struct *vma)
+{
+	struct rdma_user_mmap_entry *entry;
+
+	if (!(vma->vm_flags & VM_SHARED))
+		return NULL;
+	entry = rdma_user_mmap_entry_get_pgoff(ucontext, vma->vm_pgoff);
+	if (!entry)
+		return NULL;
+	if (entry->npages * PAGE_SIZE != vma->vm_end - vma->vm_start) {
+		rdma_user_mmap_entry_put(entry);
+		return NULL;
+	}
+	return entry;
+}
+EXPORT_SYMBOL(rdma_user_mmap_entry_get);
+
+static void rdma_user_mmap_entry_free(struct kref *kref)
+{
+	struct rdma_user_mmap_entry *entry =
+		container_of(kref, struct rdma_user_mmap_entry, ref);
+	struct ib_ucontext *ucontext = entry->ucontext;
+	unsigned long i;
+
+	/*
+	 * Erase all entries occupied by this single entry, this is deferred
+	 * until all VMA are closed so that the mmap offsets remain unique.
+	 */
+	xa_lock(&ucontext->mmap_xa);
+	for (i = 0; i < entry->npages; i++)
+		__xa_erase(&ucontext->mmap_xa, entry->start_pgoff + i);
+	xa_unlock(&ucontext->mmap_xa);
+
+	ibdev_dbg(ucontext->device, "mmap: pgoff[%#lx] npages[%#zx] removed\n",
+		  entry->start_pgoff, entry->npages);
+
+	if (ucontext->device->ops.mmap_free)
+		ucontext->device->ops.mmap_free(entry);
+}
+
+/**
+ * rdma_user_mmap_entry_put() - Drop reference to the mmap entry
+ *
+ * @entry: an entry in the mmap_xa
+ *
+ * This function is called when the mapping is closed if it was
+ * an io mapping or when the driver is done with the entry for
+ * some other reason.
+ * Should be called after rdma_user_mmap_entry_get was called
+ * and entry is no longer needed. This function will erase the
+ * entry and free it if its refcnt reaches zero.
+ */
+void rdma_user_mmap_entry_put(struct rdma_user_mmap_entry *entry)
+{
+	kref_put(&entry->ref, rdma_user_mmap_entry_free);
+}
+EXPORT_SYMBOL(rdma_user_mmap_entry_put);
+
+/**
+ * rdma_user_mmap_entry_remove() - Drop reference to entry and
+ *				   mark it as unmmapable
+ *
+ * @entry: the entry to insert into the mmap_xa
+ *
+ * Drivers can call this to prevent userspace from creating more mappings for
+ * entry, however existing mmaps continue to exist and ops->mmap_free() will
+ * not be called until all user mmaps are destroyed.
+ */
+void rdma_user_mmap_entry_remove(struct rdma_user_mmap_entry *entry)
+{
+	if (!entry)
+		return;
+
+	entry->driver_removed = true;
+	kref_put(&entry->ref, rdma_user_mmap_entry_free);
+}
+EXPORT_SYMBOL(rdma_user_mmap_entry_remove);
+
+/**
+ * rdma_user_mmap_entry_insert() - Insert an entry to the mmap_xa
+ *
+ * @ucontext: associated user context.
+ * @entry: the entry to insert into the mmap_xa
+ * @length: length of the address that will be mmapped
+ *
+ * This function should be called by drivers that use the rdma_user_mmap
+ * interface for implementing their mmap syscall A database of mmap offsets is
+ * handled in the core and helper functions are provided to insert entries
+ * into the database and extract entries when the user calls mmap with the
+ * given offset.  The function allocates a unique page offset that should be
+ * provided to user, the user will use the offset to retrieve information such
+ * as address to be mapped and how.
+ *
+ * Return: 0 on success and -ENOMEM on failure
+ */
+int rdma_user_mmap_entry_insert(struct ib_ucontext *ucontext,
+				struct rdma_user_mmap_entry *entry,
+				size_t length)
+{
+	struct ib_uverbs_file *ufile = ucontext->ufile;
+	XA_STATE(xas, &ucontext->mmap_xa, 0);
+	u32 xa_first, xa_last, npages;
+	int err;
+	u32 i;
+
+	if (!entry)
+		return -EINVAL;
+
+	kref_init(&entry->ref);
+	entry->ucontext = ucontext;
+
+	/*
+	 * We want the whole allocation to be done without interruption from a
+	 * different thread. The allocation requires finding a free range and
+	 * storing. During the xa_insert the lock could be released, possibly
+	 * allowing another thread to choose the same range.
+	 */
+	mutex_lock(&ufile->umap_lock);
+
+	xa_lock(&ucontext->mmap_xa);
+
+	/* We want to find an empty range */
+	npages = (u32)DIV_ROUND_UP(length, PAGE_SIZE);
+	entry->npages = npages;
+	while (true) {
+		/* First find an empty index */
+		xas_find_marked(&xas, U32_MAX, XA_FREE_MARK);
+		if (xas.xa_node == XAS_RESTART)
+			goto err_unlock;
+
+		xa_first = xas.xa_index;
+
+		/* Is there enough room to have the range? */
+		if (check_add_overflow(xa_first, npages, &xa_last))
+			goto err_unlock;
+
+		/*
+		 * Now look for the next present entry. If an entry doesn't
+		 * exist, we found an empty range and can proceed.
+		 */
+		xas_next_entry(&xas, xa_last - 1);
+		if (xas.xa_node == XAS_BOUNDS || xas.xa_index >= xa_last)
+			break;
+	}
+
+	for (i = xa_first; i < xa_last; i++) {
+		err = __xa_insert(&ucontext->mmap_xa, i, entry, GFP_KERNEL);
+		if (err)
+			goto err_undo;
+	}
+
+	/*
+	 * Internally the kernel uses a page offset, in libc this is a byte
+	 * offset. Drivers should not return pgoff to userspace.
+	 */
+	entry->start_pgoff = xa_first;
+	xa_unlock(&ucontext->mmap_xa);
+	mutex_unlock(&ufile->umap_lock);
+
+	ibdev_dbg(ucontext->device, "mmap: pgoff[%#lx] npages[%#x] inserted\n",
+		  entry->start_pgoff, npages);
+
+	return 0;
+
+err_undo:
+	for (; i > xa_first; i--)
+		__xa_erase(&ucontext->mmap_xa, i - 1);
+
+err_unlock:
+	xa_unlock(&ucontext->mmap_xa);
+	mutex_unlock(&ufile->umap_lock);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(rdma_user_mmap_entry_insert);
--- linux-ein-5.4.0.orig/drivers/infiniband/core/ib_peer_mem.h
+++ linux-ein-5.4.0/drivers/infiniband/core/ib_peer_mem.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/*
+ * Copyright (c) 2014-2020,  Mellanox Technologies. All rights reserved.
+ */
+#ifndef RDMA_IB_PEER_MEM_H
+#define RDMA_IB_PEER_MEM_H
+
+#include <rdma/peer_mem.h>
+#include <linux/kobject.h>
+#include <linux/xarray.h>
+#include <rdma/ib_umem.h>
+
+struct ib_peer_memory_statistics {
+	atomic64_t num_alloc_mrs;
+	atomic64_t num_dealloc_mrs;
+	atomic64_t num_reg_pages;
+	atomic64_t num_dereg_pages;
+	atomic64_t num_reg_bytes;
+	atomic64_t num_dereg_bytes;
+	unsigned long num_free_callbacks;
+};
+
+struct ib_peer_memory_client {
+	struct kobject kobj;
+	refcount_t usecnt;
+	struct completion usecnt_zero;
+	const struct peer_memory_client *peer_mem;
+	struct list_head core_peer_list;
+	struct ib_peer_memory_statistics stats;
+	struct xarray umem_xa;
+	u32 xa_cyclic_next;
+	bool invalidation_required;
+};
+
+enum ib_umem_mapped_state {
+	UMEM_PEER_UNMAPPED,
+	UMEM_PEER_MAPPED,
+	UMEM_PEER_INVALIDATED,
+};
+
+struct ib_umem_peer {
+	struct ib_umem umem;
+	struct kref kref;
+	/* peer memory that manages this umem */
+	struct ib_peer_memory_client *ib_peer_client;
+	void *peer_client_context;
+	umem_invalidate_func_t invalidation_func;
+	void *invalidation_private;
+	struct mutex mapping_lock;
+	enum ib_umem_mapped_state mapped_state;
+	u32 xa_id;
+};
+
+struct ib_umem *ib_peer_umem_get(struct ib_umem *old_umem, int old_ret,
+				 unsigned long peer_mem_flags);
+void ib_peer_umem_release(struct ib_umem *umem);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/infiniband/core/iwcm.c
+++ linux-ein-5.4.0/drivers/infiniband/core/iwcm.c
@@ -159,8 +159,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)
@@ -1185,29 +1187,34 @@
 
 	ret = iwpm_init(RDMA_NL_IWCM);
 	if (ret)
-		pr_err("iw_cm: couldn't init iwpm\n");
-	else
-		rdma_nl_register(RDMA_NL_IWCM, iwcm_nl_cb_table);
+		return ret;
+
 	iwcm_wq = alloc_ordered_workqueue("iw_cm_wq", 0);
 	if (!iwcm_wq)
-		return -ENOMEM;
+		goto err_alloc;
 
 	iwcm_ctl_table_hdr = register_net_sysctl(&init_net, "net/iw_cm",
 						 iwcm_ctl_table);
 	if (!iwcm_ctl_table_hdr) {
 		pr_err("iw_cm: couldn't register sysctl paths\n");
-		destroy_workqueue(iwcm_wq);
-		return -ENOMEM;
+		goto err_sysctl;
 	}
 
+	rdma_nl_register(RDMA_NL_IWCM, iwcm_nl_cb_table);
 	return 0;
+
+err_sysctl:
+	destroy_workqueue(iwcm_wq);
+err_alloc:
+	iwpm_exit(RDMA_NL_IWCM);
+	return -ENOMEM;
 }
 
 static void __exit iw_cm_cleanup(void)
 {
+	rdma_nl_unregister(RDMA_NL_IWCM);
 	unregister_net_sysctl_table(iwcm_ctl_table_hdr);
 	destroy_workqueue(iwcm_wq);
-	rdma_nl_unregister(RDMA_NL_IWCM);
 	iwpm_exit(RDMA_NL_IWCM);
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/core/mad.c
+++ linux-ein-5.4.0/drivers/infiniband/core/mad.c
@@ -639,10 +639,10 @@
 	xa_erase(&ib_mad_clients, mad_agent_priv->agent.hi_tid);
 
 	flush_workqueue(port_priv->wq);
-	ib_cancel_rmpp_recvs(mad_agent_priv);
 
 	deref_mad_agent(mad_agent_priv);
 	wait_for_completion(&mad_agent_priv->comp);
+	ib_cancel_rmpp_recvs(mad_agent_priv);
 
 	ib_mad_agent_security_cleanup(&mad_agent_priv->agent);
 
@@ -2960,6 +2960,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-ein-5.4.0.orig/drivers/infiniband/core/nldev.c
+++ linux-ein-5.4.0/drivers/infiniband/core/nldev.c
@@ -493,7 +493,7 @@
 	struct rdma_cm_id *cm_id = &id_priv->id;
 
 	if (port && port != cm_id->port_num)
-		return 0;
+		return -EAGAIN;
 
 	if (cm_id->port_num &&
 	    nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, cm_id->port_num))
@@ -694,6 +694,8 @@
 	int ret = 0;
 
 	table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP);
+	if (!table_attr)
+		return -EMSGSIZE;
 
 	rt = &counter->device->res[RDMA_RESTRACK_QP];
 	xa_lock(&rt->xa);
@@ -702,9 +704,6 @@
 			continue;
 
 		qp = container_of(res, struct ib_qp, res);
-		if (qp->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
-			continue;
-
 		if (!qp->counter || (qp->counter->id != counter->id))
 			continue;
 
@@ -863,6 +862,10 @@
 
 		nla_strlcpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
 			    IB_DEVICE_NAME_MAX);
+		if (strlen(name) == 0) {
+			err = -EINVAL;
+			goto done;
+		}
 		err = ib_device_rename(device, name);
 		goto done;
 	}
@@ -1244,10 +1247,10 @@
 
 	has_cap_net_admin = netlink_capable(skb, CAP_NET_ADMIN);
 	ret = fe->fill_res_func(msg, has_cap_net_admin, res, port);
-	rdma_restrack_put(res);
 	if (ret)
 		goto err_free;
 
+	rdma_restrack_put(res);
 	nlmsg_end(msg, nlh);
 	ib_device_put(device);
 	return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid);
@@ -1468,7 +1471,7 @@
 
 	nla_strlcpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
 		    sizeof(ibdev_name));
-	if (strchr(ibdev_name, '%'))
+	if (strchr(ibdev_name, '%') || strlen(ibdev_name) == 0)
 		return -EINVAL;
 
 	nla_strlcpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type));
@@ -1711,6 +1714,8 @@
 		if (ret)
 			goto err_msg;
 	} else {
+		if (!tb[RDMA_NLDEV_ATTR_RES_LQPN])
+			goto err_msg;
 		qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]);
 		if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]) {
 			cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
@@ -2075,6 +2080,7 @@
 	},
 	[RDMA_NLDEV_CMD_SYS_SET] = {
 		.doit = nldev_set_sys_set_doit,
+		.flags = RDMA_NL_ADMIN_PERM,
 	},
 	[RDMA_NLDEV_CMD_STAT_SET] = {
 		.doit = nldev_stat_set_doit,
@@ -2095,7 +2101,7 @@
 	rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table);
 }
 
-void __exit nldev_exit(void)
+void nldev_exit(void)
 {
 	rdma_nl_unregister(RDMA_NL_NLDEV);
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/core/peer_mem.c
+++ linux-ein-5.4.0/drivers/infiniband/core/peer_mem.c
@@ -0,0 +1,559 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2014-2020,  Mellanox Technologies. All rights reserved.
+ */
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
+#include <linux/sched/mm.h>
+#include "ib_peer_mem.h"
+static DEFINE_MUTEX(peer_memory_mutex);
+static LIST_HEAD(peer_memory_list);
+static struct kobject *peers_kobj;
+#define PEER_NO_INVALIDATION_ID U32_MAX
+static int ib_invalidate_peer_memory(void *reg_handle, u64 core_context);
+struct peer_mem_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct ib_peer_memory_client *ib_peer_client,
+			struct peer_mem_attribute *attr, char *buf);
+	ssize_t (*store)(struct ib_peer_memory_client *ib_peer_client,
+			 struct peer_mem_attribute *attr, const char *buf,
+			 size_t count);
+};
+
+#define PEER_ATTR_RO(_name)                                                    \
+	struct peer_mem_attribute peer_attr_ ## _name = __ATTR_RO(_name)
+
+static ssize_t version_show(struct ib_peer_memory_client *ib_peer_client,
+			    struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+			 ib_peer_client->peer_mem->version);
+}
+
+static PEER_ATTR_RO(version);
+static ssize_t num_alloc_mrs_show(struct ib_peer_memory_client *ib_peer_client,
+				  struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_alloc_mrs));
+}
+
+static PEER_ATTR_RO(num_alloc_mrs);
+static ssize_t
+num_dealloc_mrs_show(struct ib_peer_memory_client *ib_peer_client,
+		     struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_dealloc_mrs));
+}
+
+static PEER_ATTR_RO(num_dealloc_mrs);
+static ssize_t num_reg_pages_show(struct ib_peer_memory_client *ib_peer_client,
+				  struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_reg_pages));
+}
+
+static PEER_ATTR_RO(num_reg_pages);
+static ssize_t
+num_dereg_pages_show(struct ib_peer_memory_client *ib_peer_client,
+		     struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_dereg_pages));
+}
+
+static PEER_ATTR_RO(num_dereg_pages);
+static ssize_t num_reg_bytes_show(struct ib_peer_memory_client *ib_peer_client,
+				  struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_reg_bytes));
+}
+
+static PEER_ATTR_RO(num_reg_bytes);
+static ssize_t
+num_dereg_bytes_show(struct ib_peer_memory_client *ib_peer_client,
+		     struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(
+		buf, PAGE_SIZE, "%llu\n",
+		(u64)atomic64_read(&ib_peer_client->stats.num_dereg_bytes));
+}
+
+static PEER_ATTR_RO(num_dereg_bytes);
+static ssize_t
+num_free_callbacks_show(struct ib_peer_memory_client *ib_peer_client,
+			struct peer_mem_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%lu\n",
+			 ib_peer_client->stats.num_free_callbacks);
+}
+
+static PEER_ATTR_RO(num_free_callbacks);
+static struct attribute *peer_mem_attrs[] = {
+			&peer_attr_version.attr,
+			&peer_attr_num_alloc_mrs.attr,
+			&peer_attr_num_dealloc_mrs.attr,
+			&peer_attr_num_reg_pages.attr,
+			&peer_attr_num_dereg_pages.attr,
+			&peer_attr_num_reg_bytes.attr,
+			&peer_attr_num_dereg_bytes.attr,
+			&peer_attr_num_free_callbacks.attr,
+			NULL,
+};
+
+static const struct attribute_group peer_mem_attr_group = {
+	.attrs = peer_mem_attrs,
+};
+
+static ssize_t peer_attr_show(struct kobject *kobj, struct attribute *attr,
+			      char *buf)
+{
+	struct peer_mem_attribute *peer_attr =
+		container_of(attr, struct peer_mem_attribute, attr);
+	if (!peer_attr->show)
+		return -EIO;
+	return peer_attr->show(container_of(kobj, struct ib_peer_memory_client,
+					    kobj),
+			       peer_attr, buf);
+}
+
+static const struct sysfs_ops peer_mem_sysfs_ops = {
+	.show = peer_attr_show,
+};
+
+static void ib_peer_memory_client_release(struct kobject *kobj)
+{
+	struct ib_peer_memory_client *ib_peer_client =
+		container_of(kobj, struct ib_peer_memory_client, kobj);
+	kfree(ib_peer_client);
+}
+
+static struct kobj_type peer_mem_type = {
+	.sysfs_ops = &peer_mem_sysfs_ops,
+	.release = ib_peer_memory_client_release,
+};
+
+static int ib_memory_peer_check_mandatory(const struct peer_memory_client
+						     *peer_client)
+{
+#define PEER_MEM_MANDATORY_FUNC(x) {offsetof(struct peer_memory_client, x), #x}
+	int i;
+	static const struct {
+		size_t offset;
+		char *name;
+	} mandatory_table[] = {
+		PEER_MEM_MANDATORY_FUNC(acquire),
+		PEER_MEM_MANDATORY_FUNC(get_pages),
+		PEER_MEM_MANDATORY_FUNC(put_pages),
+		PEER_MEM_MANDATORY_FUNC(dma_map),
+		PEER_MEM_MANDATORY_FUNC(dma_unmap),
+	};
+	for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) {
+		if (!*(void **)((void *)peer_client +
+				mandatory_table[i].offset)) {
+			pr_err("Peer memory %s is missing mandatory function %s\n",
+			       peer_client->name, mandatory_table[i].name);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+void *
+ib_register_peer_memory_client(const struct peer_memory_client *peer_client,
+			       invalidate_peer_memory *invalidate_callback)
+{
+	struct ib_peer_memory_client *ib_peer_client;
+	int ret;
+	if (ib_memory_peer_check_mandatory(peer_client))
+		return NULL;
+	ib_peer_client = kzalloc(sizeof(*ib_peer_client), GFP_KERNEL);
+	if (!ib_peer_client)
+		return NULL;
+	kobject_init(&ib_peer_client->kobj, &peer_mem_type);
+	refcount_set(&ib_peer_client->usecnt, 1);
+	init_completion(&ib_peer_client->usecnt_zero);
+	ib_peer_client->peer_mem = peer_client;
+	xa_init_flags(&ib_peer_client->umem_xa, XA_FLAGS_ALLOC);
+	/*
+	 * If the peer wants the invalidation_callback then all memory users
+	 * linked to that peer must support invalidation.
+	 */
+	if (invalidate_callback) {
+		*invalidate_callback = ib_invalidate_peer_memory;
+		ib_peer_client->invalidation_required = true;
+	}
+	mutex_lock(&peer_memory_mutex);
+	if (!peers_kobj) {
+		/* Created under /sys/kernel/mm */
+		peers_kobj = kobject_create_and_add("memory_peers", mm_kobj);
+		if (!peers_kobj)
+			goto err_unlock;
+	}
+	ret = kobject_add(&ib_peer_client->kobj, peers_kobj, peer_client->name);
+	if (ret)
+		goto err_parent;
+	ret = sysfs_create_group(&ib_peer_client->kobj,
+				 &peer_mem_attr_group);
+	if (ret)
+		goto err_parent;
+	list_add_tail(&ib_peer_client->core_peer_list, &peer_memory_list);
+	mutex_unlock(&peer_memory_mutex);
+	return ib_peer_client;
+err_parent:
+	if (list_empty(&peer_memory_list)) {
+		kobject_put(peers_kobj);
+		peers_kobj = NULL;
+	}
+err_unlock:
+	mutex_unlock(&peer_memory_mutex);
+	kobject_put(&ib_peer_client->kobj);
+	return NULL;
+}
+EXPORT_SYMBOL(ib_register_peer_memory_client);
+
+void ib_unregister_peer_memory_client(void *reg_handle)
+{
+	struct ib_peer_memory_client *ib_peer_client = reg_handle;
+	mutex_lock(&peer_memory_mutex);
+	list_del(&ib_peer_client->core_peer_list);
+	if (list_empty(&peer_memory_list)) {
+		kobject_put(peers_kobj);
+		peers_kobj = NULL;
+	}
+	mutex_unlock(&peer_memory_mutex);
+	/*
+	 * Wait for all umems to be destroyed before returning. Once
+	 * ib_unregister_peer_memory_client() returns no umems will call any
+	 * peer_mem ops.
+	 */
+	if (refcount_dec_and_test(&ib_peer_client->usecnt))
+		complete(&ib_peer_client->usecnt_zero);
+	wait_for_completion(&ib_peer_client->usecnt_zero);
+	kobject_put(&ib_peer_client->kobj);
+}
+EXPORT_SYMBOL(ib_unregister_peer_memory_client);
+
+static struct ib_peer_memory_client *
+ib_get_peer_client(unsigned long addr, size_t size,
+		   unsigned long peer_mem_flags, void **peer_client_context)
+{
+	struct ib_peer_memory_client *ib_peer_client;
+	int ret = 0;
+	mutex_lock(&peer_memory_mutex);
+	list_for_each_entry(ib_peer_client, &peer_memory_list,
+			    core_peer_list) {
+		if (ib_peer_client->invalidation_required &&
+		    (!(peer_mem_flags & IB_PEER_MEM_INVAL_SUPP)))
+			continue;
+		ret = ib_peer_client->peer_mem->acquire(addr, size, NULL, NULL,
+							peer_client_context);
+		if (ret > 0) {
+			refcount_inc(&ib_peer_client->usecnt);
+			mutex_unlock(&peer_memory_mutex);
+			return ib_peer_client;
+		}
+	}
+	mutex_unlock(&peer_memory_mutex);
+	return NULL;
+}
+
+static void ib_put_peer_client(struct ib_peer_memory_client *ib_peer_client,
+			       void *peer_client_context)
+{
+	if (ib_peer_client->peer_mem->release)
+		ib_peer_client->peer_mem->release(peer_client_context);
+	if (refcount_dec_and_test(&ib_peer_client->usecnt))
+		complete(&ib_peer_client->usecnt_zero);
+}
+
+static void ib_peer_umem_kref_release(struct kref *kref)
+{
+	struct ib_umem_peer *umem_p =
+		container_of(kref, struct ib_umem_peer, kref);
+
+	mutex_destroy(&umem_p->mapping_lock);
+	kfree(umem_p);
+}
+
+static void ib_unmap_peer_client(struct ib_umem_peer *umem_p,
+				 enum ib_umem_mapped_state cur_state,
+				 enum ib_umem_mapped_state to_state)
+{
+	struct ib_peer_memory_client *ib_peer_client = umem_p->ib_peer_client;
+	const struct peer_memory_client *peer_mem = ib_peer_client->peer_mem;
+	struct ib_umem *umem = &umem_p->umem;
+
+	if (cur_state == UMEM_PEER_MAPPED &&
+	    (to_state == UMEM_PEER_UNMAPPED ||
+	     to_state == UMEM_PEER_INVALIDATED)) {
+		if (to_state == UMEM_PEER_UNMAPPED) {
+			peer_mem->dma_unmap(&umem_p->umem.sg_head, umem_p->peer_client_context,
+			    umem_p->umem.ibdev->dma_device);
+			peer_mem->put_pages(&umem_p->umem.sg_head, umem_p->peer_client_context);
+		}
+		memset(&umem->sg_head, 0, sizeof(umem->sg_head));
+		atomic64_inc(&ib_peer_client->stats.num_dealloc_mrs);
+	}
+
+	if ((cur_state == UMEM_PEER_MAPPED && to_state == UMEM_PEER_UNMAPPED) ||
+	    (cur_state == UMEM_PEER_INVALIDATED &&
+	     to_state == UMEM_PEER_UNMAPPED)) {
+		atomic64_add(umem->nmap, &ib_peer_client->stats.num_dereg_pages);
+		atomic64_add(umem->length, &ib_peer_client->stats.num_dereg_bytes);
+	}
+
+	umem_p->mapped_state = to_state;
+}
+
+static bool ib_peer_unmap_on_invalidate(struct ib_umem_peer *umem_p)
+{
+	const struct peer_memory_client *peer_mem =
+		umem_p->ib_peer_client->peer_mem;
+	const struct peer_memory_client_ex *peer_mem_ex;
+
+	if (peer_mem->version[IB_PEER_MEMORY_VER_MAX - 1] == 0)
+		return false;
+	peer_mem_ex = container_of(peer_mem, const struct peer_memory_client_ex,
+				   client);
+	if (peer_mem_ex->ex_size <
+	    offsetofend(struct peer_memory_client_ex, flags))
+		return false;
+	return peer_mem_ex->flags & PEER_MEM_INVALIDATE_UNMAPS;
+}
+
+
+static int ib_invalidate_peer_memory(void *reg_handle, u64 core_context)
+{
+	struct ib_peer_memory_client *ib_peer_client = reg_handle;
+	struct ib_umem_peer *umem_p;
+
+	/*
+	 * The client is not required to fence against invalidation during
+	 * put_pages() as that would deadlock when we call put_pages() here.
+	 * Thus the core_context cannot be a umem pointer as we have no control
+	 * over the lifetime. Since we won't change the kABI for this to add a
+	 * proper kref, an xarray is used.
+	 */
+	xa_lock(&ib_peer_client->umem_xa);
+	ib_peer_client->stats.num_free_callbacks += 1;
+	umem_p = xa_load(&ib_peer_client->umem_xa, core_context);
+	if (!umem_p)
+		goto out_unlock;
+	kref_get(&umem_p->kref);
+	xa_unlock(&ib_peer_client->umem_xa);
+	mutex_lock(&umem_p->mapping_lock);
+	/*
+	 * For flows that require invalidation the invalidation_func should not
+	 * be NULL while the device can be doing DMA. The mapping_lock ensures
+	 * that the device is ready to receive an invalidation before one is
+	 * triggered here.
+	 */
+	if (umem_p->mapped_state == UMEM_PEER_MAPPED &&
+	    umem_p->invalidation_func)
+		umem_p->invalidation_func(&umem_p->umem,
+					  umem_p->invalidation_private);
+	if (ib_peer_unmap_on_invalidate(umem_p))
+		ib_unmap_peer_client(umem_p, umem_p->mapped_state,
+				     UMEM_PEER_INVALIDATED);
+	else
+		ib_unmap_peer_client(umem_p, umem_p->mapped_state,
+				     UMEM_PEER_UNMAPPED);
+	mutex_unlock(&umem_p->mapping_lock);
+	kref_put(&umem_p->kref, ib_peer_umem_kref_release);
+	return 0;
+out_unlock:
+	xa_unlock(&ib_peer_client->umem_xa);
+	return 0;
+}
+
+void ib_umem_activate_invalidation_notifier(struct ib_umem *umem,
+					    umem_invalidate_func_t func,
+					    void *priv)
+{
+	struct ib_umem_peer *umem_p =
+		container_of(umem, struct ib_umem_peer, umem);
+
+	if (WARN_ON(!umem->is_peer))
+		return;
+	if (umem_p->xa_id == PEER_NO_INVALIDATION_ID)
+		return;
+
+	umem_p->invalidation_func = func;
+	umem_p->invalidation_private = priv;
+	/* Pairs with the lock in ib_peer_umem_get() */
+	mutex_unlock(&umem_p->mapping_lock);
+
+	/* At this point func can be called asynchronously */
+}
+EXPORT_SYMBOL(ib_umem_activate_invalidation_notifier);
+
+/*
+ * Caller has blocked DMA and will no longer be able to handle invalidate
+ * callbacks. Callers using invalidation must call this function before calling
+ * ib_peer_umem_release(). ib_umem_activate_invalidation_notifier() is optional
+ * before doing this.
+ */
+void ib_umem_stop_invalidation_notifier(struct ib_umem *umem)
+{
+	struct ib_umem_peer *umem_p =
+		container_of(umem, struct ib_umem_peer, umem);
+	bool unmap_on_invalidate = ib_peer_unmap_on_invalidate(umem_p);
+	enum ib_umem_mapped_state cur_state;
+
+	if (umem_p->invalidation_func) {
+		mutex_lock(&umem_p->mapping_lock);
+		umem_p->invalidation_func = NULL;
+	} else if (umem_p->xa_id != PEER_NO_INVALIDATION_ID) {
+		mutex_lock(&umem_p->mapping_lock);
+	} else {
+		/*
+		 * Haven't called ib_umem_activate_invalidation_notifier() yet,
+		 * still have the lock
+		 */
+	}
+
+	if (!unmap_on_invalidate) {
+		ib_unmap_peer_client(umem_p, umem_p->mapped_state,
+				     UMEM_PEER_UNMAPPED);
+	} else {
+		/* Block ib_invalidate_peer_memory() */
+		cur_state = umem_p->mapped_state;
+		umem_p->mapped_state = UMEM_PEER_UNMAPPED;
+	}
+	mutex_unlock(&umem_p->mapping_lock);
+
+	if (unmap_on_invalidate)
+		ib_unmap_peer_client(umem_p, cur_state, UMEM_PEER_UNMAPPED);
+
+}
+EXPORT_SYMBOL(ib_umem_stop_invalidation_notifier);
+
+struct ib_umem *ib_peer_umem_get(struct ib_umem *old_umem, int old_ret,
+				 unsigned long peer_mem_flags)
+{
+	struct ib_peer_memory_client *ib_peer_client;
+	void *peer_client_context;
+	struct ib_umem_peer *umem_p;
+	int ret;
+	ib_peer_client =
+		ib_get_peer_client(old_umem->address, old_umem->length,
+				   peer_mem_flags, &peer_client_context);
+	if (!ib_peer_client)
+		return ERR_PTR(old_ret);
+	umem_p = kzalloc(sizeof(*umem_p), GFP_KERNEL);
+	if (!umem_p) {
+		ret = -ENOMEM;
+		goto err_client;
+	}
+
+	kref_init(&umem_p->kref);
+	umem_p->umem = *old_umem;
+	memset(&umem_p->umem.sg_head, 0, sizeof(umem_p->umem.sg_head));
+	umem_p->umem.is_peer = 1;
+	umem_p->ib_peer_client = ib_peer_client;
+	umem_p->peer_client_context = peer_client_context;
+	mutex_init(&umem_p->mapping_lock);
+	umem_p->xa_id = PEER_NO_INVALIDATION_ID;
+
+	mutex_lock(&umem_p->mapping_lock);
+	if (ib_peer_client->invalidation_required) {
+		ret = xa_alloc_cyclic(&ib_peer_client->umem_xa, &umem_p->xa_id,
+				      umem_p,
+				      XA_LIMIT(0, PEER_NO_INVALIDATION_ID - 1),
+				      &ib_peer_client->xa_cyclic_next,
+				      GFP_KERNEL);
+		if (ret < 0)
+			goto err_umem;
+	}
+
+	/*
+	 * We always request write permissions to the pages, to force breaking
+	 * of any CoW during the registration of the MR. For read-only MRs we
+	 * use the "force" flag to indicate that CoW breaking is required but
+	 * the registration should not fail if referencing read-only areas.
+	 */
+	ret = ib_peer_client->peer_mem->get_pages(umem_p->umem.address,
+						  umem_p->umem.length, 1,
+						  !umem_p->umem.writable, NULL,
+						  peer_client_context,
+						  umem_p->xa_id);
+	if (ret)
+		goto err_xa;
+
+	umem_p->umem.page_shift =
+		ilog2(ib_peer_client->peer_mem->get_page_size(peer_client_context));
+
+	ret = ib_peer_client->peer_mem->dma_map(&umem_p->umem.sg_head,
+						peer_client_context,
+						umem_p->umem.ibdev->dma_device,
+						0, &umem_p->umem.nmap);
+	if (ret)
+		goto err_pages;
+
+	umem_p->mapped_state = UMEM_PEER_MAPPED;
+	atomic64_add(umem_p->umem.nmap, &ib_peer_client->stats.num_reg_pages);
+	atomic64_add(umem_p->umem.length, &ib_peer_client->stats.num_reg_bytes);
+	atomic64_inc(&ib_peer_client->stats.num_alloc_mrs);
+
+	/*
+	 * If invalidation is allowed then the caller must call
+	 * ib_umem_activate_invalidation_notifier() or ib_peer_umem_release() to
+	 * unlock this mutex. The call to  should be done after the last
+	 * read to sg_head, once the caller is ready for the invalidation
+	 * function to be called.
+	 */
+	if (umem_p->xa_id == PEER_NO_INVALIDATION_ID)
+		mutex_unlock(&umem_p->mapping_lock);
+	/*
+	 * On success the old umem is replaced with the new, larger, allocation
+	 */
+	kfree(old_umem);
+	return &umem_p->umem;
+err_pages:
+	ib_peer_client->peer_mem->put_pages(&umem_p->umem.sg_head,
+					    umem_p->peer_client_context);
+err_xa:
+	if (umem_p->xa_id != PEER_NO_INVALIDATION_ID)
+		xa_erase(&umem_p->ib_peer_client->umem_xa, umem_p->xa_id);
+err_umem:
+	mutex_unlock(&umem_p->mapping_lock);
+	kref_put(&umem_p->kref, ib_peer_umem_kref_release);
+err_client:
+	ib_put_peer_client(ib_peer_client, peer_client_context);
+	return ERR_PTR(ret);
+}
+
+void ib_peer_umem_release(struct ib_umem *umem)
+{
+	struct ib_umem_peer *umem_p =
+		container_of(umem, struct ib_umem_peer, umem);
+	/*
+	 * If ib_umem_activate_invalidation_notifier() is called then
+	 * ib_umem_stop_invalidation_notifier() must be called before release.
+	 */
+	WARN_ON(umem_p->invalidation_func);
+
+	/* For no invalidation cases, make sure it is unmapped */
+	ib_unmap_peer_client(umem_p, umem_p->mapped_state, UMEM_PEER_UNMAPPED);
+
+	if (umem_p->xa_id != PEER_NO_INVALIDATION_ID)
+		xa_erase(&umem_p->ib_peer_client->umem_xa, umem_p->xa_id);
+	ib_put_peer_client(umem_p->ib_peer_client, umem_p->peer_client_context);
+	umem_p->ib_peer_client = NULL;
+
+	/* Must match ib_umem_release() */
+	atomic64_sub(ib_umem_num_pages(umem), &umem->owning_mm->pinned_vm);
+	mmdrop(umem->owning_mm);
+
+	kref_put(&umem_p->kref, ib_peer_umem_kref_release);
+}
+
--- linux-ein-5.4.0.orig/drivers/infiniband/core/rdma_core.c
+++ linux-ein-5.4.0/drivers/infiniband/core/rdma_core.c
@@ -160,9 +160,9 @@
 	uobj->context = NULL;
 
 	/*
-	 * For DESTROY the usecnt is held write locked, the caller is expected
-	 * to put it unlock and put the object when done with it. Only DESTROY
-	 * can remove the IDR handle.
+	 * For DESTROY the usecnt is not changed, the caller is expected to
+	 * manage it via uobj_put_destroy(). Only DESTROY can remove the IDR
+	 * handle.
 	 */
 	if (reason != RDMA_REMOVE_DESTROY)
 		atomic_set(&uobj->usecnt, 0);
@@ -194,7 +194,7 @@
 /*
  * This calls uverbs_destroy_uobject() using the RDMA_REMOVE_DESTROY
  * sequence. It should only be used from command callbacks. On success the
- * caller must pair this with rdma_lookup_put_uobject(LOOKUP_WRITE). This
+ * caller must pair this with uobj_put_destroy(). This
  * version requires the caller to have already obtained an
  * LOOKUP_DESTROY uobject kref.
  */
@@ -205,6 +205,13 @@
 
 	down_read(&ufile->hw_destroy_rwsem);
 
+	/*
+	 * Once the uobject is destroyed by RDMA_REMOVE_DESTROY then it is left
+	 * write locked as the callers put it back with UVERBS_LOOKUP_DESTROY.
+	 * This is because any other concurrent thread can still see the object
+	 * in the xarray due to RCU. Leaving it locked ensures nothing else will
+	 * touch it.
+	 */
 	ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE);
 	if (ret)
 		goto out_unlock;
@@ -223,7 +230,7 @@
 /*
  * uobj_get_destroy destroys the HW object and returns a handle to the uobj
  * with a NULL object pointer. The caller must pair this with
- * uverbs_put_destroy.
+ * uobj_put_destroy().
  */
 struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
 				      u32 id, struct uverbs_attr_bundle *attrs)
@@ -257,8 +264,7 @@
 	uobj = __uobj_get_destroy(obj, id, attrs);
 	if (IS_ERR(uobj))
 		return PTR_ERR(uobj);
-
-	rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
+	uobj_put_destroy(uobj);
 	return 0;
 }
 
@@ -362,7 +368,7 @@
 	 * and the caller is expected to ensure that uverbs_close_fd is never
 	 * done while a call top lookup is possible.
 	 */
-	if (f->f_op != fd_type->fops) {
+	if (f->f_op != fd_type->fops || uobject->ufile != ufile) {
 		fput(f);
 		return ERR_PTR(-EBADF);
 	}
@@ -689,7 +695,6 @@
 			     enum rdma_lookup_mode mode)
 {
 	assert_uverbs_usecnt(uobj, mode);
-	uobj->uapi_object->type_class->lookup_put(uobj, mode);
 	/*
 	 * In order to unlock an object, either decrease its usecnt for
 	 * read access or zero it in case of exclusive access. See
@@ -706,6 +711,7 @@
 		break;
 	}
 
+	uobj->uapi_object->type_class->lookup_put(uobj, mode);
 	/* Pairs with the kref obtained by type->lookup_get */
 	uverbs_uobject_put(uobj);
 }
@@ -817,6 +823,7 @@
 	rdma_restrack_del(&ucontext->res);
 
 	ib_dev->ops.dealloc_ucontext(ucontext);
+	WARN_ON(!xa_empty(&ucontext->mmap_xa));
 	kfree(ucontext);
 
 	ufile->ucontext = NULL;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/restrack.c
+++ linux-ein-5.4.0/drivers/infiniband/core/restrack.c
@@ -234,6 +234,7 @@
 	} else {
 		ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
 				      &rt->next_id, GFP_KERNEL);
+		ret = (ret < 0) ? ret : 0;
 	}
 
 	if (!ret)
--- linux-ein-5.4.0.orig/drivers/infiniband/core/rw.c
+++ linux-ein-5.4.0/drivers/infiniband/core/rw.c
@@ -268,6 +268,23 @@
 	return 1;
 }
 
+static void rdma_rw_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
+			     u32 sg_cnt, enum dma_data_direction dir)
+{
+	if (is_pci_p2pdma_page(sg_page(sg)))
+		pci_p2pdma_unmap_sg(dev->dma_device, sg, sg_cnt, dir);
+	else
+		ib_dma_unmap_sg(dev, sg, sg_cnt, dir);
+}
+
+static int rdma_rw_map_sg(struct ib_device *dev, struct scatterlist *sg,
+			  u32 sg_cnt, enum dma_data_direction dir)
+{
+	if (is_pci_p2pdma_page(sg_page(sg)))
+		return pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
+	return ib_dma_map_sg(dev, sg, sg_cnt, dir);
+}
+
 /**
  * rdma_rw_ctx_init - initialize a RDMA READ/WRITE context
  * @ctx:	context to initialize
@@ -290,11 +307,7 @@
 	struct ib_device *dev = qp->pd->device;
 	int ret;
 
-	if (is_pci_p2pdma_page(sg_page(sg)))
-		ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
-	else
-		ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
-
+	ret = rdma_rw_map_sg(dev, sg, sg_cnt, dir);
 	if (!ret)
 		return -ENOMEM;
 	sg_cnt = ret;
@@ -333,7 +346,7 @@
 	return ret;
 
 out_unmap_sg:
-	ib_dma_unmap_sg(dev, sg, sg_cnt, dir);
+	rdma_rw_unmap_sg(dev, sg, sg_cnt, dir);
 	return ret;
 }
 EXPORT_SYMBOL(rdma_rw_ctx_init);
@@ -583,11 +596,7 @@
 		break;
 	}
 
-	if (is_pci_p2pdma_page(sg_page(sg)))
-		pci_p2pdma_unmap_sg(qp->pd->device->dma_device, sg,
-				    sg_cnt, dir);
-	else
-		ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+	rdma_rw_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
 }
 EXPORT_SYMBOL(rdma_rw_ctx_destroy);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/core/sa_query.c
+++ linux-ein-5.4.0/drivers/infiniband/core/sa_query.c
@@ -760,8 +760,9 @@
 
 	/* Construct the family header first */
 	header = skb_put(skb, NLMSG_ALIGN(sizeof(*header)));
-	memcpy(header->device_name, dev_name(&query->port->agent->device->dev),
-	       LS_DEVICE_NAME_MAX);
+	strscpy_pad(header->device_name,
+		    dev_name(&query->port->agent->device->dev),
+		    LS_DEVICE_NAME_MAX);
 	header->port_num = query->port->port_num;
 
 	if ((comp_mask & IB_SA_PATH_REC_REVERSIBLE) &&
@@ -829,13 +830,20 @@
 	return len;
 }
 
-static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
+static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
 {
 	struct sk_buff *skb = NULL;
 	struct nlmsghdr *nlh;
 	void *data;
 	struct ib_sa_mad *mad;
 	int len;
+	unsigned long flags;
+	unsigned long delay;
+	gfp_t gfp_flag;
+	int ret;
+
+	INIT_LIST_HEAD(&query->list);
+	query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq);
 
 	mad = query->mad_buf->mad;
 	len = ib_nl_get_path_rec_attrs_len(mad->sa_hdr.comp_mask);
@@ -860,36 +868,25 @@
 	/* Repair the nlmsg header length */
 	nlmsg_end(skb, nlh);
 
-	return rdma_nl_multicast(&init_net, skb, RDMA_NL_GROUP_LS, gfp_mask);
-}
+	gfp_flag = ((gfp_mask & GFP_ATOMIC) == GFP_ATOMIC) ? GFP_ATOMIC :
+		GFP_NOWAIT;
 
-static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
-{
-	unsigned long flags;
-	unsigned long delay;
-	int ret;
+	spin_lock_irqsave(&ib_nl_request_lock, flags);
+	ret = rdma_nl_multicast(&init_net, skb, RDMA_NL_GROUP_LS, gfp_flag);
 
-	INIT_LIST_HEAD(&query->list);
-	query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq);
+	if (ret)
+		goto out;
 
-	/* Put the request on the list first.*/
-	spin_lock_irqsave(&ib_nl_request_lock, flags);
+	/* Put the request on the list.*/
 	delay = msecs_to_jiffies(sa_local_svc_timeout_ms);
 	query->timeout = delay + jiffies;
 	list_add_tail(&query->list, &ib_nl_request_list);
 	/* Start the timeout if this is the only request */
 	if (ib_nl_request_list.next == &query->list)
 		queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay);
-	spin_unlock_irqrestore(&ib_nl_request_lock, flags);
 
-	ret = ib_nl_send_msg(query, gfp_mask);
-	if (ret) {
-		ret = -EIO;
-		/* Remove the request */
-		spin_lock_irqsave(&ib_nl_request_lock, flags);
-		list_del(&query->list);
-		spin_unlock_irqrestore(&ib_nl_request_lock, flags);
-	}
+out:
+	spin_unlock_irqrestore(&ib_nl_request_lock, flags);
 
 	return ret;
 }
@@ -1068,7 +1065,7 @@
 	}
 
 settimeout_out:
-	return skb->len;
+	return 0;
 }
 
 static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh)
@@ -1139,7 +1136,7 @@
 	}
 
 resp_out:
-	return skb->len;
+	return 0;
 }
 
 static void free_sm_ah(struct kref *kref)
--- linux-ein-5.4.0.orig/drivers/infiniband/core/security.c
+++ linux-ein-5.4.0/drivers/infiniband/core/security.c
@@ -339,27 +339,20 @@
 	if (!new_pps)
 		return NULL;
 
-	if (qp_attr_mask & (IB_QP_PKEY_INDEX | IB_QP_PORT)) {
-		if (!qp_pps) {
-			new_pps->main.port_num = qp_attr->port_num;
-			new_pps->main.pkey_index = qp_attr->pkey_index;
-		} else {
-			new_pps->main.port_num = (qp_attr_mask & IB_QP_PORT) ?
-						  qp_attr->port_num :
-						  qp_pps->main.port_num;
-
-			new_pps->main.pkey_index =
-					(qp_attr_mask & IB_QP_PKEY_INDEX) ?
-					 qp_attr->pkey_index :
-					 qp_pps->main.pkey_index;
-		}
-		new_pps->main.state = IB_PORT_PKEY_VALID;
-	} else if (qp_pps) {
+	if (qp_attr_mask & IB_QP_PORT)
+		new_pps->main.port_num = qp_attr->port_num;
+	else if (qp_pps)
 		new_pps->main.port_num = qp_pps->main.port_num;
+
+	if (qp_attr_mask & IB_QP_PKEY_INDEX)
+		new_pps->main.pkey_index = qp_attr->pkey_index;
+	else if (qp_pps)
 		new_pps->main.pkey_index = qp_pps->main.pkey_index;
-		if (qp_pps->main.state != IB_PORT_PKEY_NOT_VALID)
-			new_pps->main.state = IB_PORT_PKEY_VALID;
-	}
+
+	if (((qp_attr_mask & IB_QP_PKEY_INDEX) &&
+	     (qp_attr_mask & IB_QP_PORT)) ||
+	    (qp_pps && qp_pps->main.state != IB_PORT_PKEY_NOT_VALID))
+		new_pps->main.state = IB_PORT_PKEY_VALID;
 
 	if (qp_attr_mask & IB_QP_ALT_PATH) {
 		new_pps->alt.port_num = qp_attr->alt_port_num;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/sysfs.c
+++ linux-ein-5.4.0/drivers/infiniband/core/sysfs.c
@@ -1060,8 +1060,7 @@
 				   coredev->ports_kobj,
 				   "%d", port_num);
 	if (ret) {
-		kfree(p);
-		return ret;
+		goto err_put;
 	}
 
 	p->gid_attr_group = kzalloc(sizeof(*p->gid_attr_group), GFP_KERNEL);
@@ -1074,8 +1073,7 @@
 	ret = kobject_init_and_add(&p->gid_attr_group->kobj, &gid_attr_type,
 				   &p->kobj, "gid_attrs");
 	if (ret) {
-		kfree(p->gid_attr_group);
-		goto err_put;
+		goto err_put_gid_attrs;
 	}
 
 	if (device->ops.process_mad && is_full_dev) {
@@ -1406,8 +1404,10 @@
 
 		ret = kobject_init_and_add(kobj, ktype, &port->kobj, "%s",
 					   name);
-		if (ret)
+		if (ret) {
+			kobject_put(kobj);
 			return ret;
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/ucma.c
+++ linux-ein-5.4.0/drivers/infiniband/core/ucma.c
@@ -91,6 +91,7 @@
 
 	struct ucma_file	*file;
 	struct rdma_cm_id	*cm_id;
+	struct mutex		mutex;
 	u64			uid;
 
 	struct list_head	list;
@@ -216,6 +217,7 @@
 	init_completion(&ctx->comp);
 	INIT_LIST_HEAD(&ctx->mc_list);
 	ctx->file = file;
+	mutex_init(&ctx->mutex);
 
 	if (xa_alloc(&ctx_table, &ctx->id, ctx, xa_limit_32b, GFP_KERNEL))
 		goto error;
@@ -543,6 +545,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;
@@ -550,6 +553,7 @@
 		list_del(&uevent->list);
 		kfree(uevent);
 	}
+	rdma_unlock_handler(mc->ctx->cm_id);
 }
 
 /*
@@ -579,6 +583,7 @@
 			list_move_tail(&uevent->list, &list);
 	}
 	list_del(&ctx->list);
+	events_reported = ctx->events_reported;
 	mutex_unlock(&ctx->file->mut);
 
 	list_for_each_entry_safe(uevent, tmp, &list, list) {
@@ -588,7 +593,7 @@
 		kfree(uevent);
 	}
 
-	events_reported = ctx->events_reported;
+	mutex_destroy(&ctx->mutex);
 	kfree(ctx);
 	return events_reported;
 }
@@ -658,7 +663,10 @@
 	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;
 }
@@ -681,7 +689,9 @@
 	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;
 }
@@ -705,8 +715,10 @@
 	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);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -731,8 +743,10 @@
 	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);
+	mutex_unlock(&ctx->mutex);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -752,7 +766,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;
 }
@@ -841,6 +857,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 ?
@@ -864,6 +881,7 @@
 		ucma_copy_iw_route(&resp, &ctx->cm_id->route);
 
 out:
+	mutex_unlock(&ctx->mutex);
 	if (copy_to_user(u64_to_user_ptr(cmd.response),
 			 &resp, sizeof(resp)))
 		ret = -EFAULT;
@@ -1014,6 +1032,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);
@@ -1028,6 +1047,7 @@
 		ret = -ENOSYS;
 		break;
 	}
+	mutex_unlock(&ctx->mutex);
 
 	ucma_put_ctx(ctx);
 	return ret;
@@ -1068,7 +1088,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;
 }
@@ -1089,7 +1111,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;
 }
@@ -1111,14 +1135,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, NULL);
-		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, NULL);
-
+		rdma_unlock_handler(ctx->cm_id);
+		mutex_unlock(&ctx->mutex);
+	}
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1137,7 +1169,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;
 }
@@ -1156,7 +1190,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;
 }
@@ -1187,7 +1223,9 @@
 	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;
 
@@ -1273,9 +1311,13 @@
 		struct sa_path_rec opa;
 
 		sa_convert_path_ib_to_opa(&opa, &sa_path);
+		mutex_lock(&ctx->mutex);
 		ret = rdma_set_ib_path(ctx->cm_id, &opa);
+		mutex_unlock(&ctx->mutex);
 	} else {
+		mutex_lock(&ctx->mutex);
 		ret = rdma_set_ib_path(ctx->cm_id, &sa_path);
+		mutex_unlock(&ctx->mutex);
 	}
 	if (ret)
 		return ret;
@@ -1308,7 +1350,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);
@@ -1368,8 +1412,10 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	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;
@@ -1412,8 +1458,10 @@
 	mc->join_state = join_state;
 	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,
 				  join_state, mc);
+	mutex_unlock(&ctx->mutex);
 	if (ret)
 		goto err2;
 
@@ -1431,7 +1479,9 @@
 	return 0;
 
 err3:
+	mutex_lock(&ctx->mutex);
 	rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr);
+	mutex_unlock(&ctx->mutex);
 	ucma_cleanup_mc_events(mc);
 err2:
 	xa_erase(&multicast_table, mc->id);
@@ -1500,7 +1550,7 @@
 	mc = xa_load(&multicast_table, 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);
@@ -1513,7 +1563,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);
@@ -1530,45 +1583,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;
@@ -1584,40 +1607,53 @@
 		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);
 	xa_lock(&ctx_table);
-
-	list_move_tail(&ctx->list, &new_file->ctx_list);
-	ucma_move_events(ctx, new_file);
+	if (_ucma_find_context(cmd.id, cur_file) != ctx) {
+		xa_unlock(&ctx_table);
+		ret = -ENOENT;
+		goto err_unlock;
+	}
 	ctx->file = new_file;
+	xa_unlock(&ctx_table);
+
+	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);
 
-	xa_unlock(&ctx_table);
-	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(u64_to_user_ptr(cmd.response),
 			 &resp, sizeof(resp)))
 		ret = -EFAULT;
 
+err_unlock:
+	rdma_unlock_handler(ctx->cm_id);
 	ucma_put_ctx(ctx);
 file_put:
 	fdput(f);
--- linux-ein-5.4.0.orig/drivers/infiniband/core/umem.c
+++ linux-ein-5.4.0/drivers/infiniband/core/umem.c
@@ -42,6 +42,7 @@
 #include <rdma/ib_umem_odp.h>
 
 #include "uverbs.h"
+#include "ib_peer_mem.h"
 
 static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
 {
@@ -151,13 +152,24 @@
 	dma_addr_t mask;
 	int i;
 
+	/* rdma_for_each_block() has a bug if the page size is smaller than the
+	 * page size used to build the umem. For now prevent smaller page sizes
+	 * from being returned.
+	 */
+	pgsz_bitmap &= GENMASK(BITS_PER_LONG - 1, PAGE_SHIFT);
+
 	/* At minimum, drivers must support PAGE_SIZE or smaller */
 	if (WARN_ON(!(pgsz_bitmap & GENMASK(PAGE_SHIFT, 0))))
 		return 0;
 
 	va = virt;
-	/* max page size not to exceed MR length */
-	mask = roundup_pow_of_two(umem->length);
+	/* The best result is the smallest page size that results in the minimum
+	 * number of required pages. Compute the largest page size that could
+	 * work based on VA address bits that don't change.
+	 */
+	mask = pgsz_bitmap &
+	       GENMASK(BITS_PER_LONG - 1,
+		       bits_per((umem->length - 1 + virt) ^ virt));
 	/* offset into first SGL */
 	pgoff = umem->address & ~PAGE_MASK;
 
@@ -166,10 +178,13 @@
 		 * for any address.
 		 */
 		mask |= (sg_dma_address(sg) + pgoff) ^ va;
-		if (i && i != (umem->nmap - 1))
-			/* restrict by length as well for interior SGEs */
-			mask |= sg_dma_len(sg);
 		va += sg_dma_len(sg) - pgoff;
+		/* Except for the last entry, the ending iova alignment sets
+		 * the maximum possible page size as the low bits of the iova
+		 * must be zero when starting the next chunk.
+		 */
+		if (i != (umem->nmap - 1))
+			mask |= va;
 		pgoff = 0;
 	}
 	best_pg_bit = rdma_find_pg_bit(mask, pgsz_bitmap);
@@ -179,18 +194,18 @@
 EXPORT_SYMBOL(ib_umem_find_best_pgsz);
 
 /**
- * ib_umem_get - Pin and DMA map userspace memory.
+ * __ib_umem_get - Pin and DMA map userspace memory.
  *
- * @udata: userspace context to pin memory for
+ * @device: IB device to connect UMEM
  * @addr: userspace virtual address to start at
  * @size: length of region to pin
  * @access: IB_ACCESS_xxx flags for memory being pinned
- * @dmasync: flush in-flight DMA when the memory region is written
+ * @peer_mem_flags: IB_PEER_MEM_xxx flags for memory being used
  */
-struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
-			    size_t size, int access, int dmasync)
+struct ib_umem *__ib_umem_get(struct ib_device *device,
+			      unsigned long addr, size_t size, int access,
+			      unsigned long peer_mem_flags)
 {
-	struct ib_ucontext *context;
 	struct ib_umem *umem;
 	struct page **page_list;
 	unsigned long lock_limit;
@@ -199,21 +214,9 @@
 	struct mm_struct *mm;
 	unsigned long npages;
 	int ret;
-	unsigned long dma_attrs = 0;
 	struct scatterlist *sg;
 	unsigned int gup_flags = FOLL_WRITE;
 
-	if (!udata)
-		return ERR_PTR(-EIO);
-
-	context = container_of(udata, struct uverbs_attr_bundle, driver_udata)
-			  ->context;
-	if (!context)
-		return ERR_PTR(-EIO);
-
-	if (dmasync)
-		dma_attrs |= DMA_ATTR_WRITE_BARRIER;
-
 	/*
 	 * If the combination of the addr and size requested for this memory
 	 * region causes an integer overflow, return error.
@@ -231,7 +234,7 @@
 	umem = kzalloc(sizeof(*umem), GFP_KERNEL);
 	if (!umem)
 		return ERR_PTR(-ENOMEM);
-	umem->ibdev = context->device;
+	umem->ibdev      = device;
 	umem->length     = size;
 	umem->address    = addr;
 	umem->writable   = ib_access_writable(access);
@@ -286,7 +289,7 @@
 		npages   -= ret;
 
 		sg = ib_umem_add_sg_table(sg, page_list, ret,
-			dma_get_max_seg_size(context->device->dma_device),
+			dma_get_max_seg_size(device->dma_device),
 			&umem->sg_nents);
 
 		up_read(&mm->mmap_sem);
@@ -294,11 +297,10 @@
 
 	sg_mark_end(sg);
 
-	umem->nmap = ib_dma_map_sg_attrs(context->device,
-				  umem->sg_head.sgl,
-				  umem->sg_nents,
-				  DMA_BIDIRECTIONAL,
-				  dma_attrs);
+	umem->nmap = ib_dma_map_sg(device,
+				   umem->sg_head.sgl,
+				   umem->sg_nents,
+				   DMA_BIDIRECTIONAL);
 
 	if (!umem->nmap) {
 		ret = -ENOMEM;
@@ -309,7 +311,25 @@
 	goto out;
 
 umem_release:
-	__ib_umem_release(context->device, umem, 0);
+	__ib_umem_release(device, umem, 0);
+	/*
+	 * If the address belongs to peer memory client, then the first
+	 * call to get_user_pages will fail. In this case, try to get
+	 * these pages from the peers.
+	 */
+	//FIXME: this placement is horrible
+	if (ret < 0 && peer_mem_flags & IB_PEER_MEM_ALLOW) {
+		struct ib_umem *new_umem;
+
+		new_umem = ib_peer_umem_get(umem, ret, peer_mem_flags);
+		if (IS_ERR(new_umem)) {
+			ret = PTR_ERR(new_umem);
+			goto vma;
+		}
+		umem = new_umem;
+		ret = 0;
+		goto out;
+	}
 vma:
 	atomic64_sub(ib_umem_num_pages(umem), &mm->pinned_vm);
 out:
@@ -321,8 +341,23 @@
 	}
 	return ret ? ERR_PTR(ret) : umem;
 }
+
+struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
+			    size_t size, int access)
+{
+	return __ib_umem_get(device, addr, size, access, 0);
+}
 EXPORT_SYMBOL(ib_umem_get);
 
+struct ib_umem *ib_umem_get_peer(struct ib_device *device, unsigned long addr,
+				 size_t size, int access,
+				 unsigned long peer_mem_flags)
+{
+	return __ib_umem_get(device, addr, size, access,
+			     IB_PEER_MEM_ALLOW | peer_mem_flags);
+}
+EXPORT_SYMBOL(ib_umem_get_peer);
+
 /**
  * ib_umem_release - release memory pinned with ib_umem_get
  * @umem: umem struct to release
@@ -334,6 +369,8 @@
 	if (umem->is_odp)
 		return ib_umem_odp_release(to_ib_umem_odp(umem));
 
+	if (umem->is_peer)
+		return ib_peer_umem_release(umem);
 	__ib_umem_release(umem->ibdev, umem, 1);
 
 	atomic64_sub(ib_umem_num_pages(umem), &umem->owning_mm->pinned_vm);
--- linux-ein-5.4.0.orig/drivers/infiniband/core/umem_odp.c
+++ linux-ein-5.4.0/drivers/infiniband/core/umem_odp.c
@@ -287,15 +287,12 @@
  * They exist only to hold the per_mm reference to help the driver create
  * children umems.
  *
- * @udata: udata from the syscall being used to create the umem
+ * @device: IB device to create UMEM
  * @access: ib_reg_mr access flags
  */
-struct ib_umem_odp *ib_umem_odp_alloc_implicit(struct ib_udata *udata,
+struct ib_umem_odp *ib_umem_odp_alloc_implicit(struct ib_device *device,
 					       int access)
 {
-	struct ib_ucontext *context =
-		container_of(udata, struct uverbs_attr_bundle, driver_udata)
-			->context;
 	struct ib_umem *umem;
 	struct ib_umem_odp *umem_odp;
 	int ret;
@@ -303,16 +300,14 @@
 	if (access & IB_ACCESS_HUGETLB)
 		return ERR_PTR(-EINVAL);
 
-	if (!context)
-		return ERR_PTR(-EIO);
-	if (WARN_ON_ONCE(!context->device->ops.invalidate_range))
+	if (WARN_ON_ONCE(!device->ops.invalidate_range))
 		return ERR_PTR(-EINVAL);
 
 	umem_odp = kzalloc(sizeof(*umem_odp), GFP_KERNEL);
 	if (!umem_odp)
 		return ERR_PTR(-ENOMEM);
 	umem = &umem_odp->umem;
-	umem->ibdev = context->device;
+	umem->ibdev = device;
 	umem->writable = ib_access_writable(access);
 	umem->owning_mm = current->mm;
 	umem_odp->is_implicit_odp = 1;
@@ -361,19 +356,33 @@
 	umem->owning_mm  = root->umem.owning_mm;
 	odp_data->page_shift = PAGE_SHIFT;
 
-	ret = ib_init_umem_odp(odp_data);
-	if (ret) {
-		kfree(odp_data);
-		return ERR_PTR(ret);
+	/*
+	 * A mmget must be held when registering a notifier, the owming_mm only
+	 * has a mm_grab at this point.
+	 */
+	if (!mmget_not_zero(umem->owning_mm)) {
+		ret = -EFAULT;
+		goto out_free;
 	}
+
+	ret = ib_init_umem_odp(odp_data);
+	if (ret)
+		goto out_mmput;
+	mmput(umem->owning_mm);
 	return odp_data;
+
+out_mmput:
+	mmput(umem->owning_mm);
+out_free:
+	kfree(odp_data);
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(ib_umem_odp_alloc_child);
 
 /**
  * ib_umem_odp_get - Create a umem_odp for a userspace va
  *
- * @udata: userspace context to pin memory for
+ * @device: IB device struct to get UMEM
  * @addr: userspace virtual address to start at
  * @size: length of region to pin
  * @access: IB_ACCESS_xxx flags for memory being pinned
@@ -382,31 +391,23 @@
  * pinning, instead, stores the mm for future page fault handling in
  * conjunction with MMU notifiers.
  */
-struct ib_umem_odp *ib_umem_odp_get(struct ib_udata *udata, unsigned long addr,
-				    size_t size, int access)
+struct ib_umem_odp *ib_umem_odp_get(struct ib_device *device,
+				    unsigned long addr, size_t size,
+				    int access)
 {
 	struct ib_umem_odp *umem_odp;
-	struct ib_ucontext *context;
 	struct mm_struct *mm;
 	int ret;
 
-	if (!udata)
-		return ERR_PTR(-EIO);
-
-	context = container_of(udata, struct uverbs_attr_bundle, driver_udata)
-			  ->context;
-	if (!context)
-		return ERR_PTR(-EIO);
-
 	if (WARN_ON_ONCE(!(access & IB_ACCESS_ON_DEMAND)) ||
-	    WARN_ON_ONCE(!context->device->ops.invalidate_range))
+	    WARN_ON_ONCE(!device->ops.invalidate_range))
 		return ERR_PTR(-EINVAL);
 
 	umem_odp = kzalloc(sizeof(struct ib_umem_odp), GFP_KERNEL);
 	if (!umem_odp)
 		return ERR_PTR(-ENOMEM);
 
-	umem_odp->umem.ibdev = context->device;
+	umem_odp->umem.ibdev = device;
 	umem_odp->umem.length = size;
 	umem_odp->umem.address = addr;
 	umem_odp->umem.writable = ib_access_writable(access);
@@ -632,7 +633,7 @@
 
 	while (bcnt > 0) {
 		const size_t gup_num_pages = min_t(size_t,
-				(bcnt + BIT(page_shift) - 1) >> page_shift,
+				ALIGN(bcnt, PAGE_SIZE) / PAGE_SIZE,
 				PAGE_SIZE / sizeof(struct page *));
 
 		down_read(&owning_mm->mmap_sem);
--- linux-ein-5.4.0.orig/drivers/infiniband/core/user_mad.c
+++ linux-ein-5.4.0/drivers/infiniband/core/user_mad.c
@@ -131,6 +131,11 @@
 	struct ib_user_mad mad;
 };
 
+struct ib_rmpp_mad_hdr {
+	struct ib_mad_hdr	mad_hdr;
+	struct ib_rmpp_hdr      rmpp_hdr;
+} __packed;
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/ib_umad.h>
 
@@ -379,6 +384,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);
 
@@ -392,6 +402,11 @@
 		mutex_lock(&file->mutex);
 	}
 
+	if (file->agents_dead) {
+		mutex_unlock(&file->mutex);
+		return -EIO;
+	}
+
 	packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
 	list_del(&packet->list);
 
@@ -484,11 +499,11 @@
 			     size_t count, loff_t *pos)
 {
 	struct ib_umad_file *file = filp->private_data;
+	struct ib_rmpp_mad_hdr *rmpp_mad_hdr;
 	struct ib_umad_packet *packet;
 	struct ib_mad_agent *agent;
 	struct rdma_ah_attr ah_attr;
 	struct ib_ah *ah;
-	struct ib_rmpp_mad *rmpp_mad;
 	__be64 *tid;
 	int ret, data_len, hdr_len, copy_offset, rmpp_active;
 	u8 base_version;
@@ -496,7 +511,7 @@
 	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
 		return -EINVAL;
 
-	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
+	packet = kzalloc(sizeof(*packet) + IB_MGMT_RMPP_HDR, GFP_KERNEL);
 	if (!packet)
 		return -ENOMEM;
 
@@ -524,7 +539,7 @@
 
 	agent = __get_agent(file, packet->mad.hdr.id);
 	if (!agent) {
-		ret = -EINVAL;
+		ret = -EIO;
 		goto err_up;
 	}
 
@@ -550,13 +565,13 @@
 		goto err_up;
 	}
 
-	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
-	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
+	rmpp_mad_hdr = (struct ib_rmpp_mad_hdr *)packet->mad.data;
+	hdr_len = ib_get_mad_data_offset(rmpp_mad_hdr->mad_hdr.mgmt_class);
 
-	if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
+	if (ib_is_mad_class_rmpp(rmpp_mad_hdr->mad_hdr.mgmt_class)
 	    && ib_mad_kernel_rmpp_agent(agent)) {
 		copy_offset = IB_MGMT_RMPP_HDR;
-		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+		rmpp_active = ib_get_rmpp_flags(&rmpp_mad_hdr->rmpp_hdr) &
 						IB_MGMT_RMPP_FLAG_ACTIVE;
 	} else {
 		copy_offset = IB_MGMT_MAD_HDR;
@@ -605,12 +620,12 @@
 		tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
 		*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
 				   (be64_to_cpup(tid) & 0xffffffff));
-		rmpp_mad->mad_hdr.tid = *tid;
+		rmpp_mad_hdr->mad_hdr.tid = *tid;
 	}
 
 	if (!ib_mad_kernel_rmpp_agent(agent)
-	   && ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
-	   && (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) {
+	    && ib_is_mad_class_rmpp(rmpp_mad_hdr->mad_hdr.mgmt_class)
+	    && (ib_get_rmpp_flags(&rmpp_mad_hdr->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) {
 		spin_lock_irq(&file->send_lock);
 		list_add_tail(&packet->list, &file->send_list);
 		spin_unlock_irq(&file->send_lock);
@@ -653,10 +668,14 @@
 	/* we will always be able to post a MAD send */
 	__poll_t mask = EPOLLOUT | EPOLLWRNORM;
 
+	mutex_lock(&file->mutex);
 	poll_wait(filp, &file->recv_wait, wait);
 
 	if (!list_empty(&file->recv_list))
 		mask |= EPOLLIN | EPOLLRDNORM;
+	if (file->agents_dead)
+		mask = EPOLLERR;
+	mutex_unlock(&file->mutex);
 
 	return mask;
 }
@@ -1129,17 +1148,30 @@
 	.llseek	 = no_llseek,
 };
 
+static struct ib_umad_port *get_port(struct ib_device *ibdev,
+				     struct ib_umad_device *umad_dev,
+				     unsigned int port)
+{
+	if (!umad_dev)
+		return ERR_PTR(-EOPNOTSUPP);
+	if (!rdma_is_port_valid(ibdev, port))
+		return ERR_PTR(-EINVAL);
+	if (!rdma_cap_ib_mad(ibdev, port))
+		return ERR_PTR(-EOPNOTSUPP);
+
+	return &umad_dev->ports[port - rdma_start_port(ibdev)];
+}
+
 static int ib_umad_get_nl_info(struct ib_device *ibdev, void *client_data,
 			       struct ib_client_nl_info *res)
 {
-	struct ib_umad_device *umad_dev = client_data;
+	struct ib_umad_port *port = get_port(ibdev, client_data, res->port);
 
-	if (!rdma_is_port_valid(ibdev, res->port))
-		return -EINVAL;
+	if (IS_ERR(port))
+		return PTR_ERR(port);
 
 	res->abi = IB_USER_MAD_ABI_VERSION;
-	res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].dev;
-
+	res->cdev = &port->dev;
 	return 0;
 }
 
@@ -1154,15 +1186,13 @@
 static int ib_issm_get_nl_info(struct ib_device *ibdev, void *client_data,
 			       struct ib_client_nl_info *res)
 {
-	struct ib_umad_device *umad_dev =
-		ib_get_client_data(ibdev, &umad_client);
+	struct ib_umad_port *port = get_port(ibdev, client_data, res->port);
 
-	if (!rdma_is_port_valid(ibdev, res->port))
-		return -EINVAL;
+	if (IS_ERR(port))
+		return PTR_ERR(port);
 
 	res->abi = IB_USER_MAD_ABI_VERSION;
-	res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].sm_dev;
-
+	res->cdev = &port->sm_dev;
 	return 0;
 }
 
@@ -1312,6 +1342,9 @@
 	struct ib_umad_file *file;
 	int id;
 
+	cdev_device_del(&port->sm_cdev, &port->sm_dev);
+	cdev_device_del(&port->cdev, &port->dev);
+
 	mutex_lock(&port->file_mutex);
 
 	/* Mark ib_dev NULL and block ioctl or other file ops to progress
@@ -1322,6 +1355,7 @@
 	list_for_each_entry(file, &port->file_list, port_list) {
 		mutex_lock(&file->mutex);
 		file->agents_dead = 1;
+		wake_up_interruptible(&file->recv_wait);
 		mutex_unlock(&file->mutex);
 
 		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
@@ -1331,8 +1365,6 @@
 
 	mutex_unlock(&port->file_mutex);
 
-	cdev_device_del(&port->sm_cdev, &port->sm_dev);
-	cdev_device_del(&port->cdev, &port->dev);
 	ida_free(&umad_ida, port->dev_num);
 
 	/* balances device_initialize() */
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_cmd.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_cmd.c
@@ -252,6 +252,8 @@
 	ucontext->closing = false;
 	ucontext->cleanup_retryable = false;
 
+	xa_init_flags(&ucontext->mmap_xa, XA_FLAGS_ALLOC);
+
 	ret = get_unused_fd_flags(O_CLOEXEC);
 	if (ret < 0)
 		goto err_free;
@@ -757,6 +759,7 @@
 	mr->uobject = uobj;
 	atomic_inc(&pd->usecnt);
 	mr->res.type = RDMA_RESTRACK_MR;
+	mr->iova = cmd.hca_va;
 	rdma_restrack_uadd(&mr->res);
 
 	uobj->object = mr;
@@ -847,6 +850,9 @@
 		atomic_dec(&old_pd->usecnt);
 	}
 
+	if (cmd.flags & IB_MR_REREG_TRANS)
+		mr->iova = cmd.hca_va;
+
 	memset(&resp, 0, sizeof(resp));
 	resp.lkey      = mr->lkey;
 	resp.rkey      = mr->rkey;
@@ -1431,17 +1437,7 @@
 		if (ret)
 			goto err_cb;
 
-		qp->pd		  = pd;
-		qp->send_cq	  = attr.send_cq;
-		qp->recv_cq	  = attr.recv_cq;
-		qp->srq		  = attr.srq;
-		qp->rwq_ind_tbl	  = ind_tbl;
-		qp->event_handler = attr.event_handler;
-		qp->qp_context	  = attr.qp_context;
-		qp->qp_type	  = attr.qp_type;
-		atomic_set(&qp->usecnt, 0);
 		atomic_inc(&pd->usecnt);
-		qp->port = 0;
 		if (attr.send_cq)
 			atomic_inc(&attr.send_cq->usecnt);
 		if (attr.recv_cq)
@@ -1563,7 +1559,7 @@
 	struct ib_uverbs_create_qp_resp resp;
 	struct ib_uqp_object           *obj;
 	struct ib_xrcd		       *xrcd;
-	struct ib_uobject	       *uninitialized_var(xrcd_uobj);
+	struct ib_uobject	       *xrcd_uobj;
 	struct ib_qp                   *qp;
 	struct ib_qp_open_attr          attr;
 	int ret;
@@ -1869,8 +1865,13 @@
 		attr->path_mtu = cmd->base.path_mtu;
 	if (cmd->base.attr_mask & IB_QP_PATH_MIG_STATE)
 		attr->path_mig_state = cmd->base.path_mig_state;
-	if (cmd->base.attr_mask & IB_QP_QKEY)
+	if (cmd->base.attr_mask & IB_QP_QKEY) {
+		if (cmd->base.qkey & IB_QP_SET_QKEY && !capable(CAP_NET_RAW)) {
+			ret = -EPERM;
+			goto release_qp;
+		}
 		attr->qkey = cmd->base.qkey;
+	}
 	if (cmd->base.attr_mask & IB_QP_RQ_PSN)
 		attr->rq_psn = cmd->base.rq_psn;
 	if (cmd->base.attr_mask & IB_QP_SQ_PSN)
@@ -1958,7 +1959,7 @@
 	 * Last bit is reserved for extending the attr_mask by
 	 * using another field.
 	 */
-	BUILD_BUG_ON(IB_USER_LAST_QP_ATTR_MASK == (1 << 31));
+	BUILD_BUG_ON(IB_USER_LAST_QP_ATTR_MASK == (1ULL << 31));
 
 	if (cmd.base.attr_mask &
 	    ~((IB_USER_LAST_QP_ATTR_MASK << 1) - 1))
@@ -2718,12 +2719,6 @@
 	return 0;
 }
 
-static size_t kern_spec_filter_sz(const struct ib_uverbs_flow_spec_hdr *spec)
-{
-	/* Returns user space filter size, includes padding */
-	return (spec->size - sizeof(struct ib_uverbs_flow_spec_hdr)) / 2;
-}
-
 static ssize_t spec_filter_size(const void *kern_spec_filter, u16 kern_filter_size,
 				u16 ib_real_filter_sz)
 {
@@ -2867,11 +2862,16 @@
 static int kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec *kern_spec,
 				       union ib_flow_spec *ib_spec)
 {
-	ssize_t kern_filter_sz;
+	size_t kern_filter_sz;
 	void *kern_spec_mask;
 	void *kern_spec_val;
 
-	kern_filter_sz = kern_spec_filter_sz(&kern_spec->hdr);
+	if (check_sub_overflow((size_t)kern_spec->hdr.size,
+			       sizeof(struct ib_uverbs_flow_spec_hdr),
+			       &kern_filter_sz))
+		return -EINVAL;
+
+	kern_filter_sz /= 2;
 
 	kern_spec_val = (void *)kern_spec +
 		sizeof(struct ib_uverbs_flow_spec_hdr);
@@ -3038,12 +3038,29 @@
 	if (!wq)
 		return -EINVAL;
 
-	wq_attr.curr_wq_state = cmd.curr_wq_state;
-	wq_attr.wq_state = cmd.wq_state;
 	if (cmd.attr_mask & IB_WQ_FLAGS) {
 		wq_attr.flags = cmd.flags;
 		wq_attr.flags_mask = cmd.flags_mask;
 	}
+
+	if (cmd.attr_mask & IB_WQ_CUR_STATE) {
+		if (cmd.curr_wq_state > IB_WQS_ERR)
+			return -EINVAL;
+
+		wq_attr.curr_wq_state = cmd.curr_wq_state;
+	} else {
+		wq_attr.curr_wq_state = wq->state;
+	}
+
+	if (cmd.attr_mask & IB_WQ_STATE) {
+		if (cmd.wq_state > IB_WQS_ERR)
+			return -EINVAL;
+
+		wq_attr.wq_state = cmd.wq_state;
+	} else {
+		wq_attr.wq_state = wq_attr.curr_wq_state;
+	}
+
 	ret = wq->device->ops.modify_wq(wq, &wq_attr, cmd.attr_mask,
 					&attrs->driver_udata);
 	uobj_put_obj_read(wq);
@@ -3368,7 +3385,7 @@
 	struct ib_usrq_object           *obj;
 	struct ib_pd                    *pd;
 	struct ib_srq                   *srq;
-	struct ib_uobject               *uninitialized_var(xrcd_uobj);
+	struct ib_uobject               *xrcd_uobj;
 	struct ib_srq_init_attr          attr;
 	int ret;
 	struct ib_device *ib_dev;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_main.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_main.c
@@ -220,7 +220,6 @@
 }
 
 static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
-				    struct ib_uverbs_file *uverbs_file,
 				    struct file *filp, char __user *buf,
 				    size_t count, loff_t *pos,
 				    size_t eventsz)
@@ -231,25 +230,20 @@
 	spin_lock_irq(&ev_queue->lock);
 
 	while (list_empty(&ev_queue->event_list)) {
-		spin_unlock_irq(&ev_queue->lock);
+		if (ev_queue->is_closed) {
+			spin_unlock_irq(&ev_queue->lock);
+			return -EIO;
+		}
 
+		spin_unlock_irq(&ev_queue->lock);
 		if (filp->f_flags & O_NONBLOCK)
 			return -EAGAIN;
 
 		if (wait_event_interruptible(ev_queue->poll_wait,
 					     (!list_empty(&ev_queue->event_list) ||
-			/* The barriers built into wait_event_interruptible()
-			 * and wake_up() guarentee this will see the null set
-			 * without using RCU
-			 */
-					     !uverbs_file->device->ib_dev)))
+					      ev_queue->is_closed)))
 			return -ERESTARTSYS;
 
-		/* If device was disassociated and no event exists set an error */
-		if (list_empty(&ev_queue->event_list) &&
-		    !uverbs_file->device->ib_dev)
-			return -EIO;
-
 		spin_lock_irq(&ev_queue->lock);
 	}
 
@@ -285,8 +279,7 @@
 {
 	struct ib_uverbs_async_event_file *file = filp->private_data;
 
-	return ib_uverbs_event_read(&file->ev_queue, file->uverbs_file, filp,
-				    buf, count, pos,
+	return ib_uverbs_event_read(&file->ev_queue, filp, buf, count, pos,
 				    sizeof(struct ib_uverbs_async_event_desc));
 }
 
@@ -296,9 +289,8 @@
 	struct ib_uverbs_completion_event_file *comp_ev_file =
 		filp->private_data;
 
-	return ib_uverbs_event_read(&comp_ev_file->ev_queue,
-				    comp_ev_file->uobj.ufile, filp,
-				    buf, count, pos,
+	return ib_uverbs_event_read(&comp_ev_file->ev_queue, filp, buf, count,
+				    pos,
 				    sizeof(struct ib_uverbs_comp_event_desc));
 }
 
@@ -313,6 +305,8 @@
 	spin_lock_irq(&ev_queue->lock);
 	if (!list_empty(&ev_queue->event_list))
 		pollflags = EPOLLIN | EPOLLRDNORM;
+	else if (ev_queue->is_closed)
+		pollflags = EPOLLERR;
 	spin_unlock_irq(&ev_queue->lock);
 
 	return pollflags;
@@ -321,7 +315,9 @@
 static __poll_t ib_uverbs_async_event_poll(struct file *filp,
 					       struct poll_table_struct *wait)
 {
-	return ib_uverbs_event_poll(filp->private_data, filp, wait);
+	struct ib_uverbs_async_event_file *file = filp->private_data;
+
+	return ib_uverbs_event_poll(&file->ev_queue, filp, wait);
 }
 
 static __poll_t ib_uverbs_comp_event_poll(struct file *filp,
@@ -335,9 +331,9 @@
 
 static int ib_uverbs_async_event_fasync(int fd, struct file *filp, int on)
 {
-	struct ib_uverbs_event_queue *ev_queue = filp->private_data;
+	struct ib_uverbs_async_event_file *file = filp->private_data;
 
-	return fasync_helper(fd, filp, on, &ev_queue->async_queue);
+	return fasync_helper(fd, filp, on, &file->ev_queue.async_queue);
 }
 
 static int ib_uverbs_comp_event_fasync(int fd, struct file *filp, int on)
@@ -637,7 +633,7 @@
 	if (hdr->in_words * 4 != count)
 		return -EINVAL;
 
-	if (count < method_elm->req_size + sizeof(hdr)) {
+	if (count < method_elm->req_size + sizeof(*hdr)) {
 		/*
 		 * rdma-core v18 and v19 have a bug where they send DESTROY_CQ
 		 * with a 16 byte write instead of 24. Old kernels didn't
@@ -772,6 +768,8 @@
 	return (ret) ? : count;
 }
 
+static const struct vm_operations_struct rdma_umap_ops;
+
 static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
 {
 	struct ib_uverbs_file *file = filp->private_data;
@@ -785,7 +783,7 @@
 		ret = PTR_ERR(ucontext);
 		goto out;
 	}
-
+	vma->vm_ops = &rdma_umap_ops;
 	ret = ucontext->device->ops.mmap(ucontext, vma);
 out:
 	srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
@@ -793,38 +791,6 @@
 }
 
 /*
- * Each time we map IO memory into user space this keeps track of the mapping.
- * When the device is hot-unplugged we 'zap' the mmaps in user space to point
- * to the zero page and allow the hot unplug to proceed.
- *
- * This is necessary for cases like PCI physical hot unplug as the actual BAR
- * memory may vanish after this and access to it from userspace could MCE.
- *
- * RDMA drivers supporting disassociation must have their user space designed
- * to cope in some way with their IO pages going to the zero page.
- */
-struct rdma_umap_priv {
-	struct vm_area_struct *vma;
-	struct list_head list;
-};
-
-static const struct vm_operations_struct rdma_umap_ops;
-
-static void rdma_umap_priv_init(struct rdma_umap_priv *priv,
-				struct vm_area_struct *vma)
-{
-	struct ib_uverbs_file *ufile = vma->vm_file->private_data;
-
-	priv->vma = vma;
-	vma->vm_private_data = priv;
-	vma->vm_ops = &rdma_umap_ops;
-
-	mutex_lock(&ufile->umap_lock);
-	list_add(&priv->list, &ufile->umaps);
-	mutex_unlock(&ufile->umap_lock);
-}
-
-/*
  * The VMA has been dup'd, initialize the vm_private_data with a new tracking
  * struct
  */
@@ -849,7 +815,7 @@
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		goto out_unlock;
-	rdma_umap_priv_init(priv, vma);
+	rdma_umap_priv_init(priv, vma, opriv->entry);
 
 	up_read(&ufile->hw_destroy_rwsem);
 	return;
@@ -880,6 +846,9 @@
 	 * this point.
 	 */
 	mutex_lock(&ufile->umap_lock);
+	if (priv->entry)
+		rdma_user_mmap_entry_put(priv->entry);
+
 	list_del(&priv->list);
 	mutex_unlock(&ufile->umap_lock);
 	kfree(priv);
@@ -931,44 +900,6 @@
 	.fault = rdma_umap_fault,
 };
 
-/*
- * Map IO memory into a process. This is to be called by drivers as part of
- * their mmap() functions if they wish to send something like PCI-E BAR memory
- * to userspace.
- */
-int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma,
-		      unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-	struct ib_uverbs_file *ufile = ucontext->ufile;
-	struct rdma_umap_priv *priv;
-
-	if (!(vma->vm_flags & VM_SHARED))
-		return -EINVAL;
-
-	if (vma->vm_end - vma->vm_start != size)
-		return -EINVAL;
-
-	/* Driver is using this wrong, must be called by ib_uverbs_mmap */
-	if (WARN_ON(!vma->vm_file ||
-		    vma->vm_file->private_data != ufile))
-		return -EINVAL;
-	lockdep_assert_held(&ufile->device->disassociate_srcu);
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	vma->vm_page_prot = prot;
-	if (io_remap_pfn_range(vma, vma->vm_start, pfn, size, prot)) {
-		kfree(priv);
-		return -EAGAIN;
-	}
-
-	rdma_umap_priv_init(priv, vma);
-	return 0;
-}
-EXPORT_SYMBOL(rdma_user_mmap_io);
-
 void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
 {
 	struct rdma_umap_priv *priv, *next_priv;
@@ -1018,6 +949,11 @@
 
 			zap_vma_ptes(vma, vma->vm_start,
 				     vma->vm_end - vma->vm_start);
+
+			if (priv->entry) {
+				rdma_user_mmap_entry_put(priv->entry);
+				priv->entry = NULL;
+			}
 		}
 		mutex_unlock(&ufile->umap_lock);
 	skip_mm:
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_marshall.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_marshall.c
@@ -66,7 +66,7 @@
 	struct rdma_ah_attr *src = ah_attr;
 	struct rdma_ah_attr conv_ah;
 
-	memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved));
+	memset(&dst->grh, 0, sizeof(dst->grh));
 
 	if ((ah_attr->type == RDMA_AH_ATTR_TYPE_OPA) &&
 	    (rdma_ah_get_dlid(ah_attr) > be16_to_cpu(IB_LID_PERMISSIVE)) &&
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_std_types_counters.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_std_types_counters.c
@@ -105,6 +105,8 @@
 		return ret;
 
 	uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF);
+	if (IS_ERR(uattr))
+		return PTR_ERR(uattr);
 	read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64);
 	read_attr.counters_buff = uverbs_zalloc(
 		attrs, array_size(read_attr.ncounters, sizeof(u64)));
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_std_types_device.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_std_types_device.c
@@ -110,8 +110,8 @@
 		return ret;
 
 	uapi_object = uapi_get_object(attrs->ufile->device->uapi, object_id);
-	if (!uapi_object)
-		return -EINVAL;
+	if (IS_ERR(uapi_object))
+		return PTR_ERR(uapi_object);
 
 	handles = gather_objects_handle(attrs->ufile, uapi_object, attrs,
 					out_len, &total);
--- linux-ein-5.4.0.orig/drivers/infiniband/core/uverbs_uapi.c
+++ linux-ein-5.4.0/drivers/infiniband/core/uverbs_uapi.c
@@ -450,6 +450,9 @@
 	uapi->num_write_ex = max_write_ex + 1;
 	data = kmalloc_array(uapi->num_write + uapi->num_write_ex,
 			     sizeof(*uapi->write_methods), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++)
 		data[i] = &uapi->notsupp_method;
 	uapi->write_methods = data;
--- linux-ein-5.4.0.orig/drivers/infiniband/core/verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/core/verbs.c
@@ -521,6 +521,8 @@
 
 	ret = device->ops.create_ah(ah, ah_attr, flags, udata);
 	if (ret) {
+		if (ah->sgid_attr)
+			rdma_put_gid_attr(ah->sgid_attr);
 		kfree(ah);
 		return ERR_PTR(ret);
 	}
@@ -1180,16 +1182,6 @@
 	if (ret)
 		goto err;
 
-	qp->qp_type    = qp_init_attr->qp_type;
-	qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl;
-
-	atomic_set(&qp->usecnt, 0);
-	qp->mrs_used = 0;
-	spin_lock_init(&qp->mr_lock);
-	INIT_LIST_HEAD(&qp->rdma_mrs);
-	INIT_LIST_HEAD(&qp->sig_mrs);
-	qp->port = 0;
-
 	if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
 		struct ib_qp *xrc_qp =
 			create_xrc_qp_user(qp, qp_init_attr, udata);
@@ -1658,7 +1650,7 @@
 		if (!(rdma_protocol_ib(qp->device,
 				       attr->alt_ah_attr.port_num) &&
 		      rdma_protocol_ib(qp->device, port))) {
-			ret = EINVAL;
+			ret = -EINVAL;
 			goto out;
 		}
 	}
@@ -1759,7 +1751,7 @@
 
 	dev_put(netdev);
 
-	if (!rc) {
+	if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) {
 		netdev_speed = lksettings.base.speed;
 	} else {
 		netdev_speed = SPEED_1000;
@@ -2850,15 +2842,18 @@
 bool __rdma_block_iter_next(struct ib_block_iter *biter)
 {
 	unsigned int block_offset;
+	unsigned int sg_delta;
 
 	if (!biter->__sg_nents || !biter->__sg)
 		return false;
 
 	biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
 	block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
-	biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset;
+	sg_delta = BIT_ULL(biter->__pg_bit) - block_offset;
 
-	if (biter->__sg_advance >= sg_dma_len(biter->__sg)) {
+	if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) {
+		biter->__sg_advance += sg_delta;
+	} else {
 		biter->__sg_advance = 0;
 		biter->__sg = sg_next(biter->__sg);
 		biter->__sg_nents--;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -104,10 +104,19 @@
 	struct bnxt_re_qp *qp1_qp;
 };
 
+#define BNXT_RE_MAX_GSI_SQP_ENTRIES	1024
+struct bnxt_re_gsi_context {
+	struct	bnxt_re_qp *gsi_qp;
+	struct	bnxt_re_qp *gsi_sqp;
+	struct	bnxt_re_ah *gsi_sah;
+	struct	bnxt_re_sqp_entries *sqp_tbl;
+};
+
 #define BNXT_RE_MIN_MSIX		2
 #define BNXT_RE_MAX_MSIX		9
 #define BNXT_RE_AEQ_IDX			0
 #define BNXT_RE_NQ_IDX			1
+#define BNXT_RE_GEN_P5_MAX_VF		64
 
 struct bnxt_re_dev {
 	struct ib_device		ibdev;
@@ -164,10 +173,7 @@
 	u16				cosq[2];
 
 	/* QP for for handling QP1 packets */
-	u32				sqp_id;
-	struct bnxt_re_qp		*qp1_sqp;
-	struct bnxt_re_ah		*sqp_ah;
-	struct bnxt_re_sqp_entries sqp_tbl[1024];
+	struct bnxt_re_gsi_context	gsi_ctx;
 	atomic_t nq_alloc_cnt;
 	u32 is_virtfn;
 	u32 num_vfs;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -330,7 +330,7 @@
 		 */
 		if (ctx->idx == 0 &&
 		    rdma_link_local_addr((struct in6_addr *)gid_to_del) &&
-		    ctx->refcnt == 1 && rdev->qp1_sqp) {
+		    ctx->refcnt == 1 && rdev->gsi_ctx.gsi_sqp) {
 			dev_dbg(rdev_to_dev(rdev),
 				"Trying to delete GID0 while QP1 is alive\n");
 			return -EFAULT;
@@ -760,6 +760,49 @@
 	spin_unlock_irqrestore(&qp->scq->cq_lock, flags);
 }
 
+static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp)
+{
+	struct bnxt_re_qp *gsi_sqp;
+	struct bnxt_re_ah *gsi_sah;
+	struct bnxt_re_dev *rdev;
+	int rc = 0;
+
+	rdev = qp->rdev;
+	gsi_sqp = rdev->gsi_ctx.gsi_sqp;
+	gsi_sah = rdev->gsi_ctx.gsi_sah;
+
+	dev_dbg(rdev_to_dev(rdev), "Destroy the shadow AH\n");
+	bnxt_qplib_destroy_ah(&rdev->qplib_res,
+			      &gsi_sah->qplib_ah,
+			      true);
+	bnxt_qplib_clean_qp(&qp->qplib_qp);
+
+	dev_dbg(rdev_to_dev(rdev), "Destroy the shadow QP\n");
+	rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &gsi_sqp->qplib_qp);
+	if (rc) {
+		dev_err(rdev_to_dev(rdev), "Destroy Shadow QP failed");
+		goto fail;
+	}
+	bnxt_qplib_free_qp_res(&rdev->qplib_res, &gsi_sqp->qplib_qp);
+
+	/* remove from active qp list */
+	mutex_lock(&rdev->qp_lock);
+	list_del(&gsi_sqp->list);
+	mutex_unlock(&rdev->qp_lock);
+	atomic_dec(&rdev->qp_count);
+
+	kfree(rdev->gsi_ctx.sqp_tbl);
+	kfree(gsi_sah);
+	kfree(gsi_sqp);
+	rdev->gsi_ctx.gsi_sqp = NULL;
+	rdev->gsi_ctx.gsi_sah = NULL;
+	rdev->gsi_ctx.sqp_tbl = NULL;
+
+	return 0;
+fail:
+	return rc;
+}
+
 /* Queue Pairs */
 int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
 {
@@ -769,6 +812,7 @@
 	int rc;
 
 	bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);
+
 	rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
 	if (rc) {
 		dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
@@ -783,40 +827,24 @@
 
 	bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp);
 
-	if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) {
-		bnxt_qplib_destroy_ah(&rdev->qplib_res, &rdev->sqp_ah->qplib_ah,
-				      false);
-
-		bnxt_qplib_clean_qp(&qp->qplib_qp);
-		rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
-					   &rdev->qp1_sqp->qplib_qp);
-		if (rc) {
-			dev_err(rdev_to_dev(rdev),
-				"Failed to destroy Shadow QP");
-			return rc;
-		}
-		bnxt_qplib_free_qp_res(&rdev->qplib_res,
-				       &rdev->qp1_sqp->qplib_qp);
-		mutex_lock(&rdev->qp_lock);
-		list_del(&rdev->qp1_sqp->list);
-		atomic_dec(&rdev->qp_count);
-		mutex_unlock(&rdev->qp_lock);
-
-		kfree(rdev->sqp_ah);
-		kfree(rdev->qp1_sqp);
-		rdev->qp1_sqp = NULL;
-		rdev->sqp_ah = NULL;
+	if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp) {
+		rc = bnxt_re_destroy_gsi_sqp(qp);
+		if (rc)
+			goto sh_fail;
 	}
 
-	ib_umem_release(qp->rumem);
-	ib_umem_release(qp->sumem);
-
 	mutex_lock(&rdev->qp_lock);
 	list_del(&qp->list);
-	atomic_dec(&rdev->qp_count);
 	mutex_unlock(&rdev->qp_lock);
+	atomic_dec(&rdev->qp_count);
+
+	ib_umem_release(qp->rumem);
+	ib_umem_release(qp->sumem);
+
 	kfree(qp);
 	return 0;
+sh_fail:
+	return rc;
 }
 
 static u8 __from_ib_qp_type(enum ib_qp_type type)
@@ -855,7 +883,8 @@
 		bytes += (qplib_qp->sq.max_wqe * psn_sz);
 	}
 	bytes = PAGE_ALIGN(bytes);
-	umem = ib_umem_get(udata, ureq.qpsva, bytes, IB_ACCESS_LOCAL_WRITE, 1);
+	umem = ib_umem_get(&rdev->ibdev, ureq.qpsva, bytes,
+			   IB_ACCESS_LOCAL_WRITE);
 	if (IS_ERR(umem))
 		return PTR_ERR(umem);
 
@@ -868,8 +897,8 @@
 	if (!qp->qplib_qp.srq) {
 		bytes = (qplib_qp->rq.max_wqe * BNXT_QPLIB_MAX_RQE_ENTRY_SIZE);
 		bytes = PAGE_ALIGN(bytes);
-		umem = ib_umem_get(udata, ureq.qprva, bytes,
-				   IB_ACCESS_LOCAL_WRITE, 1);
+		umem = ib_umem_get(&rdev->ibdev, ureq.qprva, bytes,
+				   IB_ACCESS_LOCAL_WRITE);
 		if (IS_ERR(umem))
 			goto rqfail;
 		qp->rumem = umem;
@@ -984,8 +1013,6 @@
 	if (rc)
 		goto fail;
 
-	rdev->sqp_id = qp->qplib_qp.id;
-
 	spin_lock_init(&qp->sq_lock);
 	INIT_LIST_HEAD(&qp->list);
 	mutex_lock(&rdev->qp_lock);
@@ -998,205 +1025,375 @@
 	return NULL;
 }
 
-struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
-				struct ib_qp_init_attr *qp_init_attr,
-				struct ib_udata *udata)
+static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp,
+				struct ib_qp_init_attr *init_attr)
 {
-	struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
-	struct bnxt_re_dev *rdev = pd->rdev;
-	struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
-	struct bnxt_re_qp *qp;
-	struct bnxt_re_cq *cq;
-	struct bnxt_re_srq *srq;
-	int rc, entries;
+	struct bnxt_qplib_dev_attr *dev_attr;
+	struct bnxt_qplib_qp *qplqp;
+	struct bnxt_re_dev *rdev;
+	int entries;
 
-	if ((qp_init_attr->cap.max_send_wr > dev_attr->max_qp_wqes) ||
-	    (qp_init_attr->cap.max_recv_wr > dev_attr->max_qp_wqes) ||
-	    (qp_init_attr->cap.max_send_sge > dev_attr->max_qp_sges) ||
-	    (qp_init_attr->cap.max_recv_sge > dev_attr->max_qp_sges) ||
-	    (qp_init_attr->cap.max_inline_data > dev_attr->max_inline_data))
-		return ERR_PTR(-EINVAL);
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
+	dev_attr = &rdev->dev_attr;
 
-	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
-	if (!qp)
-		return ERR_PTR(-ENOMEM);
+	if (init_attr->srq) {
+		struct bnxt_re_srq *srq;
 
-	qp->rdev = rdev;
-	ether_addr_copy(qp->qplib_qp.smac, rdev->netdev->dev_addr);
-	qp->qplib_qp.pd = &pd->qplib_pd;
-	qp->qplib_qp.qp_handle = (u64)(unsigned long)(&qp->qplib_qp);
-	qp->qplib_qp.type = __from_ib_qp_type(qp_init_attr->qp_type);
+		srq = container_of(init_attr->srq, struct bnxt_re_srq, ib_srq);
+		if (!srq) {
+			dev_err(rdev_to_dev(rdev), "SRQ not found");
+			return -EINVAL;
+		}
+		qplqp->srq = &srq->qplib_srq;
+		qplqp->rq.max_wqe = 0;
+	} else {
+		/* Allocate 1 more than what's provided so posting max doesn't
+		 * mean empty.
+		 */
+		entries = roundup_pow_of_two(init_attr->cap.max_recv_wr + 1);
+		qplqp->rq.max_wqe = min_t(u32, entries,
+					  dev_attr->max_qp_wqes + 1);
 
-	if (qp_init_attr->qp_type == IB_QPT_GSI &&
-	    bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))
-		qp->qplib_qp.type = CMDQ_CREATE_QP_TYPE_GSI;
-	if (qp->qplib_qp.type == IB_QPT_MAX) {
+		qplqp->rq.q_full_delta = qplqp->rq.max_wqe -
+					 init_attr->cap.max_recv_wr;
+		qplqp->rq.max_sge = init_attr->cap.max_recv_sge;
+		if (qplqp->rq.max_sge > dev_attr->max_qp_sges)
+			qplqp->rq.max_sge = dev_attr->max_qp_sges;
+	}
+
+	return 0;
+}
+
+static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp)
+{
+	struct bnxt_qplib_dev_attr *dev_attr;
+	struct bnxt_qplib_qp *qplqp;
+	struct bnxt_re_dev *rdev;
+
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
+	dev_attr = &rdev->dev_attr;
+
+	qplqp->rq.max_sge = dev_attr->max_qp_sges;
+	if (qplqp->rq.max_sge > dev_attr->max_qp_sges)
+		qplqp->rq.max_sge = dev_attr->max_qp_sges;
+}
+
+static void bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
+				 struct ib_qp_init_attr *init_attr,
+				 struct ib_udata *udata)
+{
+	struct bnxt_qplib_dev_attr *dev_attr;
+	struct bnxt_qplib_qp *qplqp;
+	struct bnxt_re_dev *rdev;
+	int entries;
+
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
+	dev_attr = &rdev->dev_attr;
+
+	qplqp->sq.max_sge = init_attr->cap.max_send_sge;
+	if (qplqp->sq.max_sge > dev_attr->max_qp_sges)
+		qplqp->sq.max_sge = dev_attr->max_qp_sges;
+	/*
+	 * Change the SQ depth if user has requested minimum using
+	 * configfs. Only supported for kernel consumers
+	 */
+	entries = init_attr->cap.max_send_wr;
+	/* Allocate 128 + 1 more than what's provided */
+	entries = roundup_pow_of_two(entries + BNXT_QPLIB_RESERVED_QP_WRS + 1);
+	qplqp->sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes +
+			BNXT_QPLIB_RESERVED_QP_WRS + 1);
+	qplqp->sq.q_full_delta = BNXT_QPLIB_RESERVED_QP_WRS + 1;
+	/*
+	 * Reserving one slot for Phantom WQE. Application can
+	 * post one extra entry in this case. But allowing this to avoid
+	 * unexpected Queue full condition
+	 */
+	qplqp->sq.q_full_delta -= 1;
+}
+
+static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp,
+				       struct ib_qp_init_attr *init_attr)
+{
+	struct bnxt_qplib_dev_attr *dev_attr;
+	struct bnxt_qplib_qp *qplqp;
+	struct bnxt_re_dev *rdev;
+	int entries;
+
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
+	dev_attr = &rdev->dev_attr;
+
+	entries = roundup_pow_of_two(init_attr->cap.max_send_wr + 1);
+	qplqp->sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1);
+	qplqp->sq.q_full_delta = qplqp->sq.max_wqe -
+				 init_attr->cap.max_send_wr;
+	qplqp->sq.max_sge++; /* Need one extra sge to put UD header */
+	if (qplqp->sq.max_sge > dev_attr->max_qp_sges)
+		qplqp->sq.max_sge = dev_attr->max_qp_sges;
+}
+
+static int bnxt_re_init_qp_type(struct bnxt_re_dev *rdev,
+				struct ib_qp_init_attr *init_attr)
+{
+	struct bnxt_qplib_chip_ctx *chip_ctx;
+	int qptype;
+
+	chip_ctx = &rdev->chip_ctx;
+
+	qptype = __from_ib_qp_type(init_attr->qp_type);
+	if (qptype == IB_QPT_MAX) {
 		dev_err(rdev_to_dev(rdev), "QP type 0x%x not supported",
-			qp->qplib_qp.type);
-		rc = -EINVAL;
-		goto fail;
+			qptype);
+		qptype = -EINVAL;
+		goto out;
+	}
+
+	if (bnxt_qplib_is_chip_gen_p5(chip_ctx) &&
+	    init_attr->qp_type == IB_QPT_GSI)
+		qptype = CMDQ_CREATE_QP_TYPE_GSI;
+out:
+	return qptype;
+}
+
+static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
+				struct ib_qp_init_attr *init_attr,
+				struct ib_udata *udata)
+{
+	struct bnxt_qplib_dev_attr *dev_attr;
+	struct bnxt_qplib_qp *qplqp;
+	struct bnxt_re_dev *rdev;
+	struct bnxt_re_cq *cq;
+	int rc = 0, qptype;
+
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
+	dev_attr = &rdev->dev_attr;
+
+	/* Setup misc params */
+	ether_addr_copy(qplqp->smac, rdev->netdev->dev_addr);
+	qplqp->pd = &pd->qplib_pd;
+	qplqp->qp_handle = (u64)qplqp;
+	qplqp->max_inline_data = init_attr->cap.max_inline_data;
+	qplqp->sig_type = ((init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ?
+			    true : false);
+	qptype = bnxt_re_init_qp_type(rdev, init_attr);
+	if (qptype < 0) {
+		rc = qptype;
+		goto out;
 	}
+	qplqp->type = (u8)qptype;
 
-	qp->qplib_qp.max_inline_data = qp_init_attr->cap.max_inline_data;
-	qp->qplib_qp.sig_type = ((qp_init_attr->sq_sig_type ==
-				  IB_SIGNAL_ALL_WR) ? true : false);
-
-	qp->qplib_qp.sq.max_sge = qp_init_attr->cap.max_send_sge;
-	if (qp->qplib_qp.sq.max_sge > dev_attr->max_qp_sges)
-		qp->qplib_qp.sq.max_sge = dev_attr->max_qp_sges;
-
-	if (qp_init_attr->send_cq) {
-		cq = container_of(qp_init_attr->send_cq, struct bnxt_re_cq,
-				  ib_cq);
+	if (init_attr->qp_type == IB_QPT_RC) {
+		qplqp->max_rd_atomic = dev_attr->max_qp_rd_atom;
+		qplqp->max_dest_rd_atomic = dev_attr->max_qp_init_rd_atom;
+	}
+	qplqp->mtu = ib_mtu_enum_to_int(iboe_get_mtu(rdev->netdev->mtu));
+	qplqp->dpi = &rdev->dpi_privileged; /* Doorbell page */
+	if (init_attr->create_flags)
+		dev_dbg(rdev_to_dev(rdev),
+			"QP create flags 0x%x not supported",
+			init_attr->create_flags);
+
+	/* Setup CQs */
+	if (init_attr->send_cq) {
+		cq = container_of(init_attr->send_cq, struct bnxt_re_cq, ib_cq);
 		if (!cq) {
 			dev_err(rdev_to_dev(rdev), "Send CQ not found");
 			rc = -EINVAL;
-			goto fail;
+			goto out;
 		}
-		qp->qplib_qp.scq = &cq->qplib_cq;
+		qplqp->scq = &cq->qplib_cq;
 		qp->scq = cq;
 	}
 
-	if (qp_init_attr->recv_cq) {
-		cq = container_of(qp_init_attr->recv_cq, struct bnxt_re_cq,
-				  ib_cq);
+	if (init_attr->recv_cq) {
+		cq = container_of(init_attr->recv_cq, struct bnxt_re_cq, ib_cq);
 		if (!cq) {
 			dev_err(rdev_to_dev(rdev), "Receive CQ not found");
 			rc = -EINVAL;
-			goto fail;
+			goto out;
 		}
-		qp->qplib_qp.rcq = &cq->qplib_cq;
+		qplqp->rcq = &cq->qplib_cq;
 		qp->rcq = cq;
 	}
 
-	if (qp_init_attr->srq) {
-		srq = container_of(qp_init_attr->srq, struct bnxt_re_srq,
-				   ib_srq);
-		if (!srq) {
-			dev_err(rdev_to_dev(rdev), "SRQ not found");
-			rc = -EINVAL;
-			goto fail;
-		}
-		qp->qplib_qp.srq = &srq->qplib_srq;
-		qp->qplib_qp.rq.max_wqe = 0;
-	} else {
-		/* Allocate 1 more than what's provided so posting max doesn't
-		 * mean empty
-		 */
-		entries = roundup_pow_of_two(qp_init_attr->cap.max_recv_wr + 1);
-		qp->qplib_qp.rq.max_wqe = min_t(u32, entries,
-						dev_attr->max_qp_wqes + 1);
+	/* Setup RQ/SRQ */
+	rc = bnxt_re_init_rq_attr(qp, init_attr);
+	if (rc)
+		goto out;
+	if (init_attr->qp_type == IB_QPT_GSI)
+		bnxt_re_adjust_gsi_rq_attr(qp);
+
+	/* Setup SQ */
+	bnxt_re_init_sq_attr(qp, init_attr, udata);
+	if (init_attr->qp_type == IB_QPT_GSI)
+		bnxt_re_adjust_gsi_sq_attr(qp, init_attr);
+
+	if (udata) /* This will update DPI and qp_handle */
+		rc = bnxt_re_init_user_qp(rdev, pd, qp, udata);
+out:
+	return rc;
+}
 
-		qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe -
-						qp_init_attr->cap.max_recv_wr;
+static int bnxt_re_create_shadow_gsi(struct bnxt_re_qp *qp,
+				     struct bnxt_re_pd *pd)
+{
+	struct bnxt_re_sqp_entries *sqp_tbl = NULL;
+	struct bnxt_re_dev *rdev;
+	struct bnxt_re_qp *sqp;
+	struct bnxt_re_ah *sah;
+	int rc = 0;
+
+	rdev = qp->rdev;
+	/* Create a shadow QP to handle the QP1 traffic */
+	sqp_tbl = kzalloc(sizeof(*sqp_tbl) * BNXT_RE_MAX_GSI_SQP_ENTRIES,
+			  GFP_KERNEL);
+	if (!sqp_tbl)
+		return -ENOMEM;
+	rdev->gsi_ctx.sqp_tbl = sqp_tbl;
 
-		qp->qplib_qp.rq.max_sge = qp_init_attr->cap.max_recv_sge;
-		if (qp->qplib_qp.rq.max_sge > dev_attr->max_qp_sges)
-			qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
+	sqp = bnxt_re_create_shadow_qp(pd, &rdev->qplib_res, &qp->qplib_qp);
+	if (!sqp) {
+		rc = -ENODEV;
+		dev_err(rdev_to_dev(rdev),
+			"Failed to create Shadow QP for QP1");
+		goto out;
 	}
+	rdev->gsi_ctx.gsi_sqp = sqp;
 
-	qp->qplib_qp.mtu = ib_mtu_enum_to_int(iboe_get_mtu(rdev->netdev->mtu));
+	sqp->rcq = qp->rcq;
+	sqp->scq = qp->scq;
+	sah = bnxt_re_create_shadow_qp_ah(pd, &rdev->qplib_res,
+					  &qp->qplib_qp);
+	if (!sah) {
+		bnxt_qplib_destroy_qp(&rdev->qplib_res,
+				      &sqp->qplib_qp);
+		rc = -ENODEV;
+		dev_err(rdev_to_dev(rdev),
+			"Failed to create AH entry for ShadowQP");
+		goto out;
+	}
+	rdev->gsi_ctx.gsi_sah = sah;
 
-	if (qp_init_attr->qp_type == IB_QPT_GSI &&
-	    !(bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))) {
-		/* Allocate 1 more than what's provided */
-		entries = roundup_pow_of_two(qp_init_attr->cap.max_send_wr + 1);
-		qp->qplib_qp.sq.max_wqe = min_t(u32, entries,
-						dev_attr->max_qp_wqes + 1);
-		qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe -
-						qp_init_attr->cap.max_send_wr;
-		qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
-		if (qp->qplib_qp.rq.max_sge > dev_attr->max_qp_sges)
-			qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
-		qp->qplib_qp.sq.max_sge++;
-		if (qp->qplib_qp.sq.max_sge > dev_attr->max_qp_sges)
-			qp->qplib_qp.sq.max_sge = dev_attr->max_qp_sges;
-
-		qp->qplib_qp.rq_hdr_buf_size =
-					BNXT_QPLIB_MAX_QP1_RQ_HDR_SIZE_V2;
-
-		qp->qplib_qp.sq_hdr_buf_size =
-					BNXT_QPLIB_MAX_QP1_SQ_HDR_SIZE_V2;
-		qp->qplib_qp.dpi = &rdev->dpi_privileged;
-		rc = bnxt_qplib_create_qp1(&rdev->qplib_res, &qp->qplib_qp);
-		if (rc) {
-			dev_err(rdev_to_dev(rdev), "Failed to create HW QP1");
-			goto fail;
-		}
-		/* Create a shadow QP to handle the QP1 traffic */
-		rdev->qp1_sqp = bnxt_re_create_shadow_qp(pd, &rdev->qplib_res,
-							 &qp->qplib_qp);
-		if (!rdev->qp1_sqp) {
-			rc = -EINVAL;
-			dev_err(rdev_to_dev(rdev),
-				"Failed to create Shadow QP for QP1");
-			goto qp_destroy;
-		}
-		rdev->sqp_ah = bnxt_re_create_shadow_qp_ah(pd, &rdev->qplib_res,
-							   &qp->qplib_qp);
-		if (!rdev->sqp_ah) {
-			bnxt_qplib_destroy_qp(&rdev->qplib_res,
-					      &rdev->qp1_sqp->qplib_qp);
-			rc = -EINVAL;
-			dev_err(rdev_to_dev(rdev),
-				"Failed to create AH entry for ShadowQP");
-			goto qp_destroy;
-		}
+	return 0;
+out:
+	kfree(sqp_tbl);
+	return rc;
+}
 
-	} else {
-		/* Allocate 128 + 1 more than what's provided */
-		entries = roundup_pow_of_two(qp_init_attr->cap.max_send_wr +
-					     BNXT_QPLIB_RESERVED_QP_WRS + 1);
-		qp->qplib_qp.sq.max_wqe = min_t(u32, entries,
-						dev_attr->max_qp_wqes +
-						BNXT_QPLIB_RESERVED_QP_WRS + 1);
-		qp->qplib_qp.sq.q_full_delta = BNXT_QPLIB_RESERVED_QP_WRS + 1;
+static int bnxt_re_create_gsi_qp(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
+				 struct ib_qp_init_attr *init_attr)
+{
+	struct bnxt_re_dev *rdev;
+	struct bnxt_qplib_qp *qplqp;
+	int rc = 0;
 
-		/*
-		 * Reserving one slot for Phantom WQE. Application can
-		 * post one extra entry in this case. But allowing this to avoid
-		 * unexpected Queue full condition
-		 */
+	rdev = qp->rdev;
+	qplqp = &qp->qplib_qp;
 
-		qp->qplib_qp.sq.q_full_delta -= 1;
+	qplqp->rq_hdr_buf_size = BNXT_QPLIB_MAX_QP1_RQ_HDR_SIZE_V2;
+	qplqp->sq_hdr_buf_size = BNXT_QPLIB_MAX_QP1_SQ_HDR_SIZE_V2;
 
-		qp->qplib_qp.max_rd_atomic = dev_attr->max_qp_rd_atom;
-		qp->qplib_qp.max_dest_rd_atomic = dev_attr->max_qp_init_rd_atom;
-		if (udata) {
-			rc = bnxt_re_init_user_qp(rdev, pd, qp, udata);
-			if (rc)
-				goto fail;
-		} else {
-			qp->qplib_qp.dpi = &rdev->dpi_privileged;
-		}
+	rc = bnxt_qplib_create_qp1(&rdev->qplib_res, qplqp);
+	if (rc) {
+		dev_err(rdev_to_dev(rdev), "create HW QP1 failed!");
+		goto out;
+	}
+
+	rc = bnxt_re_create_shadow_gsi(qp, pd);
+out:
+	return rc;
+}
+
+static bool bnxt_re_test_qp_limits(struct bnxt_re_dev *rdev,
+				   struct ib_qp_init_attr *init_attr,
+				   struct bnxt_qplib_dev_attr *dev_attr)
+{
+	bool rc = true;
+
+	if (init_attr->cap.max_send_wr > dev_attr->max_qp_wqes ||
+	    init_attr->cap.max_recv_wr > dev_attr->max_qp_wqes ||
+	    init_attr->cap.max_send_sge > dev_attr->max_qp_sges ||
+	    init_attr->cap.max_recv_sge > dev_attr->max_qp_sges ||
+	    init_attr->cap.max_inline_data > dev_attr->max_inline_data) {
+		dev_err(rdev_to_dev(rdev),
+			"Create QP failed - max exceeded! 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x",
+			init_attr->cap.max_send_wr, dev_attr->max_qp_wqes,
+			init_attr->cap.max_recv_wr, dev_attr->max_qp_wqes,
+			init_attr->cap.max_send_sge, dev_attr->max_qp_sges,
+			init_attr->cap.max_recv_sge, dev_attr->max_qp_sges,
+			init_attr->cap.max_inline_data,
+			dev_attr->max_inline_data);
+		rc = false;
+	}
+	return rc;
+}
+
+struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
+				struct ib_qp_init_attr *qp_init_attr,
+				struct ib_udata *udata)
+{
+	struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
+	struct bnxt_re_dev *rdev = pd->rdev;
+	struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
+	struct bnxt_re_qp *qp;
+	int rc;
+
+	rc = bnxt_re_test_qp_limits(rdev, qp_init_attr, dev_attr);
+	if (!rc) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+	if (!qp) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+	qp->rdev = rdev;
+	rc = bnxt_re_init_qp_attr(qp, pd, qp_init_attr, udata);
+	if (rc)
+		goto fail;
 
+	if (qp_init_attr->qp_type == IB_QPT_GSI &&
+	    !(bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))) {
+		rc = bnxt_re_create_gsi_qp(qp, pd, qp_init_attr);
+		if (rc == -ENODEV)
+			goto qp_destroy;
+		if (rc)
+			goto fail;
+	} else {
 		rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp);
 		if (rc) {
 			dev_err(rdev_to_dev(rdev), "Failed to create HW QP");
 			goto free_umem;
 		}
+		if (udata) {
+			struct bnxt_re_qp_resp resp;
+
+			resp.qpid = qp->qplib_qp.id;
+			resp.rsvd = 0;
+			rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
+			if (rc) {
+				dev_err(rdev_to_dev(rdev), "Failed to copy QP udata");
+				goto qp_destroy;
+			}
+		}
 	}
 
 	qp->ib_qp.qp_num = qp->qplib_qp.id;
+	if (qp_init_attr->qp_type == IB_QPT_GSI)
+		rdev->gsi_ctx.gsi_qp = qp;
 	spin_lock_init(&qp->sq_lock);
 	spin_lock_init(&qp->rq_lock);
-
-	if (udata) {
-		struct bnxt_re_qp_resp resp;
-
-		resp.qpid = qp->ib_qp.qp_num;
-		resp.rsvd = 0;
-		rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
-		if (rc) {
-			dev_err(rdev_to_dev(rdev), "Failed to copy QP udata");
-			goto qp_destroy;
-		}
-	}
 	INIT_LIST_HEAD(&qp->list);
 	mutex_lock(&rdev->qp_lock);
 	list_add_tail(&qp->list, &rdev->qp_list);
-	atomic_inc(&rdev->qp_count);
 	mutex_unlock(&rdev->qp_lock);
+	atomic_inc(&rdev->qp_count);
 
 	return &qp->ib_qp;
 qp_destroy:
@@ -1206,6 +1403,7 @@
 	ib_umem_release(qp->sumem);
 fail:
 	kfree(qp);
+exit:
 	return ERR_PTR(rc);
 }
 
@@ -1322,7 +1520,8 @@
 
 	bytes = (qplib_srq->max_wqe * BNXT_QPLIB_MAX_RQE_ENTRY_SIZE);
 	bytes = PAGE_ALIGN(bytes);
-	umem = ib_umem_get(udata, ureq.srqva, bytes, IB_ACCESS_LOCAL_WRITE, 1);
+	umem = ib_umem_get(&rdev->ibdev, ureq.srqva, bytes,
+			   IB_ACCESS_LOCAL_WRITE);
 	if (IS_ERR(umem))
 		return PTR_ERR(umem);
 
@@ -1404,6 +1603,7 @@
 	if (nq)
 		nq->budget++;
 	atomic_inc(&rdev->srq_count);
+	spin_lock_init(&srq->lock);
 
 	return 0;
 
@@ -1425,7 +1625,7 @@
 	switch (srq_attr_mask) {
 	case IB_SRQ_MAX_WR:
 		/* SRQ resize is not supported */
-		break;
+		return -EINVAL;
 	case IB_SRQ_LIMIT:
 		/* Change the SRQ threshold */
 		if (srq_attr->srq_limit > srq->qplib_srq.max_wqe)
@@ -1440,13 +1640,12 @@
 		/* On success, update the shadow */
 		srq->srq_limit = srq_attr->srq_limit;
 		/* No need to Build and send response back to udata */
-		break;
+		return 0;
 	default:
 		dev_err(rdev_to_dev(rdev),
 			"Unsupported srq_attr_mask 0x%x", srq_attr_mask);
 		return -EINVAL;
 	}
-	return 0;
 }
 
 int bnxt_re_query_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr)
@@ -1503,7 +1702,7 @@
 				    struct bnxt_re_qp *qp1_qp,
 				    int qp_attr_mask)
 {
-	struct bnxt_re_qp *qp = rdev->qp1_sqp;
+	struct bnxt_re_qp *qp = rdev->gsi_ctx.gsi_sqp;
 	int rc = 0;
 
 	if (qp_attr_mask & IB_QP_STATE) {
@@ -1767,7 +1966,7 @@
 		dev_err(rdev_to_dev(rdev), "Failed to modify HW QP");
 		return rc;
 	}
-	if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp)
+	if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp)
 		rc = bnxt_re_modify_shadow_qp(rdev, qp, qp_attr_mask);
 	return rc;
 }
@@ -1793,6 +1992,7 @@
 		goto out;
 	}
 	qp_attr->qp_state = __to_ib_qp_state(qplib_qp->state);
+	qp_attr->cur_qp_state = __to_ib_qp_state(qplib_qp->cur_qp_state);
 	qp_attr->en_sqd_async_notify = qplib_qp->en_sqd_async_notify ? 1 : 0;
 	qp_attr->qp_access_flags = __to_ib_access_flags(qplib_qp->access);
 	qp_attr->pkey_index = qplib_qp->pkey_index;
@@ -2011,9 +2211,12 @@
 					    struct bnxt_qplib_swqe *wqe,
 					    int payload_size)
 {
+	struct bnxt_re_sqp_entries *sqp_entry;
 	struct bnxt_qplib_sge ref, sge;
+	struct bnxt_re_dev *rdev;
 	u32 rq_prod_index;
-	struct bnxt_re_sqp_entries *sqp_entry;
+
+	rdev = qp->rdev;
 
 	rq_prod_index = bnxt_qplib_get_rq_prod_index(&qp->qplib_qp);
 
@@ -2028,7 +2231,7 @@
 	ref.lkey = wqe->sg_list[0].lkey;
 	ref.size = wqe->sg_list[0].size;
 
-	sqp_entry = &qp->rdev->sqp_tbl[rq_prod_index];
+	sqp_entry = &rdev->gsi_ctx.sqp_tbl[rq_prod_index];
 
 	/* SGE 1 */
 	wqe->sg_list[0].addr = sge.addr;
@@ -2563,9 +2766,9 @@
 			goto fail;
 		}
 
-		cq->umem = ib_umem_get(udata, req.cq_va,
+		cq->umem = ib_umem_get(&rdev->ibdev, req.cq_va,
 				       entries * sizeof(struct cq_base),
-				       IB_ACCESS_LOCAL_WRITE, 1);
+				       IB_ACCESS_LOCAL_WRITE);
 		if (IS_ERR(cq->umem)) {
 			rc = PTR_ERR(cq->umem);
 			goto fail;
@@ -2848,12 +3051,13 @@
 	return rc;
 }
 
-static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *qp1_qp,
+static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *gsi_qp,
 					 struct bnxt_qplib_cqe *cqe)
 {
-	struct bnxt_re_dev *rdev = qp1_qp->rdev;
+	struct bnxt_re_dev *rdev = gsi_qp->rdev;
 	struct bnxt_re_sqp_entries *sqp_entry = NULL;
-	struct bnxt_re_qp *qp = rdev->qp1_sqp;
+	struct bnxt_re_qp *gsi_sqp = rdev->gsi_ctx.gsi_sqp;
+	struct bnxt_re_ah *gsi_sah;
 	struct ib_send_wr *swr;
 	struct ib_ud_wr udwr;
 	struct ib_recv_wr rwr;
@@ -2876,19 +3080,19 @@
 	swr = &udwr.wr;
 	tbl_idx = cqe->wr_id;
 
-	rq_hdr_buf = qp1_qp->qplib_qp.rq_hdr_buf +
-			(tbl_idx * qp1_qp->qplib_qp.rq_hdr_buf_size);
-	rq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&qp1_qp->qplib_qp,
+	rq_hdr_buf = gsi_qp->qplib_qp.rq_hdr_buf +
+			(tbl_idx * gsi_qp->qplib_qp.rq_hdr_buf_size);
+	rq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&gsi_qp->qplib_qp,
 							  tbl_idx);
 
 	/* Shadow QP header buffer */
-	shrq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&qp->qplib_qp,
+	shrq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&gsi_qp->qplib_qp,
 							    tbl_idx);
-	sqp_entry = &rdev->sqp_tbl[tbl_idx];
+	sqp_entry = &rdev->gsi_ctx.sqp_tbl[tbl_idx];
 
 	/* Store this cqe */
 	memcpy(&sqp_entry->cqe, cqe, sizeof(struct bnxt_qplib_cqe));
-	sqp_entry->qp1_qp = qp1_qp;
+	sqp_entry->qp1_qp = gsi_qp;
 
 	/* Find packet type from the cqe */
 
@@ -2942,7 +3146,7 @@
 	rwr.wr_id = tbl_idx;
 	rwr.next = NULL;
 
-	rc = bnxt_re_post_recv_shadow_qp(rdev, qp, &rwr);
+	rc = bnxt_re_post_recv_shadow_qp(rdev, gsi_sqp, &rwr);
 	if (rc) {
 		dev_err(rdev_to_dev(rdev),
 			"Failed to post Rx buffers to shadow QP");
@@ -2954,15 +3158,13 @@
 	swr->wr_id = tbl_idx;
 	swr->opcode = IB_WR_SEND;
 	swr->next = NULL;
-
-	udwr.ah = &rdev->sqp_ah->ib_ah;
-	udwr.remote_qpn = rdev->qp1_sqp->qplib_qp.id;
-	udwr.remote_qkey = rdev->qp1_sqp->qplib_qp.qkey;
+	gsi_sah = rdev->gsi_ctx.gsi_sah;
+	udwr.ah = &gsi_sah->ib_ah;
+	udwr.remote_qpn = gsi_sqp->qplib_qp.id;
+	udwr.remote_qkey = gsi_sqp->qplib_qp.qkey;
 
 	/* post data received  in the send queue */
-	rc = bnxt_re_post_send_shadow_qp(rdev, qp, swr);
-
-	return 0;
+	return bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr);
 }
 
 static void bnxt_re_process_res_rawqp1_wc(struct ib_wc *wc,
@@ -2973,6 +3175,19 @@
 	wc->wc_flags |= IB_WC_GRH;
 }
 
+static bool bnxt_re_check_if_vlan_valid(struct bnxt_re_dev *rdev,
+					u16 vlan_id)
+{
+	/*
+	 * Check if the vlan is configured in the host.  If not configured, it
+	 * can be a transparent VLAN. So dont report the vlan id.
+	 */
+	if (!__vlan_find_dev_deep_rcu(rdev->netdev,
+				      htons(ETH_P_8021Q), vlan_id))
+		return false;
+	return true;
+}
+
 static bool bnxt_re_is_vlan_pkt(struct bnxt_qplib_cqe *orig_cqe,
 				u16 *vid, u8 *sl)
 {
@@ -3014,12 +3229,12 @@
 		wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
 }
 
-static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *qp,
+static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *gsi_sqp,
 					     struct ib_wc *wc,
 					     struct bnxt_qplib_cqe *cqe)
 {
-	struct bnxt_re_dev *rdev = qp->rdev;
-	struct bnxt_re_qp *qp1_qp = NULL;
+	struct bnxt_re_dev *rdev = gsi_sqp->rdev;
+	struct bnxt_re_qp *gsi_qp = NULL;
 	struct bnxt_qplib_cqe *orig_cqe = NULL;
 	struct bnxt_re_sqp_entries *sqp_entry = NULL;
 	int nw_type;
@@ -3029,21 +3244,23 @@
 
 	tbl_idx = cqe->wr_id;
 
-	sqp_entry = &rdev->sqp_tbl[tbl_idx];
-	qp1_qp = sqp_entry->qp1_qp;
+	sqp_entry = &rdev->gsi_ctx.sqp_tbl[tbl_idx];
+	gsi_qp = sqp_entry->qp1_qp;
 	orig_cqe = &sqp_entry->cqe;
 
 	wc->wr_id = sqp_entry->wrid;
 	wc->byte_len = orig_cqe->length;
-	wc->qp = &qp1_qp->ib_qp;
+	wc->qp = &gsi_qp->ib_qp;
 
 	wc->ex.imm_data = orig_cqe->immdata;
 	wc->src_qp = orig_cqe->src_qp;
 	memcpy(wc->smac, orig_cqe->smac, ETH_ALEN);
 	if (bnxt_re_is_vlan_pkt(orig_cqe, &vlan_id, &sl)) {
-		wc->vlan_id = vlan_id;
-		wc->sl = sl;
-		wc->wc_flags |= IB_WC_WITH_VLAN;
+		if (bnxt_re_check_if_vlan_valid(rdev, vlan_id)) {
+			wc->vlan_id = vlan_id;
+			wc->sl = sl;
+			wc->wc_flags |= IB_WC_WITH_VLAN;
+		}
 	}
 	wc->port_num = 1;
 	wc->vendor_err = orig_cqe->status;
@@ -3064,8 +3281,11 @@
 				      struct ib_wc *wc,
 				      struct bnxt_qplib_cqe *cqe)
 {
+	struct bnxt_re_dev *rdev;
+	u16 vlan_id = 0;
 	u8 nw_type;
 
+	rdev = qp->rdev;
 	wc->opcode = IB_WC_RECV;
 	wc->status = __rc_to_ib_wc_status(cqe->status);
 
@@ -3077,9 +3297,12 @@
 		memcpy(wc->smac, cqe->smac, ETH_ALEN);
 		wc->wc_flags |= IB_WC_WITH_SMAC;
 		if (cqe->flags & CQ_RES_UD_FLAGS_META_FORMAT_VLAN) {
-			wc->vlan_id = (cqe->cfa_meta & 0xFFF);
-			if (wc->vlan_id < 0x1000)
-				wc->wc_flags |= IB_WC_WITH_VLAN;
+			vlan_id = (cqe->cfa_meta & 0xFFF);
+		}
+		/* Mark only if vlan_id is non zero */
+		if (vlan_id && bnxt_re_check_if_vlan_valid(rdev, vlan_id)) {
+			wc->vlan_id = vlan_id;
+			wc->wc_flags |= IB_WC_WITH_VLAN;
 		}
 		nw_type = (cqe->flags & CQ_RES_UD_FLAGS_ROCE_IP_VER_MASK) >>
 			   CQ_RES_UD_FLAGS_ROCE_IP_VER_SFT;
@@ -3114,7 +3337,7 @@
 int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
 {
 	struct bnxt_re_cq *cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq);
-	struct bnxt_re_qp *qp;
+	struct bnxt_re_qp *qp, *sh_qp;
 	struct bnxt_qplib_cqe *cqe;
 	int i, ncqe, budget;
 	struct bnxt_qplib_q *sq;
@@ -3178,8 +3401,9 @@
 
 			switch (cqe->opcode) {
 			case CQ_BASE_CQE_TYPE_REQ:
-				if (qp->rdev->qp1_sqp && qp->qplib_qp.id ==
-				    qp->rdev->qp1_sqp->qplib_qp.id) {
+				sh_qp = qp->rdev->gsi_ctx.gsi_sqp;
+				if (sh_qp &&
+				    qp->qplib_qp.id == sh_qp->qplib_qp.id) {
 					/* Handle this completion with
 					 * the stored completion
 					 */
@@ -3205,7 +3429,7 @@
 				 * stored in the table
 				 */
 				tbl_idx = cqe->wr_id;
-				sqp_entry = &cq->rdev->sqp_tbl[tbl_idx];
+				sqp_entry = &cq->rdev->gsi_ctx.sqp_tbl[tbl_idx];
 				wc->wr_id = sqp_entry->wrid;
 				bnxt_re_process_res_rawqp1_wc(wc, cqe);
 				break;
@@ -3213,8 +3437,9 @@
 				bnxt_re_process_res_rc_wc(wc, cqe);
 				break;
 			case CQ_BASE_CQE_TYPE_RES_UD:
-				if (qp->rdev->qp1_sqp && qp->qplib_qp.id ==
-				    qp->rdev->qp1_sqp->qplib_qp.id) {
+				sh_qp = qp->rdev->gsi_ctx.gsi_sqp;
+				if (sh_qp &&
+				    qp->qplib_qp.id == sh_qp->qplib_qp.id) {
 					/* Handle this completion with
 					 * the stored completion
 					 */
@@ -3323,8 +3548,10 @@
 	int rc;
 
 	rc = bnxt_qplib_free_mrw(&rdev->qplib_res, &mr->qplib_mr);
-	if (rc)
+	if (rc) {
 		dev_err(rdev_to_dev(rdev), "Dereg MR failed: %#x\n", rc);
+		return rc;
+	}
 
 	if (mr->pages) {
 		rc = bnxt_qplib_free_fast_reg_page_list(&rdev->qplib_res,
@@ -3530,7 +3757,7 @@
 	/* The fixed portion of the rkey is the same as the lkey */
 	mr->ib_mr.rkey = mr->qplib_mr.rkey;
 
-	umem = ib_umem_get(udata, start, length, mr_access_flags, 0);
+	umem = ib_umem_get(&rdev->ibdev, start, length, mr_access_flags);
 	if (IS_ERR(umem)) {
 		dev_err(rdev_to_dev(rdev), "Failed to get umem");
 		rc = -EFAULT;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/main.c
@@ -70,7 +70,7 @@
 		BNXT_RE_DESC "\n";
 
 MODULE_AUTHOR("Eddie Wai <eddie.wai@broadcom.com>");
-MODULE_DESCRIPTION(BNXT_RE_DESC " Driver");
+MODULE_DESCRIPTION(BNXT_RE_DESC);
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* globals */
@@ -119,61 +119,76 @@
  * reserved for the function. The driver may choose to allocate fewer
  * resources than the firmware maximum.
  */
-static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev)
+static void bnxt_re_limit_pf_res(struct bnxt_re_dev *rdev)
 {
-	u32 vf_qps = 0, vf_srqs = 0, vf_cqs = 0, vf_mrws = 0, vf_gids = 0;
-	u32 i;
+	struct bnxt_qplib_dev_attr *attr;
+	struct bnxt_qplib_ctx *ctx;
+	int i;
+
+	attr = &rdev->dev_attr;
+	ctx = &rdev->qplib_ctx;
+
+	ctx->qpc_count = min_t(u32, BNXT_RE_MAX_QPC_COUNT,
+			       attr->max_qp);
+	ctx->mrw_count = BNXT_RE_MAX_MRW_COUNT_256K;
+	/* Use max_mr from fw since max_mrw does not get set */
+	ctx->mrw_count = min_t(u32, ctx->mrw_count, attr->max_mr);
+	ctx->srqc_count = min_t(u32, BNXT_RE_MAX_SRQC_COUNT,
+				attr->max_srq);
+	ctx->cq_count = min_t(u32, BNXT_RE_MAX_CQ_COUNT, attr->max_cq);
+	if (!bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))
+		for (i = 0; i < MAX_TQM_ALLOC_REQ; i++)
+			rdev->qplib_ctx.tqm_count[i] =
+			rdev->dev_attr.tqm_alloc_reqs[i];
+}
+
+static void bnxt_re_limit_vf_res(struct bnxt_qplib_ctx *qplib_ctx, u32 num_vf)
+{
+	struct bnxt_qplib_vf_res *vf_res;
+	u32 mrws = 0;
 	u32 vf_pct;
+	u32 nvfs;
+
+	vf_res = &qplib_ctx->vf_res;
+	/*
+	 * Reserve a set of resources for the PF. Divide the remaining
+	 * resources among the VFs
+	 */
+	vf_pct = 100 - BNXT_RE_PCT_RSVD_FOR_PF;
+	nvfs = num_vf;
+	num_vf = 100 * num_vf;
+	vf_res->max_qp_per_vf = (qplib_ctx->qpc_count * vf_pct) / num_vf;
+	vf_res->max_srq_per_vf = (qplib_ctx->srqc_count * vf_pct) / num_vf;
+	vf_res->max_cq_per_vf = (qplib_ctx->cq_count * vf_pct) / num_vf;
+	/*
+	 * The driver allows many more MRs than other resources. If the
+	 * firmware does also, then reserve a fixed amount for the PF and
+	 * divide the rest among VFs. VFs may use many MRs for NFS
+	 * mounts, ISER, NVME applications, etc. If the firmware severely
+	 * restricts the number of MRs, then let PF have half and divide
+	 * the rest among VFs, as for the other resource types.
+	 */
+	if (qplib_ctx->mrw_count < BNXT_RE_MAX_MRW_COUNT_64K) {
+		mrws = qplib_ctx->mrw_count * vf_pct;
+		nvfs = num_vf;
+	} else {
+		mrws = qplib_ctx->mrw_count - BNXT_RE_RESVD_MR_FOR_PF;
+	}
+	vf_res->max_mrw_per_vf = (mrws / nvfs);
+	vf_res->max_gid_per_vf = BNXT_RE_MAX_GID_PER_VF;
+}
+
+static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev)
+{
 	u32 num_vfs;
-	struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
 
-	rdev->qplib_ctx.qpc_count = min_t(u32, BNXT_RE_MAX_QPC_COUNT,
-					  dev_attr->max_qp);
+	memset(&rdev->qplib_ctx.vf_res, 0, sizeof(struct bnxt_qplib_vf_res));
+	bnxt_re_limit_pf_res(rdev);
 
-	rdev->qplib_ctx.mrw_count = BNXT_RE_MAX_MRW_COUNT_256K;
-	/* Use max_mr from fw since max_mrw does not get set */
-	rdev->qplib_ctx.mrw_count = min_t(u32, rdev->qplib_ctx.mrw_count,
-					  dev_attr->max_mr);
-	rdev->qplib_ctx.srqc_count = min_t(u32, BNXT_RE_MAX_SRQC_COUNT,
-					   dev_attr->max_srq);
-	rdev->qplib_ctx.cq_count = min_t(u32, BNXT_RE_MAX_CQ_COUNT,
-					 dev_attr->max_cq);
-
-	for (i = 0; i < MAX_TQM_ALLOC_REQ; i++)
-		rdev->qplib_ctx.tqm_count[i] =
-		rdev->dev_attr.tqm_alloc_reqs[i];
-
-	if (rdev->num_vfs) {
-		/*
-		 * Reserve a set of resources for the PF. Divide the remaining
-		 * resources among the VFs
-		 */
-		vf_pct = 100 - BNXT_RE_PCT_RSVD_FOR_PF;
-		num_vfs = 100 * rdev->num_vfs;
-		vf_qps = (rdev->qplib_ctx.qpc_count * vf_pct) / num_vfs;
-		vf_srqs = (rdev->qplib_ctx.srqc_count * vf_pct) / num_vfs;
-		vf_cqs = (rdev->qplib_ctx.cq_count * vf_pct) / num_vfs;
-		/*
-		 * The driver allows many more MRs than other resources. If the
-		 * firmware does also, then reserve a fixed amount for the PF
-		 * and divide the rest among VFs. VFs may use many MRs for NFS
-		 * mounts, ISER, NVME applications, etc. If the firmware
-		 * severely restricts the number of MRs, then let PF have
-		 * half and divide the rest among VFs, as for the other
-		 * resource types.
-		 */
-		if (rdev->qplib_ctx.mrw_count < BNXT_RE_MAX_MRW_COUNT_64K)
-			vf_mrws = rdev->qplib_ctx.mrw_count * vf_pct / num_vfs;
-		else
-			vf_mrws = (rdev->qplib_ctx.mrw_count -
-				   BNXT_RE_RESVD_MR_FOR_PF) / rdev->num_vfs;
-		vf_gids = BNXT_RE_MAX_GID_PER_VF;
-	}
-	rdev->qplib_ctx.vf_res.max_mrw_per_vf = vf_mrws;
-	rdev->qplib_ctx.vf_res.max_gid_per_vf = vf_gids;
-	rdev->qplib_ctx.vf_res.max_qp_per_vf = vf_qps;
-	rdev->qplib_ctx.vf_res.max_srq_per_vf = vf_srqs;
-	rdev->qplib_ctx.vf_res.max_cq_per_vf = vf_cqs;
+	num_vfs =  bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx) ?
+			BNXT_RE_GEN_P5_MAX_VF : rdev->num_vfs;
+	if (num_vfs)
+		bnxt_re_limit_vf_res(&rdev->qplib_ctx, num_vfs);
 }
 
 /* for handling bnxt_en callbacks later */
@@ -193,9 +208,11 @@
 		return;
 
 	rdev->num_vfs = num_vfs;
-	bnxt_re_set_resource_limits(rdev);
-	bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw,
-				      &rdev->qplib_ctx);
+	if (!bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx)) {
+		bnxt_re_set_resource_limits(rdev);
+		bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw,
+					      &rdev->qplib_ctx);
+	}
 }
 
 static void bnxt_re_shutdown(void *p)
@@ -477,6 +494,7 @@
 	bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_ALLOC, -1, -1);
 	req.update_period_ms = cpu_to_le32(1000);
 	req.stats_dma_addr = cpu_to_le64(dma_map);
+	req.stats_dma_length = cpu_to_le16(sizeof(struct ctx_hw_stats_ext));
 	req.stat_ctx_flags = STAT_CTX_ALLOC_REQ_STAT_CTX_FLAGS_ROCE;
 	bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
 			    sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
@@ -788,7 +806,8 @@
 	struct ib_event event;
 	unsigned int flags;
 
-	if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
+	if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR &&
+	    rdma_is_kernel_res(&qp->ib_qp.res)) {
 		flags = bnxt_re_lock_cqs(qp);
 		bnxt_qplib_add_flush_qp(&qp->qplib_qp);
 		bnxt_re_unlock_cqs(qp, flags);
@@ -895,10 +914,14 @@
 	return 0;
 }
 
+#define BNXT_RE_GEN_P5_PF_NQ_DB		0x10000
+#define BNXT_RE_GEN_P5_VF_NQ_DB		0x4000
 static u32 bnxt_re_get_nqdb_offset(struct bnxt_re_dev *rdev, u16 indx)
 {
 	return bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx) ?
-				0x10000 : rdev->msix_entries[indx].db_offset;
+		(rdev->is_virtfn ? BNXT_RE_GEN_P5_VF_NQ_DB :
+				   BNXT_RE_GEN_P5_PF_NQ_DB) :
+				   rdev->msix_entries[indx].db_offset;
 }
 
 static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
@@ -1104,7 +1127,8 @@
 static bool bnxt_re_is_qp1_or_shadow_qp(struct bnxt_re_dev *rdev,
 					struct bnxt_re_qp *qp)
 {
-	return (qp->ib_qp.qp_type == IB_QPT_GSI) || (qp == rdev->qp1_sqp);
+	return (qp->ib_qp.qp_type == IB_QPT_GSI) ||
+	       (qp == rdev->gsi_ctx.gsi_sqp);
 }
 
 static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev)
@@ -1270,10 +1294,10 @@
 		return;
 	}
 	rdev->qplib_ctx.hwrm_intf_ver =
-		(u64)resp.hwrm_intf_major << 48 |
-		(u64)resp.hwrm_intf_minor << 32 |
-		(u64)resp.hwrm_intf_build << 16 |
-		resp.hwrm_intf_patch;
+		(u64)le16_to_cpu(resp.hwrm_intf_major) << 48 |
+		(u64)le16_to_cpu(resp.hwrm_intf_minor) << 32 |
+		(u64)le16_to_cpu(resp.hwrm_intf_build) << 16 |
+		le16_to_cpu(resp.hwrm_intf_patch);
 }
 
 static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev)
@@ -1408,8 +1432,8 @@
 				     rdev->is_virtfn);
 	if (rc)
 		goto disable_rcfw;
-	if (!rdev->is_virtfn)
-		bnxt_re_set_resource_limits(rdev);
+
+	bnxt_re_set_resource_limits(rdev);
 
 	rc = bnxt_qplib_alloc_ctx(rdev->en_dev->pdev, &rdev->qplib_ctx, 0,
 				  bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx));
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -642,12 +642,13 @@
 	int rc = 0;
 
 	RCFW_CMD_PREP(req, QUERY_SRQ, cmd_flags);
-	req.srq_cid = cpu_to_le32(srq->id);
 
 	/* Configure the request */
 	sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb));
 	if (!sbuf)
 		return -ENOMEM;
+	req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS;
+	req.srq_cid = cpu_to_le32(srq->id);
 	sb = sbuf->sb;
 	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp,
 					  (void *)sbuf, 0);
@@ -2283,13 +2284,13 @@
 			/* Add qp to flush list of the CQ */
 			bnxt_qplib_add_flush_qp(qp);
 		} else {
+			/* Before we complete, do WA 9060 */
+			if (do_wa9060(qp, cq, cq_cons, sw_sq_cons,
+				      cqe_sq_cons)) {
+				*lib_qp = qp;
+				goto out;
+			}
 			if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) {
-				/* Before we complete, do WA 9060 */
-				if (do_wa9060(qp, cq, cq_cons, sw_sq_cons,
-					      cqe_sq_cons)) {
-					*lib_qp = qp;
-					goto out;
-				}
 				cqe->status = CQ_REQ_STATUS_OK;
 				cqe++;
 				(*budget)--;
@@ -2605,11 +2606,8 @@
 
 	qp = (struct bnxt_qplib_qp *)((unsigned long)
 				      le64_to_cpu(hwcqe->qp_handle));
-	if (!qp) {
-		dev_err(&cq->hwq.pdev->dev,
-			"FP: CQ Process terminal qp is NULL\n");
+	if (!qp)
 		return -EINVAL;
-	}
 
 	/* Must block new posting of SQ and RQ */
 	qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -494,8 +494,10 @@
 	 * shall setup this area for VF. Skipping the
 	 * HW programming
 	 */
-	if (is_virtfn || bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx))
+	if (is_virtfn)
 		goto skip_ctx_setup;
+	if (bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx))
+		goto config_vf_res;
 
 	level = ctx->qpc_tbl.level;
 	req.qpc_pg_size_qpc_lvl = (level << CMDQ_INITIALIZE_FW_QPC_LVL_SFT) |
@@ -540,6 +542,7 @@
 	req.number_of_srq = cpu_to_le32(ctx->srqc_tbl.max_elements);
 	req.number_of_cq = cpu_to_le32(ctx->cq_tbl.max_elements);
 
+config_vf_res:
 	req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf);
 	req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf);
 	req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_res.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_res.c
@@ -736,6 +736,7 @@
 
 unmap_io:
 	pci_iounmap(res->pdev, dpit->dbr_bar_reg_iomem);
+	dpit->dbr_bar_reg_iomem = NULL;
 	return -ENOMEM;
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_res.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_res.h
@@ -186,7 +186,9 @@
 	u8	chip_metal;
 };
 
-#define CHIP_NUM_57500          0x1750
+#define CHIP_NUM_57508		0x1750
+#define CHIP_NUM_57504		0x1751
+#define CHIP_NUM_57502		0x1752
 
 struct bnxt_qplib_res {
 	struct pci_dev			*pdev;
@@ -203,7 +205,9 @@
 
 static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx)
 {
-	return (cctx->chip_num == CHIP_NUM_57500);
+	return (cctx->chip_num == CHIP_NUM_57508 ||
+		cctx->chip_num == CHIP_NUM_57504 ||
+		cctx->chip_num == CHIP_NUM_57502);
 }
 
 static inline u8 bnxt_qplib_get_hwq_type(struct bnxt_qplib_res *res)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -152,7 +152,7 @@
 	attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
 	attr->l2_db_size = (sb->l2_db_space_size + 1) *
 			    (0x01 << RCFW_DBR_BASE_PAGE_SHIFT);
-	attr->max_sgid = le32_to_cpu(sb->max_gid);
+	attr->max_sgid = BNXT_QPLIB_NUM_GIDS_SUPPORTED;
 
 	bnxt_qplib_query_version(rcfw, attr->fw_ver);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -47,6 +47,7 @@
 struct bnxt_qplib_dev_attr {
 #define FW_VER_ARR_LEN			4
 	u8				fw_ver[FW_VER_ARR_LEN];
+#define BNXT_QPLIB_NUM_GIDS_SUPPORTED	256
 	u16				max_sgid;
 	u16				max_mrw;
 	u32				max_qp;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -451,7 +451,7 @@
 
 	mhp->rhp = rhp;
 
-	mhp->umem = ib_umem_get(udata, start, length, acc, 0);
+	mhp->umem = ib_umem_get(pd->device, start, length, acc);
 	if (IS_ERR(mhp->umem)) {
 		err = PTR_ERR(mhp->umem);
 		kfree(mhp);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/cm.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/cm.c
@@ -1965,6 +1965,9 @@
 	int win;
 
 	skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
 	req = __skb_put_zero(skb, sizeof(*req));
 	req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR));
 	req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
@@ -2891,8 +2894,7 @@
 			srqidx = ABORT_RSS_SRQIDX_G(
 					be32_to_cpu(req->srqidx_status));
 			if (srqidx) {
-				complete_cached_srq_buffers(ep,
-							    req->srqidx_status);
+				complete_cached_srq_buffers(ep, srqidx);
 			} else {
 				/* Hold ep ref until finish_peer_abort() */
 				c4iw_get_ep(&ep->com);
@@ -3036,6 +3038,10 @@
 				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
 		}
 
+		/* As per draft-hilland-iwarp-verbs-v1.0, sec 6.2.3,
+		 * when entering the TERM state the RNIC MUST initiate a CLOSE.
+		 */
+		c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
 		c4iw_put_ep(&ep->com);
 	} else
 		pr_warn("TERM received tid %u no ep/qp\n", tid);
@@ -3279,7 +3285,7 @@
 
 static int pick_local_ip6addrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id)
 {
-	struct in6_addr uninitialized_var(addr);
+	struct in6_addr addr;
 	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
 	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
 
@@ -3379,7 +3385,7 @@
 		if (raddr->sin_addr.s_addr == htonl(INADDR_ANY)) {
 			err = pick_local_ipaddrs(dev, cm_id);
 			if (err)
-				goto fail2;
+				goto fail3;
 		}
 
 		/* find a route */
@@ -3401,7 +3407,7 @@
 		if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) {
 			err = pick_local_ip6addrs(dev, cm_id);
 			if (err)
-				goto fail2;
+				goto fail3;
 		}
 
 		/* find a route */
@@ -3607,13 +3613,14 @@
 	    ep->com.local_addr.ss_family == AF_INET) {
 		err = cxgb4_remove_server_filter(
 			ep->com.dev->rdev.lldi.ports[0], ep->stid,
-			ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+			ep->com.dev->rdev.lldi.rxq_ids[0], false);
 	} else {
 		struct sockaddr_in6 *sin6;
 		c4iw_init_wr_wait(ep->com.wr_waitp);
 		err = cxgb4_remove_server(
 				ep->com.dev->rdev.lldi.ports[0], ep->stid,
-				ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+				ep->com.dev->rdev.lldi.rxq_ids[0],
+				ep->com.local_addr.ss_family == AF_INET6);
 		if (err)
 			goto done;
 		err = c4iw_wait_for_reply(&ep->com.dev->rdev, ep->com.wr_waitp,
@@ -3874,8 +3881,8 @@
 		return 0;
 	}
 
-	ep->srqe_idx = t4_tcb_get_field32(tcb, TCB_RQ_START_W, TCB_RQ_START_W,
-			TCB_RQ_START_S);
+	ep->srqe_idx = t4_tcb_get_field32(tcb, TCB_RQ_START_W, TCB_RQ_START_M,
+					  TCB_RQ_START_S);
 cleanup:
 	pr_debug("ep %p tid %u %016x\n", ep, ep->hwtid, ep->srqe_idx);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/cq.c
@@ -754,7 +754,7 @@
 static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
 			      struct ib_wc *wc, struct c4iw_srq *srq)
 {
-	struct t4_cqe uninitialized_var(cqe);
+	struct t4_cqe cqe;
 	struct t4_wq *wq = qhp ? &qhp->wq : NULL;
 	u32 credit = 0;
 	u8 cqe_flushed;
@@ -1007,6 +1007,9 @@
 	if (attr->flags)
 		return -EINVAL;
 
+	if (entries < 1 || entries > ibdev->attrs.max_cqe)
+		return -EINVAL;
+
 	if (vector >= rhp->rdev.lldi.nciq)
 		return -EINVAL;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/device.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/device.c
@@ -953,6 +953,7 @@
 static void c4iw_remove(struct uld_ctx *ctx)
 {
 	pr_debug("c4iw_dev %p\n", ctx->dev);
+	debugfs_remove_recursive(ctx->dev->debugfs_root);
 	c4iw_unregister_device(ctx->dev);
 	c4iw_dealloc(ctx);
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/mem.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/mem.c
@@ -399,7 +399,6 @@
 	mmid = stag >> 8;
 	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
 	mhp->ibmr.length = mhp->attr.len;
-	mhp->ibmr.iova = mhp->attr.va_fbo;
 	mhp->ibmr.page_size = 1U << (mhp->attr.page_size + 12);
 	pr_debug("mmid 0x%x mhp %p\n", mmid, mhp);
 	return xa_insert_irq(&mhp->rhp->mrs, mmid, mhp, GFP_KERNEL);
@@ -543,7 +542,7 @@
 
 	mhp->rhp = rhp;
 
-	mhp->umem = ib_umem_get(udata, start, length, acc, 0);
+	mhp->umem = ib_umem_get(pd->device, start, length, acc);
 	if (IS_ERR(mhp->umem))
 		goto err_free_skb;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/qp.c
@@ -295,6 +295,7 @@
 	if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) {
 		pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n",
 			pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
+		ret = -EINVAL;
 		goto free_dma;
 	}
 
@@ -1948,10 +1949,10 @@
 			qhp->attr.layer_etype = attrs->layer_etype;
 			qhp->attr.ecode = attrs->ecode;
 			ep = qhp->ep;
-			c4iw_get_ep(&ep->com);
-			disconnect = 1;
 			if (!internal) {
+				c4iw_get_ep(&ep->com);
 				terminate = 1;
+				disconnect = 1;
 			} else {
 				terminate = qhp->attr.send_term;
 				ret = rdma_fini(rhp, qhp, ep);
@@ -2468,10 +2469,11 @@
 	memset(attr, 0, sizeof(*attr));
 	memset(init_attr, 0, sizeof(*init_attr));
 	attr->qp_state = to_ib_qp_state(qhp->attr.state);
+	attr->cur_qp_state = to_ib_qp_state(qhp->attr.state);
 	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-ein-5.4.0.orig/drivers/infiniband/hw/cxgb4/resource.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/cxgb4/resource.c
@@ -216,7 +216,7 @@
 			goto out;
 		entry->qid = qid;
 		list_add_tail(&entry->entry, &uctx->cqids);
-		for (i = qid; i & rdev->qpmask; i++) {
+		for (i = qid + 1; i & rdev->qpmask; i++) {
 			entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 			if (!entry)
 				goto out;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
@@ -579,7 +579,8 @@
 	/* Number of sub-CQs to be created for each CQ */
 	u16 sub_cqs_per_cq;
 
-	u16 reserved;
+	/* Minimum number of WQEs per SQ */
+	u16 min_sq_depth;
 
 	/*
 	 * Maximum number of SGEs (buffs) allowed for a single send work
@@ -604,6 +605,20 @@
 
 	/* The maximum size of LLQ in bytes */
 	u32 max_llq_size;
+
+	/* Maximum number of SGEs for a single RDMA read WQE */
+	u16 max_wr_rdma_sges;
+
+	/*
+	 * Maximum number of bytes that can be written to SQ between two
+	 * consecutive doorbells (in units of 64B). Driver must ensure that only
+	 * complete WQEs are written to queue before issuing a doorbell.
+	 * Examples: max_tx_batch=16 and WQE size = 64B, means up to 16 WQEs can
+	 * be written to SQ between two consecutive doorbells. max_tx_batch=11
+	 * and WQE size = 128B, means up to 5 WQEs can be written to SQ between
+	 * two consecutive doorbells. Zero means unlimited.
+	 */
+	u16 max_tx_batch;
 };
 
 struct efa_admin_feature_aenq_desc {
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_com.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_com.c
@@ -317,6 +317,7 @@
 						       struct efa_admin_acq_entry *comp,
 						       size_t comp_size_in_bytes)
 {
+	struct efa_admin_aq_entry *aqe;
 	struct efa_comp_ctx *comp_ctx;
 	u16 queue_size_mask;
 	u16 cmd_id;
@@ -350,7 +351,9 @@
 
 	reinit_completion(&comp_ctx->wait_event);
 
-	memcpy(&aq->sq.entries[pi], cmd, cmd_size_in_bytes);
+	aqe = &aq->sq.entries[pi];
+	memset(aqe, 0, sizeof(*aqe));
+	memcpy(aqe, cmd, cmd_size_in_bytes);
 
 	aq->sq.pc++;
 	atomic64_inc(&aq->stats.submitted_cmd);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_com_cmd.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_com_cmd.c
@@ -500,6 +500,8 @@
 	result->max_ah = resp.u.queue_attr.max_ah;
 	result->max_llq_size = resp.u.queue_attr.max_llq_size;
 	result->sub_cqs_per_cq = resp.u.queue_attr.sub_cqs_per_cq;
+	result->max_tx_batch = resp.u.queue_attr.max_tx_batch;
+	result->min_sq_depth = resp.u.queue_attr.min_sq_depth;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_com_cmd.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_com_cmd.h
@@ -127,6 +127,8 @@
 	u16 sub_cqs_per_cq;
 	u16 max_sq_sge;
 	u16 max_rq_sge;
+	u16 max_tx_batch;
+	u16 min_sq_depth;
 	u8 db_bar;
 };
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_main.c
@@ -10,10 +10,12 @@
 
 #include "efa.h"
 
-#define PCI_DEV_ID_EFA_VF 0xefa0
+#define PCI_DEV_ID_EFA0_VF 0xefa0
+#define PCI_DEV_ID_EFA1_VF 0xefa1
 
 static const struct pci_device_id efa_pci_tbl[] = {
-	{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA_VF) },
+	{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA0_VF) },
+	{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA1_VF) },
 	{ }
 };
 
@@ -340,6 +342,7 @@
 	}
 
 	if (irq_num != msix_vecs) {
+		efa_disable_msix(dev);
 		dev_err(&dev->pdev->dev,
 			"Allocated %d MSI-X (out of %d requested)\n",
 			irq_num, msix_vecs);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/efa/efa_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/efa/efa_verbs.c
@@ -745,7 +745,6 @@
 	rq_entry_inserted = true;
 	qp->qp_handle = create_qp_resp.qp_handle;
 	qp->ibqp.qp_num = create_qp_resp.qp_num;
-	qp->ibqp.qp_type = init_attr->qp_type;
 	qp->max_send_wr = init_attr->cap.max_send_wr;
 	qp->max_recv_wr = init_attr->cap.max_recv_wr;
 	qp->max_send_sge = init_attr->cap.max_send_sge;
@@ -1232,7 +1231,7 @@
  */
 static int pbl_indirect_initialize(struct efa_dev *dev, struct pbl_context *pbl)
 {
-	u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, PAGE_SIZE);
+	u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, EFA_CHUNK_PAYLOAD_SIZE);
 	struct scatterlist *sgl;
 	int sg_dma_cnt, err;
 
@@ -1423,7 +1422,7 @@
 		goto err_out;
 	}
 
-	mr->umem = ib_umem_get(udata, start, length, access_flags, 0);
+	mr->umem = ib_umem_get(ibpd->device, start, length, access_flags);
 	if (IS_ERR(mr->umem)) {
 		err = PTR_ERR(mr->umem);
 		ibdev_dbg(&dev->ibdev,
@@ -1538,11 +1537,39 @@
 	return efa_com_dealloc_uar(&dev->edev, &params);
 }
 
+#define EFA_CHECK_USER_COMP(_dev, _comp_mask, _attr, _mask, _attr_str) \
+	(_attr_str = (!(_dev)->dev_attr._attr || ((_comp_mask) & (_mask))) ? \
+		     NULL : #_attr)
+
+static int efa_user_comp_handshake(const struct ib_ucontext *ibucontext,
+				   const struct efa_ibv_alloc_ucontext_cmd *cmd)
+{
+	struct efa_dev *dev = to_edev(ibucontext->device);
+	char *attr_str;
+
+	if (EFA_CHECK_USER_COMP(dev, cmd->comp_mask, max_tx_batch,
+				EFA_ALLOC_UCONTEXT_CMD_COMP_TX_BATCH, attr_str))
+		goto err;
+
+	if (EFA_CHECK_USER_COMP(dev, cmd->comp_mask, min_sq_depth,
+				EFA_ALLOC_UCONTEXT_CMD_COMP_MIN_SQ_WR,
+				attr_str))
+		goto err;
+
+	return 0;
+
+err:
+	ibdev_dbg(&dev->ibdev, "Userspace handshake failed for %s attribute\n",
+		  attr_str);
+	return -EOPNOTSUPP;
+}
+
 int efa_alloc_ucontext(struct ib_ucontext *ibucontext, struct ib_udata *udata)
 {
 	struct efa_ucontext *ucontext = to_eucontext(ibucontext);
 	struct efa_dev *dev = to_edev(ibucontext->device);
 	struct efa_ibv_alloc_ucontext_resp resp = {};
+	struct efa_ibv_alloc_ucontext_cmd cmd = {};
 	struct efa_com_alloc_uar_result result;
 	int err;
 
@@ -1551,6 +1578,18 @@
 	 * we will ack input fields in our response.
 	 */
 
+	err = ib_copy_from_udata(&cmd, udata,
+				 min(sizeof(cmd), udata->inlen));
+	if (err) {
+		ibdev_dbg(&dev->ibdev,
+			  "Cannot copy udata for alloc_ucontext\n");
+		goto err_out;
+	}
+
+	err = efa_user_comp_handshake(ibucontext, &cmd);
+	if (err)
+		goto err_out;
+
 	err = efa_com_alloc_uar(&dev->edev, &result);
 	if (err)
 		goto err_out;
@@ -1563,6 +1602,8 @@
 	resp.sub_cqs_per_cq = dev->dev_attr.sub_cqs_per_cq;
 	resp.inline_buf_size = dev->dev_attr.inline_buf_size;
 	resp.max_llq_size = dev->dev_attr.max_llq_size;
+	resp.max_tx_batch = dev->dev_attr.max_tx_batch;
+	resp.min_sq_wr = dev->dev_attr.min_sq_depth;
 
 	if (udata && udata->outlen) {
 		err = ib_copy_to_udata(udata, &resp,
@@ -1612,11 +1653,13 @@
 	switch (entry->mmap_flag) {
 	case EFA_MMAP_IO_NC:
 		err = rdma_user_mmap_io(&ucontext->ibucontext, vma, pfn, length,
-					pgprot_noncached(vma->vm_page_prot));
+					pgprot_noncached(vma->vm_page_prot),
+					NULL);
 		break;
 	case EFA_MMAP_IO_WC:
 		err = rdma_user_mmap_io(&ucontext->ibucontext, vma, pfn, length,
-					pgprot_writecombine(vma->vm_page_prot));
+					pgprot_writecombine(vma->vm_page_prot),
+					NULL);
 		break;
 	case EFA_MMAP_DMA_PAGE:
 		for (va = vma->vm_start; va < vma->vm_end;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/affinity.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/affinity.c
@@ -218,6 +218,8 @@
 	for (node = 0; node < node_affinity.num_possible_nodes; node++)
 		hfi1_per_node_cntr[node] = 1;
 
+	pci_dev_put(dev);
+
 	return 0;
 }
 
@@ -479,6 +481,8 @@
 			  rvt_get_ibdev_name(&(dd)->verbs_dev.rdi), i, cpu);
 	}
 
+	free_cpumask_var(available_cpus);
+	free_cpumask_var(non_intr_cpus);
 	return 0;
 
 fail:
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/chip.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/chip.c
@@ -1685,6 +1685,14 @@
 	return dd->verbs_dev.n_piodrain;
 }
 
+static u64 access_sw_ctx0_seq_drop(const struct cntr_entry *entry,
+				   void *context, int vl, int mode, u64 data)
+{
+	struct hfi1_devdata *dd = context;
+
+	return dd->ctx0_seq_drop;
+}
+
 static u64 access_sw_vtx_wait(const struct cntr_entry *entry,
 			      void *context, int vl, int mode, u64 data)
 {
@@ -4106,6 +4114,7 @@
 static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = {
 [C_RCV_OVF] = RXE32_DEV_CNTR_ELEM(RcvOverflow, RCV_BUF_OVFL_CNT, CNTR_SYNTH),
 [C_RX_LEN_ERR] = RXE32_DEV_CNTR_ELEM(RxLenErr, RCV_LENGTH_ERR_CNT, CNTR_SYNTH),
+[C_RX_SHORT_ERR] = RXE32_DEV_CNTR_ELEM(RxShrErr, RCV_SHORT_ERR_CNT, CNTR_SYNTH),
 [C_RX_ICRC_ERR] = RXE32_DEV_CNTR_ELEM(RxICrcErr, RCV_ICRC_ERR_CNT, CNTR_SYNTH),
 [C_RX_EBP] = RXE32_DEV_CNTR_ELEM(RxEbpCnt, RCV_EBP_CNT, CNTR_SYNTH),
 [C_RX_TID_FULL] = RXE32_DEV_CNTR_ELEM(RxTIDFullEr, RCV_TID_FULL_ERR_CNT,
@@ -4249,6 +4258,8 @@
 			    access_sw_cpu_intr),
 [C_SW_CPU_RCV_LIM] = CNTR_ELEM("RcvLimit", 0, 0, CNTR_NORMAL,
 			    access_sw_cpu_rcv_limit),
+[C_SW_CTX0_SEQ_DROP] = CNTR_ELEM("SeqDrop0", 0, 0, CNTR_NORMAL,
+			    access_sw_ctx0_seq_drop),
 [C_SW_VTX_WAIT] = CNTR_ELEM("vTxWait", 0, 0, CNTR_NORMAL,
 			    access_sw_vtx_wait),
 [C_SW_PIO_WAIT] = CNTR_ELEM("PioWait", 0, 0, CNTR_NORMAL,
@@ -12180,6 +12191,7 @@
 
 	if (dd->synth_stats_timer.function)
 		del_timer_sync(&dd->synth_stats_timer);
+	cancel_work_sync(&dd->update_cntr_work);
 	ppd = (struct hfi1_pportdata *)(dd + 1);
 	for (i = 0; i < dd->num_pports; i++, ppd++) {
 		kfree(ppd->cntrs);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/chip.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/chip.h
@@ -859,6 +859,7 @@
 enum {
 	C_RCV_OVF = 0,
 	C_RX_LEN_ERR,
+	C_RX_SHORT_ERR,
 	C_RX_ICRC_ERR,
 	C_RX_EBP,
 	C_RX_TID_FULL,
@@ -926,6 +927,7 @@
 	C_DC_PG_STS_TX_MBE_CNT,
 	C_SW_CPU_INTR,
 	C_SW_CPU_RCV_LIM,
+	C_SW_CTX0_SEQ_DROP,
 	C_SW_VTX_WAIT,
 	C_SW_PIO_WAIT,
 	C_SW_PIO_DRAIN,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/chip_registers.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/chip_registers.h
@@ -381,6 +381,7 @@
 #define DC_LCB_STS_LINK_TRANSFER_ACTIVE (DC_LCB_CSRS + 0x000000000468)
 #define DC_LCB_STS_ROUND_TRIP_LTP_CNT (DC_LCB_CSRS + 0x0000000004B0)
 #define RCV_LENGTH_ERR_CNT 0
+#define RCV_SHORT_ERR_CNT 2
 #define RCV_ICRC_ERR_CNT 6
 #define RCV_EBP_CNT 9
 #define RCV_BUF_OVFL_CNT 10
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/debugfs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/debugfs.c
@@ -985,15 +985,10 @@
 static int __i2c_debugfs_open(struct inode *in, struct file *fp, u32 target)
 {
 	struct hfi1_pportdata *ppd;
-	int ret;
 
 	ppd = private2ppd(fp);
 
-	ret = acquire_chip_resource(ppd->dd, i2c_target(target), 0);
-	if (ret) /* failed - release the module */
-		module_put(THIS_MODULE);
-
-	return ret;
+	return acquire_chip_resource(ppd->dd, i2c_target(target), 0);
 }
 
 static int i2c1_debugfs_open(struct inode *in, struct file *fp)
@@ -1013,7 +1008,6 @@
 	ppd = private2ppd(fp);
 
 	release_chip_resource(ppd->dd, i2c_target(target));
-	module_put(THIS_MODULE);
 
 	return 0;
 }
@@ -1031,18 +1025,10 @@
 static int __qsfp_debugfs_open(struct inode *in, struct file *fp, u32 target)
 {
 	struct hfi1_pportdata *ppd;
-	int ret;
-
-	if (!try_module_get(THIS_MODULE))
-		return -ENODEV;
 
 	ppd = private2ppd(fp);
 
-	ret = acquire_chip_resource(ppd->dd, i2c_target(target), 0);
-	if (ret) /* failed - release the module */
-		module_put(THIS_MODULE);
-
-	return ret;
+	return acquire_chip_resource(ppd->dd, i2c_target(target), 0);
 }
 
 static int qsfp1_debugfs_open(struct inode *in, struct file *fp)
@@ -1062,7 +1048,6 @@
 	ppd = private2ppd(fp);
 
 	release_chip_resource(ppd->dd, i2c_target(target));
-	module_put(THIS_MODULE);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/driver.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/driver.c
@@ -734,6 +734,7 @@
 {
 	int ret;
 
+	packet->rcd->dd->ctx0_seq_drop++;
 	/* Set up for the next packet */
 	packet->rhqoff += packet->rsize;
 	if (packet->rhqoff >= packet->maxcnt)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/efivar.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/efivar.c
@@ -152,7 +152,7 @@
 		      unsigned long *size, void **return_data)
 {
 	char prefix_name[64];
-	char name[64];
+	char name[128];
 	int result;
 	int i;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/file_ops.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/file_ops.c
@@ -200,23 +200,24 @@
 
 	fd = kzalloc(sizeof(*fd), GFP_KERNEL);
 
-	if (fd) {
-		fd->rec_cpu_num = -1; /* no cpu affinity by default */
-		fd->mm = current->mm;
-		mmgrab(fd->mm);
-		fd->dd = dd;
-		kobject_get(&fd->dd->kobj);
-		fp->private_data = fd;
-	} else {
-		fp->private_data = NULL;
-
-		if (atomic_dec_and_test(&dd->user_refcount))
-			complete(&dd->user_comp);
-
-		return -ENOMEM;
-	}
-
+	if (!fd || init_srcu_struct(&fd->pq_srcu))
+		goto nomem;
+	spin_lock_init(&fd->pq_rcu_lock);
+	spin_lock_init(&fd->tid_lock);
+	spin_lock_init(&fd->invalid_lock);
+	fd->rec_cpu_num = -1; /* no cpu affinity by default */
+	fd->mm = current->mm;
+	mmgrab(fd->mm);
+	fd->dd = dd;
+	kobject_get(&fd->dd->kobj);
+	fp->private_data = fd;
 	return 0;
+nomem:
+	kfree(fd);
+	fp->private_data = NULL;
+	if (atomic_dec_and_test(&dd->user_refcount))
+		complete(&dd->user_comp);
+	return -ENOMEM;
 }
 
 static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
@@ -301,21 +302,32 @@
 static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
 	struct hfi1_filedata *fd = kiocb->ki_filp->private_data;
-	struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+	struct hfi1_user_sdma_pkt_q *pq;
 	struct hfi1_user_sdma_comp_q *cq = fd->cq;
 	int done = 0, reqs = 0;
 	unsigned long dim = from->nr_segs;
+	int idx;
 
-	if (!cq || !pq)
+	if (!HFI1_CAP_IS_KSET(SDMA))
+		return -EINVAL;
+	idx = srcu_read_lock(&fd->pq_srcu);
+	pq = srcu_dereference(fd->pq, &fd->pq_srcu);
+	if (!cq || !pq) {
+		srcu_read_unlock(&fd->pq_srcu, idx);
 		return -EIO;
+	}
 
-	if (!iter_is_iovec(from) || !dim)
+	if (!iter_is_iovec(from) || !dim) {
+		srcu_read_unlock(&fd->pq_srcu, idx);
 		return -EINVAL;
+	}
 
 	trace_hfi1_sdma_request(fd->dd, fd->uctxt->ctxt, fd->subctxt, dim);
 
-	if (atomic_read(&pq->n_reqs) == pq->n_max_reqs)
+	if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) {
+		srcu_read_unlock(&fd->pq_srcu, idx);
 		return -ENOSPC;
+	}
 
 	while (dim) {
 		int ret;
@@ -333,6 +345,7 @@
 		reqs++;
 	}
 
+	srcu_read_unlock(&fd->pq_srcu, idx);
 	return reqs;
 }
 
@@ -707,6 +720,7 @@
 	if (atomic_dec_and_test(&dd->user_refcount))
 		complete(&dd->user_comp);
 
+	cleanup_srcu_struct(&fdata->pq_srcu);
 	kfree(fdata);
 	return 0;
 }
@@ -1210,8 +1224,10 @@
 		goto done;
 
 	ret = init_user_ctxt(fd, uctxt);
-	if (ret)
+	if (ret) {
+		hfi1_free_ctxt_rcv_groups(uctxt);
 		goto done;
+	}
 
 	user_init(uctxt);
 
@@ -1347,12 +1363,15 @@
 		addr = arg + offsetof(struct hfi1_tid_info, tidcnt);
 		if (copy_to_user((void __user *)addr, &tinfo.tidcnt,
 				 sizeof(tinfo.tidcnt)))
-			return -EFAULT;
+			ret = -EFAULT;
 
 		addr = arg + offsetof(struct hfi1_tid_info, length);
-		if (copy_to_user((void __user *)addr, &tinfo.length,
+		if (!ret && copy_to_user((void __user *)addr, &tinfo.length,
 				 sizeof(tinfo.length)))
 			ret = -EFAULT;
+
+		if (ret)
+			hfi1_user_exp_rcv_invalid(fd, &tinfo);
 	}
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/firmware.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/firmware.c
@@ -1786,6 +1786,7 @@
 
 	if (!dd->platform_config.data) {
 		dd_dev_err(dd, "%s: Missing config file\n", __func__);
+		ret = -EINVAL;
 		goto bail;
 	}
 	ptr = (u32 *)dd->platform_config.data;
@@ -1794,6 +1795,7 @@
 	ptr++;
 	if (magic_num != PLATFORM_CONFIG_MAGIC_NUM) {
 		dd_dev_err(dd, "%s: Bad config file\n", __func__);
+		ret = -EINVAL;
 		goto bail;
 	}
 
@@ -1817,6 +1819,7 @@
 	if (file_length > dd->platform_config.size) {
 		dd_dev_info(dd, "%s:File claims to be larger than read size\n",
 			    __func__);
+		ret = -EINVAL;
 		goto bail;
 	} else if (file_length < dd->platform_config.size) {
 		dd_dev_info(dd,
@@ -1837,6 +1840,7 @@
 			dd_dev_err(dd, "%s: Failed validation at offset %ld\n",
 				   __func__, (ptr - (u32 *)
 					      dd->platform_config.data));
+			ret = -EINVAL;
 			goto bail;
 		}
 
@@ -1883,6 +1887,7 @@
 					   __func__, table_type,
 					   (ptr - (u32 *)
 					    dd->platform_config.data));
+				ret = -EINVAL;
 				goto bail; /* We don't trust this file now */
 			}
 			pcfgcache->config_tables[table_type].table = ptr;
@@ -1907,6 +1912,7 @@
 					   __func__, table_type,
 					   (ptr -
 					    (u32 *)dd->platform_config.data));
+				ret = -EINVAL;
 				goto bail; /* We don't trust this file now */
 			}
 			pcfgcache->config_tables[table_type].table_metadata =
@@ -1924,6 +1930,7 @@
 			dd_dev_err(dd, "%s: Failed CRC check at offset %ld\n",
 				   __func__, (ptr -
 				   (u32 *)dd->platform_config.data));
+			ret = -EINVAL;
 			goto bail;
 		}
 		/* Jump the CRC DWORD */
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/hfi.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/hfi.h
@@ -1153,6 +1153,8 @@
 
 	char *boardname; /* human readable board info */
 
+	u64 ctx0_seq_drop;
+
 	/* reset value */
 	u64 z_int_counter;
 	u64 z_rcv_limit;
@@ -1436,10 +1438,13 @@
 
 /* Private data for file operations */
 struct hfi1_filedata {
+	struct srcu_struct pq_srcu;
 	struct hfi1_devdata *dd;
 	struct hfi1_ctxtdata *uctxt;
 	struct hfi1_user_sdma_comp_q *cq;
-	struct hfi1_user_sdma_pkt_q *pq;
+	/* update side lock for SRCU */
+	spinlock_t pq_rcu_lock;
+	struct hfi1_user_sdma_pkt_q __rcu *pq;
 	u16 subctxt;
 	/* for cpu affinity; -1 if none */
 	int rec_cpu_num;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/init.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/init.c
@@ -543,7 +543,7 @@
 	u16 shift, mult;
 	u64 src;
 	u32 current_egress_rate; /* Mbits /sec */
-	u32 max_pkt_time;
+	u64 max_pkt_time;
 	/*
 	 * max_pkt_time is the maximum packet egress time in units
 	 * of the fabric clock period 1/(805 MHz).
@@ -664,12 +664,7 @@
 
 	ppd->pkeys[default_pkey_idx] = DEFAULT_P_KEY;
 	ppd->part_enforce |= HFI1_PART_ENFORCE_IN;
-
-	if (loopback) {
-		dd_dev_err(dd, "Faking data partition 0x8001 in idx %u\n",
-			   !default_pkey_idx);
-		ppd->pkeys[!default_pkey_idx] = 0x8001;
-	}
+	ppd->pkeys[0] = 0x8001;
 
 	INIT_WORK(&ppd->link_vc_work, handle_verify_cap);
 	INIT_WORK(&ppd->link_up_work, handle_link_up);
@@ -845,6 +840,29 @@
 }
 
 /**
+ * destroy_workqueues - destroy per port workqueues
+ * @dd: the hfi1_ib device
+ */
+static void destroy_workqueues(struct hfi1_devdata *dd)
+{
+	int pidx;
+	struct hfi1_pportdata *ppd;
+
+	for (pidx = 0; pidx < dd->num_pports; ++pidx) {
+		ppd = dd->pport + pidx;
+
+		if (ppd->hfi1_wq) {
+			destroy_workqueue(ppd->hfi1_wq);
+			ppd->hfi1_wq = NULL;
+		}
+		if (ppd->link_wq) {
+			destroy_workqueue(ppd->link_wq);
+			ppd->link_wq = NULL;
+		}
+	}
+}
+
+/**
  * enable_general_intr() - Enable the IRQs that will be handled by the
  * general interrupt handler.
  * @dd: valid devdata
@@ -1117,15 +1135,10 @@
 		 * We can't count on interrupts since we are stopping.
 		 */
 		hfi1_quiet_serdes(ppd);
-
-		if (ppd->hfi1_wq) {
-			destroy_workqueue(ppd->hfi1_wq);
-			ppd->hfi1_wq = NULL;
-		}
-		if (ppd->link_wq) {
-			destroy_workqueue(ppd->link_wq);
-			ppd->link_wq = NULL;
-		}
+		if (ppd->hfi1_wq)
+			flush_workqueue(ppd->hfi1_wq);
+		if (ppd->link_wq)
+			flush_workqueue(ppd->link_wq);
 	}
 	sdma_exit(dd);
 }
@@ -1162,7 +1175,7 @@
 	rcd->egrbufs.rcvtids = NULL;
 
 	for (e = 0; e < rcd->egrbufs.alloced; e++) {
-		if (rcd->egrbufs.buffers[e].dma)
+		if (rcd->egrbufs.buffers[e].addr)
 			dma_free_coherent(&dd->pcidev->dev,
 					  rcd->egrbufs.buffers[e].len,
 					  rcd->egrbufs.buffers[e].addr,
@@ -1814,6 +1827,7 @@
 	 * clear dma engines, etc.
 	 */
 	shutdown_device(dd);
+	destroy_workqueues(dd);
 
 	stop_timers(dd);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/iowait.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/iowait.c
@@ -81,7 +81,9 @@
 void iowait_cancel_work(struct iowait *w)
 {
 	cancel_work_sync(&iowait_get_ib_work(w)->iowork);
-	cancel_work_sync(&iowait_get_tid_work(w)->iowork);
+	/* Make sure that the iowork for TID RDMA is used */
+	if (iowait_get_tid_work(w)->iowork.func)
+		cancel_work_sync(&iowait_get_tid_work(w)->iowork);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/mmu_rb.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/mmu_rb.c
@@ -173,7 +173,7 @@
 		goto unlock;
 	}
 	__mmu_int_rb_insert(mnode, &handler->root);
-	list_add(&mnode->list, &handler->lru_list);
+	list_add_tail(&mnode->list, &handler->lru_list);
 
 	ret = handler->ops->insert(handler->ops_arg, mnode);
 	if (ret) {
@@ -220,8 +220,10 @@
 	spin_lock_irqsave(&handler->lock, flags);
 	node = __mmu_rb_search(handler, addr, len);
 	if (node) {
-		if (node->addr == addr && node->len == len)
+		if (node->addr == addr && node->len == len) {
+			list_move_tail(&node->list, &handler->lru_list);
 			goto unlock;
+		}
 		__mmu_int_rb_remove(node, &handler->root);
 		list_del(&node->list); /* remove from LRU list */
 		ret = true;
@@ -242,8 +244,7 @@
 	INIT_LIST_HEAD(&del_list);
 
 	spin_lock_irqsave(&handler->lock, flags);
-	list_for_each_entry_safe_reverse(rbnode, ptr, &handler->lru_list,
-					 list) {
+	list_for_each_entry_safe(rbnode, ptr, &handler->lru_list, list) {
 		if (handler->ops->evict(handler->ops_arg, rbnode, evict_arg,
 					&stop)) {
 			__mmu_int_rb_remove(rbnode, &handler->root);
@@ -255,9 +256,7 @@
 	}
 	spin_unlock_irqrestore(&handler->lock, flags);
 
-	while (!list_empty(&del_list)) {
-		rbnode = list_first_entry(&del_list, struct mmu_rb_node, list);
-		list_del(&rbnode->list);
+	list_for_each_entry_safe(rbnode, ptr, &del_list, list) {
 		handler->ops->remove(handler->ops_arg, rbnode);
 	}
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/pcie.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/pcie.c
@@ -45,6 +45,7 @@
  *
  */
 
+#include <linux/bitfield.h>
 #include <linux/pci.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -261,12 +262,6 @@
 	return speed;
 }
 
-/* return the PCIe link speed from the given link status */
-static u32 extract_width(u16 linkstat)
-{
-	return (linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-}
-
 /* read the link status and set dd->{lbus_width,lbus_speed,lbus_info} */
 static void update_lbus_info(struct hfi1_devdata *dd)
 {
@@ -279,7 +274,7 @@
 		return;
 	}
 
-	dd->lbus_width = extract_width(linkstat);
+	dd->lbus_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, linkstat);
 	dd->lbus_speed = extract_speed(linkstat);
 	snprintf(dd->lbus_info, sizeof(dd->lbus_info),
 		 "PCIe,%uMHz,x%u", dd->lbus_speed, dd->lbus_width);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/pio.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/pio.c
@@ -920,6 +920,7 @@
 {
 	u64 reg;
 	struct pio_buf *pbuf;
+	LIST_HEAD(wake_list);
 
 	if (!sc)
 		return;
@@ -954,19 +955,20 @@
 	spin_unlock(&sc->release_lock);
 
 	write_seqlock(&sc->waitlock);
-	while (!list_empty(&sc->piowait)) {
+	list_splice_init(&sc->piowait, &wake_list);
+	write_sequnlock(&sc->waitlock);
+	while (!list_empty(&wake_list)) {
 		struct iowait *wait;
 		struct rvt_qp *qp;
 		struct hfi1_qp_priv *priv;
 
-		wait = list_first_entry(&sc->piowait, struct iowait, list);
+		wait = list_first_entry(&wake_list, struct iowait, list);
 		qp = iowait_to_qp(wait);
 		priv = qp->priv;
 		list_del_init(&priv->s_iowait.list);
 		priv->s_iowait.lock = NULL;
 		hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN);
 	}
-	write_sequnlock(&sc->waitlock);
 
 	spin_unlock_irq(&sc->alloc_lock);
 }
@@ -2129,7 +2131,7 @@
 				   "Unable to allocate credit return DMA range for NUMA %d\n",
 				   i);
 			ret = -ENOMEM;
-			goto done;
+			goto free_cr_base;
 		}
 	}
 	set_dev_node(&dd->pcidev->dev, dd->node);
@@ -2137,6 +2139,10 @@
 	ret = 0;
 done:
 	return ret;
+
+free_cr_base:
+	free_credit_return(dd);
+	goto done;
 }
 
 void free_credit_return(struct hfi1_devdata *dd)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/qp.c
@@ -381,7 +381,10 @@
 	struct hfi1_ibport *ibp =
 		to_iport(qp->ibqp.device, qp->port_num);
 	struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-	struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+	struct hfi1_devdata *dd = ppd->dd;
+
+	if (dd->flags & HFI1_SHUTDOWN)
+		return true;
 
 	return iowait_schedule(&priv->s_iowait, ppd->hfi1_wq,
 			       priv->s_sde ?
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/sdma.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/sdma.c
@@ -1329,11 +1329,13 @@
 		kvfree(sde->tx_ring);
 		sde->tx_ring = NULL;
 	}
-	spin_lock_irq(&dd->sde_map_lock);
-	sdma_map_free(rcu_access_pointer(dd->sdma_map));
-	RCU_INIT_POINTER(dd->sdma_map, NULL);
-	spin_unlock_irq(&dd->sde_map_lock);
-	synchronize_rcu();
+	if (rcu_access_pointer(dd->sdma_map)) {
+		spin_lock_irq(&dd->sde_map_lock);
+		sdma_map_free(rcu_access_pointer(dd->sdma_map));
+		RCU_INIT_POINTER(dd->sdma_map, NULL);
+		spin_unlock_irq(&dd->sde_map_lock);
+		synchronize_rcu();
+	}
 	kfree(dd->per_sdma);
 	dd->per_sdma = NULL;
 
@@ -3056,6 +3058,7 @@
 static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
 {
 	int i;
+	struct sdma_desc *descp;
 
 	/* Handle last descriptor */
 	if (unlikely((tx->num_desc == (MAX_DESC - 1)))) {
@@ -3076,12 +3079,10 @@
 	if (unlikely(tx->num_desc == MAX_DESC))
 		goto enomem;
 
-	tx->descp = kmalloc_array(
-			MAX_DESC,
-			sizeof(struct sdma_desc),
-			GFP_ATOMIC);
-	if (!tx->descp)
+	descp = kmalloc_array(MAX_DESC, sizeof(struct sdma_desc), GFP_ATOMIC);
+	if (!descp)
 		goto enomem;
+	tx->descp = descp;
 
 	/* reserve last descriptor for coalescing */
 	tx->desc_limit = MAX_DESC - 1;
@@ -3202,7 +3203,6 @@
 {
 	int rval = 0;
 
-	tx->num_desc++;
 	if ((unlikely(tx->num_desc == tx->desc_limit))) {
 		rval = _extend_sdma_tx_descs(dd, tx);
 		if (rval) {
@@ -3216,6 +3216,7 @@
 		SDMA_MAP_NONE,
 		dd->sdma_pad_phys,
 		sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1)));
+	tx->num_desc++;
 	_sdma_close_tx(dd, tx);
 	return rval;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/sdma.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/sdma.h
@@ -672,14 +672,13 @@
 static inline void _sdma_close_tx(struct hfi1_devdata *dd,
 				  struct sdma_txreq *tx)
 {
-	tx->descp[tx->num_desc].qw[0] |=
-		SDMA_DESC0_LAST_DESC_FLAG;
-	tx->descp[tx->num_desc].qw[1] |=
-		dd->default_desc1;
+	u16 last_desc = tx->num_desc - 1;
+
+	tx->descp[last_desc].qw[0] |= SDMA_DESC0_LAST_DESC_FLAG;
+	tx->descp[last_desc].qw[1] |= dd->default_desc1;
 	if (tx->flags & SDMA_TXREQ_F_URGENT)
-		tx->descp[tx->num_desc].qw[1] |=
-			(SDMA_DESC1_HEAD_TO_HOST_FLAG |
-			 SDMA_DESC1_INT_REQ_FLAG);
+		tx->descp[last_desc].qw[1] |= (SDMA_DESC1_HEAD_TO_HOST_FLAG |
+					       SDMA_DESC1_INT_REQ_FLAG);
 }
 
 static inline int _sdma_txadd_daddr(
@@ -696,6 +695,7 @@
 		type,
 		addr, len);
 	WARN_ON(len > tx->tlen);
+	tx->num_desc++;
 	tx->tlen -= len;
 	/* special cases for last */
 	if (!tx->tlen) {
@@ -707,7 +707,6 @@
 			_sdma_close_tx(dd, tx);
 		}
 	}
-	tx->num_desc++;
 	return rval;
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/sysfs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/sysfs.c
@@ -674,7 +674,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);
 
@@ -684,7 +688,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);
 
@@ -694,7 +698,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);
 
@@ -704,7 +708,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);
@@ -742,7 +746,6 @@
 	kobject_put(&ppd->sl2sc_kobj);
 bail_sc2vl:
 	kobject_put(&ppd->sc2vl_kobj);
-bail:
 	return ret;
 }
 
@@ -853,8 +856,13 @@
 
 	return 0;
 bail:
-	for (i = 0; i < dd->num_sdma; i++)
-		kobject_del(&dd->per_sdma[i].kobj);
+	/*
+	 * The function kobject_put() will call kobject_del() if the kobject
+	 * has been added successfully. The sysfs files created under the
+	 * kobject directory will also be removed during the process.
+	 */
+	for (; i >= 0; i--)
+		kobject_put(&dd->per_sdma[i].kobj);
 
 	return ret;
 }
@@ -867,6 +875,10 @@
 	struct hfi1_pportdata *ppd;
 	int i;
 
+	/* Unwind operations in hfi1_verbs_register_sysfs() */
+	for (i = 0; i < dd->num_sdma; i++)
+		kobject_put(&dd->per_sdma[i].kobj);
+
 	for (i = 0; i < dd->num_pports; i++) {
 		ppd = &dd->pport[i];
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/tid_rdma.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/tid_rdma.c
@@ -3215,6 +3215,7 @@
 	case IB_WR_ATOMIC_CMP_AND_SWP:
 	case IB_WR_ATOMIC_FETCH_AND_ADD:
 	case IB_WR_RDMA_WRITE:
+	case IB_WR_RDMA_WRITE_WITH_IMM:
 		switch (prev->wr.opcode) {
 		case IB_WR_TID_RDMA_WRITE:
 			req = wqe_to_tid_req(prev);
@@ -4633,6 +4634,15 @@
 			 */
 			fpsn = full_flow_psn(flow, flow->flow_state.spsn);
 			req->r_ack_psn = psn;
+			/*
+			 * If resync_psn points to the last flow PSN for a
+			 * segment and the new segment (likely from a new
+			 * request) starts with a new generation number, we
+			 * need to adjust resync_psn accordingly.
+			 */
+			if (flow->flow_state.generation !=
+			    (resync_psn >> HFI1_KDETH_BTH_SEQ_SHIFT))
+				resync_psn = mask_psn(fpsn - 1);
 			flow->resync_npkts +=
 				delta_psn(mask_psn(resync_psn + 1), fpsn);
 			/*
@@ -5397,7 +5407,10 @@
 	struct hfi1_ibport *ibp =
 		to_iport(qp->ibqp.device, qp->port_num);
 	struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-	struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
+	struct hfi1_devdata *dd = ppd->dd;
+
+	if ((dd->flags & HFI1_SHUTDOWN))
+		return true;
 
 	return iowait_tid_schedule(&priv->s_iowait, ppd->hfi1_wq,
 				   priv->s_sde ?
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/user_exp_rcv.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/user_exp_rcv.c
@@ -90,9 +90,6 @@
 	struct hfi1_devdata *dd = uctxt->dd;
 	int ret = 0;
 
-	spin_lock_init(&fd->tid_lock);
-	spin_lock_init(&fd->invalid_lock);
-
 	fd->entry_to_rb = kcalloc(uctxt->expected_count,
 				  sizeof(struct rb_node *),
 				  GFP_KERNEL);
@@ -165,10 +162,12 @@
 	if (fd->handler) {
 		hfi1_mmu_rb_unregister(fd->handler);
 	} else {
+		mutex_lock(&uctxt->exp_mutex);
 		if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list))
 			unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd);
 		if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list))
 			unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd);
+		mutex_unlock(&uctxt->exp_mutex);
 	}
 
 	kfree(fd->invalid_tids);
@@ -216,16 +215,11 @@
 static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf)
 {
 	int pinned;
-	unsigned int npages;
+	unsigned int npages = tidbuf->npages;
 	unsigned long vaddr = tidbuf->vaddr;
 	struct page **pages = NULL;
 	struct hfi1_devdata *dd = fd->uctxt->dd;
 
-	/* Get the number of pages the user buffer spans */
-	npages = num_user_pages(vaddr, tidbuf->length);
-	if (!npages)
-		return -EINVAL;
-
 	if (npages > fd->uctxt->expected_count) {
 		dd_dev_err(dd, "Expected buffer too big\n");
 		return -EINVAL;
@@ -259,7 +253,6 @@
 		return pinned;
 	}
 	tidbuf->pages = pages;
-	tidbuf->npages = npages;
 	fd->tid_n_pinned += pinned;
 	return pinned;
 }
@@ -326,6 +319,8 @@
 
 	if (!PAGE_ALIGNED(tinfo->vaddr))
 		return -EINVAL;
+	if (tinfo->length == 0)
+		return -EINVAL;
 
 	tidbuf = kzalloc(sizeof(*tidbuf), GFP_KERNEL);
 	if (!tidbuf)
@@ -333,43 +328,42 @@
 
 	tidbuf->vaddr = tinfo->vaddr;
 	tidbuf->length = tinfo->length;
+	tidbuf->npages = num_user_pages(tidbuf->vaddr, tidbuf->length);
 	tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets),
 				GFP_KERNEL);
 	if (!tidbuf->psets) {
-		kfree(tidbuf);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail_release_mem;
 	}
 
 	pinned = pin_rcv_pages(fd, tidbuf);
 	if (pinned <= 0) {
-		kfree(tidbuf->psets);
-		kfree(tidbuf);
-		return pinned;
+		ret = (pinned < 0) ? pinned : -ENOSPC;
+		goto fail_unpin;
 	}
 
 	/* Find sets of physically contiguous pages */
 	tidbuf->n_psets = find_phys_blocks(tidbuf, pinned);
 
-	/*
-	 * We don't need to access this under a lock since tid_used is per
-	 * process and the same process cannot be in hfi1_user_exp_rcv_clear()
-	 * and hfi1_user_exp_rcv_setup() at the same time.
-	 */
+	/* Reserve the number of expected tids to be used. */
 	spin_lock(&fd->tid_lock);
 	if (fd->tid_used + tidbuf->n_psets > fd->tid_limit)
 		pageset_count = fd->tid_limit - fd->tid_used;
 	else
 		pageset_count = tidbuf->n_psets;
+	fd->tid_used += pageset_count;
 	spin_unlock(&fd->tid_lock);
 
-	if (!pageset_count)
-		goto bail;
+	if (!pageset_count) {
+		ret = -ENOSPC;
+		goto fail_unreserve;
+	}
 
 	ngroups = pageset_count / dd->rcv_entries.group_size;
 	tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL);
 	if (!tidlist) {
 		ret = -ENOMEM;
-		goto nomem;
+		goto fail_unreserve;
 	}
 
 	tididx = 0;
@@ -465,43 +459,60 @@
 	}
 unlock:
 	mutex_unlock(&uctxt->exp_mutex);
-nomem:
 	hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx,
 		  mapped_pages, ret);
-	if (tididx) {
-		spin_lock(&fd->tid_lock);
-		fd->tid_used += tididx;
-		spin_unlock(&fd->tid_lock);
-		tinfo->tidcnt = tididx;
-		tinfo->length = mapped_pages * PAGE_SIZE;
-
-		if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
-				 tidlist, sizeof(tidlist[0]) * tididx)) {
-			/*
-			 * On failure to copy to the user level, we need to undo
-			 * everything done so far so we don't leak resources.
-			 */
-			tinfo->tidlist = (unsigned long)&tidlist;
-			hfi1_user_exp_rcv_clear(fd, tinfo);
-			tinfo->tidlist = 0;
-			ret = -EFAULT;
-			goto bail;
-		}
+
+	/* fail if nothing was programmed, set error if none provided */
+	if (tididx == 0) {
+		if (ret >= 0)
+			ret = -ENOSPC;
+		goto fail_unreserve;
 	}
 
-	/*
-	 * If not everything was mapped (due to insufficient RcvArray entries,
-	 * for example), unpin all unmapped pages so we can pin them nex time.
-	 */
-	if (mapped_pages != pinned)
-		unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages,
-				(pinned - mapped_pages), false);
-bail:
+	/* adjust reserved tid_used to actual count */
+	spin_lock(&fd->tid_lock);
+	fd->tid_used -= pageset_count - tididx;
+	spin_unlock(&fd->tid_lock);
+
+	/* unpin all pages not covered by a TID */
+	unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages,
+			false);
+
+	tinfo->tidcnt = tididx;
+	tinfo->length = mapped_pages * PAGE_SIZE;
+
+	if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
+			 tidlist, sizeof(tidlist[0]) * tididx)) {
+		ret = -EFAULT;
+		goto fail_unprogram;
+	}
+
+	kfree(tidbuf->pages);
 	kfree(tidbuf->psets);
+	kfree(tidbuf);
 	kfree(tidlist);
+	return 0;
+
+fail_unprogram:
+	/* unprogram, unmap, and unpin all allocated TIDs */
+	tinfo->tidlist = (unsigned long)tidlist;
+	hfi1_user_exp_rcv_clear(fd, tinfo);
+	tinfo->tidlist = 0;
+	pinned = 0;		/* nothing left to unpin */
+	pageset_count = 0;	/* nothing left reserved */
+fail_unreserve:
+	spin_lock(&fd->tid_lock);
+	fd->tid_used -= pageset_count;
+	spin_unlock(&fd->tid_lock);
+fail_unpin:
+	if (pinned > 0)
+		unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false);
+fail_release_mem:
 	kfree(tidbuf->pages);
+	kfree(tidbuf->psets);
 	kfree(tidbuf);
-	return ret > 0 ? 0 : ret;
+	kfree(tidlist);
+	return ret;
 }
 
 int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/user_sdma.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -141,6 +141,7 @@
 	 */
 	xchg(&pq->state, SDMA_PKT_Q_DEFERRED);
 	if (list_empty(&pq->busy.list)) {
+		pq->busy.lock = &sde->waitlock;
 		iowait_get_priority(&pq->busy);
 		iowait_queue(pkts_sent, &pq->busy, &sde->dmawait);
 	}
@@ -155,6 +156,7 @@
 {
 	struct hfi1_user_sdma_pkt_q *pq =
 		container_of(wait, struct hfi1_user_sdma_pkt_q, busy);
+	pq->busy.lock = NULL;
 	xchg(&pq->state, SDMA_PKT_Q_ACTIVE);
 	wake_up(&wait->wait_dma);
 };
@@ -179,7 +181,6 @@
 	pq = kzalloc(sizeof(*pq), GFP_KERNEL);
 	if (!pq)
 		return -ENOMEM;
-
 	pq->dd = dd;
 	pq->ctxt = uctxt->ctxt;
 	pq->subctxt = fd->subctxt;
@@ -236,7 +237,7 @@
 		goto pq_mmu_fail;
 	}
 
-	fd->pq = pq;
+	rcu_assign_pointer(fd->pq, pq);
 	fd->cq = cq;
 
 	return 0;
@@ -257,6 +258,21 @@
 	return ret;
 }
 
+static void flush_pq_iowait(struct hfi1_user_sdma_pkt_q *pq)
+{
+	unsigned long flags;
+	seqlock_t *lock = pq->busy.lock;
+
+	if (!lock)
+		return;
+	write_seqlock_irqsave(lock, flags);
+	if (!list_empty(&pq->busy.list)) {
+		list_del_init(&pq->busy.list);
+		pq->busy.lock = NULL;
+	}
+	write_sequnlock_irqrestore(lock, flags);
+}
+
 int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
 			       struct hfi1_ctxtdata *uctxt)
 {
@@ -264,8 +280,14 @@
 
 	trace_hfi1_sdma_user_free_queues(uctxt->dd, uctxt->ctxt, fd->subctxt);
 
-	pq = fd->pq;
+	spin_lock(&fd->pq_rcu_lock);
+	pq = srcu_dereference_check(fd->pq, &fd->pq_srcu,
+				    lockdep_is_held(&fd->pq_rcu_lock));
 	if (pq) {
+		rcu_assign_pointer(fd->pq, NULL);
+		spin_unlock(&fd->pq_rcu_lock);
+		synchronize_srcu(&fd->pq_srcu);
+		/* at this point there can be no more new requests */
 		if (pq->handler)
 			hfi1_mmu_rb_unregister(pq->handler);
 		iowait_sdma_drain(&pq->busy);
@@ -276,8 +298,10 @@
 		kfree(pq->reqs);
 		kfree(pq->req_in_use);
 		kmem_cache_destroy(pq->txreq_cache);
+		flush_pq_iowait(pq);
 		kfree(pq);
-		fd->pq = NULL;
+	} else {
+		spin_unlock(&fd->pq_rcu_lock);
 	}
 	if (fd->cq) {
 		vfree(fd->cq->comps);
@@ -321,7 +345,8 @@
 {
 	int ret = 0, i;
 	struct hfi1_ctxtdata *uctxt = fd->uctxt;
-	struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+	struct hfi1_user_sdma_pkt_q *pq =
+		srcu_dereference(fd->pq, &fd->pq_srcu);
 	struct hfi1_user_sdma_comp_q *cq = fd->cq;
 	struct hfi1_devdata *dd = pq->dd;
 	unsigned long idx = 0;
@@ -564,10 +589,6 @@
 
 	set_comp_state(pq, cq, info.comp_idx, QUEUED, 0);
 	pq->state = SDMA_PKT_Q_ACTIVE;
-	/* Send the first N packets in the request to buy us some time */
-	ret = user_sdma_send_pkts(req, pcount);
-	if (unlikely(ret < 0 && ret != -EBUSY))
-		goto free_req;
 
 	/*
 	 * This is a somewhat blocking send implementation.
@@ -580,11 +601,12 @@
 		if (ret < 0) {
 			if (ret != -EBUSY)
 				goto free_req;
-			wait_event_interruptible_timeout(
+			if (wait_event_interruptible_timeout(
 				pq->busy.wait_dma,
-				(pq->state == SDMA_PKT_Q_ACTIVE),
+				pq->state == SDMA_PKT_Q_ACTIVE,
 				msecs_to_jiffies(
-					SDMA_IOWAIT_TIMEOUT));
+					SDMA_IOWAIT_TIMEOUT)) <= 0)
+				flush_pq_iowait(pq);
 		}
 	}
 	*count += idx;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hfi1/verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hfi1/verbs.c
@@ -515,10 +515,11 @@
 				       opa_get_lid(packet->dlid, 9B));
 		if (!mcast)
 			goto drop;
+		rcu_read_lock();
 		list_for_each_entry_rcu(p, &mcast->qp_list, list) {
 			packet->qp = p->qp;
 			if (hfi1_do_pkey_check(packet))
-				goto drop;
+				goto unlock_drop;
 			spin_lock_irqsave(&packet->qp->r_lock, flags);
 			packet_handler = qp_ok(packet);
 			if (likely(packet_handler))
@@ -527,6 +528,7 @@
 				ibp->rvp.n_pkt_drops++;
 			spin_unlock_irqrestore(&packet->qp->r_lock, flags);
 		}
+		rcu_read_unlock();
 		/*
 		 * Notify rvt_multicast_detach() if it is waiting for us
 		 * to finish.
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/Kconfig
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/Kconfig
@@ -1,23 +1,34 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config INFINIBAND_HNS
-	bool "HNS RoCE Driver"
+	tristate "HNS RoCE Driver"
 	depends on NET_VENDOR_HISILICON
 	depends on ARM64 || (COMPILE_TEST && 64BIT)
+	depends on (HNS_DSAF && HNS_ENET) || HNS3
 	---help---
 	  This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine
 	  is used in Hisilicon Hip06 and more further ICT SoC based on
 	  platform device.
 
+	  To compile HIP06 or HIP08 driver as module, choose M here.
+
 config INFINIBAND_HNS_HIP06
-	tristate "Hisilicon Hip06 Family RoCE support"
+	bool "Hisilicon Hip06 Family RoCE support"
 	depends on INFINIBAND_HNS && HNS && HNS_DSAF && HNS_ENET
+	depends on INFINIBAND_HNS=m || (HNS_DSAF=y && HNS_ENET=y)
 	---help---
 	  RoCE driver support for Hisilicon RoCE engine in Hisilicon Hip06 and
 	  Hip07 SoC. These RoCE engines are platform devices.
 
+	  To compile this driver, choose Y here: if INFINIBAND_HNS is m, this
+	  module will be called hns-roce-hw-v1
+
 config INFINIBAND_HNS_HIP08
-	tristate "Hisilicon Hip08 Family RoCE support"
+	bool "Hisilicon Hip08 Family RoCE support"
 	depends on INFINIBAND_HNS && PCI && HNS3
+	depends on INFINIBAND_HNS=m || HNS3=y
 	---help---
 	  RoCE driver support for Hisilicon RoCE engine in Hisilicon Hip08 SoC.
 	  The RoCE engine is a PCI device.
+
+	  To compile this driver, choose Y here: if INFINIBAND_HNS is m, this
+	  module will be called hns-roce-hw-v2.
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/Makefile
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/Makefile
@@ -9,8 +9,12 @@
 	hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
 	hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o
 
+ifdef CONFIG_INFINIBAND_HNS_HIP06
 hns-roce-hw-v1-objs := hns_roce_hw_v1.o $(hns-roce-objs)
-obj-$(CONFIG_INFINIBAND_HNS_HIP06) += hns-roce-hw-v1.o
+obj-$(CONFIG_INFINIBAND_HNS) += hns-roce-hw-v1.o
+endif
 
+ifdef CONFIG_INFINIBAND_HNS_HIP08
 hns-roce-hw-v2-objs := hns_roce_hw_v2.o hns_roce_hw_v2_dfx.o $(hns-roce-objs)
-obj-$(CONFIG_INFINIBAND_HNS_HIP08) += hns-roce-hw-v2.o
+obj-$(CONFIG_INFINIBAND_HNS) += hns-roce-hw-v2.o
+endif
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_ah.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_ah.c
@@ -46,32 +46,32 @@
 	const struct ib_gid_attr *gid_attr;
 	struct device *dev = hr_dev->dev;
 	struct hns_roce_ah *ah = to_hr_ah(ibah);
-	u16 vlan_tag = 0xffff;
 	const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
+	u16 vlan_id = 0xffff;
 	bool vlan_en = false;
 	int ret;
 
 	gid_attr = ah_attr->grh.sgid_attr;
-	ret = rdma_read_gid_l2_fields(gid_attr, &vlan_tag, NULL);
+	ret = rdma_read_gid_l2_fields(gid_attr, &vlan_id, NULL);
 	if (ret)
 		return ret;
 
 	/* Get mac address */
 	memcpy(ah->av.mac, ah_attr->roce.dmac, ETH_ALEN);
 
-	if (vlan_tag < VLAN_CFI_MASK) {
+	if (vlan_id < VLAN_N_VID) {
 		vlan_en = true;
-		vlan_tag |= (rdma_ah_get_sl(ah_attr) &
+		vlan_id |= (rdma_ah_get_sl(ah_attr) &
 			     HNS_ROCE_VLAN_SL_BIT_MASK) <<
 			     HNS_ROCE_VLAN_SL_SHIFT;
 	}
 
 	ah->av.port = rdma_ah_get_port_num(ah_attr);
 	ah->av.gid_index = grh->sgid_index;
-	ah->av.vlan = vlan_tag;
+	ah->av.vlan_id = vlan_id;
 	ah->av.vlan_en = vlan_en;
-	dev_dbg(dev, "gid_index = 0x%x,vlan = 0x%x\n", ah->av.gid_index,
-		ah->av.vlan);
+	dev_dbg(dev, "gid_index = 0x%x,vlan_id = 0x%x\n", ah->av.gid_index,
+		ah->av.vlan_id);
 
 	if (rdma_ah_get_static_rate(ah_attr))
 		ah->av.stat_rate = IB_RATE_10_GBPS;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_alloc.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_alloc.c
@@ -55,7 +55,7 @@
 			bitmap->last = 0;
 		*obj |= bitmap->top;
 	} else {
-		ret = -1;
+		ret = -EINVAL;
 	}
 
 	spin_unlock(&bitmap->lock);
@@ -100,7 +100,7 @@
 		}
 		*obj |= bitmap->top;
 	} else {
-		ret = -1;
+		ret = -EINVAL;
 	}
 
 	spin_unlock(&bitmap->lock);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_cmd.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_cmd.h
@@ -115,12 +115,12 @@
 
 enum {
 	/* TPT commands */
-	HNS_ROCE_CMD_SW2HW_MPT		= 0xd,
-	HNS_ROCE_CMD_HW2SW_MPT		= 0xf,
+	HNS_ROCE_CMD_CREATE_MPT		= 0xd,
+	HNS_ROCE_CMD_DESTROY_MPT	= 0xf,
 
 	/* CQ commands */
-	HNS_ROCE_CMD_SW2HW_CQ		= 0x16,
-	HNS_ROCE_CMD_HW2SW_CQ		= 0x17,
+	HNS_ROCE_CMD_CREATE_CQC		= 0x16,
+	HNS_ROCE_CMD_DESTROY_CQC	= 0x17,
 
 	/* QP/EE commands */
 	HNS_ROCE_CMD_RST2INIT_QP	= 0x19,
@@ -129,14 +129,14 @@
 	HNS_ROCE_CMD_RTS2RTS_QP		= 0x1c,
 	HNS_ROCE_CMD_2ERR_QP		= 0x1e,
 	HNS_ROCE_CMD_RTS2SQD_QP		= 0x1f,
-	HNS_ROCE_CMD_SQD2SQD_QP		= 0x38,
 	HNS_ROCE_CMD_SQD2RTS_QP		= 0x20,
 	HNS_ROCE_CMD_2RST_QP		= 0x21,
 	HNS_ROCE_CMD_QUERY_QP		= 0x22,
-	HNS_ROCE_CMD_SW2HW_SRQ		= 0x70,
+	HNS_ROCE_CMD_SQD2SQD_QP		= 0x38,
+	HNS_ROCE_CMD_CREATE_SRQ		= 0x70,
 	HNS_ROCE_CMD_MODIFY_SRQC	= 0x72,
 	HNS_ROCE_CMD_QUERY_SRQC		= 0x73,
-	HNS_ROCE_CMD_HW2SW_SRQ		= 0x74,
+	HNS_ROCE_CMD_DESTROY_SRQ	= 0x74,
 };
 
 int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -39,51 +39,8 @@
 #include <rdma/hns-abi.h>
 #include "hns_roce_common.h"
 
-static void hns_roce_ib_cq_comp(struct hns_roce_cq *hr_cq)
-{
-	struct ib_cq *ibcq = &hr_cq->ib_cq;
-
-	ibcq->comp_handler(ibcq, ibcq->cq_context);
-}
-
-static void hns_roce_ib_cq_event(struct hns_roce_cq *hr_cq,
-				 enum hns_roce_event event_type)
-{
-	struct hns_roce_dev *hr_dev;
-	struct ib_event event;
-	struct ib_cq *ibcq;
-
-	ibcq = &hr_cq->ib_cq;
-	hr_dev = to_hr_dev(ibcq->device);
-
-	if (event_type != HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID &&
-	    event_type != HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR &&
-	    event_type != HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW) {
-		dev_err(hr_dev->dev,
-			"hns_roce_ib: Unexpected event type 0x%x on CQ %06lx\n",
-			event_type, hr_cq->cqn);
-		return;
-	}
-
-	if (ibcq->event_handler) {
-		event.device = ibcq->device;
-		event.event = IB_EVENT_CQ_ERR;
-		event.element.cq = ibcq;
-		ibcq->event_handler(&event, ibcq->cq_context);
-	}
-}
-
-static int hns_roce_sw2hw_cq(struct hns_roce_dev *dev,
-			     struct hns_roce_cmd_mailbox *mailbox,
-			     unsigned long cq_num)
-{
-	return hns_roce_cmd_mbox(dev, mailbox->dma, 0, cq_num, 0,
-			    HNS_ROCE_CMD_SW2HW_CQ, HNS_ROCE_CMD_TIMEOUT_MSECS);
-}
-
-static int hns_roce_cq_alloc(struct hns_roce_dev *hr_dev, int nent,
-			     struct hns_roce_mtt *hr_mtt,
-			     struct hns_roce_cq *hr_cq, int vector)
+static int hns_roce_alloc_cqc(struct hns_roce_dev *hr_dev,
+			      struct hns_roce_cq *hr_cq)
 {
 	struct hns_roce_cmd_mailbox *mailbox;
 	struct hns_roce_hem_table *mtt_table;
@@ -101,35 +58,32 @@
 	else
 		mtt_table = &hr_dev->mr_table.mtt_table;
 
-	mtts = hns_roce_table_find(hr_dev, mtt_table,
-				   hr_mtt->first_seg, &dma_handle);
-	if (!mtts) {
-		dev_err(dev, "CQ alloc.Failed to find cq buf addr.\n");
-		return -EINVAL;
-	}
+	mtts = hns_roce_table_find(hr_dev, mtt_table, hr_cq->mtt.first_seg,
+				   &dma_handle);
 
-	if (vector >= hr_dev->caps.num_comp_vectors) {
-		dev_err(dev, "CQ alloc.Invalid vector.\n");
+	if (!mtts) {
+		dev_err(dev, "Failed to find mtt for CQ buf.\n");
 		return -EINVAL;
 	}
-	hr_cq->vector = vector;
 
 	ret = hns_roce_bitmap_alloc(&cq_table->bitmap, &hr_cq->cqn);
-	if (ret == -1) {
-		dev_err(dev, "CQ alloc.Failed to alloc index.\n");
-		return -ENOMEM;
+	if (ret) {
+		dev_err(dev, "Num of CQ out of range.\n");
+		return ret;
 	}
 
 	/* Get CQC memory HEM(Hardware Entry Memory) table */
 	ret = hns_roce_table_get(hr_dev, &cq_table->table, hr_cq->cqn);
 	if (ret) {
-		dev_err(dev, "CQ alloc.Failed to get context mem.\n");
+		dev_err(dev,
+			"Get context mem failed(%d) when CQ(0x%lx) alloc.\n",
+			ret, hr_cq->cqn);
 		goto err_out;
 	}
 
 	ret = xa_err(xa_store(&cq_table->array, hr_cq->cqn, hr_cq, GFP_KERNEL));
 	if (ret) {
-		dev_err(dev, "CQ alloc failed xa_store.\n");
+		dev_err(dev, "Failed to xa_store CQ.\n");
 		goto err_put;
 	}
 
@@ -140,14 +94,16 @@
 		goto err_xa;
 	}
 
-	hr_dev->hw->write_cqc(hr_dev, hr_cq, mailbox->buf, mtts, dma_handle,
-			      nent, vector);
+	hr_dev->hw->write_cqc(hr_dev, hr_cq, mailbox->buf, mtts, dma_handle);
 
 	/* Send mailbox to hw */
-	ret = hns_roce_sw2hw_cq(hr_dev, mailbox, hr_cq->cqn);
+	ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, hr_cq->cqn, 0,
+			HNS_ROCE_CMD_CREATE_CQC, HNS_ROCE_CMD_TIMEOUT_MSECS);
 	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
 	if (ret) {
-		dev_err(dev, "CQ alloc.Failed to cmd mailbox.\n");
+		dev_err(dev,
+			"Send cmd mailbox failed(%d) when CQ(0x%lx) alloc.\n",
+			ret, hr_cq->cqn);
 		goto err_xa;
 	}
 
@@ -170,24 +126,17 @@
 	return ret;
 }
 
-static int hns_roce_hw2sw_cq(struct hns_roce_dev *dev,
-			     struct hns_roce_cmd_mailbox *mailbox,
-			     unsigned long cq_num)
-{
-	return hns_roce_cmd_mbox(dev, 0, mailbox ? mailbox->dma : 0, cq_num,
-				 mailbox ? 0 : 1, HNS_ROCE_CMD_HW2SW_CQ,
-				 HNS_ROCE_CMD_TIMEOUT_MSECS);
-}
-
-void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
+void hns_roce_free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
 {
 	struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
 	struct device *dev = hr_dev->dev;
 	int ret;
 
-	ret = hns_roce_hw2sw_cq(hr_dev, NULL, hr_cq->cqn);
+	ret = hns_roce_cmd_mbox(hr_dev, 0, 0, hr_cq->cqn, 1,
+				HNS_ROCE_CMD_DESTROY_CQC,
+				HNS_ROCE_CMD_TIMEOUT_MSECS);
 	if (ret)
-		dev_err(dev, "HW2SW_CQ failed (%d) for CQN %06lx\n", ret,
+		dev_err(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", ret,
 			hr_cq->cqn);
 
 	xa_erase(&cq_table->array, hr_cq->cqn);
@@ -204,103 +153,91 @@
 	hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn, BITMAP_NO_RR);
 }
 
-static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev,
-				   struct ib_udata *udata,
-				   struct hns_roce_cq_buf *buf,
-				   struct ib_umem **umem, u64 buf_addr, int cqe)
-{
-	int ret;
-	u32 page_shift;
+static int get_cq_umem(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq,
+		       struct hns_roce_ib_create_cq ucmd,
+		       struct ib_udata *udata)
+{
+	struct hns_roce_buf *buf = &hr_cq->buf;
+	struct hns_roce_mtt *mtt = &hr_cq->mtt;
+	struct ib_umem **umem = &hr_cq->umem;
 	u32 npages;
+	int ret;
 
-	*umem = ib_umem_get(udata, buf_addr, cqe * hr_dev->caps.cq_entry_sz,
-			    IB_ACCESS_LOCAL_WRITE, 1);
+	*umem = ib_umem_get(&hr_dev->ib_dev, ucmd.buf_addr, buf->size,
+			    IB_ACCESS_LOCAL_WRITE);
 	if (IS_ERR(*umem))
 		return PTR_ERR(*umem);
 
 	if (hns_roce_check_whether_mhop(hr_dev, HEM_TYPE_CQE))
-		buf->hr_mtt.mtt_type = MTT_TYPE_CQE;
+		mtt->mtt_type = MTT_TYPE_CQE;
 	else
-		buf->hr_mtt.mtt_type = MTT_TYPE_WQE;
+		mtt->mtt_type = MTT_TYPE_WQE;
 
-	if (hr_dev->caps.cqe_buf_pg_sz) {
-		npages = (ib_umem_page_count(*umem) +
-			(1 << hr_dev->caps.cqe_buf_pg_sz) - 1) /
-			(1 << hr_dev->caps.cqe_buf_pg_sz);
-		page_shift = PAGE_SHIFT + hr_dev->caps.cqe_buf_pg_sz;
-		ret = hns_roce_mtt_init(hr_dev, npages, page_shift,
-					&buf->hr_mtt);
-	} else {
-		ret = hns_roce_mtt_init(hr_dev, ib_umem_page_count(*umem),
-					PAGE_SHIFT, &buf->hr_mtt);
-	}
+	npages = DIV_ROUND_UP(ib_umem_page_count(*umem),
+			      1 << hr_dev->caps.cqe_buf_pg_sz);
+	ret = hns_roce_mtt_init(hr_dev, npages, buf->page_shift, mtt);
 	if (ret)
 		goto err_buf;
 
-	ret = hns_roce_ib_umem_write_mtt(hr_dev, &buf->hr_mtt, *umem);
+	ret = hns_roce_ib_umem_write_mtt(hr_dev, mtt, *umem);
 	if (ret)
 		goto err_mtt;
 
 	return 0;
 
 err_mtt:
-	hns_roce_mtt_cleanup(hr_dev, &buf->hr_mtt);
+	hns_roce_mtt_cleanup(hr_dev, mtt);
 
 err_buf:
 	ib_umem_release(*umem);
 	return ret;
 }
 
-static int hns_roce_ib_alloc_cq_buf(struct hns_roce_dev *hr_dev,
-				    struct hns_roce_cq_buf *buf, u32 nent)
+static int alloc_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
 {
+	struct hns_roce_buf *buf = &hr_cq->buf;
+	struct hns_roce_mtt *mtt = &hr_cq->mtt;
 	int ret;
-	u32 page_shift = PAGE_SHIFT + hr_dev->caps.cqe_buf_pg_sz;
 
-	ret = hns_roce_buf_alloc(hr_dev, nent * hr_dev->caps.cq_entry_sz,
-				 (1 << page_shift) * 2, &buf->hr_buf,
-				 page_shift);
+	ret = hns_roce_buf_alloc(hr_dev, buf->size, (1 << buf->page_shift) * 2,
+				 buf, buf->page_shift);
 	if (ret)
 		goto out;
 
 	if (hns_roce_check_whether_mhop(hr_dev, HEM_TYPE_CQE))
-		buf->hr_mtt.mtt_type = MTT_TYPE_CQE;
+		mtt->mtt_type = MTT_TYPE_CQE;
 	else
-		buf->hr_mtt.mtt_type = MTT_TYPE_WQE;
+		mtt->mtt_type = MTT_TYPE_WQE;
 
-	ret = hns_roce_mtt_init(hr_dev, buf->hr_buf.npages,
-				buf->hr_buf.page_shift, &buf->hr_mtt);
+	ret = hns_roce_mtt_init(hr_dev, buf->npages, buf->page_shift, mtt);
 	if (ret)
 		goto err_buf;
 
-	ret = hns_roce_buf_write_mtt(hr_dev, &buf->hr_mtt, &buf->hr_buf);
+	ret = hns_roce_buf_write_mtt(hr_dev, mtt, buf);
 	if (ret)
 		goto err_mtt;
 
 	return 0;
 
 err_mtt:
-	hns_roce_mtt_cleanup(hr_dev, &buf->hr_mtt);
+	hns_roce_mtt_cleanup(hr_dev, mtt);
 
 err_buf:
-	hns_roce_buf_free(hr_dev, nent * hr_dev->caps.cq_entry_sz,
-			  &buf->hr_buf);
+	hns_roce_buf_free(hr_dev, buf->size, buf);
+
 out:
 	return ret;
 }
 
-static void hns_roce_ib_free_cq_buf(struct hns_roce_dev *hr_dev,
-				    struct hns_roce_cq_buf *buf, int cqe)
+static void free_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
 {
-	hns_roce_buf_free(hr_dev, (cqe + 1) * hr_dev->caps.cq_entry_sz,
-			  &buf->hr_buf);
+	hns_roce_buf_free(hr_dev, hr_cq->buf.size, &hr_cq->buf);
 }
 
 static int create_user_cq(struct hns_roce_dev *hr_dev,
 			  struct hns_roce_cq *hr_cq,
 			  struct ib_udata *udata,
-			  struct hns_roce_ib_create_cq_resp *resp,
-			  int cq_entries)
+			  struct hns_roce_ib_create_cq_resp *resp)
 {
 	struct hns_roce_ib_create_cq ucmd;
 	struct device *dev = hr_dev->dev;
@@ -314,9 +251,7 @@
 	}
 
 	/* Get user space address, write it into mtt table */
-	ret = hns_roce_ib_get_cq_umem(hr_dev, udata, &hr_cq->hr_buf,
-				      &hr_cq->umem, ucmd.buf_addr,
-				      cq_entries);
+	ret = get_cq_umem(hr_dev, hr_cq, ucmd, udata);
 	if (ret) {
 		dev_err(dev, "Failed to get_cq_umem.\n");
 		return ret;
@@ -337,17 +272,16 @@
 	return 0;
 
 err_mtt:
-	hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+	hns_roce_mtt_cleanup(hr_dev, &hr_cq->mtt);
 	ib_umem_release(hr_cq->umem);
 
 	return ret;
 }
 
 static int create_kernel_cq(struct hns_roce_dev *hr_dev,
-			    struct hns_roce_cq *hr_cq, int cq_entries)
+			    struct hns_roce_cq *hr_cq)
 {
 	struct device *dev = hr_dev->dev;
-	struct hns_roce_uar *uar;
 	int ret;
 
 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) {
@@ -361,15 +295,14 @@
 	}
 
 	/* Init mtt table and write buff address to mtt table */
-	ret = hns_roce_ib_alloc_cq_buf(hr_dev, &hr_cq->hr_buf, cq_entries);
+	ret = alloc_cq_buf(hr_dev, hr_cq);
 	if (ret) {
 		dev_err(dev, "Failed to alloc_cq_buf.\n");
 		goto err_db;
 	}
 
-	uar = &hr_dev->priv_uar;
 	hr_cq->cq_db_l = hr_dev->reg_base + hr_dev->odb_offset +
-			 DB_REG_OFFSET * uar->index;
+			 DB_REG_OFFSET * hr_dev->priv_uar.index;
 
 	return 0;
 
@@ -392,64 +325,71 @@
 	    (udata->outlen >= sizeof(*resp)))
 		hns_roce_db_unmap_user(context, &hr_cq->db);
 
-	hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+	hns_roce_mtt_cleanup(hr_dev, &hr_cq->mtt);
 	ib_umem_release(hr_cq->umem);
 }
 
 static void destroy_kernel_cq(struct hns_roce_dev *hr_dev,
 			      struct hns_roce_cq *hr_cq)
 {
-	hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
-	hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, hr_cq->ib_cq.cqe);
+	hns_roce_mtt_cleanup(hr_dev, &hr_cq->mtt);
+	free_cq_buf(hr_dev, hr_cq);
 
 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB)
 		hns_roce_free_db(hr_dev, &hr_cq->db);
 }
 
-int hns_roce_ib_create_cq(struct ib_cq *ib_cq,
-			  const struct ib_cq_init_attr *attr,
-			  struct ib_udata *udata)
+int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
+		       struct ib_udata *udata)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
-	struct device *dev = hr_dev->dev;
 	struct hns_roce_ib_create_cq_resp resp = {};
 	struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);
+	struct device *dev = hr_dev->dev;
 	int vector = attr->comp_vector;
-	int cq_entries = attr->cqe;
+	u32 cq_entries = attr->cqe;
 	int ret;
 
 	if (cq_entries < 1 || cq_entries > hr_dev->caps.max_cqes) {
-		dev_err(dev, "Creat CQ failed. entries=%d, max=%d\n",
+		dev_err(dev, "Create CQ failed. entries=%d, max=%d\n",
 			cq_entries, hr_dev->caps.max_cqes);
 		return -EINVAL;
 	}
 
-	if (hr_dev->caps.min_cqes)
-		cq_entries = max(cq_entries, hr_dev->caps.min_cqes);
+	if (vector >= hr_dev->caps.num_comp_vectors) {
+		dev_err(dev, "Create CQ failed, vector=%d, max=%d\n",
+			vector, hr_dev->caps.num_comp_vectors);
+		return -EINVAL;
+	}
 
-	cq_entries = roundup_pow_of_two((unsigned int)cq_entries);
-	hr_cq->ib_cq.cqe = cq_entries - 1;
+	cq_entries = max(cq_entries, hr_dev->caps.min_cqes);
+	cq_entries = roundup_pow_of_two(cq_entries);
+	hr_cq->ib_cq.cqe = cq_entries - 1; /* used as cqe index */
+	hr_cq->cq_depth = cq_entries;
+	hr_cq->vector = vector;
+	hr_cq->buf.size = hr_cq->cq_depth * hr_dev->caps.cq_entry_sz;
+	hr_cq->buf.page_shift = PAGE_SHIFT + hr_dev->caps.cqe_buf_pg_sz;
 	spin_lock_init(&hr_cq->lock);
+	INIT_LIST_HEAD(&hr_cq->sq_list);
+	INIT_LIST_HEAD(&hr_cq->rq_list);
 
 	if (udata) {
-		ret = create_user_cq(hr_dev, hr_cq, udata, &resp, cq_entries);
+		ret = create_user_cq(hr_dev, hr_cq, udata, &resp);
 		if (ret) {
 			dev_err(dev, "Create cq failed in user mode!\n");
 			goto err_cq;
 		}
 	} else {
-		ret = create_kernel_cq(hr_dev, hr_cq, cq_entries);
+		ret = create_kernel_cq(hr_dev, hr_cq);
 		if (ret) {
 			dev_err(dev, "Create cq failed in kernel mode!\n");
 			goto err_cq;
 		}
 	}
 
-	/* Allocate cq index, fill cq_context */
-	ret = hns_roce_cq_alloc(hr_dev, cq_entries, &hr_cq->hr_buf.hr_mtt,
-				hr_cq, vector);
+	ret = hns_roce_alloc_cqc(hr_dev, hr_cq);
 	if (ret) {
-		dev_err(dev, "Creat CQ .Failed to cq_alloc.\n");
+		dev_err(dev, "Alloc CQ failed(%d).\n", ret);
 		goto err_dbmap;
 	}
 
@@ -462,11 +402,6 @@
 	if (!udata && hr_cq->tptr_addr)
 		*hr_cq->tptr_addr = 0;
 
-	/* Get created cq handler and carry out event */
-	hr_cq->comp = hns_roce_ib_cq_comp;
-	hr_cq->event = hns_roce_ib_cq_event;
-	hr_cq->cq_depth = cq_entries;
-
 	if (udata) {
 		resp.cqn = hr_cq->cqn;
 		ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -477,7 +412,7 @@
 	return 0;
 
 err_cqc:
-	hns_roce_free_cq(hr_dev, hr_cq);
+	hns_roce_free_cqc(hr_dev, hr_cq);
 
 err_dbmap:
 	if (udata)
@@ -489,7 +424,7 @@
 	return ret;
 }
 
-void hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+void hns_roce_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
 	struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);
@@ -499,8 +434,8 @@
 		return;
 	}
 
-	hns_roce_free_cq(hr_dev, hr_cq);
-	hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+	hns_roce_free_cqc(hr_dev, hr_cq);
+	hns_roce_mtt_cleanup(hr_dev, &hr_cq->mtt);
 
 	ib_umem_release(hr_cq->umem);
 	if (udata) {
@@ -512,7 +447,7 @@
 					       &hr_cq->db);
 	} else {
 		/* Free the buff of stored cq */
-		hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, ib_cq->cqe);
+		free_cq_buf(hr_dev, hr_cq);
 		if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB)
 			hns_roce_free_db(hr_dev, &hr_cq->db);
 	}
@@ -520,38 +455,57 @@
 
 void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn)
 {
-	struct device *dev = hr_dev->dev;
-	struct hns_roce_cq *cq;
+	struct hns_roce_cq *hr_cq;
+	struct ib_cq *ibcq;
 
-	cq = xa_load(&hr_dev->cq_table.array, cqn & (hr_dev->caps.num_cqs - 1));
-	if (!cq) {
-		dev_warn(dev, "Completion event for bogus CQ 0x%08x\n", cqn);
+	hr_cq = xa_load(&hr_dev->cq_table.array,
+			cqn & (hr_dev->caps.num_cqs - 1));
+	if (!hr_cq) {
+		dev_warn(hr_dev->dev, "Completion event for bogus CQ 0x%06x\n",
+			 cqn);
 		return;
 	}
 
-	++cq->arm_sn;
-	cq->comp(cq);
+	++hr_cq->arm_sn;
+	ibcq = &hr_cq->ib_cq;
+	if (ibcq->comp_handler)
+		ibcq->comp_handler(ibcq, ibcq->cq_context);
 }
 
 void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
 {
-	struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
 	struct device *dev = hr_dev->dev;
-	struct hns_roce_cq *cq;
+	struct hns_roce_cq *hr_cq;
+	struct ib_event event;
+	struct ib_cq *ibcq;
 
-	cq = xa_load(&cq_table->array, cqn & (hr_dev->caps.num_cqs - 1));
-	if (cq)
-		atomic_inc(&cq->refcount);
+	hr_cq = xa_load(&hr_dev->cq_table.array,
+			cqn & (hr_dev->caps.num_cqs - 1));
+	if (!hr_cq) {
+		dev_warn(dev, "Async event for bogus CQ 0x%06x\n", cqn);
+		return;
+	}
 
-	if (!cq) {
-		dev_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+	if (event_type != HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID &&
+	    event_type != HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR &&
+	    event_type != HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW) {
+		dev_err(dev, "Unexpected event type 0x%x on CQ 0x%06x\n",
+			event_type, cqn);
 		return;
 	}
 
-	cq->event(cq, (enum hns_roce_event)event_type);
+	atomic_inc(&hr_cq->refcount);
+
+	ibcq = &hr_cq->ib_cq;
+	if (ibcq->event_handler) {
+		event.device = ibcq->device;
+		event.element.cq = ibcq;
+		event.event = IB_EVENT_CQ_ERR;
+		ibcq->event_handler(&event, ibcq->cq_context);
+	}
 
-	if (atomic_dec_and_test(&cq->refcount))
-		complete(&cq->free);
+	if (atomic_dec_and_test(&hr_cq->refcount))
+		complete(&hr_cq->free);
 }
 
 int hns_roce_init_cq_table(struct hns_roce_dev *hr_dev)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_db.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_db.c
@@ -31,7 +31,8 @@
 
 	refcount_set(&page->refcount, 1);
 	page->user_virt = page_addr;
-	page->umem = ib_umem_get(udata, page_addr, PAGE_SIZE, 0, 0);
+	page->umem = ib_umem_get(context->ibucontext.device, page_addr,
+				 PAGE_SIZE, 0);
 	if (IS_ERR(page->umem)) {
 		ret = PTR_ERR(page->umem);
 		kfree(page);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_device.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -45,16 +45,12 @@
 
 #define HNS_ROCE_MAX_MSG_LEN			0x80000000
 
-#define HNS_ROCE_ALOGN_UP(a, b) ((((a) + (b) - 1) / (b)) * (b))
-
 #define HNS_ROCE_IB_MIN_SQ_STRIDE		6
 
 #define HNS_ROCE_BA_SIZE			(32 * 4096)
 
 #define BA_BYTE_LEN				8
 
-#define BITS_PER_BYTE				8
-
 /* Hardware specification only for v1 engine */
 #define HNS_ROCE_MIN_CQE_NUM			0x40
 #define HNS_ROCE_MIN_WQE_NUM			0x20
@@ -109,11 +105,6 @@
 #define NODE_DESC_SIZE				64
 #define DB_REG_OFFSET				0x1000
 
-#define SERV_TYPE_RC				0
-#define SERV_TYPE_RD				1
-#define SERV_TYPE_UC				2
-#define SERV_TYPE_UD				3
-
 /* Configure to HW for PAGE_SIZE larger than 4KB */
 #define PG_SHIFT_OFFSET				(PAGE_SHIFT - 12)
 
@@ -133,6 +124,13 @@
 #define EQ_DEPTH_COEFF				2
 
 enum {
+	SERV_TYPE_RC,
+	SERV_TYPE_UC,
+	SERV_TYPE_RD,
+	SERV_TYPE_UD,
+};
+
+enum {
 	HNS_ROCE_SUPPORT_RQ_RECORD_DB = 1 << 0,
 	HNS_ROCE_SUPPORT_SQ_RECORD_DB = 1 << 1,
 };
@@ -425,8 +423,7 @@
 struct hns_roce_wq {
 	u64		*wrid;     /* Work request ID */
 	spinlock_t	lock;
-	int		wqe_cnt;  /* WQE num */
-	u32		max_post;
+	u32		wqe_cnt;  /* WQE num */
 	int		max_gs;
 	int		offset;
 	int		wqe_shift;	/* WQE size */
@@ -451,6 +448,7 @@
 	struct hns_roce_buf_list	*page_list;
 	int				nbufs;
 	u32				npages;
+	u32				size;
 	int				page_shift;
 };
 
@@ -482,22 +480,14 @@
 	int		order;
 };
 
-struct hns_roce_cq_buf {
-	struct hns_roce_buf hr_buf;
-	struct hns_roce_mtt hr_mtt;
-};
-
 struct hns_roce_cq {
 	struct ib_cq			ib_cq;
-	struct hns_roce_cq_buf		hr_buf;
+	struct hns_roce_buf		buf;
+	struct hns_roce_mtt		mtt;
 	struct hns_roce_db		db;
 	u8				db_en;
 	spinlock_t			lock;
 	struct ib_umem			*umem;
-	void (*comp)(struct hns_roce_cq *cq);
-	void (*event)(struct hns_roce_cq *cq, enum hns_roce_event event_type);
-
-	struct hns_roce_uar		*uar;
 	u32				cq_depth;
 	u32				cons_index;
 	u32				*set_ci_db;
@@ -508,6 +498,10 @@
 	u32				vector;
 	atomic_t			refcount;
 	struct completion		free;
+	struct list_head		sq_list; /* all qps on this send cq */
+	struct list_head		rq_list; /* all qps on this recv cq */
+	int				is_armed; /* cq is armed */
+	struct list_head		node; /* all armed cqs are on a list */
 };
 
 struct hns_roce_idx_que {
@@ -521,9 +515,8 @@
 
 struct hns_roce_srq {
 	struct ib_srq		ibsrq;
-	void (*event)(struct hns_roce_srq *srq, enum hns_roce_event event);
 	unsigned long		srqn;
-	int			max;
+	u32			wqe_cnt;
 	int			max_gs;
 	int			wqe_shift;
 	void __iomem		*db_reg_l;
@@ -539,8 +532,8 @@
 	spinlock_t		lock;
 	int			head;
 	int			tail;
-	u16			wqe_ctr;
 	struct mutex		mutex;
+	void (*event)(struct hns_roce_srq *srq, enum hns_roce_event event);
 };
 
 struct hns_roce_uar_table {
@@ -582,7 +575,7 @@
 	u8          tclass;
 	u8          dgid[HNS_ROCE_GID_SIZE];
 	u8          mac[ETH_ALEN];
-	u16         vlan;
+	u16         vlan_id;
 	bool	    vlan_en;
 };
 
@@ -648,6 +641,19 @@
 	u32			 wqe_cnt;
 };
 
+enum {
+	HNS_ROCE_FLUSH_FLAG = 0,
+};
+
+struct hns_roce_work {
+	struct hns_roce_dev *hr_dev;
+	struct work_struct work;
+	u32 qpn;
+	u32 cqn;
+	int event_type;
+	int sub_type;
+};
+
 struct hns_roce_qp {
 	struct ib_qp		ibqp;
 	struct hns_roce_buf	hr_buf;
@@ -657,8 +663,7 @@
 	u8			rdb_en;
 	u8			sdb_en;
 	u32			doorbell_qpn;
-	u32			sq_signal_bits;
-	u32			sq_next_wqe;
+	enum ib_sig_type	sq_signal_bits;
 	struct hns_roce_wq	sq;
 
 	struct ib_umem		*umem;
@@ -668,7 +673,6 @@
 	/* this define must less than HNS_ROCE_MAX_BT_REGION */
 #define HNS_ROCE_WQE_REGION_MAX	 3
 	struct hns_roce_buf_region regions[HNS_ROCE_WQE_REGION_MAX];
-	int			region_cnt;
 	int                     wqe_bt_pg_shift;
 
 	u32			buff_size;
@@ -692,11 +696,13 @@
 	struct hns_roce_sge	sge;
 	u32			next_sge;
 
+	/* 0: flush needed, 1: unneeded */
+	unsigned long		flush_flag;
+	struct hns_roce_work	flush_work;
 	struct hns_roce_rinl_buf rq_inl_buf;
-};
-
-struct hns_roce_sqp {
-	struct hns_roce_qp	hr_qp;
+	struct list_head	node;		/* all qps are on a list */
+	struct list_head	rq_node;	/* all recv qps are on a list */
+	struct list_head	sq_node;	/* all send qps are on a list */
 };
 
 struct hns_roce_ib_iboe {
@@ -771,14 +777,8 @@
 	int				eqe_ba_pg_sz;
 	int				eqe_buf_pg_sz;
 	int				hop_num;
-	u64				*bt_l0;	/* Base address table for L0 */
-	u64				**bt_l1; /* Base address table for L1 */
-	u64				**buf;
-	dma_addr_t			l0_dma;
-	dma_addr_t			*l1_dma;
-	dma_addr_t			*buf_dma;
-	u32				l0_last_num; /* L0 last chunk num */
-	u32				l1_last_num; /* L1 last chunk num */
+	struct hns_roce_mtr		mtr;
+	struct hns_roce_buf		buf;
 	int				eq_max_cnt;
 	int				eq_period;
 	int				shift;
@@ -809,10 +809,8 @@
 	int             reserved_qps;
 	int		num_qpc_timer;
 	int		num_cqc_timer;
-	u32		max_srq_sg;
 	int		num_srqs;
 	u32		max_wqes;
-	u32		max_srqs;
 	u32		max_srq_wrs;
 	u32		max_srq_sges;
 	u32		max_sq_desc_sz;
@@ -821,12 +819,11 @@
 	int		max_qp_init_rdma;
 	int		max_qp_dest_rdma;
 	int		num_cqs;
-	int		max_cqes;
-	int		min_cqes;
+	u32		max_cqes;
+	u32		min_cqes;
 	u32		min_wqes;
 	int		reserved_cqs;
 	int		reserved_srqs;
-	u32		max_srqwqes;
 	int		num_aeq_vectors;
 	int		num_comp_vectors;
 	int		num_other_vectors;
@@ -893,7 +890,7 @@
 	u32		cqc_timer_ba_pg_sz;
 	u32		cqc_timer_buf_pg_sz;
 	u32		cqc_timer_hop_num;
-	u32		cqe_ba_pg_sz;
+	u32             cqe_ba_pg_sz;	/* page_size = 4K*(2^cqe_ba_pg_sz) */
 	u32		cqe_buf_pg_sz;
 	u32		cqe_hop_num;
 	u32		srqwqe_ba_pg_sz;
@@ -910,15 +907,12 @@
 	u32		tpq_buf_pg_sz;
 	u32		chunk_sz;	/* chunk size in non multihop mode */
 	u64		flags;
-};
-
-struct hns_roce_work {
-	struct hns_roce_dev *hr_dev;
-	struct work_struct work;
-	u32 qpn;
-	u32 cqn;
-	int event_type;
-	int sub_type;
+	u16		default_ceq_max_cnt;
+	u16		default_ceq_period;
+	u16		default_aeq_max_cnt;
+	u16		default_aeq_period;
+	u16		default_aeq_arm_st;
+	u16		default_ceq_arm_st;
 };
 
 struct hns_roce_dfx_hw {
@@ -926,6 +920,12 @@
 			      int *buffer);
 };
 
+enum hns_roce_device_state {
+	HNS_ROCE_DEVICE_STATE_INITED,
+	HNS_ROCE_DEVICE_STATE_RST_DOWN,
+	HNS_ROCE_DEVICE_STATE_UNINIT,
+};
+
 struct hns_roce_hw {
 	int (*reset)(struct hns_roce_dev *hr_dev, bool enable);
 	int (*cmq_init)(struct hns_roce_dev *hr_dev);
@@ -953,7 +953,7 @@
 	int (*mw_write_mtpt)(void *mb_buf, struct hns_roce_mw *mw);
 	void (*write_cqc)(struct hns_roce_dev *hr_dev,
 			  struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts,
-			  dma_addr_t dma_handle, int nent, u32 vector);
+			  dma_addr_t dma_handle);
 	int (*set_hem)(struct hns_roce_dev *hr_dev,
 		       struct hns_roce_hem_table *table, int obj, int step_idx);
 	int (*clear_hem)(struct hns_roce_dev *hr_dev,
@@ -1008,6 +1008,9 @@
 	bool			dis_db;
 	unsigned long		reset_cnt;
 	struct hns_roce_ib_iboe iboe;
+	enum hns_roce_device_state state;
+	struct list_head	qp_list; /* list of all qps on this dev */
+	spinlock_t		qp_list_lock; /* protect qp_list */
 
 	struct list_head        pgdir_list;
 	struct mutex            pgdir_mutex;
@@ -1092,11 +1095,6 @@
 	return container_of(ibsrq, struct hns_roce_srq, ibsrq);
 }
 
-static inline struct hns_roce_sqp *hr_to_hr_sqp(struct hns_roce_qp *hr_qp)
-{
-	return container_of(hr_qp, struct hns_roce_sqp, hr_qp);
-}
-
 static inline void hns_roce_write64_k(__le32 val[2], void __iomem *dest)
 {
 	__raw_writeq(*(u64 *) val, dest);
@@ -1153,7 +1151,6 @@
 
 int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev);
 int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev);
-int hns_roce_init_eq_table(struct hns_roce_dev *hr_dev);
 int hns_roce_init_cq_table(struct hns_roce_dev *hr_dev);
 int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev);
 int hns_roce_init_srq_table(struct hns_roce_dev *hr_dev);
@@ -1198,9 +1195,9 @@
 int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
 		       unsigned int *sg_offset);
 int hns_roce_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
-int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev,
-		       struct hns_roce_cmd_mailbox *mailbox,
-		       unsigned long mpt_index);
+int hns_roce_hw_destroy_mpt(struct hns_roce_dev *hr_dev,
+			    struct hns_roce_cmd_mailbox *mailbox,
+			    unsigned long mpt_index);
 unsigned long key_to_hw_index(u32 key);
 
 struct ib_mw *hns_roce_alloc_mw(struct ib_pd *pd, enum ib_mw_type,
@@ -1240,6 +1237,7 @@
 				 struct ib_udata *udata);
 int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 		       int attr_mask, struct ib_udata *udata);
+void init_flush_work(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
 void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n);
 void *get_send_wqe(struct hns_roce_qp *hr_qp, int n);
 void *get_send_extend_sge(struct hns_roce_qp *hr_qp, int n);
@@ -1251,18 +1249,16 @@
 void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
 			 struct hns_roce_cq *recv_cq);
 void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
-void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
-void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
-			       int cnt);
+void hns_roce_qp_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			 struct ib_udata *udata);
 __be32 send_ieth(const struct ib_send_wr *wr);
 int to_hr_qp_type(int qp_type);
 
-int hns_roce_ib_create_cq(struct ib_cq *ib_cq,
-			  const struct ib_cq_init_attr *attr,
-			  struct ib_udata *udata);
+int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
+		       struct ib_udata *udata);
 
-void hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
-void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq);
+void hns_roce_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
+void hns_roce_free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq);
 
 int hns_roce_db_map_user(struct hns_roce_ucontext *context,
 			 struct ib_udata *udata, unsigned long virt,
@@ -1278,6 +1274,7 @@
 void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type);
 void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type);
 int hns_get_gid_index(struct hns_roce_dev *hr_dev, u8 port, int gid_index);
+void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev);
 int hns_roce_init(struct hns_roce_dev *hr_dev);
 void hns_roce_exit(struct hns_roce_dev *hr_dev);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -69,13 +69,13 @@
 	struct hns_roce_wqe_data_seg *dseg = NULL;
 	struct hns_roce_qp *qp = to_hr_qp(ibqp);
 	struct device *dev = &hr_dev->pdev->dev;
-	struct hns_roce_sq_db sq_db;
+	struct hns_roce_sq_db sq_db = {};
 	int ps_opcode = 0, i = 0;
 	unsigned long flags = 0;
 	void *wqe = NULL;
 	__le32 doorbell[2];
+	u32 wqe_idx = 0;
 	int nreq = 0;
-	u32 ind = 0;
 	int ret = 0;
 	u8 *smac;
 	int loopback;
@@ -88,7 +88,7 @@
 	}
 
 	spin_lock_irqsave(&qp->sq.lock, flags);
-	ind = qp->sq_next_wqe;
+
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
 		if (hns_roce_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
 			ret = -ENOMEM;
@@ -96,6 +96,8 @@
 			goto out;
 		}
 
+		wqe_idx = (qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1);
+
 		if (unlikely(wr->num_sge > qp->sq.max_gs)) {
 			dev_err(dev, "num_sge=%d > qp->sq.max_gs=%d\n",
 				wr->num_sge, qp->sq.max_gs);
@@ -104,9 +106,8 @@
 			goto out;
 		}
 
-		wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1));
-		qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] =
-								      wr->wr_id;
+		wqe = get_send_wqe(qp, wqe_idx);
+		qp->sq.wrid[wqe_idx] = wr->wr_id;
 
 		/* Corresponding to the RC and RD type wqe process separately */
 		if (ibqp->qp_type == IB_QPT_GSI) {
@@ -210,7 +211,6 @@
 				       cpu_to_le32((wr->sg_list[1].addr) >> 32);
 			ud_sq_wqe->l_key1 =
 				       cpu_to_le32(wr->sg_list[1].lkey);
-			ind++;
 		} else if (ibqp->qp_type == IB_QPT_RC) {
 			u32 tmp_len = 0;
 
@@ -271,7 +271,6 @@
 				ps_opcode = HNS_ROCE_WQE_OPCODE_SEND;
 				break;
 			case IB_WR_LOCAL_INV:
-				break;
 			case IB_WR_ATOMIC_CMP_AND_SWP:
 			case IB_WR_ATOMIC_FETCH_AND_ADD:
 			case IB_WR_LSO:
@@ -308,7 +307,6 @@
 				ctrl->flag |= cpu_to_le32(wr->num_sge <<
 					      HNS_ROCE_WQE_SGE_NUM_BIT);
 			}
-			ind++;
 		}
 	}
 
@@ -319,8 +317,6 @@
 		/* Memory barrier */
 		wmb();
 
-		sq_db.u32_4 = 0;
-		sq_db.u32_8 = 0;
 		roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_SQ_HEAD_M,
 			       SQ_DOORBELL_U32_4_SQ_HEAD_S,
 			      (qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1)));
@@ -336,7 +332,6 @@
 		doorbell[1] = sq_db.u32_8;
 
 		hns_roce_write64_k(doorbell, qp->sq.db_reg_l);
-		qp->sq_next_wqe = ind;
 	}
 
 	spin_unlock_irqrestore(&qp->sq.lock, flags);
@@ -348,22 +343,21 @@
 				 const struct ib_recv_wr *wr,
 				 const struct ib_recv_wr **bad_wr)
 {
-	int ret = 0;
-	int nreq = 0;
-	int ind = 0;
-	int i = 0;
-	u32 reg_val;
-	unsigned long flags = 0;
 	struct hns_roce_rq_wqe_ctrl *ctrl = NULL;
 	struct hns_roce_wqe_data_seg *scat = NULL;
 	struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
 	struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
 	struct device *dev = &hr_dev->pdev->dev;
-	struct hns_roce_rq_db rq_db;
+	struct hns_roce_rq_db rq_db = {};
 	__le32 doorbell[2] = {0};
+	unsigned long flags = 0;
+	unsigned int wqe_idx;
+	int ret = 0;
+	int nreq = 0;
+	int i = 0;
+	u32 reg_val;
 
 	spin_lock_irqsave(&hr_qp->rq.lock, flags);
-	ind = hr_qp->rq.head & (hr_qp->rq.wqe_cnt - 1);
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
 		if (hns_roce_wq_overflow(&hr_qp->rq, nreq,
@@ -373,6 +367,8 @@
 			goto out;
 		}
 
+		wqe_idx = (hr_qp->rq.head + nreq) & (hr_qp->rq.wqe_cnt - 1);
+
 		if (unlikely(wr->num_sge > hr_qp->rq.max_gs)) {
 			dev_err(dev, "rq:num_sge=%d > qp->sq.max_gs=%d\n",
 				wr->num_sge, hr_qp->rq.max_gs);
@@ -381,7 +377,7 @@
 			goto out;
 		}
 
-		ctrl = get_recv_wqe(hr_qp, ind);
+		ctrl = get_recv_wqe(hr_qp, wqe_idx);
 
 		roce_set_field(ctrl->rwqe_byte_12,
 			       RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_M,
@@ -393,9 +389,7 @@
 		for (i = 0; i < wr->num_sge; i++)
 			set_data_seg(scat + i, wr->sg_list + i);
 
-		hr_qp->rq.wrid[ind] = wr->wr_id;
-
-		ind = (ind + 1) & (hr_qp->rq.wqe_cnt - 1);
+		hr_qp->rq.wrid[wqe_idx] = wr->wr_id;
 	}
 
 out:
@@ -421,9 +415,6 @@
 				   ROCEE_QP1C_CFG3_0_REG +
 				   QP1C_CFGN_OFFSET * hr_qp->phy_port, reg_val);
 		} else {
-			rq_db.u32_4 = 0;
-			rq_db.u32_8 = 0;
-
 			roce_set_field(rq_db.u32_4, RQ_DOORBELL_U32_4_RQ_HEAD_M,
 				       RQ_DOORBELL_U32_4_RQ_HEAD_S,
 				       hr_qp->rq.head);
@@ -732,7 +723,7 @@
 	if (!cq)
 		return -ENOMEM;
 
-	ret = hns_roce_ib_create_cq(cq, &cq_init_attr, NULL);
+	ret = hns_roce_create_cq(cq, &cq_init_attr, NULL);
 	if (ret) {
 		dev_err(dev, "Create cq for reserved loop qp failed!");
 		goto alloc_cq_failed;
@@ -868,7 +859,7 @@
 	kfree(pd);
 
 alloc_mem_failed:
-	hns_roce_ib_destroy_cq(cq, NULL);
+	hns_roce_destroy_cq(cq, NULL);
 alloc_cq_failed:
 	kfree(cq);
 	return ret;
@@ -897,7 +888,7 @@
 				i, ret);
 	}
 
-	hns_roce_ib_destroy_cq(&free_mr->mr_free_cq->ib_cq, NULL);
+	hns_roce_destroy_cq(&free_mr->mr_free_cq->ib_cq, NULL);
 	kfree(&free_mr->mr_free_cq->ib_cq);
 	hns_roce_dealloc_pd(&free_mr->mr_free_pd->ibpd, NULL);
 	kfree(&free_mr->mr_free_pd->ibpd);
@@ -1114,9 +1105,10 @@
 	free_mr = &priv->free_mr;
 
 	if (mr->enabled) {
-		if (hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mr->key)
-				       & (hr_dev->caps.num_mtpts - 1)))
-			dev_warn(dev, "HW2SW_MPT failed!\n");
+		if (hns_roce_hw_destroy_mpt(hr_dev, NULL,
+					    key_to_hw_index(mr->key) &
+					    (hr_dev->caps.num_mtpts - 1)))
+			dev_warn(dev, "DESTROY_MPT failed!\n");
 	}
 
 	mr_work = kzalloc(sizeof(*mr_work), GFP_KERNEL);
@@ -1979,8 +1971,7 @@
 
 static void *get_cqe(struct hns_roce_cq *hr_cq, int n)
 {
-	return hns_roce_buf_offset(&hr_cq->hr_buf.hr_buf,
-				   n * HNS_ROCE_V1_CQE_ENTRY_SIZE);
+	return hns_roce_buf_offset(&hr_cq->buf, n * HNS_ROCE_V1_CQE_ENTRY_SIZE);
 }
 
 static void *get_sw_cqe(struct hns_roce_cq *hr_cq, int n)
@@ -1989,7 +1980,7 @@
 
 	/* Get cqe when Owner bit is Conversely with the MSB of cons_idx */
 	return (roce_get_bit(hr_cqe->cqe_byte_4, CQE_BYTE_4_OWNER_S) ^
-		!!(n & (hr_cq->ib_cq.cqe + 1))) ? hr_cqe : NULL;
+		!!(n & hr_cq->cq_depth)) ? hr_cqe : NULL;
 }
 
 static struct hns_roce_cqe *next_cqe_sw(struct hns_roce_cq *hr_cq)
@@ -2072,8 +2063,7 @@
 
 static void hns_roce_v1_write_cqc(struct hns_roce_dev *hr_dev,
 				  struct hns_roce_cq *hr_cq, void *mb_buf,
-				  u64 *mtts, dma_addr_t dma_handle, int nent,
-				  u32 vector)
+				  u64 *mtts, dma_addr_t dma_handle)
 {
 	struct hns_roce_cq_context *cq_context = NULL;
 	struct hns_roce_buf_list *tptr_buf;
@@ -2108,9 +2098,9 @@
 	roce_set_field(cq_context->cqc_byte_12,
 		       CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_M,
 		       CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_S,
-		       ilog2((unsigned int)nent));
+		       ilog2(hr_cq->cq_depth));
 	roce_set_field(cq_context->cqc_byte_12, CQ_CONTEXT_CQC_BYTE_12_CEQN_M,
-		       CQ_CONTEXT_CQC_BYTE_12_CEQN_S, vector);
+		       CQ_CONTEXT_CQC_BYTE_12_CEQN_S, hr_cq->vector);
 
 	cq_context->cur_cqe_ba0_l = cpu_to_le32((u32)(mtts[0]));
 
@@ -2702,7 +2692,6 @@
 		hr_qp->rq.tail = 0;
 		hr_qp->sq.head = 0;
 		hr_qp->sq.tail = 0;
-		hr_qp->sq_next_wqe = 0;
 	}
 
 	kfree(context);
@@ -3316,7 +3305,6 @@
 		hr_qp->rq.tail = 0;
 		hr_qp->sq.head = 0;
 		hr_qp->sq.tail = 0;
-		hr_qp->sq_next_wqe = 0;
 	}
 out:
 	kfree(context);
@@ -3615,39 +3603,25 @@
 	if (ret)
 		return ret;
 
-	send_cq = to_hr_cq(hr_qp->ibqp.send_cq);
-	recv_cq = to_hr_cq(hr_qp->ibqp.recv_cq);
+	send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL;
+	recv_cq = hr_qp->ibqp.recv_cq ? to_hr_cq(hr_qp->ibqp.recv_cq) : NULL;
 
 	hns_roce_lock_cqs(send_cq, recv_cq);
 	if (!udata) {
-		__hns_roce_v1_cq_clean(recv_cq, hr_qp->qpn, hr_qp->ibqp.srq ?
-				       to_hr_srq(hr_qp->ibqp.srq) : NULL);
-		if (send_cq != recv_cq)
+		if (recv_cq)
+			__hns_roce_v1_cq_clean(recv_cq, hr_qp->qpn,
+					       (hr_qp->ibqp.srq ?
+						to_hr_srq(hr_qp->ibqp.srq) :
+						NULL));
+
+		if (send_cq && send_cq != recv_cq)
 			__hns_roce_v1_cq_clean(send_cq, hr_qp->qpn, NULL);
 	}
-	hns_roce_unlock_cqs(send_cq, recv_cq);
-
 	hns_roce_qp_remove(hr_dev, hr_qp);
-	hns_roce_qp_free(hr_dev, hr_qp);
-
-	/* RC QP, release QPN */
-	if (hr_qp->ibqp.qp_type == IB_QPT_RC)
-		hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1);
-
-	hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
-
-	ib_umem_release(hr_qp->umem);
-	if (!udata) {
-		kfree(hr_qp->sq.wrid);
-		kfree(hr_qp->rq.wrid);
+	hns_roce_unlock_cqs(send_cq, recv_cq);
 
-		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
-	}
+	hns_roce_qp_destroy(hr_dev, hr_qp, udata);
 
-	if (hr_qp->ibqp.qp_type == IB_QPT_RC)
-		kfree(hr_qp);
-	else
-		kfree(hr_to_hr_sqp(hr_qp));
 	return 0;
 }
 
@@ -3658,10 +3632,9 @@
 	struct device *dev = &hr_dev->pdev->dev;
 	u32 cqe_cnt_ori;
 	u32 cqe_cnt_cur;
-	u32 cq_buf_size;
 	int wait_time = 0;
 
-	hns_roce_free_cq(hr_dev, hr_cq);
+	hns_roce_free_cqc(hr_dev, hr_cq);
 
 	/*
 	 * Before freeing cq buffer, we need to ensure that the outstanding CQE
@@ -3686,13 +3659,12 @@
 		wait_time++;
 	}
 
-	hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+	hns_roce_mtt_cleanup(hr_dev, &hr_cq->mtt);
 
 	ib_umem_release(hr_cq->umem);
 	if (!udata) {
 		/* Free the buff of stored cq */
-		cq_buf_size = (ibcq->cqe + 1) * hr_dev->caps.cq_entry_sz;
-		hns_roce_buf_free(hr_dev, cq_buf_size, &hr_cq->hr_buf.hr_buf);
+		hns_roce_buf_free(hr_dev, hr_cq->buf.size, &hr_cq->buf);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -63,20 +63,15 @@
 	struct hns_roce_mr *mr = to_hr_mr(wr->mr);
 
 	/* use ib_access_flags */
-	roce_set_bit(rc_sq_wqe->byte_4,
-		     V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S,
+	roce_set_bit(rc_sq_wqe->byte_4, V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S,
 		     wr->access & IB_ACCESS_MW_BIND ? 1 : 0);
-	roce_set_bit(rc_sq_wqe->byte_4,
-		     V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S,
+	roce_set_bit(rc_sq_wqe->byte_4, V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S,
 		     wr->access & IB_ACCESS_REMOTE_ATOMIC ? 1 : 0);
-	roce_set_bit(rc_sq_wqe->byte_4,
-		     V2_RC_FRMR_WQE_BYTE_4_RR_S,
+	roce_set_bit(rc_sq_wqe->byte_4, V2_RC_FRMR_WQE_BYTE_4_RR_S,
 		     wr->access & IB_ACCESS_REMOTE_READ ? 1 : 0);
-	roce_set_bit(rc_sq_wqe->byte_4,
-		     V2_RC_FRMR_WQE_BYTE_4_RW_S,
+	roce_set_bit(rc_sq_wqe->byte_4, V2_RC_FRMR_WQE_BYTE_4_RW_S,
 		     wr->access & IB_ACCESS_REMOTE_WRITE ? 1 : 0);
-	roce_set_bit(rc_sq_wqe->byte_4,
-		     V2_RC_FRMR_WQE_BYTE_4_LW_S,
+	roce_set_bit(rc_sq_wqe->byte_4, V2_RC_FRMR_WQE_BYTE_4_LW_S,
 		     wr->access & IB_ACCESS_LOCAL_WRITE ? 1 : 0);
 
 	/* Data structure reuse may lead to confusion */
@@ -110,7 +105,7 @@
 }
 
 static void set_extend_sge(struct hns_roce_qp *qp, const struct ib_send_wr *wr,
-			   unsigned int *sge_ind)
+			   unsigned int *sge_ind, int valid_num_sge)
 {
 	struct hns_roce_v2_wqe_data_seg *dseg;
 	struct ib_sge *sg;
@@ -123,7 +118,7 @@
 
 	if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC)
 		num_in_wqe = HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE;
-	extend_sge_num = wr->num_sge - num_in_wqe;
+	extend_sge_num = valid_num_sge - num_in_wqe;
 	sg = wr->sg_list + num_in_wqe;
 	shift = qp->hr_buf.page_shift;
 
@@ -159,14 +154,16 @@
 static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
 			     struct hns_roce_v2_rc_send_wqe *rc_sq_wqe,
 			     void *wqe, unsigned int *sge_ind,
+			     int valid_num_sge,
 			     const struct ib_send_wr **bad_wr)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
 	struct hns_roce_v2_wqe_data_seg *dseg = wqe;
 	struct hns_roce_qp *qp = to_hr_qp(ibqp);
+	int j = 0;
 	int i;
 
-	if (wr->send_flags & IB_SEND_INLINE && wr->num_sge) {
+	if (wr->send_flags & IB_SEND_INLINE && valid_num_sge) {
 		if (le32_to_cpu(rc_sq_wqe->msg_len) >
 		    hr_dev->caps.max_sq_inline) {
 			*bad_wr = wr;
@@ -190,7 +187,7 @@
 		roce_set_bit(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_INLINE_S,
 			     1);
 	} else {
-		if (wr->num_sge <= HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE) {
+		if (valid_num_sge <= HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE) {
 			for (i = 0; i < wr->num_sge; i++) {
 				if (likely(wr->sg_list[i].length)) {
 					set_data_seg_v2(dseg, wr->sg_list + i);
@@ -203,28 +200,81 @@
 				     V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_S,
 				     (*sge_ind) & (qp->sge.sge_cnt - 1));
 
-			for (i = 0; i < HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE; i++) {
+			for (i = 0; i < wr->num_sge &&
+			     j < HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE; i++) {
 				if (likely(wr->sg_list[i].length)) {
 					set_data_seg_v2(dseg, wr->sg_list + i);
 					dseg++;
+					j++;
 				}
 			}
 
-			set_extend_sge(qp, wr, sge_ind);
+			set_extend_sge(qp, wr, sge_ind, valid_num_sge);
 		}
 
 		roce_set_field(rc_sq_wqe->byte_16,
 			       V2_RC_SEND_WQE_BYTE_16_SGE_NUM_M,
-			       V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S, wr->num_sge);
+			       V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S, valid_num_sge);
 	}
 
 	return 0;
 }
 
-static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
-				 const struct ib_qp_attr *attr,
-				 int attr_mask, enum ib_qp_state cur_state,
-				 enum ib_qp_state new_state);
+static int check_send_valid(struct hns_roce_dev *hr_dev,
+			    struct hns_roce_qp *hr_qp)
+{
+	struct ib_qp *ibqp = &hr_qp->ibqp;
+	struct device *dev = hr_dev->dev;
+
+	if (unlikely(ibqp->qp_type != IB_QPT_RC &&
+		     ibqp->qp_type != IB_QPT_GSI &&
+		     ibqp->qp_type != IB_QPT_UD)) {
+		dev_err(dev, "Not supported QP(0x%x)type!\n", ibqp->qp_type);
+		return -EOPNOTSUPP;
+	} else if (unlikely(hr_qp->state == IB_QPS_RESET ||
+		   hr_qp->state == IB_QPS_INIT ||
+		   hr_qp->state == IB_QPS_RTR)) {
+		dev_err(dev, "Post WQE fail, QP state %d!\n", hr_qp->state);
+		return -EINVAL;
+	} else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) {
+		dev_err(dev, "Post WQE fail, dev state %d!\n", hr_dev->state);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline void update_sq_db(struct hns_roce_dev *hr_dev,
+				struct hns_roce_qp *qp)
+{
+	/*
+	 * Hip08 hardware cannot flush the WQEs in SQ if the QP state
+	 * gets into errored mode. Hence, as a workaround to this
+	 * hardware limitation, driver needs to assist in flushing. But
+	 * the flushing operation uses mailbox to convey the QP state to
+	 * the hardware and which can sleep due to the mutex protection
+	 * around the mailbox calls. Hence, use the deferred flush for
+	 * now.
+	 */
+	if (qp->state == IB_QPS_ERR) {
+		if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
+			init_flush_work(hr_dev, qp);
+	} else {
+		struct hns_roce_v2_db sq_db = {};
+
+		roce_set_field(sq_db.byte_4, V2_DB_BYTE_4_TAG_M,
+			       V2_DB_BYTE_4_TAG_S, qp->doorbell_qpn);
+		roce_set_field(sq_db.byte_4, V2_DB_BYTE_4_CMD_M,
+			       V2_DB_BYTE_4_CMD_S, HNS_ROCE_V2_SQ_DB);
+		roce_set_field(sq_db.parameter, V2_DB_PARAMETER_IDX_M,
+			       V2_DB_PARAMETER_IDX_S,
+			       qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1));
+		roce_set_field(sq_db.parameter, V2_DB_PARAMETER_SL_M,
+			       V2_DB_PARAMETER_SL_S, qp->sl);
+
+		hns_roce_write64(hr_dev, (__le32 *)&sq_db, qp->sq.db_reg_l);
+	}
+}
 
 static int hns_roce_v2_post_send(struct ib_qp *ibqp,
 				 const struct ib_send_wr *wr,
@@ -237,40 +287,30 @@
 	struct hns_roce_qp *qp = to_hr_qp(ibqp);
 	struct hns_roce_wqe_frmr_seg *fseg;
 	struct device *dev = hr_dev->dev;
-	struct hns_roce_v2_db sq_db;
-	struct ib_qp_attr attr;
-	unsigned int sge_ind;
 	unsigned int owner_bit;
+	unsigned int sge_idx;
+	unsigned int wqe_idx;
 	unsigned long flags;
-	unsigned int ind;
+	int valid_num_sge;
 	void *wqe = NULL;
 	bool loopback;
-	int attr_mask;
 	u32 tmp_len;
-	int ret = 0;
 	u32 hr_op;
 	u8 *smac;
 	int nreq;
+	int ret;
 	int i;
 
-	if (unlikely(ibqp->qp_type != IB_QPT_RC &&
-		     ibqp->qp_type != IB_QPT_GSI &&
-		     ibqp->qp_type != IB_QPT_UD)) {
-		dev_err(dev, "Not supported QP(0x%x)type!\n", ibqp->qp_type);
-		*bad_wr = wr;
-		return -EOPNOTSUPP;
-	}
+	spin_lock_irqsave(&qp->sq.lock, flags);
 
-	if (unlikely(qp->state == IB_QPS_RESET || qp->state == IB_QPS_INIT ||
-		     qp->state == IB_QPS_RTR)) {
-		dev_err(dev, "Post WQE fail, QP state %d err!\n", qp->state);
+	ret = check_send_valid(hr_dev, qp);
+	if (ret) {
 		*bad_wr = wr;
-		return -EINVAL;
+		nreq = 0;
+		goto out;
 	}
 
-	spin_lock_irqsave(&qp->sq.lock, flags);
-	ind = qp->sq_next_wqe;
-	sge_ind = qp->next_sge;
+	sge_idx = qp->next_sge;
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
 		if (hns_roce_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
@@ -279,6 +319,8 @@
 			goto out;
 		}
 
+		wqe_idx = (qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1);
+
 		if (unlikely(wr->num_sge > qp->sq.max_gs)) {
 			dev_err(dev, "num_sge=%d > qp->sq.max_gs=%d\n",
 				wr->num_sge, qp->sq.max_gs);
@@ -287,14 +329,20 @@
 			goto out;
 		}
 
-		wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1));
-		qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] =
-								      wr->wr_id;
-
+		wqe = get_send_wqe(qp, wqe_idx);
+		qp->sq.wrid[wqe_idx] = wr->wr_id;
 		owner_bit =
 		       ~(((qp->sq.head + nreq) >> ilog2(qp->sq.wqe_cnt)) & 0x1);
+		valid_num_sge = 0;
 		tmp_len = 0;
 
+		for (i = 0; i < wr->num_sge; i++) {
+			if (likely(wr->sg_list[i].length)) {
+				tmp_len += wr->sg_list[i].length;
+				valid_num_sge++;
+			}
+		}
+
 		/* Corresponding to the QP type, wqe process separately */
 		if (ibqp->qp_type == IB_QPT_GSI) {
 			ud_sq_wqe = wqe;
@@ -330,9 +378,6 @@
 				       V2_UD_SEND_WQE_BYTE_4_OPCODE_S,
 				       HNS_ROCE_V2_WQE_OP_SEND);
 
-			for (i = 0; i < wr->num_sge; i++)
-				tmp_len += wr->sg_list[i].length;
-
 			ud_sq_wqe->msg_len =
 			 cpu_to_le32(le32_to_cpu(ud_sq_wqe->msg_len) + tmp_len);
 
@@ -368,12 +413,12 @@
 			roce_set_field(ud_sq_wqe->byte_16,
 				       V2_UD_SEND_WQE_BYTE_16_SGE_NUM_M,
 				       V2_UD_SEND_WQE_BYTE_16_SGE_NUM_S,
-				       wr->num_sge);
+				       valid_num_sge);
 
 			roce_set_field(ud_sq_wqe->byte_20,
 				     V2_UD_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_M,
 				     V2_UD_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_S,
-				     sge_ind & (qp->sge.sge_cnt - 1));
+				     sge_idx & (qp->sge.sge_cnt - 1));
 
 			roce_set_field(ud_sq_wqe->byte_24,
 				       V2_UD_SEND_WQE_BYTE_24_UDPSPN_M,
@@ -389,7 +434,7 @@
 			roce_set_field(ud_sq_wqe->byte_36,
 				       V2_UD_SEND_WQE_BYTE_36_VLAN_M,
 				       V2_UD_SEND_WQE_BYTE_36_VLAN_S,
-				       le16_to_cpu(ah->av.vlan));
+				       ah->av.vlan_id);
 			roce_set_field(ud_sq_wqe->byte_36,
 				       V2_UD_SEND_WQE_BYTE_36_HOPLIMIT_M,
 				       V2_UD_SEND_WQE_BYTE_36_HOPLIMIT_S,
@@ -423,13 +468,10 @@
 			memcpy(&ud_sq_wqe->dgid[0], &ah->av.dgid[0],
 			       GID_LEN_V2);
 
-			set_extend_sge(qp, wr, &sge_ind);
-			ind++;
+			set_extend_sge(qp, wr, &sge_idx, valid_num_sge);
 		} else if (ibqp->qp_type == IB_QPT_RC) {
 			rc_sq_wqe = wqe;
 			memset(rc_sq_wqe, 0, sizeof(*rc_sq_wqe));
-			for (i = 0; i < wr->num_sge; i++)
-				tmp_len += wr->sg_list[i].length;
 
 			rc_sq_wqe->msg_len =
 			 cpu_to_le32(le32_to_cpu(rc_sq_wqe->msg_len) + tmp_len);
@@ -550,15 +592,14 @@
 				roce_set_field(rc_sq_wqe->byte_16,
 					       V2_RC_SEND_WQE_BYTE_16_SGE_NUM_M,
 					       V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S,
-					       wr->num_sge);
+					       valid_num_sge);
 			} else if (wr->opcode != IB_WR_REG_MR) {
 				ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe,
-							wqe, &sge_ind, bad_wr);
+							wqe, &sge_idx,
+							valid_num_sge, bad_wr);
 				if (ret)
 					goto out;
 			}
-
-			ind++;
 		} else {
 			dev_err(dev, "Illegal qp_type(0x%x)\n", ibqp->qp_type);
 			spin_unlock_irqrestore(&qp->sq.lock, flags);
@@ -570,39 +611,10 @@
 out:
 	if (likely(nreq)) {
 		qp->sq.head += nreq;
+		qp->next_sge = sge_idx;
 		/* Memory barrier */
 		wmb();
-
-		sq_db.byte_4 = 0;
-		sq_db.parameter = 0;
-
-		roce_set_field(sq_db.byte_4, V2_DB_BYTE_4_TAG_M,
-			       V2_DB_BYTE_4_TAG_S, qp->doorbell_qpn);
-		roce_set_field(sq_db.byte_4, V2_DB_BYTE_4_CMD_M,
-			       V2_DB_BYTE_4_CMD_S, HNS_ROCE_V2_SQ_DB);
-		roce_set_field(sq_db.parameter, V2_DB_PARAMETER_IDX_M,
-			       V2_DB_PARAMETER_IDX_S,
-			       qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1));
-		roce_set_field(sq_db.parameter, V2_DB_PARAMETER_SL_M,
-			       V2_DB_PARAMETER_SL_S, qp->sl);
-
-		hns_roce_write64(hr_dev, (__le32 *)&sq_db, qp->sq.db_reg_l);
-
-		qp->sq_next_wqe = ind;
-		qp->next_sge = sge_ind;
-
-		if (qp->state == IB_QPS_ERR) {
-			attr_mask = IB_QP_STATE;
-			attr.qp_state = IB_QPS_ERR;
-
-			ret = hns_roce_v2_modify_qp(&qp->ibqp, &attr, attr_mask,
-						    qp->state, IB_QPS_ERR);
-			if (ret) {
-				spin_unlock_irqrestore(&qp->sq.lock, flags);
-				*bad_wr = wr;
-				return ret;
-			}
-		}
+		update_sq_db(hr_dev, qp);
 	}
 
 	spin_unlock_irqrestore(&qp->sq.lock, flags);
@@ -610,6 +622,17 @@
 	return ret;
 }
 
+static int check_recv_valid(struct hns_roce_dev *hr_dev,
+			    struct hns_roce_qp *hr_qp)
+{
+	if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN))
+		return -EIO;
+	else if (hr_qp->state == IB_QPS_RESET)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int hns_roce_v2_post_recv(struct ib_qp *ibqp,
 				 const struct ib_recv_wr *wr,
 				 const struct ib_recv_wr **bad_wr)
@@ -619,22 +642,20 @@
 	struct hns_roce_v2_wqe_data_seg *dseg;
 	struct hns_roce_rinl_sge *sge_list;
 	struct device *dev = hr_dev->dev;
-	struct ib_qp_attr attr;
 	unsigned long flags;
 	void *wqe = NULL;
-	int attr_mask;
-	int ret = 0;
+	u32 wqe_idx;
 	int nreq;
-	int ind;
+	int ret;
 	int i;
 
 	spin_lock_irqsave(&hr_qp->rq.lock, flags);
-	ind = hr_qp->rq.head & (hr_qp->rq.wqe_cnt - 1);
 
-	if (hr_qp->state == IB_QPS_RESET) {
-		spin_unlock_irqrestore(&hr_qp->rq.lock, flags);
+	ret = check_recv_valid(hr_dev, hr_qp);
+	if (ret) {
 		*bad_wr = wr;
-		return -EINVAL;
+		nreq = 0;
+		goto out;
 	}
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
@@ -645,6 +666,8 @@
 			goto out;
 		}
 
+		wqe_idx = (hr_qp->rq.head + nreq) & (hr_qp->rq.wqe_cnt - 1);
+
 		if (unlikely(wr->num_sge > hr_qp->rq.max_gs)) {
 			dev_err(dev, "rq:num_sge=%d > qp->sq.max_gs=%d\n",
 				wr->num_sge, hr_qp->rq.max_gs);
@@ -653,7 +676,7 @@
 			goto out;
 		}
 
-		wqe = get_recv_wqe(hr_qp, ind);
+		wqe = get_recv_wqe(hr_qp, wqe_idx);
 		dseg = (struct hns_roce_v2_wqe_data_seg *)wqe;
 		for (i = 0; i < wr->num_sge; i++) {
 			if (!wr->sg_list[i].length)
@@ -669,8 +692,8 @@
 
 		/* rq support inline data */
 		if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) {
-			sge_list = hr_qp->rq_inl_buf.wqe_list[ind].sg_list;
-			hr_qp->rq_inl_buf.wqe_list[ind].sge_cnt =
+			sge_list = hr_qp->rq_inl_buf.wqe_list[wqe_idx].sg_list;
+			hr_qp->rq_inl_buf.wqe_list[wqe_idx].sge_cnt =
 							       (u32)wr->num_sge;
 			for (i = 0; i < wr->num_sge; i++) {
 				sge_list[i].addr =
@@ -679,9 +702,7 @@
 			}
 		}
 
-		hr_qp->rq.wrid[ind] = wr->wr_id;
-
-		ind = (ind + 1) & (hr_qp->rq.wqe_cnt - 1);
+		hr_qp->rq.wrid[wqe_idx] = wr->wr_id;
 	}
 
 out:
@@ -690,20 +711,21 @@
 		/* Memory barrier */
 		wmb();
 
-		*hr_qp->rdb.db_record = hr_qp->rq.head & 0xffff;
-
+		/*
+		 * Hip08 hardware cannot flush the WQEs in RQ if the QP state
+		 * gets into errored mode. Hence, as a workaround to this
+		 * hardware limitation, driver needs to assist in flushing. But
+		 * the flushing operation uses mailbox to convey the QP state to
+		 * the hardware and which can sleep due to the mutex protection
+		 * around the mailbox calls. Hence, use the deferred flush for
+		 * now.
+		 */
 		if (hr_qp->state == IB_QPS_ERR) {
-			attr_mask = IB_QP_STATE;
-			attr.qp_state = IB_QPS_ERR;
-
-			ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, &attr,
-						    attr_mask, hr_qp->state,
-						    IB_QPS_ERR);
-			if (ret) {
-				spin_unlock_irqrestore(&hr_qp->rq.lock, flags);
-				*bad_wr = wr;
-				return ret;
-			}
+			if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG,
+					      &hr_qp->flush_flag))
+				init_flush_work(hr_dev, hr_qp);
+		} else {
+			*hr_qp->rdb.db_record = hr_qp->rq.head & 0xffff;
 		}
 	}
 	spin_unlock_irqrestore(&hr_qp->rq.lock, flags);
@@ -1006,7 +1028,7 @@
 	u32 timeout = 0;
 	int handle = 0;
 	u16 desc_ret;
-	int ret = 0;
+	int ret;
 	int ntc;
 
 	spin_lock_bh(&csq->lock);
@@ -1051,15 +1073,14 @@
 	if (hns_roce_cmq_csq_done(hr_dev)) {
 		complete = true;
 		handle = 0;
+		ret = 0;
 		while (handle < num) {
 			/* get the result of hardware write back */
 			desc_to_use = &csq->desc[ntc];
 			desc[handle] = *desc_to_use;
 			dev_dbg(hr_dev->dev, "Get cmq desc:\n");
 			desc_ret = le16_to_cpu(desc[handle].retval);
-			if (desc_ret == CMD_EXEC_SUCCESS)
-				ret = 0;
-			else
+			if (unlikely(desc_ret != CMD_EXEC_SUCCESS))
 				ret = -EIO;
 			priv->cmq.last_status = desc_ret;
 			ntc++;
@@ -1254,7 +1275,6 @@
 	}
 
 out:
-	dev_err(hr_dev->dev, "Func clear fail.\n");
 	hns_roce_func_clr_rst_prc(hr_dev, ret, fclr_write_fail_flag);
 }
 
@@ -1346,40 +1366,31 @@
 static int hns_roce_query_pf_timer_resource(struct hns_roce_dev *hr_dev)
 {
 	struct hns_roce_pf_timer_res_a *req_a;
-	struct hns_roce_cmq_desc desc[2];
-	int ret, i;
-
-	for (i = 0; i < 2; i++) {
-		hns_roce_cmq_setup_basic_desc(&desc[i],
-					      HNS_ROCE_OPC_QUERY_PF_TIMER_RES,
-					      true);
+	struct hns_roce_cmq_desc desc;
+	int ret;
 
-		if (i == 0)
-			desc[i].flag |= cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
-		else
-			desc[i].flag &= ~cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
-	}
+	hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_QUERY_PF_TIMER_RES,
+				      true);
 
-	ret = hns_roce_cmq_send(hr_dev, desc, 2);
+	ret = hns_roce_cmq_send(hr_dev, &desc, 1);
 	if (ret)
 		return ret;
 
-	req_a = (struct hns_roce_pf_timer_res_a *)desc[0].data;
+	req_a = (struct hns_roce_pf_timer_res_a *)desc.data;
 
 	hr_dev->caps.qpc_timer_bt_num =
-				roce_get_field(req_a->qpc_timer_bt_idx_num,
-					PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_M,
-					PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_S);
+		roce_get_field(req_a->qpc_timer_bt_idx_num,
+			       PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_M,
+			       PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_S);
 	hr_dev->caps.cqc_timer_bt_num =
-				roce_get_field(req_a->cqc_timer_bt_idx_num,
-					PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_M,
-					PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_S);
+		roce_get_field(req_a->cqc_timer_bt_idx_num,
+			       PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_M,
+			       PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_S);
 
 	return 0;
 }
 
-static int hns_roce_set_vf_switch_param(struct hns_roce_dev *hr_dev,
-						  int vf_id)
+static int hns_roce_set_vf_switch_param(struct hns_roce_dev *hr_dev, int vf_id)
 {
 	struct hns_roce_cmq_desc desc;
 	struct hns_roce_vf_switch *swt;
@@ -1388,13 +1399,12 @@
 	swt = (struct hns_roce_vf_switch *)desc.data;
 	hns_roce_cmq_setup_basic_desc(&desc, HNS_SWITCH_PARAMETER_CFG, true);
 	swt->rocee_sel |= cpu_to_le32(HNS_ICL_SWITCH_CMD_ROCEE_SEL);
-	roce_set_field(swt->fun_id,
-			VF_SWITCH_DATA_FUN_ID_VF_ID_M,
-			VF_SWITCH_DATA_FUN_ID_VF_ID_S,
-			vf_id);
+	roce_set_field(swt->fun_id, VF_SWITCH_DATA_FUN_ID_VF_ID_M,
+		       VF_SWITCH_DATA_FUN_ID_VF_ID_S, vf_id);
 	ret = hns_roce_cmq_send(hr_dev, &desc, 1);
 	if (ret)
 		return ret;
+
 	desc.flag =
 		cpu_to_le16(HNS_ROCE_CMD_FLAG_NO_INTR | HNS_ROCE_CMD_FLAG_IN);
 	desc.flag &= cpu_to_le16(~HNS_ROCE_CMD_FLAG_WR);
@@ -1574,69 +1584,9 @@
 	return hns_roce_cmq_send(hr_dev, &desc, 1);
 }
 
-static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
+static void set_default_caps(struct hns_roce_dev *hr_dev)
 {
 	struct hns_roce_caps *caps = &hr_dev->caps;
-	int ret;
-
-	ret = hns_roce_cmq_query_hw_info(hr_dev);
-	if (ret) {
-		dev_err(hr_dev->dev, "Query hardware version fail, ret = %d.\n",
-			ret);
-		return ret;
-	}
-
-	ret = hns_roce_query_fw_ver(hr_dev);
-	if (ret) {
-		dev_err(hr_dev->dev, "Query firmware version fail, ret = %d.\n",
-			ret);
-		return ret;
-	}
-
-	ret = hns_roce_config_global_param(hr_dev);
-	if (ret) {
-		dev_err(hr_dev->dev, "Configure global param fail, ret = %d.\n",
-			ret);
-		return ret;
-	}
-
-	/* Get pf resource owned by every pf */
-	ret = hns_roce_query_pf_resource(hr_dev);
-	if (ret) {
-		dev_err(hr_dev->dev, "Query pf resource fail, ret = %d.\n",
-			ret);
-		return ret;
-	}
-
-	if (hr_dev->pci_dev->revision == 0x21) {
-		ret = hns_roce_query_pf_timer_resource(hr_dev);
-		if (ret) {
-			dev_err(hr_dev->dev,
-				"Query pf timer resource fail, ret = %d.\n",
-				ret);
-			return ret;
-		}
-	}
-
-	ret = hns_roce_alloc_vf_resource(hr_dev);
-	if (ret) {
-		dev_err(hr_dev->dev, "Allocate vf resource fail, ret = %d.\n",
-			ret);
-		return ret;
-	}
-
-	if (hr_dev->pci_dev->revision == 0x21) {
-		ret = hns_roce_set_vf_switch_param(hr_dev, 0);
-		if (ret) {
-			dev_err(hr_dev->dev,
-				"Set function switch param fail, ret = %d.\n",
-				ret);
-			return ret;
-		}
-	}
-
-	hr_dev->vendor_part_id = hr_dev->pci_dev->device;
-	hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid);
 
 	caps->num_qps		= HNS_ROCE_V2_MAX_QP_NUM;
 	caps->max_wqes		= HNS_ROCE_V2_MAX_WQE_NUM;
@@ -1644,17 +1594,15 @@
 	caps->num_srqs		= HNS_ROCE_V2_MAX_SRQ_NUM;
 	caps->min_cqes		= HNS_ROCE_MIN_CQE_NUM;
 	caps->max_cqes		= HNS_ROCE_V2_MAX_CQE_NUM;
-	caps->max_srqwqes	= HNS_ROCE_V2_MAX_SRQWQE_NUM;
 	caps->max_sq_sg		= HNS_ROCE_V2_MAX_SQ_SGE_NUM;
 	caps->max_extend_sg	= HNS_ROCE_V2_MAX_EXTEND_SGE_NUM;
 	caps->max_rq_sg		= HNS_ROCE_V2_MAX_RQ_SGE_NUM;
 	caps->max_sq_inline	= HNS_ROCE_V2_MAX_SQ_INLINE;
-	caps->max_srq_sg	= HNS_ROCE_V2_MAX_SRQ_SGE_NUM;
 	caps->num_uars		= HNS_ROCE_V2_UAR_NUM;
 	caps->phy_num_uars	= HNS_ROCE_V2_PHY_UAR_NUM;
 	caps->num_aeq_vectors	= HNS_ROCE_V2_AEQE_VEC_NUM;
 	caps->num_comp_vectors	= HNS_ROCE_V2_COMP_VEC_NUM;
-	caps->num_other_vectors	= HNS_ROCE_V2_ABNORMAL_VEC_NUM;
+	caps->num_other_vectors = HNS_ROCE_V2_ABNORMAL_VEC_NUM;
 	caps->num_mtpts		= HNS_ROCE_V2_MAX_MTPT_NUM;
 	caps->num_mtt_segs	= HNS_ROCE_V2_MAX_MTT_SEGS;
 	caps->num_cqe_segs	= HNS_ROCE_V2_MAX_CQE_SEGS;
@@ -1668,12 +1616,12 @@
 	caps->max_srq_desc_sz	= HNS_ROCE_V2_MAX_SRQ_DESC_SZ;
 	caps->qpc_entry_sz	= HNS_ROCE_V2_QPC_ENTRY_SZ;
 	caps->irrl_entry_sz	= HNS_ROCE_V2_IRRL_ENTRY_SZ;
-	caps->trrl_entry_sz	= HNS_ROCE_V2_TRRL_ENTRY_SZ;
+	caps->trrl_entry_sz	= HNS_ROCE_V2_EXT_ATOMIC_TRRL_ENTRY_SZ;
 	caps->cqc_entry_sz	= HNS_ROCE_V2_CQC_ENTRY_SZ;
 	caps->srqc_entry_sz	= HNS_ROCE_V2_SRQC_ENTRY_SZ;
 	caps->mtpt_entry_sz	= HNS_ROCE_V2_MTPT_ENTRY_SZ;
 	caps->mtt_entry_sz	= HNS_ROCE_V2_MTT_ENTRY_SZ;
-	caps->idx_entry_sz	= 4;
+	caps->idx_entry_sz	= HNS_ROCE_V2_IDX_ENTRY_SZ;
 	caps->cq_entry_sz	= HNS_ROCE_V2_CQE_ENTRY_SIZE;
 	caps->page_size_cap	= HNS_ROCE_V2_PAGE_SIZE_SUPPORTED;
 	caps->reserved_lkey	= 0;
@@ -1696,16 +1644,13 @@
 	caps->mpt_ba_pg_sz	= 0;
 	caps->mpt_buf_pg_sz	= 0;
 	caps->mpt_hop_num	= HNS_ROCE_CONTEXT_HOP_NUM;
-	caps->pbl_ba_pg_sz	= 2;
-	caps->pbl_buf_pg_sz	= 0;
-	caps->pbl_hop_num	= HNS_ROCE_PBL_HOP_NUM;
 	caps->mtt_ba_pg_sz	= 0;
 	caps->mtt_buf_pg_sz	= 0;
 	caps->mtt_hop_num	= HNS_ROCE_MTT_HOP_NUM;
-	caps->wqe_sq_hop_num	= 2;
-	caps->wqe_sge_hop_num	= 1;
-	caps->wqe_rq_hop_num	= 2;
-	caps->cqe_ba_pg_sz	= 6;
+	caps->wqe_sq_hop_num	= HNS_ROCE_SQWQE_HOP_NUM;
+	caps->wqe_sge_hop_num	= HNS_ROCE_EXT_SGE_HOP_NUM;
+	caps->wqe_rq_hop_num	= HNS_ROCE_RQWQE_HOP_NUM;
+	caps->cqe_ba_pg_sz	= HNS_ROCE_BA_PG_SZ_SUPPORTED_256K;
 	caps->cqe_buf_pg_sz	= 0;
 	caps->cqe_hop_num	= HNS_ROCE_CQE_HOP_NUM;
 	caps->srqwqe_ba_pg_sz	= 0;
@@ -1714,10 +1659,6 @@
 	caps->idx_ba_pg_sz	= 0;
 	caps->idx_buf_pg_sz	= 0;
 	caps->idx_hop_num	= HNS_ROCE_IDX_HOP_NUM;
-	caps->eqe_ba_pg_sz	= 0;
-	caps->eqe_buf_pg_sz	= 0;
-	caps->eqe_hop_num	= HNS_ROCE_EQE_HOP_NUM;
-	caps->tsq_buf_pg_sz	= 0;
 	caps->chunk_sz		= HNS_ROCE_V2_TABLE_CHUNK_SIZE;
 
 	caps->flags		= HNS_ROCE_CAP_FLAG_REREG_MR |
@@ -1726,24 +1667,19 @@
 				  HNS_ROCE_CAP_FLAG_RECORD_DB |
 				  HNS_ROCE_CAP_FLAG_SQ_RECORD_DB;
 
-	if (hr_dev->pci_dev->revision == 0x21)
-		caps->flags |= HNS_ROCE_CAP_FLAG_MW |
-			       HNS_ROCE_CAP_FLAG_FRMR;
-
 	caps->pkey_table_len[0] = 1;
-	caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM;
+	caps->gid_table_len[0]	= HNS_ROCE_V2_GID_INDEX_NUM;
 	caps->ceqe_depth	= HNS_ROCE_V2_COMP_EQE_NUM;
 	caps->aeqe_depth	= HNS_ROCE_V2_ASYNC_EQE_NUM;
 	caps->local_ca_ack_delay = 0;
 	caps->max_mtu = IB_MTU_4096;
 
-	caps->max_srqs		= HNS_ROCE_V2_MAX_SRQ;
 	caps->max_srq_wrs	= HNS_ROCE_V2_MAX_SRQ_WR;
 	caps->max_srq_sges	= HNS_ROCE_V2_MAX_SRQ_SGE;
 
-	if (hr_dev->pci_dev->revision == 0x21) {
-		caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC |
-			       HNS_ROCE_CAP_FLAG_SRQ |
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP08_B) {
+		caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC | HNS_ROCE_CAP_FLAG_MW |
+			       HNS_ROCE_CAP_FLAG_SRQ | HNS_ROCE_CAP_FLAG_FRMR |
 			       HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL;
 
 		caps->num_qpc_timer	  = HNS_ROCE_V2_MAX_QPC_TIMER_NUM;
@@ -1757,12 +1693,343 @@
 		caps->cqc_timer_buf_pg_sz = 0;
 		caps->cqc_timer_hop_num   = HNS_ROCE_HOP_NUM_0;
 
-		caps->sccc_entry_sz	= HNS_ROCE_V2_SCCC_ENTRY_SZ;
-		caps->sccc_ba_pg_sz	= 0;
-		caps->sccc_buf_pg_sz    = 0;
-		caps->sccc_hop_num	= HNS_ROCE_SCCC_HOP_NUM;
+		caps->sccc_entry_sz	  = HNS_ROCE_V2_SCCC_ENTRY_SZ;
+		caps->sccc_ba_pg_sz	  = 0;
+		caps->sccc_buf_pg_sz	  = 0;
+		caps->sccc_hop_num	  = HNS_ROCE_SCCC_HOP_NUM;
+	}
+}
+
+static void calc_pg_sz(int obj_num, int obj_size, int hop_num, int ctx_bt_num,
+		       int *buf_page_size, int *bt_page_size, u32 hem_type)
+{
+	u64 obj_per_chunk;
+	int bt_chunk_size = 1 << PAGE_SHIFT;
+	int buf_chunk_size = 1 << PAGE_SHIFT;
+	int obj_per_chunk_default = buf_chunk_size / obj_size;
+
+	*buf_page_size = 0;
+	*bt_page_size = 0;
+
+	switch (hop_num) {
+	case 3:
+		obj_per_chunk = ctx_bt_num * (bt_chunk_size / BA_BYTE_LEN) *
+				(bt_chunk_size / BA_BYTE_LEN) *
+				(bt_chunk_size / BA_BYTE_LEN) *
+				 obj_per_chunk_default;
+		break;
+	case 2:
+		obj_per_chunk = ctx_bt_num * (bt_chunk_size / BA_BYTE_LEN) *
+				(bt_chunk_size / BA_BYTE_LEN) *
+				 obj_per_chunk_default;
+		break;
+	case 1:
+		obj_per_chunk = ctx_bt_num * (bt_chunk_size / BA_BYTE_LEN) *
+				obj_per_chunk_default;
+		break;
+	case HNS_ROCE_HOP_NUM_0:
+		obj_per_chunk = ctx_bt_num * obj_per_chunk_default;
+		break;
+	default:
+		pr_err("Table %d not support hop_num = %d!\n", hem_type,
+			hop_num);
+		return;
+	}
+
+	if (hem_type >= HEM_TYPE_MTT)
+		*bt_page_size = ilog2(DIV_ROUND_UP(obj_num, obj_per_chunk));
+	else
+		*buf_page_size = ilog2(DIV_ROUND_UP(obj_num, obj_per_chunk));
+}
+
+static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
+{
+	struct hns_roce_cmq_desc desc[HNS_ROCE_QUERY_PF_CAPS_CMD_NUM];
+	struct hns_roce_caps *caps = &hr_dev->caps;
+	struct hns_roce_query_pf_caps_a *resp_a;
+	struct hns_roce_query_pf_caps_b *resp_b;
+	struct hns_roce_query_pf_caps_c *resp_c;
+	struct hns_roce_query_pf_caps_d *resp_d;
+	struct hns_roce_query_pf_caps_e *resp_e;
+	int ctx_hop_num;
+	int pbl_hop_num;
+	int ret;
+	int i;
+
+	for (i = 0; i < HNS_ROCE_QUERY_PF_CAPS_CMD_NUM; i++) {
+		hns_roce_cmq_setup_basic_desc(&desc[i],
+					      HNS_ROCE_OPC_QUERY_PF_CAPS_NUM,
+					      true);
+		if (i < (HNS_ROCE_QUERY_PF_CAPS_CMD_NUM - 1))
+			desc[i].flag |= cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
+		else
+			desc[i].flag &= ~cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
+	}
+
+	ret = hns_roce_cmq_send(hr_dev, desc, HNS_ROCE_QUERY_PF_CAPS_CMD_NUM);
+	if (ret)
+		return ret;
+
+	resp_a = (struct hns_roce_query_pf_caps_a *)desc[0].data;
+	resp_b = (struct hns_roce_query_pf_caps_b *)desc[1].data;
+	resp_c = (struct hns_roce_query_pf_caps_c *)desc[2].data;
+	resp_d = (struct hns_roce_query_pf_caps_d *)desc[3].data;
+	resp_e = (struct hns_roce_query_pf_caps_e *)desc[4].data;
+
+	caps->local_ca_ack_delay     = resp_a->local_ca_ack_delay;
+	caps->max_sq_sg		     = le16_to_cpu(resp_a->max_sq_sg);
+	caps->max_sq_inline	     = le16_to_cpu(resp_a->max_sq_inline);
+	caps->max_rq_sg		     = le16_to_cpu(resp_a->max_rq_sg);
+	caps->max_extend_sg	     = le32_to_cpu(resp_a->max_extend_sg);
+	caps->num_qpc_timer	     = le16_to_cpu(resp_a->num_qpc_timer);
+	caps->num_cqc_timer	     = le16_to_cpu(resp_a->num_cqc_timer);
+	caps->max_srq_sges	     = le16_to_cpu(resp_a->max_srq_sges);
+	caps->num_aeq_vectors	     = resp_a->num_aeq_vectors;
+	caps->num_other_vectors	     = resp_a->num_other_vectors;
+	caps->max_sq_desc_sz	     = resp_a->max_sq_desc_sz;
+	caps->max_rq_desc_sz	     = resp_a->max_rq_desc_sz;
+	caps->max_srq_desc_sz	     = resp_a->max_srq_desc_sz;
+	caps->cq_entry_sz	     = resp_a->cq_entry_sz;
+
+	caps->mtpt_entry_sz	     = resp_b->mtpt_entry_sz;
+	caps->irrl_entry_sz	     = resp_b->irrl_entry_sz;
+	caps->trrl_entry_sz	     = resp_b->trrl_entry_sz;
+	caps->cqc_entry_sz	     = resp_b->cqc_entry_sz;
+	caps->srqc_entry_sz	     = resp_b->srqc_entry_sz;
+	caps->idx_entry_sz	     = resp_b->idx_entry_sz;
+	caps->sccc_entry_sz	     = resp_b->scc_ctx_entry_sz;
+	caps->max_mtu		     = resp_b->max_mtu;
+	caps->qpc_entry_sz	     = le16_to_cpu(resp_b->qpc_entry_sz);
+	caps->min_cqes		     = resp_b->min_cqes;
+	caps->min_wqes		     = resp_b->min_wqes;
+	caps->page_size_cap	     = le32_to_cpu(resp_b->page_size_cap);
+	caps->pkey_table_len[0]	     = resp_b->pkey_table_len;
+	caps->phy_num_uars	     = resp_b->phy_num_uars;
+	ctx_hop_num		     = resp_b->ctx_hop_num;
+	pbl_hop_num		     = resp_b->pbl_hop_num;
+
+	caps->num_pds = 1 << roce_get_field(resp_c->cap_flags_num_pds,
+					    V2_QUERY_PF_CAPS_C_NUM_PDS_M,
+					    V2_QUERY_PF_CAPS_C_NUM_PDS_S);
+	caps->flags = roce_get_field(resp_c->cap_flags_num_pds,
+				     V2_QUERY_PF_CAPS_C_CAP_FLAGS_M,
+				     V2_QUERY_PF_CAPS_C_CAP_FLAGS_S);
+	caps->num_cqs = 1 << roce_get_field(resp_c->max_gid_num_cqs,
+					    V2_QUERY_PF_CAPS_C_NUM_CQS_M,
+					    V2_QUERY_PF_CAPS_C_NUM_CQS_S);
+	caps->gid_table_len[0] = roce_get_field(resp_c->max_gid_num_cqs,
+						V2_QUERY_PF_CAPS_C_MAX_GID_M,
+						V2_QUERY_PF_CAPS_C_MAX_GID_S);
+	caps->max_cqes = 1 << roce_get_field(resp_c->cq_depth,
+					     V2_QUERY_PF_CAPS_C_CQ_DEPTH_M,
+					     V2_QUERY_PF_CAPS_C_CQ_DEPTH_S);
+	caps->num_mtpts = 1 << roce_get_field(resp_c->num_mrws,
+					      V2_QUERY_PF_CAPS_C_NUM_MRWS_M,
+					      V2_QUERY_PF_CAPS_C_NUM_MRWS_S);
+	caps->num_qps = 1 << roce_get_field(resp_c->ord_num_qps,
+					    V2_QUERY_PF_CAPS_C_NUM_QPS_M,
+					    V2_QUERY_PF_CAPS_C_NUM_QPS_S);
+	caps->max_qp_init_rdma = roce_get_field(resp_c->ord_num_qps,
+						V2_QUERY_PF_CAPS_C_MAX_ORD_M,
+						V2_QUERY_PF_CAPS_C_MAX_ORD_S);
+	caps->max_qp_dest_rdma = caps->max_qp_init_rdma;
+	caps->max_wqes = 1 << le16_to_cpu(resp_c->sq_depth);
+	caps->num_srqs = 1 << roce_get_field(resp_d->wq_hop_num_max_srqs,
+					     V2_QUERY_PF_CAPS_D_NUM_SRQS_M,
+					     V2_QUERY_PF_CAPS_D_NUM_SRQS_S);
+	caps->max_srq_wrs = 1 << le16_to_cpu(resp_d->srq_depth);
+	caps->ceqe_depth = 1 << roce_get_field(resp_d->num_ceqs_ceq_depth,
+					       V2_QUERY_PF_CAPS_D_CEQ_DEPTH_M,
+					       V2_QUERY_PF_CAPS_D_CEQ_DEPTH_S);
+	caps->num_comp_vectors = roce_get_field(resp_d->num_ceqs_ceq_depth,
+						V2_QUERY_PF_CAPS_D_NUM_CEQS_M,
+						V2_QUERY_PF_CAPS_D_NUM_CEQS_S);
+	caps->aeqe_depth = 1 << roce_get_field(resp_d->arm_st_aeq_depth,
+					       V2_QUERY_PF_CAPS_D_AEQ_DEPTH_M,
+					       V2_QUERY_PF_CAPS_D_AEQ_DEPTH_S);
+	caps->default_aeq_arm_st = roce_get_field(resp_d->arm_st_aeq_depth,
+					    V2_QUERY_PF_CAPS_D_AEQ_ARM_ST_M,
+					    V2_QUERY_PF_CAPS_D_AEQ_ARM_ST_S);
+	caps->default_ceq_arm_st = roce_get_field(resp_d->arm_st_aeq_depth,
+					    V2_QUERY_PF_CAPS_D_CEQ_ARM_ST_M,
+					    V2_QUERY_PF_CAPS_D_CEQ_ARM_ST_S);
+	caps->reserved_pds = roce_get_field(resp_d->num_uars_rsv_pds,
+					    V2_QUERY_PF_CAPS_D_RSV_PDS_M,
+					    V2_QUERY_PF_CAPS_D_RSV_PDS_S);
+	caps->num_uars = 1 << roce_get_field(resp_d->num_uars_rsv_pds,
+					     V2_QUERY_PF_CAPS_D_NUM_UARS_M,
+					     V2_QUERY_PF_CAPS_D_NUM_UARS_S);
+	caps->reserved_qps = roce_get_field(resp_d->rsv_uars_rsv_qps,
+					    V2_QUERY_PF_CAPS_D_RSV_QPS_M,
+					    V2_QUERY_PF_CAPS_D_RSV_QPS_S);
+	caps->reserved_uars = roce_get_field(resp_d->rsv_uars_rsv_qps,
+					     V2_QUERY_PF_CAPS_D_RSV_UARS_M,
+					     V2_QUERY_PF_CAPS_D_RSV_UARS_S);
+	caps->reserved_mrws = roce_get_field(resp_e->chunk_size_shift_rsv_mrws,
+					     V2_QUERY_PF_CAPS_E_RSV_MRWS_M,
+					     V2_QUERY_PF_CAPS_E_RSV_MRWS_S);
+	caps->chunk_sz = 1 << roce_get_field(resp_e->chunk_size_shift_rsv_mrws,
+					 V2_QUERY_PF_CAPS_E_CHUNK_SIZE_SHIFT_M,
+					 V2_QUERY_PF_CAPS_E_CHUNK_SIZE_SHIFT_S);
+	caps->reserved_cqs = roce_get_field(resp_e->rsv_cqs,
+					    V2_QUERY_PF_CAPS_E_RSV_CQS_M,
+					    V2_QUERY_PF_CAPS_E_RSV_CQS_S);
+	caps->reserved_srqs = roce_get_field(resp_e->rsv_srqs,
+					     V2_QUERY_PF_CAPS_E_RSV_SRQS_M,
+					     V2_QUERY_PF_CAPS_E_RSV_SRQS_S);
+	caps->reserved_lkey = roce_get_field(resp_e->rsv_lkey,
+					     V2_QUERY_PF_CAPS_E_RSV_LKEYS_M,
+					     V2_QUERY_PF_CAPS_E_RSV_LKEYS_S);
+	caps->default_ceq_max_cnt = le16_to_cpu(resp_e->ceq_max_cnt);
+	caps->default_ceq_period = le16_to_cpu(resp_e->ceq_period);
+	caps->default_aeq_max_cnt = le16_to_cpu(resp_e->aeq_max_cnt);
+	caps->default_aeq_period = le16_to_cpu(resp_e->aeq_period);
+
+	caps->qpc_timer_entry_sz = HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ;
+	caps->cqc_timer_entry_sz = HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ;
+	caps->mtt_entry_sz = HNS_ROCE_V2_MTT_ENTRY_SZ;
+	caps->num_mtt_segs = HNS_ROCE_V2_MAX_MTT_SEGS;
+	caps->mtt_ba_pg_sz = 0;
+	caps->num_cqe_segs = HNS_ROCE_V2_MAX_CQE_SEGS;
+	caps->num_srqwqe_segs = HNS_ROCE_V2_MAX_SRQWQE_SEGS;
+	caps->num_idx_segs = HNS_ROCE_V2_MAX_IDX_SEGS;
+
+	caps->qpc_hop_num = ctx_hop_num;
+	caps->srqc_hop_num = ctx_hop_num;
+	caps->cqc_hop_num = ctx_hop_num;
+	caps->mpt_hop_num = ctx_hop_num;
+	caps->mtt_hop_num = pbl_hop_num;
+	caps->cqe_hop_num = pbl_hop_num;
+	caps->srqwqe_hop_num = pbl_hop_num;
+	caps->idx_hop_num = pbl_hop_num;
+	caps->wqe_sq_hop_num = roce_get_field(resp_d->wq_hop_num_max_srqs,
+					  V2_QUERY_PF_CAPS_D_SQWQE_HOP_NUM_M,
+					  V2_QUERY_PF_CAPS_D_SQWQE_HOP_NUM_S);
+	caps->wqe_sge_hop_num = roce_get_field(resp_d->wq_hop_num_max_srqs,
+					  V2_QUERY_PF_CAPS_D_EX_SGE_HOP_NUM_M,
+					  V2_QUERY_PF_CAPS_D_EX_SGE_HOP_NUM_S);
+	caps->wqe_rq_hop_num = roce_get_field(resp_d->wq_hop_num_max_srqs,
+					  V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_M,
+					  V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_S);
+
+	calc_pg_sz(caps->num_qps, caps->qpc_entry_sz, caps->qpc_hop_num,
+		   caps->qpc_bt_num, &caps->qpc_buf_pg_sz, &caps->qpc_ba_pg_sz,
+		   HEM_TYPE_QPC);
+	calc_pg_sz(caps->num_mtpts, caps->mtpt_entry_sz, caps->mpt_hop_num,
+		   caps->mpt_bt_num, &caps->mpt_buf_pg_sz, &caps->mpt_ba_pg_sz,
+		   HEM_TYPE_MTPT);
+	calc_pg_sz(caps->num_cqs, caps->cqc_entry_sz, caps->cqc_hop_num,
+		   caps->cqc_bt_num, &caps->cqc_buf_pg_sz, &caps->cqc_ba_pg_sz,
+		   HEM_TYPE_CQC);
+	calc_pg_sz(caps->num_srqs, caps->srqc_entry_sz, caps->srqc_hop_num,
+		   caps->srqc_bt_num, &caps->srqc_buf_pg_sz,
+		   &caps->srqc_ba_pg_sz, HEM_TYPE_SRQC);
+
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP08_B) {
+		caps->sccc_hop_num = ctx_hop_num;
+		caps->qpc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
+		caps->cqc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
+
+		calc_pg_sz(caps->num_qps, caps->sccc_entry_sz,
+			   caps->sccc_hop_num, caps->sccc_bt_num,
+			   &caps->sccc_buf_pg_sz, &caps->sccc_ba_pg_sz,
+			   HEM_TYPE_SCCC);
+		calc_pg_sz(caps->num_cqc_timer, caps->cqc_timer_entry_sz,
+			   caps->cqc_timer_hop_num, caps->cqc_timer_bt_num,
+			   &caps->cqc_timer_buf_pg_sz,
+			   &caps->cqc_timer_ba_pg_sz, HEM_TYPE_CQC_TIMER);
+	}
+
+	calc_pg_sz(caps->num_cqe_segs, caps->mtt_entry_sz, caps->cqe_hop_num,
+		   1, &caps->cqe_buf_pg_sz, &caps->cqe_ba_pg_sz, HEM_TYPE_CQE);
+	calc_pg_sz(caps->num_srqwqe_segs, caps->mtt_entry_sz,
+		   caps->srqwqe_hop_num, 1, &caps->srqwqe_buf_pg_sz,
+		   &caps->srqwqe_ba_pg_sz, HEM_TYPE_SRQWQE);
+	calc_pg_sz(caps->num_idx_segs, caps->idx_entry_sz, caps->idx_hop_num,
+		   1, &caps->idx_buf_pg_sz, &caps->idx_ba_pg_sz, HEM_TYPE_IDX);
+
+	return 0;
+}
+
+static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
+{
+	struct hns_roce_caps *caps = &hr_dev->caps;
+	int ret;
+
+	ret = hns_roce_cmq_query_hw_info(hr_dev);
+	if (ret) {
+		dev_err(hr_dev->dev, "Query hardware version fail, ret = %d.\n",
+			ret);
+		return ret;
+	}
+
+	ret = hns_roce_query_fw_ver(hr_dev);
+	if (ret) {
+		dev_err(hr_dev->dev, "Query firmware version fail, ret = %d.\n",
+			ret);
+		return ret;
+	}
+
+	ret = hns_roce_config_global_param(hr_dev);
+	if (ret) {
+		dev_err(hr_dev->dev, "Configure global param fail, ret = %d.\n",
+			ret);
+		return ret;
+	}
+
+	/* Get pf resource owned by every pf */
+	ret = hns_roce_query_pf_resource(hr_dev);
+	if (ret) {
+		dev_err(hr_dev->dev, "Query pf resource fail, ret = %d.\n",
+			ret);
+		return ret;
+	}
+
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP08_B) {
+		ret = hns_roce_query_pf_timer_resource(hr_dev);
+		if (ret) {
+			dev_err(hr_dev->dev,
+				"Query pf timer resource fail, ret = %d.\n",
+				ret);
+			return ret;
+		}
+
+		ret = hns_roce_set_vf_switch_param(hr_dev, 0);
+		if (ret) {
+			dev_err(hr_dev->dev,
+				"Set function switch param fail, ret = %d.\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = hns_roce_alloc_vf_resource(hr_dev);
+	if (ret) {
+		dev_err(hr_dev->dev, "Allocate vf resource fail, ret = %d.\n",
+			ret);
+		return ret;
 	}
 
+	hr_dev->vendor_part_id = hr_dev->pci_dev->device;
+	hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid);
+
+	caps->num_mtt_segs	= HNS_ROCE_V2_MAX_MTT_SEGS;
+	caps->num_cqe_segs	= HNS_ROCE_V2_MAX_CQE_SEGS;
+	caps->num_srqwqe_segs	= HNS_ROCE_V2_MAX_SRQWQE_SEGS;
+	caps->num_idx_segs	= HNS_ROCE_V2_MAX_IDX_SEGS;
+
+	caps->pbl_ba_pg_sz	= HNS_ROCE_BA_PG_SZ_SUPPORTED_16K;
+	caps->pbl_buf_pg_sz	= 0;
+	caps->pbl_hop_num	= HNS_ROCE_PBL_HOP_NUM;
+	caps->eqe_ba_pg_sz	= 0;
+	caps->eqe_buf_pg_sz	= 0;
+	caps->eqe_hop_num	= HNS_ROCE_EQE_HOP_NUM;
+	caps->tsq_buf_pg_sz	= 0;
+
+	ret = hns_roce_query_pf_caps(hr_dev);
+	if (ret)
+		set_default_caps(hr_dev);
+
 	ret = hns_roce_v2_set_bt(hr_dev);
 	if (ret)
 		dev_err(hr_dev->dev, "Configure bt attribute fail, ret = %d.\n",
@@ -1818,37 +2085,32 @@
 			req_a->base_addr_h =
 				cpu_to_le32(link_tbl->table.map >> 32);
 			roce_set_field(req_a->depth_pgsz_init_en,
-				       CFG_LLM_QUE_DEPTH_M,
-				       CFG_LLM_QUE_DEPTH_S,
+				       CFG_LLM_QUE_DEPTH_M, CFG_LLM_QUE_DEPTH_S,
 				       link_tbl->npages);
 			roce_set_field(req_a->depth_pgsz_init_en,
-				       CFG_LLM_QUE_PGSZ_M,
-				       CFG_LLM_QUE_PGSZ_S,
+				       CFG_LLM_QUE_PGSZ_M, CFG_LLM_QUE_PGSZ_S,
 				       link_tbl->pg_sz);
 			req_a->head_ba_l = cpu_to_le32(entry[0].blk_ba0);
 			req_a->head_ba_h_nxtptr =
 				cpu_to_le32(entry[0].blk_ba1_nxt_ptr);
-			roce_set_field(req_a->head_ptr,
-				       CFG_LLM_HEAD_PTR_M,
+			roce_set_field(req_a->head_ptr, CFG_LLM_HEAD_PTR_M,
 				       CFG_LLM_HEAD_PTR_S, 0);
 		} else {
 			req_b->tail_ba_l =
 				cpu_to_le32(entry[page_num - 1].blk_ba0);
-			roce_set_field(req_b->tail_ba_h,
-				       CFG_LLM_TAIL_BA_H_M,
+			roce_set_field(req_b->tail_ba_h, CFG_LLM_TAIL_BA_H_M,
 				       CFG_LLM_TAIL_BA_H_S,
 				       entry[page_num - 1].blk_ba1_nxt_ptr &
-				       HNS_ROCE_LINK_TABLE_BA1_M);
-			roce_set_field(req_b->tail_ptr,
-				       CFG_LLM_TAIL_PTR_M,
+					       HNS_ROCE_LINK_TABLE_BA1_M);
+			roce_set_field(req_b->tail_ptr, CFG_LLM_TAIL_PTR_M,
 				       CFG_LLM_TAIL_PTR_S,
 				       (entry[page_num - 2].blk_ba1_nxt_ptr &
-				       HNS_ROCE_LINK_TABLE_NXT_PTR_M) >>
-				       HNS_ROCE_LINK_TABLE_NXT_PTR_S);
+					HNS_ROCE_LINK_TABLE_NXT_PTR_M) >>
+					       HNS_ROCE_LINK_TABLE_NXT_PTR_S);
 		}
 	}
-	roce_set_field(req_a->depth_pgsz_init_en,
-		       CFG_LLM_INIT_EN_M, CFG_LLM_INIT_EN_S, 1);
+	roce_set_field(req_a->depth_pgsz_init_en, CFG_LLM_INIT_EN_M,
+		       CFG_LLM_INIT_EN_S, 1);
 
 	return hns_roce_cmq_send(hr_dev, desc, 2);
 }
@@ -2020,7 +2282,7 @@
 {
 	struct hns_roce_v2_priv *priv = hr_dev->priv;
 
-	if (hr_dev->pci_dev->revision == 0x21)
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP08_B)
 		hns_roce_function_clear(hr_dev);
 
 	hns_roce_free_link_table(hr_dev, &priv->tpq);
@@ -2141,11 +2403,9 @@
 
 	hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_CFG_SGID_TB, false);
 
-	roce_set_field(sgid_tb->table_idx_rsv,
-		       CFG_SGID_TB_TABLE_IDX_M,
+	roce_set_field(sgid_tb->table_idx_rsv, CFG_SGID_TB_TABLE_IDX_M,
 		       CFG_SGID_TB_TABLE_IDX_S, gid_index);
-	roce_set_field(sgid_tb->vf_sgid_type_rsv,
-		       CFG_SGID_TB_VF_SGID_TYPE_M,
+	roce_set_field(sgid_tb->vf_sgid_type_rsv, CFG_SGID_TB_VF_SGID_TYPE_M,
 		       CFG_SGID_TB_VF_SGID_TYPE_S, sgid_type);
 
 	p = (u32 *)&gid->raw[0];
@@ -2416,11 +2676,10 @@
 		       V2_MPT_BYTE_4_MPT_ST_S, V2_MPT_ST_FREE);
 	roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PD_M,
 		       V2_MPT_BYTE_4_PD_S, mw->pdn);
-	roce_set_field(mpt_entry->byte_4_pd_hop_st,
-		       V2_MPT_BYTE_4_PBL_HOP_NUM_M,
+	roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PBL_HOP_NUM_M,
 		       V2_MPT_BYTE_4_PBL_HOP_NUM_S,
-		       mw->pbl_hop_num == HNS_ROCE_HOP_NUM_0 ?
-		       0 : mw->pbl_hop_num);
+		       mw->pbl_hop_num == HNS_ROCE_HOP_NUM_0 ? 0 :
+							       mw->pbl_hop_num);
 	roce_set_field(mpt_entry->byte_4_pd_hop_st,
 		       V2_MPT_BYTE_4_PBL_BA_PG_SZ_M,
 		       V2_MPT_BYTE_4_PBL_BA_PG_SZ_S,
@@ -2428,6 +2687,7 @@
 
 	roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1);
 	roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1);
+	roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_LW_EN_S, 1);
 
 	roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0);
 	roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 1);
@@ -2447,8 +2707,7 @@
 
 static void *get_cqe_v2(struct hns_roce_cq *hr_cq, int n)
 {
-	return hns_roce_buf_offset(&hr_cq->hr_buf.hr_buf,
-				   n * HNS_ROCE_V2_CQE_ENTRY_SIZE);
+	return hns_roce_buf_offset(&hr_cq->buf, n * HNS_ROCE_V2_CQE_ENTRY_SIZE);
 }
 
 static void *get_sw_cqe_v2(struct hns_roce_cq *hr_cq, int n)
@@ -2457,7 +2716,7 @@
 
 	/* Get cqe when Owner bit is Conversely with the MSB of cons_idx */
 	return (roce_get_bit(cqe->byte_4, V2_CQE_BYTE_4_OWNER_S) ^
-		!!(n & (hr_cq->ib_cq.cqe + 1))) ? cqe : NULL;
+		!!(n & hr_cq->cq_depth)) ? cqe : NULL;
 }
 
 static struct hns_roce_v2_cqe *next_cqe_sw_v2(struct hns_roce_cq *hr_cq)
@@ -2483,7 +2742,7 @@
 
 static void hns_roce_v2_cq_set_ci(struct hns_roce_cq *hr_cq, u32 cons_index)
 {
-	*hr_cq->set_ci_db = cons_index & 0xffffff;
+	*hr_cq->set_ci_db = cons_index & V2_CQ_DB_PARAMETER_CONS_IDX_M;
 }
 
 static void __hns_roce_v2_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn,
@@ -2550,8 +2809,7 @@
 
 static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev,
 				  struct hns_roce_cq *hr_cq, void *mb_buf,
-				  u64 *mtts, dma_addr_t dma_handle, int nent,
-				  u32 vector)
+				  u64 *mtts, dma_addr_t dma_handle)
 {
 	struct hns_roce_v2_cq_context *cq_context;
 
@@ -2563,9 +2821,9 @@
 	roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_ARM_ST_M,
 		       V2_CQC_BYTE_4_ARM_ST_S, REG_NXT_CEQE);
 	roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_SHIFT_M,
-		       V2_CQC_BYTE_4_SHIFT_S, ilog2((unsigned int)nent));
+		       V2_CQC_BYTE_4_SHIFT_S, ilog2(hr_cq->cq_depth));
 	roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_CEQN_M,
-		       V2_CQC_BYTE_4_CEQN_S, vector);
+		       V2_CQC_BYTE_4_CEQN_S, hr_cq->vector);
 
 	roce_set_field(cq_context->byte_8_cqn, V2_CQC_BYTE_8_CQN_M,
 		       V2_CQC_BYTE_8_CQN_S, hr_cq->cqn);
@@ -2688,16 +2946,63 @@
 	return 0;
 }
 
+static int sw_comp(struct hns_roce_qp *hr_qp, struct hns_roce_wq *wq,
+		   int num_entries, struct ib_wc *wc)
+{
+	unsigned int left;
+	int npolled = 0;
+
+	left = wq->head - wq->tail;
+	if (left == 0)
+		return 0;
+
+	left = min_t(unsigned int, (unsigned int)num_entries, left);
+	while (npolled < left) {
+		wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+		wc->status = IB_WC_WR_FLUSH_ERR;
+		wc->vendor_err = 0;
+		wc->qp = &hr_qp->ibqp;
+
+		wq->tail++;
+		wc++;
+		npolled++;
+	}
+
+	return npolled;
+}
+
+static int hns_roce_v2_sw_poll_cq(struct hns_roce_cq *hr_cq, int num_entries,
+				  struct ib_wc *wc)
+{
+	struct hns_roce_qp *hr_qp;
+	int npolled = 0;
+
+	list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) {
+		npolled += sw_comp(hr_qp, &hr_qp->sq,
+				   num_entries - npolled, wc + npolled);
+		if (npolled >= num_entries)
+			goto out;
+	}
+
+	list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) {
+		npolled += sw_comp(hr_qp, &hr_qp->rq,
+				   num_entries - npolled, wc + npolled);
+		if (npolled >= num_entries)
+			goto out;
+	}
+
+out:
+	return npolled;
+}
+
 static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq,
 				struct hns_roce_qp **cur_qp, struct ib_wc *wc)
 {
+	struct hns_roce_dev *hr_dev = to_hr_dev(hr_cq->ib_cq.device);
 	struct hns_roce_srq *srq = NULL;
-	struct hns_roce_dev *hr_dev;
 	struct hns_roce_v2_cqe *cqe;
 	struct hns_roce_qp *hr_qp;
 	struct hns_roce_wq *wq;
-	struct ib_qp_attr attr;
-	int attr_mask;
 	int is_send;
 	u16 wqe_ctr;
 	u32 opcode;
@@ -2721,7 +3026,6 @@
 				V2_CQE_BYTE_16_LCL_QPN_S);
 
 	if (!*cur_qp || (qpn & HNS_ROCE_V2_CQE_QPN_MASK) != (*cur_qp)->qpn) {
-		hr_dev = to_hr_dev(hr_cq->ib_cq.device);
 		hr_qp = __hns_roce_qp_lookup(hr_dev, qpn);
 		if (unlikely(!hr_qp)) {
 			dev_err(hr_dev->dev, "CQ %06lx with entry for unknown QPN %06x\n",
@@ -2731,6 +3035,7 @@
 		*cur_qp = hr_qp;
 	}
 
+	hr_qp = *cur_qp;
 	wc->qp = &(*cur_qp)->ibqp;
 	wc->vendor_err = 0;
 
@@ -2815,14 +3120,24 @@
 		break;
 	}
 
-	/* flush cqe if wc status is error, excluding flush error */
-	if ((wc->status != IB_WC_SUCCESS) &&
-	    (wc->status != IB_WC_WR_FLUSH_ERR)) {
-		attr_mask = IB_QP_STATE;
-		attr.qp_state = IB_QPS_ERR;
-		return hns_roce_v2_modify_qp(&(*cur_qp)->ibqp,
-					     &attr, attr_mask,
-					     (*cur_qp)->state, IB_QPS_ERR);
+	/*
+	 * Hip08 hardware cannot flush the WQEs in SQ/RQ if the QP state gets
+	 * into errored mode. Hence, as a workaround to this hardware
+	 * limitation, driver needs to assist in flushing. But the flushing
+	 * operation uses mailbox to convey the QP state to the hardware and
+	 * which can sleep due to the mutex protection around the mailbox calls.
+	 * Hence, use the deferred flush for now. Once wc error detected, the
+	 * flushing operation is needed.
+	 */
+	if (wc->status != IB_WC_SUCCESS &&
+	    wc->status != IB_WC_WR_FLUSH_ERR) {
+		dev_err(hr_dev->dev, "error cqe status is: 0x%x\n",
+			status & HNS_ROCE_V2_CQE_STATUS_MASK);
+
+		if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &hr_qp->flush_flag))
+			init_flush_work(hr_dev, hr_qp);
+
+		return 0;
 	}
 
 	if (wc->status == IB_WC_WR_FLUSH_ERR)
@@ -2968,6 +3283,7 @@
 static int hns_roce_v2_poll_cq(struct ib_cq *ibcq, int num_entries,
 			       struct ib_wc *wc)
 {
+	struct hns_roce_dev *hr_dev = to_hr_dev(ibcq->device);
 	struct hns_roce_cq *hr_cq = to_hr_cq(ibcq);
 	struct hns_roce_qp *cur_qp = NULL;
 	unsigned long flags;
@@ -2975,6 +3291,18 @@
 
 	spin_lock_irqsave(&hr_cq->lock, flags);
 
+	/*
+	 * When the device starts to reset, the state is RST_DOWN. At this time,
+	 * there may still be some valid CQEs in the hardware that are not
+	 * polled. Therefore, it is not allowed to switch to the software mode
+	 * immediately. When the state changes to UNINIT, CQE no longer exists
+	 * in the hardware, and then switch to software mode.
+	 */
+	if (hr_dev->state == HNS_ROCE_DEVICE_STATE_UNINIT) {
+		npolled = hns_roce_v2_sw_poll_cq(hr_cq, num_entries, wc);
+		goto out;
+	}
+
 	for (npolled = 0; npolled < num_entries; ++npolled) {
 		if (hns_roce_v2_poll_one(hr_cq, &cur_qp, wc + npolled))
 			break;
@@ -2986,6 +3314,7 @@
 		hns_roce_v2_cq_set_ci(hr_cq, hr_cq->cons_index);
 	}
 
+out:
 	spin_unlock_irqrestore(&hr_cq->lock, flags);
 
 	return npolled;
@@ -3160,8 +3489,6 @@
 }
 
 static int hns_roce_v2_qp_modify(struct hns_roce_dev *hr_dev,
-				 enum ib_qp_state cur_state,
-				 enum ib_qp_state new_state,
 				 struct hns_roce_v2_qp_context *context,
 				 struct hns_roce_qp *hr_qp)
 {
@@ -3211,6 +3538,9 @@
 	roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S,
 		     !!(access_flags & IB_ACCESS_REMOTE_ATOMIC));
 	roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S, 0);
+	roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_EXT_ATE_S,
+		     !!(access_flags & IB_ACCESS_REMOTE_ATOMIC));
+	roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_EXT_ATE_S, 0);
 }
 
 static void set_qpc_wqe_cnt(struct hns_roce_qp *hr_qp,
@@ -3578,6 +3908,12 @@
 			     IB_ACCESS_REMOTE_ATOMIC));
 		roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S,
 			     0);
+		roce_set_bit(context->byte_76_srqn_op_en,
+			     V2_QPC_BYTE_76_EXT_ATE_S,
+			     !!(attr->qp_access_flags &
+				IB_ACCESS_REMOTE_ATOMIC));
+		roce_set_bit(qpc_mask->byte_76_srqn_op_en,
+			     V2_QPC_BYTE_76_EXT_ATE_S, 0);
 	} else {
 		roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RRE_S,
 			     !!(hr_qp->access_flags & IB_ACCESS_REMOTE_READ));
@@ -3593,6 +3929,11 @@
 			     !!(hr_qp->access_flags & IB_ACCESS_REMOTE_ATOMIC));
 		roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S,
 			     0);
+		roce_set_bit(context->byte_76_srqn_op_en,
+			     V2_QPC_BYTE_76_EXT_ATE_S,
+			     !!(hr_qp->access_flags & IB_ACCESS_REMOTE_ATOMIC));
+		roce_set_bit(qpc_mask->byte_76_srqn_op_en,
+			     V2_QPC_BYTE_76_EXT_ATE_S, 0);
 	}
 
 	roce_set_field(context->byte_16_buf_ba_pg_sz, V2_QPC_BYTE_16_PD_M,
@@ -3839,13 +4180,11 @@
 	/* Configure GID index */
 	port_num = rdma_ah_get_port_num(&attr->ah_attr);
 	roce_set_field(context->byte_20_smac_sgid_idx,
-		       V2_QPC_BYTE_20_SGID_IDX_M,
-		       V2_QPC_BYTE_20_SGID_IDX_S,
+		       V2_QPC_BYTE_20_SGID_IDX_M, V2_QPC_BYTE_20_SGID_IDX_S,
 		       hns_get_gid_index(hr_dev, port_num - 1,
 					 grh->sgid_index));
 	roce_set_field(qpc_mask->byte_20_smac_sgid_idx,
-		       V2_QPC_BYTE_20_SGID_IDX_M,
-		       V2_QPC_BYTE_20_SGID_IDX_S, 0);
+		       V2_QPC_BYTE_20_SGID_IDX_M, V2_QPC_BYTE_20_SGID_IDX_S, 0);
 	memcpy(&(context->dmac), dmac, sizeof(u32));
 	roce_set_field(context->byte_52_udpspn_dmac, V2_QPC_BYTE_52_DMAC_M,
 		       V2_QPC_BYTE_52_DMAC_S, *((u16 *)(&dmac[4])));
@@ -4061,8 +4400,8 @@
 	struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
 	const struct ib_gid_attr *gid_attr = NULL;
 	int is_roce_protocol;
+	u16 vlan_id = 0xffff;
 	bool is_udp = false;
-	u16 vlan = 0xffff;
 	u8 ib_port;
 	u8 hr_port;
 	int ret;
@@ -4074,7 +4413,7 @@
 
 	if (is_roce_protocol) {
 		gid_attr = attr->ah_attr.grh.sgid_attr;
-		ret = rdma_read_gid_l2_fields(gid_attr, &vlan, NULL);
+		ret = rdma_read_gid_l2_fields(gid_attr, &vlan_id, NULL);
 		if (ret)
 			return ret;
 
@@ -4083,7 +4422,7 @@
 				 IB_GID_TYPE_ROCE_UDP_ENCAP);
 	}
 
-	if (vlan < VLAN_CFI_MASK) {
+	if (vlan_id < VLAN_N_VID) {
 		roce_set_bit(context->byte_76_srqn_op_en,
 			     V2_QPC_BYTE_76_RQ_VLAN_EN_S, 1);
 		roce_set_bit(qpc_mask->byte_76_srqn_op_en,
@@ -4095,7 +4434,7 @@
 	}
 
 	roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M,
-		       V2_QPC_BYTE_24_VLAN_ID_S, vlan);
+		       V2_QPC_BYTE_24_VLAN_ID_S, vlan_id);
 	roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M,
 		       V2_QPC_BYTE_24_VLAN_ID_S, 0);
 
@@ -4129,7 +4468,7 @@
 	roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_HOP_LIMIT_M,
 		       V2_QPC_BYTE_24_HOP_LIMIT_S, 0);
 
-	if (hr_dev->pci_dev->revision == 0x21 && is_udp)
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP08_B && is_udp)
 		roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M,
 			       V2_QPC_BYTE_24_TC_S, grh->traffic_class >> 2);
 	else
@@ -4235,8 +4574,7 @@
 
 		roce_set_field(context->byte_212_lsn,
 			       V2_QPC_BYTE_212_RETRY_CNT_M,
-			       V2_QPC_BYTE_212_RETRY_CNT_S,
-			       attr->retry_cnt);
+			       V2_QPC_BYTE_212_RETRY_CNT_S, attr->retry_cnt);
 		roce_set_field(qpc_mask->byte_212_lsn,
 			       V2_QPC_BYTE_212_RETRY_CNT_M,
 			       V2_QPC_BYTE_212_RETRY_CNT_S, 0);
@@ -4390,6 +4728,8 @@
 	struct hns_roce_v2_qp_context *context = ctx;
 	struct hns_roce_v2_qp_context *qpc_mask = ctx + 1;
 	struct device *dev = hr_dev->dev;
+	unsigned long sq_flag = 0;
+	unsigned long rq_flag = 0;
 	int ret;
 
 	/*
@@ -4407,6 +4747,8 @@
 
 	/* When QP state is err, SQ and RQ WQE should be flushed */
 	if (new_state == IB_QPS_ERR) {
+		spin_lock_irqsave(&hr_qp->sq.lock, sq_flag);
+		hr_qp->state = IB_QPS_ERR;
 		roce_set_field(context->byte_160_sq_ci_pi,
 			       V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M,
 			       V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S,
@@ -4414,8 +4756,10 @@
 		roce_set_field(qpc_mask->byte_160_sq_ci_pi,
 			       V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M,
 			       V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S, 0);
+		spin_unlock_irqrestore(&hr_qp->sq.lock, sq_flag);
 
 		if (!ibqp->srq) {
+			spin_lock_irqsave(&hr_qp->rq.lock, rq_flag);
 			roce_set_field(context->byte_84_rq_ci_pi,
 			       V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M,
 			       V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S,
@@ -4423,6 +4767,7 @@
 			roce_set_field(qpc_mask->byte_84_rq_ci_pi,
 			       V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M,
 			       V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S, 0);
+			spin_unlock_irqrestore(&hr_qp->rq.lock, rq_flag);
 		}
 	}
 
@@ -4444,7 +4789,7 @@
 		       V2_QPC_BYTE_60_QP_ST_S, 0);
 
 	/* SW pass context to HW */
-	ret = hns_roce_v2_qp_modify(hr_dev, cur_state, new_state, ctx, hr_qp);
+	ret = hns_roce_v2_qp_modify(hr_dev, ctx, hr_qp);
 	if (ret) {
 		dev_err(dev, "hns_roce_qp_modify failed(%d)\n", ret);
 		goto out;
@@ -4465,7 +4810,6 @@
 		hr_qp->rq.tail = 0;
 		hr_qp->sq.head = 0;
 		hr_qp->sq.tail = 0;
-		hr_qp->sq_next_wqe = 0;
 		hr_qp->next_sge = 0;
 		if (hr_qp->rq.wqe_cnt)
 			*hr_qp->rdb.db_record = 0;
@@ -4562,7 +4906,7 @@
 	qp_attr->path_mig_state = IB_MIG_ARMED;
 	qp_attr->ah_attr.type   = RDMA_AH_ATTR_TYPE_ROCE;
 	if (hr_qp->ibqp.qp_type == IB_QPT_UD)
-		qp_attr->qkey = V2_QKEY_VAL;
+		qp_attr->qkey = le32_to_cpu(context.qkey_xrcd);
 
 	qp_attr->rq_psn = roce_get_field(context.byte_108_rx_reqepsn,
 					 V2_QPC_BYTE_108_RX_REQ_EPSN_M,
@@ -4620,9 +4964,11 @@
 					      V2_QPC_BYTE_28_AT_M,
 					      V2_QPC_BYTE_28_AT_S);
 	qp_attr->retry_cnt = roce_get_field(context.byte_212_lsn,
-					    V2_QPC_BYTE_212_RETRY_CNT_M,
-					    V2_QPC_BYTE_212_RETRY_CNT_S);
-	qp_attr->rnr_retry = le32_to_cpu(context.rq_rnr_timer);
+					    V2_QPC_BYTE_212_RETRY_NUM_INIT_M,
+					    V2_QPC_BYTE_212_RETRY_NUM_INIT_S);
+	qp_attr->rnr_retry = roce_get_field(context.byte_244_rnr_rxack,
+					    V2_QPC_BYTE_244_RNR_NUM_INIT_M,
+					    V2_QPC_BYTE_244_RNR_NUM_INIT_S);
 
 done:
 	qp_attr->cur_qp_state = qp_attr->qp_state;
@@ -4638,6 +4984,7 @@
 	}
 
 	qp_init_attr->cap = qp_attr->cap;
+	qp_init_attr->sq_sig_type = hr_qp->sq_signal_bits;
 
 out:
 	mutex_unlock(&hr_qp->mutex);
@@ -4650,72 +4997,41 @@
 {
 	struct hns_roce_cq *send_cq, *recv_cq;
 	struct ib_device *ibdev = &hr_dev->ib_dev;
-	int ret;
+	unsigned long flags;
+	int ret = 0;
 
 	if (hr_qp->ibqp.qp_type == IB_QPT_RC && hr_qp->state != IB_QPS_RESET) {
 		/* Modify qp to reset before destroying qp */
 		ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0,
 					    hr_qp->state, IB_QPS_RESET);
-		if (ret) {
+		if (ret)
 			ibdev_err(ibdev, "modify QP to Reset failed.\n");
-			return ret;
-		}
 	}
 
-	send_cq = to_hr_cq(hr_qp->ibqp.send_cq);
-	recv_cq = to_hr_cq(hr_qp->ibqp.recv_cq);
+	send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL;
+	recv_cq = hr_qp->ibqp.recv_cq ? to_hr_cq(hr_qp->ibqp.recv_cq) : NULL;
 
+	spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
 	hns_roce_lock_cqs(send_cq, recv_cq);
 
 	if (!udata) {
-		__hns_roce_v2_cq_clean(recv_cq, hr_qp->qpn, hr_qp->ibqp.srq ?
-				       to_hr_srq(hr_qp->ibqp.srq) : NULL);
-		if (send_cq != recv_cq)
+		if (recv_cq)
+			__hns_roce_v2_cq_clean(recv_cq, hr_qp->qpn,
+					       (hr_qp->ibqp.srq ?
+						to_hr_srq(hr_qp->ibqp.srq) :
+						NULL));
+
+		if (send_cq && send_cq != recv_cq)
 			__hns_roce_v2_cq_clean(send_cq, hr_qp->qpn, NULL);
+
 	}
 
 	hns_roce_qp_remove(hr_dev, hr_qp);
 
 	hns_roce_unlock_cqs(send_cq, recv_cq);
+	spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
 
-	hns_roce_qp_free(hr_dev, hr_qp);
-
-	/* Not special_QP, free their QPN */
-	if ((hr_qp->ibqp.qp_type == IB_QPT_RC) ||
-	    (hr_qp->ibqp.qp_type == IB_QPT_UC) ||
-	    (hr_qp->ibqp.qp_type == IB_QPT_UD))
-		hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1);
-
-	hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
-
-	if (udata) {
-		struct hns_roce_ucontext *context =
-			rdma_udata_to_drv_context(
-				udata,
-				struct hns_roce_ucontext,
-				ibucontext);
-
-		if (hr_qp->sq.wqe_cnt && (hr_qp->sdb_en == 1))
-			hns_roce_db_unmap_user(context, &hr_qp->sdb);
-
-		if (hr_qp->rq.wqe_cnt && (hr_qp->rdb_en == 1))
-			hns_roce_db_unmap_user(context, &hr_qp->rdb);
-	} else {
-		kfree(hr_qp->sq.wrid);
-		kfree(hr_qp->rq.wrid);
-		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
-		if (hr_qp->rq.wqe_cnt)
-			hns_roce_free_db(hr_dev, &hr_qp->rdb);
-	}
-	ib_umem_release(hr_qp->umem);
-
-	if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
-	     hr_qp->rq.wqe_cnt) {
-		kfree(hr_qp->rq_inl_buf.wqe_list[0].sg_list);
-		kfree(hr_qp->rq_inl_buf.wqe_list);
-	}
-
-	return 0;
+	return ret;
 }
 
 static int hns_roce_v2_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
@@ -4725,16 +5041,11 @@
 	int ret;
 
 	ret = hns_roce_v2_destroy_qp_common(hr_dev, hr_qp, udata);
-	if (ret) {
+	if (ret)
 		ibdev_err(&hr_dev->ib_dev, "Destroy qp 0x%06lx failed(%d)\n",
 			  hr_qp->qpn, ret);
-		return ret;
-	}
 
-	if (hr_qp->ibqp.qp_type == IB_QPT_GSI)
-		kfree(hr_to_hr_sqp(hr_qp));
-	else
-		kfree(hr_qp);
+	hns_roce_qp_destroy(hr_dev, hr_qp, udata);
 
 	return 0;
 }
@@ -4833,39 +5144,6 @@
 	return ret;
 }
 
-static void hns_roce_set_qps_to_err(struct hns_roce_dev *hr_dev, u32 qpn)
-{
-	struct hns_roce_qp *hr_qp;
-	struct ib_qp_attr attr;
-	int attr_mask;
-	int ret;
-
-	hr_qp = __hns_roce_qp_lookup(hr_dev, qpn);
-	if (!hr_qp) {
-		dev_warn(hr_dev->dev, "no hr_qp can be found!\n");
-		return;
-	}
-
-	if (hr_qp->ibqp.uobject) {
-		if (hr_qp->sdb_en == 1) {
-			hr_qp->sq.head = *(int *)(hr_qp->sdb.virt_addr);
-			if (hr_qp->rdb_en == 1)
-				hr_qp->rq.head = *(int *)(hr_qp->rdb.virt_addr);
-		} else {
-			dev_warn(hr_dev->dev, "flush cqe is unsupported in userspace!\n");
-			return;
-		}
-	}
-
-	attr_mask = IB_QP_STATE;
-	attr.qp_state = IB_QPS_ERR;
-	ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, &attr, attr_mask,
-				    hr_qp->state, IB_QPS_ERR);
-	if (ret)
-		dev_err(hr_dev->dev, "failed to modify qp %d to err state.\n",
-			qpn);
-}
-
 static void hns_roce_irq_work_handle(struct work_struct *work)
 {
 	struct hns_roce_work *irq_work =
@@ -4889,17 +5167,14 @@
 	case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
 		dev_err(dev, "Local work queue 0x%x catas error, sub_type:%d\n",
 			qpn, irq_work->sub_type);
-		hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
 		break;
 	case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
 		dev_err(dev, "Invalid request local work queue 0x%x error.\n",
 			qpn);
-		hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
 		break;
 	case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
 		dev_err(dev, "Local access violation work queue 0x%x error, sub_type:%d\n",
 			qpn, irq_work->sub_type);
-		hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
 		break;
 	case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH:
 		dev_warn(dev, "SRQ limit reach.\n");
@@ -4951,10 +5226,7 @@
 static void set_eq_cons_index_v2(struct hns_roce_eq *eq)
 {
 	struct hns_roce_dev *hr_dev = eq->hr_dev;
-	__le32 doorbell[2];
-
-	doorbell[0] = 0;
-	doorbell[1] = 0;
+	__le32 doorbell[2] = {};
 
 	if (eq->type_flag == HNS_ROCE_AEQ) {
 		roce_set_field(doorbell[0], HNS_ROCE_V2_EQ_DB_CMD_M,
@@ -4980,44 +5252,24 @@
 	hns_roce_write64(hr_dev, doorbell, eq->doorbell);
 }
 
-static struct hns_roce_aeqe *get_aeqe_v2(struct hns_roce_eq *eq, u32 entry)
-{
-	u32 buf_chk_sz;
-	unsigned long off;
-
-	buf_chk_sz = 1 << (eq->eqe_buf_pg_sz + PAGE_SHIFT);
-	off = (entry & (eq->entries - 1)) * HNS_ROCE_AEQ_ENTRY_SIZE;
-
-	return (struct hns_roce_aeqe *)((char *)(eq->buf_list->buf) +
-		off % buf_chk_sz);
-}
-
-static struct hns_roce_aeqe *mhop_get_aeqe(struct hns_roce_eq *eq, u32 entry)
+static inline void *get_eqe_buf(struct hns_roce_eq *eq, unsigned long offset)
 {
 	u32 buf_chk_sz;
-	unsigned long off;
 
 	buf_chk_sz = 1 << (eq->eqe_buf_pg_sz + PAGE_SHIFT);
-
-	off = (entry & (eq->entries - 1)) * HNS_ROCE_AEQ_ENTRY_SIZE;
-
-	if (eq->hop_num == HNS_ROCE_HOP_NUM_0)
-		return (struct hns_roce_aeqe *)((u8 *)(eq->bt_l0) +
-			off % buf_chk_sz);
+	if (eq->buf.nbufs == 1)
+		return eq->buf.direct.buf + offset % buf_chk_sz;
 	else
-		return (struct hns_roce_aeqe *)((u8 *)
-			(eq->buf[off / buf_chk_sz]) + off % buf_chk_sz);
+		return eq->buf.page_list[offset / buf_chk_sz].buf +
+		       offset % buf_chk_sz;
 }
 
 static struct hns_roce_aeqe *next_aeqe_sw_v2(struct hns_roce_eq *eq)
 {
 	struct hns_roce_aeqe *aeqe;
 
-	if (!eq->hop_num)
-		aeqe = get_aeqe_v2(eq, eq->cons_index);
-	else
-		aeqe = mhop_get_aeqe(eq, eq->cons_index);
-
+	aeqe = get_eqe_buf(eq, (eq->cons_index & (eq->entries - 1)) *
+			   HNS_ROCE_AEQ_ENTRY_SIZE);
 	return (roce_get_bit(aeqe->asyn, HNS_ROCE_V2_AEQ_AEQE_OWNER_S) ^
 		!!(eq->cons_index & eq->entries)) ? aeqe : NULL;
 }
@@ -5110,44 +5362,12 @@
 	return aeqe_found;
 }
 
-static struct hns_roce_ceqe *get_ceqe_v2(struct hns_roce_eq *eq, u32 entry)
-{
-	u32 buf_chk_sz;
-	unsigned long off;
-
-	buf_chk_sz = 1 << (eq->eqe_buf_pg_sz + PAGE_SHIFT);
-	off = (entry & (eq->entries - 1)) * HNS_ROCE_CEQ_ENTRY_SIZE;
-
-	return (struct hns_roce_ceqe *)((char *)(eq->buf_list->buf) +
-		off % buf_chk_sz);
-}
-
-static struct hns_roce_ceqe *mhop_get_ceqe(struct hns_roce_eq *eq, u32 entry)
-{
-	u32 buf_chk_sz;
-	unsigned long off;
-
-	buf_chk_sz = 1 << (eq->eqe_buf_pg_sz + PAGE_SHIFT);
-
-	off = (entry & (eq->entries - 1)) * HNS_ROCE_CEQ_ENTRY_SIZE;
-
-	if (eq->hop_num == HNS_ROCE_HOP_NUM_0)
-		return (struct hns_roce_ceqe *)((u8 *)(eq->bt_l0) +
-			off % buf_chk_sz);
-	else
-		return (struct hns_roce_ceqe *)((u8 *)(eq->buf[off /
-			buf_chk_sz]) + off % buf_chk_sz);
-}
-
 static struct hns_roce_ceqe *next_ceqe_sw_v2(struct hns_roce_eq *eq)
 {
 	struct hns_roce_ceqe *ceqe;
 
-	if (!eq->hop_num)
-		ceqe = get_ceqe_v2(eq, eq->cons_index);
-	else
-		ceqe = mhop_get_ceqe(eq, eq->cons_index);
-
+	ceqe = get_eqe_buf(eq, (eq->cons_index & (eq->entries - 1)) *
+			   HNS_ROCE_CEQ_ENTRY_SIZE);
 	return (!!(roce_get_bit(ceqe->comp, HNS_ROCE_V2_CEQ_CEQE_OWNER_S))) ^
 		(!!(eq->cons_index & eq->entries)) ? ceqe : NULL;
 }
@@ -5166,8 +5386,7 @@
 		 */
 		dma_rmb();
 
-		cqn = roce_get_field(ceqe->comp,
-				     HNS_ROCE_V2_CEQE_COMP_CQN_M,
+		cqn = roce_get_field(ceqe->comp, HNS_ROCE_V2_CEQE_COMP_CQN_M,
 				     HNS_ROCE_V2_CEQE_COMP_CQN_S);
 
 		hns_roce_cq_completion(hr_dev, cqn);
@@ -5223,8 +5442,8 @@
 
 		dev_err(dev, "AEQ overflow!\n");
 
-		int_st |= 1 << HNS_ROCE_V2_VF_INT_ST_AEQ_OVERFLOW_S;
-		roce_write(hr_dev, ROCEE_VF_ABN_INT_ST_REG, int_st);
+		roce_write(hr_dev, ROCEE_VF_ABN_INT_ST_REG,
+			   1 << HNS_ROCE_V2_VF_INT_ST_AEQ_OVERFLOW_S);
 
 		/* Set reset level for reset_event() */
 		if (ops->set_default_reset_request)
@@ -5308,90 +5527,11 @@
 		dev_err(dev, "[mailbox cmd] destroy eqc(%d) failed.\n", eqn);
 }
 
-static void hns_roce_mhop_free_eq(struct hns_roce_dev *hr_dev,
-				  struct hns_roce_eq *eq)
-{
-	struct device *dev = hr_dev->dev;
-	u64 idx;
-	u64 size;
-	u32 buf_chk_sz;
-	u32 bt_chk_sz;
-	u32 mhop_num;
-	int eqe_alloc;
-	int i = 0;
-	int j = 0;
-
-	mhop_num = hr_dev->caps.eqe_hop_num;
-	buf_chk_sz = 1 << (hr_dev->caps.eqe_buf_pg_sz + PAGE_SHIFT);
-	bt_chk_sz = 1 << (hr_dev->caps.eqe_ba_pg_sz + PAGE_SHIFT);
-
-	if (mhop_num == HNS_ROCE_HOP_NUM_0) {
-		dma_free_coherent(dev, (unsigned int)(eq->entries *
-				  eq->eqe_size), eq->bt_l0, eq->l0_dma);
-		return;
-	}
-
-	dma_free_coherent(dev, bt_chk_sz, eq->bt_l0, eq->l0_dma);
-	if (mhop_num == 1) {
-		for (i = 0; i < eq->l0_last_num; i++) {
-			if (i == eq->l0_last_num - 1) {
-				eqe_alloc = i * (buf_chk_sz / eq->eqe_size);
-				size = (eq->entries - eqe_alloc) * eq->eqe_size;
-				dma_free_coherent(dev, size, eq->buf[i],
-						  eq->buf_dma[i]);
-				break;
-			}
-			dma_free_coherent(dev, buf_chk_sz, eq->buf[i],
-					  eq->buf_dma[i]);
-		}
-	} else if (mhop_num == 2) {
-		for (i = 0; i < eq->l0_last_num; i++) {
-			dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
-					  eq->l1_dma[i]);
-
-			for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
-				idx = i * (bt_chk_sz / BA_BYTE_LEN) + j;
-				if ((i == eq->l0_last_num - 1)
-				     && j == eq->l1_last_num - 1) {
-					eqe_alloc = (buf_chk_sz / eq->eqe_size)
-						    * idx;
-					size = (eq->entries - eqe_alloc)
-						* eq->eqe_size;
-					dma_free_coherent(dev, size,
-							  eq->buf[idx],
-							  eq->buf_dma[idx]);
-					break;
-				}
-				dma_free_coherent(dev, buf_chk_sz, eq->buf[idx],
-						  eq->buf_dma[idx]);
-			}
-		}
-	}
-	kfree(eq->buf_dma);
-	kfree(eq->buf);
-	kfree(eq->l1_dma);
-	kfree(eq->bt_l1);
-	eq->buf_dma = NULL;
-	eq->buf = NULL;
-	eq->l1_dma = NULL;
-	eq->bt_l1 = NULL;
-}
-
-static void hns_roce_v2_free_eq(struct hns_roce_dev *hr_dev,
-				struct hns_roce_eq *eq)
+static void free_eq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
 {
-	u32 buf_chk_sz;
-
-	buf_chk_sz = 1 << (eq->eqe_buf_pg_sz + PAGE_SHIFT);
-
-	if (hr_dev->caps.eqe_hop_num) {
-		hns_roce_mhop_free_eq(hr_dev, eq);
-		return;
-	}
-
-	dma_free_coherent(hr_dev->dev, buf_chk_sz, eq->buf_list->buf,
-			  eq->buf_list->map);
-	kfree(eq->buf_list);
+	if (!eq->hop_num || eq->hop_num == HNS_ROCE_HOP_NUM_0)
+		hns_roce_mtr_cleanup(hr_dev, &eq->mtr);
+	hns_roce_buf_free(hr_dev, eq->buf.size, &eq->buf);
 }
 
 static void hns_roce_config_eqc(struct hns_roce_dev *hr_dev,
@@ -5399,6 +5539,8 @@
 				void *mb_buf)
 {
 	struct hns_roce_eq_context *eqc;
+	u64 ba[MTT_MIN_COUNT] = { 0 };
+	int count;
 
 	eqc = mb_buf;
 	memset(eqc, 0, sizeof(struct hns_roce_eq_context));
@@ -5414,349 +5556,211 @@
 	eq->eqe_buf_pg_sz = hr_dev->caps.eqe_buf_pg_sz;
 	eq->shift = ilog2((unsigned int)eq->entries);
 
-	if (!eq->hop_num)
-		eq->eqe_ba = eq->buf_list->map;
-	else
-		eq->eqe_ba = eq->l0_dma;
+	/* if not muti-hop, eqe buffer only use one trunk */
+	if (!eq->hop_num || eq->hop_num == HNS_ROCE_HOP_NUM_0) {
+		eq->eqe_ba = eq->buf.direct.map;
+		eq->cur_eqe_ba = eq->eqe_ba;
+		if (eq->buf.npages > 1)
+			eq->nxt_eqe_ba = eq->eqe_ba + (1 << eq->eqe_buf_pg_sz);
+		else
+			eq->nxt_eqe_ba = eq->eqe_ba;
+	} else {
+		count = hns_roce_mtr_find(hr_dev, &eq->mtr, 0, ba,
+					  MTT_MIN_COUNT, &eq->eqe_ba);
+		eq->cur_eqe_ba = ba[0];
+		if (count > 1)
+			eq->nxt_eqe_ba = ba[1];
+		else
+			eq->nxt_eqe_ba = ba[0];
+	}
 
 	/* set eqc state */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_EQ_ST_M,
-		       HNS_ROCE_EQC_EQ_ST_S,
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_EQ_ST_M, HNS_ROCE_EQC_EQ_ST_S,
 		       HNS_ROCE_V2_EQ_STATE_VALID);
 
 	/* set eqe hop num */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_HOP_NUM_M,
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_HOP_NUM_M,
 		       HNS_ROCE_EQC_HOP_NUM_S, eq->hop_num);
 
 	/* set eqc over_ignore */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_OVER_IGNORE_M,
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_OVER_IGNORE_M,
 		       HNS_ROCE_EQC_OVER_IGNORE_S, eq->over_ignore);
 
 	/* set eqc coalesce */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_COALESCE_M,
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_COALESCE_M,
 		       HNS_ROCE_EQC_COALESCE_S, eq->coalesce);
 
 	/* set eqc arm_state */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_ARM_ST_M,
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_ARM_ST_M,
 		       HNS_ROCE_EQC_ARM_ST_S, eq->arm_st);
 
 	/* set eqn */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_EQN_M,
-		       HNS_ROCE_EQC_EQN_S, eq->eqn);
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_EQN_M, HNS_ROCE_EQC_EQN_S,
+		       eq->eqn);
 
 	/* set eqe_cnt */
-	roce_set_field(eqc->byte_4,
-		       HNS_ROCE_EQC_EQE_CNT_M,
-		       HNS_ROCE_EQC_EQE_CNT_S,
-		       HNS_ROCE_EQ_INIT_EQE_CNT);
+	roce_set_field(eqc->byte_4, HNS_ROCE_EQC_EQE_CNT_M,
+		       HNS_ROCE_EQC_EQE_CNT_S, HNS_ROCE_EQ_INIT_EQE_CNT);
 
 	/* set eqe_ba_pg_sz */
-	roce_set_field(eqc->byte_8,
-		       HNS_ROCE_EQC_BA_PG_SZ_M,
+	roce_set_field(eqc->byte_8, HNS_ROCE_EQC_BA_PG_SZ_M,
 		       HNS_ROCE_EQC_BA_PG_SZ_S,
 		       eq->eqe_ba_pg_sz + PG_SHIFT_OFFSET);
 
 	/* set eqe_buf_pg_sz */
-	roce_set_field(eqc->byte_8,
-		       HNS_ROCE_EQC_BUF_PG_SZ_M,
+	roce_set_field(eqc->byte_8, HNS_ROCE_EQC_BUF_PG_SZ_M,
 		       HNS_ROCE_EQC_BUF_PG_SZ_S,
 		       eq->eqe_buf_pg_sz + PG_SHIFT_OFFSET);
 
 	/* set eq_producer_idx */
-	roce_set_field(eqc->byte_8,
-		       HNS_ROCE_EQC_PROD_INDX_M,
-		       HNS_ROCE_EQC_PROD_INDX_S,
-		       HNS_ROCE_EQ_INIT_PROD_IDX);
+	roce_set_field(eqc->byte_8, HNS_ROCE_EQC_PROD_INDX_M,
+		       HNS_ROCE_EQC_PROD_INDX_S, HNS_ROCE_EQ_INIT_PROD_IDX);
 
 	/* set eq_max_cnt */
-	roce_set_field(eqc->byte_12,
-		       HNS_ROCE_EQC_MAX_CNT_M,
+	roce_set_field(eqc->byte_12, HNS_ROCE_EQC_MAX_CNT_M,
 		       HNS_ROCE_EQC_MAX_CNT_S, eq->eq_max_cnt);
 
 	/* set eq_period */
-	roce_set_field(eqc->byte_12,
-		       HNS_ROCE_EQC_PERIOD_M,
+	roce_set_field(eqc->byte_12, HNS_ROCE_EQC_PERIOD_M,
 		       HNS_ROCE_EQC_PERIOD_S, eq->eq_period);
 
 	/* set eqe_report_timer */
-	roce_set_field(eqc->eqe_report_timer,
-		       HNS_ROCE_EQC_REPORT_TIMER_M,
+	roce_set_field(eqc->eqe_report_timer, HNS_ROCE_EQC_REPORT_TIMER_M,
 		       HNS_ROCE_EQC_REPORT_TIMER_S,
 		       HNS_ROCE_EQ_INIT_REPORT_TIMER);
 
 	/* set eqe_ba [34:3] */
-	roce_set_field(eqc->eqe_ba0,
-		       HNS_ROCE_EQC_EQE_BA_L_M,
+	roce_set_field(eqc->eqe_ba0, HNS_ROCE_EQC_EQE_BA_L_M,
 		       HNS_ROCE_EQC_EQE_BA_L_S, eq->eqe_ba >> 3);
 
 	/* set eqe_ba [64:35] */
-	roce_set_field(eqc->eqe_ba1,
-		       HNS_ROCE_EQC_EQE_BA_H_M,
+	roce_set_field(eqc->eqe_ba1, HNS_ROCE_EQC_EQE_BA_H_M,
 		       HNS_ROCE_EQC_EQE_BA_H_S, eq->eqe_ba >> 35);
 
 	/* set eq shift */
-	roce_set_field(eqc->byte_28,
-		       HNS_ROCE_EQC_SHIFT_M,
-		       HNS_ROCE_EQC_SHIFT_S, eq->shift);
+	roce_set_field(eqc->byte_28, HNS_ROCE_EQC_SHIFT_M, HNS_ROCE_EQC_SHIFT_S,
+		       eq->shift);
 
 	/* set eq MSI_IDX */
-	roce_set_field(eqc->byte_28,
-		       HNS_ROCE_EQC_MSI_INDX_M,
-		       HNS_ROCE_EQC_MSI_INDX_S,
-		       HNS_ROCE_EQ_INIT_MSI_IDX);
+	roce_set_field(eqc->byte_28, HNS_ROCE_EQC_MSI_INDX_M,
+		       HNS_ROCE_EQC_MSI_INDX_S, HNS_ROCE_EQ_INIT_MSI_IDX);
 
 	/* set cur_eqe_ba [27:12] */
-	roce_set_field(eqc->byte_28,
-		       HNS_ROCE_EQC_CUR_EQE_BA_L_M,
+	roce_set_field(eqc->byte_28, HNS_ROCE_EQC_CUR_EQE_BA_L_M,
 		       HNS_ROCE_EQC_CUR_EQE_BA_L_S, eq->cur_eqe_ba >> 12);
 
 	/* set cur_eqe_ba [59:28] */
-	roce_set_field(eqc->byte_32,
-		       HNS_ROCE_EQC_CUR_EQE_BA_M_M,
+	roce_set_field(eqc->byte_32, HNS_ROCE_EQC_CUR_EQE_BA_M_M,
 		       HNS_ROCE_EQC_CUR_EQE_BA_M_S, eq->cur_eqe_ba >> 28);
 
 	/* set cur_eqe_ba [63:60] */
-	roce_set_field(eqc->byte_36,
-		       HNS_ROCE_EQC_CUR_EQE_BA_H_M,
+	roce_set_field(eqc->byte_36, HNS_ROCE_EQC_CUR_EQE_BA_H_M,
 		       HNS_ROCE_EQC_CUR_EQE_BA_H_S, eq->cur_eqe_ba >> 60);
 
 	/* set eq consumer idx */
-	roce_set_field(eqc->byte_36,
-		       HNS_ROCE_EQC_CONS_INDX_M,
-		       HNS_ROCE_EQC_CONS_INDX_S,
-		       HNS_ROCE_EQ_INIT_CONS_IDX);
+	roce_set_field(eqc->byte_36, HNS_ROCE_EQC_CONS_INDX_M,
+		       HNS_ROCE_EQC_CONS_INDX_S, HNS_ROCE_EQ_INIT_CONS_IDX);
 
 	/* set nex_eqe_ba[43:12] */
-	roce_set_field(eqc->nxt_eqe_ba0,
-		       HNS_ROCE_EQC_NXT_EQE_BA_L_M,
+	roce_set_field(eqc->nxt_eqe_ba0, HNS_ROCE_EQC_NXT_EQE_BA_L_M,
 		       HNS_ROCE_EQC_NXT_EQE_BA_L_S, eq->nxt_eqe_ba >> 12);
 
 	/* set nex_eqe_ba[63:44] */
-	roce_set_field(eqc->nxt_eqe_ba1,
-		       HNS_ROCE_EQC_NXT_EQE_BA_H_M,
+	roce_set_field(eqc->nxt_eqe_ba1, HNS_ROCE_EQC_NXT_EQE_BA_H_M,
 		       HNS_ROCE_EQC_NXT_EQE_BA_H_S, eq->nxt_eqe_ba >> 44);
 }
 
-static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
-				  struct hns_roce_eq *eq)
+static int map_eq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq,
+		      u32 page_shift)
 {
-	struct device *dev = hr_dev->dev;
-	int eq_alloc_done = 0;
-	int eq_buf_cnt = 0;
-	int eqe_alloc;
-	u32 buf_chk_sz;
-	u32 bt_chk_sz;
-	u32 mhop_num;
-	u64 size;
-	u64 idx;
+	struct hns_roce_buf_region region = {};
+	dma_addr_t *buf_list = NULL;
 	int ba_num;
-	int bt_num;
-	int record_i;
-	int record_j;
-	int i = 0;
-	int j = 0;
-
-	mhop_num = hr_dev->caps.eqe_hop_num;
-	buf_chk_sz = 1 << (hr_dev->caps.eqe_buf_pg_sz + PAGE_SHIFT);
-	bt_chk_sz = 1 << (hr_dev->caps.eqe_ba_pg_sz + PAGE_SHIFT);
+	int ret;
 
 	ba_num = DIV_ROUND_UP(PAGE_ALIGN(eq->entries * eq->eqe_size),
-			      buf_chk_sz);
-	bt_num = DIV_ROUND_UP(ba_num, bt_chk_sz / BA_BYTE_LEN);
-
-	if (mhop_num == HNS_ROCE_HOP_NUM_0) {
-		if (eq->entries > buf_chk_sz / eq->eqe_size) {
-			dev_err(dev, "eq entries %d is larger than buf_pg_sz!",
-				eq->entries);
-			return -EINVAL;
-		}
-		eq->bt_l0 = dma_alloc_coherent(dev, eq->entries * eq->eqe_size,
-					       &(eq->l0_dma), GFP_KERNEL);
-		if (!eq->bt_l0)
-			return -ENOMEM;
+			      1 << page_shift);
+	hns_roce_init_buf_region(&region, hr_dev->caps.eqe_hop_num, 0, ba_num);
 
-		eq->cur_eqe_ba = eq->l0_dma;
-		eq->nxt_eqe_ba = 0;
+	/* alloc a tmp list for storing eq buf address */
+	ret = hns_roce_alloc_buf_list(&region, &buf_list, 1);
+	if (ret) {
+		dev_err(hr_dev->dev, "alloc eq buf_list error\n");
+		return ret;
+	}
 
-		return 0;
+	ba_num = hns_roce_get_kmem_bufs(hr_dev, buf_list, region.count,
+					region.offset, &eq->buf);
+	if (ba_num != region.count) {
+		dev_err(hr_dev->dev, "get eqe buf err,expect %d,ret %d.\n",
+			region.count, ba_num);
+		ret = -ENOBUFS;
+		goto done;
 	}
 
-	eq->buf_dma = kcalloc(ba_num, sizeof(*eq->buf_dma), GFP_KERNEL);
-	if (!eq->buf_dma)
-		return -ENOMEM;
-	eq->buf = kcalloc(ba_num, sizeof(*eq->buf), GFP_KERNEL);
-	if (!eq->buf)
-		goto err_kcalloc_buf;
-
-	if (mhop_num == 2) {
-		eq->l1_dma = kcalloc(bt_num, sizeof(*eq->l1_dma), GFP_KERNEL);
-		if (!eq->l1_dma)
-			goto err_kcalloc_l1_dma;
-
-		eq->bt_l1 = kcalloc(bt_num, sizeof(*eq->bt_l1), GFP_KERNEL);
-		if (!eq->bt_l1)
-			goto err_kcalloc_bt_l1;
-	}
-
-	/* alloc L0 BT */
-	eq->bt_l0 = dma_alloc_coherent(dev, bt_chk_sz, &eq->l0_dma, GFP_KERNEL);
-	if (!eq->bt_l0)
-		goto err_dma_alloc_l0;
-
-	if (mhop_num == 1) {
-		if (ba_num > (bt_chk_sz / BA_BYTE_LEN))
-			dev_err(dev, "ba_num %d is too large for 1 hop\n",
-				ba_num);
-
-		/* alloc buf */
-		for (i = 0; i < bt_chk_sz / BA_BYTE_LEN; i++) {
-			if (eq_buf_cnt + 1 < ba_num) {
-				size = buf_chk_sz;
-			} else {
-				eqe_alloc = i * (buf_chk_sz / eq->eqe_size);
-				size = (eq->entries - eqe_alloc) * eq->eqe_size;
-			}
-			eq->buf[i] = dma_alloc_coherent(dev, size,
-							&(eq->buf_dma[i]),
-							GFP_KERNEL);
-			if (!eq->buf[i])
-				goto err_dma_alloc_buf;
+	hns_roce_mtr_init(&eq->mtr, PAGE_SHIFT + hr_dev->caps.eqe_ba_pg_sz,
+			  page_shift);
+	ret = hns_roce_mtr_attach(hr_dev, &eq->mtr, &buf_list, &region, 1);
+	if (ret)
+		dev_err(hr_dev->dev, "mtr attach error for eqe\n");
 
-			*(eq->bt_l0 + i) = eq->buf_dma[i];
+	goto done;
 
-			eq_buf_cnt++;
-			if (eq_buf_cnt >= ba_num)
-				break;
-		}
-		eq->cur_eqe_ba = eq->buf_dma[0];
-		if (ba_num > 1)
-			eq->nxt_eqe_ba = eq->buf_dma[1];
-
-	} else if (mhop_num == 2) {
-		/* alloc L1 BT and buf */
-		for (i = 0; i < bt_chk_sz / BA_BYTE_LEN; i++) {
-			eq->bt_l1[i] = dma_alloc_coherent(dev, bt_chk_sz,
-							  &(eq->l1_dma[i]),
-							  GFP_KERNEL);
-			if (!eq->bt_l1[i])
-				goto err_dma_alloc_l1;
-			*(eq->bt_l0 + i) = eq->l1_dma[i];
-
-			for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
-				idx = i * bt_chk_sz / BA_BYTE_LEN + j;
-				if (eq_buf_cnt + 1 < ba_num) {
-					size = buf_chk_sz;
-				} else {
-					eqe_alloc = (buf_chk_sz / eq->eqe_size)
-						    * idx;
-					size = (eq->entries - eqe_alloc)
-						* eq->eqe_size;
-				}
-				eq->buf[idx] = dma_alloc_coherent(dev, size,
-								  &(eq->buf_dma[idx]),
-								  GFP_KERNEL);
-				if (!eq->buf[idx])
-					goto err_dma_alloc_buf;
-
-				*(eq->bt_l1[i] + j) = eq->buf_dma[idx];
-
-				eq_buf_cnt++;
-				if (eq_buf_cnt >= ba_num) {
-					eq_alloc_done = 1;
-					break;
-				}
-			}
+	hns_roce_mtr_cleanup(hr_dev, &eq->mtr);
+done:
+	hns_roce_free_buf_list(&buf_list, 1);
 
-			if (eq_alloc_done)
-				break;
-		}
-		eq->cur_eqe_ba = eq->buf_dma[0];
-		if (ba_num > 1)
-			eq->nxt_eqe_ba = eq->buf_dma[1];
-	}
+	return ret;
+}
 
-	eq->l0_last_num = i + 1;
-	if (mhop_num == 2)
-		eq->l1_last_num = j + 1;
+static int alloc_eq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
+{
+	struct hns_roce_buf *buf = &eq->buf;
+	bool is_mhop = false;
+	u32 page_shift;
+	u32 mhop_num;
+	u32 max_size;
+	int ret;
 
-	return 0;
+	page_shift = PAGE_SHIFT + hr_dev->caps.eqe_buf_pg_sz;
+	mhop_num = hr_dev->caps.eqe_hop_num;
+	if (!mhop_num) {
+		max_size = 1 << page_shift;
+		buf->size = max_size;
+	} else if (mhop_num == HNS_ROCE_HOP_NUM_0) {
+		max_size = eq->entries * eq->eqe_size;
+		buf->size = max_size;
+	} else {
+		max_size = 1 << page_shift;
+		buf->size = PAGE_ALIGN(eq->entries * eq->eqe_size);
+		is_mhop = true;
+	}
 
-err_dma_alloc_l1:
-	dma_free_coherent(dev, bt_chk_sz, eq->bt_l0, eq->l0_dma);
-	eq->bt_l0 = NULL;
-	eq->l0_dma = 0;
-	for (i -= 1; i >= 0; i--) {
-		dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
-				  eq->l1_dma[i]);
-
-		for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
-			idx = i * bt_chk_sz / BA_BYTE_LEN + j;
-			dma_free_coherent(dev, buf_chk_sz, eq->buf[idx],
-					  eq->buf_dma[idx]);
-		}
-	}
-	goto err_dma_alloc_l0;
-
-err_dma_alloc_buf:
-	dma_free_coherent(dev, bt_chk_sz, eq->bt_l0, eq->l0_dma);
-	eq->bt_l0 = NULL;
-	eq->l0_dma = 0;
-
-	if (mhop_num == 1)
-		for (i -= 1; i >= 0; i--)
-			dma_free_coherent(dev, buf_chk_sz, eq->buf[i],
-					  eq->buf_dma[i]);
-	else if (mhop_num == 2) {
-		record_i = i;
-		record_j = j;
-		for (; i >= 0; i--) {
-			dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
-					  eq->l1_dma[i]);
-
-			for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
-				if (i == record_i && j >= record_j)
-					break;
-
-				idx = i * bt_chk_sz / BA_BYTE_LEN + j;
-				dma_free_coherent(dev, buf_chk_sz,
-						  eq->buf[idx],
-						  eq->buf_dma[idx]);
-			}
-		}
+	ret = hns_roce_buf_alloc(hr_dev, buf->size, max_size, buf, page_shift);
+	if (ret) {
+		dev_err(hr_dev->dev, "alloc eq buf error\n");
+		return ret;
 	}
 
-err_dma_alloc_l0:
-	kfree(eq->bt_l1);
-	eq->bt_l1 = NULL;
-
-err_kcalloc_bt_l1:
-	kfree(eq->l1_dma);
-	eq->l1_dma = NULL;
-
-err_kcalloc_l1_dma:
-	kfree(eq->buf);
-	eq->buf = NULL;
-
-err_kcalloc_buf:
-	kfree(eq->buf_dma);
-	eq->buf_dma = NULL;
+	if (is_mhop) {
+		ret = map_eq_buf(hr_dev, eq, page_shift);
+		if (ret) {
+			dev_err(hr_dev->dev, "map roce buf error\n");
+			goto err_alloc;
+		}
+	}
 
-	return -ENOMEM;
+	return 0;
+err_alloc:
+	hns_roce_buf_free(hr_dev, buf->size, buf);
+	return ret;
 }
 
 static int hns_roce_v2_create_eq(struct hns_roce_dev *hr_dev,
 				 struct hns_roce_eq *eq,
 				 unsigned int eq_cmd)
 {
-	struct device *dev = hr_dev->dev;
 	struct hns_roce_cmd_mailbox *mailbox;
-	u32 buf_chk_sz = 0;
 	int ret;
 
 	/* Allocate mailbox memory */
@@ -5764,38 +5768,17 @@
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
-	if (!hr_dev->caps.eqe_hop_num) {
-		buf_chk_sz = 1 << (hr_dev->caps.eqe_buf_pg_sz + PAGE_SHIFT);
-
-		eq->buf_list = kzalloc(sizeof(struct hns_roce_buf_list),
-				       GFP_KERNEL);
-		if (!eq->buf_list) {
-			ret = -ENOMEM;
-			goto free_cmd_mbox;
-		}
-
-		eq->buf_list->buf = dma_alloc_coherent(dev, buf_chk_sz,
-						       &(eq->buf_list->map),
-						       GFP_KERNEL);
-		if (!eq->buf_list->buf) {
-			ret = -ENOMEM;
-			goto err_alloc_buf;
-		}
-
-	} else {
-		ret = hns_roce_mhop_alloc_eq(hr_dev, eq);
-		if (ret) {
-			ret = -ENOMEM;
-			goto free_cmd_mbox;
-		}
+	ret = alloc_eq_buf(hr_dev, eq);
+	if (ret) {
+		ret = -ENOMEM;
+		goto free_cmd_mbox;
 	}
-
 	hns_roce_config_eqc(hr_dev, eq, mailbox->buf);
 
 	ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, eq->eqn, 0,
 				eq_cmd, HNS_ROCE_CMD_TIMEOUT_MSECS);
 	if (ret) {
-		dev_err(dev, "[mailbox cmd] create eqc failed.\n");
+		dev_err(hr_dev->dev, "[mailbox cmd] create eqc failed.\n");
 		goto err_cmd_mbox;
 	}
 
@@ -5804,16 +5787,7 @@
 	return 0;
 
 err_cmd_mbox:
-	if (!hr_dev->caps.eqe_hop_num)
-		dma_free_coherent(dev, buf_chk_sz, eq->buf_list->buf,
-				  eq->buf_list->map);
-	else {
-		hns_roce_mhop_free_eq(hr_dev, eq);
-		goto free_cmd_mbox;
-	}
-
-err_alloc_buf:
-	kfree(eq->buf_list);
+	free_eq_buf(hr_dev, eq);
 
 free_cmd_mbox:
 	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
@@ -5839,18 +5813,16 @@
 
 	/* irq contains: abnormal + AEQ + CEQ */
 	for (j = 0; j < other_num; j++)
-		snprintf((char *)hr_dev->irq_names[j],
-			 HNS_ROCE_INT_NAME_LEN, "hns-abn-%d", j);
+		snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
+			 "hns-abn-%d", j);
 
 	for (j = other_num; j < (other_num + aeq_num); j++)
-		snprintf((char *)hr_dev->irq_names[j],
-			 HNS_ROCE_INT_NAME_LEN, "hns-aeq-%d",
-			 j - other_num);
+		snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
+			 "hns-aeq-%d", j - other_num);
 
 	for (j = (other_num + aeq_num); j < irq_num; j++)
-		snprintf((char *)hr_dev->irq_names[j],
-			 HNS_ROCE_INT_NAME_LEN, "hns-ceq-%d",
-			 j - other_num - aeq_num);
+		snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
+			 "hns-ceq-%d", j - other_num - aeq_num);
 
 	for (j = 0; j < irq_num; j++) {
 		if (j < other_num)
@@ -5977,8 +5949,7 @@
 		goto err_request_irq_fail;
 	}
 
-	hr_dev->irq_workq =
-		create_singlethread_workqueue("hns_roce_irq_workqueue");
+	hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0);
 	if (!hr_dev->irq_workq) {
 		dev_err(dev, "Create irq workqueue failed!\n");
 		ret = -ENOMEM;
@@ -5995,7 +5966,7 @@
 
 err_create_eq_fail:
 	for (i -= 1; i >= 0; i--)
-		hns_roce_v2_free_eq(hr_dev, &eq_table->eq[i]);
+		free_eq_buf(hr_dev, &eq_table->eq[i]);
 	kfree(eq_table->eq);
 
 	return ret;
@@ -6017,7 +5988,7 @@
 	for (i = 0; i < eq_num; i++) {
 		hns_roce_v2_destroy_eqc(hr_dev, i);
 
-		hns_roce_v2_free_eq(hr_dev, &eq_table->eq[i]);
+		free_eq_buf(hr_dev, &eq_table->eq[i]);
 	}
 
 	kfree(eq_table->eq);
@@ -6047,7 +6018,7 @@
 		       hr_dev->caps.srqwqe_hop_num));
 	roce_set_field(srq_context->byte_4_srqn_srqst,
 		       SRQC_BYTE_4_SRQ_SHIFT_M, SRQC_BYTE_4_SRQ_SHIFT_S,
-		       ilog2(srq->max));
+		       ilog2(srq->wqe_cnt));
 
 	roce_set_field(srq_context->byte_4_srqn_srqst, SRQC_BYTE_4_SRQN_M,
 		       SRQC_BYTE_4_SRQN_S, srq->srqn);
@@ -6092,11 +6063,11 @@
 	roce_set_field(srq_context->byte_44_idxbufpgsz_addr,
 		       SRQC_BYTE_44_SRQ_IDX_BA_PG_SZ_M,
 		       SRQC_BYTE_44_SRQ_IDX_BA_PG_SZ_S,
-		       hr_dev->caps.idx_ba_pg_sz);
+		       hr_dev->caps.idx_ba_pg_sz + PG_SHIFT_OFFSET);
 	roce_set_field(srq_context->byte_44_idxbufpgsz_addr,
 		       SRQC_BYTE_44_SRQ_IDX_BUF_PG_SZ_M,
 		       SRQC_BYTE_44_SRQ_IDX_BUF_PG_SZ_S,
-		       hr_dev->caps.idx_buf_pg_sz);
+		       hr_dev->caps.idx_buf_pg_sz + PG_SHIFT_OFFSET);
 
 	srq_context->idx_nxt_blk_addr =
 		cpu_to_le32(mtts_idx[1] >> PAGE_ADDR_SHIFT);
@@ -6133,7 +6104,7 @@
 	int ret;
 
 	if (srq_attr_mask & IB_SRQ_LIMIT) {
-		if (srq_attr->srq_limit >= srq->max)
+		if (srq_attr->srq_limit >= srq->wqe_cnt)
 			return -EINVAL;
 
 		mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
@@ -6193,7 +6164,7 @@
 				  SRQC_BYTE_8_SRQ_LIMIT_WL_S);
 
 	attr->srq_limit = limit_wl;
-	attr->max_wr    = srq->max - 1;
+	attr->max_wr    = srq->wqe_cnt - 1;
 	attr->max_sge   = srq->max_gs;
 
 	memcpy(srq_context, mailbox->buf, sizeof(*srq_context));
@@ -6246,7 +6217,7 @@
 
 	spin_lock_irqsave(&srq->lock, flags);
 
-	ind = srq->head & (srq->max - 1);
+	ind = srq->head & (srq->wqe_cnt - 1);
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
 		if (unlikely(wr->num_sge > srq->max_gs)) {
@@ -6261,7 +6232,7 @@
 			break;
 		}
 
-		wqe_idx = find_empty_entry(&srq->idx_que, srq->max);
+		wqe_idx = find_empty_entry(&srq->idx_que, srq->wqe_cnt);
 		if (wqe_idx < 0) {
 			ret = -ENOMEM;
 			*bad_wr = wr;
@@ -6285,7 +6256,7 @@
 		}
 
 		srq->wrid[wqe_idx] = wr->wr_id;
-		ind = (ind + 1) & (srq->max - 1);
+		ind = (ind + 1) & (srq->wqe_cnt - 1);
 	}
 
 	if (likely(nreq)) {
@@ -6380,12 +6351,14 @@
 
 MODULE_DEVICE_TABLE(pci, hns_roce_hw_v2_pci_tbl);
 
-static int hns_roce_hw_v2_get_cfg(struct hns_roce_dev *hr_dev,
+static void hns_roce_hw_v2_get_cfg(struct hns_roce_dev *hr_dev,
 				  struct hnae3_handle *handle)
 {
 	struct hns_roce_v2_priv *priv = hr_dev->priv;
 	int i;
 
+	hr_dev->pci_dev = handle->pdev;
+	hr_dev->dev = &handle->pdev->dev;
 	hr_dev->hw = &hns_roce_hw_v2;
 	hr_dev->dfx = &hns_roce_dfx_hw_v2;
 	hr_dev->sdb_offset = ROCEE_DB_SQ_L_0_REG;
@@ -6410,8 +6383,6 @@
 
 	hr_dev->reset_cnt = handle->ae_algo->ops->ae_dev_reset_cnt(handle);
 	priv->handle = handle;
-
-	return 0;
 }
 
 static int __hns_roce_hw_v2_init_instance(struct hnae3_handle *handle)
@@ -6429,14 +6400,7 @@
 		goto error_failed_kzalloc;
 	}
 
-	hr_dev->pci_dev = handle->pdev;
-	hr_dev->dev = &handle->pdev->dev;
-
-	ret = hns_roce_hw_v2_get_cfg(hr_dev, handle);
-	if (ret) {
-		dev_err(hr_dev->dev, "Get Configuration failed!\n");
-		goto error_failed_get_cfg;
-	}
+	hns_roce_hw_v2_get_cfg(hr_dev, handle);
 
 	ret = hns_roce_init(hr_dev);
 	if (ret) {
@@ -6466,6 +6430,10 @@
 		return;
 
 	handle->priv = NULL;
+
+	hr_dev->state = HNS_ROCE_DEVICE_STATE_UNINIT;
+	hns_roce_handle_device_err(hr_dev);
+
 	hns_roce_exit(hr_dev);
 	kfree(hr_dev->priv);
 	ib_dealloc_device(&hr_dev->ib_dev);
@@ -6527,7 +6495,6 @@
 static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
 {
 	struct hns_roce_dev *hr_dev;
-	struct ib_event event;
 
 	if (handle->rinfo.instance_state != HNS_ROCE_STATE_INITED) {
 		set_bit(HNS_ROCE_RST_DIRECT_RETURN, &handle->rinfo.state);
@@ -6545,10 +6512,7 @@
 	hr_dev->active = false;
 	hr_dev->dis_db = true;
 
-	event.event = IB_EVENT_DEVICE_FATAL;
-	event.device = &hr_dev->ib_dev;
-	event.element.port_num = 1;
-	ib_dispatch_event(&event);
+	hr_dev->state = HNS_ROCE_DEVICE_STATE_RST_DOWN;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -81,15 +81,17 @@
 #define HNS_ROCE_V2_QPC_ENTRY_SZ		256
 #define HNS_ROCE_V2_IRRL_ENTRY_SZ		64
 #define HNS_ROCE_V2_TRRL_ENTRY_SZ		48
+#define HNS_ROCE_V2_EXT_ATOMIC_TRRL_ENTRY_SZ	100
 #define HNS_ROCE_V2_CQC_ENTRY_SZ		64
 #define HNS_ROCE_V2_SRQC_ENTRY_SZ		64
 #define HNS_ROCE_V2_MTPT_ENTRY_SZ		64
 #define HNS_ROCE_V2_MTT_ENTRY_SZ		64
+#define HNS_ROCE_V2_IDX_ENTRY_SZ		4
 #define HNS_ROCE_V2_CQE_ENTRY_SIZE		32
 #define HNS_ROCE_V2_SCCC_ENTRY_SZ		32
-#define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ		4096
-#define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ		4096
-#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED		0xFFFFF000
+#define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ		PAGE_SIZE
+#define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ		PAGE_SIZE
+#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED		0xFFFF000
 #define HNS_ROCE_V2_MAX_INNER_MTPT_NUM		2
 #define HNS_ROCE_INVALID_LKEY			0x100
 #define HNS_ROCE_CMQ_TX_TIMEOUT			30000
@@ -109,7 +111,12 @@
 #define HNS_ROCE_PBL_HOP_NUM			2
 #define HNS_ROCE_EQE_HOP_NUM			2
 #define HNS_ROCE_IDX_HOP_NUM			1
+#define HNS_ROCE_SQWQE_HOP_NUM			2
+#define HNS_ROCE_EXT_SGE_HOP_NUM		1
+#define HNS_ROCE_RQWQE_HOP_NUM			2
 
+#define HNS_ROCE_BA_PG_SZ_SUPPORTED_256K	6
+#define HNS_ROCE_BA_PG_SZ_SUPPORTED_16K		2
 #define HNS_ROCE_V2_GID_INDEX_NUM		256
 
 #define HNS_ROCE_V2_TABLE_CHUNK_SIZE		(1 << 18)
@@ -237,6 +244,7 @@
 	HNS_ROCE_OPC_CFG_EXT_LLM			= 0x8403,
 	HNS_ROCE_OPC_CFG_TMOUT_LLM			= 0x8404,
 	HNS_ROCE_OPC_QUERY_PF_TIMER_RES			= 0x8406,
+	HNS_ROCE_OPC_QUERY_PF_CAPS_NUM                  = 0x8408,
 	HNS_ROCE_OPC_CFG_SGID_TB			= 0x8500,
 	HNS_ROCE_OPC_CFG_SMAC_TB			= 0x8501,
 	HNS_ROCE_OPC_POST_MB				= 0x8504,
@@ -643,7 +651,7 @@
 #define	V2_QPC_BYTE_76_ATE_S 27
 
 #define	V2_QPC_BYTE_76_RQIE_S 28
-
+#define	V2_QPC_BYTE_76_EXT_ATE_S 29
 #define	V2_QPC_BYTE_76_RQ_VLAN_EN_S 30
 #define	V2_QPC_BYTE_80_RX_CQN_S 0
 #define V2_QPC_BYTE_80_RX_CQN_M GENMASK(23, 0)
@@ -1569,6 +1577,155 @@
 #define CFG_SMAC_TB_VF_SMAC_H_S 0
 #define CFG_SMAC_TB_VF_SMAC_H_M GENMASK(15, 0)
 
+#define HNS_ROCE_QUERY_PF_CAPS_CMD_NUM 5
+struct hns_roce_query_pf_caps_a {
+	u8 number_ports;
+	u8 local_ca_ack_delay;
+	__le16 max_sq_sg;
+	__le16 max_sq_inline;
+	__le16 max_rq_sg;
+	__le32 max_extend_sg;
+	__le16 num_qpc_timer;
+	__le16 num_cqc_timer;
+	__le16 max_srq_sges;
+	u8 num_aeq_vectors;
+	u8 num_other_vectors;
+	u8 max_sq_desc_sz;
+	u8 max_rq_desc_sz;
+	u8 max_srq_desc_sz;
+	u8 cq_entry_sz;
+};
+
+struct hns_roce_query_pf_caps_b {
+	u8 mtpt_entry_sz;
+	u8 irrl_entry_sz;
+	u8 trrl_entry_sz;
+	u8 cqc_entry_sz;
+	u8 srqc_entry_sz;
+	u8 idx_entry_sz;
+	u8 scc_ctx_entry_sz;
+	u8 max_mtu;
+	__le16 qpc_entry_sz;
+	__le16 qpc_timer_entry_sz;
+	__le16 cqc_timer_entry_sz;
+	u8 min_cqes;
+	u8 min_wqes;
+	__le32 page_size_cap;
+	u8 pkey_table_len;
+	u8 phy_num_uars;
+	u8 ctx_hop_num;
+	u8 pbl_hop_num;
+};
+
+struct hns_roce_query_pf_caps_c {
+	__le32 cap_flags_num_pds;
+	__le32 max_gid_num_cqs;
+	__le32 cq_depth;
+	__le32 num_mrws;
+	__le32 ord_num_qps;
+	__le16 sq_depth;
+	__le16 rq_depth;
+};
+
+#define V2_QUERY_PF_CAPS_C_NUM_PDS_S 0
+#define V2_QUERY_PF_CAPS_C_NUM_PDS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_C_CAP_FLAGS_S 20
+#define V2_QUERY_PF_CAPS_C_CAP_FLAGS_M GENMASK(31, 20)
+
+#define V2_QUERY_PF_CAPS_C_NUM_CQS_S 0
+#define V2_QUERY_PF_CAPS_C_NUM_CQS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_C_MAX_GID_S 20
+#define V2_QUERY_PF_CAPS_C_MAX_GID_M GENMASK(28, 20)
+
+#define V2_QUERY_PF_CAPS_C_CQ_DEPTH_S 0
+#define V2_QUERY_PF_CAPS_C_CQ_DEPTH_M GENMASK(22, 0)
+
+#define V2_QUERY_PF_CAPS_C_NUM_MRWS_S 0
+#define V2_QUERY_PF_CAPS_C_NUM_MRWS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_C_NUM_QPS_S 0
+#define V2_QUERY_PF_CAPS_C_NUM_QPS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_C_MAX_ORD_S 20
+#define V2_QUERY_PF_CAPS_C_MAX_ORD_M GENMASK(27, 20)
+
+struct hns_roce_query_pf_caps_d {
+	__le32 wq_hop_num_max_srqs;
+	__le16 srq_depth;
+	__le16 rsv;
+	__le32 num_ceqs_ceq_depth;
+	__le32 arm_st_aeq_depth;
+	__le32 num_uars_rsv_pds;
+	__le32 rsv_uars_rsv_qps;
+};
+#define V2_QUERY_PF_CAPS_D_NUM_SRQS_S 0
+#define V2_QUERY_PF_CAPS_D_NUM_SRQS_M GENMASK(20, 0)
+
+#define V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_S 20
+#define V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_M GENMASK(21, 20)
+
+#define V2_QUERY_PF_CAPS_D_EX_SGE_HOP_NUM_S 22
+#define V2_QUERY_PF_CAPS_D_EX_SGE_HOP_NUM_M GENMASK(23, 22)
+
+#define V2_QUERY_PF_CAPS_D_SQWQE_HOP_NUM_S 24
+#define V2_QUERY_PF_CAPS_D_SQWQE_HOP_NUM_M GENMASK(25, 24)
+
+
+#define V2_QUERY_PF_CAPS_D_CEQ_DEPTH_S 0
+#define V2_QUERY_PF_CAPS_D_CEQ_DEPTH_M GENMASK(21, 0)
+
+#define V2_QUERY_PF_CAPS_D_NUM_CEQS_S 22
+#define V2_QUERY_PF_CAPS_D_NUM_CEQS_M GENMASK(31, 22)
+
+#define V2_QUERY_PF_CAPS_D_AEQ_DEPTH_S 0
+#define V2_QUERY_PF_CAPS_D_AEQ_DEPTH_M GENMASK(21, 0)
+
+#define V2_QUERY_PF_CAPS_D_AEQ_ARM_ST_S 22
+#define V2_QUERY_PF_CAPS_D_AEQ_ARM_ST_M GENMASK(23, 22)
+
+#define V2_QUERY_PF_CAPS_D_CEQ_ARM_ST_S 24
+#define V2_QUERY_PF_CAPS_D_CEQ_ARM_ST_M GENMASK(25, 24)
+
+#define V2_QUERY_PF_CAPS_D_RSV_PDS_S 0
+#define V2_QUERY_PF_CAPS_D_RSV_PDS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_D_NUM_UARS_S 20
+#define V2_QUERY_PF_CAPS_D_NUM_UARS_M GENMASK(27, 20)
+
+#define V2_QUERY_PF_CAPS_D_RSV_QPS_S 0
+#define V2_QUERY_PF_CAPS_D_RSV_QPS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_D_RSV_UARS_S 20
+#define V2_QUERY_PF_CAPS_D_RSV_UARS_M GENMASK(27, 20)
+
+struct hns_roce_query_pf_caps_e {
+	__le32 chunk_size_shift_rsv_mrws;
+	__le32 rsv_cqs;
+	__le32 rsv_srqs;
+	__le32 rsv_lkey;
+	__le16 ceq_max_cnt;
+	__le16 ceq_period;
+	__le16 aeq_max_cnt;
+	__le16 aeq_period;
+};
+
+#define V2_QUERY_PF_CAPS_E_RSV_MRWS_S 0
+#define V2_QUERY_PF_CAPS_E_RSV_MRWS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_E_CHUNK_SIZE_SHIFT_S 20
+#define V2_QUERY_PF_CAPS_E_CHUNK_SIZE_SHIFT_M GENMASK(31, 20)
+
+#define V2_QUERY_PF_CAPS_E_RSV_CQS_S 0
+#define V2_QUERY_PF_CAPS_E_RSV_CQS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_E_RSV_SRQS_S 0
+#define V2_QUERY_PF_CAPS_E_RSV_SRQS_M GENMASK(19, 0)
+
+#define V2_QUERY_PF_CAPS_E_RSV_LKEYS_S 0
+#define V2_QUERY_PF_CAPS_E_RSV_LKEYS_M GENMASK(19, 0)
+
 struct hns_roce_cmq_desc {
 	__le16 opcode;
 	__le16 flag;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -90,7 +90,7 @@
 static int hns_roce_del_gid(const struct ib_gid_attr *attr, void **context)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(attr->device);
-	struct ib_gid_attr zattr = { };
+	struct ib_gid_attr zattr = {};
 	u8 port = attr->port_num - 1;
 	int ret;
 
@@ -111,7 +111,7 @@
 
 	netdev = hr_dev->iboe.netdevs[port];
 	if (!netdev) {
-		dev_err(dev, "port(%d) can't find netdev\n", port);
+		dev_err(dev, "Can't find netdev on port(%u)!\n", port);
 		return -ENODEV;
 	}
 
@@ -210,7 +210,7 @@
 	props->max_pkeys = 1;
 	props->local_ca_ack_delay = hr_dev->caps.local_ca_ack_delay;
 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ) {
-		props->max_srq = hr_dev->caps.max_srqs;
+		props->max_srq = hr_dev->caps.num_srqs;
 		props->max_srq_wr = hr_dev->caps.max_srq_wrs;
 		props->max_srq_sge = hr_dev->caps.max_srq_sges;
 	}
@@ -253,17 +253,18 @@
 	net_dev = hr_dev->iboe.netdevs[port];
 	if (!net_dev) {
 		spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
-		dev_err(dev, "find netdev %d failed!\r\n", port);
+		dev_err(dev, "Find netdev %u failed!\n", port);
 		return -EINVAL;
 	}
 
 	mtu = iboe_get_mtu(net_dev->mtu);
 	props->active_mtu = mtu ? min(props->max_mtu, mtu) : IB_MTU_256;
-	props->state = (netif_running(net_dev) && netif_carrier_ok(net_dev)) ?
-			IB_PORT_ACTIVE : IB_PORT_DOWN;
-	props->phys_state = (props->state == IB_PORT_ACTIVE) ?
-			     IB_PORT_PHYS_STATE_LINK_UP :
-			     IB_PORT_PHYS_STATE_DISABLED;
+	props->state = netif_running(net_dev) && netif_carrier_ok(net_dev) ?
+			       IB_PORT_ACTIVE :
+			       IB_PORT_DOWN;
+	props->phys_state = props->state == IB_PORT_ACTIVE ?
+				    IB_PORT_PHYS_STATE_LINK_UP :
+				    IB_PORT_PHYS_STATE_DISABLED;
 
 	spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
 
@@ -279,6 +280,9 @@
 static int hns_roce_query_pkey(struct ib_device *ib_dev, u8 port, u16 index,
 			       u16 *pkey)
 {
+	if (index > 0)
+		return -EINVAL;
+
 	*pkey = PKEY_ID;
 
 	return 0;
@@ -301,12 +305,6 @@
 	return 0;
 }
 
-static int hns_roce_modify_port(struct ib_device *ib_dev, u8 port_num, int mask,
-				struct ib_port_modify *props)
-{
-	return 0;
-}
-
 static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
 				   struct ib_udata *udata)
 {
@@ -359,7 +357,8 @@
 		return rdma_user_mmap_io(context, vma,
 					 to_hr_ucontext(context)->uar.pfn,
 					 PAGE_SIZE,
-					 pgprot_noncached(vma->vm_page_prot));
+					 pgprot_device(vma->vm_page_prot),
+					 NULL);
 
 	/* vm_pgoff: 1 -- TPTR */
 	case 1:
@@ -372,7 +371,8 @@
 		return rdma_user_mmap_io(context, vma,
 					 hr_dev->tptr_dma_addr >> PAGE_SHIFT,
 					 hr_dev->tptr_size,
-					 vma->vm_page_prot);
+					 vma->vm_page_prot,
+					 NULL);
 
 	default:
 		return -EINVAL;
@@ -423,14 +423,14 @@
 	.alloc_pd = hns_roce_alloc_pd,
 	.alloc_ucontext = hns_roce_alloc_ucontext,
 	.create_ah = hns_roce_create_ah,
-	.create_cq = hns_roce_ib_create_cq,
+	.create_cq = hns_roce_create_cq,
 	.create_qp = hns_roce_create_qp,
 	.dealloc_pd = hns_roce_dealloc_pd,
 	.dealloc_ucontext = hns_roce_dealloc_ucontext,
 	.del_gid = hns_roce_del_gid,
 	.dereg_mr = hns_roce_dereg_mr,
 	.destroy_ah = hns_roce_destroy_ah,
-	.destroy_cq = hns_roce_ib_destroy_cq,
+	.destroy_cq = hns_roce_destroy_cq,
 	.disassociate_ucontext = hns_roce_disassociate_ucontext,
 	.fill_res_entry = hns_roce_fill_res_entry,
 	.get_dma_mr = hns_roce_get_dma_mr,
@@ -438,7 +438,6 @@
 	.get_port_immutable = hns_roce_port_immutable,
 	.mmap = hns_roce_mmap,
 	.modify_device = hns_roce_modify_device,
-	.modify_port = hns_roce_modify_port,
 	.modify_qp = hns_roce_modify_qp,
 	.query_ah = hns_roce_query_ah,
 	.query_device = hns_roce_query_device,
@@ -486,13 +485,13 @@
 
 	ib_dev = &hr_dev->ib_dev;
 
-	ib_dev->node_type		= RDMA_NODE_IB_CA;
-	ib_dev->dev.parent		= dev;
+	ib_dev->node_type = RDMA_NODE_IB_CA;
+	ib_dev->dev.parent = dev;
 
-	ib_dev->phys_port_cnt		= hr_dev->caps.num_ports;
-	ib_dev->local_dma_lkey		= hr_dev->caps.reserved_lkey;
-	ib_dev->num_comp_vectors	= hr_dev->caps.num_comp_vectors;
-	ib_dev->uverbs_cmd_mask		=
+	ib_dev->phys_port_cnt = hr_dev->caps.num_ports;
+	ib_dev->local_dma_lkey = hr_dev->caps.reserved_lkey;
+	ib_dev->num_comp_vectors = hr_dev->caps.num_comp_vectors;
+	ib_dev->uverbs_cmd_mask =
 		(1ULL << IB_USER_VERBS_CMD_GET_CONTEXT) |
 		(1ULL << IB_USER_VERBS_CMD_QUERY_DEVICE) |
 		(1ULL << IB_USER_VERBS_CMD_QUERY_PORT) |
@@ -508,8 +507,7 @@
 		(1ULL << IB_USER_VERBS_CMD_QUERY_QP) |
 		(1ULL << IB_USER_VERBS_CMD_DESTROY_QP);
 
-	ib_dev->uverbs_ex_cmd_mask |=
-		(1ULL << IB_USER_VERBS_EX_CMD_MODIFY_CQ);
+	ib_dev->uverbs_ex_cmd_mask |= (1ULL << IB_USER_VERBS_EX_CMD_MODIFY_CQ);
 
 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_REREG_MR) {
 		ib_dev->uverbs_cmd_mask |= (1ULL << IB_USER_VERBS_CMD_REREG_MR);
@@ -594,11 +592,13 @@
 
 	if (hns_roce_check_whether_mhop(hr_dev, HEM_TYPE_CQE)) {
 		ret = hns_roce_init_hem_table(hr_dev,
-				      &hr_dev->mr_table.mtt_cqe_table,
-				      HEM_TYPE_CQE, hr_dev->caps.mtt_entry_sz,
-				      hr_dev->caps.num_cqe_segs, 1);
+					      &hr_dev->mr_table.mtt_cqe_table,
+					      HEM_TYPE_CQE,
+					      hr_dev->caps.mtt_entry_sz,
+					      hr_dev->caps.num_cqe_segs, 1);
 		if (ret) {
-			dev_err(dev, "Failed to init MTT CQE context memory, aborting.\n");
+			dev_err(dev,
+				"Failed to init CQE context memory, aborting.\n");
 			goto err_unmap_cqe;
 		}
 	}
@@ -638,7 +638,7 @@
 					      hr_dev->caps.num_qps, 1);
 		if (ret) {
 			dev_err(dev,
-			       "Failed to init trrl_table memory, aborting.\n");
+				"Failed to init trrl_table memory, aborting.\n");
 			goto err_unmap_irrl;
 		}
 	}
@@ -658,7 +658,7 @@
 					      hr_dev->caps.num_srqs, 1);
 		if (ret) {
 			dev_err(dev,
-			      "Failed to init SRQ context memory, aborting.\n");
+				"Failed to init SRQ context memory, aborting.\n");
 			goto err_unmap_cq;
 		}
 	}
@@ -697,33 +697,31 @@
 					      hr_dev->caps.num_qps, 1);
 		if (ret) {
 			dev_err(dev,
-			      "Failed to init SCC context memory, aborting.\n");
+				"Failed to init SCC context memory, aborting.\n");
 			goto err_unmap_idx;
 		}
 	}
 
 	if (hr_dev->caps.qpc_timer_entry_sz) {
-		ret = hns_roce_init_hem_table(hr_dev,
-					      &hr_dev->qpc_timer_table,
+		ret = hns_roce_init_hem_table(hr_dev, &hr_dev->qpc_timer_table,
 					      HEM_TYPE_QPC_TIMER,
 					      hr_dev->caps.qpc_timer_entry_sz,
 					      hr_dev->caps.num_qpc_timer, 1);
 		if (ret) {
 			dev_err(dev,
-			      "Failed to init QPC timer memory, aborting.\n");
+				"Failed to init QPC timer memory, aborting.\n");
 			goto err_unmap_ctx;
 		}
 	}
 
 	if (hr_dev->caps.cqc_timer_entry_sz) {
-		ret = hns_roce_init_hem_table(hr_dev,
-					      &hr_dev->cqc_timer_table,
+		ret = hns_roce_init_hem_table(hr_dev, &hr_dev->cqc_timer_table,
 					      HEM_TYPE_CQC_TIMER,
 					      hr_dev->caps.cqc_timer_entry_sz,
 					      hr_dev->caps.num_cqc_timer, 1);
 		if (ret) {
 			dev_err(dev,
-			      "Failed to init CQC timer memory, aborting.\n");
+				"Failed to init CQC timer memory, aborting.\n");
 			goto err_unmap_qpc_timer;
 		}
 	}
@@ -732,8 +730,7 @@
 
 err_unmap_qpc_timer:
 	if (hr_dev->caps.qpc_timer_entry_sz)
-		hns_roce_cleanup_hem_table(hr_dev,
-					   &hr_dev->qpc_timer_table);
+		hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qpc_timer_table);
 
 err_unmap_ctx:
 	if (hr_dev->caps.sccc_entry_sz)
@@ -848,8 +845,7 @@
 	return 0;
 
 err_qp_table_free:
-	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)
-		hns_roce_cleanup_qp_table(hr_dev);
+	hns_roce_cleanup_qp_table(hr_dev);
 
 err_cq_table_free:
 	hns_roce_cleanup_cq_table(hr_dev);
@@ -868,6 +864,50 @@
 	return ret;
 }
 
+static void check_and_get_armed_cq(struct list_head *cq_list, struct ib_cq *cq)
+{
+	struct hns_roce_cq *hr_cq = to_hr_cq(cq);
+	unsigned long flags;
+
+	spin_lock_irqsave(&hr_cq->lock, flags);
+	if (cq->comp_handler) {
+		if (!hr_cq->is_armed) {
+			hr_cq->is_armed = 1;
+			list_add_tail(&hr_cq->node, cq_list);
+		}
+	}
+	spin_unlock_irqrestore(&hr_cq->lock, flags);
+}
+
+void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev)
+{
+	struct hns_roce_qp *hr_qp;
+	struct hns_roce_cq *hr_cq;
+	struct list_head cq_list;
+	unsigned long flags_qp;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&cq_list);
+
+	spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
+	list_for_each_entry(hr_qp, &hr_dev->qp_list, node) {
+		spin_lock_irqsave(&hr_qp->sq.lock, flags_qp);
+		if (hr_qp->sq.tail != hr_qp->sq.head)
+			check_and_get_armed_cq(&cq_list, hr_qp->ibqp.send_cq);
+		spin_unlock_irqrestore(&hr_qp->sq.lock, flags_qp);
+
+		spin_lock_irqsave(&hr_qp->rq.lock, flags_qp);
+		if ((!hr_qp->ibqp.srq) && (hr_qp->rq.tail != hr_qp->rq.head))
+			check_and_get_armed_cq(&cq_list, hr_qp->ibqp.recv_cq);
+		spin_unlock_irqrestore(&hr_qp->rq.lock, flags_qp);
+	}
+
+	list_for_each_entry(hr_cq, &cq_list, node)
+		hns_roce_cq_completion(hr_dev, hr_cq->cqn);
+
+	spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
+}
+
 int hns_roce_init(struct hns_roce_dev *hr_dev)
 {
 	int ret;
@@ -938,6 +978,9 @@
 		}
 	}
 
+	INIT_LIST_HEAD(&hr_dev->qp_list);
+	spin_lock_init(&hr_dev->qp_list_lock);
+
 	ret = hns_roce_register_device(hr_dev);
 	if (ret)
 		goto error_failed_register_device;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -48,21 +48,21 @@
 	return (key << 24) | (key >> 8);
 }
 
-static int hns_roce_sw2hw_mpt(struct hns_roce_dev *hr_dev,
-			      struct hns_roce_cmd_mailbox *mailbox,
-			      unsigned long mpt_index)
+static int hns_roce_hw_create_mpt(struct hns_roce_dev *hr_dev,
+				  struct hns_roce_cmd_mailbox *mailbox,
+				  unsigned long mpt_index)
 {
 	return hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, mpt_index, 0,
-				 HNS_ROCE_CMD_SW2HW_MPT,
+				 HNS_ROCE_CMD_CREATE_MPT,
 				 HNS_ROCE_CMD_TIMEOUT_MSECS);
 }
 
-int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev,
-			      struct hns_roce_cmd_mailbox *mailbox,
-			      unsigned long mpt_index)
+int hns_roce_hw_destroy_mpt(struct hns_roce_dev *hr_dev,
+			    struct hns_roce_cmd_mailbox *mailbox,
+			    unsigned long mpt_index)
 {
 	return hns_roce_cmd_mbox(hr_dev, 0, mailbox ? mailbox->dma : 0,
-				 mpt_index, !mailbox, HNS_ROCE_CMD_HW2SW_MPT,
+				 mpt_index, !mailbox, HNS_ROCE_CMD_DESTROY_MPT,
 				 HNS_ROCE_CMD_TIMEOUT_MSECS);
 }
 
@@ -83,7 +83,7 @@
 		}
 	}
 	spin_unlock(&buddy->lock);
-	return -1;
+	return -EINVAL;
 
  found:
 	clear_bit(*seg, buddy->bits[o]);
@@ -206,13 +206,14 @@
 	}
 
 	ret = hns_roce_buddy_alloc(buddy, order, seg);
-	if (ret == -1)
-		return -1;
+	if (ret)
+		return ret;
 
-	if (hns_roce_table_get_range(hr_dev, table, *seg,
-				     *seg + (1 << order) - 1)) {
+	ret = hns_roce_table_get_range(hr_dev, table, *seg,
+				       *seg + (1 << order) - 1);
+	if (ret) {
 		hns_roce_buddy_free(buddy, *seg, order);
-		return -1;
+		return ret;
 	}
 
 	return 0;
@@ -578,7 +579,7 @@
 
 	/* Allocate a key for mr from mr_table */
 	ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index);
-	if (ret == -1)
+	if (ret)
 		return -ENOMEM;
 
 	mr->iova = iova;			/* MR va starting addr */
@@ -707,10 +708,11 @@
 	int ret;
 
 	if (mr->enabled) {
-		ret = hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mr->key)
-					 & (hr_dev->caps.num_mtpts - 1));
+		ret = hns_roce_hw_destroy_mpt(hr_dev, NULL,
+					      key_to_hw_index(mr->key) &
+					      (hr_dev->caps.num_mtpts - 1));
 		if (ret)
-			dev_warn(dev, "HW2SW_MPT failed (%d)\n", ret);
+			dev_warn(dev, "DESTROY_MPT failed (%d)\n", ret);
 	}
 
 	if (mr->size != ~0ULL) {
@@ -763,10 +765,10 @@
 		goto err_page;
 	}
 
-	ret = hns_roce_sw2hw_mpt(hr_dev, mailbox,
-				 mtpt_idx & (hr_dev->caps.num_mtpts - 1));
+	ret = hns_roce_hw_create_mpt(hr_dev, mailbox,
+				     mtpt_idx & (hr_dev->caps.num_mtpts - 1));
 	if (ret) {
-		dev_err(dev, "SW2HW_MPT failed (%d)\n", ret);
+		dev_err(dev, "CREATE_MPT failed (%d)\n", ret);
 		goto err_page;
 	}
 
@@ -1062,8 +1064,8 @@
 		if (!(npage % (1 << (mtt->page_shift - PAGE_SHIFT)))) {
 			if (page_addr & ((1 << mtt->page_shift) - 1)) {
 				dev_err(dev,
-					"page_addr 0x%llx is not page_shift %d alignment!\n",
-					page_addr, mtt->page_shift);
+					"page_addr is not page_shift %d alignment!\n",
+					mtt->page_shift);
 				ret = -EINVAL;
 				goto out;
 			}
@@ -1143,7 +1145,7 @@
 	if (!mr)
 		return ERR_PTR(-ENOMEM);
 
-	mr->umem = ib_umem_get(udata, start, length, access_flags, 0);
+	mr->umem = ib_umem_get(pd->device, start, length, access_flags);
 	if (IS_ERR(mr->umem)) {
 		ret = PTR_ERR(mr->umem);
 		goto err_free;
@@ -1228,7 +1230,7 @@
 	}
 	ib_umem_release(mr->umem);
 
-	mr->umem = ib_umem_get(udata, start, length, mr_access_flags, 0);
+	mr->umem = ib_umem_get(ibmr->device, start, length, mr_access_flags);
 	if (IS_ERR(mr->umem)) {
 		ret = PTR_ERR(mr->umem);
 		mr->umem = NULL;
@@ -1308,9 +1310,9 @@
 	if (ret)
 		goto free_cmd_mbox;
 
-	ret = hns_roce_hw2sw_mpt(hr_dev, NULL, mtpt_idx);
+	ret = hns_roce_hw_destroy_mpt(hr_dev, NULL, mtpt_idx);
 	if (ret)
-		dev_warn(dev, "HW2SW_MPT failed (%d)\n", ret);
+		dev_warn(dev, "DESTROY_MPT failed (%d)\n", ret);
 
 	mr->enabled = 0;
 
@@ -1332,9 +1334,9 @@
 			goto free_cmd_mbox;
 	}
 
-	ret = hns_roce_sw2hw_mpt(hr_dev, mailbox, mtpt_idx);
+	ret = hns_roce_hw_create_mpt(hr_dev, mailbox, mtpt_idx);
 	if (ret) {
-		dev_err(dev, "SW2HW_MPT failed (%d)\n", ret);
+		dev_err(dev, "CREATE_MPT failed (%d)\n", ret);
 		ib_umem_release(mr->umem);
 		goto free_cmd_mbox;
 	}
@@ -1448,10 +1450,11 @@
 	int ret;
 
 	if (mw->enabled) {
-		ret = hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mw->rkey)
-					 & (hr_dev->caps.num_mtpts - 1));
+		ret = hns_roce_hw_destroy_mpt(hr_dev, NULL,
+					      key_to_hw_index(mw->rkey) &
+					      (hr_dev->caps.num_mtpts - 1));
 		if (ret)
-			dev_warn(dev, "MW HW2SW_MPT failed (%d)\n", ret);
+			dev_warn(dev, "MW DESTROY_MPT failed (%d)\n", ret);
 
 		hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table,
 				   key_to_hw_index(mw->rkey));
@@ -1487,10 +1490,10 @@
 		goto err_page;
 	}
 
-	ret = hns_roce_sw2hw_mpt(hr_dev, mailbox,
-				 mtpt_idx & (hr_dev->caps.num_mtpts - 1));
+	ret = hns_roce_hw_create_mpt(hr_dev, mailbox,
+				     mtpt_idx & (hr_dev->caps.num_mtpts - 1));
 	if (ret) {
-		dev_err(dev, "MW sw2hw_mpt failed (%d)\n", ret);
+		dev_err(dev, "MW CREATE_MPT failed (%d)\n", ret);
 		goto err_page;
 	}
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_pd.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -96,7 +96,7 @@
 
 	/* Using bitmap to manager UAR index */
 	ret = hns_roce_bitmap_alloc(&hr_dev->uar_table.bitmap, &uar->logic_idx);
-	if (ret == -1)
+	if (ret)
 		return -ENOMEM;
 
 	if (uar->logic_idx > 0 && hr_dev->caps.phy_num_uars > 1)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -43,6 +43,45 @@
 
 #define SQP_NUM				(2 * HNS_ROCE_MAX_PORTS)
 
+static void flush_work_handle(struct work_struct *work)
+{
+	struct hns_roce_work *flush_work = container_of(work,
+					struct hns_roce_work, work);
+	struct hns_roce_qp *hr_qp = container_of(flush_work,
+					struct hns_roce_qp, flush_work);
+	struct device *dev = flush_work->hr_dev->dev;
+	struct ib_qp_attr attr;
+	int attr_mask;
+	int ret;
+
+	attr_mask = IB_QP_STATE;
+	attr.qp_state = IB_QPS_ERR;
+
+	if (test_and_clear_bit(HNS_ROCE_FLUSH_FLAG, &hr_qp->flush_flag)) {
+		ret = hns_roce_modify_qp(&hr_qp->ibqp, &attr, attr_mask, NULL);
+		if (ret)
+			dev_err(dev, "Modify QP to error state failed(%d) during CQE flush\n",
+				ret);
+	}
+
+	/*
+	 * make sure we signal QP destroy leg that flush QP was completed
+	 * so that it can safely proceed ahead now and destroy QP
+	 */
+	if (atomic_dec_and_test(&hr_qp->refcount))
+		complete(&hr_qp->free);
+}
+
+void init_flush_work(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+{
+	struct hns_roce_work *flush_work = &hr_qp->flush_work;
+
+	flush_work->hr_dev = hr_dev;
+	INIT_WORK(&flush_work->work, flush_work_handle);
+	atomic_inc(&hr_qp->refcount);
+	queue_work(hr_dev->irq_workq, &flush_work->work);
+}
+
 void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
 {
 	struct device *dev = hr_dev->dev;
@@ -59,6 +98,15 @@
 		return;
 	}
 
+	if (hr_dev->hw_rev != HNS_ROCE_HW_VER1 &&
+	    (event_type == HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR ||
+	     event_type == HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR ||
+	     event_type == HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR)) {
+		qp->state = IB_QPS_ERR;
+		if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
+			init_flush_work(hr_dev, qp);
+	}
+
 	qp->event(qp, (enum hns_roce_event)event_type);
 
 	if (atomic_dec_and_test(&qp->refcount))
@@ -108,15 +156,34 @@
 	}
 }
 
-static int hns_roce_reserve_range_qp(struct hns_roce_dev *hr_dev, int cnt,
-				     int align, unsigned long *base)
+static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 {
-	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+	unsigned long num = 0;
+	int ret;
 
-	return hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align,
-					   base) ?
-		       -ENOMEM :
-		       0;
+	if (hr_qp->ibqp.qp_type == IB_QPT_GSI) {
+		/* when hw version is v1, the sqpn is allocated */
+		if (hr_dev->hw_rev == HNS_ROCE_HW_VER1)
+			num = HNS_ROCE_MAX_PORTS +
+			      hr_dev->iboe.phy_port[hr_qp->port];
+		else
+			num = 1;
+
+		hr_qp->doorbell_qpn = 1;
+	} else {
+		ret = hns_roce_bitmap_alloc_range(&hr_dev->qp_table.bitmap,
+						  1, 1, &num);
+		if (ret) {
+			ibdev_err(&hr_dev->ib_dev, "Failed to alloc bitmap\n");
+			return -ENOMEM;
+		}
+
+		hr_qp->doorbell_qpn = (u32)num;
+	}
+
+	hr_qp->qpn = num;
+
+	return 0;
 }
 
 enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state)
@@ -139,50 +206,75 @@
 	}
 }
 
-static int hns_roce_gsi_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
-				 struct hns_roce_qp *hr_qp)
+static void add_qp_to_list(struct hns_roce_dev *hr_dev,
+			   struct hns_roce_qp *hr_qp,
+			   struct ib_cq *send_cq, struct ib_cq *recv_cq)
+{
+	struct hns_roce_cq *hr_send_cq, *hr_recv_cq;
+	unsigned long flags;
+
+	hr_send_cq = send_cq ? to_hr_cq(send_cq) : NULL;
+	hr_recv_cq = recv_cq ? to_hr_cq(recv_cq) : NULL;
+
+	spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
+	hns_roce_lock_cqs(hr_send_cq, hr_recv_cq);
+
+	list_add_tail(&hr_qp->node, &hr_dev->qp_list);
+	if (hr_send_cq)
+		list_add_tail(&hr_qp->sq_node, &hr_send_cq->sq_list);
+	if (hr_recv_cq)
+		list_add_tail(&hr_qp->rq_node, &hr_recv_cq->rq_list);
+
+	hns_roce_unlock_cqs(hr_send_cq, hr_recv_cq);
+	spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
+}
+
+static int hns_roce_qp_store(struct hns_roce_dev *hr_dev,
+			     struct hns_roce_qp *hr_qp,
+			     struct ib_qp_init_attr *init_attr)
 {
 	struct xarray *xa = &hr_dev->qp_table_xa;
 	int ret;
 
-	if (!qpn)
+	if (!hr_qp->qpn)
 		return -EINVAL;
 
-	hr_qp->qpn = qpn;
-	atomic_set(&hr_qp->refcount, 1);
-	init_completion(&hr_qp->free);
-
-	ret = xa_err(xa_store_irq(xa, hr_qp->qpn & (hr_dev->caps.num_qps - 1),
-				hr_qp, GFP_KERNEL));
+	ret = xa_err(xa_store_irq(xa, hr_qp->qpn, hr_qp, GFP_KERNEL));
 	if (ret)
-		dev_err(hr_dev->dev, "QPC xa_store failed\n");
+		dev_err(hr_dev->dev, "Failed to xa store for QPC\n");
+	else
+		/* add QP to device's QP list for softwc */
+		add_qp_to_list(hr_dev, hr_qp, init_attr->send_cq,
+			       init_attr->recv_cq);
 
 	return ret;
 }
 
-static int hns_roce_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
-			     struct hns_roce_qp *hr_qp)
+static int alloc_qpc(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 {
 	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
 	struct device *dev = hr_dev->dev;
 	int ret;
 
-	if (!qpn)
+	if (!hr_qp->qpn)
 		return -EINVAL;
 
-	hr_qp->qpn = qpn;
+	/* In v1 engine, GSI QP context is saved in the RoCE hw's register */
+	if (hr_qp->ibqp.qp_type == IB_QPT_GSI &&
+	    hr_dev->hw_rev == HNS_ROCE_HW_VER1)
+		return 0;
 
 	/* Alloc memory for QPC */
 	ret = hns_roce_table_get(hr_dev, &qp_table->qp_table, hr_qp->qpn);
 	if (ret) {
-		dev_err(dev, "QPC table get failed\n");
+		dev_err(dev, "Failed to get QPC table\n");
 		goto err_out;
 	}
 
 	/* Alloc memory for IRRL */
 	ret = hns_roce_table_get(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
 	if (ret) {
-		dev_err(dev, "IRRL table get failed\n");
+		dev_err(dev, "Failed to get IRRL table\n");
 		goto err_put_qp;
 	}
 
@@ -191,7 +283,7 @@
 		ret = hns_roce_table_get(hr_dev, &qp_table->trrl_table,
 					 hr_qp->qpn);
 		if (ret) {
-			dev_err(dev, "TRRL table get failed\n");
+			dev_err(dev, "Failed to get TRRL table\n");
 			goto err_put_irrl;
 		}
 	}
@@ -201,22 +293,13 @@
 		ret = hns_roce_table_get(hr_dev, &qp_table->sccc_table,
 					 hr_qp->qpn);
 		if (ret) {
-			dev_err(dev, "SCC CTX table get failed\n");
+			dev_err(dev, "Failed to get SCC CTX table\n");
 			goto err_put_trrl;
 		}
 	}
 
-	ret = hns_roce_gsi_qp_alloc(hr_dev, qpn, hr_qp);
-	if (ret)
-		goto err_put_sccc;
-
 	return 0;
 
-err_put_sccc:
-	if (hr_dev->caps.sccc_entry_sz)
-		hns_roce_table_put(hr_dev, &qp_table->sccc_table,
-				   hr_qp->qpn);
-
 err_put_trrl:
 	if (hr_dev->caps.trrl_entry_sz)
 		hns_roce_table_put(hr_dev, &qp_table->trrl_table, hr_qp->qpn);
@@ -236,89 +319,85 @@
 	struct xarray *xa = &hr_dev->qp_table_xa;
 	unsigned long flags;
 
+	list_del(&hr_qp->node);
+	list_del(&hr_qp->sq_node);
+	list_del(&hr_qp->rq_node);
+
 	xa_lock_irqsave(xa, flags);
 	__xa_erase(xa, hr_qp->qpn & (hr_dev->caps.num_qps - 1));
 	xa_unlock_irqrestore(xa, flags);
 }
 
-void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+static void free_qpc(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 {
 	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
 
-	if (atomic_dec_and_test(&hr_qp->refcount))
-		complete(&hr_qp->free);
-	wait_for_completion(&hr_qp->free);
+	/* In v1 engine, GSI QP context is saved in the RoCE hw's register */
+	if (hr_qp->ibqp.qp_type == IB_QPT_GSI &&
+	    hr_dev->hw_rev == HNS_ROCE_HW_VER1)
+		return;
 
-	if ((hr_qp->ibqp.qp_type) != IB_QPT_GSI) {
-		if (hr_dev->caps.trrl_entry_sz)
-			hns_roce_table_put(hr_dev, &qp_table->trrl_table,
-					   hr_qp->qpn);
-		hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
-	}
+	if (hr_dev->caps.trrl_entry_sz)
+		hns_roce_table_put(hr_dev, &qp_table->trrl_table, hr_qp->qpn);
+	hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
 }
 
-void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
-			       int cnt)
+static void free_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
 {
 	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
 
-	if (base_qpn < hr_dev->caps.reserved_qps)
+	if (hr_qp->ibqp.qp_type == IB_QPT_GSI)
 		return;
 
-	hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, BITMAP_RR);
+	if (hr_qp->qpn < hr_dev->caps.reserved_qps)
+		return;
+
+	hns_roce_bitmap_free_range(&qp_table->bitmap, hr_qp->qpn, 1, BITMAP_RR);
 }
 
-static int hns_roce_set_rq_size(struct hns_roce_dev *hr_dev,
+static int set_rq_size(struct hns_roce_dev *hr_dev,
 				struct ib_qp_cap *cap, bool is_user, int has_rq,
 				struct hns_roce_qp *hr_qp)
 {
-	struct device *dev = hr_dev->dev;
 	u32 max_cnt;
 
-	/* Check the validity of QP support capacity */
-	if (cap->max_recv_wr > hr_dev->caps.max_wqes ||
-	    cap->max_recv_sge > hr_dev->caps.max_rq_sg) {
-		dev_err(dev, "RQ WR or sge error!max_recv_wr=%d max_recv_sge=%d\n",
-			cap->max_recv_wr, cap->max_recv_sge);
-		return -EINVAL;
-	}
-
 	/* If srq exist, set zero for relative number of rq */
 	if (!has_rq) {
 		hr_qp->rq.wqe_cnt = 0;
 		hr_qp->rq.max_gs = 0;
 		cap->max_recv_wr = 0;
 		cap->max_recv_sge = 0;
-	} else {
-		if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) {
-			dev_err(dev, "user space no need config max_recv_wr max_recv_sge\n");
-			return -EINVAL;
-		}
 
-		if (hr_dev->caps.min_wqes)
-			max_cnt = max(cap->max_recv_wr, hr_dev->caps.min_wqes);
-		else
-			max_cnt = cap->max_recv_wr;
+		return 0;
+	}
 
-		hr_qp->rq.wqe_cnt = roundup_pow_of_two(max_cnt);
+	/* Check the validity of QP support capacity */
+	if (!cap->max_recv_wr || cap->max_recv_wr > hr_dev->caps.max_wqes ||
+	    cap->max_recv_sge > hr_dev->caps.max_rq_sg) {
+		ibdev_err(&hr_dev->ib_dev, "RQ config error, depth=%u, sge=%d\n",
+			  cap->max_recv_wr, cap->max_recv_sge);
+		return -EINVAL;
+	}
 
-		if ((u32)hr_qp->rq.wqe_cnt > hr_dev->caps.max_wqes) {
-			dev_err(dev, "while setting rq size, rq.wqe_cnt too large\n");
-			return -EINVAL;
-		}
+	max_cnt = max(cap->max_recv_wr, hr_dev->caps.min_wqes);
 
-		max_cnt = max(1U, cap->max_recv_sge);
-		hr_qp->rq.max_gs = roundup_pow_of_two(max_cnt);
-		if (hr_dev->caps.max_rq_sg <= 2)
-			hr_qp->rq.wqe_shift =
-					ilog2(hr_dev->caps.max_rq_desc_sz);
-		else
-			hr_qp->rq.wqe_shift =
-					ilog2(hr_dev->caps.max_rq_desc_sz
-					      * hr_qp->rq.max_gs);
+	hr_qp->rq.wqe_cnt = roundup_pow_of_two(max_cnt);
+	if ((u32)hr_qp->rq.wqe_cnt > hr_dev->caps.max_wqes) {
+		ibdev_err(&hr_dev->ib_dev, "rq depth %u too large\n",
+			  cap->max_recv_wr);
+		return -EINVAL;
 	}
 
-	cap->max_recv_wr = hr_qp->rq.max_post = hr_qp->rq.wqe_cnt;
+	max_cnt = max(1U, cap->max_recv_sge);
+	hr_qp->rq.max_gs = roundup_pow_of_two(max_cnt);
+
+	if (hr_dev->caps.max_rq_sg <= HNS_ROCE_SGE_IN_WQE)
+		hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz);
+	else
+		hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz *
+					    hr_qp->rq.max_gs);
+
+	cap->max_recv_wr = hr_qp->rq.wqe_cnt;
 	cap->max_recv_sge = hr_qp->rq.max_gs;
 
 	return 0;
@@ -332,15 +411,14 @@
 	u8 max_sq_stride = ilog2(roundup_sq_stride);
 
 	/* Sanity check SQ size before proceeding */
-	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
-	     ucmd->log_sq_stride > max_sq_stride ||
-	     ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
-		ibdev_err(&hr_dev->ib_dev, "check SQ size error!\n");
+	if (ucmd->log_sq_stride > max_sq_stride ||
+	    ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
+		ibdev_err(&hr_dev->ib_dev, "Failed to check SQ stride size\n");
 		return -EINVAL;
 	}
 
 	if (cap->max_send_sge > hr_dev->caps.max_sq_sg) {
-		ibdev_err(&hr_dev->ib_dev, "SQ sge error! max_send_sge=%d\n",
+		ibdev_err(&hr_dev->ib_dev, "Failed to check SQ SGE size %d\n",
 			  cap->max_send_sge);
 		return -EINVAL;
 	}
@@ -348,40 +426,43 @@
 	return 0;
 }
 
-static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
-				     struct ib_qp_cap *cap,
-				     struct hns_roce_qp *hr_qp,
-				     struct hns_roce_ib_create_qp *ucmd)
+static int set_user_sq_size(struct hns_roce_dev *hr_dev,
+			    struct ib_qp_cap *cap, struct hns_roce_qp *hr_qp,
+			    struct hns_roce_ib_create_qp *ucmd)
 {
 	u32 ex_sge_num;
 	u32 page_size;
 	u32 max_cnt;
 	int ret;
 
+	if (check_shl_overflow(1, ucmd->log_sq_bb_count, &hr_qp->sq.wqe_cnt) ||
+	    hr_qp->sq.wqe_cnt > hr_dev->caps.max_wqes)
+		return -EINVAL;
+
 	ret = check_sq_size_with_integrity(hr_dev, cap, ucmd);
 	if (ret) {
-		ibdev_err(&hr_dev->ib_dev, "Sanity check sq size failed\n");
+		ibdev_err(&hr_dev->ib_dev, "Failed to check user SQ size limit\n");
 		return ret;
 	}
 
-	hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
 	hr_qp->sq.wqe_shift = ucmd->log_sq_stride;
 
 	max_cnt = max(1U, cap->max_send_sge);
-	if (hr_dev->caps.max_sq_sg <= 2)
+	if (hr_dev->hw_rev == HNS_ROCE_HW_VER1)
 		hr_qp->sq.max_gs = roundup_pow_of_two(max_cnt);
 	else
 		hr_qp->sq.max_gs = max_cnt;
 
-	if (hr_qp->sq.max_gs > 2)
+	if (hr_qp->sq.max_gs > HNS_ROCE_SGE_IN_WQE)
 		hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
 							(hr_qp->sq.max_gs - 2));
 
-	if ((hr_qp->sq.max_gs > 2) && (hr_dev->pci_dev->revision == 0x20)) {
+	if (hr_qp->sq.max_gs > HNS_ROCE_SGE_IN_WQE &&
+	    hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08_A) {
 		if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
-			dev_err(hr_dev->dev,
-				"The extended sge cnt error! sge_cnt=%d\n",
-				hr_qp->sge.sge_cnt);
+			ibdev_err(&hr_dev->ib_dev,
+				  "Failed to check extended SGE size limit %d\n",
+				  hr_qp->sge.sge_cnt);
 			return -EINVAL;
 		}
 	}
@@ -390,41 +471,39 @@
 	ex_sge_num = hr_qp->sge.sge_cnt;
 
 	/* Get buf size, SQ and RQ  are aligned to page_szie */
-	if (hr_dev->caps.max_sq_sg <= 2) {
-		hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
+	if (hr_dev->hw_rev == HNS_ROCE_HW_VER1) {
+		hr_qp->buff_size = round_up((hr_qp->rq.wqe_cnt <<
 					     hr_qp->rq.wqe_shift), PAGE_SIZE) +
-				   HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+				   round_up((hr_qp->sq.wqe_cnt <<
 					     hr_qp->sq.wqe_shift), PAGE_SIZE);
 
 		hr_qp->sq.offset = 0;
-		hr_qp->rq.offset = HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+		hr_qp->rq.offset = round_up((hr_qp->sq.wqe_cnt <<
 					     hr_qp->sq.wqe_shift), PAGE_SIZE);
 	} else {
 		page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
 		hr_qp->sge.sge_cnt = ex_sge_num ?
 		   max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num) : 0;
-		hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
+		hr_qp->buff_size = round_up((hr_qp->rq.wqe_cnt <<
 					     hr_qp->rq.wqe_shift), page_size) +
-				   HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
+				   round_up((hr_qp->sge.sge_cnt <<
 					     hr_qp->sge.sge_shift), page_size) +
-				   HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+				   round_up((hr_qp->sq.wqe_cnt <<
 					     hr_qp->sq.wqe_shift), page_size);
 
 		hr_qp->sq.offset = 0;
 		if (ex_sge_num) {
-			hr_qp->sge.offset = HNS_ROCE_ALOGN_UP(
-							(hr_qp->sq.wqe_cnt <<
-							hr_qp->sq.wqe_shift),
-							page_size);
+			hr_qp->sge.offset = round_up((hr_qp->sq.wqe_cnt <<
+						      hr_qp->sq.wqe_shift),
+						     page_size);
 			hr_qp->rq.offset = hr_qp->sge.offset +
-					HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
-						hr_qp->sge.sge_shift),
-						page_size);
+					   round_up((hr_qp->sge.sge_cnt <<
+						     hr_qp->sge.sge_shift),
+						    page_size);
 		} else {
-			hr_qp->rq.offset = HNS_ROCE_ALOGN_UP(
-							(hr_qp->sq.wqe_cnt <<
-							hr_qp->sq.wqe_shift),
-							page_size);
+			hr_qp->rq.offset = round_up((hr_qp->sq.wqe_cnt <<
+						     hr_qp->sq.wqe_shift),
+						    page_size);
 		}
 	}
 
@@ -528,13 +607,15 @@
 	}
 
 	/* ud sqwqe's sge use extend sge */
-	if (hr_dev->caps.max_sq_sg > 2 && hr_qp->ibqp.qp_type == IB_QPT_GSI) {
+	if (hr_dev->hw_rev != HNS_ROCE_HW_VER1 &&
+	    hr_qp->ibqp.qp_type == IB_QPT_GSI) {
 		hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
 				     hr_qp->sq.max_gs);
 		hr_qp->sge.sge_shift = 4;
 	}
 
-	if ((hr_qp->sq.max_gs > 2) && hr_dev->pci_dev->revision == 0x20) {
+	if (hr_qp->sq.max_gs > 2 &&
+	    hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08_A) {
 		if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
 			dev_err(dev, "The extended sge cnt error! sge_cnt=%d\n",
 				hr_qp->sge.sge_cnt);
@@ -545,70 +626,65 @@
 	return 0;
 }
 
-static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
-				       struct ib_qp_cap *cap,
-				       struct hns_roce_qp *hr_qp)
+static int set_kernel_sq_size(struct hns_roce_dev *hr_dev,
+			      struct ib_qp_cap *cap, struct hns_roce_qp *hr_qp)
 {
-	struct device *dev = hr_dev->dev;
 	u32 page_size;
 	u32 max_cnt;
 	int size;
 	int ret;
 
-	if (cap->max_send_wr  > hr_dev->caps.max_wqes  ||
+	if (!cap->max_send_wr || cap->max_send_wr > hr_dev->caps.max_wqes ||
 	    cap->max_send_sge > hr_dev->caps.max_sq_sg ||
 	    cap->max_inline_data > hr_dev->caps.max_sq_inline) {
-		dev_err(dev, "SQ WR or sge or inline data error!\n");
+		ibdev_err(&hr_dev->ib_dev,
+			  "SQ WR or sge or inline data error!\n");
 		return -EINVAL;
 	}
 
 	hr_qp->sq.wqe_shift = ilog2(hr_dev->caps.max_sq_desc_sz);
 
-	if (hr_dev->caps.min_wqes)
-		max_cnt = max(cap->max_send_wr, hr_dev->caps.min_wqes);
-	else
-		max_cnt = cap->max_send_wr;
+	max_cnt = max(cap->max_send_wr, hr_dev->caps.min_wqes);
 
 	hr_qp->sq.wqe_cnt = roundup_pow_of_two(max_cnt);
 	if ((u32)hr_qp->sq.wqe_cnt > hr_dev->caps.max_wqes) {
-		dev_err(dev, "while setting kernel sq size, sq.wqe_cnt too large\n");
+		ibdev_err(&hr_dev->ib_dev,
+			  "while setting kernel sq size, sq.wqe_cnt too large\n");
 		return -EINVAL;
 	}
 
 	/* Get data_seg numbers */
 	max_cnt = max(1U, cap->max_send_sge);
-	if (hr_dev->caps.max_sq_sg <= 2)
+	if (hr_dev->hw_rev == HNS_ROCE_HW_VER1)
 		hr_qp->sq.max_gs = roundup_pow_of_two(max_cnt);
 	else
 		hr_qp->sq.max_gs = max_cnt;
 
 	ret = set_extend_sge_param(hr_dev, hr_qp);
 	if (ret) {
-		dev_err(dev, "set extend sge parameters fail\n");
+		ibdev_err(&hr_dev->ib_dev, "set extend sge parameters fail\n");
 		return ret;
 	}
 
 	/* Get buf size, SQ and RQ are aligned to PAGE_SIZE */
 	page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
 	hr_qp->sq.offset = 0;
-	size = HNS_ROCE_ALOGN_UP(hr_qp->sq.wqe_cnt << hr_qp->sq.wqe_shift,
-				 page_size);
+	size = round_up(hr_qp->sq.wqe_cnt << hr_qp->sq.wqe_shift, page_size);
 
-	if (hr_dev->caps.max_sq_sg > 2 && hr_qp->sge.sge_cnt) {
+	if (hr_dev->hw_rev != HNS_ROCE_HW_VER1 && hr_qp->sge.sge_cnt) {
 		hr_qp->sge.sge_cnt = max(page_size/(1 << hr_qp->sge.sge_shift),
-					(u32)hr_qp->sge.sge_cnt);
+					 (u32)hr_qp->sge.sge_cnt);
 		hr_qp->sge.offset = size;
-		size += HNS_ROCE_ALOGN_UP(hr_qp->sge.sge_cnt <<
-					  hr_qp->sge.sge_shift, page_size);
+		size += round_up(hr_qp->sge.sge_cnt << hr_qp->sge.sge_shift,
+				 page_size);
 	}
 
 	hr_qp->rq.offset = size;
-	size += HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt << hr_qp->rq.wqe_shift),
-				  page_size);
+	size += round_up((hr_qp->rq.wqe_cnt << hr_qp->rq.wqe_shift), page_size);
 	hr_qp->buff_size = size;
 
 	/* Get wr and sge number which send */
-	cap->max_send_wr = hr_qp->sq.max_post = hr_qp->sq.wqe_cnt;
+	cap->max_send_wr = hr_qp->sq.wqe_cnt;
 	cap->max_send_sge = hr_qp->sq.max_gs;
 
 	/* We don't support inline sends for kernel QPs (yet) */
@@ -679,336 +755,447 @@
 	kfree(hr_qp->rq_inl_buf.wqe_list);
 }
 
-static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
-				     struct ib_pd *ib_pd,
-				     struct ib_qp_init_attr *init_attr,
-				     struct ib_udata *udata, unsigned long sqpn,
-				     struct hns_roce_qp *hr_qp)
+static int map_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+		       u32 page_shift, bool is_user)
 {
 	dma_addr_t *buf_list[ARRAY_SIZE(hr_qp->regions)] = { NULL };
-	struct device *dev = hr_dev->dev;
-	struct hns_roce_ib_create_qp ucmd;
-	struct hns_roce_ib_create_qp_resp resp = {};
-	struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(
-		udata, struct hns_roce_ucontext, ibucontext);
+	struct ib_device *ibdev = &hr_dev->ib_dev;
 	struct hns_roce_buf_region *r;
-	unsigned long qpn = 0;
-	u32 page_shift;
+	int region_count;
 	int buf_count;
 	int ret;
 	int i;
 
-	mutex_init(&hr_qp->mutex);
-	spin_lock_init(&hr_qp->sq.lock);
-	spin_lock_init(&hr_qp->rq.lock);
+	region_count = split_wqe_buf_region(hr_dev, hr_qp, hr_qp->regions,
+					ARRAY_SIZE(hr_qp->regions), page_shift);
 
-	hr_qp->state = IB_QPS_RESET;
-
-	hr_qp->ibqp.qp_type = init_attr->qp_type;
-
-	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
-		hr_qp->sq_signal_bits = IB_SIGNAL_ALL_WR;
-	else
-		hr_qp->sq_signal_bits = IB_SIGNAL_REQ_WR;
-
-	ret = hns_roce_set_rq_size(hr_dev, &init_attr->cap, udata,
-				   hns_roce_qp_has_rq(init_attr), hr_qp);
+	/* alloc a tmp list to store WQE buffers address */
+	ret = hns_roce_alloc_buf_list(hr_qp->regions, buf_list, region_count);
 	if (ret) {
-		dev_err(dev, "hns_roce_set_rq_size failed\n");
-		goto err_out;
+		ibdev_err(ibdev, "Failed to alloc WQE buffer list\n");
+		return ret;
 	}
 
-	if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
-	    hns_roce_qp_has_rq(init_attr)) {
-		ret = alloc_rq_inline_buf(hr_qp, init_attr);
-		if (ret) {
-			dev_err(dev, "allocate receive inline buffer failed\n");
-			goto err_out;
+	for (i = 0; i < region_count; i++) {
+		r = &hr_qp->regions[i];
+		if (is_user)
+			buf_count = hns_roce_get_umem_bufs(hr_dev, buf_list[i],
+					r->count, r->offset, hr_qp->umem,
+					page_shift);
+		else
+			buf_count = hns_roce_get_kmem_bufs(hr_dev, buf_list[i],
+					r->count, r->offset, &hr_qp->hr_buf);
+
+		if (buf_count != r->count) {
+			ibdev_err(ibdev, "Failed to get %s WQE buf, expect %d = %d.\n",
+				  is_user ? "user" : "kernel",
+				  r->count, buf_count);
+			ret = -ENOBUFS;
+			goto done;
 		}
 	}
 
-	page_shift = PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
-	if (udata) {
-		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
-			dev_err(dev, "ib_copy_from_udata error for create qp\n");
-			ret = -EFAULT;
-			goto err_alloc_rq_inline_buf;
-		}
+	hr_qp->wqe_bt_pg_shift = calc_wqe_bt_page_shift(hr_dev, hr_qp->regions,
+							region_count);
+	hns_roce_mtr_init(&hr_qp->mtr, PAGE_SHIFT + hr_qp->wqe_bt_pg_shift,
+			  page_shift);
+	ret = hns_roce_mtr_attach(hr_dev, &hr_qp->mtr, buf_list, hr_qp->regions,
+				  region_count);
+	if (ret)
+		ibdev_err(ibdev, "Failed to attatch WQE's mtr\n");
+
+	goto done;
+
+	hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
+done:
+	hns_roce_free_buf_list(buf_list, region_count);
 
-		ret = hns_roce_set_user_sq_size(hr_dev, &init_attr->cap, hr_qp,
-						&ucmd);
+	return ret;
+}
+
+static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			struct ib_qp_init_attr *init_attr,
+			struct ib_udata *udata, unsigned long addr)
+{
+	u32 page_shift = PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	bool is_rq_buf_inline;
+	int ret;
+
+	is_rq_buf_inline = (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
+			   hns_roce_qp_has_rq(init_attr);
+	if (is_rq_buf_inline) {
+		ret = alloc_rq_inline_buf(hr_qp, init_attr);
 		if (ret) {
-			dev_err(dev, "hns_roce_set_user_sq_size error for create qp\n");
-			goto err_alloc_rq_inline_buf;
+			ibdev_err(ibdev, "Failed to alloc inline RQ buffer\n");
+			return ret;
 		}
+	}
 
-		hr_qp->umem = ib_umem_get(udata, ucmd.buf_addr,
-					  hr_qp->buff_size, 0, 0);
+	if (udata) {
+		hr_qp->umem = ib_umem_get(ibdev, addr, hr_qp->buff_size, 0);
 		if (IS_ERR(hr_qp->umem)) {
-			dev_err(dev, "ib_umem_get error for create qp\n");
 			ret = PTR_ERR(hr_qp->umem);
-			goto err_alloc_rq_inline_buf;
-		}
-		hr_qp->region_cnt = split_wqe_buf_region(hr_dev, hr_qp,
-				hr_qp->regions, ARRAY_SIZE(hr_qp->regions),
-				page_shift);
-		ret = hns_roce_alloc_buf_list(hr_qp->regions, buf_list,
-					      hr_qp->region_cnt);
-		if (ret) {
-			dev_err(dev, "alloc buf_list error for create qp\n");
-			goto err_alloc_list;
+			goto err_inline;
 		}
+	} else {
+		ret = hns_roce_buf_alloc(hr_dev, hr_qp->buff_size,
+					 (1 << page_shift) * 2,
+					 &hr_qp->hr_buf, page_shift);
+		if (ret)
+			goto err_inline;
+	}
 
-		for (i = 0; i < hr_qp->region_cnt; i++) {
-			r = &hr_qp->regions[i];
-			buf_count = hns_roce_get_umem_bufs(hr_dev,
-					buf_list[i], r->count, r->offset,
-					hr_qp->umem, page_shift);
-			if (buf_count != r->count) {
-				dev_err(dev,
-					"get umem buf err, expect %d,ret %d.\n",
-					r->count, buf_count);
-				ret = -ENOBUFS;
-				goto err_get_bufs;
-			}
-		}
+	ret = map_wqe_buf(hr_dev, hr_qp, page_shift, udata);
+	if (ret)
+		goto err_alloc;
+
+	return 0;
+
+err_inline:
+	if (is_rq_buf_inline)
+		free_rq_inline_buf(hr_qp);
+
+err_alloc:
+	if (udata) {
+		ib_umem_release(hr_qp->umem);
+		hr_qp->umem = NULL;
+	} else {
+		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
+	}
 
-		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
-		    (udata->inlen >= sizeof(ucmd)) &&
-		    (udata->outlen >= sizeof(resp)) &&
-		    hns_roce_qp_has_sq(init_attr)) {
-			ret = hns_roce_db_map_user(uctx, udata, ucmd.sdb_addr,
+	ibdev_err(ibdev, "Failed to alloc WQE buffer, ret %d.\n", ret);
+
+	return ret;
+}
+
+static void free_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+{
+	hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
+	if (hr_qp->umem) {
+		ib_umem_release(hr_qp->umem);
+		hr_qp->umem = NULL;
+	}
+
+	if (hr_qp->hr_buf.nbufs > 0)
+		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
+
+	if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
+	     hr_qp->rq.wqe_cnt)
+		free_rq_inline_buf(hr_qp);
+}
+
+static inline bool user_qp_has_sdb(struct hns_roce_dev *hr_dev,
+				   struct ib_qp_init_attr *init_attr,
+				   struct ib_udata *udata,
+				   struct hns_roce_ib_create_qp_resp *resp,
+				   struct hns_roce_ib_create_qp *ucmd)
+{
+	return ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
+		udata->outlen >= offsetofend(typeof(*resp), cap_flags) &&
+		hns_roce_qp_has_sq(init_attr) &&
+		udata->inlen >= offsetofend(typeof(*ucmd), sdb_addr));
+}
+
+static inline bool user_qp_has_rdb(struct hns_roce_dev *hr_dev,
+				   struct ib_qp_init_attr *init_attr,
+				   struct ib_udata *udata,
+				   struct hns_roce_ib_create_qp_resp *resp)
+{
+	return ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
+		udata->outlen >= offsetofend(typeof(*resp), cap_flags) &&
+		hns_roce_qp_has_rq(init_attr));
+}
+
+static inline bool kernel_qp_has_rdb(struct hns_roce_dev *hr_dev,
+				     struct ib_qp_init_attr *init_attr)
+{
+	return ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
+		hns_roce_qp_has_rq(init_attr));
+}
+
+static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+		       struct ib_qp_init_attr *init_attr,
+		       struct ib_udata *udata,
+		       struct hns_roce_ib_create_qp *ucmd,
+		       struct hns_roce_ib_create_qp_resp *resp)
+{
+	struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(
+		udata, struct hns_roce_ucontext, ibucontext);
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	int ret;
+
+	if (udata) {
+		if (user_qp_has_sdb(hr_dev, init_attr, udata, resp, ucmd)) {
+			ret = hns_roce_db_map_user(uctx, udata, ucmd->sdb_addr,
 						   &hr_qp->sdb);
 			if (ret) {
-				dev_err(dev, "sq record doorbell map failed!\n");
-				goto err_get_bufs;
+				ibdev_err(ibdev,
+					  "Failed to map user SQ doorbell\n");
+				goto err_out;
 			}
-
-			/* indicate kernel supports sq record db */
-			resp.cap_flags |= HNS_ROCE_SUPPORT_SQ_RECORD_DB;
 			hr_qp->sdb_en = 1;
+			resp->cap_flags |= HNS_ROCE_SUPPORT_SQ_RECORD_DB;
 		}
 
-		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
-		    (udata->outlen >= sizeof(resp)) &&
-		    hns_roce_qp_has_rq(init_attr)) {
-			ret = hns_roce_db_map_user(uctx, udata, ucmd.db_addr,
+		if (user_qp_has_rdb(hr_dev, init_attr, udata, resp)) {
+			ret = hns_roce_db_map_user(uctx, udata, ucmd->db_addr,
 						   &hr_qp->rdb);
 			if (ret) {
-				dev_err(dev, "rq record doorbell map failed!\n");
-				goto err_sq_dbmap;
+				ibdev_err(ibdev,
+					  "Failed to map user RQ doorbell\n");
+				goto err_sdb;
 			}
-
-			/* indicate kernel supports rq record db */
-			resp.cap_flags |= HNS_ROCE_SUPPORT_RQ_RECORD_DB;
 			hr_qp->rdb_en = 1;
+			resp->cap_flags |= HNS_ROCE_SUPPORT_RQ_RECORD_DB;
 		}
 	} else {
-		if (init_attr->create_flags &
-		    IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
-			dev_err(dev, "init_attr->create_flags error!\n");
-			ret = -EINVAL;
-			goto err_alloc_rq_inline_buf;
-		}
-
-		if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) {
-			dev_err(dev, "init_attr->create_flags error!\n");
-			ret = -EINVAL;
-			goto err_alloc_rq_inline_buf;
-		}
-
-		/* Set SQ size */
-		ret = hns_roce_set_kernel_sq_size(hr_dev, &init_attr->cap,
-						  hr_qp);
-		if (ret) {
-			dev_err(dev, "hns_roce_set_kernel_sq_size error!\n");
-			goto err_alloc_rq_inline_buf;
-		}
-
 		/* QP doorbell register address */
 		hr_qp->sq.db_reg_l = hr_dev->reg_base + hr_dev->sdb_offset +
 				     DB_REG_OFFSET * hr_dev->priv_uar.index;
 		hr_qp->rq.db_reg_l = hr_dev->reg_base + hr_dev->odb_offset +
 				     DB_REG_OFFSET * hr_dev->priv_uar.index;
 
-		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
-		    hns_roce_qp_has_rq(init_attr)) {
+		if (kernel_qp_has_rdb(hr_dev, init_attr)) {
 			ret = hns_roce_alloc_db(hr_dev, &hr_qp->rdb, 0);
 			if (ret) {
-				dev_err(dev, "rq record doorbell alloc failed!\n");
-				goto err_alloc_rq_inline_buf;
+				ibdev_err(ibdev,
+					  "Failed to alloc kernel RQ doorbell\n");
+				goto err_out;
 			}
 			*hr_qp->rdb.db_record = 0;
 			hr_qp->rdb_en = 1;
 		}
+	}
 
-		/* Allocate QP buf */
-		if (hns_roce_buf_alloc(hr_dev, hr_qp->buff_size,
-				       (1 << page_shift) * 2,
-				       &hr_qp->hr_buf, page_shift)) {
-			dev_err(dev, "hns_roce_buf_alloc error!\n");
+	return 0;
+err_sdb:
+	if (udata && hr_qp->sdb_en)
+		hns_roce_db_unmap_user(uctx, &hr_qp->sdb);
+err_out:
+	return ret;
+}
+
+static void free_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+		       struct ib_udata *udata)
+{
+	struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(
+		udata, struct hns_roce_ucontext, ibucontext);
+
+	if (udata) {
+		if (hr_qp->rdb_en)
+			hns_roce_db_unmap_user(uctx, &hr_qp->rdb);
+		if (hr_qp->sdb_en)
+			hns_roce_db_unmap_user(uctx, &hr_qp->sdb);
+	} else {
+		if (hr_qp->rdb_en)
+			hns_roce_free_db(hr_dev, &hr_qp->rdb);
+	}
+}
+
+static int alloc_kernel_wrid(struct hns_roce_dev *hr_dev,
+			     struct hns_roce_qp *hr_qp)
+{
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	u64 *sq_wrid = NULL;
+	u64 *rq_wrid = NULL;
+	int ret;
+
+	sq_wrid = kcalloc(hr_qp->sq.wqe_cnt, sizeof(u64), GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(sq_wrid)) {
+		ibdev_err(ibdev, "Failed to alloc SQ wrid\n");
+		return -ENOMEM;
+	}
+
+	if (hr_qp->rq.wqe_cnt) {
+		rq_wrid = kcalloc(hr_qp->rq.wqe_cnt, sizeof(u64), GFP_KERNEL);
+		if (ZERO_OR_NULL_PTR(rq_wrid)) {
+			ibdev_err(ibdev, "Failed to alloc RQ wrid\n");
 			ret = -ENOMEM;
-			goto err_db;
-		}
-		hr_qp->region_cnt = split_wqe_buf_region(hr_dev, hr_qp,
-				hr_qp->regions, ARRAY_SIZE(hr_qp->regions),
-				page_shift);
-		ret = hns_roce_alloc_buf_list(hr_qp->regions, buf_list,
-					      hr_qp->region_cnt);
-		if (ret) {
-			dev_err(dev, "alloc buf_list error for create qp!\n");
-			goto err_alloc_list;
+			goto err_sq;
 		}
+	}
 
-		for (i = 0; i < hr_qp->region_cnt; i++) {
-			r = &hr_qp->regions[i];
-			buf_count = hns_roce_get_kmem_bufs(hr_dev,
-					buf_list[i], r->count, r->offset,
-					&hr_qp->hr_buf);
-			if (buf_count != r->count) {
-				dev_err(dev,
-					"get kmem buf err, expect %d,ret %d.\n",
-					r->count, buf_count);
-				ret = -ENOBUFS;
-				goto err_get_bufs;
-			}
+	hr_qp->sq.wrid = sq_wrid;
+	hr_qp->rq.wrid = rq_wrid;
+	return 0;
+err_sq:
+	kfree(sq_wrid);
+
+	return ret;
+}
+
+static void free_kernel_wrid(struct hns_roce_dev *hr_dev,
+			     struct hns_roce_qp *hr_qp)
+{
+	kfree(hr_qp->rq.wrid);
+	kfree(hr_qp->sq.wrid);
+}
+
+static int set_qp_param(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			struct ib_qp_init_attr *init_attr,
+			struct ib_udata *udata,
+			struct hns_roce_ib_create_qp *ucmd)
+{
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	int ret;
+
+	hr_qp->ibqp.qp_type = init_attr->qp_type;
+
+	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+		hr_qp->sq_signal_bits = IB_SIGNAL_ALL_WR;
+	else
+		hr_qp->sq_signal_bits = IB_SIGNAL_REQ_WR;
+
+	ret = set_rq_size(hr_dev, &init_attr->cap, udata,
+			  hns_roce_qp_has_rq(init_attr), hr_qp);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to set user RQ size\n");
+		return ret;
+	}
+
+	if (udata) {
+		if (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd))) {
+			ibdev_err(ibdev, "Failed to copy QP ucmd\n");
+			return -EFAULT;
 		}
 
-		hr_qp->sq.wrid = kcalloc(hr_qp->sq.wqe_cnt, sizeof(u64),
-					 GFP_KERNEL);
-		if (ZERO_OR_NULL_PTR(hr_qp->sq.wrid)) {
-			ret = -ENOMEM;
-			goto err_get_bufs;
+		ret = set_user_sq_size(hr_dev, &init_attr->cap, hr_qp, ucmd);
+		if (ret)
+			ibdev_err(ibdev, "Failed to set user SQ size\n");
+	} else {
+		if (init_attr->create_flags &
+		    IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
+			ibdev_err(ibdev, "Failed to check multicast loopback\n");
+			return -EINVAL;
 		}
 
-		if (hr_qp->rq.wqe_cnt) {
-			hr_qp->rq.wrid = kcalloc(hr_qp->rq.wqe_cnt, sizeof(u64),
-						 GFP_KERNEL);
-			if (ZERO_OR_NULL_PTR(hr_qp->rq.wrid)) {
-				ret = -ENOMEM;
-				goto err_sq_wrid;
-			}
+		if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) {
+			ibdev_err(ibdev, "Failed to check ipoib ud lso\n");
+			return -EINVAL;
 		}
+
+		ret = set_kernel_sq_size(hr_dev, &init_attr->cap, hr_qp);
+		if (ret)
+			ibdev_err(ibdev, "Failed to set kernel SQ size\n");
 	}
 
-	if (sqpn) {
-		qpn = sqpn;
-	} else {
-		/* Get QPN */
-		ret = hns_roce_reserve_range_qp(hr_dev, 1, 1, &qpn);
+	return ret;
+}
+
+static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
+				     struct ib_pd *ib_pd,
+				     struct ib_qp_init_attr *init_attr,
+				     struct ib_udata *udata,
+				     struct hns_roce_qp *hr_qp)
+{
+	struct hns_roce_ib_create_qp_resp resp = {};
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	struct hns_roce_ib_create_qp ucmd;
+	int ret;
+
+	mutex_init(&hr_qp->mutex);
+	spin_lock_init(&hr_qp->sq.lock);
+	spin_lock_init(&hr_qp->rq.lock);
+
+	hr_qp->state = IB_QPS_RESET;
+	hr_qp->flush_flag = 0;
+
+	ret = set_qp_param(hr_dev, hr_qp, init_attr, udata, &ucmd);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to set QP param\n");
+		return ret;
+	}
+
+	if (!udata) {
+		ret = alloc_kernel_wrid(hr_dev, hr_qp);
 		if (ret) {
-			dev_err(dev, "hns_roce_reserve_range_qp alloc qpn error\n");
-			goto err_wrid;
+			ibdev_err(ibdev, "Failed to alloc wrid\n");
+			return ret;
 		}
 	}
 
-	hr_qp->wqe_bt_pg_shift = calc_wqe_bt_page_shift(hr_dev, hr_qp->regions,
-							hr_qp->region_cnt);
-	hns_roce_mtr_init(&hr_qp->mtr, PAGE_SHIFT + hr_qp->wqe_bt_pg_shift,
-			  page_shift);
-	ret = hns_roce_mtr_attach(hr_dev, &hr_qp->mtr, buf_list,
-				  hr_qp->regions, hr_qp->region_cnt);
+	ret = alloc_qp_db(hr_dev, hr_qp, init_attr, udata, &ucmd, &resp);
 	if (ret) {
-		dev_err(dev, "mtr attach error for create qp\n");
-		goto err_mtr;
+		ibdev_err(ibdev, "Failed to alloc QP doorbell\n");
+		goto err_wrid;
 	}
 
-	if (init_attr->qp_type == IB_QPT_GSI &&
-	    hr_dev->hw_rev == HNS_ROCE_HW_VER1) {
-		/* In v1 engine, GSI QP context in RoCE engine's register */
-		ret = hns_roce_gsi_qp_alloc(hr_dev, qpn, hr_qp);
-		if (ret) {
-			dev_err(dev, "hns_roce_qp_alloc failed!\n");
-			goto err_qpn;
-		}
-	} else {
-		ret = hns_roce_qp_alloc(hr_dev, qpn, hr_qp);
-		if (ret) {
-			dev_err(dev, "hns_roce_qp_alloc failed!\n");
-			goto err_qpn;
-		}
+	ret = alloc_qp_buf(hr_dev, hr_qp, init_attr, udata, ucmd.buf_addr);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to alloc QP buffer\n");
+		goto err_db;
 	}
 
-	if (sqpn)
-		hr_qp->doorbell_qpn = 1;
-	else
-		hr_qp->doorbell_qpn = (u32)hr_qp->qpn;
+	ret = alloc_qpn(hr_dev, hr_qp);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to alloc QPN\n");
+		goto err_buf;
+	}
+
+	ret = alloc_qpc(hr_dev, hr_qp);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to alloc QP context\n");
+		goto err_qpn;
+	}
+
+	ret = hns_roce_qp_store(hr_dev, hr_qp, init_attr);
+	if (ret) {
+		ibdev_err(ibdev, "Failed to store QP\n");
+		goto err_qpc;
+	}
 
 	if (udata) {
 		ret = ib_copy_to_udata(udata, &resp,
 				       min(udata->outlen, sizeof(resp)));
-		if (ret)
-			goto err_qp;
+		if (ret) {
+			ibdev_err(ibdev, "copy qp resp failed!\n");
+			goto err_store;
+		}
 	}
 
 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) {
 		ret = hr_dev->hw->qp_flow_control_init(hr_dev, hr_qp);
 		if (ret)
-			goto err_qp;
+			goto err_store;
 	}
 
+	hr_qp->ibqp.qp_num = hr_qp->qpn;
 	hr_qp->event = hns_roce_ib_qp_event;
-	hns_roce_free_buf_list(buf_list, hr_qp->region_cnt);
+	atomic_set(&hr_qp->refcount, 1);
+	init_completion(&hr_qp->free);
 
 	return 0;
 
-err_qp:
-	if (init_attr->qp_type == IB_QPT_GSI &&
-		hr_dev->hw_rev == HNS_ROCE_HW_VER1)
-		hns_roce_qp_remove(hr_dev, hr_qp);
-	else
-		hns_roce_qp_free(hr_dev, hr_qp);
-
+err_store:
+	hns_roce_qp_remove(hr_dev, hr_qp);
+err_qpc:
+	free_qpc(hr_dev, hr_qp);
 err_qpn:
-	if (!sqpn)
-		hns_roce_release_range_qp(hr_dev, qpn, 1);
-
-err_mtr:
-	hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
-
+	free_qpn(hr_dev, hr_qp);
+err_buf:
+	free_qp_buf(hr_dev, hr_qp);
+err_db:
+	free_qp_db(hr_dev, hr_qp, udata);
 err_wrid:
-	if (udata) {
-		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
-		    (udata->outlen >= sizeof(resp)) &&
-		    hns_roce_qp_has_rq(init_attr))
-			hns_roce_db_unmap_user(uctx, &hr_qp->rdb);
-	} else {
-		if (hr_qp->rq.wqe_cnt)
-			kfree(hr_qp->rq.wrid);
-	}
-
-err_sq_dbmap:
-	if (udata)
-		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
-		    (udata->inlen >= sizeof(ucmd)) &&
-		    (udata->outlen >= sizeof(resp)) &&
-		    hns_roce_qp_has_sq(init_attr))
-			hns_roce_db_unmap_user(uctx, &hr_qp->sdb);
-
-err_sq_wrid:
-	if (!udata)
-		kfree(hr_qp->sq.wrid);
-
-err_get_bufs:
-	hns_roce_free_buf_list(buf_list, hr_qp->region_cnt);
-
-err_alloc_list:
-	if (!hr_qp->umem)
-		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
-	ib_umem_release(hr_qp->umem);
+	free_kernel_wrid(hr_dev, hr_qp);
+	return ret;
+}
 
-err_db:
-	if (!udata && hns_roce_qp_has_rq(init_attr) &&
-	    (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB))
-		hns_roce_free_db(hr_dev, &hr_qp->rdb);
+void hns_roce_qp_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			 struct ib_udata *udata)
+{
+	if (atomic_dec_and_test(&hr_qp->refcount))
+		complete(&hr_qp->free);
+	wait_for_completion(&hr_qp->free);
 
-err_alloc_rq_inline_buf:
-	if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
-	     hns_roce_qp_has_rq(init_attr))
-		free_rq_inline_buf(hr_qp);
+	free_qpc(hr_dev, hr_qp);
+	free_qpn(hr_dev, hr_qp);
+	free_qp_buf(hr_dev, hr_qp);
+	free_kernel_wrid(hr_dev, hr_qp);
+	free_qp_db(hr_dev, hr_qp, udata);
 
-err_out:
-	return ret;
+	kfree(hr_qp);
 }
 
 struct ib_qp *hns_roce_create_qp(struct ib_pd *pd,
@@ -1017,7 +1204,6 @@
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
 	struct ib_device *ibdev = &hr_dev->ib_dev;
-	struct hns_roce_sqp *hr_sqp;
 	struct hns_roce_qp *hr_qp;
 	int ret;
 
@@ -1027,17 +1213,15 @@
 		if (!hr_qp)
 			return ERR_PTR(-ENOMEM);
 
-		ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata, 0,
+		ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata,
 						hr_qp);
 		if (ret) {
-			ibdev_err(ibdev, "Create RC QP 0x%06lx failed(%d)\n",
+			ibdev_err(ibdev, "Create QP 0x%06lx failed(%d)\n",
 				  hr_qp->qpn, ret);
 			kfree(hr_qp);
 			return ERR_PTR(ret);
 		}
 
-		hr_qp->ibqp.qp_num = hr_qp->qpn;
-
 		break;
 	}
 	case IB_QPT_GSI: {
@@ -1047,26 +1231,18 @@
 			return ERR_PTR(-EINVAL);
 		}
 
-		hr_sqp = kzalloc(sizeof(*hr_sqp), GFP_KERNEL);
-		if (!hr_sqp)
+		hr_qp = kzalloc(sizeof(*hr_qp), GFP_KERNEL);
+		if (!hr_qp)
 			return ERR_PTR(-ENOMEM);
 
-		hr_qp = &hr_sqp->hr_qp;
 		hr_qp->port = init_attr->port_num - 1;
 		hr_qp->phy_port = hr_dev->iboe.phy_port[hr_qp->port];
 
-		/* when hw version is v1, the sqpn is allocated */
-		if (hr_dev->caps.max_sq_sg <= 2)
-			hr_qp->ibqp.qp_num = HNS_ROCE_MAX_PORTS +
-					     hr_dev->iboe.phy_port[hr_qp->port];
-		else
-			hr_qp->ibqp.qp_num = 1;
-
 		ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata,
-						hr_qp->ibqp.qp_num, hr_qp);
+						hr_qp);
 		if (ret) {
 			ibdev_err(ibdev, "Create GSI QP failed!\n");
-			kfree(hr_sqp);
+			kfree(hr_qp);
 			return ERR_PTR(ret);
 		}
 
@@ -1179,8 +1355,10 @@
 
 	mutex_lock(&hr_qp->mutex);
 
-	cur_state = attr_mask & IB_QP_CUR_STATE ?
-		    attr->cur_qp_state : (enum ib_qp_state)hr_qp->state;
+	if (attr_mask & IB_QP_CUR_STATE && attr->cur_qp_state != hr_qp->state)
+		goto out;
+
+	cur_state = hr_qp->state;
 	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
 
 	if (ibqp->uobject &&
@@ -1208,11 +1386,10 @@
 		goto out;
 
 	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
-		if (hr_dev->caps.min_wqes) {
+		if (hr_dev->hw_rev == HNS_ROCE_HW_VER1) {
 			ret = -EPERM;
 			ibdev_err(&hr_dev->ib_dev,
-				"cur_state=%d new_state=%d\n", cur_state,
-				new_state);
+				  "RST2RST state is not supported\n");
 		} else {
 			ret = 0;
 		}
@@ -1232,7 +1409,16 @@
 void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
 		       __acquires(&send_cq->lock) __acquires(&recv_cq->lock)
 {
-	if (send_cq == recv_cq) {
+	if (unlikely(send_cq == NULL && recv_cq == NULL)) {
+		__acquire(&send_cq->lock);
+		__acquire(&recv_cq->lock);
+	} else if (unlikely(send_cq != NULL && recv_cq == NULL)) {
+		spin_lock_irq(&send_cq->lock);
+		__acquire(&recv_cq->lock);
+	} else if (unlikely(send_cq == NULL && recv_cq != NULL)) {
+		spin_lock_irq(&recv_cq->lock);
+		__acquire(&send_cq->lock);
+	} else if (send_cq == recv_cq) {
 		spin_lock_irq(&send_cq->lock);
 		__acquire(&recv_cq->lock);
 	} else if (send_cq->cqn < recv_cq->cqn) {
@@ -1248,7 +1434,16 @@
 			 struct hns_roce_cq *recv_cq) __releases(&send_cq->lock)
 			 __releases(&recv_cq->lock)
 {
-	if (send_cq == recv_cq) {
+	if (unlikely(send_cq == NULL && recv_cq == NULL)) {
+		__release(&recv_cq->lock);
+		__release(&send_cq->lock);
+	} else if (unlikely(send_cq != NULL && recv_cq == NULL)) {
+		__release(&recv_cq->lock);
+		spin_unlock(&send_cq->lock);
+	} else if (unlikely(send_cq == NULL && recv_cq != NULL)) {
+		__release(&send_cq->lock);
+		spin_unlock(&recv_cq->lock);
+	} else if (send_cq == recv_cq) {
 		__release(&recv_cq->lock);
 		spin_unlock_irq(&send_cq->lock);
 	} else if (send_cq->cqn < recv_cq->cqn) {
@@ -1289,7 +1484,7 @@
 	u32 cur;
 
 	cur = hr_wq->head - hr_wq->tail;
-	if (likely(cur + nreq < hr_wq->max_post))
+	if (likely(cur + nreq < hr_wq->wqe_cnt))
 		return false;
 
 	hr_cq = to_hr_cq(ib_cq);
@@ -1297,7 +1492,7 @@
 	cur = hr_wq->head - hr_wq->tail;
 	spin_unlock(&hr_cq->lock);
 
-	return cur + nreq >= hr_wq->max_post;
+	return cur + nreq >= hr_wq->wqe_cnt;
 }
 
 int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_restrack.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_restrack.c
@@ -95,14 +95,18 @@
 
 	ret = hr_dev->dfx->query_cqc_info(hr_dev, hr_cq->cqn, (int *)context);
 	if (ret)
-		goto err;
+		return -EINVAL;
 
 	table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_DRIVER);
-	if (!table_attr)
+	if (!table_attr) {
+		ret = -EMSGSIZE;
 		goto err;
+	}
 
-	if (hns_roce_fill_cq(msg, context))
+	if (hns_roce_fill_cq(msg, context)) {
+		ret = -EMSGSIZE;
 		goto err_cancel_table;
+	}
 
 	nla_nest_end(msg, table_attr);
 	kfree(context);
@@ -113,7 +117,7 @@
 	nla_nest_cancel(msg, table_attr);
 err:
 	kfree(context);
-	return -EMSGSIZE;
+	return ret;
 }
 
 int hns_roce_fill_res_entry(struct sk_buff *msg,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -59,21 +59,21 @@
 	}
 }
 
-static int hns_roce_sw2hw_srq(struct hns_roce_dev *dev,
-			      struct hns_roce_cmd_mailbox *mailbox,
-			      unsigned long srq_num)
+static int hns_roce_hw_create_srq(struct hns_roce_dev *dev,
+				  struct hns_roce_cmd_mailbox *mailbox,
+				  unsigned long srq_num)
 {
 	return hns_roce_cmd_mbox(dev, mailbox->dma, 0, srq_num, 0,
-				 HNS_ROCE_CMD_SW2HW_SRQ,
+				 HNS_ROCE_CMD_CREATE_SRQ,
 				 HNS_ROCE_CMD_TIMEOUT_MSECS);
 }
 
-static int hns_roce_hw2sw_srq(struct hns_roce_dev *dev,
-			     struct hns_roce_cmd_mailbox *mailbox,
-			     unsigned long srq_num)
+static int hns_roce_hw_destroy_srq(struct hns_roce_dev *dev,
+				   struct hns_roce_cmd_mailbox *mailbox,
+				   unsigned long srq_num)
 {
 	return hns_roce_cmd_mbox(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
-				 mailbox ? 0 : 1, HNS_ROCE_CMD_HW2SW_SRQ,
+				 mailbox ? 0 : 1, HNS_ROCE_CMD_DESTROY_SRQ,
 				 HNS_ROCE_CMD_TIMEOUT_MSECS);
 }
 
@@ -95,8 +95,7 @@
 				       srq->mtt.first_seg,
 				       &dma_handle_wqe);
 	if (!mtts_wqe) {
-		dev_err(hr_dev->dev,
-			"SRQ alloc.Failed to find srq buf addr.\n");
+		dev_err(hr_dev->dev, "Failed to find mtt for srq buf.\n");
 		return -EINVAL;
 	}
 
@@ -106,13 +105,14 @@
 				       &dma_handle_idx);
 	if (!mtts_idx) {
 		dev_err(hr_dev->dev,
-			"SRQ alloc.Failed to find idx que buf addr.\n");
+			"Failed to find mtt for srq idx queue buf.\n");
 		return -EINVAL;
 	}
 
 	ret = hns_roce_bitmap_alloc(&srq_table->bitmap, &srq->srqn);
-	if (ret == -1) {
-		dev_err(hr_dev->dev, "SRQ alloc.Failed to alloc index.\n");
+	if (ret) {
+		dev_err(hr_dev->dev,
+			"Failed to alloc a bit from srq bitmap.\n");
 		return -ENOMEM;
 	}
 
@@ -134,7 +134,7 @@
 			       mtts_wqe, mtts_idx, dma_handle_wqe,
 			       dma_handle_idx);
 
-	ret = hns_roce_sw2hw_srq(hr_dev, mailbox, srq->srqn);
+	ret = hns_roce_hw_create_srq(hr_dev, mailbox, srq->srqn);
 	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
 	if (ret)
 		goto err_xa;
@@ -160,9 +160,9 @@
 	struct hns_roce_srq_table *srq_table = &hr_dev->srq_table;
 	int ret;
 
-	ret = hns_roce_hw2sw_srq(hr_dev, NULL, srq->srqn);
+	ret = hns_roce_hw_destroy_srq(hr_dev, NULL, srq->srqn);
 	if (ret)
-		dev_err(hr_dev->dev, "HW2SW_SRQ failed (%d) for CQN %06lx\n",
+		dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n",
 			ret, srq->srqn);
 
 	xa_erase(&srq_table->xa, srq->srqn);
@@ -180,22 +180,24 @@
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device);
 	struct hns_roce_ib_create_srq  ucmd;
-	u32 page_shift;
-	u32 npages;
+	struct hns_roce_buf *buf;
 	int ret;
 
 	if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
 		return -EFAULT;
 
-	srq->umem = ib_umem_get(udata, ucmd.buf_addr, srq_buf_size, 0, 0);
+	srq->umem =
+		ib_umem_get(srq->ibsrq.device, ucmd.buf_addr, srq_buf_size, 0);
 	if (IS_ERR(srq->umem))
 		return PTR_ERR(srq->umem);
 
-	npages = (ib_umem_page_count(srq->umem) +
-		(1 << hr_dev->caps.srqwqe_buf_pg_sz) - 1) /
-		(1 << hr_dev->caps.srqwqe_buf_pg_sz);
-	page_shift = PAGE_SHIFT + hr_dev->caps.srqwqe_buf_pg_sz;
-	ret = hns_roce_mtt_init(hr_dev, npages, page_shift, &srq->mtt);
+	buf = &srq->buf;
+	buf->npages = (ib_umem_page_count(srq->umem) +
+		       (1 << hr_dev->caps.srqwqe_buf_pg_sz) - 1) /
+		      (1 << hr_dev->caps.srqwqe_buf_pg_sz);
+	buf->page_shift = PAGE_SHIFT + hr_dev->caps.srqwqe_buf_pg_sz;
+	ret = hns_roce_mtt_init(hr_dev, buf->npages, buf->page_shift,
+				&srq->mtt);
 	if (ret)
 		goto err_user_buf;
 
@@ -204,17 +206,20 @@
 		goto err_user_srq_mtt;
 
 	/* config index queue BA */
-	srq->idx_que.umem = ib_umem_get(udata, ucmd.que_addr,
-					srq->idx_que.buf_size, 0, 0);
+	srq->idx_que.umem = ib_umem_get(srq->ibsrq.device, ucmd.que_addr,
+					srq->idx_que.buf_size, 0);
 	if (IS_ERR(srq->idx_que.umem)) {
 		dev_err(hr_dev->dev, "ib_umem_get error for index queue\n");
 		ret = PTR_ERR(srq->idx_que.umem);
 		goto err_user_srq_mtt;
 	}
 
-	ret = hns_roce_mtt_init(hr_dev, ib_umem_page_count(srq->idx_que.umem),
-				PAGE_SHIFT, &srq->idx_que.mtt);
-
+	buf = &srq->idx_que.idx_buf;
+	buf->npages = DIV_ROUND_UP(ib_umem_page_count(srq->idx_que.umem),
+				   1 << hr_dev->caps.idx_buf_pg_sz);
+	buf->page_shift = PAGE_SHIFT + hr_dev->caps.idx_buf_pg_sz;
+	ret = hns_roce_mtt_init(hr_dev, buf->npages, buf->page_shift,
+				&srq->idx_que.mtt);
 	if (ret) {
 		dev_err(hr_dev->dev, "hns_roce_mtt_init error for idx que\n");
 		goto err_user_idx_mtt;
@@ -251,7 +256,7 @@
 	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
 	struct hns_roce_idx_que *idx_que = &srq->idx_que;
 
-	idx_que->bitmap = bitmap_zalloc(srq->max, GFP_KERNEL);
+	idx_que->bitmap = bitmap_zalloc(srq->wqe_cnt, GFP_KERNEL);
 	if (!idx_que->bitmap)
 		return -ENOMEM;
 
@@ -277,7 +282,7 @@
 		return -ENOMEM;
 
 	srq->head = 0;
-	srq->tail = srq->max - 1;
+	srq->tail = srq->wqe_cnt - 1;
 
 	ret = hns_roce_mtt_init(hr_dev, srq->buf.npages, srq->buf.page_shift,
 				&srq->mtt);
@@ -308,7 +313,7 @@
 	if (ret)
 		goto err_kernel_idx_buf;
 
-	srq->wrid = kvmalloc_array(srq->max, sizeof(u64), GFP_KERNEL);
+	srq->wrid = kvmalloc_array(srq->wqe_cnt, sizeof(u64), GFP_KERNEL);
 	if (!srq->wrid) {
 		ret = -ENOMEM;
 		goto err_kernel_idx_buf;
@@ -354,7 +359,7 @@
 }
 
 int hns_roce_create_srq(struct ib_srq *ib_srq,
-			struct ib_srq_init_attr *srq_init_attr,
+			struct ib_srq_init_attr *init_attr,
 			struct ib_udata *udata)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(ib_srq->device);
@@ -366,24 +371,25 @@
 	u32 cqn;
 
 	/* Check the actual SRQ wqe and SRQ sge num */
-	if (srq_init_attr->attr.max_wr >= hr_dev->caps.max_srq_wrs ||
-	    srq_init_attr->attr.max_sge > hr_dev->caps.max_srq_sges)
+	if (init_attr->attr.max_wr >= hr_dev->caps.max_srq_wrs ||
+	    init_attr->attr.max_sge > hr_dev->caps.max_srq_sges)
 		return -EINVAL;
 
 	mutex_init(&srq->mutex);
 	spin_lock_init(&srq->lock);
 
-	srq->max = roundup_pow_of_two(srq_init_attr->attr.max_wr + 1);
-	srq->max_gs = srq_init_attr->attr.max_sge;
+	srq->wqe_cnt = roundup_pow_of_two(init_attr->attr.max_wr + 1);
+	srq->max_gs = init_attr->attr.max_sge;
 
-	srq_desc_size = roundup_pow_of_two(max(16, 16 * srq->max_gs));
+	srq_desc_size = roundup_pow_of_two(max(HNS_ROCE_SGE_SIZE,
+					HNS_ROCE_SGE_SIZE * srq->max_gs));
 
 	srq->wqe_shift = ilog2(srq_desc_size);
 
-	srq_buf_size = srq->max * srq_desc_size;
+	srq_buf_size = srq->wqe_cnt * srq_desc_size;
 
 	srq->idx_que.entry_sz = HNS_ROCE_IDX_QUE_ENTRY_SZ;
-	srq->idx_que.buf_size = srq->max * srq->idx_que.entry_sz;
+	srq->idx_que.buf_size = srq->wqe_cnt * srq->idx_que.entry_sz;
 	srq->mtt.mtt_type = MTT_TYPE_SRQWQE;
 	srq->idx_que.mtt.mtt_type = MTT_TYPE_IDX;
 
@@ -401,8 +407,8 @@
 		}
 	}
 
-	cqn = ib_srq_has_cq(srq_init_attr->srq_type) ?
-	      to_hr_cq(srq_init_attr->ext.cq)->cqn : 0;
+	cqn = ib_srq_has_cq(init_attr->srq_type) ?
+	      to_hr_cq(init_attr->ext.cq)->cqn : 0;
 
 	srq->db_reg_l = hr_dev->reg_base + SRQ_DB_REG;
 
@@ -449,7 +455,7 @@
 		hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
 	} else {
 		kvfree(srq->wrid);
-		hns_roce_buf_free(hr_dev, srq->max << srq->wqe_shift,
+		hns_roce_buf_free(hr_dev, srq->wqe_cnt << srq->wqe_shift,
 				  &srq->buf);
 	}
 	ib_umem_release(srq->idx_que.umem);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw.h
@@ -398,8 +398,8 @@
 }
 
 /* i40iw.c */
-void i40iw_add_ref(struct ib_qp *);
-void i40iw_rem_ref(struct ib_qp *);
+void i40iw_qp_add_ref(struct ib_qp *ibqp);
+void i40iw_qp_rem_ref(struct ib_qp *ibqp);
 struct ib_qp *i40iw_get_qp(struct ib_device *, int);
 
 void i40iw_flush_wqes(struct i40iw_device *iwdev,
@@ -411,9 +411,8 @@
 			    bool ipv4,
 			    u32 action);
 
-int i40iw_manage_apbvt(struct i40iw_device *iwdev,
-		       u16 accel_local_port,
-		       bool add_port);
+enum i40iw_status_code i40iw_manage_apbvt(struct i40iw_device *iwdev,
+					  u16 accel_local_port, bool add_port);
 
 struct i40iw_cqp_request *i40iw_get_cqp_request(struct i40iw_cqp *cqp, bool wait);
 void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request);
@@ -543,9 +542,8 @@
 					  bool wait);
 void i40iw_receive_ilq(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *rbuf);
 void i40iw_free_sqbuf(struct i40iw_sc_vsi *vsi, void *bufp);
-void i40iw_free_qp_resources(struct i40iw_device *iwdev,
-			     struct i40iw_qp *iwqp,
-			     u32 qp_num);
+void i40iw_free_qp_resources(struct i40iw_qp *iwqp);
+
 enum i40iw_status_code i40iw_obj_aligned_mem(struct i40iw_device *iwdev,
 					     struct i40iw_dma_mem *memptr,
 					     u32 size, u32 mask);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_cm.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_cm.c
@@ -1987,7 +1987,6 @@
 	struct rtable *rt;
 	struct neighbour *neigh;
 	int rc = arpindex;
-	struct net_device *netdev = iwdev->netdev;
 	__be32 dst_ipaddr = htonl(dst_ip);
 	__be32 src_ipaddr = htonl(src_ip);
 
@@ -1997,9 +1996,6 @@
 		return rc;
 	}
 
-	if (netif_is_bond_slave(netdev))
-		netdev = netdev_master_upper_dev_get(netdev);
-
 	neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
 
 	rcu_read_lock();
@@ -2065,7 +2061,6 @@
 {
 	struct neighbour *neigh;
 	int rc = arpindex;
-	struct net_device *netdev = iwdev->netdev;
 	struct dst_entry *dst;
 	struct sockaddr_in6 dst_addr;
 	struct sockaddr_in6 src_addr;
@@ -2079,16 +2074,13 @@
 	dst = i40iw_get_dst_ipv6(&src_addr, &dst_addr);
 	if (!dst || dst->error) {
 		if (dst) {
-			dst_release(dst);
 			i40iw_pr_err("ip6_route_output returned dst->error = %d\n",
 				     dst->error);
+			dst_release(dst);
 		}
 		return rc;
 	}
 
-	if (netif_is_bond_slave(netdev))
-		netdev = netdev_master_upper_dev_get(netdev);
-
 	neigh = dst_neigh_lookup(dst, dst_addr.sin6_addr.in6_u.u6_addr32);
 
 	rcu_read_lock();
@@ -2330,7 +2322,7 @@
 	iwqp = cm_node->iwqp;
 	if (iwqp) {
 		iwqp->cm_node = NULL;
-		i40iw_rem_ref(&iwqp->ibqp);
+		i40iw_qp_rem_ref(&iwqp->ibqp);
 		cm_node->iwqp = NULL;
 	} else if (cm_node->qhash_set) {
 		i40iw_get_addr_info(cm_node, &nfo);
@@ -3460,7 +3452,7 @@
 		kfree(work);
 		return;
 	}
-	i40iw_add_ref(&iwqp->ibqp);
+	i40iw_qp_add_ref(&iwqp->ibqp);
 	spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
 
 	work->iwqp = iwqp;
@@ -3631,7 +3623,7 @@
 
 	kfree(dwork);
 	i40iw_cm_disconn_true(iwqp);
-	i40iw_rem_ref(&iwqp->ibqp);
+	i40iw_qp_rem_ref(&iwqp->ibqp);
 }
 
 /**
@@ -3753,7 +3745,7 @@
 	cm_node->lsmm_size = accept.size + conn_param->private_data_len;
 	i40iw_cm_init_tsa_conn(iwqp, cm_node);
 	cm_id->add_ref(cm_id);
-	i40iw_add_ref(&iwqp->ibqp);
+	i40iw_qp_add_ref(&iwqp->ibqp);
 
 	attr.qp_state = IB_QPS_RTS;
 	cm_node->qhash_set = false;
@@ -3916,7 +3908,7 @@
 	iwqp->cm_node = cm_node;
 	cm_node->iwqp = iwqp;
 	iwqp->cm_id = cm_id;
-	i40iw_add_ref(&iwqp->ibqp);
+	i40iw_qp_add_ref(&iwqp->ibqp);
 
 	if (cm_node->state != I40IW_CM_STATE_OFFLOADED) {
 		cm_node->state = I40IW_CM_STATE_SYN_SENT;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
@@ -2945,6 +2945,9 @@
 	u64 header;
 	enum i40iw_page_size page_size;
 
+	if (!info->total_len && !info->all_memory)
+		return -EINVAL;
+
 	page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K;
 	cqp = dev->cqp;
 	wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
@@ -3003,6 +3006,9 @@
 	u8 addr_type;
 	enum i40iw_page_size page_size;
 
+	if (!info->total_len && !info->all_memory)
+		return -EINVAL;
+
 	page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K;
 	if (info->access_rights & (I40IW_ACCESS_FLAGS_REMOTEREAD_ONLY |
 				   I40IW_ACCESS_FLAGS_REMOTEWRITE_ONLY))
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_hw.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_hw.c
@@ -313,7 +313,7 @@
 					    __func__, info->qp_cq_id);
 				continue;
 			}
-			i40iw_add_ref(&iwqp->ibqp);
+			i40iw_qp_add_ref(&iwqp->ibqp);
 			spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
 			qp = &iwqp->sc_qp;
 			spin_lock_irqsave(&iwqp->lock, flags);
@@ -427,7 +427,7 @@
 			break;
 		}
 		if (info->qp)
-			i40iw_rem_ref(&iwqp->ibqp);
+			i40iw_qp_rem_ref(&iwqp->ibqp);
 	} while (1);
 
 	if (aeqcnt)
@@ -534,7 +534,7 @@
 	int arp_index;
 
 	arp_index = i40iw_arp_table(iwdev, ip_addr, ipv4, mac_addr, action);
-	if (arp_index == -1)
+	if (arp_index < 0)
 		return;
 	cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
 	if (!cqp_request)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_main.c
@@ -54,10 +54,6 @@
 #define DRV_VERSION	__stringify(DRV_VERSION_MAJOR) "."		\
 	__stringify(DRV_VERSION_MINOR) "." __stringify(DRV_VERSION_BUILD)
 
-static int push_mode;
-module_param(push_mode, int, 0644);
-MODULE_PARM_DESC(push_mode, "Low latency mode: 0=disabled (default), 1=enabled)");
-
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug flags: 0=disabled (default), 0x7fffffff=all");
@@ -1225,6 +1221,8 @@
 			const struct in_ifaddr *ifa;
 
 			idev = in_dev_get(dev);
+			if (!idev)
+				continue;
 			in_dev_for_each_ifa_rtnl(ifa, idev) {
 				i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
 					    "IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
@@ -1586,7 +1584,6 @@
 	if (status)
 		goto exit;
 	iwdev->obj_next = iwdev->obj_mem;
-	iwdev->push_mode = push_mode;
 
 	init_waitqueue_head(&iwdev->vchnl_waitq);
 	init_waitqueue_head(&dev->vf_reqs);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_pble.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_pble.c
@@ -392,12 +392,9 @@
 	i40iw_debug(dev, I40IW_DEBUG_PBLE, "next_fpm_addr = %llx chunk_size[%u] = 0x%x\n",
 		    pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
 	pble_rsrc->unallocated_pble -= (chunk->size >> 3);
-	list_add(&chunk->list, &pble_rsrc->pinfo.clist);
 	sd_reg_val = (sd_entry_type == I40IW_SD_TYPE_PAGED) ?
 			sd_entry->u.pd_table.pd_page_addr.pa : sd_entry->u.bp.addr.pa;
-	if (sd_entry->valid)
-		return 0;
-	if (dev->is_pf) {
+	if (dev->is_pf && !sd_entry->valid) {
 		ret_code = i40iw_hmc_sd_one(dev, hmc_info->hmc_fn_id,
 					    sd_reg_val, idx->sd_idx,
 					    sd_entry->entry_type, true);
@@ -408,6 +405,7 @@
 	}
 
 	sd_entry->valid = true;
+	list_add(&chunk->list, &pble_rsrc->pinfo.clist);
 	return 0;
  error:
 	kfree(chunk);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_type.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_type.h
@@ -779,6 +779,7 @@
 	bool use_hmc_fcn_index;
 	u8 hmc_fcn_index;
 	bool use_pf_rid;
+	bool all_memory;
 };
 
 struct i40iw_reg_ns_stag_info {
@@ -797,6 +798,7 @@
 	bool use_hmc_fcn_index;
 	u8 hmc_fcn_index;
 	bool use_pf_rid;
+	bool all_memory;
 };
 
 struct i40iw_fast_reg_stag_info {
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_utils.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_utils.c
@@ -480,25 +480,6 @@
 }
 
 /**
- * i40iw_free_qp - callback after destroy cqp completes
- * @cqp_request: cqp request for destroy qp
- * @num: not used
- */
-static void i40iw_free_qp(struct i40iw_cqp_request *cqp_request, u32 num)
-{
-	struct i40iw_sc_qp *qp = (struct i40iw_sc_qp *)cqp_request->param;
-	struct i40iw_qp *iwqp = (struct i40iw_qp *)qp->back_qp;
-	struct i40iw_device *iwdev;
-	u32 qp_num = iwqp->ibqp.qp_num;
-
-	iwdev = iwqp->iwdev;
-
-	i40iw_rem_pdusecount(iwqp->iwpd, iwdev);
-	i40iw_free_qp_resources(iwdev, iwqp, qp_num);
-	i40iw_rem_devusecount(iwdev);
-}
-
-/**
  * i40iw_wait_event - wait for completion
  * @iwdev: iwarp device
  * @cqp_request: cqp request to wait
@@ -618,26 +599,23 @@
 }
 
 /**
- * i40iw_add_ref - add refcount for qp
+ * i40iw_qp_add_ref - add refcount for qp
  * @ibqp: iqarp qp
  */
-void i40iw_add_ref(struct ib_qp *ibqp)
+void i40iw_qp_add_ref(struct ib_qp *ibqp)
 {
 	struct i40iw_qp *iwqp = (struct i40iw_qp *)ibqp;
 
-	atomic_inc(&iwqp->refcount);
+	refcount_inc(&iwqp->refcount);
 }
 
 /**
- * i40iw_rem_ref - rem refcount for qp and free if 0
+ * i40iw_qp_rem_ref - rem refcount for qp and free if 0
  * @ibqp: iqarp qp
  */
-void i40iw_rem_ref(struct ib_qp *ibqp)
+void i40iw_qp_rem_ref(struct ib_qp *ibqp)
 {
 	struct i40iw_qp *iwqp;
-	enum i40iw_status_code status;
-	struct i40iw_cqp_request *cqp_request;
-	struct cqp_commands_info *cqp_info;
 	struct i40iw_device *iwdev;
 	u32 qp_num;
 	unsigned long flags;
@@ -645,7 +623,7 @@
 	iwqp = to_iwqp(ibqp);
 	iwdev = iwqp->iwdev;
 	spin_lock_irqsave(&iwdev->qptable_lock, flags);
-	if (!atomic_dec_and_test(&iwqp->refcount)) {
+	if (!refcount_dec_and_test(&iwqp->refcount)) {
 		spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
 		return;
 	}
@@ -653,25 +631,8 @@
 	qp_num = iwqp->ibqp.qp_num;
 	iwdev->qp_table[qp_num] = NULL;
 	spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
-	cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
-	if (!cqp_request)
-		return;
-
-	cqp_request->callback_fcn = i40iw_free_qp;
-	cqp_request->param = (void *)&iwqp->sc_qp;
-	cqp_info = &cqp_request->info;
-	cqp_info->cqp_cmd = OP_QP_DESTROY;
-	cqp_info->post_sq = 1;
-	cqp_info->in.u.qp_destroy.qp = &iwqp->sc_qp;
-	cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request;
-	cqp_info->in.u.qp_destroy.remove_hash_idx = true;
-	status = i40iw_handle_cqp_op(iwdev, cqp_request);
-	if (!status)
-		return;
+	complete(&iwqp->free_qp);
 
-	i40iw_rem_pdusecount(iwqp->iwpd, iwdev);
-	i40iw_free_qp_resources(iwdev, iwqp, qp_num);
-	i40iw_rem_devusecount(iwdev);
 }
 
 /**
@@ -938,7 +899,7 @@
 	struct i40iw_sc_qp *qp = (struct i40iw_sc_qp *)&iwqp->sc_qp;
 
 	i40iw_terminate_done(qp, 1);
-	i40iw_rem_ref(&iwqp->ibqp);
+	i40iw_qp_rem_ref(&iwqp->ibqp);
 }
 
 /**
@@ -950,7 +911,7 @@
 	struct i40iw_qp *iwqp;
 
 	iwqp = (struct i40iw_qp *)qp->back_qp;
-	i40iw_add_ref(&iwqp->ibqp);
+	i40iw_qp_add_ref(&iwqp->ibqp);
 	timer_setup(&iwqp->terminate_timer, i40iw_terminate_timeout, 0);
 	iwqp->terminate_timer.expires = jiffies + HZ;
 	add_timer(&iwqp->terminate_timer);
@@ -966,7 +927,7 @@
 
 	iwqp = (struct i40iw_qp *)qp->back_qp;
 	if (del_timer(&iwqp->terminate_timer))
-		i40iw_rem_ref(&iwqp->ibqp);
+		i40iw_qp_rem_ref(&iwqp->ibqp);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_verbs.c
@@ -168,38 +168,16 @@
  */
 static int i40iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 {
-	struct i40iw_ucontext *ucontext;
-	u64 db_addr_offset;
-	u64 push_offset;
-
-	ucontext = to_ucontext(context);
-	if (ucontext->iwdev->sc_dev.is_pf) {
-		db_addr_offset = I40IW_DB_ADDR_OFFSET;
-		push_offset = I40IW_PUSH_OFFSET;
-		if (vma->vm_pgoff)
-			vma->vm_pgoff += I40IW_PF_FIRST_PUSH_PAGE_INDEX - 1;
-	} else {
-		db_addr_offset = I40IW_VF_DB_ADDR_OFFSET;
-		push_offset = I40IW_VF_PUSH_OFFSET;
-		if (vma->vm_pgoff)
-			vma->vm_pgoff += I40IW_VF_FIRST_PUSH_PAGE_INDEX - 1;
-	}
+	struct i40iw_ucontext *ucontext = to_ucontext(context);
+	u64 dbaddr;
 
-	vma->vm_pgoff += db_addr_offset >> PAGE_SHIFT;
+	if (vma->vm_pgoff || vma->vm_end - vma->vm_start != PAGE_SIZE)
+		return -EINVAL;
 
-	if (vma->vm_pgoff == (db_addr_offset >> PAGE_SHIFT)) {
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		vma->vm_private_data = ucontext;
-	} else {
-		if ((vma->vm_pgoff - (push_offset >> PAGE_SHIFT)) % 2)
-			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		else
-			vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-	}
+	dbaddr = I40IW_DB_ADDR_OFFSET + pci_resource_start(ucontext->iwdev->ldev->pcidev, 0);
 
-	if (io_remap_pfn_range(vma, vma->vm_start,
-			       vma->vm_pgoff + (pci_resource_start(ucontext->iwdev->ldev->pcidev, 0) >> PAGE_SHIFT),
-			       PAGE_SIZE, vma->vm_page_prot))
+	if (io_remap_pfn_range(vma, vma->vm_start, dbaddr >> PAGE_SHIFT, PAGE_SIZE,
+			       pgprot_noncached(vma->vm_page_prot)))
 		return -EAGAIN;
 
 	return 0;
@@ -366,11 +344,11 @@
  * @iwqp: qp ptr (user or kernel)
  * @qp_num: qp number assigned
  */
-void i40iw_free_qp_resources(struct i40iw_device *iwdev,
-			     struct i40iw_qp *iwqp,
-			     u32 qp_num)
+void i40iw_free_qp_resources(struct i40iw_qp *iwqp)
 {
 	struct i40iw_pbl *iwpbl = &iwqp->iwpbl;
+	struct i40iw_device *iwdev = iwqp->iwdev;
+	u32 qp_num = iwqp->ibqp.qp_num;
 
 	i40iw_ieq_cleanup_qp(iwdev->vsi.ieq, &iwqp->sc_qp);
 	i40iw_dealloc_push_page(iwdev, &iwqp->sc_qp);
@@ -404,6 +382,10 @@
 static int i40iw_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
 {
 	struct i40iw_qp *iwqp = to_iwqp(ibqp);
+	struct ib_qp_attr attr;
+	struct i40iw_device *iwdev = iwqp->iwdev;
+
+	memset(&attr, 0, sizeof(attr));
 
 	iwqp->destroyed = 1;
 
@@ -418,7 +400,15 @@
 		}
 	}
 
-	i40iw_rem_ref(&iwqp->ibqp);
+	attr.qp_state = IB_QPS_ERR;
+	i40iw_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+	i40iw_qp_rem_ref(&iwqp->ibqp);
+	wait_for_completion(&iwqp->free_qp);
+	i40iw_cqp_qp_destroy_cmd(&iwdev->sc_dev, &iwqp->sc_qp);
+	i40iw_rem_pdusecount(iwqp->iwpd, iwdev);
+	i40iw_free_qp_resources(iwqp);
+	i40iw_rem_devusecount(iwdev);
+
 	return 0;
 }
 
@@ -579,6 +569,7 @@
 	qp->back_qp = (void *)iwqp;
 	qp->push_idx = I40IW_INVALID_PUSH_PAGE_INDEX;
 
+	iwqp->iwdev = iwdev;
 	iwqp->ctx_info.iwarp_info = &iwqp->iwarp_info;
 
 	if (i40iw_allocate_dma_mem(dev->hw,
@@ -603,7 +594,6 @@
 		goto error;
 	}
 
-	iwqp->iwdev = iwdev;
 	iwqp->iwpd = iwpd;
 	iwqp->ibqp.qp_num = qp_num;
 	qp = &iwqp->sc_qp;
@@ -717,7 +707,7 @@
 		goto error;
 	}
 
-	i40iw_add_ref(&iwqp->ibqp);
+	refcount_set(&iwqp->refcount, 1);
 	spin_lock_init(&iwqp->lock);
 	iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0;
 	iwdev->qp_table[qp_num] = iwqp;
@@ -739,10 +729,11 @@
 	}
 	init_completion(&iwqp->sq_drained);
 	init_completion(&iwqp->rq_drained);
+	init_completion(&iwqp->free_qp);
 
 	return &iwqp->ibqp;
 error:
-	i40iw_free_qp_resources(iwdev, iwqp, qp_num);
+	i40iw_free_qp_resources(iwqp);
 	return ERR_PTR(err_code);
 }
 
@@ -1509,7 +1500,8 @@
 static int i40iw_hw_alloc_stag(struct i40iw_device *iwdev, struct i40iw_mr *iwmr)
 {
 	struct i40iw_allocate_stag_info *info;
-	struct i40iw_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
+	struct ib_pd *pd = iwmr->ibmr.pd;
+	struct i40iw_pd *iwpd = to_iwpd(pd);
 	enum i40iw_status_code status;
 	int err = 0;
 	struct i40iw_cqp_request *cqp_request;
@@ -1526,6 +1518,7 @@
 	info->stag_idx = iwmr->stag >> I40IW_CQPSQ_STAG_IDX_SHIFT;
 	info->pd_id = iwpd->sc_pd.pd_id;
 	info->total_len = iwmr->length;
+	info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY;
 	info->remote_access = true;
 	cqp_info->cqp_cmd = OP_ALLOC_STAG;
 	cqp_info->post_sq = 1;
@@ -1579,6 +1572,8 @@
 	iwmr->type = IW_MEMREG_TYPE_MEM;
 	palloc = &iwpbl->pble_alloc;
 	iwmr->page_cnt = max_num_sg;
+	/* Use system PAGE_SIZE as the sg page sizes are unknown at this point */
+	iwmr->length = max_num_sg * PAGE_SIZE;
 	mutex_lock(&iwdev->pbl_mutex);
 	status = i40iw_get_pble(&iwdev->sc_dev, iwdev->pble_rsrc, palloc, iwmr->page_cnt);
 	mutex_unlock(&iwdev->pbl_mutex);
@@ -1675,7 +1670,8 @@
 {
 	struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
 	struct i40iw_reg_ns_stag_info *stag_info;
-	struct i40iw_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
+	struct ib_pd *pd = iwmr->ibmr.pd;
+	struct i40iw_pd *iwpd = to_iwpd(pd);
 	struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
 	enum i40iw_status_code status;
 	int err = 0;
@@ -1695,6 +1691,7 @@
 	stag_info->total_len = iwmr->length;
 	stag_info->access_rights = access;
 	stag_info->pd_id = iwpd->sc_pd.pd_id;
+	stag_info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY;
 	stag_info->addr_type = I40IW_ADDR_TYPE_VA_BASED;
 	stag_info->page_size = iwmr->page_size;
 
@@ -1763,7 +1760,7 @@
 
 	if (length > I40IW_MAX_MR_SIZE)
 		return ERR_PTR(-EINVAL);
-	region = ib_umem_get(udata, start, length, acc, 0);
+	region = ib_umem_get(pd->device, start, length, acc);
 	if (IS_ERR(region))
 		return (struct ib_mr *)region;
 
@@ -2654,13 +2651,13 @@
 	.get_hw_stats = i40iw_get_hw_stats,
 	.get_port_immutable = i40iw_port_immutable,
 	.iw_accept = i40iw_accept,
-	.iw_add_ref = i40iw_add_ref,
+	.iw_add_ref = i40iw_qp_add_ref,
 	.iw_connect = i40iw_connect,
 	.iw_create_listen = i40iw_create_listen,
 	.iw_destroy_listen = i40iw_destroy_listen,
 	.iw_get_qp = i40iw_get_qp,
 	.iw_reject = i40iw_reject,
-	.iw_rem_ref = i40iw_rem_ref,
+	.iw_rem_ref = i40iw_qp_rem_ref,
 	.map_mr_sg = i40iw_map_mr_sg,
 	.mmap = i40iw_mmap,
 	.modify_qp = i40iw_modify_qp,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/i40iw/i40iw_verbs.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/i40iw/i40iw_verbs.h
@@ -140,7 +140,7 @@
 	struct i40iw_qp_host_ctx_info ctx_info;
 	struct i40iwarp_offload_info iwarp_info;
 	void *allocated_buffer;
-	atomic_t refcount;
+	refcount_t refcount;
 	struct iw_cm_id *cm_id;
 	void *cm_node;
 	struct ib_mr *lsmm_mr;
@@ -175,5 +175,6 @@
 	struct i40iw_dma_mem ietf_mem;
 	struct completion sq_drained;
 	struct completion rq_drained;
+	struct completion free_qp;
 };
 #endif
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/cm.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/cm.c
@@ -186,23 +186,6 @@
 	kfree(ent);
 }
 
-static void id_map_find_del(struct ib_device *ibdev, int pv_cm_id)
-{
-	struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
-	struct rb_root *sl_id_map = &sriov->sl_id_map;
-	struct id_map_entry *ent, *found_ent;
-
-	spin_lock(&sriov->id_map_lock);
-	ent = xa_erase(&sriov->pv_id_table, pv_cm_id);
-	if (!ent)
-		goto out;
-	found_ent = id_map_find_by_sl_id(ibdev, ent->slave_id, ent->sl_cm_id);
-	if (found_ent && found_ent == ent)
-		rb_erase(&found_ent->node, sl_id_map);
-out:
-	spin_unlock(&sriov->id_map_lock);
-}
-
 static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
 {
 	struct rb_root *sl_id_map = &to_mdev(ibdev)->sriov.sl_id_map;
@@ -294,9 +277,12 @@
 	spin_lock(&sriov->id_map_lock);
 	spin_lock_irqsave(&sriov->going_down_lock, flags);
 	/*make sure that there is no schedule inside the scheduled work.*/
-	if (!sriov->is_going_down) {
+	if (!sriov->is_going_down && !id->scheduled_delete) {
 		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);
@@ -341,9 +327,6 @@
 
 	if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
 		schedule_delayed(ibdev, id);
-	else if (mad->mad_hdr.attr_id == CM_DREP_ATTR_ID)
-		id_map_find_del(ibdev, pv_cm_id);
-
 	return 0;
 }
 
@@ -382,12 +365,9 @@
 		*slave = id->slave_id;
 	set_remote_comm_id(mad, id->sl_cm_id);
 
-	if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
+	if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID ||
+	    mad->mad_hdr.attr_id == CM_REJ_ATTR_ID)
 		schedule_delayed(ibdev, id);
-	else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
-			mad->mad_hdr.attr_id == CM_DREP_ATTR_ID) {
-		id_map_find_del(ibdev, (int) pv_cm_id);
-	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/cq.c
@@ -144,8 +144,8 @@
 	int shift;
 	int n;
 
-	*umem = ib_umem_get(udata, buf_addr, cqe * cqe_size,
-			    IB_ACCESS_LOCAL_WRITE, 1);
+	*umem = ib_umem_get(&dev->ib_dev, buf_addr, cqe * cqe_size,
+			    IB_ACCESS_LOCAL_WRITE);
 	if (IS_ERR(*umem))
 		return PTR_ERR(*umem);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/doorbell.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/doorbell.c
@@ -64,7 +64,8 @@
 
 	page->user_virt = (virt & PAGE_MASK);
 	page->refcnt    = 0;
-	page->umem = ib_umem_get(udata, virt & PAGE_MASK, PAGE_SIZE, 0, 0);
+	page->umem = ib_umem_get(context->ibucontext.device, virt & PAGE_MASK,
+				 PAGE_SIZE, 0);
 	if (IS_ERR(page->umem)) {
 		err = PTR_ERR(page->umem);
 		kfree(page);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/mad.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/mad.c
@@ -1307,6 +1307,18 @@
 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
 }
 
+static void mlx4_ib_wire_comp_handler(struct ib_cq *cq, void *arg)
+{
+	unsigned long flags;
+	struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context;
+	struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
+
+	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
+	if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE)
+		queue_work(ctx->wi_wq, &ctx->work);
+	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
+}
+
 static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx,
 				  struct mlx4_ib_demux_pv_qp *tun_qp,
 				  int index)
@@ -2009,7 +2021,8 @@
 		cq_size *= 2;
 
 	cq_attr.cqe = cq_size;
-	ctx->cq = ib_create_cq(ctx->ib_dev, mlx4_ib_tunnel_comp_handler,
+	ctx->cq = ib_create_cq(ctx->ib_dev,
+			       create_tun ? mlx4_ib_tunnel_comp_handler : mlx4_ib_wire_comp_handler,
 			       NULL, ctx, &cq_attr);
 	if (IS_ERR(ctx->cq)) {
 		ret = PTR_ERR(ctx->cq);
@@ -2046,6 +2059,7 @@
 		INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker);
 
 	ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq;
+	ctx->wi_wq = to_mdev(ibdev)->sriov.demux[port - 1].wi_wq;
 
 	ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP);
 	if (ret) {
@@ -2189,7 +2203,7 @@
 		goto err_mcg;
 	}
 
-	snprintf(name, sizeof name, "mlx4_ibt%d", port);
+	snprintf(name, sizeof(name), "mlx4_ibt%d", port);
 	ctx->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
 	if (!ctx->wq) {
 		pr_err("Failed to create tunnelling WQ for port %d\n", port);
@@ -2197,7 +2211,15 @@
 		goto err_wq;
 	}
 
-	snprintf(name, sizeof name, "mlx4_ibud%d", port);
+	snprintf(name, sizeof(name), "mlx4_ibwi%d", port);
+	ctx->wi_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
+	if (!ctx->wi_wq) {
+		pr_err("Failed to create wire WQ for port %d\n", port);
+		ret = -ENOMEM;
+		goto err_wiwq;
+	}
+
+	snprintf(name, sizeof(name), "mlx4_ibud%d", port);
 	ctx->ud_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
 	if (!ctx->ud_wq) {
 		pr_err("Failed to create up/down WQ for port %d\n", port);
@@ -2208,6 +2230,10 @@
 	return 0;
 
 err_udwq:
+	destroy_workqueue(ctx->wi_wq);
+	ctx->wi_wq = NULL;
+
+err_wiwq:
 	destroy_workqueue(ctx->wq);
 	ctx->wq = NULL;
 
@@ -2255,12 +2281,14 @@
 				ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING;
 		}
 		flush_workqueue(ctx->wq);
+		flush_workqueue(ctx->wi_wq);
 		for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
 			destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0);
 			free_pv_object(dev, i, ctx->port);
 		}
 		kfree(ctx->tun);
 		destroy_workqueue(ctx->ud_wq);
+		destroy_workqueue(ctx->wi_wq);
 		destroy_workqueue(ctx->wq);
 	}
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/main.c
@@ -246,6 +246,13 @@
 	return mlx4_ib_update_gids_v1(gids, ibdev, port_num);
 }
 
+static void free_gid_entry(struct gid_entry *entry)
+{
+	memset(&entry->gid, 0, sizeof(entry->gid));
+	kfree(entry->ctx);
+	entry->ctx = NULL;
+}
+
 static int mlx4_ib_add_gid(const struct ib_gid_attr *attr, void **context)
 {
 	struct mlx4_ib_dev *ibdev = to_mdev(attr->device);
@@ -306,6 +313,8 @@
 				     GFP_ATOMIC);
 		if (!gids) {
 			ret = -ENOMEM;
+			*context = NULL;
+			free_gid_entry(&port_gid_table->gids[free]);
 		} else {
 			for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) {
 				memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid));
@@ -317,6 +326,12 @@
 
 	if (!ret && hw_update) {
 		ret = mlx4_ib_update_gids(gids, ibdev, attr->port_num);
+		if (ret) {
+			spin_lock_bh(&iboe->lock);
+			*context = NULL;
+			free_gid_entry(&port_gid_table->gids[free]);
+			spin_unlock_bh(&iboe->lock);
+		}
 		kfree(gids);
 	}
 
@@ -346,10 +361,7 @@
 		if (!ctx->refcount) {
 			unsigned int real_index = ctx->real_index;
 
-			memset(&port_gid_table->gids[real_index].gid, 0,
-			       sizeof(port_gid_table->gids[real_index].gid));
-			kfree(port_gid_table->gids[real_index].ctx);
-			port_gid_table->gids[real_index].ctx = NULL;
+			free_gid_entry(&port_gid_table->gids[real_index]);
 			hw_update = 1;
 		}
 	}
@@ -565,12 +577,9 @@
 	props->cq_caps.max_cq_moderation_count = MLX4_MAX_CQ_COUNT;
 	props->cq_caps.max_cq_moderation_period = MLX4_MAX_CQ_PERIOD;
 
-	if (!mlx4_is_slave(dev->dev))
-		err = mlx4_get_internal_clock_params(dev->dev, &clock_params);
-
 	if (uhw->outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) {
 		resp.response_length += sizeof(resp.hca_core_clock_offset);
-		if (!err && !mlx4_is_slave(dev->dev)) {
+		if (!mlx4_get_internal_clock_params(dev->dev, &clock_params)) {
 			resp.comp_mask |= MLX4_IB_QUERY_DEV_RESP_MASK_CORE_CLOCK_OFFSET;
 			resp.hca_core_clock_offset = clock_params.offset % PAGE_SIZE;
 		}
@@ -769,7 +778,8 @@
 	props->ip_gids = true;
 	props->gid_tbl_len	= mdev->dev->caps.gid_table_len[port];
 	props->max_msg_sz	= mdev->dev->caps.max_msg_sz;
-	props->pkey_tbl_len	= 1;
+	if (mdev->dev->caps.pkey_table_len[port])
+		props->pkey_tbl_len = 1;
 	props->max_mtu		= IB_MTU_4096;
 	props->max_vl_num	= 2;
 	props->state		= IB_PORT_DOWN;
@@ -1146,7 +1156,8 @@
 		return rdma_user_mmap_io(context, vma,
 					 to_mucontext(context)->uar.pfn,
 					 PAGE_SIZE,
-					 pgprot_noncached(vma->vm_page_prot));
+					 pgprot_noncached(vma->vm_page_prot),
+					 NULL);
 
 	case 1:
 		if (dev->dev->caps.bf_reg_size == 0)
@@ -1155,7 +1166,8 @@
 			context, vma,
 			to_mucontext(context)->uar.pfn +
 				dev->dev->caps.num_uars,
-			PAGE_SIZE, pgprot_writecombine(vma->vm_page_prot));
+			PAGE_SIZE, pgprot_writecombine(vma->vm_page_prot),
+			NULL);
 
 	case 3: {
 		struct mlx4_clock_params params;
@@ -1171,7 +1183,8 @@
 					    params.bar) +
 			 params.offset) >>
 				PAGE_SHIFT,
-			PAGE_SIZE, pgprot_noncached(vma->vm_page_prot));
+			PAGE_SIZE, pgprot_noncached(vma->vm_page_prot),
+			NULL);
 	}
 
 	default:
@@ -1480,8 +1493,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 */
@@ -3008,16 +3022,17 @@
 	ibdev->ib_active = false;
 	flush_workqueue(wq);
 
-	mlx4_ib_close_sriov(ibdev);
-	mlx4_ib_mad_cleanup(ibdev);
-	ib_unregister_device(&ibdev->ib_dev);
-	mlx4_ib_diag_cleanup(ibdev);
 	if (ibdev->iboe.nb.notifier_call) {
 		if (unregister_netdevice_notifier(&ibdev->iboe.nb))
 			pr_warn("failure unregistering notifier\n");
 		ibdev->iboe.nb.notifier_call = NULL;
 	}
 
+	mlx4_ib_close_sriov(ibdev);
+	mlx4_ib_mad_cleanup(ibdev);
+	ib_unregister_device(&ibdev->ib_dev);
+	mlx4_ib_diag_cleanup(ibdev);
+
 	mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
 			      ibdev->steer_qpn_count);
 	kfree(ibdev->ib_uc_qpns_bitmap);
@@ -3279,7 +3294,7 @@
 	case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
 		ew = kmalloc(sizeof *ew, GFP_ATOMIC);
 		if (!ew)
-			break;
+			return;
 
 		INIT_WORK(&ew->work, handle_port_mgmt_change_event);
 		memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -459,6 +459,7 @@
 	struct ib_pd *pd;
 	struct work_struct work;
 	struct workqueue_struct *wq;
+	struct workqueue_struct *wi_wq;
 	struct mlx4_ib_demux_pv_qp qp[2];
 };
 
@@ -466,6 +467,7 @@
 	struct ib_device *ib_dev;
 	int port;
 	struct workqueue_struct *wq;
+	struct workqueue_struct *wi_wq;
 	struct workqueue_struct *ud_wq;
 	spinlock_t ud_lock;
 	atomic64_t subnet_prefix;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/mr.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/mr.c
@@ -367,7 +367,7 @@
 	return block_shift;
 }
 
-static struct ib_umem *mlx4_get_umem_mr(struct ib_udata *udata, u64 start,
+static struct ib_umem *mlx4_get_umem_mr(struct ib_device *device, u64 start,
 					u64 length, int access_flags)
 {
 	/*
@@ -398,7 +398,7 @@
 		up_read(&current->mm->mmap_sem);
 	}
 
-	return ib_umem_get(udata, start, length, access_flags, 0);
+	return ib_umem_get(device, start, length, access_flags);
 }
 
 struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
@@ -415,7 +415,7 @@
 	if (!mr)
 		return ERR_PTR(-ENOMEM);
 
-	mr->umem = mlx4_get_umem_mr(udata, start, length, access_flags);
+	mr->umem = mlx4_get_umem_mr(pd->device, start, length, access_flags);
 	if (IS_ERR(mr->umem)) {
 		err = PTR_ERR(mr->umem);
 		goto err_free;
@@ -439,7 +439,6 @@
 
 	mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key;
 	mr->ibmr.length = length;
-	mr->ibmr.iova = virt_addr;
 	mr->ibmr.page_size = 1U << shift;
 
 	return &mr->ibmr;
@@ -504,7 +503,7 @@
 
 		mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
 		ib_umem_release(mmr->umem);
-		mmr->umem = mlx4_get_umem_mr(udata, start, length,
+		mmr->umem = mlx4_get_umem_mr(mr->device, start, length,
 					     mr_access_flags);
 		if (IS_ERR(mmr->umem)) {
 			err = PTR_ERR(mmr->umem);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/qp.c
@@ -438,9 +438,13 @@
 			    struct mlx4_ib_qp *qp,
 			    struct mlx4_ib_create_qp *ucmd)
 {
+	u32 cnt;
+
 	/* Sanity check SQ size before proceeding */
-	if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes	 ||
-	    ucmd->log_sq_stride >
+	if (check_shl_overflow(1, ucmd->log_sq_bb_count, &cnt) ||
+	    cnt > dev->dev->caps.max_wqes)
+		return -EINVAL;
+	if (ucmd->log_sq_stride >
 		ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) ||
 	    ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE)
 		return -EINVAL;
@@ -552,15 +556,15 @@
 		return (-EOPNOTSUPP);
 	}
 
-	if (ucmd->rx_hash_fields_mask & ~(MLX4_IB_RX_HASH_SRC_IPV4	|
-					  MLX4_IB_RX_HASH_DST_IPV4	|
-					  MLX4_IB_RX_HASH_SRC_IPV6	|
-					  MLX4_IB_RX_HASH_DST_IPV6	|
-					  MLX4_IB_RX_HASH_SRC_PORT_TCP	|
-					  MLX4_IB_RX_HASH_DST_PORT_TCP	|
-					  MLX4_IB_RX_HASH_SRC_PORT_UDP	|
-					  MLX4_IB_RX_HASH_DST_PORT_UDP  |
-					  MLX4_IB_RX_HASH_INNER)) {
+	if (ucmd->rx_hash_fields_mask & ~(u64)(MLX4_IB_RX_HASH_SRC_IPV4	|
+					       MLX4_IB_RX_HASH_DST_IPV4	|
+					       MLX4_IB_RX_HASH_SRC_IPV6	|
+					       MLX4_IB_RX_HASH_DST_IPV6	|
+					       MLX4_IB_RX_HASH_SRC_PORT_TCP |
+					       MLX4_IB_RX_HASH_DST_PORT_TCP |
+					       MLX4_IB_RX_HASH_SRC_PORT_UDP |
+					       MLX4_IB_RX_HASH_DST_PORT_UDP |
+					       MLX4_IB_RX_HASH_INNER)) {
 		pr_debug("RX Hash fields_mask has unsupported mask (0x%llx)\n",
 			 ucmd->rx_hash_fields_mask);
 		return (-EOPNOTSUPP);
@@ -916,7 +920,7 @@
 	qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
 		       (qp->sq.wqe_cnt << qp->sq.wqe_shift);
 
-	qp->umem = ib_umem_get(udata, wq.buf_addr, qp->buf_size, 0, 0);
+	qp->umem = ib_umem_get(pd->device, wq.buf_addr, qp->buf_size, 0);
 	if (IS_ERR(qp->umem)) {
 		err = PTR_ERR(qp->umem);
 		goto err;
@@ -1111,7 +1115,7 @@
 			goto err;
 
 		qp->umem =
-			ib_umem_get(udata, ucmd.buf_addr, qp->buf_size, 0, 0);
+			ib_umem_get(pd->device, ucmd.buf_addr, qp->buf_size, 0);
 		if (IS_ERR(qp->umem)) {
 			err = PTR_ERR(qp->umem);
 			goto err;
@@ -1149,8 +1153,10 @@
 			if (dev->steering_support ==
 			    MLX4_STEERING_MODE_DEVICE_MANAGED)
 				qp->flags |= MLX4_IB_QP_NETIF;
-			else
+			else {
+				err = -EINVAL;
 				goto err;
+			}
 		}
 
 		err = set_kernel_sq_size(dev, &init_attr->cap, qp_type, qp);
@@ -2891,6 +2897,7 @@
 	int send_size;
 	int header_size;
 	int spc;
+	int err;
 	int i;
 
 	if (wr->wr.opcode != IB_WR_SEND)
@@ -2925,7 +2932,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);
@@ -3212,9 +3221,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));
@@ -3533,11 +3547,11 @@
 	int nreq;
 	int err = 0;
 	unsigned ind;
-	int uninitialized_var(size);
-	unsigned uninitialized_var(seglen);
+	int size;
+	unsigned seglen;
 	__be32 dummy;
 	__be32 *lso_wqe;
-	__be32 uninitialized_var(lso_hdr_sz);
+	__be32 lso_hdr_sz;
 	__be32 blh;
 	int i;
 	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
@@ -4286,13 +4300,8 @@
 	if (wq_attr_mask & IB_WQ_FLAGS)
 		return -EOPNOTSUPP;
 
-	cur_state = wq_attr_mask & IB_WQ_CUR_STATE ? wq_attr->curr_wq_state :
-						     ibwq->state;
-	new_state = wq_attr_mask & IB_WQ_STATE ? wq_attr->wq_state : cur_state;
-
-	if (cur_state  < IB_WQS_RESET || cur_state  > IB_WQS_ERR ||
-	    new_state < IB_WQS_RESET || new_state > IB_WQS_ERR)
-		return -EINVAL;
+	cur_state = wq_attr->curr_wq_state;
+	new_state = wq_attr->wq_state;
 
 	if ((new_state == IB_WQS_RDY) && (cur_state == IB_WQS_ERR))
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/srq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/srq.c
@@ -110,7 +110,8 @@
 		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
 			return -EFAULT;
 
-		srq->umem = ib_umem_get(udata, ucmd.buf_addr, buf_size, 0, 0);
+		srq->umem =
+			ib_umem_get(ib_srq->device, ucmd.buf_addr, buf_size, 0);
 		if (IS_ERR(srq->umem))
 			return PTR_ERR(srq->umem);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx4/sysfs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx4/sysfs.c
@@ -221,7 +221,7 @@
 static int add_port_entries(struct mlx4_ib_dev *device, int port_num)
 {
 	int i;
-	char buff[11];
+	char buff[12];
 	struct mlx4_ib_iov_port *port = NULL;
 	int ret = 0 ;
 	struct ib_port_attr attr;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/cq.c
@@ -167,7 +167,7 @@
 {
 	enum rdma_link_layer ll = rdma_port_get_link_layer(qp->ibqp.device, 1);
 	struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
-	struct mlx5_ib_srq *srq;
+	struct mlx5_ib_srq *srq = NULL;
 	struct mlx5_ib_wq *wq;
 	u16 wqe_ctr;
 	u8  roce_packet_type;
@@ -179,7 +179,8 @@
 
 		if (qp->ibqp.xrcd) {
 			msrq = mlx5_cmd_get_srq(dev, be32_to_cpu(cqe->srqn));
-			srq = to_mibsrq(msrq);
+			if (msrq)
+				srq = to_mibsrq(msrq);
 		} else {
 			srq = to_msrq(qp->ibqp.srq);
 		}
@@ -330,6 +331,22 @@
 		dump_cqe(dev, cqe);
 }
 
+static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+			   u16 tail, u16 head)
+{
+	u16 idx;
+
+	do {
+		idx = tail & (qp->sq.wqe_cnt - 1);
+		if (idx == head)
+			break;
+
+		tail = qp->sq.w_list[idx].next;
+	} while (1);
+	tail = qp->sq.w_list[idx].next;
+	qp->sq.last_poll = tail;
+}
+
 static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
 {
 	mlx5_frag_buf_free(dev->mdev, &buf->frag_buf);
@@ -368,7 +385,7 @@
 }
 
 static void sw_comp(struct mlx5_ib_qp *qp, int num_entries, struct ib_wc *wc,
-		    int *npolled, int is_send)
+		    int *npolled, bool is_send)
 {
 	struct mlx5_ib_wq *wq;
 	unsigned int cur;
@@ -383,10 +400,16 @@
 		return;
 
 	for (i = 0;  i < cur && np < num_entries; i++) {
-		wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+		unsigned int idx;
+
+		idx = (is_send) ? wq->last_poll : wq->tail;
+		idx &= (wq->wqe_cnt - 1);
+		wc->wr_id = wq->wrid[idx];
 		wc->status = IB_WC_WR_FLUSH_ERR;
 		wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
 		wq->tail++;
+		if (is_send)
+			wq->last_poll = wq->w_list[idx].next;
 		np++;
 		wc->qp = &qp->ibqp;
 		wc++;
@@ -476,6 +499,7 @@
 		wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
 		idx = wqe_ctr & (wq->wqe_cnt - 1);
 		handle_good_req(wc, cqe64, wq, idx);
+		handle_atomics(*cur_qp, cqe64, wq->last_poll, idx);
 		wc->wr_id = wq->wrid[idx];
 		wq->tail = wq->wqe_head[idx] + 1;
 		wc->status = IB_WC_SUCCESS;
@@ -709,8 +733,9 @@
 	*cqe_size = ucmd.cqe_size;
 
 	cq->buf.umem =
-		ib_umem_get(udata, ucmd.buf_addr, entries * ucmd.cqe_size,
-			    IB_ACCESS_LOCAL_WRITE, 1);
+		ib_umem_get_peer(&dev->ib_dev, ucmd.buf_addr,
+				 entries * ucmd.cqe_size,
+				 IB_ACCESS_LOCAL_WRITE, 0);
 	if (IS_ERR(cq->buf.umem)) {
 		err = PTR_ERR(cq->buf.umem);
 		return err;
@@ -805,15 +830,14 @@
 	ib_umem_release(cq->buf.umem);
 }
 
-static void init_cq_frag_buf(struct mlx5_ib_cq *cq,
-			     struct mlx5_ib_cq_buf *buf)
+static void init_cq_frag_buf(struct mlx5_ib_cq_buf *buf)
 {
 	int i;
 	void *cqe;
 	struct mlx5_cqe64 *cqe64;
 
 	for (i = 0; i < buf->nent; i++) {
-		cqe = get_cqe(cq, i);
+		cqe = mlx5_frag_buf_get_wqe(&buf->fbc, i);
 		cqe64 = buf->cqe_size == 64 ? cqe : cqe + 64;
 		cqe64->op_own = MLX5_CQE_INVALID << 4;
 	}
@@ -839,7 +863,7 @@
 	if (err)
 		goto err_db;
 
-	init_cq_frag_buf(cq, &cq->buf);
+	init_cq_frag_buf(&cq->buf);
 
 	*inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
 		 MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) *
@@ -893,8 +917,8 @@
 	struct mlx5_ib_dev *dev = to_mdev(ibdev);
 	struct mlx5_ib_cq *cq = to_mcq(ibcq);
 	u32 out[MLX5_ST_SZ_DW(create_cq_out)];
-	int uninitialized_var(index);
-	int uninitialized_var(inlen);
+	int index;
+	int inlen;
 	u32 *cqb = NULL;
 	void *cqc;
 	int cqe_size;
@@ -1109,9 +1133,9 @@
 	if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1)
 		return -EINVAL;
 
-	umem = ib_umem_get(udata, ucmd.buf_addr,
-			   (size_t)ucmd.cqe_size * entries,
-			   IB_ACCESS_LOCAL_WRITE, 1);
+	umem = ib_umem_get_peer(&dev->ib_dev, ucmd.buf_addr,
+				(size_t)ucmd.cqe_size * entries,
+				IB_ACCESS_LOCAL_WRITE, 0);
 	if (IS_ERR(umem)) {
 		err = PTR_ERR(umem);
 		return err;
@@ -1139,7 +1163,7 @@
 	if (err)
 		goto ex;
 
-	init_cq_frag_buf(cq, cq->resize_buf);
+	init_cq_frag_buf(cq->resize_buf);
 
 	return 0;
 
@@ -1214,7 +1238,7 @@
 	__be64 *pas;
 	int page_shift;
 	int inlen;
-	int uninitialized_var(cqe_size);
+	int cqe_size;
 	unsigned long flags;
 
 	if (!MLX5_CAP_GEN(dev->mdev, cq_resize)) {
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/devx.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/devx.c
@@ -100,6 +100,7 @@
 		struct mlx5_ib_devx_mr	devx_mr;
 		struct mlx5_core_dct	core_dct;
 		struct mlx5_core_cq	core_cq;
+		u32			flow_counter_bulk_size;
 	};
 	struct list_head event_sub; /* holds devx_event_subscription entries */
 };
@@ -192,15 +193,20 @@
 	}
 }
 
-bool mlx5_ib_devx_is_flow_counter(void *obj, u32 *counter_id)
+bool mlx5_ib_devx_is_flow_counter(void *obj, u32 offset, u32 *counter_id)
 {
 	struct devx_obj *devx_obj = obj;
 	u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, devx_obj->dinbox, opcode);
 
 	if (opcode == MLX5_CMD_OP_DEALLOC_FLOW_COUNTER) {
+
+		if (offset && offset >= devx_obj->flow_counter_bulk_size)
+			return false;
+
 		*counter_id = MLX5_GET(dealloc_flow_counter_in,
 				       devx_obj->dinbox,
 				       flow_counter_id);
+		*counter_id += offset;
 		return true;
 	}
 
@@ -489,6 +495,10 @@
 		obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
 					MLX5_GET(rst2init_qp_in, in, qpn));
 		break;
+	case MLX5_CMD_OP_INIT2INIT_QP:
+		obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+					MLX5_GET(init2init_qp_in, in, qpn));
+		break;
 	case MLX5_CMD_OP_INIT2RTR_QP:
 		obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
 					MLX5_GET(init2rtr_qp_in, in, qpn));
@@ -814,6 +824,7 @@
 	case MLX5_CMD_OP_SET_L2_TABLE_ENTRY:
 	case MLX5_CMD_OP_RST2INIT_QP:
 	case MLX5_CMD_OP_INIT2RTR_QP:
+	case MLX5_CMD_OP_INIT2INIT_QP:
 	case MLX5_CMD_OP_RTR2RTS_QP:
 	case MLX5_CMD_OP_RTS2RTS_QP:
 	case MLX5_CMD_OP_SQERR2RTS_QP:
@@ -1113,7 +1124,9 @@
 		MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_RQT);
 		break;
 	case MLX5_CMD_OP_CREATE_TIR:
-		MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_TIR);
+		*obj_id = MLX5_GET(create_tir_out, out, tirn);
+		MLX5_SET(destroy_tir_in, din, opcode, MLX5_CMD_OP_DESTROY_TIR);
+		MLX5_SET(destroy_tir_in, din, tirn, *obj_id);
 		break;
 	case MLX5_CMD_OP_CREATE_TIS:
 		MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_TIS);
@@ -1463,6 +1476,13 @@
 	if (err)
 		goto obj_free;
 
+	if (opcode == MLX5_CMD_OP_ALLOC_FLOW_COUNTER) {
+		u8 bulk = MLX5_GET(alloc_flow_counter_in,
+				   cmd_in,
+				   flow_counter_bulk);
+		obj->flow_counter_bulk_size = 128UL * bulk;
+	}
+
 	uobj->object = obj;
 	INIT_LIST_HEAD(&obj->event_sub);
 	obj->ib_dev = dev;
@@ -1837,8 +1857,10 @@
 				key_level2,
 				obj_event,
 				GFP_KERNEL);
-		if (err)
+		if (err) {
+			kfree(obj_event);
 			return err;
+		}
 		INIT_LIST_HEAD(&obj_event->obj_sub_list);
 	}
 
@@ -2015,8 +2037,10 @@
 
 		num_alloc_xa_entries++;
 		event_sub = kzalloc(sizeof(*event_sub), GFP_KERNEL);
-		if (!event_sub)
+		if (!event_sub) {
+			err = -ENOMEM;
 			goto err;
+		}
 
 		list_add_tail(&event_sub->event_list, &sub_list);
 		if (use_eventfd) {
@@ -2121,7 +2145,7 @@
 	if (err)
 		return err;
 
-	obj->umem = ib_umem_get(&attrs->driver_udata, addr, size, access, 0);
+	obj->umem = ib_umem_get_peer(&dev->ib_dev, addr, size, access, 0);
 	if (IS_ERR(obj->umem))
 		return PTR_ERR(obj->umem);
 
@@ -2168,6 +2192,8 @@
 	mlx5_ib_populate_pas(dev, obj->umem, obj->page_shift, mtt,
 			     (obj->umem->writable ? MLX5_IB_MTT_WRITE : 0) |
 			     MLX5_IB_MTT_READ);
+	if (obj->umem->is_peer && MLX5_CAP_GEN(dev->mdev, ats))
+		MLX5_SET(umem, umem, ats, 1);
 }
 
 static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)(
@@ -2545,7 +2571,7 @@
 {
 	struct devx_async_event_file *ev_file = filp->private_data;
 	struct devx_event_subscription *event_sub;
-	struct devx_async_event_data *uninitialized_var(event);
+	struct devx_async_event_data *event;
 	int ret = 0;
 	size_t eventsz;
 	bool omit_data;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/doorbell.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/doorbell.c
@@ -64,7 +64,8 @@
 
 	page->user_virt = (virt & PAGE_MASK);
 	page->refcnt    = 0;
-	page->umem = ib_umem_get(udata, virt & PAGE_MASK, PAGE_SIZE, 0, 0);
+	page->umem = ib_umem_get_peer(context->ibucontext.device, virt & PAGE_MASK,
+				      PAGE_SIZE, 0, 0);
 	if (IS_ERR(page->umem)) {
 		err = PTR_ERR(page->umem);
 		kfree(page);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/flow.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/flow.c
@@ -13,6 +13,7 @@
 #include <rdma/ib_umem.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/fs.h>
+#include <linux/mlx5/eswitch.h>
 #include "mlx5_ib.h"
 
 #define UVERBS_MODULE_NAME mlx5_ib
@@ -85,6 +86,8 @@
 	struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata);
 	int len, ret, i;
 	u32 counter_id = 0;
+	u32 *offset_attr;
+	u32 offset = 0;
 
 	if (!capable(CAP_NET_RAW))
 		return -EPERM;
@@ -151,8 +154,27 @@
 	if (len) {
 		devx_obj = arr_flow_actions[0]->object;
 
-		if (!mlx5_ib_devx_is_flow_counter(devx_obj, &counter_id))
+		if (uverbs_attr_is_valid(attrs,
+					 MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET)) {
+
+			int num_offsets = uverbs_attr_ptr_get_array_size(
+				attrs,
+				MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET,
+				sizeof(u32));
+
+			if (num_offsets != 1)
+				return -EINVAL;
+
+			offset_attr = uverbs_attr_get_alloced_ptr(
+				attrs,
+				MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET);
+			offset = *offset_attr;
+		}
+
+		if (!mlx5_ib_devx_is_flow_counter(devx_obj, offset,
+						  &counter_id))
 			return -EINVAL;
+
 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
 	}
 
@@ -316,6 +338,13 @@
 	if (err)
 		goto end;
 
+	if (obj->ns_type == MLX5_FLOW_NAMESPACE_FDB &&
+	    mlx5_eswitch_mode(dev->mdev->priv.eswitch) !=
+			      MLX5_ESWITCH_OFFLOADS) {
+		err = -EINVAL;
+		goto end;
+	}
+
 	uobj->object = obj;
 	obj->mdev = dev->mdev;
 	atomic_set(&obj->usecnt, 0);
@@ -598,7 +627,11 @@
 	UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX,
 			     MLX5_IB_OBJECT_DEVX_OBJ,
 			     UVERBS_ACCESS_READ, 1, 1,
-			     UA_OPTIONAL));
+			     UA_OPTIONAL),
+	UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX_OFFSET,
+			   UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
+			   UA_OPTIONAL,
+			   UA_ALLOC_AND_COPY));
 
 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
 	MLX5_IB_METHOD_DESTROY_FLOW,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/gsi.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/gsi.c
@@ -507,8 +507,7 @@
 		ret = ib_post_send(tx_qp, &cur_wr.wr, bad_wr);
 		if (ret) {
 			/* Undo the effect of adding the outstanding wr */
-			gsi->outstanding_pi = (gsi->outstanding_pi - 1) %
-					      gsi->cap.max_send_wr;
+			gsi->outstanding_pi--;
 			goto err;
 		}
 		spin_unlock_irqrestore(&gsi->lock, flags);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/ib_rep.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/ib_rep.c
@@ -35,7 +35,7 @@
 	int vport_index;
 
 	if (rep->vport == MLX5_VPORT_UPLINK)
-		profile = &uplink_rep_profile;
+		profile = &raw_eth_profile;
 	else
 		return mlx5_ib_set_vport_rep(dev, rep);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/ib_rep.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/ib_rep.h
@@ -10,7 +10,7 @@
 #include "mlx5_ib.h"
 
 #ifdef CONFIG_MLX5_ESWITCH
-extern const struct mlx5_ib_profile uplink_rep_profile;
+extern const struct mlx5_ib_profile raw_eth_profile;
 
 u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw);
 struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/mad.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/mad.c
@@ -219,6 +219,12 @@
 		mdev = dev->mdev;
 		mdev_port_num = 1;
 	}
+	if (MLX5_CAP_GEN(dev->mdev, num_ports) == 1) {
+		/* set local port to one for Function-Per-Port HCA. */
+		mdev = dev->mdev;
+		mdev_port_num = 1;
+	}
+
 	/* Declaring support of extended counters */
 	if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) {
 		struct ib_class_port_info cpi = {};
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/main.c
@@ -517,7 +517,7 @@
 					   mdev_port_num);
 	if (err)
 		goto out;
-	ext = MLX5_CAP_PCAM_FEATURE(dev->mdev, ptys_extended_ethernet);
+	ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability);
 	eth_prot_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
 
 	props->active_width     = IB_WIDTH_4X;
@@ -829,6 +829,7 @@
 				struct ib_device_attr *props,
 				struct ib_udata *uhw)
 {
+	size_t uhw_outlen = (uhw) ? uhw->outlen : 0;
 	struct mlx5_ib_dev *dev = to_mdev(ibdev);
 	struct mlx5_core_dev *mdev = dev->mdev;
 	int err = -ENOMEM;
@@ -842,12 +843,12 @@
 	u64 max_tso;
 
 	resp_len = sizeof(resp.comp_mask) + sizeof(resp.response_length);
-	if (uhw->outlen && uhw->outlen < resp_len)
+	if (uhw_outlen && uhw_outlen < resp_len)
 		return -EINVAL;
 	else
 		resp.response_length = resp_len;
 
-	if (uhw->inlen && !ib_is_udata_cleared(uhw, 0, uhw->inlen))
+	if (uhw && uhw->inlen && !ib_is_udata_cleared(uhw, 0, uhw->inlen))
 		return -EINVAL;
 
 	memset(props, 0, sizeof(*props));
@@ -887,7 +888,9 @@
 		/* We support 'Gappy' memory registration too */
 		props->device_cap_flags |= IB_DEVICE_SG_GAPS_REG;
 	}
-	props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
+	/* IB_WR_REG_MR always requires changing the entity size with UMR */
+	if (!MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
+		props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
 	if (MLX5_CAP_GEN(mdev, sho)) {
 		props->device_cap_flags |= IB_DEVICE_INTEGRITY_HANDOVER;
 		/* At this stage no support for signature handover */
@@ -911,7 +914,7 @@
 			props->raw_packet_caps |=
 				IB_RAW_PACKET_CAP_CVLAN_STRIPPING;
 
-		if (field_avail(typeof(resp), tso_caps, uhw->outlen)) {
+		if (field_avail(typeof(resp), tso_caps, uhw_outlen)) {
 			max_tso = MLX5_CAP_ETH(mdev, max_lso_cap);
 			if (max_tso) {
 				resp.tso_caps.max_tso = 1 << max_tso;
@@ -921,7 +924,7 @@
 			}
 		}
 
-		if (field_avail(typeof(resp), rss_caps, uhw->outlen)) {
+		if (field_avail(typeof(resp), rss_caps, uhw_outlen)) {
 			resp.rss_caps.rx_hash_function =
 						MLX5_RX_HASH_FUNC_TOEPLITZ;
 			resp.rss_caps.rx_hash_fields_mask =
@@ -941,9 +944,9 @@
 			resp.response_length += sizeof(resp.rss_caps);
 		}
 	} else {
-		if (field_avail(typeof(resp), tso_caps, uhw->outlen))
+		if (field_avail(typeof(resp), tso_caps, uhw_outlen))
 			resp.response_length += sizeof(resp.tso_caps);
-		if (field_avail(typeof(resp), rss_caps, uhw->outlen))
+		if (field_avail(typeof(resp), rss_caps, uhw_outlen))
 			resp.response_length += sizeof(resp.rss_caps);
 	}
 
@@ -1066,7 +1069,7 @@
 						MLX5_MAX_CQ_PERIOD;
 	}
 
-	if (field_avail(typeof(resp), cqe_comp_caps, uhw->outlen)) {
+	if (field_avail(typeof(resp), cqe_comp_caps, uhw_outlen)) {
 		resp.response_length += sizeof(resp.cqe_comp_caps);
 
 		if (MLX5_CAP_GEN(dev->mdev, cqe_compression)) {
@@ -1084,7 +1087,7 @@
 		}
 	}
 
-	if (field_avail(typeof(resp), packet_pacing_caps, uhw->outlen) &&
+	if (field_avail(typeof(resp), packet_pacing_caps, uhw_outlen) &&
 	    raw_support) {
 		if (MLX5_CAP_QOS(mdev, packet_pacing) &&
 		    MLX5_CAP_GEN(mdev, qos)) {
@@ -1103,7 +1106,7 @@
 	}
 
 	if (field_avail(typeof(resp), mlx5_ib_support_multi_pkt_send_wqes,
-			uhw->outlen)) {
+			uhw_outlen)) {
 		if (MLX5_CAP_ETH(mdev, multi_pkt_send_wqe))
 			resp.mlx5_ib_support_multi_pkt_send_wqes =
 				MLX5_IB_ALLOW_MPW;
@@ -1116,7 +1119,7 @@
 			sizeof(resp.mlx5_ib_support_multi_pkt_send_wqes);
 	}
 
-	if (field_avail(typeof(resp), flags, uhw->outlen)) {
+	if (field_avail(typeof(resp), flags, uhw_outlen)) {
 		resp.response_length += sizeof(resp.flags);
 
 		if (MLX5_CAP_GEN(mdev, cqe_compression_128))
@@ -1132,8 +1135,7 @@
 		resp.flags |= MLX5_IB_QUERY_DEV_RESP_FLAGS_SCAT2CQE_DCT;
 	}
 
-	if (field_avail(typeof(resp), sw_parsing_caps,
-			uhw->outlen)) {
+	if (field_avail(typeof(resp), sw_parsing_caps, uhw_outlen)) {
 		resp.response_length += sizeof(resp.sw_parsing_caps);
 		if (MLX5_CAP_ETH(mdev, swp)) {
 			resp.sw_parsing_caps.sw_parsing_offloads |=
@@ -1153,7 +1155,7 @@
 		}
 	}
 
-	if (field_avail(typeof(resp), striding_rq_caps, uhw->outlen) &&
+	if (field_avail(typeof(resp), striding_rq_caps, uhw_outlen) &&
 	    raw_support) {
 		resp.response_length += sizeof(resp.striding_rq_caps);
 		if (MLX5_CAP_GEN(mdev, striding_rq)) {
@@ -1170,8 +1172,7 @@
 		}
 	}
 
-	if (field_avail(typeof(resp), tunnel_offloads_caps,
-			uhw->outlen)) {
+	if (field_avail(typeof(resp), tunnel_offloads_caps, uhw_outlen)) {
 		resp.response_length += sizeof(resp.tunnel_offloads_caps);
 		if (MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan))
 			resp.tunnel_offloads_caps |=
@@ -1182,17 +1183,15 @@
 		if (MLX5_CAP_ETH(mdev, tunnel_stateless_gre))
 			resp.tunnel_offloads_caps |=
 				MLX5_IB_TUNNELED_OFFLOADS_GRE;
-		if (MLX5_CAP_GEN(mdev, flex_parser_protocols) &
-		    MLX5_FLEX_PROTO_CW_MPLS_GRE)
+		if (MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_gre))
 			resp.tunnel_offloads_caps |=
 				MLX5_IB_TUNNELED_OFFLOADS_MPLS_GRE;
-		if (MLX5_CAP_GEN(mdev, flex_parser_protocols) &
-		    MLX5_FLEX_PROTO_CW_MPLS_UDP)
+		if (MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_udp))
 			resp.tunnel_offloads_caps |=
 				MLX5_IB_TUNNELED_OFFLOADS_MPLS_UDP;
 	}
 
-	if (uhw->outlen) {
+	if (uhw_outlen) {
 		err = ib_copy_to_udata(uhw, &resp, resp.response_length);
 
 		if (err)
@@ -2054,7 +2053,7 @@
 	case MLX5_IB_MMAP_DEVICE_MEM:
 		return "Device Memory";
 	default:
-		return NULL;
+		return "Unknown";
 	}
 }
 
@@ -2168,7 +2167,7 @@
 	mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn %pa\n", idx, &pfn);
 
 	err = rdma_user_mmap_io(&context->ibucontext, vma, pfn, PAGE_SIZE,
-				prot);
+				prot, NULL);
 	if (err) {
 		mlx5_ib_err(dev,
 			    "rdma_user_mmap_io failed with error=%d, mmap_cmd=%s\n",
@@ -2210,7 +2209,8 @@
 	      PAGE_SHIFT) +
 	      page_idx;
 	return rdma_user_mmap_io(context, vma, pfn, map_size,
-				 pgprot_writecombine(vma->vm_page_prot));
+				 pgprot_writecombine(vma->vm_page_prot),
+				 NULL);
 }
 
 static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
@@ -2248,7 +2248,8 @@
 			PAGE_SHIFT;
 		return rdma_user_mmap_io(&context->ibucontext, vma, pfn,
 					 PAGE_SIZE,
-					 pgprot_noncached(vma->vm_page_prot));
+					 pgprot_noncached(vma->vm_page_prot),
+					 NULL);
 	case MLX5_IB_MMAP_CLOCK_INFO:
 		return mlx5_ib_mmap_clock_info_page(dev, vma, context);
 
@@ -3548,10 +3549,6 @@
 	}
 
 	INIT_LIST_HEAD(&handler->list);
-	if (dst) {
-		memcpy(&dest_arr[0], dst, sizeof(*dst));
-		dest_num++;
-	}
 
 	for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
 		err = parse_flow_attr(dev->mdev, spec,
@@ -3564,6 +3561,11 @@
 		ib_flow += ((union ib_flow_spec *)ib_flow)->size;
 	}
 
+	if (dst && !(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP)) {
+		memcpy(&dest_arr[0], dst, sizeof(*dst));
+		dest_num++;
+	}
+
 	if (!flow_is_multicast_only(flow_attr))
 		set_underlay_qp(dev, spec, underlay_qpn);
 
@@ -3604,10 +3606,8 @@
 	}
 
 	if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
-		if (!(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT)) {
+		if (!dest_num)
 			rule_dst = NULL;
-			dest_num = 0;
-		}
 	} else {
 		if (is_egress)
 			flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
@@ -4739,7 +4739,6 @@
 	struct ib_device_attr *dprops = NULL;
 	struct ib_port_attr *pprops = NULL;
 	int err = -ENOMEM;
-	struct ib_udata uhw = {.inlen = 0, .outlen = 0};
 
 	pprops = kzalloc(sizeof(*pprops), GFP_KERNEL);
 	if (!pprops)
@@ -4749,7 +4748,7 @@
 	if (!dprops)
 		goto out;
 
-	err = mlx5_ib_query_device(&dev->ib_dev, dprops, &uhw);
+	err = mlx5_ib_query_device(&dev->ib_dev, dprops, NULL);
 	if (err) {
 		mlx5_ib_warn(dev, "query_device failed %d\n", err);
 		goto out;
@@ -5145,8 +5144,7 @@
 	immutable->pkey_tbl_len = attr.pkey_tbl_len;
 	immutable->gid_tbl_len = attr.gid_tbl_len;
 	immutable->core_cap_flags = get_core_cap_flags(ibdev, &rep);
-	if ((ll == IB_LINK_LAYER_INFINIBAND) || MLX5_CAP_GEN(dev->mdev, roce))
-		immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+	immutable->max_mad_size = IB_MGMT_MAD_SIZE;
 
 	return 0;
 }
@@ -5249,11 +5247,9 @@
 {
 	int err;
 
-	if (MLX5_CAP_GEN(dev->mdev, roce)) {
-		err = mlx5_nic_vport_enable_roce(dev->mdev);
-		if (err)
-			return err;
-	}
+	err = mlx5_nic_vport_enable_roce(dev->mdev);
+	if (err)
+		return err;
 
 	err = mlx5_eth_lag_init(dev);
 	if (err)
@@ -5262,8 +5258,7 @@
 	return 0;
 
 err_disable_roce:
-	if (MLX5_CAP_GEN(dev->mdev, roce))
-		mlx5_nic_vport_disable_roce(dev->mdev);
+	mlx5_nic_vport_disable_roce(dev->mdev);
 
 	return err;
 }
@@ -5271,8 +5266,7 @@
 static void mlx5_disable_eth(struct mlx5_ib_dev *dev)
 {
 	mlx5_eth_lag_cleanup(dev);
-	if (MLX5_CAP_GEN(dev->mdev, roce))
-		mlx5_nic_vport_disable_roce(dev->mdev);
+	mlx5_nic_vport_disable_roce(dev->mdev);
 }
 
 struct mlx5_ib_counter {
@@ -5641,9 +5635,10 @@
 	const struct mlx5_ib_counters *cnts =
 		get_counters(dev, counter->port - 1);
 
-	/* Q counters are in the beginning of all counters */
 	return rdma_alloc_hw_stats_struct(cnts->names,
-					  cnts->num_q_counters,
+					  cnts->num_q_counters +
+					  cnts->num_cong_counters +
+					  cnts->num_ext_ppcnt_counters,
 					  RDMA_HW_STATS_DEFAULT_LIFESPAN);
 }
 
@@ -5873,8 +5868,6 @@
 
 	port->mp.mpi = NULL;
 
-	list_add_tail(&mpi->list, &mlx5_ib_unaffiliated_port_list);
-
 	spin_unlock(&port->mp.mpi_lock);
 
 	err = mlx5_nic_vport_unaffiliate_multiport(mpi->mdev);
@@ -6027,6 +6020,8 @@
 				dev->port[i].mp.mpi = NULL;
 			} else {
 				mlx5_ib_dbg(dev, "unbinding port_num: %d\n", i + 1);
+				list_add_tail(&dev->port[i].mp.mpi->list,
+					      &mlx5_ib_unaffiliated_port_list);
 				mlx5_ib_unbind_slave_port(dev, dev->port[i].mp.mpi);
 			}
 		}
@@ -6175,7 +6170,7 @@
 
 	err = set_has_smi_cap(dev);
 	if (err)
-		return err;
+		goto err_mp;
 
 	if (!mlx5_core_mp_enabled(mdev)) {
 		for (i = 1; i <= dev->num_ports; i++) {
@@ -6215,8 +6210,7 @@
 
 err_mp:
 	mlx5_ib_cleanup_multiport_master(dev);
-
-	return -ENOMEM;
+	return err;
 }
 
 static int mlx5_ib_stage_flow_db_init(struct mlx5_ib_dev *dev)
@@ -6444,7 +6438,7 @@
 	.query_port = mlx5_ib_rep_query_port,
 };
 
-static int mlx5_ib_stage_rep_non_default_cb(struct mlx5_ib_dev *dev)
+static int mlx5_ib_stage_raw_eth_non_default_cb(struct mlx5_ib_dev *dev)
 {
 	ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_port_rep_ops);
 	return 0;
@@ -6484,7 +6478,7 @@
 	mlx5_remove_netdev_notifier(dev, port_num);
 }
 
-static int mlx5_ib_stage_rep_roce_init(struct mlx5_ib_dev *dev)
+static int mlx5_ib_stage_raw_eth_roce_init(struct mlx5_ib_dev *dev)
 {
 	struct mlx5_core_dev *mdev = dev->mdev;
 	enum rdma_link_layer ll;
@@ -6500,7 +6494,7 @@
 	return err;
 }
 
-static void mlx5_ib_stage_rep_roce_cleanup(struct mlx5_ib_dev *dev)
+static void mlx5_ib_stage_raw_eth_roce_cleanup(struct mlx5_ib_dev *dev)
 {
 	mlx5_ib_stage_common_roce_cleanup(dev);
 }
@@ -6628,7 +6622,7 @@
 
 	err = mlx5_alloc_bfreg(dev->mdev, &dev->fp_bfreg, false, true);
 	if (err)
-		mlx5_free_bfreg(dev->mdev, &dev->fp_bfreg);
+		mlx5_free_bfreg(dev->mdev, &dev->bfreg);
 
 	return err;
 }
@@ -6714,6 +6708,8 @@
 		      const struct mlx5_ib_profile *profile,
 		      int stage)
 {
+	dev->ib_active = false;
+
 	/* Number of stages to cleanup */
 	while (stage) {
 		stage--;
@@ -6807,7 +6803,7 @@
 		     mlx5_ib_stage_delay_drop_cleanup),
 };
 
-const struct mlx5_ib_profile uplink_rep_profile = {
+const struct mlx5_ib_profile raw_eth_profile = {
 	STAGE_CREATE(MLX5_IB_STAGE_INIT,
 		     mlx5_ib_stage_init_init,
 		     mlx5_ib_stage_init_cleanup),
@@ -6818,11 +6814,11 @@
 		     mlx5_ib_stage_caps_init,
 		     NULL),
 	STAGE_CREATE(MLX5_IB_STAGE_NON_DEFAULT_CB,
-		     mlx5_ib_stage_rep_non_default_cb,
+		     mlx5_ib_stage_raw_eth_non_default_cb,
 		     NULL),
 	STAGE_CREATE(MLX5_IB_STAGE_ROCE,
-		     mlx5_ib_stage_rep_roce_init,
-		     mlx5_ib_stage_rep_roce_cleanup),
+		     mlx5_ib_stage_raw_eth_roce_init,
+		     mlx5_ib_stage_raw_eth_roce_cleanup),
 	STAGE_CREATE(MLX5_IB_STAGE_SRQ,
 		     mlx5_init_srq_table,
 		     mlx5_cleanup_srq_table),
@@ -6882,6 +6878,7 @@
 
 		if (bound) {
 			rdma_roce_rescan_device(&dev->ib_dev);
+			mpi->ibdev->ib_active = true;
 			break;
 		}
 	}
@@ -6898,6 +6895,7 @@
 
 static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 {
+	const struct mlx5_ib_profile *profile;
 	enum rdma_link_layer ll;
 	struct mlx5_ib_dev *dev;
 	int port_type_cap;
@@ -6933,7 +6931,12 @@
 	dev->mdev = mdev;
 	dev->num_ports = num_ports;
 
-	return __mlx5_ib_add(dev, &pf_profile);
+	if (ll == IB_LINK_LAYER_ETHERNET && !mlx5_is_roce_enabled(mdev))
+		profile = &raw_eth_profile;
+	else
+		profile = &pf_profile;
+
+	return __mlx5_ib_add(dev, profile);
 }
 
 static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/mem.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/mem.c
@@ -55,16 +55,17 @@
 	int i = 0;
 	struct scatterlist *sg;
 	int entry;
+	int page_shift = umem->is_peer ? umem->page_shift : PAGE_SHIFT;
 
-	addr = addr >> PAGE_SHIFT;
+	addr = addr >> page_shift;
 	tmp = (unsigned long)addr;
 	m = find_first_bit(&tmp, BITS_PER_LONG);
 	if (max_page_shift)
-		m = min_t(unsigned long, max_page_shift - PAGE_SHIFT, m);
+		m = min_t(unsigned long, max_page_shift - page_shift, m);
 
 	for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
-		len = sg_dma_len(sg) >> PAGE_SHIFT;
-		pfn = sg_dma_address(sg) >> PAGE_SHIFT;
+		len = sg_dma_len(sg) >> page_shift;
+		pfn = sg_dma_address(sg) >> page_shift;
 		if (base + p != pfn) {
 			/* If either the offset or the new
 			 * base are unaligned update m
@@ -96,7 +97,7 @@
 
 		*ncont = 0;
 	}
-	*shift = PAGE_SHIFT + m;
+	*shift = page_shift + m;
 	*count = i;
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -283,6 +283,7 @@
 	unsigned		head;
 	unsigned		tail;
 	u16			cur_post;
+	u16			last_poll;
 	void			*cur_edge;
 };
 
@@ -1349,7 +1350,7 @@
 	struct mlx5_flow_act *flow_act, u32 counter_id,
 	void *cmd_in, int inlen, int dest_id, int dest_type);
 bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type);
-bool mlx5_ib_devx_is_flow_counter(void *obj, u32 *counter_id);
+bool mlx5_ib_devx_is_flow_counter(void *obj, u32 offset, u32 *counter_id);
 int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root);
 void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction);
 #else
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/mr.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/mr.c
@@ -41,6 +41,8 @@
 #include <rdma/ib_verbs.h>
 #include "mlx5_ib.h"
 
+static void mlx5_invalidate_umem(struct ib_umem *umem, void *priv);
+
 enum {
 	MAX_PENDING_REG_MR = 8,
 };
@@ -428,7 +430,7 @@
 
 	if (entry < 0 || entry >= MAX_MR_CACHE_ENTRIES) {
 		mlx5_ib_err(dev, "cache entry %d is out of range\n", entry);
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	ent = &cache->ent[entry];
@@ -752,10 +754,9 @@
 	return MLX5_MAX_UMR_SHIFT;
 }
 
-static int mr_umem_get(struct mlx5_ib_dev *dev, struct ib_udata *udata,
-		       u64 start, u64 length, int access_flags,
-		       struct ib_umem **umem, int *npages, int *page_shift,
-		       int *ncont, int *order)
+static int mr_umem_get(struct mlx5_ib_dev *dev, u64 start, u64 length,
+		       int access_flags, struct ib_umem **umem, int *npages,
+		       int *page_shift, int *ncont, int *order, bool allow_peer)
 {
 	struct ib_umem *u;
 
@@ -764,7 +765,8 @@
 	if (access_flags & IB_ACCESS_ON_DEMAND) {
 		struct ib_umem_odp *odp;
 
-		odp = ib_umem_odp_get(udata, start, length, access_flags);
+		odp = ib_umem_odp_get(&dev->ib_dev, start, length,
+				      access_flags);
 		if (IS_ERR(odp)) {
 			mlx5_ib_dbg(dev, "umem get failed (%ld)\n",
 				    PTR_ERR(odp));
@@ -779,7 +781,13 @@
 		if (order)
 			*order = ilog2(roundup_pow_of_two(*ncont));
 	} else {
-		u = ib_umem_get(udata, start, length, access_flags, 0);
+		if (allow_peer)
+			u = ib_umem_get_peer(&dev->ib_dev, start, length,
+					     access_flags,
+					     IB_PEER_MEM_INVAL_SUPP);
+		else
+			u = ib_umem_get(&dev->ib_dev, start, length,
+					access_flags);
 		if (IS_ERR(u)) {
 			mlx5_ib_dbg(dev, "umem get failed (%ld)\n", PTR_ERR(u));
 			return PTR_ERR(u);
@@ -1109,6 +1117,9 @@
 			 get_octo_len(virt_addr, length, page_shift));
 	}
 
+	if (umem->is_peer && MLX5_CAP_GEN(dev->mdev, ats))
+		MLX5_SET(mkc, mkc, ma_tranlation_mode, 1);
+
 	err = mlx5_core_create_mkey(dev->mdev, &mr->mmkey, in, inlen);
 	if (err) {
 		mlx5_ib_warn(dev, "create mkey failed\n");
@@ -1279,15 +1290,17 @@
 		return &mr->ibmr;
 	}
 
-	err = mr_umem_get(dev, udata, start, length, access_flags, &umem,
-			  &npages, &page_shift, &ncont, &order);
+	err = mr_umem_get(dev, start, length, access_flags, &umem,
+			  &npages, &page_shift, &ncont, &order, true);
 
 	if (err < 0)
 		return ERR_PTR(err);
 
 	use_umr = mlx5_ib_can_use_umr(dev, true);
 
-	if (order <= mr_cache_max_order(dev) && use_umr) {
+	if (umem->is_peer && MLX5_CAP_GEN(dev->mdev, ats)) {
+		use_umr = false;
+	} else if (order <= mr_cache_max_order(dev) && use_umr) {
 		mr = alloc_mr_from_cache(pd, umem, virt_addr, length, ncont,
 					 page_shift, order, access_flags);
 		if (PTR_ERR(mr) == -EAGAIN) {
@@ -1312,6 +1325,8 @@
 
 	if (IS_ERR(mr)) {
 		err = PTR_ERR(mr);
+		if (umem->is_peer)
+			ib_umem_stop_invalidation_notifier(umem);
 		goto error;
 	}
 
@@ -1335,6 +1350,12 @@
 		}
 	}
 
+	if (umem->is_peer) {
+		ib_umem_activate_invalidation_notifier(
+			umem, mlx5_invalidate_umem, mr);
+		/* After this point the MR can be invalidated */
+	}
+
 	if (is_odp_mr(mr)) {
 		to_ib_umem_odp(mr->umem)->private = mr;
 		atomic_set(&mr->num_pending_prefetch, 0);
@@ -1412,6 +1433,10 @@
 
 	atomic_sub(mr->npages, &dev->mdev->priv.reg_pages);
 
+	/* Peer memory isn't supported */
+	if (mr->umem->is_peer)
+		return -EOPNOTSUPP;
+
 	if (!mr->umem)
 		return -EINVAL;
 
@@ -1434,9 +1459,8 @@
 		flags |= IB_MR_REREG_TRANS;
 		ib_umem_release(mr->umem);
 		mr->umem = NULL;
-		err = mr_umem_get(dev, udata, addr, len, access_flags,
-				  &mr->umem, &npages, &page_shift, &ncont,
-				  &order);
+		err = mr_umem_get(dev, addr, len, access_flags, &mr->umem,
+				  &npages, &page_shift, &ncont, &order, false);
 		if (err)
 			goto err;
 	}
@@ -1609,6 +1633,17 @@
 		/* Avoid double-freeing the umem. */
 		umem = NULL;
 	}
+	else {
+		/*
+		 * For peers, need to disable the invalidation notifier
+		 * before calling destroy_mkey().
+		 */
+		if (umem && umem->is_peer) {
+			if (unreg_umr(mr->dev ,mr))
+				return;
+			ib_umem_stop_invalidation_notifier(umem);
+		}
+	}
 
 	clean_mr(dev, mr);
 
@@ -1616,13 +1651,14 @@
 	 * We should unregister the DMA address from the HCA before
 	 * remove the DMA mapping.
 	 */
-	mlx5_mr_cache_free(dev, mr);
+	if (mr->allocated_from_cache)
+		mlx5_mr_cache_free(dev, mr);
+	else
+		kfree(mr);
+
 	ib_umem_release(umem);
 	if (umem)
 		atomic_sub(npages, &dev->mdev->priv.reg_pages);
-
-	if (!mr->allocated_from_cache)
-		kfree(mr);
 }
 
 int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
@@ -2332,3 +2368,15 @@
 
 	return n;
 }
+
+static void mlx5_invalidate_umem(struct ib_umem *umem, void *priv)
+{
+	struct mlx5_ib_mr *mr = priv;
+
+	/*
+	 * DMA is turned off for the mkey, but the mkey remains otherwise
+	 * untouched until the normal flow of dereg_mr happens. Any access to
+	 * this mkey will generate CQEs.
+	 */
+	unreg_umr(mr->dev ,mr);
+}
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/odp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/odp.c
@@ -553,7 +553,7 @@
 	struct mlx5_ib_mr *imr;
 	struct ib_umem_odp *umem_odp;
 
-	umem_odp = ib_umem_odp_alloc_implicit(udata, access_flags);
+	umem_odp = ib_umem_odp_alloc_implicit(pd->ibpd.device, access_flags);
 	if (IS_ERR(umem_odp))
 		return ERR_CAST(umem_odp);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/qp.c
@@ -749,7 +749,7 @@
 {
 	int err;
 
-	*umem = ib_umem_get(udata, addr, size, 0, 0);
+	*umem = ib_umem_get_peer(&dev->ib_dev, addr, size, 0, 0);
 	if (IS_ERR(*umem)) {
 		mlx5_ib_dbg(dev, "umem_get failed\n");
 		return PTR_ERR(*umem);
@@ -806,7 +806,7 @@
 	if (!ucmd->buf_addr)
 		return -EINVAL;
 
-	rwq->umem = ib_umem_get(udata, ucmd->buf_addr, rwq->buf_size, 0, 0);
+	rwq->umem = ib_umem_get(&dev->ib_dev, ucmd->buf_addr, rwq->buf_size, 0);
 	if (IS_ERR(rwq->umem)) {
 		mlx5_ib_dbg(dev, "umem_get failed\n");
 		err = PTR_ERR(rwq->umem);
@@ -1463,6 +1463,8 @@
 	u16 uid = to_mpd(pd)->uid;
 	u32 out[MLX5_ST_SZ_DW(create_tir_out)] = {};
 
+	if (!qp->sq.wqe_cnt && !qp->rq.wqe_cnt)
+		return -EINVAL;
 	if (qp->sq.wqe_cnt) {
 		err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd);
 		if (err)
@@ -3391,9 +3393,6 @@
 	struct mlx5_ib_qp_base *base;
 	u32 set_id;
 
-	if (!MLX5_CAP_GEN(dev->mdev, rts2rts_qp_counters_set_id))
-		return 0;
-
 	if (counter)
 		set_id = counter->id;
 	else
@@ -3728,6 +3727,7 @@
 		qp->sq.cur_post = 0;
 		if (qp->sq.wqe_cnt)
 			qp->sq.cur_edge = get_sq_edge(&qp->sq, 0);
+		qp->sq.last_poll = 0;
 		qp->db.db[MLX5_RCV_DBR] = 0;
 		qp->db.db[MLX5_SND_DBR] = 0;
 	}
@@ -3821,7 +3821,7 @@
 			return -EINVAL;
 
 		if (attr->port_num == 0 ||
-		    attr->port_num > MLX5_CAP_GEN(dev->mdev, num_ports)) {
+		    attr->port_num > dev->num_ports) {
 			mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n",
 				    attr->port_num, dev->num_ports);
 			return -EINVAL;
@@ -3865,6 +3865,8 @@
 		MLX5_SET(dctc, dctc, mtu, attr->path_mtu);
 		MLX5_SET(dctc, dctc, my_addr_index, attr->ah_attr.grh.sgid_index);
 		MLX5_SET(dctc, dctc, hop_limit, attr->ah_attr.grh.hop_limit);
+		if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE)
+			MLX5_SET(dctc, dctc, eth_prio, attr->ah_attr.sl & 0x7);
 
 		err = mlx5_core_create_dct(dev->mdev, &qp->dct.mdct, qp->dct.in,
 					   MLX5_ST_SZ_BYTES(create_dct_in), out,
@@ -3888,6 +3890,40 @@
 	return err;
 }
 
+static int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr,
+			      int attr_mask, enum ib_qp_type qp_type)
+{
+	int log_max_ra_res;
+	int log_max_ra_req;
+
+	if (qp_type == MLX5_IB_QPT_DCI) {
+		log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
+						   log_max_ra_res_dc);
+		log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
+						   log_max_ra_req_dc);
+	} else {
+		log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
+						   log_max_ra_res_qp);
+		log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
+						   log_max_ra_req_qp);
+	}
+
+	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+	    attr->max_rd_atomic > log_max_ra_res) {
+		mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
+			    attr->max_rd_atomic);
+		return false;
+	}
+
+	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+	    attr->max_dest_rd_atomic > log_max_ra_req) {
+		mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
+			    attr->max_dest_rd_atomic);
+		return false;
+	}
+	return true;
+}
+
 int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 		      int attr_mask, struct ib_udata *udata)
 {
@@ -3984,21 +4020,8 @@
 		}
 	}
 
-	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
-	    attr->max_rd_atomic >
-	    (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) {
-		mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
-			    attr->max_rd_atomic);
+	if (!validate_rd_atomic(dev, attr, attr_mask, qp_type))
 		goto out;
-	}
-
-	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
-	    attr->max_dest_rd_atomic >
-	    (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) {
-		mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
-			    attr->max_dest_rd_atomic);
-		goto out;
-	}
 
 	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
 		err = 0;
@@ -5498,7 +5521,9 @@
 	rdma_ah_set_path_bits(ah_attr, path->grh_mlid & 0x7f);
 	rdma_ah_set_static_rate(ah_attr,
 				path->static_rate ? path->static_rate - 5 : 0);
-	if (path->grh_mlid & (1 << 7)) {
+
+	if (path->grh_mlid & (1 << 7) ||
+	    ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
 		u32 tc_fl = be32_to_cpu(path->tclass_flowlabel);
 
 		rdma_ah_set_grh(ah_attr, NULL,
@@ -6134,6 +6159,10 @@
 	if (udata->outlen && udata->outlen < min_resp_len)
 		return ERR_PTR(-EINVAL);
 
+	if (!capable(CAP_SYS_RAWIO) &&
+	    init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP)
+		return ERR_PTR(-EPERM);
+
 	dev = to_mdev(pd->device);
 	switch (init_attr->wq_type) {
 	case IB_WQT_RQ:
@@ -6311,10 +6340,8 @@
 
 	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
 
-	curr_wq_state = (wq_attr_mask & IB_WQ_CUR_STATE) ?
-		wq_attr->curr_wq_state : wq->state;
-	wq_state = (wq_attr_mask & IB_WQ_STATE) ?
-		wq_attr->wq_state : curr_wq_state;
+	curr_wq_state = wq_attr->curr_wq_state;
+	wq_state = wq_attr->wq_state;
 	if (curr_wq_state == IB_WQS_ERR)
 		curr_wq_state = MLX5_RQC_STATE_ERR;
 	if (wq_state == IB_WQS_ERR)
@@ -6503,6 +6530,7 @@
  */
 int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter)
 {
+	struct mlx5_ib_dev *dev = to_mdev(qp->device);
 	struct mlx5_ib_qp *mqp = to_mqp(qp);
 	int err = 0;
 
@@ -6512,6 +6540,11 @@
 		goto out;
 	}
 
+	if (!MLX5_CAP_GEN(dev->mdev, rts2rts_qp_counters_set_id)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
 	if (mqp->state == IB_QPS_RTS) {
 		err = __mlx5_ib_qp_set_counter(qp, counter);
 		if (!err)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/srq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/srq.c
@@ -80,7 +80,7 @@
 
 	srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
 
-	srq->umem = ib_umem_get(udata, ucmd.buf_addr, buf_size, 0, 0);
+	srq->umem = ib_umem_get_peer(pd->device, ucmd.buf_addr, buf_size, 0, 0);
 	if (IS_ERR(srq->umem)) {
 		mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size);
 		err = PTR_ERR(srq->umem);
@@ -310,12 +310,18 @@
 	srq->msrq.event = mlx5_ib_srq_event;
 	srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
 
-	if (udata)
-		if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
+	if (udata) {
+		struct mlx5_ib_create_srq_resp resp = {
+			.srqn = srq->msrq.srqn,
+		};
+
+		if (ib_copy_to_udata(udata, &resp, min(udata->outlen,
+				     sizeof(resp)))) {
 			mlx5_ib_dbg(dev, "copy to user failed\n");
 			err = -EFAULT;
 			goto err_core;
 		}
+	}
 
 	init_attr->attr.max_wr = srq->msrq.max - 1;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mlx5/srq_cmd.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mlx5/srq_cmd.c
@@ -83,11 +83,11 @@
 	struct mlx5_srq_table *table = &dev->srq_table;
 	struct mlx5_core_srq *srq;
 
-	xa_lock(&table->array);
+	xa_lock_irq(&table->array);
 	srq = xa_load(&table->array, srqn);
 	if (srq)
 		refcount_inc(&srq->common.refcount);
-	xa_unlock(&table->array);
+	xa_unlock_irq(&table->array);
 
 	return srq;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -635,7 +635,7 @@
 
 int mthca_SYS_EN(struct mthca_dev *dev)
 {
-	u64 out;
+	u64 out = 0;
 	int ret;
 
 	ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D);
@@ -1955,7 +1955,7 @@
 int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    u16 *hash)
 {
-	u64 imm;
+	u64 imm = 0;
 	int err;
 
 	err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -604,7 +604,7 @@
 			entry->byte_len  = MTHCA_ATOMIC_BYTE_LEN;
 			break;
 		default:
-			entry->opcode    = MTHCA_OPCODE_INVALID;
+			entry->opcode = 0xFF;
 			break;
 		}
 	} else {
@@ -803,8 +803,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;
 
@@ -846,9 +848,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-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_dev.h
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mthca/mthca_main.c
@@ -382,7 +382,7 @@
 			  struct mthca_init_hca_param *init_hca,
 			  u64 icm_size)
 {
-	u64 aux_pages;
+	u64 aux_pages = 0;
 	int err;
 
 	err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_provider.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -880,9 +880,7 @@
 	if (!mr)
 		return ERR_PTR(-ENOMEM);
 
-	mr->umem = ib_umem_get(udata, start, length, acc,
-			       ucmd.mr_attrs & MTHCA_MR_DMASYNC);
-
+	mr->umem = ib_umem_get(pd->device, start, length, acc);
 	if (IS_ERR(mr->umem)) {
 		err = PTR_ERR(mr->umem);
 		goto err;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/mthca/mthca_qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1639,8 +1639,8 @@
 	 * without initializing f0 and size0, and they are in fact
 	 * never used uninitialized.
 	 */
-	int uninitialized_var(size0);
-	u32 uninitialized_var(f0);
+	int size0;
+	u32 f0;
 	int ind;
 	u8 op0 = 0;
 
@@ -1835,7 +1835,7 @@
 	 * without initializing size0, and it is in fact never used
 	 * uninitialized.
 	 */
-	int uninitialized_var(size0);
+	int size0;
 	int ind;
 	void *wqe;
 	void *prev_wqe;
@@ -1943,8 +1943,8 @@
 	 * without initializing f0 and size0, and they are in fact
 	 * never used uninitialized.
 	 */
-	int uninitialized_var(size0);
-	u32 uninitialized_var(f0);
+	int size0;
+	u32 f0;
 	int ind;
 	u8 op0 = 0;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -442,9 +442,9 @@
 		pr_err("%s(%d) Freeing in use pdid=0x%x.\n",
 		       __func__, dev->id, pd->id);
 	}
-	kfree(uctx->cntxt_pd);
 	uctx->cntxt_pd = NULL;
 	_ocrdma_dealloc_pd(dev, pd);
+	kfree(pd);
 }
 
 static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
@@ -875,7 +875,7 @@
 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
 	if (!mr)
 		return ERR_PTR(status);
-	mr->umem = ib_umem_get(udata, start, len, acc, 0);
+	mr->umem = ib_umem_get(ibpd->device, start, len, acc);
 	if (IS_ERR(mr->umem)) {
 		status = -EFAULT;
 		goto umem_err;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/qedr/main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/qedr/main.c
@@ -357,10 +357,15 @@
 		return -ENOMEM;
 
 	spin_lock_init(&dev->sgid_lock);
+	xa_init_flags(&dev->srqs, XA_FLAGS_LOCK_IRQ);
 
 	if (IS_IWARP(dev)) {
-		xa_init_flags(&dev->qps, XA_FLAGS_LOCK_IRQ);
+		xa_init(&dev->qps);
 		dev->iwarp_wq = create_singlethread_workqueue("qedr_iwarpq");
+		if (!dev->iwarp_wq) {
+			rc = -ENOMEM;
+			goto err1;
+		}
 	}
 
 	/* Allocate Status blocks for CNQ */
@@ -368,7 +373,7 @@
 				GFP_KERNEL);
 	if (!dev->sb_array) {
 		rc = -ENOMEM;
-		goto err1;
+		goto err_destroy_wq;
 	}
 
 	dev->cnq_array = kcalloc(dev->num_cnq,
@@ -422,6 +427,9 @@
 	kfree(dev->cnq_array);
 err2:
 	kfree(dev->sb_array);
+err_destroy_wq:
+	if (IS_IWARP(dev))
+		destroy_workqueue(dev->iwarp_wq);
 err1:
 	kfree(dev->sgid_tbl);
 	return rc;
@@ -600,7 +608,7 @@
 	qed_attr = dev->ops->rdma_query_device(dev->rdma_ctx);
 
 	/* Part 2 - check capabilities */
-	page_size = ~dev->attr.page_size_caps + 1;
+	page_size = ~qed_attr->page_size_caps + 1;
 	if (page_size > PAGE_SIZE) {
 		DP_ERR(dev,
 		       "Kernel PAGE_SIZE is %ld which is smaller than minimum page size (%d) required by qedr\n",
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/qedr/qedr.h
+++ linux-ein-5.4.0/drivers/infiniband/hw/qedr/qedr.h
@@ -40,6 +40,7 @@
 #include <linux/qed/qed_rdma_if.h>
 #include <linux/qed/qede_rdma.h>
 #include <linux/qed/roce_common.h>
+#include <linux/completion.h>
 #include "qedr_hsi_rdma.h"
 
 #define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
@@ -348,10 +349,10 @@
 	u32 wqe_prod;
 	u32 sge_prod;
 	u32 wr_prod_cnt;
-	u32 wr_cons_cnt;
+	atomic_t wr_cons_cnt;
 	u32 num_elems;
 
-	u32 *virt_prod_pair_addr;
+	struct rdma_srq_producers *virt_prod_pair_addr;
 	dma_addr_t phy_prod_pair_addr;
 };
 
@@ -377,10 +378,20 @@
 	QEDR_QP_ERR_RQ_PBL_FULL = 32,
 };
 
+enum qedr_qp_create_type {
+	QEDR_QP_CREATE_NONE,
+	QEDR_QP_CREATE_USER,
+	QEDR_QP_CREATE_KERNEL,
+};
+
+enum qedr_iwarp_cm_flags {
+	QEDR_IWARP_CM_WAIT_FOR_CONNECT    = BIT(0),
+	QEDR_IWARP_CM_WAIT_FOR_DISCONNECT = BIT(1),
+};
+
 struct qedr_qp {
 	struct ib_qp ibqp;	/* must be first */
 	struct qedr_dev *dev;
-	struct qedr_iw_ep *ep;
 	struct qedr_qp_hwq_info sq;
 	struct qedr_qp_hwq_info rq;
 
@@ -395,6 +406,7 @@
 	u32 id;
 	struct qedr_pd *pd;
 	enum ib_qp_type qp_type;
+	enum qedr_qp_create_type create_type;
 	struct qed_rdma_qp *qed_qp;
 	u32 qp_id;
 	u16 icid;
@@ -404,6 +416,7 @@
 	u32 sq_psn;
 	u32 qkey;
 	u32 dest_qp_num;
+	u8 timeout;
 
 	/* Relevant to qps created from kernel space only (ULPs) */
 	u8 prev_wqe_size;
@@ -437,8 +450,11 @@
 	/* Relevant to qps created from user space only (applications) */
 	struct qedr_userq usq;
 	struct qedr_userq urq;
-	atomic_t refcnt;
-	bool destroyed;
+
+	/* synchronization objects used with iwarp ep */
+	struct kref refcnt;
+	struct completion iwarp_cm_comp;
+	unsigned long iwarp_cm_flags; /* enum iwarp_cm_flags */
 };
 
 struct qedr_ah {
@@ -531,7 +547,7 @@
 	struct iw_cm_id	*cm_id;
 	struct qedr_qp	*qp;
 	void		*qed_context;
-	u8		during_connect;
+	struct kref	refcnt;
 };
 
 static inline
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/qedr/qedr_iw_cm.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/qedr/qedr_iw_cm.c
@@ -79,6 +79,27 @@
 	}
 }
 
+static void qedr_iw_free_qp(struct kref *ref)
+{
+	struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt);
+
+	kfree(qp);
+}
+
+static void
+qedr_iw_free_ep(struct kref *ref)
+{
+	struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt);
+
+	if (ep->qp)
+		kref_put(&ep->qp->refcnt, qedr_iw_free_qp);
+
+	if (ep->cm_id)
+		ep->cm_id->rem_ref(ep->cm_id);
+
+	kfree(ep);
+}
+
 static void
 qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params)
 {
@@ -93,6 +114,7 @@
 
 	ep->dev = dev;
 	ep->qed_context = params->ep_context;
+	kref_init(&ep->refcnt);
 
 	memset(&event, 0, sizeof(event));
 	event.event = IW_CM_EVENT_CONNECT_REQUEST;
@@ -128,8 +150,17 @@
 	if (params->cm_info) {
 		event.ird = params->cm_info->ird;
 		event.ord = params->cm_info->ord;
-		event.private_data_len = params->cm_info->private_data_len;
-		event.private_data = (void *)params->cm_info->private_data;
+		/* Only connect_request and reply have valid private data
+		 * the rest of the events this may be left overs from
+		 * connection establishment. CONNECT_REQUEST is issued via
+		 * qedr_iw_mpa_request
+		 */
+		if (event_type == IW_CM_EVENT_CONNECT_REPLY) {
+			event.private_data_len =
+				params->cm_info->private_data_len;
+			event.private_data =
+				(void *)params->cm_info->private_data;
+		}
 	}
 
 	if (ep->cm_id)
@@ -141,12 +172,10 @@
 {
 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
 
-	if (ep->cm_id) {
+	if (ep->cm_id)
 		qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE);
 
-		ep->cm_id->rem_ref(ep->cm_id);
-		ep->cm_id = NULL;
-	}
+	kref_put(&ep->refcnt, qedr_iw_free_ep);
 }
 
 static void
@@ -186,11 +215,13 @@
 	struct qedr_qp *qp = ep->qp;
 	struct iw_cm_event event;
 
-	if (qp->destroyed) {
-		kfree(dwork);
-		qedr_iw_qp_rem_ref(&qp->ibqp);
-		return;
-	}
+	/* The qp won't be released until we release the ep.
+	 * the ep's refcnt was increased before calling this
+	 * function, therefore it is safe to access qp
+	 */
+	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT,
+			     &qp->iwarp_cm_flags))
+		goto out;
 
 	memset(&event, 0, sizeof(event));
 	event.status = dwork->status;
@@ -204,7 +235,6 @@
 	else
 		qp_params.new_state = QED_ROCE_QP_STATE_SQD;
 
-	kfree(dwork);
 
 	if (ep->cm_id)
 		ep->cm_id->event_handler(ep->cm_id, &event);
@@ -214,7 +244,10 @@
 
 	dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params);
 
-	qedr_iw_qp_rem_ref(&qp->ibqp);
+	complete(&ep->qp->iwarp_cm_comp);
+out:
+	kfree(dwork);
+	kref_put(&ep->refcnt, qedr_iw_free_ep);
 }
 
 static void
@@ -224,13 +257,17 @@
 	struct qedr_discon_work *work;
 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
 	struct qedr_dev *dev = ep->dev;
-	struct qedr_qp *qp = ep->qp;
 
 	work = kzalloc(sizeof(*work), GFP_ATOMIC);
 	if (!work)
 		return;
 
-	qedr_iw_qp_add_ref(&qp->ibqp);
+	/* We can't get a close event before disconnect, but since
+	 * we're scheduling a work queue we need to make sure close
+	 * won't delete the ep, so we increase the refcnt
+	 */
+	kref_get(&ep->refcnt);
+
 	work->ep = ep;
 	work->event = params->event;
 	work->status = params->status;
@@ -252,16 +289,30 @@
 	if ((params->status == -ECONNREFUSED) && (!ep->qp)) {
 		DP_DEBUG(dev, QEDR_MSG_IWARP,
 			 "PASSIVE connection refused releasing ep...\n");
-		kfree(ep);
+		kref_put(&ep->refcnt, qedr_iw_free_ep);
 		return;
 	}
 
+	complete(&ep->qp->iwarp_cm_comp);
 	qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED);
 
 	if (params->status < 0)
 		qedr_iw_close_event(context, params);
 }
 
+static void
+qedr_iw_active_complete(void *context,
+			struct qed_iwarp_cm_event_params *params)
+{
+	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
+
+	complete(&ep->qp->iwarp_cm_comp);
+	qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY);
+
+	if (params->status < 0)
+		kref_put(&ep->refcnt, qedr_iw_free_ep);
+}
+
 static int
 qedr_iw_mpa_reply(void *context, struct qed_iwarp_cm_event_params *params)
 {
@@ -288,27 +339,15 @@
 		qedr_iw_mpa_reply(context, params);
 		break;
 	case QED_IWARP_EVENT_PASSIVE_COMPLETE:
-		ep->during_connect = 0;
 		qedr_iw_passive_complete(context, params);
 		break;
-
 	case QED_IWARP_EVENT_ACTIVE_COMPLETE:
-		ep->during_connect = 0;
-		qedr_iw_issue_event(context,
-				    params,
-				    IW_CM_EVENT_CONNECT_REPLY);
-		if (params->status < 0) {
-			struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
-
-			ep->cm_id->rem_ref(ep->cm_id);
-			ep->cm_id = NULL;
-		}
+		qedr_iw_active_complete(context, params);
 		break;
 	case QED_IWARP_EVENT_DISCONNECT:
 		qedr_iw_disconnect_event(context, params);
 		break;
 	case QED_IWARP_EVENT_CLOSE:
-		ep->during_connect = 0;
 		qedr_iw_close_event(context, params);
 		break;
 	case QED_IWARP_EVENT_RQ_EMPTY:
@@ -451,10 +490,10 @@
 
 	if ((!dst) || dst->error) {
 		if (dst) {
-			dst_release(dst);
 			DP_ERR(dev,
 			       "ip6_route_output returned dst->error = %d\n",
 			       dst->error);
+			dst_release(dst);
 		}
 		return -EINVAL;
 	}
@@ -476,6 +515,19 @@
 	return rc;
 }
 
+struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn)
+{
+	struct qedr_qp *qp;
+
+	xa_lock(&dev->qps);
+	qp = xa_load(&dev->qps, qpn);
+	if (qp)
+		kref_get(&qp->refcnt);
+	xa_unlock(&dev->qps);
+
+	return qp;
+}
+
 int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 {
 	struct qedr_dev *dev = get_qedr_dev(cm_id->device);
@@ -491,10 +543,6 @@
 	int rc = 0;
 	int i;
 
-	qp = xa_load(&dev->qps, conn_param->qpn);
-	if (unlikely(!qp))
-		return -EINVAL;
-
 	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
 	raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
 	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
@@ -516,8 +564,15 @@
 		return -ENOMEM;
 
 	ep->dev = dev;
+	kref_init(&ep->refcnt);
+
+	qp = qedr_iw_load_qp(dev, conn_param->qpn);
+	if (!qp) {
+		rc = -EINVAL;
+		goto err;
+	}
+
 	ep->qp = qp;
-	qp->ep = ep;
 	cm_id->add_ref(cm_id);
 	ep->cm_id = cm_id;
 
@@ -580,16 +635,22 @@
 	in_params.qp = qp->qed_qp;
 	memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN);
 
-	ep->during_connect = 1;
+	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
+			     &qp->iwarp_cm_flags)) {
+		rc = -ENODEV;
+		goto err; /* QP already being destroyed */
+	}
+
 	rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params);
-	if (rc)
+	if (rc) {
+		complete(&qp->iwarp_cm_comp);
 		goto err;
+	}
 
 	return rc;
 
 err:
-	cm_id->rem_ref(cm_id);
-	kfree(ep);
+	kref_put(&ep->refcnt, qedr_iw_free_ep);
 	return rc;
 }
 
@@ -668,6 +729,7 @@
 						    listener->qed_handle);
 
 	cm_id->rem_ref(cm_id);
+	kfree(listener);
 	return rc;
 }
 
@@ -681,14 +743,13 @@
 
 	DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn);
 
-	qp = xa_load(&dev->qps, conn_param->qpn);
+	qp = qedr_iw_load_qp(dev, conn_param->qpn);
 	if (!qp) {
 		DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn);
 		return -EINVAL;
 	}
 
 	ep->qp = qp;
-	qp->ep = ep;
 	cm_id->add_ref(cm_id);
 	ep->cm_id = cm_id;
 
@@ -700,15 +761,23 @@
 	params.ird = conn_param->ird;
 	params.ord = conn_param->ord;
 
-	ep->during_connect = 1;
+	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
+			     &qp->iwarp_cm_flags)) {
+		rc = -EINVAL;
+		goto err; /* QP already destroyed */
+	}
+
 	rc = dev->ops->iwarp_accept(dev->rdma_ctx, &params);
-	if (rc)
+	if (rc) {
+		complete(&qp->iwarp_cm_comp);
 		goto err;
+	}
 
 	return rc;
+
 err:
-	ep->during_connect = 0;
-	cm_id->rem_ref(cm_id);
+	kref_put(&ep->refcnt, qedr_iw_free_ep);
+
 	return rc;
 }
 
@@ -731,17 +800,14 @@
 {
 	struct qedr_qp *qp = get_qedr_qp(ibqp);
 
-	atomic_inc(&qp->refcnt);
+	kref_get(&qp->refcnt);
 }
 
 void qedr_iw_qp_rem_ref(struct ib_qp *ibqp)
 {
 	struct qedr_qp *qp = get_qedr_qp(ibqp);
 
-	if (atomic_dec_and_test(&qp->refcnt)) {
-		xa_erase_irq(&qp->dev->qps, qp->qp_id);
-		kfree(qp);
-	}
+	kref_put(&qp->refcnt, qedr_iw_free_qp);
 }
 
 struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn)
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/qedr/verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/qedr/verbs.c
@@ -51,6 +51,7 @@
 #include "verbs.h"
 #include <rdma/qedr-abi.h>
 #include "qedr_roce_cm.h"
+#include "qedr_iw_cm.h"
 
 #define QEDR_SRQ_WQE_ELEM_SIZE	sizeof(union rdma_srq_elm)
 #define	RDMA_MAX_SGE_PER_SRQ	(4)
@@ -697,7 +698,7 @@
 static inline int qedr_init_user_queue(struct ib_udata *udata,
 				       struct qedr_dev *dev,
 				       struct qedr_userq *q, u64 buf_addr,
-				       size_t buf_len, int access, int dmasync,
+				       size_t buf_len, int access,
 				       int alloc_and_init)
 {
 	u32 fw_pages;
@@ -705,7 +706,7 @@
 
 	q->buf_addr = buf_addr;
 	q->buf_len = buf_len;
-	q->umem = ib_umem_get(udata, q->buf_addr, q->buf_len, access, dmasync);
+	q->umem = ib_umem_get(&dev->ibdev, q->buf_addr, q->buf_len, access);
 	if (IS_ERR(q->umem)) {
 		DP_ERR(dev, "create user queue: failed ib_umem_get, got %ld\n",
 		       PTR_ERR(q->umem));
@@ -856,8 +857,7 @@
 		cq->cq_type = QEDR_CQ_TYPE_USER;
 
 		rc = qedr_init_user_queue(udata, dev, &cq->q, ureq.addr,
-					  ureq.len, IB_ACCESS_LOCAL_WRITE, 1,
-					  1);
+					  ureq.len, IB_ACCESS_LOCAL_WRITE, 1);
 		if (rc)
 			goto err0;
 
@@ -1193,7 +1193,10 @@
 				      struct ib_qp_init_attr *attrs)
 {
 	spin_lock_init(&qp->q_lock);
-	atomic_set(&qp->refcnt, 1);
+	if (rdma_protocol_iwarp(&dev->ibdev, 1)) {
+		kref_init(&qp->refcnt);
+		init_completion(&qp->iwarp_cm_comp);
+	}
 	qp->pd = pd;
 	qp->qp_type = attrs->qp_type;
 	qp->max_inline_data = attrs->cap.max_inline_data;
@@ -1279,19 +1282,18 @@
 static int qedr_init_srq_user_params(struct ib_udata *udata,
 				     struct qedr_srq *srq,
 				     struct qedr_create_srq_ureq *ureq,
-				     int access, int dmasync)
+				     int access)
 {
 	struct scatterlist *sg;
 	int rc;
 
 	rc = qedr_init_user_queue(udata, srq->dev, &srq->usrq, ureq->srq_addr,
-				  ureq->srq_len, access, dmasync, 1);
+				  ureq->srq_len, access, 1);
 	if (rc)
 		return rc;
 
-	srq->prod_umem =
-		ib_umem_get(udata, ureq->prod_pair_addr,
-			    sizeof(struct rdma_srq_producers), access, dmasync);
+	srq->prod_umem = ib_umem_get(srq->ibsrq.device, ureq->prod_pair_addr,
+				     sizeof(struct rdma_srq_producers), access);
 	if (IS_ERR(srq->prod_umem)) {
 		qedr_free_pbl(srq->dev, &srq->usrq.pbl_info, srq->usrq.pbl_tbl);
 		ib_umem_release(srq->usrq.umem);
@@ -1387,7 +1389,7 @@
 			goto err0;
 		}
 
-		rc = qedr_init_srq_user_params(udata, srq, &ureq, 0, 0);
+		rc = qedr_init_srq_user_params(udata, srq, &ureq, 0);
 		if (rc)
 			goto err0;
 
@@ -1577,6 +1579,14 @@
 
 	ib_umem_release(qp->urq.umem);
 	qp->urq.umem = NULL;
+
+	if (rdma_protocol_roce(&dev->ibdev, 1)) {
+		qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl);
+		qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl);
+	} else {
+		kfree(qp->usq.pbl_tbl);
+		kfree(qp->urq.pbl_tbl);
+	}
 }
 
 static int qedr_create_user_qp(struct qedr_dev *dev,
@@ -1592,6 +1602,7 @@
 	int alloc_and_init = rdma_protocol_roce(&dev->ibdev, 1);
 	int rc = -EINVAL;
 
+	qp->create_type = QEDR_QP_CREATE_USER;
 	memset(&ureq, 0, sizeof(ureq));
 	rc = ib_copy_from_udata(&ureq, udata, sizeof(ureq));
 	if (rc) {
@@ -1599,16 +1610,16 @@
 		return rc;
 	}
 
-	/* SQ - read access only (0), dma sync not required (0) */
+	/* SQ - read access only (0) */
 	rc = qedr_init_user_queue(udata, dev, &qp->usq, ureq.sq_addr,
-				  ureq.sq_len, 0, 0, alloc_and_init);
+				  ureq.sq_len, 0, alloc_and_init);
 	if (rc)
 		return rc;
 
 	if (!qp->srq) {
-		/* RQ - read access only (0), dma sync not required (0) */
+		/* RQ - read access only (0) */
 		rc = qedr_init_user_queue(udata, dev, &qp->urq, ureq.rq_addr,
-					  ureq.rq_len, 0, 0, alloc_and_init);
+					  ureq.rq_len, 0, alloc_and_init);
 		if (rc)
 			return rc;
 	}
@@ -1805,6 +1816,7 @@
 	u32 n_sq_entries;
 
 	memset(&in_params, 0, sizeof(in_params));
+	qp->create_type = QEDR_QP_CREATE_KERNEL;
 
 	/* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in
 	 * the ring. The ring should allow at least a single WR, even if the
@@ -1918,7 +1930,7 @@
 	qp->ibqp.qp_num = qp->qp_id;
 
 	if (rdma_protocol_iwarp(&dev->ibdev, 1)) {
-		rc = xa_insert_irq(&dev->qps, qp->qp_id, qp, GFP_KERNEL);
+		rc = xa_insert(&dev->qps, qp->qp_id, qp, GFP_KERNEL);
 		if (rc)
 			goto err;
 	}
@@ -2245,6 +2257,8 @@
 					1 << max_t(int, attr->timeout - 8, 0);
 		else
 			qp_params.ack_timeout = 0;
+
+		qp->timeout = attr->timeout;
 	}
 
 	if (attr_mask & IB_QP_RETRY_CNT) {
@@ -2369,15 +2383,18 @@
 	int rc = 0;
 
 	memset(&params, 0, sizeof(params));
-
-	rc = dev->ops->rdma_query_qp(dev->rdma_ctx, qp->qed_qp, &params);
-	if (rc)
-		goto err;
-
 	memset(qp_attr, 0, sizeof(*qp_attr));
 	memset(qp_init_attr, 0, sizeof(*qp_init_attr));
 
-	qp_attr->qp_state = qedr_get_ibqp_state(params.state);
+	if (qp->qp_type != IB_QPT_GSI) {
+		rc = dev->ops->rdma_query_qp(dev->rdma_ctx, qp->qed_qp, &params);
+		if (rc)
+			goto err;
+		qp_attr->qp_state = qedr_get_ibqp_state(params.state);
+	} else {
+		qp_attr->qp_state = qedr_get_ibqp_state(QED_ROCE_QP_STATE_RTS);
+	}
+
 	qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state);
 	qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu);
 	qp_attr->path_mig_state = IB_MIG_MIGRATED;
@@ -2391,7 +2408,7 @@
 	qp_attr->cap.max_recv_wr = qp->rq.max_wr;
 	qp_attr->cap.max_send_sge = qp->sq.max_sges;
 	qp_attr->cap.max_recv_sge = qp->rq.max_sges;
-	qp_attr->cap.max_inline_data = ROCE_REQ_MAX_INLINE_DATA_SIZE;
+	qp_attr->cap.max_inline_data = dev->attr.max_inline;
 	qp_init_attr->cap = qp_attr->cap;
 
 	qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE;
@@ -2401,7 +2418,7 @@
 	rdma_ah_set_dgid_raw(&qp_attr->ah_attr, &params.dgid.bytes[0]);
 	rdma_ah_set_port_num(&qp_attr->ah_attr, 1);
 	rdma_ah_set_sl(&qp_attr->ah_attr, 0);
-	qp_attr->timeout = params.timeout;
+	qp_attr->timeout = qp->timeout;
 	qp_attr->rnr_retry = params.rnr_retry;
 	qp_attr->retry_cnt = params.retry_cnt;
 	qp_attr->min_rnr_timer = params.min_rnr_nak_timer;
@@ -2437,7 +2454,7 @@
 			return rc;
 	}
 
-	if (udata)
+	if (qp->create_type == QEDR_QP_CREATE_USER)
 		qedr_cleanup_user(dev, qp);
 	else
 		qedr_cleanup_kernel(dev, qp);
@@ -2467,34 +2484,46 @@
 			qedr_modify_qp(ibqp, &attr, attr_mask, NULL);
 		}
 	} else {
-		/* Wait for the connect/accept to complete */
-		if (qp->ep) {
-			int wait_count = 1;
-
-			while (qp->ep->during_connect) {
-				DP_DEBUG(dev, QEDR_MSG_QP,
-					 "Still in during connect/accept\n");
-
-				msleep(100);
-				if (wait_count++ > 200) {
-					DP_NOTICE(dev,
-						  "during connect timeout\n");
-					break;
-				}
-			}
-		}
+		/* If connection establishment started the WAIT_FOR_CONNECT
+		 * bit will be on and we need to Wait for the establishment
+		 * to complete before destroying the qp.
+		 */
+		if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
+				     &qp->iwarp_cm_flags))
+			wait_for_completion(&qp->iwarp_cm_comp);
+
+		/* If graceful disconnect started, the WAIT_FOR_DISCONNECT
+		 * bit will be on, and we need to wait for the disconnect to
+		 * complete before continuing. We can use the same completion,
+		 * iwarp_cm_comp, since this is the only place that waits for
+		 * this completion and it is sequential. In addition,
+		 * disconnect can't occur before the connection is fully
+		 * established, therefore if WAIT_FOR_DISCONNECT is on it
+		 * means WAIT_FOR_CONNECT is also on and the completion for
+		 * CONNECT already occurred.
+		 */
+		if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT,
+				     &qp->iwarp_cm_flags))
+			wait_for_completion(&qp->iwarp_cm_comp);
 	}
 
 	if (qp->qp_type == IB_QPT_GSI)
 		qedr_destroy_gsi_qp(dev);
 
+	/* We need to remove the entry from the xarray before we release the
+	 * qp_id to avoid a race of the qp_id being reallocated and failing
+	 * on xa_insert
+	 */
+	if (rdma_protocol_iwarp(&dev->ibdev, 1))
+		xa_erase(&dev->qps, qp->qp_id);
+
 	qedr_free_qp_resources(dev, qp, udata);
 
-	if (atomic_dec_and_test(&qp->refcnt) &&
-	    rdma_protocol_iwarp(&dev->ibdev, 1)) {
-		xa_erase_irq(&dev->qps, qp->qp_id);
+	if (rdma_protocol_iwarp(&dev->ibdev, 1))
+		qedr_iw_qp_rem_ref(&qp->ibqp);
+	else
 		kfree(qp);
-	}
+
 	return 0;
 }
 
@@ -2597,7 +2626,7 @@
 
 	mr->type = QEDR_MR_USER;
 
-	mr->umem = ib_umem_get(udata, start, len, acc, 0);
+	mr->umem = ib_umem_get(ibpd->device, start, len, acc);
 	if (IS_ERR(mr->umem)) {
 		rc = -EFAULT;
 		goto err0;
@@ -2673,8 +2702,8 @@
 
 	dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid);
 
-	if ((mr->type != QEDR_MR_DMA) && (mr->type != QEDR_MR_FRMR))
-		qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table);
+	if (mr->type != QEDR_MR_DMA)
+		free_mr_info(dev, &mr->info);
 
 	/* it could be user registered memory. */
 	ib_umem_release(mr->umem);
@@ -3436,7 +3465,7 @@
 	 * count and consumer count and subtract it from max
 	 * work request supported so that we get elements left.
 	 */
-	used = hw_srq->wr_prod_cnt - hw_srq->wr_cons_cnt;
+	used = hw_srq->wr_prod_cnt - (u32)atomic_read(&hw_srq->wr_cons_cnt);
 
 	return hw_srq->max_wr - used;
 }
@@ -3451,7 +3480,6 @@
 	unsigned long flags;
 	int status = 0;
 	u32 num_sge;
-	u32 offset;
 
 	spin_lock_irqsave(&srq->lock, flags);
 
@@ -3464,7 +3492,8 @@
 		if (!qedr_srq_elem_left(hw_srq) ||
 		    wr->num_sge > srq->hw_srq.max_sges) {
 			DP_ERR(dev, "Can't post WR  (%d,%d) || (%d > %d)\n",
-			       hw_srq->wr_prod_cnt, hw_srq->wr_cons_cnt,
+			       hw_srq->wr_prod_cnt,
+			       atomic_read(&hw_srq->wr_cons_cnt),
 			       wr->num_sge, srq->hw_srq.max_sges);
 			status = -ENOMEM;
 			*bad_wr = wr;
@@ -3498,22 +3527,20 @@
 			hw_srq->sge_prod++;
 		}
 
-		/* Flush WQE and SGE information before
+		/* Update WQE and SGE information before
 		 * updating producer.
 		 */
-		wmb();
+		dma_wmb();
 
 		/* SRQ producer is 8 bytes. Need to update SGE producer index
 		 * in first 4 bytes and need to update WQE producer in
 		 * next 4 bytes.
 		 */
-		*srq->hw_srq.virt_prod_pair_addr = hw_srq->sge_prod;
-		offset = offsetof(struct rdma_srq_producers, wqe_prod);
-		*((u8 *)srq->hw_srq.virt_prod_pair_addr + offset) =
-			hw_srq->wqe_prod;
+		srq->hw_srq.virt_prod_pair_addr->sge_prod = hw_srq->sge_prod;
+		/* Make sure sge producer is updated first */
+		dma_wmb();
+		srq->hw_srq.virt_prod_pair_addr->wqe_prod = hw_srq->wqe_prod;
 
-		/* Flush producer after updating it. */
-		wmb();
 		wr = wr->next;
 	}
 
@@ -3932,7 +3959,7 @@
 	} else {
 		__process_resp_one(dev, qp, cq, wc, resp, wr_id);
 	}
-	srq->hw_srq.wr_cons_cnt++;
+	atomic_inc(&srq->hw_srq.wr_cons_cnt);
 
 	return 1;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/qib/qib_sysfs.c
+++ linux-ein-5.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);
 }
 
@@ -754,7 +760,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);
 
@@ -764,7 +770,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);
 
@@ -774,7 +780,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);
 
@@ -787,7 +793,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);
@@ -848,6 +854,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-ein-5.4.0.orig/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -602,7 +602,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;
@@ -658,7 +658,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;
@@ -722,7 +722,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,
@@ -824,8 +824,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;
 
@@ -885,7 +885,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++;
@@ -904,8 +908,7 @@
 		}
 
 		if (frag_size) {
-			int tidsmsize, n;
-			size_t pktsize;
+			size_t tidsmsize, n, pktsize, sz, addrlimit;
 
 			n = npages*((2*PAGE_SIZE/frag_size)+1);
 			pktsize = struct_size(pkt, addr, n);
@@ -923,14 +926,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-ein-5.4.0.orig/drivers/infiniband/hw/qib/qib_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/qib/qib_verbs.c
@@ -329,8 +329,10 @@
 		if (mcast == NULL)
 			goto drop;
 		this_cpu_inc(ibp->pmastats->n_multicast_rcv);
+		rcu_read_lock();
 		list_for_each_entry_rcu(p, &mcast->qp_list, list)
 			qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp);
+		rcu_read_unlock();
 		/*
 		 * Notify rvt_multicast_detach() if it is waiting for us
 		 * to finish.
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -214,6 +214,7 @@
 
 		}
 		usnic_uiom_free_dev_list(dev_list);
+		dev_list = NULL;
 	}
 
 	/* Try to find resources on an unused vf */
@@ -239,6 +240,8 @@
 qp_grp_check:
 	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);
 	}
 	return qp_grp;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -281,8 +281,8 @@
 				size = pa_end - pa_start + PAGE_SIZE;
 				usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x",
 					va_start, &pa_start, size, flags);
-				err = iommu_map(pd->domain, va_start, pa_start,
-							size, flags);
+				err = iommu_map_atomic(pd->domain, va_start,
+						       pa_start, size, flags);
 				if (err) {
 					usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
 						va_start, &pa_start, size, err);
@@ -298,8 +298,8 @@
 				size = pa - pa_start + PAGE_SIZE;
 				usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n",
 					va_start, &pa_start, size, flags);
-				err = iommu_map(pd->domain, va_start, pa_start,
-						size, flags);
+				err = iommu_map_atomic(pd->domain, va_start,
+						       pa_start, size, flags);
 				if (err) {
 					usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
 						va_start, &pa_start, size, err);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
@@ -135,8 +135,8 @@
 			goto err_cq;
 		}
 
-		cq->umem = ib_umem_get(udata, ucmd.buf_addr, ucmd.buf_size,
-				       IB_ACCESS_LOCAL_WRITE, 1);
+		cq->umem = ib_umem_get(ibdev, ucmd.buf_addr, ucmd.buf_size,
+				       IB_ACCESS_LOCAL_WRITE);
 		if (IS_ERR(cq->umem)) {
 			ret = PTR_ERR(cq->umem);
 			goto err_cq;
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
@@ -266,7 +266,7 @@
 	}
 	ret = ib_device_set_netdev(&dev->ib_dev, dev->netdev, 1);
 	if (ret)
-		return ret;
+		goto err_srq_free;
 	spin_lock_init(&dev->srq_tbl_lock);
 	rdma_set_device_sysfs_group(&dev->ib_dev, &pvrdma_attr_group);
 
@@ -829,7 +829,7 @@
 	    !(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
 		dev_err(&pdev->dev, "PCI BAR region not MMIO\n");
 		ret = -ENOMEM;
-		goto err_free_device;
+		goto err_disable_pdev;
 	}
 
 	ret = pci_request_regions(pdev, DRV_NAME);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c
@@ -126,7 +126,7 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	umem = ib_umem_get(udata, start, length, access_flags, 0);
+	umem = ib_umem_get(pd->device, start, length, access_flags);
 	if (IS_ERR(umem)) {
 		dev_warn(&dev->pdev->dev,
 			 "could not get umem for mem region\n");
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
@@ -262,8 +262,9 @@
 
 			if (!is_srq) {
 				/* set qp->sq.wqe_cnt, shift, buf_size.. */
-				qp->rumem = ib_umem_get(udata, ucmd.rbuf_addr,
-							ucmd.rbuf_size, 0, 0);
+				qp->rumem =
+					ib_umem_get(pd->device, ucmd.rbuf_addr,
+						    ucmd.rbuf_size, 0);
 				if (IS_ERR(qp->rumem)) {
 					ret = PTR_ERR(qp->rumem);
 					goto err_qp;
@@ -274,8 +275,8 @@
 				qp->srq = to_vsrq(init_attr->srq);
 			}
 
-			qp->sumem = ib_umem_get(udata, ucmd.sbuf_addr,
-						ucmd.sbuf_size, 0, 0);
+			qp->sumem = ib_umem_get(pd->device, ucmd.sbuf_addr,
+						ucmd.sbuf_size, 0);
 			if (IS_ERR(qp->sumem)) {
 				if (!is_srq)
 					ib_umem_release(qp->rumem);
--- linux-ein-5.4.0.orig/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
+++ linux-ein-5.4.0/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
@@ -146,7 +146,7 @@
 		goto err_srq;
 	}
 
-	srq->umem = ib_umem_get(udata, ucmd.buf_addr, ucmd.buf_size, 0, 0);
+	srq->umem = ib_umem_get(ibsrq->device, ucmd.buf_addr, ucmd.buf_size, 0);
 	if (IS_ERR(srq->umem)) {
 		ret = PTR_ERR(srq->umem);
 		goto err_srq;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/Kconfig
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/Kconfig
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config INFINIBAND_RDMAVT
 	tristate "RDMA verbs transport library"
-	depends on X86_64 && ARCH_DMA_ADDR_T_64BIT
+	depends on INFINIBAND_VIRT_DMA
+	depends on X86_64
 	depends on PCI
 	select DMA_VIRT_OPS
 	---help---
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/cq.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/cq.c
@@ -248,8 +248,8 @@
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
 		cq->ip = rvt_create_mmap_info(rdi, sz, udata, u_wc);
-		if (!cq->ip) {
-			err = -ENOMEM;
+		if (IS_ERR(cq->ip)) {
+			err = PTR_ERR(cq->ip);
 			goto bail_wc;
 		}
 
@@ -327,7 +327,7 @@
 	if (cq->ip)
 		kref_put(&cq->ip->ref, rvt_release_mmap_info);
 	else
-		vfree(cq->queue);
+		vfree(cq->kqueue);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/mmap.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/mmap.c
@@ -154,7 +154,7 @@
  * @udata: user data (must be valid!)
  * @obj: opaque pointer to a cq, wq etc
  *
- * Return: rvt_mmap struct on success
+ * Return: rvt_mmap struct on success, ERR_PTR on failure
  */
 struct rvt_mmap_info *rvt_create_mmap_info(struct rvt_dev_info *rdi, u32 size,
 					   struct ib_udata *udata, void *obj)
@@ -166,7 +166,7 @@
 
 	ip = kmalloc_node(sizeof(*ip), GFP_KERNEL, rdi->dparms.node);
 	if (!ip)
-		return ip;
+		return ERR_PTR(-ENOMEM);
 
 	size = PAGE_ALIGN(size);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/mr.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/mr.c
@@ -390,7 +390,7 @@
 	if (length == 0)
 		return ERR_PTR(-EINVAL);
 
-	umem = ib_umem_get(udata, start, length, mr_access_flags, 0);
+	umem = ib_umem_get(pd->device, start, length, mr_access_flags);
 	if (IS_ERR(umem))
 		return (void *)umem;
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/qp.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/qp.c
@@ -61,6 +61,8 @@
 #define RVT_RWQ_COUNT_THRESHOLD 16
 
 static void rvt_rc_timeout(struct timer_list *t);
+static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
+			 enum ib_qp_type type);
 
 /*
  * Convert the AETH RNR timeout code into the number of microseconds.
@@ -452,40 +454,41 @@
 }
 
 /**
- * free_all_qps - check for QPs still in use
+ * rvt_free_qp_cb - callback function to reset a qp
+ * @qp: the qp to reset
+ * @v: a 64-bit value
+ *
+ * This function resets the qp and removes it from the
+ * qp hash table.
+ */
+static void rvt_free_qp_cb(struct rvt_qp *qp, u64 v)
+{
+	unsigned int *qp_inuse = (unsigned int *)v;
+	struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
+
+	/* Reset the qp and remove it from the qp hash list */
+	rvt_reset_qp(rdi, qp, qp->ibqp.qp_type);
+
+	/* Increment the qp_inuse count */
+	(*qp_inuse)++;
+}
+
+/**
+ * rvt_free_all_qps - check for QPs still in use
  * @rdi: rvt device info structure
  *
  * There should not be any QPs still in use.
  * Free memory for table.
+ * Return the number of QPs still in use.
  */
 static unsigned rvt_free_all_qps(struct rvt_dev_info *rdi)
 {
-	unsigned long flags;
-	struct rvt_qp *qp;
-	unsigned n, qp_inuse = 0;
-	spinlock_t *ql; /* work around too long line below */
-
-	if (rdi->driver_f.free_all_qps)
-		qp_inuse = rdi->driver_f.free_all_qps(rdi);
+	unsigned int qp_inuse = 0;
 
 	qp_inuse += rvt_mcast_tree_empty(rdi);
 
-	if (!rdi->qp_dev)
-		return qp_inuse;
+	rvt_qp_iter(rdi, (u64)&qp_inuse, rvt_free_qp_cb);
 
-	ql = &rdi->qp_dev->qpt_lock;
-	spin_lock_irqsave(ql, flags);
-	for (n = 0; n < rdi->qp_dev->qp_table_size; n++) {
-		qp = rcu_dereference_protected(rdi->qp_dev->qp_table[n],
-					       lockdep_is_held(ql));
-		RCU_INIT_POINTER(rdi->qp_dev->qp_table[n], NULL);
-
-		for (; qp; qp = rcu_dereference_protected(qp->next,
-							  lockdep_is_held(ql)))
-			qp_inuse++;
-	}
-	spin_unlock_irqrestore(ql, flags);
-	synchronize_rcu();
 	return qp_inuse;
 }
 
@@ -502,8 +505,6 @@
 	if (qps_inuse)
 		rvt_pr_err(rdi, "QP memory leak! %u still in use\n",
 			   qps_inuse);
-	if (!rdi->qp_dev)
-		return;
 
 	kfree(rdi->qp_dev->qp_table);
 	free_qpn_table(&rdi->qp_dev->qpn_table);
@@ -895,21 +896,19 @@
 	qp->s_tail_ack_queue = 0;
 	qp->s_acked_ack_queue = 0;
 	qp->s_num_rd_atomic = 0;
-	if (qp->r_rq.kwq)
-		qp->r_rq.kwq->count = qp->r_rq.size;
 	qp->r_sge.num_sge = 0;
 	atomic_set(&qp->s_reserved_used, 0);
 }
 
 /**
- * rvt_reset_qp - initialize the QP state to the reset state
+ * _rvt_reset_qp - initialize the QP state to the reset state
  * @qp: the QP to reset
  * @type: the QP type
  *
  * r_lock, s_hlock, and s_lock are required to be held by the caller
  */
-static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
-			 enum ib_qp_type type)
+static void _rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
+			  enum ib_qp_type type)
 	__must_hold(&qp->s_lock)
 	__must_hold(&qp->s_hlock)
 	__must_hold(&qp->r_lock)
@@ -955,6 +954,27 @@
 	lockdep_assert_held(&qp->s_lock);
 }
 
+/**
+ * rvt_reset_qp - initialize the QP state to the reset state
+ * @rdi: the device info
+ * @qp: the QP to reset
+ * @type: the QP type
+ *
+ * This is the wrapper function to acquire the r_lock, s_hlock, and s_lock
+ * before calling _rvt_reset_qp().
+ */
+static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
+			 enum ib_qp_type type)
+{
+	spin_lock_irq(&qp->r_lock);
+	spin_lock(&qp->s_hlock);
+	spin_lock(&qp->s_lock);
+	_rvt_reset_qp(rdi, qp, type);
+	spin_unlock(&qp->s_lock);
+	spin_unlock(&qp->s_hlock);
+	spin_unlock_irq(&qp->r_lock);
+}
+
 /** rvt_free_qpn - Free a qpn from the bit map
  * @qpt: QP table
  * @qpn: queue pair number to free
@@ -1172,7 +1192,7 @@
 		err = alloc_ud_wq_attr(qp, rdi->dparms.node);
 		if (err) {
 			ret = (ERR_PTR(err));
-			goto bail_driver_priv;
+			goto bail_rq_rvt;
 		}
 
 		err = alloc_qpn(rdi, &rdi->qp_dev->qpn_table,
@@ -1220,8 +1240,8 @@
 
 			qp->ip = rvt_create_mmap_info(rdi, s, udata,
 						      qp->r_rq.wq);
-			if (!qp->ip) {
-				ret = ERR_PTR(-ENOMEM);
+			if (IS_ERR(qp->ip)) {
+				ret = ERR_CAST(qp->ip);
 				goto bail_qpn;
 			}
 
@@ -1276,9 +1296,11 @@
 	rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num);
 
 bail_rq_wq:
-	rvt_free_rq(&qp->r_rq);
 	free_ud_wq_attr(qp);
 
+bail_rq_rvt:
+	rvt_free_rq(&qp->r_rq);
+
 bail_driver_priv:
 	rdi->driver_f.qp_priv_free(rdi, qp);
 
@@ -1546,7 +1568,7 @@
 	switch (new_state) {
 	case IB_QPS_RESET:
 		if (qp->state != IB_QPS_RESET)
-			rvt_reset_qp(rdi, qp, ibqp->qp_type);
+			_rvt_reset_qp(rdi, qp, ibqp->qp_type);
 		break;
 
 	case IB_QPS_RTR:
@@ -1695,13 +1717,7 @@
 	struct rvt_qp *qp = ibqp_to_rvtqp(ibqp);
 	struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
 
-	spin_lock_irq(&qp->r_lock);
-	spin_lock(&qp->s_hlock);
-	spin_lock(&qp->s_lock);
 	rvt_reset_qp(rdi, qp, ibqp->qp_type);
-	spin_unlock(&qp->s_lock);
-	spin_unlock(&qp->s_hlock);
-	spin_unlock_irq(&qp->r_lock);
 
 	wait_event(qp->wait, !atomic_read(&qp->refcount));
 	/* qpn is now available for use again */
@@ -2333,31 +2349,6 @@
 }
 
 /**
- * get_count - count numbers of request work queue entries
- * in circular buffer
- * @rq: data structure for request queue entry
- * @tail: tail indices of the circular buffer
- * @head: head indices of the circular buffer
- *
- * Return - total number of entries in the circular buffer
- */
-static u32 get_count(struct rvt_rq *rq, u32 tail, u32 head)
-{
-	u32 count;
-
-	count = head;
-
-	if (count >= rq->size)
-		count = 0;
-	if (count < tail)
-		count += rq->size - tail;
-	else
-		count -= tail;
-
-	return count;
-}
-
-/**
  * get_rvt_head - get head indices of the circular buffer
  * @rq: data structure for request queue entry
  * @ip: the QP
@@ -2431,7 +2422,7 @@
 
 	if (kwq->count < RVT_RWQ_COUNT_THRESHOLD) {
 		head = get_rvt_head(rq, ip);
-		kwq->count = get_count(rq, tail, head);
+		kwq->count = rvt_get_rq_count(rq, head, tail);
 	}
 	if (unlikely(kwq->count == 0)) {
 		ret = 0;
@@ -2466,7 +2457,9 @@
 		 * the number of remaining WQEs.
 		 */
 		if (kwq->count < srq->limit) {
-			kwq->count = get_count(rq, tail, get_rvt_head(rq, ip));
+			kwq->count =
+				rvt_get_rq_count(rq,
+						 get_rvt_head(rq, ip), tail);
 			if (kwq->count < srq->limit) {
 				struct ib_event ev;
 
@@ -2817,7 +2810,7 @@
 EXPORT_SYMBOL(rvt_qp_iter);
 
 /*
- * This should be called with s_lock held.
+ * This should be called with s_lock and r_lock held.
  */
 void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
 		       enum ib_wc_status status)
@@ -3115,6 +3108,8 @@
 	case IB_WR_ATOMIC_FETCH_AND_ADD:
 		if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
 			goto inv_err;
+		if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1)))
+			goto inv_err;
 		if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
 					  wqe->atomic_wr.remote_addr,
 					  wqe->atomic_wr.rkey,
@@ -3174,7 +3169,9 @@
 	rvp->n_loop_pkts++;
 flush_send:
 	sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
+	spin_lock(&sqp->r_lock);
 	rvt_send_complete(sqp, wqe, send_status);
+	spin_unlock(&sqp->r_lock);
 	if (local_ops) {
 		atomic_dec(&sqp->local_ops_pending);
 		local_ops = 0;
@@ -3228,9 +3225,15 @@
 	spin_unlock_irqrestore(&qp->r_lock, flags);
 serr_no_r_lock:
 	spin_lock_irqsave(&sqp->s_lock, flags);
+	spin_lock(&sqp->r_lock);
 	rvt_send_complete(sqp, wqe, send_status);
+	spin_unlock(&sqp->r_lock);
 	if (sqp->ibqp.qp_type == IB_QPT_RC) {
-		int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+		int lastwqe;
+
+		spin_lock(&sqp->r_lock);
+		lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+		spin_unlock(&sqp->r_lock);
 
 		sqp->s_flags &= ~RVT_S_BUSY;
 		spin_unlock_irqrestore(&sqp->s_lock, flags);
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/rc.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/rc.c
@@ -127,9 +127,7 @@
 			 * not atomic, which is OK, since the fuzziness is
 			 * resolved as further ACKs go out.
 			 */
-			credits = head - tail;
-			if ((int)credits < 0)
-				credits += qp->r_rq.size;
+			credits = rvt_get_rq_count(&qp->r_rq, head, tail);
 		}
 		/*
 		 * Binary search the credit table to find the code to
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/srq.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/srq.c
@@ -111,8 +111,8 @@
 		u32 s = sizeof(struct rvt_rwq) + srq->rq.size * sz;
 
 		srq->ip = rvt_create_mmap_info(dev, s, udata, srq->rq.wq);
-		if (!srq->ip) {
-			ret = -ENOMEM;
+		if (IS_ERR(srq->ip)) {
+			ret = PTR_ERR(srq->ip);
 			goto bail_wq;
 		}
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rdmavt/vt.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rdmavt/vt.c
@@ -95,9 +95,7 @@
 	if (!rdi)
 		return rdi;
 
-	rdi->ports = kcalloc(nports,
-			     sizeof(struct rvt_ibport **),
-			     GFP_KERNEL);
+	rdi->ports = kcalloc(nports, sizeof(*rdi->ports), GFP_KERNEL);
 	if (!rdi->ports)
 		ib_dealloc_device(&rdi->ibdev);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/Kconfig
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/Kconfig
@@ -2,8 +2,9 @@
 config RDMA_RXE
 	tristate "Software RDMA over Ethernet (RoCE) driver"
 	depends on INET && PCI && INFINIBAND
-	depends on !64BIT || ARCH_DMA_ADDR_T_64BIT
+	depends on INFINIBAND_VIRT_DMA
 	select NET_UDP_TUNNEL
+	select CRYPTO
 	select CRYPTO_CRC32
 	select DMA_VIRT_OPS
 	---help---
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe.c
@@ -48,6 +48,8 @@
 
 }
 
+bool rxe_initialized;
+
 /* free resources for a rxe device all objects created for this device must
  * have been destroyed
  */
@@ -116,6 +118,8 @@
 	rxe->attr.max_fast_reg_page_list_len	= RXE_MAX_FMR_PAGE_LIST_LEN;
 	rxe->attr.max_pkeys			= RXE_MAX_PKEYS;
 	rxe->attr.local_ca_ack_delay		= RXE_LOCAL_CA_ACK_DELAY;
+	addrconf_addr_eui48((unsigned char *)&rxe->attr.sys_image_guid,
+			rxe->ndev->dev_addr);
 
 	rxe->max_ucontext			= RXE_MAX_UCONTEXT;
 }
@@ -157,9 +161,6 @@
 
 	rxe_init_port_param(port);
 
-	if (!port->attr.pkey_tbl_len || !port->attr.gid_tbl_len)
-		return -EINVAL;
-
 	port->pkey_tbl = kcalloc(port->attr.pkey_tbl_len,
 			sizeof(*port->pkey_tbl), GFP_KERNEL);
 
@@ -358,6 +359,7 @@
 		return err;
 
 	rdma_link_register(&rxe_link_ops);
+	rxe_initialized = true;
 	pr_info("loaded\n");
 	return 0;
 }
@@ -369,6 +371,7 @@
 	rxe_net_exit();
 	rxe_cache_exit();
 
+	rxe_initialized = false;
 	pr_info("unloaded\n");
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe.h
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe.h
@@ -67,6 +67,8 @@
 
 #define RXE_ROCE_V2_SPORT		(0xc000)
 
+extern bool rxe_initialized;
+
 static inline u32 rxe_crc32(struct rxe_dev *rxe,
 			    u32 crc, void *next, size_t len)
 {
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_comp.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -329,7 +329,7 @@
 					qp->comp.psn = pkt->psn;
 					if (qp->req.wait_psn) {
 						qp->req.wait_psn = 0;
-						rxe_run_task(&qp->req.task, 1);
+						rxe_run_task(&qp->req.task, 0);
 					}
 				}
 				return COMPST_ERROR_RETRY;
@@ -463,7 +463,7 @@
 	 */
 	if (qp->req.wait_fence) {
 		qp->req.wait_fence = 0;
-		rxe_run_task(&qp->req.task, 1);
+		rxe_run_task(&qp->req.task, 0);
 	}
 }
 
@@ -479,7 +479,7 @@
 		if (qp->req.need_rd_atomic) {
 			qp->comp.timeout_retry = 0;
 			qp->req.need_rd_atomic = 0;
-			rxe_run_task(&qp->req.task, 1);
+			rxe_run_task(&qp->req.task, 0);
 		}
 	}
 
@@ -725,7 +725,7 @@
 							RXE_CNT_COMP_RETRY);
 					qp->req.need_retry = 1;
 					qp->comp.started_retry = 1;
-					rxe_run_task(&qp->req.task, 1);
+					rxe_run_task(&qp->req.task, 0);
 				}
 
 				if (pkt) {
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_mmap.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_mmap.c
@@ -151,7 +151,7 @@
 
 	ip = kmalloc(sizeof(*ip), GFP_KERNEL);
 	if (!ip)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	size = PAGE_ALIGN(size);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_mr.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -169,11 +169,11 @@
 	void			*vaddr;
 	int err;
 
-	umem = ib_umem_get(udata, start, length, access, 0);
+	umem = ib_umem_get(pd->ibpd.device, start, length, access);
 	if (IS_ERR(umem)) {
 		pr_warn("err %d from rxe_umem_get\n",
 			(int)PTR_ERR(umem));
-		err = -EINVAL;
+		err = PTR_ERR(umem);
 		goto err1;
 	}
 
@@ -207,6 +207,7 @@
 			vaddr = page_address(sg_page_iter_page(&sg_iter));
 			if (!vaddr) {
 				pr_warn("null vaddr\n");
+				ib_umem_release(umem);
 				err = -ENOMEM;
 				goto err1;
 			}
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_net.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_net.c
@@ -117,10 +117,12 @@
 	memcpy(&fl6.daddr, daddr, sizeof(*daddr));
 	fl6.flowi6_proto = IPPROTO_UDP;
 
-	if (unlikely(ipv6_stub->ipv6_dst_lookup(sock_net(recv_sockets.sk6->sk),
-						recv_sockets.sk6->sk, &ndst, &fl6))) {
+	ndst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(recv_sockets.sk6->sk),
+					       recv_sockets.sk6->sk, &fl6,
+					       NULL);
+	if (unlikely(IS_ERR(ndst))) {
 		pr_err_ratelimited("no route to %pI6\n", daddr);
-		goto put;
+		return NULL;
 	}
 
 	if (unlikely(ndst->error)) {
@@ -249,10 +251,8 @@
 
 	/* Create UDP socket */
 	err = udp_sock_create(net, &udp_cfg, &sock);
-	if (err < 0) {
-		pr_err("failed to create udp socket. err = %d\n", err);
+	if (err < 0)
 		return ERR_PTR(err);
-	}
 
 	tnl_cfg.encap_type = 1;
 	tnl_cfg.encap_rcv = rxe_udp_encap_recv;
@@ -451,6 +451,11 @@
 
 void rxe_loopback(struct sk_buff *skb)
 {
+	if (skb->protocol == htons(ETH_P_IP))
+		skb_pull(skb, sizeof(struct iphdr));
+	else
+		skb_pull(skb, sizeof(struct ipv6hdr));
+
 	rxe_rcv(skb);
 }
 
@@ -653,6 +658,12 @@
 
 	recv_sockets.sk6 = rxe_setup_udp_tunnel(&init_net,
 						htons(ROCE_V2_UDP_DPORT), true);
+	if (PTR_ERR(recv_sockets.sk6) == -EAFNOSUPPORT) {
+		recv_sockets.sk6 = NULL;
+		pr_warn("IPv6 is not supported, can not create a UDPv6 socket\n");
+		return 0;
+	}
+
 	if (IS_ERR(recv_sockets.sk6)) {
 		recv_sockets.sk6 = NULL;
 		pr_err("Failed to create IPv6 UDP tunnel\n");
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_opcode.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_opcode.c
@@ -137,7 +137,7 @@
 		}
 	},
 	[IB_OPCODE_RC_SEND_MIDDLE]		= {
-		.name	= "IB_OPCODE_RC_SEND_MIDDLE]",
+		.name	= "IB_OPCODE_RC_SEND_MIDDLE",
 		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_SEND_MASK
 				| RXE_MIDDLE_MASK,
 		.length = RXE_BTH_BYTES,
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_param.h
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_param.h
@@ -140,7 +140,7 @@
 /* default/initial rxe port parameters */
 enum rxe_port_param {
 	RXE_PORT_GID_TBL_LEN		= 1024,
-	RXE_PORT_PORT_CAP_FLAGS		= RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP,
+	RXE_PORT_PORT_CAP_FLAGS		= IB_PORT_CM_SUP,
 	RXE_PORT_MAX_MSG_SZ		= 0x800000,
 	RXE_PORT_BAD_PKEY_CNTR		= 0,
 	RXE_PORT_QKEY_VIOL_CNTR		= 0,
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_qp.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -152,7 +152,6 @@
 void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res)
 {
 	if (res->type == RXE_ATOMIC_MASK) {
-		rxe_drop_ref(qp);
 		kfree_skb(res->atomic.skb);
 	} else if (res->type == RXE_READ_MASK) {
 		if (res->read.mr)
@@ -212,6 +211,17 @@
 	spin_lock_init(&qp->grp_lock);
 	spin_lock_init(&qp->state_lock);
 
+	spin_lock_init(&qp->req.task.state_lock);
+	spin_lock_init(&qp->resp.task.state_lock);
+	spin_lock_init(&qp->comp.task.state_lock);
+
+	spin_lock_init(&qp->sq.sq_lock);
+	spin_lock_init(&qp->rq.producer_lock);
+	spin_lock_init(&qp->rq.consumer_lock);
+
+	skb_queue_head_init(&qp->req_pkts);
+	skb_queue_head_init(&qp->resp_pkts);
+
 	atomic_set(&qp->ssn, 0);
 	atomic_set(&qp->skb_out, 0);
 }
@@ -260,6 +270,7 @@
 	if (err) {
 		vfree(qp->sq.queue->buf);
 		kfree(qp->sq.queue);
+		qp->sq.queue = NULL;
 		return err;
 	}
 
@@ -268,13 +279,8 @@
 	qp->req.opcode		= -1;
 	qp->comp.opcode		= -1;
 
-	spin_lock_init(&qp->sq.sq_lock);
-	skb_queue_head_init(&qp->req_pkts);
-
-	rxe_init_task(rxe, &qp->req.task, qp,
-		      rxe_requester, "req");
-	rxe_init_task(rxe, &qp->comp.task, qp,
-		      rxe_completer, "comp");
+	rxe_init_task(&qp->req.task, qp, rxe_requester);
+	rxe_init_task(&qp->comp.task, qp, rxe_completer);
 
 	qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */
 	if (init->qp_type == IB_QPT_RC) {
@@ -313,17 +319,12 @@
 		if (err) {
 			vfree(qp->rq.queue->buf);
 			kfree(qp->rq.queue);
+			qp->rq.queue = NULL;
 			return err;
 		}
 	}
 
-	spin_lock_init(&qp->rq.producer_lock);
-	spin_lock_init(&qp->rq.consumer_lock);
-
-	skb_queue_head_init(&qp->resp_pkts);
-
-	rxe_init_task(rxe, &qp->resp.task, qp,
-		      rxe_responder, "resp");
+	rxe_init_task(&qp->resp.task, qp, rxe_responder);
 
 	qp->resp.opcode		= OPCODE_NONE;
 	qp->resp.msn		= 0;
@@ -373,6 +374,11 @@
 err2:
 	rxe_queue_cleanup(qp->sq.queue);
 err1:
+	qp->pd = NULL;
+	qp->rcq = NULL;
+	qp->scq = NULL;
+	qp->srq = NULL;
+
 	if (srq)
 		rxe_drop_ref(srq);
 	rxe_drop_ref(scq);
@@ -592,15 +598,16 @@
 	int err;
 
 	if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
-		int max_rd_atomic = __roundup_pow_of_two(attr->max_rd_atomic);
+		int max_rd_atomic = attr->max_rd_atomic ?
+			roundup_pow_of_two(attr->max_rd_atomic) : 0;
 
 		qp->attr.max_rd_atomic = max_rd_atomic;
 		atomic_set(&qp->req.rd_atomic, max_rd_atomic);
 	}
 
 	if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
-		int max_dest_rd_atomic =
-			__roundup_pow_of_two(attr->max_dest_rd_atomic);
+		int max_dest_rd_atomic = attr->max_dest_rd_atomic ?
+			roundup_pow_of_two(attr->max_dest_rd_atomic) : 0;
 
 		qp->attr.max_dest_rd_atomic = max_dest_rd_atomic;
 
@@ -794,7 +801,9 @@
 	rxe_cleanup_task(&qp->comp.task);
 
 	/* flush out any receive wr's or pending requests */
-	__rxe_do_task(&qp->req.task);
+	if (qp->req.task.func)
+		__rxe_do_task(&qp->req.task);
+
 	if (qp->sq.queue) {
 		__rxe_do_task(&qp->comp.task);
 		__rxe_do_task(&qp->req.task);
@@ -829,13 +838,15 @@
 		qp->resp.mr = NULL;
 	}
 
-	if (qp_type(qp) == IB_QPT_RC)
-		sk_dst_reset(qp->sk->sk);
-
 	free_rd_atomic_resources(qp);
 
-	kernel_sock_shutdown(qp->sk, SHUT_RDWR);
-	sock_release(qp->sk);
+	if (qp->sk) {
+		if (qp_type(qp) == IB_QPT_RC)
+			sk_dst_reset(qp->sk->sk);
+
+		kernel_sock_shutdown(qp->sk, SHUT_RDWR);
+		sock_release(qp->sk);
+	}
 }
 
 /* called when the last reference to the qp is dropped */
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_queue.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_queue.c
@@ -45,12 +45,15 @@
 
 	if (outbuf) {
 		ip = rxe_create_mmap_info(rxe, buf_size, udata, buf);
-		if (!ip)
+		if (IS_ERR(ip)) {
+			err = PTR_ERR(ip);
 			goto err1;
+		}
 
-		err = copy_to_user(outbuf, &ip->info, sizeof(ip->info));
-		if (err)
+		if (copy_to_user(outbuf, &ip->info, sizeof(ip->info))) {
+			err = -EFAULT;
 			goto err2;
+		}
 
 		spin_lock_bh(&rxe->pending_lock);
 		list_add(&ip->pending_mmaps, &rxe->pending_mmaps);
@@ -64,7 +67,7 @@
 err2:
 	kfree(ip);
 err1:
-	return -EINVAL;
+	return err;
 }
 
 inline void rxe_queue_reset(struct rxe_queue *q)
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_recv.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_recv.c
@@ -36,21 +36,26 @@
 #include "rxe.h"
 #include "rxe_loc.h"
 
+/* check that QP matches packet opcode type and is in a valid state */
 static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 			    struct rxe_qp *qp)
 {
+	unsigned int pkt_type;
+
 	if (unlikely(!qp->valid))
 		goto err1;
 
+	pkt_type = pkt->opcode & 0xe0;
+
 	switch (qp_type(qp)) {
 	case IB_QPT_RC:
-		if (unlikely((pkt->opcode & IB_OPCODE_RC) != 0)) {
+		if (unlikely(pkt_type != IB_OPCODE_RC)) {
 			pr_warn_ratelimited("bad qp type\n");
 			goto err1;
 		}
 		break;
 	case IB_QPT_UC:
-		if (unlikely(!(pkt->opcode & IB_OPCODE_UC))) {
+		if (unlikely(pkt_type != IB_OPCODE_UC)) {
 			pr_warn_ratelimited("bad qp type\n");
 			goto err1;
 		}
@@ -58,7 +63,7 @@
 	case IB_QPT_UD:
 	case IB_QPT_SMI:
 	case IB_QPT_GSI:
-		if (unlikely(!(pkt->opcode & IB_OPCODE_UD))) {
+		if (unlikely(pkt_type != IB_OPCODE_UD)) {
 			pr_warn_ratelimited("bad qp type\n");
 			goto err1;
 		}
@@ -281,6 +286,8 @@
 	struct rxe_mc_elem *mce;
 	struct rxe_qp *qp;
 	union ib_gid dgid;
+	struct sk_buff *per_qp_skb;
+	struct rxe_pkt_info *per_qp_pkt;
 	int err;
 
 	if (skb->protocol == htons(ETH_P_IP))
@@ -298,7 +305,6 @@
 
 	list_for_each_entry(mce, &mcg->qp_list, qp_list) {
 		qp = mce->qp;
-		pkt = SKB_TO_PKT(skb);
 
 		/* validate qp for incoming packet */
 		err = check_type_state(rxe, pkt, qp);
@@ -309,15 +315,27 @@
 		if (err)
 			continue;
 
-		/* if *not* the last qp in the list
-		 * increase the users of the skb then post to the next qp
+		/* for all but the last qp create a new clone of the
+		 * skb and pass to the qp. If an error occurs in the
+		 * checks for the last qp in the list we need to
+		 * free the skb since it hasn't been passed on to
+		 * rxe_rcv_pkt() which would free it later.
 		 */
-		if (mce->qp_list.next != &mcg->qp_list)
-			skb_get(skb);
+		if (mce->qp_list.next != &mcg->qp_list) {
+			per_qp_skb = skb_clone(skb, GFP_ATOMIC);
+		} else {
+			per_qp_skb = skb;
+			/* show we have consumed the skb */
+			skb = NULL;
+		}
 
-		pkt->qp = qp;
+		if (unlikely(!per_qp_skb))
+			continue;
+
+		per_qp_pkt = SKB_TO_PKT(per_qp_skb);
+		per_qp_pkt->qp = qp;
 		rxe_add_ref(qp);
-		rxe_rcv_pkt(pkt, skb);
+		rxe_rcv_pkt(per_qp_pkt, per_qp_skb);
 	}
 
 	spin_unlock_bh(&mcg->mcg_lock);
@@ -325,15 +343,20 @@
 	rxe_drop_ref(mcg);	/* drop ref from rxe_pool_get_key. */
 
 err1:
+	/* free skb if not consumed */
 	kfree_skb(skb);
 }
 
 static int rxe_match_dgid(struct rxe_dev *rxe, struct sk_buff *skb)
 {
+	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 	const struct ib_gid_attr *gid_attr;
 	union ib_gid dgid;
 	union ib_gid *pdgid;
 
+	if (pkt->mask & RXE_LOOPBACK_MASK)
+		return 0;
+
 	if (skb->protocol == htons(ETH_P_IP)) {
 		ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
 				       (struct in6_addr *)&dgid);
@@ -366,7 +389,7 @@
 	if (unlikely(skb->len < pkt->offset + RXE_BTH_BYTES))
 		goto drop;
 
-	if (unlikely(rxe_match_dgid(rxe, skb) < 0)) {
+	if (rxe_match_dgid(rxe, skb) < 0) {
 		pr_warn_ratelimited("failed matching dgid\n");
 		goto drop;
 	}
@@ -389,7 +412,7 @@
 
 	calc_icrc = rxe_icrc_hdr(pkt, skb);
 	calc_icrc = rxe_crc32(rxe, calc_icrc, (u8 *)payload_addr(pkt),
-			      payload_size(pkt));
+			      payload_size(pkt) + bth_pad(pkt));
 	calc_icrc = (__force u32)cpu_to_be32(~calc_icrc);
 	if (unlikely(calc_icrc != pack_icrc)) {
 		if (skb->protocol == htons(ETH_P_IPV6))
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_req.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_req.c
@@ -500,6 +500,12 @@
 			if (err)
 				return err;
 		}
+		if (bth_pad(pkt)) {
+			u8 *pad = payload_addr(pkt) + paylen;
+
+			memset(pad, 0, bth_pad(pkt));
+			crc = rxe_crc32(rxe, crc, pad, bth_pad(pkt));
+		}
 	}
 	p = payload_addr(pkt) + paylen + bth_pad(pkt);
 
@@ -658,7 +664,8 @@
 	}
 
 	if (unlikely(qp_type(qp) == IB_QPT_RC &&
-		     qp->req.psn > (qp->comp.psn + RXE_MAX_UNACKED_PSNS))) {
+		psn_compare(qp->req.psn, (qp->comp.psn +
+				RXE_MAX_UNACKED_PSNS)) > 0)) {
 		qp->req.wait_psn = 1;
 		goto exit;
 	}
@@ -673,7 +680,7 @@
 	opcode = next_opcode(qp, wqe, wqe->wr.opcode);
 	if (unlikely(opcode < 0)) {
 		wqe->status = IB_WC_LOC_QP_OP_ERR;
-		goto exit;
+		goto err;
 	}
 
 	mask = rxe_opcode[opcode].mask;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_resp.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -732,6 +732,13 @@
 	if (err)
 		pr_err("Failed copying memory\n");
 
+	if (bth_pad(&ack_pkt)) {
+		struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+		u8 *pad = payload_addr(&ack_pkt) + payload;
+
+		memset(pad, 0, bth_pad(&ack_pkt));
+		icrc = rxe_crc32(rxe, icrc, pad, bth_pad(&ack_pkt));
+	}
 	p = payload_addr(&ack_pkt) + payload + bth_pad(&ack_pkt);
 	*p = ~icrc;
 
@@ -986,8 +993,6 @@
 		goto out;
 	}
 
-	rxe_add_ref(qp);
-
 	res = &qp->resp.resources[qp->resp.res_head];
 	free_rd_atomic_resource(qp, res);
 	rxe_advance_resp_resource(qp);
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_sysfs.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_sysfs.c
@@ -61,6 +61,11 @@
 	struct net_device *ndev;
 	struct rxe_dev *exists;
 
+	if (!rxe_initialized) {
+		pr_err("Module parameters are not supported, use rdma link add or rxe_cfg\n");
+		return -EAGAIN;
+	}
+
 	len = sanitize_arg(val, intf, sizeof(intf));
 	if (!len) {
 		pr_err("add: invalid interface name\n");
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_task.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_task.c
@@ -114,13 +114,10 @@
 	task->ret = ret;
 }
 
-int rxe_init_task(void *obj, struct rxe_task *task,
-		  void *arg, int (*func)(void *), char *name)
+int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *))
 {
-	task->obj	= obj;
 	task->arg	= arg;
 	task->func	= func;
-	snprintf(task->name, sizeof(task->name), "%s", name);
 	task->destroyed	= false;
 
 	tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_task.h
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_task.h
@@ -46,14 +46,12 @@
  * called again.
  */
 struct rxe_task {
-	void			*obj;
 	struct tasklet_struct	tasklet;
 	int			state;
 	spinlock_t		state_lock; /* spinlock for task state */
 	void			*arg;
 	int			(*func)(void *arg);
 	int			ret;
-	char			name[16];
 	bool			destroyed;
 };
 
@@ -62,8 +60,7 @@
  *	arg  => parameter to pass to fcn
  *	fcn  => function to call until it returns != 0
  */
-int rxe_init_task(void *obj, struct rxe_task *task,
-		  void *arg, int (*func)(void *), char *name);
+int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *));
 
 /* cleanup task */
 void rxe_cleanup_task(struct rxe_task *task);
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -679,6 +679,7 @@
 	unsigned int mask;
 	unsigned int length = 0;
 	int i;
+	struct ib_send_wr *next;
 
 	while (wr) {
 		mask = wr_opcode_mask(wr->opcode, qp);
@@ -695,6 +696,8 @@
 			break;
 		}
 
+		next = wr->next;
+
 		length = 0;
 		for (i = 0; i < wr->num_sge; i++)
 			length += wr->sg_list[i].length;
@@ -705,7 +708,7 @@
 			*bad_wr = wr;
 			break;
 		}
-		wr = wr->next;
+		wr = next;
 	}
 
 	rxe_run_task(&qp->req.task, 1);
@@ -1075,7 +1078,7 @@
 	struct rxe_dev *rxe =
 		rdma_device_to_drv_device(device, struct rxe_dev, ib_dev);
 
-	return snprintf(buf, 16, "%s\n", rxe_parent_name(rxe, 1));
+	return scnprintf(buf, PAGE_SIZE, "%s\n", rxe_parent_name(rxe, 1));
 }
 
 static DEVICE_ATTR_RO(parent);
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ linux-ein-5.4.0/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -407,7 +407,7 @@
 	struct list_head	pending_mmaps;
 
 	spinlock_t		mmap_offset_lock; /* guard mmap_offset */
-	int			mmap_offset;
+	u64			mmap_offset;
 
 	atomic64_t		stats_counters[RXE_NUM_OF_COUNTERS];
 
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/Kconfig
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/Kconfig
@@ -1,6 +1,7 @@
 config RDMA_SIW
 	tristate "Software RDMA over TCP/IP (iWARP) driver"
 	depends on INET && INFINIBAND && LIBCRC32C
+	depends on INFINIBAND_VIRT_DMA
 	select DMA_VIRT_OPS
 	help
 	This driver implements the iWARP RDMA transport over
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw.h
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw.h
@@ -658,16 +658,11 @@
 	return &qp->orq[qp->orq_get % qp->attrs.orq_size];
 }
 
-static inline struct siw_sqe *orq_get_tail(struct siw_qp *qp)
-{
-	return &qp->orq[qp->orq_put % qp->attrs.orq_size];
-}
-
 static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
 {
-	struct siw_sqe *orq_e = orq_get_tail(qp);
+	struct siw_sqe *orq_e = &qp->orq[qp->orq_put % qp->attrs.orq_size];
 
-	if (orq_e && READ_ONCE(orq_e->flags) == 0)
+	if (READ_ONCE(orq_e->flags) == 0)
 		return orq_e;
 
 	return NULL;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_cm.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_cm.c
@@ -725,11 +725,11 @@
 	enum mpa_v2_ctrl mpa_p2p_mode = MPA_V2_RDMA_NO_RTR;
 
 	rv = siw_recv_mpa_rr(cep);
-	if (rv != -EAGAIN)
-		siw_cancel_mpatimer(cep);
 	if (rv)
 		goto out_err;
 
+	siw_cancel_mpatimer(cep);
+
 	rep = &cep->mpa.hdr;
 
 	if (__mpa_rr_revision(rep->params.bits) > MPA_REVISION_2) {
@@ -895,7 +895,8 @@
 	}
 
 out_err:
-	siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, -EINVAL);
+	if (rv != -EAGAIN)
+		siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, -EINVAL);
 
 	return rv;
 }
@@ -976,14 +977,16 @@
 
 		siw_cep_set_inuse(new_cep);
 		rv = siw_proc_mpareq(new_cep);
-		siw_cep_set_free(new_cep);
-
 		if (rv != -EAGAIN) {
 			siw_cep_put(cep);
 			new_cep->listen_cep = NULL;
-			if (rv)
+			if (rv) {
+				siw_cancel_mpatimer(new_cep);
+				siw_cep_set_free(new_cep);
 				goto error;
+			}
 		}
+		siw_cep_set_free(new_cep);
 	}
 	return;
 
@@ -1103,9 +1106,12 @@
 				/*
 				 * Socket close before MPA request received.
 				 */
-				siw_dbg_cep(cep, "no mpareq: drop listener\n");
-				siw_cep_put(cep->listen_cep);
-				cep->listen_cep = NULL;
+				if (cep->listen_cep) {
+					siw_dbg_cep(cep,
+						"no mpareq: drop listener\n");
+					siw_cep_put(cep->listen_cep);
+					cep->listen_cep = NULL;
+				}
 			}
 		}
 		release_cep = 1;
@@ -1225,11 +1231,14 @@
 	read_lock(&sk->sk_callback_lock);
 
 	cep = sk_to_cep(sk);
-	if (!cep) {
-		WARN_ON(1);
+	if (!cep)
+		goto out;
+
+	siw_dbg_cep(cep, "cep state: %d, socket state %d\n",
+		    cep->state, sk->sk_state);
+
+	if (sk->sk_state != TCP_ESTABLISHED)
 		goto out;
-	}
-	siw_dbg_cep(cep, "state: %d\n", cep->state);
 
 	switch (cep->state) {
 	case SIW_EPSTATE_RDMA_MODE:
@@ -1524,7 +1533,6 @@
 
 		cep->cm_id = NULL;
 		id->rem_ref(id);
-		siw_cep_put(cep);
 
 		qp->cep = NULL;
 		siw_cep_put(cep);
@@ -1784,14 +1792,23 @@
 	return 0;
 }
 
-static int siw_listen_address(struct iw_cm_id *id, int backlog,
-			      struct sockaddr *laddr, int addr_family)
+/*
+ * siw_create_listen - Create resources for a listener's IWCM ID @id
+ *
+ * Starts listen on the socket address id->local_addr.
+ *
+ */
+int siw_create_listen(struct iw_cm_id *id, int backlog)
 {
 	struct socket *s;
 	struct siw_cep *cep = NULL;
 	struct siw_device *sdev = to_siw_dev(id->device);
+	int addr_family = id->local_addr.ss_family;
 	int rv = 0, s_val;
 
+	if (addr_family != AF_INET && addr_family != AF_INET6)
+		return -EAFNOSUPPORT;
+
 	rv = sock_create(addr_family, SOCK_STREAM, IPPROTO_TCP, &s);
 	if (rv < 0)
 		return rv;
@@ -1806,9 +1823,25 @@
 		siw_dbg(id->device, "setsockopt error: %d\n", rv);
 		goto error;
 	}
-	rv = s->ops->bind(s, laddr, addr_family == AF_INET ?
-				    sizeof(struct sockaddr_in) :
-				    sizeof(struct sockaddr_in6));
+	if (addr_family == AF_INET) {
+		struct sockaddr_in *laddr = &to_sockaddr_in(id->local_addr);
+
+		/* For wildcard addr, limit binding to current device only */
+		if (ipv4_is_zeronet(laddr->sin_addr.s_addr))
+			s->sk->sk_bound_dev_if = sdev->netdev->ifindex;
+
+		rv = s->ops->bind(s, (struct sockaddr *)laddr,
+				  sizeof(struct sockaddr_in));
+	} else {
+		struct sockaddr_in6 *laddr = &to_sockaddr_in6(id->local_addr);
+
+		/* For wildcard addr, limit binding to current device only */
+		if (ipv6_addr_any(&laddr->sin6_addr))
+			s->sk->sk_bound_dev_if = sdev->netdev->ifindex;
+
+		rv = s->ops->bind(s, (struct sockaddr *)laddr,
+				  sizeof(struct sockaddr_in6));
+	}
 	if (rv) {
 		siw_dbg(id->device, "socket bind error: %d\n", rv);
 		goto error;
@@ -1867,14 +1900,7 @@
 	list_add_tail(&cep->listenq, (struct list_head *)id->provider_data);
 	cep->state = SIW_EPSTATE_LISTENING;
 
-	if (addr_family == AF_INET)
-		siw_dbg(id->device, "Listen at laddr %pI4 %u\n",
-			&(((struct sockaddr_in *)laddr)->sin_addr),
-			((struct sockaddr_in *)laddr)->sin_port);
-	else
-		siw_dbg(id->device, "Listen at laddr %pI6 %u\n",
-			&(((struct sockaddr_in6 *)laddr)->sin6_addr),
-			((struct sockaddr_in6 *)laddr)->sin6_port);
+	siw_dbg(id->device, "Listen at laddr %pISp\n", &id->local_addr);
 
 	return 0;
 
@@ -1932,114 +1958,6 @@
 	}
 }
 
-/*
- * siw_create_listen - Create resources for a listener's IWCM ID @id
- *
- * Listens on the socket addresses id->local_addr and id->remote_addr.
- *
- * If the listener's @id provides a specific local IP address, at most one
- * listening socket is created and associated with @id.
- *
- * If the listener's @id provides the wildcard (zero) local IP address,
- * a separate listen is performed for each local IP address of the device
- * by creating a listening socket and binding to that local IP address.
- *
- */
-int siw_create_listen(struct iw_cm_id *id, int backlog)
-{
-	struct net_device *dev = to_siw_dev(id->device)->netdev;
-	int rv = 0, listeners = 0;
-
-	siw_dbg(id->device, "backlog %d\n", backlog);
-
-	/*
-	 * For each attached address of the interface, create a
-	 * listening socket, if id->local_addr is the wildcard
-	 * IP address or matches the IP address.
-	 */
-	if (id->local_addr.ss_family == AF_INET) {
-		struct in_device *in_dev = in_dev_get(dev);
-		struct sockaddr_in s_laddr, *s_raddr;
-		const struct in_ifaddr *ifa;
-
-		if (!in_dev) {
-			rv = -ENODEV;
-			goto out;
-		}
-		memcpy(&s_laddr, &id->local_addr, sizeof(s_laddr));
-		s_raddr = (struct sockaddr_in *)&id->remote_addr;
-
-		siw_dbg(id->device,
-			"laddr %pI4:%d, raddr %pI4:%d\n",
-			&s_laddr.sin_addr, ntohs(s_laddr.sin_port),
-			&s_raddr->sin_addr, ntohs(s_raddr->sin_port));
-
-		rtnl_lock();
-		in_dev_for_each_ifa_rtnl(ifa, in_dev) {
-			if (ipv4_is_zeronet(s_laddr.sin_addr.s_addr) ||
-			    s_laddr.sin_addr.s_addr == ifa->ifa_address) {
-				s_laddr.sin_addr.s_addr = ifa->ifa_address;
-
-				rv = siw_listen_address(id, backlog,
-						(struct sockaddr *)&s_laddr,
-						AF_INET);
-				if (!rv)
-					listeners++;
-			}
-		}
-		rtnl_unlock();
-		in_dev_put(in_dev);
-	} else if (id->local_addr.ss_family == AF_INET6) {
-		struct inet6_dev *in6_dev = in6_dev_get(dev);
-		struct inet6_ifaddr *ifp;
-		struct sockaddr_in6 *s_laddr = &to_sockaddr_in6(id->local_addr),
-			*s_raddr = &to_sockaddr_in6(id->remote_addr);
-
-		if (!in6_dev) {
-			rv = -ENODEV;
-			goto out;
-		}
-		siw_dbg(id->device,
-			"laddr %pI6:%d, raddr %pI6:%d\n",
-			&s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
-			&s_raddr->sin6_addr, ntohs(s_raddr->sin6_port));
-
-		rtnl_lock();
-		list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
-			if (ifp->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
-				continue;
-			if (ipv6_addr_any(&s_laddr->sin6_addr) ||
-			    ipv6_addr_equal(&s_laddr->sin6_addr, &ifp->addr)) {
-				struct sockaddr_in6 bind_addr  = {
-					.sin6_family = AF_INET6,
-					.sin6_port = s_laddr->sin6_port,
-					.sin6_flowinfo = 0,
-					.sin6_addr = ifp->addr,
-					.sin6_scope_id = dev->ifindex };
-
-				rv = siw_listen_address(id, backlog,
-						(struct sockaddr *)&bind_addr,
-						AF_INET6);
-				if (!rv)
-					listeners++;
-			}
-		}
-		rtnl_unlock();
-		in6_dev_put(in6_dev);
-	} else {
-		rv = -EAFNOSUPPORT;
-	}
-out:
-	if (listeners)
-		rv = 0;
-	else if (!rv)
-		rv = -EINVAL;
-
-	siw_dbg(id->device, "%s\n", rv ? "FAIL" : "OK");
-
-	return rv;
-}
-
 int siw_destroy_listen(struct iw_cm_id *id)
 {
 	if (!id->provider_data) {
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_cq.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_cq.c
@@ -56,8 +56,6 @@
 	if (READ_ONCE(cqe->flags) & SIW_WQE_VALID) {
 		memset(wc, 0, sizeof(*wc));
 		wc->wr_id = cqe->id;
-		wc->status = map_cqe_status[cqe->status].ib;
-		wc->opcode = map_wc_opcode[cqe->opcode];
 		wc->byte_len = cqe->bytes;
 
 		/*
@@ -71,10 +69,32 @@
 				wc->wc_flags = IB_WC_WITH_INVALIDATE;
 			}
 			wc->qp = cqe->base_qp;
+			wc->opcode = map_wc_opcode[cqe->opcode];
+			wc->status = map_cqe_status[cqe->status].ib;
 			siw_dbg_cq(cq,
 				   "idx %u, type %d, flags %2x, id 0x%pK\n",
 				   cq->cq_get % cq->num_cqe, cqe->opcode,
 				   cqe->flags, (void *)(uintptr_t)cqe->id);
+		} else {
+			/*
+			 * A malicious user may set invalid opcode or
+			 * status in the user mmapped CQE array.
+			 * Sanity check and correct values in that case
+			 * to avoid out-of-bounds access to global arrays
+			 * for opcode and status mapping.
+			 */
+			u8 opcode = cqe->opcode;
+			u16 status = cqe->status;
+
+			if (opcode >= SIW_NUM_OPCODES) {
+				opcode = 0;
+				status = SIW_WC_GENERAL_ERR;
+			} else if (status >= SIW_NUM_WC_STATUS) {
+				status = SIW_WC_GENERAL_ERR;
+			}
+			wc->opcode = map_wc_opcode[opcode];
+			wc->status = map_cqe_status[status].ib;
+
 		}
 		WRITE_ONCE(cqe->flags, 0);
 		cq->cq_get++;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_main.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_main.c
@@ -66,12 +66,13 @@
 	static int dev_id = 1;
 	int rv;
 
+	sdev->vendor_part_id = dev_id++;
+
 	rv = ib_register_device(base_dev, name);
 	if (rv) {
 		pr_warn("siw: device registration error %d\n", rv);
 		return rv;
 	}
-	sdev->vendor_part_id = dev_id++;
 
 	siw_dbg(base_dev, "HWaddr=%pM\n", sdev->netdev->dev_addr);
 
@@ -133,7 +134,7 @@
 
 static int siw_init_cpulist(void)
 {
-	int i, num_nodes = num_possible_nodes();
+	int i, num_nodes = nr_node_ids;
 
 	memset(siw_tx_thread, 0, sizeof(siw_tx_thread));
 
@@ -248,24 +249,6 @@
 	return NULL;
 }
 
-static void siw_verbs_sq_flush(struct ib_qp *base_qp)
-{
-	struct siw_qp *qp = to_siw_qp(base_qp);
-
-	down_write(&qp->state_lock);
-	siw_sq_flush(qp);
-	up_write(&qp->state_lock);
-}
-
-static void siw_verbs_rq_flush(struct ib_qp *base_qp)
-{
-	struct siw_qp *qp = to_siw_qp(base_qp);
-
-	down_write(&qp->state_lock);
-	siw_rq_flush(qp);
-	up_write(&qp->state_lock);
-}
-
 static const struct ib_device_ops siw_device_ops = {
 	.owner = THIS_MODULE,
 	.uverbs_abi_ver = SIW_ABI_VERSION,
@@ -284,8 +267,6 @@
 	.destroy_cq = siw_destroy_cq,
 	.destroy_qp = siw_destroy_qp,
 	.destroy_srq = siw_destroy_srq,
-	.drain_rq = siw_verbs_rq_flush,
-	.drain_sq = siw_verbs_sq_flush,
 	.get_dma_mr = siw_get_dma_mr,
 	.get_port_immutable = siw_get_port_immutable,
 	.iw_accept = siw_accept,
@@ -399,6 +380,9 @@
 	base_dev->dev.dma_ops = &dma_virt_ops;
 	base_dev->num_comp_vectors = num_possible_cpus();
 
+	xa_init_flags(&sdev->qp_xa, XA_FLAGS_ALLOC1);
+	xa_init_flags(&sdev->mem_xa, XA_FLAGS_ALLOC1);
+
 	ib_set_device_ops(base_dev, &siw_device_ops);
 	rv = ib_device_set_netdev(base_dev, netdev, 1);
 	if (rv)
@@ -426,9 +410,6 @@
 	sdev->attrs.max_srq_wr = SIW_MAX_SRQ_WR;
 	sdev->attrs.max_srq_sge = SIW_MAX_SGE;
 
-	xa_init_flags(&sdev->qp_xa, XA_FLAGS_ALLOC1);
-	xa_init_flags(&sdev->mem_xa, XA_FLAGS_ALLOC1);
-
 	INIT_LIST_HEAD(&sdev->cep_list);
 	INIT_LIST_HEAD(&sdev->qp_list);
 
@@ -491,9 +472,6 @@
 
 	dev_dbg(&netdev->dev, "siw: event %lu\n", event);
 
-	if (dev_net(netdev) != &init_net)
-		return NOTIFY_OK;
-
 	base_dev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_SIW);
 	if (!base_dev)
 		return NOTIFY_OK;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_mem.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_mem.c
@@ -106,8 +106,6 @@
 	mem->perms = rights & IWARP_ACCESS_MASK;
 	kref_init(&mem->ref);
 
-	mr->mem = mem;
-
 	get_random_bytes(&next, 4);
 	next &= 0x00ffffff;
 
@@ -116,6 +114,8 @@
 		kfree(mem);
 		return -ENOMEM;
 	}
+
+	mr->mem = mem;
 	/* Set the STag index part */
 	mem->stag = id << 8;
 	mr->base_mr.lkey = mr->base_mr.rkey = mem->stag;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_qp.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_qp.c
@@ -199,26 +199,26 @@
 
 static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size)
 {
-	irq_size = roundup_pow_of_two(irq_size);
-	orq_size = roundup_pow_of_two(orq_size);
-
+	if (irq_size) {
+		irq_size = roundup_pow_of_two(irq_size);
+		qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
+		if (!qp->irq) {
+			qp->attrs.irq_size = 0;
+			return -ENOMEM;
+		}
+	}
+	if (orq_size) {
+		orq_size = roundup_pow_of_two(orq_size);
+		qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
+		if (!qp->orq) {
+			qp->attrs.orq_size = 0;
+			qp->attrs.irq_size = 0;
+			vfree(qp->irq);
+			return -ENOMEM;
+		}
+	}
 	qp->attrs.irq_size = irq_size;
 	qp->attrs.orq_size = orq_size;
-
-	qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
-	if (!qp->irq) {
-		siw_dbg_qp(qp, "irq malloc for %d failed\n", irq_size);
-		qp->attrs.irq_size = 0;
-		return -ENOMEM;
-	}
-	qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
-	if (!qp->orq) {
-		siw_dbg_qp(qp, "orq malloc for %d failed\n", orq_size);
-		qp->attrs.orq_size = 0;
-		qp->attrs.irq_size = 0;
-		vfree(qp->irq);
-		return -ENOMEM;
-	}
 	siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size);
 	return 0;
 }
@@ -288,13 +288,14 @@
 	if (ctrl & MPA_V2_RDMA_WRITE_RTR)
 		wqe->sqe.opcode = SIW_OP_WRITE;
 	else if (ctrl & MPA_V2_RDMA_READ_RTR) {
-		struct siw_sqe *rreq;
+		struct siw_sqe *rreq = NULL;
 
 		wqe->sqe.opcode = SIW_OP_READ;
 
 		spin_lock(&qp->orq_lock);
 
-		rreq = orq_get_free(qp);
+		if (qp->attrs.orq_size)
+			rreq = orq_get_free(qp);
 		if (rreq) {
 			siw_read_to_orq(rreq, &wqe->sqe);
 			qp->orq_put++;
@@ -877,135 +878,88 @@
 	rreq->num_sge = 1;
 }
 
-/*
- * Must be called with SQ locked.
- * To avoid complete SQ starvation by constant inbound READ requests,
- * the active IRQ will not be served after qp->irq_burst, if the
- * SQ has pending work.
- */
-int siw_activate_tx(struct siw_qp *qp)
+static int siw_activate_tx_from_sq(struct siw_qp *qp)
 {
-	struct siw_sqe *irqe, *sqe;
+	struct siw_sqe *sqe;
 	struct siw_wqe *wqe = tx_wqe(qp);
 	int rv = 1;
 
-	irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];
-
-	if (irqe->flags & SIW_WQE_VALID) {
-		sqe = sq_get_next(qp);
-
-		/*
-		 * Avoid local WQE processing starvation in case
-		 * of constant inbound READ request stream
-		 */
-		if (sqe && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) {
-			qp->irq_burst = 0;
-			goto skip_irq;
-		}
-		memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
-		wqe->wr_status = SIW_WR_QUEUED;
-
-		/* start READ RESPONSE */
-		wqe->sqe.opcode = SIW_OP_READ_RESPONSE;
-		wqe->sqe.flags = 0;
-		if (irqe->num_sge) {
-			wqe->sqe.num_sge = 1;
-			wqe->sqe.sge[0].length = irqe->sge[0].length;
-			wqe->sqe.sge[0].laddr = irqe->sge[0].laddr;
-			wqe->sqe.sge[0].lkey = irqe->sge[0].lkey;
-		} else {
-			wqe->sqe.num_sge = 0;
-		}
-
-		/* Retain original RREQ's message sequence number for
-		 * potential error reporting cases.
-		 */
-		wqe->sqe.sge[1].length = irqe->sge[1].length;
-
-		wqe->sqe.rkey = irqe->rkey;
-		wqe->sqe.raddr = irqe->raddr;
+	sqe = sq_get_next(qp);
+	if (!sqe)
+		return 0;
 
-		wqe->processed = 0;
-		qp->irq_get++;
+	memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+	wqe->wr_status = SIW_WR_QUEUED;
 
-		/* mark current IRQ entry free */
-		smp_store_mb(irqe->flags, 0);
+	/* First copy SQE to kernel private memory */
+	memcpy(&wqe->sqe, sqe, sizeof(*sqe));
 
+	if (wqe->sqe.opcode >= SIW_NUM_OPCODES) {
+		rv = -EINVAL;
 		goto out;
 	}
-	sqe = sq_get_next(qp);
-	if (sqe) {
-skip_irq:
-		memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
-		wqe->wr_status = SIW_WR_QUEUED;
-
-		/* First copy SQE to kernel private memory */
-		memcpy(&wqe->sqe, sqe, sizeof(*sqe));
-
-		if (wqe->sqe.opcode >= SIW_NUM_OPCODES) {
+	if (wqe->sqe.flags & SIW_WQE_INLINE) {
+		if (wqe->sqe.opcode != SIW_OP_SEND &&
+		    wqe->sqe.opcode != SIW_OP_WRITE) {
 			rv = -EINVAL;
 			goto out;
 		}
-		if (wqe->sqe.flags & SIW_WQE_INLINE) {
-			if (wqe->sqe.opcode != SIW_OP_SEND &&
-			    wqe->sqe.opcode != SIW_OP_WRITE) {
-				rv = -EINVAL;
-				goto out;
-			}
-			if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) {
-				rv = -EINVAL;
-				goto out;
-			}
-			wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
-			wqe->sqe.sge[0].lkey = 0;
-			wqe->sqe.num_sge = 1;
-		}
-		if (wqe->sqe.flags & SIW_WQE_READ_FENCE) {
-			/* A READ cannot be fenced */
-			if (unlikely(wqe->sqe.opcode == SIW_OP_READ ||
-				     wqe->sqe.opcode ==
-					     SIW_OP_READ_LOCAL_INV)) {
-				siw_dbg_qp(qp, "cannot fence read\n");
-				rv = -EINVAL;
-				goto out;
-			}
-			spin_lock(&qp->orq_lock);
+		if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) {
+			rv = -EINVAL;
+			goto out;
+		}
+		wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
+		wqe->sqe.sge[0].lkey = 0;
+		wqe->sqe.num_sge = 1;
+	}
+	if (wqe->sqe.flags & SIW_WQE_READ_FENCE) {
+		/* A READ cannot be fenced */
+		if (unlikely(wqe->sqe.opcode == SIW_OP_READ ||
+			     wqe->sqe.opcode ==
+				     SIW_OP_READ_LOCAL_INV)) {
+			siw_dbg_qp(qp, "cannot fence read\n");
+			rv = -EINVAL;
+			goto out;
+		}
+		spin_lock(&qp->orq_lock);
 
-			if (!siw_orq_empty(qp)) {
-				qp->tx_ctx.orq_fence = 1;
-				rv = 0;
-			}
-			spin_unlock(&qp->orq_lock);
+		if (qp->attrs.orq_size && !siw_orq_empty(qp)) {
+			qp->tx_ctx.orq_fence = 1;
+			rv = 0;
+		}
+		spin_unlock(&qp->orq_lock);
 
-		} else if (wqe->sqe.opcode == SIW_OP_READ ||
-			   wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-			struct siw_sqe *rreq;
+	} else if (wqe->sqe.opcode == SIW_OP_READ ||
+		   wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
+		struct siw_sqe *rreq;
 
-			wqe->sqe.num_sge = 1;
+		if (unlikely(!qp->attrs.orq_size)) {
+			/* We negotiated not to send READ req's */
+			rv = -EINVAL;
+			goto out;
+		}
+		wqe->sqe.num_sge = 1;
 
-			spin_lock(&qp->orq_lock);
+		spin_lock(&qp->orq_lock);
 
-			rreq = orq_get_free(qp);
-			if (rreq) {
-				/*
-				 * Make an immediate copy in ORQ to be ready
-				 * to process loopback READ reply
-				 */
-				siw_read_to_orq(rreq, &wqe->sqe);
-				qp->orq_put++;
-			} else {
-				qp->tx_ctx.orq_fence = 1;
-				rv = 0;
-			}
-			spin_unlock(&qp->orq_lock);
+		rreq = orq_get_free(qp);
+		if (rreq) {
+			/*
+			 * Make an immediate copy in ORQ to be ready
+			 * to process loopback READ reply
+			 */
+			siw_read_to_orq(rreq, &wqe->sqe);
+			qp->orq_put++;
+		} else {
+			qp->tx_ctx.orq_fence = 1;
+			rv = 0;
 		}
-
-		/* Clear SQE, can be re-used by application */
-		smp_store_mb(sqe->flags, 0);
-		qp->sq_get++;
-	} else {
-		rv = 0;
+		spin_unlock(&qp->orq_lock);
 	}
+
+	/* Clear SQE, can be re-used by application */
+	smp_store_mb(sqe->flags, 0);
+	qp->sq_get++;
 out:
 	if (unlikely(rv < 0)) {
 		siw_dbg_qp(qp, "error %d\n", rv);
@@ -1015,6 +969,65 @@
 }
 
 /*
+ * Must be called with SQ locked.
+ * To avoid complete SQ starvation by constant inbound READ requests,
+ * the active IRQ will not be served after qp->irq_burst, if the
+ * SQ has pending work.
+ */
+int siw_activate_tx(struct siw_qp *qp)
+{
+	struct siw_sqe *irqe;
+	struct siw_wqe *wqe = tx_wqe(qp);
+
+	if (!qp->attrs.irq_size)
+		return siw_activate_tx_from_sq(qp);
+
+	irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];
+
+	if (!(irqe->flags & SIW_WQE_VALID))
+		return siw_activate_tx_from_sq(qp);
+
+	/*
+	 * Avoid local WQE processing starvation in case
+	 * of constant inbound READ request stream
+	 */
+	if (sq_get_next(qp) && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) {
+		qp->irq_burst = 0;
+		return siw_activate_tx_from_sq(qp);
+	}
+	memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+	wqe->wr_status = SIW_WR_QUEUED;
+
+	/* start READ RESPONSE */
+	wqe->sqe.opcode = SIW_OP_READ_RESPONSE;
+	wqe->sqe.flags = 0;
+	if (irqe->num_sge) {
+		wqe->sqe.num_sge = 1;
+		wqe->sqe.sge[0].length = irqe->sge[0].length;
+		wqe->sqe.sge[0].laddr = irqe->sge[0].laddr;
+		wqe->sqe.sge[0].lkey = irqe->sge[0].lkey;
+	} else {
+		wqe->sqe.num_sge = 0;
+	}
+
+	/* Retain original RREQ's message sequence number for
+	 * potential error reporting cases.
+	 */
+	wqe->sqe.sge[1].length = irqe->sge[1].length;
+
+	wqe->sqe.rkey = irqe->rkey;
+	wqe->sqe.raddr = irqe->raddr;
+
+	wqe->processed = 0;
+	qp->irq_get++;
+
+	/* mark current IRQ entry free */
+	smp_store_mb(irqe->flags, 0);
+
+	return 1;
+}
+
+/*
  * Check if current CQ state qualifies for calling CQ completion
  * handler. Must be called with CQ lock held.
  */
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_qp_rx.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_qp_rx.c
@@ -139,7 +139,8 @@
 			break;
 
 		bytes = min(bytes, len);
-		if (siw_rx_kva(srx, (void *)buf_addr, bytes) == bytes) {
+		if (siw_rx_kva(srx, (void *)(uintptr_t)buf_addr, bytes) ==
+		    bytes) {
 			copied += bytes;
 			offset += bytes;
 			len -= bytes;
@@ -679,6 +680,10 @@
 	}
 	spin_lock_irqsave(&qp->sq_lock, flags);
 
+	if (unlikely(!qp->attrs.irq_size)) {
+		run_sq = 0;
+		goto error_irq;
+	}
 	if (tx_work->wr_status == SIW_WR_IDLE) {
 		/*
 		 * immediately schedule READ response w/o
@@ -711,8 +716,9 @@
 		/* RRESP now valid as current TX wqe or placed into IRQ */
 		smp_store_mb(resp->flags, SIW_WQE_VALID);
 	} else {
-		pr_warn("siw: [QP %u]: irq %d exceeded %d\n", qp_id(qp),
-			qp->irq_put % qp->attrs.irq_size, qp->attrs.irq_size);
+error_irq:
+		pr_warn("siw: [QP %u]: IRQ exceeded or null, size %d\n",
+			qp_id(qp), qp->attrs.irq_size);
 
 		siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
 				   RDMAP_ETYPE_REMOTE_OPERATION,
@@ -739,6 +745,9 @@
 	struct siw_sqe *orqe;
 	struct siw_wqe *wqe = NULL;
 
+	if (unlikely(!qp->attrs.orq_size))
+		return -EPROTO;
+
 	/* make sure ORQ indices are current */
 	smp_mb();
 
@@ -795,8 +804,8 @@
 		 */
 		rv = siw_orqe_start_rx(qp);
 		if (rv) {
-			pr_warn("siw: [QP %u]: ORQ empty at idx %d\n",
-				qp_id(qp), qp->orq_get % qp->attrs.orq_size);
+			pr_warn("siw: [QP %u]: ORQ empty, size %d\n",
+				qp_id(qp), qp->attrs.orq_size);
 			goto error_term;
 		}
 		rv = siw_rresp_check_ntoh(srx, frx);
@@ -952,27 +961,28 @@
 static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx)
 {
 	struct sk_buff *skb = srx->skb;
+	int avail = min(srx->skb_new, srx->fpdu_part_rem);
 	u8 *tbuf = (u8 *)&srx->trailer.crc - srx->pad;
 	__wsum crc_in, crc_own = 0;
 
 	siw_dbg_qp(qp, "expected %d, available %d, pad %u\n",
 		   srx->fpdu_part_rem, srx->skb_new, srx->pad);
 
-	if (srx->skb_new < srx->fpdu_part_rem)
-		return -EAGAIN;
-
-	skb_copy_bits(skb, srx->skb_offset, tbuf, srx->fpdu_part_rem);
+	skb_copy_bits(skb, srx->skb_offset, tbuf, avail);
 
-	if (srx->mpa_crc_hd && srx->pad)
-		crypto_shash_update(srx->mpa_crc_hd, tbuf, srx->pad);
+	srx->skb_new -= avail;
+	srx->skb_offset += avail;
+	srx->skb_copied += avail;
+	srx->fpdu_part_rem -= avail;
 
-	srx->skb_new -= srx->fpdu_part_rem;
-	srx->skb_offset += srx->fpdu_part_rem;
-	srx->skb_copied += srx->fpdu_part_rem;
+	if (srx->fpdu_part_rem)
+		return -EAGAIN;
 
 	if (!srx->mpa_crc_hd)
 		return 0;
 
+	if (srx->pad)
+		crypto_shash_update(srx->mpa_crc_hd, tbuf, srx->pad);
 	/*
 	 * CRC32 is computed, transmitted and received directly in NBO,
 	 * so there's never a reason to convert byte order.
@@ -1074,10 +1084,9 @@
 	 * completely received.
 	 */
 	if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) {
-		bytes = iwarp_pktinfo[opcode].hdr_len - MIN_DDP_HDR;
+		int hdrlen = iwarp_pktinfo[opcode].hdr_len;
 
-		if (srx->skb_new < bytes)
-			return -EAGAIN;
+		bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new);
 
 		skb_copy_bits(skb, srx->skb_offset,
 			      (char *)c_hdr + srx->fpdu_part_rcvd, bytes);
@@ -1087,6 +1096,9 @@
 		srx->skb_new -= bytes;
 		srx->skb_offset += bytes;
 		srx->skb_copied += bytes;
+
+		if (srx->fpdu_part_rcvd < hdrlen)
+			return -EAGAIN;
 	}
 
 	/*
@@ -1144,11 +1156,12 @@
 
 	spin_lock_irqsave(&qp->orq_lock, flags);
 
-	rreq = orq_get_current(qp);
-
 	/* free current orq entry */
+	rreq = orq_get_current(qp);
 	WRITE_ONCE(rreq->flags, 0);
 
+	qp->orq_get++;
+
 	if (qp->tx_ctx.orq_fence) {
 		if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
 			pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
@@ -1156,10 +1169,12 @@
 			rv = -EPROTO;
 			goto out;
 		}
-		/* resume SQ processing */
+		/* resume SQ processing, if possible */
 		if (tx_waiting->sqe.opcode == SIW_OP_READ ||
 		    tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-			rreq = orq_get_tail(qp);
+
+			/* SQ processing was stopped because of a full ORQ */
+			rreq = orq_get_free(qp);
 			if (unlikely(!rreq)) {
 				pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
 				rv = -EPROTO;
@@ -1172,15 +1187,14 @@
 			resume_tx = 1;
 
 		} else if (siw_orq_empty(qp)) {
+			/*
+			 * SQ processing was stopped by fenced work request.
+			 * Resume since all previous Read's are now completed.
+			 */
 			qp->tx_ctx.orq_fence = 0;
 			resume_tx = 1;
-		} else {
-			pr_warn("siw: [QP %u]: fence resume: orq idx: %d:%d\n",
-				qp_id(qp), qp->orq_get, qp->orq_put);
-			rv = -EPROTO;
 		}
 	}
-	qp->orq_get++;
 out:
 	spin_unlock_irqrestore(&qp->orq_lock, flags);
 
@@ -1289,11 +1303,13 @@
 					      wc_status);
 		siw_wqe_put_mem(wqe, SIW_OP_READ);
 
-		if (!error)
+		if (!error) {
 			rv = siw_check_tx_fence(qp);
-		else
-			/* Disable current ORQ eleement */
-			WRITE_ONCE(orq_get_current(qp)->flags, 0);
+		} else {
+			/* Disable current ORQ element */
+			if (qp->attrs.orq_size)
+				WRITE_ONCE(orq_get_current(qp)->flags, 0);
+		}
 		break;
 
 	case RDMAP_RDMA_READ_REQ:
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_qp_tx.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_qp_tx.c
@@ -29,7 +29,7 @@
 	dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
 
 	if (paddr)
-		return virt_to_page(paddr);
+		return virt_to_page((void *)(uintptr_t)paddr);
 
 	return NULL;
 }
@@ -523,13 +523,23 @@
 					kunmap(p);
 				}
 			} else {
-				u64 va = sge->laddr + sge_off;
+				/*
+				 * Cast to an uintptr_t to preserve all 64 bits
+				 * in sge->laddr.
+				 */
+				uintptr_t va = (uintptr_t)(sge->laddr + sge_off);
 
-				page_array[seg] = virt_to_page(va & PAGE_MASK);
+				/*
+				 * virt_to_page() takes a (void *) pointer
+				 * so cast to a (void *) meaning it will be 64
+				 * bits on a 64 bit platform and 32 bits on a
+				 * 32 bit platform.
+				 */
+				page_array[seg] = virt_to_page((void *)(va & PAGE_MASK));
 				if (do_crc)
 					crypto_shash_update(
 						c_tx->mpa_crc_hd,
-						(void *)(uintptr_t)va,
+						(void *)va,
 						plen);
 			}
 
@@ -538,7 +548,7 @@
 			data_len -= plen;
 			fp_off = 0;
 
-			if (++seg > (int)MAX_ARRAY) {
+			if (++seg >= (int)MAX_ARRAY) {
 				siw_dbg_qp(tx_qp(c_tx), "to many fragments\n");
 				siw_unmap_pages(page_array, kmap_mask);
 				wqe->processed -= c_tx->bytes_unsent;
@@ -920,20 +930,27 @@
 {
 	struct ib_mr *base_mr = (struct ib_mr *)(uintptr_t)sqe->base_mr;
 	struct siw_device *sdev = to_siw_dev(pd->device);
-	struct siw_mem *mem = siw_mem_id2obj(sdev, sqe->rkey  >> 8);
+	struct siw_mem *mem;
 	int rv = 0;
 
 	siw_dbg_pd(pd, "STag 0x%08x\n", sqe->rkey);
 
-	if (unlikely(!mem || !base_mr)) {
+	if (unlikely(!base_mr)) {
 		pr_warn("siw: fastreg: STag 0x%08x unknown\n", sqe->rkey);
 		return -EINVAL;
 	}
+
 	if (unlikely(base_mr->rkey >> 8 != sqe->rkey  >> 8)) {
 		pr_warn("siw: fastreg: STag 0x%08x: bad MR\n", sqe->rkey);
-		rv = -EINVAL;
-		goto out;
+		return -EINVAL;
+	}
+
+	mem = siw_mem_id2obj(sdev, sqe->rkey  >> 8);
+	if (unlikely(!mem)) {
+		pr_warn("siw: fastreg: STag 0x%08x unknown\n", sqe->rkey);
+		return -EINVAL;
 	}
+
 	if (unlikely(mem->pd != pd)) {
 		pr_warn("siw: fastreg: PD mismatch\n");
 		rv = -EINVAL;
@@ -1100,8 +1117,8 @@
 		/*
 		 * RREQ may have already been completed by inbound RRESP!
 		 */
-		if (tx_type == SIW_OP_READ ||
-		    tx_type == SIW_OP_READ_LOCAL_INV) {
+		if ((tx_type == SIW_OP_READ ||
+		     tx_type == SIW_OP_READ_LOCAL_INV) && qp->attrs.orq_size) {
 			/* Cleanup pending entry in ORQ */
 			qp->orq_put--;
 			qp->orq[qp->orq_put % qp->attrs.orq_size].flags = 0;
--- linux-ein-5.4.0.orig/drivers/infiniband/sw/siw/siw_verbs.c
+++ linux-ein-5.4.0/drivers/infiniband/sw/siw/siw_verbs.c
@@ -314,7 +314,6 @@
 	struct siw_ucontext *uctx =
 		rdma_udata_to_drv_context(udata, struct siw_ucontext,
 					  base_ucontext);
-	struct siw_cq *scq = NULL, *rcq = NULL;
 	unsigned long flags;
 	int num_sqe, num_rqe, rv = 0;
 
@@ -353,10 +352,8 @@
 		rv = -EINVAL;
 		goto err_out;
 	}
-	scq = to_siw_cq(attrs->send_cq);
-	rcq = to_siw_cq(attrs->recv_cq);
 
-	if (!scq || (!rcq && !attrs->srq)) {
+	if (!attrs->send_cq || (!attrs->recv_cq && !attrs->srq)) {
 		siw_dbg(base_dev, "send CQ or receive CQ invalid\n");
 		rv = -EINVAL;
 		goto err_out;
@@ -387,13 +384,23 @@
 	if (rv)
 		goto err_out;
 
+	num_sqe = attrs->cap.max_send_wr;
+	num_rqe = attrs->cap.max_recv_wr;
+
 	/* All queue indices are derived from modulo operations
 	 * on a free running 'get' (consumer) and 'put' (producer)
 	 * unsigned counter. Having queue sizes at power of two
 	 * avoids handling counter wrap around.
 	 */
-	num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
-	num_rqe = roundup_pow_of_two(attrs->cap.max_recv_wr);
+	if (num_sqe)
+		num_sqe = roundup_pow_of_two(num_sqe);
+	else {
+		/* Zero sized SQ is not supported */
+		rv = -EINVAL;
+		goto err_out_xa;
+	}
+	if (num_rqe)
+		num_rqe = roundup_pow_of_two(num_rqe);
 
 	if (qp->kernel_verbs)
 		qp->sendq = vzalloc(num_sqe * sizeof(struct siw_sqe));
@@ -401,7 +408,6 @@
 		qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe));
 
 	if (qp->sendq == NULL) {
-		siw_dbg(base_dev, "SQ size %d alloc failed\n", num_sqe);
 		rv = -ENOMEM;
 		goto err_out_xa;
 	}
@@ -414,8 +420,8 @@
 		}
 	}
 	qp->pd = pd;
-	qp->scq = scq;
-	qp->rcq = rcq;
+	qp->scq = to_siw_cq(attrs->send_cq);
+	qp->rcq = to_siw_cq(attrs->recv_cq);
 
 	if (attrs->srq) {
 		/*
@@ -434,7 +440,6 @@
 				vmalloc_user(num_rqe * sizeof(struct siw_rqe));
 
 		if (qp->recvq == NULL) {
-			siw_dbg(base_dev, "RQ size %d alloc failed\n", num_rqe);
 			rv = -ENOMEM;
 			goto err_out_xa;
 		}
@@ -685,6 +690,79 @@
 	return bytes;
 }
 
+/* Complete SQ WR's without processing */
+static int siw_sq_flush_wr(struct siw_qp *qp, const struct ib_send_wr *wr,
+			   const struct ib_send_wr **bad_wr)
+{
+	int rv = 0;
+
+	while (wr) {
+		struct siw_sqe sqe = {};
+
+		switch (wr->opcode) {
+		case IB_WR_RDMA_WRITE:
+			sqe.opcode = SIW_OP_WRITE;
+			break;
+		case IB_WR_RDMA_READ:
+			sqe.opcode = SIW_OP_READ;
+			break;
+		case IB_WR_RDMA_READ_WITH_INV:
+			sqe.opcode = SIW_OP_READ_LOCAL_INV;
+			break;
+		case IB_WR_SEND:
+			sqe.opcode = SIW_OP_SEND;
+			break;
+		case IB_WR_SEND_WITH_IMM:
+			sqe.opcode = SIW_OP_SEND_WITH_IMM;
+			break;
+		case IB_WR_SEND_WITH_INV:
+			sqe.opcode = SIW_OP_SEND_REMOTE_INV;
+			break;
+		case IB_WR_LOCAL_INV:
+			sqe.opcode = SIW_OP_INVAL_STAG;
+			break;
+		case IB_WR_REG_MR:
+			sqe.opcode = SIW_OP_REG_MR;
+			break;
+		default:
+			rv = -EINVAL;
+			break;
+		}
+		if (!rv) {
+			sqe.id = wr->wr_id;
+			rv = siw_sqe_complete(qp, &sqe, 0,
+					      SIW_WC_WR_FLUSH_ERR);
+		}
+		if (rv) {
+			if (bad_wr)
+				*bad_wr = wr;
+			break;
+		}
+		wr = wr->next;
+	}
+	return rv;
+}
+
+/* Complete RQ WR's without processing */
+static int siw_rq_flush_wr(struct siw_qp *qp, const struct ib_recv_wr *wr,
+			   const struct ib_recv_wr **bad_wr)
+{
+	struct siw_rqe rqe = {};
+	int rv = 0;
+
+	while (wr) {
+		rqe.id = wr->wr_id;
+		rv = siw_rqe_complete(qp, &rqe, 0, 0, SIW_WC_WR_FLUSH_ERR);
+		if (rv) {
+			if (bad_wr)
+				*bad_wr = wr;
+			break;
+		}
+		wr = wr->next;
+	}
+	return rv;
+}
+
 /*
  * siw_post_send()
  *
@@ -703,26 +781,54 @@
 	unsigned long flags;
 	int rv = 0;
 
+	if (wr && !qp->kernel_verbs) {
+		siw_dbg_qp(qp, "wr must be empty for user mapped sq\n");
+		*bad_wr = wr;
+		return -EINVAL;
+	}
+
 	/*
 	 * Try to acquire QP state lock. Must be non-blocking
 	 * to accommodate kernel clients needs.
 	 */
 	if (!down_read_trylock(&qp->state_lock)) {
-		*bad_wr = wr;
-		siw_dbg_qp(qp, "QP locked, state %d\n", qp->attrs.state);
-		return -ENOTCONN;
+		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
+			/*
+			 * ERROR state is final, so we can be sure
+			 * this state will not change as long as the QP
+			 * exists.
+			 *
+			 * This handles an ib_drain_sq() call with
+			 * a concurrent request to set the QP state
+			 * to ERROR.
+			 */
+			rv = siw_sq_flush_wr(qp, wr, bad_wr);
+		} else {
+			siw_dbg_qp(qp, "QP locked, state %d\n",
+				   qp->attrs.state);
+			*bad_wr = wr;
+			rv = -ENOTCONN;
+		}
+		return rv;
 	}
 	if (unlikely(qp->attrs.state != SIW_QP_STATE_RTS)) {
+		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
+			/*
+			 * Immediately flush this WR to CQ, if QP
+			 * is in ERROR state. SQ is guaranteed to
+			 * be empty, so WR complets in-order.
+			 *
+			 * Typically triggered by ib_drain_sq().
+			 */
+			rv = siw_sq_flush_wr(qp, wr, bad_wr);
+		} else {
+			siw_dbg_qp(qp, "QP out of state %d\n",
+				   qp->attrs.state);
+			*bad_wr = wr;
+			rv = -ENOTCONN;
+		}
 		up_read(&qp->state_lock);
-		*bad_wr = wr;
-		siw_dbg_qp(qp, "QP out of state %d\n", qp->attrs.state);
-		return -ENOTCONN;
-	}
-	if (wr && !qp->kernel_verbs) {
-		siw_dbg_qp(qp, "wr must be empty for user mapped sq\n");
-		up_read(&qp->state_lock);
-		*bad_wr = wr;
-		return -EINVAL;
+		return rv;
 	}
 	spin_lock_irqsave(&qp->sq_lock, flags);
 
@@ -913,28 +1019,58 @@
 	unsigned long flags;
 	int rv = 0;
 
-	if (qp->srq) {
+	if (qp->srq || qp->attrs.rq_size == 0) {
 		*bad_wr = wr;
-		return -EOPNOTSUPP; /* what else from errno.h? */
+		return -EINVAL;
+	}
+	if (!qp->kernel_verbs) {
+		siw_dbg_qp(qp, "no kernel post_recv for user mapped sq\n");
+		*bad_wr = wr;
+		return -EINVAL;
 	}
+
 	/*
 	 * Try to acquire QP state lock. Must be non-blocking
 	 * to accommodate kernel clients needs.
 	 */
 	if (!down_read_trylock(&qp->state_lock)) {
-		*bad_wr = wr;
-		return -ENOTCONN;
-	}
-	if (!qp->kernel_verbs) {
-		siw_dbg_qp(qp, "no kernel post_recv for user mapped sq\n");
-		up_read(&qp->state_lock);
-		*bad_wr = wr;
-		return -EINVAL;
+		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
+			/*
+			 * ERROR state is final, so we can be sure
+			 * this state will not change as long as the QP
+			 * exists.
+			 *
+			 * This handles an ib_drain_rq() call with
+			 * a concurrent request to set the QP state
+			 * to ERROR.
+			 */
+			rv = siw_rq_flush_wr(qp, wr, bad_wr);
+		} else {
+			siw_dbg_qp(qp, "QP locked, state %d\n",
+				   qp->attrs.state);
+			*bad_wr = wr;
+			rv = -ENOTCONN;
+		}
+		return rv;
 	}
 	if (qp->attrs.state > SIW_QP_STATE_RTS) {
+		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
+			/*
+			 * Immediately flush this WR to CQ, if QP
+			 * is in ERROR state. RQ is guaranteed to
+			 * be empty, so WR complets in-order.
+			 *
+			 * Typically triggered by ib_drain_rq().
+			 */
+			rv = siw_rq_flush_wr(qp, wr, bad_wr);
+		} else {
+			siw_dbg_qp(qp, "QP out of state %d\n",
+				   qp->attrs.state);
+			*bad_wr = wr;
+			rv = -ENOTCONN;
+		}
 		up_read(&qp->state_lock);
-		*bad_wr = wr;
-		return -EINVAL;
+		return rv;
 	}
 	/*
 	 * Serialize potentially multiple producers.
@@ -1373,7 +1509,7 @@
 
 	if (pbl->max_buf < num_sle) {
 		siw_dbg_mem(mem, "too many SGE's: %d > %d\n",
-			    mem->pbl->max_buf, num_sle);
+			    num_sle, pbl->max_buf);
 		return -ENOMEM;
 	}
 	for_each_sg(sl, slp, num_sle, i) {
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib.h
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -377,8 +377,12 @@
 	struct ipoib_rx_buf *rx_ring;
 
 	struct ipoib_tx_buf *tx_ring;
+	/* cyclic ring variables for managing tx_ring, for UD only */
 	unsigned int	     tx_head;
 	unsigned int	     tx_tail;
+	/* cyclic ring variables for counting overall outstanding send WRs */
+	unsigned int	     global_tx_head;
+	unsigned int	     global_tx_tail;
 	struct ib_sge	     tx_sge[MAX_SKB_FRAGS + 1];
 	struct ib_ud_wr      tx_wr;
 	struct ib_wc	     send_wc[MAX_SEND_CQE];
@@ -511,7 +515,7 @@
 
 int ipoib_ib_dev_open_default(struct net_device *dev);
 int ipoib_ib_dev_open(struct net_device *dev);
-int ipoib_ib_dev_stop(struct net_device *dev);
+void ipoib_ib_dev_stop(struct net_device *dev);
 void ipoib_ib_dev_up(struct net_device *dev);
 void ipoib_ib_dev_down(struct net_device *dev);
 int ipoib_ib_dev_stop_default(struct net_device *dev);
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -756,7 +756,8 @@
 		return;
 	}
 
-	if ((priv->tx_head - priv->tx_tail) == ipoib_sendq_size - 1) {
+	if ((priv->global_tx_head - priv->global_tx_tail) ==
+	    ipoib_sendq_size - 1) {
 		ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
 			  tx->qp->qp_num);
 		netif_stop_queue(dev);
@@ -786,7 +787,7 @@
 	} else {
 		netif_trans_update(dev);
 		++tx->tx_head;
-		++priv->tx_head;
+		++priv->global_tx_head;
 	}
 }
 
@@ -820,10 +821,11 @@
 	netif_tx_lock(dev);
 
 	++tx->tx_tail;
-	++priv->tx_tail;
+	++priv->global_tx_tail;
 
 	if (unlikely(netif_queue_stopped(dev) &&
-		     (priv->tx_head - priv->tx_tail) <= ipoib_sendq_size >> 1 &&
+		     ((priv->global_tx_head - priv->global_tx_tail) <=
+		      ipoib_sendq_size >> 1) &&
 		     test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
 		netif_wake_queue(dev);
 
@@ -1232,8 +1234,9 @@
 		dev_kfree_skb_any(tx_req->skb);
 		netif_tx_lock_bh(p->dev);
 		++p->tx_tail;
-		++priv->tx_tail;
-		if (unlikely(priv->tx_head - priv->tx_tail == ipoib_sendq_size >> 1) &&
+		++priv->global_tx_tail;
+		if (unlikely((priv->global_tx_head - priv->global_tx_tail) <=
+			     ipoib_sendq_size >> 1) &&
 		    netif_queue_stopped(p->dev) &&
 		    test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
 			netif_wake_queue(p->dev);
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -407,9 +407,11 @@
 	dev_kfree_skb_any(tx_req->skb);
 
 	++priv->tx_tail;
+	++priv->global_tx_tail;
 
 	if (unlikely(netif_queue_stopped(dev) &&
-		     ((priv->tx_head - priv->tx_tail) <= ipoib_sendq_size >> 1) &&
+		     ((priv->global_tx_head - priv->global_tx_tail) <=
+		      ipoib_sendq_size >> 1) &&
 		     test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
 		netif_wake_queue(dev);
 
@@ -634,7 +636,8 @@
 	else
 		priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
 	/* increase the tx_head after send success, but use it for queue state */
-	if (priv->tx_head - priv->tx_tail == ipoib_sendq_size - 1) {
+	if ((priv->global_tx_head - priv->global_tx_tail) ==
+	    ipoib_sendq_size - 1) {
 		ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
 		netif_stop_queue(dev);
 	}
@@ -662,17 +665,17 @@
 
 		rc = priv->tx_head;
 		++priv->tx_head;
+		++priv->global_tx_head;
 	}
 	return rc;
 }
 
-static void __ipoib_reap_ah(struct net_device *dev)
+static void ipoib_reap_dead_ahs(struct ipoib_dev_priv *priv)
 {
-	struct ipoib_dev_priv *priv = ipoib_priv(dev);
 	struct ipoib_ah *ah, *tah;
 	unsigned long flags;
 
-	netif_tx_lock_bh(dev);
+	netif_tx_lock_bh(priv->dev);
 	spin_lock_irqsave(&priv->lock, flags);
 
 	list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
@@ -683,37 +686,37 @@
 		}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
-	netif_tx_unlock_bh(dev);
+	netif_tx_unlock_bh(priv->dev);
 }
 
 void ipoib_reap_ah(struct work_struct *work)
 {
 	struct ipoib_dev_priv *priv =
 		container_of(work, struct ipoib_dev_priv, ah_reap_task.work);
-	struct net_device *dev = priv->dev;
 
-	__ipoib_reap_ah(dev);
+	ipoib_reap_dead_ahs(priv);
 
 	if (!test_bit(IPOIB_STOP_REAPER, &priv->flags))
 		queue_delayed_work(priv->wq, &priv->ah_reap_task,
 				   round_jiffies_relative(HZ));
 }
 
-static void ipoib_flush_ah(struct net_device *dev)
+static void ipoib_start_ah_reaper(struct ipoib_dev_priv *priv)
 {
-	struct ipoib_dev_priv *priv = ipoib_priv(dev);
-
-	cancel_delayed_work(&priv->ah_reap_task);
-	flush_workqueue(priv->wq);
-	ipoib_reap_ah(&priv->ah_reap_task.work);
+	clear_bit(IPOIB_STOP_REAPER, &priv->flags);
+	queue_delayed_work(priv->wq, &priv->ah_reap_task,
+			   round_jiffies_relative(HZ));
 }
 
-static void ipoib_stop_ah(struct net_device *dev)
+static void ipoib_stop_ah_reaper(struct ipoib_dev_priv *priv)
 {
-	struct ipoib_dev_priv *priv = ipoib_priv(dev);
-
 	set_bit(IPOIB_STOP_REAPER, &priv->flags);
-	ipoib_flush_ah(dev);
+	cancel_delayed_work(&priv->ah_reap_task);
+	/*
+	 * After ipoib_stop_ah_reaper() we always go through
+	 * ipoib_reap_dead_ahs() which ensures the work is really stopped and
+	 * does a final flush out of the dead_ah's list
+	 */
 }
 
 static int recvs_pending(struct net_device *dev)
@@ -807,6 +810,7 @@
 				ipoib_dma_unmap_tx(priv, tx_req);
 				dev_kfree_skb_any(tx_req->skb);
 				++priv->tx_tail;
+				++priv->global_tx_tail;
 			}
 
 			for (i = 0; i < ipoib_recvq_size; ++i) {
@@ -841,18 +845,6 @@
 	return 0;
 }
 
-int ipoib_ib_dev_stop(struct net_device *dev)
-{
-	struct ipoib_dev_priv *priv = ipoib_priv(dev);
-
-	priv->rn_ops->ndo_stop(dev);
-
-	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
-	ipoib_flush_ah(dev);
-
-	return 0;
-}
-
 int ipoib_ib_dev_open_default(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = ipoib_priv(dev);
@@ -896,10 +888,7 @@
 		return -1;
 	}
 
-	clear_bit(IPOIB_STOP_REAPER, &priv->flags);
-	queue_delayed_work(priv->wq, &priv->ah_reap_task,
-			   round_jiffies_relative(HZ));
-
+	ipoib_start_ah_reaper(priv);
 	if (priv->rn_ops->ndo_open(dev)) {
 		pr_warn("%s: Failed to open dev\n", dev->name);
 		goto dev_stop;
@@ -910,13 +899,20 @@
 	return 0;
 
 dev_stop:
-	set_bit(IPOIB_STOP_REAPER, &priv->flags);
-	cancel_delayed_work(&priv->ah_reap_task);
-	set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
-	ipoib_ib_dev_stop(dev);
+	ipoib_stop_ah_reaper(priv);
 	return -1;
 }
 
+void ipoib_ib_dev_stop(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = ipoib_priv(dev);
+
+	priv->rn_ops->ndo_stop(dev);
+
+	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+	ipoib_stop_ah_reaper(priv);
+}
+
 void ipoib_pkey_dev_check_presence(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = ipoib_priv(dev);
@@ -1227,7 +1223,7 @@
 		ipoib_mcast_dev_flush(dev);
 		if (oper_up)
 			set_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
-		ipoib_flush_ah(dev);
+		ipoib_reap_dead_ahs(priv);
 	}
 
 	if (level >= IPOIB_FLUSH_NORMAL)
@@ -1302,7 +1298,7 @@
 	 * the neighbor garbage collection is stopped and reaped.
 	 * That should all be done now, so make a final ah flush.
 	 */
-	ipoib_stop_ah(dev);
+	ipoib_reap_dead_ahs(priv);
 
 	clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
 
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1188,9 +1188,11 @@
 
 	ipoib_warn(priv, "transmit timeout: latency %d msecs\n",
 		   jiffies_to_msecs(jiffies - dev_trans_start(dev)));
-	ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n",
-		   netif_queue_stopped(dev),
-		   priv->tx_head, priv->tx_tail);
+	ipoib_warn(priv,
+		   "queue stopped %d, tx_head %u, tx_tail %u, global_tx_head %u, global_tx_tail %u\n",
+		   netif_queue_stopped(dev), priv->tx_head, priv->tx_tail,
+		   priv->global_tx_head, priv->global_tx_tail);
+
 	/* XXX reset QP, etc. */
 }
 
@@ -1705,7 +1707,7 @@
 		goto out_rx_ring_cleanup;
 	}
 
-	/* priv->tx_head, tx_tail & tx_outstanding are already 0 */
+	/* priv->tx_head, tx_tail and global_tx_tail/head are already 0 */
 
 	if (ipoib_transport_dev_init(dev, priv->ca)) {
 		pr_warn("%s: ipoib_transport_dev_init failed\n",
@@ -1977,6 +1979,8 @@
 
 	/* no more works over the priv->wq */
 	if (priv->wq) {
+		/* See ipoib_mcast_carrier_on_task() */
+		WARN_ON(test_bit(IPOIB_FLAG_OPER_UP, &priv->flags));
 		flush_workqueue(priv->wq);
 		destroy_workqueue(priv->wq);
 		priv->wq = NULL;
@@ -2167,6 +2171,14 @@
 		rn->attach_mcast = ipoib_mcast_attach;
 		rn->detach_mcast = ipoib_mcast_detach;
 		rn->hca = hca;
+
+		rc = netif_set_real_num_tx_queues(dev, 1);
+		if (rc)
+			goto out;
+
+		rc = netif_set_real_num_rx_queues(dev, 1);
+		if (rc)
+			goto out;
 	}
 
 	priv->rn_ops = dev->netdev_ops;
@@ -2459,6 +2471,8 @@
 	/* call event handler to ensure pkey in sync */
 	queue_work(ipoib_workqueue, &priv->flush_heavy);
 
+	ndev->rtnl_link_ops = ipoib_get_link_ops();
+
 	result = register_netdev(ndev);
 	if (result) {
 		pr_warn("%s: couldn't register ipoib port %d; error %d\n",
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -543,21 +543,18 @@
 			/* SM supports sendonly-fullmember, otherwise fallback to full-member */
 			rec.join_state = SENDONLY_FULLMEMBER_JOIN;
 	}
-	spin_unlock_irq(&priv->lock);
 
 	multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
-					 &rec, comp_mask, GFP_KERNEL,
+					 &rec, comp_mask, GFP_ATOMIC,
 					 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);
 		/* 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 ret;
 	}
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -42,6 +42,11 @@
 	[IFLA_IPOIB_UMCAST]	= { .type = NLA_U16 },
 };
 
+static unsigned int ipoib_get_max_num_queues(void)
+{
+	return min_t(unsigned int, num_possible_cpus(), 128);
+}
+
 static int ipoib_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = ipoib_priv(dev);
@@ -144,6 +149,16 @@
 	return 0;
 }
 
+static void ipoib_del_child_link(struct net_device *dev, struct list_head *head)
+{
+	struct ipoib_dev_priv *priv = ipoib_priv(dev);
+
+	if (!priv->parent)
+		return;
+
+	unregister_netdevice_queue(dev, head);
+}
+
 static size_t ipoib_get_size(const struct net_device *dev)
 {
 	return nla_total_size(2) +	/* IFLA_IPOIB_PKEY   */
@@ -153,14 +168,18 @@
 
 static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
 	.kind		= "ipoib",
+	.netns_refund   = true,
 	.maxtype	= IFLA_IPOIB_MAX,
 	.policy		= ipoib_policy,
 	.priv_size	= sizeof(struct ipoib_dev_priv),
 	.setup		= ipoib_setup_common,
 	.newlink	= ipoib_new_child_link,
+	.dellink	= ipoib_del_child_link,
 	.changelink	= ipoib_changelink,
 	.get_size	= ipoib_get_size,
 	.fill_info	= ipoib_fill_info,
+	.get_num_rx_queues = ipoib_get_max_num_queues,
+	.get_num_tx_queues = ipoib_get_max_num_queues,
 };
 
 struct rtnl_link_ops *ipoib_get_link_ops(void)
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -192,6 +192,8 @@
 	}
 	priv = ipoib_priv(ndev);
 
+	ndev->rtnl_link_ops = ipoib_get_link_ops();
+
 	result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
 
 	if (result && ndev->reg_state == NETREG_UNINITIALIZED)
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -646,6 +646,7 @@
 		if (ib_conn->pi_support) {
 			u32 sig_caps = ib_dev->attrs.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-ein-5.4.0.orig/drivers/infiniband/ulp/iser/iser_memory.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/iser/iser_memory.c
@@ -292,12 +292,27 @@
 {
 	struct iser_device *device = iser_task->iser_conn->ib_conn.device;
 	struct iser_mem_reg *reg = &iser_task->rdma_reg[cmd_dir];
+	struct iser_fr_desc *desc;
+	struct ib_mr_status mr_status;
 
-	if (!reg->mem_h)
+	desc = reg->mem_h;
+	if (!desc)
 		return;
 
-	device->reg_ops->reg_desc_put(&iser_task->iser_conn->ib_conn,
-				     reg->mem_h);
+	/*
+	 * The signature MR cannot be invalidated and reused without checking.
+	 * libiscsi calls the check_protection transport handler only if
+	 * SCSI-Response is received. And the signature MR is not checked if
+	 * the task is completed for some other reason like a timeout or error
+	 * handling. That's why we must check the signature MR here before
+	 * putting it to the free pool.
+	 */
+	if (unlikely(desc->sig_protected)) {
+		desc->sig_protected = false;
+		ib_check_mr_status(desc->rsc.sig_mr, IB_MR_CHECK_SIG_STATUS,
+				   &mr_status);
+	}
+	device->reg_ops->reg_desc_put(&iser_task->iser_conn->ib_conn, desc);
 	reg->mem_h = NULL;
 }
 
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/isert/ib_isert.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/isert/ib_isert.c
@@ -182,15 +182,15 @@
 	rx_desc = isert_conn->rx_descs;
 
 	for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
-		dma_addr = ib_dma_map_single(ib_dev, (void *)rx_desc,
-					ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+		dma_addr = ib_dma_map_single(ib_dev, rx_desc->buf,
+					ISER_RX_SIZE, DMA_FROM_DEVICE);
 		if (ib_dma_mapping_error(ib_dev, dma_addr))
 			goto dma_map_fail;
 
 		rx_desc->dma_addr = dma_addr;
 
 		rx_sg = &rx_desc->rx_sg;
-		rx_sg->addr = rx_desc->dma_addr;
+		rx_sg->addr = rx_desc->dma_addr + isert_get_hdr_offset(rx_desc);
 		rx_sg->length = ISER_RX_PAYLOAD_SIZE;
 		rx_sg->lkey = device->pd->local_dma_lkey;
 		rx_desc->rx_cqe.done = isert_recv_done;
@@ -202,7 +202,7 @@
 	rx_desc = isert_conn->rx_descs;
 	for (j = 0; j < i; j++, rx_desc++) {
 		ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
-				    ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+				    ISER_RX_SIZE, DMA_FROM_DEVICE);
 	}
 	kfree(isert_conn->rx_descs);
 	isert_conn->rx_descs = NULL;
@@ -223,7 +223,7 @@
 	rx_desc = isert_conn->rx_descs;
 	for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
 		ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
-				    ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+				    ISER_RX_SIZE, DMA_FROM_DEVICE);
 	}
 
 	kfree(isert_conn->rx_descs);
@@ -408,10 +408,9 @@
 			    ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE);
 	kfree(isert_conn->login_rsp_buf);
 
-	ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
-			    ISER_RX_PAYLOAD_SIZE,
-			    DMA_FROM_DEVICE);
-	kfree(isert_conn->login_req_buf);
+	ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
+			    ISER_RX_SIZE, DMA_FROM_DEVICE);
+	kfree(isert_conn->login_desc);
 }
 
 static int
@@ -420,25 +419,25 @@
 {
 	int ret;
 
-	isert_conn->login_req_buf = kzalloc(sizeof(*isert_conn->login_req_buf),
+	isert_conn->login_desc = kzalloc(sizeof(*isert_conn->login_desc),
 			GFP_KERNEL);
-	if (!isert_conn->login_req_buf)
+	if (!isert_conn->login_desc)
 		return -ENOMEM;
 
-	isert_conn->login_req_dma = ib_dma_map_single(ib_dev,
-				isert_conn->login_req_buf,
-				ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
-	ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma);
+	isert_conn->login_desc->dma_addr = ib_dma_map_single(ib_dev,
+				isert_conn->login_desc->buf,
+				ISER_RX_SIZE, DMA_FROM_DEVICE);
+	ret = ib_dma_mapping_error(ib_dev, isert_conn->login_desc->dma_addr);
 	if (ret) {
-		isert_err("login_req_dma mapping error: %d\n", ret);
-		isert_conn->login_req_dma = 0;
-		goto out_free_login_req_buf;
+		isert_err("login_desc dma mapping error: %d\n", ret);
+		isert_conn->login_desc->dma_addr = 0;
+		goto out_free_login_desc;
 	}
 
 	isert_conn->login_rsp_buf = kzalloc(ISER_RX_PAYLOAD_SIZE, GFP_KERNEL);
 	if (!isert_conn->login_rsp_buf) {
 		ret = -ENOMEM;
-		goto out_unmap_login_req_buf;
+		goto out_unmap_login_desc;
 	}
 
 	isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev,
@@ -455,11 +454,11 @@
 
 out_free_login_rsp_buf:
 	kfree(isert_conn->login_rsp_buf);
-out_unmap_login_req_buf:
-	ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
-			    ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
-out_free_login_req_buf:
-	kfree(isert_conn->login_req_buf);
+out_unmap_login_desc:
+	ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
+			    ISER_RX_SIZE, DMA_FROM_DEVICE);
+out_free_login_desc:
+	kfree(isert_conn->login_desc);
 	return ret;
 }
 
@@ -578,7 +577,7 @@
 		ib_destroy_qp(isert_conn->qp);
 	}
 
-	if (isert_conn->login_req_buf)
+	if (isert_conn->login_desc)
 		isert_free_login_buf(isert_conn);
 
 	isert_device_put(device);
@@ -734,9 +733,13 @@
 isert_connect_error(struct rdma_cm_id *cma_id)
 {
 	struct isert_conn *isert_conn = cma_id->qp->qp_context;
+	struct isert_np *isert_np = cma_id->context;
 
 	ib_drain_qp(isert_conn->qp);
+
+	mutex_lock(&isert_np->mutex);
 	list_del_init(&isert_conn->node);
+	mutex_unlock(&isert_np->mutex);
 	isert_conn->cm_id = NULL;
 	isert_put_conn(isert_conn);
 
@@ -964,17 +967,18 @@
 	int ret;
 
 	memset(&sge, 0, sizeof(struct ib_sge));
-	sge.addr = isert_conn->login_req_dma;
+	sge.addr = isert_conn->login_desc->dma_addr +
+		isert_get_hdr_offset(isert_conn->login_desc);
 	sge.length = ISER_RX_PAYLOAD_SIZE;
 	sge.lkey = isert_conn->device->pd->local_dma_lkey;
 
 	isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n",
 		sge.addr, sge.length, sge.lkey);
 
-	isert_conn->login_req_buf->rx_cqe.done = isert_login_recv_done;
+	isert_conn->login_desc->rx_cqe.done = isert_login_recv_done;
 
 	memset(&rx_wr, 0, sizeof(struct ib_recv_wr));
-	rx_wr.wr_cqe = &isert_conn->login_req_buf->rx_cqe;
+	rx_wr.wr_cqe = &isert_conn->login_desc->rx_cqe;
 	rx_wr.sg_list = &sge;
 	rx_wr.num_sge = 1;
 
@@ -1051,7 +1055,7 @@
 static void
 isert_rx_login_req(struct isert_conn *isert_conn)
 {
-	struct iser_rx_desc *rx_desc = isert_conn->login_req_buf;
+	struct iser_rx_desc *rx_desc = isert_conn->login_desc;
 	int rx_buflen = isert_conn->login_req_len;
 	struct iscsi_conn *conn = isert_conn->conn;
 	struct iscsi_login *login = conn->conn_login;
@@ -1063,7 +1067,7 @@
 
 	if (login->first_request) {
 		struct iscsi_login_req *login_req =
-			(struct iscsi_login_req *)&rx_desc->iscsi_header;
+			(struct iscsi_login_req *)isert_get_iscsi_hdr(rx_desc);
 		/*
 		 * Setup the initial iscsi_login values from the leading
 		 * login request PDU.
@@ -1082,13 +1086,13 @@
 		login->tsih		= be16_to_cpu(login_req->tsih);
 	}
 
-	memcpy(&login->req[0], (void *)&rx_desc->iscsi_header, ISCSI_HDR_LEN);
+	memcpy(&login->req[0], isert_get_iscsi_hdr(rx_desc), ISCSI_HDR_LEN);
 
 	size = min(rx_buflen, MAX_KEY_VALUE_PAIRS);
 	isert_dbg("Using login payload size: %d, rx_buflen: %d "
 		  "MAX_KEY_VALUE_PAIRS: %d\n", size, rx_buflen,
 		  MAX_KEY_VALUE_PAIRS);
-	memcpy(login->req_buf, &rx_desc->data[0], size);
+	memcpy(login->req_buf, isert_get_data(rx_desc), size);
 
 	if (login->first_request) {
 		complete(&isert_conn->login_comp);
@@ -1153,14 +1157,15 @@
 	if (imm_data_len != data_len) {
 		sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE));
 		sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents,
-				    &rx_desc->data[0], imm_data_len);
+				    isert_get_data(rx_desc), imm_data_len);
 		isert_dbg("Copy Immediate sg_nents: %u imm_data_len: %d\n",
 			  sg_nents, imm_data_len);
 	} else {
 		sg_init_table(&isert_cmd->sg, 1);
 		cmd->se_cmd.t_data_sg = &isert_cmd->sg;
 		cmd->se_cmd.t_data_nents = 1;
-		sg_set_buf(&isert_cmd->sg, &rx_desc->data[0], imm_data_len);
+		sg_set_buf(&isert_cmd->sg, isert_get_data(rx_desc),
+				imm_data_len);
 		isert_dbg("Transfer Immediate imm_data_len: %d\n",
 			  imm_data_len);
 	}
@@ -1229,9 +1234,9 @@
 	}
 	isert_dbg("Copying DataOut: sg_start: %p, sg_off: %u "
 		  "sg_nents: %u from %p %u\n", sg_start, sg_off,
-		  sg_nents, &rx_desc->data[0], unsol_data_len);
+		  sg_nents, isert_get_data(rx_desc), unsol_data_len);
 
-	sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0],
+	sg_copy_from_buffer(sg_start, sg_nents, isert_get_data(rx_desc),
 			    unsol_data_len);
 
 	rc = iscsit_check_dataout_payload(cmd, hdr, false);
@@ -1290,7 +1295,7 @@
 	}
 	cmd->text_in_ptr = text_in;
 
-	memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
+	memcpy(cmd->text_in_ptr, isert_get_data(rx_desc), payload_length);
 
 	return iscsit_process_text_cmd(conn, cmd, hdr);
 }
@@ -1300,7 +1305,7 @@
 		uint32_t read_stag, uint64_t read_va,
 		uint32_t write_stag, uint64_t write_va)
 {
-	struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
+	struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
 	struct iscsi_conn *conn = isert_conn->conn;
 	struct iscsi_cmd *cmd;
 	struct isert_cmd *isert_cmd;
@@ -1398,8 +1403,8 @@
 	struct isert_conn *isert_conn = wc->qp->qp_context;
 	struct ib_device *ib_dev = isert_conn->cm_id->device;
 	struct iser_rx_desc *rx_desc = cqe_to_rx_desc(wc->wr_cqe);
-	struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
-	struct iser_ctrl *iser_ctrl = &rx_desc->iser_header;
+	struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
+	struct iser_ctrl *iser_ctrl = isert_get_iser_hdr(rx_desc);
 	uint64_t read_va = 0, write_va = 0;
 	uint32_t read_stag = 0, write_stag = 0;
 
@@ -1413,7 +1418,7 @@
 	rx_desc->in_use = true;
 
 	ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr,
-			ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+			ISER_RX_SIZE, DMA_FROM_DEVICE);
 
 	isert_dbg("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n",
 		 rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags,
@@ -1448,7 +1453,7 @@
 			read_stag, read_va, write_stag, write_va);
 
 	ib_dma_sync_single_for_device(ib_dev, rx_desc->dma_addr,
-			ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+			ISER_RX_SIZE, DMA_FROM_DEVICE);
 }
 
 static void
@@ -1462,8 +1467,8 @@
 		return;
 	}
 
-	ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_req_dma,
-			ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+	ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr,
+			ISER_RX_SIZE, DMA_FROM_DEVICE);
 
 	isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN;
 
@@ -1478,8 +1483,8 @@
 	complete(&isert_conn->login_req_comp);
 	mutex_unlock(&isert_conn->mutex);
 
-	ib_dma_sync_single_for_device(ib_dev, isert_conn->login_req_dma,
-				ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+	ib_dma_sync_single_for_device(ib_dev, isert_conn->login_desc->dma_addr,
+				ISER_RX_SIZE, DMA_FROM_DEVICE);
 }
 
 static void
@@ -2506,6 +2511,7 @@
 {
 	struct isert_np *isert_np = np->np_context;
 	struct isert_conn *isert_conn, *n;
+	LIST_HEAD(drop_conn_list);
 
 	if (isert_np->cm_id)
 		rdma_destroy_id(isert_np->cm_id);
@@ -2525,7 +2531,7 @@
 					 node) {
 			isert_info("cleaning isert_conn %p state (%d)\n",
 				   isert_conn, isert_conn->state);
-			isert_connect_release(isert_conn);
+			list_move_tail(&isert_conn->node, &drop_conn_list);
 		}
 	}
 
@@ -2536,11 +2542,16 @@
 					 node) {
 			isert_info("cleaning isert_conn %p state (%d)\n",
 				   isert_conn, isert_conn->state);
-			isert_connect_release(isert_conn);
+			list_move_tail(&isert_conn->node, &drop_conn_list);
 		}
 	}
 	mutex_unlock(&isert_np->mutex);
 
+	list_for_each_entry_safe(isert_conn, n, &drop_conn_list, node) {
+		list_del_init(&isert_conn->node);
+		isert_connect_release(isert_conn);
+	}
+
 	np->np_context = NULL;
 	kfree(isert_np);
 }
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/isert/ib_isert.h
+++ linux-ein-5.4.0/drivers/infiniband/ulp/isert/ib_isert.h
@@ -59,9 +59,11 @@
 				ISERT_MAX_TX_MISC_PDUS	+ \
 				ISERT_MAX_RX_MISC_PDUS)
 
-#define ISER_RX_PAD_SIZE	(ISCSI_DEF_MAX_RECV_SEG_LEN + 4096 - \
-		(ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge) + \
-		 sizeof(struct ib_cqe) + sizeof(bool)))
+/*
+ * RX size is default of 8k plus headers, but data needs to align to
+ * 512 boundary, so use 1024 to have the extra space for alignment.
+ */
+#define ISER_RX_SIZE		(ISCSI_DEF_MAX_RECV_SEG_LEN + 1024)
 
 #define ISCSI_ISER_SG_TABLESIZE		256
 
@@ -80,21 +82,41 @@
 };
 
 struct iser_rx_desc {
-	struct iser_ctrl iser_header;
-	struct iscsi_hdr iscsi_header;
-	char		data[ISCSI_DEF_MAX_RECV_SEG_LEN];
+	char		buf[ISER_RX_SIZE];
 	u64		dma_addr;
 	struct ib_sge	rx_sg;
 	struct ib_cqe	rx_cqe;
 	bool		in_use;
-	char		pad[ISER_RX_PAD_SIZE];
-} __packed;
+};
 
 static inline struct iser_rx_desc *cqe_to_rx_desc(struct ib_cqe *cqe)
 {
 	return container_of(cqe, struct iser_rx_desc, rx_cqe);
 }
 
+static void *isert_get_iser_hdr(struct iser_rx_desc *desc)
+{
+	return PTR_ALIGN(desc->buf + ISER_HEADERS_LEN, 512) - ISER_HEADERS_LEN;
+}
+
+static size_t isert_get_hdr_offset(struct iser_rx_desc *desc)
+{
+	return isert_get_iser_hdr(desc) - (void *)desc->buf;
+}
+
+static void *isert_get_iscsi_hdr(struct iser_rx_desc *desc)
+{
+	return isert_get_iser_hdr(desc) + sizeof(struct iser_ctrl);
+}
+
+static void *isert_get_data(struct iser_rx_desc *desc)
+{
+	void *data = isert_get_iser_hdr(desc) + ISER_HEADERS_LEN;
+
+	WARN_ON((uintptr_t)data & 511);
+	return data;
+}
+
 struct iser_tx_desc {
 	struct iser_ctrl iser_header;
 	struct iscsi_hdr iscsi_header;
@@ -141,9 +163,8 @@
 	u32			responder_resources;
 	u32			initiator_depth;
 	bool			pi_support;
-	struct iser_rx_desc	*login_req_buf;
+	struct iser_rx_desc	*login_desc;
 	char			*login_rsp_buf;
-	u64			login_req_dma;
 	int			login_req_len;
 	u64			login_rsp_dma;
 	struct iser_rx_desc	*rx_descs;
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/srp/ib_srp.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2536,7 +2536,8 @@
 	if (lrsp->opcode == SRP_LOGIN_RSP) {
 		ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
 		ch->req_lim       = be32_to_cpu(lrsp->req_lim_delta);
-		ch->use_imm_data  = lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP;
+		ch->use_imm_data  = srp_use_imm_data &&
+			(lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP);
 		ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
 						      ch->use_imm_data);
 		WARN_ON_ONCE(ch->max_it_iu_len >
@@ -4221,9 +4222,11 @@
 		spin_unlock(&host->target_lock);
 
 		/*
-		 * Wait for tl_err and target port removal tasks.
+		 * srp_queue_remove_work() queues a call to
+		 * srp_remove_target(). The latter function cancels
+		 * target->tl_err_work so waiting for the remove works to
+		 * finish is sufficient.
 		 */
-		flush_workqueue(system_long_wq);
 		flush_workqueue(srp_remove_wq);
 
 		kfree(host);
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/srp/ib_srp.h
+++ linux-ein-5.4.0/drivers/infiniband/ulp/srp/ib_srp.h
@@ -63,9 +63,6 @@
 	SRP_DEFAULT_CMD_SQ_SIZE = SRP_DEFAULT_QUEUE_SIZE - SRP_RSP_SQ_SIZE -
 				  SRP_TSK_MGMT_SQ_SIZE,
 
-	SRP_TAG_NO_REQ		= ~0U,
-	SRP_TAG_TSK_MGMT	= 1U << 31,
-
 	SRP_MAX_PAGES_PER_MR	= 512,
 
 	SRP_MAX_ADD_CDB_LEN	= 16,
@@ -80,6 +77,11 @@
 				  sizeof(struct srp_imm_buf),
 };
 
+enum {
+	SRP_TAG_NO_REQ		= ~0U,
+	SRP_TAG_TSK_MGMT	= BIT(31),
+};
+
 enum srp_target_state {
 	SRP_TARGET_SCANNING,
 	SRP_TARGET_LIVE,
--- linux-ein-5.4.0.orig/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ linux-ein-5.4.0/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -213,12 +213,15 @@
 /**
  * srpt_qp_event - QP event callback function
  * @event: Description of the event that occurred.
- * @ch: SRPT RDMA channel.
+ * @ptr: SRPT RDMA channel.
  */
-static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch)
+static void srpt_qp_event(struct ib_event *event, void *ptr)
 {
-	pr_debug("QP event %d on ch=%p sess_name=%s state=%d\n",
-		 event->event, ch, ch->sess_name, ch->state);
+	struct srpt_rdma_ch *ch = ptr;
+
+	pr_debug("QP event %d on ch=%p sess_name=%s-%d state=%s\n",
+		 event->event, ch, ch->sess_name, ch->qp->qp_num,
+		 get_ch_state_name(ch->state));
 
 	switch (event->event) {
 	case IB_EVENT_COMM_EST:
@@ -1364,9 +1367,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
@@ -1388,6 +1393,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);
@@ -1777,8 +1804,7 @@
 	}
 
 	qp_init->qp_context = (void *)ch;
-	qp_init->event_handler
-		= (void(*)(struct ib_event *, void*))srpt_qp_event;
+	qp_init->event_handler = srpt_qp_event;
 	qp_init->send_cq = ch->cq;
 	qp_init->recv_cq = ch->cq;
 	qp_init->sq_sig_type = IB_SIGNAL_REQ_WR;
@@ -1981,8 +2007,8 @@
 	list_for_each_entry(nexus, &sport->nexus_list, entry) {
 		list_for_each_entry(ch, &nexus->ch_list, list) {
 			if (srpt_disconnect_ch(ch) >= 0)
-				pr_info("Closing channel %s because target %s_%d has been disabled\n",
-					ch->sess_name,
+				pr_info("Closing channel %s-%d because target %s_%d has been disabled\n",
+					ch->sess_name, ch->qp->qp_num,
 					dev_name(&sport->sdev->device->dev),
 					sport->port);
 			srpt_close_ch(ch);
@@ -2349,6 +2375,7 @@
 		pr_info("rejected SRP_LOGIN_REQ because target %s_%d is not enabled\n",
 			dev_name(&sdev->device->dev), port_num);
 		mutex_unlock(&sport->mutex);
+		ret = -EINVAL;
 		goto reject;
 	}
 
--- linux-ein-5.4.0.orig/drivers/input/evdev.c
+++ linux-ein-5.4.0/drivers/input/evdev.c
@@ -224,13 +224,13 @@
 		 */
 		client->tail = (client->head - 2) & (client->bufsize - 1);
 
-		client->buffer[client->tail].input_event_sec =
-						event->input_event_sec;
-		client->buffer[client->tail].input_event_usec =
-						event->input_event_usec;
-		client->buffer[client->tail].type = EV_SYN;
-		client->buffer[client->tail].code = SYN_DROPPED;
-		client->buffer[client->tail].value = 0;
+		client->buffer[client->tail] = (struct input_event) {
+			.input_event_sec = event->input_event_sec,
+			.input_event_usec = event->input_event_usec,
+			.type = EV_SYN,
+			.code = SYN_DROPPED,
+			.value = 0,
+		};
 
 		client->packet_head = client->tail;
 	}
@@ -326,20 +326,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);
@@ -453,6 +439,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);
 
@@ -484,10 +474,7 @@
 	struct evdev_client *client;
 	int error;
 
-	client = kzalloc(struct_size(client, buffer, bufsize),
-			 GFP_KERNEL | __GFP_NOWARN);
-	if (!client)
-		client = vzalloc(struct_size(client, buffer, bufsize));
+	client = kvzalloc(struct_size(client, buffer, bufsize), GFP_KERNEL);
 	if (!client)
 		return -ENOMEM;
 
@@ -1313,7 +1300,6 @@
 	.compat_ioctl	= evdev_ioctl_compat,
 #endif
 	.fasync		= evdev_fasync,
-	.flush		= evdev_flush,
 	.llseek		= no_llseek,
 };
 
--- linux-ein-5.4.0.orig/drivers/input/input.c
+++ linux-ein-5.4.0/drivers/input/input.c
@@ -47,6 +47,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)
 {
@@ -190,6 +201,7 @@
 			input_value_sync
 		};
 
+		input_set_timestamp(dev, ktime_get());
 		input_pass_values(dev, vals, ARRAY_SIZE(vals));
 
 		if (dev->rep[REP_PERIOD])
@@ -878,16 +890,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;
 }
 
@@ -943,9 +957,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
@@ -1971,6 +1989,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-ein-5.4.0.orig/drivers/input/joydev.c
+++ linux-ein-5.4.0/drivers/input/joydev.c
@@ -456,7 +456,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;
@@ -480,6 +480,9 @@
 	int i;
 	int retval = 0;
 
+	if (len % sizeof(*keypam))
+		return -EINVAL;
+
 	len = min(len, sizeof(joydev->keypam));
 
 	/* Validate the map. */
@@ -487,7 +490,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;
@@ -497,7 +500,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-ein-5.4.0.orig/drivers/input/joystick/iforce/iforce-main.c
+++ linux-ein-5.4.0/drivers/input/joystick/iforce/iforce-main.c
@@ -50,6 +50,7 @@
 	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick_avb, abs_avb_pegasus, ff_iforce },
 	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x8886, "Boeder Force Feedback Wheel",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
 	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
 	{ 0x061c, 0xc084, "ACT LABS Force RS",				btn_wheel, abs_wheel, ff_iforce },
@@ -272,22 +273,22 @@
  * Get device info.
  */
 
-	if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
+	if (!iforce_get_id_packet(iforce, 'M', buf, &len) && len >= 3)
 		input_dev->id.vendor = get_unaligned_le16(buf + 1);
 	else
 		dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
 
-	if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
+	if (!iforce_get_id_packet(iforce, 'P', buf, &len) && len >= 3)
 		input_dev->id.product = get_unaligned_le16(buf + 1);
 	else
 		dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
 
-	if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
+	if (!iforce_get_id_packet(iforce, 'B', buf, &len) && len >= 3)
 		iforce->device_memory.end = get_unaligned_le16(buf + 1);
 	else
 		dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
 
-	if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
+	if (!iforce_get_id_packet(iforce, 'N', buf, &len) && len >= 2)
 		ff_effects = buf[1];
 	else
 		dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
--- linux-ein-5.4.0.orig/drivers/input/joystick/iforce/iforce-serio.c
+++ linux-ein-5.4.0/drivers/input/joystick/iforce/iforce-serio.c
@@ -39,7 +39,7 @@
 
 again:
 	if (iforce->xmit.head == iforce->xmit.tail) {
-		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+		iforce_clear_xmit_and_wake(iforce);
 		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 		return;
 	}
@@ -64,7 +64,7 @@
 	if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
 		goto again;
 
-	clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+	iforce_clear_xmit_and_wake(iforce);
 
 	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 }
@@ -169,7 +169,7 @@
 			iforce_serio->cmd_response_len = iforce_serio->len;
 
 			/* Signal that command is done */
-			wake_up(&iforce->wait);
+			wake_up_all(&iforce->wait);
 		} else if (likely(iforce->type)) {
 			iforce_process_packet(iforce, iforce_serio->id,
 					      iforce_serio->data_in,
--- linux-ein-5.4.0.orig/drivers/input/joystick/iforce/iforce-usb.c
+++ linux-ein-5.4.0/drivers/input/joystick/iforce/iforce-usb.c
@@ -30,7 +30,7 @@
 	spin_lock_irqsave(&iforce->xmit_lock, flags);
 
 	if (iforce->xmit.head == iforce->xmit.tail) {
-		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+		iforce_clear_xmit_and_wake(iforce);
 		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 		return;
 	}
@@ -58,9 +58,9 @@
 	XMIT_INC(iforce->xmit.tail, n);
 
 	if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
-		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
 		dev_warn(&iforce_usb->intf->dev,
 			 "usb_submit_urb failed %d\n", n);
+		iforce_clear_xmit_and_wake(iforce);
 	}
 
 	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -92,7 +92,7 @@
 				 id,
 				 USB_TYPE_VENDOR | USB_DIR_IN |
 					USB_RECIP_INTERFACE,
-				 0, 0, buf, IFORCE_MAX_LENGTH, HZ);
+				 0, 0, buf, IFORCE_MAX_LENGTH, 1000);
 	if (status < 0) {
 		dev_err(&iforce_usb->intf->dev,
 			"usb_submit_urb failed: %d\n", status);
@@ -175,15 +175,15 @@
 	struct iforce *iforce = &iforce_usb->iforce;
 
 	if (urb->status) {
-		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
 		dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
 			urb->status);
+		iforce_clear_xmit_and_wake(iforce);
 		return;
 	}
 
 	__iforce_usb_xmit(iforce);
 
-	wake_up(&iforce->wait);
+	wake_up_all(&iforce->wait);
 }
 
 static int iforce_usb_probe(struct usb_interface *intf,
--- linux-ein-5.4.0.orig/drivers/input/joystick/iforce/iforce.h
+++ linux-ein-5.4.0/drivers/input/joystick/iforce/iforce.h
@@ -119,6 +119,12 @@
 					 response_data, response_len);
 }
 
+static inline void iforce_clear_xmit_and_wake(struct iforce *iforce)
+{
+	clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+	wake_up_all(&iforce->wait);
+}
+
 /* Public functions */
 /* iforce-main.c */
 int iforce_init_device(struct device *parent, u16 bustype,
--- linux-ein-5.4.0.orig/drivers/input/joystick/psxpad-spi.c
+++ linux-ein-5.4.0/drivers/input/joystick/psxpad-spi.c
@@ -292,7 +292,7 @@
 	if (!pad)
 		return -ENOMEM;
 
-	pdev = input_allocate_polled_device();
+	pdev = devm_input_allocate_polled_device(&spi->dev);
 	if (!pdev) {
 		dev_err(&spi->dev, "failed to allocate input device\n");
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/input/joystick/spaceball.c
+++ linux-ein-5.4.0/drivers/input/joystick/spaceball.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <asm/unaligned.h>
 
 #define DRIVER_DESC	"SpaceTec SpaceBall 2003/3003/4000 FLX driver"
 
@@ -75,9 +76,15 @@
 
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++)
+			/*
+			 * Skip first three bytes; read six axes worth of data.
+			 * Axis values are signed 16-bit big-endian.
+			 */
+			data += 3;
+			for (i = 0; i < ARRAY_SIZE(spaceball_axes); i++) {
 				input_report_abs(dev, spaceball_axes[i],
-					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+					(__s16)get_unaligned_be16(&data[i * 2]));
+			}
 			break;
 
 		case 'K':					/* Button data */
--- linux-ein-5.4.0.orig/drivers/input/joystick/xpad.c
+++ linux-ein-5.4.0/drivers/input/joystick/xpad.c
@@ -112,11 +112,14 @@
 	u8 xtype;
 } xpad_device[] = {
 	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
+	{ 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 },
+	{ 0x03eb, 0xff02, "Wooting Two (Legacy)", 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 },
+	{ 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE },
 	{ 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 },
@@ -215,9 +218,17 @@
 	{ 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, 0x02ab, "PDP Controller for Xbox One", 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 },
@@ -234,6 +245,7 @@
 	{ 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 },
+	{ 0x0f0d, 0x00c5, "Hori Fighting Commander 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 },
@@ -241,6 +253,8 @@
 	{ 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
 	{ 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
 	{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
+	{ 0x11ff, 0x0511, "PXN V900", 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 },
@@ -249,9 +263,10 @@
 	{ 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 },
+	{ 0x146b, 0x0604, "Bigben Interactive DAIJA Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
 	{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
+	{ 0x1532, 0x0a29, "Razer Wolverine V2", 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 },
@@ -295,6 +310,10 @@
 	{ 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 },
@@ -309,6 +328,7 @@
 	{ 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, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, 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 },
@@ -318,6 +338,15 @@
 	{ 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 },
+	{ 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 },
+	{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
+	{ 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 },
+	{ 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 },
+	{ 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 },
+	{ 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 },
+	{ 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 },
+	{ 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 },
+	{ 0x3285, 0x0607, "Nacon GC-100", 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 }
@@ -402,7 +431,9 @@
 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(0x03eb),		/* Wooting Keyboards (Legacy) */
 	XPAD_XBOX360_VENDOR(0x044f),		/* Thrustmaster X-Box 360 controllers */
+	XPAD_XBOXONE_VENDOR(0x03f0),		/* HP HyperX Xbox One 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 */
@@ -412,12 +443,15 @@
 	{ 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(0x0c12),		/* Zeroplus X-Box 360 controllers */
 	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(0x11ff),		/* PXN V900 */
+	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 */
@@ -427,8 +461,17 @@
 	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_XBOX360_VENDOR(0x2563),		/* OneXPlayer Gamepad */
+	XPAD_XBOX360_VENDOR(0x260d),		/* Dareu H101 */
+	XPAD_XBOXONE_VENDOR(0x2dc8),		/* 8BitDo Pro 2 Wired Controller for Xbox */
+	XPAD_XBOXONE_VENDOR(0x2e24),		/* Hyperkin Duke X-Box One pad */
+	XPAD_XBOX360_VENDOR(0x2f24),		/* GameSir Controllers */
+	XPAD_XBOX360_VENDOR(0x31e3),		/* Wooting Keyboards */
+	XPAD_XBOX360_VENDOR(0x3285),		/* Nacon GC-100 */
 	{ }
 };
 
@@ -450,6 +493,9 @@
 	}
 
 
+#define GIP_WIRED_INTF_DATA 0
+#define GIP_WIRED_INTF_AUDIO 1
+
 /*
  * This packet is required for all Xbox One pads with 2015
  * or later firmware installed (or present from the factory).
@@ -459,6 +505,16 @@
 };
 
 /*
+ * 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.
@@ -516,6 +572,8 @@
 	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),
@@ -1762,7 +1820,7 @@
 	}
 
 	if (xpad->xtype == XTYPE_XBOXONE &&
-	    intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+	    intf->cur_altsetting->desc.bInterfaceNumber != GIP_WIRED_INTF_DATA) {
 		/*
 		 * The Xbox One controller lists three interfaces all with the
 		 * same interface class, subclass and protocol. Differentiate by
@@ -1932,7 +1990,6 @@
 	.disconnect	= xpad_disconnect,
 	.suspend	= xpad_suspend,
 	.resume		= xpad_resume,
-	.reset_resume	= xpad_resume,
 	.id_table	= xpad_table,
 };
 
--- linux-ein-5.4.0.orig/drivers/input/keyboard/Kconfig
+++ linux-ein-5.4.0/drivers/input/keyboard/Kconfig
@@ -68,9 +68,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
 
-config ATARI_KBD_CORE
-	bool
-
 config KEYBOARD_APPLESPI
 	tristate "Apple SPI keyboard and trackpad"
 	depends on ACPI && EFI
--- linux-ein-5.4.0.orig/drivers/input/keyboard/applespi.c
+++ linux-ein-5.4.0/drivers/input/keyboard/applespi.c
@@ -48,6 +48,7 @@
 #include <linux/efi.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
+#include <linux/ktime.h>
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -400,7 +401,7 @@
 	unsigned int			cmd_msg_cntr;
 	/* lock to protect the above parameters and flags below */
 	spinlock_t			cmd_msg_lock;
-	bool				cmd_msg_queued;
+	ktime_t				cmd_msg_queued;
 	enum applespi_evt_type		cmd_evt_type;
 
 	struct led_classdev		backlight_info;
@@ -716,7 +717,7 @@
 		wake_up_all(&applespi->drain_complete);
 
 	if (is_write_msg) {
-		applespi->cmd_msg_queued = false;
+		applespi->cmd_msg_queued = 0;
 		applespi_send_cmd_msg(applespi);
 	}
 
@@ -758,8 +759,16 @@
 		return 0;
 
 	/* check whether send is in progress */
-	if (applespi->cmd_msg_queued)
-		return 0;
+	if (applespi->cmd_msg_queued) {
+		if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
+			return 0;
+
+		dev_warn(&applespi->spi->dev, "Command %d timed out\n",
+			 applespi->cmd_evt_type);
+
+		applespi->cmd_msg_queued = 0;
+		applespi->write_active = false;
+	}
 
 	/* set up packet */
 	memset(packet, 0, APPLESPI_PACKET_SIZE);
@@ -856,7 +865,7 @@
 		return sts;
 	}
 
-	applespi->cmd_msg_queued = true;
+	applespi->cmd_msg_queued = ktime_get_coarse();
 	applespi->write_active = true;
 
 	return 0;
@@ -1908,7 +1917,7 @@
 	applespi->drain = false;
 	applespi->have_cl_led_on = false;
 	applespi->have_bl_level = 0;
-	applespi->cmd_msg_queued = false;
+	applespi->cmd_msg_queued = 0;
 	applespi->read_active = false;
 	applespi->write_active = false;
 
--- linux-ein-5.4.0.orig/drivers/input/keyboard/atkbd.c
+++ linux-ein-5.4.0/drivers/input/keyboard/atkbd.c
@@ -715,6 +715,44 @@
 			ps2dev->serio->phys);
 }
 
+#ifdef CONFIG_X86
+static bool atkbd_is_portable_device(void)
+{
+	static const char * const chassis_types[] = {
+		"8",	/* Portable */
+		"9",	/* Laptop */
+		"10",	/* Notebook */
+		"14",	/* Sub-Notebook */
+		"31",	/* Convertible */
+		"32",	/* Detachable */
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chassis_types); i++)
+		if (dmi_match(DMI_CHASSIS_TYPE, chassis_types[i]))
+			return true;
+
+	return false;
+}
+
+/*
+ * On many modern laptops ATKBD_CMD_GETID may cause problems, on these laptops
+ * the controller is always in translated mode. In this mode mice/touchpads will
+ * not work. So in this case simply assume a keyboard is connected to avoid
+ * confusing some laptop keyboards.
+ *
+ * Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard
+ * 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id
+ * and in translated mode that is a no-op.
+ */
+static bool atkbd_skip_getid(struct atkbd *atkbd)
+{
+	return atkbd->translated && atkbd_is_portable_device();
+}
+#else
+static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; }
+#endif
+
 /*
  * atkbd_probe() probes for an AT keyboard on a serio port.
  */
@@ -736,6 +774,11 @@
 				 "keyboard reset failed on %s\n",
 				 ps2dev->serio->phys);
 
+	if (atkbd_skip_getid(atkbd)) {
+		atkbd->id = 0xab83;
+		return 0;
+	}
+
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
  * Some keyboards report different values, but the first byte is always 0xab or
@@ -747,9 +790,9 @@
 	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
 
 /*
- * If the get ID command failed, we check if we can at least set the LEDs on
- * the keyboard. This should work on every keyboard out there. It also turns
- * the LEDs off, which we want anyway.
+ * If the get ID command failed, we check if we can at least set
+ * the LEDs on the keyboard. This should work on every keyboard out there.
+ * It also turns the LEDs off, which we want anyway.
  */
 		param[0] = 0;
 		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
--- linux-ein-5.4.0.orig/drivers/input/keyboard/cros_ec_keyb.c
+++ linux-ein-5.4.0/drivers/input/keyboard/cros_ec_keyb.c
@@ -183,6 +183,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-ein-5.4.0.orig/drivers/input/keyboard/dlink-dir685-touchkeys.c
+++ linux-ein-5.4.0/drivers/input/keyboard/dlink-dir685-touchkeys.c
@@ -143,7 +143,7 @@
 
 static struct i2c_driver dir685_tk_i2c_driver = {
 	.driver = {
-		.name	= "dlin-dir685-touchkeys",
+		.name	= "dlink-dir685-touchkeys",
 		.of_match_table = of_match_ptr(dir685_tk_of_match),
 	},
 	.probe		= dir685_tk_probe,
--- linux-ein-5.4.0.orig/drivers/input/keyboard/ep93xx_keypad.c
+++ linux-ein-5.4.0/drivers/input/keyboard/ep93xx_keypad.c
@@ -250,8 +250,8 @@
 	}
 
 	keypad->irq = platform_get_irq(pdev, 0);
-	if (!keypad->irq) {
-		err = -ENXIO;
+	if (keypad->irq < 0) {
+		err = keypad->irq;
 		goto failed_free;
 	}
 
--- linux-ein-5.4.0.orig/drivers/input/keyboard/hil_kbd.c
+++ linux-ein-5.4.0/drivers/input/keyboard/hil_kbd.c
@@ -512,6 +512,7 @@
 		    HIL_IDD_NUM_AXES_PER_SET(*idd)) {
 			printk(KERN_INFO PREFIX
 				"combo devices are not supported.\n");
+			error = -EINVAL;
 			goto bail1;
 		}
 
--- linux-ein-5.4.0.orig/drivers/input/keyboard/ipaq-micro-keys.c
+++ linux-ein-5.4.0/drivers/input/keyboard/ipaq-micro-keys.c
@@ -105,6 +105,9 @@
 	keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes,
 			   keys->input->keycodesize * keys->input->keycodemax,
 			   GFP_KERNEL);
+	if (!keys->codes)
+		return -ENOMEM;
+
 	keys->input->keycode = keys->codes;
 
 	__set_bit(EV_KEY, keys->input->evbit);
--- linux-ein-5.4.0.orig/drivers/input/keyboard/nspire-keypad.c
+++ linux-ein-5.4.0/drivers/input/keyboard/nspire-keypad.c
@@ -93,9 +93,15 @@
 	return IRQ_HANDLED;
 }
 
-static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
+static int nspire_keypad_open(struct input_dev *input)
 {
+	struct nspire_keypad *keypad = input_get_drvdata(input);
 	unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
+	int error;
+
+	error = clk_prepare_enable(keypad->clk);
+	if (error)
+		return error;
 
 	cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
 	if (cycles_per_us == 0)
@@ -121,30 +127,6 @@
 	keypad->int_mask = 1 << 1;
 	writel(keypad->int_mask, keypad->reg_base + KEYPAD_INTMSK);
 
-	/* Disable GPIO interrupts to prevent hanging on touchpad */
-	/* Possibly used to detect touchpad events */
-	writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
-	/* Acknowledge existing interrupts */
-	writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
-
-	return 0;
-}
-
-static int nspire_keypad_open(struct input_dev *input)
-{
-	struct nspire_keypad *keypad = input_get_drvdata(input);
-	int error;
-
-	error = clk_prepare_enable(keypad->clk);
-	if (error)
-		return error;
-
-	error = nspire_keypad_chip_init(keypad);
-	if (error) {
-		clk_disable_unprepare(keypad->clk);
-		return error;
-	}
-
 	return 0;
 }
 
@@ -152,6 +134,11 @@
 {
 	struct nspire_keypad *keypad = input_get_drvdata(input);
 
+	/* Disable interrupts */
+	writel(0, keypad->reg_base + KEYPAD_INTMSK);
+	/* Acknowledge existing interrupts */
+	writel(~0, keypad->reg_base + KEYPAD_INT);
+
 	clk_disable_unprepare(keypad->clk);
 }
 
@@ -210,6 +197,25 @@
 		return -ENOMEM;
 	}
 
+	error = clk_prepare_enable(keypad->clk);
+	if (error) {
+		dev_err(&pdev->dev, "failed to enable clock\n");
+		return error;
+	}
+
+	/* Disable interrupts */
+	writel(0, keypad->reg_base + KEYPAD_INTMSK);
+	/* Acknowledge existing interrupts */
+	writel(~0, keypad->reg_base + KEYPAD_INT);
+
+	/* Disable GPIO interrupts to prevent hanging on touchpad */
+	/* Possibly used to detect touchpad events */
+	writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
+	/* Acknowledge existing GPIO interrupts */
+	writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
+
+	clk_disable_unprepare(keypad->clk);
+
 	input_set_drvdata(input, keypad);
 
 	input->id.bustype = BUS_HOST;
--- linux-ein-5.4.0.orig/drivers/input/keyboard/omap-keypad.c
+++ linux-ein-5.4.0/drivers/input/keyboard/omap-keypad.c
@@ -46,7 +46,7 @@
 	unsigned short keymap[];
 };
 
-static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
 
 static unsigned int *row_gpios;
 static unsigned int *col_gpios;
--- linux-ein-5.4.0.orig/drivers/input/keyboard/omap4-keypad.c
+++ linux-ein-5.4.0/drivers/input/keyboard/omap4-keypad.c
@@ -186,12 +186,8 @@
 	return 0;
 }
 
-static void omap4_keypad_close(struct input_dev *input)
+static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
 {
-	struct omap4_keypad *keypad_data = input_get_drvdata(input);
-
-	disable_irq(keypad_data->irq);
-
 	/* Disable interrupts and wake-up events */
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
 			 OMAP4_VAL_IRQDISABLE);
@@ -200,7 +196,15 @@
 	/* clear pending interrupts */
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
 			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
+}
+
+static void omap4_keypad_close(struct input_dev *input)
+{
+	struct omap4_keypad *keypad_data;
 
+	keypad_data = input_get_drvdata(input);
+	disable_irq(keypad_data->irq);
+	omap4_keypad_stop(keypad_data);
 	enable_irq(keypad_data->irq);
 
 	pm_runtime_put_sync(input->dev.parent);
@@ -223,13 +227,37 @@
 	return 0;
 }
 
+static int omap4_keypad_check_revision(struct device *dev,
+				       struct omap4_keypad *keypad_data)
+{
+	unsigned int rev;
+
+	rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
+	rev &= 0x03 << 30;
+	rev >>= 30;
+	switch (rev) {
+	case KBD_REVISION_OMAP4:
+		keypad_data->reg_offset = 0x00;
+		keypad_data->irqreg_offset = 0x00;
+		break;
+	case KBD_REVISION_OMAP5:
+		keypad_data->reg_offset = 0x10;
+		keypad_data->irqreg_offset = 0x0c;
+		break;
+	default:
+		dev_err(dev, "Keypad reports unsupported revision %d", rev);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int omap4_keypad_probe(struct platform_device *pdev)
 {
 	struct omap4_keypad *keypad_data;
 	struct input_dev *input_dev;
 	struct resource *res;
 	unsigned int max_keys;
-	int rev;
 	int irq;
 	int error;
 
@@ -240,10 +268,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) {
@@ -271,41 +297,33 @@
 		goto err_release_mem;
 	}
 
+	pm_runtime_enable(&pdev->dev);
 
 	/*
 	 * Enable clocks for the keypad module so that we can read
 	 * revision register.
 	 */
-	pm_runtime_enable(&pdev->dev);
 	error = pm_runtime_get_sync(&pdev->dev);
 	if (error) {
 		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
-		goto err_unmap;
-	}
-	rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
-	rev &= 0x03 << 30;
-	rev >>= 30;
-	switch (rev) {
-	case KBD_REVISION_OMAP4:
-		keypad_data->reg_offset = 0x00;
-		keypad_data->irqreg_offset = 0x00;
-		break;
-	case KBD_REVISION_OMAP5:
-		keypad_data->reg_offset = 0x10;
-		keypad_data->irqreg_offset = 0x0c;
-		break;
-	default:
-		dev_err(&pdev->dev,
-			"Keypad reports unsupported revision %d", rev);
-		error = -EINVAL;
-		goto err_pm_put_sync;
+		pm_runtime_put_noidle(&pdev->dev);
+	} else {
+		error = omap4_keypad_check_revision(&pdev->dev,
+						    keypad_data);
+		if (!error) {
+			/* Ensure device does not raise interrupts */
+			omap4_keypad_stop(keypad_data);
+		}
+		pm_runtime_put_sync(&pdev->dev);
 	}
+	if (error)
+		goto err_pm_disable;
 
 	/* input device allocation */
 	keypad_data->input = input_dev = input_allocate_device();
 	if (!input_dev) {
 		error = -ENOMEM;
-		goto err_pm_put_sync;
+		goto err_pm_disable;
 	}
 
 	input_dev->name = pdev->name;
@@ -351,28 +369,25 @@
 		goto err_free_keymap;
 	}
 
-	device_init_wakeup(&pdev->dev, true);
-	pm_runtime_put_sync(&pdev->dev);
-
 	error = input_register_device(keypad_data->input);
 	if (error < 0) {
 		dev_err(&pdev->dev, "failed to register input device\n");
-		goto err_pm_disable;
+		goto err_free_irq;
 	}
 
+	device_init_wakeup(&pdev->dev, true);
 	platform_set_drvdata(pdev, keypad_data);
+
 	return 0;
 
-err_pm_disable:
-	pm_runtime_disable(&pdev->dev);
+err_free_irq:
 	free_irq(keypad_data->irq, keypad_data);
 err_free_keymap:
 	kfree(keypad_data->keymap);
 err_free_input:
 	input_free_device(input_dev);
-err_pm_put_sync:
-	pm_runtime_put_sync(&pdev->dev);
-err_unmap:
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
 	iounmap(keypad_data->base);
 err_release_mem:
 	release_mem_region(res->start, resource_size(res));
--- linux-ein-5.4.0.orig/drivers/input/keyboard/snvs_pwrkey.c
+++ linux-ein-5.4.0/drivers/input/keyboard/snvs_pwrkey.c
@@ -3,6 +3,7 @@
 // Driver for the IMX SNVS ON/OFF Power Key
 // Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
 
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -81,6 +82,11 @@
 	return IRQ_HANDLED;
 }
 
+static void imx_snvs_pwrkey_disable_clk(void *data)
+{
+	clk_disable_unprepare(data);
+}
+
 static void imx_snvs_pwrkey_act(void *pdata)
 {
 	struct pwrkey_drv_data *pd = pdata;
@@ -93,6 +99,7 @@
 	struct pwrkey_drv_data *pdata = NULL;
 	struct input_dev *input = NULL;
 	struct device_node *np;
+	struct clk *clk;
 	int error;
 
 	/* Get SNVS register Page */
@@ -115,6 +122,28 @@
 		dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
 	}
 
+	clk = devm_clk_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk);
+		return PTR_ERR(clk);
+	}
+
+	error = clk_prepare_enable(clk);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to enable snvs clock (%pe)\n",
+			ERR_PTR(error));
+		return error;
+	}
+
+	error = devm_add_action_or_reset(&pdev->dev,
+					 imx_snvs_pwrkey_disable_clk, clk);
+	if (error) {
+		dev_err(&pdev->dev,
+			"Failed to register clock cleanup handler (%pe)\n",
+			ERR_PTR(error));
+		return error;
+	}
+
 	pdata->wakeup = of_property_read_bool(np, "wakeup-source");
 
 	pdata->irq = platform_get_irq(pdev, 0);
--- linux-ein-5.4.0.orig/drivers/input/keyboard/sunkbd.c
+++ linux-ein-5.4.0/drivers/input/keyboard/sunkbd.c
@@ -99,7 +99,8 @@
 	switch (data) {
 
 	case SUNKBD_RET_RESET:
-		schedule_work(&sunkbd->tq);
+		if (sunkbd->enabled)
+			schedule_work(&sunkbd->tq);
 		sunkbd->reset = -1;
 		break;
 
@@ -200,16 +201,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) |
@@ -222,11 +219,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-ein-5.4.0.orig/drivers/input/keyboard/tm2-touchkey.c
+++ linux-ein-5.4.0/drivers/input/keyboard/tm2-touchkey.c
@@ -75,6 +75,14 @@
 	.cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF,
 };
 
+static const struct touchkey_variant tc360_touchkey_variant = {
+	.keycode_reg = 0x00,
+	.base_reg = 0x00,
+	.fixed_regulator = true,
+	.cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
+	.cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
+};
+
 static int tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
 					    enum led_brightness brightness)
 {
@@ -327,6 +335,9 @@
 	}, {
 		.compatible = "cypress,aries-touchkey",
 		.data = &aries_touchkey_variant,
+	}, {
+		.compatible = "coreriver,tc360-touchkey",
+		.data = &tc360_touchkey_variant,
 	},
 	{ },
 };
--- linux-ein-5.4.0.orig/drivers/input/keyboard/twl4030_keypad.c
+++ linux-ein-5.4.0/drivers/input/keyboard/twl4030_keypad.c
@@ -50,7 +50,7 @@
 	bool		autorepeat;
 	unsigned int	n_rows;
 	unsigned int	n_cols;
-	unsigned int	irq;
+	int		irq;
 
 	struct device *dbg_dev;
 	struct input_dev *input;
@@ -376,10 +376,8 @@
 	}
 
 	kp->irq = platform_get_irq(pdev, 0);
-	if (!kp->irq) {
-		dev_err(&pdev->dev, "no keyboard irq assigned\n");
-		return -EINVAL;
-	}
+	if (kp->irq < 0)
+		return kp->irq;
 
 	error = matrix_keypad_build_keymap(keymap_data, NULL,
 					   TWL4030_MAX_ROWS,
--- linux-ein-5.4.0.orig/drivers/input/misc/adxl34x.c
+++ linux-ein-5.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");
@@ -811,8 +811,7 @@
 	AC_WRITE(ac, POWER_CTL, 0);
 
 	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-				   dev_name(dev), ac);
+				   IRQF_ONESHOT, dev_name(dev), ac);
 	if (err) {
 		dev_err(dev, "irq %d busy?\n", ac->irq);
 		goto err_free_mem;
--- linux-ein-5.4.0.orig/drivers/input/misc/ati_remote2.c
+++ linux-ein-5.4.0/drivers/input/misc/ati_remote2.c
@@ -68,7 +68,7 @@
 {
 	pr_debug("%s()\n", __func__);
 
-	return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
+	return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
 }
 
 static int ati_remote2_set_mode_mask(const char *val,
@@ -84,7 +84,7 @@
 {
 	pr_debug("%s()\n", __func__);
 
-	return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg);
+	return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
 }
 
 static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
--- linux-ein-5.4.0.orig/drivers/input/misc/cm109.c
+++ linux-ein-5.4.0/drivers/input/misc/cm109.c
@@ -568,12 +568,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);
 
--- linux-ein-5.4.0.orig/drivers/input/misc/drv260x.c
+++ linux-ein-5.4.0/drivers/input/misc/drv260x.c
@@ -435,6 +435,7 @@
 	}
 
 	do {
+		usleep_range(15000, 15500);
 		error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
 		if (error) {
 			dev_err(&haptics->client->dev,
--- linux-ein-5.4.0.orig/drivers/input/misc/keyspan_remote.c
+++ linux-ein-5.4.0/drivers/input/misc/keyspan_remote.c
@@ -336,7 +336,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);
@@ -344,7 +345,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);
@@ -352,7 +354,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-ein-5.4.0.orig/drivers/input/misc/max77650-onkey.c
+++ linux-ein-5.4.0/drivers/input/misc/max77650-onkey.c
@@ -108,9 +108,16 @@
 	return input_register_device(onkey->input);
 }
 
+static const struct of_device_id max77650_onkey_of_match[] = {
+	{ .compatible = "maxim,max77650-onkey" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max77650_onkey_of_match);
+
 static struct platform_driver max77650_onkey_driver = {
 	.driver = {
 		.name = "max77650-onkey",
+		.of_match_table = max77650_onkey_of_match,
 	},
 	.probe = max77650_onkey_probe,
 };
--- linux-ein-5.4.0.orig/drivers/input/misc/pm8xxx-vibrator.c
+++ linux-ein-5.4.0/drivers/input/misc/pm8xxx-vibrator.c
@@ -90,7 +90,7 @@
 
 	if (regs->enable_mask)
 		rc = regmap_update_bits(vib->regmap, regs->enable_addr,
-					on ? regs->enable_mask : 0, val);
+					regs->enable_mask, on ? ~0 : 0);
 
 	return rc;
 }
--- linux-ein-5.4.0.orig/drivers/input/misc/powermate.c
+++ linux-ein-5.4.0/drivers/input/misc/powermate.c
@@ -425,6 +425,7 @@
 		pm->requires_update = 0;
 		usb_kill_urb(pm->irq);
 		input_unregister_device(pm->input);
+		usb_kill_urb(pm->config);
 		usb_free_urb(pm->irq);
 		usb_free_urb(pm->config);
 		powermate_free_buffers(interface_to_usbdev(intf), pm);
--- linux-ein-5.4.0.orig/drivers/input/misc/rk805-pwrkey.c
+++ linux-ein-5.4.0/drivers/input/misc/rk805-pwrkey.c
@@ -98,6 +98,7 @@
 };
 module_platform_driver(rk805_pwrkey_driver);
 
+MODULE_ALIAS("platform:rk805-pwrkey");
 MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>");
 MODULE_DESCRIPTION("RK805 PMIC Power Key driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/input/misc/sparcspkr.c
+++ linux-ein-5.4.0/drivers/input/misc/sparcspkr.c
@@ -205,6 +205,7 @@
 
 	info = &state->u.bbc;
 	info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
+	of_node_put(dp);
 	if (!info->clock_freq)
 		goto out_free;
 
--- linux-ein-5.4.0.orig/drivers/input/misc/uinput.c
+++ linux-ein-5.4.0/drivers/input/misc/uinput.c
@@ -74,12 +74,16 @@
 	struct uinput_device	*udev = input_get_drvdata(dev);
 	struct timespec64	ts;
 
-	udev->buff[udev->head].type = type;
-	udev->buff[udev->head].code = code;
-	udev->buff[udev->head].value = value;
 	ktime_get_ts64(&ts);
-	udev->buff[udev->head].input_event_sec = ts.tv_sec;
-	udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+	udev->buff[udev->head] = (struct input_event) {
+		.input_event_sec = ts.tv_sec,
+		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,
+		.type = type,
+		.code = code,
+		.value = value,
+	};
+
 	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
 
 	wake_up_interruptible(&udev->waitq);
--- linux-ein-5.4.0.orig/drivers/input/mouse/alps.c
+++ linux-ein-5.4.0/drivers/input/mouse/alps.c
@@ -852,8 +852,8 @@
 			x = y = z = 0;
 
 		/* Divide 4 since trackpoint's speed is too fast */
-		input_report_rel(dev2, REL_X, (char)x / 4);
-		input_report_rel(dev2, REL_Y, -((char)y / 4));
+		input_report_rel(dev2, REL_X, (s8)x / 4);
+		input_report_rel(dev2, REL_Y, -((s8)y / 4));
 
 		psmouse_report_standard_buttons(dev2, packet[3]);
 
@@ -1104,8 +1104,8 @@
 	    ((packet[3] & 0x20) << 1);
 	z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
 
-	input_report_rel(dev2, REL_X, (char)x);
-	input_report_rel(dev2, REL_Y, -((char)y));
+	input_report_rel(dev2, REL_X, (s8)x);
+	input_report_rel(dev2, REL_Y, -((s8)y));
 	input_report_abs(dev2, ABS_PRESSURE, z);
 
 	psmouse_report_standard_buttons(dev2, packet[1]);
@@ -2294,20 +2294,20 @@
 	if (reg < 0)
 		return reg;
 
-	x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
+	x_pitch = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */
 	x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
 
-	y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
+	y_pitch = (s8)reg >> 4; /* sign extend upper 4 bits */
 	y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
 
 	reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
 	if (reg < 0)
 		return reg;
 
-	x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
+	x_electrode = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */
 	x_electrode = 17 + x_electrode;
 
-	y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
+	y_electrode = (s8)reg >> 4; /* sign extend upper 4 bits */
 	y_electrode = 13 + y_electrode;
 
 	x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
--- linux-ein-5.4.0.orig/drivers/input/mouse/appletouch.c
+++ linux-ein-5.4.0/drivers/input/mouse/appletouch.c
@@ -916,6 +916,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;
@@ -923,8 +925,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-ein-5.4.0.orig/drivers/input/mouse/bcm5974.c
+++ linux-ein-5.4.0/drivers/input/mouse/bcm5974.c
@@ -942,17 +942,22 @@
 	if (!dev->tp_data)
 		goto err_free_bt_buffer;
 
-	if (dev->bt_urb)
+	if (dev->bt_urb) {
 		usb_fill_int_urb(dev->bt_urb, udev,
 				 usb_rcvintpipe(udev, cfg->bt_ep),
 				 dev->bt_data, dev->cfg.bt_datalen,
 				 bcm5974_irq_button, dev, 1);
 
+		dev->bt_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	}
+
 	usb_fill_int_urb(dev->tp_urb, udev,
 			 usb_rcvintpipe(udev, cfg->tp_ep),
 			 dev->tp_data, dev->cfg.tp_datalen,
 			 bcm5974_irq_trackpad, dev, 1);
 
+	dev->tp_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
 	/* create bcm5974 device */
 	usb_make_path(udev, dev->phys, sizeof(dev->phys));
 	strlcat(dev->phys, "/input0", sizeof(dev->phys));
--- linux-ein-5.4.0.orig/drivers/input/mouse/cyapa_gen6.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/input/mouse/cypress_ps2.c
+++ linux-ein-5.4.0/drivers/input/mouse/cypress_ps2.c
@@ -387,7 +387,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);
@@ -473,6 +475,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-ein-5.4.0.orig/drivers/input/mouse/cypress_ps2.h
+++ linux-ein-5.4.0/drivers/input/mouse/cypress_ps2.h
@@ -131,7 +131,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-ein-5.4.0.orig/drivers/input/mouse/elan_i2c.h
+++ linux-ein-5.4.0/drivers/input/mouse/elan_i2c.h
@@ -26,6 +26,24 @@
 
 #define ETP_CALIBRATE_MAX_LEN	3
 
+#define ETP_FEATURE_REPORT_MK	BIT(0)
+
+#define ETP_REPORT_ID		0x5D
+#define ETP_TP_REPORT_ID	0x5E
+#define ETP_TP_REPORT_ID2	0x5F
+#define ETP_REPORT_ID2		0x60	/* High precision report */
+
+#define ETP_REPORT_ID_OFFSET	2
+#define ETP_TOUCH_INFO_OFFSET	3
+#define ETP_FINGER_DATA_OFFSET	4
+#define ETP_HOVER_INFO_OFFSET	30
+#define ETP_MK_DATA_OFFSET	33	/* For high precision reports */
+
+#define ETP_MAX_REPORT_LEN	39
+
+#define ETP_MAX_FINGERS		5
+#define ETP_FINGER_DATA_LEN	5
+
 /* IAP Firmware handling */
 #define ETP_PRODUCT_ID_FORMAT_STRING	"%d.0"
 #define ETP_FW_NAME		"elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
@@ -78,7 +96,11 @@
 	int (*finish_fw_update)(struct i2c_client *client,
 				struct completion *reset_done);
 
-	int (*get_report)(struct i2c_client *client, u8 *report);
+	int (*get_report_features)(struct i2c_client *client, u8 pattern,
+				   unsigned int *features,
+				   unsigned int *report_len);
+	int (*get_report)(struct i2c_client *client, u8 *report,
+			  unsigned int report_len);
 	int (*get_pressure_adjustment)(struct i2c_client *client,
 				       int *adjustment);
 	int (*get_pattern)(struct i2c_client *client, u8 *pattern);
--- linux-ein-5.4.0.orig/drivers/input/mouse/elan_i2c_core.c
+++ linux-ein-5.4.0/drivers/input/mouse/elan_i2c_core.c
@@ -47,16 +47,6 @@
 #define ETP_FINGER_WIDTH	15
 #define ETP_RETRY_COUNT		3
 
-#define ETP_MAX_FINGERS		5
-#define ETP_FINGER_DATA_LEN	5
-#define ETP_REPORT_ID		0x5D
-#define ETP_TP_REPORT_ID	0x5E
-#define ETP_REPORT_ID_OFFSET	2
-#define ETP_TOUCH_INFO_OFFSET	3
-#define ETP_FINGER_DATA_OFFSET	4
-#define ETP_HOVER_INFO_OFFSET	30
-#define ETP_MAX_REPORT_LEN	34
-
 /* The main device structure */
 struct elan_tp_data {
 	struct i2c_client	*client;
@@ -85,6 +75,8 @@
 	u8			sm_version;
 	u8			iap_version;
 	u16			fw_checksum;
+	unsigned int		report_features;
+	unsigned int		report_len;
 	int			pressure_adjustment;
 	u8			mode;
 	u16			ic_type;
@@ -139,55 +131,21 @@
 	return 0;
 }
 
-static int elan_enable_power(struct elan_tp_data *data)
+static int elan_set_power(struct elan_tp_data *data, bool on)
 {
 	int repeat = ETP_RETRY_COUNT;
 	int error;
 
-	error = regulator_enable(data->vcc);
-	if (error) {
-		dev_err(&data->client->dev,
-			"failed to enable regulator: %d\n", error);
-		return error;
-	}
-
 	do {
-		error = data->ops->power_control(data->client, true);
+		error = data->ops->power_control(data->client, on);
 		if (error >= 0)
 			return 0;
 
 		msleep(30);
 	} while (--repeat > 0);
 
-	dev_err(&data->client->dev, "failed to enable power: %d\n", error);
-	return error;
-}
-
-static int elan_disable_power(struct elan_tp_data *data)
-{
-	int repeat = ETP_RETRY_COUNT;
-	int error;
-
-	do {
-		error = data->ops->power_control(data->client, false);
-		if (!error) {
-			error = regulator_disable(data->vcc);
-			if (error) {
-				dev_err(&data->client->dev,
-					"failed to disable regulator: %d\n",
-					error);
-				/* Attempt to power the chip back up */
-				data->ops->power_control(data->client, true);
-				break;
-			}
-
-			return 0;
-		}
-
-		msleep(30);
-	} while (--repeat > 0);
-
-	dev_err(&data->client->dev, "failed to disable power: %d\n", error);
+	dev_err(&data->client->dev, "failed to set power %s: %d\n",
+		on ? "on" : "off", error);
 	return error;
 }
 
@@ -341,6 +299,12 @@
 	else
 		ic_type = data->iap_version;
 
+	error = data->ops->get_report_features(data->client, data->pattern,
+					       &data->report_features,
+					       &data->report_len);
+	if (error)
+		return error;
+
 	error = elan_get_fwinfo(ic_type, &data->fw_validpage_count,
 				&data->fw_signature_address);
 	if (error)
@@ -351,16 +315,21 @@
 	return 0;
 }
 
-static unsigned int elan_convert_resolution(u8 val)
+static unsigned int elan_convert_resolution(u8 val, u8 pattern)
 {
 	/*
-	 * (value from firmware) * 10 + 790 = dpi
-	 *
+	 * pattern <= 0x01:
+	 *	(value from firmware) * 10 + 790 = dpi
+	 * else
+	 *	((value from firmware) + 3) * 100 = dpi
+	 */
+	int res = pattern <= 0x01 ?
+		(int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100;
+	/*
 	 * We also have to convert dpi to dots/mm (*10/254 to avoid floating
 	 * point).
 	 */
-
-	return ((int)(char)val * 10 + 790) * 10 / 254;
+	return res * 10 / 254;
 }
 
 static int elan_query_device_parameters(struct elan_tp_data *data)
@@ -409,8 +378,8 @@
 		if (error)
 			return error;
 
-		data->x_res = elan_convert_resolution(hw_x_res);
-		data->y_res = elan_convert_resolution(hw_y_res);
+		data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
+		data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
 	} else {
 		data->x_res = (data->max_x + 1) / x_mm;
 		data->y_res = (data->max_y + 1) / y_mm;
@@ -886,24 +855,22 @@
  * Elan isr functions
  ******************************************************************
  */
-static void elan_report_contact(struct elan_tp_data *data,
-				int contact_num, bool contact_valid,
-				u8 *finger_data)
+static void elan_report_contact(struct elan_tp_data *data, int contact_num,
+				bool contact_valid, bool high_precision,
+				u8 *packet, u8 *finger_data)
 {
 	struct input_dev *input = data->input;
 	unsigned int pos_x, pos_y;
-	unsigned int pressure, mk_x, mk_y;
-	unsigned int area_x, area_y, major, minor;
-	unsigned int scaled_pressure;
+	unsigned int pressure, scaled_pressure;
 
 	if (contact_valid) {
-		pos_x = ((finger_data[0] & 0xf0) << 4) |
-						finger_data[1];
-		pos_y = ((finger_data[0] & 0x0f) << 8) |
-						finger_data[2];
-		mk_x = (finger_data[3] & 0x0f);
-		mk_y = (finger_data[3] >> 4);
-		pressure = finger_data[4];
+		if (high_precision) {
+			pos_x = get_unaligned_be16(&finger_data[0]);
+			pos_y = get_unaligned_be16(&finger_data[2]);
+		} else {
+			pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1];
+			pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2];
+		}
 
 		if (pos_x > data->max_x || pos_y > data->max_y) {
 			dev_dbg(input->dev.parent,
@@ -913,18 +880,8 @@
 			return;
 		}
 
-		/*
-		 * To avoid treating large finger as palm, let's reduce the
-		 * width x and y per trace.
-		 */
-		area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
-		area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
-
-		major = max(area_x, area_y);
-		minor = min(area_x, area_y);
-
+		pressure = finger_data[4];
 		scaled_pressure = pressure + data->pressure_adjustment;
-
 		if (scaled_pressure > ETP_MAX_PRESSURE)
 			scaled_pressure = ETP_MAX_PRESSURE;
 
@@ -933,16 +890,37 @@
 		input_report_abs(input, ABS_MT_POSITION_X, pos_x);
 		input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
 		input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
-		input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
-		input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
-		input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
+
+		if (data->report_features & ETP_FEATURE_REPORT_MK) {
+			unsigned int mk_x, mk_y, area_x, area_y;
+			u8 mk_data = high_precision ?
+				packet[ETP_MK_DATA_OFFSET + contact_num] :
+				finger_data[3];
+
+			mk_x = mk_data & 0x0f;
+			mk_y = mk_data >> 4;
+
+			/*
+			 * To avoid treating large finger as palm, let's reduce
+			 * the width x and y per trace.
+			 */
+			area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
+			area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
+
+			input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
+			input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+					 max(area_x, area_y));
+			input_report_abs(input, ABS_MT_TOUCH_MINOR,
+					 min(area_x, area_y));
+		}
 	} else {
 		input_mt_slot(input, contact_num);
 		input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
 	}
 }
 
-static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
+static void elan_report_absolute(struct elan_tp_data *data, u8 *packet,
+				 bool high_precision)
 {
 	struct input_dev *input = data->input;
 	u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET];
@@ -951,11 +929,14 @@
 	u8 hover_info = packet[ETP_HOVER_INFO_OFFSET];
 	bool contact_valid, hover_event;
 
-	hover_event = hover_info & 0x40;
-	for (i = 0; i < ETP_MAX_FINGERS; i++) {
-		contact_valid = tp_info & (1U << (3 + i));
-		elan_report_contact(data, i, contact_valid, finger_data);
+	pm_wakeup_event(&data->client->dev, 0);
+
+	hover_event = hover_info & BIT(6);
 
+	for (i = 0; i < ETP_MAX_FINGERS; i++) {
+		contact_valid = tp_info & BIT(3 + i);
+		elan_report_contact(data, i, contact_valid, high_precision,
+				    packet, finger_data);
 		if (contact_valid)
 			finger_data += ETP_FINGER_DATA_LEN;
 	}
@@ -974,6 +955,8 @@
 	u8 *packet = &report[ETP_REPORT_ID_OFFSET + 1];
 	int x, y;
 
+	pm_wakeup_event(&data->client->dev, 0);
+
 	if (!data->tp_input) {
 		dev_warn_once(&data->client->dev,
 			      "received a trackpoint report while no trackpoint device has been created. Please report upstream.\n");
@@ -998,7 +981,6 @@
 static irqreturn_t elan_isr(int irq, void *dev_id)
 {
 	struct elan_tp_data *data = dev_id;
-	struct device *dev = &data->client->dev;
 	int error;
 	u8 report[ETP_MAX_REPORT_LEN];
 
@@ -1012,21 +994,23 @@
 		goto out;
 	}
 
-	error = data->ops->get_report(data->client, report);
+	error = data->ops->get_report(data->client, report, data->report_len);
 	if (error)
 		goto out;
 
-	pm_wakeup_event(dev, 0);
-
 	switch (report[ETP_REPORT_ID_OFFSET]) {
 	case ETP_REPORT_ID:
-		elan_report_absolute(data, report);
+		elan_report_absolute(data, report, false);
+		break;
+	case ETP_REPORT_ID2:
+		elan_report_absolute(data, report, true);
 		break;
 	case ETP_TP_REPORT_ID:
+	case ETP_TP_REPORT_ID2:
 		elan_report_trackpoint(data, report);
 		break;
 	default:
-		dev_err(dev, "invalid report id data (%x)\n",
+		dev_err(&data->client->dev, "invalid report id data (%x)\n",
 			report[ETP_REPORT_ID_OFFSET]);
 	}
 
@@ -1111,7 +1095,9 @@
 	input_abs_set_res(input, ABS_X, data->x_res);
 	input_abs_set_res(input, ABS_Y, data->y_res);
 	input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
-	input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
+	if (data->report_features & ETP_FEATURE_REPORT_MK)
+		input_set_abs_params(input, ABS_TOOL_WIDTH,
+				     0, ETP_FINGER_WIDTH, 0, 0);
 	input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
 
 	/* And MT parameters */
@@ -1121,10 +1107,12 @@
 	input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res);
 	input_set_abs_params(input, ABS_MT_PRESSURE, 0,
 			     ETP_MAX_PRESSURE, 0, 0);
-	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
-			     ETP_FINGER_WIDTH * max_width, 0, 0);
-	input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
-			     ETP_FINGER_WIDTH * min_width, 0, 0);
+	if (data->report_features & ETP_FEATURE_REPORT_MK) {
+		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
+				     0, ETP_FINGER_WIDTH * max_width, 0, 0);
+		input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
+				     0, ETP_FINGER_WIDTH * min_width, 0, 0);
+	}
 
 	data->input = input;
 
@@ -1315,9 +1303,19 @@
 		/* Enable wake from IRQ */
 		data->irq_wake = (enable_irq_wake(client->irq) == 0);
 	} else {
-		ret = elan_disable_power(data);
+		ret = elan_set_power(data, false);
+		if (ret)
+			goto err;
+
+		ret = regulator_disable(data->vcc);
+		if (ret) {
+			dev_err(dev, "error %d disabling regulator\n", ret);
+			/* Attempt to power the chip back up */
+			elan_set_power(data, true);
+		}
 	}
 
+err:
 	mutex_unlock(&data->sysfs_mutex);
 	return ret;
 }
@@ -1328,12 +1326,18 @@
 	struct elan_tp_data *data = i2c_get_clientdata(client);
 	int error;
 
-	if (device_may_wakeup(dev) && data->irq_wake) {
+	if (!device_may_wakeup(dev)) {
+		error = regulator_enable(data->vcc);
+		if (error) {
+			dev_err(dev, "error %d enabling regulator\n", error);
+			goto err;
+		}
+	} else if (data->irq_wake) {
 		disable_irq_wake(client->irq);
 		data->irq_wake = false;
 	}
 
-	error = elan_enable_power(data);
+	error = elan_set_power(data, true);
 	if (error) {
 		dev_err(dev, "power up when resuming failed: %d\n", error);
 		goto err;
--- linux-ein-5.4.0.orig/drivers/input/mouse/elan_i2c_i2c.c
+++ linux-ein-5.4.0/drivers/input/mouse/elan_i2c_i2c.c
@@ -55,6 +55,8 @@
 #define ETP_I2C_MIN_BASELINE_CMD	0x0318
 
 #define ETP_I2C_REPORT_LEN		34
+#define ETP_I2C_REPORT_LEN_ID2		39
+#define ETP_I2C_REPORT_MAX_LEN		39
 #define ETP_I2C_DESC_LENGTH		30
 #define ETP_I2C_REPORT_DESC_LENGTH	158
 #define ETP_I2C_INF_LENGTH		2
@@ -386,7 +388,7 @@
 		return error;
 	}
 
-	*max_x = le16_to_cpup((__le16 *)val) & 0x0fff;
+	*max_x = le16_to_cpup((__le16 *)val);
 
 	error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val);
 	if (error) {
@@ -394,7 +396,7 @@
 		return error;
 	}
 
-	*max_y = le16_to_cpup((__le16 *)val) & 0x0fff;
+	*max_y = le16_to_cpup((__le16 *)val);
 
 	return 0;
 }
@@ -617,12 +619,12 @@
 				     struct completion *completion)
 {
 	struct device *dev = &client->dev;
-	int error;
+	int error = 0;
 	int len;
-	u8 buffer[ETP_I2C_REPORT_LEN];
+	u8 buffer[ETP_I2C_REPORT_MAX_LEN];
 
-	len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
-	if (len != ETP_I2C_REPORT_LEN) {
+	len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN);
+	if (len <= 0) {
 		error = len < 0 ? len : -EIO;
 		dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
 			error, len);
@@ -656,20 +658,31 @@
 	return 0;
 }
 
-static int elan_i2c_get_report(struct i2c_client *client, u8 *report)
+static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern,
+					unsigned int *features,
+					unsigned int *report_len)
+{
+	*features = ETP_FEATURE_REPORT_MK;
+	*report_len = pattern <= 0x01 ?
+			ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2;
+	return 0;
+}
+
+static int elan_i2c_get_report(struct i2c_client *client,
+			       u8 *report, unsigned int report_len)
 {
 	int len;
 
-	len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN);
+	len = i2c_master_recv(client, report, report_len);
 	if (len < 0) {
 		dev_err(&client->dev, "failed to read report data: %d\n", len);
 		return len;
 	}
 
-	if (len != ETP_I2C_REPORT_LEN) {
+	if (len != report_len) {
 		dev_err(&client->dev,
 			"wrong report length (%d vs %d expected)\n",
-			len, ETP_I2C_REPORT_LEN);
+			len, report_len);
 		return -EIO;
 	}
 
@@ -706,5 +719,6 @@
 
 	.get_pattern		= elan_i2c_get_pattern,
 
+	.get_report_features	= elan_i2c_get_report_features,
 	.get_report		= elan_i2c_get_report,
 };
--- linux-ein-5.4.0.orig/drivers/input/mouse/elan_i2c_smbus.c
+++ linux-ein-5.4.0/drivers/input/mouse/elan_i2c_smbus.c
@@ -45,6 +45,7 @@
 #define ETP_SMBUS_CALIBRATE_QUERY	0xC5
 
 #define ETP_SMBUS_REPORT_LEN		32
+#define ETP_SMBUS_REPORT_LEN2		7
 #define ETP_SMBUS_REPORT_OFFSET		2
 #define ETP_SMBUS_HELLOPACKET_LEN	5
 #define ETP_SMBUS_IAP_PASSWORD		0x1234
@@ -469,7 +470,21 @@
 	return 0;
 }
 
-static int elan_smbus_get_report(struct i2c_client *client, u8 *report)
+static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern,
+					  unsigned int *features,
+					  unsigned int *report_len)
+{
+	/*
+	 * SMBus controllers with pattern 2 lack area info, as newer
+	 * high-precision packets use that space for coordinates.
+	 */
+	*features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0;
+	*report_len = ETP_SMBUS_REPORT_LEN;
+	return 0;
+}
+
+static int elan_smbus_get_report(struct i2c_client *client,
+				 u8 *report, unsigned int report_len)
 {
 	int len;
 
@@ -483,10 +498,13 @@
 		return len;
 	}
 
-	if (len != ETP_SMBUS_REPORT_LEN) {
+	if (report[ETP_REPORT_ID_OFFSET] == ETP_TP_REPORT_ID2)
+		report_len = ETP_SMBUS_REPORT_LEN2;
+
+	if (len != report_len) {
 		dev_err(&client->dev,
 			"wrong report length (%d vs %d expected)\n",
-			len, ETP_SMBUS_REPORT_LEN);
+			len, report_len);
 		return -EIO;
 	}
 
@@ -534,6 +552,7 @@
 	.write_fw_block		= elan_smbus_write_fw_block,
 	.finish_fw_update	= elan_smbus_finish_fw_update,
 
+	.get_report_features	= elan_smbus_get_report_features,
 	.get_report		= elan_smbus_get_report,
 	.get_pattern		= elan_smbus_get_pattern,
 };
--- linux-ein-5.4.0.orig/drivers/input/mouse/elantech.c
+++ linux-ein-5.4.0/drivers/input/mouse/elantech.c
@@ -90,6 +90,47 @@
 }
 
 /*
+ * Send an Elantech style special command to read 3 bytes from a register
+ */
+static int elantech_read_reg_params(struct psmouse *psmouse, u8 reg, u8 *param)
+{
+	if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, reg) ||
+	    elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
+		psmouse_err(psmouse,
+			    "failed to read register %#02x\n", reg);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * Send an Elantech style special command to write a register with a parameter
+ */
+static int elantech_write_reg_params(struct psmouse *psmouse, u8 reg, u8 *param)
+{
+	if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, reg) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, param[0]) ||
+	    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+	    elantech_ps2_command(psmouse, NULL, param[1]) ||
+	    elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
+		psmouse_err(psmouse,
+			    "failed to write register %#02x with value %#02x%#02x\n",
+			    reg, param[0], param[1]);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
  * Send an Elantech style special command to read a value from a register
  */
 static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
@@ -476,6 +517,19 @@
 	case 0x16008020U:
 	case 0x26800010U:
 	case 0x36808000U:
+
+		/*
+		 * This firmware misreport coordinates for trackpoint
+		 * occasionally. Discard packets outside of [-127, 127] range
+		 * to prevent cursor jumps.
+		 */
+		if (packet[4] == 0x80 || packet[5] == 0x80 ||
+		    packet[1] >> 7 == packet[4] >> 7 ||
+		    packet[2] >> 7 == packet[5] >> 7) {
+			elantech_debug("discarding packet [%6ph]\n", packet);
+			break;
+
+		}
 		x = packet[4] - (int)((packet[1]^0x80) << 1);
 		y = (int)((packet[2]^0x80) << 1) - packet[5];
 
@@ -620,10 +674,11 @@
 	struct input_dev *dev = psmouse->dev;
 	struct elantech_data *etd = psmouse->private;
 	unsigned char *packet = psmouse->packet;
-	int id = ((packet[3] & 0xe0) >> 5) - 1;
+	int id;
 	int pres, traces;
 
-	if (id < 0)
+	id = ((packet[3] & 0xe0) >> 5) - 1;
+	if (id < 0 || id >= ETP_MAX_FINGERS)
 		return;
 
 	etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2];
@@ -653,7 +708,7 @@
 	int id, sid;
 
 	id = ((packet[0] & 0xe0) >> 5) - 1;
-	if (id < 0)
+	if (id < 0 || id >= ETP_MAX_FINGERS)
 		return;
 
 	sid = ((packet[3] & 0xe0) >> 5) - 1;
@@ -674,7 +729,7 @@
 	input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x);
 	input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y);
 
-	if (sid >= 0) {
+	if (sid >= 0 && sid < ETP_MAX_FINGERS) {
 		etd->mt[sid].x += delta_x2 * weight;
 		etd->mt[sid].y -= delta_y2 * weight;
 		input_mt_slot(dev, sid);
@@ -1530,18 +1585,40 @@
 };
 
 /*
+ * Change Report id 0x5E to 0x5F.
+ */
+static int elantech_change_report_id(struct psmouse *psmouse)
+{
+	/*
+	 * NOTE: the code is expecting to receive param[] as an array of 3
+	 * items (see __ps2_command()), even if in this case only 2 are
+	 * actually needed. Make sure the array size is 3 to avoid potential
+	 * stack out-of-bound accesses.
+	 */
+	unsigned char param[3] = { 0x10, 0x03 };
+
+	if (elantech_write_reg_params(psmouse, 0x7, param) ||
+	    elantech_read_reg_params(psmouse, 0x7, param) ||
+	    param[0] != 0x10 || param[1] != 0x03) {
+		psmouse_err(psmouse, "Unable to change report ID to 0x5f.\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+/*
  * determine hardware version and set some properties according to it.
  */
 static int elantech_set_properties(struct elantech_device_info *info)
 {
 	/* This represents the version of IC body. */
-	int ver = (info->fw_version & 0x0f0000) >> 16;
+	info->ic_version = (info->fw_version & 0x0f0000) >> 16;
 
 	/* Early version of Elan touchpads doesn't obey the rule. */
 	if (info->fw_version < 0x020030 || info->fw_version == 0x020600)
 		info->hw_version = 1;
 	else {
-		switch (ver) {
+		switch (info->ic_version) {
 		case 2:
 		case 4:
 			info->hw_version = 2;
@@ -1557,6 +1634,11 @@
 		}
 	}
 
+	/* Get information pattern for hw_version 4 */
+	info->pattern = 0x00;
+	if (info->ic_version == 0x0f && (info->fw_version & 0xff) <= 0x02)
+		info->pattern = info->fw_version & 0xff;
+
 	/* decide which send_cmd we're gonna use early */
 	info->send_cmd = info->hw_version >= 3 ? elantech_send_cmd :
 						 synaptics_send_cmd;
@@ -1598,6 +1680,7 @@
 {
 	unsigned char param[3];
 	unsigned char traces;
+	unsigned char ic_body[3];
 
 	memset(info, 0, sizeof(*info));
 
@@ -1640,6 +1723,21 @@
 			     info->samples[2]);
 	}
 
+	if (info->pattern > 0x00 && info->ic_version == 0xf) {
+		if (info->send_cmd(psmouse, ETP_ICBODY_QUERY, ic_body)) {
+			psmouse_err(psmouse, "failed to query ic body\n");
+			return -EINVAL;
+		}
+		info->ic_version = be16_to_cpup((__be16 *)ic_body);
+		psmouse_info(psmouse,
+			     "Elan ic body: %#04x, current fw version: %#02x\n",
+			     info->ic_version, ic_body[2]);
+	}
+
+	info->product_id = be16_to_cpup((__be16 *)info->samples);
+	if (info->pattern == 0x00)
+		info->product_id &= 0xff;
+
 	if (info->samples[1] == 0x74 && info->hw_version == 0x03) {
 		/*
 		 * This module has a bug which makes absolute mode
@@ -1654,6 +1752,23 @@
 	/* The MSB indicates the presence of the trackpoint */
 	info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
 
+	if (info->has_trackpoint && info->ic_version == 0x0011 &&
+	    (info->product_id == 0x08 || info->product_id == 0x09 ||
+	     info->product_id == 0x0d || info->product_id == 0x0e)) {
+		/*
+		 * This module has a bug which makes trackpoint in SMBus
+		 * mode return invalid data unless trackpoint is switched
+		 * from using 0x5e reports to 0x5f. If we are not able to
+		 * make the switch, let's abort initialization so we'll be
+		 * using standard PS/2 protocol.
+		 */
+		if (elantech_change_report_id(psmouse)) {
+			psmouse_info(psmouse,
+				     "Trackpoint report is broken, forcing standard PS/2 protocol\n");
+			return -ENODEV;
+		}
+	}
+
 	info->x_res = 31;
 	info->y_res = 31;
 	if (info->hw_version == 4) {
@@ -1999,6 +2114,7 @@
 	psmouse->protocol_handler = elantech_process_byte;
 	psmouse->disconnect = elantech_disconnect;
 	psmouse->reconnect = elantech_reconnect;
+	psmouse->fast_reconnect = NULL;
 	psmouse->pktsize = info->hw_version > 1 ? 6 : 4;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/input/mouse/elantech.h
+++ linux-ein-5.4.0/drivers/input/mouse/elantech.h
@@ -18,6 +18,7 @@
 #define ETP_CAPABILITIES_QUERY		0x02
 #define ETP_SAMPLE_QUERY		0x03
 #define ETP_RESOLUTION_QUERY		0x04
+#define ETP_ICBODY_QUERY		0x05
 
 /*
  * Command values for register reading or writing
@@ -140,7 +141,10 @@
 	unsigned char samples[3];
 	unsigned char debug;
 	unsigned char hw_version;
+	unsigned char pattern;
 	unsigned int fw_version;
+	unsigned int ic_version;
+	unsigned int product_id;
 	unsigned int x_min;
 	unsigned int y_min;
 	unsigned int x_max;
--- linux-ein-5.4.0.orig/drivers/input/mouse/focaltech.c
+++ linux-ein-5.4.0/drivers/input/mouse/focaltech.c
@@ -202,8 +202,8 @@
 	state->pressed = packet[0] >> 7;
 	finger1 = ((packet[0] >> 4) & 0x7) - 1;
 	if (finger1 < FOC_MAX_FINGERS) {
-		state->fingers[finger1].x += (char)packet[1];
-		state->fingers[finger1].y += (char)packet[2];
+		state->fingers[finger1].x += (s8)packet[1];
+		state->fingers[finger1].y += (s8)packet[2];
 	} else {
 		psmouse_err(psmouse, "First finger in rel packet invalid: %d\n",
 			    finger1);
@@ -218,8 +218,8 @@
 	 */
 	finger2 = ((packet[3] >> 4) & 0x7) - 1;
 	if (finger2 < FOC_MAX_FINGERS) {
-		state->fingers[finger2].x += (char)packet[4];
-		state->fingers[finger2].y += (char)packet[5];
+		state->fingers[finger2].x += (s8)packet[4];
+		state->fingers[finger2].y += (s8)packet[5];
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/input/mouse/psmouse-base.c
+++ linux-ein-5.4.0/drivers/input/mouse/psmouse-base.c
@@ -2042,7 +2042,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-ein-5.4.0.orig/drivers/input/mouse/sentelic.c
+++ linux-ein-5.4.0/drivers/input/mouse/sentelic.c
@@ -441,7 +441,7 @@
 
 	fsp_reg_write_enable(psmouse, false);
 
-	return count;
+	return retval;
 }
 
 PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
--- linux-ein-5.4.0.orig/drivers/input/mouse/synaptics.c
+++ linux-ein-5.4.0/drivers/input/mouse/synaptics.c
@@ -146,7 +146,6 @@
 	"LEN0042", /* Yoga */
 	"LEN0045",
 	"LEN0047",
-	"LEN0049",
 	"LEN2000", /* S540 */
 	"LEN2001", /* Edge E431 */
 	"LEN2002", /* Edge E531 */
@@ -166,23 +165,30 @@
 	/* all of the topbuttonpad_pnp_ids are valid, we just add some extras */
 	"LEN0048", /* X1 Carbon 3 */
 	"LEN0046", /* X250 */
+	"LEN0049", /* Yoga 11e */
 	"LEN004a", /* W541 */
 	"LEN005b", /* P50 */
 	"LEN005e", /* T560 */
+	"LEN006c", /* T470s */
+	"LEN007a", /* T470s */
 	"LEN0071", /* T480 */
 	"LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
 	"LEN0073", /* X1 Carbon G5 (Elantech) */
+	"LEN0091", /* X1 Carbon 6 */
 	"LEN0092", /* X1 Carbon 6 */
 	"LEN0093", /* T480 */
 	"LEN0096", /* X280 */
 	"LEN0097", /* X280 -> ALPS trackpoint */
+	"LEN0099", /* X1 Extreme 1st */
 	"LEN009b", /* T580 */
 	"LEN200f", /* T450s */
+	"LEN2044", /* L470  */
 	"LEN2054", /* E480 */
 	"LEN2055", /* E580 */
 	"SYN3052", /* HP EliteBook 840 G4 */
 	"SYN3221", /* HP 15-ay000 */
 	"SYN323d", /* HP Spectre X360 13-w013dx */
+	"SYN3257", /* HP Envy 13-ad105ng */
 	NULL
 };
 
@@ -1611,6 +1617,7 @@
 	psmouse->set_rate = synaptics_set_rate;
 	psmouse->disconnect = synaptics_disconnect;
 	psmouse->reconnect = synaptics_reconnect;
+	psmouse->fast_reconnect = NULL;
 	psmouse->cleanup = synaptics_reset;
 	/* Synaptics can usually stay in sync without extra help */
 	psmouse->resync_time = 0;
@@ -1740,6 +1747,7 @@
 		psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
 		!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10);
 	const struct rmi_device_platform_data pdata = {
+		.reset_delay_ms = 30,
 		.sensor_pdata = {
 			.sensor_type = rmi_sensor_touchpad,
 			.axis_align.flip_y = true,
--- linux-ein-5.4.0.orig/drivers/input/mouse/trackpoint.c
+++ linux-ein-5.4.0/drivers/input/mouse/trackpoint.c
@@ -17,10 +17,12 @@
 #include "trackpoint.h"
 
 static const char * const trackpoint_variants[] = {
-	[TP_VARIANT_IBM]	= "IBM",
-	[TP_VARIANT_ALPS]	= "ALPS",
-	[TP_VARIANT_ELAN]	= "Elan",
-	[TP_VARIANT_NXP]	= "NXP",
+	[TP_VARIANT_IBM]		= "IBM",
+	[TP_VARIANT_ALPS]		= "ALPS",
+	[TP_VARIANT_ELAN]		= "Elan",
+	[TP_VARIANT_NXP]		= "NXP",
+	[TP_VARIANT_JYT_SYNAPTICS]	= "JYT_Synaptics",
+	[TP_VARIANT_SYNAPTICS]		= "Synaptics",
 };
 
 /*
@@ -280,6 +282,8 @@
 	case TP_VARIANT_ALPS:
 	case TP_VARIANT_ELAN:
 	case TP_VARIANT_NXP:
+	case TP_VARIANT_JYT_SYNAPTICS:
+	case TP_VARIANT_SYNAPTICS:
 		if (variant_id)
 			*variant_id = param[0];
 		if (firmware_id)
--- linux-ein-5.4.0.orig/drivers/input/mouse/trackpoint.h
+++ linux-ein-5.4.0/drivers/input/mouse/trackpoint.h
@@ -24,10 +24,12 @@
  * 0x01 was the original IBM trackpoint, others implement very limited
  * subset of trackpoint features.
  */
-#define TP_VARIANT_IBM		0x01
-#define TP_VARIANT_ALPS		0x02
-#define TP_VARIANT_ELAN		0x03
-#define TP_VARIANT_NXP		0x04
+#define TP_VARIANT_IBM			0x01
+#define TP_VARIANT_ALPS			0x02
+#define TP_VARIANT_ELAN			0x03
+#define TP_VARIANT_NXP			0x04
+#define TP_VARIANT_JYT_SYNAPTICS	0x05
+#define TP_VARIANT_SYNAPTICS		0x06
 
 /*
  * Commands
--- linux-ein-5.4.0.orig/drivers/input/rmi4/rmi_bus.c
+++ linux-ein-5.4.0/drivers/input/rmi4/rmi_bus.c
@@ -276,11 +276,11 @@
 
 	device_del(&fn->dev);
 	of_node_put(fn->dev.of_node);
-	put_device(&fn->dev);
 
 	for (i = 0; i < fn->num_of_irqs; i++)
 		irq_dispose_mapping(fn->irq[i]);
 
+	put_device(&fn->dev);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/input/rmi4/rmi_driver.c
+++ linux-ein-5.4.0/drivers/input/rmi4/rmi_driver.c
@@ -205,7 +205,7 @@
 
 	if (count) {
 		kfree(attn_data.data);
-		attn_data.data = NULL;
+		drvdata->attn_data.data = NULL;
 	}
 
 	if (!kfifo_is_empty(&drvdata->attn_fifo))
@@ -1210,7 +1210,8 @@
 	if (data->input) {
 		rmi_driver_set_input_name(rmi_dev, data->input);
 		if (!rmi_dev->xport->input) {
-			if (input_register_device(data->input)) {
+			retval = input_register_device(data->input);
+			if (retval) {
 				dev_err(dev, "%s: Failed to register input device.\n",
 					__func__);
 				goto err_destroy_functions;
--- linux-ein-5.4.0.orig/drivers/input/rmi4/rmi_f34v7.c
+++ linux-ein-5.4.0/drivers/input/rmi4/rmi_f34v7.c
@@ -1189,6 +1189,9 @@
 {
 	int ret;
 
+	f34->fn->rmi_dev->driver->set_irq_bits(f34->fn->rmi_dev,
+					       f34->fn->irq_mask);
+
 	rmi_f34v7_read_queries_bl_version(f34);
 
 	f34->v7.image = fw->data;
--- linux-ein-5.4.0.orig/drivers/input/rmi4/rmi_smbus.c
+++ linux-ein-5.4.0/drivers/input/rmi4/rmi_smbus.c
@@ -235,12 +235,29 @@
 
 static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
 {
-	int retval;
+	struct i2c_client *client = rmi_smb->client;
+	int smbus_version;
+
+	/*
+	 * psmouse driver resets the controller, we only need to wait
+	 * to give the firmware chance to fully reinitialize.
+	 */
+	if (rmi_smb->xport.pdata.reset_delay_ms)
+		msleep(rmi_smb->xport.pdata.reset_delay_ms);
 
 	/* we need to get the smbus version to activate the touchpad */
-	retval = rmi_smb_get_version(rmi_smb);
-	if (retval < 0)
-		return retval;
+	smbus_version = rmi_smb_get_version(rmi_smb);
+	if (smbus_version < 0)
+		return smbus_version;
+
+	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+		smbus_version);
+
+	if (smbus_version != 2 && smbus_version != 3) {
+		dev_err(&client->dev, "Unrecognized SMB version %d\n",
+				smbus_version);
+		return -ENODEV;
+	}
 
 	return 0;
 }
@@ -253,11 +270,10 @@
 	rmi_smb_clear_state(rmi_smb);
 
 	/*
-	 * we do not call the actual reset command, it has to be handled in
-	 * PS/2 or there will be races between PS/2 and SMBus.
-	 * PS/2 should ensure that a psmouse_reset is called before
-	 * intializing the device and after it has been removed to be in a known
-	 * state.
+	 * We do not call the actual reset command, it has to be handled in
+	 * PS/2 or there will be races between PS/2 and SMBus. PS/2 should
+	 * ensure that a psmouse_reset is called before initializing the
+	 * device and after it has been removed to be in a known state.
 	 */
 	return rmi_smb_enable_smbus_mode(rmi_smb);
 }
@@ -273,7 +289,6 @@
 {
 	struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct rmi_smb_xport *rmi_smb;
-	int smbus_version;
 	int error;
 
 	if (!pdata) {
@@ -312,18 +327,9 @@
 	rmi_smb->xport.proto_name = "smb";
 	rmi_smb->xport.ops = &rmi_smb_ops;
 
-	smbus_version = rmi_smb_get_version(rmi_smb);
-	if (smbus_version < 0)
-		return smbus_version;
-
-	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
-		smbus_version);
-
-	if (smbus_version != 2 && smbus_version != 3) {
-		dev_err(&client->dev, "Unrecognized SMB version %d\n",
-				smbus_version);
-		return -ENODEV;
-	}
+	error = rmi_smb_enable_smbus_mode(rmi_smb);
+	if (error)
+		return error;
 
 	i2c_set_clientdata(client, rmi_smb);
 
--- linux-ein-5.4.0.orig/drivers/input/serio/hil_mlc.c
+++ linux-ein-5.4.0/drivers/input/serio/hil_mlc.c
@@ -74,10 +74,10 @@
 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);
+static DECLARE_TASKLET_DISABLED_OLD(hil_mlcs_tasklet, hil_mlcs_process);
 
 
 /* #define HIL_MLC_DEBUG */
@@ -702,9 +702,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;
@@ -715,8 +719,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:
@@ -780,6 +789,12 @@
 
 static void hil_mlcs_timer(struct timer_list *unused)
 {
+	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-ein-5.4.0.orig/drivers/input/serio/hp_sdc_mlc.c
+++ linux-ein-5.4.0/drivers/input/serio/hp_sdc_mlc.c
@@ -210,7 +210,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:
@@ -219,7 +219,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;
 
@@ -234,7 +234,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));
@@ -296,7 +296,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-ein-5.4.0.orig/drivers/input/serio/i8042-x86ia64io.h
+++ linux-ein-5.4.0/drivers/input/serio/i8042-x86ia64io.h
@@ -67,25 +67,84 @@
 
 #include <linux/dmi.h>
 
-static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
+#define SERIO_QUIRK_NOKBD		BIT(0)
+#define SERIO_QUIRK_NOAUX		BIT(1)
+#define SERIO_QUIRK_NOMUX		BIT(2)
+#define SERIO_QUIRK_FORCEMUX		BIT(3)
+#define SERIO_QUIRK_UNLOCK		BIT(4)
+#define SERIO_QUIRK_PROBE_DEFER		BIT(5)
+#define SERIO_QUIRK_RESET_ALWAYS	BIT(6)
+#define SERIO_QUIRK_RESET_NEVER		BIT(7)
+#define SERIO_QUIRK_DIECT		BIT(8)
+#define SERIO_QUIRK_DUMBKBD		BIT(9)
+#define SERIO_QUIRK_NOLOOP		BIT(10)
+#define SERIO_QUIRK_NOTIMEOUT		BIT(11)
+#define SERIO_QUIRK_KBDRESET		BIT(12)
+#define SERIO_QUIRK_DRITEK		BIT(13)
+#define SERIO_QUIRK_NOPNP		BIT(14)
+
+/* Quirk table for different mainboards. Options similar or identical to i8042
+ * module parameters.
+ * ORDERING IS IMPORTANT! The first match will be apllied and the rest ignored.
+ * This allows entries to overwrite vendor wide quirks on a per device basis.
+ * Where this is irrelevant, entries are sorted case sensitive by DMI_SYS_VENDOR
+ * and/or DMI_BOARD_VENDOR to make it easier to avoid dublicate entries.
+ */
+static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
 	{
-		/*
-		 * Arima-Rioworks HDAMB -
-		 * AUX LOOP command does not raise AUX IRQ
-		 */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
-			DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
-			DMI_MATCH(DMI_BOARD_VERSION, "Rev E"),
+			DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* ASUS G1S */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
-			DMI_MATCH(DMI_BOARD_NAME, "G1S"),
-			DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		/* Asus X450LCP */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_NEVER)
+	},
+	{
+		/* ASUS ZenBook UX425UA */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
+	},
+	{
+		/* ASUS ZenBook UM325UA */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
+	},
+	/*
+	 * On some Asus laptops, just running self tests cause problems.
+	 */
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_NEVER)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_NEVER)
 	},
 	{
 		/* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */
@@ -94,156 +153,338 @@
 			DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"),
 			DMI_MATCH(DMI_BOARD_VERSION, "REV 2.X"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
+		/* ASUS G1S */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "G1S"),
+			DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
-			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
+		/* Acer Aspire 5710 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
-			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Dell Embedded Box PC 3000 */
+		/* Acer Aspire 7738 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* OQO Model 01 */
+		/* Acer Aspire 5536 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "00"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* ULI EV4873 - AUX LOOP does not work properly */
+		/*
+		 * 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, "ULI"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Microsoft Virtual Machine */
+		/* Acer Aspire One 150 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Medion MAM 2070 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Medion Akoya E7225 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Blue FB5601 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "blue"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "M606"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Gigabyte M912 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Gigabyte M1022M netbook */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."),
-			DMI_MATCH(DMI_BOARD_NAME, "M1022E"),
-			DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Gigabyte Spring Peak - defines wrong chassis type */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Gigabyte T1005 - defines wrong chassis type ("Other") */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "T1005"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
+	/*
+	 * Some Wistron based laptops need us to explicitly enable the 'Dritek
+	 * keyboard extension' to make their extra keys start generating scancodes.
+	 * Originally, this was just confined to older laptops, but a few Acer laptops
+	 * have turned up in 2007 that also need this again.
+	 */
 	{
-		/* Gigabyte T1005M/P - defines wrong chassis type ("Other") */
+		/* Acer Aspire 5100 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
 	},
 	{
+		/* Acer Aspire 5610 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
 	},
 	{
+		/* Acer Aspire 5630 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
 	},
-	{ }
-};
-
-/*
- * Some Fujitsu notebooks are having trouble with touchpads if
- * active multiplexing mode is activated. Luckily they don't have
- * external PS/2 ports so we can safely disable it.
- * ... apparently some Toshibas don't like MUX mode either and
- * die horrible death on reboot.
- */
-static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
 	{
-		/* Fujitsu Lifebook P7010/P7010D */
+		/* Acer Aspire 5650 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
 	},
 	{
-		/* Fujitsu Lifebook P7010 */
+		/* Acer Aspire 5680 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer Aspire 5720 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer Aspire 9110 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer TravelMate 660 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer TravelMate 2490 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer TravelMate 4280 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_DRITEK)
+	},
+	{
+		/* Acer TravelMate P459-G2-M */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate P459-G2-M"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		/* Amoi M636/A737 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		/* Compal HEL80I */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		/* Advent 4211 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
+	},
+	{
+		/* Dell Embedded Box PC 3000 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		/* Dell XPS M1530 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		/* Dell Vostro 1510 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		/* Dell Vostro V13 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
+	},
+	{
+		/* Dell Vostro 1320 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
+	},
+	{
+		/* Dell Vostro 1520 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
+	},
+	{
+		/* Dell Vostro 1720 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
+	},
+	{
+		/* Entroware Proteus */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS)
+	},
+	/*
+	 * Some Fujitsu notebooks are having trouble with touchpads if
+	 * active multiplexing mode is activated. Luckily they don't have
+	 * external PS/2 ports so we can safely disable it.
+	 * ... apparently some Toshibas don't like MUX mode either and
+	 * die horrible death on reboot.
+	 */
+	{
+		/* Fujitsu Lifebook P7010/P7010D */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu Lifebook P5020D */
@@ -251,6 +492,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu Lifebook S2000 */
@@ -258,6 +500,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu Lifebook S6230 */
@@ -265,6 +508,15 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		/* Fujitsu Lifebook T725 laptop */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
 	},
 	{
 		/* Fujitsu Lifebook U745 */
@@ -272,6 +524,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu T70H */
@@ -279,6 +532,50 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
+	},
+	{
+		/* Fujitsu A544 laptop */
+		/* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
+	},
+	{
+		/* Fujitsu AH544 laptop */
+		/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
+	},
+	{
+		/* Fujitsu U574 laptop */
+		/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
+	},
+	{
+		/* Fujitsu UH554 laptop */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
+	},
+	{
+		/* Fujitsu Lifebook P7010 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu-Siemens Lifebook T3010 */
@@ -286,6 +583,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu-Siemens Lifebook E4010 */
@@ -293,6 +591,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu-Siemens Amilo Pro 2010 */
@@ -300,6 +599,7 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
 		/* Fujitsu-Siemens Amilo Pro 2030 */
@@ -307,578 +607,648 @@
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/*
-		 * No data is coming from the touchscreen unless KBC
-		 * is in legacy mode.
-		 */
-		/* Panasonic CF-29 */
+		/* Fujitsu Lifebook A574/H */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "FMVA0501PZ"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/*
-		 * HP Pavilion DV4017EA -
-		 * errors on MUX ports are reported without raising AUXDATA
-		 * causing "spurious NAK" messages.
-		 */
+		/* Fujitsu Lifebook E5411 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU CLIENT COMPUTING LIMITED"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E5411"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOAUX)
 	},
 	{
-		/*
-		 * HP Pavilion ZT1000 -
-		 * like DV4017EA does not raise AUXERR for errors on MUX ports.
-		 */
+		/* Gigabyte M912 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/*
-		 * HP Pavilion DV4270ca -
-		 * like DV4017EA does not raise AUXERR for errors on MUX ports.
-		 */
+		/* Gigabyte Spring Peak - defines wrong chassis type */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
+		/* Gigabyte T1005 - defines wrong chassis type ("Other") */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T1005"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
+		/* Gigabyte T1005M/P - defines wrong chassis type ("Other") */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
+	/*
+	 * Some laptops need keyboard reset before probing for the trackpad to get
+	 * it detected, initialised & finally work.
+	 */
 	{
+		/* Gigabyte P35 v2 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
+	},
+		{
+		/* Aorus branded Gigabyte X3 Plus - Elantech touchpad */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X3"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
 	},
 	{
+		/* Gigabyte P34 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
 	},
 	{
-		/* Sharp Actius MM20 */
+		/* Gigabyte P57 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
 	},
 	{
-		/* Sony Vaio FS-115b */
+		/* Gericom Bellagio */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/*
-		 * Sony Vaio FZ-240E -
-		 * reset and GET ID commands issued via KBD port are
-		 * sometimes being delivered to AUX3.
-		 */
+		/* Gigabyte M1022M netbook */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."),
+			DMI_MATCH(DMI_BOARD_NAME, "M1022E"),
+			DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
 		/*
-		 * Most (all?) VAIOs do not have external PS/2 ports nor
-		 * they implement active multiplexing properly, and
-		 * MUX discovery usually messes up keyboard/touchpad.
+		 * HP Pavilion DV4017EA -
+		 * errors on MUX ports are reported without raising AUXDATA
+		 * causing "spurious NAK" messages.
 		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-			DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Amoi M636/A737 */
+		/*
+		 * HP Pavilion ZT1000 -
+		 * like DV4017EA does not raise AUXERR for errors on MUX ports.
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Lenovo 3000 n100 */
+		/*
+		 * HP Pavilion DV4270ca -
+		 * like DV4017EA does not raise AUXERR for errors on MUX ports.
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
+		/* Newer HP Pavilion dv4 models */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
 	},
 	{
-		/* Acer Aspire 5710 */
+		/* IBM 2656 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
+			DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Acer Aspire 7738 */
+		/* Avatar AVIU-145A6 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Gericom Bellagio */
+		/* Intel MBO Desktop D845PESV */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "D845PESV"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* IBM 2656 */
+		/*
+		 * Intel NUC D54250WYK - does not have i8042 controller but
+		 * declares PS/2 devices in DSDT.
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Dell XPS M1530 */
+		/* Lenovo 3000 n100 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Compal HEL80I */
+		/* Lenovo XiaoXin Air 12 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "80UN"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Dell Vostro 1510 */
+		/* Lenovo LaVie Z */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Acer Aspire 5536 */
+		/* Lenovo Ideapad U455 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "20046"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Dell Vostro V13 */
+		/* Lenovo ThinkPad L460 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Newer HP Pavilion dv4 models */
+		/* Lenovo ThinkPad Twist S230u */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Asus X450LCP */
+		/* LG Electronics X110 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "X110"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Avatar AVIU-145A6 */
+		/* Medion Akoya Mini E1210 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "E1210"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* TUXEDO BU1406 */
+		/* Medion Akoya E1222 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"),
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "E122X"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Lenovo LaVie Z */
+		/* MSI Wind U-100 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+			DMI_MATCH(DMI_BOARD_NAME, "U-100"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOPNP)
 	},
-	{ }
-};
-
-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
+		 * No data is coming from the touchscreen unless KBC
+		 * is in legacy mode.
 		 */
+		/* Panasonic CF-29 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
-	{ }
-};
-
-/*
- * On some Asus laptops, just running self tests cause problems.
- */
-static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
 	{
+		/* Medion Akoya E7225 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+			DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
-	{ }
-};
-static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
 	{
-		/* MSI Wind U-100 */
+		/* Microsoft Virtual Machine */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "U-100"),
-			DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* LG Electronics X110 */
+		/* Medion MAM 2070 */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "X110"),
-			DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
+			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* Acer Aspire One 150 */
+		/* TUXEDO BU1406 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Advent 4211 */
+		/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
 	{
-		/* Medion Akoya Mini E1210 */
+		/* OQO Model 01 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "E1210"),
+			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "00"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* Medion Akoya E1222 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "E122X"),
+			DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* Mivvy M310 */
+		/* Acer Aspire 5 A515 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N10"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "PK"),
+			DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Dell Vostro 1320 */
+		/* ULI EV4873 - AUX LOOP does not work properly */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"),
+			DMI_MATCH(DMI_SYS_VENDOR, "ULI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* Dell Vostro 1520 */
+		/*
+		 * Arima-Rioworks HDAMB -
+		 * AUX LOOP command does not raise AUX IRQ
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"),
+			DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
+			DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
+			DMI_MATCH(DMI_BOARD_VERSION, "Rev E"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
 	{
-		/* Dell Vostro 1720 */
+		/* Sharp Actius MM20 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"),
+			DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Lenovo Ideapad U455 */
+		/*
+		 * Sony Vaio FZ-240E -
+		 * reset and GET ID commands issued via KBD port are
+		 * sometimes being delivered to AUX3.
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "20046"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Lenovo ThinkPad L460 */
+		/*
+		 * Most (all?) VAIOs do not have external PS/2 ports nor
+		 * they implement active multiplexing properly, and
+		 * MUX discovery usually messes up keyboard/touchpad.
+		 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
+		/* Sony Vaio FS-115b */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
-	{ }
-};
-
-#ifdef CONFIG_PNP
-static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = {
 	{
-		/* Intel MBO Desktop D845PESV */
+		/*
+		 * Sony Vaio VGN-CS series require MUX or the touch sensor
+		 * buttons will disturb touchpad operation
+		 */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "D845PESV"),
-			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_FORCEMUX)
 	},
 	{
-		/*
-		 * Intel NUC D54250WYK - does not have i8042 controller but
-		 * declares PS/2 devices in DSDT.
-		 */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"),
-			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
 	{
-		/* MSI Wind U-100 */
 		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "U-100"),
-			DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
-	{ }
-};
-
-static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
 	{
 		.matches = {
-			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX)
 	},
+	/*
+	 * A lot of modern Clevo barebones have touchpad and/or keyboard issues
+	 * after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
+	 * none of them have an external PS/2 port so this can safely be set for
+	 * all of them. These two are based on a Clevo design, but have the
+	 * board_name changed.
+	 */
 	{
 		.matches = {
-			DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
+			DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
+			DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
 		.matches = {
-			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+			DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
+			DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
+		/* Mivvy M310 */
 		.matches = {
-			DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
+			DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N10"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
 	},
-	{ }
-};
-#endif
-
-static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
+	/*
+	 * Some laptops need keyboard reset before probing for the trackpad to get
+	 * it detected, initialised & finally work.
+	 */
 	{
-		/* Dell Vostro V13 */
+		/* Schenker XMG C504 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+			DMI_MATCH(DMI_SYS_VENDOR, "XMG"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
 	},
 	{
-		/* Newer HP Pavilion dv4 models */
+		/* Blue FB5601 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
+			DMI_MATCH(DMI_SYS_VENDOR, "blue"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "M606"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
 	},
+	/*
+	 * A lot of modern Clevo barebones have touchpad and/or keyboard issues
+	 * after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
+	 * none of them have an external PS/2 port so this can safely be set for
+	 * all of them.
+	 * Clevo barebones come with board_vendor and/or system_vendor set to
+	 * either the very generic string "Notebook" and/or a different value
+	 * for each individual reseller. The only somewhat universal way to
+	 * identify them is by board_name.
+	 */
 	{
-		/* Fujitsu A544 laptop */
-		/* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
+			DMI_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Fujitsu AH544 laptop */
-		/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
+			DMI_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Fujitsu U574 laptop */
-		/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
+			DMI_MATCH(DMI_BOARD_NAME, "N140CU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Fujitsu UH554 laptop */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"),
+			DMI_MATCH(DMI_BOARD_NAME, "N141CU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
-	{ }
-};
-
-/*
- * Some Wistron based laptops need us to explicitly enable the 'Dritek
- * keyboard extension' to make their extra keys start generating scancodes.
- * Originally, this was just confined to older laptops, but a few Acer laptops
- * have turned up in 2007 that also need this again.
- */
-static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
 	{
-		/* Acer Aspire 5100 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+			DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer Aspire 5610 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+			DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
+	/*
+	 * At least one modern Clevo barebone has the touchpad connected both
+	 * via PS/2 and i2c interface. This causes a race condition between the
+	 * psmouse and i2c-hid driver. Since the full capability of the touchpad
+	 * is available via the i2c interface and the device has no external
+	 * PS/2 port, it is safe to just ignore all ps2 mouses here to avoid
+	 * this issue. The known affected device is the
+	 * TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU which comes with one of
+	 * the two different dmi strings below. NS50MU is not a typo!
+	 */
 	{
-		/* Acer Aspire 5630 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
+			DMI_MATCH(DMI_BOARD_NAME, "NS50MU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
+					SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
+					SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer Aspire 5650 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
+			DMI_MATCH(DMI_BOARD_NAME, "NS50_70MU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
+					SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
+					SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer Aspire 5680 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
+			DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer Aspire 5720 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
+			DMI_MATCH(DMI_BOARD_NAME, "PB50_70DFx,DDx"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer Aspire 9110 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
+			DMI_MATCH(DMI_BOARD_NAME, "PCX0DX"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
+	/* See comment on TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU above */
 	{
-		/* Acer TravelMate 660 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
+			DMI_MATCH(DMI_BOARD_NAME, "PD5x_7xPNP_PNR_PNN_PNT"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOAUX)
 	},
 	{
-		/* Acer TravelMate 2490 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
+			DMI_MATCH(DMI_BOARD_NAME, "X170SM"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{
-		/* Acer TravelMate 4280 */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
+			DMI_MATCH(DMI_BOARD_NAME, "X170KM-G"),
 		},
+		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
 	},
 	{ }
 };
 
-/*
- * Some laptops need keyboard reset before probing for the trackpad to get
- * it detected, initialised & finally work.
- */
-static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
+#ifdef CONFIG_PNP
+static const struct dmi_system_id i8042_dmi_laptop_table[] __initconst = {
 	{
-		/* Gigabyte P35 v2 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"),
-		},
-	},
-		{
-		/* Aorus branded Gigabyte X3 Plus - Elantech touchpad */
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X3"),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
 		},
 	},
 	{
-		/* Gigabyte P34 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
 		},
 	},
 	{
-		/* Gigabyte P57 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
 		},
 	},
 	{
-		/* Schenker XMG C504 - Elantech touchpad */
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "XMG"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
 		},
 	},
 	{ }
 };
+#endif
 
 #endif /* CONFIG_X86 */
 
@@ -1033,11 +1403,6 @@
 	bool pnp_data_busted = false;
 	int err;
 
-#ifdef CONFIG_X86
-	if (dmi_check_system(i8042_dmi_nopnp_table))
-		i8042_nopnp = true;
-#endif
-
 	if (i8042_nopnp) {
 		pr_info("PNP detection disabled\n");
 		return 0;
@@ -1141,6 +1506,59 @@
 static inline void i8042_pnp_exit(void) { }
 #endif /* CONFIG_PNP */
 
+
+#ifdef CONFIG_X86
+static void __init i8042_check_quirks(void)
+{
+	const struct dmi_system_id *device_quirk_info;
+	uintptr_t quirks;
+
+	device_quirk_info = dmi_first_match(i8042_dmi_quirk_table);
+	if (!device_quirk_info)
+		return;
+
+	quirks = (uintptr_t)device_quirk_info->driver_data;
+
+	if (quirks & SERIO_QUIRK_NOKBD)
+		i8042_nokbd = true;
+	if (quirks & SERIO_QUIRK_NOAUX)
+		i8042_noaux = true;
+	if (quirks & SERIO_QUIRK_NOMUX)
+		i8042_nomux = true;
+	if (quirks & SERIO_QUIRK_FORCEMUX)
+		i8042_nomux = false;
+	if (quirks & SERIO_QUIRK_UNLOCK)
+		i8042_unlock = true;
+	if (quirks & SERIO_QUIRK_PROBE_DEFER)
+		i8042_probe_defer = true;
+	/* Honor module parameter when value is not default */
+	if (i8042_reset == I8042_RESET_DEFAULT) {
+		if (quirks & SERIO_QUIRK_RESET_ALWAYS)
+			i8042_reset = I8042_RESET_ALWAYS;
+		if (quirks & SERIO_QUIRK_RESET_NEVER)
+			i8042_reset = I8042_RESET_NEVER;
+	}
+	if (quirks & SERIO_QUIRK_DIECT)
+		i8042_direct = true;
+	if (quirks & SERIO_QUIRK_DUMBKBD)
+		i8042_dumbkbd = true;
+	if (quirks & SERIO_QUIRK_NOLOOP)
+		i8042_noloop = true;
+	if (quirks & SERIO_QUIRK_NOTIMEOUT)
+		i8042_notimeout = true;
+	if (quirks & SERIO_QUIRK_KBDRESET)
+		i8042_kbdreset = true;
+	if (quirks & SERIO_QUIRK_DRITEK)
+		i8042_dritek = true;
+#ifdef CONFIG_PNP
+	if (quirks & SERIO_QUIRK_NOPNP)
+		i8042_nopnp = true;
+#endif
+}
+#else
+static inline void i8042_check_quirks(void) {}
+#endif
+
 static int __init i8042_platform_init(void)
 {
 	int retval;
@@ -1163,42 +1581,17 @@
 	i8042_kbd_irq = I8042_MAP_IRQ(1);
 	i8042_aux_irq = I8042_MAP_IRQ(12);
 
-	retval = i8042_pnp_init();
-	if (retval)
-		return retval;
-
 #if defined(__ia64__)
-        i8042_reset = I8042_RESET_ALWAYS;
+	i8042_reset = I8042_RESET_ALWAYS;
 #endif
 
-#ifdef CONFIG_X86
-	/* 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;
-
-	if (dmi_check_system(i8042_dmi_nomux_table))
-		i8042_nomux = true;
-
-	if (dmi_check_system(i8042_dmi_forcemux_table))
-		i8042_nomux = false;
+	i8042_check_quirks();
 
-	if (dmi_check_system(i8042_dmi_notimeout_table))
-		i8042_notimeout = true;
-
-	if (dmi_check_system(i8042_dmi_dritek_table))
-		i8042_dritek = true;
-
-	if (dmi_check_system(i8042_dmi_kbdreset_table))
-		i8042_kbdreset = true;
+	retval = i8042_pnp_init();
+	if (retval)
+		return retval;
 
+#ifdef CONFIG_X86
 	/*
 	 * A20 was already enabled during early kernel init. But some buggy
 	 * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
--- linux-ein-5.4.0.orig/drivers/input/serio/i8042.c
+++ linux-ein-5.4.0/drivers/input/serio/i8042.c
@@ -44,6 +44,10 @@
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
+static bool i8042_probe_defer;
+module_param_named(probe_defer, i8042_probe_defer, bool, 0);
+MODULE_PARM_DESC(probe_defer, "Allow deferred probing.");
+
 enum i8042_controller_reset_mode {
 	I8042_RESET_NEVER,
 	I8042_RESET_ALWAYS,
@@ -121,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];
@@ -341,6 +346,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);
@@ -611,7 +619,7 @@
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		i8042_ctr &= ~I8042_CTR_KBDINT;
 		i8042_ctr |= I8042_CTR_KBDDIS;
-		pr_err("Failed to enable KBD port\n");
+		pr_info("Failed to enable KBD port\n");
 		return -EIO;
 	}
 
@@ -630,7 +638,7 @@
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		i8042_ctr &= ~I8042_CTR_AUXINT;
 		i8042_ctr |= I8042_CTR_AUXDIS;
-		pr_err("Failed to enable AUX port\n");
+		pr_info("Failed to enable AUX port\n");
 		return -EIO;
 	}
 
@@ -705,7 +713,7 @@
  * LCS/Telegraphics.
  */
 
-static int __init i8042_check_mux(void)
+static int i8042_check_mux(void)
 {
 	unsigned char mux_version;
 
@@ -722,7 +730,7 @@
 	i8042_ctr &= ~I8042_CTR_AUXINT;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		pr_err("Failed to disable AUX port, can't use MUX\n");
+		pr_info("Failed to disable AUX port, can't use MUX\n");
 		return -EIO;
 	}
 
@@ -734,10 +742,10 @@
 /*
  * The following is used to test AUX IRQ delivery.
  */
-static struct completion i8042_aux_irq_delivered __initdata;
-static bool i8042_irq_being_tested __initdata;
+static struct completion i8042_aux_irq_delivered;
+static bool i8042_irq_being_tested;
 
-static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
+static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id)
 {
 	unsigned long flags;
 	unsigned char str, data;
@@ -764,7 +772,7 @@
  * verifies success by readinng CTR. Used when testing for presence of AUX
  * port.
  */
-static int __init i8042_toggle_aux(bool on)
+static int i8042_toggle_aux(bool on)
 {
 	unsigned char param;
 	int i;
@@ -792,7 +800,7 @@
  * the presence of an AUX interface.
  */
 
-static int __init i8042_check_aux(void)
+static int i8042_check_aux(void)
 {
 	int retval = -1;
 	bool irq_registered = false;
@@ -937,25 +945,28 @@
 {
 	unsigned char param;
 	int i = 0;
+	int ret;
 
 	/*
 	 * We try this 5 times; on some really fragile systems this does not
 	 * take the first time...
 	 */
-	do {
-
-		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
-			pr_err("i8042 controller selftest timeout\n");
-			return -ENODEV;
-		}
+	while (i++ < 5) {
 
-		if (param == I8042_RET_CTL_TEST)
+		ret = i8042_command(&param, I8042_CMD_CTL_TEST);
+		if (ret)
+			pr_info("i8042 controller selftest timeout (%d/5)\n", i);
+		else if (param == I8042_RET_CTL_TEST)
 			return 0;
+		else
+			dbg("i8042 controller selftest: %#x != %#x\n",
+			    param, I8042_RET_CTL_TEST);
 
-		dbg("i8042 controller selftest: %#x != %#x\n",
-		    param, I8042_RET_CTL_TEST);
 		msleep(50);
-	} while (i++ < 5);
+	}
+
+	if (ret)
+		return -ENODEV;
 
 #ifdef CONFIG_X86
 	/*
@@ -967,7 +978,7 @@
 	pr_info("giving up on controller selftest, continuing anyway...\n");
 	return 0;
 #else
-	pr_err("i8042 controller selftest failed\n");
+	pr_info("i8042 controller selftest failed\n");
 	return -EIO;
 #endif
 }
@@ -999,7 +1010,7 @@
 
 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
 			pr_err("Can't read CTR while initializing i8042\n");
-			return -EIO;
+			return i8042_probe_defer ? -EPROBE_DEFER : -EIO;
 		}
 
 	} while (n < 2 || ctr[0] != ctr[1]);
@@ -1314,7 +1325,7 @@
 	i8042_controller_reset(false);
 }
 
-static int __init i8042_create_kbd_port(void)
+static int i8042_create_kbd_port(void)
 {
 	struct serio *serio;
 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
@@ -1342,7 +1353,7 @@
 	return 0;
 }
 
-static int __init i8042_create_aux_port(int idx)
+static int i8042_create_aux_port(int idx)
 {
 	struct serio *serio;
 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
@@ -1379,13 +1390,13 @@
 	return 0;
 }
 
-static void __init i8042_free_kbd_port(void)
+static void i8042_free_kbd_port(void)
 {
 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
 }
 
-static void __init i8042_free_aux_ports(void)
+static void i8042_free_aux_ports(void)
 {
 	int i;
 
@@ -1395,7 +1406,7 @@
 	}
 }
 
-static void __init i8042_register_ports(void)
+static void i8042_register_ports(void)
 {
 	int i;
 
@@ -1436,7 +1447,7 @@
 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
 }
 
-static int __init i8042_setup_aux(void)
+static int i8042_setup_aux(void)
 {
 	int (*aux_enable)(void);
 	int error;
@@ -1464,7 +1475,8 @@
 	if (error)
 		goto err_free_ports;
 
-	if (aux_enable())
+	error = aux_enable();
+	if (error)
 		goto err_free_irq;
 
 	i8042_aux_irq_registered = true;
@@ -1477,7 +1489,7 @@
 	return error;
 }
 
-static int __init i8042_setup_kbd(void)
+static int i8042_setup_kbd(void)
 {
 	int error;
 
@@ -1527,12 +1539,10 @@
 	return 0;
 }
 
-static int __init i8042_probe(struct platform_device *dev)
+static int i8042_probe(struct platform_device *dev)
 {
 	int error;
 
-	i8042_platform_device = dev;
-
 	if (i8042_reset == I8042_RESET_ALWAYS) {
 		error = i8042_controller_selftest();
 		if (error)
@@ -1570,7 +1580,6 @@
 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
 	i8042_free_irqs();
 	i8042_controller_reset(false);
-	i8042_platform_device = NULL;
 
 	return error;
 }
@@ -1580,7 +1589,6 @@
 	i8042_unregister_ports();
 	i8042_free_irqs();
 	i8042_controller_reset(false);
-	i8042_platform_device = NULL;
 
 	return 0;
 }
@@ -1592,6 +1600,7 @@
 		.pm	= &i8042_pm_ops,
 #endif
 	},
+	.probe		= i8042_probe,
 	.remove		= i8042_remove,
 	.shutdown	= i8042_shutdown,
 };
@@ -1602,30 +1611,44 @@
 
 static int __init i8042_init(void)
 {
-	struct platform_device *pdev;
 	int err;
 
 	dbg_init();
 
 	err = i8042_platform_init();
 	if (err)
-		return err;
+		return (err == -ENODEV) ? 0 : err;
 
 	err = i8042_controller_check();
 	if (err)
 		goto err_platform_exit;
 
-	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
-	if (IS_ERR(pdev)) {
-		err = PTR_ERR(pdev);
+	/* Set this before creating the dev to allow i8042_command to work right away */
+	i8042_present = true;
+
+	err = platform_driver_register(&i8042_driver);
+	if (err)
 		goto err_platform_exit;
+
+	i8042_platform_device = platform_device_alloc("i8042", -1);
+	if (!i8042_platform_device) {
+		err = -ENOMEM;
+		goto err_unregister_driver;
 	}
 
+	err = platform_device_add(i8042_platform_device);
+	if (err)
+		goto err_free_device;
+
 	bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
 	panic_blink = i8042_panic_blink;
 
 	return 0;
 
+err_free_device:
+	platform_device_put(i8042_platform_device);
+err_unregister_driver:
+	platform_driver_unregister(&i8042_driver);
  err_platform_exit:
 	i8042_platform_exit();
 	return err;
@@ -1633,6 +1656,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-ein-5.4.0.orig/drivers/input/serio/i8042.h
+++ linux-ein-5.4.0/drivers/input/serio/i8042.h
@@ -17,8 +17,6 @@
 #include "i8042-ip22io.h"
 #elif defined(CONFIG_SNI_RM)
 #include "i8042-snirm.h"
-#elif defined(CONFIG_PPC)
-#include "i8042-ppcio.h"
 #elif defined(CONFIG_SPARC)
 #include "i8042-sparcio.h"
 #elif defined(CONFIG_X86) || defined(CONFIG_IA64)
--- linux-ein-5.4.0.orig/drivers/input/serio/serio_raw.c
+++ linux-ein-5.4.0/drivers/input/serio/serio_raw.c
@@ -159,7 +159,7 @@
 {
 	struct serio_raw_client *client = file->private_data;
 	struct serio_raw *serio_raw = client->serio_raw;
-	char uninitialized_var(c);
+	char c;
 	ssize_t read = 0;
 	int error;
 
--- linux-ein-5.4.0.orig/drivers/input/serio/sun4i-ps2.c
+++ linux-ein-5.4.0/drivers/input/serio/sun4i-ps2.c
@@ -211,7 +211,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);
@@ -264,14 +263,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-ein-5.4.0.orig/drivers/input/tablet/aiptek.c
+++ linux-ein-5.4.0/drivers/input/tablet/aiptek.c
@@ -1801,15 +1801,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-ein-5.4.0.orig/drivers/input/tablet/gtco.c
+++ linux-ein-5.4.0/drivers/input/tablet/gtco.c
@@ -875,18 +875,14 @@
 	}
 
 	/* Sanity check that a device has an endpoint */
-	if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) {
+	if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) {
 		dev_err(&usbinterface->dev,
 			"Invalid number of endpoints\n");
 		error = -EINVAL;
 		goto err_free_urb;
 	}
 
-	/*
-	 * 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;
+	endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
 
 	/* Some debug */
 	dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
@@ -973,7 +969,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,
 			 udev,
--- linux-ein-5.4.0.orig/drivers/input/tablet/pegasus_notetaker.c
+++ linux-ein-5.4.0/drivers/input/tablet/pegasus_notetaker.c
@@ -275,7 +275,7 @@
 		return -ENODEV;
 
 	/* Sanity check that the device has an endpoint */
-	if (intf->altsetting[0].desc.bNumEndpoints < 1) {
+	if (intf->cur_altsetting->desc.bNumEndpoints < 1) {
 		dev_err(&intf->dev, "Invalid number of endpoints\n");
 		return -EINVAL;
 	}
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/Kconfig
+++ linux-ein-5.4.0/drivers/input/touchscreen/Kconfig
@@ -96,6 +96,7 @@
 config TOUCHSCREEN_ADC
 	tristate "Generic ADC based resistive touchscreen"
 	depends on IIO
+	select IIO_BUFFER
 	select IIO_BUFFER_CB
 	help
 	  Say Y here if you want to use the generic ADC
@@ -1315,3 +1316,5 @@
 	  module will be called iqs5xx.
 
 endif
+
+source "drivers/input/touchscreen/focaltech_touch/Kconfig"
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/Makefile
+++ linux-ein-5.4.0/drivers/input/touchscreen/Makefile
@@ -42,6 +42,7 @@
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
 obj-$(CONFIG_TOUCHSCREEN_EXC3000)	+= exc3000.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)		+= focaltech_touch/
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
 obj-$(CONFIG_TOUCHSCREEN_HIDEEP)	+= hideep.o
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/ads7846.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/ads7846.c
@@ -33,6 +33,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
@@ -199,6 +200,26 @@
 #define	REF_ON	(READ_12BIT_DFR(x, 1, 1))
 #define	REF_OFF	(READ_12BIT_DFR(y, 0, 0))
 
+static int get_pendown_state(struct ads7846 *ts)
+{
+	if (ts->get_pendown_state)
+		return ts->get_pendown_state();
+
+	return !gpio_get_value(ts->gpio_pendown);
+}
+
+static void ads7846_report_pen_up(struct ads7846 *ts)
+{
+	struct input_dev *input = ts->input;
+
+	input_report_key(input, BTN_TOUCH, 0);
+	input_report_abs(input, ABS_PRESSURE, 0);
+	input_sync(input);
+
+	ts->pendown = false;
+	dev_vdbg(&ts->spi->dev, "UP\n");
+}
+
 /* Must be called with ts->lock held */
 static void ads7846_stop(struct ads7846 *ts)
 {
@@ -215,6 +236,10 @@
 static void ads7846_restart(struct ads7846 *ts)
 {
 	if (!ts->disabled && !ts->suspended) {
+		/* Check if pen was released since last stop */
+		if (ts->pendown && !get_pendown_state(ts))
+			ads7846_report_pen_up(ts);
+
 		/* Tell IRQ thread that it may poll the device. */
 		ts->stopped = false;
 		mb();
@@ -410,7 +435,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;
 	}
@@ -605,14 +630,6 @@
 
 /*--------------------------------------------------------------------------*/
 
-static int get_pendown_state(struct ads7846 *ts)
-{
-	if (ts->get_pendown_state)
-		return ts->get_pendown_state();
-
-	return !gpio_get_value(ts->gpio_pendown);
-}
-
 static void null_wait_for_sync(void)
 {
 }
@@ -773,22 +790,17 @@
 	if (x == MAX_12BIT)
 		x = 0;
 
-	if (ts->model == 7843) {
+	if (ts->model == 7843 || ts->model == 7845) {
 		Rt = ts->pressure_max / 2;
-	} else if (ts->model == 7845) {
-		if (get_pendown_state(ts))
-			Rt = ts->pressure_max / 2;
-		else
-			Rt = 0;
-		dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
 	} else if (likely(x && z1)) {
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
 		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;
 	}
@@ -867,16 +879,8 @@
 				   msecs_to_jiffies(TS_POLL_PERIOD));
 	}
 
-	if (ts->pendown && !ts->stopped) {
-		struct input_dev *input = ts->input;
-
-		input_report_key(input, BTN_TOUCH, 0);
-		input_report_abs(input, ABS_PRESSURE, 0);
-		input_sync(input);
-
-		ts->pendown = false;
-		dev_vdbg(&ts->spi->dev, "UP\n");
-	}
+	if (ts->pendown && !ts->stopped)
+		ads7846_report_pen_up(ts);
 
 	return IRQ_HANDLED;
 }
@@ -1366,8 +1370,9 @@
 			pdata->y_min ? : 0,
 			pdata->y_max ? : MAX_12BIT,
 			0, 0);
-	input_set_abs_params(input_dev, ABS_PRESSURE,
-			pdata->pressure_min, pdata->pressure_max, 0, 0);
+	if (ts->model != 7845)
+		input_set_abs_params(input_dev, ABS_PRESSURE,
+				pdata->pressure_min, pdata->pressure_max, 0, 0);
 
 	/*
 	 * Parse common framework properties. Must be done here to ensure the
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/atmel_mxt_ts.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1794,7 +1794,7 @@
 	if (error) {
 		dev_err(&client->dev, "Error %d parsing object table\n", error);
 		mxt_free_object_table(data);
-		goto err_free_mem;
+		return error;
 	}
 
 	data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
@@ -3156,6 +3156,8 @@
 
 	mutex_unlock(&input_dev->mutex);
 
+	disable_irq(data->irq);
+
 	return 0;
 }
 
@@ -3168,6 +3170,8 @@
 	if (!input_dev)
 		return 0;
 
+	enable_irq(data->irq);
+
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/edt-ft5x06.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/edt-ft5x06.c
@@ -935,19 +935,25 @@
 
 	error = device_property_read_u32(dev, "offset", &val);
 	if (!error) {
-		edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
+		if (reg_addr->reg_offset != NO_REGISTER)
+			edt_ft5x06_register_write(tsdata,
+						  reg_addr->reg_offset, val);
 		tsdata->offset = val;
 	}
 
 	error = device_property_read_u32(dev, "offset-x", &val);
 	if (!error) {
-		edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val);
+		if (reg_addr->reg_offset_x != NO_REGISTER)
+			edt_ft5x06_register_write(tsdata,
+						  reg_addr->reg_offset_x, val);
 		tsdata->offset_x = val;
 	}
 
 	error = device_property_read_u32(dev, "offset-y", &val);
 	if (!error) {
-		edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val);
+		if (reg_addr->reg_offset_y != NO_REGISTER)
+			edt_ft5x06_register_write(tsdata,
+						  reg_addr->reg_offset_y, val);
 		tsdata->offset_y = val;
 	}
 }
@@ -1041,6 +1047,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;
@@ -1110,6 +1117,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-ein-5.4.0.orig/drivers/input/touchscreen/elants_i2c.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/elants_i2c.c
@@ -36,6 +36,7 @@
 #include <linux/of.h>
 #include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
+#include <linux/uuid.h>
 #include <asm/unaligned.h>
 
 /* Device, Driver information */
@@ -1077,14 +1078,12 @@
 	if (IS_ERR_OR_NULL(ts->reset_gpio))
 		return 0;
 
-	gpiod_set_value_cansleep(ts->reset_gpio, 1);
-
 	error = regulator_enable(ts->vcc33);
 	if (error) {
 		dev_err(&ts->client->dev,
 			"failed to enable vcc33 regulator: %d\n",
 			error);
-		goto release_reset_gpio;
+		return error;
 	}
 
 	error = regulator_enable(ts->vccio);
@@ -1093,7 +1092,7 @@
 			"failed to enable vccio regulator: %d\n",
 			error);
 		regulator_disable(ts->vcc33);
-		goto release_reset_gpio;
+		return error;
 	}
 
 	/*
@@ -1102,7 +1101,6 @@
 	 */
 	udelay(ELAN_POWERON_DELAY_USEC);
 
-release_reset_gpio:
 	gpiod_set_value_cansleep(ts->reset_gpio, 0);
 	if (error)
 		return error;
@@ -1127,6 +1125,40 @@
 	}
 }
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id i2c_hid_ids[] = {
+	{"ACPI0C50", 0 },
+	{"PNP0C50", 0 },
+	{ },
+};
+
+static const guid_t i2c_hid_guid =
+	GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
+		  0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
+
+static bool elants_acpi_is_hid_device(struct device *dev)
+{
+	acpi_handle handle = ACPI_HANDLE(dev);
+	union acpi_object *obj;
+
+	if (acpi_match_device_ids(ACPI_COMPANION(dev), i2c_hid_ids))
+		return false;
+
+	obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, ACPI_TYPE_INTEGER);
+	if (obj) {
+		ACPI_FREE(obj);
+		return true;
+	}
+
+	return false;
+}
+#else
+static bool elants_acpi_is_hid_device(struct device *dev)
+{
+	return false;
+}
+#endif
+
 static int elants_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
@@ -1135,9 +1167,14 @@
 	unsigned long irqflags;
 	int error;
 
+	/* Don't bind to i2c-hid compatible devices, these are handled by the i2c-hid drv. */
+	if (elants_acpi_is_hid_device(&client->dev)) {
+		dev_warn(&client->dev, "This device appears to be an I2C-HID device, not binding\n");
+		return -ENODEV;
+	}
+
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		dev_err(&client->dev,
-			"%s: i2c check functionality error\n", DEVICE_NAME);
+		dev_err(&client->dev, "I2C check functionality error\n");
 		return -ENXIO;
 	}
 
@@ -1171,7 +1208,7 @@
 		return error;
 	}
 
-	ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW);
+	ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
 	if (IS_ERR(ts->reset_gpio)) {
 		error = PTR_ERR(ts->reset_gpio);
 
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/elo.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/elo.c
@@ -341,8 +341,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-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/Kconfig
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/Kconfig
@@ -0,0 +1,16 @@
+#
+# Focaltech Touchscreen driver configuration
+#
+
+config TOUCHSCREEN_FTS
+        bool "Focaltech Touchscreen"
+		depends on I2C
+		default n
+		help
+		  Say Y here if you have Focaltech touch panel.
+		  If unsure, say N.
+
+config TOUCHSCREEN_FTS_DIRECTORY
+    string "Focaltech ts directory name"
+    default "focaltech_touch"
+    depends on TOUCHSCREEN_FTS
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/Makefile
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the focaltech touchscreen drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_TOUCHSCREEN_FTS)	+=  focaltech_core.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)	+=  focaltech_esdcheck.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)	+=  focaltech_ex_mode.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)	+=  focaltech_gesture.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)   +=  focaltech_point_report_check.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)   +=  focaltech_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_FTS)   +=  focaltech_sensor.o
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_common.h
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_common.h
@@ -0,0 +1,211 @@
+/*
+ *
+ * FocalTech fts TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, Focaltech Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+/*****************************************************************************
+*
+* File Name: focaltech_common.h
+*
+* Author: Focaltech Driver Team
+*
+* Created: 2016-08-16
+*
+* Abstract:
+*
+* Reference:
+*
+*****************************************************************************/
+
+#ifndef __LINUX_FOCALTECH_COMMON_H__
+#define __LINUX_FOCALTECH_COMMON_H__
+
+#include "focaltech_config.h"
+
+/*****************************************************************************
+* Macro definitions using #define
+*****************************************************************************/
+#define FTS_DRIVER_VERSION	"Focaltech V1.2 20161229"
+
+#define FLAGBIT(x)		(0x00000001 << (x))
+#define FLAGBITS(x, y)		((0xFFFFFFFF >> (32 - (y) - 1)) << (x))
+
+#define FLAG_ICSERIALS_LEN      5
+#define FLAG_IDC_BIT            11
+
+#define FTS_CHIP_TYPE_MAPPING { \
+	{0x01, 0x58, 0x22, 0x58, 0x22, 0x00, 0x00, 0x58, 0x2C}, \
+	{0x02, 0x54, 0x22, 0x54, 0x22, 0x00, 0x00, 0x54, 0x2C}, \
+	{0x03, 0x64, 0x26, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \
+	{0x04, 0x33, 0x67, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \
+	{0x05, 0x87, 0x16, 0x87, 0x16, 0x87, 0xA6, 0x00, 0x00}, \
+	{0x06, 0x87, 0x36, 0x87, 0x36, 0x87, 0xC6, 0x00, 0x00}, \
+	{0x07, 0x80, 0x06, 0x80, 0x06, 0x80, 0xC6, 0x80, 0xB6}, \
+	{0x08, 0x86, 0x06, 0x86, 0x06, 0x86, 0xA6, 0x00, 0x00}, \
+	{0x09, 0x86, 0x07, 0x86, 0x07, 0x86, 0xA7, 0x00, 0x00}, \
+	{0x0A, 0xE7, 0x16, 0x87, 0x16, 0xE7, 0xA6, 0x87, 0xB6}, \
+}
+
+#define I2C_BUFFER_LENGTH_MAXINUM           256
+#define FILE_NAME_LENGTH                    128
+#define ENABLE                              1
+#define DISABLE                             0
+/*register address*/
+#define FTS_REG_INT_CNT                     0x8F
+#define FTS_REG_FLOW_WORK_CNT               0x91
+#define FTS_REG_WORKMODE                    0x00
+#define FTS_REG_WORKMODE_FACTORY_VALUE      0x40
+#define FTS_REG_WORKMODE_WORK_VALUE         0x00
+#define FTS_REG_CHIP_ID                     0xA3
+#define FTS_REG_CHIP_ID2                    0x9F
+#define FTS_REG_POWER_MODE                  0xA5
+#define FTS_REG_POWER_MODE_SLEEP_VALUE      0x03
+#define FTS_REG_FW_VER                      0xA6
+#define FTS_REG_VENDOR_ID                   0xA8
+#define FTS_REG_LCD_BUSY_NUM                0xAB
+#define FTS_REG_FACE_DEC_MODE_EN            0xB0
+#define FTS_REG_GLOVE_MODE_EN               0xC0
+#define FTS_REG_COVER_MODE_EN               0xC1
+#define FTS_REG_CHARGER_MODE_EN             0x8B
+#define FTS_REG_GESTURE_EN                  0xD0
+#define FTS_REG_GESTURE_OUTPUT_ADDRESS      0xD3
+#define FTS_REG_ESD_SATURATE                0xED
+
+/*****************************************************************************
+*  Alternative mode (When something goes wrong, the modules may be able to solve the problem.)
+*****************************************************************************/
+/*
+ * point report check
+ * default: disable
+ */
+#define FTS_POINT_REPORT_CHECK_EN               0
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+struct ft_chip_t {
+	unsigned long type;
+	unsigned char chip_idh;
+	unsigned char chip_idl;
+	unsigned char rom_idh;
+	unsigned char rom_idl;
+	unsigned char pramboot_idh;
+	unsigned char pramboot_idl;
+	unsigned char bootloader_idh;
+	unsigned char bootloader_idl;
+};
+
+/* i2c communication*/
+int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue);
+int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue);
+int fts_i2c_read(struct i2c_client *client, char *writebuf, int writelen,
+		 char *readbuf, int readlen);
+int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen);
+int fts_i2c_init(void);
+int fts_i2c_exit(void);
+
+/* Gesture functions */
+#if FTS_GESTURE_EN
+int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client);
+int fts_gesture_exit(struct i2c_client *client);
+void fts_gesture_recovery(struct i2c_client *client);
+int fts_gesture_readdata(struct i2c_client *client);
+int fts_gesture_suspend(struct i2c_client *i2c_client);
+int fts_gesture_resume(struct i2c_client *client);
+#endif
+
+/* Apk and functions */
+#if FTS_APK_NODE_EN
+int fts_create_apk_debug_channel(struct i2c_client *client);
+void fts_release_apk_debug_channel(void);
+#endif
+
+/* ADB functions */
+#if FTS_SYSFS_NODE_EN
+int fts_create_sysfs(struct i2c_client *client);
+int fts_remove_sysfs(struct i2c_client *client);
+#endif
+
+/* ESD */
+#if FTS_ESDCHECK_EN
+int fts_esdcheck_init(void);
+int fts_esdcheck_exit(void);
+int fts_esdcheck_switch(bool enable);
+int fts_esdcheck_proc_busy(bool proc_debug);
+int fts_esdcheck_set_intr(bool intr);
+int fts_esdcheck_suspend(void);
+int fts_esdcheck_resume(void);
+int fts_esdcheck_get_status(void);
+#endif
+
+/* Production test */
+#if FTS_TEST_EN
+int fts_test_init(struct i2c_client *client);
+int fts_test_exit(struct i2c_client *client);
+#endif
+
+/* Point Report Check*/
+#if FTS_POINT_REPORT_CHECK_EN
+int fts_point_report_check_init(void);
+int fts_point_report_check_exit(void);
+void fts_point_report_check_queue_work(void);
+#endif
+
+/* Other */
+extern int g_show_log;
+int fts_reset_proc(int hdelayms);
+int fts_wait_tp_to_valid(struct i2c_client *client);
+void fts_tp_state_recovery(struct i2c_client *client);
+int fts_ex_mode_init(struct i2c_client *client);
+int fts_ex_mode_exit(struct i2c_client *client);
+int fts_ex_mode_recovery(struct i2c_client *client);
+
+void fts_irq_disable(void);
+void fts_irq_enable(void);
+
+/*****************************************************************************
+* DEBUG function define here
+*****************************************************************************/
+#if FTS_DEBUG_EN
+#define FTS_DEBUG_LEVEL     1
+
+#if (FTS_DEBUG_LEVEL == 2)
+#define FTS_DEBUG(fmt, args...) \
+	printk(KERN_ERR "[FTS][%s]"fmt"\n", __func__, ##args)
+#else
+#define FTS_DEBUG(fmt, args...) \
+	printk(KERN_ERR "[FTS]"fmt"\n", ##args)
+#endif
+
+#define FTS_FUNC_ENTER() \
+	printk(KERN_ERR "[FTS]%s: Enter\n", __func__)
+#define FTS_FUNC_EXIT() \
+	printk(KERN_ERR "[FTS]%s: Exit(%d)\n", __func__, __LINE__)
+#else
+#define FTS_DEBUG(fmt, args...)
+#define FTS_FUNC_ENTER()
+#define FTS_FUNC_EXIT()
+#endif
+
+#define FTS_INFO(fmt, args...) do {	\
+		if (g_show_log) \
+			printk(KERN_ERR "[FTS][Info]"fmt"\n", ##args); \
+	} while (0)
+
+#define FTS_ERROR(fmt, args...)  do {	\
+		if (g_show_log) \
+			printk(KERN_ERR "[FTS][Error]"fmt"\n", ##args); \
+	} while (0)
+
+#endif /* __LINUX_FOCALTECH_COMMON_H__ */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_config.h
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_config.h
@@ -0,0 +1,219 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+/************************************************************************
+*
+* File Name: focaltech_config.h
+*
+*    Author: Focaltech Driver Team
+*
+*   Created: 2016-08-08
+*
+*  Abstract: global configurations
+*
+*   Version: v1.0
+*
+************************************************************************/
+#ifndef _LINUX_FOCLATECH_CONFIG_H_
+#define _LINUX_FOCLATECH_CONFIG_H_
+
+/**************************************************/
+/****** G: A, I: B, S: C, U: D  ******************/
+/****** chip type defines, do not modify *********/
+#define _FT8716     0x87160805
+#define _FT8736     0x87360806
+#define _FT8006     0x80060807
+#define _FT8606     0x86060808
+#define _FT8607     0x86070809
+#define _FTE716     0xE716080a
+
+#define _FT5416     0x54160002
+#define _FT5426     0x54260002
+#define _FT5435     0x54350002
+#define _FT5436     0x54360002
+#define _FT5526     0x55260002
+#define _FT5526I    0x5526B002
+#define _FT5446     0x54460002
+#define _FT5346     0x53460002
+#define _FT5446I    0x5446B002
+#define _FT5346I    0x5346B002
+#define _FT7661     0x76610002
+#define _FT7511     0x75110002
+#define _FT7421     0x74210002
+#define _FT7681     0x76810002
+#define _FT3C47U    0x3C47D002
+#define _FT3417     0x34170002
+#define _FT3517     0x35170002
+#define _FT3327     0x33270002
+#define _FT3427     0x34270002
+
+#define _FT5626     0x56260001
+#define _FT5726     0x57260001
+#define _FT5826B    0x5826B001
+#define _FT5826S    0x5826C001
+#define _FT7811     0x78110001
+#define _FT3D47     0x3D470001
+#define _FT3617     0x36170001
+#define _FT3717     0x37170001
+#define _FT3817B    0x3817B001
+
+#define _FT6236U    0x6236D003
+#define _FT6336G    0x6336A003
+#define _FT6336U    0x6336D003
+#define _FT6436U    0x6436D003
+
+#define _FT3267     0x32670004
+#define _FT3367     0x33670004
+
+/******************* Enables *********************/
+/*********** 1 to enable, 0 to disable ***********/
+
+/*
+ * show debug log info
+ * enable it for debug, disable it for release
+ */
+#define FTS_DEBUG_EN                            0
+
+/*
+ * Linux MultiTouch Protocol
+ * 1: Protocol B(default), 0: Protocol A
+ */
+#define FTS_MT_PROTOCOL_B_EN                    1
+
+/*
+ * Report Pressure in multitouch
+ * 1:enable(default),0:disable
+*/
+#define FTS_REPORT_PRESSURE_EN                  1
+
+/*
+ * Force touch support
+ * different pressure for multitouch
+ * 1: true pressure for force touch
+ * 0: constant pressure(default)
+ */
+#define FTS_FORCE_TOUCH_EN                      0
+
+/*
+ * Gesture function enable
+ * default: disable
+ */
+#define FTS_GESTURE_EN                          0
+
+/*
+ * ESD check & protection
+ * default: disable
+ */
+#define FTS_ESDCHECK_EN                         0
+
+/*
+ * Production test enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_TEST_EN                             0
+
+/*
+ * Glove mode enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_GLOVE_EN                            0
+/*
+ * cover enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_COVER_EN                            0
+/*
+ * Charger enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_CHARGER_EN                          0
+
+/*
+ * Proximity sensor
+ * default: disable
+ */
+#define FTS_PSENSOR_EN                          0
+
+/*
+ * Nodes for tools, please keep enable
+ */
+#define FTS_SYSFS_NODE_EN                       1
+#define FTS_APK_NODE_EN                         1
+
+/*
+ * Customer power enable
+ * enable it when customer need control TP power
+ * default: disable
+ */
+#define FTS_POWER_SOURCE_CUST_EN                0
+
+/****************************************************/
+
+/********************** Upgrade ****************************/
+/*
+ * auto upgrade, please keep enable
+ */
+#define FTS_AUTO_UPGRADE_EN                     1
+
+/*
+ * auto upgrade for lcd cfg
+ * default: 0
+ */
+#define FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN         0
+
+/* auto cb check
+ * default: disable
+ */
+#define FTS_AUTO_CLB_EN                         0
+
+/*
+ * FW_APP.i file for upgrade
+ * define your own fw_app, the sample one is invalid
+ */
+#define FTS_UPGRADE_FW_APP                      "include/firmware/FT8716_app_sample.i"
+
+/*
+ * lcd_cfg.i file for lcd cfg upgrade
+ * define your own lcd_cfg.i, the sample one is invalid
+ */
+#define FTS_UPGRADE_LCD_CFG                     "include/firmware/lcd_cfg.i"
+
+/* get vedor id from flash
+ * default: enable
+ */
+#define FTS_GET_VENDOR_ID                       0
+
+/*
+ * vendor_id(s) for the ic
+ * you need confirm vendor_id for upgrade
+ * if only one vendor, ignore vendor_2_id, otherwise
+ * you need define both of them
+ */
+#define FTS_VENDOR_1_ID                         0x8d
+#define FTS_VENDOR_2_ID                         0x8d
+
+/*
+ * upgrade stress test for debug
+ * enable it for upgrade debug if needed
+ * default: disable
+ */
+#define FTS_UPGRADE_STRESS_TEST					0
+/* stress test times, default: 1000 */
+#define FTS_UPGRADE_TEST_NUMBER                 1000
+
+/*********************************************************/
+
+#endif /* _LINUX_FOCLATECH_CONFIG_H_ */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
@@ -0,0 +1,1439 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+/*****************************************************************************
+*
+* File Name: focaltech_core.c
+*
+* Author: Focaltech Driver Team
+*
+* Created: 2016-08-08
+*
+* Abstract:
+*
+* Reference:
+*
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#define FTS_SUSPEND_LEVEL 1	/* Early-suspend level */
+#endif
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define FTS_DRIVER_NAME                     "fts_ts"
+#define INTERVAL_READ_REG                   20
+#define TIMEOUT_READ_REG                    300
+#if FTS_POWER_SOURCE_CUST_EN
+#define FTS_VTG_MIN_UV                      2600000
+#define FTS_VTG_MAX_UV                      3300000
+#define FTS_I2C_VTG_MIN_UV                  1800000
+#define FTS_I2C_VTG_MAX_UV                  1800000
+#endif
+#define FTS_READ_TOUCH_BUFFER_DIVIDED       0
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+******************************************************************************/
+struct i2c_client *fts_i2c_client;
+struct fts_ts_data *fts_wq_data;
+struct input_dev *fts_input_dev;
+
+#if FTS_DEBUG_EN
+int g_show_log = 1;
+#else
+int g_show_log;
+#endif
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+char g_sz_debug[1024] = { 0 };
+#endif
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+static void fts_release_all_finger(void);
+static int fts_ts_suspend(struct device *dev);
+static int fts_ts_resume(struct device *dev);
+
+static bool fts_chip_idc(struct fts_ts_data *data)
+{
+	return ((data->pdata->fts_chip_type & FLAGBIT(FLAG_IDC_BIT)) ==
+		FLAGBIT(FLAG_IDC_BIT));
+}
+
+/*****************************************************************************
+*  Name: fts_wait_tp_to_valid
+*  Brief:   Read chip id until TP FW become valid,
+*	    need call when reset/power on/resume...
+*           1. Read Chip ID per INTERVAL_READ_REG(20ms)
+*           2. Timeout: TIMEOUT_READ_REG(300ms)
+*  Input:
+*  Output:
+*  Return: 0 - Get correct Device ID
+*****************************************************************************/
+int fts_wait_tp_to_valid(struct i2c_client *client)
+{
+	int ret = 0;
+	int cnt = 0;
+	u8 reg_value = 0;
+
+	do {
+		ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, &reg_value);
+		if (ret < 0)
+			FTS_INFO("TP Not Ready, ReadData = 0x%x", reg_value);
+		else {
+			FTS_INFO("TP Ready, Device ID = 0x%x", reg_value);
+			return 0;
+		}
+		cnt++;
+		msleep(INTERVAL_READ_REG);
+	} while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
+
+	/* error: not get correct reg data */
+	return -1;
+}
+
+/*****************************************************************************
+*  Name: fts_recover_state
+*  Brief: Need execute this function when reset
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+void fts_tp_state_recovery(struct i2c_client *client)
+{
+	/* wait tp stable */
+	fts_wait_tp_to_valid(client);
+	/* recover TP charger state 0x8B */
+	/* recover TP glove state 0xC0 */
+	/* recover TP cover state 0xC1 */
+	fts_ex_mode_recovery(client);
+	/* recover TP gesture state 0xD0 */
+#if FTS_GESTURE_EN
+	fts_gesture_recovery(client);
+#endif
+
+	fts_release_all_finger();
+}
+
+/*****************************************************************************
+*  Name: fts_reset_proc
+*  Brief: Execute reset operation
+*  Input: hdelayms - delay time unit:ms
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_reset_proc(int hdelayms)
+{
+	gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0);
+	msleep(20);
+	gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1);
+	msleep(hdelayms);
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_irq_disable
+*  Brief: disable irq
+*  Input:
+*   sync:
+*  Output:
+*  Return:
+*****************************************************************************/
+void fts_irq_disable(void)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags);
+
+	if (!fts_wq_data->irq_disable) {
+		disable_irq_nosync(fts_wq_data->client->irq);
+		fts_wq_data->irq_disable = 1;
+	}
+
+	spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags);
+}
+
+/*****************************************************************************
+*  Name: fts_irq_enable
+*  Brief: enable irq
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+void fts_irq_enable(void)
+{
+	unsigned long irqflags = 0;
+
+	spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags);
+
+	if (fts_wq_data->irq_disable) {
+		enable_irq(fts_wq_data->client->irq);
+		fts_wq_data->irq_disable = 0;
+	}
+
+	spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags);
+}
+
+/*****************************************************************************
+*  Name: fts_input_dev_init
+*  Brief: input dev init
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_input_dev_init(struct i2c_client *client,
+			      struct fts_ts_data *data,
+			      struct input_dev *input_dev,
+			      struct fts_ts_platform_data *pdata)
+{
+	int err, len;
+
+	FTS_FUNC_ENTER();
+
+	/* Init and register Input device */
+	input_dev->name = FTS_DRIVER_NAME;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_set_drvdata(input_dev, data);
+	i2c_set_clientdata(client, data);
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	if (data->pdata->have_key) {
+		FTS_DEBUG("set key capabilities");
+		for (len = 0; len < data->pdata->key_number; len++) {
+			input_set_capability(input_dev, EV_KEY,
+					     data->pdata->keys[len]);
+		}
+	}
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+#if FTS_MT_PROTOCOL_B_EN
+	input_mt_init_slots(input_dev, pdata->max_touch_number,
+			    INPUT_MT_DIRECT);
+#else
+	input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0f, 0, 0);
+#endif
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
+			     pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
+			     pdata->y_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0);
+#if FTS_REPORT_PRESSURE_EN
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0);
+#endif
+
+	err = input_register_device(input_dev);
+	if (err) {
+		FTS_ERROR("Input device registration failed");
+		goto free_inputdev;
+	}
+
+	FTS_FUNC_EXIT();
+
+	return 0;
+
+free_inputdev:
+	input_free_device(input_dev);
+	FTS_FUNC_EXIT();
+	return err;
+
+}
+
+/*****************************************************************************
+* Power Control
+*****************************************************************************/
+#if FTS_POWER_SOURCE_CUST_EN
+static int fts_power_source_init(struct fts_ts_data *data)
+{
+	int rc;
+
+	FTS_FUNC_ENTER();
+
+	data->vdd = regulator_get(&data->client->dev, "vdd");
+	if (IS_ERR(data->vdd)) {
+		rc = PTR_ERR(data->vdd);
+		FTS_ERROR("Regulator get failed vdd rc=%d", rc);
+	}
+
+	if (regulator_count_voltages(data->vdd) > 0) {
+		rc = regulator_set_voltage(data->vdd, FTS_VTG_MIN_UV,
+					   FTS_VTG_MAX_UV);
+		if (rc) {
+			FTS_ERROR("Regulator set_vtg failed vdd rc=%d", rc);
+			goto reg_vdd_put;
+		}
+	}
+
+	data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
+	if (IS_ERR(data->vcc_i2c)) {
+		rc = PTR_ERR(data->vcc_i2c);
+		FTS_ERROR("Regulator get failed vcc_i2c rc=%d", rc);
+		goto reg_vdd_set_vtg;
+	}
+
+	if (regulator_count_voltages(data->vcc_i2c) > 0) {
+		rc = regulator_set_voltage(data->vcc_i2c, FTS_I2C_VTG_MIN_UV,
+					   FTS_I2C_VTG_MAX_UV);
+		if (rc) {
+			FTS_ERROR("Regulator set_vtg failed vcc_i2c rc=%d", rc);
+			goto reg_vcc_i2c_put;
+		}
+	}
+
+	FTS_FUNC_EXIT();
+	return 0;
+
+reg_vcc_i2c_put:
+	regulator_put(data->vcc_i2c);
+reg_vdd_set_vtg:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, FTS_VTG_MAX_UV);
+reg_vdd_put:
+	regulator_put(data->vdd);
+	FTS_FUNC_EXIT();
+	return rc;
+}
+
+static int fts_power_source_ctrl(struct fts_ts_data *data, int enable)
+{
+	int rc;
+
+	FTS_FUNC_ENTER();
+	if (enable) {
+		rc = regulator_enable(data->vdd);
+		if (rc)
+			FTS_ERROR("Regulator vdd enable failed rc=%d", rc);
+
+		rc = regulator_enable(data->vcc_i2c);
+		if (rc)
+			FTS_ERROR("Regulator vcc_i2c enable failed rc=%d", rc);
+	} else {
+		rc = regulator_disable(data->vdd);
+		if (rc)
+			FTS_ERROR("Regulator vdd disable failed rc=%d", rc);
+		rc = regulator_disable(data->vcc_i2c);
+		if (rc)
+			FTS_ERROR("Regulator vcc_i2c disable failed rc=%d", rc);
+	}
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+#endif
+
+/*****************************************************************************
+*  Reprot related
+*****************************************************************************/
+/*****************************************************************************
+*  Name: fts_release_all_finger
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_release_all_finger(void)
+{
+#if FTS_MT_PROTOCOL_B_EN
+	unsigned int finger_count = 0;
+
+	for (finger_count = 0;
+	     finger_count < fts_wq_data->pdata->max_touch_number;
+	     finger_count++) {
+		input_mt_slot(fts_input_dev, finger_count);
+		input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER,
+					   false);
+	}
+#else
+	input_mt_sync(fts_input_dev);
+#endif
+	input_report_key(fts_input_dev, BTN_TOUCH, 0);
+	input_sync(fts_input_dev);
+}
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+static void fts_show_touch_buffer(u8 *buf, int point_num)
+{
+	int len = point_num * FTS_ONE_TCH_LEN;
+	int count = 0;
+	int i;
+
+	memset(g_sz_debug, 0, 1024);
+	if (len > (POINT_READ_BUF - 3))
+		len = POINT_READ_BUF - 3;
+	else if (len == 0) {
+		len += FTS_ONE_TCH_LEN;
+
+	count += sprintf(g_sz_debug, "%02X,%02X,%02X", buf[0], buf[1], buf[2]);
+	for (i = 0; i < len; i++)
+		count += sprintf(g_sz_debug + count, ",%02X", buf[i + 3]);
+
+	FTS_DEBUG("buffer: %s", g_sz_debug);
+}
+#endif
+
+static int fts_input_dev_report_key_event(struct ts_event *event,
+					  struct fts_ts_data *data)
+{
+	int i;
+
+	if (data->pdata->have_key) {
+		if ((1 == event->touch_point || 1 == event->point_num)
+		    && (event->au16_y[0] == data->pdata->key_y_coord)) {
+
+			if (event->point_num == 0) {
+				FTS_DEBUG("Keys All Up!");
+				for (i = 0; i < data->pdata->key_number; i++) {
+					input_report_key(data->input_dev,
+							 data->pdata->keys[i],
+							 0);
+				}
+			} else {
+				for (i = 0; i < data->pdata->key_number; i++) {
+					if (event->au16_x[0] >
+					    (data->pdata->key_x_coords[i] -
+					     FTS_KEY_WIDTH)
+					    && event->au16_x[0] <
+					    (data->pdata->key_x_coords[i] +
+					     FTS_KEY_WIDTH)) {
+
+						if (event->au8_touch_event[i] ==
+						    0
+						    || event->au8_touch_event[i]
+						    == 2) {
+							input_report_key
+							    (data->input_dev,
+							     data->pdata->keys
+							     [i], 1);
+							FTS_DEBUG
+							    ("Key%d(%d, %d) DOWN!",
+							     i,
+							     event->au16_x[0],
+							     event->au16_y[0]);
+						} else {
+							input_report_key
+							    (data->input_dev,
+							     data->pdata->keys
+							     [i], 0);
+							FTS_DEBUG
+							    ("Key%d(%d, %d) Up!",
+							     i,
+							     event->au16_x[0],
+							     event->au16_y[0]);
+						}
+						break;
+					}
+				}
+			}
+			input_sync(data->input_dev);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+#if FTS_MT_PROTOCOL_B_EN
+static int fts_input_dev_report_b(struct ts_event *event,
+				  struct fts_ts_data *data)
+{
+	int i = 0;
+	int uppoint = 0;
+	int touchs = 0;
+
+	for (i = 0; i < event->touch_point; i++) {
+		input_mt_slot(data->input_dev, event->au8_finger_id[i]);
+
+		if (event->au8_touch_event[i] == FTS_TOUCH_DOWN
+		    || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) {
+			input_mt_report_slot_state(data->input_dev,
+						   MT_TOOL_FINGER, true);
+
+#if FTS_REPORT_PRESSURE_EN
+#if FTS_FORCE_TOUCH_EN
+			if (event->pressure[i] <= 0) {
+				FTS_ERROR("[B]Illegal pressure: %d",
+					  event->pressure[i]);
+				event->pressure[i] = 1;
+			}
+#else
+			event->pressure[i] = 0x3f;
+#endif
+			input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+					 event->pressure[i]);
+#endif
+
+			if (event->area[i] <= 0) {
+				FTS_ERROR("[B]Illegal touch-major: %d",
+					  event->area[i]);
+				event->area[i] = 1;
+			}
+			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+					 event->area[i]);
+
+			input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+					 event->au16_x[i]);
+			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+					 event->au16_y[i]);
+			touchs |= BIT(event->au8_finger_id[i]);
+			data->touchs |= BIT(event->au8_finger_id[i]);
+
+#if FTS_REPORT_PRESSURE_EN
+			FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
+				  event->au8_finger_id[i], event->au16_x[i],
+				  event->au16_y[i], event->pressure[i],
+				  event->area[i]);
+#else
+			FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!",
+				  event->au8_finger_id[i], event->au16_x[i],
+				  event->au16_y[i], event->area[i]);
+#endif
+		} else {
+			uppoint++;
+			input_mt_report_slot_state(data->input_dev,
+						   MT_TOOL_FINGER, false);
+#if FTS_REPORT_PRESSURE_EN
+			input_report_abs(data->input_dev, ABS_MT_PRESSURE, 0);
+#endif
+			data->touchs &= ~BIT(event->au8_finger_id[i]);
+			FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]);
+		}
+	}
+
+	if (unlikely(data->touchs ^ touchs)) {
+		for (i = 0; i < data->pdata->max_touch_number; i++) {
+			if (BIT(i) & (data->touchs ^ touchs)) {
+				FTS_DEBUG("[B]P%d UP!", i);
+				input_mt_slot(data->input_dev, i);
+				input_mt_report_slot_state(data->input_dev,
+							   MT_TOOL_FINGER,
+							   false);
+#if FTS_REPORT_PRESSURE_EN
+				input_report_abs(data->input_dev,
+						 ABS_MT_PRESSURE, 0);
+#endif
+			}
+		}
+	}
+
+	data->touchs = touchs;
+	if (event->touch_point == uppoint) {
+		FTS_DEBUG("Points All Up!");
+		input_report_key(data->input_dev, BTN_TOUCH, 0);
+	} else {
+		input_report_key(data->input_dev, BTN_TOUCH,
+				 event->touch_point > 0);
+	}
+
+	input_sync(data->input_dev);
+
+	return 0;
+
+}
+
+#else
+static int fts_input_dev_report_a(struct ts_event *event,
+				  struct fts_ts_data *data)
+{
+	int i = 0;
+	int uppoint = 0;
+	int touchs = 0;
+
+	for (i = 0; i < event->touch_point; i++) {
+
+		if (event->au8_touch_event[i] == FTS_TOUCH_DOWN
+		    || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) {
+			input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
+					 event->au8_finger_id[i]);
+#if FTS_REPORT_PRESSURE_EN
+#if FTS_FORCE_TOUCH_EN
+			if (event->pressure[i] <= 0) {
+				FTS_ERROR("[B]Illegal pressure: %d",
+					  event->pressure[i]);
+				event->pressure[i] = 1;
+			}
+#else
+			event->pressure[i] = 0x3f;
+#endif
+			input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+					 event->pressure[i]);
+#endif
+
+			if (event->area[i] <= 0) {
+				FTS_ERROR("[B]Illegal touch-major: %d",
+					  event->area[i]);
+				event->area[i] = 1;
+			}
+			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+					 event->area[i]);
+
+			input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+					 event->au16_x[i]);
+			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+					 event->au16_y[i]);
+
+			input_mt_sync(data->input_dev);
+
+#if FTS_REPORT_PRESSURE_EN
+			FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
+				  event->au8_finger_id[i], event->au16_x[i],
+				  event->au16_y[i], event->pressure[i],
+				  event->area[i]);
+#else
+			FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!",
+				  event->au8_finger_id[i], event->au16_x[i],
+				  event->au16_y[i], event->area[i]);
+#endif
+		} else {
+			uppoint++;
+		}
+	}
+
+	data->touchs = touchs;
+	if (event->touch_point == uppoint) {
+		FTS_DEBUG("Points All Up!");
+		input_report_key(data->input_dev, BTN_TOUCH, 0);
+		input_mt_sync(data->input_dev);
+	} else {
+		input_report_key(data->input_dev, BTN_TOUCH,
+				 event->touch_point > 0);
+	}
+
+	input_sync(data->input_dev);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+*  Name: fts_read_touchdata
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_read_touchdata(struct fts_ts_data *data)
+{
+	u8 buf[POINT_READ_BUF] = { 0 };
+	u8 pointid = FTS_MAX_ID;
+	int ret = -1;
+	int i;
+	struct ts_event *event = &(data->event);
+
+#if FTS_GESTURE_EN
+	{
+		u8 state;
+
+		if (data->suspended) {
+			fts_i2c_read_reg(data->client, FTS_REG_GESTURE_EN,
+					 &state);
+			if (state == 1) {
+				fts_gesture_readdata(data->client);
+				return 1;
+			}
+		}
+	}
+#endif
+
+#if FTS_PSENSOR_EN
+	if ((fts_sensor_read_data(data) != 0) && (data->suspended == 1))
+		return 1;
+#endif
+
+#if FTS_READ_TOUCH_BUFFER_DIVIDED
+	memset(buf, 0xFF, POINT_READ_BUF);
+	memset(event, 0, sizeof(struct ts_event));
+
+	buf[0] = 0x00;
+	ret = fts_i2c_read(data->client, buf, 1, buf, (3 + FTS_ONE_TCH_LEN));
+	if (ret < 0) {
+		FTS_ERROR("%s read touchdata failed.", __func__);
+		return ret;
+	}
+	event->touch_point = 0;
+	event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
+	if (event->point_num > data->pdata->max_touch_number)
+		event->point_num = data->pdata->max_touch_number;
+
+	if (event->point_num > 1) {
+		buf[9] = 0x09;
+		fts_i2c_read(data->client, buf + 9, 1, buf + 9,
+			     (event->point_num - 1) * FTS_ONE_TCH_LEN);
+	}
+#else
+	ret = fts_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
+	if (ret < 0) {
+		FTS_ERROR("[B]Read touchdata failed, ret: %d", ret);
+		return ret;
+	}
+#if FTS_POINT_REPORT_CHECK_EN
+	fts_point_report_check_queue_work();
+#endif
+
+	memset(event, 0, sizeof(struct ts_event));
+	event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
+	if (event->point_num > data->pdata->max_touch_number)
+		event->point_num = data->pdata->max_touch_number;
+	event->touch_point = 0;
+#endif
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+	fts_show_touch_buffer(buf, event->point_num);
+#endif
+
+	for (i = 0; i < data->pdata->max_touch_number; i++) {
+		pointid = (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+		if (pointid >= FTS_MAX_ID)
+			break;
+
+		event->touch_point++;
+		event->au16_x[i] =
+		    (s16) (buf[FTS_TOUCH_X_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F)
+		    << 8 | (s16) buf[FTS_TOUCH_X_L_POS + FTS_ONE_TCH_LEN * i];
+		event->au16_y[i] =
+		    (s16) (buf[FTS_TOUCH_Y_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F)
+		    << 8 | (s16) buf[FTS_TOUCH_Y_L_POS + FTS_ONE_TCH_LEN * i];
+		event->au8_touch_event[i] =
+		    buf[FTS_TOUCH_EVENT_POS + FTS_ONE_TCH_LEN * i] >> 6;
+
+		if (data->pdata->swap)
+			swap(event->au16_x[i], event->au16_y[i]);
+
+		if (data->pdata->scaling_down_half) {
+			event->au16_x[i] = event->au16_x[i] >> 1;
+			event->au16_y[i] = event->au16_y[i] >> 1;
+		}
+
+		event->au8_finger_id[i] =
+		    (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+		event->area[i] =
+		    (buf[FTS_TOUCH_AREA_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+		event->pressure[i] =
+		    (s16) buf[FTS_TOUCH_PRE_POS + FTS_ONE_TCH_LEN * i];
+
+		if (0 == event->area[i])
+			event->area[i] = 0x09;
+
+		if (0 == event->pressure[i])
+			event->pressure[i] = 0x3f;
+
+		if ((event->au8_touch_event[i] == 0
+		     || event->au8_touch_event[i] == 2)
+		    && (event->point_num == 0))
+			break;
+	}
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_report_value
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_report_value(struct fts_ts_data *data)
+{
+	struct ts_event *event = &data->event;
+
+	FTS_DEBUG("point number: %d, touch point: %d", event->point_num,
+		  event->touch_point);
+
+	if (0 == fts_input_dev_report_key_event(event, data))
+		return;
+#if FTS_MT_PROTOCOL_B_EN
+	fts_input_dev_report_b(event, data);
+#else
+	fts_input_dev_report_a(event, data);
+#endif
+
+	return;
+
+}
+
+/*****************************************************************************
+*  Name: fts_ts_interrupt
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static irqreturn_t fts_ts_interrupt(int irq, void *dev_id)
+{
+	struct fts_ts_data *fts_ts = dev_id;
+	int ret = -1;
+
+	if (!fts_ts) {
+		FTS_ERROR("[INTR]: Invalid fts_ts");
+		return IRQ_HANDLED;
+	}
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_set_intr(1);
+#endif
+
+	ret = fts_read_touchdata(fts_wq_data);
+
+	if (ret == 0)
+		fts_report_value(fts_wq_data);
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_set_intr(0);
+#endif
+
+	return IRQ_HANDLED;
+}
+
+/*****************************************************************************
+*  Name: fts_gpio_configure
+*  Brief: Configure IRQ&RESET GPIO
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_gpio_configure(struct fts_ts_data *data)
+{
+	int err = 0;
+
+	FTS_FUNC_ENTER();
+	/* request irq gpio */
+	if (gpio_is_valid(data->pdata->irq_gpio)) {
+		err = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio");
+		if (err) {
+			FTS_ERROR("[GPIO]irq gpio request failed");
+			goto err_irq_gpio_req;
+		}
+
+		err = gpio_direction_input(data->pdata->irq_gpio);
+		if (err) {
+			FTS_ERROR("[GPIO]set_direction for irq gpio failed");
+			goto err_irq_gpio_dir;
+		}
+	}
+	/* request reset gpio */
+	if (gpio_is_valid(data->pdata->reset_gpio)) {
+		err = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio");
+		if (err) {
+			FTS_ERROR("[GPIO]reset gpio request failed");
+			goto err_irq_gpio_dir;
+		}
+
+		err = gpio_direction_output(data->pdata->reset_gpio, 1);
+		if (err) {
+			FTS_ERROR("[GPIO]set_direction for reset gpio failed");
+			goto err_reset_gpio_dir;
+		}
+	}
+
+	FTS_FUNC_EXIT();
+	return 0;
+
+err_reset_gpio_dir:
+	if (gpio_is_valid(data->pdata->reset_gpio))
+		gpio_free(data->pdata->reset_gpio);
+err_irq_gpio_dir:
+	if (gpio_is_valid(data->pdata->irq_gpio))
+		gpio_free(data->pdata->irq_gpio);
+err_irq_gpio_req:
+	FTS_FUNC_EXIT();
+	return err;
+}
+
+/*****************************************************************************
+*  Name: fts_get_dt_coords
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_get_dt_coords(struct device *dev, char *name,
+			     struct fts_ts_platform_data *pdata)
+{
+	u32 coords[FTS_COORDS_ARR_SIZE];
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int coords_size, rc;
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	coords_size = prop->length / sizeof(u32);
+	if (coords_size != FTS_COORDS_ARR_SIZE) {
+		FTS_ERROR("invalid %s", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(np, name, coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		FTS_ERROR("Unable to read %s", name);
+		return rc;
+	}
+
+	if (!strcmp(name, "focaltech,display-coords")) {
+		pdata->x_min = coords[0];
+		pdata->y_min = coords[1];
+		pdata->x_max = coords[2];
+		pdata->y_max = coords[3];
+	} else {
+		FTS_ERROR("unsupported property %s", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_parse_dt
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata)
+{
+	int rc;
+	struct device_node *np = dev->of_node;
+	u32 temp_val;
+
+	FTS_FUNC_ENTER();
+
+	pdata->fts_chip_type = _FT5416;
+	rc = of_property_read_u32(np, "focaltech,panel-type",
+					  &pdata->fts_chip_type);
+	if (rc)
+		FTS_ERROR("Panel type is undefined, use default panel FT5416");
+
+	rc = fts_get_dt_coords(dev, "focaltech,display-coords", pdata);
+	if (rc)
+		FTS_ERROR("Unable to get display-coords");
+
+	/* key */
+	pdata->have_key = of_property_read_bool(np, "focaltech,have-key");
+	if (pdata->have_key) {
+		rc = of_property_read_u32(np, "focaltech,key-number",
+					  &pdata->key_number);
+		if (rc)
+			FTS_ERROR("Key number undefined!");
+		rc = of_property_read_u32_array(np, "focaltech,keys",
+						pdata->keys, pdata->key_number);
+		if (rc)
+			FTS_ERROR("Keys undefined!");
+		rc = of_property_read_u32(np, "focaltech,key-y-coord",
+					  &pdata->key_y_coord);
+		if (rc)
+			FTS_ERROR("Key Y Coord undefined!");
+		rc = of_property_read_u32_array(np, "focaltech,key-x-coords",
+						pdata->key_x_coords,
+						pdata->key_number);
+		if (rc)
+			FTS_ERROR("Key X Coords undefined!");
+
+		FTS_DEBUG("%d: (%d, %d, %d), [%d, %d, %d][%d]",
+			  pdata->key_number, pdata->keys[0], pdata->keys[1],
+			  pdata->keys[2], pdata->key_x_coords[0],
+			  pdata->key_x_coords[1], pdata->key_x_coords[2],
+			  pdata->key_y_coord);
+	}
+
+	/* reset, irq gpio info */
+	pdata->reset_gpio =
+	    of_get_named_gpio_flags(np, "focaltech,reset-gpio", 0,
+				    &pdata->reset_gpio_flags);
+	if (pdata->reset_gpio < 0)
+		FTS_ERROR("Unable to get reset_gpio");
+
+	pdata->irq_gpio =
+	    of_get_named_gpio_flags(np, "focaltech,irq-gpio", 0,
+				    &pdata->irq_gpio_flags);
+	if (pdata->irq_gpio < 0)
+		FTS_ERROR("Unable to get irq_gpio");
+
+	rc = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val);
+	if (!rc) {
+		pdata->max_touch_number = temp_val;
+		FTS_DEBUG("max_touch_number=%d", pdata->max_touch_number);
+	} else {
+		FTS_ERROR("Unable to get max-touch-number");
+		pdata->max_touch_number = FTS_MAX_POINTS;
+	}
+
+	pdata->swap = of_property_read_bool(np, "focaltech,swap-xy");
+	pdata->scaling_down_half = of_property_read_bool(np,
+					"focaltech,scaling-down-half");
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+#if defined(CONFIG_FB)
+/*****************************************************************************
+*  Name: fb_notifier_callback
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fb_notifier_callback(struct notifier_block *self,
+				unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct fts_ts_data *fts_data =
+	    container_of(self, struct fts_ts_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK && fts_data
+	    && fts_data->client) {
+		blank = evdata->data;
+		if (*blank == FB_BLANK_UNBLANK)
+			fts_ts_resume(&fts_data->client->dev);
+		else if (*blank == FB_BLANK_POWERDOWN)
+			fts_ts_suspend(&fts_data->client->dev);
+	}
+
+	return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+/*****************************************************************************
+*  Name: fts_ts_early_suspend
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_ts_early_suspend(struct early_suspend *handler)
+{
+	struct fts_ts_data *data = container_of(handler,
+						struct fts_ts_data,
+						early_suspend);
+
+	fts_ts_suspend(&data->client->dev);
+}
+
+/*****************************************************************************
+*  Name: fts_ts_late_resume
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_ts_late_resume(struct early_suspend *handler)
+{
+	struct fts_ts_data *data = container_of(handler,
+						struct fts_ts_data,
+						early_suspend);
+
+	fts_ts_resume(&data->client->dev);
+}
+#endif
+
+/*****************************************************************************
+*  Name: fts_ts_probe
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_ts_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct fts_ts_platform_data *pdata;
+	struct fts_ts_data *data;
+	struct input_dev *input_dev;
+	int err;
+
+	FTS_FUNC_ENTER();
+	/* 1. Get Platform data */
+	if (client->dev.of_node) {
+		pdata =
+		    devm_kzalloc(&client->dev,
+				 sizeof(struct fts_ts_platform_data),
+				 GFP_KERNEL);
+		if (!pdata) {
+			FTS_ERROR("[MEMORY]Failed to allocate memory");
+			FTS_FUNC_EXIT();
+			return -ENOMEM;
+		}
+		err = fts_parse_dt(&client->dev, pdata);
+		if (err)
+			FTS_ERROR("[DTS]DT parsing failed");
+	} else
+		pdata = client->dev.platform_data;
+
+	if (!pdata) {
+		FTS_ERROR("Invalid pdata");
+		FTS_FUNC_EXIT();
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		FTS_ERROR("I2C not supported");
+		FTS_FUNC_EXIT();
+		return -ENODEV;
+	}
+
+	data =
+	    devm_kzalloc(&client->dev, sizeof(struct fts_ts_data), GFP_KERNEL);
+	if (!data) {
+		FTS_ERROR("[MEMORY]Failed to allocate memory");
+		FTS_FUNC_EXIT();
+		return -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		FTS_ERROR("[INPUT]Failed to allocate input device");
+		FTS_FUNC_EXIT();
+		return -ENOMEM;
+	}
+
+	data->input_dev = input_dev;
+	data->client = client;
+	data->pdata = pdata;
+
+	fts_wq_data = data;
+	fts_i2c_client = client;
+	fts_input_dev = input_dev;
+
+	spin_lock_init(&fts_wq_data->irq_lock);
+
+	fts_input_dev_init(client, data, input_dev, pdata);
+
+#if FTS_POWER_SOURCE_CUST_EN
+	fts_power_source_init(data);
+	fts_power_source_ctrl(data, 1);
+#endif
+
+	err = fts_gpio_configure(data);
+	if (err < 0) {
+		FTS_ERROR("[GPIO]Failed to configure the gpios");
+		goto free_gpio;
+	}
+
+	fts_reset_proc(200);
+	fts_wait_tp_to_valid(client);
+
+	err =
+	    request_threaded_irq(client->irq, NULL, fts_ts_interrupt,
+				 pdata->irq_gpio_flags | IRQF_ONESHOT |
+				 IRQF_TRIGGER_FALLING, client->dev.driver->name,
+				 data);
+	if (err) {
+		FTS_ERROR("Request irq failed!");
+		goto free_gpio;
+	}
+
+	fts_irq_disable();
+
+#if FTS_PSENSOR_EN
+	if (fts_sensor_init(data) != 0) {
+		FTS_ERROR("fts_sensor_init failed!");
+		FTS_FUNC_EXIT();
+		return 0;
+	}
+#endif
+
+#if FTS_POINT_REPORT_CHECK_EN
+	fts_point_report_check_init();
+#endif
+
+	fts_ex_mode_init(client);
+
+#if FTS_GESTURE_EN
+	fts_gesture_init(input_dev, client);
+#endif
+
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_init();
+#endif
+
+	fts_irq_enable();
+
+#if FTS_TEST_EN
+	fts_test_init(client);
+#endif
+
+#if defined(CONFIG_FB)
+	data->fb_notif.notifier_call = fb_notifier_callback;
+	err = fb_register_client(&data->fb_notif);
+	if (err)
+		FTS_ERROR("[FB]Unable to register fb_notifier: %d", err);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	data->early_suspend.level =
+	    EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL;
+	data->early_suspend.suspend = fts_ts_early_suspend;
+	data->early_suspend.resume = fts_ts_late_resume;
+	register_early_suspend(&data->early_suspend);
+#endif
+
+	FTS_FUNC_EXIT();
+	return 0;
+
+free_gpio:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+	return err;
+
+}
+
+/*****************************************************************************
+*  Name: fts_ts_remove
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_ts_remove(struct i2c_client *client)
+{
+	struct fts_ts_data *data = i2c_get_clientdata(client);
+
+	FTS_FUNC_ENTER();
+	cancel_work_sync(&data->touch_event_work);
+
+#if FTS_PSENSOR_EN
+	fts_sensor_remove(data);
+#endif
+
+#if FTS_POINT_REPORT_CHECK_EN
+	fts_point_report_check_exit();
+#endif
+
+	fts_ex_mode_exit(client);
+
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&data->fb_notif))
+		FTS_ERROR("Error occurred while unregistering fb_notifier.");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	unregister_early_suspend(&data->early_suspend);
+#endif
+	free_irq(client->irq, data);
+
+	if (gpio_is_valid(data->pdata->reset_gpio))
+		gpio_free(data->pdata->reset_gpio);
+
+	if (gpio_is_valid(data->pdata->irq_gpio))
+		gpio_free(data->pdata->irq_gpio);
+
+	input_unregister_device(data->input_dev);
+
+#if FTS_TEST_EN
+	fts_test_exit(client);
+#endif
+
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_exit();
+#endif
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_ts_suspend
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_ts_suspend(struct device *dev)
+{
+	struct fts_ts_data *data = dev_get_drvdata(dev);
+	int retval = 0;
+
+	FTS_FUNC_ENTER();
+	if (data->suspended) {
+		FTS_INFO("Already in suspend state");
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	fts_release_all_finger();
+
+#if FTS_GESTURE_EN
+	retval = fts_gesture_suspend(data->client);
+	if (retval == 0) {
+		/* Enter into gesture mode(suspend) */
+		retval = enable_irq_wake(fts_wq_data->client->irq);
+		if (retval)
+			FTS_ERROR("%s: set_irq_wake failed", __func__);
+		data->suspended = true;
+		FTS_FUNC_EXIT();
+		return 0;
+	}
+#endif
+
+#if FTS_PSENSOR_EN
+	if (fts_sensor_suspend(data) != 0) {
+		enable_irq_wake(data->client->irq);
+		data->suspended = true;
+		return 0;
+	}
+#endif
+
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_suspend();
+#endif
+
+	fts_irq_disable();
+
+	/* TP enter sleep mode */
+	retval =
+	    fts_i2c_write_reg(data->client, FTS_REG_POWER_MODE,
+			      FTS_REG_POWER_MODE_SLEEP_VALUE);
+	if (retval < 0)
+		FTS_ERROR("Set TP to sleep mode fail, ret=%d!", retval);
+	data->suspended = true;
+
+	FTS_FUNC_EXIT();
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_ts_resume
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_ts_resume(struct device *dev)
+{
+	struct fts_ts_data *data = dev_get_drvdata(dev);
+
+	FTS_FUNC_ENTER();
+	if (!data->suspended) {
+		FTS_DEBUG("Already in awake state");
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	if (!fts_chip_idc(data))
+		fts_reset_proc(200);
+
+	fts_tp_state_recovery(data->client);
+
+#if FTS_GESTURE_EN
+	if (fts_gesture_resume(data->client) == 0) {
+		int err;
+
+		err = disable_irq_wake(data->client->irq);
+		if (err)
+			FTS_ERROR("%s: disable_irq_wake failed", __func__);
+		data->suspended = false;
+		FTS_FUNC_EXIT();
+		return 0;
+	}
+#endif
+
+#if FTS_PSENSOR_EN
+	if (fts_sensor_resume(data) != 0) {
+		disable_irq_wake(data->client->irq);
+		data->suspended = false;
+		FTS_FUNC_EXIT();
+		return 0;
+	}
+#endif
+
+	data->suspended = false;
+
+	fts_irq_enable();
+
+#if FTS_ESDCHECK_EN
+	fts_esdcheck_resume();
+#endif
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+* I2C Driver
+*****************************************************************************/
+static const struct i2c_device_id fts_ts_id[] = {
+	{FTS_DRIVER_NAME, 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, fts_ts_id);
+
+static struct of_device_id fts_match_table[] = {
+	{.compatible = "focaltech,fts",},
+	{},
+};
+
+static struct i2c_driver fts_ts_driver = {
+	.probe = fts_ts_probe,
+	.remove = fts_ts_remove,
+	.driver = {
+		   .name = FTS_DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   .of_match_table = fts_match_table,
+		   },
+	.id_table = fts_ts_id,
+};
+
+/*****************************************************************************
+*  Name: fts_ts_init
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int __init fts_ts_init(void)
+{
+	int ret = 0;
+
+	FTS_FUNC_ENTER();
+	ret = i2c_add_driver(&fts_ts_driver);
+	if (ret != 0)
+		FTS_ERROR("Focaltech touch screen driver init failed!");
+	FTS_FUNC_EXIT();
+	return ret;
+}
+
+/*****************************************************************************
+*  Name: fts_ts_exit
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void __exit fts_ts_exit(void)
+{
+	i2c_del_driver(&fts_ts_driver);
+}
+
+module_init(fts_ts_init);
+module_exit(fts_ts_exit);
+
+MODULE_AUTHOR("FocalTech Driver Team");
+MODULE_DESCRIPTION("FocalTech Touchscreen Driver");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_core.h
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_core.h
@@ -0,0 +1,189 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, Focaltech Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+/*****************************************************************************
+*
+* File Name: focaltech_core.h
+
+* Author: Focaltech Driver Team
+*
+* Created: 2016-08-08
+*
+* Abstract:
+*
+* Reference:
+*
+*****************************************************************************/
+
+#ifndef __LINUX_FOCALTECH_CORE_H__
+#define __LINUX_FOCALTECH_CORE_H__
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mount.h>
+#include <linux/netdevice.h>
+#include <linux/unistd.h>
+#include <linux/ioctl.h>
+#include "focaltech_common.h"
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define LEN_FLASH_ECC_MAX                   0xFFFE
+
+#define FTS_WORKQUEUE_NAME                  "fts_wq"
+
+#define FTS_MAX_POINTS                      10
+#define FTS_KEY_WIDTH                       50
+#define FTS_ONE_TCH_LEN                     6
+#define POINT_READ_BUF  (3 + FTS_ONE_TCH_LEN * FTS_MAX_POINTS)
+
+#define FTS_MAX_ID                          0x0F
+#define FTS_TOUCH_X_H_POS                   3
+#define FTS_TOUCH_X_L_POS                   4
+#define FTS_TOUCH_Y_H_POS                   5
+#define FTS_TOUCH_Y_L_POS                   6
+#define FTS_TOUCH_PRE_POS                   7
+#define FTS_TOUCH_AREA_POS                  8
+#define FTS_TOUCH_POINT_NUM                 2
+#define FTS_TOUCH_EVENT_POS                 3
+#define FTS_TOUCH_ID_POS                    5
+#define FTS_COORDS_ARR_SIZE                 4
+
+#define FTS_TOUCH_DOWN      0
+#define FTS_TOUCH_UP        1
+#define FTS_TOUCH_CONTACT   2
+
+#define FTS_SYSFS_ECHO_ON(buf)		((strnicmp(buf, "1", 1)  == 0) || \
+					(strnicmp(buf, "on", 2) == 0))
+#define FTS_SYSFS_ECHO_OFF(buf)		((strnicmp(buf, "0", 1)  == 0) || \
+					(strnicmp(buf, "off", 3) == 0))
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+struct fts_ts_platform_data {
+	u32 fts_chip_type;
+	u32 irq_gpio;
+	u32 irq_gpio_flags;
+	u32 reset_gpio;
+	u32 reset_gpio_flags;
+	bool have_key;
+	u32 key_number;
+	u32 keys[4];
+	u32 key_y_coord;
+	u32 key_x_coords[4];
+	u32 x_max;
+	u32 y_max;
+	u32 x_min;
+	u32 y_min;
+	u32 max_touch_number;
+
+	bool swap;
+	bool scaling_down_half;
+};
+
+struct ts_event {
+	u16 au16_x[FTS_MAX_POINTS];	/*x coordinate */
+	u16 au16_y[FTS_MAX_POINTS];	/*y coordinate */
+	u16 pressure[FTS_MAX_POINTS];
+	/* touch event: 0 -- down; 1-- up; 2 -- contact */
+	u8 au8_touch_event[FTS_MAX_POINTS];
+	u8 au8_finger_id[FTS_MAX_POINTS];	/*touch ID */
+	u8 area[FTS_MAX_POINTS];
+	u8 touch_point;
+	u8 point_num;
+};
+
+struct fts_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct ts_event event;
+	const struct fts_ts_platform_data *pdata;
+#if FTS_PSENSOR_EN
+	struct fts_psensor_platform_data *psensor_pdata;
+#endif
+	struct work_struct touch_event_work;
+	struct workqueue_struct *ts_workqueue;
+	struct regulator *vdd;
+	struct regulator *vcc_i2c;
+	spinlock_t irq_lock;
+	u16 addr;
+	bool suspended;
+	u8 fw_ver[3];
+	u8 fw_vendor_id;
+	int touchs;
+	int irq_disable;
+
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	struct early_suspend early_suspend;
+#endif
+};
+
+#if FTS_PSENSOR_EN
+struct fts_psensor_platform_data {
+	struct input_dev *input_psensor_dev;
+	struct sensors_classdev ps_cdev;
+	int tp_psensor_opened;
+	char tp_psensor_data;	/* 0 near, 1 far */
+	struct fts_ts_data *data;
+};
+
+int fts_sensor_init(struct fts_ts_data *data);
+int fts_sensor_read_data(struct fts_ts_data *data);
+int fts_sensor_suspend(struct fts_ts_data *data);
+int fts_sensor_resume(struct fts_ts_data *data);
+int fts_sensor_remove(struct fts_ts_data *data);
+#endif
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+extern struct i2c_client *fts_i2c_client;
+extern struct fts_ts_data *fts_wq_data;
+extern struct input_dev *fts_input_dev;
+
+#endif /* __LINUX_FOCALTECH_CORE_H__ */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c
@@ -0,0 +1,473 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+*
+* File Name: focaltech_esdcheck.c
+*
+*    Author: luoguojin
+*
+*   Created: 2016-08-03
+*
+*  Abstract: ESD check function
+*
+*   Version: v1.0
+*
+* Revision History:
+*        v1.0:
+*            First release. By luougojin 2016-08-03
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if FTS_ESDCHECK_EN
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define ESDCHECK_WAIT_TIME              1000
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+struct fts_esdcheck_st {
+	u8 active:1;
+	u8 suspend:1;
+	u8 proc_debug:1;	/* apk or adb is accessing I2C */
+	u8 intr:1;		/* 1- Interrupt trigger */
+	u8 unused:4;
+	u8 flow_work_hold_cnt;
+	u8 flow_work_cnt_last;
+	u32 hardware_reset_cnt;
+	u32 i2c_nack_cnt;
+	u32 i2c_dataerror_cnt;
+};
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct delayed_work fts_esdcheck_work;
+static struct workqueue_struct *fts_esdcheck_workqueue;
+static struct fts_esdcheck_st fts_esdcheck_data;
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+/*****************************************************************************
+*  Name: lcd_esdcheck
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int lcd_need_reset;
+static int tp_need_recovery;	/* LCD reset cause Tp reset */
+int idc_esdcheck_lcderror(void)
+{
+	u8 val;
+	int ret;
+
+	FTS_DEBUG("[ESD]Check LCD ESD");
+	if ((tp_need_recovery == 1) && (lcd_need_reset == 0)) {
+		tp_need_recovery = 0;
+		/* LCD reset, need recover TP state */
+		fts_tp_state_recovery(fts_i2c_client);
+	}
+
+	ret = fts_i2c_read_reg(fts_i2c_client, FTS_REG_ESD_SATURATE, &val);
+	if (ret < 0) {
+		FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed ret=%d!", ret);
+		return -EIO;
+	}
+
+	if (val == 0xAA) {
+		/*
+		 * 1. Set flag lcd_need_reset = 1;
+		 * 2. LCD driver need reset(recovery) LCD and
+		 *    set lcd_need_reset to 0
+		 * 3. recover TP state
+		 */
+		FTS_INFO("LCD ESD, Execute LCD reset!");
+		lcd_need_reset = 1;
+		tp_need_recovery = 1;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_tp_reset
+*  Brief: esd check algorithm
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_esdcheck_tp_reset(void)
+{
+	FTS_FUNC_ENTER();
+
+	fts_esdcheck_data.flow_work_hold_cnt = 0;
+	fts_esdcheck_data.hardware_reset_cnt++;
+
+	fts_reset_proc(200);
+	fts_tp_state_recovery(fts_i2c_client);
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: get_chip_id
+*  Brief: Read Chip Id 3 times
+*  Input:
+*  Output:
+*  Return:  1 - Read Chip Id 3 times failed
+*           0 - Read Chip Id pass
+*****************************************************************************/
+static bool get_chip_id(void)
+{
+	int err = 0;
+	int i = 0;
+	u8 reg_value = 0;
+	u8 reg_addr = 0;
+
+	for (i = 0; i < 3; i++) {
+		reg_addr = FTS_REG_CHIP_ID;
+		err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+
+		if (err < 0) {
+			FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!",
+				  err);
+			fts_esdcheck_data.i2c_nack_cnt++;
+		} else {
+			/* Upgrade sometimes can't detect */
+			if ((reg_value == chip_types.chip_idh)
+						|| (reg_value == 0xEF))
+				break;
+			 else
+				fts_esdcheck_data.i2c_dataerror_cnt++;
+		}
+	}
+
+	/* if can't get correct data in 3 times, then need hardware reset */
+	if (i >= 3) {
+		FTS_ERROR
+		    ("[ESD]: Read Chip id 3 times failed,"
+					"need execute TP reset!!");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: get_flow_cnt
+*  Brief: Read flow cnt(0x91)
+*  Input:
+*  Output:
+*  Return:  1 - Reg 0x91(flow cnt) abnormal: hold a value for 5 times
+*           0 - Reg 0x91(flow cnt) normal
+*****************************************************************************/
+static bool get_flow_cnt(void)
+{
+	int err = 0;
+	u8 reg_value = 0;
+	u8 reg_addr = 0;
+
+	reg_addr = FTS_REG_FLOW_WORK_CNT;
+	err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+	if (err < 0) {
+		FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", err);
+		fts_esdcheck_data.i2c_nack_cnt++;
+	} else {
+		if (reg_value == fts_esdcheck_data.flow_work_cnt_last)
+			fts_esdcheck_data.flow_work_hold_cnt++;
+		else
+			fts_esdcheck_data.flow_work_hold_cnt = 0;
+
+		fts_esdcheck_data.flow_work_cnt_last = reg_value;
+	}
+
+	/*
+	 * if read flow work cnt 5 times and the value are
+	 * all the same, then need hardware_reset
+	 */
+	if (fts_esdcheck_data.flow_work_hold_cnt >= 5) {
+		FTS_DEBUG("[ESD]: Flow Work Cnt(reg0x91) keep a value"
+				"for 5 times, need execute TP reset!!");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: esdcheck_algorithm
+*  Brief: esd check algorithm
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int esdcheck_algorithm(void)
+{
+	int err = 0;
+	u8 reg_value = 0;
+	u8 reg_addr = 0;
+	bool hardware_reset = 0;
+
+	/* 1. esdcheck is interrupt, then return */
+	if (fts_esdcheck_data.intr == 1) {
+		FTS_INFO("[ESD]: In interrupt state,"
+				"not check esd, return immediately!!");
+		return 0;
+	}
+
+	/* 2. check power state, if suspend, no need check esd */
+	if (fts_esdcheck_data.suspend == 1) {
+		FTS_INFO("[ESD]: In suspend, not check esd,"
+					"return immediately!!");
+		/* because in suspend state, adb can be used,
+		 * when upgrade FW, will active ESD check(active = 1)
+		 * But in suspend, then will don't queue_delayed_work,
+		 * when resume, don't check ESD again
+		 */
+		fts_esdcheck_data.active = 0;
+		return 0;
+	}
+
+	/*
+	 * 3. check fts_esdcheck_data.proc_debug state,
+	 * if 1-proc busy, no need check esd
+	 */
+	if (fts_esdcheck_data.proc_debug == 1) {
+		FTS_INFO("[ESD]: In apk or adb command mode,"
+				"not check esd, return immediately!!");
+		return 0;
+	}
+
+	/* 4. In factory mode, can't check esd */
+	reg_addr = FTS_REG_WORKMODE;
+	err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+	if (err < 0) {
+		fts_esdcheck_data.i2c_nack_cnt++;
+	} else if ((reg_value & 0x70) == FTS_REG_WORKMODE_FACTORY_VALUE) {
+		FTS_INFO("[ESD]: In factory mode,"
+				"not check esd, return immediately!!");
+		return 0;
+	}
+
+	/* 5. Get Chip ID */
+	hardware_reset = get_chip_id();
+
+	/*
+	 * 6. get Flow work cnt: 0x91 If no change for 5 times,
+	 * then ESD and reset
+	 */
+	if (!hardware_reset)
+		hardware_reset = get_flow_cnt();
+
+	/* 7. If need hardware reset, then handle it here */
+	if (hardware_reset == 1)
+		fts_esdcheck_tp_reset();
+
+	FTS_INFO("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d\n",
+		 fts_esdcheck_data.i2c_nack_cnt,
+		 fts_esdcheck_data.i2c_dataerror_cnt,
+		 fts_esdcheck_data.hardware_reset_cnt);
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_func
+*  Brief: fts_esdcheck_func
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void esdcheck_func(struct work_struct *work)
+{
+	FTS_FUNC_ENTER();
+
+	idc_esdcheck_lcderror();
+
+	esdcheck_algorithm();
+
+	if (fts_esdcheck_data.suspend == 0) {
+		queue_delayed_work(fts_esdcheck_workqueue, &fts_esdcheck_work,
+				   msecs_to_jiffies(ESDCHECK_WAIT_TIME));
+	}
+
+	FTS_FUNC_EXIT();
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_set_intr
+*  Brief: interrupt flag (main used in interrupt tp report)
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_set_intr(bool intr)
+{
+	/* interrupt don't add debug message */
+	fts_esdcheck_data.intr = intr;
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_get_status(void)
+*  Brief: get current status
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_get_status(void)
+{
+	/* interrupt don't add debug message */
+	return fts_esdcheck_data.active;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_proc_busy
+*  Brief: When APK or ADB command access TP via driver,
+*  then need set proc_debug,
+*         then will not check ESD.
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_proc_busy(bool proc_debug)
+{
+	fts_esdcheck_data.proc_debug = proc_debug;
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_switch
+*  Brief: FTS esd check function switch.
+*  Input:   enable:  1 - Enable esd check
+*                    0 - Disable esd check
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_switch(bool enable)
+{
+	FTS_FUNC_ENTER();
+	if (enable == 1) {
+		if (fts_esdcheck_data.active == 0) {
+			FTS_INFO("[ESD]: ESD check start!!");
+			fts_esdcheck_data.active = 1;
+			queue_delayed_work(fts_esdcheck_workqueue,
+					   &fts_esdcheck_work,
+					   msecs_to_jiffies
+					   (ESDCHECK_WAIT_TIME));
+		}
+	} else {
+		if (fts_esdcheck_data.active == 1) {
+			FTS_INFO("[ESD]: ESD check stop!!");
+			fts_esdcheck_data.active = 0;
+			cancel_delayed_work_sync(&fts_esdcheck_work);
+		}
+	}
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_suspend
+*  Brief: Run when tp enter into suspend
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_suspend(void)
+{
+	FTS_FUNC_ENTER();
+	fts_esdcheck_switch(DISABLE);
+	fts_esdcheck_data.suspend = 1;
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_resume
+*  Brief: Run when tp resume
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_resume(void)
+{
+	FTS_FUNC_ENTER();
+	fts_esdcheck_switch(ENABLE);
+	fts_esdcheck_data.suspend = 0;
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_init
+*  Brief: Init and create a queue work to check esd
+*  Input:
+*  Output:
+*  Return: < 0: Fail to create esd check queue
+*****************************************************************************/
+int fts_esdcheck_init(void)
+{
+	FTS_FUNC_ENTER();
+
+	INIT_DELAYED_WORK(&fts_esdcheck_work, esdcheck_func);
+	fts_esdcheck_workqueue = create_workqueue("fts_esdcheck_wq");
+	if (fts_esdcheck_workqueue == NULL)
+		FTS_INFO("[ESD]: Failed to create esd work queue!!");
+
+	memset((u8 *) &fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st));
+
+	fts_esdcheck_switch(ENABLE);
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_esdcheck_exit
+*  Brief: When FTS TP driver is removed,
+*  then call this function to destroy work queue
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_esdcheck_exit(void)
+{
+	FTS_FUNC_ENTER();
+
+	destroy_workqueue(fts_esdcheck_workqueue);
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+#endif /* FTS_ESDCHECK_EN */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c
@@ -0,0 +1,357 @@
+/*
+ *
+ * FocalTech ftxxxx TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, Focaltech Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+*
+* File Name: focaltech_ex_mode.c
+*
+*    Author: Liu WeiGuang
+*
+*   Created: 2016-08-31
+*
+*  Abstract:
+*
+* Reference:
+*
+*****************************************************************************/
+
+/*****************************************************************************
+* 1.Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+/*****************************************************************************
+* 2.Private constant and macro definitions using #define
+*****************************************************************************/
+
+/*****************************************************************************
+* 3.Private enumerations, structures and unions using typedef
+*****************************************************************************/
+struct fts_mode_flag {
+	int fts_glove_mode_flag;
+	int fts_cover_mode_flag;
+	int fts_charger_mode_flag;
+};
+
+struct fts_mode_flag g_fts_mode_flag;
+
+/*****************************************************************************
+* 4.Static variables
+*****************************************************************************/
+
+/*****************************************************************************
+* 5.Global variable or extern global variabls/functions
+*****************************************************************************/
+int fts_enter_glove_mode(struct i2c_client *client, int mode);
+int fts_glove_init(struct i2c_client *client);
+int fts_glove_exit(struct i2c_client *client);
+
+int fts_enter_cover_mode(struct i2c_client *client, int mode);
+int fts_cover_init(struct i2c_client *client);
+int fts_cover_exit(struct i2c_client *client);
+
+int fts_enter_charger_mode(struct i2c_client *client, int mode);
+int fts_charger_init(struct i2c_client *client);
+int fts_charger_exit(struct i2c_client *client);
+
+/*****************************************************************************
+* 6.Static function prototypes
+*******************************************************************************/
+
+#if FTS_GLOVE_EN
+static ssize_t fts_touch_glove_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "Glove: %s\n",
+			g_fts_mode_flag.fts_glove_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_glove_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int ret;
+
+	if (FTS_SYSFS_ECHO_ON(buf)) {
+		if (!g_fts_mode_flag.fts_glove_mode_flag) {
+			FTS_INFO("[Mode]enter glove mode");
+			ret = fts_enter_glove_mode(fts_i2c_client, true);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_glove_mode_flag = true;
+		}
+	} else if (FTS_SYSFS_ECHO_OFF(buf)) {
+		if (g_fts_mode_flag.fts_glove_mode_flag) {
+			FTS_INFO("[Mode]exit glove mode");
+			ret = fts_enter_glove_mode(fts_i2c_client, false);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_glove_mode_flag = false;
+		}
+	}
+	FTS_INFO("[Mode]glove mode status:  %d",
+		 g_fts_mode_flag.fts_glove_mode_flag);
+	return count;
+}
+
+/************************************************************************
+* Name: fts_enter_glove_mode
+* Brief:  change glove mode
+* Input:  glove mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_glove_mode(struct i2c_client *client, int mode)
+{
+	int ret = 0;
+	static u8 buf_addr[2] = { 0 };
+	static u8 buf_value[2] = { 0 };
+
+	buf_addr[0] = FTS_REG_GLOVE_MODE_EN;
+
+	if (mode)
+		buf_value[0] = 0x01;
+	else
+		buf_value[0] = 0x00;
+
+	ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+	if (ret < 0)
+		FTS_ERROR("[Mode]fts_enter_glove_mode write value fail");
+
+	return ret;
+
+}
+
+/* read and write glove mode
+*   read example: cat  fts_touch_glove_mode---read  glove mode
+*   write example:echo 01 > fts_touch_glove_mode ---write glove mode to 01
+*
+*/
+static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR, fts_touch_glove_show,
+		   fts_touch_glove_store);
+
+#endif
+
+#if FTS_COVER_EN
+static ssize_t fts_touch_cover_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "Cover: %s\n",
+			g_fts_mode_flag.fts_cover_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_cover_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int ret;
+
+	if (FTS_SYSFS_ECHO_ON(buf)) {
+		if (!g_fts_mode_flag.fts_cover_mode_flag) {
+			FTS_INFO("[Mode]enter cover mode");
+			ret = fts_enter_cover_mode(fts_i2c_client, true);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_cover_mode_flag = true;
+		}
+	} else if (FTS_SYSFS_ECHO_OFF(buf)) {
+		if (g_fts_mode_flag.fts_cover_mode_flag) {
+			FTS_INFO("[Mode]exit cover mode");
+			ret = fts_enter_cover_mode(fts_i2c_client, false);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_cover_mode_flag = false;
+		}
+	}
+	FTS_INFO("[Mode]cover mode status:  %d",
+		 g_fts_mode_flag.fts_cover_mode_flag);
+	return count;
+}
+
+/************************************************************************
+* Name: fts_enter_cover_mode
+* Brief:  change cover mode
+* Input:  cover mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_cover_mode(struct i2c_client *client, int mode)
+{
+	int ret = 0;
+	static u8 buf_addr[2] = { 0 };
+	static u8 buf_value[2] = { 0 };
+
+	buf_addr[0] = FTS_REG_COVER_MODE_EN;
+
+	if (mode)
+		buf_value[0] = 0x01;
+	else
+		buf_value[0] = 0x00;
+
+	ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+	if (ret < 0)
+		FTS_ERROR("[Mode] fts_enter_cover_mode write value fail\n");
+
+	return ret;
+
+}
+
+/* read and write cover mode
+*   read example: cat  fts_touch_cover_mode---read  cover mode
+*   write example:echo 01 > fts_touch_cover_mode ---write cover mode to 01
+*
+*/
+static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR, fts_touch_cover_show,
+		   fts_touch_cover_store);
+
+#endif
+
+#if FTS_CHARGER_EN
+static ssize_t fts_touch_charger_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "Charger: %s\n",
+			g_fts_mode_flag.fts_charger_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_charger_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	int ret;
+
+	if (FTS_SYSFS_ECHO_ON(buf)) {
+		if (!g_fts_mode_flag.fts_charger_mode_flag) {
+			FTS_INFO("[Mode]enter charger mode");
+			ret = fts_enter_charger_mode(fts_i2c_client, true);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_charger_mode_flag = true;
+		}
+	} else if (FTS_SYSFS_ECHO_OFF(buf)) {
+		if (g_fts_mode_flag.fts_charger_mode_flag) {
+			FTS_INFO("[Mode]exit charger mode");
+			ret = fts_enter_charger_mode(fts_i2c_client, false);
+			if (ret >= 0)
+				g_fts_mode_flag.fts_charger_mode_flag = false;
+		}
+	}
+	FTS_INFO("[Mode]charger mode status: %d",
+		 g_fts_mode_flag.fts_charger_mode_flag);
+	return count;
+}
+
+/************************************************************************
+* Name: fts_enter_charger_mode
+* Brief:  change charger mode
+* Input:  charger mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_charger_mode(struct i2c_client *client, int mode)
+{
+	int ret = 0;
+	static u8 buf_addr[2] = { 0 };
+	static u8 buf_value[2] = { 0 };
+
+	buf_addr[0] = FTS_REG_CHARGER_MODE_EN;
+
+	if (mode)
+		buf_value[0] = 0x01;
+	else
+		buf_value[0] = 0x00;
+
+	ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+	if (ret < 0)
+		FTS_DEBUG("[Mode]fts_enter_charger_mode write value fail");
+
+	return ret;
+
+}
+
+/* read and write charger mode
+*   read example: cat  fts_touch_charger_mode---read  charger mode
+*   write example:echo 01 > fts_touch_charger_mode ---write charger mode to 01
+*
+*/
+static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR, fts_touch_charger_show,
+		   fts_touch_charger_store);
+
+#endif
+
+static struct attribute *fts_touch_mode_attrs[] = {
+#if FTS_GLOVE_EN
+	&dev_attr_fts_glove_mode.attr,
+#endif
+
+#if FTS_COVER_EN
+	&dev_attr_fts_cover_mode.attr,
+#endif
+
+#if FTS_CHARGER_EN
+	&dev_attr_fts_charger_mode.attr,
+#endif
+
+	NULL,
+};
+
+static struct attribute_group fts_touch_mode_group = {
+	.attrs = fts_touch_mode_attrs,
+};
+
+int fts_ex_mode_init(struct i2c_client *client)
+{
+	int err = 0;
+
+	g_fts_mode_flag.fts_glove_mode_flag = false;
+	g_fts_mode_flag.fts_cover_mode_flag = false;
+	g_fts_mode_flag.fts_charger_mode_flag = false;
+
+	err = sysfs_create_group(&client->dev.kobj, &fts_touch_mode_group);
+	if (0 != err) {
+		FTS_ERROR("[Mode]create sysfs failed.");
+		sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group);
+		return -EIO;
+	}
+
+	FTS_DEBUG("[Mode]create sysfs succeeded");
+
+	return err;
+
+}
+
+int fts_ex_mode_exit(struct i2c_client *client)
+{
+	sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group);
+	return 0;
+}
+
+int fts_ex_mode_recovery(struct i2c_client *client)
+{
+	int ret = 0;
+#if FTS_GLOVE_EN
+	if (g_fts_mode_flag.fts_glove_mode_flag)
+		ret = fts_enter_glove_mode(client, true);
+#endif
+
+#if FTS_COVER_EN
+	if (g_fts_mode_flag.fts_cover_mode_flag)
+		ret = fts_enter_cover_mode(client, true);
+#endif
+
+#if FTS_CHARGER_EN
+	if (g_fts_mode_flag.fts_charger_mode_flag)
+		ret = fts_enter_charger_mode(client, true);
+#endif
+
+	return ret;
+}
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c
@@ -0,0 +1,652 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, Focaltech Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+*
+* File Name: focaltech_gestrue.c
+*
+* Author: Focaltech Driver Team
+*
+* Created: 2016-08-08
+*
+* Abstract:
+*
+* Reference:
+*
+*****************************************************************************/
+
+/*****************************************************************************
+* 1.Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+#if FTS_GESTURE_EN
+/******************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define  KEY_GESTURE_U                          KEY_U
+#define  KEY_GESTURE_UP                         KEY_UP
+#define  KEY_GESTURE_DOWN                       KEY_DOWN
+#define  KEY_GESTURE_LEFT                       KEY_LEFT
+#define  KEY_GESTURE_RIGHT                      KEY_RIGHT
+#define  KEY_GESTURE_O                          KEY_O
+#define  KEY_GESTURE_E                          KEY_E
+#define  KEY_GESTURE_M                          KEY_M
+#define  KEY_GESTURE_L                          KEY_L
+#define  KEY_GESTURE_W                          KEY_W
+#define  KEY_GESTURE_S                          KEY_S
+#define  KEY_GESTURE_V                          KEY_V
+#define  KEY_GESTURE_C                          KEY_C
+#define  KEY_GESTURE_Z                          KEY_Z
+
+#define GESTURE_LEFT                            0x20
+#define GESTURE_RIGHT                           0x21
+#define GESTURE_UP                              0x22
+#define GESTURE_DOWN                            0x23
+#define GESTURE_DOUBLECLICK                     0x24
+#define GESTURE_O                               0x30
+#define GESTURE_W                               0x31
+#define GESTURE_M                               0x32
+#define GESTURE_E                               0x33
+#define GESTURE_L                               0x44
+#define GESTURE_S                               0x46
+#define GESTURE_V                               0x54
+#define GESTURE_Z                               0x41
+#define GESTURE_C                               0x34
+#define FTS_GESTRUE_POINTS                      255
+#define FTS_GESTRUE_POINTS_HEADER               8
+#define FTS_GESTURE_OUTPUT_ADRESS               0xD3
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+struct fts_gesture_st {
+	u8 header[FTS_GESTRUE_POINTS_HEADER];
+	u16 coordinate_x[FTS_GESTRUE_POINTS];
+	u16 coordinate_y[FTS_GESTRUE_POINTS];
+	u8 mode;
+	u8 active;
+};
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct fts_gesture_st fts_gesture_data;
+extern struct fts_ts_data *fts_wq_data;
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+static ssize_t fts_gesture_show(struct device *dev,
+				struct device_attribute *attr, char *buf);
+static ssize_t fts_gesture_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count);
+static ssize_t fts_gesture_buf_show(struct device *dev,
+				    struct device_attribute *attr, char *buf);
+static ssize_t fts_gesture_buf_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count);
+
+/* sysfs gesture node
+ *   read example: cat  fts_gesture_mode        ---read gesture mode
+ *   write example:echo 01 > fts_gesture_mode   ---write gesture mode to 01
+ *
+ */
+static DEVICE_ATTR(fts_gesture_mode, S_IRUGO | S_IWUSR, fts_gesture_show,
+		   fts_gesture_store);
+/*
+ *   read example: cat  fts_gesture_buf        ---read gesture buf
+ */
+static DEVICE_ATTR(fts_gesture_buf, S_IRUGO | S_IWUSR, fts_gesture_buf_show,
+		   fts_gesture_buf_store);
+static struct attribute *fts_gesture_mode_attrs[] = {
+
+	&dev_attr_fts_gesture_mode.attr,
+	&dev_attr_fts_gesture_buf.attr,
+	NULL,
+};
+
+static struct attribute_group fts_gesture_group = {
+	.attrs = fts_gesture_mode_attrs,
+};
+
+/************************************************************************
+* Name: fts_gesture_show
+* Brief:  no
+* Input: device, device attribute, char buf
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int count;
+	u8 val;
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+	mutex_lock(&fts_input_dev->mutex);
+	fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &val);
+	count =
+	    sprintf(buf, "Gesture Mode: %s\n",
+		    fts_gesture_data.mode ? "On" : "Off");
+	count += sprintf(buf + count, "Reg(0xD0) = %d\n", val);
+	mutex_unlock(&fts_input_dev->mutex);
+
+	return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_store
+* Brief:  no
+* Input: device, device attribute, char buf, char count
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	mutex_lock(&fts_input_dev->mutex);
+
+	if (FTS_SYSFS_ECHO_ON(buf)) {
+		FTS_INFO("[GESTURE]enable gesture");
+		fts_gesture_data.mode = ENABLE;
+	} else if (FTS_SYSFS_ECHO_OFF(buf)) {
+		FTS_INFO("[GESTURE]disable gesture");
+		fts_gesture_data.mode = DISABLE;
+	}
+
+	mutex_unlock(&fts_input_dev->mutex);
+
+	return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_buf_show
+* Brief:  no
+* Input: device, device attribute, char buf
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_buf_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	int count;
+	int i = 0;
+
+	mutex_lock(&fts_input_dev->mutex);
+	count =
+	    snprintf(buf, PAGE_SIZE, "Gesture ID: 0x%x\n",
+		     fts_gesture_data.header[0]);
+	count +=
+	    snprintf(buf + count, PAGE_SIZE, "Gesture PointNum: %d\n",
+		     fts_gesture_data.header[1]);
+	count += snprintf(buf + count, PAGE_SIZE, "Gesture Point Buf:\n");
+	for (i = 0; i < fts_gesture_data.header[1]; i++) {
+		count +=
+		    snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i,
+			     fts_gesture_data.coordinate_x[i],
+			     fts_gesture_data.coordinate_y[i]);
+		if ((i + 1) % 4 == 0)
+			count += snprintf(buf + count, PAGE_SIZE, "\n");
+	}
+	count += snprintf(buf + count, PAGE_SIZE, "\n");
+	mutex_unlock(&fts_input_dev->mutex);
+
+	return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_buf_store
+* Brief:  no
+* Input: device, device attribute, char buf, char count
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_buf_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	/* place holder for future use */
+	return -EPERM;
+}
+
+/*****************************************************************************
+*   Name: fts_create_gesture_sysfs
+*  Brief:
+*  Input:
+* Output: None
+* Return: 0-success or error
+*****************************************************************************/
+int fts_create_gesture_sysfs(struct i2c_client *client)
+{
+	int ret = 0;
+
+	ret = sysfs_create_group(&client->dev.kobj, &fts_gesture_group);
+	if (ret != 0) {
+		FTS_ERROR
+		    ("[GESTURE]fts_gesture_mode_group(sysfs) create failed!");
+		sysfs_remove_group(&client->dev.kobj, &fts_gesture_group);
+		return ret;
+	}
+	return 0;
+}
+
+/*****************************************************************************
+*   Name: fts_gesture_recovery
+*  Brief: recovery gesture state when reset
+*  Input:
+* Output: None
+* Return:
+*****************************************************************************/
+void fts_gesture_recovery(struct i2c_client *client)
+{
+	if (fts_gesture_data.mode && fts_gesture_data.active) {
+		fts_i2c_write_reg(client, 0xD1, 0xff);
+		fts_i2c_write_reg(client, 0xD2, 0xff);
+		fts_i2c_write_reg(client, 0xD5, 0xff);
+		fts_i2c_write_reg(client, 0xD6, 0xff);
+		fts_i2c_write_reg(client, 0xD7, 0xff);
+		fts_i2c_write_reg(client, 0xD8, 0xff);
+		fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, ENABLE);
+	}
+}
+
+/*****************************************************************************
+*   Name: fts_gesture_init
+*  Brief:
+*  Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client)
+{
+	FTS_FUNC_ENTER();
+	input_set_capability(input_dev, EV_KEY, KEY_POWER);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z);
+	input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C);
+
+	__set_bit(KEY_GESTURE_RIGHT, input_dev->keybit);
+	__set_bit(KEY_GESTURE_LEFT, input_dev->keybit);
+	__set_bit(KEY_GESTURE_UP, input_dev->keybit);
+	__set_bit(KEY_GESTURE_DOWN, input_dev->keybit);
+	__set_bit(KEY_GESTURE_U, input_dev->keybit);
+	__set_bit(KEY_GESTURE_O, input_dev->keybit);
+	__set_bit(KEY_GESTURE_E, input_dev->keybit);
+	__set_bit(KEY_GESTURE_M, input_dev->keybit);
+	__set_bit(KEY_GESTURE_W, input_dev->keybit);
+	__set_bit(KEY_GESTURE_L, input_dev->keybit);
+	__set_bit(KEY_GESTURE_S, input_dev->keybit);
+	__set_bit(KEY_GESTURE_V, input_dev->keybit);
+	__set_bit(KEY_GESTURE_C, input_dev->keybit);
+	__set_bit(KEY_GESTURE_Z, input_dev->keybit);
+
+	fts_create_gesture_sysfs(client);
+	fts_gesture_data.mode = 0;
+	fts_gesture_data.active = 0;
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/************************************************************************
+* Name: fts_gesture_exit
+* Brief:  remove sys
+* Input: i2c info
+* Output: no
+* Return: no
+***********************************************************************/
+int fts_gesture_exit(struct i2c_client *client)
+{
+	sysfs_remove_group(&client->dev.kobj, &fts_gesture_group);
+	return 0;
+}
+
+/*****************************************************************************
+*   Name: fts_check_gesture
+*  Brief:
+*  Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+static void fts_check_gesture(struct input_dev *input_dev, int gesture_id)
+{
+	char *envp[2];
+	int gesture;
+
+	FTS_FUNC_ENTER();
+	switch (gesture_id) {
+	case GESTURE_LEFT:
+		envp[0] = "GESTURE=LEFT";
+		gesture = KEY_GESTURE_LEFT;
+		break;
+	case GESTURE_RIGHT:
+		envp[0] = "GESTURE=RIGHT";
+		gesture = KEY_GESTURE_RIGHT;
+		break;
+	case GESTURE_UP:
+		envp[0] = "GESTURE=UP";
+		gesture = KEY_GESTURE_UP;
+		break;
+	case GESTURE_DOWN:
+		envp[0] = "GESTURE=DOWN";
+		gesture = KEY_GESTURE_DOWN;
+		break;
+	case GESTURE_DOUBLECLICK:
+		envp[0] = "GESTURE=DOUBLE_CLICK";
+		gesture = KEY_POWER;
+		break;
+	case GESTURE_O:
+		envp[0] = "GESTURE=O";
+		gesture = KEY_GESTURE_O;
+		break;
+	case GESTURE_W:
+		envp[0] = "GESTURE=W";
+		gesture = KEY_GESTURE_W;
+		break;
+	case GESTURE_M:
+		envp[0] = "GESTURE=M";
+		gesture = KEY_GESTURE_M;
+		break;
+	case GESTURE_E:
+		envp[0] = "GESTURE=E";
+		gesture = KEY_GESTURE_E;
+		break;
+	case GESTURE_L:
+		envp[0] = "GESTURE=L";
+		gesture = KEY_GESTURE_L;
+		break;
+	case GESTURE_S:
+		envp[0] = "GESTURE=S";
+		gesture = KEY_GESTURE_S;
+		break;
+	case GESTURE_V:
+		envp[0] = "GESTURE=V";
+		gesture = KEY_GESTURE_V;
+		break;
+	case GESTURE_Z:
+		envp[0] = "GESTURE=Z";
+		gesture = KEY_GESTURE_Z;
+		break;
+	case GESTURE_C:
+		envp[0] = "GESTURE=C";
+		gesture = KEY_GESTURE_C;
+		break;
+	default:
+		envp[0] = "GESTURE=NONE";
+		gesture = -1;
+		break;
+	}
+	FTS_DEBUG("envp[0]: %s", envp[0]);
+	/* report event key */
+	/*if (gesture != -1)
+	   {
+	   input_report_key(input_dev, gesture, 1);
+	   input_sync(input_dev);
+	   input_report_key(input_dev, gesture, 0);
+	   input_sync(input_dev);
+	   } */
+
+	envp[1] = NULL;
+	kobject_uevent_env(&fts_wq_data->client->dev.kobj, KOBJ_CHANGE, envp);
+	sysfs_notify(&fts_wq_data->client->dev.kobj, NULL, "GESTURE_ID");
+
+	FTS_FUNC_EXIT();
+}
+
+/************************************************************************
+*   Name: fts_gesture_readdata
+* Brief: read data from TP register
+* Input: no
+* Output: no
+* Return: fail <0
+***********************************************************************/
+static int fts_gesture_read_buffer(struct i2c_client *client, u8 *buf,
+				   int read_bytes)
+{
+	int remain_bytes;
+	int ret;
+	int i;
+
+	if (read_bytes <= I2C_BUFFER_LENGTH_MAXINUM) {
+		ret = fts_i2c_read(client, buf, 1, buf, read_bytes);
+	} else {
+		ret =
+		    fts_i2c_read(client, buf, 1, buf,
+				 I2C_BUFFER_LENGTH_MAXINUM);
+		remain_bytes = read_bytes - I2C_BUFFER_LENGTH_MAXINUM;
+		for (i = 1; remain_bytes > 0; i++) {
+			if (remain_bytes <= I2C_BUFFER_LENGTH_MAXINUM)
+				ret =
+				    fts_i2c_read(client, buf, 0,
+						 buf +
+						 I2C_BUFFER_LENGTH_MAXINUM * i,
+						 remain_bytes);
+			else
+				ret =
+				    fts_i2c_read(client, buf, 0,
+						 buf +
+						 I2C_BUFFER_LENGTH_MAXINUM * i,
+						 I2C_BUFFER_LENGTH_MAXINUM);
+			remain_bytes -= I2C_BUFFER_LENGTH_MAXINUM;
+		}
+	}
+
+	return ret;
+}
+
+/************************************************************************
+*   Name: fts_gesture_readdata
+* Brief: read data from TP register
+* Input: no
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_gesture_readdata(struct i2c_client *client)
+{
+	u8 buf[FTS_GESTRUE_POINTS * 4] = { 0 };
+	int ret = -1;
+	int i = 0;
+	int gestrue_id = 0;
+	int read_bytes = 0;
+	u8 pointnum;
+
+	FTS_FUNC_ENTER();
+	/* init variable before read gesture point */
+	memset(fts_gesture_data.header, 0, FTS_GESTRUE_POINTS_HEADER);
+	memset(fts_gesture_data.coordinate_x, 0,
+	       FTS_GESTRUE_POINTS * sizeof(u16));
+	memset(fts_gesture_data.coordinate_y, 0,
+	       FTS_GESTRUE_POINTS * sizeof(u16));
+
+	buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+	ret = fts_i2c_read(client, buf, 1, buf, FTS_GESTRUE_POINTS_HEADER);
+	if (ret < 0) {
+		FTS_ERROR("[GESTURE]Read gesture header data failed!!");
+		FTS_FUNC_EXIT();
+		return ret;
+	}
+
+	/* FW recognize gesture */
+	if (chip_types.chip_idh == 0x54 || chip_types.chip_idh == 0x58
+	    || chip_types.chip_idh == 0x86 || chip_types.chip_idh == 0x87
+	    || chip_types.chip_idh == 0x64) {
+		memcpy(fts_gesture_data.header, buf, FTS_GESTRUE_POINTS_HEADER);
+		gestrue_id = buf[0];
+		pointnum = buf[1];
+		read_bytes = ((int)pointnum) * 4 + 2;
+		buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+		FTS_DEBUG("[GESTURE]PointNum=%d", pointnum);
+		ret = fts_gesture_read_buffer(client, buf, read_bytes);
+		if (ret < 0) {
+			FTS_ERROR("[GESTURE]Read gesture touch data failed!!");
+			FTS_FUNC_EXIT();
+			return ret;
+		}
+
+		fts_check_gesture(fts_input_dev, gestrue_id);
+		for (i = 0; i < pointnum; i++) {
+			fts_gesture_data.coordinate_x[i] =
+			    (((s16) buf[0 + (4 * i + 2)]) & 0x0F) << 8 |
+			    (((s16) buf[1 + (4 * i + 2)]) & 0xFF);
+			fts_gesture_data.coordinate_y[i] =
+			    (((s16) buf[2 + (4 * i + 2)]) & 0x0F) << 8 |
+			    (((s16) buf[3 + (4 * i + 2)]) & 0xFF);
+		}
+		FTS_FUNC_EXIT();
+		return 0;
+	}
+	/* other IC's gestrue in driver */
+	if (0x24 == buf[0]) {
+		gestrue_id = 0x24;
+		fts_check_gesture(fts_input_dev, gestrue_id);
+		FTS_DEBUG("[GESTURE]%d check_gesture gestrue_id", gestrue_id);
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	/* Host Driver recognize gesture */
+	pointnum = buf[1];
+	read_bytes = ((int)pointnum) * 4 + 2;
+	buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+	ret = fts_gesture_read_buffer(client, buf, read_bytes);
+	if (ret < 0) {
+		FTS_ERROR ("[GESTURE]Driver recognize gesture -"
+					"Read gesture touch data failed!!");
+		FTS_FUNC_EXIT();
+		return ret;
+	}
+
+	/*
+	 * Host Driver recognize gesture, need gesture lib.a
+	 * Not use now for compatibility
+	 gestrue_id = fetch_object_sample(buf, pointnum);
+	 */
+	gestrue_id = 0x24;
+	fts_check_gesture(fts_input_dev, gestrue_id);
+	FTS_DEBUG("[GESTURE]%d read gestrue_id", gestrue_id);
+
+	for (i = 0; i < pointnum; i++) {
+		fts_gesture_data.coordinate_x[i] =
+		    (((s16) buf[0 + (4 * i + 8)]) & 0x0F) << 8 |
+		    (((s16) buf[1 + (4 * i + 8)]) & 0xFF);
+		fts_gesture_data.coordinate_y[i] =
+		    (((s16) buf[2 + (4 * i + 8)]) & 0x0F) << 8 |
+		    (((s16) buf[3 + (4 * i + 8)]) & 0xFF);
+	}
+	FTS_FUNC_EXIT();
+	return -1;
+}
+
+/*****************************************************************************
+*   Name: fts_gesture_suspend
+*  Brief:
+*  Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_suspend(struct i2c_client *i2c_client)
+{
+	int i;
+	u8 state;
+
+	FTS_FUNC_ENTER();
+
+	/* gesture not enable, return immediately */
+	if (fts_gesture_data.mode == 0) {
+		FTS_DEBUG("gesture is disabled");
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	for (i = 0; i < 5; i++) {
+		fts_i2c_write_reg(i2c_client, 0xd1, 0xff);
+		fts_i2c_write_reg(i2c_client, 0xd2, 0xff);
+		fts_i2c_write_reg(i2c_client, 0xd5, 0xff);
+		fts_i2c_write_reg(i2c_client, 0xd6, 0xff);
+		fts_i2c_write_reg(i2c_client, 0xd7, 0xff);
+		fts_i2c_write_reg(i2c_client, 0xd8, 0xff);
+		fts_i2c_write_reg(i2c_client, FTS_REG_GESTURE_EN, 0x01);
+		msleep(1);
+		fts_i2c_read_reg(i2c_client, FTS_REG_GESTURE_EN, &state);
+		if (state == 1)
+			break;
+	}
+
+	if (i >= 5) {
+		FTS_ERROR("[GESTURE]Enter into gesture(suspend) failed!\n");
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	fts_gesture_data.active = 1;
+	FTS_DEBUG("[GESTURE]Enter into gesture(suspend) successfully!");
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/*****************************************************************************
+*   Name: fts_gesture_resume
+*  Brief:
+*  Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_resume(struct i2c_client *client)
+{
+	int i;
+	u8 state;
+
+	FTS_FUNC_ENTER();
+
+	/* gesture not enable, return immediately */
+	if (fts_gesture_data.mode == 0) {
+		FTS_DEBUG("gesture is disabled");
+		FTS_FUNC_EXIT();
+		return -1;
+	}
+
+	fts_gesture_data.active = 0;
+	for (i = 0; i < 5; i++) {
+		fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, 0x00);
+		msleep(1);
+		fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &state);
+		if (state == 0)
+			break;
+	}
+
+	if (i >= 5)
+		FTS_ERROR("[GESTURE]Clear gesture(resume) failed!\n");
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+#endif
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c
@@ -0,0 +1,209 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/************************************************************************
+*
+* File Name: focaltech_i2c.c
+*
+*    Author: fupeipei
+*
+*   Created: 2016-08-04
+*
+*  Abstract: i2c communication with TP
+*
+*   Version: v1.0
+*
+* Revision History:
+*        v1.0:
+*            First release. By fupeipei 2016-08-04
+************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static DEFINE_MUTEX(i2c_rw_access);
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+
+/************************************************************************
+* Name: fts_i2c_read
+* Brief: i2c read
+* Input: i2c info, write buf, write len, read buf, read len
+* Output: get data in the 3rd buf
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_read(struct i2c_client *client, char *writebuf, int writelen,
+		 char *readbuf, int readlen)
+{
+	int ret = 0;
+
+	mutex_lock(&i2c_rw_access);
+
+	if (readlen > 0) {
+		if (writelen > 0) {
+			struct i2c_msg msgs[] = {
+				{
+				 .addr = client->addr,
+				 .flags = 0,
+				 .len = writelen,
+				 .buf = writebuf,
+				 },
+				{
+				 .addr = client->addr,
+				 .flags = I2C_M_RD,
+				 .len = readlen,
+				 .buf = readbuf,
+				 },
+			};
+			ret = i2c_transfer(client->adapter, msgs, 2);
+			if (ret < 0) {
+				FTS_ERROR("[IIC]: i2c_transfer(write)"
+					"error,ret=%d!!", ret);
+			}
+		} else {
+			struct i2c_msg msgs[] = {
+				{
+				 .addr = client->addr,
+				 .flags = I2C_M_RD,
+				 .len = readlen,
+				 .buf = readbuf,
+				 },
+			};
+			ret = i2c_transfer(client->adapter, msgs, 1);
+			if (ret < 0) {
+				FTS_ERROR("[IIC]: i2c_transfer(read)"
+					"error, ret=%d!!", ret);
+			}
+		}
+	}
+
+	mutex_unlock(&i2c_rw_access);
+	return ret;
+}
+
+/************************************************************************
+* Name: fts_i2c_write
+* Brief: i2c write
+* Input: i2c info, write buf, write len
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen)
+{
+	int ret = 0;
+
+	mutex_lock(&i2c_rw_access);
+	if (writelen > 0) {
+		struct i2c_msg msgs[] = {
+			{
+			 .addr = client->addr,
+			 .flags = 0,
+			 .len = writelen,
+			 .buf = writebuf,
+			 },
+		};
+		ret = i2c_transfer(client->adapter, msgs, 1);
+		if (ret < 0) {
+			FTS_ERROR("%s: i2c_transfer(write) error, ret=%d",
+				  __func__, ret);
+		}
+	}
+	mutex_unlock(&i2c_rw_access);
+
+	return ret;
+}
+
+/************************************************************************
+* Name: fts_i2c_write_reg
+* Brief: write register
+* Input: i2c info, reg address, reg value
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue)
+{
+	u8 buf[2] = { 0 };
+
+	buf[0] = regaddr;
+	buf[1] = regvalue;
+	return fts_i2c_write(client, buf, sizeof(buf));
+}
+
+/************************************************************************
+* Name: fts_i2c_read_reg
+* Brief: read register
+* Input: i2c info, reg address, reg value
+* Output: get reg value
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue)
+{
+	return fts_i2c_read(client, &regaddr, 1, regvalue, 1);
+}
+
+/************************************************************************
+* Name: fts_i2c_init
+* Brief: fts i2c init
+* Input:
+* Output:
+* Return:
+***********************************************************************/
+int fts_i2c_init(void)
+{
+	FTS_FUNC_ENTER();
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+
+/************************************************************************
+* Name: fts_i2c_exit
+* Brief: fts i2c exit
+* Input:
+* Output:
+* Return:
+***********************************************************************/
+int fts_i2c_exit(void)
+{
+	FTS_FUNC_ENTER();
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c
@@ -0,0 +1,151 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+*
+* File Name: focaltech_point_report_check.c
+*
+*    Author: WangTao
+*
+*   Created: 2016-11-16
+*
+*  Abstract: point report check function
+*
+*   Version: v1.0
+*
+* Revision History:
+*        v1.0:
+*            First release. By WangTao 2016-11-16
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if FTS_POINT_REPORT_CHECK_EN
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define POINT_REPORT_CHECK_WAIT_TIME              200
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct delayed_work fts_point_report_check_work;
+static struct workqueue_struct *fts_point_report_check_workqueue;
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+
+/*****************************************************************************
+*  Name: fts_point_report_check_func
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_point_report_check_func(struct work_struct *work)
+{
+
+#if FTS_MT_PROTOCOL_B_EN
+	unsigned int finger_count = 0;
+
+	FTS_FUNC_ENTER();
+
+	for (finger_count = 0; finger_count < FTS_MAX_POINTS; finger_count++) {
+		input_mt_slot(fts_input_dev, finger_count);
+		input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER,
+					   false);
+	}
+#else
+	input_mt_sync(fts_input_dev);
+#endif
+	input_report_key(fts_input_dev, BTN_TOUCH, 0);
+	input_sync(fts_input_dev);
+
+	FTS_FUNC_EXIT();
+}
+
+void fts_point_report_check_queue_work(void)
+{
+
+	cancel_delayed_work(&fts_point_report_check_work);
+	queue_delayed_work(fts_point_report_check_workqueue,
+			   &fts_point_report_check_work,
+			   msecs_to_jiffies(POINT_REPORT_CHECK_WAIT_TIME));
+
+}
+
+/*****************************************************************************
+*  Name: fts_point_report_check_init
+*  Brief:
+*  Input:
+*  Output:
+*  Return: < 0: Fail to create esd check queue
+*****************************************************************************/
+int fts_point_report_check_init(void)
+{
+	FTS_FUNC_ENTER();
+
+	INIT_DELAYED_WORK(&fts_point_report_check_work,
+			  fts_point_report_check_func);
+	fts_point_report_check_workqueue =
+	    create_workqueue("fts_point_report_check_func_wq");
+	if (fts_point_report_check_workqueue == NULL) {
+		FTS_ERROR("[POINT_REPORT]: Failed to create"
+				"fts_point_report_check_workqueue!!");
+	} else {
+		FTS_DEBUG("[POINT_REPORT]: Success to create"
+				"fts_point_report_check_workqueue!!");
+	}
+
+	FTS_FUNC_EXIT();
+
+	return 0;
+}
+
+/*****************************************************************************
+*  Name: fts_point_report_check_exit
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+int fts_point_report_check_exit(void)
+{
+	FTS_FUNC_ENTER();
+
+	destroy_workqueue(fts_point_report_check_workqueue);
+
+	FTS_FUNC_EXIT();
+	return 0;
+}
+#endif /* FTS_POINT_REPORT_CHECK_EN */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c
@@ -0,0 +1,311 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, FocalTech Systems, Ltd., all rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+*
+* File Name: focaltech_esdcheck.c
+*
+*    Author: Focaltech Driver Team
+*
+*   Created: 2016-08-03
+*
+*  Abstract: Sensor
+*
+*   Version: v1.0
+*
+* Revision History:
+*        v1.0:
+*            First release. By luougojin 2016-08-03
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if FTS_PSENSOR_EN
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+/* psensor register address*/
+#define FTS_REG_PSENSOR_ENABLE                  0xB0
+#define FTS_REG_PSENSOR_STATUS                  0x01
+
+/* psensor register bits*/
+#define FTS_PSENSOR_ENABLE_MASK                 0x01
+#define FTS_PSENSOR_STATUS_NEAR                 0xC0
+#define FTS_PSENSOR_STATUS_FAR                  0xE0
+#define FTS_PSENSOR_FAR_TO_NEAR                 0
+#define FTS_PSENSOR_NEAR_TO_FAR                 1
+#define FTS_PSENSOR_ORIGINAL_STATE_FAR          1
+#define FTS_PSENSOR_WAKEUP_TIMEOUT              500
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct sensors_classdev __maybe_unused sensors_proximity_cdev = {
+	.name = "fts-proximity",
+	.vendor = "FocalTech",
+	.version = 1,
+	.handle = SENSORS_PROXIMITY_HANDLE,
+	.type = SENSOR_TYPE_PROXIMITY,
+	.max_range = "5.0",
+	.resolution = "5.0",
+	.sensor_power = "0.1",
+	.min_delay = 0,
+	.fifo_reserved_event_count = 0,
+	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = 200,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
+};
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+/*****************************************************************************
+*  Name: fts_psensor_support_enabled
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static inline bool fts_psensor_support_enabled(void)
+{
+	/*return config_enabled(CONFIG_TOUCHSCREEN_FTS_PSENSOR); */
+	return FTS_PSENSOR_EN;
+}
+
+/*****************************************************************************
+*  Name: fts_psensor_enable
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static void fts_psensor_enable(struct fts_ts_data *data, int enable)
+{
+	u8 state;
+	int ret = -1;
+
+	if (data->client == NULL)
+		return;
+
+	fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_ENABLE, &state);
+	if (enable)
+		state |= FTS_PSENSOR_ENABLE_MASK;
+	else
+		state &= ~FTS_PSENSOR_ENABLE_MASK;
+
+	ret = fts_i2c_write_reg(data->client, FTS_REG_PSENSOR_ENABLE, state);
+	if (ret < 0)
+		FTS_ERROR("write psensor switch command failed");
+}
+
+/*****************************************************************************
+*  Name: fts_psensor_enable_set
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_psensor_enable_set(struct sensors_classdev *sensors_cdev,
+				  unsigned int enable)
+{
+	struct fts_psensor_platform_data *psensor_pdata =
+	    container_of(sensors_cdev,
+			 struct fts_psensor_platform_data, ps_cdev);
+	struct fts_ts_data *data = psensor_pdata->data;
+	struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev;
+
+	mutex_lock(&input_dev->mutex);
+	fts_psensor_enable(data, enable);
+	psensor_pdata->tp_psensor_data = FTS_PSENSOR_ORIGINAL_STATE_FAR;
+	if (enable)
+		psensor_pdata->tp_psensor_opened = 1;
+	else
+		psensor_pdata->tp_psensor_opened = 0;
+	mutex_unlock(&input_dev->mutex);
+	return enable;
+}
+
+/*****************************************************************************
+*  Name: fts_read_tp_psensor_data
+*  Brief:
+*  Input:
+*  Output:
+*  Return:
+*****************************************************************************/
+static int fts_read_tp_psensor_data(struct fts_ts_data *data)
+{
+	u8 psensor_status;
+	char tmp;
+	int ret = 1;
+
+	fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_STATUS, &psensor_status);
+
+	tmp = data->psensor_pdata->tp_psensor_data;
+	if (psensor_status == FTS_PSENSOR_STATUS_NEAR)
+		data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_FAR_TO_NEAR;
+	else if (psensor_status == FTS_PSENSOR_STATUS_FAR)
+		data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_NEAR_TO_FAR;
+
+	if (tmp != data->psensor_pdata->tp_psensor_data) {
+		FTS_ERROR("%s sensor data changed", __func__);
+		ret = 0;
+	}
+	return ret;
+}
+
+int fts_sensor_read_data(struct fts_ts_data *data)
+{
+	int ret = 0;
+
+	if (fts_psensor_support_enabled()
+	    && data->psensor_pdata->tp_psensor_opened) {
+		ret = fts_read_tp_psensor_data(data);
+		if (!ret) {
+			if (data->suspended) {
+				pm_wakeup_event(&data->client->dev,
+						FTS_PSENSOR_WAKEUP_TIMEOUT);
+			}
+			input_report_abs(data->psensor_pdata->input_psensor_dev,
+					 ABS_DISTANCE,
+					 data->psensor_pdata->tp_psensor_data);
+			input_sync(data->psensor_pdata->input_psensor_dev);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+int fts_sensor_suspend(struct fts_ts_data *data)
+{
+	int ret = 0;
+
+	if (fts_psensor_support_enabled()
+	    && device_may_wakeup(&data->client->dev)
+	    && data->psensor_pdata->tp_psensor_opened) {
+		ret = enable_irq_wake(data->client->irq);
+		if (ret != 0)
+			FTS_ERROR("%s: set_irq_wake failed", __func__);
+		data->suspended = true;
+		return 1;
+	}
+
+	return 0;
+}
+
+int fts_sensor_resume(struct fts_ts_data *data)
+{
+	int ret = 0;
+
+	if (fts_psensor_support_enabled()
+	    && device_may_wakeup(&data->client->dev)
+	    && data->psensor_pdata->tp_psensor_opened) {
+		ret = disable_irq_wake(data->client->irq);
+		if (ret)
+			FTS_ERROR("%s: disable_irq_wake failed", __func__);
+		data->suspended = false;
+		return 1;
+	}
+
+	return 0;
+}
+
+int fts_sensor_init(struct fts_ts_data *data)
+{
+	struct fts_psensor_platform_data *psensor_pdata;
+	struct input_dev *psensor_input_dev;
+	int err;
+
+	if (fts_psensor_support_enabled()) {
+		device_init_wakeup(&data->client->dev, 1);
+		psensor_pdata =
+		    devm_kzalloc(&data->client->dev,
+				 sizeof(struct fts_psensor_platform_data),
+				 GFP_KERNEL);
+		if (!psensor_pdata) {
+			FTS_ERROR("Failed to allocate memory");
+			goto irq_free;
+		}
+		data->psensor_pdata = psensor_pdata;
+
+		psensor_input_dev = input_allocate_device();
+		if (!psensor_input_dev) {
+			FTS_ERROR("Failed to allocate device");
+			goto free_psensor_pdata;
+		}
+
+		__set_bit(EV_ABS, psensor_input_dev->evbit);
+		input_set_abs_params(psensor_input_dev, ABS_DISTANCE, 0, 1, 0,
+				     0);
+		psensor_input_dev->name = "proximity";
+		psensor_input_dev->id.bustype = BUS_I2C;
+		psensor_input_dev->dev.parent = &data->client->dev;
+		data->psensor_pdata->input_psensor_dev = psensor_input_dev;
+
+		err = input_register_device(psensor_input_dev);
+		if (err) {
+			FTS_ERROR("Unable to register device, err=%d", err);
+			goto free_psensor_input_dev;
+		}
+
+		psensor_pdata->ps_cdev = sensors_proximity_cdev;
+		psensor_pdata->ps_cdev.sensors_enable = fts_psensor_enable_set;
+		psensor_pdata->data = data;
+
+		err =
+		    sensors_classdev_register(&data->client->dev,
+					      &psensor_pdata->ps_cdev);
+		if (err)
+			goto unregister_psensor_input_device;
+	}
+
+	return 0;
+unregister_psensor_input_device:
+	if (fts_psensor_support_enabled())
+		input_unregister_device(data->psensor_pdata->input_psensor_dev);
+free_psensor_input_dev:
+	if (fts_psensor_support_enabled())
+		input_free_device(data->psensor_pdata->input_psensor_dev);
+free_psensor_pdata:
+	if (fts_psensor_support_enabled()) {
+		devm_kfree(&data->client->dev, psensor_pdata);
+		data->psensor_pdata = NULL;
+	}
+irq_free:
+	if (fts_psensor_support_enabled())
+		device_init_wakeup(&data->client->dev, 0);
+	free_irq(data->client->irq, data);
+
+	return 1;
+}
+
+int fts_sensor_remove(struct fts_ts_data *data)
+{
+	if (fts_psensor_support_enabled()) {
+		device_init_wakeup(&data->client->dev, 0);
+		sensors_classdev_unregister(&data->psensor_pdata->ps_cdev);
+		input_unregister_device(data->psensor_pdata->input_psensor_dev);
+		devm_kfree(&data->client->dev, data->psensor_pdata);
+		data->psensor_pdata = NULL;
+	}
+	return 0;
+}
+#endif /* FTS_PSENSOR_EN */
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/goodix.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/goodix.c
@@ -129,6 +129,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"),
@@ -149,16 +170,40 @@
 static const struct dmi_system_id nine_bytes_report[] = {
 #if defined(CONFIG_DMI) && defined(CONFIG_X86)
 	{
-		.ident = "Lenovo YogaBook",
-		/* YB1-X91L/F and YB1-X90L/F */
+		/* Lenovo Yoga Book X90F / X90L */
 		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
+		}
+	},
+	{
+		/* Lenovo Yoga Book X91F / X91L */
+		.matches = {
+			/* Non exact match to match F + L versions */
+			DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
 		}
 	},
 #endif
 	{}
 };
 
+/*
+ * Those tablets have their x coordinate inverted
+ */
+static const struct dmi_system_id inverted_x_screen[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+	{
+		.ident = "Cube I15-TC",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Cube"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC")
+		},
+	},
+#endif
+	{}
+};
+
 /**
  * goodix_i2c_read - read data from a register of the i2c slave device.
  *
@@ -298,7 +343,7 @@
 	 * The Goodix panel will send spurious interrupts after a
 	 * 'finger up' event, which will always cause a timeout.
 	 */
-	return 0;
+	return -ENOMSG;
 }
 
 static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
@@ -771,6 +816,12 @@
 			"Non-standard 9-bytes report format quirk\n");
 	}
 
+	if (dmi_check_system(inverted_x_screen)) {
+		ts->prop.invert_x = true;
+		dev_dbg(&ts->client->dev,
+			"Applying 'inverted x screen' quirk\n");
+	}
+
 	error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 	if (error) {
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/hideep.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/hideep.c
@@ -361,13 +361,16 @@
 	return -EIO;
 }
 
-static void hideep_nvm_unlock(struct hideep_ts *ts)
+static int hideep_nvm_unlock(struct hideep_ts *ts)
 {
 	u32 unmask_code;
+	int error;
 
 	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE);
-	hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
+	error = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
 	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+	if (error)
+		return error;
 
 	/* make it unprotected code */
 	unmask_code &= ~HIDEEP_PROT_MODE;
@@ -384,6 +387,8 @@
 	NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask);
 	SET_FLASH_HWCONTROL();
 	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+
+	return 0;
 }
 
 static int hideep_check_status(struct hideep_ts *ts)
@@ -462,7 +467,9 @@
 	u32 addr = 0;
 	int error;
 
-	hideep_nvm_unlock(ts);
+       error = hideep_nvm_unlock(ts);
+       if (error)
+               return error;
 
 	while (ucode_len > 0) {
 		xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/ili210x.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/ili210x.c
@@ -109,7 +109,7 @@
 	if (finger >= ILI210X_TOUCHES)
 		return false;
 
-	if (touchdata[0] & BIT(finger))
+	if (!(touchdata[0] & BIT(finger)))
 		return false;
 
 	*x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
@@ -290,9 +290,9 @@
 		if (error)
 			return error;
 
-		usleep_range(50, 100);
+		usleep_range(12000, 15000);
 		gpiod_set_value_cansleep(reset_gpio, 0);
-		msleep(100);
+		msleep(160);
 	}
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -334,7 +334,12 @@
 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
 	touchscreen_parse_properties(input, true, &priv->prop);
-	input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
+
+	error = input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
+	if (error) {
+		dev_err(dev, "Unable to set up slots, err: %d\n", error);
+		return error;
+	}
 
 	error = devm_add_action(dev, ili210x_cancel_work, priv);
 	if (error)
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/imx6ul_tsc.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/imx6ul_tsc.c
@@ -530,20 +530,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-ein-5.4.0.orig/drivers/input/touchscreen/melfas_mip4.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/melfas_mip4.c
@@ -1453,7 +1453,7 @@
 					      "ce", GPIOD_OUT_LOW);
 	if (IS_ERR(ts->gpio_ce)) {
 		error = PTR_ERR(ts->gpio_ce);
-		if (error != EPROBE_DEFER)
+		if (error != -EPROBE_DEFER)
 			dev_err(&client->dev,
 				"Failed to get gpio: %d\n", error);
 		return error;
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/mms114.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/mms114.c
@@ -54,6 +54,7 @@
 enum mms_type {
 	TYPE_MMS114	= 114,
 	TYPE_MMS152	= 152,
+	TYPE_MMS345L	= 345,
 };
 
 struct mms114_data {
@@ -91,15 +92,15 @@
 	if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL)
 		BUG();
 
-	/* Write register: use repeated start */
+	/* Write register */
 	xfer[0].addr = client->addr;
-	xfer[0].flags = I2C_M_TEN | I2C_M_NOSTART;
+	xfer[0].flags = client->flags & I2C_M_TEN;
 	xfer[0].len = 1;
 	xfer[0].buf = &buf;
 
 	/* Read data */
 	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
+	xfer[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
 	xfer[1].len = len;
 	xfer[1].buf = val;
 
@@ -250,6 +251,15 @@
 	int error;
 
 	switch (data->type) {
+	case TYPE_MMS345L:
+		error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
+		if (error)
+			return error;
+
+		dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n",
+			 buf[0], buf[1], buf[2]);
+		break;
+
 	case TYPE_MMS152:
 		error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
 		if (error)
@@ -287,8 +297,8 @@
 	if (error < 0)
 		return error;
 
-	/* MMS152 has no configuration or power on registers */
-	if (data->type == TYPE_MMS152)
+	/* Only MMS114 has configuration and power on registers */
+	if (data->type != TYPE_MMS114)
 		return 0;
 
 	error = mms114_set_active(data, true);
@@ -428,10 +438,8 @@
 	const void *match_data;
 	int error;
 
-	if (!i2c_check_functionality(client->adapter,
-				I2C_FUNC_PROTOCOL_MANGLING)) {
-		dev_err(&client->dev,
-			"Need i2c bus that supports protocol mangling\n");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "Not supported I2C adapter\n");
 		return -ENODEV;
 	}
 
@@ -600,6 +608,9 @@
 	}, {
 		.compatible = "melfas,mms152",
 		.data = (void *)TYPE_MMS152,
+	}, {
+		.compatible = "melfas,mms345l",
+		.data = (void *)TYPE_MMS345L,
 	},
 	{ }
 };
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/of_touchscreen.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/of_touchscreen.c
@@ -77,12 +77,12 @@
 	axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
 	data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
 						input_abs_get_min(input, axis),
-						&minimum) |
-		       touchscreen_get_prop_u32(dev, "touchscreen-size-x",
+						&minimum);
+	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x",
 						input_abs_get_max(input,
 								  axis) + 1,
-						&maximum) |
-		       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
+						&maximum);
+	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
 						input_abs_get_fuzz(input, axis),
 						&fuzz);
 	if (data_present)
@@ -91,12 +91,12 @@
 	axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
 	data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
 						input_abs_get_min(input, axis),
-						&minimum) |
-		       touchscreen_get_prop_u32(dev, "touchscreen-size-y",
+						&minimum);
+	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y",
 						input_abs_get_max(input,
 								  axis) + 1,
-						&maximum) |
-		       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
+						&maximum);
+	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
 						input_abs_get_fuzz(input, axis),
 						&fuzz);
 	if (data_present)
@@ -106,11 +106,11 @@
 	data_present = touchscreen_get_prop_u32(dev,
 						"touchscreen-max-pressure",
 						input_abs_get_max(input, axis),
-						&maximum) |
-		       touchscreen_get_prop_u32(dev,
-						"touchscreen-fuzz-pressure",
-						input_abs_get_fuzz(input, axis),
-						&fuzz);
+						&maximum);
+	data_present |= touchscreen_get_prop_u32(dev,
+						 "touchscreen-fuzz-pressure",
+						 input_abs_get_fuzz(input, axis),
+						 &fuzz);
 	if (data_present)
 		touchscreen_set_params(input, axis, 0, maximum, fuzz);
 
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/raspberrypi-ts.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/raspberrypi-ts.c
@@ -137,7 +137,7 @@
 		return -ENOENT;
 	}
 
-	fw = rpi_firmware_get(fw_node);
+	fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
 	of_node_put(fw_node);
 	if (!fw)
 		return -EPROBE_DEFER;
@@ -164,7 +164,6 @@
 	touchbuf = (u32)ts->fw_regs_phys;
 	error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF,
 				      &touchbuf, sizeof(touchbuf));
-
 	if (error || touchbuf != 0) {
 		dev_warn(dev, "Failed to set touchbuf, %d\n", error);
 		return error;
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/raydium_i2c_ts.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -410,6 +410,7 @@
 				    enum raydium_bl_ack state)
 {
 	int error;
+	static const u8 cmd[] = { 0xFF, 0x39 };
 
 	error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
 	if (error) {
@@ -418,7 +419,7 @@
 		return error;
 	}
 
-	error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0);
+	error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd));
 	if (error) {
 		dev_err(&client->dev, "Ack obj command failed: %d\n", error);
 		return error;
@@ -432,7 +433,7 @@
 	return 0;
 }
 
-static bool raydium_i2c_boot_trigger(struct i2c_client *client)
+static int raydium_i2c_boot_trigger(struct i2c_client *client)
 {
 	static const u8 cmd[7][6] = {
 		{ 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 },
@@ -457,10 +458,10 @@
 		}
 	}
 
-	return false;
+	return 0;
 }
 
-static bool raydium_i2c_fw_trigger(struct i2c_client *client)
+static int raydium_i2c_fw_trigger(struct i2c_client *client)
 {
 	static const u8 cmd[5][11] = {
 		{ 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 },
@@ -483,7 +484,7 @@
 		}
 	}
 
-	return false;
+	return 0;
 }
 
 static int raydium_i2c_check_path(struct i2c_client *client)
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/s6sy761.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/s6sy761.c
@@ -145,8 +145,8 @@
 	u8 major = event[4];
 	u8 minor = event[5];
 	u8 z = event[6] & S6SY761_MASK_Z;
-	u16 x = (event[1] << 3) | ((event[3] & S6SY761_MASK_X) >> 4);
-	u16 y = (event[2] << 3) | (event[3] & S6SY761_MASK_Y);
+	u16 x = (event[1] << 4) | ((event[3] & S6SY761_MASK_X) >> 4);
+	u16 y = (event[2] << 4) | (event[3] & S6SY761_MASK_Y);
 
 	input_mt_slot(sdata->input, tid);
 
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/silead.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/silead.c
@@ -20,6 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/irq.h>
 #include <linux/regulator/consumer.h>
 
@@ -335,10 +336,8 @@
 
 	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
 					      sizeof(chip_id), (u8 *)&chip_id);
-	if (error < 0) {
-		dev_err(&client->dev, "Chip ID read error %d\n", error);
+	if (error < 0)
 		return error;
-	}
 
 	data->chip_id = le32_to_cpu(chip_id);
 	dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id);
@@ -351,12 +350,49 @@
 	int error;
 	u32 status;
 
+	/*
+	 * Some buggy BIOS-es bring up the chip in a stuck state where it
+	 * blocks the I2C bus. The following steps are necessary to
+	 * unstuck the chip / bus:
+	 * 1. Turn off the Silead chip.
+	 * 2. Try to do an I2C transfer with the chip, this will fail in
+	 *    response to which the I2C-bus-driver will call:
+	 *    i2c_recover_bus() which will unstuck the I2C-bus. Note the
+	 *    unstuck-ing of the I2C bus only works if we first drop the
+	 *    chip off the bus by turning it off.
+	 * 3. Turn the chip back on.
+	 *
+	 * On the x86/ACPI systems were this problem is seen, step 1. and
+	 * 3. require making ACPI calls and dealing with ACPI Power
+	 * Resources. The workaround below runtime-suspends the chip to
+	 * turn it off, leaving it up to the ACPI subsystem to deal with
+	 * this.
+	 */
+
+	if (device_property_read_bool(&client->dev,
+				      "silead,stuck-controller-bug")) {
+		pm_runtime_set_active(&client->dev);
+		pm_runtime_enable(&client->dev);
+		pm_runtime_allow(&client->dev);
+
+		pm_runtime_suspend(&client->dev);
+
+		dev_warn(&client->dev, FW_BUG "Stuck I2C bus: please ignore the next 'controller timed out' error\n");
+		silead_ts_get_id(client);
+
+		/* The forbid will also resume the device */
+		pm_runtime_forbid(&client->dev);
+		pm_runtime_disable(&client->dev);
+	}
+
 	silead_ts_set_power(client, SILEAD_POWER_OFF);
 	silead_ts_set_power(client, SILEAD_POWER_ON);
 
 	error = silead_ts_get_id(client);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Chip ID read error %d\n", error);
 		return error;
+	}
 
 	error = silead_ts_init(client);
 	if (error)
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/st1232.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/st1232.c
@@ -149,6 +149,11 @@
 		gpiod_set_value_cansleep(ts->reset_gpio, !poweron);
 }
 
+static void st1232_ts_power_off(void *data)
+{
+	st1232_ts_power(data, false);
+}
+
 static const struct st_chip_info st1232_chip_info = {
 	.have_z		= true,
 	.max_x		= 0x31f, /* 800 - 1 */
@@ -229,6 +234,13 @@
 
 	st1232_ts_power(ts, true);
 
+	error = devm_add_action_or_reset(&client->dev, st1232_ts_power_off, ts);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to install power off action: %d\n", error);
+		return error;
+	}
+
 	input_dev->name = "st1232-touchscreen";
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->dev.parent = &client->dev;
@@ -271,15 +283,6 @@
 	return 0;
 }
 
-static int st1232_ts_remove(struct i2c_client *client)
-{
-	struct st1232_ts_data *ts = i2c_get_clientdata(client);
-
-	st1232_ts_power(ts, false);
-
-	return 0;
-}
-
 static int __maybe_unused st1232_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -329,7 +332,6 @@
 
 static struct i2c_driver st1232_ts_driver = {
 	.probe		= st1232_ts_probe,
-	.remove		= st1232_ts_remove,
 	.id_table	= st1232_ts_id,
 	.driver = {
 		.name	= ST1232_TS_NAME,
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/stmfts.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/stmfts.c
@@ -337,13 +337,15 @@
 	struct stmfts_data *sdata = input_get_drvdata(dev);
 	int err;
 
-	err = pm_runtime_get_sync(&sdata->client->dev);
-	if (err < 0)
+	err = pm_runtime_resume_and_get(&sdata->client->dev);
+	if (err)
 		return err;
 
 	err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON);
-	if (err)
+	if (err) {
+		pm_runtime_put_sync(&sdata->client->dev);
 		return err;
+	}
 
 	mutex_lock(&sdata->mutex);
 	sdata->running = true;
@@ -479,7 +481,7 @@
 
 	mutex_lock(&sdata->mutex);
 
-	if (value & sdata->hover_enabled)
+	if (value && sdata->hover_enabled)
 		goto out;
 
 	if (sdata->running)
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/sun4i-ts.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/sun4i-ts.c
@@ -237,6 +237,7 @@
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct device *hwmon;
+	struct thermal_zone_device *thermal;
 	int error;
 	u32 reg;
 	bool ts_attached;
@@ -355,7 +356,10 @@
 	if (IS_ERR(hwmon))
 		return PTR_ERR(hwmon);
 
-	devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops);
+	thermal = devm_thermal_zone_of_sensor_register(ts->dev, 0, ts,
+						       &sun4i_ts_tz_ops);
+	if (IS_ERR(thermal))
+		return PTR_ERR(thermal);
 
 	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
 
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/sur40.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/sur40.c
@@ -653,7 +653,7 @@
 	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;
 
@@ -774,6 +774,7 @@
 		dev_err(&interface->dev,
 			"Unable to register video controls.");
 		v4l2_ctrl_handler_free(&sur40->hdl);
+		error = sur40->hdl.error;
 		goto err_unreg_v4l2;
 	}
 
--- linux-ein-5.4.0.orig/drivers/input/touchscreen/usbtouchscreen.c
+++ linux-ein-5.4.0/drivers/input/touchscreen/usbtouchscreen.c
@@ -182,6 +182,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},
@@ -250,7 +251,7 @@
 	int ret;
 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
 
-	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 	                      0x01, 0x02, 0x0000, 0x0081,
 	                      NULL, 0, USB_CTRL_SET_TIMEOUT);
 
@@ -530,7 +531,7 @@
 	if (ret)
 		return ret;
 
-	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 	                      MTOUCHUSB_RESET,
 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -542,7 +543,7 @@
 	msleep(150);
 
 	for (i = 0; i < 3; i++) {
-		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 				      MTOUCHUSB_ASYNC_REPORT,
 				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -721,7 +722,7 @@
 	}
 
 	/* start sending data */
-	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 	                      TSC10_CMD_DATA1,
 	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
--- linux-ein-5.4.0.orig/drivers/interconnect/core.c
+++ linux-ein-5.4.0/drivers/interconnect/core.c
@@ -19,39 +19,13 @@
 #include <linux/of.h>
 #include <linux/overflow.h>
 
+#include "internal.h"
+
 static DEFINE_IDR(icc_idr);
 static LIST_HEAD(icc_providers);
 static DEFINE_MUTEX(icc_lock);
 static struct dentry *icc_debugfs_dir;
 
-/**
- * struct icc_req - constraints that are attached to each node
- * @req_node: entry in list of requests for the particular @node
- * @node: the interconnect node to which this constraint applies
- * @dev: reference to the device that sets the constraints
- * @tag: path tag (optional)
- * @avg_bw: an integer describing the average bandwidth in kBps
- * @peak_bw: an integer describing the peak bandwidth in kBps
- */
-struct icc_req {
-	struct hlist_node req_node;
-	struct icc_node *node;
-	struct device *dev;
-	u32 tag;
-	u32 avg_bw;
-	u32 peak_bw;
-};
-
-/**
- * struct icc_path - interconnect path structure
- * @num_nodes: number of hops (nodes)
- * @reqs: array of the requests applicable to this path of nodes
- */
-struct icc_path {
-	size_t num_nodes;
-	struct icc_req reqs[];
-};
-
 static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
 {
 	if (!n)
@@ -117,6 +91,7 @@
 		hlist_add_head(&path->reqs[i].req_node, &node->req_list);
 		path->reqs[i].node = node;
 		path->reqs[i].dev = dev;
+		path->reqs[i].enabled = true;
 		/* reference to previous node was saved during path traversal */
 		node = node->reverse;
 	}
@@ -201,6 +176,7 @@
 {
 	struct icc_provider *p = node->provider;
 	struct icc_req *r;
+	u32 avg_bw, peak_bw;
 
 	node->avg_bw = 0;
 	node->peak_bw = 0;
@@ -208,9 +184,17 @@
 	if (p->pre_aggregate)
 		p->pre_aggregate(node);
 
-	hlist_for_each_entry(r, &node->req_list, req_node)
-		p->aggregate(node, r->tag, r->avg_bw, r->peak_bw,
+	hlist_for_each_entry(r, &node->req_list, req_node) {
+		if (r->enabled) {
+			avg_bw = r->avg_bw;
+			peak_bw = r->peak_bw;
+		} else {
+			avg_bw = 0;
+			peak_bw = 0;
+		}
+		p->aggregate(node, r->tag, avg_bw, peak_bw,
 			     &node->avg_bw, &node->peak_bw);
+	}
 
 	return 0;
 }
@@ -296,6 +280,9 @@
 	}
 	mutex_unlock(&icc_lock);
 
+	if (!node)
+		return ERR_PTR(-EINVAL);
+
 	return node;
 }
 
@@ -475,6 +462,39 @@
 }
 EXPORT_SYMBOL_GPL(icc_set_bw);
 
+static int __icc_enable(struct icc_path *path, bool enable)
+{
+	int i;
+
+	if (!path)
+		return 0;
+
+	if (WARN_ON(IS_ERR(path) || !path->num_nodes))
+		return -EINVAL;
+
+	mutex_lock(&icc_lock);
+
+	for (i = 0; i < path->num_nodes; i++)
+		path->reqs[i].enabled = enable;
+
+	mutex_unlock(&icc_lock);
+
+	return icc_set_bw(path, path->reqs[0].avg_bw,
+			  path->reqs[0].peak_bw);
+}
+
+int icc_enable(struct icc_path *path)
+{
+	return __icc_enable(path, true);
+}
+EXPORT_SYMBOL_GPL(icc_enable);
+
+int icc_disable(struct icc_path *path)
+{
+	return __icc_enable(path, false);
+}
+EXPORT_SYMBOL_GPL(icc_disable);
+
 /**
  * icc_get() - return a handle for path between two endpoints
  * @dev: the device requesting the path
@@ -612,6 +632,10 @@
 
 	mutex_unlock(&icc_lock);
 
+	if (!node)
+		return;
+
+	kfree(node->links);
 	kfree(node);
 }
 EXPORT_SYMBOL_GPL(icc_node_destroy);
@@ -704,6 +728,8 @@
 		       GFP_KERNEL);
 	if (new)
 		src->links = new;
+	else
+		ret = -ENOMEM;
 
 out:
 	mutex_unlock(&icc_lock);
--- linux-ein-5.4.0.orig/drivers/interconnect/internal.h
+++ linux-ein-5.4.0/drivers/interconnect/internal.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Interconnect framework internal structs
+ *
+ * Copyright (c) 2019, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_INTERNAL_H
+#define __DRIVERS_INTERCONNECT_INTERNAL_H
+
+/**
+ * struct icc_req - constraints that are attached to each node
+ * @req_node: entry in list of requests for the particular @node
+ * @node: the interconnect node to which this constraint applies
+ * @dev: reference to the device that sets the constraints
+ * @enabled: indicates whether the path with this request is enabled
+ * @tag: path tag (optional)
+ * @avg_bw: an integer describing the average bandwidth in kBps
+ * @peak_bw: an integer describing the peak bandwidth in kBps
+ */
+struct icc_req {
+	struct hlist_node req_node;
+	struct icc_node *node;
+	struct device *dev;
+	bool enabled;
+	u32 tag;
+	u32 avg_bw;
+	u32 peak_bw;
+};
+
+/**
+ * struct icc_path - interconnect path structure
+ * @num_nodes: number of hops (nodes)
+ * @reqs: array of the requests applicable to this path of nodes
+ */
+struct icc_path {
+	size_t num_nodes;
+	struct icc_req reqs[];
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/interconnect/qcom/qcs404.c
+++ linux-ein-5.4.0/drivers/interconnect/qcom/qcs404.c
@@ -157,8 +157,8 @@
 	}
 
 DEFINE_QNODE(mas_apps_proc, QCS404_MASTER_AMPSS_M0, 8, 0, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
-DEFINE_QNODE(mas_oxili, QCS404_MASTER_GRAPHICS_3D, 8, 6, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
-DEFINE_QNODE(mas_mdp, QCS404_MASTER_MDP_PORT0, 8, 8, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_oxili, QCS404_MASTER_GRAPHICS_3D, 8, -1, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_mdp, QCS404_MASTER_MDP_PORT0, 8, -1, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
 DEFINE_QNODE(mas_snoc_bimc_1, QCS404_SNOC_BIMC_1_MAS, 8, 76, -1, QCS404_SLAVE_EBI_CH0);
 DEFINE_QNODE(mas_tcu_0, QCS404_MASTER_TCU_0, 8, -1, -1, QCS404_SLAVE_EBI_CH0, QCS404_BIMC_SNOC_SLV);
 DEFINE_QNODE(mas_spdm, QCS404_MASTER_SPDM, 4, -1, -1, QCS404_PNOC_INT_3);
@@ -414,7 +414,7 @@
 	struct icc_provider *provider;
 	struct qcom_icc_node **qnodes;
 	struct qcom_icc_provider *qp;
-	struct icc_node *node;
+	struct icc_node *node, *tmp;
 	size_t num_nodes, i;
 	int ret;
 
@@ -494,7 +494,7 @@
 
 	return 0;
 err:
-	list_for_each_entry(node, &provider->nodes, node_list) {
+	list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) {
 		icc_node_del(node);
 		icc_node_destroy(node->id);
 	}
@@ -508,9 +508,9 @@
 {
 	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
 	struct icc_provider *provider = &qp->provider;
-	struct icc_node *n;
+	struct icc_node *n, *tmp;
 
-	list_for_each_entry(n, &provider->nodes, node_list) {
+	list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
 		icc_node_del(n);
 		icc_node_destroy(n->id);
 	}
--- linux-ein-5.4.0.orig/drivers/interconnect/qcom/sdm845.c
+++ linux-ein-5.4.0/drivers/interconnect/qcom/sdm845.c
@@ -868,9 +868,9 @@
 {
 	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
 	struct icc_provider *provider = &qp->provider;
-	struct icc_node *n;
+	struct icc_node *n, *tmp;
 
-	list_for_each_entry(n, &provider->nodes, node_list) {
+	list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
 		icc_node_del(n);
 		icc_node_destroy(n->id);
 	}
--- linux-ein-5.4.0.orig/drivers/iommu/Kconfig
+++ linux-ein-5.4.0/drivers/iommu/Kconfig
@@ -138,7 +138,7 @@
 	select PCI_PASID
 	select IOMMU_API
 	select IOMMU_IOVA
-	depends on X86_64 && PCI && ACPI
+	depends on X86_64 && PCI && ACPI && HAVE_CMPXCHG_DOUBLE
 	---help---
 	  With this option you can enable support for AMD IOMMU hardware in
 	  your system. An IOMMU is a hardware component which provides
@@ -205,7 +205,7 @@
 
 config INTEL_IOMMU_SVM
 	bool "Support for Shared Virtual Memory with Intel IOMMU"
-	depends on INTEL_IOMMU && X86
+	depends on INTEL_IOMMU && X86_64
 	select PCI_PASID
 	select MMU_NOTIFIER
 	help
--- linux-ein-5.4.0.orig/drivers/iommu/amd_iommu.c
+++ linux-ein-5.4.0/drivers/iommu/amd_iommu.c
@@ -226,71 +226,58 @@
 	return NULL;
 }
 
-static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
+static int clone_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;
+	u16 devid = pci_dev_id(pdev);
 
-	/* The callers make sure that get_device_id() does not fail here */
-	devid = get_device_id(dev);
-
-	/* For ACPI HID devices, we simply return the devid as such */
-	if (!dev_is_pci(dev))
-		return devid;
+	if (devid == alias)
+		return 0;
 
-	ivrs_alias = amd_iommu_alias_table[devid];
+	amd_iommu_rlookup_table[alias] =
+		amd_iommu_rlookup_table[devid];
+	memcpy(amd_iommu_dev_table[alias].data,
+	       amd_iommu_dev_table[devid].data,
+	       sizeof(amd_iommu_dev_table[alias].data));
 
-	pci_for_each_dma_alias(pdev, __last_alias, &pci_alias);
+	return 0;
+}
 
-	if (ivrs_alias == pci_alias)
-		return ivrs_alias;
+static void clone_aliases(struct pci_dev *pdev)
+{
+	if (!pdev)
+		return;
 
 	/*
-	 * 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.
+	 * The IVRS alias stored in the alias table may not be
+	 * part of the PCI DMA aliases if it's bus differs
+	 * from the original 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));
-		}
+	clone_alias(pdev, amd_iommu_alias_table[pci_dev_id(pdev)], NULL);
 
-		return pci_alias;
-	}
+	pci_for_each_dma_alias(pdev, clone_alias, NULL);
+}
 
-	pci_info(pdev, "Using IVRS reported alias %02x:%02x.%d "
-		"for device [%04x:%04x], kernel reported alias "
-		"%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias),
-		PCI_FUNC(ivrs_alias), pdev->vendor, pdev->device,
-		PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias),
-		PCI_FUNC(pci_alias));
+static struct pci_dev *setup_aliases(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u16 ivrs_alias;
+
+	/* For ACPI HID devices, there are no aliases */
+	if (!dev_is_pci(dev))
+		return NULL;
 
 	/*
-	 * 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.
+	 * Add the IVRS alias to the pci aliases if it is on the same
+	 * bus. The IVRS table may know about a quirk that we don't.
 	 */
-	if (pci_alias == devid &&
-	    PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
-		pci_add_dma_alias(pdev, ivrs_alias & 0xff);
-		pci_info(pdev, "Added PCI DMA alias %02x.%d\n",
-			PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias));
-	}
+	ivrs_alias = amd_iommu_alias_table[pci_dev_id(pdev)];
+	if (ivrs_alias != pci_dev_id(pdev) &&
+	    PCI_BUS_NUM(ivrs_alias) == pdev->bus->number)
+		pci_add_dma_alias(pdev, ivrs_alias & 0xff, 1);
+
+	clone_aliases(pdev);
 
-	return ivrs_alias;
+	return pdev;
 }
 
 static struct iommu_dev_data *find_dev_data(u16 devid)
@@ -428,7 +415,7 @@
 	if (!dev_data)
 		return -ENOMEM;
 
-	dev_data->alias = get_alias(dev);
+	dev_data->pdev = setup_aliases(dev);
 
 	/*
 	 * By default we use passthrough mode for IOMMUv2 capable device.
@@ -453,20 +440,16 @@
 
 static void iommu_ignore_device(struct device *dev)
 {
-	u16 alias;
 	int devid;
 
 	devid = get_device_id(dev);
 	if (devid < 0)
 		return;
 
-	alias = get_alias(dev);
-
+	amd_iommu_rlookup_table[devid] = NULL;
 	memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
-	memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
 
-	amd_iommu_rlookup_table[devid] = NULL;
-	amd_iommu_rlookup_table[alias] = NULL;
+	setup_aliases(dev);
 }
 
 static void iommu_uninit_device(struct device *dev)
@@ -1236,6 +1219,13 @@
 	return iommu_queue_command(iommu, &cmd);
 }
 
+static int device_flush_dte_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+	struct amd_iommu *iommu = data;
+
+	return iommu_flush_dte(iommu, alias);
+}
+
 /*
  * Command send function for invalidating a device table entry
  */
@@ -1246,14 +1236,22 @@
 	int ret;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = dev_data->alias;
 
-	ret = iommu_flush_dte(iommu, dev_data->devid);
-	if (!ret && alias != dev_data->devid)
-		ret = iommu_flush_dte(iommu, alias);
+	if (dev_data->pdev)
+		ret = pci_for_each_dma_alias(dev_data->pdev,
+					     device_flush_dte_alias, iommu);
+	else
+		ret = iommu_flush_dte(iommu, dev_data->devid);
 	if (ret)
 		return ret;
 
+	alias = amd_iommu_alias_table[dev_data->devid];
+	if (alias != dev_data->devid) {
+		ret = iommu_flush_dte(iommu, alias);
+		if (ret)
+			return ret;
+	}
+
 	if (dev_data->ats.enabled)
 		ret = device_flush_iotlb(dev_data, 0, ~0UL);
 
@@ -1471,25 +1469,27 @@
 	bool ret = false;
 	u64 *pte;
 
+	pte = (void *)get_zeroed_page(gfp);
+	if (!pte)
+		return false;
+
 	spin_lock_irqsave(&domain->lock, flags);
 
 	if (address <= PM_LEVEL_SIZE(domain->mode) ||
 	    WARN_ON_ONCE(domain->mode == PAGE_MODE_6_LEVEL))
 		goto out;
 
-	pte = (void *)get_zeroed_page(gfp);
-	if (!pte)
-		goto out;
-
 	*pte             = PM_LEVEL_PDE(domain->mode,
 					iommu_virt_to_phys(domain->pt_root));
 	domain->pt_root  = pte;
 	domain->mode    += 1;
 
+	pte = NULL;
 	ret = true;
 
 out:
 	spin_unlock_irqrestore(&domain->lock, flags);
+	free_page((unsigned long)pte);
 
 	return ret;
 }
@@ -2035,11 +2035,9 @@
 		      struct protection_domain *domain)
 {
 	struct amd_iommu *iommu;
-	u16 alias;
 	bool ats;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = dev_data->alias;
 	ats   = dev_data->ats.enabled;
 
 	/* Update data structures */
@@ -2052,8 +2050,7 @@
 
 	/* Update device table */
 	set_dte_entry(dev_data->devid, domain, ats, dev_data->iommu_v2);
-	if (alias != dev_data->devid)
-		set_dte_entry(alias, domain, ats, dev_data->iommu_v2);
+	clone_aliases(dev_data->pdev);
 
 	device_flush_dte(dev_data);
 }
@@ -2062,17 +2059,14 @@
 {
 	struct protection_domain *domain = dev_data->domain;
 	struct amd_iommu *iommu;
-	u16 alias;
 
 	iommu = amd_iommu_rlookup_table[dev_data->devid];
-	alias = dev_data->alias;
 
 	/* Update data structures */
 	dev_data->domain = NULL;
 	list_del(&dev_data->list);
 	clear_dte_entry(dev_data->devid);
-	if (alias != dev_data->devid)
-		clear_dte_entry(alias);
+	clone_aliases(dev_data->pdev);
 
 	/* Flush the DTE entry */
 	device_flush_dte(dev_data);
@@ -2384,13 +2378,7 @@
 	list_for_each_entry(dev_data, &domain->dev_list, list) {
 		set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled,
 			      dev_data->iommu_v2);
-
-		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,
-			      dev_data->iommu_v2);
+		clone_aliases(dev_data->pdev);
 	}
 }
 
@@ -2400,6 +2388,7 @@
 
 	domain_flush_devices(domain);
 	domain_flush_tlb_pde(domain);
+	domain_flush_complete(domain);
 }
 
 static int dir2prot(enum dma_data_direction direction)
@@ -3109,7 +3098,8 @@
 }
 
 static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
-			 phys_addr_t paddr, size_t page_size, int iommu_prot)
+			 phys_addr_t paddr, size_t page_size, int iommu_prot,
+			 gfp_t gfp)
 {
 	struct protection_domain *domain = to_pdomain(dom);
 	int prot = 0;
@@ -3124,7 +3114,7 @@
 		prot |= IOMMU_PROT_IW;
 
 	mutex_lock(&domain->api_lock);
-	ret = iommu_map_page(domain, iova, paddr, page_size, prot, GFP_KERNEL);
+	ret = iommu_map_page(domain, iova, paddr, page_size, prot, gfp);
 	mutex_unlock(&domain->api_lock);
 
 	domain_flush_np_cache(domain, iova, page_size);
@@ -3752,7 +3742,20 @@
 	iommu_flush_dte(iommu, devid);
 }
 
-static struct irq_remap_table *alloc_irq_table(u16 devid)
+static int set_remap_table_entry_alias(struct pci_dev *pdev, u16 alias,
+				       void *data)
+{
+	struct irq_remap_table *table = data;
+
+	irq_lookup_table[alias] = table;
+	set_dte_irq_entry(alias, table);
+
+	iommu_flush_dte(amd_iommu_rlookup_table[alias], alias);
+
+	return 0;
+}
+
+static struct irq_remap_table *alloc_irq_table(u16 devid, struct pci_dev *pdev)
 {
 	struct irq_remap_table *table = NULL;
 	struct irq_remap_table *new_table = NULL;
@@ -3798,7 +3801,12 @@
 	table = new_table;
 	new_table = NULL;
 
-	set_remap_table_entry(iommu, devid, table);
+	if (pdev)
+		pci_for_each_dma_alias(pdev, set_remap_table_entry_alias,
+				       table);
+	else
+		set_remap_table_entry(iommu, devid, table);
+
 	if (devid != alias)
 		set_remap_table_entry(iommu, alias, table);
 
@@ -3815,7 +3823,8 @@
 	return table;
 }
 
-static int alloc_irq_index(u16 devid, int count, bool align)
+static int alloc_irq_index(u16 devid, int count, bool align,
+			   struct pci_dev *pdev)
 {
 	struct irq_remap_table *table;
 	int index, c, alignment = 1;
@@ -3825,7 +3834,7 @@
 	if (!iommu)
 		return -ENODEV;
 
-	table = alloc_irq_table(devid);
+	table = alloc_irq_table(devid, pdev);
 	if (!table)
 		return -ENODEV;
 
@@ -3867,6 +3876,7 @@
 static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
 			  struct amd_ir_data *data)
 {
+	bool ret;
 	struct irq_remap_table *table;
 	struct amd_iommu *iommu;
 	unsigned long flags;
@@ -3884,10 +3894,18 @@
 
 	entry = (struct irte_ga *)table->table;
 	entry = &entry[index];
-	entry->lo.fields_remap.valid = 0;
-	entry->hi.val = irte->hi.val;
-	entry->lo.val = irte->lo.val;
-	entry->lo.fields_remap.valid = 1;
+
+	ret = cmpxchg_double(&entry->lo.val, &entry->hi.val,
+			     entry->lo.val, entry->hi.val,
+			     irte->lo.val, irte->hi.val);
+	/*
+	 * We use cmpxchg16 to atomically update the 128-bit IRTE,
+	 * and it cannot be updated by the hardware or other processors
+	 * behind us, so the return value of cmpxchg16 should be the
+	 * same as the old value.
+	 */
+	WARN_ON(!ret);
+
 	if (data)
 		data->ref = entry;
 
@@ -4258,7 +4276,7 @@
 		struct irq_remap_table *table;
 		struct amd_iommu *iommu;
 
-		table = alloc_irq_table(devid);
+		table = alloc_irq_table(devid, NULL);
 		if (table) {
 			if (!table->min_index) {
 				/*
@@ -4275,11 +4293,15 @@
 		} else {
 			index = -ENOMEM;
 		}
-	} else {
+	} else if (info->type == X86_IRQ_ALLOC_TYPE_MSI ||
+		   info->type == X86_IRQ_ALLOC_TYPE_MSIX) {
 		bool align = (info->type == X86_IRQ_ALLOC_TYPE_MSI);
 
-		index = alloc_irq_index(devid, nr_irqs, align);
+		index = alloc_irq_index(devid, nr_irqs, align, info->msi_dev);
+	} else {
+		index = alloc_irq_index(devid, nr_irqs, false, NULL);
 	}
+
 	if (index < 0) {
 		pr_warn("Failed to allocate IRTE\n");
 		ret = index;
@@ -4398,8 +4420,7 @@
 	struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
 	struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
 
-	if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
-	    !entry || entry->lo.fields_vapic.guest_mode)
+	if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || !entry)
 		return 0;
 
 	entry->lo.val = 0;
@@ -4412,7 +4433,7 @@
 	entry->lo.fields_vapic.ga_tag      = ir_data->ga_tag;
 
 	return modify_irte_ga(ir_data->irq_2_irte.devid,
-			      ir_data->irq_2_irte.index, entry, NULL);
+			      ir_data->irq_2_irte.index, entry, ir_data);
 }
 EXPORT_SYMBOL(amd_iommu_activate_guest_mode);
 
@@ -4421,14 +4442,18 @@
 	struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
 	struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
 	struct irq_cfg *cfg = ir_data->cfg;
+	u64 valid;
 
 	if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
 	    !entry || !entry->lo.fields_vapic.guest_mode)
 		return 0;
 
+	valid = entry->lo.fields_remap.valid;
+
 	entry->lo.val = 0;
 	entry->hi.val = 0;
 
+	entry->lo.fields_remap.valid       = valid;
 	entry->lo.fields_remap.dm          = apic->irq_dest_mode;
 	entry->lo.fields_remap.int_type    = apic->irq_delivery_mode;
 	entry->hi.fields.vector            = cfg->vector;
@@ -4438,7 +4463,7 @@
 				APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
 
 	return modify_irte_ga(ir_data->irq_2_irte.devid,
-			      ir_data->irq_2_irte.index, entry, NULL);
+			      ir_data->irq_2_irte.index, entry, ir_data);
 }
 EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 
@@ -4565,9 +4590,10 @@
 	if (!fn)
 		return -ENOMEM;
 	iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, iommu);
-	irq_domain_free_fwnode(fn);
-	if (!iommu->ir_domain)
+	if (!iommu->ir_domain) {
+		irq_domain_free_fwnode(fn);
 		return -ENOMEM;
+	}
 
 	iommu->ir_domain->parent = arch_get_ir_parent_domain();
 	iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
--- linux-ein-5.4.0.orig/drivers/iommu/amd_iommu_init.c
+++ linux-ein-5.4.0/drivers/iommu/amd_iommu_init.c
@@ -21,6 +21,7 @@
 #include <linux/iommu.h>
 #include <linux/kmemleak.h>
 #include <linux/mem_encrypt.h>
+#include <linux/iopoll.h>
 #include <asm/pci-direct.h>
 #include <asm/iommu.h>
 #include <asm/apic.h>
@@ -82,7 +83,11 @@
 #define ACPI_DEVFLAG_LINT1              0x80
 #define ACPI_DEVFLAG_ATSDIS             0x10000000
 
-#define LOOP_TIMEOUT	100000
+#define LOOP_TIMEOUT	2000000
+
+#define IVRS_GET_SBDF_ID(seg, bus, dev, fd)	(((seg & 0xffff) << 16) | ((bus & 0xff) << 8) \
+						 | ((dev & 0x1f) << 3) | (fn & 0x7))
+
 /*
  * ACPI table definitions
  *
@@ -147,7 +152,7 @@
 bool amd_iommu_irq_remap __read_mostly;
 
 int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
-static int amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
+static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
 
 static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
@@ -759,6 +764,7 @@
 		status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
 		if (status & (MMIO_STATUS_GALOG_RUN_MASK))
 			break;
+		udelay(10);
 	}
 
 	if (i >= LOOP_TIMEOUT)
@@ -1331,8 +1337,8 @@
 		}
 		case IVHD_DEV_ACPI_HID: {
 			u16 devid;
-			u8 hid[ACPIHID_HID_LEN] = {0};
-			u8 uid[ACPIHID_UID_LEN] = {0};
+			u8 hid[ACPIHID_HID_LEN];
+			u8 uid[ACPIHID_UID_LEN];
 			int ret;
 
 			if (h->type != 0x40) {
@@ -1349,6 +1355,7 @@
 				break;
 			}
 
+			uid[0] = '\0';
 			switch (e->uidf) {
 			case UID_NOT_PRESENT:
 
@@ -1363,8 +1370,8 @@
 				break;
 			case UID_IS_CHARACTER:
 
-				memcpy(uid, (u8 *)(&e->uid), ACPIHID_UID_LEN - 1);
-				uid[ACPIHID_UID_LEN - 1] = '\0';
+				memcpy(uid, &e->uid, e->uidl);
+				uid[e->uidl] = '\0';
 
 				break;
 			default:
@@ -1521,10 +1528,15 @@
 			iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
 		else
 			iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-		if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
+
+		/*
+		 * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+		 * GAM also requires GA mode. Therefore, we need to
+		 * check cmpxchg16b support before enabling it.
+		 */
+		if (!boot_cpu_has(X86_FEATURE_CX16) ||
+		    ((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
 			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
-		if (((h->efr_attr & (0x1 << IOMMU_FEAT_XTSUP_SHIFT)) == 0))
-			amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
 		break;
 	case 0x11:
 	case 0x40:
@@ -1532,10 +1544,27 @@
 			iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
 		else
 			iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-		if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0))
+
+		/*
+		 * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+		 * XT, GAM also requires GA mode. Therefore, we need to
+		 * check cmpxchg16b support before enabling them.
+		 */
+		if (!boot_cpu_has(X86_FEATURE_CX16) ||
+		    ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) {
 			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
-		if (((h->efr_reg & (0x1 << IOMMU_EFR_XTSUP_SHIFT)) == 0))
-			amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
+			break;
+		}
+
+		/*
+		 * Note: Since iommu_update_intcapxt() leverages
+		 * the IOMMU MMIO access to MSI capability block registers
+		 * for MSI address lo/hi/data, we need to check both
+		 * EFR[XtSup] and EFR[MsiCapMmioSup] for x2APIC support.
+		 */
+		if ((h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT)) &&
+		    (h->efr_reg & BIT(IOMMU_EFR_MSICAPMMIOSUP_SHIFT)))
+			amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
 		break;
 	default:
 		return -EINVAL;
@@ -1649,33 +1678,23 @@
 	return 0;
 }
 
-static int iommu_pc_get_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr,
-				u8 fxn, u64 *value, bool is_write);
-
 static void init_iommu_perf_ctr(struct amd_iommu *iommu)
 {
+	u64 val;
 	struct pci_dev *pdev = iommu->dev;
-	u64 val = 0xabcd, val2 = 0;
 
 	if (!iommu_feature(iommu, FEATURE_PC))
 		return;
 
 	amd_iommu_pc_present = true;
 
-	/* Check if the performance counters can be written to */
-	if ((iommu_pc_get_set_reg(iommu, 0, 0, 0, &val, true)) ||
-	    (iommu_pc_get_set_reg(iommu, 0, 0, 0, &val2, false)) ||
-	    (val != val2)) {
-		pci_err(pdev, "Unable to write to IOMMU perf counter.\n");
-		amd_iommu_pc_present = false;
-		return;
-	}
-
 	pci_info(pdev, "IOMMU performance counters supported\n");
 
 	val = readl(iommu->mmio_base + MMIO_CNTR_CONF_OFFSET);
 	iommu->max_banks = (u8) ((val >> 12) & 0x3f);
 	iommu->max_counters = (u8) ((val >> 7) & 0xf);
+
+	return;
 }
 
 static ssize_t amd_iommu_show_cap(struct device *dev,
@@ -1984,8 +2003,8 @@
 	struct irq_affinity_notify *notify = &iommu->intcapxt_notify;
 
 	/**
-	 * IntCapXT requires XTSup=1, which can be inferred
-	 * amd_iommu_xt_mode.
+	 * IntCapXT requires XTSup=1 and MsiCapMmioSup=1,
+	 * which can be inferred from amd_iommu_xt_mode.
 	 */
 	if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE)
 		return 0;
@@ -2516,6 +2535,7 @@
 	struct acpi_table_header *ivrs_base;
 	acpi_status status;
 	int i, remap_cache_sz, ret = 0;
+	u32 pci_id;
 
 	if (!amd_iommu_detected)
 		return -ENODEV;
@@ -2603,6 +2623,16 @@
 	if (ret)
 		goto out;
 
+	/* Disable IOMMU if there's Stoney Ridge graphics */
+	for (i = 0; i < 32; i++) {
+		pci_id = read_pci_config(0, i, 0, 0);
+		if ((pci_id & 0xffff) == 0x1002 && (pci_id >> 16) == 0x98e4) {
+			pr_info("Disable IOMMU on Stoney Ridge\n");
+			amd_iommu_disabled = true;
+			break;
+		}
+	}
+
 	/* Disable any previously enabled IOMMUs */
 	if (!is_kdump_kernel() || amd_iommu_disabled)
 		disable_iommus();
@@ -2711,7 +2741,7 @@
 		ret = early_amd_iommu_init();
 		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
 		if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) {
-			pr_info("AMD IOMMU disabled on kernel command-line\n");
+			pr_info("AMD IOMMU disabled\n");
 			init_state = IOMMU_CMDLINE_DISABLED;
 			ret = -EINVAL;
 		}
@@ -2918,7 +2948,7 @@
 {
 	for (; *str; ++str) {
 		if (strncmp(str, "legacy", 6) == 0) {
-			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
+			amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY_GA;
 			break;
 		}
 		if (strncmp(str, "vapic", 5) == 0) {
@@ -2945,24 +2975,32 @@
 
 static int __init parse_ivrs_ioapic(char *str)
 {
-	unsigned int bus, dev, fn;
-	int ret, id, i;
-	u16 devid;
-
-	ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn);
+	u32 seg = 0, bus, dev, fn;
+	int id, i;
+	u32 devid;
 
-	if (ret != 4) {
-		pr_err("Invalid command line: ivrs_ioapic%s\n", str);
-		return 1;
+	if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
+	    sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5)
+		goto found;
+
+	if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
+	    sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) {
+		pr_warn("ivrs_ioapic%s option format deprecated; use ivrs_ioapic=%d@%04x:%02x:%02x.%d instead\n",
+			str, id, seg, bus, dev, fn);
+		goto found;
 	}
 
+	pr_err("Invalid command line: ivrs_ioapic%s\n", str);
+	return 1;
+
+found:
 	if (early_ioapic_map_size == EARLY_MAP_SIZE) {
 		pr_err("Early IOAPIC map overflow - ignoring ivrs_ioapic%s\n",
 			str);
 		return 1;
 	}
 
-	devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+	devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn);
 
 	cmdline_maps			= true;
 	i				= early_ioapic_map_size++;
@@ -2975,24 +3013,32 @@
 
 static int __init parse_ivrs_hpet(char *str)
 {
-	unsigned int bus, dev, fn;
-	int ret, id, i;
-	u16 devid;
-
-	ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn);
+	u32 seg = 0, bus, dev, fn;
+	int id, i;
+	u32 devid;
 
-	if (ret != 4) {
-		pr_err("Invalid command line: ivrs_hpet%s\n", str);
-		return 1;
+	if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
+	    sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5)
+		goto found;
+
+	if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
+	    sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) {
+		pr_warn("ivrs_hpet%s option format deprecated; use ivrs_hpet=%d@%04x:%02x:%02x.%d instead\n",
+			str, id, seg, bus, dev, fn);
+		goto found;
 	}
 
+	pr_err("Invalid command line: ivrs_hpet%s\n", str);
+	return 1;
+
+found:
 	if (early_hpet_map_size == EARLY_MAP_SIZE) {
 		pr_err("Early HPET map overflow - ignoring ivrs_hpet%s\n",
 			str);
 		return 1;
 	}
 
-	devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+	devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn);
 
 	cmdline_maps			= true;
 	i				= early_hpet_map_size++;
@@ -3003,19 +3049,53 @@
 	return 1;
 }
 
+#define ACPIID_LEN (ACPIHID_UID_LEN + ACPIHID_HID_LEN)
+
 static int __init parse_ivrs_acpihid(char *str)
 {
-	u32 bus, dev, fn;
-	char *hid, *uid, *p;
-	char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
-	int ret, i;
-
-	ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid);
-	if (ret != 4) {
-		pr_err("Invalid command line: ivrs_acpihid(%s)\n", str);
-		return 1;
+	u32 seg = 0, bus, dev, fn;
+	char *hid, *uid, *p, *addr;
+	char acpiid[ACPIID_LEN] = {0};
+	int i;
+
+	addr = strchr(str, '@');
+	if (!addr) {
+		addr = strchr(str, '=');
+		if (!addr)
+			goto not_found;
+
+		++addr;
+
+		if (strlen(addr) > ACPIID_LEN)
+			goto not_found;
+
+		if (sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid) == 4 ||
+		    sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid) == 5) {
+			pr_warn("ivrs_acpihid%s option format deprecated; use ivrs_acpihid=%s@%04x:%02x:%02x.%d instead\n",
+				str, acpiid, seg, bus, dev, fn);
+			goto found;
+		}
+		goto not_found;
 	}
 
+	/* We have the '@', make it the terminator to get just the acpiid */
+	*addr++ = 0;
+
+	if (strlen(str) > ACPIID_LEN + 1)
+		goto not_found;
+
+	if (sscanf(str, "=%s", acpiid) != 1)
+		goto not_found;
+
+	if (sscanf(addr, "%x:%x.%x", &bus, &dev, &fn) == 3 ||
+	    sscanf(addr, "%x:%x:%x.%x", &seg, &bus, &dev, &fn) == 4)
+		goto found;
+
+not_found:
+	pr_err("Invalid command line: ivrs_acpihid%s\n", str);
+	return 1;
+
+found:
 	p = acpiid;
 	hid = strsep(&p, ":");
 	uid = p;
@@ -3025,11 +3105,17 @@
 		return 1;
 	}
 
+	/*
+	 * Ignore leading zeroes after ':', so e.g., AMDI0095:00
+	 * will match AMDI0095:0 in the second strcmp in acpi_dev_hid_uid_match
+	 */
+	while (*uid == '0' && *(uid + 1))
+		uid++;
+
 	i = early_acpihid_map_size++;
 	memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
 	memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
-	early_acpihid_map[i].devid =
-		((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+	early_acpihid_map[i].devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn);
 	early_acpihid_map[i].cmd_line	= true;
 
 	return 1;
--- linux-ein-5.4.0.orig/drivers/iommu/amd_iommu_types.h
+++ linux-ein-5.4.0/drivers/iommu/amd_iommu_types.h
@@ -254,7 +254,7 @@
 #define DTE_IRQ_REMAP_INTCTL_MASK	(0x3ULL << 60)
 #define DTE_IRQ_TABLE_LEN_MASK	(0xfULL << 1)
 #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
 
 #define PAGE_MODE_NONE    0x00
@@ -348,7 +348,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
@@ -377,12 +377,12 @@
 #define IOMMU_CAP_EFR     27
 
 /* IOMMU Feature Reporting Field (for IVHD type 10h */
-#define IOMMU_FEAT_XTSUP_SHIFT	0
 #define IOMMU_FEAT_GASUP_SHIFT	6
 
 /* IOMMU Extended Feature Register (EFR) */
 #define IOMMU_EFR_XTSUP_SHIFT	2
 #define IOMMU_EFR_GASUP_SHIFT	7
+#define IOMMU_EFR_MSICAPMMIOSUP_SHIFT	46
 
 #define MAX_DOMAIN_ID 65536
 
@@ -406,7 +406,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 {
@@ -639,8 +643,8 @@
 	struct list_head list;		  /* For domain->dev_list */
 	struct llist_node dev_data_list;  /* For global dev_data_list */
 	struct protection_domain *domain; /* Domain the device is bound to */
+	struct pci_dev *pdev;
 	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 {
@@ -882,8 +886,8 @@
 	 */
 	struct irq_cfg *cfg;
 	int ga_vector;
-	int ga_root_ptr;
-	int ga_tag;
+	u64 ga_root_ptr;
+	u32 ga_tag;
 };
 
 struct amd_irte_ops {
--- linux-ein-5.4.0.orig/drivers/iommu/amd_iommu_v2.c
+++ linux-ein-5.4.0/drivers/iommu/amd_iommu_v2.c
@@ -591,6 +591,7 @@
 	put_device_state(dev_state);
 
 out:
+	pci_dev_put(pdev);
 	return ret;
 }
 
@@ -741,6 +742,13 @@
 
 	might_sleep();
 
+	/*
+	 * When memory encryption is active the device is likely not in a
+	 * direct-mapped domain. Forbid using IOMMUv2 functionality for now.
+	 */
+	if (mem_encrypt_active())
+		return -ENODEV;
+
 	if (!amd_iommu_v2_supported())
 		return -ENODEV;
 
--- linux-ein-5.4.0.orig/drivers/iommu/arm-smmu-v3.c
+++ linux-ein-5.4.0/drivers/iommu/arm-smmu-v3.c
@@ -760,6 +760,18 @@
 	q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
 }
 
+static void queue_sync_cons_ovf(struct arm_smmu_queue *q)
+{
+	struct arm_smmu_ll_queue *llq = &q->llq;
+
+	if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons)))
+		return;
+
+	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
+		      Q_IDX(llq, llq->cons);
+	queue_sync_cons_out(q);
+}
+
 static int queue_sync_prod_in(struct arm_smmu_queue *q)
 {
 	int ret = 0;
@@ -856,6 +868,7 @@
 		cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
 		break;
 	case CMDQ_OP_TLBI_NH_VA:
+		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
 		cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
@@ -1642,7 +1655,8 @@
 						 STRTAB_STE_1_EATS_TRANS));
 
 	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 */
@@ -1706,6 +1720,7 @@
 				dev_info(smmu->dev, "\t0x%016llx\n",
 					 (unsigned long long)evt[i]);
 
+			cond_resched();
 		}
 
 		/*
@@ -1717,8 +1732,7 @@
 	} while (!queue_empty(llq));
 
 	/* Sync our overflow flag, as we believe we're up to speed */
-	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
-		    Q_IDX(llq, llq->cons);
+	queue_sync_cons_ovf(q);
 	return IRQ_HANDLED;
 }
 
@@ -1776,9 +1790,7 @@
 	} while (!queue_empty(llq));
 
 	/* Sync our overflow flag, as we believe we're up to speed */
-	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
-		      Q_IDX(llq, llq->cons);
-	queue_sync_cons_out(q);
+	queue_sync_cons_ovf(q);
 	return IRQ_HANDLED;
 }
 
@@ -2448,7 +2460,7 @@
 }
 
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
-			phys_addr_t paddr, size_t size, int prot)
+			phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
 
@@ -3611,19 +3623,19 @@
 
 	/* Interrupt lines */
 
-	irq = platform_get_irq_byname(pdev, "combined");
+	irq = platform_get_irq_byname_optional(pdev, "combined");
 	if (irq > 0)
 		smmu->combined_irq = irq;
 	else {
-		irq = platform_get_irq_byname(pdev, "eventq");
+		irq = platform_get_irq_byname_optional(pdev, "eventq");
 		if (irq > 0)
 			smmu->evtq.q.irq = irq;
 
-		irq = platform_get_irq_byname(pdev, "priq");
+		irq = platform_get_irq_byname_optional(pdev, "priq");
 		if (irq > 0)
 			smmu->priq.q.irq = irq;
 
-		irq = platform_get_irq_byname(pdev, "gerror");
+		irq = platform_get_irq_byname_optional(pdev, "gerror");
 		if (irq > 0)
 			smmu->gerr_irq = irq;
 	}
--- linux-ein-5.4.0.orig/drivers/iommu/arm-smmu.c
+++ linux-ein-5.4.0/drivers/iommu/arm-smmu.c
@@ -114,7 +114,7 @@
 static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
 {
 	if (pm_runtime_enabled(smmu->dev))
-		return pm_runtime_get_sync(smmu->dev);
+		return pm_runtime_resume_and_get(smmu->dev);
 
 	return 0;
 }
@@ -1160,7 +1160,7 @@
 }
 
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
-			phys_addr_t paddr, size_t size, int prot)
+			phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
 	struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
@@ -1231,6 +1231,7 @@
 	u64 phys;
 	unsigned long va, flags;
 	int ret, idx = cfg->cbndx;
+	phys_addr_t addr = 0;
 
 	ret = arm_smmu_rpm_get(smmu);
 	if (ret < 0)
@@ -1249,6 +1250,7 @@
 		dev_err(dev,
 			"iova to phys timed out on %pad. Falling back to software table walk.\n",
 			&iova);
+		arm_smmu_rpm_put(smmu);
 		return ops->iova_to_phys(ops, iova);
 	}
 
@@ -1257,12 +1259,14 @@
 	if (phys & CB_PAR_F) {
 		dev_err(dev, "translation fault!\n");
 		dev_err(dev, "PAR = 0x%llx\n", phys);
-		return 0;
+		goto out;
 	}
 
+	addr = (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
+out:
 	arm_smmu_rpm_put(smmu);
 
-	return (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
+	return addr;
 }
 
 static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
--- linux-ein-5.4.0.orig/drivers/iommu/dma-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/dma-iommu.c
@@ -19,6 +19,7 @@
 #include <linux/iova.h>
 #include <linux/irq.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <linux/vmalloc.h>
@@ -43,7 +44,6 @@
 		dma_addr_t		msi_iova;
 	};
 	struct list_head		msi_page_list;
-	spinlock_t			msi_lock;
 
 	/* Domain for flush queue callback; NULL if flush queue not in use */
 	struct iommu_domain		*fq_domain;
@@ -62,7 +62,6 @@
 
 	cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
 	if (cookie) {
-		spin_lock_init(&cookie->msi_lock);
 		INIT_LIST_HEAD(&cookie->msi_page_list);
 		cookie->type = type;
 	}
@@ -177,15 +176,15 @@
 	start -= iova_offset(iovad, start);
 	num_pages = iova_align(iovad, end - start) >> iova_shift(iovad);
 
-	msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL);
-	if (!msi_page)
-		return -ENOMEM;
-
 	for (i = 0; i < num_pages; i++) {
-		msi_page[i].phys = start;
-		msi_page[i].iova = start;
-		INIT_LIST_HEAD(&msi_page[i].list);
-		list_add(&msi_page[i].list, &cookie->msi_page_list);
+		msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL);
+		if (!msi_page)
+			return -ENOMEM;
+
+		msi_page->phys = start;
+		msi_page->iova = start;
+		INIT_LIST_HEAD(&msi_page->list);
+		list_add(&msi_page->list, &cookie->msi_page_list);
 		start += iovad->granule;
 	}
 
@@ -217,9 +216,11 @@
 			lo = iova_pfn(iovad, start);
 			hi = iova_pfn(iovad, end);
 			reserve_iova(iovad, lo, hi);
-		} else {
+		} else if (end < start) {
 			/* dma_ranges list should be sorted */
-			dev_err(&dev->dev, "Failed to reserve IOVA\n");
+			dev_err(&dev->dev,
+				"Failed to reserve IOVA [%pa-%pa]\n",
+				&start, &end);
 			return -EINVAL;
 		}
 
@@ -476,7 +477,7 @@
 	if (!iova)
 		return DMA_MAPPING_ERROR;
 
-	if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+	if (iommu_map_atomic(domain, iova, phys - iova_off, size, prot)) {
 		iommu_dma_free_iova(cookie, iova, size);
 		return DMA_MAPPING_ERROR;
 	}
@@ -611,7 +612,7 @@
 			arch_dma_prep_coherent(sg_page(sg), sg->length);
 	}
 
-	if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot)
+	if (iommu_map_sg_atomic(domain, iova, sgt.sgl, sgt.orig_nents, ioprot)
 			< size)
 		goto out_free_sg;
 
@@ -659,7 +660,7 @@
 		return;
 
 	phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
-	arch_sync_dma_for_cpu(dev, phys, size, dir);
+	arch_sync_dma_for_cpu(phys, size, dir);
 }
 
 static void iommu_dma_sync_single_for_device(struct device *dev,
@@ -671,7 +672,7 @@
 		return;
 
 	phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
-	arch_sync_dma_for_device(dev, phys, size, dir);
+	arch_sync_dma_for_device(phys, size, dir);
 }
 
 static void iommu_dma_sync_sg_for_cpu(struct device *dev,
@@ -685,7 +686,7 @@
 		return;
 
 	for_each_sg(sgl, sg, nelems, i)
-		arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
+		arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
 }
 
 static void iommu_dma_sync_sg_for_device(struct device *dev,
@@ -699,7 +700,7 @@
 		return;
 
 	for_each_sg(sgl, sg, nelems, i)
-		arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir);
+		arch_sync_dma_for_device(sg_phys(sg), sg->length, dir);
 }
 
 static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
@@ -714,7 +715,7 @@
 	dma_handle =__iommu_dma_map(dev, phys, size, prot);
 	if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
 	    dma_handle != DMA_MAPPING_ERROR)
-		arch_sync_dma_for_device(dev, phys, size, dir);
+		arch_sync_dma_for_device(phys, size, dir);
 	return dma_handle;
 }
 
@@ -871,7 +872,7 @@
 	 * We'll leave any physical concatenation to the IOMMU driver's
 	 * implementation - it knows better than we do.
 	 */
-	if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len)
+	if (iommu_map_sg_atomic(domain, iova, sg, nents, prot) < iova_len)
 		goto out_free_iova;
 
 	return __finalise_sg(dev, sg, nents, iova);
@@ -1150,7 +1151,7 @@
 		if (msi_page->phys == msi_addr)
 			return msi_page;
 
-	msi_page = kzalloc(sizeof(*msi_page), GFP_ATOMIC);
+	msi_page = kzalloc(sizeof(*msi_page), GFP_KERNEL);
 	if (!msi_page)
 		return NULL;
 
@@ -1178,25 +1179,22 @@
 {
 	struct device *dev = msi_desc_to_dev(desc);
 	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct iommu_dma_cookie *cookie;
 	struct iommu_dma_msi_page *msi_page;
-	unsigned long flags;
+	static DEFINE_MUTEX(msi_prepare_lock); /* see below */
 
 	if (!domain || !domain->iova_cookie) {
 		desc->iommu_cookie = NULL;
 		return 0;
 	}
 
-	cookie = domain->iova_cookie;
-
 	/*
-	 * We disable IRQs to rule out a possible inversion against
-	 * irq_desc_lock if, say, someone tries to retarget the affinity
-	 * of an MSI from within an IPI handler.
+	 * In fact the whole prepare operation should already be serialised by
+	 * irq_domain_mutex further up the callchain, but that's pretty subtle
+	 * on its own, so consider this locking as failsafe documentation...
 	 */
-	spin_lock_irqsave(&cookie->msi_lock, flags);
+	mutex_lock(&msi_prepare_lock);
 	msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
-	spin_unlock_irqrestore(&cookie->msi_lock, flags);
+	mutex_unlock(&msi_prepare_lock);
 
 	msi_desc_set_iommu_cookie(desc, msi_page);
 
--- linux-ein-5.4.0.orig/drivers/iommu/dmar.c
+++ linux-ein-5.4.0/drivers/iommu/dmar.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/iommu.h>
 #include <linux/numa.h>
+#include <linux/limits.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -128,6 +129,13 @@
 
 	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)
@@ -355,7 +363,7 @@
 
 static struct notifier_block dmar_pci_bus_nb = {
 	.notifier_call = dmar_pci_bus_notifier,
-	.priority = INT_MIN,
+	.priority = 1,
 };
 
 static struct dmar_drhd_unit *
@@ -363,7 +371,8 @@
 {
 	struct dmar_drhd_unit *dmaru;
 
-	list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list)
+	list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list,
+				dmar_rcu_check())
 		if (dmaru->segment == drhd->segment &&
 		    dmaru->reg_base_addr == drhd->address)
 			return dmaru;
@@ -440,12 +449,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,
@@ -465,20 +475,20 @@
 		if (drhd->reg_base_addr == rhsa->base_address) {
 			int node = acpi_map_pxm_to_node(rhsa->proximity_domain);
 
-			if (!node_online(node))
+			if (node != NUMA_NO_NODE && !node_online(node))
 				node = NUMA_NO_NODE;
 			drhd->iommu->node = node;
 			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;
 }
@@ -784,6 +794,7 @@
 			info = dmar_alloc_pci_notify_info(dev,
 					BUS_NOTIFY_ADD_DEVICE);
 			if (!info) {
+				pci_dev_put(dev);
 				return dmar_dev_scope_status;
 			} else {
 				dmar_pci_bus_add_dev(info);
@@ -827,14 +838,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
@@ -888,7 +899,8 @@
 	if (!ret)
 		ret = dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl,
 					   &validate_drhd_cb);
-	if (!ret && !no_iommu && !iommu_detected && !dmar_disabled) {
+	if (!ret && !no_iommu && !iommu_detected &&
+	    (!dmar_disabled || dmar_platform_optin())) {
 		iommu_detected = 1;
 		/* Make sure ACS will be enabled */
 		pci_request_acs();
@@ -1009,8 +1021,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) {
@@ -1035,17 +1047,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;
@@ -1072,7 +1095,12 @@
 
 	raw_spin_lock_init(&iommu->register_lock);
 
-	if (intel_iommu_enabled) {
+	/*
+	 * This is only for hotplug; at boot time intel_iommu_enabled won't
+	 * be set yet. When intel_iommu_init() runs, it registers the units
+	 * present at boot time, then sets intel_iommu_enabled.
+	 */
+	if (intel_iommu_enabled && !drhd->ignored) {
 		err = iommu_device_sysfs_add(&iommu->iommu, NULL,
 					     intel_iommu_groups,
 					     "%s", iommu->name);
@@ -1083,13 +1111,16 @@
 
 		err = iommu_device_register(&iommu->iommu);
 		if (err)
-			goto err_unmap;
+			goto err_sysfs;
 	}
 
 	drhd->iommu = iommu;
+	iommu->drhd = drhd;
 
 	return 0;
 
+err_sysfs:
+	iommu_device_sysfs_remove(&iommu->iommu);
 err_unmap:
 	unmap_iommu(iommu);
 error_free_seq_id:
@@ -1101,7 +1132,7 @@
 
 static void free_iommu(struct intel_iommu *iommu)
 {
-	if (intel_iommu_enabled) {
+	if (intel_iommu_enabled && !iommu->drhd->ignored) {
 		iommu_device_unregister(&iommu->iommu);
 		iommu_device_sysfs_remove(&iommu->iommu);
 	}
@@ -1351,7 +1382,6 @@
 	struct qi_desc desc;
 
 	if (mask) {
-		WARN_ON_ONCE(addr & ((1ULL << (VTD_PAGE_SHIFT + mask)) - 1));
 		addr |= (1ULL << (VTD_PAGE_SHIFT + mask - 1)) - 1;
 		desc.qw1 = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE;
 	} else
--- linux-ein-5.4.0.orig/drivers/iommu/exynos-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/exynos-iommu.c
@@ -635,7 +635,7 @@
 
 	ret = iommu_device_register(&data->iommu);
 	if (ret)
-		return ret;
+		goto err_iommu_register;
 
 	platform_set_drvdata(pdev, data);
 
@@ -662,6 +662,10 @@
 	pm_runtime_enable(dev);
 
 	return 0;
+
+err_iommu_register:
+	iommu_device_sysfs_remove(&data->iommu);
+	return ret;
 }
 
 static int __maybe_unused exynos_sysmmu_suspend(struct device *dev)
@@ -1073,7 +1077,7 @@
  */
 static int exynos_iommu_map(struct iommu_domain *iommu_domain,
 			    unsigned long l_iova, phys_addr_t paddr, size_t size,
-			    int prot)
+			    int prot, gfp_t gfp)
 {
 	struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
 	sysmmu_pte_t *entry;
@@ -1299,13 +1303,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);
 		mutex_init(&owner->rpm_lock);
--- linux-ein-5.4.0.orig/drivers/iommu/fsl_pamu.c
+++ linux-ein-5.4.0/drivers/iommu/fsl_pamu.c
@@ -1122,7 +1122,7 @@
 		ret = create_csd(ppaact_phys, mem_size, csd_port_id);
 		if (ret) {
 			dev_err(dev, "could not create coherence subdomain\n");
-			return ret;
+			goto error;
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/iommu/hyperv-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/hyperv-iommu.c
@@ -155,7 +155,10 @@
 				0, IOAPIC_REMAPPING_ENTRY, fn,
 				&hyperv_ir_domain_ops, NULL);
 
-	irq_domain_free_fwnode(fn);
+	if (!ioapic_ir_domain) {
+		irq_domain_free_fwnode(fn);
+		return -ENOMEM;
+	}
 
 	/*
 	 * Hyper-V doesn't provide irq remapping function for
--- linux-ein-5.4.0.orig/drivers/iommu/intel-iommu-debugfs.c
+++ linux-ein-5.4.0/drivers/iommu/intel-iommu-debugfs.c
@@ -32,38 +32,42 @@
 
 #define IOMMU_REGSET_ENTRY(_reg_)					\
 	{ DMAR_##_reg_##_REG, __stringify(_reg_) }
-static const struct iommu_regset iommu_regs[] = {
+
+static const struct iommu_regset iommu_regs_32[] = {
 	IOMMU_REGSET_ENTRY(VER),
-	IOMMU_REGSET_ENTRY(CAP),
-	IOMMU_REGSET_ENTRY(ECAP),
 	IOMMU_REGSET_ENTRY(GCMD),
 	IOMMU_REGSET_ENTRY(GSTS),
-	IOMMU_REGSET_ENTRY(RTADDR),
-	IOMMU_REGSET_ENTRY(CCMD),
 	IOMMU_REGSET_ENTRY(FSTS),
 	IOMMU_REGSET_ENTRY(FECTL),
 	IOMMU_REGSET_ENTRY(FEDATA),
 	IOMMU_REGSET_ENTRY(FEADDR),
 	IOMMU_REGSET_ENTRY(FEUADDR),
-	IOMMU_REGSET_ENTRY(AFLOG),
 	IOMMU_REGSET_ENTRY(PMEN),
 	IOMMU_REGSET_ENTRY(PLMBASE),
 	IOMMU_REGSET_ENTRY(PLMLIMIT),
+	IOMMU_REGSET_ENTRY(ICS),
+	IOMMU_REGSET_ENTRY(PRS),
+	IOMMU_REGSET_ENTRY(PECTL),
+	IOMMU_REGSET_ENTRY(PEDATA),
+	IOMMU_REGSET_ENTRY(PEADDR),
+	IOMMU_REGSET_ENTRY(PEUADDR),
+};
+
+static const struct iommu_regset iommu_regs_64[] = {
+	IOMMU_REGSET_ENTRY(CAP),
+	IOMMU_REGSET_ENTRY(ECAP),
+	IOMMU_REGSET_ENTRY(RTADDR),
+	IOMMU_REGSET_ENTRY(CCMD),
+	IOMMU_REGSET_ENTRY(AFLOG),
 	IOMMU_REGSET_ENTRY(PHMBASE),
 	IOMMU_REGSET_ENTRY(PHMLIMIT),
 	IOMMU_REGSET_ENTRY(IQH),
 	IOMMU_REGSET_ENTRY(IQT),
 	IOMMU_REGSET_ENTRY(IQA),
-	IOMMU_REGSET_ENTRY(ICS),
 	IOMMU_REGSET_ENTRY(IRTA),
 	IOMMU_REGSET_ENTRY(PQH),
 	IOMMU_REGSET_ENTRY(PQT),
 	IOMMU_REGSET_ENTRY(PQA),
-	IOMMU_REGSET_ENTRY(PRS),
-	IOMMU_REGSET_ENTRY(PECTL),
-	IOMMU_REGSET_ENTRY(PEDATA),
-	IOMMU_REGSET_ENTRY(PEADDR),
-	IOMMU_REGSET_ENTRY(PEUADDR),
 	IOMMU_REGSET_ENTRY(MTRRCAP),
 	IOMMU_REGSET_ENTRY(MTRRDEF),
 	IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000),
@@ -126,10 +130,16 @@
 		 * by adding the offset to the pointer (virtual address).
 		 */
 		raw_spin_lock_irqsave(&iommu->register_lock, flag);
-		for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) {
-			value = dmar_readq(iommu->reg + iommu_regs[i].offset);
+		for (i = 0 ; i < ARRAY_SIZE(iommu_regs_32); i++) {
+			value = dmar_readl(iommu->reg + iommu_regs_32[i].offset);
 			seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
-				   iommu_regs[i].regs, iommu_regs[i].offset,
+				   iommu_regs_32[i].regs, iommu_regs_32[i].offset,
+				   value);
+		}
+		for (i = 0 ; i < ARRAY_SIZE(iommu_regs_64); i++) {
+			value = dmar_readq(iommu->reg + iommu_regs_64[i].offset);
+			seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
+				   iommu_regs_64[i].regs, iommu_regs_64[i].offset,
 				   value);
 		}
 		raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
@@ -271,9 +281,16 @@
 {
 	struct dmar_drhd_unit *drhd;
 	struct intel_iommu *iommu;
+	u32 sts;
 
 	rcu_read_lock();
 	for_each_active_iommu(iommu, drhd) {
+		sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
+		if (!(sts & DMA_GSTS_TES)) {
+			seq_printf(m, "DMA Remapping is not enabled on %s\n",
+				   iommu->name);
+			continue;
+		}
 		root_tbl_walk(m, iommu);
 		seq_putc(m, '\n');
 	}
@@ -343,6 +360,7 @@
 	struct dmar_drhd_unit *drhd;
 	struct intel_iommu *iommu;
 	u64 irta;
+	u32 sts;
 
 	rcu_read_lock();
 	for_each_active_iommu(iommu, drhd) {
@@ -352,7 +370,8 @@
 		seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n",
 			   iommu->name);
 
-		if (iommu->ir_table) {
+		sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
+		if (iommu->ir_table && (sts & DMA_GSTS_IRES)) {
 			irta = virt_to_phys(iommu->ir_table->base);
 			seq_printf(m, " IR table address:%llx\n", irta);
 			ir_tbl_remap_entry_show(m, iommu);
--- linux-ein-5.4.0.orig/drivers/iommu/intel-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/intel-iommu.c
@@ -123,29 +123,29 @@
 	return (level - 1) * LEVEL_STRIDE;
 }
 
-static inline int pfn_level_offset(unsigned long pfn, int level)
+static inline int pfn_level_offset(u64 pfn, int level)
 {
 	return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
 }
 
-static inline unsigned long level_mask(int level)
+static inline u64 level_mask(int level)
 {
-	return -1UL << level_to_offset_bits(level);
+	return -1ULL << level_to_offset_bits(level);
 }
 
-static inline unsigned long level_size(int level)
+static inline u64 level_size(int level)
 {
-	return 1UL << level_to_offset_bits(level);
+	return 1ULL << level_to_offset_bits(level);
 }
 
-static inline unsigned long align_to_level(unsigned long pfn, int level)
+static inline u64 align_to_level(u64 pfn, int level)
 {
 	return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
 static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
 {
-	return  1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
+	return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
 }
 
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
@@ -179,7 +179,7 @@
  * (used when kernel is launched w/ TXT)
  */
 static int force_on = 0;
-int intel_iommu_tboot_noforce;
+static int intel_iommu_tboot_noforce;
 static int no_platform_optin;
 
 #define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
@@ -611,6 +611,12 @@
 	return g_iommus[iommu_id];
 }
 
+static inline bool iommu_paging_structure_coherency(struct intel_iommu *iommu)
+{
+	return sm_supported(iommu) ?
+			ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap);
+}
+
 static void domain_update_iommu_coherency(struct dmar_domain *domain)
 {
 	struct dmar_drhd_unit *drhd;
@@ -622,7 +628,7 @@
 
 	for_each_domain_iommu(i, domain) {
 		found = true;
-		if (!ecap_coherent(g_iommus[i]->ecap)) {
+		if (!iommu_paging_structure_coherency(g_iommus[i])) {
 			domain->iommu_coherency = 0;
 			break;
 		}
@@ -633,7 +639,7 @@
 	/* No hardware attached; use lowest common denominator */
 	rcu_read_lock();
 	for_each_active_iommu(iommu, drhd) {
-		if (!ecap_coherent(iommu->ecap)) {
+		if (!iommu_paging_structure_coherency(iommu)) {
 			domain->iommu_coherency = 0;
 			break;
 		}
@@ -732,6 +738,11 @@
 	return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
 }
 
+static bool attach_deferred(struct device *dev)
+{
+	return dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO;
+}
+
 /**
  * is_downstream_to_pci_bridge - test if a device belongs to the PCI
  *				 sub-hierarchy of a candidate PCI-PCI bridge
@@ -1847,7 +1858,7 @@
 static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu,
 		       int guest_width)
 {
-	int adjust_width, agaw;
+	int adjust_width, agaw, cap_width;
 	unsigned long sagaw;
 	int err;
 
@@ -1861,8 +1872,9 @@
 	domain_reserve_special_ranges(domain);
 
 	/* calculate AGAW */
-	if (guest_width > cap_mgaw(iommu->cap))
-		guest_width = cap_mgaw(iommu->cap);
+	cap_width = min_t(int, cap_mgaw(iommu->cap), agaw_to_width(iommu->agaw));
+	if (guest_width > cap_width)
+		guest_width = cap_width;
 	domain->gaw = guest_width;
 	adjust_width = guestwidth_to_adjustwidth(guest_width);
 	agaw = width_to_agaw(adjust_width);
@@ -2090,7 +2102,8 @@
 
 	context_set_fault_enable(context);
 	context_set_present(context);
-	domain_flush_cache(domain, context, sizeof(*context));
+	if (!ecap_coherent(iommu->ecap))
+		clflush_cache_range(context, sizeof(*context));
 
 	/*
 	 * It's a non-present to present mapping. If hardware doesn't cache
@@ -2420,31 +2433,31 @@
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 }
 
-/*
- * find_domain
- * Note: we use struct device->archdata.iommu stores the info
- */
 static struct dmar_domain *find_domain(struct device *dev)
 {
 	struct device_domain_info *info;
 
-	if (unlikely(dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO)) {
-		struct iommu_domain *domain;
-
-		dev->archdata.iommu = NULL;
-		domain = iommu_get_domain_for_dev(dev);
-		if (domain)
-			intel_iommu_attach_device(domain, dev);
-	}
+	if (unlikely(attach_deferred(dev) || iommu_dummy(dev)))
+		return NULL;
 
 	/* No lock here, assumes no domain exit in normal case */
 	info = dev->archdata.iommu;
-
 	if (likely(info))
 		return info->domain;
+
 	return NULL;
 }
 
+static void do_deferred_attach(struct device *dev)
+{
+	struct iommu_domain *domain;
+
+	dev->archdata.iommu = NULL;
+	domain = iommu_get_domain_for_dev(dev);
+	if (domain)
+		intel_iommu_attach_device(domain, dev);
+}
+
 static inline struct device_domain_info *
 dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
 {
@@ -2553,14 +2566,14 @@
 		}
 
 		/* Setup the PASID entry for requests without PASID: */
-		spin_lock(&iommu->lock);
+		spin_lock_irqsave(&iommu->lock, flags);
 		if (hw_pass_through && domain_type_is_si(domain))
 			ret = intel_pasid_setup_pass_through(iommu, domain,
 					dev, PASID_RID2PASID);
 		else
 			ret = intel_pasid_setup_second_level(iommu, domain,
 					dev, PASID_RID2PASID);
-		spin_unlock(&iommu->lock);
+		spin_unlock_irqrestore(&iommu->lock, flags);
 		if (ret) {
 			dev_err(dev, "Setup RID2PASID failed\n");
 			dmar_remove_one_dev_info(dev);
@@ -2743,6 +2756,7 @@
 
 	if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
 		domain_exit(si_domain);
+		si_domain = NULL;
 		return -EFAULT;
 	}
 
@@ -2762,10 +2776,8 @@
 	}
 
 	/*
-	 * Normally we use DMA domains for devices which have RMRRs. But we
-	 * loose this requirement for graphic and usb devices. Identity map
-	 * the RMRRs for graphic and USB devices so that they could use the
-	 * si_domain.
+	 * Identity map the RMRRs so that devices with RMRRs could also use
+	 * the si_domain.
 	 */
 	for_each_rmrr_units(rmrr) {
 		for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
@@ -2773,9 +2785,6 @@
 			unsigned long long start = rmrr->base_address;
 			unsigned long long end = rmrr->end_address;
 
-			if (device_is_rmrr_locked(dev))
-				continue;
-
 			if (WARN_ON(end < start ||
 				    end >> agaw_to_width(si_domain->agaw)))
 				continue;
@@ -2794,7 +2803,7 @@
 	struct device_domain_info *info;
 
 	info = dev->archdata.iommu;
-	if (info && info != DUMMY_DEVICE_DOMAIN_INFO && info != DEFER_DEVICE_DOMAIN_INFO)
+	if (info)
 		return (info->domain == si_domain);
 
 	return 0;
@@ -2914,9 +2923,6 @@
 	if (dev_is_pci(dev)) {
 		struct pci_dev *pdev = to_pci_dev(dev);
 
-		if (device_is_rmrr_locked(dev))
-			return IOMMU_DOMAIN_DMA;
-
 		/*
 		 * Prevent any device marked as untrusted from getting
 		 * placed into the statically identity mapping domain.
@@ -2954,9 +2960,6 @@
 				return IOMMU_DOMAIN_DMA;
 		} else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
 			return IOMMU_DOMAIN_DMA;
-	} else {
-		if (device_has_rmrr(dev))
-			return IOMMU_DOMAIN_DMA;
 	}
 
 	return (iommu_identity_mapping & IDENTMAP_ALL) ?
@@ -3289,6 +3292,12 @@
 
 		if (!ecap_pass_through(iommu->ecap))
 			hw_pass_through = 0;
+
+		if (!intel_iommu_strict && cap_caching_mode(iommu->cap)) {
+			pr_info("Disable batched IOTLB flush due to virtualization");
+			intel_iommu_strict = 1;
+		}
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 		if (pasid_supported(iommu))
 			intel_svm_init(iommu);
@@ -3368,6 +3377,10 @@
 		disable_dmar_iommu(iommu);
 		free_dmar_iommu(iommu);
 	}
+	if (si_domain) {
+		domain_exit(si_domain);
+		si_domain = NULL;
+	}
 
 	kfree(g_iommus);
 
@@ -3401,7 +3414,8 @@
 	iova_pfn = alloc_iova_fast(&domain->iovad, nrpages,
 				   IOVA_PFN(dma_mask), true);
 	if (unlikely(!iova_pfn)) {
-		dev_err(dev, "Allocating %ld-page iova failed", nrpages);
+		dev_err_once(dev, "Allocating %ld-page iova failed\n",
+			     nrpages);
 		return 0;
 	}
 
@@ -3464,6 +3478,9 @@
 	if (iommu_dummy(dev))
 		return false;
 
+	if (unlikely(attach_deferred(dev)))
+		do_deferred_attach(dev);
+
 	ret = identity_mapping(dev);
 	if (ret) {
 		u64 dma_mask = *dev->dma_mask;
@@ -3827,7 +3844,11 @@
 	int prot = 0;
 	int ret;
 
+	if (unlikely(attach_deferred(dev)))
+		do_deferred_attach(dev);
+
 	domain = find_domain(dev);
+
 	if (WARN_ON(dir == DMA_NONE || !domain))
 		return DMA_MAPPING_ERROR;
 
@@ -4128,10 +4149,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);
 
@@ -4344,7 +4366,8 @@
 	struct dmar_atsr_unit *atsru;
 	struct acpi_dmar_atsr *tmp;
 
-	list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
+	list_for_each_entry_rcu(atsru, &dmar_atsr_units, list,
+				dmar_rcu_check()) {
 		tmp = (struct acpi_dmar_atsr *)atsru->hdr;
 		if (atsr->segment != tmp->segment)
 			continue;
@@ -4928,7 +4951,8 @@
 	 * Intel IOMMU is required for a TXT/tboot launch or platform
 	 * opt in, so enforce that.
 	 */
-	force_on = tboot_force_iommu() || platform_optin_force_iommu();
+	force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
+		    platform_optin_force_iommu();
 
 	if (iommu_init_mempool()) {
 		if (force_on)
@@ -4959,6 +4983,9 @@
 
 	down_write(&dmar_global_lock);
 
+	if (!no_iommu)
+		intel_iommu_debugfs_init();
+
 	if (no_iommu || dmar_disabled) {
 		/*
 		 * We exit the function here to ensure IOMMU's remapping and
@@ -5022,6 +5049,7 @@
 
 	init_iommu_pm_ops();
 
+	down_read(&dmar_global_lock);
 	for_each_active_iommu(iommu, drhd) {
 		iommu_device_sysfs_add(&iommu->iommu, NULL,
 				       intel_iommu_groups,
@@ -5029,6 +5057,7 @@
 		iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
 		iommu_device_register(&iommu->iommu);
 	}
+	up_read(&dmar_global_lock);
 
 	bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
 	if (si_domain && !hw_pass_through)
@@ -5039,7 +5068,6 @@
 	down_read(&dmar_global_lock);
 	if (probe_acpi_namespace_devices())
 		pr_warn("ACPI name space devices didn't probe correctly\n");
-	up_read(&dmar_global_lock);
 
 	/* Finally, we enable the DMA remapping hardware. */
 	for_each_iommu(iommu, drhd) {
@@ -5048,10 +5076,11 @@
 
 		iommu_disable_protect_mem_regions(iommu);
 	}
+	up_read(&dmar_global_lock);
+
 	pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
 
 	intel_iommu_enabled = 1;
-	intel_iommu_debugfs_init();
 
 	return 0;
 
@@ -5132,7 +5161,8 @@
 
 	spin_lock_irqsave(&device_domain_lock, flags);
 	info = dev->archdata.iommu;
-	if (info)
+	if (info && info != DEFER_DEVICE_DOMAIN_INFO
+	    && info != DUMMY_DEVICE_DOMAIN_INFO)
 		__dmar_remove_one_dev_info(info);
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 }
@@ -5440,16 +5470,13 @@
 
 static int intel_iommu_map(struct iommu_domain *domain,
 			   unsigned long iova, phys_addr_t hpa,
-			   size_t size, int iommu_prot)
+			   size_t size, int iommu_prot, gfp_t gfp)
 {
 	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
 	u64 max_addr;
 	int prot = 0;
 	int ret;
 
-	if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
-		return -EINVAL;
-
 	if (iommu_prot & IOMMU_READ)
 		prot |= DMA_PTE_READ;
 	if (iommu_prot & IOMMU_WRITE)
@@ -5492,8 +5519,6 @@
 	/* Cope with horrid API which requires us to unmap more than the
 	   size argument if it happens to be a large-page mapping. */
 	BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level));
-	if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
-		return 0;
 
 	if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
 		size = VTD_PAGE_SIZE << level_to_offset_bits(level);
@@ -5525,12 +5550,11 @@
 	int level = 0;
 	u64 phys = 0;
 
-	if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
-		return 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;
 }
@@ -5601,8 +5625,10 @@
 
 	group = iommu_group_get_for_dev(dev);
 
-	if (IS_ERR(group))
-		return PTR_ERR(group);
+	if (IS_ERR(group)) {
+		ret = PTR_ERR(group);
+		goto unlink;
+	}
 
 	iommu_group_put(group);
 
@@ -5628,7 +5654,8 @@
 				if (!get_private_domain_for_dev(dev)) {
 					dev_warn(dev,
 						 "Failed to get a private domain.\n");
-					return -ENOMEM;
+					ret = -ENOMEM;
+					goto unlink;
 				}
 
 				dev_info(dev,
@@ -5643,6 +5670,10 @@
 	}
 
 	return 0;
+
+unlink:
+	iommu_device_unlink(&iommu->iommu, dev);
+	return ret;
 }
 
 static void intel_iommu_remove_device(struct device *dev)
@@ -5705,8 +5736,8 @@
 		struct pci_dev *pdev = to_pci_dev(device);
 
 		if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) {
-			reg = iommu_alloc_resv_region(0, 1UL << 24, 0,
-						      IOMMU_RESV_DIRECT);
+			reg = iommu_alloc_resv_region(0, 1UL << 24, prot,
+						   IOMMU_RESV_DIRECT_RELAXABLE);
 			if (reg)
 				list_add_tail(&reg->list, head);
 		}
@@ -5794,6 +5825,13 @@
 	WARN_ON_ONCE(!reserve_iova(&dmar_domain->iovad, start, end));
 }
 
+static struct iommu_group *intel_iommu_device_group(struct device *dev)
+{
+	if (dev_is_pci(dev))
+		return pci_device_group(dev);
+	return generic_device_group(dev);
+}
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
 {
@@ -5946,7 +5984,24 @@
 static bool intel_iommu_is_attach_deferred(struct iommu_domain *domain,
 					   struct device *dev)
 {
-	return dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO;
+	return attach_deferred(dev);
+}
+
+/*
+ * Check that the device does not live on an external facing PCI port that is
+ * marked as untrusted. Such devices should not be able to apply quirks and
+ * thus not be able to bypass the IOMMU restrictions.
+ */
+static bool risky_device(struct pci_dev *pdev)
+{
+	if (pdev->untrusted) {
+		pci_info(pdev,
+			 "Skipping IOMMU quirk for dev [%04X:%04X] on untrusted PCI link\n",
+			 pdev->vendor, pdev->device);
+		pci_info(pdev, "Please check with your BIOS/Platform vendor about this\n");
+		return true;
+	}
+	return false;
 }
 
 const struct iommu_ops intel_iommu_ops = {
@@ -5966,7 +6021,7 @@
 	.get_resv_regions	= intel_iommu_get_resv_regions,
 	.put_resv_regions	= intel_iommu_put_resv_regions,
 	.apply_resv_region	= intel_iommu_apply_resv_region,
-	.device_group		= pci_device_group,
+	.device_group		= intel_iommu_device_group,
 	.dev_has_feat		= intel_iommu_dev_has_feat,
 	.dev_feat_enabled	= intel_iommu_dev_feat_enabled,
 	.dev_enable_feat	= intel_iommu_dev_enable_feat,
@@ -5977,6 +6032,9 @@
 
 static void quirk_iommu_igfx(struct pci_dev *dev)
 {
+	if (risky_device(dev))
+		return;
+
 	pci_info(dev, "Disabling IOMMU for graphics on this chipset\n");
 	dmar_map_gfx = 0;
 }
@@ -6018,6 +6076,9 @@
 
 static void quirk_iommu_rwbf(struct pci_dev *dev)
 {
+	if (risky_device(dev))
+		return;
+
 	/*
 	 * Mobile 4 Series Chipset neglects to set RWBF capability,
 	 * but needs it. Same seems to hold for the desktop versions.
@@ -6048,6 +6109,9 @@
 {
 	unsigned short ggc;
 
+	if (risky_device(dev))
+		return;
+
 	if (pci_read_config_word(dev, GGC, &ggc))
 		return;
 
@@ -6081,6 +6145,12 @@
 	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
 	if (!pdev)
 		return;
+
+	if (risky_device(pdev)) {
+		pci_dev_put(pdev);
+		return;
+	}
+
 	pci_dev_put(pdev);
 
 	/* System Management Registers. Might be hidden, in which case
@@ -6090,6 +6160,11 @@
 	if (!pdev)
 		return;
 
+	if (risky_device(pdev)) {
+		pci_dev_put(pdev);
+		return;
+	}
+
 	if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
 		pci_dev_put(pdev);
 		return;
--- linux-ein-5.4.0.orig/drivers/iommu/intel-pasid.c
+++ linux-ein-5.4.0/drivers/iommu/intel-pasid.c
@@ -166,6 +166,9 @@
 attach_out:
 	device_attach_pasid_table(info, pasid_table);
 
+	if (!ecap_coherent(info->iommu->ecap))
+		clflush_cache_range(pasid_table->table, (1 << order) * PAGE_SIZE);
+
 	return 0;
 }
 
@@ -250,6 +253,10 @@
 
 		WRITE_ONCE(dir[dir_index].val,
 			   (u64)virt_to_phys(entries) | PASID_PTE_PRESENT);
+		if (!ecap_coherent(info->iommu->ecap)) {
+			clflush_cache_range(entries, VTD_PAGE_SIZE);
+			clflush_cache_range(&dir[dir_index].val, sizeof(*dir));
+		}
 	}
 	spin_unlock(&pasid_lock);
 
@@ -499,8 +506,16 @@
 	}
 
 #ifdef CONFIG_X86
-	if (cpu_feature_enabled(X86_FEATURE_LA57))
-		pasid_set_flpm(pte, 1);
+	/* Both CPU and IOMMU paging mode need to match */
+	if (cpu_feature_enabled(X86_FEATURE_LA57)) {
+		if (cap_5lp_support(iommu->cap)) {
+			pasid_set_flpm(pte, 1);
+		} else {
+			pr_err("VT-d has no 5-level paging support for CPU\n");
+			pasid_clear_entry(pte);
+			return -EINVAL;
+		}
+	}
 #endif /* CONFIG_X86 */
 
 	pasid_set_domain_id(pte, did);
--- linux-ein-5.4.0.orig/drivers/iommu/intel-svm.c
+++ linux-ein-5.4.0/drivers/iommu/intel-svm.c
@@ -99,16 +99,14 @@
 	return 0;
 }
 
-static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_dev *sdev,
-				unsigned long address, unsigned long pages, int ih)
+static void __flush_svm_range_dev(struct intel_svm *svm,
+				  struct intel_svm_dev *sdev,
+				  unsigned long address,
+				  unsigned long pages, int ih)
 {
 	struct qi_desc desc;
 
-	/*
-	 * Do PASID granu IOTLB invalidation if page selective capability is
-	 * not available.
-	 */
-	if (pages == -1 || !cap_pgsel_inv(svm->iommu->cap)) {
+	if (pages == -1) {
 		desc.qw0 = QI_EIOTLB_PASID(svm->pasid) |
 			QI_EIOTLB_DID(sdev->did) |
 			QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
@@ -155,6 +153,22 @@
 	}
 }
 
+static void intel_flush_svm_range_dev(struct intel_svm *svm,
+				      struct intel_svm_dev *sdev,
+				      unsigned long address,
+				      unsigned long pages, int ih)
+{
+	unsigned long shift = ilog2(__roundup_pow_of_two(pages));
+	unsigned long align = (1ULL << (VTD_PAGE_SHIFT + shift));
+	unsigned long start = ALIGN_DOWN(address, align);
+	unsigned long end = ALIGN(address + (pages << VTD_PAGE_SHIFT), align);
+
+	while (start < end) {
+		__flush_svm_range_dev(svm, sdev, start, align >> VTD_PAGE_SHIFT, ih);
+		start += align;
+	}
+}
+
 static void intel_flush_svm_range(struct intel_svm *svm, unsigned long address,
 				unsigned long pages, int ih)
 {
@@ -321,7 +335,7 @@
 		/* Do not use PASID 0 in caching mode (virtualised IOMMU) */
 		ret = intel_pasid_alloc_id(svm,
 					   !!cap_caching_mode(iommu->cap),
-					   pasid_max - 1, GFP_KERNEL);
+					   pasid_max, GFP_KERNEL);
 		if (ret < 0) {
 			kfree(svm);
 			kfree(sdev);
@@ -506,7 +520,7 @@
 	u64 priv_data[2];
 };
 
-#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10)
+#define PRQ_RING_MASK	((0x1000 << PRQ_ORDER) - 0x20)
 
 static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req)
 {
@@ -587,14 +601,15 @@
 		 * any faults on kernel addresses. */
 		if (!svm->mm)
 			goto bad_req;
-		/* If the mm is already defunct, don't handle faults. */
-		if (!mmget_not_zero(svm->mm))
-			goto bad_req;
 
 		/* If address is not canonical, return invalid response */
 		if (!is_canonical_address(address))
 			goto bad_req;
 
+		/* If the mm is already defunct, don't handle faults. */
+		if (!mmget_not_zero(svm->mm))
+			goto bad_req;
+
 		down_read(&svm->mm->mmap_sem);
 		vma = find_extend_vma(svm->mm, address);
 		if (!vma || address < vma->vm_start)
@@ -649,7 +664,7 @@
 			resp.qw0 = QI_PGRP_PASID(req->pasid) |
 				QI_PGRP_DID(req->rid) |
 				QI_PGRP_PASID_P(req->pasid_present) |
-				QI_PGRP_PDP(req->pasid_present) |
+				QI_PGRP_PDP(req->priv_data_present) |
 				QI_PGRP_RESP_CODE(result) |
 				QI_PGRP_RESP_TYPE;
 			resp.qw1 = QI_PGRP_IDX(req->prg_index) |
@@ -658,11 +673,10 @@
 			if (req->priv_data_present)
 				memcpy(&resp.qw2, req->priv_data,
 				       sizeof(req->priv_data));
+			resp.qw2 = 0;
+			resp.qw3 = 0;
+			qi_submit_sync(&resp, iommu);
 		}
-		resp.qw2 = 0;
-		resp.qw3 = 0;
-		qi_submit_sync(&resp, iommu);
-
 		head = (head + sizeof(*req)) & PRQ_RING_MASK;
 	}
 
--- linux-ein-5.4.0.orig/drivers/iommu/intel_irq_remapping.c
+++ linux-ein-5.4.0/drivers/iommu/intel_irq_remapping.c
@@ -507,12 +507,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
@@ -563,10 +569,9 @@
 					    0, INTR_REMAP_TABLE_ENTRIES,
 					    fn, &intel_ir_domain_ops,
 					    iommu);
-	irq_domain_free_fwnode(fn);
 	if (!iommu->ir_domain) {
 		pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
-		goto out_free_bitmap;
+		goto out_free_fwnode;
 	}
 	iommu->ir_msi_domain =
 		arch_create_remap_msi_irq_domain(iommu->ir_domain,
@@ -590,7 +595,7 @@
 
 		if (dmar_enable_qi(iommu)) {
 			pr_err("Failed to enable queued invalidation\n");
-			goto out_free_bitmap;
+			goto out_free_ir_domain;
 		}
 	}
 
@@ -614,6 +619,14 @@
 
 	return 0;
 
+out_free_ir_domain:
+	if (iommu->ir_msi_domain)
+		irq_domain_remove(iommu->ir_msi_domain);
+	iommu->ir_msi_domain = NULL;
+	irq_domain_remove(iommu->ir_domain);
+	iommu->ir_domain = NULL;
+out_free_fwnode:
+	irq_domain_free_fwnode(fn);
 out_free_bitmap:
 	bitmap_free(bitmap);
 out_free_pages:
@@ -628,13 +641,21 @@
 
 static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
 {
+	struct fwnode_handle *fn;
+
 	if (iommu && iommu->ir_table) {
 		if (iommu->ir_msi_domain) {
+			fn = iommu->ir_msi_domain->fwnode;
+
 			irq_domain_remove(iommu->ir_msi_domain);
+			irq_domain_free_fwnode(fn);
 			iommu->ir_msi_domain = NULL;
 		}
 		if (iommu->ir_domain) {
+			fn = iommu->ir_domain->fwnode;
+
 			irq_domain_remove(iommu->ir_domain);
+			irq_domain_free_fwnode(fn);
 			iommu->ir_domain = NULL;
 		}
 		free_pages((unsigned long)iommu->ir_table->base,
@@ -1386,6 +1407,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-ein-5.4.0.orig/drivers/iommu/io-pgtable-arm-v7s.c
+++ linux-ein-5.4.0/drivers/iommu/io-pgtable-arm-v7s.c
@@ -244,13 +244,17 @@
 			__GFP_ZERO | ARM_V7S_TABLE_GFP_DMA, get_order(size));
 	else if (lvl == 2)
 		table = kmem_cache_zalloc(data->l2_tables, gfp);
+
+	if (!table)
+		return NULL;
+
 	phys = virt_to_phys(table);
 	if (phys != (arm_v7s_iopte)phys) {
 		/* Doesn't fit in PTE */
 		dev_err(dev, "Page table does not fit in PTE: %pa", &phys);
 		goto out_free;
 	}
-	if (table && !cfg->coherent_walk) {
+	if (!cfg->coherent_walk) {
 		dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
 		if (dma_mapping_error(dev, dma))
 			goto out_free;
--- linux-ein-5.4.0.orig/drivers/iommu/io-pgtable-arm.c
+++ linux-ein-5.4.0/drivers/iommu/io-pgtable-arm.c
@@ -351,11 +351,12 @@
 static arm_lpae_iopte arm_lpae_install_table(arm_lpae_iopte *table,
 					     arm_lpae_iopte *ptep,
 					     arm_lpae_iopte curr,
-					     struct io_pgtable_cfg *cfg)
+					     struct arm_lpae_io_pgtable *data)
 {
 	arm_lpae_iopte old, new;
+	struct io_pgtable_cfg *cfg = &data->iop.cfg;
 
-	new = __pa(table) | ARM_LPAE_PTE_TYPE_TABLE;
+	new = paddr_to_iopte(__pa(table), data) | ARM_LPAE_PTE_TYPE_TABLE;
 	if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
 		new |= ARM_LPAE_PTE_NSTABLE;
 
@@ -406,7 +407,7 @@
 		if (!cptep)
 			return -ENOMEM;
 
-		pte = arm_lpae_install_table(cptep, ptep, 0, cfg);
+		pte = arm_lpae_install_table(cptep, ptep, 0, data);
 		if (pte)
 			__arm_lpae_free_pages(cptep, tblsz, cfg);
 	} else if (!cfg->coherent_walk && !(pte & ARM_LPAE_PTE_SW_SYNC)) {
@@ -575,7 +576,7 @@
 		__arm_lpae_init_pte(data, blk_paddr, pte, lvl, &tablep[i]);
 	}
 
-	pte = arm_lpae_install_table(tablep, ptep, blk_pte, cfg);
+	pte = arm_lpae_install_table(tablep, ptep, blk_pte, data);
 	if (pte != blk_pte) {
 		__arm_lpae_free_pages(tablep, tablesz, cfg);
 		/*
--- linux-ein-5.4.0.orig/drivers/iommu/iommu.c
+++ linux-ein-5.4.0/drivers/iommu/iommu.c
@@ -312,8 +312,8 @@
 	list_for_each_entry_safe(iter, tmp, regions, list) {
 		phys_addr_t top_end, iter_end = iter->start + iter->length - 1;
 
-		/* no merge needed on elements of different types than @nr */
-		if (iter->type != nr->type) {
+		/* no merge needed on elements of different types than @new */
+		if (iter->type != new->type) {
 			list_move_tail(&iter->list, &stack);
 			continue;
 		}
@@ -492,7 +492,7 @@
 				   NULL, "%d", group->id);
 	if (ret) {
 		ida_simple_remove(&iommu_group_ida, group->id);
-		kfree(group);
+		kobject_put(&group->kobj);
 		return ERR_PTR(ret);
 	}
 
@@ -751,6 +751,7 @@
 	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:
@@ -774,6 +775,9 @@
 	struct iommu_group *group = dev->iommu_group;
 	struct group_device *tmp_device, *device = NULL;
 
+	if (!group)
+		return;
+
 	dev_info(dev, "Removing from iommu group %d\n", group->id);
 
 	/* Pre-notify listeners that a device is being removed. */
@@ -1854,8 +1858,8 @@
 	return pgsize;
 }
 
-int iommu_map(struct iommu_domain *domain, unsigned long iova,
-	      phys_addr_t paddr, size_t size, int prot)
+int __iommu_map(struct iommu_domain *domain, unsigned long iova,
+	      phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	const struct iommu_ops *ops = domain->ops;
 	unsigned long orig_iova = iova;
@@ -1892,8 +1896,8 @@
 
 		pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 			 iova, &paddr, pgsize);
+		ret = ops->map(domain, iova, paddr, pgsize, prot, gfp);
 
-		ret = ops->map(domain, iova, paddr, pgsize, prot);
 		if (ret)
 			break;
 
@@ -1913,8 +1917,22 @@
 
 	return ret;
 }
+
+int iommu_map(struct iommu_domain *domain, unsigned long iova,
+	      phys_addr_t paddr, size_t size, int prot)
+{
+	might_sleep();
+	return __iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL);
+}
 EXPORT_SYMBOL_GPL(iommu_map);
 
+int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova,
+	      phys_addr_t paddr, size_t size, int prot)
+{
+	return __iommu_map(domain, iova, paddr, size, prot, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(iommu_map_atomic);
+
 static size_t __iommu_unmap(struct iommu_domain *domain,
 			    unsigned long iova, size_t size,
 			    struct iommu_iotlb_gather *iotlb_gather)
@@ -1991,8 +2009,9 @@
 }
 EXPORT_SYMBOL_GPL(iommu_unmap_fast);
 
-size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
-		    struct scatterlist *sg, unsigned int nents, int prot)
+size_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+		    struct scatterlist *sg, unsigned int nents, int prot,
+		    gfp_t gfp)
 {
 	size_t len = 0, mapped = 0;
 	phys_addr_t start;
@@ -2003,7 +2022,9 @@
 		phys_addr_t s_phys = sg_phys(sg);
 
 		if (len && s_phys != start + len) {
-			ret = iommu_map(domain, iova + mapped, start, len, prot);
+			ret = __iommu_map(domain, iova + mapped, start,
+					len, prot, gfp);
+
 			if (ret)
 				goto out_err;
 
@@ -2031,8 +2052,22 @@
 	return 0;
 
 }
+
+size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+		    struct scatterlist *sg, unsigned int nents, int prot)
+{
+	might_sleep();
+	return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_KERNEL);
+}
 EXPORT_SYMBOL_GPL(iommu_map_sg);
 
+size_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,
+		    struct scatterlist *sg, unsigned int nents, int prot)
+{
+	return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(iommu_map_sg_atomic);
+
 int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
 			       phys_addr_t paddr, u64 size, int prot)
 {
@@ -2221,13 +2256,13 @@
 		goto out;
 	}
 
-	iommu_group_create_direct_mappings(group, dev);
-
 	/* Make the domain the default for this group */
 	if (group->default_domain)
 		iommu_domain_free(group->default_domain);
 	group->default_domain = domain;
 
+	iommu_group_create_direct_mappings(group, dev);
+
 	dev_info(dev, "Using iommu %s mapping\n",
 		 type == IOMMU_DOMAIN_DMA ? "dma" : "direct");
 
--- linux-ein-5.4.0.orig/drivers/iommu/iova.c
+++ linux-ein-5.4.0/drivers/iommu/iova.c
@@ -64,8 +64,7 @@
 	if (!has_iova_flush_queue(iovad))
 		return;
 
-	if (timer_pending(&iovad->fq_timer))
-		del_timer(&iovad->fq_timer);
+	del_timer_sync(&iovad->fq_timer);
 
 	fq_destroy_all_entries(iovad);
 
@@ -139,10 +138,11 @@
 	cached_iova = rb_entry(iovad->cached32_node, struct iova, node);
 	if (free == cached_iova ||
 	    (free->pfn_hi < iovad->dma_32bit_pfn &&
-	     free->pfn_lo >= cached_iova->pfn_lo)) {
+	     free->pfn_lo >= cached_iova->pfn_lo))
 		iovad->cached32_node = rb_next(&free->node);
+
+	if (free->pfn_lo < iovad->dma_32bit_pfn)
 		iovad->max32_alloc_size = iovad->dma_32bit_pfn;
-	}
 
 	cached_iova = rb_entry(iovad->cached_node, struct iova, node);
 	if (free->pfn_lo >= cached_iova->pfn_lo)
@@ -233,7 +233,7 @@
 
 struct iova *alloc_iova_mem(void)
 {
-	return kmem_cache_alloc(iova_cache, GFP_ATOMIC);
+	return kmem_cache_zalloc(iova_cache, GFP_ATOMIC | __GFP_NOWARN);
 }
 EXPORT_SYMBOL(alloc_iova_mem);
 
@@ -811,7 +811,9 @@
 	for (i = 0 ; i < mag->size; ++i) {
 		struct iova *iova = private_find_iova(iovad, mag->pfns[i]);
 
-		BUG_ON(!iova);
+		if (WARN_ON(!iova))
+			continue;
+
 		private_free_iova(iovad, iova);
 	}
 
--- linux-ein-5.4.0.orig/drivers/iommu/ipmmu-vmsa.c
+++ linux-ein-5.4.0/drivers/iommu/ipmmu-vmsa.c
@@ -724,7 +724,7 @@
 }
 
 static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
-		     phys_addr_t paddr, size_t size, int prot)
+		     phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
 
@@ -1061,7 +1061,9 @@
 	bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
 	mmu->features = of_device_get_match_data(&pdev->dev);
 	memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs);
-	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
+	if (ret)
+		return ret;
 
 	/* Map I/O memory and request IRQ. */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--- linux-ein-5.4.0.orig/drivers/iommu/msm_iommu.c
+++ linux-ein-5.4.0/drivers/iommu/msm_iommu.c
@@ -504,7 +504,7 @@
 }
 
 static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			 phys_addr_t pa, size_t len, int prot)
+			 phys_addr_t pa, size_t len, int prot, gfp_t gfp)
 {
 	struct msm_priv *priv = to_msm_priv(domain);
 	unsigned long flags;
@@ -636,16 +636,19 @@
 static int qcom_iommu_of_xlate(struct device *dev,
 			       struct of_phandle_args *spec)
 {
-	struct msm_iommu_dev *iommu;
+	struct msm_iommu_dev *iommu = NULL, *iter;
 	unsigned long flags;
 	int ret = 0;
 
 	spin_lock_irqsave(&msm_iommu_lock, flags);
-	list_for_each_entry(iommu, &qcom_iommu_devices, dev_node)
-		if (iommu->dev->of_node == spec->np)
+	list_for_each_entry(iter, &qcom_iommu_devices, dev_node) {
+		if (iter->dev->of_node == spec->np) {
+			iommu = iter;
 			break;
+		}
+	}
 
-	if (!iommu || iommu->dev->of_node != spec->np) {
+	if (!iommu) {
 		ret = -ENODEV;
 		goto fail;
 	}
--- linux-ein-5.4.0.orig/drivers/iommu/mtk_iommu.c
+++ linux-ein-5.4.0/drivers/iommu/mtk_iommu.c
@@ -219,22 +219,37 @@
 static void mtk_iommu_tlb_flush_walk(unsigned long iova, size_t size,
 				     size_t granule, void *cookie)
 {
+	struct mtk_iommu_data *data = cookie;
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->tlb_lock, flags);
 	mtk_iommu_tlb_add_flush_nosync(iova, size, granule, false, cookie);
 	mtk_iommu_tlb_sync(cookie);
+	spin_unlock_irqrestore(&data->tlb_lock, flags);
 }
 
 static void mtk_iommu_tlb_flush_leaf(unsigned long iova, size_t size,
 				     size_t granule, void *cookie)
 {
+	struct mtk_iommu_data *data = cookie;
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->tlb_lock, flags);
 	mtk_iommu_tlb_add_flush_nosync(iova, size, granule, true, cookie);
 	mtk_iommu_tlb_sync(cookie);
+	spin_unlock_irqrestore(&data->tlb_lock, flags);
 }
 
 static void mtk_iommu_tlb_flush_page_nosync(struct iommu_iotlb_gather *gather,
 					    unsigned long iova, size_t granule,
 					    void *cookie)
 {
+	struct mtk_iommu_data *data = cookie;
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->tlb_lock, flags);
 	mtk_iommu_tlb_add_flush_nosync(iova, granule, granule, true, cookie);
+	spin_unlock_irqrestore(&data->tlb_lock, flags);
 }
 
 static const struct iommu_flush_ops mtk_iommu_flush_ops = {
@@ -412,7 +427,7 @@
 }
 
 static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			 phys_addr_t paddr, size_t size, int prot)
+			 phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
 	struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
@@ -447,13 +462,18 @@
 
 static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
 {
-	mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
+	mtk_iommu_tlb_flush_all(mtk_iommu_get_m4u_data());
 }
 
 static void mtk_iommu_iotlb_sync(struct iommu_domain *domain,
 				 struct iommu_iotlb_gather *gather)
 {
-	mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
+	struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->tlb_lock, flags);
+	mtk_iommu_tlb_sync(data);
+	spin_unlock_irqrestore(&data->tlb_lock, flags);
 }
 
 static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -733,6 +753,7 @@
 	if (ret)
 		return ret;
 
+	spin_lock_init(&data->tlb_lock);
 	list_add_tail(&data->list, &m4ulist);
 
 	if (!iommu_present(&platform_bus_type))
@@ -748,8 +769,7 @@
 	iommu_device_sysfs_remove(&data->iommu);
 	iommu_device_unregister(&data->iommu);
 
-	if (iommu_present(&platform_bus_type))
-		bus_set_iommu(&platform_bus_type, NULL);
+	list_del(&data->list);
 
 	clk_disable_unprepare(data->bclk);
 	devm_free_irq(&pdev->dev, data->irq, data);
--- linux-ein-5.4.0.orig/drivers/iommu/mtk_iommu.h
+++ linux-ein-5.4.0/drivers/iommu/mtk_iommu.h
@@ -58,6 +58,7 @@
 	struct iommu_group		*m4u_group;
 	bool                            enable_4GB;
 	bool				tlb_flush_active;
+	spinlock_t			tlb_lock; /* lock for tlb range flush */
 
 	struct iommu_device		iommu;
 	const struct mtk_iommu_plat_data *plat_data;
--- linux-ein-5.4.0.orig/drivers/iommu/mtk_iommu_v1.c
+++ linux-ein-5.4.0/drivers/iommu/mtk_iommu_v1.c
@@ -295,7 +295,7 @@
 }
 
 static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			 phys_addr_t paddr, size_t size, int prot)
+			 phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct mtk_iommu_domain *dom = to_mtk_domain(domain);
 	unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT;
@@ -626,18 +626,34 @@
 	ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
 				     dev_name(&pdev->dev));
 	if (ret)
-		return ret;
+		goto out_clk_unprepare;
 
 	iommu_device_set_ops(&data->iommu, &mtk_iommu_ops);
 
 	ret = iommu_device_register(&data->iommu);
 	if (ret)
-		return ret;
+		goto out_sysfs_remove;
+
+	if (!iommu_present(&platform_bus_type)) {
+		ret = bus_set_iommu(&platform_bus_type,  &mtk_iommu_ops);
+		if (ret)
+			goto out_dev_unreg;
+	}
 
-	if (!iommu_present(&platform_bus_type))
-		bus_set_iommu(&platform_bus_type,  &mtk_iommu_ops);
+	ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
+	if (ret)
+		goto out_bus_set_null;
+	return ret;
 
-	return component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
+out_bus_set_null:
+	bus_set_iommu(&platform_bus_type, NULL);
+out_dev_unreg:
+	iommu_device_unregister(&data->iommu);
+out_sysfs_remove:
+	iommu_device_sysfs_remove(&data->iommu);
+out_clk_unprepare:
+	clk_disable_unprepare(data->bclk);
+	return ret;
 }
 
 static int mtk_iommu_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/iommu/of_iommu.c
+++ linux-ein-5.4.0/drivers/iommu/of_iommu.c
@@ -121,7 +121,7 @@
 	struct of_phandle_args iommu_spec = { .args_count = 1 };
 	int err;
 
-	err = of_map_rid(info->np, alias, "iommu-map", "iommu-map-mask",
+	err = of_map_id(info->np, alias, "iommu-map", "iommu-map-mask",
 			 &iommu_spec.np, iommu_spec.args);
 	if (err)
 		return err == -ENODEV ? NO_IOMMU : err;
@@ -137,7 +137,7 @@
 	struct of_phandle_args iommu_spec = { .args_count = 1 };
 	int err;
 
-	err = of_map_rid(master_np, mc_dev->icid, "iommu-map",
+	err = of_map_id(master_np, mc_dev->icid, "iommu-map",
 			 "iommu-map-mask", &iommu_spec.np,
 			 iommu_spec.args);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/iommu/omap-iommu-debug.c
+++ linux-ein-5.4.0/drivers/iommu/omap-iommu-debug.c
@@ -32,12 +32,12 @@
 		ssize_t bytes;						\
 		const char *str = "%20s: %08x\n";			\
 		const int maxcol = 32;					\
-		bytes = snprintf(p, maxcol, str, __stringify(name),	\
+		if (len < maxcol)					\
+			goto out;					\
+		bytes = scnprintf(p, maxcol, str, __stringify(name),	\
 				 iommu_read_reg(obj, MMU_##name));	\
 		p += bytes;						\
 		len -= bytes;						\
-		if (len < maxcol)					\
-			goto out;					\
 	} while (0)
 
 static ssize_t
@@ -98,8 +98,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-ein-5.4.0.orig/drivers/iommu/omap-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/omap-iommu.c
@@ -1339,7 +1339,7 @@
 }
 
 static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
-			  phys_addr_t pa, size_t bytes, int prot)
+			  phys_addr_t pa, size_t bytes, int prot, gfp_t gfp)
 {
 	struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
 	struct device *dev = omap_domain->dev;
--- linux-ein-5.4.0.orig/drivers/iommu/qcom_iommu.c
+++ linux-ein-5.4.0/drivers/iommu/qcom_iommu.c
@@ -345,21 +345,19 @@
 {
 	struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
 
-	if (WARN_ON(qcom_domain->iommu))    /* forgot to detach? */
-		return;
-
 	iommu_put_dma_cookie(domain);
 
-	/* NOTE: unmap can be called after client device is powered off,
-	 * for example, with GPUs or anything involving dma-buf.  So we
-	 * cannot rely on the device_link.  Make sure the IOMMU is on to
-	 * avoid unclocked accesses in the TLB inv path:
-	 */
-	pm_runtime_get_sync(qcom_domain->iommu->dev);
-
-	free_io_pgtable_ops(qcom_domain->pgtbl_ops);
-
-	pm_runtime_put_sync(qcom_domain->iommu->dev);
+	if (qcom_domain->iommu) {
+		/*
+		 * NOTE: unmap can be called after client device is powered
+		 * off, for example, with GPUs or anything involving dma-buf.
+		 * So we cannot rely on the device_link.  Make sure the IOMMU
+		 * is on to avoid unclocked accesses in the TLB inv path:
+		 */
+		pm_runtime_get_sync(qcom_domain->iommu->dev);
+		free_io_pgtable_ops(qcom_domain->pgtbl_ops);
+		pm_runtime_put_sync(qcom_domain->iommu->dev);
+	}
 
 	kfree(qcom_domain);
 }
@@ -405,7 +403,7 @@
 	struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
 	unsigned i;
 
-	if (!qcom_domain->iommu)
+	if (WARN_ON(!qcom_domain->iommu))
 		return;
 
 	pm_runtime_get_sync(qcom_iommu->dev);
@@ -418,12 +416,10 @@
 		ctx->domain = NULL;
 	}
 	pm_runtime_put_sync(qcom_iommu->dev);
-
-	qcom_domain->iommu = NULL;
 }
 
 static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			  phys_addr_t paddr, size_t size, int prot)
+			  phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	int ret;
 	unsigned long flags;
@@ -789,9 +785,12 @@
 {
 	struct device_node *child;
 
-	for_each_child_of_node(qcom_iommu->dev->of_node, child)
-		if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec"))
+	for_each_child_of_node(qcom_iommu->dev->of_node, child) {
+		if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) {
+			of_node_put(child);
 			return true;
+		}
+	}
 
 	return false;
 }
@@ -818,8 +817,11 @@
 	qcom_iommu->dev = dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res)
+	if (res) {
 		qcom_iommu->local_base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(qcom_iommu->local_base))
+			return PTR_ERR(qcom_iommu->local_base);
+	}
 
 	qcom_iommu->iface_clk = devm_clk_get(dev, "iface");
 	if (IS_ERR(qcom_iommu->iface_clk)) {
--- linux-ein-5.4.0.orig/drivers/iommu/rockchip-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/rockchip-iommu.c
@@ -758,7 +758,7 @@
 }
 
 static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
-			phys_addr_t paddr, size_t size, int prot)
+			phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
 	unsigned long flags;
@@ -980,13 +980,13 @@
 	if (!dma_dev)
 		return NULL;
 
-	rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL);
+	rk_domain = kzalloc(sizeof(*rk_domain), GFP_KERNEL);
 	if (!rk_domain)
 		return NULL;
 
 	if (type == IOMMU_DOMAIN_DMA &&
 	    iommu_get_dma_cookie(&rk_domain->domain))
-		return NULL;
+		goto err_free_domain;
 
 	/*
 	 * rk32xx iommus use a 2 level pagetable.
@@ -1021,6 +1021,8 @@
 err_put_cookie:
 	if (type == IOMMU_DOMAIN_DMA)
 		iommu_put_dma_cookie(&rk_domain->domain);
+err_free_domain:
+	kfree(rk_domain);
 
 	return NULL;
 }
@@ -1049,6 +1051,7 @@
 
 	if (domain->type == IOMMU_DOMAIN_DMA)
 		iommu_put_dma_cookie(&rk_domain->domain);
+	kfree(rk_domain);
 }
 
 static int rk_iommu_add_device(struct device *dev)
@@ -1227,18 +1230,20 @@
 	for (i = 0; i < iommu->num_irq; i++) {
 		int irq = platform_get_irq(pdev, i);
 
-		if (irq < 0)
-			return irq;
+		if (irq < 0) {
+			err = irq;
+			goto err_pm_disable;
+		}
 
 		err = devm_request_irq(iommu->dev, irq, rk_iommu_irq,
 				       IRQF_SHARED, dev_name(dev), iommu);
-		if (err) {
-			pm_runtime_disable(dev);
-			goto err_remove_sysfs;
-		}
+		if (err)
+			goto err_pm_disable;
 	}
 
 	return 0;
+err_pm_disable:
+	pm_runtime_disable(dev);
 err_remove_sysfs:
 	iommu_device_sysfs_remove(&iommu->iommu);
 err_put_group:
--- linux-ein-5.4.0.orig/drivers/iommu/s390-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/s390-iommu.c
@@ -87,7 +87,7 @@
 				    struct device *dev)
 {
 	struct s390_domain *s390_domain = to_s390_domain(domain);
-	struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
+	struct zpci_dev *zdev = to_zpci_dev(dev);
 	struct s390_domain_device *domain_device;
 	unsigned long flags;
 	int rc;
@@ -139,7 +139,7 @@
 				     struct device *dev)
 {
 	struct s390_domain *s390_domain = to_s390_domain(domain);
-	struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
+	struct zpci_dev *zdev = to_zpci_dev(dev);
 	struct s390_domain_device *domain_device, *tmp;
 	unsigned long flags;
 	int found = 0;
@@ -169,7 +169,7 @@
 static int s390_iommu_add_device(struct device *dev)
 {
 	struct iommu_group *group = iommu_group_get_for_dev(dev);
-	struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
+	struct zpci_dev *zdev = to_zpci_dev(dev);
 
 	if (IS_ERR(group))
 		return PTR_ERR(group);
@@ -182,7 +182,7 @@
 
 static void s390_iommu_remove_device(struct device *dev)
 {
-	struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
+	struct zpci_dev *zdev = to_zpci_dev(dev);
 	struct iommu_domain *domain;
 
 	/*
@@ -265,7 +265,7 @@
 }
 
 static int s390_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			  phys_addr_t paddr, size_t size, int prot)
+			  phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct s390_domain *s390_domain = to_s390_domain(domain);
 	int flags = ZPCI_PTE_VALID, rc = 0;
--- linux-ein-5.4.0.orig/drivers/iommu/tegra-gart.c
+++ linux-ein-5.4.0/drivers/iommu/tegra-gart.c
@@ -178,7 +178,7 @@
 }
 
 static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			  phys_addr_t pa, size_t bytes, int prot)
+			  phys_addr_t pa, size_t bytes, int prot, gfp_t gfp)
 {
 	struct gart_device *gart = gart_handle;
 	int ret;
--- linux-ein-5.4.0.orig/drivers/iommu/tegra-smmu.c
+++ linux-ein-5.4.0/drivers/iommu/tegra-smmu.c
@@ -159,9 +159,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)
@@ -549,6 +549,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;
 
@@ -557,7 +558,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);
 }
@@ -599,7 +600,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);
@@ -624,7 +625,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);
 
@@ -650,7 +651,7 @@
 }
 
 static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
-			  phys_addr_t paddr, size_t size, int prot)
+			  phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	struct tegra_smmu_as *as = to_smmu_as(domain);
 	dma_addr_t pte_dma;
--- linux-ein-5.4.0.orig/drivers/iommu/virtio-iommu.c
+++ linux-ein-5.4.0/drivers/iommu/virtio-iommu.c
@@ -454,7 +454,7 @@
 	if (!region)
 		return -ENOMEM;
 
-	list_add(&vdev->resv_regions, &region->list);
+	list_add(&region->list, &vdev->resv_regions);
 	return 0;
 }
 
@@ -614,18 +614,20 @@
 	int ret;
 	struct viommu_domain *vdomain = to_viommu_domain(domain);
 
-	vdomain->viommu		= viommu;
-	vdomain->map_flags	= viommu->map_flags;
+	ret = ida_alloc_range(&viommu->domain_ids, viommu->first_domain,
+			      viommu->last_domain, GFP_KERNEL);
+	if (ret < 0)
+		return ret;
+
+	vdomain->id		= (unsigned int)ret;
 
 	domain->pgsize_bitmap	= viommu->pgsize_bitmap;
 	domain->geometry	= viommu->geometry;
 
-	ret = ida_alloc_range(&viommu->domain_ids, viommu->first_domain,
-			      viommu->last_domain, GFP_KERNEL);
-	if (ret >= 0)
-		vdomain->id = (unsigned int)ret;
+	vdomain->map_flags	= viommu->map_flags;
+	vdomain->viommu		= viommu;
 
-	return ret > 0 ? 0 : ret;
+	return 0;
 }
 
 static void viommu_domain_free(struct iommu_domain *domain)
@@ -713,7 +715,7 @@
 }
 
 static int viommu_map(struct iommu_domain *domain, unsigned long iova,
-		      phys_addr_t paddr, size_t size, int prot)
+		      phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
 {
 	int ret;
 	u32 flags;
--- linux-ein-5.4.0.orig/drivers/ipack/carriers/tpci200.c
+++ linux-ein-5.4.0/drivers/ipack/carriers/tpci200.c
@@ -91,16 +91,13 @@
 	free_irq(tpci200->info->pdev->irq, (void *) tpci200);
 
 	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
-	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
 
 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
 	pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
 	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
-	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
 
 	pci_disable_device(tpci200->info->pdev);
-	pci_dev_put(tpci200->info->pdev);
 }
 
 static void tpci200_enable_irq(struct tpci200_board *tpci200,
@@ -259,7 +256,7 @@
 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_disable_pci;
+		goto err_disable_device;
 	}
 
 	/* Request IO ID INT space (Bar 3) */
@@ -271,7 +268,7 @@
 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_release_ip_space;
+		goto err_ip_interface_bar;
 	}
 
 	/* Request MEM8 space (Bar 5) */
@@ -282,7 +279,7 @@
 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5!",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_release_ioid_int_space;
+		goto err_io_id_int_spaces_bar;
 	}
 
 	/* Request MEM16 space (Bar 4) */
@@ -293,7 +290,7 @@
 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_release_mem8_space;
+		goto err_mem8_space_bar;
 	}
 
 	/* Map internal tpci200 driver user space */
@@ -306,7 +303,8 @@
 			"(bn 0x%X, sn 0x%X) failed to map driver user space!",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_release_mem8_space;
+		res = -ENOMEM;
+		goto err_mem16_space_bar;
 	}
 
 	/* Initialize lock that protects interface_regs */
@@ -345,18 +343,22 @@
 			"(bn 0x%X, sn 0x%X) unable to register IRQ !",
 			tpci200->info->pdev->bus->number,
 			tpci200->info->pdev->devfn);
-		goto out_release_ioid_int_space;
+		goto err_interface_regs;
 	}
 
 	return 0;
 
-out_release_mem8_space:
+err_interface_regs:
+	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
+err_mem16_space_bar:
+	pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
+err_mem8_space_bar:
 	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
-out_release_ioid_int_space:
+err_io_id_int_spaces_bar:
 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
-out_release_ip_space:
+err_ip_interface_bar:
 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
-out_disable_pci:
+err_disable_device:
 	pci_disable_device(tpci200->info->pdev);
 	return res;
 }
@@ -528,7 +530,7 @@
 	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
 	if (!tpci200->info) {
 		ret = -ENOMEM;
-		goto out_err_info;
+		goto err_tpci200;
 	}
 
 	pci_dev_get(pdev);
@@ -539,7 +541,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
 		ret = -EBUSY;
-		goto out_err_pci_request;
+		goto err_tpci200_info;
 	}
 	tpci200->info->cfg_regs = ioremap_nocache(
 			pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
@@ -547,7 +549,7 @@
 	if (!tpci200->info->cfg_regs) {
 		dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
 		ret = -EFAULT;
-		goto out_err_ioremap;
+		goto err_request_region;
 	}
 
 	/* Disable byte swapping for 16 bit IP module access. This will ensure
@@ -570,7 +572,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "error during tpci200 install\n");
 		ret = -ENODEV;
-		goto out_err_install;
+		goto err_cfg_regs;
 	}
 
 	/* Register the carrier in the industry pack bus driver */
@@ -582,7 +584,7 @@
 		dev_err(&pdev->dev,
 			"error registering the carrier on ipack driver\n");
 		ret = -EFAULT;
-		goto out_err_bus_register;
+		goto err_tpci200_install;
 	}
 
 	/* save the bus number given by ipack to logging purpose */
@@ -593,16 +595,16 @@
 		tpci200_create_device(tpci200, i);
 	return 0;
 
-out_err_bus_register:
+err_tpci200_install:
 	tpci200_uninstall(tpci200);
-out_err_install:
-	iounmap(tpci200->info->cfg_regs);
-out_err_ioremap:
+err_cfg_regs:
+	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
+err_request_region:
 	pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
-out_err_pci_request:
-	pci_dev_put(pdev);
+err_tpci200_info:
 	kfree(tpci200->info);
-out_err_info:
+	pci_dev_put(pdev);
+err_tpci200:
 	kfree(tpci200);
 	return ret;
 }
@@ -612,6 +614,12 @@
 	ipack_bus_unregister(tpci200->info->ipack_bus);
 	tpci200_uninstall(tpci200);
 
+	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
+
+	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
+
+	pci_dev_put(tpci200->info->pdev);
+
 	kfree(tpci200->info);
 	kfree(tpci200);
 }
--- linux-ein-5.4.0.orig/drivers/ipack/devices/ipoctal.c
+++ linux-ein-5.4.0/drivers/ipack/devices/ipoctal.c
@@ -35,6 +35,7 @@
 	unsigned int			pointer_read;
 	unsigned int			pointer_write;
 	struct tty_port			tty_port;
+	bool				tty_registered;
 	union scc2698_channel __iomem	*regs;
 	union scc2698_block __iomem	*block_regs;
 	unsigned int			board_id;
@@ -83,22 +84,34 @@
 	return 0;
 }
 
-static int ipoctal_open(struct tty_struct *tty, struct file *file)
+static int ipoctal_install(struct tty_driver *driver, struct tty_struct *tty)
 {
 	struct ipoctal_channel *channel = dev_get_drvdata(tty->dev);
 	struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
-	int err;
-
-	tty->driver_data = channel;
+	int res;
 
 	if (!ipack_get_carrier(ipoctal->dev))
 		return -EBUSY;
 
-	err = tty_port_open(&channel->tty_port, tty, file);
-	if (err)
-		ipack_put_carrier(ipoctal->dev);
+	res = tty_standard_install(driver, tty);
+	if (res)
+		goto err_put_carrier;
+
+	tty->driver_data = channel;
+
+	return 0;
+
+err_put_carrier:
+	ipack_put_carrier(ipoctal->dev);
+
+	return res;
+}
+
+static int ipoctal_open(struct tty_struct *tty, struct file *file)
+{
+	struct ipoctal_channel *channel = tty->driver_data;
 
-	return err;
+	return tty_port_open(&channel->tty_port, tty, file);
 }
 
 static void ipoctal_reset_stats(struct ipoctal_stats *stats)
@@ -266,7 +279,6 @@
 	int res;
 	int i;
 	struct tty_driver *tty;
-	char name[20];
 	struct ipoctal_channel *channel;
 	struct ipack_region *region;
 	void __iomem *addr;
@@ -357,8 +369,11 @@
 	/* Fill struct tty_driver with ipoctal data */
 	tty->owner = THIS_MODULE;
 	tty->driver_name = KBUILD_MODNAME;
-	sprintf(name, KBUILD_MODNAME ".%d.%d.", bus_nr, slot);
-	tty->name = name;
+	tty->name = kasprintf(GFP_KERNEL, KBUILD_MODNAME ".%d.%d.", bus_nr, slot);
+	if (!tty->name) {
+		res = -ENOMEM;
+		goto err_put_driver;
+	}
 	tty->major = 0;
 
 	tty->minor_start = 0;
@@ -374,8 +389,7 @@
 	res = tty_register_driver(tty);
 	if (res) {
 		dev_err(&ipoctal->dev->dev, "Can't register tty driver.\n");
-		put_tty_driver(tty);
-		return res;
+		goto err_free_name;
 	}
 
 	/* Save struct tty_driver for use it when uninstalling the device */
@@ -386,7 +400,9 @@
 
 		channel = &ipoctal->channel[i];
 		tty_port_init(&channel->tty_port);
-		tty_port_alloc_xmit_buf(&channel->tty_port);
+		res = tty_port_alloc_xmit_buf(&channel->tty_port);
+		if (res)
+			continue;
 		channel->tty_port.ops = &ipoctal_tty_port_ops;
 
 		ipoctal_reset_stats(&channel->stats);
@@ -394,13 +410,15 @@
 		spin_lock_init(&channel->lock);
 		channel->pointer_read = 0;
 		channel->pointer_write = 0;
-		tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
+		tty_dev = tty_port_register_device_attr(&channel->tty_port, tty,
+							i, NULL, channel, NULL);
 		if (IS_ERR(tty_dev)) {
 			dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
+			tty_port_free_xmit_buf(&channel->tty_port);
 			tty_port_destroy(&channel->tty_port);
 			continue;
 		}
-		dev_set_drvdata(tty_dev, channel);
+		channel->tty_registered = true;
 	}
 
 	/*
@@ -412,6 +430,13 @@
 				       ipoctal_irq_handler, ipoctal);
 
 	return 0;
+
+err_free_name:
+	kfree(tty->name);
+err_put_driver:
+	put_tty_driver(tty);
+
+	return res;
 }
 
 static inline int ipoctal_copy_write_buffer(struct ipoctal_channel *channel,
@@ -652,6 +677,7 @@
 
 static const struct tty_operations ipoctal_fops = {
 	.ioctl =		NULL,
+	.install =		ipoctal_install,
 	.open =			ipoctal_open,
 	.close =		ipoctal_close,
 	.write =		ipoctal_write_tty,
@@ -694,12 +720,17 @@
 
 	for (i = 0; i < NR_CHANNELS; i++) {
 		struct ipoctal_channel *channel = &ipoctal->channel[i];
+
+		if (!channel->tty_registered)
+			continue;
+
 		tty_unregister_device(ipoctal->tty_drv, i);
 		tty_port_free_xmit_buf(&channel->tty_port);
 		tty_port_destroy(&channel->tty_port);
 	}
 
 	tty_unregister_driver(ipoctal->tty_drv);
+	kfree(ipoctal->tty_drv->name);
 	put_tty_driver(ipoctal->tty_drv);
 	kfree(ipoctal);
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/Kconfig
+++ linux-ein-5.4.0/drivers/irqchip/Kconfig
@@ -415,6 +415,7 @@
 config GOLDFISH_PIC
        bool "Goldfish programmable interrupt controller"
        depends on MIPS && (GOLDFISH || COMPILE_TEST)
+       select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
        help
          Say yes here to enable Goldfish interrupt controller driver used
@@ -446,7 +447,7 @@
 	  the controller's register.
 
 config IMX_IRQSTEER
-	bool "i.MX IRQSTEER support"
+	tristate "i.MX IRQSTEER support"
 	depends on ARCH_MXC || COMPILE_TEST
 	default ARCH_MXC
 	select IRQ_DOMAIN
@@ -483,8 +484,6 @@
 	  If you wish to use interrupt aggregator irq resources managed by the
 	  TI System Controller, say Y here. Otherwise, say N.
 
-endmenu
-
 config SIFIVE_PLIC
 	bool "SiFive Platform-Level Interrupt Controller"
 	depends on RISCV
@@ -496,3 +495,5 @@
 	   interrupt sources are subordinate to the PLIC.
 
 	   If you don't know what to do here, say Y.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-alpine-msi.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-alpine-msi.c
@@ -165,8 +165,7 @@
 	return 0;
 
 err_sgi:
-	while (--i >= 0)
-		irq_domain_free_irqs_parent(domain, virq, i);
+	irq_domain_free_irqs_parent(domain, virq, i - 1);
 	alpine_msix_free_sgi(priv, sgi, nr_irqs);
 	return err;
 }
@@ -200,6 +199,7 @@
 	}
 
 	gic_domain = irq_find_host(gic_node);
+	of_node_put(gic_node);
 	if (!gic_domain) {
 		pr_err("Failed to find the GIC domain\n");
 		return -ENXIO;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-armada-370-xp.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-armada-370-xp.c
@@ -232,16 +232,12 @@
 	int hwirq, i;
 
 	mutex_lock(&msi_used_lock);
+	hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR,
+					order_base_2(nr_irqs));
+	mutex_unlock(&msi_used_lock);
 
-	hwirq = bitmap_find_next_zero_area(msi_used, PCI_MSI_DOORBELL_NR,
-					   0, nr_irqs, 0);
-	if (hwirq >= PCI_MSI_DOORBELL_NR) {
-		mutex_unlock(&msi_used_lock);
+	if (hwirq < 0)
 		return -ENOSPC;
-	}
-
-	bitmap_set(msi_used, hwirq, nr_irqs);
-	mutex_unlock(&msi_used_lock);
 
 	for (i = 0; i < nr_irqs; i++) {
 		irq_domain_set_info(domain, virq + i, hwirq + i,
@@ -250,7 +246,7 @@
 				    NULL, NULL);
 	}
 
-	return hwirq;
+	return 0;
 }
 
 static void armada_370_xp_msi_free(struct irq_domain *domain,
@@ -259,7 +255,7 @@
 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 
 	mutex_lock(&msi_used_lock);
-	bitmap_clear(msi_used, d->hwirq, nr_irqs);
+	bitmap_release_region(msi_used, d->hwirq, order_base_2(nr_irqs));
 	mutex_unlock(&msi_used_lock);
 }
 
@@ -396,7 +392,16 @@
 
 static void armada_xp_mpic_perf_init(void)
 {
-	unsigned long cpuid = cpu_logical_map(smp_processor_id());
+	unsigned long cpuid;
+
+	/*
+	 * This Performance Counter Overflow interrupt is specific for
+	 * Armada 370 and XP. It is not available on Armada 375, 38x and 39x.
+	 */
+	if (!of_machine_is_compatible("marvell,armada-370-xp"))
+		return;
+
+	cpuid = cpu_logical_map(smp_processor_id());
 
 	/* Enable Performance Counter Overflow interrupts */
 	writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-aspeed-i2c-ic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-aspeed-i2c-ic.c
@@ -79,8 +79,8 @@
 	}
 
 	i2c_ic->parent_irq = irq_of_parse_and_map(node, 0);
-	if (i2c_ic->parent_irq < 0) {
-		ret = i2c_ic->parent_irq;
+	if (!i2c_ic->parent_irq) {
+		ret = -EINVAL;
 		goto err_iounmap;
 	}
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-bcm6345-l1.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-bcm6345-l1.c
@@ -82,6 +82,7 @@
 };
 
 struct bcm6345_l1_cpu {
+	struct bcm6345_l1_chip	*intc;
 	void __iomem		*map_base;
 	unsigned int		parent_irq;
 	u32			enable_cache[];
@@ -115,17 +116,11 @@
 
 static void bcm6345_l1_irq_handle(struct irq_desc *desc)
 {
-	struct bcm6345_l1_chip *intc = irq_desc_get_handler_data(desc);
-	struct bcm6345_l1_cpu *cpu;
+	struct bcm6345_l1_cpu *cpu = irq_desc_get_handler_data(desc);
+	struct bcm6345_l1_chip *intc = cpu->intc;
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned int idx;
 
-#ifdef CONFIG_SMP
-	cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
-#else
-	cpu = intc->cpus[0];
-#endif
-
 	chained_irq_enter(chip, desc);
 
 	for (idx = 0; idx < intc->n_words; idx++) {
@@ -140,7 +135,7 @@
 		for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
 			irq = irq_linear_revmap(intc->domain, base + hwirq);
 			if (irq)
-				do_IRQ(irq);
+				generic_handle_irq(irq);
 			else
 				spurious_interrupt();
 		}
@@ -257,6 +252,7 @@
 	if (!cpu)
 		return -ENOMEM;
 
+	cpu->intc = intc;
 	cpu->map_base = ioremap(res.start, sz);
 	if (!cpu->map_base)
 		return -ENOMEM;
@@ -272,7 +268,7 @@
 		return -EINVAL;
 	}
 	irq_set_chained_handler_and_data(cpu->parent_irq,
-						bcm6345_l1_irq_handle, intc);
+						bcm6345_l1_irq_handle, cpu);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-bcm7038-l1.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-bcm7038-l1.c
@@ -281,6 +281,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);
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-bcm7120-l2.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-bcm7120-l2.c
@@ -268,7 +268,8 @@
 		flags |= IRQ_GC_BE_IO;
 
 	ret = irq_alloc_domain_generic_chips(data->domain, IRQS_PER_WORD, 1,
-				dn->full_name, handle_level_irq, clr, 0, flags);
+				dn->full_name, handle_level_irq, clr,
+				IRQ_LEVEL, flags);
 	if (ret) {
 		pr_err("failed to allocate generic irq chip\n");
 		goto out_free_domain;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-brcmstb-l2.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-brcmstb-l2.c
@@ -2,7 +2,7 @@
 /*
  * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
  *
- * Copyright (C) 2014-2017 Broadcom
+ * Copyright (C) 2014-2024 Broadcom
  */
 
 #define pr_fmt(fmt)	KBUILD_MODNAME	": " fmt
@@ -113,6 +113,9 @@
 		generic_handle_irq(irq_linear_revmap(b->domain, irq));
 	} while (status);
 out:
+	/* Don't ack parent before all device writes are done */
+	wmb();
+
 	chained_irq_exit(chip, desc);
 }
 
@@ -161,6 +164,7 @@
 					  *init_params)
 {
 	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+	unsigned int set = 0;
 	struct brcmstb_l2_intc_data *data;
 	struct irq_chip_type *ct;
 	int ret;
@@ -208,9 +212,12 @@
 	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
 		flags |= IRQ_GC_BE_IO;
 
+	if (init_params->handler == handle_level_irq)
+		set |= IRQ_LEVEL;
+
 	/* Allocate a single Generic IRQ chip for this node */
 	ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
-			np->full_name, init_params->handler, clr, 0, flags);
+			np->full_name, init_params->handler, clr, set, flags);
 	if (ret) {
 		pr_err("failed to allocate generic irq chip\n");
 		goto out_free_domain;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic-pm.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic-pm.c
@@ -104,7 +104,7 @@
 
 	pm_runtime_enable(dev);
 
-	ret = pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0)
 		goto rpm_disable;
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic-realview.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic-realview.c
@@ -57,6 +57,7 @@
 
 	/* The PB11MPCore GIC needs to be configured in the syscon */
 	map = syscon_node_to_regmap(np);
+	of_node_put(np);
 	if (!IS_ERR(map)) {
 		/* new irq mode with no DCC */
 		regmap_write(map, REALVIEW_SYS_LOCK_OFFSET,
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic-v3-its.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic-v3-its.c
@@ -40,7 +40,6 @@
 #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 ITS_FLAGS_SAVE_SUSPEND_STATE		(1ULL << 3)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING	(1 << 0)
 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED	(1 << 1)
@@ -571,11 +570,11 @@
 						   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);
 
-	return NULL;
+	return desc->its_invall_cmd.col;
 }
 
 static struct its_vpe *its_build_vinvall_cmd(struct its_node *its,
@@ -2581,6 +2580,7 @@
 	msi_alloc_info_t *info = args;
 	struct its_device *its_dev = info->scratchpad[0].ptr;
 	struct its_node *its = its_dev->its;
+	struct irq_data *irqd;
 	irq_hw_number_t hwirq;
 	int err;
 	int i;
@@ -2600,7 +2600,9 @@
 
 		irq_domain_set_hwirq_and_chip(domain, virq + i,
 					      hwirq + i, &its_irq_chip, its_dev);
-		irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i)));
+		irqd = irq_get_irq_data(virq + i);
+		irqd_set_single_target(irqd);
+		irqd_set_affinity_on_activate(irqd);
 		pr_debug("ID:%d pID:%d vID:%d\n",
 			 (int)(hwirq + i - its_dev->event_map.lpi_base),
 			 (int)(hwirq + i), virq + i);
@@ -2985,12 +2987,18 @@
 	return 0;
 }
 
+static int its_vpe_retrigger(struct irq_data *d)
+{
+	return !its_vpe_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true);
+}
+
 static struct irq_chip its_vpe_irq_chip = {
 	.name			= "GICv4-vpe",
 	.irq_mask		= its_vpe_mask_irq,
 	.irq_unmask		= its_vpe_unmask_irq,
 	.irq_eoi		= irq_chip_eoi_parent,
 	.irq_set_affinity	= its_vpe_set_affinity,
+	.irq_retrigger		= its_vpe_retrigger,
 	.irq_set_irqchip_state	= its_vpe_set_irqchip_state,
 	.irq_set_vcpu_affinity	= its_vpe_set_vcpu_affinity,
 };
@@ -3115,7 +3123,7 @@
 
 	if (err) {
 		if (i > 0)
-			its_vpe_irq_domain_free(domain, virq, i - 1);
+			its_vpe_irq_domain_free(domain, virq, i);
 
 		its_lpi_free(bitmap, base, nr_ids);
 		its_free_prop_table(vprop_page);
@@ -3358,9 +3366,6 @@
 	list_for_each_entry(its, &its_nodes, entry) {
 		void __iomem *base;
 
-		if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-			continue;
-
 		base = its->base;
 		its->ctlr_save = readl_relaxed(base + GITS_CTLR);
 		err = its_force_quiescent(base);
@@ -3379,9 +3384,6 @@
 		list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
 			void __iomem *base;
 
-			if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-				continue;
-
 			base = its->base;
 			writel_relaxed(its->ctlr_save, base + GITS_CTLR);
 		}
@@ -3401,9 +3403,6 @@
 		void __iomem *base;
 		int i;
 
-		if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-			continue;
-
 		base = its->base;
 
 		/*
@@ -3411,7 +3410,10 @@
 		 * don't restore it since writing to CBASER or BASER<n>
 		 * registers is undefined according to the GIC v3 ITS
 		 * Specification.
+		 *
+		 * Firmware resuming with the ITS enabled is terminally broken.
 		 */
+		WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE);
 		ret = its_force_quiescent(base);
 		if (ret) {
 			pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
@@ -3678,9 +3680,6 @@
 		ctlr |= GITS_CTLR_ImDe;
 	writel_relaxed(ctlr, its->base + GITS_CTLR);
 
-	if (GITS_TYPER_HCC(typer))
-		its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
-
 	err = its_init_domain(handle, its);
 	if (err)
 		goto out_free_tables;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic-v3-mbi.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic-v3-mbi.c
@@ -303,7 +303,7 @@
 	reg = of_get_property(np, "mbi-alias", NULL);
 	if (reg) {
 		mbi_phys_base = of_translate_address(np, reg);
-		if (mbi_phys_base == OF_BAD_ADDR) {
+		if (mbi_phys_base == (phys_addr_t)OF_BAD_ADDR) {
 			ret = -ENXIO;
 			goto err_free_mbi;
 		}
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic-v3.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic-v3.c
@@ -162,11 +162,11 @@
 	}
 }
 
-static void gic_do_wait_for_rwp(void __iomem *base)
+static void gic_do_wait_for_rwp(void __iomem *base, u32 bit)
 {
 	u32 count = 1000000;	/* 1s! */
 
-	while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) {
+	while (readl_relaxed(base + GICD_CTLR) & bit) {
 		count--;
 		if (!count) {
 			pr_err_ratelimited("RWP timeout, gone fishing\n");
@@ -180,13 +180,13 @@
 /* Wait for completion of a distributor change */
 static void gic_dist_wait_for_rwp(void)
 {
-	gic_do_wait_for_rwp(gic_data.dist_base);
+	gic_do_wait_for_rwp(gic_data.dist_base, GICD_CTLR_RWP);
 }
 
 /* Wait for completion of a redistributor change */
 static void gic_redist_wait_for_rwp(void)
 {
-	gic_do_wait_for_rwp(gic_data_rdist_rd_base());
+	gic_do_wait_for_rwp(gic_data_rdist_rd_base(), GICR_CTLR_RWP);
 }
 
 #ifdef CONFIG_ARM64
@@ -621,6 +621,10 @@
 
 	irqnr = gic_read_iar();
 
+	/* Check for special IDs first */
+	if ((irqnr >= 1020 && irqnr <= 1023))
+		return;
+
 	if (gic_supports_nmi() &&
 	    unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) {
 		gic_handle_nmi(irqnr, regs);
@@ -632,10 +636,6 @@
 		gic_arch_enable_irqs();
 	}
 
-	/* Check for special IDs first */
-	if ((irqnr >= 1020 && irqnr <= 1023))
-		return;
-
 	/* Treat anything but SGIs in a uniform way */
 	if (likely(irqnr > 15)) {
 		int err;
@@ -1616,7 +1616,7 @@
 
 	gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
 	if (!gic_data.ppi_descs)
-		return;
+		goto out_put_node;
 
 	nr_parts = of_get_child_count(parts_node);
 
@@ -1657,12 +1657,15 @@
 				continue;
 
 			cpu = of_cpu_node_to_id(cpu_node);
-			if (WARN_ON(cpu < 0))
+			if (WARN_ON(cpu < 0)) {
+				of_node_put(cpu_node);
 				continue;
+			}
 
 			pr_cont("%pOF[%d] ", cpu_node, cpu);
 
 			cpumask_set_cpu(cpu, &part->mask);
+			of_node_put(cpu_node);
 		}
 
 		pr_cont("}\n");
@@ -1801,6 +1804,7 @@
 	struct redist_region *redist_regs;
 	u32 nr_redist_regions;
 	bool single_redist;
+	int enabled_rdists;
 	u32 maint_irq;
 	int maint_irq_mode;
 	phys_addr_t vcpu_base;
@@ -1895,8 +1899,10 @@
 	 * If GICC is enabled and has valid gicr base address, then it means
 	 * GICR base is presented via GICC
 	 */
-	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
+	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) {
+		acpi_data.enabled_rdists++;
 		return 0;
+	}
 
 	/*
 	 * It's perfectly valid firmware can pass disabled GICC entry, driver
@@ -1926,8 +1932,10 @@
 
 	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
 				      gic_acpi_match_gicc, 0);
-	if (count > 0)
+	if (count > 0) {
 		acpi_data.single_redist = true;
+		count = acpi_data.enabled_rdists;
+	}
 
 	return count;
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-gic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-gic.c
@@ -86,6 +86,8 @@
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+	u32 exclude_irq_count;
+	u32 *exclude_irq;
 };
 
 #ifdef CONFIG_BL_SWITCHER
@@ -329,10 +331,8 @@
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 			    bool force)
 {
-	void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
-	unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
-	u32 val, mask, bit;
-	unsigned long flags;
+	void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d);
+	unsigned int cpu;
 
 	if (!force)
 		cpu = cpumask_any_and(mask_val, cpu_online_mask);
@@ -342,13 +342,7 @@
 	if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
 		return -EINVAL;
 
-	gic_lock_irqsave(flags);
-	mask = 0xff << shift;
-	bit = gic_cpu_map[cpu] << shift;
-	val = readl_relaxed(reg) & ~mask;
-	writel_relaxed(val | bit, reg);
-	gic_unlock_irqrestore(flags);
-
+	writeb_relaxed(gic_cpu_map[cpu], reg);
 	irq_data_update_effective_affinity(d, cpumask_of(cpu));
 
 	return IRQ_SET_MASK_OK_DONE;
@@ -488,6 +482,129 @@
 }
 
 
+static int gic_dist_init_with_irq_exclude(struct gic_chip_data *gic)
+{
+	int ret;
+	unsigned int i;
+	u32 cpumask;
+	unsigned int gic_irqs = gic->gic_irqs;
+	void __iomem *base = gic_data_dist_base(gic);
+	u32 field, intNum;
+	unsigned int *mask_array = NULL;
+	u32 *priority_array = NULL;
+	u32 tmp;
+
+	/*
+	 * Set all global interrupts to this CPU only.
+	 */
+	cpumask = gic_get_cpumask(gic);
+	cpumask |= cpumask << 8;
+	cpumask |= cpumask << 16;
+
+	mask_array = kcalloc(((gic_irqs + 32 + 3) / 4), sizeof(*mask_array),
+			GFP_KERNEL);
+	if (mask_array == NULL)	{
+		ret = -ENOMEM;
+		goto free_exclude_irq;
+	}
+
+	for (i = 32; i < gic_irqs; i += 4)
+		mask_array[i / 4] = cpumask;
+
+	for (i = 0; i < gic->exclude_irq_count; i++) {
+		tmp = mask_array[gic->exclude_irq[i] / 4];
+		tmp &= ~(0xFF << (8 * (gic->exclude_irq[i] % 4)));
+		tmp |=  (0x02 << (8 * (gic->exclude_irq[i] % 4)));
+		mask_array[gic->exclude_irq[i] / 4] = tmp;
+	}
+
+	for (i = 32; i < gic_irqs; i += 4)
+		writel_relaxed(mask_array[i / 4],
+			base + GIC_DIST_TARGET + i / 4 * 4);
+
+	kfree(mask_array);
+	mask_array = NULL;
+
+	/*
+	 * Set all global interrupts to be level triggered, active low.
+	 */
+	for (i = 32; i < gic_irqs; i += 16)
+		writel_relaxed(GICD_INT_ACTLOW_LVLTRIG,
+				       base + GIC_DIST_CONFIG + i / 4);
+
+	priority_array = kcalloc(gic->exclude_irq_count,
+				sizeof(*priority_array), GFP_KERNEL);
+	if (priority_array == NULL)	{
+		ret = -ENOMEM;
+		goto free_exclude_irq;
+	}
+
+	/* There are 4 8-bit fields per 32 bit register, extract the priority
+	 * for each excluded interrupt
+	 */
+	for (i = 0; i < gic->exclude_irq_count; i++) {
+		intNum = gic->exclude_irq[i];
+		field = (gic->exclude_irq[i] % 4) * 8;
+		priority_array[i] = (readl_relaxed(base + GIC_DIST_PRI +
+					intNum / 4 * 4) >> field) & 0xFF;
+		pr_info("GIC: before 0x%X\n", priority_array[i]);
+	}
+
+	/*
+	 * Clear the Priorities
+	 */
+	for (i = 32; i < gic_irqs; i += 4)
+		writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
+
+	/* Restore the Priorities */
+	for (i = 0; i < gic->exclude_irq_count; i++) {
+		intNum = gic->exclude_irq[i];
+		field = (gic->exclude_irq[i] % 4) * 8;
+		tmp = readl_relaxed(base + GIC_DIST_PRI + intNum / 4 * 4);
+		tmp &= ~(0xFF << field);
+		tmp |= (priority_array[i] << field);
+		writel_relaxed(tmp, base + GIC_DIST_PRI + intNum / 4 * 4);
+		pr_info("GIC: int:%d Field %d, after 0x%X\n", intNum,
+			field, tmp);
+	}
+
+	kfree(priority_array);
+	priority_array = NULL;
+
+	/*
+	 * Deactivate and disable all SPIs. Leave the PPI and SGIs
+	 * alone as they are in the redistributor registers on GICv3.
+	 */
+	for (i = 32; i < gic_irqs; i += 32) {
+		writel_relaxed(GICD_INT_EN_CLR_X32,
+			      base + GIC_DIST_ACTIVE_CLEAR + i / 8);
+		writel_relaxed(GICD_INT_EN_CLR_X32,
+			      base + GIC_DIST_ENABLE_CLEAR + i / 8);
+	}
+
+	/* Re-Enable all excluded Interrupts */
+	for (i = 0; i < gic->exclude_irq_count; i++) {
+		tmp = readl_relaxed(base + GIC_DIST_ENABLE_SET +
+				(gic->exclude_irq[i] / 32) * sizeof(u32));
+		tmp |= (0x1 << (gic->exclude_irq[i] % 32));
+
+		/* Enables the CSI interrupt to undo being overwritten in the
+		 * gic_dist_config
+		 */
+		writel_relaxed(tmp, base + GIC_DIST_ENABLE_SET +
+			(gic->exclude_irq[i] / 32) * 4);
+	}
+
+	ret = 0;
+
+free_exclude_irq:
+	kfree(gic->exclude_irq);
+	gic->exclude_irq = NULL;
+
+	return ret;
+}
+
+
 static void gic_dist_init(struct gic_chip_data *gic)
 {
 	unsigned int i;
@@ -497,6 +614,15 @@
 
 	writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL);
 
+	if ((gic->exclude_irq_count) > 0 && (gic->exclude_irq != NULL))	{
+		int ret;
+
+		ret = gic_dist_init_with_irq_exclude(gic);
+		if (!ret)
+			goto gic_dist_init_exit;
+		pr_err("GIC: Excluding interrupts failed (%d)\n", ret);
+	}
+
 	/*
 	 * Set all global interrupts to this CPU only.
 	 */
@@ -508,6 +634,7 @@
 
 	gic_dist_config(base, gic_irqs, NULL);
 
+gic_dist_init_exit:
 	writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
 }
 
@@ -1355,6 +1482,28 @@
 	if (!gic || !node)
 		return -EINVAL;
 
+	gic->exclude_irq_count = 0;
+	gic->exclude_irq = NULL;
+	if (of_find_property(node, "exclude-int", &gic->exclude_irq_count)) {
+		gic->exclude_irq_count = gic->exclude_irq_count / sizeof(u32);
+		gic->exclude_irq = kcalloc(gic->exclude_irq_count,
+			sizeof(*(gic->exclude_irq)), GFP_KERNEL);
+
+		if ((gic->exclude_irq == NULL) ||
+		    of_property_read_u32_array(node, "exclude-int",
+				gic->exclude_irq, gic->exclude_irq_count)) {
+			gic->exclude_irq_count = 0;
+		} else {
+			int i;
+
+			pr_info("GIC: Excluding interrupts:");
+			for (i = 0; i < gic->exclude_irq_count; i++) {
+				pr_info(KERN_CONT " %d", gic->exclude_irq[i]);
+				gic->exclude_irq[i] += 32;
+			}
+		}
+	}
+
 	gic->raw_dist_base = of_iomap(node, 0);
 	if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
 		goto error;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-imx-gpcv2.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-imx-gpcv2.c
@@ -3,11 +3,25 @@
  * Copyright (C) 2015 Freescale Semiconductor, Inc.
  */
 
+#include <linux/arm-smccc.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/irqchip.h>
 #include <linux/syscore_ops.h>
+#include <linux/smp.h>
+#include <linux/cpuidle.h>
+
+#define FSL_SIP_GPC                     0xC2000000
+#define FSL_SIP_CONFIG_GPC_MASK         0x00
+#define FSL_SIP_CONFIG_GPC_UNMASK       0x01
+#define FSL_SIP_CONFIG_GPC_SET_WAKE     0x02
+#define FSL_SIP_CONFIG_GPC_PM_DOMAIN    0x03
+#define FSL_SIP_CONFIG_GPC_SET_AFF      0x04
+#define FSL_SIP_CONFIG_GPC_CORE_WAKE    0x05
 
 #define IMR_NUM			4
 #define GPC_MAX_IRQS            (IMR_NUM * 32)
@@ -17,6 +31,7 @@
 #define GPC_IMR1_CORE2		0x1c0
 #define GPC_IMR1_CORE3		0x1d0
 
+static unsigned int err11171;
 
 struct gpcv2_irqchip_data {
 	struct raw_spinlock	rlock;
@@ -70,9 +85,61 @@
 	.resume		= gpcv2_wakeup_source_restore,
 };
 
+#ifdef CONFIG_ARM64
+static void (*__gic_v3_smp_cross_call)(const struct cpumask *, unsigned int);
+#endif
+
+#ifdef CONFIG_SMP
+static void imx_gpcv2_raise_softirq(const struct cpumask *mask,
+					  unsigned int irq)
+{
+	struct arm_smccc_res res;
+
+#ifdef CONFIG_ARM64
+	/* call the hijacked smp cross call handler */
+	__gic_v3_smp_cross_call(mask, irq);
+#endif
+
+	/* now call into EL3 and take care of the wakeup */
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_CORE_WAKE,
+			*cpumask_bits(mask), 0, 0, 0, 0, 0, &res);
+}
+#endif
+
+static void imx_gpcv2_wake_request_fixup(void)
+{
+	struct regmap *iomux_gpr;
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_CORE_WAKE,
+			0, 0, 0, 0, 0, 0, &res);
+
+	if (res.a0) {
+		pr_warn("irq-imx-gpcv2: EL3 does not support FSL_SIP_CONFIG_GPC_CORE_WAKE, disabling cpuidle.\n");
+		disable_cpuidle();
+		return;
+	}
+
+#ifdef CONFIG_ARM64
+	/* hijack the already registered smp cross call handler */
+	__gic_v3_smp_cross_call = __smp_cross_call;
+#endif
+
+#ifdef CONFIG_SMP
+	/* register our workaround handler for smp cross call */
+	set_smp_cross_call(imx_gpcv2_raise_softirq);
+#endif
+
+	iomux_gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+	if (!IS_ERR(iomux_gpr))
+		regmap_update_bits(iomux_gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT,
+					IMX6Q_GPR1_GINT);
+}
+
 static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct gpcv2_irqchip_data *cd = d->chip_data;
+	struct arm_smccc_res res;
 	unsigned int idx = d->hwirq / 32;
 	unsigned long flags;
 	u32 mask, val;
@@ -82,8 +149,29 @@
 	val = cd->wakeup_sources[idx];
 
 	cd->wakeup_sources[idx] = on ? (val & ~mask) : (val | mask);
+
+#ifdef CONFIG_ARM64
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_SET_WAKE,
+			d->hwirq, on, 0, 0, 0, 0, &res);
+#endif
 	raw_spin_unlock_irqrestore(&cd->rlock, flags);
 
+
+	/*
+	 * Do *not* call into the parent, as the GIC doesn't have any
+	 * wake-up facility...
+	 */
+
+	return 0;
+}
+
+static int imx8mq_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_SET_WAKE,
+		d->hwirq, on, 0, 0, 0, 0, &res);
+
 	/*
 	 * Do *not* call into the parent, as the GIC doesn't have any
 	 * wake-up facility...
@@ -108,6 +196,16 @@
 	irq_chip_unmask_parent(d);
 }
 
+static void imx8mq_gpcv2_irq_unmask(struct irq_data *d)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_UNMASK,
+		d->hwirq, 0, 0, 0, 0, 0, &res);
+
+	irq_chip_unmask_parent(d);
+}
+
 static void imx_gpcv2_irq_mask(struct irq_data *d)
 {
 	struct gpcv2_irqchip_data *cd = d->chip_data;
@@ -124,6 +222,41 @@
 	irq_chip_mask_parent(d);
 }
 
+static void imx8mq_gpcv2_irq_mask(struct irq_data *d)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_MASK,
+		d->hwirq, 0, 0, 0, 0, 0, &res);
+
+	irq_chip_mask_parent(d);
+}
+
+int imx8mq_gpcv2_irq_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
+		      bool force)
+{
+	struct arm_smccc_res res;
+	int cpu = cpumask_any_and(cpumask, cpu_online_mask);
+
+	arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_SET_AFF,
+		d->hwirq, cpu, 0, 0, 0, 0, &res);
+
+	return irq_chip_set_affinity_parent(d, cpumask, force);
+}
+
+static struct irq_chip gpcv2_imx8mq_irqchip_data_chip = {
+	.name			= "GPCv2 i.MX8MQ",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_mask		= imx8mq_gpcv2_irq_mask,
+	.irq_unmask		= imx8mq_gpcv2_irq_unmask,
+	.irq_set_wake		= imx8mq_gpcv2_irq_set_wake,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= irq_chip_set_type_parent,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= imx8mq_gpcv2_irq_set_affinity,
+#endif
+};
+
 static struct irq_chip gpcv2_irqchip_data_chip = {
 	.name			= "GPCv2",
 	.irq_eoi		= irq_chip_eoi_parent,
@@ -178,6 +311,7 @@
 
 	for (i = 0; i < nr_irqs; i++) {
 		irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+				err11171 ? &gpcv2_imx8mq_irqchip_data_chip :
 				&gpcv2_irqchip_data_chip, domain->host_data);
 	}
 
@@ -251,34 +385,43 @@
 	}
 	irq_set_default_host(domain);
 
-	/* Initially mask all interrupts */
-	for (i = 0; i < IMR_NUM; i++) {
-		void __iomem *reg = cd->gpc_base + i * 4;
-
-		switch (core_num) {
-		case 4:
-			writel_relaxed(~0, reg + GPC_IMR1_CORE2);
-			writel_relaxed(~0, reg + GPC_IMR1_CORE3);
-			/* fall through */
-		case 2:
-			writel_relaxed(~0, reg + GPC_IMR1_CORE0);
-			writel_relaxed(~0, reg + GPC_IMR1_CORE1);
+	if (of_machine_is_compatible("fsl,imx8mq")) {
+		/* sw workaround for IPI can't wakeup CORE
+		ERRATA(ERR011171) on i.MX8MQ */
+		err11171 = true;
+		imx_gpcv2_wake_request_fixup();
+	} else {
+		/* Initially mask all interrupts */
+		for (i = 0; i < IMR_NUM; i++) {
+			void __iomem *reg = cd->gpc_base + i * 4;
+
+			switch (core_num) {
+			case 4:
+				writel_relaxed(~0, reg + GPC_IMR1_CORE2);
+				writel_relaxed(~0, reg + GPC_IMR1_CORE3);
+				/* fall through */
+			case 2:
+				writel_relaxed(~0, reg + GPC_IMR1_CORE0);
+				writel_relaxed(~0, reg + GPC_IMR1_CORE1);
+			}
+			cd->wakeup_sources[i] = ~0;
 		}
-		cd->wakeup_sources[i] = ~0;
-	}
 
-	/* Let CORE0 as the default CPU to wake up by GPC */
-	cd->cpu2wakeup = GPC_IMR1_CORE0;
+		/* Let CORE0 as the default CPU to wake up by GPC */
+		cd->cpu2wakeup = GPC_IMR1_CORE0;
 
-	/*
-	 * Due to hardware design failure, need to make sure GPR
-	 * interrupt(#32) is unmasked during RUN mode to avoid entering
-	 * DSM by mistake.
-	 */
-	writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
+		/*
+		 * Due to hardware design failure, need to make sure GPR
+		 * interrupt(#32) is unmasked during RUN mode to avoid entering
+		 * DSM by mistake.
+		 */
+		writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
+	}
 
 	imx_gpcv2_instance = cd;
-	register_syscore_ops(&imx_gpcv2_syscore_ops);
+
+	if (!err11171)
+		register_syscore_ops(&imx_gpcv2_syscore_ops);
 
 	/*
 	 * Clear the OF_POPULATED flag set in of_irq_init so that
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-imx-irqsteer.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-imx-irqsteer.c
@@ -10,9 +10,13 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/spinlock.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
 
 #define CTRL_STRIDE_OFF(_t, _r)	(_t * 4 * _r)
 #define CHANCTRL		0x0
@@ -25,6 +29,7 @@
 #define CHAN_MAX_OUTPUT_INT	0x8
 
 struct irqsteer_data {
+	struct irq_chip		chip;
 	void __iomem		*regs;
 	struct clk		*ipg_clk;
 	int			irq[CHAN_MAX_OUTPUT_INT];
@@ -34,6 +39,11 @@
 	int			channel;
 	struct irq_domain	*domain;
 	u32			*saved_reg;
+	bool			inited;
+
+	struct device		*dev;
+	struct device		*pd_csi;
+	struct device		*pd_isi;
 };
 
 static int imx_irqsteer_get_reg_index(struct irqsteer_data *data,
@@ -42,6 +52,44 @@
 	return (data->reg_num - irqnum / 32 - 1);
 }
 
+static int imx_irqsteer_attach_pd(struct irqsteer_data *data)
+{
+	struct device *dev = data->dev;
+	struct device_link *link;
+
+	data->pd_csi = dev_pm_domain_attach_by_name(dev, "pd_csi");
+	if (IS_ERR(data->pd_csi )) {
+		if (PTR_ERR(data->pd_csi) != -EPROBE_DEFER)
+			return PTR_ERR(data->pd_csi);
+		else
+			return PTR_ERR(data->pd_csi);
+	} else if (!data->pd_csi) {
+		return 0;
+	}
+	link = device_link_add(dev, data->pd_csi,
+			DL_FLAG_STATELESS |
+			DL_FLAG_PM_RUNTIME);
+	if (IS_ERR(link))
+		return PTR_ERR(link);
+
+	data->pd_isi = dev_pm_domain_attach_by_name(dev, "pd_isi_ch0");
+	if (IS_ERR(data->pd_isi)) {
+		if (PTR_ERR(data->pd_isi) != -EPROBE_DEFER)
+			return PTR_ERR(data->pd_isi);
+		else
+			return PTR_ERR(data->pd_isi);
+	} else if (!data->pd_isi) {
+		return 0;
+	}
+	link = device_link_add(dev, data->pd_isi,
+			DL_FLAG_STATELESS |
+			DL_FLAG_PM_RUNTIME);
+	if (IS_ERR(link))
+		return PTR_ERR(link);
+
+	return 0;
+}
+
 static void imx_irqsteer_irq_unmask(struct irq_data *d)
 {
 	struct irqsteer_data *data = d->chip_data;
@@ -79,9 +127,11 @@
 static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq,
 				irq_hw_number_t hwirq)
 {
+	struct irqsteer_data *irqsteer_data = h->host_data;
+
 	irq_set_status_flags(irq, IRQ_LEVEL);
 	irq_set_chip_data(irq, h->host_data);
-	irq_set_chip_and_handler(irq, &imx_irqsteer_irq_chip, handle_level_irq);
+	irq_set_chip_and_handler(irq, &irqsteer_data->chip, handle_level_irq);
 
 	return 0;
 }
@@ -140,6 +190,33 @@
 	chained_irq_exit(irq_desc_get_chip(desc), desc);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int imx_irqsteer_chans_enable(struct irqsteer_data *data)
+{
+	return 0;
+}
+#else
+static int imx_irqsteer_chans_enable(struct irqsteer_data *data)
+{
+	int ret;
+
+	ret = clk_prepare_enable(data->ipg_clk);
+	if (ret) {
+		dev_err(data->dev, "failed to enable ipg clk: %d\n", ret);
+		return ret;
+	}
+
+	/* steer all IRQs into configured channel */
+	writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
+
+	/* read back CHANCTRL register cannot reflact on HW register
+	 * real value due to the HW action, so add one flag here.
+	 */
+	data->inited = true;
+	return 0;
+}
+#endif
+
 static int imx_irqsteer_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -151,6 +228,10 @@
 	if (!data)
 		return -ENOMEM;
 
+	data->chip = imx_irqsteer_irq_chip;
+	data->chip.parent_device = &pdev->dev;
+	data->dev = &pdev->dev;
+	data->inited = false;
 	data->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(data->regs)) {
 		dev_err(&pdev->dev, "failed to initialize reg\n");
@@ -165,6 +246,14 @@
 		return ret;
 	}
 
+	ret = imx_irqsteer_attach_pd(data);
+	if (ret < 0 && ret == -EPROBE_DEFER)
+		return ret;
+
+	ret = device_reset(&pdev->dev);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+
 	raw_spin_lock_init(&data->lock);
 
 	ret = of_property_read_u32(np, "fsl,num-irqs", &irqs_num);
@@ -189,14 +278,9 @@
 			return -ENOMEM;
 	}
 
-	ret = clk_prepare_enable(data->ipg_clk);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret);
+	ret = imx_irqsteer_chans_enable(data);
+	if (ret)
 		return ret;
-	}
-
-	/* steer all IRQs into configured channel */
-	writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
 
 	data->domain = irq_domain_add_linear(np, data->reg_num * 32,
 					     &imx_irqsteer_domain_ops, data);
@@ -225,6 +309,7 @@
 
 	platform_set_drvdata(pdev, data);
 
+	pm_runtime_enable(&pdev->dev);
 	return 0;
 out:
 	clk_disable_unprepare(data->ipg_clk);
@@ -242,12 +327,21 @@
 
 	irq_domain_remove(irqsteer_data->domain);
 
-	clk_disable_unprepare(irqsteer_data->ipg_clk);
-
-	return 0;
+	return pm_runtime_force_suspend(&pdev->dev);
 }
 
 #ifdef CONFIG_PM_SLEEP
+static void imx_irqsteer_init(struct irqsteer_data *data)
+{
+	/* steer all IRQs into configured channel */
+	writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
+
+	/* read back CHANCTRL register cannot reflact on HW register
+	 * real value due to the HW action, so add one flag here.
+	 */
+	data->inited = true;
+}
+
 static void imx_irqsteer_save_regs(struct irqsteer_data *data)
 {
 	int i;
@@ -267,7 +361,7 @@
 			       data->regs + CHANMASK(i, data->reg_num));
 }
 
-static int imx_irqsteer_suspend(struct device *dev)
+static int imx_irqsteer_runtime_suspend(struct device *dev)
 {
 	struct irqsteer_data *irqsteer_data = dev_get_drvdata(dev);
 
@@ -277,7 +371,7 @@
 	return 0;
 }
 
-static int imx_irqsteer_resume(struct device *dev)
+static int imx_irqsteer_runtime_resume(struct device *dev)
 {
 	struct irqsteer_data *irqsteer_data = dev_get_drvdata(dev);
 	int ret;
@@ -287,20 +381,29 @@
 		dev_err(dev, "failed to enable ipg clk: %d\n", ret);
 		return ret;
 	}
-	imx_irqsteer_restore_regs(irqsteer_data);
+
+	/* don't need restore registers when first sub_irq requested */
+	if (!irqsteer_data->inited)
+		imx_irqsteer_init(irqsteer_data);
+	else
+		imx_irqsteer_restore_regs(irqsteer_data);
 
 	return 0;
 }
 #endif
 
 static const struct dev_pm_ops imx_irqsteer_pm_ops = {
-	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_irqsteer_suspend, imx_irqsteer_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				      pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(imx_irqsteer_runtime_suspend,
+			   imx_irqsteer_runtime_resume, NULL)
 };
 
 static const struct of_device_id imx_irqsteer_dt_ids[] = {
 	{ .compatible = "fsl,imx-irqsteer", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, imx_irqsteer_dt_ids);
 
 static struct platform_driver imx_irqsteer_driver = {
 	.driver = {
@@ -311,4 +414,5 @@
 	.probe = imx_irqsteer_probe,
 	.remove = imx_irqsteer_remove,
 };
-builtin_platform_driver(imx_irqsteer_driver);
+module_platform_driver(imx_irqsteer_driver);
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-ingenic-tcu.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-ingenic-tcu.c
@@ -179,4 +179,5 @@
 }
 IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init);
+IRQCHIP_DECLARE(jz4760_tcu_irq, "ingenic,jz4760-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init);
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-ingenic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-ingenic.c
@@ -108,6 +108,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) +
@@ -134,14 +142,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:
@@ -163,6 +168,7 @@
 {
 	return ingenic_intc_of_init(node, 2);
 }
+IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-jcore-aic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-jcore-aic.c
@@ -68,6 +68,7 @@
 	unsigned min_irq = JCORE_AIC2_MIN_HWIRQ;
 	unsigned dom_sz = JCORE_AIC_MAX_HWIRQ+1;
 	struct irq_domain *domain;
+	int ret;
 
 	pr_info("Initializing J-Core AIC\n");
 
@@ -100,11 +101,17 @@
 	jcore_aic.irq_unmask = noop;
 	jcore_aic.name = "AIC";
 
-	domain = irq_domain_add_linear(node, dom_sz, &jcore_aic_irqdomain_ops,
+	ret = irq_alloc_descs(-1, min_irq, dom_sz - min_irq,
+			      of_node_to_nid(node));
+
+	if (ret < 0)
+		return ret;
+
+	domain = irq_domain_add_legacy(node, dom_sz - min_irq, min_irq, min_irq,
+				       &jcore_aic_irqdomain_ops,
 				       &jcore_aic);
 	if (!domain)
 		return -ENOMEM;
-	irq_create_strict_mappings(domain, min_irq, min_irq, dom_sz - min_irq);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-mbigen.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-mbigen.c
@@ -220,10 +220,16 @@
 	return 0;
 }
 
+static void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+				   unsigned int nr_irqs)
+{
+	platform_msi_domain_free(domain, virq, nr_irqs);
+}
+
 static const struct irq_domain_ops mbigen_domain_ops = {
 	.translate	= mbigen_domain_translate,
 	.alloc		= mbigen_irq_domain_alloc,
-	.free		= irq_domain_free_irqs_common,
+	.free		= mbigen_irq_domain_free,
 };
 
 static int mbigen_of_create_domain(struct platform_device *pdev,
@@ -374,6 +380,7 @@
 		.name		= "Hisilicon MBIGEN-V2",
 		.of_match_table	= mbigen_of_match,
 		.acpi_match_table = ACPI_PTR(mbigen_acpi_match),
+		.suppress_bind_attrs = true,
 	},
 	.probe			= mbigen_device_probe,
 };
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-meson-gpio.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-meson-gpio.c
@@ -70,7 +70,7 @@
 	.support_edge_both = true,
 };
 
-static const struct of_device_id meson_irq_gpio_matches[] = {
+static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
 	{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
 	{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
 	{ .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-mips-cpu.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-mips-cpu.c
@@ -197,6 +197,13 @@
 		if (ret)
 			return ret;
 
+		ret = irq_domain_set_hwirq_and_chip(domain->parent, virq + i, hwirq,
+						    &mips_mt_cpu_irq_controller,
+						    NULL);
+
+		if (ret)
+			return ret;
+
 		ret = irq_set_irq_type(virq + i, IRQ_TYPE_LEVEL_HIGH);
 		if (ret)
 			return ret;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-mips-gic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-mips-gic.c
@@ -48,7 +48,7 @@
 
 DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks);
 
-static DEFINE_SPINLOCK(gic_lock);
+static DEFINE_RAW_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
 static struct irq_domain *gic_ipi_domain;
 static int gic_shared_intrs;
@@ -207,7 +207,7 @@
 
 	irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 	switch (type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_FALLING:
 		pol = GIC_POL_FALLING_EDGE;
@@ -247,7 +247,7 @@
 	else
 		irq_set_chip_handler_name_locked(d, &gic_level_irq_controller,
 						 handle_level_irq, NULL);
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 
 	return 0;
 }
@@ -265,7 +265,7 @@
 		return -EINVAL;
 
 	/* Assumption : cpumask refers to a single CPU */
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 
 	/* Re-route this IRQ */
 	write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
@@ -276,7 +276,7 @@
 		set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
 
 	irq_data_update_effective_affinity(d, cpumask_of(cpu));
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 
 	return IRQ_SET_MASK_OK;
 }
@@ -354,12 +354,12 @@
 	cd = irq_data_get_irq_chip_data(d);
 	cd->mask = false;
 
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 	for_each_online_cpu(cpu) {
 		write_gic_vl_other(mips_cm_vp_id(cpu));
 		write_gic_vo_rmask(BIT(intr));
 	}
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 }
 
 static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
@@ -372,32 +372,45 @@
 	cd = irq_data_get_irq_chip_data(d);
 	cd->mask = true;
 
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 	for_each_online_cpu(cpu) {
 		write_gic_vl_other(mips_cm_vp_id(cpu));
 		write_gic_vo_smask(BIT(intr));
 	}
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 }
 
-static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
+static void gic_all_vpes_irq_cpu_online(void)
 {
-	struct gic_all_vpes_chip_data *cd;
-	unsigned int intr;
+	static const unsigned int local_intrs[] = {
+		GIC_LOCAL_INT_TIMER,
+		GIC_LOCAL_INT_PERFCTR,
+		GIC_LOCAL_INT_FDC,
+	};
+	unsigned long flags;
+	int i;
 
-	intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
-	cd = irq_data_get_irq_chip_data(d);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 
-	write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
-	if (cd->mask)
-		write_gic_vl_smask(BIT(intr));
+	for (i = 0; i < ARRAY_SIZE(local_intrs); i++) {
+		unsigned int intr = local_intrs[i];
+		struct gic_all_vpes_chip_data *cd;
+
+		if (!gic_local_irq_is_routable(intr))
+			continue;
+		cd = &gic_all_vpes_chip_data[intr];
+		write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
+		if (cd->mask)
+			write_gic_vl_smask(BIT(intr));
+	}
+
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 }
 
 static struct irq_chip gic_all_vpes_local_irq_controller = {
 	.name			= "MIPS GIC Local",
 	.irq_mask		= gic_mask_local_irq_all_vpes,
 	.irq_unmask		= gic_unmask_local_irq_all_vpes,
-	.irq_cpu_online		= gic_all_vpes_irq_cpu_online,
 };
 
 static void __gic_irq_dispatch(void)
@@ -421,11 +434,11 @@
 
 	data = irq_get_irq_data(virq);
 
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 	write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
 	write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
 	irq_data_update_effective_affinity(data, cpumask_of(cpu));
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 
 	return 0;
 }
@@ -476,6 +489,10 @@
 	intr = GIC_HWIRQ_TO_LOCAL(hwirq);
 	map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
 
+	/*
+	 * If adding support for more per-cpu interrupts, keep the the
+	 * array in gic_all_vpes_irq_cpu_online() in sync.
+	 */
 	switch (intr) {
 	case GIC_LOCAL_INT_TIMER:
 		/* CONFIG_MIPS_CMP workaround (see __gic_init) */
@@ -514,12 +531,12 @@
 	if (!gic_local_irq_is_routable(intr))
 		return -EPERM;
 
-	spin_lock_irqsave(&gic_lock, flags);
+	raw_spin_lock_irqsave(&gic_lock, flags);
 	for_each_online_cpu(cpu) {
 		write_gic_vl_other(mips_cm_vp_id(cpu));
 		write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
 	}
-	spin_unlock_irqrestore(&gic_lock, flags);
+	raw_spin_unlock_irqrestore(&gic_lock, flags);
 
 	return 0;
 }
@@ -662,8 +679,8 @@
 	/* Clear all local IRQ masks (ie. disable all local interrupts) */
 	write_gic_vl_rmask(~0);
 
-	/* Invoke irq_cpu_online callbacks to enable desired interrupts */
-	irq_cpu_online();
+	/* Enable desired interrupts */
+	gic_all_vpes_irq_cpu_online();
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-mtk-sysirq.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-mtk-sysirq.c
@@ -15,7 +15,7 @@
 #include <linux/spinlock.h>
 
 struct mtk_sysirq_chip_data {
-	spinlock_t lock;
+	raw_spinlock_t lock;
 	u32 nr_intpol_bases;
 	void __iomem **intpol_bases;
 	u32 *intpol_words;
@@ -37,7 +37,7 @@
 	reg_index = chip_data->which_word[hwirq];
 	offset = hwirq & 0x1f;
 
-	spin_lock_irqsave(&chip_data->lock, flags);
+	raw_spin_lock_irqsave(&chip_data->lock, flags);
 	value = readl_relaxed(base + reg_index * 4);
 	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING) {
 		if (type == IRQ_TYPE_LEVEL_LOW)
@@ -53,7 +53,7 @@
 
 	data = data->parent_data;
 	ret = data->chip->irq_set_type(data, type);
-	spin_unlock_irqrestore(&chip_data->lock, flags);
+	raw_spin_unlock_irqrestore(&chip_data->lock, flags);
 	return ret;
 }
 
@@ -212,7 +212,7 @@
 		ret = -ENOMEM;
 		goto out_free_which_word;
 	}
-	spin_lock_init(&chip_data->lock);
+	raw_spin_lock_init(&chip_data->lock);
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-mvebu-gicp.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-mvebu-gicp.c
@@ -223,6 +223,7 @@
 	}
 
 	parent_domain = irq_find_host(irq_parent_dn);
+	of_node_put(irq_parent_dn);
 	if (!parent_domain) {
 		dev_err(&pdev->dev, "failed to find parent IRQ domain\n");
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-nvic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-nvic.c
@@ -26,7 +26,7 @@
 
 #define NVIC_ISER		0x000
 #define NVIC_ICER		0x080
-#define NVIC_IPR		0x300
+#define NVIC_IPR		0x400
 
 #define NVIC_MAX_BANKS		16
 /*
@@ -105,6 +105,7 @@
 
 	if (!nvic_irq_domain) {
 		pr_warn("Failed to allocate irq domain\n");
+		iounmap(nvic_base);
 		return -ENOMEM;
 	}
 
@@ -114,6 +115,7 @@
 	if (ret) {
 		pr_warn("Failed to allocate irq chips\n");
 		irq_domain_remove(nvic_irq_domain);
+		iounmap(nvic_base);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-or1k-pic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-or1k-pic.c
@@ -66,7 +66,6 @@
 		.name = "or1k-PIC-level",
 		.irq_unmask = or1k_pic_unmask,
 		.irq_mask = or1k_pic_mask,
-		.irq_mask_ack = or1k_pic_mask_ack,
 	},
 	.handle = handle_level_irq,
 	.flags = IRQ_LEVEL | IRQ_NOPROBE,
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-s3c24xx.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-s3c24xx.c
@@ -359,11 +359,25 @@
 asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
 {
 	do {
-		if (likely(s3c_intc[0]))
-			if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
-				continue;
+		/*
+		 * For platform based machines, neither ERR nor NULL can happen here.
+		 * The s3c24xx_handle_irq() will be set as IRQ handler iff this succeeds:
+		 *
+		 *    s3c_intc[0] = s3c24xx_init_intc()
+		 *
+		 * If this fails, the next calls to s3c24xx_init_intc() won't be executed.
+		 *
+		 * For DT machine, s3c_init_intc_of() could set the IRQ handler without
+		 * setting s3c_intc[0] only if it was called with num_ctrl=0. There is no
+		 * such code path, so again the s3c_intc[0] will have a valid pointer if
+		 * set_handle_irq() is called.
+		 *
+		 * Therefore in s3c24xx_handle_irq(), the s3c_intc[0] is always something.
+		 */
+		if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
+			continue;
 
-		if (s3c_intc[2])
+		if (!IS_ERR_OR_NULL(s3c_intc[2]))
 			if (s3c24xx_handle_intc(s3c_intc[2], regs, 64))
 				continue;
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-sifive-plic.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-sifive-plic.c
@@ -138,7 +138,13 @@
 {
 	struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
 
-	writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+	if (irqd_irq_masked(d)) {
+		plic_irq_unmask(d);
+		writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+		plic_irq_mask(d);
+	} else {
+		writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+	}
 }
 
 static struct irq_chip plic_chip = {
@@ -307,3 +313,4 @@
 
 IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
 IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
+IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-sni-exiu.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-sni-exiu.c
@@ -37,11 +37,26 @@
 	u32		spi_base;
 };
 
-static void exiu_irq_eoi(struct irq_data *d)
+static void exiu_irq_ack(struct irq_data *d)
 {
 	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
 
 	writel(BIT(d->hwirq), data->base + EIREQCLR);
+}
+
+static void exiu_irq_eoi(struct irq_data *d)
+{
+	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+
+	/*
+	 * Level triggered interrupts are latched and must be cleared during
+	 * EOI or the interrupt will be jammed on. Of course if a level
+	 * triggered interrupt is still asserted then the write will not clear
+	 * the interrupt.
+	 */
+	if (irqd_is_level_type(d))
+		writel(BIT(d->hwirq), data->base + EIREQCLR);
+
 	irq_chip_eoi_parent(d);
 }
 
@@ -91,10 +106,13 @@
 	writel_relaxed(val, data->base + EILVL);
 
 	val = readl_relaxed(data->base + EIEDG);
-	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) {
 		val &= ~BIT(d->hwirq);
-	else
+		irq_set_handler_locked(d, handle_fasteoi_irq);
+	} else {
 		val |= BIT(d->hwirq);
+		irq_set_handler_locked(d, handle_fasteoi_ack_irq);
+	}
 	writel_relaxed(val, data->base + EIEDG);
 
 	writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
@@ -104,6 +122,7 @@
 
 static struct irq_chip exiu_irq_chip = {
 	.name			= "EXIU",
+	.irq_ack		= exiu_irq_ack,
 	.irq_eoi		= exiu_irq_eoi,
 	.irq_enable		= exiu_irq_enable,
 	.irq_mask		= exiu_irq_mask,
@@ -136,7 +155,7 @@
 		if (fwspec->param_count != 2)
 			return -EINVAL;
 		*hwirq = fwspec->param[0];
-		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
 	}
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-stm32-exti.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-stm32-exti.c
@@ -414,6 +414,7 @@
 	.map	= irq_map_generic_chip,
 	.alloc  = stm32_exti_alloc,
 	.free	= stm32_exti_free,
+	.xlate	= irq_domain_xlate_twocell,
 };
 
 static void stm32_irq_ack(struct irq_data *d)
@@ -431,6 +432,16 @@
 	irq_gc_unlock(gc);
 }
 
+/* directly set the target bit without reading first. */
+static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg)
+{
+	struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
+	void __iomem *base = chip_data->host_data->base;
+	u32 val = BIT(d->hwirq % IRQS_PER_BANK);
+
+	writel_relaxed(val, base + reg);
+}
+
 static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
 {
 	struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
@@ -464,9 +475,9 @@
 
 	raw_spin_lock(&chip_data->rlock);
 
-	stm32_exti_set_bit(d, stm32_bank->rpr_ofst);
+	stm32_exti_write_bit(d, stm32_bank->rpr_ofst);
 	if (stm32_bank->fpr_ofst != UNDEF_REG)
-		stm32_exti_set_bit(d, stm32_bank->fpr_ofst);
+		stm32_exti_write_bit(d, stm32_bank->fpr_ofst);
 
 	raw_spin_unlock(&chip_data->rlock);
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-tegra.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-tegra.c
@@ -148,10 +148,10 @@
 		lic->cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
 
 		/* Disable COP interrupts */
-		writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
+		writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_COP_IER_CLR);
 
 		/* Disable CPU interrupts */
-		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+		writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_CPU_IER_CLR);
 
 		/* Enable the wakeup sources of ictlr */
 		writel_relaxed(lic->ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
@@ -172,12 +172,12 @@
 
 		writel_relaxed(lic->cpu_iep[i],
 			       ictlr + ICTLR_CPU_IEP_CLASS);
-		writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+		writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_CPU_IER_CLR);
 		writel_relaxed(lic->cpu_ier[i],
 			       ictlr + ICTLR_CPU_IER_SET);
 		writel_relaxed(lic->cop_iep[i],
 			       ictlr + ICTLR_COP_IEP_CLASS);
-		writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
+		writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_COP_IER_CLR);
 		writel_relaxed(lic->cop_ier[i],
 			       ictlr + ICTLR_COP_IER_SET);
 	}
@@ -312,7 +312,7 @@
 		lic->base[i] = base;
 
 		/* Disable all interrupts */
-		writel_relaxed(~0UL, base + ICTLR_CPU_IER_CLR);
+		writel_relaxed(GENMASK(31, 0), base + ICTLR_CPU_IER_CLR);
 		/* All interrupts target IRQ */
 		writel_relaxed(0, base + ICTLR_CPU_IEP_CLASS);
 
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-ti-sci-inta.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-ti-sci-inta.c
@@ -2,7 +2,7 @@
 /*
  * Texas Instruments' K3 Interrupt Aggregator irqchip driver
  *
- * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
  *	Lokesh Vutla <lokeshvutla@ti.com>
  */
 
@@ -37,6 +37,7 @@
 #define VINT_ENABLE_SET_OFFSET	0x0
 #define VINT_ENABLE_CLR_OFFSET	0x8
 #define VINT_STATUS_OFFSET	0x18
+#define VINT_STATUS_MASKED_OFFSET	0x20
 
 /**
  * struct ti_sci_inta_event_desc - Description of an event coming to
@@ -116,7 +117,7 @@
 	chained_irq_enter(irq_desc_get_chip(desc), desc);
 
 	val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
-			    VINT_STATUS_OFFSET);
+			    VINT_STATUS_MASKED_OFFSET);
 
 	for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
 		virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
@@ -570,7 +571,7 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	inta->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(inta->base))
-		return -ENODEV;
+		return PTR_ERR(inta->base);
 
 	domain = irq_domain_add_linear(dev_of_node(dev),
 				       ti_sci_get_num_resources(inta->vint),
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-ti-sci-intr.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-ti-sci-intr.c
@@ -2,7 +2,7 @@
 /*
  * Texas Instruments' K3 Interrupt Router irqchip driver
  *
- * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
  *	Lokesh Vutla <lokeshvutla@ti.com>
  */
 
@@ -205,6 +205,7 @@
 	}
 
 	parent_domain = irq_find_host(parent_node);
+	of_node_put(parent_node);
 	if (!parent_domain) {
 		dev_err(dev, "Failed to find IRQ parent domain\n");
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/irqchip/irq-versatile-fpga.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-versatile-fpga.c
@@ -6,6 +6,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>
@@ -68,12 +69,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 {
@@ -82,6 +87,9 @@
 		status &= ~(1 << irq);
 		generic_handle_irq(irq_find_mapping(f->domain, irq));
 	} while (status);
+
+out:
+	chained_irq_exit(chip, desc);
 }
 
 /*
@@ -204,6 +212,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) {
@@ -213,9 +224,6 @@
 
 	fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
 
-	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-ein-5.4.0.orig/drivers/irqchip/irq-xtensa-mx.c
+++ linux-ein-5.4.0/drivers/irqchip/irq-xtensa-mx.c
@@ -151,14 +151,25 @@
 	.irq_set_affinity = xtensa_mx_irq_set_affinity,
 };
 
+static void __init xtensa_mx_init_common(struct irq_domain *root_domain)
+{
+	unsigned int i;
+
+	irq_set_default_host(root_domain);
+	secondary_init_irq();
+
+	/* Initialize default IRQ routing to CPU 0 */
+	for (i = 0; i < XCHAL_NUM_EXTINTERRUPTS; ++i)
+		set_er(1, MIROUT(i));
+}
+
 int __init xtensa_mx_init_legacy(struct device_node *interrupt_parent)
 {
 	struct irq_domain *root_domain =
 		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);
-	secondary_init_irq();
+	xtensa_mx_init_common(root_domain);
 	return 0;
 }
 
@@ -168,8 +179,7 @@
 	struct irq_domain *root_domain =
 		irq_domain_add_linear(np, NR_IRQS, &xtensa_mx_irq_domain_ops,
 				&xtensa_mx_irq_chip);
-	irq_set_default_host(root_domain);
-	secondary_init_irq();
+	xtensa_mx_init_common(root_domain);
 	return 0;
 }
 IRQCHIP_DECLARE(xtensa_mx_irq_chip, "cdns,xtensa-mx", xtensa_mx_init);
--- linux-ein-5.4.0.orig/drivers/irqchip/qcom-pdc.c
+++ linux-ein-5.4.0/drivers/irqchip/qcom-pdc.c
@@ -50,17 +50,18 @@
 static void pdc_enable_intr(struct irq_data *d, bool on)
 {
 	int pin_out = d->hwirq;
+	unsigned long flags;
 	u32 index, mask;
 	u32 enable;
 
 	index = pin_out / 32;
 	mask = pin_out % 32;
 
-	raw_spin_lock(&pdc_lock);
+	raw_spin_lock_irqsave(&pdc_lock, flags);
 	enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
 	enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask);
 	pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
-	raw_spin_unlock(&pdc_lock);
+	raw_spin_unlock_irqrestore(&pdc_lock, flags);
 }
 
 static void qcom_pdc_gic_mask(struct irq_data *d)
--- linux-ein-5.4.0.orig/drivers/isdn/capi/kcapi.c
+++ linux-ein-5.4.0/drivers/isdn/capi/kcapi.c
@@ -565,6 +565,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;
@@ -846,7 +851,7 @@
  * Return value: CAPI result code
  */
 
-u16 capi20_get_manufacturer(u32 contr, u8 *buf)
+u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
 {
 	struct capi_ctr *ctr;
 	u16 ret;
@@ -916,7 +921,7 @@
  * Return value: CAPI result code
  */
 
-u16 capi20_get_serial(u32 contr, u8 *serial)
+u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN])
 {
 	struct capi_ctr *ctr;
 	u16 ret;
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3219,6 +3219,7 @@
 hfcm_l1callback(struct dchannel *dch, u_int cmd)
 {
 	struct hfc_multi	*hc = dch->hw;
+	struct sk_buff_head	free_queue;
 	u_long	flags;
 
 	switch (cmd) {
@@ -3247,6 +3248,7 @@
 		l1_event(dch->l1, HW_POWERUP_IND);
 		break;
 	case HW_DEACT_REQ:
+		__skb_queue_head_init(&free_queue);
 		/* start deactivation */
 		spin_lock_irqsave(&hc->lock, flags);
 		if (hc->ctype == HFC_TYPE_E1) {
@@ -3266,20 +3268,21 @@
 				plxsd_checksync(hc, 0);
 			}
 		}
-		skb_queue_purge(&dch->squeue);
+		skb_queue_splice_init(&dch->squeue, &free_queue);
 		if (dch->tx_skb) {
-			dev_kfree_skb(dch->tx_skb);
+			__skb_queue_tail(&free_queue, dch->tx_skb);
 			dch->tx_skb = NULL;
 		}
 		dch->tx_idx = 0;
 		if (dch->rx_skb) {
-			dev_kfree_skb(dch->rx_skb);
+			__skb_queue_tail(&free_queue, dch->rx_skb);
 			dch->rx_skb = NULL;
 		}
 		test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
 		if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
 			del_timer(&dch->timer);
 		spin_unlock_irqrestore(&hc->lock, flags);
+		__skb_queue_purge(&free_queue);
 		break;
 	case HW_POWERUP_REQ:
 		spin_lock_irqsave(&hc->lock, flags);
@@ -3386,6 +3389,9 @@
 	case PH_DEACTIVATE_REQ:
 		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
 		if (dch->dev.D.protocol != ISDN_P_TE_S0) {
+			struct sk_buff_head free_queue;
+
+			__skb_queue_head_init(&free_queue);
 			spin_lock_irqsave(&hc->lock, flags);
 			if (debug & DEBUG_HFCMULTI_MSG)
 				printk(KERN_DEBUG
@@ -3407,14 +3413,14 @@
 				/* deactivate */
 				dch->state = 1;
 			}
-			skb_queue_purge(&dch->squeue);
+			skb_queue_splice_init(&dch->squeue, &free_queue);
 			if (dch->tx_skb) {
-				dev_kfree_skb(dch->tx_skb);
+				__skb_queue_tail(&free_queue, dch->tx_skb);
 				dch->tx_skb = NULL;
 			}
 			dch->tx_idx = 0;
 			if (dch->rx_skb) {
-				dev_kfree_skb(dch->rx_skb);
+				__skb_queue_tail(&free_queue, dch->rx_skb);
 				dch->rx_skb = NULL;
 			}
 			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
@@ -3426,6 +3432,7 @@
 #endif
 			ret = 0;
 			spin_unlock_irqrestore(&hc->lock, flags);
+			__skb_queue_purge(&free_queue);
 		} else
 			ret = l1_event(dch->l1, hh->prim);
 		break;
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/hfcpci.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -839,7 +839,7 @@
 		*z1t = cpu_to_le16(new_z1);	/* now send data */
 		if (bch->tx_idx < bch->tx_skb->len)
 			return;
-		dev_kfree_skb(bch->tx_skb);
+		dev_kfree_skb_any(bch->tx_skb);
 		if (get_next_bframe(bch))
 			goto next_t_frame;
 		return;
@@ -895,7 +895,7 @@
 	}
 	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
 	bz->f1 = new_f1;	/* next frame */
-	dev_kfree_skb(bch->tx_skb);
+	dev_kfree_skb_any(bch->tx_skb);
 	get_next_bframe(bch);
 }
 
@@ -1119,7 +1119,7 @@
 	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
 		hfcpci_fill_fifo(bch);
 	else {
-		dev_kfree_skb(bch->tx_skb);
+		dev_kfree_skb_any(bch->tx_skb);
 		if (get_next_bframe(bch))
 			hfcpci_fill_fifo(bch);
 	}
@@ -1617,16 +1617,19 @@
 		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
 		spin_lock_irqsave(&hc->lock, flags);
 		if (hc->hw.protocol == ISDN_P_NT_S0) {
+			struct sk_buff_head free_queue;
+
+			__skb_queue_head_init(&free_queue);
 			/* prepare deactivation */
 			Write_hfc(hc, HFCPCI_STATES, 0x40);
-			skb_queue_purge(&dch->squeue);
+			skb_queue_splice_init(&dch->squeue, &free_queue);
 			if (dch->tx_skb) {
-				dev_kfree_skb(dch->tx_skb);
+				__skb_queue_tail(&free_queue, dch->tx_skb);
 				dch->tx_skb = NULL;
 			}
 			dch->tx_idx = 0;
 			if (dch->rx_skb) {
-				dev_kfree_skb(dch->rx_skb);
+				__skb_queue_tail(&free_queue, dch->rx_skb);
 				dch->rx_skb = NULL;
 			}
 			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
@@ -1639,10 +1642,12 @@
 			hc->hw.mst_m &= ~HFCPCI_MASTER;
 			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
 			ret = 0;
+			spin_unlock_irqrestore(&hc->lock, flags);
+			__skb_queue_purge(&free_queue);
 		} else {
 			ret = l1_event(dch->l1, hh->prim);
+			spin_unlock_irqrestore(&hc->lock, flags);
 		}
-		spin_unlock_irqrestore(&hc->lock, flags);
 		break;
 	}
 	if (!ret)
@@ -2267,7 +2272,7 @@
 		return 0;
 
 	if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
-		spin_lock(&hc->lock);
+		spin_lock_irq(&hc->lock);
 		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
 		if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
 			main_rec_hfcpci(bch);
@@ -2278,7 +2283,7 @@
 			main_rec_hfcpci(bch);
 			tx_birq(bch);
 		}
-		spin_unlock(&hc->lock);
+		spin_unlock_irq(&hc->lock);
 	}
 	return 0;
 }
@@ -2341,7 +2346,7 @@
 HFC_cleanup(void)
 {
 	if (timer_pending(&hfc_tl))
-		del_timer(&hfc_tl);
+		del_timer_sync(&hfc_tl);
 
 	pci_unregister_driver(&hfc_driver);
 }
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -46,7 +46,7 @@
 static void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel);
 static int  hfcsusb_setup_bch(struct bchannel *bch, int protocol);
 static void deactivate_bchannel(struct bchannel *bch);
-static void hfcsusb_ph_info(struct hfcsusb *hw);
+static int  hfcsusb_ph_info(struct hfcsusb *hw);
 
 /* start next background transfer for control channel */
 static void
@@ -241,7 +241,7 @@
  * send full D/B channel status information
  * as MPH_INFORMATION_IND
  */
-static void
+static int
 hfcsusb_ph_info(struct hfcsusb *hw)
 {
 	struct ph_info *phi;
@@ -250,7 +250,7 @@
 
 	phi = kzalloc(struct_size(phi, bch, dch->dev.nrbchan), GFP_ATOMIC);
 	if (!phi)
-		return;
+		return -ENOMEM;
 
 	phi->dch.ch.protocol = hw->protocol;
 	phi->dch.ch.Flags = dch->Flags;
@@ -264,6 +264,8 @@
 		    sizeof(struct ph_info_dch) + dch->dev.nrbchan *
 		    sizeof(struct ph_info_ch), phi, GFP_ATOMIC);
 	kfree(phi);
+
+	return 0;
 }
 
 /*
@@ -325,20 +327,24 @@
 		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
 
 		if (hw->protocol == ISDN_P_NT_S0) {
+			struct sk_buff_head free_queue;
+
+			__skb_queue_head_init(&free_queue);
 			hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT);
 			spin_lock_irqsave(&hw->lock, flags);
-			skb_queue_purge(&dch->squeue);
+			skb_queue_splice_init(&dch->squeue, &free_queue);
 			if (dch->tx_skb) {
-				dev_kfree_skb(dch->tx_skb);
+				__skb_queue_tail(&free_queue, dch->tx_skb);
 				dch->tx_skb = NULL;
 			}
 			dch->tx_idx = 0;
 			if (dch->rx_skb) {
-				dev_kfree_skb(dch->rx_skb);
+				__skb_queue_tail(&free_queue, dch->rx_skb);
 				dch->rx_skb = NULL;
 			}
 			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
 			spin_unlock_irqrestore(&hw->lock, flags);
+			__skb_queue_purge(&free_queue);
 #ifdef FIXME
 			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
 				dchannel_sched_event(&hc->dch, D_CLEARBUSY);
@@ -348,8 +354,7 @@
 			ret = l1_event(dch->l1, hh->prim);
 		break;
 	case MPH_INFORMATION_REQ:
-		hfcsusb_ph_info(hw);
-		ret = 0;
+		ret = hfcsusb_ph_info(hw);
 		break;
 	}
 
@@ -404,8 +409,7 @@
 			       hw->name, __func__, cmd);
 		return -1;
 	}
-	hfcsusb_ph_info(hw);
-	return 0;
+	return hfcsusb_ph_info(hw);
 }
 
 static int
@@ -747,8 +751,7 @@
 			handle_led(hw, (bch->nr == 1) ? LED_B1_OFF :
 				   LED_B2_OFF);
 	}
-	hfcsusb_ph_info(hw);
-	return 0;
+	return hfcsusb_ph_info(hw);
 }
 
 static void
@@ -1332,7 +1335,7 @@
 					printk("\n");
 				}
 
-				dev_kfree_skb(tx_skb);
+				dev_consume_skb_irq(tx_skb);
 				tx_skb = NULL;
 				if (fifo->dch && get_next_dframe(fifo->dch))
 					tx_skb = fifo->dch->tx_skb;
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -630,17 +630,19 @@
 release_io(struct inf_hw *hw)
 {
 	if (hw->cfg.mode) {
-		if (hw->cfg.p) {
+		if (hw->cfg.mode == AM_MEMIO) {
 			release_mem_region(hw->cfg.start, hw->cfg.size);
-			iounmap(hw->cfg.p);
+			if (hw->cfg.p)
+				iounmap(hw->cfg.p);
 		} else
 			release_region(hw->cfg.start, hw->cfg.size);
 		hw->cfg.mode = AM_NONE;
 	}
 	if (hw->addr.mode) {
-		if (hw->addr.p) {
+		if (hw->addr.mode == AM_MEMIO) {
 			release_mem_region(hw->addr.start, hw->addr.size);
-			iounmap(hw->addr.p);
+			if (hw->addr.p)
+				iounmap(hw->addr.p);
 		} else
 			release_region(hw->addr.start, hw->addr.size);
 		hw->addr.mode = AM_NONE;
@@ -670,9 +672,12 @@
 				(ulong)hw->cfg.start, (ulong)hw->cfg.size);
 			return err;
 		}
-		if (hw->ci->cfg_mode == AM_MEMIO)
-			hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
 		hw->cfg.mode = hw->ci->cfg_mode;
+		if (hw->ci->cfg_mode == AM_MEMIO) {
+			hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
+			if (!hw->cfg.p)
+				return -ENOMEM;
+		}
 		if (debug & DEBUG_HW)
 			pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",
 				  hw->name, (ulong)hw->cfg.start,
@@ -697,12 +702,12 @@
 				(ulong)hw->addr.start, (ulong)hw->addr.size);
 			return err;
 		}
+		hw->addr.mode = hw->ci->addr_mode;
 		if (hw->ci->addr_mode == AM_MEMIO) {
 			hw->addr.p = ioremap(hw->addr.start, hw->addr.size);
-			if (unlikely(!hw->addr.p))
+			if (!hw->addr.p)
 				return -ENOMEM;
 		}
-		hw->addr.mode = hw->ci->addr_mode;
 		if (debug & DEBUG_HW)
 			pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",
 				  hw->name, (ulong)hw->addr.start,
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -694,7 +694,7 @@
 {
 	if (isac->type & IPAC_TYPE_ISACX)
 		WriteISAC(isac, ISACX_MASK, 0xff);
-	else
+	else if (isac->type != 0)
 		WriteISAC(isac, ISAC_MASK, 0xff);
 	if (isac->dch.timer.function != NULL) {
 		del_timer(&isac->dch.timer);
--- linux-ein-5.4.0.orig/drivers/isdn/hardware/mISDN/netjet.c
+++ linux-ein-5.4.0/drivers/isdn/hardware/mISDN/netjet.c
@@ -949,14 +949,14 @@
 		nj_disable_hwirq(card);
 		mode_tiger(&card->bc[0], ISDN_P_NONE);
 		mode_tiger(&card->bc[1], ISDN_P_NONE);
-		card->isac.release(&card->isac);
 		spin_unlock_irqrestore(&card->lock, flags);
+		card->isac.release(&card->isac);
 		release_region(card->base, card->base_s);
 		card->base_s = 0;
 	}
 	if (card->irq > 0)
 		free_irq(card->irq, card);
-	if (card->isac.dch.dev.dev.class)
+	if (device_is_registered(&card->isac.dch.dev.dev))
 		mISDN_unregister_device(&card->isac.dch.dev);
 
 	for (i = 0; i < 2; i++) {
@@ -1100,7 +1100,6 @@
 		card->typ = NETJET_S_TJ300;
 
 	card->base = pci_resource_start(pdev, 0);
-	card->irq = pdev->irq;
 	pci_set_drvdata(pdev, card);
 	err = setup_instance(card);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/Kconfig
+++ linux-ein-5.4.0/drivers/isdn/mISDN/Kconfig
@@ -13,6 +13,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-ein-5.4.0.orig/drivers/isdn/mISDN/core.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/core.c
@@ -222,7 +222,7 @@
 
 	err = get_free_devid();
 	if (err < 0)
-		goto error1;
+		return err;
 	dev->id = err;
 
 	device_initialize(&dev->dev);
@@ -233,11 +233,12 @@
 	if (debug & DEBUG_CORE)
 		printk(KERN_DEBUG "mISDN_register %s %d\n",
 		       dev_name(&dev->dev), dev->id);
+	dev->dev.class = &mISDN_class;
+
 	err = create_stack(dev);
 	if (err)
 		goto error1;
 
-	dev->dev.class = &mISDN_class;
 	dev->dev.platform_data = dev;
 	dev->dev.parent = parent;
 	dev_set_drvdata(&dev->dev, dev);
@@ -249,8 +250,8 @@
 
 error3:
 	delete_stack(dev);
-	return err;
 error1:
+	put_device(&dev->dev);
 	return err;
 
 }
@@ -381,7 +382,7 @@
 	err = mISDN_inittimer(&debug);
 	if (err)
 		goto error2;
-	err = l1_init(&debug);
+	err = Isdnl1_Init(&debug);
 	if (err)
 		goto error3;
 	err = Isdnl2_Init(&debug);
@@ -395,7 +396,7 @@
 error5:
 	Isdnl2_cleanup();
 error4:
-	l1_cleanup();
+	Isdnl1_cleanup();
 error3:
 	mISDN_timer_cleanup();
 error2:
@@ -408,7 +409,7 @@
 {
 	misdn_sock_cleanup();
 	Isdnl2_cleanup();
-	l1_cleanup();
+	Isdnl1_cleanup();
 	mISDN_timer_cleanup();
 	class_unregister(&mISDN_class);
 
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/core.h
+++ linux-ein-5.4.0/drivers/isdn/mISDN/core.h
@@ -60,8 +60,8 @@
 extern int	mISDN_inittimer(u_int *);
 extern void	mISDN_timer_cleanup(void);
 
-extern int	l1_init(u_int *);
-extern void	l1_cleanup(void);
+extern int	Isdnl1_Init(u_int *);
+extern void	Isdnl1_cleanup(void);
 extern int	Isdnl2_Init(u_int *);
 extern void	Isdnl2_cleanup(void);
 
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/dsp.h
+++ linux-ein-5.4.0/drivers/isdn/mISDN/dsp.h
@@ -247,7 +247,7 @@
 extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id);
 extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb);
 extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb);
-extern void dsp_cmx_send(void *arg);
+extern void dsp_cmx_send(struct timer_list *arg);
 extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb);
 extern int dsp_cmx_del_conf_member(struct dsp *dsp);
 extern int dsp_cmx_del_conf(struct dsp_conf *conf);
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/dsp_cmx.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/dsp_cmx.c
@@ -1625,7 +1625,7 @@
 static int	dsp_count_valid; /* if we have last sample count */
 
 void
-dsp_cmx_send(void *arg)
+dsp_cmx_send(struct timer_list *arg)
 {
 	struct dsp_conf *conf;
 	struct dsp_conf_member *member;
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/dsp_core.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/dsp_core.c
@@ -1200,7 +1200,7 @@
 	}
 
 	/* set sample timer */
-	timer_setup(&dsp_spl_tl, (void *)dsp_cmx_send, 0);
+	timer_setup(&dsp_spl_tl, dsp_cmx_send, 0);
 	dsp_spl_tl.expires = jiffies + dsp_tics;
 	dsp_spl_jiffies = dsp_spl_tl.expires;
 	add_timer(&dsp_spl_tl);
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/dsp_pipeline.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/dsp_pipeline.c
@@ -80,6 +80,7 @@
 	if (!entry)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&entry->list);
 	entry->elem = elem;
 
 	entry->dev.class = elements_class;
@@ -114,7 +115,7 @@
 	device_unregister(&entry->dev);
 	return ret;
 err1:
-	kfree(entry);
+	put_device(&entry->dev);
 	return ret;
 }
 EXPORT_SYMBOL(mISDN_dsp_element_register);
--- linux-ein-5.4.0.orig/drivers/isdn/mISDN/l1oip.h
+++ linux-ein-5.4.0/drivers/isdn/mISDN/l1oip.h
@@ -59,6 +59,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-ein-5.4.0.orig/drivers/isdn/mISDN/l1oip_core.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/l1oip_core.c
@@ -275,7 +275,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;
@@ -601,7 +601,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 */
@@ -1232,11 +1234,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-ein-5.4.0.orig/drivers/isdn/mISDN/layer1.c
+++ linux-ein-5.4.0/drivers/isdn/mISDN/layer1.c
@@ -398,7 +398,7 @@
 EXPORT_SYMBOL(create_l1);
 
 int
-l1_init(u_int *deb)
+Isdnl1_Init(u_int *deb)
 {
 	debug = deb;
 	l1fsm_s.state_count = L1S_STATE_COUNT;
@@ -409,7 +409,7 @@
 }
 
 void
-l1_cleanup(void)
+Isdnl1_cleanup(void)
 {
 	mISDN_FsmFree(&l1fsm_s);
 }
--- linux-ein-5.4.0.orig/drivers/leds/Kconfig
+++ linux-ein-5.4.0/drivers/leds/Kconfig
@@ -144,6 +144,7 @@
 
 config LEDS_LM3532
 	tristate "LCD Backlight driver for LM3532"
+	select REGMAP_I2C
 	depends on LEDS_CLASS
 	depends on I2C
 	help
@@ -344,7 +345,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.
@@ -801,7 +801,7 @@
 config LEDS_TI_LMU_COMMON
 	tristate "LED driver for TI LMU"
 	depends on LEDS_CLASS
-	depends on REGMAP
+	select REGMAP
 	help
 	  Say Y to enable the LED driver for TI LMU devices.
 	  This supports common features between the TI LM3532, LM3631, LM3632,
--- linux-ein-5.4.0.orig/drivers/leds/led-class.c
+++ linux-ein-5.4.0/drivers/leds/led-class.c
@@ -172,6 +172,7 @@
 {
 	led_cdev->flags |= LED_SUSPENDED;
 	led_set_brightness_nopm(led_cdev, 0);
+	flush_work(&led_cdev->set_brightness_work);
 }
 EXPORT_SYMBOL_GPL(led_classdev_suspend);
 
@@ -281,7 +282,7 @@
 
 	if (ret)
 		dev_warn(parent, "Led %s renamed to %s due to name collision",
-				led_cdev->name, dev_name(led_cdev->dev));
+				proposed_name, dev_name(led_cdev->dev));
 
 	if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
 		ret = led_add_brightness_hw_changed(led_cdev);
--- linux-ein-5.4.0.orig/drivers/leds/led-triggers.c
+++ linux-ein-5.4.0/drivers/leds/led-triggers.c
@@ -318,14 +318,15 @@
 			enum led_brightness brightness)
 {
 	struct led_classdev *led_cdev;
+	unsigned long flags;
 
 	if (!trig)
 		return;
 
-	read_lock(&trig->leddev_list_lock);
+	read_lock_irqsave(&trig->leddev_list_lock, flags);
 	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
 		led_set_brightness(led_cdev, brightness);
-	read_unlock(&trig->leddev_list_lock);
+	read_unlock_irqrestore(&trig->leddev_list_lock, flags);
 }
 EXPORT_SYMBOL_GPL(led_trigger_event);
 
@@ -336,11 +337,12 @@
 			     int invert)
 {
 	struct led_classdev *led_cdev;
+	unsigned long flags;
 
 	if (!trig)
 		return;
 
-	read_lock(&trig->leddev_list_lock);
+	read_lock_irqsave(&trig->leddev_list_lock, flags);
 	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
 		if (oneshot)
 			led_blink_set_oneshot(led_cdev, delay_on, delay_off,
@@ -348,7 +350,7 @@
 		else
 			led_blink_set(led_cdev, delay_on, delay_off);
 	}
-	read_unlock(&trig->leddev_list_lock);
+	read_unlock_irqrestore(&trig->leddev_list_lock, flags);
 }
 
 void led_trigger_blink(struct led_trigger *trig,
--- linux-ein-5.4.0.orig/drivers/leds/leds-88pm860x.c
+++ linux-ein-5.4.0/drivers/leds/leds-88pm860x.c
@@ -203,21 +203,33 @@
 	data->cdev.brightness_set_blocking = pm860x_led_set;
 	mutex_init(&data->lock);
 
-	ret = devm_led_classdev_register(chip->dev, &data->cdev);
+	ret = led_classdev_register(chip->dev, &data->cdev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
 		return ret;
 	}
 	pm860x_led_set(&data->cdev, 0);
+
+	platform_set_drvdata(pdev, data);
+
 	return 0;
 }
 
+static int pm860x_led_remove(struct platform_device *pdev)
+{
+	struct pm860x_led *data = platform_get_drvdata(pdev);
+
+	led_classdev_unregister(&data->cdev);
+
+	return 0;
+}
 
 static struct platform_driver pm860x_led_driver = {
 	.driver	= {
 		.name	= "88pm860x-led",
 	},
 	.probe	= pm860x_led_probe,
+	.remove	= pm860x_led_remove,
 };
 
 module_platform_driver(pm860x_led_driver);
--- linux-ein-5.4.0.orig/drivers/leds/leds-an30259a.c
+++ linux-ein-5.4.0/drivers/leds/leds-an30259a.c
@@ -305,6 +305,13 @@
 
 	chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
 
+	if (IS_ERR(chip->regmap)) {
+		err = PTR_ERR(chip->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			err);
+		goto exit;
+	}
+
 	for (i = 0; i < chip->num_leds; i++) {
 		struct led_init_data init_data = {};
 
--- linux-ein-5.4.0.orig/drivers/leds/leds-as3645a.c
+++ linux-ein-5.4.0/drivers/leds/leds-as3645a.c
@@ -544,6 +544,7 @@
 	if (!flash->indicator_node) {
 		dev_warn(&flash->client->dev,
 			 "can't find indicator node\n");
+		rval = -ENODEV;
 		goto out_err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/leds/leds-bcm6328.c
+++ linux-ein-5.4.0/drivers/leds/leds-bcm6328.c
@@ -332,7 +332,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-ein-5.4.0.orig/drivers/leds/leds-bcm6358.c
+++ linux-ein-5.4.0/drivers/leds/leds-bcm6358.c
@@ -137,7 +137,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-ein-5.4.0.orig/drivers/leds/leds-da903x.c
+++ linux-ein-5.4.0/drivers/leds/leds-da903x.c
@@ -110,12 +110,23 @@
 	led->flags = pdata->flags;
 	led->master = pdev->dev.parent;
 
-	ret = devm_led_classdev_register(led->master, &led->cdev);
+	ret = led_classdev_register(led->master, &led->cdev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register LED %d\n", id);
 		return ret;
 	}
 
+	platform_set_drvdata(pdev, led);
+
+	return 0;
+}
+
+static int da903x_led_remove(struct platform_device *pdev)
+{
+	struct da903x_led *led = platform_get_drvdata(pdev);
+
+	led_classdev_unregister(&led->cdev);
+
 	return 0;
 }
 
@@ -124,6 +135,7 @@
 		.name	= "da903x-led",
 	},
 	.probe		= da903x_led_probe,
+	.remove		= da903x_led_remove,
 };
 
 module_platform_driver(da903x_led_driver);
--- linux-ein-5.4.0.orig/drivers/leds/leds-gpio.c
+++ linux-ein-5.4.0/drivers/leds/leds-gpio.c
@@ -151,9 +151,14 @@
 		struct gpio_led led = {};
 		const char *state = NULL;
 
+		/*
+		 * Acquire gpiod from DT with uninitialized label, which
+		 * will be updated after LED class device is registered,
+		 * Only then the final LED name is known.
+		 */
 		led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
 							     GPIOD_ASIS,
-							     led.name);
+							     NULL);
 		if (IS_ERR(led.gpiod)) {
 			fwnode_handle_put(child);
 			return ERR_CAST(led.gpiod);
@@ -186,6 +191,9 @@
 			fwnode_handle_put(child);
 			return ERR_PTR(ret);
 		}
+		/* Set gpiod label to match the corresponding LED name. */
+		gpiod_set_consumer_name(led_dat->gpiod,
+					led_dat->cdev.dev->kobj.name);
 		priv->num_leds++;
 	}
 
--- linux-ein-5.4.0.orig/drivers/leds/leds-ktd2692.c
+++ linux-ein-5.4.0/drivers/leds/leds-ktd2692.c
@@ -256,6 +256,17 @@
 				 | KTD2692_REG_FLASH_CURRENT_BASE);
 }
 
+static void regulator_disable_action(void *_data)
+{
+	struct device *dev = _data;
+	struct ktd2692_context *led = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_disable(led->regulator);
+	if (ret)
+		dev_err(dev, "Failed to disable supply: %d\n", ret);
+}
+
 static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
 			    struct ktd2692_led_config_data *cfg)
 {
@@ -286,8 +297,14 @@
 
 	if (led->regulator) {
 		ret = regulator_enable(led->regulator);
-		if (ret)
+		if (ret) {
 			dev_err(dev, "Failed to enable supply: %d\n", ret);
+		} else {
+			ret = devm_add_action_or_reset(dev,
+						regulator_disable_action, dev);
+			if (ret)
+				return ret;
+		}
 	}
 
 	child_node = of_get_next_available_child(np, NULL);
@@ -377,17 +394,9 @@
 static int ktd2692_remove(struct platform_device *pdev)
 {
 	struct ktd2692_context *led = platform_get_drvdata(pdev);
-	int ret;
 
 	led_classdev_flash_unregister(&led->fled_cdev);
 
-	if (led->regulator) {
-		ret = regulator_disable(led->regulator);
-		if (ret)
-			dev_err(&pdev->dev,
-				"Failed to disable supply: %d\n", ret);
-	}
-
 	mutex_destroy(&led->lock);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/leds/leds-lm3533.c
+++ linux-ein-5.4.0/drivers/leds/leds-lm3533.c
@@ -694,7 +694,7 @@
 
 	platform_set_drvdata(pdev, led);
 
-	ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev);
+	ret = led_classdev_register(pdev->dev.parent, &led->cdev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
 		return ret;
@@ -704,13 +704,18 @@
 
 	ret = lm3533_led_setup(led, pdata);
 	if (ret)
-		return ret;
+		goto err_deregister;
 
 	ret = lm3533_ctrlbank_enable(&led->cb);
 	if (ret)
-		return ret;
+		goto err_deregister;
 
 	return 0;
+
+err_deregister:
+	led_classdev_unregister(&led->cdev);
+
+	return ret;
 }
 
 static int lm3533_led_remove(struct platform_device *pdev)
@@ -720,6 +725,7 @@
 	dev_dbg(&pdev->dev, "%s\n", __func__);
 
 	lm3533_ctrlbank_disable(&led->cb);
+	led_classdev_unregister(&led->cdev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/leds/leds-lm355x.c
+++ linux-ein-5.4.0/drivers/leds/leds-lm355x.c
@@ -165,18 +165,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-ein-5.4.0.orig/drivers/leds/leds-lm36274.c
+++ linux-ein-5.4.0/drivers/leds/leds-lm36274.c
@@ -41,37 +41,36 @@
 };
 
 static int lm36274_brightness_set(struct led_classdev *led_cdev,
-				enum led_brightness brt_val)
+				  enum led_brightness brt_val)
 {
-	struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev);
+	struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev);
 
-	return ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
+	return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val);
 }
 
-static int lm36274_init(struct lm36274 *lm36274_data)
+static int lm36274_init(struct lm36274 *chip)
 {
 	int enable_val = 0;
 	int i;
 
-	for (i = 0; i < lm36274_data->num_leds; i++)
-		enable_val |= (1 << lm36274_data->led_sources[i]);
+	for (i = 0; i < chip->num_leds; i++)
+		enable_val |= (1 << chip->led_sources[i]);
 
 	if (!enable_val) {
-		dev_err(lm36274_data->dev, "No LEDs were enabled\n");
+		dev_err(chip->dev, "No LEDs were enabled\n");
 		return -EINVAL;
 	}
 
 	enable_val |= LM36274_BL_EN;
 
-	return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN,
-			    enable_val);
+	return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val);
 }
 
-static int lm36274_parse_dt(struct lm36274 *lm36274_data)
+static int lm36274_parse_dt(struct lm36274 *chip)
 {
 	struct fwnode_handle *child = NULL;
 	char label[LED_MAX_NAME_SIZE];
-	struct device *dev = &lm36274_data->pdev->dev;
+	struct device *dev = &chip->pdev->dev;
 	const char *name;
 	int child_cnt;
 	int ret = -EINVAL;
@@ -84,37 +83,37 @@
 	device_for_each_child_node(dev, child) {
 		ret = fwnode_property_read_string(child, "label", &name);
 		if (ret)
-			snprintf(label, sizeof(label),
-				"%s::", lm36274_data->pdev->name);
+			snprintf(label, sizeof(label), "%s::",
+				 chip->pdev->name);
 		else
-			snprintf(label, sizeof(label),
-				 "%s:%s", lm36274_data->pdev->name, name);
+			snprintf(label, sizeof(label), "%s:%s",
+				 chip->pdev->name, name);
 
-		lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources");
-		if (lm36274_data->num_leds <= 0)
+		chip->num_leds = fwnode_property_count_u32(child, "led-sources");
+		if (chip->num_leds <= 0)
 			return -ENODEV;
 
 		ret = fwnode_property_read_u32_array(child, "led-sources",
-						     lm36274_data->led_sources,
-						     lm36274_data->num_leds);
+						     chip->led_sources,
+						     chip->num_leds);
 		if (ret) {
 			dev_err(dev, "led-sources property missing\n");
 			return ret;
 		}
 
 		fwnode_property_read_string(child, "linux,default-trigger",
-					&lm36274_data->led_dev.default_trigger);
+					    &chip->led_dev.default_trigger);
 
 	}
 
-	lm36274_data->lmu_data.regmap = lm36274_data->regmap;
-	lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
-	lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
-	lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
-
-	lm36274_data->led_dev.name = label;
-	lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
-	lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
+	chip->lmu_data.regmap = chip->regmap;
+	chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
+	chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
+	chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
+
+	chip->led_dev.name = label;
+	chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
+	chip->led_dev.brightness_set_blocking = lm36274_brightness_set;
 
 	return 0;
 }
@@ -122,33 +121,40 @@
 static int lm36274_probe(struct platform_device *pdev)
 {
 	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
-	struct lm36274 *lm36274_data;
+	struct lm36274 *chip;
 	int ret;
 
-	lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
-				    GFP_KERNEL);
-	if (!lm36274_data)
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
 		return -ENOMEM;
 
-	lm36274_data->pdev = pdev;
-	lm36274_data->dev = lmu->dev;
-	lm36274_data->regmap = lmu->regmap;
-	dev_set_drvdata(&pdev->dev, lm36274_data);
+	chip->pdev = pdev;
+	chip->dev = lmu->dev;
+	chip->regmap = lmu->regmap;
+	platform_set_drvdata(pdev, chip);
 
-	ret = lm36274_parse_dt(lm36274_data);
+	ret = lm36274_parse_dt(chip);
 	if (ret) {
-		dev_err(lm36274_data->dev, "Failed to parse DT node\n");
+		dev_err(chip->dev, "Failed to parse DT node\n");
 		return ret;
 	}
 
-	ret = lm36274_init(lm36274_data);
+	ret = lm36274_init(chip);
 	if (ret) {
-		dev_err(lm36274_data->dev, "Failed to init the device\n");
+		dev_err(chip->dev, "Failed to init the device\n");
 		return ret;
 	}
 
-	return devm_led_classdev_register(lm36274_data->dev,
-					 &lm36274_data->led_dev);
+	return led_classdev_register(chip->dev, &chip->led_dev);
+}
+
+static int lm36274_remove(struct platform_device *pdev)
+{
+	struct lm36274 *chip = platform_get_drvdata(pdev);
+
+	led_classdev_unregister(&chip->led_dev);
+
+	return 0;
 }
 
 static const struct of_device_id of_lm36274_leds_match[] = {
@@ -159,6 +165,7 @@
 
 static struct platform_driver lm36274_driver = {
 	.probe  = lm36274_probe,
+	.remove = lm36274_remove,
 	.driver = {
 		.name = "lm36274-leds",
 	},
--- linux-ein-5.4.0.orig/drivers/leds/leds-lm3692x.c
+++ linux-ein-5.4.0/drivers/leds/leds-lm3692x.c
@@ -334,9 +334,18 @@
 		return ret;
 	}
 
-	led->regulator = devm_regulator_get(&led->client->dev, "vled");
-	if (IS_ERR(led->regulator))
+	led->regulator = devm_regulator_get_optional(&led->client->dev, "vled");
+	if (IS_ERR(led->regulator)) {
+		ret = PTR_ERR(led->regulator);
+		if (ret != -ENODEV) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(&led->client->dev,
+					"Failed to get vled regulator: %d\n",
+					ret);
+			return ret;
+		}
 		led->regulator = NULL;
+	}
 
 	child = device_get_next_child_node(&led->client->dev, child);
 	if (!child) {
@@ -349,6 +358,7 @@
 
 	ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
 	if (ret) {
+		fwnode_handle_put(child);
 		dev_err(&led->client->dev, "reg DT property missing\n");
 		return ret;
 	}
@@ -359,12 +369,11 @@
 
 	ret = devm_led_classdev_register_ext(&led->client->dev, &led->led_dev,
 					     &init_data);
-	if (ret) {
+	if (ret)
 		dev_err(&led->client->dev, "led register err: %d\n", ret);
-		return ret;
-	}
 
-	return 0;
+	fwnode_handle_put(init_data.fwnode);
+	return ret;
 }
 
 static int lm3692x_probe(struct i2c_client *client,
--- linux-ein-5.4.0.orig/drivers/leds/leds-lp5523.c
+++ linux-ein-5.4.0/drivers/leds/leds-lp5523.c
@@ -307,7 +307,7 @@
 	usleep_range(3000, 6000);
 	ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
 	if (ret)
-		return ret;
+		goto out;
 	status &= LP5523_ENG_STATUS_MASK;
 
 	if (status != LP5523_ENG_STATUS_MASK) {
--- linux-ein-5.4.0.orig/drivers/leds/leds-lt3593.c
+++ linux-ein-5.4.0/drivers/leds/leds-lt3593.c
@@ -103,10 +103,9 @@
 	init_data.default_label = ":";
 
 	ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
-	if (ret < 0) {
-		fwnode_handle_put(child);
+	fwnode_handle_put(child);
+	if (ret < 0)
 		return ret;
-	}
 
 	led_data->cdev.dev->of_node = dev->of_node;
 	platform_set_drvdata(pdev, led_data);
--- linux-ein-5.4.0.orig/drivers/leds/leds-max77650.c
+++ linux-ein-5.4.0/drivers/leds/leds-max77650.c
@@ -135,9 +135,16 @@
 	return rv;
 }
 
+static const struct of_device_id max77650_led_of_match[] = {
+	{ .compatible = "maxim,max77650-led" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max77650_led_of_match);
+
 static struct platform_driver max77650_led_driver = {
 	.driver = {
 		.name = "max77650-led",
+		.of_match_table = max77650_led_of_match,
 	},
 	.probe = max77650_led_probe,
 };
--- linux-ein-5.4.0.orig/drivers/leds/leds-mlxreg.c
+++ linux-ein-5.4.0/drivers/leds/leds-mlxreg.c
@@ -228,8 +228,8 @@
 			brightness = LED_OFF;
 			led_data->base_color = MLXREG_LED_GREEN_SOLID;
 		}
-		sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
-			data->label);
+		snprintf(led_data->led_cdev_name, sizeof(led_data->led_cdev_name),
+			 "mlxreg:%s", data->label);
 		led_cdev->name = led_data->led_cdev_name;
 		led_cdev->brightness = brightness;
 		led_cdev->max_brightness = LED_ON;
--- linux-ein-5.4.0.orig/drivers/leds/leds-pca963x.c
+++ linux-ein-5.4.0/drivers/leds/leds-pca963x.c
@@ -40,6 +40,8 @@
 #define PCA963X_LED_PWM		0x2	/* Controlled through PWM */
 #define PCA963X_LED_GRP_PWM	0x3	/* Controlled through PWM/GRPPWM */
 
+#define PCA963X_MODE2_OUTDRV	0x04	/* Open-drain or totem pole */
+#define PCA963X_MODE2_INVRT	0x10	/* Normal or inverted direction */
 #define PCA963X_MODE2_DMBLNK	0x20	/* Enable blinking */
 
 #define PCA963X_MODE1		0x00
@@ -438,12 +440,12 @@
 						    PCA963X_MODE2);
 		/* Configure output: open-drain or totem pole (push-pull) */
 		if (pdata->outdrv == PCA963X_OPEN_DRAIN)
-			mode2 |= 0x01;
+			mode2 &= ~PCA963X_MODE2_OUTDRV;
 		else
-			mode2 |= 0x05;
+			mode2 |= PCA963X_MODE2_OUTDRV;
 		/* Configure direction: normal or inverted */
 		if (pdata->dir == PCA963X_INVERTED)
-			mode2 |= 0x10;
+			mode2 |= PCA963X_MODE2_INVRT;
 		i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
 					  mode2);
 	}
--- linux-ein-5.4.0.orig/drivers/leds/leds-pwm.c
+++ linux-ein-5.4.0/drivers/leds/leds-pwm.c
@@ -22,9 +22,8 @@
 struct led_pwm_data {
 	struct led_classdev	cdev;
 	struct pwm_device	*pwm;
+	struct pwm_state	pwmstate;
 	unsigned int		active_low;
-	unsigned int		period;
-	int			duty;
 };
 
 struct led_pwm_priv {
@@ -32,44 +31,29 @@
 	struct led_pwm_data leds[0];
 };
 
-static void __led_pwm_set(struct led_pwm_data *led_dat)
-{
-	int new_duty = led_dat->duty;
-
-	pwm_config(led_dat->pwm, new_duty, led_dat->period);
-
-	if (new_duty == 0)
-		pwm_disable(led_dat->pwm);
-	else
-		pwm_enable(led_dat->pwm);
-}
-
 static int led_pwm_set(struct led_classdev *led_cdev,
 		       enum led_brightness brightness)
 {
 	struct led_pwm_data *led_dat =
 		container_of(led_cdev, struct led_pwm_data, cdev);
 	unsigned int max = led_dat->cdev.max_brightness;
-	unsigned long long duty =  led_dat->period;
+	unsigned long long duty = led_dat->pwmstate.period;
 
 	duty *= brightness;
 	do_div(duty, max);
 
 	if (led_dat->active_low)
-		duty = led_dat->period - duty;
-
-	led_dat->duty = duty;
+		duty = led_dat->pwmstate.period - duty;
 
-	__led_pwm_set(led_dat);
-
-	return 0;
+	led_dat->pwmstate.duty_cycle = duty;
+	led_dat->pwmstate.enabled = true;
+	return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
 }
 
 static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 		       struct led_pwm *led, struct fwnode_handle *fwnode)
 {
 	struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
-	struct pwm_args pargs;
 	int ret;
 
 	led_data->active_low = led->active_low;
@@ -93,17 +77,10 @@
 
 	led_data->cdev.brightness_set_blocking = led_pwm_set;
 
-	/*
-	 * FIXME: pwm_apply_args() should be removed when switching to the
-	 * atomic PWM API.
-	 */
-	pwm_apply_args(led_data->pwm);
-
-	pwm_get_args(led_data->pwm, &pargs);
-
-	led_data->period = pargs.period;
-	if (!led_data->period && (led->pwm_period_ns > 0))
-		led_data->period = led->pwm_period_ns;
+	pwm_init_state(led_data->pwm, &led_data->pwmstate);
+
+	if (!led_data->pwmstate.period)
+		led_data->pwmstate.period = led->pwm_period_ns;
 
 	ret = devm_led_classdev_register(dev, &led_data->cdev);
 	if (ret == 0) {
--- linux-ein-5.4.0.orig/drivers/leds/leds-tlc591xx.c
+++ linux-ein-5.4.0/drivers/leds/leds-tlc591xx.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 
 #define TLC591XX_MAX_LEDS	16
+#define TLC591XX_MAX_BRIGHTNESS	256
 
 #define TLC591XX_REG_MODE1	0x00
 #define MODE1_RESPON_ADDR_MASK	0xF0
@@ -112,11 +113,11 @@
 	struct tlc591xx_priv *priv = led->priv;
 	int err;
 
-	switch (brightness) {
+	switch ((int)brightness) {
 	case 0:
 		err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
 		break;
-	case LED_FULL:
+	case TLC591XX_MAX_BRIGHTNESS:
 		err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
 		break;
 	default:
@@ -157,7 +158,7 @@
 		led->priv = priv;
 		led->led_no = i;
 		led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
-		led->ldev.max_brightness = LED_FULL;
+		led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS;
 		err = led_classdev_register(dev, &led->ldev);
 		if (err < 0) {
 			dev_err(dev, "couldn't register LED %s\n",
--- linux-ein-5.4.0.orig/drivers/leds/leds-wm831x-status.c
+++ linux-ein-5.4.0/drivers/leds/leds-wm831x-status.c
@@ -269,12 +269,23 @@
 	drvdata->cdev.blink_set = wm831x_status_blink_set;
 	drvdata->cdev.groups = wm831x_status_groups;
 
-	ret = devm_led_classdev_register(wm831x->dev, &drvdata->cdev);
+	ret = led_classdev_register(wm831x->dev, &drvdata->cdev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
 		return ret;
 	}
 
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+}
+
+static int wm831x_status_remove(struct platform_device *pdev)
+{
+	struct wm831x_status *drvdata = platform_get_drvdata(pdev);
+
+	led_classdev_unregister(&drvdata->cdev);
+
 	return 0;
 }
 
@@ -283,6 +294,7 @@
 		   .name = "wm831x-status",
 		   },
 	.probe = wm831x_status_probe,
+	.remove = wm831x_status_remove,
 };
 
 module_platform_driver(wm831x_status_driver);
--- linux-ein-5.4.0.orig/drivers/leds/trigger/ledtrig-audio.c
+++ linux-ein-5.4.0/drivers/leds/trigger/ledtrig-audio.c
@@ -6,10 +6,33 @@
 #include <linux/kernel.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include "../leds.h"
 
-static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
 static enum led_brightness audio_state[NUM_AUDIO_LEDS];
 
+static int ledtrig_audio_mute_activate(struct led_classdev *led_cdev)
+{
+	led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MUTE]);
+	return 0;
+}
+
+static int ledtrig_audio_micmute_activate(struct led_classdev *led_cdev)
+{
+	led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MICMUTE]);
+	return 0;
+}
+
+static struct led_trigger ledtrig_audio[NUM_AUDIO_LEDS] = {
+	[LED_AUDIO_MUTE] = {
+		.name     = "audio-mute",
+		.activate = ledtrig_audio_mute_activate,
+	},
+	[LED_AUDIO_MICMUTE] = {
+		.name     = "audio-micmute",
+		.activate = ledtrig_audio_micmute_activate,
+	},
+};
+
 enum led_brightness ledtrig_audio_get(enum led_audio type)
 {
 	return audio_state[type];
@@ -19,24 +42,22 @@
 void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
 {
 	audio_state[type] = state;
-	led_trigger_event(ledtrig_audio[type], state);
+	led_trigger_event(&ledtrig_audio[type], state);
 }
 EXPORT_SYMBOL_GPL(ledtrig_audio_set);
 
 static int __init ledtrig_audio_init(void)
 {
-	led_trigger_register_simple("audio-mute",
-				    &ledtrig_audio[LED_AUDIO_MUTE]);
-	led_trigger_register_simple("audio-micmute",
-				    &ledtrig_audio[LED_AUDIO_MICMUTE]);
+	led_trigger_register(&ledtrig_audio[LED_AUDIO_MUTE]);
+	led_trigger_register(&ledtrig_audio[LED_AUDIO_MICMUTE]);
 	return 0;
 }
 module_init(ledtrig_audio_init);
 
 static void __exit ledtrig_audio_exit(void)
 {
-	led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
-	led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
+	led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MUTE]);
+	led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MICMUTE]);
 }
 module_exit(ledtrig_audio_exit);
 
--- linux-ein-5.4.0.orig/drivers/leds/trigger/ledtrig-cpu.c
+++ linux-ein-5.4.0/drivers/leds/trigger/ledtrig-cpu.c
@@ -2,14 +2,18 @@
 /*
  * ledtrig-cpu.c - LED trigger based on CPU activity
  *
- * This LED trigger will be registered for each possible CPU and named as
- * cpu0, cpu1, cpu2, cpu3, etc.
+ * This LED trigger will be registered for first 8 CPUs and named
+ * as cpu0..cpu7. There's additional trigger called cpu that
+ * is on when any CPU is active.
+ *
+ * If you want support for arbitrary number of CPUs, make it one trigger,
+ * with additional sysfs file selecting which CPU to watch.
  *
  * It can be bound to any LED just like other triggers using either a
  * board file or via sysfs interface.
  *
  * An API named ledtrig_cpu is exported for any user, who want to add CPU
- * activity indication in their code
+ * activity indication in their code.
  *
  * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
  * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
@@ -126,7 +130,7 @@
 
 static int __init ledtrig_cpu_init(void)
 {
-	int cpu;
+	unsigned int cpu;
 	int ret;
 
 	/* Supports up to 9999 cpu cores */
@@ -145,7 +149,10 @@
 	for_each_possible_cpu(cpu) {
 		struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
 
-		snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
+		if (cpu >= 8)
+			continue;
+
+		snprintf(trig->name, MAX_NAME_LEN, "cpu%u", cpu);
 
 		led_trigger_register_simple(trig->name, &trig->_trig);
 	}
--- linux-ein-5.4.0.orig/drivers/leds/trigger/ledtrig-netdev.c
+++ linux-ein-5.4.0/drivers/leds/trigger/ledtrig-netdev.c
@@ -302,10 +302,12 @@
 		container_of(nb, struct led_netdev_data, notifier);
 
 	if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
-	    && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
+	    && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
+	    && evt != NETDEV_CHANGENAME)
 		return NOTIFY_DONE;
 
 	if (!(dev == trigger_data->net_dev ||
+	      (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
 	      (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
 		return NOTIFY_DONE;
 
@@ -315,6 +317,10 @@
 
 	clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
 	switch (evt) {
+	case NETDEV_CHANGENAME:
+		if (netif_carrier_ok(dev))
+			set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
+		fallthrough;
 	case NETDEV_REGISTER:
 		if (trigger_data->net_dev)
 			dev_put(trigger_data->net_dev);
--- linux-ein-5.4.0.orig/drivers/leds/trigger/ledtrig-panic.c
+++ linux-ein-5.4.0/drivers/leds/trigger/ledtrig-panic.c
@@ -63,10 +63,13 @@
 
 static int __init ledtrig_panic_init(void)
 {
+	led_trigger_register_simple("panic", &trigger);
+	if (!trigger)
+		return -ENOMEM;
+
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &led_trigger_panic_nb);
 
-	led_trigger_register_simple("panic", &trigger);
 	panic_blink = led_panic_blink;
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/lightnvm/Kconfig
+++ linux-ein-5.4.0/drivers/lightnvm/Kconfig
@@ -5,7 +5,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.
 
@@ -19,6 +19,7 @@
 
 config NVM_PBLK
 	tristate "Physical Block Device Open-Channel SSD target"
+	select CRC32
 	help
 	  Allows an open-channel SSD to be exposed as a block device to the
 	  host. The target assumes the device exposes raw flash and must be
--- linux-ein-5.4.0.orig/drivers/lightnvm/core.c
+++ linux-ein-5.4.0/drivers/lightnvm/core.c
@@ -849,11 +849,10 @@
 	rqd.ppa_addr = generic_to_dev_addr(dev, ppa);
 
 	ret = nvm_submit_io_sync_raw(dev, &rqd);
+	__free_page(page);
 	if (ret)
 		return ret;
 
-	__free_page(page);
-
 	return rqd.error;
 }
 
@@ -1316,8 +1315,9 @@
 		strlcpy(info->bmname, "gennvm", sizeof(info->bmname));
 		i++;
 
-		if (i > 31) {
-			pr_err("max 31 devices can be reported.\n");
+		if (i >= ARRAY_SIZE(devices->info)) {
+			pr_err("max %zd devices can be reported.\n",
+			       ARRAY_SIZE(devices->info));
 			break;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/macintosh/Kconfig
+++ linux-ein-5.4.0/drivers/macintosh/Kconfig
@@ -44,6 +44,7 @@
 config ADB_CUDA
 	bool "Support for Cuda/Egret based Macs and PowerMacs"
 	depends on (ADB || PPC_PMAC) && !PPC_PMAC64
+	select RTC_LIB
 	help
 	  This provides support for Cuda/Egret based Macintosh and
 	  Power Macintosh systems. This includes most m68k based Macs,
@@ -57,6 +58,7 @@
 config ADB_PMU
 	bool "Support for PMU based PowerMacs and PowerBooks"
 	depends on PPC_PMAC || MAC
+	select RTC_LIB
 	help
 	  On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
 	  PMU is an embedded microprocessor whose primary function is to
@@ -67,6 +69,10 @@
 	  this device; you should do so if your machine is one of those
 	  mentioned above.
 
+config ADB_PMU_EVENT
+	def_bool y
+	depends on ADB_PMU && INPUT=y
+
 config ADB_PMU_LED
 	bool "Support for the Power/iBook front LED"
 	depends on PPC_PMAC && ADB_PMU
@@ -80,6 +86,7 @@
 
 config ADB_PMU_LED_DISK
 	bool "Use front LED as DISK LED by default"
+	depends on ATA
 	depends on ADB_PMU_LED
 	depends on LEDS_CLASS
 	select LEDS_TRIGGERS
--- linux-ein-5.4.0.orig/drivers/macintosh/Makefile
+++ linux-ein-5.4.0/drivers/macintosh/Makefile
@@ -12,7 +12,8 @@
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
 
-obj-$(CONFIG_ADB_PMU)		+= via-pmu.o via-pmu-event.o
+obj-$(CONFIG_ADB_PMU)		+= via-pmu.o
+obj-$(CONFIG_ADB_PMU_EVENT)	+= via-pmu-event.o
 obj-$(CONFIG_ADB_PMU_LED)	+= via-pmu-led.o
 obj-$(CONFIG_PMAC_BACKLIGHT)	+= via-pmu-backlight.o
 obj-$(CONFIG_ADB_CUDA)		+= via-cuda.o
--- linux-ein-5.4.0.orig/drivers/macintosh/adb.c
+++ linux-ein-5.4.0/drivers/macintosh/adb.c
@@ -647,7 +647,7 @@
 
 	switch(req->data[1]) {
 	case ADB_QUERY_GETDEVINFO:
-		if (req->nbytes < 3)
+		if (req->nbytes < 3 || req->data[2] >= 16)
 			break;
 		mutex_lock(&adb_handler_mutex);
 		req->reply[0] = adb_handler[req->data[2]].original_address;
--- linux-ein-5.4.0.orig/drivers/macintosh/macio-adb.c
+++ linux-ein-5.4.0/drivers/macintosh/macio-adb.c
@@ -106,6 +106,10 @@
 		return -ENXIO;
 	}
 	adb = ioremap(r.start, sizeof(struct adb_regs));
+	if (!adb) {
+		of_node_put(adbs);
+		return -ENOMEM;
+	}
 
 	out_8(&adb->ctrl.r, 0);
 	out_8(&adb->intr.r, 0);
--- linux-ein-5.4.0.orig/drivers/macintosh/macio_asic.c
+++ linux-ein-5.4.0/drivers/macintosh/macio_asic.c
@@ -425,7 +425,7 @@
 	if (of_device_register(&dev->ofdev) != 0) {
 		printk(KERN_DEBUG"macio: device registration error for %s!\n",
 		       dev_name(&dev->ofdev.dev));
-		kfree(dev);
+		put_device(&dev->ofdev.dev);
 		return NULL;
 	}
 
--- linux-ein-5.4.0.orig/drivers/macintosh/therm_windtunnel.c
+++ linux-ein-5.4.0/drivers/macintosh/therm_windtunnel.c
@@ -300,9 +300,11 @@
 /*	i2c probing and setup						*/
 /************************************************************************/
 
-static int
-do_attach( struct i2c_adapter *adapter )
+static void do_attach(struct i2c_adapter *adapter)
 {
+	struct i2c_board_info info = { };
+	struct device_node *np;
+
 	/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
 	static const unsigned short scan_ds1775[] = {
 		0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
@@ -313,25 +315,24 @@
 		I2C_CLIENT_END
 	};
 
-	if( strncmp(adapter->name, "uni-n", 5) )
-		return 0;
-
-	if( !x.running ) {
-		struct i2c_board_info info;
+	if (x.running || strncmp(adapter->name, "uni-n", 5))
+		return;
 
-		memset(&info, 0, sizeof(struct i2c_board_info));
-		strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
+	np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,ds1775");
+	if (np) {
+		of_node_put(np);
+	} else {
+		strlcpy(info.type, "MAC,ds1775", I2C_NAME_SIZE);
 		i2c_new_probed_device(adapter, &info, scan_ds1775, NULL);
+	}
 
-		strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
+	np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,adm1030");
+	if (np) {
+		of_node_put(np);
+	} else {
+		strlcpy(info.type, "MAC,adm1030", I2C_NAME_SIZE);
 		i2c_new_probed_device(adapter, &info, scan_adm1030, NULL);
-
-		if( x.thermostat && x.fan ) {
-			x.running = 1;
-			x.poll_task = kthread_run(control_loop, NULL, "g4fand");
-		}
 	}
-	return 0;
 }
 
 static int
@@ -404,8 +405,8 @@
 enum chip { ds1775, adm1030 };
 
 static const struct i2c_device_id therm_windtunnel_id[] = {
-	{ "therm_ds1775", ds1775 },
-	{ "therm_adm1030", adm1030 },
+	{ "MAC,ds1775", ds1775 },
+	{ "MAC,adm1030", adm1030 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, therm_windtunnel_id);
@@ -414,6 +415,7 @@
 do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adapter = cl->adapter;
+	int ret = 0;
 
 	if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
 				     | I2C_FUNC_SMBUS_WRITE_BYTE) )
@@ -421,11 +423,19 @@
 
 	switch (id->driver_data) {
 	case adm1030:
-		return attach_fan( cl );
+		ret = attach_fan(cl);
+		break;
 	case ds1775:
-		return attach_thermostat(cl);
+		ret = attach_thermostat(cl);
+		break;
 	}
-	return 0;
+
+	if (!x.running && x.thermostat && x.fan) {
+		x.running = 1;
+		x.poll_task = kthread_run(control_loop, NULL, "g4fand");
+	}
+
+	return ret;
 }
 
 static struct i2c_driver g4fan_driver = {
--- linux-ein-5.4.0.orig/drivers/macintosh/via-macii.c
+++ linux-ein-5.4.0/drivers/macintosh/via-macii.c
@@ -270,15 +270,12 @@
 	unsigned long flags;
 	int err = 0;
 
+	local_irq_save(flags);
+
 	/* bit 1 == device 1, and so on. */
 	autopoll_devs = devs & 0xFFFE;
 
-	if (!autopoll_devs)
-		return 0;
-
-	local_irq_save(flags);
-
-	if (current_req == NULL) {
+	if (autopoll_devs && !current_req) {
 		/* Send a Talk Reg 0. The controller will repeatedly transmit
 		 * this as long as it is idle.
 		 */
--- linux-ein-5.4.0.orig/drivers/macintosh/via-pmu.c
+++ linux-ein-5.4.0/drivers/macintosh/via-pmu.c
@@ -1464,7 +1464,7 @@
 		pmu_pass_intr(data, len);
 		/* len == 6 is probably a bad check. But how do I
 		 * know what PMU versions send what events here? */
-		if (len == 6) {
+		if (IS_ENABLED(CONFIG_ADB_PMU_EVENT) && len == 6) {
 			via_pmu_event(PMU_EVT_POWER, !!(data[1]&8));
 			via_pmu_event(PMU_EVT_LID, data[1]&1);
 		}
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_ad7417_sensor.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_ad7417_sensor.c
@@ -312,9 +312,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
 
+static const struct of_device_id wf_ad7417_of_id[] = {
+	{ .compatible = "ad7417", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_ad7417_of_id);
+
 static struct i2c_driver wf_ad7417_driver = {
 	.driver = {
 		.name	= "wf_ad7417",
+		.of_match_table = wf_ad7417_of_id,
 	},
 	.probe		= wf_ad7417_probe,
 	.remove		= wf_ad7417_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_fcu_controls.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_fcu_controls.c
@@ -582,9 +582,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
 
+static const struct of_device_id wf_fcu_of_id[] = {
+	{ .compatible = "fcu", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_fcu_of_id);
+
 static struct i2c_driver wf_fcu_driver = {
 	.driver = {
 		.name	= "wf_fcu",
+		.of_match_table = wf_fcu_of_id,
 	},
 	.probe		= wf_fcu_probe,
 	.remove		= wf_fcu_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_lm75_sensor.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_lm75_sensor.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -33,8 +34,8 @@
 #endif
 
 struct wf_lm75_sensor {
-	int			ds1775 : 1;
-	int			inited : 1;
+	unsigned int		ds1775 : 1;
+	unsigned int		inited : 1;
 	struct i2c_client	*i2c;
 	struct wf_sensor	sens;
 };
@@ -91,9 +92,14 @@
 			 const struct i2c_device_id *id)
 {	
 	struct wf_lm75_sensor *lm;
-	int rc, ds1775 = id->driver_data;
+	int rc, ds1775;
 	const char *name, *loc;
 
+	if (id)
+		ds1775 = id->driver_data;
+	else
+		ds1775 = !!of_device_get_match_data(&client->dev);
+
 	DBG("wf_lm75: creating  %s device at address 0x%02x\n",
 	    ds1775 ? "ds1775" : "lm75", client->addr);
 
@@ -164,9 +170,17 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
 
+static const struct of_device_id wf_lm75_of_id[] = {
+	{ .compatible = "lm75", .data = (void *)0},
+	{ .compatible = "ds1775", .data = (void *)1 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_lm75_of_id);
+
 static struct i2c_driver wf_lm75_driver = {
 	.driver = {
 		.name	= "wf_lm75",
+		.of_match_table = wf_lm75_of_id,
 	},
 	.probe		= wf_lm75_probe,
 	.remove		= wf_lm75_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_lm87_sensor.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_lm87_sensor.c
@@ -166,9 +166,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
 
+static const struct of_device_id wf_lm87_of_id[] = {
+	{ .compatible = "lm87cimt", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_lm87_of_id);
+
 static struct i2c_driver wf_lm87_driver = {
 	.driver = {
 		.name	= "wf_lm87",
+		.of_match_table = wf_lm87_of_id,
 	},
 	.probe		= wf_lm87_probe,
 	.remove		= wf_lm87_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_max6690_sensor.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_max6690_sensor.c
@@ -120,9 +120,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
 
+static const struct of_device_id wf_max6690_of_id[] = {
+	{ .compatible = "max6690", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_max6690_of_id);
+
 static struct i2c_driver wf_max6690_driver = {
 	.driver = {
 		.name		= "wf_max6690",
+		.of_match_table = wf_max6690_of_id,
 	},
 	.probe		= wf_max6690_probe,
 	.remove		= wf_max6690_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_pm112.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_pm112.c
@@ -132,14 +132,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) {
@@ -152,6 +144,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,
@@ -174,6 +176,9 @@
 		pid.min = fmin;
 
 	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+
+	kfree(hdr);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_smu_sat.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_smu_sat.c
@@ -171,6 +171,7 @@
 
 	if (sat->nr >= 0)
 		sats[sat->nr] = NULL;
+	of_node_put(sat->node);
 	kfree(sat);
 }
 
@@ -341,9 +342,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wf_sat_id);
 
+static const struct of_device_id wf_sat_of_id[] = {
+	{ .compatible = "smu-sat", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wf_sat_of_id);
+
 static struct i2c_driver wf_sat_driver = {
 	.driver = {
 		.name		= "wf_smu_sat",
+		.of_match_table = wf_sat_of_id,
 	},
 	.probe		= wf_sat_probe,
 	.remove		= wf_sat_remove,
--- linux-ein-5.4.0.orig/drivers/macintosh/windfarm_smu_sensors.c
+++ linux-ein-5.4.0/drivers/macintosh/windfarm_smu_sensors.c
@@ -273,8 +273,8 @@
 	struct list_head	link;
 	struct wf_sensor	*volts;
 	struct wf_sensor	*amps;
-	int			fake_volts : 1;
-	int			quadratic : 1;
+	unsigned int		fake_volts : 1;
+	unsigned int		quadratic : 1;
 	struct wf_sensor	sens;
 };
 #define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens)
--- linux-ein-5.4.0.orig/drivers/mailbox/bcm-flexrm-mailbox.c
+++ linux-ein-5.4.0/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -632,15 +632,15 @@
 
 	rc = dma_map_sg(dev, msg->spu.src, sg_nents(msg->spu.src),
 			DMA_TO_DEVICE);
-	if (rc < 0)
-		return rc;
+	if (!rc)
+		return -EIO;
 
 	rc = dma_map_sg(dev, msg->spu.dst, sg_nents(msg->spu.dst),
 			DMA_FROM_DEVICE);
-	if (rc < 0) {
+	if (!rc) {
 		dma_unmap_sg(dev, msg->spu.src, sg_nents(msg->spu.src),
 			     DMA_TO_DEVICE);
-		return rc;
+		return -EIO;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/mailbox/imx-mailbox.c
+++ linux-ein-5.4.0/drivers/mailbox/imx-mailbox.c
@@ -12,19 +12,11 @@
 #include <linux/of_device.h>
 #include <linux/slab.h>
 
-/* Transmit Register */
-#define IMX_MU_xTRn(x)		(0x00 + 4 * (x))
-/* Receive Register */
-#define IMX_MU_xRRn(x)		(0x10 + 4 * (x))
-/* Status Register */
-#define IMX_MU_xSR		0x20
 #define IMX_MU_xSR_GIPn(x)	BIT(28 + (3 - (x)))
 #define IMX_MU_xSR_RFn(x)	BIT(24 + (3 - (x)))
 #define IMX_MU_xSR_TEn(x)	BIT(20 + (3 - (x)))
 #define IMX_MU_xSR_BRDIP	BIT(9)
 
-/* Control Register */
-#define IMX_MU_xCR		0x24
 /* General Purpose Interrupt Enable */
 #define IMX_MU_xCR_GIEn(x)	BIT(28 + (3 - (x)))
 /* Receive Interrupt Enable */
@@ -44,6 +36,13 @@
 	IMX_MU_TYPE_RXDB,	/* Rx doorbell */
 };
 
+struct imx_mu_dcfg {
+	u32	xTR[4];		/* Transmit Registers */
+	u32	xRR[4];		/* Receive Registers */
+	u32	xSR;		/* Status Register */
+	u32	xCR;		/* Control Register */
+};
+
 struct imx_mu_con_priv {
 	unsigned int		idx;
 	char			irq_desc[IMX_MU_CHAN_NAME_SIZE];
@@ -61,12 +60,30 @@
 	struct mbox_chan	mbox_chans[IMX_MU_CHANS];
 
 	struct imx_mu_con_priv  con_priv[IMX_MU_CHANS];
+	const struct imx_mu_dcfg	*dcfg;
 	struct clk		*clk;
 	int			irq;
 
+	/* for control register save and restore */
+	u32 xcr;
+
 	bool			side_b;
 };
 
+static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
+	.xTR	= {0x0, 0x4, 0x8, 0xc},
+	.xRR	= {0x10, 0x14, 0x18, 0x1c},
+	.xSR	= 0x20,
+	.xCR	= 0x24,
+};
+
+static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
+	.xTR	= {0x20, 0x24, 0x28, 0x2c},
+	.xRR	= {0x40, 0x44, 0x48, 0x4c},
+	.xSR	= 0x60,
+	.xCR	= 0x64,
+};
+
 static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
 {
 	return container_of(mbox, struct imx_mu_priv, mbox);
@@ -88,10 +105,10 @@
 	u32 val;
 
 	spin_lock_irqsave(&priv->xcr_lock, flags);
-	val = imx_mu_read(priv, IMX_MU_xCR);
+	val = imx_mu_read(priv, priv->dcfg->xCR);
 	val &= ~clr;
 	val |= set;
-	imx_mu_write(priv, val, IMX_MU_xCR);
+	imx_mu_write(priv, val, priv->dcfg->xCR);
 	spin_unlock_irqrestore(&priv->xcr_lock, flags);
 
 	return val;
@@ -111,8 +128,8 @@
 	struct imx_mu_con_priv *cp = chan->con_priv;
 	u32 val, ctrl, dat;
 
-	ctrl = imx_mu_read(priv, IMX_MU_xCR);
-	val = imx_mu_read(priv, IMX_MU_xSR);
+	ctrl = imx_mu_read(priv, priv->dcfg->xCR);
+	val = imx_mu_read(priv, priv->dcfg->xSR);
 
 	switch (cp->type) {
 	case IMX_MU_TYPE_TX:
@@ -138,10 +155,10 @@
 		imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
 		mbox_chan_txdone(chan, 0);
 	} else if (val == IMX_MU_xSR_RFn(cp->idx)) {
-		dat = imx_mu_read(priv, IMX_MU_xRRn(cp->idx));
+		dat = imx_mu_read(priv, priv->dcfg->xRR[cp->idx]);
 		mbox_chan_received_data(chan, (void *)&dat);
 	} else if (val == IMX_MU_xSR_GIPn(cp->idx)) {
-		imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), IMX_MU_xSR);
+		imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), priv->dcfg->xSR);
 		mbox_chan_received_data(chan, NULL);
 	} else {
 		dev_warn_ratelimited(priv->dev, "Not handled interrupt\n");
@@ -159,7 +176,7 @@
 
 	switch (cp->type) {
 	case IMX_MU_TYPE_TX:
-		imx_mu_write(priv, *arg, IMX_MU_xTRn(cp->idx));
+		imx_mu_write(priv, *arg, priv->dcfg->xTR[cp->idx]);
 		imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0);
 		break;
 	case IMX_MU_TYPE_TXDB:
@@ -214,11 +231,24 @@
 	struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox);
 	struct imx_mu_con_priv *cp = chan->con_priv;
 
-	if (cp->type == IMX_MU_TYPE_TXDB)
+	if (cp->type == IMX_MU_TYPE_TXDB) {
 		tasklet_kill(&cp->txdb_tasklet);
+		return;
+	}
 
-	imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx) |
-		       IMX_MU_xCR_RIEn(cp->idx) | IMX_MU_xCR_GIEn(cp->idx));
+	switch (cp->type) {
+	case IMX_MU_TYPE_TX:
+		imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
+		break;
+	case IMX_MU_TYPE_RX:
+		imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(cp->idx));
+		break;
+	case IMX_MU_TYPE_RXDB:
+		imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_GIEn(cp->idx));
+		break;
+	default:
+		break;
+	}
 
 	free_irq(priv->irq, chan);
 }
@@ -257,7 +287,7 @@
 		return;
 
 	/* Set default MU configuration */
-	imx_mu_write(priv, 0, IMX_MU_xCR);
+	imx_mu_write(priv, 0, priv->dcfg->xCR);
 }
 
 static int imx_mu_probe(struct platform_device *pdev)
@@ -265,6 +295,7 @@
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct imx_mu_priv *priv;
+	const struct imx_mu_dcfg *dcfg;
 	unsigned int i;
 	int ret;
 
@@ -282,6 +313,11 @@
 	if (priv->irq < 0)
 		return priv->irq;
 
+	dcfg = of_device_get_match_data(dev);
+	if (!dcfg)
+		return -EINVAL;
+	priv->dcfg = dcfg;
+
 	priv->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(priv->clk)) {
 		if (PTR_ERR(priv->clk) != -ENOENT)
@@ -334,8 +370,32 @@
 	return 0;
 }
 
+static int imx_mu_suspend_noirq(struct device *dev)
+{
+	struct imx_mu_priv *priv = dev_get_drvdata(dev);
+
+	priv->xcr = imx_mu_read(priv, priv->dcfg->xCR);
+
+        return 0;
+}
+
+static int imx_mu_resume_noirq(struct device *dev)
+{
+	struct imx_mu_priv *priv = dev_get_drvdata(dev);
+
+	imx_mu_write(priv, priv->xcr, priv->dcfg->xCR);
+
+	return 0;
+}
+
+static const struct dev_pm_ops imx_mu_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_mu_suspend_noirq,
+				      imx_mu_resume_noirq)
+};
+
 static const struct of_device_id imx_mu_dt_ids[] = {
-	{ .compatible = "fsl,imx6sx-mu" },
+	{ .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp },
+	{ .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
@@ -346,9 +406,23 @@
 	.driver = {
 		.name	= "imx_mu",
 		.of_match_table = imx_mu_dt_ids,
+		.pm = &imx_mu_pm_ops,
 	},
 };
-module_platform_driver(imx_mu_driver);
+static int __init imx_mu_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&imx_mu_driver);
+	if (ret)
+		pr_err("Unable to initialize mu driver\n");
+	else
+		pr_info("imx mu driver is registered.\n");
+
+	return ret;
+}
+
+arch_initcall(imx_mu_init);
 
 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
 MODULE_DESCRIPTION("Message Unit driver for i.MX");
--- linux-ein-5.4.0.orig/drivers/mailbox/mailbox-test.c
+++ linux-ein-5.4.0/drivers/mailbox/mailbox-test.c
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/poll.h>
@@ -38,6 +39,7 @@
 	char			*signal;
 	char			*message;
 	spinlock_t		lock;
+	struct mutex		mutex;
 	wait_queue_head_t	waitq;
 	struct fasync_struct	*async_queue;
 	struct dentry		*root_debugfs_dir;
@@ -95,6 +97,7 @@
 				       size_t count, loff_t *ppos)
 {
 	struct mbox_test_device *tdev = filp->private_data;
+	char *message;
 	void *data;
 	int ret;
 
@@ -110,10 +113,13 @@
 		return -EINVAL;
 	}
 
-	tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
-	if (!tdev->message)
+	message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
+	if (!message)
 		return -ENOMEM;
 
+	mutex_lock(&tdev->mutex);
+
+	tdev->message = message;
 	ret = copy_from_user(tdev->message, userbuf, count);
 	if (ret) {
 		ret = -EFAULT;
@@ -144,6 +150,8 @@
 	kfree(tdev->message);
 	tdev->signal = NULL;
 
+	mutex_unlock(&tdev->mutex);
+
 	return ret < 0 ? ret : count;
 }
 
@@ -392,6 +400,7 @@
 	platform_set_drvdata(pdev, tdev);
 
 	spin_lock_init(&tdev->lock);
+	mutex_init(&tdev->mutex);
 
 	if (tdev->rx_channel) {
 		tdev->rx_buffer = devm_kzalloc(&pdev->dev,
--- linux-ein-5.4.0.orig/drivers/mailbox/mailbox.c
+++ linux-ein-5.4.0/drivers/mailbox/mailbox.c
@@ -82,9 +82,12 @@
 exit:
 	spin_unlock_irqrestore(&chan->lock, flags);
 
-	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
+	if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
 		/* kick start the timer immediately to avoid delays */
+		spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags);
 		hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+		spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags);
+	}
 }
 
 static void tx_tick(struct mbox_chan *chan, int r)
@@ -117,6 +120,7 @@
 		container_of(hrtimer, struct mbox_controller, poll_hrt);
 	bool txdone, resched = false;
 	int i;
+	unsigned long flags;
 
 	for (i = 0; i < mbox->num_chans; i++) {
 		struct mbox_chan *chan = &mbox->chans[i];
@@ -131,7 +135,11 @@
 	}
 
 	if (resched) {
-		hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
+		spin_lock_irqsave(&mbox->poll_hrt_lock, flags);
+		if (!hrtimer_is_queued(hrtimer))
+			hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
+		spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags);
+
 		return HRTIMER_RESTART;
 	}
 	return HRTIMER_NORESTART;
@@ -498,6 +506,7 @@
 		hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
 			     HRTIMER_MODE_REL);
 		mbox->poll_hrt.function = txdone_hrtimer;
+		spin_lock_init(&mbox->poll_hrt_lock);
 	}
 
 	for (i = 0; i < mbox->num_chans; i++) {
--- linux-ein-5.4.0.orig/drivers/mailbox/mtk-cmdq-mailbox.c
+++ linux-ein-5.4.0/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -70,7 +70,7 @@
 struct cmdq {
 	struct mbox_controller	mbox;
 	void __iomem		*base;
-	u32			irq;
+	int			irq;
 	u32			thread_nr;
 	u32			irq_mask;
 	struct cmdq_thread	*thread;
@@ -474,10 +474,8 @@
 	}
 
 	cmdq->irq = platform_get_irq(pdev, 0);
-	if (!cmdq->irq) {
-		dev_err(dev, "failed to get irq\n");
-		return -EINVAL;
-	}
+	if (cmdq->irq < 0)
+		return cmdq->irq;
 
 	cmdq->thread_nr = (u32)(unsigned long)of_device_get_match_data(dev);
 	cmdq->irq_mask = GENMASK(cmdq->thread_nr - 1, 0);
--- linux-ein-5.4.0.orig/drivers/mailbox/tegra-hsp.c
+++ linux-ein-5.4.0/drivers/mailbox/tegra-hsp.c
@@ -403,6 +403,11 @@
 		value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX);
 		if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) {
 			mbox_chan_txdone(chan, 0);
+
+			/* Wait until channel is empty */
+			if (chan->active_req != NULL)
+				continue;
+
 			return 0;
 		}
 
@@ -657,7 +662,7 @@
 	hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK;
 	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
 
-	err = platform_get_irq_byname(pdev, "doorbell");
+	err = platform_get_irq_byname_optional(pdev, "doorbell");
 	if (err >= 0)
 		hsp->doorbell_irq = err;
 
@@ -677,7 +682,7 @@
 			if (!name)
 				return -ENOMEM;
 
-			err = platform_get_irq_byname(pdev, name);
+			err = platform_get_irq_byname_optional(pdev, name);
 			if (err >= 0) {
 				hsp->shared_irqs[i] = err;
 				count++;
--- linux-ein-5.4.0.orig/drivers/mailbox/ti-msgmgr.c
+++ linux-ein-5.4.0/drivers/mailbox/ti-msgmgr.c
@@ -385,14 +385,20 @@
 		/* Ensure all unused data is 0 */
 		data_trail &= 0xFFFFFFFF >> (8 * (sizeof(u32) - trail_bytes));
 		writel(data_trail, data_reg);
-		data_reg++;
+		data_reg += sizeof(u32);
 	}
+
 	/*
 	 * 'data_reg' indicates next register to write. If we did not already
 	 * write on tx complete reg(last reg), we must do so for transmit
+	 * In addition, we also need to make sure all intermediate data
+	 * registers(if any required), are reset to 0 for TISCI backward
+	 * compatibility to be maintained.
 	 */
-	if (data_reg <= qinst->queue_buff_end)
-		writel(0, qinst->queue_buff_end);
+	while (data_reg <= qinst->queue_buff_end) {
+		writel(0, data_reg);
+		data_reg += sizeof(u32);
+	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mailbox/zynqmp-ipi-mailbox.c
+++ linux-ein-5.4.0/drivers/mailbox/zynqmp-ipi-mailbox.c
@@ -110,7 +110,7 @@
 	unsigned int method;
 	u32 local_id;
 	int num_mboxes;
-	struct zynqmp_ipi_mbox *ipi_mboxes;
+	struct zynqmp_ipi_mbox ipi_mboxes[];
 };
 
 static struct device_driver zynqmp_ipi_mbox_driver = {
@@ -152,7 +152,7 @@
 	struct zynqmp_ipi_message *msg;
 	u64 arg0, arg3;
 	struct arm_smccc_res res;
-	int ret, i;
+	int ret, i, status = IRQ_NONE;
 
 	(void)irq;
 	arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY;
@@ -170,11 +170,11 @@
 				memcpy_fromio(msg->data, mchan->req_buf,
 					      msg->len);
 				mbox_chan_received_data(chan, (void *)msg);
-				return IRQ_HANDLED;
+				status = IRQ_HANDLED;
 			}
 		}
 	}
-	return IRQ_NONE;
+	return status;
 }
 
 /**
@@ -493,6 +493,7 @@
 	ret = device_register(&ipi_mbox->dev);
 	if (ret) {
 		dev_err(dev, "Failed to register ipi mbox dev.\n");
+		put_device(&ipi_mbox->dev);
 		return ret;
 	}
 	mdev = &ipi_mbox->dev;
@@ -504,10 +505,9 @@
 		mchan->req_buf_size = resource_size(&res);
 		mchan->req_buf = devm_ioremap(mdev, res.start,
 					      mchan->req_buf_size);
-		if (IS_ERR(mchan->req_buf)) {
+		if (!mchan->req_buf) {
 			dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
-			ret = PTR_ERR(mchan->req_buf);
-			return ret;
+			return -ENOMEM;
 		}
 	} else if (ret != -ENODEV) {
 		dev_err(mdev, "Unmatched resource %s, %d.\n", name, ret);
@@ -520,10 +520,9 @@
 		mchan->resp_buf_size = resource_size(&res);
 		mchan->resp_buf = devm_ioremap(mdev, res.start,
 					       mchan->resp_buf_size);
-		if (IS_ERR(mchan->resp_buf)) {
+		if (!mchan->resp_buf) {
 			dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
-			ret = PTR_ERR(mchan->resp_buf);
-			return ret;
+			return -ENOMEM;
 		}
 	} else if (ret != -ENODEV) {
 		dev_err(mdev, "Unmatched resource %s.\n", name);
@@ -543,10 +542,9 @@
 		mchan->req_buf_size = resource_size(&res);
 		mchan->req_buf = devm_ioremap(mdev, res.start,
 					      mchan->req_buf_size);
-		if (IS_ERR(mchan->req_buf)) {
+		if (!mchan->req_buf) {
 			dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
-			ret = PTR_ERR(mchan->req_buf);
-			return ret;
+			return -ENOMEM;
 		}
 	} else if (ret != -ENODEV) {
 		dev_err(mdev, "Unmatched resource %s.\n", name);
@@ -559,10 +557,9 @@
 		mchan->resp_buf_size = resource_size(&res);
 		mchan->resp_buf = devm_ioremap(mdev, res.start,
 					       mchan->resp_buf_size);
-		if (IS_ERR(mchan->resp_buf)) {
+		if (!mchan->resp_buf) {
 			dev_err(mdev, "Unable to map IPI buffer I/O memory\n");
-			ret = PTR_ERR(mchan->resp_buf);
-			return ret;
+			return -ENOMEM;
 		}
 	} else if (ret != -ENODEV) {
 		dev_err(mdev, "Unmatched resource %s.\n", name);
@@ -623,7 +620,8 @@
 		ipi_mbox = &pdata->ipi_mboxes[i];
 		if (ipi_mbox->dev.parent) {
 			mbox_controller_unregister(&ipi_mbox->mbox);
-			device_unregister(&ipi_mbox->dev);
+			if (device_is_registered(&ipi_mbox->dev))
+				device_unregister(&ipi_mbox->dev);
 		}
 	}
 }
@@ -636,8 +634,13 @@
 	struct zynqmp_ipi_mbox *mbox;
 	int num_mboxes, ret = -EINVAL;
 
-	num_mboxes = of_get_child_count(np);
-	pdata = devm_kzalloc(dev, sizeof(*pdata) + (num_mboxes * sizeof(*mbox)),
+	num_mboxes = of_get_available_child_count(np);
+	if (num_mboxes == 0) {
+		dev_err(dev, "mailbox nodes not available\n");
+		return -EINVAL;
+	}
+
+	pdata = devm_kzalloc(dev, struct_size(pdata, ipi_mboxes, num_mboxes),
 			     GFP_KERNEL);
 	if (!pdata)
 		return -ENOMEM;
@@ -651,8 +654,6 @@
 	}
 
 	pdata->num_mboxes = num_mboxes;
-	pdata->ipi_mboxes = (struct zynqmp_ipi_mbox *)
-			    ((char *)pdata + sizeof(*pdata));
 
 	mbox = pdata->ipi_mboxes;
 	for_each_available_child_of_node(np, nc) {
--- linux-ein-5.4.0.orig/drivers/mcb/mcb-core.c
+++ linux-ein-5.4.0/drivers/mcb/mcb-core.c
@@ -71,8 +71,10 @@
 
 	get_device(dev);
 	ret = mdrv->probe(mdev, found_id);
-	if (ret)
+	if (ret) {
 		module_put(carrier_mod);
+		put_device(dev);
+	}
 
 	return ret;
 }
@@ -246,6 +248,7 @@
 	return 0;
 
 out:
+	put_device(&dev->dev);
 
 	return ret;
 }
@@ -277,8 +280,8 @@
 
 	bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
 	if (bus_nr < 0) {
-		rc = bus_nr;
-		goto err_free;
+		kfree(bus);
+		return ERR_PTR(bus_nr);
 	}
 
 	bus->bus_nr = bus_nr;
@@ -293,12 +296,12 @@
 	dev_set_name(&bus->dev, "mcb:%d", bus_nr);
 	rc = device_add(&bus->dev);
 	if (rc)
-		goto err_free;
+		goto err_put;
 
 	return bus;
-err_free:
-	put_device(carrier);
-	kfree(bus);
+
+err_put:
+	put_device(&bus->dev);
 	return ERR_PTR(rc);
 }
 EXPORT_SYMBOL_GPL(mcb_alloc_bus);
@@ -387,17 +390,13 @@
 
 static int __mcb_bus_add_devices(struct device *dev, void *data)
 {
-	struct mcb_device *mdev = to_mcb_device(dev);
 	int retval;
 
-	if (mdev->is_added)
-		return 0;
-
 	retval = device_attach(dev);
-	if (retval < 0)
+	if (retval < 0) {
 		dev_err(dev, "Error adding device (%d)\n", retval);
-
-	mdev->is_added = true;
+		return retval;
+	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mcb/mcb-lpc.c
+++ linux-ein-5.4.0/drivers/mcb/mcb-lpc.c
@@ -23,7 +23,7 @@
 {
 	struct resource *res;
 	struct priv *priv;
-	int ret = 0;
+	int ret = 0, table_size;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -58,16 +58,43 @@
 
 	ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base);
 	if (ret < 0) {
-		mcb_release_bus(priv->bus);
-		return ret;
+		goto out_mcb_bus;
 	}
 
-	dev_dbg(&pdev->dev, "Found %d cells\n", ret);
+	table_size = ret;
+
+	if (table_size < CHAM_HEADER_SIZE) {
+		/* Release the previous resources */
+		devm_iounmap(&pdev->dev, priv->base);
+		devm_release_mem_region(&pdev->dev, priv->mem->start, resource_size(priv->mem));
+
+		/* Then, allocate it again with the actual chameleon table size */
+		res = devm_request_mem_region(&pdev->dev, priv->mem->start,
+					      table_size,
+					      KBUILD_MODNAME);
+		if (!res) {
+			dev_err(&pdev->dev, "Failed to request PCI memory\n");
+			ret = -EBUSY;
+			goto out_mcb_bus;
+		}
+
+		priv->base = devm_ioremap(&pdev->dev, priv->mem->start, table_size);
+		if (!priv->base) {
+			dev_err(&pdev->dev, "Cannot ioremap\n");
+			ret = -ENOMEM;
+			goto out_mcb_bus;
+		}
+
+		platform_set_drvdata(pdev, priv);
+	}
 
 	mcb_bus_add_devices(priv->bus);
 
 	return 0;
 
+out_mcb_bus:
+	mcb_release_bus(priv->bus);
+	return ret;
 }
 
 static int mcb_lpc_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/mcb/mcb-parse.c
+++ linux-ein-5.4.0/drivers/mcb/mcb-parse.c
@@ -99,8 +99,6 @@
 	mdev->mem.end = mdev->mem.start + size - 1;
 	mdev->mem.flags = IORESOURCE_MEM;
 
-	mdev->is_added = false;
-
 	ret = mcb_device_register(bus, mdev);
 	if (ret < 0)
 		goto err;
@@ -130,7 +128,7 @@
 	}
 }
 
-static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
+static int chameleon_get_bar(void __iomem **base, phys_addr_t mapbase,
 			     struct chameleon_bar **cb)
 {
 	struct chameleon_bar *c;
@@ -179,12 +177,13 @@
 {
 	struct chameleon_fpga_header *header;
 	struct chameleon_bar *cb;
-	char __iomem *p = base;
+	void __iomem *p = base;
 	int num_cells = 0;
 	uint32_t dtype;
 	int bar_count;
 	int ret;
 	u32 hsize;
+	u32 table_size;
 
 	hsize = sizeof(struct chameleon_fpga_header);
 
@@ -239,12 +238,16 @@
 		num_cells++;
 	}
 
-	if (num_cells == 0)
-		num_cells = -EINVAL;
+	if (num_cells == 0) {
+		ret = -EINVAL;
+		goto free_bar;
+	}
 
+	table_size = p - base;
+	pr_debug("%d cell(s) found. Chameleon table size: 0x%04x bytes\n", num_cells, table_size);
 	kfree(cb);
 	kfree(header);
-	return num_cells;
+	return table_size;
 
 free_bar:
 	kfree(cb);
--- linux-ein-5.4.0.orig/drivers/mcb/mcb-pci.c
+++ linux-ein-5.4.0/drivers/mcb/mcb-pci.c
@@ -31,7 +31,7 @@
 {
 	struct resource *res;
 	struct priv *priv;
-	int ret;
+	int ret, table_size;
 	unsigned long flags;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
@@ -90,7 +90,30 @@
 	if (ret < 0)
 		goto out_mcb_bus;
 
-	dev_dbg(&pdev->dev, "Found %d cells\n", ret);
+	table_size = ret;
+
+	if (table_size < CHAM_HEADER_SIZE) {
+		/* Release the previous resources */
+		devm_iounmap(&pdev->dev, priv->base);
+		devm_release_mem_region(&pdev->dev, priv->mapbase, CHAM_HEADER_SIZE);
+
+		/* Then, allocate it again with the actual chameleon table size */
+		res = devm_request_mem_region(&pdev->dev, priv->mapbase,
+						table_size,
+						KBUILD_MODNAME);
+		if (!res) {
+			dev_err(&pdev->dev, "Failed to request PCI memory\n");
+			ret = -EBUSY;
+			goto out_mcb_bus;
+		}
+
+		priv->base = devm_ioremap(&pdev->dev, priv->mapbase, table_size);
+		if (!priv->base) {
+			dev_err(&pdev->dev, "Cannot ioremap\n");
+			ret = -ENOMEM;
+			goto out_mcb_bus;
+		}
+	}
 
 	mcb_bus_add_devices(priv->bus);
 
--- linux-ein-5.4.0.orig/drivers/md/Kconfig
+++ linux-ein-5.4.0/drivers/md/Kconfig
@@ -565,6 +565,7 @@
 	select BLK_DEV_INTEGRITY
 	select DM_BUFIO
 	select CRYPTO
+	select CRYPTO_SKCIPHER
 	select ASYNC_XOR
 	---help---
 	  This device-mapper target emulates a block device that has
--- linux-ein-5.4.0.orig/drivers/md/bcache/alloc.c
+++ linux-ein-5.4.0/drivers/md/bcache/alloc.c
@@ -49,7 +49,7 @@
  *
  * bch_bucket_alloc() allocates a single bucket from a specific cache.
  *
- * bch_bucket_alloc_set() allocates one or more buckets from different caches
+ * bch_bucket_alloc_set() allocates one  bucket from different caches
  * out of a cache set.
  *
  * free_some_buckets() drives all the processes described above. It's called
@@ -377,7 +377,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);
+			}
 		}
 	}
 out:
@@ -485,34 +488,29 @@
 }
 
 int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
-			   struct bkey *k, int n, bool wait)
+			   struct bkey *k, bool wait)
 {
-	int i;
+	struct cache *ca;
+	long b;
 
 	/* No allocation if CACHE_SET_IO_DISABLE bit is set */
 	if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags)))
 		return -1;
 
 	lockdep_assert_held(&c->bucket_lock);
-	BUG_ON(!n || n > c->caches_loaded || n > MAX_CACHES_PER_SET);
 
 	bkey_init(k);
 
-	/* sort by free space/prio of oldest data in caches */
-
-	for (i = 0; i < n; i++) {
-		struct cache *ca = c->cache_by_alloc[i];
-		long b = bch_bucket_alloc(ca, reserve, wait);
+	ca = c->cache_by_alloc[0];
+	b = bch_bucket_alloc(ca, reserve, wait);
+	if (b == -1)
+		goto err;
+
+	k->ptr[0] = MAKE_PTR(ca->buckets[b].gen,
+			     bucket_to_sector(c, b),
+			     ca->sb.nr_this_dev);
 
-		if (b == -1)
-			goto err;
-
-		k->ptr[i] = MAKE_PTR(ca->buckets[b].gen,
-				bucket_to_sector(c, b),
-				ca->sb.nr_this_dev);
-
-		SET_KEY_PTRS(k, i + 1);
-	}
+	SET_KEY_PTRS(k, 1);
 
 	return 0;
 err:
@@ -522,12 +520,12 @@
 }
 
 int bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
-			 struct bkey *k, int n, bool wait)
+			 struct bkey *k, bool wait)
 {
 	int ret;
 
 	mutex_lock(&c->bucket_lock);
-	ret = __bch_bucket_alloc_set(c, reserve, k, n, wait);
+	ret = __bch_bucket_alloc_set(c, reserve, k, wait);
 	mutex_unlock(&c->bucket_lock);
 	return ret;
 }
@@ -635,7 +633,7 @@
 
 		spin_unlock(&c->data_bucket_lock);
 
-		if (bch_bucket_alloc_set(c, watermark, &alloc.key, 1, wait))
+		if (bch_bucket_alloc_set(c, watermark, &alloc.key, wait))
 			return false;
 
 		spin_lock(&c->data_bucket_lock);
--- linux-ein-5.4.0.orig/drivers/md/bcache/bcache.h
+++ linux-ein-5.4.0/drivers/md/bcache/bcache.h
@@ -264,7 +264,8 @@
 #define BCACHE_DEV_UNLINK_DONE		2
 #define BCACHE_DEV_WB_RUNNING		3
 #define BCACHE_DEV_RATE_DW_RUNNING	4
-	unsigned int		nr_stripes;
+	int			nr_stripes;
+#define BCH_MIN_STRIPE_SZ		((4 << 20) >> SECTOR_SHIFT)
 	unsigned int		stripe_size;
 	atomic_t		*stripe_sectors_dirty;
 	unsigned long		*full_dirty_stripes;
@@ -329,6 +330,9 @@
 	 */
 	atomic_t		has_dirty;
 
+#define BCH_CACHE_READA_ALL		0
+#define BCH_CACHE_READA_META_ONLY	1
+	unsigned int		cache_readahead_policy;
 	struct bch_ratelimit	writeback_rate;
 	struct delayed_work	writeback_rate_update;
 
@@ -369,6 +373,7 @@
 	unsigned int		partial_stripes_expensive:1;
 	unsigned int		writeback_metadata:1;
 	unsigned int		writeback_running:1;
+	unsigned int		writeback_consider_fragment:1;
 	unsigned char		writeback_percent;
 	unsigned int		writeback_delay;
 
@@ -381,6 +386,9 @@
 	unsigned int		writeback_rate_update_seconds;
 	unsigned int		writeback_rate_i_term_inverse;
 	unsigned int		writeback_rate_p_term_inverse;
+	unsigned int		writeback_rate_fp_term_low;
+	unsigned int		writeback_rate_fp_term_mid;
+	unsigned int		writeback_rate_fp_term_high;
 	unsigned int		writeback_rate_minimum;
 
 	enum stop_on_failure	stop_when_cache_set_failed;
@@ -582,6 +590,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
@@ -966,9 +975,9 @@
 
 long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait);
 int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
-			   struct bkey *k, int n, bool wait);
+			   struct bkey *k, bool wait);
 int bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
-			 struct bkey *k, int n, bool wait);
+			 struct bkey *k, bool wait);
 bool bch_alloc_sectors(struct cache_set *c, struct bkey *k,
 		       unsigned int sectors, unsigned int write_point,
 		       unsigned int write_prio, bool wait);
@@ -977,11 +986,12 @@
 __printf(2, 3)
 bool bch_cache_set_error(struct cache_set *c, const char *fmt, ...);
 
-void bch_prio_write(struct cache *ca);
+int bch_prio_write(struct cache *ca, bool wait);
 void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent);
 
 extern struct workqueue_struct *bcache_wq;
 extern struct workqueue_struct *bch_journal_wq;
+extern struct workqueue_struct *bch_flush_wq;
 extern struct mutex bch_register_lock;
 extern struct list_head bch_cache_sets;
 
@@ -1004,6 +1014,7 @@
 int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
 			  uint8_t *set_uuid);
 void bch_cached_dev_detach(struct cached_dev *dc);
+void bch_cached_dev_emit_change(struct cached_dev *);
 int bch_cached_dev_run(struct cached_dev *dc);
 void bcache_device_stop(struct bcache_device *d);
 
@@ -1023,5 +1034,7 @@
 void bch_debug_init(void);
 void bch_request_exit(void);
 int bch_request_init(void);
+void bch_btree_exit(void);
+int bch_btree_init(void);
 
 #endif /* _BCACHE_H */
--- linux-ein-5.4.0.orig/drivers/md/bcache/bset.c
+++ linux-ein-5.4.0/drivers/md/bcache/bset.c
@@ -321,7 +321,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;
 
--- linux-ein-5.4.0.orig/drivers/md/bcache/bset.h
+++ linux-ein-5.4.0/drivers/md/bcache/bset.h
@@ -397,7 +397,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 int idx)
 {
--- linux-ein-5.4.0.orig/drivers/md/bcache/btree.c
+++ linux-ein-5.4.0/drivers/md/bcache/btree.c
@@ -99,6 +99,8 @@
 #define PTR_HASH(c, k)							\
 	(((k)->ptr[0] >> c->bucket_bits) | PTR_GEN(k, 0))
 
+static struct workqueue_struct *btree_io_wq;
+
 #define insert_lock(s, b)	((b)->level <= (s)->lock)
 
 /*
@@ -366,7 +368,7 @@
 	btree_complete_write(b, w);
 
 	if (btree_node_dirty(b))
-		schedule_delayed_work(&b->work, 30 * HZ);
+		queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
 
 	closure_return_with_destructor(cl, btree_node_write_unlock);
 }
@@ -539,7 +541,7 @@
 	BUG_ON(!i->keys);
 
 	if (!btree_node_dirty(b))
-		schedule_delayed_work(&b->work, 30 * HZ);
+		queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
 
 	set_btree_node_dirty(b);
 
@@ -723,38 +725,38 @@
 	 * 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) {
+	list_for_each_entry_safe_reverse(b, t, &c->btree_cache_freeable, list) {
 		if (nr <= 0)
 			goto out;
 
-		if (++i > 3 &&
-		    !mca_reap(b, 0, false)) {
+		if (!mca_reap(b, 0, false)) {
 			mca_data_free(b);
 			rw_unlock(true, b);
 			freed++;
 		}
 		nr--;
+		i++;
 	}
 
-	for (;  (nr--) && i < btree_cache_used; i++) {
-		if (list_empty(&c->btree_cache))
+	list_for_each_entry_safe_reverse(b, t, &c->btree_cache, list) {
+		if (nr <= 0 || i >= btree_cache_used)
 			goto out;
 
-		b = list_first_entry(&c->btree_cache, struct btree, list);
-		list_rotate_left(&c->btree_cache);
-
-		if (!b->accessed &&
-		    !mca_reap(b, 0, false)) {
+		if (!mca_reap(b, 0, false)) {
 			mca_bucket_free(b);
 			mca_data_free(b);
 			rw_unlock(true, b);
 			freed++;
-		} else
-			b->accessed = 0;
+		}
+
+		nr--;
+		i++;
 	}
 out:
 	mutex_unlock(&c->bucket_lock);
@@ -838,7 +840,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);
 
@@ -884,15 +886,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;
 }
@@ -927,10 +931,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,
@@ -1012,6 +1018,9 @@
  *
  * The btree node will have either a read or a write lock held, depending on
  * level and op->lock.
+ *
+ * Note: Only error code or btree pointer will be returned, it is unncessary
+ *       for callers to check NULL pointer.
  */
 struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
 				 struct bkey *k, int level, bool write,
@@ -1058,7 +1067,6 @@
 	BUG_ON(!b->written);
 
 	b->parent = parent;
-	b->accessed = 1;
 
 	for (; i <= b->keys.nsets && b->keys.set[i].size; i++) {
 		prefetch(b->keys.set[i].tree);
@@ -1124,16 +1132,22 @@
 	mutex_unlock(&b->c->bucket_lock);
 }
 
+/*
+ * Only error code or btree pointer will be returned, it is unncessary for
+ * callers to check NULL pointer.
+ */
 struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
 				     int level, bool wait,
 				     struct btree *parent)
 {
 	BKEY_PADDED(key) k;
-	struct btree *b = ERR_PTR(-EAGAIN);
+	struct btree *b;
 
 	mutex_lock(&c->bucket_lock);
 retry:
-	if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, wait))
+	/* return ERR_PTR(-EAGAIN) when it fails */
+	b = ERR_PTR(-EAGAIN);
+	if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, wait))
 		goto err;
 
 	bkey_put(c, &k.key);
@@ -1149,7 +1163,6 @@
 		goto retry;
 	}
 
-	b->accessed = 1;
 	b->parent = parent;
 	bch_bset_init_next(&b->keys, b->keys.set->data, bset_magic(&b->c->sb));
 
@@ -1178,7 +1191,7 @@
 {
 	struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent);
 
-	if (!IS_ERR_OR_NULL(n)) {
+	if (!IS_ERR(n)) {
 		mutex_lock(&n->write_lock);
 		bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
 		bkey_copy_key(&n->key, &b->key);
@@ -1393,7 +1406,7 @@
 
 	for (i = 0; i < nodes; i++) {
 		new_nodes[i] = btree_node_alloc_replacement(r[i].b, NULL);
-		if (IS_ERR_OR_NULL(new_nodes[i]))
+		if (IS_ERR(new_nodes[i]))
 			goto out_nocoalesce;
 	}
 
@@ -1440,7 +1453,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 */
@@ -1469,7 +1482,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);
@@ -1515,6 +1528,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);
 
@@ -1541,6 +1558,8 @@
 		return 0;
 
 	n = btree_node_alloc_replacement(replace, NULL);
+	if (IS_ERR(n))
+		return 0;
 
 	/* recheck reserve after allocating replacement node */
 	if (btree_check_reserve(b, NULL)) {
@@ -1706,7 +1725,7 @@
 	if (should_rewrite) {
 		n = btree_node_alloc_replacement(b, NULL);
 
-		if (!IS_ERR_OR_NULL(n)) {
+		if (!IS_ERR(n)) {
 			bch_btree_node_write_sync(n);
 
 			bch_btree_set_root(n);
@@ -2649,3 +2668,18 @@
 	spin_lock_init(&buf->lock);
 	array_allocator_init(&buf->freelist);
 }
+
+void bch_btree_exit(void)
+{
+	if (btree_io_wq)
+		destroy_workqueue(btree_io_wq);
+}
+
+int __init bch_btree_init(void)
+{
+	btree_io_wq = alloc_workqueue("bch_btree_io", WQ_MEM_RECLAIM, 0);
+	if (!btree_io_wq)
+		return -ENOMEM;
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/md/bcache/btree.h
+++ linux-ein-5.4.0/drivers/md/bcache/btree.h
@@ -121,8 +121,6 @@
 	/* Key/pointer for this btree node */
 	BKEY_PADDED(key);
 
-	/* Single bit - set when accessed, cleared by shrinker */
-	unsigned long		accessed;
 	unsigned long		seq;
 	struct rw_semaphore	lock;
 	struct cache_set	*c;
--- linux-ein-5.4.0.orig/drivers/md/bcache/journal.c
+++ linux-ein-5.4.0/drivers/md/bcache/journal.c
@@ -417,10 +417,15 @@
 
 /* Journalling */
 
+#define nr_to_fifo_front(p, front_p, mask)	(((p) - (front_p)) & (mask))
+
 static void btree_flush_write(struct cache_set *c)
 {
 	struct btree *b, *t, *btree_nodes[BTREE_FLUSH_NR];
-	unsigned int i, n;
+	unsigned int i, nr;
+	int ref_nr;
+	atomic_t *fifo_front_p, *now_fifo_front_p;
+	size_t mask;
 
 	if (c->journal.btree_flushing)
 		return;
@@ -433,12 +438,50 @@
 	c->journal.btree_flushing = true;
 	spin_unlock(&c->journal.flush_write_lock);
 
+	/* get the oldest journal entry and check its refcount */
+	spin_lock(&c->journal.lock);
+	fifo_front_p = &fifo_front(&c->journal.pin);
+	ref_nr = atomic_read(fifo_front_p);
+	if (ref_nr <= 0) {
+		/*
+		 * do nothing if no btree node references
+		 * the oldest journal entry
+		 */
+		spin_unlock(&c->journal.lock);
+		goto out;
+	}
+	spin_unlock(&c->journal.lock);
+
+	mask = c->journal.pin.mask;
+	nr = 0;
 	atomic_long_inc(&c->flush_write);
 	memset(btree_nodes, 0, sizeof(btree_nodes));
-	n = 0;
 
 	mutex_lock(&c->bucket_lock);
 	list_for_each_entry_safe_reverse(b, t, &c->btree_cache, list) {
+		/*
+		 * It is safe to get now_fifo_front_p without holding
+		 * c->journal.lock here, because we don't need to know
+		 * the exactly accurate value, just check whether the
+		 * front pointer of c->journal.pin is changed.
+		 */
+		now_fifo_front_p = &fifo_front(&c->journal.pin);
+		/*
+		 * If the oldest journal entry is reclaimed and front
+		 * pointer of c->journal.pin changes, it is unnecessary
+		 * to scan c->btree_cache anymore, just quit the loop and
+		 * flush out what we have already.
+		 */
+		if (now_fifo_front_p != fifo_front_p)
+			break;
+		/*
+		 * quit this loop if all matching btree nodes are
+		 * scanned and record in btree_nodes[] already.
+		 */
+		ref_nr = atomic_read(fifo_front_p);
+		if (nr >= ref_nr)
+			break;
+
 		if (btree_node_journal_flush(b))
 			pr_err("BUG: flush_write bit should not be set here!");
 
@@ -454,17 +497,44 @@
 			continue;
 		}
 
+		/*
+		 * Only select the btree node which exactly references
+		 * the oldest journal entry.
+		 *
+		 * If the journal entry pointed by fifo_front_p is
+		 * reclaimed in parallel, don't worry:
+		 * - the list_for_each_xxx loop will quit when checking
+		 *   next now_fifo_front_p.
+		 * - If there are matched nodes recorded in btree_nodes[],
+		 *   they are clean now (this is why and how the oldest
+		 *   journal entry can be reclaimed). These selected nodes
+		 *   will be ignored and skipped in the folowing for-loop.
+		 */
+		if (nr_to_fifo_front(btree_current_write(b)->journal,
+				     fifo_front_p,
+				     mask) != 0) {
+			mutex_unlock(&b->write_lock);
+			continue;
+		}
+
 		set_btree_node_journal_flush(b);
 
 		mutex_unlock(&b->write_lock);
 
-		btree_nodes[n++] = b;
-		if (n == BTREE_FLUSH_NR)
+		btree_nodes[nr++] = b;
+		/*
+		 * To avoid holding c->bucket_lock too long time,
+		 * only scan for BTREE_FLUSH_NR matched btree nodes
+		 * at most. If there are more btree nodes reference
+		 * the oldest journal entry, try to flush them next
+		 * time when btree_flush_write() is called.
+		 */
+		if (nr == BTREE_FLUSH_NR)
 			break;
 	}
 	mutex_unlock(&c->bucket_lock);
 
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < nr; i++) {
 		b = btree_nodes[i];
 		if (!b) {
 			pr_err("BUG: btree_nodes[%d] is NULL", i);
@@ -497,6 +567,7 @@
 		mutex_unlock(&b->write_lock);
 	}
 
+out:
 	spin_lock(&c->journal.flush_write_lock);
 	c->journal.btree_flushing = false;
 	spin_unlock(&c->journal.flush_write_lock);
@@ -887,8 +958,8 @@
 		journal_try_write(c);
 	} else if (!w->dirty) {
 		w->dirty = true;
-		schedule_delayed_work(&c->journal.work,
-				      msecs_to_jiffies(c->journal_delay_ms));
+		queue_delayed_work(bch_flush_wq, &c->journal.work,
+				   msecs_to_jiffies(c->journal_delay_ms));
 		spin_unlock(&c->journal.lock);
 	} else {
 		spin_unlock(&c->journal.lock);
@@ -931,8 +1002,8 @@
 	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)))
+	    !(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-ein-5.4.0.orig/drivers/md/bcache/request.c
+++ linux-ein-5.4.0/drivers/md/bcache/request.c
@@ -391,13 +391,20 @@
 		goto skip;
 
 	/*
-	 * Flag for bypass if the IO is for read-ahead or background,
-	 * unless the read-ahead request is for metadata
+	 * If the bio is for read-ahead or background IO, bypass it or
+	 * not depends on the following situations,
+	 * - If the IO is for meta data, always cache it and no bypass
+	 * - If the IO is not meta data, check dc->cache_reada_policy,
+	 *      BCH_CACHE_READA_ALL: cache it and not bypass
+	 *      BCH_CACHE_READA_META_ONLY: not cache it and bypass
+	 * That is, read-ahead request for metadata always get cached
 	 * (eg, for gfs2 or xfs).
 	 */
-	if (bio->bi_opf & (REQ_RAHEAD|REQ_BACKGROUND) &&
-	    !(bio->bi_opf & (REQ_META|REQ_PRIO)))
-		goto skip;
+	if ((bio->bi_opf & (REQ_RAHEAD|REQ_BACKGROUND))) {
+		if (!(bio->bi_opf & (REQ_META|REQ_PRIO)) &&
+		    (dc->cache_readahead_policy != BCH_CACHE_READA_ALL))
+			goto skip;
+	}
 
 	if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) ||
 	    bio_sectors(bio) & (c->sb.block_size - 1)) {
@@ -1112,6 +1119,12 @@
 	 * which would call closure_get(&dc->disk.cl)
 	 */
 	ddip = kzalloc(sizeof(struct detached_dev_io_private), GFP_NOIO);
+	if (!ddip) {
+		bio->bi_status = BLK_STS_RESOURCE;
+		bio->bi_end_io(bio);
+		return;
+	}
+
 	ddip->d = d;
 	ddip->start_time = jiffies;
 	ddip->bi_end_io = bio->bi_end_io;
--- linux-ein-5.4.0.orig/drivers/md/bcache/stats.c
+++ linux-ein-5.4.0/drivers/md/bcache/stats.c
@@ -109,9 +109,13 @@
 
 void bch_cache_accounting_clear(struct cache_accounting *acc)
 {
-	memset(&acc->total.cache_hits,
-	       0,
-	       sizeof(struct cache_stats));
+	acc->total.cache_hits = 0;
+	acc->total.cache_misses = 0;
+	acc->total.cache_bypass_hits = 0;
+	acc->total.cache_bypass_misses = 0;
+	acc->total.cache_readaheads = 0;
+	acc->total.cache_miss_collisions = 0;
+	acc->total.sectors_bypassed = 0;
 }
 
 void bch_cache_accounting_destroy(struct cache_accounting *acc)
--- linux-ein-5.4.0.orig/drivers/md/bcache/super.c
+++ linux-ein-5.4.0/drivers/md/bcache/super.c
@@ -48,6 +48,7 @@
 static DEFINE_IDA(bcache_device_idx);
 static wait_queue_head_t unregister_wait;
 struct workqueue_struct *bcache_wq;
+struct workqueue_struct *bch_flush_wq;
 struct workqueue_struct *bch_journal_wq;
 
 
@@ -427,7 +428,7 @@
 	closure_init_stack(&cl);
 	lockdep_assert_held(&bch_register_lock);
 
-	if (bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, true))
+	if (bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, true))
 		return 1;
 
 	SET_KEY_SIZE(&k.key, c->sb.bucket_size);
@@ -529,12 +530,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);
@@ -544,9 +562,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;
@@ -564,7 +579,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);
@@ -593,6 +608,7 @@
 
 		ca->prio_last_buckets[i] = ca->prio_buckets[i];
 	}
+	return 0;
 }
 
 static void prio_read(struct cache *ca, uint64_t bucket)
@@ -761,20 +777,31 @@
 
 static void bcache_device_free(struct bcache_device *d)
 {
+	struct gendisk *disk = d->disk;
+
 	lockdep_assert_held(&bch_register_lock);
 
-	pr_info("%s stopped", d->disk->disk_name);
+	if (disk)
+		pr_info("%s stopped", disk->disk_name);
+	else
+		pr_err("bcache device (NULL gendisk) stopped");
 
 	if (d->c)
 		bcache_device_detach(d);
-	if (d->disk && d->disk->flags & GENHD_FL_UP)
-		del_gendisk(d->disk);
-	if (d->disk && d->disk->queue)
-		blk_cleanup_queue(d->disk->queue);
-	if (d->disk) {
+
+	if (disk) {
+		bool disk_added = (disk->flags & GENHD_FL_UP) != 0;
+
+		if (disk_added)
+			del_gendisk(disk);
+
+		if (disk->queue)
+			blk_cleanup_queue(disk->queue);
+
 		ida_simple_remove(&bcache_device_idx,
-				  first_minor_to_idx(d->disk->first_minor));
-		put_disk(d->disk);
+				  first_minor_to_idx(disk->first_minor));
+		if (disk_added)
+			put_disk(disk);
 	}
 
 	bioset_exit(&d->bio_split);
@@ -785,24 +812,26 @@
 }
 
 static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
-			      sector_t sectors)
+			      sector_t sectors, struct block_device *cached_bdev)
 {
 	struct request_queue *q;
 	const size_t max_stripes = min_t(size_t, INT_MAX,
 					 SIZE_MAX / sizeof(atomic_t));
-	size_t n;
+	uint64_t n;
 	int idx;
 
 	if (!d->stripe_size)
 		d->stripe_size = 1 << 31;
+	else if (d->stripe_size < BCH_MIN_STRIPE_SZ)
+		d->stripe_size = roundup(BCH_MIN_STRIPE_SZ, d->stripe_size);
 
-	d->nr_stripes = DIV_ROUND_UP_ULL(sectors, d->stripe_size);
-
-	if (!d->nr_stripes || d->nr_stripes > max_stripes) {
-		pr_err("nr_stripes too large or invalid: %u (start sector beyond end of disk?)",
-			(unsigned int)d->nr_stripes);
+	n = DIV_ROUND_UP_ULL(sectors, d->stripe_size);
+	if (!n || n > max_stripes) {
+		pr_err("nr_stripes too large or invalid: %llu (start sector beyond end of disk?)\n",
+			n);
 		return -ENOMEM;
 	}
+	d->nr_stripes = n;
 
 	n = d->nr_stripes * sizeof(atomic_t);
 	d->stripe_sectors_dirty = kvzalloc(n, GFP_KERNEL);
@@ -812,20 +841,20 @@
 	n = BITS_TO_LONGS(d->nr_stripes) * sizeof(unsigned long);
 	d->full_dirty_stripes = kvzalloc(n, GFP_KERNEL);
 	if (!d->full_dirty_stripes)
-		return -ENOMEM;
+		goto out_free_stripe_sectors_dirty;
 
 	idx = ida_simple_get(&bcache_device_idx, 0,
 				BCACHE_DEVICE_IDX_MAX, GFP_KERNEL);
 	if (idx < 0)
-		return idx;
+		goto out_free_full_dirty_stripes;
 
 	if (bioset_init(&d->bio_split, 4, offsetof(struct bbio, bio),
 			BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
-		goto err;
+		goto out_ida_remove;
 
 	d->disk = alloc_disk(BCACHE_MINORS);
 	if (!d->disk)
-		goto err;
+		goto out_bioset_exit;
 
 	set_capacity(d->disk, sectors);
 	snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", idx);
@@ -852,6 +881,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));
+	}
+
 	blk_queue_flag_set(QUEUE_FLAG_NONROT, d->disk->queue);
 	blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, d->disk->queue);
 	blk_queue_flag_set(QUEUE_FLAG_DISCARD, d->disk->queue);
@@ -860,8 +904,14 @@
 
 	return 0;
 
-err:
+out_bioset_exit:
+	bioset_exit(&d->bio_split);
+out_ida_remove:
 	ida_simple_remove(&bcache_device_idx, idx);
+out_free_full_dirty_stripes:
+	kvfree(d->full_dirty_stripes);
+out_free_stripe_sectors_dirty:
+	kvfree(d->stripe_sectors_dirty);
 	return -ENOMEM;
 
 }
@@ -917,7 +967,7 @@
 }
 
 
-int 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 = kmemdup_nul(dc->sb.label, SB_LABEL_SIZE, GFP_KERNEL);
@@ -928,19 +978,26 @@
 		NULL,
 	};
 
+	/*
+	 * 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]);
+	kfree(buf);
+}
+
+int bch_cached_dev_run(struct cached_dev *dc)
+{
+	struct bcache_device *d = &dc->disk;
 	if (dc->io_disable) {
 		pr_err("I/O disabled on cached dev %s",
 		       dc->backing_dev_name);
-		kfree(env[1]);
-		kfree(env[2]);
-		kfree(buf);
 		return -EIO;
 	}
 
 	if (atomic_xchg(&dc->running, 1)) {
-		kfree(env[1]);
-		kfree(env[2]);
-		kfree(buf);
 		pr_info("cached dev %s is running already",
 		       dc->backing_dev_name);
 		return -EBUSY;
@@ -959,14 +1016,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]);
-	kfree(buf);
+
+	/* 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,
@@ -1251,6 +1303,9 @@
 
 	mutex_unlock(&bch_register_lock);
 
+	if (dc->sb_bio.bi_inline_vecs[0].bv_page)
+		put_page(bio_first_page_all(&dc->sb_bio));
+
 	if (!IS_ERR_OR_NULL(dc->bdev))
 		blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
 
@@ -1305,7 +1360,7 @@
 			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;
 
@@ -1421,7 +1476,7 @@
 
 	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);
@@ -1597,7 +1652,7 @@
 	if (!IS_ERR_OR_NULL(c->gc_thread))
 		kthread_stop(c->gc_thread);
 
-	if (!IS_ERR_OR_NULL(c->root))
+	if (!IS_ERR(c->root))
 		list_add(&c->root->list, &c->btree_cache);
 
 	/*
@@ -1725,7 +1780,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)
 {
@@ -1769,6 +1824,7 @@
 	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);
@@ -1869,7 +1925,7 @@
 		c->root = bch_btree_node_get(c, NULL, k,
 					     j->btree_level,
 					     true, NULL);
-		if (IS_ERR_OR_NULL(c->root))
+		if (IS_ERR(c->root))
 			goto err;
 
 		list_del_init(&c->root->list);
@@ -1954,7 +2010,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";
@@ -1963,7 +2019,7 @@
 
 		err = "cannot allocate new btree root";
 		c->root = __bch_btree_node_alloc(c, NULL, 0, true, NULL);
-		if (IS_ERR_OR_NULL(c->root))
+		if (IS_ERR(c->root))
 			goto err;
 
 		mutex_lock(&c->root->write_lock);
@@ -2062,7 +2118,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;
@@ -2325,6 +2388,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;
@@ -2346,29 +2424,36 @@
 static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
 			       const char *buffer, size_t size)
 {
-	ssize_t ret = -EINVAL;
-	const char *err = "cannot allocate memory";
+	const char *err;
 	char *path = NULL;
-	struct cache_sb *sb = NULL;
+	struct cache_sb *sb;
 	struct block_device *bdev = NULL;
-	struct page *sb_page = NULL;
+	struct cached_dev *dc = NULL;
+	struct page *sb_page;
+	ssize_t ret;
 
+	ret = -EBUSY;
+	err = "failed to reference bcache module";
 	if (!try_module_get(THIS_MODULE))
-		return -EBUSY;
+		goto out;
 
 	/* For latest state of bcache_is_reboot */
 	smp_mb();
+	err = "bcache is in reboot";
 	if (bcache_is_reboot)
-		return -EBUSY;
+		goto out_module_put;
 
+	ret = -ENOMEM;
+	err = "cannot allocate memory";
 	path = kstrndup(buffer, size, GFP_KERNEL);
 	if (!path)
-		goto err;
+		goto out_module_put;
 
 	sb = kmalloc(sizeof(struct cache_sb), GFP_KERNEL);
 	if (!sb)
-		goto err;
+		goto out_free_path;
 
+	ret = -EINVAL;
 	err = "failed to open device";
 	bdev = blkdev_get_by_path(strim(path),
 				  FMODE_READ|FMODE_WRITE|FMODE_EXCL,
@@ -2377,65 +2462,87 @@
 		if (bdev == ERR_PTR(-EBUSY)) {
 			bdev = lookup_bdev(strim(path));
 			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 quiet_out;
+				goto done;
 		}
-		goto err;
+		goto out_free_sb;
 	}
 
 	err = "failed to set blocksize";
 	if (set_blocksize(bdev, 4096))
-		goto err_close;
+		goto out_blkdev_put;
 
 	err = read_super(sb, bdev, &sb_page);
 	if (err)
-		goto err_close;
+		goto out_blkdev_put;
 
 	err = "failed to register device";
 	if (SB_IS_BDEV(sb)) {
 		struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
 
 		if (!dc)
-			goto err_close;
+			goto out_put_sb_page;
 
 		mutex_lock(&bch_register_lock);
 		ret = register_bdev(sb, sb_page, bdev, dc);
 		mutex_unlock(&bch_register_lock);
 		/* blkdev_put() will be called in cached_dev_free() */
-		if (ret < 0)
-			goto err;
+		if (ret < 0) {
+			bdev = NULL;
+			goto out_put_sb_page;
+		}
 	} else {
 		struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
 
 		if (!ca)
-			goto err_close;
+			goto out_put_sb_page;
 
 		/* blkdev_put() will be called in bch_cache_release() */
-		if (register_cache(sb, sb_page, bdev, ca) != 0)
-			goto err;
+		if (register_cache(sb, sb_page, bdev, ca) != 0) {
+			bdev = NULL;
+			goto out_put_sb_page;
+		}
 	}
-quiet_out:
-	ret = size;
-out:
-	if (sb_page)
-		put_page(sb_page);
+
+	put_page(sb_page);
+done:
 	kfree(sb);
 	kfree(path);
 	module_put(THIS_MODULE);
-	return ret;
+	return size;
 
-err_close:
-	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
-err:
-	pr_info("error %s: %s", path, err);
-	goto out;
+out_put_sb_page:
+	put_page(sb_page);
+out_blkdev_put:
+	if (bdev)
+		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+out_free_sb:
+	kfree(sb);
+out_free_path:
+	kfree(path);
+	path = NULL;
+out_module_put:
+	module_put(THIS_MODULE);
+out:
+	pr_info("error %s: %s", path?path:"", err);
+	return ret;
 }
 
 
@@ -2597,6 +2704,9 @@
 		destroy_workqueue(bcache_wq);
 	if (bch_journal_wq)
 		destroy_workqueue(bch_journal_wq);
+	if (bch_flush_wq)
+		destroy_workqueue(bch_flush_wq);
+	bch_btree_exit();
 
 	if (bcache_major)
 		unregister_blkdev(bcache_major, "bcache");
@@ -2652,10 +2762,26 @@
 		return bcache_major;
 	}
 
+	if (bch_btree_init())
+		goto err;
+
 	bcache_wq = alloc_workqueue("bcache", WQ_MEM_RECLAIM, 0);
 	if (!bcache_wq)
 		goto err;
 
+	/*
+	 * Let's not make this `WQ_MEM_RECLAIM` for the following reasons:
+	 *
+	 * 1. It used `system_wq` before which also does no memory reclaim.
+	 * 2. With `WQ_MEM_RECLAIM` desktop stalls, increased boot times, and
+	 *    reduced throughput can be observed.
+	 *
+	 * We still want to user our own queue to not congest the `system_wq`.
+	 */
+	bch_flush_wq = alloc_workqueue("bch_flush", 0, 0);
+	if (!bch_flush_wq)
+		goto err;
+
 	bch_journal_wq = alloc_workqueue("bch_journal", WQ_MEM_RECLAIM, 0);
 	if (!bch_journal_wq)
 		goto err;
--- linux-ein-5.4.0.orig/drivers/md/bcache/sysfs.c
+++ linux-ein-5.4.0/drivers/md/bcache/sysfs.c
@@ -27,6 +27,12 @@
 	NULL
 };
 
+static const char * const bch_reada_cache_policies[] = {
+	"all",
+	"meta-only",
+	NULL
+};
+
 /* Default is 0 ("auto") */
 static const char * const bch_stop_on_failure_modes[] = {
 	"auto",
@@ -100,16 +106,21 @@
 rw_attribute(sequential_cutoff);
 rw_attribute(data_csum);
 rw_attribute(cache_mode);
+rw_attribute(readahead_cache_policy);
 rw_attribute(stop_when_cache_set_failed);
 rw_attribute(writeback_metadata);
 rw_attribute(writeback_running);
 rw_attribute(writeback_percent);
 rw_attribute(writeback_delay);
 rw_attribute(writeback_rate);
+rw_attribute(writeback_consider_fragment);
 
 rw_attribute(writeback_rate_update_seconds);
 rw_attribute(writeback_rate_i_term_inverse);
 rw_attribute(writeback_rate_p_term_inverse);
+rw_attribute(writeback_rate_fp_term_low);
+rw_attribute(writeback_rate_fp_term_mid);
+rw_attribute(writeback_rate_fp_term_high);
 rw_attribute(writeback_rate_minimum);
 read_attribute(writeback_rate_debug);
 
@@ -167,6 +178,11 @@
 					       bch_cache_modes,
 					       BDEV_CACHE_MODE(&dc->sb));
 
+	if (attr == &sysfs_readahead_cache_policy)
+		return bch_snprint_string_list(buf, PAGE_SIZE,
+					      bch_reada_cache_policies,
+					      dc->cache_readahead_policy);
+
 	if (attr == &sysfs_stop_when_cache_set_failed)
 		return bch_snprint_string_list(buf, PAGE_SIZE,
 					       bch_stop_on_failure_modes,
@@ -178,6 +194,7 @@
 	var_printf(bypass_torture_test,	"%i");
 	var_printf(writeback_metadata,	"%i");
 	var_printf(writeback_running,	"%i");
+	var_printf(writeback_consider_fragment,	"%i");
 	var_print(writeback_delay);
 	var_print(writeback_percent);
 	sysfs_hprint(writeback_rate,
@@ -188,6 +205,9 @@
 	var_print(writeback_rate_update_seconds);
 	var_print(writeback_rate_i_term_inverse);
 	var_print(writeback_rate_p_term_inverse);
+	var_print(writeback_rate_fp_term_low);
+	var_print(writeback_rate_fp_term_mid);
+	var_print(writeback_rate_fp_term_high);
 	var_print(writeback_rate_minimum);
 
 	if (attr == &sysfs_writeback_rate_debug) {
@@ -286,6 +306,7 @@
 	sysfs_strtoul_bool(bypass_torture_test, dc->bypass_torture_test);
 	sysfs_strtoul_bool(writeback_metadata, dc->writeback_metadata);
 	sysfs_strtoul_bool(writeback_running, dc->writeback_running);
+	sysfs_strtoul_bool(writeback_consider_fragment, dc->writeback_consider_fragment);
 	sysfs_strtoul_clamp(writeback_delay, dc->writeback_delay, 0, UINT_MAX);
 
 	sysfs_strtoul_clamp(writeback_percent, dc->writeback_percent,
@@ -314,6 +335,16 @@
 	sysfs_strtoul_clamp(writeback_rate_p_term_inverse,
 			    dc->writeback_rate_p_term_inverse,
 			    1, UINT_MAX);
+	sysfs_strtoul_clamp(writeback_rate_fp_term_low,
+			    dc->writeback_rate_fp_term_low,
+			    1, dc->writeback_rate_fp_term_mid - 1);
+	sysfs_strtoul_clamp(writeback_rate_fp_term_mid,
+			    dc->writeback_rate_fp_term_mid,
+			    dc->writeback_rate_fp_term_low + 1,
+			    dc->writeback_rate_fp_term_high - 1);
+	sysfs_strtoul_clamp(writeback_rate_fp_term_high,
+			    dc->writeback_rate_fp_term_high,
+			    dc->writeback_rate_fp_term_mid + 1, UINT_MAX);
 	sysfs_strtoul_clamp(writeback_rate_minimum,
 			    dc->writeback_rate_minimum,
 			    1, UINT_MAX);
@@ -352,6 +383,15 @@
 		}
 	}
 
+	if (attr == &sysfs_readahead_cache_policy) {
+		v = __sysfs_match_string(bch_reada_cache_policies, -1, buf);
+		if (v < 0)
+			return v;
+
+		if ((unsigned int) v != dc->cache_readahead_policy)
+			dc->cache_readahead_policy = v;
+	}
+
 	if (attr == &sysfs_stop_when_cache_set_failed) {
 		v = __sysfs_match_string(bch_stop_on_failure_modes, -1, buf);
 		if (v < 0)
@@ -466,15 +506,20 @@
 	&sysfs_data_csum,
 #endif
 	&sysfs_cache_mode,
+	&sysfs_readahead_cache_policy,
 	&sysfs_stop_when_cache_set_failed,
 	&sysfs_writeback_metadata,
 	&sysfs_writeback_running,
 	&sysfs_writeback_delay,
 	&sysfs_writeback_percent,
 	&sysfs_writeback_rate,
+	&sysfs_writeback_consider_fragment,
 	&sysfs_writeback_rate_update_seconds,
 	&sysfs_writeback_rate_i_term_inverse,
 	&sysfs_writeback_rate_p_term_inverse,
+	&sysfs_writeback_rate_fp_term_low,
+	&sysfs_writeback_rate_fp_term_mid,
+	&sysfs_writeback_rate_fp_term_high,
 	&sysfs_writeback_rate_minimum,
 	&sysfs_writeback_rate_debug,
 	&sysfs_io_errors,
@@ -1035,7 +1080,7 @@
 			sum += INITIAL_PRIO - cached[i];
 
 		if (n)
-			do_div(sum, n);
+			sum = div64_u64(sum, n);
 
 		for (i = 0; i < ARRAY_SIZE(q); i++)
 			q[i] = INITIAL_PRIO - cached[n * (i + 1) /
--- linux-ein-5.4.0.orig/drivers/md/bcache/writeback.c
+++ linux-ein-5.4.0/drivers/md/bcache/writeback.c
@@ -88,6 +88,44 @@
 	int64_t integral_scaled;
 	uint32_t new_rate;
 
+	/*
+	 * We need to consider the number of dirty buckets as well
+	 * when calculating the proportional_scaled, Otherwise we might
+	 * have an unreasonable small writeback rate at a highly fragmented situation
+	 * when very few dirty sectors consumed a lot dirty buckets, the
+	 * worst case is when dirty buckets reached cutoff_writeback_sync and
+	 * dirty data is still not even reached to writeback percent, so the rate
+	 * still will be at the minimum value, which will cause the write
+	 * stuck at a non-writeback mode.
+	 */
+	struct cache_set *c = dc->disk.c;
+
+	int64_t dirty_buckets = c->nbuckets - c->avail_nbuckets;
+
+	if (dc->writeback_consider_fragment &&
+		c->gc_stats.in_use > BCH_WRITEBACK_FRAGMENT_THRESHOLD_LOW && dirty > 0) {
+		int64_t fragment =
+			div_s64((dirty_buckets *  c->sb.bucket_size), dirty);
+		int64_t fp_term;
+		int64_t fps;
+
+		if (c->gc_stats.in_use <= BCH_WRITEBACK_FRAGMENT_THRESHOLD_MID) {
+			fp_term = dc->writeback_rate_fp_term_low *
+			(c->gc_stats.in_use - BCH_WRITEBACK_FRAGMENT_THRESHOLD_LOW);
+		} else if (c->gc_stats.in_use <= BCH_WRITEBACK_FRAGMENT_THRESHOLD_HIGH) {
+			fp_term = dc->writeback_rate_fp_term_mid *
+			(c->gc_stats.in_use - BCH_WRITEBACK_FRAGMENT_THRESHOLD_MID);
+		} else {
+			fp_term = dc->writeback_rate_fp_term_high *
+			(c->gc_stats.in_use - BCH_WRITEBACK_FRAGMENT_THRESHOLD_HIGH);
+		}
+		fps = div_s64(dirty, dirty_buckets) * fp_term;
+		if (fragment > 3 && fps > proportional_scaled) {
+			/* Only overrite the p when fragment > 3 */
+			proportional_scaled = fps;
+		}
+	}
+
 	if ((error < 0 && dc->writeback_rate_integral > 0) ||
 	    (error > 0 && time_before64(local_clock(),
 			 dc->writeback_rate.next + NSEC_PER_MSEC))) {
@@ -119,27 +157,61 @@
 	dc->writeback_rate_target = target;
 }
 
+static bool idle_counter_exceeded(struct cache_set *c)
+{
+	int counter, dev_nr;
+
+	/*
+	 * If c->idle_counter is overflow (idel for really long time),
+	 * reset as 0 and not set maximum rate this time for code
+	 * simplicity.
+	 */
+	counter = atomic_inc_return(&c->idle_counter);
+	if (counter <= 0) {
+		atomic_set(&c->idle_counter, 0);
+		return false;
+	}
+
+	dev_nr = atomic_read(&c->attached_dev_nr);
+	if (dev_nr == 0)
+		return false;
+
+	/*
+	 * c->idle_counter is increased by writeback thread of all
+	 * attached backing devices, in order to represent a rough
+	 * time period, counter should be divided by dev_nr.
+	 * Otherwise the idle time cannot be larger with more backing
+	 * device attached.
+	 * The following calculation equals to checking
+	 *	(counter / dev_nr) < (dev_nr * 6)
+	 */
+	if (counter < (dev_nr * dev_nr * 6))
+		return false;
+
+	return true;
+}
+
+/*
+ * Idle_counter is increased every time when update_writeback_rate() is
+ * called. If all backing devices attached to the same cache set have
+ * identical dc->writeback_rate_update_seconds values, it is about 6
+ * rounds of update_writeback_rate() on each backing device before
+ * c->at_max_writeback_rate is set to 1, and then max wrteback rate set
+ * to each dc->writeback_rate.rate.
+ * In order to avoid extra locking cost for counting exact dirty cached
+ * devices number, c->attached_dev_nr is used to calculate the idle
+ * throushold. It might be bigger if not all cached device are in write-
+ * back mode, but it still works well with limited extra rounds of
+ * update_writeback_rate().
+ */
 static bool set_at_max_writeback_rate(struct cache_set *c,
 				       struct cached_dev *dc)
 {
 	/* Don't set max writeback rate if gc is running */
 	if (!c->gc_mark_valid)
 		return false;
-	/*
-	 * Idle_counter is increased everytime when update_writeback_rate() is
-	 * called. If all backing devices attached to the same cache set have
-	 * identical dc->writeback_rate_update_seconds values, it is about 6
-	 * rounds of update_writeback_rate() on each backing device before
-	 * c->at_max_writeback_rate is set to 1, and then max wrteback rate set
-	 * to each dc->writeback_rate.rate.
-	 * In order to avoid extra locking cost for counting exact dirty cached
-	 * devices number, c->attached_dev_nr is used to calculate the idle
-	 * throushold. It might be bigger if not all cached device are in write-
-	 * back mode, but it still works well with limited extra rounds of
-	 * update_writeback_rate().
-	 */
-	if (atomic_inc_return(&c->idle_counter) <
-	    atomic_read(&c->attached_dev_nr) * 6)
+
+	if (!idle_counter_exceeded(c))
 		return false;
 
 	if (atomic_read(&c->at_max_writeback_rate) != 1)
@@ -153,13 +225,10 @@
 	dc->writeback_rate_change = 0;
 
 	/*
-	 * Check c->idle_counter and c->at_max_writeback_rate agagain in case
-	 * new I/O arrives during before set_at_max_writeback_rate() returns.
-	 * Then the writeback rate is set to 1, and its new value should be
-	 * decided via __update_writeback_rate().
+	 * In case new I/O arrives during before
+	 * set_at_max_writeback_rate() returns.
 	 */
-	if ((atomic_read(&c->idle_counter) <
-	     atomic_read(&c->attached_dev_nr) * 6) ||
+	if (!idle_counter_exceeded(c) ||
 	    !atomic_read(&c->at_max_writeback_rate))
 		return false;
 
@@ -519,15 +588,19 @@
 				  uint64_t offset, int nr_sectors)
 {
 	struct bcache_device *d = c->devices[inode];
-	unsigned int stripe_offset, stripe, sectors_dirty;
+	unsigned int stripe_offset, sectors_dirty;
+	int stripe;
 
 	if (!d)
 		return;
 
+	stripe = offset_to_stripe(d, offset);
+	if (stripe < 0)
+		return;
+
 	if (UUID_FLASH_ONLY(&c->uuids[inode]))
 		atomic_long_add(nr_sectors, &c->flash_dev_dirty_sectors);
 
-	stripe = offset_to_stripe(d, offset);
 	stripe_offset = offset & (d->stripe_size - 1);
 
 	while (nr_sectors) {
@@ -567,12 +640,12 @@
 static void refill_full_stripes(struct cached_dev *dc)
 {
 	struct keybuf *buf = &dc->writeback_keys;
-	unsigned int start_stripe, stripe, next_stripe;
+	unsigned int start_stripe, next_stripe;
+	int stripe;
 	bool wrapped = false;
 
 	stripe = offset_to_stripe(&dc->disk, KEY_OFFSET(&buf->last_scanned));
-
-	if (stripe >= dc->disk.nr_stripes)
+	if (stripe < 0)
 		stripe = 0;
 
 	start_stripe = stripe;
@@ -812,6 +885,7 @@
 
 	dc->writeback_metadata		= true;
 	dc->writeback_running		= false;
+	dc->writeback_consider_fragment = true;
 	dc->writeback_percent		= 10;
 	dc->writeback_delay		= 30;
 	atomic_long_set(&dc->writeback_rate.rate, 1024);
@@ -819,6 +893,9 @@
 
 	dc->writeback_rate_update_seconds = WRITEBACK_RATE_UPDATE_SECS_DEFAULT;
 	dc->writeback_rate_p_term_inverse = 40;
+	dc->writeback_rate_fp_term_low = 1;
+	dc->writeback_rate_fp_term_mid = 10;
+	dc->writeback_rate_fp_term_high = 1000;
 	dc->writeback_rate_i_term_inverse = 10000;
 
 	WARN_ON(test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags));
--- linux-ein-5.4.0.orig/drivers/md/bcache/writeback.h
+++ linux-ein-5.4.0/drivers/md/bcache/writeback.h
@@ -16,6 +16,10 @@
 
 #define BCH_AUTO_GC_DIRTY_THRESHOLD	50
 
+#define BCH_WRITEBACK_FRAGMENT_THRESHOLD_LOW 50
+#define BCH_WRITEBACK_FRAGMENT_THRESHOLD_MID 57
+#define BCH_WRITEBACK_FRAGMENT_THRESHOLD_HIGH 64
+
 /*
  * 14 (16384ths) is chosen here as something that each backing device
  * should be a reasonable fraction of the share, and not to blow up
@@ -33,10 +37,22 @@
 	return ret;
 }
 
-static inline unsigned int offset_to_stripe(struct bcache_device *d,
+static inline int offset_to_stripe(struct bcache_device *d,
 					uint64_t offset)
 {
 	do_div(offset, d->stripe_size);
+
+	/* d->nr_stripes is in range [1, INT_MAX] */
+	if (unlikely(offset >= d->nr_stripes)) {
+		pr_err("Invalid stripe %llu (>= nr_stripes %d).\n",
+			offset, d->nr_stripes);
+		return -EINVAL;
+	}
+
+	/*
+	 * Here offset is definitly smaller than INT_MAX,
+	 * return it as int will never overflow.
+	 */
 	return offset;
 }
 
@@ -44,7 +60,10 @@
 					   uint64_t offset,
 					   unsigned int nr_sectors)
 {
-	unsigned int stripe = offset_to_stripe(&dc->disk, offset);
+	int stripe = offset_to_stripe(&dc->disk, offset);
+
+	if (stripe < 0)
+		return false;
 
 	while (1) {
 		if (atomic_read(dc->disk.stripe_sectors_dirty + stripe))
--- linux-ein-5.4.0.orig/drivers/md/dm-bio-record.h
+++ linux-ein-5.4.0/drivers/md/dm-bio-record.h
@@ -20,8 +20,13 @@
 struct dm_bio_details {
 	struct gendisk *bi_disk;
 	u8 bi_partno;
+	int __bi_remaining;
 	unsigned long bi_flags;
 	struct bvec_iter bi_iter;
+	bio_end_io_t *bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+	struct bio_integrity_payload *bi_integrity;
+#endif
 };
 
 static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
@@ -30,6 +35,11 @@
 	bd->bi_partno = bio->bi_partno;
 	bd->bi_flags = bio->bi_flags;
 	bd->bi_iter = bio->bi_iter;
+	bd->__bi_remaining = atomic_read(&bio->__bi_remaining);
+	bd->bi_end_io = bio->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+	bd->bi_integrity = bio_integrity(bio);
+#endif
 }
 
 static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
@@ -38,6 +48,11 @@
 	bio->bi_partno = bd->bi_partno;
 	bio->bi_flags = bd->bi_flags;
 	bio->bi_iter = bd->bi_iter;
+	atomic_set(&bio->__bi_remaining, bd->__bi_remaining);
+	bio->bi_end_io = bd->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+	bio->bi_integrity = bd->bi_integrity;
+#endif
 }
 
 #endif
--- linux-ein-5.4.0.orig/drivers/md/dm-bufio.c
+++ linux-ein-5.4.0/drivers/md/dm-bufio.c
@@ -1438,6 +1438,10 @@
 sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
 {
 	sector_t s = i_size_read(c->bdev->bd_inode) >> SECTOR_SHIFT;
+	if (s >= c->start)
+		s -= c->start;
+	else
+		s = 0;
 	if (likely(c->sectors_per_block_bits >= 0))
 		s >>= c->sectors_per_block_bits;
 	else
@@ -1446,6 +1450,12 @@
 }
 EXPORT_SYMBOL_GPL(dm_bufio_get_device_size);
 
+struct dm_io_client *dm_bufio_get_dm_io_client(struct dm_bufio_client *c)
+{
+	return c->dm_io;
+}
+EXPORT_SYMBOL_GPL(dm_bufio_get_dm_io_client);
+
 sector_t dm_bufio_get_block_number(struct dm_buffer *b)
 {
 	return b->block;
--- linux-ein-5.4.0.orig/drivers/md/dm-cache-metadata.c
+++ linux-ein-5.4.0/drivers/md/dm-cache-metadata.c
@@ -537,21 +537,27 @@
 					  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;
 }
 
-static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd)
+static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd,
+					      bool destroy_bm)
 {
 	dm_sm_destroy(cmd->metadata_sm);
 	dm_tm_destroy(cmd->tm);
-	dm_block_manager_destroy(cmd->bm);
+	if (destroy_bm)
+		dm_block_manager_destroy(cmd->bm);
 }
 
 typedef unsigned long (*flags_mutator)(unsigned long);
@@ -822,7 +828,7 @@
 		cmd2 = lookup(bdev);
 		if (cmd2) {
 			mutex_unlock(&table_lock);
-			__destroy_persistent_data_objects(cmd);
+			__destroy_persistent_data_objects(cmd, true);
 			kfree(cmd);
 			return cmd2;
 		}
@@ -870,7 +876,7 @@
 		mutex_unlock(&table_lock);
 
 		if (!cmd->fail_io)
-			__destroy_persistent_data_objects(cmd);
+			__destroy_persistent_data_objects(cmd, true);
 		kfree(cmd);
 	}
 }
@@ -1804,14 +1810,52 @@
 
 int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
 {
-	int r;
+	int r = -EINVAL;
+	struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
+
+	/* fail_io is double-checked with cmd->root_lock held below */
+	if (unlikely(cmd->fail_io))
+		return r;
+
+	/*
+	 * Replacement block manager (new_bm) is created and old_bm destroyed outside of
+	 * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
+	 * shrinker associated with the block manager's bufio client vs cmd root_lock).
+	 * - must take shrinker_rwsem without holding cmd->root_lock
+	 */
+	new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
+					 CACHE_MAX_CONCURRENT_LOCKS);
 
 	WRITE_LOCK(cmd);
-	__destroy_persistent_data_objects(cmd);
-	r = __create_persistent_data_objects(cmd, false);
+	if (cmd->fail_io) {
+		WRITE_UNLOCK(cmd);
+		goto out;
+	}
+
+	__destroy_persistent_data_objects(cmd, false);
+	old_bm = cmd->bm;
+	if (IS_ERR(new_bm)) {
+		DMERR("could not create block manager during abort");
+		cmd->bm = NULL;
+		r = PTR_ERR(new_bm);
+		goto out_unlock;
+	}
+
+	cmd->bm = new_bm;
+	r = __open_or_format_metadata(cmd, false);
+	if (r) {
+		cmd->bm = NULL;
+		goto out_unlock;
+	}
+	new_bm = NULL;
+out_unlock:
 	if (r)
 		cmd->fail_io = true;
 	WRITE_UNLOCK(cmd);
+	dm_block_manager_destroy(old_bm);
+out:
+	if (new_bm && !IS_ERR(new_bm))
+		dm_block_manager_destroy(new_bm);
 
 	return r;
 }
--- linux-ein-5.4.0.orig/drivers/md/dm-cache-policy-smq.c
+++ linux-ein-5.4.0/drivers/md/dm-cache-policy-smq.c
@@ -854,7 +854,13 @@
 
 	struct background_tracker *bg_work;
 
-	bool migrations_allowed;
+	bool migrations_allowed:1;
+
+	/*
+	 * If this is set the policy will try and clean the whole cache
+	 * even if the device is not idle.
+	 */
+	bool cleaner:1;
 };
 
 /*----------------------------------------------------------------*/
@@ -1133,7 +1139,7 @@
 	 * Cache entries may not be populated.  So we cannot rely on the
 	 * size of the clean queue.
 	 */
-	if (idle) {
+	if (idle || mq->cleaner) {
 		/*
 		 * We'd like to clean everything.
 		 */
@@ -1716,11 +1722,9 @@
 		*hotspot_block_size /= 2u;
 }
 
-static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size,
-					    sector_t origin_size,
-					    sector_t cache_block_size,
-					    bool mimic_mq,
-					    bool migrations_allowed)
+static struct dm_cache_policy *
+__smq_create(dm_cblock_t cache_size, sector_t origin_size, sector_t cache_block_size,
+	     bool mimic_mq, bool migrations_allowed, bool cleaner)
 {
 	unsigned i;
 	unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
@@ -1807,6 +1811,7 @@
 		goto bad_btracker;
 
 	mq->migrations_allowed = migrations_allowed;
+	mq->cleaner = cleaner;
 
 	return &mq->policy;
 
@@ -1830,21 +1835,24 @@
 					  sector_t origin_size,
 					  sector_t cache_block_size)
 {
-	return __smq_create(cache_size, origin_size, cache_block_size, false, true);
+	return __smq_create(cache_size, origin_size, cache_block_size,
+			    false, true, false);
 }
 
 static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
 					 sector_t origin_size,
 					 sector_t cache_block_size)
 {
-	return __smq_create(cache_size, origin_size, cache_block_size, true, true);
+	return __smq_create(cache_size, origin_size, cache_block_size,
+			    true, true, false);
 }
 
 static struct dm_cache_policy *cleaner_create(dm_cblock_t cache_size,
 					      sector_t origin_size,
 					      sector_t cache_block_size)
 {
-	return __smq_create(cache_size, origin_size, cache_block_size, false, false);
+	return __smq_create(cache_size, origin_size, cache_block_size,
+			    false, false, true);
 }
 
 /*----------------------------------------------------------------*/
--- linux-ein-5.4.0.orig/drivers/md/dm-cache-target.c
+++ linux-ein-5.4.0/drivers/md/dm-cache-target.c
@@ -1011,16 +1011,16 @@
 	if (get_cache_mode(cache) >= CM_READ_ONLY)
 		return;
 
-	if (dm_cache_metadata_set_needs_check(cache->cmd)) {
-		DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
-		set_cache_mode(cache, CM_FAIL);
-	}
-
 	DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
 	if (dm_cache_metadata_abort(cache->cmd)) {
 		DMERR("%s: failed to abort metadata transaction", dev_name);
 		set_cache_mode(cache, CM_FAIL);
 	}
+
+	if (dm_cache_metadata_set_needs_check(cache->cmd)) {
+		DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+		set_cache_mode(cache, CM_FAIL);
+	}
 }
 
 static void metadata_operation_failed(struct cache *cache, const char *op, int r)
@@ -1910,6 +1910,7 @@
 
 		else
 			commit_needed = process_bio(cache, bio) || commit_needed;
+		cond_resched();
 	}
 
 	if (commit_needed)
@@ -1932,6 +1933,7 @@
 	while ((bio = bio_list_pop(&bios))) {
 		bio->bi_status = BLK_STS_DM_REQUEUE;
 		bio_endio(bio);
+		cond_resched();
 	}
 }
 
@@ -1972,6 +1974,8 @@
 		r = mg_start(cache, op, NULL);
 		if (r)
 			break;
+
+		cond_resched();
 	}
 }
 
@@ -1992,6 +1996,7 @@
 	if (cache->prison)
 		dm_bio_prison_destroy_v2(cache->prison);
 
+	cancel_delayed_work_sync(&cache->waker);
 	if (cache->wq)
 		destroy_workqueue(cache->wq);
 
@@ -2867,8 +2872,8 @@
 	prevent_background_work(cache);
 	BUG_ON(atomic_read(&cache->nr_io_migrations));
 
-	cancel_delayed_work(&cache->waker);
-	flush_workqueue(cache->wq);
+	cancel_delayed_work_sync(&cache->waker);
+	drain_workqueue(cache->wq);
 	WARN_ON(cache->tracker.in_flight);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/md/dm-clone-metadata.c
+++ linux-ein-5.4.0/drivers/md/dm-clone-metadata.c
@@ -67,23 +67,34 @@
  * To save constantly doing look ups on disk we keep an in core copy of the
  * on-disk bitmap, the region_map.
  *
- * To further reduce metadata I/O overhead we use a second bitmap, the dmap
- * (dirty bitmap), which tracks the dirty words, i.e. longs, of the region_map.
+ * In order to track which regions are hydrated during a metadata transaction,
+ * we use a second set of bitmaps, the dmap (dirty bitmap), which includes two
+ * bitmaps, namely dirty_regions and dirty_words. The dirty_regions bitmap
+ * tracks the regions that got hydrated during the current metadata
+ * transaction. The dirty_words bitmap tracks the dirty words, i.e. longs, of
+ * the dirty_regions bitmap.
+ *
+ * This allows us to precisely track the regions that were hydrated during the
+ * current metadata transaction and update the metadata accordingly, when we
+ * commit the current transaction. This is important because dm-clone should
+ * only commit the metadata of regions that were properly flushed to the
+ * destination device beforehand. Otherwise, in case of a crash, we could end
+ * up with a corrupted dm-clone device.
  *
  * When a region finishes hydrating dm-clone calls
  * dm_clone_set_region_hydrated(), or for discard requests
  * dm_clone_cond_set_range(), which sets the corresponding bits in region_map
  * and dmap.
  *
- * During a metadata commit we scan the dmap for dirty region_map words (longs)
- * and update accordingly the on-disk metadata. Thus, we don't have to flush to
- * disk the whole region_map. We can just flush the dirty region_map words.
+ * During a metadata commit we scan dmap->dirty_words and dmap->dirty_regions
+ * and update the on-disk metadata accordingly. Thus, we don't have to flush to
+ * disk the whole region_map. We can just flush the dirty region_map bits.
  *
- * We use a dirty bitmap, which is smaller than the original region_map, to
- * reduce the amount of memory accesses during a metadata commit. As dm-bitset
- * accesses the on-disk bitmap in 64-bit word granularity, there is no
- * significant benefit in tracking the dirty region_map bits with a smaller
- * granularity.
+ * We use the helper dmap->dirty_words bitmap, which is smaller than the
+ * original region_map, to reduce the amount of memory accesses during a
+ * metadata commit. Moreover, as dm-bitset also accesses the on-disk bitmap in
+ * 64-bit word granularity, the dirty_words bitmap helps us avoid useless disk
+ * accesses.
  *
  * We could update directly the on-disk bitmap, when dm-clone calls either
  * dm_clone_set_region_hydrated() or dm_clone_cond_set_range(), buts this
@@ -92,12 +103,13 @@
  * e.g., in a hooked overwrite bio's completion routine, and further reduce the
  * I/O completion latency.
  *
- * We maintain two dirty bitmaps. During a metadata commit we atomically swap
- * the currently used dmap with the unused one. This allows the metadata update
- * functions to run concurrently with an ongoing commit.
+ * We maintain two dirty bitmap sets. During a metadata commit we atomically
+ * swap the currently used dmap with the unused one. This allows the metadata
+ * update functions to run concurrently with an ongoing commit.
  */
 struct dirty_map {
 	unsigned long *dirty_words;
+	unsigned long *dirty_regions;
 	unsigned int changed;
 };
 
@@ -115,6 +127,9 @@
 	struct dirty_map dmap[2];
 	struct dirty_map *current_dmap;
 
+	/* Protected by lock */
+	struct dirty_map *committing_dmap;
+
 	/*
 	 * In core copy of the on-disk bitmap to save constantly doing look ups
 	 * on disk.
@@ -461,34 +476,53 @@
 	return BITS_TO_LONGS(nr_bits) * sizeof(long);
 }
 
-static int dirty_map_init(struct dm_clone_metadata *cmd)
+static int __dirty_map_init(struct dirty_map *dmap, unsigned long nr_words,
+			    unsigned long nr_regions)
 {
-	cmd->dmap[0].changed = 0;
-	cmd->dmap[0].dirty_words = kvzalloc(bitmap_size(cmd->nr_words), GFP_KERNEL);
+	dmap->changed = 0;
 
-	if (!cmd->dmap[0].dirty_words) {
-		DMERR("Failed to allocate dirty bitmap");
+	dmap->dirty_words = kvzalloc(bitmap_size(nr_words), GFP_KERNEL);
+	if (!dmap->dirty_words)
+		return -ENOMEM;
+
+	dmap->dirty_regions = kvzalloc(bitmap_size(nr_regions), GFP_KERNEL);
+	if (!dmap->dirty_regions) {
+		kvfree(dmap->dirty_words);
 		return -ENOMEM;
 	}
 
-	cmd->dmap[1].changed = 0;
-	cmd->dmap[1].dirty_words = kvzalloc(bitmap_size(cmd->nr_words), GFP_KERNEL);
+	return 0;
+}
+
+static void __dirty_map_exit(struct dirty_map *dmap)
+{
+	kvfree(dmap->dirty_words);
+	kvfree(dmap->dirty_regions);
+}
+
+static int dirty_map_init(struct dm_clone_metadata *cmd)
+{
+	if (__dirty_map_init(&cmd->dmap[0], cmd->nr_words, cmd->nr_regions)) {
+		DMERR("Failed to allocate dirty bitmap");
+		return -ENOMEM;
+	}
 
-	if (!cmd->dmap[1].dirty_words) {
+	if (__dirty_map_init(&cmd->dmap[1], cmd->nr_words, cmd->nr_regions)) {
 		DMERR("Failed to allocate dirty bitmap");
-		kvfree(cmd->dmap[0].dirty_words);
+		__dirty_map_exit(&cmd->dmap[0]);
 		return -ENOMEM;
 	}
 
 	cmd->current_dmap = &cmd->dmap[0];
+	cmd->committing_dmap = NULL;
 
 	return 0;
 }
 
 static void dirty_map_exit(struct dm_clone_metadata *cmd)
 {
-	kvfree(cmd->dmap[0].dirty_words);
-	kvfree(cmd->dmap[1].dirty_words);
+	__dirty_map_exit(&cmd->dmap[0]);
+	__dirty_map_exit(&cmd->dmap[1]);
 }
 
 static int __load_bitset_in_core(struct dm_clone_metadata *cmd)
@@ -622,7 +656,7 @@
 	return (bit >= (start + nr_regions));
 }
 
-unsigned long dm_clone_nr_of_hydrated_regions(struct dm_clone_metadata *cmd)
+unsigned int dm_clone_nr_of_hydrated_regions(struct dm_clone_metadata *cmd)
 {
 	return bitmap_weight(cmd->region_map, cmd->nr_regions);
 }
@@ -633,21 +667,23 @@
 	return find_next_zero_bit(cmd->region_map, cmd->nr_regions, start);
 }
 
-static int __update_metadata_word(struct dm_clone_metadata *cmd, unsigned long word)
+static int __update_metadata_word(struct dm_clone_metadata *cmd,
+				  unsigned long *dirty_regions,
+				  unsigned long word)
 {
 	int r;
 	unsigned long index = word * BITS_PER_LONG;
 	unsigned long max_index = min(cmd->nr_regions, (word + 1) * BITS_PER_LONG);
 
 	while (index < max_index) {
-		if (test_bit(index, cmd->region_map)) {
+		if (test_bit(index, dirty_regions)) {
 			r = dm_bitset_set_bit(&cmd->bitset_info, cmd->bitset_root,
 					      index, &cmd->bitset_root);
-
 			if (r) {
 				DMERR("dm_bitset_set_bit failed");
 				return r;
 			}
+			__clear_bit(index, dirty_regions);
 		}
 		index++;
 	}
@@ -712,7 +748,7 @@
 static int __flush_dmap(struct dm_clone_metadata *cmd, struct dirty_map *dmap)
 {
 	int r;
-	unsigned long word, flags;
+	unsigned long word;
 
 	word = 0;
 	do {
@@ -721,7 +757,7 @@
 		if (word == cmd->nr_words)
 			break;
 
-		r = __update_metadata_word(cmd, word);
+		r = __update_metadata_word(cmd, dmap->dirty_regions, word);
 
 		if (r)
 			return r;
@@ -736,23 +772,24 @@
 		return r;
 
 	/* Update the changed flag */
-	spin_lock_irqsave(&cmd->bitmap_lock, flags);
+	spin_lock_irq(&cmd->bitmap_lock);
 	dmap->changed = 0;
-	spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
+	spin_unlock_irq(&cmd->bitmap_lock);
 
 	return 0;
 }
 
-int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
+int dm_clone_metadata_pre_commit(struct dm_clone_metadata *cmd)
 {
-	int r = -EPERM;
-	unsigned long flags;
+	int r = 0;
 	struct dirty_map *dmap, *next_dmap;
 
 	down_write(&cmd->lock);
 
-	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm))
+	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
+		r = -EPERM;
 		goto out;
+	}
 
 	/* Get current dirty bitmap */
 	dmap = cmd->current_dmap;
@@ -764,21 +801,43 @@
 	 * The last commit failed, so we don't have a clean dirty-bitmap to
 	 * use.
 	 */
-	if (WARN_ON(next_dmap->changed)) {
+	if (WARN_ON(next_dmap->changed || cmd->committing_dmap)) {
 		r = -EINVAL;
 		goto out;
 	}
 
 	/* Swap dirty bitmaps */
-	spin_lock_irqsave(&cmd->bitmap_lock, flags);
+	spin_lock_irq(&cmd->bitmap_lock);
 	cmd->current_dmap = next_dmap;
-	spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
+	spin_unlock_irq(&cmd->bitmap_lock);
 
-	/*
-	 * No one is accessing the old dirty bitmap anymore, so we can flush
-	 * it.
-	 */
-	r = __flush_dmap(cmd, dmap);
+	/* Set old dirty bitmap as currently committing */
+	cmd->committing_dmap = dmap;
+out:
+	up_write(&cmd->lock);
+
+	return r;
+}
+
+int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
+{
+	int r = -EPERM;
+
+	down_write(&cmd->lock);
+
+	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm))
+		goto out;
+
+	if (WARN_ON(!cmd->committing_dmap)) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	r = __flush_dmap(cmd, cmd->committing_dmap);
+	if (!r) {
+		/* Clear committing dmap */
+		cmd->committing_dmap = NULL;
+	}
 out:
 	up_write(&cmd->lock);
 
@@ -791,6 +850,12 @@
 	struct dirty_map *dmap;
 	unsigned long word, flags;
 
+	if (unlikely(region_nr >= cmd->nr_regions)) {
+		DMERR("Region %lu out of range (total number of regions %lu)",
+		      region_nr, cmd->nr_regions);
+		return -ERANGE;
+	}
+
 	word = region_nr / BITS_PER_LONG;
 
 	spin_lock_irqsave(&cmd->bitmap_lock, flags);
@@ -803,6 +868,7 @@
 	dmap = cmd->current_dmap;
 
 	__set_bit(word, dmap->dirty_words);
+	__set_bit(region_nr, dmap->dirty_regions);
 	__set_bit(region_nr, cmd->region_map);
 	dmap->changed = 1;
 
@@ -817,9 +883,16 @@
 {
 	int r = 0;
 	struct dirty_map *dmap;
-	unsigned long word, region_nr, flags;
+	unsigned long word, region_nr;
 
-	spin_lock_irqsave(&cmd->bitmap_lock, flags);
+	if (unlikely(start >= cmd->nr_regions || (start + nr_regions) < start ||
+		     (start + nr_regions) > cmd->nr_regions)) {
+		DMERR("Invalid region range: start %lu, nr_regions %lu (total number of regions %lu)",
+		      start, nr_regions, cmd->nr_regions);
+		return -ERANGE;
+	}
+
+	spin_lock_irq(&cmd->bitmap_lock);
 
 	if (cmd->read_only) {
 		r = -EPERM;
@@ -831,12 +904,13 @@
 		if (!test_bit(region_nr, cmd->region_map)) {
 			word = region_nr / BITS_PER_LONG;
 			__set_bit(word, dmap->dirty_words);
+			__set_bit(region_nr, dmap->dirty_regions);
 			__set_bit(region_nr, cmd->region_map);
 			dmap->changed = 1;
 		}
 	}
 out:
-	spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
+	spin_unlock_irq(&cmd->bitmap_lock);
 
 	return r;
 }
@@ -903,13 +977,11 @@
 
 void dm_clone_metadata_set_read_only(struct dm_clone_metadata *cmd)
 {
-	unsigned long flags;
-
 	down_write(&cmd->lock);
 
-	spin_lock_irqsave(&cmd->bitmap_lock, flags);
+	spin_lock_irq(&cmd->bitmap_lock);
 	cmd->read_only = 1;
-	spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
+	spin_unlock_irq(&cmd->bitmap_lock);
 
 	if (!cmd->fail_io)
 		dm_bm_set_read_only(cmd->bm);
@@ -919,13 +991,11 @@
 
 void dm_clone_metadata_set_read_write(struct dm_clone_metadata *cmd)
 {
-	unsigned long flags;
-
 	down_write(&cmd->lock);
 
-	spin_lock_irqsave(&cmd->bitmap_lock, flags);
+	spin_lock_irq(&cmd->bitmap_lock);
 	cmd->read_only = 0;
-	spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
+	spin_unlock_irq(&cmd->bitmap_lock);
 
 	if (!cmd->fail_io)
 		dm_bm_set_read_write(cmd->bm);
--- linux-ein-5.4.0.orig/drivers/md/dm-clone-metadata.h
+++ linux-ein-5.4.0/drivers/md/dm-clone-metadata.h
@@ -44,7 +44,9 @@
  * @start: Starting region number
  * @nr_regions: Number of regions in the range
  *
- * This function doesn't block, so it's safe to call it from interrupt context.
+ * This function doesn't block, but since it uses spin_lock_irq()/spin_unlock_irq()
+ * it's NOT safe to call it from any context where interrupts are disabled, e.g.,
+ * from interrupt context.
  */
 int dm_clone_cond_set_range(struct dm_clone_metadata *cmd, unsigned long start,
 			    unsigned long nr_regions);
@@ -73,7 +75,23 @@
 
 /*
  * Commit dm-clone metadata to disk.
+ *
+ * We use a two phase commit:
+ *
+ * 1. dm_clone_metadata_pre_commit(): Prepare the current transaction for
+ *    committing. After this is called, all subsequent metadata updates, done
+ *    through either dm_clone_set_region_hydrated() or
+ *    dm_clone_cond_set_range(), will be part of the **next** transaction.
+ *
+ * 2. dm_clone_metadata_commit(): Actually commit the current transaction to
+ *    disk and start a new transaction.
+ *
+ * This allows dm-clone to flush the destination device after step (1) to
+ * ensure that all freshly hydrated regions, for which we are updating the
+ * metadata, are properly written to non-volatile storage and won't be lost in
+ * case of a crash.
  */
+int dm_clone_metadata_pre_commit(struct dm_clone_metadata *cmd);
 int dm_clone_metadata_commit(struct dm_clone_metadata *cmd);
 
 /*
@@ -110,6 +128,7 @@
  * Switches metadata to a read only mode. Once read-only mode has been entered
  * the following functions will return -EPERM:
  *
+ *   dm_clone_metadata_pre_commit()
  *   dm_clone_metadata_commit()
  *   dm_clone_set_region_hydrated()
  *   dm_clone_cond_set_range()
@@ -137,7 +156,7 @@
 /*
  * Returns the number of hydrated regions.
  */
-unsigned long dm_clone_nr_of_hydrated_regions(struct dm_clone_metadata *cmd);
+unsigned int dm_clone_nr_of_hydrated_regions(struct dm_clone_metadata *cmd);
 
 /*
  * Returns the first unhydrated region with region_nr >= @start
--- linux-ein-5.4.0.orig/drivers/md/dm-clone-target.c
+++ linux-ein-5.4.0/drivers/md/dm-clone-target.c
@@ -86,6 +86,12 @@
 
 	struct dm_clone_metadata *cmd;
 
+	/*
+	 * bio used to flush the destination device, before committing the
+	 * metadata.
+	 */
+	struct bio flush_bio;
+
 	/* Region hydration hash table */
 	struct hash_table_bucket *ht;
 
@@ -276,7 +282,7 @@
 /* Get the address of the region in sectors */
 static inline sector_t region_to_sector(struct clone *clone, unsigned long region_nr)
 {
-	return (region_nr << clone->region_shift);
+	return ((sector_t)region_nr << clone->region_shift);
 }
 
 /* Get the region number of the bio */
@@ -287,10 +293,17 @@
 
 /* Get the region range covered by the bio */
 static void bio_region_range(struct clone *clone, struct bio *bio,
-			     unsigned long *rs, unsigned long *re)
+			     unsigned long *rs, unsigned long *nr_regions)
 {
+	unsigned long end;
+
 	*rs = dm_sector_div_up(bio->bi_iter.bi_sector, clone->region_size);
-	*re = bio_end_sector(bio) >> clone->region_shift;
+	end = bio_end_sector(bio) >> clone->region_shift;
+
+	if (*rs >= end)
+		*nr_regions = 0;
+	else
+		*nr_regions = end - *rs;
 }
 
 /* Check whether a bio overwrites a region */
@@ -332,8 +345,6 @@
  */
 static void issue_bio(struct clone *clone, struct bio *bio)
 {
-	unsigned long flags;
-
 	if (!bio_triggers_commit(clone, bio)) {
 		generic_make_request(bio);
 		return;
@@ -352,9 +363,9 @@
 	 * Batch together any bios that trigger commits and then issue a single
 	 * commit for them in process_deferred_flush_bios().
 	 */
-	spin_lock_irqsave(&clone->lock, flags);
+	spin_lock_irq(&clone->lock);
 	bio_list_add(&clone->deferred_flush_bios, bio);
-	spin_unlock_irqrestore(&clone->lock, flags);
+	spin_unlock_irq(&clone->lock);
 
 	wake_worker(clone);
 }
@@ -450,7 +461,7 @@
 
 static void complete_discard_bio(struct clone *clone, struct bio *bio, bool success)
 {
-	unsigned long rs, re;
+	unsigned long rs, nr_regions;
 
 	/*
 	 * If the destination device supports discards, remap and trim the
@@ -459,9 +470,9 @@
 	 */
 	if (test_bit(DM_CLONE_DISCARD_PASSDOWN, &clone->flags) && success) {
 		remap_to_dest(clone, bio);
-		bio_region_range(clone, bio, &rs, &re);
-		trim_bio(bio, rs << clone->region_shift,
-			 (re - rs) << clone->region_shift);
+		bio_region_range(clone, bio, &rs, &nr_regions);
+		trim_bio(bio, region_to_sector(clone, rs),
+			 nr_regions << clone->region_shift);
 		generic_make_request(bio);
 	} else
 		bio_endio(bio);
@@ -469,12 +480,21 @@
 
 static void process_discard_bio(struct clone *clone, struct bio *bio)
 {
-	unsigned long rs, re, flags;
+	unsigned long rs, nr_regions;
 
-	bio_region_range(clone, bio, &rs, &re);
-	BUG_ON(re > clone->nr_regions);
+	bio_region_range(clone, bio, &rs, &nr_regions);
+	if (!nr_regions) {
+		bio_endio(bio);
+		return;
+	}
 
-	if (unlikely(rs == re)) {
+	if (WARN_ON(rs >= clone->nr_regions || (rs + nr_regions) < rs ||
+		    (rs + nr_regions) > clone->nr_regions)) {
+		DMERR("%s: Invalid range (%lu + %lu, total regions %lu) for discard (%llu + %u)",
+		      clone_device_name(clone), rs, nr_regions,
+		      clone->nr_regions,
+		      (unsigned long long)bio->bi_iter.bi_sector,
+		      bio_sectors(bio));
 		bio_endio(bio);
 		return;
 	}
@@ -483,7 +503,7 @@
 	 * The covered regions are already hydrated so we just need to pass
 	 * down the discard.
 	 */
-	if (dm_clone_is_range_hydrated(clone->cmd, rs, re - rs)) {
+	if (dm_clone_is_range_hydrated(clone->cmd, rs, nr_regions)) {
 		complete_discard_bio(clone, bio, true);
 		return;
 	}
@@ -501,9 +521,9 @@
 	/*
 	 * Defer discard processing.
 	 */
-	spin_lock_irqsave(&clone->lock, flags);
+	spin_lock_irq(&clone->lock);
 	bio_list_add(&clone->deferred_discard_bios, bio);
-	spin_unlock_irqrestore(&clone->lock, flags);
+	spin_unlock_irq(&clone->lock);
 
 	wake_worker(clone);
 }
@@ -778,11 +798,14 @@
 	struct dm_io_region from, to;
 	struct clone *clone = hd->clone;
 
+	if (WARN_ON(!nr_regions))
+		return;
+
 	region_size = clone->region_size;
 	region_start = hd->region_nr;
 	region_end = region_start + nr_regions - 1;
 
-	total_size = (nr_regions - 1) << clone->region_shift;
+	total_size = region_to_sector(clone, nr_regions - 1);
 
 	if (region_end == clone->nr_regions - 1) {
 		/*
@@ -1106,10 +1129,13 @@
 /*
  * A non-zero return indicates read-only or fail mode.
  */
-static int commit_metadata(struct clone *clone)
+static int commit_metadata(struct clone *clone, bool *dest_dev_flushed)
 {
 	int r = 0;
 
+	if (dest_dev_flushed)
+		*dest_dev_flushed = false;
+
 	mutex_lock(&clone->commit_lock);
 
 	if (!dm_clone_changed_this_transaction(clone->cmd))
@@ -1120,8 +1146,26 @@
 		goto out;
 	}
 
-	r = dm_clone_metadata_commit(clone->cmd);
+	r = dm_clone_metadata_pre_commit(clone->cmd);
+	if (unlikely(r)) {
+		__metadata_operation_failed(clone, "dm_clone_metadata_pre_commit", r);
+		goto out;
+	}
+
+	bio_reset(&clone->flush_bio);
+	bio_set_dev(&clone->flush_bio, clone->dest_dev->bdev);
+	clone->flush_bio.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
+
+	r = submit_bio_wait(&clone->flush_bio);
+	if (unlikely(r)) {
+		__metadata_operation_failed(clone, "flush destination device", r);
+		goto out;
+	}
 
+	if (dest_dev_flushed)
+		*dest_dev_flushed = true;
+
+	r = dm_clone_metadata_commit(clone->cmd);
 	if (unlikely(r)) {
 		__metadata_operation_failed(clone, "dm_clone_metadata_commit", r);
 		goto out;
@@ -1140,13 +1184,13 @@
 	int r = -EPERM;
 	struct bio *bio;
 	struct blk_plug plug;
-	unsigned long rs, re, flags;
+	unsigned long rs, nr_regions;
 	struct bio_list discards = BIO_EMPTY_LIST;
 
-	spin_lock_irqsave(&clone->lock, flags);
+	spin_lock_irq(&clone->lock);
 	bio_list_merge(&discards, &clone->deferred_discard_bios);
 	bio_list_init(&clone->deferred_discard_bios);
-	spin_unlock_irqrestore(&clone->lock, flags);
+	spin_unlock_irq(&clone->lock);
 
 	if (bio_list_empty(&discards))
 		return;
@@ -1156,14 +1200,13 @@
 
 	/* Update the metadata */
 	bio_list_for_each(bio, &discards) {
-		bio_region_range(clone, bio, &rs, &re);
+		bio_region_range(clone, bio, &rs, &nr_regions);
 		/*
 		 * A discard request might cover regions that have been already
 		 * hydrated. There is no need to update the metadata for these
 		 * regions.
 		 */
-		r = dm_clone_cond_set_range(clone->cmd, rs, re - rs);
-
+		r = dm_clone_cond_set_range(clone->cmd, rs, nr_regions);
 		if (unlikely(r))
 			break;
 	}
@@ -1176,13 +1219,12 @@
 
 static void process_deferred_bios(struct clone *clone)
 {
-	unsigned long flags;
 	struct bio_list bios = BIO_EMPTY_LIST;
 
-	spin_lock_irqsave(&clone->lock, flags);
+	spin_lock_irq(&clone->lock);
 	bio_list_merge(&bios, &clone->deferred_bios);
 	bio_list_init(&clone->deferred_bios);
-	spin_unlock_irqrestore(&clone->lock, flags);
+	spin_unlock_irq(&clone->lock);
 
 	if (bio_list_empty(&bios))
 		return;
@@ -1193,7 +1235,7 @@
 static void process_deferred_flush_bios(struct clone *clone)
 {
 	struct bio *bio;
-	unsigned long flags;
+	bool dest_dev_flushed;
 	struct bio_list bios = BIO_EMPTY_LIST;
 	struct bio_list bio_completions = BIO_EMPTY_LIST;
 
@@ -1201,19 +1243,19 @@
 	 * If there are any deferred flush bios, we must commit the metadata
 	 * before issuing them or signaling their completion.
 	 */
-	spin_lock_irqsave(&clone->lock, flags);
+	spin_lock_irq(&clone->lock);
 	bio_list_merge(&bios, &clone->deferred_flush_bios);
 	bio_list_init(&clone->deferred_flush_bios);
 
 	bio_list_merge(&bio_completions, &clone->deferred_flush_completions);
 	bio_list_init(&clone->deferred_flush_completions);
-	spin_unlock_irqrestore(&clone->lock, flags);
+	spin_unlock_irq(&clone->lock);
 
 	if (bio_list_empty(&bios) && bio_list_empty(&bio_completions) &&
 	    !(dm_clone_changed_this_transaction(clone->cmd) && need_commit_due_to_time(clone)))
 		return;
 
-	if (commit_metadata(clone)) {
+	if (commit_metadata(clone, &dest_dev_flushed)) {
 		bio_list_merge(&bios, &bio_completions);
 
 		while ((bio = bio_list_pop(&bios)))
@@ -1227,8 +1269,17 @@
 	while ((bio = bio_list_pop(&bio_completions)))
 		bio_endio(bio);
 
-	while ((bio = bio_list_pop(&bios)))
-		generic_make_request(bio);
+	while ((bio = bio_list_pop(&bios))) {
+		if ((bio->bi_opf & REQ_PREFLUSH) && dest_dev_flushed) {
+			/* We just flushed the destination device as part of
+			 * the metadata commit, so there is no reason to send
+			 * another flush.
+			 */
+			bio_endio(bio);
+		} else {
+			generic_make_request(bio);
+		}
+	}
 }
 
 static void do_worker(struct work_struct *work)
@@ -1400,7 +1451,7 @@
 
 		/* Commit to ensure statistics aren't out-of-date */
 		if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti))
-			(void) commit_metadata(clone);
+			(void) commit_metadata(clone, NULL);
 
 		r = dm_clone_get_free_metadata_block_count(clone->cmd, &nr_free_metadata_blocks);
 
@@ -1418,7 +1469,7 @@
 			goto error;
 		}
 
-		DMEMIT("%u %llu/%llu %llu %lu/%lu %u ",
+		DMEMIT("%u %llu/%llu %llu %u/%lu %u ",
 		       DM_CLONE_METADATA_BLOCK_SIZE,
 		       (unsigned long long)(nr_metadata_blocks - nr_free_metadata_blocks),
 		       (unsigned long long)nr_metadata_blocks,
@@ -1738,6 +1789,7 @@
 static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	int r;
+	sector_t nr_regions;
 	struct clone *clone;
 	struct dm_arg_set as;
 
@@ -1779,7 +1831,16 @@
 		goto out_with_source_dev;
 
 	clone->region_shift = __ffs(clone->region_size);
-	clone->nr_regions = dm_sector_div_up(ti->len, clone->region_size);
+	nr_regions = dm_sector_div_up(ti->len, clone->region_size);
+
+	/* Check for overflow */
+	if (nr_regions != (unsigned long)nr_regions) {
+		ti->error = "Too many regions. Consider increasing the region size";
+		r = -EOVERFLOW;
+		goto out_with_source_dev;
+	}
+
+	clone->nr_regions = nr_regions;
 
 	r = validate_nr_regions(clone->nr_regions, &ti->error);
 	if (r)
@@ -1834,6 +1895,7 @@
 	bio_list_init(&clone->deferred_flush_completions);
 	clone->hydration_offset = 0;
 	atomic_set(&clone->hydrations_in_flight, 0);
+	bio_init(&clone->flush_bio, NULL, 0);
 
 	clone->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM, 0);
 	if (!clone->wq) {
@@ -1907,6 +1969,7 @@
 	struct clone *clone = ti->private;
 
 	mutex_destroy(&clone->commit_lock);
+	bio_uninit(&clone->flush_bio);
 
 	for (i = 0; i < clone->nr_ctr_args; i++)
 		kfree(clone->ctr_args[i]);
@@ -1914,6 +1977,7 @@
 
 	mempool_exit(&clone->hydration_pool);
 	dm_kcopyd_client_destroy(clone->kcopyd_client);
+	cancel_delayed_work_sync(&clone->waker);
 	destroy_workqueue(clone->wq);
 	hash_table_exit(clone);
 	dm_clone_metadata_close(clone->cmd);
@@ -1961,7 +2025,7 @@
 	wait_event(clone->hydration_stopped, !atomic_read(&clone->hydrations_in_flight));
 	flush_workqueue(clone->wq);
 
-	(void) commit_metadata(clone);
+	(void) commit_metadata(clone, NULL);
 }
 
 static void clone_resume(struct dm_target *ti)
@@ -2168,6 +2232,7 @@
 	r = dm_register_target(&clone_target);
 	if (r < 0) {
 		DMERR("Failed to register clone target");
+		kmem_cache_destroy(_hydration_cache);
 		return r;
 	}
 
--- linux-ein-5.4.0.orig/drivers/md/dm-core.h
+++ linux-ein-5.4.0/drivers/md/dm-core.h
@@ -18,6 +18,8 @@
 #include "dm.h"
 
 #define DM_RESERVED_MAX_IOS		1024
+#define DM_MAX_TARGETS			1048576
+#define DM_MAX_TARGET_PARAMS		1024
 
 struct dm_kobject_holder {
 	struct kobject kobj;
@@ -106,6 +108,10 @@
 
 	struct block_device *bdev;
 
+	int swap_bios;
+	struct semaphore swap_bios_semaphore;
+	struct mutex swap_bios_lock;
+
 	struct dm_stats stats;
 
 	/* for blk-mq request-based DM support */
--- linux-ein-5.4.0.orig/drivers/md/dm-crypt.c
+++ linux-ein-5.4.0/drivers/md/dm-crypt.c
@@ -331,8 +331,14 @@
 static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
 			      const char *opts)
 {
-	unsigned bs = crypto_skcipher_blocksize(any_tfm(cc));
-	int log = ilog2(bs);
+	unsigned bs;
+	int log;
+
+	if (test_bit(CRYPT_MODE_INTEGRITY_AEAD, &cc->cipher_flags))
+		bs = crypto_aead_blocksize(any_tfm_aead(cc));
+	else
+		bs = crypto_skcipher_blocksize(any_tfm(cc));
+	log = ilog2(bs);
 
 	/* we need to calculate how far we must shift the sector count
 	 * to get the cipher block count, we use this shift in _gen */
@@ -714,10 +720,10 @@
 	u8 buf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(__le64));
 	struct skcipher_request *req;
 	struct scatterlist src, dst;
-	struct crypto_wait wait;
+	DECLARE_CRYPTO_WAIT(wait);
 	int err;
 
-	req = skcipher_request_alloc(any_tfm(cc), GFP_KERNEL | GFP_NOFS);
+	req = skcipher_request_alloc(any_tfm(cc), GFP_NOIO);
 	if (!req)
 		return -ENOMEM;
 
@@ -1548,6 +1554,7 @@
 			io = crypt_io_from_node(rb_first(&write_tree));
 			rb_erase(&io->rb_node, &write_tree);
 			kcryptd_io_write(io);
+			cond_resched();
 		} while (!RB_EMPTY_ROOT(&write_tree));
 		blk_finish_plug(&plug);
 	}
@@ -1620,6 +1627,12 @@
 	io->ctx.bio_out = clone;
 	io->ctx.iter_out = clone->bi_iter;
 
+	if (crypt_integrity_aead(cc)) {
+		bio_copy_data(clone, io->base_bio);
+		io->ctx.bio_in = clone;
+		io->ctx.iter_in = clone->bi_iter;
+	}
+
 	sector += bio_sectors(clone);
 
 	crypt_inc_pending(io);
@@ -2004,7 +2017,7 @@
 
 static int get_key_size(char **key_string)
 {
-	return (*key_string[0] == ':') ? -EINVAL : strlen(*key_string) >> 1;
+	return (*key_string[0] == ':') ? -EINVAL : (int)(strlen(*key_string) >> 1);
 }
 
 #endif
@@ -2086,7 +2099,12 @@
 	struct crypt_config *cc = pool_data;
 	struct page *page;
 
-	if (unlikely(percpu_counter_compare(&cc->n_allocated_pages, dm_crypt_pages_per_client) >= 0) &&
+	/*
+	 * Note, percpu_counter_read_positive() may over (and under) estimate
+	 * the current usage by at most (batch - 1) * num_online_cpus() pages,
+	 * but avoids potential spinlock contention of an exact result.
+	 */
+	if (unlikely(percpu_counter_read_positive(&cc->n_allocated_pages) >= dm_crypt_pages_per_client) &&
 	    likely(gfp_mask & __GFP_NORETRY))
 		return NULL;
 
@@ -2700,21 +2718,18 @@
 	}
 
 	ret = -ENOMEM;
-	cc->io_queue = alloc_workqueue("kcryptd_io/%s",
-				       WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
-				       1, devname);
+	cc->io_queue = alloc_workqueue("kcryptd_io/%s", WQ_MEM_RECLAIM, 1, devname);
 	if (!cc->io_queue) {
 		ti->error = "Couldn't create kcryptd io queue";
 		goto bad;
 	}
 
 	if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
-		cc->crypt_queue = alloc_workqueue("kcryptd/%s",
-						  WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
+		cc->crypt_queue = alloc_workqueue("kcryptd/%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
 						  1, devname);
 	else
 		cc->crypt_queue = alloc_workqueue("kcryptd/%s",
-						  WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
+						  WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
 						  num_online_cpus(), devname);
 	if (!cc->crypt_queue) {
 		ti->error = "Couldn't create kcryptd queue";
@@ -2734,6 +2749,7 @@
 	wake_up_process(cc->write_thread);
 
 	ti->num_flush_bios = 1;
+	ti->limit_swap_bios = true;
 
 	return 0;
 
@@ -2808,6 +2824,11 @@
 	return DM_MAPIO_SUBMITTED;
 }
 
+static char hex2asc(unsigned char c)
+{
+	return c + '0' + ((unsigned)(9 - c) >> 4 & 0x27);
+}
+
 static void crypt_status(struct dm_target *ti, status_type_t type,
 			 unsigned status_flags, char *result, unsigned maxlen)
 {
@@ -2826,9 +2847,12 @@
 		if (cc->key_size > 0) {
 			if (cc->key_string)
 				DMEMIT(":%u:%s", cc->key_size, cc->key_string);
-			else
-				for (i = 0; i < cc->key_size; i++)
-					DMEMIT("%02x", cc->key[i]);
+			else {
+				for (i = 0; i < cc->key_size; i++) {
+					DMEMIT("%c%c", hex2asc(cc->key[i] >> 4),
+					       hex2asc(cc->key[i] & 0xf));
+				}
+			}
 		} else
 			DMEMIT("-");
 
@@ -2954,7 +2978,7 @@
 	limits->max_segment_size = PAGE_SIZE;
 
 	limits->logical_block_size =
-		max_t(unsigned short, limits->logical_block_size, cc->sector_size);
+		max_t(unsigned, limits->logical_block_size, cc->sector_size);
 	limits->physical_block_size =
 		max_t(unsigned, limits->physical_block_size, cc->sector_size);
 	limits->io_min = max_t(unsigned, limits->io_min, cc->sector_size);
--- linux-ein-5.4.0.orig/drivers/md/dm-delay.c
+++ linux-ein-5.4.0/drivers/md/dm-delay.c
@@ -30,7 +30,7 @@
 	struct workqueue_struct *kdelayd_wq;
 	struct work_struct flush_expired_bios;
 	struct list_head delayed_bios;
-	atomic_t may_delay;
+	bool may_delay;
 
 	struct delay_class read;
 	struct delay_class write;
@@ -191,7 +191,7 @@
 	INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
 	INIT_LIST_HEAD(&dc->delayed_bios);
 	mutex_init(&dc->timer_lock);
-	atomic_set(&dc->may_delay, 1);
+	dc->may_delay = true;
 	dc->argc = argc;
 
 	ret = delay_class_ctr(ti, &dc->read, argv);
@@ -245,7 +245,7 @@
 	struct dm_delay_info *delayed;
 	unsigned long expires = 0;
 
-	if (!c->delay || !atomic_read(&dc->may_delay))
+	if (!c->delay)
 		return DM_MAPIO_REMAPPED;
 
 	delayed = dm_per_bio_data(bio, sizeof(struct dm_delay_info));
@@ -254,6 +254,10 @@
 	delayed->expires = expires = jiffies + msecs_to_jiffies(c->delay);
 
 	mutex_lock(&delayed_bios_lock);
+	if (unlikely(!dc->may_delay)) {
+		mutex_unlock(&delayed_bios_lock);
+		return DM_MAPIO_REMAPPED;
+	}
 	c->ops++;
 	list_add_tail(&delayed->list, &dc->delayed_bios);
 	mutex_unlock(&delayed_bios_lock);
@@ -267,7 +271,10 @@
 {
 	struct delay_c *dc = ti->private;
 
-	atomic_set(&dc->may_delay, 0);
+	mutex_lock(&delayed_bios_lock);
+	dc->may_delay = false;
+	mutex_unlock(&delayed_bios_lock);
+
 	del_timer_sync(&dc->delay_timer);
 	flush_bios(flush_delayed_bios(dc, 1));
 }
@@ -276,7 +283,7 @@
 {
 	struct delay_c *dc = ti->private;
 
-	atomic_set(&dc->may_delay, 1);
+	dc->may_delay = true;
 }
 
 static int delay_map(struct dm_target *ti, struct bio *bio)
--- linux-ein-5.4.0.orig/drivers/md/dm-era-target.c
+++ linux-ein-5.4.0/drivers/md/dm-era-target.c
@@ -47,6 +47,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,
@@ -71,8 +72,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__);
@@ -85,12 +84,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__);
@@ -134,7 +135,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);
@@ -746,6 +756,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;
@@ -759,12 +775,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;
@@ -802,6 +812,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);
 }
@@ -839,6 +851,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;
 	}
 
@@ -849,6 +862,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;
 	}
 
@@ -870,7 +885,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);
@@ -882,6 +896,7 @@
 		return r;
 	}
 
+	md->current_writeset->md.root = INVALID_WRITESET_ROOT;
 	md->archived_writesets = true;
 
 	return 0;
@@ -898,7 +913,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;
@@ -951,7 +966,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) {
@@ -1226,8 +1241,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);
@@ -1237,9 +1254,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) {
 			/*
@@ -1247,7 +1266,6 @@
 			 * FIXME: finish.
 			 */
 			failed = true;
-
 		} else if (r == 0)
 			commit_needed = true;
 
@@ -1263,9 +1281,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)
@@ -1369,7 +1397,7 @@
 static void stop_worker(struct era *era)
 {
 	atomic_set(&era->suspended, 1);
-	flush_workqueue(era->wq);
+	drain_workqueue(era->wq);
 }
 
 /*----------------------------------------------------------------
@@ -1486,15 +1514,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";
@@ -1562,6 +1581,12 @@
 	}
 
 	stop_worker(era);
+
+	r = metadata_commit(era->md);
+	if (r) {
+		DMERR("%s: metadata_commit failed", __func__);
+		/* FIXME: fail mode */
+	}
 }
 
 static int era_preresume(struct dm_target *ti)
@@ -1571,16 +1596,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-ein-5.4.0.orig/drivers/md/dm-flakey.c
+++ linux-ein-5.4.0/drivers/md/dm-flakey.c
@@ -124,9 +124,9 @@
 			 * Direction r or w?
 			 */
 			arg_name = dm_shift_arg(as);
-			if (!strcasecmp(arg_name, "w"))
+			if (arg_name && !strcasecmp(arg_name, "w"))
 				fc->corrupt_bio_rw = WRITE;
-			else if (!strcasecmp(arg_name, "r"))
+			else if (arg_name && !strcasecmp(arg_name, "r"))
 				fc->corrupt_bio_rw = READ;
 			else {
 				ti->error = "Invalid corrupt bio direction (r or w)";
@@ -301,8 +301,11 @@
 	 */
 	bio_for_each_segment(bvec, bio, iter) {
 		if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
-			char *segment = (page_address(bio_iter_page(bio, iter))
-					 + bio_iter_offset(bio, iter));
+			char *segment;
+			struct page *page = bio_iter_page(bio, iter);
+			if (unlikely(page == ZERO_PAGE(0)))
+				break;
+			segment = (page_address(page) + bio_iter_offset(bio, iter));
 			segment[corrupt_bio_byte] = fc->corrupt_bio_value;
 			DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
 				"(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
@@ -360,9 +363,11 @@
 		/*
 		 * Corrupt matching writes.
 		 */
-		if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) {
-			if (all_corrupt_bio_flags_match(bio, fc))
-				corrupt_bio_data(bio, fc);
+		if (fc->corrupt_bio_byte) {
+			if (fc->corrupt_bio_rw == WRITE) {
+				if (all_corrupt_bio_flags_match(bio, fc))
+					corrupt_bio_data(bio, fc);
+			}
 			goto map_bio;
 		}
 
@@ -388,13 +393,14 @@
 		return DM_ENDIO_DONE;
 
 	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);
-
+		if (fc->corrupt_bio_byte) {
+			if ((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) &&
 			   !test_bit(ERROR_WRITES, &fc->flags)) {
 			/*
--- linux-ein-5.4.0.orig/drivers/md/dm-integrity.c
+++ linux-ein-5.4.0/drivers/md/dm-integrity.c
@@ -6,6 +6,8 @@
  * This file is released under the GPL.
  */
 
+#include "dm-bio-record.h"
+
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/device-mapper.h>
@@ -29,11 +31,11 @@
 #define DEFAULT_BUFFER_SECTORS		128
 #define DEFAULT_JOURNAL_WATERMARK	50
 #define DEFAULT_SYNC_MSEC		10000
-#define DEFAULT_MAX_JOURNAL_SECTORS	131072
+#define DEFAULT_MAX_JOURNAL_SECTORS	(IS_ENABLED(CONFIG_64BIT) ? 131072 : 8192)
 #define MIN_LOG2_INTERLEAVE_SECTORS	3
 #define MAX_LOG2_INTERLEAVE_SECTORS	31
 #define METADATA_WORKQUEUE_MAX_ACTIVE	16
-#define RECALC_SECTORS			8192
+#define RECALC_SECTORS			(IS_ENABLED(CONFIG_64BIT) ? 32768 : 2048)
 #define RECALC_WRITE_SUPER		16
 #define BITMAP_BLOCK_SIZE		4096	/* don't change it */
 #define BITMAP_FLUSH_INTERVAL		(10 * HZ)
@@ -199,17 +201,19 @@
 	__u8 log2_blocks_per_bitmap_bit;
 
 	unsigned char mode;
-	int suspending;
 
 	int failed;
 
 	struct crypto_shash *internal_hash;
 
+	struct dm_target *ti;
+
 	/* these variables are locked with endio_wait.lock */
 	struct rb_root in_progress;
 	struct list_head wait_list;
 	wait_queue_head_t endio_wait;
 	struct workqueue_struct *wait_wq;
+	struct workqueue_struct *offload_wq;
 
 	unsigned char commit_seq;
 	commit_id_t commit_ids[N_COMMIT_IDS];
@@ -250,6 +254,7 @@
 	bool journal_uptodate;
 	bool just_formatted;
 	bool recalculate_flag;
+	bool legacy_recalculate;
 
 	struct alg_spec internal_hash_alg;
 	struct alg_spec journal_crypt_alg;
@@ -290,11 +295,7 @@
 
 	struct completion *completion;
 
-	struct gendisk *orig_bi_disk;
-	u8 orig_bi_partno;
-	bio_end_io_t *orig_bi_end_io;
-	struct bio_integrity_payload *orig_bi_integrity;
-	struct bvec_iter orig_bi_iter;
+	struct dm_bio_details bio_details;
 };
 
 struct journal_completion {
@@ -381,6 +382,14 @@
 	return READ_ONCE(ic->failed);
 }
 
+static bool dm_integrity_disable_recalculate(struct dm_integrity_c *ic)
+{
+	if ((ic->internal_hash_alg.key || ic->journal_mac_alg.key) &&
+	    !ic->legacy_recalculate)
+		return true;
+	return false;
+}
+
 static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i,
 					  unsigned j, unsigned char seq)
 {
@@ -1343,12 +1352,52 @@
 	return 0;
 }
 
-static void dm_integrity_flush_buffers(struct dm_integrity_c *ic)
+struct flush_request {
+	struct dm_io_request io_req;
+	struct dm_io_region io_reg;
+	struct dm_integrity_c *ic;
+	struct completion comp;
+};
+
+static void flush_notify(unsigned long error, void *fr_)
+{
+	struct flush_request *fr = fr_;
+	if (unlikely(error != 0))
+		dm_integrity_io_error(fr->ic, "flusing disk cache", -EIO);
+	complete(&fr->comp);
+}
+
+static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data)
 {
 	int r;
+
+	struct flush_request fr;
+
+	if (!ic->meta_dev)
+		flush_data = false;
+	if (flush_data) {
+		fr.io_req.bi_op = REQ_OP_WRITE,
+		fr.io_req.bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
+		fr.io_req.mem.type = DM_IO_KMEM,
+		fr.io_req.mem.ptr.addr = NULL,
+		fr.io_req.notify.fn = flush_notify,
+		fr.io_req.notify.context = &fr;
+		fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio),
+		fr.io_reg.bdev = ic->dev->bdev,
+		fr.io_reg.sector = 0,
+		fr.io_reg.count = 0,
+		fr.ic = ic;
+		init_completion(&fr.comp);
+		r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL);
+		BUG_ON(r);
+	}
+
 	r = dm_bufio_write_dirty_buffers(ic->bufio);
 	if (unlikely(r))
 		dm_integrity_io_error(ic, "writing tags", r);
+
+	if (flush_data)
+		wait_for_completion(&fr.comp);
 }
 
 static void sleep_on_endio_wait(struct dm_integrity_c *ic)
@@ -1434,7 +1483,7 @@
 			dio->range.logical_sector += dio->range.n_sectors;
 			bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT);
 			INIT_WORK(&dio->work, integrity_bio_wait);
-			queue_work(ic->wait_wq, &dio->work);
+			queue_work(ic->offload_wq, &dio->work);
 			return;
 		}
 		do_endio_flush(ic, dio);
@@ -1445,14 +1494,9 @@
 {
 	struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
 
-	bio->bi_iter = dio->orig_bi_iter;
-	bio->bi_disk = dio->orig_bi_disk;
-	bio->bi_partno = dio->orig_bi_partno;
-	if (dio->orig_bi_integrity) {
-		bio->bi_integrity = dio->orig_bi_integrity;
+	dm_bio_restore(&dio->bio_details, bio);
+	if (bio->bi_integrity)
 		bio->bi_opf |= REQ_INTEGRITY;
-	}
-	bio->bi_end_io = dio->orig_bi_end_io;
 
 	if (dio->completion)
 		complete(dio->completion);
@@ -1519,7 +1563,7 @@
 		struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
 		char *checksums;
 		unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
-		char checksums_onstack[HASH_MAX_DIGESTSIZE];
+		char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
 		unsigned sectors_to_process = dio->range.n_sectors;
 		sector_t sector = dio->range.logical_sector;
 
@@ -1537,12 +1581,13 @@
 			}
 		}
 
-		__bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
+		__bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
+			struct bio_vec bv_copy = bv;
 			unsigned pos;
 			char *mem, *checksums_ptr;
 
 again:
-			mem = (char *)kmap_atomic(bv.bv_page) + bv.bv_offset;
+			mem = (char *)kmap_atomic(bv_copy.bv_page) + bv_copy.bv_offset;
 			pos = 0;
 			checksums_ptr = checksums;
 			do {
@@ -1551,7 +1596,7 @@
 				sectors_to_process -= ic->sectors_per_block;
 				pos += ic->sectors_per_block << SECTOR_SHIFT;
 				sector += ic->sectors_per_block;
-			} while (pos < bv.bv_len && sectors_to_process && checksums != checksums_onstack);
+			} while (pos < bv_copy.bv_len && sectors_to_process && checksums != checksums_onstack);
 			kunmap_atomic(mem);
 
 			r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
@@ -1571,9 +1616,9 @@
 			if (!sectors_to_process)
 				break;
 
-			if (unlikely(pos < bv.bv_len)) {
-				bv.bv_offset += pos;
-				bv.bv_len -= pos;
+			if (unlikely(pos < bv_copy.bv_len)) {
+				bv_copy.bv_offset += pos;
+				bv_copy.bv_len -= pos;
 				goto again;
 			}
 		}
@@ -1581,7 +1626,7 @@
 		if (likely(checksums != checksums_onstack))
 			kfree(checksums);
 	} else {
-		struct bio_integrity_payload *bip = dio->orig_bi_integrity;
+		struct bio_integrity_payload *bip = dio->bio_details.bi_integrity;
 
 		if (bip) {
 			struct bio_vec biv;
@@ -1748,7 +1793,7 @@
 				} while (++s < ic->sectors_per_block);
 #ifdef INTERNAL_VERIFY
 				if (ic->internal_hash) {
-					char checksums_onstack[max(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
+					char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
 
 					integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack);
 					if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
@@ -1860,7 +1905,7 @@
 
 	if (need_sync_io && from_map) {
 		INIT_WORK(&dio->work, integrity_bio_wait);
-		queue_work(ic->metadata_wq, &dio->work);
+		queue_work(ic->offload_wq, &dio->work);
 		return;
 	}
 
@@ -2000,20 +2045,13 @@
 	} else
 		dio->completion = NULL;
 
-	dio->orig_bi_iter = bio->bi_iter;
-
-	dio->orig_bi_disk = bio->bi_disk;
-	dio->orig_bi_partno = bio->bi_partno;
+	dm_bio_record(&dio->bio_details, bio);
 	bio_set_dev(bio, ic->dev->bdev);
-
-	dio->orig_bi_integrity = bio_integrity(bio);
 	bio->bi_integrity = NULL;
 	bio->bi_opf &= ~REQ_INTEGRITY;
-
-	dio->orig_bi_end_io = bio->bi_end_io;
 	bio->bi_end_io = integrity_end_io;
-
 	bio->bi_iter.bi_size = dio->range.n_sectors << SECTOR_SHIFT;
+
 	generic_make_request(bio);
 
 	if (need_sync_io) {
@@ -2089,7 +2127,7 @@
 	flushes = bio_list_get(&ic->flush_bio_list);
 	if (unlikely(ic->mode != 'J')) {
 		spin_unlock_irq(&ic->endio_wait.lock);
-		dm_integrity_flush_buffers(ic);
+		dm_integrity_flush_buffers(ic, true);
 		goto release_flush_bios;
 	}
 
@@ -2299,7 +2337,7 @@
 	complete_journal_op(&comp);
 	wait_for_completion_io(&comp.comp);
 
-	dm_integrity_flush_buffers(ic);
+	dm_integrity_flush_buffers(ic, true);
 }
 
 static void integrity_writer(struct work_struct *w)
@@ -2309,10 +2347,6 @@
 
 	unsigned prev_free_sectors;
 
-	/* the following test is not needed, but it tests the replay code */
-	if (READ_ONCE(ic->suspending) && !ic->meta_dev)
-		return;
-
 	spin_lock_irq(&ic->endio_wait.lock);
 	write_start = ic->committed_section;
 	write_sections = ic->n_committed_sections;
@@ -2341,7 +2375,7 @@
 {
 	int r;
 
-	dm_integrity_flush_buffers(ic);
+	dm_integrity_flush_buffers(ic, false);
 	if (dm_integrity_failed(ic))
 		return;
 
@@ -2371,12 +2405,13 @@
 
 next_chunk:
 
-	if (unlikely(READ_ONCE(ic->suspending)))
+	if (unlikely(dm_post_suspending(ic->ti)))
 		goto unlock_ret;
 
 	range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
 	if (unlikely(range.logical_sector >= ic->provided_data_sectors)) {
 		if (ic->mode == 'B') {
+			block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
 			DEBUG_print("queue_delayed_work: bitmap_flush_work\n");
 			queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
 		}
@@ -2454,6 +2489,17 @@
 		goto err;
 	}
 
+	if (ic->mode == 'B') {
+		sector_t start, end;
+		start = (range.logical_sector >>
+			 (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
+			(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+		end = ((range.logical_sector + range.n_sectors) >>
+		       (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
+			(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+		block_bitmap_op(ic, ic->recalc_bitmap, start, end - start, BITMAP_OP_CLEAR);
+	}
+
 advance_and_next:
 	cond_resched();
 
@@ -2496,7 +2542,7 @@
 				    dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {
 			remove_range(ic, &dio->range);
 			INIT_WORK(&dio->work, integrity_bio_wait);
-			queue_work(ic->wait_wq, &dio->work);
+			queue_work(ic->offload_wq, &dio->work);
 		} else {
 			block_bitmap_op(ic, ic->journal, dio->range.logical_sector,
 					dio->range.n_sectors, BITMAP_OP_SET);
@@ -2519,7 +2565,7 @@
 
 		remove_range(ic, &dio->range);
 		INIT_WORK(&dio->work, integrity_bio_wait);
-		queue_work(ic->wait_wq, &dio->work);
+		queue_work(ic->offload_wq, &dio->work);
 	}
 
 	queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
@@ -2532,7 +2578,7 @@
 	unsigned long limit;
 	struct bio *bio;
 
-	dm_integrity_flush_buffers(ic);
+	dm_integrity_flush_buffers(ic, false);
 
 	range.logical_sector = 0;
 	range.n_sectors = ic->provided_data_sectors;
@@ -2541,7 +2587,7 @@
 	add_new_range_and_wait(ic, &range);
 	spin_unlock_irq(&ic->endio_wait.lock);
 
-	dm_integrity_flush_buffers(ic);
+	dm_integrity_flush_buffers(ic, true);
 	if (ic->meta_dev)
 		blkdev_issue_flush(ic->dev->bdev, GFP_NOIO, NULL);
 
@@ -2799,8 +2845,6 @@
 
 	del_timer_sync(&ic->autocommit_timer);
 
-	WRITE_ONCE(ic->suspending, 1);
-
 	if (ic->recalc_wq)
 		drain_workqueue(ic->recalc_wq);
 
@@ -2811,14 +2855,13 @@
 	drain_workqueue(ic->commit_wq);
 
 	if (ic->mode == 'J') {
-		if (ic->meta_dev)
-			queue_work(ic->writer_wq, &ic->writer_work);
+		queue_work(ic->writer_wq, &ic->writer_work);
 		drain_workqueue(ic->writer_wq);
-		dm_integrity_flush_buffers(ic);
+		dm_integrity_flush_buffers(ic, true);
 	}
 
 	if (ic->mode == 'B') {
-		dm_integrity_flush_buffers(ic);
+		dm_integrity_flush_buffers(ic, true);
 #if 1
 		/* set to 0 to test bitmap replay code */
 		init_journal(ic, 0, ic->journal_sections, 0);
@@ -2829,8 +2872,6 @@
 #endif
 	}
 
-	WRITE_ONCE(ic->suspending, 0);
-
 	BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
 
 	ic->journal_uptodate = true;
@@ -2883,17 +2924,24 @@
 	} else {
 		replay_journal(ic);
 		if (ic->mode == 'B') {
-			int mode;
 			ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
 			ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
 			r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
 			if (unlikely(r))
 				dm_integrity_io_error(ic, "writing superblock", r);
 
-			mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR;
-			block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode);
-			block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode);
-			block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode);
+			block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+			block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+			block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+			if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+			    le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) {
+				block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector),
+						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+				block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+				block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+						ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+			}
 			rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
 					   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
 		}
@@ -2955,13 +3003,14 @@
 		arg_count += !!ic->internal_hash_alg.alg_string;
 		arg_count += !!ic->journal_crypt_alg.alg_string;
 		arg_count += !!ic->journal_mac_alg.alg_string;
+		arg_count += ic->legacy_recalculate;
 		DMEMIT("%s %llu %u %c %u", ic->dev->name, (unsigned long long)ic->start,
 		       ic->tag_size, ic->mode, arg_count);
 		if (ic->meta_dev)
 			DMEMIT(" meta_device:%s", ic->meta_dev->name);
 		if (ic->sectors_per_block != 1)
 			DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);
-		if (ic->recalculate_flag)
+		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
 			DMEMIT(" recalculate");
 		DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
 		DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
@@ -2974,6 +3023,8 @@
 			DMEMIT(" sectors_per_bit:%llu", (unsigned long long)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit);
 			DMEMIT(" bitmap_flush_interval:%u", jiffies_to_msecs(ic->bitmap_flush_interval));
 		}
+		if (ic->legacy_recalculate)
+			DMEMIT(" legacy_recalculate");
 
 #define EMIT_ALG(a, n)							\
 		do {							\
@@ -3582,7 +3633,7 @@
 	unsigned extra_args;
 	struct dm_arg_set as;
 	static const struct dm_arg _args[] = {
-		{0, 9, "Invalid number of feature args"},
+		{0, 14, "Invalid number of feature args"},
 	};
 	unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
 	bool should_write_sb;
@@ -3607,6 +3658,7 @@
 	}
 	ti->private = ic;
 	ti->per_io_data_size = sizeof(struct dm_integrity_io);
+	ic->ti = ti;
 
 	ic->in_progress = RB_ROOT;
 	INIT_LIST_HEAD(&ic->wait_list);
@@ -3706,6 +3758,7 @@
 			if (val >= (uint64_t)UINT_MAX * 1000 / HZ) {
 				r = -EINVAL;
 				ti->error = "Invalid bitmap_flush_interval argument";
+				goto bad;
 			}
 			ic->bitmap_flush_interval = msecs_to_jiffies(val);
 		} else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) {
@@ -3725,6 +3778,8 @@
 				goto bad;
 		} else if (!strcmp(opt_string, "recalculate")) {
 			ic->recalculate_flag = true;
+		} else if (!strcmp(opt_string, "legacy_recalculate")) {
+			ic->legacy_recalculate = true;
 		} else {
 			r = -EINVAL;
 			ti->error = "Invalid argument";
@@ -3818,6 +3873,14 @@
 		goto bad;
 	}
 
+	ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM,
+					  METADATA_WORKQUEUE_MAX_ACTIVE);
+	if (!ic->offload_wq) {
+		ti->error = "Cannot allocate workqueue";
+		r = -ENOMEM;
+		goto bad;
+	}
+
 	ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1);
 	if (!ic->commit_wq) {
 		ti->error = "Cannot allocate workqueue";
@@ -3987,6 +4050,7 @@
 	}
 
 	if (ic->internal_hash) {
+		size_t recalc_tags_size;
 		ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1);
 		if (!ic->recalc_wq ) {
 			ti->error = "Cannot allocate workqueue";
@@ -4000,13 +4064,29 @@
 			r = -ENOMEM;
 			goto bad;
 		}
-		ic->recalc_tags = kvmalloc_array(RECALC_SECTORS >> ic->sb->log2_sectors_per_block,
-						 ic->tag_size, GFP_KERNEL);
+		recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size;
+		if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size)
+			recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size;
+		ic->recalc_tags = kvmalloc(recalc_tags_size, GFP_KERNEL);
 		if (!ic->recalc_tags) {
 			ti->error = "Cannot allocate tags for recalculating";
 			r = -ENOMEM;
 			goto bad;
 		}
+	} else {
+		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
+			ti->error = "Recalculate can only be specified with internal_hash";
+			r = -EINVAL;
+			goto bad;
+		}
+	}
+
+	if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+	    le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors &&
+	    dm_integrity_disable_recalculate(ic)) {
+		ti->error = "Recalculating with HMAC is disabled for security reasons - if you really need it, use the argument \"legacy_recalculate\"";
+		r = -EOPNOTSUPP;
+		goto bad;
 	}
 
 	ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev,
@@ -4065,8 +4145,6 @@
 	}
 
 	if (should_write_sb) {
-		int r;
-
 		init_journal(ic, 0, ic->journal_sections, 0);
 		r = dm_integrity_failed(ic);
 		if (unlikely(r)) {
@@ -4118,10 +4196,14 @@
 	BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
 	BUG_ON(!list_empty(&ic->wait_list));
 
+	if (ic->mode == 'B')
+		cancel_delayed_work_sync(&ic->bitmap_flush_work);
 	if (ic->metadata_wq)
 		destroy_workqueue(ic->metadata_wq);
 	if (ic->wait_wq)
 		destroy_workqueue(ic->wait_wq);
+	if (ic->offload_wq)
+		destroy_workqueue(ic->offload_wq);
 	if (ic->commit_wq)
 		destroy_workqueue(ic->commit_wq);
 	if (ic->writer_wq)
@@ -4207,11 +4289,13 @@
 	}
 
 	r = dm_register_target(&integrity_target);
-
-	if (r < 0)
+	if (r < 0) {
 		DMERR("register failed %d", r);
+		kmem_cache_destroy(journal_io_cache);
+		return r;
+	}
 
-	return r;
+	return 0;
 }
 
 static void __exit dm_integrity_exit(void)
--- linux-ein-5.4.0.orig/drivers/md/dm-io.c
+++ linux-ein-5.4.0/drivers/md/dm-io.c
@@ -306,7 +306,7 @@
 	struct request_queue *q = bdev_get_queue(where->bdev);
 	unsigned short logical_block_size = queue_logical_block_size(q);
 	sector_t num_sectors;
-	unsigned int uninitialized_var(special_cmd_max_sectors);
+	unsigned int special_cmd_max_sectors;
 
 	/*
 	 * Reject unsupported discard and write same requests.
--- linux-ein-5.4.0.orig/drivers/md/dm-ioctl.c
+++ linux-ein-5.4.0/drivers/md/dm-ioctl.c
@@ -17,6 +17,7 @@
 #include <linux/dm-ioctl.h>
 #include <linux/hdreg.h>
 #include <linux/compat.h>
+#include <linux/nospec.h>
 
 #include <linux/uaccess.h>
 
@@ -529,7 +530,7 @@
 	 * Grab our output buffer.
 	 */
 	nl = orig_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;
 	}
@@ -572,7 +573,7 @@
     size_t *needed = needed_param;
 
     *needed += sizeof(struct dm_target_versions);
-    *needed += strlen(tt->name);
+    *needed += strlen(tt->name) + 1;
     *needed += ALIGN_MASK;
 }
 
@@ -637,7 +638,7 @@
 	iter_info.old_vers = NULL;
 	iter_info.vers = vers;
 	iter_info.flags = 0;
-	iter_info.end = (char *)vers+len;
+	iter_info.end = (char *)vers + needed;
 
 	/*
 	 * Now loop through filling out the names & versions.
@@ -808,15 +809,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)
@@ -1434,11 +1441,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);
@@ -1600,6 +1608,7 @@
 
 	if (!argc) {
 		DMWARN("Empty message received.");
+		r = -EINVAL;
 		goto out_argv;
 	}
 
@@ -1695,6 +1704,7 @@
 	if (unlikely(cmd >= ARRAY_SIZE(_ioctls)))
 		return NULL;
 
+	cmd = array_index_nospec(cmd, ARRAY_SIZE(_ioctls));
 	*ioctl_flags = _ioctls[cmd].flags;
 	return _ioctls[cmd].fn;
 }
@@ -1756,8 +1766,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;
 
@@ -1844,7 +1858,7 @@
 	int ioctl_flags;
 	int param_flags;
 	unsigned int cmd;
-	struct dm_ioctl *uninitialized_var(param);
+	struct dm_ioctl *param;
 	ioctl_fn fn = NULL;
 	size_t input_param_size;
 	struct dm_ioctl param_kernel;
--- linux-ein-5.4.0.orig/drivers/md/dm-log.c
+++ linux-ein-5.4.0/drivers/md/dm-log.c
@@ -415,8 +415,7 @@
 	/*
 	 * Work out how many "unsigned long"s we need to hold the bitset.
 	 */
-	bitset_size = dm_round_up(region_count,
-				  sizeof(*lc->clean_bits) << BYTE_SHIFT);
+	bitset_size = dm_round_up(region_count, BITS_PER_LONG);
 	bitset_size >>= BYTE_SHIFT;
 
 	lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
@@ -616,7 +615,7 @@
 			log_clear_bit(lc, lc->clean_bits, i);
 
 	/* clear any old bits -- device has shrunk */
-	for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
+	for (i = lc->region_count; i % BITS_PER_LONG; i++)
 		log_clear_bit(lc, lc->clean_bits, i);
 
 	/* copy clean across to sync */
--- linux-ein-5.4.0.orig/drivers/md/dm-mpath.c
+++ linux-ein-5.4.0/drivers/md/dm-mpath.c
@@ -576,10 +576,12 @@
 
 	/* Do we need to select a new pgpath? */
 	pgpath = READ_ONCE(m->current_pgpath);
-	queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags);
-	if (!pgpath || !queue_io)
+	if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags))
 		pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
 
+	/* MPATHF_QUEUE_IO might have been cleared by choose_pgpath. */
+	queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags);
+
 	if ((pgpath && queue_io) ||
 	    (!pgpath && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))) {
 		/* Queue for the daemon to resubmit */
@@ -599,45 +601,10 @@
 	return pgpath;
 }
 
-static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio)
-{
-	struct pgpath *pgpath;
-	unsigned long flags;
-
-	/* Do we need to select a new pgpath? */
-	/*
-	 * FIXME: currently only switching path if no path (due to failure, etc)
-	 * - which negates the point of using a path selector
-	 */
-	pgpath = READ_ONCE(m->current_pgpath);
-	if (!pgpath)
-		pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
-
-	if (!pgpath) {
-		if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
-			/* Queue for the daemon to resubmit */
-			spin_lock_irqsave(&m->lock, flags);
-			bio_list_add(&m->queued_bios, bio);
-			spin_unlock_irqrestore(&m->lock, flags);
-			queue_work(kmultipathd, &m->process_queued_bios);
-
-			return ERR_PTR(-EAGAIN);
-		}
-		return NULL;
-	}
-
-	return pgpath;
-}
-
 static int __multipath_map_bio(struct multipath *m, struct bio *bio,
 			       struct dm_mpath_io *mpio)
 {
-	struct pgpath *pgpath;
-
-	if (!m->hw_handler_name)
-		pgpath = __map_bio_fast(m, bio);
-	else
-		pgpath = __map_bio(m, bio);
+	struct pgpath *pgpath = __map_bio(m, bio);
 
 	if (IS_ERR(pgpath))
 		return DM_MAPIO_SUBMITTED;
@@ -1223,17 +1190,25 @@
 static void flush_multipath_work(struct multipath *m)
 {
 	if (m->hw_handler_name) {
-		set_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
-		smp_mb__after_atomic();
+		unsigned long flags;
+
+		if (!atomic_read(&m->pg_init_in_progress))
+			goto skip;
+
+		spin_lock_irqsave(&m->lock, flags);
+		if (atomic_read(&m->pg_init_in_progress) &&
+		    !test_and_set_bit(MPATHF_PG_INIT_DISABLED, &m->flags)) {
+			spin_unlock_irqrestore(&m->lock, flags);
 
-		if (atomic_read(&m->pg_init_in_progress))
 			flush_workqueue(kmpath_handlerd);
-		multipath_wait_for_pg_init_completion(m);
+			multipath_wait_for_pg_init_completion(m);
 
-		clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
-		smp_mb__after_atomic();
+			spin_lock_irqsave(&m->lock, flags);
+			clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
+		}
+		spin_unlock_irqrestore(&m->lock, flags);
 	}
-
+skip:
 	if (m->queue_mode == DM_TYPE_BIO_BASED)
 		flush_work(&m->process_queued_bios);
 	flush_work(&m->trigger_event);
@@ -1889,7 +1864,7 @@
 	int r;
 
 	current_pgpath = READ_ONCE(m->current_pgpath);
-	if (!current_pgpath)
+	if (!current_pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags))
 		current_pgpath = choose_pgpath(m, 0);
 
 	if (current_pgpath) {
--- linux-ein-5.4.0.orig/drivers/md/dm-raid.c
+++ linux-ein-5.4.0/drivers/md/dm-raid.c
@@ -998,12 +998,13 @@
 static int validate_raid_redundancy(struct raid_set *rs)
 {
 	unsigned int i, rebuild_cnt = 0;
-	unsigned int rebuilds_per_group = 0, copies;
+	unsigned int rebuilds_per_group = 0, copies, raid_disks;
 	unsigned int group_size, last_group_start;
 
-	for (i = 0; i < rs->md.raid_disks; i++)
-		if (!test_bit(In_sync, &rs->dev[i].rdev.flags) ||
-		    !rs->dev[i].rdev.sb_page)
+	for (i = 0; i < rs->raid_disks; i++)
+		if (!test_bit(FirstUse, &rs->dev[i].rdev.flags) &&
+		    ((!test_bit(In_sync, &rs->dev[i].rdev.flags) ||
+		      !rs->dev[i].rdev.sb_page)))
 			rebuild_cnt++;
 
 	switch (rs->md.level) {
@@ -1043,8 +1044,9 @@
 		 *	    A	 A    B	   B	C
 		 *	    C	 D    D	   E	E
 		 */
+		raid_disks = min(rs->raid_disks, rs->md.raid_disks);
 		if (__is_raid10_near(rs->md.new_layout)) {
-			for (i = 0; i < rs->md.raid_disks; i++) {
+			for (i = 0; i < raid_disks; i++) {
 				if (!(i % copies))
 					rebuilds_per_group = 0;
 				if ((!rs->dev[i].rdev.sb_page ||
@@ -1067,10 +1069,10 @@
 		 * results in the need to treat the last (potentially larger)
 		 * set differently.
 		 */
-		group_size = (rs->md.raid_disks / copies);
-		last_group_start = (rs->md.raid_disks / group_size) - 1;
+		group_size = (raid_disks / copies);
+		last_group_start = (raid_disks / group_size) - 1;
 		last_group_start *= group_size;
-		for (i = 0; i < rs->md.raid_disks; i++) {
+		for (i = 0; i < raid_disks; i++) {
 			if (!(i % copies) && !(i > last_group_start))
 				rebuilds_per_group = 0;
 			if ((!rs->dev[i].rdev.sb_page ||
@@ -1585,7 +1587,7 @@
 {
 	int i;
 
-	for (i = 0; i < rs->md.raid_disks; i++) {
+	for (i = 0; i < rs->raid_disks; i++) {
 		struct md_rdev *rdev = &rs->dev[i].rdev;
 
 		if (!test_bit(Journal, &rdev->flags) &&
@@ -1892,6 +1894,14 @@
 	return rs->md.new_level != rs->md.level;
 }
 
+/* True if layout is set to reshape. */
+static bool rs_is_layout_change(struct raid_set *rs, bool use_mddev)
+{
+	return (use_mddev ? rs->md.delta_disks : rs->delta_disks) ||
+	       rs->md.new_layout != rs->md.layout ||
+	       rs->md.new_chunk_sectors != rs->md.chunk_sectors;
+}
+
 /* True if @rs is requested to reshape by ctr */
 static bool rs_reshape_requested(struct raid_set *rs)
 {
@@ -1904,9 +1914,7 @@
 	if (rs_is_raid0(rs))
 		return false;
 
-	change = mddev->new_layout != mddev->layout ||
-		 mddev->new_chunk_sectors != mddev->chunk_sectors ||
-		 rs->delta_disks;
+	change = rs_is_layout_change(rs, false);
 
 	/* Historical case to support raid1 reshape without delta disks */
 	if (rs_is_raid1(rs)) {
@@ -2843,7 +2851,7 @@
 }
 
 /*
- *
+ * Reshape:
  * - change raid layout
  * - change chunk size
  * - add disks
@@ -2953,6 +2961,20 @@
 }
 
 /*
+ * If the md resync thread has updated superblock with max reshape position
+ * at the end of a reshape but not (yet) reset the layout configuration
+ * changes -> reset the latter.
+ */
+static void rs_reset_inconclusive_reshape(struct raid_set *rs)
+{
+	if (!rs_is_reshaping(rs) && rs_is_layout_change(rs, true)) {
+		rs_set_cur(rs);
+		rs->md.delta_disks = 0;
+		rs->md.reshape_backwards = 0;
+	}
+}
+
+/*
  * Enable/disable discard support on RAID set depending on
  * RAID level and discard properties of underlying RAID members.
  */
@@ -3216,11 +3238,14 @@
 	if (r)
 		goto bad;
 
+	/* Catch any inconclusive reshape superblock content. */
+	rs_reset_inconclusive_reshape(rs);
+
 	/* Start raid set read-only and assumed clean to change in raid_resume() */
 	rs->md.ro = 1;
 	rs->md.in_sync = 1;
 
-	/* Keep array frozen */
+	/* Keep array frozen until resume. */
 	set_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
 
 	/* Has to be held on running the array */
@@ -3234,7 +3259,6 @@
 	}
 
 	r = md_start(&rs->md);
-
 	if (r) {
 		ti->error = "Failed to start raid array";
 		mddev_unlock(&rs->md);
@@ -3260,15 +3284,19 @@
 	/* Try to adjust the raid4/5/6 stripe cache size to the stripe size */
 	if (rs_is_raid456(rs)) {
 		r = rs_set_raid456_stripe_cache(rs);
-		if (r)
+		if (r) {
+			mddev_unlock(&rs->md);
 			goto bad_stripe_cache;
+		}
 	}
 
 	/* Now do an early reshape check */
 	if (test_bit(RT_FLAG_RESHAPE_RS, &rs->runtime_flags)) {
 		r = rs_check_reshape(rs);
-		if (r)
+		if (r) {
+			mddev_unlock(&rs->md);
 			goto bad_check_reshape;
+		}
 
 		/* Restore new, ctr requested layout to perform check */
 		rs_config_restore(rs, &rs_layout);
@@ -3277,6 +3305,7 @@
 			r = rs->md.pers->check_reshape(&rs->md);
 			if (r) {
 				ti->error = "Reshape check failed";
+				mddev_unlock(&rs->md);
 				goto bad_check_reshape;
 			}
 		}
@@ -3504,7 +3533,7 @@
 {
 	struct raid_set *rs = ti->private;
 	struct mddev *mddev = &rs->md;
-	struct r5conf *conf = mddev->private;
+	struct r5conf *conf = rs_is_raid456(rs) ? mddev->private : NULL;
 	int i, max_nr_stripes = conf ? conf->max_nr_stripes : 0;
 	unsigned long recovery;
 	unsigned int raid_param_cnt = 1; /* at least 1 for chunksize */
@@ -3724,13 +3753,13 @@
 	unsigned int i;
 	int r = 0;
 
-	for (i = 0; !r && i < rs->md.raid_disks; i++)
-		if (rs->dev[i].data_dev)
-			r = fn(ti,
-				 rs->dev[i].data_dev,
-				 0, /* No offset on data devs */
-				 rs->md.dev_sectors,
-				 data);
+	for (i = 0; !r && i < rs->raid_disks; i++) {
+		if (rs->dev[i].data_dev) {
+			r = fn(ti, rs->dev[i].data_dev,
+			       0, /* No offset on data devs */
+			       rs->md.dev_sectors, data);
+		}
+	}
 
 	return r;
 }
@@ -3742,15 +3771,6 @@
 
 	blk_limits_io_min(limits, chunk_size_bytes);
 	blk_limits_io_opt(limits, chunk_size_bytes * mddev_data_stripes(rs));
-
-	/*
-	 * RAID1 and RAID10 personalities require bio splitting,
-	 * RAID0/4/5/6 don't and process large discard bios properly.
-	 */
-	if (rs_is_raid1(rs) || rs_is_raid10(rs)) {
-		limits->discard_granularity = chunk_size_bytes;
-		limits->max_discard_sectors = rs->md.chunk_sectors;
-	}
 }
 
 static void raid_postsuspend(struct dm_target *ti)
@@ -3784,7 +3804,7 @@
 
 	memset(cleared_failed_devices, 0, sizeof(cleared_failed_devices));
 
-	for (i = 0; i < mddev->raid_disks; i++) {
+	for (i = 0; i < rs->raid_disks; i++) {
 		r = &rs->dev[i].rdev;
 		/* HM FIXME: enhance journal device recovery processing */
 		if (test_bit(Journal, &r->flags))
--- linux-ein-5.4.0.orig/drivers/md/dm-rq.c
+++ linux-ein-5.4.0/drivers/md/dm-rq.c
@@ -70,9 +70,6 @@
 
 void dm_stop_queue(struct request_queue *q)
 {
-	if (blk_mq_queue_stopped(q))
-		return;
-
 	blk_mq_quiesce_queue(q);
 }
 
@@ -288,7 +285,8 @@
 	struct dm_rq_target_io *tio = tio_from_request(rq);
 
 	tio->error = error;
-	blk_mq_complete_request(rq);
+	if (likely(!blk_should_fake_timeout(rq->q)))
+		blk_mq_complete_request(rq);
 }
 
 /*
@@ -575,6 +573,7 @@
 	blk_mq_free_tag_set(md->tag_set);
 out_kfree_tag_set:
 	kfree(md->tag_set);
+	md->tag_set = NULL;
 
 	return err;
 }
@@ -584,6 +583,7 @@
 	if (md->tag_set) {
 		blk_mq_free_tag_set(md->tag_set);
 		kfree(md->tag_set);
+		md->tag_set = NULL;
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/md/dm-snap-persistent.c
+++ linux-ein-5.4.0/drivers/md/dm-snap-persistent.c
@@ -17,7 +17,7 @@
 #include <linux/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
 
@@ -613,7 +613,7 @@
 						    chunk_t old, chunk_t new),
 				    void *callback_context)
 {
-	int r, uninitialized_var(new_snapshot);
+	int r, new_snapshot;
 	struct pstore *ps = get_info(store);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/md/dm-snap.c
+++ linux-ein-5.4.0/drivers/md/dm-snap.c
@@ -141,6 +141,11 @@
 	 * for them to be committed.
 	 */
 	struct bio_list bios_queued_during_merge;
+
+	/*
+	 * Flush data after merge.
+	 */
+	struct bio flush_bio;
 };
 
 /*
@@ -849,7 +854,7 @@
 static uint32_t __minimum_chunk_size(struct origin *o)
 {
 	struct dm_snapshot *snap;
-	unsigned chunk_size = 0;
+	unsigned chunk_size = rounddown_pow_of_two(UINT_MAX);
 
 	if (o)
 		list_for_each_entry(snap, &o->snapshots, list)
@@ -1121,6 +1126,17 @@
 
 static void error_bios(struct bio *bio);
 
+static int flush_data(struct dm_snapshot *s)
+{
+	struct bio *flush_bio = &s->flush_bio;
+
+	bio_reset(flush_bio);
+	bio_set_dev(flush_bio, s->origin->bdev);
+	flush_bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
+
+	return submit_bio_wait(flush_bio);
+}
+
 static void merge_callback(int read_err, unsigned long write_err, void *context)
 {
 	struct dm_snapshot *s = context;
@@ -1134,6 +1150,11 @@
 		goto shut;
 	}
 
+	if (flush_data(s) < 0) {
+		DMERR("Flush after merge failed: shutting down merge");
+		goto shut;
+	}
+
 	if (s->store->type->commit_merge(s->store,
 					 s->num_merging_chunks) < 0) {
 		DMERR("Write error in exception store: shutting down merge");
@@ -1318,6 +1339,7 @@
 	s->first_merging_chunk = 0;
 	s->num_merging_chunks = 0;
 	bio_list_init(&s->bios_queued_during_merge);
+	bio_init(&s->flush_bio, NULL, 0);
 
 	/* Allocate hash table for COW data */
 	if (init_hash_tables(s)) {
@@ -1386,6 +1408,7 @@
 
 	if (!s->store->chunk_size) {
 		ti->error = "Chunk size not set";
+		r = -EINVAL;
 		goto bad_read_metadata;
 	}
 
@@ -1504,6 +1527,8 @@
 
 	dm_exception_store_destroy(s->store);
 
+	bio_uninit(&s->flush_bio);
+
 	dm_put_device(ti, s->cow);
 
 	dm_put_device(ti, s->origin);
--- linux-ein-5.4.0.orig/drivers/md/dm-stats.c
+++ linux-ein-5.4.0/drivers/md/dm-stats.c
@@ -188,7 +188,7 @@
 	       atomic_read(&shared->in_flight[WRITE]);
 }
 
-void dm_stats_init(struct dm_stats *stats)
+int dm_stats_init(struct dm_stats *stats)
 {
 	int cpu;
 	struct dm_stats_last_position *last;
@@ -196,11 +196,16 @@
 	mutex_init(&stats->mutex);
 	INIT_LIST_HEAD(&stats->list);
 	stats->last = alloc_percpu(struct dm_stats_last_position);
+	if (!stats->last)
+		return -ENOMEM;
+
 	for_each_possible_cpu(cpu) {
 		last = per_cpu_ptr(stats->last, cpu);
 		last->last_sector = (sector_t)ULLONG_MAX;
 		last->last_rw = UINT_MAX;
 	}
+
+	return 0;
 }
 
 void dm_stats_cleanup(struct dm_stats *stats)
@@ -224,6 +229,7 @@
 				       atomic_read(&shared->in_flight[READ]),
 				       atomic_read(&shared->in_flight[WRITE]));
 			}
+			cond_resched();
 		}
 		dm_stat_free(&s->rcu_head);
 	}
@@ -313,6 +319,7 @@
 	for (ni = 0; ni < n_entries; ni++) {
 		atomic_set(&s->stat_shared[ni].in_flight[READ], 0);
 		atomic_set(&s->stat_shared[ni].in_flight[WRITE], 0);
+		cond_resched();
 	}
 
 	if (s->n_histogram_entries) {
@@ -325,6 +332,7 @@
 		for (ni = 0; ni < n_entries; ni++) {
 			s->stat_shared[ni].tmp.histogram = hi;
 			hi += s->n_histogram_entries + 1;
+			cond_resched();
 		}
 	}
 
@@ -345,6 +353,7 @@
 			for (ni = 0; ni < n_entries; ni++) {
 				p[ni].histogram = hi;
 				hi += s->n_histogram_entries + 1;
+				cond_resched();
 			}
 		}
 	}
@@ -474,6 +483,7 @@
 			}
 			DMEMIT("\n");
 		}
+		cond_resched();
 	}
 	mutex_unlock(&stats->mutex);
 
@@ -750,6 +760,7 @@
 				local_irq_enable();
 			}
 		}
+		cond_resched();
 	}
 }
 
@@ -865,6 +876,8 @@
 
 		if (unlikely(sz + 1 >= maxlen))
 			goto buffer_overflow;
+
+		cond_resched();
 	}
 
 	if (clear)
--- linux-ein-5.4.0.orig/drivers/md/dm-stats.h
+++ linux-ein-5.4.0/drivers/md/dm-stats.h
@@ -22,7 +22,7 @@
 	unsigned long long duration_ns;
 };
 
-void dm_stats_init(struct dm_stats *st);
+int dm_stats_init(struct dm_stats *st);
 void dm_stats_cleanup(struct dm_stats *st);
 
 struct mapped_device;
--- linux-ein-5.4.0.orig/drivers/md/dm-table.c
+++ linux-ein-5.4.0/drivers/md/dm-table.c
@@ -184,7 +184,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;
@@ -199,7 +204,7 @@
 
 	if (!num_targets) {
 		kfree(t);
-		return -ENOMEM;
+		return -EOVERFLOW;
 	}
 
 	if (alloc_targets(t, num_targets)) {
@@ -428,14 +433,23 @@
 {
 	int r;
 	dev_t dev;
+	unsigned int major, minor;
+	char dummy;
 	struct dm_dev_internal *dd;
 	struct dm_table *t = ti->table;
 
 	BUG_ON(!t);
 
-	dev = dm_get_dev_t(path);
-	if (!dev)
-		return -ENODEV;
+	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;
+	}
 
 	dd = find_device(&t->devices, dev);
 	if (!dd) {
@@ -659,7 +673,7 @@
 	 */
 	unsigned short remaining = 0;
 
-	struct dm_target *uninitialized_var(ti);
+	struct dm_target *ti;
 	struct queue_limits ti_limits;
 	unsigned i;
 
@@ -863,8 +877,7 @@
 static bool __table_type_bio_based(enum dm_queue_mode table_type)
 {
 	return (table_type == DM_TYPE_BIO_BASED ||
-		table_type == DM_TYPE_DAX_BIO_BASED ||
-		table_type == DM_TYPE_NVME_BIO_BASED);
+		table_type == DM_TYPE_DAX_BIO_BASED);
 }
 
 static bool __table_type_request_based(enum dm_queue_mode table_type)
@@ -879,20 +892,24 @@
 EXPORT_SYMBOL_GPL(dm_table_set_type);
 
 /* validate the dax capability of the target device span */
-int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
 			sector_t start, sector_t len, void *data)
 {
-	int blocksize = *(int *) data;
+	int blocksize = *(int *) data, id;
+	bool rc;
+
+	id = dax_read_lock();
+	rc = !dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
+	dax_read_unlock(id);
 
-	return generic_fsdax_supported(dev->dax_dev, dev->bdev, blocksize,
-				       start, len);
+	return rc;
 }
 
 /* Check devices support synchronous DAX */
-static int device_dax_synchronous(struct dm_target *ti, struct dm_dev *dev,
-				  sector_t start, sector_t len, void *data)
+static int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_dev *dev,
+					      sector_t start, sector_t len, void *data)
 {
-	return dev->dax_dev && dax_synchronous(dev->dax_dev);
+	return !dev->dax_dev || !dax_synchronous(dev->dax_dev);
 }
 
 bool dm_table_supports_dax(struct dm_table *t,
@@ -909,30 +926,22 @@
 			return false;
 
 		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, iterate_fn, blocksize))
+		    ti->type->iterate_devices(ti, iterate_fn, blocksize))
 			return false;
 	}
 
 	return true;
 }
 
-static bool dm_table_does_not_support_partial_completion(struct dm_table *t);
-
-struct verify_rq_based_data {
-	unsigned sq_count;
-	unsigned mq_count;
-};
-
-static int device_is_rq_based(struct dm_target *ti, struct dm_dev *dev,
-			      sector_t start, sector_t len, void *data)
+static int device_is_rq_stackable(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);
-	struct verify_rq_based_data *v = data;
+	struct block_device *bdev = dev->bdev;
+	struct request_queue *q = bdev_get_queue(bdev);
 
-	if (queue_is_mq(q))
-		v->mq_count++;
-	else
-		v->sq_count++;
+	/* request-based cannot stack on partitions! */
+	if (bdev != bdev->bd_contains)
+		return false;
 
 	return queue_is_mq(q);
 }
@@ -941,7 +950,6 @@
 {
 	unsigned i;
 	unsigned bio_based = 0, request_based = 0, hybrid = 0;
-	struct verify_rq_based_data v = {.sq_count = 0, .mq_count = 0};
 	struct dm_target *tgt;
 	struct list_head *devices = dm_table_get_devices(t);
 	enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
@@ -954,7 +962,6 @@
 			goto verify_bio_based;
 		}
 		BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED);
-		BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED);
 		goto verify_rq_based;
 	}
 
@@ -990,18 +997,9 @@
 verify_bio_based:
 		/* We must use this table as bio-based */
 		t->type = DM_TYPE_BIO_BASED;
-		if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
+		if (dm_table_supports_dax(t, device_not_dax_capable, &page_size) ||
 		    (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
 			t->type = DM_TYPE_DAX_BIO_BASED;
-		} else {
-			/* Check if upgrading to NVMe bio-based is valid or required */
-			tgt = dm_table_get_immutable_target(t);
-			if (tgt && !tgt->max_io_len && dm_table_does_not_support_partial_completion(t)) {
-				t->type = DM_TYPE_NVME_BIO_BASED;
-				goto verify_rq_based; /* must be stacked directly on NVMe (blk-mq) */
-			} else if (list_empty(devices) && live_md_type == DM_TYPE_NVME_BIO_BASED) {
-				t->type = DM_TYPE_NVME_BIO_BASED;
-			}
 		}
 		return 0;
 	}
@@ -1018,8 +1016,7 @@
 	 * (e.g. request completion process for partial completion.)
 	 */
 	if (t->num_targets > 1) {
-		DMERR("%s DM doesn't support multiple targets",
-		      t->type == DM_TYPE_NVME_BIO_BASED ? "nvme bio-based" : "request-based");
+		DMERR("request-based DM doesn't support multiple targets");
 		return -EINVAL;
 	}
 
@@ -1045,14 +1042,10 @@
 
 	/* Non-request-stackable devices can't be used for request-based dm */
 	if (!tgt->type->iterate_devices ||
-	    !tgt->type->iterate_devices(tgt, device_is_rq_based, &v)) {
+	    !tgt->type->iterate_devices(tgt, device_is_rq_stackable, NULL)) {
 		DMERR("table load rejected: including non-request-stackable devices");
 		return -EINVAL;
 	}
-	if (v.sq_count > 0) {
-		DMERR("table load rejected: not all devices are blk-mq request-stackable");
-		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -1327,12 +1320,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);
@@ -1380,6 +1367,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, data);
+ */
+static bool dm_table_any_dev_attr(struct dm_table *t,
+				  iterate_devices_callout_fn func, void *data)
+{
+	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, data))
+			return true;
+        }
+
+	return false;
+}
+
 static int count_device(struct dm_target *ti, struct dm_dev *dev,
 			sector_t start, sector_t len, void *data)
 {
@@ -1416,13 +1443,13 @@
 	return true;
 }
 
-static int device_is_zoned_model(struct dm_target *ti, struct dm_dev *dev,
-				 sector_t start, sector_t len, void *data)
+static int device_not_zoned_model(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);
 	enum blk_zoned_model *zoned_model = data;
 
-	return q && blk_queue_zoned_model(q) == *zoned_model;
+	return !q || blk_queue_zoned_model(q) != *zoned_model;
 }
 
 static bool dm_table_supports_zoned_model(struct dm_table *t,
@@ -1439,37 +1466,20 @@
 			return false;
 
 		if (!ti->type->iterate_devices ||
-		    !ti->type->iterate_devices(ti, device_is_zoned_model, &zoned_model))
+		    ti->type->iterate_devices(ti, device_not_zoned_model, &zoned_model))
 			return false;
 	}
 
 	return true;
 }
 
-static int device_matches_zone_sectors(struct dm_target *ti, struct dm_dev *dev,
-				       sector_t start, sector_t len, void *data)
+static int device_not_matches_zone_sectors(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);
 	unsigned int *zone_sectors = data;
 
-	return q && blk_queue_zone_sectors(q) == *zone_sectors;
-}
-
-static bool dm_table_matches_zone_sectors(struct dm_table *t,
-					  unsigned int zone_sectors)
-{
-	struct dm_target *ti;
-	unsigned 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, device_matches_zone_sectors, &zone_sectors))
-			return false;
-	}
-
-	return true;
+	return !q || blk_queue_zone_sectors(q) != *zone_sectors;
 }
 
 static int validate_hardware_zoned_model(struct dm_table *table,
@@ -1489,7 +1499,7 @@
 	if (!zone_sectors || !is_power_of_2(zone_sectors))
 		return -EINVAL;
 
-	if (!dm_table_matches_zone_sectors(table, zone_sectors)) {
+	if (dm_table_any_dev_attr(table, device_not_matches_zone_sectors, &zone_sectors)) {
 		DMERR("%s: zone sectors is not consistent across all devices",
 		      dm_device_name(table->md));
 		return -EINVAL;
@@ -1679,29 +1689,12 @@
 	return false;
 }
 
-static int dm_table_supports_dax_write_cache(struct dm_table *t)
-{
-	struct dm_target *ti;
-	unsigned 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,
-				device_dax_write_cache_enabled, NULL))
-			return true;
-	}
-
-	return false;
-}
-
-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,
@@ -1712,37 +1705,6 @@
 	return q && !blk_queue_add_random(q);
 }
 
-static bool dm_table_all_devices_attribute(struct dm_table *t,
-					   iterate_devices_callout_fn func)
-{
-	struct dm_target *ti;
-	unsigned 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 false;
-	}
-
-	return true;
-}
-
-static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev,
-					sector_t start, sector_t len, void *data)
-{
-	char b[BDEVNAME_SIZE];
-
-	/* For now, NVMe devices are the only devices of this class */
-	return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0);
-}
-
-static bool dm_table_does_not_support_partial_completion(struct dm_table *t)
-{
-	return dm_table_all_devices_attribute(t, device_no_partial_completion);
-}
-
 static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
 					 sector_t start, sector_t len, void *data)
 {
@@ -1867,27 +1829,6 @@
 	return q && bdi_cap_stable_pages_required(q->backing_dev_info);
 }
 
-/*
- * If any underlying device requires stable pages, a table must require
- * them as well.  Only targets that support iterate_devices are considered:
- * don't want error, zero, etc to require stable pages.
- */
-static bool dm_table_requires_stable_pages(struct dm_table *t)
-{
-	struct dm_target *ti;
-	unsigned 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, device_requires_stable_pages, NULL))
-			return true;
-	}
-
-	return false;
-}
-
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
 			       struct queue_limits *limits)
 {
@@ -1920,22 +1861,22 @@
 	}
 	blk_queue_write_cache(q, wc, fua);
 
-	if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
+	if (dm_table_supports_dax(t, device_not_dax_capable, &page_size)) {
 		blk_queue_flag_set(QUEUE_FLAG_DAX, q);
-		if (dm_table_supports_dax(t, device_dax_synchronous, NULL))
+		if (dm_table_supports_dax(t, device_not_dax_synchronous_capable, NULL))
 			set_dax_synchronous(t->md->dax_dev);
 	}
 	else
 		blk_queue_flag_clear(QUEUE_FLAG_DAX, q);
 
-	if (dm_table_supports_dax_write_cache(t))
+	if (dm_table_any_dev_attr(t, device_dax_write_cache_enabled, NULL))
 		dax_write_cache(t->md->dax_dev, true);
 
 	/* Ensure that all underlying devices are non-rotational. */
-	if (dm_table_all_devices_attribute(t, device_is_nonrot))
-		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-	else
+	if (dm_table_any_dev_attr(t, device_is_rotational, NULL))
 		blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
+	else
+		blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
 
 	if (!dm_table_supports_write_same(t))
 		q->limits.max_write_same_sectors = 0;
@@ -1947,8 +1888,11 @@
 	/*
 	 * Some devices don't use blk_integrity but still want stable pages
 	 * because they do their own checksumming.
+	 * If any underlying device requires stable pages, a table must require
+	 * them as well.  Only targets that support iterate_devices are considered:
+	 * don't want error, zero, etc to require stable pages.
 	 */
-	if (dm_table_requires_stable_pages(t))
+	if (dm_table_any_dev_attr(t, device_requires_stable_pages, NULL))
 		q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 	else
 		q->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES;
@@ -1959,7 +1903,8 @@
 	 * 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, NULL))
 		blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/md/dm-thin-metadata.c
+++ linux-ein-5.4.0/drivers/md/dm-thin-metadata.c
@@ -189,6 +189,15 @@
 	sector_t data_block_size;
 
 	/*
+	 * Pre-commit callback.
+	 *
+	 * This allows the thin provisioning target to run a callback before
+	 * the metadata are committed.
+	 */
+	dm_pool_pre_commit_fn pre_commit_fn;
+	void *pre_commit_context;
+
+	/*
 	 * We reserve a section of the metadata for commit overhead.
 	 * All reported space does *not* include this.
 	 */
@@ -378,16 +387,15 @@
  * Variant that is used for in-core only changes or code that
  * shouldn't put the pool in service on its own (e.g. commit).
  */
-static inline void __pmd_write_lock(struct dm_pool_metadata *pmd)
+static inline void pmd_write_lock_in_core(struct dm_pool_metadata *pmd)
 	__acquires(pmd->root_lock)
 {
 	down_write(&pmd->root_lock);
 }
-#define pmd_write_lock_in_core(pmd) __pmd_write_lock((pmd))
 
 static inline void pmd_write_lock(struct dm_pool_metadata *pmd)
 {
-	__pmd_write_lock(pmd);
+	pmd_write_lock_in_core(pmd);
 	if (unlikely(!pmd->in_service))
 		pmd->in_service = true;
 }
@@ -693,6 +701,15 @@
 		goto bad_cleanup_data_sm;
 	}
 
+	/*
+	 * For pool metadata opening process, root setting is redundant
+	 * because it will be set again in __begin_transaction(). But dm
+	 * pool aborting process really needs to get last transaction's
+	 * root to avoid accessing broken btree.
+	 */
+	pmd->root = le64_to_cpu(disk_super->data_mapping_root);
+	pmd->details_root = le64_to_cpu(disk_super->device_details_root);
+
 	__setup_btree_details(pmd);
 	dm_bm_unlock(sblock);
 
@@ -731,23 +748,29 @@
 					  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;
 }
 
-static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd)
+static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd,
+					      bool destroy_bm)
 {
 	dm_sm_destroy(pmd->data_sm);
 	dm_sm_destroy(pmd->metadata_sm);
 	dm_tm_destroy(pmd->nb_tm);
 	dm_tm_destroy(pmd->tm);
-	dm_block_manager_destroy(pmd->bm);
+	if (destroy_bm)
+		dm_block_manager_destroy(pmd->bm);
 }
 
 static int __begin_transaction(struct dm_pool_metadata *pmd)
@@ -822,10 +845,19 @@
 	 * We need to know if the thin_disk_superblock exceeds a 512-byte sector.
 	 */
 	BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
+	BUG_ON(!rwsem_is_locked(&pmd->root_lock));
 
 	if (unlikely(!pmd->in_service))
 		return 0;
 
+	if (pmd->pre_commit_fn) {
+		r = pmd->pre_commit_fn(pmd->pre_commit_context);
+		if (r < 0) {
+			DMERR("pre-commit callback failed");
+			return r;
+		}
+	}
+
 	r = __write_changed_details(pmd);
 	if (r < 0)
 		return r;
@@ -892,6 +924,8 @@
 	pmd->in_service = false;
 	pmd->bdev = bdev;
 	pmd->data_block_size = data_block_size;
+	pmd->pre_commit_fn = NULL;
+	pmd->pre_commit_context = NULL;
 
 	r = __create_persistent_data_objects(pmd, format_device);
 	if (r) {
@@ -934,14 +968,16 @@
 		return -EBUSY;
 	}
 
-	if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
+	pmd_write_lock_in_core(pmd);
+	if (!pmd->fail_io && !dm_bm_is_read_only(pmd->bm)) {
 		r = __commit_transaction(pmd);
 		if (r < 0)
 			DMWARN("%s: __commit_transaction() failed, error = %d",
 			       __func__, r);
 	}
+	pmd_write_unlock(pmd);
 	if (!pmd->fail_io)
-		__destroy_persistent_data_objects(pmd);
+		__destroy_persistent_data_objects(pmd, true);
 
 	kfree(pmd);
 	return 0;
@@ -1822,7 +1858,7 @@
 	 * Care is taken to not have commit be what
 	 * triggers putting the thin-pool in-service.
 	 */
-	__pmd_write_lock(pmd);
+	pmd_write_lock_in_core(pmd);
 	if (pmd->fail_io)
 		goto out;
 
@@ -1850,19 +1886,52 @@
 int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
 {
 	int r = -EINVAL;
+	struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
+
+	/* fail_io is double-checked with pmd->root_lock held below */
+	if (unlikely(pmd->fail_io))
+		return r;
+
+	/*
+	 * Replacement block manager (new_bm) is created and old_bm destroyed outside of
+	 * pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
+	 * shrinker associated with the block manager's bufio client vs pmd root_lock).
+	 * - must take shrinker_rwsem without holding pmd->root_lock
+	 */
+	new_bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
+					 THIN_MAX_CONCURRENT_LOCKS);
 
 	pmd_write_lock(pmd);
-	if (pmd->fail_io)
+	if (pmd->fail_io) {
+		pmd_write_unlock(pmd);
 		goto out;
+	}
 
 	__set_abort_with_changes_flags(pmd);
-	__destroy_persistent_data_objects(pmd);
-	r = __create_persistent_data_objects(pmd, false);
+	__destroy_persistent_data_objects(pmd, false);
+	old_bm = pmd->bm;
+	if (IS_ERR(new_bm)) {
+		DMERR("could not create block manager during abort");
+		pmd->bm = NULL;
+		r = PTR_ERR(new_bm);
+		goto out_unlock;
+	}
+
+	pmd->bm = new_bm;
+	r = __open_or_format_metadata(pmd, false);
+	if (r) {
+		pmd->bm = NULL;
+		goto out_unlock;
+	}
+	new_bm = NULL;
+out_unlock:
 	if (r)
 		pmd->fail_io = true;
-
-out:
 	pmd_write_unlock(pmd);
+	dm_block_manager_destroy(old_bm);
+out:
+	if (new_bm && !IS_ERR(new_bm))
+		dm_block_manager_destroy(new_bm);
 
 	return r;
 }
@@ -2035,15 +2104,28 @@
 					dm_sm_threshold_fn fn,
 					void *context)
 {
-	int r;
+	int r = -EINVAL;
 
 	pmd_write_lock_in_core(pmd);
-	r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
+	if (!pmd->fail_io) {
+		r = dm_sm_register_threshold_callback(pmd->metadata_sm,
+						      threshold, fn, context);
+	}
 	pmd_write_unlock(pmd);
 
 	return r;
 }
 
+void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd,
+					  dm_pool_pre_commit_fn fn,
+					  void *context)
+{
+	pmd_write_lock_in_core(pmd);
+	pmd->pre_commit_fn = fn;
+	pmd->pre_commit_context = context;
+	pmd_write_unlock(pmd);
+}
+
 int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
 {
 	int r = -EINVAL;
--- linux-ein-5.4.0.orig/drivers/md/dm-thin-metadata.h
+++ linux-ein-5.4.0/drivers/md/dm-thin-metadata.h
@@ -230,6 +230,13 @@
  */
 void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd);
 
+/* Pre-commit callback */
+typedef int (*dm_pool_pre_commit_fn)(void *context);
+
+void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd,
+					  dm_pool_pre_commit_fn fn,
+					  void *context);
+
 /*----------------------------------------------------------------*/
 
 #endif
--- linux-ein-5.4.0.orig/drivers/md/dm-thin.c
+++ linux-ein-5.4.0/drivers/md/dm-thin.c
@@ -231,6 +231,7 @@
 	struct dm_target *ti;	/* Only set if a pool target is bound */
 
 	struct mapped_device *pool_md;
+	struct block_device *data_dev;
 	struct block_device *md_dev;
 	struct dm_pool_metadata *pmd;
 
@@ -328,6 +329,7 @@
 	dm_block_t low_water_blocks;
 	struct pool_features requested_pf; /* Features requested during table load */
 	struct pool_features adjusted_pf;  /* Features used after adjusting for constituent devices */
+	struct bio flush_bio;
 };
 
 /*
@@ -2222,6 +2224,7 @@
 			throttle_work_update(&pool->throttle);
 			dm_pool_issue_prefetches(pool->pmd);
 		}
+		cond_resched();
 	}
 	blk_finish_plug(&plug);
 }
@@ -2305,6 +2308,7 @@
 			else
 				pool->process_cell(tc, cell);
 		}
+		cond_resched();
 	} while (!list_empty(&cells));
 }
 
@@ -2392,8 +2396,16 @@
 	while ((bio = bio_list_pop(&bio_completions)))
 		bio_endio(bio);
 
-	while ((bio = bio_list_pop(&bios)))
-		generic_make_request(bio);
+	while ((bio = bio_list_pop(&bios))) {
+		/*
+		 * The data device was flushed as part of metadata commit,
+		 * so complete redundant flushes immediately.
+		 */
+		if (bio->bi_opf & REQ_PREFLUSH)
+			bio_endio(bio);
+		else
+			generic_make_request(bio);
+	}
 }
 
 static void do_worker(struct work_struct *ws)
@@ -2921,6 +2933,8 @@
 	dm_bio_prison_destroy(pool->prison);
 	dm_kcopyd_client_destroy(pool->copier);
 
+	cancel_delayed_work_sync(&pool->waker);
+	cancel_delayed_work_sync(&pool->no_space_timeout);
 	if (pool->wq)
 		destroy_workqueue(pool->wq);
 
@@ -2936,6 +2950,7 @@
 
 static struct pool *pool_create(struct mapped_device *pool_md,
 				struct block_device *metadata_dev,
+				struct block_device *data_dev,
 				unsigned long block_size,
 				int read_only, char **error)
 {
@@ -3043,6 +3058,7 @@
 	pool->last_commit_jiffies = jiffies;
 	pool->pool_md = pool_md;
 	pool->md_dev = metadata_dev;
+	pool->data_dev = data_dev;
 	__pool_table_insert(pool);
 
 	return pool;
@@ -3084,6 +3100,7 @@
 
 static struct pool *__pool_find(struct mapped_device *pool_md,
 				struct block_device *metadata_dev,
+				struct block_device *data_dev,
 				unsigned long block_size, int read_only,
 				char **error, int *created)
 {
@@ -3094,19 +3111,23 @@
 			*error = "metadata device already in use by a pool";
 			return ERR_PTR(-EBUSY);
 		}
+		if (pool->data_dev != data_dev) {
+			*error = "data device already in use by a pool";
+			return ERR_PTR(-EBUSY);
+		}
 		__pool_inc(pool);
 
 	} else {
 		pool = __pool_table_lookup(pool_md);
 		if (pool) {
-			if (pool->md_dev != metadata_dev) {
+			if (pool->md_dev != metadata_dev || pool->data_dev != data_dev) {
 				*error = "different pool cannot replace a pool";
 				return ERR_PTR(-EINVAL);
 			}
 			__pool_inc(pool);
 
 		} else {
-			pool = pool_create(pool_md, metadata_dev, block_size, read_only, error);
+			pool = pool_create(pool_md, metadata_dev, data_dev, block_size, read_only, error);
 			*created = 1;
 		}
 	}
@@ -3127,6 +3148,7 @@
 	__pool_dec(pt->pool);
 	dm_put_device(ti, pt->metadata_dev);
 	dm_put_device(ti, pt->data_dev);
+	bio_uninit(&pt->flush_bio);
 	kfree(pt);
 
 	mutex_unlock(&dm_thin_pool_table.mutex);
@@ -3192,6 +3214,29 @@
 	dm_table_event(pool->ti->table);
 }
 
+/*
+ * We need to flush the data device **before** committing the metadata.
+ *
+ * This ensures that the data blocks of any newly inserted mappings are
+ * properly written to non-volatile storage and won't be lost in case of a
+ * crash.
+ *
+ * Failure to do so can result in data corruption in the case of internal or
+ * external snapshots and in the case of newly provisioned blocks, when block
+ * zeroing is enabled.
+ */
+static int metadata_pre_commit_callback(void *context)
+{
+	struct pool_c *pt = context;
+	struct bio *flush_bio = &pt->flush_bio;
+
+	bio_reset(flush_bio);
+	bio_set_dev(flush_bio, pt->data_dev->bdev);
+	flush_bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
+
+	return submit_bio_wait(flush_bio);
+}
+
 static sector_t get_dev_size(struct block_device *bdev)
 {
 	return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
@@ -3335,7 +3380,7 @@
 		goto out;
 	}
 
-	pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev,
+	pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev, data_dev->bdev,
 			   block_size, pf.mode == PM_READ_ONLY, &ti->error, &pool_created);
 	if (IS_ERR(pool)) {
 		r = PTR_ERR(pool);
@@ -3360,7 +3405,9 @@
 	pt->data_dev = data_dev;
 	pt->low_water_blocks = low_water_blocks;
 	pt->adjusted_pf = pt->requested_pf = pf;
+	bio_init(&pt->flush_bio, NULL, 0);
 	ti->num_flush_bios = 1;
+	ti->limit_swap_bios = true;
 
 	/*
 	 * Only need to enable discards if the pool should pass
@@ -3383,8 +3430,10 @@
 						calc_metadata_threshold(pt),
 						metadata_low_callback,
 						pool);
-	if (r)
+	if (r) {
+		ti->error = "Error registering metadata threshold";
 		goto out_flags_changed;
+	}
 
 	pt->callbacks.congested_fn = pool_is_congested;
 	dm_table_add_target_callbacks(ti->table, &pt->callbacks);
@@ -3547,20 +3596,31 @@
 	 */
 	r = bind_control_target(pool, ti);
 	if (r)
-		return r;
+		goto out;
+
+	dm_pool_register_pre_commit_callback(pool->pmd,
+					     metadata_pre_commit_callback, pt);
 
 	r = maybe_resize_data_dev(ti, &need_commit1);
 	if (r)
-		return r;
+		goto out;
 
 	r = maybe_resize_metadata_dev(ti, &need_commit2);
 	if (r)
-		return r;
+		goto out;
 
 	if (need_commit1 || need_commit2)
 		(void) commit(pool);
+out:
+	/*
+	 * When a thin-pool is PM_FAIL, it cannot be rebuilt if
+	 * bio is in deferred list. Therefore need to return 0
+	 * to allow pool_resume() to flush IO.
+	 */
+	if (r && get_pool_mode(pool) == PM_FAIL)
+		r = 0;
 
-	return 0;
+	return r;
 }
 
 static void pool_suspend_active_thins(struct pool *pool)
@@ -4077,7 +4137,7 @@
 	.name = "thin-pool",
 	.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
 		    DM_TARGET_IMMUTABLE,
-	.version = {1, 21, 0},
+	.version = {1, 22, 0},
 	.module = THIS_MODULE,
 	.ctr = pool_ctr,
 	.dtr = pool_dtr,
@@ -4233,6 +4293,7 @@
 		goto bad;
 
 	ti->num_flush_bios = 1;
+	ti->limit_swap_bios = true;
 	ti->flush_supported = true;
 	ti->per_io_data_size = sizeof(struct dm_thin_endio_hook);
 
@@ -4456,7 +4517,7 @@
 
 static struct target_type thin_target = {
 	.name = "thin",
-	.version = {1, 21, 0},
+	.version = {1, 22, 0},
 	.module	= THIS_MODULE,
 	.ctr = thin_ctr,
 	.dtr = thin_dtr,
--- linux-ein-5.4.0.orig/drivers/md/dm-verity-fec.c
+++ linux-ein-5.4.0/drivers/md/dm-verity-fec.c
@@ -24,7 +24,8 @@
  */
 static inline struct dm_verity_fec_io *fec_io(struct dm_verity_io *io)
 {
-	return (struct dm_verity_fec_io *) verity_io_digest_end(io->v, io);
+	return (struct dm_verity_fec_io *)
+		((char *)io + io->v->ti->per_io_data_size - sizeof(struct dm_verity_fec_io));
 }
 
 /*
@@ -61,19 +62,18 @@
 static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
 			   unsigned *offset, struct dm_buffer **buf)
 {
-	u64 position, block;
+	u64 position, block, rem;
 	u8 *res;
 
 	position = (index + rsb) * v->fec->roots;
-	block = position >> v->data_dev_block_bits;
-	*offset = (unsigned)(position - (block << v->data_dev_block_bits));
+	block = div64_u64_rem(position, v->fec->io_size, &rem);
+	*offset = (unsigned)rem;
 
-	res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf);
+	res = dm_bufio_read(v->fec->bufio, block, buf);
 	if (IS_ERR(res)) {
 		DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
 		      v->data_dev->name, (unsigned long long)rsb,
-		      (unsigned long long)(v->fec->start + block),
-		      PTR_ERR(res));
+		      (unsigned long long)block, PTR_ERR(res));
 		*buf = NULL;
 	}
 
@@ -155,7 +155,7 @@
 
 		/* read the next block when we run out of parity bytes */
 		offset += v->fec->roots;
-		if (offset >= 1 << v->data_dev_block_bits) {
+		if (offset >= v->fec->io_size) {
 			dm_bufio_release(buf);
 
 			par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
@@ -435,7 +435,7 @@
 	fio->level++;
 
 	if (type == DM_VERITY_BLOCK_TYPE_METADATA)
-		block += v->data_blocks;
+		block = block - v->hash_start + v->data_blocks;
 
 	/*
 	 * For RS(M, N), the continuous FEC data is divided into blocks of N
@@ -551,6 +551,7 @@
 	mempool_exit(&f->rs_pool);
 	mempool_exit(&f->prealloc_pool);
 	mempool_exit(&f->extra_pool);
+	mempool_exit(&f->output_pool);
 	kmem_cache_destroy(f->cache);
 
 	if (f->data_bufio)
@@ -673,7 +674,7 @@
 {
 	struct dm_verity_fec *f = v->fec;
 	struct dm_target *ti = v->ti;
-	u64 hash_blocks;
+	u64 hash_blocks, fec_blocks;
 	int ret;
 
 	if (!verity_fec_is_enabled(v)) {
@@ -742,16 +743,23 @@
 		return -E2BIG;
 	}
 
+	if ((f->roots << SECTOR_SHIFT) & ((1 << v->data_dev_block_bits) - 1))
+		f->io_size = 1 << v->data_dev_block_bits;
+	else
+		f->io_size = v->fec->roots << SECTOR_SHIFT;
+
 	f->bufio = dm_bufio_client_create(f->dev->bdev,
-					  1 << v->data_dev_block_bits,
+					  f->io_size,
 					  1, 0, NULL, NULL);
 	if (IS_ERR(f->bufio)) {
 		ti->error = "Cannot initialize FEC bufio client";
 		return PTR_ERR(f->bufio);
 	}
 
-	if (dm_bufio_get_device_size(f->bufio) <
-	    ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) {
+	dm_bufio_set_sector_offset(f->bufio, f->start << (v->data_dev_block_bits - SECTOR_SHIFT));
+
+	fec_blocks = div64_u64(f->rounds * f->roots, v->fec->roots << SECTOR_SHIFT);
+	if (dm_bufio_get_device_size(f->bufio) < fec_blocks) {
 		ti->error = "FEC device is too small";
 		return -E2BIG;
 	}
--- linux-ein-5.4.0.orig/drivers/md/dm-verity-fec.h
+++ linux-ein-5.4.0/drivers/md/dm-verity-fec.h
@@ -36,6 +36,7 @@
 	struct dm_dev *dev;	/* parity data device */
 	struct dm_bufio_client *data_bufio;	/* for data dev access */
 	struct dm_bufio_client *bufio;		/* for parity data access */
+	size_t io_size;		/* IO size for roots */
 	sector_t start;		/* parity data start in blocks */
 	sector_t blocks;	/* number of blocks covered */
 	sector_t rounds;	/* number of interleaving rounds */
--- linux-ein-5.4.0.orig/drivers/md/dm-verity-target.c
+++ linux-ein-5.4.0/drivers/md/dm-verity-target.c
@@ -33,7 +33,7 @@
 #define DM_VERITY_OPT_IGN_ZEROES	"ignore_zero_blocks"
 #define DM_VERITY_OPT_AT_MOST_ONCE	"check_at_most_once"
 
-#define DM_VERITY_OPTS_MAX		(2 + DM_VERITY_OPTS_FEC + \
+#define DM_VERITY_OPTS_MAX		(3 + DM_VERITY_OPTS_FEC + \
 					 DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
 
 static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
@@ -471,13 +471,14 @@
 	struct bvec_iter start;
 	unsigned b;
 	struct crypto_wait wait;
+	struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
 
 	for (b = 0; b < io->n_blocks; b++) {
 		int r;
 		sector_t cur_block = io->block + b;
 		struct ahash_request *req = verity_io_hash_req(v, io);
 
-		if (v->validated_blocks &&
+		if (v->validated_blocks && bio->bi_status == BLK_STS_OK &&
 		    likely(test_bit(cur_block, v->validated_blocks))) {
 			verity_bv_skip_block(v, io, &io->iter);
 			continue;
@@ -525,15 +526,32 @@
 		else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
 					   cur_block, NULL, &start) == 0)
 			continue;
-		else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
-					   cur_block))
-			return -EIO;
+		else {
+			if (bio->bi_status) {
+				/*
+				 * Error correction failed; Just return error
+				 */
+				return -EIO;
+			}
+			if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
+					      cur_block))
+				return -EIO;
+		}
 	}
 
 	return 0;
 }
 
 /*
+ * Skip verity work in response to I/O error when system is shutting down.
+ */
+static inline bool verity_is_system_shutting_down(void)
+{
+	return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF
+		|| system_state == SYSTEM_RESTART;
+}
+
+/*
  * End one "io" structure with a given error.
  */
 static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
@@ -560,7 +578,10 @@
 {
 	struct dm_verity_io *io = bio->bi_private;
 
-	if (bio->bi_status && !verity_fec_is_enabled(io->v)) {
+	if (bio->bi_status &&
+	    (!verity_fec_is_enabled(io->v) ||
+	     verity_is_system_shutting_down() ||
+	     (bio->bi_opf & REQ_RAHEAD))) {
 		verity_finish_io(io, bio->bi_status);
 		return;
 	}
@@ -1207,6 +1228,7 @@
 
 static struct target_type verity_target = {
 	.name		= "verity",
+	.features	= DM_TARGET_IMMUTABLE,
 	.version	= {1, 5, 0},
 	.module		= THIS_MODULE,
 	.ctr		= verity_ctr,
--- linux-ein-5.4.0.orig/drivers/md/dm-verity-verify-sig.c
+++ linux-ein-5.4.0/drivers/md/dm-verity-verify-sig.c
@@ -15,7 +15,7 @@
 #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
 
 static bool require_signatures;
-module_param(require_signatures, bool, false);
+module_param(require_signatures, bool, 0444);
 MODULE_PARM_DESC(require_signatures,
 		"Verify the roothash of dm-verity hash tree");
 
--- linux-ein-5.4.0.orig/drivers/md/dm-verity.h
+++ linux-ein-5.4.0/drivers/md/dm-verity.h
@@ -110,12 +110,6 @@
 	return (u8 *)(io + 1) + v->ahash_reqsize + v->digest_size;
 }
 
-static inline u8 *verity_io_digest_end(struct dm_verity *v,
-				       struct dm_verity_io *io)
-{
-	return verity_io_want_digest(v, io) + v->digest_size;
-}
-
 extern int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
 			       struct bvec_iter *iter,
 			       int (*process)(struct dm_verity *v,
--- linux-ein-5.4.0.orig/drivers/md/dm-writecache.c
+++ linux-ein-5.4.0/drivers/md/dm-writecache.c
@@ -20,7 +20,7 @@
 
 #define HIGH_WATERMARK			50
 #define LOW_WATERMARK			45
-#define MAX_WRITEBACK_JOBS		0
+#define MAX_WRITEBACK_JOBS		min(0x10000000 / PAGE_SIZE, totalram_pages() / 16)
 #define ENDIO_LATENCY			16
 #define WRITEBACK_LATENCY		64
 #define AUTOCOMMIT_BLOCKS_SSD		65536
@@ -142,6 +142,7 @@
 	size_t metadata_sectors;
 	size_t n_blocks;
 	uint64_t seq_count;
+	sector_t data_device_sectors;
 	void *block_start;
 	struct wc_entry *entries;
 	unsigned block_size;
@@ -153,6 +154,7 @@
 	bool overwrote_committed:1;
 	bool memory_vmapped:1;
 
+	bool start_sector_set:1;
 	bool high_wm_percent_set:1;
 	bool low_wm_percent_set:1;
 	bool max_writeback_jobs_set:1;
@@ -161,6 +163,10 @@
 	bool writeback_fua_set:1;
 	bool flush_on_suspend:1;
 
+	unsigned high_wm_percent_value;
+	unsigned low_wm_percent_value;
+	unsigned autocommit_time_value;
+
 	unsigned writeback_all;
 	struct workqueue_struct *writeback_wq;
 	struct work_struct writeback_work;
@@ -224,6 +230,7 @@
 	pfn_t pfn;
 	int id;
 	struct page **pages;
+	sector_t offset;
 
 	wc->memory_vmapped = false;
 
@@ -242,9 +249,16 @@
 		goto err1;
 	}
 
+	offset = get_start_sect(wc->ssd_dev->bdev);
+	if (offset & (PAGE_SIZE / 512 - 1)) {
+		r = -EINVAL;
+		goto err1;
+	}
+	offset >>= PAGE_SHIFT - 9;
+
 	id = dax_read_lock();
 
-	da = dax_direct_access(wc->ssd_dev->dax_dev, 0, p, &wc->memory_map, &pfn);
+	da = dax_direct_access(wc->ssd_dev->dax_dev, offset, p, &wc->memory_map, &pfn);
 	if (da < 0) {
 		wc->memory_map = NULL;
 		r = da;
@@ -266,7 +280,7 @@
 		i = 0;
 		do {
 			long daa;
-			daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i,
+			daa = dax_direct_access(wc->ssd_dev->dax_dev, offset + i, p - i,
 						NULL, &pfn);
 			if (daa <= 0) {
 				r = daa ? daa : -EINVAL;
@@ -279,6 +293,8 @@
 			while (daa-- && i < p) {
 				pages[i++] = pfn_t_to_page(pfn);
 				pfn.val++;
+				if (!(i & 15))
+					cond_resched();
 			}
 		} while (i < p);
 		wc->memory_map = vmap(pages, p, VM_MAP, PAGE_KERNEL);
@@ -306,7 +322,7 @@
 #else
 static int persistent_memory_claim(struct dm_writecache *wc)
 {
-	BUG();
+	return -EOPNOTSUPP;
 }
 #endif
 
@@ -442,7 +458,13 @@
 		complete(&endio->c);
 }
 
-static void ssd_commit_flushed(struct dm_writecache *wc)
+static void writecache_wait_for_ios(struct dm_writecache *wc, int direction)
+{
+	wait_event(wc->bio_in_progress_wait[direction],
+		   !atomic_read(&wc->bio_in_progress[direction]));
+}
+
+static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
 {
 	struct dm_io_region region;
 	struct dm_io_request req;
@@ -488,17 +510,20 @@
 	writecache_notify_io(0, &endio);
 	wait_for_completion_io(&endio.c);
 
+	if (wait_for_ios)
+		writecache_wait_for_ios(wc, WRITE);
+
 	writecache_disk_flush(wc, wc->ssd_dev);
 
 	memset(wc->dirty_bitmap, 0, wc->dirty_bitmap_size);
 }
 
-static void writecache_commit_flushed(struct dm_writecache *wc)
+static void writecache_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
 {
 	if (WC_MODE_PMEM(wc))
 		wmb();
 	else
-		ssd_commit_flushed(wc);
+		ssd_commit_flushed(wc, wait_for_ios);
 }
 
 static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev)
@@ -522,12 +547,6 @@
 		writecache_error(wc, r, "error flushing metadata: %d", r);
 }
 
-static void writecache_wait_for_ios(struct dm_writecache *wc, int direction)
-{
-	wait_event(wc->bio_in_progress_wait[direction],
-		   !atomic_read(&wc->bio_in_progress[direction]));
-}
-
 #define WFE_RETURN_FOLLOWING	1
 #define WFE_LOWEST_SEQ		2
 
@@ -622,6 +641,12 @@
 	wc->freelist_size++;
 }
 
+static inline void writecache_verify_watermark(struct dm_writecache *wc)
+{
+	if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
+		queue_work(wc->writeback_wq, &wc->writeback_work);
+}
+
 static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc)
 {
 	struct wc_entry *e;
@@ -643,8 +668,8 @@
 		list_del(&e->lru);
 	}
 	wc->freelist_size--;
-	if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
-		queue_work(wc->writeback_wq, &wc->writeback_work);
+
+	writecache_verify_watermark(wc);
 
 	return e;
 }
@@ -724,15 +749,12 @@
 		e = e2;
 		cond_resched();
 	}
-	writecache_commit_flushed(wc);
-
-	if (!WC_MODE_PMEM(wc))
-		writecache_wait_for_ios(wc, WRITE);
+	writecache_commit_flushed(wc, true);
 
 	wc->seq_count++;
 	pmem_assign(sb(wc)->seq_count, cpu_to_le64(wc->seq_count));
 	writecache_flush_region(wc, &sb(wc)->seq_count, sizeof sb(wc)->seq_count);
-	writecache_commit_flushed(wc);
+	writecache_commit_flushed(wc, false);
 
 	wc->overwrote_committed = false;
 
@@ -756,7 +778,7 @@
 	}
 
 	if (need_flush_after_free)
-		writecache_commit_flushed(wc);
+		writecache_commit_flushed(wc, false);
 }
 
 static void writecache_flush_work(struct work_struct *work)
@@ -799,6 +821,8 @@
 				writecache_wait_for_ios(wc, WRITE);
 				discarded_something = true;
 			}
+			if (!writecache_entry_is_committed(wc, e))
+				wc->uncommitted_blocks--;
 			writecache_free_entry(wc, e);
 		}
 
@@ -809,7 +833,7 @@
 	}
 
 	if (discarded_something)
-		writecache_commit_flushed(wc);
+		writecache_commit_flushed(wc, false);
 }
 
 static bool writecache_wait_for_writeback(struct dm_writecache *wc)
@@ -838,7 +862,7 @@
 	}
 	wc_unlock(wc);
 
-	flush_workqueue(wc->writeback_wq);
+	drain_workqueue(wc->writeback_wq);
 
 	wc_lock(wc);
 	if (flush_on_suspend)
@@ -866,11 +890,30 @@
 		struct wc_entry *e = &wc->entries[b];
 		e->index = b;
 		e->write_in_progress = false;
+		cond_resched();
 	}
 
 	return 0;
 }
 
+static int writecache_read_metadata(struct dm_writecache *wc, sector_t n_sectors)
+{
+	struct dm_io_region region;
+	struct dm_io_request req;
+
+	region.bdev = wc->ssd_dev->bdev;
+	region.sector = wc->start_sector;
+	region.count = n_sectors;
+	req.bi_op = REQ_OP_READ;
+	req.bi_op_flags = REQ_SYNC;
+	req.mem.type = DM_IO_VMA;
+	req.mem.ptr.vma = (char *)wc->memory_map;
+	req.client = wc->dm_io;
+	req.notify.fn = NULL;
+
+	return dm_io(&req, 1, &region, NULL);
+}
+
 static void writecache_resume(struct dm_target *ti)
 {
 	struct dm_writecache *wc = ti->private;
@@ -881,8 +924,20 @@
 
 	wc_lock(wc);
 
-	if (WC_MODE_PMEM(wc))
+	wc->data_device_sectors = i_size_read(wc->dev->bdev->bd_inode) >> SECTOR_SHIFT;
+
+	if (WC_MODE_PMEM(wc)) {
 		persistent_memory_invalidate_cache(wc->memory_map, wc->memory_map_size);
+	} else {
+		r = writecache_read_metadata(wc, wc->metadata_sectors);
+		if (r) {
+			size_t sb_entries_offset;
+			writecache_error(wc, r, "unable to read metadata: %d", r);
+			sb_entries_offset = offsetof(struct wc_memory_superblock, entries);
+			memset((char *)wc->memory_map + sb_entries_offset, -1,
+			       (wc->metadata_sectors << SECTOR_SHIFT) - sb_entries_offset);
+		}
+	}
 
 	wc->tree = RB_ROOT;
 	INIT_LIST_HEAD(&wc->lru);
@@ -920,6 +975,7 @@
 			e->original_sector = le64_to_cpu(wme.original_sector);
 			e->seq_count = le64_to_cpu(wme.seq_count);
 		}
+		cond_resched();
 	}
 #endif
 	for (b = 0; b < wc->n_blocks; b++) {
@@ -958,9 +1014,11 @@
 
 	if (need_flush) {
 		writecache_flush_all_metadata(wc);
-		writecache_commit_flushed(wc);
+		writecache_commit_flushed(wc, false);
 	}
 
+	writecache_verify_watermark(wc);
+
 	wc_unlock(wc);
 }
 
@@ -1218,7 +1276,8 @@
 			}
 		} while (bio->bi_iter.bi_size);
 
-		if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks))
+		if (unlikely(bio->bi_opf & REQ_FUA ||
+			     wc->uncommitted_blocks >= wc->autocommit_blocks))
 			writecache_flush(wc);
 		else
 			writecache_schedule_autocommit(wc);
@@ -1341,7 +1400,7 @@
 			wc->writeback_size--;
 			n_walked++;
 			if (unlikely(n_walked >= ENDIO_LATENCY)) {
-				writecache_commit_flushed(wc);
+				writecache_commit_flushed(wc, false);
 				wc_unlock(wc);
 				wc_lock(wc);
 				n_walked = 0;
@@ -1422,7 +1481,7 @@
 			writecache_wait_for_ios(wc, READ);
 		}
 
-		writecache_commit_flushed(wc);
+		writecache_commit_flushed(wc, false);
 
 		wc_unlock(wc);
 	}
@@ -1437,6 +1496,10 @@
 	void *address = memory_data(wc, e);
 
 	persistent_memory_flush_cache(address, block_size);
+
+	if (unlikely(bio_end_sector(&wb->bio) >= wc->data_device_sectors))
+		return true;
+
 	return bio_add_page(&wb->bio, persistent_memory_page(address),
 			    block_size, persistent_memory_page_offset(address)) != 0;
 }
@@ -1508,6 +1571,9 @@
 		if (writecache_has_error(wc)) {
 			bio->bi_status = BLK_STS_IOERR;
 			bio_endio(bio);
+		} else if (unlikely(!bio_sectors(bio))) {
+			bio->bi_status = BLK_STS_OK;
+			bio_endio(bio);
 		} else {
 			submit_bio(bio);
 		}
@@ -1551,6 +1617,14 @@
 			e = f;
 		}
 
+		if (unlikely(to.sector + to.count > wc->data_device_sectors)) {
+			if (to.sector >= wc->data_device_sectors) {
+				writecache_copy_endio(0, 0, c);
+				continue;
+			}
+			from.count = to.count = wc->data_device_sectors - to.sector;
+		}
+
 		dm_kcopyd_copy(wc->dm_kcopyd, &from, 1, &to, 0, writecache_copy_endio, c);
 
 		__writeback_throttle(wc, wbl);
@@ -1761,14 +1835,16 @@
 	pmem_assign(sb(wc)->n_blocks, cpu_to_le64(wc->n_blocks));
 	pmem_assign(sb(wc)->seq_count, cpu_to_le64(0));
 
-	for (b = 0; b < wc->n_blocks; b++)
+	for (b = 0; b < wc->n_blocks; b++) {
 		write_original_sector_seq_count(wc, &wc->entries[b], -1, -1);
+		cond_resched();
+	}
 
 	writecache_flush_all_metadata(wc);
-	writecache_commit_flushed(wc);
+	writecache_commit_flushed(wc, false);
 	pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC));
 	writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic);
-	writecache_commit_flushed(wc);
+	writecache_commit_flushed(wc, false);
 
 	return 0;
 }
@@ -1836,7 +1912,7 @@
 	struct wc_memory_superblock s;
 
 	static struct dm_arg _args[] = {
-		{0, 10, "Invalid number of feature args"},
+		{0, 16, "Invalid number of feature args"},
 	};
 
 	as.argc = argc;
@@ -1971,6 +2047,12 @@
 		ti->error = "Invalid block size";
 		goto bad;
 	}
+	if (wc->block_size < bdev_logical_block_size(wc->dev->bdev) ||
+	    wc->block_size < bdev_logical_block_size(wc->ssd_dev->bdev)) {
+		r = -EINVAL;
+		ti->error = "Block size is smaller than device logical block size";
+		goto bad;
+	}
 	wc->block_size_bits = __ffs(wc->block_size);
 
 	wc->max_writeback_jobs = MAX_WRITEBACK_JOBS;
@@ -1992,6 +2074,7 @@
 			if (sscanf(string, "%llu%c", &start_sector, &dummy) != 1)
 				goto invalid_optional;
 			wc->start_sector = start_sector;
+			wc->start_sector_set = true;
 			if (wc->start_sector != start_sector ||
 			    wc->start_sector >= wc->memory_map_size >> SECTOR_SHIFT)
 				goto invalid_optional;
@@ -2001,6 +2084,7 @@
 				goto invalid_optional;
 			if (high_wm_percent < 0 || high_wm_percent > 100)
 				goto invalid_optional;
+			wc->high_wm_percent_value = high_wm_percent;
 			wc->high_wm_percent_set = true;
 		} else if (!strcasecmp(string, "low_watermark") && opt_params >= 1) {
 			string = dm_shift_arg(&as), opt_params--;
@@ -2008,6 +2092,7 @@
 				goto invalid_optional;
 			if (low_wm_percent < 0 || low_wm_percent > 100)
 				goto invalid_optional;
+			wc->low_wm_percent_value = low_wm_percent;
 			wc->low_wm_percent_set = true;
 		} else if (!strcasecmp(string, "writeback_jobs") && opt_params >= 1) {
 			string = dm_shift_arg(&as), opt_params--;
@@ -2027,6 +2112,7 @@
 			if (autocommit_msecs > 3600000)
 				goto invalid_optional;
 			wc->autocommit_jiffies = msecs_to_jiffies(autocommit_msecs);
+			wc->autocommit_time_value = autocommit_msecs;
 			wc->autocommit_time_set = true;
 		} else if (!strcasecmp(string, "fua")) {
 			if (WC_MODE_PMEM(wc)) {
@@ -2053,14 +2139,18 @@
 	}
 
 	if (WC_MODE_PMEM(wc)) {
+		if (!dax_synchronous(wc->ssd_dev->dax_dev)) {
+			r = -EOPNOTSUPP;
+			ti->error = "Asynchronous persistent memory not supported as pmem cache";
+			goto bad;
+		}
+
 		r = persistent_memory_claim(wc);
 		if (r) {
 			ti->error = "Unable to map persistent memory for cache";
 			goto bad;
 		}
 	} else {
-		struct dm_io_region region;
-		struct dm_io_request req;
 		size_t n_blocks, n_metadata_blocks;
 		uint64_t n_bitmap_bits;
 
@@ -2117,19 +2207,9 @@
 			goto bad;
 		}
 
-		region.bdev = wc->ssd_dev->bdev;
-		region.sector = wc->start_sector;
-		region.count = wc->metadata_sectors;
-		req.bi_op = REQ_OP_READ;
-		req.bi_op_flags = REQ_SYNC;
-		req.mem.type = DM_IO_VMA;
-		req.mem.ptr.vma = (char *)wc->memory_map;
-		req.client = wc->dm_io;
-		req.notify.fn = NULL;
-
-		r = dm_io(&req, 1, &region, NULL);
+		r = writecache_read_metadata(wc, wc->block_size >> SECTOR_SHIFT);
 		if (r) {
-			ti->error = "Unable to read metadata";
+			ti->error = "Unable to read first block of metadata";
 			goto bad;
 		}
 	}
@@ -2234,7 +2314,6 @@
 	struct dm_writecache *wc = ti->private;
 	unsigned extra_args;
 	unsigned sz = 0;
-	uint64_t x;
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -2246,7 +2325,7 @@
 		DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's',
 				wc->dev->name, wc->ssd_dev->name, wc->block_size);
 		extra_args = 0;
-		if (wc->start_sector)
+		if (wc->start_sector_set)
 			extra_args += 2;
 		if (wc->high_wm_percent_set)
 			extra_args += 2;
@@ -2262,26 +2341,18 @@
 			extra_args++;
 
 		DMEMIT("%u", extra_args);
-		if (wc->start_sector)
+		if (wc->start_sector_set)
 			DMEMIT(" start_sector %llu", (unsigned long long)wc->start_sector);
-		if (wc->high_wm_percent_set) {
-			x = (uint64_t)wc->freelist_high_watermark * 100;
-			x += wc->n_blocks / 2;
-			do_div(x, (size_t)wc->n_blocks);
-			DMEMIT(" high_watermark %u", 100 - (unsigned)x);
-		}
-		if (wc->low_wm_percent_set) {
-			x = (uint64_t)wc->freelist_low_watermark * 100;
-			x += wc->n_blocks / 2;
-			do_div(x, (size_t)wc->n_blocks);
-			DMEMIT(" low_watermark %u", 100 - (unsigned)x);
-		}
+		if (wc->high_wm_percent_set)
+			DMEMIT(" high_watermark %u", wc->high_wm_percent_value);
+		if (wc->low_wm_percent_set)
+			DMEMIT(" low_watermark %u", wc->low_wm_percent_value);
 		if (wc->max_writeback_jobs_set)
 			DMEMIT(" writeback_jobs %u", wc->max_writeback_jobs);
 		if (wc->autocommit_blocks_set)
 			DMEMIT(" autocommit_blocks %u", wc->autocommit_blocks);
 		if (wc->autocommit_time_set)
-			DMEMIT(" autocommit_time %u", jiffies_to_msecs(wc->autocommit_jiffies));
+			DMEMIT(" autocommit_time %u", wc->autocommit_time_value);
 		if (wc->writeback_fua_set)
 			DMEMIT(" %sfua", wc->writeback_fua ? "" : "no");
 		break;
--- linux-ein-5.4.0.orig/drivers/md/dm-zoned-metadata.c
+++ linux-ein-5.4.0/drivers/md/dm-zoned-metadata.c
@@ -134,6 +134,7 @@
 
 	sector_t		zone_bitmap_size;
 	unsigned int		zone_nr_bitmap_blocks;
+	unsigned int		zone_bits_per_mblk;
 
 	unsigned int		nr_bitmap_blocks;
 	unsigned int		nr_map_blocks;
@@ -554,6 +555,7 @@
 		       TASK_UNINTERRUPTIBLE);
 	if (test_bit(DMZ_META_ERROR, &mblk->state)) {
 		dmz_release_mblock(zmd, mblk);
+		dmz_check_bdev(zmd->dev);
 		return ERR_PTR(-EIO);
 	}
 
@@ -625,6 +627,8 @@
 	ret = submit_bio_wait(bio);
 	bio_put(bio);
 
+	if (ret)
+		dmz_check_bdev(zmd->dev);
 	return ret;
 }
 
@@ -691,6 +695,7 @@
 			       TASK_UNINTERRUPTIBLE);
 		if (test_bit(DMZ_META_ERROR, &mblk->state)) {
 			clear_bit(DMZ_META_ERROR, &mblk->state);
+			dmz_check_bdev(zmd->dev);
 			ret = -EIO;
 		}
 		nr_mblks_submitted--;
@@ -768,7 +773,7 @@
 	/* If there are no dirty metadata blocks, just flush the device cache */
 	if (list_empty(&write_list)) {
 		ret = blkdev_issue_flush(zmd->dev->bdev, GFP_NOIO, NULL);
-		goto out;
+		goto err;
 	}
 
 	/*
@@ -778,7 +783,7 @@
 	 */
 	ret = dmz_log_dirty_mblocks(zmd, &write_list);
 	if (ret)
-		goto out;
+		goto err;
 
 	/*
 	 * The log is on disk. It is now safe to update in place
@@ -786,11 +791,11 @@
 	 */
 	ret = dmz_write_dirty_mblocks(zmd, &write_list, zmd->mblk_primary);
 	if (ret)
-		goto out;
+		goto err;
 
 	ret = dmz_write_sb(zmd, zmd->mblk_primary);
 	if (ret)
-		goto out;
+		goto err;
 
 	while (!list_empty(&write_list)) {
 		mblk = list_first_entry(&write_list, struct dmz_mblock, link);
@@ -805,16 +810,20 @@
 
 	zmd->sb_gen++;
 out:
-	if (ret && !list_empty(&write_list)) {
-		spin_lock(&zmd->mblk_lock);
-		list_splice(&write_list, &zmd->mblk_dirty_list);
-		spin_unlock(&zmd->mblk_lock);
-	}
-
 	dmz_unlock_flush(zmd);
 	up_write(&zmd->mblk_sem);
 
 	return ret;
+
+err:
+	if (!list_empty(&write_list)) {
+		spin_lock(&zmd->mblk_lock);
+		list_splice(&write_list, &zmd->mblk_dirty_list);
+		spin_unlock(&zmd->mblk_lock);
+	}
+	if (!dmz_check_bdev(zmd->dev))
+		ret = -EIO;
+	goto out;
 }
 
 /*
@@ -1098,7 +1107,6 @@
 
 	if (blkz->type == BLK_ZONE_TYPE_CONVENTIONAL) {
 		set_bit(DMZ_RND, &zone->flags);
-		zmd->nr_rnd_zones++;
 	} else if (blkz->type == BLK_ZONE_TYPE_SEQWRITE_REQ ||
 		   blkz->type == BLK_ZONE_TYPE_SEQWRITE_PREF) {
 		set_bit(DMZ_SEQ, &zone->flags);
@@ -1159,7 +1167,10 @@
 
 	/* Init */
 	zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3;
-	zmd->zone_nr_bitmap_blocks = zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT;
+	zmd->zone_nr_bitmap_blocks =
+		max_t(sector_t, 1, zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT);
+	zmd->zone_bits_per_mblk = min_t(sector_t, dev->zone_nr_blocks,
+					DMZ_BLOCK_SIZE_BITS);
 
 	/* Allocate zone array */
 	zmd->zones = kcalloc(dev->nr_zones, sizeof(struct dm_zone), GFP_KERNEL);
@@ -1244,6 +1255,7 @@
 	if (ret) {
 		dmz_dev_err(zmd->dev, "Get zone %u report failed",
 			    dmz_id(zmd, zone));
+		dmz_check_bdev(zmd->dev);
 		return ret;
 	}
 
@@ -1577,7 +1589,7 @@
 			return dzone;
 	}
 
-	return ERR_PTR(-EBUSY);
+	return NULL;
 }
 
 /*
@@ -1597,7 +1609,7 @@
 			return zone;
 	}
 
-	return ERR_PTR(-EBUSY);
+	return NULL;
 }
 
 /*
@@ -1982,7 +1994,7 @@
 		dmz_release_mblock(zmd, to_mblk);
 		dmz_release_mblock(zmd, from_mblk);
 
-		chunk_block += DMZ_BLOCK_SIZE_BITS;
+		chunk_block += zmd->zone_bits_per_mblk;
 	}
 
 	to_zone->weight = from_zone->weight;
@@ -2043,7 +2055,7 @@
 
 		/* Set bits */
 		bit = chunk_block & DMZ_BLOCK_MASK_BITS;
-		nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit);
+		nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
 
 		count = dmz_set_bits((unsigned long *)mblk->data, bit, nr_bits);
 		if (count) {
@@ -2122,7 +2134,7 @@
 
 		/* Clear bits */
 		bit = chunk_block & DMZ_BLOCK_MASK_BITS;
-		nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit);
+		nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
 
 		count = dmz_clear_bits((unsigned long *)mblk->data,
 				       bit, nr_bits);
@@ -2182,6 +2194,7 @@
 {
 	struct dmz_mblock *mblk;
 	unsigned int bit, set_bit, nr_bits;
+	unsigned int zone_bits = zmd->zone_bits_per_mblk;
 	unsigned long *bitmap;
 	int n = 0;
 
@@ -2196,15 +2209,15 @@
 		/* Get offset */
 		bitmap = (unsigned long *) mblk->data;
 		bit = chunk_block & DMZ_BLOCK_MASK_BITS;
-		nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit);
+		nr_bits = min(nr_blocks, zone_bits - bit);
 		if (set)
-			set_bit = find_next_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit);
+			set_bit = find_next_bit(bitmap, zone_bits, bit);
 		else
-			set_bit = find_next_zero_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit);
+			set_bit = find_next_zero_bit(bitmap, zone_bits, bit);
 		dmz_release_mblock(zmd, mblk);
 
 		n += set_bit - bit;
-		if (set_bit < DMZ_BLOCK_SIZE_BITS)
+		if (set_bit < zone_bits)
 			break;
 
 		nr_blocks -= nr_bits;
@@ -2307,7 +2320,7 @@
 		/* Count bits in this block */
 		bitmap = mblk->data;
 		bit = chunk_block & DMZ_BLOCK_MASK_BITS;
-		nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit);
+		nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
 		n += dmz_count_bits(bitmap, bit, nr_bits);
 
 		dmz_release_mblock(zmd, mblk);
--- linux-ein-5.4.0.orig/drivers/md/dm-zoned-reclaim.c
+++ linux-ein-5.4.0/drivers/md/dm-zoned-reclaim.c
@@ -82,6 +82,7 @@
 			    "Align zone %u wp %llu to %llu (wp+%u) blocks failed %d",
 			    dmz_id(zmd, zone), (unsigned long long)wp_block,
 			    (unsigned long long)block, nr_blocks, ret);
+		dmz_check_bdev(zrc->dev);
 		return ret;
 	}
 
@@ -348,8 +349,8 @@
 
 	/* Get a data zone */
 	dzone = dmz_get_zone_for_reclaim(zmd);
-	if (IS_ERR(dzone))
-		return PTR_ERR(dzone);
+	if (!dzone)
+		return -EBUSY;
 
 	start = jiffies;
 
@@ -489,12 +490,7 @@
 	ret = dmz_do_reclaim(zrc);
 	if (ret) {
 		dmz_dev_debug(zrc->dev, "Reclaim error %d\n", ret);
-		if (ret == -EIO)
-			/*
-			 * LLD might be performing some error handling sequence
-			 * at the underlying device. To not interfere, do not
-			 * attempt to schedule the next reclaim run immediately.
-			 */
+		if (!dmz_check_bdev(zrc->dev))
 			return;
 	}
 
--- linux-ein-5.4.0.orig/drivers/md/dm-zoned-target.c
+++ linux-ein-5.4.0/drivers/md/dm-zoned-target.c
@@ -80,6 +80,8 @@
 
 	if (status != BLK_STS_OK && bio->bi_status == BLK_STS_OK)
 		bio->bi_status = status;
+	if (bio->bi_status != BLK_STS_OK)
+		bioctx->target->dev->flags |= DMZ_CHECK_BDEV;
 
 	if (refcount_dec_and_test(&bioctx->ref)) {
 		struct dm_zone *zone = bioctx->zone;
@@ -531,8 +533,9 @@
 
 	/* Get the BIO chunk work. If one is not active yet, create one */
 	cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
-	if (!cw) {
-
+	if (cw) {
+		dmz_get_chunk_work(cw);
+	} else {
 		/* Create a new chunk work */
 		cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
 		if (unlikely(!cw)) {
@@ -541,7 +544,7 @@
 		}
 
 		INIT_WORK(&cw->work, dmz_chunk_work);
-		refcount_set(&cw->refcount, 0);
+		refcount_set(&cw->refcount, 1);
 		cw->target = dmz;
 		cw->chunk = chunk;
 		bio_list_init(&cw->bio_list);
@@ -554,7 +557,6 @@
 	}
 
 	bio_list_add(&cw->bio_list, bio);
-	dmz_get_chunk_work(cw);
 
 	dmz_reclaim_bio_acc(dmz->reclaim);
 	if (queue_work(dmz->chunk_wq, &cw->work))
@@ -565,32 +567,52 @@
 }
 
 /*
- * Check the backing device availability. If it's on the way out,
+ * Check if the backing device is being removed. If it's on the way out,
  * start failing I/O. Reclaim and metadata components also call this
  * function to cleanly abort operation in the event of such failure.
  */
 bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev)
 {
-	struct gendisk *disk;
+	if (dmz_dev->flags & DMZ_BDEV_DYING)
+		return true;
 
-	if (!(dmz_dev->flags & DMZ_BDEV_DYING)) {
-		disk = dmz_dev->bdev->bd_disk;
-		if (blk_queue_dying(bdev_get_queue(dmz_dev->bdev))) {
-			dmz_dev_warn(dmz_dev, "Backing device queue dying");
-			dmz_dev->flags |= DMZ_BDEV_DYING;
-		} else if (disk->fops->check_events) {
-			if (disk->fops->check_events(disk, 0) &
-					DISK_EVENT_MEDIA_CHANGE) {
-				dmz_dev_warn(dmz_dev, "Backing device offline");
-				dmz_dev->flags |= DMZ_BDEV_DYING;
-			}
-		}
+	if (dmz_dev->flags & DMZ_CHECK_BDEV)
+		return !dmz_check_bdev(dmz_dev);
+
+	if (blk_queue_dying(bdev_get_queue(dmz_dev->bdev))) {
+		dmz_dev_warn(dmz_dev, "Backing device queue dying");
+		dmz_dev->flags |= DMZ_BDEV_DYING;
 	}
 
 	return dmz_dev->flags & DMZ_BDEV_DYING;
 }
 
 /*
+ * Check the backing device availability. This detects such events as
+ * backing device going offline due to errors, media removals, etc.
+ * This check is less efficient than dmz_bdev_is_dying() and should
+ * only be performed as a part of error handling.
+ */
+bool dmz_check_bdev(struct dmz_dev *dmz_dev)
+{
+	struct gendisk *disk;
+
+	dmz_dev->flags &= ~DMZ_CHECK_BDEV;
+
+	if (dmz_bdev_is_dying(dmz_dev))
+		return false;
+
+	disk = dmz_dev->bdev->bd_disk;
+	if (disk->fops->check_events &&
+	    disk->fops->check_events(disk, 0) & DISK_EVENT_MEDIA_CHANGE) {
+		dmz_dev_warn(dmz_dev, "Backing device offline");
+		dmz_dev->flags |= DMZ_BDEV_DYING;
+	}
+
+	return !(dmz_dev->flags & DMZ_BDEV_DYING);
+}
+
+/*
  * Process a new BIO.
  */
 static int dmz_map(struct dm_target *ti, struct bio *bio)
@@ -768,7 +790,7 @@
 	}
 
 	/* Set target (no write same support) */
-	ti->max_io_len = dev->zone_nr_sectors << 9;
+	ti->max_io_len = dev->zone_nr_sectors;
 	ti->num_flush_bios = 1;
 	ti->num_discard_bios = 1;
 	ti->num_write_zeroes_bios = 1;
@@ -902,8 +924,8 @@
 {
 	struct dmz_target *dmz = ti->private;
 
-	if (dmz_bdev_is_dying(dmz->dev))
-		return -ENODEV;
+	if (!dmz_check_bdev(dmz->dev))
+		return -EIO;
 
 	*bdev = dmz->dev->bdev;
 
--- linux-ein-5.4.0.orig/drivers/md/dm-zoned.h
+++ linux-ein-5.4.0/drivers/md/dm-zoned.h
@@ -72,6 +72,7 @@
 
 /* Device flags. */
 #define DMZ_BDEV_DYING		(1 << 0)
+#define DMZ_CHECK_BDEV		(2 << 0)
 
 /*
  * Zone descriptor.
@@ -255,5 +256,6 @@
  * Functions defined in dm-zoned-target.c
  */
 bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev);
+bool dmz_check_bdev(struct dmz_dev *dmz_dev);
 
 #endif /* DM_ZONED_H */
--- linux-ein-5.4.0.orig/drivers/md/dm.c
+++ linux-ein-5.4.0/drivers/md/dm.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/sched/mm.h>
 #include <linux/sched/signal.h>
 #include <linux/blkpg.h>
 #include <linux/bio.h>
@@ -140,10 +141,21 @@
 #define DMF_NOFLUSH_SUSPENDING 5
 #define DMF_DEFERRED_REMOVE 6
 #define DMF_SUSPENDED_INTERNALLY 7
+#define DMF_POST_SUSPENDING 8
 
 #define DM_NUMA_NODE NUMA_NO_NODE
 static int dm_numa_node = DM_NUMA_NODE;
 
+#define DEFAULT_SWAP_BIOS	(8 * 1048576 / PAGE_SIZE)
+static int swap_bios = DEFAULT_SWAP_BIOS;
+static int get_swap_bios(void)
+{
+	int latch = READ_ONCE(swap_bios);
+	if (unlikely(latch <= 0))
+		latch = DEFAULT_SWAP_BIOS;
+	return latch;
+}
+
 /*
  * For mempools pre-allocation at the table loading time.
  */
@@ -251,7 +263,6 @@
 
 static void local_exit(void)
 {
-	flush_scheduled_work();
 	destroy_workqueue(deferred_remove_workqueue);
 
 	unregister_blkdev(_major, _name);
@@ -453,8 +464,10 @@
 		return -EAGAIN;
 
 	map = dm_get_live_table(md, &srcu_idx);
-	if (!map)
-		return -EIO;
+	if (!map) {
+		ret = -EIO;
+		goto out;
+	}
 
 	tgt = dm_table_find_target(map, sector);
 	if (!tgt) {
@@ -491,7 +504,6 @@
 
 static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
 			    struct block_device **bdev)
-	__acquires(md->io_barrier)
 {
 	struct dm_target *tgt;
 	struct dm_table *map;
@@ -525,7 +537,6 @@
 }
 
 static void dm_unprepare_ioctl(struct mapped_device *md, int srcu_idx)
-	__releases(md->io_barrier)
 {
 	dm_put_live_table(md, srcu_idx);
 }
@@ -546,7 +557,7 @@
 		 * subset of the parent bdev; require extra privileges.
 		 */
 		if (!capable(CAP_SYS_RAWIO)) {
-			DMWARN_LIMIT(
+			DMDEBUG_LIMIT(
 	"%s: sending ioctl %x to DM device without required privilege.",
 				current->comm, cmd);
 			r = -ENOIOCTLCMD;
@@ -664,19 +675,20 @@
 				    false, 0, &io->stats_aux);
 }
 
-static void end_io_acct(struct dm_io *io)
+static void end_io_acct(struct mapped_device *md, struct bio *bio,
+			unsigned long start_time, struct dm_stats_aux *stats_aux)
 {
-	struct mapped_device *md = io->md;
-	struct bio *bio = io->orig_bio;
-	unsigned long duration = jiffies - io->start_time;
-
-	generic_end_io_acct(md->queue, bio_op(bio), &dm_disk(md)->part0,
-			    io->start_time);
+	unsigned long duration = jiffies - start_time;
 
 	if (unlikely(dm_stats_used(&md->stats)))
 		dm_stats_account_io(&md->stats, bio_data_dir(bio),
 				    bio->bi_iter.bi_sector, bio_sectors(bio),
-				    true, duration, &io->stats_aux);
+				    true, duration, stats_aux);
+
+	smp_wmb();
+
+	generic_end_io_acct(md->queue, bio_op(bio), &dm_disk(md)->part0,
+			    start_time);
 
 	/* nudge anyone waiting on suspend queue */
 	if (unlikely(wq_has_sleeper(&md->wait)))
@@ -897,6 +909,8 @@
 	blk_status_t io_error;
 	struct bio *bio;
 	struct mapped_device *md = io->md;
+	unsigned long start_time = 0;
+	struct dm_stats_aux stats_aux;
 
 	/* Push-back supersedes any I/O errors */
 	if (unlikely(error)) {
@@ -923,8 +937,10 @@
 
 		io_error = io->status;
 		bio = io->orig_bio;
-		end_io_acct(io);
+		start_time = io->start_time;
+		stats_aux = io->stats_aux;
 		free_io(md, io);
+		end_io_acct(md, bio, start_time, &stats_aux);
 
 		if (io_error == BLK_STS_DM_REQUEUE)
 			return;
@@ -970,6 +986,11 @@
 	limits->max_write_zeroes_sectors = 0;
 }
 
+static bool swap_bios_limit(struct dm_target *ti, struct bio *bio)
+{
+	return unlikely((bio->bi_opf & REQ_SWAP) != 0) && unlikely(ti->limit_swap_bios);
+}
+
 static void clone_endio(struct bio *bio)
 {
 	blk_status_t error = bio->bi_status;
@@ -978,7 +999,7 @@
 	struct mapped_device *md = tio->io->md;
 	dm_endio_fn endio = tio->ti->type->end_io;
 
-	if (unlikely(error == BLK_STS_TARGET) && md->type != DM_TYPE_NVME_BIO_BASED) {
+	if (unlikely(error == BLK_STS_TARGET)) {
 		if (bio_op(bio) == REQ_OP_DISCARD &&
 		    !bio->bi_disk->queue->limits.max_discard_sectors)
 			disable_discard(md);
@@ -1007,6 +1028,11 @@
 		}
 	}
 
+	if (unlikely(swap_bios_limit(tio->ti, bio))) {
+		struct mapped_device *md = io->md;
+		up(&md->swap_bios_semaphore);
+	}
+
 	free_tio(tio);
 	dec_pending(io, error);
 }
@@ -1110,15 +1136,16 @@
 {
 	struct mapped_device *md = dax_get_private(dax_dev);
 	struct dm_table *map;
+	bool ret = false;
 	int srcu_idx;
-	bool ret;
 
 	map = dm_get_live_table(md, &srcu_idx);
 	if (!map)
-		return false;
+		goto out;
 
-	ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
+	ret = dm_table_supports_dax(map, device_not_dax_capable, &blocksize);
 
+out:
 	dm_put_live_table(md, srcu_idx);
 
 	return ret;
@@ -1260,6 +1287,22 @@
 }
 EXPORT_SYMBOL_GPL(dm_remap_zone_report);
 
+static noinline void __set_swap_bios_limit(struct mapped_device *md, int latch)
+{
+	mutex_lock(&md->swap_bios_lock);
+	while (latch < md->swap_bios) {
+		cond_resched();
+		down(&md->swap_bios_semaphore);
+		md->swap_bios--;
+	}
+	while (latch > md->swap_bios) {
+		cond_resched();
+		up(&md->swap_bios_semaphore);
+		md->swap_bios++;
+	}
+	mutex_unlock(&md->swap_bios_lock);
+}
+
 static blk_qc_t __map_bio(struct dm_target_io *tio)
 {
 	int r;
@@ -1280,6 +1323,13 @@
 	atomic_inc(&io->io_count);
 	sector = clone->bi_iter.bi_sector;
 
+	if (unlikely(swap_bios_limit(ti, clone))) {
+		int latch = get_swap_bios();
+		if (unlikely(latch != md->swap_bios))
+			__set_swap_bios_limit(md, latch);
+		down(&md->swap_bios_semaphore);
+	}
+
 	r = ti->type->map(ti, clone);
 	switch (r) {
 	case DM_MAPIO_SUBMITTED:
@@ -1288,16 +1338,17 @@
 		/* the bio has been remapped so dispatch it */
 		trace_block_bio_remap(clone->bi_disk->queue, clone,
 				      bio_dev(io->orig_bio), sector);
-		if (md->type == DM_TYPE_NVME_BIO_BASED)
-			ret = direct_make_request(clone);
-		else
-			ret = generic_make_request(clone);
+		ret = generic_make_request(clone);
 		break;
 	case DM_MAPIO_KILL:
+		if (unlikely(swap_bios_limit(ti, clone)))
+			up(&md->swap_bios_semaphore);
 		free_tio(tio);
 		dec_pending(io, BLK_STS_IOERR);
 		break;
 	case DM_MAPIO_REQUEUE:
+		if (unlikely(swap_bios_limit(ti, clone)))
+			up(&md->swap_bios_semaphore);
 		free_tio(tio);
 		dec_pending(io, BLK_STS_DM_REQUEUE);
 		break;
@@ -1436,9 +1487,6 @@
 	BUG_ON(bio_has_data(ci->bio));
 	while ((ti = dm_table_get_target(ci->map, target_nr++)))
 		__send_duplicate_bios(ci, ti, ti->num_flush_bios, NULL);
-
-	bio_disassociate_blkg(ci->bio);
-
 	return 0;
 }
 
@@ -1626,6 +1674,7 @@
 		ci.bio = &flush_bio;
 		ci.sector_count = 0;
 		error = __send_empty_flush(&ci);
+		bio_uninit(ci.bio);
 		/* dec_pending submits any data associated with flush */
 	} else if (bio_op(bio) == REQ_OP_ZONE_RESET) {
 		ci.bio = bio;
@@ -1674,67 +1723,6 @@
 	return ret;
 }
 
-/*
- * Optimized variant of __split_and_process_bio that leverages the
- * fact that targets that use it do _not_ have a need to split bios.
- */
-static blk_qc_t __process_bio(struct mapped_device *md, struct dm_table *map,
-			      struct bio *bio, struct dm_target *ti)
-{
-	struct clone_info ci;
-	blk_qc_t ret = BLK_QC_T_NONE;
-	int error = 0;
-
-	init_clone_info(&ci, md, map, bio);
-
-	if (bio->bi_opf & REQ_PREFLUSH) {
-		struct bio flush_bio;
-
-		/*
-		 * Use an on-stack bio for this, it's safe since we don't
-		 * need to reference it after submit. It's just used as
-		 * the basis for the clone(s).
-		 */
-		bio_init(&flush_bio, NULL, 0);
-		flush_bio.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC;
-		ci.bio = &flush_bio;
-		ci.sector_count = 0;
-		error = __send_empty_flush(&ci);
-		/* dec_pending submits any data associated with flush */
-	} else {
-		struct dm_target_io *tio;
-
-		ci.bio = bio;
-		ci.sector_count = bio_sectors(bio);
-		if (__process_abnormal_io(&ci, ti, &error))
-			goto out;
-
-		tio = alloc_tio(&ci, ti, 0, GFP_NOIO);
-		ret = __clone_and_map_simple_bio(&ci, tio, NULL);
-	}
-out:
-	/* drop the extra reference count */
-	dec_pending(ci.io, errno_to_blk_status(error));
-	return ret;
-}
-
-static void dm_queue_split(struct mapped_device *md, struct dm_target *ti, struct bio **bio)
-{
-	unsigned len, sector_count;
-
-	sector_count = bio_sectors(*bio);
-	len = min_t(sector_t, max_io_len((*bio)->bi_iter.bi_sector, ti), sector_count);
-
-	if (sector_count > len) {
-		struct bio *split = bio_split(*bio, len, GFP_NOIO, &md->queue->bio_split);
-
-		bio_chain(split, *bio);
-		trace_block_split(md->queue, split, (*bio)->bi_iter.bi_sector);
-		generic_make_request(*bio);
-		*bio = split;
-	}
-}
-
 static blk_qc_t dm_process_bio(struct mapped_device *md,
 			       struct dm_table *map, struct bio *bio)
 {
@@ -1760,15 +1748,12 @@
 	 * won't be imposed.
 	 */
 	if (current->bio_list) {
-		blk_queue_split(md->queue, &bio);
-		if (!is_abnormal_io(bio))
-			dm_queue_split(md, ti, &bio);
+		if (is_abnormal_io(bio))
+			blk_queue_split(md->queue, &bio);
+		/* regular IO is split by __split_and_process_bio */
 	}
 
-	if (dm_get_md_type(md) == DM_TYPE_NVME_BIO_BASED)
-		return __process_bio(md, map, bio, ti);
-	else
-		return __split_and_process_bio(md, map, bio);
+	return __split_and_process_bio(md, map, bio);
 }
 
 static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
@@ -1809,7 +1794,8 @@
 			 * With request-based DM we only need to check the
 			 * top-level queue for congestion.
 			 */
-			r = md->queue->backing_dev_info->wb.state & bdi_bits;
+			struct backing_dev_info *bdi = md->queue->backing_dev_info;
+			r = bdi->wb.congested->state & bdi_bits;
 		} else {
 			map = dm_get_live_table_fast(md);
 			if (map)
@@ -1875,14 +1861,6 @@
 
 static void dm_wq_work(struct work_struct *work);
 
-static void dm_init_normal_md_queue(struct mapped_device *md)
-{
-	/*
-	 * Initialize aspects of queue that aren't relevant for blk-mq
-	 */
-	md->queue->backing_dev_info->congested_fn = dm_any_congested;
-}
-
 static void cleanup_mapped_device(struct mapped_device *md)
 {
 	if (md->wq)
@@ -1917,6 +1895,7 @@
 	mutex_destroy(&md->suspend_lock);
 	mutex_destroy(&md->type_lock);
 	mutex_destroy(&md->table_devices_lock);
+	mutex_destroy(&md->swap_bios_lock);
 
 	dm_mq_cleanup_mapped_device(md);
 }
@@ -1970,7 +1949,12 @@
 	if (!md->queue)
 		goto bad;
 	md->queue->queuedata = md;
-	md->queue->backing_dev_info->congested_data = 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_node(1, md->numa_node_id);
 	if (!md->disk)
@@ -1981,6 +1965,10 @@
 	init_waitqueue_head(&md->eventq);
 	init_completion(&md->kobj_holder.completion);
 
+	md->swap_bios = get_swap_bios();
+	sema_init(&md->swap_bios_semaphore, md->swap_bios);
+	mutex_init(&md->swap_bios_lock);
+
 	md->disk->major = _major;
 	md->disk->first_minor = minor;
 	md->disk->fops = &dm_blk_dops;
@@ -2006,7 +1994,9 @@
 	if (!md->bdev)
 		goto bad;
 
-	dm_stats_init(&md->stats);
+	r = dm_stats_init(&md->stats);
+	if (r < 0)
+		goto bad;
 
 	/* Populate the mapping, nobody knows we exist yet */
 	spin_lock(&_minor_lock);
@@ -2156,12 +2146,10 @@
 	if (request_based)
 		dm_stop_queue(q);
 
-	if (request_based || md->type == DM_TYPE_NVME_BIO_BASED) {
+	if (request_based) {
 		/*
-		 * Leverage the fact that request-based DM targets and
-		 * NVMe bio based targets are immutable singletons
-		 * - used to optimize both dm_request_fn and dm_mq_queue_rq;
-		 *   and __process_bio.
+		 * Leverage the fact that request-based DM targets are
+		 * immutable singletons - used to optimize dm_mq_queue_rq.
 		 */
 		md->immutable_target = dm_table_get_immutable_target(t);
 	}
@@ -2264,6 +2252,12 @@
 }
 EXPORT_SYMBOL_GPL(dm_get_queue_limits);
 
+static void dm_init_congested_fn(struct mapped_device *md)
+{
+	md->queue->backing_dev_info->congested_data = md;
+	md->queue->backing_dev_info->congested_fn = dm_any_congested;
+}
+
 /*
  * Setup the DM device's queue based on md's type
  */
@@ -2280,12 +2274,11 @@
 			DMERR("Cannot initialize queue for request-based dm-mq mapped device");
 			return r;
 		}
+		dm_init_congested_fn(md);
 		break;
 	case DM_TYPE_BIO_BASED:
 	case DM_TYPE_DAX_BIO_BASED:
-	case DM_TYPE_NVME_BIO_BASED:
-		dm_init_normal_md_queue(md);
-		blk_queue_make_request(md->queue, dm_make_request);
+		dm_init_congested_fn(md);
 		break;
 	case DM_TYPE_NONE:
 		WARN_ON_ONCE(true);
@@ -2384,6 +2377,8 @@
 	map = dm_get_live_table(md, &srcu_idx);
 	if (!dm_suspended_md(md)) {
 		dm_table_presuspend_targets(map);
+		set_bit(DMF_SUSPENDED, &md->flags);
+		set_bit(DMF_POST_SUSPENDING, &md->flags);
 		dm_table_postsuspend_targets(map);
 	}
 	/* dm_put_live_table must be before msleep, otherwise deadlock is possible */
@@ -2444,6 +2439,8 @@
 	}
 	finish_wait(&md->wait, &wait);
 
+	smp_rmb();
+
 	return r;
 }
 
@@ -2706,7 +2703,9 @@
 	if (r)
 		goto out_unlock;
 
+	set_bit(DMF_POST_SUSPENDING, &md->flags);
 	dm_table_postsuspend_targets(map);
+	clear_bit(DMF_POST_SUSPENDING, &md->flags);
 
 out_unlock:
 	mutex_unlock(&md->suspend_lock);
@@ -2803,7 +2802,9 @@
 	(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
 			    DMF_SUSPENDED_INTERNALLY);
 
+	set_bit(DMF_POST_SUSPENDING, &md->flags);
 	dm_table_postsuspend_targets(map);
+	clear_bit(DMF_POST_SUSPENDING, &md->flags);
 }
 
 static void __dm_internal_resume(struct mapped_device *md)
@@ -2880,17 +2881,25 @@
 int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
 		       unsigned cookie)
 {
+	int r;
+	unsigned noio_flag;
 	char udev_cookie[DM_COOKIE_LENGTH];
 	char *envp[] = { udev_cookie, NULL };
 
+	noio_flag = memalloc_noio_save();
+
 	if (!cookie)
-		return kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
+		r = kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
 	else {
 		snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
 			 DM_COOKIE_ENV_VAR_NAME, cookie);
-		return kobject_uevent_env(&disk_to_dev(md->disk)->kobj,
-					  action, envp);
+		r = kobject_uevent_env(&disk_to_dev(md->disk)->kobj,
+				       action, envp);
 	}
+
+	memalloc_noio_restore(noio_flag);
+
+	return r;
 }
 
 uint32_t dm_next_uevent_seq(struct mapped_device *md)
@@ -2956,6 +2965,11 @@
 	return test_bit(DMF_SUSPENDED, &md->flags);
 }
 
+static int dm_post_suspending_md(struct mapped_device *md)
+{
+	return test_bit(DMF_POST_SUSPENDING, &md->flags);
+}
+
 int dm_suspended_internally_md(struct mapped_device *md)
 {
 	return test_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
@@ -2972,6 +2986,12 @@
 }
 EXPORT_SYMBOL_GPL(dm_suspended);
 
+int dm_post_suspending(struct dm_target *ti)
+{
+	return dm_post_suspending_md(dm_table_get_md(ti->table));
+}
+EXPORT_SYMBOL_GPL(dm_post_suspending);
+
 int dm_noflush_suspending(struct dm_target *ti)
 {
 	return __noflush_suspending(dm_table_get_md(ti->table));
@@ -2993,7 +3013,6 @@
 	switch (type) {
 	case DM_TYPE_BIO_BASED:
 	case DM_TYPE_DAX_BIO_BASED:
-	case DM_TYPE_NVME_BIO_BASED:
 		pool_size = max(dm_get_reserved_bio_based_ios(), min_pool_size);
 		front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
 		io_front_pad = roundup(front_pad,  __alignof__(struct dm_io)) + offsetof(struct dm_io, tio);
@@ -3062,6 +3081,11 @@
 		goto out;
 	ti = dm_table_get_target(table, 0);
 
+	if (dm_suspended_md(md)) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
 	ret = -EINVAL;
 	if (!ti->type->iterate_devices)
 		goto out;
@@ -3232,6 +3256,9 @@
 module_param(dm_numa_node, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(dm_numa_node, "NUMA node for DM device memory allocations");
 
+module_param(swap_bios, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(swap_bios, "Maximum allowed inflight swap IOs");
+
 MODULE_DESCRIPTION(DM_NAME " driver");
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/md/dm.h
+++ linux-ein-5.4.0/drivers/md/dm.h
@@ -74,7 +74,7 @@
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
 			   int *blocksize);
-int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_not_dax_capable(struct dm_target *ti, struct dm_dev *dev,
 			   sector_t start, sector_t len, void *data);
 
 void dm_lock_md_type(struct mapped_device *md);
--- linux-ein-5.4.0.orig/drivers/md/md-bitmap.c
+++ linux-ein-5.4.0/drivers/md/md-bitmap.c
@@ -54,14 +54,7 @@
 {
 	unsigned char *mappage;
 
-	if (page >= bitmap->pages) {
-		/* This can happen if bitmap_start_sync goes beyond
-		 * End-of-device while looking for a whole page.
-		 * It is harmless.
-		 */
-		return -EINVAL;
-	}
-
+	WARN_ON_ONCE(page >= bitmap->pages);
 	if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */
 		return 0;
 
@@ -489,7 +482,7 @@
 	sb = kmap_atomic(bitmap->storage.sb_page);
 	pr_debug("%s: bitmap file superblock:\n", bmname(bitmap));
 	pr_debug("         magic: %08x\n", le32_to_cpu(sb->magic));
-	pr_debug("       version: %d\n", le32_to_cpu(sb->version));
+	pr_debug("       version: %u\n", le32_to_cpu(sb->version));
 	pr_debug("          uuid: %08x.%08x.%08x.%08x\n",
 		 le32_to_cpu(*(__le32 *)(sb->uuid+0)),
 		 le32_to_cpu(*(__le32 *)(sb->uuid+4)),
@@ -500,11 +493,11 @@
 	pr_debug("events cleared: %llu\n",
 		 (unsigned long long) le64_to_cpu(sb->events_cleared));
 	pr_debug("         state: %08x\n", le32_to_cpu(sb->state));
-	pr_debug("     chunksize: %d B\n", le32_to_cpu(sb->chunksize));
-	pr_debug("  daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
+	pr_debug("     chunksize: %u B\n", le32_to_cpu(sb->chunksize));
+	pr_debug("  daemon sleep: %us\n", le32_to_cpu(sb->daemon_sleep));
 	pr_debug("     sync size: %llu KB\n",
 		 (unsigned long long)le64_to_cpu(sb->sync_size)/2);
-	pr_debug("max write behind: %d\n", le32_to_cpu(sb->write_behind));
+	pr_debug("max write behind: %u\n", le32_to_cpu(sb->write_behind));
 	kunmap_atomic(sb);
 }
 
@@ -642,14 +635,6 @@
 	daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
 	write_behind = le32_to_cpu(sb->write_behind);
 	sectors_reserved = le32_to_cpu(sb->sectors_reserved);
-	/* Setup nodes/clustername only if bitmap version is
-	 * cluster-compatible
-	 */
-	if (sb->version == cpu_to_le32(BITMAP_MAJOR_CLUSTERED)) {
-		nodes = le32_to_cpu(sb->nodes);
-		strlcpy(bitmap->mddev->bitmap_info.cluster_name,
-				sb->cluster_name, 64);
-	}
 
 	/* verify that the bitmap-specific fields are valid */
 	if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -671,6 +656,16 @@
 		goto out;
 	}
 
+	/*
+	 * Setup nodes/clustername only if bitmap version is
+	 * cluster-compatible
+	 */
+	if (sb->version == cpu_to_le32(BITMAP_MAJOR_CLUSTERED)) {
+		nodes = le32_to_cpu(sb->nodes);
+		strlcpy(bitmap->mddev->bitmap_info.cluster_name,
+				sb->cluster_name, 64);
+	}
+
 	/* keep the array size field of the bitmap superblock up to date */
 	sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
 
@@ -703,9 +698,9 @@
 
 out:
 	kunmap_atomic(sb);
-	/* Assigning chunksize is required for "re_read" */
-	bitmap->mddev->bitmap_info.chunksize = chunksize;
 	if (err == 0 && nodes && (bitmap->cluster_slot < 0)) {
+		/* Assigning chunksize is required for "re_read" */
+		bitmap->mddev->bitmap_info.chunksize = chunksize;
 		err = md_setup_cluster(bitmap->mddev, nodes);
 		if (err) {
 			pr_warn("%s: Could not setup cluster service (%d)\n",
@@ -716,18 +711,18 @@
 		goto re_read;
 	}
 
-
 out_no_sb:
-	if (test_bit(BITMAP_STALE, &bitmap->flags))
-		bitmap->events_cleared = bitmap->mddev->events;
-	bitmap->mddev->bitmap_info.chunksize = chunksize;
-	bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
-	bitmap->mddev->bitmap_info.max_write_behind = write_behind;
-	bitmap->mddev->bitmap_info.nodes = nodes;
-	if (bitmap->mddev->bitmap_info.space == 0 ||
-	    bitmap->mddev->bitmap_info.space > sectors_reserved)
-		bitmap->mddev->bitmap_info.space = sectors_reserved;
-	if (err) {
+	if (err == 0) {
+		if (test_bit(BITMAP_STALE, &bitmap->flags))
+			bitmap->events_cleared = bitmap->mddev->events;
+		bitmap->mddev->bitmap_info.chunksize = chunksize;
+		bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+		bitmap->mddev->bitmap_info.max_write_behind = write_behind;
+		bitmap->mddev->bitmap_info.nodes = nodes;
+		if (bitmap->mddev->bitmap_info.space == 0 ||
+			bitmap->mddev->bitmap_info.space > sectors_reserved)
+			bitmap->mddev->bitmap_info.space = sectors_reserved;
+	} else {
 		md_bitmap_print_sb(bitmap);
 		if (bitmap->cluster_slot < 0)
 			md_cluster_stop(bitmap->mddev);
@@ -1367,12 +1362,20 @@
 	sector_t csize;
 	int err;
 
+	if (page >= bitmap->pages) {
+		/*
+		 * This can happen if bitmap_start_sync goes beyond
+		 * End-of-device while looking for a whole page or
+		 * user set a huge number to sysfs bitmap_set_bits.
+		 */
+		return NULL;
+	}
 	err = md_bitmap_checkpage(bitmap, page, create, 0);
 
 	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));
@@ -1726,6 +1729,8 @@
 	md_bitmap_daemon_work(mddev);
 	bitmap->daemon_lastrun -= sleep;
 	md_bitmap_daemon_work(mddev);
+	if (mddev->bitmap_info.external)
+		md_super_wait(mddev);
 	md_bitmap_update_sb(bitmap);
 }
 
@@ -1954,6 +1959,7 @@
 }
 EXPORT_SYMBOL_GPL(md_bitmap_load);
 
+/* caller need to free returned bitmap with md_bitmap_free() */
 struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot)
 {
 	int rv = 0;
@@ -2017,6 +2023,7 @@
 	md_bitmap_unplug(mddev->bitmap);
 	*low = lo;
 	*high = hi;
+	md_bitmap_free(bitmap);
 
 	return rv;
 }
@@ -2104,7 +2111,8 @@
 			bytes = DIV_ROUND_UP(chunks, 8);
 			if (!bitmap->mddev->bitmap_info.external)
 				bytes += sizeof(bitmap_super_t);
-		} while (bytes > (space << 9));
+		} while (bytes > (space << 9) && (chunkshift + BITMAP_BLOCK_SHIFT) <
+			(BITS_PER_BYTE * sizeof(((bitmap_super_t *)0)->chunksize) - 1));
 	} else
 		chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
 
@@ -2139,6 +2147,7 @@
 		memcpy(page_address(store.sb_page),
 		       page_address(bitmap->storage.sb_page),
 		       sizeof(bitmap_super_t));
+	spin_lock_irq(&bitmap->counts.lock);
 	md_bitmap_file_unmap(&bitmap->storage);
 	bitmap->storage = store;
 
@@ -2148,13 +2157,12 @@
 	bitmap->counts.missing_pages = pages;
 	bitmap->counts.chunkshift = chunkshift;
 	bitmap->counts.chunks = chunks;
-	bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
+	bitmap->mddev->bitmap_info.chunksize = 1UL << (chunkshift +
 						     BITMAP_BLOCK_SHIFT);
 
 	blocks = min(old_counts.chunks << old_counts.chunkshift,
 		     chunks << chunkshift);
 
-	spin_lock_irq(&bitmap->counts.lock);
 	/* For cluster raid, need to pre-allocate bitmap */
 	if (mddev_is_clustered(bitmap->mddev)) {
 		unsigned long page;
@@ -2175,8 +2183,8 @@
 				bitmap->counts.missing_pages = old_counts.pages;
 				bitmap->counts.chunkshift = old_counts.chunkshift;
 				bitmap->counts.chunks = old_counts.chunks;
-				bitmap->mddev->bitmap_info.chunksize = 1 << (old_counts.chunkshift +
-									     BITMAP_BLOCK_SHIFT);
+				bitmap->mddev->bitmap_info.chunksize =
+					1UL << (old_counts.chunkshift + BITMAP_BLOCK_SHIFT);
 				blocks = old_counts.chunks << old_counts.chunkshift;
 				pr_warn("Could not pre-allocate in-memory bitmap for cluster raid\n");
 				break;
@@ -2194,20 +2202,23 @@
 
 		if (set) {
 			bmc_new = md_bitmap_get_counter(&bitmap->counts, block, &new_blocks, 1);
-			if (*bmc_new == 0) {
-				/* need to set on-disk bits too. */
-				sector_t end = block + new_blocks;
-				sector_t start = block >> chunkshift;
-				start <<= chunkshift;
-				while (start < end) {
-					md_bitmap_file_set_bit(bitmap, block);
-					start += 1 << chunkshift;
+			if (bmc_new) {
+				if (*bmc_new == 0) {
+					/* need to set on-disk bits too. */
+					sector_t end = block + new_blocks;
+					sector_t start = block >> chunkshift;
+
+					start <<= chunkshift;
+					while (start < end) {
+						md_bitmap_file_set_bit(bitmap, block);
+						start += 1 << chunkshift;
+					}
+					*bmc_new = 2;
+					md_bitmap_count_page(&bitmap->counts, block, 1);
+					md_bitmap_set_pending(&bitmap->counts, block);
 				}
-				*bmc_new = 2;
-				md_bitmap_count_page(&bitmap->counts, block, 1);
-				md_bitmap_set_pending(&bitmap->counts, block);
+				*bmc_new |= NEEDED_MASK;
 			}
-			*bmc_new |= NEEDED_MASK;
 			if (new_blocks < old_blocks)
 				old_blocks = new_blocks;
 		}
@@ -2469,11 +2480,35 @@
 {
 	unsigned long backlog;
 	unsigned long old_mwb = mddev->bitmap_info.max_write_behind;
+	struct md_rdev *rdev;
+	bool has_write_mostly = false;
 	int rv = kstrtoul(buf, 10, &backlog);
 	if (rv)
 		return rv;
 	if (backlog > COUNTER_MAX)
 		return -EINVAL;
+
+	rv = mddev_lock(mddev);
+	if (rv)
+		return rv;
+
+	/*
+	 * Without write mostly device, it doesn't make sense to set
+	 * backlog for max_write_behind.
+	 */
+	rdev_for_each(rdev, mddev) {
+		if (test_bit(WriteMostly, &rdev->flags)) {
+			has_write_mostly = true;
+			break;
+		}
+	}
+	if (!has_write_mostly) {
+		pr_warn_ratelimited("%s: can't set backlog, no write mostly device available\n",
+				    mdname(mddev));
+		mddev_unlock(mddev);
+		return -EINVAL;
+	}
+
 	mddev->bitmap_info.max_write_behind = backlog;
 	if (!backlog && mddev->wb_info_pool) {
 		/* wb_info_pool is not needed if backlog is zero */
@@ -2488,6 +2523,8 @@
 	}
 	if (old_mwb != backlog)
 		md_bitmap_update_sb(mddev->bitmap);
+
+	mddev_unlock(mddev);
 	return len;
 }
 
@@ -2514,6 +2551,9 @@
 	if (csize < 512 ||
 	    !is_power_of_2(csize))
 		return -EINVAL;
+	if (BITS_PER_LONG > 32 && csize >= (1ULL << (BITS_PER_BYTE *
+		sizeof(((bitmap_super_t *)0)->chunksize))))
+		return -EOVERFLOW;
 	mddev->bitmap_info.chunksize = csize;
 	return len;
 }
@@ -2620,4 +2660,3 @@
 	.name = "bitmap",
 	.attrs = md_bitmap_attrs,
 };
-
--- linux-ein-5.4.0.orig/drivers/md/md-cluster.c
+++ linux-ein-5.4.0/drivers/md/md-cluster.c
@@ -664,9 +664,27 @@
  * Takes the lock on the TOKEN lock resource so no other
  * node can communicate while the operation is underway.
  */
-static int lock_token(struct md_cluster_info *cinfo, bool mddev_locked)
+static int lock_token(struct md_cluster_info *cinfo)
 {
-	int error, set_bit = 0;
+	int error;
+
+	error = dlm_lock_sync(cinfo->token_lockres, DLM_LOCK_EX);
+	if (error) {
+		pr_err("md-cluster(%s:%d): failed to get EX on TOKEN (%d)\n",
+				__func__, __LINE__, error);
+	} else {
+		/* Lock the receive sequence */
+		mutex_lock(&cinfo->recv_mutex);
+	}
+	return error;
+}
+
+/* lock_comm()
+ * Sets the MD_CLUSTER_SEND_LOCK bit to lock the send channel.
+ */
+static int lock_comm(struct md_cluster_info *cinfo, bool mddev_locked)
+{
+	int rv, set_bit = 0;
 	struct mddev *mddev = cinfo->mddev;
 
 	/*
@@ -677,34 +695,19 @@
 	 */
 	if (mddev_locked && !test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD,
 				      &cinfo->state)) {
-		error = test_and_set_bit_lock(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD,
+		rv = test_and_set_bit_lock(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD,
 					      &cinfo->state);
-		WARN_ON_ONCE(error);
+		WARN_ON_ONCE(rv);
 		md_wakeup_thread(mddev->thread);
 		set_bit = 1;
 	}
-	error = dlm_lock_sync(cinfo->token_lockres, DLM_LOCK_EX);
-	if (set_bit)
-		clear_bit_unlock(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
 
-	if (error)
-		pr_err("md-cluster(%s:%d): failed to get EX on TOKEN (%d)\n",
-				__func__, __LINE__, error);
-
-	/* Lock the receive sequence */
-	mutex_lock(&cinfo->recv_mutex);
-	return error;
-}
-
-/* lock_comm()
- * Sets the MD_CLUSTER_SEND_LOCK bit to lock the send channel.
- */
-static int lock_comm(struct md_cluster_info *cinfo, bool mddev_locked)
-{
 	wait_event(cinfo->wait,
 		   !test_and_set_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state));
-
-	return lock_token(cinfo, mddev_locked);
+	rv = lock_token(cinfo);
+	if (set_bit)
+		clear_bit_unlock(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
+	return rv;
 }
 
 static void unlock_comm(struct md_cluster_info *cinfo)
@@ -784,9 +787,11 @@
 {
 	int ret;
 
-	lock_comm(cinfo, mddev_locked);
-	ret = __sendmsg(cinfo, cmsg);
-	unlock_comm(cinfo);
+	ret = lock_comm(cinfo, mddev_locked);
+	if (!ret) {
+		ret = __sendmsg(cinfo, cmsg);
+		unlock_comm(cinfo);
+	}
 	return ret;
 }
 
@@ -1061,7 +1066,7 @@
 		return 0;
 	}
 
-	ret = lock_token(cinfo, 1);
+	ret = lock_token(cinfo);
 	clear_bit_unlock(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
 	return ret;
 }
@@ -1139,6 +1144,7 @@
 		bitmap = get_bitmap_from_slot(mddev, i);
 		if (IS_ERR(bitmap)) {
 			pr_err("can't get bitmap from slot %d\n", i);
+			bitmap = NULL;
 			goto out;
 		}
 		counts = &bitmap->counts;
@@ -1165,6 +1171,7 @@
 			 * can't resize bitmap
 			 */
 			goto out;
+		md_bitmap_free(bitmap);
 	}
 
 	return 0;
@@ -1253,7 +1260,10 @@
 	int raid_slot = -1;
 
 	md_update_sb(mddev, 1);
-	lock_comm(cinfo, 1);
+	if (lock_comm(cinfo, 1)) {
+		pr_err("%s: lock_comm failed\n", __func__);
+		return;
+	}
 
 	memset(&cmsg, 0, sizeof(cmsg));
 	cmsg.type = cpu_to_le32(METADATA_UPDATED);
@@ -1405,7 +1415,8 @@
 	cmsg.type = cpu_to_le32(NEWDISK);
 	memcpy(cmsg.uuid, uuid, 16);
 	cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
-	lock_comm(cinfo, 1);
+	if (lock_comm(cinfo, 1))
+		return -EAGAIN;
 	ret = __sendmsg(cinfo, &cmsg);
 	if (ret) {
 		unlock_comm(cinfo);
@@ -1518,6 +1529,7 @@
 			}
 		}
 		kfree(cinfo->other_bitmap_lockres);
+		cinfo->other_bitmap_lockres = NULL;
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/md/md-linear.c
+++ linux-ein-5.4.0/drivers/md/md-linear.c
@@ -244,10 +244,9 @@
 	sector_t start_sector, end_sector, data_offset;
 	sector_t bio_sector = bio->bi_iter.bi_sector;
 
-	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-		md_flush_request(mddev, bio);
+	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+	    && md_flush_request(mddev, bio))
 		return true;
-	}
 
 	tmp_dev = which_dev(mddev, bio_sector);
 	start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors;
--- linux-ein-5.4.0.orig/drivers/md/md-multipath.c
+++ linux-ein-5.4.0/drivers/md/md-multipath.c
@@ -104,10 +104,9 @@
 	struct multipath_bh * mp_bh;
 	struct multipath_info *multipath;
 
-	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-		md_flush_request(mddev, bio);
+	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+	    && md_flush_request(mddev, bio))
 		return true;
-	}
 
 	mp_bh = mempool_alloc(&conf->pool, GFP_NOIO);
 
--- linux-ein-5.4.0.orig/drivers/md/md.c
+++ linux-ein-5.4.0/drivers/md/md.c
@@ -376,17 +376,18 @@
 	struct mddev *mddev = q->queuedata;
 	unsigned int sectors;
 
-	if (unlikely(test_bit(MD_BROKEN, &mddev->flags)) && (rw == WRITE)) {
+	if (mddev == NULL || mddev->pers == NULL) {
 		bio_io_error(bio);
 		return BLK_QC_T_NONE;
 	}
 
-	blk_queue_split(q, &bio);
-
-	if (mddev == NULL || mddev->pers == NULL) {
+	if (unlikely(test_bit(MD_BROKEN, &mddev->flags)) && (rw == WRITE)) {
 		bio_io_error(bio);
 		return BLK_QC_T_NONE;
 	}
+
+	blk_queue_split(q, &bio);
+
 	if (mddev->ro == 1 && unlikely(rw == WRITE)) {
 		if (bio_sectors(bio) != 0)
 			bio->bi_status = BLK_STS_IOERR;
@@ -480,13 +481,14 @@
 	struct md_rdev *rdev = bio->bi_private;
 	struct mddev *mddev = rdev->mddev;
 
+	bio_put(bio);
+
 	rdev_dec_pending(rdev, mddev);
 
 	if (atomic_dec_and_test(&mddev->flush_pending)) {
 		/* The pre-request flush has finished */
 		queue_work(md_wq, &mddev->flush_work);
 	}
-	bio_put(bio);
 }
 
 static void md_submit_flush_data(struct work_struct *ws);
@@ -537,8 +539,10 @@
 	 * could wait for this and below md_handle_request could wait for those
 	 * bios because of suspend check
 	 */
+	spin_lock_irq(&mddev->lock);
 	mddev->last_flush = mddev->start_flush;
 	mddev->flush_bio = NULL;
+	spin_unlock_irq(&mddev->lock);
 	wake_up(&mddev->sb_wait);
 
 	if (bio->bi_iter.bi_size == 0) {
@@ -550,7 +554,13 @@
 	}
 }
 
-void md_flush_request(struct mddev *mddev, struct bio *bio)
+/*
+ * Manages consolidation of flushes and submitting any flushes needed for
+ * a bio with REQ_PREFLUSH.  Returns true if the bio is finished or is
+ * being finished in another context.  Returns false if the flushing is
+ * complete but still needs the I/O portion of the bio to be processed.
+ */
+bool md_flush_request(struct mddev *mddev, struct bio *bio)
 {
 	ktime_t start = ktime_get_boottime();
 	spin_lock_irq(&mddev->lock);
@@ -575,9 +585,10 @@
 			bio_endio(bio);
 		else {
 			bio->bi_opf &= ~REQ_PREFLUSH;
-			mddev->pers->make_request(mddev, bio);
+			return false;
 		}
 	}
+	return true;
 }
 EXPORT_SYMBOL(md_flush_request);
 
@@ -637,8 +648,35 @@
 }
 EXPORT_SYMBOL_GPL(mddev_init);
 
+static struct mddev *mddev_find_locked(dev_t unit)
+{
+	struct mddev *mddev;
+
+	list_for_each_entry(mddev, &all_mddevs, all_mddevs)
+		if (mddev->unit == unit)
+			return mddev;
+
+	return NULL;
+}
+
 static struct mddev *mddev_find(dev_t unit)
 {
+	struct mddev *mddev;
+
+	if (MAJOR(unit) != MD_MAJOR)
+		unit &= ~((1 << MdpMinorShift) - 1);
+
+	spin_lock(&all_mddevs_lock);
+	mddev = mddev_find_locked(unit);
+	if (mddev)
+		mddev_get(mddev);
+	spin_unlock(&all_mddevs_lock);
+
+	return mddev;
+}
+
+static struct mddev *mddev_find_or_alloc(dev_t unit)
+{
 	struct mddev *mddev, *new = NULL;
 
 	if (unit && MAJOR(unit) != MD_MAJOR)
@@ -648,13 +686,13 @@
 	spin_lock(&all_mddevs_lock);
 
 	if (unit) {
-		list_for_each_entry(mddev, &all_mddevs, all_mddevs)
-			if (mddev->unit == unit) {
-				mddev_get(mddev);
-				spin_unlock(&all_mddevs_lock);
-				kfree(new);
-				return mddev;
-			}
+		mddev = mddev_find_locked(unit);
+		if (mddev) {
+			mddev_get(mddev);
+			spin_unlock(&all_mddevs_lock);
+			kfree(new);
+			return mddev;
+		}
 
 		if (new) {
 			list_add(&new->all_mddevs, &all_mddevs);
@@ -680,12 +718,7 @@
 				return NULL;
 			}
 
-			is_free = 1;
-			list_for_each_entry(mddev, &all_mddevs, all_mddevs)
-				if (mddev->unit == dev) {
-					is_free = 0;
-					break;
-				}
+			is_free = !mddev_find_locked(dev);
 		}
 		new->unit = dev;
 		new->md_minor = MINOR(dev);
@@ -853,10 +886,12 @@
 	} else
 		clear_bit(LastDev, &rdev->flags);
 
+	bio_put(bio);
+
+	rdev_dec_pending(rdev, mddev);
+
 	if (atomic_dec_and_test(&mddev->pending_writes))
 		wake_up(&mddev->sb_wait);
-	rdev_dec_pending(rdev, mddev);
-	bio_put(bio);
 }
 
 void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
@@ -1063,6 +1098,7 @@
 					  struct md_rdev *refdev,
 					  int minor_version);
 	int		    (*validate_super)(struct mddev *mddev,
+					      struct md_rdev *freshest,
 					      struct md_rdev *rdev);
 	void		    (*sync_super)(struct mddev *mddev,
 					  struct md_rdev *rdev);
@@ -1098,6 +1134,7 @@
 	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 	mdp_super_t *sb;
 	int ret;
+	bool spare_disk = true;
 
 	/*
 	 * Calculate the position of the superblock (512byte sectors),
@@ -1148,8 +1185,19 @@
 	else
 		rdev->desc_nr = sb->this_disk.number;
 
+	/* not spare disk, or LEVEL_MULTIPATH */
+	if (sb->level == LEVEL_MULTIPATH ||
+		(rdev->desc_nr >= 0 &&
+		 rdev->desc_nr < MD_SB_DISKS &&
+		 sb->disks[rdev->desc_nr].state &
+		 ((1<<MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE))))
+		spare_disk = false;
+
 	if (!refdev) {
-		ret = 1;
+		if (!spare_disk)
+			ret = 1;
+		else
+			ret = 0;
 	} else {
 		__u64 ev1, ev2;
 		mdp_super_t *refsb = page_address(refdev->sb_page);
@@ -1165,7 +1213,8 @@
 		}
 		ev1 = md_event(sb);
 		ev2 = md_event(refsb);
-		if (ev1 > ev2)
+
+		if (!spare_disk && ev1 > ev2)
 			ret = 1;
 		else
 			ret = 0;
@@ -1188,8 +1237,9 @@
 
 /*
  * validate_super for 0.90.0
+ * note: we are not using "freshest" for 0.9 superblock
  */
-static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
+static int super_90_validate(struct mddev *mddev, struct md_rdev *freshest, struct md_rdev *rdev)
 {
 	mdp_disk_t *desc;
 	mdp_super_t *sb = page_address(rdev->sb_page);
@@ -1525,6 +1575,7 @@
 	sector_t sectors;
 	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 	int bmask;
+	bool spare_disk = true;
 
 	/*
 	 * Calculate the position of the superblock in 512byte sectors.
@@ -1658,8 +1709,19 @@
 	    sb->level != 0)
 		return -EINVAL;
 
+	/* not spare disk, or LEVEL_MULTIPATH */
+	if (sb->level == cpu_to_le32(LEVEL_MULTIPATH) ||
+		(rdev->desc_nr >= 0 &&
+		rdev->desc_nr < le32_to_cpu(sb->max_dev) &&
+		(le16_to_cpu(sb->dev_roles[rdev->desc_nr]) < MD_DISK_ROLE_MAX ||
+		 le16_to_cpu(sb->dev_roles[rdev->desc_nr]) == MD_DISK_ROLE_JOURNAL)))
+		spare_disk = false;
+
 	if (!refdev) {
-		ret = 1;
+		if (!spare_disk)
+			ret = 1;
+		else
+			ret = 0;
 	} else {
 		__u64 ev1, ev2;
 		struct mdp_superblock_1 *refsb = page_address(refdev->sb_page);
@@ -1676,7 +1738,7 @@
 		ev1 = le64_to_cpu(sb->events);
 		ev2 = le64_to_cpu(refsb->events);
 
-		if (ev1 > ev2)
+		if (!spare_disk && ev1 > ev2)
 			ret = 1;
 		else
 			ret = 0;
@@ -1692,7 +1754,7 @@
 	return ret;
 }
 
-static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
+static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struct md_rdev *rdev)
 {
 	struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
 	__u64 ev1 = le64_to_cpu(sb->events);
@@ -1788,13 +1850,15 @@
 		}
 	} else if (mddev->pers == NULL) {
 		/* Insist of good event counter while assembling, except for
-		 * spares (which don't need an event count) */
-		++ev1;
+		 * spares (which don't need an event count).
+		 * Similar to mdadm, we allow event counter difference of 1
+		 * from the freshest device.
+		 */
 		if (rdev->desc_nr >= 0 &&
 		    rdev->desc_nr < le32_to_cpu(sb->max_dev) &&
 		    (le16_to_cpu(sb->dev_roles[rdev->desc_nr]) < MD_DISK_ROLE_MAX ||
 		     le16_to_cpu(sb->dev_roles[rdev->desc_nr]) == MD_DISK_ROLE_JOURNAL))
-			if (ev1 < mddev->events)
+			if (ev1 + 1 < mddev->events)
 				return -EINVAL;
 	} else if (mddev->bitmap) {
 		/* If adding to array with a bitmap, then we can accept an
@@ -1815,8 +1879,38 @@
 		    rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
 			role = MD_DISK_ROLE_SPARE;
 			rdev->desc_nr = -1;
-		} else
+		} else if (mddev->pers == NULL && freshest && ev1 < mddev->events) {
+			/*
+			 * If we are assembling, and our event counter is smaller than the
+			 * highest event counter, we cannot trust our superblock about the role.
+			 * It could happen that our rdev was marked as Faulty, and all other
+			 * superblocks were updated with +1 event counter.
+			 * Then, before the next superblock update, which typically happens when
+			 * remove_and_add_spares() removes the device from the array, there was
+			 * a crash or reboot.
+			 * If we allow current rdev without consulting the freshest superblock,
+			 * we could cause data corruption.
+			 * Note that in this case our event counter is smaller by 1 than the
+			 * highest, otherwise, this rdev would not be allowed into array;
+			 * both kernel and mdadm allow event counter difference of 1.
+			 */
+			struct mdp_superblock_1 *freshest_sb = page_address(freshest->sb_page);
+			u32 freshest_max_dev = le32_to_cpu(freshest_sb->max_dev);
+
+			if (rdev->desc_nr >= freshest_max_dev) {
+				/* this is unexpected, better not proceed */
+				pr_warn("md: %s: rdev[%pg]: desc_nr(%d) >= freshest(%pg)->sb->max_dev(%u)\n",
+						mdname(mddev), rdev->bdev, rdev->desc_nr,
+						freshest->bdev, freshest_max_dev);
+				return -EUCLEAN;
+			}
+
+			role = le16_to_cpu(freshest_sb->dev_roles[rdev->desc_nr]);
+			pr_debug("md: %s: rdev[%pg]: role=%d(0x%x) according to freshest %pg\n",
+				     mdname(mddev), rdev->bdev, role, role, freshest->bdev);
+		} else {
 			role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
+		}
 		switch(role) {
 		case MD_DISK_ROLE_SPARE: /* spare */
 			break;
@@ -2475,14 +2569,16 @@
 
 static bool does_sb_need_changing(struct mddev *mddev)
 {
-	struct md_rdev *rdev;
+	struct md_rdev *rdev = NULL, *iter;
 	struct mdp_superblock_1 *sb;
 	int role;
 
 	/* Find a good rdev */
-	rdev_for_each(rdev, mddev)
-		if ((rdev->raid_disk >= 0) && !test_bit(Faulty, &rdev->flags))
+	rdev_for_each(iter, mddev)
+		if ((iter->raid_disk >= 0) && !test_bit(Faulty, &iter->flags)) {
+			rdev = iter;
 			break;
+		}
 
 	/* No good device found. */
 	if (!rdev)
@@ -2718,7 +2814,7 @@
 		 * and should be added immediately.
 		 */
 		super_types[mddev->major_version].
-			validate_super(mddev, rdev);
+			validate_super(mddev, NULL/*freshest*/, rdev);
 		if (add_journal)
 			mddev_suspend(mddev);
 		err = mddev->pers->hot_add_disk(mddev, rdev);
@@ -3020,6 +3116,9 @@
 		err = kstrtouint(buf, 10, (unsigned int *)&slot);
 		if (err < 0)
 			return err;
+		if (slot < 0)
+			/* overflow */
+			return -ENOSPC;
 	}
 	if (rdev->mddev->pers && slot == -1) {
 		/* Setting 'slot' on an active array requires also
@@ -3597,7 +3696,7 @@
  * Check a full RAID array for plausibility
  */
 
-static void analyze_sbs(struct mddev *mddev)
+static int analyze_sbs(struct mddev *mddev)
 {
 	int i;
 	struct md_rdev *rdev, *freshest, *tmp;
@@ -3618,8 +3717,14 @@
 			md_kick_rdev_from_array(rdev);
 		}
 
+	/* Cannot find a valid fresh disk */
+	if (!freshest) {
+		pr_warn("md: cannot find a valid disk\n");
+		return -EINVAL;
+	}
+
 	super_types[mddev->major_version].
-		validate_super(mddev, freshest);
+		validate_super(mddev, NULL/*freshest*/, freshest);
 
 	i = 0;
 	rdev_for_each_safe(rdev, tmp, mddev) {
@@ -3634,7 +3739,7 @@
 		}
 		if (rdev != freshest) {
 			if (super_types[mddev->major_version].
-			    validate_super(mddev, rdev)) {
+			    validate_super(mddev, freshest, rdev)) {
 				pr_warn("md: kicking non-fresh %s from array!\n",
 					bdevname(rdev->bdev,b));
 				md_kick_rdev_from_array(rdev);
@@ -3652,6 +3757,8 @@
 			clear_bit(In_sync, &rdev->flags);
 		}
 	}
+
+	return 0;
 }
 
 /* Read a fixed-point number.
@@ -3693,8 +3800,9 @@
 static ssize_t
 safe_delay_show(struct mddev *mddev, char *page)
 {
-	int msec = (mddev->safemode_delay*1000)/HZ;
-	return sprintf(page, "%d.%03d\n", msec/1000, msec%1000);
+	unsigned int msec = ((unsigned long)mddev->safemode_delay*1000)/HZ;
+
+	return sprintf(page, "%u.%03u\n", msec/1000, msec%1000);
 }
 static ssize_t
 safe_delay_store(struct mddev *mddev, const char *cbuf, size_t len)
@@ -3706,7 +3814,7 @@
 		return -EINVAL;
 	}
 
-	if (strict_strtoul_scaled(cbuf, &msec, 3) < 0)
+	if (strict_strtoul_scaled(cbuf, &msec, 3) < 0 || msec > UINT_MAX / HZ)
 		return -EINVAL;
 	if (msec == 0)
 		mddev->safemode_delay = 0;
@@ -4367,6 +4475,8 @@
 	rv = kstrtouint(buf, 10, &n);
 	if (rv < 0)
 		return rv;
+	if (n > INT_MAX)
+		return -EINVAL;
 	atomic_set(&mddev->max_corr_read_errors, n);
 	return len;
 }
@@ -4667,11 +4777,21 @@
 			return -EINVAL;
 		err = mddev_lock(mddev);
 		if (!err) {
-			if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+			if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
 				err =  -EBUSY;
-			else {
+			} else if (mddev->reshape_position == MaxSector ||
+				   mddev->pers->check_reshape == NULL ||
+				   mddev->pers->check_reshape(mddev)) {
 				clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 				err = mddev->pers->start_reshape(mddev);
+			} else {
+				/*
+				 * If reshape is still in progress, and
+				 * md_check_recovery() can continue to reshape,
+				 * don't restart reshape because data can be
+				 * corrupted for raid456.
+				 */
+				clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 			}
 			mddev_unlock(mddev);
 		}
@@ -5393,7 +5513,7 @@
 	 * writing to /sys/module/md_mod/parameters/new_array.
 	 */
 	static DEFINE_MUTEX(disks_mutex);
-	struct mddev *mddev = mddev_find(dev);
+	struct mddev *mddev = mddev_find_or_alloc(dev);
 	struct gendisk *disk;
 	int partitioned;
 	int shift;
@@ -5470,10 +5590,6 @@
 	 */
 	disk->flags |= GENHD_FL_EXT_DEVT;
 	mddev->gendisk = disk;
-	/* As soon as we call add_disk(), another thread could get
-	 * through to md_open, so make sure it doesn't get too far
-	 */
-	mutex_lock(&mddev->open_mutex);
 	add_disk(disk);
 
 	error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
@@ -5488,7 +5604,6 @@
 	if (mddev->kobj.sd &&
 	    sysfs_create_group(&mddev->kobj, &md_bitmap_group))
 		pr_debug("pointless warning\n");
-	mutex_unlock(&mddev->open_mutex);
  abort:
 	mutex_unlock(&disks_mutex);
 	if (!error && mddev->kobj.sd) {
@@ -5570,7 +5685,9 @@
 	if (!mddev->raid_disks) {
 		if (!mddev->persistent)
 			return -EINVAL;
-		analyze_sbs(mddev);
+		err = analyze_sbs(mddev);
+		if (err)
+			return -EINVAL;
 	}
 
 	if (mddev->level != LEVEL_NONE)
@@ -5998,7 +6115,7 @@
 static void mddev_detach(struct mddev *mddev)
 {
 	md_bitmap_wait_behind_writes(mddev);
-	if (mddev->pers && mddev->pers->quiesce) {
+	if (mddev->pers && mddev->pers->quiesce && !mddev->suspended) {
 		mddev->pers->quiesce(mddev, 1);
 		mddev->pers->quiesce(mddev, 0);
 	}
@@ -6030,6 +6147,7 @@
 	/* stop the array and free an attached data structures.
 	 * This is called from dm-raid
 	 */
+	__md_stop_writes(mddev);
 	__md_stop(mddev);
 	bioset_exit(&mddev->bio_set);
 	bioset_exit(&mddev->sync_set);
@@ -6267,11 +6385,9 @@
 
 		md_probe(dev, NULL, NULL);
 		mddev = mddev_find(dev);
-		if (!mddev || !mddev->gendisk) {
-			if (mddev)
-				mddev_put(mddev);
+		if (!mddev)
 			break;
-		}
+
 		if (mddev_lock(mddev))
 			pr_warn("md: %s locked, cannot run\n", mdname(mddev));
 		else if (mddev->raid_disks || mddev->major_version
@@ -6528,7 +6644,7 @@
 			rdev->saved_raid_disk = rdev->raid_disk;
 		} else
 			super_types[mddev->major_version].
-				validate_super(mddev, rdev);
+				validate_super(mddev, NULL/*freshest*/, rdev);
 		if ((info->state & (1<<MD_DISK_SYNC)) &&
 		     rdev->raid_disk != info->raid_disk) {
 			/* This was a hot-add request, but events doesn't
@@ -6678,8 +6794,10 @@
 		goto busy;
 
 kick_rdev:
-	if (mddev_is_clustered(mddev))
-		md_cluster_ops->remove_disk(mddev, rdev);
+	if (mddev_is_clustered(mddev)) {
+		if (md_cluster_ops->remove_disk(mddev, rdev))
+			goto busy;
+	}
 
 	md_kick_rdev_from_array(rdev);
 	set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
@@ -7009,6 +7127,7 @@
 		return -EINVAL;
 	if (mddev->sync_thread ||
 	    test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+	    test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) ||
 	    mddev->reshape_position != MaxSector)
 		return -EBUSY;
 
@@ -7328,8 +7447,11 @@
 			err = -EBUSY;
 			goto out;
 		}
-		WARN_ON_ONCE(test_bit(MD_CLOSING, &mddev->flags));
-		set_bit(MD_CLOSING, &mddev->flags);
+		if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
+			mutex_unlock(&mddev->open_mutex);
+			err = -EBUSY;
+			goto out;
+		}
 		did_set_md_closing = true;
 		mutex_unlock(&mddev->open_mutex);
 		sync_blockdev(bdev);
@@ -7565,9 +7687,9 @@
 		 */
 		mddev_put(mddev);
 		/* Wait until bdev->bd_disk is definitely gone */
-		flush_workqueue(md_misc_wq);
-		/* Then retry the open from the top */
-		return -ERESTARTSYS;
+		if (work_pending(&mddev->del_work))
+			flush_workqueue(md_misc_wq);
+		return -EBUSY;
 	}
 	BUG_ON(mddev != bdev->bd_disk->private_data);
 
@@ -7709,17 +7831,22 @@
 
 void md_unregister_thread(struct md_thread **threadp)
 {
-	struct md_thread *thread = *threadp;
-	if (!thread)
-		return;
-	pr_debug("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
-	/* Locking ensures that mddev_unlock does not wake_up a
+	struct md_thread *thread;
+
+	/*
+	 * Locking ensures that mddev_unlock does not wake_up a
 	 * non-existent thread
 	 */
 	spin_lock(&pers_lock);
+	thread = *threadp;
+	if (!thread) {
+		spin_unlock(&pers_lock);
+		return;
+	}
 	*threadp = NULL;
 	spin_unlock(&pers_lock);
 
+	pr_debug("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
 	kthread_stop(thread->tsk);
 	kfree(thread);
 }
@@ -7900,7 +8027,11 @@
 	loff_t l = *pos;
 	struct mddev *mddev;
 
-	if (l >= 0x10000)
+	if (l == 0x10000) {
+		++*pos;
+		return (void *)2;
+	}
+	if (l > 0x10000)
 		return NULL;
 	if (!l--)
 		/* header */
@@ -8319,6 +8450,26 @@
 
 EXPORT_SYMBOL(md_write_end);
 
+/* This is used by raid0 and raid10 */
+void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
+			struct bio *bio, sector_t start, sector_t size)
+{
+	struct bio *discard_bio = NULL;
+
+	if (__blkdev_issue_discard(rdev->bdev, start, size, GFP_NOIO, 0,
+			&discard_bio) || !discard_bio)
+		return;
+
+	bio_chain(discard_bio, bio);
+	bio_clone_blkg_association(discard_bio, bio);
+	if (mddev->gendisk)
+		trace_block_bio_remap(bdev_get_queue(rdev->bdev),
+				discard_bio, disk_devt(mddev->gendisk),
+				bio->bi_iter.bi_sector);
+	generic_make_request(discard_bio);
+}
+EXPORT_SYMBOL_GPL(md_submit_discard_bio);
+
 /* md_allow_write(mddev)
  * Calling this ensures that the array is marked 'active' so that writes
  * may proceed without blocking.  It is important to call this before
@@ -8997,11 +9148,11 @@
 		}
 
 		if (mddev_is_clustered(mddev)) {
-			struct md_rdev *rdev;
+			struct md_rdev *rdev, *tmp;
 			/* kick the device if another node issued a
 			 * remove disk.
 			 */
-			rdev_for_each(rdev, mddev) {
+			rdev_for_each_safe(rdev, tmp, mddev) {
 				if (test_and_clear_bit(ClusterRemove, &rdev->flags) &&
 						rdev->raid_disk < 0)
 					md_kick_rdev_from_array(rdev);
@@ -9314,7 +9465,7 @@
 static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
 {
 	struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
-	struct md_rdev *rdev2;
+	struct md_rdev *rdev2, *tmp;
 	int role, ret;
 	char b[BDEVNAME_SIZE];
 
@@ -9331,7 +9482,7 @@
 	}
 
 	/* Check for change of roles in the active devices */
-	rdev_for_each(rdev2, mddev) {
+	rdev_for_each_safe(rdev2, tmp, mddev) {
 		if (test_bit(Faulty, &rdev2->flags))
 			continue;
 
@@ -9376,8 +9527,11 @@
 		}
 	}
 
-	if (mddev->raid_disks != le32_to_cpu(sb->raid_disks))
-		update_raid_disks(mddev, le32_to_cpu(sb->raid_disks));
+	if (mddev->raid_disks != le32_to_cpu(sb->raid_disks)) {
+		ret = update_raid_disks(mddev, le32_to_cpu(sb->raid_disks));
+		if (ret)
+			pr_warn("md: updating array disks failed. %d\n", ret);
+	}
 
 	/*
 	 * Since mddev->delta_disks has already updated in update_raid_disks,
@@ -9456,16 +9610,18 @@
 
 void md_reload_sb(struct mddev *mddev, int nr)
 {
-	struct md_rdev *rdev;
+	struct md_rdev *rdev = NULL, *iter;
 	int err;
 
 	/* Find the rdev */
-	rdev_for_each_rcu(rdev, mddev) {
-		if (rdev->desc_nr == nr)
+	rdev_for_each_rcu(iter, mddev) {
+		if (iter->desc_nr == nr) {
+			rdev = iter;
 			break;
+		}
 	}
 
-	if (!rdev || rdev->desc_nr != nr) {
+	if (!rdev) {
 		pr_warn("%s: %d Could not find rdev with nr %d\n", __func__, __LINE__, nr);
 		return;
 	}
--- linux-ein-5.4.0.orig/drivers/md/md.h
+++ linux-ein-5.4.0/drivers/md/md.h
@@ -550,7 +550,7 @@
 	int level;
 	struct list_head list;
 	struct module *owner;
-	bool (*make_request)(struct mddev *mddev, struct bio *bio);
+	bool __must_check (*make_request)(struct mddev *mddev, struct bio *bio);
 	/*
 	 * start up works that do NOT require md_thread. tasks that
 	 * requires md_thread should go into start()
@@ -701,9 +701,11 @@
 extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
 extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
 extern void md_finish_reshape(struct mddev *mddev);
+void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
+			struct bio *bio, sector_t start, sector_t size);
 
 extern int mddev_congested(struct mddev *mddev, int bits);
-extern void md_flush_request(struct mddev *mddev, struct bio *bio);
+extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
 extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
 			   sector_t sector, int size, struct page *page);
 extern int md_super_wait(struct mddev *mddev);
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-block-manager.c
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-block-manager.c
@@ -493,7 +493,7 @@
 	void *p;
 	int r;
 
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
@@ -562,7 +562,7 @@
 	struct buffer_aux *aux;
 	void *p;
 
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result);
@@ -602,7 +602,7 @@
 
 int dm_bm_flush(struct dm_block_manager *bm)
 {
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	return dm_bufio_write_dirty_buffers(bm->bufio);
@@ -616,19 +616,21 @@
 
 bool dm_bm_is_read_only(struct dm_block_manager *bm)
 {
-	return bm->read_only;
+	return (bm ? bm->read_only : true);
 }
 EXPORT_SYMBOL_GPL(dm_bm_is_read_only);
 
 void dm_bm_set_read_only(struct dm_block_manager *bm)
 {
-	bm->read_only = true;
+	if (bm)
+		bm->read_only = true;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_only);
 
 void dm_bm_set_read_write(struct dm_block_manager *bm)
 {
-	bm->read_only = false;
+	if (bm)
+		bm->read_only = false;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_write);
 
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-btree-internal.h
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-btree-internal.h
@@ -34,12 +34,12 @@
 	__le32 max_entries;
 	__le32 value_size;
 	__le32 padding;
-} __packed;
+} __attribute__((packed, aligned(8)));
 
 struct btree_node {
 	struct node_header header;
 	__le64 keys[0];
-} __packed;
+} __attribute__((packed, aligned(8)));
 
 
 /*
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-btree-remove.c
+++ linux-ein-5.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) {
 		/*
@@ -417,9 +423,9 @@
 
 		memcpy(n, dm_block_data(child),
 		       dm_bm_block_size(dm_tm_get_bm(info->tm)));
-		dm_tm_unlock(info->tm, child);
 
 		dm_tm_dec(info->tm, dm_block_location(child));
+		dm_tm_unlock(info->tm, child);
 		return 0;
 	}
 
@@ -543,7 +549,8 @@
 		delete_at(n, index);
 	}
 
-	*new_root = shadow_root(&spine);
+	if (!r)
+		*new_root = shadow_root(&spine);
 	exit_shadow_spine(&spine);
 
 	return r;
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-btree.c
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-btree.c
@@ -83,14 +83,16 @@
 }
 
 static int insert_at(size_t value_size, struct btree_node *node, unsigned index,
-		      uint64_t key, void *value)
-		      __dm_written_to_disk(value)
+		     uint64_t key, void *value)
+	__dm_written_to_disk(value)
 {
 	uint32_t nr_entries = le32_to_cpu(node->header.nr_entries);
+	uint32_t max_entries = le32_to_cpu(node->header.max_entries);
 	__le64 key_le = cpu_to_le64(key);
 
 	if (index > nr_entries ||
-	    index >= le32_to_cpu(node->header.max_entries)) {
+	    index >= max_entries ||
+	    nr_entries >= max_entries) {
 		DMERR("too many entries in btree node for insert");
 		__dm_unbless_for_disk(value);
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-space-map-common.c
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-space-map-common.c
@@ -281,6 +281,11 @@
 	struct disk_index_entry ie_disk;
 	struct dm_block *blk;
 
+	if (b >= ll->nr_blocks) {
+		DMERR_LIMIT("metadata block out of bounds");
+		return -EINVAL;
+	}
+
 	b = do_div(index, ll->entries_per_block);
 	r = ll->load_ie(ll, index, &ie_disk);
 	if (r < 0)
@@ -339,6 +344,8 @@
 	 */
 	begin = do_div(index_begin, ll->entries_per_block);
 	end = do_div(end, ll->entries_per_block);
+	if (end == 0)
+		end = ll->entries_per_block;
 
 	for (i = index_begin; i < index_end; i++, begin = 0) {
 		struct dm_block *blk;
@@ -380,6 +387,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-ein-5.4.0.orig/drivers/md/persistent-data/dm-space-map-common.h
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-space-map-common.h
@@ -33,7 +33,7 @@
 	__le64 blocknr;
 	__le32 nr_free;
 	__le32 none_free_before;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 
 #define MAX_METADATA_BITMAPS 255
@@ -43,7 +43,7 @@
 	__le64 blocknr;
 
 	struct disk_index_entry index[MAX_METADATA_BITMAPS];
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 struct ll_disk;
 
@@ -86,7 +86,7 @@
 	__le64 nr_allocated;
 	__le64 bitmap_root;
 	__le64 ref_count_root;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 #define ENTRIES_PER_BYTE 4
 
@@ -94,7 +94,7 @@
 	__le32 csum;
 	__le32 not_used;
 	__le64 blocknr;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 enum allocation_event {
 	SM_NONE,
@@ -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-ein-5.4.0.orig/drivers/md/persistent-data/dm-space-map-disk.c
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-space-map-disk.c
@@ -167,8 +167,18 @@
 	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 == -ENOSPC) {
+		/*
+		 * There's no free block between smd->begin and the end of the metadata device.
+		 * We search before smd->begin in case something has been freed.
+		 */
+		r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, 0, smd->begin, b);
+	}
+
 	if (r)
 		return r;
 
@@ -197,7 +207,6 @@
 		return r;
 
 	memcpy(&smd->old_ll, &smd->ll, sizeof(smd->old_ll));
-	smd->begin = 0;
 	smd->nr_allocated_this_transaction = 0;
 
 	r = sm_disk_get_nr_free(sm, &nr_free);
--- linux-ein-5.4.0.orig/drivers/md/persistent-data/dm-space-map-metadata.c
+++ linux-ein-5.4.0/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -448,7 +448,18 @@
 	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 == -ENOSPC) {
+		/*
+		 * There's no free block between smm->begin and the end of the metadata device.
+		 * We search before smm->begin in case something has been freed.
+		 */
+		r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, 0, smm->begin, b);
+	}
+
 	if (r)
 		return r;
 
@@ -500,7 +511,6 @@
 		return r;
 
 	memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
-	smm->begin = 0;
 	smm->allocated_this_transaction = 0;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/md/raid0.c
+++ linux-ein-5.4.0/drivers/md/raid0.c
@@ -63,7 +63,7 @@
 		int len = 0;
 
 		for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
-			len += snprintf(line+len, 200-len, "%s%s", k?"/":"",
+			len += scnprintf(line+len, 200-len, "%s%s", k?"/":"",
 					bdevname(conf->devlist[j*raid_disks
 							       + k]->bdev, b));
 		pr_debug("md: zone%d=[%s]\n", j, line);
@@ -87,7 +87,7 @@
 	char b[BDEVNAME_SIZE];
 	char b2[BDEVNAME_SIZE];
 	struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
-	unsigned short blksize = 512;
+	unsigned blksize = 512;
 
 	*private_conf = ERR_PTR(-ENOMEM);
 	if (!conf)
@@ -143,21 +143,6 @@
 	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 {
-		pr_err("md/raid0:%s: cannot assemble multi-zone RAID0 with default_layout setting\n",
-		       mdname(mddev));
-		pr_err("md/raid0: please set raid0.default_layout to 1 or 2\n");
-		err = -ENOTSUPP;
-		goto abort;
-	}
 	/*
 	 * now since we have the hard sector sizes, we can make sure
 	 * chunk size is a multiple of that sector size
@@ -288,6 +273,36 @@
 			 (unsigned long long)smallest->sectors);
 	}
 
+	if (conf->nr_strip_zones == 1 || conf->strip_zone[1].nb_dev == 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 {
+		pr_err("md/raid0:%s: cannot assemble multi-zone RAID0 with default_layout setting\n",
+		       mdname(mddev));
+		pr_err("md/raid0: please set raid0.default_layout to 1 or 2\n");
+		pr_err("md/raid0: Read the following page for more information:\n");
+		pr_err("md/raid0: https://wiki.ubuntu.com/Kernel/Raid0LayoutMigration\n");
+		err = -EOPNOTSUPP;
+		goto abort;
+	}
+
+	if (conf->layout == RAID0_ORIG_LAYOUT) {
+		for (i = 1; i < conf->nr_strip_zones; i++) {
+			sector_t first_sector = conf->strip_zone[i-1].zone_end;
+
+			sector_div(first_sector, mddev->chunk_sectors);
+			zone = conf->strip_zone + i;
+			/* disk_shift is first disk index used in the zone */
+			zone->disk_shift = sector_div(first_sector,
+						      zone->nb_dev);
+		}
+	}
+
 	pr_debug("md/raid0:%s: done.\n", mdname(mddev));
 	*private_conf = conf;
 
@@ -474,6 +489,20 @@
 	}
 }
 
+/*
+ * Convert disk_index to the disk order in which it is read/written.
+ *  For example, if we have 4 disks, they are numbered 0,1,2,3. If we
+ *  write the disks starting at disk 3, then the read/write order would
+ *  be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift()
+ *  to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map
+ *  to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in
+ *  that 'output' space to understand the read/write disk ordering.
+ */
+static int map_disk_shift(int disk_index, int num_disks, int disk_shift)
+{
+	return ((disk_index + num_disks - disk_shift) % num_disks);
+}
+
 static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
 {
 	struct r0conf *conf = mddev->private;
@@ -487,7 +516,9 @@
 	sector_t end_disk_offset;
 	unsigned int end_disk_index;
 	unsigned int disk;
+	sector_t orig_start, orig_end;
 
+	orig_start = start;
 	zone = find_zone(conf, &start);
 
 	if (bio_end_sector(bio) > zone->zone_end) {
@@ -501,6 +532,7 @@
 	} else
 		end = bio_end_sector(bio);
 
+	orig_end = end;
 	if (zone != conf->strip_zone)
 		end = end - zone[-1].zone_end;
 
@@ -512,33 +544,49 @@
 	last_stripe_index = end;
 	sector_div(last_stripe_index, stripe_size);
 
-	start_disk_index = (int)(start - first_stripe_index * stripe_size) /
-		mddev->chunk_sectors;
+	/* In the first zone the original and alternate layouts are the same */
+	if ((conf->layout == RAID0_ORIG_LAYOUT) && (zone != conf->strip_zone)) {
+		sector_div(orig_start, mddev->chunk_sectors);
+		start_disk_index = sector_div(orig_start, zone->nb_dev);
+		start_disk_index = map_disk_shift(start_disk_index,
+						  zone->nb_dev,
+						  zone->disk_shift);
+		sector_div(orig_end, mddev->chunk_sectors);
+		end_disk_index = sector_div(orig_end, zone->nb_dev);
+		end_disk_index = map_disk_shift(end_disk_index,
+						zone->nb_dev, zone->disk_shift);
+	} else {
+		start_disk_index = (int)(start - first_stripe_index * stripe_size) /
+			mddev->chunk_sectors;
+		end_disk_index = (int)(end - last_stripe_index * stripe_size) /
+			mddev->chunk_sectors;
+	}
 	start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %
 		mddev->chunk_sectors) +
 		first_stripe_index * mddev->chunk_sectors;
-	end_disk_index = (int)(end - last_stripe_index * stripe_size) /
-		mddev->chunk_sectors;
 	end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %
 		mddev->chunk_sectors) +
 		last_stripe_index * mddev->chunk_sectors;
 
 	for (disk = 0; disk < zone->nb_dev; disk++) {
 		sector_t dev_start, dev_end;
-		struct bio *discard_bio = NULL;
 		struct md_rdev *rdev;
+		int compare_disk;
+
+		compare_disk = map_disk_shift(disk, zone->nb_dev,
+					      zone->disk_shift);
 
-		if (disk < start_disk_index)
+		if (compare_disk < start_disk_index)
 			dev_start = (first_stripe_index + 1) *
 				mddev->chunk_sectors;
-		else if (disk > start_disk_index)
+		else if (compare_disk > start_disk_index)
 			dev_start = first_stripe_index * mddev->chunk_sectors;
 		else
 			dev_start = start_disk_offset;
 
-		if (disk < end_disk_index)
+		if (compare_disk < end_disk_index)
 			dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
-		else if (disk > end_disk_index)
+		else if (compare_disk > end_disk_index)
 			dev_end = last_stripe_index * mddev->chunk_sectors;
 		else
 			dev_end = end_disk_offset;
@@ -548,18 +596,9 @@
 
 		rdev = conf->devlist[(zone - conf->strip_zone) *
 			conf->strip_zone[0].nb_dev + disk];
-		if (__blkdev_issue_discard(rdev->bdev,
+		md_submit_discard_bio(mddev, rdev, bio,
 			dev_start + zone->dev_start + rdev->data_offset,
-			dev_end - dev_start, GFP_NOIO, 0, &discard_bio) ||
-		    !discard_bio)
-			continue;
-		bio_chain(discard_bio, bio);
-		bio_clone_blkg_association(discard_bio, bio);
-		if (mddev->gendisk)
-			trace_block_bio_remap(bdev_get_queue(rdev->bdev),
-				discard_bio, disk_devt(mddev->gendisk),
-				bio->bi_iter.bi_sector);
-		generic_make_request(discard_bio);
+			dev_end - dev_start);
 	}
 	bio_endio(bio);
 }
@@ -575,10 +614,9 @@
 	unsigned chunk_sects;
 	unsigned sectors;
 
-	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-		md_flush_request(mddev, bio);
+	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+	    && md_flush_request(mddev, bio))
 		return true;
-	}
 
 	if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
 		raid0_handle_discard(mddev, bio);
@@ -615,7 +653,7 @@
 		tmp_dev = map_sector(mddev, zone, sector, &sector);
 		break;
 	default:
-		WARN("md/raid0:%s: Invalid layout\n", mdname(mddev));
+		WARN(1, "md/raid0:%s: Invalid layout\n", mdname(mddev));
 		bio_io_error(bio);
 		return true;
 	}
--- linux-ein-5.4.0.orig/drivers/md/raid0.h
+++ linux-ein-5.4.0/drivers/md/raid0.h
@@ -6,6 +6,7 @@
 	sector_t zone_end;	/* Start of the next zone (in sectors) */
 	sector_t dev_start;	/* Zone offset in real dev (in sectors) */
 	int	 nb_dev;	/* # of devices attached to the zone */
+	int	 disk_shift;	/* start disk for the original layout */
 };
 
 /* Linux 3.14 (20d0189b101) made an unintended change to
--- linux-ein-5.4.0.orig/drivers/md/raid1.c
+++ linux-ein-5.4.0/drivers/md/raid1.c
@@ -452,12 +452,12 @@
 		/*
 		 * When the device is faulty, it is not necessary to
 		 * handle write error.
-		 * For failfast, this is the only remaining device,
-		 * We need to retry the write without FailFast.
 		 */
 		if (!test_bit(Faulty, &rdev->flags))
 			set_bit(R1BIO_WriteError, &r1_bio->state);
 		else {
+			/* Fail the request */
+			set_bit(R1BIO_Degraded, &r1_bio->state);
 			/* Finished with this branch */
 			r1_bio->bios[mirror] = NULL;
 			to_put = bio;
@@ -1567,10 +1567,9 @@
 {
 	sector_t sectors;
 
-	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-		md_flush_request(mddev, bio);
+	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+	    && md_flush_request(mddev, bio))
 		return true;
-	}
 
 	/*
 	 * There is a limit to the maximum size, but
@@ -1811,6 +1810,9 @@
 	int number = rdev->raid_disk;
 	struct raid1_info *p = conf->mirrors + number;
 
+	if (unlikely(number >= conf->raid_disks))
+		goto abort;
+
 	if (rdev != p->rdev)
 		p = conf->mirrors + conf->raid_disks + number;
 
@@ -2782,7 +2784,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_set_dev(bio, rdev->bdev);
@@ -3133,6 +3135,7 @@
 	 * RAID1 needs at least one disk in active
 	 */
 	if (conf->raid_disks - mddev->degraded < 1) {
+		md_unregister_thread(&conf->thread);
 		ret = -EINVAL;
 		goto abort;
 	}
--- linux-ein-5.4.0.orig/drivers/md/raid10.c
+++ linux-ein-5.4.0/drivers/md/raid10.c
@@ -91,7 +91,7 @@
 static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
 {
 	struct r10conf *conf = data;
-	int size = offsetof(struct r10bio, devs[conf->copies]);
+	int size = offsetof(struct r10bio, devs[conf->geo.raid_disks]);
 
 	/* allocate a r10bio with room for raid_disks entries in the
 	 * bios array */
@@ -191,7 +191,7 @@
 
 out_free_pages:
 	while (--j >= 0)
-		resync_free_pages(&rps[j * 2]);
+		resync_free_pages(&rps[j]);
 
 	j = 0;
 out_free_bio:
@@ -238,7 +238,7 @@
 {
 	int i;
 
-	for (i = 0; i < conf->copies; i++) {
+	for (i = 0; i < conf->geo.raid_disks; i++) {
 		struct bio **bio = & r10_bio->devs[i].bio;
 		if (!BIO_SPECIAL(*bio))
 			bio_put(*bio);
@@ -327,7 +327,7 @@
 	int slot;
 	int repl = 0;
 
-	for (slot = 0; slot < conf->copies; slot++) {
+	for (slot = 0; slot < conf->geo.raid_disks; slot++) {
 		if (r10_bio->devs[slot].bio == bio)
 			break;
 		if (r10_bio->devs[slot].repl_bio == bio) {
@@ -336,7 +336,6 @@
 		}
 	}
 
-	BUG_ON(slot == conf->copies);
 	update_head_pos(slot, r10_bio);
 
 	if (slotp)
@@ -470,12 +469,12 @@
 			/*
 			 * When the device is faulty, it is not necessary to
 			 * handle write error.
-			 * For failfast, this is the only remaining device,
-			 * We need to retry the write without FailFast.
 			 */
 			if (!test_bit(Faulty, &rdev->flags))
 				set_bit(R10BIO_WriteError, &r10_bio->state);
 			else {
+				/* Fail the request */
+				set_bit(R10BIO_Degraded, &r10_bio->state);
 				r10_bio->devs[slot].bio = NULL;
 				to_put = bio;
 				dec_rdev = 1;
@@ -751,8 +750,16 @@
 		disk = r10_bio->devs[slot].devnum;
 		rdev = rcu_dereference(conf->mirrors[disk].replacement);
 		if (rdev == NULL || test_bit(Faulty, &rdev->flags) ||
-		    r10_bio->devs[slot].addr + sectors > rdev->recovery_offset)
+		    r10_bio->devs[slot].addr + sectors >
+		    rdev->recovery_offset) {
+			/*
+			 * Read replacement first to prevent reading both rdev
+			 * and replacement as NULL during replacement replace
+			 * rdev.
+			 */
+			smp_mb();
 			rdev = rcu_dereference(conf->mirrors[disk].rdev);
+		}
 		if (rdev == NULL ||
 		    test_bit(Faulty, &rdev->flags))
 			continue;
@@ -919,6 +926,7 @@
 			else
 				generic_make_request(bio);
 			bio = next;
+			cond_resched();
 		}
 		blk_finish_plug(&plug);
 	} else
@@ -1104,6 +1112,7 @@
 		else
 			generic_make_request(bio);
 		bio = next;
+		cond_resched();
 	}
 	kfree(plug);
 }
@@ -1145,7 +1154,7 @@
 	struct md_rdev *err_rdev = NULL;
 	gfp_t gfp = GFP_NOIO;
 
-	if (r10_bio->devs[slot].rdev) {
+	if (slot >= 0 && r10_bio->devs[slot].rdev) {
 		/*
 		 * This is an error retry, but we cannot
 		 * safely dereference the rdev in the r10_bio,
@@ -1293,12 +1302,77 @@
 	}
 }
 
+static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
+{
+	int i;
+	struct r10conf *conf = mddev->private;
+	struct md_rdev *blocked_rdev;
+
+retry_wait:
+	blocked_rdev = NULL;
+	rcu_read_lock();
+	for (i = 0; i < conf->copies; i++) {
+		struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		struct md_rdev *rrdev = rcu_dereference(
+			conf->mirrors[i].replacement);
+		if (rdev == rrdev)
+			rrdev = NULL;
+		if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+			atomic_inc(&rdev->nr_pending);
+			blocked_rdev = rdev;
+			break;
+		}
+		if (rrdev && unlikely(test_bit(Blocked, &rrdev->flags))) {
+			atomic_inc(&rrdev->nr_pending);
+			blocked_rdev = rrdev;
+			break;
+		}
+
+		if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) {
+			sector_t first_bad;
+			sector_t dev_sector = r10_bio->devs[i].addr;
+			int bad_sectors;
+			int is_bad;
+
+			/*
+			 * Discard request doesn't care the write result
+			 * so it doesn't need to wait blocked disk here.
+			 */
+			if (!r10_bio->sectors)
+				continue;
+
+			is_bad = is_badblock(rdev, dev_sector, r10_bio->sectors,
+					     &first_bad, &bad_sectors);
+			if (is_bad < 0) {
+				/*
+				 * Mustn't write here until the bad block
+				 * is acknowledged
+				 */
+				atomic_inc(&rdev->nr_pending);
+				set_bit(BlockedBadBlocks, &rdev->flags);
+				blocked_rdev = rdev;
+				break;
+			}
+		}
+	}
+	rcu_read_unlock();
+
+	if (unlikely(blocked_rdev)) {
+		/* Have to wait for this device to get unblocked, then retry */
+		allow_barrier(conf);
+		raid10_log(conf->mddev, "%s wait rdev %d blocked",
+				__func__, blocked_rdev->raid_disk);
+		md_wait_for_blocked_rdev(blocked_rdev, mddev);
+		wait_barrier(conf);
+		goto retry_wait;
+	}
+}
+
 static void raid10_write_request(struct mddev *mddev, struct bio *bio,
 				 struct r10bio *r10_bio)
 {
 	struct r10conf *conf = mddev->private;
 	int i;
-	struct md_rdev *blocked_rdev;
 	sector_t sectors;
 	int max_sectors;
 
@@ -1356,28 +1430,25 @@
 
 	r10_bio->read_slot = -1; /* make sure repl_bio gets freed */
 	raid10_find_phys(conf, r10_bio);
-retry_write:
-	blocked_rdev = NULL;
+
+	wait_blocked_dev(mddev, r10_bio);
+
 	rcu_read_lock();
 	max_sectors = r10_bio->sectors;
 
 	for (i = 0;  i < conf->copies; i++) {
 		int d = r10_bio->devs[i].devnum;
-		struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev);
-		struct md_rdev *rrdev = rcu_dereference(
-			conf->mirrors[d].replacement);
+		struct md_rdev *rdev, *rrdev;
+
+		rrdev = rcu_dereference(conf->mirrors[d].replacement);
+		/*
+		 * Read replacement first to prevent reading both rdev and
+		 * replacement as NULL during replacement replace rdev.
+		 */
+		smp_mb();
+		rdev = rcu_dereference(conf->mirrors[d].rdev);
 		if (rdev == rrdev)
 			rrdev = NULL;
-		if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
-			atomic_inc(&rdev->nr_pending);
-			blocked_rdev = rdev;
-			break;
-		}
-		if (rrdev && unlikely(test_bit(Blocked, &rrdev->flags))) {
-			atomic_inc(&rrdev->nr_pending);
-			blocked_rdev = rrdev;
-			break;
-		}
 		if (rdev && (test_bit(Faulty, &rdev->flags)))
 			rdev = NULL;
 		if (rrdev && (test_bit(Faulty, &rrdev->flags)))
@@ -1398,15 +1469,6 @@
 
 			is_bad = is_badblock(rdev, dev_sector, max_sectors,
 					     &first_bad, &bad_sectors);
-			if (is_bad < 0) {
-				/* Mustn't write here until the bad block
-				 * is acknowledged
-				 */
-				atomic_inc(&rdev->nr_pending);
-				set_bit(BlockedBadBlocks, &rdev->flags);
-				blocked_rdev = rdev;
-				break;
-			}
 			if (is_bad && first_bad <= dev_sector) {
 				/* Cannot write here at all */
 				bad_sectors -= (dev_sector - first_bad);
@@ -1442,35 +1504,6 @@
 	}
 	rcu_read_unlock();
 
-	if (unlikely(blocked_rdev)) {
-		/* Have to wait for this device to get unblocked, then retry */
-		int j;
-		int d;
-
-		for (j = 0; j < i; j++) {
-			if (r10_bio->devs[j].bio) {
-				d = r10_bio->devs[j].devnum;
-				rdev_dec_pending(conf->mirrors[d].rdev, mddev);
-			}
-			if (r10_bio->devs[j].repl_bio) {
-				struct md_rdev *rdev;
-				d = r10_bio->devs[j].devnum;
-				rdev = conf->mirrors[d].replacement;
-				if (!rdev) {
-					/* Race with remove_disk */
-					smp_mb();
-					rdev = conf->mirrors[d].rdev;
-				}
-				rdev_dec_pending(rdev, mddev);
-			}
-		}
-		allow_barrier(conf);
-		raid10_log(conf->mddev, "wait rdev %d blocked", blocked_rdev->raid_disk);
-		md_wait_for_blocked_rdev(blocked_rdev, mddev);
-		wait_barrier(conf);
-		goto retry_write;
-	}
-
 	if (max_sectors < r10_bio->sectors)
 		r10_bio->sectors = max_sectors;
 
@@ -1510,7 +1543,9 @@
 	r10_bio->mddev = mddev;
 	r10_bio->sector = bio->bi_iter.bi_sector;
 	r10_bio->state = 0;
-	memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) * conf->copies);
+	r10_bio->read_slot = -1;
+	memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
+			conf->geo.raid_disks);
 
 	if (bio_data_dir(bio) == READ)
 		raid10_read_request(mddev, bio, r10_bio);
@@ -1518,6 +1553,304 @@
 		raid10_write_request(mddev, bio, r10_bio);
 }
 
+static void raid_end_discard_bio(struct r10bio *r10bio)
+{
+	struct r10conf *conf = r10bio->mddev->private;
+	struct r10bio *first_r10bio;
+
+	while (atomic_dec_and_test(&r10bio->remaining)) {
+
+		allow_barrier(conf);
+
+		if (!test_bit(R10BIO_Discard, &r10bio->state)) {
+			first_r10bio = (struct r10bio *)r10bio->master_bio;
+			free_r10bio(r10bio);
+			r10bio = first_r10bio;
+		} else {
+			md_write_end(r10bio->mddev);
+			bio_endio(r10bio->master_bio);
+			free_r10bio(r10bio);
+			break;
+		}
+	}
+}
+
+static void raid10_end_discard_request(struct bio *bio)
+{
+	struct r10bio *r10_bio = bio->bi_private;
+	struct r10conf *conf = r10_bio->mddev->private;
+	struct md_rdev *rdev = NULL;
+	int dev;
+	int slot, repl;
+
+	/*
+	 * We don't care the return value of discard bio
+	 */
+	if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
+		set_bit(R10BIO_Uptodate, &r10_bio->state);
+
+	dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
+	if (repl)
+		rdev = conf->mirrors[dev].replacement;
+	if (!rdev) {
+		/*
+		 * raid10_remove_disk uses smp_mb to make sure rdev is set to
+		 * replacement before setting replacement to NULL. It can read
+		 * rdev first without barrier protect even replacment is NULL
+		 */
+		smp_rmb();
+		rdev = conf->mirrors[dev].rdev;
+	}
+
+	raid_end_discard_bio(r10_bio);
+	rdev_dec_pending(rdev, conf->mddev);
+}
+
+/*
+ * There are some limitations to handle discard bio
+ * 1st, the discard size is bigger than stripe_size*2.
+ * 2st, if the discard bio spans reshape progress, we use the old way to
+ * handle discard bio
+ */
+static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
+{
+	struct r10conf *conf = mddev->private;
+	struct geom *geo = &conf->geo;
+	int far_copies = geo->far_copies;
+	bool first_copy = true;
+	struct r10bio *r10_bio, *first_r10bio;
+	struct bio *split;
+	int disk;
+	sector_t chunk;
+	unsigned int stripe_size;
+	unsigned int stripe_data_disks;
+	sector_t split_size;
+	sector_t bio_start, bio_end;
+	sector_t first_stripe_index, last_stripe_index;
+	sector_t start_disk_offset;
+	unsigned int start_disk_index;
+	sector_t end_disk_offset;
+	unsigned int end_disk_index;
+	unsigned int remainder;
+
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+		return -EAGAIN;
+
+	wait_barrier(conf);
+
+	/*
+	 * Check reshape again to avoid reshape happens after checking
+	 * MD_RECOVERY_RESHAPE and before wait_barrier
+	 */
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+		goto out;
+
+	if (geo->near_copies)
+		stripe_data_disks = geo->raid_disks / geo->near_copies +
+					geo->raid_disks % geo->near_copies;
+	else
+		stripe_data_disks = geo->raid_disks;
+
+	stripe_size = stripe_data_disks << geo->chunk_shift;
+
+	bio_start = bio->bi_iter.bi_sector;
+	bio_end = bio_end_sector(bio);
+
+	/*
+	 * Maybe one discard bio is smaller than strip size or across one
+	 * stripe and discard region is larger than one stripe size. For far
+	 * offset layout, if the discard region is not aligned with stripe
+	 * size, there is hole when we submit discard bio to member disk.
+	 * For simplicity, we only handle discard bio which discard region
+	 * is bigger than stripe_size * 2
+	 */
+	if (bio_sectors(bio) < stripe_size*2)
+		goto out;
+
+	/*
+	 * Keep bio aligned with strip size.
+	 */
+	div_u64_rem(bio_start, stripe_size, &remainder);
+	if (remainder) {
+		split_size = stripe_size - remainder;
+		split = bio_split(bio, split_size, GFP_NOIO, &conf->bio_split);
+		bio_chain(split, bio);
+		allow_barrier(conf);
+		/* Resend the fist split part */
+		generic_make_request(split);
+		wait_barrier(conf);
+	}
+	div_u64_rem(bio_end, stripe_size, &remainder);
+	if (remainder) {
+		split_size = bio_sectors(bio) - remainder;
+		split = bio_split(bio, split_size, GFP_NOIO, &conf->bio_split);
+		bio_chain(split, bio);
+		allow_barrier(conf);
+		/* Resend the second split part */
+		generic_make_request(bio);
+		bio = split;
+		wait_barrier(conf);
+	}
+
+	bio_start = bio->bi_iter.bi_sector;
+	bio_end = bio_end_sector(bio);
+
+	/*
+	 * Raid10 uses chunk as the unit to store data. It's similar like raid0.
+	 * One stripe contains the chunks from all member disk (one chunk from
+	 * one disk at the same HBA address). For layout detail, see 'man md 4'
+	 */
+	chunk = bio_start >> geo->chunk_shift;
+	chunk *= geo->near_copies;
+	first_stripe_index = chunk;
+	start_disk_index = sector_div(first_stripe_index, geo->raid_disks);
+	if (geo->far_offset)
+		first_stripe_index *= geo->far_copies;
+	start_disk_offset = (bio_start & geo->chunk_mask) +
+				(first_stripe_index << geo->chunk_shift);
+
+	chunk = bio_end >> geo->chunk_shift;
+	chunk *= geo->near_copies;
+	last_stripe_index = chunk;
+	end_disk_index = sector_div(last_stripe_index, geo->raid_disks);
+	if (geo->far_offset)
+		last_stripe_index *= geo->far_copies;
+	end_disk_offset = (bio_end & geo->chunk_mask) +
+				(last_stripe_index << geo->chunk_shift);
+
+retry_discard:
+	r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO);
+	r10_bio->mddev = mddev;
+	r10_bio->state = 0;
+	r10_bio->sectors = 0;
+	memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) * geo->raid_disks);
+	wait_blocked_dev(mddev, r10_bio);
+
+	/*
+	 * For far layout it needs more than one r10bio to cover all regions.
+	 * Inspired by raid10_sync_request, we can use the first r10bio->master_bio
+	 * to record the discard bio. Other r10bio->master_bio record the first
+	 * r10bio. The first r10bio only release after all other r10bios finish.
+	 * The discard bio returns only first r10bio finishes
+	 */
+	if (first_copy) {
+		r10_bio->master_bio = bio;
+		set_bit(R10BIO_Discard, &r10_bio->state);
+		first_copy = false;
+		first_r10bio = r10_bio;
+	} else
+		r10_bio->master_bio = (struct bio *)first_r10bio;
+
+	rcu_read_lock();
+	for (disk = 0; disk < geo->raid_disks; disk++) {
+		struct md_rdev *rdev = rcu_dereference(conf->mirrors[disk].rdev);
+		struct md_rdev *rrdev = rcu_dereference(
+			conf->mirrors[disk].replacement);
+
+		r10_bio->devs[disk].bio = NULL;
+		r10_bio->devs[disk].repl_bio = NULL;
+
+		if (rdev && (test_bit(Faulty, &rdev->flags)))
+			rdev = NULL;
+		if (rrdev && (test_bit(Faulty, &rrdev->flags)))
+			rrdev = NULL;
+		if (!rdev && !rrdev)
+			continue;
+
+		if (rdev) {
+			r10_bio->devs[disk].bio = bio;
+			atomic_inc(&rdev->nr_pending);
+		}
+		if (rrdev) {
+			r10_bio->devs[disk].repl_bio = bio;
+			atomic_inc(&rrdev->nr_pending);
+		}
+	}
+	rcu_read_unlock();
+
+	atomic_set(&r10_bio->remaining, 1);
+	for (disk = 0; disk < geo->raid_disks; disk++) {
+		sector_t dev_start, dev_end;
+		struct bio *mbio, *rbio = NULL;
+		struct md_rdev *rdev = rcu_dereference(conf->mirrors[disk].rdev);
+		struct md_rdev *rrdev = rcu_dereference(
+			conf->mirrors[disk].replacement);
+
+		/*
+		 * Now start to calculate the start and end address for each disk.
+		 * The space between dev_start and dev_end is the discard region.
+		 *
+		 * For dev_start, it needs to consider three conditions:
+		 * 1st, the disk is before start_disk, you can imagine the disk in
+		 * the next stripe. So the dev_start is the start address of next
+		 * stripe.
+		 * 2st, the disk is after start_disk, it means the disk is at the
+		 * same stripe of first disk
+		 * 3st, the first disk itself, we can use start_disk_offset directly
+		 */
+		if (disk < start_disk_index)
+			dev_start = (first_stripe_index + 1) * mddev->chunk_sectors;
+		else if (disk > start_disk_index)
+			dev_start = first_stripe_index * mddev->chunk_sectors;
+		else
+			dev_start = start_disk_offset;
+
+		if (disk < end_disk_index)
+			dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
+		else if (disk > end_disk_index)
+			dev_end = last_stripe_index * mddev->chunk_sectors;
+		else
+			dev_end = end_disk_offset;
+
+		/*
+		 * It only handles discard bio which size is >= stripe size, so
+		 * dev_end > dev_start all the time
+		 */
+		if (r10_bio->devs[disk].bio) {
+			mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set);
+			mbio->bi_end_io = raid10_end_discard_request;
+			mbio->bi_private = r10_bio;
+			r10_bio->devs[disk].bio = mbio;
+			r10_bio->devs[disk].devnum = disk;
+			atomic_inc(&r10_bio->remaining);
+			md_submit_discard_bio(mddev, rdev, mbio,
+					dev_start + choose_data_offset(r10_bio, rdev),
+					dev_end - dev_start);
+			bio_endio(mbio);
+		}
+		if (r10_bio->devs[disk].repl_bio) {
+			rbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set);
+			rbio->bi_end_io = raid10_end_discard_request;
+			rbio->bi_private = r10_bio;
+			r10_bio->devs[disk].repl_bio = rbio;
+			r10_bio->devs[disk].devnum = disk;
+			atomic_inc(&r10_bio->remaining);
+			md_submit_discard_bio(mddev, rrdev, rbio,
+					dev_start + choose_data_offset(r10_bio, rrdev),
+					dev_end - dev_start);
+			bio_endio(rbio);
+		}
+	}
+
+	if (!geo->far_offset && --far_copies) {
+		first_stripe_index += geo->stride >> geo->chunk_shift;
+		start_disk_offset += geo->stride;
+		last_stripe_index += geo->stride >> geo->chunk_shift;
+		end_disk_offset += geo->stride;
+		atomic_inc(&first_r10bio->remaining);
+		raid_end_discard_bio(r10_bio);
+		wait_barrier(conf);
+		goto retry_discard;
+	}
+
+	raid_end_discard_bio(r10_bio);
+
+	return 0;
+out:
+	allow_barrier(conf);
+	return -EAGAIN;
+}
+
 static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
 {
 	struct r10conf *conf = mddev->private;
@@ -1525,14 +1858,17 @@
 	int chunk_sects = chunk_mask + 1;
 	int sectors = bio_sectors(bio);
 
-	if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-		md_flush_request(mddev, bio);
+	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+	    && md_flush_request(mddev, bio))
 		return true;
-	}
 
 	if (!md_write_start(mddev, bio))
 		return false;
 
+	if (unlikely(bio_op(bio) == REQ_OP_DISCARD))
+		if (!raid10_handle_discard(mddev, bio))
+			return true;
+
 	/*
 	 * If this request crosses a chunk boundary, we need to split
 	 * it.
@@ -1826,9 +2162,12 @@
 	int err = 0;
 	int number = rdev->raid_disk;
 	struct md_rdev **rdevp;
-	struct raid10_info *p = conf->mirrors + number;
+	struct raid10_info *p;
 
 	print_conf(conf);
+	if (unlikely(number >= mddev->raid_disks))
+		return 0;
+	p = conf->mirrors + number;
 	if (rdev == p->rdev)
 		rdevp = &p->rdev;
 	else if (rdev == p->replacement)
@@ -2226,11 +2565,22 @@
 {
 	struct r10conf *conf = mddev->private;
 	int d;
-	struct bio *wbio, *wbio2;
+	struct bio *wbio = r10_bio->devs[1].bio;
+	struct bio *wbio2 = r10_bio->devs[1].repl_bio;
+
+	/* Need to test wbio2->bi_end_io before we call
+	 * generic_make_request as if the former is NULL,
+	 * the latter is free to free wbio2.
+	 */
+	if (wbio2 && !wbio2->bi_end_io)
+		wbio2 = NULL;
 
 	if (!test_bit(R10BIO_Uptodate, &r10_bio->state)) {
 		fix_recovery_read_error(r10_bio);
-		end_sync_request(r10_bio);
+		if (wbio->bi_end_io)
+			end_sync_request(r10_bio);
+		if (wbio2)
+			end_sync_request(r10_bio);
 		return;
 	}
 
@@ -2239,14 +2589,6 @@
 	 * and submit the write request
 	 */
 	d = r10_bio->devs[1].devnum;
-	wbio = r10_bio->devs[1].bio;
-	wbio2 = r10_bio->devs[1].repl_bio;
-	/* Need to test wbio2->bi_end_io before we call
-	 * generic_make_request as if the former is NULL,
-	 * the latter is free to free wbio2.
-	 */
-	if (wbio2 && !wbio2->bi_end_io)
-		wbio2 = NULL;
 	if (wbio->bi_end_io) {
 		atomic_inc(&conf->mirrors[d].rdev->nr_pending);
 		md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio));
@@ -2914,10 +3256,6 @@
 	sector_t chunk_mask = conf->geo.chunk_mask;
 	int page_idx = 0;
 
-	if (!mempool_initialized(&conf->r10buf_pool))
-		if (init_resync(conf))
-			return 0;
-
 	/*
 	 * Allow skipping a full rebuild for incremental assembly
 	 * of a clean array, like RAID1 does.
@@ -2933,6 +3271,10 @@
 		return mddev->dev_sectors - sector_nr;
 	}
 
+	if (!mempool_initialized(&conf->r10buf_pool))
+		if (init_resync(conf))
+			return 0;
+
  skipped:
 	max_sector = mddev->dev_sectors;
 	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
@@ -3048,7 +3390,6 @@
 			int must_sync;
 			int any_working;
 			int need_recover = 0;
-			int need_replace = 0;
 			struct raid10_info *mirror = &conf->mirrors[i];
 			struct md_rdev *mrdev, *mreplace;
 
@@ -3060,11 +3401,10 @@
 			    !test_bit(Faulty, &mrdev->flags) &&
 			    !test_bit(In_sync, &mrdev->flags))
 				need_recover = 1;
-			if (mreplace != NULL &&
-			    !test_bit(Faulty, &mreplace->flags))
-				need_replace = 1;
+			if (mreplace && test_bit(Faulty, &mreplace->flags))
+				mreplace = NULL;
 
-			if (!need_recover && !need_replace) {
+			if (!need_recover && !mreplace) {
 				rcu_read_unlock();
 				continue;
 			}
@@ -3080,8 +3420,6 @@
 				rcu_read_unlock();
 				continue;
 			}
-			if (mreplace && test_bit(Faulty, &mreplace->flags))
-				mreplace = NULL;
 			/* Unless we are doing a full sync, or a replacement
 			 * we only need to recover the block if it is set in
 			 * the bitmap
@@ -3204,11 +3542,11 @@
 				bio = r10_bio->devs[1].repl_bio;
 				if (bio)
 					bio->bi_end_io = NULL;
-				/* Note: if need_replace, then bio
+				/* Note: if replace is not NULL, then bio
 				 * cannot be NULL as r10buf_pool_alloc will
 				 * have allocated it.
 				 */
-				if (!need_replace)
+				if (!mreplace)
 					break;
 				bio->bi_next = biolist;
 				biolist = bio;
@@ -3629,6 +3967,20 @@
 	return nc*fc;
 }
 
+static void raid10_free_conf(struct r10conf *conf)
+{
+	if (!conf)
+		return;
+
+	mempool_exit(&conf->r10bio_pool);
+	kfree(conf->mirrors);
+	kfree(conf->mirrors_old);
+	kfree(conf->mirrors_new);
+	safe_put_page(conf->tmppage);
+	bioset_exit(&conf->bio_split);
+	kfree(conf);
+}
+
 static struct r10conf *setup_conf(struct mddev *mddev)
 {
 	struct r10conf *conf = NULL;
@@ -3711,20 +4063,24 @@
 	return conf;
 
  out:
-	if (conf) {
-		mempool_exit(&conf->r10bio_pool);
-		kfree(conf->mirrors);
-		safe_put_page(conf->tmppage);
-		bioset_exit(&conf->bio_split);
-		kfree(conf);
-	}
+	raid10_free_conf(conf);
 	return ERR_PTR(err);
 }
 
+static void raid10_set_io_opt(struct r10conf *conf)
+{
+	int raid_disks = conf->geo.raid_disks;
+
+	if (!(conf->geo.raid_disks % conf->geo.near_copies))
+		raid_disks /= conf->geo.near_copies;
+	blk_queue_io_opt(conf->mddev->queue, (conf->mddev->chunk_sectors << 9) *
+			 raid_disks);
+}
+
 static int raid10_run(struct mddev *mddev)
 {
 	struct r10conf *conf;
-	int i, disk_idx, chunk_size;
+	int i, disk_idx;
 	struct raid10_info *disk;
 	struct md_rdev *rdev;
 	sector_t size;
@@ -3745,6 +4101,9 @@
 	if (!conf)
 		goto out;
 
+	mddev->thread = conf->thread;
+	conf->thread = NULL;
+
 	if (mddev_is_clustered(conf->mddev)) {
 		int fc, fo;
 
@@ -3757,21 +4116,13 @@
 		}
 	}
 
-	mddev->thread = conf->thread;
-	conf->thread = NULL;
-
-	chunk_size = mddev->chunk_sectors << 9;
 	if (mddev->queue) {
 		blk_queue_max_discard_sectors(mddev->queue,
-					      mddev->chunk_sectors);
+					      UINT_MAX);
 		blk_queue_max_write_same_sectors(mddev->queue, 0);
 		blk_queue_max_write_zeroes_sectors(mddev->queue, 0);
-		blk_queue_io_min(mddev->queue, chunk_size);
-		if (conf->geo.raid_disks % conf->geo.near_copies)
-			blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
-		else
-			blk_queue_io_opt(mddev->queue, chunk_size *
-					 (conf->geo.raid_disks / conf->geo.near_copies));
+		blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
+		raid10_set_io_opt(conf);
 	}
 
 	rdev_for_each(rdev, mddev) {
@@ -3931,10 +4282,7 @@
 
 out_free_conf:
 	md_unregister_thread(&mddev->thread);
-	mempool_exit(&conf->r10bio_pool);
-	safe_put_page(conf->tmppage);
-	kfree(conf->mirrors);
-	kfree(conf);
+	raid10_free_conf(conf);
 	mddev->private = NULL;
 out:
 	return -EIO;
@@ -3942,15 +4290,7 @@
 
 static void raid10_free(struct mddev *mddev, void *priv)
 {
-	struct r10conf *conf = priv;
-
-	mempool_exit(&conf->r10bio_pool);
-	safe_put_page(conf->tmppage);
-	kfree(conf->mirrors);
-	kfree(conf->mirrors_old);
-	kfree(conf->mirrors_new);
-	bioset_exit(&conf->bio_split);
-	kfree(conf);
+	raid10_free_conf(priv);
 }
 
 static void raid10_quiesce(struct mddev *mddev, int quiesce)
@@ -4745,6 +5085,7 @@
 		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;
+		raid10_set_io_opt(conf);
 	}
 	conf->fullsync = 0;
 }
--- linux-ein-5.4.0.orig/drivers/md/raid10.h
+++ linux-ein-5.4.0/drivers/md/raid10.h
@@ -179,5 +179,6 @@
 	R10BIO_Previous,
 /* failfast devices did receive failfast requests. */
 	R10BIO_FailFast,
+	R10BIO_Discard,
 };
 #endif
--- linux-ein-5.4.0.orig/drivers/md/raid5.c
+++ linux-ein-5.4.0/drivers/md/raid5.c
@@ -609,17 +609,17 @@
 	return degraded;
 }
 
-static int has_failed(struct r5conf *conf)
+static bool has_failed(struct r5conf *conf)
 {
-	int degraded;
+	int degraded = conf->mddev->degraded;
 
-	if (conf->mddev->reshape_position == MaxSector)
-		return conf->mddev->degraded > conf->max_degraded;
+	if (test_bit(MD_BROKEN, &conf->mddev->flags))
+		return true;
 
-	degraded = raid5_calc_degraded(conf);
-	if (degraded > conf->max_degraded)
-		return 1;
-	return 0;
+	if (conf->mddev->reshape_position != MaxSector)
+		degraded = raid5_calc_degraded(conf);
+
+	return degraded > conf->max_degraded;
 }
 
 struct stripe_head *
@@ -2228,14 +2228,19 @@
  * of the P and Q blocks.
  */
 static int scribble_alloc(struct raid5_percpu *percpu,
-			  int num, int cnt, gfp_t flags)
+			  int num, int cnt)
 {
 	size_t obj_size =
 		sizeof(struct page *) * (num+2) +
 		sizeof(addr_conv_t) * (num+2);
 	void *scribble;
 
-	scribble = kvmalloc_array(cnt, obj_size, flags);
+	/*
+	 * If here is in raid array suspend context, it is in memalloc noio
+	 * context as well, there is no potential recursive memory reclaim
+	 * I/Os with the GFP_KERNEL flag.
+	 */
+	scribble = kvmalloc_array(cnt, obj_size, GFP_KERNEL);
 	if (!scribble)
 		return -ENOMEM;
 
@@ -2267,8 +2272,7 @@
 
 		percpu = per_cpu_ptr(conf->percpu, cpu);
 		err = scribble_alloc(percpu, new_disks,
-				     new_sectors / STRIPE_SECTORS,
-				     GFP_NOIO);
+				     new_sectors / STRIPE_SECTORS);
 		if (err)
 			break;
 	}
@@ -2403,8 +2407,6 @@
 	} else
 		err = -ENOMEM;
 
-	mutex_unlock(&conf->cache_size_mutex);
-
 	conf->slab_cache = sc;
 	conf->active_name = 1-conf->active_name;
 
@@ -2427,6 +2429,8 @@
 
 	if (!err)
 		conf->pool_size = newsize;
+	mutex_unlock(&conf->cache_size_mutex);
+
 	return err;
 }
 
@@ -2594,7 +2598,7 @@
 	struct stripe_head *sh = bi->bi_private;
 	struct r5conf *conf = sh->raid_conf;
 	int disks = sh->disks, i;
-	struct md_rdev *uninitialized_var(rdev);
+	struct md_rdev *rdev;
 	sector_t first_bad;
 	int bad_sectors;
 	int replacement = 0;
@@ -2662,10 +2666,10 @@
 	if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
 		clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
-	raid5_release_stripe(sh);
 
 	if (sh->batch_head && sh != sh->batch_head)
 		raid5_release_stripe(sh->batch_head);
+	raid5_release_stripe(sh);
 }
 
 static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
@@ -2675,34 +2679,31 @@
 	unsigned long flags;
 	pr_debug("raid456: error called\n");
 
+	pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n",
+		mdname(mddev), bdevname(rdev->bdev, b));
+
 	spin_lock_irqsave(&conf->device_lock, flags);
+	set_bit(Faulty, &rdev->flags);
+	clear_bit(In_sync, &rdev->flags);
+	mddev->degraded = raid5_calc_degraded(conf);
 
-	if (test_bit(In_sync, &rdev->flags) &&
-	    mddev->degraded == conf->max_degraded) {
-		/*
-		 * Don't allow to achieve failed state
-		 * Don't try to recover this device
-		 */
+	if (has_failed(conf)) {
+		set_bit(MD_BROKEN, &conf->mddev->flags);
 		conf->recovery_disabled = mddev->recovery_disabled;
-		spin_unlock_irqrestore(&conf->device_lock, flags);
-		return;
+
+		pr_crit("md/raid:%s: Cannot continue operation (%d/%d failed).\n",
+			mdname(mddev), mddev->degraded, conf->raid_disks);
+	} else {
+		pr_crit("md/raid:%s: Operation continuing on %d devices.\n",
+			mdname(mddev), conf->raid_disks - mddev->degraded);
 	}
 
-	set_bit(Faulty, &rdev->flags);
-	clear_bit(In_sync, &rdev->flags);
-	mddev->degraded = raid5_calc_degraded(conf);
 	spin_unlock_irqrestore(&conf->device_lock, flags);
 	set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 
 	set_bit(Blocked, &rdev->flags);
 	set_mask_bits(&mddev->sb_flags, 0,
 		      BIT(MD_SB_CHANGE_DEVS) | BIT(MD_SB_CHANGE_PENDING));
-	pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n"
-		"md/raid:%s: Operation continuing on %d devices.\n",
-		mdname(mddev),
-		bdevname(rdev->bdev, b),
-		mdname(mddev),
-		conf->raid_disks - mddev->degraded);
 	r5c_update_on_rdev_error(mddev, rdev);
 }
 
@@ -3600,6 +3601,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;
@@ -3726,7 +3728,7 @@
 		 * back cache (prexor with orig_page, and then xor with
 		 * page) in the read path
 		 */
-		if (s->injournal && s->failed) {
+		if (s->to_read && s->injournal && s->failed) {
 			if (test_bit(STRIPE_R5C_CACHING, &sh->state))
 				r5c_make_stripe_write_out(sh);
 			goto out;
@@ -4835,7 +4837,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)
@@ -5592,8 +5594,8 @@
 		if (ret == 0)
 			return true;
 		if (ret == -ENODEV) {
-			md_flush_request(mddev, bi);
-			return true;
+			if (md_flush_request(mddev, bi))
+				return true;
 		}
 		/* ret == -EAGAIN, fallback */
 		/*
@@ -5726,7 +5728,7 @@
 				do_flush = false;
 			}
 
-			if (!sh->batch_head)
+			if (!sh->batch_head || sh == sh->batch_head)
 				set_bit(STRIPE_HANDLE, &sh->state);
 			clear_bit(STRIPE_DELAYED, &sh->state);
 			if ((!sh->batch_head || sh == sh->batch_head) &&
@@ -6765,8 +6767,7 @@
 			       conf->previous_raid_disks),
 			   max(conf->chunk_sectors,
 			       conf->prev_chunk_sectors)
-			   / STRIPE_SECTORS,
-			   GFP_KERNEL)) {
+			   / STRIPE_SECTORS)) {
 		free_scratch_buffer(conf, percpu);
 		return -ENOMEM;
 	}
@@ -7146,6 +7147,12 @@
 	return 0;
 }
 
+static void raid5_set_io_opt(struct r5conf *conf)
+{
+	blk_queue_io_opt(conf->mddev->queue, (conf->chunk_sectors << 9) *
+			 (conf->raid_disks - conf->max_degraded));
+}
+
 static int raid5_run(struct mddev *mddev)
 {
 	struct r5conf *conf;
@@ -7435,8 +7442,7 @@
 
 		chunk_size = mddev->chunk_sectors << 9;
 		blk_queue_io_min(mddev->queue, chunk_size);
-		blk_queue_io_opt(mddev->queue, chunk_size *
-				 (conf->raid_disks - conf->max_degraded));
+		raid5_set_io_opt(conf);
 		mddev->queue->limits.raid_partial_stripes_expensive = 1;
 		/*
 		 * We can only discard a whole stripe. It doesn't make sense to
@@ -7721,6 +7727,7 @@
 	 */
 	if (rdev->saved_raid_disk >= 0 &&
 	    rdev->saved_raid_disk >= first &&
+	    rdev->saved_raid_disk <= last &&
 	    conf->disks[rdev->saved_raid_disk].rdev == NULL)
 		first = rdev->saved_raid_disk;
 
@@ -8029,6 +8036,7 @@
 						   / PAGE_SIZE);
 			if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
 				conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
+			raid5_set_io_opt(conf);
 		}
 	}
 }
--- linux-ein-5.4.0.orig/drivers/media/cec/cec-adap.c
+++ linux-ein-5.4.0/drivers/media/cec/cec-adap.c
@@ -378,7 +378,8 @@
 	} else {
 		list_del_init(&data->list);
 		if (!(data->msg.tx_status & CEC_TX_STATUS_OK))
-			data->adap->transmit_queue_sz--;
+			if (!WARN_ON(!data->adap->transmit_queue_sz))
+				data->adap->transmit_queue_sz--;
 	}
 
 	if (data->msg.tx_status & CEC_TX_STATUS_OK) {
@@ -430,6 +431,14 @@
 		 * need to do anything special in that case.
 		 */
 	}
+	/*
+	 * If something went wrong and this counter isn't what it should
+	 * be, then this will reset it back to 0. Warn if it is not 0,
+	 * since it indicates a bug, either in this framework or in a
+	 * CEC driver.
+	 */
+	if (WARN_ON(adap->transmit_queue_sz))
+		adap->transmit_queue_sz = 0;
 }
 
 /*
@@ -454,7 +463,7 @@
 		bool timeout = false;
 		u8 attempts;
 
-		if (adap->transmitting) {
+		if (adap->transmit_in_progress) {
 			int err;
 
 			/*
@@ -489,7 +498,7 @@
 			goto unlock;
 		}
 
-		if (adap->transmitting && timeout) {
+		if (adap->transmit_in_progress && timeout) {
 			/*
 			 * If we timeout, then log that. Normally this does
 			 * not happen and it is an indication of a faulty CEC
@@ -498,14 +507,18 @@
 			 * so much traffic on the bus that the adapter was
 			 * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s).
 			 */
-			pr_warn("cec-%s: message %*ph timed out\n", adap->name,
-				adap->transmitting->msg.len,
-				adap->transmitting->msg.msg);
+			if (adap->transmitting) {
+				pr_warn("cec-%s: message %*ph timed out\n", adap->name,
+					adap->transmitting->msg.len,
+					adap->transmitting->msg.msg);
+				/* Just give up on this. */
+				cec_data_cancel(adap->transmitting,
+						CEC_TX_STATUS_TIMEOUT);
+			} else {
+				pr_warn("cec-%s: transmit timed out\n", adap->name);
+			}
 			adap->transmit_in_progress = false;
 			adap->tx_timeouts++;
-			/* Just give up on this. */
-			cec_data_cancel(adap->transmitting,
-					CEC_TX_STATUS_TIMEOUT);
 			goto unlock;
 		}
 
@@ -520,7 +533,8 @@
 		data = list_first_entry(&adap->transmit_queue,
 					struct cec_data, list);
 		list_del_init(&data->list);
-		adap->transmit_queue_sz--;
+		if (!WARN_ON(!data->adap->transmit_queue_sz))
+			adap->transmit_queue_sz--;
 
 		/* Make this the current transmitting message */
 		adap->transmitting = data;
@@ -1063,7 +1077,8 @@
 	mutex_lock(&adap->lock);
 	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);
 
-	adap->last_initiator = 0xff;
+	if (!adap->transmit_in_progress)
+		adap->last_initiator = 0xff;
 
 	/* Check if this message was for us (directed or broadcast). */
 	if (!cec_msg_is_broadcast(msg))
@@ -1083,11 +1098,11 @@
 			valid_la = false;
 		else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED))
 			valid_la = false;
-		else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4))
+		else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST))
 			valid_la = false;
 		else if (cec_msg_is_broadcast(msg) &&
-			 adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 &&
-			 !(dir_fl & BCAST2_0))
+			 adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0 &&
+			 !(dir_fl & BCAST1_4))
 			valid_la = false;
 	}
 	if (valid_la && min_len) {
@@ -1177,6 +1192,7 @@
 			if (abort)
 				dst->rx_status |= CEC_RX_STATUS_FEATURE_ABORT;
 			msg->flags = dst->flags;
+			msg->sequence = dst->sequence;
 			/* Remove it from the wait_queue */
 			list_del_init(&data->list);
 
@@ -1248,7 +1264,7 @@
 		 * While trying to poll the physical address was reset
 		 * and the adapter was unconfigured, so bail out.
 		 */
-		if (!adap->is_configuring)
+		if (adap->phys_addr == CEC_PHYS_ADDR_INVALID)
 			return -EINTR;
 
 		if (err)
@@ -1306,7 +1322,6 @@
 	    adap->phys_addr != CEC_PHYS_ADDR_INVALID)
 		WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
 	adap->log_addrs.log_addr_mask = 0;
-	adap->is_configuring = false;
 	adap->is_configured = false;
 	memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs));
 	cec_flush(adap);
@@ -1499,9 +1514,10 @@
 	for (i = 0; i < las->num_log_addrs; i++)
 		las->log_addr[i] = CEC_LOG_ADDR_INVALID;
 	cec_adap_unconfigure(adap);
+	adap->is_configuring = false;
 	adap->kthread_config = NULL;
-	mutex_unlock(&adap->lock);
 	complete(&adap->config_completion);
+	mutex_unlock(&adap->lock);
 	return 0;
 }
 
@@ -1718,6 +1734,10 @@
 		unsigned j;
 
 		log_addrs->log_addr[i] = CEC_LOG_ADDR_INVALID;
+		if (log_addrs->log_addr_type[i] > CEC_LOG_ADDR_TYPE_UNREGISTERED) {
+			dprintk(1, "unknown logical address type\n");
+			return -EINVAL;
+		}
 		if (type_mask & (1 << log_addrs->log_addr_type[i])) {
 			dprintk(1, "duplicate logical address type\n");
 			return -EINVAL;
@@ -1738,10 +1758,6 @@
 			dprintk(1, "invalid primary device type\n");
 			return -EINVAL;
 		}
-		if (log_addrs->log_addr_type[i] > CEC_LOG_ADDR_TYPE_UNREGISTERED) {
-			dprintk(1, "unknown logical address type\n");
-			return -EINVAL;
-		}
 		for (j = 0; j < feature_sz; j++) {
 			if ((features[j] & 0x80) == 0) {
 				if (op_is_dev_features)
--- linux-ein-5.4.0.orig/drivers/media/cec/cec-api.c
+++ linux-ein-5.4.0/drivers/media/cec/cec-api.c
@@ -147,7 +147,13 @@
 	struct cec_log_addrs log_addrs;
 
 	mutex_lock(&adap->lock);
-	log_addrs = adap->log_addrs;
+	/*
+	 * We use memcpy here instead of assignment since there is a
+	 * hole at the end of struct cec_log_addrs that an assignment
+	 * might ignore. So when we do copy_to_user() we could leak
+	 * one byte of memory.
+	 */
+	memcpy(&log_addrs, &adap->log_addrs, sizeof(log_addrs));
 	if (!adap->is_configured)
 		memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID,
 		       sizeof(log_addrs.log_addr));
--- linux-ein-5.4.0.orig/drivers/media/common/saa7146/saa7146_fops.c
+++ linux-ein-5.4.0/drivers/media/common/saa7146/saa7146_fops.c
@@ -525,7 +525,7 @@
 		ERR("out of memory. aborting.\n");
 		kfree(vv);
 		v4l2_ctrl_handler_free(hdl);
-		return -1;
+		return -ENOMEM;
 	}
 
 	saa7146_video_uops.init(dev,vv);
--- linux-ein-5.4.0.orig/drivers/media/common/siano/smscoreapi.c
+++ linux-ein-5.4.0/drivers/media/common/siano/smscoreapi.c
@@ -908,7 +908,7 @@
 					 void *buffer, size_t size)
 {
 	struct sms_firmware *firmware = (struct sms_firmware *) buffer;
-	struct sms_msg_data4 *msg;
+	struct sms_msg_data5 *msg;
 	u32 mem_address,  calc_checksum = 0;
 	u32 i, *ptr;
 	u8 *payload = firmware->payload;
@@ -989,24 +989,20 @@
 		goto exit_fw_download;
 
 	if (coredev->mode == DEVICE_MODE_NONE) {
-		struct sms_msg_data *trigger_msg =
-			(struct sms_msg_data *) msg;
-
 		pr_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ\n");
 		SMS_INIT_MSG(&msg->x_msg_header,
 				MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
-				sizeof(struct sms_msg_hdr) +
-				sizeof(u32) * 5);
+				sizeof(*msg));
 
-		trigger_msg->msg_data[0] = firmware->start_address;
+		msg->msg_data[0] = firmware->start_address;
 					/* Entry point */
-		trigger_msg->msg_data[1] = 6; /* Priority */
-		trigger_msg->msg_data[2] = 0x200; /* Stack size */
-		trigger_msg->msg_data[3] = 0; /* Parameter */
-		trigger_msg->msg_data[4] = 4; /* Task ID */
+		msg->msg_data[1] = 6; /* Priority */
+		msg->msg_data[2] = 0x200; /* Stack size */
+		msg->msg_data[3] = 0; /* Parameter */
+		msg->msg_data[4] = 4; /* Task ID */
 
-		rc = smscore_sendrequest_and_wait(coredev, trigger_msg,
-					trigger_msg->x_msg_header.msg_length,
+		rc = smscore_sendrequest_and_wait(coredev, msg,
+					msg->x_msg_header.msg_length,
 					&coredev->trigger_done);
 	} else {
 		SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ,
--- linux-ein-5.4.0.orig/drivers/media/common/siano/smscoreapi.h
+++ linux-ein-5.4.0/drivers/media/common/siano/smscoreapi.h
@@ -629,9 +629,9 @@
 	u32 msg_data[2];
 };
 
-struct sms_msg_data4 {
+struct sms_msg_data5 {
 	struct sms_msg_hdr x_msg_header;
-	u32 msg_data[4];
+	u32 msg_data[5];
 };
 
 struct sms_data_download {
--- linux-ein-5.4.0.orig/drivers/media/common/siano/smsdvb-main.c
+++ linux-ein-5.4.0/drivers/media/common/siano/smsdvb-main.c
@@ -1169,12 +1169,19 @@
 	rc = dvb_create_media_graph(&client->adapter, true);
 	if (rc < 0) {
 		pr_err("dvb_create_media_graph failed %d\n", rc);
-		goto client_error;
+		goto media_graph_error;
 	}
 
 	pr_info("DVB interface registered.\n");
 	return 0;
 
+media_graph_error:
+	mutex_lock(&g_smsdvb_clientslock);
+	list_del(&client->entry);
+	mutex_unlock(&g_smsdvb_clientslock);
+
+	smsdvb_debugfs_release(client);
+
 client_error:
 	dvb_unregister_frontend(&client->frontend);
 
--- linux-ein-5.4.0.orig/drivers/media/common/videobuf2/videobuf2-core.c
+++ linux-ein-5.4.0/drivers/media/common/videobuf2/videobuf2-core.c
@@ -1512,6 +1512,7 @@
 		  struct media_request *req)
 {
 	struct vb2_buffer *vb;
+	enum vb2_buffer_state orig_state;
 	int ret;
 
 	if (q->error) {
@@ -1611,6 +1612,7 @@
 	 * Add to the queued buffers list, a buffer will stay on it until
 	 * dequeued in dqbuf.
 	 */
+	orig_state = vb->state;
 	list_add_tail(&vb->queued_entry, &q->queued_list);
 	q->queued_count++;
 	q->waiting_for_buffers = false;
@@ -1641,8 +1643,17 @@
 	if (q->streaming && !q->start_streaming_called &&
 	    q->queued_count >= q->min_buffers_needed) {
 		ret = vb2_start_streaming(q);
-		if (ret)
+		if (ret) {
+			/*
+			 * Since vb2_core_qbuf will return with an error,
+			 * we should return it to state DEQUEUED since
+			 * the error indicates that the buffer wasn't queued.
+			 */
+			list_del(&vb->queued_entry);
+			q->queued_count--;
+			vb->state = orig_state;
 			return ret;
+		}
 	}
 
 	dprintk(2, "qbuf of buffer %d succeeded\n", vb->index);
--- linux-ein-5.4.0.orig/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ linux-ein-5.4.0/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -154,7 +154,7 @@
 	buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,
 					GFP_KERNEL | gfp_flags, buf->attrs);
 	if (!buf->cookie) {
-		dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
+		dev_err(dev, "dma_alloc_coherent of size %lu failed\n", size);
 		kfree(buf);
 		return ERR_PTR(-ENOMEM);
 	}
@@ -200,9 +200,9 @@
 
 	vma->vm_ops->open(vma);
 
-	pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n",
-		__func__, (unsigned long)buf->dma_addr, vma->vm_start,
-		buf->size);
+	pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %lu\n",
+		 __func__, (unsigned long)buf->dma_addr, vma->vm_start,
+		 buf->size);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dmxdev.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dmxdev.c
@@ -800,6 +800,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;
@@ -1413,7 +1418,7 @@
 };
 int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
-	int i;
+	int i, ret;
 
 	if (dmxdev->demux->open(dmxdev->demux) < 0)
 		return -EUSERS;
@@ -1432,21 +1437,36 @@
 					    DMXDEV_STATE_FREE);
 	}
 
-	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+	ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
 			    DVB_DEVICE_DEMUX, dmxdev->filternum);
-	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+	if (ret < 0)
+		goto err_register_dvbdev;
+
+	ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
 			    dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
+	if (ret < 0)
+		goto err_register_dvr_dvbdev;
 
 	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
 
 	return 0;
+
+err_register_dvr_dvbdev:
+	dvb_unregister_device(dmxdev->dvbdev);
+err_register_dvbdev:
+	vfree(dmxdev->filter);
+	dmxdev->filter = NULL;
+	return ret;
 }
 
 EXPORT_SYMBOL(dvb_dmxdev_init);
 
 void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
+	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-ein-5.4.0.orig/drivers/media/dvb-core/dvb_ca_en50221.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -151,13 +151,19 @@
 
 	/* mutex serializing ioctls */
 	struct mutex ioctl_mutex;
+
+	/* A mutex used when a device is disconnected */
+	struct mutex remove_mutex;
+
+	/* Whether the device is disconnected */
+	int exit;
 };
 
 static void dvb_ca_private_free(struct dvb_ca_private *ca)
 {
 	unsigned int i;
 
-	dvb_free_device(ca->dvbdev);
+	dvb_device_put(ca->dvbdev);
 	for (i = 0; i < ca->slot_count; i++)
 		vfree(ca->slot_info[i].rx_buffer.data);
 
@@ -187,7 +193,7 @@
 static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
 				    u8 *ebuf, int ecount);
 static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
-				     u8 *ebuf, int ecount);
+				     u8 *ebuf, int ecount, int size_write_flag);
 
 /**
  * Safely find needle in haystack.
@@ -370,7 +376,7 @@
 	ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
 	if (ret)
 		return ret;
-	ret = dvb_ca_en50221_write_data(ca, slot, buf, 2);
+	ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW);
 	if (ret != 2)
 		return -EIO;
 	ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
@@ -778,11 +784,13 @@
  * @buf: The data in this buffer is treated as a complete link-level packet to
  *	 be written.
  * @bytes_write: Size of ebuf.
+ * @size_write_flag: A flag on Command Register which says whether the link size
+ * information will be writen or not.
  *
  * return: Number of bytes written, or < 0 on error.
  */
 static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
-				     u8 *buf, int bytes_write)
+				     u8 *buf, int bytes_write, int size_write_flag)
 {
 	struct dvb_ca_slot *sl = &ca->slot_info[slot];
 	int status;
@@ -817,7 +825,7 @@
 
 	/* OK, set HC bit */
 	status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
-					    IRQEN | CMDREG_HC);
+					    IRQEN | CMDREG_HC | size_write_flag);
 	if (status)
 		goto exit;
 
@@ -1505,7 +1513,7 @@
 
 			mutex_lock(&sl->slot_lock);
 			status = dvb_ca_en50221_write_data(ca, slot, fragbuf,
-							   fraglen + 2);
+							   fraglen + 2, 0);
 			mutex_unlock(&sl->slot_lock);
 			if (status == (fraglen + 2)) {
 				written = 1;
@@ -1706,12 +1714,22 @@
 
 	dprintk("%s\n", __func__);
 
-	if (!try_module_get(ca->pub->owner))
+	mutex_lock(&ca->remove_mutex);
+
+	if (ca->exit) {
+		mutex_unlock(&ca->remove_mutex);
+		return -ENODEV;
+	}
+
+	if (!try_module_get(ca->pub->owner)) {
+		mutex_unlock(&ca->remove_mutex);
 		return -EIO;
+	}
 
 	err = dvb_generic_open(inode, file);
 	if (err < 0) {
 		module_put(ca->pub->owner);
+		mutex_unlock(&ca->remove_mutex);
 		return err;
 	}
 
@@ -1736,6 +1754,7 @@
 
 	dvb_ca_private_get(ca);
 
+	mutex_unlock(&ca->remove_mutex);
 	return 0;
 }
 
@@ -1755,6 +1774,8 @@
 
 	dprintk("%s\n", __func__);
 
+	mutex_lock(&ca->remove_mutex);
+
 	/* mark the CA device as closed */
 	ca->open = 0;
 	dvb_ca_en50221_thread_update_delay(ca);
@@ -1765,6 +1786,13 @@
 
 	dvb_ca_private_put(ca);
 
+	if (dvbdev->users == 1 && ca->exit == 1) {
+		mutex_unlock(&ca->remove_mutex);
+		wake_up(&dvbdev->wait_queue);
+	} else {
+		mutex_unlock(&ca->remove_mutex);
+	}
+
 	return err;
 }
 
@@ -1888,6 +1916,7 @@
 	}
 
 	mutex_init(&ca->ioctl_mutex);
+	mutex_init(&ca->remove_mutex);
 
 	if (signal_pending(current)) {
 		ret = -EINTR;
@@ -1930,6 +1959,14 @@
 
 	dprintk("%s\n", __func__);
 
+	mutex_lock(&ca->remove_mutex);
+	ca->exit = 1;
+	mutex_unlock(&ca->remove_mutex);
+
+	if (ca->dvbdev->users < 1)
+		wait_event(ca->dvbdev->wait_queue,
+				ca->dvbdev->users == 1);
+
 	/* shutdown the thread if there was one */
 	kthread_stop(ca->thread);
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dvb_demux.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvb_demux.c
@@ -125,12 +125,12 @@
 
 	cc = buf[3] & 0x0f;
 	ccok = ((feed->cc + 1) & 0x0f) == cc;
-	feed->cc = cc;
 	if (!ccok) {
 		set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
 		dprintk_sect_loss("missed packet: %d instead of %d!\n",
 				  cc, (feed->cc + 1) & 0x0f);
 	}
+	feed->cc = cc;
 
 	if (buf[1] & 0x40)	// PUSI ?
 		feed->peslen = 0xfffa;
@@ -310,7 +310,6 @@
 
 	cc = buf[3] & 0x0f;
 	ccok = ((feed->cc + 1) & 0x0f) == cc;
-	feed->cc = cc;
 
 	if (buf[3] & 0x20) {
 		/* adaption field present, check for discontinuity_indicator */
@@ -346,6 +345,7 @@
 		feed->pusi_seen = false;
 		dvb_dmx_swfilter_section_new(feed);
 	}
+	feed->cc = cc;
 
 	if (buf[1] & 0x40) {
 		/* PUSI=1 (is set), section boundary is here */
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dvb_frontend.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvb_frontend.c
@@ -135,7 +135,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	if (fepriv)
-		dvb_free_device(fepriv->dvbdev);
+		dvb_device_put(fepriv->dvbdev);
 
 	dvb_frontend_invoke_release(fe, fe->ops.release);
 
@@ -292,14 +292,22 @@
 	}
 
 	if (events->eventw == events->eventr) {
-		int ret;
+		struct wait_queue_entry wait;
+		int ret = 0;
 
 		if (flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 
-		ret = wait_event_interruptible(events->wait_queue,
-					       dvb_frontend_test_event(fepriv, events));
-
+		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;
 	}
@@ -2961,6 +2969,7 @@
 		.name = fe->ops.info.name,
 #endif
 	};
+	int ret;
 
 	dev_dbg(dvb->device, "%s:\n", __func__);
 
@@ -2994,8 +3003,13 @@
 		 "DVB: registering adapter %i frontend %i (%s)...\n",
 		 fe->dvb->num, fe->id, fe->ops.info.name);
 
-	dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+	ret = dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			    fe, DVB_DEVICE_FRONTEND, 0);
+	if (ret) {
+		dvb_frontend_put(fe);
+		mutex_unlock(&frontend_mutex);
+		return ret;
+	}
 
 	/*
 	 * Initialize the cache to the proper values according with the
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dvb_net.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvb_net.c
@@ -45,6 +45,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/nospec.h>
 #include <linux/etherdevice.h>
 #include <linux/dvb/net.h>
 #include <linux/uio.h>
@@ -1462,14 +1463,20 @@
 		struct net_device *netdev;
 		struct dvb_net_priv *priv_data;
 		struct dvb_net_if *dvbnetif = parg;
+		int if_num = dvbnetif->if_num;
 
-		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-		    !dvbnet->state[dvbnetif->if_num]) {
+		if (if_num >= DVB_NET_DEVICES_MAX) {
 			ret = -EINVAL;
 			goto ioctl_error;
 		}
+		if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
 
-		netdev = dvbnet->device[dvbnetif->if_num];
+		if (!dvbnet->state[if_num]) {
+			ret = -EINVAL;
+			goto ioctl_error;
+		}
+
+		netdev = dvbnet->device[if_num];
 
 		priv_data = netdev_priv(netdev);
 		dvbnetif->pid=priv_data->pid;
@@ -1522,14 +1529,20 @@
 		struct net_device *netdev;
 		struct dvb_net_priv *priv_data;
 		struct __dvb_net_if_old *dvbnetif = parg;
+		int if_num = dvbnetif->if_num;
+
+		if (if_num >= DVB_NET_DEVICES_MAX) {
+			ret = -EINVAL;
+			goto ioctl_error;
+		}
+		if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
 
-		if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-		    !dvbnet->state[dvbnetif->if_num]) {
+		if (!dvbnet->state[if_num]) {
 			ret = -EINVAL;
 			goto ioctl_error;
 		}
 
-		netdev = dvbnet->device[dvbnetif->if_num];
+		netdev = dvbnet->device[if_num];
 
 		priv_data = netdev_priv(netdev);
 		dvbnetif->pid=priv_data->pid;
@@ -1551,15 +1564,43 @@
 	return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
 }
 
+static int locked_dvb_net_open(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_net *dvbnet = dvbdev->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&dvbnet->remove_mutex))
+		return -ERESTARTSYS;
+
+	if (dvbnet->exit) {
+		mutex_unlock(&dvbnet->remove_mutex);
+		return -ENODEV;
+	}
+
+	ret = dvb_generic_open(inode, file);
+
+	mutex_unlock(&dvbnet->remove_mutex);
+
+	return ret;
+}
+
 static int dvb_net_close(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_net *dvbnet = dvbdev->priv;
 
+	mutex_lock(&dvbnet->remove_mutex);
+
 	dvb_generic_release(inode, file);
 
-	if(dvbdev->users == 1 && dvbnet->exit == 1)
+	if (dvbdev->users == 1 && dvbnet->exit == 1) {
+		mutex_unlock(&dvbnet->remove_mutex);
 		wake_up(&dvbdev->wait_queue);
+	} else {
+		mutex_unlock(&dvbnet->remove_mutex);
+	}
+
 	return 0;
 }
 
@@ -1567,7 +1608,7 @@
 static const struct file_operations dvb_net_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = dvb_net_ioctl,
-	.open =	dvb_generic_open,
+	.open =	locked_dvb_net_open,
 	.release = dvb_net_close,
 	.llseek = noop_llseek,
 };
@@ -1586,10 +1627,13 @@
 {
 	int i;
 
+	mutex_lock(&dvbnet->remove_mutex);
 	dvbnet->exit = 1;
+	mutex_unlock(&dvbnet->remove_mutex);
+
 	if (dvbnet->dvbdev->users < 1)
 		wait_event(dvbnet->dvbdev->wait_queue,
-				dvbnet->dvbdev->users==1);
+				dvbnet->dvbdev->users == 1);
 
 	dvb_unregister_device(dvbnet->dvbdev);
 
@@ -1608,6 +1652,7 @@
 	int i;
 
 	mutex_init(&dvbnet->ioctl_mutex);
+	mutex_init(&dvbnet->remove_mutex);
 	dvbnet->demux = dmx;
 
 	for (i=0; i<DVB_NET_DEVICES_MAX; i++)
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dvb_vb2.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvb_vb2.c
@@ -358,6 +358,12 @@
 
 int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
 {
+	struct vb2_queue *q = &ctx->vb_q;
+
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "[%s] buffer index out of range\n", ctx->name);
+		return -EINVAL;
+	}
 	vb2_core_querybuf(&ctx->vb_q, b->index, b);
 	dprintk(3, "[%s] index=%d\n", ctx->name, b->index);
 	return 0;
@@ -382,8 +388,13 @@
 
 int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
 {
+	struct vb2_queue *q = &ctx->vb_q;
 	int ret;
 
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "[%s] buffer index out of range\n", ctx->name);
+		return -EINVAL;
+	}
 	ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL);
 	if (ret) {
 		dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
--- linux-ein-5.4.0.orig/drivers/media/dvb-core/dvbdev.c
+++ linux-ein-5.4.0/drivers/media/dvb-core/dvbdev.c
@@ -37,6 +37,7 @@
 #include <media/tuner.h>
 
 static DEFINE_MUTEX(dvbdev_mutex);
+static LIST_HEAD(dvbdevfops_list);
 static int dvbdev_debug;
 
 module_param(dvbdev_debug, int, 0644);
@@ -107,12 +108,14 @@
 		new_fops = fops_get(dvbdev->fops);
 		if (!new_fops)
 			goto fail;
-		file->private_data = dvbdev;
+		file->private_data = dvb_device_get(dvbdev);
 		replace_fops(file, new_fops);
 		if (file->f_op->open)
 			err = file->f_op->open(inode, file);
 		up_read(&minor_rwsem);
 		mutex_unlock(&dvbdev_mutex);
+		if (err)
+			dvb_device_put(dvbdev);
 		return err;
 	}
 fail:
@@ -171,6 +174,9 @@
 	}
 
 	dvbdev->users++;
+
+	dvb_device_put(dvbdev);
+
 	return 0;
 }
 EXPORT_SYMBOL(dvb_generic_release);
@@ -241,6 +247,7 @@
 
 	if (dvbdev->adapter->conn) {
 		media_device_unregister_entity(dvbdev->adapter->conn);
+		kfree(dvbdev->adapter->conn);
 		dvbdev->adapter->conn = NULL;
 		kfree(dvbdev->adapter->conn_pads);
 		dvbdev->adapter->conn_pads = NULL;
@@ -341,6 +348,7 @@
 				       GFP_KERNEL);
 		if (!dvbdev->pads) {
 			kfree(dvbdev->entity);
+			dvbdev->entity = NULL;
 			return -ENOMEM;
 		}
 	}
@@ -457,14 +465,15 @@
 			enum dvb_device_type type, int demux_sink_pads)
 {
 	struct dvb_device *dvbdev;
-	struct file_operations *dvbdevfops;
+	struct file_operations *dvbdevfops = NULL;
+	struct dvbdevfops_node *node = NULL, *new_node = NULL;
 	struct device *clsdev;
 	int minor;
 	int id, ret;
 
 	mutex_lock(&dvbdev_register_lock);
 
-	if ((id = dvbdev_get_free_id (adap, type)) < 0){
+	if ((id = dvbdev_get_free_id (adap, type)) < 0) {
 		mutex_unlock(&dvbdev_register_lock);
 		*pdvbdev = NULL;
 		pr_err("%s: couldn't find free device id\n", __func__);
@@ -472,40 +481,69 @@
 	}
 
 	*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
-
 	if (!dvbdev){
 		mutex_unlock(&dvbdev_register_lock);
 		return -ENOMEM;
 	}
 
-	dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+	/*
+	 * When a device of the same type is probe()d more than once,
+	 * the first allocated fops are used. This prevents memory leaks
+	 * that can occur when the same device is probe()d repeatedly.
+	 */
+	list_for_each_entry(node, &dvbdevfops_list, list_head) {
+		if (node->fops->owner == adap->module &&
+				node->type == type &&
+				node->template == template) {
+			dvbdevfops = node->fops;
+			break;
+		}
+	}
 
-	if (!dvbdevfops){
-		kfree (dvbdev);
-		mutex_unlock(&dvbdev_register_lock);
-		return -ENOMEM;
+	if (dvbdevfops == NULL) {
+		dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+		if (!dvbdevfops) {
+			kfree(dvbdev);
+			mutex_unlock(&dvbdev_register_lock);
+			return -ENOMEM;
+		}
+
+		new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL);
+		if (!new_node) {
+			kfree(dvbdevfops);
+			kfree(dvbdev);
+			mutex_unlock(&dvbdev_register_lock);
+			return -ENOMEM;
+		}
+
+		new_node->fops = dvbdevfops;
+		new_node->type = type;
+		new_node->template = template;
+		list_add_tail (&new_node->list_head, &dvbdevfops_list);
 	}
 
 	memcpy(dvbdev, template, sizeof(struct dvb_device));
+	kref_init(&dvbdev->ref);
 	dvbdev->type = type;
 	dvbdev->id = id;
 	dvbdev->adapter = adap;
 	dvbdev->priv = priv;
 	dvbdev->fops = dvbdevfops;
 	init_waitqueue_head (&dvbdev->wait_queue);
-
 	dvbdevfops->owner = adap->module;
-
 	list_add_tail (&dvbdev->list_head, &adap->device_list);
-
 	down_write(&minor_rwsem);
 #ifdef CONFIG_DVB_DYNAMIC_MINORS
 	for (minor = 0; minor < MAX_DVB_MINORS; minor++)
 		if (dvb_minors[minor] == NULL)
 			break;
-
 	if (minor == MAX_DVB_MINORS) {
-		kfree(dvbdevfops);
+		if (new_node) {
+			list_del (&new_node->list_head);
+			kfree(dvbdevfops);
+			kfree(new_node);
+		}
+		list_del (&dvbdev->list_head);
 		kfree(dvbdev);
 		up_write(&minor_rwsem);
 		mutex_unlock(&dvbdev_register_lock);
@@ -514,36 +552,47 @@
 #else
 	minor = nums2minor(adap->num, type, id);
 #endif
-
 	dvbdev->minor = minor;
-	dvb_minors[minor] = dvbdev;
+	dvb_minors[minor] = dvb_device_get(dvbdev);
 	up_write(&minor_rwsem);
-
 	ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
 	if (ret) {
 		pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
 		      __func__);
-
+		if (new_node) {
+			list_del (&new_node->list_head);
+			kfree(dvbdevfops);
+			kfree(new_node);
+		}
 		dvb_media_device_free(dvbdev);
-		kfree(dvbdevfops);
+		list_del (&dvbdev->list_head);
 		kfree(dvbdev);
 		mutex_unlock(&dvbdev_register_lock);
 		return ret;
 	}
 
-	mutex_unlock(&dvbdev_register_lock);
-
 	clsdev = device_create(dvb_class, adap->device,
 			       MKDEV(DVB_MAJOR, minor),
 			       dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
 	if (IS_ERR(clsdev)) {
 		pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
 		       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+		if (new_node) {
+			list_del (&new_node->list_head);
+			kfree(dvbdevfops);
+			kfree(new_node);
+		}
+		dvb_media_device_free(dvbdev);
+		list_del (&dvbdev->list_head);
+		kfree(dvbdev);
+		mutex_unlock(&dvbdev_register_lock);
 		return PTR_ERR(clsdev);
 	}
+
 	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, minor, minor);
 
+	mutex_unlock(&dvbdev_register_lock);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_register_device);
@@ -556,6 +605,7 @@
 
 	down_write(&minor_rwsem);
 	dvb_minors[dvbdev->minor] = NULL;
+	dvb_device_put(dvbdev);
 	up_write(&minor_rwsem);
 
 	dvb_media_device_free(dvbdev);
@@ -567,21 +617,33 @@
 EXPORT_SYMBOL(dvb_remove_device);
 
 
-void dvb_free_device(struct dvb_device *dvbdev)
+static void dvb_free_device(struct kref *ref)
 {
-	if (!dvbdev)
-		return;
+	struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
 
-	kfree (dvbdev->fops);
 	kfree (dvbdev);
 }
-EXPORT_SYMBOL(dvb_free_device);
+
+
+struct dvb_device *dvb_device_get(struct dvb_device *dvbdev)
+{
+	kref_get(&dvbdev->ref);
+	return dvbdev;
+}
+EXPORT_SYMBOL(dvb_device_get);
+
+
+void dvb_device_put(struct dvb_device *dvbdev)
+{
+	if (dvbdev)
+		kref_put(&dvbdev->ref, dvb_free_device);
+}
 
 
 void dvb_unregister_device(struct dvb_device *dvbdev)
 {
 	dvb_remove_device(dvbdev);
-	dvb_free_device(dvbdev);
+	dvb_device_put(dvbdev);
 }
 EXPORT_SYMBOL(dvb_unregister_device);
 
@@ -707,9 +769,10 @@
 	}
 
 	if (ntuner && ndemod) {
-		pad_source = media_get_pad_index(tuner, true,
+		/* NOTE: first found tuner source pad presumed correct */
+		pad_source = media_get_pad_index(tuner, false,
 						 PAD_SIGNAL_ANALOG);
-		if (pad_source)
+		if (pad_source < 0)
 			return -EINVAL;
 		ret = media_create_pad_links(mdev,
 					     MEDIA_ENT_F_TUNER,
@@ -1063,9 +1126,17 @@
 
 static void __exit exit_dvbdev(void)
 {
+	struct dvbdevfops_node *node, *next;
+
 	class_destroy(dvb_class);
 	cdev_del(&dvb_device_cdev);
 	unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+
+	list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
+		list_del (&node->list_head);
+		kfree(node->fops);
+		kfree(node);
+	}
 }
 
 subsys_initcall(init_dvbdev);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ascot2e.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ascot2e.c
@@ -533,7 +533,7 @@
 		priv->i2c_address, priv->i2c);
 	return fe;
 }
-EXPORT_SYMBOL(ascot2e_attach);
+EXPORT_SYMBOL_GPL(ascot2e_attach);
 
 MODULE_DESCRIPTION("Sony ASCOT2E terr/cab tuner driver");
 MODULE_AUTHOR("info@netup.ru");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/atbm8830.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/atbm8830.c
@@ -489,7 +489,7 @@
 	return NULL;
 
 }
-EXPORT_SYMBOL(atbm8830_attach);
+EXPORT_SYMBOL_GPL(atbm8830_attach);
 
 MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
 MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/au8522_dig.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/au8522_dig.c
@@ -879,7 +879,7 @@
 	au8522_release_state(state);
 	return NULL;
 }
-EXPORT_SYMBOL(au8522_attach);
+EXPORT_SYMBOL_GPL(au8522_attach);
 
 static const struct dvb_frontend_ops au8522_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/bcm3510.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/bcm3510.c
@@ -649,6 +649,7 @@
 		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
 		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
 			err("firmware download failed: %d\n",ret);
+			release_firmware(fw);
 			return ret;
 		}
 		i += 4 + len;
@@ -834,7 +835,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(bcm3510_attach);
+EXPORT_SYMBOL_GPL(bcm3510_attach);
 
 static const struct dvb_frontend_ops bcm3510_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx22700.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx22700.c
@@ -432,4 +432,4 @@
 MODULE_AUTHOR("Holger Waechtler");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cx22700_attach);
+EXPORT_SYMBOL_GPL(cx22700_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx22702.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx22702.c
@@ -604,7 +604,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(cx22702_attach);
+EXPORT_SYMBOL_GPL(cx22702_attach);
 
 static const struct dvb_frontend_ops cx22702_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx24110.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx24110.c
@@ -653,4 +653,4 @@
 MODULE_AUTHOR("Peter Hettkamp");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cx24110_attach);
+EXPORT_SYMBOL_GPL(cx24110_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx24113.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx24113.c
@@ -590,7 +590,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(cx24113_attach);
+EXPORT_SYMBOL_GPL(cx24113_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx24116.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx24116.c
@@ -1133,7 +1133,7 @@
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 }
-EXPORT_SYMBOL(cx24116_attach);
+EXPORT_SYMBOL_GPL(cx24116_attach);
 
 /*
  * Initialise or wake up device
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx24120.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx24120.c
@@ -305,7 +305,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(cx24120_attach);
+EXPORT_SYMBOL_GPL(cx24120_attach);
 
 static int cx24120_test_rom(struct cx24120_state *state)
 {
@@ -972,7 +972,9 @@
 	cmd.arg[8] = (clock_ratios_table[idx].rate >> 8) & 0xff;
 	cmd.arg[9] = (clock_ratios_table[idx].rate >> 0) & 0xff;
 
-	cx24120_message_send(state, &cmd);
+	ret = cx24120_message_send(state, &cmd);
+	if (ret != 0)
+		return;
 
 	/* Calculate ber window rates for stat work */
 	cx24120_calculate_ber_window(state, clock_ratios_table[idx].rate);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cx24123.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cx24123.c
@@ -1096,7 +1096,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(cx24123_attach);
+EXPORT_SYMBOL_GPL(cx24123_attach);
 
 static const struct dvb_frontend_ops cx24123_ops = {
 	.delsys = { SYS_DVBS },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cxd2820r_core.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -536,7 +536,7 @@
 
 	return pdata.get_dvb_frontend(client);
 }
-EXPORT_SYMBOL(cxd2820r_attach);
+EXPORT_SYMBOL_GPL(cxd2820r_attach);
 
 static struct dvb_frontend *cxd2820r_get_dvb_frontend(struct i2c_client *client)
 {
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cxd2841er.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cxd2841er.c
@@ -3920,14 +3920,14 @@
 {
 	return cxd2841er_attach(cfg, i2c, SYS_DVBS);
 }
-EXPORT_SYMBOL(cxd2841er_attach_s);
+EXPORT_SYMBOL_GPL(cxd2841er_attach_s);
 
 struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg,
 					struct i2c_adapter *i2c)
 {
 	return cxd2841er_attach(cfg, i2c, 0);
 }
-EXPORT_SYMBOL(cxd2841er_attach_t_c);
+EXPORT_SYMBOL_GPL(cxd2841er_attach_t_c);
 
 static const struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = {
 	.delsys = { SYS_DVBS, SYS_DVBS2 },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -1950,7 +1950,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(cxd2880_attach);
+EXPORT_SYMBOL_GPL(cxd2880_attach);
 
 MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver");
 MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib0070.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib0070.c
@@ -755,7 +755,7 @@
 	fe->tuner_priv = NULL;
 	return NULL;
 }
-EXPORT_SYMBOL(dib0070_attach);
+EXPORT_SYMBOL_GPL(dib0070_attach);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib0090.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib0090.c
@@ -2631,7 +2631,7 @@
 	return NULL;
 }
 
-EXPORT_SYMBOL(dib0090_register);
+EXPORT_SYMBOL_GPL(dib0090_register);
 
 struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
 {
@@ -2657,7 +2657,7 @@
 	fe->tuner_priv = NULL;
 	return NULL;
 }
-EXPORT_SYMBOL(dib0090_fw_register);
+EXPORT_SYMBOL_GPL(dib0090_fw_register);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib3000mb.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib3000mb.c
@@ -815,4 +815,4 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(dib3000mb_attach);
+EXPORT_SYMBOL_GPL(dib3000mb_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib3000mc.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib3000mc.c
@@ -935,7 +935,7 @@
 	kfree(st);
 	return NULL;
 }
-EXPORT_SYMBOL(dib3000mc_attach);
+EXPORT_SYMBOL_GPL(dib3000mc_attach);
 
 static const struct dvb_frontend_ops dib3000mc_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib7000m.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib7000m.c
@@ -1434,7 +1434,7 @@
 	kfree(st);
 	return NULL;
 }
-EXPORT_SYMBOL(dib7000m_attach);
+EXPORT_SYMBOL_GPL(dib7000m_attach);
 
 static const struct dvb_frontend_ops dib7000m_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib7000p.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib7000p.c
@@ -497,7 +497,7 @@
 	prediv = reg_1856 & 0x3f;
 	loopdiv = (reg_1856 >> 6) & 0x3f;
 
-	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
+	if (loopdiv && bw && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
 		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
 		reg_1856 &= 0xf000;
 		reg_1857 = dib7000p_read_word(state, 1857);
@@ -2822,7 +2822,7 @@
 
 	return ops;
 }
-EXPORT_SYMBOL(dib7000p_attach);
+EXPORT_SYMBOL_GPL(dib7000p_attach);
 
 static const struct dvb_frontend_ops dib7000p_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib8000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib8000.c
@@ -2107,32 +2107,55 @@
 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
 }
 
-static const u16 lut_prbs_2k[14] = {
-	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
+static const u16 lut_prbs_2k[13] = {
+	0x423, 0x009, 0x5C7,
+	0x7A6, 0x3D8, 0x527,
+	0x7FF, 0x79B, 0x3D6,
+	0x3A2, 0x53B, 0x2F4,
+	0x213
 };
-static const u16 lut_prbs_4k[14] = {
-	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
+
+static const u16 lut_prbs_4k[13] = {
+	0x208, 0x0C3, 0x7B9,
+	0x423, 0x5C7, 0x3D8,
+	0x7FF, 0x3D6, 0x53B,
+	0x213, 0x029, 0x0D0,
+	0x48E
 };
-static const u16 lut_prbs_8k[14] = {
-	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
+
+static const u16 lut_prbs_8k[13] = {
+	0x740, 0x069, 0x7DD,
+	0x208, 0x7B9, 0x5C7,
+	0x7FF, 0x53B, 0x029,
+	0x48E, 0x4C4, 0x367,
+	0x684
 };
 
 static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
 {
 	int sub_channel_prbs_group = 0;
+	int prbs_group;
 
-	sub_channel_prbs_group = (subchannel / 3) + 1;
-	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
+	sub_channel_prbs_group = subchannel / 3;
+	if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k))
+		return 0;
 
 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
 	case TRANSMISSION_MODE_2K:
-			return lut_prbs_2k[sub_channel_prbs_group];
+		prbs_group = lut_prbs_2k[sub_channel_prbs_group];
+		break;
 	case TRANSMISSION_MODE_4K:
-			return lut_prbs_4k[sub_channel_prbs_group];
+		prbs_group =  lut_prbs_4k[sub_channel_prbs_group];
+		break;
 	default:
 	case TRANSMISSION_MODE_8K:
-			return lut_prbs_8k[sub_channel_prbs_group];
+		prbs_group = lut_prbs_8k[sub_channel_prbs_group];
 	}
+
+	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n",
+		sub_channel_prbs_group, subchannel, prbs_group);
+
+	return prbs_group;
 }
 
 static void dib8000_set_13seg_channel(struct dib8000_state *state)
@@ -2409,10 +2432,8 @@
 	/* TSB or ISDBT ? apply it now */
 	if (c->isdbt_sb_mode) {
 		dib8000_set_sb_channel(state);
-		if (c->isdbt_sb_subchannel < 14)
-			init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
-		else
-			init_prbs = 0;
+		init_prbs = dib8000_get_init_prbs(state,
+						  c->isdbt_sb_subchannel);
 	} else {
 		dib8000_set_13seg_channel(state);
 		init_prbs = 0xfff;
@@ -3004,6 +3025,7 @@
 
 	unsigned long *timeout = &state->timeout;
 	unsigned long now = jiffies;
+	u16 init_prbs;
 #ifdef DIB8000_AGC_FREEZE
 	u16 agc1, agc2;
 #endif
@@ -3302,8 +3324,10 @@
 		break;
 
 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
-		if (state->subchannel <= 41) {
-			dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
+		init_prbs = dib8000_get_init_prbs(state, state->subchannel);
+
+		if (init_prbs) {
+			dib8000_set_subchannel_prbs(state, init_prbs);
 			*tune_state = CT_DEMOD_STEP_9;
 		} else {
 			*tune_state = CT_DEMOD_STOP;
@@ -4449,8 +4473,10 @@
 
 	state->timf_default = cfg->pll->timf;
 
-	if (dib8000_identify(&state->i2c) == 0)
+	if (dib8000_identify(&state->i2c) == 0) {
+		kfree(fe);
 		goto error;
+	}
 
 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
 
@@ -4501,7 +4527,7 @@
 
 	return ops;
 }
-EXPORT_SYMBOL(dib8000_attach);
+EXPORT_SYMBOL_GPL(dib8000_attach);
 
 MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
 MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dib9000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dib9000.c
@@ -2546,7 +2546,7 @@
 	kfree(st);
 	return NULL;
 }
-EXPORT_SYMBOL(dib9000_attach);
+EXPORT_SYMBOL_GPL(dib9000_attach);
 
 static const struct dvb_frontend_ops dib9000_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -12366,7 +12366,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(drx39xxj_attach);
+EXPORT_SYMBOL_GPL(drx39xxj_attach);
 
 static const struct dvb_frontend_ops drx39xxj_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/drxd_hard.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/drxd_hard.c
@@ -2948,7 +2948,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(drxd_attach);
+EXPORT_SYMBOL_GPL(drxd_attach);
 
 MODULE_DESCRIPTION("DRXD driver");
 MODULE_AUTHOR("Micronas");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/drxk_hard.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/drxk_hard.c
@@ -6684,7 +6684,7 @@
 static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
 	struct drxk_state *state = fe->demodulator_priv;
-	u16 err;
+	u16 err = 0;
 
 	dprintk(1, "\n");
 
@@ -6857,7 +6857,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(drxk_attach);
+EXPORT_SYMBOL_GPL(drxk_attach);
 
 MODULE_DESCRIPTION("DRX-K driver");
 MODULE_AUTHOR("Ralph Metzler");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ds3000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ds3000.c
@@ -859,7 +859,7 @@
 	ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF);
 	return &state->frontend;
 }
-EXPORT_SYMBOL(ds3000_attach);
+EXPORT_SYMBOL_GPL(ds3000_attach);
 
 static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
 					s32 carrier_offset_khz)
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/dvb-pll.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/dvb-pll.c
@@ -866,7 +866,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(dvb_pll_attach);
+EXPORT_SYMBOL_GPL(dvb_pll_attach);
 
 
 static int
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ec100.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ec100.c
@@ -299,7 +299,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(ec100_attach);
+EXPORT_SYMBOL_GPL(ec100_attach);
 
 static const struct dvb_frontend_ops ec100_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/helene.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/helene.c
@@ -1025,7 +1025,7 @@
 			priv->i2c_address, priv->i2c);
 	return fe;
 }
-EXPORT_SYMBOL(helene_attach_s);
+EXPORT_SYMBOL_GPL(helene_attach_s);
 
 struct dvb_frontend *helene_attach(struct dvb_frontend *fe,
 		const struct helene_config *config,
@@ -1061,7 +1061,7 @@
 			priv->i2c_address, priv->i2c);
 	return fe;
 }
-EXPORT_SYMBOL(helene_attach);
+EXPORT_SYMBOL_GPL(helene_attach);
 
 static int helene_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/horus3a.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/horus3a.c
@@ -395,7 +395,7 @@
 		priv->i2c_address, priv->i2c);
 	return fe;
 }
-EXPORT_SYMBOL(horus3a_attach);
+EXPORT_SYMBOL_GPL(horus3a_attach);
 
 MODULE_DESCRIPTION("Sony HORUS3A satellite tuner driver");
 MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/isl6405.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/isl6405.c
@@ -141,7 +141,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(isl6405_attach);
+EXPORT_SYMBOL_GPL(isl6405_attach);
 
 MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
 MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/isl6421.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/isl6421.c
@@ -213,7 +213,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(isl6421_attach);
+EXPORT_SYMBOL_GPL(isl6421_attach);
 
 MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
 MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/isl6423.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/isl6423.c
@@ -289,7 +289,7 @@
 	fe->sec_priv = NULL;
 	return NULL;
 }
-EXPORT_SYMBOL(isl6423_attach);
+EXPORT_SYMBOL_GPL(isl6423_attach);
 
 MODULE_DESCRIPTION("ISL6423 SEC");
 MODULE_AUTHOR("Manu Abraham");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/itd1000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/itd1000.c
@@ -389,7 +389,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(itd1000_attach);
+EXPORT_SYMBOL_GPL(itd1000_attach);
 
 MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
 MODULE_DESCRIPTION("Integrant ITD1000 driver");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ix2505v.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ix2505v.c
@@ -302,7 +302,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(ix2505v_attach);
+EXPORT_SYMBOL_GPL(ix2505v_attach);
 
 module_param_named(debug, ix2505v_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/l64781.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/l64781.c
@@ -593,4 +593,4 @@
 MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(l64781_attach);
+EXPORT_SYMBOL_GPL(l64781_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lg2160.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lg2160.c
@@ -1426,7 +1426,7 @@
 
 	return &state->frontend;
 }
-EXPORT_SYMBOL(lg2160_attach);
+EXPORT_SYMBOL_GPL(lg2160_attach);
 
 MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lgdt3305.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lgdt3305.c
@@ -1148,7 +1148,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(lgdt3305_attach);
+EXPORT_SYMBOL_GPL(lgdt3305_attach);
 
 static const struct dvb_frontend_ops lgdt3304_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lgdt3306a.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lgdt3306a.c
@@ -1881,7 +1881,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(lgdt3306a_attach);
+EXPORT_SYMBOL_GPL(lgdt3306a_attach);
 
 #ifdef DBG_DUMP
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lgdt330x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lgdt330x.c
@@ -928,7 +928,7 @@
 
 	return lgdt330x_get_dvb_frontend(client);
 }
-EXPORT_SYMBOL(lgdt330x_attach);
+EXPORT_SYMBOL_GPL(lgdt330x_attach);
 
 static const struct dvb_frontend_ops lgdt3302_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lgs8gxx.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lgs8gxx.c
@@ -1043,7 +1043,7 @@
 	return NULL;
 
 }
-EXPORT_SYMBOL(lgs8gxx_attach);
+EXPORT_SYMBOL_GPL(lgs8gxx_attach);
 
 MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver");
 MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lnbh25.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lnbh25.c
@@ -173,7 +173,7 @@
 		__func__, priv->i2c_address);
 	return fe;
 }
-EXPORT_SYMBOL(lnbh25_attach);
+EXPORT_SYMBOL_GPL(lnbh25_attach);
 
 MODULE_DESCRIPTION("ST LNBH25 driver");
 MODULE_AUTHOR("info@netup.ru");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lnbp21.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lnbp21.c
@@ -155,7 +155,7 @@
 	return lnbx2x_attach(fe, i2c, override_set, override_clear,
 							i2c_addr, LNBH24_TTX);
 }
-EXPORT_SYMBOL(lnbh24_attach);
+EXPORT_SYMBOL_GPL(lnbh24_attach);
 
 struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
 				struct i2c_adapter *i2c, u8 override_set,
@@ -164,7 +164,7 @@
 	return lnbx2x_attach(fe, i2c, override_set, override_clear,
 							0x08, LNBP21_ISEL);
 }
-EXPORT_SYMBOL(lnbp21_attach);
+EXPORT_SYMBOL_GPL(lnbp21_attach);
 
 MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
 MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/lnbp22.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/lnbp22.c
@@ -125,7 +125,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(lnbp22_attach);
+EXPORT_SYMBOL_GPL(lnbp22_attach);
 
 MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
 MODULE_AUTHOR("Dominik Kuhlen");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/m88ds3103.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/m88ds3103.c
@@ -1284,7 +1284,7 @@
 	*tuner_i2c_adapter = pdata.get_i2c_adapter(client);
 	return pdata.get_dvb_frontend(client);
 }
-EXPORT_SYMBOL(m88ds3103_attach);
+EXPORT_SYMBOL_GPL(m88ds3103_attach);
 
 static const struct dvb_frontend_ops m88ds3103_ops = {
 	.delsys = {SYS_DVBS, SYS_DVBS2},
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/m88rs2000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/m88rs2000.c
@@ -807,7 +807,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(m88rs2000_attach);
+EXPORT_SYMBOL_GPL(m88rs2000_attach);
 
 MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
 MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/mb86a16.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/mb86a16.c
@@ -1851,6 +1851,6 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(mb86a16_attach);
+EXPORT_SYMBOL_GPL(mb86a16_attach);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Manu Abraham");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/mb86a20s.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/mb86a20s.c
@@ -2089,7 +2089,7 @@
 	dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n");
 	return &state->frontend;
 }
-EXPORT_SYMBOL(mb86a20s_attach);
+EXPORT_SYMBOL_GPL(mb86a20s_attach);
 
 static const struct dvb_frontend_ops mb86a20s_ops = {
 	.delsys = { SYS_ISDBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/mn88443x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/mn88443x.c
@@ -204,11 +204,18 @@
 	struct regmap *regmap_t;
 };
 
-static void mn88443x_cmn_power_on(struct mn88443x_priv *chip)
+static int mn88443x_cmn_power_on(struct mn88443x_priv *chip)
 {
+	struct device *dev = &chip->client_s->dev;
 	struct regmap *r_t = chip->regmap_t;
+	int ret;
 
-	clk_prepare_enable(chip->mclk);
+	ret = clk_prepare_enable(chip->mclk);
+	if (ret) {
+		dev_err(dev, "Failed to prepare and enable mclk: %d\n",
+			ret);
+		return ret;
+	}
 
 	gpiod_set_value_cansleep(chip->reset_gpio, 1);
 	usleep_range(100, 1000);
@@ -222,6 +229,8 @@
 	} else {
 		regmap_write(r_t, HIZSET3, 0x8f);
 	}
+
+	return 0;
 }
 
 static void mn88443x_cmn_power_off(struct mn88443x_priv *chip)
@@ -738,7 +747,10 @@
 	chip->fe.demodulator_priv = chip;
 	i2c_set_clientdata(client, chip);
 
-	mn88443x_cmn_power_on(chip);
+	ret = mn88443x_cmn_power_on(chip);
+	if (ret)
+		goto err_i2c_t;
+
 	mn88443x_s_sleep(chip);
 	mn88443x_t_sleep(chip);
 
@@ -788,7 +800,7 @@
 static struct i2c_driver mn88443x_driver = {
 	.driver = {
 		.name = "mn88443x",
-		.of_match_table = of_match_ptr(mn88443x_of_match),
+		.of_match_table = mn88443x_of_match,
 	},
 	.probe    = mn88443x_probe,
 	.remove   = mn88443x_remove,
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/mt312.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/mt312.c
@@ -832,7 +832,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(mt312_attach);
+EXPORT_SYMBOL_GPL(mt312_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/mt352.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/mt352.c
@@ -593,4 +593,4 @@
 MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(mt352_attach);
+EXPORT_SYMBOL_GPL(mt352_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/nxt200x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/nxt200x.c
@@ -1232,5 +1232,5 @@
 MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(nxt200x_attach);
+EXPORT_SYMBOL_GPL(nxt200x_attach);
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/nxt6000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/nxt6000.c
@@ -621,4 +621,4 @@
 MODULE_AUTHOR("Florian Schirmer");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(nxt6000_attach);
+EXPORT_SYMBOL_GPL(nxt6000_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/or51132.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/or51132.c
@@ -605,4 +605,4 @@
 MODULE_AUTHOR("Trent Piepho");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(or51132_attach);
+EXPORT_SYMBOL_GPL(or51132_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/or51211.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/or51211.c
@@ -551,5 +551,5 @@
 MODULE_AUTHOR("Kirk Lapray");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(or51211_attach);
+EXPORT_SYMBOL_GPL(or51211_attach);
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/rtl2832.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/rtl2832.c
@@ -640,7 +640,7 @@
 	struct i2c_client *client = dev->client;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
-	u32 uninitialized_var(tmp);
+	u32 tmp;
 	u8 u8tmp, buf[2];
 	u16 u16tmp;
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/s5h1409.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/s5h1409.c
@@ -981,7 +981,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(s5h1409_attach);
+EXPORT_SYMBOL_GPL(s5h1409_attach);
 
 static const struct dvb_frontend_ops s5h1409_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/s5h1411.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/s5h1411.c
@@ -900,7 +900,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(s5h1411_attach);
+EXPORT_SYMBOL_GPL(s5h1411_attach);
 
 static const struct dvb_frontend_ops s5h1411_ops = {
 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/s5h1420.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/s5h1420.c
@@ -918,7 +918,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(s5h1420_attach);
+EXPORT_SYMBOL_GPL(s5h1420_attach);
 
 static const struct dvb_frontend_ops s5h1420_ops = {
 	.delsys = { SYS_DVBS },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/s5h1432.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/s5h1432.c
@@ -355,7 +355,7 @@
 
 	return &state->frontend;
 }
-EXPORT_SYMBOL(s5h1432_attach);
+EXPORT_SYMBOL_GPL(s5h1432_attach);
 
 static const struct dvb_frontend_ops s5h1432_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/s921.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/s921.c
@@ -495,7 +495,7 @@
 
 	return &state->frontend;
 }
-EXPORT_SYMBOL(s921_attach);
+EXPORT_SYMBOL_GPL(s921_attach);
 
 static const struct dvb_frontend_ops s921_ops = {
 	.delsys = { SYS_ISDBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/si21xx.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/si21xx.c
@@ -938,7 +938,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(si21xx_attach);
+EXPORT_SYMBOL_GPL(si21xx_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/sp8870.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/sp8870.c
@@ -281,7 +281,7 @@
 
 	// read status reg in order to clear pending irqs
 	err = sp8870_readreg(state, 0x200);
-	if (err)
+	if (err < 0)
 		return err;
 
 	// system controller start
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/sp887x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/sp887x.c
@@ -626,4 +626,4 @@
 MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(sp887x_attach);
+EXPORT_SYMBOL_GPL(sp887x_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stb0899_drv.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stb0899_drv.c
@@ -1638,7 +1638,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stb0899_attach);
+EXPORT_SYMBOL_GPL(stb0899_attach);
 MODULE_PARM_DESC(verbose, "Set Verbosity level");
 MODULE_AUTHOR("Manu Abraham");
 MODULE_DESCRIPTION("STB0899 Multi-Std frontend");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stb6000.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stb6000.c
@@ -232,7 +232,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(stb6000_attach);
+EXPORT_SYMBOL_GPL(stb6000_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stb6100.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stb6100.c
@@ -557,7 +557,7 @@
 	kfree(state);
 }
 
-EXPORT_SYMBOL(stb6100_attach);
+EXPORT_SYMBOL_GPL(stb6100_attach);
 MODULE_PARM_DESC(verbose, "Set Verbosity level");
 
 MODULE_AUTHOR("Manu Abraham");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv0288.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv0288.c
@@ -440,9 +440,8 @@
 	struct stv0288_state *state = fe->demodulator_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-	char tm;
-	unsigned char tda[3];
-	u8 reg, time_out = 0;
+	u8 tda[3], reg, time_out = 0;
+	s8 tm;
 
 	dprintk("%s : FE_SET_FRONTEND\n", __func__);
 
@@ -591,7 +590,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(stv0288_attach);
+EXPORT_SYMBOL_GPL(stv0288_attach);
 
 module_param(debug_legacy_dish_switch, int, 0444);
 MODULE_PARM_DESC(debug_legacy_dish_switch,
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv0297.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv0297.c
@@ -710,4 +710,4 @@
 MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(stv0297_attach);
+EXPORT_SYMBOL_GPL(stv0297_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv0299.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv0299.c
@@ -751,4 +751,4 @@
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(stv0299_attach);
+EXPORT_SYMBOL_GPL(stv0299_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv0367.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv0367.c
@@ -1750,7 +1750,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stv0367ter_attach);
+EXPORT_SYMBOL_GPL(stv0367ter_attach);
 
 static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
@@ -2923,7 +2923,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stv0367cab_attach);
+EXPORT_SYMBOL_GPL(stv0367cab_attach);
 
 /*
  * Functions for operation on Digital Devices hardware
@@ -3344,7 +3344,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stv0367ddb_attach);
+EXPORT_SYMBOL_GPL(stv0367ddb_attach);
 
 MODULE_PARM_DESC(debug, "Set debug");
 MODULE_PARM_DESC(i2c_debug, "Set i2c debug");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv0900_core.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv0900_core.c
@@ -1957,7 +1957,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stv0900_attach);
+EXPORT_SYMBOL_GPL(stv0900_attach);
 
 MODULE_PARM_DESC(debug, "Set debug");
 
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv090x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv090x.c
@@ -5073,7 +5073,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(stv090x_attach);
+EXPORT_SYMBOL_GPL(stv090x_attach);
 
 static const struct i2c_device_id stv090x_id_table[] = {
 	{"stv090x", 0},
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv6110.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv6110.c
@@ -427,7 +427,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(stv6110_attach);
+EXPORT_SYMBOL_GPL(stv6110_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/stv6110x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/stv6110x.c
@@ -469,7 +469,7 @@
 	dev_info(&stv6110x->i2c->dev, "Attaching STV6110x\n");
 	return stv6110x->devctl;
 }
-EXPORT_SYMBOL(stv6110x_attach);
+EXPORT_SYMBOL_GPL(stv6110x_attach);
 
 static const struct i2c_device_id stv6110x_id_table[] = {
 	{"stv6110x", 0},
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda10021.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda10021.c
@@ -513,4 +513,4 @@
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(tda10021_attach);
+EXPORT_SYMBOL_GPL(tda10021_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda10023.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda10023.c
@@ -594,4 +594,4 @@
 MODULE_AUTHOR("Georg Acher, Hartmut Birr");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(tda10023_attach);
+EXPORT_SYMBOL_GPL(tda10023_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda10048.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda10048.c
@@ -1138,7 +1138,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(tda10048_attach);
+EXPORT_SYMBOL_GPL(tda10048_attach);
 
 static const struct dvb_frontend_ops tda10048_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda1004x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda1004x.c
@@ -1378,5 +1378,5 @@
 MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(tda10045_attach);
-EXPORT_SYMBOL(tda10046_attach);
+EXPORT_SYMBOL_GPL(tda10045_attach);
+EXPORT_SYMBOL_GPL(tda10046_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda10071.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda10071.c
@@ -470,10 +470,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-ein-5.4.0.orig/drivers/media/dvb-frontends/tda10086.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda10086.c
@@ -764,4 +764,4 @@
 MODULE_AUTHOR("Andrew de Quincey");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(tda10086_attach);
+EXPORT_SYMBOL_GPL(tda10086_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda665x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda665x.c
@@ -227,7 +227,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(tda665x_attach);
+EXPORT_SYMBOL_GPL(tda665x_attach);
 
 MODULE_DESCRIPTION("TDA665x driver");
 MODULE_AUTHOR("Manu Abraham");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda8083.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda8083.c
@@ -481,4 +481,4 @@
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(tda8083_attach);
+EXPORT_SYMBOL_GPL(tda8083_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda8261.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda8261.c
@@ -188,7 +188,7 @@
 	return NULL;
 }
 
-EXPORT_SYMBOL(tda8261_attach);
+EXPORT_SYMBOL_GPL(tda8261_attach);
 
 MODULE_AUTHOR("Manu Abraham");
 MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tda826x.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tda826x.c
@@ -164,7 +164,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(tda826x_attach);
+EXPORT_SYMBOL_GPL(tda826x_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ts2020.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ts2020.c
@@ -525,7 +525,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(ts2020_attach);
+EXPORT_SYMBOL_GPL(ts2020_attach);
 
 /*
  * We implement own regmap locking due to legacy DVB attach which uses frontend
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/tua6100.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/tua6100.c
@@ -186,7 +186,7 @@
 	fe->tuner_priv = priv;
 	return fe;
 }
-EXPORT_SYMBOL(tua6100_attach);
+EXPORT_SYMBOL_GPL(tua6100_attach);
 
 MODULE_DESCRIPTION("DVB tua6100 driver");
 MODULE_AUTHOR("Andrew de Quincey");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ves1820.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ves1820.c
@@ -434,4 +434,4 @@
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(ves1820_attach);
+EXPORT_SYMBOL_GPL(ves1820_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/ves1x93.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/ves1x93.c
@@ -540,4 +540,4 @@
 MODULE_AUTHOR("Ralph Metzler");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(ves1x93_attach);
+EXPORT_SYMBOL_GPL(ves1x93_attach);
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/zl10036.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/zl10036.c
@@ -496,7 +496,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(zl10036_attach);
+EXPORT_SYMBOL_GPL(zl10036_attach);
 
 module_param_named(debug, zl10036_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/zl10039.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/zl10039.c
@@ -295,7 +295,7 @@
 	kfree(state);
 	return NULL;
 }
-EXPORT_SYMBOL(zl10039_attach);
+EXPORT_SYMBOL_GPL(zl10039_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
--- linux-ein-5.4.0.orig/drivers/media/dvb-frontends/zl10353.c
+++ linux-ein-5.4.0/drivers/media/dvb-frontends/zl10353.c
@@ -665,4 +665,4 @@
 MODULE_AUTHOR("Chris Pascoe");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(zl10353_attach);
+EXPORT_SYMBOL_GPL(zl10353_attach);
--- linux-ein-5.4.0.orig/drivers/media/firewire/firedtv-avc.c
+++ linux-ein-5.4.0/drivers/media/firewire/firedtv-avc.c
@@ -1165,7 +1165,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++];
@@ -1177,13 +1181,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-ein-5.4.0.orig/drivers/media/firewire/firedtv-ci.c
+++ linux-ein-5.4.0/drivers/media/firewire/firedtv-ci.c
@@ -134,6 +134,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-ein-5.4.0.orig/drivers/media/firewire/firedtv-fw.c
+++ linux-ein-5.4.0/drivers/media/firewire/firedtv-fw.c
@@ -272,6 +272,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-ein-5.4.0.orig/drivers/media/i2c/Kconfig
+++ linux-ein-5.4.0/drivers/media/i2c/Kconfig
@@ -1113,6 +1113,7 @@
 config SDR_MAX2175
 	tristate "Maxim 2175 RF to Bits tuner"
 	depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C
+	select REGMAP_I2C
 	help
 	  Support for Maxim 2175 tuner. It is an advanced analog/digital
 	  radio receiver with RF-to-Bits front-end designed for SDR solutions.
--- linux-ein-5.4.0.orig/drivers/media/i2c/ad5820.c
+++ linux-ein-5.4.0/drivers/media/i2c/ad5820.c
@@ -309,22 +309,23 @@
 	v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops);
 	coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 	coil->subdev.internal_ops = &ad5820_internal_ops;
+	coil->subdev.entity.function = MEDIA_ENT_F_LENS;
 	strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name));
 
 	ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL);
 	if (ret < 0)
-		goto cleanup2;
+		goto clean_mutex;
 
 	ret = v4l2_async_register_subdev(&coil->subdev);
 	if (ret < 0)
-		goto cleanup;
+		goto clean_entity;
 
 	return ret;
 
-cleanup2:
-	mutex_destroy(&coil->power_lock);
-cleanup:
+clean_entity:
 	media_entity_cleanup(&coil->subdev.entity);
+clean_mutex:
+	mutex_destroy(&coil->power_lock);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/adv748x/adv748x.h
+++ linux-ein-5.4.0/drivers/media/i2c/adv748x/adv748x.h
@@ -394,10 +394,10 @@
 
 #define io_read(s, r) adv748x_read(s, ADV748X_PAGE_IO, r)
 #define io_write(s, r, v) adv748x_write(s, ADV748X_PAGE_IO, r, v)
-#define io_clrset(s, r, m, v) io_write(s, r, (io_read(s, r) & ~m) | v)
+#define io_clrset(s, r, m, v) io_write(s, r, (io_read(s, r) & ~(m)) | (v))
 
 #define hdmi_read(s, r) adv748x_read(s, ADV748X_PAGE_HDMI, r)
-#define hdmi_read16(s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, r+1)) & m)
+#define hdmi_read16(s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, (r)+1)) & (m))
 #define hdmi_write(s, r, v) adv748x_write(s, ADV748X_PAGE_HDMI, r, v)
 
 #define repeater_read(s, r) adv748x_read(s, ADV748X_PAGE_REPEATER, r)
@@ -405,11 +405,11 @@
 
 #define sdp_read(s, r) adv748x_read(s, ADV748X_PAGE_SDP, r)
 #define sdp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_SDP, r, v)
-#define sdp_clrset(s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~m) | v)
+#define sdp_clrset(s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~(m)) | (v))
 
 #define cp_read(s, r) adv748x_read(s, ADV748X_PAGE_CP, r)
 #define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v)
-#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v)
+#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~(m)) | (v))
 
 #define tx_read(t, r) adv748x_read(t->state, t->page, r)
 #define tx_write(t, r, v) adv748x_write(t->state, t->page, r, v)
--- linux-ein-5.4.0.orig/drivers/media/i2c/adv7511-v4l2.c
+++ linux-ein-5.4.0/drivers/media/i2c/adv7511-v4l2.c
@@ -555,7 +555,7 @@
 	buffer[3] = 0;
 	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
@@ -1964,7 +1964,7 @@
 
 	adv7511_set_isr(sd, false);
 	adv7511_init_setup(sd);
-	cancel_delayed_work(&state->edid_handler);
+	cancel_delayed_work_sync(&state->edid_handler);
 	i2c_unregister_device(state->i2c_edid);
 	i2c_unregister_device(state->i2c_cec);
 	i2c_unregister_device(state->i2c_pktmem);
--- linux-ein-5.4.0.orig/drivers/media/i2c/adv7604.c
+++ linux-ein-5.4.0/drivers/media/i2c/adv7604.c
@@ -2444,7 +2444,7 @@
 		buffer[i + 3] = infoframe_read(sd,
 				       adv76xx_cri[index].payload_addr + i);
 
-	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
+	if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
 			 adv76xx_cri[index].desc);
 		return -ENOENT;
@@ -3606,7 +3606,7 @@
 	io_write(sd, 0x6e, 0);
 	io_write(sd, 0x73, 0);
 
-	cancel_delayed_work(&state->delayed_work_enable_hotplug);
+	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
 	v4l2_async_unregister_subdev(sd);
 	media_entity_cleanup(&sd->entity);
 	adv76xx_unregister_clients(to_state(sd));
--- linux-ein-5.4.0.orig/drivers/media/i2c/adv7842.c
+++ linux-ein-5.4.0/drivers/media/i2c/adv7842.c
@@ -2574,7 +2574,7 @@
 	for (i = 0; i < len; i++)
 		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
-	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
@@ -3586,7 +3586,7 @@
 	struct adv7842_state *state = to_state(sd);
 
 	adv7842_irq_enable(sd, false);
-	cancel_delayed_work(&state->delayed_work_enable_hotplug);
+	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
 	v4l2_device_unregister_subdev(sd);
 	media_entity_cleanup(&sd->entity);
 	adv7842_unregister_clients(sd);
--- linux-ein-5.4.0.orig/drivers/media/i2c/imx214.c
+++ linux-ein-5.4.0/drivers/media/i2c/imx214.c
@@ -785,7 +785,7 @@
 		if (ret < 0)
 			goto err_rpm_put;
 	} else {
-		ret = imx214_start_streaming(imx214);
+		ret = imx214_stop_streaming(imx214);
 		if (ret < 0)
 			goto err_rpm_put;
 		pm_runtime_put(imx214->dev);
--- linux-ein-5.4.0.orig/drivers/media/i2c/imx258.c
+++ linux-ein-5.4.0/drivers/media/i2c/imx258.c
@@ -22,7 +22,7 @@
 #define IMX258_CHIP_ID			0x0258
 
 /* V_TIMING internal */
-#define IMX258_VTS_30FPS		0x0c98
+#define IMX258_VTS_30FPS		0x0c50
 #define IMX258_VTS_30FPS_2K		0x0638
 #define IMX258_VTS_30FPS_VGA		0x034c
 #define IMX258_VTS_MAX			0xffff
@@ -46,7 +46,7 @@
 /* Analog gain control */
 #define IMX258_REG_ANALOG_GAIN		0x0204
 #define IMX258_ANA_GAIN_MIN		0
-#define IMX258_ANA_GAIN_MAX		0x1fff
+#define IMX258_ANA_GAIN_MAX		480
 #define IMX258_ANA_GAIN_STEP		1
 #define IMX258_ANA_GAIN_DEFAULT		0x0
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/imx274.c
+++ linux-ein-5.4.0/drivers/media/i2c/imx274.c
@@ -1235,6 +1235,8 @@
 	ret = imx274_set_frame_interval(imx274, fi->interval);
 
 	if (!ret) {
+		fi->interval = imx274->frame_interval;
+
 		/*
 		 * exposure time range is decided by frame interval
 		 * need to update it after frame interval changes
@@ -1730,9 +1732,9 @@
 		__func__, frame_interval.numerator,
 		frame_interval.denominator);
 
-	if (frame_interval.numerator == 0) {
-		err = -EINVAL;
-		goto fail;
+	if (frame_interval.numerator == 0 || frame_interval.denominator == 0) {
+		frame_interval.denominator = IMX274_DEF_FRAME_RATE;
+		frame_interval.numerator = 1;
 	}
 
 	req_frame_rate = (u32)(frame_interval.denominator
--- linux-ein-5.4.0.orig/drivers/media/i2c/ir-kbd-i2c.c
+++ linux-ein-5.4.0/drivers/media/i2c/ir-kbd-i2c.c
@@ -678,8 +678,8 @@
 		goto out_unlock;
 	}
 
-	i = i2c_master_recv(ir->tx_c, buf, 1);
-	if (i != 1) {
+	ret = i2c_master_recv(ir->tx_c, buf, 1);
+	if (ret != 1) {
 		dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret);
 		ret = -EIO;
 		goto out_unlock;
@@ -791,6 +791,7 @@
 		rc_proto    = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
 							RC_PROTO_BIT_RC6_6A_32;
 		ir_codes    = RC_MAP_HAUPPAUGE;
+		ir->polling_interval = 125;
 		probe_tx = true;
 		break;
 	}
--- linux-ein-5.4.0.orig/drivers/media/i2c/m5mols/m5mols_core.c
+++ linux-ein-5.4.0/drivers/media/i2c/m5mols/m5mols_core.c
@@ -488,7 +488,7 @@
 	do {
 		if (code == m5mols_default_ffmt[type].code)
 			return type;
-	} while (type++ != SIZE_DEFAULT_FFMT);
+	} while (++type != SIZE_DEFAULT_FFMT);
 
 	return 0;
 }
@@ -764,7 +764,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-ein-5.4.0.orig/drivers/media/i2c/max2175.c
+++ linux-ein-5.4.0/drivers/media/i2c/max2175.c
@@ -503,7 +503,7 @@
 	}
 }
 
-static bool max2175_set_csm_mode(struct max2175 *ctx,
+static int max2175_set_csm_mode(struct max2175 *ctx,
 			  enum max2175_csm_mode new_mode)
 {
 	int ret = max2175_poll_csm_ready(ctx);
--- linux-ein-5.4.0.orig/drivers/media/i2c/mt9p031.c
+++ linux-ein-5.4.0/drivers/media/i2c/mt9p031.c
@@ -78,7 +78,9 @@
 #define		MT9P031_PIXEL_CLOCK_INVERT		(1 << 15)
 #define		MT9P031_PIXEL_CLOCK_SHIFT(n)		((n) << 8)
 #define		MT9P031_PIXEL_CLOCK_DIVIDE(n)		((n) << 0)
-#define MT9P031_FRAME_RESTART				0x0b
+#define MT9P031_RESTART					0x0b
+#define		MT9P031_FRAME_PAUSE_RESTART		(1 << 1)
+#define		MT9P031_FRAME_RESTART			(1 << 0)
 #define MT9P031_SHUTTER_DELAY				0x0c
 #define MT9P031_RST					0x0d
 #define		MT9P031_RST_ENABLE			1
@@ -445,9 +447,23 @@
 static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
 {
 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(subdev);
+	int val;
 	int ret;
 
 	if (!enable) {
+		/* enable pause restart */
+		val = MT9P031_FRAME_PAUSE_RESTART;
+		ret = mt9p031_write(client, MT9P031_RESTART, val);
+		if (ret < 0)
+			return ret;
+
+		/* enable restart + keep pause restart set */
+		val |= MT9P031_FRAME_RESTART;
+		ret = mt9p031_write(client, MT9P031_RESTART, val);
+		if (ret < 0)
+			return ret;
+
 		/* Stop sensor readout */
 		ret = mt9p031_set_output_control(mt9p031,
 						 MT9P031_OUTPUT_CONTROL_CEN, 0);
@@ -467,6 +483,16 @@
 	if (ret < 0)
 		return ret;
 
+	/*
+	 * - clear pause restart
+	 * - don't clear restart as clearing restart manually can cause
+	 *   undefined behavior
+	 */
+	val = MT9P031_FRAME_RESTART;
+	ret = mt9p031_write(client, MT9P031_RESTART, val);
+	if (ret < 0)
+		return ret;
+
 	return mt9p031_pll_enable(mt9p031);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/mt9v032.c
+++ linux-ein-5.4.0/drivers/media/i2c/mt9v032.c
@@ -428,10 +428,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;
 }
 
@@ -439,7 +441,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-ein-5.4.0.orig/drivers/media/i2c/ov2659.c
+++ linux-ein-5.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 },
 };
 
@@ -1201,11 +1205,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-ein-5.4.0.orig/drivers/media/i2c/ov2680.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov2680.c
@@ -85,15 +85,8 @@
 
 struct ov2680_ctrls {
 	struct v4l2_ctrl_handler handler;
-	struct {
-		struct v4l2_ctrl *auto_exp;
-		struct v4l2_ctrl *exposure;
-	};
-	struct {
-		struct v4l2_ctrl *auto_gain;
-		struct v4l2_ctrl *gain;
-	};
-
+	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *gain;
 	struct v4l2_ctrl *hflip;
 	struct v4l2_ctrl *vflip;
 	struct v4l2_ctrl *test_pattern;
@@ -143,6 +136,7 @@
 	{0x380e, 0x02}, {0x380f, 0x84}, {0x3811, 0x04}, {0x3813, 0x04},
 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3820, 0xc0}, {0x4008, 0x00},
 	{0x4009, 0x03}, {0x4837, 0x1e}, {0x3501, 0x4e}, {0x3502, 0xe0},
+	{0x3503, 0x03},
 };
 
 static const struct reg_value ov2680_setting_30fps_720P_1280_720[] = {
@@ -321,70 +315,49 @@
 	usleep_range(5000, 10000);
 }
 
-static int ov2680_bayer_order(struct ov2680_dev *sensor)
+static void ov2680_set_bayer_order(struct ov2680_dev *sensor)
 {
-	u32 format1;
-	u32 format2;
-	u32 hv_flip;
-	int ret;
-
-	ret = ov2680_read_reg(sensor, OV2680_REG_FORMAT1, &format1);
-	if (ret < 0)
-		return ret;
+	int hv_flip = 0;
 
-	ret = ov2680_read_reg(sensor, OV2680_REG_FORMAT2, &format2);
-	if (ret < 0)
-		return ret;
+	if (sensor->ctrls.vflip && sensor->ctrls.vflip->val)
+		hv_flip += 1;
 
-	hv_flip = (format2 & BIT(2)  << 1) | (format1 & BIT(2));
+	if (sensor->ctrls.hflip && sensor->ctrls.hflip->val)
+		hv_flip += 2;
 
 	sensor->fmt.code = ov2680_hv_flip_bayer_order[hv_flip];
-
-	return 0;
 }
 
-static int ov2680_vflip_enable(struct ov2680_dev *sensor)
+static int ov2680_set_vflip(struct ov2680_dev *sensor, s32 val)
 {
 	int ret;
 
-	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1, BIT(2), BIT(2));
-	if (ret < 0)
-		return ret;
+	if (sensor->is_streaming)
+		return -EBUSY;
 
-	return ov2680_bayer_order(sensor);
-}
-
-static int ov2680_vflip_disable(struct ov2680_dev *sensor)
-{
-	int ret;
-
-	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1, BIT(2), BIT(0));
+	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT1,
+			     BIT(2), val ? BIT(2) : 0);
 	if (ret < 0)
 		return ret;
 
-	return ov2680_bayer_order(sensor);
+	ov2680_set_bayer_order(sensor);
+	return 0;
 }
 
-static int ov2680_hflip_enable(struct ov2680_dev *sensor)
+static int ov2680_set_hflip(struct ov2680_dev *sensor, s32 val)
 {
 	int ret;
 
-	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2, BIT(2), BIT(2));
-	if (ret < 0)
-		return ret;
+	if (sensor->is_streaming)
+		return -EBUSY;
 
-	return ov2680_bayer_order(sensor);
-}
-
-static int ov2680_hflip_disable(struct ov2680_dev *sensor)
-{
-	int ret;
-
-	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2, BIT(2), BIT(0));
+	ret = ov2680_mod_reg(sensor, OV2680_REG_FORMAT2,
+			     BIT(2), val ? BIT(2) : 0);
 	if (ret < 0)
 		return ret;
 
-	return ov2680_bayer_order(sensor);
+	ov2680_set_bayer_order(sensor);
+	return 0;
 }
 
 static int ov2680_test_pattern_set(struct ov2680_dev *sensor, int value)
@@ -405,69 +378,15 @@
 	return 0;
 }
 
-static int ov2680_gain_set(struct ov2680_dev *sensor, bool auto_gain)
+static int ov2680_gain_set(struct ov2680_dev *sensor, u32 gain)
 {
-	struct ov2680_ctrls *ctrls = &sensor->ctrls;
-	u32 gain;
-	int ret;
-
-	ret = ov2680_mod_reg(sensor, OV2680_REG_R_MANUAL, BIT(1),
-			     auto_gain ? 0 : BIT(1));
-	if (ret < 0)
-		return ret;
-
-	if (auto_gain || !ctrls->gain->is_new)
-		return 0;
-
-	gain = ctrls->gain->val;
-
-	ret = ov2680_write_reg16(sensor, OV2680_REG_GAIN_PK, gain);
-
-	return 0;
+	return ov2680_write_reg16(sensor, OV2680_REG_GAIN_PK, gain);
 }
 
-static int ov2680_gain_get(struct ov2680_dev *sensor)
+static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp)
 {
-	u32 gain;
-	int ret;
-
-	ret = ov2680_read_reg16(sensor, OV2680_REG_GAIN_PK, &gain);
-	if (ret)
-		return ret;
-
-	return gain;
-}
-
-static int ov2680_exposure_set(struct ov2680_dev *sensor, bool auto_exp)
-{
-	struct ov2680_ctrls *ctrls = &sensor->ctrls;
-	u32 exp;
-	int ret;
-
-	ret = ov2680_mod_reg(sensor, OV2680_REG_R_MANUAL, BIT(0),
-			     auto_exp ? 0 : BIT(0));
-	if (ret < 0)
-		return ret;
-
-	if (auto_exp || !ctrls->exposure->is_new)
-		return 0;
-
-	exp = (u32)ctrls->exposure->val;
-	exp <<= 4;
-
-	return ov2680_write_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH, exp);
-}
-
-static int ov2680_exposure_get(struct ov2680_dev *sensor)
-{
-	int ret;
-	u32 exp;
-
-	ret = ov2680_read_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH, &exp);
-	if (ret)
-		return ret;
-
-	return exp >> 4;
+	return ov2680_write_reg24(sensor, OV2680_REG_EXPOSURE_PK_HIGH,
+				  exp << 4);
 }
 
 static int ov2680_stream_enable(struct ov2680_dev *sensor)
@@ -482,33 +401,17 @@
 
 static int ov2680_mode_set(struct ov2680_dev *sensor)
 {
-	struct ov2680_ctrls *ctrls = &sensor->ctrls;
 	int ret;
 
-	ret = ov2680_gain_set(sensor, false);
-	if (ret < 0)
-		return ret;
-
-	ret = ov2680_exposure_set(sensor, false);
+	ret = ov2680_load_regs(sensor, sensor->current_mode);
 	if (ret < 0)
 		return ret;
 
-	ret = ov2680_load_regs(sensor, sensor->current_mode);
+	/* Restore value of all ctrls */
+	ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
 	if (ret < 0)
 		return ret;
 
-	if (ctrls->auto_gain->val) {
-		ret = ov2680_gain_set(sensor, true);
-		if (ret < 0)
-			return ret;
-	}
-
-	if (ctrls->auto_exp->val == V4L2_EXPOSURE_AUTO) {
-		ret = ov2680_exposure_set(sensor, true);
-		if (ret < 0)
-			return ret;
-	}
-
 	sensor->mode_pending_changes = false;
 
 	return 0;
@@ -556,7 +459,7 @@
 		ret = ov2680_write_reg(sensor, OV2680_REG_SOFT_RESET, 0x01);
 		if (ret != 0) {
 			dev_err(dev, "sensor soft reset failed\n");
-			return ret;
+			goto err_disable_regulators;
 		}
 		usleep_range(1000, 2000);
 	} else {
@@ -566,7 +469,7 @@
 
 	ret = clk_prepare_enable(sensor->xvclk);
 	if (ret < 0)
-		return ret;
+		goto err_disable_regulators;
 
 	sensor->is_enabled = true;
 
@@ -576,6 +479,10 @@
 	ov2680_stream_disable(sensor);
 
 	return 0;
+
+err_disable_regulators:
+	regulator_bulk_disable(OV2680_NUM_SUPPLIES, sensor->supplies);
+	return ret;
 }
 
 static int ov2680_s_power(struct v4l2_subdev *sd, int on)
@@ -590,15 +497,10 @@
 	else
 		ret = ov2680_power_off(sensor);
 
-	mutex_unlock(&sensor->lock);
-
-	if (on && ret == 0) {
-		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-		if (ret < 0)
-			return ret;
-
+	if (on && ret == 0)
 		ret = ov2680_mode_restore(sensor);
-	}
+
+	mutex_unlock(&sensor->lock);
 
 	return ret;
 }
@@ -793,66 +695,23 @@
 	return 0;
 }
 
-static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-	struct ov2680_dev *sensor = to_ov2680_dev(sd);
-	struct ov2680_ctrls *ctrls = &sensor->ctrls;
-	int val;
-
-	if (!sensor->is_enabled)
-		return 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_GAIN:
-		val = ov2680_gain_get(sensor);
-		if (val < 0)
-			return val;
-		ctrls->gain->val = val;
-		break;
-	case V4L2_CID_EXPOSURE:
-		val = ov2680_exposure_get(sensor);
-		if (val < 0)
-			return val;
-		ctrls->exposure->val = val;
-		break;
-	}
-
-	return 0;
-}
-
 static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
 	struct ov2680_dev *sensor = to_ov2680_dev(sd);
-	struct ov2680_ctrls *ctrls = &sensor->ctrls;
 
 	if (!sensor->is_enabled)
 		return 0;
 
 	switch (ctrl->id) {
-	case V4L2_CID_AUTOGAIN:
-		return ov2680_gain_set(sensor, !!ctrl->val);
 	case V4L2_CID_GAIN:
-		return ov2680_gain_set(sensor, !!ctrls->auto_gain->val);
-	case V4L2_CID_EXPOSURE_AUTO:
-		return ov2680_exposure_set(sensor, !!ctrl->val);
+		return ov2680_gain_set(sensor, ctrl->val);
 	case V4L2_CID_EXPOSURE:
-		return ov2680_exposure_set(sensor, !!ctrls->auto_exp->val);
+		return ov2680_exposure_set(sensor, ctrl->val);
 	case V4L2_CID_VFLIP:
-		if (sensor->is_streaming)
-			return -EBUSY;
-		if (ctrl->val)
-			return ov2680_vflip_enable(sensor);
-		else
-			return ov2680_vflip_disable(sensor);
+		return ov2680_set_vflip(sensor, ctrl->val);
 	case V4L2_CID_HFLIP:
-		if (sensor->is_streaming)
-			return -EBUSY;
-		if (ctrl->val)
-			return ov2680_hflip_enable(sensor);
-		else
-			return ov2680_hflip_disable(sensor);
+		return ov2680_set_hflip(sensor, ctrl->val);
 	case V4L2_CID_TEST_PATTERN:
 		return ov2680_test_pattern_set(sensor, ctrl->val);
 	default:
@@ -863,7 +722,6 @@
 }
 
 static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
-	.g_volatile_ctrl = ov2680_g_volatile_ctrl,
 	.s_ctrl = ov2680_s_ctrl,
 };
 
@@ -935,7 +793,7 @@
 	if (ret < 0)
 		return ret;
 
-	v4l2_ctrl_handler_init(hdl, 7);
+	v4l2_ctrl_handler_init(hdl, 5);
 
 	hdl->lock = &sensor->lock;
 
@@ -947,16 +805,9 @@
 					ARRAY_SIZE(test_pattern_menu) - 1,
 					0, 0, test_pattern_menu);
 
-	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
-						 V4L2_CID_EXPOSURE_AUTO,
-						 V4L2_EXPOSURE_MANUAL, 0,
-						 V4L2_EXPOSURE_AUTO);
-
 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
 					    0, 32767, 1, 0);
 
-	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
-					     0, 1, 1, 1);
 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 2047, 1, 0);
 
 	if (hdl->error) {
@@ -964,11 +815,8 @@
 		goto cleanup_entity;
 	}
 
-	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-
-	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
-	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
+	ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+	ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
 
 	sensor->sd.ctrl_handler = hdl;
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov5640.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov5640.c
@@ -34,6 +34,8 @@
 #define OV5640_REG_SYS_RESET02		0x3002
 #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
 #define OV5640_REG_SYS_CTRL0		0x3008
+#define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
+#define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
 #define OV5640_REG_CHIP_ID		0x300a
 #define OV5640_REG_IO_MIPI_CTRL00	0x300e
 #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
@@ -272,8 +274,7 @@
 /* YUV422 UYVY VGA@30fps */
 static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
-	{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
-	{0x3630, 0x36, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -740,7 +741,7 @@
  *               +->| PLL Root Div | - reg 0x3037, bit 4
  *                  +-+------------+
  *                    |  +---------+
- *                    +->| Bit Div | - reg 0x3035, bits 0-3
+ *                    +->| Bit Div | - reg 0x3034, bits 0-3
  *                       +-+-------+
  *                         |  +-------------+
  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
@@ -874,7 +875,7 @@
 			 * We have reached the maximum allowed PLL1 output,
 			 * increase sysdiv.
 			 */
-			if (!rate)
+			if (!_rate)
 				break;
 
 			/*
@@ -1109,6 +1110,12 @@
 		val = regs->val;
 		mask = regs->mask;
 
+		/* remain in power down mode for DVP */
+		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
+		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
+		    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
+			continue;
+
 		if (mask)
 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
 		else
@@ -1199,96 +1206,9 @@
 
 static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
 {
-	int ret;
-	unsigned int flags = sensor->ep.bus.parallel.flags;
-	u8 pclk_pol = 0;
-	u8 hsync_pol = 0;
-	u8 vsync_pol = 0;
-
-	/*
-	 * Note about parallel port configuration.
-	 *
-	 * When configured in parallel mode, the OV5640 will
-	 * output 10 bits data on DVP data lines [9:0].
-	 * If only 8 bits data are wanted, the 8 bits data lines
-	 * of the camera interface must be physically connected
-	 * on the DVP data lines [9:2].
-	 *
-	 * Control lines polarity can be configured through
-	 * devicetree endpoint control lines properties.
-	 * If no endpoint control lines properties are set,
-	 * polarity will be as below:
-	 * - VSYNC:	active high
-	 * - HREF:	active low
-	 * - PCLK:	active low
-	 */
-
-	if (on) {
-		/*
-		 * configure parallel port control lines polarity
-		 *
-		 * POLARITY CTRL0
-		 * - [5]:	PCLK polarity (0: active low, 1: active high)
-		 * - [1]:	HREF polarity (0: active low, 1: active high)
-		 * - [0]:	VSYNC polarity (mismatch here between
-		 *		datasheet and hardware, 0 is active high
-		 *		and 1 is active low...)
-		 */
-		if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
-			pclk_pol = 1;
-		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
-			hsync_pol = 1;
-		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-			vsync_pol = 1;
-
-		ret = ov5640_write_reg(sensor,
-				       OV5640_REG_POLARITY_CTRL00,
-				       (pclk_pol << 5) |
-				       (hsync_pol << 1) |
-				       vsync_pol);
-
-		if (ret)
-			return ret;
-	}
-
-	/*
-	 * powerdown MIPI TX/RX PHY & disable MIPI
-	 *
-	 * MIPI CONTROL 00
-	 * 4:	 PWDN PHY TX
-	 * 3:	 PWDN PHY RX
-	 * 2:	 MIPI enable
-	 */
-	ret = ov5640_write_reg(sensor,
-			       OV5640_REG_IO_MIPI_CTRL00, on ? 0x18 : 0);
-	if (ret)
-		return ret;
-
-	/*
-	 * enable VSYNC/HREF/PCLK DVP control lines
-	 * & D[9:6] DVP data lines
-	 *
-	 * PAD OUTPUT ENABLE 01
-	 * - 6:		VSYNC output enable
-	 * - 5:		HREF output enable
-	 * - 4:		PCLK output enable
-	 * - [3:0]:	D[9:6] output enable
-	 */
-	ret = ov5640_write_reg(sensor,
-			       OV5640_REG_PAD_OUTPUT_ENABLE01,
-			       on ? 0x7f : 0);
-	if (ret)
-		return ret;
-
-	/*
-	 * enable D[5:0] DVP data lines
-	 *
-	 * PAD OUTPUT ENABLE 02
-	 * - [7:2]:	D[5:0] output enable
-	 */
-	return ov5640_write_reg(sensor,
-				OV5640_REG_PAD_OUTPUT_ENABLE02,
-				on ? 0xfc : 0);
+	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
+				OV5640_REG_SYS_CTRL0_SW_PWUP :
+				OV5640_REG_SYS_CTRL0_SW_PWDN);
 }
 
 static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
@@ -1611,6 +1531,11 @@
 	    !(mode->hact == 640 && mode->vact == 480))
 		return NULL;
 
+	/* 2592x1944 only works at 15fps max */
+	if ((mode->hact == 2592 && mode->vact == 1944) &&
+	    fr > OV5640_15_FPS)
+		return NULL;
+
 	return mode;
 }
 
@@ -1982,6 +1907,153 @@
 	clk_disable_unprepare(sensor->xclk);
 }
 
+static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
+{
+	int ret;
+
+	if (!on) {
+		/* Reset MIPI bus settings to their default values. */
+		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
+		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
+		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
+		return 0;
+	}
+
+	/*
+	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
+	 *
+	 * 0x300e = 0x40
+	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
+	 *		  "ov5640_set_stream_mipi()")
+	 * [4] = 0	: Power up MIPI HS Tx
+	 * [3] = 0	: Power up MIPI LS Rx
+	 * [2] = 1	: MIPI interface enabled
+	 */
+	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x44);
+	if (ret)
+		return ret;
+
+	/*
+	 * Gate clock and set LP11 in 'no packets mode' (idle)
+	 *
+	 * 0x4800 = 0x24
+	 * [5] = 1	: Gate clock when 'no packets'
+	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
+	 */
+	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
+	if (ret)
+		return ret;
+
+	/*
+	 * Set data lanes and clock in LP11 when 'sleeping'
+	 *
+	 * 0x3019 = 0x70
+	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
+	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
+	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
+	 */
+	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
+	if (ret)
+		return ret;
+
+	/* Give lanes some time to coax into LP11 state. */
+	usleep_range(500, 1000);
+
+	return 0;
+}
+
+static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
+{
+	unsigned int flags = sensor->ep.bus.parallel.flags;
+	u8 pclk_pol = 0;
+	u8 hsync_pol = 0;
+	u8 vsync_pol = 0;
+	int ret;
+
+	if (!on) {
+		/* Reset settings to their default values. */
+		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
+		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
+		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
+		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
+		return 0;
+	}
+
+	/*
+	 * Note about parallel port configuration.
+	 *
+	 * When configured in parallel mode, the OV5640 will
+	 * output 10 bits data on DVP data lines [9:0].
+	 * If only 8 bits data are wanted, the 8 bits data lines
+	 * of the camera interface must be physically connected
+	 * on the DVP data lines [9:2].
+	 *
+	 * Control lines polarity can be configured through
+	 * devicetree endpoint control lines properties.
+	 * If no endpoint control lines properties are set,
+	 * polarity will be as below:
+	 * - VSYNC:	active high
+	 * - HREF:	active low
+	 * - PCLK:	active low
+	 */
+	/*
+	 * configure parallel port control lines polarity
+	 *
+	 * POLARITY CTRL0
+	 * - [5]:	PCLK polarity (0: active low, 1: active high)
+	 * - [1]:	HREF polarity (0: active low, 1: active high)
+	 * - [0]:	VSYNC polarity (mismatch here between
+	 *		datasheet and hardware, 0 is active high
+	 *		and 1 is active low...)
+	 */
+	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+		pclk_pol = 1;
+	if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+		hsync_pol = 1;
+	if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+		vsync_pol = 1;
+
+	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00,
+			       (pclk_pol << 5) | (hsync_pol << 1) | vsync_pol);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * powerdown MIPI TX/RX PHY & disable MIPI
+	 *
+	 * MIPI CONTROL 00
+	 * 4:	 PWDN PHY TX
+	 * 3:	 PWDN PHY RX
+	 * 2:	 MIPI enable
+	 */
+	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
+	if (ret)
+		return ret;
+
+	/*
+	 * enable VSYNC/HREF/PCLK DVP control lines
+	 * & D[9:6] DVP data lines
+	 *
+	 * PAD OUTPUT ENABLE 01
+	 * - 6:		VSYNC output enable
+	 * - 5:		HREF output enable
+	 * - 4:		PCLK output enable
+	 * - [3:0]:	D[9:6] output enable
+	 */
+	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x7f);
+	if (ret)
+		return ret;
+
+	/*
+	 * enable D[5:0] DVP data lines
+	 *
+	 * PAD OUTPUT ENABLE 02
+	 * - [7:2]:	D[5:0] output enable
+	 */
+	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
+}
+
 static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
 {
 	int ret = 0;
@@ -1994,67 +2066,17 @@
 		ret = ov5640_restore_mode(sensor);
 		if (ret)
 			goto power_off;
+	}
 
-		/* We're done here for DVP bus, while CSI-2 needs setup. */
-		if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
-			return 0;
-
-		/*
-		 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
-		 *
-		 * 0x300e = 0x40
-		 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
-		 *		  "ov5640_set_stream_mipi()")
-		 * [4] = 0	: Power up MIPI HS Tx
-		 * [3] = 0	: Power up MIPI LS Rx
-		 * [2] = 0	: MIPI interface disabled
-		 */
-		ret = ov5640_write_reg(sensor,
-				       OV5640_REG_IO_MIPI_CTRL00, 0x40);
-		if (ret)
-			goto power_off;
-
-		/*
-		 * Gate clock and set LP11 in 'no packets mode' (idle)
-		 *
-		 * 0x4800 = 0x24
-		 * [5] = 1	: Gate clock when 'no packets'
-		 * [2] = 1	: MIPI bus in LP11 when 'no packets'
-		 */
-		ret = ov5640_write_reg(sensor,
-				       OV5640_REG_MIPI_CTRL00, 0x24);
-		if (ret)
-			goto power_off;
-
-		/*
-		 * Set data lanes and clock in LP11 when 'sleeping'
-		 *
-		 * 0x3019 = 0x70
-		 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
-		 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
-		 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
-		 */
-		ret = ov5640_write_reg(sensor,
-				       OV5640_REG_PAD_OUTPUT00, 0x70);
-		if (ret)
-			goto power_off;
-
-		/* Give lanes some time to coax into LP11 state. */
-		usleep_range(500, 1000);
-
-	} else {
-		if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
-			/* Reset MIPI bus settings to their default values. */
-			ov5640_write_reg(sensor,
-					 OV5640_REG_IO_MIPI_CTRL00, 0x58);
-			ov5640_write_reg(sensor,
-					 OV5640_REG_MIPI_CTRL00, 0x04);
-			ov5640_write_reg(sensor,
-					 OV5640_REG_PAD_OUTPUT00, 0x00);
-		}
+	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+		ret = ov5640_set_power_mipi(sensor, on);
+	else
+		ret = ov5640_set_power_dvp(sensor, on);
+	if (ret)
+		goto power_off;
 
+	if (!on)
 		ov5640_set_power_off(sensor);
-	}
 
 	return 0;
 
@@ -2675,7 +2697,7 @@
 	/* Auto/manual gain */
 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
 					     0, 1, 1, 1);
-	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
 					0, 1023, 1, 0);
 
 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
@@ -3032,8 +3054,7 @@
 
 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
 
-	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-			    V4L2_SUBDEV_FL_HAS_EVENTS;
+	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
@@ -3063,8 +3084,8 @@
 free_ctrls:
 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
 entity_cleanup:
-	mutex_destroy(&sensor->lock);
 	media_entity_cleanup(&sensor->sd.entity);
+	mutex_destroy(&sensor->lock);
 	return ret;
 }
 
@@ -3074,9 +3095,9 @@
 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
 
 	v4l2_async_unregister_subdev(&sensor->sd);
-	mutex_destroy(&sensor->lock);
 	media_entity_cleanup(&sensor->sd.entity);
 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+	mutex_destroy(&sensor->lock);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov5670.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov5670.c
@@ -2081,7 +2081,8 @@
 
 	/* By default, V4L2_CID_PIXEL_RATE is read only */
 	ov5670->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops,
-					       V4L2_CID_PIXEL_RATE, 0,
+					       V4L2_CID_PIXEL_RATE,
+					       link_freq_configs[0].pixel_rate,
 					       link_freq_configs[0].pixel_rate,
 					       1,
 					       link_freq_configs[0].pixel_rate);
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov5675.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov5675.c
@@ -722,8 +722,10 @@
 				     V4L2_CID_TEST_PATTERN,
 				     ARRAY_SIZE(ov5675_test_pattern_menu) - 1,
 				     0, 0, ov5675_test_pattern_menu);
-	if (ctrl_hdlr->error)
+	if (ctrl_hdlr->error) {
+		v4l2_ctrl_handler_free(ctrl_hdlr);
 		return ctrl_hdlr->error;
+	}
 
 	ov5675->sd.ctrl_handler = ctrl_hdlr;
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov5695.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov5695.c
@@ -971,16 +971,9 @@
 	return ret;
 }
 
-/* Calculate the delay in us by clock rate and clock cycles */
-static inline u32 ov5695_cal_delay(u32 cycles)
-{
-	return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000);
-}
-
 static int __ov5695_power_on(struct ov5695 *ov5695)
 {
-	int ret;
-	u32 delay_us;
+	int i, ret;
 	struct device *dev = &ov5695->client->dev;
 
 	ret = clk_prepare_enable(ov5695->xvclk);
@@ -991,21 +984,28 @@
 
 	gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
 
-	ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);
-	if (ret < 0) {
-		dev_err(dev, "Failed to enable regulators\n");
-		goto disable_clk;
+	/*
+	 * The hardware requires the regulators to be powered on in order,
+	 * so enable them one by one.
+	 */
+	for (i = 0; i < OV5695_NUM_SUPPLIES; i++) {
+		ret = regulator_enable(ov5695->supplies[i].consumer);
+		if (ret) {
+			dev_err(dev, "Failed to enable %s: %d\n",
+				ov5695->supplies[i].supply, ret);
+			goto disable_reg_clk;
+		}
 	}
 
 	gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
 
-	/* 8192 cycles prior to first SCCB transaction */
-	delay_us = ov5695_cal_delay(8192);
-	usleep_range(delay_us, delay_us * 2);
+	usleep_range(1000, 1200);
 
 	return 0;
 
-disable_clk:
+disable_reg_clk:
+	for (--i; i >= 0; i--)
+		regulator_disable(ov5695->supplies[i].consumer);
 	clk_disable_unprepare(ov5695->xvclk);
 
 	return ret;
@@ -1013,9 +1013,22 @@
 
 static void __ov5695_power_off(struct ov5695 *ov5695)
 {
+	struct device *dev = &ov5695->client->dev;
+	int i, ret;
+
 	clk_disable_unprepare(ov5695->xvclk);
 	gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
-	regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies);
+
+	/*
+	 * The hardware requires the regulators to be powered off in order,
+	 * so disable them one by one.
+	 */
+	for (i = OV5695_NUM_SUPPLIES - 1; i >= 0; i--) {
+		ret = regulator_disable(ov5695->supplies[i].consumer);
+		if (ret)
+			dev_err(dev, "Failed to disable %s: %d\n",
+				ov5695->supplies[i].supply, ret);
+	}
 }
 
 static int __maybe_unused ov5695_runtime_resume(struct device *dev)
@@ -1285,7 +1298,7 @@
 	if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
 		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
 
-	ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 	if (IS_ERR(ov5695->reset_gpio)) {
 		dev_err(dev, "Failed to get reset-gpios\n");
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov6650.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov6650.c
@@ -130,6 +130,7 @@
 #define CLKRC_24MHz		0xc0
 #define CLKRC_DIV_MASK		0x3f
 #define GET_CLKRC_DIV(x)	(((x) & CLKRC_DIV_MASK) + 1)
+#define DEF_CLKRC		0x00
 
 #define COMA_RESET		BIT(7)
 #define COMA_QCIF		BIT(5)
@@ -200,7 +201,6 @@
 	unsigned long		pclk_max;	/* from resolution and format */
 	struct v4l2_fract	tpf;		/* as requested with s_frame_interval */
 	u32 code;
-	enum v4l2_colorspace	colorspace;
 };
 
 
@@ -213,6 +213,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)
 {
@@ -465,38 +476,39 @@
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov6650 *priv = to_ov6650(client);
-	struct v4l2_rect rect = sel->r;
 	int ret;
 
 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
 	    sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
 
-	v4l_bound_align_image(&rect.width, 2, W_CIF, 1,
-			      &rect.height, 2, H_CIF, 1, 0);
-	v4l_bound_align_image(&rect.left, DEF_HSTRT << 1,
-			      (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1,
-			      &rect.top, DEF_VSTRT << 1,
-			      (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1,
-			      0);
+	v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
+			      &sel->r.height, 2, H_CIF, 1, 0);
+	v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
+			      (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1,
+			      &sel->r.top, DEF_VSTRT << 1,
+			      (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height,
+			      1, 0);
 
-	ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1);
+	ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
 	if (!ret) {
-		priv->rect.left = rect.left;
+		priv->rect.width += priv->rect.left - sel->r.left;
+		priv->rect.left = sel->r.left;
 		ret = ov6650_reg_write(client, REG_HSTOP,
-				(rect.left + rect.width) >> 1);
+				       (sel->r.left + sel->r.width) >> 1);
 	}
 	if (!ret) {
-		priv->rect.width = rect.width;
-		ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1);
+		priv->rect.width = sel->r.width;
+		ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
 	}
 	if (!ret) {
-		priv->rect.top = rect.top;
+		priv->rect.height += priv->rect.top - sel->r.top;
+		priv->rect.top = sel->r.top;
 		ret = ov6650_reg_write(client, REG_VSTOP,
-				(rect.top + rect.height) >> 1);
+				       (sel->r.top + sel->r.height) >> 1);
 	}
 	if (!ret)
-		priv->rect.height = rect.height;
+		priv->rect.height = sel->r.height;
 
 	return ret;
 }
@@ -512,12 +524,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;
 }
 
@@ -610,7 +630,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) {
@@ -623,11 +642,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;
@@ -636,7 +650,6 @@
 		dev_dbg(&client->dev, "max resolution: CIF\n");
 		coma_mask |= COMA_QCIF;
 	}
-	priv->half_scale = half_scale;
 
 	clkrc = CLKRC_12MHz;
 	mclk = 12000000;
@@ -654,14 +667,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;
 }
 
@@ -680,8 +693,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;
@@ -691,20 +702,39 @@
 	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;
 		/* fall through */
 	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;
 }
 
@@ -754,19 +784,17 @@
 	else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
 		div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
 
-	/*
-	 * Keep result to be used as tpf limit
-	 * for subsequent clock divider calculations
-	 */
-	priv->tpf.numerator = div;
-	priv->tpf.denominator = FRAME_RATE_MAX;
+	tpf->numerator = div;
+	tpf->denominator = FRAME_RATE_MAX;
 
-	clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+	clkrc = to_clkrc(tpf, priv->pclk_limit, priv->pclk_max);
 
 	ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
 	if (!ret) {
-		tpf->numerator = GET_CLKRC_DIV(clkrc);
-		tpf->denominator = FRAME_RATE_MAX;
+		priv->tpf.numerator = GET_CLKRC_DIV(clkrc);
+		priv->tpf.denominator = FRAME_RATE_MAX;
+
+		*tpf = priv->tpf;
 	}
 
 	return ret;
@@ -849,6 +877,11 @@
 	ret = ov6650_reset(client);
 	if (!ret)
 		ret = ov6650_prog_dflt(client);
+	if (!ret) {
+		struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
+
+		ret = ov6650_s_fmt(sd, &mf);
+	}
 	if (!ret)
 		ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
@@ -989,8 +1022,10 @@
 			V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
 
 	priv->subdev.ctrl_handler = &priv->hdl;
-	if (priv->hdl.error)
-		return priv->hdl.error;
+	if (priv->hdl.error) {
+		ret = priv->hdl.error;
+		goto ectlhdlfree;
+	}
 
 	v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
 	v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
@@ -1001,15 +1036,18 @@
 	priv->rect.top	  = DEF_VSTRT << 1;
 	priv->rect.width  = W_CIF;
 	priv->rect.height = H_CIF;
-	priv->half_scale  = false;
-	priv->code	  = MEDIA_BUS_FMT_YUYV8_2X8;
-	priv->colorspace  = V4L2_COLORSPACE_JPEG;
+
+	/* Hardware default frame interval */
+	priv->tpf.numerator   = GET_CLKRC_DIV(DEF_CLKRC);
+	priv->tpf.denominator = FRAME_RATE_MAX;
 
 	priv->subdev.internal_ops = &ov6650_internal_ops;
 
 	ret = v4l2_async_register_subdev(&priv->subdev);
-	if (ret)
-		v4l2_ctrl_handler_free(&priv->hdl);
+	if (!ret)
+		return 0;
+ectlhdlfree:
+	v4l2_ctrl_handler_free(&priv->hdl);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov7670.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov7670.c
@@ -1824,7 +1824,7 @@
 
 	if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
 		dev_err(dev, "Unsupported media bus type\n");
-		return ret;
+		return -EINVAL;
 	}
 	info->mbus_config = bus_cfg.bus.parallel.flags;
 
@@ -2000,7 +2000,6 @@
 	v4l2_async_unregister_subdev(sd);
 	v4l2_ctrl_handler_free(&info->hdl);
 	media_entity_cleanup(&info->sd.entity);
-	ov7670_power_off(sd);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/ov772x.c
+++ linux-ein-5.4.0/drivers/media/i2c/ov772x.c
@@ -1397,7 +1397,7 @@
 	priv->subdev.ctrl_handler = &priv->hdl;
 	if (priv->hdl.error) {
 		ret = priv->hdl.error;
-		goto error_mutex_destroy;
+		goto error_ctrl_free;
 	}
 
 	priv->clk = clk_get(&client->dev, NULL);
@@ -1446,7 +1446,6 @@
 	clk_put(priv->clk);
 error_ctrl_free:
 	v4l2_ctrl_handler_free(&priv->hdl);
-error_mutex_destroy:
 	mutex_destroy(&priv->lock);
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ linux-ein-5.4.0/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1386,7 +1386,7 @@
 	s5c73m3_gpio_deassert(state, STBY);
 	usleep_range(100, 200);
 
-	s5c73m3_gpio_deassert(state, RST);
+	s5c73m3_gpio_deassert(state, RSET);
 	usleep_range(50, 100);
 
 	return 0;
@@ -1401,7 +1401,7 @@
 {
 	int i, ret;
 
-	if (s5c73m3_gpio_assert(state, RST))
+	if (s5c73m3_gpio_assert(state, RSET))
 		usleep_range(10, 50);
 
 	if (s5c73m3_gpio_assert(state, STBY))
@@ -1606,7 +1606,7 @@
 
 		state->mclk_frequency = pdata->mclk_frequency;
 		state->gpio[STBY] = pdata->gpio_stby;
-		state->gpio[RST] = pdata->gpio_reset;
+		state->gpio[RSET] = pdata->gpio_reset;
 		return 0;
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ linux-ein-5.4.0/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -353,7 +353,7 @@
 
 enum s5c73m3_gpio_id {
 	STBY,
-	RST,
+	RSET,
 	GPIO_NUM,
 };
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/s5k4ecgx.c
+++ linux-ein-5.4.0/drivers/media/i2c/s5k4ecgx.c
@@ -173,7 +173,7 @@
 
 enum s5k4ecgx_gpio_id {
 	STBY,
-	RST,
+	RSET,
 	GPIO_NUM,
 };
 
@@ -476,7 +476,7 @@
 	if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level))
 		usleep_range(30, 50);
 
-	if (s5k4ecgx_gpio_set_value(priv, RST, priv->gpio[RST].level))
+	if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level))
 		usleep_range(30, 50);
 
 	return 0;
@@ -484,7 +484,7 @@
 
 static int __s5k4ecgx_power_off(struct s5k4ecgx *priv)
 {
-	if (s5k4ecgx_gpio_set_value(priv, RST, !priv->gpio[RST].level))
+	if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level))
 		usleep_range(30, 50);
 
 	if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level))
@@ -872,7 +872,7 @@
 	int ret;
 
 	priv->gpio[STBY].gpio = -EINVAL;
-	priv->gpio[RST].gpio  = -EINVAL;
+	priv->gpio[RSET].gpio  = -EINVAL;
 
 	ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY");
 
@@ -891,7 +891,7 @@
 		s5k4ecgx_free_gpios(priv);
 		return ret;
 	}
-	priv->gpio[RST] = *gpio;
+	priv->gpio[RSET] = *gpio;
 	if (gpio_is_valid(gpio->gpio))
 		gpio_set_value(gpio->gpio, 0);
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/s5k5baf.c
+++ linux-ein-5.4.0/drivers/media/i2c/s5k5baf.c
@@ -235,7 +235,7 @@
 
 enum s5k5baf_gpio_id {
 	STBY,
-	RST,
+	RSET,
 	NUM_GPIOS,
 };
 
@@ -970,7 +970,7 @@
 
 	s5k5baf_gpio_deassert(state, STBY);
 	usleep_range(50, 100);
-	s5k5baf_gpio_deassert(state, RST);
+	s5k5baf_gpio_deassert(state, RSET);
 	return 0;
 
 err_reg_dis:
@@ -988,7 +988,7 @@
 	state->apply_cfg = 0;
 	state->apply_crop = 0;
 
-	s5k5baf_gpio_assert(state, RST);
+	s5k5baf_gpio_assert(state, RSET);
 	s5k5baf_gpio_assert(state, STBY);
 
 	if (!IS_ERR(state->clock))
--- linux-ein-5.4.0.orig/drivers/media/i2c/s5k6aa.c
+++ linux-ein-5.4.0/drivers/media/i2c/s5k6aa.c
@@ -177,7 +177,7 @@
 
 enum s5k6aa_gpio_id {
 	STBY,
-	RST,
+	RSET,
 	GPIO_NUM,
 };
 
@@ -841,7 +841,7 @@
 		ret = s5k6aa->s_power(1);
 	usleep_range(4000, 5000);
 
-	if (s5k6aa_gpio_deassert(s5k6aa, RST))
+	if (s5k6aa_gpio_deassert(s5k6aa, RSET))
 		msleep(20);
 
 	return ret;
@@ -851,7 +851,7 @@
 {
 	int ret;
 
-	if (s5k6aa_gpio_assert(s5k6aa, RST))
+	if (s5k6aa_gpio_assert(s5k6aa, RSET))
 		usleep_range(100, 150);
 
 	if (s5k6aa->s_power) {
@@ -1510,7 +1510,7 @@
 	int ret;
 
 	s5k6aa->gpio[STBY].gpio = -EINVAL;
-	s5k6aa->gpio[RST].gpio  = -EINVAL;
+	s5k6aa->gpio[RSET].gpio  = -EINVAL;
 
 	gpio = &pdata->gpio_stby;
 	if (gpio_is_valid(gpio->gpio)) {
@@ -1533,7 +1533,7 @@
 		if (ret < 0)
 			return ret;
 
-		s5k6aa->gpio[RST] = *gpio;
+		s5k6aa->gpio[RSET] = *gpio;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/media/i2c/saa6588.c
+++ linux-ein-5.4.0/drivers/media/i2c/saa6588.c
@@ -380,7 +380,7 @@
 
 /* ---------------------------------------------------------------------- */
 
-static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+static long saa6588_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	struct saa6588 *s = to_saa6588(sd);
 	struct saa6588_command *a = arg;
@@ -433,7 +433,7 @@
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa6588_core_ops = {
-	.ioctl = saa6588_ioctl,
+	.command = saa6588_command,
 };
 
 static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
--- linux-ein-5.4.0.orig/drivers/media/i2c/smiapp/smiapp-core.c
+++ linux-ein-5.4.0/drivers/media/i2c/smiapp/smiapp-core.c
@@ -2327,11 +2327,12 @@
 		if (rval < 0) {
 			if (rval != -EBUSY && rval != -EAGAIN)
 				pm_runtime_set_active(&client->dev);
-			pm_runtime_put(&client->dev);
+			pm_runtime_put_noidle(&client->dev);
 			return -ENODEV;
 		}
 
 		if (smiapp_read_nvm(sensor, sensor->nvm)) {
+			pm_runtime_put(&client->dev);
 			dev_err(&client->dev, "nvm read failed\n");
 			return -ENODEV;
 		}
@@ -3101,19 +3102,23 @@
 	if (rval < 0)
 		goto out_media_entity_cleanup;
 
-	rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
-	if (rval < 0)
-		goto out_media_entity_cleanup;
-
 	pm_runtime_set_active(&client->dev);
 	pm_runtime_get_noresume(&client->dev);
 	pm_runtime_enable(&client->dev);
+
+	rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
+	if (rval < 0)
+		goto out_disable_runtime_pm;
+
 	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
 	pm_runtime_use_autosuspend(&client->dev);
 	pm_runtime_put_autosuspend(&client->dev);
 
 	return 0;
 
+out_disable_runtime_pm:
+	pm_runtime_disable(&client->dev);
+
 out_media_entity_cleanup:
 	media_entity_cleanup(&sensor->src->sd.entity);
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/st-mipid02.c
+++ linux-ein-5.4.0/drivers/media/i2c/st-mipid02.c
@@ -971,6 +971,11 @@
 	bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset",
 						     GPIOD_OUT_HIGH);
 
+	if (IS_ERR(bridge->reset_gpio)) {
+		dev_err(dev, "failed to get reset GPIO\n");
+		return PTR_ERR(bridge->reset_gpio);
+	}
+
 	ret = mipid02_get_regulators(bridge);
 	if (ret) {
 		dev_err(dev, "failed to get regulators %d", ret);
--- linux-ein-5.4.0.orig/drivers/media/i2c/tc358743.c
+++ linux-ein-5.4.0/drivers/media/i2c/tc358743.c
@@ -919,8 +919,8 @@
 	.adap_monitor_all_enable = tc358743_cec_adap_monitor_all_enable,
 };
 
-static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus,
-			     bool *handled)
+static void tc358743_cec_handler(struct v4l2_subdev *sd, u16 intstatus,
+				 bool *handled)
 {
 	struct tc358743_state *state = to_state(sd);
 	unsigned int cec_rxint, cec_txint;
@@ -953,7 +953,8 @@
 			cec_transmit_attempt_done(state->cec_adap,
 						  CEC_TX_STATUS_ERROR);
 		}
-		*handled = true;
+		if (handled)
+			*handled = true;
 	}
 	if ((intstatus & MASK_CEC_RINT) &&
 	    (cec_rxint & MASK_CECRIEND)) {
@@ -968,7 +969,8 @@
 			msg.msg[i] = v & 0xff;
 		}
 		cec_received_msg(state->cec_adap, &msg);
-		*handled = true;
+		if (handled)
+			*handled = true;
 	}
 	i2c_wr16(sd, INTSTATUS,
 		 intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
@@ -1432,7 +1434,7 @@
 
 #ifdef CONFIG_VIDEO_TC358743_CEC
 	if (intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)) {
-		tc358743_cec_isr(sd, intstatus, handled);
+		tc358743_cec_handler(sd, intstatus, handled);
 		i2c_wr16(sd, INTSTATUS,
 			 intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
 		intstatus &= ~(MASK_CEC_RINT | MASK_CEC_TINT);
@@ -1461,7 +1463,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);
 
@@ -1971,6 +1973,7 @@
 	bps_pr_lane = 2 * endpoint.link_frequencies[0];
 	if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
 		dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
+		ret = -EINVAL;
 		goto disable_clk;
 	}
 
@@ -2190,7 +2193,7 @@
 		del_timer_sync(&state->timer);
 		flush_work(&state->work_i2c_poll);
 	}
-	cancel_delayed_work(&state->delayed_work_enable_hotplug);
+	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
 	cec_unregister_adapter(state->cec_adap);
 	v4l2_async_unregister_subdev(sd);
 	v4l2_device_unregister_subdev(sd);
--- linux-ein-5.4.0.orig/drivers/media/i2c/tda1997x.c
+++ linux-ein-5.4.0/drivers/media/i2c/tda1997x.c
@@ -1247,13 +1247,13 @@
 {
 	struct v4l2_subdev *sd = &state->sd;
 	union hdmi_infoframe frame;
-	u8 buffer[40];
+	u8 buffer[40] = { 0 };
 	u8 reg;
 	int len, err;
 
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
-	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
+	err = hdmi_infoframe_unpack(&frame, buffer, len);
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1695,14 +1695,15 @@
 				     struct v4l2_dv_timings *timings)
 {
 	struct tda1997x_state *state = to_state(sd);
+	int ret;
 
 	v4l_dbg(1, debug, state->client, "%s\n", __func__);
 	memset(timings, 0, sizeof(struct v4l2_dv_timings));
 	mutex_lock(&state->lock);
-	tda1997x_detect_std(state, timings);
+	ret = tda1997x_detect_std(state, timings);
 	mutex_unlock(&state->lock);
 
-	return 0;
+	return ret;
 }
 
 static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
@@ -1926,13 +1927,13 @@
 {
 	struct tda1997x_state *state = to_state(sd);
 	union hdmi_infoframe frame;
-	u8 buffer[40];
+	u8 buffer[40] = { 0 };
 	int len, err;
 
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
 	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
-	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
+	err = hdmi_infoframe_unpack(&frame, buffer, len);
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -2233,6 +2234,7 @@
 	/* get initial HDMI status */
 	state->hdmi_status = io_read(sd, REG_HDMI_FLAGS);
 
+	io_write(sd, REG_EDID_ENABLE, EDID_ENABLE_A_EN | EDID_ENABLE_B_EN);
 	return 0;
 }
 
@@ -2804,7 +2806,7 @@
 	media_entity_cleanup(&sd->entity);
 	v4l2_ctrl_handler_free(&state->hdl);
 	regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies);
-	cancel_delayed_work(&state->delayed_work_enable_hpd);
+	cancel_delayed_work_sync(&state->delayed_work_enable_hpd);
 	mutex_destroy(&state->page_lock);
 	mutex_destroy(&state->lock);
 
--- linux-ein-5.4.0.orig/drivers/media/i2c/video-i2c.c
+++ linux-ein-5.4.0/drivers/media/i2c/video-i2c.c
@@ -255,7 +255,7 @@
 	return amg88xx_set_power_off(data);
 }
 
-#if IS_ENABLED(CONFIG_HWMON)
+#if IS_REACHABLE(CONFIG_HWMON)
 
 static const u32 amg88xx_temp_config[] = {
 	HWMON_T_INPUT,
--- linux-ein-5.4.0.orig/drivers/media/mc/Makefile
+++ linux-ein-5.4.0/drivers/media/mc/Makefile
@@ -3,7 +3,7 @@
 mc-objs	:= mc-device.o mc-devnode.o mc-entity.o \
 	   mc-request.o
 
-ifeq ($(CONFIG_USB),y)
+ifneq ($(CONFIG_USB),)
 	mc-objs += mc-dev-allocator.o
 endif
 
--- linux-ein-5.4.0.orig/drivers/media/mc/mc-device.c
+++ linux-ein-5.4.0/drivers/media/mc/mc-device.c
@@ -575,6 +575,38 @@
 	dev_dbg(devnode->parent, "Media device released\n");
 }
 
+static void __media_device_unregister_entity(struct media_entity *entity)
+{
+	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_link *link, *tmp;
+	struct media_interface *intf;
+	unsigned int i;
+
+	ida_free(&mdev->entity_internal_idx, entity->internal_idx);
+
+	/* Remove all interface links pointing to this entity */
+	list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
+		list_for_each_entry_safe(link, tmp, &intf->links, list) {
+			if (link->entity == entity)
+				__media_remove_intf_link(link);
+		}
+	}
+
+	/* Remove all data links that belong to this entity */
+	__media_entity_remove_links(entity);
+
+	/* Remove all pads that belong to this entity */
+	for (i = 0; i < entity->num_pads; i++)
+		media_gobj_destroy(&entity->pads[i].graph_obj);
+
+	/* Remove the entity */
+	media_gobj_destroy(&entity->graph_obj);
+
+	/* invoke entity_notify callbacks to handle entity removal?? */
+
+	entity->graph_obj.mdev = NULL;
+}
+
 /**
  * media_device_register_entity - Register an entity with a media device
  * @mdev:	The media device
@@ -632,6 +664,7 @@
 		 */
 		ret = media_graph_walk_init(&new, mdev);
 		if (ret) {
+			__media_device_unregister_entity(entity);
 			mutex_unlock(&mdev->graph_mutex);
 			return ret;
 		}
@@ -644,38 +677,6 @@
 }
 EXPORT_SYMBOL_GPL(media_device_register_entity);
 
-static void __media_device_unregister_entity(struct media_entity *entity)
-{
-	struct media_device *mdev = entity->graph_obj.mdev;
-	struct media_link *link, *tmp;
-	struct media_interface *intf;
-	unsigned int i;
-
-	ida_free(&mdev->entity_internal_idx, entity->internal_idx);
-
-	/* Remove all interface links pointing to this entity */
-	list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
-		list_for_each_entry_safe(link, tmp, &intf->links, list) {
-			if (link->entity == entity)
-				__media_remove_intf_link(link);
-		}
-	}
-
-	/* Remove all data links that belong to this entity */
-	__media_entity_remove_links(entity);
-
-	/* Remove all pads that belong to this entity */
-	for (i = 0; i < entity->num_pads; i++)
-		media_gobj_destroy(&entity->pads[i].graph_obj);
-
-	/* Remove the entity */
-	media_gobj_destroy(&entity->graph_obj);
-
-	/* invoke entity_notify callbacks to handle entity removal?? */
-
-	entity->graph_obj.mdev = NULL;
-}
-
 void media_device_unregister_entity(struct media_entity *entity)
 {
 	struct media_device *mdev = entity->graph_obj.mdev;
--- linux-ein-5.4.0.orig/drivers/media/mc/mc-entity.c
+++ linux-ein-5.4.0/drivers/media/mc/mc-entity.c
@@ -386,7 +386,7 @@
 	if (ret)
 		return ret;
 
-	ret = entity->ops->get_fwnode_pad(&endpoint);
+	ret = entity->ops->get_fwnode_pad(entity, &endpoint);
 	if (ret < 0)
 		return ret;
 
@@ -639,9 +639,9 @@
 		return -EINVAL;
 
 	for (i = 0; i < entity->num_pads; i++) {
-		if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
+		if (entity->pads[i].flags & MEDIA_PAD_FL_SINK)
 			pad_is_sink = true;
-		else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
+		else if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE)
 			pad_is_sink = false;
 		else
 			continue;	/* This is an error! */
--- linux-ein-5.4.0.orig/drivers/media/mc/mc-request.c
+++ linux-ein-5.4.0/drivers/media/mc/mc-request.c
@@ -296,9 +296,18 @@
 	if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
 		return -ENOMEM;
 
+	if (mdev->ops->req_alloc)
+		req = mdev->ops->req_alloc(mdev);
+	else
+		req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
 	fd = get_unused_fd_flags(O_CLOEXEC);
-	if (fd < 0)
-		return fd;
+	if (fd < 0) {
+		ret = fd;
+		goto err_free_req;
+	}
 
 	filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
 	if (IS_ERR(filp)) {
@@ -306,15 +315,6 @@
 		goto err_put_fd;
 	}
 
-	if (mdev->ops->req_alloc)
-		req = mdev->ops->req_alloc(mdev);
-	else
-		req = kzalloc(sizeof(*req), GFP_KERNEL);
-	if (!req) {
-		ret = -ENOMEM;
-		goto err_fput;
-	}
-
 	filp->private_data = req;
 	req->mdev = mdev;
 	req->state = MEDIA_REQUEST_STATE_IDLE;
@@ -336,12 +336,15 @@
 
 	return 0;
 
-err_fput:
-	fput(filp);
-
 err_put_fd:
 	put_unused_fd(fd);
 
+err_free_req:
+	if (mdev->ops->req_free)
+		mdev->ops->req_free(req);
+	else
+		kfree(req);
+
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/pci/b2c2/flexcop-pci.c
+++ linux-ein-5.4.0/drivers/media/pci/b2c2/flexcop-pci.c
@@ -185,6 +185,8 @@
 		dma_addr_t cur_addr =
 			fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
 		u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
+		if (cur_pos > fc_pci->dma[0].size * 2)
+			goto error;
 
 		deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ",
 				jiffies_to_usecs(jiffies - fc_pci->last_irq),
@@ -225,6 +227,7 @@
 		ret = IRQ_NONE;
 	}
 
+error:
 	spin_unlock_irqrestore(&fc_pci->irq_lock, flags);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/pci/bt8xx/bt878.c
+++ linux-ein-5.4.0/drivers/media/pci/bt8xx/bt878.c
@@ -477,6 +477,9 @@
 	btwrite(0, BT878_AINT_MASK);
 	bt878_num++;
 
+	if (!bt->tasklet.func)
+		tasklet_disable(&bt->tasklet);
+
 	return 0;
 
       fail2:
--- linux-ein-5.4.0.orig/drivers/media/pci/bt8xx/bttv-driver.c
+++ linux-ein-5.4.0/drivers/media/pci/bt8xx/bttv-driver.c
@@ -3187,7 +3187,7 @@
 
 	btv->radio_user--;
 
-	bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+	bttv_call_all(btv, core, command, SAA6588_CMD_CLOSE, &cmd);
 
 	if (btv->radio_user == 0)
 		btv->has_radio_tuner = 0;
@@ -3268,7 +3268,7 @@
 	cmd.result = -ENODEV;
 	radio_enable(btv);
 
-	bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
+	bttv_call_all(btv, core, command, SAA6588_CMD_READ, &cmd);
 
 	return cmd.result;
 }
@@ -3289,7 +3289,7 @@
 	cmd.instance = file;
 	cmd.event_list = wait;
 	cmd.poll_mask = res;
-	bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
+	bttv_call_all(btv, core, command, SAA6588_CMD_POLL, &cmd);
 
 	return cmd.poll_mask;
 }
@@ -3898,7 +3898,7 @@
 
 	/* video */
 	vdev_init(btv, &btv->video_dev, &bttv_video_template, "video");
-	btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+	btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
 				     V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 	if (btv->tuner_type != TUNER_ABSENT)
 		btv->video_dev.device_caps |= V4L2_CAP_TUNER;
@@ -3919,7 +3919,7 @@
 	/* vbi */
 	vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi");
 	btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE |
-				   V4L2_CAP_STREAMING | V4L2_CAP_TUNER;
+				   V4L2_CAP_STREAMING;
 	if (btv->tuner_type != TUNER_ABSENT)
 		btv->vbi_dev.device_caps |= V4L2_CAP_TUNER;
 
@@ -4013,11 +4013,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),
@@ -4025,7 +4027,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);
@@ -4211,6 +4214,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;
 }
 
@@ -4251,6 +4258,7 @@
 
 	/* free resources */
 	free_irq(btv->c.pci->irq,btv);
+	del_timer_sync(&btv->timeout);
 	iounmap(btv->bt848_mmio);
 	release_mem_region(pci_resource_start(btv->c.pci,0),
 			   pci_resource_len(btv->c.pci,0));
--- linux-ein-5.4.0.orig/drivers/media/pci/bt8xx/dst.c
+++ linux-ein-5.4.0/drivers/media/pci/bt8xx/dst.c
@@ -1722,7 +1722,7 @@
 	return state;				/*	Manu (DST is a card not a frontend)	*/
 }
 
-EXPORT_SYMBOL(dst_attach);
+EXPORT_SYMBOL_GPL(dst_attach);
 
 static const struct dvb_frontend_ops dst_dvbt_ops = {
 	.delsys = { SYS_DVBT },
--- linux-ein-5.4.0.orig/drivers/media/pci/bt8xx/dst_ca.c
+++ linux-ein-5.4.0/drivers/media/pci/bt8xx/dst_ca.c
@@ -668,7 +668,7 @@
 	return NULL;
 }
 
-EXPORT_SYMBOL(dst_ca_attach);
+EXPORT_SYMBOL_GPL(dst_ca_attach);
 
 MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
 MODULE_AUTHOR("Manu Abraham");
--- linux-ein-5.4.0.orig/drivers/media/pci/cobalt/cobalt-driver.c
+++ linux-ein-5.4.0/drivers/media/pci/cobalt/cobalt-driver.c
@@ -8,6 +8,7 @@
  *  All rights reserved.
  */
 
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <media/i2c/adv7604.h>
 #include <media/i2c/adv7842.h>
@@ -210,17 +211,17 @@
 	pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &stat);
 	cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n",
 			capa, get_link_speed(capa),
-			(capa & PCI_EXP_LNKCAP_MLW) >> 4);
+			FIELD_GET(PCI_EXP_LNKCAP_MLW, capa));
 	cobalt_info("PCIe link control 0x%04x\n", ctrl);
 	cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n",
 		    stat, get_link_speed(stat),
-		    (stat & PCI_EXP_LNKSTA_NLW) >> 4);
+		    FIELD_GET(PCI_EXP_LNKSTA_NLW, stat));
 
 	/* Bus */
 	pcie_capability_read_dword(pci_bus_dev, PCI_EXP_LNKCAP, &capa);
 	cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n",
 			capa, get_link_speed(capa),
-			(capa & PCI_EXP_LNKCAP_MLW) >> 4);
+			FIELD_GET(PCI_EXP_LNKCAP_MLW, capa));
 
 	/* Slot */
 	pcie_capability_read_dword(pci_dev, PCI_EXP_SLTCAP, &capa);
@@ -239,7 +240,7 @@
 	if (!pci_is_pcie(pci_dev))
 		return 0;
 	pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &link);
-	return (link & PCI_EXP_LNKSTA_NLW) >> 4;
+	return FIELD_GET(PCI_EXP_LNKSTA_NLW, link);
 }
 
 static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt)
@@ -250,7 +251,7 @@
 	if (!pci_is_pcie(pci_dev))
 		return 0;
 	pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &link);
-	return (link & PCI_EXP_LNKCAP_MLW) >> 4;
+	return FIELD_GET(PCI_EXP_LNKCAP_MLW, link);
 }
 
 static void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev)
@@ -667,6 +668,7 @@
 		return -ENOMEM;
 	cobalt->pci_dev = pci_dev;
 	cobalt->instance = i;
+	mutex_init(&cobalt->pci_lock);
 
 	retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev);
 	if (retval) {
--- linux-ein-5.4.0.orig/drivers/media/pci/cobalt/cobalt-driver.h
+++ linux-ein-5.4.0/drivers/media/pci/cobalt/cobalt-driver.h
@@ -251,6 +251,8 @@
 	int instance;
 	struct pci_dev *pci_dev;
 	struct v4l2_device v4l2_dev;
+	/* serialize PCI access in cobalt_s_bit_sysctrl() */
+	struct mutex pci_lock;
 
 	void __iomem *bar0, *bar1;
 
@@ -320,10 +322,13 @@
 static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt,
 					int bit, int val)
 {
-	u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
+	u32 ctrl;
 
+	mutex_lock(&cobalt->pci_lock);
+	ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
 	cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE,
 			(ctrl & ~(1UL << bit)) | (val << bit));
+	mutex_unlock(&cobalt->pci_lock);
 }
 
 static inline u32 cobalt_g_sysstat(struct cobalt *cobalt)
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23885-alsa.c
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -550,7 +550,7 @@
 			   SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 			THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
 	if (err < 0)
-		goto error;
+		goto error_msg;
 
 	chip = (struct cx23885_audio_dev *) card->private_data;
 	chip->dev = dev;
@@ -576,6 +576,7 @@
 
 error:
 	snd_card_free(card);
+error_msg:
 	pr_err("%s(): Failed to register analog audio adapter\n",
 	       __func__);
 
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23885-cards.c
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23885-cards.c
@@ -801,6 +801,25 @@
 		.name		= "Hauppauge WinTV-Starburst2",
 		.portb		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_AVERMEDIA_CE310B] = {
+		.name		= "AVerMedia CE310B",
+		.porta		= CX23885_ANALOG_VIDEO,
+		.force_bff	= 1,
+		.input          = {{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = CX25840_VIN1_CH1 |
+				  CX25840_NONE_CH2 |
+				  CX25840_NONE0_CH3,
+			.amux   = CX25840_AUDIO7,
+		}, {
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = CX25840_VIN8_CH1 |
+				  CX25840_NONE_CH2 |
+				  CX25840_VIN7_CH3 |
+				  CX25840_SVIDEO_ON,
+			.amux   = CX25840_AUDIO7,
+		} },
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -1124,6 +1143,10 @@
 		.subvendor = 0x0070,
 		.subdevice = 0xf02a,
 		.card      = CX23885_BOARD_HAUPPAUGE_STARBURST2,
+	}, {
+		.subvendor = 0x1461,
+		.subdevice = 0x3100,
+		.card      = CX23885_BOARD_AVERMEDIA_CE310B,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -2348,6 +2371,7 @@
 	case CX23885_BOARD_DVBSKY_T982:
 	case CX23885_BOARD_VIEWCAST_260E:
 	case CX23885_BOARD_VIEWCAST_460E:
+	case CX23885_BOARD_AVERMEDIA_CE310B:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", 0x88 >> 1, NULL);
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23885-core.c
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23885-core.c
@@ -2074,6 +2074,10 @@
 	 * 0x1451 is PCI ID for the IOMMU found on Ryzen
 	 */
 	{ PCI_VENDOR_ID_AMD, 0x1451 },
+	/* According to sudo lspci -nn,
+	 * 0x1423 is the PCI ID for the IOMMU found on Kaveri
+	 */
+	{ PCI_VENDOR_ID_AMD, 0x1423 },
 };
 
 static bool cx23885_does_need_dma_reset(void)
@@ -2150,7 +2154,7 @@
 	err = pci_set_dma_mask(pci_dev, 0xffffffff);
 	if (err) {
 		pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
-		goto fail_ctrl;
+		goto fail_dma_set_mask;
 	}
 
 	err = request_irq(pci_dev->irq, cx23885_irq,
@@ -2158,7 +2162,7 @@
 	if (err < 0) {
 		pr_err("%s: can't get IRQ %d\n",
 		       dev->name, pci_dev->irq);
-		goto fail_irq;
+		goto fail_dma_set_mask;
 	}
 
 	switch (dev->board) {
@@ -2180,7 +2184,7 @@
 
 	return 0;
 
-fail_irq:
+fail_dma_set_mask:
 	cx23885_dev_unregister(dev);
 fail_ctrl:
 	v4l2_ctrl_handler_free(hdl);
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23885-video.c
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23885-video.c
@@ -257,7 +257,8 @@
 		(dev->board == CX23885_BOARD_MYGICA_X8507) ||
 		(dev->board == CX23885_BOARD_AVERMEDIA_HC81R) ||
 		(dev->board == CX23885_BOARD_VIEWCAST_260E) ||
-		(dev->board == CX23885_BOARD_VIEWCAST_460E)) {
+		(dev->board == CX23885_BOARD_VIEWCAST_460E) ||
+		(dev->board == CX23885_BOARD_AVERMEDIA_CE310B)) {
 		/* Configure audio routing */
 		v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
 			INPUT(input)->amux, 0, 0);
@@ -408,7 +409,7 @@
 				dev->height >> 1);
 		break;
 	default:
-		BUG();
+		return -EINVAL; /* should not happen */
 	}
 	dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp 0x%08x - dma=0x%08lx\n",
 		buf, buf->vb.vb2_buf.index,
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23885.h
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23885.h
@@ -101,6 +101,7 @@
 #define CX23885_BOARD_HAUPPAUGE_STARBURST2     59
 #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885 60
 #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885 61
+#define CX23885_BOARD_AVERMEDIA_CE310B         62
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
--- linux-ein-5.4.0.orig/drivers/media/pci/cx23885/cx23888-ir.c
+++ linux-ein-5.4.0/drivers/media/pci/cx23885/cx23888-ir.c
@@ -1167,8 +1167,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-ein-5.4.0.orig/drivers/media/pci/cx25821/cx25821-core.c
+++ linux-ein-5.4.0/drivers/media/pci/cx25821/cx25821-core.c
@@ -976,8 +976,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)
@@ -1338,11 +1340,11 @@
 	struct cx25821_dev *dev = get_cx25821(v4l2_dev);
 
 	cx25821_shutdown(dev);
-	pci_disable_device(pci_dev);
 
 	/* unregister stuff */
 	if (pci_dev->irq)
 		free_irq(pci_dev->irq, dev);
+	pci_disable_device(pci_dev);
 
 	cx25821_dev_unregister(dev);
 	v4l2_device_unregister(v4l2_dev);
--- linux-ein-5.4.0.orig/drivers/media/pci/cx88/cx88-mpeg.c
+++ linux-ein-5.4.0/drivers/media/pci/cx88/cx88-mpeg.c
@@ -162,6 +162,9 @@
 	cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET);
 	q->count = 0;
 
+	/* clear interrupt status register */
+	cx_write(MO_TS_INTSTAT,  0x1f1111);
+
 	/* enable irqs */
 	dprintk(1, "setting the interrupt mask\n");
 	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
--- linux-ein-5.4.0.orig/drivers/media/pci/cx88/cx88-vbi.c
+++ linux-ein-5.4.0/drivers/media/pci/cx88/cx88-vbi.c
@@ -144,11 +144,10 @@
 		return -EINVAL;
 	vb2_set_plane_payload(vb, 0, size);
 
-	cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl,
-			 0, VBI_LINE_LENGTH * lines,
-			 VBI_LINE_LENGTH, 0,
-			 lines);
-	return 0;
+	return cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl,
+				0, VBI_LINE_LENGTH * lines,
+				VBI_LINE_LENGTH, 0,
+				lines);
 }
 
 static void buffer_finish(struct vb2_buffer *vb)
--- linux-ein-5.4.0.orig/drivers/media/pci/cx88/cx88-video.c
+++ linux-ein-5.4.0/drivers/media/pci/cx88/cx88-video.c
@@ -433,6 +433,7 @@
 
 static int buffer_prepare(struct vb2_buffer *vb)
 {
+	int ret;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
 	struct cx88_core *core = dev->core;
@@ -447,35 +448,35 @@
 
 	switch (core->field) {
 	case V4L2_FIELD_TOP:
-		cx88_risc_buffer(dev->pci, &buf->risc,
-				 sgt->sgl, 0, UNSET,
-				 buf->bpl, 0, core->height);
+		ret = cx88_risc_buffer(dev->pci, &buf->risc,
+				       sgt->sgl, 0, UNSET,
+				       buf->bpl, 0, core->height);
 		break;
 	case V4L2_FIELD_BOTTOM:
-		cx88_risc_buffer(dev->pci, &buf->risc,
-				 sgt->sgl, UNSET, 0,
-				 buf->bpl, 0, core->height);
+		ret = cx88_risc_buffer(dev->pci, &buf->risc,
+				       sgt->sgl, UNSET, 0,
+				       buf->bpl, 0, core->height);
 		break;
 	case V4L2_FIELD_SEQ_TB:
-		cx88_risc_buffer(dev->pci, &buf->risc,
-				 sgt->sgl,
-				 0, buf->bpl * (core->height >> 1),
-				 buf->bpl, 0,
-				 core->height >> 1);
+		ret = cx88_risc_buffer(dev->pci, &buf->risc,
+				       sgt->sgl,
+				       0, buf->bpl * (core->height >> 1),
+				       buf->bpl, 0,
+				       core->height >> 1);
 		break;
 	case V4L2_FIELD_SEQ_BT:
-		cx88_risc_buffer(dev->pci, &buf->risc,
-				 sgt->sgl,
-				 buf->bpl * (core->height >> 1), 0,
-				 buf->bpl, 0,
-				 core->height >> 1);
+		ret = cx88_risc_buffer(dev->pci, &buf->risc,
+				       sgt->sgl,
+				       buf->bpl * (core->height >> 1), 0,
+				       buf->bpl, 0,
+				       core->height >> 1);
 		break;
 	case V4L2_FIELD_INTERLACED:
 	default:
-		cx88_risc_buffer(dev->pci, &buf->risc,
-				 sgt->sgl, 0, buf->bpl,
-				 buf->bpl, buf->bpl,
-				 core->height >> 1);
+		ret = cx88_risc_buffer(dev->pci, &buf->risc,
+				       sgt->sgl, 0, buf->bpl,
+				       buf->bpl, buf->bpl,
+				       core->height >> 1);
 		break;
 	}
 	dprintk(2,
@@ -483,7 +484,7 @@
 		buf, buf->vb.vb2_buf.index, __func__,
 		core->width, core->height, dev->fmt->depth, dev->fmt->fourcc,
 		(unsigned long)buf->risc.dma);
-	return 0;
+	return ret;
 }
 
 static void buffer_finish(struct vb2_buffer *vb)
@@ -1277,7 +1278,7 @@
 	core = cx88_core_get(dev->pci);
 	if (!core) {
 		err = -EINVAL;
-		goto fail_free;
+		goto fail_disable;
 	}
 	dev->core = core;
 
@@ -1323,7 +1324,7 @@
 				       cc->step, cc->default_value);
 		if (!vc) {
 			err = core->audio_hdl.error;
-			goto fail_core;
+			goto fail_irq;
 		}
 		vc->priv = (void *)cc;
 	}
@@ -1337,7 +1338,7 @@
 				       cc->step, cc->default_value);
 		if (!vc) {
 			err = core->video_hdl.error;
-			goto fail_core;
+			goto fail_irq;
 		}
 		vc->priv = (void *)cc;
 		if (vc->id == V4L2_CID_CHROMA_AGC)
@@ -1509,11 +1510,14 @@
 
 fail_unreg:
 	cx8800_unregister_video(dev);
-	free_irq(pci_dev->irq, dev);
 	mutex_unlock(&core->lock);
+fail_irq:
+	free_irq(pci_dev->irq, dev);
 fail_core:
 	core->v4ldev = NULL;
 	cx88_core_put(core, dev->pci);
+fail_disable:
+	pci_disable_device(pci_dev);
 fail_free:
 	kfree(dev);
 	return err;
--- linux-ein-5.4.0.orig/drivers/media/pci/ddbridge/ddbridge-main.c
+++ linux-ein-5.4.0/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -247,7 +247,7 @@
 	ddb_unmap(dev);
 	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
-	return -1;
+	return stat;
 }
 
 /****************************************************************************/
--- linux-ein-5.4.0.orig/drivers/media/pci/dm1105/dm1105.c
+++ linux-ein-5.4.0/drivers/media/pci/dm1105/dm1105.c
@@ -1179,6 +1179,7 @@
 	struct dvb_demux *dvbdemux = &dev->demux;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
+	cancel_work_sync(&dev->ir.work);
 	dm1105_ir_exit(dev);
 	dmx->close(dmx);
 	dvb_net_release(&dev->dvbnet);
--- linux-ein-5.4.0.orig/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ linux-ein-5.4.0/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -359,7 +359,7 @@
 	void __iomem *const base = cio2->base;
 	u8 lanes, csi2bus = q->csi2.port;
 	u8 sensor_vc = SENSOR_VIR_CH_DFLT;
-	struct cio2_csi2_timing timing;
+	struct cio2_csi2_timing timing = { 0 };
 	int i, r;
 
 	fmt = cio2_find_format(NULL, &q->subdev_fmt.code);
@@ -799,6 +799,7 @@
 			atomic_dec(&q->bufs_queued);
 			vb2_buffer_done(&q->bufs[i]->vbb.vb2_buf,
 					state);
+			q->bufs[i] = NULL;
 		}
 	}
 }
@@ -1243,29 +1244,15 @@
 			       struct v4l2_subdev_format *fmt)
 {
 	struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
-	struct v4l2_subdev_format format;
-	int ret;
-
-	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
-		return 0;
-	}
 
-	if (fmt->pad == CIO2_PAD_SINK) {
-		format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
-				       &format);
+	mutex_lock(&q->subdev_lock);
 
-		if (ret)
-			return ret;
-		/* update colorspace etc */
-		q->subdev_fmt.colorspace = format.format.colorspace;
-		q->subdev_fmt.ycbcr_enc = format.format.ycbcr_enc;
-		q->subdev_fmt.quantization = format.format.quantization;
-		q->subdev_fmt.xfer_func = format.format.xfer_func;
-	}
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+	else
+		fmt->format = q->subdev_fmt;
 
-	fmt->format = q->subdev_fmt;
+	mutex_unlock(&q->subdev_lock);
 
 	return 0;
 }
@@ -1282,6 +1269,9 @@
 			       struct v4l2_subdev_format *fmt)
 {
 	struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
+	struct v4l2_mbus_framefmt *mbus;
+	u32 mbus_code = fmt->format.code;
+	unsigned int i;
 
 	/*
 	 * Only allow setting sink pad format;
@@ -1290,16 +1280,29 @@
 	if (fmt->pad == CIO2_PAD_SOURCE)
 		return cio2_subdev_get_fmt(sd, cfg, fmt);
 
-	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
-	} else {
-		/* It's the sink, allow changing frame size */
-		q->subdev_fmt.width = fmt->format.width;
-		q->subdev_fmt.height = fmt->format.height;
-		q->subdev_fmt.code = fmt->format.code;
-		fmt->format = q->subdev_fmt;
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		mbus = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+	else
+		mbus = &q->subdev_fmt;
+
+	fmt->format.code = formats[0].mbus_code;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].mbus_code == mbus_code) {
+			fmt->format.code = mbus_code;
+			break;
+		}
 	}
 
+	fmt->format.width = min_t(u32, fmt->format.width, CIO2_IMAGE_MAX_WIDTH);
+	fmt->format.height = min_t(u32, fmt->format.height,
+				   CIO2_IMAGE_MAX_LENGTH);
+	fmt->format.field = V4L2_FIELD_NONE;
+
+	mutex_lock(&q->subdev_lock);
+	*mbus = fmt->format;
+	mutex_unlock(&q->subdev_lock);
+
 	return 0;
 }
 
@@ -1558,6 +1561,7 @@
 
 	/* Initialize miscellaneous variables */
 	mutex_init(&q->lock);
+	mutex_init(&q->subdev_lock);
 
 	/* Initialize formats to default values */
 	fmt = &q->subdev_fmt;
@@ -1676,6 +1680,7 @@
 fail_subdev_media_entity:
 	cio2_fbpt_exit(q, &cio2->pci_dev->dev);
 fail_fbpt:
+	mutex_destroy(&q->subdev_lock);
 	mutex_destroy(&q->lock);
 
 	return r;
@@ -1689,6 +1694,7 @@
 	v4l2_device_unregister_subdev(&q->subdev);
 	media_entity_cleanup(&q->subdev.entity);
 	cio2_fbpt_exit(q, &cio2->pci_dev->dev);
+	mutex_destroy(&q->subdev_lock);
 	mutex_destroy(&q->lock);
 }
 
@@ -1865,6 +1871,9 @@
 	v4l2_device_unregister(&cio2->v4l2_dev);
 	media_device_cleanup(&cio2->media_dev);
 	mutex_destroy(&cio2->lock);
+
+	pm_runtime_forbid(&pci_dev->dev);
+	pm_runtime_get_noresume(&pci_dev->dev);
 }
 
 static int __maybe_unused cio2_runtime_suspend(struct device *dev)
--- linux-ein-5.4.0.orig/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ linux-ein-5.4.0/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -332,6 +332,7 @@
 
 	/* Subdev, /dev/v4l-subdevX */
 	struct v4l2_subdev subdev;
+	struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */
 	struct media_pad subdev_pads[CIO2_PADS];
 	struct v4l2_mbus_framefmt subdev_fmt;
 	atomic_t frame_sequence;
--- linux-ein-5.4.0.orig/drivers/media/pci/ivtv/ivtv-driver.h
+++ linux-ein-5.4.0/drivers/media/pci/ivtv/ivtv-driver.h
@@ -333,7 +333,6 @@
 	struct ivtv *itv;		/* for ease of use */
 	const char *name;		/* name of the stream */
 	int type;			/* stream type */
-	u32 caps;			/* V4L2 capabilities */
 
 	struct v4l2_fh *fh;		/* pointer to the streaming filehandle */
 	spinlock_t qlock;		/* locks access to the queues */
--- linux-ein-5.4.0.orig/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ linux-ein-5.4.0/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -443,7 +443,7 @@
 	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
 	struct v4l2_window *winfmt = &fmt->fmt.win;
 
-	if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -EINVAL;
 	if (!itv->osd_video_pbase)
 		return -EINVAL;
@@ -554,7 +554,7 @@
 	u32 chromakey = fmt->fmt.win.chromakey;
 	u8 global_alpha = fmt->fmt.win.global_alpha;
 
-	if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -EINVAL;
 	if (!itv->osd_video_pbase)
 		return -EINVAL;
@@ -1386,7 +1386,7 @@
 		0,
 	};
 
-	if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -ENOTTY;
 	if (!itv->osd_video_pbase)
 		return -ENOTTY;
@@ -1453,7 +1453,7 @@
 	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
 	struct yuv_playback_info *yi = &itv->yuv_info;
 
-	if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -ENOTTY;
 	if (!itv->osd_video_pbase)
 		return -ENOTTY;
@@ -1473,7 +1473,7 @@
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
 
-	if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+	if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -ENOTTY;
 	if (!itv->osd_video_pbase)
 		return -ENOTTY;
--- linux-ein-5.4.0.orig/drivers/media/pci/ivtv/ivtv-streams.c
+++ linux-ein-5.4.0/drivers/media/pci/ivtv/ivtv-streams.c
@@ -176,7 +176,7 @@
 	s->itv = itv;
 	s->type = type;
 	s->name = ivtv_stream_info[type].name;
-	s->caps = ivtv_stream_info[type].v4l2_caps;
+	s->vdev.device_caps = ivtv_stream_info[type].v4l2_caps;
 
 	if (ivtv_stream_info[type].pio)
 		s->dma = PCI_DMA_NONE;
@@ -299,12 +299,9 @@
 		if (s_mpg->vdev.v4l2_dev)
 			num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset;
 	}
-	s->vdev.device_caps = s->caps;
-	if (itv->osd_video_pbase) {
-		itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |=
-			V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
-		itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |=
-			V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+	if (itv->osd_video_pbase && (type == IVTV_DEC_STREAM_TYPE_YUV ||
+				     type == IVTV_DEC_STREAM_TYPE_MPG)) {
+		s->vdev.device_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
 		itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
 	}
 	video_set_drvdata(&s->vdev, s);
--- linux-ein-5.4.0.orig/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ linux-ein-5.4.0/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -258,19 +258,24 @@
 	if ((reg40 & AVL_IRQ_ASSERTED) != 0) {
 		/* IRQ is being signaled */
 		reg_isr = readw(ndev->bmmio0 + REG_ISR);
-		if (reg_isr & NETUP_UNIDVB_IRQ_I2C0) {
-			iret = netup_i2c_interrupt(&ndev->i2c[0]);
-		} else if (reg_isr & NETUP_UNIDVB_IRQ_I2C1) {
-			iret = netup_i2c_interrupt(&ndev->i2c[1]);
-		} else if (reg_isr & NETUP_UNIDVB_IRQ_SPI) {
+		if (reg_isr & NETUP_UNIDVB_IRQ_SPI)
 			iret = netup_spi_interrupt(ndev->spi);
-		} else if (reg_isr & NETUP_UNIDVB_IRQ_DMA1) {
-			iret = netup_dma_interrupt(&ndev->dma[0]);
-		} else if (reg_isr & NETUP_UNIDVB_IRQ_DMA2) {
-			iret = netup_dma_interrupt(&ndev->dma[1]);
-		} else if (reg_isr & NETUP_UNIDVB_IRQ_CI) {
-			iret = netup_ci_interrupt(ndev);
+		else if (!ndev->old_fw) {
+			if (reg_isr & NETUP_UNIDVB_IRQ_I2C0) {
+				iret = netup_i2c_interrupt(&ndev->i2c[0]);
+			} else if (reg_isr & NETUP_UNIDVB_IRQ_I2C1) {
+				iret = netup_i2c_interrupt(&ndev->i2c[1]);
+			} else if (reg_isr & NETUP_UNIDVB_IRQ_DMA1) {
+				iret = netup_dma_interrupt(&ndev->dma[0]);
+			} else if (reg_isr & NETUP_UNIDVB_IRQ_DMA2) {
+				iret = netup_dma_interrupt(&ndev->dma[1]);
+			} else if (reg_isr & NETUP_UNIDVB_IRQ_CI) {
+				iret = netup_ci_interrupt(ndev);
+			} else {
+				goto err;
+			}
 		} else {
+err:
 			dev_err(&pci_dev->dev,
 				"%s(): unknown interrupt 0x%x\n",
 				__func__, reg_isr);
@@ -692,7 +697,7 @@
 	netup_unidvb_dma_enable(dma, 0);
 	msleep(50);
 	cancel_work_sync(&dma->work);
-	del_timer(&dma->timeout);
+	del_timer_sync(&dma->timeout);
 }
 
 static int netup_unidvb_dma_setup(struct netup_unidvb_dev *ndev)
@@ -882,12 +887,7 @@
 		ndev->lmmio0, (u32)pci_resource_len(pci_dev, 0),
 		ndev->lmmio1, (u32)pci_resource_len(pci_dev, 1),
 		pci_dev->irq);
-	if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED,
-			"netup_unidvb", pci_dev) < 0) {
-		dev_err(&pci_dev->dev,
-			"%s(): can't get IRQ %d\n", __func__, pci_dev->irq);
-		goto irq_request_err;
-	}
+
 	ndev->dma_size = 2 * 188 *
 		NETUP_DMA_BLOCKS_COUNT * NETUP_DMA_PACKETS_COUNT;
 	ndev->dma_virt = dma_alloc_coherent(&pci_dev->dev,
@@ -928,6 +928,14 @@
 		dev_err(&pci_dev->dev, "netup_unidvb: DMA setup failed\n");
 		goto dma_setup_err;
 	}
+
+	if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED,
+			"netup_unidvb", pci_dev) < 0) {
+		dev_err(&pci_dev->dev,
+			"%s(): can't get IRQ %d\n", __func__, pci_dev->irq);
+		goto dma_setup_err;
+	}
+
 	dev_info(&pci_dev->dev,
 		"netup_unidvb: device has been initialized\n");
 	return 0;
@@ -946,8 +954,6 @@
 	dma_free_coherent(&pci_dev->dev, ndev->dma_size,
 			ndev->dma_virt, ndev->dma_phys);
 dma_alloc_err:
-	free_irq(pci_dev->irq, pci_dev);
-irq_request_err:
 	iounmap(ndev->lmmio1);
 pci_bar1_error:
 	iounmap(ndev->lmmio0);
--- linux-ein-5.4.0.orig/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
+++ linux-ein-5.4.0/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
@@ -175,7 +175,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,
@@ -208,6 +208,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__);
@@ -226,13 +227,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-ein-5.4.0.orig/drivers/media/pci/ngene/ngene-core.c
+++ linux-ein-5.4.0/drivers/media/pci/ngene/ngene-core.c
@@ -385,7 +385,7 @@
 
 	com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
 	com.cmd.hdr.Length = 6;
-	memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
+	memcpy(&com.cmd.ConfigureFreeBuffers.config, config, 6);
 	com.in_len = 6;
 	com.out_len = 0;
 
--- linux-ein-5.4.0.orig/drivers/media/pci/ngene/ngene.h
+++ linux-ein-5.4.0/drivers/media/pci/ngene/ngene.h
@@ -407,12 +407,14 @@
 
 struct FW_CONFIGURE_FREE_BUFFERS {
 	struct FW_HEADER hdr;
-	u8   UVI1_BufferLength;
-	u8   UVI2_BufferLength;
-	u8   TVO_BufferLength;
-	u8   AUD1_BufferLength;
-	u8   AUD2_BufferLength;
-	u8   TVA_BufferLength;
+	struct {
+		u8   UVI1_BufferLength;
+		u8   UVI2_BufferLength;
+		u8   TVO_BufferLength;
+		u8   AUD1_BufferLength;
+		u8   AUD2_BufferLength;
+		u8   TVA_BufferLength;
+	} __packed config;
 } __attribute__ ((__packed__));
 
 struct FW_CONFIGURE_UART {
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7134/saa7134-empress.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7134/saa7134-empress.c
@@ -282,8 +282,11 @@
 	q->lock = &dev->lock;
 	q->dev = &dev->pci->dev;
 	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;
 	dev->empress_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
 					V4L2_CAP_VIDEO_CAPTURE;
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7134/saa7134-ts.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7134/saa7134-ts.c
@@ -300,6 +300,7 @@
 
 int saa7134_ts_fini(struct saa7134_dev *dev)
 {
+	del_timer_sync(&dev->ts_q.timeout);
 	saa7134_pgtable_free(dev->pci, &dev->ts_q.pt);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -683,7 +683,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-ein-5.4.0.orig/drivers/media/pci/saa7134/saa7134-vbi.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -185,6 +185,7 @@
 int saa7134_vbi_fini(struct saa7134_dev *dev)
 {
 	/* nothing */
+	del_timer_sync(&dev->vbi_q.timeout);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7134/saa7134-video.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7134/saa7134-video.c
@@ -1179,7 +1179,7 @@
 
 	saa_call_all(dev, tuner, standby);
 	if (vdev->vfl_type == VFL_TYPE_RADIO)
-		saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+		saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
 	mutex_unlock(&dev->lock);
 
 	return 0;
@@ -1198,7 +1198,7 @@
 	cmd.result = -ENODEV;
 
 	mutex_lock(&dev->lock);
-	saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
+	saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
 	mutex_unlock(&dev->lock);
 
 	return cmd.result;
@@ -1214,7 +1214,7 @@
 	cmd.event_list = wait;
 	cmd.poll_mask = 0;
 	mutex_lock(&dev->lock);
-	saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
+	saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
 	mutex_unlock(&dev->lock);
 
 	return rc | cmd.poll_mask;
@@ -2154,6 +2154,7 @@
 
 void saa7134_video_fini(struct saa7134_dev *dev)
 {
+	del_timer_sync(&dev->video_q.timeout);
 	/* free stuff */
 	vb2_queue_release(&dev->video_vbq);
 	saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7146/hexium_gemini.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7146/hexium_gemini.c
@@ -284,7 +284,12 @@
 	hexium_set_input(hexium, 0);
 	hexium->cur_input = 0;
 
-	saa7146_vv_init(dev, &vv_data);
+	ret = saa7146_vv_init(dev, &vv_data);
+	if (ret) {
+		i2c_del_adapter(&hexium->i2c_adapter);
+		kfree(hexium);
+		return ret;
+	}
 
 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7146/hexium_orion.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7146/hexium_orion.c
@@ -355,10 +355,16 @@
 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
+	int ret;
 
 	DEB_EE("\n");
 
-	saa7146_vv_init(dev, &vv_data);
+	ret = saa7146_vv_init(dev, &vv_data);
+	if (ret) {
+		pr_err("Error in saa7146_vv_init()\n");
+		return ret;
+	}
+
 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7146/mxb.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7146/mxb.c
@@ -641,16 +641,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
@@ -682,10 +683,16 @@
 static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
 	struct mxb *mxb;
+	int ret;
 
 	DEB_EE("dev:%p\n", dev);
 
-	saa7146_vv_init(dev, &vv_data);
+	ret = saa7146_vv_init(dev, &vv_data);
+	if (ret) {
+		ERR("Error in saa7146_vv_init()");
+		return ret;
+	}
+
 	if (mxb_probe(dev)) {
 		saa7146_vv_release(dev);
 		return -1;
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7164/saa7164-core.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7164/saa7164-core.c
@@ -1227,7 +1227,7 @@
 
 	if (saa7164_dev_setup(dev) < 0) {
 		err = -EINVAL;
-		goto fail_free;
+		goto fail_dev;
 	}
 
 	/* print pci info */
@@ -1395,6 +1395,8 @@
 
 fail_irq:
 	saa7164_dev_unregister(dev);
+fail_dev:
+	pci_disable_device(pci_dev);
 fail_free:
 	v4l2_device_unregister(&dev->v4l2_dev);
 	kfree(dev);
--- linux-ein-5.4.0.orig/drivers/media/pci/saa7164/saa7164-encoder.c
+++ linux-ein-5.4.0/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -1008,7 +1008,7 @@
 		printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n",
 			__func__, result);
 		result = -ENOMEM;
-		goto failed;
+		goto fail_pci;
 	}
 
 	/* Establish encoder defaults here */
@@ -1062,7 +1062,7 @@
 			  100000, ENCODER_DEF_BITRATE);
 	if (hdl->error) {
 		result = hdl->error;
-		goto failed;
+		goto fail_hdl;
 	}
 
 	port->std = V4L2_STD_NTSC_M;
@@ -1080,7 +1080,7 @@
 		printk(KERN_INFO "%s: can't allocate mpeg device\n",
 			dev->name);
 		result = -ENOMEM;
-		goto failed;
+		goto fail_hdl;
 	}
 
 	port->v4l_device->ctrl_handler = hdl;
@@ -1091,10 +1091,7 @@
 	if (result < 0) {
 		printk(KERN_INFO "%s: can't register mpeg device\n",
 			dev->name);
-		/* TODO: We're going to leak here if we don't dealloc
-		 The buffers above. The unreg function can't deal wit it.
-		*/
-		goto failed;
+		goto fail_reg;
 	}
 
 	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
@@ -1116,9 +1113,14 @@
 
 	saa7164_api_set_encoder(port);
 	saa7164_api_get_encoder(port);
+	return 0;
 
-	result = 0;
-failed:
+fail_reg:
+	video_device_release(port->v4l_device);
+	port->v4l_device = NULL;
+fail_hdl:
+	v4l2_ctrl_handler_free(hdl);
+fail_pci:
 	return result;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/pci/smipcie/smipcie-ir.c
+++ linux-ein-5.4.0/drivers/media/pci/smipcie/smipcie-ir.c
@@ -60,39 +60,45 @@
 {
 	struct smi_dev *dev = ir->dev;
 	struct rc_dev *rc_dev = ir->rc_dev;
-	u32 dwIRControl, dwIRData;
-	u8 index, ucIRCount, readLoop;
+	u32 control, data;
+	u8 index, ir_count, read_loop;
 
-	dwIRControl = smi_read(IR_Init_Reg);
+	control = smi_read(IR_Init_Reg);
 
-	if (dwIRControl & rbIRVld) {
-		ucIRCount = (u8) smi_read(IR_Data_Cnt);
+	dev_dbg(&rc_dev->dev, "ircontrol: 0x%08x\n", control);
 
-		readLoop = ucIRCount/4;
-		if (ucIRCount % 4)
-			readLoop += 1;
-		for (index = 0; index < readLoop; index++) {
-			dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index * 4));
-
-			ir->irData[index*4 + 0] = (u8)(dwIRData);
-			ir->irData[index*4 + 1] = (u8)(dwIRData >> 8);
-			ir->irData[index*4 + 2] = (u8)(dwIRData >> 16);
-			ir->irData[index*4 + 3] = (u8)(dwIRData >> 24);
+	if (control & rbIRVld) {
+		ir_count = (u8)smi_read(IR_Data_Cnt);
+
+		dev_dbg(&rc_dev->dev, "ircount %d\n", ir_count);
+
+		read_loop = ir_count / 4;
+		if (ir_count % 4)
+			read_loop += 1;
+		for (index = 0; index < read_loop; index++) {
+			data = smi_read(IR_DATA_BUFFER_BASE + (index * 4));
+			dev_dbg(&rc_dev->dev, "IRData 0x%08x\n", data);
+
+			ir->irData[index * 4 + 0] = (u8)(data);
+			ir->irData[index * 4 + 1] = (u8)(data >> 8);
+			ir->irData[index * 4 + 2] = (u8)(data >> 16);
+			ir->irData[index * 4 + 3] = (u8)(data >> 24);
 		}
-		smi_raw_process(rc_dev, ir->irData, ucIRCount);
-		smi_set(IR_Init_Reg, rbIRVld);
+		smi_raw_process(rc_dev, ir->irData, ir_count);
 	}
 
-	if (dwIRControl & rbIRhighidle) {
+	if (control & rbIRhighidle) {
 		struct ir_raw_event rawir = {};
 
+		dev_dbg(&rc_dev->dev, "high idle\n");
+
 		rawir.pulse = 0;
 		rawir.duration = US_TO_NS(SMI_SAMPLE_PERIOD *
 					  SMI_SAMPLE_IDLEMIN);
 		ir_raw_event_store_with_filter(rc_dev, &rawir);
-		smi_set(IR_Init_Reg, rbIRhighidle);
 	}
 
+	smi_set(IR_Init_Reg, rbIRVld);
 	ir_raw_event_handle(rc_dev);
 }
 
@@ -151,7 +157,7 @@
 	rc_dev->dev.parent = &dev->pci_dev->dev;
 
 	rc_dev->map_name = dev->info->rc_map;
-	rc_dev->timeout = MS_TO_NS(100);
+	rc_dev->timeout = US_TO_NS(SMI_SAMPLE_PERIOD * SMI_SAMPLE_IDLEMIN);
 	rc_dev->rx_resolution = US_TO_NS(SMI_SAMPLE_PERIOD);
 
 	ir->rc_dev = rc_dev;
@@ -174,7 +180,7 @@
 	struct smi_rc *ir = &dev->ir;
 	struct rc_dev *rc_dev = ir->rc_dev;
 
-	smi_ir_stop(ir);
 	rc_unregister_device(rc_dev);
+	smi_ir_stop(ir);
 	ir->rc_dev = NULL;
 }
--- linux-ein-5.4.0.orig/drivers/media/pci/solo6x10/solo6x10-core.c
+++ linux-ein-5.4.0/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -420,6 +420,7 @@
 		     solo_dev->nr_chans);
 
 	if (device_register(dev)) {
+		put_device(dev);
 		dev->parent = NULL;
 		return -ENOMEM;
 	}
--- linux-ein-5.4.0.orig/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ linux-ein-5.4.0/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -399,7 +399,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-ein-5.4.0.orig/drivers/media/pci/sta2x11/Kconfig
+++ linux-ein-5.4.0/drivers/media/pci/sta2x11/Kconfig
@@ -2,6 +2,7 @@
 config STA2X11_VIP
 	tristate "STA2X11 VIP Video For Linux"
 	depends on STA2X11 || COMPILE_TEST
+	select GPIOLIB if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEOBUF2_DMA_CONTIG
 	depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
--- linux-ein-5.4.0.orig/drivers/media/pci/ttpci/av7110.c
+++ linux-ein-5.4.0/drivers/media/pci/ttpci/av7110.c
@@ -406,14 +406,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-ein-5.4.0.orig/drivers/media/pci/ttpci/av7110_av.c
+++ linux-ein-5.4.0/drivers/media/pci/ttpci/av7110_av.c
@@ -822,10 +822,10 @@
 		av7110_ipack_flush(ipack);
 
 	if (buf[3] & ADAPT_FIELD) {
+		if (buf[4] > len - 1 - 4)
+			return 0;
 		len -= buf[4] + 1;
 		buf += buf[4] + 1;
-		if (!len)
-			return 0;
 	}
 
 	av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
--- linux-ein-5.4.0.orig/drivers/media/pci/ttpci/budget-core.c
+++ linux-ein-5.4.0/drivers/media/pci/ttpci/budget-core.c
@@ -369,20 +369,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-ein-5.4.0.orig/drivers/media/pci/tw5864/tw5864-video.c
+++ linux-ein-5.4.0/drivers/media/pci/tw5864/tw5864-video.c
@@ -767,6 +767,9 @@
 	fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
 
 	ret = tw5864_frameinterval_get(input, &frameinterval);
+	if (ret)
+		return ret;
+
 	fintv->stepwise.step = frameinterval;
 	fintv->stepwise.min = frameinterval;
 	fintv->stepwise.max = frameinterval;
@@ -785,6 +788,9 @@
 	cp->capability = V4L2_CAP_TIMEPERFRAME;
 
 	ret = tw5864_frameinterval_get(input, &cp->timeperframe);
+	if (ret)
+		return ret;
+
 	cp->timeperframe.numerator *= input->frame_interval;
 	cp->capturemode = 0;
 	cp->readbuffers = 2;
--- linux-ein-5.4.0.orig/drivers/media/pci/tw686x/tw686x-core.c
+++ linux-ein-5.4.0/drivers/media/pci/tw686x/tw686x-core.c
@@ -315,13 +315,6 @@
 
 	spin_lock_init(&dev->lock);
 
-	err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
-			  dev->name, dev);
-	if (err < 0) {
-		dev_err(&pci_dev->dev, "unable to request interrupt\n");
-		goto iounmap;
-	}
-
 	timer_setup(&dev->dma_delay_timer, tw686x_dma_delay, 0);
 
 	/*
@@ -333,18 +326,23 @@
 	err = tw686x_video_init(dev);
 	if (err) {
 		dev_err(&pci_dev->dev, "can't register video\n");
-		goto free_irq;
+		goto iounmap;
 	}
 
 	err = tw686x_audio_init(dev);
 	if (err)
 		dev_warn(&pci_dev->dev, "can't register audio\n");
 
+	err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
+			  dev->name, dev);
+	if (err < 0) {
+		dev_err(&pci_dev->dev, "unable to request interrupt\n");
+		goto iounmap;
+	}
+
 	pci_set_drvdata(pci_dev, dev);
 	return 0;
 
-free_irq:
-	free_irq(pci_dev->irq, dev);
 iounmap:
 	pci_iounmap(pci_dev, dev->mmio);
 free_region:
--- linux-ein-5.4.0.orig/drivers/media/platform/Kconfig
+++ linux-ein-5.4.0/drivers/media/platform/Kconfig
@@ -141,6 +141,29 @@
 	help
 	  This is a v4l2 driver for the Renesas CEU Interface
 
+config VIDEO_MX8_CAPTURE
+	tristate "MX8 Video For Linux Video Capture"
+	depends on VIDEO_V4L2
+	---help---
+	  This is the video4linux2 capture driver based on i.MX8 module.
+
+source "drivers/media/platform/imx8/Kconfig"
+
+config VIDEO_MXC_CAPTURE
+	tristate "MXC Video For Linux Video Capture"
+	depends on VIDEO_V4L2
+	---help---
+	  This is the video4linux2 capture driver based on i.MX video-in module.
+
+source "drivers/media/platform/mxc/capture/Kconfig"
+
+config VIDEO_MXC_OUTPUT
+	tristate "MXC Video For Linux Video Output"
+	depends on VIDEO_DEV && ARCH_MXC && FB_MXC
+	select VIDEOBUF_DMA_CONTIG
+	---help---
+	This is the video4linux2 output driver based on MXC module.
+source "drivers/media/platform/mxc/output/Kconfig"
 source "drivers/media/platform/exynos4-is/Kconfig"
 source "drivers/media/platform/am437x/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
--- linux-ein-5.4.0.orig/drivers/media/platform/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/Makefile
@@ -84,6 +84,11 @@
 
 obj-$(CONFIG_VIDEO_STM32_DCMI)		+= stm32/
 
+obj-$(CONFIG_VIDEO_MX8_CAPTURE)		+= imx8/
+
+obj-$(CONFIG_VIDEO_MXC_CAPTURE)		+= mxc/capture/
+
+obj-$(CONFIG_VIDEO_MXC_OUTPUT)		+= mxc/output/
 obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
 
 obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
--- linux-ein-5.4.0.orig/drivers/media/platform/am437x/am437x-vpfe.c
+++ linux-ein-5.4.0/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1830,6 +1830,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-ein-5.4.0.orig/drivers/media/platform/aspeed-video.c
+++ linux-ein-5.4.0/drivers/media/platform/aspeed-video.c
@@ -151,7 +151,7 @@
 #define  VE_SRC_TB_EDGE_DET_BOT		GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF)
 
 #define VE_MODE_DETECT_STATUS		0x098
-#define  VE_MODE_DETECT_H_PIXELS	GENMASK(11, 0)
+#define  VE_MODE_DETECT_H_PERIOD	GENMASK(11, 0)
 #define  VE_MODE_DETECT_V_LINES_SHF	16
 #define  VE_MODE_DETECT_V_LINES		GENMASK(27, VE_MODE_DETECT_V_LINES_SHF)
 #define  VE_MODE_DETECT_STATUS_VSYNC	BIT(28)
@@ -162,6 +162,8 @@
 #define  VE_SYNC_STATUS_VSYNC_SHF	16
 #define  VE_SYNC_STATUS_VSYNC		GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF)
 
+#define VE_H_TOTAL_PIXELS		0x0A0
+
 #define VE_INTERRUPT_CTRL		0x304
 #define VE_INTERRUPT_STATUS		0x308
 #define  VE_INTERRUPT_MODE_DETECT_WD	BIT(0)
@@ -477,6 +479,10 @@
 	aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
 			    VE_INTERRUPT_MODE_DETECT);
 
+	/* Disable mode detect in order to re-trigger */
+	aspeed_video_update(video, VE_SEQ_CTRL,
+			    VE_SEQ_CTRL_TRIG_MODE_DET, 0);
+
 	/* Trigger mode detect */
 	aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET);
 }
@@ -491,8 +497,8 @@
 	aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
 
 	/* Turn off the relevant clocks */
-	clk_disable(video->vclk);
 	clk_disable(video->eclk);
+	clk_disable(video->vclk);
 
 	clear_bit(VIDEO_CLOCKS_ON, &video->flags);
 }
@@ -503,8 +509,8 @@
 		return;
 
 	/* Turn on the relevant clocks */
-	clk_enable(video->eclk);
 	clk_enable(video->vclk);
+	clk_enable(video->eclk);
 
 	set_bit(VIDEO_CLOCKS_ON, &video->flags);
 }
@@ -529,6 +535,8 @@
 	set_bit(VIDEO_RES_CHANGE, &video->flags);
 	clear_bit(VIDEO_FRAME_INPRG, &video->flags);
 
+	video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
+
 	aspeed_video_off(video);
 	aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
 
@@ -606,6 +614,16 @@
 			aspeed_video_start_frame(video);
 	}
 
+	/*
+	 * CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these
+	 * are disabled in the VE_INTERRUPT_CTRL register so clear them to
+	 * prevent unnecessary interrupt calls.
+	 */
+	if (sts & VE_INTERRUPT_CAPTURE_COMPLETE)
+		sts &= ~VE_INTERRUPT_CAPTURE_COMPLETE;
+	if (sts & VE_INTERRUPT_FRAME_COMPLETE)
+		sts &= ~VE_INTERRUPT_FRAME_COMPLETE;
+
 	return sts ? IRQ_NONE : IRQ_HANDLED;
 }
 
@@ -727,6 +745,7 @@
 	u32 src_lr_edge;
 	u32 src_tb_edge;
 	u32 sync;
+	u32 htotal;
 	struct v4l2_bt_timings *det = &video->detected_timings;
 
 	det->width = MIN_WIDTH;
@@ -741,6 +760,8 @@
 		}
 
 		set_bit(VIDEO_RES_DETECT, &video->flags);
+		aspeed_video_update(video, VE_CTRL,
+				    VE_CTRL_VSYNC_POL | VE_CTRL_HSYNC_POL, 0);
 		aspeed_video_enable_mode_detect(video);
 
 		rc = wait_event_interruptible_timeout(video->wait,
@@ -752,10 +773,6 @@
 			return;
 		}
 
-		/* Disable mode detect in order to re-trigger */
-		aspeed_video_update(video, VE_SEQ_CTRL,
-				    VE_SEQ_CTRL_TRIG_MODE_DET, 0);
-
 		aspeed_video_check_and_set_polarity(video);
 
 		aspeed_video_enable_mode_detect(video);
@@ -773,6 +790,7 @@
 		src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET);
 		mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
 		sync = aspeed_video_read(video, VE_SYNC_STATUS);
+		htotal = aspeed_video_read(video, VE_H_TOTAL_PIXELS);
 
 		video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >>
 			VE_SRC_TB_EDGE_DET_BOT_SHF;
@@ -789,8 +807,7 @@
 			VE_SRC_LR_EDGE_DET_RT_SHF;
 		video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT;
 		det->hfrontporch = video->frame_left;
-		det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) -
-			video->frame_right;
+		det->hbackporch = htotal - video->frame_right;
 		det->hsync = sync & VE_SYNC_STATUS_HSYNC;
 		if (video->frame_left > video->frame_right)
 			continue;
@@ -1303,7 +1320,6 @@
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct aspeed_video *video = container_of(dwork, struct aspeed_video,
 						  res_work);
-	u32 input_status = video->v4l2_input_status;
 
 	aspeed_video_on(video);
 
@@ -1316,8 +1332,7 @@
 	aspeed_video_get_resolution(video);
 
 	if (video->detected_timings.width != video->active_timings.width ||
-	    video->detected_timings.height != video->active_timings.height ||
-	    input_status != video->v4l2_input_status) {
+	    video->detected_timings.height != video->active_timings.height) {
 		static const struct v4l2_event ev = {
 			.type = V4L2_EVENT_SOURCE_CHANGE,
 			.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
@@ -1517,12 +1532,12 @@
 			       V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
 			       V4L2_JPEG_CHROMA_SUBSAMPLING_444);
 
-	if (video->ctrl_handler.error) {
+	rc = video->ctrl_handler.error;
+	if (rc) {
 		v4l2_ctrl_handler_free(&video->ctrl_handler);
 		v4l2_device_unregister(v4l2_dev);
 
-		dev_err(video->dev, "Failed to init controls: %d\n",
-			video->ctrl_handler.error);
+		dev_err(video->dev, "Failed to init controls: %d\n", rc);
 		return rc;
 	}
 
@@ -1646,7 +1661,8 @@
 {
 	int rc;
 	struct resource *res;
-	struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL);
+	struct aspeed_video *video =
+		devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL);
 
 	if (!video)
 		return -ENOMEM;
@@ -1671,8 +1687,12 @@
 		return rc;
 
 	rc = aspeed_video_setup_video(video);
-	if (rc)
+	if (rc) {
+		aspeed_video_free_buf(video, &video->jpeg);
+		clk_unprepare(video->vclk);
+		clk_unprepare(video->eclk);
 		return rc;
+	}
 
 	return 0;
 }
@@ -1696,8 +1716,7 @@
 
 	v4l2_device_unregister(v4l2_dev);
 
-	dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt,
-			  video->jpeg.dma);
+	aspeed_video_free_buf(video, &video->jpeg);
 
 	of_reserved_mem_device_release(dev);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/cadence/cdns-csi2rx.c
+++ linux-ein-5.4.0/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -129,7 +129,7 @@
 	 */
 	for (i = csi2rx->num_lanes; i < csi2rx->max_lanes; i++) {
 		unsigned int idx = find_first_zero_bit(&lanes_used,
-						       sizeof(lanes_used));
+						       csi2rx->max_lanes);
 		set_bit(idx, &lanes_used);
 		reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1);
 	}
--- linux-ein-5.4.0.orig/drivers/media/platform/coda/coda-bit.c
+++ linux-ein-5.4.0/drivers/media/platform/coda/coda-bit.c
@@ -852,7 +852,7 @@
 		/* Only H.264BP and H.263P3 are considered */
 		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
 		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
-		if (!iram_info->buf_dbk_c_use)
+		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
 			goto out;
 		iram_info->axi_sram_use |= dbk_bits;
 
@@ -876,7 +876,7 @@
 
 		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
 		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
-		if (!iram_info->buf_dbk_c_use)
+		if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use)
 			goto out;
 		iram_info->axi_sram_use |= dbk_bits;
 
@@ -1082,10 +1082,16 @@
 	}
 
 	if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
-		if (!ctx->params.jpeg_qmat_tab[0])
+		if (!ctx->params.jpeg_qmat_tab[0]) {
 			ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
-		if (!ctx->params.jpeg_qmat_tab[1])
+			if (!ctx->params.jpeg_qmat_tab[0])
+				return -ENOMEM;
+		}
+		if (!ctx->params.jpeg_qmat_tab[1]) {
 			ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+			if (!ctx->params.jpeg_qmat_tab[1])
+				return -ENOMEM;
+		}
 		coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
 	}
 
@@ -2023,17 +2029,25 @@
 	u32 src_fourcc, dst_fourcc;
 	int ret;
 
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	src_fourcc = q_data_src->fourcc;
+	dst_fourcc = q_data_dst->fourcc;
+
 	if (!ctx->initialized) {
 		ret = __coda_decoder_seq_init(ctx);
 		if (ret < 0)
 			return ret;
+	} else {
+		ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
+					 CODA9_FRAME_TILED2LINEAR);
+		if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
+			ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
+		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
+			ctx->frame_mem_ctrl |= (0x3 << 9) |
+				((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
 	}
 
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	src_fourcc = q_data_src->fourcc;
-	dst_fourcc = q_data_dst->fourcc;
-
 	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
 
 	ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
--- linux-ein-5.4.0.orig/drivers/media/platform/coda/coda-common.c
+++ linux-ein-5.4.0/drivers/media/platform/coda/coda-common.c
@@ -372,6 +372,7 @@
 	if (!vdoa_data)
 		vdoa_data = ERR_PTR(-EPROBE_DEFER);
 
+	put_device(&vdoa_pdev->dev);
 out:
 	of_node_put(vdoa_node);
 
@@ -1084,16 +1085,16 @@
 
 	switch (dc->cmd) {
 	case V4L2_DEC_CMD_START:
-		mutex_lock(&ctx->bitstream_mutex);
 		mutex_lock(&dev->coda_mutex);
+		mutex_lock(&ctx->bitstream_mutex);
 		coda_bitstream_flush(ctx);
-		mutex_unlock(&dev->coda_mutex);
 		dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
 					 V4L2_BUF_TYPE_VIDEO_CAPTURE);
 		vb2_clear_last_buffer_dequeued(dst_vq);
 		ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG;
 		coda_fill_bitstream(ctx, NULL);
 		mutex_unlock(&ctx->bitstream_mutex);
+		mutex_unlock(&dev->coda_mutex);
 		break;
 	case V4L2_DEC_CMD_STOP:
 		stream_end = false;
@@ -1191,7 +1192,8 @@
 				    struct v4l2_frmivalenum *f)
 {
 	struct coda_ctx *ctx = fh_to_ctx(fh);
-	int i;
+	struct coda_q_data *q_data;
+	const struct coda_codec *codec;
 
 	if (f->index)
 		return -EINVAL;
@@ -1200,12 +1202,19 @@
 	if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV)
 		return -EINVAL;
 
-	for (i = 0; i < CODA_MAX_FORMATS; i++) {
-		if (f->pixel_format == ctx->cvd->src_formats[i] ||
-		    f->pixel_format == ctx->cvd->dst_formats[i])
-			break;
+	if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) {
+		q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		codec = coda_find_codec(ctx->dev, f->pixel_format,
+					q_data->fourcc);
+	} else {
+		codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+					f->pixel_format);
 	}
-	if (i == CODA_MAX_FORMATS)
+	if (!codec)
+		return -EINVAL;
+
+	if (f->width < MIN_W || f->width > codec->max_w ||
+	    f->height < MIN_H || f->height > codec->max_h)
 		return -EINVAL;
 
 	f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
@@ -2163,8 +2172,8 @@
 		V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);
 	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
 		V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-		V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
-		V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+		V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0,
+		V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE);
 	if (ctx->dev->devtype->product == CODA_HX4 ||
 	    ctx->dev->devtype->product == CODA_7541) {
 		v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@@ -2178,12 +2187,15 @@
 	if (ctx->dev->devtype->product == CODA_960) {
 		v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
 			V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-			V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
-			~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+			V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+			~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
 			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
 			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
 			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+			  (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
 			V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
 	}
 	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -2245,7 +2257,7 @@
 	ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
 		&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
 		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-		~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+		~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
 		  (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
 		  (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
 		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
--- linux-ein-5.4.0.orig/drivers/media/platform/coda/imx-vdoa.c
+++ linux-ein-5.4.0/drivers/media/platform/coda/imx-vdoa.c
@@ -287,7 +287,11 @@
 	struct resource *res;
 	int ret;
 
-	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(&pdev->dev, "DMA enable failed\n");
+		return ret;
+	}
 
 	vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL);
 	if (!vdoa)
--- linux-ein-5.4.0.orig/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
+++ linux-ein-5.4.0/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
@@ -45,6 +45,8 @@
 	uint8_t *cec_message = cros_ec->event_data.data.cec_message;
 	unsigned int len = cros_ec->event_size;
 
+	if (len > CEC_MAX_MSG_SIZE)
+		len = CEC_MAX_MSG_SIZE;
 	cros_ec_cec->rx_msg.len = len;
 	memcpy(cros_ec_cec->rx_msg.msg, cec_message, len);
 
@@ -278,11 +280,7 @@
 	platform_set_drvdata(pdev, cros_ec_cec);
 	cros_ec_cec->cros_ec = cros_ec;
 
-	ret = device_init_wakeup(&pdev->dev, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to initialize wakeup\n");
-		return ret;
-	}
+	device_init_wakeup(&pdev->dev, 1);
 
 	cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec,
 						 DRV_NAME,
--- linux-ein-5.4.0.orig/drivers/media/platform/davinci/vpbe_display.c
+++ linux-ein-5.4.0/drivers/media/platform/davinci/vpbe_display.c
@@ -48,7 +48,7 @@
 
 	ret = v4l2_subdev_call(vpbe_dev->venc,
 			       core,
-			       ioctl,
+			       command,
 			       VENC_GET_FLD,
 			       &val);
 	if (ret < 0) {
--- linux-ein-5.4.0.orig/drivers/media/platform/davinci/vpbe_venc.c
+++ linux-ein-5.4.0/drivers/media/platform/davinci/vpbe_venc.c
@@ -521,9 +521,7 @@
 	return ret;
 }
 
-static long venc_ioctl(struct v4l2_subdev *sd,
-			unsigned int cmd,
-			void *arg)
+static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	u32 val;
 
@@ -542,7 +540,7 @@
 }
 
 static const struct v4l2_subdev_core_ops venc_core_ops = {
-	.ioctl      = venc_ioctl,
+	.command      = venc_command,
 };
 
 static const struct v4l2_subdev_video_ops venc_video_ops = {
--- linux-ein-5.4.0.orig/drivers/media/platform/davinci/vpif.c
+++ linux-ein-5.4.0/drivers/media/platform/davinci/vpif.c
@@ -496,6 +496,7 @@
 
 static int vpif_remove(struct platform_device *pdev)
 {
+	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/davinci/vpif_capture.c
+++ linux-ein-5.4.0/drivers/media/platform/davinci/vpif_capture.c
@@ -1482,8 +1482,6 @@
 		/* Unregister video device */
 		video_unregister_device(&ch->video_dev);
 	}
-	kfree(vpif_obj.sd);
-	v4l2_device_unregister(&vpif_obj.v4l2_dev);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/davinci/vpss.c
+++ linux-ein-5.4.0/drivers/media/platform/davinci/vpss.c
@@ -505,19 +505,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)) {
-		release_mem_region(VPSS_CLK_CTRL, 4);
-		return -ENOMEM;
+		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-ein-5.4.0.orig/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -56,10 +56,8 @@
 static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct gsc_ctx *ctx = q->drv_priv;
-	int ret;
 
-	ret = pm_runtime_get_sync(&ctx->gsc_dev->pdev->dev);
-	return ret > 0 ? 0 : ret;
+	return pm_runtime_resume_and_get(&ctx->gsc_dev->pdev->dev);
 }
 
 static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-core.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-core.c
@@ -1231,7 +1231,7 @@
 	return platform_driver_register(&fimc_driver);
 }
 
-void __exit fimc_unregister_driver(void)
+void fimc_unregister_driver(void)
 {
 	platform_driver_unregister(&fimc_driver);
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-is.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-is.c
@@ -141,7 +141,7 @@
 			dev_err(&is->pdev->dev, "clock %s enable failed\n",
 				fimc_is_clocks[i]);
 			for (--i; i >= 0; i--)
-				clk_disable(is->clocks[i]);
+				clk_disable_unprepare(is->clocks[i]);
 			return ret;
 		}
 		pr_debug("enabled clock: %s\n", fimc_is_clocks[i]);
@@ -214,6 +214,7 @@
 
 			if (ret < 0 || index >= FIMC_IS_SENSORS_NUM) {
 				of_node_put(child);
+				of_node_put(i2c_bus);
 				return ret;
 			}
 			index++;
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -305,17 +305,20 @@
 	struct fimc_is_video *ivc = &isp->video_capture;
 	struct media_entity *entity = &ivc->ve.vdev.entity;
 	struct media_device *mdev = entity->graph_obj.mdev;
+	bool is_singular_file;
 
 	mutex_lock(&isp->video_lock);
 
-	if (v4l2_fh_is_singular_file(file) && ivc->streaming) {
+	is_singular_file = v4l2_fh_is_singular_file(file);
+
+	if (is_singular_file && ivc->streaming) {
 		media_pipeline_stop(entity);
 		ivc->streaming = 0;
 	}
 
-	vb2_fop_release(file);
+	_vb2_fop_release(file, NULL);
 
-	if (v4l2_fh_is_singular_file(file)) {
+	if (is_singular_file) {
 		fimc_pipeline_call(&ivc->ve, close);
 
 		mutex_lock(&mdev->graph_mutex);
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-isp-video.h
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-isp-video.h
@@ -32,7 +32,7 @@
 	return 0;
 }
 
-void fimc_isp_video_device_unregister(struct fimc_isp *isp,
+static inline void fimc_isp_video_device_unregister(struct fimc_isp *isp,
 				enum v4l2_buf_type type)
 {
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-isp.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -305,8 +305,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-ein-5.4.0.orig/drivers/media/platform/exynos4-is/fimc-lite.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -470,7 +470,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-ein-5.4.0.orig/drivers/media/platform/exynos4-is/media-dev.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/media-dev.c
@@ -484,8 +484,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;
 
@@ -1268,6 +1270,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;
@@ -1457,12 +1460,12 @@
 	ret = v4l2_device_register(dev, &fmd->v4l2_dev);
 	if (ret < 0) {
 		v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
-		return ret;
+		goto err_md;
 	}
 
 	ret = fimc_md_get_clocks(fmd);
 	if (ret)
-		goto err_md;
+		goto err_v4l2dev;
 
 	ret = fimc_md_get_pinctrl(fmd);
 	if (ret < 0) {
@@ -1519,9 +1522,10 @@
 	fimc_md_unregister_entities(fmd);
 err_clk:
 	fimc_md_put_clocks(fmd);
+err_v4l2dev:
+	v4l2_device_unregister(&fmd->v4l2_dev);
 err_md:
 	media_device_cleanup(&fmd->media_dev);
-	v4l2_device_unregister(&fmd->v4l2_dev);
 	return ret;
 }
 
@@ -1577,7 +1581,11 @@
 	if (ret)
 		return ret;
 
-	return platform_driver_register(&fimc_md_driver);
+	ret = platform_driver_register(&fimc_md_driver);
+	if (ret)
+		fimc_unregister_driver();
+
+	return ret;
 }
 
 static void __exit fimc_md_exit(void)
--- linux-ein-5.4.0.orig/drivers/media/platform/exynos4-is/mipi-csis.c
+++ linux-ein-5.4.0/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -510,8 +510,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-ein-5.4.0.orig/drivers/media/platform/imx-pxp.c
+++ linux-ein-5.4.0/drivers/media/platform/imx-pxp.c
@@ -1664,6 +1664,8 @@
 	if (irq < 0)
 		return irq;
 
+	spin_lock_init(&dev->irqlock);
+
 	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
 			IRQF_ONESHOT, dev_name(&pdev->dev), dev);
 	if (ret < 0) {
@@ -1681,8 +1683,6 @@
 		goto err_clk;
 	}
 
-	spin_lock_init(&dev->irqlock);
-
 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
 	if (ret)
 		goto err_clk;
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/Kconfig
+++ linux-ein-5.4.0/drivers/media/platform/imx8/Kconfig
@@ -0,0 +1,17 @@
+if VIDEO_MX8_CAPTURE
+menu "IMX8 Camera ISI/MIPI Features support"
+
+config IMX8_MIPI_CSI2_YAV
+	tristate "IMX8 MIPI CSI2 Controller Yet Another Version"
+	default y
+
+config IMX8_JPEG
+	tristate "IMX8 JPEG Encoder/Decoder"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	select V4L2_MEM2MEM_DEV
+	select VIDEOBUF2_DMA_CONTIG
+	default m
+
+endmenu
+endif #VIDEO_MX8_CAPTURE
+
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/imx8/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_IMX8_MIPI_CSI2_YAV) += mxc-mipi-csi2_yav.o
+
+mxc-jpeg-encdec-objs := mxc-jpeg-hw.o mxc-jpeg.o
+obj-$(CONFIG_IMX8_JPEG) += mxc-jpeg-encdec.o
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-jpeg-hw.c
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-jpeg-hw.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/delay.h>
+#include <media/videobuf2-core.h>
+#include "mxc-jpeg-hw.h"
+
+#define print_wrapper_reg(dev, base_address, reg_offset)\
+		internal_print_wrapper_reg(dev, (base_address), #reg_offset,\
+					   (reg_offset))
+#define internal_print_wrapper_reg(dev, base_address, reg_name, reg_offset) {\
+		int val;\
+		val = readl((base_address) + (reg_offset));\
+		dev_dbg(dev, "Wrapper reg %s = 0x%x\n", reg_name, val);\
+}
+
+void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc)
+{
+	dev_dbg(dev, " MXC JPEG NEXT_DESCPT_PTR 0x%x\n",
+		desc->next_descpt_ptr);
+	dev_dbg(dev, " MXC JPEG BUF_BASE0 0x%x\n", desc->buf_base0);
+	dev_dbg(dev, " MXC JPEG BUF_BASE1 0x%x\n", desc->buf_base1);
+	dev_dbg(dev, " MXC JPEG LINE_PITCH %d\n", desc->line_pitch);
+	dev_dbg(dev, " MXC JPEG STM_BUFBASE 0x%x\n", desc->stm_bufbase);
+	dev_dbg(dev, " MXC JPEG STM_BUFSIZE %d\n", desc->stm_bufsize);
+	dev_dbg(dev, " MXC JPEG IMGSIZE %x (%d x %d)\n", desc->imgsize,
+		desc->imgsize >> 16, desc->imgsize & 0xFFFF);
+	dev_dbg(dev, " MXC JPEG STM_CTRL 0x%x\n", desc->stm_ctrl);
+}
+
+void print_cast_status(struct device *dev, void __iomem *reg,
+		       unsigned int mode)
+{
+	dev_dbg(dev, "CAST IP status regs:\n");
+	print_wrapper_reg(dev, reg, CAST_STATUS0);
+	print_wrapper_reg(dev, reg, CAST_STATUS1);
+	print_wrapper_reg(dev, reg, CAST_STATUS2);
+	print_wrapper_reg(dev, reg, CAST_STATUS3);
+	print_wrapper_reg(dev, reg, CAST_STATUS4);
+	print_wrapper_reg(dev, reg, CAST_STATUS5);
+	print_wrapper_reg(dev, reg, CAST_STATUS6);
+	print_wrapper_reg(dev, reg, CAST_STATUS7);
+	print_wrapper_reg(dev, reg, CAST_STATUS8);
+	print_wrapper_reg(dev, reg, CAST_STATUS9);
+	print_wrapper_reg(dev, reg, CAST_STATUS10);
+	print_wrapper_reg(dev, reg, CAST_STATUS11);
+	print_wrapper_reg(dev, reg, CAST_STATUS12);
+	print_wrapper_reg(dev, reg, CAST_STATUS13);
+	if (mode == MXC_JPEG_DECODE)
+		return;
+	print_wrapper_reg(dev, reg, CAST_STATUS14);
+	print_wrapper_reg(dev, reg, CAST_STATUS15);
+	print_wrapper_reg(dev, reg, CAST_STATUS16);
+	print_wrapper_reg(dev, reg, CAST_STATUS17);
+	print_wrapper_reg(dev, reg, CAST_STATUS18);
+	print_wrapper_reg(dev, reg, CAST_STATUS19);
+}
+
+void print_wrapper_info(struct device *dev, void __iomem *reg)
+{
+	dev_dbg(dev, "Wrapper regs:\n");
+	print_wrapper_reg(dev, reg, GLB_CTRL);
+	print_wrapper_reg(dev, reg, COM_STATUS);
+	print_wrapper_reg(dev, reg, BUF_BASE0);
+	print_wrapper_reg(dev, reg, BUF_BASE1);
+	print_wrapper_reg(dev, reg, LINE_PITCH);
+	print_wrapper_reg(dev, reg, STM_BUFBASE);
+	print_wrapper_reg(dev, reg, STM_BUFSIZE);
+	print_wrapper_reg(dev, reg, IMGSIZE);
+	print_wrapper_reg(dev, reg, STM_CTRL);
+}
+
+void mxc_jpeg_enable_irq(void __iomem *reg, int slot)
+{
+	writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
+}
+
+void mxc_jpeg_sw_reset(void __iomem *reg)
+{
+	/*
+	 * engine soft reset, internal state machine reset
+	 * this will not reset registers, however, it seems
+	 * the registers may remain inconsistent with the internal state
+	 * so, on purpose, at least let GLB_CTRL bits clear after this reset
+	 */
+	writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL);
+}
+
+u32 mxc_jpeg_get_offset(void __iomem *reg, int slot)
+{
+	return readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
+}
+
+void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg)
+{
+	dev_dbg(dev, "CAST Encoder CONFIG...\n");
+	/*
+	 * "Config_Mode" enabled, "Config_Mode auto clear enabled",
+	 */
+	writel(0xa0, reg + CAST_MODE);
+
+	/* all markers and segments */
+	writel(0x3ff, reg + CAST_CFG_MODE);
+
+	/* quality factor */
+	writel(0x4b, reg + CAST_QUALITY);
+}
+
+void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg)
+{
+	dev_dbg(dev, "CAST Encoder GO...\n");
+	/*
+	 * "GO" enabled, "GO bit auto clear" enabled
+	 */
+	writel(0x140, reg + CAST_MODE);
+}
+
+void wait_frmdone(struct device *dev, void __iomem *reg)
+{
+	u32 regval = 0;
+
+	do {
+		regval = readl(reg + MXC_SLOT_OFFSET(0, SLOT_STATUS));
+	} while (!(regval & SLOTa_STATUS_FRMDONE));
+
+	writel(regval, reg + MXC_SLOT_OFFSET(0, SLOT_STATUS)); /* w1c */
+
+	dev_dbg(dev, "Received FRMDONE\n");
+	if (regval & SLOTa_STATUS_ENC_CONFIG_ERR)
+		dev_info(dev, "SLOTa_STATUS_ENC_CONFIG_ERR\n");
+}
+
+int mxc_jpeg_enable(void __iomem *reg)
+{
+	u32 regval;
+
+	writel(GLB_CTRL_JPG_EN, reg + GLB_CTRL);
+	regval = readl(reg);
+	return regval;
+}
+
+void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg)
+{
+	dev_dbg(dev, "CAST Decoder GO...\n");
+	writel(MXC_DEC_EXIT_IDLE_MODE, reg + CAST_CTRL);
+}
+
+int mxc_jpeg_get_slot(void __iomem *reg)
+{
+	int slot_val;
+	int i = 0;
+	int tmp = GLB_CTRL_SLOT_EN(0);
+
+	/* currently enabled slots */
+	slot_val = readl(reg + GLB_CTRL) & 0xF0;
+
+	for (; tmp != tmp << 4; tmp = tmp << 1) {
+		if ((slot_val & tmp) == 0)
+			/* first free slot */
+			return i;
+		++i;
+	}
+	return -EINVAL;
+}
+
+void mxc_jpeg_enable_slot(void __iomem *reg, int slot)
+{
+	u32 regval;
+
+	regval = readl(reg + GLB_CTRL);
+	writel(GLB_CTRL_SLOT_EN(slot) | regval, reg + GLB_CTRL);
+}
+
+void mxc_jpeg_set_l_endian(void __iomem *reg, int le)
+{
+	u32 regval;
+
+	regval = readl(reg + GLB_CTRL);
+	regval &= ~GLB_CTRL_L_ENDIAN(1); /* clear */
+	writel(GLB_CTRL_L_ENDIAN(le) | regval, reg + GLB_CTRL); /* set */
+}
+
+void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode)
+{
+	u32 regval;
+
+	regval = readl(reg + STM_CTRL);
+	regval &= ~STM_CTRL_CONFIG_MOD(1);
+	writel(STM_CTRL_CONFIG_MOD(config_mode) | regval, reg + STM_CTRL);
+}
+
+int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc,  u32 bufsize,
+			 u16 out_pitch, u32 format)
+{
+	desc->line_pitch = out_pitch;
+	desc->stm_bufsize = bufsize;
+	switch (format) {
+	case V4L2_PIX_FMT_YUV32:
+		desc->stm_ctrl |= MXC_JPEG_YUV444 << 3;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		desc->stm_ctrl |= MXC_JPEG_YUV422 << 3;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		desc->stm_ctrl |= MXC_JPEG_RGB << 3;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc,  u32 bufsize)
+{
+	desc->stm_bufsize = bufsize;
+}
+
+void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h)
+{
+	desc->imgsize = w << 16 | h;
+}
+
+
+void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch)
+{
+	desc->line_pitch = line_pitch;
+}
+
+void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot)
+{
+	writel(desc | MXC_NXT_DESCPT_EN,
+	       reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
+}
+
+void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, void __iomem *reg)
+{
+	writel(desc->buf_base0, reg + BUF_BASE0);
+	writel(desc->buf_base1, reg + BUF_BASE1);
+	writel(desc->line_pitch, reg + LINE_PITCH);
+	writel(desc->stm_bufbase, reg + STM_BUFBASE);
+	writel(desc->stm_bufsize, reg + STM_BUFSIZE);
+	writel(desc->imgsize, reg + IMGSIZE);
+	writel(desc->stm_ctrl, reg + STM_CTRL);
+}
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-jpeg-hw.h
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-jpeg-hw.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#ifndef _MXC_JPEG_HW_H
+#define _MXC_JPEG_HW_H
+
+#define MXC_JPEG_DECODE			0
+#define MXC_JPEG_ENCODE			1
+
+/* JPEG Decoder/Encoder Wrapper Register Map */
+#define GLB_CTRL			0x0
+#define COM_STATUS			0x4
+#define BUF_BASE0			0x14
+#define BUF_BASE1			0x18
+#define LINE_PITCH			0x1C
+#define STM_BUFBASE			0x20
+#define STM_BUFSIZE			0x24
+#define IMGSIZE				0x28
+#define STM_CTRL			0x2C
+
+/* CAST JPEG-Decoder/Encoder Status Register Map (read-only)*/
+#define CAST_STATUS0			0x100
+#define CAST_STATUS1			0x104
+#define CAST_STATUS2			0x108
+#define CAST_STATUS3			0x10c
+#define CAST_STATUS4			0x110
+#define CAST_STATUS5			0x114
+#define CAST_STATUS6			0x118
+#define CAST_STATUS7			0x11c
+#define CAST_STATUS8			0x120
+#define CAST_STATUS9			0x124
+#define CAST_STATUS10			0x128
+#define CAST_STATUS11			0x12c
+#define CAST_STATUS12			0x130
+#define CAST_STATUS13			0x134
+/* the following are for encoder only */
+#define CAST_STATUS14		0x138
+#define CAST_STATUS15		0x13c
+#define CAST_STATUS16		0x140
+#define CAST_STATUS17		0x144
+#define CAST_STATUS18		0x148
+#define CAST_STATUS19		0x14c
+
+/* CAST JPEG-Decoder Control Register Map (write-only) */
+#define CAST_CTRL			CAST_STATUS13
+
+/* CAST JPEG-Encoder Control Register Map (write-only) */
+#define CAST_MODE			CAST_STATUS0
+#define CAST_CFG_MODE			CAST_STATUS1
+#define CAST_QUALITY			CAST_STATUS2
+#define CAST_RSVD			CAST_STATUS3
+#define CAST_REC_REGS_SEL		CAST_STATUS4
+#define CAST_LUMTH			CAST_STATUS5
+#define CAST_CHRTH			CAST_STATUS6
+#define CAST_NOMFRSIZE_LO		CAST_STATUS7
+#define CAST_NOMFRSIZE_HI		CAST_STATUS8
+#define CAST_OFBSIZE_LO			CAST_STATUS9
+#define CAST_OFBSIZE_HI			CAST_STATUS10
+
+#define MXC_MAX_SLOTS	1 /* TODO use all 4 slots*/
+/* JPEG-Decoder Wrapper Slot Registers 0..3 */
+#define SLOT_BASE			0x10000
+#define SLOT_STATUS			0x0
+#define SLOT_IRQ_EN			0x4
+#define SLOT_BUF_PTR			0x8
+#define SLOT_CUR_DESCPT_PTR		0xC
+#define SLOT_NXT_DESCPT_PTR		0x10
+#define MXC_SLOT_OFFSET(slot, offset)	((SLOT_BASE * (slot + 1)) + offset)
+
+/* GLB_CTRL fields */
+#define GLB_CTRL_JPG_EN					0x1
+#define GLB_CTRL_SFT_RST				(0x1 << 1)
+#define GLB_CTRL_DEC_GO					(0x1 << 2)
+#define GLB_CTRL_L_ENDIAN(le)				((le) << 3)
+#define GLB_CTRL_SLOT_EN(slot)				(0x1 << (slot + 4))
+
+/* COM_STAUS fields */
+#define COM_STATUS_DEC_ONGOING(r)		(((r) & (1 << 31)) >> 31)
+#define COM_STATUS_CUR_SLOT(r)			(((r) & (0x3 << 29)) >> 29)
+
+/* STM_CTRL fields */
+#define STM_CTRL_PIXEL_PRECISION		(0x1 << 2)
+#define STM_CTRL_IMAGE_FORMAT(img_fmt)		((img_fmt) << 3)
+#define STM_CTRL_IMAGE_FORMAT_MASK		(0xF << 3)
+#define STM_CTRL_BITBUF_PTR_CLR(clr)		((clr) << 7)
+#define STM_CTRL_AUTO_START(go)			((go) << 8)
+#define STM_CTRL_CONFIG_MOD(mod)		((mod) << 9)
+
+/* SLOTa_STATUS fields TBD */
+#define SLOTa_STATUS_FRMDONE			(0x1 << 3)
+#define SLOTa_STATUS_ENC_CONFIG_ERR		(0x1 << 8)
+
+/* SLOTa_IRQ_EN fields TBD */
+
+#define MXC_NXT_DESCPT_EN			0x1
+#define MXC_DEC_EXIT_IDLE_MODE			0x4
+
+/* JPEG-Decoder Wrapper - STM_CTRL Register Fields */
+#define MXC_PIXEL_PRECISION(precision) ((precision)/8 << 2)
+enum mxc_jpeg_image_format {
+	MXC_JPEG_INVALID = -1,
+	MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */
+	MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */
+	MXC_JPEG_RGB	= 0x2, /* RGBRGB packed format */
+	MXC_JPEG_YUV444	= 0x3, /* 1 Plannar, YUVYUV sequence */
+	MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */
+	MXC_JPEG_RESERVED = 0x5,
+	MXC_JPEG_ARGB	= 0x6,
+};
+
+
+#include "mxc-jpeg.h"
+void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc);
+void print_cast_status(struct device *dev, void __iomem *reg,
+		       unsigned int mode);
+void print_wrapper_info(struct device *dev, void __iomem *reg);
+void mxc_jpeg_sw_reset(void __iomem *reg);
+int mxc_jpeg_enable(void __iomem *reg);
+void wait_frmdone(struct device *dev, void __iomem *reg);
+void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg);
+void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg);
+void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg);
+int mxc_jpeg_get_slot(void __iomem *reg);
+u32 mxc_jpeg_get_offset(void __iomem *reg, int slot);
+void mxc_jpeg_enable_slot(void __iomem *reg, int slot);
+void mxc_jpeg_set_l_endian(void __iomem *reg, int le);
+void mxc_jpeg_enable_irq(void __iomem *reg, int slot);
+int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize);
+int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf,
+			u16 w, u16 h);
+void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode);
+int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc,  u32 bufsize, u16
+			out_pitch, u32 format);
+void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc,  u32 bufsize);
+void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h);
+void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch);
+void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot);
+void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc,
+				 void __iomem *reg);
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-jpeg.c
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-jpeg.c
@@ -0,0 +1,2286 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <linux/string.h>
+
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mxc-jpeg-hw.h"
+#include "mxc-jpeg.h"
+
+static struct mxc_jpeg_fmt mxc_formats[] = {
+	{
+		.name		= "JPEG",
+		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.colplanes	= 1,
+		.flags		= MXC_JPEG_FMT_TYPE_ENC,
+	},
+	{
+		.name		= "RGB", /*RGBRGB packed format*/
+		.fourcc		= V4L2_PIX_FMT_RGB24,
+		.depth		= 24,
+		.colplanes	= 1,
+		.h_align	= 3,
+		.v_align	= 3,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+	{
+		.name		= "ARGB", /* ARGBARGB packed format */
+		.fourcc		= V4L2_PIX_FMT_ARGB32,
+		.depth		= 32,
+		.colplanes	= 1,
+		.h_align	= 3,
+		.v_align	= 3,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+	{
+		.name		= "YUV420", /* 1st plane = Y, 2nd plane = UV */
+		.fourcc		= V4L2_PIX_FMT_NV12,
+		.depth		= 12, /* 6 bytes (4Y + UV) for 4 pixels */
+		.colplanes	= 2, /* 1 plane Y, 1 plane UV interleaved */
+		.h_align	= 4,
+		.v_align	= 4,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+	{
+		.name		= "YUV422", /* YUYV */
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= 16,
+		.colplanes	= 1,
+		.h_align	= 4,
+		.v_align	= 3,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+	{
+		.name		= "YUV444", /* YUVYUV */
+		.fourcc		= V4L2_PIX_FMT_YUV24,
+		.depth		= 24,
+		.colplanes	= 1,
+		.h_align	= 3,
+		.v_align	= 3,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+	{
+		.name		= "Gray", /* Gray (Y8/Y12) or Single Comp */
+		.fourcc		= V4L2_PIX_FMT_GREY,
+		.depth		= 8,
+		.colplanes	= 1,
+		.h_align	= 3,
+		.v_align	= 3,
+		.flags		= MXC_JPEG_FMT_TYPE_RAW,
+	},
+};
+#define MXC_JPEG_NUM_FORMATS ARRAY_SIZE(mxc_formats)
+
+static const struct of_device_id mxc_jpeg_match[] = {
+	{
+		.compatible = "fsl,imx8-jpgdec",
+		.data       = (void *)MXC_JPEG_DECODE,
+	},
+	{
+		.compatible = "fsl,imx8-jpgenc",
+		.data       = (void *)MXC_JPEG_ENCODE,
+	},
+	{ },
+};
+
+/* default configuration stream 64x64 yuv422 */
+static const unsigned char jpeg_soi[] = {0xFF, 0xD8};
+static const unsigned char jpeg_app0[] = {0xFF, 0xE0, 0x00, 0x10, 0x4A,
+0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00,
+0x00, 0x01, 0x00, 0x01, 0x00, 0x00};
+static const unsigned char jpeg_app14[] = {
+0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62,
+0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const unsigned char jpeg_dqt[] = {0xFF, 0xDB,
+0x00, 0x84, 0x00, 0x10, 0x0B, 0x0C,
+0x0E, 0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E,
+0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1A,
+0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39,
+0x33, 0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E,
+0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50,
+0x6D, 0x51, 0x57, 0x5F, 0x62, 0x67, 0x68,
+0x67, 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64,
+0x78, 0x5C, 0x65, 0x67, 0x63, 0x01, 0x11,
+0x12, 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A,
+0x1A, 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63};
+static const unsigned char jpeg_sof_maximal[] = {0xFF, 0xC0,
+0x00, 0x14, 0x08, 0x00, 0x40,
+0x00, 0x40, 0x04, 0x01, 0x11, 0x00, 0x02,
+0x11, 0x01, 0x03, 0x11, 0x01, 0x04, 0x11, 0x01};
+static const unsigned char jpeg_dht[] = {0xFF, 0xC4,
+0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
+0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05,
+0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01,
+0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91,
+0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15,
+0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
+0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19,
+0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
+0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
+0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76,
+0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85,
+0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93,
+0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
+0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
+0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
+0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
+0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3,
+0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
+0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
+0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06,
+0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
+0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52,
+0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16,
+0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18,
+0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
+0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43,
+0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
+0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
+0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
+0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93,
+0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
+0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
+0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
+0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
+0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5,
+0xF6, 0xF7, 0xF8, 0xF9, 0xFA};
+static const unsigned char jpeg_dri[] = {0xFF, 0xDD,
+0x00, 0x04, 0x00, 0x20};
+static const unsigned char jpeg_sos_maximal[] = {0xFF, 0xDA,
+0x00, 0x0C, 0x04, 0x01, 0x00, 0x02, 0x11, 0x03,
+0x11, 0x04, 0x11, 0x00, 0x3F, 0x00,};
+static const unsigned char jpeg_eoi[] = {0xFF, 0xD9};
+
+struct mxc_jpeg_src_buf {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_v4l2_buffer	b;
+	struct list_head	list;
+
+	/* mxc-jpeg specific */
+	bool			dht_needed;
+};
+
+static inline struct mxc_jpeg_src_buf *vb2_to_mxc_buf(struct vb2_buffer *vb)
+{
+	return container_of(to_vb2_v4l2_buffer(vb), struct mxc_jpeg_src_buf, b);
+}
+
+/*  Print Four-character-code (FOURCC) */
+static char *fourcc_to_str(u32 format)
+{
+	char *buf = kmalloc(32, GFP_KERNEL);
+
+	snprintf(buf, 32,
+		 "%c%c%c%c",
+		 format & 0xff,
+		 (format >> 8) & 0xff,
+		 (format >> 16) & 0xff,
+		 (format >> 24) & 0x7f);
+	return buf;
+}
+
+static unsigned int mxc_jpeg_tracing;
+module_param_named(jpeg_tracing, mxc_jpeg_tracing, int, 0600);
+MODULE_PARM_DESC(jpeg_tracing, "Enable detailed debug messages");
+
+static void _bswap16(u16 *a)
+{
+	*a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8);
+}
+
+static void print_buf_preview(struct device *dev, struct vb2_buffer *buf)
+{
+	unsigned char *data;
+	u32 dma_addr;
+
+	if (!mxc_jpeg_tracing)
+		return;
+
+	dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+	data = (char *)vb2_plane_vaddr(buf, 0);
+
+	/* print just the first 4 bytes from the beginning of the buffer */
+	dev_dbg(dev, "vaddr=%p dma_addr=%x: %x %x %x %x ...\n",
+		data, dma_addr,
+		data[0], data[1], data[2], data[3]);
+}
+
+static void print_nbuf_to_eoi(struct device *dev, struct vb2_buffer *buf,
+			      int n)
+{
+	unsigned char *data;
+	u32 dma_addr;
+	int i;
+	int items_per_line = 22;
+	char *bufstr, *bufptr;
+
+	if (!mxc_jpeg_tracing)
+		return;
+
+	if (n == 0)
+		n = buf->planes[0].bytesused;
+
+	dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+	data = (unsigned char *)vb2_plane_vaddr(buf, 0);
+
+	dev_dbg(dev, "vaddr=%p dma_addr=%x bytesused=%d:",
+		 data, dma_addr, n);
+
+	bufstr = kmalloc(items_per_line * 6, GFP_ATOMIC);
+	bufptr = bufstr;
+	for (i = 0; i < n; i++) {
+		snprintf(bufptr, 6, "0x%02x,", data[i]);
+		bufptr += 5;
+		if ((i+1) % items_per_line == 0) {
+			/* print the current line */
+			dev_dbg(dev, "%s", bufstr);
+			/* back to buffer start */
+			bufptr = bufstr;
+		}
+		/* stop at End of Image (EOI) marker*/
+		if (i > 0 && data[i-1] == 0xFF && data[i] == 0xD9)
+			break;
+	}
+	if (bufptr != bufstr)
+		dev_dbg(dev, "%s", bufstr);
+	dev_dbg(dev, "buffer size = %d", i);
+	kfree(bufstr);
+}
+
+static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct mxc_jpeg_ctx, fh);
+}
+
+static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
+		    struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num = 0;
+
+	for (i = 0; i < n; ++i) {
+		if (mxc_formats[i].flags == type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index
+			 */
+			++num;
+		}
+	}
+
+	/* Format not found */
+	if (i >= n)
+		return -EINVAL;
+
+	strscpy(f->description, mxc_formats[i].name, sizeof(f->description));
+	f->pixelformat = mxc_formats[i].fourcc;
+
+	return 0;
+}
+
+static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
+						 u32 pixelformat)
+{
+	unsigned int k;
+
+	for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
+		struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
+
+		if (fmt->fourcc == pixelformat)
+			return fmt;
+	}
+	return NULL;
+}
+
+static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(
+	u32	fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_GREY:
+		return MXC_JPEG_GRAY;
+	case V4L2_PIX_FMT_YUYV:
+		return MXC_JPEG_YUV422;
+	case V4L2_PIX_FMT_NV12:
+		return MXC_JPEG_YUV420;
+	case V4L2_PIX_FMT_YUV24:
+		return MXC_JPEG_YUV444;
+	case V4L2_PIX_FMT_RGB24:
+		return MXC_JPEG_RGB;
+	case V4L2_PIX_FMT_ARGB32:
+		return MXC_JPEG_ARGB;
+	default:
+		return MXC_JPEG_INVALID;
+	}
+}
+
+static int mxc_jpeg_imgfmt_to_fourcc(enum mxc_jpeg_image_format imgfmt,
+				  u32 *fourcc)
+{
+	switch (imgfmt) {
+	case MXC_JPEG_GRAY:
+		*fourcc = V4L2_PIX_FMT_GREY;
+		return 0;
+	case MXC_JPEG_YUV422:
+		*fourcc = V4L2_PIX_FMT_YUYV;
+		return 0;
+	case MXC_JPEG_YUV420:
+		*fourcc =  V4L2_PIX_FMT_NV12;
+		return 0;
+	case MXC_JPEG_YUV444:
+		*fourcc =  V4L2_PIX_FMT_YUV24;
+		return 0;
+	case MXC_JPEG_RGB:
+		*fourcc =  V4L2_PIX_FMT_RGB24;
+		return 0;
+	case MXC_JPEG_ARGB:
+		*fourcc =  V4L2_PIX_FMT_ARGB32;
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
+						   enum v4l2_buf_type type)
+{
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return &ctx->out_q;
+	return &ctx->cap_q;
+}
+
+static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
+			   struct vb2_buffer *raw_buf,
+			   struct vb2_buffer *jpeg_buf, int offset)
+{
+	int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK;
+
+	desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0);
+	desc->buf_base1 = 0;
+	if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
+		WARN_ON(raw_buf->num_planes < 2);
+		desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1);
+	}
+	desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) +
+		offset;
+}
+
+static void notify_eos(struct mxc_jpeg_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_EOS
+	};
+
+	dev_dbg(ctx->mxc_jpeg->dev, "Notify app event EOS reached");
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static void notify_src_chg(struct mxc_jpeg_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+			.type = V4L2_EVENT_SOURCE_CHANGE,
+			.u.src_change.changes =
+			V4L2_EVENT_SRC_CH_RESOLUTION,
+		};
+
+	dev_dbg(ctx->mxc_jpeg->dev, "Notify app event SRC_CH_RESOLUTION");
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static int mxc_get_free_slot(struct mxc_jpeg_slot_data slot_data[], int n)
+{
+	int free_slot = 0;
+
+	while (slot_data[free_slot].used && free_slot < n)
+		free_slot++;
+
+	return free_slot; /* >=n when there are no more free slots */
+}
+
+static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg,
+				     unsigned int slot)
+{
+	if (jpeg->slot_data[slot].desc)
+		goto skip_alloc; /* already allocated, reuse it */
+	/* allocate descriptor for decoding/encoding phase */
+	jpeg->slot_data[slot].desc = dma_alloc_coherent(jpeg->dev,
+		sizeof(struct mxc_jpeg_desc),
+		&jpeg->slot_data[slot].desc_handle, GFP_ATOMIC);
+	if (!jpeg->slot_data[slot].desc)
+		goto err;
+
+	/* allocate descriptor for configuration phase (encoder only) */
+	jpeg->slot_data[slot].cfg_desc = dma_alloc_coherent(jpeg->dev,
+		sizeof(struct mxc_jpeg_desc),
+		&jpeg->slot_data[slot].cfg_desc_handle, GFP_ATOMIC);
+	if (!jpeg->slot_data[slot].cfg_desc)
+		goto err;
+
+	/* allocate configuration stream */
+	jpeg->slot_data[slot].cfg_stream_vaddr = dma_alloc_coherent(
+		jpeg->dev,
+		MXC_JPEG_MAX_CFG_STREAM,
+		&jpeg->slot_data[slot].cfg_stream_handle, GFP_ATOMIC);
+	if (!jpeg->slot_data[slot].cfg_stream_vaddr)
+		goto err;
+skip_alloc:
+	jpeg->slot_data[slot].used = true;
+
+	return true;
+err:
+	dev_err(jpeg->dev, "Could not allocate descriptors for slot %d", slot);
+	return false;
+}
+
+static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg,
+				    unsigned int slot)
+{
+	if (slot >= MXC_MAX_SLOTS) {
+		dev_err(jpeg->dev, "Invalid slot %d, nothing to free.", slot);
+		return;
+	}
+
+	/* free descriptor for decoding/encoding phase */
+	dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc),
+			  jpeg->slot_data[slot].desc,
+			  jpeg->slot_data[slot].desc_handle);
+
+	/* free descriptor for encoder configuration phase / decoder DHT */
+	dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc),
+			  jpeg->slot_data[slot].cfg_desc,
+			  jpeg->slot_data[slot].cfg_desc_handle);
+
+	/* free configuration stream */
+	dma_free_coherent(jpeg->dev, MXC_JPEG_MAX_CFG_STREAM,
+			  jpeg->slot_data[slot].cfg_stream_vaddr,
+			  jpeg->slot_data[slot].cfg_stream_handle);
+
+	jpeg->slot_data[slot].used = false;
+}
+
+static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
+{
+	struct mxc_jpeg_dev *jpeg = priv;
+	struct mxc_jpeg_ctx *ctx;
+	void __iomem *reg = jpeg->base_reg;
+	struct device *dev = jpeg->dev;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	struct mxc_jpeg_src_buf *jpeg_src_buf;
+	enum vb2_buffer_state buf_state;
+	u32 dec_ret, com_status;
+	unsigned long payload;
+	struct mxc_jpeg_q_data *q_data;
+	enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	unsigned int slot;
+
+	spin_lock(&jpeg->hw_lock);
+
+	com_status = readl(reg + COM_STATUS);
+	slot = COM_STATUS_CUR_SLOT(com_status);
+	dev_dbg(dev, "Irq %d on slot %d.\n", irq, slot);
+
+	ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+	if (!ctx) {
+		dev_err(dev,
+			"Instance released before the end of transaction.\n");
+		/* soft reset only resets internal state, not registers */
+		mxc_jpeg_sw_reset(reg);
+		/* clear all interrupts */
+		writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
+		goto job_unlock;
+	}
+
+	if (slot != ctx->slot) {
+		/* TODO investigate after all power domains work together */
+		dev_warn(dev, "IRQ slot %d != context slot %d.\n",
+			 slot, ctx->slot);
+		goto job_unlock;
+	}
+
+	dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
+	writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */
+
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	if (!dst_buf || !src_buf) {
+		dev_err(dev, "No source or destination buffer.\n");
+		goto job_unlock;
+	}
+	jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf);
+
+	if (ctx->aborting) {
+		dev_warn(dev, "Aborting current job\n");
+		mxc_jpeg_sw_reset(reg);
+		buf_state = VB2_BUF_STATE_ERROR;
+		goto buffers_done;
+	}
+
+	if (dec_ret & SLOTa_STATUS_ENC_CONFIG_ERR) {
+		u32 ret = readl(reg + CAST_STATUS12);
+
+		dev_err(dev, "Encoder/decoder error, status=0x%08x", ret);
+		mxc_jpeg_sw_reset(reg);
+		buf_state = VB2_BUF_STATE_ERROR;
+		goto buffers_done;
+	}
+
+	if (!(dec_ret & SLOTa_STATUS_FRMDONE))
+		goto job_unlock;
+
+	if (ctx->mode == MXC_JPEG_ENCODE
+	    && ctx->enc_state == MXC_JPEG_ENC_CONF) {
+		ctx->enc_state = MXC_JPEG_ENC_DONE;
+		dev_dbg(dev, "Encoder config finished. Start encoding...\n");
+		mxc_jpeg_enc_mode_go(dev, reg);
+		goto job_unlock;
+	}
+	if (ctx->mode == MXC_JPEG_DECODE && jpeg_src_buf->dht_needed) {
+		jpeg_src_buf->dht_needed = false;
+		dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n");
+		goto job_unlock;
+	}
+	if (ctx->mode == MXC_JPEG_ENCODE) {
+		payload = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload);
+		dev_dbg(dev, "Encoding finished, payload size: %ld\n",
+			payload);
+	} else {
+		q_data = mxc_jpeg_get_q_data(ctx, cap_type);
+		payload = q_data->sizeimage[0];
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload);
+		vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+		if (q_data->fmt->colplanes == 2) {
+			payload = q_data->sizeimage[1];
+			vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload);
+		}
+		dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n",
+			vb2_get_plane_payload(&dst_buf->vb2_buf, 0),
+			vb2_get_plane_payload(&dst_buf->vb2_buf, 1));
+	}
+
+	/* short preview of the results */
+	dev_dbg(dev, "src_buf preview: ");
+	print_buf_preview(dev, &src_buf->vb2_buf);
+	dev_dbg(dev, "dst_buf preview: ");
+	print_buf_preview(dev, &dst_buf->vb2_buf);
+	buf_state = VB2_BUF_STATE_DONE;
+
+buffers_done:
+	jpeg->slot_data[slot].used = false; /* unused, but don't free */
+	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_buf_done(src_buf, buf_state);
+	v4l2_m2m_buf_done(dst_buf, buf_state);
+	spin_unlock(&jpeg->hw_lock);
+	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+	return IRQ_HANDLED;
+job_unlock:
+	spin_unlock(&jpeg->hw_lock);
+	return IRQ_HANDLED;
+}
+
+static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
+			      u32 fourcc,
+			      u16 w, u16 h)
+{
+	int sof_length;
+
+	sof->precision = 8; /* TODO allow 8/12 bit precision*/
+	sof->height = h;
+	_bswap16(&sof->height);
+	sof->width = w;
+	_bswap16(&sof->width);
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		sof->components_no = 3;
+		sof->comp[0].v = 0x2; sof->comp[0].h = 0x2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		sof->components_no = 3;
+		sof->comp[0].v = 0x1; sof->comp[0].h = 0x2;
+		break;
+	case V4L2_PIX_FMT_YUV24:
+	case V4L2_PIX_FMT_RGB24:
+	default:
+		sof->components_no = 3;
+		break;
+	case V4L2_PIX_FMT_ARGB32:
+		sof->components_no = 4;
+		break;
+	case V4L2_PIX_FMT_GREY:
+		sof->components_no = 1;
+		break;
+	}
+	sof_length = 8 + 3 * sof->components_no;
+	sof->length = sof_length;
+	_bswap16(&sof->length);
+
+	return sof_length; /* not swaped */
+}
+
+static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos,
+			      u32 fourcc)
+{
+	int sos_length;
+	u8 *sof_u8 = (u8 *)sos;
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		sos->components_no = 3;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		sos->components_no = 3;
+		break;
+	case V4L2_PIX_FMT_YUV24:
+	case V4L2_PIX_FMT_RGB24:
+	default:
+		sos->components_no = 3;
+		break;
+	case V4L2_PIX_FMT_ARGB32:
+		sos->components_no = 4;
+		break;
+	case V4L2_PIX_FMT_GREY:
+		sos->components_no = 1;
+		break;
+	}
+	sos_length = 6 + 2 * sos->components_no;
+	sos->length = sos_length;
+	_bswap16(&sos->length);
+
+	/* SOS ignorable bytes, not so ignorable after all */
+	sof_u8[sos_length - 1] = 0x0;
+	sof_u8[sos_length - 2] = 0x3f;
+	sof_u8[sos_length - 3] = 0x0;
+
+	return sos_length; /* not swaped */
+}
+
+static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
+					      u32 fourcc,
+					      u16 w, u16 h)
+{
+	unsigned int offset = 0;
+	u8 *cfg = (u8 *)cfg_stream_vaddr;
+	struct mxc_jpeg_sof *sof;
+	struct mxc_jpeg_sos *sos;
+
+	memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi));
+	offset += ARRAY_SIZE(jpeg_soi);
+
+	if (fourcc == V4L2_PIX_FMT_RGB24 ||
+	    fourcc == V4L2_PIX_FMT_ARGB32) {
+		memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14));
+		offset += sizeof(jpeg_app14);
+	} else {
+		memcpy(cfg + offset, jpeg_app0, sizeof(jpeg_app0));
+		offset += sizeof(jpeg_app0);
+	}
+
+	memcpy(cfg + offset, jpeg_dqt, sizeof(jpeg_dqt));
+	offset += sizeof(jpeg_dqt);
+
+	memcpy(cfg + offset, jpeg_sof_maximal, sizeof(jpeg_sof_maximal));
+	offset += 2; /* skip marker ID */
+	sof = (struct mxc_jpeg_sof *)(cfg + offset);
+	offset += mxc_jpeg_fixup_sof(sof, fourcc, w, h);
+
+	memcpy(cfg + offset, jpeg_dht, sizeof(jpeg_dht));
+	offset += sizeof(jpeg_dht);
+
+	memcpy(cfg + offset, jpeg_dri, sizeof(jpeg_dri));
+	offset += sizeof(jpeg_dri);
+
+	memcpy(cfg + offset, jpeg_sos_maximal, sizeof(jpeg_sos_maximal));
+	offset += 2; /* skip marker ID */
+	sos = (struct mxc_jpeg_sos *)(cfg + offset);
+	offset += mxc_jpeg_fixup_sos(sos, fourcc);
+
+	memcpy(cfg + offset, jpeg_eoi, sizeof(jpeg_eoi));
+	offset += sizeof(jpeg_eoi);
+
+	return offset;
+}
+
+static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf,
+				     struct mxc_jpeg_ctx *ctx,
+				     struct vb2_buffer *src_buf,
+				     struct vb2_buffer *dst_buf)
+{
+	enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	struct mxc_jpeg_q_data *q_data_cap;
+	enum mxc_jpeg_image_format img_fmt;
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	void __iomem *reg = jpeg->base_reg;
+	unsigned int slot = ctx->slot;
+	struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
+	struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc;
+	dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
+	dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle;
+	dma_addr_t cfg_stream_handle = jpeg->slot_data[slot].cfg_stream_handle;
+	unsigned int *cfg_size = &jpeg->slot_data[slot].cfg_stream_size;
+	void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr;
+	struct mxc_jpeg_src_buf *jpeg_src_buf;
+
+	jpeg_src_buf = vb2_to_mxc_buf(src_buf);
+
+	/* setup the decoding descriptor */
+	desc->next_descpt_ptr = 0; /* end of chain */
+	q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type);
+	desc->imgsize = q_data_cap->w_adjusted << 16 | q_data_cap->h_adjusted;
+	img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data_cap->fmt->fourcc);
+	desc->stm_ctrl &= ~STM_CTRL_IMAGE_FORMAT(0xF); /* clear image format */
+	desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
+	desc->line_pitch = q_data_cap->bytesperline[0];
+	mxc_jpeg_addrs(desc, dst_buf, src_buf, 0);
+	mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(src_buf, 0), 1024));
+	print_descriptor_info(jpeg->dev, desc);
+
+	if (!jpeg_src_buf->dht_needed) {
+		/* validate the decoding descriptor */
+		mxc_jpeg_set_desc(desc_handle, reg, slot);
+		return;
+	}
+
+	/*
+	 * if a default huffman table is needed, use the config descriptor to
+	 * inject a DHT, by chaining it before the decoding descriptor
+	 */
+	*cfg_size = mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
+					      V4L2_PIX_FMT_YUYV,
+					      MXC_JPEG_MIN_WIDTH,
+					      MXC_JPEG_MIN_HEIGHT);
+	cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
+	cfg_desc->buf_base0 = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	cfg_desc->buf_base1 = 0;
+	cfg_desc->imgsize = MXC_JPEG_MIN_WIDTH << 16;
+	cfg_desc->imgsize |= MXC_JPEG_MIN_HEIGHT;
+	cfg_desc->line_pitch = MXC_JPEG_MIN_WIDTH * 2;
+	cfg_desc->stm_ctrl = STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422);
+	cfg_desc->stm_bufbase = cfg_stream_handle;
+	cfg_desc->stm_bufsize = ALIGN(*cfg_size, 1024);
+	print_descriptor_info(jpeg->dev, cfg_desc);
+
+	/* validate the configuration descriptor */
+	mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
+}
+
+static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
+				     struct mxc_jpeg_ctx *ctx,
+				     struct vb2_buffer *src_buf,
+				     struct vb2_buffer *dst_buf)
+{
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	void __iomem *reg = jpeg->base_reg;
+	unsigned int slot = ctx->slot;
+	struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
+	struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc;
+	dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
+	dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle;
+	void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr;
+	struct mxc_jpeg_q_data *q_data;
+	enum mxc_jpeg_image_format img_fmt;
+	int w, h;
+
+	q_data = mxc_jpeg_get_q_data(ctx, src_buf->vb2_queue->type);
+
+	jpeg->slot_data[slot].cfg_stream_size =
+			mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
+						  q_data->fmt->fourcc,
+						  q_data->w_adjusted,
+						  q_data->h_adjusted);
+
+	/* chain the config descriptor with the encoding descriptor */
+	cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
+
+	cfg_desc->buf_base0 = jpeg->slot_data[slot].cfg_stream_handle;
+	cfg_desc->buf_base1 = 0;
+	cfg_desc->line_pitch = 0;
+	cfg_desc->stm_bufbase = 0;
+	cfg_desc->stm_bufsize = 0x2000;
+	cfg_desc->imgsize = 0;
+	cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1);
+
+	desc->next_descpt_ptr = 0; /* end of chain */
+
+	/* use adjusted resolution for CAST IP job */
+	w = q_data->w_adjusted;
+	h = q_data->h_adjusted;
+	mxc_jpeg_set_res(desc, w, h);
+	mxc_jpeg_set_line_pitch(desc, w * (q_data->fmt->depth / 8));
+	mxc_jpeg_set_bufsize(desc, desc->line_pitch * h);
+	img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
+	if (img_fmt == MXC_JPEG_INVALID)
+		dev_err(jpeg->dev, "No valid image format detected\n");
+	desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) |
+			 STM_CTRL_IMAGE_FORMAT(img_fmt);
+	mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
+	dev_dbg(jpeg->dev, "cfg_desc - 0x%llx:\n", cfg_desc_handle);
+	print_descriptor_info(jpeg->dev, cfg_desc);
+	dev_dbg(jpeg->dev, "enc desc - 0x%llx:\n", desc_handle);
+	print_descriptor_info(jpeg->dev, desc);
+	print_wrapper_info(jpeg->dev, reg);
+	print_cast_status(jpeg->dev, reg, MXC_JPEG_ENCODE);
+
+	/* validate the configuration descriptor */
+	mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
+}
+
+static void mxc_jpeg_device_run(void *priv)
+{
+	struct mxc_jpeg_ctx *ctx = priv;
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	void __iomem *reg = jpeg->base_reg;
+	struct device *dev = jpeg->dev;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
+	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	if (!src_buf || !dst_buf) {
+		dev_err(dev, "Null src or dst buf\n");
+		goto end;
+	}
+
+	/*
+	 * TODO: this reset should be removed, once we figure out
+	 * how to overcome hardware issues both on encoder and decoder
+	 */
+	mxc_jpeg_sw_reset(reg);
+	mxc_jpeg_enable(reg);
+	mxc_jpeg_set_l_endian(reg, 1);
+
+	ctx->slot = mxc_get_free_slot(jpeg->slot_data, MXC_MAX_SLOTS);
+	if (ctx->slot >= MXC_MAX_SLOTS) {
+		dev_err(dev, "No more free slots\n");
+		goto end;
+	}
+	if (!mxc_jpeg_alloc_slot_data(jpeg, ctx->slot)) {
+		dev_err(dev, "Canot allocate slot data\n");
+		goto end;
+	}
+
+	mxc_jpeg_enable_slot(reg, ctx->slot);
+	mxc_jpeg_enable_irq(reg, ctx->slot);
+
+	if (ctx->mode == MXC_JPEG_ENCODE) {
+		dev_dbg(dev, "Encoding on slot %d\n", ctx->slot);
+		ctx->enc_state = MXC_JPEG_ENC_CONF;
+		mxc_jpeg_config_enc_desc(&dst_buf->vb2_buf, ctx,
+					 &src_buf->vb2_buf, &dst_buf->vb2_buf);
+		mxc_jpeg_enc_mode_conf(dev, reg);
+	} else {
+		dev_dbg(dev, "Decoding on slot %d\n", ctx->slot);
+		print_nbuf_to_eoi(dev, &src_buf->vb2_buf, 0);
+		mxc_jpeg_config_dec_desc(&dst_buf->vb2_buf, ctx,
+					 &src_buf->vb2_buf, &dst_buf->vb2_buf);
+		mxc_jpeg_dec_mode_go(dev, reg);
+	}
+end:
+	spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+}
+
+static int mxc_jpeg_try_decoder_cmd(struct file *file, void *fh,
+				    struct v4l2_decoder_cmd *c)
+{
+	if (c->cmd != V4L2_DEC_CMD_STOP && c->cmd != V4L2_DEC_CMD_START)
+		return -EINVAL;
+
+	c->flags = 0;
+
+	if (c->cmd == V4L2_DEC_CMD_START) {
+		c->start.speed = 0;
+		c->start.format = 0;
+	}
+
+	return 0;
+}
+
+static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
+				struct v4l2_decoder_cmd *cmd)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+	struct device *dev = ctx->mxc_jpeg->dev;
+	int ret;
+
+	ret = mxc_jpeg_try_decoder_cmd(file, fh, cmd);
+	if (ret < 0)
+		return ret;
+
+	/* Ignore decoder command silently in encoder context */
+	if (ctx->mode != MXC_JPEG_DECODE)
+		return 0;
+
+	if (cmd->cmd == V4L2_DEC_CMD_STOP) {
+		dev_dbg(dev, "Received V4L2_DEC_CMD_STOP");
+		if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
+			/* No more src bufs, notify app EOS */
+			notify_eos(ctx);
+		} else {
+			/* will send EOS later*/
+			ctx->stopping = 1;
+		}
+	}
+
+	return 0;
+}
+
+static int mxc_jpeg_try_encoder_cmd(struct file *file, void *fh,
+				    struct v4l2_encoder_cmd *c)
+{
+	if (c->cmd != V4L2_ENC_CMD_STOP && c->cmd != V4L2_ENC_CMD_START)
+		return -EINVAL;
+
+	c->flags = 0;
+
+	return 0;
+}
+
+static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
+				struct v4l2_encoder_cmd *cmd)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+	struct device *dev = ctx->mxc_jpeg->dev;
+	int ret;
+
+	ret = mxc_jpeg_try_encoder_cmd(file, fh, cmd);
+	if (ret < 0)
+		return ret;
+
+	/* Ignore encoder command silently in decoder context */
+	if (ctx->mode != MXC_JPEG_ENCODE)
+		return 0;
+
+	if (cmd->cmd == V4L2_ENC_CMD_STOP) {
+		dev_dbg(dev, "Received V4L2_ENC_CMD_STOP");
+		if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
+			/* No more src bufs, notify app EOS */
+			notify_eos(ctx);
+		} else {
+			/* will send EOS later*/
+			ctx->stopping = 1;
+		}
+	}
+
+	return 0;
+}
+
+static int mxc_jpeg_job_ready(void *priv)
+{
+	struct mxc_jpeg_ctx *ctx = priv;
+	unsigned int num_src_bufs_ready;
+	unsigned int num_dst_bufs_ready;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
+
+	num_src_bufs_ready = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx);
+	num_dst_bufs_ready = v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx);
+
+	spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+
+	if (num_src_bufs_ready >= 1 && num_dst_bufs_ready >= 1)
+		return 1;
+	return 0;
+}
+static void mxc_jpeg_job_abort(void *priv)
+{
+	struct mxc_jpeg_ctx *ctx = priv;
+
+	ctx->aborting = 1;
+	dev_dbg(ctx->mxc_jpeg->dev, "Abort requested\n");
+}
+
+static int mxc_jpeg_queue_setup(struct vb2_queue *q,
+				unsigned int *nbuffers,
+				unsigned int *nplanes,
+				unsigned int sizes[],
+				struct device *alloc_ctxs[])
+{
+	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+	struct mxc_jpeg_q_data *q_data = NULL;
+	int i;
+
+	q_data = mxc_jpeg_get_q_data(ctx, q->type);
+	if (!q_data)
+		return -EINVAL;
+
+	/* Handle CREATE_BUFS situation - *nplanes != 0 */
+	if (*nplanes) {
+		for (i = 0; i < *nplanes; i++) {
+			if (sizes[i] < q_data->sizeimage[i])
+				return -EINVAL;
+		}
+	}
+
+	/* Handle REQBUFS situation */
+	*nplanes = q_data->fmt->colplanes;
+	for (i = 0; i < *nplanes; i++)
+		sizes[i] = q_data->sizeimage[i];
+
+	return 0;
+}
+static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+	int ret;
+
+	dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
+	ret = pm_runtime_get_sync(ctx->mxc_jpeg->dev);
+	return ret > 0 ? 0 : ret;
+}
+
+static void release_active_buffers(struct vb2_queue *q,
+				   enum vb2_buffer_state s)
+{
+	struct vb2_buffer *vb;
+
+	if (!list_empty(&q->queued_list))
+		list_for_each_entry(vb, &q->queued_list, queued_entry) {
+			if (vb->state == VB2_BUF_STATE_ACTIVE)
+				vb2_buffer_done(vb, s);
+		}
+}
+
+static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
+{
+	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+
+	dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming ctx=%p", ctx);
+
+	/* Release all active buffers */
+	release_active_buffers(q, VB2_BUF_STATE_ERROR);
+
+	pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
+}
+struct mxc_jpeg_stream {
+	u8 *addr;
+	u32 loc;
+	u32 end;
+};
+static u8 get_byte(struct mxc_jpeg_stream *stream)
+{
+	u8 ret;
+
+	if (stream->loc >= stream->end)
+		return -1;
+	ret = stream->addr[stream->loc];
+	stream->loc++;
+	return ret;
+}
+
+static int get_sof(struct device *dev,
+	struct mxc_jpeg_stream *stream,
+	struct mxc_jpeg_sof *sof)
+{
+	int i;
+
+	if (stream->loc + sizeof(struct mxc_jpeg_sof) >= stream->end)
+		return -1;
+	memcpy(sof, &stream->addr[stream->loc], sizeof(struct mxc_jpeg_sof));
+	_bswap16(&sof->length);
+	_bswap16(&sof->height);
+	_bswap16(&sof->width);
+	dev_dbg(dev, "JPEG SOF: precision=%d\n", sof->precision);
+	dev_dbg(dev, "JPEG SOF: height=%d, width=%d\n",
+		sof->height, sof->width);
+	for (i = 0; i < sof->components_no; i++) {
+		dev_dbg(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
+			sof->comp[i].id, sof->comp[i].v, sof->comp[i].h);
+	}
+	return 0;
+}
+
+static int mxc_jpeg_valid_comp_id(
+	struct device *dev,
+	struct mxc_jpeg_sof *sof,
+	struct mxc_jpeg_sos *sos)
+{
+	int valid = 1;
+	int i;
+
+	for (i = 0; i < sof->components_no; i++)
+		if (sof->comp[i].id > MXC_JPEG_MAX_COMPONENTS) {
+			valid = 0;
+			dev_err(dev, "Component %d has invalid ID: %d",
+				i, sof->comp[i].id);
+		}
+	if (!valid)
+		/* patch all comp IDs if at least one is invalid */
+		for (i = 0; i < sof->components_no; i++) {
+			dev_warn(dev, "Component %d ID patched to: %d",
+				 i, i + 1);
+			sof->comp[i].id = i + 1;
+			sos->comp[i].id = i + 1;
+		}
+
+	return valid;
+}
+
+static enum mxc_jpeg_image_format mxc_jpeg_get_image_format(
+	struct device *dev,
+	const struct mxc_jpeg_sof *sof)
+{
+	if (sof->components_no == 1) {
+		dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
+		return MXC_JPEG_GRAY;
+	}
+	if (sof->components_no == 3) {
+		if (sof->comp[0].h == 2 && sof->comp[0].v == 2 &&
+		    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+		    sof->comp[2].h == 1 && sof->comp[2].v == 1){
+			dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
+			return MXC_JPEG_YUV420;
+		}
+		if (sof->comp[0].h == 2 && sof->comp[0].v == 1 &&
+		    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+		    sof->comp[2].h == 1 && sof->comp[2].v == 1){
+			dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
+			return MXC_JPEG_YUV422;
+		}
+		if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
+		    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+		    sof->comp[2].h == 1 && sof->comp[2].v == 1){
+			dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
+			return MXC_JPEG_YUV444;
+		}
+	}
+	if (sof->components_no == 4) {
+		if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
+		    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+		    sof->comp[2].h == 1 && sof->comp[2].v == 1 &&
+		    sof->comp[3].h == 1 && sof->comp[3].v == 1){
+			/* this is not tested */
+			dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_ARGB\n");
+			return MXC_JPEG_ARGB;
+		}
+	}
+	dev_err(dev, "Could not identify image format\n");
+	return MXC_JPEG_INVALID;
+}
+
+static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q,
+				  u32 precision)
+{
+	/* Bytes distance between the leftmost pixels in two adjacent lines */
+	if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+		/* bytesperline unused for compressed formats */
+		q->bytesperline[0] = 0;
+		q->bytesperline[1] = 0;
+	} else if (q->fmt->fourcc == V4L2_PIX_FMT_NV12) {
+		/* When the image format is planar the bytesperline value
+		 * applies to the first plane and is divided by the same factor
+		 * as the width field for the other planes
+		 */
+		q->bytesperline[0] = q->w * (precision / 8) *
+				     (q->fmt->depth / 8);
+		q->bytesperline[1] = q->bytesperline[0];
+	} else {
+		/* single plane formats */
+		q->bytesperline[0] = q->w * (precision / 8) *
+				     (q->fmt->depth / 8);
+		q->bytesperline[1] = 0;
+	}
+}
+
+static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q)
+{
+	if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+		/* if no sizeimage from user, assume worst jpeg compression */
+		if (!q->sizeimage[0])
+			q->sizeimage[0] = 6 * q->w * q->h;
+		q->sizeimage[1] = 0;
+
+		if (q->sizeimage[0] > MXC_JPEG_MAX_SIZEIMAGE)
+			q->sizeimage[0] = MXC_JPEG_MAX_SIZEIMAGE;
+
+		/* jpeg stream size must be multiple of 1K */
+		q->sizeimage[0] = ALIGN(q->sizeimage[0], 1024);
+	} else {
+		q->sizeimage[0] = q->bytesperline[0] * q->h;
+		q->sizeimage[1] = 0;
+		if (q->fmt->fourcc == V4L2_PIX_FMT_NV12)
+			q->sizeimage[1] = q->sizeimage[0] / 2;
+	}
+}
+
+static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
+	u8 *src_addr, u32 size, bool *dht_needed)
+{
+	struct device *dev = ctx->mxc_jpeg->dev;
+	struct mxc_jpeg_q_data *q_data_out, *q_data_cap;
+	enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	struct mxc_jpeg_stream stream;
+	bool notfound = true;
+	bool app14 = false;
+	bool src_chg = false;
+	u8 app14_transform = 0;
+	struct mxc_jpeg_sof sof, *psof = 0;
+	struct mxc_jpeg_sos *psos = 0;
+	u8 byte, *next = 0;
+	enum mxc_jpeg_image_format img_fmt;
+	u32 fourcc;
+
+	memset(&sof, 0, sizeof(struct mxc_jpeg_sof));
+	stream.addr = src_addr;
+	stream.end = size;
+	stream.loc = 0;
+	*dht_needed = true;
+	while (notfound) {
+		byte = get_byte(&stream);
+		if (byte == -1)
+			return -EINVAL;
+		if (byte != 0xff)
+			continue;
+		do {
+			byte = get_byte(&stream);
+		} while (byte == 0xff);
+		if (byte == 0)
+			continue;
+		switch (byte) {
+		case DHT:
+			/* DHT marker present, no need to inject default one */
+			*dht_needed = false;
+			break;
+		case SOF2: /* Progressive DCF frame definition */
+			dev_err(dev,
+				"Progressive JPEG not supported by hardware");
+			return -EINVAL;
+		case SOF1: /* Extended sequential DCF frame definition */
+		case SOF0: /* Baseline sequential DCF frame definition */
+			if (get_sof(dev, &stream, &sof) == -1)
+				break;
+			next = stream.addr + stream.loc;
+			psof = (struct mxc_jpeg_sof *)next;
+			break;
+		case SOS:
+			next = stream.addr + stream.loc;
+			psos = (struct mxc_jpeg_sos *)next;
+			notfound = false;
+			break;
+		case APP14:
+			app14 = true;
+			/*
+			 * Application Data Syntax is:
+			 * 2 bytes(APPn:0xFF,0xEE), 2 bytes(Lp), Ap1...ApLp-2
+			 * The transform flag is in Ap12
+			 * stream.loc is now on APPn-0xEE byte
+			 */
+			app14_transform = *(stream.addr + stream.loc + 12 + 1);
+			break;
+		default:
+			notfound = true;
+		}
+	}
+	q_data_out = mxc_jpeg_get_q_data(ctx,
+					 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+	if (q_data_out->w == 0 && q_data_out->h == 0) {
+		dev_warn(dev, "Invalid user resolution 0x0");
+		dev_warn(dev, "Keeping resolution from JPEG: %dx%d",
+			 sof.width, sof.height);
+		 q_data_out->w = sof.width;
+		 q_data_out->h = sof.height;
+	} else if (sof.width != q_data_out->w || sof.height != q_data_out->h) {
+		dev_err(dev,
+			"Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
+			sof.width, sof.height, q_data_out->w, q_data_out->h);
+		return -EINVAL;
+	}
+	if (sof.width % 8 != 0 || sof.height % 8 != 0) {
+		dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
+			sof.width, sof.height);
+		return -EINVAL;
+	}
+	if (sof.width > MXC_JPEG_MAX_WIDTH ||
+	    sof.height > MXC_JPEG_MAX_HEIGHT) {
+		dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n",
+			sof.width, sof.height);
+		return -EINVAL;
+	}
+	if (sof.width < MXC_JPEG_MIN_WIDTH ||
+	    sof.height < MXC_JPEG_MIN_HEIGHT) {
+		dev_err(dev, "JPEG width or height should be > 64: %dx%d\n",
+			sof.width, sof.height);
+		return -EINVAL;
+	}
+	if (sof.components_no > MXC_JPEG_MAX_COMPONENTS) {
+		dev_err(dev, "JPEG number of components should be <=%d",
+			MXC_JPEG_MAX_COMPONENTS);
+		return -EINVAL;
+	}
+	/* check and, if necessary, patch component IDs*/
+	if (!mxc_jpeg_valid_comp_id(dev, psof, psos))
+		dev_warn(dev, "JPEG component ids should be 0-3 or 1-4");
+
+	img_fmt = mxc_jpeg_get_image_format(dev, &sof);
+	if (img_fmt == MXC_JPEG_INVALID)
+		return -EINVAL;
+
+	/*
+	 * If the transform flag from APP14 marker is 0, images that are
+	 * encoded with 3 components have RGB colorspace, see Recommendation
+	 * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding
+	 */
+	if ((img_fmt == MXC_JPEG_YUV444) && app14 && (app14_transform == 0))
+		img_fmt = MXC_JPEG_RGB;
+
+	if (mxc_jpeg_imgfmt_to_fourcc(img_fmt, &fourcc)) {
+		dev_err(dev, "Fourcc not found for %d", img_fmt);
+		return -EINVAL;
+	}
+
+	/*
+	 * set-up the capture queue with the pixelformat and resolution
+	 * detected from the jpeg output stream
+	 */
+	q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type);
+	if (q_data_cap->w != sof.width || q_data_cap->h != sof.height)
+		src_chg = true;
+	q_data_cap->w = sof.width;
+	q_data_cap->h = sof.height;
+	q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc);
+	q_data_cap->w_adjusted = q_data_cap->w;
+	q_data_cap->h_adjusted = q_data_cap->h;
+	/*
+	 * align up the resolution for CAST IP,
+	 * but leave the buffer resolution unchanged
+	 */
+	v4l_bound_align_image(&q_data_cap->w_adjusted,
+			      q_data_cap->w_adjusted,  /* adjust up */
+			      MXC_JPEG_MAX_WIDTH,
+			      q_data_cap->fmt->h_align,
+			      &q_data_cap->h_adjusted,
+			      q_data_cap->h_adjusted, /* adjust up */
+			      MXC_JPEG_MAX_HEIGHT,
+			      q_data_cap->fmt->v_align,
+			      0);
+	{
+		char *jpeg_format_name = fourcc_to_str(fourcc);
+
+		dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%s\n",
+			q_data_cap->w, q_data_cap->h,
+			q_data_cap->w_adjusted, q_data_cap->h_adjusted,
+			jpeg_format_name);
+		kfree(jpeg_format_name);
+	}
+
+	/* setup bytesperline/sizeimage for capture queue */
+	mxc_jpeg_bytesperline(q_data_cap, sof.precision);
+	mxc_jpeg_sizeimage(q_data_cap);
+
+	/*
+	 * if the CAPTURE format was updated with new values, regardless of
+	 * whether they match the values set by the client or not, signal
+	 * a source change event
+	 */
+	if (src_chg)
+		notify_src_chg(ctx);
+
+	return 0;
+}
+
+static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+	int ret;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mxc_jpeg_src_buf *jpeg_src_buf;
+
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		goto end;
+
+	/* for V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE */
+	if (ctx->mode != MXC_JPEG_DECODE)
+		goto end;
+	jpeg_src_buf = vb2_to_mxc_buf(vb);
+	ret = mxc_jpeg_parse(ctx,
+			(u8 *)vb2_plane_vaddr(vb, 0),
+			vb2_get_plane_payload(vb, 0),
+			&jpeg_src_buf->dht_needed);
+	if (ret) {
+		v4l2_err(&ctx->mxc_jpeg->v4l2_dev,
+			 "driver does not support this resolution/format\n");
+		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		return;
+	}
+end:
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mxc_jpeg_q_data *q_data = NULL;
+	struct device *dev = ctx->mxc_jpeg->dev;
+	unsigned long sizeimage;
+	int i;
+
+	q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
+	if (!q_data)
+		return -EINVAL;
+	for (i = 0; i < q_data->fmt->colplanes; i++) {
+		sizeimage = q_data->sizeimage[i];
+		if (vb2_plane_size(vb, i) < sizeimage) {
+			dev_err(dev, "plane %d too small (%lu < %lu)",
+				i, vb2_plane_size(vb, i), sizeimage);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, sizeimage);
+	}
+	return 0;
+}
+
+static void mxc_jpeg_buf_clean(struct vb2_buffer *vb)
+{
+}
+
+static const struct vb2_ops mxc_jpeg_qops = {
+	.queue_setup		= mxc_jpeg_queue_setup,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+	.buf_prepare		= mxc_jpeg_buf_prepare,
+	.buf_cleanup		= mxc_jpeg_buf_clean,
+	.start_streaming	= mxc_jpeg_start_streaming,
+	.stop_streaming		= mxc_jpeg_stop_streaming,
+	.buf_queue		= mxc_jpeg_buf_queue,
+};
+static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
+			       struct vb2_queue *dst_vq)
+{
+	struct mxc_jpeg_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct mxc_jpeg_src_buf);
+	src_vq->ops = &mxc_jpeg_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->mxc_jpeg->lock;
+	src_vq->dev = ctx->mxc_jpeg->dev;
+	src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &mxc_jpeg_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->mxc_jpeg->lock;
+	dst_vq->dev = ctx->mxc_jpeg->dev;
+
+	ret = vb2_queue_init(dst_vq);
+	return ret;
+}
+
+static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx)
+{
+	struct mxc_jpeg_q_data *out_q = &ctx->out_q;
+	struct mxc_jpeg_q_data *cap_q = &ctx->cap_q;
+	struct mxc_jpeg_q_data *q[2] = {out_q, cap_q};
+	int i;
+
+	ctx->colorspace = V4L2_COLORSPACE_JPEG,
+	ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+	ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+	if (ctx->mode == MXC_JPEG_ENCODE) {
+		out_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT);
+		cap_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
+	} else {
+		out_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
+		cap_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT);
+	}
+
+	for (i = 0; i < 2; i++) {
+		q[i]->w = MXC_JPEG_DEFAULT_WIDTH;
+		q[i]->h = MXC_JPEG_DEFAULT_HEIGHT;
+		mxc_jpeg_bytesperline(q[i], 8);
+		mxc_jpeg_sizeimage(q[i]);
+	}
+}
+
+static int mxc_jpeg_open(struct file *file)
+{
+	struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+	struct video_device *mxc_vfd = video_devdata(file);
+	struct device *dev = mxc_jpeg->dev;
+	struct mxc_jpeg_ctx *ctx;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (mutex_lock_interruptible(&mxc_jpeg->lock)) {
+		ret = -ERESTARTSYS;
+		goto free;
+	}
+
+	pm_runtime_get_sync(mxc_jpeg->dev);
+
+	v4l2_fh_init(&ctx->fh, mxc_vfd);
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->mxc_jpeg = mxc_jpeg;
+	ctx->mode = mxc_jpeg->mode;
+
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(mxc_jpeg->m2m_dev, ctx,
+					    mxc_jpeg_queue_init);
+
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		goto error;
+	}
+
+	mxc_jpeg_set_default_params(ctx);
+	ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */
+
+	if (mxc_jpeg->mode == MXC_JPEG_DECODE)
+		dev_dbg(dev, "Opened JPEG decoder instance %p\n", ctx);
+	else
+		dev_dbg(dev, "Opened JPEG encoder instance %p\n", ctx);
+	mutex_unlock(&mxc_jpeg->lock);
+	return 0;
+
+error:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	mutex_unlock(&mxc_jpeg->lock);
+free:
+	kfree(ctx);
+	return ret;
+}
+
+static int mxc_jpeg_querycap(struct file *file, void *priv,
+			     struct v4l2_capability *cap)
+{
+	struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+
+	strscpy(cap->driver, MXC_JPEG_NAME " decoder", sizeof(cap->driver));
+	strscpy(cap->card, MXC_JPEG_NAME " decoder", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 dev_name(mxc_jpeg->dev));
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+				     struct v4l2_fmtdesc *f)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+
+	if (ctx->mode == MXC_JPEG_ENCODE)
+		return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
+			MXC_IN_FORMAT);
+	else
+		return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
+			MXC_OUT_FORMAT);
+}
+
+static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+				     struct v4l2_fmtdesc *f)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+
+	if (ctx->mode == MXC_JPEG_DECODE)
+		return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
+				MXC_IN_FORMAT);
+	else
+		return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
+				MXC_OUT_FORMAT);
+}
+
+static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
+			    struct mxc_jpeg_ctx *ctx, int q_type)
+{
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	struct v4l2_plane_pix_format *pfmt;
+	u32 w = (pix_mp->width < MXC_JPEG_MAX_WIDTH) ?
+		 pix_mp->width : MXC_JPEG_MAX_WIDTH;
+	u32 h = (pix_mp->height < MXC_JPEG_MAX_HEIGHT) ?
+		 pix_mp->height : MXC_JPEG_MAX_HEIGHT;
+	int i;
+	struct mxc_jpeg_q_data tmp_q;
+
+	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->num_planes = fmt->colplanes;
+	pix_mp->pixelformat = fmt->fourcc;
+
+	/*
+	 * use MXC_JPEG_H_ALIGN instead of fmt->v_align, for vertical
+	 * alignment, to loosen up the alignment to multiple of 8,
+	 * otherwise NV12-1080p fails as 1080 is not a multiple of 16
+	 */
+	v4l_bound_align_image(&w,
+			      MXC_JPEG_MIN_WIDTH,
+			      w, /* adjust downwards*/
+			      fmt->h_align,
+			      &h,
+			      MXC_JPEG_MIN_HEIGHT,
+			      h, /* adjust downwards*/
+			      MXC_JPEG_H_ALIGN,
+			      0);
+	pix_mp->width = w; /* negotiate the width */
+	pix_mp->height = h; /* negotiate the height */
+
+	/* get user input into the tmp_q */
+	tmp_q.w = w;
+	tmp_q.h = h;
+	tmp_q.fmt = fmt;
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		pfmt = &pix_mp->plane_fmt[i];
+		tmp_q.bytesperline[i] = pfmt->bytesperline;
+		tmp_q.sizeimage[i] = pfmt->sizeimage;
+	}
+
+	/* calculate bytesperline & sizeimage into the tmp_q */
+	mxc_jpeg_bytesperline(&tmp_q, 8);
+	mxc_jpeg_sizeimage(&tmp_q);
+
+	/* adjust user format according to our calculations */
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		pfmt = &pix_mp->plane_fmt[i];
+		memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+		pfmt->bytesperline = tmp_q.bytesperline[i];
+		pfmt->sizeimage = tmp_q.sizeimage[i];
+	}
+
+	return 0;
+}
+static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	struct device *dev = jpeg->dev;
+	struct mxc_jpeg_fmt *fmt;
+	u32 fourcc = f->fmt.pix_mp.pixelformat;
+
+	int q_type = (ctx->mode == MXC_JPEG_DECODE) ?
+		     MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
+
+	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
+		dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type);
+		return -EINVAL;
+	}
+
+	fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
+	if (!fmt || (fmt->flags != q_type)) {
+		char *format_name = fourcc_to_str(fourcc);
+
+		dev_warn(dev, "Format not supported: %s, use the default.\n",
+			 format_name);
+		kfree(format_name);
+		f->fmt.pix_mp.pixelformat = (ctx->mode == MXC_JPEG_DECODE) ?
+				MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG;
+		fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
+	}
+	return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
+}
+static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	struct device *dev = jpeg->dev;
+	struct mxc_jpeg_fmt *fmt;
+	u32 fourcc = f->fmt.pix_mp.pixelformat;
+
+	int q_type = (ctx->mode == MXC_JPEG_ENCODE) ?
+		     MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
+
+	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
+		dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type);
+		return -EINVAL;
+	}
+
+	fmt = mxc_jpeg_find_format(ctx, fourcc);
+	if (!fmt || (fmt->flags != q_type)) {
+		char *format_name = fourcc_to_str(fourcc);
+
+		dev_warn(dev, "Format not supported: %s, use the default.\n",
+			 format_name);
+		kfree(format_name);
+		f->fmt.pix_mp.pixelformat = (ctx->mode == MXC_JPEG_ENCODE) ?
+				MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG;
+		fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
+	}
+	return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
+}
+static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
+			  struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct mxc_jpeg_q_data *q_data = NULL;
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	int i;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = mxc_jpeg_get_q_data(ctx, f->type);
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
+		return -EBUSY;
+	}
+
+	q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat);
+	q_data->w = pix_mp->width;
+	q_data->h = pix_mp->height;
+
+	q_data->w_adjusted = q_data->w;
+	q_data->h_adjusted = q_data->h;
+	if (ctx->mode == MXC_JPEG_DECODE) {
+		/*
+		 * align up the resolution for CAST IP,
+		 * but leave the buffer resolution unchanged
+		 * TODO check if CAST IP will write past the buffer
+		 */
+		v4l_bound_align_image(&q_data->w_adjusted,
+				      q_data->w_adjusted,  /* adjust upwards */
+				      MXC_JPEG_MAX_WIDTH,
+				      q_data->fmt->h_align,
+				      &q_data->h_adjusted,
+				      q_data->h_adjusted, /* adjust upwards */
+				      MXC_JPEG_MAX_HEIGHT,
+				      q_data->fmt->v_align,
+				      0);
+	} else {
+		/*
+		 * align down the resolution for CAST IP,
+		 * but leave the buffer resolution unchanged
+		 */
+		v4l_bound_align_image(&q_data->w_adjusted,
+				      MXC_JPEG_MIN_WIDTH,
+				      q_data->w_adjusted, /* adjust downwards*/
+				      q_data->fmt->h_align,
+				      &q_data->h_adjusted,
+				      MXC_JPEG_MIN_HEIGHT,
+				      q_data->h_adjusted, /* adjust downwards*/
+				      q_data->fmt->v_align,
+				      0);
+	}
+
+	ctx->colorspace = pix_mp->colorspace;
+	ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+	ctx->xfer_func = pix_mp->xfer_func;
+	ctx->quantization = pix_mp->quantization;
+
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
+		q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+	}
+
+	return 0;
+}
+static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = mxc_jpeg_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+}
+static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = mxc_jpeg_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+}
+
+static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv,
+			      struct v4l2_format *f)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	struct device *dev = jpeg->dev;
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+	struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);
+	int i;
+
+	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
+		dev_err(dev, "G_FMT with Invalid type: %d\n", f->type);
+		return -EINVAL;
+	}
+
+	pix_mp->pixelformat = q_data->fmt->fourcc;
+	pix_mp->width = q_data->w;
+	pix_mp->height = q_data->h;
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->colorspace = ctx->colorspace;
+	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+	pix_mp->xfer_func = ctx->xfer_func;
+	pix_mp->quantization = ctx->quantization;
+	pix_mp->num_planes = q_data->fmt->colplanes;
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+		pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+	}
+
+	return 0;
+}
+
+static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mxc_jpeg_qbuf(struct file *file, void *priv,
+			 struct v4l2_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+	struct device *dev = ctx->mxc_jpeg->dev;
+	struct vb2_queue *vq;
+
+	dev_dbg(dev, "QBUF type=%d, index=%d", buf->type, buf->index);
+	vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
+	if (buf->index >= vq->num_buffers) {
+		dev_err(dev, "buffer index out of range\n");
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+
+static int mxc_jpeg_dqbuf(struct file *file, void *priv,
+			  struct v4l2_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+	struct device *dev = ctx->mxc_jpeg->dev;
+	int num_src_ready = v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx);
+	int ret;
+
+	dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index);
+	if (ctx->stopping == 1	&& num_src_ready == 0) {
+		/* No more src bufs, notify app EOS */
+		notify_eos(ctx);
+		ctx->stopping = 0;
+	}
+
+	ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
+	buf->field = V4L2_FIELD_NONE;
+
+	return ret;
+}
+static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
+	.vidioc_querycap		= mxc_jpeg_querycap,
+	.vidioc_enum_fmt_vid_cap	= mxc_jpeg_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out	= mxc_jpeg_enum_fmt_vid_out,
+
+	.vidioc_try_fmt_vid_cap_mplane		= mxc_jpeg_try_fmt_vid_cap,
+	.vidioc_try_fmt_vid_out_mplane		= mxc_jpeg_try_fmt_vid_out,
+
+	.vidioc_s_fmt_vid_cap_mplane		= mxc_jpeg_s_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out_mplane		= mxc_jpeg_s_fmt_vid_out,
+
+	.vidioc_g_fmt_vid_cap_mplane		= mxc_jpeg_g_fmt_vid,
+	.vidioc_g_fmt_vid_out_mplane		= mxc_jpeg_g_fmt_vid,
+
+	.vidioc_subscribe_event		= mxc_jpeg_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+	.vidioc_try_decoder_cmd		= mxc_jpeg_try_decoder_cmd,
+	.vidioc_decoder_cmd		= mxc_jpeg_decoder_cmd,
+	.vidioc_try_encoder_cmd		= mxc_jpeg_try_encoder_cmd,
+	.vidioc_encoder_cmd		= mxc_jpeg_encoder_cmd,
+
+	.vidioc_qbuf			= mxc_jpeg_qbuf,
+	.vidioc_dqbuf                   = mxc_jpeg_dqbuf,
+
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+	.vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
+	.vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
+};
+
+static int mxc_jpeg_release(struct file *file)
+{
+	struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data);
+	struct device *dev = mxc_jpeg->dev;
+
+	mutex_lock(&mxc_jpeg->lock);
+	if (mxc_jpeg->mode == MXC_JPEG_DECODE)
+		dev_dbg(dev, "Release JPEG decoder instance on slot %d.",
+			ctx->slot);
+	else
+		dev_dbg(dev, "Release JPEG encoder instance on slot %d.",
+			ctx->slot);
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	mutex_unlock(&mxc_jpeg->lock);
+
+	pm_runtime_put_sync(mxc_jpeg->dev);
+	return 0;
+}
+
+static const struct v4l2_file_operations mxc_jpeg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mxc_jpeg_open,
+	.release	= mxc_jpeg_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+static struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
+	.device_run	= mxc_jpeg_device_run,
+	.job_ready	= mxc_jpeg_job_ready,
+	.job_abort	= mxc_jpeg_job_abort,
+};
+
+static void mxc_jpeg_detach_pm_domains(struct mxc_jpeg_dev *jpeg)
+{
+	int i;
+
+	for (i = 0; i < MXC_JPEG_NUM_PD; i++) {
+		if (jpeg->pd_link[i] && !IS_ERR(jpeg->pd_link[i]))
+			device_link_del(jpeg->pd_link[i]);
+		if (jpeg->pd_dev[i] && !IS_ERR(jpeg->pd_dev[i]))
+			dev_pm_domain_detach(jpeg->pd_dev[i], true);
+		jpeg->pd_dev[i] = NULL;
+		jpeg->pd_link[i] = NULL;
+	}
+}
+
+static int mxc_jpeg_attach_pm_domains(struct mxc_jpeg_dev *jpeg)
+{
+	struct device *dev = jpeg->dev;
+	struct device_node *np = jpeg->pdev->dev.of_node;
+	int i, num_domains;
+	int ret;
+
+	num_domains = of_count_phandle_with_args(np, "power-domains",
+						 "#power-domain-cells");
+	if (num_domains != MXC_JPEG_NUM_PD) {
+		dev_err(dev, "Expecting %d power domains, got %d\n",
+			MXC_JPEG_NUM_PD, num_domains);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MXC_JPEG_NUM_PD; i++) {
+		jpeg->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
+		if (IS_ERR(jpeg->pd_dev[i])) {
+			ret = PTR_ERR(jpeg->pd_dev[i]);
+			goto fail;
+		}
+
+		jpeg->pd_link[i] = device_link_add(dev, jpeg->pd_dev[i],
+			DL_FLAG_STATELESS |
+			DL_FLAG_PM_RUNTIME |
+			DL_FLAG_RPM_ACTIVE);
+		if (IS_ERR(jpeg->pd_link[i])) {
+			ret = PTR_ERR(jpeg->pd_link[i]);
+			goto fail;
+		}
+	}
+
+	return 0;
+fail:
+	mxc_jpeg_detach_pm_domains(jpeg);
+	return ret;
+}
+
+static int mxc_jpeg_probe(struct platform_device *pdev)
+{
+	struct mxc_jpeg_dev *jpeg;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int dec_irq;
+	int ret;
+	int mode;
+	const struct of_device_id *of_id;
+	unsigned int slot;
+
+	of_id = of_match_node(mxc_jpeg_match, dev->of_node);
+	mode = (int)(u64) of_id->data;
+
+	jpeg = devm_kzalloc(dev, sizeof(struct mxc_jpeg_dev), GFP_KERNEL);
+	if (!jpeg)
+		return -ENOMEM;
+
+	mutex_init(&jpeg->lock);
+	spin_lock_init(&jpeg->hw_lock);
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(&pdev->dev, "No suitable DMA available.\n");
+		goto err_irq;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	jpeg->base_reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(jpeg->base_reg))
+		return PTR_ERR(jpeg->base_reg);
+
+	for (slot = 0; slot < MXC_MAX_SLOTS; slot++) {
+		dec_irq = platform_get_irq(pdev, slot);
+		if (dec_irq < 0) {
+			dev_err(&pdev->dev, "Failed to get irq %d\n", dec_irq);
+			ret = dec_irq;
+			goto err_irq;
+		}
+		ret = devm_request_irq(&pdev->dev, dec_irq, mxc_jpeg_dec_irq,
+				       0, pdev->name, jpeg);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request irq %d (%d)\n",
+				dec_irq, ret);
+			goto err_irq;
+		}
+	}
+
+	jpeg->pdev = pdev;
+	jpeg->dev = dev;
+	jpeg->mode = mode;
+
+	/* Start clock */
+	jpeg->clk_ipg = devm_clk_get(dev, "ipg");
+	if (IS_ERR(jpeg->clk_ipg)) {
+		dev_err(dev, "failed to get clock: ipg\n");
+		goto err_clk;
+	}
+
+	jpeg->clk_per = devm_clk_get(dev, "per");
+	if (IS_ERR(jpeg->clk_per)) {
+		dev_err(dev, "failed to get clock: per\n");
+		goto err_clk;
+	}
+
+	ret = mxc_jpeg_attach_pm_domains(jpeg);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach power domains %d\n", ret);
+		return ret;
+	}
+
+	/* v4l2 */
+	ret = v4l2_device_register(dev, &jpeg->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "failed to register v4l2 device\n");
+		goto err_register;
+	}
+	jpeg->m2m_dev = v4l2_m2m_init(&mxc_jpeg_m2m_ops);
+	if (IS_ERR(jpeg->m2m_dev)) {
+		dev_err(dev, "failed to register v4l2 device\n");
+		goto err_m2m;
+	}
+
+	jpeg->dec_vdev = video_device_alloc();
+	if (!jpeg->dec_vdev) {
+		dev_err(dev, "failed to register v4l2 device\n");
+		goto err_vdev_alloc;
+	}
+	if (mode == MXC_JPEG_ENCODE)
+		snprintf(jpeg->dec_vdev->name,
+				sizeof(jpeg->dec_vdev->name),
+				"%s-enc", MXC_JPEG_M2M_NAME);
+	else
+		snprintf(jpeg->dec_vdev->name,
+				sizeof(jpeg->dec_vdev->name),
+				"%s-dec", MXC_JPEG_M2M_NAME);
+
+	jpeg->dec_vdev->fops = &mxc_jpeg_fops;
+	jpeg->dec_vdev->ioctl_ops = &mxc_jpeg_ioctl_ops;
+	jpeg->dec_vdev->minor = -1;
+	jpeg->dec_vdev->release = video_device_release;
+	jpeg->dec_vdev->lock = &jpeg->lock; /* lock for ioctl serialization*/
+	jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
+	jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
+	jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
+					V4L2_CAP_VIDEO_M2M_MPLANE;
+
+	ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		dev_err(dev, "failed to register video device\n");
+		goto err_vdev_register;
+	}
+	video_set_drvdata(jpeg->dec_vdev, jpeg);
+	if (mode == MXC_JPEG_ENCODE)
+		v4l2_info(&jpeg->v4l2_dev,
+			"encoder device registered as /dev/video%d (%d,%d)\n",
+			jpeg->dec_vdev->num, VIDEO_MAJOR,
+			jpeg->dec_vdev->minor);
+	else
+		v4l2_info(&jpeg->v4l2_dev,
+			"decoder device registered as /dev/video%d (%d,%d)\n",
+			jpeg->dec_vdev->num, VIDEO_MAJOR,
+			jpeg->dec_vdev->minor);
+
+	platform_set_drvdata(pdev, jpeg);
+	pm_runtime_enable(dev);
+	return 0;
+
+err_vdev_register:
+	video_device_release(jpeg->dec_vdev);
+
+err_vdev_alloc:
+	v4l2_m2m_release(jpeg->m2m_dev);
+
+err_m2m:
+	v4l2_device_unregister(&jpeg->v4l2_dev);
+
+err_register:
+err_irq:
+err_clk:
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int mxc_jpeg_runtime_resume(struct device *dev)
+{
+	struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(jpeg->clk_ipg);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable clock: ipg\n");
+		goto err_clk;
+	}
+
+	ret = clk_prepare_enable(jpeg->clk_per);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable clock: per\n");
+		goto err_clk;
+	}
+
+	return 0;
+
+err_clk:
+	return ret;
+}
+
+static int mxc_jpeg_runtime_suspend(struct device *dev)
+{
+	struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(jpeg->clk_ipg);
+	clk_disable_unprepare(jpeg->clk_per);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops	mxc_jpeg_pm_ops = {
+	SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend,
+			   mxc_jpeg_runtime_resume, NULL)
+};
+
+static int mxc_jpeg_remove(struct platform_device *pdev)
+{
+	unsigned int slot;
+	struct mxc_jpeg_dev *jpeg = platform_get_drvdata(pdev);
+
+	for (slot = 0; slot < MXC_MAX_SLOTS; slot++)
+		mxc_jpeg_free_slot_data(jpeg, slot);
+
+	pm_runtime_disable(&pdev->dev);
+	video_unregister_device(jpeg->dec_vdev);
+	video_device_release(jpeg->dec_vdev);
+	v4l2_m2m_release(jpeg->m2m_dev);
+	v4l2_device_unregister(&jpeg->v4l2_dev);
+	mxc_jpeg_detach_pm_domains(jpeg);
+
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(of, mxc_jpeg_match);
+
+static struct platform_driver mxc_jpeg_driver = {
+	.probe = mxc_jpeg_probe,
+	.remove = mxc_jpeg_remove,
+	.driver = {
+		.name = "mxc-jpeg",
+		.of_match_table = mxc_jpeg_match,
+		.pm = &mxc_jpeg_pm_ops,
+	},
+};
+module_platform_driver(mxc_jpeg_driver);
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-jpeg.h
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-jpeg.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+
+#ifndef _MXC_JPEG_CORE_H
+#define _MXC_JPEG_CORE_H
+
+#define MXC_JPEG_M2M_NAME		"mxc-jpeg"
+#define MXC_JPEG_NAME			"mxc-jpeg"
+#define MXC_IN_FORMAT			0
+#define MXC_OUT_FORMAT			1
+#define MXC_JPEG_FMT_TYPE_ENC		0
+#define MXC_JPEG_FMT_TYPE_RAW		1
+#define MXC_JPEG_DEFAULT_WIDTH		1280
+#define MXC_JPEG_DEFAULT_HEIGHT		720
+#define MXC_JPEG_DEFAULT_PFMT		V4L2_PIX_FMT_RGB24
+#define MXC_JPEG_MIN_WIDTH		64
+#define MXC_JPEG_MIN_HEIGHT		64
+#define MXC_JPEG_MAX_WIDTH		0x2000
+#define MXC_JPEG_MAX_HEIGHT		0x2000
+#define MXC_JPEG_MAX_CFG_STREAM		0x1000
+#define MXC_JPEG_H_ALIGN		3
+#define MXC_JPEG_W_ALIGN		3
+#define MXC_JPEG_DEFAULT_SIZEIMAGE	(6 * MXC_JPEG_DEFAULT_WIDTH * \
+					 MXC_JPEG_DEFAULT_HEIGHT)
+#define MXC_JPEG_MAX_SIZEIMAGE		0xFFFFFC00
+#define MXC_JPEG_ENC_CONF		1
+#define MXC_JPEG_ENC_DONE		0
+#define SOF0				0xC0
+#define SOF1				0xC1
+#define SOF2				0xC2
+#define SOS				0xDA
+#define DHT				0xC4
+#define APP14				0xEE
+#define MXC_JPEG_ENC_CONF_DONE		1
+#define MXC_JPEG_MAX_PLANES		2
+#define MXC_JPEG_NUM_PD			6
+
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @name:	format description
+ * @fourcc:	fourcc code, 0 if not applicable
+ * @depth:	number of bits per pixel
+ * @colplanes:	number of color planes (1 for packed formats)
+ * @h_align:	horizontal alignment order (align to 2^h_align)
+ * @v_align:	vertical alignment order (align to 2^v_align)
+ * @flags:	flags describing format applicability
+ */
+struct mxc_jpeg_fmt {
+	char	*name;
+	u32	fourcc;
+	int	depth;
+	int	colplanes;
+	int	memplanes;
+	int	h_align;
+	int	v_align;
+	int	subsampling;
+	u32	flags;
+};
+struct mxc_jpeg_desc {
+	u32 next_descpt_ptr;
+	u32 buf_base0;
+	u32 buf_base1;
+	u32 line_pitch;
+	u32 stm_bufbase;
+	u32 stm_bufsize;
+	u32 imgsize;
+	u32 stm_ctrl;
+} __packed;
+
+struct mxc_jpeg_q_data {
+	struct mxc_jpeg_fmt	*fmt;
+	u32			sizeimage[MXC_JPEG_MAX_PLANES];
+	u32			bytesperline[MXC_JPEG_MAX_PLANES];
+	int w;
+	int w_adjusted;
+	int h;
+	int h_adjusted;
+};
+struct mxc_jpeg_ctx {
+	struct mxc_jpeg_dev		*mxc_jpeg;
+	struct mxc_jpeg_q_data		out_q;
+	struct mxc_jpeg_q_data		cap_q;
+	struct v4l2_rect		crop_rect;
+	unsigned long			state;
+	struct v4l2_fh			fh;
+	unsigned int			mode;
+	unsigned int			enc_state;
+	unsigned int			aborting;
+	unsigned int			stopping;
+	unsigned int			dht_needed;
+	unsigned int			slot;
+	enum v4l2_colorspace colorspace;
+	enum v4l2_ycbcr_encoding ycbcr_enc;
+	enum v4l2_quantization quantization;
+	enum v4l2_xfer_func xfer_func;
+};
+
+struct mxc_jpeg_slot_data {
+	bool used;
+	struct mxc_jpeg_desc *desc; // enc/dec descriptor
+	struct mxc_jpeg_desc *cfg_desc; // configuration descriptor
+	void *cfg_stream_vaddr; // configuration bitstream virtual address
+	unsigned int cfg_stream_size;
+	int flags;
+	dma_addr_t desc_handle;
+	dma_addr_t cfg_desc_handle; // configuration descriptor dma address
+	dma_addr_t cfg_stream_handle; // configuration bitstream dma address
+};
+
+struct mxc_jpeg_dev {
+	spinlock_t			hw_lock;
+	unsigned int			mode;
+	struct mutex			lock;
+	bool				enc;
+	bool				dec;
+	struct clk			*clk_ipg;
+	struct clk			*clk_per;
+	struct platform_device		*pdev;
+	struct device			*dev;
+	void __iomem			*base_reg;
+	void __iomem			*enc_reg;
+	struct v4l2_device		v4l2_dev;
+	struct v4l2_m2m_dev		*m2m_dev;
+	struct video_device		*dec_vdev;
+	unsigned int			irq;
+	int				id;
+	struct mxc_jpeg_slot_data	slot_data[MXC_MAX_SLOTS];
+	struct device			*pd_dev[MXC_JPEG_NUM_PD];
+	struct device_link		*pd_link[MXC_JPEG_NUM_PD];
+};
+
+#define MXC_JPEG_MAX_COMPONENTS 4
+/* JPEG Start Of Frame marker fields*/
+struct mxc_jpeg_sof_comp {
+	u8 id; /*component id*/
+	u8 v :4; /* vertical sampling*/
+	u8 h :4; /* horizontal sampling*/
+	u8 quantization_table_no;
+} __packed;
+
+struct mxc_jpeg_sof {
+	u16 length;
+	u8 precision;
+	u16 height, width;
+	u8 components_no;
+	struct mxc_jpeg_sof_comp comp[MXC_JPEG_MAX_COMPONENTS];
+} __packed;
+
+/* JPEG Start Of Scan marker fields*/
+struct mxc_jpeg_sos_comp {
+	u8 id; /*component id*/
+	u8 huffman_table_no;
+} __packed;
+struct mxc_jpeg_sos {
+	u16 length;
+	u8 components_no;
+	struct mxc_jpeg_sos_comp comp[MXC_JPEG_MAX_COMPONENTS];
+	u8 ignorable_bytes[3];
+} __packed;
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-mipi-csi2.h
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-mipi-csi2.h
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2017 NXP
+ */
+
+#ifndef MXC_MIPI_CSI2_H_
+#define MXC_MIPI_CSI2_H_
+
+#include <media/v4l2-device.h>
+
+#define MXC_MIPI_CSI2_DRIVER_NAME	"mxc-mipi-csi2"
+#define MXC_MIPI_CSI2_SUBDEV_NAME	MXC_MIPI_CSI2_DRIVER_NAME
+#define MXC_MIPI_CSI2_MAX_DEVS		2
+#define MXC_MIPI_CSI2_MAX_LANES		4
+
+#define MIPI_CSI2_OF_NODE_NAME	"csi"
+
+#define MXC_MIPI_CSI2_VC0_PAD_SINK		0
+#define MXC_MIPI_CSI2_VC1_PAD_SINK		1
+#define MXC_MIPI_CSI2_VC2_PAD_SINK		2
+#define MXC_MIPI_CSI2_VC3_PAD_SINK		3
+
+#define MXC_MIPI_CSI2_VC0_PAD_SOURCE	4
+#define MXC_MIPI_CSI2_VC1_PAD_SOURCE	5
+#define MXC_MIPI_CSI2_VC2_PAD_SOURCE	6
+#define MXC_MIPI_CSI2_VC3_PAD_SOURCE	7
+#define MXC_MIPI_CSI2_VCX_PADS_NUM		8
+
+/* Subsystem CSR */
+#define CSI2SS_BASE_OFFSET					0x0
+
+#define CSI2SS_PLM_CTRL						(CSI2SS_BASE_OFFSET + 0x0)
+#define CSI2SS_PLM_CTRL_PL_CLK_RUN			0x80000000
+#define CSI2SS_PLM_CTRL_VSYNC_OVERRIDE		0x200
+#define CSI2SS_PLM_CTRL_HSYNC_OVERRIDE		0x400
+#define CSI2SS_PLM_CTRL_VALID_OVERRIDE		0x800
+#define CSI2SS_PLM_CTRL_POLARITY_MASK		0x1000
+#define CSI2SS_PLM_CTRL_POLARITY_HIGH		0x1000
+#define CSI2SS_PLM_CTRL_POLARITY_LOW		0x0
+#define CSI2SS_PLM_CTRL_ENABLE_PL			1
+#define CSI2SS_PLM_CTRL_ENABLE_PL_OFFSET	0
+#define CSI2SS_PLM_CTRL_ENABLE_PL_MASK		1
+
+#define CSI2SS_PHY_CTRL						(CSI2SS_BASE_OFFSET + 0x4)
+#define CSI2SS_PHY_CTRL_PD					1
+#define CSI2SS_PHY_CTRL_PD_OFFSET			22
+#define CSI2SS_PHY_CTRL_PD_MASK				0x400000
+#define CSI2SS_PHY_CTRL_RTERM_SEL			1
+#define CSI2SS_PHY_CTRL_RTERM_SEL_OFFSET	21
+#define CSI2SS_PHY_CTRL_RTERM_SEL_MASK		0x200000
+#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_OFFSET	4
+#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK	0x3F0
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE		1
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE_OFFSET	3
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE_MASK	0x8
+#define CSI2SS_PHY_CTRL_DDRCLK_EN			1
+#define CSI2SS_PHY_CTRL_DDRCLK_EN_OFFSET	2
+#define CSI2SS_PHY_CTRL_DDRCLK_EN_MASK		0x4
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN			1
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN_OFFSET	1
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN_MASK		0x2
+#define CSI2SS_PHY_CTRL_RX_ENABLE			1
+#define CSI2SS_PHY_CTRL_RX_ENABLE_OFFSET	0
+#define CSI2SS_PHY_CTRL_RX_ENABLE_MASK		0x1
+
+#define CSI2SS_PHY_STATUS					(CSI2SS_BASE_OFFSET + 0x8)
+#define CSI2SS_PHY_TEST_STATUS				(CSI2SS_BASE_OFFSET + 0x10)
+#define CSI2SS_PHY_TEST_STATUS_D0			(CSI2SS_BASE_OFFSET + 0x14)
+#define CSI2SS_PHY_TEST_STATUS_D1			(CSI2SS_BASE_OFFSET + 0x18)
+#define CSI2SS_PHY_TEST_STATUS_D2			(CSI2SS_BASE_OFFSET + 0x1C)
+#define CSI2SS_PHY_TEST_STATUS_D3			(CSI2SS_BASE_OFFSET + 0x20)
+
+#define CSI2SS_VC_INTERLACED				(CSI2SS_BASE_OFFSET + 0x30)
+#define CSI2SS_VC_INTERLACED_VC0			1
+#define CSI2SS_VC_INTERLACED_VC1			2
+#define CSI2SS_VC_INTERLACED_VC2			4
+#define CSI2SS_VC_INTERLACED_VC3			8
+#define CSI2SS_VC_INTERLACED_OFFSET			0
+#define CSI2SS_VC_INTERLACED_MASK			0xF
+
+#define CSI2SS_DATA_TYPE						(CSI2SS_BASE_OFFSET + 0x38)
+#define CSI2SS_DATA_TYPE_LEGACY_YUV420_8BIT		(1 << 2)
+#define CSI2SS_DATA_TYPE_YUV422_8BIT       		(1 << 6)
+#define CSI2SS_DATA_TYPE_YUV422_10BIT      		(1 << 7)
+#define CSI2SS_DATA_TYPE_RGB444					(1 << 8)
+#define CSI2SS_DATA_TYPE_RGB555					(1 << 9)
+#define CSI2SS_DATA_TYPE_RGB565					(1 << 10)
+#define CSI2SS_DATA_TYPE_RGB666					(1 << 11)
+#define CSI2SS_DATA_TYPE_RGB888					(1 << 12)
+#define CSI2SS_DATA_TYPE_RAW6					(1 << 16)
+#define CSI2SS_DATA_TYPE_RAW8					(1 << 18)
+#define CSI2SS_DATA_TYPE_RAW10					(1 << 19)
+#define CSI2SS_DATA_TYPE_RAW12					(1 << 20)
+#define CSI2SS_DATA_TYPE_RAW14					(1 << 21)
+
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE		(CSI2SS_BASE_OFFSET + 0x40)
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_ODD	0
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_EVEN	1
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_OFFSET	0
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_MASK	1
+
+#define CSI2SS_CTRL_CLK_RESET					(CSI2SS_BASE_OFFSET + 0x44)
+#define CSI2SS_CTRL_CLK_RESET_EN				1
+#define CSI2SS_CTRL_CLK_RESET_OFFSET			0
+#define CSI2SS_CTRL_CLK_RESET_MASK				1
+#define CSI2SS_CTRL_CLK_RESET_CLK_OFF			1
+#define CSI2SS_CTRL_CLK_RESET_CLK_OFFSET		1
+#define CSI2SS_CTRL_CLK_RESET_CLK_MASK			0x1
+
+#define CSI2SS_STREAM_FENCE_CTRL				(CSI2SS_BASE_OFFSET + 0x48)
+#define CSI2SS_STREAM_FENCE_VC0					1
+#define CSI2SS_STREAM_FENCE_VC1					2
+#define CSI2SS_STREAM_FENCE_VC2					4
+#define CSI2SS_STREAM_FENCE_VC3					8
+#define CSI2SS_STREAM_FENCE_CTRL_OFFSET			0
+#define CSI2SS_STREAM_FENCE_CTRL_MASK			0xF
+
+#define CSI2SS_STREAM_FENCE_STATUS				(CSI2SS_BASE_OFFSET + 0x4C)
+
+/* CSI-2 controller CSR */
+#define CSI2RX_BASE_OFFSET						(0x100)
+
+#define CSI2RX_CFG_NUM_LANES					(CSI2RX_BASE_OFFSET + 0x0)
+#define CSI2RX_CFG_NUM_LANES_OFFSET				0
+#define CSI2RX_CFG_NUM_LANES_MASK				0x3
+
+#define CSI2RX_CFG_DISABLE_DATA_LANES			(CSI2RX_BASE_OFFSET + 0x4)
+#define CSI2RX_CFG_DISABLE_DATA_LANES_3			8
+#define CSI2RX_CFG_DISABLE_DATA_LANES_2			4
+#define CSI2RX_CFG_DISABLE_DATA_LANES_1			2
+#define CSI2RX_CFG_DISABLE_DATA_LANES_0			1
+#define CSI2RX_CFG_DISABLE_DATA_LANES_OFFSET	0
+#define CSI2RX_CFG_DISABLE_DATA_LANES_MASK		0xF
+
+#define CSI2RX_BIT_ERR								(CSI2RX_BASE_OFFSET + 0x8)
+
+#define CSI2RX_IRQ_STATUS							(CSI2RX_BASE_OFFSET + 0xC)
+#define CSI2RX_IRQ_STATUS_CRC_ERROR					0x1
+#define CSI2RX_IRQ_STATUS_1BIT_CRC_ERROR			0x2
+#define CSI2RX_IRQ_STATUS_2BIT_CRC_ERROR			0x4
+#define CSI2RX_IRQ_STATUS_ULPS_CHANGE				0x8
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSOTHS				0x10
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSOTSYNC_HS		0x20
+#define CSI2RX_IRQ_STATUS_DPHY_ERRESC				0x40
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSYNCESC			0x80
+#define CSI2RX_IRQ_STATUS_DPHY_ERRCTRL				0x100
+
+#define CSI2RX_IRQ_MASK								(CSI2RX_BASE_OFFSET + 0x10)
+#define CSI2RX_IRQ_MASK_CRC_ERROR					0x1
+#define CSI2RX_IRQ_MASK_1BIT_CRC_ERROR				0x2
+#define CSI2RX_IRQ_MASK_2BIT_CRC_ERROR				0x4
+#define CSI2RX_IRQ_MASK_ULPS_CHANGE					0x8
+#define CSI2RX_IRQ_MASK_DPHY_ERRSOTHS				0x10
+#define CSI2RX_IRQ_MASK_DPHY_ERRSOTSYNC_HS			0x20
+#define CSI2RX_IRQ_MASK_DPHY_ERRESC					0x40
+#define CSI2RX_IRQ_MASK_DPHY_ERRSYNCESC				0x80
+#define CSI2RX_IRQ_MASK_DPHY_ERRCTRL				0x100
+
+#define CSI2RX_ULPS_STATUS							(CSI2RX_BASE_OFFSET + 0x14)
+#define CSI2RX_ULPS_STATUS_CLK_LANE_ULPS			0x1
+#define CSI2RX_ULPS_STATUS_DAT_LANE0_ULPS			0x2
+#define CSI2RX_ULPS_STATUS_DAT_LANE1_ULPS			0x4
+#define CSI2RX_ULPS_STATUS_DAT_LANE2_ULPS			0x8
+#define CSI2RX_ULPS_STATUS_DAT_LANE3_ULPS			0x10
+#define CSI2RX_ULPS_STATUS_CLK_LANE_MARK			0x20
+#define CSI2RX_ULPS_STATUS_DAT_LANE0_MARK			0x40
+#define CSI2RX_ULPS_STATUS_DAT_LANE1_MARK			0x80
+#define CSI2RX_ULPS_STATUS_DAT_LANE2_MARK			0x100
+#define CSI2RX_ULPS_STATUS_DAT_LANE3_MARK			0x200
+
+#define CSI2RX_PPI_ERRSOT_HS						(CSI2RX_BASE_OFFSET + 0x18)
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE0				0x1
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE1				0x2
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE2				0x4
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE3				0x8
+
+#define CSI2RX_PPI_ERRSOTSYNC_HS					(CSI2RX_BASE_OFFSET + 0x1C)
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE0			0x1
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE1			0x2
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE2			0x4
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE3			0x8
+
+#define CSI2RX_PPI_ERRESC				   		 	(CSI2RX_BASE_OFFSET + 0x20)
+#define CSI2RX_PPI_ERRESC_DAT_LANE0		   		 	0x1
+#define CSI2RX_PPI_ERRESC_DAT_LANE1		   		 	0x2
+#define CSI2RX_PPI_ERRESC_DAT_LANE2		   		 	0x4
+#define CSI2RX_PPI_ERRESC_DAT_LANE3		   		 	0x8
+
+#define CSI2RX_PPI_ERRSYNCESC			   		 	(CSI2RX_BASE_OFFSET + 0x24)
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE0	   		 	0x1
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE1	   		 	0x2
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE2	   		 	0x4
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE3	   		 	0x8
+
+#define CSI2RX_PPI_ERRCONTROL			   		 	(CSI2RX_BASE_OFFSET + 0x28)
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE0	   		 	0x1
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE1	   		 	0x2
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE2	   		 	0x4
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE3	   		 	0x8
+
+#define CSI2RX_CFG_DISABLE_PAYLOAD_0							(CSI2RX_BASE_OFFSET + 0x2C)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_LEGACY_YUV420_8BIT		(1 << 10)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_YUV422_8BIT				(1 << 14)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_YUV422_10BIT			(1 << 15)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB444					(1 << 16)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB555					(1 << 17)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB565					(1 << 18)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB666					(1 << 19)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB888					(1 << 20)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW6					(1 << 24)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW7					(1 << 25)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW8					(1 << 26)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW10					(1 << 27)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW12					(1 << 28)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW14					(1 << 29)
+
+#define CSI2RX_CFG_DISABLE_PAYLOAD_1	(CSI2RX_BASE_OFFSET + 0x30)
+
+struct csis_hw_reset {
+	struct regmap *src;
+	u8 req_src;
+	u8 rst_val;
+};
+struct csis_phy_gpr {
+	struct regmap *gpr;
+	u8 req_src;
+};
+
+struct mxc_mipi_csi2_dev {
+	struct v4l2_device		v4l2_dev;
+	struct v4l2_subdev		sd;
+	struct v4l2_subdev		*sensor_sd;
+
+	struct media_pad pads[MXC_MIPI_CSI2_VCX_PADS_NUM];
+	struct v4l2_mbus_framefmt format;
+
+	void __iomem *csr_regs;
+	void __iomem *base_regs;
+	struct platform_device *pdev;
+	u32 flags;
+	int irq;
+
+	struct clk *clk_apb;
+	struct clk *clk_core;
+	struct clk *clk_esc;
+	struct clk *clk_pxl;
+
+	struct csis_hw_reset		hw_reset;
+	struct csis_phy_gpr		phy_gpr;
+
+	struct v4l2_async_subdev	asd;
+	struct v4l2_async_notifier	subdev_notifier;
+	struct v4l2_async_subdev	*async_subdevs[2];
+
+	struct mutex lock;
+
+	int	 id;
+	u32 hs_settle;
+	u32 send_level;
+	u32 num_lanes;
+	u8 data_lanes[4];
+	u8 vchannel;
+	u8 running;
+};
+
+enum mxc_mipi_csi2_pm_state {
+	MXC_MIPI_CSI2_PM_POWERED	= 0x1,
+	MXC_MIPI_CSI2_PM_SUSPENDED	= 0x2,
+	MXC_MIPI_CSI2_RUNTIME_SUSPENDED	= 0x4,
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c
+++ linux-ein-5.4.0/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c
@@ -0,0 +1,734 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2017 NXP
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+#include "mxc-mipi-csi2.h"
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define MXC_MIPI_CSI2_YAV_DRIVER_NAME	"mxc-mipi-csi2_yav"
+#define MXC_MIPI_CSI2_YAV_SUBDEV_NAME	MXC_MIPI_CSI2_DRIVER_NAME
+
+#define	GPR_CSI2_1_RX_ENABLE		BIT(13)
+#define	GPR_CSI2_1_VID_INTFC_ENB	BIT(12)
+#define	GPR_CSI2_1_PD_RX 		BIT(11)
+#define	GPR_CSI2_1_HSEL			BIT(10)
+#define	GPR_CSI2_1_AUTO_PD_EN 		BIT(9)
+#define	GPR_CSI2_1_CONT_CLK_MODE 	BIT(8)
+#define	GPR_CSI2_1_S_PRG_RXHS_SETTLE(x)	(((x) & 0x3F) << 2)
+#define	GPR_CSI2_1_RX_RCAL		(3)
+
+static u8 rxhs_settle[2] = { 0x14, 0x9 };
+
+static struct mxc_mipi_csi2_dev *sd_to_mxc_mipi_csi2_dev(struct v4l2_subdev
+							 *sdev)
+{
+	return container_of(sdev, struct mxc_mipi_csi2_dev, sd);
+}
+
+#ifdef debug
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	printk("MIPI CSI2 HC register dump, mipi csi%d\n", csi2dev->id);
+	printk("MIPI CSI2 HC num of lanes     0x100 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x100));
+	printk("MIPI CSI2 HC dis lanes        0x104 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x104));
+	printk("MIPI CSI2 HC BIT ERR          0x108 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x108));
+	printk("MIPI CSI2 HC IRQ STATUS       0x10C = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x10C));
+	printk("MIPI CSI2 HC IRQ MASK         0x110 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x110));
+	printk("MIPI CSI2 HC ULPS STATUS      0x114 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x114));
+	printk("MIPI CSI2 HC DPHY ErrSotHS    0x118 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x118));
+	printk("MIPI CSI2 HC DPHY ErrSotSync  0x11c = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x11c));
+	printk("MIPI CSI2 HC DPHY ErrEsc      0x120 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x120));
+	printk("MIPI CSI2 HC DPHY ErrSyncEsc  0x124 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x124));
+	printk("MIPI CSI2 HC DPHY ErrControl  0x128 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x128));
+	printk("MIPI CSI2 HC DISABLE_PAYLOAD  0x12C = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x12C));
+	printk("MIPI CSI2 HC DISABLE_PAYLOAD  0x130 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x130));
+	printk("MIPI CSI2 HC IGNORE_VC        0x180 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x180));
+	printk("MIPI CSI2 HC VID_VC           0x184 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x184));
+	printk("MIPI CSI2 HC FIFO_SEND_LEVEL  0x188 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x188));
+	printk("MIPI CSI2 HC VID_VSYNC        0x18C = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x18C));
+	printk("MIPI CSI2 HC VID_SYNC_FP      0x190 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x190));
+	printk("MIPI CSI2 HC VID_HSYNC        0x194 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x194));
+	printk("MIPI CSI2 HC VID_HSYNC_BP     0x198 = 0x%x\n",
+	       readl(csi2dev->base_regs + 0x198));
+}
+#else
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+}
+#endif
+
+static int mxc_mipi_csi2_phy_reset(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *node;
+	phandle phandle;
+	u32 out_val[3];
+	int ret;
+
+	ret = of_property_read_u32_array(np, "csis-phy-reset", out_val, 3);
+	if (ret) {
+		dev_info(dev, "no csis-hw-reset property found\n");
+	} else {
+		phandle = *out_val;
+
+		node = of_find_node_by_phandle(phandle);
+		if (!node) {
+			dev_dbg(dev, "not find src node by phandle\n");
+			ret = PTR_ERR(node);
+		}
+		csi2dev->hw_reset.src = syscon_node_to_regmap(node);
+		if (IS_ERR(csi2dev->hw_reset.src)) {
+			dev_err(dev, "failed to get src regmap\n");
+			ret = PTR_ERR(csi2dev->hw_reset.src);
+		}
+		of_node_put(node);
+		if (ret < 0)
+			return ret;
+
+		csi2dev->hw_reset.req_src = out_val[1];
+		csi2dev->hw_reset.rst_val = out_val[2];
+
+		/* reset mipi phy */
+		regmap_update_bits(csi2dev->hw_reset.src,
+				   csi2dev->hw_reset.req_src,
+				   csi2dev->hw_reset.rst_val,
+				   csi2dev->hw_reset.rst_val);
+		msleep(20);
+	}
+
+	return ret;
+}
+
+static int mxc_mipi_csi2_phy_gpr(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *node;
+	phandle phandle;
+	u32 out_val[2];
+	int ret;
+
+	ret = of_property_read_u32_array(np, "phy-gpr", out_val, 2);
+	if (ret) {
+		dev_dbg(dev, "no phy-gpr property found\n");
+	} else {
+		phandle = *out_val;
+
+		node = of_find_node_by_phandle(phandle);
+		if (!node) {
+			dev_dbg(dev, "not find gpr node by phandle\n");
+			ret = PTR_ERR(node);
+		}
+		csi2dev->phy_gpr.gpr = syscon_node_to_regmap(node);
+		if (IS_ERR(csi2dev->phy_gpr.gpr)) {
+			dev_err(dev, "failed to get gpr regmap\n");
+			ret = PTR_ERR(csi2dev->phy_gpr.gpr);
+		}
+		of_node_put(node);
+		if (ret < 0)
+			return ret;
+
+		csi2dev->phy_gpr.req_src = out_val[1];
+
+		regmap_update_bits(csi2dev->phy_gpr.gpr,
+				   csi2dev->phy_gpr.req_src,
+				   0x3FFF,
+				   GPR_CSI2_1_RX_ENABLE |
+				   GPR_CSI2_1_VID_INTFC_ENB |
+				   GPR_CSI2_1_HSEL |
+				   GPR_CSI2_1_CONT_CLK_MODE |
+				   GPR_CSI2_1_S_PRG_RXHS_SETTLE(csi2dev->
+								hs_settle));
+	}
+
+	return ret;
+}
+
+static void mxc_mipi_csi2_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	mxc_mipi_csi2_phy_gpr(csi2dev);
+}
+
+static void mxc_mipi_csi2_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	/* Disable Data lanes */
+	writel(0xf, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+}
+
+static void mxc_mipi_csi2_hc_config(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	u32 val0, val1;
+	u32 i;
+
+	val0 = 0;
+
+	/* Lanes */
+	writel(csi2dev->num_lanes - 1,
+	       csi2dev->base_regs + CSI2RX_CFG_NUM_LANES);
+
+	for (i = 0; i < csi2dev->num_lanes; i++)
+		val0 |= (1 << (csi2dev->data_lanes[i] - 1));
+
+	val1 = 0xF & ~val0;
+	writel(val1, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+
+	/* Mask interrupt */
+	writel(0x1FF, csi2dev->base_regs + CSI2RX_IRQ_MASK);
+
+	writel(1, csi2dev->base_regs + 0x180);
+	/* vid_vc */
+	writel(1, csi2dev->base_regs + 0x184);
+	writel(csi2dev->send_level, csi2dev->base_regs + 0x188);
+}
+
+static int mipi_csi2_clk_init(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+
+	csi2dev->clk_core = devm_clk_get(dev, "clk_core");
+	if (IS_ERR(csi2dev->clk_core)) {
+		dev_err(dev, "failed to get csi core clk\n");
+		return PTR_ERR(csi2dev->clk_core);
+	}
+
+	csi2dev->clk_esc = devm_clk_get(dev, "clk_esc");
+	if (IS_ERR(csi2dev->clk_esc)) {
+		dev_err(dev, "failed to get csi esc clk\n");
+		return PTR_ERR(csi2dev->clk_esc);
+	}
+
+	csi2dev->clk_pxl = devm_clk_get(dev, "clk_pxl");
+	if (IS_ERR(csi2dev->clk_pxl)) {
+		dev_err(dev, "failed to get csi pixel link clk\n");
+		return PTR_ERR(csi2dev->clk_pxl);
+	}
+
+	return 0;
+}
+
+static int mipi_csi2_clk_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+	int ret;
+
+	ret = clk_prepare_enable(csi2dev->clk_core);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk_core error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(csi2dev->clk_esc);
+	if (ret < 0) {
+		dev_err(dev, "%s, prepare clk_esc error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(csi2dev->clk_pxl);
+	if (ret < 0) {
+		dev_err(dev, "%s, prepare clk_pxl error\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void mipi_csi2_clk_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	clk_disable_unprepare(csi2dev->clk_core);
+	clk_disable_unprepare(csi2dev->clk_esc);
+	clk_disable_unprepare(csi2dev->clk_pxl);
+}
+
+static int mipi_csi2_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return 0;
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+	return 0;
+}
+
+static int mipi_csi2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct device *dev = &csi2dev->pdev->dev;
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+	int ret = 0;
+
+	dev_dbg(&csi2dev->pdev->dev, "%s: %d, csi2dev: 0x%x\n",
+		__func__, enable, csi2dev->flags);
+
+	if (enable) {
+		if (!csi2dev->running) {
+			pm_runtime_get_sync(dev);
+			mxc_mipi_csi2_phy_reset(csi2dev);
+			mxc_mipi_csi2_hc_config(csi2dev);
+			mxc_mipi_csi2_enable(csi2dev);
+			mxc_mipi_csi2_reg_dump(csi2dev);
+		}
+		v4l2_subdev_call(sensor_sd, video, s_stream, true);
+		csi2dev->running++;
+
+	} else {
+
+		v4l2_subdev_call(sensor_sd, video, s_stream, false);
+		csi2dev->running--;
+		if (!csi2dev->running) {
+			pm_runtime_put(dev);
+			mxc_mipi_csi2_disable(csi2dev);
+		}
+	}
+
+	return ret;
+}
+
+static int mipi_csis_enum_framesizes(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mipi_csis_enum_frameintervals(struct v4l2_subdev *sd,
+					 struct v4l2_subdev_pad_config *cfg,
+					 struct v4l2_subdev_frame_interval_enum
+					 *fie)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, pad, enum_mbus_code, NULL, code);
+}
+
+static int mipi_csi2_get_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	if (fmt->pad)
+		return -EINVAL;
+
+	return v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, fmt);
+}
+
+static int mipi_csi2_set_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *fmt)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	if (fmt->pad)
+		return -EINVAL;
+
+	if (fmt->format.width * fmt->format.height > 720 * 480) {
+		csi2dev->hs_settle = rxhs_settle[1];
+	} else {
+		csi2dev->hs_settle = rxhs_settle[0];
+	}
+	csi2dev->send_level = 64;
+
+	return v4l2_subdev_call(sensor_sd, pad, set_fmt, NULL, fmt);
+}
+
+static int mipi_csis_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, video, s_parm, a);
+}
+
+static int mipi_csis_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+	struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, video, g_parm, a);
+}
+
+static const struct v4l2_subdev_internal_ops mipi_csi2_sd_internal_ops = {
+	.open = mipi_csi2_open,
+};
+
+static struct v4l2_subdev_pad_ops mipi_csi2_pad_ops = {
+	.enum_frame_size = mipi_csis_enum_framesizes,
+	.enum_frame_interval = mipi_csis_enum_frameintervals,
+	.enum_mbus_code = mipi_csis_enum_mbus_code,
+	.get_fmt = mipi_csi2_get_fmt,
+	.set_fmt = mipi_csi2_set_fmt,
+};
+
+static struct v4l2_subdev_core_ops mipi_csi2_core_ops = {
+	.s_power = mipi_csi2_s_power,
+};
+
+static struct v4l2_subdev_video_ops mipi_csi2_video_ops = {
+	.s_stream = mipi_csi2_s_stream,
+
+	.s_parm = mipi_csis_s_parm,
+	.g_parm = mipi_csis_g_parm,
+};
+
+static struct v4l2_subdev_ops mipi_csi2_subdev_ops = {
+	.core = &mipi_csi2_core_ops,
+	.video = &mipi_csi2_video_ops,
+	.pad = &mipi_csi2_pad_ops,
+};
+
+static int mipi_csi2_parse_dt(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct v4l2_fwnode_endpoint endpoint;
+	u32 i;
+
+	csi2dev->id = of_alias_get_id(node, "csi");
+
+	csi2dev->vchannel = of_property_read_bool(node, "virtual-channel");
+
+	node = of_graph_get_next_endpoint(node, NULL);
+	if (!node) {
+		dev_err(dev, "No port node\n");
+		return -EINVAL;
+	}
+
+	/* Get port node */
+	memset(&endpoint, 0x0, sizeof(endpoint));
+	v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &endpoint);
+
+	csi2dev->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
+	for (i = 0; i < csi2dev->num_lanes; i++)
+		csi2dev->data_lanes[i] = endpoint.bus.mipi_csi2.data_lanes[i];
+
+	of_node_put(node);
+
+	return 0;
+}
+
+static inline struct mxc_mipi_csi2_dev
+*notifier_to_mipi_dev(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct mxc_mipi_csi2_dev, subdev_notifier);
+}
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+				 struct v4l2_subdev *subdev,
+				 struct v4l2_async_subdev *asd)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = notifier_to_mipi_dev(notifier);
+
+	/* Find platform data for this sensor subdev */
+	if (csi2dev->asd.match.fwnode == of_fwnode_handle(subdev->dev->of_node))
+		csi2dev->sensor_sd = subdev;
+
+	if (subdev == NULL)
+		return -EINVAL;
+
+	v4l2_info(&csi2dev->v4l2_dev, "Registered sensor subdevice: %s\n",
+		  subdev->name);
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
+	.bound = subdev_notifier_bound,
+};
+
+static int mipi_csis_subdev_host(struct mxc_mipi_csi2_dev *csi2dev)
+{
+	struct device *dev = &csi2dev->pdev->dev;
+	struct device_node *parent = dev->of_node;
+	struct device_node *node, *port, *rem;
+	int ret;
+
+	v4l2_async_notifier_init(&csi2dev->subdev_notifier);
+
+	/* Attach sensors linked to csi receivers */
+	for_each_available_child_of_node(parent, node) {
+		if (of_node_cmp(node->name, "port"))
+			continue;
+
+		/* The csi node can have only port subnode. */
+		port = of_get_next_child(node, NULL);
+		if (!port)
+			continue;
+		rem = of_graph_get_remote_port_parent(port);
+		of_node_put(port);
+		if (rem == NULL) {
+			v4l2_info(&csi2dev->v4l2_dev,
+				  "Remote device at %s not found\n",
+				  port->full_name);
+			return -1;
+		} else
+			v4l2_info(&csi2dev->v4l2_dev,
+				  "Remote device at %s XXX found\n",
+				  port->full_name);
+
+		INIT_LIST_HEAD(&csi2dev->asd.list);
+		csi2dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+		csi2dev->asd.match.fwnode = of_fwnode_handle(rem);
+		csi2dev->async_subdevs[0] = &csi2dev->asd;
+
+		of_node_put(rem);
+		break;
+	}
+
+	ret = v4l2_async_notifier_add_subdev(&csi2dev->subdev_notifier,
+					&csi2dev->asd);
+	if (ret) {
+		dev_err(dev, "failed to add subdev to a notifier\n");
+		return ret;
+	}
+
+	csi2dev->subdev_notifier.v4l2_dev = &csi2dev->v4l2_dev;
+	csi2dev->subdev_notifier.ops = &subdev_notifier_ops;
+
+	ret = v4l2_async_notifier_register(&csi2dev->v4l2_dev,
+					   &csi2dev->subdev_notifier);
+	if (ret)
+		dev_err(dev,
+			"Error register async notifier regoster, ret %d\n",
+			ret);
+
+	return ret;
+}
+
+static int mipi_csi2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *mem_res;
+	struct mxc_mipi_csi2_dev *csi2dev;
+	int ret = -ENOMEM;
+
+	dev_info(&pdev->dev, "%s\n", __func__);
+	csi2dev = devm_kzalloc(dev, sizeof(*csi2dev), GFP_KERNEL);
+	if (!csi2dev)
+		return -ENOMEM;
+
+	csi2dev->pdev = pdev;
+
+	ret = mipi_csi2_parse_dt(csi2dev);
+	if (ret < 0)
+		return -EINVAL;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	csi2dev->base_regs = devm_ioremap_resource(dev, mem_res);
+	if (IS_ERR(csi2dev->base_regs)) {
+		dev_err(dev, "Failed to get mipi csi2 HC register\n");
+		return PTR_ERR(csi2dev->base_regs);
+	}
+
+	ret = mipi_csi2_clk_init(csi2dev);
+	if (ret < 0)
+		return -EINVAL;
+
+	v4l2_subdev_init(&csi2dev->sd, &mipi_csi2_subdev_ops);
+
+	csi2dev->sd.owner = THIS_MODULE;
+	snprintf(csi2dev->sd.name, sizeof(csi2dev->sd.name), "%s.%d",
+		 MXC_MIPI_CSI2_YAV_SUBDEV_NAME, csi2dev->id);
+
+	csi2dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	csi2dev->sd.dev = &pdev->dev;
+
+	/* First register a v4l2 device */
+	ret = v4l2_device_register(dev, &csi2dev->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to register v4l2 device.\n");
+		return -EINVAL;
+	}
+	ret = v4l2_async_register_subdev(&csi2dev->sd);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n",
+			__func__, ret);
+		goto e_v4l_dev;
+	}
+
+	ret = mipi_csis_subdev_host(csi2dev);
+	if (ret < 0)
+		goto e_clkdis;
+
+	/* This allows to retrieve the platform device id by the host driver */
+	v4l2_set_subdevdata(&csi2dev->sd, pdev);
+
+	/* .. and a pointer to the subdev. */
+	platform_set_drvdata(pdev, csi2dev);
+
+	ret = mipi_csi2_clk_enable(csi2dev);
+	if (ret < 0)
+		goto e_clkdis;
+
+	dev_info(&pdev->dev, "lanes: %d, name: %s\n",
+		 csi2dev->num_lanes, csi2dev->sd.name);
+
+	csi2dev->running = 0;
+	csi2dev->flags = MXC_MIPI_CSI2_PM_POWERED;
+	pm_runtime_enable(&pdev->dev);
+	mipi_csi2_clk_disable(csi2dev);
+
+	return 0;
+
+e_clkdis:
+	v4l2_async_unregister_subdev(&csi2dev->sd);
+e_v4l_dev:
+	v4l2_device_unregister(&csi2dev->v4l2_dev);
+	return ret;
+}
+
+static int mipi_csi2_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+
+	mipi_csi2_clk_disable(csi2dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int __maybe_unused mipi_csi2_pm_runtime_resume(struct device *dev)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+	int ret;
+
+	ret = mipi_csi2_clk_enable(csi2dev);
+	if (ret < 0) {
+		dev_info(dev, "%s:%d fail\n", __func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int __maybe_unused mipi_csi2_runtime_pm_suspend(struct device *dev)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+
+	mipi_csi2_clk_disable(csi2dev);
+
+	return 0;
+}
+
+static int __maybe_unused mipi_csi2_pm_suspend(struct device *dev)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+
+	if (csi2dev->flags & MXC_MIPI_CSI2_PM_SUSPENDED)
+		return 0;
+
+	if (csi2dev->running) {
+		dev_warn(dev, "running, prevent entering suspend.\n");
+		return -EAGAIN;
+	}
+	csi2dev->flags &= ~MXC_MIPI_CSI2_PM_POWERED;
+	csi2dev->flags |= MXC_MIPI_CSI2_PM_SUSPENDED;
+
+	return 0;
+}
+
+static int __maybe_unused mipi_csi2_pm_resume(struct device *dev)
+{
+	struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+
+	if (csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED)
+		return 0;
+
+	csi2dev->flags |= MXC_MIPI_CSI2_PM_POWERED;
+	csi2dev->flags &= ~MXC_MIPI_CSI2_PM_SUSPENDED;
+
+	return 0;
+}
+
+static const struct dev_pm_ops mipi_csi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mipi_csi2_pm_suspend, mipi_csi2_pm_resume)
+	SET_RUNTIME_PM_OPS(mipi_csi2_runtime_pm_suspend,
+				mipi_csi2_pm_runtime_resume,
+				NULL)
+};
+
+static const struct of_device_id mipi_csi2_of_match[] = {
+	{.compatible = "fsl,mxc-mipi-csi2_yav",},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, mipi_csi2_of_match);
+
+static struct platform_driver mipi_csi2_driver = {
+	.driver = {
+		   .name = MXC_MIPI_CSI2_YAV_DRIVER_NAME,
+		   .of_match_table = mipi_csi2_of_match,
+		   .pm = &mipi_csi_pm_ops,
+		   },
+	.probe = mipi_csi2_probe,
+	.remove = mipi_csi2_remove,
+};
+
+module_platform_driver(mipi_csi2_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC MIPI CSI2 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MXC_MIPI_CSI2_YAV_DRIVER_NAME);
--- linux-ein-5.4.0.orig/drivers/media/platform/marvell-ccic/mcam-core.c
+++ linux-ein-5.4.0/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1940,6 +1940,7 @@
 out:
 	v4l2_async_notifier_unregister(&cam->notifier);
 	v4l2_device_unregister(&cam->v4l2_dev);
+	v4l2_async_notifier_cleanup(&cam->notifier);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(mccic_register);
@@ -1961,6 +1962,7 @@
 	v4l2_ctrl_handler_free(&cam->ctrl_handler);
 	v4l2_async_notifier_unregister(&cam->notifier);
 	v4l2_device_unregister(&cam->v4l2_dev);
+	v4l2_async_notifier_cleanup(&cam->notifier);
 }
 EXPORT_SYMBOL_GPL(mccic_shutdown);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/meson/ao-cec-g12a.c
+++ linux-ein-5.4.0/drivers/media/platform/meson/ao-cec-g12a.c
@@ -662,34 +662,27 @@
 	if (IS_ERR(ao_cec->adap))
 		return PTR_ERR(ao_cec->adap);
 
-	ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
-							ao_cec->adap);
-	if (!ao_cec->notify) {
-		ret = -ENOMEM;
-		goto out_probe_adapter;
-	}
-
 	ao_cec->adap->owner = THIS_MODULE;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base)) {
 		ret = PTR_ERR(base);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
 					       &meson_ao_cec_g12a_regmap_conf);
 	if (IS_ERR(ao_cec->regmap)) {
 		ret = PTR_ERR(ao_cec->regmap);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec,
 					   &meson_ao_cec_g12a_cec_regmap_conf);
 	if (IS_ERR(ao_cec->regmap_cec)) {
 		ret = PTR_ERR(ao_cec->regmap_cec);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -699,45 +692,52 @@
 					0, NULL, ao_cec);
 	if (ret) {
 		dev_err(&pdev->dev, "irq request failed\n");
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
 	if (IS_ERR(ao_cec->oscin)) {
 		dev_err(&pdev->dev, "oscin clock request failed\n");
 		ret = PTR_ERR(ao_cec->oscin);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ret = meson_ao_cec_g12a_setup_clk(ao_cec);
 	if (ret)
-		goto out_probe_notify;
+		goto out_probe_adapter;
 
 	ret = clk_prepare_enable(ao_cec->core);
 	if (ret) {
 		dev_err(&pdev->dev, "core clock enable failed\n");
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	device_reset_optional(&pdev->dev);
 
 	platform_set_drvdata(pdev, ao_cec);
 
+	ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+							ao_cec->adap);
+	if (!ao_cec->notify) {
+		ret = -ENOMEM;
+		goto out_probe_core_clk;
+	}
+
 	ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
 	if (ret < 0)
-		goto out_probe_core_clk;
+		goto out_probe_notify;
 
 	/* Setup Hardware */
 	regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
 
 	return 0;
 
-out_probe_core_clk:
-	clk_disable_unprepare(ao_cec->core);
-
 out_probe_notify:
 	cec_notifier_cec_adap_unregister(ao_cec->notify);
 
+out_probe_core_clk:
+	clk_disable_unprepare(ao_cec->core);
+
 out_probe_adapter:
 	cec_delete_adapter(ao_cec->adap);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/meson/ao-cec.c
+++ linux-ein-5.4.0/drivers/media/platform/meson/ao-cec.c
@@ -624,20 +624,13 @@
 	if (IS_ERR(ao_cec->adap))
 		return PTR_ERR(ao_cec->adap);
 
-	ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
-							ao_cec->adap);
-	if (!ao_cec->notify) {
-		ret = -ENOMEM;
-		goto out_probe_adapter;
-	}
-
 	ao_cec->adap->owner = THIS_MODULE;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ao_cec->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(ao_cec->base)) {
 		ret = PTR_ERR(ao_cec->base);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -647,20 +640,20 @@
 					0, NULL, ao_cec);
 	if (ret) {
 		dev_err(&pdev->dev, "irq request failed\n");
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ao_cec->core = devm_clk_get(&pdev->dev, "core");
 	if (IS_ERR(ao_cec->core)) {
 		dev_err(&pdev->dev, "core clock request failed\n");
 		ret = PTR_ERR(ao_cec->core);
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ret = clk_prepare_enable(ao_cec->core);
 	if (ret) {
 		dev_err(&pdev->dev, "core clock enable failed\n");
-		goto out_probe_notify;
+		goto out_probe_adapter;
 	}
 
 	ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE);
@@ -674,9 +667,16 @@
 	ao_cec->pdev = pdev;
 	platform_set_drvdata(pdev, ao_cec);
 
+	ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+							ao_cec->adap);
+	if (!ao_cec->notify) {
+		ret = -ENOMEM;
+		goto out_probe_clk;
+	}
+
 	ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
 	if (ret < 0)
-		goto out_probe_clk;
+		goto out_probe_notify;
 
 	/* Setup Hardware */
 	writel_relaxed(CEC_GEN_CNTL_RESET,
@@ -684,12 +684,12 @@
 
 	return 0;
 
-out_probe_clk:
-	clk_disable_unprepare(ao_cec->core);
-
 out_probe_notify:
 	cec_notifier_cec_adap_unregister(ao_cec->notify);
 
+out_probe_clk:
+	clk_disable_unprepare(ao_cec->core);
+
 out_probe_adapter:
 	cec_delete_adapter(ao_cec->adap);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -571,6 +571,13 @@
 	if (!q_data)
 		return -EINVAL;
 
+	if (*num_planes) {
+		for (i = 0; i < *num_planes; i++)
+			if (sizes[i] < q_data->sizeimage[i])
+				return -EINVAL;
+		return 0;
+	}
+
 	*num_planes = q_data->fmt->colplanes;
 	for (i = 0; i < q_data->fmt->colplanes; i++) {
 		sizes[i] = q_data->sizeimage[i];
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
+++ linux-ein-5.4.0/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h
@@ -40,12 +40,14 @@
  * @ipi_id        : IPI_MDP
  * @ap_inst       : AP mtk_mdp_vpu address
  * @vpu_inst_addr : VPU MDP instance address
+ * @padding       : Alignment padding
  */
 struct mdp_ipi_comm {
 	uint32_t msg_id;
 	uint32_t ipi_id;
 	uint64_t ap_inst;
 	uint32_t vpu_inst_addr;
+	uint32_t padding;
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -402,12 +402,12 @@
 	struct mtk_mdp_ctx *ctx = q->drv_priv;
 	int ret;
 
-	ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+	ret = pm_runtime_resume_and_get(&ctx->mdp_dev->pdev->dev);
 	if (ret < 0)
-		mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
+		mtk_mdp_dbg(1, "[%d] pm_runtime_resume_and_get failed:%d",
 			    ctx->id, ret);
 
-	return 0;
+	return ret;
 }
 
 static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -142,7 +142,9 @@
 	mtk_vcodec_dec_set_default_params(ctx);
 
 	if (v4l2_fh_is_singular(&ctx->fh)) {
-		mtk_vcodec_dec_pw_on(&dev->pm);
+		ret = mtk_vcodec_dec_pw_on(&dev->pm);
+		if (ret < 0)
+			goto err_load_fw;
 		/*
 		 * vpu_load_firmware checks if it was loaded already and
 		 * does nothing in that case
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -48,11 +48,14 @@
 		dec_clk->clk_info = devm_kcalloc(&pdev->dev,
 			dec_clk->clk_num, sizeof(*clk_info),
 			GFP_KERNEL);
-		if (!dec_clk->clk_info)
-			return -ENOMEM;
+		if (!dec_clk->clk_info) {
+			ret = -ENOMEM;
+			goto put_device;
+		}
 	} else {
 		mtk_v4l2_err("Failed to get vdec clock count");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto put_device;
 	}
 
 	for (i = 0; i < dec_clk->clk_num; i++) {
@@ -61,34 +64,40 @@
 			"clock-names", i, &clk_info->clk_name);
 		if (ret) {
 			mtk_v4l2_err("Failed to get clock name id = %d", i);
-			return ret;
+			goto put_device;
 		}
 		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
 			clk_info->clk_name);
 		if (IS_ERR(clk_info->vcodec_clk)) {
 			mtk_v4l2_err("devm_clk_get (%d)%s fail", i,
 				clk_info->clk_name);
-			return PTR_ERR(clk_info->vcodec_clk);
+			ret = PTR_ERR(clk_info->vcodec_clk);
+			goto put_device;
 		}
 	}
 
 	pm_runtime_enable(&pdev->dev);
-
+	return 0;
+put_device:
+	put_device(pm->larbvdec);
 	return ret;
 }
 
 void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
 {
 	pm_runtime_disable(dev->pm.dev);
+	put_device(dev->pm.larbvdec);
 }
 
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
 {
 	int ret;
 
-	ret = pm_runtime_get_sync(pm->dev);
+	ret = pm_runtime_resume_and_get(pm->dev);
 	if (ret)
-		mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
+		mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
+
+	return ret;
 }
 
 void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -12,7 +12,7 @@
 int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
 void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
 
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -759,6 +759,8 @@
 		return -EINVAL;
 
 	if (*nplanes) {
+		if (*nplanes != q_data->fmt->num_planes)
+			return -EINVAL;
 		for (i = 0; i < *nplanes; i++)
 			if (sizes[i] < q_data->sizeimage[i])
 				return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -209,11 +209,11 @@
 	mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
 	mutex_lock(&dev->dev_mutex);
 
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
 	mtk_vcodec_enc_release(ctx);
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
 	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
-	v4l2_m2m_ctx_release(ctx->m2m_ctx);
 
 	list_del_init(&ctx->list);
 	kfree(ctx);
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -49,14 +49,16 @@
 	node = of_parse_phandle(dev->of_node, "mediatek,larb", 1);
 	if (!node) {
 		mtk_v4l2_err("no mediatek,larb found");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto put_larbvenc;
 	}
 
 	pdev = of_find_device_by_node(node);
 	of_node_put(node);
 	if (!pdev) {
 		mtk_v4l2_err("no mediatek,larb device found");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto put_larbvenc;
 	}
 
 	pm->larbvenclt = &pdev->dev;
@@ -69,11 +71,14 @@
 		enc_clk->clk_info = devm_kcalloc(&pdev->dev,
 			enc_clk->clk_num, sizeof(*clk_info),
 			GFP_KERNEL);
-		if (!enc_clk->clk_info)
-			return -ENOMEM;
+		if (!enc_clk->clk_info) {
+			ret = -ENOMEM;
+			goto put_larbvenclt;
+		}
 	} else {
 		mtk_v4l2_err("Failed to get venc clock count");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto put_larbvenclt;
 	}
 
 	for (i = 0; i < enc_clk->clk_num; i++) {
@@ -82,17 +87,24 @@
 			"clock-names", i, &clk_info->clk_name);
 		if (ret) {
 			mtk_v4l2_err("venc failed to get clk name %d", i);
-			return ret;
+			goto put_larbvenclt;
 		}
 		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
 			clk_info->clk_name);
 		if (IS_ERR(clk_info->vcodec_clk)) {
 			mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i,
 				clk_info->clk_name);
-			return PTR_ERR(clk_info->vcodec_clk);
+			ret = PTR_ERR(clk_info->vcodec_clk);
+			goto put_larbvenclt;
 		}
 	}
 
+	return 0;
+
+put_larbvenclt:
+	put_device(pm->larbvenclt);
+put_larbvenc:
+	put_device(pm->larbvenc);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -222,10 +222,11 @@
 		if (fb->base_y.va == addr) {
 			list_move_tail(&node->list,
 				       &inst->available_fb_node_list);
-			break;
+			return fb;
 		}
 	}
-	return fb;
+
+	return NULL;
 }
 
 static void vp9_add_to_fb_free_list(struct vdec_vp9_inst *inst,
--- linux-ein-5.4.0.orig/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ linux-ein-5.4.0/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -529,15 +529,17 @@
 int vpu_load_firmware(struct platform_device *pdev)
 {
 	struct mtk_vpu *vpu;
-	struct device *dev = &pdev->dev;
+	struct device *dev;
 	struct vpu_run *run;
 	int ret;
 
 	if (!pdev) {
-		dev_err(dev, "VPU platform device is invalid\n");
+		pr_err("VPU platform device is invalid\n");
 		return -EINVAL;
 	}
 
+	dev = &pdev->dev;
+
 	vpu = platform_get_drvdata(pdev);
 	run = &vpu->run;
 
@@ -809,7 +811,8 @@
 	vpu->wdt.wq = create_singlethread_workqueue("vpu_wdt");
 	if (!vpu->wdt.wq) {
 		dev_err(dev, "initialize wdt workqueue failed\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto clk_unprepare;
 	}
 	INIT_WORK(&vpu->wdt.ws, vpu_wdt_reset_func);
 	mutex_init(&vpu->vpu_mutex);
@@ -908,6 +911,8 @@
 	vpu_clock_disable(vpu);
 workqueue_destroy:
 	destroy_workqueue(vpu->wdt.wq);
+clk_unprepare:
+	clk_unprepare(vpu->clk);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/mx2_emmaprp.c
+++ linux-ein-5.4.0/drivers/media/platform/mx2_emmaprp.c
@@ -852,8 +852,11 @@
 	platform_set_drvdata(pdev, pcdev);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	if (irq < 0) {
+		ret = irq;
+		goto rel_vdev;
+	}
+
 	ret = devm_request_irq(&pdev->dev, irq, emmaprp_irq, 0,
 			       dev_name(&pdev->dev), pcdev);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/Kconfig
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/Kconfig
@@ -0,0 +1,130 @@
+if VIDEO_MXC_CAPTURE
+
+config VIDEO_V4L2_MXC_INT_DEVICE
+       tristate
+
+config VIDEO_MXC_CSI_CAMERA
+	tristate "CSI camera support"
+	depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+	help
+		This is the video4linux2 capture driver based on CSI module.
+
+config MXC_VADC
+	tristate "mxc VADC support"
+	depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+	help
+		If you plan to use the VADC with your MXC system, say Y here.
+
+config MXC_MIPI_CSI
+	tristate "mxc mipi csi driver"
+	depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+	help
+		This is a V4L2 driver for i.MX7D SoC MIPI-CSI2 receiver devices.
+
+menu "MXC Camera/V4L2 PRP Features support"
+config VIDEO_MXC_IPU_CAMERA
+	bool
+	select VIDEO_V4L2_MXC_INT_DEVICE
+	depends on VIDEO_MXC_CAPTURE && MXC_IPU
+	default y
+
+config MXC_CAMERA_OV5640
+        tristate "OmniVision ov5640 camera support"
+        depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+	depends on VIDEO_V4L2_MXC_INT_DEVICE
+        help
+          If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_V2
+	tristate "OmniVision ov5640 camera support"
+	depends on VIDEO_MXC_CAPTURE && I2C
+	help
+	  If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5642
+	tristate "OmniVision ov5642 camera support"
+	depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+	depends on VIDEO_V4L2_MXC_INT_DEVICE
+	help
+	  If you plan to use the ov5642 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_MIPI
+	tristate "OmniVision ov5640 camera support using mipi"
+	depends on !VIDEO_MXC_EMMA_CAMERA && I2C && MXC_MIPI_CSI2
+	depends on VIDEO_V4L2_MXC_INT_DEVICE
+	help
+	  If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_MIPI_V2
+	tristate "OmniVision ov5640 camera support using mipi"
+	depends on MXC_MIPI_CSI && I2C
+	help
+	  If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_CAMERA_OV9281_MIPI_V2
+	tristate "OmniVision ov9281 camera support using mipi"
+	depends on MXC_MIPI_CSI && I2C
+	help
+	  If you plan to use the ov9281 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_CAMERA_OV5647_MIPI
+	tristate "OmniVision ov5647 camera support using mipi"
+	depends on MXC_MIPI_CSI && I2C
+	help
+	  If you plan to use the ov5647 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_TVIN_ADV7180
+	tristate "Analog Device adv7180 TV Decoder Input support"
+	depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+	depends on VIDEO_V4L2_MXC_INT_DEVICE
+	help
+	  If you plan to use the adv7180 video decoder with your MXC system, say Y here.
+
+choice
+	prompt "Select Overlay Rounting"
+	default MXC_IPU_DEVICE_QUEUE_SDC
+	depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL
+
+config MXC_IPU_DEVICE_QUEUE_SDC
+	tristate "Queue ipu device for overlay library"
+	depends on VIDEO_MXC_IPU_CAMERA
+	help
+	  Use case CSI->MEM->IPU DEVICE->SDC:
+		Images from sensor will be frist recieved in memory,then
+		queue to ipu device for processing if needed, and displaying
+		it on synchronous display with SDC use case.
+
+config MXC_IPU_PRP_VF_SDC
+	bool "Pre-Processor VF SDC library"
+	depends on VIDEO_MXC_IPU_CAMERA
+	help
+	  Use case PRP_VF_SDC:
+		Preprocessing image from smart sensor for viewfinder and
+		displaying it on synchronous display with SDC use case.
+		If SDC BG is selected, Rotation will not be supported.
+		CSI -> IC (PRP VF) -> MEM
+		MEM -> IC (ROT) -> MEM
+		MEM -> SDC (FG/BG)
+
+endchoice
+
+config MXC_IPU_PRP_ENC
+	tristate "Pre-processor Encoder library"
+	depends on VIDEO_MXC_IPU_CAMERA
+	default y
+	help
+	  Use case PRP_ENC:
+		Preprocessing image from smart sensor for encoder.
+		CSI -> IC (PRP ENC) -> MEM
+
+config MXC_IPU_CSI_ENC
+	tristate "IPU CSI Encoder library"
+	depends on VIDEO_MXC_IPU_CAMERA
+	default y
+	help
+	  Use case IPU_CSI_ENC:
+		Get raw image with CSI from smart sensor for encoder.
+		CSI -> MEM
+endmenu
+
+endif
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/Makefile
@@ -0,0 +1,41 @@
+ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y)
+	obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o
+	obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o
+	obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o
+	obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o
+	obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o
+endif
+
+obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o
+obj-$(CONFIG_MXC_VADC) += mxc_vadc.o
+obj-$(CONFIG_MXC_MIPI_CSI) += mxc_mipi_csi.o
+
+# Used for iMX 6QDL
+ov5640_camera_int-objs := ov5640.o
+obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera_int.o
+
+# Used for iMX 6UL/ULL/SX/SL/SLL
+ov5640_camera_v2-objs := ov5640_v2.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_V2) += ov5640_camera_v2.o
+
+ov5642_camera-objs := ov5642.o
+obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o
+
+# Used for iMX 6QDL/DQSCM
+ov5640_camera_mipi_int-objs := ov5640_mipi.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi_int.o
+
+# Used for iMX 7D
+ov5640_camera_mipi_v2-objs := ov5640_mipi_v2.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI_V2) += ov5640_camera_mipi_v2.o
+
+ov9281_camera_mipi_v2-objs := ov9281_mipi_v2.o
+obj-$(CONFIG_MXC_CAMERA_OV9281_MIPI_V2) += ov9281_camera_mipi_v2.o
+
+ov5647_camera_mipi-objs := ov5647_mipi.o
+obj-$(CONFIG_MXC_CAMERA_OV5647_MIPI) += ov5647_camera_mipi.o
+
+adv7180_tvin-objs := adv7180.o
+obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o
+
+obj-$(CONFIG_VIDEO_V4L2_MXC_INT_DEVICE) += v4l2-int-device.o
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/adv7180.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/adv7180.c
@@ -0,0 +1,1393 @@
+/*
+ * Copyright 2005-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file adv7180.c
+ *
+ * @brief Analog Device ADV7180 video decoder functions
+ *
+ * @ingroup Camera
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define ADV7180_VOLTAGE_ANALOG               1800000
+#define ADV7180_VOLTAGE_DIGITAL_CORE         1800000
+#define ADV7180_VOLTAGE_DIGITAL_IO           3300000
+#define ADV7180_VOLTAGE_PLL                  1800000
+
+static struct regulator *dvddio_regulator;
+static struct regulator *dvdd_regulator;
+static struct regulator *avdd_regulator;
+static struct regulator *pvdd_regulator;
+static int pwn_gpio;
+
+static int adv7180_probe(struct i2c_client *adapter,
+			 const struct i2c_device_id *id);
+static int adv7180_detach(struct i2c_client *client);
+
+#ifdef CONFIG_OF
+static const struct of_device_id adv7180_of_match[] = {
+	{ .compatible = "adv,adv7180",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, adv7180_of_match);
+#endif
+
+static const struct i2c_device_id adv7180_id[] = {
+	{"adv7180", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+
+static struct i2c_driver adv7180_i2c_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "adv7180",
+#ifdef CONFIG_OF
+		   .of_match_table = of_match_ptr(adv7180_of_match),
+#endif
+		   },
+	.probe = adv7180_probe,
+	.remove = adv7180_detach,
+	.id_table = adv7180_id,
+};
+
+/*!
+ * Maintains the information on the current state of the sensor.
+ */
+struct sensor {
+	struct sensor_data sen;
+	v4l2_std_id std_id;
+} adv7180_data;
+
+
+/*! List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt_t
+ */
+typedef enum {
+	ADV7180_NTSC = 0,	/*!< Locked on (M) NTSC video signal. */
+	ADV7180_PAL,		/*!< (B, G, H, I, N)PAL video signal. */
+	ADV7180_NOT_LOCKED,	/*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define ADV7180_STD_MAX		(ADV7180_PAL + 1)
+
+/*! Video format structure. */
+typedef struct {
+	int v4l2_id;		/*!< Video for linux ID. */
+	char name[16];		/*!< Name (e.g., "NTSC", "PAL", etc.) */
+	u16 raw_width;		/*!< Raw width. */
+	u16 raw_height;		/*!< Raw height. */
+	u16 active_width;	/*!< Active width. */
+	u16 active_height;	/*!< Active height. */
+	int frame_rate;		/*!< Frame rate. */
+} video_fmt_t;
+
+/*! Description of video formats supported.
+ *
+ *  PAL: raw=720x625, active=720x576.
+ *  NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+	{			/*! NTSC */
+	 .v4l2_id = V4L2_STD_NTSC,
+	 .name = "NTSC",
+	 .raw_width = 720,	/* SENS_FRM_WIDTH */
+	 .raw_height = 525,	/* SENS_FRM_HEIGHT */
+	 .active_width = 720,	/* ACT_FRM_WIDTH plus 1 */
+	 .active_height = 480,	/* ACT_FRM_WIDTH plus 1 */
+	 .frame_rate = 30,
+	 },
+	{			/*! (B, G, H, I, N) PAL */
+	 .v4l2_id = V4L2_STD_PAL,
+	 .name = "PAL",
+	 .raw_width = 720,
+	 .raw_height = 625,
+	 .active_width = 720,
+	 .active_height = 576,
+	 .frame_rate = 25,
+	 },
+	{			/*! Unlocked standard */
+	 .v4l2_id = V4L2_STD_ALL,
+	 .name = "Autodetect",
+	 .raw_width = 720,
+	 .raw_height = 625,
+	 .active_width = 720,
+	 .active_height = 576,
+	 .frame_rate = 0,
+	 },
+};
+
+/*!* Standard index of ADV7180. */
+static video_fmt_idx video_idx = ADV7180_PAL;
+
+/*! @brief This mutex is used to provide mutual exclusion.
+ *
+ *  Create a mutex that can be used to provide mutually exclusive
+ *  read/write access to the globally accessible data structures
+ *  and variables that were defined above.
+ */
+static DEFINE_MUTEX(mutex);
+
+#define IF_NAME                    "adv7180"
+#define ADV7180_INPUT_CTL              0x00	/* Input Control */
+#define ADV7180_STATUS_1               0x10	/* Status #1 */
+#define ADV7180_BRIGHTNESS             0x0a	/* Brightness */
+#define ADV7180_IDENT                  0x11	/* IDENT */
+#define ADV7180_VSYNC_FIELD_CTL_1      0x31	/* VSYNC Field Control #1 */
+#define ADV7180_MANUAL_WIN_CTL         0x3d	/* Manual Window Control */
+#define ADV7180_SD_SATURATION_CB       0xe3	/* SD Saturation Cb */
+#define ADV7180_SD_SATURATION_CR       0xe4	/* SD Saturation Cr */
+#define ADV7180_PWR_MNG                0x0f     /* Power Management */
+
+/* supported controls */
+/* This hasn't been fully implemented yet.
+ * This is how it should work, though. */
+static struct v4l2_queryctrl adv7180_qctrl[] = {
+	{
+	.id = V4L2_CID_BRIGHTNESS,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Brightness",
+	.minimum = 0,		/* check this value */
+	.maximum = 255,		/* check this value */
+	.step = 1,		/* check this value */
+	.default_value = 127,	/* check this value */
+	.flags = 0,
+	}, {
+	.id = V4L2_CID_SATURATION,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Saturation",
+	.minimum = 0,		/* check this value */
+	.maximum = 255,		/* check this value */
+	.step = 0x1,		/* check this value */
+	.default_value = 127,	/* check this value */
+	.flags = 0,
+	}
+};
+
+static inline void adv7180_power_down(int enable)
+{
+	gpio_set_value_cansleep(pwn_gpio, !enable);
+	msleep(2);
+}
+
+static int adv7180_regulator_enable(struct device *dev)
+{
+	int ret = 0;
+
+	dvddio_regulator = devm_regulator_get(dev, "DOVDD");
+
+	if (!IS_ERR(dvddio_regulator)) {
+		regulator_set_voltage(dvddio_regulator,
+				      ADV7180_VOLTAGE_DIGITAL_IO,
+				      ADV7180_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(dvddio_regulator);
+		if (ret) {
+			dev_err(dev, "set io voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set io voltage ok\n");
+		}
+	} else {
+		dev_warn(dev, "cannot get io voltage\n");
+	}
+
+	dvdd_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(dvdd_regulator)) {
+		regulator_set_voltage(dvdd_regulator,
+				      ADV7180_VOLTAGE_DIGITAL_CORE,
+				      ADV7180_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(dvdd_regulator);
+		if (ret) {
+			dev_err(dev, "set core voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set core voltage ok\n");
+		}
+	} else {
+		dev_warn(dev, "cannot get core voltage\n");
+	}
+
+	avdd_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(avdd_regulator)) {
+		regulator_set_voltage(avdd_regulator,
+				      ADV7180_VOLTAGE_ANALOG,
+				      ADV7180_VOLTAGE_ANALOG);
+		ret = regulator_enable(avdd_regulator);
+		if (ret) {
+			dev_err(dev, "set analog voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set analog voltage ok\n");
+		}
+	} else {
+		dev_warn(dev, "cannot get analog voltage\n");
+	}
+
+	pvdd_regulator = devm_regulator_get(dev, "PVDD");
+	if (!IS_ERR(pvdd_regulator)) {
+		regulator_set_voltage(pvdd_regulator,
+				      ADV7180_VOLTAGE_PLL,
+				      ADV7180_VOLTAGE_PLL);
+		ret = regulator_enable(pvdd_regulator);
+		if (ret) {
+			dev_err(dev, "set pll voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set pll voltage ok\n");
+		}
+	} else {
+		dev_warn(dev, "cannot get pll voltage\n");
+	}
+
+	return ret;
+}
+
+
+/***********************************************************************
+ * I2C transfert.
+ ***********************************************************************/
+
+/*! Read one register from a ADV7180 i2c slave device.
+ *
+ *  @param *reg		register in the device we wish to access.
+ *
+ *  @return		       0 if success, an error code otherwise.
+ */
+static inline int adv7180_read(u8 reg)
+{
+	int val;
+
+	val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg);
+	if (val < 0) {
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"%s:read reg error: reg=%2x\n", __func__, reg);
+		return -1;
+	}
+	return val;
+}
+
+/*! Write one register of a ADV7180 i2c slave device.
+ *
+ *  @param *reg		register in the device we wish to access.
+ *
+ *  @return		       0 if success, an error code otherwise.
+ */
+static int adv7180_write_reg(u8 reg, u8 val)
+{
+	s32 ret;
+
+	ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val);
+	if (ret < 0) {
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"%s:write reg error:reg=%2x,val=%2x\n", __func__,
+			reg, val);
+		return -1;
+	}
+	return 0;
+}
+
+/***********************************************************************
+ * mxc_v4l2_capture interface.
+ ***********************************************************************/
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ *  @return		None.
+ */
+static void adv7180_get_std(v4l2_std_id *std)
+{
+	int status_1, standard, idx;
+	bool locked;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n");
+
+	status_1 = adv7180_read(ADV7180_STATUS_1);
+	locked = status_1 & 0x1;
+	standard = status_1 & 0x70;
+
+	mutex_lock(&mutex);
+	*std = V4L2_STD_ALL;
+	idx = ADV7180_NOT_LOCKED;
+	if (locked) {
+		if (standard == 0x40) {
+			*std = V4L2_STD_PAL;
+			idx = ADV7180_PAL;
+		} else if (standard == 0) {
+			*std = V4L2_STD_NTSC;
+			idx = ADV7180_NTSC;
+		}
+	}
+	mutex_unlock(&mutex);
+
+	/* This assumes autodetect which this device uses. */
+	if (*std != adv7180_data.std_id) {
+		video_idx = idx;
+		adv7180_data.std_id = *std;
+		adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+		adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+	}
+}
+
+/***********************************************************************
+ * IOCTL Functions from v4l2_int_ioctl_desc.
+ ***********************************************************************/
+
+/*!
+ * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num
+ * s: pointer to standard V4L2 device structure
+ * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
+ *
+ * Gets slave interface parameters.
+ * Calculates the required xclk value to support the requested
+ * clock parameters in p.  This value is returned in the p
+ * parameter.
+ *
+ * vidioc_int_g_ifparm returns platform-specific information about the
+ * interface settings used by the sensor.
+ *
+ * Called on open.
+ */
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n");
+
+	if (s == NULL) {
+		pr_err("   ERROR!! no slave device set!\n");
+		return -1;
+	}
+
+	/* Initialize structure to 0s then set any non-0 values. */
+	memset(p, 0, sizeof(*p));
+	p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */
+	p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+	p->u.bt656.nobt_hs_inv = 1;
+	p->u.bt656.bt_sync_correct = 1;
+
+	/* ADV7180 has a dedicated clock so no clock settings needed. */
+
+	return 0;
+}
+
+/*!
+ * Sets the camera power.
+ *
+ * s  pointer to the camera device
+ * on if 1, power is to be turned on.  0 means power is to be turned off
+ *
+ * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ * This is called on open, close, suspend and resume.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+	struct sensor *sensor = s->priv;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n");
+
+	if (on && !sensor->sen.on) {
+		if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0)
+			return -EIO;
+
+		/*
+		 * FIXME:Additional 400ms to wait the chip to be stable?
+		 * This is a workaround for preview scrolling issue.
+		 */
+		msleep(400);
+	} else if (!on && sensor->sen.on) {
+		if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0)
+			return -EIO;
+	}
+
+	sensor->sen.on = on;
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	struct sensor *sensor = s->priv;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n");
+
+	switch (a->type) {
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		pr_debug("   type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->sen.streamcap.capability;
+		cparm->timeperframe = sensor->sen.streamcap.timeperframe;
+		cparm->capturemode = sensor->sen.streamcap.capturemode;
+		break;
+
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		break;
+
+	default:
+		pr_debug("ioctl_g_parm:type is unknown %d\n", a->type);
+		break;
+	}
+
+	return 0;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ *
+ * This driver cannot change these settings.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n");
+
+	switch (a->type) {
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		break;
+	}
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+	struct sensor *sensor = s->priv;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n");
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		pr_debug("   Returning size of %dx%d\n",
+			 sensor->sen.pix.width, sensor->sen.pix.height);
+		f->fmt.pix = sensor->sen.pix;
+		break;
+
+	case V4L2_BUF_TYPE_PRIVATE: {
+		v4l2_std_id std;
+		adv7180_get_std(&std);
+		f->fmt.pix.pixelformat = (u32)std;
+		}
+		break;
+
+	default:
+		f->fmt.pix = sensor->sen.pix;
+		break;
+	}
+
+	return 0;
+}
+
+/*!
+ * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * from the video_control[] array.  Otherwise, returns -EINVAL if the
+ * control is not supported.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+			   struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n");
+
+	for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++)
+		if (qc->id && qc->id == adv7180_qctrl[i].id) {
+			memcpy(qc, &(adv7180_qctrl[i]),
+				sizeof(*qc));
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array.  Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int ret = 0;
+	int sat = 0;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n");
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_BRIGHTNESS\n");
+		adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS);
+		vc->value = adv7180_data.sen.brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_CONTRAST\n");
+		vc->value = adv7180_data.sen.contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_SATURATION\n");
+		sat = adv7180_read(ADV7180_SD_SATURATION_CB);
+		adv7180_data.sen.saturation = sat;
+		vc->value = adv7180_data.sen.saturation;
+		break;
+	case V4L2_CID_HUE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_HUE\n");
+		vc->value = adv7180_data.sen.hue;
+		break;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_AUTO_WHITE_BALANCE\n");
+		break;
+	case V4L2_CID_DO_WHITE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_DO_WHITE_BALANCE\n");
+		break;
+	case V4L2_CID_RED_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_RED_BALANCE\n");
+		vc->value = adv7180_data.sen.red;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_BLUE_BALANCE\n");
+		vc->value = adv7180_data.sen.blue;
+		break;
+	case V4L2_CID_GAMMA:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_GAMMA\n");
+		break;
+	case V4L2_CID_EXPOSURE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_EXPOSURE\n");
+		vc->value = adv7180_data.sen.ae_mode;
+		break;
+	case V4L2_CID_AUTOGAIN:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_AUTOGAIN\n");
+		break;
+	case V4L2_CID_GAIN:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_GAIN\n");
+		break;
+	case V4L2_CID_HFLIP:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_HFLIP\n");
+		break;
+	case V4L2_CID_VFLIP:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_VFLIP\n");
+		break;
+	default:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   Default case\n");
+		vc->value = 0;
+		ret = -EPERM;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array).  Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int retval = 0;
+	u8 tmp;
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n");
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_BRIGHTNESS\n");
+		tmp = vc->value;
+		adv7180_write_reg(ADV7180_BRIGHTNESS, tmp);
+		adv7180_data.sen.brightness = vc->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_CONTRAST\n");
+		break;
+	case V4L2_CID_SATURATION:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_SATURATION\n");
+		tmp = vc->value;
+		adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp);
+		adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp);
+		adv7180_data.sen.saturation = vc->value;
+		break;
+	case V4L2_CID_HUE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_HUE\n");
+		break;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_AUTO_WHITE_BALANCE\n");
+		break;
+	case V4L2_CID_DO_WHITE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_DO_WHITE_BALANCE\n");
+		break;
+	case V4L2_CID_RED_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_RED_BALANCE\n");
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_BLUE_BALANCE\n");
+		break;
+	case V4L2_CID_GAMMA:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_GAMMA\n");
+		break;
+	case V4L2_CID_EXPOSURE:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_EXPOSURE\n");
+		break;
+	case V4L2_CID_AUTOGAIN:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_AUTOGAIN\n");
+		break;
+	case V4L2_CID_GAIN:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_GAIN\n");
+		break;
+	case V4L2_CID_HFLIP:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_HFLIP\n");
+		break;
+	case V4L2_CID_VFLIP:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   V4L2_CID_VFLIP\n");
+		break;
+	default:
+		dev_dbg(&adv7180_data.sen.i2c_client->dev,
+			"   Default case\n");
+		retval = -EPERM;
+		break;
+	}
+
+	return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+				 struct v4l2_frmsizeenum *fsize)
+{
+	if (fsize->index >= 1)
+		return -EINVAL;
+
+	fsize->discrete.width = video_fmts[video_idx].active_width;
+	fsize->discrete.height  = video_fmts[video_idx].active_height;
+
+	return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+					 struct v4l2_frmivalenum *fival)
+{
+	video_fmt_t fmt;
+	int i;
+
+	if (fival->index != 0)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(video_fmts) - 1; i++) {
+		fmt = video_fmts[i];
+		if (fival->width  == fmt.active_width &&
+		    fival->height == fmt.active_height) {
+			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+			fival->discrete.numerator = 1;
+			fival->discrete.denominator = fmt.frame_rate;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ *			VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+	((struct v4l2_dbg_chip_ident *)id)->match.type =
+					V4L2_CHIP_MATCH_I2C_DRIVER;
+	strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
+						"adv7180_decoder");
+	((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180;
+
+	return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n");
+	return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n");
+	return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module.
+ */
+static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = {
+
+	{vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init},
+
+	/*!
+	 * Delinitialise the dev. at slave detach.
+	 * The complement of ioctl_dev_init.
+	 */
+/*	{vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */
+
+	{vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power},
+	{vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm},
+/*	{vidioc_int_g_needs_reset_num,
+				(v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
+/*	{vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
+	{vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init},
+
+	/*!
+	 * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+	 */
+/*	{vidioc_int_enum_fmt_cap_num,
+				(v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */
+
+	/*!
+	 * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
+	 * This ioctl is used to negotiate the image capture size and
+	 * pixel format without actually making it take effect.
+	 */
+/*	{vidioc_int_try_fmt_cap_num,
+				(v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
+
+	{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap},
+
+	/*!
+	 * If the requested format is supported, configures the HW to use that
+	 * format, returns error code if format not supported or HW can't be
+	 * correctly configured.
+	 */
+/*	{vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */
+
+	{vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm},
+	{vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm},
+	{vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl},
+	{vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl},
+	{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl},
+	{vidioc_int_enum_framesizes_num,
+				(v4l2_int_ioctl_func *)ioctl_enum_framesizes},
+	{vidioc_int_enum_frameintervals_num,
+				(v4l2_int_ioctl_func *)
+				ioctl_enum_frameintervals},
+	{vidioc_int_g_chip_ident_num,
+				(v4l2_int_ioctl_func *)ioctl_g_chip_ident},
+};
+
+static struct v4l2_int_slave adv7180_slave = {
+	.ioctls = adv7180_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc),
+};
+
+static struct v4l2_int_device adv7180_int_device = {
+	.module = THIS_MODULE,
+	.name = "adv7180",
+	.type = v4l2_int_type_slave,
+	.u = {
+		.slave = &adv7180_slave,
+	},
+};
+
+
+/***********************************************************************
+ * I2C client and driver.
+ ***********************************************************************/
+
+/*! ADV7180 Reset function.
+ *
+ *  @return		None.
+ */
+static void adv7180_hard_reset(bool cvbs)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev,
+		"In adv7180:adv7180_hard_reset\n");
+
+	if (cvbs) {
+		/* Set CVBS input on AIN1 */
+		adv7180_write_reg(ADV7180_INPUT_CTL, 0x00);
+	} else {
+		/*
+		 * Set YPbPr input on AIN1,4,5 and normal
+		 * operations(autodection of all stds).
+		 */
+		adv7180_write_reg(ADV7180_INPUT_CTL, 0x09);
+	}
+
+	/* Datasheet recommends */
+	adv7180_write_reg(0x01, 0xc8);
+	adv7180_write_reg(0x02, 0x04);
+	adv7180_write_reg(0x03, 0x00);
+	adv7180_write_reg(0x04, 0x45);
+	adv7180_write_reg(0x05, 0x00);
+	adv7180_write_reg(0x06, 0x02);
+	adv7180_write_reg(0x07, 0x7F);
+	adv7180_write_reg(0x08, 0x80);
+	adv7180_write_reg(0x0A, 0x00);
+	adv7180_write_reg(0x0B, 0x00);
+	adv7180_write_reg(0x0C, 0x36);
+	adv7180_write_reg(0x0D, 0x7C);
+	adv7180_write_reg(0x0E, 0x00);
+	adv7180_write_reg(0x0F, 0x00);
+	adv7180_write_reg(0x13, 0x00);
+	adv7180_write_reg(0x14, 0x12);
+	adv7180_write_reg(0x15, 0x00);
+	adv7180_write_reg(0x16, 0x00);
+	adv7180_write_reg(0x17, 0x01);
+	adv7180_write_reg(0x18, 0x93);
+	adv7180_write_reg(0xF1, 0x19);
+	adv7180_write_reg(0x1A, 0x00);
+	adv7180_write_reg(0x1B, 0x00);
+	adv7180_write_reg(0x1C, 0x00);
+	adv7180_write_reg(0x1D, 0x40);
+	adv7180_write_reg(0x1E, 0x00);
+	adv7180_write_reg(0x1F, 0x00);
+	adv7180_write_reg(0x20, 0x00);
+	adv7180_write_reg(0x21, 0x00);
+	adv7180_write_reg(0x22, 0x00);
+	adv7180_write_reg(0x23, 0xC0);
+	adv7180_write_reg(0x24, 0x00);
+	adv7180_write_reg(0x25, 0x00);
+	adv7180_write_reg(0x26, 0x00);
+	adv7180_write_reg(0x27, 0x58);
+	adv7180_write_reg(0x28, 0x00);
+	adv7180_write_reg(0x29, 0x00);
+	adv7180_write_reg(0x2A, 0x00);
+	adv7180_write_reg(0x2B, 0xE1);
+	adv7180_write_reg(0x2C, 0xAE);
+	adv7180_write_reg(0x2D, 0xF4);
+	adv7180_write_reg(0x2E, 0x00);
+	adv7180_write_reg(0x2F, 0xF0);
+	adv7180_write_reg(0x30, 0x00);
+	adv7180_write_reg(0x31, 0x12);
+	adv7180_write_reg(0x32, 0x41);
+	adv7180_write_reg(0x33, 0x84);
+	adv7180_write_reg(0x34, 0x00);
+	adv7180_write_reg(0x35, 0x02);
+	adv7180_write_reg(0x36, 0x00);
+	adv7180_write_reg(0x37, 0x01);
+	adv7180_write_reg(0x38, 0x80);
+	adv7180_write_reg(0x39, 0xC0);
+	adv7180_write_reg(0x3A, 0x10);
+	adv7180_write_reg(0x3B, 0x05);
+	adv7180_write_reg(0x3C, 0x58);
+	adv7180_write_reg(0x3D, 0xB2);
+	adv7180_write_reg(0x3E, 0x64);
+	adv7180_write_reg(0x3F, 0xE4);
+	adv7180_write_reg(0x40, 0x90);
+	adv7180_write_reg(0x41, 0x01);
+	adv7180_write_reg(0x42, 0x7E);
+	adv7180_write_reg(0x43, 0xA4);
+	adv7180_write_reg(0x44, 0xFF);
+	adv7180_write_reg(0x45, 0xB6);
+	adv7180_write_reg(0x46, 0x12);
+	adv7180_write_reg(0x48, 0x00);
+	adv7180_write_reg(0x49, 0x00);
+	adv7180_write_reg(0x4A, 0x00);
+	adv7180_write_reg(0x4B, 0x00);
+	adv7180_write_reg(0x4C, 0x00);
+	adv7180_write_reg(0x4D, 0xEF);
+	adv7180_write_reg(0x4E, 0x08);
+	adv7180_write_reg(0x4F, 0x08);
+	adv7180_write_reg(0x50, 0x08);
+	adv7180_write_reg(0x51, 0x24);
+	adv7180_write_reg(0x52, 0x0B);
+	adv7180_write_reg(0x53, 0x4E);
+	adv7180_write_reg(0x54, 0x80);
+	adv7180_write_reg(0x55, 0x00);
+	adv7180_write_reg(0x56, 0x10);
+	adv7180_write_reg(0x57, 0x00);
+	adv7180_write_reg(0x58, 0x00);
+	adv7180_write_reg(0x59, 0x00);
+	adv7180_write_reg(0x5A, 0x00);
+	adv7180_write_reg(0x5B, 0x00);
+	adv7180_write_reg(0x5C, 0x00);
+	adv7180_write_reg(0x5D, 0x00);
+	adv7180_write_reg(0x5E, 0x00);
+	adv7180_write_reg(0x5F, 0x00);
+	adv7180_write_reg(0x60, 0x00);
+	adv7180_write_reg(0x61, 0x00);
+	adv7180_write_reg(0x62, 0x20);
+	adv7180_write_reg(0x63, 0x00);
+	adv7180_write_reg(0x64, 0x00);
+	adv7180_write_reg(0x65, 0x00);
+	adv7180_write_reg(0x66, 0x00);
+	adv7180_write_reg(0x67, 0x03);
+	adv7180_write_reg(0x68, 0x01);
+	adv7180_write_reg(0x69, 0x00);
+	adv7180_write_reg(0x6A, 0x00);
+	adv7180_write_reg(0x6B, 0xC0);
+	adv7180_write_reg(0x6C, 0x00);
+	adv7180_write_reg(0x6D, 0x00);
+	adv7180_write_reg(0x6E, 0x00);
+	adv7180_write_reg(0x6F, 0x00);
+	adv7180_write_reg(0x70, 0x00);
+	adv7180_write_reg(0x71, 0x00);
+	adv7180_write_reg(0x72, 0x00);
+	adv7180_write_reg(0x73, 0x10);
+	adv7180_write_reg(0x74, 0x04);
+	adv7180_write_reg(0x75, 0x01);
+	adv7180_write_reg(0x76, 0x00);
+	adv7180_write_reg(0x77, 0x3F);
+	adv7180_write_reg(0x78, 0xFF);
+	adv7180_write_reg(0x79, 0xFF);
+	adv7180_write_reg(0x7A, 0xFF);
+	adv7180_write_reg(0x7B, 0x1E);
+	adv7180_write_reg(0x7C, 0xC0);
+	adv7180_write_reg(0x7D, 0x00);
+	adv7180_write_reg(0x7E, 0x00);
+	adv7180_write_reg(0x7F, 0x00);
+	adv7180_write_reg(0x80, 0x00);
+	adv7180_write_reg(0x81, 0xC0);
+	adv7180_write_reg(0x82, 0x04);
+	adv7180_write_reg(0x83, 0x00);
+	adv7180_write_reg(0x84, 0x0C);
+	adv7180_write_reg(0x85, 0x02);
+	adv7180_write_reg(0x86, 0x03);
+	adv7180_write_reg(0x87, 0x63);
+	adv7180_write_reg(0x88, 0x5A);
+	adv7180_write_reg(0x89, 0x08);
+	adv7180_write_reg(0x8A, 0x10);
+	adv7180_write_reg(0x8B, 0x00);
+	adv7180_write_reg(0x8C, 0x40);
+	adv7180_write_reg(0x8D, 0x00);
+	adv7180_write_reg(0x8E, 0x40);
+	adv7180_write_reg(0x8F, 0x00);
+	adv7180_write_reg(0x90, 0x00);
+	adv7180_write_reg(0x91, 0x50);
+	adv7180_write_reg(0x92, 0x00);
+	adv7180_write_reg(0x93, 0x00);
+	adv7180_write_reg(0x94, 0x00);
+	adv7180_write_reg(0x95, 0x00);
+	adv7180_write_reg(0x96, 0x00);
+	adv7180_write_reg(0x97, 0xF0);
+	adv7180_write_reg(0x98, 0x00);
+	adv7180_write_reg(0x99, 0x00);
+	adv7180_write_reg(0x9A, 0x00);
+	adv7180_write_reg(0x9B, 0x00);
+	adv7180_write_reg(0x9C, 0x00);
+	adv7180_write_reg(0x9D, 0x00);
+	adv7180_write_reg(0x9E, 0x00);
+	adv7180_write_reg(0x9F, 0x00);
+	adv7180_write_reg(0xA0, 0x00);
+	adv7180_write_reg(0xA1, 0x00);
+	adv7180_write_reg(0xA2, 0x00);
+	adv7180_write_reg(0xA3, 0x00);
+	adv7180_write_reg(0xA4, 0x00);
+	adv7180_write_reg(0xA5, 0x00);
+	adv7180_write_reg(0xA6, 0x00);
+	adv7180_write_reg(0xA7, 0x00);
+	adv7180_write_reg(0xA8, 0x00);
+	adv7180_write_reg(0xA9, 0x00);
+	adv7180_write_reg(0xAA, 0x00);
+	adv7180_write_reg(0xAB, 0x00);
+	adv7180_write_reg(0xAC, 0x00);
+	adv7180_write_reg(0xAD, 0x00);
+	adv7180_write_reg(0xAE, 0x60);
+	adv7180_write_reg(0xAF, 0x00);
+	adv7180_write_reg(0xB0, 0x00);
+	adv7180_write_reg(0xB1, 0x60);
+	adv7180_write_reg(0xB2, 0x1C);
+	adv7180_write_reg(0xB3, 0x54);
+	adv7180_write_reg(0xB4, 0x00);
+	adv7180_write_reg(0xB5, 0x00);
+	adv7180_write_reg(0xB6, 0x00);
+	adv7180_write_reg(0xB7, 0x13);
+	adv7180_write_reg(0xB8, 0x03);
+	adv7180_write_reg(0xB9, 0x33);
+	adv7180_write_reg(0xBF, 0x02);
+	adv7180_write_reg(0xC0, 0x00);
+	adv7180_write_reg(0xC1, 0x00);
+	adv7180_write_reg(0xC2, 0x00);
+	adv7180_write_reg(0xC3, 0x00);
+	adv7180_write_reg(0xC4, 0x00);
+	adv7180_write_reg(0xC5, 0x81);
+	adv7180_write_reg(0xC6, 0x00);
+	adv7180_write_reg(0xC7, 0x00);
+	adv7180_write_reg(0xC8, 0x00);
+	adv7180_write_reg(0xC9, 0x04);
+	adv7180_write_reg(0xCC, 0x69);
+	adv7180_write_reg(0xCD, 0x00);
+	adv7180_write_reg(0xCE, 0x01);
+	adv7180_write_reg(0xCF, 0xB4);
+	adv7180_write_reg(0xD0, 0x00);
+	adv7180_write_reg(0xD1, 0x10);
+	adv7180_write_reg(0xD2, 0xFF);
+	adv7180_write_reg(0xD3, 0xFF);
+	adv7180_write_reg(0xD4, 0x7F);
+	adv7180_write_reg(0xD5, 0x7F);
+	adv7180_write_reg(0xD6, 0x3E);
+	adv7180_write_reg(0xD7, 0x08);
+	adv7180_write_reg(0xD8, 0x3C);
+	adv7180_write_reg(0xD9, 0x08);
+	adv7180_write_reg(0xDA, 0x3C);
+	adv7180_write_reg(0xDB, 0x9B);
+	adv7180_write_reg(0xDC, 0xAC);
+	adv7180_write_reg(0xDD, 0x4C);
+	adv7180_write_reg(0xDE, 0x00);
+	adv7180_write_reg(0xDF, 0x00);
+	adv7180_write_reg(0xE0, 0x14);
+	adv7180_write_reg(0xE1, 0x80);
+	adv7180_write_reg(0xE2, 0x80);
+	adv7180_write_reg(0xE3, 0x80);
+	adv7180_write_reg(0xE4, 0x80);
+	adv7180_write_reg(0xE5, 0x25);
+	adv7180_write_reg(0xE6, 0x44);
+	adv7180_write_reg(0xE7, 0x63);
+	adv7180_write_reg(0xE8, 0x65);
+	adv7180_write_reg(0xE9, 0x14);
+	adv7180_write_reg(0xEA, 0x63);
+	adv7180_write_reg(0xEB, 0x55);
+	adv7180_write_reg(0xEC, 0x55);
+	adv7180_write_reg(0xEE, 0x00);
+	adv7180_write_reg(0xEF, 0x4A);
+	adv7180_write_reg(0xF0, 0x44);
+	adv7180_write_reg(0xF1, 0x0C);
+	adv7180_write_reg(0xF2, 0x32);
+	adv7180_write_reg(0xF3, 0x00);
+	adv7180_write_reg(0xF4, 0x3F);
+	adv7180_write_reg(0xF5, 0xE0);
+	adv7180_write_reg(0xF6, 0x69);
+	adv7180_write_reg(0xF7, 0x10);
+	adv7180_write_reg(0xF8, 0x00);
+	adv7180_write_reg(0xF9, 0x03);
+	adv7180_write_reg(0xFA, 0xFA);
+	adv7180_write_reg(0xFB, 0x40);
+}
+
+/*! ADV7180 I2C attach function.
+ *
+ *  @param *adapter	struct i2c_adapter *.
+ *
+ *  @return		Error code indicating success or failure.
+ */
+
+/*!
+ * ADV7180 I2C probe function.
+ * Function set in i2c_driver struct.
+ * Called by insmod.
+ *
+ *  @param *adapter	I2C adapter descriptor.
+ *
+ *  @return		Error code indicating success or failure.
+ */
+static int adv7180_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int rev_id;
+	int ret = 0;
+	u32 cvbs = true;
+	struct pinctrl *pinctrl;
+	struct device *dev = &client->dev;
+
+	printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data);
+
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl)) {
+		dev_err(dev, "setup pinctrl failed\n");
+		return PTR_ERR(pinctrl);
+	}
+
+	/* request power down pin */
+	pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(pwn_gpio)) {
+		dev_err(dev, "no sensor pwdn pin available\n");
+		return -ENODEV;
+	}
+	ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+					"adv7180_pwdn");
+	if (ret < 0) {
+		dev_err(dev, "no power pin available!\n");
+		return ret;
+	}
+
+	adv7180_regulator_enable(dev);
+
+	adv7180_power_down(0);
+
+	msleep(1);
+
+	/* Set initial values for the sensor struct. */
+	memset(&adv7180_data, 0, sizeof(adv7180_data));
+	adv7180_data.sen.i2c_client = client;
+	adv7180_data.sen.streamcap.timeperframe.denominator = 30;
+	adv7180_data.sen.streamcap.timeperframe.numerator = 1;
+	adv7180_data.std_id = V4L2_STD_ALL;
+	video_idx = ADV7180_NOT_LOCKED;
+	adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+	adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+	adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY;  /* YUV422 */
+	adv7180_data.sen.pix.priv = 1;  /* 1 is used to indicate TV in */
+	adv7180_data.sen.on = true;
+
+	adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(adv7180_data.sen.sensor_clk)) {
+		dev_err(dev, "get mclk failed\n");
+		return PTR_ERR(adv7180_data.sen.sensor_clk);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "mclk",
+					&adv7180_data.sen.mclk);
+	if (ret) {
+		dev_err(dev, "mclk frequency is invalid\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(
+		dev->of_node, "mclk_source",
+		(u32 *) &(adv7180_data.sen.mclk_source));
+	if (ret) {
+		dev_err(dev, "mclk_source invalid\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "csi_id",
+					&(adv7180_data.sen.csi));
+	if (ret) {
+		dev_err(dev, "csi_id invalid\n");
+		return ret;
+	}
+
+	clk_prepare_enable(adv7180_data.sen.sensor_clk);
+
+	dev_dbg(&adv7180_data.sen.i2c_client->dev,
+		"%s:adv7180 probe i2c address is 0x%02X\n",
+		__func__, adv7180_data.sen.i2c_client->addr);
+
+	/*! Read the revision ID of the tvin chip */
+	rev_id = adv7180_read(ADV7180_IDENT);
+	dev_dbg(dev,
+		"%s:Analog Device adv7%2X0 detected!\n", __func__,
+		rev_id);
+
+	ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs));
+	if (ret) {
+		dev_err(dev, "cvbs setting is not found\n");
+		cvbs = true;
+	}
+
+	/*! ADV7180 initialization. */
+	adv7180_hard_reset(cvbs);
+
+	pr_debug("   type is %d (expect %d)\n",
+		 adv7180_int_device.type, v4l2_int_type_slave);
+	pr_debug("   num ioctls is %d\n",
+		 adv7180_int_device.u.slave->num_ioctls);
+
+	/* This function attaches this structure to the /dev/video0 device.
+	 * The pointer in priv points to the adv7180_data structure here.*/
+	adv7180_int_device.priv = &adv7180_data;
+	ret = v4l2_int_device_register(&adv7180_int_device);
+
+	clk_disable_unprepare(adv7180_data.sen.sensor_clk);
+
+	return ret;
+}
+
+/*!
+ * ADV7180 I2C detach function.
+ * Called on rmmod.
+ *
+ *  @param *client	struct i2c_client*.
+ *
+ *  @return		Error code indicating success or failure.
+ */
+static int adv7180_detach(struct i2c_client *client)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev,
+		"%s:Removing %s video decoder @ 0x%02X from adapter %s\n",
+		__func__, IF_NAME, client->addr << 1, client->adapter->name);
+
+	/* Power down via i2c */
+	adv7180_write_reg(ADV7180_PWR_MNG, 0x24);
+
+	if (dvddio_regulator)
+		regulator_disable(dvddio_regulator);
+
+	if (dvdd_regulator)
+		regulator_disable(dvdd_regulator);
+
+	if (avdd_regulator)
+		regulator_disable(avdd_regulator);
+
+	if (pvdd_regulator)
+		regulator_disable(pvdd_regulator);
+
+	v4l2_int_device_unregister(&adv7180_int_device);
+
+	return 0;
+}
+
+/*!
+ * ADV7180 init function.
+ * Called on insmod.
+ *
+ * @return    Error code indicating success or failure.
+ */
+static __init int adv7180_init(void)
+{
+	u8 err = 0;
+
+	pr_debug("In adv7180_init\n");
+
+	/* Tells the i2c driver what functions to call for this driver. */
+	err = i2c_add_driver(&adv7180_i2c_driver);
+	if (err != 0)
+		pr_err("%s:driver registration failed, error=%d\n",
+			__func__, err);
+
+	return err;
+}
+
+/*!
+ * ADV7180 cleanup function.
+ * Called on rmmod.
+ *
+ * @return   Error code indicating success or failure.
+ */
+static void __exit adv7180_clean(void)
+{
+	dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n");
+	i2c_del_driver(&adv7180_i2c_driver);
+}
+
+module_init(adv7180_init);
+module_exit(adv7180_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
@@ -0,0 +1,544 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_bg_overlay_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int csi_buffer_num;
+static u32 bpp, csi_mem_bufsize = 3;
+static u32 out_format;
+static struct ipu_soc *disp_ipu;
+static u32 offset;
+
+static void csi_buf_work_func(struct work_struct *work)
+{
+	int err = 0;
+	cam_data *cam =
+		container_of(work, struct _cam_data, csi_work_struct);
+
+	struct ipu_task	task;
+	memset(&task, 0, sizeof(task));
+
+	if (csi_buffer_num)
+		task.input.paddr = cam->vf_bufs[0];
+	else
+		task.input.paddr = cam->vf_bufs[1];
+	task.input.width = cam->crop_current.width;
+	task.input.height = cam->crop_current.height;
+	task.input.format = IPU_PIX_FMT_UYVY;
+
+	task.output.paddr = offset;
+	task.output.width = cam->overlay_fb->var.xres;
+	task.output.height = cam->overlay_fb->var.yres;
+	task.output.format = out_format;
+	task.output.rotate = cam->rotation;
+	task.output.crop.pos.x = cam->win.w.left;
+	task.output.crop.pos.y = cam->win.w.top;
+	if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
+		task.output.crop.w = cam->overlay_fb->var.xres;
+		task.output.crop.h = cam->overlay_fb->var.yres;
+	} else {
+		task.output.crop.w = cam->win.w.width;
+		task.output.crop.h = cam->win.w.height;
+	}
+again:
+	err = ipu_check_task(&task);
+	if (err != IPU_CHECK_OK) {
+		if (err > IPU_CHECK_ERR_MIN) {
+			if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+				task.input.crop.w -= 8;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+				task.input.crop.h -= 8;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+					task.output.width -= 8;
+					task.output.crop.w = task.output.width;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+					task.output.height -= 8;
+					task.output.crop.h = task.output.height;
+				goto again;
+			}
+			printk(KERN_ERR "check ipu taks fail\n");
+			return;
+		}
+		printk(KERN_ERR "check ipu taks fail\n");
+		return;
+	}
+	err = ipu_queue_task(&task);
+	if (err < 0)
+		printk(KERN_ERR "queue ipu task error\n");
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+	if (cam->output > 2)
+		disp_ipu = ipu_get_soc(1); /* using DISP4 */
+	else
+		disp_ipu = ipu_get_soc(0);
+}
+
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+	cam_data *cam = (cam_data *) dev_id;
+	ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
+		CSI_MEM0 : CSI_MEM1;
+
+	ipu_select_buffer(cam->ipu, chan,
+			IPU_OUTPUT_BUFFER, csi_buffer_num);
+	schedule_work(&cam->csi_work_struct);
+	csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+	return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+	ipu_channel_params_t params;
+	u32 pixel_fmt;
+	int err = 0, sensor_protocol = 0;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (!cam) {
+		printk(KERN_ERR "cam private is NULL\n");
+		return -ENXIO;
+	}
+
+	memset(&params, 0, sizeof(ipu_channel_params_t));
+	params.csi_mem.csi = cam->csi;
+
+	sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+	switch (sensor_protocol) {
+	case IPU_CSI_CLK_MODE_GATED_CLK:
+	case IPU_CSI_CLK_MODE_NONGATED_CLK:
+	case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+		params.csi_mem.interlaced = false;
+		break;
+	case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+		params.csi_mem.interlaced = true;
+		break;
+	default:
+		printk(KERN_ERR "sensor protocol unsupported\n");
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				params.csi_mem.mipi_en = true;
+				params.csi_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				params.csi_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				params.csi_mem.mipi_en = false;
+				params.csi_mem.mipi_vc = 0;
+				params.csi_mem.mipi_id = 0;
+			}
+		} else {
+			params.csi_mem.mipi_en = false;
+			params.csi_mem.mipi_vc = 0;
+			params.csi_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+	}
+	csi_mem_bufsize =
+		cam->crop_current.width * cam->crop_current.height * 2;
+	cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+	cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[0],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[0],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[0] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_2;
+	}
+	cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+	cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[1],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[1],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[1] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_1;
+	}
+	pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+	err = ipu_init_channel(cam->ipu, chan, &params);
+	if (err != 0) {
+		printk(KERN_ERR "ipu_init_channel %d\n", err);
+		goto out_1;
+	}
+
+	pixel_fmt = IPU_PIX_FMT_UYVY;
+	err = ipu_init_channel_buffer(
+		cam->ipu, chan, IPU_OUTPUT_BUFFER, pixel_fmt,
+		cam->crop_current.width, cam->crop_current.height,
+		cam->crop_current.width, IPU_ROTATE_NONE,
+		cam->vf_bufs[0], cam->vf_bufs[1], 0,
+		cam->offset.u_offset, cam->offset.u_offset);
+	if (err != 0) {
+		printk(KERN_ERR "CSI_MEM output buffer\n");
+		goto out_1;
+	}
+	err = ipu_enable_channel(cam->ipu, chan);
+	if (err < 0) {
+		printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+		goto out_1;
+	}
+
+	csi_buffer_num = 0;
+
+	ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
+	ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
+	return err;
+out_1:
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+out_2:
+	return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
+	err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
+			csi_enc_callback, 0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
+		return err;
+	}
+
+	INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+	err = csi_enc_setup(cam);
+	if (err != 0) {
+		printk(KERN_ERR "csi_enc_setup %d\n", err);
+		goto out1;
+	}
+
+	return err;
+out1:
+	ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+	return err;
+}
+
+/*!
+ * bg_overlay_start - start the overlay task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_start(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	if (!cam) {
+		printk(KERN_ERR "private is NULL\n");
+		return -EIO;
+	}
+
+	if (cam->overlay_active == true) {
+		pr_debug("already start.\n");
+		return 0;
+	}
+
+	get_disp_ipu(cam);
+
+	out_format = cam->v4l2_fb.fmt.pixelformat;
+	if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+		bpp = 3, csi_mem_bufsize = 3;
+		pr_info("BGR24\n");
+	} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+		bpp = 2, csi_mem_bufsize = 2;
+		pr_info("RGB565\n");
+	} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+		bpp = 4, csi_mem_bufsize = 4;
+		pr_info("BGR32\n");
+	} else {
+		printk(KERN_ERR
+		       "unsupported fix format from the framebuffer.\n");
+		return -EINVAL;
+	}
+
+	offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+	    csi_mem_bufsize * cam->win.w.left;
+
+	if (cam->v4l2_fb.base == 0)
+		printk(KERN_ERR "invalid frame buffer address.\n");
+	else
+		offset += (u32) cam->v4l2_fb.base;
+
+	csi_mem_bufsize = cam->win.w.width * cam->win.w.height
+				* csi_mem_bufsize;
+
+	err = csi_enc_enabling_tasks(cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error csi enc enable fail\n");
+		return err;
+	}
+
+	cam->overlay_active = true;
+	return err;
+}
+
+/*!
+ * bg_overlay_stop - stop the overlay task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_stop(void *private)
+{
+	int err = 0;
+	cam_data *cam = (cam_data *) private;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (cam->overlay_active == false)
+		return 0;
+
+	err = ipu_disable_channel(cam->ipu, chan, true);
+
+	ipu_uninit_channel(cam->ipu, chan);
+
+	csi_buffer_num = 0;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	flush_work(&cam->csi_work_struct);
+	cancel_work_sync(&cam->csi_work_struct);
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[0],
+				  cam->rot_vf_bufs_vaddr[0],
+				  cam->rot_vf_bufs[0]);
+		cam->rot_vf_bufs_vaddr[0] = NULL;
+		cam->rot_vf_bufs[0] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[1],
+				  cam->rot_vf_bufs_vaddr[1],
+				  cam->rot_vf_bufs[1]);
+		cam->rot_vf_bufs_vaddr[1] = NULL;
+		cam->rot_vf_bufs[1] = 0;
+	}
+
+	cam->overlay_active = false;
+	return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int bg_overlay_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int bg_overlay_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select bg as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int bg_overlay_sdc_select(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	if (cam) {
+		cam->vf_start_sdc = bg_overlay_start;
+		cam->vf_stop_sdc = bg_overlay_stop;
+		cam->vf_enable_csi = bg_overlay_enable_csi;
+		cam->vf_disable_csi = bg_overlay_disable_csi;
+		cam->overlay_active = false;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_select);
+
+/*!
+ * function to de-select bg as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int bg_overlay_sdc_deselect(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	if (cam) {
+		cam->vf_start_sdc = NULL;
+		cam->vf_stop_sdc = NULL;
+		cam->vf_enable_csi = NULL;
+		cam->vf_disable_csi = NULL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_deselect);
+
+/*!
+ * Init background overlay task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int bg_overlay_sdc_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit background overlay task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit bg_overlay_sdc_exit(void)
+{
+}
+
+module_init(bg_overlay_sdc_init);
+module_exit(bg_overlay_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_csi_enc.c
@@ -0,0 +1,423 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_csi_enc.c
+ *
+ * @brief CSI Use case for video capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+	#define CAMERA_TRACE(x) (printk)x
+#else
+	#define CAMERA_TRACE(x)
+#endif
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+	cam_data *cam = (cam_data *) dev_id;
+
+	if (cam->enc_callback == NULL)
+		return IRQ_HANDLED;
+
+	cam->enc_callback(irq, dev_id);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * CSI ENC enable channel setup function
+ *
+ * @param cam       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_setup(cam_data *cam)
+{
+	ipu_channel_params_t params;
+	u32 pixel_fmt;
+	int err = 0, sensor_protocol = 0;
+	dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	CAMERA_TRACE("In csi_enc_setup\n");
+	if (!cam) {
+		printk(KERN_ERR "cam private is NULL\n");
+		return -ENXIO;
+	}
+
+	memset(&params, 0, sizeof(ipu_channel_params_t));
+	params.csi_mem.csi = cam->csi;
+
+	sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+	switch (sensor_protocol) {
+	case IPU_CSI_CLK_MODE_GATED_CLK:
+	case IPU_CSI_CLK_MODE_NONGATED_CLK:
+	case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+		params.csi_mem.interlaced = false;
+		break;
+	case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+		params.csi_mem.interlaced = true;
+		break;
+	default:
+		printk(KERN_ERR "sensor protocol unsupported\n");
+		return -EINVAL;
+	}
+
+	if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+		pixel_fmt = IPU_PIX_FMT_YUV420P;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
+		pixel_fmt = IPU_PIX_FMT_YVU420P;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+		pixel_fmt = IPU_PIX_FMT_YUV422P;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+		pixel_fmt = IPU_PIX_FMT_UYVY;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+		pixel_fmt = IPU_PIX_FMT_YUYV;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+		pixel_fmt = IPU_PIX_FMT_NV12;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+		pixel_fmt = IPU_PIX_FMT_BGR24;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+		pixel_fmt = IPU_PIX_FMT_RGB24;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+		pixel_fmt = IPU_PIX_FMT_RGB565;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+		pixel_fmt = IPU_PIX_FMT_BGR32;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+		pixel_fmt = IPU_PIX_FMT_RGB32;
+	else {
+		printk(KERN_ERR "format not supported\n");
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				params.csi_mem.mipi_en = true;
+				params.csi_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				params.csi_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				params.csi_mem.mipi_en = false;
+				params.csi_mem.mipi_vc = 0;
+				params.csi_mem.mipi_id = 0;
+			}
+		} else {
+			params.csi_mem.mipi_en = false;
+			params.csi_mem.mipi_vc = 0;
+			params.csi_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	err = ipu_init_channel(cam->ipu, chan, &params);
+	if (err != 0) {
+		printk(KERN_ERR "ipu_init_channel %d\n", err);
+		return err;
+	}
+
+	err = ipu_init_channel_buffer(cam->ipu,
+				      chan,
+				      IPU_OUTPUT_BUFFER,
+				      pixel_fmt, cam->v2f.fmt.pix.width,
+				      cam->v2f.fmt.pix.height,
+				      cam->v2f.fmt.pix.bytesperline,
+				      IPU_ROTATE_NONE,
+				      dummy, dummy, 0,
+				      cam->offset.u_offset,
+				      cam->offset.v_offset);
+	if (err != 0) {
+		printk(KERN_ERR "CSI_MEM output buffer\n");
+		return err;
+	}
+	err = ipu_enable_channel(cam->ipu, chan);
+	if (err < 0) {
+		printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+		return err;
+	}
+
+	return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param *private    pointer to the cam_data structure
+ * @param eba         physical buffer address for encorder IDMA channel
+ *
+ * @return  status
+ */
+static int csi_enc_eba_update(void *private, dma_addr_t eba)
+{
+	int err = 0;
+	cam_data *cam = (cam_data *) private;
+	struct ipu_soc *ipu = cam->ipu;
+	int *buffer_num = &cam->ping_pong_csi;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+	pr_debug("eba %x\n", eba);
+	err = ipu_update_channel_buffer(ipu, chan, IPU_OUTPUT_BUFFER,
+					*buffer_num, eba);
+	if (err != 0) {
+		ipu_clear_buffer_ready(ipu, chan, IPU_OUTPUT_BUFFER,
+				       *buffer_num);
+
+		err = ipu_update_channel_buffer(ipu, chan,
+				IPU_OUTPUT_BUFFER, *buffer_num, eba);
+		if (err != 0) {
+			pr_err("ERROR: v4l2 capture: fail to update "
+			       "buf%d\n", *buffer_num);
+			return err;
+		}
+	}
+
+	ipu_select_buffer(ipu, chan, IPU_OUTPUT_BUFFER, *buffer_num);
+
+	*buffer_num = (*buffer_num == 0) ? 1 : 0;
+
+	return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+	uint32_t irq = (cam->csi == 0) ?
+		IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
+
+	CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+	cam->dummy_frame.vaddress = dma_alloc_coherent(cam->dev,
+			       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+			       &cam->dummy_frame.paddress,
+			       GFP_DMA | GFP_KERNEL);
+	if (cam->dummy_frame.vaddress == 0) {
+		pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+		       "failed.\n");
+		return -ENOBUFS;
+	}
+	cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+	cam->dummy_frame.buffer.length =
+	    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+	cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+	ipu_clear_irq(cam->ipu, irq);
+	err = ipu_request_irq(
+		cam->ipu, irq, csi_enc_callback, 0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering rot irq\n");
+		return err;
+	}
+
+	err = csi_enc_setup(cam);
+	if (err != 0) {
+		printk(KERN_ERR "csi_enc_setup %d\n", err);
+		return err;
+	}
+
+	return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+static int csi_enc_disabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	err = ipu_disable_channel(cam->ipu, chan, true);
+
+	ipu_uninit_channel(cam->ipu, chan);
+
+	if (cam->dummy_frame.vaddress != 0) {
+		dma_free_coherent(cam->dev, cam->dummy_frame.buffer.length,
+				  cam->dummy_frame.vaddress,
+				  cam->dummy_frame.paddress);
+		cam->dummy_frame.vaddress = 0;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	uint32_t irq = (cam->csi == 0) ?
+		IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	ipu_free_irq(cam->ipu, irq, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select CSI ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int csi_enc_select(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	if (cam) {
+		cam->enc_update_eba = csi_enc_eba_update;
+		cam->enc_enable = csi_enc_enabling_tasks;
+		cam->enc_disable = csi_enc_disabling_tasks;
+		cam->enc_enable_csi = csi_enc_enable_csi;
+		cam->enc_disable_csi = csi_enc_disable_csi;
+	} else {
+		err = -EIO;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(csi_enc_select);
+
+/*!
+ * function to de-select CSI ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int csi_enc_deselect(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	if (cam) {
+		cam->enc_update_eba = NULL;
+		cam->enc_enable = NULL;
+		cam->enc_disable = NULL;
+		cam->enc_enable_csi = NULL;
+		cam->enc_disable_csi = NULL;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(csi_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int csi_enc_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit csi_enc_exit(void)
+{
+}
+
+module_init(csi_enc_init);
+module_exit(csi_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("CSI ENC Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c
@@ -0,0 +1,633 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_foreground_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/mxcfb.h>
+#include <linux/mipi_csi2.h>
+
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+	#define CAMERA_TRACE(x) (printk)x
+#else
+	#define CAMERA_TRACE(x)
+#endif
+
+static int csi_buffer_num, buffer_num;
+static u32 csi_mem_bufsize;
+static struct ipu_soc *disp_ipu;
+static struct fb_info *fbi;
+static struct fb_var_screeninfo fbvar;
+static u32 vf_out_format;
+static void csi_buf_work_func(struct work_struct *work)
+{
+	int err = 0;
+	cam_data *cam =
+		container_of(work, struct _cam_data, csi_work_struct);
+
+	struct ipu_task	task;
+	memset(&task, 0, sizeof(task));
+
+	if (csi_buffer_num)
+		task.input.paddr = cam->vf_bufs[0];
+	else
+		task.input.paddr = cam->vf_bufs[1];
+	task.input.width = cam->crop_current.width;
+	task.input.height = cam->crop_current.height;
+	task.input.format = IPU_PIX_FMT_NV12;
+
+	if (buffer_num == 0)
+		task.output.paddr = fbi->fix.smem_start +
+				(fbi->fix.line_length * fbvar.yres);
+	else
+		task.output.paddr = fbi->fix.smem_start;
+	task.output.width = cam->win.w.width;
+	task.output.height = cam->win.w.height;
+	task.output.format = vf_out_format;
+	task.output.rotate = cam->rotation;
+again:
+	err = ipu_check_task(&task);
+	if (err != IPU_CHECK_OK) {
+		if (err > IPU_CHECK_ERR_MIN) {
+			if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+				task.input.crop.w -= 8;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+				task.input.crop.h -= 8;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+					task.output.width -= 8;
+					task.output.crop.w = task.output.width;
+				goto again;
+			}
+			if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+					task.output.height -= 8;
+					task.output.crop.h = task.output.height;
+				goto again;
+			}
+			printk(KERN_ERR "check ipu taks fail\n");
+			return;
+		}
+		printk(KERN_ERR "check ipu taks fail\n");
+		return;
+	}
+	err = ipu_queue_task(&task);
+	if (err < 0)
+		printk(KERN_ERR "queue ipu task error\n");
+	ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num);
+	buffer_num = (buffer_num == 0) ? 1 : 0;
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+	if (cam->output > 2)
+		disp_ipu = ipu_get_soc(1); /* using DISP4 */
+	else
+		disp_ipu = ipu_get_soc(0);
+}
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+	cam_data *cam = (cam_data *) dev_id;
+	ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
+		CSI_MEM0 : CSI_MEM1;
+
+	ipu_select_buffer(cam->ipu, chan,
+			  IPU_OUTPUT_BUFFER, csi_buffer_num);
+
+	if ((cam->crop_current.width != cam->win.w.width) ||
+		(cam->crop_current.height != cam->win.w.height) ||
+		(vf_out_format != IPU_PIX_FMT_NV12) ||
+		(cam->rotation >= IPU_ROTATE_VERT_FLIP))
+		schedule_work(&cam->csi_work_struct);
+	csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+	return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+	ipu_channel_params_t params;
+	int err = 0, sensor_protocol = 0;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	CAMERA_TRACE("In csi_enc_setup\n");
+	if (!cam) {
+		printk(KERN_ERR "cam private is NULL\n");
+		return -ENXIO;
+	}
+
+	memset(&params, 0, sizeof(ipu_channel_params_t));
+	params.csi_mem.csi = cam->csi;
+
+	sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+	switch (sensor_protocol) {
+	case IPU_CSI_CLK_MODE_GATED_CLK:
+	case IPU_CSI_CLK_MODE_NONGATED_CLK:
+	case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+		params.csi_mem.interlaced = false;
+		break;
+	case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+		params.csi_mem.interlaced = true;
+		break;
+	default:
+		printk(KERN_ERR "sensor protocol unsupported\n");
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				params.csi_mem.mipi_en = true;
+				params.csi_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				params.csi_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				params.csi_mem.mipi_en = false;
+				params.csi_mem.mipi_vc = 0;
+				params.csi_mem.mipi_id = 0;
+			}
+		} else {
+			params.csi_mem.mipi_en = false;
+			params.csi_mem.mipi_vc = 0;
+			params.csi_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+	}
+	csi_mem_bufsize = cam->crop_current.width *
+			  cam->crop_current.height * 3/2;
+	cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+	cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[0],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[0],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[0] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_2;
+	}
+	cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+	cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[1],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[1],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[1] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_1;
+	}
+	pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+	err = ipu_init_channel(cam->ipu, chan, &params);
+	if (err != 0) {
+		printk(KERN_ERR "ipu_init_channel %d\n", err);
+		goto out_1;
+	}
+
+	if ((cam->crop_current.width == cam->win.w.width) &&
+		(cam->crop_current.height == cam->win.w.height) &&
+		(vf_out_format == IPU_PIX_FMT_NV12) &&
+		(cam->rotation < IPU_ROTATE_VERT_FLIP)) {
+		err = ipu_init_channel_buffer(cam->ipu, chan,
+				IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
+				cam->crop_current.width,
+				cam->crop_current.height,
+				cam->crop_current.width, IPU_ROTATE_NONE,
+				fbi->fix.smem_start +
+				(fbi->fix.line_length * fbvar.yres),
+				fbi->fix.smem_start, 0,
+				cam->offset.u_offset, cam->offset.u_offset);
+	} else {
+		err = ipu_init_channel_buffer(cam->ipu, chan,
+				IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
+				cam->crop_current.width,
+				cam->crop_current.height,
+				cam->crop_current.width, IPU_ROTATE_NONE,
+				cam->vf_bufs[0], cam->vf_bufs[1], 0,
+				cam->offset.u_offset, cam->offset.u_offset);
+	}
+	if (err != 0) {
+		printk(KERN_ERR "CSI_MEM output buffer\n");
+		goto out_1;
+	}
+	err = ipu_enable_channel(cam->ipu, chan);
+	if (err < 0) {
+		printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+		goto out_1;
+	}
+
+	csi_buffer_num = 0;
+
+	ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
+	ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
+	return err;
+out_1:
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+out_2:
+	return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+	CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+	ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
+	err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
+			      csi_enc_callback, 0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
+		return err;
+	}
+
+	INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+	err = csi_enc_setup(cam);
+	if (err != 0) {
+		printk(KERN_ERR "csi_enc_setup %d\n", err);
+		goto out1;
+	}
+
+	return err;
+out1:
+	ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+	return err;
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * foreground_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_start(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0, i = 0, screen_size;
+	char *base;
+
+	if (!cam) {
+		printk(KERN_ERR "private is NULL\n");
+		return -EIO;
+	}
+
+	if (cam->overlay_active == true) {
+		pr_debug("already started.\n");
+		return 0;
+	}
+
+	get_disp_ipu(cam);
+
+	for (i = 0; i < num_registered_fb; i++) {
+		char *idstr = registered_fb[i]->fix.id;
+		if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+		    ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+			fbi = registered_fb[i];
+			break;
+		}
+	}
+
+	if (fbi == NULL) {
+		printk(KERN_ERR "DISP FG fb not found\n");
+		return -EPERM;
+	}
+
+	fbvar = fbi->var;
+
+	/* Store the overlay frame buffer's original std */
+	cam->fb_origin_std = fbvar.nonstd;
+
+	if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+		/* Use DP to do CSC so that we can get better performance */
+		vf_out_format = IPU_PIX_FMT_NV12;
+		fbvar.nonstd = vf_out_format;
+	} else {
+		vf_out_format = IPU_PIX_FMT_RGB565;
+		fbvar.nonstd = 0;
+	}
+
+	fbvar.bits_per_pixel = 16;
+	fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+	fbvar.yres = cam->win.w.height;
+	fbvar.yres_virtual = cam->win.w.height * 2;
+	fbvar.yoffset = 0;
+	fbvar.vmode &= ~FB_VMODE_YWRAP;
+	fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+	fbvar.activate |= FB_ACTIVATE_FORCE;
+	fb_set_var(fbi, &fbvar);
+
+	ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+			cam->win.w.top);
+
+	/* Fill black color for framebuffer */
+	base = (char *) fbi->screen_base;
+	screen_size = fbi->var.xres * fbi->var.yres;
+	if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+		memset(base, 0, screen_size);
+		base += screen_size;
+		for (i = 0; i < screen_size / 2; i++, base++)
+			*base = 0x80;
+	} else {
+		for (i = 0; i < screen_size * 2; i++, base++)
+			*base = 0x00;
+	}
+
+	console_lock();
+	fb_blank(fbi, FB_BLANK_UNBLANK);
+	console_unlock();
+
+	/* correct display ch buffer address */
+	ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+				0, fbi->fix.smem_start +
+				(fbi->fix.line_length * fbvar.yres));
+	ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+					1, fbi->fix.smem_start);
+
+	err = csi_enc_enabling_tasks(cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error csi enc enable fail\n");
+		return err;
+	}
+
+	cam->overlay_active = true;
+	return err;
+
+}
+
+/*!
+ * foreground_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_stop(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0, i = 0;
+	struct fb_info *fbi = NULL;
+	struct fb_var_screeninfo fbvar;
+	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (cam->overlay_active == false)
+		return 0;
+
+	err = ipu_disable_channel(cam->ipu, chan, true);
+
+	ipu_uninit_channel(cam->ipu, chan);
+
+	csi_buffer_num = 0;
+	buffer_num = 0;
+
+	for (i = 0; i < num_registered_fb; i++) {
+		char *idstr = registered_fb[i]->fix.id;
+		if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+		    ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+			fbi = registered_fb[i];
+			break;
+		}
+	}
+
+	if (fbi == NULL) {
+		printk(KERN_ERR "DISP FG fb not found\n");
+		return -EPERM;
+	}
+
+	console_lock();
+	fb_blank(fbi, FB_BLANK_POWERDOWN);
+	console_unlock();
+
+	/* Set the overlay frame buffer std to what it is used to be */
+	fbvar = fbi->var;
+	fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+	fbvar.nonstd = cam->fb_origin_std;
+	fbvar.activate |= FB_ACTIVATE_FORCE;
+	fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	flush_work(&cam->csi_work_struct);
+	cancel_work_sync(&cam->csi_work_struct);
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+
+	cam->overlay_active = false;
+	return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int foreground_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int foreground_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select foreground as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int foreground_sdc_select(void *private)
+{
+	cam_data *cam;
+	int err = 0;
+	if (private) {
+		cam = (cam_data *) private;
+		cam->vf_start_sdc = foreground_start;
+		cam->vf_stop_sdc = foreground_stop;
+		cam->vf_enable_csi = foreground_enable_csi;
+		cam->vf_disable_csi = foreground_disable_csi;
+		cam->overlay_active = false;
+	} else
+		err = -EIO;
+
+	return err;
+}
+EXPORT_SYMBOL(foreground_sdc_select);
+
+/*!
+ * function to de-select foreground as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  int
+ */
+int foreground_sdc_deselect(void *private)
+{
+	cam_data *cam;
+
+	if (private) {
+		cam = (cam_data *) private;
+		cam->vf_start_sdc = NULL;
+		cam->vf_stop_sdc = NULL;
+		cam->vf_enable_csi = NULL;
+		cam->vf_disable_csi = NULL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(foreground_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int foreground_sdc_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit foreground_sdc_exit(void)
+{
+}
+
+module_init(foreground_sdc_init);
+module_exit(foreground_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_prp_enc.c
@@ -0,0 +1,590 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_prp_enc.c
+ *
+ * @brief IPU Use case for PRP-ENC
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+	#define CAMERA_TRACE(x) (printk)x
+#else
+	#define CAMERA_TRACE(x)
+#endif
+
+static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * IPU ENC callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_enc_callback(int irq, void *dev_id)
+{
+	cam_data *cam = (cam_data *) dev_id;
+
+	if (cam->enc_callback == NULL)
+		return IRQ_HANDLED;
+
+	cam->enc_callback(irq, dev_id);
+
+	return IRQ_HANDLED;
+}
+
+/*!
+ * PrpENC enable channel setup function
+ *
+ * @param cam       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_setup(cam_data *cam)
+{
+	ipu_channel_params_t enc;
+	int err = 0;
+	dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	CAMERA_TRACE("In prp_enc_setup\n");
+	if (!cam) {
+		printk(KERN_ERR "cam private is NULL\n");
+		return -ENXIO;
+	}
+	memset(&enc, 0, sizeof(ipu_channel_params_t));
+
+	ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width,
+				&enc.csi_prp_enc_mem.in_height, cam->csi);
+
+	enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+	enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
+	enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height;
+	enc.csi_prp_enc_mem.csi = cam->csi;
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+		enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
+		enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
+	}
+
+	if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
+		pr_info("YUV420\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P;
+		pr_info("YVU420\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
+		pr_info("YUV422P\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
+		pr_info("YUYV\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
+		pr_info("UYVY\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
+		pr_info("NV12\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
+		pr_info("BGR24\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
+		pr_info("RGB24\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
+		pr_info("RGB565\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
+		pr_info("BGR32\n");
+	} else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
+		enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
+		pr_info("RGB32\n");
+	} else {
+		printk(KERN_ERR "format not supported\n");
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				enc.csi_prp_enc_mem.mipi_en = true;
+				enc.csi_prp_enc_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				enc.csi_prp_enc_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				enc.csi_prp_enc_mem.mipi_en = false;
+				enc.csi_prp_enc_mem.mipi_vc = 0;
+				enc.csi_prp_enc_mem.mipi_id = 0;
+			}
+		} else {
+			enc.csi_prp_enc_mem.mipi_en = false;
+			enc.csi_prp_enc_mem.mipi_vc = 0;
+			enc.csi_prp_enc_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
+	if (err != 0) {
+		printk(KERN_ERR "ipu_init_channel %d\n", err);
+		return err;
+	}
+
+	grotation = cam->rotation;
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+		if (cam->rot_enc_bufs_vaddr[0]) {
+			dma_free_coherent(cam->dev, cam->rot_enc_buf_size[0],
+					  cam->rot_enc_bufs_vaddr[0],
+					  cam->rot_enc_bufs[0]);
+		}
+		if (cam->rot_enc_bufs_vaddr[1]) {
+			dma_free_coherent(cam->dev, cam->rot_enc_buf_size[1],
+					  cam->rot_enc_bufs_vaddr[1],
+					  cam->rot_enc_bufs[1]);
+		}
+		cam->rot_enc_buf_size[0] =
+		    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+		cam->rot_enc_bufs_vaddr[0] =
+		    (void *)dma_alloc_coherent(cam->dev, cam->rot_enc_buf_size[0],
+					       &cam->rot_enc_bufs[0],
+					       GFP_DMA | GFP_KERNEL);
+		if (!cam->rot_enc_bufs_vaddr[0]) {
+			printk(KERN_ERR "alloc enc_bufs0\n");
+			return -ENOMEM;
+		}
+		cam->rot_enc_buf_size[1] =
+		    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+		cam->rot_enc_bufs_vaddr[1] =
+		    (void *)dma_alloc_coherent(cam->dev, cam->rot_enc_buf_size[1],
+					       &cam->rot_enc_bufs[1],
+					       GFP_DMA | GFP_KERNEL);
+		if (!cam->rot_enc_bufs_vaddr[1]) {
+			dma_free_coherent(cam->dev, cam->rot_enc_buf_size[0],
+					  cam->rot_enc_bufs_vaddr[0],
+					  cam->rot_enc_bufs[0]);
+			cam->rot_enc_bufs_vaddr[0] = NULL;
+			cam->rot_enc_bufs[0] = 0;
+			printk(KERN_ERR "alloc enc_bufs1\n");
+			return -ENOMEM;
+		}
+
+		err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      enc.csi_prp_enc_mem.out_pixel_fmt,
+					      enc.csi_prp_enc_mem.out_width,
+					      enc.csi_prp_enc_mem.out_height,
+					      enc.csi_prp_enc_mem.out_width,
+					      IPU_ROTATE_NONE,
+					      cam->rot_enc_bufs[0],
+					      cam->rot_enc_bufs[1], 0, 0, 0);
+		if (err != 0) {
+			printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
+			return err;
+		}
+
+		err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
+		if (err != 0) {
+			printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
+			return err;
+		}
+
+		err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+					      IPU_INPUT_BUFFER,
+					      enc.csi_prp_enc_mem.out_pixel_fmt,
+					      enc.csi_prp_enc_mem.out_width,
+					      enc.csi_prp_enc_mem.out_height,
+					      enc.csi_prp_enc_mem.out_width,
+					      cam->rotation,
+					      cam->rot_enc_bufs[0],
+					      cam->rot_enc_bufs[1], 0, 0, 0);
+		if (err != 0) {
+			printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
+			return err;
+		}
+
+		err =
+		    ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+					    IPU_OUTPUT_BUFFER,
+					    enc.csi_prp_enc_mem.out_pixel_fmt,
+					    enc.csi_prp_enc_mem.out_height,
+					    enc.csi_prp_enc_mem.out_width,
+					    cam->v2f.fmt.pix.bytesperline /
+					    bytes_per_pixel(enc.csi_prp_enc_mem.
+							    out_pixel_fmt),
+					    IPU_ROTATE_NONE,
+					    dummy, dummy, 0,
+					    cam->offset.u_offset,
+					    cam->offset.v_offset);
+		if (err != 0) {
+			printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
+			return err;
+		}
+
+		err = ipu_link_channels(cam->ipu,
+					CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+		if (err < 0) {
+			printk(KERN_ERR
+			       "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
+			return err;
+		}
+
+		err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+		if (err < 0) {
+			printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+			return err;
+		}
+		err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
+		if (err < 0) {
+			printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
+			return err;
+		}
+
+		ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+				  IPU_OUTPUT_BUFFER, 0);
+		ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+				  IPU_OUTPUT_BUFFER, 1);
+	} else {
+		err =
+		    ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+					    IPU_OUTPUT_BUFFER,
+					    enc.csi_prp_enc_mem.out_pixel_fmt,
+					    enc.csi_prp_enc_mem.out_width,
+					    enc.csi_prp_enc_mem.out_height,
+					    cam->v2f.fmt.pix.bytesperline /
+					    bytes_per_pixel(enc.csi_prp_enc_mem.
+							    out_pixel_fmt),
+					    cam->rotation,
+					    dummy, dummy, 0,
+					    cam->offset.u_offset,
+					    cam->offset.v_offset);
+		if (err != 0) {
+			printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
+			return err;
+		}
+		err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+		if (err < 0) {
+			printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+			return err;
+		}
+	}
+
+	return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param private     pointer to cam_data structure
+ * @param eba         physical buffer address for encorder IDMA channel
+ *
+ * @return  status
+ */
+static int prp_enc_eba_update(void *private, dma_addr_t eba)
+{
+	int err = 0;
+	cam_data *cam = (cam_data *) private;
+	struct ipu_soc *ipu = cam->ipu;
+	int *buffer_num = &cam->ping_pong_csi;
+
+	pr_debug("eba %x\n", eba);
+	if (grotation >= IPU_ROTATE_90_RIGHT) {
+		err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+						IPU_OUTPUT_BUFFER, *buffer_num,
+						eba);
+	} else {
+		err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+						IPU_OUTPUT_BUFFER, *buffer_num,
+						eba);
+	}
+	if (err != 0) {
+		if (grotation >= IPU_ROTATE_90_RIGHT) {
+			ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
+					       IPU_OUTPUT_BUFFER,
+					       *buffer_num);
+			err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+							IPU_OUTPUT_BUFFER,
+							*buffer_num,
+							eba);
+		} else {
+			ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
+					       IPU_OUTPUT_BUFFER,
+					       *buffer_num);
+			err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+							IPU_OUTPUT_BUFFER,
+							*buffer_num,
+							eba);
+		}
+
+		if (err != 0) {
+			pr_err("ERROR: v4l2 capture: fail to update "
+			       "buf%d\n", *buffer_num);
+			return err;
+		}
+	}
+
+	if (grotation >= IPU_ROTATE_90_RIGHT) {
+		ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
+				  *buffer_num);
+	} else {
+		ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
+				  *buffer_num);
+	}
+
+	*buffer_num = (*buffer_num == 0) ? 1 : 0;
+	return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_enabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+	CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
+
+	cam->dummy_frame.vaddress = dma_alloc_coherent(cam->dev,
+			       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+			       &cam->dummy_frame.paddress,
+			       GFP_DMA | GFP_KERNEL);
+	if (cam->dummy_frame.vaddress == 0) {
+		pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+		       "failed.\n");
+		return -ENOBUFS;
+	}
+	cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+	cam->dummy_frame.buffer.length =
+	    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+	cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+		err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
+				      prp_enc_callback, 0, "Mxc Camera", cam);
+	} else {
+		err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
+				      prp_enc_callback, 0, "Mxc Camera", cam);
+	}
+	if (err != 0) {
+		printk(KERN_ERR "Error registering rot irq\n");
+		return err;
+	}
+
+	err = prp_enc_setup(cam);
+	if (err != 0) {
+		printk(KERN_ERR "prp_enc_setup %d\n", err);
+		return err;
+	}
+
+	return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+static int prp_enc_disabling_tasks(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+		ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
+		ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+	}
+
+	err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+		err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
+
+	ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+		ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
+
+	if (cam->dummy_frame.vaddress != 0) {
+		dma_free_coherent(cam->dev, cam->dummy_frame.buffer.length,
+				  cam->dummy_frame.vaddress,
+				  cam->dummy_frame.paddress);
+		cam->dummy_frame.vaddress = 0;
+	}
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_enc_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	if (cam->rotation < IPU_ROTATE_90_RIGHT)
+		ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int prp_enc_select(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	if (cam) {
+		cam->enc_update_eba = prp_enc_eba_update;
+		cam->enc_enable = prp_enc_enabling_tasks;
+		cam->enc_disable = prp_enc_disabling_tasks;
+		cam->enc_enable_csi = prp_enc_enable_csi;
+		cam->enc_disable_csi = prp_enc_disable_csi;
+	} else {
+		err = -EIO;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(prp_enc_select);
+
+/*!
+ * function to de-select PRP-ENC as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  int
+ */
+int prp_enc_deselect(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	if (cam) {
+		cam->enc_update_eba = NULL;
+		cam->enc_enable = NULL;
+		cam->enc_disable = NULL;
+		cam->enc_enable_csi = NULL;
+		cam->enc_disable_csi = NULL;
+		if (cam->rot_enc_bufs_vaddr[0]) {
+			dma_free_coherent(cam->dev, cam->rot_enc_buf_size[0],
+					  cam->rot_enc_bufs_vaddr[0],
+					  cam->rot_enc_bufs[0]);
+			cam->rot_enc_bufs_vaddr[0] = NULL;
+			cam->rot_enc_bufs[0] = 0;
+		}
+		if (cam->rot_enc_bufs_vaddr[1]) {
+			dma_free_coherent(cam->dev, cam->rot_enc_buf_size[1],
+					  cam->rot_enc_bufs_vaddr[1],
+					  cam->rot_enc_bufs[1]);
+			cam->rot_enc_bufs_vaddr[1] = NULL;
+			cam->rot_enc_bufs[1] = 0;
+		}
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(prp_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_enc_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_enc_exit(void)
+{
+}
+
+module_init(prp_enc_init);
+module_exit(prp_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP ENC Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_prp_sw.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_prp_sw.h
+ *
+ * @brief This file contains the IPU PRP use case driver header.
+ *
+ * @ingroup IPU
+ */
+
+#ifndef _INCLUDE_IPU__PRP_SW_H_
+#define _INCLUDE_IPU__PRP_SW_H_
+
+int csi_enc_select(void *private);
+int csi_enc_deselect(void *private);
+int prp_enc_select(void *private);
+int prp_enc_deselect(void *private);
+#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+int prp_vf_sdc_select(void *private);
+int prp_vf_sdc_deselect(void *private);
+int prp_vf_sdc_select_bg(void *private);
+int prp_vf_sdc_deselect_bg(void *private);
+#else
+int foreground_sdc_select(void *private);
+int foreground_sdc_deselect(void *private);
+int bg_overlay_sdc_select(void *private);
+int bg_overlay_sdc_deselect(void *private);
+#endif
+int prp_still_select(void *private);
+int prp_still_deselect(void *private);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
@@ -0,0 +1,576 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <mach/hardware.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+	if (cam->output > 2)
+		disp_ipu = ipu_get_soc(1); /* using DISP4 */
+	else
+		disp_ipu = ipu_get_soc(0);
+}
+
+static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id)
+{
+	cam_data *cam = dev_id;
+	pr_debug("buffer_num %d\n",  buffer_num);
+
+	if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+		ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+				  IPU_INPUT_BUFFER, buffer_num);
+		buffer_num = (buffer_num == 0) ? 1 : 0;
+		ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+				  IPU_OUTPUT_BUFFER, buffer_num);
+	} else {
+		ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+				  IPU_INPUT_BUFFER, buffer_num);
+		buffer_num = (buffer_num == 0) ? 1 : 0;
+		ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+				  IPU_OUTPUT_BUFFER, buffer_num);
+	}
+	return IRQ_HANDLED;
+}
+/*
+ * Function definitions
+ */
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+	struct fb_var_screeninfo fbvar;
+	struct fb_info *fbi = NULL;
+	cam_data *cam = (cam_data *) private;
+	ipu_channel_params_t vf;
+	u32 vf_out_format = 0;
+	u32 size = 2, temp = 0;
+	int err = 0, i = 0;
+	short *tmp, color;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (!cam) {
+		printk(KERN_ERR "private is NULL\n");
+		return -EIO;
+	}
+
+	if (cam->overlay_active == true) {
+		pr_debug("already started.\n");
+		return 0;
+	}
+
+	get_disp_ipu(cam);
+
+	for (i = 0; i < num_registered_fb; i++) {
+		char *idstr = registered_fb[i]->fix.id;
+		if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+		    ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+			fbi = registered_fb[i];
+			break;
+		}
+	}
+
+	if (fbi == NULL) {
+		printk(KERN_ERR "DISP FG fb not found\n");
+		return -EPERM;
+	}
+
+	fbvar = fbi->var;
+
+	/* Store the overlay frame buffer's original std */
+	cam->fb_origin_std = fbvar.nonstd;
+
+	if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+		/* Use DP to do CSC so that we can get better performance */
+		vf_out_format = IPU_PIX_FMT_UYVY;
+		fbvar.nonstd = vf_out_format;
+		color = 0x80;
+	} else {
+		vf_out_format = IPU_PIX_FMT_RGB565;
+		fbvar.nonstd = 0;
+		color = 0x0;
+	}
+
+	fbvar.bits_per_pixel = 16;
+	fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+	fbvar.yres = cam->win.w.height;
+	fbvar.yres_virtual = cam->win.w.height * 2;
+	fbvar.yoffset = 0;
+	fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+	fbvar.activate |= FB_ACTIVATE_FORCE;
+	fb_set_var(fbi, &fbvar);
+
+	ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+			cam->win.w.top);
+
+	/* Fill black color for framebuffer */
+	tmp = (short *) fbi->screen_base;
+	for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2;
+			i++, tmp++)
+		*tmp = color;
+
+	console_lock();
+	fb_blank(fbi, FB_BLANK_UNBLANK);
+	console_unlock();
+
+	/* correct display ch buffer address */
+	ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+				0, fbi->fix.smem_start +
+				(fbi->fix.line_length * fbvar.yres));
+	ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+					1, fbi->fix.smem_start);
+
+	memset(&vf, 0, sizeof(ipu_channel_params_t));
+	ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+				&vf.csi_prp_vf_mem.in_height, cam->csi);
+	vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+	vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+	vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+	vf.csi_prp_vf_mem.csi = cam->csi;
+	if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+		vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+		vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+	}
+	vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format;
+	size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				vf.csi_prp_vf_mem.mipi_en = true;
+				vf.csi_prp_vf_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				vf.csi_prp_vf_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				vf.csi_prp_vf_mem.mipi_en = false;
+				vf.csi_prp_vf_mem.mipi_vc = 0;
+				vf.csi_prp_vf_mem.mipi_id = 0;
+			}
+		} else {
+			vf.csi_prp_vf_mem.mipi_en = false;
+			vf.csi_prp_vf_mem.mipi_vc = 0;
+			vf.csi_prp_vf_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+	if (err != 0)
+		goto out_5;
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+	}
+	cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+	cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[0],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[0],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[0] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_4;
+	}
+	cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+	cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[1],
+							   (dma_addr_t *) &
+							   cam->vf_bufs[1],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[1] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_3;
+	}
+	pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+	if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+		err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      vf_out_format,
+					      vf.csi_prp_vf_mem.out_width,
+					      vf.csi_prp_vf_mem.out_height,
+					      vf.csi_prp_vf_mem.out_width,
+					      IPU_ROTATE_NONE,
+					      cam->vf_bufs[0], cam->vf_bufs[1],
+					      0, 0, 0);
+		if (err != 0)
+			goto out_3;
+
+		err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+		if (err != 0) {
+			printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+			goto out_3;
+		}
+
+		err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+					      IPU_INPUT_BUFFER,
+					      vf_out_format,
+					      vf.csi_prp_vf_mem.out_width,
+					      vf.csi_prp_vf_mem.out_height,
+					      vf.csi_prp_vf_mem.out_width,
+					      cam->vf_rotation,
+					      cam->vf_bufs[0],
+					      cam->vf_bufs[1],
+					      0, 0, 0);
+		if (err != 0) {
+			printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+			goto out_2;
+		}
+
+		if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
+			temp = vf.csi_prp_vf_mem.out_width;
+			vf.csi_prp_vf_mem.out_width =
+						vf.csi_prp_vf_mem.out_height;
+			vf.csi_prp_vf_mem.out_height = temp;
+		}
+
+		err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      vf_out_format,
+					      vf.csi_prp_vf_mem.out_height,
+					      vf.csi_prp_vf_mem.out_width,
+					      vf.csi_prp_vf_mem.out_height,
+					      IPU_ROTATE_NONE,
+					      fbi->fix.smem_start +
+					      (fbi->fix.line_length *
+					       fbi->var.yres),
+					      fbi->fix.smem_start, 0, 0, 0);
+
+		if (err != 0) {
+			printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+			goto out_2;
+		}
+
+		ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
+		err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
+				      prpvf_rot_eof_callback,
+			      0, "Mxc Camera", cam);
+		if (err < 0) {
+			printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
+			goto out_2;
+		}
+
+		err = ipu_link_channels(cam->ipu,
+					CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+		if (err < 0) {
+			printk(KERN_ERR
+			       "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
+			goto out_1;
+		}
+
+		ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+		ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+		ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+				  IPU_OUTPUT_BUFFER, 0);
+		ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+				  IPU_OUTPUT_BUFFER, 1);
+		ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+				  IPU_OUTPUT_BUFFER, 0);
+	} else {
+		err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      vf_out_format, cam->win.w.width,
+					      cam->win.w.height,
+					      cam->win.w.width,
+					      cam->vf_rotation,
+					      fbi->fix.smem_start +
+					      (fbi->fix.line_length *
+					       fbi->var.yres),
+					      fbi->fix.smem_start, 0, 0, 0);
+		if (err != 0) {
+			printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+			goto out_4;
+		}
+		ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+		err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+				      prpvf_rot_eof_callback,
+			      0, "Mxc Camera", cam);
+		if (err < 0) {
+			printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
+			goto out_4;
+		}
+
+		ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+		ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+				  IPU_OUTPUT_BUFFER, 0);
+	}
+
+	cam->overlay_active = true;
+	return err;
+
+out_1:
+	ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+	if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
+		ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+out_4:
+	ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_5:
+	return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0, i = 0;
+	struct fb_info *fbi = NULL;
+	struct fb_var_screeninfo fbvar;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (cam->overlay_active == false)
+		return 0;
+
+	for (i = 0; i < num_registered_fb; i++) {
+		char *idstr = registered_fb[i]->fix.id;
+		if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+		    ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+			fbi = registered_fb[i];
+			break;
+		}
+	}
+
+	if (fbi == NULL) {
+		printk(KERN_ERR "DISP FG fb not found\n");
+		return -EPERM;
+	}
+
+	if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+		ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+		ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
+	}
+	buffer_num = 0;
+
+	ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+
+	if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+		ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+		ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+	}
+	ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+	console_lock();
+	fb_blank(fbi, FB_BLANK_POWERDOWN);
+	console_unlock();
+
+	/* Set the overlay frame buffer std to what it is used to be */
+	fbvar = fbi->var;
+	fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+	fbvar.nonstd = cam->fb_origin_std;
+	fbvar.activate |= FB_ACTIVATE_FORCE;
+	fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0],
+				  (dma_addr_t) cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1],
+				  (dma_addr_t) cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+
+	cam->overlay_active = false;
+	return err;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
+		ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_select(void *private)
+{
+	cam_data *cam;
+	int err = 0;
+	if (private) {
+		cam = (cam_data *) private;
+		cam->vf_start_sdc = prpvf_start;
+		cam->vf_stop_sdc = prpvf_stop;
+		cam->vf_enable_csi = prp_vf_enable_csi;
+		cam->vf_disable_csi = prp_vf_disable_csi;
+		cam->overlay_active = false;
+	} else
+		err = -EIO;
+
+	return err;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  int
+ */
+int prp_vf_sdc_deselect(void *private)
+{
+	cam_data *cam;
+
+	if (private) {
+		cam = (cam_data *) private;
+		cam->vf_start_sdc = NULL;
+		cam->vf_stop_sdc = NULL;
+		cam->vf_enable_csi = NULL;
+		cam->vf_disable_csi = NULL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit(void)
+{
+}
+
+module_init(prp_vf_sdc_init);
+module_exit(prp_vf_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
@@ -0,0 +1,514 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static int buffer_ready;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+	if (cam->output > 2)
+		disp_ipu = ipu_get_soc(1); /* using DISP4 */
+	else
+		disp_ipu = ipu_get_soc(0);
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * SDC V-Sync callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
+{
+	cam_data *cam = dev_id;
+	if (buffer_ready > 0) {
+		ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+				  IPU_OUTPUT_BUFFER, 0);
+		buffer_ready--;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*!
+ * VF EOF callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
+{
+	cam_data *cam = dev_id;
+	pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
+
+	ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+			  IPU_INPUT_BUFFER, buffer_num);
+	buffer_num = (buffer_num == 0) ? 1 : 0;
+	ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+			  IPU_OUTPUT_BUFFER, buffer_num);
+	buffer_ready++;
+	return IRQ_HANDLED;
+}
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	ipu_channel_params_t vf;
+	u32 format;
+	u32 offset;
+	u32 bpp, size = 3;
+	int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (!cam) {
+		printk(KERN_ERR "private is NULL\n");
+		return -EIO;
+	}
+
+	if (cam->overlay_active == true) {
+		pr_debug("already start.\n");
+		return 0;
+	}
+
+	get_disp_ipu(cam);
+
+	format = cam->v4l2_fb.fmt.pixelformat;
+	if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+		bpp = 3, size = 3;
+		pr_info("BGR24\n");
+	} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+		bpp = 2, size = 2;
+		pr_info("RGB565\n");
+	} else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+		bpp = 4, size = 4;
+		pr_info("BGR32\n");
+	} else {
+		printk(KERN_ERR
+		       "unsupported fix format from the framebuffer.\n");
+		return -EINVAL;
+	}
+
+	offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+	    size * cam->win.w.left;
+
+	if (cam->v4l2_fb.base == 0)
+		printk(KERN_ERR "invalid frame buffer address.\n");
+	else
+		offset += (u32) cam->v4l2_fb.base;
+
+	memset(&vf, 0, sizeof(ipu_channel_params_t));
+	ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+				&vf.csi_prp_vf_mem.in_height, cam->csi);
+	vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+	vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+	vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+	vf.csi_prp_vf_mem.csi = cam->csi;
+	if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+		vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+		vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+	}
+	vf.csi_prp_vf_mem.out_pixel_fmt = format;
+	size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id) {
+				vf.csi_prp_vf_mem.mipi_en = true;
+				vf.csi_prp_vf_mem.mipi_vc =
+				mipi_csi2_get_virtual_channel(mipi_csi2_info);
+				vf.csi_prp_vf_mem.mipi_id =
+				mipi_csi2_get_datatype(mipi_csi2_info);
+
+				mipi_csi2_pixelclk_enable(mipi_csi2_info);
+			} else {
+				vf.csi_prp_vf_mem.mipi_en = false;
+				vf.csi_prp_vf_mem.mipi_vc = 0;
+				vf.csi_prp_vf_mem.mipi_id = 0;
+			}
+		} else {
+			vf.csi_prp_vf_mem.mipi_en = false;
+			vf.csi_prp_vf_mem.mipi_vc = 0;
+			vf.csi_prp_vf_mem.mipi_id = 0;
+		}
+	}
+#endif
+
+	err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+	if (err != 0)
+		goto out_4;
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+	}
+	cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+	cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[0],
+							   &cam->vf_bufs[0],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[0] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_3;
+	}
+	cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+	cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(cam->dev,
+							   cam->vf_bufs_size[1],
+							   &cam->vf_bufs[1],
+							   GFP_DMA |
+							   GFP_KERNEL);
+	if (cam->vf_bufs_vaddr[1] == NULL) {
+		printk(KERN_ERR "Error to allocate vf buffer\n");
+		err = -ENOMEM;
+		goto out_3;
+	}
+
+	err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+				      IPU_OUTPUT_BUFFER,
+				      format, vf.csi_prp_vf_mem.out_width,
+				      vf.csi_prp_vf_mem.out_height,
+				      vf.csi_prp_vf_mem.out_width,
+				      IPU_ROTATE_NONE,
+				      cam->vf_bufs[0],
+				      cam->vf_bufs[1],
+				      0, 0, 0);
+	if (err != 0) {
+		printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+		goto out_3;
+	}
+	err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+	if (err != 0) {
+		printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+		goto out_3;
+	}
+
+	err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+				      IPU_INPUT_BUFFER,
+				      format, vf.csi_prp_vf_mem.out_width,
+				      vf.csi_prp_vf_mem.out_height,
+				      vf.csi_prp_vf_mem.out_width,
+				      cam->vf_rotation,
+				      cam->vf_bufs[0],
+				      cam->vf_bufs[1],
+				      0, 0, 0);
+	if (err != 0) {
+		printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+		goto out_2;
+	}
+
+	if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+		err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      format,
+					      vf.csi_prp_vf_mem.out_height,
+					      vf.csi_prp_vf_mem.out_width,
+					      cam->overlay_fb->var.xres * bpp,
+					      IPU_ROTATE_NONE,
+					      offset, 0, 0, 0, 0);
+
+		if (err != 0) {
+			printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+			goto out_2;
+		}
+	} else {
+		err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+					      IPU_OUTPUT_BUFFER,
+					      format,
+					      vf.csi_prp_vf_mem.out_width,
+					      vf.csi_prp_vf_mem.out_height,
+					      cam->overlay_fb->var.xres * bpp,
+					      IPU_ROTATE_NONE,
+					      offset, 0, 0, 0, 0);
+		if (err != 0) {
+			printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+			goto out_2;
+		}
+	}
+
+	ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+	err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+			      prpvf_vf_eof_callback,
+			      0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR
+		       "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
+		goto out_2;
+	}
+
+	ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
+	err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
+			      prpvf_sdc_vsync_callback,
+			      0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
+		goto out_1;
+	}
+
+	ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+	ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+	buffer_num = 0;
+	buffer_ready = 0;
+	ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
+
+	cam->overlay_active = true;
+	return err;
+
+out_1:
+	ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+	ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+	ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_4:
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[0],
+				  cam->rot_vf_bufs_vaddr[0],
+				  cam->rot_vf_bufs[0]);
+		cam->rot_vf_bufs_vaddr[0] = NULL;
+		cam->rot_vf_bufs[0] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[1],
+				  cam->rot_vf_bufs_vaddr[1],
+				  cam->rot_vf_bufs[1]);
+		cam->rot_vf_bufs_vaddr[1] = NULL;
+		cam->rot_vf_bufs[1] = 0;
+	}
+	return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+#ifdef CONFIG_MXC_MIPI_CSI2
+	void *mipi_csi2_info;
+	int ipu_id;
+	int csi_id;
+#endif
+
+	if (cam->overlay_active == false)
+		return 0;
+
+	ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
+
+	ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+	ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+	ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+	ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	if (mipi_csi2_info) {
+		if (mipi_csi2_get_status(mipi_csi2_info)) {
+			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+			if (cam->ipu == ipu_get_soc(ipu_id)
+				&& cam->csi == csi_id)
+				mipi_csi2_pixelclk_disable(mipi_csi2_info);
+		}
+	}
+#endif
+
+	if (cam->vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[0],
+				  cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+		cam->vf_bufs_vaddr[0] = NULL;
+		cam->vf_bufs[0] = 0;
+	}
+	if (cam->vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->vf_bufs_size[1],
+				  cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+		cam->vf_bufs_vaddr[1] = NULL;
+		cam->vf_bufs[1] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[0]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[0],
+				  cam->rot_vf_bufs_vaddr[0],
+				  cam->rot_vf_bufs[0]);
+		cam->rot_vf_bufs_vaddr[0] = NULL;
+		cam->rot_vf_bufs[0] = 0;
+	}
+	if (cam->rot_vf_bufs_vaddr[1]) {
+		dma_free_coherent(cam->dev, cam->rot_vf_buf_size[1],
+				  cam->rot_vf_bufs_vaddr[1],
+				  cam->rot_vf_bufs[1]);
+		cam->rot_vf_bufs_vaddr[1] = NULL;
+		cam->rot_vf_bufs[1] = 0;
+	}
+
+	buffer_num = 0;
+	buffer_ready = 0;
+	cam->overlay_active = false;
+	return 0;
+}
+
+/*!
+ * Enable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	/* free csi eof irq firstly.
+	 * when disable csi, wait for idmac eof.
+	 * it requests eof irq again */
+	ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+	return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_select_bg(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	if (cam) {
+		cam->vf_start_sdc = prpvf_start;
+		cam->vf_stop_sdc = prpvf_stop;
+		cam->vf_enable_csi = prp_vf_enable_csi;
+		cam->vf_disable_csi = prp_vf_disable_csi;
+		cam->overlay_active = false;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select_bg);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private    cam_data * mxc v4l2 main structure
+ *
+ * @return  status
+ */
+int prp_vf_sdc_deselect_bg(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	if (cam) {
+		cam->vf_start_sdc = NULL;
+		cam->vf_stop_sdc = NULL;
+		cam->vf_enable_csi = NULL;
+		cam->vf_disable_csi = NULL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init_bg(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return  Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit_bg(void)
+{
+}
+
+module_init(prp_vf_sdc_init_bg);
+module_exit(prp_vf_sdc_exit_bg);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ipu_still.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ipu_still.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file ipu_still.c
+ *
+ * @brief IPU Use case for still image capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+#include <linux/ipu.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int callback_eof_flag;
+#ifndef CONFIG_MXC_IPU_V1
+static int buffer_num;
+#endif
+
+#ifdef CONFIG_MXC_IPU_V1
+static int callback_flag;
+/*
+ * Function definitions
+ */
+/*!
+ * CSI EOF callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id)
+{
+	cam_data *cam = devid;
+	ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+			  callback_flag%2 ? 1 : 0);
+	if (callback_flag == 0)
+		ipu_enable_channel(cam->ipu, CSI_MEM);
+
+	callback_flag++;
+	return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * CSI callback function.
+ *
+ * @param irq       int irq line
+ * @param dev_id    void * device id
+ *
+ * @return status   IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_still_callback(int irq, void *dev_id)
+{
+	cam_data *cam = (cam_data *) dev_id;
+
+	callback_eof_flag++;
+	if (callback_eof_flag < 5) {
+#ifndef CONFIG_MXC_IPU_V1
+		buffer_num = (buffer_num == 0) ? 1 : 0;
+		ipu_select_buffer(cam->ipu, CSI_MEM,
+				  IPU_OUTPUT_BUFFER, buffer_num);
+#endif
+	} else {
+		cam->still_counter++;
+		wake_up_interruptible(&cam->still_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*!
+ * start csi->mem task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_still_start(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	u32 pixel_fmt;
+	int err;
+	ipu_channel_params_t params;
+
+	if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+		pixel_fmt = IPU_PIX_FMT_YUV420P;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+		pixel_fmt = IPU_PIX_FMT_NV12;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+		pixel_fmt = IPU_PIX_FMT_YUV422P;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+		pixel_fmt = IPU_PIX_FMT_UYVY;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+		pixel_fmt = IPU_PIX_FMT_YUYV;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+		pixel_fmt = IPU_PIX_FMT_BGR24;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+		pixel_fmt = IPU_PIX_FMT_RGB24;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+		pixel_fmt = IPU_PIX_FMT_RGB565;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+		pixel_fmt = IPU_PIX_FMT_BGR32;
+	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+		pixel_fmt = IPU_PIX_FMT_RGB32;
+	else {
+		printk(KERN_ERR "format not supported\n");
+		return -EINVAL;
+	}
+
+	memset(&params, 0, sizeof(params));
+	err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+	if (err != 0)
+		return err;
+
+	err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+				      pixel_fmt, cam->v2f.fmt.pix.width,
+				      cam->v2f.fmt.pix.height,
+				      cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
+				      cam->still_buf[0], cam->still_buf[1], 0,
+				      0, 0);
+	if (err != 0)
+		return err;
+
+#ifdef CONFIG_MXC_IPU_V1
+	ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF);
+	err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback,
+			      0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering irq.\n");
+		return err;
+	}
+	callback_flag = 0;
+	callback_eof_flag = 0;
+	ipu_clear_irq(IPU_IRQ_SENSOR_EOF);
+	err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback,
+			      0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n");
+		return err;
+	}
+#else
+	callback_eof_flag = 0;
+	buffer_num = 0;
+
+	ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+	err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+			      prp_still_callback,
+			      0, "Mxc Camera", cam);
+	if (err != 0) {
+		printk(KERN_ERR "Error registering irq.\n");
+		return err;
+	}
+
+	ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+	ipu_enable_channel(cam->ipu, CSI_MEM);
+	ipu_enable_csi(cam->ipu, cam->csi);
+#endif
+
+	return err;
+}
+
+/*!
+ * stop csi->mem encoder task
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+static int prp_still_stop(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+#ifdef CONFIG_MXC_IPU_V1
+	ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL);
+	ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam);
+#else
+	ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+#endif
+
+	ipu_disable_csi(cam->ipu, cam->csi);
+	ipu_disable_channel(cam->ipu, CSI_MEM, true);
+	ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+	return err;
+}
+
+/*!
+ * function to select CSI_MEM as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+int prp_still_select(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+
+	if (cam) {
+		cam->csi_start = prp_still_start;
+		cam->csi_stop = prp_still_stop;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(prp_still_select);
+
+/*!
+ * function to de-select CSI_MEM as the working path
+ *
+ * @param private       struct cam_data * mxc capture instance
+ *
+ * @return  status
+ */
+int prp_still_deselect(void *private)
+{
+	cam_data *cam = (cam_data *) private;
+	int err = 0;
+
+	err = prp_still_stop(cam);
+
+	if (cam) {
+		cam->csi_start = NULL;
+		cam->csi_stop = NULL;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(prp_still_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return  Error code indicating success or failure
+ */
+__init int prp_still_init(void)
+{
+	return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_still_exit(void)
+{
+}
+
+module_init(prp_still_init);
+module_exit(prp_still_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mx6s_capture.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mx6s_capture.c
@@ -0,0 +1,2040 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file mx6s_csi.c
+ *
+ * @brief mx6sx CMOS Sensor interface functions
+ *
+ * @ingroup CSI
+ */
+#include <asm/dma.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gcd.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/media-bus-format.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MX6S_CAM_DRV_NAME "mx6s-csi"
+#define MX6S_CAM_VERSION "0.0.1"
+#define MX6S_CAM_DRIVER_DESCRIPTION "i.MX6S_CSI"
+
+#define MAX_VIDEO_MEM 64
+
+/* reset values */
+#define CSICR1_RESET_VAL	0x40000800
+#define CSICR2_RESET_VAL	0x0
+#define CSICR3_RESET_VAL	0x0
+
+/* csi control reg 1 */
+#define BIT_SWAP16_EN		(0x1 << 31)
+#define BIT_EXT_VSYNC		(0x1 << 30)
+#define BIT_EOF_INT_EN		(0x1 << 29)
+#define BIT_PRP_IF_EN		(0x1 << 28)
+#define BIT_CCIR_MODE		(0x1 << 27)
+#define BIT_COF_INT_EN		(0x1 << 26)
+#define BIT_SF_OR_INTEN		(0x1 << 25)
+#define BIT_RF_OR_INTEN		(0x1 << 24)
+#define BIT_SFF_DMA_DONE_INTEN  (0x1 << 22)
+#define BIT_STATFF_INTEN	(0x1 << 21)
+#define BIT_FB2_DMA_DONE_INTEN  (0x1 << 20)
+#define BIT_FB1_DMA_DONE_INTEN  (0x1 << 19)
+#define BIT_RXFF_INTEN		(0x1 << 18)
+#define BIT_SOF_POL		(0x1 << 17)
+#define BIT_SOF_INTEN		(0x1 << 16)
+#define BIT_MCLKDIV		(0xF << 12)
+#define BIT_HSYNC_POL		(0x1 << 11)
+#define BIT_CCIR_EN		(0x1 << 10)
+#define BIT_MCLKEN		(0x1 << 9)
+#define BIT_FCC			(0x1 << 8)
+#define BIT_PACK_DIR		(0x1 << 7)
+#define BIT_CLR_STATFIFO	(0x1 << 6)
+#define BIT_CLR_RXFIFO		(0x1 << 5)
+#define BIT_GCLK_MODE		(0x1 << 4)
+#define BIT_INV_DATA		(0x1 << 3)
+#define BIT_INV_PCLK		(0x1 << 2)
+#define BIT_REDGE		(0x1 << 1)
+#define BIT_PIXEL_BIT		(0x1 << 0)
+
+#define SHIFT_MCLKDIV		12
+
+/* control reg 3 */
+#define BIT_FRMCNT		(0xFFFF << 16)
+#define BIT_FRMCNT_RST		(0x1 << 15)
+#define BIT_DMA_REFLASH_RFF	(0x1 << 14)
+#define BIT_DMA_REFLASH_SFF	(0x1 << 13)
+#define BIT_DMA_REQ_EN_RFF	(0x1 << 12)
+#define BIT_DMA_REQ_EN_SFF	(0x1 << 11)
+#define BIT_STATFF_LEVEL	(0x7 << 8)
+#define BIT_HRESP_ERR_EN	(0x1 << 7)
+#define BIT_RXFF_LEVEL		(0x7 << 4)
+#define BIT_TWO_8BIT_SENSOR	(0x1 << 3)
+#define BIT_ZERO_PACK_EN	(0x1 << 2)
+#define BIT_ECC_INT_EN		(0x1 << 1)
+#define BIT_ECC_AUTO_EN		(0x1 << 0)
+
+#define SHIFT_FRMCNT		16
+#define SHIFT_RXFIFO_LEVEL	4
+
+/* csi status reg */
+#define BIT_ADDR_CH_ERR_INT (0x1 << 28)
+#define BIT_FIELD0_INT      (0x1 << 27)
+#define BIT_FIELD1_INT      (0x1 << 26)
+#define BIT_SFF_OR_INT		(0x1 << 25)
+#define BIT_RFF_OR_INT		(0x1 << 24)
+#define BIT_DMA_TSF_DONE_SFF	(0x1 << 22)
+#define BIT_STATFF_INT		(0x1 << 21)
+#define BIT_DMA_TSF_DONE_FB2	(0x1 << 20)
+#define BIT_DMA_TSF_DONE_FB1	(0x1 << 19)
+#define BIT_RXFF_INT		(0x1 << 18)
+#define BIT_EOF_INT		(0x1 << 17)
+#define BIT_SOF_INT		(0x1 << 16)
+#define BIT_F2_INT		(0x1 << 15)
+#define BIT_F1_INT		(0x1 << 14)
+#define BIT_COF_INT		(0x1 << 13)
+#define BIT_HRESP_ERR_INT	(0x1 << 7)
+#define BIT_ECC_INT		(0x1 << 1)
+#define BIT_DRDY		(0x1 << 0)
+
+/* csi control reg 18 */
+#define BIT_CSI_ENABLE			(0x1 << 31)
+#define BIT_MIPI_DATA_FORMAT_RAW8		(0x2a << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW10		(0x2b << 25)
+#define BIT_MIPI_DATA_FORMAT_YUV422_8B	(0x1e << 25)
+#define BIT_MIPI_DATA_FORMAT_MASK	(0x3F << 25)
+#define BIT_MIPI_DATA_FORMAT_OFFSET	25
+#define BIT_DATA_FROM_MIPI		(0x1 << 22)
+#define BIT_MIPI_YU_SWAP		(0x1 << 21)
+#define BIT_MIPI_DOUBLE_CMPNT	(0x1 << 20)
+#define BIT_BASEADDR_CHG_ERR_EN	(0x1 << 9)
+#define BIT_BASEADDR_SWITCH_SEL	(0x1 << 5)
+#define BIT_BASEADDR_SWITCH_EN	(0x1 << 4)
+#define BIT_PARALLEL24_EN		(0x1 << 3)
+#define BIT_DEINTERLACE_EN		(0x1 << 2)
+#define BIT_TVDECODER_IN_EN		(0x1 << 1)
+#define BIT_NTSC_EN				(0x1 << 0)
+
+#define CSI_MCLK_VF		1
+#define CSI_MCLK_ENC		2
+#define CSI_MCLK_RAW		4
+#define CSI_MCLK_I2C		8
+
+#define CSI_CSICR1		0x0
+#define CSI_CSICR2		0x4
+#define CSI_CSICR3		0x8
+#define CSI_STATFIFO		0xC
+#define CSI_CSIRXFIFO		0x10
+#define CSI_CSIRXCNT		0x14
+#define CSI_CSISR		0x18
+
+#define CSI_CSIDBG		0x1C
+#define CSI_CSIDMASA_STATFIFO	0x20
+#define CSI_CSIDMATS_STATFIFO	0x24
+#define CSI_CSIDMASA_FB1	0x28
+#define CSI_CSIDMASA_FB2	0x2C
+#define CSI_CSIFBUF_PARA	0x30
+#define CSI_CSIIMAG_PARA	0x34
+
+#define CSI_CSICR18		0x48
+#define CSI_CSICR19		0x4c
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+#define MX6SX_MAX_SENSORS    1
+
+struct csi_signal_cfg_t {
+	unsigned data_width:3;
+	unsigned clk_mode:2;
+	unsigned ext_vsync:1;
+	unsigned Vsync_pol:1;
+	unsigned Hsync_pol:1;
+	unsigned pixclk_pol:1;
+	unsigned data_pol:1;
+	unsigned sens_clksrc:1;
+};
+
+struct csi_config_t {
+	/* control reg 1 */
+	unsigned int swap16_en:1;
+	unsigned int ext_vsync:1;
+	unsigned int eof_int_en:1;
+	unsigned int prp_if_en:1;
+	unsigned int ccir_mode:1;
+	unsigned int cof_int_en:1;
+	unsigned int sf_or_inten:1;
+	unsigned int rf_or_inten:1;
+	unsigned int sff_dma_done_inten:1;
+	unsigned int statff_inten:1;
+	unsigned int fb2_dma_done_inten:1;
+	unsigned int fb1_dma_done_inten:1;
+	unsigned int rxff_inten:1;
+	unsigned int sof_pol:1;
+	unsigned int sof_inten:1;
+	unsigned int mclkdiv:4;
+	unsigned int hsync_pol:1;
+	unsigned int ccir_en:1;
+	unsigned int mclken:1;
+	unsigned int fcc:1;
+	unsigned int pack_dir:1;
+	unsigned int gclk_mode:1;
+	unsigned int inv_data:1;
+	unsigned int inv_pclk:1;
+	unsigned int redge:1;
+	unsigned int pixel_bit:1;
+
+	/* control reg 3 */
+	unsigned int frmcnt:16;
+	unsigned int frame_reset:1;
+	unsigned int dma_reflash_rff:1;
+	unsigned int dma_reflash_sff:1;
+	unsigned int dma_req_en_rff:1;
+	unsigned int dma_req_en_sff:1;
+	unsigned int statff_level:3;
+	unsigned int hresp_err_en:1;
+	unsigned int rxff_level:3;
+	unsigned int two_8bit_sensor:1;
+	unsigned int zero_pack_en:1;
+	unsigned int ecc_int_en:1;
+	unsigned int ecc_auto_en:1;
+	/* fifo counter */
+	unsigned int rxcnt;
+};
+
+/*
+ * Basic structures
+ */
+struct mx6s_fmt {
+	char  name[32];
+	u32   fourcc;		/* v4l2 format id */
+	u32   pixelformat;
+	u32   mbus_code;
+	int   bpp;
+};
+
+static struct mx6s_fmt formats[] = {
+	{
+		.name		= "UYVY-16",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.pixelformat	= V4L2_PIX_FMT_UYVY,
+		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
+		.bpp		= 2,
+	}, {
+		.name		= "YUYV-16",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
+		.bpp		= 2,
+	}, {
+		.name		= "YUV32 (X-Y-U-V)",
+		.fourcc		= V4L2_PIX_FMT_YUV32,
+		.pixelformat	= V4L2_PIX_FMT_YUV32,
+		.mbus_code	= MEDIA_BUS_FMT_AYUV8_1X32,
+		.bpp		= 4,
+	}, {
+		.name		= "RAWRGB8 (SBGGR8)",
+		.fourcc		= V4L2_PIX_FMT_SBGGR8,
+		.pixelformat	= V4L2_PIX_FMT_SBGGR8,
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
+		.bpp		= 1,
+	}, {
+		.name		= "RAW 8",
+		.fourcc		= V4L2_PIX_FMT_GREY,
+		.pixelformat	= V4L2_PIX_FMT_GREY,
+		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
+		.bpp		= 1,
+	}
+};
+
+struct mx6s_buf_internal {
+	struct list_head	queue;
+	int					bufnum;
+	bool				discard;
+};
+
+/* buffer for one video frame */
+struct mx6s_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_v4l2_buffer			vb;
+	struct mx6s_buf_internal	internal;
+};
+
+struct mx6s_csi_mux {
+	struct regmap *gpr;
+	u8 req_gpr;
+	u8 req_bit;
+};
+
+struct mx6s_csi_soc {
+	bool rx_fifo_rst;
+	int baseaddr_switch;
+};
+
+struct mx6s_csi_dev {
+	struct device		*dev;
+	struct video_device *vdev;
+	struct v4l2_subdev	*sd;
+	struct v4l2_device	v4l2_dev;
+
+	struct vb2_queue			vb2_vidq;
+	struct v4l2_ctrl_handler	ctrl_handler;
+
+	struct mutex		lock;
+	spinlock_t			slock;
+
+	int open_count;
+
+	/* clock */
+	struct clk	*clk_disp_axi;
+	struct clk	*clk_disp_dcic;
+	struct clk	*clk_csi_mclk;
+
+	void __iomem *regbase;
+	int irq;
+
+	u32      nextfb;
+	u32      skipframe;
+	u32	 type;
+	u32 bytesperline;
+	v4l2_std_id std;
+	struct mx6s_fmt		*fmt;
+	struct v4l2_pix_format pix;
+	u32 mbus_code;
+
+	unsigned int frame_count;
+
+	struct list_head	capture;
+	struct list_head	active_bufs;
+	struct list_head	discard;
+
+	void						*discard_buffer;
+	dma_addr_t					discard_buffer_dma;
+	size_t						discard_size;
+	struct mx6s_buf_internal	buf_discard[2];
+
+	struct v4l2_async_subdev	asd;
+	struct v4l2_async_notifier	subdev_notifier;
+
+	bool csi_mipi_mode;
+	bool csi_two_8bit_sensor_mode;
+	const struct mx6s_csi_soc *soc;
+	struct mx6s_csi_mux csi_mux;
+};
+
+static const struct of_device_id mx6s_csi_dt_ids[];
+
+static inline int csi_read(struct mx6s_csi_dev *csi, unsigned int offset)
+{
+	return __raw_readl(csi->regbase + offset);
+}
+static inline void csi_write(struct mx6s_csi_dev *csi, unsigned int value,
+			     unsigned int offset)
+{
+	__raw_writel(value, csi->regbase + offset);
+}
+
+static inline struct mx6s_csi_dev
+				*notifier_to_mx6s_dev(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct mx6s_csi_dev, subdev_notifier);
+}
+
+struct mx6s_fmt *format_by_fourcc(int fourcc)
+{
+	int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].pixelformat == fourcc)
+			return formats + i;
+	}
+
+	pr_err("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+	return NULL;
+}
+
+struct mx6s_fmt *format_by_mbus(u32 code)
+{
+	int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].mbus_code == code)
+			return formats + i;
+	}
+
+	pr_err("unknown mbus:0x%x\n", code);
+	return NULL;
+}
+
+static struct mx6s_buffer *mx6s_ibuf_to_buf(struct mx6s_buf_internal *int_buf)
+{
+	return container_of(int_buf, struct mx6s_buffer, internal);
+}
+
+void csi_clk_enable(struct mx6s_csi_dev *csi_dev)
+{
+	clk_prepare_enable(csi_dev->clk_disp_axi);
+	clk_prepare_enable(csi_dev->clk_disp_dcic);
+	clk_prepare_enable(csi_dev->clk_csi_mclk);
+}
+
+void csi_clk_disable(struct mx6s_csi_dev *csi_dev)
+{
+	clk_disable_unprepare(csi_dev->clk_csi_mclk);
+	clk_disable_unprepare(csi_dev->clk_disp_dcic);
+	clk_disable_unprepare(csi_dev->clk_disp_axi);
+}
+
+static void csihw_reset(struct mx6s_csi_dev *csi_dev)
+{
+	__raw_writel(__raw_readl(csi_dev->regbase + CSI_CSICR3)
+			| BIT_FRMCNT_RST,
+			csi_dev->regbase + CSI_CSICR3);
+
+	__raw_writel(CSICR1_RESET_VAL, csi_dev->regbase + CSI_CSICR1);
+	__raw_writel(CSICR2_RESET_VAL, csi_dev->regbase + CSI_CSICR2);
+	__raw_writel(CSICR3_RESET_VAL, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csisw_reset(struct mx6s_csi_dev *csi_dev)
+{
+	int cr1, cr3, cr18, isr;
+
+	/* Disable csi  */
+	cr18 = csi_read(csi_dev, CSI_CSICR18);
+	cr18 &= ~BIT_CSI_ENABLE;
+	csi_write(csi_dev, cr18, CSI_CSICR18);
+
+	/* Clear RX FIFO */
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+	/* DMA reflash */
+	cr3 = csi_read(csi_dev, CSI_CSICR3);
+	cr3 |= BIT_DMA_REFLASH_RFF | BIT_FRMCNT_RST;
+	csi_write(csi_dev, cr3, CSI_CSICR3);
+
+	msleep(2);
+
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+	isr = csi_read(csi_dev, CSI_CSISR);
+	csi_write(csi_dev, isr, CSI_CSISR);
+
+	cr18 |= csi_dev->soc->baseaddr_switch;
+
+	/* Enable csi  */
+	cr18 |= BIT_CSI_ENABLE;
+	csi_write(csi_dev, cr18, CSI_CSICR18);
+}
+
+/*!
+ * csi_init_interface
+ *    Init csi interface
+ */
+static void csi_init_interface(struct mx6s_csi_dev *csi_dev)
+{
+	unsigned int val = 0;
+	unsigned int imag_para;
+
+	val |= BIT_SOF_POL;
+	val |= BIT_REDGE;
+	val |= BIT_GCLK_MODE;
+	val |= BIT_HSYNC_POL;
+	val |= BIT_FCC;
+	val |= 1 << SHIFT_MCLKDIV;
+	val |= BIT_MCLKEN;
+	__raw_writel(val, csi_dev->regbase + CSI_CSICR1);
+
+	imag_para = (640 << 16) | 960;
+	__raw_writel(imag_para, csi_dev->regbase + CSI_CSIIMAG_PARA);
+
+	val = BIT_DMA_REFLASH_RFF;
+	__raw_writel(val, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_enable_int(struct mx6s_csi_dev *csi_dev, int arg)
+{
+	unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+	cr1 |= BIT_SOF_INTEN;
+	cr1 |= BIT_RFF_OR_INT;
+	if (arg == 1) {
+		/* still capture needs DMA intterrupt */
+		cr1 |= BIT_FB1_DMA_DONE_INTEN;
+		cr1 |= BIT_FB2_DMA_DONE_INTEN;
+	}
+	__raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_disable_int(struct mx6s_csi_dev *csi_dev)
+{
+	unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+	cr1 &= ~BIT_SOF_INTEN;
+	cr1 &= ~BIT_RFF_OR_INT;
+	cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
+	cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
+	__raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_enable(struct mx6s_csi_dev *csi_dev, int arg)
+{
+	unsigned long cr = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+	if (arg == 1)
+		cr |= BIT_CSI_ENABLE;
+	else
+		cr &= ~BIT_CSI_ENABLE;
+	__raw_writel(cr, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_buf_stride_set(struct mx6s_csi_dev *csi_dev, u32 stride)
+{
+	__raw_writel(stride, csi_dev->regbase + CSI_CSIFBUF_PARA);
+}
+
+static void csi_deinterlace_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+	unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+	if (enable == true)
+		cr18 |= BIT_DEINTERLACE_EN;
+	else
+		cr18 &= ~BIT_DEINTERLACE_EN;
+
+	__raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_deinterlace_mode(struct mx6s_csi_dev *csi_dev, int mode)
+{
+	unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+	if (mode == V4L2_STD_NTSC)
+		cr18 |= BIT_NTSC_EN;
+	else
+		cr18 &= ~BIT_NTSC_EN;
+
+	__raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_tvdec_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+	unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+	unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+	if (enable == true) {
+		cr18 |= (BIT_TVDECODER_IN_EN |
+				BIT_BASEADDR_SWITCH_EN |
+				BIT_BASEADDR_SWITCH_SEL |
+				BIT_BASEADDR_CHG_ERR_EN);
+		cr1 |= BIT_CCIR_MODE;
+		cr1 &= ~(BIT_SOF_POL | BIT_REDGE);
+	} else {
+		cr18 &= ~(BIT_TVDECODER_IN_EN |
+				BIT_BASEADDR_SWITCH_EN |
+				BIT_BASEADDR_SWITCH_SEL |
+				BIT_BASEADDR_CHG_ERR_EN);
+		cr1 &= ~BIT_CCIR_MODE;
+		cr1 |= BIT_SOF_POL | BIT_REDGE;
+	}
+
+	__raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+	__raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_dmareq_rff_enable(struct mx6s_csi_dev *csi_dev)
+{
+	unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+	unsigned long cr2 = __raw_readl(csi_dev->regbase + CSI_CSICR2);
+
+	/* Burst Type of DMA Transfer from RxFIFO. INCR16 */
+	cr2 |= 0xC0000000;
+
+	cr3 |= BIT_DMA_REQ_EN_RFF;
+	cr3 |= BIT_HRESP_ERR_EN;
+	cr3 &= ~BIT_RXFF_LEVEL;
+	cr3 |= 0x2 << 4;
+	if (csi_dev->csi_two_8bit_sensor_mode)
+		cr3 |= BIT_TWO_8BIT_SENSOR;
+
+	__raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+	__raw_writel(cr2, csi_dev->regbase + CSI_CSICR2);
+}
+
+static void csi_dmareq_rff_disable(struct mx6s_csi_dev *csi_dev)
+{
+	unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+
+	cr3 &= ~BIT_DMA_REQ_EN_RFF;
+	cr3 &= ~BIT_HRESP_ERR_EN;
+	__raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_set_imagpara(struct mx6s_csi_dev *csi,
+					int width, int height)
+{
+	int imag_para = 0;
+	unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3);
+
+	imag_para = (width << 16) | height;
+	__raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA);
+
+	/* reflash the embeded DMA controller */
+	__raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3);
+}
+
+static void csi_error_recovery(struct mx6s_csi_dev *csi_dev)
+{
+	u32 cr1, cr3, cr18;
+	/* software reset */
+
+	/* Disable csi  */
+	cr18 = csi_read(csi_dev, CSI_CSICR18);
+	cr18 &= ~BIT_CSI_ENABLE;
+	csi_write(csi_dev, cr18, CSI_CSICR18);
+
+	/* Clear RX FIFO */
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+	cr1 = csi_read(csi_dev, CSI_CSICR1);
+	csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+	/* DMA reflash */
+	cr3 = csi_read(csi_dev, CSI_CSICR3);
+	cr3 |= BIT_DMA_REFLASH_RFF;
+	csi_write(csi_dev, cr3, CSI_CSICR3);
+
+	/* Ensable csi  */
+	cr18 |= BIT_CSI_ENABLE;
+	csi_write(csi_dev, cr18, CSI_CSICR18);
+}
+
+/*
+ *  Videobuf operations
+ */
+static int mx6s_videobuf_setup(struct vb2_queue *vq,
+			unsigned int *count, unsigned int *num_planes,
+			unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+
+	dev_dbg(csi_dev->dev, "count=%d, size=%d\n", *count, sizes[0]);
+
+	alloc_devs[0] = csi_dev->dev;
+
+	sizes[0] = csi_dev->pix.sizeimage;
+
+	pr_debug("size=%d\n", sizes[0]);
+	if (0 == *count)
+		*count = 32;
+	if (!*num_planes &&
+	    sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+	*num_planes = 1;
+
+	return 0;
+}
+
+static int mx6s_videobuf_prepare(struct vb2_buffer *vb)
+{
+	struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+	int ret = 0;
+
+	dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+#ifdef DEBUG
+	/*
+	 * This can be useful if you want to see if we actually fill
+	 * the buffer with something
+	 */
+	if (vb2_plane_vaddr(vb, 0))
+		memset((void *)vb2_plane_vaddr(vb, 0),
+		       0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+	vb2_set_plane_payload(vb, 0, csi_dev->pix.sizeimage);
+	if (vb2_plane_vaddr(vb, 0) &&
+	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static void mx6s_videobuf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct mx6s_buffer *buf = container_of(vbuf, struct mx6s_buffer, vb);
+	unsigned long flags;
+
+	dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+	spin_lock_irqsave(&csi_dev->slock, flags);
+
+	list_add_tail(&buf->internal.queue, &csi_dev->capture);
+
+	spin_unlock_irqrestore(&csi_dev->slock, flags);
+}
+
+static void mx6s_update_csi_buf(struct mx6s_csi_dev *csi_dev,
+				 unsigned long phys, int bufnum)
+{
+	if (bufnum == 1)
+		csi_write(csi_dev, phys, CSI_CSIDMASA_FB2);
+	else
+		csi_write(csi_dev, phys, CSI_CSIDMASA_FB1);
+}
+
+static void mx6s_csi_init(struct mx6s_csi_dev *csi_dev)
+{
+	csi_clk_enable(csi_dev);
+	csihw_reset(csi_dev);
+	csi_init_interface(csi_dev);
+	csi_dmareq_rff_disable(csi_dev);
+}
+
+static void mx6s_csi_deinit(struct mx6s_csi_dev *csi_dev)
+{
+	csihw_reset(csi_dev);
+	csi_init_interface(csi_dev);
+	csi_dmareq_rff_disable(csi_dev);
+	csi_clk_disable(csi_dev);
+}
+
+static int mx6s_csi_enable(struct mx6s_csi_dev *csi_dev)
+{
+	struct v4l2_pix_format *pix = &csi_dev->pix;
+	unsigned long flags;
+	unsigned long val;
+	int timeout, timeout2;
+
+	csi_dev->skipframe = 0;
+	csisw_reset(csi_dev);
+
+	if (pix->field == V4L2_FIELD_INTERLACED)
+		csi_tvdec_enable(csi_dev, true);
+
+	/* For mipi csi input only */
+	if (csi_dev->csi_mipi_mode == true) {
+		csi_dmareq_rff_enable(csi_dev);
+		csi_enable_int(csi_dev, 1);
+		csi_enable(csi_dev, 1);
+		return 0;
+	}
+
+	local_irq_save(flags);
+	for (timeout = 10000000; timeout > 0; timeout--) {
+		if (csi_read(csi_dev, CSI_CSISR) & BIT_SOF_INT) {
+			val = csi_read(csi_dev, CSI_CSICR3);
+			csi_write(csi_dev, val | BIT_DMA_REFLASH_RFF,
+					CSI_CSICR3);
+			/* Wait DMA reflash done */
+			for (timeout2 = 1000000; timeout2 > 0; timeout2--) {
+				if (csi_read(csi_dev, CSI_CSICR3) &
+					BIT_DMA_REFLASH_RFF)
+					cpu_relax();
+				else
+					break;
+			}
+			if (timeout2 <= 0) {
+				pr_err("timeout when wait for reflash done.\n");
+				local_irq_restore(flags);
+				return -ETIME;
+			}
+			/* For imx6sl csi, DMA FIFO will auto start when sensor ready to work,
+			 * so DMA should enable right after FIFO reset, otherwise dma will lost data
+			 * and image will split.
+			 */
+			csi_dmareq_rff_enable(csi_dev);
+			csi_enable_int(csi_dev, 1);
+			csi_enable(csi_dev, 1);
+			break;
+		} else
+			cpu_relax();
+	}
+	if (timeout <= 0) {
+		pr_err("timeout when wait for SOF\n");
+		local_irq_restore(flags);
+		return -ETIME;
+	}
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static void mx6s_csi_disable(struct mx6s_csi_dev *csi_dev)
+{
+	struct v4l2_pix_format *pix = &csi_dev->pix;
+
+	csi_dmareq_rff_disable(csi_dev);
+	csi_disable_int(csi_dev);
+
+	/* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */
+	csi_write(csi_dev, 0, CSI_CSIDMASA_FB1);
+	csi_write(csi_dev, 0, CSI_CSIDMASA_FB2);
+
+	csi_buf_stride_set(csi_dev, 0);
+
+	if (pix->field == V4L2_FIELD_INTERLACED) {
+		csi_deinterlace_enable(csi_dev, false);
+		csi_tvdec_enable(csi_dev, false);
+	}
+
+	csi_enable(csi_dev, 0);
+}
+
+static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
+{
+	struct v4l2_pix_format *pix = &csi_dev->pix;
+	u32 cr1, cr18;
+	u32 width;
+
+	if (pix->field == V4L2_FIELD_INTERLACED) {
+		csi_deinterlace_enable(csi_dev, true);
+		csi_buf_stride_set(csi_dev, csi_dev->pix.width);
+		csi_deinterlace_mode(csi_dev, csi_dev->std);
+	} else {
+		csi_deinterlace_enable(csi_dev, false);
+		csi_buf_stride_set(csi_dev, 0);
+	}
+
+	switch (csi_dev->fmt->pixelformat) {
+	case V4L2_PIX_FMT_YUV32:
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_GREY:
+		width = pix->width;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YUYV:
+		if (csi_dev->csi_mipi_mode == true)
+			width = pix->width;
+		else
+			/* For parallel 8-bit sensor input */
+			width = pix->width * 2;
+		break;
+	default:
+		pr_debug("   case not supported\n");
+		return -EINVAL;
+	}
+	csi_set_imagpara(csi_dev, width, pix->height);
+
+	if (csi_dev->csi_mipi_mode == true) {
+		cr1 = csi_read(csi_dev, CSI_CSICR1);
+		cr1 &= ~BIT_GCLK_MODE;
+		csi_write(csi_dev, cr1, CSI_CSICR1);
+
+		cr18 = csi_read(csi_dev, CSI_CSICR18);
+		cr18 &= ~BIT_MIPI_DATA_FORMAT_MASK;
+		cr18 |= BIT_DATA_FROM_MIPI;
+
+		switch (csi_dev->fmt->pixelformat) {
+		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_YUYV:
+			cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
+			break;
+		case V4L2_PIX_FMT_SBGGR8:
+		case V4L2_PIX_FMT_GREY:
+			cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
+			break;
+		default:
+			pr_debug("   fmt not supported\n");
+			return -EINVAL;
+		}
+
+		csi_write(csi_dev, cr18, CSI_CSICR18);
+	}
+	return 0;
+}
+
+static int mx6s_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+	struct vb2_buffer *vb;
+	struct mx6s_buffer *buf;
+	unsigned long phys;
+	unsigned long flags;
+
+	if (count < 2)
+		return -ENOBUFS;
+
+	/*
+	 * I didn't manage to properly enable/disable
+	 * a per frame basis during running transfers,
+	 * thus we allocate a buffer here and use it to
+	 * discard frames when no buffer is available.
+	 * Feel free to work on this ;)
+	 */
+	csi_dev->discard_size = csi_dev->pix.sizeimage;
+	csi_dev->discard_buffer = dma_alloc_coherent(csi_dev->v4l2_dev.dev,
+					PAGE_ALIGN(csi_dev->discard_size),
+					&csi_dev->discard_buffer_dma,
+					GFP_DMA | GFP_KERNEL);
+	if (!csi_dev->discard_buffer)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&csi_dev->slock, flags);
+
+	csi_dev->buf_discard[0].discard = true;
+	list_add_tail(&csi_dev->buf_discard[0].queue,
+		      &csi_dev->discard);
+
+	csi_dev->buf_discard[1].discard = true;
+	list_add_tail(&csi_dev->buf_discard[1].queue,
+		      &csi_dev->discard);
+
+	/* csi buf 0 */
+	buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+			       internal.queue);
+	buf->internal.bufnum = 0;
+	vb = &buf->vb.vb2_buf;
+	vb->state = VB2_BUF_STATE_ACTIVE;
+
+	phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+	mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+	list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+	/* csi buf 1 */
+	buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+			       internal.queue);
+	buf->internal.bufnum = 1;
+	vb = &buf->vb.vb2_buf;
+	vb->state = VB2_BUF_STATE_ACTIVE;
+
+	phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+	mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+	list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+	csi_dev->nextfb = 0;
+
+	spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+	return mx6s_csi_enable(csi_dev);
+}
+
+static void mx6s_stop_streaming(struct vb2_queue *vq)
+{
+	struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+	unsigned long flags;
+	struct mx6s_buffer *buf, *tmp;
+	void *b;
+
+	mx6s_csi_disable(csi_dev);
+
+	spin_lock_irqsave(&csi_dev->slock, flags);
+
+	list_for_each_entry_safe(buf, tmp,
+				&csi_dev->active_bufs, internal.queue) {
+		list_del_init(&buf->internal.queue);
+		if (buf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+	}
+
+	list_for_each_entry_safe(buf, tmp,
+				&csi_dev->capture, internal.queue) {
+		list_del_init(&buf->internal.queue);
+		if (buf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+	}
+
+	INIT_LIST_HEAD(&csi_dev->capture);
+	INIT_LIST_HEAD(&csi_dev->active_bufs);
+	INIT_LIST_HEAD(&csi_dev->discard);
+
+	b = csi_dev->discard_buffer;
+	csi_dev->discard_buffer = NULL;
+
+	spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+	dma_free_coherent(csi_dev->v4l2_dev.dev,
+				csi_dev->discard_size, b,
+				csi_dev->discard_buffer_dma);
+}
+
+static struct vb2_ops mx6s_videobuf_ops = {
+	.queue_setup     = mx6s_videobuf_setup,
+	.buf_prepare     = mx6s_videobuf_prepare,
+	.buf_queue       = mx6s_videobuf_queue,
+	.wait_prepare    = vb2_ops_wait_prepare,
+	.wait_finish     = vb2_ops_wait_finish,
+	.start_streaming = mx6s_start_streaming,
+	.stop_streaming	 = mx6s_stop_streaming,
+};
+
+static void mx6s_csi_frame_done(struct mx6s_csi_dev *csi_dev,
+		int bufnum, bool err)
+{
+	struct mx6s_buf_internal *ibuf;
+	struct mx6s_buffer *buf;
+	struct vb2_buffer *vb;
+	unsigned long phys;
+	unsigned int phys_fb1;
+	unsigned int phys_fb2;
+
+	ibuf = list_first_entry(&csi_dev->active_bufs, struct mx6s_buf_internal,
+			       queue);
+
+	if (ibuf->discard) {
+		/*
+		 * Discard buffer must not be returned to user space.
+		 * Just return it to the discard queue.
+		 */
+		list_move_tail(csi_dev->active_bufs.next, &csi_dev->discard);
+	} else {
+		buf = mx6s_ibuf_to_buf(ibuf);
+
+		vb = &buf->vb.vb2_buf;
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		if (bufnum == 1) {
+			phys_fb2 = csi_read(csi_dev, CSI_CSIDMASA_FB2);
+			if (phys_fb2 != (u32)phys) {
+				dev_err(csi_dev->dev, "%lx != %x\n", phys,
+					phys_fb2);
+			}
+		} else {
+			phys_fb1 = csi_read(csi_dev, CSI_CSIDMASA_FB1);
+			if (phys_fb1 != (u32)phys) {
+				dev_err(csi_dev->dev, "%lx != %x\n", phys,
+					phys_fb1);
+			}
+		}
+		dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+				vb2_plane_vaddr(vb, 0),
+				vb2_get_plane_payload(vb, 0));
+
+		list_del_init(&buf->internal.queue);
+		vb->timestamp =ktime_get_ns();
+		to_vb2_v4l2_buffer(vb)->sequence = csi_dev->frame_count;
+		if (err)
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		else
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+
+	csi_dev->frame_count++;
+	csi_dev->nextfb = (bufnum == 0 ? 1 : 0);
+
+	/* Config discard buffer to active_bufs */
+	if (list_empty(&csi_dev->capture)) {
+		if (list_empty(&csi_dev->discard)) {
+			dev_warn(csi_dev->dev,
+					"%s: trying to access empty discard list\n",
+					__func__);
+			return;
+		}
+
+		ibuf = list_first_entry(&csi_dev->discard,
+					struct mx6s_buf_internal, queue);
+		ibuf->bufnum = bufnum;
+
+		list_move_tail(csi_dev->discard.next, &csi_dev->active_bufs);
+
+		mx6s_update_csi_buf(csi_dev,
+					csi_dev->discard_buffer_dma, bufnum);
+		return;
+	}
+
+	buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+			       internal.queue);
+
+	buf->internal.bufnum = bufnum;
+
+	list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+	vb = &buf->vb.vb2_buf;
+	vb->state = VB2_BUF_STATE_ACTIVE;
+
+	phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+	mx6s_update_csi_buf(csi_dev, phys, bufnum);
+}
+
+static irqreturn_t mx6s_csi_irq_handler(int irq, void *data)
+{
+	struct mx6s_csi_dev *csi_dev =  data;
+	unsigned long status;
+	u32 cr3, cr18;
+
+	spin_lock(&csi_dev->slock);
+
+	status = csi_read(csi_dev, CSI_CSISR);
+	csi_write(csi_dev, status, CSI_CSISR);
+
+	if (list_empty(&csi_dev->active_bufs)) {
+		dev_warn(csi_dev->dev,
+				"%s: called while active list is empty\n",
+				__func__);
+
+		spin_unlock(&csi_dev->slock);
+		return IRQ_HANDLED;
+	}
+
+	if (status & BIT_RFF_OR_INT) {
+		dev_warn(csi_dev->dev, "%s Rx fifo overflow\n", __func__);
+		if (csi_dev->soc->rx_fifo_rst)
+			csi_error_recovery(csi_dev);
+	}
+
+	if (status & BIT_HRESP_ERR_INT) {
+		dev_warn(csi_dev->dev, "%s Hresponse error detected\n",
+			__func__);
+		csi_error_recovery(csi_dev);
+	}
+
+	if (status & BIT_ADDR_CH_ERR_INT) {
+		/* Disable csi  */
+		cr18 = csi_read(csi_dev, CSI_CSICR18);
+		cr18 &= ~BIT_CSI_ENABLE;
+		csi_write(csi_dev, cr18, CSI_CSICR18);
+
+		/* DMA reflash */
+		cr3 = csi_read(csi_dev, CSI_CSICR3);
+		cr3 |= BIT_DMA_REFLASH_RFF;
+		csi_write(csi_dev, cr3, CSI_CSICR3);
+
+		/* Ensable csi  */
+		cr18 |= BIT_CSI_ENABLE;
+		csi_write(csi_dev, cr18, CSI_CSICR18);
+
+		csi_dev->skipframe = 1;
+		pr_debug("base address switching Change Err.\n");
+	}
+
+	if ((status & BIT_DMA_TSF_DONE_FB1) &&
+		(status & BIT_DMA_TSF_DONE_FB2)) {
+		/* For both FB1 and FB2 interrupter bits set case,
+		 * CSI DMA is work in one of FB1 and FB2 buffer,
+		 * but software can not know the state.
+		 * Skip it to avoid base address updated
+		 * when csi work in field0 and field1 will write to
+		 * new base address.
+		 * PDM TKT230775 */
+		pr_debug("Skip two frames\n");
+	} else if (status & BIT_DMA_TSF_DONE_FB1) {
+		if (csi_dev->nextfb == 0) {
+			if (csi_dev->skipframe > 0)
+				csi_dev->skipframe--;
+			else
+				mx6s_csi_frame_done(csi_dev, 0, false);
+		} else
+			pr_warn("skip frame 0\n");
+
+	} else if (status & BIT_DMA_TSF_DONE_FB2) {
+		if (csi_dev->nextfb == 1) {
+			if (csi_dev->skipframe > 0)
+				csi_dev->skipframe--;
+			else
+				mx6s_csi_frame_done(csi_dev, 1, false);
+		} else
+			pr_warn("skip frame 1\n");
+	}
+
+	spin_unlock(&csi_dev->slock);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int mx6s_csi_open(struct file *file)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	struct vb2_queue *q = &csi_dev->vb2_vidq;
+	int ret = 0;
+
+	file->private_data = csi_dev;
+
+	if (mutex_lock_interruptible(&csi_dev->lock))
+		return -ERESTARTSYS;
+
+	if (csi_dev->open_count++ == 0) {
+		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_USERPTR;
+		q->drv_priv = csi_dev;
+		q->ops = &mx6s_videobuf_ops;
+		q->mem_ops = &vb2_dma_contig_memops;
+		q->buf_struct_size = sizeof(struct mx6s_buffer);
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->lock = &csi_dev->lock;
+
+		ret = vb2_queue_init(q);
+		if (ret < 0)
+			goto unlock;
+
+		pm_runtime_get_sync(csi_dev->dev);
+
+		v4l2_subdev_call(sd, core, s_power, 1);
+		mx6s_csi_init(csi_dev);
+
+	}
+	mutex_unlock(&csi_dev->lock);
+
+	return ret;
+unlock:
+	mutex_unlock(&csi_dev->lock);
+	return ret;
+}
+
+static int mx6s_csi_close(struct file *file)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	mutex_lock(&csi_dev->lock);
+
+	if (--csi_dev->open_count == 0) {
+		vb2_queue_release(&csi_dev->vb2_vidq);
+
+		mx6s_csi_deinit(csi_dev);
+		v4l2_subdev_call(sd, core, s_power, 0);
+
+		file->private_data = NULL;
+
+		pm_runtime_put_sync_suspend(csi_dev->dev);
+	}
+	mutex_unlock(&csi_dev->lock);
+
+	return 0;
+}
+
+static ssize_t mx6s_csi_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(csi_dev->dev, "read called, buf %p\n", buf);
+
+	mutex_lock(&csi_dev->lock);
+	ret = vb2_read(&csi_dev->vb2_vidq, buf, count, ppos,
+				file->f_flags & O_NONBLOCK);
+	mutex_unlock(&csi_dev->lock);
+	return ret;
+}
+
+static struct v4l2_file_operations mx6s_csi_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mx6s_csi_open,
+	.release	= mx6s_csi_close,
+	.read		= mx6s_csi_read,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl	= video_ioctl2, /* V4L2 ioctl handler */
+	.mmap		= vb2_fop_mmap,
+};
+
+/*
+ * Video node IOCTLs
+ */
+static int mx6s_vidioc_enum_input(struct file *file, void *priv,
+				 struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
+
+	/* default is camera */
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(inp->name, "Camera");
+
+	return 0;
+}
+
+static int mx6s_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int mx6s_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mx6s_vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	return v4l2_subdev_call(sd, video, querystd, a);
+}
+
+static int mx6s_vidioc_s_std(struct file *file, void *priv, v4l2_std_id a)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	return v4l2_subdev_call(sd, video, s_std, a);
+}
+
+static int mx6s_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	return v4l2_subdev_call(sd, video, g_std, a);
+}
+
+static int mx6s_vidioc_reqbufs(struct file *file, void *priv,
+			      struct v4l2_requestbuffers *p)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	WARN_ON(priv != file->private_data);
+
+	return vb2_reqbufs(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_querybuf(struct file *file, void *priv,
+			       struct v4l2_buffer *p)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	ret = vb2_querybuf(&csi_dev->vb2_vidq, p);
+
+	if (!ret) {
+		/* return physical address */
+		struct vb2_buffer *vb = csi_dev->vb2_vidq.bufs[p->index];
+		if (p->flags & V4L2_BUF_FLAG_MAPPED)
+			p->m.offset = vb2_dma_contig_plane_dma_addr(vb, 0);
+	}
+	return ret;
+}
+
+static int mx6s_vidioc_qbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *p)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	WARN_ON(priv != file->private_data);
+
+	return vb2_qbuf(&csi_dev->vb2_vidq, NULL, p);
+}
+
+static int mx6s_vidioc_dqbuf(struct file *file, void *priv,
+			    struct v4l2_buffer *p)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	WARN_ON(priv != file->private_data);
+
+	return vb2_dqbuf(&csi_dev->vb2_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mx6s_vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	struct v4l2_subdev_mbus_code_enum code = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.index = f->index,
+	};
+	struct mx6s_fmt *fmt;
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code);
+	if (ret < 0) {
+		/* no more formats */
+		dev_dbg(csi_dev->dev, "No more fmt\n");
+		return -EINVAL;
+	}
+
+	fmt = format_by_mbus(code.code);
+	if (!fmt) {
+		dev_err(csi_dev->dev, "mbus (0x%08x) invalid.\n", code.code);
+		return -EINVAL;
+	}
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->pixelformat;
+
+	return 0;
+}
+
+static int mx6s_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				      struct v4l2_format *f)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct v4l2_subdev_format format = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct mx6s_fmt *fmt;
+	int ret;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		dev_err(csi_dev->dev, "Fourcc format (0x%08x) invalid.",
+			f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	if (f->fmt.pix.width == 0 || f->fmt.pix.height == 0) {
+		dev_err(csi_dev->dev, "width %d, height %d is too small.\n",
+			f->fmt.pix.width, f->fmt.pix.height);
+		return -EINVAL;
+	}
+
+	v4l2_fill_mbus_format(&format.format, pix, fmt->mbus_code);
+	ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format);
+	v4l2_fill_pix_format(pix, &format.format);
+
+	if (pix->field != V4L2_FIELD_INTERLACED)
+		pix->field = V4L2_FIELD_NONE;
+
+	pix->sizeimage = fmt->bpp * pix->height * pix->width;
+	pix->bytesperline = fmt->bpp * pix->width;
+
+	return ret;
+}
+
+/*
+ * The real work of figuring out a workable format.
+ */
+
+static int mx6s_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	int ret;
+
+	ret = mx6s_vidioc_try_fmt_vid_cap(file, csi_dev, f);
+	if (ret < 0)
+		return ret;
+
+	csi_dev->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+	csi_dev->mbus_code     = csi_dev->fmt->mbus_code;
+	csi_dev->pix.width     = f->fmt.pix.width;
+	csi_dev->pix.height    = f->fmt.pix.height;
+	csi_dev->pix.sizeimage = f->fmt.pix.sizeimage;
+	csi_dev->pix.field     = f->fmt.pix.field;
+	csi_dev->type          = f->type;
+	dev_dbg(csi_dev->dev, "set to pixelformat '%4.6s'\n",
+			(char *)&csi_dev->fmt->name);
+
+	/* Config csi */
+	mx6s_configure_csi(csi_dev);
+
+	return 0;
+}
+
+static int mx6s_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	WARN_ON(priv != file->private_data);
+
+	f->fmt.pix = csi_dev->pix;
+
+	return 0;
+}
+
+static int mx6s_vidioc_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	WARN_ON(priv != file->private_data);
+
+	/* cap->name is set by the friendly caller:-> */
+	strlcpy(cap->driver, MX6S_CAM_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 dev_name(csi_dev->dev));
+
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int mx6s_vidioc_expbuf(struct file *file, void *priv,
+			     struct v4l2_exportbuffer *eb)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return vb2_expbuf(&csi_dev->vb2_vidq, eb);
+
+	return -EINVAL;
+}
+
+static int mx6s_vidioc_streamon(struct file *file, void *priv,
+			       enum v4l2_buf_type i)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	ret = vb2_streamon(&csi_dev->vb2_vidq, i);
+	if (!ret)
+		v4l2_subdev_call(sd, video, s_stream, 1);
+
+	return ret;
+}
+
+static int mx6s_vidioc_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	WARN_ON(priv != file->private_data);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/*
+	 * This calls buf_release from host driver's videobuf_queue_ops for all
+	 * remaining buffers. When the last buffer is freed, stop capture
+	 */
+	vb2_streamoff(&csi_dev->vb2_vidq, i);
+
+	v4l2_subdev_call(sd, video, s_stream, 0);
+
+	return 0;
+}
+
+static int mx6s_vidioc_g_pixelaspect(struct file *file, void *fh,
+			       int type, struct v4l2_fract *f)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	dev_dbg(csi_dev->dev, "G_PIXELASPECT not implemented\n");
+
+	return 0;
+}
+
+static int mx6s_vidioc_g_selection(struct file *file, void *priv,
+			     struct v4l2_selection *s)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	dev_dbg(csi_dev->dev, "VIDIOC_G_SELECTION not implemented\n");
+
+	return 0;
+}
+
+static int mx6s_vidioc_s_selection(struct file *file, void *priv,
+			     struct v4l2_selection *s)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	dev_dbg(csi_dev->dev, "VIDIOC_S_SELECTION not implemented\n");
+
+	return 0;
+}
+
+static int mx6s_vidioc_g_parm(struct file *file, void *priv,
+			     struct v4l2_streamparm *a)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	return v4l2_subdev_call(sd, video, g_parm, a);
+}
+
+static int mx6s_vidioc_s_parm(struct file *file, void *priv,
+				struct v4l2_streamparm *a)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+
+	return v4l2_subdev_call(sd, video, s_parm, a);
+}
+
+static int mx6s_vidioc_enum_framesizes(struct file *file, void *priv,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	struct mx6s_fmt *fmt;
+	struct v4l2_subdev_frame_size_enum fse = {
+		.index = fsize->index,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	int ret;
+
+	fmt = format_by_fourcc(fsize->pixel_format);
+	if (fmt->pixelformat != fsize->pixel_format)
+		return -EINVAL;
+	fse.code = fmt->mbus_code;
+
+	ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
+	if (ret)
+		return ret;
+
+	if (fse.min_width == fse.max_width &&
+	    fse.min_height == fse.max_height) {
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete.width = fse.min_width;
+		fsize->discrete.height = fse.min_height;
+		return 0;
+	}
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->stepwise.min_width = fse.min_width;
+	fsize->stepwise.max_width = fse.max_width;
+	fsize->stepwise.min_height = fse.min_height;
+	fsize->stepwise.max_height = fse.max_height;
+	fsize->stepwise.step_width = 1;
+	fsize->stepwise.step_height = 1;
+
+	return 0;
+}
+
+static int mx6s_vidioc_enum_frameintervals(struct file *file, void *priv,
+		struct v4l2_frmivalenum *interval)
+{
+	struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+	struct v4l2_subdev *sd = csi_dev->sd;
+	struct mx6s_fmt *fmt;
+	struct v4l2_subdev_frame_interval_enum fie = {
+		.index = interval->index,
+		.width = interval->width,
+		.height = interval->height,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	int ret;
+
+	fmt = format_by_fourcc(interval->pixel_format);
+	if (fmt->pixelformat != interval->pixel_format)
+		return -EINVAL;
+	fie.code = fmt->mbus_code;
+
+	ret = v4l2_subdev_call(sd, pad, enum_frame_interval, NULL, &fie);
+	if (ret)
+		return ret;
+	interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	interval->discrete = fie.interval;
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mx6s_csi_ioctl_ops = {
+	.vidioc_querycap          = mx6s_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = mx6s_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = mx6s_vidioc_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = mx6s_vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = mx6s_vidioc_s_fmt_vid_cap,
+	.vidioc_g_pixelaspect     = mx6s_vidioc_g_pixelaspect,
+	.vidioc_s_selection   = mx6s_vidioc_s_selection,
+	.vidioc_g_selection   = mx6s_vidioc_g_selection,
+	.vidioc_reqbufs       = mx6s_vidioc_reqbufs,
+	.vidioc_querybuf      = mx6s_vidioc_querybuf,
+	.vidioc_qbuf          = mx6s_vidioc_qbuf,
+	.vidioc_dqbuf         = mx6s_vidioc_dqbuf,
+	.vidioc_g_std         = mx6s_vidioc_g_std,
+	.vidioc_s_std         = mx6s_vidioc_s_std,
+	.vidioc_querystd      = mx6s_vidioc_querystd,
+	.vidioc_enum_input    = mx6s_vidioc_enum_input,
+	.vidioc_g_input       = mx6s_vidioc_g_input,
+	.vidioc_s_input       = mx6s_vidioc_s_input,
+	.vidioc_expbuf        = mx6s_vidioc_expbuf,
+	.vidioc_streamon      = mx6s_vidioc_streamon,
+	.vidioc_streamoff     = mx6s_vidioc_streamoff,
+	.vidioc_g_parm        = mx6s_vidioc_g_parm,
+	.vidioc_s_parm        = mx6s_vidioc_s_parm,
+	.vidioc_enum_framesizes = mx6s_vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals = mx6s_vidioc_enum_frameintervals,
+};
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+			    struct v4l2_subdev *subdev,
+			    struct v4l2_async_subdev *asd)
+{
+	struct mx6s_csi_dev *csi_dev = notifier_to_mx6s_dev(notifier);
+
+	/* Find platform data for this sensor subdev */
+	if (csi_dev->asd.match.fwnode == dev_fwnode(subdev->dev))
+		csi_dev->sd = subdev;
+
+	if (subdev == NULL)
+		return -EINVAL;
+
+	v4l2_info(&csi_dev->v4l2_dev, "Registered sensor subdevice: %s\n",
+		  subdev->name);
+
+	return 0;
+}
+
+static int mx6s_csi_mode_sel(struct mx6s_csi_dev *csi_dev)
+{
+	struct device_node *np = csi_dev->dev->of_node;
+	struct device_node *node;
+	phandle phandle;
+	u32 out_val[3];
+	int ret = 0;
+
+	if (of_get_property(np, "fsl,mipi-mode", NULL))
+		csi_dev->csi_mipi_mode = true;
+	else {
+		csi_dev->csi_mipi_mode = false;
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "csi-mux-mipi", out_val, 3);
+	if (ret) {
+		dev_dbg(csi_dev->dev, "no csi-mux-mipi property found\n");
+	} else {
+		phandle = *out_val;
+
+		node = of_find_node_by_phandle(phandle);
+		if (!node) {
+			dev_dbg(csi_dev->dev, "not find gpr node by phandle\n");
+			ret = PTR_ERR(node);
+		}
+		csi_dev->csi_mux.gpr = syscon_node_to_regmap(node);
+		if (IS_ERR(csi_dev->csi_mux.gpr)) {
+			dev_err(csi_dev->dev, "failed to get gpr regmap\n");
+			ret = PTR_ERR(csi_dev->csi_mux.gpr);
+		}
+		of_node_put(node);
+		if (ret < 0)
+			return ret;
+
+		csi_dev->csi_mux.req_gpr = out_val[1];
+		csi_dev->csi_mux.req_bit = out_val[2];
+
+		regmap_update_bits(csi_dev->csi_mux.gpr, csi_dev->csi_mux.req_gpr,
+			1 << csi_dev->csi_mux.req_bit, 1 << csi_dev->csi_mux.req_bit);
+	}
+	return ret;
+}
+
+static const struct v4l2_async_notifier_operations mx6s_capture_async_ops = {
+	.bound = subdev_notifier_bound,
+};
+
+static int mx6s_csi_two_8bit_sensor_mode_sel(struct mx6s_csi_dev *csi_dev)
+{
+	struct device_node *np = csi_dev->dev->of_node;
+
+	if (of_get_property(np, "fsl,two-8bit-sensor-mode", NULL))
+		csi_dev->csi_two_8bit_sensor_mode = true;
+	else {
+		csi_dev->csi_two_8bit_sensor_mode = false;
+	}
+
+	return 0;
+}
+
+static int mx6sx_register_subdevs(struct mx6s_csi_dev *csi_dev)
+{
+	struct device_node *parent = csi_dev->dev->of_node;
+	struct device_node *node, *port, *rem;
+	int ret;
+
+	v4l2_async_notifier_init(&csi_dev->subdev_notifier);
+
+	/* Attach sensors linked to csi receivers */
+	for_each_available_child_of_node(parent, node) {
+		if (of_node_cmp(node->name, "port"))
+			continue;
+
+		/* The csi node can have only port subnode. */
+		port = of_get_next_child(node, NULL);
+		if (!port)
+			continue;
+		rem = of_graph_get_remote_port_parent(port);
+		of_node_put(port);
+		if (rem == NULL) {
+			v4l2_info(&csi_dev->v4l2_dev,
+						"Remote device at %s not found\n",
+						port->full_name);
+			return -1;
+		}
+
+		csi_dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+		csi_dev->asd.match.fwnode = of_fwnode_handle(rem);
+
+		ret = v4l2_async_notifier_add_subdev(&csi_dev->subdev_notifier,
+						&csi_dev->asd);
+		if (ret) {
+			of_node_put(rem);
+		}
+
+		of_node_put(rem);
+		break;
+	}
+
+	csi_dev->subdev_notifier.ops = &mx6s_capture_async_ops;
+
+	ret = v4l2_async_notifier_register(&csi_dev->v4l2_dev,
+					&csi_dev->subdev_notifier);
+	if (ret)
+		dev_err(csi_dev->dev,
+					"Error register async notifier regoster\n");
+
+	return ret;
+}
+
+static int mx6s_csi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id;
+	struct mx6s_csi_dev *csi_dev;
+	struct video_device *vdev;
+	struct resource *res;
+	int ret = 0;
+
+	dev_info(dev, "initialising\n");
+
+	/* Prepare our private structure */
+	csi_dev = devm_kzalloc(dev, sizeof(struct mx6s_csi_dev), GFP_ATOMIC);
+	if (!csi_dev) {
+		dev_err(dev, "Can't allocate private structure\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	csi_dev->irq = platform_get_irq(pdev, 0);
+	if (res == NULL || csi_dev->irq < 0) {
+		dev_err(dev, "Missing platform resources data\n");
+		return -ENODEV;
+	}
+
+	csi_dev->regbase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(csi_dev->regbase)) {
+		dev_err(dev, "Failed platform resources map\n");
+		return -ENODEV;
+	}
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&csi_dev->capture);
+	INIT_LIST_HEAD(&csi_dev->active_bufs);
+	INIT_LIST_HEAD(&csi_dev->discard);
+
+	csi_dev->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+	if (IS_ERR(csi_dev->clk_disp_axi)) {
+		dev_err(dev, "Could not get csi axi clock\n");
+		return -ENODEV;
+	}
+
+	csi_dev->clk_disp_dcic = devm_clk_get(dev, "disp_dcic");
+	if (IS_ERR(csi_dev->clk_disp_dcic)) {
+		dev_err(dev, "Could not get disp dcic clock\n");
+		return -ENODEV;
+	}
+
+	csi_dev->clk_csi_mclk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(csi_dev->clk_csi_mclk)) {
+		dev_err(dev, "Could not get csi mclk clock\n");
+		return -ENODEV;
+	}
+
+	csi_dev->dev = dev;
+
+	mx6s_csi_mode_sel(csi_dev);
+	mx6s_csi_two_8bit_sensor_mode_sel(csi_dev);
+
+	of_id = of_match_node(mx6s_csi_dt_ids, csi_dev->dev->of_node);
+	if (!of_id)
+		return -EINVAL;
+	csi_dev->soc = of_id->data;
+
+	snprintf(csi_dev->v4l2_dev.name,
+		 sizeof(csi_dev->v4l2_dev.name), "CSI");
+
+	ret = v4l2_device_register(dev, &csi_dev->v4l2_dev);
+	if (ret < 0) {
+		dev_err(dev, "v4l2_device_register() failed: %d\n", ret);
+		return -ENODEV;
+	}
+
+	/* initialize locks */
+	mutex_init(&csi_dev->lock);
+	spin_lock_init(&csi_dev->slock);
+
+	/* Allocate memory for video device */
+	vdev = video_device_alloc();
+	if (vdev == NULL) {
+		ret = -ENOMEM;
+		goto err_vdev;
+	}
+
+	snprintf(vdev->name, sizeof(vdev->name), "mx6s-csi");
+
+	vdev->v4l2_dev		= &csi_dev->v4l2_dev;
+	vdev->fops			= &mx6s_csi_fops;
+	vdev->ioctl_ops		= &mx6s_csi_ioctl_ops;
+	vdev->release		= video_device_release;
+	vdev->lock			= &csi_dev->lock;
+	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	vdev->queue = &csi_dev->vb2_vidq;
+
+	csi_dev->vdev = vdev;
+
+	video_set_drvdata(csi_dev->vdev, csi_dev);
+	mutex_lock(&csi_dev->lock);
+
+	ret = video_register_device(csi_dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		video_device_release(csi_dev->vdev);
+		mutex_unlock(&csi_dev->lock);
+		goto err_vdev;
+	}
+
+	/* install interrupt handler */
+	if (devm_request_irq(dev, csi_dev->irq, mx6s_csi_irq_handler,
+				0, "csi", (void *)csi_dev)) {
+		mutex_unlock(&csi_dev->lock);
+		dev_err(dev, "Request CSI IRQ failed.\n");
+		ret = -ENODEV;
+		goto err_irq;
+	}
+
+	mutex_unlock(&csi_dev->lock);
+
+	ret = mx6sx_register_subdevs(csi_dev);
+	if (ret < 0)
+		goto err_irq;
+
+	pm_runtime_enable(csi_dev->dev);
+	return 0;
+
+err_irq:
+	video_unregister_device(csi_dev->vdev);
+err_vdev:
+	v4l2_device_unregister(&csi_dev->v4l2_dev);
+	return ret;
+}
+
+static int mx6s_csi_remove(struct platform_device *pdev)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+	struct mx6s_csi_dev *csi_dev =
+				container_of(v4l2_dev, struct mx6s_csi_dev, v4l2_dev);
+
+	v4l2_async_notifier_unregister(&csi_dev->subdev_notifier);
+
+	video_unregister_device(csi_dev->vdev);
+	v4l2_device_unregister(&csi_dev->v4l2_dev);
+
+	pm_runtime_disable(csi_dev->dev);
+	return 0;
+}
+
+static int mx6s_csi_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "csi v4l2 busfreq high release.\n");
+	return 0;
+}
+
+static int mx6s_csi_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "csi v4l2 busfreq high request.\n");
+	return 0;
+}
+
+static const struct dev_pm_ops mx6s_csi_pm_ops = {
+	SET_RUNTIME_PM_OPS(mx6s_csi_runtime_suspend, mx6s_csi_runtime_resume, NULL)
+};
+
+static const struct mx6s_csi_soc mx6s_soc = {
+	.rx_fifo_rst = true,
+	.baseaddr_switch = 0,
+};
+static const struct mx6s_csi_soc mx6sl_soc = {
+	.rx_fifo_rst = false,
+	.baseaddr_switch = 0,
+};
+static const struct mx6s_csi_soc mx8mq_soc = {
+	.rx_fifo_rst = true,
+	.baseaddr_switch = 0x80030,
+};
+
+static const struct of_device_id mx6s_csi_dt_ids[] = {
+	{ .compatible = "fsl,imx6s-csi",
+	  .data = &mx6s_soc,
+	},
+	{ .compatible = "fsl,imx6sl-csi",
+	  .data = &mx6sl_soc,
+	},
+	{ .compatible = "fsl,imx8mq-csi",
+	  .data = &mx8mq_soc,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mx6s_csi_dt_ids);
+
+static struct platform_driver mx6s_csi_driver = {
+	.driver		= {
+		.name	= MX6S_CAM_DRV_NAME,
+		.of_match_table = of_match_ptr(mx6s_csi_dt_ids),
+		.pm = &mx6s_csi_pm_ops,
+	},
+	.probe	= mx6s_csi_probe,
+	.remove	= mx6s_csi_remove,
+};
+
+module_platform_driver(mx6s_csi_driver);
+
+MODULE_DESCRIPTION("i.MX6Sx SoC Camera Host driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MX6S_CAM_VERSION);
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mxc_mipi_csi.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mxc_mipi_csi.c
@@ -0,0 +1,1320 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver
+ *
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+/*
+ * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define CSIS_DRIVER_NAME	"mxc_mipi-csi"
+#define CSIS_SUBDEV_NAME	CSIS_DRIVER_NAME
+#define CSIS_MAX_ENTITIES	2
+#define CSIS0_MAX_LANES		4
+#define CSIS1_MAX_LANES		2
+
+#define MIPI_CSIS_DEF_PIX_WIDTH	640
+#define MIPI_CSIS_DEF_PIX_HEIGHT	480
+
+/* Register map definition */
+
+/* CSIS version */
+#define MIPI_CSIS_VERSION		0x00
+
+/* CSIS common control */
+#define MIPI_CSIS_CMN_CTRL			0x04
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW	(1 << 16)
+#define MIPI_CSIS_CMN_CTRL_INTER_MODE		(1 << 10)
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET	8
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK		(3 << 8)
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL	(1 << 2)
+#define MIPI_CSIS_CMN_CTRL_RESET		(1 << 1)
+#define MIPI_CSIS_CMN_CTRL_ENABLE		(1 << 0)
+
+/* CSIS clock control */
+#define MIPI_CSIS_CLK_CTRL		0x08
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x)	(x << 28)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x)	(x << 24)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x)	(x << 20)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x)	(x << 16)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK	(0xf << 4)
+#define MIPI_CSIS_CLK_CTRL_WCLK_SRC		(1 << 0)
+
+/* CSIS Interrupt mask */
+#define MIPI_CSIS_INTMSK			0x10
+#define MIPI_CSIS_INTMSK_EVEN_BEFORE	(1 << 31)
+#define MIPI_CSIS_INTMSK_EVEN_AFTER	(1 << 30)
+#define MIPI_CSIS_INTMSK_ODD_BEFORE	(1 << 29)
+#define MIPI_CSIS_INTMSK_ODD_AFTER	(1 << 28)
+#define MIPI_CSIS_INTMSK_FRAME_START	(1 << 24)
+#define MIPI_CSIS_INTMSK_FRAME_END	(1 << 20)
+#define MIPI_CSIS_INTMSK_ERR_SOT_HS	(1 << 16)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FS	(1 << 12)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FE	(1 << 8)
+#define MIPI_CSIS_INTMSK_ERR_OVER		(1 << 4)
+#define MIPI_CSIS_INTMSK_ERR_WRONG_CFG	(1 << 3)
+#define MIPI_CSIS_INTMSK_ERR_ECC		(1 << 2)
+#define MIPI_CSIS_INTMSK_ERR_CRC		(1 << 1)
+#define MIPI_CSIS_INTMSK_ERR_UNKNOWN	(1 << 0)
+
+/* CSIS Interrupt source */
+#define MIPI_CSIS_INTSRC			0x14
+#define MIPI_CSIS_INTSRC_EVEN_BEFORE	(1 << 31)
+#define MIPI_CSIS_INTSRC_EVEN_AFTER	(1 << 30)
+#define MIPI_CSIS_INTSRC_EVEN		(0x3 << 30)
+#define MIPI_CSIS_INTSRC_ODD_BEFORE	(1 << 29)
+#define MIPI_CSIS_INTSRC_ODD_AFTER	(1 << 28)
+#define MIPI_CSIS_INTSRC_ODD			(0x3 << 28)
+#define MIPI_CSIS_INTSRC_NON_IMAGE_DATA	(0xf << 28)
+#define MIPI_CSIS_INTSRC_FRAME_START	(1 << 24)
+#define MIPI_CSIS_INTSRC_FRAME_END	(1 << 20)
+#define MIPI_CSIS_INTSRC_ERR_SOT_HS	(1 << 16)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FS	(1 << 12)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FE	(1 << 8)
+#define MIPI_CSIS_INTSRC_ERR_OVER		(1 << 4)
+#define MIPI_CSIS_INTSRC_ERR_WRONG_CFG	(1 << 3)
+#define MIPI_CSIS_INTSRC_ERR_ECC		(1 << 2)
+#define MIPI_CSIS_INTSRC_ERR_CRC		(1 << 1)
+#define MIPI_CSIS_INTSRC_ERR_UNKNOWN	(1 << 0)
+#define MIPI_CSIS_INTSRC_ERRORS		0xfffff
+
+/* D-PHY status control */
+#define MIPI_CSIS_DPHYSTATUS		0x20
+#define MIPI_CSIS_DPHYSTATUS_ULPS_DAT			(1 << 8)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_DAT		(1 << 4)
+#define MIPI_CSIS_DPHYSTATUS_ULPS_CLK			(1 << 1)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_CLK		(1 << 0)
+
+/* D-PHY common control */
+#define MIPI_CSIS_DPHYCTRL		0x24
+#define MIPI_CSIS_DPHYCTRL_HSS_MASK			(0xff << 24)
+#define MIPI_CSIS_DPHYCTRL_HSS_OFFSET		24
+#define MIPI_CSIS_DPHYCTRL_SCLKS_MASK		(0x3 << 22)
+#define MIPI_CSIS_DPHYCTRL_SCLKS_OFFSET		22
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_CLK	(1 << 6)
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_DAT	(1 << 5)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_DAT		(1 << 1)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_CLK		(1 << 0)
+#define MIPI_CSIS_DPHYCTRL_ENABLE			(0x1f << 0)
+
+/* D-PHY Master and Slave Control register Low */
+#define MIPI_CSIS_DPHYBCTRL_L		0x30
+/* D-PHY Master and Slave Control register High */
+#define MIPI_CSIS_DPHYBCTRL_H		0x34
+/* D-PHY Slave Control register Low */
+#define MIPI_CSIS_DPHYSCTRL_L		0x38
+/* D-PHY Slave Control register High */
+#define MIPI_CSIS_DPHYSCTRL_H		0x3c
+
+
+/* ISP Configuration register */
+#define MIPI_CSIS_ISPCONFIG_CH0			0x40
+#define MIPI_CSIS_ISPCONFIG_CH1			0x50
+#define MIPI_CSIS_ISPCONFIG_CH2			0x60
+#define MIPI_CSIS_ISPCONFIG_CH3			0x70
+
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK    (0xff << 24)
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x)     (x << 24)
+#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT        (1 << 12)
+#define MIPI_CSIS_ISPCFG_ALIGN_32BIT         (1 << 11)
+#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT   (0x1e << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW8		(0x2a << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW10		(0x2b << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW12		(0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define MIPI_CSIS_ISPCFG_FMT_USER(x)	((0x30 + x - 1) << 2)
+#define MIPI_CSIS_ISPCFG_FMT_MASK		(0x3f << 2)
+
+/* ISP Image Resolution register */
+#define MIPI_CSIS_ISPRESOL_CH0			0x44
+#define MIPI_CSIS_ISPRESOL_CH1			0x54
+#define MIPI_CSIS_ISPRESOL_CH2			0x64
+#define MIPI_CSIS_ISPRESOL_CH3			0x74
+#define CSIS_MAX_PIX_WIDTH		0xffff
+#define CSIS_MAX_PIX_HEIGHT		0xffff
+
+/* ISP SYNC register */
+#define MIPI_CSIS_ISPSYNC_CH0			0x48
+#define MIPI_CSIS_ISPSYNC_CH1			0x58
+#define MIPI_CSIS_ISPSYNC_CH2			0x68
+#define MIPI_CSIS_ISPSYNC_CH3			0x78
+
+#define MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET	18
+#define MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET 	12
+#define MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET	0
+
+/* Non-image packet data buffers */
+#define MIPI_CSIS_PKTDATA_ODD		0x2000
+#define MIPI_CSIS_PKTDATA_EVEN		0x3000
+#define MIPI_CSIS_PKTDATA_SIZE		SZ_4K
+
+#define DEFAULT_SCLK_CSIS_FREQ	166000000UL
+
+enum {
+	ST_POWERED	= 1,
+	ST_STREAMING	= 2,
+	ST_SUSPENDED	= 4,
+};
+
+struct mipi_csis_event {
+	u32 mask;
+	const char * const name;
+	unsigned int counter;
+};
+
+static const struct mipi_csis_event mipi_csis_events[] = {
+	/* Errors */
+	{ MIPI_CSIS_INTSRC_ERR_SOT_HS,	"SOT Error" },
+	{ MIPI_CSIS_INTSRC_ERR_LOST_FS,	"Lost Frame Start Error" },
+	{ MIPI_CSIS_INTSRC_ERR_LOST_FE,	"Lost Frame End Error" },
+	{ MIPI_CSIS_INTSRC_ERR_OVER,	"FIFO Overflow Error" },
+	{ MIPI_CSIS_INTSRC_ERR_ECC,	"ECC Error" },
+	{ MIPI_CSIS_INTSRC_ERR_CRC,	"CRC Error" },
+	{ MIPI_CSIS_INTSRC_ERR_UNKNOWN,	"Unknown Error" },
+	/* Non-image data receive events */
+	{ MIPI_CSIS_INTSRC_EVEN_BEFORE,	"Non-image data before even frame" },
+	{ MIPI_CSIS_INTSRC_EVEN_AFTER,	"Non-image data after even frame" },
+	{ MIPI_CSIS_INTSRC_ODD_BEFORE,	"Non-image data before odd frame" },
+	{ MIPI_CSIS_INTSRC_ODD_AFTER,	"Non-image data after odd frame" },
+	/* Frame start/end */
+	{ MIPI_CSIS_INTSRC_FRAME_START,	"Frame Start" },
+	{ MIPI_CSIS_INTSRC_FRAME_END,	"Frame End" },
+};
+#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
+
+struct csis_pktbuf {
+	u32 *data;
+	unsigned int len;
+};
+
+struct csis_hw_reset {
+	struct regmap *src;
+	u8 req_src;
+	u8 rst_bit;
+};
+
+/**
+ * struct csi_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ *        protecting @format and @flags members
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @index: the hardware instance index
+ * @pdev: CSIS platform device
+ * @phy: pointer to the CSIS generic PHY
+ * @regs: mmaped I/O registers memory
+ * @supplies: CSIS regulator supplies
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @clock_frequency: device bus clock frequency
+ * @hs_settle: HS-RX settle time
+ * @clk_settle: Clk settle time
+ * @num_lanes: number of MIPI-CSI data lanes used
+ * @max_num_lanes: maximum number of MIPI-CSI data lanes supported
+ * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ * @slock: spinlock protecting structure members below
+ * @pkt_buf: the frame embedded (non-image) data buffer
+ * @events: MIPI-CSIS event (error) counters
+ */
+struct csi_state {
+	struct mutex lock;
+	struct device		*dev;
+	struct v4l2_subdev mipi_sd;
+	struct v4l2_subdev *sensor_sd;
+	struct v4l2_device	v4l2_dev;
+
+	u8 index;
+	struct platform_device *pdev;
+	struct phy *phy;
+	void __iomem *regs;
+	struct clk *mipi_clk;
+	struct clk *phy_clk;
+	struct clk *disp_axi;
+	struct clk *disp_apb;
+	int irq;
+	u32 flags;
+
+	u32 clk_frequency;
+	u32 hs_settle;
+	u32 clk_settle;
+	u32 num_lanes;
+	u32 max_num_lanes;
+	u8 wclk_ext;
+
+	const struct csis_pix_format *csis_fmt;
+	struct v4l2_mbus_framefmt format;
+
+	spinlock_t slock;
+	struct csis_pktbuf pkt_buf;
+	struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
+
+	struct v4l2_async_subdev    asd;
+	struct v4l2_async_notifier  subdev_notifier;
+	struct v4l2_async_subdev    *async_subdevs[2];
+
+	struct csis_hw_reset hw_reset;
+	struct regulator     *mipi_phy_regulator;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ *                       multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: MIPI_CSIS_CONFIG register value
+ * @data_alignment: MIPI-CSI data alignment in bits
+ */
+struct csis_pix_format {
+	unsigned int pix_width_alignment;
+	u32 code;
+	u32 fmt_reg;
+	u8 data_alignment;
+};
+
+static const struct csis_pix_format mipi_csis_formats[] = {
+	{
+		.code = MEDIA_BUS_FMT_YUYV8_2X8,
+		.fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+		.data_alignment = 16,
+	}, {
+		.code = MEDIA_BUS_FMT_VYUY8_2X8,
+		.fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+		.data_alignment = 16,
+	}, {
+		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+		.data_alignment = 8,
+	}, {
+		.code = MEDIA_BUS_FMT_Y8_1X8,
+		.fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+		.data_alignment = 8,
+	}
+};
+
+typedef int (*mipi_csis_phy_reset_t)(struct csi_state *state);
+
+#define mipi_csis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define mipi_csis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csi_state *mipi_sd_to_csi_state(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csi_state, mipi_sd);
+}
+
+static inline struct csi_state
+				*notifier_to_mipi_dev(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct csi_state, subdev_notifier);
+}
+
+static const struct csis_pix_format *find_csis_format(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
+		if (code == mipi_csis_formats[i].code)
+			return &mipi_csis_formats[i];
+	return NULL;
+}
+
+static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
+{
+	u32 val = mipi_csis_read(state, MIPI_CSIS_INTMSK);
+	if (on)
+		val |= 0xf00fffff;
+	else
+		val &= ~0xf00fffff;
+	mipi_csis_write(state, MIPI_CSIS_INTMSK, val);
+}
+
+static void mipi_csis_sw_reset(struct csi_state *state)
+{
+	u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+
+	mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_RESET);
+	udelay(10);
+}
+
+static int mipi_csis_phy_init(struct csi_state *state)
+{
+	int ret;
+
+	state->mipi_phy_regulator = devm_regulator_get(state->dev,
+				"mipi-phy");
+
+	ret = regulator_set_voltage(state->mipi_phy_regulator,
+			1000000, 1000000);
+
+	return ret;
+}
+
+static int mipi_csis_phy_reset_mx8mm(struct csi_state *state)
+{
+	struct reset_control *phy_reset;
+
+	phy_reset = devm_reset_control_get_exclusive(state->dev, "csi,mipi_rst");
+	if (IS_ERR(phy_reset))
+		return PTR_ERR(phy_reset);
+
+	reset_control_assert(phy_reset);
+	usleep_range(10, 20);
+	reset_control_deassert(phy_reset);
+	usleep_range(10, 20);
+
+	return 0;
+
+}
+
+static int mipi_csis_phy_reset(struct csi_state *state)
+{
+	struct device_node *np = state->dev->of_node;
+	struct device_node *node;
+	phandle phandle;
+	u32 out_val[3];
+	int ret;
+
+	ret = of_property_read_u32_array(np, "csis-phy-reset", out_val, 3);
+	if (ret) {
+		dev_dbg(state->dev, "no csis-hw-reset property found\n");
+	} else {
+		phandle = *out_val;
+
+		node = of_find_node_by_phandle(phandle);
+		if (!node) {
+			dev_dbg(state->dev, "not find src node by phandle\n");
+			ret = PTR_ERR(node);
+		}
+		state->hw_reset.src = syscon_node_to_regmap(node);
+		if (IS_ERR(state->hw_reset.src)) {
+			dev_err(state->dev, "failed to get src regmap\n");
+			ret = PTR_ERR(state->hw_reset.src);
+		}
+		of_node_put(node);
+		if (ret < 0)
+			return ret;
+
+		state->hw_reset.req_src = out_val[1];
+		state->hw_reset.rst_bit = out_val[2];
+
+		/* reset mipi phy */
+		regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src,
+			1 << state->hw_reset.rst_bit, 1 << state->hw_reset.rst_bit);
+		msleep(20);
+		regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src,
+			1 << state->hw_reset.rst_bit, 0);
+
+	}
+	return ret;
+}
+
+static void mipi_csis_system_enable(struct csi_state *state, int on)
+{
+	u32 val, mask;
+
+	val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+	if (on)
+		val |= MIPI_CSIS_CMN_CTRL_ENABLE;
+	else
+		val &= ~MIPI_CSIS_CMN_CTRL_ENABLE;
+	mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+	val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+	val &= ~MIPI_CSIS_DPHYCTRL_ENABLE;
+	if (on) {
+		mask = (1 << (state->num_lanes + 1)) - 1;
+		val |= (mask & MIPI_CSIS_DPHYCTRL_ENABLE);
+	}
+	mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __mipi_csis_set_format(struct csi_state *state)
+{
+	struct v4l2_mbus_framefmt *mf = &state->format;
+	u32 val;
+
+	v4l2_dbg(1, debug, &state->mipi_sd, "fmt: %#x, %d x %d\n",
+		 mf->code, mf->width, mf->height);
+
+	/* Color format */
+	val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+	val = (val & ~MIPI_CSIS_ISPCFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+	mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+	/* Pixel resolution */
+	val = mf->width | (mf->height << 16);
+	mipi_csis_write(state, MIPI_CSIS_ISPRESOL_CH0, val);
+}
+
+static void mipi_csis_set_hsync_settle(struct csi_state *state,
+								int hs_settle, int clk_settle)
+{
+	u32 val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+
+	val = (val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) |
+				(hs_settle << 24) | (clk_settle << 22);
+
+	mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+static void mipi_csis_set_params(struct csi_state *state)
+{
+	u32 val;
+
+	val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+	val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
+	val |= (state->num_lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
+	mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+	__mipi_csis_set_format(state);
+
+	mipi_csis_set_hsync_settle(state, state->hs_settle, state->clk_settle);
+
+	val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+	if (state->csis_fmt->data_alignment == 32)
+		val |= MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+	else /* Normal output */
+		val &= ~MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+	mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+	val = (0 << MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET) |
+		(0 << MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET) |
+		(0 << MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET);
+	mipi_csis_write(state, MIPI_CSIS_ISPSYNC_CH0, val);
+
+	val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL);
+	val &= ~MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+	if (state->wclk_ext)
+		val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+	val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15);
+	val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK;
+	mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val);
+
+	mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_L, 0x1f4);
+	mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_H, 0);
+
+	/* Update the shadow register. */
+	val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+	mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW |
+					MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
+}
+
+static void mipi_csis_clk_enable(struct csi_state *state)
+{
+	clk_prepare_enable(state->mipi_clk);
+	clk_prepare_enable(state->phy_clk);
+	if (state->disp_axi)
+		clk_prepare_enable(state->disp_axi);
+	if (state->disp_apb)
+		clk_prepare_enable(state->disp_apb);
+}
+
+static void mipi_csis_clk_disable(struct csi_state *state)
+{
+	clk_disable_unprepare(state->mipi_clk);
+	clk_disable_unprepare(state->phy_clk);
+	if (state->disp_axi)
+		clk_disable_unprepare(state->disp_axi);
+	if (state->disp_apb)
+		clk_disable_unprepare(state->disp_apb);
+}
+
+static int mipi_csis_clk_get(struct csi_state *state)
+{
+	struct device *dev = &state->pdev->dev;
+	int ret = true;
+
+	state->mipi_clk = devm_clk_get(dev, "mipi_clk");
+	if (IS_ERR(state->mipi_clk)) {
+		dev_err(dev, "Could not get mipi csi clock\n");
+		return -ENODEV;
+	}
+
+	state->phy_clk = devm_clk_get(dev, "phy_clk");
+	if (IS_ERR(state->phy_clk)) {
+		dev_err(dev, "Could not get mipi phy clock\n");
+		return -ENODEV;
+	}
+
+	state->disp_axi = devm_clk_get(dev, "disp_axi");
+	if (IS_ERR(state->disp_axi)) {
+		dev_warn(dev, "Could not get disp_axi clock\n");
+		state->disp_axi = NULL;
+	}
+
+	state->disp_apb = devm_clk_get(dev, "disp_apb");
+	if (IS_ERR(state->disp_apb)) {
+		dev_warn(dev, "Could not get disp apb clock\n");
+		state->disp_apb = NULL;
+	}
+
+	/* Set clock rate */
+	if (state->clk_frequency)
+		ret = clk_set_rate(state->mipi_clk,
+				   state->clk_frequency);
+	else
+		dev_WARN(dev, "No clock frequency specified!\n");
+	if (ret < 0) {
+		dev_err(dev, "set rate filed, rate=%d\n", state->clk_frequency);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static void dump_regs(struct csi_state *state, const char *label)
+{
+	struct {
+		u32 offset;
+		const char * const name;
+	} registers[] = {
+		{ 0x00, "CTRL" },
+		{ 0x04, "DPHYCTRL" },
+		{ 0x08, "CONFIG" },
+		{ 0x0c, "DPHYSTS" },
+		{ 0x10, "INTMSK" },
+		{ 0x2c, "RESOL" },
+		{ 0x38, "SDW_CONFIG" },
+	};
+	u32 i;
+
+	v4l2_info(&state->mipi_sd, "--- %s ---\n", label);
+
+	for (i = 0; i < ARRAY_SIZE(registers); i++) {
+		u32 cfg = mipi_csis_read(state, registers[i].offset);
+		v4l2_info(&state->mipi_sd, "%10s: 0x%08x\n", registers[i].name, cfg);
+	}
+}
+
+static void mipi_csis_start_stream(struct csi_state *state)
+{
+	mipi_csis_sw_reset(state);
+	mipi_csis_set_params(state);
+	mipi_csis_system_enable(state, true);
+	mipi_csis_enable_interrupts(state, true);
+}
+
+static void mipi_csis_stop_stream(struct csi_state *state)
+{
+	mipi_csis_enable_interrupts(state, false);
+	mipi_csis_system_enable(state, false);
+}
+
+static void mipi_csis_clear_counters(struct csi_state *state)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&state->slock, flags);
+	for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++)
+		state->events[i].counter = 0;
+	spin_unlock_irqrestore(&state->slock, flags);
+}
+
+static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
+{
+	int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->slock, flags);
+
+	for (i--; i >= 0; i--) {
+		if (state->events[i].counter > 0 || debug)
+			v4l2_info(&state->mipi_sd, "%s events: %d\n",
+				  state->events[i].name,
+				  state->events[i].counter);
+	}
+	spin_unlock_irqrestore(&state->slock, flags);
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csis_s_power(struct v4l2_subdev *mipi_sd, int on)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct device *dev = &state->pdev->dev;
+
+	v4l2_subdev_call(state->sensor_sd, core, s_power, on);
+
+	if (on)
+		return pm_runtime_get_sync(dev);
+
+	return pm_runtime_put_sync(dev);
+}
+
+static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, mipi_sd, "%s: %d, state: 0x%x\n",
+		 __func__, enable, state->flags);
+
+	if (enable) {
+		mipi_csis_clear_counters(state);
+		ret = pm_runtime_get_sync(&state->pdev->dev);
+		if (ret && ret != 1)
+			return ret;
+	}
+
+	mutex_lock(&state->lock);
+	if (enable) {
+		if (state->flags & ST_SUSPENDED) {
+			ret = -EBUSY;
+			goto unlock;
+		}
+		mipi_csis_start_stream(state);
+		v4l2_subdev_call(state->sensor_sd, video, s_stream, true);
+		state->flags |= ST_STREAMING;
+	} else {
+		v4l2_subdev_call(state->sensor_sd, video, s_stream, false);
+		mipi_csis_stop_stream(state);
+		state->flags &= ~ST_STREAMING;
+		if (debug > 0)
+			mipi_csis_log_counters(state, true);
+	}
+unlock:
+	mutex_unlock(&state->lock);
+	if (!enable)
+		pm_runtime_put(&state->pdev->dev);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+	struct csis_pix_format const *csis_fmt;
+	int ret;
+
+	ret = v4l2_subdev_call(sensor_sd, pad, enum_mbus_code, NULL, code);
+	if (ret < 0)
+		return -EINVAL;
+
+	csis_fmt = find_csis_format(code->code);
+	if (csis_fmt == NULL) {
+		dev_err(state->dev, "format not match\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *format)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+	struct csis_pix_format const *csis_fmt;
+	struct v4l2_mbus_framefmt *mf  = &format->format;
+
+	if (format->pad)
+		return -EINVAL;
+
+	csis_fmt = find_csis_format(mf->code);
+	if (csis_fmt == NULL)
+		csis_fmt = &mipi_csis_formats[0];
+
+	v4l2_subdev_call(sensor_sd, pad, set_fmt, NULL, format);
+
+	mf->code = csis_fmt->code;
+	v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+			      csis_fmt->pix_width_alignment,
+			      &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+			      0);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	state->format.code = mf->code;
+	state->format.width = mf->width;
+	state->format.height = mf->height;
+
+	mutex_lock(&state->lock);
+	state->csis_fmt = csis_fmt;
+	mutex_unlock(&state->lock);
+
+	return 0;
+}
+
+static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
+			     struct v4l2_subdev_pad_config *cfg,
+			     struct v4l2_subdev_format *format)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+	if (format->pad)
+		return -EINVAL;
+
+	return v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, format);
+}
+
+static int mipi_csis_s_rx_buffer(struct v4l2_subdev *mipi_sd, void *buf,
+			       unsigned int *size)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	unsigned long flags;
+
+	*size = min_t(unsigned int, *size, MIPI_CSIS_PKTDATA_SIZE);
+
+	spin_lock_irqsave(&state->slock, flags);
+	state->pkt_buf.data = buf;
+	state->pkt_buf.len = *size;
+	spin_unlock_irqrestore(&state->slock, flags);
+
+	return 0;
+}
+
+static int mipi_csis_s_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, video, s_parm, a);
+}
+
+static int mipi_csis_g_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, video, g_parm, a);
+}
+
+static int mipi_csis_enum_framesizes(struct v4l2_subdev *mipi_sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mipi_csis_enum_frameintervals(struct v4l2_subdev *mipi_sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+	struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+	return v4l2_subdev_call(sensor_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
+{
+	struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+
+	mutex_lock(&state->lock);
+	mipi_csis_log_counters(state, true);
+	if (debug && (state->flags & ST_POWERED))
+		dump_regs(state, __func__);
+	mutex_unlock(&state->lock);
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops mipi_csis_core_ops = {
+	.s_power = mipi_csis_s_power,
+	.log_status = mipi_csis_log_status,
+};
+
+static struct v4l2_subdev_video_ops mipi_csis_video_ops = {
+	.s_rx_buffer = mipi_csis_s_rx_buffer,
+	.s_stream = mipi_csis_s_stream,
+
+	.s_parm = mipi_csis_s_parm,
+	.g_parm = mipi_csis_g_parm,
+};
+
+static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
+	.enum_frame_size       = mipi_csis_enum_framesizes,
+	.enum_frame_interval   = mipi_csis_enum_frameintervals,
+	.enum_mbus_code        = mipi_csis_enum_mbus_code,
+	.get_fmt               = mipi_csis_get_fmt,
+	.set_fmt               = mipi_csis_set_fmt,
+};
+
+static struct v4l2_subdev_ops mipi_csis_subdev_ops = {
+	.core = &mipi_csis_core_ops,
+	.video = &mipi_csis_video_ops,
+	.pad = &mipi_csis_pad_ops,
+};
+
+static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
+{
+	struct csi_state *state = dev_id;
+	struct csis_pktbuf *pktbuf = &state->pkt_buf;
+	unsigned long flags;
+	u32 status;
+
+	status = mipi_csis_read(state, MIPI_CSIS_INTSRC);
+
+	spin_lock_irqsave(&state->slock, flags);
+
+	if ((status & MIPI_CSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) {
+		u32 offset;
+
+		if (status & MIPI_CSIS_INTSRC_EVEN)
+			offset = MIPI_CSIS_PKTDATA_EVEN;
+		else
+			offset = MIPI_CSIS_PKTDATA_ODD;
+
+		memcpy(pktbuf->data, state->regs + offset, pktbuf->len);
+		pktbuf->data = NULL;
+		rmb();
+	}
+
+	/* Update the event/error counters */
+	if ((status & MIPI_CSIS_INTSRC_ERRORS) || debug) {
+		int i;
+		for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+			if (!(status & state->events[i].mask))
+				continue;
+			state->events[i].counter++;
+			v4l2_dbg(2, debug, &state->mipi_sd, "%s: %d\n",
+				 state->events[i].name,
+				 state->events[i].counter);
+		}
+		v4l2_dbg(2, debug, &state->mipi_sd, "status: %08x\n", status);
+	}
+	spin_unlock_irqrestore(&state->slock, flags);
+
+	mipi_csis_write(state, MIPI_CSIS_INTSRC, status);
+	return IRQ_HANDLED;
+}
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+			    struct v4l2_subdev *subdev,
+			    struct v4l2_async_subdev *asd)
+{
+	struct csi_state *state = notifier_to_mipi_dev(notifier);
+
+	/* Find platform data for this sensor subdev */
+	if (state->asd.match.fwnode == dev_fwnode(subdev->dev))
+		state->sensor_sd = subdev;
+
+	if (subdev == NULL)
+		return -EINVAL;
+
+	v4l2_info(&state->v4l2_dev, "Registered sensor subdevice: %s\n",
+		  subdev->name);
+
+	return 0;
+}
+
+static int mipi_csis_parse_dt(struct platform_device *pdev,
+			    struct csi_state *state)
+{
+	struct device_node *node = pdev->dev.of_node;
+
+	if (of_property_read_u32(node, "clock-frequency",
+				 &state->clk_frequency))
+		state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+	if (of_property_read_u32(node, "bus-width",
+				 &state->max_num_lanes))
+		return -EINVAL;
+
+	node = of_graph_get_next_endpoint(node, NULL);
+	if (!node) {
+		dev_err(&pdev->dev, "No port node at %s\n",
+				pdev->dev.of_node->full_name);
+		return -EINVAL;
+	}
+
+	/* Get MIPI CSI-2 bus configration from the endpoint node. */
+	of_property_read_u32(node, "csis-hs-settle",
+					&state->hs_settle);
+
+	of_property_read_u32(node, "csis-clk-settle",
+					&state->clk_settle);
+	state->wclk_ext = of_property_read_bool(node,
+					"csis-wclk");
+
+	of_property_read_u32(node, "data-lanes",
+					&state->num_lanes);
+	of_node_put(node);
+
+	return 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime);
+static const struct of_device_id mipi_csis_of_match[];
+
+static const struct v4l2_async_notifier_operations mxc_mipi_csi_subdev_ops = {
+	.bound = subdev_notifier_bound,
+};
+
+/* register parent dev */
+static int mipi_csis_subdev_host(struct csi_state *state)
+{
+	struct device_node *parent = state->dev->of_node;
+	struct device_node *node, *port, *rem;
+	int ret;
+
+	v4l2_async_notifier_init(&state->subdev_notifier);
+
+	/* Attach sensors linked to csi receivers */
+	for_each_available_child_of_node(parent, node) {
+		if (of_node_cmp(node->name, "port"))
+			continue;
+
+		/* The csi node can have only port subnode. */
+		port = of_get_next_child(node, NULL);
+		if (!port)
+			continue;
+		rem = of_graph_get_remote_port_parent(port);
+		of_node_put(port);
+		if (rem == NULL) {
+			v4l2_info(&state->v4l2_dev,
+						"Remote device at %s not found\n",
+						port->full_name);
+			return -1;
+		}
+
+		INIT_LIST_HEAD(&state->asd.list);
+		state->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+		state->asd.match.fwnode = of_fwnode_handle(rem);
+		state->async_subdevs[0] = &state->asd;
+
+		of_node_put(rem);
+		break;
+	}
+
+	ret = v4l2_async_notifier_add_subdev(&state->subdev_notifier,
+					&state->asd);
+	if (ret) {
+		dev_err(state->dev, "failed to add subdev to a notifier\n");
+		return ret;
+	}
+	state->subdev_notifier.v4l2_dev = &state->v4l2_dev;
+	state->subdev_notifier.ops = &mxc_mipi_csi_subdev_ops;
+
+	ret = v4l2_async_notifier_register(&state->v4l2_dev,
+					&state->subdev_notifier);
+	if (ret)
+		dev_err(state->dev,
+					"Error register async notifier regoster\n");
+
+	return ret;
+}
+
+/* init subdev */
+static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
+		struct platform_device *pdev,
+		const struct v4l2_subdev_ops *ops)
+{
+	struct csi_state *state = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	v4l2_subdev_init(mipi_sd, ops);
+	mipi_sd->owner = THIS_MODULE;
+	snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
+		 CSIS_SUBDEV_NAME, state->index);
+	mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	mipi_sd->dev = &pdev->dev;
+
+	state->csis_fmt = &mipi_csis_formats[0];
+	state->format.code = mipi_csis_formats[0].code;
+	state->format.width = MIPI_CSIS_DEF_PIX_WIDTH;
+	state->format.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+
+	/* This allows to retrieve the platform device id by the host driver */
+	v4l2_set_subdevdata(mipi_sd, pdev);
+
+	ret = v4l2_async_register_subdev(mipi_sd);
+	if (ret < 0)
+		dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int mipi_csis_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct v4l2_subdev *mipi_sd;
+	struct resource *mem_res;
+	struct csi_state *state;
+	const struct of_device_id *of_id;
+	mipi_csis_phy_reset_t phy_reset_fn;
+	int ret = -ENOMEM;
+
+	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mutex_init(&state->lock);
+	spin_lock_init(&state->slock);
+
+	state->pdev = pdev;
+	mipi_sd = &state->mipi_sd;
+	state->dev = dev;
+
+	ret = mipi_csis_parse_dt(pdev, state);
+	if (ret < 0)
+		return ret;
+
+	if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
+		dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n",
+			state->num_lanes, state->max_num_lanes);
+		return -EINVAL;
+	}
+
+	mipi_csis_phy_init(state);
+	of_id = of_match_node(mipi_csis_of_match, dev->of_node);
+	if (!of_id || !of_id->data)
+		return -EINVAL;
+
+	phy_reset_fn = of_id->data;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	state->regs = devm_ioremap_resource(dev, mem_res);
+	if (IS_ERR(state->regs))
+		return PTR_ERR(state->regs);
+
+	state->irq = platform_get_irq(pdev, 0);
+	if (state->irq < 0) {
+		dev_err(dev, "Failed to get irq\n");
+		return state->irq;
+	}
+
+	ret = mipi_csis_clk_get(state);
+	if (ret < 0)
+		return ret;
+
+	mipi_csis_clk_enable(state);
+
+	phy_reset_fn(state);
+
+	ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler,
+			       0, dev_name(dev), state);
+	if (ret) {
+		dev_err(dev, "Interrupt request failed\n");
+		goto e_clkdis;
+	}
+
+	/* First register a v4l2 device */
+	ret = v4l2_device_register(dev, &state->v4l2_dev);
+	if (ret) {
+		v4l2_err(dev->driver,
+			"Unable to register v4l2 device.\n");
+		goto e_clkdis;
+	}
+	v4l2_info(&state->v4l2_dev, "mipi csi v4l2 device registered\n");
+
+	/* .. and a pointer to the subdev. */
+	platform_set_drvdata(pdev, state);
+
+	ret = mipi_csis_subdev_init(&state->mipi_sd, pdev, &mipi_csis_subdev_ops);
+	if (ret < 0)
+		goto e_sd_mipi;
+
+	memcpy(state->events, mipi_csis_events, sizeof(state->events));
+
+	/* subdev host register */
+	ret = mipi_csis_subdev_host(state);
+	if (ret < 0)
+		goto e_sd_host;
+
+	pm_runtime_enable(dev);
+	if (!pm_runtime_enabled(dev)) {
+		ret = mipi_csis_pm_resume(dev, true);
+		if (ret < 0)
+			goto e_sd_host;
+	}
+
+	mipi_csis_clk_disable(state);
+	dev_info(&pdev->dev,
+			"lanes: %d, hs_settle: %d, clk_settle: %d, wclk: %d, freq: %u\n",
+		 state->num_lanes, state->hs_settle, state->clk_settle,
+		 state->wclk_ext, state->clk_frequency);
+	return 0;
+
+e_sd_host:
+	v4l2_async_notifier_unregister(&state->subdev_notifier);
+	v4l2_device_unregister(&state->v4l2_dev);
+e_sd_mipi:
+	v4l2_async_unregister_subdev(&state->mipi_sd);
+e_clkdis:
+	mipi_csis_clk_disable(state);
+	return ret;
+}
+
+static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct csi_state *state = platform_get_drvdata(pdev);
+	struct v4l2_subdev *mipi_sd = &state->mipi_sd;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n",
+		 __func__, state->flags);
+
+	mutex_lock(&state->lock);
+	if (state->flags & ST_POWERED) {
+		mipi_csis_stop_stream(state);
+		ret = regulator_disable(state->mipi_phy_regulator);
+		if (ret)
+			goto unlock;
+		mipi_csis_clk_disable(state);
+		state->flags &= ~ST_POWERED;
+		if (!runtime)
+			state->flags |= ST_SUSPENDED;
+	}
+ unlock:
+	mutex_unlock(&state->lock);
+	return ret ? -EAGAIN : 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct csi_state *state = platform_get_drvdata(pdev);
+	struct v4l2_subdev *mipi_sd = &state->mipi_sd;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n",
+		 __func__, state->flags);
+
+	mutex_lock(&state->lock);
+	if (!runtime && !(state->flags & ST_SUSPENDED))
+		goto unlock;
+
+	if (!(state->flags & ST_POWERED)) {
+		ret = regulator_enable(state->mipi_phy_regulator);
+		if (!ret) {
+			state->flags |= ST_POWERED;
+		} else {
+			goto unlock;
+		}
+		mipi_csis_clk_enable(state);
+	}
+	if (state->flags & ST_STREAMING)
+		mipi_csis_start_stream(state);
+
+	state->flags &= ~ST_SUSPENDED;
+ unlock:
+	mutex_unlock(&state->lock);
+	return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mipi_csis_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct csi_state *state = platform_get_drvdata(pdev);
+
+	if (state->flags & ST_STREAMING) {
+		dev_warn(dev, "running, prevent entering suspend.\n");
+		return -EAGAIN;
+	}
+
+	return mipi_csis_pm_suspend(dev, false);
+}
+
+static int mipi_csis_resume(struct device *dev)
+{
+	return mipi_csis_pm_resume(dev, false);
+}
+#endif
+
+static int mipi_csis_runtime_suspend(struct device *dev)
+{
+	return mipi_csis_pm_suspend(dev, true);
+}
+
+static int mipi_csis_runtime_resume(struct device *dev)
+{
+	return mipi_csis_pm_resume(dev, true);
+}
+
+static int mipi_csis_remove(struct platform_device *pdev)
+{
+	struct csi_state *state = platform_get_drvdata(pdev);
+
+	v4l2_async_unregister_subdev(&state->mipi_sd);
+	v4l2_async_notifier_unregister(&state->subdev_notifier);
+	v4l2_device_unregister(&state->v4l2_dev);
+
+	pm_runtime_disable(&pdev->dev);
+	mipi_csis_pm_suspend(&pdev->dev, true);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops mipi_csis_pm_ops = {
+	SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
+};
+
+static const struct of_device_id mipi_csis_of_match[] = {
+	{	.compatible = "fsl,imx7d-mipi-csi",
+		.data = (void *)&mipi_csis_phy_reset,
+	},
+	{	.compatible = "fsl,imx8mm-mipi-csi",
+		.data = (void *)&mipi_csis_phy_reset_mx8mm,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
+
+static struct platform_driver mipi_csis_driver = {
+	.probe		= mipi_csis_probe,
+	.remove		= mipi_csis_remove,
+	.driver		= {
+		.of_match_table = mipi_csis_of_match,
+		.name		= CSIS_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.pm		= &mipi_csis_pm_ops,
+	},
+};
+
+module_platform_driver(mipi_csis_driver);
+
+MODULE_DESCRIPTION("Freescale MIPI-CSI2 receiver driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
@@ -0,0 +1,3147 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+ *
+ * @brief Mxc Video For Linux 2 driver
+ *
+ * @ingroup MXC_V4L2_CAPTURE
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/mxcfb.h>
+#include <linux/of_device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include "v4l2-int-device.h"
+#include <linux/fsl_devices.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#define init_MUTEX(sem)         sema_init(sem, 1)
+
+static struct platform_device_id imx_v4l2_devtype[] = {
+	{
+		.name = "v4l2-capture-imx5",
+		.driver_data = IMX5_V4L2,
+	}, {
+		.name = "v4l2-capture-imx6",
+		.driver_data = IMX6_V4L2,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, imx_v4l2_devtype);
+
+static const struct of_device_id mxc_v4l2_dt_ids[] = {
+	{
+		.compatible = "fsl,imx6q-v4l2-capture",
+		.data = &imx_v4l2_devtype[IMX6_V4L2],
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, mxc_v4l2_dt_ids);
+
+static int video_nr = -1;
+
+/*! This data is used for the output to the display. */
+#define MXC_V4L2_CAPTURE_NUM_OUTPUTS	6
+#define MXC_V4L2_CAPTURE_NUM_INPUTS	2
+static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {
+	{
+	 .index = 0,
+	 .name = "DISP3 BG",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+	{
+	 .index = 1,
+	 .name = "DISP3 BG - DI1",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+	{
+	 .index = 2,
+	 .name = "DISP3 FG",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+	{
+	 .index = 3,
+	 .name = "DISP4 BG",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+	{
+	 .index = 4,
+	 .name = "DISP4 BG - DI1",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+	{
+	 .index = 5,
+	 .name = "DISP4 FG",
+	 .type = V4L2_OUTPUT_TYPE_ANALOG,
+	 .audioset = 0,
+	 .modulator = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 },
+};
+
+static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = {
+	{
+	 .index = 0,
+	 .name = "CSI IC MEM",
+	 .type = V4L2_INPUT_TYPE_CAMERA,
+	 .audioset = 0,
+	 .tuner = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 .status = 0,
+	 },
+	{
+	 .index = 1,
+	 .name = "CSI MEM",
+	 .type = V4L2_INPUT_TYPE_CAMERA,
+	 .audioset = 0,
+	 .tuner = 0,
+	 .std = V4L2_STD_UNKNOWN,
+	 .status = V4L2_IN_ST_NO_POWER,
+	 },
+};
+
+/*! List of TV input video formats supported. The video formats is corresponding
+ * to the v4l2_id in video_fmt_t.
+ * Currently, only PAL and NTSC is supported. Needs to be expanded in the
+ * future.
+ */
+typedef enum {
+	TV_NTSC = 0,		/*!< Locked on (M) NTSC video signal. */
+	TV_PAL,			/*!< (B, G, H, I, N)PAL video signal. */
+	TV_NOT_LOCKED,		/*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define TV_STD_MAX		(TV_NOT_LOCKED + 1)
+
+/*! Video format structure. */
+typedef struct {
+	int v4l2_id;		/*!< Video for linux ID. */
+	char name[16];		/*!< Name (e.g., "NTSC", "PAL", etc.) */
+	u16 raw_width;		/*!< Raw width. */
+	u16 raw_height;		/*!< Raw height. */
+	u16 active_width;	/*!< Active width. */
+	u16 active_height;	/*!< Active height. */
+	u16 active_top;		/*!< Active top. */
+	u16 active_left;	/*!< Active left. */
+} video_fmt_t;
+
+/*!
+ * Description of video formats supported.
+ *
+ *  PAL: raw=720x625, active=720x576.
+ *  NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+	{			/*! NTSC */
+	 .v4l2_id = V4L2_STD_NTSC,
+	 .name = "NTSC",
+	 .raw_width = 720,		/* SENS_FRM_WIDTH */
+	 .raw_height = 525,		/* SENS_FRM_HEIGHT */
+	 .active_width = 720,		/* ACT_FRM_WIDTH */
+	 .active_height = 480,		/* ACT_FRM_HEIGHT */
+	 .active_top = 13,
+	 .active_left = 0,
+	 },
+	{			/*! (B, G, H, I, N) PAL */
+	 .v4l2_id = V4L2_STD_PAL,
+	 .name = "PAL",
+	 .raw_width = 720,
+	 .raw_height = 625,
+	 .active_width = 720,
+	 .active_height = 576,
+	 .active_top = 0,
+	 .active_left = 0,
+	 },
+	{			/*! Unlocked standard */
+	 .v4l2_id = V4L2_STD_ALL,
+	 .name = "Autodetect",
+	 .raw_width = 720,
+	 .raw_height = 625,
+	 .active_width = 720,
+	 .active_height = 576,
+	 .active_top = 0,
+	 .active_left = 0,
+	 },
+};
+
+/*!* Standard index of TV. */
+static video_fmt_idx video_index = TV_NOT_LOCKED;
+
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave);
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave);
+static int start_preview(cam_data *cam);
+static int stop_preview(cam_data *cam);
+
+/*! Information about this driver. */
+static struct v4l2_int_master mxc_v4l2_master = {
+	.attach = mxc_v4l2_master_attach,
+	.detach = mxc_v4l2_master_detach,
+};
+
+/***************************************************************************
+ * Functions for handling Frame buffers.
+ **************************************************************************/
+
+/*!
+ * Free frame buffers
+ *
+ * @param cam      Structure cam_data *
+ *
+ * @return status  0 success.
+ */
+static int mxc_free_frame_buf(cam_data *cam)
+{
+	int i;
+
+	pr_debug("MVC: In mxc_free_frame_buf\n");
+
+	for (i = 0; i < FRAME_NUM; i++) {
+		if (cam->frame[i].vaddress != 0) {
+			dma_free_coherent(cam->dev, cam->frame[i].buffer.length,
+					  cam->frame[i].vaddress,
+					  cam->frame[i].paddress);
+			cam->frame[i].vaddress = 0;
+		}
+	}
+
+	return 0;
+}
+
+/*!
+ * Allocate frame buffers
+ *
+ * @param cam      Structure cam_data*
+ * @param count    int number of buffer need to allocated
+ *
+ * @return status  -0 Successfully allocated a buffer, -ENOBUFS	failed.
+ */
+static int mxc_allocate_frame_buf(cam_data *cam, int count)
+{
+	int i;
+
+	pr_debug("In MVC:mxc_allocate_frame_buf - size=%d\n",
+		cam->v2f.fmt.pix.sizeimage);
+
+	for (i = 0; i < count; i++) {
+		cam->frame[i].vaddress =
+		    dma_alloc_coherent(cam->dev,
+				       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+				       &cam->frame[i].paddress,
+				       GFP_DMA | GFP_KERNEL);
+		if (cam->frame[i].vaddress == 0) {
+			pr_err("ERROR: v4l2 capture: "
+				"mxc_allocate_frame_buf failed.\n");
+			mxc_free_frame_buf(cam);
+			return -ENOBUFS;
+		}
+		cam->frame[i].buffer.index = i;
+		cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+		cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cam->frame[i].buffer.length =
+		    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+		cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;
+		cam->frame[i].buffer.m.offset = cam->frame[i].paddress;
+		cam->frame[i].index = i;
+	}
+
+	return 0;
+}
+
+/*!
+ * Free frame buffers status
+ *
+ * @param cam    Structure cam_data *
+ *
+ * @return none
+ */
+static void mxc_free_frames(cam_data *cam)
+{
+	int i;
+
+	pr_debug("In MVC:mxc_free_frames\n");
+
+	for (i = 0; i < FRAME_NUM; i++)
+		cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+
+	cam->enc_counter = 0;
+	INIT_LIST_HEAD(&cam->ready_q);
+	INIT_LIST_HEAD(&cam->working_q);
+	INIT_LIST_HEAD(&cam->done_q);
+}
+
+/*!
+ * Return the buffer status
+ *
+ * @param cam	   Structure cam_data *
+ * @param buf	   Structure v4l2_buffer *
+ *
+ * @return status  0 success, EINVAL failed.
+ */
+static int mxc_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf)
+{
+	pr_debug("In MVC:mxc_v4l2_buffer_status\n");
+
+	if (buf->index >= FRAME_NUM) {
+		pr_err("ERROR: v4l2 capture: mxc_v4l2_buffer_status buffers "
+		       "not allocated\n");
+		return -EINVAL;
+	}
+
+	memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));
+	return 0;
+}
+
+static int mxc_v4l2_release_bufs(cam_data *cam)
+{
+	pr_debug("In MVC:mxc_v4l2_release_bufs\n");
+	return 0;
+}
+
+static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf)
+{
+	pr_debug("In MVC:mxc_v4l2_prepare_bufs\n");
+
+	if (buf->index >= FRAME_NUM || buf->length <
+			PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) {
+		pr_err("ERROR: v4l2 capture: mxc_v4l2_prepare_bufs buffers "
+			"not allocated,index=%d, length=%d\n", buf->index,
+			buf->length);
+		return -EINVAL;
+	}
+
+	cam->frame[buf->index].buffer.index = buf->index;
+	cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+	cam->frame[buf->index].buffer.length = buf->length;
+	cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress
+		= buf->m.offset;
+	cam->frame[buf->index].buffer.type = buf->type;
+	cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR;
+	cam->frame[buf->index].index = buf->index;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Functions for handling the video stream.
+ **************************************************************************/
+
+/*!
+ * Indicates whether the palette is supported.
+ *
+ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
+ *
+ * @return 0 if failed
+ */
+static inline int valid_mode(u32 palette)
+{
+	return ((palette == V4L2_PIX_FMT_RGB565) ||
+		(palette == V4L2_PIX_FMT_BGR24) ||
+		(palette == V4L2_PIX_FMT_RGB24) ||
+		(palette == V4L2_PIX_FMT_BGR32) ||
+		(palette == V4L2_PIX_FMT_GREY) ||
+		(palette == V4L2_PIX_FMT_RGB32) ||
+		(palette == V4L2_PIX_FMT_YUV422P) ||
+		(palette == V4L2_PIX_FMT_UYVY) ||
+		(palette == V4L2_PIX_FMT_YUYV) ||
+		(palette == V4L2_PIX_FMT_YUV420) ||
+		(palette == V4L2_PIX_FMT_YVU420) ||
+		(palette == V4L2_PIX_FMT_NV12));
+}
+
+/*!
+ * Start the encoder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int mxc_streamon(cam_data *cam)
+{
+	struct mxc_v4l_frame *frame;
+	unsigned long lock_flags;
+	int err = 0;
+
+	pr_debug("In MVC:mxc_streamon\n");
+
+	if (NULL == cam) {
+		pr_err("ERROR! cam parameter is NULL\n");
+		return -1;
+	}
+
+	if (cam->capture_on) {
+		pr_err("ERROR: v4l2 capture: Capture stream has been turned "
+		       " on\n");
+		return -1;
+	}
+
+	if (list_empty(&cam->ready_q)) {
+		pr_err("ERROR: v4l2 capture: mxc_streamon buffer has not been "
+			"queued yet\n");
+		return -EINVAL;
+	}
+	if (cam->enc_update_eba &&
+		cam->ready_q.prev == cam->ready_q.next) {
+		pr_err("ERROR: v4l2 capture: mxc_streamon buffer need "
+		       "ping pong at least two buffers\n");
+		return -EINVAL;
+	}
+
+	cam->capture_pid = current->pid;
+
+	if (cam->overlay_on == true)
+		stop_preview(cam);
+
+	if (cam->enc_enable) {
+		err = cam->enc_enable(cam);
+		if (err != 0)
+			return err;
+	}
+
+	spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+	cam->ping_pong_csi = 0;
+	cam->local_buf_num = 0;
+	if (cam->enc_update_eba) {
+		frame =
+		    list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+		list_del(cam->ready_q.next);
+		list_add_tail(&frame->queue, &cam->working_q);
+		frame->ipu_buf_num = cam->ping_pong_csi;
+		err = cam->enc_update_eba(cam, frame->buffer.m.offset);
+
+		frame =
+		    list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+		list_del(cam->ready_q.next);
+		list_add_tail(&frame->queue, &cam->working_q);
+		frame->ipu_buf_num = cam->ping_pong_csi;
+		err |= cam->enc_update_eba(cam, frame->buffer.m.offset);
+		spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+	} else {
+		spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+		return -EINVAL;
+	}
+
+	if (cam->overlay_on == true)
+		start_preview(cam);
+
+	if (cam->enc_enable_csi) {
+		err = cam->enc_enable_csi(cam);
+		if (err != 0)
+			return err;
+	}
+
+	cam->capture_on = true;
+
+	return err;
+}
+
+/*!
+ * Shut down the encoder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int mxc_streamoff(cam_data *cam)
+{
+	int err = 0;
+
+	pr_debug("In MVC:mxc_streamoff\n");
+
+	if (cam->capture_on == false)
+		return 0;
+
+	/* For both CSI--MEM and CSI--IC--MEM
+	 * 1. wait for idmac eof
+	 * 2. disable csi first
+	 * 3. disable idmac
+	 * 4. disable smfc (CSI--MEM channel)
+	 */
+	if (mxc_capture_inputs[cam->current_input].name != NULL) {
+		if (cam->enc_disable_csi) {
+			err = cam->enc_disable_csi(cam);
+			if (err != 0)
+				return err;
+		}
+		if (cam->enc_disable) {
+			err = cam->enc_disable(cam);
+			if (err != 0)
+				return err;
+		}
+	}
+
+	mxc_free_frames(cam);
+	mxc_capture_inputs[cam->current_input].status |= V4L2_IN_ST_NO_POWER;
+	cam->capture_on = false;
+	return err;
+}
+
+/*!
+ * Valid and adjust the overlay window size, position
+ *
+ * @param cam      structure cam_data *
+ * @param win      struct v4l2_window  *
+ *
+ * @return 0
+ */
+static int verify_preview(cam_data *cam, struct v4l2_window *win)
+{
+	int i = 0, width_bound = 0, height_bound = 0;
+	int *width, *height;
+	unsigned int ipu_ch = CHAN_NONE;
+	struct fb_info *bg_fbi = NULL, *fbi = NULL;
+	bool foregound_fb = false;
+	mm_segment_t old_fs;
+
+	pr_debug("In MVC: verify_preview\n");
+
+	do {
+		fbi = (struct fb_info *)registered_fb[i];
+		if (fbi == NULL) {
+			pr_err("ERROR: verify_preview frame buffer NULL.\n");
+			return -1;
+		}
+
+		/* Which DI supports 2 layers? */
+		if (((strncmp(fbi->fix.id, "DISP3 BG", 8) == 0) &&
+					(cam->output < 3)) ||
+		    ((strncmp(fbi->fix.id, "DISP4 BG", 8) == 0) &&
+					(cam->output >= 3))) {
+			if (fbi->fbops->fb_ioctl) {
+				old_fs = get_fs();
+				set_fs(KERNEL_DS);
+				fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+						(unsigned long)&ipu_ch);
+				set_fs(old_fs);
+			}
+			if (ipu_ch == MEM_BG_SYNC) {
+				bg_fbi = fbi;
+				pr_debug("Found background frame buffer.\n");
+			}
+		}
+
+		/* Found the frame buffer to preview on. */
+		if (strcmp(fbi->fix.id,
+			    mxc_capture_outputs[cam->output].name) == 0) {
+			if (((strcmp(fbi->fix.id, "DISP3 FG") == 0) &&
+						(cam->output < 3)) ||
+			    ((strcmp(fbi->fix.id, "DISP4 FG") == 0) &&
+						(cam->output >= 3)))
+				foregound_fb = true;
+
+			cam->overlay_fb = fbi;
+			break;
+		}
+	} while (++i < FB_MAX);
+
+	if (foregound_fb && bg_fbi) {
+		width_bound = bg_fbi->var.xres;
+		height_bound = bg_fbi->var.yres;
+
+		if (win->w.width + win->w.left > bg_fbi->var.xres ||
+		    win->w.height + win->w.top > bg_fbi->var.yres) {
+			pr_err("ERROR: FG window position exceeds.\n");
+			return -1;
+		}
+	} else {
+		/* 4 bytes alignment for BG */
+		width_bound = cam->overlay_fb->var.xres;
+		height_bound = cam->overlay_fb->var.yres;
+
+		if (cam->overlay_fb->var.bits_per_pixel == 24)
+			win->w.left -= win->w.left % 4;
+		else if (cam->overlay_fb->var.bits_per_pixel == 16)
+			win->w.left -= win->w.left % 2;
+
+		if (win->w.width + win->w.left > cam->overlay_fb->var.xres)
+			win->w.width = cam->overlay_fb->var.xres - win->w.left;
+		if (win->w.height + win->w.top > cam->overlay_fb->var.yres)
+			win->w.height = cam->overlay_fb->var.yres - win->w.top;
+	}
+
+	/* stride line limitation */
+	win->w.height -= win->w.height % 8;
+	win->w.width -= win->w.width % 8;
+
+	if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+		height = &win->w.width;
+		width = &win->w.height;
+	} else {
+		width = &win->w.width;
+		height = &win->w.height;
+	}
+
+	if (*width == 0 || *height == 0) {
+		pr_err("ERROR: v4l2 capture: width or height"
+			" too small.\n");
+		return -EINVAL;
+	}
+
+	if ((cam->crop_bounds.width / *width > 8) ||
+	    ((cam->crop_bounds.width / *width == 8) &&
+	     (cam->crop_bounds.width % *width))) {
+		*width = cam->crop_bounds.width / 8;
+		if (*width % 8)
+			*width += 8 - *width % 8;
+		if (*width + win->w.left > width_bound) {
+			pr_err("ERROR: v4l2 capture: width exceeds "
+				"resize limit.\n");
+			return -1;
+		}
+		pr_err("ERROR: v4l2 capture: width exceeds limit. "
+			"Resize to %d.\n",
+			*width);
+	}
+
+	if ((cam->crop_bounds.height / *height > 8) ||
+	    ((cam->crop_bounds.height / *height == 8) &&
+	     (cam->crop_bounds.height % *height))) {
+		*height = cam->crop_bounds.height / 8;
+		if (*height % 8)
+			*height += 8 - *height % 8;
+		if (*height + win->w.top > height_bound) {
+			pr_err("ERROR: v4l2 capture: height exceeds "
+				"resize limit.\n");
+			return -1;
+		}
+		pr_err("ERROR: v4l2 capture: height exceeds limit "
+			"resize to %d.\n",
+			*height);
+	}
+
+	return 0;
+}
+
+/*!
+ * start the viewfinder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int start_preview(cam_data *cam)
+{
+	int err = 0;
+
+	pr_debug("MVC: start_preview\n");
+
+	if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+	#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+		err = prp_vf_sdc_select(cam);
+	#else
+		err = foreground_sdc_select(cam);
+	#endif
+	else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+	#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+		err = prp_vf_sdc_select_bg(cam);
+	#else
+		err = bg_overlay_sdc_select(cam);
+	#endif
+	if (err != 0)
+		return err;
+
+	if (cam->vf_start_sdc) {
+		err = cam->vf_start_sdc(cam);
+		if (err != 0)
+			return err;
+	}
+
+	if (cam->vf_enable_csi)
+		err = cam->vf_enable_csi(cam);
+
+	pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+		 __func__,
+		 cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+	pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_bounds.width, cam->crop_bounds.height);
+	pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_defrect.width, cam->crop_defrect.height);
+	pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_current.width, cam->crop_current.height);
+
+	return err;
+}
+
+/*!
+ * shut down the viewfinder job
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int stop_preview(cam_data *cam)
+{
+	int err = 0;
+
+	if (cam->vf_disable_csi) {
+		err = cam->vf_disable_csi(cam);
+		if (err != 0)
+			return err;
+	}
+
+	if (cam->vf_stop_sdc) {
+		err = cam->vf_stop_sdc(cam);
+		if (err != 0)
+			return err;
+	}
+
+	if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+	#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+		err = prp_vf_sdc_deselect(cam);
+	#else
+		err = foreground_sdc_deselect(cam);
+	#endif
+	else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+	#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+		err = prp_vf_sdc_deselect_bg(cam);
+	#else
+		err = bg_overlay_sdc_deselect(cam);
+	#endif
+
+	return err;
+}
+
+/***************************************************************************
+ * VIDIOC Functions.
+ **************************************************************************/
+
+/*!
+ * V4L2 - mxc_v4l2_g_fmt function
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param f           structure v4l2_format *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f)
+{
+	int retval = 0;
+
+	pr_debug("In MVC: mxc_v4l2_g_fmt type=%d\n", f->type);
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		pr_debug("   type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+		f->fmt.pix = cam->v2f.fmt.pix;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		pr_debug("   type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+		f->fmt.win = cam->win;
+		break;
+	default:
+		pr_debug("   type is invalid\n");
+		retval = -EINVAL;
+	}
+
+	pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+		 __func__,
+		 cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+	pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_bounds.width, cam->crop_bounds.height);
+	pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_defrect.width, cam->crop_defrect.height);
+	pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_current.width, cam->crop_current.height);
+
+	return retval;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_fmt function
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param f           structure v4l2_format *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
+{
+	int retval = 0;
+	int size = 0;
+	int bytesperline = 0;
+	int *width, *height;
+
+	pr_debug("In MVC: mxc_v4l2_s_fmt\n");
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		pr_debug("   type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+		if (!valid_mode(f->fmt.pix.pixelformat)) {
+			pr_err("ERROR: v4l2 capture: mxc_v4l2_s_fmt: format "
+			       "not supported\n");
+			return -EINVAL;
+		}
+
+		/*
+		 * Force the capture window resolution to be crop bounds
+		 * for CSI MEM input mode.
+		 */
+		if (strcmp(mxc_capture_inputs[cam->current_input].name,
+			   "CSI MEM") == 0) {
+			f->fmt.pix.width = cam->crop_current.width;
+			f->fmt.pix.height = cam->crop_current.height;
+		}
+
+		if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+			height = &f->fmt.pix.width;
+			width = &f->fmt.pix.height;
+		} else {
+			width = &f->fmt.pix.width;
+			height = &f->fmt.pix.height;
+		}
+
+		/* stride line limitation */
+		*width -= *width % 8;
+		*height -= *height % 8;
+
+		if (*width == 0 || *height == 0) {
+			pr_err("ERROR: v4l2 capture: width or height"
+				" too small.\n");
+			return -EINVAL;
+		}
+
+		if ((cam->crop_current.width / *width > 8) ||
+		    ((cam->crop_current.width / *width == 8) &&
+		     (cam->crop_current.width % *width))) {
+			*width = cam->crop_current.width / 8;
+			if (*width % 8)
+				*width += 8 - *width % 8;
+			pr_err("ERROR: v4l2 capture: width exceeds limit "
+				"resize to %d.\n",
+			       *width);
+		}
+
+		if ((cam->crop_current.height / *height > 8) ||
+		    ((cam->crop_current.height / *height == 8) &&
+		     (cam->crop_current.height % *height))) {
+			*height = cam->crop_current.height / 8;
+			if (*height % 8)
+				*height += 8 - *height % 8;
+			pr_err("ERROR: v4l2 capture: height exceeds limit "
+			       "resize to %d.\n",
+			       *height);
+		}
+
+		switch (f->fmt.pix.pixelformat) {
+		case V4L2_PIX_FMT_RGB565:
+			size = f->fmt.pix.width * f->fmt.pix.height * 2;
+			bytesperline = f->fmt.pix.width * 2;
+			break;
+		case V4L2_PIX_FMT_BGR24:
+			size = f->fmt.pix.width * f->fmt.pix.height * 3;
+			bytesperline = f->fmt.pix.width * 3;
+			break;
+		case V4L2_PIX_FMT_RGB24:
+			size = f->fmt.pix.width * f->fmt.pix.height * 3;
+			bytesperline = f->fmt.pix.width * 3;
+			break;
+		case V4L2_PIX_FMT_BGR32:
+			size = f->fmt.pix.width * f->fmt.pix.height * 4;
+			bytesperline = f->fmt.pix.width * 4;
+			break;
+		case V4L2_PIX_FMT_RGB32:
+			size = f->fmt.pix.width * f->fmt.pix.height * 4;
+			bytesperline = f->fmt.pix.width * 4;
+			break;
+		case V4L2_PIX_FMT_YUV422P:
+			size = f->fmt.pix.width * f->fmt.pix.height * 2;
+			bytesperline = f->fmt.pix.width;
+			break;
+		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_YUYV:
+			size = f->fmt.pix.width * f->fmt.pix.height * 2;
+			bytesperline = f->fmt.pix.width * 2;
+			break;
+		case V4L2_PIX_FMT_YUV420:
+		case V4L2_PIX_FMT_YVU420:
+			size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+			bytesperline = f->fmt.pix.width;
+			break;
+		case V4L2_PIX_FMT_NV12:
+			size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+			bytesperline = f->fmt.pix.width;
+			break;
+		case V4L2_PIX_FMT_GREY:
+			size = f->fmt.pix.width * f->fmt.pix.height;
+			bytesperline = f->fmt.pix.width;
+			break;
+		default:
+			break;
+		}
+
+		if (f->fmt.pix.bytesperline < bytesperline)
+			f->fmt.pix.bytesperline = bytesperline;
+		else
+			bytesperline = f->fmt.pix.bytesperline;
+
+		if (f->fmt.pix.sizeimage < size)
+			f->fmt.pix.sizeimage = size;
+		else
+			size = f->fmt.pix.sizeimage;
+
+		cam->v2f.fmt.pix = f->fmt.pix;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		pr_debug("   type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+		retval = verify_preview(cam, &f->fmt.win);
+		cam->win = f->fmt.win;
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+		 __func__,
+		 cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+	pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_bounds.width, cam->crop_bounds.height);
+	pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_defrect.width, cam->crop_defrect.height);
+	pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_current.width, cam->crop_current.height);
+
+	return retval;
+}
+
+/*!
+ * get control param
+ *
+ * @param cam         structure cam_data *
+ *
+ * @param c           structure v4l2_control *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+	int status = 0;
+
+	pr_debug("In MVC:mxc_v4l2_g_ctrl\n");
+
+	/* probably don't need to store the values that can be retrieved,
+	 * locally, but they are for now. */
+	switch (c->id) {
+	case V4L2_CID_HFLIP:
+		/* This is handled in the ipu. */
+		if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+			c->value = 1;
+		break;
+	case V4L2_CID_VFLIP:
+		/* This is handled in the ipu. */
+		if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+			c->value = 1;
+		break;
+	case V4L2_CID_MXC_ROT:
+		/* This is handled in the ipu. */
+		c->value = cam->rotation;
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		if (cam->sensor) {
+			c->value = cam->bright;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->bright = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_HUE:
+		if (cam->sensor) {
+			c->value = cam->hue;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->hue = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_CONTRAST:
+		if (cam->sensor) {
+			c->value = cam->contrast;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->contrast = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_SATURATION:
+		if (cam->sensor) {
+			c->value = cam->saturation;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->saturation = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_RED_BALANCE:
+		if (cam->sensor) {
+			c->value = cam->red;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->red = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		if (cam->sensor) {
+			c->value = cam->blue;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->blue = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	case V4L2_CID_BLACK_LEVEL:
+		if (cam->sensor) {
+			c->value = cam->ae_mode;
+			status = vidioc_int_g_ctrl(cam->sensor, c);
+			cam->ae_mode = c->value;
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			status = -ENODEV;
+		}
+		break;
+	default:
+		pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n");
+	}
+
+	return status;
+}
+
+/*!
+ * V4L2 - set_control function
+ *          V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing.
+ *          0 for normal operation
+ *          1 for vertical flip
+ *          2 for horizontal flip
+ *          3 for horizontal and vertical flip
+ *          4 for 90 degree rotation
+ * @param cam         structure cam_data *
+ *
+ * @param c           structure v4l2_control *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+	int i, ret = 0;
+	int tmp_rotation = IPU_ROTATE_NONE;
+	struct sensor_data *sensor_data;
+
+	pr_debug("In MVC:mxc_v4l2_s_ctrl\n");
+
+	switch (c->id) {
+	case V4L2_CID_HFLIP:
+		/* This is done by the IPU */
+		if (c->value == 1) {
+			if ((cam->rotation != IPU_ROTATE_VERT_FLIP) &&
+			    (cam->rotation != IPU_ROTATE_180))
+				cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+			else
+				cam->rotation = IPU_ROTATE_180;
+		} else {
+			if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+				cam->rotation = IPU_ROTATE_NONE;
+			if (cam->rotation == IPU_ROTATE_180)
+				cam->rotation = IPU_ROTATE_VERT_FLIP;
+		}
+		break;
+	case V4L2_CID_VFLIP:
+		/* This is done by the IPU */
+		if (c->value == 1) {
+			if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) &&
+			    (cam->rotation != IPU_ROTATE_180))
+				cam->rotation = IPU_ROTATE_VERT_FLIP;
+			else
+				cam->rotation = IPU_ROTATE_180;
+		} else {
+			if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+				cam->rotation = IPU_ROTATE_NONE;
+			if (cam->rotation == IPU_ROTATE_180)
+				cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+		}
+		break;
+	case V4L2_CID_MXC_ROT:
+	case V4L2_CID_MXC_VF_ROT:
+		/* This is done by the IPU */
+		switch (c->value) {
+		case V4L2_MXC_ROTATE_NONE:
+			tmp_rotation = IPU_ROTATE_NONE;
+			break;
+		case V4L2_MXC_ROTATE_VERT_FLIP:
+			tmp_rotation = IPU_ROTATE_VERT_FLIP;
+			break;
+		case V4L2_MXC_ROTATE_HORIZ_FLIP:
+			tmp_rotation = IPU_ROTATE_HORIZ_FLIP;
+			break;
+		case V4L2_MXC_ROTATE_180:
+			tmp_rotation = IPU_ROTATE_180;
+			break;
+		case V4L2_MXC_ROTATE_90_RIGHT:
+			tmp_rotation = IPU_ROTATE_90_RIGHT;
+			break;
+		case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
+			tmp_rotation = IPU_ROTATE_90_RIGHT_VFLIP;
+			break;
+		case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
+			tmp_rotation = IPU_ROTATE_90_RIGHT_HFLIP;
+			break;
+		case V4L2_MXC_ROTATE_90_LEFT:
+			tmp_rotation = IPU_ROTATE_90_LEFT;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+		if (c->id == V4L2_CID_MXC_VF_ROT)
+			cam->vf_rotation = tmp_rotation;
+		else
+			cam->rotation = tmp_rotation;
+		#else
+			cam->rotation = tmp_rotation;
+		#endif
+
+		break;
+	case V4L2_CID_HUE:
+		if (cam->sensor) {
+			cam->hue = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_CONTRAST:
+		if (cam->sensor) {
+			cam->contrast = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		if (cam->sensor) {
+			cam->bright = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_SATURATION:
+		if (cam->sensor) {
+			cam->saturation = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_RED_BALANCE:
+		if (cam->sensor) {
+			cam->red = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		if (cam->sensor) {
+			cam->blue = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_EXPOSURE:
+		if (cam->sensor) {
+			cam->ae_mode = c->value;
+			ret = vidioc_int_s_ctrl(cam->sensor, c);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			ret = -ENODEV;
+		}
+		break;
+	case V4L2_CID_MXC_FLASH:
+#ifdef CONFIG_MXC_IPU_V1
+		ipu_csi_flash_strobe(true);
+#endif
+		break;
+	case V4L2_CID_MXC_SWITCH_CAM:
+		if (cam->sensor == cam->all_sensors[c->value])
+			break;
+
+		/* power down other cameraes before enable new one */
+		for (i = 0; i < cam->sensor_index; i++) {
+			if (i != c->value) {
+				vidioc_int_dev_exit(cam->all_sensors[i]);
+				vidioc_int_s_power(cam->all_sensors[i], 0);
+				if (cam->mclk_on[cam->mclk_source]) {
+					ipu_csi_enable_mclk_if(cam->ipu,
+							CSI_MCLK_I2C,
+							cam->mclk_source,
+							false, false);
+					cam->mclk_on[cam->mclk_source] =
+								false;
+				}
+			}
+		}
+		sensor_data = cam->all_sensors[c->value]->priv;
+		if (sensor_data->io_init)
+			sensor_data->io_init();
+		cam->sensor = cam->all_sensors[c->value];
+		cam->mclk_source = sensor_data->mclk_source;
+		ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+				       cam->mclk_source, true, true);
+		cam->mclk_on[cam->mclk_source] = true;
+		vidioc_int_s_power(cam->sensor, 1);
+		vidioc_int_dev_init(cam->sensor);
+		break;
+	default:
+		pr_debug("   default case\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_param function
+ * Allows setting of capturemode and frame rate.
+ *
+ * @param cam         structure cam_data *
+ * @param parm        structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
+{
+	struct v4l2_ifparm ifparm;
+	struct v4l2_format cam_fmt;
+	struct v4l2_streamparm currentparm;
+	ipu_csi_signal_cfg_t csi_param;
+	u32 current_fps, parm_fps;
+	int err = 0;
+
+	pr_debug("In mxc_v4l2_s_param\n");
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n");
+		return -EINVAL;
+	}
+
+	/* Stop the viewfinder */
+	if (cam->overlay_on == true)
+		stop_preview(cam);
+
+	currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	/* First check that this device can support the changes requested. */
+	err = vidioc_int_g_parm(cam->sensor, &currentparm);
+	if (err) {
+		pr_err("%s: vidioc_int_g_parm returned an error %d\n",
+			__func__, err);
+		goto exit;
+	}
+
+	current_fps = currentparm.parm.capture.timeperframe.denominator
+			/ currentparm.parm.capture.timeperframe.numerator;
+	parm_fps = parm->parm.capture.timeperframe.denominator
+			/ parm->parm.capture.timeperframe.numerator;
+
+	pr_debug("   Current capabilities are %x\n",
+			currentparm.parm.capture.capability);
+	pr_debug("   Current capturemode is %d  change to %d\n",
+			currentparm.parm.capture.capturemode,
+			parm->parm.capture.capturemode);
+	pr_debug("   Current framerate is %d  change to %d\n",
+			current_fps, parm_fps);
+
+	/* This will change any camera settings needed. */
+	err = vidioc_int_s_parm(cam->sensor, parm);
+	if (err) {
+		pr_err("%s: vidioc_int_s_parm returned an error %d\n",
+			__func__, err);
+		goto exit;
+	}
+
+	/* If resolution changed, need to re-program the CSI */
+	/* Get new values. */
+	vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+	csi_param.data_width = 0;
+	csi_param.clk_mode = 0;
+	csi_param.ext_vsync = 0;
+	csi_param.Vsync_pol = 0;
+	csi_param.Hsync_pol = 0;
+	csi_param.pixclk_pol = 0;
+	csi_param.data_pol = 0;
+	csi_param.sens_clksrc = 0;
+	csi_param.pack_tight = 0;
+	csi_param.force_eof = 0;
+	csi_param.data_en_pol = 0;
+	csi_param.data_fmt = 0;
+	csi_param.csi = cam->csi;
+	csi_param.mclk = 0;
+
+	pr_debug("   clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr);
+	if (ifparm.u.bt656.clock_curr == 0)
+		csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+	else
+		csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+
+	csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+	if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) {
+		csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+	} else if (ifparm.u.bt656.mode
+				== V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) {
+		csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+	} else {
+		csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+	}
+
+	csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+	csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+	csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct;
+
+	/* if the capturemode changed, the size bounds will have changed. */
+	cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+	pr_debug("   g_fmt_cap returns widthxheight of input as %d x %d\n",
+			cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+
+	csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+
+	cam->crop_bounds.top = cam->crop_bounds.left = 0;
+	cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+	cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+	/*
+	 * Set the default current cropped resolution to be the same with
+	 * the cropping boundary(except for tvin module).
+	 */
+	if (cam->device_type != 1) {
+		cam->crop_current.width = cam->crop_bounds.width;
+		cam->crop_current.height = cam->crop_bounds.height;
+	}
+
+	/* This essentially loses the data at the left and bottom of the image
+	 * giving a digital zoom image, if crop_current is less than the full
+	 * size of the image. */
+	ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+				cam->crop_current.height, cam->csi);
+	ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+			       cam->crop_current.top,
+			       cam->csi);
+	ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+			       cam->crop_bounds.height,
+			       cam_fmt.fmt.pix.pixelformat, csi_param);
+
+
+exit:
+	if (cam->overlay_on == true)
+		start_preview(cam);
+
+	return err;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_std function
+ *
+ * Sets the TV standard to be used.
+ *
+ * @param cam	      structure cam_data *
+ * @param parm	      structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_std(cam_data *cam, v4l2_std_id e)
+{
+	pr_debug("In mxc_v4l2_s_std %Lx\n", e);
+
+	if (e == V4L2_STD_PAL) {
+		pr_debug("   Setting standard to PAL %Lx\n", V4L2_STD_PAL);
+		cam->standard.id = V4L2_STD_PAL;
+		video_index = TV_PAL;
+	} else if (e == V4L2_STD_NTSC) {
+		pr_debug("   Setting standard to NTSC %Lx\n",
+				V4L2_STD_NTSC);
+		/* Get rid of the white dot line in NTSC signal input */
+		cam->standard.id = V4L2_STD_NTSC;
+		video_index = TV_NTSC;
+	} else {
+		cam->standard.id = V4L2_STD_ALL;
+		video_index = TV_NOT_LOCKED;
+		pr_err("ERROR: unrecognized std! %Lx (PAL=%Lx, NTSC=%Lx\n",
+			e, V4L2_STD_PAL, V4L2_STD_NTSC);
+	}
+
+	cam->standard.index = video_index;
+	strcpy(cam->standard.name, video_fmts[video_index].name);
+	cam->crop_bounds.width = video_fmts[video_index].raw_width;
+	cam->crop_bounds.height = video_fmts[video_index].raw_height;
+	cam->crop_current.width = video_fmts[video_index].active_width;
+	cam->crop_current.height = video_fmts[video_index].active_height;
+	cam->crop_current.top = video_fmts[video_index].active_top;
+	cam->crop_current.left = video_fmts[video_index].active_left;
+
+	return 0;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_g_std function
+ *
+ * Gets the TV standard from the TV input device.
+ *
+ * @param cam	      structure cam_data *
+ *
+ * @param e	      structure v4l2_streamparm *
+ *
+ * @return  status    0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e)
+{
+	struct v4l2_format tv_fmt;
+
+	pr_debug("In mxc_v4l2_g_std\n");
+
+	if (cam->device_type == 1) {
+		/* Use this function to get what the TV-In device detects the
+		 * format to be. pixelformat is used to return the std value
+		 * since the interface has no vidioc_g_std.*/
+		tv_fmt.type = V4L2_BUF_TYPE_PRIVATE;
+		vidioc_int_g_fmt_cap(cam->sensor, &tv_fmt);
+
+		/* If the TV-in automatically detects the standard, then if it
+		 * changes, the settings need to change. */
+		if (cam->standard_autodetect) {
+			if (cam->standard.id != tv_fmt.fmt.pix.pixelformat) {
+				pr_debug("MVC: mxc_v4l2_g_std: "
+					"Changing standard\n");
+				mxc_v4l2_s_std(cam, tv_fmt.fmt.pix.pixelformat);
+			}
+		}
+
+		*e = tv_fmt.fmt.pix.pixelformat;
+	}
+
+	return 0;
+}
+
+/*!
+ * Dequeue one V4L capture buffer
+ *
+ * @param cam         structure cam_data *
+ * @param buf         structure v4l2_buffer *
+ *
+ * @return  status    0 success, EINVAL invalid frame number,
+ *                    ETIME timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
+{
+	int retval = 0;
+	struct mxc_v4l_frame *frame;
+	unsigned long lock_flags;
+
+	pr_debug("In MVC:mxc_v4l_dqueue\n");
+
+	if (!wait_event_interruptible_timeout(cam->enc_queue,
+					      cam->enc_counter != 0,
+					      10 * HZ)) {
+		pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout "
+			"enc_counter %x\n",
+		       cam->enc_counter);
+		return -ETIME;
+	} else if (signal_pending(current)) {
+		pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() "
+			"interrupt received\n");
+		return -ERESTARTSYS;
+	}
+
+	if (down_interruptible(&cam->busy_lock))
+		return -EBUSY;
+
+	spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags);
+	cam->enc_counter--;
+
+	frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
+	list_del(cam->done_q.next);
+	if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) {
+		frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
+	} else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+		pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+			"Buffer not filled.\n");
+		frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+		retval = -EINVAL;
+	} else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {
+		pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+			"Buffer not queued.\n");
+		retval = -EINVAL;
+	}
+
+	cam->frame[frame->index].buffer.field = cam->device_type ?
+				V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+
+	buf->bytesused = cam->v2f.fmt.pix.sizeimage;
+	buf->index = frame->index;
+	buf->flags = frame->buffer.flags;
+	buf->m = cam->frame[frame->index].buffer.m;
+	buf->timestamp = cam->frame[frame->index].buffer.timestamp;
+	buf->field = cam->frame[frame->index].buffer.field;
+	spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags);
+
+	up(&cam->busy_lock);
+	return retval;
+}
+
+/*!
+ * V4L interface - open function
+ *
+ * @param file         structure file *
+ *
+ * @return  status    0 success, ENODEV invalid device instance,
+ *                    ENODEV timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_open(struct file *file)
+{
+	struct v4l2_ifparm ifparm;
+	struct v4l2_format cam_fmt;
+	ipu_csi_signal_cfg_t csi_param;
+	struct video_device *dev = video_devdata(file);
+	cam_data *cam = video_get_drvdata(dev);
+	int err = 0;
+	struct sensor_data *sensor;
+
+	pr_debug("\nIn MVC: mxc_v4l_open\n");
+	pr_debug("   device name is %s\n", dev->name);
+
+	if (!cam) {
+		pr_err("ERROR: v4l2 capture: Internal error, "
+			"cam_data not found!\n");
+		return -EBADF;
+	}
+
+	if (cam->sensor == NULL ||
+	    cam->sensor->type != v4l2_int_type_slave) {
+		pr_err("ERROR: v4l2 capture: slave not found!\n");
+		return -EAGAIN;
+	}
+
+	sensor = cam->sensor->priv;
+	if (!sensor) {
+		pr_err("%s: Internal error, sensor_data is not found!\n",
+		       __func__);
+		return -EBADF;
+	}
+
+	down(&cam->busy_lock);
+	err = 0;
+	if (signal_pending(current))
+		goto oops;
+
+	if (cam->open_count++ == 0) {
+		wait_event_interruptible(cam->power_queue,
+					 cam->low_power == false);
+
+		if (strcmp(mxc_capture_inputs[cam->current_input].name,
+			   "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+			err = csi_enc_select(cam);
+#endif
+		} else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+				  "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+			err = prp_enc_select(cam);
+#endif
+		}
+
+		cam->enc_counter = 0;
+		INIT_LIST_HEAD(&cam->ready_q);
+		INIT_LIST_HEAD(&cam->working_q);
+		INIT_LIST_HEAD(&cam->done_q);
+
+		vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+		csi_param.sens_clksrc = 0;
+
+		csi_param.clk_mode = 0;
+		csi_param.data_pol = 0;
+		csi_param.ext_vsync = 0;
+
+		csi_param.pack_tight = 0;
+		csi_param.force_eof = 0;
+		csi_param.data_en_pol = 0;
+
+		csi_param.mclk = ifparm.u.bt656.clock_curr;
+
+		csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+		if (ifparm.u.bt656.mode
+				== V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT)
+			csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+		else if (ifparm.u.bt656.mode
+				== V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT)
+			csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+		else
+			csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+
+
+		csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+		csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+
+		csi_param.csi = cam->csi;
+
+		cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+		/* Reset the sizes.  Needed to prevent carryover of last
+		 * operation.*/
+		cam->crop_bounds.top = cam->crop_bounds.left = 0;
+		cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+		cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+		/* This also is the max crop size for this device. */
+		cam->crop_defrect.top = cam->crop_defrect.left = 0;
+		cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+		cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+		/* At this point, this is also the current image size. */
+		cam->crop_current.top = cam->crop_current.left = 0;
+		cam->crop_current.width = cam_fmt.fmt.pix.width;
+		cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+		pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+			__func__,
+			cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+		pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+			__func__,
+			cam->crop_bounds.width, cam->crop_bounds.height);
+		pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+			__func__,
+			cam->crop_defrect.width, cam->crop_defrect.height);
+		pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+			__func__,
+			cam->crop_current.width, cam->crop_current.height);
+
+		csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+		pr_debug("On Open: Input to ipu size is %d x %d\n",
+				cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+		ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+					cam->crop_current.height,
+					cam->csi);
+		ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+					cam->crop_current.top,
+					cam->csi);
+		ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+					cam->crop_bounds.height,
+					cam_fmt.fmt.pix.pixelformat,
+					csi_param);
+		clk_prepare_enable(sensor->sensor_clk);
+		vidioc_int_s_power(cam->sensor, 1);
+		vidioc_int_init(cam->sensor);
+		vidioc_int_dev_init(cam->sensor);
+	}
+
+	file->private_data = dev;
+
+oops:
+	up(&cam->busy_lock);
+	return err;
+}
+
+/*!
+ * V4L interface - close function
+ *
+ * @param file     struct file *
+ *
+ * @return         0 success
+ */
+static int mxc_v4l_close(struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	int err = 0;
+	cam_data *cam = video_get_drvdata(dev);
+	struct sensor_data *sensor;
+	pr_debug("In MVC:mxc_v4l_close\n");
+
+	if (!cam) {
+		pr_err("ERROR: v4l2 capture: Internal error, "
+			"cam_data not found!\n");
+		return -EBADF;
+	}
+
+	if (!cam->sensor) {
+		pr_err("%s: Internal error, camera is not found!\n",
+		       __func__);
+		return -EBADF;
+	}
+
+	sensor = cam->sensor->priv;
+	if (!sensor) {
+		pr_err("%s: Internal error, sensor_data is not found!\n",
+		       __func__);
+		return -EBADF;
+	}
+
+	down(&cam->busy_lock);
+
+	/* for the case somebody hit the ctrl C */
+	if (cam->overlay_pid == current->pid && cam->overlay_on) {
+		err = stop_preview(cam);
+		cam->overlay_on = false;
+	}
+	if (cam->capture_pid == current->pid) {
+		err |= mxc_streamoff(cam);
+		wake_up_interruptible(&cam->enc_queue);
+	}
+
+	if (--cam->open_count == 0) {
+		vidioc_int_s_power(cam->sensor, 0);
+		clk_disable_unprepare(sensor->sensor_clk);
+		wait_event_interruptible(cam->power_queue,
+					 cam->low_power == false);
+		pr_debug("mxc_v4l_close: release resource\n");
+
+		if (strcmp(mxc_capture_inputs[cam->current_input].name,
+			   "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+			err |= csi_enc_deselect(cam);
+#endif
+		} else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+				  "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+			err |= prp_enc_deselect(cam);
+#endif
+		}
+
+		mxc_free_frame_buf(cam);
+		file->private_data = NULL;
+
+		/* capture off */
+		wake_up_interruptible(&cam->enc_queue);
+		mxc_free_frames(cam);
+		cam->enc_counter++;
+	}
+
+	up(&cam->busy_lock);
+
+	return err;
+}
+
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC) || \
+    defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) || \
+    defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+/*
+ * V4L interface - read function
+ *
+ * @param file       struct file *
+ * @param read buf   char *
+ * @param count      size_t
+ * @param ppos       structure loff_t *
+ *
+ * @return           bytes read
+ */
+static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
+			    loff_t *ppos)
+{
+	int err = 0;
+	u8 *v_address[2];
+	struct video_device *dev = video_devdata(file);
+	cam_data *cam = video_get_drvdata(dev);
+
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	/* Stop the viewfinder */
+	if (cam->overlay_on == true)
+		stop_preview(cam);
+
+	v_address[0] = dma_alloc_coherent(cam->dev,
+				       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+				       &cam->still_buf[0],
+				       GFP_DMA | GFP_KERNEL);
+
+	v_address[1] = dma_alloc_coherent(cam->dev,
+				       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+				       &cam->still_buf[1],
+				       GFP_DMA | GFP_KERNEL);
+
+	if (!v_address[0] || !v_address[1]) {
+		err = -ENOBUFS;
+		goto exit0;
+	}
+
+	err = prp_still_select(cam);
+	if (err != 0) {
+		err = -EIO;
+		goto exit0;
+	}
+
+	cam->still_counter = 0;
+	err = cam->csi_start(cam);
+	if (err != 0) {
+		err = -EIO;
+		goto exit1;
+	}
+
+	if (!wait_event_interruptible_timeout(cam->still_queue,
+					      cam->still_counter != 0,
+					      10 * HZ)) {
+		pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n",
+		       cam->still_counter);
+		err = -ETIME;
+		goto exit1;
+	}
+	err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage);
+
+exit1:
+	prp_still_deselect(cam);
+
+exit0:
+	if (v_address[0] != 0)
+		dma_free_coherent(cam->dev, cam->v2f.fmt.pix.sizeimage, v_address[0],
+				  cam->still_buf[0]);
+	if (v_address[1] != 0)
+		dma_free_coherent(cam->dev, cam->v2f.fmt.pix.sizeimage, v_address[1],
+				  cam->still_buf[1]);
+
+	cam->still_buf[0] = cam->still_buf[1] = 0;
+
+	if (cam->overlay_on == true)
+		start_preview(cam);
+
+	up(&cam->busy_lock);
+	if (err < 0)
+		return err;
+
+	return cam->v2f.fmt.pix.sizeimage - err;
+}
+#endif
+
+/*!
+ * V4L interface - ioctl function
+ *
+ * @param file       struct file*
+ *
+ * @param ioctlnr    unsigned int
+ *
+ * @param arg        void*
+ *
+ * @return           0 success, ENODEV for invalid device instance,
+ *                   -1 for other errors.
+ */
+static long mxc_v4l_do_ioctl(struct file *file,
+			    unsigned int ioctlnr, void *arg)
+{
+	struct video_device *dev = video_devdata(file);
+	cam_data *cam = video_get_drvdata(dev);
+	int retval = 0;
+	unsigned long lock_flags;
+
+	pr_debug("In MVC: mxc_v4l_do_ioctl %x\n", ioctlnr);
+	wait_event_interruptible(cam->power_queue, cam->low_power == false);
+	/* make this _really_ smp-safe */
+	if (ioctlnr != VIDIOC_DQBUF)
+		if (down_interruptible(&cam->busy_lock))
+			return -EBUSY;
+
+	switch (ioctlnr) {
+	/*!
+	 * V4l2 VIDIOC_QUERYCAP ioctl
+	 */
+	case VIDIOC_QUERYCAP: {
+		struct v4l2_capability *cap = arg;
+		pr_debug("   case VIDIOC_QUERYCAP\n");
+		strcpy(cap->driver, "mxc_v4l2");
+		cap->version = KERNEL_VERSION(0, 1, 11);
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+				    V4L2_CAP_VIDEO_OVERLAY |
+				    V4L2_CAP_STREAMING |
+				    V4L2_CAP_READWRITE;
+		cap->card[0] = '\0';
+		cap->bus_info[0] = '\0';
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_G_FMT ioctl
+	 */
+	case VIDIOC_G_FMT: {
+		struct v4l2_format *gf = arg;
+		pr_debug("   case VIDIOC_G_FMT\n");
+		retval = mxc_v4l2_g_fmt(cam, gf);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_S_DEST_CROP ioctl
+	 */
+	case VIDIOC_S_DEST_CROP: {
+		struct v4l2_mxc_dest_crop  *of = arg;
+		pr_debug("   case VIDIOC_S_DEST_CROP\n");
+		cam->offset.u_offset = of->offset.u_offset;
+		cam->offset.v_offset = of->offset.v_offset;
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_S_FMT ioctl
+	 */
+	case VIDIOC_S_FMT: {
+		struct v4l2_format *sf = arg;
+		pr_debug("   case VIDIOC_S_FMT\n");
+		retval = mxc_v4l2_s_fmt(cam, sf);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_REQBUFS ioctl
+	 */
+	case VIDIOC_REQBUFS: {
+		struct v4l2_requestbuffers *req = arg;
+		pr_debug("   case VIDIOC_REQBUFS\n");
+
+		if (req->count > FRAME_NUM) {
+			pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+			       "not enough buffers\n");
+			req->count = FRAME_NUM;
+		}
+
+		if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+			pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+			       "wrong buffer type\n");
+			retval = -EINVAL;
+			break;
+		}
+
+		mxc_streamoff(cam);
+		if (req->memory & V4L2_MEMORY_MMAP) {
+			mxc_free_frame_buf(cam);
+			retval = mxc_allocate_frame_buf(cam, req->count);
+		}
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_QUERYBUF ioctl
+	 */
+	case VIDIOC_QUERYBUF: {
+		struct v4l2_buffer *buf = arg;
+		int index = buf->index;
+		pr_debug("   case VIDIOC_QUERYBUF\n");
+
+		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			pr_err("ERROR: v4l2 capture: "
+			       "VIDIOC_QUERYBUFS: "
+			       "wrong buffer type\n");
+			retval = -EINVAL;
+			break;
+		}
+
+		down(&cam->param_lock);
+		if (buf->memory & V4L2_MEMORY_USERPTR) {
+			mxc_v4l2_release_bufs(cam);
+			retval = mxc_v4l2_prepare_bufs(cam, buf);
+		}
+
+		if (buf->memory & V4L2_MEMORY_MMAP) {
+			memset(buf, 0, sizeof(*buf));
+			buf->index = index;
+			retval = mxc_v4l2_buffer_status(cam, buf);
+		}
+		up(&cam->param_lock);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_QBUF ioctl
+	 */
+	case VIDIOC_QBUF: {
+		struct v4l2_buffer *buf = arg;
+		int index = buf->index;
+		pr_debug("   case VIDIOC_QBUF\n");
+
+		spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+		if ((cam->frame[index].buffer.flags & 0x7) ==
+		    V4L2_BUF_FLAG_MAPPED) {
+			cam->frame[index].buffer.flags |=
+			    V4L2_BUF_FLAG_QUEUED;
+			list_add_tail(&cam->frame[index].queue,
+				      &cam->ready_q);
+		} else if (cam->frame[index].buffer.
+			   flags & V4L2_BUF_FLAG_QUEUED) {
+			pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+			       "buffer already queued\n");
+			retval = -EINVAL;
+		} else if (cam->frame[index].buffer.
+			   flags & V4L2_BUF_FLAG_DONE) {
+			pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+			       "overwrite done buffer.\n");
+			cam->frame[index].buffer.flags &=
+			    ~V4L2_BUF_FLAG_DONE;
+			cam->frame[index].buffer.flags |=
+			    V4L2_BUF_FLAG_QUEUED;
+			retval = -EINVAL;
+		}
+
+		buf->flags = cam->frame[index].buffer.flags;
+		spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_DQBUF ioctl
+	 */
+	case VIDIOC_DQBUF: {
+		struct v4l2_buffer *buf = arg;
+		pr_debug("   case VIDIOC_DQBUF\n");
+
+		if ((cam->enc_counter == 0) &&
+			(file->f_flags & O_NONBLOCK)) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		retval = mxc_v4l_dqueue(cam, buf);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_STREAMON ioctl
+	 */
+	case VIDIOC_STREAMON: {
+		pr_debug("   case VIDIOC_STREAMON\n");
+		retval = mxc_streamon(cam);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_STREAMOFF ioctl
+	 */
+	case VIDIOC_STREAMOFF: {
+		pr_debug("   case VIDIOC_STREAMOFF\n");
+		retval = mxc_streamoff(cam);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_G_CTRL ioctl
+	 */
+	case VIDIOC_G_CTRL: {
+		pr_debug("   case VIDIOC_G_CTRL\n");
+		retval = mxc_v4l2_g_ctrl(cam, arg);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_S_CTRL ioctl
+	 */
+	case VIDIOC_S_CTRL: {
+		pr_debug("   case VIDIOC_S_CTRL\n");
+		retval = mxc_v4l2_s_ctrl(cam, arg);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_CROPCAP ioctl
+	 */
+	case VIDIOC_CROPCAP: {
+		struct v4l2_cropcap *cap = arg;
+		pr_debug("   case VIDIOC_CROPCAP\n");
+		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+			retval = -EINVAL;
+			break;
+		}
+		cap->bounds = cam->crop_bounds;
+		cap->defrect = cam->crop_defrect;
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_G_CROP ioctl
+	 */
+	case VIDIOC_G_CROP: {
+		struct v4l2_crop *crop = arg;
+		pr_debug("   case VIDIOC_G_CROP\n");
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+			retval = -EINVAL;
+			break;
+		}
+		crop->c = cam->crop_current;
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_S_CROP ioctl
+	 */
+	case VIDIOC_S_CROP: {
+		struct v4l2_crop *crop = arg;
+		struct v4l2_rect *b = &cam->crop_bounds;
+		pr_debug("   case VIDIOC_S_CROP\n");
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+			retval = -EINVAL;
+			break;
+		}
+
+		crop->c.top = (crop->c.top < b->top) ? b->top
+			      : crop->c.top;
+		if (crop->c.top > b->top + b->height)
+			crop->c.top = b->top + b->height - 1;
+		if (crop->c.height > b->top + b->height - crop->c.top)
+			crop->c.height =
+				b->top + b->height - crop->c.top;
+
+		crop->c.left = (crop->c.left < b->left) ? b->left
+		    : crop->c.left;
+		if (crop->c.left > b->left + b->width)
+			crop->c.left = b->left + b->width - 1;
+		if (crop->c.width > b->left - crop->c.left + b->width)
+			crop->c.width =
+				b->left - crop->c.left + b->width;
+
+		crop->c.width -= crop->c.width % 8;
+		crop->c.left -= crop->c.left % 4;
+		cam->crop_current = crop->c;
+
+		pr_debug("   Cropping Input to ipu size %d x %d\n",
+				cam->crop_current.width,
+				cam->crop_current.height);
+		ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+					cam->crop_current.height,
+					cam->csi);
+		ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+				       cam->crop_current.top,
+				       cam->csi);
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_OVERLAY ioctl
+	 */
+	case VIDIOC_OVERLAY: {
+		int *on = arg;
+		pr_debug("   VIDIOC_OVERLAY on=%d\n", *on);
+		if (*on) {
+			cam->overlay_on = true;
+			cam->overlay_pid = current->pid;
+			retval = start_preview(cam);
+		}
+		if (!*on) {
+			retval = stop_preview(cam);
+			cam->overlay_on = false;
+		}
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_G_FBUF ioctl
+	 */
+	case VIDIOC_G_FBUF: {
+		struct v4l2_framebuffer *fb = arg;
+		pr_debug("   case VIDIOC_G_FBUF\n");
+		*fb = cam->v4l2_fb;
+		fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
+		break;
+	}
+
+	/*!
+	 * V4l2 VIDIOC_S_FBUF ioctl
+	 */
+	case VIDIOC_S_FBUF: {
+		struct v4l2_framebuffer *fb = arg;
+		pr_debug("   case VIDIOC_S_FBUF\n");
+		cam->v4l2_fb = *fb;
+		break;
+	}
+
+	case VIDIOC_G_PARM: {
+		struct v4l2_streamparm *parm = arg;
+		pr_debug("   case VIDIOC_G_PARM\n");
+		if (cam->sensor)
+			retval = vidioc_int_g_parm(cam->sensor, parm);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+
+	case VIDIOC_S_PARM:  {
+		struct v4l2_streamparm *parm = arg;
+		pr_debug("   case VIDIOC_S_PARM\n");
+		if (cam->sensor)
+			retval = mxc_v4l2_s_param(cam, parm);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+
+	/* linux v4l2 bug, kernel c0485619 user c0405619 */
+	case VIDIOC_ENUMSTD: {
+		struct v4l2_standard *e = arg;
+		pr_debug("   case VIDIOC_ENUMSTD\n");
+		*e = cam->standard;
+		break;
+	}
+
+	case VIDIOC_G_STD: {
+		v4l2_std_id *e = arg;
+		pr_debug("   case VIDIOC_G_STD\n");
+		if (cam->sensor)
+			retval = mxc_v4l2_g_std(cam, e);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+
+	case VIDIOC_S_STD: {
+		v4l2_std_id *e = arg;
+		pr_debug("   case VIDIOC_S_STD\n");
+		retval = mxc_v4l2_s_std(cam, *e);
+
+		break;
+	}
+
+	case VIDIOC_ENUMOUTPUT: {
+		struct v4l2_output *output = arg;
+		pr_debug("   case VIDIOC_ENUMOUTPUT\n");
+		if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+			retval = -EINVAL;
+			break;
+		}
+		*output = mxc_capture_outputs[output->index];
+
+		break;
+	}
+	case VIDIOC_G_OUTPUT: {
+		int *p_output_num = arg;
+		pr_debug("   case VIDIOC_G_OUTPUT\n");
+		*p_output_num = cam->output;
+		break;
+	}
+
+	case VIDIOC_S_OUTPUT: {
+		int *p_output_num = arg;
+		pr_debug("   case VIDIOC_S_OUTPUT\n");
+		if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+			retval = -EINVAL;
+			break;
+		}
+		cam->output = *p_output_num;
+		break;
+	}
+
+	case VIDIOC_ENUMINPUT: {
+		struct v4l2_input *input = arg;
+		pr_debug("   case VIDIOC_ENUMINPUT\n");
+		if (input->index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+			retval = -EINVAL;
+			break;
+		}
+		*input = mxc_capture_inputs[input->index];
+		break;
+	}
+
+	case VIDIOC_G_INPUT: {
+		int *index = arg;
+		pr_debug("   case VIDIOC_G_INPUT\n");
+		*index = cam->current_input;
+		break;
+	}
+
+	case VIDIOC_S_INPUT: {
+		int *index = arg;
+		pr_debug("   case VIDIOC_S_INPUT\n");
+		if (*index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (*index == cam->current_input)
+			break;
+
+		if ((mxc_capture_inputs[cam->current_input].status &
+		    V4L2_IN_ST_NO_POWER) == 0) {
+			retval = mxc_streamoff(cam);
+			if (retval)
+				break;
+			mxc_capture_inputs[cam->current_input].status |=
+							V4L2_IN_ST_NO_POWER;
+		}
+
+		if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+			retval = csi_enc_select(cam);
+			if (retval)
+				break;
+#endif
+		} else if (strcmp(mxc_capture_inputs[*index].name,
+				  "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+			retval = prp_enc_select(cam);
+			if (retval)
+				break;
+#endif
+		}
+
+		mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER;
+		cam->current_input = *index;
+		break;
+	}
+	case VIDIOC_ENUM_FMT: {
+		struct v4l2_fmtdesc *f = arg;
+		if (cam->sensor)
+			retval = vidioc_int_enum_fmt_cap(cam->sensor, f);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+	case VIDIOC_ENUM_FRAMESIZES: {
+		struct v4l2_frmsizeenum *fsize = arg;
+		if (cam->sensor)
+			retval = vidioc_int_enum_framesizes(cam->sensor, fsize);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+	case VIDIOC_ENUM_FRAMEINTERVALS: {
+		struct v4l2_frmivalenum *fival = arg;
+		if (cam->sensor) {
+			retval = vidioc_int_enum_frameintervals(cam->sensor,
+								fival);
+		} else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+	case VIDIOC_DBG_G_CHIP_IDENT: {
+		struct v4l2_dbg_chip_ident *p = arg;
+		p->ident = V4L2_IDENT_NONE;
+		p->revision = 0;
+		if (cam->sensor)
+			retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p);
+		else {
+			pr_err("ERROR: v4l2 capture: slave not found!\n");
+			retval = -ENODEV;
+		}
+		break;
+	}
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_QUERYCTRL:
+	case VIDIOC_G_TUNER:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_G_FREQUENCY:
+	case VIDIOC_S_FREQUENCY:
+	default:
+		pr_debug("   case default or not supported\n");
+		retval = -EINVAL;
+		break;
+	}
+
+	if (ioctlnr != VIDIOC_DQBUF)
+		up(&cam->busy_lock);
+	return retval;
+}
+
+/*
+ * V4L interface - ioctl function
+ *
+ * @return  None
+ */
+static long mxc_v4l_ioctl(struct file *file, unsigned int cmd,
+			 unsigned long arg)
+{
+	pr_debug("In MVC:mxc_v4l_ioctl\n");
+	return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl);
+}
+
+/*!
+ * V4L interface - mmap function
+ *
+ * @param file        structure file *
+ *
+ * @param vma         structure vm_area_struct *
+ *
+ * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error
+ */
+static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *dev = video_devdata(file);
+	unsigned long size;
+	int res = 0;
+	cam_data *cam = video_get_drvdata(dev);
+
+	pr_debug("In MVC:mxc_mmap\n");
+	pr_debug("   pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
+		 vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	size = vma->vm_end - vma->vm_start;
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	if (remap_pfn_range(vma, vma->vm_start,
+			    vma->vm_pgoff, size, vma->vm_page_prot)) {
+		pr_err("ERROR: v4l2 capture: mxc_mmap: "
+			"remap_pfn_range failed\n");
+		res = -ENOBUFS;
+		goto mxc_mmap_exit;
+	}
+
+	vma->vm_flags &= ~VM_IO;	/* using shared anonymous pages */
+
+mxc_mmap_exit:
+	up(&cam->busy_lock);
+	return res;
+}
+
+/*!
+ * V4L interface - poll function
+ *
+ * @param file       structure file *
+ *
+ * @param wait       structure poll_table_struct *
+ *
+ * @return  status   POLLIN | POLLRDNORM
+ */
+static unsigned int mxc_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *dev = video_devdata(file);
+	cam_data *cam = video_get_drvdata(dev);
+	wait_queue_head_t *queue = NULL;
+	int res = POLLIN | POLLRDNORM;
+
+	pr_debug("In MVC:mxc_poll\n");
+
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	queue = &cam->enc_queue;
+	poll_wait(file, queue, wait);
+
+	up(&cam->busy_lock);
+
+	return res;
+}
+
+/*!
+ * This structure defines the functions to be called in this driver.
+ */
+static struct v4l2_file_operations mxc_v4l_fops = {
+	.owner = THIS_MODULE,
+	.open = mxc_v4l_open,
+	.release = mxc_v4l_close,
+	.read = mxc_v4l_read,
+	.unlocked_ioctl = mxc_v4l_ioctl,
+	.mmap = mxc_mmap,
+	.poll = mxc_poll,
+};
+
+static struct video_device mxc_v4l_template = {
+	.name = "Mxc Camera",
+	.fops = &mxc_v4l_fops,
+	.release = video_device_release,
+	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING,
+};
+
+/*!
+ * This function can be used to release any platform data on closing.
+ */
+static void camera_platform_release(struct device *device)
+{
+}
+
+/*!
+ * Camera V4l2 callback function.
+ *
+ * @param mask      u32
+ *
+ * @param dev       void device structure
+ *
+ * @return status
+ */
+static void camera_callback(u32 mask, void *dev)
+{
+	struct mxc_v4l_frame *done_frame;
+	struct mxc_v4l_frame *ready_frame;
+	struct timespec64 ts;
+
+	cam_data *cam = (cam_data *) dev;
+	if (cam == NULL)
+		return;
+
+	pr_debug("In MVC:camera_callback\n");
+
+	spin_lock(&cam->queue_int_lock);
+	spin_lock(&cam->dqueue_int_lock);
+	if (!list_empty(&cam->working_q)) {
+		ktime_get_real_ts64(&ts);
+
+		done_frame = list_entry(cam->working_q.next,
+					struct mxc_v4l_frame,
+					queue);
+
+		if (done_frame->ipu_buf_num != cam->local_buf_num)
+			goto next;
+
+		/*
+		 * Set the current time to done frame buffer's
+		 * timestamp. Users can use this information to judge
+		 * the frame's usage.
+		 */
+		done_frame->buffer.timestamp =
+			ns_to_timeval(ts.tv_sec * 1000000000ULL + ts.tv_nsec);
+
+		if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+			done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
+			done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+			/* Added to the done queue */
+			list_del(cam->working_q.next);
+			list_add_tail(&done_frame->queue, &cam->done_q);
+
+			/* Wake up the queue */
+			cam->enc_counter++;
+			wake_up_interruptible(&cam->enc_queue);
+		} else
+			pr_err("ERROR: v4l2 capture: camera_callback: "
+				"buffer not queued\n");
+	}
+
+next:
+	if (!list_empty(&cam->ready_q)) {
+		ready_frame = list_entry(cam->ready_q.next,
+					 struct mxc_v4l_frame,
+					 queue);
+		if (cam->enc_update_eba)
+			if (cam->enc_update_eba(
+				cam,
+				ready_frame->buffer.m.offset) == 0) {
+				list_del(cam->ready_q.next);
+				list_add_tail(&ready_frame->queue,
+					      &cam->working_q);
+				ready_frame->ipu_buf_num = cam->local_buf_num;
+			}
+	} else {
+		if (cam->enc_update_eba)
+			cam->enc_update_eba(
+				cam, cam->dummy_frame.buffer.m.offset);
+	}
+
+	cam->local_buf_num = (cam->local_buf_num == 0) ? 1 : 0;
+	spin_unlock(&cam->dqueue_int_lock);
+	spin_unlock(&cam->queue_int_lock);
+
+	return;
+}
+
+/*!
+ * initialize cam_data structure
+ *
+ * @param cam      structure cam_data *
+ *
+ * @return status  0 Success
+ */
+static int init_camera_struct(cam_data *cam, struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(mxc_v4l2_dt_ids, &pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	int ipu_id, csi_id, mclk_source;
+	int ret = 0;
+	struct v4l2_device *v4l2_dev;
+
+	pr_debug("In MVC: init_camera_struct\n");
+
+	ret = of_property_read_u32(np, "ipu_id", &ipu_id);
+	if (ret) {
+		dev_err(&pdev->dev, "ipu_id missing or invalid\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "csi_id", &csi_id);
+	if (ret) {
+		dev_err(&pdev->dev, "csi_id missing or invalid\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "mclk_source", &mclk_source);
+	if (ret) {
+		dev_err(&pdev->dev, "sensor mclk missing or invalid\n");
+		return ret;
+	}
+
+	/* Default everything to 0 */
+	memset(cam, 0, sizeof(cam_data));
+
+	/* get devtype to distinguish if the cpu is imx5 or imx6
+	 * IMX5_V4L2 specify the cpu is imx5
+	 * IMX6_V4L2 specify the cpu is imx6q or imx6sdl
+	 */
+	if (of_id)
+		pdev->id_entry = of_id->data;
+	cam->devtype = pdev->id_entry->driver_data;
+
+	cam->ipu = ipu_get_soc(ipu_id);
+	if (cam->ipu == NULL) {
+		pr_err("ERROR: v4l2 capture: failed to get ipu\n");
+		return -EINVAL;
+	} else if (cam->ipu == ERR_PTR(-ENODEV)) {
+		pr_err("ERROR: v4l2 capture: get invalid ipu\n");
+		return -ENODEV;
+	}
+
+	init_MUTEX(&cam->param_lock);
+	init_MUTEX(&cam->busy_lock);
+
+	cam->video_dev = video_device_alloc();
+	if (cam->video_dev == NULL)
+		return -ENODEV;
+
+	*(cam->video_dev) = mxc_v4l_template;
+
+	video_set_drvdata(cam->video_dev, cam);
+	dev_set_drvdata(&pdev->dev, (void *)cam);
+	cam->video_dev->minor = -1;
+
+	v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL);
+	if (!v4l2_dev) {
+		dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n");
+		video_device_release(cam->video_dev);
+		return -ENOMEM;
+	}
+
+	if (v4l2_device_register(&pdev->dev, v4l2_dev) < 0) {
+		dev_err(&pdev->dev, "register v4l2 device failed\n");
+		video_device_release(cam->video_dev);
+		kfree(v4l2_dev);
+		return -ENODEV;
+	}
+	cam->video_dev->v4l2_dev = v4l2_dev;
+
+	init_waitqueue_head(&cam->enc_queue);
+	init_waitqueue_head(&cam->still_queue);
+
+	/* setup cropping */
+	cam->crop_bounds.left = 0;
+	cam->crop_bounds.width = 640;
+	cam->crop_bounds.top = 0;
+	cam->crop_bounds.height = 480;
+	cam->crop_current = cam->crop_defrect = cam->crop_bounds;
+	ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+				cam->crop_current.height, cam->csi);
+	ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+				cam->crop_current.top, cam->csi);
+	cam->streamparm.parm.capture.capturemode = 0;
+
+	cam->standard.index = 0;
+	cam->standard.id = V4L2_STD_UNKNOWN;
+	cam->standard.frameperiod.denominator = 30;
+	cam->standard.frameperiod.numerator = 1;
+	cam->standard.framelines = 480;
+	cam->standard_autodetect = true;
+	cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;
+	cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	cam->overlay_on = false;
+	cam->capture_on = false;
+	cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;
+
+	cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
+	cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
+	cam->v2f.fmt.pix.width = 288;
+	cam->v2f.fmt.pix.height = 352;
+	cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+	cam->win.w.width = 160;
+	cam->win.w.height = 160;
+	cam->win.w.left = 0;
+	cam->win.w.top = 0;
+
+	cam->ipu_id = ipu_id;
+	cam->csi = csi_id;
+	cam->mclk_source = mclk_source;
+	cam->mclk_on[cam->mclk_source] = false;
+
+	cam->enc_callback = camera_callback;
+	init_waitqueue_head(&cam->power_queue);
+	spin_lock_init(&cam->queue_int_lock);
+	spin_lock_init(&cam->dqueue_int_lock);
+
+	cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);
+	cam->self->module = THIS_MODULE;
+	sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);
+	cam->self->type = v4l2_int_type_master;
+	cam->self->u.master = &mxc_v4l2_master;
+
+	return 0;
+}
+
+static ssize_t show_streaming(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct video_device *video_dev = container_of(dev,
+						struct video_device, dev);
+	cam_data *cam = video_get_drvdata(video_dev);
+
+	if (cam->capture_on)
+		return sprintf(buf, "stream on\n");
+	else
+		return sprintf(buf, "stream off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_capture_property, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_overlay(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct video_device *video_dev = container_of(dev,
+						struct video_device, dev);
+	cam_data *cam = video_get_drvdata(video_dev);
+
+	if (cam->overlay_on)
+		return sprintf(buf, "overlay on\n");
+	else
+		return sprintf(buf, "overlay off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_overlay_property, S_IRUGO, show_overlay, NULL);
+
+static ssize_t show_csi(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct video_device *video_dev = container_of(dev,
+						struct video_device, dev);
+	cam_data *cam = video_get_drvdata(video_dev);
+
+	return sprintf(buf, "ipu%d_csi%d\n", cam->ipu_id, cam->csi);
+}
+static DEVICE_ATTR(fsl_csi_property, S_IRUGO, show_csi, NULL);
+
+/*!
+ * This function is called to probe the devices if registered.
+ *
+ * @param   pdev  the device structure used to give information on which device
+ *                to probe
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_probe(struct platform_device *pdev)
+{
+	/* Create cam and initialize it. */
+	cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
+	if (cam == NULL) {
+		pr_err("ERROR: v4l2 capture: failed to register camera\n");
+		return -1;
+	}
+
+	init_camera_struct(cam, pdev);
+	pdev->dev.release = camera_platform_release;
+
+	cam->dev = &pdev->dev;
+	/* Set up the v4l2 device and register it*/
+	cam->self->priv = cam;
+	v4l2_int_device_register(cam->self);
+
+	/* register v4l video device */
+	if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr)
+		< 0) {
+		kfree(cam);
+		cam = NULL;
+		pr_err("ERROR: v4l2 capture: video_register_device failed\n");
+		return -1;
+	}
+	pr_debug("   Video device registered: %s #%d\n",
+		 cam->video_dev->name, cam->video_dev->minor);
+
+	if (device_create_file(&cam->video_dev->dev,
+			&dev_attr_fsl_v4l2_capture_property))
+		dev_err(&pdev->dev, "Error on creating sysfs file"
+			" for capture\n");
+
+	if (device_create_file(&cam->video_dev->dev,
+			&dev_attr_fsl_v4l2_overlay_property))
+		dev_err(&pdev->dev, "Error on creating sysfs file"
+			" for overlay\n");
+
+	if (device_create_file(&cam->video_dev->dev,
+			&dev_attr_fsl_csi_property))
+		dev_err(&pdev->dev, "Error on creating sysfs file"
+			" for csi number\n");
+
+	return 0;
+}
+
+/*!
+ * This function is called to remove the devices when device unregistered.
+ *
+ * @param   pdev  the device structure used to give information on which device
+ *                to remove
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_remove(struct platform_device *pdev)
+{
+	cam_data *cam = (cam_data *)platform_get_drvdata(pdev);
+	if (cam->open_count) {
+		pr_err("ERROR: v4l2 capture:camera open "
+			"-- setting ops to NULL\n");
+		return -EBUSY;
+	} else {
+		struct v4l2_device *v4l2_dev = cam->video_dev->v4l2_dev;
+		device_remove_file(&cam->video_dev->dev,
+			&dev_attr_fsl_v4l2_capture_property);
+		device_remove_file(&cam->video_dev->dev,
+			&dev_attr_fsl_v4l2_overlay_property);
+		device_remove_file(&cam->video_dev->dev,
+			&dev_attr_fsl_csi_property);
+
+		pr_info("V4L2 freeing image input device\n");
+		v4l2_int_device_unregister(cam->self);
+		video_unregister_device(cam->video_dev);
+
+		mxc_free_frame_buf(cam);
+		kfree(cam);
+
+		v4l2_device_unregister(v4l2_dev);
+		kfree(v4l2_dev);
+	}
+
+	pr_info("V4L2 unregistering video\n");
+	return 0;
+}
+
+/*!
+ * This function is called to put the sensor in a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param   pdev  the device structure used to give information on which I2C
+ *                to suspend
+ * @param   state the power state the device is entering
+ *
+ * @return  The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	cam_data *cam = platform_get_drvdata(pdev);
+
+	pr_debug("In MVC:mxc_v4l2_suspend\n");
+
+	if (cam == NULL)
+		return -1;
+
+	down(&cam->busy_lock);
+
+	cam->low_power = true;
+
+	if (cam->overlay_on == true)
+		stop_preview(cam);
+	if (cam->capture_on == true) {
+		if (cam->enc_disable_csi)
+			cam->enc_disable_csi(cam);
+
+		if (cam->enc_disable)
+			cam->enc_disable(cam);
+	}
+
+	if (cam->sensor && cam->open_count) {
+		if (cam->mclk_on[cam->mclk_source]) {
+			ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+					       cam->mclk_source,
+					       false, false);
+			cam->mclk_on[cam->mclk_source] = false;
+		}
+		vidioc_int_s_power(cam->sensor, 0);
+	}
+
+	up(&cam->busy_lock);
+
+	return 0;
+}
+
+/*!
+ * This function is called to bring the sensor back from a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param   pdev   the device structure
+ *
+ * @return  The function returns 0 on success and -1 on failure
+ */
+static int mxc_v4l2_resume(struct platform_device *pdev)
+{
+	cam_data *cam = platform_get_drvdata(pdev);
+
+	pr_debug("In MVC:mxc_v4l2_resume\n");
+
+	if (cam == NULL)
+		return -1;
+
+	down(&cam->busy_lock);
+
+	cam->low_power = false;
+	wake_up_interruptible(&cam->power_queue);
+
+	if (cam->sensor && cam->open_count) {
+		vidioc_int_s_power(cam->sensor, 1);
+
+		if (!cam->mclk_on[cam->mclk_source]) {
+			ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+					       cam->mclk_source,
+					       true, true);
+			cam->mclk_on[cam->mclk_source] = true;
+		}
+	}
+
+	if (cam->overlay_on == true)
+		start_preview(cam);
+	if (cam->capture_on == true) {
+		if (cam->enc_enable)
+			cam->enc_enable(cam);
+
+		if (cam->enc_enable_csi)
+			cam->enc_enable_csi(cam);
+	}
+
+	up(&cam->busy_lock);
+
+	return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_v4l2_driver = {
+	.driver = {
+		   .name = "mxc_v4l2_capture",
+		   .owner = THIS_MODULE,
+		   .of_match_table = mxc_v4l2_dt_ids,
+		   },
+	.id_table = imx_v4l2_devtype,
+	.probe = mxc_v4l2_probe,
+	.remove = mxc_v4l2_remove,
+	.suspend = mxc_v4l2_suspend,
+	.resume = mxc_v4l2_resume,
+	.shutdown = NULL,
+};
+
+/*!
+ * Initializes the camera driver.
+ */
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)
+{
+	cam_data *cam = slave->u.slave->master->priv;
+	struct v4l2_format cam_fmt;
+	int i;
+	struct sensor_data *sdata = slave->priv;
+
+	pr_debug("In MVC: mxc_v4l2_master_attach\n");
+	pr_debug("   slave.name = %s\n", slave->name);
+	pr_debug("   master.name = %s\n", slave->u.slave->master->name);
+
+	if (slave == NULL) {
+		pr_err("ERROR: v4l2 capture: slave parameter not valid.\n");
+		return -1;
+	}
+
+	if (sdata->csi != cam->csi) {
+		pr_debug("%s: csi doesn't match\n", __func__);
+		return -1;
+	}
+
+	cam->sensor = slave;
+
+	if (cam->sensor_index < MXC_SENSOR_NUM) {
+		cam->all_sensors[cam->sensor_index] = slave;
+		cam->sensor_index++;
+	} else {
+		pr_err("ERROR: v4l2 capture: slave number exceeds "
+		       "the maximum.\n");
+		return -1;
+	}
+
+	for (i = 0; i < cam->sensor_index; i++) {
+		vidioc_int_dev_exit(cam->all_sensors[i]);
+		vidioc_int_s_power(cam->all_sensors[i], 0);
+	}
+
+	cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+	/* Used to detect TV in (type 1) vs. camera (type 0)*/
+	cam->device_type = cam_fmt.fmt.pix.priv;
+
+	/* Set the input size to the ipu for this device */
+	cam->crop_bounds.top = cam->crop_bounds.left = 0;
+	cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+	cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+	/* This also is the max crop size for this device. */
+	cam->crop_defrect.top = cam->crop_defrect.left = 0;
+	cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+	cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+	/* At this point, this is also the current image size. */
+	cam->crop_current.top = cam->crop_current.left = 0;
+	cam->crop_current.width = cam_fmt.fmt.pix.width;
+	cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+	pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+		 __func__,
+		 cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+	pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_bounds.width, cam->crop_bounds.height);
+	pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_defrect.width, cam->crop_defrect.height);
+	pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+		 __func__,
+		 cam->crop_current.width, cam->crop_current.height);
+
+	return 0;
+}
+
+/*!
+ * Disconnects the camera driver.
+ */
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave)
+{
+	unsigned int i;
+	cam_data *cam = slave->u.slave->master->priv;
+
+	pr_debug("In MVC:mxc_v4l2_master_detach\n");
+
+	if (cam->sensor_index > 1) {
+		for (i = 0; i < cam->sensor_index; i++) {
+			if (cam->all_sensors[i] != slave)
+				continue;
+			/* Move all the sensors behind this
+			 * sensor one step forward
+			 */
+			for (; i <= MXC_SENSOR_NUM - 2; i++)
+				cam->all_sensors[i] = cam->all_sensors[i+1];
+			break;
+		}
+		/* Point current sensor to the last one */
+		cam->sensor = cam->all_sensors[cam->sensor_index - 2];
+	} else
+		cam->sensor = NULL;
+
+	cam->sensor_index--;
+	vidioc_int_dev_exit(slave);
+}
+
+/*!
+ * Entry point for the V4L2
+ *
+ * @return  Error code indicating success or failure
+ */
+static __init int camera_init(void)
+{
+	u8 err = 0;
+
+	pr_debug("In MVC:camera_init\n");
+
+	/* Register the device driver structure. */
+	err = platform_driver_register(&mxc_v4l2_driver);
+	if (err != 0) {
+		pr_err("ERROR: v4l2 capture:camera_init: "
+			"platform_driver_register failed.\n");
+		return err;
+	}
+
+	return err;
+}
+
+/*!
+ * Exit and cleanup for the V4L2
+ */
+static void __exit camera_exit(void)
+{
+	pr_debug("In MVC: camera_exit\n");
+
+	platform_driver_unregister(&mxc_v4l2_driver);
+}
+
+module_init(camera_init);
+module_exit(camera_exit);
+
+module_param(video_nr, int, 0444);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*!
+ * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver
+ */
+/*!
+ * @file mxc_v4l2_capture.h
+ *
+ * @brief mxc V4L2 capture device API  Header file
+ *
+ * It include all the defines for frame operations, also three structure defines
+ * use case ops structure, common v4l2 driver structure and frame structure.
+ *
+ * @ingroup MXC_V4L2_CAPTURE
+ */
+#ifndef __MXC_V4L2_CAPTURE_H__
+#define __MXC_V4L2_CAPTURE_H__
+
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/mxc_v4l2.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/ipu-v3.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include <media/v4l2-dev.h>
+#include "v4l2-int-device.h"
+
+
+#define FRAME_NUM 10
+#define MXC_SENSOR_NUM 2
+
+enum imx_v4l2_devtype {
+	IMX5_V4L2,
+	IMX6_V4L2,
+};
+
+/*!
+ * v4l2 frame structure.
+ */
+struct mxc_v4l_frame {
+	u32 paddress;
+	void *vaddress;
+	int count;
+	int width;
+	int height;
+
+	struct v4l2_buffer buffer;
+	struct list_head queue;
+	int index;
+	union {
+		int ipu_buf_num;
+		int csi_buf_num;
+	};
+};
+
+/* Only for old version.  Will go away soon. */
+typedef struct {
+	u8 clk_mode;
+	u8 ext_vsync;
+	u8 Vsync_pol;
+	u8 Hsync_pol;
+	u8 pixclk_pol;
+	u8 data_pol;
+	u8 data_width;
+	u8 pack_tight;
+	u8 force_eof;
+	u8 data_en_pol;
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u32 mclk;
+	u16 active_width;
+	u16 active_height;
+} sensor_interface;
+
+/* Sensor control function */
+/* Only for old version.  Will go away soon. */
+struct camera_sensor {
+	void (*set_color) (int bright, int saturation, int red, int green,
+			   int blue);
+	void (*get_color) (int *bright, int *saturation, int *red, int *green,
+			   int *blue);
+	void (*set_ae_mode) (int ae_mode);
+	void (*get_ae_mode) (int *ae_mode);
+	sensor_interface *(*config) (int *frame_rate, int high_quality);
+	sensor_interface *(*reset) (void);
+	void (*get_std) (v4l2_std_id *std);
+	void (*set_std) (v4l2_std_id std);
+	unsigned int csi;
+};
+
+/*!
+ * common v4l2 driver structure.
+ */
+typedef struct _cam_data {
+	struct device *dev;
+	struct video_device *video_dev;
+	int device_type;
+
+	/* semaphore guard against SMP multithreading */
+	struct semaphore busy_lock;
+
+	int open_count;
+
+	/* params lock for this camera */
+	struct semaphore param_lock;
+
+	/* Encoder */
+	struct list_head ready_q;
+	struct list_head done_q;
+	struct list_head working_q;
+	int ping_pong_csi;
+	spinlock_t queue_int_lock;
+	spinlock_t dqueue_int_lock;
+	struct mxc_v4l_frame frame[FRAME_NUM];
+	struct mxc_v4l_frame dummy_frame;
+	wait_queue_head_t enc_queue;
+	int enc_counter;
+	dma_addr_t rot_enc_bufs[2];
+	void *rot_enc_bufs_vaddr[2];
+	int rot_enc_buf_size[2];
+	enum v4l2_buf_type type;
+
+	/* still image capture */
+	wait_queue_head_t still_queue;
+	int still_counter;
+	dma_addr_t still_buf[2];
+	void *still_buf_vaddr;
+
+	/* overlay */
+	struct v4l2_window win;
+	struct v4l2_framebuffer v4l2_fb;
+	dma_addr_t vf_bufs[2];
+	void *vf_bufs_vaddr[2];
+	int vf_bufs_size[2];
+	dma_addr_t rot_vf_bufs[2];
+	void *rot_vf_bufs_vaddr[2];
+	int rot_vf_buf_size[2];
+	bool overlay_active;
+	int output;
+	struct fb_info *overlay_fb;
+	int fb_origin_std;
+	struct work_struct csi_work_struct;
+
+	/* v4l2 format */
+	struct v4l2_format v2f;
+	struct v4l2_format input_fmt;	/* camera in */
+	bool bswapenable;
+	int rotation;	/* for IPUv1 and IPUv3, this means encoder rotation */
+	int vf_rotation; /* viewfinder rotation only for IPUv1 and IPUv3 */
+	struct v4l2_mxc_offset offset;
+
+	/* V4l2 control bit */
+	int bright;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	/* standard */
+	struct v4l2_streamparm streamparm;
+	struct v4l2_standard standard;
+	bool standard_autodetect;
+
+	/* crop */
+	struct v4l2_rect crop_bounds;
+	struct v4l2_rect crop_defrect;
+	struct v4l2_rect crop_current;
+
+	int (*enc_update_eba) (void *private, dma_addr_t eba);
+	int (*enc_enable) (void *private);
+	int (*enc_disable) (void *private);
+	int (*enc_enable_csi) (void *private);
+	int (*enc_disable_csi) (void *private);
+	void (*enc_callback) (u32 mask, void *dev);
+	int (*vf_start_adc) (void *private);
+	int (*vf_stop_adc) (void *private);
+	int (*vf_start_sdc) (void *private);
+	int (*vf_stop_sdc) (void *private);
+	int (*vf_enable_csi) (void *private);
+	int (*vf_disable_csi) (void *private);
+	int (*csi_start) (void *private);
+	int (*csi_stop) (void *private);
+
+	/* misc status flag */
+	bool overlay_on;
+	bool capture_on;
+	int overlay_pid;
+	int capture_pid;
+	bool low_power;
+	wait_queue_head_t power_queue;
+	unsigned int ipu_id;
+	unsigned int csi;
+	u8 mclk_source;
+	bool mclk_on[2];	/* two mclk sources at most now */
+	int current_input;
+
+	int local_buf_num;
+
+	/* camera sensor interface */
+	struct camera_sensor *cam_sensor;	/* old version */
+	struct v4l2_int_device *all_sensors[MXC_SENSOR_NUM];
+	struct v4l2_int_device *sensor;
+	struct v4l2_int_device *self;
+	int sensor_index;
+	void *ipu;
+	void *csi_soc;
+	enum imx_v4l2_devtype devtype;
+
+	/* v4l2 buf elements related to PxP DMA */
+	struct completion pxp_tx_cmpl;
+	struct pxp_channel *pxp_chan;
+	struct pxp_config_data pxp_conf;
+	struct dma_async_tx_descriptor *txd;
+	dma_cookie_t cookie;
+	struct scatterlist sg[2];
+} cam_data;
+
+struct sensor_data {
+	const struct ov5642_platform_data *platform_data;
+	struct v4l2_int_device *v4l2_int_device;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	struct v4l2_captureparm streamcap;
+	bool on;
+
+	/* control settings */
+	int brightness;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	u32 mclk;
+	u8 mclk_source;
+	struct clk *sensor_clk;
+	int csi;
+
+	void (*io_init)(void);
+};
+
+void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi);
+#endif				/* __MXC_V4L2_CAPTURE_H__ */
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mxc_vadc.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mxc_vadc.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/media-bus-format.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include "mxc_vadc.h"
+
+/* Resource names for the VADC driver. */
+#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe"
+#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec"
+
+#define reg32_write(addr, val) __raw_writel(val, addr)
+#define reg32_read(addr)       __raw_readl(addr)
+#define reg32setbit(addr, bitpos) \
+	reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
+
+#define reg32clrbit(addr, bitpos) \
+	reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos)))))
+
+#define GPC_CNTR		0x00
+#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK	BIT(17)
+#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK	BIT(18)
+
+void __iomem *vafe_regbase;
+void __iomem *vdec_regbase;
+
+
+/* List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt
+ */
+enum video_fmt_idx {
+	VADC_NTSC = 0,	/* Locked on (M) NTSC video signal. */
+	VADC_PAL,		/* (B, G, H, I, N)PAL video signal. */
+};
+
+/* Number of video standards supported (including 'not locked' signal). */
+#define VADC_STD_MAX		(VADC_PAL + 1)
+
+/* Video format structure. */
+struct video_fmt{
+	v4l2_std_id  v4l2_std;	/* Video for linux ID. */
+	char name[16];		/* Name (e.g., "NTSC", "PAL", etc.) */
+	u16 raw_width;		/* Raw width. */
+	u16 raw_height;		/* Raw height. */
+	u16 active_width;	/* Active width. */
+	u16 active_height;	/* Active height. */
+	u16 framerates;
+};
+
+/*
+ * Maintains the information on the current state of the sensor.
+ */
+struct vadc_state {
+	struct v4l2_device v4l2_dev;
+	struct v4l2_subdev sd;
+	struct video_fmt *fmt;
+
+	struct clk *vadc_clk;
+	struct clk *csi_clk;
+	struct regmap *gpr;
+	void __iomem *gpc_reg;
+
+	u32 vadc_in;
+	u32 csi_id;
+};
+
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std);
+
+/* Description of video formats supported.
+ *
+ *  PAL: raw=720x625, active=720x576.
+ *  NTSC: raw=720x525, active=720x480.
+ */
+static struct video_fmt video_fmts[] = {
+	/* NTSC */
+	{
+	 .v4l2_std = V4L2_STD_NTSC,
+	 .name = "NTSC",
+	 .raw_width = 720,
+	 .raw_height = 525,
+	 .active_width = 720,
+	 .active_height = 480,
+	 .framerates = 30,
+	 },
+	/* (B, G, H, I, N) PAL */
+	{
+	 .v4l2_std = V4L2_STD_PAL,
+	 .name = "PAL",
+	 .raw_width = 720,
+	 .raw_height = 625,
+	 .active_width = 720,
+	 .active_height = 576,
+	 .framerates = 25,
+	 },
+};
+
+static void afe_voltage_clampingmode(void)
+{
+	reg32_write(AFE_CLAMP, 0x07);
+	reg32_write(AFE_CLMPAMP, 0x60);
+	reg32_write(AFE_CLMPDAT, 0xF0);
+}
+
+static void afe_alwayson_clampingmode(void)
+{
+	reg32_write(AFE_CLAMP, 0x15);
+	reg32_write(AFE_CLMPDAT, 0x08);
+	reg32_write(AFE_CLMPAMP, 0x00);
+}
+
+static void afe_init(void)
+{
+	pr_debug("%s\n", __func__);
+
+	reg32_write(AFE_PDBUF, 0x1f);
+	reg32_write(AFE_PDADC, 0x0f);
+	reg32_write(AFE_PDSARH, 0x01);
+	reg32_write(AFE_PDSARL, 0xff);
+	reg32_write(AFE_PDADCRFH, 0x01);
+	reg32_write(AFE_PDADCRFL, 0xff);
+	reg32_write(AFE_ICTRL, 0x3a);
+	reg32_write(AFE_ICTLSTG, 0x1e);
+
+	reg32_write(AFE_RCTRLSTG, 0x1e);
+	reg32_write(AFE_INPBUF, 0x035);
+	reg32_write(AFE_INPFLT, 0x02);
+	reg32_write(AFE_ADCDGN, 0x40);
+	reg32_write(AFE_TSTSEL, 0x10);
+
+	reg32_write(AFE_ACCTST, 0x07);
+
+	reg32_write(AFE_BGREG, 0x08);
+
+	reg32_write(AFE_ADCGN, 0x09);
+
+	/* set current controlled clamping
+	* always on, low current */
+	reg32_write(AFE_CLAMP, 0x11);
+	reg32_write(AFE_CLMPAMP, 0x08);
+}
+
+static void vdec_mode_timing_init(int std)
+{
+	if (std == V4L2_STD_NTSC) {
+		/* NTSC 720x480 */
+		reg32_write(VDEC_HACTS, 0x66);
+		reg32_write(VDEC_HACTE, 0x24);
+
+		reg32_write(VDEC_VACTS, 0x29);
+		reg32_write(VDEC_VACTE, 0x04);
+
+		/* set V Position */
+		reg32_write(VDEC_VRTPOS, 0x2);
+	} else if (std == V4L2_STD_PAL) {
+		/* PAL 720x576 */
+		reg32_write(VDEC_HACTS, 0x66);
+		reg32_write(VDEC_HACTE, 0x24);
+
+		reg32_write(VDEC_VACTS, 0x29);
+		reg32_write(VDEC_VACTE, 0x04);
+
+		/* set V Position */
+		reg32_write(VDEC_VRTPOS, 0x6);
+	} else
+		pr_debug("Error not support video mode\n");
+
+	/* set H Position */
+	reg32_write(VDEC_HZPOS, 0x60);
+
+	/* set H ignore start */
+	reg32_write(VDEC_HSIGS, 0xf8);
+
+	/* set H ignore end */
+	reg32_write(VDEC_HSIGE, 0x18);
+}
+
+/*
+* vdec_init()
+* Initialises the VDEC registers
+* Returns: nothing
+*/
+static void vdec_init(struct vadc_state *vadc)
+{
+	v4l2_std_id std;
+
+	pr_debug("%s\n", __func__);
+
+	/* Get work mode PAL or NTSC */
+	vadc_querystd(&vadc->sd, &std);
+
+	vdec_mode_timing_init(std);
+
+	/* vcr detect threshold high, automatic detections */
+	reg32_write(VDEC_VSCON2, 0);
+
+	reg32_write(VDEC_BASE + 0x110, 0x01);
+
+	/* set the noramp mode on the Hloop PLL. */
+	reg32_write(VDEC_BASE+(0x14*4), 0x10);
+
+	/* set the YC relative delay.*/
+	reg32_write(VDEC_YCDEL, 0x90);
+
+	/* setup the Hpll */
+	reg32_write(VDEC_BASE+(0x13*4), 0x13);
+
+	/* setup the 2d comb */
+	/* set the gain of the Hdetail output to 3
+	 * set the notch alpha gain to 1 */
+	reg32_write(VDEC_CFC2, 0x34);
+
+	/* setup various 2d comb bits.*/
+	reg32_write(VDEC_BASE+(0x02*4), 0x01);
+	reg32_write(VDEC_BASE+(0x03*4), 0x18);
+	reg32_write(VDEC_BASE+(0x04*4), 0x34);
+
+	/* set the start of the burst gate */
+	reg32_write(VDEC_BRSTGT, 0x30);
+
+	/* set 1f motion gain */
+	reg32_write(VDEC_BASE+(0x0f*4), 0x20);
+
+	/* set the 1F chroma motion detector thresh
+	 * for colour reverse detection */
+	reg32_write(VDEC_THSH1, 0x02);
+	reg32_write(VDEC_BASE+(0x4a*4), 0x20);
+	reg32_write(VDEC_BASE+(0x4b*4), 0x08);
+
+	reg32_write(VDEC_BASE+(0x4c*4), 0x08);
+
+	/* set the threshold for the narrow/wide adaptive chroma BW */
+	reg32_write(VDEC_BASE+(0x20*4), 0x20);
+
+	/* turn up the colour with the new colour gain reg */
+	/* hue: */
+	reg32_write(VDEC_HUE, 0x00);
+
+	/* cbgain: 22 B4 */
+	reg32_write(VDEC_CBGN, 0xb4);
+	/* cr gain 80 */
+	reg32_write(VDEC_CRGN, 0x80);
+	/* luma gain (contrast) */
+	reg32_write(VDEC_CNTR, 0x80);
+
+	/* setup the signed black level register, brightness */
+	reg32_write(VDEC_BRT, 0x00);
+
+	/* filter the standard detection
+	 * enable the comb for the ntsc443 */
+	reg32_write(VDEC_STDDBG, 0x20);
+
+	/* setup chroma kill thresh for no chroma */
+	reg32_write(VDEC_CHBTH, 0x0);
+
+	/* set chroma loop to wider BW
+	 * no set it to normal BW. i fixed the bw problem.*/
+	reg32_write(VDEC_YCDEL, 0x00);
+
+	/* set the compensation in the chroma loop for the Hloop
+	 * set the ratio for the nonarithmetic 3d comb modes.*/
+	reg32_write(VDEC_BASE + (0x1d*4), 0x90);
+
+	/* set the threshold for the nonarithmetic mode for the 2d comb
+	 * the higher the value the more Fc Fh offset
+	 * we will tolerate before turning off the comb. */
+	reg32_write(VDEC_BASE + (0x33*4), 0xa0);
+
+	/* setup the bluescreen output colour */
+	reg32_write(VDEC_BASE + (0x3d*4), 35);
+	reg32_write(VDEC_BLSCRCR, 114);
+	reg32_write(VDEC_BLSCRCB, 212);
+
+	/* disable the active blanking */
+	reg32_write(VDEC_BASE + (0x15*4), 0x02);
+
+	/* setup the luma agc for automatic gain. */
+	reg32_write(VDEC_LMAGC2, 0x5e);
+	reg32_write(VDEC_LMAGC1, 0x81);
+
+	/* setup chroma agc */
+	reg32_write(VDEC_CHAGC2, 0xa0);
+	reg32_write(VDEC_CHAGC1, 0x01);
+
+	/* setup the MV thresh lower nibble
+	 * setup the sync top cap, upper nibble */
+	reg32_write(VDEC_BASE + (0x3a*4), 0x80);
+	reg32_write(VDEC_SHPIMP, 0x00);
+
+	/* setup the vsync block */
+	reg32_write(VDEC_VSCON1, 0x87);
+
+	/* set the nosignal threshold
+	 * set the vsync threshold */
+	reg32_write(VDEC_VSSGTH, 0x35);
+
+	/* set length for min hphase filter
+	 * (or saturate limit if saturate is chosen) */
+	reg32_write(VDEC_BASE + (0x45*4), 0x40);
+
+	/* enable the internal resampler,
+	 * select min filter not saturate for
+	 * hphase noise filter for vcr detect.
+	 * enable vcr pause mode different field lengths */
+	reg32_write(VDEC_BASE + (0x46*4), 0x90);
+
+	/* disable VCR detection, lock to the Hsync rather than the Vsync */
+	reg32_write(VDEC_VSCON2, 0x04);
+
+	/* set tiplevel goal for dc clamp. */
+	reg32_write(VDEC_BASE + (0x3c*4), 0xB0);
+
+	/* override SECAM detection and force SECAM off */
+	reg32_write(VDEC_BASE + (0x2f*4), 0x20);
+
+	/* Set r3d_hardblend in 3D control2 reg */
+	reg32_write(VDEC_BASE + (0x0c*4), 0x04);
+}
+
+/* set Input selector & input pull-downs */
+static void vadc_s_routing(int vadc_in)
+{
+	switch (vadc_in) {
+	case 0:
+		reg32_write(AFE_INPFLT, 0x02);
+		reg32_write(AFE_OFFDRV, 0x00);
+		reg32_write(AFE_INPCONFIG, 0x1e);
+		break;
+	case 1:
+		reg32_write(AFE_INPFLT, 0x02);
+		reg32_write(AFE_OFFDRV, 0x00);
+		reg32_write(AFE_INPCONFIG, 0x2d);
+		break;
+	case 2:
+		reg32_write(AFE_INPFLT, 0x02);
+		reg32_write(AFE_OFFDRV, 0x00);
+		reg32_write(AFE_INPCONFIG, 0x4b);
+		break;
+	case 3:
+		reg32_write(AFE_INPFLT, 0x02);
+		reg32_write(AFE_OFFDRV, 0x00);
+		reg32_write(AFE_INPCONFIG, 0x87);
+		break;
+	default:
+		pr_debug("error video input %d\n", vadc_in);
+	}
+}
+
+static void vadc_power_up(struct vadc_state *state)
+{
+	/* Power on vadc analog */
+	reg32clrbit(state->gpc_reg + GPC_CNTR, 17);
+
+	/* Power down vadc ext power */
+	reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+	/* software reset afe  */
+	regmap_update_bits(state->gpr, IOMUXC_GPR1,
+			IMX6SX_GPR1_VADC_SW_RST_MASK,
+			IMX6SX_GPR1_VADC_SW_RST_RESET);
+
+	msleep(10);
+
+	/* clock config for vadc */
+	reg32_write(VDEC_BASE + 0x320, 0xe3);
+	reg32_write(VDEC_BASE + 0x324, 0x38);
+	reg32_write(VDEC_BASE + 0x328, 0x8e);
+	reg32_write(VDEC_BASE + 0x32c, 0x23);
+
+	/* Release reset bit  */
+	regmap_update_bits(state->gpr, IOMUXC_GPR1,
+			IMX6SX_GPR1_VADC_SW_RST_MASK,
+			IMX6SX_GPR1_VADC_SW_RST_RELEASE);
+
+	/* Power on vadc ext power */
+	reg32setbit(state->gpc_reg + GPC_CNTR, 18);
+}
+
+static void vadc_power_down(struct vadc_state *state)
+{
+	/* Power down vadc analog */
+	reg32setbit(state->gpc_reg + GPC_CNTR, 17);
+
+	/* Power down vadc ext power */
+	reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+}
+static void vadc_init(struct vadc_state *vadc)
+{
+	pr_debug("%s\n", __func__);
+
+	vadc_power_up(vadc);
+
+	afe_init();
+
+	/* select Video Input 0-3 */
+	vadc_s_routing(vadc->vadc_in);
+
+	afe_voltage_clampingmode();
+
+	vdec_init(vadc);
+
+	/*
+	* current control loop will move sinewave input off below
+	* the bottom of the signal range visible
+	* when the testbus is viewed as magnitude,
+	* so have to break before this point while capturing ENOB data:
+	*/
+	afe_alwayson_clampingmode();
+}
+
+static inline struct vadc_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct vadc_state, sd);
+}
+
+static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct vadc_state *state = to_state(sd);
+
+	*std = state->fmt->v4l2_std;
+	return 0;
+}
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ *  @return		None.
+ */
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct vadc_state *state = to_state(sd);
+	int mod;
+	int idx;
+	int i;
+
+	/* Read auto mode detected result */
+	printk(KERN_INFO"wait vadc auto detect video mode....\n");
+	for (i = 0; i < 10; i++) {
+		msleep(200);
+		mod = reg32_read(VDEC_VIDMOD);
+		/* Check video signal states */
+		if ((mod & VDEC_VIDMOD_SIGNAL_MASK)
+				== VDEC_VIDMOD_SIGNAL_DETECT)
+			break;
+	}
+	if (i == 10)
+		printk(KERN_INFO"Timeout detect video signal mod=0x%x\n", mod);
+
+	if ((mod & VDEC_VIDMOD_PAL_MASK) || (mod & VDEC_VIDMOD_M625_MASK))
+		idx = VADC_PAL;
+	else
+		idx = VADC_NTSC;
+
+	*std = video_fmts[idx].v4l2_std;
+	state->fmt = &video_fmts[idx];
+
+	printk(KERN_INFO"video mode %s\n", video_fmts[idx].name);
+	return 0;
+}
+
+static int vadc_enum_mbus_code(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_mbus_code_enum *code)
+{
+	/* support only one format  */
+	if (code->pad || code->index >= 1)
+		return -EINVAL;
+
+	code->code = MEDIA_BUS_FMT_AYUV8_1X32;
+	return 0;
+}
+
+static int vadc_get_fmt(struct v4l2_subdev *sd,
+			struct v4l2_subdev_pad_config *cfg,
+			struct v4l2_subdev_format *format)
+{
+	struct vadc_state *state = to_state(sd);
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+
+	if (format->pad)
+		return -EINVAL;
+
+	fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	fmt->field = V4L2_FIELD_INTERLACED;
+	fmt->width = 720;
+	fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576;
+
+	return 0;
+}
+
+static int vadc_set_fmt(struct v4l2_subdev *sd,
+			struct v4l2_subdev_pad_config *cfg,
+			struct v4l2_subdev_format *format)
+{
+	return vadc_get_fmt(sd, cfg, format);
+}
+
+static int vadc_enum_framesizes(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct vadc_state *state = to_state(sd);
+	if (fse->index >= 1)
+		return -EINVAL;
+
+	fse->min_width = state->fmt->active_width;
+	fse->max_width = state->fmt->active_width;
+	fse->min_height  = state->fmt->active_height;
+	fse->max_height  = state->fmt->active_height;
+
+	return 0;
+}
+static int vadc_enum_frameintervals(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct vadc_state *state = to_state(sd);
+
+	if (fie->index < 0 || fie->index >= 1)
+		return -EINVAL;
+
+	fie->interval.numerator = 1;
+
+	fie->interval.denominator = state->fmt->framerates;
+
+	return 0;
+}
+
+static int vadc_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct vadc_state *state = to_state(sd);
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (parms->parm.capture.timeperframe.denominator
+				!= state->fmt->framerates)
+		parms->parm.capture.timeperframe.denominator
+				= state->fmt->framerates;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops vadc_video_ops = {
+	.querystd              = vadc_querystd,
+	.s_parm                = vadc_s_parm,
+	.g_std                 = vadc_g_std,
+};
+
+
+static const struct v4l2_subdev_pad_ops vadc_pad_ops = {
+	.get_fmt	       = vadc_get_fmt,
+	.set_fmt	       = vadc_set_fmt,
+	.enum_mbus_code        = vadc_enum_mbus_code,
+	.enum_frame_size       = vadc_enum_framesizes,
+	.enum_frame_interval   = vadc_enum_frameintervals,
+};
+
+static const struct v4l2_subdev_ops vadc_ops = {
+	.video = &vadc_video_ops,
+	.pad = &vadc_pad_ops,
+};
+
+static const struct of_device_id fsl_vadc_dt_ids[] = {
+	{ .compatible = "fsl,imx6sx-vadc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids);
+
+static int vadc_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *gpc_np;
+	struct vadc_state *state = platform_get_drvdata(pdev);
+	int csi_id;
+	int ret;
+
+	/* Get csi_id to setting vadc to csi mux in gpr */
+	ret = of_property_read_u32(np, "csi_id", &csi_id);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to read of property csi_id\n");
+		return ret;
+	}
+
+	state->csi_id = csi_id;
+
+	/* remap GPR register */
+	state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+			"gpr");
+	if (IS_ERR(state->gpr)) {
+		dev_dbg(&pdev->dev, "can not get gpr\n");
+		return -ENOMEM;
+	}
+
+	/* Configuration vadc-to-csi 0 or 1 */
+	if (csi_id) {
+		regmap_update_bits(state->gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_CSI2_MUX_CTRL_MASK,
+				IMX6SX_GPR5_CSI2_MUX_CTRL_CVD);
+	} else {
+		regmap_update_bits(state->gpr, IOMUXC_GPR5,
+				IMX6SX_GPR5_CSI1_MUX_CTRL_MASK,
+				IMX6SX_GPR5_CSI1_MUX_CTRL_CVD);
+	}
+
+	/* Get default vadc_in number  */
+	ret = of_property_read_u32(np, "vadc_in", &state->vadc_in);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to read of property vadc_in\n");
+		return ret;
+	}
+
+	/* map GPC register  */
+	gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
+	state->gpc_reg = of_iomap(gpc_np, 0);
+	if (!state->gpc_reg) {
+		dev_err(&pdev->dev, "ioremap failed with gpc base\n");
+		goto error;
+	}
+
+	return ret;
+
+error:
+	iounmap(state->gpc_reg);
+	return ret;
+}
+
+static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd,
+		struct platform_device *pdev,
+		const struct v4l2_subdev_ops *ops)
+{
+	struct vadc_state *state = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	v4l2_subdev_init(sd, ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->owner = pdev->dev.driver->owner;
+	sd->dev = &pdev->dev;
+
+	/* initialize name */
+	snprintf(sd->name, sizeof(sd->name), "%s",
+		pdev->dev.driver->name);
+
+	v4l2_set_subdevdata(sd, state);
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0)
+		dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
+}
+
+static int vadc_probe(struct platform_device *pdev)
+{
+	struct vadc_state *state;
+	struct v4l2_subdev *sd;
+	struct resource *res;
+	int ret = 0;
+
+	state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL);
+	if (!state) {
+		dev_err(&pdev->dev, "Cannot allocate device data\n");
+		return -ENOMEM;
+	}
+
+	/* Set initial values for the sensor struct. */
+	state->fmt = &video_fmts[VADC_NTSC];
+
+	sd = &state->sd;
+
+	/* map vafe address  */
+	res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME);
+	if (!res) {
+		dev_err(&pdev->dev, "No vafe base address found.\n");
+		return -ENOMEM;
+	}
+	vafe_regbase = devm_ioremap_resource(&pdev->dev, res);
+	if (!vafe_regbase) {
+		dev_err(&pdev->dev, "ioremap failed with vafe base\n");
+		return -ENOMEM;
+	}
+
+	/* map vdec address  */
+	res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME);
+	if (!res) {
+		dev_err(&pdev->dev, "No vdec base address found.\n");
+		return -ENODEV;
+	}
+	vdec_regbase = devm_ioremap_resource(&pdev->dev, res);
+	if (!vdec_regbase) {
+		dev_err(&pdev->dev, "ioremap failed with vdec base\n");
+		return -ENOMEM;
+	}
+
+	/* Get clock */
+	state->vadc_clk = devm_clk_get(&pdev->dev, "vadc");
+	if (IS_ERR(state->vadc_clk)) {
+		ret = PTR_ERR(state->vadc_clk);
+		return ret;
+	}
+
+	state->csi_clk = devm_clk_get(&pdev->dev, "csi");
+	if (IS_ERR(state->csi_clk)) {
+		ret = PTR_ERR(state->csi_clk);
+		return ret;
+	}
+
+	/* clock  */
+	clk_prepare_enable(state->csi_clk);
+	clk_prepare_enable(state->vadc_clk);
+
+	platform_set_drvdata(pdev, state);
+
+	vadc_v4l2_subdev_init(sd, pdev, &vadc_ops);
+
+	pm_runtime_enable(&pdev->dev);
+
+	pm_runtime_get_sync(&pdev->dev);
+	/* Init VADC */
+	ret = vadc_of_init(pdev);
+	if (ret < 0)
+		goto err;
+	vadc_init(state);
+
+	pr_info("vadc driver loaded\n");
+
+	return 0;
+err:
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	v4l2_async_unregister_subdev(&state->sd);
+	clk_disable_unprepare(state->csi_clk);
+	clk_disable_unprepare(state->vadc_clk);
+	return ret;
+}
+
+static int vadc_remove(struct platform_device *pdev)
+{
+	struct vadc_state *state = platform_get_drvdata(pdev);
+
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	v4l2_async_unregister_subdev(&state->sd);
+	clk_disable_unprepare(state->csi_clk);
+	clk_disable_unprepare(state->vadc_clk);
+
+	vadc_power_down(state);
+	return true;
+}
+
+static int vadc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vadc_state *state = platform_get_drvdata(pdev);
+
+	clk_disable(state->csi_clk);
+	clk_disable(state->vadc_clk);
+
+	vadc_power_down(state);
+
+	return 0;
+}
+
+static int vadc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vadc_state *state = platform_get_drvdata(pdev);
+
+	clk_enable(state->csi_clk);
+	clk_enable(state->vadc_clk);
+
+	vadc_init(state);
+	return 0;
+}
+
+static const struct dev_pm_ops vadc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(vadc_suspend, vadc_resume)
+};
+
+static struct platform_driver vadc_driver = {
+	.driver = {
+		.name = "fsl_vadc",
+		.of_match_table = of_match_ptr(fsl_vadc_dt_ids),
+		.pm	= &vadc_pm_ops,
+	},
+	.probe = vadc_probe,
+	.remove = vadc_remove,
+};
+
+module_platform_driver(vadc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("fsl VADC/VDEC driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/mxc_vadc.h
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/mxc_vadc.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef MXC_VDEC_H
+#define MXC_VDEC_H
+
+/*** define base address ***/
+#define VDEC_BASE vdec_regbase
+#define AFE_BASE vafe_regbase
+
+/* AFE - Register offsets */
+#define AFE_BLOCK_ID_OFFSET				0x00000000
+#define AFE_PDBUF_OFFSET				0x00000004
+#define AFE_SWRST_OFFSET				0x00000008
+#define AFE_TSTSEL_OFFSET				0x0000000c
+#define AFE_TSTMSC_OFFSET				0x00000010
+#define AFE_ENPADIO_OFFSET				0x00000014
+#define AFE_BGREG_OFFSET				0x00000018
+#define AFE_ACCESSAR_ID_OFFSET			0x00000400
+#define AFE_PDADC_OFFSET				0x00000404
+#define AFE_PDSARH_OFFSET				0x00000408
+#define AFE_PDSARL_OFFSET				0x0000040C
+#define AFE_PDADCRFH_OFFSET				0x00000410
+#define AFE_PDADCRFL_OFFSET				0x00000414
+#define AFE_ACCTST_OFFSET				0x00000418
+#define AFE_ADCGN_OFFSET				0x0000041C
+#define AFE_ICTRL_OFFSET				0x00000420
+#define AFE_ICTLSTG_OFFSET				0x00000424
+#define AFE_RCTRLSTG_OFFSET				0x00000428
+#define AFE_TCTRLSTG_OFFSET				0x0000042c
+#define AFE_REFMOD_OFFSET				0x00000430
+#define AFE_REFTRIML_OFFSET				0x00000434
+#define AFE_REFTRIMH_OFFSET				0x00000438
+#define AFE_ADCR_OFFSET					0x0000043c
+#define AFE_DUMMY0_OFFSET				0x00000440
+#define AFE_DUMMY1_OFFSET				0x00000444
+#define AFE_DUMMY2_OFFSET				0x00000448
+#define AFE_DACAMP_OFFSET				0x0000044c
+#define AFE_CLMPTST_OFFSET				0x00000450
+#define AFE_CLMPDAT_OFFSET				0x00000454
+#define AFE_CLMPAMP_OFFSET				0x00000458
+#define AFE_CLAMP_OFFSET				0x0000045c
+#define AFE_INPBUF_OFFSET				0x00000460
+#define AFE_INPFLT_OFFSET				0x00000464
+#define AFE_ADCDGN_OFFSET				0x00000468
+#define AFE_OFFDRV_OFFSET				0x0000046c
+#define AFE_INPCONFIG_OFFSET			0x00000470
+#define AFE_PROGDELAY_OFFSET			0x00000474
+#define AFE_ADCOMT_OFFSET				0x00000478
+#define AFE_ALGDELAY_OFFSET				0x0000047c
+#define AFE_ACC_ID_OFFSET				0x00000800
+#define AFE_ACCSTA_OFFSET				0x00000804
+#define AFE_ACCNOSLI_OFFSET				0x00000808
+#define AFE_ACCCALCON_OFFSET			0x0000080c
+#define AFE_BWEWRICTRL_OFFSET			0x00000810
+#define AFE_SELSLI_OFFSET				0x00000814
+#define AFE_SELBYT_OFFSET				0x00000818
+#define AFE_REDVAL_OFFSET				0x00000820
+#define AFE_WRIBYT_OFFSET				0x00000824
+
+/* AFE Register per module */
+#define AFE_BLOCK_ID			(AFE_BASE + AFE_BLOCK_ID_OFFSET)
+#define AFE_PDBUF				(AFE_BASE + AFE_PDBUF_OFFSET)
+#define AFE_SWRST				(AFE_BASE + AFE_SWRST_OFFSET)
+#define AFE_TSTSEL				(AFE_BASE + AFE_TSTSEL_OFFSET)
+#define AFE_TSTMSC				(AFE_BASE + AFE_TSTMSC_OFFSET)
+#define AFE_ENPADIO				(AFE_BASE + AFE_ENPADIO_OFFSET)
+#define AFE_BGREG				(AFE_BASE + AFE_BGREG_OFFSET)
+#define AFE_ACCESSAR_ID			(AFE_BASE + AFE_ACCESSAR_ID_OFFSET)
+#define AFE_PDADC				(AFE_BASE + AFE_PDADC_OFFSET)
+#define AFE_PDSARH			    (AFE_BASE + AFE_PDSARH_OFFSET)
+#define AFE_PDSARL			    (AFE_BASE + AFE_PDSARL_OFFSET)
+#define AFE_PDADCRFH			(AFE_BASE + AFE_PDADCRFH_OFFSET)
+#define AFE_PDADCRFL			(AFE_BASE + AFE_PDADCRFL_OFFSET)
+#define AFE_ACCTST				(AFE_BASE + AFE_ACCTST_OFFSET)
+#define AFE_ADCGN				(AFE_BASE + AFE_ADCGN_OFFSET)
+#define AFE_ICTRL				(AFE_BASE + AFE_ICTRL_OFFSET)
+#define AFE_ICTLSTG				(AFE_BASE + AFE_ICTLSTG_OFFSET)
+#define AFE_RCTRLSTG			(AFE_BASE + AFE_RCTRLSTG_OFFSET)
+#define AFE_TCTRLSTG			(AFE_BASE + AFE_TCTRLSTG_OFFSET)
+#define AFE_REFMOD				(AFE_BASE + AFE_REFMOD_OFFSET)
+#define AFE_REFTRIML			(AFE_BASE + AFE_REFTRIML_OFFSET)
+#define AFE_REFTRIMH			(AFE_BASE + AFE_REFTRIMH_OFFSET)
+#define AFE_ADCR				(AFE_BASE + AFE_ADCR_OFFSET)
+#define AFE_DUMMY0				(AFE_BASE + AFE_DUMMY0_OFFSET)
+#define AFE_DUMMY1				(AFE_BASE + AFE_DUMMY1_OFFSET)
+#define AFE_DUMMY2				(AFE_BASE + AFE_DUMMY2_OFFSET)
+#define AFE_DACAMP				(AFE_BASE + AFE_DACAMP_OFFSET)
+#define AFE_CLMPTST				(AFE_BASE + AFE_CLMPTST_OFFSET)
+#define AFE_CLMPDAT				(AFE_BASE + AFE_CLMPDAT_OFFSET)
+#define AFE_CLMPAMP				(AFE_BASE + AFE_CLMPAMP_OFFSET)
+#define AFE_CLAMP				(AFE_BASE + AFE_CLAMP_OFFSET)
+#define AFE_INPBUF				(AFE_BASE + AFE_INPBUF_OFFSET)
+#define AFE_INPFLT				(AFE_BASE + AFE_INPFLT_OFFSET)
+#define AFE_ADCDGN				(AFE_BASE + AFE_ADCDGN_OFFSET)
+#define AFE_OFFDRV				(AFE_BASE + AFE_OFFDRV_OFFSET)
+#define AFE_INPCONFIG			(AFE_BASE + AFE_INPCONFIG_OFFSET)
+#define AFE_PROGDELAY			(AFE_BASE + AFE_PROGDELAY_OFFSET)
+#define AFE_ADCOMT				(AFE_BASE + AFE_ADCOMT_OFFSET)
+#define AFE_ALGDELAY			(AFE_BASE + AFE_ALGDELAY_OFFSET)
+#define AFE_ACC_ID				(AFE_BASE + AFE_ACC_ID_OFFSET)
+#define AFE_ACCSTA				(AFE_BASE + AFE_ACCSTA_OFFSET)
+#define AFE_ACCNOSLI			(AFE_BASE + AFE_ACCNOSLI_OFFSET)
+#define AFE_ACCCALCON			(AFE_BASE + AFE_ACCCALCON_OFFSET)
+#define AFE_BWEWRICTRL			(AFE_BASE + AFE_BWEWRICTRL_OFFSET)
+#define AFE_SELSLI				(AFE_BASE + AFE_SELSLI_OFFSET)
+#define AFE_SELBYT				(AFE_BASE + AFE_SELBYT_OFFSET)
+#define AFE_REDVAL				(AFE_BASE + AFE_REDVAL_OFFSET)
+#define AFE_WRIBYT				(AFE_BASE + AFE_WRIBYT_OFFSET)
+
+/* VDEC - Register offsets */
+#define VDEC_CFC1_OFFSET                0x00000000
+#define VDEC_CFC2_OFFSET                0x00000004
+#define VDEC_BRSTGT_OFFSET              0x00000024
+#define VDEC_HZPOS_OFFSET               0x00000040
+#define VDEC_VRTPOS_OFFSET              0x00000044
+#define VDEC_HVSHIFT_OFFSET             0x00000054
+#define VDEC_HSIGS_OFFSET               0x00000058
+#define VDEC_HSIGE_OFFSET               0x0000005C
+#define VDEC_VSCON1_OFFSET              0x00000060
+#define VDEC_VSCON2_OFFSET              0x00000064
+#define VDEC_YCDEL_OFFSET               0x0000006C
+#define VDEC_AFTCLP_OFFSET              0x00000070
+#define VDEC_DCOFF_OFFSET               0x00000078
+#define VDEC_CSID_OFFSET                0x00000084
+#define VDEC_CBGN_OFFSET                0x00000088
+#define VDEC_CRGN_OFFSET                0x0000008C
+#define VDEC_CNTR_OFFSET                0x00000090
+#define VDEC_BRT_OFFSET                 0x00000094
+#define VDEC_HUE_OFFSET                 0x00000098
+#define VDEC_CHBTH_OFFSET               0x0000009C
+#define VDEC_SHPIMP_OFFSET              0x000000A4
+#define VDEC_CHPLLIM_OFFSET             0x000000A8
+#define VDEC_VIDMOD_OFFSET              0x000000AC
+#define VDEC_VIDSTS_OFFSET              0x000000B0
+#define VDEC_NOISE_OFFSET               0x000000B4
+#define VDEC_STDDBG_OFFSET              0x000000B8
+#define VDEC_MANOVR_OFFSET              0x000000BC
+#define VDEC_VSSGTH_OFFSET              0x000000C8
+#define VDEC_DBGFBH_OFFSET              0x000000D0
+#define VDEC_DBGFBL_OFFSET              0x000000D4
+#define VDEC_HACTS_OFFSET               0x000000D8
+#define VDEC_HACTE_OFFSET               0x000000DC
+#define VDEC_VACTS_OFFSET               0x000000E0
+#define VDEC_VACTE_OFFSET               0x000000E4
+#define VDEC_HSTIP_OFFSET               0x000000EC
+#define VDEC_BLSCRY_OFFSET              0x000000F4
+#define VDEC_BLSCRCR_OFFSET             0x000000F8
+#define VDEC_BLSCRCB_OFFSET             0x000000FC
+#define VDEC_LMAGC1_OFFSET              0x00000100
+#define VDEC_LMAGC2_OFFSET              0x00000104
+#define VDEC_CHAGC1_OFFSET              0x00000108
+#define VDEC_CHAGC2_OFFSET              0x0000010C
+#define VDEC_MINTH_OFFSET               0x00000114
+#define VDEC_VFRQOH_OFFSET              0x0000011C
+#define VDEC_VFRQOL_OFFSET              0x00000120
+#define VDEC_THSH1_OFFSET               0x00000124
+#define VDEC_THSH2_OFFSET               0x00000128
+#define VDEC_NCHTH_OFFSET               0x0000012C
+#define VDEC_TH1F_OFFSET                0x00000130
+
+/* VDEC Register per module */
+#define VDEC_CFC1                        (VDEC_BASE + VDEC_CFC1_OFFSET)
+#define VDEC_CFC2                        (VDEC_BASE + VDEC_CFC2_OFFSET)
+#define VDEC_BRSTGT                      (VDEC_BASE + VDEC_BRSTGT_OFFSET)
+#define VDEC_HZPOS                       (VDEC_BASE + VDEC_HZPOS_OFFSET)
+#define VDEC_VRTPOS                      (VDEC_BASE + VDEC_VRTPOS_OFFSET)
+#define VDEC_HVSHIFT                     (VDEC_BASE + VDEC_HVSHIFT_OFFSET)
+#define VDEC_HSIGS                       (VDEC_BASE + VDEC_HSIGS_OFFSET)
+#define VDEC_HSIGE                       (VDEC_BASE + VDEC_HSIGE_OFFSET)
+#define VDEC_VSCON1                      (VDEC_BASE + VDEC_VSCON1_OFFSET)
+#define VDEC_VSCON2                      (VDEC_BASE + VDEC_VSCON2_OFFSET)
+#define VDEC_YCDEL                       (VDEC_BASE + VDEC_YCDEL_OFFSET)
+#define VDEC_AFTCLP                      (VDEC_BASE + VDEC_AFTCLP_OFFSET)
+#define VDEC_DCOFF                       (VDEC_BASE + VDEC_DCOFF_OFFSET)
+#define VDEC_CSID                        (VDEC_BASE + VDEC_CSID_OFFSET)
+#define VDEC_CBGN                        (VDEC_BASE + VDEC_CBGN_OFFSET)
+#define VDEC_CRGN                        (VDEC_BASE + VDEC_CRGN_OFFSET)
+#define VDEC_CNTR                        (VDEC_BASE + VDEC_CNTR_OFFSET)
+#define VDEC_BRT                         (VDEC_BASE + VDEC_BRT_OFFSET)
+#define VDEC_HUE                         (VDEC_BASE + VDEC_HUE_OFFSET)
+#define VDEC_CHBTH                       (VDEC_BASE + VDEC_CHBTH_OFFSET)
+#define VDEC_SHPIMP                      (VDEC_BASE + VDEC_SHPIMP_OFFSET)
+#define VDEC_CHPLLIM                     (VDEC_BASE + VDEC_CHPLLIM_OFFSET)
+#define VDEC_VIDMOD                      (VDEC_BASE + VDEC_VIDMOD_OFFSET)
+#define VDEC_VIDSTS                      (VDEC_BASE + VDEC_VIDSTS_OFFSET)
+#define VDEC_NOISE                       (VDEC_BASE + VDEC_NOISE_OFFSET)
+#define VDEC_STDDBG                      (VDEC_BASE + VDEC_STDDBG_OFFSET)
+#define VDEC_MANOVR                      (VDEC_BASE + VDEC_MANOVR_OFFSET)
+#define VDEC_VSSGTH                      (VDEC_BASE + VDEC_VSSGTH_OFFSET)
+#define VDEC_DBGFBH                      (VDEC_BASE + VDEC_DBGFBH_OFFSET)
+#define VDEC_DBGFBL                      (VDEC_BASE + VDEC_DBGFBL_OFFSET)
+#define VDEC_HACTS                       (VDEC_BASE + VDEC_HACTS_OFFSET)
+#define VDEC_HACTE                       (VDEC_BASE + VDEC_HACTE_OFFSET)
+#define VDEC_VACTS                       (VDEC_BASE + VDEC_VACTS_OFFSET)
+#define VDEC_VACTE                       (VDEC_BASE + VDEC_VACTE_OFFSET)
+#define VDEC_HSTIP                       (VDEC_BASE + VDEC_HSTIP_OFFSET)
+#define VDEC_BLSCRY                      (VDEC_BASE + VDEC_BLSCRY_OFFSET)
+#define VDEC_BLSCRCR                     (VDEC_BASE + VDEC_BLSCRCR_OFFSET)
+#define VDEC_BLSCRCB                     (VDEC_BASE + VDEC_BLSCRCB_OFFSET)
+#define VDEC_LMAGC1                      (VDEC_BASE + VDEC_LMAGC1_OFFSET)
+#define VDEC_LMAGC2                      (VDEC_BASE + VDEC_LMAGC2_OFFSET)
+#define VDEC_CHAGC1                      (VDEC_BASE + VDEC_CHAGC1_OFFSET)
+#define VDEC_CHAGC2                      (VDEC_BASE + VDEC_CHAGC2_OFFSET)
+#define VDEC_MINTH                       (VDEC_BASE + VDEC_MINTH_OFFSET)
+#define VDEC_VFRQOH                      (VDEC_BASE + VDEC_VFRQOH_OFFSET)
+#define VDEC_VFRQOL                      (VDEC_BASE + VDEC_VFRQOL_OFFSET)
+#define VDEC_THSH1                       (VDEC_BASE + VDEC_THSH1_OFFSET)
+#define VDEC_THSH2                       (VDEC_BASE + VDEC_THSH2_OFFSET)
+#define VDEC_NCHTH                       (VDEC_BASE + VDEC_NCHTH_OFFSET)
+#define VDEC_TH1F                        (VDEC_BASE + VDEC_TH1F_OFFSET)
+
+#define VDEC_VIDMOD_SIGNAL_MASK           0x0F
+#define VDEC_VIDMOD_SIGNAL_DETECT         0x0F
+
+#define VDEC_VIDMOD_M625_SHIFT            4
+#define VDEC_VIDMOD_M625_MASK             (1 << VDEC_VIDMOD_M625_SHIFT)
+
+#define VDEC_VIDMOD_PAL_SHIFT             7
+#define VDEC_VIDMOD_PAL_MASK              (1 << VDEC_VIDMOD_PAL_SHIFT)
+/*** define base address ***/
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ov5640.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ov5640.c
@@ -0,0 +1,1965 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define OV5640_VOLTAGE_ANALOG               2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE         1500000
+#define OV5640_VOLTAGE_DIGITAL_IO           1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE        0x300A
+#define OV5640_CHIP_ID_LOW_BYTE         0x300B
+
+enum ov5640_mode {
+	ov5640_mode_MIN = 0,
+	ov5640_mode_VGA_640_480 = 0,
+	ov5640_mode_QVGA_320_240 = 1,
+	ov5640_mode_NTSC_720_480 = 2,
+	ov5640_mode_PAL_720_576 = 3,
+	ov5640_mode_720P_1280_720 = 4,
+	ov5640_mode_1080P_1920_1080 = 5,
+	ov5640_mode_QSXGA_2592_1944 = 6,
+	ov5640_mode_QCIF_176_144 = 7,
+	ov5640_mode_XGA_1024_768 = 8,
+	ov5640_mode_MAX = 8
+};
+
+enum ov5640_frame_rate {
+	ov5640_15_fps,
+	ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+	[ov5640_15_fps] = 15,
+	[ov5640_30_fps] = 30,
+};
+
+struct reg_value {
+	u16 u16RegAddr;
+	u8 u8Val;
+	u8 u8Mask;
+	u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+	enum ov5640_mode mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct sensor_data ov5640_data;
+static int pwn_gpio, rst_gpio;
+static int prev_sysclk;
+static int AE_Target = 52, night_mode;
+static int prev_HTS;
+static int AE_high, AE_low;
+
+static struct reg_value ov5640_global_init_setting[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+	{0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0},
+	{0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0},
+	{0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0},
+	{0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0},
+	{0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0},
+	{0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0},
+	{0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0},
+	{0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0},
+	{0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+	{0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0},
+	{0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0},
+	{0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0},
+	{0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+	{0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+	{0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0},
+	{0x3008, 0x02, 0, 0},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+	{0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0},
+	{0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+	{0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0},
+	{0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+	{0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0},
+	{0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0},
+	{0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0},
+	{0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0},
+	{0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+	{0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+	{0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0},
+	{0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0},
+	{0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0},
+	{0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0},
+	{0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0},
+	{0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0},
+	{0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0},
+	{0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0},
+	{0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0},
+	{0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0},
+	{0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0},
+	{0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0},
+	{0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0},
+	{0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0},
+	{0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0},
+	{0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0},
+	{0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0},
+	{0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0},
+	{0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0},
+	{0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0},
+	{0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0},
+	{0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0},
+	{0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0},
+	{0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0},
+	{0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0},
+	{0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0},
+	{0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0},
+	{0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0},
+	{0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0},
+	{0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0},
+	{0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0},
+	{0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0},
+	{0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0},
+	{0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0},
+	{0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0},
+	{0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0},
+	{0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0},
+	{0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0},
+	{0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0},
+	{0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0},
+	{0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0},
+	{0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+	{0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+	{0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+	{0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+	{0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+	{0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+	{0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+	{0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+	{0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+	{0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+	{0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+	{0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0},
+	{0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0},
+	{0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+	{0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+	{0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+	{0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+	{0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+	{0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0},
+	{0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0},
+	{0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+	{0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+	{0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+	{0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+	{
+		{ov5640_mode_VGA_640_480,      640,  480,
+		ov5640_setting_15fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240,     320,  240,
+		ov5640_setting_15fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480,     720,  480,
+		ov5640_setting_15fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576,      720,  576,
+		ov5640_setting_15fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720,   1280,  720,
+		ov5640_setting_15fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, 1920, 1080,
+		ov5640_setting_15fps_1080P_1920_1080,
+		ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+		{ov5640_mode_QSXGA_2592_1944, 2592, 1944,
+		ov5640_setting_15fps_QSXGA_2592_1944,
+		ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+		{ov5640_mode_QCIF_176_144,     176,  144,
+		ov5640_setting_15fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768,    1024,  768,
+		ov5640_setting_15fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+	},
+	{
+		{ov5640_mode_VGA_640_480,      640,  480,
+		ov5640_setting_30fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240,     320,  240,
+		ov5640_setting_30fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480,     720,  480,
+		ov5640_setting_30fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576,      720,  576,
+		ov5640_setting_30fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720,   1280,  720,
+		ov5640_setting_30fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0},
+		{ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0},
+		{ov5640_mode_QCIF_176_144,     176,  144,
+		ov5640_setting_30fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768,    1024,  768,
+		ov5640_setting_30fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+	},
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ov5640_of_match[] = {
+	{ .compatible = "ovti,ov564x",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ov5640_of_match);
+#endif
+
+static const struct i2c_device_id ov5640_id[] = {
+	{"ov564x", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+	.driver = {
+		  .owner = THIS_MODULE,
+		  .name  = "ov564x",
+#ifdef CONFIG_OF
+		  .of_match_table = of_match_ptr(ov5640_of_match),
+#endif
+		  },
+	.probe  = ov5640_probe,
+	.remove = ov5640_remove,
+	.id_table = ov5640_id,
+};
+
+static inline void ov5640_power_down(int enable)
+{
+	gpio_set_value(pwn_gpio, enable);
+
+	msleep(2);
+}
+
+static inline void ov5640_reset(void)
+{
+	/* camera reset */
+	gpio_set_value(rst_gpio, 1);
+
+	/* camera power down */
+	gpio_set_value(pwn_gpio, 1);
+	msleep(5);
+	gpio_set_value(pwn_gpio, 0);
+	msleep(5);
+	gpio_set_value(rst_gpio, 0);
+	msleep(1);
+	gpio_set_value(rst_gpio, 1);
+	msleep(5);
+	gpio_set_value(pwn_gpio, 1);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+	int ret = 0;
+
+	io_regulator = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(io_regulator)) {
+		regulator_set_voltage(io_regulator,
+				      OV5640_VOLTAGE_DIGITAL_IO,
+				      OV5640_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(io_regulator);
+		if (ret) {
+			dev_err(dev, "set io voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set io voltage ok\n");
+		}
+	} else {
+		io_regulator = NULL;
+		dev_warn(dev, "cannot get io voltage\n");
+	}
+
+	core_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(core_regulator)) {
+		regulator_set_voltage(core_regulator,
+				      OV5640_VOLTAGE_DIGITAL_CORE,
+				      OV5640_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(core_regulator);
+		if (ret) {
+			dev_err(dev, "set core voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set core voltage ok\n");
+		}
+	} else {
+		core_regulator = NULL;
+		dev_warn(dev, "cannot get core voltage\n");
+	}
+
+	analog_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(analog_regulator)) {
+		regulator_set_voltage(analog_regulator,
+				      OV5640_VOLTAGE_ANALOG,
+				      OV5640_VOLTAGE_ANALOG);
+		ret = regulator_enable(analog_regulator);
+		if (ret) {
+			dev_err(dev, "set analog voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set analog voltage ok\n");
+		}
+	} else {
+		analog_regulator = NULL;
+		dev_warn(dev, "cannot get analog voltage\n");
+	}
+
+	return ret;
+}
+
+static void ov5640_regulator_disable(void)
+{
+	if (analog_regulator)
+		regulator_disable(analog_regulator);
+
+	if (core_regulator)
+		regulator_disable(core_regulator);
+
+	if (io_regulator)
+		regulator_disable(io_regulator);
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+	u8 au8Buf[3] = {0};
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+		pr_err("%s:write reg error:reg=%x,val=%x\n",
+			__func__, reg, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+		pr_err("%s:write reg error:reg=%x\n",
+				__func__, reg);
+		return -1;
+	}
+
+	if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+		pr_err("%s:read reg error:reg=%x,val=%x\n",
+				__func__, reg, u8RdVal);
+		return -1;
+	}
+
+	*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+static void ov5640_soft_reset(void)
+{
+	/* sysclk from pad */
+	ov5640_write_reg(0x3103, 0x11);
+
+	/* software reset */
+	ov5640_write_reg(0x3008, 0x82);
+
+	/* delay at least 5ms */
+	msleep(10);
+}
+
+/* set sensor driver capability
+ * 0x302c[7:6] - strength
+	00     - 1x
+	01     - 2x
+	10     - 3x
+	11     - 4x
+ */
+static int ov5640_driver_capability(int strength)
+{
+	u8 temp = 0;
+
+	if (strength > 4 || strength < 1) {
+		pr_err("The valid driver capability of ov5640 is 1x~4x\n");
+		return -EINVAL;
+	}
+
+	ov5640_read_reg(0x302c, &temp);
+
+	temp &= ~0xc0;	/* clear [7:6] */
+	temp |= ((strength - 1) << 6);	/* set [7:6] */
+
+	ov5640_write_reg(0x302c, temp);
+
+	return 0;
+}
+
+/* calculate sysclk */
+static int ov5640_get_sysclk(void)
+{
+	int xvclk = ov5640_data.mclk / 10000;
+	int sysclk;
+	int temp1, temp2;
+	int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv;
+	int sclk_rdiv_map[] = {1, 2, 4, 8};
+	u8 regval = 0;
+
+	temp1 = ov5640_read_reg(0x3034, &regval);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10) {
+		Bit_div2x = temp2 / 2;
+	} else {
+		pr_err("ov5640: unsupported bit mode %d\n", temp2);
+		return -1;
+	}
+
+	temp1 = ov5640_read_reg(0x3035, &regval);
+	SysDiv = temp1 >> 4;
+	if (SysDiv == 0)
+		SysDiv = 16;
+
+	temp1 = ov5640_read_reg(0x3036, &regval);
+	Multiplier = temp1;
+	temp1 = ov5640_read_reg(0x3037, &regval);
+	PreDiv = temp1 & 0x0f;
+	Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov5640_read_reg(0x3108, &regval);
+	temp2 = temp1 & 0x03;
+
+	sclk_rdiv = sclk_rdiv_map[temp2];
+	VCO = xvclk * Multiplier / PreDiv;
+	sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+	return sysclk;
+}
+
+/* read HTS from register settings */
+static int ov5640_get_HTS(void)
+{
+	int HTS;
+	u8 temp = 0;
+
+	HTS = ov5640_read_reg(0x380c, &temp);
+	HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+	return HTS;
+}
+
+/* read VTS from register settings */
+static int ov5640_get_VTS(void)
+{
+	int VTS;
+	u8 temp = 0;
+
+	VTS = ov5640_read_reg(0x380e, &temp);
+	VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+	return VTS;
+}
+
+/* write VTS to registers */
+static int ov5640_set_VTS(int VTS)
+{
+	int temp;
+
+	temp = VTS & 0xff;
+	ov5640_write_reg(0x380f, temp);
+
+	temp = VTS>>8;
+	ov5640_write_reg(0x380e, temp);
+	return 0;
+}
+
+/* read shutter, in number of line period */
+static int ov5640_get_shutter(void)
+{
+	int shutter;
+	u8 regval;
+
+	shutter = (ov5640_read_reg(0x03500, &regval) & 0x0f);
+
+	shutter = (shutter<<8) + ov5640_read_reg(0x3501, &regval);
+	shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &regval)>>4);
+
+	return shutter;
+}
+
+/* write shutter, in number of line period */
+static int ov5640_set_shutter(int shutter)
+{
+	int temp;
+
+	shutter = shutter & 0xffff;
+	temp = shutter & 0x0f;
+	temp = temp<<4;
+	ov5640_write_reg(0x3502, temp);
+
+	temp = shutter & 0xfff;
+	temp = temp>>4;
+	ov5640_write_reg(0x3501, temp);
+
+	temp = shutter>>12;
+	ov5640_write_reg(0x3500, temp);
+
+	return 0;
+}
+
+/* read gain, 16 = 1x */
+static int ov5640_get_gain16(void)
+{
+	int gain16;
+	u8 regval;
+
+	gain16 = ov5640_read_reg(0x350a, &regval) & 0x03;
+	gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &regval);
+
+	return gain16;
+}
+
+/* write gain, 16 = 1x */
+static int ov5640_set_gain16(int gain16)
+{
+	int temp;
+
+	gain16 = gain16 & 0x3ff;
+	temp = gain16 & 0xff;
+
+	ov5640_write_reg(0x350b, temp);
+	temp = gain16>>8;
+
+	ov5640_write_reg(0x350a, temp);
+	return 0;
+}
+
+/* get banding filter value */
+static int ov5640_get_light_freq(void)
+{
+	int temp, temp1, light_frequency;
+	u8 regval;
+
+	temp = ov5640_read_reg(0x3c01, &regval);
+	if (temp & 0x80) {
+		/* manual */
+		temp1 = ov5640_read_reg(0x3c00, &regval);
+		if (temp1 & 0x04) {
+			/* 50Hz */
+			light_frequency = 50;
+		} else {
+			/* 60Hz */
+			light_frequency = 60;
+		}
+	} else {
+		/* auto */
+		temp1 = ov5640_read_reg(0x3c0c, &regval);
+		if (temp1 & 0x01) {
+			/* 50Hz */
+			light_frequency = 50;
+		} else {
+			/* 60Hz */
+			light_frequency = 60;
+		}
+	}
+
+	return light_frequency;
+}
+
+static void ov5640_set_bandingfilter(void)
+{
+	int prev_VTS;
+	int band_step60, max_band60, band_step50, max_band50;
+
+	/* read preview PCLK */
+	prev_sysclk = ov5640_get_sysclk();
+
+	/* read preview HTS */
+	prev_HTS = ov5640_get_HTS();
+
+	/* read preview VTS */
+	prev_VTS = ov5640_get_VTS();
+
+	/* calculate banding filter */
+	/* 60Hz */
+	band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+	ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+	ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+	max_band60 = (int)((prev_VTS-4)/band_step60);
+	ov5640_write_reg(0x3a0d, max_band60);
+
+	/* 50Hz */
+	band_step50 = prev_sysclk * 100/prev_HTS;
+	ov5640_write_reg(0x3a08, (band_step50 >> 8));
+	ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+	max_band50 = (int)((prev_VTS-4)/band_step50);
+	ov5640_write_reg(0x3a0e, max_band50);
+}
+
+/* stable in high */
+static int ov5640_set_AE_target(int target)
+{
+	int fast_high, fast_low;
+
+	AE_low = target * 23 / 25; /* 0.92 */
+	AE_high = target * 27 / 25; /* 1.08 */
+	fast_high = AE_high << 1;
+
+	if (fast_high > 255)
+		fast_high = 255;
+	fast_low = AE_low >> 1;
+
+	ov5640_write_reg(0x3a0f, AE_high);
+	ov5640_write_reg(0x3a10, AE_low);
+	ov5640_write_reg(0x3a1b, AE_high);
+	ov5640_write_reg(0x3a1e, AE_low);
+	ov5640_write_reg(0x3a11, fast_high);
+	ov5640_write_reg(0x3a1f, fast_low);
+
+	return 0;
+}
+
+/* enable = 0 to turn off night mode
+   enable = 1 to turn on night mode */
+static int ov5640_set_night_mode(int enable)
+{
+	u8 mode;
+
+	ov5640_read_reg(0x3a00, &mode);
+
+	if (enable) {
+		/* night mode on */
+		mode |= 0x04;
+		ov5640_write_reg(0x3a00, mode);
+	} else {
+		/* night mode off */
+		mode &= 0xfb;
+		ov5640_write_reg(0x3a00, mode);
+	}
+
+	return 0;
+}
+
+/* enable = 0 to turn off AEC/AGC
+   enable = 1 to turn on AEC/AGC */
+static void ov5640_turn_on_AE_AG(int enable)
+{
+	u8 ae_ag_ctrl;
+
+	ov5640_read_reg(0x3503, &ae_ag_ctrl);
+	if (enable) {
+		/* turn on auto AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+	} else {
+		/* turn off AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl | 0x03;
+	}
+	ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+	register u32 Delay_ms = 0;
+	register u16 RegAddr = 0;
+	register u8 Mask = 0;
+	register u8 Val = 0;
+	u8 RegVal = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+		Delay_ms = pModeSetting->u32Delay_ms;
+		RegAddr = pModeSetting->u16RegAddr;
+		Val = pModeSetting->u8Val;
+		Mask = pModeSetting->u8Mask;
+
+		if (Mask) {
+			retval = ov5640_read_reg(RegAddr, &RegVal);
+			if (retval < 0)
+				goto err;
+
+			RegVal &= ~(u8)Mask;
+			Val &= Mask;
+			Val |= RegVal;
+		}
+
+		retval = ov5640_write_reg(RegAddr, Val);
+		if (retval < 0)
+			goto err;
+
+		if (Delay_ms)
+			msleep(Delay_ms);
+	}
+err:
+	return retval;
+}
+
+static int ov5640_init_mode(void)
+{
+	struct reg_value *pModeSetting = NULL;
+	int ArySize = 0, retval = 0;
+
+	ov5640_soft_reset();
+
+	pModeSetting = ov5640_global_init_setting;
+	ArySize = ARRAY_SIZE(ov5640_global_init_setting);
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	pModeSetting = ov5640_init_setting_30fps_VGA;
+	ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* change driver capability to 2x according to validation board.
+	 * if the image is not stable, please increase the driver strength.
+	 */
+	ov5640_driver_capability(2);
+	ov5640_set_bandingfilter();
+	ov5640_set_AE_target(AE_Target);
+	ov5640_set_night_mode(night_mode);
+
+	/* skip 9 vysnc: start capture at 10th vsync */
+	msleep(300);
+
+	/* turn off night mode */
+	night_mode = 0;
+	ov5640_data.pix.width = 640;
+	ov5640_data.pix.height = 480;
+err:
+	return retval;
+}
+
+/* change to or back to subsampling mode set the mode directly
+ * image size below 1280 * 960 is subsampling mode */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+		pr_err("Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+	    pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* set ov5640 to subsampling mode */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+
+	/* turn on AE AG for subsampling mode, in case the firmware didn't */
+	ov5640_turn_on_AE_AG(1);
+
+	/* calculate banding filter */
+	ov5640_set_bandingfilter();
+
+	/* set AE target */
+	ov5640_set_AE_target(AE_Target);
+
+	/* update night mode setting */
+	ov5640_set_night_mode(night_mode);
+
+	/* skip 9 vysnc: start capture at 10th vsync */
+	if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) {
+		pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n");
+		/* 1/22.5 * 9*/
+		msleep(400);
+		return retval;
+	}
+
+	if (frame_rate == ov5640_15_fps) {
+		/* 1/15 * 9*/
+		msleep(600);
+	} else if (frame_rate == ov5640_30_fps) {
+		/* 1/30 * 9*/
+		msleep(300);
+	}
+
+	return retval;
+}
+
+/* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	int prev_shutter, prev_gain16, average;
+	int cap_shutter, cap_gain16;
+	int cap_sysclk, cap_HTS, cap_VTS;
+	int light_freq, cap_bandfilt, cap_maxband;
+	long cap_gain16_shutter;
+	u8 temp;
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* read preview shutter */
+	prev_shutter = ov5640_get_shutter();
+
+	/* read preview gain */
+	prev_gain16 = ov5640_get_gain16();
+
+	/* get average */
+	average = ov5640_read_reg(0x56a1, &temp);
+
+	/* turn off night mode for capture */
+	ov5640_set_night_mode(0);
+
+	/* turn off overlay */
+	ov5640_write_reg(0x3022, 0x06);
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* turn off AE AG when capture image. */
+	ov5640_turn_on_AE_AG(0);
+
+	/* read capture VTS */
+	cap_VTS = ov5640_get_VTS();
+	cap_HTS = ov5640_get_HTS();
+	cap_sysclk = ov5640_get_sysclk();
+
+	/* calculate capture banding filter */
+	light_freq = ov5640_get_light_freq();
+	if (light_freq == 60) {
+		/* 60Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+	} else {
+		/* 50Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+	}
+	cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+	/* calculate capture shutter/gain16 */
+	if (average > AE_low && average < AE_high) {
+		/* in stable range */
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+			prev_HTS/cap_HTS * AE_Target / average;
+	} else {
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+			prev_HTS/cap_HTS;
+	}
+
+	/* gain to shutter */
+	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+		/* shutter < 1/100 */
+		cap_shutter = cap_gain16_shutter/16;
+		if (cap_shutter < 1)
+			cap_shutter = 1;
+		cap_gain16 = cap_gain16_shutter/cap_shutter;
+		if (cap_gain16 < 16)
+			cap_gain16 = 16;
+	} else {
+		if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) {
+			/* exposure reach max */
+			cap_shutter = cap_bandfilt*cap_maxband;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		} else {
+			/* 1/100 < cap_shutter =< max, cap_shutter = n/100 */
+			cap_shutter =
+				((int)(cap_gain16_shutter/16/cap_bandfilt))
+				* cap_bandfilt;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		}
+	}
+
+	/* write capture gain */
+	ov5640_set_gain16(cap_gain16);
+
+	/* write capture shutter */
+	if (cap_shutter > (cap_VTS - 4)) {
+		cap_VTS = cap_shutter + 4;
+		ov5640_set_VTS(cap_VTS);
+	}
+
+	ov5640_set_shutter(cap_shutter);
+
+	/* skip 2 vysnc: start capture at 3rd vsync
+	 * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2
+	 */
+	pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n",
+		mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA");
+	msleep(267);
+err:
+	return retval;
+}
+
+static int ov5640_change_mode(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	int retval = 0;
+
+	if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+		pr_err("Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	if (mode == ov5640_mode_1080P_1920_1080 ||
+			mode == ov5640_mode_QSXGA_2592_1944) {
+		/* change to scaling mode go through exposure calucation
+		 * image size above 1280 * 960 is scaling mode */
+		retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+	} else {
+		/* change back to subsampling modem download firmware directly
+		 * image size below 1280 * 960 is subsampling mode */
+		retval = ov5640_change_mode_direct(frame_rate, mode);
+	}
+
+	return retval;
+}
+
+/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+	if (s == NULL) {
+		pr_err("   ERROR!! no slave device set!\n");
+		return -1;
+	}
+
+	memset(p, 0, sizeof(*p));
+	p->u.bt656.clock_curr = ov5640_data.mclk;
+	pr_debug("   clock_curr=mclk=%d\n", ov5640_data.mclk);
+	p->if_type = V4L2_IF_TYPE_BT656;
+	p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+	p->u.bt656.clock_min = OV5640_XCLK_MIN;
+	p->u.bt656.clock_max = OV5640_XCLK_MAX;
+	p->u.bt656.bt_sync_correct = 1;  /* Indicate external vsync */
+
+	return 0;
+}
+
+/*!
+ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+	struct sensor_data *sensor = s->priv;
+
+	if (on && !sensor->on) {
+		if (io_regulator)
+			if (regulator_enable(io_regulator) != 0)
+				return -EIO;
+		if (core_regulator)
+			if (regulator_enable(core_regulator) != 0)
+				return -EIO;
+		if (analog_regulator)
+			if (regulator_enable(analog_regulator) != 0)
+				return -EIO;
+		/* Make sure power on */
+		ov5640_power_down(0);
+	} else if (!on && sensor->on) {
+		ov5640_regulator_disable();
+
+		ov5640_power_down(1);
+}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	struct sensor_data *sensor = s->priv;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->streamcap.capability;
+		cparm->timeperframe = sensor->streamcap.timeperframe;
+		cparm->capturemode = sensor->streamcap.capturemode;
+		ret = 0;
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	struct sensor_data *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	int ret = 0;
+
+	/* Make sure power on */
+	ov5640_power_down(0);
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		/* Check that the new frame rate is allowed. */
+		if ((timeperframe->numerator == 0) ||
+		    (timeperframe->denominator == 0)) {
+			timeperframe->denominator = DEFAULT_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps > MAX_FPS) {
+			timeperframe->denominator = MAX_FPS;
+			timeperframe->numerator = 1;
+		} else if (tgt_fps < MIN_FPS) {
+			timeperframe->denominator = MIN_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		/* Actual frame rate we use */
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps == 15)
+			frame_rate = ov5640_15_fps;
+		else if (tgt_fps == 30)
+			frame_rate = ov5640_30_fps;
+		else {
+			pr_err(" The camera frame rate is not supported!\n");
+			return -EINVAL;
+		}
+
+		ret = ov5640_change_mode(frame_rate,
+				a->parm.capture.capturemode);
+		if (ret < 0)
+			return ret;
+
+		sensor->streamcap.timeperframe = *timeperframe;
+		sensor->streamcap.capturemode = a->parm.capture.capturemode;
+
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		pr_debug("   type is not " \
+			"V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+			a->type);
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+	struct sensor_data *sensor = s->priv;
+
+	f->fmt.pix = sensor->pix;
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array.  Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int ret = 0;
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		vc->value = ov5640_data.brightness;
+		break;
+	case V4L2_CID_HUE:
+		vc->value = ov5640_data.hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		vc->value = ov5640_data.contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		vc->value = ov5640_data.saturation;
+		break;
+	case V4L2_CID_RED_BALANCE:
+		vc->value = ov5640_data.red;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		vc->value = ov5640_data.blue;
+		break;
+	case V4L2_CID_EXPOSURE:
+		vc->value = ov5640_data.ae_mode;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array).  Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int retval = 0;
+
+	pr_debug("In ov5640:ioctl_s_ctrl %d\n",
+		 vc->id);
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		break;
+	case V4L2_CID_CONTRAST:
+		break;
+	case V4L2_CID_SATURATION:
+		break;
+	case V4L2_CID_HUE:
+		break;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		break;
+	case V4L2_CID_DO_WHITE_BALANCE:
+		break;
+	case V4L2_CID_RED_BALANCE:
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		break;
+	case V4L2_CID_GAMMA:
+		break;
+	case V4L2_CID_EXPOSURE:
+		break;
+	case V4L2_CID_AUTOGAIN:
+		break;
+	case V4L2_CID_GAIN:
+		break;
+	case V4L2_CID_HFLIP:
+		break;
+	case V4L2_CID_VFLIP:
+		break;
+	default:
+		retval = -EPERM;
+		break;
+	}
+
+	return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+				 struct v4l2_frmsizeenum *fsize)
+{
+	if (fsize->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fsize->pixel_format = ov5640_data.pix.pixelformat;
+	fsize->discrete.width =
+			max(ov5640_mode_info_data[0][fsize->index].width,
+			    ov5640_mode_info_data[1][fsize->index].width);
+	fsize->discrete.height =
+			max(ov5640_mode_info_data[0][fsize->index].height,
+			    ov5640_mode_info_data[1][fsize->index].height);
+	return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+					 struct v4l2_frmivalenum *fival)
+{
+	int i, j, count;
+
+	if (fival->index < 0 || fival->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	if (fival->width == 0 || fival->height == 0 ||
+	    fival->pixel_format == 0) {
+		pr_warning("Please assign pixelformat, width and height.\n");
+		return -EINVAL;
+	}
+
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete.numerator = 1;
+
+	count = 0;
+	for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+		for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+			if (fival->pixel_format == ov5640_data.pix.pixelformat
+			 && fival->width == ov5640_mode_info_data[i][j].width
+			 && fival->height == ov5640_mode_info_data[i][j].height
+			 && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+				count++;
+			}
+			if (fival->index == (count - 1)) {
+				fival->discrete.denominator =
+						ov5640_framerates[i];
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ *			VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+	((struct v4l2_dbg_chip_ident *)id)->match.type =
+					V4L2_CHIP_MATCH_I2C_DRIVER;
+	strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5640_camera");
+
+	return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+
+	return 0;
+}
+
+/*!
+ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: pointer to standard V4L2 fmt description structure
+ *
+ * Return 0.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+			      struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fmt->pixelformat = ov5640_data.pix.pixelformat;
+
+	return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	struct sensor_data *sensor = s->priv;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	int ret;
+
+	ov5640_data.on = true;
+
+	/* mclk */
+	tgt_xclk = ov5640_data.mclk;
+	tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+	ov5640_data.mclk = tgt_xclk;
+
+	pr_debug("   Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+	clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk);
+
+	/* Default camera frame rate is set in probe */
+	tgt_fps = sensor->streamcap.timeperframe.denominator /
+		  sensor->streamcap.timeperframe.numerator;
+
+	if (tgt_fps == 15)
+		frame_rate = ov5640_15_fps;
+	else if (tgt_fps == 30)
+		frame_rate = ov5640_30_fps;
+	else
+		return -EINVAL; /* Only support 15fps or 30fps now. */
+
+	ret = ov5640_init_mode();
+	return ret;
+}
+
+/*!
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the device when slave detaches to the master.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+	return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module and links them to the
+ * enumeration.
+ */
+static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = {
+	{ vidioc_int_dev_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_dev_init },
+	{ vidioc_int_dev_exit_num,
+	  ioctl_dev_exit},
+	{ vidioc_int_s_power_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_power },
+	{ vidioc_int_g_ifparm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+	{ vidioc_int_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_init },
+	{ vidioc_int_enum_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+	{ vidioc_int_g_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+	{ vidioc_int_g_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_parm },
+	{ vidioc_int_s_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_parm },
+	{ vidioc_int_g_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+	{ vidioc_int_s_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+	{ vidioc_int_enum_framesizes_num,
+	  (v4l2_int_ioctl_func *)ioctl_enum_framesizes },
+	{ vidioc_int_enum_frameintervals_num,
+	  (v4l2_int_ioctl_func *)ioctl_enum_frameintervals },
+	{ vidioc_int_g_chip_ident_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_chip_ident },
+};
+
+static struct v4l2_int_slave ov5640_slave = {
+	.ioctls = ov5640_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov5640_int_device = {
+	.module = THIS_MODULE,
+	.name = "ov564x",
+	.type = v4l2_int_type_slave,
+	.u = {
+		.slave = &ov5640_slave,
+	},
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter            struct i2c_adapter *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct pinctrl *pinctrl;
+	struct device *dev = &client->dev;
+	int retval;
+	u8 chip_id_high, chip_id_low;
+
+	/* ov5640 pinctrl */
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl)) {
+		dev_err(dev, "setup pinctrl failed\n");
+		return PTR_ERR(pinctrl);
+	}
+
+	/* request power down pin */
+	pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(pwn_gpio)) {
+		dev_err(dev, "no sensor pwdn pin available\n");
+		return -ENODEV;
+	}
+	retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_pwdn");
+	if (retval < 0)
+		return retval;
+
+	/* request reset pin */
+	rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+	if (!gpio_is_valid(rst_gpio)) {
+		dev_err(dev, "no sensor reset pin available\n");
+		return -EINVAL;
+	}
+	retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_reset");
+	if (retval < 0)
+		return retval;
+
+	/* Set initial values for the sensor struct. */
+	memset(&ov5640_data, 0, sizeof(ov5640_data));
+	ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(ov5640_data.sensor_clk)) {
+		dev_err(dev, "get mclk failed\n");
+		return PTR_ERR(ov5640_data.sensor_clk);
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk",
+					&ov5640_data.mclk);
+	if (retval) {
+		dev_err(dev, "mclk frequency is invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk_source",
+					(u32 *) &(ov5640_data.mclk_source));
+	if (retval) {
+		dev_err(dev, "mclk_source invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "csi_id",
+					&(ov5640_data.csi));
+	if (retval) {
+		dev_err(dev, "csi_id invalid\n");
+		return retval;
+	}
+
+	clk_prepare_enable(ov5640_data.sensor_clk);
+
+	ov5640_data.io_init = ov5640_reset;
+	ov5640_data.i2c_client = client;
+	ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	ov5640_data.pix.width = 640;
+	ov5640_data.pix.height = 480;
+	ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	ov5640_data.streamcap.capturemode = 0;
+	ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+	ov5640_data.streamcap.timeperframe.numerator = 1;
+
+	ov5640_regulator_enable(&client->dev);
+
+	ov5640_reset();
+
+	ov5640_power_down(0);
+
+	retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+	if (retval < 0 || chip_id_high != 0x56) {
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		ov5640_regulator_disable();
+		pr_warning("camera ov5640 is not found\n");
+		return -ENODEV;
+	}
+	retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+	if (retval < 0 || chip_id_low != 0x40) {
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		ov5640_regulator_disable();
+		pr_warning("camera ov5640 is not found\n");
+		return -ENODEV;
+	}
+
+	ov5640_power_down(1);
+
+	clk_disable_unprepare(ov5640_data.sensor_clk);
+
+	ov5640_int_device.priv = &ov5640_data;
+	retval = v4l2_int_device_register(&ov5640_int_device);
+
+	pr_info("camera ov5640 is found\n");
+	return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+	v4l2_int_device_unregister(&ov5640_int_device);
+	ov5640_regulator_disable();
+
+	return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ov5640_mipi.c
@@ -0,0 +1,2157 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fsl_devices.h>
+#include <linux/mipi_csi2.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define OV5640_VOLTAGE_ANALOG               2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE         1500000
+#define OV5640_VOLTAGE_DIGITAL_IO           1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE	0x300A
+#define OV5640_CHIP_ID_LOW_BYTE		0x300B
+
+enum ov5640_mode {
+	ov5640_mode_MIN = 0,
+	ov5640_mode_VGA_640_480 = 0,
+	ov5640_mode_QVGA_320_240 = 1,
+	ov5640_mode_NTSC_720_480 = 2,
+	ov5640_mode_PAL_720_576 = 3,
+	ov5640_mode_720P_1280_720 = 4,
+	ov5640_mode_1080P_1920_1080 = 5,
+	ov5640_mode_QSXGA_2592_1944 = 6,
+	ov5640_mode_QCIF_176_144 = 7,
+	ov5640_mode_XGA_1024_768 = 8,
+	ov5640_mode_MAX = 8,
+	ov5640_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov5640_frame_rate {
+	ov5640_15_fps,
+	ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+	[ov5640_15_fps] = 15,
+	[ov5640_30_fps] = 30,
+};
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5640_downsize_mode {
+	SUBSAMPLING,
+	SCALING,
+};
+
+struct reg_value {
+	u16 u16RegAddr;
+	u8 u8Val;
+	u8 u8Mask;
+	u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+	enum ov5640_mode mode;
+	enum ov5640_downsize_mode dn_mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct sensor_data ov5640_data;
+static int pwn_gpio, rst_gpio;
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+
+	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
+	{0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
+	{0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
+	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
+	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
+	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
+	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
+	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
+	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
+	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
+	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
+	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
+	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
+	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
+	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
+	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
+	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
+	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
+	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
+	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
+	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
+	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
+	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
+	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
+	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
+	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
+	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
+	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
+	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
+	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
+	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
+	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
+	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
+	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
+	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
+	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
+	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
+	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
+	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
+	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
+	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
+	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
+	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
+	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
+	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
+	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
+	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
+	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
+	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
+	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
+	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
+	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+
+	{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+
+	{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
+	{0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
+	{0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0},
+	{0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+	{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+	{0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+	{0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+	{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+	{0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+	{0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+	{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+	{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+	{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
+	{0x3008, 0x02, 0, 0}, {0x3503, 0,    0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+	{0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+	{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+	{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+	{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+	{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+	{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+	{0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+	{0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+	{0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+	{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
+	{0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+	{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+	{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+	{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+	{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+	{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+	{0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+	{0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+	{0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+	{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+	{0x4202, 0x0f, 0, 0},	/* stream off the sensor */
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+	{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+	{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+	{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
+	{0x4202, 0x00, 0, 0},	/* stream on the sensor */
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+	{
+		{ov5640_mode_VGA_640_480, SUBSAMPLING, 640,  480,
+		ov5640_setting_15fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240, SUBSAMPLING, 320,  240,
+		ov5640_setting_15fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+		ov5640_setting_15fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576,
+		ov5640_setting_15fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+		ov5640_setting_15fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+		ov5640_setting_15fps_1080P_1920_1080,
+		ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+		{ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
+		ov5640_setting_15fps_QSXGA_2592_1944,
+		ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+		{ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
+		ov5640_setting_15fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768,
+		ov5640_setting_15fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+	},
+	{
+		{ov5640_mode_VGA_640_480, SUBSAMPLING, 640,  480,
+		ov5640_setting_30fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240, SUBSAMPLING, 320,  240,
+		ov5640_setting_30fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+		ov5640_setting_30fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576,
+		ov5640_setting_30fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+		ov5640_setting_30fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+		ov5640_setting_30fps_1080P_1920_1080,
+		ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
+		{ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
+		{ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
+		ov5640_setting_30fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768,
+		ov5640_setting_30fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+	},
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ov5640_of_match[] = {
+	{ .compatible = "ovti,ov564x_mipi",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ov5640_of_match);
+#endif
+
+static const struct i2c_device_id ov5640_id[] = {
+	{"ov564x_mipi", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+	.driver = {
+		  .owner = THIS_MODULE,
+		  .name  = "ov564x_mipi",
+#ifdef CONFIG_OF
+		  .of_match_table = of_match_ptr(ov5640_of_match),
+#endif
+		  },
+	.probe  = ov5640_probe,
+	.remove = ov5640_remove,
+	.id_table = ov5640_id,
+};
+
+static void ov5640_standby(s32 enable)
+{
+	if (enable)
+		gpio_set_value(pwn_gpio, 1);
+	else
+		gpio_set_value(pwn_gpio, 0);
+
+	msleep(100);
+}
+
+static void ov5640_reset(void)
+{
+	/* camera reset */
+	gpio_set_value(rst_gpio, 1);
+
+	/* camera power dowmn */
+	gpio_set_value(pwn_gpio, 1);
+	msleep(5);
+
+	gpio_set_value(pwn_gpio, 0);
+	msleep(5);
+
+	gpio_set_value(rst_gpio, 0);
+	msleep(1);
+
+	gpio_set_value(rst_gpio, 1);
+	msleep(5);
+
+	gpio_set_value(pwn_gpio, 1);
+}
+
+static int ov5640_power_on(struct device *dev)
+{
+	int ret = 0;
+
+	io_regulator = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(io_regulator)) {
+		regulator_set_voltage(io_regulator,
+				      OV5640_VOLTAGE_DIGITAL_IO,
+				      OV5640_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(io_regulator);
+		if (ret) {
+			pr_err("%s:io set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:io set voltage ok\n", __func__);
+		}
+	} else {
+		pr_err("%s: cannot get io voltage error\n", __func__);
+		io_regulator = NULL;
+	}
+
+	core_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(core_regulator)) {
+		regulator_set_voltage(core_regulator,
+				      OV5640_VOLTAGE_DIGITAL_CORE,
+				      OV5640_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(core_regulator);
+		if (ret) {
+			pr_err("%s:core set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:core set voltage ok\n", __func__);
+		}
+	} else {
+		core_regulator = NULL;
+		pr_err("%s: cannot get core voltage error\n", __func__);
+	}
+
+	analog_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(analog_regulator)) {
+		regulator_set_voltage(analog_regulator,
+				      OV5640_VOLTAGE_ANALOG,
+				      OV5640_VOLTAGE_ANALOG);
+		ret = regulator_enable(analog_regulator);
+		if (ret) {
+			pr_err("%s:analog set voltage error\n",
+				__func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:analog set voltage ok\n", __func__);
+		}
+	} else {
+		analog_regulator = NULL;
+		pr_err("%s: cannot get analog voltage error\n", __func__);
+	}
+
+	return ret;
+}
+
+static void ov5640_power_off(void)
+{
+	if (analog_regulator)
+		regulator_disable(analog_regulator);
+
+	if (core_regulator)
+		regulator_disable(core_regulator);
+
+	if (io_regulator)
+		regulator_disable(io_regulator);
+
+	if (gpo_regulator)
+		regulator_disable(gpo_regulator);
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+	u8 au8Buf[3] = {0};
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+		pr_err("%s:write reg error:reg=%x,val=%x\n",
+			__func__, reg, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+		pr_err("%s:write reg error:reg=%x\n",
+				__func__, reg);
+		return -1;
+	}
+
+	if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+		pr_err("%s:read reg error:reg=%x,val=%x\n",
+				__func__, reg, u8RdVal);
+		return -1;
+	}
+
+	*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+static int prev_sysclk, prev_HTS;
+static int AE_low, AE_high, AE_Target = 52;
+
+static void OV5640_stream_on(void)
+{
+	ov5640_write_reg(0x4202, 0x00);
+}
+
+static void OV5640_stream_off(void)
+{
+	ov5640_write_reg(0x4202, 0x0f);
+}
+
+
+static int OV5640_get_sysclk(void)
+{
+	 /* calculate sysclk */
+	int xvclk = ov5640_data.mclk / 10000;
+	int temp1, temp2;
+	int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv;
+	int Bit_div2x = 1, sclk_rdiv, sysclk;
+	u8 temp;
+
+	int sclk_rdiv_map[] = {1, 2, 4, 8};
+
+	temp1 = ov5640_read_reg(0x3034, &temp);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10)
+		Bit_div2x = temp2 / 2;
+
+	temp1 = ov5640_read_reg(0x3035, &temp);
+	SysDiv = temp1>>4;
+	if (SysDiv == 0)
+		SysDiv = 16;
+
+	temp1 = ov5640_read_reg(0x3036, &temp);
+	Multiplier = temp1;
+
+	temp1 = ov5640_read_reg(0x3037, &temp);
+	PreDiv = temp1 & 0x0f;
+	Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov5640_read_reg(0x3108, &temp);
+	temp2 = temp1 & 0x03;
+	sclk_rdiv = sclk_rdiv_map[temp2];
+
+	VCO = xvclk * Multiplier / PreDiv;
+
+	sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+	return sysclk;
+}
+
+static void OV5640_set_night_mode(void)
+{
+	 /* read HTS from register settings */
+	u8 mode;
+
+	ov5640_read_reg(0x3a00, &mode);
+	mode &= 0xfb;
+	ov5640_write_reg(0x3a00, mode);
+}
+
+static int OV5640_get_HTS(void)
+{
+	 /* read HTS from register settings */
+	int HTS;
+	u8 temp;
+
+	HTS = ov5640_read_reg(0x380c, &temp);
+	HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+
+	return HTS;
+}
+
+static int OV5640_get_VTS(void)
+{
+	 /* read VTS from register settings */
+	int VTS;
+	u8 temp;
+
+	/* total vertical size[15:8] high byte */
+	VTS = ov5640_read_reg(0x380e, &temp);
+
+	VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+	return VTS;
+}
+
+static int OV5640_set_VTS(int VTS)
+{
+	 /* write VTS to registers */
+	 int temp;
+
+	 temp = VTS & 0xff;
+	 ov5640_write_reg(0x380f, temp);
+
+	 temp = VTS>>8;
+	 ov5640_write_reg(0x380e, temp);
+
+	 return 0;
+}
+
+static int OV5640_get_shutter(void)
+{
+	 /* read shutter, in number of line period */
+	int shutter;
+	u8 temp;
+
+	shutter = (ov5640_read_reg(0x03500, &temp) & 0x0f);
+	shutter = (shutter<<8) + ov5640_read_reg(0x3501, &temp);
+	shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &temp)>>4);
+
+	 return shutter;
+}
+
+static int OV5640_set_shutter(int shutter)
+{
+	 /* write shutter, in number of line period */
+	 int temp;
+
+	 shutter = shutter & 0xffff;
+
+	 temp = shutter & 0x0f;
+	 temp = temp<<4;
+	 ov5640_write_reg(0x3502, temp);
+
+	 temp = shutter & 0xfff;
+	 temp = temp>>4;
+	 ov5640_write_reg(0x3501, temp);
+
+	 temp = shutter>>12;
+	 ov5640_write_reg(0x3500, temp);
+
+	 return 0;
+}
+
+static int OV5640_get_gain16(void)
+{
+	 /* read gain, 16 = 1x */
+	int gain16;
+	u8 temp;
+
+	gain16 = ov5640_read_reg(0x350a, &temp) & 0x03;
+	gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &temp);
+
+	return gain16;
+}
+
+static int OV5640_set_gain16(int gain16)
+{
+	/* write gain, 16 = 1x */
+	u8 temp;
+	gain16 = gain16 & 0x3ff;
+
+	temp = gain16 & 0xff;
+	ov5640_write_reg(0x350b, temp);
+
+	temp = gain16>>8;
+	ov5640_write_reg(0x350a, temp);
+
+	return 0;
+}
+
+static int OV5640_get_light_freq(void)
+{
+	/* get banding filter value */
+	int temp, temp1, light_freq = 0;
+	u8 tmp;
+
+	temp = ov5640_read_reg(0x3c01, &tmp);
+
+	if (temp & 0x80) {
+		/* manual */
+		temp1 = ov5640_read_reg(0x3c00, &tmp);
+		if (temp1 & 0x04) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+			light_freq = 60;
+		}
+	} else {
+		/* auto */
+		temp1 = ov5640_read_reg(0x3c0c, &tmp);
+		if (temp1 & 0x01) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+		}
+	}
+	return light_freq;
+}
+
+static void OV5640_set_bandingfilter(void)
+{
+	int prev_VTS;
+	int band_step60, max_band60, band_step50, max_band50;
+
+	/* read preview PCLK */
+	prev_sysclk = OV5640_get_sysclk();
+	/* read preview HTS */
+	prev_HTS = OV5640_get_HTS();
+
+	/* read preview VTS */
+	prev_VTS = OV5640_get_VTS();
+
+	/* calculate banding filter */
+	/* 60Hz */
+	band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+	ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+	ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+	max_band60 = (int)((prev_VTS-4)/band_step60);
+	ov5640_write_reg(0x3a0d, max_band60);
+
+	/* 50Hz */
+	band_step50 = prev_sysclk * 100/prev_HTS;
+	ov5640_write_reg(0x3a08, (band_step50 >> 8));
+	ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+	max_band50 = (int)((prev_VTS-4)/band_step50);
+	ov5640_write_reg(0x3a0e, max_band50);
+}
+
+static int OV5640_set_AE_target(int target)
+{
+	/* stable in high */
+	int fast_high, fast_low;
+	AE_low = target * 23 / 25;	/* 0.92 */
+	AE_high = target * 27 / 25;	/* 1.08 */
+
+	fast_high = AE_high<<1;
+	if (fast_high > 255)
+		fast_high = 255;
+
+	fast_low = AE_low >> 1;
+
+	ov5640_write_reg(0x3a0f, AE_high);
+	ov5640_write_reg(0x3a10, AE_low);
+	ov5640_write_reg(0x3a1b, AE_high);
+	ov5640_write_reg(0x3a1e, AE_low);
+	ov5640_write_reg(0x3a11, fast_high);
+	ov5640_write_reg(0x3a1f, fast_low);
+
+	return 0;
+}
+
+static void OV5640_turn_on_AE_AG(int enable)
+{
+	u8 ae_ag_ctrl;
+
+	ov5640_read_reg(0x3503, &ae_ag_ctrl);
+	if (enable) {
+		/* turn on auto AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+	} else {
+		/* turn off AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl | 0x03;
+	}
+	ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+static bool binning_on(void)
+{
+	u8 temp;
+	ov5640_read_reg(0x3821, &temp);
+	temp &= 0xfe;
+	if (temp)
+		return true;
+	else
+		return false;
+}
+
+static void ov5640_set_virtual_channel(int channel)
+{
+	u8 channel_id;
+
+	ov5640_read_reg(0x4814, &channel_id);
+	channel_id &= ~(3 << 6);
+	ov5640_write_reg(0x4814, channel_id | (channel << 6));
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+	register u32 Delay_ms = 0;
+	register u16 RegAddr = 0;
+	register u8 Mask = 0;
+	register u8 Val = 0;
+	u8 RegVal = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+		Delay_ms = pModeSetting->u32Delay_ms;
+		RegAddr = pModeSetting->u16RegAddr;
+		Val = pModeSetting->u8Val;
+		Mask = pModeSetting->u8Mask;
+
+		if (Mask) {
+			retval = ov5640_read_reg(RegAddr, &RegVal);
+			if (retval < 0)
+				goto err;
+
+			RegVal &= ~(u8)Mask;
+			Val &= Mask;
+			Val |= RegVal;
+		}
+
+		retval = ov5640_write_reg(RegAddr, Val);
+		if (retval < 0)
+			goto err;
+
+		if (Delay_ms)
+			msleep(Delay_ms);
+	}
+err:
+	return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+				enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	u8 average;
+	int prev_shutter, prev_gain16;
+	int cap_shutter, cap_gain16;
+	int cap_sysclk, cap_HTS, cap_VTS;
+	int light_freq, cap_bandfilt, cap_maxband;
+	long cap_gain16_shutter;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* auto focus */
+	/* OV5640_auto_focus();//if no af function, just skip it */
+
+	/* turn off AE/AG */
+	OV5640_turn_on_AE_AG(0);
+
+	/* read preview shutter */
+	prev_shutter = OV5640_get_shutter();
+	if ((binning_on()) && (mode != ov5640_mode_720P_1280_720)
+			&& (mode != ov5640_mode_1080P_1920_1080))
+		prev_shutter *= 2;
+
+	/* read preview gain */
+	prev_gain16 = OV5640_get_gain16();
+
+	/* get average */
+	ov5640_read_reg(0x56a1, &average);
+
+	/* turn off night mode for capture */
+	OV5640_set_night_mode();
+
+	/* turn off overlay */
+	/* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */
+
+	OV5640_stream_off();
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* read capture VTS */
+	cap_VTS = OV5640_get_VTS();
+	cap_HTS = OV5640_get_HTS();
+	cap_sysclk = OV5640_get_sysclk();
+
+	/* calculate capture banding filter */
+	light_freq = OV5640_get_light_freq();
+	if (light_freq == 60) {
+		/* 60Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+	} else {
+		/* 50Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+	}
+	cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+
+	/* calculate capture shutter/gain16 */
+	if (average > AE_low && average < AE_high) {
+		/* in stable range */
+		cap_gain16_shutter =
+		  prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+		  * prev_HTS/cap_HTS * AE_Target / average;
+	} else {
+		cap_gain16_shutter =
+		  prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+		  * prev_HTS/cap_HTS;
+	}
+
+	/* gain to shutter */
+	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+		/* shutter < 1/100 */
+		cap_shutter = cap_gain16_shutter/16;
+		if (cap_shutter < 1)
+			cap_shutter = 1;
+
+		cap_gain16 = cap_gain16_shutter/cap_shutter;
+		if (cap_gain16 < 16)
+			cap_gain16 = 16;
+	} else {
+		if (cap_gain16_shutter >
+				(cap_bandfilt * cap_maxband * 16)) {
+			/* exposure reach max */
+			cap_shutter = cap_bandfilt * cap_maxband;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		} else {
+			/* 1/100 < (cap_shutter = n/100) =< max */
+			cap_shutter =
+			  ((int) (cap_gain16_shutter/16 / cap_bandfilt))
+			  *cap_bandfilt;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		}
+	}
+
+	/* write capture gain */
+	OV5640_set_gain16(cap_gain16);
+
+	/* write capture shutter */
+	if (cap_shutter > (cap_VTS - 4)) {
+		cap_VTS = cap_shutter + 4;
+		OV5640_set_VTS(cap_VTS);
+	}
+	OV5640_set_shutter(cap_shutter);
+
+	OV5640_stream_on();
+
+err:
+	return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+				enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* turn off AE/AG */
+	OV5640_turn_on_AE_AG(0);
+
+	OV5640_stream_off();
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	OV5640_stream_on();
+
+	OV5640_turn_on_AE_AG(1);
+
+err:
+	return retval;
+}
+
+static int ov5640_init_mode(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode, enum ov5640_mode orig_mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+	void *mipi_csi2_info;
+	u32 mipi_reg, msec_wait4stable = 0;
+	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
+
+	if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN)
+		&& (mode != ov5640_mode_INIT)) {
+		pr_err("Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	/* initial mipi dphy */
+	if (!mipi_csi2_info) {
+		printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+		       __func__, __FILE__);
+		return -1;
+	}
+
+	if (!mipi_csi2_get_status(mipi_csi2_info))
+		mipi_csi2_enable(mipi_csi2_info);
+
+	if (!mipi_csi2_get_status(mipi_csi2_info)) {
+		pr_err("Can not enable mipi csi2 driver!\n");
+		return -1;
+	}
+
+	mipi_csi2_set_lanes(mipi_csi2_info);
+
+	/*Only reset MIPI CSI2 HW at sensor initialize*/
+	if (mode == ov5640_mode_INIT)
+		mipi_csi2_reset(mipi_csi2_info);
+
+	if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+		mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_YUV422);
+	else if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+		mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RGB565);
+	else
+		pr_err("currently this sensor format can not be supported!\n");
+
+	dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode;
+	orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode;
+	if (mode == ov5640_mode_INIT) {
+		pModeSetting = ov5640_init_setting_30fps_VGA;
+		ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+		ov5640_data.pix.width = 640;
+		ov5640_data.pix.height = 480;
+		retval = ov5640_download_firmware(pModeSetting, ArySize);
+		if (retval < 0)
+			goto err;
+
+		pModeSetting = ov5640_setting_30fps_VGA_640_480;
+		ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);
+		retval = ov5640_download_firmware(pModeSetting, ArySize);
+	} else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
+			(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
+		/* change between subsampling and scaling
+		 * go through exposure calucation */
+		retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+	} else {
+		/* change inside subsampling or scaling
+		 * download firmware directly */
+		retval = ov5640_change_mode_direct(frame_rate, mode);
+	}
+
+	if (retval < 0)
+		goto err;
+
+	OV5640_set_AE_target(AE_Target);
+	OV5640_get_light_freq();
+	OV5640_set_bandingfilter();
+	ov5640_set_virtual_channel(ov5640_data.csi);
+
+	/* add delay to wait for sensor stable */
+	if (mode == ov5640_mode_QSXGA_2592_1944) {
+		/* dump the first two frames: 1/7.5*2
+		 * the frame rate of QSXGA is 7.5fps */
+		msec_wait4stable = 267;
+	} else if (frame_rate == ov5640_15_fps) {
+		/* dump the first nine frames: 1/15*9 */
+		msec_wait4stable = 600;
+	} else if (frame_rate == ov5640_30_fps) {
+		/* dump the first nine frames: 1/30*9 */
+		msec_wait4stable = 300;
+	}
+	msleep(msec_wait4stable);
+
+	if (mipi_csi2_info) {
+		unsigned int i;
+
+		i = 0;
+
+		/* wait for mipi sensor ready */
+		mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);
+		while ((mipi_reg == 0x200) && (i < 10)) {
+			mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);
+			i++;
+			msleep(10);
+		}
+
+		if (i >= 10) {
+			pr_err("mipi csi2 can not receive sensor clk!\n");
+			return -1;
+		}
+
+		i = 0;
+
+		/* wait for mipi stable */
+		mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);
+		while ((mipi_reg != 0x0) && (i < 10)) {
+			mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);
+			i++;
+			msleep(10);
+		}
+
+		if (i >= 10) {
+			pr_err("mipi csi2 can not reveive data correctly!\n");
+			return -1;
+		}
+	}
+err:
+	return retval;
+}
+
+/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+	if (s == NULL) {
+		pr_err("   ERROR!! no slave device set!\n");
+		return -1;
+	}
+
+	memset(p, 0, sizeof(*p));
+	p->u.bt656.clock_curr = ov5640_data.mclk;
+	pr_debug("   clock_curr=mclk=%d\n", ov5640_data.mclk);
+	p->if_type = V4L2_IF_TYPE_BT656;
+	p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+	p->u.bt656.clock_min = OV5640_XCLK_MIN;
+	p->u.bt656.clock_max = OV5640_XCLK_MAX;
+	p->u.bt656.bt_sync_correct = 1;  /* Indicate external vsync */
+
+	return 0;
+}
+
+/*!
+ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+	struct sensor_data *sensor = s->priv;
+
+	if (on && !sensor->on) {
+		if (io_regulator)
+			if (regulator_enable(io_regulator) != 0)
+				return -EIO;
+		if (core_regulator)
+			if (regulator_enable(core_regulator) != 0)
+				return -EIO;
+		if (gpo_regulator)
+			if (regulator_enable(gpo_regulator) != 0)
+				return -EIO;
+		if (analog_regulator)
+			if (regulator_enable(analog_regulator) != 0)
+				return -EIO;
+		/* Make sure power on */
+		ov5640_standby(0);
+	} else if (!on && sensor->on) {
+
+		ov5640_power_off();
+
+		ov5640_standby(1);
+	}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	struct sensor_data *sensor = s->priv;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->streamcap.capability;
+		cparm->timeperframe = sensor->streamcap.timeperframe;
+		cparm->capturemode = sensor->streamcap.capturemode;
+		ret = 0;
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+	struct sensor_data *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	enum ov5640_mode orig_mode;
+	int ret = 0;
+
+	/* Make sure power on */
+	ov5640_standby(0);
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		/* Check that the new frame rate is allowed. */
+		if ((timeperframe->numerator == 0) ||
+		    (timeperframe->denominator == 0)) {
+			timeperframe->denominator = DEFAULT_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps > MAX_FPS) {
+			timeperframe->denominator = MAX_FPS;
+			timeperframe->numerator = 1;
+		} else if (tgt_fps < MIN_FPS) {
+			timeperframe->denominator = MIN_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		/* Actual frame rate we use */
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps == 15)
+			frame_rate = ov5640_15_fps;
+		else if (tgt_fps == 30)
+			frame_rate = ov5640_30_fps;
+		else {
+			pr_err(" The camera frame rate is not supported!\n");
+			return -EINVAL;
+		}
+
+		orig_mode = sensor->streamcap.capturemode;
+		ret = ov5640_init_mode(frame_rate,
+				(u32)a->parm.capture.capturemode, orig_mode);
+		if (ret < 0)
+			return ret;
+
+		sensor->streamcap.timeperframe = *timeperframe;
+		sensor->streamcap.capturemode =
+				(u32)a->parm.capture.capturemode;
+
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		pr_debug("   type is not " \
+			"V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+			a->type);
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+	struct sensor_data *sensor = s->priv;
+
+	f->fmt.pix = sensor->pix;
+
+	return 0;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array.  Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int ret = 0;
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		vc->value = ov5640_data.brightness;
+		break;
+	case V4L2_CID_HUE:
+		vc->value = ov5640_data.hue;
+		break;
+	case V4L2_CID_CONTRAST:
+		vc->value = ov5640_data.contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		vc->value = ov5640_data.saturation;
+		break;
+	case V4L2_CID_RED_BALANCE:
+		vc->value = ov5640_data.red;
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		vc->value = ov5640_data.blue;
+		break;
+	case V4L2_CID_EXPOSURE:
+		vc->value = ov5640_data.ae_mode;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array).  Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+	int retval = 0;
+
+	pr_debug("In ov5640:ioctl_s_ctrl %d\n",
+		 vc->id);
+
+	switch (vc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		break;
+	case V4L2_CID_CONTRAST:
+		break;
+	case V4L2_CID_SATURATION:
+		break;
+	case V4L2_CID_HUE:
+		break;
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		break;
+	case V4L2_CID_DO_WHITE_BALANCE:
+		break;
+	case V4L2_CID_RED_BALANCE:
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		break;
+	case V4L2_CID_GAMMA:
+		break;
+	case V4L2_CID_EXPOSURE:
+		break;
+	case V4L2_CID_AUTOGAIN:
+		break;
+	case V4L2_CID_GAIN:
+		break;
+	case V4L2_CID_HFLIP:
+		break;
+	case V4L2_CID_VFLIP:
+		break;
+	default:
+		retval = -EPERM;
+		break;
+	}
+
+	return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+				 struct v4l2_frmsizeenum *fsize)
+{
+	if (fsize->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fsize->pixel_format = ov5640_data.pix.pixelformat;
+	fsize->discrete.width =
+			max(ov5640_mode_info_data[0][fsize->index].width,
+			    ov5640_mode_info_data[1][fsize->index].width);
+	fsize->discrete.height =
+			max(ov5640_mode_info_data[0][fsize->index].height,
+			    ov5640_mode_info_data[1][fsize->index].height);
+	return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+					 struct v4l2_frmivalenum *fival)
+{
+	int i, j, count = 0;
+
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete.numerator = 1;
+
+	for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++)
+		for (j = 0; j < (ov5640_mode_MAX + 1); j++)
+			if (fival->pixel_format == ov5640_data.pix.pixelformat
+			 && fival->width == ov5640_mode_info_data[i][j].width
+			 && fival->height == ov5640_mode_info_data[i][j].height
+			 && ov5640_mode_info_data[i][j].init_data_ptr != NULL
+			 && fival->index == count++) {
+				fival->discrete.denominator =
+						ov5640_framerates[i];
+				return 0;
+			}
+
+	return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ *			VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+	((struct v4l2_dbg_chip_ident *)id)->match.type =
+					V4L2_CHIP_MATCH_I2C_DRIVER;
+	strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
+		"ov5640_mipi_camera");
+
+	return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+
+	return 0;
+}
+
+/*!
+ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: pointer to standard V4L2 fmt description structure
+ *
+ * Return 0.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+			      struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fmt->pixelformat = ov5640_data.pix.pixelformat;
+
+	return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	struct sensor_data *sensor = s->priv;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	int ret;
+	enum ov5640_frame_rate frame_rate;
+	void *mipi_csi2_info;
+
+	ov5640_data.on = true;
+
+	/* mclk */
+	tgt_xclk = ov5640_data.mclk;
+	tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+	ov5640_data.mclk = tgt_xclk;
+
+	pr_debug("   Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+	/* Default camera frame rate is set in probe */
+	tgt_fps = sensor->streamcap.timeperframe.denominator /
+		  sensor->streamcap.timeperframe.numerator;
+
+	if (tgt_fps == 15)
+		frame_rate = ov5640_15_fps;
+	else if (tgt_fps == 30)
+		frame_rate = ov5640_30_fps;
+	else
+		return -EINVAL; /* Only support 15fps or 30fps now. */
+
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	/* enable mipi csi2 */
+	if (mipi_csi2_info)
+		mipi_csi2_enable(mipi_csi2_info);
+	else {
+		printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+		       __func__, __FILE__);
+		return -EPERM;
+	}
+
+	ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT);
+
+	return ret;
+}
+
+/*!
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the device when slave detaches to the master.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+	void *mipi_csi2_info;
+
+	mipi_csi2_info = mipi_csi2_get_info();
+
+	/* disable mipi csi2 */
+	if (mipi_csi2_info)
+		if (mipi_csi2_get_status(mipi_csi2_info))
+			mipi_csi2_disable(mipi_csi2_info);
+
+	return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module and links them to the
+ * enumeration.
+ */
+static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = {
+	{vidioc_int_dev_init_num, (v4l2_int_ioctl_func *) ioctl_dev_init},
+	{vidioc_int_dev_exit_num, ioctl_dev_exit},
+	{vidioc_int_s_power_num, (v4l2_int_ioctl_func *) ioctl_s_power},
+	{vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *) ioctl_g_ifparm},
+/*	{vidioc_int_g_needs_reset_num,
+				(v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
+/*	{vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
+	{vidioc_int_init_num, (v4l2_int_ioctl_func *) ioctl_init},
+	{vidioc_int_enum_fmt_cap_num,
+				(v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
+/*	{vidioc_int_try_fmt_cap_num,
+				(v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
+	{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
+/*	{vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, */
+	{vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
+	{vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
+/*	{vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */
+	{vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl},
+	{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
+	{vidioc_int_enum_framesizes_num,
+				(v4l2_int_ioctl_func *) ioctl_enum_framesizes},
+	{vidioc_int_enum_frameintervals_num,
+			(v4l2_int_ioctl_func *) ioctl_enum_frameintervals},
+	{vidioc_int_g_chip_ident_num,
+				(v4l2_int_ioctl_func *) ioctl_g_chip_ident},
+};
+
+static struct v4l2_int_slave ov5640_slave = {
+	.ioctls = ov5640_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov5640_int_device = {
+	.module = THIS_MODULE,
+	.name = "ov564x",
+	.type = v4l2_int_type_slave,
+	.u = {
+		.slave = &ov5640_slave,
+	},
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter            struct i2c_adapter *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	int retval;
+	u8 chip_id_high, chip_id_low;
+
+	/* request power down pin */
+	pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(pwn_gpio)) {
+		dev_warn(dev, "no sensor pwdn pin available");
+		return -EINVAL;
+	}
+	retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_mipi_pwdn");
+	if (retval < 0)
+		return retval;
+
+	/* request reset pin */
+	rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+	if (!gpio_is_valid(rst_gpio)) {
+		dev_warn(dev, "no sensor reset pin available");
+		return -EINVAL;
+	}
+	retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_mipi_reset");
+	if (retval < 0)
+		return retval;
+
+	/* Set initial values for the sensor struct. */
+	memset(&ov5640_data, 0, sizeof(ov5640_data));
+	ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(ov5640_data.sensor_clk)) {
+		/* assuming clock enabled by default */
+		ov5640_data.sensor_clk = NULL;
+		dev_err(dev, "clock-frequency missing or invalid\n");
+		return PTR_ERR(ov5640_data.sensor_clk);
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk",
+					&(ov5640_data.mclk));
+	if (retval) {
+		dev_err(dev, "mclk missing or invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk_source",
+					(u32 *) &(ov5640_data.mclk_source));
+	if (retval) {
+		dev_err(dev, "mclk_source missing or invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "csi_id",
+					&(ov5640_data.csi));
+	if (retval) {
+		dev_err(dev, "csi id missing or invalid\n");
+		return retval;
+	}
+
+	clk_prepare_enable(ov5640_data.sensor_clk);
+
+	ov5640_data.io_init = ov5640_reset;
+	ov5640_data.i2c_client = client;
+	ov5640_data.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+	ov5640_data.pix.width = 640;
+	ov5640_data.pix.height = 480;
+	ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	ov5640_data.streamcap.capturemode = 0;
+	ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+	ov5640_data.streamcap.timeperframe.numerator = 1;
+
+	ov5640_power_on(dev);
+
+	ov5640_reset();
+
+	ov5640_standby(0);
+
+	retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+	if (retval < 0 || chip_id_high != 0x56) {
+		pr_warning("camera ov5640_mipi is not found\n");
+		ov5640_power_off();
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		return -ENODEV;
+	}
+	retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+	if (retval < 0 || chip_id_low != 0x40) {
+		pr_warning("camera ov5640_mipi is not found\n");
+		ov5640_power_off();
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		return -ENODEV;
+	}
+
+	ov5640_standby(1);
+
+	ov5640_int_device.priv = &ov5640_data;
+	retval = v4l2_int_device_register(&ov5640_int_device);
+
+	clk_disable_unprepare(ov5640_data.sensor_clk);
+
+	pr_info("camera ov5640_mipi is found\n");
+	return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+	v4l2_int_device_unregister(&ov5640_int_device);
+
+	ov5640_power_off();
+
+	return 0;
+}
+
+/*!
+ * ov5640 init function
+ * Called by insmod ov5640_camera.ko.
+ *
+ * @return  Error code indicating success or failure
+ */
+static __init int ov5640_init(void)
+{
+	u8 err;
+
+	err = i2c_add_driver(&ov5640_i2c_driver);
+	if (err != 0)
+		pr_err("%s:driver registration failed, error=%d\n",
+			__func__, err);
+
+	return err;
+}
+
+/*!
+ * OV5640 cleanup function
+ * Called on rmmod ov5640_camera.ko
+ *
+ * @return  Error code indicating success or failure
+ */
+static void __exit ov5640_clean(void)
+{
+	i2c_del_driver(&ov5640_i2c_driver);
+}
+
+module_init(ov5640_init);
+module_exit(ov5640_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ov5640_mipi_v2.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ov5640_mipi_v2.c
@@ -0,0 +1,1868 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Copyright 2018-2019 NXP
+ *
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG               2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE         1500000
+#define OV5640_VOLTAGE_DIGITAL_IO           1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+#define OV5640_XCLK_20MHZ 20000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE	0x300A
+#define OV5640_CHIP_ID_LOW_BYTE		0x300B
+
+#define DEFAULT_SCCB_ID 0x78
+
+enum ov5640_mode {
+	ov5640_mode_MIN = 0,
+	ov5640_mode_VGA_640_480 = 0,
+	ov5640_mode_QVGA_320_240 = 1,
+	ov5640_mode_NTSC_720_480 = 2,
+	ov5640_mode_720P_1280_720 = 3,
+	ov5640_mode_1080P_1920_1080 = 4,
+	ov5640_mode_QSXGA_2592_1944 = 5,
+	ov5640_mode_MAX = 5,
+	ov5640_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov5640_frame_rate {
+	ov5640_15_fps,
+	ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+	[ov5640_15_fps] = 15,
+	[ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+	u32	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5640_downsize_mode {
+	SUBSAMPLING,
+	SCALING,
+};
+
+struct reg_value {
+	u16 u16RegAddr;
+	u8 u8Val;
+	u8 u8Mask;
+	u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+	enum ov5640_mode mode;
+	enum ov5640_downsize_mode dn_mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+struct ov5640 {
+	struct v4l2_subdev		subdev;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	const struct ov5640_datafmt	*fmt;
+	struct v4l2_captureparm streamcap;
+	bool on;
+
+	/* control settings */
+	int brightness;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	u32 mclk;
+	u8 mclk_source;
+	struct clk *sensor_clk;
+	int csi;
+
+	void (*io_init)(struct ov5640 *);
+	int pwn_gpio, rst_gpio;
+};
+
+struct ov5640_res {
+	int width;
+	int height;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+
+
+struct ov5640_res ov5640_valid_res[] = {
+	[0] = {640, 480},
+	[1] = {320, 240},
+	[2] = {720, 480},
+	[3] = {1280, 720},
+	[4] = {1920, 1080},
+	[5] = {2592, 1944},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+
+	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
+	{0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
+	{0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x30, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
+	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
+	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
+	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
+	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
+	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
+	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
+	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
+	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
+	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
+	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
+	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
+	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
+	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
+	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
+	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
+	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
+	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
+	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
+	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
+	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
+	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
+	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
+	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
+	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
+	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
+	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
+	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
+	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
+	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
+	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
+	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
+	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
+	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
+	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
+	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
+	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
+	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
+	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
+	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
+	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
+	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
+	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
+	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
+	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
+	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
+	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
+	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
+	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
+	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x42, 0, 0}, {0x3c00, 0x04, 0, 300},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+	{0x380b, 0xF0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
+	{0x3008, 0x02, 0, 0}, {0x3503, 0,    0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+	{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+	{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+	{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+	{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+	{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+	{0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+	{0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+	{0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+	{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
+	{0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/
+	{0x3035, 0x11, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+	{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+	{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+	{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, {0x3008, 0x02, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+	{
+		{ov5640_mode_VGA_640_480, -1, 0, 0, NULL, 0},
+		{ov5640_mode_QVGA_320_240, -1, 0, 0, NULL, 0},
+		{ov5640_mode_NTSC_720_480, -1, 0, 0, NULL, 0},
+		{ov5640_mode_720P_1280_720, -1, 0, 0, NULL, 0},
+		{ov5640_mode_1080P_1920_1080, -1, 0, 0, NULL, 0},
+		{ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
+		ov5640_setting_15fps_QSXGA_2592_1944,
+		ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+	},
+	{
+		{ov5640_mode_VGA_640_480, SUBSAMPLING, 640,  480,
+		ov5640_setting_30fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240, SUBSAMPLING, 320,  240,
+		ov5640_setting_30fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+		ov5640_setting_30fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+		{ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+		ov5640_setting_30fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+		ov5640_setting_30fps_1080P_1920_1080,
+		ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
+		{ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
+	},
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+static DEFINE_MUTEX(ov5640_mutex);
+
+static int ov5640_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val);
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val);
+#ifdef CONFIG_OF
+static const struct of_device_id ov5640_mipi_v2_of_match[] = {
+	{ .compatible = "ovti,ov5640_mipi",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ov5640_mipi_v2_of_match);
+#endif
+
+static const struct i2c_device_id ov5640_id[] = {
+	{"ov5640_mipi", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+	.driver = {
+		  .owner = THIS_MODULE,
+		  .name  = "ov5640_mipi",
+#ifdef CONFIG_OF
+		  .of_match_table = of_match_ptr(ov5640_mipi_v2_of_match),
+#endif
+		  },
+	.probe  = ov5640_probe,
+	.remove = ov5640_remove,
+	.id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+	{MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static int get_capturemode(int width, int height)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov5640_valid_res); i++) {
+		if ((ov5640_valid_res[i].width == width) &&
+		     (ov5640_valid_res[i].height == height))
+			return i;
+	}
+
+	return -1;
+}
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+			*ov5640_find_datafmt(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+		if (ov5640_colour_fmts[i].code == code)
+			return ov5640_colour_fmts + i;
+
+	return NULL;
+}
+
+static inline void ov5640_power_down(struct ov5640 *sensor, int enable)
+{
+	if (sensor->pwn_gpio < 0)
+		return;
+
+	if (!enable)
+		gpio_set_value_cansleep(sensor->pwn_gpio, 0);
+	else
+		gpio_set_value_cansleep(sensor->pwn_gpio, 1);
+
+	msleep(2);
+}
+
+static int ov5640_update_slave_id(struct ov5640 *sensor)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u8 slave_id;
+	struct i2c_client *tmp_client;
+	s32 retval;
+
+	if (sensor->i2c_client->addr << 1 == DEFAULT_SCCB_ID)
+		return 0; /* nothing to do */
+
+	/* Change camera i2c slave address */
+	slave_id = (u8)(sensor->i2c_client->addr << 1); /* new slave id*/
+	tmp_client = sensor->i2c_client;
+
+	sensor->i2c_client =
+		i2c_new_dummy(tmp_client->adapter, DEFAULT_SCCB_ID >> 1);
+	if (!sensor->i2c_client) {
+		dev_err(dev, "Failed to communicate on 0x%x\n",
+			DEFAULT_SCCB_ID);
+		return -1;
+	}
+
+	retval = ov5640_write_reg(sensor, 0x3100, slave_id);
+	i2c_unregister_device(sensor->i2c_client);
+	sensor->i2c_client = tmp_client;
+	if (retval != 0) {
+		dev_err(dev, "Failed to update SCCB_ID to 0x%x\n", slave_id);
+		return -1;
+	}
+
+	ov5640_read_reg(sensor, 0x3100, &slave_id);
+	dev_dbg(dev, "Updated SCCB_ID 0x%x\n", slave_id);
+
+	return 0;
+}
+
+static void ov5640_reset(struct ov5640 *sensor)
+{
+	if (sensor->rst_gpio < 0 || sensor->pwn_gpio < 0)
+		return;
+
+	/* camera reset */
+	gpio_set_value(sensor->rst_gpio, 1);
+
+	/* camera power dowmn */
+	gpio_set_value(sensor->pwn_gpio, 1);
+	msleep(5);
+
+	gpio_set_value(sensor->rst_gpio, 0);
+	msleep(1);
+
+	gpio_set_value(sensor->pwn_gpio, 0);
+	msleep(5);
+
+	gpio_set_value(sensor->rst_gpio, 1);
+	msleep(5);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+	int ret = 0;
+
+	io_regulator = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(io_regulator)) {
+		regulator_set_voltage(io_regulator,
+				      OV5640_VOLTAGE_DIGITAL_IO,
+				      OV5640_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(io_regulator);
+		if (ret) {
+			pr_err("%s:io set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:io set voltage ok\n", __func__);
+		}
+	} else {
+		pr_err("%s: cannot get io voltage error\n", __func__);
+		io_regulator = NULL;
+	}
+
+	core_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(core_regulator)) {
+		regulator_set_voltage(core_regulator,
+				      OV5640_VOLTAGE_DIGITAL_CORE,
+				      OV5640_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(core_regulator);
+		if (ret) {
+			pr_err("%s:core set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:core set voltage ok\n", __func__);
+		}
+	} else {
+		core_regulator = NULL;
+		pr_err("%s: cannot get core voltage error\n", __func__);
+	}
+
+	analog_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(analog_regulator)) {
+		regulator_set_voltage(analog_regulator,
+				      OV5640_VOLTAGE_ANALOG,
+				      OV5640_VOLTAGE_ANALOG);
+		ret = regulator_enable(analog_regulator);
+		if (ret) {
+			pr_err("%s:analog set voltage error\n",
+				__func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:analog set voltage ok\n", __func__);
+		}
+	} else {
+		analog_regulator = NULL;
+		pr_err("%s: cannot get analog voltage error\n", __func__);
+	}
+
+	return ret;
+}
+
+static void ov5640_regualtor_disable(void)
+{
+	if (analog_regulator)
+		regulator_disable(analog_regulator);
+
+	if (core_regulator)
+		regulator_disable(core_regulator);
+
+	if (io_regulator)
+		regulator_disable(io_regulator);
+
+	if (gpo_regulator)
+		regulator_disable(gpo_regulator);
+}
+
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u8 au8Buf[3] = {0};
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	if (i2c_master_send(sensor->i2c_client, au8Buf, 3) < 0) {
+		dev_err(dev, "Write reg error: reg=%x, val=%x\n", reg, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (i2c_master_send(sensor->i2c_client, au8RegBuf, 2) != 2) {
+		dev_err(dev, "Read reg error: reg=%x\n", reg);
+		return -1;
+	}
+
+	if (i2c_master_recv(sensor->i2c_client, &u8RdVal, 1) != 1) {
+		dev_err(dev, "Read reg error: reg=%x, val=%x\n", reg, u8RdVal);
+		return -1;
+	}
+
+	*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+static int prev_sysclk, prev_HTS;
+static int AE_low, AE_high, AE_Target = 52;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5640_get_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xffff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov5640_read_reg(sensor, reg->reg, &val);
+	if (!ret)
+		reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov5640_set_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+
+	if (reg->reg & ~0xffff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov5640_write_reg(sensor, reg->reg, reg->val);
+}
+#endif
+
+static void OV5640_stream_on(struct ov5640 *sensor)
+{
+	ov5640_write_reg(sensor, 0x4202, 0x00);
+}
+
+static void OV5640_stream_off(struct ov5640 *sensor)
+{
+	ov5640_write_reg(sensor, 0x4202, 0x0f);
+	ov5640_write_reg(sensor, 0x3008, 0x42);
+}
+
+static int OV5640_get_sysclk(struct ov5640 *sensor)
+{
+	 /* calculate sysclk */
+	int xvclk = sensor->mclk / 10000;
+	int temp1, temp2;
+	int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv;
+	int Bit_div2x = 1, sclk_rdiv, sysclk;
+	u8 temp;
+
+	int sclk_rdiv_map[] = {1, 2, 4, 8};
+
+	temp1 = ov5640_read_reg(sensor, 0x3034, &temp);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10)
+		Bit_div2x = temp2 / 2;
+
+	temp1 = ov5640_read_reg(sensor, 0x3035, &temp);
+	SysDiv = temp1>>4;
+	if (SysDiv == 0)
+		SysDiv = 16;
+
+	temp1 = ov5640_read_reg(sensor, 0x3036, &temp);
+	Multiplier = temp1;
+
+	temp1 = ov5640_read_reg(sensor, 0x3037, &temp);
+	PreDiv = temp1 & 0x0f;
+	Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov5640_read_reg(sensor, 0x3108, &temp);
+	temp2 = temp1 & 0x03;
+	sclk_rdiv = sclk_rdiv_map[temp2];
+
+	VCO = xvclk * Multiplier / PreDiv;
+
+	sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+	return sysclk;
+}
+
+static void OV5640_set_night_mode(struct ov5640 *sensor)
+{
+	 /* read HTS from register settings */
+	u8 mode;
+
+	ov5640_read_reg(sensor, 0x3a00, &mode);
+	mode &= 0xfb;
+	ov5640_write_reg(sensor, 0x3a00, mode);
+}
+
+static int OV5640_get_HTS(struct ov5640 *sensor)
+{
+	 /* read HTS from register settings */
+	int HTS;
+	u8 temp;
+
+	HTS = ov5640_read_reg(sensor, 0x380c, &temp);
+	HTS = (HTS<<8) + ov5640_read_reg(sensor, 0x380d, &temp);
+
+	return HTS;
+}
+
+static int OV5640_get_VTS(struct ov5640 *sensor)
+{
+	 /* read VTS from register settings */
+	int VTS;
+	u8 temp;
+
+	/* total vertical size[15:8] high byte */
+	VTS = ov5640_read_reg(sensor, 0x380e, &temp);
+
+	VTS = (VTS<<8) + ov5640_read_reg(sensor, 0x380f, &temp);
+
+	return VTS;
+}
+
+static int OV5640_set_VTS(struct ov5640 *sensor, int VTS)
+{
+	 /* write VTS to registers */
+	 int temp;
+
+	 temp = VTS & 0xff;
+	 ov5640_write_reg(sensor, 0x380f, temp);
+
+	 temp = VTS>>8;
+	 ov5640_write_reg(sensor, 0x380e, temp);
+
+	 return 0;
+}
+
+static int OV5640_get_shutter(struct ov5640 *sensor)
+{
+	 /* read shutter, in number of line period */
+	int shutter;
+	u8 temp;
+
+	shutter = (ov5640_read_reg(sensor, 0x03500, &temp) & 0x0f);
+	shutter = (shutter<<8) + ov5640_read_reg(sensor, 0x3501, &temp);
+	shutter = (shutter<<4) + (ov5640_read_reg(sensor, 0x3502, &temp)>>4);
+
+	 return shutter;
+}
+
+static int OV5640_set_shutter(struct ov5640 *sensor, int shutter)
+{
+	 /* write shutter, in number of line period */
+	 int temp;
+
+	 shutter = shutter & 0xffff;
+
+	 temp = shutter & 0x0f;
+	 temp = temp<<4;
+	 ov5640_write_reg(sensor, 0x3502, temp);
+
+	 temp = shutter & 0xfff;
+	 temp = temp>>4;
+	 ov5640_write_reg(sensor, 0x3501, temp);
+
+	 temp = shutter>>12;
+	 ov5640_write_reg(sensor, 0x3500, temp);
+
+	 return 0;
+}
+
+
+static int OV5640_get_gain16(struct ov5640 *sensor)
+{
+	 /* read gain, 16 = 1x */
+	int gain16;
+	u8 temp;
+
+	gain16 = ov5640_read_reg(sensor, 0x350a, &temp) & 0x03;
+	gain16 = (gain16<<8) + ov5640_read_reg(sensor, 0x350b, &temp);
+
+	return gain16;
+}
+
+static int OV5640_set_gain16(struct ov5640 *sensor, int gain16)
+{
+	/* write gain, 16 = 1x */
+	u8 temp;
+	gain16 = gain16 & 0x3ff;
+
+	temp = gain16 & 0xff;
+	ov5640_write_reg(sensor, 0x350b, temp);
+
+	temp = gain16>>8;
+	ov5640_write_reg(sensor, 0x350a, temp);
+
+	return 0;
+}
+
+static int OV5640_get_light_freq(struct ov5640 *sensor)
+{
+	/* get banding filter value */
+	int temp, temp1, light_freq = 0;
+	u8 tmp;
+
+	temp = ov5640_read_reg(sensor, 0x3c01, &tmp);
+
+	if (temp & 0x80) {
+		/* manual */
+		temp1 = ov5640_read_reg(sensor, 0x3c00, &tmp);
+		if (temp1 & 0x04) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+			light_freq = 60;
+		}
+	} else {
+		/* auto */
+		temp1 = ov5640_read_reg(sensor, 0x3c0c, &tmp);
+		if (temp1 & 0x01) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+		}
+	}
+	return light_freq;
+}
+
+static void OV5640_set_bandingfilter(struct ov5640 *sensor)
+{
+	int prev_VTS;
+	int band_step60, max_band60, band_step50, max_band50;
+
+	/* read preview PCLK */
+	prev_sysclk = OV5640_get_sysclk(sensor);
+	/* read preview HTS */
+	prev_HTS = OV5640_get_HTS(sensor);
+
+	/* read preview VTS */
+	prev_VTS = OV5640_get_VTS(sensor);
+
+	/* calculate banding filter */
+	/* 60Hz */
+	band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+	ov5640_write_reg(sensor, 0x3a0a, (band_step60 >> 8));
+	ov5640_write_reg(sensor, 0x3a0b, (band_step60 & 0xff));
+
+	max_band60 = (int)((prev_VTS-4)/band_step60);
+	ov5640_write_reg(sensor, 0x3a0d, max_band60);
+
+	/* 50Hz */
+	band_step50 = prev_sysclk * 100/prev_HTS;
+	ov5640_write_reg(sensor, 0x3a08, (band_step50 >> 8));
+	ov5640_write_reg(sensor, 0x3a09, (band_step50 & 0xff));
+
+	max_band50 = (int)((prev_VTS-4)/band_step50);
+	ov5640_write_reg(sensor, 0x3a0e, max_band50);
+}
+
+static int OV5640_set_AE_target(struct ov5640 *sensor, int target)
+{
+	/* stable in high */
+	int fast_high, fast_low;
+	AE_low = target * 23 / 25;	/* 0.92 */
+	AE_high = target * 27 / 25;	/* 1.08 */
+
+	fast_high = AE_high<<1;
+	if (fast_high > 255)
+		fast_high = 255;
+
+	fast_low = AE_low >> 1;
+
+	ov5640_write_reg(sensor, 0x3a0f, AE_high);
+	ov5640_write_reg(sensor, 0x3a10, AE_low);
+	ov5640_write_reg(sensor, 0x3a1b, AE_high);
+	ov5640_write_reg(sensor, 0x3a1e, AE_low);
+	ov5640_write_reg(sensor, 0x3a11, fast_high);
+	ov5640_write_reg(sensor, 0x3a1f, fast_low);
+
+	return 0;
+}
+
+static void OV5640_turn_on_AE_AG(struct ov5640 *sensor, int enable)
+{
+	u8 ae_ag_ctrl;
+
+	ov5640_read_reg(sensor, 0x3503, &ae_ag_ctrl);
+	if (enable) {
+		/* turn on auto AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+	} else {
+		/* turn off AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl | 0x03;
+	}
+	ov5640_write_reg(sensor, 0x3503, ae_ag_ctrl);
+}
+
+static bool binning_on(struct ov5640 *sensor)
+{
+	u8 temp;
+	ov5640_read_reg(sensor, 0x3821, &temp);
+	temp &= 0xfe;
+	if (temp)
+		return true;
+	else
+		return false;
+}
+
+static void ov5640_set_virtual_channel(struct ov5640 *sensor, int channel)
+{
+	u8 channel_id;
+
+	ov5640_read_reg(sensor, 0x4814, &channel_id);
+	channel_id &= ~(3 << 6);
+	ov5640_write_reg(sensor, 0x4814, channel_id | (channel << 6));
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct ov5640 *sensor,
+				    struct reg_value *pModeSetting,
+				    s32 ArySize)
+{
+	register u32 Delay_ms = 0;
+	register u16 RegAddr = 0;
+	register u8 Mask = 0;
+	register u8 Val = 0;
+	u8 RegVal = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+		Delay_ms = pModeSetting->u32Delay_ms;
+		RegAddr = pModeSetting->u16RegAddr;
+		Val = pModeSetting->u8Val;
+		Mask = pModeSetting->u8Mask;
+
+		if (Mask) {
+			retval = ov5640_read_reg(sensor, RegAddr, &RegVal);
+			if (retval < 0)
+				goto err;
+
+			RegVal &= ~(u8)Mask;
+			Val &= Mask;
+			Val |= RegVal;
+		}
+
+		retval = ov5640_write_reg(sensor, RegAddr, Val);
+		if (retval < 0)
+			goto err;
+
+		if (Delay_ms)
+			msleep(Delay_ms);
+	}
+err:
+	return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov5640_change_mode_exposure_calc(struct ov5640 *sensor,
+				enum ov5640_frame_rate frame_rate,
+				enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	u8 average;
+	int prev_shutter, prev_gain16;
+	int cap_shutter, cap_gain16;
+	int cap_sysclk, cap_HTS, cap_VTS;
+	int light_freq, cap_bandfilt, cap_maxband;
+	long cap_gain16_shutter;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	sensor->pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* auto focus */
+	/* OV5640_auto_focus();//if no af function, just skip it */
+
+	/* turn off AE/AG */
+	OV5640_turn_on_AE_AG(sensor, 0);
+
+	/* read preview shutter */
+	prev_shutter = OV5640_get_shutter(sensor);
+	if ((binning_on(sensor)) && (mode != ov5640_mode_720P_1280_720)
+			&& (mode != ov5640_mode_1080P_1920_1080))
+		prev_shutter *= 2;
+
+	/* read preview gain */
+	prev_gain16 = OV5640_get_gain16(sensor);
+
+	/* get average */
+	ov5640_read_reg(sensor, 0x56a1, &average);
+
+	/* turn off night mode for capture */
+	OV5640_set_night_mode(sensor);
+
+	/* turn off overlay */
+	/* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */
+
+	OV5640_stream_off(sensor);
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* read capture VTS */
+	cap_VTS = OV5640_get_VTS(sensor);
+	cap_HTS = OV5640_get_HTS(sensor);
+	cap_sysclk = OV5640_get_sysclk(sensor);
+
+	/* calculate capture banding filter */
+	light_freq = OV5640_get_light_freq(sensor);
+	if (light_freq == 60) {
+		/* 60Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+	} else {
+		/* 50Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+	}
+	cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+
+	/* calculate capture shutter/gain16 */
+	if (average > AE_low && average < AE_high) {
+		/* in stable range */
+		cap_gain16_shutter =
+		  prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+		  * prev_HTS/cap_HTS * AE_Target / average;
+	} else {
+		cap_gain16_shutter =
+		  prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+		  * prev_HTS/cap_HTS;
+	}
+
+	/* gain to shutter */
+	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+		/* shutter < 1/100 */
+		cap_shutter = cap_gain16_shutter/16;
+		if (cap_shutter < 1)
+			cap_shutter = 1;
+
+		cap_gain16 = cap_gain16_shutter/cap_shutter;
+		if (cap_gain16 < 16)
+			cap_gain16 = 16;
+	} else {
+		if (cap_gain16_shutter >
+				(cap_bandfilt * cap_maxband * 16)) {
+			/* exposure reach max */
+			cap_shutter = cap_bandfilt * cap_maxband;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		} else {
+			/* 1/100 < (cap_shutter = n/100) =< max */
+			cap_shutter =
+			  ((int) (cap_gain16_shutter/16 / cap_bandfilt))
+			  *cap_bandfilt;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		}
+	}
+
+	/* write capture gain */
+	OV5640_set_gain16(sensor, cap_gain16);
+
+	/* write capture shutter */
+	if (cap_shutter > (cap_VTS - 4)) {
+		cap_VTS = cap_shutter + 4;
+		OV5640_set_VTS(sensor, cap_VTS);
+	}
+	OV5640_set_shutter(sensor, cap_shutter);
+
+err:
+	return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov5640_change_mode_direct(struct ov5640 *sensor,
+				enum ov5640_frame_rate frame_rate,
+				enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	sensor->pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* turn off AE/AG */
+	OV5640_turn_on_AE_AG(sensor, 0);
+
+	OV5640_stream_off(sensor);
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	OV5640_turn_on_AE_AG(sensor, 1);
+
+err:
+	return retval;
+}
+
+static int ov5640_init_mode(struct ov5640 *sensor,
+			    enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode, enum ov5640_mode orig_mode)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+	u32 msec_wait4stable = 0;
+	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
+
+	if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN)
+		&& (mode != ov5640_mode_INIT)) {
+		dev_err(dev, "Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode;
+	orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode;
+	if (mode == ov5640_mode_INIT) {
+		pModeSetting = ov5640_init_setting_30fps_VGA;
+		ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+		sensor->pix.width = 640;
+		sensor->pix.height = 480;
+		retval = ov5640_download_firmware(sensor, pModeSetting,
+						  ArySize);
+		if (retval < 0)
+			goto err;
+
+		pModeSetting = ov5640_setting_30fps_VGA_640_480;
+		ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);
+		retval = ov5640_download_firmware(sensor, pModeSetting,
+						  ArySize);
+	} else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
+			(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
+		/* change between subsampling and scaling
+		 * go through exposure calucation */
+		retval = ov5640_change_mode_exposure_calc(sensor,
+				frame_rate, mode);
+	} else {
+		/* change inside subsampling or scaling
+		 * download firmware directly */
+		retval = ov5640_change_mode_direct(sensor, frame_rate, mode);
+	}
+
+	if (retval < 0)
+		goto err;
+
+	OV5640_set_AE_target(sensor, AE_Target);
+	OV5640_get_light_freq(sensor);
+	OV5640_set_bandingfilter(sensor);
+	ov5640_set_virtual_channel(sensor, sensor->csi);
+
+	/* add delay to wait for sensor stable */
+	if (mode == ov5640_mode_QSXGA_2592_1944) {
+		/* dump the first two frames: 1/7.5*2
+		 * the frame rate of QSXGA is 7.5fps */
+		msec_wait4stable = 267;
+	} else {
+		/* dump the first eighteen frames: 1/30*18 */
+		msec_wait4stable = 600;
+	}
+	msleep(msec_wait4stable);
+
+err:
+	return retval;
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+
+	if (on && !sensor->on) {
+		if (io_regulator)
+			if (regulator_enable(io_regulator) != 0)
+				return -EIO;
+		if (core_regulator)
+			if (regulator_enable(core_regulator) != 0)
+				return -EIO;
+		if (gpo_regulator)
+			if (regulator_enable(gpo_regulator) != 0)
+				return -EIO;
+		if (analog_regulator)
+			if (regulator_enable(analog_regulator) != 0)
+				return -EIO;
+	} else if (!on && sensor->on) {
+		ov5640_regualtor_disable();
+	}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	struct device *dev = &sensor->i2c_client->dev;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->streamcap.capability;
+		cparm->timeperframe = sensor->streamcap.timeperframe;
+		cparm->capturemode = sensor->streamcap.capturemode;
+		ret = 0;
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		ret = -EINVAL;
+		break;
+
+	default:
+		dev_warn(dev, "Type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	struct device *dev = &sensor->i2c_client->dev;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	enum ov5640_mode orig_mode;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		/* Check that the new frame rate is allowed. */
+		if ((timeperframe->numerator == 0) ||
+		    (timeperframe->denominator == 0)) {
+			timeperframe->denominator = DEFAULT_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps > MAX_FPS) {
+			timeperframe->denominator = MAX_FPS;
+			timeperframe->numerator = 1;
+		} else if (tgt_fps < MIN_FPS) {
+			timeperframe->denominator = MIN_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		/* Actual frame rate we use */
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps == 15)
+			frame_rate = ov5640_15_fps;
+		else if (tgt_fps == 30)
+			frame_rate = ov5640_30_fps;
+		else {
+			dev_warn(dev,
+				"The camera frame rate is not supported!\n");
+			return -EINVAL;
+		}
+
+		orig_mode = sensor->streamcap.capturemode;
+		ret = ov5640_init_mode(sensor, frame_rate,
+				(u32)a->parm.capture.capturemode, orig_mode);
+		if (ret < 0)
+			return ret;
+
+		sensor->streamcap.timeperframe = *timeperframe;
+		sensor->streamcap.capturemode =
+				(u32)a->parm.capture.capturemode;
+
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		dev_warn(dev, "Type is not V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+			a->type);
+		ret = -EINVAL;
+		break;
+
+	default:
+		dev_warn(dev, "Type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int ov5640_set_fmt(struct v4l2_subdev *sd,
+			struct v4l2_subdev_pad_config *cfg,
+			struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	int capturemode;
+
+	if (!fmt) {
+		mf->code	= ov5640_colour_fmts[0].code;
+		mf->colorspace	= ov5640_colour_fmts[0].colorspace;
+		fmt		= &ov5640_colour_fmts[0];
+	}
+
+	mf->field	= V4L2_FIELD_NONE;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	sensor->fmt = fmt;
+
+	capturemode = get_capturemode(mf->width, mf->height);
+	if (capturemode >= 0) {
+		sensor->streamcap.capturemode = capturemode;
+		sensor->pix.width = mf->width;
+		sensor->pix.height = mf->height;
+		return 0;
+	}
+
+	dev_err(&client->dev, "Set format failed %d, %d\n",
+		fmt->code, fmt->colorspace);
+	return -EINVAL;
+}
+
+
+static int ov5640_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	const struct ov5640_datafmt *fmt = sensor->fmt;
+
+	if (format->pad)
+		return -EINVAL;
+
+	mf->code	= fmt->code;
+	mf->colorspace	= fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	mf->width	= sensor->pix.width;
+	mf->height	= sensor->pix.height;
+
+	return 0;
+}
+
+static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= ARRAY_SIZE(ov5640_colour_fmts))
+		return -EINVAL;
+
+	code->code = ov5640_colour_fmts[code->index].code;
+	return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fse->max_width =
+			max(ov5640_mode_info_data[0][fse->index].width,
+			    ov5640_mode_info_data[1][fse->index].width);
+	fse->min_width = fse->max_width;
+	fse->max_height =
+			max(ov5640_mode_info_data[0][fse->index].height,
+			    ov5640_mode_info_data[1][fse->index].height);
+	fse->min_height = fse->max_height;
+	return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	int i, j, count = 0;
+
+	if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	if (fie->width == 0 || fie->height == 0 ||
+	    fie->code == 0) {
+		dev_warn(dev, "Please assign pixel format, width and height\n");
+		return -EINVAL;
+	}
+
+	fie->interval.numerator = 1;
+
+	count = 0;
+	for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+		for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+			if (fie->width == ov5640_mode_info_data[i][j].width
+			 && fie->height == ov5640_mode_info_data[i][j].height
+			 && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+				count++;
+			}
+			if (fie->index == (count - 1)) {
+				fie->interval.denominator =
+						ov5640_framerates[i];
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(struct ov5640 *sensor)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	int ret;
+
+	sensor->on = true;
+
+	/* mclk */
+	tgt_xclk = sensor->mclk;
+	tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+	sensor->mclk = tgt_xclk;
+
+	dev_dbg(dev, "Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+	/* Default camera frame rate is set in probe */
+	tgt_fps = sensor->streamcap.timeperframe.denominator /
+		  sensor->streamcap.timeperframe.numerator;
+
+	if (tgt_fps == 15)
+		frame_rate = ov5640_15_fps;
+	else if (tgt_fps == 30)
+		frame_rate = ov5640_30_fps;
+	else
+		return -EINVAL; /* Only support 15fps or 30fps now. */
+
+	ret = ov5640_init_mode(sensor, frame_rate, ov5640_mode_INIT,
+			       ov5640_mode_INIT);
+
+	return ret;
+}
+
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	struct device *dev = &sensor->i2c_client->dev;
+
+	dev_info(dev, "s_stream: %d\n", enable);
+	if (enable)
+		OV5640_stream_on(sensor);
+	else
+		OV5640_stream_off(sensor);
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+	.g_parm = ov5640_g_parm,
+	.s_parm = ov5640_s_parm,
+	.s_stream = ov5640_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+	.enum_frame_size       = ov5640_enum_framesizes,
+	.enum_frame_interval   = ov5640_enum_frameintervals,
+	.enum_mbus_code        = ov5640_enum_mbus_code,
+	.set_fmt               = ov5640_set_fmt,
+	.get_fmt               = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+	.s_power	= ov5640_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov5640_get_register,
+	.s_register	= ov5640_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+	.core	= &ov5640_subdev_core_ops,
+	.video	= &ov5640_subdev_video_ops,
+	.pad	= &ov5640_subdev_pad_ops,
+};
+
+static void ov5640_adjust_setting_20mhz(void)
+{
+	struct reg_value *regsetting;
+	int i, array_size;
+
+	/* adjust for INIT mode */
+	regsetting = ov5640_init_setting_30fps_VGA;
+	array_size = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+	for (i = 0; i < array_size; i++, regsetting++)
+		if (regsetting->u16RegAddr == 0x3037)
+			regsetting->u8Val = 0x17;
+}
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter            struct i2c_adapter *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct pinctrl *pinctrl;
+	struct device *dev = &client->dev;
+	int retval;
+	u8 chip_id_high, chip_id_low;
+	struct ov5640 *sensor;
+
+	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	/* ov5640 pinctrl */
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl))
+		dev_warn(dev, "No pin available\n");
+
+	/* request power down pin */
+	sensor->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(sensor->pwn_gpio))
+		dev_warn(dev, "No sensor pwdn pin available");
+	else {
+		retval = devm_gpio_request_one(dev, sensor->pwn_gpio,
+				GPIOF_OUT_INIT_HIGH, "ov5640_mipi_pwdn");
+		if (retval < 0) {
+			dev_warn(dev, "Failed to set power pin\n");
+			dev_warn(dev, "retval=%d\n", retval);
+			return retval;
+		}
+	}
+
+	/* request reset pin */
+	sensor->rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+	if (!gpio_is_valid(sensor->rst_gpio))
+		dev_warn(dev, "No sensor reset pin available");
+	else {
+		retval = devm_gpio_request_one(dev, sensor->rst_gpio,
+				GPIOF_OUT_INIT_HIGH, "ov5640_mipi_reset");
+		if (retval < 0) {
+			dev_warn(dev, "Failed to set reset pin\n");
+			return retval;
+		}
+	}
+
+
+	sensor->sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(sensor->sensor_clk)) {
+		/* assuming clock enabled by default */
+		sensor->sensor_clk = NULL;
+		dev_err(dev, "clock-frequency missing or invalid\n");
+		return PTR_ERR(sensor->sensor_clk);
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk",
+					&(sensor->mclk));
+	if (retval) {
+		dev_err(dev, "mclk missing or invalid\n");
+		return retval;
+	}
+
+	if (sensor->mclk == OV5640_XCLK_20MHZ)
+		ov5640_adjust_setting_20mhz();
+
+	retval = of_property_read_u32(dev->of_node, "mclk_source",
+					(u32 *) &(sensor->mclk_source));
+	if (retval) {
+		dev_err(dev, "mclk_source missing or invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "csi_id",
+					&(sensor->csi));
+	if (retval) {
+		dev_err(dev, "csi id missing or invalid\n");
+		return retval;
+	}
+
+	clk_prepare_enable(sensor->sensor_clk);
+
+	sensor->io_init = ov5640_reset;
+	sensor->i2c_client = client;
+	sensor->pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	sensor->pix.width = 640;
+	sensor->pix.height = 480;
+	sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	sensor->streamcap.capturemode = 0;
+	sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+	sensor->streamcap.timeperframe.numerator = 1;
+
+	ov5640_regulator_enable(&client->dev);
+
+	mutex_lock(&ov5640_mutex);
+	{
+		ov5640_reset(sensor);
+		ov5640_power_down(sensor, 0);
+		retval = ov5640_update_slave_id(sensor);
+	}
+	mutex_unlock(&ov5640_mutex);
+	if (retval < 0) {
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+
+	retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_HIGH_BYTE,
+				 &chip_id_high);
+	if (retval < 0 || chip_id_high != 0x56) {
+		dev_warn(dev, "Camera is not found\n");
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+	retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+	if (retval < 0 || chip_id_low != 0x40) {
+		dev_warn(dev, "Camera is not found\n");
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+
+
+	retval = init_device(sensor);
+	if (retval < 0) {
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		dev_warn(dev, "Camera init failed\n");
+		ov5640_power_down(sensor, 1);
+		return retval;
+	}
+
+	v4l2_i2c_subdev_init(&sensor->subdev, client, &ov5640_subdev_ops);
+
+	sensor->subdev.grp_id = 678;
+	retval = v4l2_async_register_subdev(&sensor->subdev);
+	if (retval < 0)
+		dev_err(&client->dev, "Async register failed, ret=%d\n",
+			retval);
+
+	OV5640_stream_off(sensor);
+	dev_info(dev, "Camera is found\n");
+	return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov5640 *sensor = to_ov5640(client);
+
+	v4l2_async_unregister_subdev(sd);
+
+	clk_disable_unprepare(sensor->sensor_clk);
+
+	ov5640_power_down(sensor, 1);
+
+	ov5640_regualtor_disable();
+
+	return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ov5640_v2.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ov5640_v2.c
@@ -0,0 +1,1917 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG               2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE         1500000
+#define OV5640_VOLTAGE_DIGITAL_IO           1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE        0x300A
+#define OV5640_CHIP_ID_LOW_BYTE         0x300B
+
+enum ov5640_mode {
+	ov5640_mode_MIN = 0,
+	ov5640_mode_VGA_640_480 = 0,
+	ov5640_mode_QVGA_320_240 = 1,
+	ov5640_mode_NTSC_720_480 = 2,
+	ov5640_mode_PAL_720_576 = 3,
+	ov5640_mode_720P_1280_720 = 4,
+	ov5640_mode_1080P_1920_1080 = 5,
+	ov5640_mode_QSXGA_2592_1944 = 6,
+	ov5640_mode_QCIF_176_144 = 7,
+	ov5640_mode_XGA_1024_768 = 8,
+	ov5640_mode_MAX = 8
+};
+
+enum ov5640_frame_rate {
+	ov5640_15_fps,
+	ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+	[ov5640_15_fps] = 15,
+	[ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+	u32	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+struct reg_value {
+	u16 u16RegAddr;
+	u8 u8Val;
+	u8 u8Mask;
+	u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+	enum ov5640_mode mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+struct ov5640 {
+	struct v4l2_subdev		subdev;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	const struct ov5640_datafmt	*fmt;
+	struct v4l2_captureparm streamcap;
+	bool on;
+
+	/* control settings */
+	int brightness;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	u32 mclk;
+	u8 mclk_source;
+	struct clk *sensor_clk;
+	int csi;
+
+	void (*io_init)(void);
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct ov5640 ov5640_data;
+static int pwn_gpio, rst_gpio;
+static int prev_sysclk;
+static int AE_Target = 52, night_mode;
+static int prev_HTS;
+static int AE_high, AE_low;
+
+static struct reg_value ov5640_global_init_setting[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+	{0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0},
+	{0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0},
+	{0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0},
+	{0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0},
+	{0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0},
+	{0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0},
+	{0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0},
+	{0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0},
+	{0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+	{0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0},
+	{0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0},
+	{0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0},
+	{0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+	{0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0},
+	{0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+	{0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0},
+	{0x3008, 0x02, 0, 0},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+	{0x3008, 0x42, 0, 0},
+	{0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+	{0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0},
+	{0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+	{0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+	{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+	{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+	{0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+	{0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0},
+	{0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+	{0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0},
+	{0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0},
+	{0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0},
+	{0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0},
+	{0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+	{0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+	{0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0},
+	{0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0},
+	{0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0},
+	{0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0},
+	{0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0},
+	{0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0},
+	{0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0},
+	{0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0},
+	{0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0},
+	{0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0},
+	{0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0},
+	{0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0},
+	{0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0},
+	{0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0},
+	{0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0},
+	{0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0},
+	{0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0},
+	{0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0},
+	{0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0},
+	{0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0},
+	{0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0},
+	{0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0},
+	{0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0},
+	{0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0},
+	{0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0},
+	{0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0},
+	{0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0},
+	{0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0},
+	{0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0},
+	{0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0},
+	{0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0},
+	{0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0},
+	{0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0},
+	{0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0},
+	{0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0},
+	{0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0},
+	{0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0},
+	{0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0},
+	{0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0},
+	{0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0},
+	{0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0},
+	{0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+	{0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+	{0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+	{0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+	{0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+	{0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+	{0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+	{0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+	{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+	{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+	{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+	{0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+	{0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+	{0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+	{0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+	{0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+	{0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+	{0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+	{0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+	{0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+	{0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+	{0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+	{0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+	{0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+	{0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+	{0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+	{0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0},
+	{0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0},
+	{0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0},
+	{0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+	{0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+	{0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+	{0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+	{0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+	{0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+	{0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0},
+	{0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+	{0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0},
+	{0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0},
+	{0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+	{0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+	{0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+	{0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+	{0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+	{0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+	{0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+	{0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+	{
+		{ov5640_mode_VGA_640_480,      640,  480,
+		ov5640_setting_15fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240,     320,  240,
+		ov5640_setting_15fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480,     720,  480,
+		ov5640_setting_15fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576,      720,  576,
+		ov5640_setting_15fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720,   1280,  720,
+		ov5640_setting_15fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, 1920, 1080,
+		ov5640_setting_15fps_1080P_1920_1080,
+		ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+		{ov5640_mode_QSXGA_2592_1944, 2592, 1944,
+		ov5640_setting_15fps_QSXGA_2592_1944,
+		ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+		{ov5640_mode_QCIF_176_144,     176,  144,
+		ov5640_setting_15fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768,    1024,  768,
+		ov5640_setting_15fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+	},
+	{
+		{ov5640_mode_VGA_640_480,      640,  480,
+		ov5640_setting_30fps_VGA_640_480,
+		ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+		{ov5640_mode_QVGA_320_240,     320,  240,
+		ov5640_setting_30fps_QVGA_320_240,
+		ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+		{ov5640_mode_NTSC_720_480,     720,  480,
+		ov5640_setting_30fps_NTSC_720_480,
+		ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+		{ov5640_mode_PAL_720_576,      720,  576,
+		ov5640_setting_30fps_PAL_720_576,
+		ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+		{ov5640_mode_720P_1280_720,   1280,  720,
+		ov5640_setting_30fps_720P_1280_720,
+		ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+		{ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0},
+		{ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0},
+		{ov5640_mode_QCIF_176_144,     176,  144,
+		ov5640_setting_30fps_QCIF_176_144,
+		ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+		{ov5640_mode_XGA_1024_768,    1024,  768,
+		ov5640_setting_30fps_XGA_1024_768,
+		ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+	},
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ov5640_of_match[] = {
+	{ .compatible = "ovti,ov5640",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ov5640_of_match);
+#endif
+
+static const struct i2c_device_id ov5640_id[] = {
+	{"ov5640", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+	.driver = {
+		  .owner = THIS_MODULE,
+		  .name  = "ov5640",
+#ifdef CONFIG_OF
+		  .of_match_table = of_match_ptr(ov5640_of_match),
+#endif
+		  },
+	.probe  = ov5640_probe,
+	.remove = ov5640_remove,
+	.id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+	{MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+			*ov5640_find_datafmt(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+		if (ov5640_colour_fmts[i].code == code)
+			return ov5640_colour_fmts + i;
+
+	return NULL;
+}
+
+static inline void ov5640_power_down(int enable)
+{
+	gpio_set_value_cansleep(pwn_gpio, enable);
+
+	msleep(2);
+}
+
+static inline void ov5640_reset(void)
+{
+	/* camera reset */
+	gpio_set_value_cansleep(rst_gpio, 1);
+
+	/* camera power down */
+	gpio_set_value_cansleep(pwn_gpio, 1);
+	msleep(5);
+	gpio_set_value_cansleep(pwn_gpio, 0);
+	msleep(5);
+	gpio_set_value_cansleep(rst_gpio, 0);
+	msleep(1);
+	gpio_set_value_cansleep(rst_gpio, 1);
+	msleep(5);
+	gpio_set_value_cansleep(pwn_gpio, 1);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+	int ret = 0;
+
+	io_regulator = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(io_regulator)) {
+		regulator_set_voltage(io_regulator,
+				      OV5640_VOLTAGE_DIGITAL_IO,
+				      OV5640_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(io_regulator);
+		if (ret) {
+			dev_err(dev, "set io voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set io voltage ok\n");
+		}
+	} else {
+		io_regulator = NULL;
+		dev_warn(dev, "cannot get io voltage\n");
+	}
+
+	core_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(core_regulator)) {
+		regulator_set_voltage(core_regulator,
+				      OV5640_VOLTAGE_DIGITAL_CORE,
+				      OV5640_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(core_regulator);
+		if (ret) {
+			dev_err(dev, "set core voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set core voltage ok\n");
+		}
+	} else {
+		core_regulator = NULL;
+		dev_warn(dev, "cannot get core voltage\n");
+	}
+
+	analog_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(analog_regulator)) {
+		regulator_set_voltage(analog_regulator,
+				      OV5640_VOLTAGE_ANALOG,
+				      OV5640_VOLTAGE_ANALOG);
+		ret = regulator_enable(analog_regulator);
+		if (ret) {
+			dev_err(dev, "set analog voltage failed\n");
+			return ret;
+		} else {
+			dev_dbg(dev, "set analog voltage ok\n");
+		}
+	} else {
+		analog_regulator = NULL;
+		dev_warn(dev, "cannot get analog voltage\n");
+	}
+
+	return ret;
+}
+
+static void ov5640_regualtor_disable(void)
+{
+	if (analog_regulator)
+		regulator_disable(analog_regulator);
+
+	if (core_regulator)
+		regulator_disable(core_regulator);
+
+	if (io_regulator)
+		regulator_disable(io_regulator);
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+	u8 au8Buf[3] = {0};
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+		pr_err("%s:write reg error:reg=%x,val=%x\n",
+			__func__, reg, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+		pr_err("%s:write reg error:reg=%x\n",
+				__func__, reg);
+		return -1;
+	}
+
+	if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+		pr_err("%s:read reg error:reg=%x,val=%x\n",
+				__func__, reg, u8RdVal);
+		return -1;
+	}
+
+	*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5640_get_register(struct v4l2_subdev *sd,
+					struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xffff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov5640_read_reg(reg->reg, &val);
+	if (!ret)
+		reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov5640_set_register(struct v4l2_subdev *sd,
+					const struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (reg->reg & ~0xffff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov5640_write_reg(reg->reg, reg->val);
+}
+#endif
+
+static void ov5640_soft_reset(void)
+{
+	/* sysclk from pad */
+	ov5640_write_reg(0x3103, 0x11);
+
+	/* software reset */
+	ov5640_write_reg(0x3008, 0x82);
+
+	/* delay at least 5ms */
+	msleep(10);
+}
+
+/* set sensor driver capability
+ * 0x302c[7:6] - strength
+	00     - 1x
+	01     - 2x
+	10     - 3x
+	11     - 4x
+ */
+static int ov5640_driver_capability(int strength)
+{
+	u8 temp = 0;
+
+	if (strength > 4 || strength < 1) {
+		pr_err("The valid driver capability of ov5640 is 1x~4x\n");
+		return -EINVAL;
+	}
+
+	ov5640_read_reg(0x302c, &temp);
+
+	temp &= ~0xc0;	/* clear [7:6] */
+	temp |= ((strength - 1) << 6);	/* set [7:6] */
+
+	ov5640_write_reg(0x302c, temp);
+
+	return 0;
+}
+
+/* calculate sysclk */
+static int ov5640_get_sysclk(void)
+{
+	int xvclk = ov5640_data.mclk / 10000;
+	int sysclk;
+	int temp1, temp2;
+	int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv;
+	int sclk_rdiv_map[] = {1, 2, 4, 8};
+	u8 regval = 0;
+
+	temp1 = ov5640_read_reg(0x3034, &regval);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10) {
+		Bit_div2x = temp2 / 2;
+	} else {
+		pr_err("ov5640: unsupported bit mode %d\n", temp2);
+		return -1;
+	}
+
+	temp1 = ov5640_read_reg(0x3035, &regval);
+	SysDiv = temp1 >> 4;
+	if (SysDiv == 0)
+		SysDiv = 16;
+
+	temp1 = ov5640_read_reg(0x3036, &regval);
+	Multiplier = temp1;
+	temp1 = ov5640_read_reg(0x3037, &regval);
+	PreDiv = temp1 & 0x0f;
+	Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov5640_read_reg(0x3108, &regval);
+	temp2 = temp1 & 0x03;
+
+	sclk_rdiv = sclk_rdiv_map[temp2];
+	VCO = xvclk * Multiplier / PreDiv;
+	sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+	return sysclk;
+}
+
+/* read HTS from register settings */
+static int ov5640_get_HTS(void)
+{
+	int HTS;
+	u8 temp = 0;
+
+	HTS = ov5640_read_reg(0x380c, &temp);
+	HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+	return HTS;
+}
+
+/* read VTS from register settings */
+static int ov5640_get_VTS(void)
+{
+	int VTS;
+	u8 temp = 0;
+
+	VTS = ov5640_read_reg(0x380e, &temp);
+	VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+	return VTS;
+}
+
+/* write VTS to registers */
+static int ov5640_set_VTS(int VTS)
+{
+	int temp;
+
+	temp = VTS & 0xff;
+	ov5640_write_reg(0x380f, temp);
+
+	temp = VTS>>8;
+	ov5640_write_reg(0x380e, temp);
+	return 0;
+}
+
+/* read shutter, in number of line period */
+static int ov5640_get_shutter(void)
+{
+	int shutter;
+	u8 regval;
+
+	shutter = (ov5640_read_reg(0x03500, &regval) & 0x0f);
+
+	shutter = (shutter<<8) + ov5640_read_reg(0x3501, &regval);
+	shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &regval)>>4);
+
+	return shutter;
+}
+
+/* write shutter, in number of line period */
+static int ov5640_set_shutter(int shutter)
+{
+	int temp;
+
+	shutter = shutter & 0xffff;
+	temp = shutter & 0x0f;
+	temp = temp<<4;
+	ov5640_write_reg(0x3502, temp);
+
+	temp = shutter & 0xfff;
+	temp = temp>>4;
+	ov5640_write_reg(0x3501, temp);
+
+	temp = shutter>>12;
+	ov5640_write_reg(0x3500, temp);
+
+	return 0;
+}
+
+/* read gain, 16 = 1x */
+static int ov5640_get_gain16(void)
+{
+	int gain16;
+	u8 regval;
+
+	gain16 = ov5640_read_reg(0x350a, &regval) & 0x03;
+	gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &regval);
+
+	return gain16;
+}
+
+/* write gain, 16 = 1x */
+static int ov5640_set_gain16(int gain16)
+{
+	int temp;
+
+	gain16 = gain16 & 0x3ff;
+	temp = gain16 & 0xff;
+
+	ov5640_write_reg(0x350b, temp);
+	temp = gain16>>8;
+
+	ov5640_write_reg(0x350a, temp);
+	return 0;
+}
+
+/* get banding filter value */
+static int ov5640_get_light_freq(void)
+{
+	int temp, temp1, light_frequency;
+	u8 regval;
+
+	temp = ov5640_read_reg(0x3c01, &regval);
+	if (temp & 0x80) {
+		/* manual */
+		temp1 = ov5640_read_reg(0x3c00, &regval);
+		if (temp1 & 0x04) {
+			/* 50Hz */
+			light_frequency = 50;
+		} else {
+			/* 60Hz */
+			light_frequency = 60;
+		}
+	} else {
+		/* auto */
+		temp1 = ov5640_read_reg(0x3c0c, &regval);
+		if (temp1 & 0x01) {
+			/* 50Hz */
+			light_frequency = 50;
+		} else {
+			/* 60Hz */
+			light_frequency = 60;
+		}
+	}
+
+	return light_frequency;
+}
+
+static void ov5640_set_bandingfilter(void)
+{
+	int prev_VTS;
+	int band_step60, max_band60, band_step50, max_band50;
+
+	/* read preview PCLK */
+	prev_sysclk = ov5640_get_sysclk();
+
+	/* read preview HTS */
+	prev_HTS = ov5640_get_HTS();
+
+	/* read preview VTS */
+	prev_VTS = ov5640_get_VTS();
+
+	/* calculate banding filter */
+	/* 60Hz */
+	band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+	ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+	ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+	max_band60 = (int)((prev_VTS-4)/band_step60);
+	ov5640_write_reg(0x3a0d, max_band60);
+
+	/* 50Hz */
+	band_step50 = prev_sysclk * 100/prev_HTS;
+	ov5640_write_reg(0x3a08, (band_step50 >> 8));
+	ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+	max_band50 = (int)((prev_VTS-4)/band_step50);
+	ov5640_write_reg(0x3a0e, max_band50);
+}
+
+/* stable in high */
+static int ov5640_set_AE_target(int target)
+{
+	int fast_high, fast_low;
+
+	AE_low = target * 23 / 25; /* 0.92 */
+	AE_high = target * 27 / 25; /* 1.08 */
+	fast_high = AE_high << 1;
+
+	if (fast_high > 255)
+		fast_high = 255;
+	fast_low = AE_low >> 1;
+
+	ov5640_write_reg(0x3a0f, AE_high);
+	ov5640_write_reg(0x3a10, AE_low);
+	ov5640_write_reg(0x3a1b, AE_high);
+	ov5640_write_reg(0x3a1e, AE_low);
+	ov5640_write_reg(0x3a11, fast_high);
+	ov5640_write_reg(0x3a1f, fast_low);
+
+	return 0;
+}
+
+/* enable = 0 to turn off night mode
+   enable = 1 to turn on night mode */
+static int ov5640_set_night_mode(int enable)
+{
+	u8 mode;
+
+	ov5640_read_reg(0x3a00, &mode);
+
+	if (enable) {
+		/* night mode on */
+		mode |= 0x04;
+		ov5640_write_reg(0x3a00, mode);
+	} else {
+		/* night mode off */
+		mode &= 0xfb;
+		ov5640_write_reg(0x3a00, mode);
+	}
+
+	return 0;
+}
+
+/* enable = 0 to turn off AEC/AGC
+   enable = 1 to turn on AEC/AGC */
+static void ov5640_turn_on_AE_AG(int enable)
+{
+	u8 ae_ag_ctrl;
+
+	ov5640_read_reg(0x3503, &ae_ag_ctrl);
+	if (enable) {
+		/* turn on auto AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+	} else {
+		/* turn off AE/AG */
+		ae_ag_ctrl = ae_ag_ctrl | 0x03;
+	}
+	ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+	register u32 Delay_ms = 0;
+	register u16 RegAddr = 0;
+	register u8 Mask = 0;
+	register u8 Val = 0;
+	u8 RegVal = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+		Delay_ms = pModeSetting->u32Delay_ms;
+		RegAddr = pModeSetting->u16RegAddr;
+		Val = pModeSetting->u8Val;
+		Mask = pModeSetting->u8Mask;
+
+		if (Mask) {
+			retval = ov5640_read_reg(RegAddr, &RegVal);
+			if (retval < 0)
+				goto err;
+
+			RegVal &= ~(u8)Mask;
+			Val &= Mask;
+			Val |= RegVal;
+		}
+
+		retval = ov5640_write_reg(RegAddr, Val);
+		if (retval < 0)
+			goto err;
+
+		if (Delay_ms)
+			msleep(Delay_ms);
+	}
+err:
+	return retval;
+}
+
+static int ov5640_init_mode(void)
+{
+	struct reg_value *pModeSetting = NULL;
+	int ArySize = 0, retval = 0;
+
+	ov5640_soft_reset();
+
+	pModeSetting = ov5640_global_init_setting;
+	ArySize = ARRAY_SIZE(ov5640_global_init_setting);
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	pModeSetting = ov5640_init_setting_30fps_VGA;
+	ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* change driver capability to 2x according to validation board.
+	 * if the image is not stable, please increase the driver strength.
+	 */
+	ov5640_driver_capability(2);
+	ov5640_set_bandingfilter();
+	ov5640_set_AE_target(AE_Target);
+	ov5640_set_night_mode(night_mode);
+
+	/* skip 9 vysnc: start capture at 10th vsync */
+	msleep(300);
+
+	/* turn off night mode */
+	night_mode = 0;
+	ov5640_data.pix.width = 640;
+	ov5640_data.pix.height = 480;
+err:
+	return retval;
+}
+
+/* change to or back to subsampling mode set the mode directly
+ * image size below 1280 * 960 is subsampling mode */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+		pr_err("Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+	    pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* set ov5640 to subsampling mode */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+
+	/* turn on AE AG for subsampling mode, in case the firmware didn't */
+	ov5640_turn_on_AE_AG(1);
+
+	/* calculate banding filter */
+	ov5640_set_bandingfilter();
+
+	/* set AE target */
+	ov5640_set_AE_target(AE_Target);
+
+	/* update night mode setting */
+	ov5640_set_night_mode(night_mode);
+
+	/* skip 9 vysnc: start capture at 10th vsync */
+	if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) {
+		pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n");
+		/* 1/22.5 * 9*/
+		msleep(400);
+		return retval;
+	}
+
+	if (frame_rate == ov5640_15_fps) {
+		/* 1/15 * 9*/
+		msleep(600);
+	} else if (frame_rate == ov5640_30_fps) {
+		/* 1/30 * 9*/
+		msleep(300);
+	}
+
+	return retval;
+}
+
+/* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	int prev_shutter, prev_gain16, average;
+	int cap_shutter, cap_gain16;
+	int cap_sysclk, cap_HTS, cap_VTS;
+	int light_freq, cap_bandfilt, cap_maxband;
+	long cap_gain16_shutter;
+	u8 temp;
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	ov5640_data.pix.width =
+		ov5640_mode_info_data[frame_rate][mode].width;
+	ov5640_data.pix.height =
+		ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* read preview shutter */
+	prev_shutter = ov5640_get_shutter();
+
+	/* read preview gain */
+	prev_gain16 = ov5640_get_gain16();
+
+	/* get average */
+	average = ov5640_read_reg(0x56a1, &temp);
+
+	/* turn off night mode for capture */
+	ov5640_set_night_mode(0);
+
+	/* turn off overlay */
+	ov5640_write_reg(0x3022, 0x06);
+
+	/* Write capture setting */
+	retval = ov5640_download_firmware(pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* turn off AE AG when capture image. */
+	ov5640_turn_on_AE_AG(0);
+
+	/* read capture VTS */
+	cap_VTS = ov5640_get_VTS();
+	cap_HTS = ov5640_get_HTS();
+	cap_sysclk = ov5640_get_sysclk();
+
+	/* calculate capture banding filter */
+	light_freq = ov5640_get_light_freq();
+	if (light_freq == 60) {
+		/* 60Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+	} else {
+		/* 50Hz */
+		cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+	}
+	cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+	/* calculate capture shutter/gain16 */
+	if (average > AE_low && average < AE_high) {
+		/* in stable range */
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+			prev_HTS/cap_HTS * AE_Target / average;
+	} else {
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+			prev_HTS/cap_HTS;
+	}
+
+	/* gain to shutter */
+	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+		/* shutter < 1/100 */
+		cap_shutter = cap_gain16_shutter/16;
+		if (cap_shutter < 1)
+			cap_shutter = 1;
+		cap_gain16 = cap_gain16_shutter/cap_shutter;
+		if (cap_gain16 < 16)
+			cap_gain16 = 16;
+	} else {
+		if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) {
+			/* exposure reach max */
+			cap_shutter = cap_bandfilt*cap_maxband;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		} else {
+			/* 1/100 < cap_shutter =< max, cap_shutter = n/100 */
+			cap_shutter =
+				((int)(cap_gain16_shutter/16/cap_bandfilt))
+				* cap_bandfilt;
+			cap_gain16 = cap_gain16_shutter / cap_shutter;
+		}
+	}
+
+	/* write capture gain */
+	ov5640_set_gain16(cap_gain16);
+
+	/* write capture shutter */
+	if (cap_shutter > (cap_VTS - 4)) {
+		cap_VTS = cap_shutter + 4;
+		ov5640_set_VTS(cap_VTS);
+	}
+
+	ov5640_set_shutter(cap_shutter);
+
+	/* skip 2 vysnc: start capture at 3rd vsync
+	 * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2
+	 */
+	pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n",
+		mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA");
+	msleep(267);
+err:
+	return retval;
+}
+
+static int ov5640_change_mode(enum ov5640_frame_rate frame_rate,
+			    enum ov5640_mode mode)
+{
+	int retval = 0;
+
+	if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+		pr_err("Wrong ov5640 mode detected!\n");
+		return -1;
+	}
+
+	if (mode == ov5640_mode_1080P_1920_1080 ||
+			mode == ov5640_mode_QSXGA_2592_1944) {
+		/* change to scaling mode go through exposure calucation
+		 * image size above 1280 * 960 is scaling mode */
+		retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+	} else {
+		/* change back to subsampling modem download firmware directly
+		 * image size below 1280 * 960 is subsampling mode */
+		retval = ov5640_change_mode_direct(frame_rate, mode);
+	}
+
+	return retval;
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+
+	if (on)
+		clk_enable(ov5640_data.sensor_clk);
+	else
+		clk_disable(ov5640_data.sensor_clk);
+
+	sensor->on = on;
+
+	return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->streamcap.capability;
+		cparm->timeperframe = sensor->streamcap.timeperframe;
+		cparm->capturemode = sensor->streamcap.capturemode;
+		ret = 0;
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		/* Check that the new frame rate is allowed. */
+		if ((timeperframe->numerator == 0) ||
+		    (timeperframe->denominator == 0)) {
+			timeperframe->denominator = DEFAULT_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps > MAX_FPS) {
+			timeperframe->denominator = MAX_FPS;
+			timeperframe->numerator = 1;
+		} else if (tgt_fps < MIN_FPS) {
+			timeperframe->denominator = MIN_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		/* Actual frame rate we use */
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps == 15)
+			frame_rate = ov5640_15_fps;
+		else if (tgt_fps == 30)
+			frame_rate = ov5640_30_fps;
+		else {
+			pr_err(" The camera frame rate is not supported!\n");
+			goto error;
+		}
+
+		ret = ov5640_change_mode(frame_rate,
+				a->parm.capture.capturemode);
+		if (ret < 0)
+			goto error;
+
+		sensor->streamcap.timeperframe = *timeperframe;
+		sensor->streamcap.capturemode = a->parm.capture.capturemode;
+
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		pr_debug("   type is not " \
+			"V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+			a->type);
+		ret = -EINVAL;
+		break;
+
+	default:
+		pr_debug("   type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+error:
+	return ret;
+}
+
+static int ov5640_set_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+
+	if (format->pad)
+		return -EINVAL;
+
+	if (!fmt) {
+		mf->code	= ov5640_colour_fmts[0].code;
+		mf->colorspace	= ov5640_colour_fmts[0].colorspace;
+	}
+
+	mf->field	= V4L2_FIELD_NONE;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	sensor->fmt = fmt;
+
+	return 0;
+}
+
+static int ov5640_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5640 *sensor = to_ov5640(client);
+	const struct ov5640_datafmt *fmt = sensor->fmt;
+
+	if (format->pad)
+		return -EINVAL;
+
+	mf->code	= fmt->code;
+	mf->colorspace	= fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int ov5640_enum_code(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_pad_config *cfg,
+			    struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= ARRAY_SIZE(ov5640_colour_fmts))
+		return -EINVAL;
+
+	code->code = ov5640_colour_fmts[code->index].code;
+	return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	fse->max_width =
+			max(ov5640_mode_info_data[0][fse->index].width,
+			    ov5640_mode_info_data[1][fse->index].width);
+	fse->min_width = fse->max_width;
+	fse->max_height =
+			max(ov5640_mode_info_data[0][fse->index].height,
+			    ov5640_mode_info_data[1][fse->index].height);
+	fse->min_height = fse->max_height;
+	return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_interval_enum *fie)
+{
+	int i, j, count;
+
+	if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+		return -EINVAL;
+
+	if (fie->width == 0 || fie->height == 0 ||
+	    fie->code == 0) {
+		pr_warning("Please assign pixel format, width and height.\n");
+		return -EINVAL;
+	}
+
+	fie->interval.numerator = 1;
+
+	count = 0;
+	for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+		for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+			if (fie->width == ov5640_mode_info_data[i][j].width
+			 && fie->height == ov5640_mode_info_data[i][j].height
+			 && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+				count++;
+			}
+			if (fie->index == (count - 1)) {
+				fie->interval.denominator =
+						ov5640_framerates[i];
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int ov5640_set_clk_rate(void)
+{
+	u32 tgt_xclk;	/* target xclk */
+	int ret;
+
+	/* mclk */
+	tgt_xclk = ov5640_data.mclk;
+	tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+	ov5640_data.mclk = tgt_xclk;
+
+	pr_debug("   Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+	ret = clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk);
+	if (ret < 0)
+		pr_debug("set rate filed, rate=%d\n", ov5640_data.mclk);
+	return ret;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(void)
+{
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov5640_frame_rate frame_rate;
+	int ret;
+
+	ov5640_data.on = true;
+
+	/* mclk */
+	tgt_xclk = ov5640_data.mclk;
+
+	/* Default camera frame rate is set in probe */
+	tgt_fps = ov5640_data.streamcap.timeperframe.denominator /
+		  ov5640_data.streamcap.timeperframe.numerator;
+
+	if (tgt_fps == 15)
+		frame_rate = ov5640_15_fps;
+	else if (tgt_fps == 30)
+		frame_rate = ov5640_30_fps;
+	else
+		return -EINVAL; /* Only support 15fps or 30fps now. */
+
+	ret = ov5640_init_mode();
+
+	return ret;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+	.g_parm = ov5640_g_parm,
+	.s_parm = ov5640_s_parm,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+	.enum_frame_size       = ov5640_enum_framesizes,
+	.enum_frame_interval   = ov5640_enum_frameintervals,
+	.enum_mbus_code        = ov5640_enum_code,
+	.set_fmt               = ov5640_set_fmt,
+	.get_fmt               = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+	.s_power	= ov5640_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov5640_get_register,
+	.s_register	= ov5640_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+	.core	= &ov5640_subdev_core_ops,
+	.video	= &ov5640_subdev_video_ops,
+	.pad	= &ov5640_subdev_pad_ops,
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter            struct i2c_adapter *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct pinctrl *pinctrl;
+	struct device *dev = &client->dev;
+	int retval;
+	u8 chip_id_high, chip_id_low;
+
+	/* ov5640 pinctrl */
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl)) {
+		dev_err(dev, "setup pinctrl failed\n");
+		return PTR_ERR(pinctrl);
+	}
+
+	/* request power down pin */
+	pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(pwn_gpio)) {
+		dev_err(dev, "no sensor pwdn pin available\n");
+		return -ENODEV;
+	}
+	retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_pwdn");
+	if (retval < 0)
+		return retval;
+
+	/* request reset pin */
+	rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+	if (!gpio_is_valid(rst_gpio)) {
+		dev_err(dev, "no sensor reset pin available\n");
+		return -EINVAL;
+	}
+	retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+					"ov5640_reset");
+	if (retval < 0)
+		return retval;
+
+	/* Set initial values for the sensor struct. */
+	memset(&ov5640_data, 0, sizeof(ov5640_data));
+	ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(ov5640_data.sensor_clk)) {
+		dev_err(dev, "get mclk failed\n");
+		return PTR_ERR(ov5640_data.sensor_clk);
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk",
+					&ov5640_data.mclk);
+	if (retval) {
+		dev_err(dev, "mclk frequency is invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk_source",
+					(u32 *) &(ov5640_data.mclk_source));
+	if (retval) {
+		dev_err(dev, "mclk_source invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "csi_id",
+					&(ov5640_data.csi));
+	if (retval) {
+		dev_err(dev, "csi_id invalid\n");
+		return retval;
+	}
+
+	/* Set mclk rate before clk on */
+	ov5640_set_clk_rate();
+
+	clk_prepare_enable(ov5640_data.sensor_clk);
+
+	ov5640_data.io_init = ov5640_reset;
+	ov5640_data.i2c_client = client;
+	ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	ov5640_data.pix.width = 640;
+	ov5640_data.pix.height = 480;
+	ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	ov5640_data.streamcap.capturemode = 0;
+	ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+	ov5640_data.streamcap.timeperframe.numerator = 1;
+
+	ov5640_regulator_enable(&client->dev);
+
+	ov5640_reset();
+
+	ov5640_power_down(0);
+
+	retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+	if (retval < 0 || chip_id_high != 0x56) {
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		pr_warning("camera ov5640 is not found\n");
+		return -ENODEV;
+	}
+	retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+	if (retval < 0 || chip_id_low != 0x40) {
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		pr_warning("camera ov5640 is not found\n");
+		return -ENODEV;
+	}
+
+	retval = init_device();
+	if (retval < 0) {
+		ov5640_regualtor_disable();
+		clk_disable_unprepare(ov5640_data.sensor_clk);
+		pr_warning("camera ov5640 init failed\n");
+		ov5640_power_down(1);
+		return retval;
+	}
+
+	clk_disable(ov5640_data.sensor_clk);
+
+	v4l2_i2c_subdev_init(&ov5640_data.subdev, client, &ov5640_subdev_ops);
+
+	retval = v4l2_async_register_subdev(&ov5640_data.subdev);
+	if (retval < 0)
+		dev_err(&client->dev,
+					"%s--Async register failed, ret=%d\n", __func__, retval);
+
+	pr_info("camera ov5640, is found\n");
+	return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_async_unregister_subdev(sd);
+
+	clk_unprepare(ov5640_data.sensor_clk);
+
+	ov5640_power_down(1);
+
+	ov5640_regualtor_disable();
+
+	return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/ov9281_mipi_v2.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/ov9281_mipi_v2.c
@@ -0,0 +1,2620 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Copyright 2018-2019 NXP
+ *
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV9281_VOLTAGE_ANALOG               2800000
+#define OV9281_VOLTAGE_DIGITAL_CORE         1200000
+#define OV9281_VOLTAGE_DIGITAL_IO           1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 120
+#define DEFAULT_FPS 30
+
+#define OV9281_XCLK_MIN 6000000
+#define OV9281_XCLK_MAX 24000000
+#define OV9281_XCLK_20MHZ 20000000
+
+#define OV9281_CHIP_ID_HIGH_BYTE	0x300A
+#define OV9281_CHIP_ID_LOW_BYTE		0x300B
+
+#define DEFAULT_SCCB_ID 0xc0
+
+enum ov9281_mode {
+	ov9281_mode_MIN = 0,
+	ov9281_mode_600P_600_400 = 0,
+	ov9281_mode_600P_600_480 = 1,
+	ov9281_mode_620P_620_480 = 2,
+	ov9281_mode_720P_1280_720 = 3,
+	ov9281_mode_800P_1280_800 = 4,
+	ov9281_mode_720P_1280_720_trig = 5,
+	ov9281_mode_MAX = 5,
+	ov9281_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov9281_frame_rate {
+	ov9281_120_fps,
+	ov9281_30_fps,
+	ov9281_15_fps
+};
+
+static int ov9281_framerates[] = {
+	[ov9281_120_fps] = 120,
+	[ov9281_30_fps] = 30,
+	[ov9281_15_fps] = 15
+};
+
+struct ov9281_datafmt {
+	u32	code;
+	enum v4l2_colorspace		colorspace;
+};
+
+struct reg_value {
+	u16 u16RegAddr;
+	u8 u8Val;
+	u8 u8Mask;
+	u32 u32Delay_ms;
+};
+
+struct ov9281_mode_info {
+	enum ov9281_mode mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+struct ov9281 {
+	struct v4l2_subdev		subdev;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	const struct ov9281_datafmt	*fmt;
+	struct v4l2_captureparm streamcap;
+	bool on;
+
+	/* control settings */
+	int brightness;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	u32 mclk;
+	u8 mclk_source;
+	struct clk *xclk;
+	struct clk *sensor_clk;
+	int csi;
+
+	void (*io_init)(struct ov9281 *);
+	int pwn_gpio, rst_gpio;
+};
+
+struct ov9281_res {
+	int width;
+	int height;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+
+
+struct ov9281_res ov9281_valid_res[] = {
+	[0] = {600, 400},
+	[1] = {600, 480},
+	[2] = {620, 480},
+	[3] = {1280, 720},
+	[4] = {1280, 800},
+	[5] = {1280, 720},
+};
+
+static struct reg_value ov9281_setting_120fps_600_400[] = {
+
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 4
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x30 }, // Exposure (Def=0x02)       0x2a   //KTC!!! (back to default)
+    { 0x3502, 0x00 }, // Exposure (Def=0x00)       0x90   //KTC!!! (back to default)
+    { 0x3503, 0x00 }, // gain_prec16_en (Def=0x00) 0x08
+    { 0x3505, 0x00 }, // gain conversion option (Def=0x00) 0x8c    //KTC!!! (back to default)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00) 0x03    //KTC!!! (back to default)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x80 }, // GAIN                      0x10      //KTC!!! (back to default)
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x07 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x03 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    { 0x3803, 0x00 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    { 0x3808, 0x05 },   // Def.
+    { 0x3809, 0x00 },   // Def.
+    { 0x380a, 0x03 },   // Def.
+    { 0x380b, 0x20 },   // Def.
+    { 0x380c, 0x02 },   // Def.
+    { 0x380d, 0xd8 },   // Def.
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x8e },   // Def.
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3881, 0x42 }, // ??
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x10 }, // ir_blk_lvl_target_o 0x40  //KTC!!! (back to default)
+    { 0x4008, 0x02 }, // r_up_bl_start_o     0x04  //KTC!!! (back to default)
+    { 0x4009, 0x05 }, // r_up_bl_end_o       0x0b  //KTC!!! (back to default)
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x03 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o  0x40  //KTC!!! (back to default)
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4300, 0x3f },   // DATA_MAX H Data max [9:2] // KTC Clips data at 255 (Per Jim M.)
+    { 0x4301, 0x00 },   // DATA_MIN H Data max [9:2] Def.  Min = 0
+    { 0x4302, 0x0c },   // CLIP L Data min/max [1:0] Def.
+    { 0x4303, 0x00 },   // Def FORMAT CTRL3
+    { 0x4304, 0x38 },   // data_bit_swap FORMAT CTRL4  // seb
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x00},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0x11},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x00},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x22},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x00},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x33},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0x44},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //12
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x00 }, /* bit 5: gated clk */ // use falling edge of mipi_pclk_o to generate MIPI bus to PHY
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+//KTC!!!
+    /* Window control */
+    { 0x5a00, 0x01 },   // XStart = 0x154 = 340        XSTART MAN [10:8]  //KTC!!! Centering on image sensor
+    { 0x5a01, 0x54 },   //                             XSTART MAN [7:0]
+    { 0x5a02, 0x00 },   // YStart = 0x0C8 = 200        YSTART MAN [9:8]   //KTC!!! Centering on image sensor
+    { 0x5a03, 0xc8 },   //                             YSTART MAN [7:0]
+    { 0x5a04, 0x02 },   // Width  = 0x280 = 640        XWIN MAN [10:8]    (Def = 0x0500 = 1280)
+    { 0x5a05, 0x58 },   //          0x258 = 600        XWIN MAN [7:0]
+    { 0x5a06, 0x01 },   // Height = 0x190 = 400        YWIN MAN [9:8]     (Def = 0x0320 = 800)
+    { 0x5a07, 0x90 },   //          0x080 = 128        YWIN MAN [7:0]
+    { 0x5a08, 0x87 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    { 0x5a09, 0x00 },   // Def.    WINC SEL
+//10
+//KTC!!!
+
+    /* ???? */
+    { 0x5d00, 0x07 },  // Def
+    { 0x5d01, 0x00 },  // Def
+ //2
+    //---------------------- 98
+};
+
+static struct reg_value ov9281_setting_120fps_600_480[] = {
+
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 4
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x30 }, // Exposure (Def=0x02)       0x2a   //KTC!!! (back to default)
+    { 0x3502, 0x00 }, // Exposure (Def=0x00)       0x90   //KTC!!! (back to default)
+    { 0x3503, 0x00 }, // gain_prec16_en (Def=0x00) 0x08
+    { 0x3505, 0x00 }, // gain conversion option (Def=0x00) 0x8c    //KTC!!! (back to default)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00) 0x03    //KTC!!! (back to default)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x80 }, // GAIN                      0x10      //KTC!!! (back to default)
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x07 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x03 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    { 0x3803, 0x00 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    { 0x3808, 0x02 },   // Def.  258 = 600
+    { 0x3809, 0x58 },   // Def.
+    { 0x380a, 0x01 },   // Def. 1E0 = 480
+    { 0x380b, 0xe0 },   // Def.
+    { 0x380c, 0x02 },   // Def.
+    { 0x380d, 0xd8 },   // Def.
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x8e },   // Def.
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3881, 0x42 }, // ??
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x10 }, // ir_blk_lvl_target_o 0x40  //KTC!!! (back to default)
+    { 0x4008, 0x02 }, // r_up_bl_start_o     0x04  //KTC!!! (back to default)
+    { 0x4009, 0x05 }, // r_up_bl_end_o       0x0b  //KTC!!! (back to default)
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x03 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o  0x40  //KTC!!! (back to default)
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4300, 0x3f },   // DATA_MAX H Data max [9:2] //KTC Clips data at 255 (Per Jim M.)
+    { 0x4301, 0x00 },   // DATA_MIN H Data max [9:2] Def.  Min = 0
+    { 0x4302, 0x0c },   // CLIP L Data min/max [1:0] Def.
+    { 0x4303, 0x00 },   // Def FORMAT CTRL3
+    { 0x4304, 0x38 },   // data_bit_swap FORMAT CTRL4  // seb
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x00},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0x11},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x00},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x22},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x00},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x33},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0x44},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //12
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x00 }, /* bit 5: gated clk */ // use falling edge of mipi_pclk_o to generate MIPI bus to PHY
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+//KTC!!!
+    /* Window control */
+    { 0x5a00, 0x01 },   // XStart = 0x154 = 340        XSTART MAN [10:8]  //KTC!!! Centering on image sensor
+    { 0x5a01, 0x54 },   //                             XSTART MAN [7:0]
+    { 0x5a02, 0x00 },   // YStart = 0x0C8 = 200        YSTART MAN [9:8]   //KTC!!! Centering on image sensor
+    { 0x5a03, 0xc8 },   //                             YSTART MAN [7:0]
+    { 0x5a04, 0x02 },   // Width  = 0x280 = 640        XWIN MAN [10:8]    (Def = 0x0500 = 1280)
+    { 0x5a05, 0x58 },   //          0x258 = 600        XWIN MAN [7:0]
+    { 0x5a06, 0x01 },   // Height = 0x1E0 = 480        YWIN MAN [9:8]     (Def = 0x0320 = 800)
+    { 0x5a07, 0xE0 },   //          0x080 = 128        YWIN MAN [7:0]
+    { 0x5a08, 0x87 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    { 0x5a09, 0x00 },   // Def.    WINC SEL
+//10
+//KTC!!!
+
+    /* ???? */
+    { 0x5d00, 0x07 },  // Def
+    { 0x5d01, 0x00 },  // Def
+ //2
+    //---------------------- 98
+};
+
+static struct reg_value ov9281_setting_120fps_620_480[] = {
+
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 4
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x30 }, // Exposure (Def=0x02)
+    { 0x3502, 0x90 }, // Exposure (Def=0x00)
+    { 0x3503, 0x08 }, // gain_prec16_en (Def=0x00)
+    { 0x3505, 0x8c }, // gain conversion option (Def=0x00)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x10 }, // GAIN
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x07 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x03 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    { 0x3803, 0x00 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    { 0x3808, 0x02 },   // Def.
+    { 0x3809, 0x80 },   // Def.
+    { 0x380a, 0x01 },   // Def.
+    { 0x380b, 0xe0 },   // Def.
+    { 0x380c, 0x02 },   // Def.
+    { 0x380d, 0xd8 },   // Def.
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x8e },   // Def.
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3881, 0x42 }, // ??
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x40 }, // ir_blk_lvl_target_o
+    { 0x4008, 0x04 }, // r_up_bl_start_o
+    { 0x4009, 0x0b }, // r_up_bl_end_o
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x07 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4303, 0x00 },   // Def FORMAT CTRL3
+    { 0x4304, 0x38 },   // data_bit_swap FORMAT CTRL4  // seb
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x00},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0x11},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x00},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x22},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x00},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x33},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0x44},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //12
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x00 }, /* bit 5: gated clk */ // use falling edge of mipi_pclk_o to generate MIPI bus to PHY
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+//KTC!!!
+    /* Window control */
+    { 0x5a00, 0x00 },   // Def.    XSTART MAN [10:8]
+    { 0x5a01, 0x00 },   // Def.    XSTART MAN [7:0]
+    { 0x5a02, 0x00 },   // Def.    YSTART MAN [9:8]
+    { 0x5a03, 0x00 },   // Def.    YSTART MAN [7:0]
+    { 0x5a04, 0x02 },   // Width  = 0x26c = 620        XWIN MAN [10:8]    (Def = 0x0500 = 1280)
+    { 0x5a05, 0x6c },   //          0x258 = 600        XWIN MAN [7:0]
+    { 0x5a06, 0x01 },   // Height = 0x1e0 = 480        YWIN MAN [9:8]     (Def = 0x0320 = 800)
+    { 0x5a07, 0xe0 },   //          0x080 = 128        YWIN MAN [7:0]
+    { 0x5a08, 0x86 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    { 0x5a09, 0x00 },   // Def.    WINC SEL
+//10
+//KTC!!!
+
+    /* ???? */
+    { 0x5d00, 0x07 },  // Def
+    { 0x5d01, 0x00 },  // Def
+ //2
+    //---------------------- 98
+};
+
+static struct reg_value ov9281_init_setting_30fps_VGA[] = {
+
+    /* PLL control */
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 3
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // Def.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x30 }, // Exposure (Def=0x02)
+    { 0x3502, 0x90 }, // Exposure (Def=0x00)
+    { 0x3503, 0x08 }, // gain_prec16_en (Def=0x00)
+    { 0x3505, 0x8c }, // gain conversion option (Def=0x00)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x10 }, // GAIN
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x06 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x03 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    { 0x3803, 0x00 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    { 0x3808, 0x05 },   // Def.
+    { 0x3809, 0x00 },   // Def.
+    { 0x380a, 0x03 },   // Def.
+    { 0x380b, 0x20 },   // Def.
+    { 0x380c, 0x02 },   // Def.
+    { 0x380d, 0xd8 },   // Def.
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x8e },   // Def.
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3881, 0x42 }, // ??
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x40 }, // ir_blk_lvl_target_o
+    { 0x4008, 0x04 }, // r_up_bl_start_o
+    { 0x4009, 0x0b }, // r_up_bl_end_o
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x07 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4304, 0x38 },   // data_bit_swap FORMAT CTRL4  // seb
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x02},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0xa8},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x01},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x54},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x03},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x30},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0xCC},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //12
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x00 }, /* bit 5: gated clk */ // use falling edge of mipi_pclk_o to generate MIPI bus to PHY
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+
+    /* ???? */
+    { 0x5d00, 0x07 },
+    { 0x5d01, 0x00 },
+ //2
+    //---------------------- 98
+};
+static struct reg_value ov9281_setting_30fps_800P_1280_800[] = {
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 3
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x301c, 0xf0},   //from OV init
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x30 }, // Exposure (Def=0x02)       0x2a   //KTC!!! (back to default)
+    { 0x3502, 0x00 }, // Exposure (Def=0x00)       0x90   //KTC!!! (back to default)
+    { 0x3503, 0x00 }, // gain_prec16_en (Def=0x00) 0x08
+    { 0x3505, 0x00 }, // gain conversion option (Def=0x00) 0x8c    //KTC!!! (back to default)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00) 0x03    //KTC!!! (back to default)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x80 }, // GAIN                      0x10      //KTC!!! (back to default)
+    //8
+
+        /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x07 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x07 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+    //9
+
+        /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+     //11
+
+        /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    { 0x3803, 0x00 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    { 0x3808, 0x05 },   // Def.  // 500 = 1280
+    { 0x3809, 0x00 },   // Def.
+    { 0x380a, 0x03 },   // Def.  // 2d0 = 720  320 - 800
+    { 0x380b, 0x20 },   // Def.
+    { 0x380c, 0x02 },   // Def.
+    { 0x380d, 0xd8 },   // Def.
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x8e },   // Def.
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x382c, 0x05 },   //Def
+    { 0x382d, 0xb0 },   //Def
+    { 0x389d, 0x00 }, //undocumented register OV sets
+    { 0x3881, 0x42 }, // ??
+    { 0x3882, 0x01 }, //undocumented register OV sets
+    { 0x3883, 0x00 }, //undocumented register OV sets
+    { 0x3885, 0x02 }, //undocumented register OV sets
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38b3, 0x02 }, //undocumented register OV sets
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x10 }, // ir_blk_lvl_target_o 0x40  //KTC!!! (back to default)
+    { 0x4008, 0x02 }, // r_up_bl_start_o     0x04  //KTC!!! (back to default)
+    { 0x4009, 0x05 }, // r_up_bl_end_o       0x0b  //KTC!!! (back to default)
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x03 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o  0x40  //KTC!!! (back to default)
+    { 0x4043, 0x40 },   // Def.
+     //7
+
+    /* format control */
+    { 0x4300, 0x3f },   // DATA_MAX H Data max [9:2] //KTC Clips data at 255 (Per Jim M.)
+    { 0x4301, 0x00 },   // DATA_MIN H Data max [9:2] Def.  Min = 0
+    { 0x4302, 0x0c },   // CLIP L Data min/max [1:0] Def.
+    { 0x4303, 0x00 },   // Def. FORMAT CTRL3
+    { 0x4304, 0x38 },   // Data bit swap FORMAT CTRL4
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x02},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0xa8},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x01},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x54},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x03},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x30},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0xCC},  // P3 Value for Solid Test Pattern SEB KTC!!!
+//4
+
+        /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+//4
+
+        /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+     //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+     //1
+
+    /* MIPI top control */
+    {0x4800, 0x01},
+    {0x4825, 0x80},
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+     //3
+
+    /* ???? */
+    { 0x5d00, 0x07 },
+    { 0x5d01, 0x00 },
+    {0x4f00, 0x04},
+    {0x4f10, 0x00},
+    {0x4f11, 0x98},
+    {0x4f12, 0x0f},
+    {0xf13, 0xc4}
+};
+static struct reg_value ov9281_setting_30fps_720P_1280_720[] = {
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x0304, 0x03 }, // Def. 0x03  // PLL1 pix clk  0 = /4; 3 = /8
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 3
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x04 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3030, 0x10 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x02 }, // Exposure (Def=0x02)       0x2a   //KTC!!! (back to default)
+    { 0x3502, 0x10 }, // Exposure (Def=0x00)       0x90   //KTC!!! (back to default)
+    { 0x3503, 0x00 }, // gain_prec16_en (Def=0x00) 0x08
+    { 0x3505, 0x00 }, // gain conversion option (Def=0x00) 0x8c    //KTC!!! (back to default)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00) 0x03    //KTC!!! (back to default)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x80 }, // GAIN                      0x10      //KTC!!! (back to default)
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x06 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x07 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    //{ 0x3803, 0x00 },   // Def.
+    { 0x3803, 0x28 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def. 
+    //{ 0x3807, 0x07 },   // Def. 775 for 720
+    { 0x3808, 0x05 },   // Def.
+    { 0x3809, 0x00 },   // Def.
+    //{ 0x380a, 0x03 },   // Def.
+    //{ 0x380b, 0x20 },   // Def.
+    { 0x380a, 0x02 },   // Def.
+    { 0x380b, 0xd0 },   // Def.
+    { 0x380c, 0x03 },   //
+    { 0x380d, 0x00 },   //
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x63 },   //
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3881, 0x42 }, // ??
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x10 }, // ir_blk_lvl_target_o 0x40  //KTC!!! (back to default)
+    { 0x4008, 0x02 }, // r_up_bl_start_o     0x04  //KTC!!! (back to default)
+    { 0x4009, 0x05 }, // r_up_bl_end_o       0x0b  //KTC!!! (back to default)
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x03 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o  0x40  //KTC!!! (back to default)
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4300, 0x3f },   // DATA_MAX H Data max [9:2] //KTC Clips data at 255 (Per Jim M.)
+    { 0x4301, 0x00 },   // DATA_MIN H Data max [9:2] Def.  Min = 0
+    { 0x4302, 0x0c },   // CLIP L Data min/max [1:0] Def.
+    { 0x4303, 0x00 },   // Def. FORMAT CTRL3
+    { 0x4304, 0x38 },   // Data bit swap FORMAT CTRL4
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x02},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0xa8},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x01},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x54},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x03},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x30},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0xCC},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //4
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x01 }, //change the low power delay to manual (see register 0x4825)
+    { 0x4825, 0x80 },
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+
+    /* Window control */
+    { 0x5a00, 0x01 },   // XStart = 0x154 = 340        XSTART MAN [10:8]  //KTC!!! Centering on image sensor
+    { 0x5a01, 0x54 },   //                             XSTART MAN [7:0]
+    { 0x5a02, 0x00 },   // YStart = 0x0C8 = 200        YSTART MAN [9:8]   //KTC!!! Centering on image sensor
+    { 0x5a03, 0xc8 },   //                             YSTART MAN [7:0]
+    { 0x5a04, 0x05 },   // Width  = 0x280 = 640        XWIN MAN [10:8]    (Def = 0x0500 = 1280)
+    { 0x5a05, 0x00 },   //          0x258 = 600        XWIN MAN [7:0]
+    { 0x5a06, 0x02 },   // Height = 0x190 = 400        YWIN MAN [9:8]     (Def = 0x0320 = 800)
+    { 0x5a07, 0xd0 },   //          0x080 = 128        YWIN MAN [7:0]
+    { 0x5a08, 0x86 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    //{ 0x5a08, 0x87 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    { 0x5a09, 0x00 },   // Def.    WINC SEL
+//10
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+
+    /* ???? */
+    { 0x5d00, 0x07 },
+    { 0x5d01, 0x00 },
+ //2
+    //---------------------- 98
+};
+
+static struct reg_value ov9281_setting_30fps_720P_1280_720_triggered[] = {
+    /* PLL control */
+    { 0x0103, 0x01 }, // Def. 0x00  // SW reset
+    { 0x0300, 0x01 }, // Def. 0x01  // PLL_Ctrl_Predivider
+    { 0x0302, 0x32 }, // Def.       // PLL1 Multiplier (X50) (Def=0x01)
+    { 0x0304, 0x03 }, // Def. 0x03  // PLL1 pix clk  0 = /4; 3 = /8
+    { 0x030d, 0x50 }, // Def.       // PLL2 Multiplier (X80)
+    { 0x030e, 0x02 }, // Def.       // PLL2 System Divider (/2)
+ // 3
+    { 0x030a, 0x00 }, // Def 0x00  //  System Divider 0 = /1 , 1 = /2
+
+    /* system control */
+    { 0x3001, 0x00 }, // Clear Debug control (Def=0x02)
+    { 0x3004, 0x00 }, // Def. (GPIO2 & D9 inputs)
+    { 0x3005, 0x00 }, // Def.
+    { 0x3006, 0x00 }, // ILPWM output enable (Def=0x00)
+    { 0x3011, 0x0a }, // pgm_vcm (Def=0x08)
+    { 0x3013, 0x18 }, // r_iref (Def=0x10)
+    { 0x3022, 0x01 }, // Def.
+    { 0x3023, 0x15 }, // Def.
+    { 0x3030, 0x04 }, // Def.
+    { 0x3039, 0x32 }, // Def.
+    //{ 0x3039, 0x12 }, // one mipi lane.
+    { 0x303a, 0x00 }, // Def.
+    { 0x303f, 0x01 }, // Def.
+ //10
+
+    /* manual AEC/AGC */
+    { 0x3500, 0x00 }, // Def.
+    { 0x3501, 0x02 }, // Exposure (Def=0x02)       0x2a   //KTC!!! (back to default)
+    { 0x3502, 0x10 }, // Exposure (Def=0x00)       0x90   //KTC!!! (back to default)
+    { 0x3503, 0x00 }, // gain_prec16_en (Def=0x00) 0x08
+    { 0x3505, 0x00 }, // gain conversion option (Def=0x00) 0x8c    //KTC!!! (back to default)
+    { 0x3507, 0x03 }, // gain shift (left shift 3 bit) (Def=0x00) 0x03    //KTC!!! (back to default)
+    { 0x3508, 0x00 }, // Debug
+    { 0x3509, 0x80 }, // GAIN                      0x10      //KTC!!! (back to default)
+//8
+
+    /* analog control */
+    { 0x3610, 0x80 }, // Reserved
+    { 0x3611, 0xa0 }, // Reserved
+    { 0x3620, 0x6e }, // Reserved
+    { 0x3632, 0x56 }, // Reserved
+    { 0x3633, 0x78 }, // Reserved
+    // - SEBchanged to RAW8   { 0x3662, 0x05 },   // Def. (MIPI 2-lane, Debug control, RAW10 bit selection)
+    //{ 0x3662, 0x06 },   // Def. (MIPI 2-lane, Debug control, RAW8 bit selection)
+    { 0x3662, 0x07 },   // Def. (MIPI 1-lane, Debug control, RAW8 bit selection)
+    { 0x3666, 0x00 }, // Internal frame sync input select = From FSIN pin (default=0x0A=fixed 0)
+    { 0x366f, 0x5a }, // Reserved
+    { 0x3670, 0x68 }, // Undocumented register, from Fsync example in datasheet
+    { 0x3680, 0x84 }, // Reserved
+ //9
+
+    /* sensor control */
+    { 0x3712, 0x80 }, // ??
+    { 0x372d, 0x22 }, // ??
+    { 0x3731, 0x80 }, // ??
+    { 0x3732, 0x30 }, // ??
+    { 0x3740, 0x01 },   // from Fsync example in datasheet
+    { 0x3741, 0x00 },   // from Fsync example in datasheet
+    { 0x3742, 0x08 },   // from Fsync example in datasheet
+    { 0x3778, 0x00 },   // Def.
+    { 0x377d, 0x22 }, // ??
+    { 0x3788, 0x02 }, // ??
+    { 0x3789, 0xa4 }, // ??
+    { 0x378a, 0x00 }, // ??
+    { 0x378b, 0x4a }, // ??
+    { 0x3799, 0x20 }, // ??
+ //11
+
+    /* timing control */
+    { 0x3800, 0x00 },   // Def.
+    { 0x3801, 0x00 },   // Def.
+    { 0x3802, 0x00 },   // Def.
+    //{ 0x3803, 0x00 },   // Def.
+    { 0x3803, 0x28 },   // Def.
+    { 0x3804, 0x05 },   // Def.
+    { 0x3805, 0x0f },   // Def.
+    { 0x3806, 0x03 },   // Def.
+    { 0x3807, 0x2f },   // Def.
+    //{ 0x3807, 0x07 },   // Def. 775 for 720
+    { 0x3808, 0x05 },   // Def.
+    { 0x3809, 0x00 },   // Def.
+    //{ 0x380a, 0x03 },   // Def.
+    //{ 0x380b, 0x20 },   // Def.
+    { 0x380a, 0x02 },   // Def.
+    { 0x380b, 0xd0 },   // Def.
+    { 0x380c, 0x03 },   //
+    { 0x380d, 0x21 },   //
+    { 0x380e, 0x03 },   // Def.
+    { 0x380f, 0x40 },   //
+    { 0x3810, 0x00 },   // Def.
+    { 0x3811, 0x08 },   // Def.
+    { 0x3812, 0x00 },   // Def.
+    { 0x3813, 0x08 },   // Def.
+    { 0x3814, 0x11 },   // Def.
+    { 0x3815, 0x11 },   // Def.
+    { 0x3820, 0x40 },   // Def.
+    { 0x3821, 0x00 },   // Def.
+    { 0x3823, 0x20 },   // from Fsync example in datasheet
+    { 0x3824, 0x00 },   // from Fsync example in datasheet
+    { 0x3825, 0x08 },   // from Fsync example in datasheet
+    { 0x3826, 0x03 },   // from Fsync example in datasheet
+    { 0x3827, 0x8A },   // from Fsync example in datasheet
+    { 0x382B, 0x3A },   // from Fsync example in datasheet
+    { 0x3881, 0x42 }, // ??
+    { 0x3885, 0x07 }, // Undocumented register, from Fsync example in datasheet
+
+//25
+
+    /* Global shutter control */
+    { 0x38a8, 0x02 }, // ??
+    { 0x38a9, 0x80 }, // ??
+    { 0x38b1, 0x00 }, // ??
+    { 0x38b3, 0x07 }, // Undocumented register, from Fsync example in datasheet
+    { 0x38c4, 0x00 }, // ??
+    { 0x38c5, 0xc0 }, // ??
+    { 0x38c6, 0x04 }, // ??
+    { 0x38c7, 0x80 }, // ??
+//7
+
+    /* PWM and strobe control */
+    { 0x3920, 0xff }, // Strobe pattern
+//1
+
+    /* BLC control */
+    { 0x4003, 0x10 }, // ir_blk_lvl_target_o 0x40  //KTC!!! (back to default)
+    { 0x4008, 0x02 }, // r_up_bl_start_o     0x04  //KTC!!! (back to default)
+    { 0x4009, 0x05 }, // r_up_bl_end_o       0x0b  //KTC!!! (back to default)
+    { 0x400c, 0x00 },   // Def.
+    { 0x400d, 0x03 },   // Def.
+    { 0x4010, 0x40 }, // r_off_allways_up_o  0x40  //KTC!!! (back to default)
+    { 0x4043, 0x40 },   // Def.
+ //7
+
+    /* format control */
+    { 0x4300, 0x3f },   // DATA_MAX H Data max [9:2] //KTC Clips data at 255 (Per Jim M.)
+    { 0x4301, 0x00 },   // DATA_MIN H Data max [9:2] Def.  Min = 0
+    { 0x4302, 0x0c },   // CLIP L Data min/max [1:0] Def.
+    { 0x4303, 0x00 },   // Def. FORMAT CTRL3
+    { 0x4304, 0x38 },   // Data bit swap FORMAT CTRL4
+    { 0x4307, 0x30 },   // Def. (EMBED_CTRL)
+    { 0x4317, 0x00 },   // Def. (MIPI MODE ENABLE)
+
+    //{ 0x4320, 0x82},  // Pixel order=P1P2/P3P4, Sold test pattern enable KTC!!!
+    { 0x4320, 0x80},  // Pixel order=P1P2/P3P4, Normal Video SEB!!!
+    { 0x4322, 0x02},  // P1 Value for Solid Test Pattern MSB KTC!!!
+    { 0x4323, 0xa8},  // P1 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4324, 0x01},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4325, 0x54},  // P2 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4326, 0x03},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4327, 0x30},  // P4 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4328, 0x00},  // P3 Value for Solid Test Pattern SEB KTC!!!
+    { 0x4329, 0xCC},  // P3 Value for Solid Test Pattern SEB KTC!!!
+ //4
+
+    /* ???? */
+    { 0x4501, 0x00 },
+    { 0x4507, 0x00 },
+    { 0x4509, 0x00 },
+    { 0x450a, 0x08 },
+ //4
+
+    /* VFIFO control */
+    { 0x4601, 0x04 },   // Def.
+ //1
+
+    /* DVP control */
+    { 0x470f, 0x00 },   // Def.
+ //1
+
+    /* low power mode control */
+    { 0x4f07, 0x00 }, // r_pchg_st_offs
+ //1
+
+    /* MIPI top control */
+    { 0x4800, 0x01 }, //change the low power delay to manual (see register 0x4825)
+    { 0x4825, 0x80 },
+    //{ 0x4800, 0x04 }, // use rising edge of mipi_pclk_o to generate MIPI bus to PHY
+
+    { 0x4F00, 0x01 },   // Def.
+    /* ISP top control */
+    { 0x5000, 0x9f },   // Def.
+    { 0x5001, 0x00 },   // Def.
+
+    /* Window control */
+    { 0x5a00, 0x01 },   // XStart = 0x154 = 340        XSTART MAN [10:8]  //KTC!!! Centering on image sensor
+    { 0x5a01, 0x54 },   //                             XSTART MAN [7:0]
+    { 0x5a02, 0x00 },   // YStart = 0x0C8 = 200        YSTART MAN [9:8]   //KTC!!! Centering on image sensor
+    { 0x5a03, 0xc8 },   //                             YSTART MAN [7:0]
+    { 0x5a04, 0x05 },   // Width  = 0x280 = 640        XWIN MAN [10:8]    (Def = 0x0500 = 1280)
+    { 0x5a05, 0x00 },   //          0x258 = 600        XWIN MAN [7:0]
+    { 0x5a06, 0x02 },   // Height = 0x190 = 400        YWIN MAN [9:8]     (Def = 0x0320 = 800)
+    { 0x5a07, 0xd0 },   //          0x080 = 128        YWIN MAN [7:0]
+    { 0x5a08, 0x86 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    //{ 0x5a08, 0x87 },   // Def.    WINC CTRL  0x86 = default, 0x87 = use manual parameters (above)
+    { 0x5a09, 0x00 },   // Def.    WINC SEL
+//10
+    //{ 0x5e00, 0x80 },   // Def.  0x80 standard test pattern 00 normal video
+    { 0x5e00, 0x00 },   // Def.  0x80 standard test pattern 00 normal video
+ //3
+
+    /* ???? */
+    { 0x5d00, 0x07 },
+    { 0x5d01, 0x00 },
+ //2
+    //---------------------- 98
+};
+
+static struct ov9281_mode_info ov9281_mode_info_data[2][ov9281_mode_MAX + 1] = {
+	{
+		{ov9281_mode_600P_600_400, 600, 400,
+		ov9281_setting_120fps_600_400,
+		ARRAY_SIZE(ov9281_setting_120fps_600_400)},
+
+		{ov9281_mode_600P_600_480, 600, 480,
+		ov9281_setting_120fps_600_480,
+		ARRAY_SIZE(ov9281_setting_120fps_600_480)},
+
+		{ov9281_mode_620P_620_480, 620, 480,
+		ov9281_setting_120fps_620_480,
+		ARRAY_SIZE(ov9281_setting_120fps_620_480)},
+
+		{ov9281_mode_720P_1280_720, 1280, 720,
+		ov9281_setting_30fps_720P_1280_720,
+		ARRAY_SIZE(ov9281_setting_30fps_720P_1280_720)},
+
+		{ov9281_mode_800P_1280_800, 1280, 800,
+		ov9281_setting_30fps_800P_1280_800,
+		ARRAY_SIZE(ov9281_setting_30fps_800P_1280_800)},
+
+		{ov9281_mode_720P_1280_720_trig, 1280, 720,
+		ov9281_setting_30fps_720P_1280_720_triggered,
+        ARRAY_SIZE(ov9281_setting_30fps_720P_1280_720_triggered)},
+
+	},
+	{
+		{ov9281_mode_600P_600_400, 600, 400,
+		ov9281_setting_120fps_600_400,
+		ARRAY_SIZE(ov9281_setting_120fps_600_400)},
+
+		{ov9281_mode_600P_600_480, 600, 480,
+		ov9281_setting_120fps_600_480,
+		ARRAY_SIZE(ov9281_setting_120fps_600_480)},
+
+		{ov9281_mode_620P_620_480, 620, 480,
+		ov9281_setting_120fps_620_480,
+		ARRAY_SIZE(ov9281_setting_120fps_620_480)},
+
+        {ov9281_mode_720P_1280_720_trig, 1280, 720,
+        ov9281_setting_30fps_720P_1280_720_triggered, 
+        ARRAY_SIZE(ov9281_setting_30fps_720P_1280_720_triggered)},
+
+		{ov9281_mode_800P_1280_800, 1280, 800,
+		ov9281_setting_30fps_800P_1280_800,
+		ARRAY_SIZE(ov9281_setting_30fps_800P_1280_800)},
+
+        {ov9281_mode_720P_1280_720_trig, 1280, 720,
+        ov9281_setting_30fps_720P_1280_720_triggered,
+        ARRAY_SIZE(ov9281_setting_30fps_720P_1280_720_triggered)},
+	},
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+static DEFINE_MUTEX(ov9281_mutex);
+
+static int ov9281_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov9281_remove(struct i2c_client *client);
+
+static s32 ov9281_read_reg(struct ov9281 *sensor, u16 reg, u8 *val);
+static s32 ov9281_write_reg(struct ov9281 *sensor, u16 reg, u8 val);
+#ifdef CONFIG_OF
+static const struct of_device_id ov9281_mipi_v2_of_match[] = {
+	{ .compatible = "ovti,ov9281_mipi",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ov9281_mipi_v2_of_match);
+#endif
+
+static const struct i2c_device_id ov9281_id[] = {
+	{"ov9281_mipi", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov9281_id);
+
+static struct i2c_driver ov9281_i2c_driver = {
+	.driver = {
+		  .owner = THIS_MODULE,
+		  .name  = "ov9281_mipi",
+#ifdef CONFIG_OF
+		  .of_match_table = of_match_ptr(ov9281_mipi_v2_of_match),
+#endif
+		  },
+	.probe  = ov9281_probe,
+	.remove = ov9281_remove,
+	.id_table = ov9281_id,
+};
+
+static const struct ov9281_datafmt ov9281_colour_fmts[] = {
+	{MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_RAW},
+};
+
+static int get_capturemode(int width, int height)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov9281_valid_res); i++) {
+		if ((ov9281_valid_res[i].width == width) &&
+		     (ov9281_valid_res[i].height == height))
+			return i;
+	}
+
+	return -1;
+}
+
+static struct ov9281 *to_ov9281(const struct i2c_client *client)
+{
+	return container_of(i2c_get_clientdata(client), struct ov9281, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov9281_datafmt
+			*ov9281_find_datafmt(u32 code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov9281_colour_fmts); i++)
+		if (ov9281_colour_fmts[i].code == code)
+			return ov9281_colour_fmts + i;
+
+	return NULL;
+}
+
+static inline void ov9281_power_down(struct ov9281 *sensor, int enable)
+{
+	if (sensor->pwn_gpio < 0)
+		return;
+
+	if (!enable)
+		gpio_set_value_cansleep(sensor->pwn_gpio, 0);
+	else
+		gpio_set_value_cansleep(sensor->pwn_gpio, 1);
+
+	msleep(2);
+}
+
+static void ov9281_reset(struct ov9281 *sensor)
+{
+	if (sensor->rst_gpio < 0 || sensor->pwn_gpio < 0)
+		return;
+
+	gpio_set_value(sensor->pwn_gpio, 0);
+	msleep(5);
+
+	gpio_set_value(sensor->pwn_gpio, 1);
+	msleep(5);
+}
+
+static int ov9281_regulator_enable(struct device *dev)
+{
+	int ret = 0;
+
+	analog_regulator = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(analog_regulator)) {
+		regulator_set_voltage(analog_regulator,
+				      OV9281_VOLTAGE_ANALOG,
+				      OV9281_VOLTAGE_ANALOG);
+		ret = regulator_enable(analog_regulator);
+		if (ret) {
+			pr_err("%s:analog set voltage error\n",
+				__func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:analog set voltage ok\n", __func__);
+		}
+	} else {
+		analog_regulator = NULL;
+		pr_err("%s: cannot get analog voltage error\n", __func__);
+	}
+
+	io_regulator = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(io_regulator)) {
+		regulator_set_voltage(io_regulator,
+				      OV9281_VOLTAGE_DIGITAL_IO,
+				      OV9281_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(io_regulator);
+		if (ret) {
+			pr_err("%s:io set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:io set voltage ok\n", __func__);
+		}
+	} else {
+		pr_err("%s: cannot get io voltage error\n", __func__);
+		io_regulator = NULL;
+	}
+
+	core_regulator = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(core_regulator)) {
+		regulator_set_voltage(core_regulator,
+				      OV9281_VOLTAGE_DIGITAL_CORE,
+				      OV9281_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(core_regulator);
+		if (ret) {
+			pr_err("%s:core set voltage error\n", __func__);
+			return ret;
+		} else {
+			dev_dbg(dev,
+				"%s:core set voltage ok\n", __func__);
+		}
+	} else {
+		core_regulator = NULL;
+		pr_err("%s: cannot get core voltage error\n", __func__);
+	}
+
+	return ret;
+}
+
+static void ov9281_regulator_disable(void)
+{
+	if (analog_regulator)
+		regulator_disable(analog_regulator);
+
+	if (core_regulator)
+		regulator_disable(core_regulator);
+
+	if (io_regulator)
+		regulator_disable(io_regulator);
+
+	if (gpo_regulator)
+		regulator_disable(gpo_regulator);
+}
+
+static s32 ov9281_write_reg(struct ov9281 *sensor, u16 reg, u8 val)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u8 au8Buf[3] = {0};
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	if (i2c_master_send(sensor->i2c_client, au8Buf, 3) < 0) {
+		dev_err(dev, "Write reg error: reg=%x, val=%x\n", reg, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static s32 ov9281_read_reg(struct ov9281 *sensor, u16 reg, u8 *val)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (i2c_master_send(sensor->i2c_client, au8RegBuf, 2) != 2) {
+		dev_err(dev, "Read reg error: reg=%x\n", reg);
+		return -1;
+	}
+
+	if (i2c_master_recv(sensor->i2c_client, &u8RdVal, 1) != 1) {
+		dev_err(dev, "Read reg error: reg=%x, val=%x\n", reg, u8RdVal);
+		return -1;
+	}
+
+	*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9281_get_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	int ret;
+	u8 val;
+
+	if (reg->reg & ~0xffff)
+		return -EINVAL;
+
+	reg->size = 1;
+
+	ret = ov9281_read_reg(sensor, reg->reg, &val);
+	if (!ret)
+		reg->val = (__u64)val;
+
+	return ret;
+}
+
+static int ov9281_set_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+
+	if (reg->reg & ~0xffff || reg->val & ~0xff)
+		return -EINVAL;
+
+	return ov9281_write_reg(sensor, reg->reg, reg->val);
+}
+#endif
+
+static void OV9281_stream_on(struct ov9281 *sensor)
+{
+	ov9281_write_reg(sensor, 0x0100, 0x01);
+}
+
+static void OV9281_stream_off(struct ov9281 *sensor)
+{
+	ov9281_write_reg(sensor, 0x0100, 0x00);
+}
+
+static int OV9281_get_sysclk(struct ov9281 *sensor)
+{
+	 /* calculate sysclk */
+	int xvclk = sensor->mclk / 10000;
+	int temp1, temp2;
+	int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv;
+	int Bit_div2x = 1, sclk_rdiv, sysclk;
+	u8 temp;
+
+	int sclk_rdiv_map[] = {1, 2, 4, 8};
+
+	temp1 = ov9281_read_reg(sensor, 0x3034, &temp);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10)
+		Bit_div2x = temp2 / 2;
+
+	temp1 = ov9281_read_reg(sensor, 0x3035, &temp);
+	SysDiv = temp1>>4;
+	if (SysDiv == 0)
+		SysDiv = 16;
+
+	temp1 = ov9281_read_reg(sensor, 0x3036, &temp);
+	Multiplier = temp1;
+
+	temp1 = ov9281_read_reg(sensor, 0x3037, &temp);
+	PreDiv = temp1 & 0x0f;
+	Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov9281_read_reg(sensor, 0x3108, &temp);
+	temp2 = temp1 & 0x03;
+	sclk_rdiv = sclk_rdiv_map[temp2];
+
+	VCO = xvclk * Multiplier / PreDiv;
+
+	sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+	return sysclk;
+}
+
+static int OV9281_get_HTS(struct ov9281 *sensor)
+{
+	 /* read HTS from register settings */
+	int HTS;
+	u8 temp;
+
+	HTS = ov9281_read_reg(sensor, 0x380c, &temp);
+	HTS = (HTS<<8) + ov9281_read_reg(sensor, 0x380d, &temp);
+
+	return HTS;
+}
+
+static int OV9281_get_VTS(struct ov9281 *sensor)
+{
+	 /* read VTS from register settings */
+	int VTS;
+	u8 temp;
+
+	/* total vertical size[15:8] high byte */
+	VTS = ov9281_read_reg(sensor, 0x380e, &temp);
+
+	VTS = (VTS<<8) + ov9281_read_reg(sensor, 0x380f, &temp);
+
+	return VTS;
+}
+
+static int OV9281_get_gain16(struct ov9281 *sensor)
+{
+	 /* read gain, 16 = 1x */
+	int gain16;
+	u8 temp;
+
+	gain16 = ov9281_read_reg(sensor, 0x350a, &temp) & 0x03;
+	gain16 = (gain16<<8) + ov9281_read_reg(sensor, 0x350b, &temp);
+
+	return gain16;
+}
+
+static void ov9281_set_virtual_channel(struct ov9281 *sensor, int channel)
+{
+	u8 channel_id;
+
+	ov9281_read_reg(sensor, 0x4814, &channel_id);
+	channel_id &= ~(3 << 6);
+	ov9281_write_reg(sensor, 0x4814, channel_id | (channel << 6));
+}
+
+/* download ov9281 settings to sensor through i2c */
+static int ov9281_download_firmware(struct ov9281 *sensor,
+				    struct reg_value *pModeSetting,
+				    s32 ArySize)
+{
+	register u32 Delay_ms = 0;
+	register u16 RegAddr = 0;
+	register u8 Mask = 0;
+	register u8 Val = 0;
+	u8 RegVal = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+		Delay_ms = pModeSetting->u32Delay_ms;
+		RegAddr = pModeSetting->u16RegAddr;
+		Val = pModeSetting->u8Val;
+		Mask = pModeSetting->u8Mask;
+
+		if (Mask) {
+			retval = ov9281_read_reg(sensor, RegAddr, &RegVal);
+			if (retval < 0)
+				goto err;
+
+			RegVal &= ~(u8)Mask;
+			Val &= Mask;
+			Val |= RegVal;
+		}
+
+		retval = ov9281_write_reg(sensor, RegAddr, Val);
+		if (retval < 0)
+			goto err;
+
+		if (Delay_ms)
+			msleep(Delay_ms);
+	}
+err:
+	return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov9281_change_mode_exposure_calc(struct ov9281 *sensor,
+				enum ov9281_frame_rate frame_rate,
+				enum ov9281_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	u8 average;
+	int prev_gain16;
+	int cap_sysclk, cap_HTS, cap_VTS;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov9281_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov9281_mode_info_data[frame_rate][mode].init_data_size;
+	sensor->pix.width =
+		ov9281_mode_info_data[frame_rate][mode].width;
+	sensor->pix.height =
+		ov9281_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	/* read preview gain */
+	prev_gain16 = OV9281_get_gain16(sensor);
+
+	/* get average */
+	ov9281_read_reg(sensor, 0x56a1, &average);
+
+	OV9281_stream_off(sensor);
+
+	/* Write capture setting */
+	retval = ov9281_download_firmware(sensor, pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+	/* read capture VTS */
+	cap_VTS = OV9281_get_VTS(sensor);
+	cap_HTS = OV9281_get_HTS(sensor);
+	cap_sysclk = OV9281_get_sysclk(sensor);
+
+	/* write capture gain */
+	OV9281_stream_on(sensor);
+
+err:
+	return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov9281_change_mode_direct(struct ov9281 *sensor,
+				enum ov9281_frame_rate frame_rate,
+				enum ov9281_mode mode)
+{
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	pModeSetting =
+		ov9281_mode_info_data[frame_rate][mode].init_data_ptr;
+	ArySize =
+		ov9281_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->pix.width =
+		ov9281_mode_info_data[frame_rate][mode].width;
+	sensor->pix.height =
+		ov9281_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+		pModeSetting == NULL || ArySize == 0)
+		return -EINVAL;
+
+	OV9281_stream_off(sensor);
+
+	/* Write capture setting */
+	retval = ov9281_download_firmware(sensor, pModeSetting, ArySize);
+	if (retval < 0)
+		goto err;
+
+err:
+	return retval;
+}
+
+static int ov9281_init_mode(struct ov9281 *sensor,
+			    enum ov9281_frame_rate frame_rate,
+			    enum ov9281_mode mode, enum ov9281_mode orig_mode)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	struct reg_value *pModeSetting = NULL;
+	s32 ArySize = 0;
+	int retval = 0;
+	u32 msec_wait4stable = 0;
+
+	if ((mode > ov9281_mode_MAX || mode < ov9281_mode_MIN)
+		&& (mode != ov9281_mode_INIT)) {
+		dev_err(dev, "Wrong ov9281 mode detected!\n");
+		return -1;
+	}
+
+	if (mode == ov9281_mode_INIT) {
+		dev_err(dev, "Setting Mode INIT\n");
+		pModeSetting = ov9281_setting_120fps_620_480;
+		ArySize = ARRAY_SIZE(ov9281_setting_120fps_620_480);
+
+		sensor->pix.width = 620;
+		sensor->pix.height = 480;
+		retval = ov9281_download_firmware(sensor, pModeSetting,
+						  ArySize);
+		if (retval < 0)
+			goto err;
+
+		pModeSetting = ov9281_setting_120fps_620_480;
+		ArySize = ARRAY_SIZE(ov9281_setting_120fps_620_480);
+		retval = ov9281_download_firmware(sensor, pModeSetting,
+						  ArySize);
+	} else {
+		/* change inside subsampling or scaling
+		 * download firmware directly */
+		retval = ov9281_change_mode_direct(sensor, frame_rate, mode);
+	}
+
+	if (retval < 0)
+		goto err;
+
+	ov9281_set_virtual_channel(sensor, sensor->csi);
+
+	/* add delay to wait for sensor stable */
+	/* dump the first eighteen frames: 1/30*18 */
+	msec_wait4stable = 600;
+	msleep(msec_wait4stable);
+
+err:
+	return retval;
+}
+
+/*!
+ * ov9281_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov9281_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+
+	if (on && !sensor->on) {
+		if (io_regulator)
+			if (regulator_enable(io_regulator) != 0)
+				return -EIO;
+		if (core_regulator)
+			if (regulator_enable(core_regulator) != 0)
+				return -EIO;
+		if (gpo_regulator)
+			if (regulator_enable(gpo_regulator) != 0)
+				return -EIO;
+		if (analog_regulator)
+			if (regulator_enable(analog_regulator) != 0)
+				return -EIO;
+	} else if (!on && sensor->on) {
+		ov9281_regulator_disable();
+	}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+/*!
+ * ov9281_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov9281_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	struct device *dev = &sensor->i2c_client->dev;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		memset(a, 0, sizeof(*a));
+		a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cparm->capability = sensor->streamcap.capability;
+		cparm->timeperframe = sensor->streamcap.timeperframe;
+		cparm->capturemode = sensor->streamcap.capturemode;
+		ret = 0;
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		ret = -EINVAL;
+		break;
+
+	default:
+		dev_warn(dev, "Type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov9281_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	struct device *dev = &sensor->i2c_client->dev;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov9281_frame_rate frame_rate;
+	enum ov9281_mode orig_mode;
+	int ret = 0;
+
+	switch (a->type) {
+	/* This is the only case currently handled. */
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		/* Check that the new frame rate is allowed. */
+		if ((timeperframe->numerator == 0) ||
+		    (timeperframe->denominator == 0)) {
+			timeperframe->denominator = DEFAULT_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps > MAX_FPS) {
+			timeperframe->denominator = MAX_FPS;
+			timeperframe->numerator = 1;
+		} else if (tgt_fps < MIN_FPS) {
+			timeperframe->denominator = MIN_FPS;
+			timeperframe->numerator = 1;
+		}
+
+		/* Actual frame rate we use */
+		tgt_fps = timeperframe->denominator /
+			  timeperframe->numerator;
+
+		if (tgt_fps == 15)
+			frame_rate = ov9281_15_fps;
+		else if (tgt_fps == 30)
+			frame_rate = ov9281_30_fps;
+		else if (tgt_fps == 120)
+			frame_rate = ov9281_120_fps;
+		else {
+			dev_warn(dev,
+				"The camera frame rate is not supported!\n");
+			return -EINVAL;
+		}
+
+		orig_mode = sensor->streamcap.capturemode;
+		ret = ov9281_init_mode(sensor, frame_rate,
+				(u32)a->parm.capture.capturemode, orig_mode);
+		if (ret < 0)
+			return ret;
+
+		sensor->streamcap.timeperframe = *timeperframe;
+		sensor->streamcap.capturemode =
+				(u32)a->parm.capture.capturemode;
+
+		break;
+
+	/* These are all the possible cases. */
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		dev_warn(dev, "Type is not V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+			a->type);
+		ret = -EINVAL;
+		break;
+
+	default:
+		dev_warn(dev, "Type is unknown - %d\n", a->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int ov9281_set_fmt(struct v4l2_subdev *sd,
+			struct v4l2_subdev_pad_config *cfg,
+			struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	const struct ov9281_datafmt *fmt = ov9281_find_datafmt(mf->code);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	int capturemode;
+
+	if (!fmt) {
+		mf->code	= ov9281_colour_fmts[0].code;
+		mf->colorspace	= ov9281_colour_fmts[0].colorspace;
+		fmt		= &ov9281_colour_fmts[0];
+	}
+
+	mf->field	= V4L2_FIELD_NONE;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	sensor->fmt = fmt;
+
+	capturemode = get_capturemode(mf->width, mf->height);
+	if (capturemode >= 0) {
+		sensor->streamcap.capturemode = capturemode;
+		sensor->pix.width = mf->width;
+		sensor->pix.height = mf->height;
+		return 0;
+	}
+
+	dev_err(&client->dev, "Set format failed %d, %d\n",
+		fmt->code, fmt->colorspace);
+	return -EINVAL;
+}
+
+
+static int ov9281_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	const struct ov9281_datafmt *fmt = sensor->fmt;
+
+	if (format->pad)
+		return -EINVAL;
+
+	mf->code	= fmt->code;
+	mf->colorspace	= fmt->colorspace;
+	mf->field	= V4L2_FIELD_NONE;
+
+	mf->width	= sensor->pix.width;
+	mf->height	= sensor->pix.height;
+
+	return 0;
+}
+
+static int ov9281_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= ARRAY_SIZE(ov9281_colour_fmts))
+		return -EINVAL;
+
+	code->code = ov9281_colour_fmts[code->index].code;
+	return 0;
+}
+
+/*!
+ * ov9281_enum_framesizes - V4L2 sensor interface handler for
+ *			   VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov9281_enum_framesizes(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index > ov9281_mode_MAX)
+		return -EINVAL;
+
+	fse->max_width =
+			max(ov9281_mode_info_data[0][fse->index].width,
+			    ov9281_mode_info_data[1][fse->index].width);
+	fse->min_width = fse->max_width;
+	fse->max_height =
+			max(ov9281_mode_info_data[0][fse->index].height,
+			    ov9281_mode_info_data[1][fse->index].height);
+	fse->min_height = fse->max_height;
+	return 0;
+}
+
+/*!
+ * ov9281_enum_frameintervals - V4L2 sensor interface handler for
+ *			       VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov9281_enum_frameintervals(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct device *dev = &client->dev;
+	int i, j, count = 0;
+
+	if (fie->index < 0 || fie->index > ov9281_mode_MAX)
+		return -EINVAL;
+
+	if (fie->width == 0 || fie->height == 0 ||
+	    fie->code == 0) {
+		dev_warn(dev, "Please assign pixel format, width and height\n");
+		return -EINVAL;
+	}
+
+	fie->interval.numerator = 1;
+
+	count = 0;
+	for (i = 0; i < ARRAY_SIZE(ov9281_mode_info_data); i++) {
+		for (j = 0; j < (ov9281_mode_MAX + 1); j++) {
+			if (fie->width == ov9281_mode_info_data[i][j].width
+			 && fie->height == ov9281_mode_info_data[i][j].height
+			 && ov9281_mode_info_data[i][j].init_data_ptr != NULL) {
+				count++;
+			}
+			if (fie->index == (count - 1)) {
+				fie->interval.denominator =
+						ov9281_framerates[i];
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(struct ov9281 *sensor)
+{
+	struct device *dev = &sensor->i2c_client->dev;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	enum ov9281_frame_rate frame_rate;
+	int ret;
+
+	sensor->on = true;
+
+	/* mclk */
+	tgt_xclk = sensor->mclk;
+	tgt_xclk = min(tgt_xclk, (u32)OV9281_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)OV9281_XCLK_MIN);
+	sensor->mclk = tgt_xclk;
+
+	dev_dbg(dev, "Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+	/* Default camera frame rate is set in probe */
+	tgt_fps = sensor->streamcap.timeperframe.denominator /
+		  sensor->streamcap.timeperframe.numerator;
+
+	if (tgt_fps == 15)
+		frame_rate = ov9281_15_fps;
+	else if (tgt_fps == 30)
+		frame_rate = ov9281_30_fps;
+	else if (tgt_fps == 120)
+		frame_rate = ov9281_120_fps;
+	else
+		return -EINVAL; /* Only support 15fps or 30fps now. */
+
+	ret = ov9281_init_mode(sensor, frame_rate, ov9281_mode_INIT,
+			       ov9281_mode_INIT);
+
+	return ret;
+}
+
+static int ov9281_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov9281 *sensor = to_ov9281(client);
+	struct device *dev = &sensor->i2c_client->dev;
+
+	dev_info(dev, "s_stream: %d\n", enable);
+	if (enable)
+		OV9281_stream_on(sensor);
+	else
+		OV9281_stream_off(sensor);
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov9281_subdev_video_ops = {
+	.g_parm = ov9281_g_parm,
+	.s_parm = ov9281_s_parm,
+	.s_stream = ov9281_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov9281_subdev_pad_ops = {
+	.enum_frame_size       = ov9281_enum_framesizes,
+	.enum_frame_interval   = ov9281_enum_frameintervals,
+	.enum_mbus_code        = ov9281_enum_mbus_code,
+	.set_fmt               = ov9281_set_fmt,
+	.get_fmt               = ov9281_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov9281_subdev_core_ops = {
+	.s_power	= ov9281_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register	= ov9281_get_register,
+	.s_register	= ov9281_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov9281_subdev_ops = {
+	.core	= &ov9281_subdev_core_ops,
+	.video	= &ov9281_subdev_video_ops,
+	.pad	= &ov9281_subdev_pad_ops,
+};
+
+static void ov9281_adjust_setting_20mhz(void)
+{
+	struct reg_value *regsetting;
+	int i, array_size;
+
+	/* adjust for INIT mode */
+	regsetting = ov9281_setting_120fps_620_480;
+	array_size = ARRAY_SIZE(ov9281_setting_120fps_620_480);
+
+	for (i = 0; i < array_size; i++, regsetting++)
+		if (regsetting->u16RegAddr == 0x3037)
+			regsetting->u8Val = 0x17;
+}
+
+/*!
+ * ov9281 I2C probe function
+ *
+ * @param adapter            struct i2c_adapter *
+ * @return  Error code indicating success or failure
+ */
+static int ov9281_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct pinctrl *pinctrl;
+	struct device *dev = &client->dev;
+	int retval;
+	u8 chip_id_high, chip_id_low;
+	struct ov9281 *sensor;
+
+	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	/* ov9281 pinctrl */
+	pinctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(pinctrl))
+		dev_warn(dev, "No pin available\n");
+
+	/* request power down pin */
+	sensor->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+	if (!gpio_is_valid(sensor->pwn_gpio))
+		dev_warn(dev, "No sensor pwdn pin available");
+	else {
+		retval = devm_gpio_request_one(dev, sensor->pwn_gpio,
+				GPIOF_OUT_INIT_HIGH, "ov9281_mipi_pwdn");
+		// power on system
+		gpio_set_value_cansleep(sensor->pwn_gpio, 1);
+		dev_warn(dev, "ov9281 pwn_gpio set value:%d",1);
+		if (retval < 0) {
+			dev_warn(dev, "Failed to set power pin\n");
+			dev_warn(dev, "retval=%d\n", retval);
+			return retval;
+		}
+	}
+
+	sensor->rst_gpio = sensor->pwn_gpio;
+
+	sensor->sensor_clk = devm_clk_get(dev, "csi_mclk");
+	if (IS_ERR(sensor->sensor_clk)) {
+		/* assuming clock enabled by default */
+		sensor->sensor_clk = NULL;
+		dev_err(dev, "clock-frequency missing or invalid\n");
+		return PTR_ERR(sensor->sensor_clk);
+	}
+
+	retval = of_property_read_u32(dev->of_node, "mclk",
+					&(sensor->mclk));
+	if (retval) {
+		dev_err(dev, "mclk missing or invalid\n");
+		return retval;
+	}
+
+	if (sensor->mclk == OV9281_XCLK_20MHZ)
+		ov9281_adjust_setting_20mhz();
+
+	retval = of_property_read_u32(dev->of_node, "mclk_source",
+					(u32 *) &(sensor->mclk_source));
+	if (retval) {
+		dev_err(dev, "mclk_source missing or invalid\n");
+		return retval;
+	}
+
+	retval = of_property_read_u32(dev->of_node, "csi_id",
+					&(sensor->csi));
+	if (retval) {
+		dev_err(dev, "csi id missing or invalid\n");
+		return retval;
+	}
+
+	clk_prepare_enable(sensor->sensor_clk);
+
+	sensor->io_init = ov9281_reset;
+	sensor->i2c_client = client;
+	sensor->pix.pixelformat = V4L2_PIX_FMT_GREY;
+	sensor->pix.width = 620;
+	sensor->pix.height = 480;
+	sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	sensor->streamcap.capturemode = 0;
+	sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+	sensor->streamcap.timeperframe.numerator = 1;
+
+	ov9281_regulator_enable(&client->dev);
+
+	ov9281_reset(sensor);
+
+#if 0
+	mutex_lock(&ov9281_mutex);
+	{
+		ov9281_reset(sensor);
+		ov9281_power_down(sensor, 0);
+		retval = ov9281_update_slave_id(sensor);
+	}
+	mutex_unlock(&ov9281_mutex);
+	if (retval < 0) {
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+#endif
+
+	retval = ov9281_read_reg(sensor, OV9281_CHIP_ID_HIGH_BYTE,
+				 &chip_id_high);
+	if (retval < 0 || chip_id_high != 0x92) {
+		dev_warn(dev, "Camera is not found\n");
+		ov9281_regulator_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+	retval = ov9281_read_reg(sensor, OV9281_CHIP_ID_LOW_BYTE, &chip_id_low);
+	if (retval < 0 || chip_id_low != 0x81) {
+		dev_warn(dev, "Camera is not found\n");
+		ov9281_regulator_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		return -ENODEV;
+	}
+
+	retval = init_device(sensor);
+	if (retval < 0) {
+		ov9281_regulator_disable();
+		clk_disable_unprepare(sensor->sensor_clk);
+		dev_warn(dev, "Camera init failed\n");
+		ov9281_power_down(sensor, 1);
+		return retval;
+	}
+
+	v4l2_i2c_subdev_init(&sensor->subdev, client, &ov9281_subdev_ops);
+
+	sensor->subdev.grp_id = 678;
+	retval = v4l2_async_register_subdev(&sensor->subdev);
+	if (retval < 0)
+		dev_err(&client->dev, "Async register failed, ret=%d\n",
+			retval);
+
+	OV9281_stream_off(sensor);
+	dev_info(dev, "Camera is found\n");
+	return retval;
+}
+
+/*!
+ * ov9281 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov9281_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov9281 *sensor = to_ov9281(client);
+
+	v4l2_async_unregister_subdev(sd);
+
+	clk_disable_unprepare(sensor->sensor_clk);
+
+	ov9281_power_down(sensor, 1);
+
+	ov9281_regulator_disable();
+
+	return 0;
+}
+
+module_i2c_driver(ov9281_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV9281 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/v4l2-int-device.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/v4l2-int-device.c
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * drivers/media/video/v4l2-int-device.c
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright 2005-2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include "v4l2-int-device.h"
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(int_list);
+
+void v4l2_int_device_try_attach_all(void)
+{
+	struct v4l2_int_device *m, *s;
+
+	list_for_each_entry(m, &int_list, head) {
+		if (m->type != v4l2_int_type_master)
+			continue;
+
+		list_for_each_entry(s, &int_list, head) {
+			if (s->type != v4l2_int_type_slave)
+				continue;
+
+			/* Slave is connected? */
+			if (s->u.slave->master)
+				continue;
+
+			/* Slave wants to attach to master? */
+			if (s->u.slave->attach_to[0] != 0
+			    && strncmp(m->name, s->u.slave->attach_to,
+				       V4L2NAMESIZE))
+				continue;
+
+			if (!try_module_get(m->module))
+				continue;
+
+			s->u.slave->master = m;
+			if (m->u.master->attach(s)) {
+				s->u.slave->master = NULL;
+				module_put(m->module);
+				continue;
+			}
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);
+
+static int ioctl_sort_cmp(const void *a, const void *b)
+{
+	const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
+
+	if (d1->num > d2->num)
+		return 1;
+
+	if (d1->num < d2->num)
+		return -1;
+
+	return 0;
+}
+
+int v4l2_int_device_register(struct v4l2_int_device *d)
+{
+	if (d->type == v4l2_int_type_slave)
+		sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
+		     sizeof(struct v4l2_int_ioctl_desc),
+		     &ioctl_sort_cmp, NULL);
+	mutex_lock(&mutex);
+	list_add(&d->head, &int_list);
+	v4l2_int_device_try_attach_all();
+	mutex_unlock(&mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_register);
+
+void v4l2_int_device_unregister(struct v4l2_int_device *d)
+{
+	mutex_lock(&mutex);
+	list_del(&d->head);
+	if (d->type == v4l2_int_type_slave
+	    && d->u.slave->master != NULL) {
+		d->u.slave->master->u.master->detach(d);
+		module_put(d->u.slave->master->module);
+		d->u.slave->master = NULL;
+	}
+	mutex_unlock(&mutex);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
+
+/* Adapted from search_extable in extable.c. */
+static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
+				       v4l2_int_ioctl_func *no_such_ioctl)
+{
+	const struct v4l2_int_ioctl_desc *first = slave->ioctls;
+	const struct v4l2_int_ioctl_desc *last =
+		first + slave->num_ioctls - 1;
+
+	while (first <= last) {
+		const struct v4l2_int_ioctl_desc *mid;
+
+		mid = (last - first) / 2 + first;
+
+		if (mid->num < cmd)
+			first = mid + 1;
+		else if (mid->num > cmd)
+			last = mid - 1;
+		else
+			return mid->func;
+	}
+
+	return no_such_ioctl;
+}
+
+static int no_such_ioctl_0(struct v4l2_int_device *d)
+{
+	return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
+{
+	return ((v4l2_int_ioctl_func_0 *)
+		find_ioctl(d->u.slave, cmd,
+			   (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0);
+
+static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
+{
+	return ((v4l2_int_ioctl_func_1 *)
+		find_ioctl(d->u.slave, cmd,
+			   (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1);
+
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/capture/v4l2-int-device.h
+++ linux-ein-5.4.0/drivers/media/platform/mxc/capture/v4l2-int-device.h
@@ -0,0 +1,309 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * include/media/v4l2-int-device.h
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright 2005-2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_INT_DEVICE_H
+#define V4L2_INT_DEVICE_H
+
+#include <media/v4l2-common.h>
+
+#define V4L2NAMESIZE 32
+
+/*
+ *
+ * The internal V4L2 device interface core.
+ *
+ */
+
+enum v4l2_int_type {
+	v4l2_int_type_master = 1,
+	v4l2_int_type_slave
+};
+
+struct module;
+
+struct v4l2_int_device;
+
+struct v4l2_int_master {
+	int (*attach)(struct v4l2_int_device *slave);
+	void (*detach)(struct v4l2_int_device *slave);
+};
+
+typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *);
+typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *);
+typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *);
+
+struct v4l2_int_ioctl_desc {
+	int num;
+	v4l2_int_ioctl_func *func;
+};
+
+struct v4l2_int_slave {
+	/* Don't touch master. */
+	struct v4l2_int_device *master;
+
+	char attach_to[V4L2NAMESIZE];
+
+	int num_ioctls;
+	struct v4l2_int_ioctl_desc *ioctls;
+};
+
+struct v4l2_int_device {
+	/* Don't touch head. */
+	struct list_head head;
+
+	struct module *module;
+
+	char name[V4L2NAMESIZE];
+
+	enum v4l2_int_type type;
+	union {
+		struct v4l2_int_master *master;
+		struct v4l2_int_slave *slave;
+	} u;
+
+	void *priv;
+};
+
+void v4l2_int_device_try_attach_all(void);
+
+int v4l2_int_device_register(struct v4l2_int_device *d);
+void v4l2_int_device_unregister(struct v4l2_int_device *d);
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd);
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg);
+
+/*
+ *
+ * Types and definitions for IOCTL commands.
+ *
+ */
+
+enum v4l2_power {
+	V4L2_POWER_OFF = 0,
+	V4L2_POWER_ON,
+	V4L2_POWER_STANDBY,
+};
+
+/* Slave interface type. */
+enum v4l2_if_type {
+	/*
+	 * Parallel 8-, 10- or 12-bit interface, used by for example
+	 * on certain image sensors.
+	 */
+	V4L2_IF_TYPE_BT656,
+};
+
+enum v4l2_if_type_bt656_mode {
+	/*
+	 * Modes without Bt synchronisation codes. Separate
+	 * synchronisation signal lines are used.
+	 */
+	V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+	V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT,
+	V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT,
+	/*
+	 * Use Bt synchronisation codes. The vertical and horizontal
+	 * synchronisation is done based on synchronisation codes.
+	 */
+	V4L2_IF_TYPE_BT656_MODE_BT_8BIT,
+	V4L2_IF_TYPE_BT656_MODE_BT_10BIT,
+};
+
+struct v4l2_if_type_bt656 {
+	/*
+	 * 0: Frame begins when vsync is high.
+	 * 1: Frame begins when vsync changes from low to high.
+	 */
+	unsigned frame_start_on_rising_vs:1;
+	/* Use Bt synchronisation codes for sync correction. */
+	unsigned bt_sync_correct:1;
+	/* Swap every two adjacent image data elements. */
+	unsigned swap:1;
+	/* Inverted latch clock polarity from slave. */
+	unsigned latch_clk_inv:1;
+	/* Hs polarity. 0 is active high, 1 active low. */
+	unsigned nobt_hs_inv:1;
+	/* Vs polarity. 0 is active high, 1 active low. */
+	unsigned nobt_vs_inv:1;
+	enum v4l2_if_type_bt656_mode mode;
+	/* Minimum accepted bus clock for slave (in Hz). */
+	u32 clock_min;
+	/* Maximum accepted bus clock for slave. */
+	u32 clock_max;
+	/*
+	 * Current wish of the slave. May only change in response to
+	 * ioctls that affect image capture.
+	 */
+	u32 clock_curr;
+};
+
+struct v4l2_ifparm {
+	enum v4l2_if_type if_type;
+	union {
+		struct v4l2_if_type_bt656 bt656;
+	} u;
+};
+
+/* IOCTL command numbers. */
+enum v4l2_int_ioctl_num {
+	/*
+	 *
+	 * "Proper" V4L ioctls, as in struct video_device.
+	 *
+	 */
+	vidioc_int_enum_fmt_cap_num = 1,
+	vidioc_int_g_fmt_cap_num,
+	vidioc_int_s_fmt_cap_num,
+	vidioc_int_try_fmt_cap_num,
+	vidioc_int_queryctrl_num,
+	vidioc_int_g_ctrl_num,
+	vidioc_int_s_ctrl_num,
+	vidioc_int_cropcap_num,
+	vidioc_int_g_crop_num,
+	vidioc_int_s_crop_num,
+	vidioc_int_g_parm_num,
+	vidioc_int_s_parm_num,
+	vidioc_int_querystd_num,
+	vidioc_int_s_std_num,
+	vidioc_int_s_video_routing_num,
+
+	/*
+	 *
+	 * Strictly internal ioctls.
+	 *
+	 */
+	/* Initialise the device when slave attaches to the master. */
+	vidioc_int_dev_init_num = 1000,
+	/* Delinitialise the device at slave detach. */
+	vidioc_int_dev_exit_num,
+	/* Set device power state. */
+	vidioc_int_s_power_num,
+	/*
+	* Get slave private data, e.g. platform-specific slave
+	* configuration used by the master.
+	*/
+	vidioc_int_g_priv_num,
+	/* Get slave interface parameters. */
+	vidioc_int_g_ifparm_num,
+	/* Does the slave need to be reset after VIDIOC_DQBUF? */
+	vidioc_int_g_needs_reset_num,
+	vidioc_int_enum_framesizes_num,
+	vidioc_int_enum_frameintervals_num,
+
+	/*
+	 *
+	 * VIDIOC_INT_* ioctls.
+	 *
+	 */
+	/* VIDIOC_INT_RESET */
+	vidioc_int_reset_num,
+	/* VIDIOC_INT_INIT */
+	vidioc_int_init_num,
+	/* VIDIOC_DBG_G_CHIP_IDENT */
+	vidioc_int_g_chip_ident_num,
+
+	/*
+	 *
+	 * Start of private ioctls.
+	 *
+	 */
+	vidioc_int_priv_start_num = 2000,
+};
+
+/*
+ *
+ * IOCTL wrapper functions for better type checking.
+ *
+ */
+
+#define V4L2_INT_WRAPPER_0(name)					\
+	static inline int vidioc_int_##name(struct v4l2_int_device *d)	\
+	{								\
+		return v4l2_int_ioctl_0(d, vidioc_int_##name##_num);	\
+	}								\
+									\
+	static inline struct v4l2_int_ioctl_desc			\
+	vidioc_int_##name##_cb(int (*func)				\
+			       (struct v4l2_int_device *))		\
+	{								\
+		struct v4l2_int_ioctl_desc desc;			\
+									\
+		desc.num = vidioc_int_##name##_num;			\
+		desc.func = (v4l2_int_ioctl_func *)func;		\
+									\
+		return desc;						\
+	}
+
+#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk)			\
+	static inline int vidioc_int_##name(struct v4l2_int_device *d,	\
+					    arg_type asterisk arg)	\
+	{								\
+		return v4l2_int_ioctl_1(d, vidioc_int_##name##_num,	\
+					(void *)(unsigned long)arg);	\
+	}								\
+									\
+	static inline struct v4l2_int_ioctl_desc			\
+	vidioc_int_##name##_cb(int (*func)				\
+			       (struct v4l2_int_device *,		\
+				arg_type asterisk))			\
+	{								\
+		struct v4l2_int_ioctl_desc desc;			\
+									\
+		desc.num = vidioc_int_##name##_num;			\
+		desc.func = (v4l2_int_ioctl_func *)func;		\
+									\
+		return desc;						\
+	}
+
+V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
+V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
+V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
+V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
+V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
+V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
+V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
+V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
+V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
+V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
+V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
+
+V4L2_INT_WRAPPER_0(dev_init);
+V4L2_INT_WRAPPER_0(dev_exit);
+V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, /*dummy arg*/);
+V4L2_INT_WRAPPER_1(g_priv, void, *);
+V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *);
+V4L2_INT_WRAPPER_1(g_needs_reset, void, *);
+V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *);
+V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *);
+
+V4L2_INT_WRAPPER_0(reset);
+V4L2_INT_WRAPPER_0(init);
+V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/output/Kconfig
+++ linux-ein-5.4.0/drivers/media/platform/mxc/output/Kconfig
@@ -0,0 +1,16 @@
+config VIDEO_MXC_IPU_OUTPUT
+	tristate "IPU v4l2 output support"
+	depends on VIDEO_MXC_OUTPUT && MXC_IPU
+	help
+	This is the video4linux2 driver for IPU post processing video output.
+
+config VIDEO_MXC_PXP_V4L2
+        tristate "MXC PxP V4L2 driver"
+        depends on VIDEO_DEV && VIDEO_V4L2
+        select VIDEOBUF_DMA_CONTIG
+        help
+          This is a video4linux driver for the Freescale PxP
+          (Pixel Pipeline). This module supports output overlay of
+          the MXC framebuffer on a video stream.
+
+          To compile this driver as a module, choose M here.
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/output/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/mxc/output/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o
+obj-$(CONFIG_VIDEO_MXC_PXP_V4L2)   += mxc_pxp_v4l2.o
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c
@@ -0,0 +1,1335 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/mxcfb.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mxc_pxp_v4l2.h"
+
+#define PXP_DRIVER_NAME			"pxp-v4l2"
+#define PXP_DRIVER_MAJOR		2
+#define PXP_DRIVER_MINOR		0
+
+#define PXP_DEF_BUFS			2
+#define PXP_MIN_PIX			8
+
+#define V4L2_OUTPUT_TYPE_INTERNAL	4
+
+static int video_nr = -1;	/* -1 ==> auto assign */
+static struct pxp_data_format pxp_s0_formats[] = {
+	{
+		.name = "24-bit RGB",
+		.bpp = 4,
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	}, {
+		.name = "16-bit RGB 5:6:5",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	}, {
+		.name = "16-bit RGB 5:5:5",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_RGB555,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	}, {
+		.name = "YUV 4:2:0 Planar",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+	}, {
+		.name = "YUV 4:2:2 Planar",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+	}, {
+		.name = "UYVY",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+	}, {
+		.name = "YUYV",
+		.bpp = 2,
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+	}, {
+		.name = "YUV32",
+		.bpp = 4,
+		.fourcc = V4L2_PIX_FMT_YUV32,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+};
+
+static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt)
+{
+	u32 pxp_fmt = 0;
+
+	if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24)
+		pxp_fmt = PXP_PIX_FMT_XRGB32;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565)
+		pxp_fmt = PXP_PIX_FMT_RGB565;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
+		pxp_fmt = PXP_PIX_FMT_RGB555;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420)
+		pxp_fmt = PXP_PIX_FMT_YUV420P;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P)
+		pxp_fmt = PXP_PIX_FMT_YUV422P;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_UYVY)
+		pxp_fmt = PXP_PIX_FMT_UYVY;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV32)
+		pxp_fmt = PXP_PIX_FMT_VUY444;
+	else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUYV)
+		pxp_fmt = PXP_PIX_FMT_YUYV;
+
+	return pxp_fmt;
+}
+struct v4l2_queryctrl pxp_controls[] = {
+	{
+		.id 		= V4L2_CID_HFLIP,
+		.type 		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name 		= "Horizontal Flip",
+		.minimum 	= 0,
+		.maximum 	= 1,
+		.step 		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+	}, {
+		.id		= V4L2_CID_VFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Vertical Flip",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+	}, {
+		.id		= V4L2_CID_PRIVATE_BASE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Rotation",
+		.minimum	= 0,
+		.maximum	= 270,
+		.step		= 90,
+		.default_value	= 0,
+		.flags		= 0,
+	}, {
+		.id		= V4L2_CID_PRIVATE_BASE + 1,
+		.name		= "Background Color",
+		.minimum	= 0,
+		.maximum	= 0xFFFFFF,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+	}, {
+		.id		= V4L2_CID_PRIVATE_BASE + 2,
+		.name		= "Set S0 Chromakey",
+		.minimum	= -1,
+		.maximum	= 0xFFFFFF,
+		.step		= 1,
+		.default_value	= -1,
+		.flags		= 0,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+	}, {
+		.id		= V4L2_CID_PRIVATE_BASE + 3,
+		.name		= "YUV Colorspace",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+		.flags		= 0,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+	},
+};
+
+static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf)
+{
+	dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr);
+	dev_dbg(&pxp->pdev->dev,
+			"free dma size:0x%x, paddr:0x%x\n",
+			buf->size, buf->paddr);
+	memset(buf, 0, sizeof(*buf));
+}
+
+static int alloc_dma_buf(struct pxps *pxp, struct dma_mem *buf)
+{
+
+	buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr,
+						GFP_DMA | GFP_KERNEL);
+	if (!buf->vaddr) {
+		dev_err(&pxp->pdev->dev,
+			"cannot get dma buf size:0x%x\n", buf->size);
+		return -ENOMEM;
+	}
+	dev_dbg(&pxp->pdev->dev,
+		"alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr);
+	return 0;
+}
+
+/* callback function */
+static void video_dma_done(void *arg)
+{
+	struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+	struct dma_chan *chan = tx_desc->txd.chan;
+	struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+	struct pxps *pxp = pxp_chan->client;
+	struct videobuf_buffer *vb;
+	struct timespec64 ts;
+
+	dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+			tx_desc->txd.cookie,
+			pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0);
+
+	spin_lock(&pxp->lock);
+	if (pxp->active) {
+		vb = &pxp->active->vb;
+
+		list_del_init(&vb->queue);
+		vb->state = VIDEOBUF_DONE;
+		ktime_get_real_ts64(&ts);
+		vb->ts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+		vb->field_count++;
+		wake_up(&vb->done);
+	}
+
+	if (list_empty(&pxp->outq)) {
+		pxp->active = NULL;
+		spin_unlock(&pxp->lock);
+
+		return;
+	}
+
+	pxp->active = list_entry(pxp->outq.next,
+				     struct pxp_buffer, vb.queue);
+	pxp->active->vb.state = VIDEOBUF_ACTIVE;
+	spin_unlock(&pxp->lock);
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+	if (imx_dma_is_pxp(chan))
+		return true;
+	else
+		return false;
+}
+
+static int acquire_dma_channel(struct pxps *pxp)
+{
+	dma_cap_mask_t mask;
+	struct dma_chan *chan;
+	struct pxp_channel **pchan = &pxp->pxp_channel[0];
+
+	if (*pchan) {
+		struct videobuf_buffer *vb, *_vb;
+		dma_release_channel(&(*pchan)->dma_chan);
+		*pchan = NULL;
+		pxp->active = NULL;
+		list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) {
+			list_del_init(&vb->queue);
+			vb->state = VIDEOBUF_ERROR;
+			wake_up(&vb->done);
+		}
+	}
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_PRIVATE, mask);
+	chan = dma_request_channel(mask, chan_filter, NULL);
+	if (!chan)
+		return -EBUSY;
+
+	*pchan = to_pxp_channel(chan);
+	(*pchan)->client = pxp;
+
+	return 0;
+}
+
+static int _get_fbinfo(struct fb_info **fbi)
+{
+	int i;
+	for (i = 0; i < num_registered_fb; i++) {
+		char *idstr = registered_fb[i]->fix.id;
+		if (strncmp(idstr, "mxs", 3) == 0) {
+			*fbi = registered_fb[i];
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+static int pxp_set_fbinfo(struct pxps *pxp)
+{
+	struct v4l2_framebuffer *fb = &pxp->fb;
+	int err;
+
+	err = _get_fbinfo(&pxp->fbi);
+	if (err)
+		return err;
+
+	fb->fmt.width = pxp->fbi->var.xres;
+	fb->fmt.height = pxp->fbi->var.yres;
+	pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres;
+	if (pxp->fbi->var.bits_per_pixel == 16)
+		fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+	else
+		fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24;
+
+	fb->base = (void *)pxp->fbi->fix.smem_start;
+
+	return 0;
+}
+
+static int _get_cur_fb_blank(struct pxps *pxp)
+{
+	struct fb_info *fbi;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	err = _get_fbinfo(&fbi);
+	if (err)
+		return err;
+
+	if (fbi->fbops->fb_ioctl) {
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
+				(unsigned int)(&pxp->fb_blank));
+		set_fs(old_fs);
+	}
+
+	return err;
+}
+
+static int pxp_show_buf(struct pxps *pxp, unsigned long paddr)
+{
+	struct fb_info *fbi = pxp->fbi;
+	int ret = -EINVAL;
+
+	if (paddr == 0) {
+		dev_err(&pxp->pdev->dev, "Invalid paddr\n");
+		return ret;
+	}
+
+	console_lock();
+	fbi->fix.smem_start = paddr;
+	ret = fb_pan_display(fbi, &fbi->var);
+	console_unlock();
+
+	return ret;
+}
+
+static int set_fb_blank(int blank)
+{
+	struct fb_info *fbi;
+	int err = 0;
+
+	err = _get_fbinfo(&fbi);
+	if (err)
+		return err;
+
+	console_lock();
+	fb_blank(fbi, blank);
+	console_unlock();
+
+	return err;
+}
+
+static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+
+	if (vc->id == V4L2_CID_HFLIP) {
+		pxp->pxp_conf.proc_data.hflip = vc->value;
+	} else if (vc->id == V4L2_CID_VFLIP) {
+		pxp->pxp_conf.proc_data.vflip = vc->value;
+	} else if (vc->id == V4L2_CID_PRIVATE_BASE) {
+		if (vc->value % 90)
+			return -ERANGE;
+		pxp->pxp_conf.proc_data.rotate = vc->value;
+	} else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) {
+		pxp->pxp_conf.proc_data.bgcolor = vc->value;
+	} else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) {
+		pxp->pxp_conf.s0_param.color_key = vc->value;
+	} else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) {
+		pxp->pxp_conf.proc_data.yuv = vc->value;
+	}
+
+	return 0;
+}
+
+static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+	if (vc->id == V4L2_CID_HFLIP)
+		vc->value = pxp->pxp_conf.proc_data.hflip;
+	else if (vc->id == V4L2_CID_VFLIP)
+		vc->value = pxp->pxp_conf.proc_data.vflip;
+	else if (vc->id == V4L2_CID_PRIVATE_BASE)
+		vc->value = pxp->pxp_conf.proc_data.rotate;
+	else if (vc->id == V4L2_CID_PRIVATE_BASE + 1)
+		vc->value = pxp->pxp_conf.proc_data.bgcolor;
+	else if (vc->id == V4L2_CID_PRIVATE_BASE + 2)
+		vc->value = pxp->pxp_conf.s0_param.color_key;
+	else if (vc->id == V4L2_CID_PRIVATE_BASE + 3)
+		vc->value = pxp->pxp_conf.proc_data.yuv;
+
+	return 0;
+}
+
+static int pxp_enumoutput(struct file *file, void *fh,
+			struct v4l2_output *o)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	if (o->index > 1)
+		return -EINVAL;
+
+	memset(o, 0, sizeof(struct v4l2_output));
+	if (o->index == 0) {
+		strcpy(o->name, "PxP Display Output");
+		pxp->output = 0;
+	} else {
+		strcpy(o->name, "PxP Virtual Output");
+		pxp->output = 1;
+	}
+	o->type = V4L2_OUTPUT_TYPE_INTERNAL;
+	o->std = 0;
+	o->reserved[0] = pxp->outbuf.paddr;
+
+	return 0;
+}
+
+static int pxp_g_output(struct file *file, void *fh,
+			unsigned int *i)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	*i = pxp->output;
+
+	return 0;
+}
+
+static int pxp_s_output(struct file *file, void *fh,
+			unsigned int i)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct v4l2_pix_format *fmt = (struct v4l2_pix_format*)(&pxp->fb.fmt);
+	u32 size;
+	int ret, bpp;
+
+	if (i > 1)
+		return -EINVAL;
+
+	/* Output buffer is same format as fbdev */
+	if (fmt->pixelformat == V4L2_PIX_FMT_RGB24  ||
+		fmt->pixelformat == V4L2_PIX_FMT_YUV32)
+		bpp = 4;
+	else
+		bpp = 2;
+
+	size = fmt->width * fmt->height * bpp;
+	if (size > pxp->outbuf.size) {
+		if (pxp->outbuf.vaddr)
+			free_dma_buf(pxp, &pxp->outbuf);
+		pxp->outbuf.size = size;
+		ret = alloc_dma_buf(pxp, &pxp->outbuf);
+		if (ret < 0)
+			return ret;
+	}
+	memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+	pxp->pxp_conf.out_param.width = fmt->width;
+	pxp->pxp_conf.out_param.height = fmt->height;
+	if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
+		pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_XRGB32;
+	else
+		pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+
+	return 0;
+}
+
+static int pxp_enum_fmt_video_output(struct file *file, void *fh,
+				struct v4l2_fmtdesc *fmt)
+{
+	enum v4l2_buf_type type = fmt->type;
+	unsigned int index = fmt->index;
+
+	if (fmt->index >= ARRAY_SIZE(pxp_s0_formats))
+		return -EINVAL;
+
+	memset(fmt, 0, sizeof(struct v4l2_fmtdesc));
+	fmt->index = index;
+	fmt->type = type;
+	fmt->pixelformat = pxp_s0_formats[index].fourcc;
+	strcpy(fmt->description, pxp_s0_formats[index].name);
+
+	return 0;
+}
+
+static int pxp_g_fmt_video_output(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct v4l2_pix_format *pf = &f->fmt.pix;
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct pxp_data_format *fmt = pxp->s0_fmt;
+
+	pf->width = pxp->pxp_conf.s0_param.width;
+	pf->height = pxp->pxp_conf.s0_param.height;
+	pf->pixelformat = fmt->fourcc;
+	pf->field = V4L2_FIELD_NONE;
+	pf->bytesperline = fmt->bpp * pf->width;
+	pf->sizeimage = pf->bytesperline * pf->height;
+	pf->colorspace = fmt->colorspace;
+	pf->priv = 0;
+
+	return 0;
+}
+
+static struct pxp_data_format *pxp_get_format(struct v4l2_format *f)
+{
+	struct pxp_data_format *fmt;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) {
+		fmt = &pxp_s0_formats[i];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(pxp_s0_formats))
+		return NULL;
+
+	return &pxp_s0_formats[i];
+}
+
+static int pxp_try_fmt_video_output(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	int w = f->fmt.pix.width;
+	int h = f->fmt.pix.height;
+	struct pxp_data_format *fmt = pxp_get_format(f);
+
+	if (!fmt)
+		return -EINVAL;
+
+	w = min(w, 2040);
+	w = max(w, 8);
+	h = min(h, 2040);
+	h = max(h, 8);
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = w;
+	f->fmt.pix.height = h;
+	f->fmt.pix.pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int pxp_s_fmt_video_output(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct v4l2_pix_format *pf = &f->fmt.pix;
+	int ret;
+
+	ret = acquire_dma_channel(pxp);
+	if (ret < 0)
+		return ret;
+
+	ret = pxp_try_fmt_video_output(file, fh, f);
+	if (ret == 0) {
+		pxp->s0_fmt = pxp_get_format(f);
+		pxp->pxp_conf.s0_param.pixel_fmt =
+			v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc);
+		pxp->pxp_conf.s0_param.width = pf->width;
+		pxp->pxp_conf.s0_param.height = pf->height;
+	}
+
+
+	return ret;
+}
+
+static int pxp_g_fmt_output_overlay(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct v4l2_window *wf = &f->fmt.win;
+
+	memset(wf, 0, sizeof(struct v4l2_window));
+	wf->chromakey = pxp->s1_chromakey;
+	wf->global_alpha = pxp->global_alpha;
+	wf->field = V4L2_FIELD_NONE;
+	wf->clips = NULL;
+	wf->clipcount = 0;
+	wf->bitmap = NULL;
+	wf->w.left = pxp->pxp_conf.proc_data.srect.left;
+	wf->w.top = pxp->pxp_conf.proc_data.srect.top;
+	wf->w.width = pxp->pxp_conf.proc_data.srect.width;
+	wf->w.height = pxp->pxp_conf.proc_data.srect.height;
+
+	return 0;
+}
+
+static int pxp_try_fmt_output_overlay(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct v4l2_window *wf = &f->fmt.win;
+	struct v4l2_rect srect;
+	u32 s1_chromakey = wf->chromakey;
+	u8 global_alpha = wf->global_alpha;
+
+	memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect));
+
+	pxp_g_fmt_output_overlay(file, fh, f);
+
+	wf->chromakey = s1_chromakey;
+	wf->global_alpha = global_alpha;
+
+	/* Constrain parameters to the input buffer */
+	wf->w.left = srect.left;
+	wf->w.top = srect.top;
+	wf->w.width = min(srect.width,
+			((__u32)pxp->pxp_conf.s0_param.width - wf->w.left));
+	wf->w.height = min(srect.height,
+			((__u32)pxp->pxp_conf.s0_param.height - wf->w.top));
+
+	return 0;
+}
+
+static int pxp_s_fmt_output_overlay(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	struct v4l2_window *wf = &f->fmt.win;
+	int ret = pxp_try_fmt_output_overlay(file, fh, f);
+
+	if (ret == 0) {
+		pxp->global_alpha = wf->global_alpha;
+		pxp->s1_chromakey = wf->chromakey;
+		pxp->pxp_conf.proc_data.srect.left = wf->w.left;
+		pxp->pxp_conf.proc_data.srect.top = wf->w.top;
+		pxp->pxp_conf.proc_data.srect.width = wf->w.width;
+		pxp->pxp_conf.proc_data.srect.height = wf->w.height;
+		pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha;
+		pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey;
+		pxp->pxp_conf.ol_param[0].color_key_enable =
+					pxp->s1_chromakey_state;
+	}
+
+	return ret;
+}
+
+static int pxp_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *r)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	return videobuf_reqbufs(&pxp->s0_vbq, r);
+}
+
+static int pxp_querybuf(struct file *file, void *priv,
+			struct v4l2_buffer *b)
+{
+	int ret;
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	ret = videobuf_querybuf(&pxp->s0_vbq, b);
+	if (!ret) {
+		struct videobuf_buffer *vb = pxp->s0_vbq.bufs[b->index];
+		if (b->flags & V4L2_BUF_FLAG_MAPPED)
+			b->m.offset = videobuf_to_dma_contig(vb);
+	}
+
+	return ret;
+}
+
+static int pxp_qbuf(struct file *file, void *priv,
+			struct v4l2_buffer *b)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	return videobuf_qbuf(&pxp->s0_vbq, b);
+}
+
+static int pxp_dqbuf(struct file *file, void *priv,
+			struct v4l2_buffer *b)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int pxp_streamon(struct file *file, void *priv,
+			enum v4l2_buf_type t)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	int ret = 0;
+
+	if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	_get_cur_fb_blank(pxp);
+	set_fb_blank(FB_BLANK_UNBLANK);
+
+	ret = videobuf_streamon(&pxp->s0_vbq);
+
+	if (!ret && (pxp->output == 0))
+		pxp_show_buf(pxp, pxp->outbuf.paddr);
+
+	return ret;
+}
+
+static int pxp_streamoff(struct file *file, void *priv,
+			enum v4l2_buf_type t)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	int ret = 0;
+
+	if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	ret = videobuf_streamoff(&pxp->s0_vbq);
+
+	pxp_show_buf(pxp, (unsigned long)pxp->fb.base);
+
+	if (pxp->fb_blank)
+		set_fb_blank(FB_BLANK_POWERDOWN);
+
+	return ret;
+}
+
+static int pxp_buf_setup(struct videobuf_queue *q,
+			unsigned int *count, unsigned *size)
+{
+	struct pxps *pxp = q->priv_data;
+
+	*size = pxp->pxp_conf.s0_param.width *
+		pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp;
+
+	if (0 == *count)
+		*count = PXP_DEF_BUFS;
+
+	return 0;
+}
+
+static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf)
+{
+	struct videobuf_buffer *vb = &buf->vb;
+
+	BUG_ON(in_interrupt());
+
+	pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/*
+	 * This waits until this buffer is out of danger, i.e., until it is no
+	 * longer in STATE_QUEUED or STATE_ACTIVE
+	 */
+	videobuf_waiton(q, vb, 0, 0);
+
+	videobuf_dma_contig_free(q, vb);
+	buf->txd = NULL;
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxp_buf_prepare(struct videobuf_queue *q,
+			struct videobuf_buffer *vb,
+			enum v4l2_field field)
+{
+	struct pxps *pxp = q->priv_data;
+	struct pxp_config_data *pxp_conf = &pxp->pxp_conf;
+	struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+	struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+	struct pxp_tx_desc *desc;
+	int ret = 0;
+	int i, length;
+
+	if (!pxp->outbuf.paddr)  {
+		dev_err(&pxp->pdev->dev, "Not allocate memory for "
+			"PxP Out buffer?\n");
+		return -ENOMEM;
+	}
+
+	vb->width = pxp->pxp_conf.s0_param.width;
+	vb->height = pxp->pxp_conf.s0_param.height;
+	vb->size = vb->width * vb->height * pxp->s0_fmt->bpp;
+	vb->field = V4L2_FIELD_NONE;
+	if (vb->state != VIDEOBUF_NEEDS_INIT)
+		pxp_buf_free(q, buf);
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		struct pxp_channel *pchan = pxp->pxp_channel[0];
+		struct scatterlist *sg = &buf->sg[0];
+
+		/* This actually (allocates and) maps buffers */
+		ret = videobuf_iolock(q, vb, NULL);
+		if (ret) {
+			pr_err("fail to call videobuf_iolock, ret = %d\n", ret);
+			goto fail;
+		}
+
+		/*
+		 * sg[0] for input(S0)
+		 * Sg[1] for output
+		 */
+		sg_init_table(sg, 3);
+
+		buf->txd = pchan->dma_chan.device->device_prep_slave_sg(
+			&pchan->dma_chan, sg, 3, DMA_FROM_DEVICE,
+			DMA_PREP_INTERRUPT, NULL);
+		if (!buf->txd) {
+			ret = -EIO;
+			goto fail;
+		}
+
+		buf->txd->callback_param	= buf->txd;
+		buf->txd->callback		= video_dma_done;
+
+		desc = to_tx_desc(buf->txd);
+		length = desc->len;
+		for (i = 0; i < length; i++) {
+			if (i == 0) {/* S0 */
+				memcpy(&desc->proc_data, proc_data,
+					sizeof(struct pxp_proc_data));
+				pxp_conf->s0_param.paddr =
+						videobuf_to_dma_contig(vb);
+				memcpy(&desc->layer_param.s0_param,
+					&pxp_conf->s0_param,
+					sizeof(struct pxp_layer_param));
+			} else if (i == 1) { /* Output */
+				/* we should always pass the output
+				 * width and height which is the value
+				 * after been rotated.
+				 */
+				pxp_conf->out_param.width =
+					pxp->fb.fmt.width;
+				pxp_conf->out_param.height =
+					pxp->fb.fmt.height;
+
+				pxp_conf->out_param.paddr = pxp->outbuf.paddr;
+				memcpy(&desc->layer_param.out_param,
+					&pxp_conf->out_param,
+					sizeof(struct pxp_layer_param));
+			} else if (pxp_conf->ol_param[0].combine_enable) {
+				/* Overlay */
+				pxp_conf->ol_param[0].paddr =
+						(dma_addr_t)pxp->fb.base;
+				pxp_conf->ol_param[0].width = pxp->fb.fmt.width;
+				pxp_conf->ol_param[0].height =
+						pxp->fb.fmt.height;
+				pxp_conf->ol_param[0].pixel_fmt =
+						pxp_conf->out_param.pixel_fmt;
+				memcpy(&desc->layer_param.ol_param,
+				       &pxp_conf->ol_param[0],
+				       sizeof(struct pxp_layer_param));
+			}
+
+			desc = desc->next;
+		}
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	return 0;
+
+fail:
+	pxp_buf_free(q, buf);
+	return ret;
+}
+
+
+static void pxp_buf_queue(struct videobuf_queue *q,
+			struct videobuf_buffer *vb)
+{
+	struct pxps *pxp = q->priv_data;
+	struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+	struct dma_async_tx_descriptor *txd = buf->txd;
+	struct pxp_channel *pchan = pxp->pxp_channel[0];
+	dma_cookie_t cookie;
+
+	BUG_ON(!irqs_disabled());
+
+	list_add_tail(&vb->queue, &pxp->outq);
+
+	if (!pxp->active) {
+		pxp->active = buf;
+		vb->state = VIDEOBUF_ACTIVE;
+	} else {
+		vb->state = VIDEOBUF_QUEUED;
+	}
+
+	spin_unlock_irq(&pxp->lock);
+
+	cookie = txd->tx_submit(txd);
+	dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n",
+				cookie, sg_dma_address(&buf->sg[0]));
+	mdelay(5);
+	/* trigger ePxP */
+	dma_async_issue_pending(&pchan->dma_chan);
+
+	spin_lock_irq(&pxp->lock);
+
+	if (cookie >= 0)
+		return;
+
+	/* Submit error */
+	pr_err("%s: Submit error\n", __func__);
+	vb->state = VIDEOBUF_PREPARED;
+
+	list_del_init(&vb->queue);
+
+	if (pxp->active == buf)
+		pxp->active = NULL;
+}
+
+static void pxp_buf_release(struct videobuf_queue *q,
+			struct videobuf_buffer *vb)
+{
+	struct pxps *pxp = q->priv_data;
+	struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pxp->lock, flags);
+	if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+	    !list_empty(&vb->queue)) {
+		vb->state = VIDEOBUF_ERROR;
+
+		list_del_init(&vb->queue);
+		if (pxp->active == buf)
+			pxp->active = NULL;
+	}
+	spin_unlock_irqrestore(&pxp->lock, flags);
+
+	pxp_buf_free(q, buf);
+}
+
+static struct videobuf_queue_ops pxp_vbq_ops = {
+	.buf_setup	= pxp_buf_setup,
+	.buf_prepare	= pxp_buf_prepare,
+	.buf_queue	= pxp_buf_queue,
+	.buf_release	= pxp_buf_release,
+};
+
+static int pxp_querycap(struct file *file, void *fh,
+			struct v4l2_capability *cap)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	memset(cap, 0, sizeof(*cap));
+	strcpy(cap->driver, "pxp");
+	strcpy(cap->card, "pxp");
+	strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev),
+		sizeof(cap->bus_info));
+
+	cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR;
+
+	cap->device_caps = V4L2_CAP_STREAMING |	V4L2_CAP_VIDEO_OUTPUT |
+				V4L2_CAP_VIDEO_OVERLAY;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int pxp_g_fbuf(struct file *file, void *priv,
+			struct v4l2_framebuffer *fb)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	memset(fb, 0, sizeof(*fb));
+
+	fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+			 V4L2_FBUF_CAP_CHROMAKEY |
+			 V4L2_FBUF_CAP_LOCAL_ALPHA |
+			 V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+	if (pxp->global_alpha_state)
+		fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+	if (pxp->s1_chromakey_state)
+		fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+	return 0;
+}
+
+static int pxp_s_fbuf(struct file *file, void *priv,
+			const struct v4l2_framebuffer *fb)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	pxp->overlay_state =
+		(fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+	pxp->global_alpha_state =
+		(fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+	pxp->s1_chromakey_state =
+		(fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+
+	pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state;
+	pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state;
+
+	return 0;
+}
+
+static int pxp_g_selection(struct file *file, void *fh,
+			  struct v4l2_selection *s)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+		return -EINVAL;
+
+	s->r.left = pxp->pxp_conf.proc_data.drect.left;
+	s->r.top = pxp->pxp_conf.proc_data.drect.top;
+	s->r.width = pxp->pxp_conf.proc_data.drect.width;
+	s->r.height = pxp->pxp_conf.proc_data.drect.height;
+
+	return 0;
+}
+
+static int pxp_s_selection(struct file *file, void *fh,
+			 struct v4l2_selection *s)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	int l = s->r.left;
+	int t = s->r.top;
+	int w = s->r.width;
+	int h = s->r.height;
+	int fbw = pxp->fb.fmt.width;
+	int fbh = pxp->fb.fmt.height;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+		return -EINVAL;
+
+	/* Constrain parameters to FB limits */
+	w = min(w, fbw);
+	w = max(w, PXP_MIN_PIX);
+	h = min(h, fbh);
+	h = max(h, PXP_MIN_PIX);
+
+	/* Round up values to PxP pixel block */
+	l = roundup(l, PXP_MIN_PIX);
+	t = roundup(t, PXP_MIN_PIX);
+	w = roundup(w, PXP_MIN_PIX);
+	h = roundup(h, PXP_MIN_PIX);
+
+	if ((l + w) > fbw)
+		l = 0;
+	if ((t + h) > fbh)
+		t = 0;
+
+	pxp->pxp_conf.proc_data.drect.left = l;
+	pxp->pxp_conf.proc_data.drect.top = t;
+	pxp->pxp_conf.proc_data.drect.width = w;
+	pxp->pxp_conf.proc_data.drect.height = h;
+
+	memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+	return 0;
+}
+
+static int pxp_queryctrl(struct file *file, void *priv,
+			 struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+		if (qc->id && qc->id == pxp_controls[i].id) {
+			memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static int pxp_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *vc)
+{
+	int i;
+
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+		if (vc->id == pxp_controls[i].id)
+			return pxp_get_cstate(pxp, vc);
+
+	return -EINVAL;
+}
+
+static int pxp_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *vc)
+{
+	int i;
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+		if (vc->id == pxp_controls[i].id) {
+			if (vc->value < pxp_controls[i].minimum ||
+			    vc->value > pxp_controls[i].maximum)
+				return -ERANGE;
+			return pxp_set_cstate(pxp, vc);
+		}
+
+	memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+	return -EINVAL;
+}
+
+void pxp_release(struct video_device *vfd)
+{
+	struct pxps *pxp = video_get_drvdata(vfd);
+
+	spin_lock(&pxp->lock);
+	video_device_release(vfd);
+	spin_unlock(&pxp->lock);
+}
+
+static int pxp_open(struct file *file)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	int ret = 0;
+
+	mutex_lock(&pxp->mutex);
+	pxp->users++;
+
+	if (pxp->users > 1) {
+		pxp->users--;
+		ret = -EBUSY;
+		goto out;
+	}
+out:
+	mutex_unlock(&pxp->mutex);
+	if (ret)
+		return ret;
+
+	ret = pxp_set_fbinfo(pxp);
+	if (ret) {
+		dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n");
+		return ret;
+	}
+
+	videobuf_queue_dma_contig_init(&pxp->s0_vbq,
+				&pxp_vbq_ops,
+				&pxp->pdev->dev,
+				&pxp->lock,
+				V4L2_BUF_TYPE_VIDEO_OUTPUT,
+				V4L2_FIELD_NONE,
+				sizeof(struct pxp_buffer),
+				pxp,
+				NULL);
+	dev_dbg(&pxp->pdev->dev, "call pxp_open\n");
+
+	return 0;
+}
+
+static int pxp_close(struct file *file)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+	pxp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	videobuf_stop(&pxp->s0_vbq);
+	videobuf_mmap_free(&pxp->s0_vbq);
+	pxp->active = NULL;
+
+	mutex_lock(&pxp->mutex);
+	pxp->users--;
+	mutex_unlock(&pxp->mutex);
+
+	return 0;
+}
+
+static int pxp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct pxps *pxp = video_get_drvdata(video_devdata(file));
+	int ret;
+
+	ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations pxp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pxp_open,
+	.release	= pxp_close,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= pxp_mmap,
+};
+
+static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
+	.vidioc_querycap		= pxp_querycap,
+
+	.vidioc_reqbufs			= pxp_reqbufs,
+	.vidioc_querybuf		= pxp_querybuf,
+	.vidioc_qbuf			= pxp_qbuf,
+	.vidioc_dqbuf			= pxp_dqbuf,
+
+	.vidioc_streamon		= pxp_streamon,
+	.vidioc_streamoff		= pxp_streamoff,
+
+	.vidioc_enum_output		= pxp_enumoutput,
+	.vidioc_g_output		= pxp_g_output,
+	.vidioc_s_output		= pxp_s_output,
+
+	.vidioc_enum_fmt_vid_out	= pxp_enum_fmt_video_output,
+	.vidioc_try_fmt_vid_out		= pxp_try_fmt_video_output,
+	.vidioc_g_fmt_vid_out		= pxp_g_fmt_video_output,
+	.vidioc_s_fmt_vid_out		= pxp_s_fmt_video_output,
+
+	.vidioc_try_fmt_vid_out_overlay	= pxp_try_fmt_output_overlay,
+	.vidioc_g_fmt_vid_out_overlay	= pxp_g_fmt_output_overlay,
+	.vidioc_s_fmt_vid_out_overlay	= pxp_s_fmt_output_overlay,
+
+	.vidioc_g_fbuf			= pxp_g_fbuf,
+	.vidioc_s_fbuf			= pxp_s_fbuf,
+
+	.vidioc_g_selection		= pxp_g_selection,
+	.vidioc_s_selection		= pxp_s_selection,
+
+	.vidioc_queryctrl		= pxp_queryctrl,
+	.vidioc_g_ctrl			= pxp_g_ctrl,
+	.vidioc_s_ctrl			= pxp_s_ctrl,
+};
+
+static const struct video_device pxp_template = {
+	.name				= "PxP",
+	.device_caps 			= V4L2_CAP_VIDEO_OUTPUT |
+						V4L2_CAP_VIDEO_OVERLAY |
+						V4L2_CAP_STREAMING,
+	.vfl_dir			= VFL_DIR_TX,
+	.fops				= &pxp_fops,
+	.release			= pxp_release,
+	.minor				= -1,
+	.ioctl_ops			= &pxp_ioctl_ops,
+};
+
+static const struct of_device_id imx_pxpv4l2_dt_ids[] = {
+	{ .compatible = "fsl,imx6sl-pxp-v4l2", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids);
+
+static int pxp_probe(struct platform_device *pdev)
+{
+	struct pxps *pxp;
+	struct v4l2_device *v4l2_dev;
+	int err = 0;
+
+	pxp = kzalloc(sizeof(*pxp), GFP_KERNEL);
+	if (!pxp) {
+		dev_err(&pdev->dev, "failed to allocate control object\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	dev_set_drvdata(&pdev->dev, pxp);
+
+	v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL);
+	if (!v4l2_dev) {
+		dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n");
+		err = -ENOMEM;
+		goto freeirq;
+	}
+
+	err = v4l2_device_register(&pdev->dev, v4l2_dev);
+	if (err) {
+		dev_err(&pdev->dev, "register v4l2 device failed\n");
+		goto freev4l2;
+	}
+
+	INIT_LIST_HEAD(&pxp->outq);
+	spin_lock_init(&pxp->lock);
+	mutex_init(&pxp->mutex);
+
+	pxp->pdev = pdev;
+
+	pxp->vdev = video_device_alloc();
+	if (!pxp->vdev) {
+		dev_err(&pdev->dev, "video_device_alloc() failed\n");
+		err = -ENOMEM;
+		goto relv4l2;
+	}
+
+	memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template));
+	pxp->vdev->v4l2_dev = v4l2_dev;
+	video_set_drvdata(pxp->vdev, pxp);
+
+	err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register video device\n");
+		goto freevdev;
+	}
+
+	dev_info(&pdev->dev, "initialized\n");
+
+exit:
+	return err;
+
+freevdev:
+	video_device_release(pxp->vdev);
+relv4l2:
+	v4l2_device_unregister(v4l2_dev);
+freev4l2:
+	kfree(v4l2_dev);
+freeirq:
+	kfree(pxp);
+
+	return err;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+	struct pxps *pxp = platform_get_drvdata(pdev);
+	struct v4l2_device *v4l2_dev = pxp->vdev->v4l2_dev;
+
+	video_unregister_device(pxp->vdev);
+	video_device_release(pxp->vdev);
+	v4l2_device_unregister(v4l2_dev);
+	kfree(v4l2_dev);
+
+	free_dma_buf(pxp, &pxp->outbuf);
+
+	kfree(pxp);
+
+	return 0;
+}
+
+static struct platform_driver pxp_driver = {
+	.driver 	= {
+		.name	= PXP_DRIVER_NAME,
+		.of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids),
+	},
+	.probe		= pxp_probe,
+	.remove		= pxp_remove,
+};
+
+module_platform_driver(pxp_driver);
+
+module_param(video_nr, int, 0444);
+MODULE_DESCRIPTION("MXC PxP V4L2 driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h
+++ linux-ein-5.4.0/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#ifndef	_MXC_PXP_V4L2_H
+#define	_MXC_PXP_V4L2_H
+
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+
+struct pxp_buffer {
+	/* Must be first! */
+	struct videobuf_buffer vb;
+
+	/* One descriptor per scatterlist (per frame) */
+	struct dma_async_tx_descriptor		*txd;
+
+	struct scatterlist			sg[3];
+};
+
+struct dma_mem {
+	void *vaddr;
+	dma_addr_t paddr;
+	size_t size;
+};
+
+struct pxps {
+	struct platform_device *pdev;
+
+	spinlock_t lock;
+	struct mutex mutex;
+	int users;
+
+	struct video_device *vdev;
+
+	struct videobuf_queue s0_vbq;
+	struct pxp_buffer *active;
+	struct list_head outq;
+	struct pxp_channel	*pxp_channel[1];	/* We need 1 channel */
+	struct pxp_config_data pxp_conf;
+	struct dma_mem outbuf;
+
+	int output;
+
+	/* Current S0 configuration */
+	struct pxp_data_format *s0_fmt;
+
+	struct fb_info *fbi;
+	struct v4l2_framebuffer fb;
+
+	/* Output overlay support */
+	int overlay_state;
+	int global_alpha_state;
+	u8  global_alpha;
+	int s1_chromakey_state;
+	u32 s1_chromakey;
+
+	int fb_blank;
+};
+
+struct pxp_data_format {
+	char *name;
+	unsigned int bpp;
+	u32 fourcc;
+	enum v4l2_colorspace colorspace;
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/media/platform/mxc/output/mxc_vout.c
+++ linux-ein-5.4.0/drivers/media/platform/mxc/output/mxc_vout.c
@@ -0,0 +1,2300 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/mxc_v4l2.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define UYVY_BLACK	(0x00800080)
+#define RGB_BLACK	(0x0)
+#define UV_BLACK	(0x80)
+#define Y_BLACK		(0x0)
+
+#define MAX_FB_NUM	6
+#define FB_BUFS		3
+#define VDOA_FB_BUFS	(FB_BUFS - 1)
+#define VALID_HEIGHT_1080P	(1080)
+#define FRAME_HEIGHT_1080P	(1088)
+#define FRAME_WIDTH_1080P	(1920)
+#define CHECK_TILED_1080P_DISPLAY(vout)	\
+	((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) ||	\
+	       ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\
+	       ((vout)->task.input.width == FRAME_WIDTH_1080P) &&	\
+	       ((vout)->task.input.height == FRAME_HEIGHT_1080P) &&	\
+	       ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) &&	\
+	       (((vout)->task.input.crop.h == FRAME_HEIGHT_1080P) ||	\
+	       ((vout)->task.input.crop.h == VALID_HEIGHT_1080P)) &&	\
+	       ((vout)->task.output.width == FRAME_WIDTH_1080P) &&	\
+	       ((vout)->task.output.height == VALID_HEIGHT_1080P) &&	\
+	       ((vout)->task.output.crop.w == FRAME_WIDTH_1080P) &&	\
+	       ((vout)->task.output.crop.h == VALID_HEIGHT_1080P))
+#define CHECK_TILED_1080P_STREAM(vout)	\
+	((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) ||	\
+	       ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\
+	       ((vout)->task.input.width == FRAME_WIDTH_1080P) &&	\
+	       ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) &&	\
+	       ((vout)->task.input.height == FRAME_HEIGHT_1080P) &&	\
+	       ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P))
+#define IS_PLANAR_PIXEL_FORMAT(format) \
+	(format == IPU_PIX_FMT_NV12 ||		\
+	    format == IPU_PIX_FMT_YUV420P2 ||	\
+	    format == IPU_PIX_FMT_YUV420P ||	\
+	    format == IPU_PIX_FMT_YVU420P ||	\
+	    format == IPU_PIX_FMT_YUV422P ||	\
+	    format == IPU_PIX_FMT_YVU422P ||	\
+	    format == IPU_PIX_FMT_YUV444P)
+
+#define NSEC_PER_FRAME_30FPS		(33333333)
+
+struct mxc_vout_fb {
+	char *name;
+	int ipu_id;
+	struct v4l2_rect crop_bounds;
+	unsigned int disp_fmt;
+	bool disp_support_csc;
+	bool disp_support_windows;
+};
+
+struct dma_mem {
+	void *vaddr;
+	dma_addr_t paddr;
+	size_t size;
+};
+
+struct mxc_vout_output {
+	int open_cnt;
+	struct fb_info *fbi;
+	unsigned long fb_smem_start;
+	unsigned long fb_smem_len;
+	struct video_device *vfd;
+	struct mutex mutex;
+	struct mutex task_lock;
+	struct mutex accs_lock;
+	enum v4l2_buf_type type;
+
+	struct videobuf_queue vbq;
+	spinlock_t vbq_lock;
+
+	struct list_head queue_list;
+	struct list_head active_list;
+
+	struct v4l2_rect crop_bounds;
+	unsigned int disp_fmt;
+	struct mxcfb_pos win_pos;
+	bool disp_support_windows;
+	bool disp_support_csc;
+
+	bool fmt_init;
+	bool release;
+	bool linear_bypass_pp;
+	bool vdoa_1080p;
+	bool tiled_bypass_pp;
+	struct v4l2_rect in_rect;
+	struct ipu_task	task;
+	struct ipu_task	vdoa_task;
+	struct dma_mem vdoa_work;
+	struct dma_mem vdoa_output[VDOA_FB_BUFS];
+
+	bool timer_stop;
+	struct hrtimer timer;
+	struct workqueue_struct *v4l_wq;
+	struct work_struct disp_work;
+	unsigned long frame_count;
+	unsigned long vdi_frame_cnt;
+	ktime_t start_ktime;
+
+	int ctrl_rotate;
+	int ctrl_vflip;
+	int ctrl_hflip;
+
+	dma_addr_t disp_bufs[FB_BUFS];
+
+	struct videobuf_buffer *pre1_vb;
+	struct videobuf_buffer *pre2_vb;
+
+	bool input_crop;
+};
+
+struct mxc_vout_dev {
+	struct device	*dev;
+	struct v4l2_device v4l2_dev;
+	struct mxc_vout_output *out[MAX_FB_NUM];
+	int out_num;
+};
+
+/* Driver Configuration macros */
+#define VOUT_NAME		"mxc_vout"
+
+/* Variables configurable through module params*/
+static int debug;
+static int vdi_rate_double;
+static int video_nr = 16;
+
+static int mxc_vidioc_s_input_crop(struct mxc_vout_output *vout,
+				const struct v4l2_crop *crop);
+static int mxc_vidioc_g_input_crop(struct mxc_vout_output *vout,
+				struct v4l2_crop *crop);
+/* Module parameters */
+module_param(video_nr, int, S_IRUGO);
+MODULE_PARM_DESC(video_nr, "video device numbers");
+module_param(debug, int, 0600);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+module_param(vdi_rate_double, int, 0600);
+MODULE_PARM_DESC(vdi_rate_double, "vdi frame rate double on/off");
+
+static const struct v4l2_fmtdesc mxc_formats[] = {
+	{
+		.description = "RGB565",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+	},
+	{
+		.description = "BGR24",
+		.pixelformat = V4L2_PIX_FMT_BGR24,
+	},
+	{
+		.description = "RGB24",
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+	},
+	{
+		.description = "RGB32",
+		.pixelformat = V4L2_PIX_FMT_RGB32,
+	},
+	{
+		.description = "BGR32",
+		.pixelformat = V4L2_PIX_FMT_BGR32,
+	},
+	{
+		.description = "NV12",
+		.pixelformat = V4L2_PIX_FMT_NV12,
+	},
+	{
+		.description = "UYVY",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+	},
+	{
+		.description = "YUYV",
+		.pixelformat = V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.description = "YUV422 planar",
+		.pixelformat = V4L2_PIX_FMT_YUV422P,
+	},
+	{
+		.description = "YUV444",
+		.pixelformat = V4L2_PIX_FMT_YUV444,
+	},
+	{
+		.description = "YUV420",
+		.pixelformat = V4L2_PIX_FMT_YUV420,
+	},
+	{
+		.description = "YVU420",
+		.pixelformat = V4L2_PIX_FMT_YVU420,
+	},
+	{
+		.description = "TILED NV12P",
+		.pixelformat = IPU_PIX_FMT_TILED_NV12,
+	},
+	{
+		.description = "TILED NV12F",
+		.pixelformat = IPU_PIX_FMT_TILED_NV12F,
+	},
+	{
+		.description = "YUV444 planar",
+		.pixelformat = IPU_PIX_FMT_YUV444P,
+	},
+};
+
+#define NUM_MXC_VOUT_FORMATS (ARRAY_SIZE(mxc_formats))
+
+#define DEF_INPUT_WIDTH		320
+#define DEF_INPUT_HEIGHT	240
+
+static int mxc_vidioc_streamoff(struct file *file, void *fh,
+					enum v4l2_buf_type i);
+
+static struct mxc_vout_fb g_fb_setting[MAX_FB_NUM];
+static int config_disp_output(struct mxc_vout_output *vout);
+static void release_disp_output(struct mxc_vout_output *vout);
+
+static DEFINE_MUTEX(gfb_mutex);
+static DEFINE_MUTEX(gfbi_mutex);
+
+static unsigned int get_frame_size(struct mxc_vout_output *vout)
+{
+	unsigned int size;
+
+	if (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)
+		size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+					vout->task.input.height);
+	else if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+		size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+					vout->task.input.height/2);
+		size *= 2;
+	} else
+		size = vout->task.input.width * vout->task.input.height *
+				fmt_to_bpp(vout->task.input.format)/8;
+
+	return size;
+}
+
+static void free_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf)
+{
+	dma_free_coherent(vout->vbq.dev, buf->size, buf->vaddr, buf->paddr);
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"free dma size:0x%x, paddr:0x%x\n",
+			buf->size, buf->paddr);
+	memset(buf, 0, sizeof(*buf));
+}
+
+static int alloc_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf)
+{
+
+	buf->vaddr = dma_alloc_coherent(vout->vbq.dev, buf->size, &buf->paddr,
+						GFP_DMA | GFP_KERNEL);
+	if (!buf->vaddr) {
+		v4l2_err(vout->vfd->v4l2_dev,
+			"cannot get dma buf size:0x%x\n", buf->size);
+		return -ENOMEM;
+	}
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+		"alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr);
+	return 0;
+}
+
+static ipu_channel_t get_ipu_channel(struct fb_info *fbi)
+{
+	ipu_channel_t ipu_ch = CHAN_NONE;
+	mm_segment_t old_fs;
+
+	if (fbi->fbops->fb_ioctl) {
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+				(unsigned long)&ipu_ch);
+		set_fs(old_fs);
+	}
+
+	return ipu_ch;
+}
+
+static unsigned int get_ipu_fmt(struct fb_info *fbi)
+{
+	mm_segment_t old_fs;
+	unsigned int fb_fmt = 0;
+
+	if (fbi->fbops->fb_ioctl) {
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT,
+				(unsigned long)&fb_fmt);
+		set_fs(old_fs);
+	}
+
+	return fb_fmt;
+}
+
+static void update_display_setting(void)
+{
+	int i;
+	struct fb_info *fbi;
+	struct v4l2_rect bg_crop_bounds[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0} };
+
+	mutex_lock(&gfb_mutex);
+	for (i = 0; i < num_registered_fb; i++) {
+		fbi = registered_fb[i];
+
+		memset(&g_fb_setting[i], 0, sizeof(struct mxc_vout_fb));
+
+		if (!strncmp(fbi->fix.id, "DISP3", 5))
+			g_fb_setting[i].ipu_id = 0;
+		else
+			g_fb_setting[i].ipu_id = 1;
+
+		g_fb_setting[i].name = fbi->fix.id;
+		g_fb_setting[i].crop_bounds.left = 0;
+		g_fb_setting[i].crop_bounds.top = 0;
+		g_fb_setting[i].crop_bounds.width = fbi->var.xres;
+		g_fb_setting[i].crop_bounds.height = fbi->var.yres;
+		g_fb_setting[i].disp_fmt = get_ipu_fmt(fbi);
+
+		if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
+			bg_crop_bounds[g_fb_setting[i].ipu_id] =
+				g_fb_setting[i].crop_bounds;
+			g_fb_setting[i].disp_support_csc = true;
+		} else if (get_ipu_channel(fbi) == MEM_FG_SYNC) {
+			g_fb_setting[i].disp_support_csc = true;
+			g_fb_setting[i].disp_support_windows = true;
+		}
+	}
+
+	for (i = 0; i < num_registered_fb; i++) {
+		fbi = registered_fb[i];
+
+		if (get_ipu_channel(fbi) == MEM_FG_SYNC)
+			g_fb_setting[i].crop_bounds =
+				bg_crop_bounds[g_fb_setting[i].ipu_id];
+	}
+	mutex_unlock(&gfb_mutex);
+}
+
+/* called after g_fb_setting filled by update_display_setting */
+static int update_setting_from_fbi(struct mxc_vout_output *vout,
+			struct fb_info *fbi)
+{
+	int i;
+	bool found = false;
+
+	mutex_lock(&gfbi_mutex);
+
+	update_display_setting();
+
+	for (i = 0; i < MAX_FB_NUM; i++) {
+		if (g_fb_setting[i].name) {
+			if (!strcmp(fbi->fix.id, g_fb_setting[i].name)) {
+				vout->crop_bounds = g_fb_setting[i].crop_bounds;
+				vout->disp_fmt = g_fb_setting[i].disp_fmt;
+				vout->disp_support_csc =
+					g_fb_setting[i].disp_support_csc;
+				vout->disp_support_windows =
+					g_fb_setting[i].disp_support_windows;
+				found = true;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		v4l2_err(vout->vfd->v4l2_dev, "can not find output\n");
+		mutex_unlock(&gfbi_mutex);
+		return -EINVAL;
+	}
+	strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name));
+
+	memset(&vout->task, 0, sizeof(struct ipu_task));
+
+	vout->task.input.width = DEF_INPUT_WIDTH;
+	vout->task.input.height = DEF_INPUT_HEIGHT;
+	vout->task.input.crop.pos.x = 0;
+	vout->task.input.crop.pos.y = 0;
+	vout->task.input.crop.w = DEF_INPUT_WIDTH;
+	vout->task.input.crop.h = DEF_INPUT_HEIGHT;
+	vout->input_crop = false;
+
+	vout->task.output.width = vout->crop_bounds.width;
+	vout->task.output.height = vout->crop_bounds.height;
+	vout->task.output.crop.pos.x = 0;
+	vout->task.output.crop.pos.y = 0;
+	vout->task.output.crop.w = vout->crop_bounds.width;
+	vout->task.output.crop.h = vout->crop_bounds.height;
+	if (colorspaceofpixel(vout->disp_fmt) == YUV_CS)
+		vout->task.output.format = IPU_PIX_FMT_UYVY;
+	else
+		vout->task.output.format = IPU_PIX_FMT_RGB565;
+
+	mutex_unlock(&gfbi_mutex);
+	return 0;
+}
+
+static bool deinterlace_3_field(struct mxc_vout_output *vout)
+{
+	return (vout->task.input.deinterlace.enable &&
+		(vout->task.input.deinterlace.motion != HIGH_MOTION));
+}
+
+static int set_field_fmt(struct mxc_vout_output *vout, enum v4l2_field field)
+{
+	struct ipu_deinterlace *deinterlace = &vout->task.input.deinterlace;
+
+	switch (field) {
+	/* Images are in progressive format, not interlaced */
+	case V4L2_FIELD_NONE:
+	case V4L2_FIELD_ANY:
+		deinterlace->enable = false;
+		deinterlace->field_fmt = 0;
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "Progressive frame.\n");
+		break;
+	case V4L2_FIELD_INTERLACED_TB:
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+				"Enable deinterlace TB.\n");
+		deinterlace->enable = true;
+		deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_TOP;
+		break;
+	case V4L2_FIELD_INTERLACED_BT:
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+				"Enable deinterlace BT.\n");
+		deinterlace->enable = true;
+		deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM;
+		break;
+	default:
+		v4l2_err(vout->vfd->v4l2_dev,
+			"field format:%d not supported yet!\n", field);
+		return -EINVAL;
+	}
+
+	if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+				"tiled fmt enable deinterlace.\n");
+		deinterlace->enable = true;
+	}
+
+	if (deinterlace->enable && vdi_rate_double)
+		deinterlace->field_fmt |= IPU_DEINTERLACE_RATE_EN;
+
+	return 0;
+}
+
+static bool is_pp_bypass(struct mxc_vout_output *vout)
+{
+	if ((IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == vout->task.input.format))
+		return false;
+	if ((vout->task.input.width == vout->task.output.width) &&
+		(vout->task.input.height == vout->task.output.height) &&
+		(vout->task.input.crop.w == vout->task.output.crop.w) &&
+		(vout->task.input.crop.h == vout->task.output.crop.h) &&
+		(vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) &&
+		!vout->task.input.deinterlace.enable) {
+		if (vout->disp_support_csc)
+			return true;
+		else if (!need_csc(vout->task.input.format, vout->disp_fmt))
+			return true;
+	/*
+	 * input crop show to full output which can show based on
+	 * xres_virtual/yres_virtual
+	 */
+	} else if ((vout->task.input.crop.w == vout->task.output.crop.w) &&
+			(vout->task.output.crop.w == vout->task.output.width) &&
+			(vout->task.input.crop.h == vout->task.output.crop.h) &&
+			(vout->task.output.crop.h ==
+				vout->task.output.height) &&
+			(vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) &&
+			!vout->task.input.deinterlace.enable) {
+		if (vout->disp_support_csc)
+			return true;
+		else if (!need_csc(vout->task.input.format, vout->disp_fmt))
+			return true;
+	}
+	return false;
+}
+
+static void setup_buf_timer(struct mxc_vout_output *vout,
+			struct videobuf_buffer *vb)
+{
+	ktime_t expiry_time, now;
+
+	/* if timestamp is 0, then default to 30fps */
+	if (vb->ts == 0)
+		expiry_time = ktime_add_ns(vout->start_ktime,
+				NSEC_PER_FRAME_30FPS * vout->frame_count);
+	else
+		expiry_time = ns_to_ktime(vb->ts);
+
+	now = hrtimer_cb_get_time(&vout->timer);
+	if (ktime_after(now, expiry_time)) {
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+				"warning: timer timeout already expired.\n");
+		expiry_time = now;
+	}
+
+	hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS);
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next "
+		"schedule: %lldnsecs\n", ktime_to_ns(expiry_time));
+}
+
+static int show_buf(struct mxc_vout_output *vout, int idx,
+	struct ipu_pos *ipos)
+{
+	struct fb_info *fbi = vout->fbi;
+	struct fb_var_screeninfo var;
+	int ret;
+	u32 fb_base = 0;
+
+	memcpy(&var, &fbi->var, sizeof(var));
+
+	if (vout->linear_bypass_pp || vout->tiled_bypass_pp) {
+		/*
+		 * crack fb base
+		 * NOTE: should not do other fb operation during v4l2
+		 */
+		console_lock();
+		fb_base = fbi->fix.smem_start;
+		fbi->fix.smem_start = vout->task.output.paddr;
+		fbi->var.yoffset = ipos->y + 1;
+		var.xoffset = ipos->x;
+		var.yoffset = ipos->y;
+		var.vmode |= FB_VMODE_YWRAP;
+		ret = fb_pan_display(fbi, &var);
+		fbi->fix.smem_start = fb_base;
+		console_unlock();
+	} else {
+		console_lock();
+		var.yoffset = idx * fbi->var.yres;
+		var.vmode &= ~FB_VMODE_YWRAP;
+		ret = fb_pan_display(fbi, &var);
+		console_unlock();
+	}
+
+	return ret;
+}
+
+static void disp_work_func(struct work_struct *work)
+{
+	struct mxc_vout_output *vout =
+		container_of(work, struct mxc_vout_output, disp_work);
+	struct videobuf_queue *q = &vout->vbq;
+	struct videobuf_buffer *vb, *vb_next = NULL;
+	unsigned long flags = 0;
+	struct ipu_pos ipos;
+	int ret = 0;
+	u32 in_fmt = 0, in_width = 0, in_height = 0;
+	u32 vdi_cnt = 0;
+	u32 vdi_frame;
+	u32 index = 0;
+	u32 ocrop_h = 0;
+	u32 o_height = 0;
+	u32 tiled_interlaced = 0;
+	bool tiled_fmt = false;
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work begin one frame\n");
+
+	spin_lock_irqsave(q->irqlock, flags);
+
+	if (list_empty(&vout->active_list)) {
+		v4l2_warn(vout->vfd->v4l2_dev,
+			"no entry in active_list, should not be here\n");
+		spin_unlock_irqrestore(q->irqlock, flags);
+		return;
+	}
+
+	vb = list_first_entry(&vout->active_list,
+			struct videobuf_buffer, queue);
+	ret = set_field_fmt(vout, vb->field);
+	if (ret < 0) {
+		spin_unlock_irqrestore(q->irqlock, flags);
+		return;
+	}
+	if (deinterlace_3_field(vout)) {
+		if (list_is_singular(&vout->active_list)) {
+			if (list_empty(&vout->queue_list)) {
+				vout->timer_stop = true;
+				spin_unlock_irqrestore(q->irqlock, flags);
+				v4l2_warn(vout->vfd->v4l2_dev,
+					"no enough entry for 3 fields "
+					"deinterlacer\n");
+				return;
+			}
+
+			/*
+			 * We need to use the next vb even if it is
+			 * not on the active list.
+			 */
+			vb_next = list_first_entry(&vout->queue_list,
+					struct videobuf_buffer, queue);
+		} else
+			vb_next = list_first_entry(vout->active_list.next,
+						struct videobuf_buffer, queue);
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"cur field_fmt:%d, next field_fmt:%d.\n",
+			vb->field, vb_next->field);
+		/* repeat the last field during field format changing */
+		if ((vb->field != vb_next->field) &&
+			(vb_next->field != V4L2_FIELD_NONE))
+			vb_next = vb;
+	}
+
+	spin_unlock_irqrestore(q->irqlock, flags);
+
+vdi_frame_rate_double:
+	mutex_lock(&vout->task_lock);
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+		"v4l2 frame_cnt:%ld, vb_field:%d, fmt:%d\n",
+		vout->frame_count, vb->field,
+		vout->task.input.deinterlace.field_fmt);
+	if (vb->memory == V4L2_MEMORY_USERPTR)
+		vout->task.input.paddr = vb->baddr;
+	else
+		vout->task.input.paddr = videobuf_to_dma_contig(vb);
+
+	if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
+		index = vout->vdi_frame_cnt % FB_BUFS;
+	else
+		index = vout->frame_count % FB_BUFS;
+	if (vout->linear_bypass_pp) {
+		vout->task.output.paddr = vout->task.input.paddr;
+		ipos.x = vout->task.input.crop.pos.x;
+		ipos.y = vout->task.input.crop.pos.y;
+	} else {
+		if (deinterlace_3_field(vout)) {
+			if (vb->memory == V4L2_MEMORY_USERPTR)
+				vout->task.input.paddr_n = vb_next->baddr;
+			else
+				vout->task.input.paddr_n =
+					videobuf_to_dma_contig(vb_next);
+		}
+		vout->task.output.paddr = vout->disp_bufs[index];
+		if (vout->vdoa_1080p) {
+			o_height =  vout->task.output.height;
+			ocrop_h = vout->task.output.crop.h;
+			vout->task.output.height = FRAME_HEIGHT_1080P;
+			vout->task.output.crop.h = FRAME_HEIGHT_1080P;
+		}
+		tiled_fmt =
+			(IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ||
+			(IPU_PIX_FMT_TILED_NV12F == vout->task.input.format);
+		if (vout->tiled_bypass_pp) {
+			ipos.x = vout->task.input.crop.pos.x;
+			ipos.y = vout->task.input.crop.pos.y;
+		} else if (tiled_fmt) {
+			vout->vdoa_task.input.paddr = vout->task.input.paddr;
+			if (deinterlace_3_field(vout))
+				vout->vdoa_task.input.paddr_n =
+						vout->task.input.paddr_n;
+			vout->vdoa_task.output.paddr = vout->vdoa_work.paddr;
+			ret = ipu_queue_task(&vout->vdoa_task);
+			if (ret < 0) {
+				mutex_unlock(&vout->task_lock);
+				goto err;
+			}
+			vout->task.input.paddr = vout->vdoa_task.output.paddr;
+			in_fmt = vout->task.input.format;
+			in_width = vout->task.input.width;
+			in_height = vout->task.input.height;
+			vout->task.input.format = vout->vdoa_task.output.format;
+			vout->task.input.width = vout->vdoa_task.output.width;
+			vout->task.input.height = vout->vdoa_task.output.height;
+			if (vout->task.input.deinterlace.enable) {
+				tiled_interlaced = 1;
+				vout->task.input.deinterlace.enable = 0;
+			}
+			v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+					"tiled queue task\n");
+		}
+		ret = ipu_queue_task(&vout->task);
+		if ((!vout->tiled_bypass_pp) && tiled_fmt) {
+			vout->task.input.format = in_fmt;
+			vout->task.input.width = in_width;
+			vout->task.input.height = in_height;
+		}
+		if (tiled_interlaced)
+			vout->task.input.deinterlace.enable = 1;
+		if (ret < 0) {
+			mutex_unlock(&vout->task_lock);
+			goto err;
+		}
+		if (vout->vdoa_1080p) {
+			vout->task.output.crop.h = ocrop_h;
+			vout->task.output.height = o_height;
+		}
+	}
+
+	mutex_unlock(&vout->task_lock);
+
+	ret = show_buf(vout, index, &ipos);
+	if (ret < 0)
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"show buf with ret %d\n", ret);
+
+	if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) {
+		vdi_frame = vout->task.input.deinterlace.field_fmt
+				& IPU_DEINTERLACE_RATE_FRAME1;
+		if (vdi_frame)
+			vout->task.input.deinterlace.field_fmt &=
+			~IPU_DEINTERLACE_RATE_FRAME1;
+		else
+			vout->task.input.deinterlace.field_fmt |=
+			IPU_DEINTERLACE_RATE_FRAME1;
+		vout->vdi_frame_cnt++;
+		vdi_cnt++;
+		if (vdi_cnt < IPU_DEINTERLACE_MAX_FRAME)
+			goto vdi_frame_rate_double;
+	}
+	spin_lock_irqsave(q->irqlock, flags);
+
+	list_del(&vb->queue);
+
+	/*
+	 * The videobuf before the last one has been shown. Set
+	 * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass
+	 * case, which makes sure a buffer being shown will not be
+	 * dequeued to be overwritten. It also brings side-effect that
+	 * the last 2 buffers can not be dequeued correctly, apps need
+	 * to take care of it.
+	 */
+	if (vout->pre2_vb) {
+		vout->pre2_vb->state = VIDEOBUF_DONE;
+		wake_up_interruptible(&vout->pre2_vb->done);
+		vout->pre2_vb = NULL;
+	}
+
+	if (vout->linear_bypass_pp) {
+		vout->pre2_vb = vout->pre1_vb;
+		vout->pre1_vb = vb;
+	} else {
+		if (vout->pre1_vb) {
+			vout->pre1_vb->state = VIDEOBUF_DONE;
+			wake_up_interruptible(&vout->pre1_vb->done);
+			vout->pre1_vb = NULL;
+		}
+		vb->state = VIDEOBUF_DONE;
+		wake_up_interruptible(&vb->done);
+	}
+
+	vout->frame_count++;
+
+	/* pick next queue buf to setup timer */
+	if (list_empty(&vout->queue_list))
+		vout->timer_stop = true;
+	else {
+		vb = list_first_entry(&vout->queue_list,
+				struct videobuf_buffer, queue);
+		setup_buf_timer(vout, vb);
+	}
+
+	spin_unlock_irqrestore(q->irqlock, flags);
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work finish one frame\n");
+
+	return;
+err:
+	v4l2_err(vout->vfd->v4l2_dev, "display work fail ret = %d\n", ret);
+	vout->timer_stop = true;
+	vb->state = VIDEOBUF_ERROR;
+	return;
+}
+
+static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer)
+{
+	struct mxc_vout_output *vout = container_of(timer,
+						    struct mxc_vout_output,
+						    timer);
+	struct videobuf_queue *q = &vout->vbq;
+	struct videobuf_buffer *vb;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(q->irqlock, flags);
+
+	/*
+	 * put first queued entry into active, if previous entry did not
+	 * finish, setup current entry's timer again.
+	 */
+	if (list_empty(&vout->queue_list)) {
+		spin_unlock_irqrestore(q->irqlock, flags);
+		return HRTIMER_NORESTART;
+	}
+
+	/* move videobuf from queued list to active list */
+	vb = list_first_entry(&vout->queue_list,
+			struct videobuf_buffer, queue);
+	list_del(&vb->queue);
+	list_add_tail(&vb->queue, &vout->active_list);
+
+	if (queue_work(vout->v4l_wq, &vout->disp_work) == 0) {
+		v4l2_warn(vout->vfd->v4l2_dev,
+		"disp work was in queue already, queue buf again next time\n");
+		list_del(&vb->queue);
+		list_add(&vb->queue, &vout->queue_list);
+		spin_unlock_irqrestore(q->irqlock, flags);
+		return HRTIMER_NORESTART;
+	}
+
+	vb->state = VIDEOBUF_ACTIVE;
+
+	spin_unlock_irqrestore(q->irqlock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+/* Video buffer call backs */
+
+/*
+ * Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+			  unsigned int *size)
+{
+	struct mxc_vout_output *vout = q->priv_data;
+	unsigned int frame_size;
+
+	if (!vout)
+		return -EINVAL;
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+		return -EINVAL;
+
+	frame_size = get_frame_size(vout);
+	*size = PAGE_ALIGN(frame_size);
+
+	return 0;
+}
+
+/*
+ * This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * converts user space virtual address into physical address if userptr memory
+ * exchange mechanism is used.
+ */
+static int mxc_vout_buffer_prepare(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb,
+			    enum v4l2_field field)
+{
+	vb->state = VIDEOBUF_PREPARED;
+	return 0;
+}
+
+/*
+ * Buffer queue function will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed.
+ * This function is protected by q->irqlock.
+ */
+static void mxc_vout_buffer_queue(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb)
+{
+	struct mxc_vout_output *vout = q->priv_data;
+	struct videobuf_buffer *active_vb;
+
+	list_add_tail(&vb->queue, &vout->queue_list);
+	vb->state = VIDEOBUF_QUEUED;
+
+	if (vout->timer_stop) {
+		if (deinterlace_3_field(vout) &&
+			!list_empty(&vout->active_list)) {
+			active_vb = list_first_entry(&vout->active_list,
+					struct videobuf_buffer, queue);
+			setup_buf_timer(vout, active_vb);
+		} else {
+			setup_buf_timer(vout, vb);
+		}
+		vout->timer_stop = false;
+	}
+}
+
+/*
+ * Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated
+ */
+static void mxc_vout_buffer_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int mxc_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int ret;
+	struct mxc_vout_output *vout = file->private_data;
+
+	if (!vout)
+		return -ENODEV;
+
+	ret = videobuf_mmap_mapper(&vout->vbq, vma);
+	if (ret < 0)
+		v4l2_err(vout->vfd->v4l2_dev,
+				"offset invalid [offset=0x%lx]\n",
+				(vma->vm_pgoff << PAGE_SHIFT));
+
+	return ret;
+}
+
+static int mxc_vout_release(struct file *file)
+{
+	unsigned int ret = 0;
+	struct videobuf_queue *q;
+	struct mxc_vout_output *vout = file->private_data;
+
+	if (!vout)
+		return 0;
+
+	mutex_lock(&vout->accs_lock);
+	if (--vout->open_cnt == 0) {
+		q = &vout->vbq;
+		if (q->streaming)
+			mxc_vidioc_streamoff(file, vout, vout->type);
+		else {
+			release_disp_output(vout);
+			videobuf_queue_cancel(q);
+		}
+		destroy_workqueue(vout->v4l_wq);
+		ret = videobuf_mmap_free(q);
+	}
+
+	mutex_unlock(&vout->accs_lock);
+	return ret;
+}
+
+static long mxc_vout_ioctl(struct file *file,
+	       unsigned int cmd, unsigned long arg)
+{
+	struct mxc_vout_output *vout = file->private_data;
+	struct v4l2_crop crop;
+	int ret;
+
+	switch (cmd) {
+	case VIDIOC_S_INPUT_CROP:
+		if (copy_from_user(&crop, (void __user *)arg, sizeof(struct v4l2_crop)))
+			return -EFAULT;
+		ret = mxc_vidioc_s_input_crop(vout, &crop);
+		break;
+	case VIDIOC_G_INPUT_CROP:
+		mxc_vidioc_g_input_crop(vout, &crop);
+		ret = copy_from_user((void __user *)arg, &crop, sizeof(struct v4l2_crop));
+		break;
+	default:
+		ret = video_ioctl2(file, cmd, arg);
+	}
+	return ret;
+}
+
+static int mxc_vout_open(struct file *file)
+{
+	struct mxc_vout_output *vout = NULL;
+	int ret = 0;
+
+	vout = video_drvdata(file);
+
+	if (vout == NULL)
+		return -ENODEV;
+
+	mutex_lock(&vout->accs_lock);
+	if (vout->open_cnt++ == 0) {
+		vout->ctrl_rotate = 0;
+		vout->ctrl_vflip = 0;
+		vout->ctrl_hflip = 0;
+		ret = update_setting_from_fbi(vout, vout->fbi);
+		if (ret < 0)
+			goto err;
+
+		vout->v4l_wq = create_singlethread_workqueue("v4l2q");
+		if (!vout->v4l_wq) {
+			v4l2_err(vout->vfd->v4l2_dev,
+					"Could not create work queue\n");
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		INIT_WORK(&vout->disp_work, disp_work_func);
+
+		INIT_LIST_HEAD(&vout->queue_list);
+		INIT_LIST_HEAD(&vout->active_list);
+
+		vout->fmt_init = false;
+		vout->frame_count = 0;
+		vout->vdi_frame_cnt = 0;
+
+		vout->win_pos.x = 0;
+		vout->win_pos.y = 0;
+		vout->release = true;
+	}
+
+	file->private_data = vout;
+
+err:
+	mutex_unlock(&vout->accs_lock);
+	return ret;
+}
+
+/*
+ * V4L2 ioctls
+ */
+static int mxc_vidioc_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct mxc_vout_output *vout = fh;
+
+	strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+	cap->bus_info[0] = '\0';
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int mxc_vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	if (fmt->index >= NUM_MXC_VOUT_FORMATS)
+		return -EINVAL;
+
+	strlcpy(fmt->description, mxc_formats[fmt->index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = mxc_formats[fmt->index].pixelformat;
+
+	return 0;
+}
+
+static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct mxc_vout_output *vout = fh;
+
+	f->fmt.pix.width = vout->task.input.width;
+	f->fmt.pix.height = vout->task.input.height;
+	f->fmt.pix.pixelformat = vout->task.input.format;
+	f->fmt.pix.sizeimage = get_frame_size(vout);
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"frame_size:0x%x, pix_fmt:0x%x\n",
+			f->fmt.pix.sizeimage,
+			vout->task.input.format);
+
+	return 0;
+}
+
+static inline int ipu_try_task(struct mxc_vout_output *vout)
+{
+	int ret;
+	struct ipu_task *task = &vout->task;
+
+again:
+	ret = ipu_check_task(task);
+	if (ret != IPU_CHECK_OK) {
+		if (ret > IPU_CHECK_ERR_MIN) {
+			if (ret == IPU_CHECK_ERR_SPLIT_INPUTW_OVER ||
+			    ret == IPU_CHECK_ERR_W_DOWNSIZE_OVER) {
+				task->input.crop.w -= 8;
+				goto again;
+			}
+			if (ret == IPU_CHECK_ERR_SPLIT_INPUTH_OVER ||
+			    ret == IPU_CHECK_ERR_H_DOWNSIZE_OVER) {
+				task->input.crop.h -= 8;
+				goto again;
+			}
+			if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+				if (vout->disp_support_windows) {
+					task->output.width -= 8;
+					task->output.crop.w =
+						task->output.width;
+				} else
+					task->output.crop.w -= 8;
+				goto again;
+			}
+			if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+				if (vout->disp_support_windows) {
+					task->output.height -= 8;
+					task->output.crop.h =
+						task->output.height;
+				} else
+					task->output.crop.h -= 8;
+				goto again;
+			}
+			ret = -EINVAL;
+		}
+	} else
+		ret = 0;
+
+	return ret;
+}
+
+static inline int vdoaipu_try_task(struct mxc_vout_output *vout)
+{
+	int ret;
+	int is_1080p_stream;
+	int in_width, in_height;
+	size_t size;
+	struct ipu_task *ipu_task = &vout->task;
+	struct ipu_crop *icrop = &ipu_task->input.crop;
+	struct ipu_task *vdoa_task = &vout->vdoa_task;
+	u32 deinterlace = 0;
+	u32 in_fmt;
+
+	if (vout->task.input.deinterlace.enable)
+		deinterlace = 1;
+
+	memset(vdoa_task, 0, sizeof(*vdoa_task));
+	vdoa_task->output.format = IPU_PIX_FMT_NV12;
+	memcpy(&vdoa_task->input, &ipu_task->input,
+			sizeof(ipu_task->input));
+	if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+		(icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+		vdoa_task->input.crop.w =
+			ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+		vdoa_task->input.crop.h =
+			ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+	}
+	vdoa_task->output.width = vdoa_task->input.crop.w;
+	vdoa_task->output.height = vdoa_task->input.crop.h;
+	vdoa_task->output.crop.w = vdoa_task->input.crop.w;
+	vdoa_task->output.crop.h = vdoa_task->input.crop.h;
+
+	size = PAGE_ALIGN(vdoa_task->input.crop.w *
+					vdoa_task->input.crop.h *
+					fmt_to_bpp(vdoa_task->output.format)/8);
+	if (size > vout->vdoa_work.size) {
+		if (vout->vdoa_work.vaddr)
+			free_dma_buf(vout, &vout->vdoa_work);
+		vout->vdoa_work.size = size;
+		ret = alloc_dma_buf(vout, &vout->vdoa_work);
+		if (ret < 0)
+			return ret;
+	}
+	ret = ipu_check_task(vdoa_task);
+	if (ret != IPU_CHECK_OK)
+		return -EINVAL;
+
+	is_1080p_stream = CHECK_TILED_1080P_STREAM(vout);
+	if (is_1080p_stream)
+		ipu_task->input.crop.h = VALID_HEIGHT_1080P;
+	in_fmt = ipu_task->input.format;
+	in_width = ipu_task->input.width;
+	in_height = ipu_task->input.height;
+	ipu_task->input.format = vdoa_task->output.format;
+	ipu_task->input.height = vdoa_task->output.height;
+	ipu_task->input.width = vdoa_task->output.width;
+	if (deinterlace)
+		ipu_task->input.deinterlace.enable = 0;
+	ret = ipu_try_task(vout);
+	if (deinterlace)
+		ipu_task->input.deinterlace.enable = 1;
+	ipu_task->input.format = in_fmt;
+	ipu_task->input.width = in_width;
+	ipu_task->input.height = in_height;
+
+	return ret;
+}
+
+static int mxc_vout_try_task(struct mxc_vout_output *vout)
+{
+	int ret = 0;
+	struct ipu_output *output = &vout->task.output;
+	struct ipu_input *input = &vout->task.input;
+	struct ipu_crop *crop = &input->crop;
+	u32 o_height = 0;
+	u32 ocrop_h = 0;
+	bool tiled_fmt = false;
+	bool tiled_need_pp = false;
+
+	vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+	if (vout->vdoa_1080p) {
+		input->crop.h = FRAME_HEIGHT_1080P;
+		o_height = output->height;
+		ocrop_h = output->crop.h;
+		output->height = FRAME_HEIGHT_1080P;
+		output->crop.h = FRAME_HEIGHT_1080P;
+	}
+
+	if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
+		(IPU_PIX_FMT_TILED_NV12F == input->format)) {
+		if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+			(input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+			(crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+			(crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+			v4l2_err(vout->vfd->v4l2_dev,
+				"ERR: tiled fmt needs 16 pixel align.\n");
+			return -EINVAL;
+		}
+		if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+			(crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			tiled_need_pp = true;
+	} else {
+		crop->w -= crop->w % 8;
+		crop->h -= crop->h % 8;
+	}
+	/* assume task.output already set by S_CROP */
+	vout->linear_bypass_pp = is_pp_bypass(vout);
+	if (vout->linear_bypass_pp) {
+		v4l2_info(vout->vfd->v4l2_dev, "Bypass IC.\n");
+		output->format = input->format;
+	} else {
+		/* if need CSC, choose IPU-DP or IPU_IC do it */
+		if (vout->disp_support_csc) {
+			if (colorspaceofpixel(input->format) == YUV_CS)
+				output->format = IPU_PIX_FMT_UYVY;
+			else
+				output->format = IPU_PIX_FMT_RGB565;
+		} else {
+			if (colorspaceofpixel(vout->disp_fmt) == YUV_CS)
+				output->format = IPU_PIX_FMT_UYVY;
+			else
+				output->format = IPU_PIX_FMT_RGB565;
+		}
+
+		vout->tiled_bypass_pp = false;
+		if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
+			(IPU_PIX_FMT_TILED_NV12F == input->format)) {
+			/* check resize/rotate/flip, or csc task */
+			if (!(tiled_need_pp ||
+				(IPU_ROTATE_NONE != output->rotate) ||
+				(input->crop.w != output->crop.w) ||
+				(input->crop.h != output->crop.h) ||
+				(!vout->disp_support_csc &&
+				(colorspaceofpixel(vout->disp_fmt) == RGB_CS)))
+				) {
+				/* IC bypass */
+				output->format = IPU_PIX_FMT_NV12;
+				v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+						"tiled bypass pp\n");
+				vout->tiled_bypass_pp = true;
+			}
+			tiled_fmt = true;
+		}
+
+		if ((!vout->tiled_bypass_pp) && tiled_fmt)
+			ret = vdoaipu_try_task(vout);
+		else
+			ret = ipu_try_task(vout);
+	}
+
+	if (vout->vdoa_1080p) {
+		output->height = o_height;
+		output->crop.h = ocrop_h;
+	}
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"icrop.w:%u, icrop.h:%u, iw:%u, ih:%u,"
+			"ocrop.w:%u, ocrop.h:%u, ow:%u, oh:%u\n",
+			input->crop.w, input->crop.h,
+			input->width, input->height,
+			output->crop.w, output->crop.h,
+			output->width, output->height);
+	return ret;
+}
+
+static int mxc_vout_try_format(struct mxc_vout_output *vout,
+				struct v4l2_format *f)
+{
+	int ret = 0;
+
+	if ((f->fmt.pix.field != V4L2_FIELD_NONE) &&
+		(IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)) {
+		v4l2_err(vout->vfd->v4l2_dev,
+			"progressive tiled fmt should used V4L2_FIELD_NONE!\n");
+		return -EINVAL;
+	}
+
+	if (vout->input_crop == false) {
+		vout->task.input.crop.pos.x = 0;
+		vout->task.input.crop.pos.y = 0;
+		vout->task.input.crop.w = f->fmt.pix.width;
+		vout->task.input.crop.h = f->fmt.pix.height;
+	}
+
+	vout->task.input.width = f->fmt.pix.width;
+	vout->task.input.height = f->fmt.pix.height;
+	vout->task.input.format = f->fmt.pix.pixelformat;
+
+	ret = set_field_fmt(vout, f->fmt.pix.field);
+	if (ret < 0)
+		return ret;
+
+	ret = mxc_vout_try_task(vout);
+	if (!ret) {
+		f->fmt.pix.width = vout->task.input.crop.w;
+		f->fmt.pix.height = vout->task.input.crop.h;
+	}
+
+	return ret;
+}
+
+static bool mxc_vout_need_fb_reconfig(struct mxc_vout_output *vout,
+				      struct mxc_vout_output *pre_vout)
+{
+	if (!vout->vbq.streaming)
+		return false;
+
+	if (vout->tiled_bypass_pp)
+		return true;
+
+	if (vout->linear_bypass_pp != pre_vout->linear_bypass_pp)
+		return true;
+
+	/* cropped output resolution or format are changed */
+	if (vout->task.output.format != pre_vout->task.output.format ||
+	    vout->task.output.crop.w != pre_vout->task.output.crop.w ||
+	    vout->task.output.crop.h != pre_vout->task.output.crop.h)
+		return true;
+
+	/* overlay: window position or resolution are changed */
+	if (vout->disp_support_windows &&
+	    (vout->win_pos.x != pre_vout->win_pos.x ||
+	     vout->win_pos.y != pre_vout->win_pos.y ||
+	     vout->task.output.width  != pre_vout->task.output.width ||
+	     vout->task.output.height != pre_vout->task.output.height))
+		return true;
+
+	/* background: cropped position is changed */
+	if (!vout->disp_support_windows &&
+	    (vout->task.output.crop.pos.x !=
+	     pre_vout->task.output.crop.pos.x ||
+	     vout->task.output.crop.pos.y !=
+	     pre_vout->task.output.crop.pos.y))
+		return true;
+
+	return false;
+}
+
+static int mxc_vidioc_s_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct mxc_vout_output *vout = fh;
+	int ret = 0;
+
+	if (vout->vbq.streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->task_lock);
+	ret = mxc_vout_try_format(vout, f);
+	if (ret >= 0)
+		vout->fmt_init = true;
+	mutex_unlock(&vout->task_lock);
+
+	return ret;
+}
+
+static int mxc_vidioc_g_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct mxc_vout_output *vout = fh;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		s->r = vout->crop_bounds;
+		break;
+	default:
+		if (vout->disp_support_windows) {
+			s->r.left = vout->win_pos.x;
+			s->r.top = vout->win_pos.y;
+			s->r.width = vout->task.output.width;
+			s->r.height = vout->task.output.height;
+		} else {
+			if (vout->task.output.crop.w &&
+			    vout->task.output.crop.h) {
+				s->r.left = vout->task.output.crop.pos.x;
+				s->r.top = vout->task.output.crop.pos.y;
+				s->r.width = vout->task.output.crop.w;
+				s->r.height = vout->task.output.crop.h;
+			} else {
+				s->r.left = 0;
+				s->r.top = 0;
+				s->r.width = vout->task.output.width;
+				s->r.height = vout->task.output.height;
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int mxc_vidioc_s_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct mxc_vout_output *vout = fh, *pre_vout;
+	struct v4l2_rect *b = &vout->crop_bounds;
+	struct v4l2_selection fix_up_selection;
+	int ret = 0;
+
+	memcpy(&fix_up_selection, s, sizeof(*s));
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (s->r.width == 0)
+		fix_up_selection.r.width = b->width - b->left;
+	if (s->r.height == 0)
+		fix_up_selection.r.height = b->height - b->top;
+
+	if (s->r.top < b->top)
+		fix_up_selection.r.top = b->top;
+	if (s->r.top >= b->top + b->height)
+		fix_up_selection.r.top = b->top + b->height - 1;
+	if (s->r.height > b->top - s->r.top + b->height)
+		fix_up_selection.r.height =
+			b->top - fix_up_selection.r.top + b->height;
+
+	if (s->r.left < b->left)
+		fix_up_selection.r.left = b->left;
+	if (s->r.left >= b->left + b->width)
+		fix_up_selection.r.left = b->left + b->width - 1;
+	if (s->r.width > b->left - s->r.left + b->width)
+		fix_up_selection.r.width =
+			b->left - fix_up_selection.r.left + b->width;
+
+	/* stride line limitation */
+	fix_up_selection.r.height -= fix_up_selection.r.height % 8;
+	fix_up_selection.r.width -= fix_up_selection.r.width % 8;
+	if ((fix_up_selection.r.width <= 0) ||
+	    (fix_up_selection.r.height <= 0) ||
+	    ((fix_up_selection.r.left + fix_up_selection.r.width) >
+	     (b->left + b->width)) ||
+	    ((fix_up_selection.r.top + fix_up_selection.r.height) >
+	     (b->top + b->height))) {
+		v4l2_err(vout->vfd->v4l2_dev, "s_selection err: %d, %d, %d, %d",
+			fix_up_selection.r.left, fix_up_selection.r.top,
+			fix_up_selection.r.width, fix_up_selection.r.height);
+		return -EINVAL;
+	}
+
+	/* the same setting, return */
+	if (vout->disp_support_windows) {
+		if ((vout->win_pos.x == fix_up_selection.r.left) &&
+			(vout->win_pos.y == fix_up_selection.r.top) &&
+			(vout->task.output.crop.w == fix_up_selection.r.width) &&
+			(vout->task.output.crop.h == fix_up_selection.r.height))
+			return 0;
+	} else {
+		if ((vout->task.output.crop.pos.x == fix_up_selection.r.left) &&
+			(vout->task.output.crop.pos.y == fix_up_selection.r.top) &&
+			(vout->task.output.crop.w == fix_up_selection.r.width) &&
+			(vout->task.output.crop.h == fix_up_selection.r.height))
+			return 0;
+	}
+
+	pre_vout = vmalloc(sizeof(*pre_vout));
+	if (!pre_vout)
+		return -ENOMEM;
+
+	/* wait current work finish */
+	if (vout->vbq.streaming)
+		flush_workqueue(vout->v4l_wq);
+
+	mutex_lock(&vout->task_lock);
+
+	memcpy(pre_vout, vout, sizeof(*vout));
+
+	if (vout->disp_support_windows) {
+		vout->task.output.crop.pos.x = 0;
+		vout->task.output.crop.pos.y = 0;
+		vout->win_pos.x = fix_up_selection.r.left;
+		vout->win_pos.y = fix_up_selection.r.top;
+		vout->task.output.width = fix_up_selection.r.width;
+		vout->task.output.height = fix_up_selection.r.height;
+	} else {
+		vout->task.output.crop.pos.x = fix_up_selection.r.left;
+		vout->task.output.crop.pos.y = fix_up_selection.r.top;
+	}
+
+	vout->task.output.crop.w = fix_up_selection.r.width;
+	vout->task.output.crop.h = fix_up_selection.r.height;
+
+	/*
+	 * must S_CROP before S_FMT, for fist time S_CROP, will not check
+	 * ipu task, it will check in S_FMT, after S_FMT, S_CROP should
+	 * check ipu task too.
+	 */
+	if (vout->fmt_init) {
+		memcpy(&vout->task.input.crop, &vout->in_rect,
+			sizeof(vout->in_rect));
+		ret = mxc_vout_try_task(vout);
+		if (ret < 0) {
+			v4l2_err(vout->vfd->v4l2_dev,
+					"vout check task failed\n");
+			memcpy(vout, pre_vout, sizeof(*vout));
+			goto done;
+		}
+
+		if (mxc_vout_need_fb_reconfig(vout, pre_vout)) {
+			ret = config_disp_output(vout);
+			if (ret < 0)
+				v4l2_err(vout->vfd->v4l2_dev,
+					"Config display output failed\n");
+		}
+	}
+
+done:
+	vfree(pre_vout);
+	mutex_unlock(&vout->task_lock);
+
+	return ret;
+}
+
+static int mxc_vidioc_queryctrl(struct file *file, void *fh,
+		struct v4l2_queryctrl *ctrl)
+{
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+		break;
+	case V4L2_CID_HFLIP:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+		break;
+	case V4L2_CID_MXC_MOTION:
+		ret = v4l2_ctrl_query_fill(ctrl, 0, 2, 1, 0);
+		break;
+	default:
+		ctrl->name[0] = '\0';
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int mxc_vidioc_g_ctrl(struct file *file, void *fh,
+				struct v4l2_control *ctrl)
+{
+	int ret = 0;
+	struct mxc_vout_output *vout = fh;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ctrl->value = vout->ctrl_rotate;
+		break;
+	case V4L2_CID_VFLIP:
+		ctrl->value = vout->ctrl_vflip;
+		break;
+	case V4L2_CID_HFLIP:
+		ctrl->value = vout->ctrl_hflip;
+		break;
+	case V4L2_CID_MXC_MOTION:
+		if (vout->task.input.deinterlace.enable)
+			ctrl->value = vout->task.input.deinterlace.motion;
+		else
+			ctrl->value = 0;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static void setup_task_rotation(struct mxc_vout_output *vout)
+{
+	if (vout->ctrl_rotate == 0) {
+		if (vout->ctrl_vflip && vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_180;
+		else if (vout->ctrl_vflip)
+			vout->task.output.rotate = IPU_ROTATE_VERT_FLIP;
+		else if (vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP;
+		else
+			vout->task.output.rotate = IPU_ROTATE_NONE;
+	} else if (vout->ctrl_rotate == 90) {
+		if (vout->ctrl_vflip && vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_90_LEFT;
+		else if (vout->ctrl_vflip)
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP;
+		else if (vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP;
+		else
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT;
+	} else if (vout->ctrl_rotate == 180) {
+		if (vout->ctrl_vflip && vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_NONE;
+		else if (vout->ctrl_vflip)
+			vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP;
+		else if (vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_VERT_FLIP;
+		else
+			vout->task.output.rotate = IPU_ROTATE_180;
+	} else if (vout->ctrl_rotate == 270) {
+		if (vout->ctrl_vflip && vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT;
+		else if (vout->ctrl_vflip)
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP;
+		else if (vout->ctrl_hflip)
+			vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP;
+		else
+			vout->task.output.rotate = IPU_ROTATE_90_LEFT;
+	}
+}
+
+static int mxc_vidioc_s_ctrl(struct file *file, void *fh,
+				struct v4l2_control *ctrl)
+{
+	int ret = 0;
+	struct mxc_vout_output *vout = fh, *pre_vout;
+
+	pre_vout = vmalloc(sizeof(*pre_vout));
+	if (!pre_vout)
+		return -ENOMEM;
+
+	/* wait current work finish */
+	if (vout->vbq.streaming)
+		flush_workqueue(vout->v4l_wq);
+
+	mutex_lock(&vout->task_lock);
+
+	memcpy(pre_vout, vout, sizeof(*vout));
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+	{
+		vout->ctrl_rotate = (ctrl->value/90) * 90;
+		if (vout->ctrl_rotate > 270)
+			vout->ctrl_rotate = 270;
+		setup_task_rotation(vout);
+		break;
+	}
+	case V4L2_CID_VFLIP:
+	{
+		vout->ctrl_vflip = ctrl->value;
+		setup_task_rotation(vout);
+		break;
+	}
+	case V4L2_CID_HFLIP:
+	{
+		vout->ctrl_hflip = ctrl->value;
+		setup_task_rotation(vout);
+		break;
+	}
+	case V4L2_CID_MXC_MOTION:
+	{
+		vout->task.input.deinterlace.motion = ctrl->value;
+		break;
+	}
+	default:
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (vout->fmt_init) {
+		memcpy(&vout->task.input.crop, &vout->in_rect,
+				sizeof(vout->in_rect));
+		ret = mxc_vout_try_task(vout);
+		if (ret < 0) {
+			v4l2_err(vout->vfd->v4l2_dev,
+					"vout check task failed\n");
+			memcpy(vout, pre_vout, sizeof(*vout));
+			goto done;
+		}
+
+		if (mxc_vout_need_fb_reconfig(vout, pre_vout)) {
+			ret = config_disp_output(vout);
+			if (ret < 0)
+				v4l2_err(vout->vfd->v4l2_dev,
+					"Config display output failed\n");
+		}
+	}
+
+done:
+	vfree(pre_vout);
+	mutex_unlock(&vout->task_lock);
+
+	return ret;
+}
+
+static int mxc_vidioc_reqbufs(struct file *file, void *fh,
+			struct v4l2_requestbuffers *req)
+{
+	int ret = 0;
+	struct mxc_vout_output *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+
+	if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	/* should not be here after streaming, videobuf_reqbufs will control */
+	mutex_lock(&vout->task_lock);
+
+	ret = videobuf_reqbufs(q, req);
+
+	mutex_unlock(&vout->task_lock);
+	return ret;
+}
+
+static int mxc_vidioc_querybuf(struct file *file, void *fh,
+			struct v4l2_buffer *b)
+{
+	int ret;
+	struct mxc_vout_output *vout = fh;
+
+	ret = videobuf_querybuf(&vout->vbq, b);
+	if (!ret) {
+		/* return physical address */
+		struct videobuf_buffer *vb = vout->vbq.bufs[b->index];
+		if (b->flags & V4L2_BUF_FLAG_MAPPED)
+			b->m.offset = videobuf_to_dma_contig(vb);
+	}
+
+	return ret;
+}
+
+static int mxc_vidioc_qbuf(struct file *file, void *fh,
+			struct v4l2_buffer *buffer)
+{
+	struct mxc_vout_output *vout = fh;
+
+	return videobuf_qbuf(&vout->vbq, buffer);
+}
+
+static int mxc_vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+	struct mxc_vout_output *vout = fh;
+
+	if (!vout->vbq.streaming)
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK)
+		return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 1);
+	else
+		return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 0);
+}
+
+static int mxc_vidioc_s_input_crop(struct mxc_vout_output *vout,
+				const struct v4l2_crop *crop)
+{
+	int ret = 0;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	if (crop->c.width < 0 || crop->c.height < 0)
+		return -EINVAL;
+
+	vout->task.input.crop.pos.x = crop->c.left;
+	vout->task.input.crop.pos.y = crop->c.top;
+	vout->task.input.crop.w = crop->c.width;
+	vout->task.input.crop.h = crop->c.height;
+
+	vout->input_crop = true;
+	memcpy(&vout->in_rect, &vout->task.input.crop, sizeof(vout->in_rect));
+
+	return ret;
+}
+
+static int mxc_vidioc_g_input_crop(struct mxc_vout_output *vout,
+				struct v4l2_crop *crop)
+{
+	int ret = 0;
+
+	crop->c.left = vout->task.input.crop.pos.x;
+	crop->c.top = vout->task.input.crop.pos.y;
+	crop->c.width = vout->task.input.crop.w;
+	crop->c.height = vout->task.input.crop.h;
+
+	return ret;
+}
+
+static int set_window_position(struct mxc_vout_output *vout,
+				struct mxcfb_pos *pos)
+{
+	struct fb_info *fbi = vout->fbi;
+	mm_segment_t old_fs;
+	int ret = 0;
+
+	if (vout->disp_support_windows) {
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS,
+				(unsigned long)pos);
+		set_fs(old_fs);
+	}
+
+	return ret;
+}
+
+static int config_disp_output(struct mxc_vout_output *vout)
+{
+	struct dma_mem *buf = NULL;
+	struct fb_info *fbi = vout->fbi;
+	struct fb_var_screeninfo var;
+	struct mxcfb_pos pos;
+	int i, fb_num, ret;
+	u32 fb_base;
+	u32 size;
+	u32 display_buf_size;
+	u32 *pixel = NULL;
+	u32 color;
+	int j;
+
+	memcpy(&var, &fbi->var, sizeof(var));
+	fb_base = fbi->fix.smem_start;
+
+	var.xres = vout->task.output.width;
+	var.yres = vout->task.output.height;
+	if (vout->linear_bypass_pp || vout->tiled_bypass_pp) {
+		fb_num = 1;
+		/* input crop */
+		if (vout->task.input.width > vout->task.output.width)
+			var.xres_virtual = vout->task.input.width;
+		else
+			var.xres_virtual = var.xres;
+		if (vout->task.input.height > vout->task.output.height)
+			var.yres_virtual = vout->task.input.height;
+		else
+			var.yres_virtual = var.yres;
+		var.rotate = vout->task.output.rotate;
+		var.vmode |= FB_VMODE_YWRAP;
+	} else {
+		fb_num = FB_BUFS;
+		var.xres_virtual = var.xres;
+		var.yres_virtual = fb_num * var.yres;
+		var.vmode &= ~FB_VMODE_YWRAP;
+	}
+	var.bits_per_pixel = fmt_to_bpp(vout->task.output.format);
+	var.nonstd = vout->task.output.format;
+
+	v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"set display fb to %d %d\n",
+			var.xres, var.yres);
+
+	/*
+	 * To setup the overlay fb from scratch without
+	 * the last time overlay fb position or resolution's
+	 * impact, we take the following steps:
+	 * - blank fb
+	 * - set fb position to the starting point
+	 * - reconfigure fb
+	 * - set fb position to a specific point
+	 * - unblank fb
+	 * This procedure applies to non-overlay fbs as well.
+	 */
+	console_lock();
+	fbi->flags |= FBINFO_MISC_USEREVENT;
+	fb_blank(fbi, FB_BLANK_POWERDOWN);
+	fbi->flags &= ~FBINFO_MISC_USEREVENT;
+	console_unlock();
+
+	pos.x = 0;
+	pos.y = 0;
+	ret = set_window_position(vout, &pos);
+	if (ret < 0) {
+		v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position "
+			"to starting point\n");
+		return ret;
+	}
+
+	/* Init display channel through fb API */
+	var.yoffset = 0;
+	var.activate |= FB_ACTIVATE_FORCE;
+	console_lock();
+	fbi->flags |= FBINFO_MISC_USEREVENT;
+	ret = fb_set_var(fbi, &var);
+	fbi->flags &= ~FBINFO_MISC_USEREVENT;
+	console_unlock();
+	if (ret < 0) {
+		v4l2_err(vout->vfd->v4l2_dev,
+				"ERR:%s fb_set_var ret:%d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = set_window_position(vout, &vout->win_pos);
+	if (ret < 0) {
+		v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position\n");
+		return ret;
+	}
+
+	if (vout->linear_bypass_pp || vout->tiled_bypass_pp)
+		display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual;
+	else
+		display_buf_size = fbi->fix.line_length * fbi->var.yres;
+	for (i = 0; i < fb_num; i++)
+		vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size;
+	if (vout->tiled_bypass_pp) {
+		size = PAGE_ALIGN(vout->task.input.crop.w *
+					vout->task.input.crop.h *
+					fmt_to_bpp(vout->task.output.format)/8);
+		if (size > vout->vdoa_output[0].size) {
+			for (i = 0; i < VDOA_FB_BUFS; i++) {
+				buf = &vout->vdoa_output[i];
+				if (buf->vaddr)
+					free_dma_buf(vout, buf);
+				buf->size = size;
+				ret = alloc_dma_buf(vout, buf);
+				if (ret < 0)
+					goto err;
+			}
+		}
+		for (i = fb_num; i < (fb_num + VDOA_FB_BUFS); i++)
+			vout->disp_bufs[i] =
+				vout->vdoa_output[i - fb_num].paddr;
+	}
+	vout->fb_smem_len = fbi->fix.smem_len;
+	vout->fb_smem_start = fbi->fix.smem_start;
+	if (fb_base != fbi->fix.smem_start) {
+		v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+			"realloc fb mem size:0x%x@0x%lx,old paddr @0x%x\n",
+			fbi->fix.smem_len, fbi->fix.smem_start, fb_base);
+	}
+
+	/* fill black when video config changed */
+	color = colorspaceofpixel(vout->task.output.format) == YUV_CS ?
+			UYVY_BLACK : RGB_BLACK;
+	if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) {
+		size = display_buf_size * 8 /
+			fmt_to_bpp(vout->task.output.format);
+		memset(fbi->screen_base, Y_BLACK, size);
+		memset(fbi->screen_base + size, UV_BLACK,
+				display_buf_size - size);
+	} else {
+		pixel = (u32 *)fbi->screen_base;
+		for (i = 0; i < ((display_buf_size * fb_num) >> 2); i++)
+			*pixel++ = color;
+	}
+	console_lock();
+	fbi->flags |= FBINFO_MISC_USEREVENT;
+	ret = fb_blank(fbi, FB_BLANK_UNBLANK);
+	fbi->flags &= ~FBINFO_MISC_USEREVENT;
+	console_unlock();
+	vout->release = false;
+
+	return ret;
+err:
+	for (j = i - 1; j >= 0; j--) {
+		buf = &vout->vdoa_output[j];
+		if (buf->vaddr)
+			free_dma_buf(vout, buf);
+	}
+	return ret;
+}
+
+static inline void wait_for_vsync(struct mxc_vout_output *vout)
+{
+	struct fb_info *fbi = vout->fbi;
+	mm_segment_t old_fs;
+
+	if (fbi->fbops->fb_ioctl) {
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+				(unsigned long)NULL);
+		set_fs(old_fs);
+	}
+
+	return;
+}
+
+static void release_disp_output(struct mxc_vout_output *vout)
+{
+	struct fb_info *fbi = vout->fbi;
+	struct mxcfb_pos pos;
+
+	if (vout->release)
+		return;
+	console_lock();
+	fbi->flags |= FBINFO_MISC_USEREVENT;
+	fb_blank(fbi, FB_BLANK_POWERDOWN);
+	fbi->flags &= ~FBINFO_MISC_USEREVENT;
+	console_unlock();
+
+	/* restore pos to 0,0 avoid fb pan display hang? */
+	pos.x = 0;
+	pos.y = 0;
+	set_window_position(vout, &pos);
+
+	if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
+		console_lock();
+		fbi->fix.smem_start = vout->disp_bufs[0];
+		fbi->flags |= FBINFO_MISC_USEREVENT;
+		fb_blank(fbi, FB_BLANK_UNBLANK);
+		fbi->flags &= ~FBINFO_MISC_USEREVENT;
+		console_unlock();
+
+	}
+
+	vout->release = true;
+}
+
+static int mxc_vidioc_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct mxc_vout_output *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	int ret;
+
+	if (q->streaming) {
+		v4l2_err(vout->vfd->v4l2_dev,
+				"video output already run\n");
+		ret = -EBUSY;
+		goto done;
+	}
+
+	if (deinterlace_3_field(vout) && list_is_singular(&q->stream)) {
+		v4l2_err(vout->vfd->v4l2_dev,
+			"deinterlacing: need queue 2 frame before streamon\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = config_disp_output(vout);
+	if (ret < 0) {
+		v4l2_err(vout->vfd->v4l2_dev,
+				"Config display output failed\n");
+		goto done;
+	}
+
+	hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+	vout->timer.function = mxc_vout_timer_handler;
+	vout->timer_stop = true;
+	vout->frame_count = 0;
+	vout->vdi_frame_cnt = 0;
+
+	vout->start_ktime = hrtimer_cb_get_time(&vout->timer);
+
+	vout->pre1_vb = NULL;
+	vout->pre2_vb = NULL;
+
+	ret = videobuf_streamon(q);
+done:
+	return ret;
+}
+
+static int mxc_vidioc_streamoff(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct mxc_vout_output *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	int ret = 0;
+
+	if (q->streaming) {
+		flush_workqueue(vout->v4l_wq);
+
+		hrtimer_cancel(&vout->timer);
+
+		/*
+		 * Wait for 2 vsyncs to make sure
+		 * frames are drained on triple
+		 * buffer.
+		 */
+		wait_for_vsync(vout);
+		wait_for_vsync(vout);
+
+		release_disp_output(vout);
+
+		ret = videobuf_streamoff(&vout->vbq);
+	}
+	INIT_LIST_HEAD(&vout->queue_list);
+	INIT_LIST_HEAD(&vout->active_list);
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops mxc_vout_ioctl_ops = {
+	.vidioc_querycap			= mxc_vidioc_querycap,
+	.vidioc_enum_fmt_vid_out		= mxc_vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out			= mxc_vidioc_g_fmt_vid_out,
+	.vidioc_s_fmt_vid_out			= mxc_vidioc_s_fmt_vid_out,
+	.vidioc_g_selection			= mxc_vidioc_g_selection,
+	.vidioc_s_selection			= mxc_vidioc_s_selection,
+	.vidioc_queryctrl			= mxc_vidioc_queryctrl,
+	.vidioc_g_ctrl				= mxc_vidioc_g_ctrl,
+	.vidioc_s_ctrl				= mxc_vidioc_s_ctrl,
+	.vidioc_reqbufs				= mxc_vidioc_reqbufs,
+	.vidioc_querybuf			= mxc_vidioc_querybuf,
+	.vidioc_qbuf				= mxc_vidioc_qbuf,
+	.vidioc_dqbuf				= mxc_vidioc_dqbuf,
+	.vidioc_streamon			= mxc_vidioc_streamon,
+	.vidioc_streamoff			= mxc_vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations mxc_vout_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= mxc_vout_ioctl,
+	.mmap		= mxc_vout_mmap,
+	.open		= mxc_vout_open,
+	.release	= mxc_vout_release,
+};
+
+static struct video_device mxc_vout_template = {
+	.name		= "MXC Video Output",
+	.device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT,
+	.fops           = &mxc_vout_fops,
+	.ioctl_ops	= &mxc_vout_ioctl_ops,
+	.release	= video_device_release,
+};
+
+static struct videobuf_queue_ops mxc_vout_vbq_ops = {
+	.buf_setup = mxc_vout_buffer_setup,
+	.buf_prepare = mxc_vout_buffer_prepare,
+	.buf_release = mxc_vout_buffer_release,
+	.buf_queue = mxc_vout_buffer_queue,
+};
+
+static void mxc_vout_free_output(struct mxc_vout_dev *dev)
+{
+	int i;
+	int j;
+	struct mxc_vout_output *vout;
+	struct video_device *vfd;
+
+	for (i = 0; i < dev->out_num; i++) {
+		vout = dev->out[i];
+		vfd = vout->vfd;
+		if (vout->vdoa_work.vaddr)
+			free_dma_buf(vout, &vout->vdoa_work);
+		for (j = 0; j < VDOA_FB_BUFS; j++) {
+			if (vout->vdoa_output[j].vaddr)
+				free_dma_buf(vout, &vout->vdoa_output[j]);
+		}
+		if (vfd) {
+			if (!video_is_registered(vfd))
+				video_device_release(vfd);
+			else
+				video_unregister_device(vfd);
+		}
+		kfree(vout);
+	}
+}
+
+static int mxc_vout_setup_output(struct mxc_vout_dev *dev)
+{
+	struct videobuf_queue *q;
+	struct fb_info *fbi;
+	struct mxc_vout_output *vout;
+	int i, ret = 0;
+
+	update_display_setting();
+
+	/* all output/overlay based on fb */
+	for (i = 0; i < num_registered_fb; i++) {
+		fbi = registered_fb[i];
+
+		vout = kzalloc(sizeof(struct mxc_vout_output), GFP_KERNEL);
+		if (!vout) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		dev->out[dev->out_num] = vout;
+		dev->out_num++;
+
+		vout->fbi = fbi;
+		vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		vout->vfd = video_device_alloc();
+		if (!vout->vfd) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		*vout->vfd = mxc_vout_template;
+		vout->vfd->v4l2_dev = &dev->v4l2_dev;
+		vout->vfd->lock = &vout->mutex;
+		vout->vfd->vfl_dir = VFL_DIR_TX;
+
+		mutex_init(&vout->mutex);
+		mutex_init(&vout->task_lock);
+		mutex_init(&vout->accs_lock);
+
+		strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name));
+
+		video_set_drvdata(vout->vfd, vout);
+
+		if (video_register_device(vout->vfd,
+			VFL_TYPE_GRABBER, video_nr + i) < 0) {
+			ret = -ENODEV;
+			break;
+		}
+
+		q = &vout->vbq;
+		q->dev = dev->dev;
+		spin_lock_init(&vout->vbq_lock);
+		videobuf_queue_dma_contig_init(q, &mxc_vout_vbq_ops, q->dev,
+				&vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
+				sizeof(struct videobuf_buffer), vout, NULL);
+
+		v4l2_info(vout->vfd->v4l2_dev, "V4L2 device registered as %s\n",
+				video_device_node_name(vout->vfd));
+
+	}
+
+	return ret;
+}
+
+static int mxc_vout_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct mxc_vout_dev *dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->dev = &pdev->dev;
+	dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), GFP_KERNEL);
+	*dev->dev->dma_mask = DMA_BIT_MASK(32);
+	dev->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ret = v4l2_device_register(dev->dev, &dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev->dev, "v4l2_device_register failed\n");
+		goto free_dev;
+	}
+
+	ret = mxc_vout_setup_output(dev);
+	if (ret < 0)
+		goto rel_vdev;
+
+	return 0;
+
+rel_vdev:
+	mxc_vout_free_output(dev);
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	kfree(dev);
+	return ret;
+}
+
+static int mxc_vout_remove(struct platform_device *pdev)
+{
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct mxc_vout_dev *dev = container_of(v4l2_dev, struct
+			mxc_vout_dev, v4l2_dev);
+
+	mxc_vout_free_output(dev);
+	v4l2_device_unregister(v4l2_dev);
+	kfree(dev);
+	return 0;
+}
+
+static const struct of_device_id mxc_v4l2_dt_ids[] = {
+	{ .compatible = "fsl,mxc_v4l2_output", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver mxc_vout_driver = {
+	.driver = {
+		.name = "mxc_v4l2_output",
+		.of_match_table = mxc_v4l2_dt_ids,
+	},
+	.probe = mxc_vout_probe,
+	.remove = mxc_vout_remove,
+};
+
+static int __init mxc_vout_init(void)
+{
+	if (platform_driver_register(&mxc_vout_driver) != 0) {
+		printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void mxc_vout_cleanup(void)
+{
+	platform_driver_unregister(&mxc_vout_driver);
+}
+
+module_init(mxc_vout_init);
+module_exit(mxc_vout_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("V4L2-driver for MXC video output");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/media/platform/omap3isp/isp.c
+++ linux-ein-5.4.0/drivers/media/platform/omap3isp/isp.c
@@ -2312,7 +2312,16 @@
 
 	/* Regulators */
 	isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1");
+	if (IS_ERR(isp->isp_csiphy1.vdd)) {
+		ret = PTR_ERR(isp->isp_csiphy1.vdd);
+		goto error;
+	}
+
 	isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2");
+	if (IS_ERR(isp->isp_csiphy2.vdd)) {
+		ret = PTR_ERR(isp->isp_csiphy2.vdd);
+		goto error;
+	}
 
 	/* Clocks
 	 *
@@ -2330,8 +2339,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-ein-5.4.0.orig/drivers/media/platform/omap3isp/isppreview.c
+++ linux-ein-5.4.0/drivers/media/platform/omap3isp/isppreview.c
@@ -2287,7 +2287,7 @@
 	me->ops = &preview_media_ops;
 	ret = media_entity_pads_init(me, PREV_PADS_NUM, pads);
 	if (ret < 0)
-		return ret;
+		goto error_handler_free;
 
 	preview_init_formats(sd, NULL);
 
@@ -2320,6 +2320,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-ein-5.4.0.orig/drivers/media/platform/pxa_camera.c
+++ linux-ein-5.4.0/drivers/media/platform/pxa_camera.c
@@ -1447,6 +1447,9 @@
 	struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue);
 	struct pxa_buffer *buf = vb2_to_pxa_buffer(vb);
 	int ret = 0;
+#ifdef DEBUG
+	int i;
+#endif
 
 	switch (pcdev->channels) {
 	case 1:
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -176,8 +176,10 @@
 		int ret;
 
 		ret = pm_runtime_get_sync(dev);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put_sync(dev);
 			return ret;
+		}
 
 		ret = csiphy_set_clock_rates(csiphy);
 		if (ret < 0) {
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/camss/camss-video.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/camss/camss-video.c
@@ -438,7 +438,7 @@
 
 	ret = media_pipeline_start(&vdev->entity, &video->pipe);
 	if (ret < 0)
-		return ret;
+		goto flush_buffers;
 
 	ret = video_check_format(video);
 	if (ret < 0)
@@ -467,6 +467,7 @@
 error:
 	media_pipeline_stop(&vdev->entity);
 
+flush_buffers:
 	video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
 
 	return ret;
@@ -901,6 +902,7 @@
 			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
 		}
 	} else {
+		ret = -EINVAL;
 		goto error_video_register;
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/camss/camss.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/camss/camss.c
@@ -504,7 +504,6 @@
 	return num_subdevs;
 
 err_cleanup:
-	v4l2_async_notifier_cleanup(&camss->notifier);
 	of_node_put(node);
 	return ret;
 }
@@ -835,29 +834,38 @@
 		camss->csid_num = 4;
 		camss->vfe_num = 2;
 	} else {
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_free;
 	}
 
 	camss->csiphy = devm_kcalloc(dev, camss->csiphy_num,
 				     sizeof(*camss->csiphy), GFP_KERNEL);
-	if (!camss->csiphy)
-		return -ENOMEM;
+	if (!camss->csiphy) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid),
 				   GFP_KERNEL);
-	if (!camss->csid)
-		return -ENOMEM;
+	if (!camss->csid) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
 				  GFP_KERNEL);
-	if (!camss->vfe)
-		return -ENOMEM;
+	if (!camss->vfe) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
 
 	v4l2_async_notifier_init(&camss->notifier);
 
 	num_subdevs = camss_of_parse_ports(camss);
-	if (num_subdevs < 0)
-		return num_subdevs;
+	if (num_subdevs < 0) {
+		ret = num_subdevs;
+		goto err_cleanup;
+	}
 
 	ret = camss_init_subdevices(camss);
 	if (ret < 0)
@@ -936,6 +944,8 @@
 	v4l2_device_unregister(&camss->v4l2_dev);
 err_cleanup:
 	v4l2_async_notifier_cleanup(&camss->notifier);
+err_free:
+	kfree(camss);
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/core.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/core.c
@@ -289,11 +289,11 @@
 
 	ret = venus_firmware_init(core);
 	if (ret)
-		goto err_runtime_disable;
+		goto err_of_depopulate;
 
 	ret = venus_boot(core);
 	if (ret)
-		goto err_runtime_disable;
+		goto err_firmware_deinit;
 
 	ret = hfi_core_resume(core, true);
 	if (ret)
@@ -316,8 +316,10 @@
 		goto err_core_deinit;
 
 	ret = pm_runtime_put_sync(dev);
-	if (ret)
+	if (ret) {
+		pm_runtime_get_noresume(dev);
 		goto err_dev_unregister;
+	}
 
 	return 0;
 
@@ -327,7 +329,12 @@
 	hfi_core_deinit(core, false);
 err_venus_shutdown:
 	venus_shutdown(core);
+err_firmware_deinit:
+	venus_firmware_deinit(core);
+err_of_depopulate:
+	of_platform_depopulate(dev);
 err_runtime_disable:
+	pm_runtime_put_noidle(dev);
 	pm_runtime_set_suspended(dev);
 	pm_runtime_disable(dev);
 	hfi_destroy(core);
@@ -427,10 +434,11 @@
 };
 
 static const struct freq_tbl msm8996_freq_table[] = {
-	{ 1944000, 490000000 },	/* 4k UHD @ 60 */
-	{  972000, 320000000 },	/* 4k UHD @ 30 */
-	{  489600, 150000000 },	/* 1080p @ 60 */
-	{  244800,  75000000 },	/* 1080p @ 30 */
+	{ 1944000, 520000000 },	/* 4k UHD @ 60 (decode only) */
+	{  972000, 520000000 },	/* 4k UHD @ 30 */
+	{  489600, 346666667 },	/* 1080p @ 60 */
+	{  244800, 150000000 },	/* 1080p @ 30 */
+	{  108000,  75000000 },	/* 720p @ 30 */
 };
 
 static const struct reg_val msm8996_reg_preset[] = {
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/firmware.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/firmware.c
@@ -44,8 +44,14 @@
 
 int venus_set_hw_state(struct venus_core *core, bool resume)
 {
-	if (core->use_tz)
-		return qcom_scm_set_remote_state(resume, 0);
+	int ret;
+
+	if (core->use_tz) {
+		ret = qcom_scm_set_remote_state(resume, 0);
+		if (resume && ret == -EINVAL)
+			ret = 0;
+		return ret;
+	}
 
 	if (resume)
 		venus_reset_cpu(core);
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/hfi.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/hfi.c
@@ -104,6 +104,9 @@
 		mutex_lock(&core->lock);
 	}
 
+	if (!core->ops)
+		goto unlock;
+
 	ret = core->ops->core_deinit(core);
 
 	if (!ret)
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/hfi_msgs.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/hfi_msgs.c
@@ -350,7 +350,7 @@
 		memcpy(&bufreq[idx], buf_req, sizeof(*bufreq));
 		idx++;
 
-		if (idx > HFI_BUFFER_TYPE_MAX)
+		if (idx >= HFI_BUFFER_TYPE_MAX)
 			return HFI_ERR_SESSION_INVALID_PARAMETER;
 
 		req_bytes -= sizeof(struct hfi_buffer_requirements);
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/hfi_parser.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/hfi_parser.c
@@ -19,6 +19,9 @@
 	struct venus_caps *caps = core->caps, *cap;
 	unsigned long bit;
 
+	if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM)
+		return;
+
 	for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {
 		cap = &caps[core->codecs_count++];
 		cap->codec = BIT(bit);
@@ -86,6 +89,9 @@
 {
 	const struct hfi_profile_level *pl = data;
 
+	if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT)
+		return;
+
 	memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));
 	cap->num_pl += num;
 }
@@ -111,6 +117,9 @@
 {
 	const struct hfi_capability *caps = data;
 
+	if (cap->num_caps + num >= MAX_CAP_ENTRIES)
+		return;
+
 	memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));
 	cap->num_caps += num;
 }
@@ -137,6 +146,9 @@
 {
 	const struct raw_formats *formats = fmts;
 
+	if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES)
+		return;
+
 	memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));
 	cap->num_fmts += num_fmts;
 }
@@ -159,6 +171,9 @@
 		rawfmts[i].buftype = fmt->buffer_type;
 		i++;
 
+		if (i >= MAX_FMT_ENTRIES)
+			return;
+
 		if (pinfo->num_planes > MAX_PLANES)
 			break;
 
@@ -181,6 +196,7 @@
 	if (IS_V1(core)) {
 		core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;
 		core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
+		core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/hfi_venus.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -206,6 +206,11 @@
 
 	new_wr_idx = wr_idx + dwords;
 	wr_ptr = (u32 *)(queue->qmem.kva + (wr_idx << 2));
+
+	if (wr_ptr < (u32 *)queue->qmem.kva ||
+	    wr_ptr > (u32 *)(queue->qmem.kva + queue->qmem.size - sizeof(*wr_ptr)))
+		return -EINVAL;
+
 	if (new_wr_idx < qsize) {
 		memcpy(wr_ptr, packet, dwords << 2);
 	} else {
@@ -273,6 +278,11 @@
 	}
 
 	rd_ptr = (u32 *)(queue->qmem.kva + (rd_idx << 2));
+
+	if (rd_ptr < (u32 *)queue->qmem.kva ||
+	    rd_ptr > (u32 *)(queue->qmem.kva + queue->qmem.size - sizeof(*rd_ptr)))
+		return -EINVAL;
+
 	dwords = *rd_ptr >> 2;
 	if (!dwords)
 		return -EINVAL;
@@ -1472,6 +1482,7 @@
 {
 	struct venus_hfi_device *hdev = to_hfi_priv(core);
 	struct device *dev = core->dev;
+	u32 ctrl_status;
 	bool val;
 	int ret;
 
@@ -1487,6 +1498,10 @@
 		return -EINVAL;
 	}
 
+	ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+	if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
+		goto power_off;
+
 	/*
 	 * Power collapse sequence for Venus 3xx and 4xx versions:
 	 * 1. Check for ARM9 and video core to be idle by checking WFI bit
@@ -1511,6 +1526,7 @@
 	if (ret)
 		return ret;
 
+power_off:
 	mutex_lock(&hdev->lock);
 
 	ret = venus_power_off(hdev);
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/vdec.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/vdec.c
@@ -157,6 +157,8 @@
 		else
 			return NULL;
 		fmt = find_format(inst, pixmp->pixelformat, f->type);
+		if (!fmt)
+			return NULL;
 	}
 
 	pixmp->width = clamp(pixmp->width, frame_width_min(inst),
@@ -987,11 +989,10 @@
 		ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT);
 		vdec_cancel_dst_buffers(inst);
 		inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP;
-		INIT_LIST_HEAD(&inst->registeredbufs);
 		venus_helper_free_dpb_bufs(inst);
 		break;
 	default:
-		return 0;
+		break;
 	}
 
 	return ret;
@@ -1090,6 +1091,14 @@
 static void vdec_buf_cleanup(struct vb2_buffer *vb)
 {
 	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct venus_buffer *buf = to_venus_buffer(vbuf);
+
+	mutex_lock(&inst->lock);
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		if (!list_empty(&inst->registeredbufs))
+			list_del_init(&buf->reg_list);
+	mutex_unlock(&inst->lock);
 
 	inst->buf_count--;
 	if (!inst->buf_count)
@@ -1412,9 +1421,6 @@
 	.unlocked_ioctl = video_ioctl2,
 	.poll = v4l2_m2m_fop_poll,
 	.mmap = v4l2_m2m_fop_mmap,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl32 = v4l2_compat_ioctl32,
-#endif
 };
 
 static int vdec_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/media/platform/qcom/venus/venc.c
+++ linux-ein-5.4.0/drivers/media/platform/qcom/venus/venc.c
@@ -308,6 +308,8 @@
 		else
 			return NULL;
 		fmt = find_format(inst, pixmp->pixelformat, f->type);
+		if (!fmt)
+			return NULL;
 	}
 
 	pixmp->width = clamp(pixmp->width, frame_width_min(inst),
@@ -1235,9 +1237,6 @@
 	.unlocked_ioctl = video_ioctl2,
 	.poll = v4l2_m2m_fop_poll,
 	.mmap = v4l2_m2m_fop_mmap,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl32 = v4l2_compat_ioctl32,
-#endif
 };
 
 static int venc_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar-fcp.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar-fcp.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -21,6 +22,7 @@
 struct rcar_fcp_device {
 	struct list_head list;
 	struct device *dev;
+	struct device_dma_parameters dma_parms;
 };
 
 static LIST_HEAD(fcp_devices);
@@ -101,8 +103,10 @@
 		return 0;
 
 	ret = pm_runtime_get_sync(fcp->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(fcp->dev);
 		return ret;
+	}
 
 	return 0;
 }
@@ -136,6 +140,9 @@
 
 	fcp->dev = &pdev->dev;
 
+	fcp->dev->dma_parms = &fcp->dma_parms;
+	dma_set_max_seg_size(fcp->dev, DMA_BIT_MASK(32));
+
 	pm_runtime_enable(&pdev->dev);
 
 	mutex_lock(&fcp_lock);
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -361,7 +361,6 @@
 	struct media_pad pads[NR_OF_RCAR_CSI2_PAD];
 
 	struct v4l2_async_notifier notifier;
-	struct v4l2_async_subdev asd;
 	struct v4l2_subdev *remote;
 
 	struct v4l2_mbus_framefmt mf;
@@ -431,16 +430,23 @@
 static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
 {
 	const struct rcsi2_mbps_reg *hsfreq;
+	const struct rcsi2_mbps_reg *hsfreq_prev = NULL;
 
-	for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++)
+	for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) {
 		if (hsfreq->mbps >= mbps)
 			break;
+		hsfreq_prev = hsfreq;
+	}
 
 	if (!hsfreq->mbps) {
 		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
 		return -ERANGE;
 	}
 
+	if (hsfreq_prev &&
+	    ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps)))
+		hsfreq = hsfreq_prev;
+
 	rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg));
 
 	return 0;
@@ -489,6 +495,8 @@
 
 	/* Code is validated in set_fmt. */
 	format = rcsi2_code_to_fmt(priv->mf.code);
+	if (!format)
+		return -EINVAL;
 
 	/*
 	 * Enable all supported CSI-2 channels with virtual channel and
@@ -810,6 +818,8 @@
 
 static int rcsi2_parse_dt(struct rcar_csi2 *priv)
 {
+	struct v4l2_async_subdev *asd;
+	struct fwnode_handle *fwnode;
 	struct device_node *ep;
 	struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
 	int ret;
@@ -833,24 +843,19 @@
 		return ret;
 	}
 
-	priv->asd.match.fwnode =
-		fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep));
-	priv->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
-
+	fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep));
 	of_node_put(ep);
 
-	v4l2_async_notifier_init(&priv->notifier);
-
-	ret = v4l2_async_notifier_add_subdev(&priv->notifier, &priv->asd);
-	if (ret) {
-		fwnode_handle_put(priv->asd.match.fwnode);
-		return ret;
-	}
+	dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode));
 
+	v4l2_async_notifier_init(&priv->notifier);
 	priv->notifier.ops = &rcar_csi2_notify_ops;
 
-	dev_dbg(priv->dev, "Found '%pOF'\n",
-		to_of_node(priv->asd.match.fwnode));
+	asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode,
+						    sizeof(*asd));
+	fwnode_handle_put(fwnode);
+	if (IS_ERR(asd))
+		return PTR_ERR(asd);
 
 	ret = v4l2_async_subdev_notifier_register(&priv->subdev,
 						  &priv->notifier);
@@ -906,10 +911,17 @@
 				 const struct rcsi2_mbps_reg *values, u16 code)
 {
 	const struct rcsi2_mbps_reg *value;
+	const struct rcsi2_mbps_reg *prev_value = NULL;
 
-	for (value = values; value->mbps; value++)
+	for (value = values; value->mbps; value++) {
 		if (value->mbps >= mbps)
 			break;
+		prev_value = value;
+	}
+
+	if (prev_value &&
+	    ((mbps - prev_value->mbps) <= (value->mbps - mbps)))
+		value = prev_value;
 
 	if (!value->mbps) {
 		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar-vin/rcar-dma.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -638,6 +638,7 @@
 		vnmc = VNMC_IM_FULL | VNMC_FOC;
 		break;
 	case V4L2_FIELD_NONE:
+	case V4L2_FIELD_ALTERNATE:
 		vnmc = VNMC_IM_ODD_EVEN;
 		progressive = true;
 		break;
@@ -1334,8 +1335,10 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(vin->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(vin->dev);
 		return ret;
+	}
 
 	/* Make register writes take effect immediately. */
 	vnmc = rvin_read(vin, VNMC_REG);
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -208,6 +208,7 @@
 	ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
 	if (ret < 0 && ret != -ENOIOCTLCMD)
 		goto done;
+	ret = 0;
 
 	v4l2_fill_pix_format(pix, &format.format);
 
@@ -242,7 +243,7 @@
 done:
 	v4l2_subdev_free_pad_config(pad_cfg);
 
-	return 0;
+	return ret;
 }
 
 static int rvin_querycap(struct file *file, void *priv,
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar_drif.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar_drif.c
@@ -185,7 +185,6 @@
 /* OF graph endpoint's V4L2 async data */
 struct rcar_drif_graph_ep {
 	struct v4l2_subdev *subdev;	/* Async matched subdev */
-	struct v4l2_async_subdev asd;	/* Async sub-device descriptor */
 };
 
 /* DMA buffer */
@@ -1104,12 +1103,6 @@
 	struct rcar_drif_sdr *sdr =
 		container_of(notifier, struct rcar_drif_sdr, notifier);
 
-	if (sdr->ep.asd.match.fwnode !=
-	    of_fwnode_handle(subdev->dev->of_node)) {
-		rdrif_err(sdr, "subdev %s cannot bind\n", subdev->name);
-		return -EINVAL;
-	}
-
 	v4l2_set_subdev_hostdata(subdev, sdr);
 	sdr->ep.subdev = subdev;
 	rdrif_dbg(sdr, "bound asd %s\n", subdev->name);
@@ -1213,7 +1206,7 @@
 {
 	struct v4l2_async_notifier *notifier = &sdr->notifier;
 	struct fwnode_handle *fwnode, *ep;
-	int ret;
+	struct v4l2_async_subdev *asd;
 
 	v4l2_async_notifier_init(notifier);
 
@@ -1222,26 +1215,21 @@
 	if (!ep)
 		return 0;
 
+	/* Get the endpoint properties */
+	rcar_drif_get_ep_properties(sdr, ep);
+
 	fwnode = fwnode_graph_get_remote_port_parent(ep);
+	fwnode_handle_put(ep);
 	if (!fwnode) {
 		dev_warn(sdr->dev, "bad remote port parent\n");
-		fwnode_handle_put(ep);
 		return -EINVAL;
 	}
 
-	sdr->ep.asd.match.fwnode = fwnode;
-	sdr->ep.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
-	ret = v4l2_async_notifier_add_subdev(notifier, &sdr->ep.asd);
-	if (ret) {
-		fwnode_handle_put(fwnode);
-		return ret;
-	}
-
-	/* Get the endpoint properties */
-	rcar_drif_get_ep_properties(sdr, ep);
-
+	asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
+						    sizeof(*asd));
 	fwnode_handle_put(fwnode);
-	fwnode_handle_put(ep);
+	if (IS_ERR(asd))
+		return PTR_ERR(asd);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/rcar_fdp1.c
+++ linux-ein-5.4.0/drivers/media/platform/rcar_fdp1.c
@@ -2121,9 +2121,7 @@
 
 	if (ctx->hdl.error) {
 		ret = ctx->hdl.error;
-		v4l2_ctrl_handler_free(&ctx->hdl);
-		kfree(ctx);
-		goto done;
+		goto error_ctx;
 	}
 
 	ctx->fh.ctrl_handler = &ctx->hdl;
@@ -2137,20 +2135,27 @@
 
 	if (IS_ERR(ctx->fh.m2m_ctx)) {
 		ret = PTR_ERR(ctx->fh.m2m_ctx);
-
-		v4l2_ctrl_handler_free(&ctx->hdl);
-		kfree(ctx);
-		goto done;
+		goto error_ctx;
 	}
 
 	/* Perform any power management required */
-	pm_runtime_get_sync(fdp1->dev);
+	ret = pm_runtime_resume_and_get(fdp1->dev);
+	if (ret < 0)
+		goto error_pm;
 
 	v4l2_fh_add(&ctx->fh);
 
 	dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n",
 		ctx, ctx->fh.m2m_ctx);
 
+	mutex_unlock(&fdp1->dev_mutex);
+	return 0;
+
+error_pm:
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+error_ctx:
+	v4l2_ctrl_handler_free(&ctx->hdl);
+	kfree(ctx);
 done:
 	mutex_unlock(&fdp1->dev_mutex);
 	return ret;
@@ -2255,7 +2260,6 @@
 	struct fdp1_dev *fdp1;
 	struct video_device *vfd;
 	struct device_node *fcp_node;
-	struct resource *res;
 	struct clk *clk;
 	unsigned int i;
 
@@ -2282,17 +2286,15 @@
 	platform_set_drvdata(pdev, fdp1);
 
 	/* Memory-mapped registers */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	fdp1->regs = devm_ioremap_resource(&pdev->dev, res);
+	fdp1->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(fdp1->regs))
 		return PTR_ERR(fdp1->regs);
 
 	/* Interrupt service routine registration */
-	fdp1->irq = ret = platform_get_irq(pdev, 0);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot find IRQ\n");
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
 		return ret;
-	}
+	fdp1->irq = ret;
 
 	ret = devm_request_irq(&pdev->dev, fdp1->irq, fdp1_irq_handler, 0,
 			       dev_name(&pdev->dev), fdp1);
@@ -2315,8 +2317,10 @@
 
 	/* Determine our clock rate */
 	clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		goto put_dev;
+	}
 
 	fdp1->clk_rate = clk_get_rate(clk);
 	clk_put(clk);
@@ -2325,7 +2329,7 @@
 	ret = v4l2_device_register(&pdev->dev, &fdp1->v4l2_dev);
 	if (ret) {
 		v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n");
-		return ret;
+		goto put_dev;
 	}
 
 	/* M2M registration */
@@ -2355,7 +2359,9 @@
 
 	/* Power up the cells to read HW */
 	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(fdp1->dev);
+	ret = pm_runtime_resume_and_get(fdp1->dev);
+	if (ret < 0)
+		goto disable_pm;
 
 	hw_version = fdp1_read(fdp1, FD1_IP_INTDATA);
 	switch (hw_version) {
@@ -2369,7 +2375,7 @@
 		dprintk(fdp1, "FDP1 Version R-Car H3\n");
 		break;
 	case FD1_IP_M3N:
-		dprintk(fdp1, "FDP1 Version R-Car M3N\n");
+		dprintk(fdp1, "FDP1 Version R-Car M3-N\n");
 		break;
 	case FD1_IP_E3:
 		dprintk(fdp1, "FDP1 Version R-Car E3\n");
@@ -2384,12 +2390,17 @@
 
 	return 0;
 
+disable_pm:
+	pm_runtime_disable(fdp1->dev);
+
 release_m2m:
 	v4l2_m2m_release(fdp1->m2m_dev);
 
 unreg_dev:
 	v4l2_device_unregister(&fdp1->v4l2_dev);
 
+put_dev:
+	rcar_fcp_put(fdp1->fcp);
 	return ret;
 }
 
@@ -2401,6 +2412,7 @@
 	video_unregister_device(&fdp1->vfd);
 	v4l2_device_unregister(&fdp1->v4l2_dev);
 	pm_runtime_disable(&pdev->dev);
+	rcar_fcp_put(fdp1->fcp);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/rockchip/rga/rga-buf.c
+++ linux-ein-5.4.0/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -81,6 +81,7 @@
 
 	ret = pm_runtime_get_sync(rga->dev);
 	if (ret < 0) {
+		pm_runtime_put_noidle(rga->dev);
 		rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
 		return ret;
 	}
--- linux-ein-5.4.0.orig/drivers/media/platform/rockchip/rga/rga-hw.c
+++ linux-ein-5.4.0/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -200,22 +200,25 @@
 	dst_info.data.format = ctx->out.fmt->hw_format;
 	dst_info.data.swap = ctx->out.fmt->color_swap;
 
-	if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
-		if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
-			switch (ctx->in.colorspace) {
-			case V4L2_COLORSPACE_REC709:
-				src_info.data.csc_mode =
-					RGA_SRC_CSC_MODE_BT709_R0;
-				break;
-			default:
-				src_info.data.csc_mode =
-					RGA_SRC_CSC_MODE_BT601_R0;
-				break;
-			}
+	/*
+	 * CSC mode must only be set when the colorspace families differ between
+	 * input and output. It must remain unset (zeroed) if both are the same.
+	 */
+
+	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
+		switch (ctx->in.colorspace) {
+		case V4L2_COLORSPACE_REC709:
+			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
+			break;
+		default:
+			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0;
+			break;
 		}
 	}
 
-	if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
 		switch (ctx->out.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
--- linux-ein-5.4.0.orig/drivers/media/platform/rockchip/rga/rga-hw.h
+++ linux-ein-5.4.0/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -95,6 +95,11 @@
 #define RGA_COLOR_FMT_CP_8BPP 15
 #define RGA_COLOR_FMT_MASK 15
 
+#define RGA_COLOR_FMT_IS_YUV(fmt) \
+	(((fmt) >= RGA_COLOR_FMT_YUV422SP) && ((fmt) < RGA_COLOR_FMT_CP_1BPP))
+#define RGA_COLOR_FMT_IS_RGB(fmt) \
+	((fmt) < RGA_COLOR_FMT_YUV422SP)
+
 #define RGA_COLOR_NONE_SWAP 0
 #define RGA_COLOR_RB_SWAP 1
 #define RGA_COLOR_ALPHA_SWAP 2
--- linux-ein-5.4.0.orig/drivers/media/platform/rockchip/rga/rga.c
+++ linux-ein-5.4.0/drivers/media/platform/rockchip/rga/rga.c
@@ -187,7 +187,7 @@
 static struct rga_fmt formats[] = {
 	{
 		.fourcc = V4L2_PIX_FMT_ARGB32,
-		.color_swap = RGA_COLOR_RB_SWAP,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
 		.hw_format = RGA_COLOR_FMT_ABGR8888,
 		.depth = 32,
 		.uv_factor = 1,
@@ -195,17 +195,8 @@
 		.x_div = 1,
 	},
 	{
-		.fourcc = V4L2_PIX_FMT_XRGB32,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_XBGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
 		.fourcc = V4L2_PIX_FMT_ABGR32,
-		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.color_swap = RGA_COLOR_RB_SWAP,
 		.hw_format = RGA_COLOR_FMT_ABGR8888,
 		.depth = 32,
 		.uv_factor = 1,
@@ -214,7 +205,7 @@
 	},
 	{
 		.fourcc = V4L2_PIX_FMT_XBGR32,
-		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.color_swap = RGA_COLOR_RB_SWAP,
 		.hw_format = RGA_COLOR_FMT_XBGR8888,
 		.depth = 32,
 		.uv_factor = 1,
--- linux-ein-5.4.0.orig/drivers/media/platform/s3c-camif/camif-capture.c
+++ linux-ein-5.4.0/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1132,12 +1132,12 @@
 
 	ret = vb2_queue_init(q);
 	if (ret)
-		goto err_vd_rel;
+		return ret;
 
 	vp->pad.flags = MEDIA_PAD_FL_SINK;
 	ret = media_entity_pads_init(&vfd->entity, 1, &vp->pad);
 	if (ret)
-		goto err_vd_rel;
+		return ret;
 
 	video_set_drvdata(vfd, vp);
 
@@ -1170,8 +1170,6 @@
 	v4l2_ctrl_handler_free(&vp->ctrl_handler);
 err_me_cleanup:
 	media_entity_cleanup(&vfd->entity);
-err_vd_rel:
-	video_device_release(vfd);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/s3c-camif/camif-core.c
+++ linux-ein-5.4.0/drivers/media/platform/s3c-camif/camif-core.c
@@ -464,7 +464,7 @@
 
 	ret = camif_media_dev_init(camif);
 	if (ret < 0)
-		goto err_alloc;
+		goto err_pm;
 
 	ret = camif_register_sensor(camif);
 	if (ret < 0)
@@ -498,10 +498,9 @@
 	media_device_unregister(&camif->media_dev);
 	media_device_cleanup(&camif->media_dev);
 	camif_unregister_media_entities(camif);
-err_alloc:
+err_pm:
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
-err_pm:
 	camif_clk_put(camif);
 err_clk:
 	s3c_camif_unregister_subdev(camif);
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-cec/s5p_cec.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-cec/s5p_cec.c
@@ -35,10 +35,13 @@
 
 static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
+	int ret;
 	struct s5p_cec_dev *cec = cec_get_drvdata(adap);
 
 	if (enable) {
-		pm_runtime_get_sync(cec->dev);
+		ret = pm_runtime_resume_and_get(cec->dev);
+		if (ret < 0)
+			return ret;
 
 		s5p_cec_reset(cec);
 
@@ -51,7 +54,7 @@
 	} else {
 		s5p_cec_mask_tx_interrupts(cec);
 		s5p_cec_mask_rx_interrupts(cec);
-		pm_runtime_disable(cec->dev);
+		pm_runtime_put(cec->dev);
 	}
 
 	return 0;
@@ -112,6 +115,8 @@
 				dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n");
 			cec->rx = STATE_BUSY;
 			cec->msg.len = status >> 24;
+			if (cec->msg.len > CEC_MAX_MSG_SIZE)
+				cec->msg.len = CEC_MAX_MSG_SIZE;
 			cec->msg.rx_status = CEC_RX_STATUS_OK;
 			s5p_cec_get_rx_buf(cec, cec->msg.len,
 					cec->msg.msg);
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-g2d/g2d.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-g2d/g2d.c
@@ -276,6 +276,9 @@
 	struct g2d_dev *dev = video_drvdata(file);
 	struct g2d_ctx *ctx = fh2ctx(file->private_data);
 
+	mutex_lock(&dev->mutex);
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+	mutex_unlock(&dev->mutex);
 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -2579,11 +2579,8 @@
 static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
-	int ret;
 
-	ret = pm_runtime_get_sync(ctx->jpeg->dev);
-
-	return ret > 0 ? 0 : ret;
+	return pm_runtime_resume_and_get(ctx->jpeg->dev);
 }
 
 static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -1279,11 +1279,15 @@
 	spin_lock_init(&dev->condlock);
 	dev->plat_dev = pdev;
 	if (!dev->plat_dev) {
-		dev_err(&pdev->dev, "No platform data specified\n");
+		mfc_err("No platform data specified\n");
 		return -ENODEV;
 	}
 
 	dev->variant = of_device_get_match_data(&pdev->dev);
+	if (!dev->variant) {
+		dev_err(&pdev->dev, "Failed to get device MFC hardware variant information\n");
+		return -ENOENT;
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
@@ -1576,8 +1580,18 @@
 	.port_num	= MFC_NUM_PORTS_V7,
 	.buf_size	= &buf_size_v7,
 	.fw_name[0]     = "s5p-mfc-v7.fw",
-	.clk_names	= {"mfc", "sclk_mfc"},
-	.num_clocks	= 2,
+	.clk_names	= {"mfc"},
+	.num_clocks	= 1,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v7_3250 = {
+	.version        = MFC_VERSION_V7,
+	.version_bit    = MFC_V7_BIT,
+	.port_num       = MFC_NUM_PORTS_V7,
+	.buf_size       = &buf_size_v7,
+	.fw_name[0]     = "s5p-mfc-v7.fw",
+	.clk_names      = {"mfc", "sclk_mfc"},
+	.num_clocks     = 2,
 };
 
 static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
@@ -1648,6 +1662,9 @@
 		.compatible = "samsung,mfc-v7",
 		.data = &mfc_drvdata_v7,
 	}, {
+		.compatible = "samsung,exynos3250-mfc",
+		.data = &mfc_drvdata_v7_3250,
+	}, {
 		.compatible = "samsung,mfc-v8",
 		.data = &mfc_drvdata_v8,
 	}, {
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -468,8 +468,10 @@
 	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
 	/* Wait until instance is returned or timeout occurred */
 	if (s5p_mfc_wait_for_done_ctx(ctx,
-				S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
+				S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)){
+		clear_work_bit_irqsave(ctx);
 		mfc_err("Err returning instance\n");
+	}
 
 	/* Free resources */
 	s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -1212,6 +1212,7 @@
 	unsigned long mb_y_addr, mb_c_addr;
 	int slice_type;
 	unsigned int strm_size;
+	bool src_ready;
 
 	slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev);
 	strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev);
@@ -1251,7 +1252,8 @@
 			}
 		}
 	}
-	if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+	if (ctx->src_queue_cnt > 0 && (ctx->state == MFCINST_RUNNING ||
+				       ctx->state == MFCINST_FINISHING)) {
 		mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
 									list);
 		if (mb_entry->flags & MFC_BUF_FLAG_USED) {
@@ -1282,7 +1284,13 @@
 		vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size);
 		vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
 	}
-	if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0))
+
+	src_ready = true;
+	if (ctx->state == MFCINST_RUNNING && ctx->src_queue_cnt == 0)
+		src_ready = false;
+	if (ctx->state == MFCINST_FINISHING && ctx->ref_queue_cnt == 0)
+		src_ready = false;
+	if (!src_ready || ctx->dst_queue_cnt == 0)
 		clear_work_bit(ctx);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1060,7 +1060,7 @@
 	}
 
 	/* aspect ratio VUI */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 5);
 	reg |= ((p_h264->vui_sar & 0x1) << 5);
 	writel(reg, mfc_regs->e_h264_options);
@@ -1083,7 +1083,7 @@
 
 	/* intra picture period for H.264 open GOP */
 	/* control */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 4);
 	reg |= ((p_h264->open_gop & 0x1) << 4);
 	writel(reg, mfc_regs->e_h264_options);
@@ -1097,23 +1097,23 @@
 	}
 
 	/* 'WEIGHTED_BI_PREDICTION' for B is disable */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x3 << 9);
 	writel(reg, mfc_regs->e_h264_options);
 
 	/* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 14);
 	writel(reg, mfc_regs->e_h264_options);
 
 	/* ASO */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 6);
 	reg |= ((p_h264->aso & 0x1) << 6);
 	writel(reg, mfc_regs->e_h264_options);
 
 	/* hier qp enable */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 8);
 	reg |= ((p_h264->open_gop & 0x1) << 8);
 	writel(reg, mfc_regs->e_h264_options);
@@ -1134,7 +1134,7 @@
 	writel(reg, mfc_regs->e_h264_num_t_layer);
 
 	/* frame packing SEI generation */
-	readl(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 25);
 	reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
 	writel(reg, mfc_regs->e_h264_options);
--- linux-ein-5.4.0.orig/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ linux-ein-5.4.0/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -79,8 +79,10 @@
 	int i, ret = 0;
 
 	ret = pm_runtime_get_sync(pm->device);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(pm->device);
 		return ret;
+	}
 
 	/* clock control */
 	for (i = 0; i < pm->num_clocks; i++) {
--- linux-ein-5.4.0.orig/drivers/media/platform/seco-cec/seco-cec.c
+++ linux-ein-5.4.0/drivers/media/platform/seco-cec/seco-cec.c
@@ -675,6 +675,7 @@
 err_delete_adapter:
 	cec_delete_adapter(secocec->cec_adap);
 err:
+	release_region(BRA_SMB_BASE_ADDR, 7);
 	dev_err(dev, "%s device probe failed\n", dev_name(dev));
 
 	return ret;
--- linux-ein-5.4.0.orig/drivers/media/platform/sh_vou.c
+++ linux-ein-5.4.0/drivers/media/platform/sh_vou.c
@@ -1133,7 +1133,11 @@
 	if (v4l2_fh_is_singular_file(file) &&
 	    vou_dev->status == SH_VOU_INITIALISING) {
 		/* First open */
-		pm_runtime_get_sync(vou_dev->v4l2_dev.dev);
+		err = pm_runtime_resume_and_get(vou_dev->v4l2_dev.dev);
+		if (err < 0) {
+			v4l2_fh_release(file);
+			goto done_open;
+		}
 		err = sh_vou_hw_init(vou_dev);
 		if (err < 0) {
 			pm_runtime_put(vou_dev->v4l2_dev.dev);
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/bdisp/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/sti/bdisp/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_BDISP) := bdisp.o
+obj-$(CONFIG_VIDEO_STI_BDISP) += bdisp.o
 
 bdisp-objs := bdisp-v4l2.o bdisp-hw.o bdisp-debug.o
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/bdisp/bdisp-debug.c
+++ linux-ein-5.4.0/drivers/media/platform/sti/bdisp/bdisp-debug.c
@@ -480,7 +480,7 @@
 	int ret;
 	unsigned int i;
 
-	ret = pm_runtime_get_sync(bdisp->dev);
+	ret = pm_runtime_resume_and_get(bdisp->dev);
 	if (ret < 0) {
 		seq_puts(s, "Cannot wake up IP\n");
 		return 0;
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/bdisp/bdisp-hw.c
+++ linux-ein-5.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,
@@ -382,7 +382,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-ein-5.4.0.orig/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ linux-ein-5.4.0/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -499,7 +499,7 @@
 {
 	struct bdisp_ctx *ctx = q->drv_priv;
 	struct vb2_v4l2_buffer *buf;
-	int ret = pm_runtime_get_sync(ctx->bdisp_dev->dev);
+	int ret = pm_runtime_resume_and_get(ctx->bdisp_dev->dev);
 
 	if (ret < 0) {
 		dev_err(ctx->bdisp_dev->dev, "failed to set runtime PM\n");
@@ -651,8 +651,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);
 
@@ -1309,6 +1308,8 @@
 	init_waitqueue_head(&bdisp->irq_queue);
 	INIT_DELAYED_WORK(&bdisp->timeout_work, bdisp_irq_timeout);
 	bdisp->work_queue = create_workqueue(BDISP_NAME);
+	if (!bdisp->work_queue)
+		return -ENOMEM;
 
 	spin_lock_init(&bdisp->slock);
 	mutex_init(&bdisp->lock);
@@ -1365,10 +1366,10 @@
 
 	/* Power management */
 	pm_runtime_enable(dev);
-	ret = pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0) {
 		dev_err(dev, "failed to set PM\n");
-		goto err_dbg;
+		goto err_remove;
 	}
 
 	/* Filters */
@@ -1396,7 +1397,7 @@
 	bdisp_hw_free_filters(bdisp->dev);
 err_pm:
 	pm_runtime_put(dev);
-err_dbg:
+err_remove:
 	bdisp_debugfs_remove(bdisp);
 err_v4l2:
 	v4l2_device_unregister(&bdisp->v4l2_dev);
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ linux-ein-5.4.0/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -939,6 +939,7 @@
 		if (ret) {
 			dev_err(fei->dev,
 				"configure_memdma_and_inputblock failed\n");
+			of_node_put(child);
 			goto err_unmap;
 		}
 		index++;
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/delta/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/sti/delta/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) := st-delta.o
+obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) += st-delta.o
 st-delta-y := delta-v4l2.o delta-mem.o delta-ipc.o delta-debug.o
 
 # MJPEG support
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/delta/delta-v4l2.c
+++ linux-ein-5.4.0/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -954,8 +954,10 @@
 	/* enable the hardware */
 	if (!dec->pm) {
 		ret = delta_get_sync(ctx);
-		if (ret)
+		if (ret) {
+			delta_put_autosuspend(ctx);
 			goto err;
+		}
 	}
 
 	/* decode this access unit */
@@ -1860,7 +1862,7 @@
 	if (ret) {
 		dev_err(delta->dev, "%s failed to initialize firmware ipc channel\n",
 			DELTA_PREFIX);
-		goto err;
+		goto err_pm_disable;
 	}
 
 	/* register all available decoders */
@@ -1874,7 +1876,7 @@
 	if (ret) {
 		dev_err(delta->dev, "%s failed to register V4L2 device\n",
 			DELTA_PREFIX);
-		goto err;
+		goto err_pm_disable;
 	}
 
 	delta->work_queue = create_workqueue(DELTA_NAME);
@@ -1899,6 +1901,8 @@
 	destroy_workqueue(delta->work_queue);
 err_v4l2:
 	v4l2_device_unregister(&delta->v4l2_dev);
+err_pm_disable:
+	pm_runtime_disable(dev);
 err:
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/hva/Makefile
+++ linux-ein-5.4.0/drivers/media/platform/sti/hva/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_HVA) := st-hva.o
+obj-$(CONFIG_VIDEO_STI_HVA) += st-hva.o
 st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
 st-hva-$(CONFIG_VIDEO_STI_HVA_DEBUGFS) += hva-debugfs.o
--- linux-ein-5.4.0.orig/drivers/media/platform/sti/hva/hva-hw.c
+++ linux-ein-5.4.0/drivers/media/platform/sti/hva/hva-hw.c
@@ -130,8 +130,7 @@
 	ctx_id = (hva->sts_reg & 0xFF00) >> 8;
 	if (ctx_id >= HVA_MAX_INSTANCES) {
 		dev_err(dev, "%s     %s: bad context identifier: %d\n",
-			ctx->name, __func__, ctx_id);
-		ctx->hw_err = true;
+			HVA_PREFIX, __func__, ctx_id);
 		goto out;
 	}
 
@@ -272,6 +271,7 @@
 
 	if (pm_runtime_get_sync(dev) < 0) {
 		dev_err(dev, "%s     failed to get pm_runtime\n", HVA_PREFIX);
+		pm_runtime_put_noidle(dev);
 		mutex_unlock(&hva->protect_mutex);
 		return -EFAULT;
 	}
@@ -388,7 +388,7 @@
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
 		dev_err(dev, "%s     failed to set PM\n", HVA_PREFIX);
-		goto err_clk;
+		goto err_pm;
 	}
 
 	/* check IP hardware version */
@@ -553,6 +553,7 @@
 
 	if (pm_runtime_get_sync(dev) < 0) {
 		seq_puts(s, "Cannot wake up IP\n");
+		pm_runtime_put_noidle(dev);
 		mutex_unlock(&hva->protect_mutex);
 		return;
 	}
--- linux-ein-5.4.0.orig/drivers/media/platform/stm32/stm32-dcmi.c
+++ linux-ein-5.4.0/drivers/media/platform/stm32/stm32-dcmi.c
@@ -135,6 +135,7 @@
 	int				sequence;
 	struct list_head		buffers;
 	struct dcmi_buf			*active;
+	int			irq;
 
 	struct v4l2_device		v4l2_dev;
 	struct video_device		*vdev;
@@ -733,7 +734,7 @@
 	if (ret < 0) {
 		dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
 			__func__, ret);
-		goto err_release_buffers;
+		goto err_pm_put;
 	}
 
 	ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline);
@@ -837,8 +838,6 @@
 
 err_pm_put:
 	pm_runtime_put(dcmi->dev);
-
-err_release_buffers:
 	spin_lock_irq(&dcmi->irqlock);
 	/*
 	 * Return all buffers to vb2 in QUEUED state.
@@ -1722,6 +1721,14 @@
 		return ret;
 	}
 
+	ret = devm_request_threaded_irq(dcmi->dev, dcmi->irq, dcmi_irq_callback,
+					dcmi_irq_thread, IRQF_ONESHOT,
+					dev_name(dcmi->dev), dcmi);
+	if (ret) {
+		dev_err(dcmi->dev, "Unable to request irq %d\n", dcmi->irq);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -1883,6 +1890,8 @@
 	if (irq <= 0)
 		return irq ? irq : -ENXIO;
 
+	dcmi->irq = irq;
+
 	dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!dcmi->res) {
 		dev_err(&pdev->dev, "Could not get resource\n");
@@ -1895,14 +1904,6 @@
 		return PTR_ERR(dcmi->regs);
 	}
 
-	ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback,
-					dcmi_irq_thread, IRQF_ONESHOT,
-					dev_name(&pdev->dev), dcmi);
-	if (ret) {
-		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
-		return ret;
-	}
-
 	mclk = devm_clk_get(&pdev->dev, "mclk");
 	if (IS_ERR(mclk)) {
 		if (PTR_ERR(mclk) != -EPROBE_DEFER)
--- linux-ein-5.4.0.orig/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ linux-ein-5.4.0/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -155,6 +156,27 @@
 	subdev = &csi->subdev;
 	vdev = &csi->vdev;
 
+	/*
+	 * On Allwinner SoCs, some high memory bandwidth devices do DMA
+	 * directly over the memory bus (called MBUS), instead of the
+	 * system bus. The memory bus has a different addressing scheme
+	 * without the DRAM starting offset.
+	 *
+	 * In some cases this can be described by an interconnect in
+	 * the device tree. In other cases where the hardware is not
+	 * fully understood and the interconnect is left out of the
+	 * device tree, fall back to a default offset.
+	 */
+	if (of_find_property(csi->dev->of_node, "interconnects", NULL)) {
+		ret = of_dma_configure(csi->dev, csi->dev->of_node, true);
+		if (ret)
+			return ret;
+	} else {
+#ifdef PHYS_PFN_OFFSET
+		csi->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
+#endif
+	}
+
 	csi->mdev.dev = csi->dev;
 	strscpy(csi->mdev.model, "Allwinner Video Capture Device",
 		sizeof(csi->mdev.model));
--- linux-ein-5.4.0.orig/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
+++ linux-ein-5.4.0/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
@@ -22,8 +22,8 @@
 #define CSI_CFG_INPUT_FMT(fmt)			((fmt) << 20)
 #define CSI_CFG_OUTPUT_FMT(fmt)			((fmt) << 16)
 #define CSI_CFG_YUV_DATA_SEQ(seq)		((seq) << 8)
-#define CSI_CFG_VSYNC_POL(pol)			((pol) << 2)
-#define CSI_CFG_HSYNC_POL(pol)			((pol) << 1)
+#define CSI_CFG_VREF_POL(pol)			((pol) << 2)
+#define CSI_CFG_HREF_POL(pol)			((pol) << 1)
 #define CSI_CFG_PCLK_POL(pol)			((pol) << 0)
 
 #define CSI_CPT_CTRL_REG		0x08
--- linux-ein-5.4.0.orig/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ linux-ein-5.4.0/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -228,7 +228,7 @@
 	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
 	struct v4l2_fwnode_bus_parallel *bus = &csi->bus;
 	const struct sun4i_csi_format *csi_fmt;
-	unsigned long hsync_pol, pclk_pol, vsync_pol;
+	unsigned long href_pol, pclk_pol, vref_pol;
 	unsigned long flags;
 	unsigned int i;
 	int ret;
@@ -278,13 +278,21 @@
 	writel(CSI_WIN_CTRL_H_ACTIVE(csi->fmt.height),
 	       csi->regs + CSI_WIN_CTRL_H_REG);
 
-	hsync_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH);
-	pclk_pol = !!(bus->flags & V4L2_MBUS_DATA_ACTIVE_HIGH);
-	vsync_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH);
+	/*
+	 * This hardware uses [HV]REF instead of [HV]SYNC. Based on the
+	 * provided timing diagrams in the manual, positive polarity
+	 * equals active high [HV]REF.
+	 *
+	 * When the back porch is 0, [HV]REF is more or less equivalent
+	 * to [HV]SYNC inverted.
+	 */
+	href_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+	vref_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+	pclk_pol = !!(bus->flags & V4L2_MBUS_PCLK_SAMPLE_RISING);
 	writel(CSI_CFG_INPUT_FMT(csi_fmt->input) |
 	       CSI_CFG_OUTPUT_FMT(csi_fmt->output) |
-	       CSI_CFG_VSYNC_POL(vsync_pol) |
-	       CSI_CFG_HSYNC_POL(hsync_pol) |
+	       CSI_CFG_VREF_POL(vref_pol) |
+	       CSI_CFG_HREF_POL(href_pol) |
 	       CSI_CFG_PCLK_POL(pclk_pol),
 	       csi->regs + CSI_CFG_REG);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ linux-ein-5.4.0/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -151,8 +151,10 @@
 	}
 
 	subdev = sun6i_video_remote_subdev(video, NULL);
-	if (!subdev)
+	if (!subdev) {
+		ret = -EINVAL;
 		goto stop_media_pipeline;
+	}
 
 	config.pixelformat = video->fmt.fmt.pix.pixelformat;
 	config.code = video->mbus_code;
--- linux-ein-5.4.0.orig/drivers/media/platform/tegra-cec/tegra_cec.c
+++ linux-ein-5.4.0/drivers/media/platform/tegra-cec/tegra_cec.c
@@ -366,7 +366,11 @@
 		return -ENOENT;
 	}
 
-	clk_prepare_enable(cec->clk);
+	ret = clk_prepare_enable(cec->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to prepare clock for CEC\n");
+		return ret;
+	}
 
 	/* set context info. */
 	cec->dev = &pdev->dev;
@@ -446,9 +450,7 @@
 
 	dev_notice(&pdev->dev, "Resuming\n");
 
-	clk_prepare_enable(cec->clk);
-
-	return 0;
+	return clk_prepare_enable(cec->clk);
 }
 #endif
 
--- linux-ein-5.4.0.orig/drivers/media/platform/ti-vpe/cal.c
+++ linux-ein-5.4.0/drivers/media/platform/ti-vpe/cal.c
@@ -266,8 +266,6 @@
 	struct v4l2_subdev	*sensor;
 	struct v4l2_fwnode_endpoint	endpoint;
 
-	struct v4l2_async_subdev asd;
-
 	struct v4l2_fh		fh;
 	struct cal_dev		*dev;
 	struct cc_data		*cc;
@@ -537,16 +535,16 @@
 
 static void disable_irqs(struct cal_ctx *ctx)
 {
+	u32 val;
+
 	/* Disable IRQ_WDMA_END 0/1 */
-	reg_write_field(ctx->dev,
-			CAL_HL_IRQENABLE_CLR(2),
-			CAL_HL_IRQ_CLEAR,
-			CAL_HL_IRQ_MASK(ctx->csi2_port));
+	val = 0;
+	set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port));
+	reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(2), val);
 	/* Disable IRQ_WDMA_START 0/1 */
-	reg_write_field(ctx->dev,
-			CAL_HL_IRQENABLE_CLR(3),
-			CAL_HL_IRQ_CLEAR,
-			CAL_HL_IRQ_MASK(ctx->csi2_port));
+	val = 0;
+	set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port));
+	reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(3), val);
 	/* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */
 	reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0);
 }
@@ -680,12 +678,13 @@
 }
 
 static void cal_wr_dma_config(struct cal_ctx *ctx,
-			      unsigned int width)
+			      unsigned int width, unsigned int height)
 {
 	u32 val;
 
 	val = reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port));
 	set_field(&val, ctx->csi2_port, CAL_WR_DMA_CTRL_CPORT_MASK);
+	set_field(&val, height, CAL_WR_DMA_CTRL_YSIZE_MASK);
 	set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT,
 		  CAL_WR_DMA_CTRL_DTAG_MASK);
 	set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
@@ -1308,7 +1307,8 @@
 	csi2_lane_config(ctx);
 	csi2_ctx_config(ctx);
 	pix_proc_config(ctx);
-	cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline);
+	cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline,
+			  ctx->v_fmt.fmt.pix.height);
 	cal_wr_dma_addr(ctx, addr);
 	csi2_ppi_enable(ctx);
 
@@ -1648,7 +1648,6 @@
 
 	parent = pdev->dev.of_node;
 
-	asd = &ctx->asd;
 	endpoint = &ctx->endpoint;
 
 	ep_node = NULL;
@@ -1695,8 +1694,6 @@
 		ctx_dbg(3, ctx, "can't get remote parent\n");
 		goto cleanup_exit;
 	}
-	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-	asd->match.fwnode = of_fwnode_handle(sensor_node);
 
 	v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint);
 
@@ -1726,9 +1723,17 @@
 
 	v4l2_async_notifier_init(&ctx->notifier);
 
+	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+	if (!asd)
+		goto cleanup_exit;
+
+	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+	asd->match.fwnode = of_fwnode_handle(sensor_node);
+
 	ret = v4l2_async_notifier_add_subdev(&ctx->notifier, asd);
 	if (ret) {
 		ctx_err(ctx, "Error adding asd\n");
+		kfree(asd);
 		goto cleanup_exit;
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/platform/ti-vpe/vpdma.h
+++ linux-ein-5.4.0/drivers/media/platform/ti-vpe/vpdma.h
@@ -57,6 +57,7 @@
 						 * line stride of source and dest
 						 * buffers should be 16 byte aligned
 						 */
+#define VPDMA_MAX_STRIDE		65520	/* Max line stride 16 byte aligned */
 #define VPDMA_DTD_DESC_SIZE		32	/* 8 words */
 #define VPDMA_CFD_CTD_DESC_SIZE		16	/* 4 words */
 
--- linux-ein-5.4.0.orig/drivers/media/platform/ti-vpe/vpe.c
+++ linux-ein-5.4.0/drivers/media/platform/ti-vpe/vpe.c
@@ -338,20 +338,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.
@@ -1013,11 +1018,14 @@
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 	u32 offset = 0;
+	u32 stride;
 
 	if (port == VPE_PORT_MV_OUT) {
 		vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
 		dma_addr = ctx->mv_buf_dma[mv_buf_selector];
 		q_data = &ctx->q_data[Q_DATA_SRC];
+		stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3,
+			       VPDMA_STRIDE_ALIGN);
 	} else {
 		/* to incorporate interleaved formats */
 		int plane = fmt->coplanar ? p_data->vb_part : 0;
@@ -1044,6 +1052,7 @@
 		}
 		/* Apply the offset */
 		dma_addr += offset;
+		stride = q_data->bytesperline[VPE_LUMA];
 	}
 
 	if (q_data->flags & Q_DATA_FRAME_1D)
@@ -1055,7 +1064,7 @@
 			   MAX_W, MAX_H);
 
 	vpdma_add_out_dtd(&ctx->desc_list, q_data->width,
-			  q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
+			  stride, &q_data->c_rect,
 			  vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1,
 			  MAX_OUT_HEIGHT_REG1, p_data->channel, flags);
 }
@@ -1074,10 +1083,13 @@
 	dma_addr_t dma_addr;
 	u32 flags = 0;
 	u32 offset = 0;
+	u32 stride;
 
 	if (port == VPE_PORT_MV_IN) {
 		vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
 		dma_addr = ctx->mv_buf_dma[mv_buf_selector];
+		stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3,
+			       VPDMA_STRIDE_ALIGN);
 	} else {
 		/* to incorporate interleaved formats */
 		int plane = fmt->coplanar ? p_data->vb_part : 0;
@@ -1104,6 +1116,7 @@
 		}
 		/* Apply the offset */
 		dma_addr += offset;
+		stride = q_data->bytesperline[VPE_LUMA];
 
 		if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) {
 			/*
@@ -1139,10 +1152,10 @@
 	if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
 		frame_height /= 2;
 
-	vpdma_add_in_dtd(&ctx->desc_list, q_data->width,
-			 q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
-		vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
-		frame_height, 0, 0);
+	vpdma_add_in_dtd(&ctx->desc_list, q_data->width, stride,
+			 &q_data->c_rect, vpdma_fmt, dma_addr,
+			 p_data->channel, field, flags, frame_width,
+			 frame_height, 0, 0);
 }
 
 /*
@@ -1391,9 +1404,6 @@
 	 /* the previous dst mv buffer becomes the next src mv buffer */
 	ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector;
 
-	if (ctx->aborting)
-		goto finished;
-
 	s_vb = ctx->src_vbs[0];
 	d_vb = ctx->dst_vb;
 
@@ -1404,6 +1414,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_IS_INTERLACED) {
@@ -1457,6 +1468,9 @@
 	ctx->src_vbs[0] = NULL;
 	ctx->dst_vb = NULL;
 
+	if (ctx->aborting)
+		goto finished;
+
 	ctx->bufs_completed++;
 	if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) {
 		device_run(ctx);
@@ -1566,9 +1580,9 @@
 	unsigned int stride = 0;
 
 	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
@@ -1615,7 +1629,7 @@
 			      &pix->height, MIN_H, MAX_H, H_ALIGN,
 			      S_ALIGN);
 
-	if (!pix->num_planes)
+	if (!pix->num_planes || pix->num_planes > 2)
 		pix->num_planes = fmt->coplanar ? 2 : 1;
 	else if (pix->num_planes > 1 && !fmt->coplanar)
 		pix->num_planes = 1;
@@ -1654,6 +1668,10 @@
 		if (stride > plane_fmt->bytesperline)
 			plane_fmt->bytesperline = stride;
 
+		plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline,
+						  stride,
+						  VPDMA_MAX_STRIDE);
+
 		plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline,
 						VPDMA_STRIDE_ALIGN);
 
@@ -2274,7 +2292,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->nplanes = 1;
@@ -2352,6 +2370,12 @@
 
 	mutex_lock(&dev->dev_mutex);
 	free_mv_buffers(ctx);
+
+	vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);
+	vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);
+	vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);
+	vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);
+
 	vpdma_free_desc_list(&ctx->desc_list);
 	vpdma_free_desc_buf(&ctx->mmr_adb);
 
@@ -2411,6 +2435,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-ein-5.4.0.orig/drivers/media/platform/vicodec/codec-v4l2-fwht.c
+++ linux-ein-5.4.0/drivers/media/platform/vicodec/codec-v4l2-fwht.c
@@ -27,17 +27,17 @@
 	{ V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
-	{ V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_BGRA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+	{ V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
 	{ V4L2_PIX_FMT_RGBA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-	{ V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
+	{ V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV},
 	{ V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
 };
 
@@ -175,22 +175,14 @@
 	case V4L2_PIX_FMT_RGB32:
 	case V4L2_PIX_FMT_XRGB32:
 	case V4L2_PIX_FMT_HSV32:
-		rf->cr = rf->luma + 1;
-		rf->cb = rf->cr + 2;
-		rf->luma += 2;
-		break;
-	case V4L2_PIX_FMT_BGR32:
-	case V4L2_PIX_FMT_XBGR32:
-		rf->cb = rf->luma;
-		rf->cr = rf->cb + 2;
-		rf->luma++;
-		break;
 	case V4L2_PIX_FMT_ARGB32:
 		rf->alpha = rf->luma;
 		rf->cr = rf->luma + 1;
 		rf->cb = rf->cr + 2;
 		rf->luma += 2;
 		break;
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_XBGR32:
 	case V4L2_PIX_FMT_ABGR32:
 		rf->cb = rf->luma;
 		rf->cr = rf->cb + 2;
@@ -198,10 +190,6 @@
 		rf->alpha = rf->cr + 1;
 		break;
 	case V4L2_PIX_FMT_BGRX32:
-		rf->cb = rf->luma + 1;
-		rf->cr = rf->cb + 2;
-		rf->luma += 2;
-		break;
 	case V4L2_PIX_FMT_BGRA32:
 		rf->alpha = rf->luma;
 		rf->cb = rf->luma + 1;
@@ -209,10 +197,6 @@
 		rf->luma += 2;
 		break;
 	case V4L2_PIX_FMT_RGBX32:
-		rf->cr = rf->luma;
-		rf->cb = rf->cr + 2;
-		rf->luma++;
-		break;
 	case V4L2_PIX_FMT_RGBA32:
 		rf->alpha = rf->luma + 3;
 		rf->cr = rf->luma;
--- linux-ein-5.4.0.orig/drivers/media/platform/vicodec/vicodec-core.c
+++ linux-ein-5.4.0/drivers/media/platform/vicodec/vicodec-core.c
@@ -2052,6 +2052,7 @@
 	}
 	ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl,
 					       vicodec_ctrl_stateless_state.id);
+	v4l2_ctrl_request_hdl_put(hdl);
 	if (!ctrl) {
 		v4l2_info(&ctx->dev->v4l2_dev,
 			  "Missing required codec control\n");
@@ -2139,6 +2140,9 @@
 	v4l2_m2m_release(dev->stateful_enc.m2m_dev);
 	v4l2_m2m_release(dev->stateful_dec.m2m_dev);
 	v4l2_m2m_release(dev->stateless_dec.m2m_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+	media_device_cleanup(&dev->mdev);
+#endif
 	kfree(dev);
 }
 
@@ -2169,16 +2173,19 @@
 
 	platform_set_drvdata(pdev, dev);
 
-	if (register_instance(dev, &dev->stateful_enc,
-			      "stateful-encoder", true))
+	ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder",
+				true);
+	if (ret)
 		goto unreg_dev;
 
-	if (register_instance(dev, &dev->stateful_dec,
-			      "stateful-decoder", false))
+	ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder",
+				false);
+	if (ret)
 		goto unreg_sf_enc;
 
-	if (register_instance(dev, &dev->stateless_dec,
-			      "stateless-decoder", false))
+	ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder",
+				false);
+	if (ret)
 		goto unreg_sf_dec;
 
 #ifdef CONFIG_MEDIA_CONTROLLER
@@ -2250,7 +2257,6 @@
 	v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
 	v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
 	v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
-	media_device_cleanup(&dev->mdev);
 #endif
 
 	video_unregister_device(&dev->stateful_enc.vfd);
--- linux-ein-5.4.0.orig/drivers/media/platform/video-mux.c
+++ linux-ein-5.4.0/drivers/media/platform/video-mux.c
@@ -17,10 +17,12 @@
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
 #include <media/v4l2-subdev.h>
 
 struct video_mux {
 	struct v4l2_subdev subdev;
+	struct v4l2_async_notifier notifier;
 	struct media_pad *pads;
 	struct v4l2_mbus_framefmt *format_mbus;
 	struct mux_control *mux;
@@ -35,6 +37,12 @@
 	.field = V4L2_FIELD_NONE,
 };
 
+static inline struct video_mux *
+notifier_to_video_mux(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct video_mux, notifier);
+}
+
 static inline struct video_mux *v4l2_subdev_to_video_mux(struct v4l2_subdev *sd)
 {
 	return container_of(sd, struct video_mux, subdev);
@@ -96,6 +104,7 @@
 static const struct media_entity_operations video_mux_ops = {
 	.link_setup = video_mux_link_setup,
 	.link_validate = v4l2_subdev_link_validate,
+	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
 };
 
 static int video_mux_s_stream(struct v4l2_subdev *sd, int enable)
@@ -330,36 +339,64 @@
 	.video = &video_mux_subdev_video_ops,
 };
 
-static int video_mux_parse_endpoint(struct device *dev,
-				    struct v4l2_fwnode_endpoint *vep,
-				    struct v4l2_async_subdev *asd)
+static int video_mux_notify_bound(struct v4l2_async_notifier *notifier,
+				  struct v4l2_subdev *sd,
+				  struct v4l2_async_subdev *asd)
 {
-	/*
-	 * it's not an error if remote is missing on a video-mux
-	 * input port, return -ENOTCONN to skip this endpoint with
-	 * no error.
-	 */
-	return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN;
+	struct video_mux *vmux = notifier_to_video_mux(notifier);
+
+	return v4l2_create_fwnode_links(sd, &vmux->subdev);
 }
 
+static const struct v4l2_async_notifier_operations video_mux_notify_ops = {
+	.bound = video_mux_notify_bound,
+};
+
 static int video_mux_async_register(struct video_mux *vmux,
 				    unsigned int num_input_pads)
 {
-	unsigned int i, *ports;
+	unsigned int i;
 	int ret;
 
-	ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL);
-	if (!ports)
-		return -ENOMEM;
-	for (i = 0; i < num_input_pads; i++)
-		ports[i] = i;
+	v4l2_async_notifier_init(&vmux->notifier);
 
-	ret = v4l2_async_register_fwnode_subdev(
-		&vmux->subdev, sizeof(struct v4l2_async_subdev),
-		ports, num_input_pads, video_mux_parse_endpoint);
+	for (i = 0; i < num_input_pads; i++) {
+		struct v4l2_async_subdev *asd;
+		struct fwnode_handle *ep;
+
+		ep = fwnode_graph_get_endpoint_by_id(
+			dev_fwnode(vmux->subdev.dev), i, 0,
+			FWNODE_GRAPH_ENDPOINT_NEXT);
+		if (!ep)
+			continue;
+
+		asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+		if (!asd) {
+			fwnode_handle_put(ep);
+			return -ENOMEM;
+		}
 
-	kfree(ports);
-	return ret;
+		ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+			&vmux->notifier, ep, asd);
+
+		fwnode_handle_put(ep);
+
+		if (ret) {
+			kfree(asd);
+			/* OK if asd already exists */
+			if (ret != -EEXIST)
+				return ret;
+		}
+	}
+
+	vmux->notifier.ops = &video_mux_notify_ops;
+
+	ret = v4l2_async_subdev_notifier_register(&vmux->subdev,
+						  &vmux->notifier);
+	if (ret)
+		return ret;
+
+	return v4l2_async_register_subdev(&vmux->subdev);
 }
 
 static int video_mux_probe(struct platform_device *pdev)
@@ -434,7 +471,13 @@
 
 	vmux->subdev.entity.ops = &video_mux_ops;
 
-	return video_mux_async_register(vmux, num_pads - 1);
+	ret = video_mux_async_register(vmux, num_pads - 1);
+	if (ret) {
+		v4l2_async_notifier_unregister(&vmux->notifier);
+		v4l2_async_notifier_cleanup(&vmux->notifier);
+	}
+
+	return ret;
 }
 
 static int video_mux_remove(struct platform_device *pdev)
@@ -442,6 +485,8 @@
 	struct video_mux *vmux = platform_get_drvdata(pdev);
 	struct v4l2_subdev *sd = &vmux->subdev;
 
+	v4l2_async_notifier_unregister(&vmux->notifier);
+	v4l2_async_notifier_cleanup(&vmux->notifier);
 	v4l2_async_unregister_subdev(sd);
 	media_entity_cleanup(&sd->entity);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vim2m.c
+++ linux-ein-5.4.0/drivers/media/platform/vim2m.c
@@ -1073,6 +1073,9 @@
 	if (!q_data)
 		return -EINVAL;
 
+	if (V4L2_TYPE_IS_OUTPUT(q->type))
+		ctx->aborting = 0;
+
 	q_data->sequence = 0;
 	return 0;
 }
@@ -1272,6 +1275,9 @@
 
 	v4l2_device_unregister(&dev->v4l2_dev);
 	v4l2_m2m_release(dev->m2m_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+	media_device_cleanup(&dev->mdev);
+#endif
 	kfree(dev);
 }
 
@@ -1327,12 +1333,6 @@
 	vfd->lock = &dev->dev_mutex;
 	vfd->v4l2_dev = &dev->v4l2_dev;
 
-	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
-	if (ret) {
-		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
-		goto error_v4l2;
-	}
-
 	video_set_drvdata(vfd, dev);
 	v4l2_info(&dev->v4l2_dev,
 		  "Device registered as /dev/video%d\n", vfd->num);
@@ -1343,6 +1343,7 @@
 	if (IS_ERR(dev->m2m_dev)) {
 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
 		ret = PTR_ERR(dev->m2m_dev);
+		dev->m2m_dev = NULL;
 		goto error_dev;
 	}
 
@@ -1354,12 +1355,20 @@
 	media_device_init(&dev->mdev);
 	dev->mdev.ops = &m2m_media_ops;
 	dev->v4l2_dev.mdev = &dev->mdev;
+#endif
 
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto error_m2m;
+	}
+
+#ifdef CONFIG_MEDIA_CONTROLLER
 	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
 						 MEDIA_ENT_F_PROC_VIDEO_SCALER);
 	if (ret) {
 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
-		goto error_dev;
+		goto error_v4l2;
 	}
 
 	ret = media_device_register(&dev->mdev);
@@ -1374,11 +1383,13 @@
 error_m2m_mc:
 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
 #endif
-error_dev:
+error_v4l2:
 	video_unregister_device(&dev->vfd);
 	/* vim2m_device_release called by video_unregister_device to release various objects */
 	return ret;
-error_v4l2:
+error_m2m:
+	v4l2_m2m_release(dev->m2m_dev);
+error_dev:
 	v4l2_device_unregister(&dev->v4l2_dev);
 error_free:
 	kfree(dev);
@@ -1395,7 +1406,6 @@
 #ifdef CONFIG_MEDIA_CONTROLLER
 	media_device_unregister(&dev->mdev);
 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
-	media_device_cleanup(&dev->mdev);
 #endif
 	video_unregister_device(&dev->vfd);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vimc/vimc-common.c
+++ linux-ein-5.4.0/drivers/media/platform/vimc/vimc-common.c
@@ -375,7 +375,7 @@
 {
 	int ret;
 
-	/* Allocate the pads */
+	/* Allocate the pads. Should be released from the sd_int_op release */
 	ved->pads = vimc_pads_init(num_pads, pads_flag);
 	if (IS_ERR(ved->pads))
 		return PTR_ERR(ved->pads);
@@ -424,7 +424,6 @@
 void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
 {
 	media_entity_cleanup(ved->ent);
-	vimc_pads_cleanup(ved->pads);
 	v4l2_device_unregister_subdev(sd);
 }
 EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister);
--- linux-ein-5.4.0.orig/drivers/media/platform/vimc/vimc-debayer.c
+++ linux-ein-5.4.0/drivers/media/platform/vimc/vimc-debayer.c
@@ -484,6 +484,7 @@
 	struct vimc_deb_device *vdeb =
 				container_of(sd, struct vimc_deb_device, sd);
 
+	vimc_pads_cleanup(vdeb->ved.pads);
 	kfree(vdeb);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vimc/vimc-scaler.c
+++ linux-ein-5.4.0/drivers/media/platform/vimc/vimc-scaler.c
@@ -343,6 +343,7 @@
 	struct vimc_sca_device *vsca =
 				container_of(sd, struct vimc_sca_device, sd);
 
+	vimc_pads_cleanup(vsca->ved.pads);
 	kfree(vsca);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vimc/vimc-sensor.c
+++ linux-ein-5.4.0/drivers/media/platform/vimc/vimc-sensor.c
@@ -25,7 +25,6 @@
 	struct v4l2_subdev sd;
 	struct device *dev;
 	struct tpg_data tpg;
-	struct task_struct *kthread_sen;
 	u8 *frame;
 	/* The active format */
 	struct v4l2_mbus_framefmt mbus_format;
@@ -208,10 +207,6 @@
 		const struct vimc_pix_map *vpix;
 		unsigned int frame_size;
 
-		if (vsen->kthread_sen)
-			/* tpg is already executing */
-			return 0;
-
 		/* Calculate the frame size */
 		vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
 		frame_size = vsen->mbus_format.width * vpix->bpp *
@@ -297,6 +292,7 @@
 
 	v4l2_ctrl_handler_free(&vsen->hdl);
 	tpg_free(&vsen->tpg);
+	vimc_pads_cleanup(vsen->ved.pads);
 	kfree(vsen);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-core.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-core.c
@@ -174,13 +174,13 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7b,
 
-	0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f,
+	0x02, 0x03, 0x3f, 0xf1, 0x51, 0x61, 0x60, 0x5f,
 	0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21,
 	0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09,
 	0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03,
 	0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00,
 	0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4,
-	0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3,
+	0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3,
 	0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d,
 	0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30,
 	0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00,
@@ -189,7 +189,7 @@
 	0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51,
 	0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0,
 	0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82,
 };
 
 static int vidioc_querycap(struct file *file, void  *priv,
@@ -297,6 +297,28 @@
 	return vivid_vid_out_g_fbuf(file, fh, a);
 }
 
+/*
+ * Only support the framebuffer of one of the vivid instances.
+ * Anything else is rejected.
+ */
+bool vivid_validate_fb(const struct v4l2_framebuffer *a)
+{
+	struct vivid_dev *dev;
+	int i;
+
+	for (i = 0; i < n_devs; i++) {
+		dev = vivid_devs[i];
+		if (!dev || !dev->video_pbase)
+			continue;
+		if ((unsigned long)a->base == dev->video_pbase &&
+		    a->fmt.width <= dev->display_width &&
+		    a->fmt.height <= dev->display_height &&
+		    a->fmt.bytesperline <= dev->display_byte_stride)
+			return true;
+	}
+	return false;
+}
+
 static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -616,6 +638,9 @@
 
 	vivid_free_controls(dev);
 	v4l2_device_unregister(&dev->v4l2_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+	media_device_cleanup(&dev->mdev);
+#endif
 	vfree(dev->scaled_line);
 	vfree(dev->blended_line);
 	vfree(dev->edid);
@@ -1580,7 +1605,6 @@
 
 #ifdef CONFIG_MEDIA_CONTROLLER
 		media_device_unregister(&dev->mdev);
-		media_device_cleanup(&dev->mdev);
 #endif
 
 		if (dev->has_vid_cap) {
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-core.h
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-core.h
@@ -564,4 +564,6 @@
 	return dev->output_type[dev->output] == HDMI;
 }
 
+bool vivid_validate_fb(const struct v4l2_framebuffer *a);
+
 #endif
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -796,7 +796,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;
@@ -956,8 +960,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-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-kthread-out.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -143,7 +143,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;
@@ -301,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-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-rds-gen.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-rds-gen.c
@@ -145,7 +145,7 @@
 	rds->ta = alt;
 	rds->ms = true;
 	snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
-		 freq / 16, ((freq & 0xf) * 10) / 16);
+		 (freq / 16) % 1000000, (((freq & 0xf) * 10) / 16) % 10);
 	if (alt)
 		strscpy(rds->radiotext,
 			" The Radio Data System can switch between different Radio Texts ",
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -141,7 +141,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;
@@ -303,10 +307,8 @@
 	}
 
 	/* shutdown control thread */
-	mutex_unlock(&dev->mutex);
 	kthread_stop(dev->kthread_sdr_cap);
 	dev->kthread_sdr_cap = NULL;
-	mutex_lock(&dev->mutex);
 }
 
 static void sdr_cap_buf_request_complete(struct vb2_buffer *vb)
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-vid-cap.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -223,9 +223,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++)
@@ -455,6 +452,12 @@
 	tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
 	dev->crop_cap = dev->src_rect;
 	dev->crop_bounds_cap = dev->src_rect;
+	if (dev->bitmap_cap &&
+	    (dev->compose_cap.width != dev->crop_cap.width ||
+	     dev->compose_cap.height != dev->crop_cap.height)) {
+		vfree(dev->bitmap_cap);
+		dev->bitmap_cap = NULL;
+	}
 	dev->compose_cap = dev->crop_cap;
 	if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
 		dev->compose_cap.height /= 2;
@@ -886,6 +889,8 @@
 	struct vivid_dev *dev = video_drvdata(file);
 	struct v4l2_rect *crop = &dev->crop_cap;
 	struct v4l2_rect *compose = &dev->compose_cap;
+	unsigned orig_compose_w = compose->width;
+	unsigned orig_compose_h = compose->height;
 	unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
 	int ret;
 
@@ -930,6 +935,7 @@
 			if (dev->has_compose_cap) {
 				v4l2_rect_set_min_size(compose, &min_rect);
 				v4l2_rect_set_max_size(compose, &max_rect);
+				v4l2_rect_map_inside(compose, &fmt);
 			}
 			dev->fmt_cap_rect = fmt;
 			tpg_s_buf_height(&dev->tpg, fmt.height);
@@ -1002,17 +1008,17 @@
 			s->r.height /= factor;
 		}
 		v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect);
-		if (dev->bitmap_cap && (compose->width != s->r.width ||
-					compose->height != s->r.height)) {
-			vfree(dev->bitmap_cap);
-			dev->bitmap_cap = NULL;
-		}
 		*compose = s->r;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	if (dev->bitmap_cap && (compose->width != orig_compose_w ||
+				compose->height != orig_compose_h)) {
+		vfree(dev->bitmap_cap);
+		dev->bitmap_cap = NULL;
+	}
 	tpg_s_crop_compose(&dev->tpg, crop, compose);
 	return 0;
 }
@@ -1253,7 +1259,14 @@
 		return -EINVAL;
 	if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8)
 		return -EINVAL;
-	if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
+	if (a->fmt.bytesperline > a->fmt.sizeimage / a->fmt.height)
+		return -EINVAL;
+
+	/*
+	 * Only support the framebuffer of one of the vivid instances.
+	 * Anything else is rejected.
+	 */
+	if (!vivid_validate_fb(a))
 		return -EINVAL;
 
 	dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);
--- linux-ein-5.4.0.orig/drivers/media/platform/vivid/vivid-vid-out.c
+++ linux-ein-5.4.0/drivers/media/platform/vivid/vivid-vid-out.c
@@ -161,9 +161,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) {
@@ -1028,7 +1025,7 @@
 		return -EINVAL;
 	}
 	dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags);
-	dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags);
+	dev->fbuf_out_flags |= a->flags & (chroma_flags | alpha_flags);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vsp1/vsp1_dl.c
+++ linux-ein-5.4.0/drivers/media/platform/vsp1/vsp1_dl.c
@@ -431,6 +431,8 @@
 	if (!pool)
 		return NULL;
 
+	pool->vsp1 = vsp1;
+
 	spin_lock_init(&pool->lock);
 	INIT_LIST_HEAD(&pool->free);
 
--- linux-ein-5.4.0.orig/drivers/media/platform/vsp1/vsp1_drm.c
+++ linux-ein-5.4.0/drivers/media/platform/vsp1/vsp1_drm.c
@@ -245,7 +245,7 @@
 		brx = &vsp1->bru->entity;
 	else if (pipe->brx && !drm_pipe->force_brx_release)
 		brx = pipe->brx;
-	else if (!vsp1->bru->entity.pipe)
+	else if (vsp1_feature(vsp1, VSP1_HAS_BRU) && !vsp1->bru->entity.pipe)
 		brx = &vsp1->bru->entity;
 	else
 		brx = &vsp1->brs->entity;
@@ -462,9 +462,9 @@
 	 * make sure it is present in the pipeline's list of entities if it
 	 * wasn't already.
 	 */
-	if (!use_uif) {
+	if (drm_pipe->uif && !use_uif) {
 		drm_pipe->uif->pipe = NULL;
-	} else if (!drm_pipe->uif->pipe) {
+	} else if (drm_pipe->uif && !drm_pipe->uif->pipe) {
 		drm_pipe->uif->pipe = pipe;
 		list_add_tail(&drm_pipe->uif->list_pipe, &pipe->entities);
 	}
--- linux-ein-5.4.0.orig/drivers/media/platform/vsp1/vsp1_drv.c
+++ linux-ein-5.4.0/drivers/media/platform/vsp1/vsp1_drv.c
@@ -562,7 +562,12 @@
 	int ret;
 
 	ret = pm_runtime_get_sync(vsp1->dev);
-	return ret < 0 ? ret : 0;
+	if (ret < 0) {
+		pm_runtime_put_noidle(vsp1->dev);
+		return ret;
+	}
+
+	return 0;
 }
 
 /*
@@ -845,12 +850,12 @@
 	/* Configure device parameters based on the version register. */
 	pm_runtime_enable(&pdev->dev);
 
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = vsp1_device_get(vsp1);
 	if (ret < 0)
 		goto done;
 
 	vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
-	pm_runtime_put_sync(&pdev->dev);
+	vsp1_device_put(vsp1);
 
 	for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
 		if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
@@ -877,8 +882,10 @@
 	}
 
 done:
-	if (ret)
+	if (ret) {
 		pm_runtime_disable(&pdev->dev);
+		rcar_fcp_put(vsp1->fcp);
+	}
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/platform/vsp1/vsp1_rpf.c
+++ linux-ein-5.4.0/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -291,11 +291,11 @@
 		     + crop.left * fmtinfo->bpp[0] / 8;
 
 	if (format->num_planes > 1) {
+		unsigned int bpl = format->plane_fmt[1].bytesperline;
 		unsigned int offset;
 
-		offset = crop.top * format->plane_fmt[1].bytesperline
-		       + crop.left / fmtinfo->hsub
-		       * fmtinfo->bpp[1] / 8;
+		offset = crop.top / fmtinfo->vsub * bpl
+		       + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8;
 		mem.addr[1] += offset;
 		mem.addr[2] += offset;
 	}
--- linux-ein-5.4.0.orig/drivers/media/platform/xilinx/xilinx-vipp.c
+++ linux-ein-5.4.0/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -472,7 +472,7 @@
 {
 	struct device_node *ports;
 	struct device_node *port;
-	int ret;
+	int ret = 0;
 
 	ports = of_get_child_by_name(xdev->dev->of_node, "ports");
 	if (ports == NULL) {
@@ -482,13 +482,14 @@
 
 	for_each_child_of_node(ports, port) {
 		ret = xvip_graph_dma_init_one(xdev, port);
-		if (ret < 0) {
+		if (ret) {
 			of_node_put(port);
-			return ret;
+			break;
 		}
 	}
 
-	return 0;
+	of_node_put(ports);
+	return ret;
 }
 
 static void xvip_graph_cleanup(struct xvip_composite_device *xdev)
--- linux-ein-5.4.0.orig/drivers/media/radio/radio-shark.c
+++ linux-ein-5.4.0/drivers/media/radio/radio-shark.c
@@ -316,6 +316,16 @@
 {
 	struct shark_device *shark;
 	int retval = -ENOMEM;
+	static const u8 ep_addresses[] = {
+		SHARK_IN_EP | USB_DIR_IN,
+		SHARK_OUT_EP | USB_DIR_OUT,
+		0};
+
+	/* Are the expected endpoints present? */
+	if (!usb_check_int_endpoints(intf, ep_addresses)) {
+		dev_err(&intf->dev, "Invalid radioSHARK device\n");
+		return -EINVAL;
+	}
 
 	shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
 	if (!shark)
--- linux-ein-5.4.0.orig/drivers/media/radio/radio-shark2.c
+++ linux-ein-5.4.0/drivers/media/radio/radio-shark2.c
@@ -282,6 +282,16 @@
 {
 	struct shark_device *shark;
 	int retval = -ENOMEM;
+	static const u8 ep_addresses[] = {
+		SHARK_IN_EP | USB_DIR_IN,
+		SHARK_OUT_EP | USB_DIR_OUT,
+		0};
+
+	/* Are the expected endpoints present? */
+	if (!usb_check_int_endpoints(intf, ep_addresses)) {
+		dev_err(&intf->dev, "Invalid radioSHARK2 device\n");
+		return -EINVAL;
+	}
 
 	shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
 	if (!shark)
--- linux-ein-5.4.0.orig/drivers/media/radio/radio-wl1273.c
+++ linux-ein-5.4.0/drivers/media/radio/radio-wl1273.c
@@ -1148,8 +1148,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;
 
@@ -1280,7 +1279,7 @@
 
 	strscpy(capability->driver, WL1273_FM_DRIVER_NAME,
 		sizeof(capability->driver));
-	strscpy(capability->card, "Texas Instruments Wl1273 FM Radio",
+	strscpy(capability->card, "TI Wl1273 FM Radio",
 		sizeof(capability->card));
 	strscpy(capability->bus_info, radio->bus_type,
 		sizeof(capability->bus_info));
--- linux-ein-5.4.0.orig/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ linux-ein-5.4.0/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -11,7 +11,7 @@
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
-#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio"
 #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
 #define DRIVER_VERSION "1.0.2"
 
@@ -368,7 +368,7 @@
 	if (radio->hdl.error) {
 		retval = radio->hdl.error;
 		dev_err(&client->dev, "couldn't register control\n");
-		goto err_dev;
+		goto err_all;
 	}
 
 	/* video device initialization */
@@ -463,7 +463,6 @@
 	return 0;
 err_all:
 	v4l2_ctrl_handler_free(&radio->hdl);
-err_dev:
 	v4l2_device_unregister(&radio->v4l2_dev);
 err_initial:
 	return retval;
@@ -482,6 +481,8 @@
 	if (radio->gpio_reset)
 		gpiod_set_value(radio->gpio_reset, 0);
 
+	v4l2_ctrl_handler_free(&radio->hdl);
+	v4l2_device_unregister(&radio->v4l2_dev);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/radio/si470x/radio-si470x-usb.c
+++ linux-ein-5.4.0/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -16,7 +16,7 @@
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
-#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
 #define DRIVER_VERSION "1.0.10"
 
@@ -733,8 +733,10 @@
 
 	/* start radio */
 	retval = si470x_start_usb(radio);
-	if (retval < 0)
+	if (retval < 0 && !radio->int_in_running)
 		goto err_buf;
+	else if (retval < 0)	/* in case of radio->int_in_running == 1 */
+		goto err_all;
 
 	/* set initial frequency */
 	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
--- linux-ein-5.4.0.orig/drivers/media/rc/Makefile
+++ linux-ein-5.4.0/drivers/media/rc/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_RC_CORE) += rc-core.o
 rc-core-y := rc-main.o rc-ir-raw.o
 rc-core-$(CONFIG_LIRC) += lirc_dev.o
+rc-core-$(CONFIG_MEDIA_CEC_RC) += keymaps/rc-cec.o
 rc-core-$(CONFIG_BPF_LIRC_MODE2) += bpf-lirc.o
 obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
 obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
--- linux-ein-5.4.0.orig/drivers/media/rc/ati_remote.c
+++ linux-ein-5.4.0/drivers/media/rc/ati_remote.c
@@ -835,6 +835,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(RC_DRIVER_SCANCODE);
--- linux-ein-5.4.0.orig/drivers/media/rc/bpf-lirc.c
+++ linux-ein-5.4.0/drivers/media/rc/bpf-lirc.c
@@ -329,7 +329,8 @@
 	}
 
 	if (attr->query.prog_cnt != 0 && prog_ids && cnt)
-		ret = bpf_prog_array_copy_to_user(progs, prog_ids, cnt);
+		ret = bpf_prog_array_copy_to_user(progs, prog_ids,
+						  attr->query.prog_cnt);
 
 unlock:
 	mutex_unlock(&ir_raw_handler_lock);
--- linux-ein-5.4.0.orig/drivers/media/rc/ene_ir.c
+++ linux-ein-5.4.0/drivers/media/rc/ene_ir.c
@@ -1106,6 +1106,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);
@@ -1113,7 +1115,6 @@
 
 	free_irq(dev->irq, dev);
 	release_region(dev->hw_io, ENE_IO_SIZE);
-	rc_unregister_device(dev->rdev);
 	kfree(dev);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/rc/gpio-ir-recv.c
+++ linux-ein-5.4.0/drivers/media/rc/gpio-ir-recv.c
@@ -83,6 +83,8 @@
 		rcdev->map_name = RC_MAP_EMPTY;
 
 	gpio_dev->rcdev = rcdev;
+	if (of_property_read_bool(np, "wakeup-source"))
+		device_init_wakeup(dev, true);
 
 	rc = devm_rc_register_device(dev, rcdev);
 	if (rc < 0) {
--- linux-ein-5.4.0.orig/drivers/media/rc/gpio-ir-tx.c
+++ linux-ein-5.4.0/drivers/media/rc/gpio-ir-tx.c
@@ -79,13 +79,8 @@
 			// space
 			edge = ktime_add_us(edge, txbuf[i]);
 			delta = ktime_us_delta(edge, ktime_get());
-			if (delta > 10) {
-				spin_unlock_irqrestore(&gpio_ir->lock, flags);
-				usleep_range(delta, delta + 10);
-				spin_lock_irqsave(&gpio_ir->lock, flags);
-			} else if (delta > 0) {
+			if (delta > 0)
 				udelay(delta);
-			}
 		} else {
 			// pulse
 			ktime_t last = ktime_add_us(edge, txbuf[i]);
--- linux-ein-5.4.0.orig/drivers/media/rc/igorplugusb.c
+++ linux-ein-5.4.0/drivers/media/rc/igorplugusb.c
@@ -64,9 +64,11 @@
 	if (start >= len) {
 		dev_err(ir->dev, "receive overflow invalid: %u", overflow);
 	} else {
-		if (overflow > 0)
+		if (overflow > 0) {
 			dev_warn(ir->dev, "receive overflow, at least %u lost",
 								overflow);
+			ir_raw_event_reset(ir->rc);
+		}
 
 		do {
 			rawir.duration = ir->buf_in[i] * 85333;
--- linux-ein-5.4.0.orig/drivers/media/rc/iguanair.c
+++ linux-ein-5.4.0/drivers/media/rc/iguanair.c
@@ -413,7 +413,7 @@
 	int ret, pipein, pipeout;
 	struct usb_host_interface *idesc;
 
-	idesc = intf->altsetting;
+	idesc = intf->cur_altsetting;
 	if (idesc->desc.bNumEndpoints < 2)
 		return -ENODEV;
 
--- linux-ein-5.4.0.orig/drivers/media/rc/imon.c
+++ linux-ein-5.4.0/drivers/media/rc/imon.c
@@ -604,15 +604,14 @@
 		pr_err_ratelimited("error submitting urb(%d)\n", retval);
 	} else {
 		/* Wait for transmission to complete (or abort) */
-		mutex_unlock(&ictx->lock);
 		retval = wait_for_completion_interruptible(
 				&ictx->tx.finished);
 		if (retval) {
 			usb_kill_urb(ictx->tx_urb);
 			pr_err_ratelimited("task interrupted\n");
 		}
-		mutex_lock(&ictx->lock);
 
+		ictx->tx.busy = false;
 		retval = ictx->tx.status;
 		if (retval)
 			pr_err_ratelimited("packet tx failed (%d)\n", retval);
@@ -919,7 +918,8 @@
 		return -ENODEV;
 	}
 
-	mutex_lock(&ictx->lock);
+	if (mutex_lock_interruptible(&ictx->lock))
+		return -ERESTARTSYS;
 
 	if (!ictx->dev_present_intf0) {
 		pr_err_ratelimited("no iMON device present\n");
@@ -1598,8 +1598,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;
 
--- linux-ein-5.4.0.orig/drivers/media/rc/ir-sharp-decoder.c
+++ linux-ein-5.4.0/drivers/media/rc/ir-sharp-decoder.c
@@ -15,7 +15,9 @@
 #define SHARP_UNIT		40000  /* ns */
 #define SHARP_BIT_PULSE		(8    * SHARP_UNIT) /* 320us */
 #define SHARP_BIT_0_PERIOD	(25   * SHARP_UNIT) /* 1ms (680us space) */
-#define SHARP_BIT_1_PERIOD	(50   * SHARP_UNIT) /* 2ms (1680ms space) */
+#define SHARP_BIT_1_PERIOD	(50   * SHARP_UNIT) /* 2ms (1680us space) */
+#define SHARP_BIT_0_SPACE	(17   * SHARP_UNIT) /* 680us space */
+#define SHARP_BIT_1_SPACE	(42   * SHARP_UNIT) /* 1680us space */
 #define SHARP_ECHO_SPACE	(1000 * SHARP_UNIT) /* 40 ms */
 #define SHARP_TRAILER_SPACE	(125  * SHARP_UNIT) /* 5 ms (even longer) */
 
@@ -168,8 +170,8 @@
 	.header_pulse  = 0,
 	.header_space  = 0,
 	.bit_pulse     = SHARP_BIT_PULSE,
-	.bit_space[0]  = SHARP_BIT_0_PERIOD,
-	.bit_space[1]  = SHARP_BIT_1_PERIOD,
+	.bit_space[0]  = SHARP_BIT_0_SPACE,
+	.bit_space[1]  = SHARP_BIT_1_SPACE,
 	.trailer_pulse = SHARP_BIT_PULSE,
 	.trailer_space = SHARP_ECHO_SPACE,
 	.msb_first     = 1,
--- linux-ein-5.4.0.orig/drivers/media/rc/ite-cir.c
+++ linux-ein-5.4.0/drivers/media/rc/ite-cir.c
@@ -276,6 +276,12 @@
 	/* read the interrupt flags */
 	iflags = dev->params.get_irq_causes(dev);
 
+	/* Check for RX overflow */
+	if (iflags & ITE_IRQ_RX_FIFO_OVERRUN) {
+		dev_warn(&dev->rdev->dev, "receive overflow\n");
+		ir_raw_event_reset(dev->rdev);
+	}
+
 	/* check for the receive interrupt */
 	if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) {
 		/* read the FIFO bytes */
--- linux-ein-5.4.0.orig/drivers/media/rc/keymaps/Makefile
+++ linux-ein-5.4.0/drivers/media/rc/keymaps/Makefile
@@ -20,7 +20,6 @@
 			rc-behold.o \
 			rc-behold-columbus.o \
 			rc-budget-ci-old.o \
-			rc-cec.o \
 			rc-cinergy-1400.o \
 			rc-cinergy.o \
 			rc-d680-dmb.o \
@@ -117,6 +116,7 @@
 			rc-videomate-m1f.o \
 			rc-videomate-s350.o \
 			rc-videomate-tv-pvr.o \
+			rc-videostrong-kii-pro.o \
 			rc-wetek-hub.o \
 			rc-wetek-play2.o \
 			rc-winfast.o \
--- linux-ein-5.4.0.orig/drivers/media/rc/keymaps/rc-cec.c
+++ linux-ein-5.4.0/drivers/media/rc/keymaps/rc-cec.c
@@ -1,6 +1,16 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* Keytable for the CEC remote control
  *
+ * This keymap is unusual in that it can't be built as a module,
+ * instead it is registered directly in rc-main.c if CONFIG_MEDIA_CEC_RC
+ * is set. This is because it can be called from drm_dp_cec_set_edid() via
+ * cec_register_adapter() in an asynchronous context, and it is not
+ * allowed to use request_module() to load rc-cec.ko in that case.
+ *
+ * Since this keymap is only used if CONFIG_MEDIA_CEC_RC is set, we
+ * just compile this keymap into the rc-core module and never as a
+ * separate module.
+ *
  * Copyright (c) 2015 by Kamil Debski
  */
 
@@ -152,7 +162,7 @@
 	/* 0x77-0xff: Reserved */
 };
 
-static struct rc_map_list cec_map = {
+struct rc_map_list cec_map = {
 	.map = {
 		.scan		= cec,
 		.size		= ARRAY_SIZE(cec),
@@ -160,19 +170,3 @@
 		.name		= RC_MAP_CEC,
 	}
 };
-
-static int __init init_rc_map_cec(void)
-{
-	return rc_map_register(&cec_map);
-}
-
-static void __exit exit_rc_map_cec(void)
-{
-	rc_map_unregister(&cec_map);
-}
-
-module_init(init_rc_map_cec);
-module_exit(exit_rc_map_cec);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kamil Debski");
--- linux-ein-5.4.0.orig/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c
+++ linux-ein-5.4.0/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2019 Mohammad Rasim <mohammad.rasim96@gmail.com>
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+//
+// Keytable for the Videostrong KII Pro STB remote control
+//
+
+static struct rc_map_table kii_pro[] = {
+	{ 0x59, KEY_POWER },
+	{ 0x19, KEY_MUTE },
+	{ 0x42, KEY_RED },
+	{ 0x40, KEY_GREEN },
+	{ 0x00, KEY_YELLOW },
+	{ 0x03, KEY_BLUE },
+	{ 0x4a, KEY_BACK },
+	{ 0x48, KEY_FORWARD },
+	{ 0x08, KEY_PREVIOUSSONG},
+	{ 0x0b, KEY_NEXTSONG},
+	{ 0x46, KEY_PLAYPAUSE },
+	{ 0x44, KEY_STOP },
+	{ 0x1f, KEY_FAVORITES},	//KEY_F5?
+	{ 0x04, KEY_PVR },
+	{ 0x4d, KEY_EPG },
+	{ 0x02, KEY_INFO },
+	{ 0x09, KEY_SUBTITLE },
+	{ 0x01, KEY_AUDIO },
+	{ 0x0d, KEY_HOMEPAGE },
+	{ 0x11, KEY_TV },	// DTV ?
+	{ 0x06, KEY_UP },
+	{ 0x5a, KEY_LEFT },
+	{ 0x1a, KEY_ENTER },	// KEY_OK ?
+	{ 0x1b, KEY_RIGHT },
+	{ 0x16, KEY_DOWN },
+	{ 0x45, KEY_MENU },
+	{ 0x05, KEY_ESC },
+	{ 0x13, KEY_VOLUMEUP },
+	{ 0x17, KEY_VOLUMEDOWN },
+	{ 0x58, KEY_APPSELECT },
+	{ 0x12, KEY_VENDOR },	// mouse
+	{ 0x55, KEY_PAGEUP },	// KEY_CHANNELUP ?
+	{ 0x15, KEY_PAGEDOWN },	// KEY_CHANNELDOWN ?
+	{ 0x52, KEY_1 },
+	{ 0x50, KEY_2 },
+	{ 0x10, KEY_3 },
+	{ 0x56, KEY_4 },
+	{ 0x54, KEY_5 },
+	{ 0x14, KEY_6 },
+	{ 0x4e, KEY_7 },
+	{ 0x4c, KEY_8 },
+	{ 0x0c, KEY_9 },
+	{ 0x18, KEY_WWW },	// KEY_F7
+	{ 0x0f, KEY_0 },
+	{ 0x51, KEY_BACKSPACE },
+};
+
+static struct rc_map_list kii_pro_map = {
+	.map = {
+		.scan     = kii_pro,
+		.size     = ARRAY_SIZE(kii_pro),
+		.rc_proto = RC_PROTO_NEC,
+		.name     = RC_MAP_KII_PRO,
+	}
+};
+
+static int __init init_rc_map_kii_pro(void)
+{
+	return rc_map_register(&kii_pro_map);
+}
+
+static void __exit exit_rc_map_kii_pro(void)
+{
+	rc_map_unregister(&kii_pro_map);
+}
+
+module_init(init_rc_map_kii_pro)
+module_exit(exit_rc_map_kii_pro)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mohammad Rasim <mohammad.rasim96@gmail.com>");
--- linux-ein-5.4.0.orig/drivers/media/rc/lirc_dev.c
+++ linux-ein-5.4.0/drivers/media/rc/lirc_dev.c
@@ -292,7 +292,11 @@
 		if (ret < 0)
 			goto out_kfree_raw;
 
-		count = ret;
+		/* drop trailing space */
+		if (!(ret % 2))
+			count = ret - 1;
+		else
+			count = ret;
 
 		txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL);
 		if (!txbuf) {
--- linux-ein-5.4.0.orig/drivers/media/rc/mceusb.c
+++ linux-ein-5.4.0/drivers/media/rc/mceusb.c
@@ -564,7 +564,7 @@
 			datasize = 4;
 			break;
 		case MCE_CMD_G_REVISION:
-			datasize = 2;
+			datasize = 4;
 			break;
 		case MCE_RSP_EQWAKESUPPORT:
 		case MCE_RSP_GETWAKESOURCE:
@@ -600,14 +600,9 @@
 	char *inout;
 	u8 cmd, subcmd, *data;
 	struct device *dev = ir->dev;
-	int start, skip = 0;
 	u32 carrier, period;
 
-	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
-	if (ir->flags.microsoft_gen1 && !out && !offset)
-		skip = 2;
-
-	if (len <= skip)
+	if (offset < 0 || offset >= buf_len)
 		return;
 
 	dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)",
@@ -616,11 +611,32 @@
 
 	inout = out ? "Request" : "Got";
 
-	start  = offset + skip;
-	cmd    = buf[start] & 0xff;
-	subcmd = buf[start + 1] & 0xff;
-	data = buf + start + 2;
+	cmd    = buf[offset];
+	subcmd = (offset + 1 < buf_len) ? buf[offset + 1] : 0;
+	data   = &buf[offset] + 2;
+
+	/* Trace meaningless 0xb1 0x60 header bytes on original receiver */
+	if (ir->flags.microsoft_gen1 && !out && !offset) {
+		dev_dbg(dev, "MCE gen 1 header");
+		return;
+	}
 
+	/* Trace IR data header or trailer */
+	if (cmd != MCE_CMD_PORT_IR &&
+	    (cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA) {
+		if (cmd == MCE_IRDATA_TRAILER)
+			dev_dbg(dev, "End of raw IR data");
+		else
+			dev_dbg(dev, "Raw IR data, %d pulse/space samples",
+				cmd & MCE_PACKET_LENGTH_MASK);
+		return;
+	}
+
+	/* Unexpected end of buffer? */
+	if (offset + len > buf_len)
+		return;
+
+	/* Decode MCE command/response */
 	switch (cmd) {
 	case MCE_CMD_NULL:
 		if (subcmd == MCE_CMD_NULL)
@@ -644,7 +660,7 @@
 				dev_dbg(dev, "Get hw/sw rev?");
 			else
 				dev_dbg(dev, "hw/sw rev %*ph",
-					4, &buf[start + 2]);
+					4, &buf[offset + 2]);
 			break;
 		case MCE_CMD_RESUME:
 			dev_dbg(dev, "Device resume requested");
@@ -685,11 +701,18 @@
 				data[0], data[1]);
 			break;
 		case MCE_RSP_EQIRCFS:
+			if (!data[0] && !data[1]) {
+				dev_dbg(dev, "%s: no carrier", inout);
+				break;
+			}
+			// prescaler should make sense
+			if (data[0] > 8)
+				break;
 			period = DIV_ROUND_CLOSEST((1U << data[0] * 2) *
 						   (data[1] + 1), 10);
 			if (!period)
 				break;
-			carrier = (1000 * 1000) / period;
+			carrier = USEC_PER_SEC / period;
 			dev_dbg(dev, "%s carrier of %u Hz (period %uus)",
 				 inout, carrier, period);
 			break;
@@ -746,13 +769,6 @@
 	default:
 		break;
 	}
-
-	if (cmd == MCE_IRDATA_TRAILER)
-		dev_dbg(dev, "End of raw IR data");
-	else if ((cmd != MCE_CMD_PORT_IR) &&
-		 ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
-		dev_dbg(dev, "Raw IR data, %d pulse/space samples",
-			cmd & MCE_PACKET_LENGTH_MASK);
 #endif
 }
 
@@ -1136,32 +1152,62 @@
 }
 
 /*
+ * Handle PORT_SYS/IR command response received from the MCE device.
+ *
+ * Assumes single response with all its data (not truncated)
+ * in buf_in[]. The response itself determines its total length
+ * (mceusb_cmd_datasize() + 2) and hence the minimum size of buf_in[].
+ *
  * We don't do anything but print debug spew for many of the command bits
  * we receive from the hardware, but some of them are useful information
  * we want to store so that we can use them.
  */
-static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
 {
+	u8 cmd = buf_in[0];
+	u8 subcmd = buf_in[1];
+	u8 *hi = &buf_in[2];		/* read only when required */
+	u8 *lo = &buf_in[3];		/* read only when required */
 	struct ir_raw_event rawir = {};
-	u8 hi = ir->buf_in[index + 1] & 0xff;
-	u8 lo = ir->buf_in[index + 2] & 0xff;
 	u32 carrier_cycles;
 	u32 cycles_fix;
 
-	switch (ir->buf_in[index]) {
-	/* the one and only 5-byte return value command */
-	case MCE_RSP_GETPORTSTATUS:
-		if ((ir->buf_in[index + 4] & 0xff) == 0x00)
-			ir->txports_cabled |= 1 << hi;
-		break;
+	if (cmd == MCE_CMD_PORT_SYS) {
+		switch (subcmd) {
+		/* the one and only 5-byte return value command */
+		case MCE_RSP_GETPORTSTATUS:
+			if (buf_in[5] == 0 && *hi < 8)
+				ir->txports_cabled |= 1 << *hi;
+			break;
+
+		/* 1-byte return value commands */
+		case MCE_RSP_EQEMVER:
+			ir->emver = *hi;
+			break;
 
+		/* No return value commands */
+		case MCE_RSP_CMD_ILLEGAL:
+			ir->need_reset = true;
+			break;
+
+		default:
+			break;
+		}
+
+		return;
+	}
+
+	if (cmd != MCE_CMD_PORT_IR)
+		return;
+
+	switch (subcmd) {
 	/* 2-byte return value commands */
 	case MCE_RSP_EQIRTIMEOUT:
-		ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
+		ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT);
 		break;
 	case MCE_RSP_EQIRNUMPORTS:
-		ir->num_txports = hi;
-		ir->num_rxports = lo;
+		ir->num_txports = *hi;
+		ir->num_rxports = *lo;
 		break;
 	case MCE_RSP_EQIRRXCFCNT:
 		/*
@@ -1174,7 +1220,7 @@
 		 */
 		if (ir->carrier_report_enabled && ir->learning_active &&
 		    ir->pulse_tunit > 0) {
-			carrier_cycles = (hi << 8 | lo);
+			carrier_cycles = (*hi << 8 | *lo);
 			/*
 			 * Adjust carrier cycle count by adding
 			 * 1 missed count per pulse "on"
@@ -1192,24 +1238,24 @@
 		break;
 
 	/* 1-byte return value commands */
-	case MCE_RSP_EQEMVER:
-		ir->emver = hi;
-		break;
 	case MCE_RSP_EQIRTXPORTS:
-		ir->tx_mask = hi;
+		ir->tx_mask = *hi;
 		break;
 	case MCE_RSP_EQIRRXPORTEN:
-		ir->learning_active = ((hi & 0x02) == 0x02);
-		if (ir->rxports_active != hi) {
+		ir->learning_active = ((*hi & 0x02) == 0x02);
+		if (ir->rxports_active != *hi) {
 			dev_info(ir->dev, "%s-range (0x%x) receiver active",
-				 ir->learning_active ? "short" : "long", hi);
-			ir->rxports_active = hi;
+				 ir->learning_active ? "short" : "long", *hi);
+			ir->rxports_active = *hi;
 		}
 		break;
+
+	/* No return value commands */
 	case MCE_RSP_CMD_ILLEGAL:
 	case MCE_RSP_TX_TIMEOUT:
 		ir->need_reset = true;
 		break;
+
 	default:
 		break;
 	}
@@ -1235,7 +1281,8 @@
 			ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
 			mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1,
 					     ir->rem + 2, false);
-			mceusb_handle_command(ir, i);
+			if (i + ir->rem < buf_len)
+				mceusb_handle_command(ir, &ir->buf_in[i - 1]);
 			ir->parser_state = CMD_DATA;
 			break;
 		case PARSE_IRDATA:
@@ -1264,15 +1311,22 @@
 			ir->rem--;
 			break;
 		case CMD_HEADER:
-			/* decode mce packets of the form (84),AA,BB,CC,DD */
-			/* IR data packets can span USB messages - rem */
 			ir->cmd = ir->buf_in[i];
 			if ((ir->cmd == MCE_CMD_PORT_IR) ||
 			    ((ir->cmd & MCE_PORT_MASK) !=
 			     MCE_COMMAND_IRDATA)) {
+				/*
+				 * got PORT_SYS, PORT_IR, or unknown
+				 * command response prefix
+				 */
 				ir->parser_state = SUBCMD;
 				continue;
 			}
+			/*
+			 * got IR data prefix (0x80 + num_bytes)
+			 * decode MCE packets of the form {0x83, AA, BB, CC}
+			 * IR data packets can span USB messages
+			 */
 			ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
 			mceusb_dev_printdata(ir, ir->buf_in, buf_len,
 					     i, ir->rem + 1, false);
@@ -1296,6 +1350,14 @@
 		if (ir->parser_state != CMD_HEADER && !ir->rem)
 			ir->parser_state = CMD_HEADER;
 	}
+
+	/*
+	 * Accept IR data spanning multiple rx buffers.
+	 * Reject MCE command response spanning multiple rx buffers.
+	 */
+	if (ir->parser_state != PARSE_IRDATA || !ir->rem)
+		ir->parser_state = CMD_HEADER;
+
 	if (event) {
 		dev_dbg(ir->dev, "processed IR data");
 		ir_raw_event_handle(ir->rc);
@@ -1324,6 +1386,7 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -EILSEQ:
+	case -EPROTO:
 	case -ESHUTDOWN:
 		usb_unlink_urb(urb);
 		return;
@@ -1353,42 +1416,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 */
@@ -1396,8 +1454,6 @@
 
 	/* get hw/sw revision? */
 	mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION));
-
-	kfree(data);
 }
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
--- linux-ein-5.4.0.orig/drivers/media/rc/rc-loopback.c
+++ linux-ein-5.4.0/drivers/media/rc/rc-loopback.c
@@ -42,7 +42,7 @@
 
 	if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
 		dprintk("invalid tx mask: %u\n", mask);
-		return -EINVAL;
+		return 2;
 	}
 
 	dprintk("setting tx mask: %u\n", mask);
--- linux-ein-5.4.0.orig/drivers/media/rc/rc-main.c
+++ linux-ein-5.4.0/drivers/media/rc/rc-main.c
@@ -1256,6 +1256,10 @@
 	}
 
 	mutex_lock(&dev->lock);
+	if (!dev->registered) {
+		mutex_unlock(&dev->lock);
+		return -ENODEV;
+	}
 
 	old_protocols = *current_protocols;
 	new_protocols = old_protocols;
@@ -1394,6 +1398,10 @@
 		return -EINVAL;
 
 	mutex_lock(&dev->lock);
+	if (!dev->registered) {
+		mutex_unlock(&dev->lock);
+		return -ENODEV;
+	}
 
 	new_filter = *filter;
 	if (fattr->mask)
@@ -1508,6 +1516,10 @@
 	int i;
 
 	mutex_lock(&dev->lock);
+	if (!dev->registered) {
+		mutex_unlock(&dev->lock);
+		return -ENODEV;
+	}
 
 	allowed = dev->allowed_wakeup_protocols;
 
@@ -1565,25 +1577,25 @@
 	kfree(dev);
 }
 
-#define ADD_HOTPLUG_VAR(fmt, val...)					\
-	do {								\
-		int err = add_uevent_var(env, fmt, val);		\
-		if (err)						\
-			return err;					\
-	} while (0)
-
 static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
 	struct rc_dev *dev = to_rc_dev(device);
+	int ret = 0;
+
+	mutex_lock(&dev->lock);
 
-	if (dev->rc_map.name)
-		ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
-	if (dev->driver_name)
-		ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
-	if (dev->device_name)
-		ADD_HOTPLUG_VAR("DEV_NAME=%s", dev->device_name);
+	if (!dev->registered)
+		ret = -ENODEV;
+	if (ret == 0 && dev->rc_map.name)
+		ret = add_uevent_var(env, "NAME=%s", dev->rc_map.name);
+	if (ret == 0 && dev->driver_name)
+		ret = add_uevent_var(env, "DRV_NAME=%s", dev->driver_name);
+	if (ret == 0 && dev->device_name)
+		ret = add_uevent_var(env, "DEV_NAME=%s", dev->device_name);
 
-	return 0;
+	mutex_unlock(&dev->lock);
+
+	return ret;
 }
 
 /*
@@ -1773,6 +1785,7 @@
 	set_bit(MSC_SCAN, dev->input_dev->mscbit);
 
 	/* Pointer/mouse events */
+	set_bit(INPUT_PROP_POINTING_STICK, dev->input_dev->propbit);
 	set_bit(EV_REL, dev->input_dev->evbit);
 	set_bit(REL_X, dev->input_dev->relbit);
 	set_bit(REL_Y, dev->input_dev->relbit);
@@ -1879,6 +1892,8 @@
 			goto out_raw;
 	}
 
+	dev->registered = true;
+
 	rc = device_add(&dev->dev);
 	if (rc)
 		goto out_rx_free;
@@ -1888,25 +1903,28 @@
 		 dev->device_name ?: "Unspecified device", path ?: "N/A");
 	kfree(path);
 
-	dev->registered = true;
+	/*
+	 * once the the input device is registered in rc_setup_rx_device,
+	 * userspace can open the input device and rc_open() will be called
+	 * as a result. This results in driver code being allowed to submit
+	 * keycodes with rc_keydown, so lirc must be registered first.
+	 */
+	if (dev->allowed_protocols != RC_PROTO_BIT_CEC) {
+		rc = ir_lirc_register(dev);
+		if (rc < 0)
+			goto out_dev;
+	}
 
 	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
 		rc = rc_setup_rx_device(dev);
 		if (rc)
-			goto out_dev;
-	}
-
-	/* Ensure that the lirc kfifo is setup before we start the thread */
-	if (dev->allowed_protocols != RC_PROTO_BIT_CEC) {
-		rc = ir_lirc_register(dev);
-		if (rc < 0)
-			goto out_rx;
+			goto out_lirc;
 	}
 
 	if (dev->driver_type == RC_DRIVER_IR_RAW) {
 		rc = ir_raw_event_register(dev);
 		if (rc < 0)
-			goto out_lirc;
+			goto out_rx;
 	}
 
 	dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor,
@@ -1914,11 +1932,11 @@
 
 	return 0;
 
+out_rx:
+	rc_free_rx_device(dev);
 out_lirc:
 	if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
 		ir_lirc_unregister(dev);
-out_rx:
-	rc_free_rx_device(dev);
 out_dev:
 	device_del(&dev->dev);
 out_rx_free:
@@ -1969,14 +1987,14 @@
 	del_timer_sync(&dev->timer_keyup);
 	del_timer_sync(&dev->timer_repeat);
 
-	rc_free_rx_device(dev);
-
 	mutex_lock(&dev->lock);
 	if (dev->users && dev->close)
 		dev->close(dev);
 	dev->registered = false;
 	mutex_unlock(&dev->lock);
 
+	rc_free_rx_device(dev);
+
 	/*
 	 * lirc device should be freed with dev->registered = false, so
 	 * that userspace polling will get notified.
@@ -2015,6 +2033,9 @@
 
 	led_trigger_register_simple("rc-feedback", &led_feedback);
 	rc_map_register(&empty_map);
+#ifdef CONFIG_MEDIA_CEC_RC
+	rc_map_register(&cec_map);
+#endif
 
 	return 0;
 }
@@ -2024,6 +2045,9 @@
 	lirc_dev_exit();
 	class_unregister(&rc_class);
 	led_trigger_unregister_simple(led_feedback);
+#ifdef CONFIG_MEDIA_CEC_RC
+	rc_map_unregister(&cec_map);
+#endif
 	rc_map_unregister(&empty_map);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/rc/redrat3.c
+++ linux-ein-5.4.0/drivers/media/rc/redrat3.c
@@ -405,7 +405,7 @@
 	udev = rr3->udev;
 	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd,
 			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			      0x0000, 0x0000, data, sizeof(u8), HZ * 10);
+			      0x0000, 0x0000, data, sizeof(u8), 10000);
 
 	if (res < 0) {
 		dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d",
@@ -481,7 +481,7 @@
 	pipe = usb_rcvctrlpipe(rr3->udev, 0);
 	ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
 			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			      RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
+			      RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, 5000);
 	if (ret != len)
 		dev_warn(rr3->dev, "Failed to read timeout from hardware\n");
 	else {
@@ -511,7 +511,7 @@
 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RR3_SET_IR_PARAM,
 		     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
 		     RR3_IR_IO_SIG_TIMEOUT, 0, timeout, sizeof(*timeout),
-		     HZ * 25);
+		     25000);
 	dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n",
 						be32_to_cpu(*timeout), ret);
 
@@ -543,32 +543,32 @@
 	*val = 0x01;
 	rc = usb_control_msg(udev, rxpipe, RR3_RESET,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			     RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25);
+			     RR3_CPUCS_REG_ADDR, 0, val, len, 25000);
 	dev_dbg(dev, "reset returned 0x%02x\n", rc);
 
 	*val = length_fuzz;
 	rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-			     RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25);
+			     RR3_IR_IO_LENGTH_FUZZ, 0, val, len, 25000);
 	dev_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc);
 
 	*val = (65536 - (minimum_pause * 2000)) / 256;
 	rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-			     RR3_IR_IO_MIN_PAUSE, 0, val, len, HZ * 25);
+			     RR3_IR_IO_MIN_PAUSE, 0, val, len, 25000);
 	dev_dbg(dev, "set ir parm min pause %d rc 0x%02x\n", *val, rc);
 
 	*val = periods_measure_carrier;
 	rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-			     RR3_IR_IO_PERIODS_MF, 0, val, len, HZ * 25);
+			     RR3_IR_IO_PERIODS_MF, 0, val, len, 25000);
 	dev_dbg(dev, "set ir parm periods measure carrier %d rc 0x%02x", *val,
 									rc);
 
 	*val = RR3_DRIVER_MAXLENS;
 	rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-			     RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25);
+			     RR3_IR_IO_MAX_LENGTHS, 0, val, len, 25000);
 	dev_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc);
 
 	kfree(val);
@@ -586,7 +586,7 @@
 	rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0),
 			     RR3_FW_VERSION,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			     0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5);
+			     0, 0, buffer, RR3_FW_VERSION_LEN, 5000);
 
 	if (rc >= 0)
 		dev_info(rr3->dev, "Firmware rev: %s", buffer);
@@ -826,14 +826,14 @@
 
 	pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
 	ret = usb_bulk_msg(rr3->udev, pipe, irdata,
-			    sendbuf_len, &ret_len, 10 * HZ);
+			    sendbuf_len, &ret_len, 10000);
 	dev_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret);
 
 	/* now tell the hardware to transmit what we sent it */
 	pipe = usb_rcvctrlpipe(rr3->udev, 0);
 	ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
 			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			      0, 0, irdata, 2, HZ * 10);
+			      0, 0, irdata, 2, 10000);
 
 	if (ret < 0)
 		dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
--- linux-ein-5.4.0.orig/drivers/media/rc/sunxi-cir.c
+++ linux-ein-5.4.0/drivers/media/rc/sunxi-cir.c
@@ -137,6 +137,8 @@
 	} else if (status & REG_RXSTA_RPE) {
 		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);
--- linux-ein-5.4.0.orig/drivers/media/spi/cxd2880-spi.c
+++ linux-ein-5.4.0/drivers/media/spi/cxd2880-spi.c
@@ -524,13 +524,13 @@
 	if (IS_ERR(dvb_spi->vcc_supply)) {
 		if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) {
 			ret = -EPROBE_DEFER;
-			goto fail_adapter;
+			goto fail_regulator;
 		}
 		dvb_spi->vcc_supply = NULL;
 	} else {
 		ret = regulator_enable(dvb_spi->vcc_supply);
 		if (ret)
-			goto fail_adapter;
+			goto fail_regulator;
 	}
 
 	dvb_spi->spi = spi;
@@ -618,6 +618,9 @@
 fail_attach:
 	dvb_unregister_adapter(&dvb_spi->adapter);
 fail_adapter:
+	if (dvb_spi->vcc_supply)
+		regulator_disable(dvb_spi->vcc_supply);
+fail_regulator:
 	kfree(dvb_spi);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/media/tuners/fc0011.c
+++ linux-ein-5.4.0/drivers/media/tuners/fc0011.c
@@ -499,7 +499,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(fc0011_attach);
+EXPORT_SYMBOL_GPL(fc0011_attach);
 
 MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
 MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
--- linux-ein-5.4.0.orig/drivers/media/tuners/fc0012.c
+++ linux-ein-5.4.0/drivers/media/tuners/fc0012.c
@@ -495,7 +495,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(fc0012_attach);
+EXPORT_SYMBOL_GPL(fc0012_attach);
 
 MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
 MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
--- linux-ein-5.4.0.orig/drivers/media/tuners/fc0013.c
+++ linux-ein-5.4.0/drivers/media/tuners/fc0013.c
@@ -608,7 +608,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(fc0013_attach);
+EXPORT_SYMBOL_GPL(fc0013_attach);
 
 MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
 MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
--- linux-ein-5.4.0.orig/drivers/media/tuners/m88rs6000t.c
+++ linux-ein-5.4.0/drivers/media/tuners/m88rs6000t.c
@@ -525,7 +525,7 @@
 	PGA2_cri = PGA2_GC >> 2;
 	PGA2_crf = PGA2_GC & 0x03;
 
-	for (i = 0; i <= RF_GC; i++)
+	for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++)
 		RFG += RFGS[i];
 
 	if (RF_GC == 0)
@@ -537,12 +537,12 @@
 	if (RF_GC == 3)
 		RFG += 100;
 
-	for (i = 0; i <= IF_GC; i++)
+	for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++)
 		IFG += IFGS[i];
 
 	TIAG = TIA_GC * TIA_GS;
 
-	for (i = 0; i <= BB_GC; i++)
+	for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++)
 		BBG += BBGS[i];
 
 	PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
--- linux-ein-5.4.0.orig/drivers/media/tuners/max2165.c
+++ linux-ein-5.4.0/drivers/media/tuners/max2165.c
@@ -410,7 +410,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(max2165_attach);
+EXPORT_SYMBOL_GPL(max2165_attach);
 
 MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
 MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/tuners/mc44s803.c
+++ linux-ein-5.4.0/drivers/media/tuners/mc44s803.c
@@ -356,7 +356,7 @@
 	kfree(priv);
 	return NULL;
 }
-EXPORT_SYMBOL(mc44s803_attach);
+EXPORT_SYMBOL_GPL(mc44s803_attach);
 
 MODULE_AUTHOR("Jochen Friedrich");
 MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/tuners/msi001.c
+++ linux-ein-5.4.0/drivers/media/tuners/msi001.c
@@ -442,6 +442,13 @@
 			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
 	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops,
 			V4L2_CID_RF_TUNER_BANDWIDTH, 200000, 8000000, 1, 200000);
+	if (dev->hdl.error) {
+		ret = dev->hdl.error;
+		dev_err(&spi->dev, "Could not initialize controls\n");
+		/* control init failed, free handler */
+		goto err_ctrl_handler_free;
+	}
+
 	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
 	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops,
 			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1);
--- linux-ein-5.4.0.orig/drivers/media/tuners/mt2060.c
+++ linux-ein-5.4.0/drivers/media/tuners/mt2060.c
@@ -440,7 +440,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(mt2060_attach);
+EXPORT_SYMBOL_GPL(mt2060_attach);
 
 static int mt2060_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
--- linux-ein-5.4.0.orig/drivers/media/tuners/mt2131.c
+++ linux-ein-5.4.0/drivers/media/tuners/mt2131.c
@@ -274,7 +274,7 @@
 	fe->tuner_priv = priv;
 	return fe;
 }
-EXPORT_SYMBOL(mt2131_attach);
+EXPORT_SYMBOL_GPL(mt2131_attach);
 
 MODULE_AUTHOR("Steven Toth");
 MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/tuners/mt2266.c
+++ linux-ein-5.4.0/drivers/media/tuners/mt2266.c
@@ -336,7 +336,7 @@
 	mt2266_calibrate(priv);
 	return fe;
 }
-EXPORT_SYMBOL(mt2266_attach);
+EXPORT_SYMBOL_GPL(mt2266_attach);
 
 MODULE_AUTHOR("Olivier DANET");
 MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/tuners/mxl5005s.c
+++ linux-ein-5.4.0/drivers/media/tuners/mxl5005s.c
@@ -4114,7 +4114,7 @@
 	fe->tuner_priv = state;
 	return fe;
 }
-EXPORT_SYMBOL(mxl5005s_attach);
+EXPORT_SYMBOL_GPL(mxl5005s_attach);
 
 MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
 MODULE_AUTHOR("Steven Toth");
--- linux-ein-5.4.0.orig/drivers/media/tuners/qm1d1c0042.c
+++ linux-ein-5.4.0/drivers/media/tuners/qm1d1c0042.c
@@ -343,8 +343,10 @@
 		if (val == reg_initval[reg_index][0x00])
 			break;
 	}
-	if (reg_index >= QM1D1C0042_NUM_REG_ROWS)
+	if (reg_index >= QM1D1C0042_NUM_REG_ROWS) {
+		ret = -EINVAL;
 		goto failed;
+	}
 	memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS);
 	usleep_range(2000, 3000);
 
--- linux-ein-5.4.0.orig/drivers/media/tuners/qt1010.c
+++ linux-ein-5.4.0/drivers/media/tuners/qt1010.c
@@ -215,7 +215,7 @@
 static int qt1010_init_meas1(struct qt1010_priv *priv,
 			     u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
 {
-	u8 i, val1, uninitialized_var(val2);
+	u8 i, val1, val2;
 	int err;
 
 	qt1010_i2c_oper_t i2c_data[] = {
@@ -250,7 +250,7 @@
 static int qt1010_init_meas2(struct qt1010_priv *priv,
 			    u8 reg_init_val, u8 *retval)
 {
-	u8 i, uninitialized_var(val);
+	u8 i, val;
 	int err;
 	qt1010_i2c_oper_t i2c_data[] = {
 		{ QT1010_WR, 0x07, reg_init_val },
@@ -342,11 +342,12 @@
 			else
 				valptr = &tmpval;
 
-			BUG_ON(i >= ARRAY_SIZE(i2c_data) - 1);
-
-			err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
-						i2c_data[i].reg,
-						i2c_data[i].val, valptr);
+			if (i >= ARRAY_SIZE(i2c_data) - 1)
+				err = -EIO;
+			else
+				err = qt1010_init_meas1(priv, i2c_data[i + 1].reg,
+							i2c_data[i].reg,
+							i2c_data[i].val, valptr);
 			i++;
 			break;
 		}
@@ -437,7 +438,7 @@
 	fe->tuner_priv = priv;
 	return fe;
 }
-EXPORT_SYMBOL(qt1010_attach);
+EXPORT_SYMBOL_GPL(qt1010_attach);
 
 MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
--- linux-ein-5.4.0.orig/drivers/media/tuners/si2157.c
+++ linux-ein-5.4.0/drivers/media/tuners/si2157.c
@@ -75,24 +75,23 @@
 	struct si2157_cmd cmd;
 	const struct firmware *fw;
 	const char *fw_name;
-	unsigned int uitmp, chip_id;
+	unsigned int chip_id, xtal_trim;
 
 	dev_dbg(&client->dev, "\n");
 
-	/* Returned IF frequency is garbage when firmware is not running */
-	memcpy(cmd.args, "\x15\x00\x06\x07", 4);
+	/* Try to get Xtal trim property, to verify tuner still running */
+	memcpy(cmd.args, "\x15\x00\x02\x04", 4);
 	cmd.wlen = 4;
 	cmd.rlen = 4;
 	ret = si2157_cmd_execute(client, &cmd);
-	if (ret)
-		goto err;
 
-	uitmp = cmd.args[2] << 0 | cmd.args[3] << 8;
-	dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp);
+	xtal_trim = cmd.args[2] | (cmd.args[3] << 8);
 
-	if (uitmp == dev->if_frequency / 1000)
+	if (ret == 0 && xtal_trim < 16)
 		goto warm;
 
+	dev->if_frequency = 0; /* we no longer know current tuner state */
+
 	/* power up */
 	if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
 		memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
--- linux-ein-5.4.0.orig/drivers/media/tuners/tda18218.c
+++ linux-ein-5.4.0/drivers/media/tuners/tda18218.c
@@ -336,7 +336,7 @@
 
 	return fe;
 }
-EXPORT_SYMBOL(tda18218_attach);
+EXPORT_SYMBOL_GPL(tda18218_attach);
 
 MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
--- linux-ein-5.4.0.orig/drivers/media/tuners/tuner-simple.c
+++ linux-ein-5.4.0/drivers/media/tuners/tuner-simple.c
@@ -500,7 +500,7 @@
 	case TUNER_TENA_9533_DI:
 	case TUNER_YMEC_TVF_5533MF:
 		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
-		return 0;
+		return -EINVAL;
 	case TUNER_PHILIPS_FM1216ME_MK3:
 	case TUNER_PHILIPS_FM1236_MK3:
 	case TUNER_PHILIPS_FMD1216ME_MK3:
@@ -702,7 +702,8 @@
 		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
 	/* Bandswitch byte */
-	simple_radio_bandswitch(fe, &buffer[0]);
+	if (simple_radio_bandswitch(fe, &buffer[0]))
+		return 0;
 
 	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
 	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
--- linux-ein-5.4.0.orig/drivers/media/tuners/xc4000.c
+++ linux-ein-5.4.0/drivers/media/tuners/xc4000.c
@@ -1744,7 +1744,7 @@
 	xc4000_release(fe);
 	return NULL;
 }
-EXPORT_SYMBOL(xc4000_attach);
+EXPORT_SYMBOL_GPL(xc4000_attach);
 
 MODULE_AUTHOR("Steven Toth, Davide Ferri");
 MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/tuners/xc5000.c
+++ linux-ein-5.4.0/drivers/media/tuners/xc5000.c
@@ -1460,7 +1460,7 @@
 	xc5000_release(fe);
 	return NULL;
 }
-EXPORT_SYMBOL(xc5000_attach);
+EXPORT_SYMBOL_GPL(xc5000_attach);
 
 MODULE_AUTHOR("Steven Toth");
 MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
--- linux-ein-5.4.0.orig/drivers/media/usb/au0828/au0828-core.c
+++ linux-ein-5.4.0/drivers/media/usb/au0828/au0828-core.c
@@ -199,8 +199,8 @@
 	struct media_device *mdev;
 
 	mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
-	if (!mdev)
-		return -ENOMEM;
+	if (IS_ERR(mdev))
+		return PTR_ERR(mdev);
 
 	dev->media_dev = mdev;
 #endif
--- linux-ein-5.4.0.orig/drivers/media/usb/b2c2/flexcop-usb.c
+++ linux-ein-5.4.0/drivers/media/usb/b2c2/flexcop-usb.c
@@ -87,7 +87,7 @@
 			0,
 			fc_usb->data,
 			sizeof(u32),
-			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+			B2C2_WAIT_FOR_OPERATION_RDW);
 
 	if (ret != sizeof(u32)) {
 		err("error while %s dword from %d (%d).", read ? "reading" :
@@ -155,7 +155,7 @@
 			wIndex,
 			fc_usb->data,
 			buflen,
-			nWaitTime * HZ);
+			nWaitTime);
 	if (ret != buflen)
 		ret = -EIO;
 
@@ -249,13 +249,13 @@
 		/* DKT 020208 - add this to support special case of DiSEqC */
 	case USB_FUNC_I2C_CHECKWRITE:
 		pipe = B2C2_USB_CTRL_PIPE_OUT;
-		nWaitTime = 2;
+		nWaitTime = 2000;
 		request_type |= USB_DIR_OUT;
 		break;
 	case USB_FUNC_I2C_READ:
 	case USB_FUNC_I2C_REPEATREAD:
 		pipe = B2C2_USB_CTRL_PIPE_IN;
-		nWaitTime = 2;
+		nWaitTime = 2000;
 		request_type |= USB_DIR_IN;
 		break;
 	default:
@@ -282,7 +282,7 @@
 			wIndex,
 			fc_usb->data,
 			buflen,
-			nWaitTime * HZ);
+			nWaitTime);
 
 	if (ret != buflen)
 		ret = -EIO;
@@ -295,7 +295,7 @@
 
 	mutex_unlock(&fc_usb->data_mutex);
 
-	return 0;
+	return ret;
 }
 
 /* actual bus specific access functions,
@@ -504,7 +504,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-ein-5.4.0.orig/drivers/media/usb/b2c2/flexcop-usb.h
+++ linux-ein-5.4.0/drivers/media/usb/b2c2/flexcop-usb.h
@@ -91,13 +91,13 @@
 	UTILITY_SRAM_TESTVERIFY     = 0x16,
 } flexcop_usb_utility_function_t;
 
-#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ)
-#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ)
+#define B2C2_WAIT_FOR_OPERATION_RW 1000
+#define B2C2_WAIT_FOR_OPERATION_RDW 3000
+#define B2C2_WAIT_FOR_OPERATION_WDW 1000
 
-#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ)
-#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ)
+#define B2C2_WAIT_FOR_OPERATION_V8READ 3000
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3000
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3000
 
 typedef enum {
 	V8_MEMORY_PAGE_DVB_CI = 0x20,
--- linux-ein-5.4.0.orig/drivers/media/usb/cpia2/cpia2.h
+++ linux-ein-5.4.0/drivers/media/usb/cpia2/cpia2.h
@@ -429,6 +429,7 @@
 int cpia2_do_command(struct camera_data *cam,
 		     unsigned int command,
 		     unsigned char direction, unsigned char param);
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf);
 struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
 int cpia2_init_camera(struct camera_data *cam);
 int cpia2_allocate_buffers(struct camera_data *cam);
--- linux-ein-5.4.0.orig/drivers/media/usb/cpia2/cpia2_core.c
+++ linux-ein-5.4.0/drivers/media/usb/cpia2/cpia2_core.c
@@ -2167,6 +2167,18 @@
  *
  *  cpia2_init_camera_struct
  *
+ *  Deinitialize camera struct
+ *****************************************************************************/
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf)
+{
+	v4l2_device_unregister(&cam->v4l2_dev);
+	kfree(cam);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera_struct
+ *
  *  Initializes camera struct, does not call reset to fill in defaults.
  *****************************************************************************/
 struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
--- linux-ein-5.4.0.orig/drivers/media/usb/cpia2/cpia2_usb.c
+++ linux-ein-5.4.0/drivers/media/usb/cpia2/cpia2_usb.c
@@ -550,7 +550,7 @@
 			       0,	/* index */
 			       buf,	/* buffer */
 			       size,
-			       HZ);
+			       1000);
 
 	kfree(buf);
 	return ret;
@@ -582,7 +582,7 @@
 			       0,	/* index */
 			       buf,	/* buffer */
 			       size,
-			       HZ);
+			       1000);
 
 	if (ret >= 0)
 		memcpy(registers, buf, size);
@@ -844,15 +844,13 @@
 	ret = set_alternate(cam, USBIF_CMDONLY);
 	if (ret < 0) {
 		ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
-		kfree(cam);
-		return ret;
+		goto alt_err;
 	}
 
 
 	if((ret = cpia2_init_camera(cam)) < 0) {
 		ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
-		kfree(cam);
-		return ret;
+		goto alt_err;
 	}
 	LOG("  CPiA Version: %d.%02d (%d.%d)\n",
 	       cam->params.version.firmware_revision_hi,
@@ -872,11 +870,14 @@
 	ret = cpia2_register_camera(cam);
 	if (ret < 0) {
 		ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
-		kfree(cam);
-		return ret;
+		goto alt_err;
 	}
 
 	return 0;
+
+alt_err:
+	cpia2_deinit_camera_struct(cam, intf);
+	return ret;
 }
 
 /******************************************************************************
--- linux-ein-5.4.0.orig/drivers/media/usb/cx231xx/cx231xx-core.c
+++ linux-ein-5.4.0/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1028,6 +1028,7 @@
 	if (!dev->video_mode.isoc_ctl.urb) {
 		dev_err(dev->dev,
 			"cannot alloc memory for usb buffers\n");
+		kfree(dma_q->p_left_data);
 		return -ENOMEM;
 	}
 
@@ -1037,6 +1038,7 @@
 		dev_err(dev->dev,
 			"cannot allocate memory for usbtransfer\n");
 		kfree(dev->video_mode.isoc_ctl.urb);
+		kfree(dma_q->p_left_data);
 		return -ENOMEM;
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/af9035.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -269,6 +269,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	struct state *state = d_to_priv(d);
 	int ret;
+	u32 reg;
 
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
@@ -321,8 +322,12 @@
 			ret = -EOPNOTSUPP;
 		} else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
 			   (msg[0].addr == state->af9033_i2c_addr[1])) {
+			if (msg[0].len < 3 || msg[1].len < 1) {
+				ret = -EOPNOTSUPP;
+				goto unlock;
+			}
 			/* demod access via firmware interface */
-			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+			reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
 					msg[0].buf[2];
 
 			if (msg[0].addr == state->af9033_i2c_addr[1])
@@ -380,17 +385,18 @@
 			ret = -EOPNOTSUPP;
 		} else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
 			   (msg[0].addr == state->af9033_i2c_addr[1])) {
+			if (msg[0].len < 3) {
+				ret = -EOPNOTSUPP;
+				goto unlock;
+			}
 			/* demod access via firmware interface */
-			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+			reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
 					msg[0].buf[2];
 
 			if (msg[0].addr == state->af9033_i2c_addr[1])
 				reg |= 0x100000;
 
-			ret = (msg[0].len >= 3) ? af9035_wr_regs(d, reg,
-							         &msg[0].buf[3],
-							         msg[0].len - 3)
-					        : -EOPNOTSUPP;
+			ret = af9035_wr_regs(d, reg, &msg[0].buf[3], msg[0].len - 3);
 		} else {
 			/* I2C write */
 			u8 buf[MAX_XFER_SIZE];
@@ -457,6 +463,7 @@
 		ret = -EOPNOTSUPP;
 	}
 
+unlock:
 	mutex_unlock(&d->i2c_mutex);
 
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/anysee.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -202,7 +202,7 @@
 
 	while (i < num) {
 		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-			if (msg[i].len > 2 || msg[i+1].len > 60) {
+			if (msg[i].len != 2 || msg[i + 1].len > 60) {
 				ret = -EOPNOTSUPP;
 				break;
 			}
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/az6007.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -202,7 +202,8 @@
 	unsigned code;
 	enum rc_proto proto;
 
-	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
+	if (az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10) < 0)
+		return -EIO;
 
 	if (st->data[1] == 0x44)
 		return 0;
@@ -787,6 +788,10 @@
 			if (az6007_xfer_debug)
 				printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
 				       addr, msgs[i].len);
+			if (msgs[i].len < 1) {
+				ret = -EIO;
+				goto err;
+			}
 			req = AZ6007_I2C_WR;
 			index = msgs[i].buf[0];
 			value = addr | (1 << 8);
@@ -801,6 +806,10 @@
 			if (az6007_xfer_debug)
 				printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
 				       addr, msgs[i].len);
+			if (msgs[i].len < 1) {
+				ret = -EIO;
+				goto err;
+			}
 			req = AZ6007_I2C_RD;
 			index = msgs[i].buf[0];
 			value = addr;
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/ce6230.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/ce6230.c
@@ -101,6 +101,10 @@
 		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
 			if (msg[i].addr ==
 				ce6230_zl10353_config.demod_address) {
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				req.cmd = DEMOD_READ;
 				req.value = msg[i].addr >> 1;
 				req.index = msg[i].buf[0];
@@ -117,6 +121,10 @@
 		} else {
 			if (msg[i].addr ==
 				ce6230_zl10353_config.demod_address) {
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				req.cmd = DEMOD_WRITE;
 				req.value = msg[i].addr >> 1;
 				req.index = msg[i].buf[0];
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -792,6 +792,9 @@
 	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C,
 		&mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C",
 		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
+	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE,
+		&mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C Lite",
+		NULL) },
 	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2,
 		&mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C v2",
 		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/ec168.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/ec168.c
@@ -115,6 +115,10 @@
 	while (i < num) {
 		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
 			if (msg[i].addr == ec168_ec100_config.demod_address) {
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				req.cmd = READ_DEMOD;
 				req.value = 0;
 				req.index = 0xff00 + msg[i].buf[0]; /* reg */
@@ -131,6 +135,10 @@
 			}
 		} else {
 			if (msg[i].addr == ec168_ec100_config.demod_address) {
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				req.cmd = WRITE_DEMOD;
 				req.value = msg[i].buf[1]; /* val */
 				req.index = 0xff00 + msg[i].buf[0]; /* reg */
@@ -139,6 +147,10 @@
 				ret = ec168_ctrl_msg(d, &req);
 				i += 1;
 			} else {
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				req.cmd = WRITE_I2C;
 				req.value = msg[i].buf[0]; /* val */
 				req.index = 0x0100 + msg[i].addr; /* I2C addr */
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -391,7 +391,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);
 
 	usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
 	info("INT Interrupt Service Started");
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -931,8 +931,6 @@
 		  .len = sizeof(eeprom), .buf = eeprom },
 	};
 
-	mutex_init(&state->msg_lock);
-
 	ret = get_chip_info(state);
 	if (mxl_fail(ret))
 		pr_err("failed to get chip info during probe");
@@ -1074,6 +1072,14 @@
 	return 0;
 }
 
+static int mxl111sf_probe(struct dvb_usb_device *dev)
+{
+	struct mxl111sf_state *state = d_to_priv(dev);
+
+	mutex_init(&state->msg_lock);
+	return 0;
+}
+
 static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
 	.driver_name = KBUILD_MODNAME,
 	.owner = THIS_MODULE,
@@ -1083,6 +1089,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_dvbt,
 	.tuner_attach      = mxl111sf_attach_tuner,
@@ -1124,6 +1131,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_atsc,
 	.tuner_attach      = mxl111sf_attach_tuner,
@@ -1165,6 +1173,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_mh,
 	.tuner_attach      = mxl111sf_attach_tuner,
@@ -1233,6 +1242,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_atsc_mh,
 	.tuner_attach      = mxl111sf_attach_tuner,
@@ -1311,6 +1321,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_mercury,
 	.tuner_attach      = mxl111sf_attach_tuner,
@@ -1381,6 +1392,7 @@
 	.generic_bulk_ctrl_endpoint = 0x02,
 	.generic_bulk_ctrl_endpoint_response = 0x81,
 
+	.probe             = mxl111sf_probe,
 	.i2c_algo          = &mxl111sf_i2c_algo,
 	.frontend_attach   = mxl111sf_frontend_attach_mercury_mh,
 	.tuner_attach      = mxl111sf_attach_tuner,
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -37,7 +37,16 @@
 	} else {
 		/* read */
 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-		pipe = usb_rcvctrlpipe(d->udev, 0);
+
+		/*
+		 * Zero-length transfers must use usb_sndctrlpipe() and
+		 * rtl28xxu_identify_state() uses a zero-length i2c read
+		 * command to determine the chip type.
+		 */
+		if (req->size)
+			pipe = usb_rcvctrlpipe(d->udev, 0);
+		else
+			pipe = usb_sndctrlpipe(d->udev, 0);
 	}
 
 	ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
@@ -167,6 +176,10 @@
 			ret = -EOPNOTSUPP;
 			goto err_mutex_unlock;
 		} else if (msg[0].addr == 0x10) {
+			if (msg[0].len < 1 || msg[1].len < 1) {
+				ret = -EOPNOTSUPP;
+				goto err_mutex_unlock;
+			}
 			/* method 1 - integrated demod */
 			if (msg[0].buf[0] == 0x00) {
 				/* return demod page from driver cache */
@@ -180,6 +193,10 @@
 				ret = rtl28xxu_ctrl_msg(d, &req);
 			}
 		} else if (msg[0].len < 2) {
+			if (msg[0].len < 1) {
+				ret = -EOPNOTSUPP;
+				goto err_mutex_unlock;
+			}
 			/* method 2 - old I2C */
 			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
 			req.index = CMD_I2C_RD;
@@ -208,8 +225,16 @@
 			ret = -EOPNOTSUPP;
 			goto err_mutex_unlock;
 		} else if (msg[0].addr == 0x10) {
+			if (msg[0].len < 1) {
+				ret = -EOPNOTSUPP;
+				goto err_mutex_unlock;
+			}
 			/* method 1 - integrated demod */
 			if (msg[0].buf[0] == 0x00) {
+				if (msg[0].len < 2) {
+					ret = -EOPNOTSUPP;
+					goto err_mutex_unlock;
+				}
 				/* save demod page for later demod access */
 				dev->page = msg[0].buf[1];
 				ret = 0;
@@ -222,6 +247,10 @@
 				ret = rtl28xxu_ctrl_msg(d, &req);
 			}
 		} else if ((msg[0].len < 23) && (!dev->new_i2c_write)) {
+			if (msg[0].len < 1) {
+				ret = -EOPNOTSUPP;
+				goto err_mutex_unlock;
+			}
 			/* method 2 - old I2C */
 			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
 			req.index = CMD_I2C_WR;
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/Kconfig
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/Kconfig
@@ -150,6 +150,7 @@
 config DVB_USB_CXUSB_ANALOG
 	bool "Analog support for the Conexant USB2.0 hybrid reference design"
 	depends on DVB_USB_CXUSB && VIDEO_V4L2
+	depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_USB_CXUSB
 	select VIDEO_CX25840
 	select VIDEOBUF2_VMALLOC
 	help
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/af9005.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/af9005.c
@@ -422,6 +422,10 @@
 		if (ret == 0)
 			ret = 2;
 	} else {
+		if (msg[0].len < 2) {
+			ret = -EOPNOTSUPP;
+			goto unlock;
+		}
 		/* write one or more registers */
 		reg = msg[0].buf[0];
 		addr = msg[0].addr;
@@ -431,6 +435,7 @@
 			ret = 1;
 	}
 
+unlock:
 	mutex_unlock(&d->i2c_mutex);
 	return ret;
 }
@@ -554,7 +559,7 @@
 			      u8 *buf, int size)
 {
 	u16 checksum;
-	int act_len, i, ret;
+	int act_len = 0, i, ret;
 
 	memset(buf, 0, size);
 	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
@@ -976,8 +981,9 @@
 	else if (reply == 0x02)
 		*cold = 0;
 	else
-		return -EIO;
-	deb_info("Identify state cold = %d\n", *cold);
+		ret = -EIO;
+	if (!ret)
+		deb_info("Identify state cold = %d\n", *cold);
 
 err:
 	kfree(buf);
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/az6027.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/az6027.c
@@ -391,6 +391,7 @@
 /* remote control stuff (does not work with my box) */
 static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
+	*state = REMOTE_NO_KEY_PRESSED;
 	return 0;
 }
 
@@ -974,6 +975,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);
@@ -983,6 +988,10 @@
 			/* write/read request */
 			if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
 				req = 0xB9;
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
 				value = msg[i].addr + (msg[i].len << 8);
 				length = msg[i + 1].len + 6;
@@ -996,6 +1005,10 @@
 
 				/* demod 16bit addr */
 				req = 0xBD;
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
 				value = msg[i].addr + (2 << 8);
 				length = msg[i].len - 2;
@@ -1021,6 +1034,10 @@
 			} else {
 
 				req = 0xBD;
+				if (msg[i].len < 1) {
+					i = -EOPNOTSUPP;
+					break;
+				}
 				index = msg[i].buf[0] & 0x00FF;
 				value = msg[i].addr + (1 << 8);
 				length = msg[i].len - 1;
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/cinergyT2-core.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/cinergyT2-core.c
@@ -78,6 +78,8 @@
 
 	ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 3, 0);
 	if (ret < 0) {
+		if (adap->fe_adap[0].fe)
+			adap->fe_adap[0].fe->ops.release(adap->fe_adap[0].fe);
 		deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep state info\n");
 	}
 	mutex_unlock(&d->data_mutex);
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/cxusb.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/cxusb.c
@@ -521,7 +521,8 @@
 {
 	u8 ircode[4];
 
-	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;
 
 	if (ircode[2] || ircode[3])
 		rc_keydown(d->rc_dev, RC_PROTO_NEC,
@@ -1949,7 +1950,7 @@
 
 	.size_of_priv     = sizeof(struct cxusb_state),
 
-	.num_adapters = 2,
+	.num_adapters = 1,
 	.adapter = {
 		{
 		.num_frontends = 1,
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dib0700_core.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -616,8 +616,6 @@
 		deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
 		if (onoff)
 			st->channel_state |=	1 << (adap->id);
-		else
-			st->channel_state |=	1 << ~(adap->id);
 	} else {
 		if (onoff)
 			st->channel_state |=	1 << (adap->fe_adap[0].stream.props.endpoint-2);
@@ -818,7 +816,7 @@
 
 	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
 
-	if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1)
+	if (intf->cur_altsetting->desc.bNumEndpoints < rc_ep + 1)
 		return -ENODEV;
 
 	purb = usb_alloc_urb(0, GFP_KERNEL);
@@ -838,7 +836,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-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dibusb-common.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -223,7 +223,7 @@
 	u8 *buf;
 	int rc;
 
-	buf = kmalloc(2, GFP_KERNEL);
+	buf = kzalloc(2, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dibusb-mb.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -81,7 +81,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-ein-5.4.0.orig/drivers/media/usb/dvb-usb/digitv.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/digitv.c
@@ -63,6 +63,10 @@
 		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
 
 	for (i = 0; i < num; i++) {
+		if (msg[i].len < 1) {
+			i = -EOPNOTSUPP;
+			break;
+		}
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
 			if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
@@ -230,18 +234,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-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dtv5100.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dtv5100.c
@@ -26,6 +26,7 @@
 			   u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
 	struct dtv5100_state *st = d->priv;
+	unsigned int pipe;
 	u8 request;
 	u8 type;
 	u16 value;
@@ -34,6 +35,7 @@
 	switch (wlen) {
 	case 1:
 		/* write { reg }, read { value } */
+		pipe = usb_rcvctrlpipe(d->udev, 0);
 		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
 							DTV5100_TUNER_READ);
 		type = USB_TYPE_VENDOR | USB_DIR_IN;
@@ -41,6 +43,7 @@
 		break;
 	case 2:
 		/* write { reg, value } */
+		pipe = usb_sndctrlpipe(d->udev, 0);
 		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
 							DTV5100_TUNER_WRITE);
 		type = USB_TYPE_VENDOR | USB_DIR_OUT;
@@ -54,7 +57,7 @@
 
 	memcpy(st->data, rbuf, rlen);
 	msleep(1); /* avoid I2C errors */
-	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+	return usb_control_msg(d->udev, pipe, request,
 			       type, value, index, st->data, rlen,
 			       DTV5100_USB_TIMEOUT);
 }
@@ -141,7 +144,7 @@
 
 	/* initialize non qt1010/zl10353 part? */
 	for (i = 0; dtv5100_init[i].request; i++) {
-		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 				      dtv5100_init[i].request,
 				      USB_TYPE_VENDOR | USB_DIR_OUT,
 				      dtv5100_init[i].value,
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
@@ -17,7 +17,8 @@
 
 	if (d->props.i2c_algo == NULL) {
 		err("no i2c algorithm specified");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
@@ -27,11 +28,15 @@
 
 	i2c_set_adapdata(&d->i2c_adap, d);
 
-	if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
+	ret = i2c_add_adapter(&d->i2c_adap);
+	if (ret < 0) {
 		err("could not add i2c adapter");
+		goto err;
+	}
 
 	d->state |= DVB_USB_STATE_I2C;
 
+err:
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -79,11 +79,17 @@
 			}
 		}
 
-		if ((ret = dvb_usb_adapter_stream_init(adap)) ||
-			(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
-			(ret = dvb_usb_adapter_frontend_init(adap))) {
-			return ret;
-		}
+		ret = dvb_usb_adapter_stream_init(adap);
+		if (ret)
+			goto stream_init_err;
+
+		ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs);
+		if (ret)
+			goto dvb_init_err;
+
+		ret = dvb_usb_adapter_frontend_init(adap);
+		if (ret)
+			goto frontend_init_err;
 
 		/* use exclusive FE lock if there is multiple shared FEs */
 		if (adap->fe_adap[1].fe)
@@ -103,6 +109,14 @@
 	}
 
 	return 0;
+
+frontend_init_err:
+	dvb_usb_adapter_dvb_exit(adap);
+dvb_init_err:
+	dvb_usb_adapter_stream_exit(adap);
+stream_init_err:
+	kfree(adap->priv);
+	return ret;
 }
 
 static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
@@ -158,22 +172,20 @@
 
 		if (d->props.priv_init != NULL) {
 			ret = d->props.priv_init(d);
-			if (ret != 0) {
-				kfree(d->priv);
-				d->priv = NULL;
-				return ret;
-			}
+			if (ret != 0)
+				goto err_priv_init;
 		}
 	}
 
 	/* check the capabilities and set appropriate variables */
 	dvb_usb_device_power_ctrl(d, 1);
 
-	if ((ret = dvb_usb_i2c_init(d)) ||
-		(ret = dvb_usb_adapter_init(d, adapter_nums))) {
-		dvb_usb_exit(d);
-		return ret;
-	}
+	ret = dvb_usb_i2c_init(d);
+	if (ret)
+		goto err_i2c_init;
+	ret = dvb_usb_adapter_init(d, adapter_nums);
+	if (ret)
+		goto err_adapter_init;
 
 	if ((ret = dvb_usb_remote_init(d)))
 		err("could not initialize remote control.");
@@ -181,6 +193,17 @@
 	dvb_usb_device_power_ctrl(d, 0);
 
 	return 0;
+
+err_adapter_init:
+	dvb_usb_adapter_exit(d);
+	dvb_usb_i2c_exit(d);
+err_i2c_init:
+	if (d->priv && d->props.priv_destroy)
+		d->props.priv_destroy(d);
+err_priv_init:
+	kfree(d->priv);
+	d->priv = NULL;
+	return ret;
 }
 
 /* determine the name and the state of the just found USB device */
@@ -255,41 +278,50 @@
 	if (du != NULL)
 		*du = NULL;
 
-	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d) {
+		err("no memory for 'struct dvb_usb_device'");
+		return -ENOMEM;
+	}
+
+	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
+
+	desc = dvb_usb_find_device(udev, &d->props, &cold);
+	if (!desc) {
 		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto error;
 	}
 
 	if (cold) {
 		info("found a '%s' in cold state, will try to load a firmware", desc->name);
 		ret = dvb_usb_download_firmware(udev, props);
 		if (!props->no_reconnect || ret != 0)
-			return ret;
+			goto error;
 	}
 
 	info("found a '%s' in warm state.", desc->name);
-	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
-	if (d == NULL) {
-		err("no memory for 'struct dvb_usb_device'");
-		return -ENOMEM;
-	}
-
 	d->udev = udev;
-	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
 	d->desc = desc;
 	d->owner = owner;
 
 	usb_set_intfdata(intf, d);
 
-	if (du != NULL)
+	ret = dvb_usb_init(d, adapter_nums);
+	if (ret) {
+		info("%s error while loading driver (%d)", desc->name, ret);
+		goto error;
+	}
+
+	if (du)
 		*du = d;
 
-	ret = dvb_usb_init(d, adapter_nums);
+	info("%s successfully initialized and connected.", desc->name);
+	return 0;
 
-	if (ret == 0)
-		info("%s successfully initialized and connected.", desc->name);
-	else
-		info("%s error while loading driver (%d)", desc->name, ret);
+ error:
+	usb_set_intfdata(intf, NULL);
+	kfree(d);
 	return ret;
 }
 EXPORT_SYMBOL(dvb_usb_device_init);
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb-urb.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dvb-usb-urb.c
@@ -12,7 +12,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-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dvb-usb.h
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -485,7 +485,7 @@
 dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
 
 /* commonly used remote control parsing */
-extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[5], u32 *, int *);
 
 /* commonly used firmware download types and function */
 struct hexline {
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/dw2102.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/dw2102.c
@@ -128,6 +128,10 @@
 
 	switch (num) {
 	case 2:
+		if (msg[0].len < 1) {
+			num = -EOPNOTSUPP;
+			break;
+		}
 		/* read stv0299 register */
 		value = msg[0].buf[0];/* register */
 		for (i = 0; i < msg[1].len; i++) {
@@ -139,6 +143,10 @@
 	case 1:
 		switch (msg[0].addr) {
 		case 0x68:
+			if (msg[0].len < 2) {
+				num = -EOPNOTSUPP;
+				break;
+			}
 			/* write to stv0299 register */
 			buf6[0] = 0x2a;
 			buf6[1] = msg[0].buf[0];
@@ -148,6 +156,10 @@
 			break;
 		case 0x60:
 			if (msg[0].flags == 0) {
+				if (msg[0].len < 4) {
+					num = -EOPNOTSUPP;
+					break;
+				}
 			/* write to tuner pll */
 				buf6[0] = 0x2c;
 				buf6[1] = 5;
@@ -159,6 +171,10 @@
 				dw210x_op_rw(d->udev, 0xb2, 0, 0,
 						buf6, 7, DW210X_WRITE_MSG);
 			} else {
+				if (msg[0].len < 1) {
+					num = -EOPNOTSUPP;
+					break;
+				}
 			/* read from tuner */
 				dw210x_op_rw(d->udev, 0xb5, 0, 0,
 						buf6, 1, DW210X_READ_MSG);
@@ -166,12 +182,20 @@
 			}
 			break;
 		case (DW2102_RC_QUERY):
+			if (msg[0].len < 2) {
+				num = -EOPNOTSUPP;
+				break;
+			}
 			dw210x_op_rw(d->udev, 0xb8, 0, 0,
 					buf6, 2, DW210X_READ_MSG);
 			msg[0].buf[0] = buf6[0];
 			msg[0].buf[1] = buf6[1];
 			break;
 		case (DW2102_VOLTAGE_CTRL):
+			if (msg[0].len < 1) {
+				num = -EOPNOTSUPP;
+				break;
+			}
 			buf6[0] = 0x30;
 			buf6[1] = msg[0].buf[0];
 			dw210x_op_rw(d->udev, 0xb2, 0, 0,
@@ -946,7 +970,7 @@
 	for (i = 0; i < 6; i++) {
 		obuf[1] = 0xf0 + i;
 		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
-			break;
+			return -1;
 		else
 			mac[i] = ibuf[0];
 	}
@@ -2098,46 +2122,153 @@
 	}
 };
 
-static const struct dvb_usb_device_description d1100 = {
-	"Prof 1100 USB ",
-	{&dw2102_table[PROF_1100], NULL},
-	{NULL},
-};
+static struct dvb_usb_device_properties p1100_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct dw2102_state),
+	.firmware = P1100_FIRMWARE,
+	.no_reconnect = 1,
 
-static const struct dvb_usb_device_description d660 = {
-	"TeVii S660 USB",
-	{&dw2102_table[TEVII_S660], NULL},
-	{NULL},
-};
+	.i2c_algo = &s6x0_i2c_algo,
+	.rc.core = {
+		.rc_interval = 150,
+		.rc_codes = RC_MAP_TBS_NEC,
+		.module_name = "dw2102",
+		.allowed_protos   = RC_PROTO_BIT_NEC,
+		.rc_query = prof_rc_query,
+	},
 
-static const struct dvb_usb_device_description d480_1 = {
-	"TeVii S480.1 USB",
-	{&dw2102_table[TEVII_S480_1], NULL},
-	{NULL},
+	.generic_bulk_ctrl_endpoint = 0x81,
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = s6x0_read_mac_address,
+	.adapter = {
+		{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach = stv0288_frontend_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 8,
+					.endpoint = 0x82,
+					.u = {
+						.bulk = {
+							.buffersize = 4096,
+						}
+					}
+				},
+			} },
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{"Prof 1100 USB ",
+			{&dw2102_table[PROF_1100], NULL},
+			{NULL},
+		},
+	}
 };
 
-static const struct dvb_usb_device_description d480_2 = {
-	"TeVii S480.2 USB",
-	{&dw2102_table[TEVII_S480_2], NULL},
-	{NULL},
-};
+static struct dvb_usb_device_properties s660_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct dw2102_state),
+	.firmware = S660_FIRMWARE,
+	.no_reconnect = 1,
 
-static const struct dvb_usb_device_description d7500 = {
-	"Prof 7500 USB DVB-S2",
-	{&dw2102_table[PROF_7500], NULL},
-	{NULL},
-};
+	.i2c_algo = &s6x0_i2c_algo,
+	.rc.core = {
+		.rc_interval = 150,
+		.rc_codes = RC_MAP_TEVII_NEC,
+		.module_name = "dw2102",
+		.allowed_protos   = RC_PROTO_BIT_NEC,
+		.rc_query = dw2102_rc_query,
+	},
 
-static const struct dvb_usb_device_description d421 = {
-	"TeVii S421 PCI",
-	{&dw2102_table[TEVII_S421], NULL},
-	{NULL},
+	.generic_bulk_ctrl_endpoint = 0x81,
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = s6x0_read_mac_address,
+	.adapter = {
+		{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach = ds3000_frontend_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 8,
+					.endpoint = 0x82,
+					.u = {
+						.bulk = {
+							.buffersize = 4096,
+						}
+					}
+				},
+			} },
+		}
+	},
+	.num_device_descs = 3,
+	.devices = {
+		{"TeVii S660 USB",
+			{&dw2102_table[TEVII_S660], NULL},
+			{NULL},
+		},
+		{"TeVii S480.1 USB",
+			{&dw2102_table[TEVII_S480_1], NULL},
+			{NULL},
+		},
+		{"TeVii S480.2 USB",
+			{&dw2102_table[TEVII_S480_2], NULL},
+			{NULL},
+		},
+	}
 };
 
-static const struct dvb_usb_device_description d632 = {
-	"TeVii S632 USB",
-	{&dw2102_table[TEVII_S632], NULL},
-	{NULL},
+static struct dvb_usb_device_properties p7500_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct dw2102_state),
+	.firmware = P7500_FIRMWARE,
+	.no_reconnect = 1,
+
+	.i2c_algo = &s6x0_i2c_algo,
+	.rc.core = {
+		.rc_interval = 150,
+		.rc_codes = RC_MAP_TBS_NEC,
+		.module_name = "dw2102",
+		.allowed_protos   = RC_PROTO_BIT_NEC,
+		.rc_query = prof_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = s6x0_read_mac_address,
+	.adapter = {
+		{
+			.num_frontends = 1,
+			.fe = {{
+				.frontend_attach = prof_7500_frontend_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 8,
+					.endpoint = 0x82,
+					.u = {
+						.bulk = {
+							.buffersize = 4096,
+						}
+					}
+				},
+			} },
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{"Prof 7500 USB DVB-S2",
+			{&dw2102_table[PROF_7500], NULL},
+			{NULL},
+		},
+	}
 };
 
 static struct dvb_usb_device_properties su3000_properties = {
@@ -2209,6 +2340,59 @@
 	}
 };
 
+static struct dvb_usb_device_properties s421_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct dw2102_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.core = {
+		.rc_interval = 150,
+		.rc_codes = RC_MAP_SU3000,
+		.module_name = "dw2102",
+		.allowed_protos   = RC_PROTO_BIT_RC5,
+		.rc_query = su3000_rc_query,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = m88rs2000_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		} },
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "TeVii S421 PCI",
+			{ &dw2102_table[TEVII_S421], NULL },
+			{ NULL },
+		},
+		{ "TeVii S632 USB",
+			{ &dw2102_table[TEVII_S632], NULL },
+			{ NULL },
+		},
+	}
+};
+
 static struct dvb_usb_device_properties t220_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.usb_ctrl = DEVICE_SPECIFIC,
@@ -2326,101 +2510,33 @@
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	int retval = -ENOMEM;
-	struct dvb_usb_device_properties *p1100;
-	struct dvb_usb_device_properties *s660;
-	struct dvb_usb_device_properties *p7500;
-	struct dvb_usb_device_properties *s421;
-
-	p1100 = kmemdup(&s6x0_properties,
-			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!p1100)
-		goto err0;
-
-	/* copy default structure */
-	/* fill only different fields */
-	p1100->firmware = P1100_FIRMWARE;
-	p1100->devices[0] = d1100;
-	p1100->rc.core.rc_query = prof_rc_query;
-	p1100->rc.core.rc_codes = RC_MAP_TBS_NEC;
-	p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
-
-	s660 = kmemdup(&s6x0_properties,
-		       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!s660)
-		goto err1;
-
-	s660->firmware = S660_FIRMWARE;
-	s660->num_device_descs = 3;
-	s660->devices[0] = d660;
-	s660->devices[1] = d480_1;
-	s660->devices[2] = d480_2;
-	s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
-
-	p7500 = kmemdup(&s6x0_properties,
-			sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!p7500)
-		goto err2;
-
-	p7500->firmware = P7500_FIRMWARE;
-	p7500->devices[0] = d7500;
-	p7500->rc.core.rc_query = prof_rc_query;
-	p7500->rc.core.rc_codes = RC_MAP_TBS_NEC;
-	p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
-
-
-	s421 = kmemdup(&su3000_properties,
-		       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-	if (!s421)
-		goto err3;
-
-	s421->num_device_descs = 2;
-	s421->devices[0] = d421;
-	s421->devices[1] = d632;
-	s421->adapter->fe[0].frontend_attach = m88rs2000_frontend_attach;
-
-	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw2104_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw3101_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &s6x0_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p1100,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, s660,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p7500,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, s421,
-			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &su3000_properties,
-			 THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &t220_properties,
-			 THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &tt_s2_4600_properties,
-			 THIS_MODULE, NULL, adapter_nr)) {
-
-		/* clean up copied properties */
-		kfree(s421);
-		kfree(p7500);
-		kfree(s660);
-		kfree(p1100);
+	if (!(dvb_usb_device_init(intf, &dw2102_properties,
+			          THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &dw2104_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &dw3101_properties,
+			          THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &s6x0_properties,
+			          THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &p1100_properties,
+			          THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &s660_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &p7500_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &s421_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &su3000_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &t220_properties,
+				  THIS_MODULE, NULL, adapter_nr) &&
+	      dvb_usb_device_init(intf, &tt_s2_4600_properties,
+				  THIS_MODULE, NULL, adapter_nr))) {
 
 		return 0;
 	}
 
-	retval = -ENODEV;
-	kfree(s421);
-err3:
-	kfree(p7500);
-err2:
-	kfree(s660);
-err1:
-	kfree(p1100);
-err0:
-	return retval;
+	return -ENODEV;
 }
 
 static void dw2102_disconnect(struct usb_interface *intf)
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/gp8psk.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/gp8psk.c
@@ -182,7 +182,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-ein-5.4.0.orig/drivers/media/usb/dvb-usb/m920x.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/m920x.c
@@ -274,6 +274,12 @@
 			/* Should check for ack here, if we knew how. */
 		}
 		if (msg[i].flags & I2C_M_RD) {
+			char *read = kmalloc(1, GFP_KERNEL);
+			if (!read) {
+				ret = -ENOMEM;
+				goto unlock;
+			}
+
 			for (j = 0; j < msg[i].len; j++) {
 				/* Last byte of transaction?
 				 * Send STOP, otherwise send ACK. */
@@ -281,9 +287,14 @@
 
 				if ((ret = m920x_read(d->udev, M9206_I2C, 0x0,
 						      0x20 | stop,
-						      &msg[i].buf[j], 1)) != 0)
+						      read, 1)) != 0) {
+					kfree(read);
 					goto unlock;
+				}
+				msg[i].buf[j] = read[0];
 			}
+
+			kfree(read);
 		} else {
 			for (j = 0; j < msg[i].len; j++) {
 				/* Last byte of transaction? Then send STOP. */
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/nova-t-usb2.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/nova-t-usb2.c
@@ -130,7 +130,7 @@
 
 static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
 {
-	int i;
+	int i, ret;
 	u8 b;
 
 	mac[0] = 0x00;
@@ -139,7 +139,9 @@
 
 	/* this is a complete guess, but works for my box */
 	for (i = 136; i < 139; i++) {
-		dibusb_read_eeprom_byte(d,i, &b);
+		ret = dibusb_read_eeprom_byte(d, i, &b);
+		if (ret)
+			return ret;
 
 		mac[5 - (i - 136)] = b;
 	}
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/vp702x.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/vp702x.c
@@ -291,16 +291,22 @@
 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 {
 	u8 i, *buf;
+	int ret;
 	struct vp702x_device_state *st = d->priv;
 
 	mutex_lock(&st->buf_mutex);
 	buf = st->buf;
-	for (i = 6; i < 12; i++)
-		vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
+	for (i = 6; i < 12; i++) {
+		ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1,
+				       &buf[i - 6], 1);
+		if (ret < 0)
+			goto err;
+	}
 
 	memcpy(mac, buf, 6);
+err:
 	mutex_unlock(&st->buf_mutex);
-	return 0;
+	return ret;
 }
 
 static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
--- linux-ein-5.4.0.orig/drivers/media/usb/dvb-usb/vp7045.c
+++ linux-ein-5.4.0/drivers/media/usb/dvb-usb/vp7045.c
@@ -96,10 +96,14 @@
 
 static int vp7045_rc_query(struct dvb_usb_device *d)
 {
+	int ret;
 	u8 key;
-	vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
 
-	deb_rc("remote query key: %x %d\n",key,key);
+	ret = vp7045_usb_op(d, RC_VAL_READ, NULL, 0, &key, 1, 20);
+	if (ret)
+		return ret;
+
+	deb_rc("remote query key: %x\n", key);
 
 	if (key != 0x44) {
 		/*
@@ -115,15 +119,18 @@
 
 static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
 {
-	int i = 0;
-	u8 v,br[2];
+	int i, ret;
+	u8 v, br[2];
 	for (i=0; i < len; i++) {
 		v = offset + i;
-		vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
+		ret = vp7045_usb_op(d, GET_EE_VALUE, &v, 1, br, 2, 5);
+		if (ret)
+			return ret;
+
 		buf[i] = br[1];
 	}
-	deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
-	debug_dump(buf,i,deb_info);
+	deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ", offset, i);
+	debug_dump(buf, i, deb_info);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/usb/em28xx/em28xx-cards.c
+++ linux-ein-5.4.0/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3515,8 +3515,10 @@
 
 	if (dev->is_audio_only) {
 		retval = em28xx_audio_setup(dev);
-		if (retval)
-			return -ENODEV;
+		if (retval) {
+			retval = -ENODEV;
+			goto err_deinit_media;
+		}
 		em28xx_init_extension(dev);
 
 		return 0;
@@ -3535,7 +3537,7 @@
 		dev_err(&dev->intf->dev,
 			"%s: em28xx_i2c_register bus 0 - error [%d]!\n",
 		       __func__, retval);
-		return retval;
+		goto err_deinit_media;
 	}
 
 	/* register i2c bus 1 */
@@ -3551,9 +3553,7 @@
 				"%s: em28xx_i2c_register bus 1 - error [%d]!\n",
 				__func__, retval);
 
-			em28xx_i2c_unregister(dev, 0);
-
-			return retval;
+			goto err_unreg_i2c;
 		}
 	}
 
@@ -3561,6 +3561,12 @@
 	em28xx_card_setup(dev);
 
 	return 0;
+
+err_unreg_i2c:
+	em28xx_i2c_unregister(dev, 0);
+err_deinit_media:
+	em28xx_unregister_media_device(dev);
+	return retval;
 }
 
 static int em28xx_duplicate_dev(struct em28xx *dev)
@@ -3815,6 +3821,8 @@
 		goto err_free;
 	}
 
+	kref_init(&dev->ref);
+
 	dev->devno = nr;
 	dev->model = id->driver_info;
 	dev->alt   = -1;
@@ -3915,6 +3923,8 @@
 	}
 
 	if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
+		kref_init(&dev->dev_next->ref);
+
 		dev->dev_next->ts = SECONDARY_TS;
 		dev->dev_next->alt   = -1;
 		dev->dev_next->is_audio_only = has_vendor_audio &&
@@ -3969,12 +3979,8 @@
 			em28xx_write_reg(dev, 0x0b, 0x82);
 			mdelay(100);
 		}
-
-		kref_init(&dev->dev_next->ref);
 	}
 
-	kref_init(&dev->ref);
-
 	request_modules(dev);
 
 	/*
--- linux-ein-5.4.0.orig/drivers/media/usb/em28xx/em28xx-core.c
+++ linux-ein-5.4.0/drivers/media/usb/em28xx/em28xx-core.c
@@ -89,7 +89,7 @@
 	mutex_lock(&dev->ctrl_urb_lock);
 	ret = usb_control_msg(udev, pipe, req,
 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			      0x0000, reg, dev->urb_buf, len, HZ);
+			      0x0000, reg, dev->urb_buf, len, 1000);
 	if (ret < 0) {
 		em28xx_regdbg("(pipe 0x%08x): IN:  %02x %02x %02x %02x %02x %02x %02x %02x  failed with error %i\n",
 			      pipe,
@@ -158,7 +158,7 @@
 	memcpy(dev->urb_buf, buf, len);
 	ret = usb_control_msg(udev, pipe, req,
 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			      0x0000, reg, dev->urb_buf, len, HZ);
+			      0x0000, reg, dev->urb_buf, len, 1000);
 	mutex_unlock(&dev->ctrl_urb_lock);
 
 	if (ret < 0) {
@@ -956,14 +956,10 @@
 
 		usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL);
 		if (!usb_bufs->buf[i]) {
-			em28xx_uninit_usb_xfer(dev, mode);
-
 			for (i--; i >= 0; i--)
 				kfree(usb_bufs->buf[i]);
 
-			kfree(usb_bufs->buf);
-			usb_bufs->buf = NULL;
-
+			em28xx_uninit_usb_xfer(dev, mode);
 			return -ENOMEM;
 		}
 
@@ -1156,8 +1152,9 @@
 	dev_info(&dev->intf->dev, "Suspending extensions\n");
 	mutex_lock(&em28xx_devlist_mutex);
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-		if (ops->suspend)
-			ops->suspend(dev);
+		if (!ops->suspend)
+			continue;
+		ops->suspend(dev);
 		if (dev->dev_next)
 			ops->suspend(dev->dev_next);
 	}
--- linux-ein-5.4.0.orig/drivers/media/usb/em28xx/em28xx-dvb.c
+++ linux-ein-5.4.0/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1924,6 +1924,7 @@
 	return result;
 
 out_free:
+	em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
 	kfree(dvb);
 	dev->dvb = NULL;
 	goto ret;
--- linux-ein-5.4.0.orig/drivers/media/usb/em28xx/em28xx-input.c
+++ linux-ein-5.4.0/drivers/media/usb/em28xx/em28xx-input.c
@@ -720,7 +720,8 @@
 			dev->board.has_ir_i2c = 0;
 			dev_warn(&dev->intf->dev,
 				 "No i2c IR remote control device found.\n");
-			return -ENODEV;
+			err = -ENODEV;
+			goto ref_put;
 		}
 	}
 
@@ -735,7 +736,7 @@
 
 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 	if (!ir)
-		return -ENOMEM;
+		goto ref_put;
 	rc = rc_allocate_device(RC_DRIVER_SCANCODE);
 	if (!rc)
 		goto error;
@@ -839,6 +840,8 @@
 	dev->ir = NULL;
 	rc_free_device(rc);
 	kfree(ir);
+ref_put:
+	em28xx_shutdown_buttons(dev);
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/media/usb/go7007/go7007-driver.c
+++ linux-ein-5.4.0/drivers/media/usb/go7007/go7007-driver.c
@@ -691,49 +691,23 @@
 						struct device *dev)
 {
 	struct go7007 *go;
-	int i;
 
 	go = kzalloc(sizeof(struct go7007), GFP_KERNEL);
 	if (go == NULL)
 		return NULL;
 	go->dev = dev;
 	go->board_info = board;
-	go->board_id = 0;
 	go->tuner_type = -1;
-	go->channel_number = 0;
-	go->name[0] = 0;
 	mutex_init(&go->hw_lock);
 	init_waitqueue_head(&go->frame_waitq);
 	spin_lock_init(&go->spinlock);
 	go->status = STATUS_INIT;
-	memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
-	go->i2c_adapter_online = 0;
-	go->interrupt_available = 0;
 	init_waitqueue_head(&go->interrupt_waitq);
-	go->input = 0;
 	go7007_update_board(go);
-	go->encoder_h_halve = 0;
-	go->encoder_v_halve = 0;
-	go->encoder_subsample = 0;
 	go->format = V4L2_PIX_FMT_MJPEG;
 	go->bitrate = 1500000;
 	go->fps_scale = 1;
-	go->pali = 0;
 	go->aspect_ratio = GO7007_RATIO_1_1;
-	go->gop_size = 0;
-	go->ipb = 0;
-	go->closed_gop = 0;
-	go->repeat_seqhead = 0;
-	go->seq_header_enable = 0;
-	go->gop_header_enable = 0;
-	go->dvd_mode = 0;
-	go->interlace_coding = 0;
-	for (i = 0; i < 4; ++i)
-		go->modet[i].enable = 0;
-	for (i = 0; i < 1624; ++i)
-		go->modet_map[i] = 0;
-	go->audio_deliver = NULL;
-	go->audio_enabled = 0;
 
 	return go;
 }
--- linux-ein-5.4.0.orig/drivers/media/usb/go7007/go7007-i2c.c
+++ linux-ein-5.4.0/drivers/media/usb/go7007/go7007-i2c.c
@@ -165,8 +165,6 @@
 		} else if (msgs[i].len == 3) {
 			if (msgs[i].flags & I2C_M_RD)
 				return -EIO;
-			if (msgs[i].len != 3)
-				return -EIO;
 			if (go7007_i2c_xfer(go, msgs[i].addr, 0,
 					(msgs[i].buf[0] << 8) | msgs[i].buf[1],
 					0x01, &msgs[i].buf[2]) < 0)
--- linux-ein-5.4.0.orig/drivers/media/usb/go7007/go7007-usb.c
+++ linux-ein-5.4.0/drivers/media/usb/go7007/go7007-usb.c
@@ -1044,6 +1044,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;
@@ -1140,7 +1141,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-ein-5.4.0.orig/drivers/media/usb/go7007/s2250-board.c
+++ linux-ein-5.4.0/drivers/media/usb/go7007/s2250-board.c
@@ -504,6 +504,7 @@
 	u8 *data;
 	struct go7007 *go = i2c_get_adapdata(adapter);
 	struct go7007_usb *usb = go->hpi_context;
+	int err = -EIO;
 
 	audio = i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1);
 	if (IS_ERR(audio))
@@ -532,11 +533,8 @@
 		V4L2_CID_HUE, -512, 511, 1, 0);
 	sd->ctrl_handler = &state->hdl;
 	if (state->hdl.error) {
-		int err = state->hdl.error;
-
-		v4l2_ctrl_handler_free(&state->hdl);
-		kfree(state);
-		return err;
+		err = state->hdl.error;
+		goto fail;
 	}
 
 	state->std = V4L2_STD_NTSC;
@@ -600,7 +598,7 @@
 	i2c_unregister_device(audio);
 	v4l2_ctrl_handler_free(&state->hdl);
 	kfree(state);
-	return -EIO;
+	return err;
 }
 
 static int s2250_remove(struct i2c_client *client)
--- linux-ein-5.4.0.orig/drivers/media/usb/go7007/snd-go7007.c
+++ linux-ein-5.4.0/drivers/media/usb/go7007/snd-go7007.c
@@ -236,22 +236,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;
+
 	strscpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
 	strscpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->shortname));
 	strscpy(gosnd->card->longname, gosnd->card->shortname,
@@ -262,11 +258,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;
@@ -274,6 +267,12 @@
 	++dev;
 
 	return 0;
+
+free_card:
+	snd_card_free(gosnd->card);
+free_snd:
+	kfree(gosnd);
+	return ret;
 }
 EXPORT_SYMBOL(go7007_snd_init);
 
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/cpia1.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/cpia1.c
@@ -18,6 +18,7 @@
 
 #include <linux/input.h>
 #include <linux/sched/signal.h>
+#include <linux/bitops.h>
 
 #include "gspca.h"
 
@@ -1027,6 +1028,8 @@
 			sd->params.exposure.expMode = 2;
 			sd->exposure_status = EXPOSURE_NORMAL;
 		}
+		if (sd->params.exposure.gain >= BITS_PER_TYPE(currentexp))
+			return -EINVAL;
 		currentexp = currentexp << sd->params.exposure.gain;
 		sd->params.exposure.gain = 0;
 		/* round down current exposure to nearest value */
@@ -1424,7 +1427,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
-	int ret;
 
 	sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
 	reset_camera_params(gspca_dev);
@@ -1436,10 +1438,7 @@
 	cam->cam_mode = mode;
 	cam->nmodes = ARRAY_SIZE(mode);
 
-	ret = goto_low_power(gspca_dev);
-	if (ret)
-		gspca_err(gspca_dev, "Cannot go to low power mode: %d\n",
-			  ret);
+	goto_low_power(gspca_dev);
 	/* Check the firmware version. */
 	sd->params.version.firmwareVersion = 0;
 	get_version_information(gspca_dev);
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/gl860/gl860.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/gl860/gl860.c
@@ -561,8 +561,8 @@
 					len, 400 + 200 * (len > 1));
 			memcpy(pdata, gspca_dev->usb_buf, len);
 		} else {
-			r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-					req, pref, val, index, NULL, len, 400);
+			gspca_err(gspca_dev, "zero-length read request\n");
+			r = -EINVAL;
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/gspca.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/gspca.c
@@ -1461,7 +1461,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;
@@ -1575,6 +1575,9 @@
 		input_unregister_device(gspca_dev->input_dev);
 #endif
 	v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
+	v4l2_device_unregister(&gspca_dev->v4l2_dev);
+	if (sd_desc->probe_error)
+		sd_desc->probe_error(gspca_dev);
 	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 	return ret;
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/gspca.h
+++ linux-ein-5.4.0/drivers/media/usb/gspca/gspca.h
@@ -105,6 +105,7 @@
 	cam_cf_op config;	/* called on probe */
 	cam_op init;		/* called on probe and resume */
 	cam_op init_controls;	/* called on probe */
+	cam_v_op probe_error;	/* called if probe failed, do cleanup here */
 	cam_op start;		/* called on stream on after URBs creation */
 	cam_pkt_op pkt_scan;
 /* optional operations */
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
@@ -195,7 +195,7 @@
 int mt9m111_probe(struct sd *sd)
 {
 	u8 data[2] = {0x00, 0x00};
-	int i, rc = 0;
+	int i, err;
 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 
 	if (force_sensor) {
@@ -213,18 +213,18 @@
 	/* Do the preinit */
 	for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
 		if (preinit_mt9m111[i][0] == BRIDGE) {
-			rc |= m5602_write_bridge(sd,
-				preinit_mt9m111[i][1],
-				preinit_mt9m111[i][2]);
+			err = m5602_write_bridge(sd,
+					preinit_mt9m111[i][1],
+					preinit_mt9m111[i][2]);
 		} else {
 			data[0] = preinit_mt9m111[i][2];
 			data[1] = preinit_mt9m111[i][3];
-			rc |= m5602_write_sensor(sd,
-				preinit_mt9m111[i][1], data, 2);
+			err = m5602_write_sensor(sd,
+					preinit_mt9m111[i][1], data, 2);
 		}
+		if (err < 0)
+			return err;
 	}
-	if (rc < 0)
-		return rc;
 
 	if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/m5602/m5602_po1030.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/m5602/m5602_po1030.c
@@ -154,8 +154,8 @@
 
 int po1030_probe(struct sd *sd)
 {
-	int rc = 0;
 	u8 dev_id_h = 0, i;
+	int err;
 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 
 	if (force_sensor) {
@@ -174,14 +174,14 @@
 	for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
 		u8 data = preinit_po1030[i][2];
 		if (preinit_po1030[i][0] == SENSOR)
-			rc |= m5602_write_sensor(sd,
-				preinit_po1030[i][1], &data, 1);
+			err = m5602_write_sensor(sd, preinit_po1030[i][1],
+						 &data, 1);
 		else
-			rc |= m5602_write_bridge(sd, preinit_po1030[i][1],
-						data);
+			err = m5602_write_bridge(sd, preinit_po1030[i][1],
+						 data);
+		if (err < 0)
+			return err;
 	}
-	if (rc < 0)
-		return rc;
 
 	if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/ov519.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/ov519.c
@@ -3477,6 +3477,11 @@
 		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);
 
@@ -3603,6 +3608,11 @@
 		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-ein-5.4.0.orig/drivers/media/usb/gspca/sq905.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/sq905.c
@@ -116,7 +116,7 @@
 	}
 
 	ret = usb_control_msg(gspca_dev->dev,
-			      usb_sndctrlpipe(gspca_dev->dev, 0),
+			      usb_rcvctrlpipe(gspca_dev->dev, 0),
 			      USB_REQ_SYNCH_FRAME,                /* request */
 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			      SQ905_PING, 0, gspca_dev->usb_buf, 1,
@@ -158,7 +158,7 @@
 sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
 {
 	int ret;
-	int act_len;
+	int act_len = 0;
 
 	gspca_dev->usb_buf[0] = '\0';
 	if (need_lock)
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -282,6 +282,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)
@@ -306,11 +309,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]);
 
@@ -323,6 +336,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];
@@ -512,12 +529,21 @@
 static int stv06xx_config(struct gspca_dev *gspca_dev,
 			  const struct usb_device_id *id);
 
+static void stv06xx_probe_error(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	kfree(sd->sensor_priv);
+	sd->sensor_priv = NULL;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.config = stv06xx_config,
 	.init = stv06xx_init,
 	.init_controls = stv06xx_init_controls,
+	.probe_error = stv06xx_probe_error,
 	.start = stv06xx_start,
 	.stopN = stv06xx_stopN,
 	.pkt_scan = stv06xx_pkt_scan,
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
@@ -185,6 +185,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-ein-5.4.0.orig/drivers/media/usb/gspca/sunplus.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/sunplus.c
@@ -242,6 +242,10 @@
 		gspca_err(gspca_dev, "reg_r: buffer overflow\n");
 		return;
 	}
+	if (len == 0) {
+		gspca_err(gspca_dev, "reg_r: zero-length read\n");
+		return;
+	}
 	if (gspca_dev->usb_err < 0)
 		return;
 	ret = usb_control_msg(gspca_dev->dev,
@@ -250,7 +254,7 @@
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0,		/* value */
 			index,
-			len ? gspca_dev->usb_buf : NULL, len,
+			gspca_dev->usb_buf, len,
 			500);
 	if (ret < 0) {
 		pr_err("reg_r err %d\n", ret);
@@ -727,7 +731,7 @@
 		case MegaImageVI:
 			reg_w_riv(gspca_dev, 0xf0, 0, 0);
 			spca504B_WaitCmdStatus(gspca_dev);
-			reg_r(gspca_dev, 0xf0, 4, 0);
+			reg_w_riv(gspca_dev, 0xf0, 4, 0);
 			spca504B_WaitCmdStatus(gspca_dev);
 			break;
 		default:
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/vicam.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/vicam.c
@@ -225,7 +225,7 @@
 {
 	int ret;
 	const struct ihex_binrec *rec;
-	const struct firmware *uninitialized_var(fw);
+	const struct firmware *fw;
 	u8 *firmware_buf;
 
 	ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,
--- linux-ein-5.4.0.orig/drivers/media/usb/gspca/xirlink_cit.c
+++ linux-ein-5.4.0/drivers/media/usb/gspca/xirlink_cit.c
@@ -1442,6 +1442,9 @@
 		return -EIO;
 	}
 
+	if (alt->desc.bNumEndpoints < 1)
+		return -ENODEV;
+
 	return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 }
 
@@ -2626,6 +2629,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;
 
@@ -2641,8 +2645,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;
@@ -2665,6 +2678,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-ein-5.4.0.orig/drivers/media/usb/hdpvr/hdpvr-video.c
+++ linux-ein-5.4.0/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -308,7 +308,6 @@
 
 	dev->status = STATUS_STREAMING;
 
-	INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
 	schedule_work(&dev->worker);
 
 	v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
@@ -410,7 +409,7 @@
 	struct hdpvr_device *dev = video_drvdata(file);
 	struct hdpvr_buffer *buf = NULL;
 	struct urb *urb;
-	unsigned int ret = 0;
+	int ret = 0;
 	int rem, cnt;
 
 	if (*pos)
@@ -1165,6 +1164,9 @@
 	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
 	int res;
 
+	// initialize dev->worker
+	INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+
 	dev->cur_std = V4L2_STD_525_60;
 	dev->width = 720;
 	dev->height = 480;
--- linux-ein-5.4.0.orig/drivers/media/usb/msi2500/msi2500.c
+++ linux-ein-5.4.0/drivers/media/usb/msi2500/msi2500.c
@@ -1230,7 +1230,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-ein-5.4.0.orig/drivers/media/usb/pulse8-cec/pulse8-cec.c
+++ linux-ein-5.4.0/drivers/media/usb/pulse8-cec/pulse8-cec.c
@@ -116,6 +116,7 @@
 	unsigned int vers;
 	struct completion cmd_done;
 	struct work_struct work;
+	u8 work_result;
 	struct delayed_work ping_eeprom_work;
 	struct cec_msg rx_msg;
 	u8 data[DATA_SIZE];
@@ -137,8 +138,10 @@
 {
 	struct pulse8 *pulse8 =
 		container_of(work, struct pulse8, work);
+	u8 result = pulse8->work_result;
 
-	switch (pulse8->data[0] & 0x3f) {
+	pulse8->work_result = 0;
+	switch (result & 0x3f) {
 	case MSGCODE_FRAME_DATA:
 		cec_received_msg(pulse8->adap, &pulse8->rx_msg);
 		break;
@@ -172,12 +175,12 @@
 		pulse8->escape = false;
 	} else if (data == MSGEND) {
 		struct cec_msg *msg = &pulse8->rx_msg;
+		u8 msgcode = pulse8->buf[0];
 
 		if (debug)
 			dev_info(pulse8->dev, "received: %*ph\n",
 				 pulse8->idx, pulse8->buf);
-		pulse8->data[0] = pulse8->buf[0];
-		switch (pulse8->buf[0] & 0x3f) {
+		switch (msgcode & 0x3f) {
 		case MSGCODE_FRAME_START:
 			msg->len = 1;
 			msg->msg[0] = pulse8->buf[1];
@@ -186,14 +189,20 @@
 			if (msg->len == CEC_MAX_MSG_SIZE)
 				break;
 			msg->msg[msg->len++] = pulse8->buf[1];
-			if (pulse8->buf[0] & MSGCODE_FRAME_EOM)
+			if (msgcode & MSGCODE_FRAME_EOM) {
+				WARN_ON(pulse8->work_result);
+				pulse8->work_result = msgcode;
 				schedule_work(&pulse8->work);
+				break;
+			}
 			break;
 		case MSGCODE_TRANSMIT_SUCCEEDED:
 		case MSGCODE_TRANSMIT_FAILED_LINE:
 		case MSGCODE_TRANSMIT_FAILED_ACK:
 		case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
 		case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
+			WARN_ON(pulse8->work_result);
+			pulse8->work_result = msgcode;
 			schedule_work(&pulse8->work);
 			break;
 		case MSGCODE_HIGH_ERROR:
--- linux-ein-5.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ linux-ein-5.4.0/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -268,7 +268,8 @@
 {
 	pvr2_hdw_disconnect(mp->hdw);
 	mp->disconnect_flag = !0;
-	pvr2_context_notify(mp);
+	if (!pvr2_context_shutok())
+		pvr2_context_notify(mp);
 }
 
 
--- linux-ein-5.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ linux-ein-5.4.0/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -1468,7 +1468,7 @@
 	for (address = 0; address < fwsize; address += 0x800) {
 		memcpy(fw_ptr, fw_entry->data + address, 0x800);
 		ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
-				       0, fw_ptr, 0x800, HZ);
+				       0, fw_ptr, 0x800, 1000);
 	}
 
 	trace_firmware("Upload done, releasing device's CPU");
@@ -1606,7 +1606,7 @@
 			((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
 
 		ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
-				    &actual_length, HZ);
+				    &actual_length, 1000);
 		ret |= (actual_length != bcnt);
 		if (ret) break;
 		fw_done += bcnt;
@@ -2570,6 +2570,11 @@
 	} while (0);
 	mutex_unlock(&pvr2_unit_mtx);
 
+	INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll);
+
+	if (hdw->unit_number == -1)
+		goto fail;
+
 	cnt1 = 0;
 	cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
 	cnt1 += cnt2;
@@ -2581,8 +2586,6 @@
 	if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
 	hdw->name[cnt1] = 0;
 
-	INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
-
 	pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
 		   hdw->unit_number,hdw->name);
 
@@ -2608,6 +2611,7 @@
 		del_timer_sync(&hdw->encoder_run_timer);
 		del_timer_sync(&hdw->encoder_wait_timer);
 		flush_work(&hdw->workpoll);
+		v4l2_device_unregister(&hdw->v4l2_dev);
 		usb_free_urb(hdw->ctl_read_urb);
 		usb_free_urb(hdw->ctl_write_urb);
 		kfree(hdw->ctl_read_buffer);
@@ -2677,9 +2681,8 @@
 		pvr2_stream_destroy(hdw->vid_stream);
 		hdw->vid_stream = NULL;
 	}
-	pvr2_i2c_core_done(hdw);
 	v4l2_device_unregister(&hdw->v4l2_dev);
-	pvr2_hdw_remove_usb_stuff(hdw);
+	pvr2_hdw_disconnect(hdw);
 	mutex_lock(&pvr2_unit_mtx);
 	do {
 		if ((hdw->unit_number >= 0) &&
@@ -2706,6 +2709,7 @@
 {
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
 	LOCK_TAKE(hdw->big_lock);
+	pvr2_i2c_core_done(hdw);
 	LOCK_TAKE(hdw->ctl_lock);
 	pvr2_hdw_remove_usb_stuff(hdw);
 	LOCK_GIVE(hdw->ctl_lock);
@@ -3439,7 +3443,7 @@
 						      0xa0,0xc0,
 						      address,0,
 						      hdw->fw_buffer+address,
-						      0x800,HZ);
+						      0x800,1000);
 				if (ret < 0) break;
 			}
 
@@ -3978,7 +3982,7 @@
 	/* Write the CPUCS register on the 8051.  The lsb of the register
 	   is the reset bit; a 1 asserts reset while a 0 clears it. */
 	pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
-	ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ);
+	ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,1000);
 	if (ret < 0) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "cpureset_assert(%d) error=%d",val,ret);
--- linux-ein-5.4.0.orig/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ linux-ein-5.4.0/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -898,8 +898,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);
 }
 
@@ -935,7 +939,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-ein-5.4.0.orig/drivers/media/usb/pwc/pwc-if.c
+++ linux-ein-5.4.0/drivers/media/usb/pwc/pwc-if.c
@@ -147,16 +147,17 @@
 /***************************************************************************/
 /* Private functions */
 
-static void *pwc_alloc_urb_buffer(struct device *dev,
+static void *pwc_alloc_urb_buffer(struct usb_device *dev,
 				  size_t size, dma_addr_t *dma_handle)
 {
+	struct device *dmadev = dev->bus->sysdev;
 	void *buffer = kmalloc(size, GFP_KERNEL);
 
 	if (!buffer)
 		return NULL;
 
-	*dma_handle = dma_map_single(dev, buffer, size, DMA_FROM_DEVICE);
-	if (dma_mapping_error(dev, *dma_handle)) {
+	*dma_handle = dma_map_single(dmadev, buffer, size, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dmadev, *dma_handle)) {
 		kfree(buffer);
 		return NULL;
 	}
@@ -164,12 +165,14 @@
 	return buffer;
 }
 
-static void pwc_free_urb_buffer(struct device *dev,
+static void pwc_free_urb_buffer(struct usb_device *dev,
 				size_t size,
 				void *buffer,
 				dma_addr_t dma_handle)
 {
-	dma_unmap_single(dev, dma_handle, size, DMA_FROM_DEVICE);
+	struct device *dmadev = dev->bus->sysdev;
+
+	dma_unmap_single(dmadev, dma_handle, size, DMA_FROM_DEVICE);
 	kfree(buffer);
 }
 
@@ -274,6 +277,7 @@
 static void pwc_isoc_handler(struct urb *urb)
 {
 	struct pwc_device *pdev = (struct pwc_device *)urb->context;
+	struct device *dmadev = urb->dev->bus->sysdev;
 	int i, fst, flen;
 	unsigned char *iso_buf = NULL;
 
@@ -320,7 +324,7 @@
 	/* Reset ISOC error counter. We did get here, after all. */
 	pdev->visoc_errors = 0;
 
-	dma_sync_single_for_cpu(&urb->dev->dev,
+	dma_sync_single_for_cpu(dmadev,
 				urb->transfer_dma,
 				urb->transfer_buffer_length,
 				DMA_FROM_DEVICE);
@@ -371,7 +375,7 @@
 		pdev->vlast_packet_size = flen;
 	}
 
-	dma_sync_single_for_device(&urb->dev->dev,
+	dma_sync_single_for_device(dmadev,
 				   urb->transfer_dma,
 				   urb->transfer_buffer_length,
 				   DMA_FROM_DEVICE);
@@ -453,7 +457,7 @@
 		urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
 		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
-		urb->transfer_buffer = pwc_alloc_urb_buffer(&udev->dev,
+		urb->transfer_buffer = pwc_alloc_urb_buffer(udev,
 							    urb->transfer_buffer_length,
 							    &urb->transfer_dma);
 		if (urb->transfer_buffer == NULL) {
@@ -516,7 +520,7 @@
 		if (urb) {
 			PWC_DEBUG_MEMORY("Freeing URB\n");
 			if (urb->transfer_buffer)
-				pwc_free_urb_buffer(&urb->dev->dev,
+				pwc_free_urb_buffer(urb->dev,
 						    urb->transfer_buffer_length,
 						    urb->transfer_buffer,
 						    urb->transfer_dma);
--- linux-ein-5.4.0.orig/drivers/media/usb/s2255/s2255drv.c
+++ linux-ein-5.4.0/drivers/media/usb/s2255/s2255drv.c
@@ -1884,7 +1884,7 @@
 				    USB_TYPE_VENDOR | USB_RECIP_DEVICE |
 				    USB_DIR_IN,
 				    Value, Index, buf,
-				    TransferBufferLength, HZ * 5);
+				    TransferBufferLength, USB_CTRL_SET_TIMEOUT);
 
 		if (r >= 0)
 			memcpy(TransferBuffer, buf, TransferBufferLength);
@@ -1893,7 +1893,7 @@
 		r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 				    Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				    Value, Index, buf,
-				    TransferBufferLength, HZ * 5);
+				    TransferBufferLength, USB_CTRL_SET_TIMEOUT);
 	}
 	kfree(buf);
 	return r;
--- linux-ein-5.4.0.orig/drivers/media/usb/siano/smsusb.c
+++ linux-ein-5.4.0/drivers/media/usb/siano/smsusb.c
@@ -179,6 +179,8 @@
 
 	for (i = 0; i < MAX_URBS; i++) {
 		usb_kill_urb(&dev->surbs[i].urb);
+		if (dev->surbs[i].wq.func)
+			cancel_work_sync(&dev->surbs[i].wq);
 
 		if (dev->surbs[i].cb) {
 			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
@@ -453,12 +455,7 @@
 	rc = smscore_register_device(&params, &dev->coredev, 0, mdev);
 	if (rc < 0) {
 		pr_err("smscore_register_device(...) failed, rc %d\n", rc);
-		smsusb_term_device(intf);
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-		media_device_unregister(mdev);
-#endif
-		kfree(mdev);
-		return rc;
+		goto err_unregister_device;
 	}
 
 	smscore_set_board_id(dev->coredev, board_id);
@@ -475,8 +472,7 @@
 	rc = smsusb_start_streaming(dev);
 	if (rc < 0) {
 		pr_err("smsusb_start_streaming(...) failed\n");
-		smsusb_term_device(intf);
-		return rc;
+		goto err_unregister_device;
 	}
 
 	dev->state = SMSUSB_ACTIVE;
@@ -484,13 +480,20 @@
 	rc = smscore_start_device(dev->coredev);
 	if (rc < 0) {
 		pr_err("smscore_start_device(...) failed\n");
-		smsusb_term_device(intf);
-		return rc;
+		goto err_unregister_device;
 	}
 
 	pr_debug("device 0x%p created\n", dev);
 
 	return rc;
+
+err_unregister_device:
+	smsusb_term_device(intf);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	media_device_unregister(mdev);
+#endif
+	kfree(mdev);
+	return rc;
 }
 
 static int smsusb_probe(struct usb_interface *intf,
--- linux-ein-5.4.0.orig/drivers/media/usb/stk1160/stk1160-core.c
+++ linux-ein-5.4.0/drivers/media/usb/stk1160/stk1160-core.c
@@ -65,7 +65,7 @@
 		return -ENOMEM;
 	ret = usb_control_msg(dev->udev, pipe, 0x00,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			0x00, reg, buf, sizeof(u8), HZ);
+			0x00, reg, buf, sizeof(u8), 1000);
 	if (ret < 0) {
 		stk1160_err("read failed on reg 0x%x (%d)\n",
 			reg, ret);
@@ -85,7 +85,7 @@
 
 	ret =  usb_control_msg(dev->udev, pipe, 0x01,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, reg, NULL, 0, HZ);
+			value, reg, NULL, 0, 1000);
 	if (ret < 0) {
 		stk1160_err("write failed on reg 0x%x (%d)\n",
 			reg, ret);
@@ -403,7 +403,7 @@
 	/* Here is the only place where isoc get released */
 	stk1160_uninit_isoc(dev);
 
-	stk1160_clear_queue(dev);
+	stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR);
 
 	video_unregister_device(&dev->vdev);
 	v4l2_device_disconnect(&dev->v4l2_dev);
--- linux-ein-5.4.0.orig/drivers/media/usb/stk1160/stk1160-v4l.c
+++ linux-ein-5.4.0/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -258,7 +258,7 @@
 	stk1160_uninit_isoc(dev);
 out_stop_hw:
 	usb_set_interface(dev->udev, 0, 0);
-	stk1160_clear_queue(dev);
+	stk1160_clear_queue(dev, VB2_BUF_STATE_QUEUED);
 
 	mutex_unlock(&dev->v4l_lock);
 
@@ -306,7 +306,7 @@
 
 	stk1160_stop_hw(dev);
 
-	stk1160_clear_queue(dev);
+	stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR);
 
 	stk1160_dbg("streaming stopped\n");
 
@@ -745,7 +745,7 @@
 /********************************************************************/
 
 /* Must be called with both v4l_lock and vb_queue_lock hold */
-void stk1160_clear_queue(struct stk1160 *dev)
+void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state)
 {
 	struct stk1160_buffer *buf;
 	unsigned long flags;
@@ -756,7 +756,7 @@
 		buf = list_first_entry(&dev->avail_bufs,
 			struct stk1160_buffer, list);
 		list_del(&buf->list);
-		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+		vb2_buffer_done(&buf->vb.vb2_buf, vb2_state);
 		stk1160_dbg("buffer [%p/%d] aborted\n",
 			    buf, buf->vb.vb2_buf.index);
 	}
@@ -766,7 +766,7 @@
 		buf = dev->isoc_ctl.buf;
 		dev->isoc_ctl.buf = NULL;
 
-		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+		vb2_buffer_done(&buf->vb.vb2_buf, vb2_state);
 		stk1160_dbg("buffer [%p/%d] aborted\n",
 			    buf, buf->vb.vb2_buf.index);
 	}
--- linux-ein-5.4.0.orig/drivers/media/usb/stk1160/stk1160-video.c
+++ linux-ein-5.4.0/drivers/media/usb/stk1160/stk1160-video.c
@@ -107,8 +107,7 @@
 
 	/*
 	 * TODO: These stk1160_dbg are very spammy!
-	 * We should 1) check why we are getting them
-	 * and 2) add ratelimit.
+	 * We should check why we are getting them.
 	 *
 	 * UPDATE: One of the reasons (the only one?) for getting these
 	 * is incorrect standard (mismatch between expected and configured).
@@ -151,7 +150,7 @@
 
 	/* Let the bug hunt begin! sanity checks! */
 	if (lencopy < 0) {
-		stk1160_dbg("copy skipped: negative lencopy\n");
+		printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n");
 		return;
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/usb/stk1160/stk1160.h
+++ linux-ein-5.4.0/drivers/media/usb/stk1160/stk1160.h
@@ -166,7 +166,7 @@
 int stk1160_vb2_setup(struct stk1160 *dev);
 int stk1160_video_register(struct stk1160 *dev);
 void stk1160_video_unregister(struct stk1160 *dev);
-void stk1160_clear_queue(struct stk1160 *dev);
+void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state);
 
 /* Provided by stk1160-video.c */
 int stk1160_alloc_isoc(struct stk1160 *dev);
--- linux-ein-5.4.0.orig/drivers/media/usb/stkwebcam/stk-webcam.c
+++ linux-ein-5.4.0/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -1346,7 +1346,7 @@
 	if (!dev->isoc_ep) {
 		pr_err("Could not find isoc-in endpoint\n");
 		err = -ENODEV;
-		goto error;
+		goto error_put;
 	}
 	dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
 	dev->vsettings.mode = MODE_VGA;
@@ -1359,10 +1359,12 @@
 
 	err = stk_register_video_device(dev);
 	if (err)
-		goto error;
+		goto error_put;
 
 	return 0;
 
+error_put:
+	usb_put_intf(interface);
 error:
 	v4l2_ctrl_handler_free(hdl);
 	v4l2_device_unregister(&dev->v4l2_dev);
--- linux-ein-5.4.0.orig/drivers/media/usb/tm6000/tm6000-dvb.c
+++ linux-ein-5.4.0/drivers/media/usb/tm6000/tm6000-dvb.c
@@ -141,6 +141,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 reset\n");
--- linux-ein-5.4.0.orig/drivers/media/usb/tm6000/tm6000-video.c
+++ linux-ein-5.4.0/drivers/media/usb/tm6000/tm6000-video.c
@@ -461,11 +461,12 @@
 	if (dev->urb_buffer)
 		return 0;
 
-	dev->urb_buffer = kmalloc_array(num_bufs, sizeof(void *), GFP_KERNEL);
+	dev->urb_buffer = kmalloc_array(num_bufs, sizeof(*dev->urb_buffer),
+					GFP_KERNEL);
 	if (!dev->urb_buffer)
 		return -ENOMEM;
 
-	dev->urb_dma = kmalloc_array(num_bufs, sizeof(dma_addr_t *),
+	dev->urb_dma = kmalloc_array(num_bufs, sizeof(*dev->urb_dma),
 				     GFP_KERNEL);
 	if (!dev->urb_dma)
 		return -ENOMEM;
@@ -853,8 +854,7 @@
 	struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
 
 	strscpy(cap->driver, "tm6000", sizeof(cap->driver));
-	strscpy(cap->card, "Trident TVMaster TM5600/6000/6010",
-		sizeof(cap->card));
+	strscpy(cap->card, "Trident TM5600/6000/6010", sizeof(cap->card));
 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
 			    V4L2_CAP_DEVICE_CAPS;
--- linux-ein-5.4.0.orig/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ linux-ein-5.4.0/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -1551,8 +1551,7 @@
 	dvb_dmx_release(&dec->demux);
 	if (dec->fe) {
 		dvb_unregister_frontend(dec->fe);
-		if (dec->fe->ops.release)
-			dec->fe->ops.release(dec->fe);
+		dvb_frontend_detach(dec->fe);
 	}
 	dvb_unregister_adapter(&dec->adapter);
 }
--- linux-ein-5.4.0.orig/drivers/media/usb/usbtv/usbtv-audio.c
+++ linux-ein-5.4.0/drivers/media/usb/usbtv/usbtv-audio.c
@@ -399,7 +399,7 @@
 	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-ein-5.4.0.orig/drivers/media/usb/usbtv/usbtv-core.c
+++ linux-ein-5.4.0/drivers/media/usb/usbtv/usbtv-core.c
@@ -56,7 +56,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;
 	}
@@ -113,7 +113,8 @@
 
 usbtv_audio_fail:
 	/* we must not free at this point */
-	usb_get_dev(usbtv->udev);
+	v4l2_device_get(&usbtv->v4l2_dev);
+	/* this will undo the v4l2_device_get() */
 	usbtv_video_free(usbtv);
 
 usbtv_video_fail:
--- linux-ein-5.4.0.orig/drivers/media/usb/usbtv/usbtv-video.c
+++ linux-ein-5.4.0/drivers/media/usb/usbtv/usbtv-video.c
@@ -800,7 +800,8 @@
 		ret = usb_control_msg(usbtv->udev,
 			usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			0, USBTV_BASE + 0x0244, (void *)data, 3, 0);
+			0, USBTV_BASE + 0x0244, (void *)data, 3,
+			USB_CTRL_GET_TIMEOUT);
 		if (ret < 0)
 			goto error;
 	}
@@ -851,7 +852,7 @@
 	ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0),
 			USBTV_CONTROL_REG,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			0, index, (void *)data, size, 0);
+			0, index, (void *)data, size, USB_CTRL_SET_TIMEOUT);
 
 error:
 	if (ret < 0)
--- linux-ein-5.4.0.orig/drivers/media/usb/usbvision/usbvision-video.c
+++ linux-ein-5.4.0/drivers/media/usb/usbvision/usbvision-video.c
@@ -314,6 +314,10 @@
 	if (mutex_lock_interruptible(&usbvision->v4l2_lock))
 		return -ERESTARTSYS;
 
+	if (usbvision->remove_pending) {
+		err_code = -ENODEV;
+		goto unlock;
+	}
 	if (usbvision->user) {
 		err_code = -EBUSY;
 	} else {
@@ -377,6 +381,7 @@
 static int usbvision_v4l2_close(struct file *file)
 {
 	struct usb_usbvision *usbvision = video_drvdata(file);
+	int r;
 
 	PDEBUG(DBG_IO, "close");
 
@@ -391,9 +396,10 @@
 	usbvision_scratch_free(usbvision);
 
 	usbvision->user--;
+	r = usbvision->remove_pending;
 	mutex_unlock(&usbvision->v4l2_lock);
 
-	if (usbvision->remove_pending) {
+	if (r) {
 		printk(KERN_INFO "%s: Final disconnect\n", __func__);
 		usbvision_release(usbvision);
 		return 0;
@@ -453,6 +459,9 @@
 {
 	struct usb_usbvision *usbvision = video_drvdata(file);
 
+	if (!usbvision->dev)
+		return -ENODEV;
+
 	strscpy(vc->driver, "USBVision", sizeof(vc->driver));
 	strscpy(vc->card,
 		usbvision_device_data[usbvision->dev_model].model_string,
@@ -1061,6 +1070,11 @@
 
 	if (mutex_lock_interruptible(&usbvision->v4l2_lock))
 		return -ERESTARTSYS;
+
+	if (usbvision->remove_pending) {
+		err_code = -ENODEV;
+		goto out;
+	}
 	err_code = v4l2_fh_open(file);
 	if (err_code)
 		goto out;
@@ -1093,21 +1107,24 @@
 static int usbvision_radio_close(struct file *file)
 {
 	struct usb_usbvision *usbvision = video_drvdata(file);
+	int r;
 
 	PDEBUG(DBG_IO, "");
 
 	mutex_lock(&usbvision->v4l2_lock);
 	/* Set packet size to 0 */
 	usbvision->iface_alt = 0;
-	usb_set_interface(usbvision->dev, usbvision->iface,
-				    usbvision->iface_alt);
+	if (usbvision->dev)
+		usb_set_interface(usbvision->dev, usbvision->iface,
+				  usbvision->iface_alt);
 
 	usbvision_audio_off(usbvision);
 	usbvision->radio = 0;
 	usbvision->user--;
+	r = usbvision->remove_pending;
 	mutex_unlock(&usbvision->v4l2_lock);
 
-	if (usbvision->remove_pending) {
+	if (r) {
 		printk(KERN_INFO "%s: Final disconnect\n", __func__);
 		v4l2_fh_release(file);
 		usbvision_release(usbvision);
@@ -1539,6 +1556,7 @@
 static void usbvision_disconnect(struct usb_interface *intf)
 {
 	struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
+	int u;
 
 	PDEBUG(DBG_PROBE, "");
 
@@ -1555,13 +1573,14 @@
 	v4l2_device_disconnect(&usbvision->v4l2_dev);
 	usbvision_i2c_unregister(usbvision);
 	usbvision->remove_pending = 1;	/* Now all ISO data will be ignored */
+	u = usbvision->user;
 
 	usb_put_dev(usbvision->dev);
 	usbvision->dev = NULL;	/* USB device is no more */
 
 	mutex_unlock(&usbvision->v4l2_lock);
 
-	if (usbvision->user) {
+	if (u) {
 		printk(KERN_INFO "%s: In use, disconnect pending\n",
 		       __func__);
 		wake_up_interruptible(&usbvision->wait_frame);
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_ctrl.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_ctrl.c
@@ -6,6 +6,7 @@
  *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  */
 
+#include <asm/barrier.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -773,12 +774,16 @@
 	offset &= 7;
 	mask = ((1LL << bits) - 1) << offset;
 
-	for (; bits > 0; data++) {
+	while (1) {
 		u8 byte = *data & mask;
 		value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
 		bits -= 8 - (offset > 0 ? offset : 0);
+		if (bits <= 0)
+			break;
+
 		offset -= 8;
 		mask = (1 << bits) - 1;
+		data++;
 	}
 
 	/* Sign-extend the value if needed. */
@@ -1271,17 +1276,12 @@
 	uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
 }
 
-static void uvc_ctrl_status_event_work(struct work_struct *work)
+void uvc_ctrl_status_event(struct uvc_video_chain *chain,
+			   struct uvc_control *ctrl, const u8 *data)
 {
-	struct uvc_device *dev = container_of(work, struct uvc_device,
-					      async_ctrl.work);
-	struct uvc_ctrl_work *w = &dev->async_ctrl;
-	struct uvc_video_chain *chain = w->chain;
 	struct uvc_control_mapping *mapping;
-	struct uvc_control *ctrl = w->ctrl;
 	struct uvc_fh *handle;
 	unsigned int i;
-	int ret;
 
 	mutex_lock(&chain->ctrl_mutex);
 
@@ -1289,7 +1289,7 @@
 	ctrl->handle = NULL;
 
 	list_for_each_entry(mapping, &ctrl->info.mappings, list) {
-		s32 value = __uvc_ctrl_get_value(mapping, w->data);
+		s32 value = __uvc_ctrl_get_value(mapping, data);
 
 		/*
 		 * handle may be NULL here if the device sends auto-update
@@ -1308,6 +1308,20 @@
 	}
 
 	mutex_unlock(&chain->ctrl_mutex);
+}
+
+static void uvc_ctrl_status_event_work(struct work_struct *work)
+{
+	struct uvc_device *dev = container_of(work, struct uvc_device,
+					      async_ctrl.work);
+	struct uvc_ctrl_work *w = &dev->async_ctrl;
+	int ret;
+
+	uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+
+	/* The barrier is needed to synchronize with uvc_status_stop(). */
+	if (smp_load_acquire(&dev->flush_status))
+		return;
 
 	/* Resubmit the URB. */
 	w->urb->interval = dev->int_ep->desc.bInterval;
@@ -1317,8 +1331,8 @@
 			   ret);
 }
 
-bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain,
-			   struct uvc_control *ctrl, const u8 *data)
+bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain,
+				 struct uvc_control *ctrl, const u8 *data)
 {
 	struct uvc_device *dev = chain->dev;
 	struct uvc_ctrl_work *w = &dev->async_ctrl;
@@ -1844,30 +1858,35 @@
 {
 	struct uvc_entity *entity;
 	struct uvc_control *ctrl;
-	unsigned int i, found = 0;
+	unsigned int i;
+	bool found;
 	u32 reqflags;
 	u16 size;
 	u8 *data = NULL;
 	int ret;
 
 	/* Find the extension unit. */
+	found = false;
 	list_for_each_entry(entity, &chain->entities, chain) {
 		if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
-		    entity->id == xqry->unit)
+		    entity->id == xqry->unit) {
+			found = true;
 			break;
+		}
 	}
 
-	if (entity->id != xqry->unit) {
+	if (!found) {
 		uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
 			xqry->unit);
 		return -ENOENT;
 	}
 
 	/* Find the control and perform delayed initialization if needed. */
+	found = false;
 	for (i = 0; i < entity->ncontrols; ++i) {
 		ctrl = &entity->controls[i];
 		if (ctrl->index == xqry->selector - 1) {
-			found = 1;
+			found = true;
 			break;
 		}
 	}
@@ -2024,13 +2043,6 @@
 		goto done;
 	}
 
-	/*
-	 * Retrieve control flags from the device. Ignore errors and work with
-	 * default flag values from the uvc_ctrl array when the device doesn't
-	 * properly implement GET_INFO on standard controls.
-	 */
-	uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
-
 	ctrl->initialized = 1;
 
 	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
@@ -2253,6 +2265,13 @@
 		if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
 		    ctrl->index == info->index) {
 			uvc_ctrl_add_info(dev, ctrl, info);
+			/*
+			 * Retrieve control flags from the device. Ignore errors
+			 * and work with default flag values from the uvc_ctrl
+			 * array when the device doesn't properly implement
+			 * GET_INFO on standard controls.
+			 */
+			uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
 			break;
 		 }
 	}
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_driver.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_driver.c
@@ -214,6 +214,11 @@
 		.guid		= UVC_GUID_FORMAT_CNF4,
 		.fcc		= V4L2_PIX_FMT_CNF4,
 	},
+	{
+		.name		= "HEVC",
+		.guid		= UVC_GUID_FORMAT_HEVC,
+		.fcc		= V4L2_PIX_FMT_HEVC,
+	},
 };
 
 /* ------------------------------------------------------------------------
@@ -497,6 +502,22 @@
 			}
 		}
 
+		/* Some devices report bpp that doesn't match the format. */
+		if (dev->quirks & UVC_QUIRK_FORCE_BPP) {
+			const struct v4l2_format_info *info =
+				v4l2_format_info(format->fcc);
+
+			if (info) {
+				unsigned int div = info->hdiv * info->vdiv;
+
+				n = info->bpp[0] * div;
+				for (i = 1; i < info->comp_planes; i++)
+					n += info->bpp[i];
+
+				format->bpp = DIV_ROUND_UP(8 * n, div);
+			}
+		}
+
 		if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
 			ftype = UVC_VS_FRAME_UNCOMPRESSED;
 		} else {
@@ -951,7 +972,10 @@
 	unsigned int i;
 
 	extra_size = roundup(extra_size, sizeof(*entity->pads));
-	num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
+	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);
@@ -967,7 +991,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;
@@ -1041,10 +1065,8 @@
 					       + n;
 		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
 
-		if (buffer[24+p+2*n] != 0)
-			usb_string(udev, buffer[24+p+2*n], unit->name,
-				   sizeof(unit->name));
-		else
+		if (buffer[24+p+2*n] == 0 ||
+		    usb_string(udev, buffer[24+p+2*n], unit->name, sizeof(unit->name)) < 0)
 			sprintf(unit->name, "Extension %u", buffer[3]);
 
 		list_add_tail(&unit->list, &dev->entities);
@@ -1169,15 +1191,15 @@
 			memcpy(term->media.bmTransportModes, &buffer[10+n], p);
 		}
 
-		if (buffer[7] != 0)
-			usb_string(udev, buffer[7], term->name,
-				   sizeof(term->name));
-		else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
-			sprintf(term->name, "Camera %u", buffer[3]);
-		else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
-			sprintf(term->name, "Media %u", buffer[3]);
-		else
-			sprintf(term->name, "Input %u", buffer[3]);
+		if (buffer[7] == 0 ||
+		    usb_string(udev, buffer[7], term->name, sizeof(term->name)) < 0) {
+			if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
+				sprintf(term->name, "Camera %u", buffer[3]);
+			if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
+				sprintf(term->name, "Media %u", buffer[3]);
+			else
+				sprintf(term->name, "Input %u", buffer[3]);
+		}
 
 		list_add_tail(&term->list, &dev->entities);
 		break;
@@ -1209,10 +1231,8 @@
 
 		memcpy(term->baSourceID, &buffer[7], 1);
 
-		if (buffer[8] != 0)
-			usb_string(udev, buffer[8], term->name,
-				   sizeof(term->name));
-		else
+		if (buffer[8] == 0 ||
+		    usb_string(udev, buffer[8], term->name, sizeof(term->name)) < 0)
 			sprintf(term->name, "Output %u", buffer[3]);
 
 		list_add_tail(&term->list, &dev->entities);
@@ -1234,10 +1254,8 @@
 
 		memcpy(unit->baSourceID, &buffer[5], p);
 
-		if (buffer[5+p] != 0)
-			usb_string(udev, buffer[5+p], unit->name,
-				   sizeof(unit->name));
-		else
+		if (buffer[5+p] == 0 ||
+		    usb_string(udev, buffer[5+p], unit->name, sizeof(unit->name)) < 0)
 			sprintf(unit->name, "Selector %u", buffer[3]);
 
 		list_add_tail(&unit->list, &dev->entities);
@@ -1267,10 +1285,8 @@
 		if (dev->uvc_version >= 0x0110)
 			unit->processing.bmVideoStandards = buffer[9+n];
 
-		if (buffer[8+n] != 0)
-			usb_string(udev, buffer[8+n], unit->name,
-				   sizeof(unit->name));
-		else
+		if (buffer[8+n] == 0 ||
+		    usb_string(udev, buffer[8+n], unit->name, sizeof(unit->name)) < 0)
 			sprintf(unit->name, "Processing %u", buffer[3]);
 
 		list_add_tail(&unit->list, &dev->entities);
@@ -1298,10 +1314,8 @@
 		unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
 		memcpy(unit->extension.bmControls, &buffer[23+p], n);
 
-		if (buffer[23+p+n] != 0)
-			usb_string(udev, buffer[23+p+n], unit->name,
-				   sizeof(unit->name));
-		else
+		if (buffer[23+p+n] == 0 ||
+		    usb_string(udev, buffer[23+p+n], unit->name, sizeof(unit->name)) < 0)
 			sprintf(unit->name, "Extension %u", buffer[3]);
 
 		list_add_tail(&unit->list, &dev->entities);
@@ -1493,6 +1507,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:
@@ -1574,6 +1593,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(KERN_CONT " %d", term->id);
 
@@ -2151,6 +2177,20 @@
 			   sizeof(dev->name) - len);
 	}
 
+	/* Initialize the media device. */
+#ifdef CONFIG_MEDIA_CONTROLLER
+	dev->mdev.dev = &intf->dev;
+	strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+	if (udev->serial)
+		strscpy(dev->mdev.serial, udev->serial,
+			sizeof(dev->mdev.serial));
+	usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info));
+	dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+	media_device_init(&dev->mdev);
+
+	dev->vdev.mdev = &dev->mdev;
+#endif
+
 	/* Parse the Video Class control descriptor. */
 	if (uvc_parse_control(dev) < 0) {
 		uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
@@ -2171,19 +2211,7 @@
 			"linux-uvc-devel mailing list.\n");
 	}
 
-	/* Initialize the media device and register the V4L2 device. */
-#ifdef CONFIG_MEDIA_CONTROLLER
-	dev->mdev.dev = &intf->dev;
-	strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
-	if (udev->serial)
-		strscpy(dev->mdev.serial, udev->serial,
-			sizeof(dev->mdev.serial));
-	usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info));
-	dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
-	media_device_init(&dev->mdev);
-
-	dev->vdev.mdev = &dev->mdev;
-#endif
+	/* Register the V4L2 device. */
 	if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
 		goto error;
 
@@ -2439,6 +2467,24 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= (kernel_ulong_t)&uvc_quirk_probe_minmax },
+	/* Logitech, Webcam C910 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x0821,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)},
+	/* Logitech, Webcam B910 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x0823,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)},
 	/* Logitech Quickcam Fusion */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2860,6 +2906,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= (kernel_ulong_t)&uvc_quirk_force_y8 },
+	/* GEO Semiconductor GC6500 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x29fe,
+	  .idProduct		= 0x4d53,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
 	/* Intel RealSense D4M */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_entity.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_entity.c
@@ -37,7 +37,7 @@
 			continue;
 
 		remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
-		if (remote == NULL)
+		if (remote == NULL || remote->num_pads == 0)
 			return -EINVAL;
 
 		source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
@@ -73,10 +73,45 @@
 	int ret;
 
 	if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
+		u32 function;
+
 		v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
 		strscpy(entity->subdev.name, entity->name,
 			sizeof(entity->subdev.name));
 
+		switch (UVC_ENTITY_TYPE(entity)) {
+		case UVC_VC_SELECTOR_UNIT:
+			function = MEDIA_ENT_F_VID_MUX;
+			break;
+		case UVC_VC_PROCESSING_UNIT:
+		case UVC_VC_EXTENSION_UNIT:
+			/* For lack of a better option. */
+			function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+			break;
+		case UVC_COMPOSITE_CONNECTOR:
+		case UVC_COMPONENT_CONNECTOR:
+			function = MEDIA_ENT_F_CONN_COMPOSITE;
+			break;
+		case UVC_SVIDEO_CONNECTOR:
+			function = MEDIA_ENT_F_CONN_SVIDEO;
+			break;
+		case UVC_ITT_CAMERA:
+			function = MEDIA_ENT_F_CAM_SENSOR;
+			break;
+		case UVC_TT_VENDOR_SPECIFIC:
+		case UVC_ITT_VENDOR_SPECIFIC:
+		case UVC_ITT_MEDIA_TRANSPORT_INPUT:
+		case UVC_OTT_VENDOR_SPECIFIC:
+		case UVC_OTT_DISPLAY:
+		case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+		case UVC_EXTERNAL_VENDOR_SPECIFIC:
+		default:
+			function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+			break;
+		}
+
+		entity->subdev.entity.function = function;
+
 		ret = media_entity_pads_init(&entity->subdev.entity,
 					entity->num_pads, entity->pads);
 
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_status.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_status.c
@@ -6,6 +6,7 @@
  *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  */
 
+#include <asm/barrier.h>
 #include <linux/kernel.h>
 #include <linux/input.h>
 #include <linux/slab.h>
@@ -179,7 +180,8 @@
 
 	switch (status->bAttribute) {
 	case UVC_CTRL_VALUE_CHANGE:
-		return uvc_ctrl_status_event(urb, chain, ctrl, status->bValue);
+		return uvc_ctrl_status_event_async(urb, chain, ctrl,
+						   status->bValue);
 
 	case UVC_CTRL_INFO_CHANGE:
 	case UVC_CTRL_FAILURE_CHANGE:
@@ -309,5 +311,41 @@
 
 void uvc_status_stop(struct uvc_device *dev)
 {
+	struct uvc_ctrl_work *w = &dev->async_ctrl;
+
+	/*
+	 * Prevent the asynchronous control handler from requeing the URB. The
+	 * barrier is needed so the flush_status change is visible to other
+	 * CPUs running the asynchronous handler before usb_kill_urb() is
+	 * called below.
+	 */
+	smp_store_release(&dev->flush_status, true);
+
+	/*
+	 * Cancel any pending asynchronous work. If any status event was queued,
+	 * process it synchronously.
+	 */
+	if (cancel_work_sync(&w->work))
+		uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+
+	/* Kill the urb. */
 	usb_kill_urb(dev->int_urb);
+
+	/*
+	 * The URB completion handler may have queued asynchronous work. This
+	 * won't resubmit the URB as flush_status is set, but it needs to be
+	 * cancelled before returning or it could then race with a future
+	 * uvc_status_start() call.
+	 */
+	if (cancel_work_sync(&w->work))
+		uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+
+	/*
+	 * From this point, there are no events on the queue and the status URB
+	 * is dead. No events will be queued until uvc_status_start() is called.
+	 * The barrier is needed to make sure that flush_status is visible to
+	 * uvc_ctrl_status_event_work() when uvc_status_start() will be called
+	 * again.
+	 */
+	smp_store_release(&dev->flush_status, false);
 }
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_v4l2.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_v4l2.c
@@ -247,11 +247,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 = uvc_v4l2_get_bytesperline(format, frame);
 	fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+	fmt->fmt.pix.pixelformat = format->fcc;
 	fmt->fmt.pix.colorspace = format->colorspace;
 
 	if (uvc_format != NULL)
@@ -437,10 +467,13 @@
 	uvc_simplify_fraction(&timeperframe.numerator,
 		&timeperframe.denominator, 8, 333);
 
-	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		parm->parm.capture.timeperframe = timeperframe;
-	else
+		parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	} else {
 		parm->parm.output.timeperframe = timeperframe;
+		parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+	}
 
 	return 0;
 }
@@ -826,29 +859,31 @@
 	struct uvc_video_chain *chain = handle->chain;
 	const struct uvc_entity *selector = chain->selector;
 	struct uvc_entity *iterm = NULL;
+	struct uvc_entity *it;
 	u32 index = input->index;
-	int pin = 0;
 
 	if (selector == NULL ||
 	    (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
 		if (index != 0)
 			return -EINVAL;
-		list_for_each_entry(iterm, &chain->entities, chain) {
-			if (UVC_ENTITY_IS_ITERM(iterm))
+		list_for_each_entry(it, &chain->entities, chain) {
+			if (UVC_ENTITY_IS_ITERM(it)) {
+				iterm = it;
 				break;
+			}
 		}
-		pin = iterm->id;
 	} else if (index < selector->bNrInPins) {
-		pin = selector->baSourceID[index];
-		list_for_each_entry(iterm, &chain->entities, chain) {
-			if (!UVC_ENTITY_IS_ITERM(iterm))
+		list_for_each_entry(it, &chain->entities, chain) {
+			if (!UVC_ENTITY_IS_ITERM(it))
 				continue;
-			if (iterm->id == pin)
+			if (it->id == selector->baSourceID[index]) {
+				iterm = it;
 				break;
+			}
 		}
 	}
 
-	if (iterm == NULL || iterm->id != pin)
+	if (iterm == NULL)
 		return -EINVAL;
 
 	memset(input, 0, sizeof(*input));
@@ -864,8 +899,8 @@
 {
 	struct uvc_fh *handle = fh;
 	struct uvc_video_chain *chain = handle->chain;
+	u8 *buf;
 	int ret;
-	u8 i;
 
 	if (chain->selector == NULL ||
 	    (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
@@ -873,22 +908,27 @@
 		return 0;
 	}
 
+	buf = kmalloc(1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
 	ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, chain->selector->id,
 			     chain->dev->intfnum,  UVC_SU_INPUT_SELECT_CONTROL,
-			     &i, 1);
-	if (ret < 0)
-		return ret;
+			     buf, 1);
+	if (!ret)
+		*input = *buf - 1;
 
-	*input = i - 1;
-	return 0;
+	kfree(buf);
+
+	return ret;
 }
 
 static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
 {
 	struct uvc_fh *handle = fh;
 	struct uvc_video_chain *chain = handle->chain;
+	u8 *buf;
 	int ret;
-	u32 i;
 
 	ret = uvc_acquire_privileges(handle);
 	if (ret < 0)
@@ -904,10 +944,17 @@
 	if (input >= chain->selector->bNrInPins)
 		return -EINVAL;
 
-	i = input + 1;
-	return uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id,
-			      chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL,
-			      &i, 1);
+	buf = kmalloc(1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	*buf = input + 1;
+	ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id,
+			     chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL,
+			     buf, 1);
+	kfree(buf);
+
+	return ret;
 }
 
 static int uvc_ioctl_queryctrl(struct file *file, void *fh,
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvc_video.c
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvc_video.c
@@ -112,6 +112,11 @@
 	case 5: /* Invalid unit */
 	case 6: /* Invalid control */
 	case 7: /* Invalid Request */
+		/*
+		 * The firmware has not properly implemented
+		 * the control or there has been a HW error.
+		 */
+		return -EIO;
 	case 8: /* Invalid value within range */
 		return -EINVAL;
 	default: /* reserved or unknown */
@@ -124,10 +129,37 @@
 static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
 	struct uvc_streaming_control *ctrl)
 {
+	static const struct usb_device_id elgato_cam_link_4k = {
+		USB_DEVICE(0x0fd9, 0x0066)
+	};
 	struct uvc_format *format = NULL;
 	struct uvc_frame *frame = NULL;
 	unsigned int i;
 
+	/*
+	 * The response of the Elgato Cam Link 4K is incorrect: The second byte
+	 * contains bFormatIndex (instead of being the second byte of bmHint).
+	 * The first byte is always zero. The third byte is always 1.
+	 *
+	 * The UVC 1.5 class specification defines the first five bits in the
+	 * bmHint bitfield. The remaining bits are reserved and should be zero.
+	 * Therefore a valid bmHint will be less than 32.
+	 *
+	 * Latest Elgato Cam Link 4K firmware as of 2021-03-23 needs this fix.
+	 * MCU: 20.02.19, FPGA: 67
+	 */
+	if (usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k) &&
+	    ctrl->bmHint > 255) {
+		u8 corrected_format_index = ctrl->bmHint >> 8;
+
+		uvc_trace(UVC_TRACE_VIDEO,
+			"Correct USB video probe response from {bmHint: 0x%04x, bFormatIndex: %u} to {bmHint: 0x%04x, bFormatIndex: %u}\n",
+			ctrl->bmHint, ctrl->bFormatIndex,
+			1, corrected_format_index);
+		ctrl->bmHint = 1;
+		ctrl->bFormatIndex = corrected_format_index;
+	}
+
 	for (i = 0; i < stream->nformats; ++i) {
 		if (stream->format[i].index == ctrl->bFormatIndex) {
 			format = &stream->format[i];
@@ -765,9 +797,9 @@
 	unsigned int header_size;
 	bool has_pts = false;
 	bool has_scr = false;
-	u16 uninitialized_var(scr_sof);
-	u32 uninitialized_var(scr_stc);
-	u32 uninitialized_var(pts);
+	u16 scr_sof;
+	u32 scr_stc;
+	u32 pts;
 
 	if (stream->stats.stream.nb_frames == 0 &&
 	    stream->stats.frame.nb_packets == 0)
@@ -1276,7 +1308,9 @@
 	if (has_scr)
 		memcpy(stream->clock.last_scr, scr, 6);
 
-	memcpy(&meta->length, mem, length);
+	meta->length = mem[0];
+	meta->flags  = mem[1];
+	memcpy(meta->buf, &mem[2], length - 2);
 	meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
 
 	uvc_trace(UVC_TRACE_FRAME,
@@ -1828,7 +1862,7 @@
 		struct usb_host_endpoint *best_ep = NULL;
 		unsigned int best_psize = UINT_MAX;
 		unsigned int bandwidth;
-		unsigned int uninitialized_var(altsetting);
+		unsigned int altsetting;
 		int intfnum = stream->intfnum;
 
 		/* Isochronous endpoint, select the alternate setting. */
@@ -1871,6 +1905,17 @@
 		uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
 			"(%u B/frame bandwidth).\n", altsetting, best_psize);
 
+		/*
+		 * Some devices, namely the Logitech C910 and B910, are unable
+		 * to recover from a USB autosuspend, unless the alternate
+		 * setting of the streaming interface is toggled.
+		 */
+		if (stream->dev->quirks & UVC_QUIRK_WAKE_AUTOSUSPEND) {
+			usb_set_interface(stream->dev->udev, intfnum,
+					  altsetting);
+			usb_set_interface(stream->dev->udev, intfnum, 0);
+		}
+
 		ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
 		if (ret < 0)
 			return ret;
@@ -1883,6 +1928,10 @@
 		if (ep == NULL)
 			return -EIO;
 
+		/* Reject broken descriptors. */
+		if (usb_endpoint_maxp(&ep->desc) == 0)
+			return -EIO;
+
 		ret = uvc_init_video_bulk(stream, ep, gfp_flags);
 	}
 
--- linux-ein-5.4.0.orig/drivers/media/usb/uvc/uvcvideo.h
+++ linux-ein-5.4.0/drivers/media/usb/uvc/uvcvideo.h
@@ -165,6 +165,10 @@
 	{0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
 	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
+#define UVC_GUID_FORMAT_HEVC \
+	{ 'H',  'E',  'V',  'C', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
 
 /* ------------------------------------------------------------------------
  * Driver specific constants.
@@ -179,7 +183,7 @@
 /* Maximum status buffer size in bytes of interrupt URB. */
 #define UVC_MAX_STATUS_SIZE	16
 
-#define UVC_CTRL_CONTROL_TIMEOUT	500
+#define UVC_CTRL_CONTROL_TIMEOUT	5000
 #define UVC_CTRL_STREAMING_TIMEOUT	5000
 
 /* Maximum allowed number of control mappings per device */
@@ -198,6 +202,8 @@
 #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200
 #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT	0x00000400
 #define UVC_QUIRK_FORCE_Y8		0x00000800
+#define UVC_QUIRK_FORCE_BPP		0x00001000
+#define UVC_QUIRK_WAKE_AUTOSUSPEND	0x00002000
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
@@ -662,6 +668,7 @@
 	/* Status Interrupt Endpoint */
 	struct usb_host_endpoint *int_ep;
 	struct urb *int_urb;
+	bool flush_status;
 	u8 *status;
 	struct input_dev *input;
 	char input_phys[64];
@@ -831,7 +838,9 @@
 int uvc_ctrl_init_device(struct uvc_device *dev);
 void uvc_ctrl_cleanup_device(struct uvc_device *dev);
 int uvc_ctrl_restore_values(struct uvc_device *dev);
-bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain,
+bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain,
+				 struct uvc_control *ctrl, const u8 *data);
+void uvc_ctrl_status_event(struct uvc_video_chain *chain,
 			   struct uvc_control *ctrl, const u8 *data);
 
 int uvc_ctrl_begin(struct uvc_video_chain *chain);
--- linux-ein-5.4.0.orig/drivers/media/usb/zr364xx/zr364xx.c
+++ linux-ein-5.4.0/drivers/media/usb/zr364xx/zr364xx.c
@@ -1037,6 +1037,7 @@
 	DBG("submitting URB %p\n", pipe_info->stream_urb);
 	retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
 	if (retval) {
+		usb_free_urb(pipe_info->stream_urb);
 		printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
 		return retval;
 	}
@@ -1186,15 +1187,11 @@
 	return err;
 }
 
-static void zr364xx_release(struct v4l2_device *v4l2_dev)
+static void zr364xx_board_uninit(struct zr364xx_camera *cam)
 {
-	struct zr364xx_camera *cam =
-		container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
 	unsigned long i;
 
-	v4l2_device_unregister(&cam->v4l2_dev);
-
-	videobuf_mmap_free(&cam->vb_vidq);
+	zr364xx_stop_readpipe(cam);
 
 	/* release sys buffers */
 	for (i = 0; i < FRAMES; i++) {
@@ -1205,9 +1202,19 @@
 		cam->buffer.frame[i].lpvbits = NULL;
 	}
 
-	v4l2_ctrl_handler_free(&cam->ctrl_handler);
 	/* release transfer buffer */
 	kfree(cam->pipe->transfer_buffer);
+}
+
+static void zr364xx_release(struct v4l2_device *v4l2_dev)
+{
+	struct zr364xx_camera *cam =
+		container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
+
+	videobuf_mmap_free(&cam->vb_vidq);
+	v4l2_ctrl_handler_free(&cam->ctrl_handler);
+	zr364xx_board_uninit(cam);
+	v4l2_device_unregister(&cam->v4l2_dev);
 	kfree(cam);
 }
 
@@ -1330,6 +1337,7 @@
 {
 	struct zr364xx_pipeinfo *pipe = cam->pipe;
 	unsigned long i;
+	int err;
 
 	DBG("board init: %p\n", cam);
 	memset(pipe, 0, sizeof(*pipe));
@@ -1362,9 +1370,8 @@
 
 	if (i == 0) {
 		printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
-		kfree(cam->pipe->transfer_buffer);
-		cam->pipe->transfer_buffer = NULL;
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto err_free;
 	} else
 		cam->buffer.dwFrames = i;
 
@@ -1379,9 +1386,20 @@
 	/*** end create system buffers ***/
 
 	/* start read pipe */
-	zr364xx_start_readpipe(cam);
+	err = zr364xx_start_readpipe(cam);
+	if (err)
+		goto err_free_frames;
+
 	DBG(": board initialized\n");
 	return 0;
+
+err_free_frames:
+	for (i = 0; i < FRAMES; i++)
+		vfree(cam->buffer.frame[i].lpvbits);
+err_free:
+	kfree(cam->pipe->transfer_buffer);
+	cam->pipe->transfer_buffer = NULL;
+	return err;
 }
 
 static int zr364xx_probe(struct usb_interface *intf,
@@ -1406,12 +1424,10 @@
 	if (!cam)
 		return -ENOMEM;
 
-	cam->v4l2_dev.release = zr364xx_release;
 	err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
 	if (err < 0) {
 		dev_err(&udev->dev, "couldn't register v4l2_device\n");
-		kfree(cam);
-		return err;
+		goto free_cam;
 	}
 	hdl = &cam->ctrl_handler;
 	v4l2_ctrl_handler_init(hdl, 1);
@@ -1420,7 +1436,7 @@
 	if (hdl->error) {
 		err = hdl->error;
 		dev_err(&udev->dev, "couldn't register control\n");
-		goto fail;
+		goto free_hdlr_and_unreg_dev;
 	}
 	/* save the init method used by this camera */
 	cam->method = id->driver_info;
@@ -1493,7 +1509,7 @@
 	if (!cam->read_endpoint) {
 		err = -ENOMEM;
 		dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
-		goto fail;
+		goto free_hdlr_and_unreg_dev;
 	}
 
 	/* v4l */
@@ -1504,10 +1520,11 @@
 
 	/* load zr364xx board specific */
 	err = zr364xx_board_init(cam);
-	if (!err)
-		err = v4l2_ctrl_handler_setup(hdl);
 	if (err)
-		goto fail;
+		goto free_hdlr_and_unreg_dev;
+	err = v4l2_ctrl_handler_setup(hdl);
+	if (err)
+		goto board_uninit;
 
 	spin_lock_init(&cam->slock);
 
@@ -1522,16 +1539,20 @@
 	err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
 	if (err) {
 		dev_err(&udev->dev, "video_register_device failed\n");
-		goto fail;
+		goto board_uninit;
 	}
+	cam->v4l2_dev.release = zr364xx_release;
 
 	dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n",
 		 video_device_node_name(&cam->vdev));
 	return 0;
 
-fail:
+board_uninit:
+	zr364xx_board_uninit(cam);
+free_hdlr_and_unreg_dev:
 	v4l2_ctrl_handler_free(hdl);
 	v4l2_device_unregister(&cam->v4l2_dev);
+free_cam:
 	kfree(cam);
 	return err;
 }
@@ -1578,10 +1599,19 @@
 	if (!cam->was_streaming)
 		return 0;
 
-	zr364xx_start_readpipe(cam);
+	res = zr364xx_start_readpipe(cam);
+	if (res)
+		return res;
+
 	res = zr364xx_prepare(cam);
-	if (!res)
-		zr364xx_start_acquire(cam);
+	if (res)
+		goto err_prepare;
+
+	zr364xx_start_acquire(cam);
+	return 0;
+
+err_prepare:
+	zr364xx_stop_readpipe(cam);
 	return res;
 }
 #endif
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1183,36 +1183,38 @@
 	u32 aux_space;
 	int compatible_arg = 1;
 	long err = 0;
+	unsigned int ncmd;
 
 	/*
 	 * 1. When struct size is different, converts the command.
 	 */
 	switch (cmd) {
-	case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
-	case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
-	case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
-	case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
-	case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
-	case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
-	case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
-	case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
-	case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
-	case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
-	case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
-	case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
-	case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
-	case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
-	case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
-	case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
-	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
-	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
-	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
-	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
-	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
-	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
-	case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
-	case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break;
-	case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break;
+	case VIDIOC_G_FMT32: ncmd = VIDIOC_G_FMT; break;
+	case VIDIOC_S_FMT32: ncmd = VIDIOC_S_FMT; break;
+	case VIDIOC_QUERYBUF32: ncmd = VIDIOC_QUERYBUF; break;
+	case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break;
+	case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break;
+	case VIDIOC_QBUF32: ncmd = VIDIOC_QBUF; break;
+	case VIDIOC_DQBUF32: ncmd = VIDIOC_DQBUF; break;
+	case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break;
+	case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break;
+	case VIDIOC_TRY_FMT32: ncmd = VIDIOC_TRY_FMT; break;
+	case VIDIOC_G_EXT_CTRLS32: ncmd = VIDIOC_G_EXT_CTRLS; break;
+	case VIDIOC_S_EXT_CTRLS32: ncmd = VIDIOC_S_EXT_CTRLS; break;
+	case VIDIOC_TRY_EXT_CTRLS32: ncmd = VIDIOC_TRY_EXT_CTRLS; break;
+	case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break;
+	case VIDIOC_OVERLAY32: ncmd = VIDIOC_OVERLAY; break;
+	case VIDIOC_STREAMON32: ncmd = VIDIOC_STREAMON; break;
+	case VIDIOC_STREAMOFF32: ncmd = VIDIOC_STREAMOFF; break;
+	case VIDIOC_G_INPUT32: ncmd = VIDIOC_G_INPUT; break;
+	case VIDIOC_S_INPUT32: ncmd = VIDIOC_S_INPUT; break;
+	case VIDIOC_G_OUTPUT32: ncmd = VIDIOC_G_OUTPUT; break;
+	case VIDIOC_S_OUTPUT32: ncmd = VIDIOC_S_OUTPUT; break;
+	case VIDIOC_CREATE_BUFS32: ncmd = VIDIOC_CREATE_BUFS; break;
+	case VIDIOC_PREPARE_BUF32: ncmd = VIDIOC_PREPARE_BUF; break;
+	case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break;
+	case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break;
+	default: ncmd = cmd; break;
 	}
 
 	/*
@@ -1221,11 +1223,11 @@
 	 * argument into it.
 	 */
 	switch (cmd) {
-	case VIDIOC_OVERLAY:
-	case VIDIOC_STREAMON:
-	case VIDIOC_STREAMOFF:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_OUTPUT:
+	case VIDIOC_OVERLAY32:
+	case VIDIOC_STREAMON32:
+	case VIDIOC_STREAMOFF32:
+	case VIDIOC_S_INPUT32:
+	case VIDIOC_S_OUTPUT32:
 		err = alloc_userspace(sizeof(unsigned int), 0, &new_p64);
 		if (!err && assign_in_user((unsigned int __user *)new_p64,
 					   (compat_uint_t __user *)p32))
@@ -1233,23 +1235,23 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_G_INPUT:
-	case VIDIOC_G_OUTPUT:
+	case VIDIOC_G_INPUT32:
+	case VIDIOC_G_OUTPUT32:
 		err = alloc_userspace(sizeof(unsigned int), 0, &new_p64);
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_G_EDID:
-	case VIDIOC_S_EDID:
+	case VIDIOC_G_EDID32:
+	case VIDIOC_S_EDID32:
 		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
 		if (!err)
 			err = get_v4l2_edid32(new_p64, p32);
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
+	case VIDIOC_G_FMT32:
+	case VIDIOC_S_FMT32:
+	case VIDIOC_TRY_FMT32:
 		err = bufsize_v4l2_format(p32, &aux_space);
 		if (!err)
 			err = alloc_userspace(sizeof(struct v4l2_format),
@@ -1262,7 +1264,7 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_CREATE_BUFS:
+	case VIDIOC_CREATE_BUFS32:
 		err = bufsize_v4l2_create(p32, &aux_space);
 		if (!err)
 			err = alloc_userspace(sizeof(struct v4l2_create_buffers),
@@ -1275,10 +1277,10 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_PREPARE_BUF:
-	case VIDIOC_QUERYBUF:
-	case VIDIOC_QBUF:
-	case VIDIOC_DQBUF:
+	case VIDIOC_PREPARE_BUF32:
+	case VIDIOC_QUERYBUF32:
+	case VIDIOC_QBUF32:
+	case VIDIOC_DQBUF32:
 		err = bufsize_v4l2_buffer(p32, &aux_space);
 		if (!err)
 			err = alloc_userspace(sizeof(struct v4l2_buffer),
@@ -1291,7 +1293,7 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_S_FBUF:
+	case VIDIOC_S_FBUF32:
 		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
 				      &new_p64);
 		if (!err)
@@ -1299,13 +1301,13 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_G_FBUF:
+	case VIDIOC_G_FBUF32:
 		err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
 				      &new_p64);
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_ENUMSTD:
+	case VIDIOC_ENUMSTD32:
 		err = alloc_userspace(sizeof(struct v4l2_standard), 0,
 				      &new_p64);
 		if (!err)
@@ -1313,16 +1315,16 @@
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_ENUMINPUT:
+	case VIDIOC_ENUMINPUT32:
 		err = alloc_userspace(sizeof(struct v4l2_input), 0, &new_p64);
 		if (!err)
 			err = get_v4l2_input32(new_p64, p32);
 		compatible_arg = 0;
 		break;
 
-	case VIDIOC_G_EXT_CTRLS:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS32:
+	case VIDIOC_S_EXT_CTRLS32:
+	case VIDIOC_TRY_EXT_CTRLS32:
 		err = bufsize_v4l2_ext_controls(p32, &aux_space);
 		if (!err)
 			err = alloc_userspace(sizeof(struct v4l2_ext_controls),
@@ -1334,7 +1336,7 @@
 		}
 		compatible_arg = 0;
 		break;
-	case VIDIOC_DQEVENT:
+	case VIDIOC_DQEVENT32:
 		err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64);
 		compatible_arg = 0;
 		break;
@@ -1352,9 +1354,9 @@
 	 * Otherwise, it will pass the newly allocated @new_p64 argument.
 	 */
 	if (compatible_arg)
-		err = native_ioctl(file, cmd, (unsigned long)p32);
+		err = native_ioctl(file, ncmd, (unsigned long)p32);
 	else
-		err = native_ioctl(file, cmd, (unsigned long)new_p64);
+		err = native_ioctl(file, ncmd, (unsigned long)new_p64);
 
 	if (err == -ENOTTY)
 		return err;
@@ -1370,13 +1372,13 @@
 	 * the blocks to maximum allowed value.
 	 */
 	switch (cmd) {
-	case VIDIOC_G_EXT_CTRLS:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS32:
+	case VIDIOC_S_EXT_CTRLS32:
+	case VIDIOC_TRY_EXT_CTRLS32:
 		if (put_v4l2_ext_controls32(file, new_p64, p32))
 			err = -EFAULT;
 		break;
-	case VIDIOC_S_EDID:
+	case VIDIOC_S_EDID32:
 		if (put_v4l2_edid32(new_p64, p32))
 			err = -EFAULT;
 		break;
@@ -1389,49 +1391,49 @@
 	 * the original 32 bits structure.
 	 */
 	switch (cmd) {
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_OUTPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_G_OUTPUT:
+	case VIDIOC_S_INPUT32:
+	case VIDIOC_S_OUTPUT32:
+	case VIDIOC_G_INPUT32:
+	case VIDIOC_G_OUTPUT32:
 		if (assign_in_user((compat_uint_t __user *)p32,
 				   ((unsigned int __user *)new_p64)))
 			err = -EFAULT;
 		break;
 
-	case VIDIOC_G_FBUF:
+	case VIDIOC_G_FBUF32:
 		err = put_v4l2_framebuffer32(new_p64, p32);
 		break;
 
-	case VIDIOC_DQEVENT:
+	case VIDIOC_DQEVENT32:
 		err = put_v4l2_event32(new_p64, p32);
 		break;
 
-	case VIDIOC_G_EDID:
+	case VIDIOC_G_EDID32:
 		err = put_v4l2_edid32(new_p64, p32);
 		break;
 
-	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
+	case VIDIOC_G_FMT32:
+	case VIDIOC_S_FMT32:
+	case VIDIOC_TRY_FMT32:
 		err = put_v4l2_format32(new_p64, p32);
 		break;
 
-	case VIDIOC_CREATE_BUFS:
+	case VIDIOC_CREATE_BUFS32:
 		err = put_v4l2_create32(new_p64, p32);
 		break;
 
-	case VIDIOC_PREPARE_BUF:
-	case VIDIOC_QUERYBUF:
-	case VIDIOC_QBUF:
-	case VIDIOC_DQBUF:
+	case VIDIOC_PREPARE_BUF32:
+	case VIDIOC_QUERYBUF32:
+	case VIDIOC_QBUF32:
+	case VIDIOC_DQBUF32:
 		err = put_v4l2_buffer32(new_p64, p32);
 		break;
 
-	case VIDIOC_ENUMSTD:
+	case VIDIOC_ENUMSTD32:
 		err = put_v4l2_standard32(new_p64, p32);
 		break;
 
-	case VIDIOC_ENUMINPUT:
+	case VIDIOC_ENUMINPUT32:
 		err = put_v4l2_input32(new_p64, p32);
 		break;
 	}
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-ctrls.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1795,7 +1795,8 @@
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
 		if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
 			return -ERANGE;
-		if (ctrl->menu_skip_mask & (1ULL << ptr.p_s32[idx]))
+		if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
+		    (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
 			return -EINVAL;
 		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
 		    ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
@@ -2154,7 +2155,15 @@
 	if (hdl == NULL || hdl->buckets == NULL)
 		return;
 
-	if (!hdl->req_obj.req && !list_empty(&hdl->requests)) {
+	/*
+	 * If the main handler is freed and it is used by handler objects in
+	 * outstanding requests, then unbind and put those objects before
+	 * freeing the main handler.
+	 *
+	 * The main handler can be identified by having a NULL ops pointer in
+	 * the request object.
+	 */
+	if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) {
 		struct v4l2_ctrl_handler *req, *next_req;
 
 		list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
@@ -3144,6 +3153,7 @@
 	struct v4l2_ctrl_handler *prev_hdl = NULL;
 	struct v4l2_ctrl_ref *ref_ctrl, *ref_ctrl_prev = NULL;
 
+	mutex_lock(main_hdl->lock);
 	if (list_empty(&main_hdl->requests_queued))
 		goto queue;
 
@@ -3175,18 +3185,22 @@
 queue:
 	list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
 	hdl->request_is_queued = true;
+	mutex_unlock(main_hdl->lock);
 }
 
 static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
 {
 	struct v4l2_ctrl_handler *hdl =
 		container_of(obj, struct v4l2_ctrl_handler, req_obj);
+	struct v4l2_ctrl_handler *main_hdl = obj->priv;
 
+	mutex_lock(main_hdl->lock);
 	list_del_init(&hdl->requests);
 	if (hdl->request_is_queued) {
 		list_del_init(&hdl->requests_queued);
 		hdl->request_is_queued = false;
 	}
+	mutex_unlock(main_hdl->lock);
 }
 
 static void v4l2_ctrl_request_release(struct media_request_object *obj)
@@ -3240,8 +3254,11 @@
 	if (!ret) {
 		ret = media_request_object_bind(req, &req_ops,
 						from, false, &hdl->req_obj);
-		if (!ret)
+		if (!ret) {
+			mutex_lock(from->lock);
 			list_add_tail(&hdl->requests, &from->requests);
+			mutex_unlock(from->lock);
+		}
 	}
 	return ret;
 }
@@ -4128,9 +4145,11 @@
 		v4l2_ctrl_unlock(ctrl);
 	}
 
+	mutex_lock(main_hdl->lock);
 	WARN_ON(!hdl->request_is_queued);
 	list_del_init(&hdl->requests_queued);
 	hdl->request_is_queued = false;
+	mutex_unlock(main_hdl->lock);
 	media_request_object_complete(obj);
 	media_request_object_put(obj);
 }
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-dev.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-dev.c
@@ -579,6 +579,7 @@
 	set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
 	set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
 #endif
+	SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
 	/* yes, really vidioc_subscribe_event */
 	SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
 	SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-device.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-device.c
@@ -179,6 +179,7 @@
 
 	if (sd->internal_ops && sd->internal_ops->release)
 		sd->internal_ops->release(sd);
+	sd->devnode = NULL;
 	module_put(owner);
 }
 
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -145,6 +145,8 @@
 	const struct v4l2_bt_timings *bt = &t->bt;
 	const struct v4l2_bt_timings_cap *cap = &dvcap->bt;
 	u32 caps = cap->capabilities;
+	const u32 max_vert = 10240;
+	u32 max_hor = 3 * bt->width;
 
 	if (t->type != V4L2_DV_BT_656_1120)
 		return false;
@@ -161,6 +163,26 @@
 	    (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
 	    (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
 		return false;
+
+	/* sanity checks for the blanking timings */
+	if (!bt->interlaced &&
+	    (bt->il_vbackporch || bt->il_vsync || bt->il_vfrontporch))
+		return false;
+	/*
+	 * Some video receivers cannot properly separate the frontporch,
+	 * backporch and sync values, and instead they only have the total
+	 * blanking. That can be assigned to any of these three fields.
+	 * So just check that none of these are way out of range.
+	 */
+	if (bt->hfrontporch > max_hor ||
+	    bt->hsync > max_hor || bt->hbackporch > max_hor)
+		return false;
+	if (bt->vfrontporch > max_vert ||
+	    bt->vsync > max_vert || bt->vbackporch > max_vert)
+		return false;
+	if (bt->interlaced && (bt->il_vfrontporch > max_vert ||
+	    bt->il_vsync > max_vert || bt->il_vbackporch > max_vert))
+		return false;
 	return fnc == NULL || fnc(t, fnc_handle);
 }
 EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings);
@@ -196,7 +218,7 @@
 	if (!v4l2_valid_dv_timings(t, cap, fnc, fnc_handle))
 		return false;
 
-	for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) {
+	for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
 		if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap,
 					  fnc, fnc_handle) &&
 		    v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i,
@@ -218,7 +240,7 @@
 {
 	unsigned int i;
 
-	for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) {
+	for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
 		const struct v4l2_bt_timings *bt =
 			&v4l2_dv_timings_presets[i].bt;
 
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-fh.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-fh.c
@@ -96,6 +96,7 @@
 		v4l2_fh_del(fh);
 		v4l2_fh_exit(fh);
 		kfree(fh);
+		filp->private_data = NULL;
 	}
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-fwnode.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -93,7 +93,7 @@
 	const struct v4l2_fwnode_bus_conv *conv =
 		get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
 
-	return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
+	return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
 }
 
 static const char *
@@ -436,6 +436,10 @@
 		 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
 		 vep->bus_type);
 	mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
+	if (mbus_type == V4L2_MBUS_INVALID) {
+		pr_debug("unsupported bus type %u\n", bus_type);
+		return -EINVAL;
+	}
 
 	if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
 		if (mbus_type != V4L2_MBUS_UNKNOWN &&
@@ -556,35 +560,38 @@
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
 
-int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
+int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
 			   struct v4l2_fwnode_link *link)
 {
-	const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
-	struct fwnode_handle *fwnode;
+	struct fwnode_endpoint fwep;
 
 	memset(link, 0, sizeof(*link));
 
-	fwnode = fwnode_get_parent(__fwnode);
-	fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
-	fwnode = fwnode_get_next_parent(fwnode);
-	if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
-		fwnode = fwnode_get_next_parent(fwnode);
-	link->local_node = fwnode;
-
-	fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
-	if (!fwnode) {
-		fwnode_handle_put(fwnode);
+	fwnode_graph_parse_endpoint(fwnode, &fwep);
+	link->local_port = fwep.port;
+	link->local_node = fwnode_graph_get_port_parent(fwnode);
+	if (!link->local_node)
 		return -ENOLINK;
-	}
 
-	fwnode = fwnode_get_parent(fwnode);
-	fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
-	fwnode = fwnode_get_next_parent(fwnode);
-	if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
-		fwnode = fwnode_get_next_parent(fwnode);
-	link->remote_node = fwnode;
+	fwnode = fwnode_graph_get_remote_endpoint(fwnode);
+	if (!fwnode)
+		goto err_put_local_node;
+
+	fwnode_graph_parse_endpoint(fwnode, &fwep);
+	link->remote_port = fwep.port;
+	link->remote_node = fwnode_graph_get_port_parent(fwnode);
+	if (!link->remote_node)
+		goto err_put_remote_endpoint;
 
 	return 0;
+
+err_put_remote_endpoint:
+	fwnode_handle_put(fwnode);
+
+err_put_local_node:
+	fwnode_handle_put(link->local_node);
+
+	return -ENOLINK;
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
 
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-ioctl.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -26,6 +26,8 @@
 #include <media/videobuf2-v4l2.h>
 #include <media/v4l2-mc.h>
 #include <media/v4l2-mem2mem.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf2-core.h>
 
 #include <trace/events/v4l2.h>
 
@@ -674,6 +676,20 @@
 		pr_info("pts=%llu\n", p->stop.pts);
 }
 
+static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
+{
+	const struct v4l2_dbg_chip_ident *p = arg;
+
+	pr_cont("type=%u, ", p->match.type);
+	if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		pr_cont("name=%.*s, ",
+				(int)sizeof(p->match.name), p->match.name);
+	else
+		pr_cont("addr=%u, ", p->match.addr);
+	pr_cont("chip_ident=%u, revision=0x%x\n",
+			p->ident, p->revision);
+}
+
 static void v4l_print_dbg_chip_info(const void *arg, bool write_only)
 {
 	const struct v4l2_dbg_chip_info *p = arg;
@@ -902,7 +918,7 @@
 	pr_cont("driver-specific ioctl\n");
 }
 
-static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+static bool check_ext_ctrls(struct v4l2_ext_controls *c, unsigned long ioctl)
 {
 	__u32 i;
 
@@ -911,23 +927,41 @@
 	for (i = 0; i < c->count; i++)
 		c->controls[i].reserved2[0] = 0;
 
-	/* V4L2_CID_PRIVATE_BASE cannot be used as control class
-	   when using extended controls.
-	   Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
-	   is it allowed for backwards compatibility.
-	 */
-	if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE)
-		return 0;
-	if (!c->which)
-		return 1;
+	switch (c->which) {
+	case V4L2_CID_PRIVATE_BASE:
+		/*
+		 * V4L2_CID_PRIVATE_BASE cannot be used as control class
+		 * when using extended controls.
+		 * Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
+		 * is it allowed for backwards compatibility.
+		 */
+		if (ioctl == VIDIOC_G_CTRL || ioctl == VIDIOC_S_CTRL)
+			return false;
+		break;
+	case V4L2_CTRL_WHICH_DEF_VAL:
+		/* Default value cannot be changed */
+		if (ioctl == VIDIOC_S_EXT_CTRLS ||
+		    ioctl == VIDIOC_TRY_EXT_CTRLS) {
+			c->error_idx = c->count;
+			return false;
+		}
+		return true;
+	case V4L2_CTRL_WHICH_CUR_VAL:
+		return true;
+	case V4L2_CTRL_WHICH_REQUEST_VAL:
+		c->error_idx = c->count;
+		return false;
+	}
+
 	/* Check that all controls are from the same control class. */
 	for (i = 0; i < c->count; i++) {
 		if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) {
-			c->error_idx = i;
-			return 0;
+			c->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i :
+								      c->count;
+			return false;
 		}
 	}
-	return 1;
+	return true;
 }
 
 static int check_fmt(struct file *file, enum v4l2_buf_type type)
@@ -1236,6 +1270,7 @@
 	case V4L2_PIX_FMT_YUV444:	descr = "16-bit A/XYUV 4-4-4-4"; break;
 	case V4L2_PIX_FMT_YUV555:	descr = "16-bit A/XYUV 1-5-5-5"; break;
 	case V4L2_PIX_FMT_YUV565:	descr = "16-bit YUV 5-6-5"; break;
+	case V4L2_PIX_FMT_YUV24:	descr = "24-bit YUV 4:4:4 8-8-8"; break;
 	case V4L2_PIX_FMT_YUV32:	descr = "32-bit A/XYUV 8-8-8-8"; break;
 	case V4L2_PIX_FMT_AYUV32:	descr = "32-bit AYUV 8-8-8-8"; break;
 	case V4L2_PIX_FMT_XYUV32:	descr = "32-bit XYUV 8-8-8-8"; break;
@@ -1466,10 +1501,26 @@
 	return ret;
 }
 
+static void v4l_pix_format_touch(struct v4l2_pix_format *p)
+{
+	/*
+	 * The v4l2_pix_format structure contains fields that make no sense for
+	 * touch. Set them to default values in this case.
+	 */
+
+	p->field = V4L2_FIELD_NONE;
+	p->colorspace = V4L2_COLORSPACE_RAW;
+	p->flags = 0;
+	p->ycbcr_enc = 0;
+	p->quantization = 0;
+	p->xfer_func = 0;
+}
+
 static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_format *p = arg;
+	struct video_device *vfd = video_devdata(file);
 	int ret = check_fmt(file, p->type);
 
 	if (ret)
@@ -1507,6 +1558,8 @@
 		ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
 		/* just in case the driver zeroed it again */
 		p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+		if (vfd->vfl_type == VFL_TYPE_TOUCH)
+			v4l_pix_format_touch(&p->fmt.pix);
 		return ret;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
@@ -1544,21 +1597,6 @@
 	return -EINVAL;
 }
 
-static void v4l_pix_format_touch(struct v4l2_pix_format *p)
-{
-	/*
-	 * The v4l2_pix_format structure contains fields that make no sense for
-	 * touch. Set them to default values in this case.
-	 */
-
-	p->field = V4L2_FIELD_NONE;
-	p->colorspace = V4L2_COLORSPACE_RAW;
-	p->flags = 0;
-	p->ycbcr_enc = 0;
-	p->quantization = 0;
-	p->xfer_func = 0;
-}
-
 static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -1602,12 +1640,12 @@
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 		if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.vbi);
+		CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
 		return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 		if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sliced);
+		CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
 		return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		if (unlikely(!ops->vidioc_s_fmt_vid_out))
@@ -1633,22 +1671,22 @@
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
 		if (unlikely(!ops->vidioc_s_fmt_vbi_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.vbi);
+		CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
 		return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 		if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sliced);
+		CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
 		return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 		if (unlikely(!ops->vidioc_s_fmt_sdr_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
 		return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
 		if (unlikely(!ops->vidioc_s_fmt_sdr_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
 		return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
 	case V4L2_BUF_TYPE_META_CAPTURE:
 		if (unlikely(!ops->vidioc_s_fmt_meta_cap))
@@ -1704,12 +1742,12 @@
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 		if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.vbi);
+		CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
 		return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 		if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sliced);
+		CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
 		return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		if (unlikely(!ops->vidioc_try_fmt_vid_out))
@@ -1735,22 +1773,22 @@
 	case V4L2_BUF_TYPE_VBI_OUTPUT:
 		if (unlikely(!ops->vidioc_try_fmt_vbi_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.vbi);
+		CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
 		return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 		if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sliced);
+		CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
 		return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
 		if (unlikely(!ops->vidioc_try_fmt_sdr_cap))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
 		return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
 	case V4L2_BUF_TYPE_SDR_OUTPUT:
 		if (unlikely(!ops->vidioc_try_fmt_sdr_out))
 			break;
-		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
 		return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
 	case V4L2_BUF_TYPE_META_CAPTURE:
 		if (unlikely(!ops->vidioc_try_fmt_meta_cap))
@@ -2025,6 +2063,7 @@
 static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
+	struct video_device *vfd = video_devdata(file);
 	struct v4l2_streamparm *p = arg;
 	v4l2_std_id std;
 	int ret = check_fmt(file, p->type);
@@ -2036,7 +2075,8 @@
 	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
 	    p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 		return -EINVAL;
-	p->parm.capture.readbuffers = 2;
+	if (vfd->device_caps & V4L2_CAP_READWRITE)
+		p->parm.capture.readbuffers = 2;
 	ret = ops->vidioc_g_std(file, fh, &std);
 	if (ret == 0)
 		v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe);
@@ -2049,22 +2089,7 @@
 	struct v4l2_streamparm *p = arg;
 	int ret = check_fmt(file, p->type);
 
-	if (ret)
-		return ret;
-
-	/* Note: extendedmode is never used in drivers */
-	if (V4L2_TYPE_IS_OUTPUT(p->type)) {
-		memset(p->parm.output.reserved, 0,
-		       sizeof(p->parm.output.reserved));
-		p->parm.output.extendedmode = 0;
-		p->parm.output.outputmode &= V4L2_MODE_HIGHQUALITY;
-	} else {
-		memset(p->parm.capture.reserved, 0,
-		       sizeof(p->parm.capture.reserved));
-		p->parm.capture.extendedmode = 0;
-		p->parm.capture.capturemode &= V4L2_MODE_HIGHQUALITY;
-	}
-	return ops->vidioc_s_parm(file, fh, p);
+	return ret ? ret : ops->vidioc_s_parm(file, fh, p);
 }
 
 static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops,
@@ -2142,7 +2167,7 @@
 	ctrls.controls = &ctrl;
 	ctrl.id = p->id;
 	ctrl.value = p->value;
-	if (check_ext_ctrls(&ctrls, 1)) {
+	if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) {
 		int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls);
 
 		if (ret == 0)
@@ -2176,7 +2201,7 @@
 	ctrls.controls = &ctrl;
 	ctrl.id = p->id;
 	ctrl.value = p->value;
-	if (check_ext_ctrls(&ctrls, 1))
+	if (check_ext_ctrls(&ctrls, VIDIOC_S_CTRL))
 		return ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
 	return -EINVAL;
 }
@@ -2198,8 +2223,8 @@
 					vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_g_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ?
+				ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
@@ -2219,8 +2244,8 @@
 					vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_s_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ?
+				ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
@@ -2240,8 +2265,8 @@
 					  vfd, vfd->v4l2_dev->mdev, p);
 	if (ops->vidioc_try_ext_ctrls == NULL)
 		return -ENOTTY;
-	return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) :
-					-EINVAL;
+	return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ?
+			ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL;
 }
 
 /*
@@ -2478,6 +2503,18 @@
 #endif
 }
 
+static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct v4l2_dbg_chip_ident *p = arg;
+
+	p->ident = V4L2_IDENT_NONE;
+	p->revision = 0;
+	if (p->match.type == V4L2_CHIP_MATCH_SUBDEV)
+		return -EINVAL;
+	return ops->vidioc_g_chip_ident(file, fh, p);
+}
+
 static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -2755,6 +2792,7 @@
 	IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, v4l_stub_try_decoder_cmd, v4l_print_decoder_cmd, 0),
 	IOCTL_INFO(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
 	IOCTL_INFO(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
+	IOCTL_INFO(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
 	IOCTL_INFO(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
 	IOCTL_INFO(VIDIOC_S_DV_TIMINGS, v4l_stub_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_dv_timings, bt.flags)),
 	IOCTL_INFO(VIDIOC_G_DV_TIMINGS, v4l_stub_g_dv_timings, v4l_print_dv_timings, 0),
@@ -3013,7 +3051,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;
@@ -3072,20 +3110,14 @@
 	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 = kvmalloc(array_size, GFP_KERNEL);
+		array_buf = kvmalloc(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 */
@@ -3104,7 +3136,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;
 	}
@@ -3126,9 +3158,11 @@
 	}
 
 out:
+	kvfree(array_buf);
 	kvfree(mbuf);
 	return err;
 }
+EXPORT_SYMBOL(video_usercopy);
 
 long video_ioctl2(struct file *file,
 	       unsigned int cmd, unsigned long arg)
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-mc.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-mc.c
@@ -309,6 +309,101 @@
 }
 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
 
+int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
+				    struct media_pad *sink)
+{
+	struct fwnode_handle *endpoint;
+	struct v4l2_subdev *sink_sd;
+
+	if (!(sink->flags & MEDIA_PAD_FL_SINK) ||
+	    !is_media_entity_v4l2_subdev(sink->entity))
+		return -EINVAL;
+
+	sink_sd = media_entity_to_v4l2_subdev(sink->entity);
+
+	fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
+		struct fwnode_handle *remote_ep;
+		int src_idx, sink_idx, ret;
+		struct media_pad *src;
+
+		src_idx = media_entity_get_fwnode_pad(&src_sd->entity,
+						      endpoint,
+						      MEDIA_PAD_FL_SOURCE);
+		if (src_idx < 0)
+			continue;
+
+		remote_ep = fwnode_graph_get_remote_endpoint(endpoint);
+		if (!remote_ep)
+			continue;
+
+		/*
+		 * ask the sink to verify it owns the remote endpoint,
+		 * and translate to a sink pad.
+		 */
+		sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity,
+						       remote_ep,
+						       MEDIA_PAD_FL_SINK);
+		fwnode_handle_put(remote_ep);
+
+		if (sink_idx < 0 || sink_idx != sink->index)
+			continue;
+
+		/*
+		 * the source endpoint corresponds to one of its source pads,
+		 * the source endpoint connects to an endpoint at the sink
+		 * entity, and the sink endpoint corresponds to the sink
+		 * pad requested, so we have found an endpoint connection
+		 * that works, create the media link for it.
+		 */
+
+		src = &src_sd->entity.pads[src_idx];
+
+		/* skip if link already exists */
+		if (media_entity_find_link(src, sink))
+			continue;
+
+		dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n",
+			src_sd->entity.name, src_idx,
+			sink_sd->entity.name, sink_idx);
+
+		ret = media_create_pad_link(&src_sd->entity, src_idx,
+					    &sink_sd->entity, sink_idx, 0);
+		if (ret) {
+			dev_err(sink_sd->dev,
+				"link %s:%d -> %s:%d failed with %d\n",
+				src_sd->entity.name, src_idx,
+				sink_sd->entity.name, sink_idx, ret);
+
+			fwnode_handle_put(endpoint);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad);
+
+int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
+			     struct v4l2_subdev *sink_sd)
+{
+	unsigned int i;
+
+	for (i = 0; i < sink_sd->entity.num_pads; i++) {
+		struct media_pad *pad = &sink_sd->entity.pads[i];
+		int ret;
+
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			continue;
+
+		ret = v4l2_create_fwnode_links_to_pad(src_sd, pad);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);
+
 /* -----------------------------------------------------------------------------
  * Pipeline power management
  *
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -460,19 +460,14 @@
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs);
 
-int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
-		      struct v4l2_buffer *buf)
+static void v4l2_m2m_adjust_mem_offset(struct vb2_queue *vq,
+				       struct v4l2_buffer *buf)
 {
-	struct vb2_queue *vq;
-	int ret = 0;
-	unsigned int i;
-
-	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-	ret = vb2_querybuf(vq, buf);
-
 	/* Adjust MMAP memory offsets for the CAPTURE queue */
 	if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) {
 		if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) {
+			unsigned int i;
+
 			for (i = 0; i < buf->length; ++i)
 				buf->m.planes[i].m.mem_offset
 					+= DST_QUEUE_OFF_BASE;
@@ -480,8 +475,23 @@
 			buf->m.offset += DST_QUEUE_OFF_BASE;
 		}
 	}
+}
 
-	return ret;
+int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      struct v4l2_buffer *buf)
+{
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = vb2_querybuf(vq, buf);
+	if (ret)
+		return ret;
+
+	/* Adjust MMAP memory offsets for the CAPTURE queue */
+	v4l2_m2m_adjust_mem_offset(vq, buf);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
 
@@ -500,10 +510,16 @@
 		return -EPERM;
 	}
 	ret = vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf);
-	if (!ret && !(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
+	if (ret)
+		return ret;
+
+	/* Adjust MMAP memory offsets for the CAPTURE queue */
+	v4l2_m2m_adjust_mem_offset(vq, buf);
+
+	if (!(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
 		v4l2_m2m_try_schedule(m2m_ctx);
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
 
@@ -511,9 +527,17 @@
 		   struct v4l2_buffer *buf)
 {
 	struct vb2_queue *vq;
+	int ret;
 
 	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-	return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+	ret = vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+	if (ret)
+		return ret;
+
+	/* Adjust MMAP memory offsets for the CAPTURE queue */
+	v4l2_m2m_adjust_mem_offset(vq, buf);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
 
@@ -522,9 +546,17 @@
 {
 	struct video_device *vdev = video_devdata(file);
 	struct vb2_queue *vq;
+	int ret;
 
 	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-	return vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf);
+	ret = vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf);
+	if (ret)
+		return ret;
+
+	/* Adjust MMAP memory offsets for the CAPTURE queue */
+	v4l2_m2m_adjust_mem_offset(vq, buf);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
 
@@ -635,10 +667,8 @@
 		 * If the last buffer was dequeued from the capture queue,
 		 * return immediately. DQBUF will return -EPIPE.
 		 */
-		if (dst_q->last_buffer_dequeued) {
-			spin_unlock_irqrestore(&dst_q->done_lock, flags);
-			return EPOLLIN | EPOLLRDNORM;
-		}
+		if (dst_q->last_buffer_dequeued)
+			rc |= EPOLLIN | EPOLLRDNORM;
 	}
 	spin_unlock_irqrestore(&dst_q->done_lock, flags);
 
@@ -809,12 +839,12 @@
 		goto err_rel_entity1;
 
 	/* Connect the three entities */
-	ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 1,
+	ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 0,
 			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
 	if (ret)
 		goto err_rel_entity2;
 
-	ret = media_create_pad_link(&m2m_dev->proc, 0, &m2m_dev->sink, 0,
+	ret = media_create_pad_link(&m2m_dev->proc, 1, &m2m_dev->sink, 0,
 			MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
 	if (ret)
 		goto err_rm_links0;
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/v4l2-subdev.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/v4l2-subdev.c
@@ -299,6 +299,20 @@
 	       sd->ops->pad->enum_dv_timings(sd, dvt);
 }
 
+static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+				struct v4l2_mbus_config *config)
+{
+	return check_pad(sd, pad) ? :
+	       sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
+static int call_set_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+				struct v4l2_mbus_config *config)
+{
+	return check_pad(sd, pad) ? :
+	       sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
 static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
 	.get_fmt		= call_get_fmt,
 	.set_fmt		= call_set_fmt,
@@ -311,6 +325,8 @@
 	.set_edid		= call_set_edid,
 	.dv_timings_cap		= call_dv_timings_cap,
 	.enum_dv_timings	= call_enum_dv_timings,
+	.get_mbus_config	= call_get_mbus_config,
+	.set_mbus_config	= call_set_mbus_config,
 };
 
 static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
@@ -672,6 +688,28 @@
 };
 
 #ifdef CONFIG_MEDIA_CONTROLLER
+
+int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity,
+				      struct fwnode_endpoint *endpoint)
+{
+	struct fwnode_handle *fwnode;
+	struct v4l2_subdev *sd;
+
+	if (!is_media_entity_v4l2_subdev(entity))
+		return -EINVAL;
+
+	sd = media_entity_to_v4l2_subdev(entity);
+
+	fwnode = fwnode_graph_get_port_parent(endpoint->local_fwnode);
+	fwnode_handle_put(fwnode);
+
+	if (dev_fwnode(sd->dev) == fwnode)
+		return endpoint->port;
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_fwnode_pad_1_to_1);
+
 int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
 				      struct media_link *link,
 				      struct v4l2_subdev_format *source_fmt,
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/videobuf-core.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/videobuf-core.c
@@ -590,6 +590,13 @@
 		    buf->baddr != b->m.userptr)
 			q->ops->buf_release(q, buf);
 		buf->baddr = b->m.userptr;
+		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_VBI_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) {
+			buf->field = b->field;
+			buf->ts = v4l2_timeval_to_ns(&b->timestamp);
+		}
 		break;
 	case V4L2_MEMORY_OVERLAY:
 		buf->boff = b->m.offset;
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -36,12 +36,11 @@
 
 static int __videobuf_dc_alloc(struct device *dev,
 			       struct videobuf_dma_contig_memory *mem,
-			       unsigned long size, gfp_t flags)
+			       unsigned long size)
 {
 	mem->size = size;
-	mem->vaddr = dma_alloc_coherent(dev, mem->size,
-					&mem->dma_handle, flags);
-
+	mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle,
+					GFP_KERNEL);
 	if (!mem->vaddr) {
 		dev_err(dev, "memory alloc size %ld failed\n", mem->size);
 		return -ENOMEM;
@@ -258,8 +257,7 @@
 			return videobuf_dma_contig_user_get(mem, vb);
 
 		/* allocate memory for the read() method */
-		if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
-					GFP_KERNEL))
+		if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size)))
 			return -ENOMEM;
 		break;
 	case V4L2_MEMORY_OVERLAY:
@@ -295,22 +293,18 @@
 	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 
-	if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
-				GFP_KERNEL | __GFP_COMP))
+	if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize)))
 		goto error;
 
-	/* Try to remap memory */
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
 	/* the "vm_pgoff" is just used in v4l2 to find the
 	 * corresponding buffer data structure which is allocated
 	 * earlier and it does not mean the offset from the physical
 	 * buffer start address as usual. So set it to 0 to pass
-	 * the sanity check in vm_iomap_memory().
+	 * the sanity check in dma_mmap_coherent().
 	 */
 	vma->vm_pgoff = 0;
-
-	retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
+	retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
+				   mem->size);
 	if (retval) {
 		dev_err(q->dev, "mmap: remap failed with error %d. ",
 			retval);
--- linux-ein-5.4.0.orig/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ linux-ein-5.4.0/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -349,8 +349,11 @@
 	BUG_ON(dma->sglen);
 
 	if (dma->pages) {
-		for (i = 0; i < dma->nr_pages; i++)
+		for (i = 0; i < dma->nr_pages; i++) {
+			if (dma->direction == DMA_FROM_DEVICE)
+				set_page_dirty_lock(dma->pages[i]);
 			put_page(dma->pages[i]);
+		}
 		kfree(dma->pages);
 		dma->pages = NULL;
 	}
--- linux-ein-5.4.0.orig/drivers/memory/atmel-ebi.c
+++ linux-ein-5.4.0/drivers/memory/atmel-ebi.c
@@ -545,20 +545,27 @@
 	smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
 
 	ebi->smc.regmap = syscon_node_to_regmap(smc_np);
-	if (IS_ERR(ebi->smc.regmap))
-		return PTR_ERR(ebi->smc.regmap);
+	if (IS_ERR(ebi->smc.regmap)) {
+		ret = PTR_ERR(ebi->smc.regmap);
+		goto put_node;
+	}
 
 	ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
-	if (IS_ERR(ebi->smc.layout))
-		return PTR_ERR(ebi->smc.layout);
+	if (IS_ERR(ebi->smc.layout)) {
+		ret = PTR_ERR(ebi->smc.layout);
+		goto put_node;
+	}
 
 	ebi->smc.clk = of_clk_get(smc_np, 0);
 	if (IS_ERR(ebi->smc.clk)) {
-		if (PTR_ERR(ebi->smc.clk) != -ENOENT)
-			return PTR_ERR(ebi->smc.clk);
+		if (PTR_ERR(ebi->smc.clk) != -ENOENT) {
+			ret = PTR_ERR(ebi->smc.clk);
+			goto put_node;
+		}
 
 		ebi->smc.clk = NULL;
 	}
+	of_node_put(smc_np);
 	ret = clk_prepare_enable(ebi->smc.clk);
 	if (ret)
 		return ret;
@@ -601,12 +608,18 @@
 				child);
 
 			ret = atmel_ebi_dev_disable(ebi, child);
-			if (ret)
+			if (ret) {
+				of_node_put(child);
 				return ret;
+			}
 		}
 	}
 
 	return of_platform_populate(np, NULL, NULL, dev);
+
+put_node:
+	of_node_put(smc_np);
+	return ret;
 }
 
 static __maybe_unused int atmel_ebi_resume(struct device *dev)
--- linux-ein-5.4.0.orig/drivers/memory/atmel-sdramc.c
+++ linux-ein-5.4.0/drivers/memory/atmel-sdramc.c
@@ -47,19 +47,17 @@
 	caps = of_device_get_match_data(&pdev->dev);
 
 	if (caps->has_ddrck) {
-		clk = devm_clk_get(&pdev->dev, "ddrck");
+		clk = devm_clk_get_enabled(&pdev->dev, "ddrck");
 		if (IS_ERR(clk))
 			return PTR_ERR(clk);
-		clk_prepare_enable(clk);
 	}
 
 	if (caps->has_mpddr_clk) {
-		clk = devm_clk_get(&pdev->dev, "mpddr");
+		clk = devm_clk_get_enabled(&pdev->dev, "mpddr");
 		if (IS_ERR(clk)) {
 			pr_err("AT91 RAMC: couldn't get mpddr clock\n");
 			return PTR_ERR(clk);
 		}
-		clk_prepare_enable(clk);
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/memory/brcmstb_dpfe.c
+++ linux-ein-5.4.0/drivers/memory/brcmstb_dpfe.c
@@ -398,15 +398,17 @@
 static int __send_command(struct private_data *priv, unsigned int cmd,
 			  u32 result[])
 {
-	const u32 *msg = priv->dpfe_api->command[cmd];
 	void __iomem *regs = priv->regs;
 	unsigned int i, chksum, chksum_idx;
+	const u32 *msg;
 	int ret = 0;
 	u32 resp;
 
 	if (cmd >= DPFE_CMD_MAX)
 		return -1;
 
+	msg = priv->dpfe_api->command[cmd];
+
 	mutex_lock(&priv->lock);
 
 	/* Wait for DCPU to become ready */
--- linux-ein-5.4.0.orig/drivers/memory/emif.c
+++ linux-ein-5.4.0/drivers/memory/emif.c
@@ -163,35 +163,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)
@@ -1446,7 +1423,7 @@
 	temp	= devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
 	dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
 
-	if (!emif || !pd || !dev_info) {
+	if (!emif || !temp || !dev_info) {
 		dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
 		goto error;
 	}
@@ -1538,7 +1515,7 @@
 {
 	struct emif_data	*emif;
 	struct resource		*res;
-	int			irq;
+	int			irq, ret;
 
 	if (pdev->dev.of_node)
 		emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev);
@@ -1572,7 +1549,9 @@
 	emif_onetime_settings(emif);
 	emif_debugfs_init(emif);
 	disable_and_clear_all_interrupts(emif);
-	setup_interrupts(emif, irq);
+	ret = setup_interrupts(emif, irq);
+	if (ret)
+		goto error;
 
 	/* One-time actions taken on probing the first device */
 	if (!emif1) {
--- linux-ein-5.4.0.orig/drivers/memory/fsl-corenet-cf.c
+++ linux-ein-5.4.0/drivers/memory/fsl-corenet-cf.c
@@ -211,10 +211,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-ein-5.4.0.orig/drivers/memory/fsl_ifc.c
+++ linux-ein-5.4.0/drivers/memory/fsl_ifc.c
@@ -96,7 +96,6 @@
 	iounmap(ctrl->gregs);
 
 	dev_set_drvdata(&dev->dev, NULL);
-	kfree(ctrl);
 
 	return 0;
 }
@@ -208,7 +207,8 @@
 
 	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
 
-	fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
+	fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
+					GFP_KERNEL);
 	if (!fsl_ifc_ctrl_dev)
 		return -ENOMEM;
 
@@ -218,8 +218,7 @@
 	fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
 	if (!fsl_ifc_ctrl_dev->gregs) {
 		dev_err(&dev->dev, "failed to get memory region\n");
-		ret = -ENODEV;
-		goto err;
+		return -ENODEV;
 	}
 
 	if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
@@ -264,7 +263,7 @@
 
 	ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
 	if (ret < 0)
-		goto err;
+		goto err_unmap_nandirq;
 
 	init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
 
@@ -273,7 +272,7 @@
 	if (ret != 0) {
 		dev_err(&dev->dev, "failed to install irq (%d)\n",
 			fsl_ifc_ctrl_dev->irq);
-		goto err_irq;
+		goto err_unmap_nandirq;
 	}
 
 	if (fsl_ifc_ctrl_dev->nand_irq) {
@@ -282,19 +281,19 @@
 		if (ret != 0) {
 			dev_err(&dev->dev, "failed to install irq (%d)\n",
 				fsl_ifc_ctrl_dev->nand_irq);
-			goto err_nandirq;
+			goto err_free_irq;
 		}
 	}
 
 	return 0;
 
-err_nandirq:
-	free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
-	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
-err_irq:
+err_free_irq:
 	free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
+err_unmap_nandirq:
+	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
 	irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
 err:
+	iounmap(fsl_ifc_ctrl_dev->gregs);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/memory/mtk-smi.c
+++ linux-ein-5.4.0/drivers/memory/mtk-smi.c
@@ -127,7 +127,7 @@
 
 int mtk_smi_larb_get(struct device *larbdev)
 {
-	int ret = pm_runtime_get_sync(larbdev);
+	int ret = pm_runtime_resume_and_get(larbdev);
 
 	return (ret < 0) ? ret : 0;
 }
@@ -336,7 +336,7 @@
 	int ret;
 
 	/* Power on smi-common. */
-	ret = pm_runtime_get_sync(larb->smi_common_dev);
+	ret = pm_runtime_resume_and_get(larb->smi_common_dev);
 	if (ret < 0) {
 		dev_err(dev, "Failed to pm get for smi-common(%d).\n", ret);
 		return ret;
@@ -366,6 +366,8 @@
 
 static const struct dev_pm_ops smi_larb_pm_ops = {
 	SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
 };
 
 static struct platform_driver mtk_smi_larb_driver = {
@@ -507,6 +509,8 @@
 
 static const struct dev_pm_ops smi_common_pm_ops = {
 	SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
 };
 
 static struct platform_driver mtk_smi_common_driver = {
--- linux-ein-5.4.0.orig/drivers/memory/mvebu-devbus.c
+++ linux-ein-5.4.0/drivers/memory/mvebu-devbus.c
@@ -282,10 +282,9 @@
 	if (IS_ERR(devbus->base))
 		return PTR_ERR(devbus->base);
 
-	clk = devm_clk_get(&pdev->dev, NULL);
+	clk = devm_clk_get_enabled(&pdev->dev, NULL);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
-	clk_prepare_enable(clk);
 
 	/*
 	 * Obtain clock period in picoseconds,
--- linux-ein-5.4.0.orig/drivers/memory/of_memory.c
+++ linux-ein-5.4.0/drivers/memory/of_memory.c
@@ -132,6 +132,7 @@
 	for_each_child_of_node(np_ddr, np_tim) {
 		if (of_device_is_compatible(np_tim, tim_compat)) {
 			if (of_do_get_timings(np_tim, &timings[i])) {
+				of_node_put(np_tim);
 				devm_kfree(dev, timings);
 				goto default_timings;
 			}
--- linux-ein-5.4.0.orig/drivers/memory/omap-gpmc.c
+++ linux-ein-5.4.0/drivers/memory/omap-gpmc.c
@@ -949,7 +949,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;
 	}
@@ -984,7 +984,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;
 	}
@@ -1026,8 +1026,8 @@
 
 void gpmc_cs_free(int cs)
 {
-	struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
-	struct resource *res = &gpmc->mem;
+	struct gpmc_cs_data *gpmc;
+	struct resource *res;
 
 	spin_lock(&gpmc_mem_lock);
 	if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
@@ -1036,6 +1036,9 @@
 		spin_unlock(&gpmc_mem_lock);
 		return;
 	}
+	gpmc = &gpmc_cs[cs];
+	res = &gpmc->mem;
+
 	gpmc_cs_disable_mem(cs);
 	if (res->flags)
 		release_resource(res);
@@ -2274,6 +2277,10 @@
 	}
 }
 #else
+void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+{
+	memset(p, 0, sizeof(*p));
+}
 static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	return 0;
--- linux-ein-5.4.0.orig/drivers/memory/pl353-smc.c
+++ linux-ein-5.4.0/drivers/memory/pl353-smc.c
@@ -63,7 +63,7 @@
 /* ECC memory config register specific constants */
 #define PL353_SMC_ECC_MEMCFG_MODE_MASK	0xC
 #define PL353_SMC_ECC_MEMCFG_MODE_SHIFT	2
-#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK	0xC
+#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK	0x3
 
 #define PL353_SMC_DC_UPT_NAND_REGS	((4 << 23) |	/* CS: NAND chip */ \
 				 (2 << 21))	/* UpdateRegs operation */
@@ -407,6 +407,7 @@
 		break;
 	}
 	if (!match) {
+		err = -ENODEV;
 		dev_err(&adev->dev, "no matching children\n");
 		goto out_clk_disable;
 	}
@@ -415,6 +416,7 @@
 	if (init)
 		init(adev, child);
 	of_platform_device_create(child, NULL, &adev->dev);
+	of_node_put(child);
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/memory/ti-aemif.c
+++ linux-ein-5.4.0/drivers/memory/ti-aemif.c
@@ -378,8 +378,10 @@
 		 */
 		for_each_available_child_of_node(np, child_np) {
 			ret = of_aemif_parse_abus_config(pdev, child_np);
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(child_np);
 				goto error;
+			}
 		}
 	} else if (pdata && pdata->num_abus_data > 0) {
 		for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) {
@@ -405,8 +407,10 @@
 		for_each_available_child_of_node(np, child_np) {
 			ret = of_platform_populate(child_np, NULL,
 						   dev_lookup, dev);
-			if (ret < 0)
+			if (ret < 0) {
+				of_node_put(child_np);
 				goto error;
+			}
 		}
 	} else if (pdata) {
 		for (i = 0; i < pdata->num_sub_devices; i++) {
--- linux-ein-5.4.0.orig/drivers/memstick/core/memstick.c
+++ linux-ein-5.4.0/drivers/memstick/core/memstick.c
@@ -412,6 +412,7 @@
 	return card;
 err_out:
 	host->card = old_card;
+	kfree_const(card->dev.kobj.name);
 	kfree(card);
 	return NULL;
 }
@@ -441,6 +442,9 @@
 	} else if (host->card->stop)
 		host->card->stop(host->card);
 
+	if (host->removing)
+		goto out_power_off;
+
 	card = memstick_alloc_card(host);
 
 	if (!card) {
@@ -465,11 +469,12 @@
 			host->card = card;
 			if (device_register(&card->dev)) {
 				put_device(&card->dev);
-				kfree(host->card);
 				host->card = NULL;
 			}
-		} else
+		} else {
+			kfree_const(card->dev.kobj.name);
 			kfree(card);
+		}
 	}
 
 out_power_off:
@@ -545,6 +550,7 @@
  */
 void memstick_remove_host(struct memstick_host *host)
 {
+	host->removing = 1;
 	flush_workqueue(workqueue);
 	mutex_lock(&host->lock);
 	if (host->card)
--- linux-ein-5.4.0.orig/drivers/memstick/core/ms_block.c
+++ linux-ein-5.4.0/drivers/memstick/core/ms_block.c
@@ -1335,17 +1335,17 @@
 	msb->zone_count = msb->block_count / MS_BLOCKS_IN_ZONE;
 	msb->logical_block_count = msb->zone_count * 496 - 2;
 
-	msb->used_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
-	msb->erased_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
+	msb->used_blocks_bitmap = bitmap_zalloc(msb->block_count, GFP_KERNEL);
+	msb->erased_blocks_bitmap = bitmap_zalloc(msb->block_count, GFP_KERNEL);
 	msb->lba_to_pba_table =
 		kmalloc_array(msb->logical_block_count, sizeof(u16),
 			      GFP_KERNEL);
 
 	if (!msb->used_blocks_bitmap || !msb->lba_to_pba_table ||
 						!msb->erased_blocks_bitmap) {
-		kfree(msb->used_blocks_bitmap);
+		bitmap_free(msb->used_blocks_bitmap);
+		bitmap_free(msb->erased_blocks_bitmap);
 		kfree(msb->lba_to_pba_table);
-		kfree(msb->erased_blocks_bitmap);
 		return -ENOMEM;
 	}
 
@@ -1727,7 +1727,7 @@
 	msb->pages_in_block = boot_block->attr.block_size * 2;
 	msb->block_size = msb->page_size * msb->pages_in_block;
 
-	if (msb->page_size > PAGE_SIZE) {
+	if ((size_t)msb->page_size > PAGE_SIZE) {
 		/* this isn't supported by linux at all, anyway*/
 		dbg("device page %d size isn't supported", msb->page_size);
 		return -EINVAL;
@@ -1953,7 +1953,8 @@
 static void msb_data_clear(struct msb_data *msb)
 {
 	kfree(msb->boot_page);
-	kfree(msb->used_blocks_bitmap);
+	bitmap_free(msb->used_blocks_bitmap);
+	bitmap_free(msb->erased_blocks_bitmap);
 	kfree(msb->lba_to_pba_table);
 	kfree(msb->cache);
 	msb->card = NULL;
--- linux-ein-5.4.0.orig/drivers/memstick/host/jmb38x_ms.c
+++ linux-ein-5.4.0/drivers/memstick/host/jmb38x_ms.c
@@ -314,7 +314,7 @@
 	}
 
 	while (length) {
-		unsigned int uninitialized_var(p_off);
+		unsigned int p_off;
 
 		if (host->req->long_data) {
 			pg = nth_page(sg_page(&host->req->sg),
@@ -899,7 +899,7 @@
 
 	iounmap(host->addr);
 err_out_free:
-	kfree(msh);
+	memstick_free_host(msh);
 	return NULL;
 }
 
--- linux-ein-5.4.0.orig/drivers/memstick/host/r592.c
+++ linux-ein-5.4.0/drivers/memstick/host/r592.c
@@ -44,12 +44,10 @@
  * memstick_debug_get_tpc_name - debug helper that returns string for
  * a TPC number
  */
-const char *memstick_debug_get_tpc_name(int tpc)
+static __maybe_unused const char *memstick_debug_get_tpc_name(int tpc)
 {
 	return tpc_names[tpc-1];
 }
-EXPORT_SYMBOL(memstick_debug_get_tpc_name);
-
 
 /* Read a register*/
 static inline u32 r592_read_reg(struct r592_device *dev, int address)
@@ -759,8 +757,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);
@@ -786,12 +786,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");
@@ -824,7 +826,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) {
@@ -833,15 +835,15 @@
 	}
 	memstick_remove_host(dev->host);
 
+	if (dev->dummy_dma_page)
+		dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page,
+			dev->dummy_dma_page_physical_address);
+
 	free_irq(dev->irq, dev);
 	iounmap(dev->mmio);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	memstick_free_host(dev->host);
-
-	if (dev->dummy_dma_page)
-		dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page,
-			dev->dummy_dma_page_physical_address);
 }
 
 #ifdef CONFIG_PM_SLEEP
--- linux-ein-5.4.0.orig/drivers/memstick/host/rtsx_usb_ms.c
+++ linux-ein-5.4.0/drivers/memstick/host/rtsx_usb_ms.c
@@ -799,9 +799,9 @@
 
 	return 0;
 err_out:
-	memstick_free_host(msh);
 	pm_runtime_disable(ms_dev(host));
 	pm_runtime_put_noidle(ms_dev(host));
+	memstick_free_host(msh);
 	return err;
 }
 
@@ -828,9 +828,6 @@
 	}
 	mutex_unlock(&host->host_mutex);
 
-	memstick_remove_host(msh);
-	memstick_free_host(msh);
-
 	/* Balance possible unbalanced usage count
 	 * e.g. unconditional module removal
 	 */
@@ -838,10 +835,11 @@
 		pm_runtime_put(ms_dev(host));
 
 	pm_runtime_disable(ms_dev(host));
-	platform_set_drvdata(pdev, NULL);
-
+	memstick_remove_host(msh);
 	dev_dbg(ms_dev(host),
 		": Realtek USB Memstick controller has been removed\n");
+	memstick_free_host(msh);
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/memstick/host/tifm_ms.c
+++ linux-ein-5.4.0/drivers/memstick/host/tifm_ms.c
@@ -198,7 +198,7 @@
 		host->block_pos);
 
 	while (length) {
-		unsigned int uninitialized_var(p_off);
+		unsigned int p_off;
 
 		if (host->req->long_data) {
 			pg = nth_page(sg_page(&host->req->sg),
--- linux-ein-5.4.0.orig/drivers/message/fusion/mptctl.c
+++ linux-ein-5.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));
 
@@ -2659,15 +2554,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;
@@ -2681,12 +2574,6 @@
 		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",
@@ -2854,7 +2741,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);
 
@@ -2908,7 +2795,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-ein-5.4.0.orig/drivers/message/fusion/mptlan.c
+++ linux-ein-5.4.0/drivers/message/fusion/mptlan.c
@@ -1430,7 +1430,9 @@
 {
 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
 	struct net_device	*dev = ioc->netdev;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 
+	cancel_delayed_work_sync(&priv->post_buckets_task);
 	if(dev != NULL) {
 		unregister_netdev(dev);
 		free_netdev(dev);
--- linux-ein-5.4.0.orig/drivers/message/fusion/mptscsih.c
+++ linux-ein-5.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 @@
 	MPT_SCSI_HOST		*hd;
 	int sz1;
 
-	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);
 
 }
@@ -2422,7 +2423,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-ein-5.4.0.orig/drivers/mfd/Kconfig
+++ linux-ein-5.4.0/drivers/mfd/Kconfig
@@ -407,6 +407,21 @@
 	  Select this option to enable support for Samsung Exynos Low Power
 	  Audio Subsystem.
 
+config MFD_GATEWORKS_GSC
+	tristate "Gateworks System Controller"
+	depends on (I2C && OF)
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  Enable support for the Gateworks System Controller (GSC) found
+	  on Gateworks Single Board Computers supporting system functions
+	  such as push-button monitor, multiple ADC's for voltage and
+	  temperature monitoring, fan controller and watchdog monitor.
+	  This driver provides common support for accessing the device.
+	  Additional drivers must be enabled in order to use the
+	  functionality of the device.
+
 config MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
@@ -460,6 +475,12 @@
 	  i.MX25 processors. They consist of a conversion queue for general
 	  purpose ADC and a queue for Touchscreens.
 
+config MFD_IMX_AUDIOMIX
+	tristate "NXP i.MX8MP Audiomix Control Driver"
+	depends on OF || COMPILE_TEST
+	help
+	  Enable audiomix support
+
 config MFD_HI6421_PMIC
 	tristate "HiSilicon Hi6421 PMU/Codec IC"
 	depends on OF
@@ -758,6 +779,7 @@
 	depends on OF || COMPILE_TEST
 	select MFD_CORE
 	select REGMAP_I2C
+	select REGMAP_IRQ
 	help
 	  Say Y here to add support for Maxim Semiconductor MAX77650 and
 	  MAX77651 Power Management ICs. This is the core multifunction
@@ -1298,6 +1320,7 @@
 
 config MFD_TI_AM335X_TSCADC
 	tristate "TI ADC / Touch Screen chip support"
+	depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
 	select MFD_CORE
 	select REGMAP
 	select REGMAP_MMIO
@@ -2011,5 +2034,16 @@
 	  Select this to get support for the Supervisory Processor
 	  device found on several devices in RAVE line of hardware.
 
+config MFD_AHC1EC0
+	tristate "Advantech AHC1EC0 Embedded Controller Module"
+	depends on X86
+	depends on UBUNTU_ODM_DRIVERS
+	select MFD_CORE
+	help
+	  This is the core function that for Advantech EC drivers. It
+	  includes the sub-devices such as hwmon, watchdog, etc. And also
+	  provides expose functions for sub-devices to read/write the value
+	  to embedded controller.
+
 endmenu
 endif
--- linux-ein-5.4.0.orig/drivers/mfd/Makefile
+++ linux-ein-5.4.0/drivers/mfd/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_MFD_BD9571MWV)	+= bd9571mwv.o
 obj-$(CONFIG_MFD_CROS_EC_DEV)	+= cros_ec_dev.o
 obj-$(CONFIG_MFD_EXYNOS_LPASS)	+= exynos-lpass.o
+obj-$(CONFIG_MFD_GATEWORKS_GSC)	+= gateworks-gsc.o
 
 obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
@@ -112,6 +113,7 @@
 obj-$(CONFIG_TWL6040_CORE)	+= twl6040.o
 
 obj-$(CONFIG_MFD_MX25_TSADC)	+= fsl-imx25-tsadc.o
+obj-$(CONFIG_MFD_IMX_AUDIOMIX)	+= imx-audiomix.o
 
 obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx-core.o
 obj-$(CONFIG_MFD_MC13XXX_SPI)	+= mc13xxx-spi.o
@@ -256,3 +258,5 @@
 obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
 obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
 
+obj-$(CONFIG_MFD_AHC1EC0)	+= ahc1ec0.o
+
--- linux-ein-5.4.0.orig/drivers/mfd/ab8500-core.c
+++ linux-ein-5.4.0/drivers/mfd/ab8500-core.c
@@ -493,7 +493,7 @@
 		if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
 			line += 1;
 
-		handle_nested_irq(irq_create_mapping(ab8500->domain, line));
+		handle_nested_irq(irq_find_mapping(ab8500->domain, line));
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/mfd/ahc1ec0.c
+++ linux-ein-5.4.0/drivers/mfd/ahc1ec0.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Advantech embedded controller core driver AHC1EC0
+ *
+ * Copyright 2020 Advantech IIoT Group
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/errno.h>
+#include <linux/mfd/ahc1ec0.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME      "ahc1ec0"
+
+enum {
+	ADVEC_SUBDEV_BRIGHTNESS = 0,
+	ADVEC_SUBDEV_EEPROM,
+	ADVEC_SUBDEV_GPIO,
+	ADVEC_SUBDEV_HWMON,
+	ADVEC_SUBDEV_LED,
+	ADVEC_SUBDEV_WDT,
+	ADVEC_SUBDEV_MAX,
+};
+
+/* Wait IBF (Input Buffer Full) clear */
+static int ec_wait_write(void)
+{
+	int i;
+
+	for (i = 0; i < EC_MAX_TIMEOUT_COUNT; i++) {
+		if ((inb(EC_COMMAND_PORT) & EC_COMMAND_BIT_IBF) == 0)
+			return 0;
+
+		udelay(EC_RETRY_UDELAY);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* Wait OBF (Output Buffer Full) data ready */
+static int ec_wait_read(void)
+{
+	int i;
+
+	for (i = 0; i < EC_MAX_TIMEOUT_COUNT; i++) {
+		if ((inb(EC_COMMAND_PORT) & EC_COMMAND_BIT_OBF) != 0)
+			return 0;
+
+		udelay(EC_RETRY_UDELAY);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* Read data from EC HW RAM, the process is the following:
+ * Step 0. Wait IBF clear to send command
+ * Step 1. Send read command to EC command port
+ * Step 2. Wait IBF clear that means command is got by EC
+ * Step 3. Send read address to EC data port
+ * Step 4. Wait OBF data ready
+ * Step 5. Get data from EC data port
+ */
+int read_hw_ram(struct adv_ec_platform_data *adv_ec_data, unsigned char addr, unsigned char *data)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_HW_RAM_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(addr, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	*data = inb(EC_STATUS_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+
+	return ret;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+	dev_err(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+	       __LINE__);
+
+	return ret;
+}
+
+/* Write data to EC HW RAM
+ * Step 0. Wait IBF clear to send command
+ * Step 1. Send write command to EC command port
+ * Step 2. Wait IBF clear that means command is got by EC
+ * Step 3. Send write address to EC data port
+ * Step 4. Wait IBF clear that means command is got by EC
+ * Step 5. Send data to EC data port
+ */
+int write_hw_ram(struct adv_ec_platform_data *adv_ec_data, unsigned char addr, unsigned char data)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_HW_RAM_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(addr, EC_STATUS_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(data, EC_STATUS_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_err(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+	       __LINE__);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(write_hw_ram);
+
+/* Get dynamic control table */
+static int adv_get_dynamic_tab(struct adv_ec_platform_data *adv_ec_data)
+{
+	int i, ret;
+	unsigned char pin_tmp, device_id;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	for (i = 0; i < EC_MAX_TBL_NUM; i++) {
+		adv_ec_data->dym_tbl[i].device_id = 0xff;
+		adv_ec_data->dym_tbl[i].hw_pin_num = 0xff;
+	}
+
+	for (i = 0; i < EC_MAX_TBL_NUM; i++) {
+		ret = ec_wait_write();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_write. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+		outb(EC_TBL_WRITE_ITEM, EC_COMMAND_PORT);
+
+		ret = ec_wait_write();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_write. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+		outb(i, EC_STATUS_PORT);
+
+		ret = ec_wait_read();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_read. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+
+		/*
+		 *  If item is defined, EC will return item number.
+		 *  If table item is not defined, EC will return 0xFF.
+		 */
+		pin_tmp = inb(EC_STATUS_PORT);
+		if (pin_tmp == 0xff) {
+			dev_dbg(adv_ec_data->dev, "%s: inb(EC_STATUS_PORT)=0x%02x != 0xff.\n",
+				__func__, pin_tmp);
+			goto pass;
+		}
+
+		ret = ec_wait_write();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_write. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+		outb(EC_TBL_GET_PIN, EC_COMMAND_PORT);
+
+		ret = ec_wait_read();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_read. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+		pin_tmp = inb(EC_STATUS_PORT) & 0xff;
+		if (pin_tmp == 0xff) {
+			dev_dbg(adv_ec_data->dev, "%s: pin_tmp(0x%02X). line: %d\n", __func__,
+				pin_tmp, __LINE__);
+			goto pass;
+		}
+
+		ret = ec_wait_write();
+		if (ret)
+			goto error;
+		outb(EC_TBL_GET_DEVID, EC_COMMAND_PORT);
+
+		ret = ec_wait_read();
+		if (ret) {
+			dev_dbg(adv_ec_data->dev, "%s: ec_wait_read. line: %d\n", __func__,
+				__LINE__);
+			goto error;
+		}
+		device_id = inb(EC_STATUS_PORT) & 0xff;
+
+		dev_dbg(adv_ec_data->dev, "%s: device_id=0x%02X. line: %d\n", __func__,
+			device_id, __LINE__);
+
+		adv_ec_data->dym_tbl[i].device_id = device_id;
+		adv_ec_data->dym_tbl[i].hw_pin_num = pin_tmp;
+	}
+
+pass:
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+	dev_err(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n",
+		__func__, __LINE__);
+	return ret;
+}
+
+int read_ad_value(struct adv_ec_platform_data *adv_ec_data, unsigned char hwpin,
+		unsigned char multi)
+{
+	int ret;
+	u32 ret_val;
+	unsigned int LSB, MSB;
+
+	mutex_lock(&adv_ec_data->lock);
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_AD_INDEX_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(hwpin, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+
+	if (inb(EC_STATUS_PORT) == 0xff) {
+		mutex_unlock(&adv_ec_data->lock);
+		return -1;
+	}
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_AD_LSB_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	LSB = inb(EC_STATUS_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_AD_MSB_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	MSB = inb(EC_STATUS_PORT);
+	ret_val = ((MSB << 8) | LSB) & 0x03FF;
+	ret_val = ret_val * multi * 100;
+
+	mutex_unlock(&adv_ec_data->lock);
+	return ret_val;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+		__LINE__);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(read_ad_value);
+
+int read_acpi_value(struct adv_ec_platform_data *adv_ec_data, unsigned char addr,
+		unsigned char *pvalue)
+{
+	int ret;
+	unsigned char value;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_ACPI_RAM_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(addr, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	value = inb(EC_STATUS_PORT);
+	*pvalue = value;
+
+	mutex_unlock(&adv_ec_data->lock);
+
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+		__LINE__);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(read_acpi_value);
+
+int write_acpi_value(struct adv_ec_platform_data *adv_ec_data, unsigned char addr,
+		unsigned char value)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_ACPI_DATA_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(addr, EC_STATUS_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(value, EC_STATUS_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+		__LINE__);
+
+	return ret;
+}
+
+int read_gpio_status(struct adv_ec_platform_data *adv_ec_data, unsigned char PinNumber,
+		unsigned char *pvalue)
+{
+	int ret;
+
+	unsigned char gpio_status_value;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_INDEX_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(PinNumber, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+
+	if (inb(EC_STATUS_PORT) == 0xff) {
+		dev_err(adv_ec_data->dev, "%s: Read Pin Number error!!\n", __func__);
+		mutex_unlock(&adv_ec_data->lock);
+		return -1;
+	}
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_STATUS_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	gpio_status_value = inb(EC_STATUS_PORT);
+
+	*pvalue = gpio_status_value;
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+		__LINE__);
+	return ret;
+}
+
+int write_gpio_status(struct adv_ec_platform_data *adv_ec_data, unsigned char PinNumber,
+		unsigned char value)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_INDEX_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(PinNumber, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+
+	if (inb(EC_STATUS_PORT) == 0xff) {
+		mutex_unlock(&adv_ec_data->lock);
+		dev_err(adv_ec_data->dev, "%s: Read Pin Number error!!\n", __func__);
+		return -1;
+	}
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_STATUS_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(value, EC_STATUS_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+	dev_err(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d", __func__,
+		__LINE__);
+
+	return ret;
+}
+
+int read_gpio_dir(struct adv_ec_platform_data *adv_ec_data, unsigned char PinNumber,
+		unsigned char *pvalue)
+{
+	int ret;
+	unsigned char gpio_dir_value;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_INDEX_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(PinNumber, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+
+	if (inb(EC_STATUS_PORT) == 0xff) {
+		mutex_unlock(&adv_ec_data->lock);
+		dev_err(adv_ec_data->dev, "%s: Read Pin Number error!! line: %d\n", __func__,
+			__LINE__);
+		return -1;
+	}
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_DIR_READ, EC_COMMAND_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+	gpio_dir_value = inb(EC_STATUS_PORT);
+	*pvalue = gpio_dir_value;
+
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+			__LINE__);
+
+	return ret;
+}
+
+int write_gpio_dir(struct adv_ec_platform_data *adv_ec_data, unsigned char PinNumber,
+		unsigned char value)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_INDEX_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(PinNumber, EC_STATUS_PORT);
+
+	ret = ec_wait_read();
+	if (ret)
+		goto error;
+
+	if (inb(EC_STATUS_PORT) == 0xff) {
+		mutex_unlock(&adv_ec_data->lock);
+		dev_warn(adv_ec_data->dev, "%s: Read Pin Number error!! line: %d\n", __func__,
+			__LINE__);
+
+		return -1;
+	}
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(EC_GPIO_DIR_WRITE, EC_COMMAND_PORT);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(value, EC_STATUS_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+			__LINE__);
+
+	return ret;
+}
+
+int write_hwram_command(struct adv_ec_platform_data *adv_ec_data, unsigned char data)
+{
+	int ret;
+
+	mutex_lock(&adv_ec_data->lock);
+
+	ret = ec_wait_write();
+	if (ret)
+		goto error;
+	outb(data, EC_COMMAND_PORT);
+
+	mutex_unlock(&adv_ec_data->lock);
+	return 0;
+
+error:
+	mutex_unlock(&adv_ec_data->lock);
+
+	dev_warn(adv_ec_data->dev, "%s: Wait for IBF or OBF too long. line: %d\n", __func__,
+			__LINE__);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(write_hwram_command);
+
+static int adv_ec_get_productname(struct adv_ec_platform_data *adv_ec_data, char *product)
+{
+	const char *vendor, *device;
+	int length = 0;
+
+	/* Check it is Advantech board */
+	vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+	if (memcmp(vendor, "Advantech", sizeof("Advantech")) != 0)
+		return -ENODEV;
+
+	/* Get product model name */
+	device = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (device) {
+		while ((device[length] != ' ')
+			&& (length < AMI_ADVANTECH_BOARD_ID_LENGTH))
+			length++;
+		memset(product, 0, AMI_ADVANTECH_BOARD_ID_LENGTH);
+		memmove(product, device, length);
+
+		dev_info(adv_ec_data->dev, "BIOS Product Name = %s\n", product);
+
+		return 0;
+	}
+
+	dev_warn(adv_ec_data->dev, "This device is not Advantech Board (%s)!\n", product);
+
+	return -ENODEV;
+}
+
+static const struct mfd_cell adv_ec_sub_cells[] = {
+	{ .name = "adv-ec-brightness", },
+	{ .name = "adv-ec-eeprom", },
+	{ .name = "adv-ec-gpio", },
+	{ .name = "ahc1ec0-hwmon", },
+	{ .name = "adv-ec-led", },
+	{ .name = "ahc1ec0-wdt", },
+};
+
+static int adv_ec_init_ec_data(struct adv_ec_platform_data *adv_ec_data)
+{
+	int ret;
+
+	adv_ec_data->sub_dev_mask = 0;
+	adv_ec_data->sub_dev_nb = 0;
+	adv_ec_data->dym_tbl = NULL;
+	adv_ec_data->bios_product_name = NULL;
+
+	mutex_init(&adv_ec_data->lock);
+
+	/* Get product name */
+	adv_ec_data->bios_product_name =
+		devm_kzalloc(adv_ec_data->dev, AMI_ADVANTECH_BOARD_ID_LENGTH, GFP_KERNEL);
+	if (!adv_ec_data->bios_product_name)
+		return -ENOMEM;
+
+	memset(adv_ec_data->bios_product_name, 0, AMI_ADVANTECH_BOARD_ID_LENGTH);
+	ret = adv_ec_get_productname(adv_ec_data, adv_ec_data->bios_product_name);
+	if (ret)
+		return ret;
+
+	/* Get pin table */
+	adv_ec_data->dym_tbl = devm_kzalloc(adv_ec_data->dev,
+					EC_MAX_TBL_NUM * sizeof(struct ec_dynamic_table),
+					GFP_KERNEL);
+	if (!adv_ec_data->dym_tbl)
+		return -ENOMEM;
+
+	ret = adv_get_dynamic_tab(adv_ec_data);
+
+	return ret;
+}
+
+static int adv_ec_parse_prop(struct adv_ec_platform_data *adv_ec_data)
+{
+	int i, ret;
+	u32 nb, sub_dev[ADVEC_SUBDEV_MAX];
+
+	ret = device_property_read_u32(adv_ec_data->dev, "advantech,sub-dev-nb", &nb);
+	if (ret < 0) {
+		dev_err(adv_ec_data->dev, "get sub-dev-nb failed! (%d)\n", ret);
+		return ret;
+	}
+	adv_ec_data->sub_dev_nb = nb;
+
+	ret = device_property_read_u32_array(adv_ec_data->dev, "advantech,sub-dev",
+					     sub_dev, nb);
+	if (ret < 0) {
+		dev_err(adv_ec_data->dev, "get sub-dev failed! (%d)\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < nb; i++) {
+		switch (sub_dev[i]) {
+		case ADVEC_SUBDEV_BRIGHTNESS:
+		case ADVEC_SUBDEV_EEPROM:
+		case ADVEC_SUBDEV_GPIO:
+		case ADVEC_SUBDEV_HWMON:
+		case ADVEC_SUBDEV_LED:
+		case ADVEC_SUBDEV_WDT:
+			adv_ec_data->sub_dev_mask |= BIT(sub_dev[i]);
+			break;
+		default:
+			dev_err(adv_ec_data->dev, "invalid prop value(%d)!\n",
+				sub_dev[i]);
+		}
+	}
+	dev_info(adv_ec_data->dev, "sub-dev mask = 0x%x\n", adv_ec_data->sub_dev_mask);
+
+	return 0;
+}
+
+static int adv_ec_probe(struct platform_device *pdev)
+{
+	int ret, i;
+	struct device *dev = &pdev->dev;
+	struct adv_ec_platform_data *adv_ec_data;
+
+	adv_ec_data = devm_kzalloc(dev, sizeof(struct adv_ec_platform_data), GFP_KERNEL);
+	if (!adv_ec_data)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, adv_ec_data);
+	adv_ec_data->dev = dev;
+
+	ret = adv_ec_init_ec_data(adv_ec_data);
+	if (ret)
+		goto err_init_data;
+
+	ret = adv_ec_parse_prop(adv_ec_data);
+	if (ret)
+		goto err_prop;
+
+	/* check whether this EC has the following subdevices. */
+	for (i = 0; i < ARRAY_SIZE(adv_ec_sub_cells); i++) {
+		if (adv_ec_data->sub_dev_mask & BIT(i)) {
+			ret = mfd_add_hotplug_devices(dev, &adv_ec_sub_cells[i], 1);
+			dev_info(adv_ec_data->dev, "mfd_add_hotplug_devices[%d] %s\n", i,
+				adv_ec_sub_cells[i].name);
+			if (ret)
+				dev_err(dev, "failed to add %s subdevice: %d\n",
+					adv_ec_sub_cells[i].name, ret);
+		}
+	}
+
+	dev_info(adv_ec_data->dev, "Advantech EC probe done");
+
+	return 0;
+
+err_prop:
+	dev_err(dev, "failed to probe\n");
+
+err_init_data:
+	mutex_destroy(&adv_ec_data->lock);
+
+	dev_err(dev, "failed to init data\n");
+
+	return ret;
+}
+
+static int adv_ec_remove(struct platform_device *pdev)
+{
+	struct adv_ec_platform_data *adv_ec_data;
+
+	adv_ec_data = dev_get_drvdata(&pdev->dev);
+
+	mutex_destroy(&adv_ec_data->lock);
+
+	mfd_remove_devices(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id adv_ec_of_match[] __maybe_unused = {
+	{
+		.compatible = "advantech,ahc1ec0",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, adv_ec_of_match);
+
+static const struct acpi_device_id adv_ec_acpi_match[] __maybe_unused = {
+	{"AHC1EC0", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, adv_ec_acpi_match);
+
+static struct platform_driver adv_ec_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(adv_ec_of_match),
+		.acpi_match_table = ACPI_PTR(adv_ec_acpi_match),
+	},
+	.probe = adv_ec_probe,
+	.remove = adv_ec_remove,
+};
+module_platform_driver(adv_ec_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION("Advantech Embedded Controller core driver.");
+MODULE_AUTHOR("Campion Kang <campion.kang@advantech.com.tw>");
+MODULE_AUTHOR("Jianfeng Dai <jianfeng.dai@advantech.com.cn>");
+MODULE_VERSION("1.0");
--- linux-ein-5.4.0.orig/drivers/mfd/arizona-core.c
+++ linux-ein-5.4.0/drivers/mfd/arizona-core.c
@@ -45,7 +45,7 @@
 	if (arizona->clk32k_ref == 1) {
 		switch (arizona->pdata.clk32k_src) {
 		case ARIZONA_32KZ_MCLK1:
-			ret = pm_runtime_get_sync(arizona->dev);
+			ret = pm_runtime_resume_and_get(arizona->dev);
 			if (ret != 0)
 				goto err_ref;
 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
@@ -1430,6 +1430,15 @@
 	arizona_irq_exit(arizona);
 err_pm:
 	pm_runtime_disable(arizona->dev);
+
+	switch (arizona->pdata.clk32k_src) {
+	case ARIZONA_32KZ_MCLK1:
+	case ARIZONA_32KZ_MCLK2:
+		arizona_clk32k_disable(arizona);
+		break;
+	default:
+		break;
+	}
 err_reset:
 	arizona_enable_reset(arizona);
 	regulator_disable(arizona->dcvdd);
@@ -1452,6 +1461,15 @@
 	regulator_disable(arizona->dcvdd);
 	regulator_put(arizona->dcvdd);
 
+	switch (arizona->pdata.clk32k_src) {
+	case ARIZONA_32KZ_MCLK1:
+	case ARIZONA_32KZ_MCLK2:
+		arizona_clk32k_disable(arizona);
+		break;
+	default:
+		break;
+	}
+
 	mfd_remove_devices(arizona->dev);
 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
--- linux-ein-5.4.0.orig/drivers/mfd/arizona-irq.c
+++ linux-ein-5.4.0/drivers/mfd/arizona-irq.c
@@ -100,7 +100,7 @@
 	unsigned int val;
 	int ret;
 
-	ret = pm_runtime_get_sync(arizona->dev);
+	ret = pm_runtime_resume_and_get(arizona->dev);
 	if (ret < 0) {
 		dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
 		return IRQ_NONE;
--- linux-ein-5.4.0.orig/drivers/mfd/asic3.c
+++ linux-ein-5.4.0/drivers/mfd/asic3.c
@@ -914,14 +914,14 @@
 		ret = mfd_add_devices(&pdev->dev, pdev->id,
 			&asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL);
 		if (ret < 0)
-			goto out;
+			goto out_unmap;
 	}
 
 	if (mem_sdio && (irq >= 0)) {
 		ret = mfd_add_devices(&pdev->dev, pdev->id,
 			&asic3_cell_mmc, 1, mem_sdio, irq, NULL);
 		if (ret < 0)
-			goto out;
+			goto out_unmap;
 	}
 
 	ret = 0;
@@ -935,8 +935,12 @@
 		ret = mfd_add_devices(&pdev->dev, 0,
 			asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL);
 	}
+	return ret;
 
- out:
+out_unmap:
+	if (asic->tmio_cnf)
+		iounmap(asic->tmio_cnf);
+out:
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/mfd/axp20x.c
+++ linux-ein-5.4.0/drivers/mfd/axp20x.c
@@ -125,12 +125,13 @@
 
 static const struct regmap_range axp288_volatile_ranges[] = {
 	regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON),
+	regmap_reg_range(AXP22X_PWR_OUT_CTRL1, AXP22X_ALDO3_V_OUT),
 	regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL),
-	regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT),
+	regmap_reg_range(AXP288_BC_DET_STAT, AXP20X_VBUS_IPSOUT_MGMT),
 	regmap_reg_range(AXP20X_CHRG_BAK_CTRL, AXP20X_CHRG_BAK_CTRL),
 	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
 	regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
-	regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
+	regmap_reg_range(AXP20X_GPIO1_CTRL, AXP22X_GPIO_STATE),
 	regmap_reg_range(AXP288_RT_BATT_V_H, AXP288_RT_BATT_V_L),
 	regmap_reg_range(AXP20X_FG_RES, AXP288_FG_CC_CAP_REG),
 };
--- linux-ein-5.4.0.orig/drivers/mfd/bd9571mwv.c
+++ linux-ein-5.4.0/drivers/mfd/bd9571mwv.c
@@ -185,9 +185,9 @@
 		return ret;
 	}
 
-	ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells,
-			      ARRAY_SIZE(bd9571mwv_cells), NULL, 0,
-			      regmap_irq_get_domain(bd->irq_data));
+	ret = devm_mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO,
+				   bd9571mwv_cells, ARRAY_SIZE(bd9571mwv_cells),
+				   NULL, 0, regmap_irq_get_domain(bd->irq_data));
 	if (ret) {
 		regmap_del_irq_chip(bd->irq, bd->irq_data);
 		return ret;
--- linux-ein-5.4.0.orig/drivers/mfd/da9052-i2c.c
+++ linux-ein-5.4.0/drivers/mfd/da9052-i2c.c
@@ -113,6 +113,7 @@
 	{"da9053-bc", DA9053_BC},
 	{}
 };
+MODULE_DEVICE_TABLE(i2c, da9052_i2c_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id dialog_dt_ids[] = {
--- linux-ein-5.4.0.orig/drivers/mfd/da9062-core.c
+++ linux-ein-5.4.0/drivers/mfd/da9062-core.c
@@ -248,7 +248,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-ein-5.4.0.orig/drivers/mfd/davinci_voicecodec.c
+++ linux-ein-5.4.0/drivers/mfd/davinci_voicecodec.c
@@ -46,14 +46,12 @@
 	}
 	clk_enable(davinci_vc->clk);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-	fifo_base = (dma_addr_t)res->start;
-	davinci_vc->base = devm_ioremap_resource(&pdev->dev, res);
+	davinci_vc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 	if (IS_ERR(davinci_vc->base)) {
 		ret = PTR_ERR(davinci_vc->base);
 		goto fail;
 	}
+	fifo_base = (dma_addr_t)res->start;
 
 	davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev,
 						   davinci_vc->base,
--- linux-ein-5.4.0.orig/drivers/mfd/db8500-prcmu.c
+++ linux-ein-5.4.0/drivers/mfd/db8500-prcmu.c
@@ -1695,22 +1695,20 @@
 }
 
 static const unsigned long db8500_armss_freqs[] = {
-	200000000,
-	400000000,
-	800000000,
+	199680000,
+	399360000,
+	798720000,
 	998400000
 };
 
 /* The DB8520 has slightly higher ARMSS max frequency */
 static const unsigned long db8520_armss_freqs[] = {
-	200000000,
-	400000000,
-	800000000,
+	199680000,
+	399360000,
+	798720000,
 	1152000000
 };
 
-
-
 static long round_armss_rate(unsigned long rate)
 {
 	unsigned long freq = 0;
--- linux-ein-5.4.0.orig/drivers/mfd/dln2.c
+++ linux-ein-5.4.0/drivers/mfd/dln2.c
@@ -90,6 +90,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;
@@ -282,7 +287,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))
@@ -722,6 +731,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;
@@ -731,12 +742,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-ein-5.4.0.orig/drivers/mfd/fsl-imx25-tsadc.c
+++ linux-ein-5.4.0/drivers/mfd/fsl-imx25-tsadc.c
@@ -69,7 +69,7 @@
 	int irq;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
+	if (irq < 0)
 		return irq;
 
 	tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops,
@@ -84,6 +84,19 @@
 	return 0;
 }
 
+static int mx25_tsadc_unset_irq(struct platform_device *pdev)
+{
+	struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
+	int irq = platform_get_irq(pdev, 0);
+
+	if (irq >= 0) {
+		irq_set_chained_handler_and_data(irq, NULL, NULL);
+		irq_domain_remove(tsadc->domain);
+	}
+
+	return 0;
+}
+
 static void mx25_tsadc_setup_clk(struct platform_device *pdev,
 				 struct mx25_tsadc *tsadc)
 {
@@ -171,18 +184,21 @@
 
 	platform_set_drvdata(pdev, tsadc);
 
-	return devm_of_platform_populate(dev);
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		goto err_irq;
+
+	return 0;
+
+err_irq:
+	mx25_tsadc_unset_irq(pdev);
+
+	return ret;
 }
 
 static int mx25_tsadc_remove(struct platform_device *pdev)
 {
-	struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
-	int irq = platform_get_irq(pdev, 0);
-
-	if (irq) {
-		irq_set_chained_handler_and_data(irq, NULL, NULL);
-		irq_domain_remove(tsadc->domain);
-	}
+	mx25_tsadc_unset_irq(pdev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mfd/gateworks-gsc.c
+++ linux-ein-5.4.0/drivers/mfd/gateworks-gsc.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Gateworks System Controller (GSC) is a multi-function
+ * device designed for use in Gateworks Single Board Computers.
+ * The control interface is I2C, with an interrupt. The device supports
+ * system functions such as push-button monitoring, multiple ADC's for
+ * voltage and temperature monitoring, fan controller and watchdog monitor.
+ *
+ * Copyright (C) 2020 Gateworks Corporation
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/gsc.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <asm/unaligned.h>
+
+/*
+ * The GSC suffers from an errata where occasionally during
+ * ADC cycles the chip can NAK I2C transactions. To ensure we have reliable
+ * register access we place retries around register access.
+ */
+#define I2C_RETRIES	3
+
+int gsc_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+	int retry, ret;
+
+	for (retry = 0; retry < I2C_RETRIES; retry++) {
+		ret = i2c_smbus_write_byte_data(client, reg, val);
+		/*
+		 * -EAGAIN returned when the i2c host controller is busy
+		 * -EIO returned when i2c device is busy
+		 */
+		if (ret != -EAGAIN && ret != -EIO)
+			break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gsc_write);
+
+int gsc_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	int retry, ret;
+
+	for (retry = 0; retry < I2C_RETRIES; retry++) {
+		ret = i2c_smbus_read_byte_data(client, reg);
+		/*
+		 * -EAGAIN returned when the i2c host controller is busy
+		 * -EIO returned when i2c device is busy
+		 */
+		if (ret != -EAGAIN && ret != -EIO)
+			break;
+	}
+	*val = ret & 0xff;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gsc_read);
+
+/*
+ * gsc_powerdown - API to use GSC to power down board for a specific time
+ *
+ * secs - number of seconds to remain powered off
+ */
+static int gsc_powerdown(struct gsc_dev *gsc, unsigned long secs)
+{
+	int ret;
+	unsigned char regs[4];
+
+	dev_info(&gsc->i2c->dev, "GSC powerdown for %ld seconds\n",
+		 secs);
+
+	put_unaligned_le32(secs, regs);
+	ret = regmap_bulk_write(gsc->regmap, GSC_TIME_ADD, regs, 4);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1,
+				 BIT(GSC_CTRL_1_SLEEP_ADD),
+				 BIT(GSC_CTRL_1_SLEEP_ADD));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1,
+				 BIT(GSC_CTRL_1_SLEEP_ACTIVATE) |
+				 BIT(GSC_CTRL_1_SLEEP_ENABLE),
+				 BIT(GSC_CTRL_1_SLEEP_ACTIVATE) |
+				 BIT(GSC_CTRL_1_SLEEP_ENABLE));
+
+
+	return ret;
+}
+
+static ssize_t gsc_show(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct gsc_dev *gsc = dev_get_drvdata(dev);
+	const char *name = attr->attr.name;
+	int rz = 0;
+
+	if (strcasecmp(name, "fw_version") == 0)
+		rz = sprintf(buf, "%d\n", gsc->fwver);
+	else if (strcasecmp(name, "fw_crc") == 0)
+		rz = sprintf(buf, "0x%04x\n", gsc->fwcrc);
+	else
+		dev_err(dev, "invalid command: '%s'\n", name);
+
+	return rz;
+}
+
+static ssize_t gsc_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct gsc_dev *gsc = dev_get_drvdata(dev);
+	const char *name = attr->attr.name;
+	long value;
+
+	if (strcasecmp(name, "powerdown") == 0) {
+		if (kstrtol(buf, 0, &value) == 0)
+			gsc_powerdown(gsc, value);
+	} else {
+		dev_err(dev, "invalid command: '%s\n", name);
+	}
+
+	return count;
+}
+
+static struct device_attribute attr_fwver =
+	__ATTR(fw_version, 0440, gsc_show, NULL);
+static struct device_attribute attr_fwcrc =
+	__ATTR(fw_crc, 0440, gsc_show, NULL);
+static struct device_attribute attr_pwrdown =
+	__ATTR(powerdown, 0220, NULL, gsc_store);
+
+static struct attribute *gsc_attrs[] = {
+	&attr_fwver.attr,
+	&attr_fwcrc.attr,
+	&attr_pwrdown.attr,
+	NULL,
+};
+
+static struct attribute_group attr_group = {
+	.attrs = gsc_attrs,
+};
+
+static const struct of_device_id gsc_of_match[] = {
+	{ .compatible = "gw,gsc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gsc_of_match);
+
+static struct regmap_bus gsc_regmap_bus = {
+	.reg_read = gsc_read,
+	.reg_write = gsc_write,
+};
+
+static const struct regmap_config gsc_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+	.max_register = GSC_WP,
+};
+
+static const struct regmap_irq gsc_irqs[] = {
+	REGMAP_IRQ_REG(GSC_IRQ_PB, 0, BIT(GSC_IRQ_PB)),
+	REGMAP_IRQ_REG(GSC_IRQ_KEY_ERASED, 0, BIT(GSC_IRQ_KEY_ERASED)),
+	REGMAP_IRQ_REG(GSC_IRQ_EEPROM_WP, 0, BIT(GSC_IRQ_EEPROM_WP)),
+	REGMAP_IRQ_REG(GSC_IRQ_RESV, 0, BIT(GSC_IRQ_RESV)),
+	REGMAP_IRQ_REG(GSC_IRQ_GPIO, 0, BIT(GSC_IRQ_GPIO)),
+	REGMAP_IRQ_REG(GSC_IRQ_TAMPER, 0, BIT(GSC_IRQ_TAMPER)),
+	REGMAP_IRQ_REG(GSC_IRQ_WDT_TIMEOUT, 0, BIT(GSC_IRQ_WDT_TIMEOUT)),
+	REGMAP_IRQ_REG(GSC_IRQ_SWITCH_HOLD, 0, BIT(GSC_IRQ_SWITCH_HOLD)),
+};
+
+static const struct regmap_irq_chip gsc_irq_chip = {
+	.name = "gateworks-gsc",
+	.irqs = gsc_irqs,
+	.num_irqs = ARRAY_SIZE(gsc_irqs),
+	.num_regs = 1,
+	.status_base = GSC_IRQ_STATUS,
+	.mask_base = GSC_IRQ_ENABLE,
+	.mask_invert = true,
+	.ack_base = GSC_IRQ_STATUS,
+	.ack_invert = true,
+};
+
+static int gsc_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct gsc_dev *gsc;
+	struct regmap_irq_chip_data *irq_data;
+	int ret;
+	unsigned int reg;
+
+	gsc = devm_kzalloc(dev, sizeof(*gsc), GFP_KERNEL);
+	if (!gsc)
+		return -ENOMEM;
+
+	gsc->dev = &client->dev;
+	gsc->i2c = client;
+	i2c_set_clientdata(client, gsc);
+
+	gsc->regmap = devm_regmap_init(dev, &gsc_regmap_bus, client,
+				       &gsc_regmap_config);
+	if (IS_ERR(gsc->regmap))
+		return PTR_ERR(gsc->regmap);
+
+	if (regmap_read(gsc->regmap, GSC_FW_VER, &reg))
+		return -EIO;
+	gsc->fwver = reg;
+
+	regmap_read(gsc->regmap, GSC_FW_CRC, &reg);
+	gsc->fwcrc = reg;
+	regmap_read(gsc->regmap, GSC_FW_CRC + 1, &reg);
+	gsc->fwcrc |= reg << 8;
+
+	gsc->i2c_hwmon = devm_i2c_new_dummy_device(dev, client->adapter,
+						   GSC_HWMON);
+	if (IS_ERR(gsc->i2c_hwmon)) {
+		dev_err(dev, "Failed to allocate I2C device for HWMON\n");
+		return PTR_ERR(gsc->i2c_hwmon);
+	}
+
+	ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq,
+				       IRQF_ONESHOT | IRQF_SHARED |
+				       IRQF_TRIGGER_FALLING, 0,
+				       &gsc_irq_chip, &irq_data);
+	if (ret)
+		return ret;
+
+	dev_info(dev, "Gateworks System Controller v%d: fw 0x%04x\n",
+		 gsc->fwver, gsc->fwcrc);
+
+	ret = sysfs_create_group(&dev->kobj, &attr_group);
+	if (ret)
+		dev_err(dev, "failed to create sysfs attrs\n");
+
+	ret = devm_of_platform_populate(dev);
+	if (ret) {
+		sysfs_remove_group(&dev->kobj, &attr_group);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int gsc_remove(struct i2c_client *client)
+{
+	sysfs_remove_group(&client->dev.kobj, &attr_group);
+
+	return 0;
+}
+
+static struct i2c_driver gsc_driver = {
+	.driver = {
+		.name	= "gateworks-gsc",
+		.of_match_table = gsc_of_match,
+	},
+	.probe_new	= gsc_probe,
+	.remove		= gsc_remove,
+};
+module_i2c_driver(gsc_driver);
+
+MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
+MODULE_DESCRIPTION("I2C Core interface for GSC");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/mfd/imx-audiomix.c
+++ linux-ein-5.4.0/drivers/mfd/imx-audiomix.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/mfd/core.h>
+
+static int imx_audiomix_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *base;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	dev_set_drvdata(dev, base);
+
+	return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id imx_audiomix_of_match[] = {
+	{ .compatible = "fsl,imx8mp-audiomix" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_audiomix_of_match);
+
+static struct platform_driver imx_audiomix_driver = {
+	.probe = imx_audiomix_probe,
+	.driver = {
+		.name = "imx-audiomix",
+		.of_match_table = of_match_ptr(imx_audiomix_of_match),
+	},
+};
+module_platform_driver(imx_audiomix_driver);
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/mfd/intel-lpss-acpi.c
+++ linux-ein-5.4.0/drivers/mfd/intel-lpss-acpi.c
@@ -102,6 +102,7 @@
 {
 	struct intel_lpss_platform_info *info;
 	const struct acpi_device_id *id;
+	int ret;
 
 	id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev);
 	if (!id)
@@ -113,12 +114,19 @@
 		return -ENOMEM;
 
 	info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!info->mem)
+		return -ENODEV;
+
 	info->irq = platform_get_irq(pdev, 0);
 
+	ret = intel_lpss_probe(&pdev->dev, info);
+	if (ret)
+		return ret;
+
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
-	return intel_lpss_probe(&pdev->dev, info);
+	return 0;
 }
 
 static int intel_lpss_acpi_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/mfd/intel-lpss-pci.c
+++ linux-ein-5.4.0/drivers/mfd/intel-lpss-pci.c
@@ -122,13 +122,25 @@
 	.properties = apl_i2c_properties,
 };
 
+static struct property_entry glk_i2c_properties[] = {
+	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313),
+	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290),
+	{ },
+};
+
+static const struct intel_lpss_platform_info glk_i2c_info = {
+	.clk_rate = 133000000,
+	.properties = glk_i2c_properties,
+};
+
 static const struct intel_lpss_platform_info cnl_i2c_info = {
 	.clk_rate = 216000000,
 	.properties = spt_i2c_properties,
 };
 
 static const struct pci_device_id intel_lpss_pci_ids[] = {
-	/* CML */
+	/* CML-LP */
 	{ PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&spt_info },
@@ -141,6 +153,17 @@
 	{ PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&spt_info },
+	/* CML-H */
+	{ PCI_VDEVICE(INTEL, 0x06a8), (kernel_ulong_t)&spt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x06a9), (kernel_ulong_t)&spt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&spt_info },
+	{ PCI_VDEVICE(INTEL, 0x06c7), (kernel_ulong_t)&spt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x06e8), (kernel_ulong_t)&cnl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x06e9), (kernel_ulong_t)&cnl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x06ea), (kernel_ulong_t)&cnl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x06eb), (kernel_ulong_t)&cnl_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&spt_info },
 	/* BXT A-Step */
 	{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info },
@@ -173,15 +196,18 @@
 	{ PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
+	/* EBG */
+	{ PCI_VDEVICE(INTEL, 0x1bad), (kernel_ulong_t)&bxt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x1bae), (kernel_ulong_t)&bxt_uart_info },
 	/* GLK */
-	{ PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&bxt_i2c_info },
-	{ PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&glk_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&glk_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info },
@@ -202,6 +228,22 @@
 	{ PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info },
 	{ PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info },
+	/* TGL-H */
+	{ PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x43a9), (kernel_ulong_t)&bxt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&bxt_info },
+	{ PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&bxt_info },
+	{ PCI_VDEVICE(INTEL, 0x43ad), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43ae), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43d8), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43da), (kernel_ulong_t)&bxt_uart_info },
+	{ PCI_VDEVICE(INTEL, 0x43e8), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43e9), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43ea), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43eb), (kernel_ulong_t)&bxt_i2c_info },
+	{ PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&bxt_info },
+	{ PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&bxt_info },
 	/* EHL */
 	{ PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info },
 	{ PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info },
--- linux-ein-5.4.0.orig/drivers/mfd/intel-lpss.c
+++ linux-ein-5.4.0/drivers/mfd/intel-lpss.c
@@ -384,7 +384,7 @@
 	if (!lpss)
 		return -ENOMEM;
 
-	lpss->priv = devm_ioremap(dev, info->mem->start + LPSS_PRIV_OFFSET,
+	lpss->priv = devm_ioremap_uc(dev, info->mem->start + LPSS_PRIV_OFFSET,
 				  LPSS_PRIV_SIZE);
 	if (!lpss->priv)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/mfd/intel_soc_pmic_core.c
+++ linux-ein-5.4.0/drivers/mfd/intel_soc_pmic_core.c
@@ -111,6 +111,7 @@
 	return 0;
 
 err_del_irq_chip:
+	pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
 	regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/mfd/ipaq-micro.c
+++ linux-ein-5.4.0/drivers/mfd/ipaq-micro.c
@@ -407,7 +407,7 @@
 	micro_reset_comm(micro);
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq)
+	if (irq < 0)
 		return -EINVAL;
 	ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr,
 			       IRQF_SHARED, "ipaq-micro",
--- linux-ein-5.4.0.orig/drivers/mfd/lp8788-irq.c
+++ linux-ein-5.4.0/drivers/mfd/lp8788-irq.c
@@ -175,6 +175,7 @@
 				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 				"lp8788-irq", irqd);
 	if (ret) {
+		irq_domain_remove(lp->irqdm);
 		dev_err(lp->dev, "failed to create a thread for IRQ_N\n");
 		return ret;
 	}
@@ -188,4 +189,6 @@
 {
 	if (lp->irq)
 		free_irq(lp->irq, lp->irqdm);
+	if (lp->irqdm)
+		irq_domain_remove(lp->irqdm);
 }
--- linux-ein-5.4.0.orig/drivers/mfd/lp8788.c
+++ linux-ein-5.4.0/drivers/mfd/lp8788.c
@@ -195,8 +195,16 @@
 	if (ret)
 		return ret;
 
-	return mfd_add_devices(lp->dev, -1, lp8788_devs,
-			       ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
+	ret = mfd_add_devices(lp->dev, -1, lp8788_devs,
+			      ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
+	if (ret)
+		goto err_exit_irq;
+
+	return 0;
+
+err_exit_irq:
+	lp8788_irq_exit(lp);
+	return ret;
 }
 
 static int lp8788_remove(struct i2c_client *cl)
--- linux-ein-5.4.0.orig/drivers/mfd/max77620.c
+++ linux-ein-5.4.0/drivers/mfd/max77620.c
@@ -418,9 +418,11 @@
 		ret = max77620_config_fps(chip, fps_child);
 		if (ret < 0) {
 			of_node_put(fps_child);
+			of_node_put(fps_np);
 			return ret;
 		}
 	}
+	of_node_put(fps_np);
 
 	config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0;
 	ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
--- linux-ein-5.4.0.orig/drivers/mfd/mc13xxx-core.c
+++ linux-ein-5.4.0/drivers/mfd/mc13xxx-core.c
@@ -323,8 +323,10 @@
 		adc1 |= MC13783_ADC1_ATOX;
 
 	dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
-	mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
+	ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
 			mc13xxx_handler_adcdone, __func__, &adcdone_data);
+	if (ret)
+		goto out;
 
 	mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
 	mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
--- linux-ein-5.4.0.orig/drivers/mfd/mfd-core.c
+++ linux-ein-5.4.0/drivers/mfd/mfd-core.c
@@ -28,6 +28,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);
@@ -45,6 +50,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);
--- linux-ein-5.4.0.orig/drivers/mfd/motorola-cpcap.c
+++ linux-ein-5.4.0/drivers/mfd/motorola-cpcap.c
@@ -97,7 +97,6 @@
 		.ack_base = CPCAP_REG_MI1,
 		.mask_base = CPCAP_REG_MIM1,
 		.use_ack = true,
-		.ack_invert = true,
 	},
 	{
 		.name = "cpcap-m2",
@@ -106,7 +105,6 @@
 		.ack_base = CPCAP_REG_MI2,
 		.mask_base = CPCAP_REG_MIM2,
 		.use_ack = true,
-		.ack_invert = true,
 	},
 	{
 		.name = "cpcap1-4",
@@ -115,7 +113,6 @@
 		.ack_base = CPCAP_REG_INT1,
 		.mask_base = CPCAP_REG_INTM1,
 		.use_ack = true,
-		.ack_invert = true,
 	},
 };
 
@@ -305,6 +302,10 @@
 	if (ret)
 		return ret;
 
+	/* Parent SPI controller uses DMA, CPCAP and child devices do not */
+	spi->dev.coherent_dma_mask = 0;
+	spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
+
 	return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
 				    ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
 }
--- linux-ein-5.4.0.orig/drivers/mfd/pcf50633-adc.c
+++ linux-ein-5.4.0/drivers/mfd/pcf50633-adc.c
@@ -136,6 +136,7 @@
 			     void *callback_param)
 {
 	struct pcf50633_adc_request *req;
+	int ret;
 
 	/* req is freed when the result is ready, in interrupt handler */
 	req = kmalloc(sizeof(*req), GFP_KERNEL);
@@ -147,7 +148,11 @@
 	req->callback = callback;
 	req->callback_param = callback_param;
 
-	return adc_enqueue_request(pcf, req);
+	ret = adc_enqueue_request(pcf, req);
+	if (ret)
+		kfree(req);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
 
--- linux-ein-5.4.0.orig/drivers/mfd/rn5t618.c
+++ linux-ein-5.4.0/drivers/mfd/rn5t618.c
@@ -26,6 +26,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-ein-5.4.0.orig/drivers/mfd/rt5033.c
+++ linux-ein-5.4.0/drivers/mfd/rt5033.c
@@ -42,9 +42,6 @@
 		.name = "rt5033-charger",
 		.of_compatible = "richtek,rt5033-charger",
 	}, {
-		.name = "rt5033-battery",
-		.of_compatible = "richtek,rt5033-battery",
-	}, {
 		.name = "rt5033-led",
 		.of_compatible = "richtek,rt5033-led",
 	},
--- linux-ein-5.4.0.orig/drivers/mfd/sm501.c
+++ linux-ein-5.4.0/drivers/mfd/sm501.c
@@ -1424,8 +1424,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);
@@ -1727,7 +1733,12 @@
 
 static int __init sm501_base_init(void)
 {
-	platform_driver_register(&sm501_plat_driver);
+	int ret;
+
+	ret = platform_driver_register(&sm501_plat_driver);
+	if (ret < 0)
+		return ret;
+
 	return pci_register_driver(&sm501_pci_driver);
 }
 
--- linux-ein-5.4.0.orig/drivers/mfd/sprd-sc27xx-spi.c
+++ linux-ein-5.4.0/drivers/mfd/sprd-sc27xx-spi.c
@@ -204,7 +204,7 @@
 	}
 
 	ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq,
-				       IRQF_ONESHOT | IRQF_NO_SUSPEND, 0,
+				       IRQF_ONESHOT, 0,
 				       &ddata->irq_chip, &ddata->irq_data);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to add PMIC irq chip %d\n", ret);
@@ -220,9 +220,34 @@
 		return ret;
 	}
 
+	device_init_wakeup(&spi->dev, true);
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sprd_pmic_suspend(struct device *dev)
+{
+	struct sprd_pmic *ddata = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(ddata->irq);
+
+	return 0;
+}
+
+static int sprd_pmic_resume(struct device *dev)
+{
+	struct sprd_pmic *ddata = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(ddata->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(sprd_pmic_pm_ops, sprd_pmic_suspend, sprd_pmic_resume);
+
 static const struct of_device_id sprd_pmic_match[] = {
 	{ .compatible = "sprd,sc2731", .data = &sc2731_data },
 	{},
@@ -234,6 +259,7 @@
 		.name = "sc27xx-pmic",
 		.bus = &spi_bus_type,
 		.of_match_table = sprd_pmic_match,
+		.pm = &sprd_pmic_pm_ops,
 	},
 	.probe = sprd_pmic_probe,
 };
--- linux-ein-5.4.0.orig/drivers/mfd/stm32-timers.c
+++ linux-ein-5.4.0/drivers/mfd/stm32-timers.c
@@ -158,13 +158,18 @@
 
 static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
 {
+	u32 arr;
+
+	/* Backup ARR to restore it after getting the maximum value */
+	regmap_read(ddata->regmap, TIM_ARR, &arr);
+
 	/*
 	 * Only the available bits will be written so when readback
 	 * we get the maximum value of auto reload register
 	 */
 	regmap_write(ddata->regmap, TIM_ARR, ~0L);
 	regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
-	regmap_write(ddata->regmap, TIM_ARR, 0x0);
+	regmap_write(ddata->regmap, TIM_ARR, arr);
 }
 
 static void stm32_timers_dma_probe(struct device *dev,
--- linux-ein-5.4.0.orig/drivers/mfd/stmfx.c
+++ linux-ein-5.4.0/drivers/mfd/stmfx.c
@@ -287,14 +287,21 @@
 
 	ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin);
 	if (ret)
-		return ret;
+		goto irq_exit;
 
 	ret = devm_request_threaded_irq(stmfx->dev, client->irq,
 					NULL, stmfx_irq_handler,
 					irqtrigger | IRQF_ONESHOT,
 					"stmfx", stmfx);
 	if (ret)
-		stmfx_irq_exit(client);
+		goto irq_exit;
+
+	stmfx->irq = client->irq;
+
+	return 0;
+
+irq_exit:
+	stmfx_irq_exit(client);
 
 	return ret;
 }
@@ -382,7 +389,7 @@
 
 err:
 	if (stmfx->vdd)
-		return regulator_disable(stmfx->vdd);
+		regulator_disable(stmfx->vdd);
 
 	return ret;
 }
@@ -481,6 +488,8 @@
 	if (ret)
 		return ret;
 
+	disable_irq(stmfx->irq);
+
 	if (stmfx->vdd)
 		return regulator_disable(stmfx->vdd);
 
@@ -501,6 +510,13 @@
 		}
 	}
 
+	/* Reset STMFX - supply has been stopped during suspend */
+	ret = stmfx_chip_reset(stmfx);
+	if (ret) {
+		dev_err(stmfx->dev, "Failed to reset chip: %d\n", ret);
+		return ret;
+	}
+
 	ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL,
 			       &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
 	if (ret)
@@ -517,6 +533,8 @@
 	if (ret)
 		return ret;
 
+	enable_irq(stmfx->irq);
+
 	return 0;
 }
 #endif
--- linux-ein-5.4.0.orig/drivers/mfd/stmpe-i2c.c
+++ linux-ein-5.4.0/drivers/mfd/stmpe-i2c.c
@@ -109,7 +109,7 @@
 	{ "stmpe2403", STMPE2403 },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, stmpe_id);
+MODULE_DEVICE_TABLE(i2c, stmpe_i2c_id);
 
 static struct i2c_driver stmpe_i2c_driver = {
 	.driver = {
--- linux-ein-5.4.0.orig/drivers/mfd/stmpe.c
+++ linux-ein-5.4.0/drivers/mfd/stmpe.c
@@ -1091,7 +1091,7 @@
 
 	if (variant->id_val == STMPE801_ID ||
 	    variant->id_val == STMPE1600_ID) {
-		int base = irq_create_mapping(stmpe->domain, 0);
+		int base = irq_find_mapping(stmpe->domain, 0);
 
 		handle_nested_irq(base);
 		return IRQ_HANDLED;
@@ -1119,7 +1119,7 @@
 		while (status) {
 			int bit = __ffs(status);
 			int line = bank * 8 + bit;
-			int nestedirq = irq_create_mapping(stmpe->domain, line);
+			int nestedirq = irq_find_mapping(stmpe->domain, line);
 
 			handle_nested_irq(nestedirq);
 			status &= ~(1 << bit);
@@ -1494,9 +1494,9 @@
 
 int stmpe_remove(struct stmpe *stmpe)
 {
-	if (!IS_ERR(stmpe->vio))
+	if (!IS_ERR(stmpe->vio) && regulator_is_enabled(stmpe->vio))
 		regulator_disable(stmpe->vio);
-	if (!IS_ERR(stmpe->vcc))
+	if (!IS_ERR(stmpe->vcc) && regulator_is_enabled(stmpe->vcc))
 		regulator_disable(stmpe->vcc);
 
 	__stmpe_disable(stmpe, STMPE_BLOCK_ADC);
--- linux-ein-5.4.0.orig/drivers/mfd/t7l66xb.c
+++ linux-ein-5.4.0/drivers/mfd/t7l66xb.c
@@ -405,11 +405,8 @@
 
 static int t7l66xb_remove(struct platform_device *dev)
 {
-	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
-	int ret;
 
-	ret = pdata->disable(dev);
 	clk_disable_unprepare(t7l66xb->clk48m);
 	clk_put(t7l66xb->clk48m);
 	clk_disable_unprepare(t7l66xb->clk32k);
@@ -420,8 +417,7 @@
 	mfd_remove_devices(&dev->dev);
 	kfree(t7l66xb);
 
-	return ret;
-
+	return 0;
 }
 
 static struct platform_driver t7l66xb_platform_driver = {
--- linux-ein-5.4.0.orig/drivers/mfd/tc3589x.c
+++ linux-ein-5.4.0/drivers/mfd/tc3589x.c
@@ -187,7 +187,7 @@
 
 	while (status) {
 		int bit = __ffs(status);
-		int virq = irq_create_mapping(tc3589x->domain, bit);
+		int virq = irq_find_mapping(tc3589x->domain, bit);
 
 		handle_nested_irq(virq);
 		status &= ~(1 << bit);
--- linux-ein-5.4.0.orig/drivers/mfd/tqmx86.c
+++ linux-ein-5.4.0/drivers/mfd/tqmx86.c
@@ -210,6 +210,8 @@
 
 		/* Assumes the IRQ resource is first. */
 		tqmx_gpio_resources[0].start = gpio_irq;
+	} else {
+		tqmx_gpio_resources[0].flags = 0;
 	}
 
 	ocores_platfom_data.clock_khz = tqmx86_board_id_to_clk_rate(board_id);
--- linux-ein-5.4.0.orig/drivers/mfd/wm831x-auxadc.c
+++ linux-ein-5.4.0/drivers/mfd/wm831x-auxadc.c
@@ -93,11 +93,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-ein-5.4.0.orig/drivers/mfd/wm8994-core.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/mfd/wm8994-irq.c
+++ linux-ein-5.4.0/drivers/mfd/wm8994-irq.c
@@ -154,7 +154,7 @@
 	struct wm8994 *wm8994 = data;
 
 	while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
-		handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0));
+		handle_nested_irq(irq_find_mapping(wm8994->edge_irq, 0));
 
 	return IRQ_HANDLED;
 }
--- linux-ein-5.4.0.orig/drivers/misc/Kconfig
+++ linux-ein-5.4.0/drivers/misc/Kconfig
@@ -433,6 +433,17 @@
 	  bus. System Configuration interface is one of the possible means
 	  of generating transactions on this bus.
 
+config VESTA_OVERLAY_MGR
+	tristate "Vesta Gateway Device Tree Overlay Manager"
+	depends on OF
+	select EEPROM
+	select OF_OVERLAY
+	help
+	  Say Y here to include support for automatic loading of
+	  device tree overlays when an expansion card is present in the
+	  Vesta Gateway.  Select M to build as a module which
+	  will be named vesta_overlaymgr.
+
 config PCI_ENDPOINT_TEST
 	depends on PCI
 	select CRC32
--- linux-ein-5.4.0.orig/drivers/misc/Makefile
+++ linux-ein-5.4.0/drivers/misc/Makefile
@@ -50,6 +50,7 @@
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+obj-$(CONFIG_VESTA_OVERLAY_MGR) += vesta_overlaymgr.o vesta_expansion.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
--- linux-ein-5.4.0.orig/drivers/misc/altera-stapl/altera.c
+++ linux-ein-5.4.0/drivers/misc/altera-stapl/altera.c
@@ -2112,8 +2112,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,
@@ -2170,7 +2170,7 @@
 						&p[note_table + (8 * i) + 4])];
 
 				if (value != NULL)
-					strlcpy(value, value_ptr, length);
+					strlcpy(value, value_ptr, vallen);
 
 			}
 		}
@@ -2189,13 +2189,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;
 		}
@@ -2449,7 +2449,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-ein-5.4.0.orig/drivers/misc/atmel-ssc.c
+++ linux-ein-5.4.0/drivers/misc/atmel-ssc.c
@@ -10,7 +10,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>
@@ -20,7 +20,7 @@
 #include "../../sound/soc/atmel/atmel_ssc_dai.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)
@@ -28,7 +28,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);
@@ -232,14 +232,14 @@
 	clk_disable_unprepare(ssc->clk);
 
 	ssc->irq = platform_get_irq(pdev, 0);
-	if (!ssc->irq) {
+	if (ssc->irq < 0) {
 		dev_dbg(&pdev->dev, "could not get irq\n");
-		return -ENXIO;
+		return ssc->irq;
 	}
 
-	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);
 
@@ -258,9 +258,9 @@
 
 	ssc_sound_dai_remove(ssc);
 
-	spin_lock(&user_lock);
+	mutex_lock(&user_lock);
 	list_del(&ssc->list);
-	spin_unlock(&user_lock);
+	mutex_unlock(&user_lock);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/alcor_pci.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/alcor_pci.c
@@ -133,7 +133,13 @@
 	u32 val32;
 
 	priv->pdev_cap_off    = alcor_pci_find_cap_offset(priv, priv->pdev);
-	priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
+	/*
+	 * A device might be attached to root complex directly and
+	 * priv->parent_pdev will be NULL. In this case we don't check its
+	 * capability and disable ASPM completely.
+	 */
+	if (priv->parent_pdev)
+		priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
 							 priv->parent_pdev);
 
 	if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) {
@@ -254,7 +260,7 @@
 	if (!priv)
 		return -ENOMEM;
 
-	ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL);
+	ret = ida_alloc(&alcor_pci_idr, GFP_KERNEL);
 	if (ret < 0)
 		return ret;
 	priv->id = ret;
@@ -268,7 +274,8 @@
 	ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI);
 	if (ret) {
 		dev_err(&pdev->dev, "Cannot request region\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto error_free_ida;
 	}
 
 	if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
@@ -312,6 +319,8 @@
 
 error_release_regions:
 	pci_release_regions(pdev);
+error_free_ida:
+	ida_free(&alcor_pci_idr, priv->id);
 	return ret;
 }
 
@@ -325,7 +334,7 @@
 
 	mfd_remove_devices(&pdev->dev);
 
-	ida_simple_remove(&alcor_pci_idr, priv->id);
+	ida_free(&alcor_pci_idr, priv->id);
 
 	pci_release_regions(pdev);
 	pci_set_drvdata(pdev, NULL);
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/rts5227.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/rts5227.c
@@ -338,6 +338,11 @@
 {
 	rts5227_extra_init_hw(pcr);
 
+	/* Power down OCP for power consumption */
+	if (!pcr->card_exist)
+		rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
+				OC_POWER_DOWN);
+
 	rtsx_pci_write_register(pcr, FUNC_FORCE_CTL, FUNC_FORCE_UPME_XMT_DBG,
 		FUNC_FORCE_UPME_XMT_DBG);
 	rtsx_pci_write_register(pcr, PCLK_CTL, 0x04, 0x04);
@@ -394,7 +399,8 @@
 void rts522a_init_params(struct rtsx_pcr *pcr)
 {
 	rts5227_init_params(pcr);
-
+	pcr->ops = &rts522a_pcr_ops;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11);
 	pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
 
 	pcr->option.ocp_en = 1;
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/rts5249.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/rts5249.c
@@ -618,6 +618,7 @@
 void rts524a_init_params(struct rtsx_pcr *pcr)
 {
 	rts5249_init_params(pcr);
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
 	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
 	pcr->option.ltr_l1off_snooze_sspwrgate =
 		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
@@ -733,6 +734,7 @@
 void rts525a_init_params(struct rtsx_pcr *pcr)
 {
 	rts5249_init_params(pcr);
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(25, 29, 11);
 	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
 	pcr->option.ltr_l1off_snooze_sspwrgate =
 		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/rts5260.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/rts5260.c
@@ -663,7 +663,7 @@
 	pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
 	pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
 	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
 	pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
 	pcr->ic_version = rts5260_get_ic_version(pcr);
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/rtsx_pcr.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/rtsx_pcr.c
@@ -143,6 +143,9 @@
 
 	rtsx_disable_aspm(pcr);
 
+	/* Fixes DMA transfer timout issue after disabling ASPM on RTS5260 */
+	msleep(1);
+
 	if (option->ltr_enabled)
 		rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
 
@@ -1186,10 +1189,6 @@
 			rtsx_pci_write_register(pcr, REG_OCPGLITCH,
 				SD_OCP_GLITCH_MASK, pcr->hw_param.ocp_glitch);
 			rtsx_pci_enable_ocp(pcr);
-		} else {
-			/* OC power down */
-			rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
-				OC_POWER_DOWN);
 		}
 	}
 }
@@ -1486,7 +1485,7 @@
 	pcr->remap_addr = ioremap_nocache(base, len);
 	if (!pcr->remap_addr) {
 		ret = -ENOMEM;
-		goto free_handle;
+		goto free_idr;
 	}
 
 	pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev),
@@ -1531,12 +1530,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:
@@ -1546,6 +1547,10 @@
 			pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
 unmap:
 	iounmap(pcr->remap_addr);
+free_idr:
+	spin_lock(&rtsx_pci_lock);
+	idr_remove(&rtsx_pci_idr, pcr->id);
+	spin_unlock(&rtsx_pci_lock);
 free_handle:
 	kfree(handle);
 free_pcr:
--- linux-ein-5.4.0.orig/drivers/misc/cardreader/rtsx_usb.c
+++ linux-ein-5.4.0/drivers/misc/cardreader/rtsx_usb.c
@@ -631,16 +631,20 @@
 
 	ucr->pusb_dev = usb_dev;
 
-	ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
-			GFP_KERNEL, &ucr->iobuf_dma);
-	if (!ucr->iobuf)
+	ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+	if (!ucr->cmd_buf)
 		return -ENOMEM;
 
+	ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+	if (!ucr->rsp_buf) {
+		ret = -ENOMEM;
+		goto out_free_cmd_buf;
+	}
+
 	usb_set_intfdata(intf, ucr);
 
 	ucr->vendor_id = id->idVendor;
 	ucr->product_id = id->idProduct;
-	ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
 
 	mutex_init(&ucr->dev_mutex);
 
@@ -667,8 +671,12 @@
 	return 0;
 
 out_init_fail:
-	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-			ucr->iobuf_dma);
+	usb_set_intfdata(ucr->pusb_intf, NULL);
+	kfree(ucr->rsp_buf);
+	ucr->rsp_buf = NULL;
+out_free_cmd_buf:
+	kfree(ucr->cmd_buf);
+	ucr->cmd_buf = NULL;
 	return ret;
 }
 
@@ -681,8 +689,12 @@
 	mfd_remove_devices(&intf->dev);
 
 	usb_set_intfdata(ucr->pusb_intf, NULL);
-	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-			ucr->iobuf_dma);
+
+	kfree(ucr->cmd_buf);
+	ucr->cmd_buf = NULL;
+
+	kfree(ucr->rsp_buf);
+	ucr->rsp_buf = NULL;
 }
 
 #ifdef CONFIG_PM
--- linux-ein-5.4.0.orig/drivers/misc/cb710/sgbuf2.c
+++ linux-ein-5.4.0/drivers/misc/cb710/sgbuf2.c
@@ -47,7 +47,7 @@
 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 	return false;
 #else
-	return ((ptr - NULL) & 3) != 0;
+	return ((uintptr_t)ptr & 3) != 0;
 #endif
 }
 
--- linux-ein-5.4.0.orig/drivers/misc/cxl/flash.c
+++ linux-ein-5.4.0/drivers/misc/cxl/flash.c
@@ -473,12 +473,6 @@
 		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;
@@ -514,7 +508,7 @@
 	.owner		= THIS_MODULE,
 	.open		= device_open,
 	.unlocked_ioctl	= device_ioctl,
-	.compat_ioctl	= device_compat_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
 	.release	= device_close,
 };
 
--- linux-ein-5.4.0.orig/drivers/misc/cxl/guest.c
+++ linux-ein-5.4.0/drivers/misc/cxl/guest.c
@@ -959,10 +959,10 @@
 	 * if it returns an error!
 	 */
 	if ((rc = cxl_register_afu(afu)))
-		goto err_put1;
+		goto err_put_dev;
 
 	if ((rc = cxl_sysfs_afu_add(afu)))
-		goto err_put1;
+		goto err_del_dev;
 
 	/*
 	 * pHyp doesn't expose the programming models supported by the
@@ -978,7 +978,7 @@
 		afu->modes_supported = CXL_MODE_DIRECTED;
 
 	if ((rc = cxl_afu_select_best_mode(afu)))
-		goto err_put2;
+		goto err_remove_sysfs;
 
 	adapter->afu[afu->slice] = afu;
 
@@ -998,10 +998,12 @@
 
 	return 0;
 
-err_put2:
+err_remove_sysfs:
 	cxl_sysfs_afu_remove(afu);
-err_put1:
-	device_unregister(&afu->dev);
+err_del_dev:
+	device_del(&afu->dev);
+err_put_dev:
+	put_device(&afu->dev);
 	free = false;
 	guest_release_serr_irq(afu);
 err2:
@@ -1135,18 +1137,20 @@
 	 * even if it returns an error!
 	 */
 	if ((rc = cxl_register_adapter(adapter)))
-		goto err_put1;
+		goto err_put_dev;
 
 	if ((rc = cxl_sysfs_adapter_add(adapter)))
-		goto err_put1;
+		goto err_del_dev;
 
 	/* release the context lock as the adapter is configured */
 	cxl_adapter_context_unlock(adapter);
 
 	return adapter;
 
-err_put1:
-	device_unregister(&adapter->dev);
+err_del_dev:
+	device_del(&adapter->dev);
+err_put_dev:
+	put_device(&adapter->dev);
 	free = false;
 	cxl_guest_remove_chardev(adapter);
 err1:
--- linux-ein-5.4.0.orig/drivers/misc/cxl/irq.c
+++ linux-ein-5.4.0/drivers/misc/cxl/irq.c
@@ -349,6 +349,7 @@
 
 out:
 	cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
+	bitmap_free(ctx->irq_bitmap);
 	afu_irq_name_free(ctx);
 	return -ENOMEM;
 }
--- linux-ein-5.4.0.orig/drivers/misc/cxl/pci.c
+++ linux-ein-5.4.0/drivers/misc/cxl/pci.c
@@ -387,14 +387,15 @@
 	rc = get_phb_index(np, phb_index);
 	if (rc) {
 		pr_err("cxl: invalid phb index\n");
+		of_node_put(np);
 		return rc;
 	}
 
 	*capp_unit_id = get_capp_unit_id(np, *phb_index);
 	of_node_put(np);
 	if (!*capp_unit_id) {
-		pr_err("cxl: invalid capp unit id (phb_index: %d)\n",
-		       *phb_index);
+		pr_err("cxl: No capp unit found for PHB[%lld,%d]. Make sure the adapter is on a capi-compatible slot\n",
+		       *chipid, *phb_index);
 		return -ENODEV;
 	}
 
@@ -1164,10 +1165,10 @@
 	 * if it returns an error!
 	 */
 	if ((rc = cxl_register_afu(afu)))
-		goto err_put1;
+		goto err_put_dev;
 
 	if ((rc = cxl_sysfs_afu_add(afu)))
-		goto err_put1;
+		goto err_del_dev;
 
 	adapter->afu[afu->slice] = afu;
 
@@ -1176,10 +1177,12 @@
 
 	return 0;
 
-err_put1:
+err_del_dev:
+	device_del(&afu->dev);
+err_put_dev:
 	pci_deconfigure_afu(afu);
 	cxl_debugfs_afu_remove(afu);
-	device_unregister(&afu->dev);
+	put_device(&afu->dev);
 	return rc;
 
 err_free_native:
@@ -1667,23 +1670,25 @@
 	 * even if it returns an error!
 	 */
 	if ((rc = cxl_register_adapter(adapter)))
-		goto err_put1;
+		goto err_put_dev;
 
 	if ((rc = cxl_sysfs_adapter_add(adapter)))
-		goto err_put1;
+		goto err_del_dev;
 
 	/* Release the context lock as adapter is configured */
 	cxl_adapter_context_unlock(adapter);
 
 	return adapter;
 
-err_put1:
+err_del_dev:
+	device_del(&adapter->dev);
+err_put_dev:
 	/* This should mirror cxl_remove_adapter, except without the
 	 * sysfs parts
 	 */
 	cxl_debugfs_adapter_remove(adapter);
 	cxl_deconfigure_adapter(adapter);
-	device_unregister(&adapter->dev);
+	put_device(&adapter->dev);
 	return ERR_PTR(rc);
 
 err_release:
--- linux-ein-5.4.0.orig/drivers/misc/cxl/sysfs.c
+++ linux-ein-5.4.0/drivers/misc/cxl/sysfs.c
@@ -624,7 +624,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)
--- linux-ein-5.4.0.orig/drivers/misc/eeprom/Kconfig
+++ linux-ein-5.4.0/drivers/misc/eeprom/Kconfig
@@ -6,6 +6,7 @@
 	depends on I2C && SYSFS
 	select NVMEM
 	select NVMEM_SYSFS
+	select REGMAP
 	select REGMAP_I2C
 	help
 	  Enable this driver to get read/write support to most I2C EEPROMs
--- linux-ein-5.4.0.orig/drivers/misc/eeprom/at25.c
+++ linux-ein-5.4.0/drivers/misc/eeprom/at25.c
@@ -358,7 +358,7 @@
 	at25->nvmem_config.reg_read = at25_ee_read;
 	at25->nvmem_config.reg_write = at25_ee_write;
 	at25->nvmem_config.priv = at25;
-	at25->nvmem_config.stride = 4;
+	at25->nvmem_config.stride = 1;
 	at25->nvmem_config.word_size = 1;
 	at25->nvmem_config.size = chip.byte_len;
 
--- linux-ein-5.4.0.orig/drivers/misc/eeprom/ee1004.c
+++ linux-ein-5.4.0/drivers/misc/eeprom/ee1004.c
@@ -82,6 +82,9 @@
 	if (unlikely(offset + count > EE1004_PAGE_SIZE))
 		count = EE1004_PAGE_SIZE - offset;
 
+	if (count > I2C_SMBUS_BLOCK_MAX)
+		count = I2C_SMBUS_BLOCK_MAX;
+
 	status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset,
 							   count, buf);
 	dev_dbg(&client->dev, "read %zu@%d --> %d\n", count, offset, status);
--- linux-ein-5.4.0.orig/drivers/misc/eeprom/eeprom_93xx46.c
+++ linux-ein-5.4.0/drivers/misc/eeprom/eeprom_93xx46.c
@@ -35,6 +35,10 @@
 		  EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
 };
 
+static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
+	.quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE,
+};
+
 struct eeprom_93xx46_dev {
 	struct spi_device *spi;
 	struct eeprom_93xx46_platform_data *pdata;
@@ -55,6 +59,11 @@
 	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
 }
 
+static inline bool has_quirk_extra_read_cycle(struct eeprom_93xx46_dev *edev)
+{
+	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE;
+}
+
 static int eeprom_93xx46_read(void *priv, unsigned int off,
 			      void *val, size_t count)
 {
@@ -96,6 +105,11 @@
 		dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
 			cmd_addr, edev->spi->max_speed_hz);
 
+		if (has_quirk_extra_read_cycle(edev)) {
+			cmd_addr <<= 1;
+			bits += 1;
+		}
+
 		spi_message_init(&m);
 
 		t[0].tx_buf = (char *)&cmd_addr;
@@ -363,6 +377,7 @@
 static const struct of_device_id eeprom_93xx46_of_table[] = {
 	{ .compatible = "eeprom-93xx46", },
 	{ .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
+	{ .compatible = "microchip,93lc46b", .data = &microchip_93lc46b_data, },
 	{}
 };
 MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table);
@@ -511,3 +526,4 @@
 MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
 MODULE_ALIAS("spi:93xx46");
+MODULE_ALIAS("spi:eeprom-93xx46");
--- linux-ein-5.4.0.orig/drivers/misc/eeprom/idt_89hpesx.c
+++ linux-ein-5.4.0/drivers/misc/eeprom/idt_89hpesx.c
@@ -1126,11 +1126,10 @@
 
 	device_for_each_child_node(dev, fwnode) {
 		ee_id = idt_ee_match_id(fwnode);
-		if (!ee_id) {
-			dev_warn(dev, "Skip unsupported EEPROM device");
-			continue;
-		} else
+		if (ee_id)
 			break;
+
+		dev_warn(dev, "Skip unsupported EEPROM device %pfw\n", fwnode);
 	}
 
 	/* If there is no fwnode EEPROM device, then set zero size */
@@ -1161,6 +1160,7 @@
 	else /* if (!fwnode_property_read_bool(node, "read-only")) */
 		pdev->eero = false;
 
+	fwnode_handle_put(fwnode);
 	dev_info(dev, "EEPROM of %d bytes found by 0x%x",
 		pdev->eesize, pdev->eeaddr);
 }
--- linux-ein-5.4.0.orig/drivers/misc/enclosure.c
+++ linux-ein-5.4.0/drivers/misc/enclosure.c
@@ -406,10 +406,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;
--- linux-ein-5.4.0.orig/drivers/misc/fastrpc.c
+++ linux-ein-5.4.0/drivers/misc/fastrpc.c
@@ -218,6 +218,13 @@
 		dma_buf_put(map->buf);
 	}
 
+	if (map->fl) {
+		spin_lock(&map->fl->lock);
+		list_del(&map->node);
+		spin_unlock(&map->fl->lock);
+		map->fl = NULL;
+	}
+
 	kfree(map);
 }
 
@@ -227,10 +234,12 @@
 		kref_put(&map->refcount, fastrpc_free_map);
 }
 
-static void fastrpc_map_get(struct fastrpc_map *map)
+static int fastrpc_map_get(struct fastrpc_map *map)
 {
-	if (map)
-		kref_get(&map->refcount);
+	if (!map)
+		return -ENOENT;
+
+	return kref_get_unless_zero(&map->refcount) ? 0 : -ENOENT;
 }
 
 static int fastrpc_map_find(struct fastrpc_user *fl, int fd,
@@ -693,16 +702,18 @@
 static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
 {
 	u64 size = 0;
-	int i;
+	int oix;
 
 	size = ALIGN(metalen, FASTRPC_ALIGN);
-	for (i = 0; i < ctx->nscalars; i++) {
+	for (oix = 0; oix < ctx->nbufs; oix++) {
+		int i = ctx->olaps[oix].raix;
+
 		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
 
-			if (ctx->olaps[i].offset == 0)
+			if (ctx->olaps[oix].offset == 0)
 				size = ALIGN(size, FASTRPC_ALIGN);
 
-			size += (ctx->olaps[i].mend - ctx->olaps[i].mstart);
+			size += (ctx->olaps[oix].mend - ctx->olaps[oix].mstart);
 		}
 	}
 
@@ -886,6 +897,7 @@
 	struct fastrpc_channel_ctx *cctx;
 	struct fastrpc_user *fl = ctx->fl;
 	struct fastrpc_msg *msg = &ctx->msg;
+	int ret;
 
 	cctx = fl->cctx;
 	msg->pid = fl->tgid;
@@ -901,7 +913,13 @@
 	msg->size = roundup(ctx->msg_sz, PAGE_SIZE);
 	fastrpc_context_get(ctx);
 
-	return rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg));
+	ret = rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg));
+
+	if (ret)
+		fastrpc_context_put(ctx);
+
+	return ret;
+
 }
 
 static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
@@ -917,6 +935,11 @@
 	if (!fl->cctx->rpdev)
 		return -EPIPE;
 
+	if (handle == FASTRPC_INIT_HANDLE && !kernel) {
+		dev_warn_ratelimited(fl->sctx->dev, "user app trying to send a kernel RPC message (%d)\n",  handle);
+		return -EPERM;
+	}
+
 	ctx = fastrpc_context_alloc(fl, kernel, sc, args);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
@@ -1051,7 +1074,7 @@
 
 	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
 	if (init.attrs)
-		sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 6, 0);
+		sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
 
 	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
 				      sc, args);
@@ -1066,12 +1089,7 @@
 	fl->init_mem = NULL;
 	fastrpc_buf_free(imem);
 err_alloc:
-	if (map) {
-		spin_lock(&fl->lock);
-		list_del(&map->node);
-		spin_unlock(&fl->lock);
-		fastrpc_map_put(map);
-	}
+	fastrpc_map_put(map);
 err:
 	kfree(args);
 
@@ -1147,10 +1165,8 @@
 		fastrpc_context_put(ctx);
 	}
 
-	list_for_each_entry_safe(map, m, &fl->maps, node) {
-		list_del(&map->node);
+	list_for_each_entry_safe(map, m, &fl->maps, node)
 		fastrpc_map_put(map);
-	}
 
 	fastrpc_session_free(cctx, fl->sctx);
 	fastrpc_channel_ctx_put(cctx);
@@ -1231,7 +1247,14 @@
 	}
 
 	if (copy_to_user(argp, &bp, sizeof(bp))) {
-		dma_buf_put(buf->dmabuf);
+		/*
+		 * The usercopy failed, but we can't do much about it, as
+		 * dma_buf_fd() already called fd_install() and made the
+		 * file descriptor accessible for the current process. It
+		 * might already be closed and dmabuf no longer valid when
+		 * we reach this point. Therefore "leak" the fd and rely on
+		 * the process exit path to do any required cleanup.
+		 */
 		return -EFAULT;
 	}
 
@@ -1336,7 +1359,12 @@
 	of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
 
 	spin_lock_irqsave(&cctx->lock, flags);
-	sess = &cctx->session[cctx->sesscount];
+	if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) {
+		dev_err(&pdev->dev, "too many sessions\n");
+		spin_unlock_irqrestore(&cctx->lock, flags);
+		return -ENOSPC;
+	}
+	sess = &cctx->session[cctx->sesscount++];
 	sess->used = false;
 	sess->valid = true;
 	sess->dev = dev;
@@ -1349,13 +1377,12 @@
 		struct fastrpc_session_ctx *dup_sess;
 
 		for (i = 1; i < sessions; i++) {
-			if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS)
+			if (cctx->sesscount >= FASTRPC_MAX_SESSIONS)
 				break;
-			dup_sess = &cctx->session[cctx->sesscount];
+			dup_sess = &cctx->session[cctx->sesscount++];
 			memcpy(dup_sess, sess, sizeof(*dup_sess));
 		}
 	}
-	cctx->sesscount++;
 	spin_unlock_irqrestore(&cctx->lock, flags);
 	rc = dma_set_mask(dev, DMA_BIT_MASK(32));
 	if (rc) {
@@ -1374,7 +1401,7 @@
 	int i;
 
 	spin_lock_irqsave(&cctx->lock, flags);
-	for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) {
+	for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) {
 		if (cctx->session[i].sid == sess->sid) {
 			cctx->session[i].valid = false;
 			cctx->sesscount--;
@@ -1430,12 +1457,14 @@
 		return -ENOMEM;
 
 	data->miscdev.minor = MISC_DYNAMIC_MINOR;
-	data->miscdev.name = kasprintf(GFP_KERNEL, "fastrpc-%s",
-				domains[domain_id]);
+	data->miscdev.name = devm_kasprintf(rdev, GFP_KERNEL, "fastrpc-%s",
+					    domains[domain_id]);
 	data->miscdev.fops = &fastrpc_fops;
 	err = misc_register(&data->miscdev);
-	if (err)
+	if (err) {
+		kfree(data);
 		return err;
+	}
 
 	kref_init(&data->refcount);
 
@@ -1455,8 +1484,10 @@
 	struct fastrpc_invoke_ctx *ctx;
 
 	spin_lock(&user->lock);
-	list_for_each_entry(ctx, &user->pending, node)
+	list_for_each_entry(ctx, &user->pending, node) {
+		ctx->retval = -EPIPE;
 		complete(&ctx->work);
+	}
 	spin_unlock(&user->lock);
 }
 
@@ -1466,7 +1497,9 @@
 	struct fastrpc_user *user;
 	unsigned long flags;
 
+	/* No invocations past this point */
 	spin_lock_irqsave(&cctx->lock, flags);
+	cctx->rpdev = NULL;
 	list_for_each_entry(user, &cctx->users, user)
 		fastrpc_notify_users(user);
 	spin_unlock_irqrestore(&cctx->lock, flags);
@@ -1474,7 +1507,6 @@
 	misc_deregister(&cctx->miscdev);
 	of_platform_depopulate(&rpdev->dev);
 
-	cctx->rpdev = NULL;
 	fastrpc_channel_ctx_put(cctx);
 }
 
--- linux-ein-5.4.0.orig/drivers/misc/genwqe/card_dev.c
+++ linux-ein-5.4.0/drivers/misc/genwqe/card_dev.c
@@ -1215,34 +1215,13 @@
 	return rc;
 }
 
-#if defined(CONFIG_COMPAT)
-/**
- * genwqe_compat_ioctl() - Compatibility ioctl
- *
- * Called whenever a 32-bit process running under a 64-bit kernel
- * performs an ioctl on /dev/genwqe<n>_card.
- *
- * @filp:        file pointer.
- * @cmd:         command.
- * @arg:         user argument.
- * Return:       zero on success or negative number on failure.
- */
-static long genwqe_compat_ioctl(struct file *filp, unsigned int cmd,
-				unsigned long arg)
-{
-	return genwqe_ioctl(filp, cmd, arg);
-}
-#endif /* defined(CONFIG_COMPAT) */
-
 static const struct file_operations genwqe_fops = {
 	.owner		= THIS_MODULE,
 	.open		= genwqe_open,
 	.fasync		= genwqe_fasync,
 	.mmap		= genwqe_mmap,
 	.unlocked_ioctl	= genwqe_ioctl,
-#if defined(CONFIG_COMPAT)
-	.compat_ioctl   = genwqe_compat_ioctl,
-#endif
+	.compat_ioctl   = compat_ptr_ioctl,
 	.release	= genwqe_release,
 };
 
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/command_submission.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/command_submission.c
@@ -777,8 +777,9 @@
 	memset(args, 0, sizeof(*args));
 
 	if (rc < 0) {
-		dev_err(hdev->dev, "Error %ld on waiting for CS handle %llu\n",
-			rc, seq);
+		dev_err_ratelimited(hdev->dev,
+				"Error %ld on waiting for CS handle %llu\n",
+				rc, seq);
 		if (rc == -ERESTARTSYS) {
 			args->out.status = HL_WAIT_CS_STATUS_INTERRUPTED;
 			rc = -EINTR;
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/context.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/context.c
@@ -176,7 +176,7 @@
 	spin_lock(&ctx->cs_lock);
 
 	if (seq >= ctx->cs_sequence) {
-		dev_notice(hdev->dev,
+		dev_notice_ratelimited(hdev->dev,
 			"Can't wait on seq %llu because current CS is at seq %llu\n",
 			seq, ctx->cs_sequence);
 		spin_unlock(&ctx->cs_lock);
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/device.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/device.c
@@ -108,6 +108,8 @@
 	list_del(&hpriv->dev_node);
 	mutex_unlock(&hdev->fpriv_list_lock);
 
+	put_pid(hpriv->taskpid);
+
 	kfree(hpriv);
 
 	return 0;
@@ -229,16 +231,16 @@
 
 static void device_cdev_sysfs_del(struct hl_device *hdev)
 {
-	/* device_release() won't be called so must free devices explicitly */
-	if (!hdev->cdev_sysfs_created) {
-		kfree(hdev->dev_ctrl);
-		kfree(hdev->dev);
-		return;
-	}
+	if (!hdev->cdev_sysfs_created)
+		goto put_devices;
 
 	hl_sysfs_fini(hdev);
 	cdev_device_del(&hdev->cdev_ctrl, hdev->dev_ctrl);
 	cdev_device_del(&hdev->cdev, hdev->dev);
+
+put_devices:
+	put_device(hdev->dev);
+	put_device(hdev->dev_ctrl);
 }
 
 /*
@@ -600,7 +602,9 @@
 			goto out;
 		}
 
-		hdev->asic_funcs->halt_coresight(hdev);
+		if (!hdev->hard_reset_pending)
+			hdev->asic_funcs->halt_coresight(hdev);
+
 		hdev->in_debug = 0;
 
 		goto out;
@@ -957,6 +961,7 @@
 						GFP_KERNEL);
 		if (!hdev->kernel_ctx) {
 			rc = -ENOMEM;
+			hl_mmu_fini(hdev);
 			goto out_err;
 		}
 
@@ -968,6 +973,7 @@
 				"failed to init kernel ctx in hard reset\n");
 			kfree(hdev->kernel_ctx);
 			hdev->kernel_ctx = NULL;
+			hl_mmu_fini(hdev);
 			goto out_err;
 		}
 	}
@@ -1185,6 +1191,7 @@
 	if (hdev->asic_funcs->get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
 		dev_info(hdev->dev,
 			"H/W state is dirty, must reset before initializing\n");
+		hdev->asic_funcs->halt_engines(hdev, true);
 		hdev->asic_funcs->hw_fini(hdev, true);
 	}
 
@@ -1282,9 +1289,9 @@
 early_fini:
 	device_early_fini(hdev);
 free_dev_ctrl:
-	kfree(hdev->dev_ctrl);
+	put_device(hdev->dev_ctrl);
 free_dev:
-	kfree(hdev->dev);
+	put_device(hdev->dev);
 out_disabled:
 	hdev->disabled = true;
 	if (add_cdev_sysfs_on_err)
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/firmware_if.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/firmware_if.c
@@ -11,6 +11,7 @@
 #include <linux/genalloc.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 
+#define FW_FILE_MAX_SIZE	0x1400000 /* maximum size of 20MB */
 /**
  * hl_fw_push_fw_to_device() - Push FW code to device.
  * @hdev: pointer to hl_device structure.
@@ -43,6 +44,14 @@
 
 	dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
 
+	if (fw_size > FW_FILE_MAX_SIZE) {
+		dev_err(hdev->dev,
+			"FW file size %zu exceeds maximum of %u bytes\n",
+			fw_size, FW_FILE_MAX_SIZE);
+		rc = -EINVAL;
+		goto out;
+	}
+
 	fw_data = (const u64 *) fw->data;
 
 	memcpy_toio(dst, fw_data, fw_size);
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/goya/goya.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/goya/goya.c
@@ -869,6 +869,11 @@
  */
 static void goya_disable_external_queues(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_DMA))
+		return;
+
 	WREG32(mmDMA_QM_0_GLBL_CFG0, 0);
 	WREG32(mmDMA_QM_1_GLBL_CFG0, 0);
 	WREG32(mmDMA_QM_2_GLBL_CFG0, 0);
@@ -930,6 +935,11 @@
 {
 	int rc, retval = 0;
 
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_DMA))
+		return retval;
+
 	rc = goya_stop_queue(hdev,
 			mmDMA_QM_0_GLBL_CFG1,
 			mmDMA_QM_0_CP_STS,
@@ -1719,9 +1729,18 @@
  */
 static void goya_disable_internal_queues(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_MME))
+		goto disable_tpc;
+
 	WREG32(mmMME_QM_GLBL_CFG0, 0);
 	WREG32(mmMME_CMDQ_GLBL_CFG0, 0);
 
+disable_tpc:
+	if (!(goya->hw_cap_initialized & HW_CAP_TPC))
+		return;
+
 	WREG32(mmTPC0_QM_GLBL_CFG0, 0);
 	WREG32(mmTPC0_CMDQ_GLBL_CFG0, 0);
 
@@ -1757,8 +1776,12 @@
  */
 static int goya_stop_internal_queues(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
 	int rc, retval = 0;
 
+	if (!(goya->hw_cap_initialized & HW_CAP_MME))
+		goto stop_tpc;
+
 	/*
 	 * Each queue (QMAN) is a separate H/W logic. That means that each
 	 * QMAN can be stopped independently and failure to stop one does NOT
@@ -1785,6 +1808,10 @@
 		retval = -EIO;
 	}
 
+stop_tpc:
+	if (!(goya->hw_cap_initialized & HW_CAP_TPC))
+		return retval;
+
 	rc = goya_stop_queue(hdev,
 			mmTPC0_QM_GLBL_CFG1,
 			mmTPC0_QM_CP_STS,
@@ -1950,6 +1977,11 @@
 
 static void goya_dma_stall(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_DMA))
+		return;
+
 	WREG32(mmDMA_QM_0_GLBL_CFG1, 1 << DMA_QM_0_GLBL_CFG1_DMA_STOP_SHIFT);
 	WREG32(mmDMA_QM_1_GLBL_CFG1, 1 << DMA_QM_1_GLBL_CFG1_DMA_STOP_SHIFT);
 	WREG32(mmDMA_QM_2_GLBL_CFG1, 1 << DMA_QM_2_GLBL_CFG1_DMA_STOP_SHIFT);
@@ -1959,6 +1991,11 @@
 
 static void goya_tpc_stall(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_TPC))
+		return;
+
 	WREG32(mmTPC0_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
 	WREG32(mmTPC1_CFG_TPC_STALL, 1 << TPC1_CFG_TPC_STALL_V_SHIFT);
 	WREG32(mmTPC2_CFG_TPC_STALL, 1 << TPC2_CFG_TPC_STALL_V_SHIFT);
@@ -1971,6 +2008,11 @@
 
 static void goya_mme_stall(struct hl_device *hdev)
 {
+	struct goya_device *goya = hdev->asic_specific;
+
+	if (!(goya->hw_cap_initialized & HW_CAP_MME))
+		return;
+
 	WREG32(mmMME_STALL, 0xFFFFFFFF);
 }
 
@@ -2171,7 +2213,7 @@
 
 static int goya_pldm_init_cpu(struct hl_device *hdev)
 {
-	u32 val, unit_rst_val;
+	u32 unit_rst_val;
 	int rc;
 
 	/* Must initialize SRAM scrambler before pushing u-boot to SRAM */
@@ -2179,14 +2221,14 @@
 
 	/* Put ARM cores into reset */
 	WREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL, CPU_RESET_ASSERT);
-	val = RREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL);
+	RREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL);
 
 	/* Reset the CA53 MACRO */
 	unit_rst_val = RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
 	WREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N, CA53_RESET);
-	val = RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
+	RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
 	WREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N, unit_rst_val);
-	val = RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
+	RREG32(mmPSOC_GLOBAL_CONF_UNIT_RST_N);
 
 	rc = goya_push_uboot_to_device(hdev);
 	if (rc)
@@ -2207,7 +2249,7 @@
 	/* Release ARM core 0 from reset */
 	WREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL,
 					CPU_RESET_CORE0_DEASSERT);
-	val = RREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL);
+	RREG32(mmCPU_CA53_CFG_ARM_RST_CONTROL);
 
 	return 0;
 }
@@ -2475,13 +2517,12 @@
 static int goya_hw_init(struct hl_device *hdev)
 {
 	struct asic_fixed_properties *prop = &hdev->asic_prop;
-	u32 val;
 	int rc;
 
 	dev_info(hdev->dev, "Starting initialization of H/W\n");
 
 	/* Perform read from the device to make sure device is up */
-	val = RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
+	RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
 
 	/*
 	 * Let's mark in the H/W that we have reached this point. We check
@@ -2533,7 +2574,7 @@
 		goto disable_queues;
 
 	/* Perform read from the device to flush all MSI-X configuration */
-	val = RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
+	RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
 
 	return 0;
 
@@ -4625,8 +4666,6 @@
 
 	rc = goya_send_job_on_qman0(hdev, job);
 
-	hl_cb_put(job->patched_cb);
-
 	hl_debugfs_remove_job(hdev, job);
 	kfree(job);
 	cb->cs_cnt--;
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/goya/goya_security.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/goya/goya_security.c
@@ -695,7 +695,6 @@
 	mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
-	mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC0_CFG_TPC_STALL & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC0_CFG_MSS_CONFIG & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC0_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
@@ -875,6 +874,16 @@
 	goya_pb_set_block(hdev, mmTPC1_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC1_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC1_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC1_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC1_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC1_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC1_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -882,6 +891,10 @@
 	mask |= 1 << ((mmTPC1_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC1_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC1_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC1_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1057,6 +1070,16 @@
 	goya_pb_set_block(hdev, mmTPC2_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC2_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC2_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC2_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC2_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC2_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC2_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -1064,6 +1087,10 @@
 	mask |= 1 << ((mmTPC2_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC2_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC2_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC2_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1239,6 +1266,16 @@
 	goya_pb_set_block(hdev, mmTPC3_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC3_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC3_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC3_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC3_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC3_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC3_CFG_CFG_BASE_ADDRESS_HIGH
 			& PROT_BITS_OFFS) >> 7) << 2;
@@ -1246,6 +1283,10 @@
 	mask |= 1 << ((mmTPC3_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC3_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC3_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC3_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1421,6 +1462,16 @@
 	goya_pb_set_block(hdev, mmTPC4_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC4_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC4_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC4_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC4_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC4_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC4_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -1428,6 +1479,10 @@
 	mask |= 1 << ((mmTPC4_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC4_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC4_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC4_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1603,6 +1658,16 @@
 	goya_pb_set_block(hdev, mmTPC5_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC5_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC5_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC5_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC5_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC5_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC5_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -1610,6 +1675,10 @@
 	mask |= 1 << ((mmTPC5_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC5_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC5_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC5_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1785,6 +1854,16 @@
 	goya_pb_set_block(hdev, mmTPC6_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC6_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC6_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC6_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC6_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC6_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
 	word_offset = ((mmTPC6_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -1792,6 +1871,10 @@
 	mask |= 1 << ((mmTPC6_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC6_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC6_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC6_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
@@ -1967,6 +2050,16 @@
 	goya_pb_set_block(hdev, mmTPC7_RD_REGULATOR_BASE);
 	goya_pb_set_block(hdev, mmTPC7_WR_REGULATOR_BASE);
 
+	pb_addr = (mmTPC7_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+	word_offset = ((mmTPC7_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+	mask = 1 << ((mmTPC7_CFG_SEMAPHORE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_VFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_SFLAGS & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_STATUS & 0x7F) >> 2);
+
+	WREG32(pb_addr + word_offset, ~mask);
+
 	pb_addr = (mmTPC7_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) +	PROT_BITS_OFFS;
 	word_offset = ((mmTPC7_CFG_CFG_BASE_ADDRESS_HIGH &
 			PROT_BITS_OFFS) >> 7) << 2;
@@ -1974,6 +2067,10 @@
 	mask |= 1 << ((mmTPC7_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC7_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
 	mask |= 1 << ((mmTPC7_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_TPC_STALL & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_MSS_CONFIG & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+	mask |= 1 << ((mmTPC7_CFG_TPC_INTR_MASK & 0x7F) >> 2);
 
 	WREG32(pb_addr + word_offset, ~mask);
 
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/habanalabs.h
+++ linux-ein-5.4.0/drivers/misc/habanalabs/habanalabs.h
@@ -23,7 +23,7 @@
 
 #define HL_MMAP_CB_MASK			(0x8000000000000000ull >> PAGE_SHIFT)
 
-#define HL_PENDING_RESET_PER_SEC	5
+#define HL_PENDING_RESET_PER_SEC	30
 
 #define HL_DEVICE_TIMEOUT_USEC		1000000 /* 1 s */
 
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/habanalabs_drv.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/habanalabs_drv.c
@@ -443,6 +443,7 @@
 	.id_table = ids,
 	.probe = hl_pci_probe,
 	.remove = hl_pci_remove,
+	.shutdown = hl_pci_remove,
 	.driver.pm = &hl_pm_ops,
 };
 
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/memory.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/memory.c
@@ -67,6 +67,11 @@
 	num_pgs = (args->alloc.mem_size + (page_size - 1)) >> page_shift;
 	total_size = num_pgs << page_shift;
 
+	if (!total_size) {
+		dev_err(hdev->dev, "Cannot allocate 0 bytes\n");
+		return -EINVAL;
+	}
+
 	contiguous = args->flags & HL_MEM_CONTIGUOUS;
 
 	if (contiguous) {
@@ -94,7 +99,7 @@
 	phys_pg_pack->contiguous = contiguous;
 
 	phys_pg_pack->pages = kvmalloc_array(num_pgs, sizeof(u64), GFP_KERNEL);
-	if (!phys_pg_pack->pages) {
+	if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
 		rc = -ENOMEM;
 		goto pages_arr_err;
 	}
@@ -689,7 +694,7 @@
 
 	phys_pg_pack->pages = kvmalloc_array(total_npages, sizeof(u64),
 						GFP_KERNEL);
-	if (!phys_pg_pack->pages) {
+	if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
 		rc = -ENOMEM;
 		goto page_pack_arr_mem_err;
 	}
@@ -965,17 +970,19 @@
  *
  * @ctx                 : current context
  * @vaddr               : device virtual address to unmap
+ * @ctx_free            : true if in context free flow, false otherwise.
  *
  * This function does the following:
  * - Unmap the physical pages related to the given virtual address
  * - return the device virtual block to the virtual block list
  */
-static int unmap_device_va(struct hl_ctx *ctx, u64 vaddr)
+static int unmap_device_va(struct hl_ctx *ctx, u64 vaddr, bool ctx_free)
 {
 	struct hl_device *hdev = ctx->hdev;
 	struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
 	struct hl_vm_hash_node *hnode = NULL;
 	struct hl_userptr *userptr = NULL;
+	struct hl_va_range *va_range;
 	enum vm_type_t *vm_type;
 	u64 next_vaddr, i;
 	u32 page_size;
@@ -1003,6 +1010,7 @@
 
 	if (*vm_type == VM_TYPE_USERPTR) {
 		is_userptr = true;
+		va_range = &ctx->host_va_range;
 		userptr = hnode->ptr;
 		rc = init_phys_pg_pack_from_userptr(ctx, userptr,
 				&phys_pg_pack);
@@ -1014,6 +1022,7 @@
 		}
 	} else if (*vm_type == VM_TYPE_PHYS_PACK) {
 		is_userptr = false;
+		va_range = &ctx->dram_va_range;
 		phys_pg_pack = hnode->ptr;
 	} else {
 		dev_warn(hdev->dev,
@@ -1052,12 +1061,18 @@
 
 	mutex_unlock(&ctx->mmu_lock);
 
-	if (add_va_block(hdev,
-			is_userptr ? &ctx->host_va_range : &ctx->dram_va_range,
-			vaddr,
-			vaddr + phys_pg_pack->total_size - 1))
-		dev_warn(hdev->dev, "add va block failed for vaddr: 0x%llx\n",
-				vaddr);
+	/*
+	 * No point in maintaining the free VA block list if the context is
+	 * closing as the list will be freed anyway
+	 */
+	if (!ctx_free) {
+		rc = add_va_block(hdev, va_range, vaddr,
+					vaddr + phys_pg_pack->total_size - 1);
+		if (rc)
+			dev_warn(hdev->dev,
+					"add va block failed for vaddr: 0x%llx\n",
+					vaddr);
+	}
 
 	atomic_dec(&phys_pg_pack->mapping_cnt);
 	kfree(hnode);
@@ -1189,8 +1204,8 @@
 		break;
 
 	case HL_MEM_OP_UNMAP:
-		rc = unmap_device_va(ctx,
-				args->in.unmap.device_virt_addr);
+		rc = unmap_device_va(ctx, args->in.unmap.device_virt_addr,
+					false);
 		break;
 
 	default:
@@ -1620,7 +1635,7 @@
 		dev_dbg(hdev->dev,
 			"hl_mem_hash_node of vaddr 0x%llx of asid %d is still alive\n",
 			hnode->vaddr, ctx->asid);
-		unmap_device_va(ctx, hnode->vaddr);
+		unmap_device_va(ctx, hnode->vaddr, true);
 	}
 
 	spin_lock(&vm->idr_lock);
--- linux-ein-5.4.0.orig/drivers/misc/habanalabs/mmu.c
+++ linux-ein-5.4.0/drivers/misc/habanalabs/mmu.c
@@ -422,7 +422,7 @@
 	hdev->mmu_shadow_hop0 = kvmalloc_array(prop->max_asid,
 					prop->mmu_hop_table_size,
 					GFP_KERNEL | __GFP_ZERO);
-	if (!hdev->mmu_shadow_hop0) {
+	if (ZERO_OR_NULL_PTR(hdev->mmu_shadow_hop0)) {
 		rc = -ENOMEM;
 		goto err_pool_add;
 	}
--- linux-ein-5.4.0.orig/drivers/misc/ibmasm/module.c
+++ linux-ein-5.4.0/drivers/misc/ibmasm/module.c
@@ -111,7 +111,7 @@
 	result = ibmasm_init_remote_input_dev(sp);
 	if (result) {
 		dev_err(sp->dev, "Failed to initialize remote queue\n");
-		goto error_send_message;
+		goto error_init_remote;
 	}
 
 	result = ibmasm_send_driver_vpd(sp);
@@ -131,8 +131,9 @@
 	return 0;
 
 error_send_message:
-	disable_sp_interrupts(sp->base_address);
 	ibmasm_free_remote_input_dev(sp);
+error_init_remote:
+	disable_sp_interrupts(sp->base_address);
 	free_irq(sp->irq, (void *)sp);
 error_request_irq:
 	iounmap(sp->base_address);
--- linux-ein-5.4.0.orig/drivers/misc/ics932s401.c
+++ linux-ein-5.4.0/drivers/misc/ics932s401.c
@@ -134,7 +134,7 @@
 	for (i = 0; i < NUM_MIRRORED_REGS; i++) {
 		temp = i2c_smbus_read_word_data(client, regs_to_copy[i]);
 		if (temp < 0)
-			data->regs[regs_to_copy[i]] = 0;
+			temp = 0;
 		data->regs[regs_to_copy[i]] = temp >> 8;
 	}
 
--- linux-ein-5.4.0.orig/drivers/misc/kgdbts.c
+++ linux-ein-5.4.0/drivers/misc/kgdbts.c
@@ -95,19 +95,20 @@
 
 #include <asm/sections.h>
 
-#define v1printk(a...) do { \
-	if (verbose) \
-		printk(KERN_INFO a); \
-	} while (0)
-#define v2printk(a...) do { \
-	if (verbose > 1) \
-		printk(KERN_INFO a); \
-		touch_nmi_watchdog();	\
-	} while (0)
-#define eprintk(a...) do { \
-		printk(KERN_ERR a); \
-		WARN_ON(1); \
-	} while (0)
+#define v1printk(a...) do {		\
+	if (verbose)			\
+		printk(KERN_INFO a);	\
+} while (0)
+#define v2printk(a...) do {		\
+	if (verbose > 1) {		\
+		printk(KERN_INFO a);	\
+	}				\
+	touch_nmi_watchdog();		\
+} while (0)
+#define eprintk(a...) do {		\
+	printk(KERN_ERR a);		\
+	WARN_ON(1);			\
+} while (0)
 #define MAX_CONFIG_LEN		40
 
 static struct kgdb_io kgdbts_io_ops;
@@ -1059,10 +1060,10 @@
 {
 	if (strlen(opt) >= MAX_CONFIG_LEN) {
 		printk(KERN_ERR "kgdbts: config string too long\n");
-		return -ENOSPC;
+		return 1;
 	}
 	strcpy(config, opt);
-	return 0;
+	return 1;
 }
 
 __setup("kgdbts=", kgdbts_option_setup);
--- linux-ein-5.4.0.orig/drivers/misc/lattice-ecp3-config.c
+++ linux-ein-5.4.0/drivers/misc/lattice-ecp3-config.c
@@ -77,12 +77,12 @@
 
 	if (fw == NULL) {
 		dev_err(&spi->dev, "Cannot load firmware, aborting\n");
-		return;
+		goto out;
 	}
 
 	if (fw->size == 0) {
 		dev_err(&spi->dev, "Error: Firmware size is 0!\n");
-		return;
+		goto out;
 	}
 
 	/* Fill dummy data (24 stuffing bits for commands) */
@@ -104,7 +104,7 @@
 		dev_err(&spi->dev,
 			"Error: No supported FPGA detected (JEDEC_ID=%08x)!\n",
 			jedec_id);
-		return;
+		goto out;
 	}
 
 	dev_info(&spi->dev, "FPGA %s detected\n", ecp3_dev[i].name);
@@ -117,7 +117,7 @@
 	buffer = kzalloc(fw->size + 8, GFP_KERNEL);
 	if (!buffer) {
 		dev_err(&spi->dev, "Error: Can't allocate memory!\n");
-		return;
+		goto out;
 	}
 
 	/*
@@ -156,7 +156,7 @@
 			"Error: Timeout waiting for FPGA to clear (status=%08x)!\n",
 			status);
 		kfree(buffer);
-		return;
+		goto out;
 	}
 
 	dev_info(&spi->dev, "Configuring the FPGA...\n");
@@ -182,7 +182,7 @@
 	release_firmware(fw);
 
 	kfree(buffer);
-
+out:
 	complete(&data->fw_loaded);
 }
 
--- linux-ein-5.4.0.orig/drivers/misc/lis3lv02d/lis3lv02d.c
+++ linux-ein-5.4.0/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -208,7 +208,7 @@
 static int lis3_3dlh_rates[4] = {50, 100, 400, 1000};
 
 /* ODR is Output Data Rate */
-static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
+static int lis3lv02d_get_odr_index(struct lis3lv02d *lis3)
 {
 	u8 ctrl;
 	int shift;
@@ -216,15 +216,23 @@
 	lis3->read(lis3, CTRL_REG1, &ctrl);
 	ctrl &= lis3->odr_mask;
 	shift = ffs(lis3->odr_mask) - 1;
-	return lis3->odrs[(ctrl >> shift)];
+	return (ctrl >> shift);
 }
 
 static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3)
 {
-	int div = lis3lv02d_get_odr(lis3);
+	int odr_idx = lis3lv02d_get_odr_index(lis3);
+	int div = lis3->odrs[odr_idx];
 
-	if (WARN_ONCE(div == 0, "device returned spurious data"))
+	if (div == 0) {
+		if (odr_idx == 0) {
+			/* Power-down mode, not sampling no need to sleep */
+			return 0;
+		}
+
+		dev_err(&lis3->pdev->dev, "Error unknown odrs-index: %d\n", odr_idx);
 		return -ENXIO;
+	}
 
 	/* LIS3 power on delay is quite long */
 	msleep(lis3->pwron_delay / div);
@@ -807,9 +815,12 @@
 			struct device_attribute *attr, char *buf)
 {
 	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
+	int odr_idx;
 
 	lis3lv02d_sysfs_poweron(lis3);
-	return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
+
+	odr_idx = lis3lv02d_get_odr_index(lis3);
+	return sprintf(buf, "%d\n", lis3->odrs[odr_idx]);
 }
 
 static ssize_t lis3lv02d_rate_set(struct device *dev,
--- linux-ein-5.4.0.orig/drivers/misc/lis3lv02d/lis3lv02d.h
+++ linux-ein-5.4.0/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -271,6 +271,7 @@
 	int			regs_size;
 	u8                      *reg_cache;
 	bool			regs_stored;
+	bool			init_required;
 	u8                      odr_mask;  /* ODR bit mask */
 	u8			whoami;    /* indicates measurement precision */
 	s16 (*read_data) (struct lis3lv02d *lis3, int reg);
--- linux-ein-5.4.0.orig/drivers/misc/lkdtm/Makefile
+++ linux-ein-5.4.0/drivers/misc/lkdtm/Makefile
@@ -16,7 +16,7 @@
 
 OBJCOPYFLAGS :=
 OBJCOPYFLAGS_rodata_objcopy.o	:= \
-			--rename-section .text=.rodata,alloc,readonly,load
+			--rename-section .noinstr.text=.rodata,alloc,readonly,load,contents
 targets += rodata.o rodata_objcopy.o
 $(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE
 	$(call if_changed,objcopy)
--- linux-ein-5.4.0.orig/drivers/misc/lkdtm/bugs.c
+++ linux-ein-5.4.0/drivers/misc/lkdtm/bugs.c
@@ -274,7 +274,7 @@
 
 void lkdtm_UNSET_SMEP(void)
 {
-#ifdef CONFIG_X86_64
+#if IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_UML)
 #define MOV_CR4_DEPTH	64
 	void (*direct_write_cr4)(unsigned long val);
 	unsigned char *insn;
--- linux-ein-5.4.0.orig/drivers/misc/lkdtm/refcount.c
+++ linux-ein-5.4.0/drivers/misc/lkdtm/refcount.c
@@ -6,14 +6,6 @@
 #include "lkdtm.h"
 #include <linux/refcount.h>
 
-#ifdef CONFIG_REFCOUNT_FULL
-#define REFCOUNT_MAX		(UINT_MAX - 1)
-#define REFCOUNT_SATURATED	UINT_MAX
-#else
-#define REFCOUNT_MAX		INT_MAX
-#define REFCOUNT_SATURATED	(INT_MIN / 2)
-#endif
-
 static void overflow_check(refcount_t *ref)
 {
 	switch (refcount_read(ref)) {
--- linux-ein-5.4.0.orig/drivers/misc/lkdtm/rodata.c
+++ linux-ein-5.4.0/drivers/misc/lkdtm/rodata.c
@@ -5,7 +5,7 @@
  */
 #include "lkdtm.h"
 
-void notrace lkdtm_rodata_do_nothing(void)
+void noinstr lkdtm_rodata_do_nothing(void)
 {
 	/* Does nothing. We just want an architecture agnostic "return". */
 }
--- linux-ein-5.4.0.orig/drivers/misc/lkdtm/usercopy.c
+++ linux-ein-5.4.0/drivers/misc/lkdtm/usercopy.c
@@ -30,12 +30,12 @@
  */
 static noinline unsigned char *trick_compiler(unsigned char *stack)
 {
-	return stack + 0;
+	return stack + unconst;
 }
 
 static noinline unsigned char *do_usercopy_stack_callee(int value)
 {
-	unsigned char buf[32];
+	unsigned char buf[128];
 	int i;
 
 	/* Exercise stack to avoid everything living in registers. */
@@ -43,7 +43,12 @@
 		buf[i] = value & 0xff;
 	}
 
-	return trick_compiler(buf);
+	/*
+	 * Put the target buffer in the middle of stack allocation
+	 * so that we don't step on future stack users regardless
+	 * of stack growth direction.
+	 */
+	return trick_compiler(&buf[(128/2)-32]);
 }
 
 static noinline void do_usercopy_stack(bool to_user, bool bad_frame)
@@ -66,6 +71,12 @@
 		bad_stack -= sizeof(unsigned long);
 	}
 
+#ifdef ARCH_HAS_CURRENT_STACK_POINTER
+	pr_info("stack     : %px\n", (void *)current_stack_pointer);
+#endif
+	pr_info("good_stack: %px-%px\n", good_stack, good_stack + sizeof(good_stack));
+	pr_info("bad_stack : %px-%px\n", bad_stack, bad_stack + sizeof(good_stack));
+
 	user_addr = vm_mmap(NULL, 0, PAGE_SIZE,
 			    PROT_READ | PROT_WRITE | PROT_EXEC,
 			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
--- linux-ein-5.4.0.orig/drivers/misc/mei/bus-fixup.c
+++ linux-ein-5.4.0/drivers/misc/mei/bus-fixup.c
@@ -178,7 +178,7 @@
 	ret = __mei_cl_send(cldev->cl, buf, sizeof(struct mkhi_msg_hdr),
 			    MEI_CL_IO_TX_BLOCKING);
 	if (ret < 0) {
-		dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n");
+		dev_err(&cldev->dev, "Could not send ReqFWVersion cmd ret = %d\n", ret);
 		return ret;
 	}
 
@@ -190,7 +190,7 @@
 		 * Should be at least one version block,
 		 * error out if nothing found
 		 */
-		dev_err(&cldev->dev, "Could not read FW version\n");
+		dev_err(&cldev->dev, "Could not read FW version ret = %d\n", bytes_recv);
 		return -EIO;
 	}
 
@@ -339,7 +339,7 @@
 	ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd),
 			    MEI_CL_IO_TX_BLOCKING);
 	if (ret < 0) {
-		dev_err(bus->dev, "Could not send IF version cmd\n");
+		dev_err(bus->dev, "Could not send IF version cmd ret = %d\n", ret);
 		return ret;
 	}
 
@@ -354,7 +354,7 @@
 	ret = 0;
 	bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0, 0);
 	if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) {
-		dev_err(bus->dev, "Could not read IF version\n");
+		dev_err(bus->dev, "Could not read IF version ret = %d\n", bytes_recv);
 		ret = -EIO;
 		goto err;
 	}
--- linux-ein-5.4.0.orig/drivers/misc/mei/bus.c
+++ linux-ein-5.4.0/drivers/misc/mei/bus.c
@@ -745,9 +745,8 @@
 
 	mei_cl_bus_module_put(cldev);
 	module_put(THIS_MODULE);
-	dev->driver = NULL;
-	return ret;
 
+	return ret;
 }
 
 static ssize_t name_show(struct device *dev, struct device_attribute *a,
@@ -873,15 +872,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-ein-5.4.0.orig/drivers/misc/mei/client.c
+++ linux-ein-5.4.0/drivers/misc/mei/client.c
@@ -266,6 +266,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);
 }
 
@@ -287,6 +288,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);
 }
 
--- linux-ein-5.4.0.orig/drivers/misc/mei/client.h
+++ linux-ein-5.4.0/drivers/misc/mei/client.h
@@ -128,11 +128,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-ein-5.4.0.orig/drivers/misc/mei/hbm.c
+++ linux-ein-5.4.0/drivers/misc/mei/hbm.c
@@ -1300,7 +1300,7 @@
 			return -EPROTO;
 		}
 
-		dev->dev_state = MEI_DEV_POWER_DOWN;
+		mei_set_devstate(dev, MEI_DEV_POWER_DOWN);
 		dev_info(dev->dev, "hbm: stop response: resetting.\n");
 		/* force the reset */
 		return -EPROTO;
--- linux-ein-5.4.0.orig/drivers/misc/mei/hdcp/mei_hdcp.c
+++ linux-ein-5.4.0/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -758,11 +758,38 @@
 	.unbind = mei_component_master_unbind,
 };
 
+/**
+ * mei_hdcp_component_match - compare function for matching mei hdcp.
+ *
+ *    The function checks if the driver is i915, the subcomponent is HDCP
+ *    and the grand parent of hdcp and the parent of i915 are the same
+ *    PCH device.
+ *
+ * @dev: master device
+ * @subcomponent: subcomponent to match (I915_COMPONENT_HDCP)
+ * @data: compare data (mei hdcp device)
+ *
+ * Return:
+ * * 1 - if components match
+ * * 0 - otherwise
+ */
 static int mei_hdcp_component_match(struct device *dev, int subcomponent,
 				    void *data)
 {
-	return !strcmp(dev->driver->name, "i915") &&
-	       subcomponent == I915_COMPONENT_HDCP;
+	struct device *base = data;
+
+	if (strcmp(dev->driver->name, "i915") ||
+	    subcomponent != I915_COMPONENT_HDCP)
+		return 0;
+
+	base = base->parent;
+	if (!base)
+		return 0;
+
+	base = base->parent;
+	dev = dev->parent;
+
+	return (base && dev && dev == base);
 }
 
 static int mei_hdcp_probe(struct mei_cl_device *cldev,
@@ -786,7 +813,7 @@
 
 	master_match = NULL;
 	component_match_add_typed(&cldev->dev, &master_match,
-				  mei_hdcp_component_match, comp_master);
+				  mei_hdcp_component_match, &cldev->dev);
 	if (IS_ERR_OR_NULL(master_match)) {
 		ret = -ENOMEM;
 		goto err_exit;
--- linux-ein-5.4.0.orig/drivers/misc/mei/hw-me-regs.h
+++ linux-ein-5.4.0/drivers/misc/mei/hw-me-regs.h
@@ -82,7 +82,15 @@
 #define MEI_DEV_ID_CMP_LP     0x02e0  /* Comet Point LP */
 #define MEI_DEV_ID_CMP_LP_3   0x02e4  /* Comet Point LP 3 (iTouch) */
 
+#define MEI_DEV_ID_CMP_V      0xA3BA  /* Comet Point Lake V */
+
+#define MEI_DEV_ID_CMP_H      0x06e0  /* Comet Lake H */
+#define MEI_DEV_ID_CMP_H_3    0x06e4  /* Comet Lake H 3 (iTouch) */
+
+#define MEI_DEV_ID_CDF        0x18D3  /* Cedar Fork */
+
 #define MEI_DEV_ID_ICP_LP     0x34E0  /* Ice Lake Point LP */
+#define MEI_DEV_ID_ICP_N      0x38E0  /* Ice Lake Point N */
 
 #define MEI_DEV_ID_TGP_LP     0xA0E0  /* Tiger Lake Point LP */
 
--- linux-ein-5.4.0.orig/drivers/misc/mei/interrupt.c
+++ linux-ein-5.4.0/drivers/misc/mei/interrupt.c
@@ -222,6 +222,9 @@
 		return ret;
 	}
 
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_request_autosuspend(dev->dev);
+
 	list_move_tail(&cb->list, &cl->rd_pending);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/misc/mei/pci-me.c
+++ linux-ein-5.4.0/drivers/misc/mei/pci-me.c
@@ -32,6 +32,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_ICH_CFG)},
@@ -98,14 +101,20 @@
 
 	{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
 	{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_CFG)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H, MEI_ME_PCH12_CFG)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)},
 
 	{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
+	{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)},
 
 	{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)},
 
 	{MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH12_CFG)},
 	{MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
 
+	{MEI_PCI_DEVICE(MEI_DEV_ID_CDF, MEI_ME_PCH8_CFG)},
+
 	/* required last entry */
 	{0, }
 };
@@ -199,7 +208,8 @@
 	hw = to_me_hw(dev);
 	hw->mem_addr = pcim_iomap_table(pdev)[0];
 
-	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;
--- linux-ein-5.4.0.orig/drivers/misc/mic/scif/scif_rma.c
+++ linux-ein-5.4.0/drivers/misc/mic/scif/scif_rma.c
@@ -1381,6 +1381,8 @@
 				(prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
 				pinned_pages->pages);
 		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, nr_pages);
@@ -1400,7 +1402,6 @@
 
 	if (pinned_pages->nr_pages < nr_pages) {
 		err = -EFAULT;
-		pinned_pages->nr_pages = nr_pages;
 		goto dec_pinned;
 	}
 
@@ -1413,7 +1414,6 @@
 		__scif_dec_pinned_vm_lock(mm, nr_pages);
 	/* 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,
--- linux-ein-5.4.0.orig/drivers/misc/mic/vop/vop_main.c
+++ linux-ein-5.4.0/drivers/misc/mic/vop/vop_main.c
@@ -320,7 +320,7 @@
 	/* First assign the vring's allocated in host memory */
 	vqconfig = _vop_vq_config(vdev->desc) + index;
 	memcpy_fromio(&config, vqconfig, sizeof(config));
-	_vr_size = vring_size(le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN);
+	_vr_size = round_up(vring_size(le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN), 4);
 	vr_size = PAGE_ALIGN(_vr_size + sizeof(struct _mic_vring_info));
 	va = vpdev->hw_ops->remap(vpdev, le64_to_cpu(config.address), vr_size);
 	if (!va)
--- linux-ein-5.4.0.orig/drivers/misc/mic/vop/vop_vringh.c
+++ linux-ein-5.4.0/drivers/misc/mic/vop/vop_vringh.c
@@ -296,7 +296,7 @@
 
 		num = le16_to_cpu(vqconfig[i].num);
 		mutex_init(&vvr->vr_mutex);
-		vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) +
+		vr_size = PAGE_ALIGN(round_up(vring_size(num, MIC_VIRTIO_RING_ALIGN), 4) +
 			sizeof(struct _mic_vring_info));
 		vr->va = (void *)
 			__get_free_pages(GFP_KERNEL | __GFP_ZERO,
@@ -308,7 +308,7 @@
 			goto err;
 		}
 		vr->len = vr_size;
-		vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN);
+		vr->info = vr->va + round_up(vring_size(num, MIC_VIRTIO_RING_ALIGN), 4);
 		vr->info->magic = cpu_to_le32(MIC_MAGIC + vdev->virtio_id + i);
 		vr_addr = dma_map_single(&vpdev->dev, vr->va, vr_size,
 					 DMA_BIDIRECTIONAL);
@@ -602,6 +602,7 @@
 	size_t partlen;
 	bool dma = VOP_USE_DMA && vi->dma_ch;
 	int err = 0;
+	size_t offset = 0;
 
 	if (dma) {
 		dma_alignment = 1 << vi->dma_ch->device->copy_align;
@@ -655,13 +656,20 @@
 	 * We are copying to IO below and should ideally use something
 	 * like copy_from_user_toio(..) if it existed.
 	 */
-	if (copy_from_user((void __force *)dbuf, ubuf, len)) {
-		err = -EFAULT;
-		dev_err(vop_dev(vdev), "%s %d err %d\n",
-			__func__, __LINE__, err);
-		goto err;
+	while (len) {
+		partlen = min_t(size_t, len, VOP_INT_DMA_BUF_SIZE);
+
+		if (copy_from_user(vvr->buf, ubuf + offset, partlen)) {
+			err = -EFAULT;
+			dev_err(vop_dev(vdev), "%s %d err %d\n",
+				__func__, __LINE__, err);
+			goto err;
+		}
+		memcpy_toio(dbuf + offset, vvr->buf, partlen);
+		offset += partlen;
+		vdev->out_bytes += partlen;
+		len -= partlen;
 	}
-	vdev->out_bytes += len;
 	err = 0;
 err:
 	vpdev->hw_ops->unmap(vpdev, dbuf);
--- linux-ein-5.4.0.orig/drivers/misc/ocxl/Kconfig
+++ linux-ein-5.4.0/drivers/misc/ocxl/Kconfig
@@ -11,6 +11,7 @@
 	tristate "OpenCAPI coherent accelerator support"
 	depends on PPC_POWERNV && PCI && EEH
 	select OCXL_BASE
+	select HOTPLUG_PCI_POWERNV
 	default m
 	help
 	  Select this option to enable the ocxl driver for Open
--- linux-ein-5.4.0.orig/drivers/misc/ocxl/context.c
+++ linux-ein-5.4.0/drivers/misc/ocxl/context.c
@@ -10,18 +10,17 @@
 	int pasid;
 	struct ocxl_context *ctx;
 
-	*context = kzalloc(sizeof(struct ocxl_context), GFP_KERNEL);
-	if (!*context)
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
 		return -ENOMEM;
 
-	ctx = *context;
-
 	ctx->afu = afu;
 	mutex_lock(&afu->contexts_lock);
 	pasid = idr_alloc(&afu->contexts_idr, ctx, afu->pasid_base,
 			afu->pasid_base + afu->pasid_max, GFP_KERNEL);
 	if (pasid < 0) {
 		mutex_unlock(&afu->contexts_lock);
+		kfree(ctx);
 		return pasid;
 	}
 	afu->pasid_count++;
@@ -43,6 +42,7 @@
 	 * duration of the life of the context
 	 */
 	ocxl_afu_get(afu);
+	*context = ctx;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ocxl_context_alloc);
--- linux-ein-5.4.0.orig/drivers/misc/ocxl/file.c
+++ linux-ein-5.4.0/drivers/misc/ocxl/file.c
@@ -18,18 +18,15 @@
 static struct mutex minors_idr_lock;
 static struct idr minors_idr;
 
-static struct ocxl_file_info *find_file_info(dev_t devno)
+static struct ocxl_file_info *find_and_get_file_info(dev_t devno)
 {
 	struct ocxl_file_info *info;
 
-	/*
-	 * We don't declare an RCU critical section here, as our AFU
-	 * is protected by a reference counter on the device. By the time the
-	 * info reference is removed from the idr, the ref count of
-	 * the device is already at 0, so no user API will access that AFU and
-	 * this function can't return it.
-	 */
+	mutex_lock(&minors_idr_lock);
 	info = idr_find(&minors_idr, MINOR(devno));
+	if (info)
+		get_device(&info->dev);
+	mutex_unlock(&minors_idr_lock);
 	return info;
 }
 
@@ -58,14 +55,16 @@
 
 	pr_debug("%s for device %x\n", __func__, inode->i_rdev);
 
-	info = find_file_info(inode->i_rdev);
+	info = find_and_get_file_info(inode->i_rdev);
 	if (!info)
 		return -ENODEV;
 
 	rc = ocxl_context_alloc(&ctx, info->afu, inode->i_mapping);
-	if (rc)
+	if (rc) {
+		put_device(&info->dev);
 		return rc;
-
+	}
+	put_device(&info->dev);
 	file->private_data = ctx;
 	return 0;
 }
@@ -260,6 +259,8 @@
 		if (IS_ERR(ev_ctx))
 			return PTR_ERR(ev_ctx);
 		rc = ocxl_irq_set_handler(ctx, irq_id, irq_handler, irq_free, ev_ctx);
+		if (rc)
+			eventfd_ctx_put(ev_ctx);
 		break;
 
 	case OCXL_IOCTL_GET_METADATA:
@@ -487,7 +488,6 @@
 {
 	struct ocxl_file_info *info = container_of(dev, struct ocxl_file_info, dev);
 
-	free_minor(info);
 	ocxl_afu_put(info->afu);
 	kfree(info);
 }
@@ -543,8 +543,11 @@
 		goto err_put;
 
 	rc = device_register(&info->dev);
-	if (rc)
-		goto err_put;
+	if (rc) {
+		free_minor(info);
+		put_device(&info->dev);
+		return rc;
+	}
 
 	rc = ocxl_sysfs_register_afu(info);
 	if (rc)
@@ -560,7 +563,9 @@
 
 err_unregister:
 	ocxl_sysfs_unregister_afu(info); // safe to call even if register failed
+	free_minor(info);
 	device_unregister(&info->dev);
+	return rc;
 err_put:
 	ocxl_afu_put(afu);
 	free_minor(info);
@@ -577,6 +582,7 @@
 
 	ocxl_file_make_invisible(info);
 	ocxl_sysfs_unregister_afu(info);
+	free_minor(info);
 	device_unregister(&info->dev);
 }
 
--- linux-ein-5.4.0.orig/drivers/misc/pci_endpoint_test.c
+++ linux-ein-5.4.0/drivers/misc/pci_endpoint_test.c
@@ -98,6 +98,7 @@
 	struct completion irq_raised;
 	int		last_irq;
 	int		num_irqs;
+	int		irq_type;
 	/* mutex to protect the ioctls */
 	struct mutex	mutex;
 	struct miscdevice miscdev;
@@ -157,6 +158,7 @@
 	struct pci_dev *pdev = test->pdev;
 
 	pci_free_irq_vectors(pdev);
+	test->irq_type = IRQ_TYPE_UNDEFINED;
 }
 
 static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
@@ -191,6 +193,8 @@
 		irq = 0;
 		res = false;
 	}
+
+	test->irq_type = type;
 	test->num_irqs = irq;
 
 	return res;
@@ -330,6 +334,7 @@
 	dma_addr_t orig_dst_phys_addr;
 	size_t offset;
 	size_t alignment = test->alignment;
+	int irq_type = test->irq_type;
 	u32 src_crc32;
 	u32 dst_crc32;
 
@@ -426,6 +431,7 @@
 	dma_addr_t orig_phys_addr;
 	size_t offset;
 	size_t alignment = test->alignment;
+	int irq_type = test->irq_type;
 	u32 crc32;
 
 	if (size > SIZE_MAX - alignment)
@@ -494,6 +500,7 @@
 	dma_addr_t orig_phys_addr;
 	size_t offset;
 	size_t alignment = test->alignment;
+	int irq_type = test->irq_type;
 	u32 crc32;
 
 	if (size > SIZE_MAX - alignment)
@@ -555,7 +562,7 @@
 		return false;
 	}
 
-	if (irq_type == req_irq_type)
+	if (test->irq_type == req_irq_type)
 		return true;
 
 	pci_endpoint_test_release_irq(test);
@@ -567,12 +574,10 @@
 	if (!pci_endpoint_test_request_irq(test))
 		goto err;
 
-	irq_type = req_irq_type;
 	return true;
 
 err:
 	pci_endpoint_test_free_irq_vectors(test);
-	irq_type = IRQ_TYPE_UNDEFINED;
 	return false;
 }
 
@@ -585,6 +590,10 @@
 	struct pci_dev *pdev = test->pdev;
 
 	mutex_lock(&test->mutex);
+
+	reinit_completion(&test->irq_raised);
+	test->last_irq = -ENODATA;
+
 	switch (cmd) {
 	case PCITEST_BAR:
 		bar = arg;
@@ -633,7 +642,7 @@
 {
 	int err;
 	int id;
-	char name[20];
+	char name[24];
 	enum pci_barno bar;
 	void __iomem *base;
 	struct device *dev = &pdev->dev;
@@ -652,6 +661,7 @@
 	test->test_reg_bar = 0;
 	test->alignment = 0;
 	test->pdev = pdev;
+	test->irq_type = IRQ_TYPE_UNDEFINED;
 
 	if (no_msi)
 		irq_type = IRQ_TYPE_LEGACY;
@@ -768,6 +778,9 @@
 	if (id < 0)
 		return;
 
+	pci_endpoint_test_release_irq(test);
+	pci_endpoint_test_free_irq_vectors(test);
+
 	misc_deregister(&test->miscdev);
 	kfree(misc_device->name);
 	ida_simple_remove(&pci_endpoint_test_ida, id);
@@ -776,9 +789,6 @@
 			pci_iounmap(pdev, test->bar[bar]);
 	}
 
-	pci_endpoint_test_release_irq(test);
-	pci_endpoint_test_free_irq_vectors(test);
-
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 }
--- linux-ein-5.4.0.orig/drivers/misc/pvpanic.c
+++ linux-ein-5.4.0/drivers/misc/pvpanic.c
@@ -166,6 +166,7 @@
 	{ .compatible = "qemu,pvpanic-mmio", },
 	{}
 };
+MODULE_DEVICE_TABLE(of, pvpanic_mmio_match);
 
 static struct platform_driver pvpanic_mmio_driver = {
 	.driver = {
--- linux-ein-5.4.0.orig/drivers/misc/sgi-gru/grufault.c
+++ linux-ein-5.4.0/drivers/misc/sgi-gru/grufault.c
@@ -648,6 +648,7 @@
 	if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB)
 		return -EINVAL;
 
+again:
 	gts = gru_find_lock_gts(cb);
 	if (!gts)
 		return -EINVAL;
@@ -656,7 +657,11 @@
 	if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
 		goto exit;
 
-	gru_check_context_placement(gts);
+	if (gru_check_context_placement(gts)) {
+		gru_unlock_gts(gts);
+		gru_unload_context(gts, 1);
+		goto again;
+	}
 
 	/*
 	 * CCH may contain stale data if ts_force_cch_reload is set.
@@ -874,7 +879,11 @@
 		} else {
 			gts->ts_user_blade_id = req.val1;
 			gts->ts_user_chiplet_id = req.val0;
-			gru_check_context_placement(gts);
+			if (gru_check_context_placement(gts)) {
+				gru_unlock_gts(gts);
+				gru_unload_context(gts, 1);
+				return ret;
+			}
 		}
 		break;
 	case sco_gseg_owner:
--- linux-ein-5.4.0.orig/drivers/misc/sgi-gru/grumain.c
+++ linux-ein-5.4.0/drivers/misc/sgi-gru/grumain.c
@@ -716,9 +716,10 @@
  * chiplet. Misassignment can occur if the process migrates to a different
  * blade or if the user changes the selected blade/chiplet.
  */
-void gru_check_context_placement(struct gru_thread_state *gts)
+int gru_check_context_placement(struct gru_thread_state *gts)
 {
 	struct gru_state *gru;
+	int ret = 0;
 
 	/*
 	 * If the current task is the context owner, verify that the
@@ -726,15 +727,23 @@
 	 * references. Pthread apps use non-owner references to the CBRs.
 	 */
 	gru = gts->ts_gru;
+	/*
+	 * If gru or gts->ts_tgid_owner isn't initialized properly, return
+	 * success to indicate that the caller does not need to unload the
+	 * gru context.The caller is responsible for their inspection and
+	 * reinitialization if needed.
+	 */
 	if (!gru || gts->ts_tgid_owner != current->tgid)
-		return;
+		return ret;
 
 	if (!gru_check_chiplet_assignment(gru, gts)) {
 		STAT(check_context_unload);
-		gru_unload_context(gts, 1);
+		ret = -EINVAL;
 	} else if (gru_retarget_intr(gts)) {
 		STAT(check_context_retarget_intr);
 	}
+
+	return ret;
 }
 
 
@@ -934,7 +943,12 @@
 	mutex_lock(&gts->ts_ctxlock);
 	preempt_disable();
 
-	gru_check_context_placement(gts);
+	if (gru_check_context_placement(gts)) {
+		preempt_enable();
+		mutex_unlock(&gts->ts_ctxlock);
+		gru_unload_context(gts, 1);
+		return VM_FAULT_NOPAGE;
+	}
 
 	if (!gts->ts_gru) {
 		STAT(load_user_context);
--- linux-ein-5.4.0.orig/drivers/misc/sgi-gru/grutables.h
+++ linux-ein-5.4.0/drivers/misc/sgi-gru/grutables.h
@@ -637,7 +637,7 @@
 extern int gru_user_unload_context(unsigned long arg);
 extern int gru_get_exception_detail(unsigned long arg);
 extern int gru_set_context_option(unsigned long address);
-extern void gru_check_context_placement(struct gru_thread_state *gts);
+extern int gru_check_context_placement(struct gru_thread_state *gts);
 extern int gru_cpu_fault_map_id(void);
 extern struct vm_area_struct *gru_find_vma(unsigned long vaddr);
 extern void gru_flush_all_tlb(struct gru_state *gru);
--- linux-ein-5.4.0.orig/drivers/misc/ti-st/st_core.c
+++ linux-ein-5.4.0/drivers/misc/ti-st/st_core.c
@@ -15,6 +15,7 @@
 #include <linux/skbuff.h>
 
 #include <linux/ti_wilink_st.h>
+#include <linux/netdevice.h>
 
 extern void st_kim_recv(void *, const unsigned char *, long);
 void st_int_recv(void *, const unsigned char *, long);
@@ -423,7 +424,7 @@
 	case ST_LL_AWAKE_TO_ASLEEP:
 		pr_err("ST LL is illegal state(%ld),"
 			   "purging received skb.", st_ll_getstate(st_gdata));
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		break;
 	case ST_LL_ASLEEP:
 		skb_queue_tail(&st_gdata->tx_waitq, skb);
@@ -432,7 +433,7 @@
 	default:
 		pr_err("ST LL is illegal state(%ld),"
 			   "purging received skb.", st_ll_getstate(st_gdata));
-		kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		break;
 	}
 
@@ -486,7 +487,7 @@
 				spin_unlock_irqrestore(&st_data->lock, flags);
 				break;
 			}
-			kfree_skb(skb);
+			dev_kfree_skb_irq(skb);
 			spin_unlock_irqrestore(&st_data->lock, flags);
 		}
 		/* if wake-up is set in another context- restart sending */
--- linux-ein-5.4.0.orig/drivers/misc/tifm_7xx1.c
+++ linux-ein-5.4.0/drivers/misc/tifm_7xx1.c
@@ -190,7 +190,7 @@
 				spin_unlock_irqrestore(&fm->lock, flags);
 			}
 			if (sock)
-				tifm_free_device(&sock->dev);
+				put_device(&sock->dev);
 		}
 		spin_lock_irqsave(&fm->lock, flags);
 	}
--- linux-ein-5.4.0.orig/drivers/misc/vesta_expansion.c
+++ linux-ein-5.4.0/drivers/misc/vesta_expansion.c
@@ -0,0 +1,169 @@
+/*
+ *  Copyright (C) Nagaraj Krishnamurthy
+ *  Copyright (C) Rigado, Inc 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This is a generic platform driver for Vesta Gateway expansion cards.
+ * This driver currently does absolutely nothing, but is needed since
+ * an expansion card platform device must be created when an expansion
+ * card is detected, so that the card's GPIO pin configuration as specified
+ * in the card's device tree overlay file will be activated after the
+ * overlay is inserted.  If a future expansion card needs specific
+ * kernel-level functionality, such as interrupt processing, this driver can be
+ * cloned and then customized for the expansion card in question.
+ * 
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+
+
+
+/***********************************************************************
+ * Platform device driver code here......
+ ***********************************************************************/
+
+/* sample per-device data structure driver can populate and register
+	during its probe sequence, if such data is needed 
+	by other driver functions, such as an interrupt handler.  
+	Can be modified to hold whatever data is needed.
+
+struct my_driver_data {
+    int data1;
+    int data2;
+};
+*/
+
+/* Suspend the device. */
+static int vesta_exp_card_pm_suspend(struct device *dev)
+{
+    //struct vesta_exp_card_data* driver_data = dev_get_drvdata(dev);
+
+    printk(KERN_ALERT " %s\n", __FUNCTION__);
+
+    /* Suspend the device here*/
+
+    return 0;
+}
+
+/* Resume the device. */
+static int vesta_exp_card_pm_resume(struct device *dev)
+{
+    //struct vesta_exp_card_data* driver_data = dev_get_drvdata(dev);
+
+    printk(KERN_ALERT " %s\n", __FUNCTION__);
+
+    /* Resume the device here*/
+
+    return 0;
+}
+
+static int vesta_exp_card_probe(struct platform_device *pdev)
+{
+    //struct vesta_exp_card_data* driver_data;
+
+    printk(KERN_ALERT " %s\n", __FUNCTION__);
+
+
+    /* If needed create, and populate a device_data structure, and
+	associated it with this device's pdata structure.
+	A device_data structure would most likely be needed if a Vesta
+	expansion card can generate interrupts that must be handled by 
+	the driver, and the interrupt handler (which would be registered
+	by this probe function) needs access to device-specific data. 
+
+    driver_data = kzalloc(sizeof(struct my_driver_data), GFP_KERNEL);
+    if(!driver_data)
+        return -ENOMEM;
+
+    //populate contents of driver_data here
+
+    // Add pointer to driver_data to the platform device structure
+    // so it can be retrieved in future.
+
+    platform_set_drvdata(pdev, driver_data);
+
+    */
+
+    return 0;
+}
+
+static int vesta_exp_card_remove(struct platform_device *pdev)
+{
+    //struct my_driver_data *driver_data = platform_get_drvdata(pdev);
+
+    printk(KERN_ALERT " %s\n", __FUNCTION__);
+
+    /* do something with the driver */
+
+    return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id vesta_exp_card_of_match[] = {
+        {
+                .compatible = "rigado,vesta-exp-card",
+        },
+        { },
+};
+MODULE_DEVICE_TABLE(of, vesta_exp_card_of_match);
+
+#endif
+
+
+static const struct dev_pm_ops vesta_exp_card_pm_ops = {
+    .suspend	= vesta_exp_card_pm_suspend,
+    .resume	= vesta_exp_card_pm_resume,
+};
+
+static struct platform_driver vesta_exp_card_driver = {
+    .probe      = vesta_exp_card_probe,
+    .remove     = vesta_exp_card_remove,
+    .driver     = {
+        .name	= "vesta_exp_card_driver",
+        .owner	= THIS_MODULE,
+        .pm	= &vesta_exp_card_pm_ops,
+	.of_match_table = of_match_ptr(vesta_exp_card_of_match),
+    },
+};
+
+/* Use these functions if more complex processing needed when the
+   driver code is initialized or unloaded
+
+static int __init vesta_exp_card_init_module(void)
+{
+    int ret;
+    pr_info(" %s\n", __FUNCTION__);
+    
+    return platform_driver_register(&vesta_exp_card_driver);
+}
+
+// entry point for unloading the module 
+static void __exit vesta_exp_card_cleanup_module(void)
+{
+    pr_info(" %s\n", __FUNCTION__);
+    platform_driver_unregister(&vesta_exp_card_driver);
+}
+
+module_init(vesta_exp_card_init_module);
+module_exit(vesta_exp_card_cleanup_module);
+*/
+
+/* Otherwise, use simple platrform driver registration macro */
+
+module_platform_driver(vesta_exp_card_driver);
+
+MODULE_AUTHOR("Peter Tucker");
+MODULE_DESCRIPTION("Vesta Gateway expansion card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vesta_exp_card_driver");
--- linux-ein-5.4.0.orig/drivers/misc/vesta_overlaymgr.c
+++ linux-ein-5.4.0/drivers/misc/vesta_overlaymgr.c
@@ -0,0 +1,2031 @@
+/*
+ * Rigado Vesta Gateway device tree overay manager
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2012-2015 Konsulko Group.
+ * Author: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ * Copyright (C) 2017 Rigado, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * The Vesta device tree overlay manager was adapted from the 
+ * BeagleBone CAPE manager. Note that the term "slot" is used
+ * somewhat differently for Vesta vs. the BeagleBone.  BeagleBone
+ * expansion cards (called CAPEs) are designed to be stacked, with the
+ * result that the total number of slots is not a fixed entity.  The CAPE
+ * manager allows the user to specify, via the baseboard #slots parameter,
+ * that overlays for a certain number of slots are to be applied automatically
+ * at boot time, but also allows the user to apply overlays for additional CAPEs
+ * from user space after boot has completed.  In contrast, Vesta Gateways have
+ * a fixed number of slots (currently 1), each of which can hold just a single
+ * expasnion card.  For Vesta, the goal is simply to detect the presence
+ * of any expansion cards, and apply the appropriate overlays, during boot.
+ * As such, the slots_store() function, which allows user to create
+ * new slots from user space, and apply overlays for these slots,
+ * has been disabled.
+ *
+ * See Documentation/misc-devices/vesta_overlaymgr.txt and /Documentation/
+ * devicetree/bindings/misc/vesta_overlaymgr.txt for additional information
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/firmware.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/memory.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/taskstats_kern.h>
+#include <generated/utsrelease.h>
+
+/* disabled expansion cards */
+static char *disable_partno;
+module_param(disable_partno, charp, 0444);
+MODULE_PARM_DESC(disable_partno,
+		"Comma delimited list of PART-NUMBER[:REV] of disabled expansion cards");
+
+/* enable expansion cards */
+static char *enable_partno;
+module_param(enable_partno, charp, 0444);
+MODULE_PARM_DESC(enable_partno,
+		"Comma delimited list of PART-NUMBER[:REV] of enabled expansion cards");
+
+/* delay to scan on boot until rootfs appears */
+static int boot_scan_period = 2000;
+module_param(boot_scan_period, int, 0444);
+MODULE_PARM_DESC(boot_scan_period,
+		"boot scan period until rootfs firmware is available");
+
+static int uboot_overlaymgr_enabled = 0;
+module_param(uboot_overlaymgr_enabled, int, 0444);
+MODULE_PARM_DESC(uboot_overlaymgr_enabled,
+		 "U-Boot Cape Manager is enabled (0=Kernel Cape Manager [default], 1=Disable Kernel Cape Manager)");
+
+struct overlaymgr_info;
+
+struct slot_ee_attribute {
+	struct device_attribute devattr;
+	unsigned int field;
+	struct vesta_slot *slot;	/* this is filled when instantiated */
+};
+#define to_slot_ee_attribute(x) \
+	container_of((x), struct slot_ee_attribute, devattr)
+
+struct bbrd_ee_attribute {
+	struct device_attribute devattr;
+	unsigned int field;
+};
+#define to_bbrd_ee_attribute(x) \
+	container_of((x), struct bbrd_ee_attribute, devattr)
+
+/* Be sure signature is large enough to hold data read in from EEPROM */
+struct vesta_slot {
+	struct list_head	node;
+	struct overlaymgr_info	*info;
+	int			slotno;
+	struct nvmem_cell	*nvmem_cell;
+
+	char			text_id[256];
+	char			signature[74];
+	/* quick access */
+	char			board_name[32+1];
+	char			version[4+1];
+	char			manufacturer[16+1];
+	char			part_number[16+1];
+
+	/* attribute group */
+	char			*ee_attr_name;
+	int			ee_attrs_count;
+	struct slot_ee_attribute *ee_attrs;
+	struct attribute	**ee_attrs_tab;
+	struct attribute_group	attrgroup;
+
+	/* state flags */
+	unsigned int		probed : 1;
+	unsigned int		probe_failed : 1;
+	unsigned int		override : 1;
+	unsigned int		loading : 1;
+	unsigned int		loaded : 1;
+	unsigned int		retry_loading : 1;
+	unsigned int		disabled : 1;
+
+	char			*dtbo;
+	const struct firmware	*fw;
+	struct device_node	*overlay;
+	int			overlay_id;
+
+	/* loader thread */
+	struct workqueue_struct *loader_wq;
+	struct work_struct	loader_work;
+
+	/* load priority */
+	int priority;
+};
+
+struct vesta_baseboard {
+
+	/* from the matched boardmap node */
+	char			*compatible_name;
+
+	/* filled in by reading the eeprom */
+	char			signature[256];
+	char			text_id[64+1];
+
+	/* quick access */
+	char			board_name[8+1];
+	char			revision[4+1];
+	char			serial_number[12+1];
+
+	/* access to the eeprom */
+	struct nvmem_cell	*nvmem_cell;
+};
+
+struct overlaymgr_info {
+	struct platform_device	*pdev;
+
+	atomic_t next_slot_nr;
+	struct list_head	slot_list;
+	struct mutex		slots_list_mutex;
+
+	/* baseboard EEPROM data */
+	struct vesta_baseboard	baseboard;
+
+	/* wait queue for keeping the priorities straight */
+	wait_queue_head_t	load_wq;
+};
+
+static int vesta_slot_fill_override(struct vesta_slot *slot,
+		const char *part_number, const char *version);
+static struct vesta_slot *overlaymgr_add_slot(
+		struct overlaymgr_info *info, const char *slot_name,
+		const char *part_number, const char *version, int prio);
+static int overlaymgr_remove_slot_no_lock(struct vesta_slot *slot);
+static int overlaymgr_remove_slot(struct vesta_slot *slot);
+static int overlaymgr_load_slot(struct vesta_slot *slot);
+static int overlaymgr_unload_slot(struct vesta_slot *slot);
+
+/* baseboard EEPROM field definition */
+#define BBRD_EE_FIELD_HEADER		0
+#define BBRD_EE_FIELD_BOARD_NAME	1
+#define BBRD_EE_FIELD_REVISION		2
+#define BBRD_EE_FIELD_SERIAL_NUMBER	3
+#define BBRD_EE_FIELD_CONFIG_OPTION	4
+#define BBRD_EE_FILED_RSVD1		5
+#define BBRD_EE_FILED_RSVD2		6
+#define BBRD_EE_FILED_RSVD3		7
+
+/* Expansion card EEPROM field definitions */
+#define EXCARD_EE_FIELD_HEADER		0
+#define EXCARD_EE_FIELD_EEPROM_REV	1
+#define EXCARD_EE_FIELD_BOARD_NAME	2
+#define EXCARD_EE_FIELD_VERSION		3
+#define EXCARD_EE_FIELD_MANUFACTURER	4
+#define EXCARD_EE_FIELD_PART_NUMBER	5
+#define EXCARD_EE_FIELD_NUMBER_OF_PINS	6
+#define EXCARD_EE_FIELD_SERIAL_NUMBER	7
+#define EXCARD_EE_FIELD_PIN_USAGE		8
+#define EXCARD_EE_FIELD_VDD_3V3EXP	9
+#define EXCARD_EE_FIELD_VDD_5V		10
+#define EXCARD_EE_FIELD_SYS_5V		11
+#define EXCARD_EE_FIELD_DC_SUPPLIED	12
+#define EXCARD_EE_FIELD_FIELDS_NR		13
+
+#define EE_FIELD_MAKE_HEADER(p)	\
+	({ \
+		const u8 *_p = (p); \
+		(((u32)_p[0] << 24) | ((u32)_p[1] << 16) | \
+		 ((u32)_p[2] <<  8) |  (u32)_p[3]); \
+	})
+
+#define EE_FIELD_HEADER_VALID	0xaa5533ee
+
+struct ee_field {
+	const char	*name;
+	int		start;
+	int		size;
+	unsigned int	ascii : 1;
+	unsigned int	strip_trailing_dots : 1;
+	const char	*override;
+};
+
+/* baseboard definitions */
+static const struct ee_field bbrd_sig_fields[] = {
+	[BBRD_EE_FIELD_HEADER] = {
+		.name		= "header",
+		.start		= 0,
+		.size		= 4,
+		.ascii		= 0,
+		.override	= "\xaa\x55\x33\xee",	/* AA 55 33 EE */
+	},
+	[BBRD_EE_FIELD_BOARD_NAME] = {
+		.name		= "board-name",
+		.start		= 4,
+		.size		= 8,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Board Name",
+	},
+	[BBRD_EE_FIELD_REVISION] = {
+		.name		= "revision",
+		.start		= 12,
+		.size		= 4,
+		.ascii		= 1,
+		.override	= "00A0",
+	},
+/*
+	[BBRD_EE_FIELD_SERIAL_NUMBER] = {
+		.name		= "serial-number",
+		.start		= 16,
+		.size		= 12,
+		.ascii		= 1,
+		.override	= "0000000000",
+	},
+	[BBRD_EE_FIELD_CONFIG_OPTION] = {
+		.name		= "config-option",
+		.start		= 28,
+		.size		= 32,
+	},
+*/
+};
+
+/* Expansion card  EEPROM definitions */
+static const struct ee_field excard_sig_fields[] = {
+	[EXCARD_EE_FIELD_HEADER] = {
+		.name		= "header",
+		.start		= 0,
+		.size		= 4,
+		.ascii		= 0,
+		.override	= "\xaa\x55\x33\xee",	/* AA 55 33 EE */
+	},
+	[EXCARD_EE_FIELD_EEPROM_REV] = {
+		.name		= "eeprom-format-revision",
+		.start		= 4,
+		.size		= 2,
+		.ascii		= 1,
+		.override	= "A0",
+	},
+	[EXCARD_EE_FIELD_BOARD_NAME] = {
+		.name		= "board-name",
+		.start		= 6,
+		.size		= 32,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Board Name",
+	},
+	[EXCARD_EE_FIELD_VERSION] = {
+		.name		= "version",
+		.start		= 38,
+		.size		= 4,
+		.ascii		= 1,
+		.override	= "00A0",
+	},
+	[EXCARD_EE_FIELD_MANUFACTURER] = {
+		.name		= "manufacturer",
+		.start		= 42,
+		.size		= 16,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Manuf",
+	},
+	[EXCARD_EE_FIELD_PART_NUMBER] = {
+		.name		= "part-number",
+		.start		= 58,
+		.size		= 16,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Part#",
+	},
+/*
+	[EXCARD_EE_FIELD_NUMBER_OF_PINS] = {
+		.name		= "number-of-pins",
+		.start		= 74,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[EXCARD_EE_FIELD_SERIAL_NUMBER] = {
+		.name		= "serial-number",
+		.start		= 76,
+		.size		= 12,
+		.ascii		= 1,
+		.override	= "0000000000",
+	},
+	[EXCARD_EE_FIELD_PIN_USAGE] = {
+		.name		= "pin-usage",
+		.start		= 88,
+		.size		= 140,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[EXCARD_EE_FIELD_VDD_3V3EXP] = {
+		.name		= "vdd-3v3exp",
+		.start		= 228,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[EXCARD_EE_FIELD_VDD_5V] = {
+		.name		= "vdd-5v",
+		.start		= 230,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[EXCARD_EE_FIELD_SYS_5V] = {
+		.name		= "sys-5v",
+		.start		= 232,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[EXCARD_EE_FIELD_DC_SUPPLIED] = {
+		.name		= "dc-supplied",
+		.start		= 234,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+*/
+};
+
+static char *ee_field_get(const struct ee_field *sig_field,
+		const void *data, int field, char *buf, int bufsz)
+{
+	int len;
+
+	/* enough space? */
+	if (bufsz < sig_field->size + sig_field->ascii)
+		return NULL;
+
+	memcpy(buf, (char *)data + sig_field->start, sig_field->size);
+
+	/* terminate ascii field */
+	if (sig_field->ascii)
+		buf[sig_field->size] = '\0';
+
+	if (sig_field->strip_trailing_dots) {
+		len = strlen(buf);
+		while (len > 1 && buf[len - 1] == '.')
+			buf[--len] = '\0';
+	}
+
+	return buf;
+}
+
+char *bbrd_ee_field_get(const void *data,
+		int field, char *buf, int bufsz)
+{
+	if ((unsigned int)field >= ARRAY_SIZE(bbrd_sig_fields))
+		return NULL;
+
+	return ee_field_get(&bbrd_sig_fields[field], data, field, buf, bufsz);
+}
+
+char *excard_ee_field_get(const void *data,
+		int field, char *buf, int bufsz)
+{
+	if ((unsigned int)field >= ARRAY_SIZE(excard_sig_fields))
+		return NULL;
+
+	return ee_field_get(&excard_sig_fields[field], data, field, buf, bufsz);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id overlaymgr_of_match[] = {
+	{
+		.compatible = "rigado,vesta-overlaymgr",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, overlaymgr_of_match);
+
+#endif
+
+struct vesta_baseboard_data {
+	u8 header[4];
+	char name[8];
+	char revision[4];
+/*
+	char serial_no[12];
+	u8 config_option[32];
+*/
+};
+
+static struct vesta_slot def_adc_slot = {
+	.slotno = 0,
+
+	.signature = "\xaa\x55\x33\xee",
+	.board_name = "Default ADC Card",
+	.version = "0001",
+	.manufacturer = "Rigado, Inc",
+	.part_number = "310-00001",
+	.probed = 1,
+	.probe_failed = 0,
+	.override = 1,
+};
+
+static int vesta_baseboard_scan(struct vesta_baseboard *bbrd)
+{
+	struct overlaymgr_info *info = container_of(bbrd,
+			struct overlaymgr_info, baseboard);
+	const u8 *p;
+	//int ret;
+	//size_t len;
+	struct vesta_baseboard_data base = {
+		{ 0xaa, 0x55, 0x33, 0xee },
+		"vesta",
+	 	"0001",
+	};
+
+/* Vesta Gateway's main board does not have its own EEPROM, so hardcode
+ * this data for now.  In future, may want to store this info in 
+ * the emmc peristant data area, and retrieve it at runtime.
+ */
+	
+/*
+	p = nvmem_cell_read(bbrd->nvmem_cell, &len);
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		dev_err(&info->pdev->dev,
+			"Cannot read cell (ret=%d)\n", ret);
+		return ret;
+	}
+
+	
+	if (len < sizeof(bbrd->signature)) {
+		dev_info(&info->pdev->dev,
+			"Short read %d (should be >= %d bytes)\n",
+			len, sizeof(bbrd->signature));
+		return -EINVAL;
+	}
+*/
+	memcpy(bbrd->signature, &base, sizeof(base));
+
+	p = bbrd->signature;
+	if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
+		dev_err(&info->pdev->dev, "Invalid board signature '%08x'\n",
+			EE_FIELD_MAKE_HEADER(p));
+		return -ENODEV;
+	}
+
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_BOARD_NAME,
+			bbrd->board_name, sizeof(bbrd->board_name));
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_REVISION,
+			bbrd->revision, sizeof(bbrd->revision));
+/*
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_SERIAL_NUMBER,
+			bbrd->serial_number, sizeof(bbrd->serial_number));
+*/
+
+	/* board_name,version */
+	snprintf(bbrd->text_id, sizeof(bbrd->text_id) - 1,
+			"%s,%s", bbrd->board_name, bbrd->revision);
+
+	/* terminate always */
+	bbrd->text_id[sizeof(bbrd->text_id) - 1] = '\0';
+
+	return 0;
+}
+
+static int vesta_slot_scan(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	const u8 *p;
+	int r;
+	ssize_t len;
+
+	/* need to read EEPROM? */
+	if (slot->probed)
+		goto slot_fail_check;
+
+	if (uboot_overlaymgr_enabled)
+		goto slot_fail_check;
+
+	slot->probed = 1;
+
+	if (!slot->override) {
+
+		p = nvmem_cell_read(slot->nvmem_cell, &len);
+		if (IS_ERR(p)) {
+			r = PTR_ERR(p);
+			slot->probe_failed = 1;
+
+			/* timeout is normal when no expansion card is present */
+			if (r != -ETIMEDOUT)
+				dev_err(&info->pdev->dev,
+					"Cannot read cell (ret=%d)\n", r);
+			return r;
+		}
+		if (len < sizeof(slot->signature)) {
+			dev_info(&info->pdev->dev,
+				"Short read %d (should be >= %d bytes)\n",
+				len, sizeof(slot->signature));
+			return -EINVAL;
+		}
+		memcpy(slot->signature, p, sizeof(slot->signature));
+
+	} else
+		dev_info(&info->pdev->dev,
+			"Using override eeprom data at slot %d\n",
+			slot->slotno);
+
+	p = slot->signature;
+	if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
+		dev_err(&info->pdev->dev,
+			"Invalid signature '%08x' at slot %d\n",
+			EE_FIELD_MAKE_HEADER(p), slot->slotno);
+		slot->probe_failed = 1;
+		return -ENODEV;
+	}
+
+	excard_ee_field_get(slot->signature,
+			EXCARD_EE_FIELD_BOARD_NAME,
+			slot->board_name, sizeof(slot->board_name));
+	excard_ee_field_get(slot->signature,
+			EXCARD_EE_FIELD_VERSION,
+			slot->version, sizeof(slot->version));
+	excard_ee_field_get(slot->signature,
+			EXCARD_EE_FIELD_MANUFACTURER,
+			slot->manufacturer, sizeof(slot->manufacturer));
+	excard_ee_field_get(slot->signature,
+			EXCARD_EE_FIELD_PART_NUMBER,
+			slot->part_number, sizeof(slot->part_number));
+
+	/* board_name,version,manufacturer,part_number */
+	snprintf(slot->text_id, sizeof(slot->text_id) - 1,
+			"%s,%s,%s,%s", slot->board_name, slot->version,
+			slot->manufacturer, slot->part_number);
+
+	/* terminate always */
+	slot->text_id[sizeof(slot->text_id) - 1] = '\0';
+
+slot_fail_check:
+	/* slot has failed and we don't support hotpluging */
+	if (slot->probe_failed)
+		return -ENODEV;
+
+	return 0;
+}
+
+/* return 0 if not matched,, 1 if matched */
+static int vesta_match_excard(const char *match,
+		const char *part_number, const char *version)
+{
+	char *tmp_part_number, *tmp_version;
+	char *buf, *s, *e, *sn;
+	int found;
+
+	if (match == NULL || part_number == NULL)
+		return 0;
+
+	/* copy the argument to work on it */
+	buf = kstrdup(match, GFP_KERNEL);
+
+	/* no memory, too bad... */
+	if (buf == NULL)
+		return 0;
+
+	found = 0;
+	s = buf;
+	e = s + strlen(s);
+	while (s < e) {
+		/* find comma separator */
+		sn = strchr(s, ',');
+		if (sn != NULL)
+			*sn++ = '\0';
+		else
+			sn = e;
+		tmp_part_number = s;
+		tmp_version = strchr(tmp_part_number, ':');
+		if (tmp_version != NULL)
+			*tmp_version++ = '\0';
+		s = sn;
+
+		/* the part names must match */
+		if (strcmp(tmp_part_number, part_number) != 0)
+			continue;
+
+		/* if there's no version, match any */
+		if (version == NULL || tmp_version == NULL ||
+			strcmp(version, tmp_version) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	kfree(buf);
+
+	return found;
+}
+
+/* helper method */
+static int of_multi_prop_cmp(const struct property *prop, const char *value)
+{
+	const char *cp;
+	int cplen, vlen, l;
+
+	/* check if it's directly compatible */
+	cp = prop->value;
+	cplen = prop->length;
+	vlen = strlen(value);
+
+	while (cplen > 0) {
+		/* compatible? */
+		if (of_compat_cmp(cp, value, vlen) == 0)
+			return 0;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+	return -1;
+}
+
+static ssize_t slot_ee_attr_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct slot_ee_attribute *ee_attr = to_slot_ee_attribute(attr);
+	struct vesta_slot *slot = ee_attr->slot;
+	const struct ee_field *sig_field;
+	//int i;
+	int len;
+	char *p, *s;
+	//u16 val;
+
+	/* add newline for ascii fields */
+	sig_field = &excard_sig_fields[ee_attr->field];
+
+	len = sig_field->size + sig_field->ascii;
+	p = kmalloc(len, GFP_KERNEL);
+	if (p == NULL)
+		return -ENOMEM;
+
+	s = excard_ee_field_get(slot->signature, ee_attr->field, p, len);
+	if (s == NULL)
+		return -EINVAL;
+
+	/* add newline for ascii fields and return */
+	if (sig_field->ascii) {
+		len = sprintf(buf, "%s\n", s);
+		goto out;
+	}
+
+	/* case by case handling */
+	switch (ee_attr->field) {
+	case EXCARD_EE_FIELD_HEADER:
+		len = sprintf(buf, "%02x %02x %02x %02x\n",
+				s[0], s[1], s[2], s[3]);
+		break;
+
+		/* 2 bytes */
+/*
+	case EXCARD_EE_FIELD_NUMBER_OF_PINS:
+	case EXCARD_EE_FIELD_VDD_3V3EXP:
+	case EXCARD_EE_FIELD_VDD_5V:
+	case EXCARD_EE_FIELD_SYS_5V:
+	case EXCARD_EE_FIELD_DC_SUPPLIED:
+		val = s[0] & (s[1] << 8);
+		len = sprintf(buf, "%u\n", (unsigned int)val & 0xffff);
+		break;
+
+	case EXCARD_EE_FIELD_PIN_USAGE:
+
+		len = 0;
+		for (i = 0; i < sig_field->size / 2; i++) {
+			val = s[0] & (s[1] << 8);
+			sprintf(buf, "%04x\n", val);
+			buf += 5;
+			len += 5;
+			s += 2;
+		}
+
+		break;
+*/
+	default:
+		*buf = '\0';
+		len = 0;
+		break;
+	}
+
+out:
+	kfree(p);
+
+	return len;
+}
+
+#define SLOT_EE_ATTR(_name, _field) \
+	{ \
+		.devattr = __ATTR(_name, S_IRUGO, slot_ee_attr_show, NULL), \
+		.field = EXCARD_EE_FIELD_##_field, \
+		.slot = NULL, \
+	}
+
+static const struct slot_ee_attribute slot_ee_attrs[] = {
+	SLOT_EE_ATTR(header, HEADER),
+	SLOT_EE_ATTR(eeprom-format-revision, EEPROM_REV),
+	SLOT_EE_ATTR(board-name, BOARD_NAME),
+	SLOT_EE_ATTR(version, VERSION),
+	SLOT_EE_ATTR(manufacturer, MANUFACTURER),
+	SLOT_EE_ATTR(part-number, PART_NUMBER),
+/*
+	SLOT_EE_ATTR(number-of-pins, NUMBER_OF_PINS),
+	SLOT_EE_ATTR(serial-number, SERIAL_NUMBER),
+	SLOT_EE_ATTR(pin-usage, PIN_USAGE),
+	SLOT_EE_ATTR(vdd-3v3exp, VDD_3V3EXP),
+	SLOT_EE_ATTR(vdd-5v, VDD_5V),
+	SLOT_EE_ATTR(sys-5v, SYS_5V),
+	SLOT_EE_ATTR(dc-supplied, DC_SUPPLIED),
+*/
+};
+
+static int vesta_slot_sysfs_register(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct slot_ee_attribute *ee_attr;
+	struct attribute_group *attrgroup;
+	int i, err, sz;
+
+	slot->ee_attr_name = kasprintf(GFP_KERNEL, "slot-%d", slot->slotno);
+	if (slot->ee_attr_name == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attr_name\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attr_name;
+	}
+
+	slot->ee_attrs_count = ARRAY_SIZE(slot_ee_attrs);
+
+	sz = slot->ee_attrs_count * sizeof(*slot->ee_attrs);
+	slot->ee_attrs = kmalloc(sz, GFP_KERNEL);
+	if (slot->ee_attrs == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs;
+	}
+
+	attrgroup = &slot->attrgroup;
+	memset(attrgroup, 0, sizeof(*attrgroup));
+	attrgroup->name = slot->ee_attr_name;
+
+	sz = sizeof(*slot->ee_attrs_tab) * (slot->ee_attrs_count + 1);
+	attrgroup->attrs = kmalloc(sz, GFP_KERNEL);
+	if (attrgroup->attrs == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs_tab;
+	}
+	/* copy everything over */
+	memcpy(slot->ee_attrs, slot_ee_attrs, sizeof(slot_ee_attrs));
+
+	/* bind this attr to the slot */
+	for (i = 0; i < slot->ee_attrs_count; i++) {
+		ee_attr = &slot->ee_attrs[i];
+		ee_attr->slot = slot;
+		attrgroup->attrs[i] = &ee_attr->devattr.attr;
+	}
+	attrgroup->attrs[i] = NULL;
+
+	/* make lockdep happy */
+	for (i = 0; i < slot->ee_attrs_count; i++) {
+		ee_attr = &slot->ee_attrs[i];
+		sysfs_attr_init(&ee_attr->devattr.attr);
+	}
+
+	err = sysfs_create_group(&dev->kobj, attrgroup);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs_group;
+	}
+
+	return 0;
+
+err_fail_no_ee_attrs_group:
+	kfree(slot->ee_attrs_tab);
+err_fail_no_ee_attrs_tab:
+	kfree(slot->ee_attrs);
+err_fail_no_ee_attrs:
+	kfree(slot->ee_attr_name);
+err_fail_no_ee_attr_name:
+	return err;
+}
+
+static void vesta_slot_sysfs_unregister(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+
+	sysfs_remove_group(&dev->kobj, &slot->attrgroup);
+	kfree(slot->ee_attrs_tab);
+	kfree(slot->ee_attrs);
+	kfree(slot->ee_attr_name);
+}
+
+static ssize_t bbrd_ee_attr_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct bbrd_ee_attribute *ee_attr = to_bbrd_ee_attribute(attr);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct overlaymgr_info *info = platform_get_drvdata(pdev);
+	struct vesta_baseboard *bbrd = &info->baseboard;
+	const struct ee_field *sig_field;
+	//u16 val;
+        //int i;
+	int len;
+	char *p, *s;
+
+	/* add newline for ascii fields */
+	sig_field = &bbrd_sig_fields[ee_attr->field];
+
+	len = sig_field->size + sig_field->ascii;
+	p = kmalloc(len, GFP_KERNEL);
+	if (p == NULL)
+		return -ENOMEM;
+
+	s = bbrd_ee_field_get(bbrd->signature, ee_attr->field, p, len);
+	if (s == NULL)
+		return -EINVAL;
+
+	/* add newline for ascii fields and return */
+	if (sig_field->ascii) {
+		len = sprintf(buf, "%s\n", s);
+		goto out;
+	}
+
+	/* case by case handling */
+	switch (ee_attr->field) {
+	case BBRD_EE_FIELD_HEADER:
+		len = sprintf(buf, "%02x %02x %02x %02x\n",
+				s[0], s[1], s[2], s[3]);
+		break;
+
+/*
+	case BBRD_EE_FIELD_CONFIG_OPTION:
+		len = 0;
+		for (i = 0; i < sig_field->size / 2; i++) {
+			val = s[0] & (s[1] << 8);
+			sprintf(buf, "%04x\n", val);
+			buf += 5;
+			len += 5;
+			s += 2;
+		}
+		break;
+*/
+
+	default:
+		*buf = '\0';
+		len = 0;
+		break;
+	}
+
+out:
+	kfree(p);
+
+	return len;
+}
+
+#define BBRD_EE_ATTR(_name, _field) \
+	{ \
+		.devattr = __ATTR(_name, 0440, bbrd_ee_attr_show, NULL), \
+		.field = BBRD_EE_FIELD_##_field, \
+	}
+
+static struct bbrd_ee_attribute bbrd_ee_attrs[] = {
+	BBRD_EE_ATTR(header, HEADER),
+	BBRD_EE_ATTR(board-name, BOARD_NAME),
+	BBRD_EE_ATTR(revision, REVISION),
+/*
+	BBRD_EE_ATTR(serial-number, SERIAL_NUMBER),
+	BBRD_EE_ATTR(config-option, CONFIG_OPTION),
+*/
+};
+
+static struct attribute *bbrd_attrs_flat[] = {
+	&bbrd_ee_attrs[BBRD_EE_FIELD_HEADER].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_BOARD_NAME].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_REVISION].devattr.attr,
+/*
+	&bbrd_ee_attrs[BBRD_EE_FIELD_SERIAL_NUMBER].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_CONFIG_OPTION].devattr.attr,
+*/
+	NULL,
+};
+
+static const struct attribute_group bbrd_attr_group = {
+	.name	= "baseboard",
+	.attrs	= bbrd_attrs_flat,
+};
+
+static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
+		char *buf);
+/* Remove ability to apply overlays from user space, which does not
+   have much practical value for Vesta
+
+static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count);
+
+static DEVICE_ATTR(slots, 0644, slots_show, slots_store);
+
+*/
+
+static DEVICE_ATTR(slots, 0444, slots_show, NULL);
+
+static struct attribute *root_attrs_flat[] = {
+	&dev_attr_slots.attr,
+	NULL,
+};
+
+static const struct attribute_group root_attr_group = {
+	.attrs = root_attrs_flat,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&root_attr_group,
+	&bbrd_attr_group,
+	NULL,
+};
+
+static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct overlaymgr_info *info = platform_get_drvdata(pdev);
+	struct vesta_slot *slot;
+	ssize_t len, sz;
+
+	mutex_lock(&info->slots_list_mutex);
+	sz = 0;
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		len = sprintf(buf, "%2d: %c%c%c%c%c%c %3d %s\n",
+				slot->slotno,
+				slot->probed       ? 'P' : '-',
+				slot->probe_failed ? 'F' : '-',
+				slot->override     ? 'O' : '-',
+				slot->loading	   ? 'l' : '-',
+				slot->loaded	   ? 'L' : '-',
+				slot->disabled     ? 'D' : '-',
+				slot->overlay_id, slot->text_id);
+
+		buf += len;
+		sz += len;
+	}
+	mutex_unlock(&info->slots_list_mutex);
+
+	return sz;
+}
+
+
+/* The beaglebone cape manager allows overlay application to be triggered
+   from user space, but the implementation, which creates a NEW slot each 
+   time it is run, rather than applying an overlay to an existing slot, makes
+   no sense for Vesta, where expansion cards can't be stacked on top of one 
+   another.  I considered modifying this function to let users specify
+   an overlay to apply to an existing slot, but decided that since overlays
+   are automatically applied during boot for any existing Vesta slot that is occupied,
+   this capability would not be of much practical value.
+
+static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct overlaymgr_info *info = platform_get_drvdata(pdev);
+	struct vesta_slot *slot;
+	struct device_node *pnode, *node;
+	char *s, *part_number, *version;
+	int ret;
+	int slotno;
+
+	// check for remove slot 
+	if (strlen(buf) > 0 && buf[0] == '-') {
+		ret = kstrtoint(buf + 1, 10, &slotno);
+		if (ret != 0)
+			return ret;
+
+		// now load each (take lock to be sure 
+		mutex_lock(&info->slots_list_mutex);
+		list_for_each_entry(slot, &info->slot_list, node) {
+			if (slotno == slot->slotno)
+				goto found;
+		}
+
+		mutex_unlock(&info->slots_list_mutex);
+		return -ENODEV;
+found:
+		// the hardware slots just get unloaded 
+		if (!slot->override) {
+			ret = overlaymgr_unload_slot(slot);
+			if (ret == 0)
+				dev_info(&pdev->dev,
+					"Unloaded slot #%d\n", slotno);
+			else
+				dev_err(&pdev->dev,
+					"Failed to unload slot #%d\n", slotno);
+		} else {
+			ret = overlaymgr_remove_slot_no_lock(slot);
+			if (ret == 0)
+				dev_info(&pdev->dev,
+					"Removed slot #%d\n", slotno);
+			else
+				dev_err(&pdev->dev,
+					"Failed to remove slot #%d\n", slotno);
+		}
+		mutex_unlock(&info->slots_list_mutex);
+
+		return ret == 0 ? strlen(buf) : ret;
+	}
+
+	part_number = kstrdup(buf, GFP_KERNEL);
+	if (part_number == NULL)
+		return -ENOMEM;
+
+	// remove trailing spaces dots and newlines 
+	s = part_number + strlen(part_number);
+	while (s > part_number &&
+			(isspace(s[-1]) || s[-1] == '\n' || s[-1] == '.'))
+		*--s = '\0';
+
+	version = strchr(part_number, ':');
+	if (version != NULL)
+		*version++ = '\0';
+
+	dev_info(&pdev->dev, "part_number '%s', version '%s'\n",
+			part_number, version ? version : "N/A");
+
+	pnode = pdev->dev.of_node;
+	node = NULL;
+	slot = NULL;
+	ret = 0;
+
+	// no specific slot found, try immediate 
+	slot = overlaymgr_add_slot(info, NULL, part_number, version, 0);
+
+	if (IS_ERR_OR_NULL(slot)) {
+		dev_err(&pdev->dev, "Failed to add slot #%d\n",
+			atomic_read(&info->next_slot_nr) - 1);
+		ret = slot ? PTR_ERR(slot) : -ENODEV;
+		slot = NULL;
+		goto err_fail;
+	}
+
+	kfree(part_number);
+
+	ret = overlaymgr_load_slot(slot);
+	if (ret != 0)
+		overlaymgr_remove_slot(slot);
+
+	return ret == 0 ? strlen(buf) : ret;
+err_fail:
+	of_node_put(node);
+	kfree(part_number);
+	return ret;
+}
+
+*/
+
+/* verify the overlay */
+static int __maybe_unused overlaymgr_verify_overlay(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct vesta_baseboard *bbrd = &info->baseboard;
+	struct device_node *node = slot->overlay;
+	struct property *prop;
+	struct vesta_slot *slotn;
+	int err, counta, countb, i, j;
+	const char *ra, *rb;
+
+	/* validate */
+	if (node == NULL) {
+		dev_err(dev, "slot #%d: No overlay for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* check if the slot is compatible with the board */
+	prop = of_find_property(node, "compatible", NULL);
+
+	/* no compatible property? */
+	if (prop == NULL) {
+		dev_err(dev, "slot #%d: No compatible property for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* verify that the expansion card is baseboard compatible */
+	if (of_multi_prop_cmp(prop, bbrd->compatible_name) != 0) {
+		dev_err(dev, "slot #%d: Incompatible with baseboard for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* count the strings */
+	counta = of_property_count_strings(node, "exclusive-use");
+	/* no valid property, or no resources; no matter, it's OK */
+	if (counta <= 0)
+		return 0;
+
+	/* and now check if there's a resource conflict */
+	err = 0;
+	mutex_lock(&info->slots_list_mutex);
+	for (i = 0; i < counta; i++) {
+
+		ra = NULL;
+		err = of_property_read_string_index(node, "exclusive-use",
+				i, &ra);
+		if (err != 0) {
+			dev_err(dev, "slot #%d: Could not read string #%d\n",
+					slot->slotno, i);
+			break;
+		}
+
+		list_for_each_entry(slotn, &info->slot_list, node) {
+
+			/* don't check against self */
+			if (slot == slotn)
+				continue;
+
+			/* only check against loaded or loading slots */
+			if (!slotn->loaded && !slotn->loading)
+				continue;
+
+			countb = of_property_count_strings(slotn->overlay,
+					"exclusive-use");
+			/* no valid property, or resources; it's OK */
+			if (countb <= 0)
+				continue;
+
+
+			for (j = 0; j < countb; j++) {
+
+				/* count the resources */
+				rb = NULL;
+				err = of_property_read_string_index(
+					slotn->overlay, "exclusive-use",
+						j, &rb);
+				if (err != 0) {
+					/* error, but we don't care */
+					err = 0;
+					break;
+				}
+
+				/* ignore case; just in case ;) */
+				if (strcasecmp(ra, rb) == 0) {
+
+					/* resource conflict */
+					err = -EEXIST;
+					dev_err(dev,
+						"slot #%d: %s conflict %s (#%d:%s)\n",
+						slot->slotno,
+						slot->part_number, ra,
+						slotn->slotno,
+						slotn->part_number);
+					goto out;
+				}
+			}
+		}
+	}
+out:
+	mutex_unlock(&info->slots_list_mutex);
+
+	return err;
+}
+
+static int overlaymgr_load_slot(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	//const char *dtbo;
+	int err;
+
+	if (slot->probe_failed) {
+		dev_err(dev, "slot #%d: probe failed for '%s'\n",
+			slot->slotno, slot->part_number);
+		return -ENODEV;
+	}
+
+	if (slot->loaded) {
+		dev_err(dev, "slot #%d: already loaded for '%s'\n",
+			slot->slotno, slot->part_number);
+		return -EAGAIN;
+	}
+
+	/* make sure we don't leak this on repeated calls */
+	kfree(slot->dtbo);
+	slot->dtbo = NULL;
+
+	dev_info(dev, "slot #%d: Requesting part number/version based '%s-%s.dtbo'\n",
+			slot->slotno, slot->part_number, slot->version);
+
+	/* request the part number + .dtbo*/
+	slot->dtbo = kasprintf(GFP_KERNEL, UTS_RELEASE"/device-tree/overlays/%s-%s.dtbo",
+			slot->part_number, slot->version);
+	if (slot->dtbo == NULL) {
+		dev_err(dev, "slot #%d: memory allocation error while attempting to retrieve dtbo\n",
+				slot->slotno);
+		return -ENOMEM;
+	}
+
+	dev_info(dev, "slot #%d: Requesting firmware '%s' for board-name '%s', version '%s'%s\n",
+			slot->slotno,
+			slot->dtbo, slot->board_name, slot->version,
+			system_state == SYSTEM_BOOTING ? " - booting" : "");
+
+	err = request_firmware_direct(&slot->fw, slot->dtbo, dev);
+	if (err != 0) {
+		dev_info(dev, "failed to load firmware '%s'\n", slot->dtbo);
+		goto err_fail_no_fw;
+	}
+
+	dev_info(dev, "slot #%d: dtbo '%s' loaded; converting to live tree\n",
+			slot->slotno, slot->dtbo);
+#if 0
+	of_fdt_unflatten_tree((unsigned long *)slot->fw->data, NULL, &slot->overlay);
+	if (slot->overlay == NULL) {
+		dev_err(dev, "slot #%d: Failed to unflatten\n",
+				slot->slotno);
+		err = -EINVAL;
+		goto err_fail;
+	}
+
+	/* mark it as detached */
+	of_node_set_flag(slot->overlay, OF_DETACHED);
+
+	/* perform resolution */
+	err = of_resolve_phandles(slot->overlay);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed to resolve tree\n",
+				slot->slotno);
+		goto err_fail;
+	}
+
+	err = overlaymgr_verify_overlay(slot);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed verification\n",
+				slot->slotno);
+		goto err_fail;
+	}
+
+	err = of_overlay_create(slot->overlay);
+	if (err < 0) {
+		dev_err(dev, "slot #%d: Failed to create overlay\n",
+				slot->slotno);
+		goto err_fail;
+	}
+
+	slot->overlay_id = err;
+#else
+	if (of_overlay_fdt_apply(slot->fw->data, slot->fw->size, &slot->overlay_id))
+		goto err_fail;
+#endif
+	
+	slot->loading = 0;
+	slot->loaded = 1;
+
+	dev_info(dev, "slot #%d: dtbo '%s' loaded; overlay id #%d\n",
+			slot->slotno, slot->dtbo, slot->overlay_id);
+
+	return 0;
+
+err_fail:
+
+	/* TODO: free the overlay, we can't right now cause
+	 * the unflatten method does not track it */
+	slot->overlay = NULL;
+
+	release_firmware(slot->fw);
+	slot->fw = NULL;
+
+err_fail_no_fw:
+	slot->loading = 0;
+	return err;
+}
+
+static int overlaymgr_unload_slot(struct vesta_slot *slot)
+{
+	if (!slot->loaded || slot->overlay_id == -1)
+		return -EINVAL;
+
+	of_overlay_remove(&(slot->overlay_id));
+	slot->overlay_id = -1;
+
+	slot->loaded = 0;
+
+	return 0;
+
+}
+
+/* slots_list_mutex must be taken */
+static int overlaymgr_remove_slot_no_lock(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	int ret;
+
+	if (slot == NULL)
+		return 0;
+
+	if (slot->loaded && slot->overlay_id >= 0) {
+		/* unload just in case */
+		ret = overlaymgr_unload_slot(slot);
+		if (ret != 0) {
+			dev_err(dev, "Unable to unload slot #%d\n",
+				slot->slotno);
+			return ret;
+		}
+	}
+
+	/* if probed OK, remove the sysfs nodes */
+	if (slot->probed && !slot->probe_failed)
+		vesta_slot_sysfs_unregister(slot);
+
+	/* remove it from the list */
+	list_del(&slot->node);
+
+	if (slot->nvmem_cell)
+		nvmem_cell_put(slot->nvmem_cell);
+
+	if (slot != &def_adc_slot)
+		devm_kfree(dev, slot);
+
+	return 0;
+}
+
+static int overlaymgr_remove_slot(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	int ret;
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = overlaymgr_remove_slot_no_lock(slot);
+	mutex_unlock(&info->slots_list_mutex);
+
+	return ret;
+}
+
+static int vesta_slot_fill_override(struct vesta_slot *slot,
+		const char *part_number, const char *version)
+{
+	const struct ee_field *sig_field;
+	int i, len, has_part_number;
+	char *p;
+
+	slot->probe_failed = 0;
+	slot->probed = 0;
+
+	/* zero out signature */
+	memset(slot->signature, 0,
+			sizeof(slot->signature));
+
+	/* first, fill in all with override defaults */
+	for (i = 0; i < ARRAY_SIZE(excard_sig_fields); i++) {
+
+		sig_field = &excard_sig_fields[i];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		if (sig_field->override)
+			memcpy(p, sig_field->override,
+					sig_field->size);
+		else
+			memset(p, 0, sig_field->size);
+	}
+
+	/* if a part_number is supplied use it */
+	len = part_number ? strlen(part_number) : 0;
+	if (len > 0) {
+		sig_field = &excard_sig_fields[EXCARD_EE_FIELD_PART_NUMBER];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		/* copy and zero out any remainder */
+		if (len > sig_field->size)
+			len = sig_field->size;
+		memcpy(p, part_number, len);
+		if (len < sig_field->size)
+			memset(p + len, 0, sig_field->size - len);
+
+		has_part_number = 1;
+	}
+
+	/* if a version is supplied use it */
+	len = version ? strlen(version) : 0;
+	if (len > 0) {
+		sig_field = &excard_sig_fields[EXCARD_EE_FIELD_VERSION];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		/* copy and zero out any remainder */
+		if (len > sig_field->size)
+			len = sig_field->size;
+		memcpy(p, version, len);
+		if (len < sig_field->size)
+			memset(p + len, 0, sig_field->size - len);
+	}
+
+	/* we must have a part number */
+	if (!has_part_number)
+		return -EINVAL;
+
+	slot->override = 1;
+
+	return 0;
+}
+
+static struct vesta_slot *
+overlaymgr_add_slot(struct overlaymgr_info *info, const char *slot_name,
+		const char *part_number, const char *version, int prio)
+{
+	struct vesta_slot *slot;
+	struct device *dev = &info->pdev->dev;
+	int slotno;
+	int ret;
+
+	slotno = atomic_inc_return(&info->next_slot_nr) - 1;
+
+	slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL);
+	if (slot == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	slot->info = info;
+	slot->slotno = slotno;
+	slot->priority = prio;
+	slot->overlay_id = -1;
+
+	if (slot_name) {
+		slot->nvmem_cell = nvmem_cell_get(dev, slot_name);
+		if (IS_ERR(slot->nvmem_cell)) {
+			ret = PTR_ERR(slot->nvmem_cell);
+			if (ret != -EPROBE_DEFER)
+				dev_info(dev, "Failed to get slot eeprom cell\n");
+			slot->nvmem_cell = NULL;
+			goto err_out;
+		}
+	} else {
+		dev_info(dev, "slot #%d: override\n", slotno);
+
+		/* fill in everything with defaults first */
+		ret = vesta_slot_fill_override(slot, part_number, version);
+		if (ret != 0) {
+			dev_info(dev, "slot #%d: override failed\n", slotno);
+			goto err_out;
+		}
+	}
+
+	ret = vesta_slot_scan(slot);
+	if (ret != 0) {
+
+		if (!slot->probe_failed) {
+			dev_info(dev, "slot #%d: scan failed\n",
+					slotno);
+			goto err_out;
+		}
+
+		dev_info(dev, "slot #%d: No expansion card found\n", slotno);
+		/* but all is fine */
+		devm_kfree(dev, slot);
+
+		/* add default ADC card */
+		slot = &def_adc_slot;
+		slot->info = info;
+		slot->priority= prio;
+		slot->overlay_id = -1;
+
+	} else {
+		if (uboot_overlaymgr_enabled == 0) {
+			dev_info(dev, "slot #%d: '%s'\n",
+					slotno, slot->text_id);
+
+			ret = vesta_slot_sysfs_register(slot);
+			if (ret != 0) {
+				dev_info(dev, "slot #%d: sysfs register failed\n",
+						slotno);
+				goto err_out;
+			}
+		} else {
+			dev_info(dev, "slot #%d: auto loading handled by U-Boot\n", slotno);
+		}
+
+	}
+
+	/* add to the slot list */
+	mutex_lock(&info->slots_list_mutex);
+	list_add_tail(&slot->node, &info->slot_list);
+	mutex_unlock(&info->slots_list_mutex);
+
+	return slot;
+
+err_out:
+	if (slot->nvmem_cell)
+		nvmem_cell_put(slot->nvmem_cell);
+	devm_kfree(dev, slot);
+	return ERR_PTR(ret);
+}
+
+/* return 1 if it makes sense to retry loading */
+static int retry_loading_condition(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct vesta_slot *slotn;
+	int ret;
+
+	dev_dbg(dev, "loader: retry_loading slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = 0;
+	list_for_each_entry(slotn, &info->slot_list, node) {
+		/* if same slot or not loading skip */
+		if (!slotn->loading || slotn->retry_loading)
+			continue;
+		/* at least one expansion card is still loading (without retrying) */
+		ret = 1;
+	}
+	mutex_unlock(&info->slots_list_mutex);
+	return ret;
+}
+
+/* return 1 if this slot is clear to try to load now */
+static int clear_to_load_condition(struct vesta_slot *slot)
+{
+	struct overlaymgr_info *info = slot->info;
+	int my_prio = slot->priority;
+	struct device *dev = &info->pdev->dev;
+	int ret;
+
+	dev_dbg(dev, "loader: check slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = 1;
+	list_for_each_entry(slot, &info->slot_list, node) {
+		/* if any slot is loading with lowest priority */
+		if (!slot->loading)
+			continue;
+		if (slot->priority < my_prio) {
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&info->slots_list_mutex);
+	return ret;
+}
+
+static void overlaymgr_loader(struct work_struct *work)
+{
+	struct vesta_slot *slot = container_of(work, struct vesta_slot,
+					       loader_work);
+	struct overlaymgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	int ret, done, other_loading, booting;
+
+	done = 0;
+
+	slot->retry_loading = 0;
+
+	dev_info(dev, "loader: before slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/*
+	 * We have a basic priority based arbitration system
+	 * Slots have priorities, so the lower priority ones
+	 * should start loading first. So each time we end up
+	 * here.
+	 */
+	ret = wait_event_interruptible(info->load_wq,
+			clear_to_load_condition(slot));
+	if (ret < 0) {
+		dev_warn(dev, "loader, Signal pending\n");
+		return;
+	}
+
+	dev_info(dev, "loader: after slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/* using the return value */
+	ret = overlaymgr_load_slot(slot);
+
+	/* wake up all just in case */
+	wake_up_interruptible_all(&info->load_wq);
+
+	if (ret == 0)
+		goto done;
+
+	dev_info(dev, "loader: retrying slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/* first attempt has failed; now try each time there's any change */
+	slot->retry_loading = 1;
+
+	for (;;) {
+		booting = (system_state == SYSTEM_BOOTING);
+		other_loading = retry_loading_condition(slot);
+		if (!booting && !other_loading)
+			break;
+
+		/* simple wait for someone to kick us */
+		if (other_loading) {
+			DEFINE_WAIT(__wait);
+
+			prepare_to_wait(&info->load_wq, &__wait,
+					TASK_INTERRUPTIBLE);
+			finish_wait(&info->load_wq, &__wait);
+		} else {
+			/* always delay when booting */
+			msleep(boot_scan_period);
+		}
+
+		if (signal_pending(current)) {
+			dev_warn(dev, "loader, Signal pending\n");
+			ret = -ERESTARTSYS;
+			goto done;
+		}
+
+		/* using the return value */
+		ret = overlaymgr_load_slot(slot);
+		if (ret == 0)
+			goto done;
+
+		/* wake up all just in case */
+		wake_up_interruptible_all(&info->load_wq);
+	}
+
+done:
+	slot->loading = 0;
+	slot->retry_loading = 0;
+
+	if (ret == 0) {
+		dev_info(dev, "loader: done slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+	} else {
+		dev_err(dev, "loader: failed to load slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+
+		/* if it's a override slot remove it */
+		if (slot->override)
+			overlaymgr_remove_slot(slot);
+	}
+}
+
+static int
+overlaymgr_probe(struct platform_device *pdev)
+{
+	struct overlaymgr_info *info;
+	struct vesta_baseboard *bbrd;
+	struct vesta_slot *slot;
+	struct device_node *pnode = pdev->dev.of_node;
+	struct device_node *baseboardmaps_node;
+	struct device_node *node;
+	//const char *part_number;
+	//const char *version;
+	const char *board_name;
+	const char *compatible_name;
+	char slot_name[16];
+	u32 slots_nr;
+	int i, ret;
+	//len, prio;
+	//long val;
+	//char *wbuf, *s, *p, *e;
+
+	if (uboot_overlaymgr_enabled)
+		return 0;
+
+	/* we don't use platform_data at all; we require OF */
+	if (pnode == NULL)
+		return -ENOTSUPP;
+
+	info = devm_kzalloc(&pdev->dev,
+			sizeof(struct overlaymgr_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pdev = pdev;
+	platform_set_drvdata(pdev, info);
+
+	atomic_set(&info->next_slot_nr, 0);
+	INIT_LIST_HEAD(&info->slot_list);
+	mutex_init(&info->slots_list_mutex);
+
+	init_waitqueue_head(&info->load_wq);
+
+	baseboardmaps_node = NULL;
+
+	/* find the baseboard */
+	bbrd = &info->baseboard;
+
+	baseboardmaps_node = of_get_child_by_name(pnode, "baseboardmaps");
+	if (baseboardmaps_node == NULL) {
+		dev_err(&pdev->dev, "Failed to get baseboardmaps node");
+		ret = -ENODEV;
+		goto err_exit;
+	}
+
+/* Vesta Gateways don't have an EEPROM for the main board.  For now,
+ * just use hardcoded data.  In future, we may want to pull this
+ * data from the persistent data area in emmc (that would require
+ * changes to the Gateway manufacturing process, however, to
+ * populate the emmc with the required info). 
+ *
+ */
+
+/*
+  bbrd->nvmem_cell = nvmem_cell_get(&pdev->dev, "baseboard");
+	if (IS_ERR(bbrd->nvmem_cell)) {
+		ret = PTR_ERR(bbrd->nvmem_cell);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to get baseboard eeprom cell\n");
+		bbrd->nvmem_cell = NULL;
+		goto err_exit;
+	}
+
+*/
+	ret = vesta_baseboard_scan(bbrd);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to scan baseboard eeprom\n");
+		goto err_exit;
+	}
+
+	dev_info(&pdev->dev, "Gateway: '%s'\n", bbrd->text_id);
+
+	board_name = NULL;
+	compatible_name = NULL;
+	for_each_child_of_node(baseboardmaps_node, node) {
+		/* there must be board-name */
+		if (of_property_read_string(node, "board-name",
+					&board_name) != 0 ||
+		    of_property_read_string(node, "compatible-name",
+					&compatible_name) != 0)
+			continue;
+
+		if (strcmp(bbrd->board_name, board_name) == 0)
+			break;
+	}
+	of_node_put(baseboardmaps_node);
+	baseboardmaps_node = NULL;
+
+	if (node == NULL) {
+		dev_err(&pdev->dev, "Failed to find compatible map for %s\n",
+				bbrd->board_name);
+		ret = -ENODEV;
+		goto err_exit;
+	}
+	bbrd->compatible_name = kstrdup(compatible_name, GFP_KERNEL);
+	if (bbrd->compatible_name == NULL) {
+		ret = -ENOMEM;
+		goto err_exit;
+	}
+	of_node_put(node);
+
+	/* get number of expansion slots on Gateway baseboard */
+	ret = of_property_read_u32(pnode, "#slots", &slots_nr);
+	if (ret != 0)
+		slots_nr = 0;
+
+	dev_info(&pdev->dev, "compatible-gateway=%s - #slots=%d\n",
+			bbrd->compatible_name, slots_nr);
+
+	/* for each expansion slot, create a slot structure, and scan slot
+		to see if an expansion card is present.  */
+	for (i = 0; i < slots_nr; i++) {
+		snprintf(slot_name, sizeof(slot_name), "slot%d", i);
+		slot = overlaymgr_add_slot(info, slot_name, NULL, NULL, 0);
+		if (IS_ERR(slot)) {
+			dev_err(&pdev->dev, "Failed to add slot #%d\n",
+				atomic_read(&info->next_slot_nr));
+			ret = PTR_ERR(slot);
+			goto err_exit;
+		}
+
+		slot->loader_wq = create_singlethread_workqueue(slot_name);
+		if (!slot->loader_wq) {
+			ret = -ENODEV;
+			goto err_exit;
+		}
+		INIT_WORK(&slot->loader_work, overlaymgr_loader);
+	}
+
+/* The enable partno functionality as designed for beaglebone,
+	whose expansion cards can be stacked on top of one another,
+	does not make sense for vesta, where there will always
+	be a maximum of one card per slot. 
+
+	// iterate over enable_partno (if there) 
+
+	if (enable_partno && strlen(enable_partno) > 0) {
+
+		// allocate a temporary buffer 
+		wbuf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
+		if (wbuf == NULL) {
+			ret = -ENOMEM;
+			goto err_exit;
+		}
+
+		// add any enable_partno expansion cards 
+		s = enable_partno;
+		while (*s) {
+			// form is PART[:REV[:PRIO]],PART.. 
+			p = strchr(s, ',');
+			if (p == NULL)
+				e = s + strlen(s);
+			else
+				e = p;
+
+			// copy to temp buffer
+			len = e - s;
+			if (len >= PAGE_SIZE - 1)
+				len = PAGE_SIZE - 1;
+			memcpy(wbuf, s, len);
+			wbuf[len] = '\0';
+
+			// move to the next 
+			s = *e ? e + 1 : e;
+
+			part_number = wbuf;
+
+			// default version is NULL & prio is 0
+			version = NULL;
+			prio = 0;
+
+			// now split the rev & prio part 
+			p = strchr(wbuf, ':');
+			if (p != NULL) {
+				*p++ = '\0';
+				if (*p != ':')
+					version = p;
+				p = strchr(p, ':');
+				if (p != NULL) {
+					*p++ = '\0';
+					ret = kstrtol(p, 10, &val);
+					if (ret == 0)
+						prio = val;
+				}
+			}
+
+			dev_info(&pdev->dev,
+				"enabled_partno PARTNO '%s' VER '%s' PR '%d'\n",
+					part_number,
+					version ? version : "N/A", prio);
+
+			// only immediate slots are allowed here
+			slot = overlaymgr_add_slot(info, NULL,
+					part_number, version, prio);
+
+			// we continue even in case of an error 
+			if (IS_ERR_OR_NULL(slot)) {
+				dev_warn(&pdev->dev, "Failed to add slot #%d\n",
+					atomic_read(&info->next_slot_nr) - 1);
+			}
+		}
+
+		devm_kfree(&pdev->dev, wbuf);
+	}
+
+*/
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(&pdev->dev, "Failed to pm_runtime_get_sync()\n");
+		goto err_exit;
+	}
+
+	pm_runtime_put(&pdev->dev);
+
+	/* it is safe to create the attribute groups */
+	ret = sysfs_create_groups(&pdev->dev.kobj, attr_groups);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to create sysfs attributes\n");
+		goto err_exit;
+	}
+	/* automatically cleared by driver core now */
+	pdev->dev.groups = attr_groups;
+
+	/* now load each (take lock to be sure */
+	mutex_lock(&info->slots_list_mutex);
+
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		/* if matches the disabled ones skip */
+		if (vesta_match_excard(disable_partno, slot->part_number,
+					slot->version)) {
+			dev_info(&pdev->dev,
+				"Skipping loading of disabled expansion card with part# %s\n",
+				slot->part_number);
+			slot->disabled = 1;
+			continue;
+		}
+
+		if (!slot->probe_failed && !slot->loaded)
+			slot->loading = 1;
+	}
+
+	/* now start the loader thread(s) (all at once) */
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		if (!slot->loading)
+			continue;
+
+		queue_work(slot->loader_wq, &slot->loader_work);
+	}
+	mutex_unlock(&info->slots_list_mutex);
+
+	dev_info(&pdev->dev, "initialized OK.\n");
+
+	return 0;
+
+err_exit:
+	if (bbrd->nvmem_cell)
+		nvmem_cell_put(bbrd->nvmem_cell);
+	of_node_put(baseboardmaps_node);
+	platform_set_drvdata(pdev, NULL);
+	kfree(bbrd->compatible_name);
+	devm_kfree(&pdev->dev, info);
+
+	return ret;
+}
+
+static int overlaymgr_remove(struct platform_device *pdev)
+{
+	struct overlaymgr_info *info = platform_get_drvdata(pdev);
+	struct vesta_baseboard *bbrd = &info->baseboard;
+	struct vesta_slot *slot, *slotn;
+	int ret;
+
+	mutex_lock(&info->slots_list_mutex);
+	list_for_each_entry_safe(slot, slotn, &info->slot_list, node) {
+		flush_workqueue(slot->loader_wq);
+		destroy_workqueue(slot->loader_wq);
+		overlaymgr_remove_slot_no_lock(slot);
+	}
+	mutex_unlock(&info->slots_list_mutex);
+
+	platform_set_drvdata(pdev, NULL);
+
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	if (bbrd->nvmem_cell)
+		nvmem_cell_put(bbrd->nvmem_cell);
+	devm_kfree(&pdev->dev, info);
+
+	return 0;
+}
+
+static struct platform_driver overlaymgr_driver = {
+	.probe		= overlaymgr_probe,
+	.remove		= overlaymgr_remove,
+	.driver		= {
+		.name	= "vesta_overlaymgr",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(overlaymgr_of_match),
+	},
+};
+
+module_platform_driver(overlaymgr_driver);
+
+MODULE_AUTHOR("Pantelis Antoniou");
+MODULE_DESCRIPTION("Vesta Gateway DT overlay manager");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vesta_overlaymgr");
--- linux-ein-5.4.0.orig/drivers/misc/vmw_vmci/vmci_context.c
+++ linux-ein-5.4.0/drivers/misc/vmw_vmci/vmci_context.c
@@ -743,7 +743,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;
 
--- linux-ein-5.4.0.orig/drivers/misc/vmw_vmci/vmci_doorbell.c
+++ linux-ein-5.4.0/drivers/misc/vmw_vmci/vmci_doorbell.c
@@ -326,7 +326,7 @@
 bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn)
 {
 	int result;
-	struct vmci_notify_bm_set_msg bitmap_set_msg;
+	struct vmci_notify_bm_set_msg bitmap_set_msg = { };
 
 	bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
 						  VMCI_SET_NOTIFY_BITMAP);
--- linux-ein-5.4.0.orig/drivers/misc/vmw_vmci/vmci_guest.c
+++ linux-ein-5.4.0/drivers/misc/vmw_vmci/vmci_guest.c
@@ -168,7 +168,7 @@
 				VMCI_UTIL_NUM_RESOURCES * sizeof(u32);
 	struct vmci_datagram *check_msg;
 
-	check_msg = kmalloc(msg_size, GFP_KERNEL);
+	check_msg = kzalloc(msg_size, GFP_KERNEL);
 	if (!check_msg) {
 		dev_err(&pdev->dev, "%s: Insufficient memory\n", __func__);
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/misc/vmw_vmci/vmci_host.c
+++ linux-ein-5.4.0/drivers/misc/vmw_vmci/vmci_host.c
@@ -160,10 +160,16 @@
 static __poll_t vmci_host_poll(struct file *filp, poll_table *wait)
 {
 	struct vmci_host_dev *vmci_host_dev = filp->private_data;
-	struct vmci_ctx *context = vmci_host_dev->context;
+	struct vmci_ctx *context;
 	__poll_t mask = 0;
 
 	if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) {
+		/*
+		 * Read context only if ct_type == VMCIOBJ_CONTEXT to make
+		 * sure that context is initialized
+		 */
+		context = vmci_host_dev->context;
+
 		/* Check for VMCI calls to this VM context. */
 		if (wait)
 			poll_wait(filp, &context->host_context.wait_queue,
--- linux-ein-5.4.0.orig/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ linux-ein-5.4.0/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -537,6 +537,9 @@
 
 	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;
@@ -630,7 +633,7 @@
 
 	for (i = 0; i < num_pages; i++) {
 		if (dirty)
-			set_page_dirty(pages[i]);
+			set_page_dirty_lock(pages[i]);
 
 		put_page(pages[i]);
 		pages[i] = NULL;
@@ -657,8 +660,9 @@
 	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;
 	}
@@ -670,8 +674,9 @@
 	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;
@@ -847,6 +852,7 @@
 	u32 context_id = vmci_get_context_id();
 	struct vmci_event_qp ev;
 
+	memset(&ev, 0, sizeof(ev));
 	ev.msg.hdr.dst = vmci_make_handle(context_id, VMCI_EVENT_HANDLER);
 	ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
 					  VMCI_CONTEXT_RESOURCE_ID);
@@ -1460,6 +1466,7 @@
 	 * kernel.
 	 */
 
+	memset(&ev, 0, sizeof(ev));
 	ev.msg.hdr.dst = vmci_make_handle(peer_id, VMCI_EVENT_HANDLER);
 	ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
 					  VMCI_CONTEXT_RESOURCE_ID);
@@ -2233,7 +2240,8 @@
 
 	result = VMCI_SUCCESS;
 
-	if (context_id != VMCI_HOST_CONTEXT_ID) {
+	if (context_id != VMCI_HOST_CONTEXT_ID &&
+	    !QPBROKERSTATE_HAS_MEM(entry)) {
 		struct vmci_qp_page_store page_store;
 
 		page_store.pages = guest_mem;
@@ -2340,7 +2348,8 @@
 		goto out;
 	}
 
-	if (context_id != VMCI_HOST_CONTEXT_ID) {
+	if (context_id != VMCI_HOST_CONTEXT_ID &&
+	    QPBROKERSTATE_HAS_MEM(entry)) {
 		qp_acquire_queue_mutex(entry->produce_q);
 		result = qp_save_headers(entry);
 		if (result < VMCI_SUCCESS)
--- linux-ein-5.4.0.orig/drivers/misc/xilinx_sdfec.c
+++ linux-ein-5.4.0/drivers/misc/xilinx_sdfec.c
@@ -602,10 +602,10 @@
 			      const u32 depth)
 {
 	u32 reg = 0;
-	u32 res;
-	u32 n, i;
+	int res, i, nr_pages;
+	u32 n;
 	u32 *addr = NULL;
-	struct page *page[MAX_NUM_PAGES];
+	struct page *pages[MAX_NUM_PAGES];
 
 	/*
 	 * Writes that go beyond the length of
@@ -622,15 +622,22 @@
 	if ((len * XSDFEC_REG_WIDTH_JUMP) % PAGE_SIZE)
 		n += 1;
 
-	res = get_user_pages_fast((unsigned long)src_ptr, n, 0, page);
-	if (res < n) {
-		for (i = 0; i < res; i++)
-			put_page(page[i]);
+	if (WARN_ON_ONCE(n > INT_MAX))
+		return -EINVAL;
+
+	nr_pages = n;
+
+	res = get_user_pages_fast((unsigned long)src_ptr, nr_pages, 0, pages);
+	if (res < nr_pages) {
+		if (res > 0) {
+			for (i = 0; i < res; i++)
+				put_page(pages[i]);
+		}
 		return -EINVAL;
 	}
 
-	for (i = 0; i < n; i++) {
-		addr = kmap(page[i]);
+	for (i = 0; i < nr_pages; i++) {
+		addr = kmap(pages[i]);
 		do {
 			xsdfec_regwrite(xsdfec,
 					base_addr + ((offset + reg) *
@@ -639,7 +646,7 @@
 			reg++;
 		} while ((reg < len) &&
 			 ((reg * XSDFEC_REG_WIDTH_JUMP) % PAGE_SIZE));
-		put_page(page[i]);
+		put_page(pages[i]);
 	}
 	return reg;
 }
@@ -1025,25 +1032,25 @@
 }
 #endif
 
-static unsigned int xsdfec_poll(struct file *file, poll_table *wait)
+static __poll_t xsdfec_poll(struct file *file, poll_table *wait)
 {
-	unsigned int mask = 0;
+	__poll_t mask = 0;
 	struct xsdfec_dev *xsdfec;
 
 	xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);
 
 	if (!xsdfec)
-		return POLLNVAL | POLLHUP;
+		return EPOLLNVAL | EPOLLHUP;
 
 	poll_wait(file, &xsdfec->waitq, wait);
 
 	/* XSDFEC ISR detected an error */
 	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
 	if (xsdfec->state_updated)
-		mask |= POLLIN | POLLPRI;
+		mask |= EPOLLIN | EPOLLPRI;
 
 	if (xsdfec->stats_updated)
-		mask |= POLLIN | POLLRDNORM;
+		mask |= EPOLLIN | EPOLLRDNORM;
 	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
 
 	return mask;
--- linux-ein-5.4.0.orig/drivers/mmc/core/block.c
+++ linux-ein-5.4.0/drivers/mmc/core/block.c
@@ -249,6 +249,7 @@
 		goto out_put;
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
+	req_to_mmc_queue_req(req)->drv_op_result = -EIO;
 	blk_execute_rq(mq->queue, NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
@@ -344,6 +345,10 @@
 	struct mmc_ioc_cmd ic;
 	unsigned char *buf;
 	u64 buf_bytes;
+	unsigned int flags;
+#define MMC_BLK_IOC_DROP	BIT(0)	/* drop this mrq */
+#define MMC_BLK_IOC_SBC	BIT(1)	/* use mrq.sbc */
+
 	struct mmc_rpmb_data *rpmb;
 };
 
@@ -408,38 +413,6 @@
 	return 0;
 }
 
-static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
-				       u32 retries_max)
-{
-	int err;
-	u32 retry_count = 0;
-
-	if (!status || !retries_max)
-		return -EINVAL;
-
-	do {
-		err = __mmc_send_status(card, status, 5);
-		if (err)
-			break;
-
-		if (!R1_STATUS(*status) &&
-				(R1_CURRENT_STATE(*status) != R1_STATE_PRG))
-			break; /* RPMB programming operation complete */
-
-		/*
-		 * Rechedule to give the MMC device a chance to continue
-		 * processing the previous command without being polled too
-		 * frequently.
-		 */
-		usleep_range(1000, 5000);
-	} while (++retry_count < retries_max);
-
-	if (retry_count == retries_max)
-		err = -EPERM;
-
-	return err;
-}
-
 static int ioctl_do_sanitize(struct mmc_card *card)
 {
 	int err;
@@ -468,8 +441,60 @@
 	return err;
 }
 
+static inline bool mmc_blk_in_tran_state(u32 status)
+{
+	/*
+	 * Some cards mishandle the status bits, so make sure to check both the
+	 * busy indication and the card state.
+	 */
+	return status & R1_READY_FOR_DATA &&
+	       (R1_CURRENT_STATE(status) == R1_STATE_TRAN);
+}
+
+static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
+			    u32 *resp_errs)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+	int err = 0;
+	u32 status;
+
+	do {
+		bool done = time_after(jiffies, timeout);
+
+		err = __mmc_send_status(card, &status, 5);
+		if (err) {
+			dev_err(mmc_dev(card->host),
+				"error %d requesting status\n", err);
+			return err;
+		}
+
+		/* Accumulate any response error bits seen */
+		if (resp_errs)
+			*resp_errs |= status;
+
+		/*
+		 * Timeout if the device never becomes ready for data and never
+		 * leaves the program state.
+		 */
+		if (done) {
+			dev_err(mmc_dev(card->host),
+				"Card stuck in wrong state! %s status: %#x\n",
+				 __func__, status);
+			return -ETIMEDOUT;
+		}
+
+		/*
+		 * Some cards mishandle the status bits,
+		 * so make sure to check both the busy
+		 * indication and the card state.
+		 */
+	} while (!mmc_blk_in_tran_state(status));
+
+	return err;
+}
+
 static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
-			       struct mmc_blk_ioc_data *idata)
+			       struct mmc_blk_ioc_data **idatas, int i)
 {
 	struct mmc_command cmd = {}, sbc = {};
 	struct mmc_data data = {};
@@ -477,11 +502,18 @@
 	struct scatterlist sg;
 	int err;
 	unsigned int target_part;
-	u32 status = 0;
+	struct mmc_blk_ioc_data *idata = idatas[i];
+	struct mmc_blk_ioc_data *prev_idata = NULL;
 
 	if (!card || !md || !idata)
 		return -EINVAL;
 
+	if (idata->flags & MMC_BLK_IOC_DROP)
+		return 0;
+
+	if (idata->flags & MMC_BLK_IOC_SBC)
+		prev_idata = idatas[i - 1];
+
 	/*
 	 * The RPMB accesses comes in from the character device, so we
 	 * need to target these explicitly. Else we just target the
@@ -548,7 +580,7 @@
 			return err;
 	}
 
-	if (idata->rpmb) {
+	if (idata->rpmb || prev_idata) {
 		sbc.opcode = MMC_SET_BLOCK_COUNT;
 		/*
 		 * We don't do any blockcount validation because the max size
@@ -556,6 +588,8 @@
 		 * 'Reliable Write' bit here.
 		 */
 		sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31));
+		if (prev_idata)
+			sbc.arg = prev_idata->ic.arg;
 		sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
 		mrq.sbc = &sbc;
 	}
@@ -572,6 +606,16 @@
 	}
 
 	mmc_wait_for_req(card->host, &mrq);
+	memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
+
+	if (prev_idata) {
+		memcpy(&prev_idata->ic.response, sbc.resp, sizeof(sbc.resp));
+		if (sbc.error) {
+			dev_err(mmc_dev(card->host), "%s: sbc error %d\n",
+							__func__, sbc.error);
+			return sbc.error;
+		}
+	}
 
 	if (cmd.error) {
 		dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
@@ -603,24 +647,30 @@
 	}
 
 	/*
+	 * Make sure to update CACHE_CTRL in case it was changed. The cache
+	 * will get turned back on if the card is re-initialized, e.g.
+	 * suspend/resume or hw reset in recovery.
+	 */
+	if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_CACHE_CTRL) &&
+	    (cmd.opcode == MMC_SWITCH)) {
+		u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg) & 1;
+
+		card->ext_csd.cache_ctrl = value;
+	}
+
+	/*
 	 * According to the SD specs, some commands require a delay after
 	 * issuing the command.
 	 */
 	if (idata->ic.postsleep_min_us)
 		usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
 
-	memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
-
-	if (idata->rpmb) {
+	if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
 		/*
-		 * Ensure RPMB command has completed by polling CMD13
+		 * Ensure RPMB/R1B command has completed by polling CMD13
 		 * "Send Status".
 		 */
-		err = ioctl_rpmb_card_status_poll(card, &status, 5);
-		if (err)
-			dev_err(mmc_dev(card->host),
-					"%s: Card Status=0x%08X, error %d\n",
-					__func__, status, err);
+		err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, NULL);
 	}
 
 	return err;
@@ -662,6 +712,7 @@
 	idatas[0] = idata;
 	req_to_mmc_queue_req(req)->drv_op =
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
+	req_to_mmc_queue_req(req)->drv_op_result = -EIO;
 	req_to_mmc_queue_req(req)->drv_op_data = idatas;
 	req_to_mmc_queue_req(req)->ioc_count = 1;
 	blk_execute_rq(mq->queue, NULL, req, 0);
@@ -731,6 +782,7 @@
 	}
 	req_to_mmc_queue_req(req)->drv_op =
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
+	req_to_mmc_queue_req(req)->drv_op_result = -EIO;
 	req_to_mmc_queue_req(req)->drv_op_data = idata;
 	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
 	blk_execute_rq(mq->queue, NULL, req, 0);
@@ -821,9 +873,10 @@
 static int mmc_blk_part_switch_pre(struct mmc_card *card,
 				   unsigned int part_type)
 {
+	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB;
 	int ret = 0;
 
-	if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+	if ((part_type & mask) == mask) {
 		if (card->ext_csd.cmdq_en) {
 			ret = mmc_cmdq_disable(card);
 			if (ret)
@@ -838,9 +891,10 @@
 static int mmc_blk_part_switch_post(struct mmc_card *card,
 				    unsigned int part_type)
 {
+	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB;
 	int ret = 0;
 
-	if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+	if ((part_type & mask) == mask) {
 		mmc_retune_unpause(card->host);
 		if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
 			ret = mmc_cmdq_enable(card);
@@ -970,58 +1024,6 @@
 	return ms;
 }
 
-static inline bool mmc_blk_in_tran_state(u32 status)
-{
-	/*
-	 * Some cards mishandle the status bits, so make sure to check both the
-	 * busy indication and the card state.
-	 */
-	return status & R1_READY_FOR_DATA &&
-	       (R1_CURRENT_STATE(status) == R1_STATE_TRAN);
-}
-
-static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
-			    struct request *req, u32 *resp_errs)
-{
-	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-	int err = 0;
-	u32 status;
-
-	do {
-		bool done = time_after(jiffies, timeout);
-
-		err = __mmc_send_status(card, &status, 5);
-		if (err) {
-			pr_err("%s: error %d requesting status\n",
-			       req->rq_disk->disk_name, err);
-			return err;
-		}
-
-		/* Accumulate any response error bits seen */
-		if (resp_errs)
-			*resp_errs |= status;
-
-		/*
-		 * Timeout if the device never becomes ready for data and never
-		 * leaves the program state.
-		 */
-		if (done) {
-			pr_err("%s: Card stuck in wrong state! %s %s status: %#x\n",
-				mmc_hostname(card->host),
-				req->rq_disk->disk_name, __func__, status);
-			return -ETIMEDOUT;
-		}
-
-		/*
-		 * Some cards mishandle the status bits,
-		 * so make sure to check both the busy
-		 * indication and the card state.
-		 */
-	} while (!mmc_blk_in_tran_state(status));
-
-	return err;
-}
-
 static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
 			 int type)
 {
@@ -1056,6 +1058,20 @@
 	md->reset_done &= ~type;
 }
 
+static void mmc_blk_check_sbc(struct mmc_queue_req *mq_rq)
+{
+	struct mmc_blk_ioc_data **idata = mq_rq->drv_op_data;
+	int i;
+
+	for (i = 1; i < mq_rq->ioc_count; i++) {
+		if (idata[i - 1]->ic.opcode == MMC_SET_BLOCK_COUNT &&
+		    mmc_op_multi(idata[i]->ic.opcode)) {
+			idata[i - 1]->flags |= MMC_BLK_IOC_DROP;
+			idata[i]->flags |= MMC_BLK_IOC_SBC;
+		}
+	}
+}
+
 /*
  * The non-block commands come back from the block layer after it queued it and
  * processed it with all other requests and then they get issued in this
@@ -1078,16 +1094,27 @@
 
 	switch (mq_rq->drv_op) {
 	case MMC_DRV_OP_IOCTL:
+		if (card->ext_csd.cmdq_en) {
+			ret = mmc_cmdq_disable(card);
+			if (ret)
+				break;
+		}
+
+		mmc_blk_check_sbc(mq_rq);
+
+		fallthrough;
 	case MMC_DRV_OP_IOCTL_RPMB:
 		idata = mq_rq->drv_op_data;
 		for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
-			ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
+			ret = __mmc_blk_ioctl_cmd(card, md, idata, i);
 			if (ret)
 				break;
 		}
 		/* Always switch back to main area after RPMB access */
 		if (rpmb_ioctl)
 			mmc_blk_part_switch(card, 0);
+		else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
+			mmc_cmdq_enable(card);
 		break;
 	case MMC_DRV_OP_BOOT_WP:
 		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1144,7 +1171,7 @@
 					 card->erase_arg == MMC_TRIM_ARG ?
 					 INAND_CMD38_ARG_TRIM :
 					 INAND_CMD38_ARG_ERASE,
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 		}
 		if (!err)
 			err = mmc_erase(card, from, nr, card->erase_arg);
@@ -1186,7 +1213,7 @@
 				 arg == MMC_SECURE_TRIM1_ARG ?
 				 INAND_CMD38_ARG_SECTRIM1 :
 				 INAND_CMD38_ARG_SECERASE,
-				 0);
+				 card->ext_csd.generic_cmd6_time);
 		if (err)
 			goto out_retry;
 	}
@@ -1204,7 +1231,7 @@
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 INAND_CMD38_ARG_EXT_CSD,
 					 INAND_CMD38_ARG_SECTRIM2,
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 			if (err)
 				goto out_retry;
 		}
@@ -1454,6 +1481,7 @@
 	struct mmc_request *mrq = &mqrq->brq.mrq;
 	struct request_queue *q = req->q;
 	struct mmc_host *host = mq->card->host;
+	enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
 	unsigned long flags;
 	bool put_card;
 	int err;
@@ -1477,13 +1505,15 @@
 			blk_mq_requeue_request(req, true);
 		else
 			__blk_mq_end_request(req, BLK_STS_OK);
+	} else if (mq->in_recovery) {
+		blk_mq_requeue_request(req, true);
 	} else {
 		blk_mq_end_request(req, BLK_STS_OK);
 	}
 
 	spin_lock_irqsave(&mq->lock, flags);
 
-	mq->in_flight[mmc_issue_type(mq, req)] -= 1;
+	mq->in_flight[issue_type] -= 1;
 
 	put_card = (mmc_tot_in_flight(mq) == 0);
 
@@ -1509,8 +1539,7 @@
 	err = mmc_cqe_recovery(host);
 	if (err)
 		mmc_blk_reset(mq->blkdata, host, MMC_BLK_CQE_RECOVERY);
-	else
-		mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
+	mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
 
 	pr_debug("%s: CQE recovery done\n", mmc_hostname(host));
 }
@@ -1529,7 +1558,7 @@
 	 */
 	if (mq->in_recovery)
 		mmc_blk_cqe_complete_rq(mq, req);
-	else
+	else if (likely(!blk_should_fake_timeout(req->q)))
 		blk_mq_complete_request(req);
 }
 
@@ -1671,7 +1700,7 @@
 
 	mmc_blk_send_stop(card, timeout);
 
-	err = card_busy_detect(card, timeout, req, NULL);
+	err = card_busy_detect(card, timeout, NULL);
 
 	mmc_retune_release(card->host);
 
@@ -1688,31 +1717,31 @@
 	struct mmc_card *card = mq->card;
 	struct mmc_host *host = card->host;
 	blk_status_t error = BLK_STS_OK;
-	int retries = 0;
 
 	do {
 		u32 status;
 		int err;
+		int retries = 0;
 
-		mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
+		while (retries++ <= MMC_READ_SINGLE_RETRIES) {
+			mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
 
-		mmc_wait_for_req(host, mrq);
+			mmc_wait_for_req(host, mrq);
 
-		err = mmc_send_status(card, &status);
-		if (err)
-			goto error_exit;
-
-		if (!mmc_host_is_spi(host) &&
-		    !mmc_blk_in_tran_state(status)) {
-			err = mmc_blk_fix_state(card, req);
+			err = mmc_send_status(card, &status);
 			if (err)
 				goto error_exit;
-		}
 
-		if (mrq->cmd->error && retries++ < MMC_READ_SINGLE_RETRIES)
-			continue;
+			if (!mmc_host_is_spi(host) &&
+			    !mmc_blk_in_tran_state(status)) {
+				err = mmc_blk_fix_state(card, req);
+				if (err)
+					goto error_exit;
+			}
 
-		retries = 0;
+			if (!mrq->cmd->error)
+				break;
+		}
 
 		if (mrq->cmd->error ||
 		    mrq->data->error ||
@@ -1895,7 +1924,7 @@
 	if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ)
 		return 0;
 
-	err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, req, &status);
+	err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, &status);
 
 	/*
 	 * Do not assume data transferred correctly if there are any error bits
@@ -1963,7 +1992,7 @@
 
 	if (mq->use_cqe)
 		mmc_blk_cqe_complete_rq(mq, req);
-	else
+	else if (likely(!blk_should_fake_timeout(req->q)))
 		mmc_blk_mq_complete_rq(mq, req);
 }
 
@@ -1984,14 +2013,14 @@
 	mmc_blk_urgent_bkops(mq, mqrq);
 }
 
-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type)
 {
 	unsigned long flags;
 	bool put_card;
 
 	spin_lock_irqsave(&mq->lock, flags);
 
-	mq->in_flight[mmc_issue_type(mq, req)] -= 1;
+	mq->in_flight[issue_type] -= 1;
 
 	put_card = (mmc_tot_in_flight(mq) == 0);
 
@@ -2003,6 +2032,7 @@
 
 static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req)
 {
+	enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
 	struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
 	struct mmc_request *mrq = &mqrq->brq.mrq;
 	struct mmc_host *host = mq->card->host;
@@ -2015,10 +2045,10 @@
 	 */
 	if (mq->in_recovery)
 		mmc_blk_mq_complete_rq(mq, req);
-	else
+	else if (likely(!blk_should_fake_timeout(req->q)))
 		blk_mq_complete_request(req);
 
-	mmc_blk_mq_dec_in_flight(mq, req);
+	mmc_blk_mq_dec_in_flight(mq, issue_type);
 }
 
 void mmc_blk_mq_recovery(struct mmc_queue *mq)
@@ -2251,6 +2281,10 @@
 	case MMC_ISSUE_ASYNC:
 		switch (req_op(req)) {
 		case REQ_OP_FLUSH:
+			if (!mmc_cache_enabled(host)) {
+				blk_mq_end_request(req, BLK_STS_OK);
+				return MMC_REQ_FINISHED;
+			}
 			ret = mmc_blk_cqe_issue_flush(mq, req);
 			break;
 		case REQ_OP_READ:
@@ -2511,8 +2545,8 @@
 	struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
 						  struct mmc_rpmb_data, chrdev);
 
-	put_device(&rpmb->dev);
 	mmc_blk_put(rpmb->md);
+	put_device(&rpmb->dev);
 
 	return 0;
 }
@@ -2752,6 +2786,7 @@
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
+	req_to_mmc_queue_req(req)->drv_op_result = -EIO;
 	blk_execute_rq(mq->queue, NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	if (ret >= 0) {
@@ -2790,6 +2825,7 @@
 		goto out_free;
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
+	req_to_mmc_queue_req(req)->drv_op_result = -EIO;
 	req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
 	blk_execute_rq(mq->queue, NULL, req, 0);
 	err = req_to_mmc_queue_req(req)->drv_op_result;
@@ -3097,4 +3133,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
--- linux-ein-5.4.0.orig/drivers/mmc/core/bus.c
+++ linux-ein-5.4.0/drivers/mmc/core/bus.c
@@ -373,11 +373,6 @@
 	mmc_remove_card_debugfs(card);
 #endif
 
-	if (host->cqe_enabled) {
-		host->cqe_ops->cqe_disable(host);
-		host->cqe_enabled = false;
-	}
-
 	if (mmc_card_present(card)) {
 		if (mmc_host_is_spi(card->host)) {
 			pr_info("%s: SPI card removed\n",
@@ -390,6 +385,10 @@
 		of_node_put(card->dev.of_node);
 	}
 
+	if (host->cqe_enabled) {
+		host->cqe_ops->cqe_disable(host);
+		host->cqe_enabled = false;
+	}
+
 	put_device(&card->dev);
 }
-
--- linux-ein-5.4.0.orig/drivers/mmc/core/core.c
+++ linux-ein-5.4.0/drivers/mmc/core/core.c
@@ -52,6 +52,8 @@
 
 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
+static int __mmc_max_reserved_idx = -1;
+
 /*
  * Enabling software CRCs on the data blocks can be a significant (30%)
  * performance cost, and for other reasons may not always be desired.
@@ -564,22 +566,27 @@
 	host->cqe_ops->cqe_recovery_start(host);
 
 	memset(&cmd, 0, sizeof(cmd));
-	cmd.opcode       = MMC_STOP_TRANSMISSION,
-	cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC,
+	cmd.opcode       = MMC_STOP_TRANSMISSION;
+	cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC;
 	cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
-	cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
-	mmc_wait_for_cmd(host, &cmd, 0);
+	cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+	mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+
+	mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, true);
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.opcode       = MMC_CMDQ_TASK_MGMT;
 	cmd.arg          = 1; /* Discard entire queue */
 	cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC;
 	cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
-	cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
-	err = mmc_wait_for_cmd(host, &cmd, 0);
+	cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 
 	host->cqe_ops->cqe_recovery_finish(host);
 
+	if (err)
+		err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+
 	mmc_retune_release(host);
 
 	return err;
@@ -953,11 +960,14 @@
 
 	err = host->ops->execute_tuning(host, opcode);
 
-	if (err)
+	if (err) {
 		pr_err("%s: tuning execution failed: %d\n",
 			mmc_hostname(host), err);
-	else
+	} else {
+		host->retune_now = 0;
+		host->need_retune = 0;
 		mmc_retune_enable(host);
+	}
 
 	return err;
 }
@@ -1142,7 +1152,13 @@
 		mmc_power_cycle(host, ocr);
 	} else {
 		bit = fls(ocr) - 1;
-		ocr &= 3 << bit;
+		/*
+		 * The bit variable represents the highest voltage bit set in
+		 * the OCR register.
+		 * To keep a range of 2 values (e.g. 3.2V/3.3V and 3.3V/3.4V),
+		 * we must shift the mask '3' with (bit - 1).
+		 */
+		ocr &= 3 << (bit - 1);
 		if (bit != host->ios.vdd)
 			dev_warn(mmc_dev(host), "exceeding card's volts\n");
 	}
@@ -1221,7 +1237,7 @@
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
-		return err;
+		goto power_cycle;
 
 	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
 		return -EIO;
@@ -1469,8 +1485,7 @@
 	mmc_bus_put(host);
 }
 
-static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
-				bool cd_irq)
+void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
 {
 	/*
 	 * If the device is configured as wakeup, we prevent a new sleep for
@@ -1548,6 +1563,11 @@
 		card->pref_erase = 0;
 }
 
+static bool is_trim_arg(unsigned int arg)
+{
+	return (arg & MMC_TRIM_OR_DISCARD_ARGS) && arg != MMC_DISCARD_ARG;
+}
+
 static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
 				          unsigned int arg, unsigned int qty)
 {
@@ -1733,8 +1753,11 @@
 	 * the erase operation does not exceed the max_busy_timeout, we should
 	 * use R1B response. Or we need to prevent the host from doing hw busy
 	 * detection, which is done by converting to a R1 response instead.
+	 * Note, some hosts requires R1B, which also means they are on their own
+	 * when it comes to deal with the busy timeout.
 	 */
-	if (card->host->max_busy_timeout &&
+	if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
+	    card->host->max_busy_timeout &&
 	    busy_timeout > card->host->max_busy_timeout) {
 		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	} else {
@@ -1876,7 +1899,7 @@
 	    !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
 		return -EOPNOTSUPP;
 
-	if (mmc_card_mmc(card) && (arg & MMC_TRIM_ARGS) &&
+	if (mmc_card_mmc(card) && is_trim_arg(arg) &&
 	    !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
 		return -EOPNOTSUPP;
 
@@ -1906,7 +1929,7 @@
 	 * identified by the card->eg_boundary flag.
 	 */
 	rem = card->erase_size - (from % card->erase_size);
-	if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
+	if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) {
 		err = mmc_do_erase(card, from, from + rem - 1, arg);
 		from += rem;
 		if ((err) || (to <= from))
@@ -2129,7 +2152,7 @@
 	ret = host->bus_ops->hw_reset(host);
 	mmc_bus_put(host);
 
-	if (ret)
+	if (ret < 0)
 		pr_warn("%s: tried to HW reset card, got error %d\n",
 			mmc_hostname(host), ret);
 
@@ -2297,11 +2320,8 @@
 
 	mmc_bus_get(host);
 
-	/*
-	 * if there is a _removable_ card registered, check whether it is
-	 * still present
-	 */
-	if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host))
+	/* Verify a registered card to be functional, else remove it. */
+	if (host->bus_ops && !host->bus_dead)
 		host->bus_ops->detect(host);
 
 	host->detect_change = 0;
@@ -2362,7 +2382,7 @@
 	_mmc_detect_change(host, 0, false);
 }
 
-void mmc_stop_host(struct mmc_host *host)
+void __mmc_stop_host(struct mmc_host *host)
 {
 	if (host->slot.cd_irq >= 0) {
 		mmc_gpio_set_cd_wake(host, false);
@@ -2371,6 +2391,11 @@
 
 	host->rescan_disable = 1;
 	cancel_delayed_work_sync(&host->detect);
+}
+
+void mmc_stop_host(struct mmc_host *host)
+{
+	__mmc_stop_host(host);
 
 	/* clear pm flags now and let card drivers set them as needed */
 	host->pm_flags = 0;
@@ -2393,84 +2418,46 @@
 	mmc_release_host(host);
 }
 
-#ifdef CONFIG_PM_SLEEP
-/* Do the card removal on suspend if card is assumed removeable
- * Do that in pm notifier while userspace isn't yet frozen, so we will be able
-   to sync the card.
-*/
-static int mmc_pm_notify(struct notifier_block *notify_block,
-			unsigned long mode, void *unused)
+/*
+ * mmc_first_nonreserved_index() - get the first index that
+ * is not reserved
+ */
+int mmc_first_nonreserved_index(void)
 {
-	struct mmc_host *host = container_of(
-		notify_block, struct mmc_host, pm_notify);
-	unsigned long flags;
-	int err = 0;
-
-	switch (mode) {
-	case PM_HIBERNATION_PREPARE:
-	case PM_SUSPEND_PREPARE:
-	case PM_RESTORE_PREPARE:
-		spin_lock_irqsave(&host->lock, flags);
-		host->rescan_disable = 1;
-		spin_unlock_irqrestore(&host->lock, flags);
-		cancel_delayed_work_sync(&host->detect);
-
-		if (!host->bus_ops)
-			break;
-
-		/* Validate prerequisites for suspend */
-		if (host->bus_ops->pre_suspend)
-			err = host->bus_ops->pre_suspend(host);
-		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);
-		mmc_detach_bus(host);
-		mmc_power_off(host);
-		mmc_release_host(host);
-		host->pm_flags = 0;
-		break;
-
-	case PM_POST_SUSPEND:
-	case PM_POST_HIBERNATION:
-	case PM_POST_RESTORE:
-
-		spin_lock_irqsave(&host->lock, flags);
-		host->rescan_disable = 0;
-		spin_unlock_irqrestore(&host->lock, flags);
-		_mmc_detect_change(host, 0, false);
-
-	}
-
-	return 0;
+	return __mmc_max_reserved_idx + 1;
 }
+EXPORT_SYMBOL(mmc_first_nonreserved_index);
 
-void mmc_register_pm_notifier(struct mmc_host *host)
+/*
+ * mmc_get_reserved_index() - get the index reserved for this host
+ * Return: The index reserved for this host or negative error value
+ *        if no index is reserved for this host
+ */
+int mmc_get_reserved_index(struct mmc_host *host)
 {
-	host->pm_notify.notifier_call = mmc_pm_notify;
-	register_pm_notifier(&host->pm_notify);
+	return of_alias_get_id(host->parent->of_node, "mmc");
 }
+EXPORT_SYMBOL(mmc_get_reserved_index);
 
-void mmc_unregister_pm_notifier(struct mmc_host *host)
+static void mmc_of_reserve_idx(void)
 {
-	unregister_pm_notifier(&host->pm_notify);
+	int max;
+
+	max = of_alias_max_index("mmc");
+	if (max < 0)
+		return;
+
+	__mmc_max_reserved_idx = max;
+	pr_debug("MMC: reserving %d slots for of aliases\n",
+			__mmc_max_reserved_idx + 1);
 }
-#endif
 
 static int __init mmc_init(void)
 {
 	int ret;
 
+	mmc_of_reserve_idx();
+
 	ret = mmc_register_bus();
 	if (ret)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/mmc/core/core.h
+++ linux-ein-5.4.0/drivers/mmc/core/core.h
@@ -29,6 +29,7 @@
 	int (*shutdown)(struct mmc_host *);
 	int (*hw_reset)(struct mmc_host *);
 	int (*sw_reset)(struct mmc_host *);
+	bool (*cache_enabled)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -68,15 +69,19 @@
 
 void mmc_rescan(struct work_struct *work);
 void mmc_start_host(struct mmc_host *host);
+void __mmc_stop_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
+			bool cd_irq);
 int _mmc_detect_card_removed(struct mmc_host *host);
 int mmc_detect_card_removed(struct mmc_host *host);
 
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
-
+int mmc_first_nonreserved_index(void);
+int mmc_get_reserved_index(struct mmc_host *host);
 /* Module parameters */
 extern bool use_spi_crc;
 
@@ -91,14 +96,6 @@
 int mmc_hs200_to_hs400(struct mmc_card *card);
 int mmc_hs400_to_hs200(struct mmc_card *card);
 
-#ifdef CONFIG_PM_SLEEP
-void mmc_register_pm_notifier(struct mmc_host *host);
-void mmc_unregister_pm_notifier(struct mmc_host *host);
-#else
-static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
-static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
-#endif
-
 void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
 bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
 
@@ -169,4 +166,12 @@
 		host->ops->post_req(host, mrq, err);
 }
 
+static inline bool mmc_cache_enabled(struct mmc_host *host)
+{
+	if (host->bus_ops->cache_enabled)
+		return host->bus_ops->cache_enabled(host);
+
+	return false;
+}
+
 #endif
--- linux-ein-5.4.0.orig/drivers/mmc/core/host.c
+++ linux-ein-5.4.0/drivers/mmc/core/host.c
@@ -33,6 +33,42 @@
 
 static DEFINE_IDA(mmc_host_ida);
 
+#ifdef CONFIG_PM_SLEEP
+static int mmc_host_class_prepare(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	/*
+	 * It's safe to access the bus_ops pointer, as both userspace and the
+	 * workqueue for detecting cards are frozen at this point.
+	 */
+	if (!host->bus_ops)
+		return 0;
+
+	/* Validate conditions for system suspend. */
+	if (host->bus_ops->pre_suspend)
+		return host->bus_ops->pre_suspend(host);
+
+	return 0;
+}
+
+static void mmc_host_class_complete(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	_mmc_detect_change(host, 0, false);
+}
+
+static const struct dev_pm_ops mmc_host_class_dev_pm_ops = {
+	.prepare = mmc_host_class_prepare,
+	.complete = mmc_host_class_complete,
+};
+
+#define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops)
+#else
+#define MMC_HOST_CLASS_DEV_PM_OPS NULL
+#endif
+
 static void mmc_host_classdev_release(struct device *dev)
 {
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
@@ -40,9 +76,19 @@
 	kfree(host);
 }
 
+static int mmc_host_classdev_shutdown(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	__mmc_stop_host(host);
+	return 0;
+}
+
 static struct class mmc_host_class = {
 	.name		= "mmc_host",
 	.dev_release	= mmc_host_classdev_release,
+	.shutdown_pre	= mmc_host_classdev_shutdown,
+	.pm		= MMC_HOST_CLASS_DEV_PM_OPS,
 };
 
 int mmc_register_host_class(void)
@@ -176,7 +222,6 @@
 	u32 bus_width, drv_type, cd_debounce_delay_ms;
 	int ret;
 	bool cd_cap_invert, cd_gpio_invert = false;
-	bool ro_cap_invert, ro_gpio_invert = false;
 
 	if (!dev || !dev_fwnode(dev))
 		return 0;
@@ -255,9 +300,11 @@
 	}
 
 	/* Parse Write Protection */
-	ro_cap_invert = device_property_read_bool(dev, "wp-inverted");
 
-	ret = mmc_gpiod_request_ro(host, "wp", 0, 0, &ro_gpio_invert);
+	if (device_property_read_bool(dev, "wp-inverted"))
+		host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+
+	ret = mmc_gpiod_request_ro(host, "wp", 0, 0, NULL);
 	if (!ret)
 		dev_info(host->parent, "Got WP GPIO\n");
 	else if (ret != -ENOENT && ret != -ENOSYS)
@@ -266,10 +313,6 @@
 	if (device_property_read_bool(dev, "disable-wp"))
 		host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
 
-	/* See the comment on CD inversion above */
-	if (ro_cap_invert ^ ro_gpio_invert)
-		host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-
 	if (device_property_read_bool(dev, "cap-sd-highspeed"))
 		host->caps |= MMC_CAP_SD_HIGHSPEED;
 	if (device_property_read_bool(dev, "cap-mmc-highspeed"))
@@ -399,6 +442,7 @@
 struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 {
 	int err;
+	int alias_id;
 	struct mmc_host *host;
 
 	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
@@ -407,8 +451,16 @@
 
 	/* scanning will be enabled when we're ready */
 	host->rescan_disable = 1;
+	host->parent = dev;
 
-	err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL);
+	alias_id = mmc_get_reserved_index(host);
+	if (alias_id >= 0)
+		err = ida_simple_get(&mmc_host_ida, alias_id,
+				alias_id + 1, GFP_KERNEL);
+	else
+		err = ida_simple_get(&mmc_host_ida,
+					mmc_first_nonreserved_index(),
+					0, GFP_KERNEL);
 	if (err < 0) {
 		kfree(host);
 		return NULL;
@@ -418,7 +470,6 @@
 
 	dev_set_name(&host->class_dev, "mmc%d", host->index);
 
-	host->parent = dev;
 	host->class_dev.parent = dev;
 	host->class_dev.class = &mmc_host_class;
 	device_initialize(&host->class_dev);
@@ -454,6 +505,16 @@
 
 EXPORT_SYMBOL(mmc_alloc_host);
 
+static int mmc_validate_host_caps(struct mmc_host *host)
+{
+	if (host->caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) {
+		dev_warn(host->parent, "missing ->enable_sdio_irq() ops\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  *	mmc_add_host - initialise host hardware
  *	@host: mmc host
@@ -466,8 +527,9 @@
 {
 	int err;
 
-	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
-		!host->ops->enable_sdio_irq);
+	err = mmc_validate_host_caps(host);
+	if (err)
+		return err;
 
 	err = device_add(&host->class_dev);
 	if (err)
@@ -480,8 +542,6 @@
 #endif
 
 	mmc_start_host(host);
-	mmc_register_pm_notifier(host);
-
 	return 0;
 }
 
@@ -497,7 +557,6 @@
  */
 void mmc_remove_host(struct mmc_host *host)
 {
-	mmc_unregister_pm_notifier(host);
 	mmc_stop_host(host);
 
 #ifdef CONFIG_DEBUG_FS
@@ -519,6 +578,7 @@
  */
 void mmc_free_host(struct mmc_host *host)
 {
+	cancel_delayed_work_sync(&host->detect);
 	mmc_pwrseq_free(host);
 	put_device(&host->class_dev);
 }
--- linux-ein-5.4.0.orig/drivers/mmc/core/mmc.c
+++ linux-ein-5.4.0/drivers/mmc/core/mmc.c
@@ -297,7 +297,7 @@
 	}
 }
 
-static void mmc_part_add(struct mmc_card *card, unsigned int size,
+static void mmc_part_add(struct mmc_card *card, u64 size,
 			 unsigned int part_cfg, char *name, int idx, bool ro,
 			 int area_type)
 {
@@ -313,7 +313,7 @@
 {
 	int idx;
 	u8 hc_erase_grp_sz, hc_wp_grp_sz;
-	unsigned int part_size;
+	u64 part_size;
 
 	/*
 	 * General purpose partition feature support --
@@ -343,8 +343,7 @@
 				(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
 				<< 8) +
 				ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
-			part_size *= (size_t)(hc_erase_grp_sz *
-				hc_wp_grp_sz);
+			part_size *= (hc_erase_grp_sz * hc_wp_grp_sz);
 			mmc_part_add(card, part_size << 19,
 				EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
 				"gp%d", idx, false,
@@ -362,7 +361,7 @@
 static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 {
 	int err = 0, idx;
-	unsigned int part_size;
+	u64 part_size;
 	struct device_node *np;
 	bool broken_hpi = false;
 
@@ -424,10 +423,6 @@
 
 		/* EXT_CSD value is in units of 10ms, but we store in ms */
 		card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
-		/* Some eMMC set the value too low so set a minimum */
-		if (card->ext_csd.part_time &&
-		    card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
-			card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
 
 		/* Sleep / awake timeout in 100ns units */
 		if (sa_shift > 0 && sa_shift <= 0x17)
@@ -617,6 +612,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],
@@ -985,10 +991,12 @@
 	static unsigned ext_csd_bits[] = {
 		EXT_CSD_BUS_WIDTH_8,
 		EXT_CSD_BUS_WIDTH_4,
+		EXT_CSD_BUS_WIDTH_1,
 	};
 	static unsigned bus_widths[] = {
 		MMC_BUS_WIDTH_8,
 		MMC_BUS_WIDTH_4,
+		MMC_BUS_WIDTH_1,
 	};
 	struct mmc_host *host = card->host;
 	unsigned idx, bus_width = 0;
@@ -1911,9 +1919,12 @@
 	 * If the max_busy_timeout of the host is specified, validate it against
 	 * the sleep cmd timeout. A failure means we need to prevent the host
 	 * from doing hw busy detection, which is done by converting to a R1
-	 * response instead of a R1B.
+	 * response instead of a R1B. Note, some hosts requires R1B, which also
+	 * means they are on their own when it comes to deal with the busy
+	 * timeout.
 	 */
-	if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
+	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+	    (timeout_ms > host->max_busy_timeout)) {
 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 	} else {
 		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
@@ -2010,6 +2021,12 @@
 	}
 }
 
+static bool _mmc_cache_enabled(struct mmc_host *host)
+{
+	return host->card->ext_csd.cache_size > 0 &&
+	       host->card->ext_csd.cache_ctrl & 1;
+}
+
 static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
 	int err = 0;
@@ -2188,6 +2205,7 @@
 	.alive = mmc_alive,
 	.shutdown = mmc_shutdown,
 	.hw_reset = _mmc_hw_reset,
+	.cache_enabled = _mmc_cache_enabled,
 };
 
 /*
--- linux-ein-5.4.0.orig/drivers/mmc/core/mmc_ops.c
+++ linux-ein-5.4.0/drivers/mmc/core/mmc_ops.c
@@ -19,7 +19,9 @@
 #include "host.h"
 #include "mmc_ops.h"
 
-#define MMC_OPS_TIMEOUT_MS	(10 * 60 * 1000) /* 10 minute timeout */
+#define MMC_OPS_TIMEOUT_MS		(10 * 60 * 1000) /* 10min*/
+#define MMC_BKOPS_TIMEOUT_MS		(120 * 1000) /* 120s */
+#define MMC_CACHE_FLUSH_TIMEOUT_MS	(30 * 1000) /* 30s */
 
 static const u8 tuning_blk_pattern_4bit[] = {
 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
@@ -448,8 +450,8 @@
 	return __mmc_switch_status(card, true);
 }
 
-static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-			bool send_status, bool retry_crc_err)
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+		      bool send_status, bool retry_crc_err)
 {
 	struct mmc_host *host = card->host;
 	int err;
@@ -458,10 +460,6 @@
 	bool expired = false;
 	bool busy = false;
 
-	/* We have an unspecified cmd timeout, use the fallback value. */
-	if (!timeout_ms)
-		timeout_ms = MMC_OPS_TIMEOUT_MS;
-
 	/*
 	 * In cases when not allowed to poll by using CMD13 or because we aren't
 	 * capable of polling by using ->card_busy(), then rely on waiting the
@@ -506,6 +504,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
 
 /**
  *	__mmc_switch - modify EXT_CSD register
@@ -534,14 +533,22 @@
 
 	mmc_retune_hold(host);
 
+	if (!timeout_ms) {
+		pr_warn("%s: unspecified timeout for CMD6 - use generic\n",
+			mmc_hostname(host));
+		timeout_ms = card->ext_csd.generic_cmd6_time;
+	}
+
 	/*
 	 * If the cmd timeout and the max_busy_timeout of the host are both
 	 * specified, let's validate them. A failure means we need to prevent
 	 * the host from doing hw busy detection, which is done by converting
-	 * to a R1 response instead of a R1B.
+	 * to a R1 response instead of a R1B. Note, some hosts requires R1B,
+	 * which also means they are on their own when it comes to deal with the
+	 * busy timeout.
 	 */
-	if (timeout_ms && host->max_busy_timeout &&
-		(timeout_ms > host->max_busy_timeout))
+	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) &&
+	    host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
 		use_r1b_resp = false;
 
 	cmd.opcode = MMC_SWITCH;
@@ -552,10 +559,6 @@
 	cmd.flags = MMC_CMD_AC;
 	if (use_r1b_resp) {
 		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
-		/*
-		 * A busy_timeout of zero means the host can decide to use
-		 * whatever value it finds suitable.
-		 */
 		cmd.busy_timeout = timeout_ms;
 	} else {
 		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
@@ -941,7 +944,7 @@
 	 * urgent levels by using an asynchronous background task, when idle.
 	 */
 	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_BKOPS_START, 1, MMC_OPS_TIMEOUT_MS);
+			 EXT_CSD_BKOPS_START, 1, MMC_BKOPS_TIMEOUT_MS);
 	if (err)
 		pr_warn("%s: Error %d starting bkops\n",
 			mmc_hostname(card->host), err);
@@ -957,11 +960,10 @@
 {
 	int err = 0;
 
-	if (mmc_card_mmc(card) &&
-			(card->ext_csd.cache_size > 0) &&
-			(card->ext_csd.cache_ctrl & 1)) {
+	if (mmc_cache_enabled(card->host)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_FLUSH_CACHE, 1, 0);
+				 EXT_CSD_FLUSH_CACHE, 1,
+				 MMC_CACHE_FLUSH_TIMEOUT_MS);
 		if (err)
 			pr_err("%s: cache flush error %d\n",
 					mmc_hostname(card->host), err);
--- linux-ein-5.4.0.orig/drivers/mmc/core/mmc_ops.h
+++ linux-ein-5.4.0/drivers/mmc/core/mmc_ops.h
@@ -31,6 +31,8 @@
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card);
 int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+		      bool send_status, bool retry_crc_err);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		unsigned int timeout_ms, unsigned char timing,
 		bool use_busy_signal, bool send_status,	bool retry_crc_err);
--- linux-ein-5.4.0.orig/drivers/mmc/core/mmc_test.c
+++ linux-ein-5.4.0/drivers/mmc/core/mmc_test.c
@@ -3167,7 +3167,8 @@
 	struct mmc_test_dbgfs_file *df;
 
 	if (card->debugfs_root)
-		debugfs_create_file(name, mode, card->debugfs_root, card, fops);
+		file = debugfs_create_file(name, mode, card->debugfs_root,
+					   card, fops);
 
 	df = kmalloc(sizeof(*df), GFP_KERNEL);
 	if (!df) {
--- linux-ein-5.4.0.orig/drivers/mmc/core/queue.c
+++ linux-ein-5.4.0/drivers/mmc/core/queue.c
@@ -107,11 +107,10 @@
 	case MMC_ISSUE_DCMD:
 		if (host->cqe_ops->cqe_timeout(host, mrq, &recovery_needed)) {
 			if (recovery_needed)
-				__mmc_cqe_recovery_notifier(mq);
+				mmc_cqe_recovery_notifier(mrq);
 			return BLK_EH_RESET_TIMER;
 		}
-		/* No timeout (XXX: huh? comment doesn't make much sense) */
-		blk_mq_complete_request(req);
+		/* The request has gone already */
 		return BLK_EH_DONE;
 	default:
 		/* Timeout is handled by mmc core */
@@ -125,18 +124,13 @@
 	struct request_queue *q = req->q;
 	struct mmc_queue *mq = q->queuedata;
 	unsigned long flags;
-	int ret;
+	bool ignore_tout;
 
 	spin_lock_irqsave(&mq->lock, flags);
-
-	if (mq->recovery_needed || !mq->use_cqe)
-		ret = BLK_EH_RESET_TIMER;
-	else
-		ret = mmc_cqe_timed_out(req);
-
+	ignore_tout = mq->recovery_needed || !mq->use_cqe;
 	spin_unlock_irqrestore(&mq->lock, flags);
 
-	return ret;
+	return ignore_tout ? BLK_EH_RESET_TIMER : mmc_cqe_timed_out(req);
 }
 
 static void mmc_mq_recovery_handler(struct work_struct *work)
@@ -190,7 +184,7 @@
 	q->limits.discard_granularity = card->pref_erase << 9;
 	/* granularity must not be greater than max. discard */
 	if (card->pref_erase > max_discard)
-		q->limits.discard_granularity = 0;
+		q->limits.discard_granularity = SECTOR_SIZE;
 	if (mmc_can_secure_erase_trim(card))
 		blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
 }
@@ -376,8 +370,10 @@
 		     "merging was advertised but not possible");
 	blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
 
-	if (mmc_card_mmc(card))
+	if (mmc_card_mmc(card) && card->ext_csd.data_sector_size) {
 		block_size = card->ext_csd.data_sector_size;
+		WARN_ON(block_size != 512 && block_size != 4096);
+	}
 
 	blk_queue_logical_block_size(mq->queue, block_size);
 	/*
--- linux-ein-5.4.0.orig/drivers/mmc/core/quirks.h
+++ linux-ein-5.4.0/drivers/mmc/core/quirks.h
@@ -91,6 +91,20 @@
 		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
 
 	/*
+	 * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
+	 * support being used to offload WRITE_ZEROES.
+	 */
+	MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
+		  MMC_QUIRK_TRIM_BROKEN),
+
+	/*
+	 * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
+	 * support being used to offload WRITE_ZEROES.
+	 */
+	MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
+		  MMC_QUIRK_TRIM_BROKEN),
+
+	/*
 	 *  On Some Kingston eMMCs, performing trim can result in
 	 *  unrecoverable data conrruption occasionally due to a firmware bug.
 	 */
@@ -119,7 +133,14 @@
 	END_FIXUP
 };
 
+
 static const struct mmc_fixup sdio_fixup_methods[] = {
+	SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
+		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+	SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
+		   add_quirk, MMC_QUIRK_DISABLE_CD),
+
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
--- linux-ein-5.4.0.orig/drivers/mmc/core/regulator.c
+++ linux-ein-5.4.0/drivers/mmc/core/regulator.c
@@ -258,3 +258,44 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
+
+/**
+ * mmc_regulator_enable_vqmmc - enable VQMMC regulator for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. Enables the regulator for vqmmc.
+ * Keeps track of the enable status for ensuring that calls to
+ * regulator_enable/disable are balanced.
+ */
+int mmc_regulator_enable_vqmmc(struct mmc_host *mmc)
+{
+	int ret = 0;
+
+	if (!IS_ERR(mmc->supply.vqmmc) && !mmc->vqmmc_enabled) {
+		ret = regulator_enable(mmc->supply.vqmmc);
+		if (ret < 0)
+			dev_err(mmc_dev(mmc), "enabling vqmmc regulator failed\n");
+		else
+			mmc->vqmmc_enabled = true;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_enable_vqmmc);
+
+/**
+ * mmc_regulator_disable_vqmmc - disable VQMMC regulator for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. Disables the regulator for vqmmc.
+ * Keeps track of the enable status for ensuring that calls to
+ * regulator_enable/disable are balanced.
+ */
+void mmc_regulator_disable_vqmmc(struct mmc_host *mmc)
+{
+	if (!IS_ERR(mmc->supply.vqmmc) && mmc->vqmmc_enabled) {
+		regulator_disable(mmc->supply.vqmmc);
+		mmc->vqmmc_enabled = false;
+	}
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_disable_vqmmc);
--- linux-ein-5.4.0.orig/drivers/mmc/core/sd.c
+++ linux-ein-5.4.0/drivers/mmc/core/sd.c
@@ -135,6 +135,9 @@
 			csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
 			csd->erase_size <<= csd->write_blkbits - 9;
 		}
+
+		if (UNSTUFF_BITS(resp, 13, 1))
+			mmc_card_set_readonly(card);
 		break;
 	case 1:
 		/*
@@ -169,6 +172,9 @@
 		csd->write_blkbits = 9;
 		csd->write_partial = 0;
 		csd->erase_size = 1;
+
+		if (UNSTUFF_BITS(resp, 13, 1))
+			mmc_card_set_readonly(card);
 		break;
 	default:
 		pr_err("%s: unrecognised CSD structure version %d\n",
@@ -787,11 +793,14 @@
 		return err;
 
 	/*
-	 * In case CCS and S18A in the response is set, start Signal Voltage
-	 * Switch procedure. SPI mode doesn't support CMD11.
+	 * In case the S18A bit is set in the response, let's start the signal
+	 * voltage switch procedure. SPI mode doesn't support CMD11.
+	 * Note that, according to the spec, the S18A bit is not valid unless
+	 * the CCS bit is set as well. We deliberately deviate from the spec in
+	 * regards to this, which allows UHS-I to be supported for SDSC cards.
 	 */
-	if (!mmc_host_is_spi(host) && rocr &&
-	   ((*rocr & 0x41000000) == 0x41000000)) {
+	if (!mmc_host_is_spi(host) && (ocr & SD_OCR_S18R) &&
+	    rocr && (*rocr & SD_ROCR_S18A)) {
 		err = mmc_set_uhs_voltage(host, pocr);
 		if (err == -EAGAIN) {
 			retries--;
--- linux-ein-5.4.0.orig/drivers/mmc/core/sdio.c
+++ linux-ein-5.4.0/drivers/mmc/core/sdio.c
@@ -584,7 +584,7 @@
 	 */
 	err = mmc_send_io_op_cond(host, ocr, &rocr);
 	if (err)
-		goto err;
+		return err;
 
 	/*
 	 * For SPI, enable CRC as appropriate.
@@ -592,17 +592,15 @@
 	if (mmc_host_is_spi(host)) {
 		err = mmc_spi_set_crc(host, use_spi_crc);
 		if (err)
-			goto err;
+			return err;
 	}
 
 	/*
 	 * Allocate card structure.
 	 */
 	card = mmc_alloc_card(host, NULL);
-	if (IS_ERR(card)) {
-		err = PTR_ERR(card);
-		goto err;
-	}
+	if (IS_ERR(card))
+		return PTR_ERR(card);
 
 	if ((rocr & R4_MEMORY_PRESENT) &&
 	    mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
@@ -610,19 +608,15 @@
 
 		if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
 		    memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
-			mmc_remove_card(card);
-			pr_debug("%s: Perhaps the card was replaced\n",
-				mmc_hostname(host));
-			return -ENOENT;
+			err = -ENOENT;
+			goto mismatch;
 		}
 	} else {
 		card->type = MMC_TYPE_SDIO;
 
 		if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
-			mmc_remove_card(card);
-			pr_debug("%s: Perhaps the card was replaced\n",
-				mmc_hostname(host));
-			return -ENOENT;
+			err = -ENOENT;
+			goto mismatch;
 		}
 	}
 
@@ -632,6 +626,8 @@
 	if (host->ops->init_card)
 		host->ops->init_card(host, card);
 
+	card->ocr = ocr_card;
+
 	/*
 	 * If the host and card support UHS-I mode request the card
 	 * to switch to 1.8V signaling level.  No 1.8v signalling if
@@ -677,7 +673,7 @@
 	if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
 		err = mmc_sd_get_csd(host, card);
 		if (err)
-			return err;
+			goto remove;
 
 		mmc_decode_cid(card);
 	}
@@ -704,7 +700,12 @@
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
-		goto finish;
+		if (oldcard)
+			mmc_remove_card(card);
+		else
+			host->card = card;
+
+		return 0;
 	}
 
 	/*
@@ -718,9 +719,8 @@
 			/* Retry init sequence, but without R4_18V_PRESENT. */
 			retries = 0;
 			goto try_again;
-		} else {
-			goto remove;
 		}
+		return err;
 	}
 
 	/*
@@ -731,18 +731,16 @@
 		goto remove;
 
 	if (oldcard) {
-		int same = (card->cis.vendor == oldcard->cis.vendor &&
-			    card->cis.device == oldcard->cis.device);
-		mmc_remove_card(card);
-		if (!same) {
-			pr_debug("%s: Perhaps the card was replaced\n",
-				mmc_hostname(host));
-			return -ENOENT;
+		if (card->cis.vendor == oldcard->cis.vendor &&
+		    card->cis.device == oldcard->cis.device) {
+			mmc_remove_card(card);
+			card = oldcard;
+		} else {
+			err = -ENOENT;
+			goto mismatch;
 		}
-
-		card = oldcard;
 	}
-	card->ocr = ocr_card;
+
 	mmc_fixup_device(card, sdio_fixup_methods);
 
 	if (card->type == MMC_TYPE_SD_COMBO) {
@@ -801,16 +799,15 @@
 		err = -EINVAL;
 		goto remove;
 	}
-finish:
-	if (!oldcard)
-		host->card = card;
+
+	host->card = card;
 	return 0;
 
+mismatch:
+	pr_debug("%s: Perhaps the card was replaced\n", mmc_hostname(host));
 remove:
-	if (!oldcard)
+	if (oldcard != card)
 		mmc_remove_card(card);
-
-err:
 	return err;
 }
 
@@ -929,21 +926,37 @@
  */
 static int mmc_sdio_pre_suspend(struct mmc_host *host)
 {
-	int i, err = 0;
+	int i;
 
 	for (i = 0; i < host->card->sdio_funcs; i++) {
 		struct sdio_func *func = host->card->sdio_func[i];
 		if (func && sdio_func_present(func) && func->dev.driver) {
 			const struct dev_pm_ops *pmops = func->dev.driver->pm;
-			if (!pmops || !pmops->suspend || !pmops->resume) {
+			if (!pmops || !pmops->suspend || !pmops->resume)
 				/* force removal of entire card in that case */
-				err = -ENOSYS;
-				break;
-			}
+				goto remove;
 		}
 	}
 
-	return err;
+	return 0;
+
+remove:
+	if (!mmc_card_is_removable(host)) {
+		dev_warn(mmc_dev(host),
+			 "missing suspend/resume ops for non-removable SDIO card\n");
+		/* Don't remove a non-removable card - we can't re-detect it. */
+		return 0;
+	}
+
+	/* Remove the SDIO card and let it be re-detected later on. */
+	mmc_sdio_remove(host);
+	mmc_claim_host(host);
+	mmc_detach_bus(host);
+	mmc_power_off(host);
+	mmc_release_host(host);
+	host->pm_flags = 0;
+
+	return 0;
 }
 
 /*
@@ -1001,8 +1014,14 @@
 		}
 		err = mmc_sdio_reinit_card(host);
 	} else if (mmc_card_wake_sdio_irq(host)) {
-		/* We may have switched to 1-bit mode during suspend */
+		/*
+		 * We may have switched to 1-bit mode during suspend,
+		 * need to hold retuning, because tuning only supprt
+		 * 4-bit mode or 8 bit mode.
+		 */
+		mmc_retune_hold_now(host);
 		err = sdio_enable_4bit_bus(host->card);
+		mmc_retune_release(host);
 	}
 
 	if (err)
@@ -1048,9 +1067,35 @@
 	return ret;
 }
 
+/*
+ * SDIO HW reset
+ *
+ * Returns 0 if the HW reset was executed synchronously, returns 1 if the HW
+ * reset was asynchronously scheduled, else a negative error code.
+ */
 static int mmc_sdio_hw_reset(struct mmc_host *host)
 {
-	mmc_power_cycle(host, host->card->ocr);
+	struct mmc_card *card = host->card;
+
+	/*
+	 * In case the card is shared among multiple func drivers, reset the
+	 * card through a rescan work. In this way it will be removed and
+	 * re-detected, thus all func drivers becomes informed about it.
+	 */
+	if (atomic_read(&card->sdio_funcs_probed) > 1) {
+		if (mmc_card_removed(card))
+			return 1;
+		host->rescan_entered = 0;
+		mmc_card_set_removed(card);
+		_mmc_detect_change(host, 0, false);
+		return 1;
+	}
+
+	/*
+	 * A single func driver has been probed, then let's skip the heavy
+	 * hotplug dance above and execute the reset immediately.
+	 */
+	mmc_power_cycle(host, card->ocr);
 	return mmc_sdio_reinit_card(host);
 }
 
--- linux-ein-5.4.0.orig/drivers/mmc/core/sdio_bus.c
+++ linux-ein-5.4.0/drivers/mmc/core/sdio_bus.c
@@ -138,6 +138,8 @@
 	if (ret)
 		return ret;
 
+	atomic_inc(&func->card->sdio_funcs_probed);
+
 	/* Unbound SDIO functions are always suspended.
 	 * During probe, the function is set active and the usage count
 	 * is incremented.  If the driver supports runtime PM,
@@ -153,7 +155,10 @@
 	/* Set the default block size so the driver is sure it's something
 	 * sensible. */
 	sdio_claim_host(func);
-	ret = sdio_set_block_size(func, 0);
+	if (mmc_card_removed(func->card))
+		ret = -ENOMEDIUM;
+	else
+		ret = sdio_set_block_size(func, 0);
 	sdio_release_host(func);
 	if (ret)
 		goto disable_runtimepm;
@@ -165,6 +170,7 @@
 	return 0;
 
 disable_runtimepm:
+	atomic_dec(&func->card->sdio_funcs_probed);
 	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
 		pm_runtime_put_noidle(dev);
 	dev_pm_domain_detach(dev, false);
@@ -181,6 +187,7 @@
 		pm_runtime_get_sync(dev);
 
 	drv->remove(func);
+	atomic_dec(&func->card->sdio_funcs_probed);
 
 	if (func->irq_handler) {
 		pr_warn("WARNING: driver %s did not remove its interrupt handler!\n",
@@ -259,7 +266,14 @@
 {
 	struct sdio_func *func = dev_to_sdio_func(dev);
 
-	sdio_free_func_cis(func);
+	if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO))
+		sdio_free_func_cis(func);
+
+	/*
+	 * We have now removed the link to the tuples in the
+	 * card structure, so remove the reference.
+	 */
+	put_device(&func->card->dev);
 
 	kfree(func->info);
 	kfree(func->tmpbuf);
@@ -291,6 +305,12 @@
 
 	device_initialize(&func->dev);
 
+	/*
+	 * We may link to tuples in the card structure,
+	 * we need make sure we have a reference to it.
+	 */
+	get_device(&func->card->dev);
+
 	func->dev.parent = &card->dev;
 	func->dev.bus = &sdio_bus_type;
 	func->dev.release = sdio_release_func;
@@ -344,10 +364,9 @@
  */
 void sdio_remove_func(struct sdio_func *func)
 {
-	if (!sdio_func_present(func))
-		return;
+	if (sdio_func_present(func))
+		device_del(&func->dev);
 
-	device_del(&func->dev);
 	of_node_put(func->dev.of_node);
 	put_device(&func->dev);
 }
--- linux-ein-5.4.0.orig/drivers/mmc/core/sdio_cis.c
+++ linux-ein-5.4.0/drivers/mmc/core/sdio_cis.c
@@ -20,12 +20,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;
@@ -263,6 +268,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)
@@ -315,6 +322,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",
@@ -375,12 +384,6 @@
 		return ret;
 
 	/*
-	 * Since we've linked to tuples in the card structure,
-	 * we must make sure we have a reference to it.
-	 */
-	get_device(&func->card->dev);
-
-	/*
 	 * Vendor/device id is optional for function CIS, so
 	 * copy it from the card structure as needed.
 	 */
@@ -405,11 +408,5 @@
 	}
 
 	func->tuples = NULL;
-
-	/*
-	 * We have now removed the link to the tuples in the
-	 * card structure, so remove the reference.
-	 */
-	put_device(&func->card->dev);
 }
 
--- linux-ein-5.4.0.orig/drivers/mmc/core/sdio_ops.c
+++ linux-ein-5.4.0/drivers/mmc/core/sdio_ops.c
@@ -121,6 +121,7 @@
 	struct sg_table sgtable;
 	unsigned int nents, left_size, i;
 	unsigned int seg_size = card->host->max_seg_size;
+	int err;
 
 	WARN_ON(blksz == 0);
 
@@ -170,28 +171,32 @@
 
 	mmc_set_data_timeout(&data, card);
 
-	mmc_wait_for_req(card->host, &mrq);
+	mmc_pre_req(card->host, &mrq);
 
-	if (nents > 1)
-		sg_free_table(&sgtable);
+	mmc_wait_for_req(card->host, &mrq);
 
 	if (cmd.error)
-		return cmd.error;
-	if (data.error)
-		return data.error;
-
-	if (mmc_host_is_spi(card->host)) {
+		err = cmd.error;
+	else if (data.error)
+		err = data.error;
+	else if (mmc_host_is_spi(card->host))
 		/* host driver already reported errors */
-	} else {
-		if (cmd.resp[0] & R5_ERROR)
-			return -EIO;
-		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
-			return -EINVAL;
-		if (cmd.resp[0] & R5_OUT_OF_RANGE)
-			return -ERANGE;
-	}
+		err = 0;
+	else if (cmd.resp[0] & R5_ERROR)
+		err = -EIO;
+	else if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+		err = -EINVAL;
+	else if (cmd.resp[0] & R5_OUT_OF_RANGE)
+		err = -ERANGE;
+	else
+		err = 0;
+
+	mmc_post_req(card->host, &mrq, err);
+
+	if (nents > 1)
+		sg_free_table(&sgtable);
 
-	return 0;
+	return err;
 }
 
 int sdio_reset(struct mmc_host *host)
--- linux-ein-5.4.0.orig/drivers/mmc/core/slot-gpio.c
+++ linux-ein-5.4.0/drivers/mmc/core/slot-gpio.c
@@ -63,11 +63,15 @@
 int mmc_gpio_get_ro(struct mmc_host *host)
 {
 	struct mmc_gpio *ctx = host->slot.handler_priv;
+	int cansleep;
 
 	if (!ctx || !ctx->ro_gpio)
 		return -ENOSYS;
 
-	return gpiod_get_value_cansleep(ctx->ro_gpio);
+	cansleep = gpiod_cansleep(ctx->ro_gpio);
+	return cansleep ?
+		gpiod_get_value_cansleep(ctx->ro_gpio) :
+		gpiod_get_value(ctx->ro_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_ro);
 
@@ -241,6 +245,9 @@
 			return ret;
 	}
 
+	if (host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH)
+		gpiod_toggle_active_low(desc);
+
 	if (gpio_invert)
 		*gpio_invert = !gpiod_is_active_low(desc);
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/Kconfig
+++ linux-ein-5.4.0/drivers/mmc/host/Kconfig
@@ -449,7 +449,7 @@
 
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
-	depends on ISA_DMA_API
+	depends on ISA_DMA_API && !M68K
 	help
 	  This selects the Winbond(R) W83L51xD Secure digital and
 	  Multimedia card Interface.
@@ -466,11 +466,12 @@
 	  of Alcor Micro PCI-E card reader
 
 config MMC_AU1X
-	tristate "Alchemy AU1XX0 MMC Card Interface support"
+	bool "Alchemy AU1XX0 MMC Card Interface support"
 	depends on MIPS_ALCHEMY
+	depends on MMC=y
 	help
 	  This selects the AMD Alchemy(R) Multimedia card interface.
-	  If you have a Alchemy platform with a MMC slot, say Y or M here.
+	  If you have a Alchemy platform with a MMC slot, say Y here.
 
 	  If unsure, say N.
 
@@ -995,13 +996,14 @@
 
 config MMC_SDHCI_OMAP
 	tristate "TI SDHCI Controller Support"
+	depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
 	depends on MMC_SDHCI_PLTFM && OF
 	select THERMAL
 	imply TI_SOC_THERMAL
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
-	  support present in TI's DRA7 SOCs. The controller supports
-	  SD/MMC/SDIO devices.
+	  support present in TI's Keystone/OMAP2+/DRA7 SOCs. The controller
+	  supports SD/MMC/SDIO devices.
 
 	  If you have a controller with this interface, say Y or M here.
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/alcor.c
+++ linux-ein-5.4.0/drivers/mmc/host/alcor.c
@@ -1104,7 +1104,7 @@
 
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to get irq for data line\n");
-		return ret;
+		goto free_host;
 	}
 
 	mutex_init(&host->cmd_mutex);
@@ -1114,8 +1114,15 @@
 	alcor_hw_init(host);
 
 	dev_set_drvdata(&pdev->dev, host);
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto free_host;
+
 	return 0;
+
+free_host:
+	mmc_free_host(mmc);
+	return ret;
 }
 
 static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/mmc/host/android-goldfish.c
+++ linux-ein-5.4.0/drivers/mmc/host/android-goldfish.c
@@ -545,6 +545,7 @@
 	.remove		= goldfish_mmc_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/atmel-mci.c
+++ linux-ein-5.4.0/drivers/mmc/host/atmel-mci.c
@@ -1812,7 +1812,6 @@
 				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
 				state = STATE_WAITING_NOTBUSY;
 			} else if (host->mrq->stop) {
-				atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
 				atmci_send_stop_cmd(host, data);
 				state = STATE_SENDING_STOP;
 			} else {
@@ -1845,8 +1844,6 @@
 				 * command to send.
 				 */
 				if (host->mrq->stop) {
-					atmci_writel(host, ATMCI_IER,
-					             ATMCI_CMDRDY);
 					atmci_send_stop_cmd(host, data);
 					state = STATE_SENDING_STOP;
 				} else {
@@ -2217,6 +2214,7 @@
 {
 	struct mmc_host			*mmc;
 	struct atmel_mci_slot		*slot;
+	int ret;
 
 	mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
 	if (!mmc)
@@ -2300,11 +2298,13 @@
 
 	host->slot[id] = slot;
 	mmc_regulator_get_supply(mmc);
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		mmc_free_host(mmc);
+		return ret;
+	}
 
 	if (gpio_is_valid(slot->detect_pin)) {
-		int ret;
-
 		timer_setup(&slot->detect_timer, atmci_detect_change, 0);
 
 		ret = request_irq(gpio_to_irq(slot->detect_pin),
@@ -2663,6 +2663,7 @@
 	.remove		= atmci_remove,
 	.driver		= {
 		.name		= "atmel_mci",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= of_match_ptr(atmci_dt_ids),
 		.pm		= &atmci_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/au1xmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/au1xmmc.c
@@ -1116,8 +1116,9 @@
 	if (host->platdata && host->platdata->cd_setup &&
 	    !(mmc->caps & MMC_CAP_NEEDS_POLL))
 		host->platdata->cd_setup(mmc, 0);
-out_clk:
+
 	clk_disable_unprepare(host->clk);
+out_clk:
 	clk_put(host->clk);
 out_irq:
 	free_irq(host->irq, host);
@@ -1208,6 +1209,7 @@
 	.resume        = au1xmmc_resume,
 	.driver        = {
 		.name  = DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/bcm2835.c
+++ linux-ein-5.4.0/drivers/mmc/host/bcm2835.c
@@ -1408,8 +1408,8 @@
 	host->max_clk = clk_get_rate(clk);
 
 	host->irq = platform_get_irq(pdev, 0);
-	if (host->irq <= 0) {
-		ret = -EINVAL;
+	if (host->irq < 0) {
+		ret = host->irq;
 		goto err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/cavium-octeon.c
+++ linux-ein-5.4.0/drivers/mmc/host/cavium-octeon.c
@@ -288,6 +288,7 @@
 		if (ret) {
 			dev_err(&pdev->dev, "Error populating slots\n");
 			octeon_mmc_set_shared_power(host, 0);
+			of_node_put(cn);
 			goto error;
 		}
 		i++;
--- linux-ein-5.4.0.orig/drivers/mmc/host/cavium-thunderx.c
+++ linux-ein-5.4.0/drivers/mmc/host/cavium-thunderx.c
@@ -138,8 +138,10 @@
 				continue;
 
 			ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host);
-			if (ret)
+			if (ret) {
+				of_node_put(child_node);
 				goto error;
+			}
 		}
 		i++;
 	}
--- linux-ein-5.4.0.orig/drivers/mmc/host/cqhci.c
+++ linux-ein-5.4.0/drivers/mmc/host/cqhci.c
@@ -5,6 +5,7 @@
 #include <linux/delay.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
@@ -272,6 +273,9 @@
 
 	cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
 
+	if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
+		cqhci_writel(cq_host, 0, CQHCI_CTL);
+
 	mmc->cqe_on = true;
 
 	if (cq_host->ops->enable)
@@ -298,16 +302,16 @@
 	cq_host->activated = false;
 }
 
-int cqhci_suspend(struct mmc_host *mmc)
+int cqhci_deactivate(struct mmc_host *mmc)
 {
 	struct cqhci_host *cq_host = mmc->cqe_private;
 
-	if (cq_host->enabled)
+	if (cq_host->enabled && cq_host->activated)
 		__cqhci_disable(cq_host);
 
 	return 0;
 }
-EXPORT_SYMBOL(cqhci_suspend);
+EXPORT_SYMBOL(cqhci_deactivate);
 
 int cqhci_resume(struct mmc_host *mmc)
 {
@@ -343,12 +347,16 @@
 /* CQHCI is idle and should halt immediately, so set a small timeout */
 #define CQHCI_OFF_TIMEOUT 100
 
+static u32 cqhci_read_ctl(struct cqhci_host *cq_host)
+{
+	return cqhci_readl(cq_host, CQHCI_CTL);
+}
+
 static void cqhci_off(struct mmc_host *mmc)
 {
 	struct cqhci_host *cq_host = mmc->cqe_private;
-	ktime_t timeout;
-	bool timed_out;
 	u32 reg;
+	int err;
 
 	if (!cq_host->enabled || !mmc->cqe_on || cq_host->recovery_halt)
 		return;
@@ -358,15 +366,9 @@
 
 	cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
 
-	timeout = ktime_add_us(ktime_get(), CQHCI_OFF_TIMEOUT);
-	while (1) {
-		timed_out = ktime_compare(ktime_get(), timeout) > 0;
-		reg = cqhci_readl(cq_host, CQHCI_CTL);
-		if ((reg & CQHCI_HALT) || timed_out)
-			break;
-	}
-
-	if (timed_out)
+	err = readx_poll_timeout(cqhci_read_ctl, cq_host, reg,
+				 reg & CQHCI_HALT, 0, CQHCI_OFF_TIMEOUT);
+	if (err < 0)
 		pr_err("%s: cqhci: CQE stuck on\n", mmc_hostname(mmc));
 	else
 		pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc));
@@ -876,8 +878,8 @@
 	ret = cqhci_tasks_cleared(cq_host);
 
 	if (!ret)
-		pr_debug("%s: cqhci: Failed to clear tasks\n",
-			 mmc_hostname(mmc));
+		pr_warn("%s: cqhci: Failed to clear tasks\n",
+			mmc_hostname(mmc));
 
 	return ret;
 }
@@ -910,7 +912,7 @@
 	ret = cqhci_halted(cq_host);
 
 	if (!ret)
-		pr_debug("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
+		pr_warn("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
 
 	return ret;
 }
@@ -918,10 +920,10 @@
 /*
  * After halting we expect to be able to use the command line. We interpret the
  * failure to halt to mean the data lines might still be in use (and the upper
- * layers will need to send a STOP command), so we set the timeout based on a
- * generous command timeout.
+ * layers will need to send a STOP command), however failing to halt complicates
+ * the recovery, so set a timeout that would reasonably allow I/O to complete.
  */
-#define CQHCI_START_HALT_TIMEOUT	5
+#define CQHCI_START_HALT_TIMEOUT	500
 
 static void cqhci_recovery_start(struct mmc_host *mmc)
 {
@@ -1009,28 +1011,28 @@
 
 	ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
 
-	if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
-		ok = false;
-
 	/*
 	 * The specification contradicts itself, by saying that tasks cannot be
 	 * cleared if CQHCI does not halt, but if CQHCI does not halt, it should
 	 * be disabled/re-enabled, but not to disable before clearing tasks.
 	 * Have a go anyway.
 	 */
-	if (!ok) {
-		pr_debug("%s: cqhci: disable / re-enable\n", mmc_hostname(mmc));
-		cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
-		cqcfg &= ~CQHCI_ENABLE;
-		cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
-		cqcfg |= CQHCI_ENABLE;
-		cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
-		/* Be sure that there are no tasks */
-		ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
-		if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
-			ok = false;
-		WARN_ON(!ok);
-	}
+	if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
+		ok = false;
+
+	/* Disable to make sure tasks really are cleared */
+	cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
+	cqcfg &= ~CQHCI_ENABLE;
+	cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+
+	cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
+	cqcfg |= CQHCI_ENABLE;
+	cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+
+	cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
+
+	if (!ok)
+		cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT);
 
 	cqhci_recover_mrqs(cq_host);
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/cqhci.h
+++ linux-ein-5.4.0/drivers/mmc/host/cqhci.h
@@ -230,7 +230,11 @@
 		      int data_error);
 int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
 struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
-int cqhci_suspend(struct mmc_host *mmc);
+int cqhci_deactivate(struct mmc_host *mmc);
+static inline int cqhci_suspend(struct mmc_host *mmc)
+{
+	return cqhci_deactivate(mmc);
+}
 int cqhci_resume(struct mmc_host *mmc);
 
 #endif
--- linux-ein-5.4.0.orig/drivers/mmc/host/davinci_mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/davinci_mmc.c
@@ -1376,8 +1376,12 @@
 static int davinci_mmcsd_resume(struct device *dev)
 {
 	struct mmc_davinci_host *host = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_enable(host->clk);
+	if (ret)
+		return ret;
 
-	clk_enable(host->clk);
 	mmc_davinci_reset_ctrl(host, 0);
 
 	return 0;
@@ -1396,6 +1400,7 @@
 static struct platform_driver davinci_mmcsd_driver = {
 	.driver		= {
 		.name	= "davinci_mmc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= davinci_mmcsd_pm_ops,
 		.of_match_table = davinci_mmc_dt_ids,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/dw_mmc-exynos.c
+++ linux-ein-5.4.0/drivers/mmc/host/dw_mmc-exynos.c
@@ -462,6 +462,18 @@
 		}
 	}
 
+	/*
+	 * If there is no cadiates value, then it needs to return -EIO.
+	 * If there are candiates values and don't find bset clk sample value,
+	 * then use a first candiates clock sample value.
+	 */
+	for (i = 0; i < iter; i++) {
+		__c = ror8(candiates, i);
+		if ((__c & 0x1) == 0x1) {
+			loc = i;
+			goto out;
+		}
+	}
 out:
 	return loc;
 }
@@ -492,6 +504,8 @@
 		priv->tuned_sample = found;
 	} else {
 		ret = -EIO;
+		dev_warn(&mmc->class_dev,
+			"There is no candiates value about clksmpl!\n");
 	}
 
 	return ret;
@@ -590,6 +604,7 @@
 	.remove		= dw_mci_exynos_remove,
 	.driver		= {
 		.name		= "dwmmc_exynos",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= dw_mci_exynos_match,
 		.pm		= &dw_mci_exynos_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/dw_mmc-k3.c
+++ linux-ein-5.4.0/drivers/mmc/host/dw_mmc-k3.c
@@ -473,6 +473,7 @@
 	.remove		= dw_mci_pltfm_remove,
 	.driver		= {
 		.name		= "dwmmc_k3",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= dw_mci_k3_match,
 		.pm		= &dw_mci_k3_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/dw_mmc-pltfm.c
+++ linux-ein-5.4.0/drivers/mmc/host/dw_mmc-pltfm.c
@@ -98,6 +98,7 @@
 	.remove		= dw_mci_pltfm_remove,
 	.driver		= {
 		.name		= "dw_mmc",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= dw_mci_pltfm_match,
 		.pm		= &dw_mci_pltfm_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/dw_mmc-rockchip.c
+++ linux-ein-5.4.0/drivers/mmc/host/dw_mmc-rockchip.c
@@ -383,6 +383,7 @@
 	.remove		= dw_mci_rockchip_remove,
 	.driver		= {
 		.name		= "dwmmc_rockchip",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= dw_mci_rockchip_match,
 		.pm		= &dw_mci_rockchip_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/dw_mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/dw_mmc.c
@@ -782,6 +782,7 @@
 	int ret = 0;
 
 	/* Set external dma config: burst size, burst width */
+	memset(&cfg, 0, sizeof(cfg));
 	cfg.dst_addr = host->phy_regs + fifo_offset;
 	cfg.src_addr = cfg.dst_addr;
 	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -2012,13 +2013,14 @@
 				 * delayed. Allowing the transfer to take place
 				 * avoids races and keeps things simple.
 				 */
-				if (err != -ETIMEDOUT) {
+				if (err != -ETIMEDOUT &&
+				    host->dir_status == DW_MCI_RECV_STATUS) {
 					state = STATE_SENDING_DATA;
 					continue;
 				}
 
-				dw_mci_stop_dma(host);
 				send_stop_abort(host, data);
+				dw_mci_stop_dma(host);
 				state = STATE_SENDING_STOP;
 				break;
 			}
@@ -2042,10 +2044,10 @@
 			 */
 			if (test_and_clear_bit(EVENT_DATA_ERROR,
 					       &host->pending_events)) {
-				dw_mci_stop_dma(host);
 				if (!(host->data_status & (SDMMC_INT_DRTO |
 							   SDMMC_INT_EBE)))
 					send_stop_abort(host, data);
+				dw_mci_stop_dma(host);
 				state = STATE_DATA_ERROR;
 				break;
 			}
@@ -2078,10 +2080,10 @@
 			 */
 			if (test_and_clear_bit(EVENT_DATA_ERROR,
 					       &host->pending_events)) {
-				dw_mci_stop_dma(host);
 				if (!(host->data_status & (SDMMC_INT_DRTO |
 							   SDMMC_INT_EBE)))
 					send_stop_abort(host, data);
+				dw_mci_stop_dma(host);
 				state = STATE_DATA_ERROR;
 				break;
 			}
--- linux-ein-5.4.0.orig/drivers/mmc/host/jz4740_mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/jz4740_mmc.c
@@ -224,6 +224,26 @@
 		return PTR_ERR(host->dma_rx);
 	}
 
+	/*
+	 * Limit the maximum segment size in any SG entry according to
+	 * the parameters of the DMA engine device.
+	 */
+	if (host->dma_tx) {
+		struct device *dev = host->dma_tx->device->dev;
+		unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+		if (max_seg_size < host->mmc->max_seg_size)
+			host->mmc->max_seg_size = max_seg_size;
+	}
+
+	if (host->dma_rx) {
+		struct device *dev = host->dma_rx->device->dev;
+		unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+		if (max_seg_size < host->mmc->max_seg_size)
+			host->mmc->max_seg_size = max_seg_size;
+	}
+
 	return 0;
 }
 
@@ -1088,6 +1108,7 @@
 	.remove = jz4740_mmc_remove,
 	.driver = {
 		.name = "jz4740-mmc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(jz4740_mmc_of_match),
 		.pm = JZ4740_MMC_PM_OPS,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/meson-gx-mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/meson-gx-mmc.c
@@ -166,6 +166,7 @@
 
 	unsigned int bounce_buf_size;
 	void *bounce_buf;
+	void __iomem *bounce_iomem_buf;
 	dma_addr_t bounce_dma_addr;
 	struct sd_emmc_desc *descs;
 	dma_addr_t descs_dma_addr;
@@ -173,6 +174,8 @@
 	int irq;
 
 	bool vqmmc_enabled;
+	bool needs_pre_post_req;
+
 };
 
 #define CMD_CFG_LENGTH_MASK GENMASK(8, 0)
@@ -654,6 +657,8 @@
 	struct meson_host *host = mmc_priv(mmc);
 
 	host->cmd = NULL;
+	if (host->needs_pre_post_req)
+		meson_mmc_post_req(mmc, mrq, 0);
 	mmc_request_done(host->mmc, mrq);
 }
 
@@ -737,6 +742,53 @@
 	writel(start, host->regs + SD_EMMC_START);
 }
 
+/* local sg copy for dram_access_quirk */
+static void meson_mmc_copy_buffer(struct meson_host *host, struct mmc_data *data,
+				  size_t buflen, bool to_buffer)
+{
+	unsigned int sg_flags = SG_MITER_ATOMIC;
+	struct scatterlist *sgl = data->sg;
+	unsigned int nents = data->sg_len;
+	struct sg_mapping_iter miter;
+	unsigned int offset = 0;
+
+	if (to_buffer)
+		sg_flags |= SG_MITER_FROM_SG;
+	else
+		sg_flags |= SG_MITER_TO_SG;
+
+	sg_miter_start(&miter, sgl, nents, sg_flags);
+
+	while ((offset < buflen) && sg_miter_next(&miter)) {
+		unsigned int buf_offset = 0;
+		unsigned int len, left;
+		u32 *buf = miter.addr;
+
+		len = min(miter.length, buflen - offset);
+		left = len;
+
+		if (to_buffer) {
+			do {
+				writel(*buf++, host->bounce_iomem_buf + offset + buf_offset);
+
+				buf_offset += 4;
+				left -= 4;
+			} while (left);
+		} else {
+			do {
+				*buf++ = readl(host->bounce_iomem_buf + offset + buf_offset);
+
+				buf_offset += 4;
+				left -= 4;
+			} while (left);
+		}
+
+		offset += len;
+	}
+
+	sg_miter_stop(&miter);
+}
+
 static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
 {
 	struct meson_host *host = mmc_priv(mmc);
@@ -751,7 +803,6 @@
 
 	cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode);
 	cmd_cfg |= CMD_CFG_OWNER;  /* owned by CPU */
-	cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */
 
 	meson_mmc_set_response_bits(cmd, &cmd_cfg);
 
@@ -780,8 +831,11 @@
 		if (data->flags & MMC_DATA_WRITE) {
 			cmd_cfg |= CMD_CFG_DATA_WR;
 			WARN_ON(xfer_bytes > host->bounce_buf_size);
-			sg_copy_to_buffer(data->sg, data->sg_len,
-					  host->bounce_buf, xfer_bytes);
+			if (host->dram_access_quirk)
+				meson_mmc_copy_buffer(host, data, xfer_bytes, true);
+			else
+				sg_copy_to_buffer(data->sg, data->sg_len,
+						  host->bounce_buf, xfer_bytes);
 			dma_wmb();
 		}
 
@@ -800,28 +854,56 @@
 	writel(cmd->arg, host->regs + SD_EMMC_CMD_ARG);
 }
 
+static int meson_mmc_validate_dram_access(struct mmc_host *mmc, struct mmc_data *data)
+{
+	struct scatterlist *sg;
+	int i;
+
+	/* Reject request if any element offset or size is not 32bit aligned */
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
+		    !IS_ALIGNED(sg->length, sizeof(u32))) {
+			dev_err(mmc_dev(mmc), "unaligned sg offset %u len %u\n",
+				data->sg->offset, data->sg->length);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct meson_host *host = mmc_priv(mmc);
-	bool needs_pre_post_req = mrq->data &&
+	host->needs_pre_post_req = mrq->data &&
 			!(mrq->data->host_cookie & SD_EMMC_PRE_REQ_DONE);
 
-	if (needs_pre_post_req) {
+	/*
+	 * The memory at the end of the controller used as bounce buffer for
+	 * the dram_access_quirk only accepts 32bit read/write access,
+	 * check the aligment and length of the data before starting the request.
+	 */
+	if (host->dram_access_quirk && mrq->data) {
+		mrq->cmd->error = meson_mmc_validate_dram_access(mmc, mrq->data);
+		if (mrq->cmd->error) {
+			mmc_request_done(mmc, mrq);
+			return;
+		}
+	}
+
+	if (host->needs_pre_post_req) {
 		meson_mmc_get_transfer_mode(mmc, mrq);
 		if (!meson_mmc_desc_chain_mode(mrq->data))
-			needs_pre_post_req = false;
+			host->needs_pre_post_req = false;
 	}
 
-	if (needs_pre_post_req)
+	if (host->needs_pre_post_req)
 		meson_mmc_pre_req(mmc, mrq);
 
 	/* Stop execution */
 	writel(0, host->regs + SD_EMMC_START);
 
 	meson_mmc_start_cmd(mmc, mrq->sbc ?: mrq->cmd);
-
-	if (needs_pre_post_req)
-		meson_mmc_post_req(mmc, mrq, 0);
 }
 
 static void meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
@@ -890,11 +972,8 @@
 	if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) {
 		if (data && !cmd->error)
 			data->bytes_xfered = data->blksz * data->blocks;
-		if (meson_mmc_bounce_buf_read(data) ||
-		    meson_mmc_get_next_command(cmd))
-			ret = IRQ_WAKE_THREAD;
-		else
-			ret = IRQ_HANDLED;
+
+		return IRQ_WAKE_THREAD;
 	}
 
 out:
@@ -906,9 +985,6 @@
 		writel(start, host->regs + SD_EMMC_START);
 	}
 
-	if (ret == IRQ_HANDLED)
-		meson_mmc_request_done(host->mmc, cmd->mrq);
-
 	return ret;
 }
 
@@ -950,8 +1026,11 @@
 	if (meson_mmc_bounce_buf_read(data)) {
 		xfer_bytes = data->blksz * data->blocks;
 		WARN_ON(xfer_bytes > host->bounce_buf_size);
-		sg_copy_from_buffer(data->sg, data->sg_len,
-				    host->bounce_buf, xfer_bytes);
+		if (host->dram_access_quirk)
+			meson_mmc_copy_buffer(host, data, xfer_bytes, false);
+		else
+			sg_copy_from_buffer(data->sg, data->sg_len,
+					    host->bounce_buf, xfer_bytes);
 	}
 
 	next_cmd = meson_mmc_get_next_command(cmd);
@@ -1151,9 +1230,11 @@
 
 	mmc->caps |= MMC_CAP_CMD23;
 	if (host->dram_access_quirk) {
+		/* Limit segments to 1 due to low available sram memory */
+		mmc->max_segs = 1;
 		/* Limit to the available sram memory */
-		mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
-		mmc->max_blk_count = mmc->max_segs;
+		mmc->max_blk_count = SD_EMMC_SRAM_DATA_BUF_LEN /
+				     mmc->max_blk_size;
 	} else {
 		mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
 		mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
@@ -1177,7 +1258,7 @@
 		 * instead of the DDR memory
 		 */
 		host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
-		host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
+		host->bounce_iomem_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
 		host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
 	} else {
 		/* data bounce buffer */
@@ -1201,7 +1282,9 @@
 	}
 
 	mmc->ops = &meson_mmc_ops;
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto err_free_irq;
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/meson-mx-sdio.c
+++ linux-ein-5.4.0/drivers/mmc/host/meson-mx-sdio.c
@@ -246,6 +246,9 @@
 
 	mrq = host->mrq;
 
+	if (host->cmd->error)
+		meson_mx_mmc_soft_reset(host);
+
 	host->mrq = NULL;
 	host->cmd = NULL;
 
@@ -357,14 +360,6 @@
 		meson_mx_mmc_start_cmd(mmc, mrq->cmd);
 }
 
-static int meson_mx_mmc_card_busy(struct mmc_host *mmc)
-{
-	struct meson_mx_mmc_host *host = mmc_priv(mmc);
-	u32 irqc = readl(host->base + MESON_MX_SDIO_IRQC);
-
-	return !!(irqc & MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK);
-}
-
 static void meson_mx_mmc_read_response(struct mmc_host *mmc,
 				       struct mmc_command *cmd)
 {
@@ -506,7 +501,6 @@
 static struct mmc_host_ops meson_mx_mmc_ops = {
 	.request		= meson_mx_mmc_request,
 	.set_ios		= meson_mx_mmc_set_ios,
-	.card_busy		= meson_mx_mmc_card_busy,
 	.get_cd			= mmc_gpio_get_cd,
 	.get_ro			= mmc_gpio_get_ro,
 };
@@ -570,7 +564,7 @@
 	mmc->f_max = clk_round_rate(host->cfg_div_clk,
 				    clk_get_rate(host->parent_clk));
 
-	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY;
 	mmc->ops = &meson_mx_mmc_ops;
 
 	ret = mmc_of_parse(mmc);
@@ -671,6 +665,11 @@
 	}
 
 	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = irq;
+		goto error_free_mmc;
+	}
+
 	ret = devm_request_threaded_irq(host->controller_dev, irq,
 					meson_mx_mmc_irq,
 					meson_mx_mmc_irq_thread, IRQF_ONESHOT,
--- linux-ein-5.4.0.orig/drivers/mmc/host/mmc_spi.c
+++ linux-ein-5.4.0/drivers/mmc/host/mmc_spi.c
@@ -1134,17 +1134,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,
@@ -1415,7 +1420,7 @@
 
 	status = mmc_add_host(mmc);
 	if (status != 0)
-		goto fail_add_host;
+		goto fail_glue_init;
 
 	/*
 	 * Index 0 is card detect
@@ -1423,7 +1428,7 @@
 	 */
 	status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1, NULL);
 	if (status == -EPROBE_DEFER)
-		goto fail_add_host;
+		goto fail_gpiod_request;
 	if (!status) {
 		/*
 		 * The platform has a CD GPIO signal that may support
@@ -1438,7 +1443,7 @@
 	/* Index 1 is write protect/read only */
 	status = mmc_gpiod_request_ro(mmc, NULL, 1, 0, NULL);
 	if (status == -EPROBE_DEFER)
-		goto fail_add_host;
+		goto fail_gpiod_request;
 	if (!status)
 		has_ro = true;
 
@@ -1452,7 +1457,7 @@
 				? ", cd polling" : "");
 	return 0;
 
-fail_add_host:
+fail_gpiod_request:
 	mmc_remove_host(mmc);
 fail_glue_init:
 	if (host->dma_dev)
--- linux-ein-5.4.0.orig/drivers/mmc/host/mmci.c
+++ linux-ein-5.4.0/drivers/mmc/host/mmci.c
@@ -168,6 +168,8 @@
 	.cmdreg_srsp		= MCI_CPSM_RESPONSE,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_any_blocksz	= true,
+	.dma_power_of_2		= true,
 	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
@@ -201,6 +203,8 @@
 	.datactrl_mask_ddrmode	= MCI_DPSM_ST_DDRMODE,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_any_blocksz	= true,
+	.dma_power_of_2		= true,
 	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
@@ -260,6 +264,7 @@
 	.datacnt_useless	= true,
 	.datalength_bits	= 25,
 	.datactrl_blocksz	= 14,
+	.datactrl_any_blocksz	= true,
 	.stm32_idmabsize_mask	= GENMASK(12, 5),
 	.init			= sdmmc_variant_init,
 };
@@ -279,6 +284,7 @@
 	.data_cmd_enable	= MCI_CPSM_QCOM_DATCMD,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_any_blocksz	= true,
 	.pwrreg_powerup		= MCI_PWR_UP,
 	.f_max			= 208000000,
 	.explicit_mclk_control	= true,
@@ -447,10 +453,11 @@
 static int mmci_validate_data(struct mmci_host *host,
 			      struct mmc_data *data)
 {
+	struct variant_data *variant = host->variant;
+
 	if (!data)
 		return 0;
-
-	if (!is_power_of_2(data->blksz)) {
+	if (!is_power_of_2(data->blksz) && !variant->datactrl_any_blocksz) {
 		dev_err(mmc_dev(host->mmc),
 			"unsupported block size (%d bytes)\n", data->blksz);
 		return -EINVAL;
@@ -515,7 +522,9 @@
 		 "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
 		 data->sg_len, data->blksz, data->blocks, data->flags);
 
-	host->ops->dma_start(host, &datactrl);
+	ret = host->ops->dma_start(host, &datactrl);
+	if (ret)
+		return ret;
 
 	/* Trigger the DMA transfer */
 	mmci_write_datactrlreg(host, datactrl);
@@ -822,6 +831,18 @@
 	if (data->blksz * data->blocks <= variant->fifosize)
 		return -EINVAL;
 
+	/*
+	 * This is necessary to get SDIO working on the Ux500. We do not yet
+	 * know if this is a bug in:
+	 * - The Ux500 DMA controller (DMA40)
+	 * - The MMCI DMA interface on the Ux500
+	 * some power of two blocks (such as 64 bytes) are sent regularly
+	 * during SDIO traffic and those work fine so for these we enable DMA
+	 * transfers.
+	 */
+	if (host->variant->dma_power_of_2 && !is_power_of_2(data->blksz))
+		return -EINVAL;
+
 	device = chan->device;
 	nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
 			   mmc_get_dma_dir(data));
@@ -872,9 +893,14 @@
 int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl)
 {
 	struct mmci_dmae_priv *dmae = host->dma_priv;
+	int ret;
 
 	host->dma_in_progress = true;
-	dmaengine_submit(dmae->desc_current);
+	ret = dma_submit_error(dmaengine_submit(dmae->desc_current));
+	if (ret < 0) {
+		host->dma_in_progress = false;
+		return ret;
+	}
 	dma_async_issue_pending(dmae->cur);
 
 	*datactrl |= MCI_DPSM_DMAENABLE;
@@ -2053,7 +2079,9 @@
 	pm_runtime_set_autosuspend_delay(&dev->dev, 50);
 	pm_runtime_use_autosuspend(&dev->dev);
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto clk_disable;
 
 	pm_runtime_put(&dev->dev);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/mmc/host/mmci.h
+++ linux-ein-5.4.0/drivers/mmc/host/mmci.h
@@ -278,7 +278,11 @@
  * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
  * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
  * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @datactrl_blksz: block size in power of two
+ * @datactrl_blocksz: block size in power of two
+ * @datactrl_any_blocksz: true if block any block sizes are accepted by
+ *		  hardware, such as with some SDIO traffic that send
+ *		  odd packets.
+ * @dma_power_of_2: DMA only works with blocks that are a power of 2.
  * @datactrl_first: true if data must be setup before send command
  * @datacnt_useless: true if you could not use datacnt register to read
  *		     remaining data
@@ -323,6 +327,8 @@
 	unsigned int		datactrl_mask_ddrmode;
 	unsigned int		datactrl_mask_sdio;
 	unsigned int		datactrl_blocksz;
+	u8			datactrl_any_blocksz:1;
+	u8			dma_power_of_2:1;
 	u8			datactrl_first:1;
 	u8			datacnt_useless:1;
 	u8			st_sdio:1;
--- linux-ein-5.4.0.orig/drivers/mmc/host/mmci_stm32_sdmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/mmci_stm32_sdmmc.c
@@ -36,8 +36,8 @@
 	 * excepted the last element which has no constraint on idmasize
 	 */
 	for_each_sg(data->sg, sg, data->sg_len - 1, i) {
-		if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) ||
-		    !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) {
+		if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
+		    !IS_ALIGNED(sg->length, SDMMC_IDMA_BURST)) {
 			dev_err(mmc_dev(host->mmc),
 				"unaligned scatterlist: ofst:%x length:%d\n",
 				data->sg->offset, data->sg->length);
@@ -45,7 +45,7 @@
 		}
 	}
 
-	if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) {
+	if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
 		dev_err(mmc_dev(host->mmc),
 			"unaligned last scatterlist: ofst:%x length:%d\n",
 			data->sg->offset, data->sg->length);
@@ -162,6 +162,9 @@
 static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data)
 {
 	writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR);
+
+	if (!data->host_cookie)
+		sdmmc_idma_unprep_data(host, data, 0);
 }
 
 static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
--- linux-ein-5.4.0.orig/drivers/mmc/host/moxart-mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/moxart-mmc.c
@@ -111,8 +111,8 @@
 #define CLK_DIV_MASK		0x7f
 
 /* REG_BUS_WIDTH */
-#define BUS_WIDTH_8		BIT(2)
-#define BUS_WIDTH_4		BIT(1)
+#define BUS_WIDTH_4_SUPPORT	BIT(3)
+#define BUS_WIDTH_4		BIT(2)
 #define BUS_WIDTH_1		BIT(0)
 
 #define MMC_VDD_360		23
@@ -339,13 +339,7 @@
 				return;
 			}
 			for (len = 0; len < remain && len < host->fifo_width;) {
-				/* SCR data must be read in big endian. */
-				if (data->mrq->cmd->opcode == SD_APP_SEND_SCR)
-					*sgp = ioread32be(host->base +
-							  REG_DATA_WINDOW);
-				else
-					*sgp = ioread32(host->base +
-							REG_DATA_WINDOW);
+				*sgp = ioread32(host->base + REG_DATA_WINDOW);
 				sgp++;
 				len += 4;
 			}
@@ -527,9 +521,6 @@
 	case MMC_BUS_WIDTH_4:
 		writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH);
 		break;
-	case MMC_BUS_WIDTH_8:
-		writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH);
-		break;
 	default:
 		writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH);
 		break;
@@ -631,6 +622,7 @@
 			 host->dma_chan_tx, host->dma_chan_rx);
 		host->have_dma = true;
 
+		memset(&cfg, 0, sizeof(cfg));
 		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
@@ -645,16 +637,8 @@
 		dmaengine_slave_config(host->dma_chan_rx, &cfg);
 	}
 
-	switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) {
-	case 1:
+	if (readl(host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT)
 		mmc->caps |= MMC_CAP_4_BIT_DATA;
-		break;
-	case 2:
-		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
-		break;
-	default:
-		break;
-	}
 
 	writel(0, host->base + REG_INTERRUPT_MASK);
 
@@ -670,7 +654,9 @@
 		goto out;
 
 	dev_set_drvdata(dev, mmc);
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto out;
 
 	dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width);
 
@@ -695,12 +681,12 @@
 		if (!IS_ERR(host->dma_chan_rx))
 			dma_release_channel(host->dma_chan_rx);
 		mmc_remove_host(mmc);
-		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);
+		mmc_free_host(mmc);
 	}
 	return 0;
 }
@@ -717,6 +703,7 @@
 	.remove     = moxart_remove,
 	.driver     = {
 		.name		= "mmc-moxart",
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table	= moxart_mmc_match,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/mtk-sd.c
+++ linux-ein-5.4.0/drivers/mmc/host/mtk-sd.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/reset.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/core.h>
@@ -228,6 +229,7 @@
 #define MSDC_PATCH_BIT_SPCPUSH    (0x1 << 29)	/* RW */
 #define MSDC_PATCH_BIT_DECRCTMO   (0x1 << 30)	/* RW */
 
+#define MSDC_PATCH_BIT1_CMDTA     (0x7 << 3)    /* RW */
 #define MSDC_PATCH_BIT1_STOP_DLY  (0xf << 8)    /* RW */
 
 #define MSDC_PATCH_BIT2_CFGRESP   (0x1 << 15)   /* RW */
@@ -411,6 +413,7 @@
 	struct pinctrl_state *pins_uhs;
 	struct delayed_work req_timeout;
 	int irq;		/* host interrupt */
+	struct reset_control *reset;
 
 	struct clk *src_clk;	/* msdc source clock */
 	struct clk *h_clk;      /* msdc h_clk */
@@ -1017,13 +1020,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);
@@ -1043,7 +1046,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
@@ -1064,6 +1067,7 @@
 
 	if (done)
 		return true;
+	rsp = cmd->resp;
 
 	sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 
@@ -1251,7 +1255,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 &
@@ -1267,6 +1271,7 @@
 
 	if (done)
 		return true;
+	stop = data->stop;
 
 	if (check_data || (stop && stop->error)) {
 		dev_dbg(host->dev, "DMA status: 0x%8X\n",
@@ -1473,6 +1478,12 @@
 	u32 val;
 	u32 tune_reg = host->dev_comp->pad_tune_reg;
 
+	if (host->reset) {
+		reset_control_assert(host->reset);
+		usleep_range(10, 50);
+		reset_control_deassert(host->reset);
+	}
+
 	/* Configure to MMC/SD mode, clock free running */
 	sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
 
@@ -1881,6 +1892,7 @@
 
 	/* select EMMC50 PAD CMD tune */
 	sdr_set_bits(host->base + PAD_CMD_TUNE, BIT(0));
+	sdr_set_field(host->base + MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMDTA, 2);
 
 	if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
 	    mmc->ios.timing == MMC_TIMING_UHS_SDR104)
@@ -2230,9 +2242,14 @@
 	if (IS_ERR(host->src_clk_cg))
 		host->src_clk_cg = NULL;
 
+	host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+								"hrst");
+	if (IS_ERR(host->reset))
+		return PTR_ERR(host->reset);
+
 	host->irq = platform_get_irq(pdev, 0);
 	if (host->irq < 0) {
-		ret = -EINVAL;
+		ret = host->irq;
 		goto host_free;
 	}
 
@@ -2472,6 +2489,7 @@
 	.remove = msdc_drv_remove,
 	.driver = {
 		.name = "mtk-msdc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = msdc_of_ids,
 		.pm = &msdc_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/mvsdio.c
+++ linux-ein-5.4.0/drivers/mmc/host/mvsdio.c
@@ -696,17 +696,15 @@
 	struct mmc_host *mmc = NULL;
 	struct mvsd_host *host = NULL;
 	const struct mbus_dram_target_info *dram;
-	struct resource *r;
 	int ret, irq;
 
 	if (!np) {
 		dev_err(&pdev->dev, "no DT node\n");
 		return -ENODEV;
 	}
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (!r || irq < 0)
-		return -ENXIO;
+	if (irq < 0)
+		return irq;
 
 	mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev);
 	if (!mmc) {
@@ -758,7 +756,7 @@
 
 	spin_lock_init(&host->lock);
 
-	host->base = devm_ioremap_resource(&pdev->dev, r);
+	host->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(host->base)) {
 		ret = PTR_ERR(host->base);
 		goto out;
@@ -828,6 +826,7 @@
 	.remove		= mvsd_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = mvsdio_dt_ids,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/mxcmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/mxcmmc.c
@@ -1158,7 +1158,9 @@
 
 	timer_setup(&host->watchdog, mxcmci_watchdog, 0);
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto out_free_dma;
 
 	return 0;
 
@@ -1235,6 +1237,7 @@
 	.id_table	= mxcmci_devtype,
 	.driver		= {
 		.name		= DRIVER_NAME,
+		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &mxcmci_pm_ops,
 		.of_match_table	= mxcmci_of_match,
 	}
--- linux-ein-5.4.0.orig/drivers/mmc/host/mxs-mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/mxs-mmc.c
@@ -565,6 +565,11 @@
 };
 MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
 
+static void mxs_mmc_regulator_disable(void *regulator)
+{
+	regulator_disable(regulator);
+}
+
 static int mxs_mmc_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *of_id =
@@ -606,6 +611,11 @@
 				"Failed to enable vmmc regulator: %d\n", ret);
 			goto out_mmc_free;
 		}
+
+		ret = devm_add_action_or_reset(&pdev->dev, mxs_mmc_regulator_disable,
+					       reg_vmmc);
+		if (ret)
+			goto out_mmc_free;
 	}
 
 	ssp->clk = devm_clk_get(&pdev->dev, NULL);
@@ -644,7 +654,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;
 
@@ -727,6 +737,7 @@
 	.id_table	= mxs_ssp_ids,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &mxs_mmc_pm_ops,
 		.of_match_table = mxs_mmc_dt_ids,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/omap.c
+++ linux-ein-5.4.0/drivers/mmc/host/omap.c
@@ -1344,7 +1344,7 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
-		return -ENXIO;
+		return irq;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	host->virt_base = devm_ioremap_resource(&pdev->dev, res);
@@ -1504,6 +1504,7 @@
 	.remove		= mmc_omap_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(mmc_omap_match),
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/omap_hsmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/omap_hsmmc.c
@@ -1512,6 +1512,36 @@
 
 	if (mmc_pdata(host)->init_card)
 		mmc_pdata(host)->init_card(card);
+	else if (card->type == MMC_TYPE_SDIO ||
+		 card->type == MMC_TYPE_SD_COMBO) {
+		struct device_node *np = mmc_dev(mmc)->of_node;
+
+		/*
+		 * REVISIT: should be moved to sdio core and made more
+		 * general e.g. by expanding the DT bindings of child nodes
+		 * to provide a mechanism to provide this information:
+		 * Documentation/devicetree/bindings/mmc/mmc-card.txt
+		 */
+
+		np = of_get_compatible_child(np, "ti,wl1251");
+		if (np) {
+			/*
+			 * We have TI wl1251 attached to MMC3. Pass this
+			 * information to the SDIO core because it can't be
+			 * probed by normal methods.
+			 */
+
+			dev_info(host->dev, "found wl1251\n");
+			card->quirks |= MMC_QUIRK_NONSTD_SDIO;
+			card->cccr.wide_bus = 1;
+			card->cis.vendor = 0x104c;
+			card->cis.device = 0x9066;
+			card->cis.blksize = 512;
+			card->cis.max_dtr = 24000000;
+			card->ocr = 0x80;
+			of_node_put(np);
+		}
+	}
 }
 
 static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1813,9 +1843,11 @@
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	irq = platform_get_irq(pdev, 0);
-	if (res == NULL || irq < 0)
+	if (!res)
 		return -ENXIO;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
 
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
@@ -1968,7 +2000,9 @@
 	if (!ret)
 		mmc->caps |= MMC_CAP_SDIO_IRQ;
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto err_irq;
 
 	if (mmc_pdata(host)->name != NULL) {
 		ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
@@ -2150,6 +2184,7 @@
 	.remove		= omap_hsmmc_remove,
 	.driver		= {
 		.name = DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm = &omap_hsmmc_dev_pm_ops,
 		.of_match_table = of_match_ptr(omap_mmc_of_match),
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/pxamci.c
+++ linux-ein-5.4.0/drivers/mmc/host/pxamci.c
@@ -648,7 +648,7 @@
 
 	ret = pxamci_of_init(pdev, mmc);
 	if (ret)
-		return ret;
+		goto out;
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
@@ -672,7 +672,7 @@
 
 	ret = pxamci_init_ocr(host);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	mmc->caps = 0;
 	host->cmdat = 0;
@@ -729,6 +729,7 @@
 
 		host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
 		if (IS_ERR(host->power)) {
+			ret = PTR_ERR(host->power);
 			dev_err(dev, "Failed requesting gpio_power\n");
 			goto out;
 		}
@@ -740,16 +741,16 @@
 			goto out;
 		}
 
+		if (!host->pdata->gpio_card_ro_invert)
+			mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+
 		ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0, NULL);
 		if (ret && ret != -ENOENT) {
 			dev_err(dev, "Failed requesting gpio_ro\n");
 			goto out;
 		}
-		if (!ret) {
+		if (!ret)
 			host->use_ro_gpio = true;
-			mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
-				0 : MMC_CAP2_RO_ACTIVE_HIGH;
-		}
 
 		if (host->pdata->init)
 			host->pdata->init(dev, pxamci_detect_irq, mmc);
@@ -760,7 +761,12 @@
 			dev_warn(dev, "gpio_ro and get_ro() both defined\n");
 	}
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		if (host->pdata && host->pdata->exit)
+			host->pdata->exit(dev, mmc);
+		goto out;
+	}
 
 	return 0;
 
@@ -809,6 +815,7 @@
 	.remove		= pxamci_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(pxa_mmc_dt_ids),
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/renesas_sdhi_core.c
+++ linux-ein-5.4.0/drivers/mmc/host/renesas_sdhi_core.c
@@ -349,10 +349,10 @@
 			SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
 			sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
 
-	/* Set the sampling clock selection range of HS400 mode */
 	sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
 		       SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
-		       0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
+		       sd_scc_read32(host, priv,
+				     SH_MOBILE_SDHI_SCC_DTCNTL));
 
 
 	if (host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400)
@@ -874,6 +874,7 @@
 
 	tmio_mmc_host_remove(host);
 	renesas_sdhi_clk_disable(host);
+	tmio_mmc_host_free(host);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ linux-ein-5.4.0/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -186,8 +186,8 @@
 			mmc_get_dma_dir(data)))
 		goto force_pio;
 
-	/* This DMAC cannot handle if buffer is not 8-bytes alignment */
-	if (!IS_ALIGNED(sg_dma_address(sg), 8))
+	/* This DMAC cannot handle if buffer is not 128-bytes alignment */
+	if (!IS_ALIGNED(sg_dma_address(sg), 128))
 		goto force_pio_with_unmap;
 
 	if (data->flags & MMC_DATA_READ) {
@@ -229,15 +229,12 @@
 					    DTRAN_CTRL_DM_START);
 }
 
-static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
+static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
 {
-	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
 	enum dma_data_direction dir;
 
-	spin_lock_irq(&host->lock);
-
 	if (!host->data)
-		goto out;
+		return false;
 
 	if (host->data->flags & MMC_DATA_READ)
 		dir = DMA_FROM_DEVICE;
@@ -250,6 +247,17 @@
 	if (dir == DMA_FROM_DEVICE)
 		clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
 
+	return true;
+}
+
+static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
+{
+	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+	spin_lock_irq(&host->lock);
+	if (!renesas_sdhi_internal_dmac_complete(host))
+		goto out;
+
 	tmio_mmc_do_data_irq(host);
 out:
 	spin_unlock_irq(&host->lock);
--- linux-ein-5.4.0.orig/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -37,10 +37,7 @@
 	bool			double_clk;
 	bool			eject;
 	bool			initial_mode;
-	int			power_state;
-#define SDMMC_POWER_ON		1
-#define SDMMC_POWER_OFF		0
-
+	int			prev_power_state;
 	int			sg_count;
 	s32			cookie;
 	int			cookie_sg_count;
@@ -539,9 +536,22 @@
 	return 0;
 }
 
+static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
+{
+	rtsx_pci_write_register(host->pcr, SD_CFG1,
+			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128);
+}
+
+static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host)
+{
+	rtsx_pci_write_register(host->pcr, SD_CFG1,
+			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
+}
+
 static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
 {
 	struct mmc_data *data = mrq->data;
+	int err;
 
 	if (host->sg_count < 0) {
 		data->error = host->sg_count;
@@ -550,22 +560,19 @@
 		return data->error;
 	}
 
-	if (data->flags & MMC_DATA_READ)
-		return sd_read_long_data(host, mrq);
+	if (data->flags & MMC_DATA_READ) {
+		if (host->initial_mode)
+			sd_disable_initial_mode(host);
 
-	return sd_write_long_data(host, mrq);
-}
+		err = sd_read_long_data(host, mrq);
 
-static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
-{
-	rtsx_pci_write_register(host->pcr, SD_CFG1,
-			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128);
-}
+		if (host->initial_mode)
+			sd_enable_initial_mode(host);
 
-static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host)
-{
-	rtsx_pci_write_register(host->pcr, SD_CFG1,
-			SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
+		return err;
+	}
+
+	return sd_write_long_data(host, mrq);
 }
 
 static void sd_normal_rw(struct realtek_pci_sdmmc *host,
@@ -606,19 +613,22 @@
 		u8 sample_point, bool rx)
 {
 	struct rtsx_pcr *pcr = host->pcr;
-
+	u16 SD_VP_CTL = 0;
 	dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
 			__func__, rx ? "RX" : "TX", sample_point);
 
 	rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
-	if (rx)
+	if (rx) {
+		SD_VP_CTL = SD_VPRX_CTL;
 		rtsx_pci_write_register(pcr, SD_VPRX_CTL,
 			PHASE_SELECT_MASK, sample_point);
-	else
+	} else {
+		SD_VP_CTL = SD_VPTX_CTL;
 		rtsx_pci_write_register(pcr, SD_VPTX_CTL,
 			PHASE_SELECT_MASK, sample_point);
-	rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
-	rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET,
+	}
+	rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET, 0);
+	rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET,
 				PHASE_NOT_RESET);
 	rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
 	rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
@@ -889,14 +899,21 @@
 	return err;
 }
 
-static int sd_power_on(struct realtek_pci_sdmmc *host)
+static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode)
 {
 	struct rtsx_pcr *pcr = host->pcr;
 	int err;
 
-	if (host->power_state == SDMMC_POWER_ON)
+	if (host->prev_power_state == MMC_POWER_ON)
 		return 0;
 
+	if (host->prev_power_state == MMC_POWER_UP) {
+		rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0);
+		goto finish;
+	}
+
+	msleep(100);
+
 	rtsx_pci_init_cmd(pcr);
 	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
 	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE,
@@ -915,11 +932,17 @@
 	if (err < 0)
 		return err;
 
+	mdelay(1);
+
 	err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
 	if (err < 0)
 		return err;
 
-	host->power_state = SDMMC_POWER_ON;
+	/* send at least 74 clocks */
+	rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN);
+
+finish:
+	host->prev_power_state = power_mode;
 	return 0;
 }
 
@@ -928,7 +951,7 @@
 	struct rtsx_pcr *pcr = host->pcr;
 	int err;
 
-	host->power_state = SDMMC_POWER_OFF;
+	host->prev_power_state = MMC_POWER_OFF;
 
 	rtsx_pci_init_cmd(pcr);
 
@@ -954,7 +977,7 @@
 	if (power_mode == MMC_POWER_OFF)
 		err = sd_power_off(host);
 	else
-		err = sd_power_on(host);
+		err = sd_power_on(host, power_mode);
 
 	return err;
 }
@@ -1389,10 +1412,11 @@
 
 	host = mmc_priv(mmc);
 	host->pcr = pcr;
+	mmc->ios.power_delay_ms = 5;
 	host->mmc = mmc;
 	host->pdev = pdev;
 	host->cookie = -1;
-	host->power_state = SDMMC_POWER_OFF;
+	host->prev_power_state = MMC_POWER_OFF;
 	INIT_WORK(&host->work, sd_request);
 	platform_set_drvdata(pdev, host);
 	pcr->slots[RTSX_SD_CARD].p_dev = pdev;
@@ -1466,6 +1490,7 @@
 	.id_table       = rtsx_pci_sdmmc_ids,
 	.driver		= {
 		.name	= DRV_NAME_RTSX_PCI_SDMMC,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 };
 module_platform_driver(rtsx_pci_sdmmc_driver);
--- linux-ein-5.4.0.orig/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -1338,6 +1338,7 @@
 #ifdef RTSX_USB_USE_LEDS_CLASS
 	int err;
 #endif
+	int ret;
 
 	ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
 	if (!ucr)
@@ -1374,7 +1375,15 @@
 	INIT_WORK(&host->led_work, rtsx_usb_update_led);
 
 #endif
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret) {
+#ifdef RTSX_USB_USE_LEDS_CLASS
+		led_classdev_unregister(&host->led);
+#endif
+		mmc_free_host(mmc);
+		pm_runtime_disable(&pdev->dev);
+		return ret;
+	}
 
 	return 0;
 }
@@ -1459,6 +1468,7 @@
 	.id_table       = rtsx_usb_sdmmc_ids,
 	.driver		= {
 		.name	= "rtsx_usb_sdmmc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &rtsx_usb_sdmmc_dev_pm_ops,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/s3cmci.c
+++ linux-ein-5.4.0/drivers/mmc/host/s3cmci.c
@@ -1816,6 +1816,7 @@
 static struct platform_driver s3cmci_driver = {
 	.driver	= {
 		.name	= "s3c-sdi",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = s3cmci_dt_match,
 	},
 	.id_table	= s3cmci_driver_ids,
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-acpi.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-acpi.c
@@ -532,6 +532,11 @@
 	.caps    = MMC_CAP_NONREMOVABLE,
 };
 
+struct amd_sdhci_host {
+	bool	tuned_clock;
+	bool	dll_enabled;
+};
+
 /* AMD sdhci reset dll register. */
 #define SDHCI_AMD_RESET_DLL_REGISTER    0x908
 
@@ -542,39 +547,96 @@
 	return MMC_SET_DRIVER_TYPE_A;
 }
 
-static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
+static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable)
 {
+	struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+	struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
 	/* AMD Platform requires dll setting */
 	sdhci_writel(host, 0x40003210, SDHCI_AMD_RESET_DLL_REGISTER);
 	usleep_range(10, 20);
-	sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER);
+	if (enable)
+		sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER);
+
+	amd_host->dll_enabled = enable;
 }
 
 /*
- * For AMD Platform it is required to disable the tuning
- * bit first controller to bring to HS Mode from HS200
- * mode, later enable to tune to HS400 mode.
+ * The initialization sequence for HS400 is:
+ *     HS->HS200->Perform Tuning->HS->HS400
+ *
+ * The re-tuning sequence is:
+ *     HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
+ *
+ * The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400
+ * mode. If we switch to a different mode, we need to disable the tuned clock.
+ * If we have previously performed tuning and switch back to HS200 or
+ * HS400, we can re-enable the tuned clock.
+ *
  */
 static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+	struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
 	unsigned int old_timing = host->timing;
+	u16 val;
 
 	sdhci_set_ios(mmc, ios);
-	if (old_timing == MMC_TIMING_MMC_HS200 &&
-	    ios->timing == MMC_TIMING_MMC_HS)
-		sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2);
-	if (old_timing != MMC_TIMING_MMC_HS400 &&
-	    ios->timing == MMC_TIMING_MMC_HS400) {
-		sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2);
-		sdhci_acpi_amd_hs400_dll(host);
+
+	if (old_timing != host->timing && amd_host->tuned_clock) {
+		if (host->timing == MMC_TIMING_MMC_HS400 ||
+		    host->timing == MMC_TIMING_MMC_HS200) {
+			val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+			val |= SDHCI_CTRL_TUNED_CLK;
+			sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+		} else {
+			val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+			val &= ~SDHCI_CTRL_TUNED_CLK;
+			sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+		}
+
+		/* DLL is only required for HS400 */
+		if (host->timing == MMC_TIMING_MMC_HS400 &&
+		    !amd_host->dll_enabled)
+			sdhci_acpi_amd_hs400_dll(host, true);
+	}
+}
+
+static int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	int err;
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+	struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
+	amd_host->tuned_clock = false;
+
+	err = sdhci_execute_tuning(mmc, opcode);
+
+	if (!err && !host->tuning_err)
+		amd_host->tuned_clock = true;
+
+	return err;
+}
+
+static void amd_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+	struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
+	if (mask & SDHCI_RESET_ALL) {
+		amd_host->tuned_clock = false;
+		sdhci_acpi_amd_hs400_dll(host, false);
 	}
+
+	sdhci_reset(host, mask);
 }
 
 static const struct sdhci_ops sdhci_acpi_ops_amd = {
 	.set_clock	= sdhci_set_clock,
 	.set_bus_width	= sdhci_set_bus_width,
-	.reset		= sdhci_reset,
+	.reset		= amd_sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
@@ -596,17 +658,58 @@
 	    (host->mmc->caps & MMC_CAP_1_8V_DDR))
 		host->mmc->caps2 = MMC_CAP2_HS400_1_8V;
 
+	/*
+	 * There are two types of presets out in the wild:
+	 * 1) Default/broken presets.
+	 *    These presets have two sets of problems:
+	 *    a) The clock divisor for SDR12, SDR25, and SDR50 is too small.
+	 *       This results in clock frequencies that are 2x higher than
+	 *       acceptable. i.e., SDR12 = 25 MHz, SDR25 = 50 MHz, SDR50 =
+	 *       100 MHz.x
+	 *    b) The HS200 and HS400 driver strengths don't match.
+	 *       By default, the SDR104 preset register has a driver strength of
+	 *       A, but the (internal) HS400 preset register has a driver
+	 *       strength of B. As part of initializing HS400, HS200 tuning
+	 *       needs to be performed. Having different driver strengths
+	 *       between tuning and operation is wrong. It results in different
+	 *       rise/fall times that lead to incorrect sampling.
+	 * 2) Firmware with properly initialized presets.
+	 *    These presets have proper clock divisors. i.e., SDR12 => 12MHz,
+	 *    SDR25 => 25 MHz, SDR50 => 50 MHz. Additionally the HS200 and
+	 *    HS400 preset driver strengths match.
+	 *
+	 *    Enabling presets for HS400 doesn't work for the following reasons:
+	 *    1) sdhci_set_ios has a hard coded list of timings that are used
+	 *       to determine if presets should be enabled.
+	 *    2) sdhci_get_preset_value is using a non-standard register to
+	 *       read out HS400 presets. The AMD controller doesn't support this
+	 *       non-standard register. In fact, it doesn't expose the HS400
+	 *       preset register anywhere in the SDHCI memory map. This results
+	 *       in reading a garbage value and using the wrong presets.
+	 *
+	 *       Since HS400 and HS200 presets must be identical, we could
+	 *       instead use the the SDR104 preset register.
+	 *
+	 *    If the above issues are resolved we could remove this quirk for
+	 *    firmware that that has valid presets (i.e., SDR12 <= 12 MHz).
+	 */
+	host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+
 	host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
 	host->mmc_host_ops.set_ios = amd_set_ios;
+	host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
 	return 0;
 }
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
-	.chip   = &sdhci_acpi_chip_amd,
-	.caps   = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
-	.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE |
-			SDHCI_QUIRK_32BIT_ADMA_SIZE,
+	.chip		= &sdhci_acpi_chip_amd,
+	.caps		= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+	.quirks		= SDHCI_QUIRK_32BIT_DMA_ADDR |
+			  SDHCI_QUIRK_32BIT_DMA_SIZE |
+			  SDHCI_QUIRK_32BIT_ADMA_SIZE,
+	.quirks2	= SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
 	.probe_slot     = sdhci_acpi_emmc_amd_probe_slot,
+	.priv_size	= sizeof(struct amd_sdhci_host),
 };
 
 struct sdhci_acpi_uid_slot {
@@ -732,7 +835,7 @@
 	host->ops	= &sdhci_acpi_ops_dflt;
 	host->irq	= platform_get_irq(pdev, 0);
 	if (host->irq < 0) {
-		err = -EINVAL;
+		err = host->irq;
 		goto err_free;
 	}
 
@@ -897,6 +1000,7 @@
 static struct platform_driver sdhci_acpi_driver = {
 	.driver = {
 		.name			= "sdhci-acpi",
+		.probe_type		= PROBE_PREFER_ASYNCHRONOUS,
 		.acpi_match_table	= sdhci_acpi_ids,
 		.pm			= &sdhci_acpi_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-bcm-kona.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-bcm-kona.c
@@ -324,6 +324,7 @@
 static struct platform_driver sdhci_bcm_kona_driver = {
 	.driver		= {
 		.name	= "sdhci-kona",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &sdhci_pltfm_pmops,
 		.of_match_table = sdhci_bcm_kona_of_match,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-cadence.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-cadence.c
@@ -11,6 +11,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "sdhci-pltfm.h"
 
@@ -193,52 +194,6 @@
 	return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
 }
 
-static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
-					 unsigned int timing)
-{
-	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
-	u32 mode;
-
-	switch (timing) {
-	case MMC_TIMING_MMC_HS:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
-		break;
-	case MMC_TIMING_MMC_DDR52:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
-		break;
-	case MMC_TIMING_MMC_HS200:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
-		break;
-	case MMC_TIMING_MMC_HS400:
-		if (priv->enhanced_strobe)
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
-		else
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
-		break;
-	default:
-		mode = SDHCI_CDNS_HRS06_MODE_SD;
-		break;
-	}
-
-	sdhci_cdns_set_emmc_mode(priv, mode);
-
-	/* For SD, fall back to the default handler */
-	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
-		sdhci_set_uhs_signaling(host, timing);
-}
-
-static const struct sdhci_ops sdhci_cdns_ops = {
-	.set_clock = sdhci_set_clock,
-	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
-	.set_bus_width = sdhci_set_bus_width,
-	.reset = sdhci_reset,
-	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
-};
-
-static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
-	.ops = &sdhci_cdns_ops,
-};
-
 static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
 {
 	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
@@ -272,23 +227,24 @@
 	return 0;
 }
 
-static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
+/*
+ * In SD mode, software must not use the hardware tuning and instead perform
+ * an almost identical procedure to eMMC.
+ */
+static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
-	struct sdhci_host *host = mmc_priv(mmc);
 	int cur_streak = 0;
 	int max_streak = 0;
 	int end_of_streak = 0;
 	int i;
 
 	/*
-	 * This handler only implements the eMMC tuning that is specific to
-	 * this controller.  Fall back to the standard method for SD timing.
+	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
+	 * The delay is set by probe, based on the DT properties.
 	 */
-	if (host->timing != MMC_TIMING_MMC_HS200)
-		return sdhci_execute_tuning(mmc, opcode);
-
-	if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
-		return -EINVAL;
+	if (host->timing != MMC_TIMING_MMC_HS200 &&
+	    host->timing != MMC_TIMING_UHS_SDR104)
+		return 0;
 
 	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
 		if (sdhci_cdns_set_tune_val(host, i) ||
@@ -311,6 +267,58 @@
 	return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
 }
 
+static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
+					 unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 mode;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		if (priv->enhanced_strobe)
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
+		else
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+		break;
+	default:
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+		break;
+	}
+
+	sdhci_cdns_set_emmc_mode(priv, mode);
+
+	/* For SD, fall back to the default handler */
+	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
+		sdhci_set_uhs_signaling(host, timing);
+}
+
+static const struct sdhci_ops sdhci_cdns_ops = {
+	.set_clock = sdhci_set_clock,
+	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
+	.platform_execute_tuning = sdhci_cdns_execute_tuning,
+	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
+	.ops = &sdhci_cdns_ops,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
+	.ops = &sdhci_cdns_ops,
+};
+
 static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
 					     struct mmc_ios *ios)
 {
@@ -334,6 +342,7 @@
 static int sdhci_cdns_probe(struct platform_device *pdev)
 {
 	struct sdhci_host *host;
+	const struct sdhci_pltfm_data *data;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_cdns_priv *priv;
 	struct clk *clk;
@@ -350,8 +359,12 @@
 	if (ret)
 		return ret;
 
+	data = of_device_get_match_data(dev);
+	if (!data)
+		data = &sdhci_cdns_pltfm_data;
+
 	nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
-	host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data,
+	host = sdhci_pltfm_init(pdev, data,
 				struct_size(priv, phy_params, nr_phy_params));
 	if (IS_ERR(host)) {
 		ret = PTR_ERR(host);
@@ -366,7 +379,6 @@
 	priv->hrs_addr = host->ioaddr;
 	priv->enhanced_strobe = false;
 	host->ioaddr += SDHCI_CDNS_SRS_BASE;
-	host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
 	host->mmc_host_ops.hs400_enhanced_strobe =
 				sdhci_cdns_hs400_enhanced_strobe;
 	sdhci_enable_v4_mode(host);
@@ -431,7 +443,10 @@
 };
 
 static const struct of_device_id sdhci_cdns_match[] = {
-	{ .compatible = "socionext,uniphier-sd4hc" },
+	{
+		.compatible = "socionext,uniphier-sd4hc",
+		.data = &sdhci_cdns_uniphier_pltfm_data,
+	},
 	{ .compatible = "cdns,sd4hc" },
 	{ /* sentinel */ }
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-cns3xxx.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-cns3xxx.c
@@ -98,6 +98,7 @@
 static struct platform_driver sdhci_cns3xxx_driver = {
 	.driver		= {
 		.name	= "sdhci-cns3xxx",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &sdhci_pltfm_pmops,
 	},
 	.probe		= sdhci_cns3xxx_probe,
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-cqhci.h
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-cqhci.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2022 The Chromium OS Authors
+ *
+ * Support that applies to the combination of SDHCI and CQHCI, while not
+ * expressing a dependency between the two modules.
+ */
+
+#ifndef __MMC_HOST_SDHCI_CQHCI_H__
+#define __MMC_HOST_SDHCI_CQHCI_H__
+
+#include "cqhci.h"
+#include "sdhci.h"
+
+static inline void sdhci_and_cqhci_reset(struct sdhci_host *host, u8 mask)
+{
+	if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
+	    host->mmc->cqe_private)
+		cqhci_deactivate(host->mmc);
+
+	sdhci_reset(host, mask);
+}
+
+#endif /* __MMC_HOST_SDHCI_CQHCI_H__ */
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-dove.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-dove.c
@@ -105,6 +105,7 @@
 static struct platform_driver sdhci_dove_driver = {
 	.driver		= {
 		.name	= "sdhci-dove",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &sdhci_pltfm_pmops,
 		.of_match_table = sdhci_dove_of_match_table,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-esdhc-imx.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -8,7 +8,9 @@
  *   Author: Wolfram Sang <kernel@pengutronix.de>
  */
 
+#include <linux/bitfield.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -24,6 +26,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/mmc-esdhc-imx.h>
 #include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 #include "cqhci.h"
@@ -36,6 +39,16 @@
 #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK	(1 << 1)
 #define  ESDHC_VENDOR_SPEC_VSELECT	(1 << 1)
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
+#define ESDHC_DEBUG_SEL_AND_STATUS_REG		0xc2
+#define ESDHC_DEBUG_SEL_REG			0xc3
+#define ESDHC_DEBUG_SEL_MASK			0xf
+#define ESDHC_DEBUG_SEL_CMD_STATE		1
+#define ESDHC_DEBUG_SEL_DATA_STATE		2
+#define ESDHC_DEBUG_SEL_TRANS_STATE		3
+#define ESDHC_DEBUG_SEL_DMA_STATE		4
+#define ESDHC_DEBUG_SEL_ADMA_STATE		5
+#define ESDHC_DEBUG_SEL_FIFO_STATE		6
+#define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE	7
 #define ESDHC_WTMK_LVL			0x44
 #define  ESDHC_WTMK_DEFAULT_VAL		0x10401040
 #define  ESDHC_WTMK_LVL_RD_WML_MASK	0x000000FF
@@ -73,6 +86,7 @@
 #define ESDHC_STROBE_DLL_CTRL		0x70
 #define ESDHC_STROBE_DLL_CTRL_ENABLE	(1 << 0)
 #define ESDHC_STROBE_DLL_CTRL_RESET	(1 << 1)
+#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT	0x7
 #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT	3
 #define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT	(4 << 20)
 
@@ -87,7 +101,9 @@
 #define ESDHC_STD_TUNING_EN		(1 << 24)
 /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
 #define ESDHC_TUNING_START_TAP_DEFAULT	0x1
-#define ESDHC_TUNING_START_TAP_MASK	0xff
+#define ESDHC_TUNING_START_TAP_MASK	0x7f
+#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE	(1 << 7)
+#define ESDHC_TUNING_STEP_DEFAULT	0x1
 #define ESDHC_TUNING_STEP_MASK		0x00070000
 #define ESDHC_TUNING_STEP_SHIFT		16
 
@@ -150,8 +166,8 @@
 #define ESDHC_FLAG_HS400		BIT(9)
 /*
  * The IP has errata ERR010450
- * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't
- * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
+ * uSDHC: At 1.8V due to the I/O timing limit, for SDR mode, SD card
+ * clock can't exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
  */
 #define ESDHC_FLAG_ERR010450		BIT(10)
 /* The IP supports HS400ES mode */
@@ -160,6 +176,22 @@
 #define ESDHC_FLAG_CQHCI		BIT(12)
 /* need request pmqos during low power */
 #define ESDHC_FLAG_PMQOS		BIT(13)
+/* The IP state got lost in low power mode */
+#define ESDHC_FLAG_STATE_LOST_IN_LPMODE		BIT(14)
+/* The IP lost clock rate in PM_RUNTIME */
+#define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME	BIT(15)
+/*
+ * The IP do not support the ACMD23 feature completely when use ADMA mode.
+ * In ADMA mode, it only use the 16 bit block count of the register 0x4
+ * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will
+ * ignore the upper 16 bit of the CMD23's argument. This will block the reliable
+ * write operation in RPMB, because RPMB reliable write need to set the bit31
+ * of the CMD23's argument.
+ * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA
+ * do not has this limitation. so when these SoC use ADMA mode, it need to
+ * disable the ACMD23 feature.
+ */
+#define ESDHC_FLAG_BROKEN_AUTO_CMD23	BIT(16)
 
 struct esdhc_soc_data {
 	u32 flags;
@@ -182,49 +214,71 @@
 };
 
 static const struct esdhc_soc_data usdhc_imx6q_data = {
-	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING,
+	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
+			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
 };
 
 static const struct esdhc_soc_data usdhc_imx6sl_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536
-			| ESDHC_FLAG_HS200,
+			| ESDHC_FLAG_HS200
+			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
+};
+
+static const struct esdhc_soc_data usdhc_imx6sll_data = {
+	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+			| ESDHC_FLAG_HS400
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static const struct esdhc_soc_data usdhc_imx6sx_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
-			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
+			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
+			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
 };
 
 static const struct esdhc_soc_data usdhc_imx6ull_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_ERR010450,
+			| ESDHC_FLAG_ERR010450
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static const struct esdhc_soc_data usdhc_imx7d_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_HS400,
+			| ESDHC_FLAG_HS400
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
+			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
 };
 
 static struct esdhc_soc_data usdhc_imx7ulp_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400,
+			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static struct esdhc_soc_data usdhc_imx8qxp_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
-			| ESDHC_FLAG_CQHCI,
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
+			| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
+};
+
+static struct esdhc_soc_data usdhc_imx8mm_data = {
+	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 struct pltfm_imx_data {
 	u32 scratchpad;
 	struct pinctrl *pinctrl;
-	struct pinctrl_state *pins_default;
 	struct pinctrl_state *pins_100mhz;
 	struct pinctrl_state *pins_200mhz;
 	const struct esdhc_soc_data *socdata;
@@ -265,11 +319,13 @@
 	{ .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, },
 	{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
 	{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
+	{ .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, },
 	{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
 	{ .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },
 	{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
 	{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
 	{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },
+	{ .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -302,6 +358,45 @@
 	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
 }
 
+#define DRIVER_NAME "sdhci-esdhc-imx"
+#define ESDHC_IMX_DUMP(f, x...) \
+	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+static void esdhc_dump_debug_regs(struct sdhci_host *host)
+{
+	int i;
+	char *debug_status[7] = {
+				 "cmd debug status",
+				 "data debug status",
+				 "trans debug status",
+				 "dma debug status",
+				 "adma debug status",
+				 "fifo debug status",
+				 "async fifo debug status"
+	};
+
+	ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n");
+	for (i = 0; i < 7; i++) {
+		esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK,
+			ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG);
+		ESDHC_IMX_DUMP("%s:  0x%04x\n", debug_status[i],
+			readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG));
+	}
+
+	esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG);
+
+}
+
+static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
+{
+	u32 present_state;
+	int ret;
+
+	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
+				(present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
+	if (ret == -ETIMEDOUT)
+		dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
+}
+
 static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -345,7 +440,8 @@
 				val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
 					| SDHCI_SUPPORT_SDR50
 					| SDHCI_USE_SDR50_TUNING
-					| (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT);
+					| FIELD_PREP(SDHCI_RETUNING_MODE_MASK,
+						     SDHCI_TUNING_MODE_3);
 
 			if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
 				val |= SDHCI_SUPPORT_HS400;
@@ -363,9 +459,9 @@
 
 	if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) {
 		val = 0;
-		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
-		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
-		val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT;
+		val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF);
+		val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF);
+		val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF);
 	}
 
 	if (unlikely(reg == SDHCI_INT_STATUS)) {
@@ -515,6 +611,8 @@
 		else
 			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+		if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
+			esdhc_wait_for_card_clock_gate_off(host);
 		return;
 	case SDHCI_HOST_CONTROL2:
 		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -583,10 +681,24 @@
 			 * For DMA access restore the levels to default value.
 			 */
 			m = readl(host->ioaddr + ESDHC_WTMK_LVL);
-			if (val & SDHCI_TRNS_DMA)
+			if (val & SDHCI_TRNS_DMA) {
 				wml = ESDHC_WTMK_LVL_WML_VAL_DEF;
-			else
+			} else {
+				u8 ctrl;
 				wml = ESDHC_WTMK_LVL_WML_VAL_MAX;
+
+				/*
+				 * Since already disable DMA mode, so also need
+				 * to clear the DMASEL. Otherwise, for standard
+				 * tuning, when send tuning command, usdhc will
+				 * still prefetch the ADMA script from wrong
+				 * DMA address, then we will see IOMMU report
+				 * some error which show lack of TLB mapping.
+				 */
+				ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+				ctrl &= ~SDHCI_CTRL_DMA_MASK;
+				sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+			}
 			m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK |
 			       ESDHC_WTMK_LVL_WR_WML_MASK);
 			m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) |
@@ -743,12 +855,14 @@
 	int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
 	int pre_div = 1;
 	int div = 1;
+	int ret;
 	u32 temp, val;
 
 	if (esdhc_is_usdhc(imx_data)) {
 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 		writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 			host->ioaddr + ESDHC_VENDOR_SPEC);
+		esdhc_wait_for_card_clock_gate_off(host);
 	}
 
 	if (clock == 0) {
@@ -775,7 +889,8 @@
 		| ESDHC_CLOCK_MASK);
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
-	if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) {
+	if ((imx_data->socdata->flags & ESDHC_FLAG_ERR010450) &&
+	    (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V))) {
 		unsigned int max_clock;
 
 		max_clock = imx_data->is_ddr ? 45000000 : 150000000;
@@ -803,13 +918,18 @@
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
+	/* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
+	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
+				(temp & ESDHC_CLOCK_STABLE), 2, 100);
+	if (ret == -ETIMEDOUT)
+		dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
+
 	if (esdhc_is_usdhc(imx_data)) {
 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 			host->ioaddr + ESDHC_VENDOR_SPEC);
 	}
 
-	mdelay(1);
 }
 
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
@@ -868,10 +988,20 @@
 static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
 {
 	u32 reg;
+	u8 sw_rst;
+	int ret;
 
 	/* FIXME: delay a bit for card to be ready for next tuning due to errors */
 	mdelay(1);
 
+	/* IC suggest to reset USDHC before every tuning command */
+	esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET);
+	ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst,
+				!(sw_rst & SDHCI_RESET_ALL), 10, 100);
+	if (ret == -ETIMEDOUT)
+		dev_warn(mmc_dev(host->mmc),
+		"warning! RESET_ALL never complete before sending tuning command\n");
+
 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
 	reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
 			ESDHC_MIX_CTRL_FBCLK_SEL;
@@ -951,7 +1081,6 @@
 	dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
 
 	if (IS_ERR(imx_data->pinctrl) ||
-		IS_ERR(imx_data->pins_default) ||
 		IS_ERR(imx_data->pins_100mhz) ||
 		IS_ERR(imx_data->pins_200mhz))
 		return -EINVAL;
@@ -968,7 +1097,7 @@
 		break;
 	default:
 		/* back to default state for other legacy timing */
-		pinctrl = imx_data->pins_default;
+		return pinctrl_select_default_state(mmc_dev(host->mmc));
 	}
 
 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
@@ -985,12 +1114,17 @@
  */
 static void esdhc_set_strobe_dll(struct sdhci_host *host)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+	u32 strobe_delay;
 	u32 v;
+	int ret;
 
 	/* disable clock before enabling strobe dll */
 	writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
 		~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 		host->ioaddr + ESDHC_VENDOR_SPEC);
+	esdhc_wait_for_card_clock_gate_off(host);
 
 	/* force a reset on strobe dll */
 	writel(ESDHC_STROBE_DLL_CTRL_RESET,
@@ -1002,19 +1136,21 @@
 	 * enable strobe dll ctrl and adjust the delay target
 	 * for the uSDHC loopback read clock
 	 */
+	if (imx_data->boarddata.strobe_dll_delay_target)
+		strobe_delay = imx_data->boarddata.strobe_dll_delay_target;
+	else
+		strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT;
 	v = ESDHC_STROBE_DLL_CTRL_ENABLE |
 		ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |
-		(7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
+		(strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
 	writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
-	/* wait 5us to make sure strobe dll status register stable */
-	udelay(5);
-	v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
-	if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
-		dev_warn(mmc_dev(host->mmc),
-		"warning! HS400 strobe DLL status REF not lock!\n");
-	if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
+
+	/* wait max 50us to get the REF/SLV lock */
+	ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v,
+		((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50);
+	if (ret == -ETIMEDOUT)
 		dev_warn(mmc_dev(host->mmc),
-		"warning! HS400 strobe DLL status SLV not lock!\n");
+		"warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v);
 }
 
 static void esdhc_reset_tuning(struct sdhci_host *host)
@@ -1022,6 +1158,7 @@
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
 	u32 ctrl;
+	int ret;
 
 	/* Reset the tuning circuit */
 	if (esdhc_is_usdhc(imx_data)) {
@@ -1034,7 +1171,22 @@
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
 			ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+			ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
 			writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
+			/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
+			ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
+				ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
+			if (ret == -ETIMEDOUT)
+				dev_warn(mmc_dev(host->mmc),
+				 "Warning! clear execute tuning bit failed\n");
+			/*
+			 * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
+			 * usdhc IP internal logic flag execute_tuning_with_clr_buf, which
+			 * will finally make sure the normal data transfer logic correct.
+			 */
+			ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
+			ctrl |= SDHCI_INT_DATA_AVAIL;
+			writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
 		}
 	}
 }
@@ -1150,6 +1302,7 @@
 	.set_uhs_signaling = esdhc_set_uhs_signaling,
 	.reset = esdhc_reset,
 	.irq = esdhc_cqhci_irq,
+	.dump_vendor_regs = esdhc_dump_debug_regs,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -1164,7 +1317,8 @@
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
-	int tmp;
+	struct cqhci_host *cq_host = host->mmc->cqe_private;
+	u32 tmp;
 
 	if (esdhc_is_usdhc(imx_data)) {
 		/*
@@ -1217,18 +1371,37 @@
 
 		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
 			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-			tmp |= ESDHC_STD_TUNING_EN |
-				ESDHC_TUNING_START_TAP_DEFAULT;
-			if (imx_data->boarddata.tuning_start_tap) {
-				tmp &= ~ESDHC_TUNING_START_TAP_MASK;
+			tmp |= ESDHC_STD_TUNING_EN;
+
+			/*
+			 * ROM code or bootloader may config the start tap
+			 * and step, unmask them first.
+			 */
+			tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK);
+			if (imx_data->boarddata.tuning_start_tap)
 				tmp |= imx_data->boarddata.tuning_start_tap;
-			}
+			else
+				tmp |= ESDHC_TUNING_START_TAP_DEFAULT;
 
 			if (imx_data->boarddata.tuning_step) {
-				tmp &= ~ESDHC_TUNING_STEP_MASK;
 				tmp |= imx_data->boarddata.tuning_step
 					<< ESDHC_TUNING_STEP_SHIFT;
+			} else {
+				tmp |= ESDHC_TUNING_STEP_DEFAULT
+					<< ESDHC_TUNING_STEP_SHIFT;
 			}
+
+			/* Disable the CMD CRC check for tuning, if not, need to
+			 * add some delay after every tuning command, because
+			 * hardware standard tuning logic will directly go to next
+			 * step once it detect the CMD CRC error, will not wait for
+			 * the card side to finally send out the tuning data, trigger
+			 * the buffer read ready interrupt immediately. If usdhc send
+			 * the next tuning command some eMMC card will stuck, can't
+			 * response, block the tuning procedure or the first command
+			 * after the whole tuning procedure always can't get any response.
+			 */
+			 tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE;
 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
 		} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
 			/*
@@ -1240,6 +1413,21 @@
 			tmp &= ~ESDHC_STD_TUNING_EN;
 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
 		}
+
+		/*
+		 * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
+		 * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the
+		 * the 1st linux configure power/clock for the 2nd Linux.
+		 *
+		 * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
+		 * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump.
+		 * After we clear the pending interrupt and halt CQCTL, issue gone.
+		 */
+		if (cq_host) {
+			tmp = cqhci_readl(cq_host, CQHCI_IS);
+			cqhci_writel(cq_host, tmp, CQHCI_IS);
+			cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
+		}
 	}
 }
 
@@ -1286,7 +1474,7 @@
 	 * system resume back.
 	 */
 	cqhci_writel(cq_host, 0, CQHCI_CTL);
-	if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT)
+	if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
 		dev_err(mmc_dev(host->mmc),
 			"failed to exit halt state when enable CQE\n");
 
@@ -1330,6 +1518,8 @@
 	of_property_read_u32(np, "fsl,tuning-start-tap",
 			     &boarddata->tuning_start_tap);
 
+	of_property_read_u32(np, "fsl,strobe-dll-delay-target",
+				&boarddata->strobe_dll_delay_target);
 	if (of_find_property(np, "no-1-8-v", NULL))
 		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
 
@@ -1338,7 +1528,7 @@
 
 	mmc_of_parse_voltage(np, &host->ocr_mask);
 
-	if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pins_default)) {
+	if (esdhc_is_usdhc(imx_data)) {
 		imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
 						ESDHC_PINCTRL_STATE_100MHZ);
 		imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
@@ -1381,13 +1571,14 @@
 				host->mmc->parent->platform_data);
 	/* write_protect */
 	if (boarddata->wp_type == ESDHC_WP_GPIO) {
+		host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+
 		err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0, NULL);
 		if (err) {
 			dev_err(mmc_dev(host->mmc),
 				"failed to request write-protect gpio!\n");
 			return err;
 		}
-		host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 	}
 
 	/* card_detect */
@@ -1487,19 +1678,16 @@
 		goto disable_ipg_clk;
 
 	imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
-	if (IS_ERR(imx_data->pinctrl)) {
-		err = PTR_ERR(imx_data->pinctrl);
-		goto disable_ahb_clk;
-	}
-
-	imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
-						PINCTRL_STATE_DEFAULT);
-	if (IS_ERR(imx_data->pins_default))
-		dev_warn(mmc_dev(host->mmc), "could not get default state\n");
+	if (IS_ERR(imx_data->pinctrl))
+		dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
 
 	if (esdhc_is_usdhc(imx_data)) {
 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 		host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;
+
+		/* GPIO CD can be set as a wakeup source */
+		host->mmc->caps |= MMC_CAP_CD_WAKE;
+
 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
 
@@ -1525,6 +1713,9 @@
 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
 		host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
 
+	if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
+		host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
+
 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
 		host->mmc->caps2 |= MMC_CAP2_HS400_ES;
 		host->mmc_host_ops.hs400_enhanced_strobe =
@@ -1554,8 +1745,6 @@
 	if (err)
 		goto disable_ahb_clk;
 
-	host->tuning_delay = 1;
-
 	sdhci_esdhc_imx_hwinit(host);
 
 	err = sdhci_add_host(host);
@@ -1588,9 +1777,10 @@
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
-	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);
 
@@ -1612,6 +1802,8 @@
 static int sdhci_esdhc_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
 	int ret;
 
 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
@@ -1620,10 +1812,26 @@
 			return ret;
 	}
 
+	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
+		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}
+
 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
 		mmc_retune_needed(host->mmc);
 
-	return sdhci_suspend_host(host);
+	ret = sdhci_suspend_host(host);
+	if (ret)
+		return ret;
+
+	ret = pinctrl_pm_select_sleep_state(dev);
+	if (ret)
+		return ret;
+
+	ret = mmc_gpio_set_cd_wake(host->mmc, true);
+
+	return ret;
 }
 
 static int sdhci_esdhc_resume(struct device *dev)
@@ -1631,6 +1839,10 @@
 	struct sdhci_host *host = dev_get_drvdata(dev);
 	int ret;
 
+	ret = pinctrl_pm_select_default_state(dev);
+	if (ret)
+		return ret;
+
 	/* re-initialize hw state in case it's lost in low power mode */
 	sdhci_esdhc_imx_hwinit(host);
 
@@ -1641,6 +1853,9 @@
 	if (host->mmc->caps2 & MMC_CAP2_CQE)
 		ret = cqhci_resume(host->mmc);
 
+	if (!ret)
+		ret = mmc_gpio_set_cd_wake(host->mmc, false);
+
 	return ret;
 }
 #endif
@@ -1689,6 +1904,9 @@
 		pm_qos_add_request(&imx_data->pm_qos_req,
 			PM_QOS_CPU_DMA_LATENCY, 0);
 
+	if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME)
+		clk_set_rate(imx_data->clk_per, pltfm_host->clock);
+
 	err = clk_prepare_enable(imx_data->clk_ahb);
 	if (err)
 		goto remove_pm_qos_request;
@@ -1734,6 +1952,7 @@
 static struct platform_driver sdhci_esdhc_imx_driver = {
 	.driver		= {
 		.name	= "sdhci-esdhc-imx",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = imx_esdhc_dt_ids,
 		.pm	= &sdhci_esdhc_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-esdhc.h
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-esdhc.h
@@ -5,7 +5,8 @@
  * Copyright (c) 2007 Freescale Semiconductor, Inc.
  * Copyright (c) 2009 MontaVista Software, Inc.
  * Copyright (c) 2010 Pengutronix e.K.
- *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ * Copyright 2020 NXP
+ *   Author: Wolfram Sang <kernel@pengutronix.de>
  */
 
 #ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
@@ -31,6 +32,7 @@
 
 /* Present State Register */
 #define ESDHC_PRSSTAT			0x24
+#define ESDHC_CLOCK_GATE_OFF		0x00000080
 #define ESDHC_CLOCK_STABLE		0x00000008
 
 /* Protocol Control Register */
@@ -51,6 +53,11 @@
 #define ESDHC_CLOCK_HCKEN		0x00000002
 #define ESDHC_CLOCK_IPGEN		0x00000001
 
+/* System Control 2 Register */
+#define ESDHC_SYSTEM_CONTROL_2		0x3c
+#define ESDHC_SMPCLKSEL			0x00800000
+#define ESDHC_EXTN			0x00400000
+
 /* Host Controller Capabilities Register 2 */
 #define ESDHC_CAPABILITIES_1		0x114
 
@@ -59,7 +66,16 @@
 #define ESDHC_HS400_WNDW_ADJUST		0x00000040
 #define ESDHC_HS400_MODE		0x00000010
 #define ESDHC_TB_EN			0x00000004
+#define ESDHC_TB_MODE_MASK		0x00000003
+#define ESDHC_TB_MODE_SW		0x00000003
+#define ESDHC_TB_MODE_3			0x00000002
+
+#define ESDHC_TBSTAT			0x124
+
 #define ESDHC_TBPTR			0x128
+#define ESDHC_WNDW_STRT_PTR_SHIFT	8
+#define ESDHC_WNDW_STRT_PTR_MASK	(0x7f << 8)
+#define ESDHC_WNDW_END_PTR_MASK		0x7f
 
 /* SD Clock Control Register */
 #define ESDHC_SDCLKCTL			0x144
@@ -73,6 +89,7 @@
 /* DLL Config 0 Register */
 #define ESDHC_DLLCFG0			0x160
 #define ESDHC_DLL_ENABLE		0x80000000
+#define ESDHC_DLL_RESET			0x40000000
 #define ESDHC_DLL_FREQ_SEL		0x08000000
 
 /* DLL Config 1 Register */
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-iproc.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-iproc.c
@@ -351,6 +351,7 @@
 static struct platform_driver sdhci_iproc_driver = {
 	.driver = {
 		.name = "sdhci-iproc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_iproc_of_match,
 		.acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
 		.pm = &sdhci_pltfm_pmops,
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-msm.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-msm.c
@@ -99,7 +99,7 @@
 
 #define CORE_PWRSAVE_DLL	BIT(3)
 
-#define DDR_CONFIG_POR_VAL	0x80040853
+#define DDR_CONFIG_POR_VAL	0x80040873
 
 
 #define INVALID_TUNING_PHASE	-1
@@ -148,8 +148,9 @@
 	u32 core_ddr_200_cfg;
 	u32 core_vendor_spec3;
 	u32 core_dll_config_2;
+	u32 core_dll_config_3;
+	u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */
 	u32 core_ddr_config;
-	u32 core_ddr_config_2;
 };
 
 static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
@@ -177,8 +178,8 @@
 	.core_ddr_200_cfg = 0x224,
 	.core_vendor_spec3 = 0x250,
 	.core_dll_config_2 = 0x254,
-	.core_ddr_config = 0x258,
-	.core_ddr_config_2 = 0x25c,
+	.core_dll_config_3 = 0x258,
+	.core_ddr_config = 0x25c,
 };
 
 static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
@@ -207,8 +208,8 @@
 	.core_ddr_200_cfg = 0x184,
 	.core_vendor_spec3 = 0x1b0,
 	.core_dll_config_2 = 0x1b4,
-	.core_ddr_config = 0x1b8,
-	.core_ddr_config_2 = 0x1bc,
+	.core_ddr_config_old = 0x1b8,
+	.core_ddr_config = 0x1bc,
 };
 
 struct sdhci_msm_variant_ops {
@@ -253,6 +254,7 @@
 	const struct sdhci_msm_offset *offset;
 	bool use_cdr;
 	u32 transfer_mode;
+	bool updated_ddr_cfg;
 };
 
 static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
@@ -924,8 +926,10 @@
 static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
 {
 	struct mmc_host *mmc = host->mmc;
-	u32 dll_status, config;
+	u32 dll_status, config, ddr_cfg_offset;
 	int ret;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
 	const struct sdhci_msm_offset *msm_offset =
 					sdhci_priv_msm_offset(host);
 
@@ -938,8 +942,11 @@
 	 * bootloaders. In the future, if this changes, then the desired
 	 * values will need to be programmed appropriately.
 	 */
-	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr +
-			msm_offset->core_ddr_config);
+	if (msm_host->updated_ddr_cfg)
+		ddr_cfg_offset = msm_offset->core_ddr_config;
+	else
+		ddr_cfg_offset = msm_offset->core_ddr_config_old;
+	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + ddr_cfg_offset);
 
 	if (mmc->ios.enhanced_strobe) {
 		config = readl_relaxed(host->ioaddr +
@@ -1089,7 +1096,7 @@
 static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
-	int tuning_seq_cnt = 3;
+	int tuning_seq_cnt = 10;
 	u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
 	int rc;
 	struct mmc_ios ios = host->mmc->ios;
@@ -1106,6 +1113,12 @@
 	msm_host->use_cdr = true;
 
 	/*
+	 * Clear tuning_done flag before tuning to ensure proper
+	 * HS400 settings.
+	 */
+	msm_host->tuning_done = 0;
+
+	/*
 	 * For HS400 tuning in HS200 timing requires:
 	 * - select MCLK/2 in VENDOR_SPEC
 	 * - program MCLK to 400MHz (or nearest supported) in GCC
@@ -1139,6 +1152,22 @@
 	} while (++phase < ARRAY_SIZE(tuned_phases));
 
 	if (tuned_phase_cnt) {
+		if (tuned_phase_cnt == ARRAY_SIZE(tuned_phases)) {
+			/*
+			 * All phases valid is _almost_ as bad as no phases
+			 * valid.  Probably all phases are not really reliable
+			 * but we didn't detect where the unreliable place is.
+			 * That means we'll essentially be guessing and hoping
+			 * we get a good phase.  Better to try a few times.
+			 */
+			dev_dbg(mmc_dev(mmc), "%s: All phases valid; try again\n",
+				mmc_hostname(mmc));
+			if (--tuning_seq_cnt) {
+				tuned_phase_cnt = 0;
+				goto retry;
+			}
+		}
+
 		rc = msm_find_most_appropriate_phase(host, tuned_phases,
 						     tuned_phase_cnt);
 		if (rc < 0)
@@ -1560,6 +1589,23 @@
 	__sdhci_msm_set_clock(host, clock);
 }
 
+static void sdhci_msm_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	u32 count, start = 15;
+
+	__sdhci_set_timeout(host, cmd);
+	count = sdhci_readb(host, SDHCI_TIMEOUT_CONTROL);
+	/*
+	 * Update software timeout value if its value is less than hardware data
+	 * timeout value. Qcom SoC hardware data timeout value was calculated
+	 * using 4 * MCLK * 2^(count + 13). where MCLK = 1 / host->clock.
+	 */
+	if (cmd && cmd->data && host->clock > 400000 &&
+	    host->clock <= 50000000 &&
+	    ((1 << (count + start)) > (10 * host->clock)))
+		host->data_timeout = 22LL * NSEC_PER_SEC;
+}
+
 /*
  * Platform specific register write functions. This is so that, if any
  * register write needs to be followed up by platform specific actions,
@@ -1709,6 +1755,7 @@
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
 	{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
+	{.compatible = "qcom,sdm670-sdhci", .data = &sdm845_sdhci_var},
 	{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
 	{},
 };
@@ -1724,12 +1771,15 @@
 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
 	.write_w = sdhci_msm_writew,
 	.write_b = sdhci_msm_writeb,
+	.set_timeout = sdhci_msm_set_timeout,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
 	.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
-		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+
 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.ops = &sdhci_msm_ops,
 };
@@ -1899,6 +1949,9 @@
 				msm_offset->core_vendor_spec_capabilities0);
 	}
 
+	if (core_major == 1 && core_minor >= 0x49)
+		msm_host->updated_ddr_cfg = true;
+
 	/*
 	 * Power on reset state may trigger power irq if previous status of
 	 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
@@ -1934,6 +1987,8 @@
 		goto clk_disable;
 	}
 
+	msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
+
 	pm_runtime_get_noresume(&pdev->dev);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-arasan.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-arasan.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 
 #include "cqhci.h"
+#include "sdhci-cqhci.h"
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
@@ -192,7 +193,12 @@
 			 * through low speeds without power cycling.
 			 */
 			sdhci_set_clock(host, host->max_clk);
-			phy_power_on(sdhci_arasan->phy);
+			if (phy_power_on(sdhci_arasan->phy)) {
+				pr_err("%s: Cannot power on phy.\n",
+				       mmc_hostname(host->mmc));
+				return;
+			}
+
 			sdhci_arasan->is_phy_on = true;
 
 			/*
@@ -228,7 +234,12 @@
 		msleep(20);
 
 	if (ctrl_phy) {
-		phy_power_on(sdhci_arasan->phy);
+		if (phy_power_on(sdhci_arasan->phy)) {
+			pr_err("%s: Cannot power on phy.\n",
+			       mmc_hostname(host->mmc));
+			return;
+		}
+
 		sdhci_arasan->is_phy_on = true;
 	}
 }
@@ -254,7 +265,7 @@
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
 
-	sdhci_reset(host, mask);
+	sdhci_and_cqhci_reset(host, mask);
 
 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
 		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
@@ -416,7 +427,9 @@
 		ret = phy_power_off(sdhci_arasan->phy);
 		if (ret) {
 			dev_err(dev, "Cannot power off phy.\n");
-			sdhci_resume_host(host);
+			if (sdhci_resume_host(host))
+				dev_err(dev, "Cannot resume host.\n");
+
 			return ret;
 		}
 		sdhci_arasan->is_phy_on = false;
@@ -895,6 +908,7 @@
 static struct platform_driver sdhci_arasan_driver = {
 	.driver = {
 		.name = "sdhci-arasan",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_arasan_of_match,
 		.pm = &sdhci_arasan_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-aspeed.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-aspeed.c
@@ -68,7 +68,7 @@
 	if (WARN_ON(clock > host->max_clk))
 		clock = host->max_clk;
 
-	for (div = 1; div < 256; div *= 2) {
+	for (div = 2; div < 256; div *= 2) {
 		if ((parent / div) <= clock)
 			break;
 	}
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-at91.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-at91.c
@@ -109,8 +109,13 @@
 static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
 					 unsigned int timing)
 {
-	if (timing == MMC_TIMING_MMC_DDR52)
-		sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R);
+	u8 mc1r;
+
+	if (timing == MMC_TIMING_MMC_DDR52) {
+		mc1r = sdhci_readb(host, SDMMC_MC1R);
+		mc1r |= SDMMC_MC1R_DDR;
+		sdhci_writeb(host, mc1r, SDMMC_MC1R);
+	}
 	sdhci_set_uhs_signaling(host, timing);
 }
 
@@ -118,7 +123,8 @@
 {
 	sdhci_reset(host, mask);
 
-	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+	if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+	    || mmc_gpio_get_cd(host->mmc) >= 0)
 		sdhci_at91_set_force_card_detect(host);
 }
 
@@ -324,19 +330,22 @@
 	priv->mainck = devm_clk_get(&pdev->dev, "baseclk");
 	if (IS_ERR(priv->mainck)) {
 		dev_err(&pdev->dev, "failed to get baseclk\n");
-		return PTR_ERR(priv->mainck);
+		ret = PTR_ERR(priv->mainck);
+		goto sdhci_pltfm_free;
 	}
 
 	priv->hclock = devm_clk_get(&pdev->dev, "hclock");
 	if (IS_ERR(priv->hclock)) {
 		dev_err(&pdev->dev, "failed to get hclock\n");
-		return PTR_ERR(priv->hclock);
+		ret = PTR_ERR(priv->hclock);
+		goto sdhci_pltfm_free;
 	}
 
 	priv->gck = devm_clk_get(&pdev->dev, "multclk");
 	if (IS_ERR(priv->gck)) {
 		dev_err(&pdev->dev, "failed to get multclk\n");
-		return PTR_ERR(priv->gck);
+		ret = PTR_ERR(priv->gck);
+		goto sdhci_pltfm_free;
 	}
 
 	ret = sdhci_at91_set_clks_presets(&pdev->dev);
@@ -394,8 +403,11 @@
 	 * detection procedure using the SDMCC_CD signal is bypassed.
 	 * This bit is reset when a software reset for all command is performed
 	 * so we need to implement our own reset function to set back this bit.
+	 *
+	 * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
 	 */
-	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+	if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+	    || mmc_gpio_get_cd(host->mmc) >= 0)
 		sdhci_at91_set_force_card_detect(host);
 
 	pm_runtime_put_autosuspend(&pdev->dev);
@@ -440,6 +452,7 @@
 static struct platform_driver sdhci_at91_driver = {
 	.driver		= {
 		.name	= "sdhci-at91",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_at91_dt_match,
 		.pm	= &sdhci_at91_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -58,6 +58,7 @@
 static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
 	.ops = &sdhci_dwcmshc_ops,
 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
 static int dwcmshc_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-esdhc.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-esdhc.c
@@ -4,6 +4,7 @@
  *
  * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
  * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright 2020 NXP
  *
  * Authors: Xiaobo Xie <X.Xie@freescale.com>
  *	    Anton Vorontsov <avorontsov@ru.mvista.com>
@@ -19,6 +20,7 @@
 #include <linux/clk.h>
 #include <linux/ktime.h>
 #include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include "sdhci-pltfm.h"
@@ -77,8 +79,12 @@
 	bool quirk_incorrect_hostver;
 	bool quirk_limited_clk_division;
 	bool quirk_unreliable_pulse_detection;
-	bool quirk_fixup_tuning;
+	bool quirk_tuning_erratum_type1;
+	bool quirk_tuning_erratum_type2;
 	bool quirk_ignore_data_inhibit;
+	bool quirk_delay_before_data_reset;
+	bool quirk_trans_complete_erratum;
+	bool in_sw_tuning;
 	unsigned int peripheral_clock;
 	const struct esdhc_clk_fixup *clk_fixup;
 	u32 div_ratio;
@@ -120,6 +126,7 @@
 			return ret;
 		}
 	}
+
 	/*
 	 * The DAT[3:0] line signal levels and the CMD line signal level are
 	 * not compatible with standard SDHC register. The line signal levels
@@ -131,6 +138,16 @@
 		ret = value & 0x000fffff;
 		ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
 		ret |= (value << 1) & SDHCI_CMD_LVL;
+
+		/*
+		 * Some controllers have unreliable Data Line Active
+		 * bit for commands with busy signal. This affects
+		 * Command Inhibit (data) bit. Just ignore it since
+		 * MMC core driver has already polled card status
+		 * with CMD13 after any command with busy siganl.
+		 */
+		if (esdhc->quirk_ignore_data_inhibit)
+			ret &= ~SDHCI_DATA_INHIBIT;
 		return ret;
 	}
 
@@ -145,19 +162,6 @@
 		return ret;
 	}
 
-	/*
-	 * Some controllers have unreliable Data Line Active
-	 * bit for commands with busy signal. This affects
-	 * Command Inhibit (data) bit. Just ignore it since
-	 * MMC core driver has already polled card status
-	 * with CMD13 after any command with busy siganl.
-	 */
-	if ((spec_reg == SDHCI_PRESENT_STATE) &&
-	(esdhc->quirk_ignore_data_inhibit == true)) {
-		ret = value & ~SDHCI_DATA_INHIBIT;
-		return ret;
-	}
-
 	ret = value;
 	return ret;
 }
@@ -408,6 +412,8 @@
 
 static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 	int base = reg & ~0x3;
 	u32 value;
 	u32 ret;
@@ -416,10 +422,24 @@
 	ret = esdhc_writew_fixup(host, reg, val, value);
 	if (reg != SDHCI_TRANSFER_MODE)
 		iowrite32be(ret, host->ioaddr + base);
+
+	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
+	 * 1us later after ESDHC_EXTN is set.
+	 */
+	if (base == ESDHC_SYSTEM_CONTROL_2) {
+		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
+		    esdhc->in_sw_tuning) {
+			udelay(1);
+			ret |= ESDHC_SMPCLKSEL;
+			iowrite32be(ret, host->ioaddr + base);
+		}
+	}
 }
 
 static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 	int base = reg & ~0x3;
 	u32 value;
 	u32 ret;
@@ -428,6 +448,18 @@
 	ret = esdhc_writew_fixup(host, reg, val, value);
 	if (reg != SDHCI_TRANSFER_MODE)
 		iowrite32(ret, host->ioaddr + base);
+
+	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
+	 * 1us later after ESDHC_EXTN is set.
+	 */
+	if (base == ESDHC_SYSTEM_CONTROL_2) {
+		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
+		    esdhc->in_sw_tuning) {
+			udelay(1);
+			ret |= ESDHC_SMPCLKSEL;
+			iowrite32(ret, host->ioaddr + base);
+		}
+	}
 }
 
 static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
@@ -487,12 +519,16 @@
 
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
+	int ret;
 	u32 value;
 	struct device *dev = mmc_dev(host->mmc);
 
 	if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") ||
-	    of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc"))
-		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+	    of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) {
+		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+		if (ret)
+			return ret;
+	}
 
 	value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 
@@ -648,6 +684,21 @@
 		if (host->mmc->actual_clock == MMC_HS200_MAX_DTR)
 			temp |= ESDHC_DLL_FREQ_SEL;
 		sdhci_writel(host, temp, ESDHC_DLLCFG0);
+
+		temp |= ESDHC_DLL_RESET;
+		sdhci_writel(host, temp, ESDHC_DLLCFG0);
+		udelay(1);
+		temp &= ~ESDHC_DLL_RESET;
+		sdhci_writel(host, temp, ESDHC_DLLCFG0);
+
+		/* Wait max 20 ms */
+		if (read_poll_timeout(sdhci_readl, temp,
+				      temp & ESDHC_DLL_STS_SLV_LOCK,
+				      10, 20000, false,
+				      host, ESDHC_DLLSTAT0))
+			pr_err("%s: timeout for delay chain lock.\n",
+			       mmc_hostname(host->mmc));
+
 		temp = sdhci_readl(host, ESDHC_TBCTL);
 		sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);
 
@@ -703,21 +754,58 @@
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
-	u32 val;
+	u32 val, bus_width = 0;
+
+	/*
+	 * Add delay to make sure all the DMA transfers are finished
+	 * for quirk.
+	 */
+	if (esdhc->quirk_delay_before_data_reset &&
+	    (mask & SDHCI_RESET_DATA) &&
+	    (host->flags & SDHCI_REQ_USE_DMA))
+		mdelay(5);
+
+	/*
+	 * Save bus-width for eSDHC whose vendor version is 2.2
+	 * or lower for data reset.
+	 */
+	if ((mask & SDHCI_RESET_DATA) &&
+	    (esdhc->vendor_ver <= VENDOR_V_22)) {
+		val = sdhci_readl(host, ESDHC_PROCTL);
+		bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
+	}
 
 	sdhci_reset(host, mask);
 
-	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+	/*
+	 * Restore bus-width setting and interrupt registers for eSDHC
+	 * whose vendor version is 2.2 or lower for data reset.
+	 */
+	if ((mask & SDHCI_RESET_DATA) &&
+	    (esdhc->vendor_ver <= VENDOR_V_22)) {
+		val = sdhci_readl(host, ESDHC_PROCTL);
+		val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
+		val |= bus_width;
+		sdhci_writel(host, val, ESDHC_PROCTL);
 
-	if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc"))
-		mdelay(5);
+		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+	}
 
-	if (mask & SDHCI_RESET_ALL) {
+	/*
+	 * Some bits have to be cleaned manually for eSDHC whose spec
+	 * version is higher than 3.0 for all reset.
+	 */
+	if ((mask & SDHCI_RESET_ALL) &&
+	    (esdhc->spec_ver >= SDHCI_SPEC_300)) {
 		val = sdhci_readl(host, ESDHC_TBCTL);
 		val &= ~ESDHC_TB_EN;
 		sdhci_writel(host, val, ESDHC_TBCTL);
 
+		/*
+		 * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to
+		 * 0 for quirk.
+		 */
 		if (esdhc->quirk_unreliable_pulse_detection) {
 			val = sdhci_readl(host, ESDHC_DLLCFG1);
 			val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
@@ -771,6 +859,7 @@
 		scfg_node = of_find_matching_node(NULL, scfg_device_ids);
 		if (scfg_node)
 			scfg_base = of_iomap(scfg_node, 0);
+		of_node_put(scfg_node);
 		if (scfg_base) {
 			sdhciovselcr = SDHCIOVSELCR_TGLEN |
 				       SDHCIOVSELCR_VSELVAL;
@@ -796,16 +885,21 @@
 	}
 }
 
-static struct soc_device_attribute soc_fixup_tuning[] = {
+static struct soc_device_attribute soc_tuning_erratum_type1[] = {
+	{ .family = "QorIQ T1023", .revision = "1.0", },
 	{ .family = "QorIQ T1040", .revision = "1.0", },
 	{ .family = "QorIQ T2080", .revision = "1.0", },
-	{ .family = "QorIQ T1023", .revision = "1.0", },
 	{ .family = "QorIQ LS1021A", .revision = "1.0", },
-	{ .family = "QorIQ LS1080A", .revision = "1.0", },
-	{ .family = "QorIQ LS2080A", .revision = "1.0", },
+	{ },
+};
+
+static struct soc_device_attribute soc_tuning_erratum_type2[] = {
 	{ .family = "QorIQ LS1012A", .revision = "1.0", },
 	{ .family = "QorIQ LS1043A", .revision = "1.*", },
 	{ .family = "QorIQ LS1046A", .revision = "1.0", },
+	{ .family = "QorIQ LS1080A", .revision = "1.0", },
+	{ .family = "QorIQ LS2080A", .revision = "1.0", },
+	{ .family = "QorIQ LA1575A", .revision = "1.0", },
 	{ },
 };
 
@@ -829,15 +923,97 @@
 	esdhc_clock_enable(host, true);
 }
 
+static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start,
+				    u8 *window_end)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+	u8 tbstat_15_8, tbstat_7_0;
+	u32 val;
+
+	if (esdhc->quirk_tuning_erratum_type1) {
+		*window_start = 5 * esdhc->div_ratio;
+		*window_end = 3 * esdhc->div_ratio;
+		return;
+	}
+
+	/* Write TBCTL[11:8]=4'h8 */
+	val = sdhci_readl(host, ESDHC_TBCTL);
+	val &= ~(0xf << 8);
+	val |= 8 << 8;
+	sdhci_writel(host, val, ESDHC_TBCTL);
+
+	mdelay(1);
+
+	/* Read TBCTL[31:0] register and rewrite again */
+	val = sdhci_readl(host, ESDHC_TBCTL);
+	sdhci_writel(host, val, ESDHC_TBCTL);
+
+	mdelay(1);
+
+	/* Read the TBSTAT[31:0] register twice */
+	val = sdhci_readl(host, ESDHC_TBSTAT);
+	val = sdhci_readl(host, ESDHC_TBSTAT);
+
+	/* Reset data lines by setting ESDHCCTL[RSTD] */
+	sdhci_reset(host, SDHCI_RESET_DATA);
+	/* Write 32'hFFFF_FFFF to IRQSTAT register */
+	sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS);
+
+	/* If TBSTAT[15:8]-TBSTAT[7:0] > 4 * div_ratio
+	 * or TBSTAT[7:0]-TBSTAT[15:8] > 4 * div_ratio,
+	 * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio
+	 * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio.
+	 */
+	tbstat_7_0 = val & 0xff;
+	tbstat_15_8 = (val >> 8) & 0xff;
+
+	if (abs(tbstat_15_8 - tbstat_7_0) > (4 * esdhc->div_ratio)) {
+		*window_start = 8 * esdhc->div_ratio;
+		*window_end = 4 * esdhc->div_ratio;
+	} else {
+		*window_start = 5 * esdhc->div_ratio;
+		*window_end = 3 * esdhc->div_ratio;
+	}
+}
+
+static int esdhc_execute_sw_tuning(struct mmc_host *mmc, u32 opcode,
+				   u8 window_start, u8 window_end)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+	u32 val;
+	int ret;
+
+	/* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */
+	val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) &
+	      ESDHC_WNDW_STRT_PTR_MASK;
+	val |= window_end & ESDHC_WNDW_END_PTR_MASK;
+	sdhci_writel(host, val, ESDHC_TBPTR);
+
+	/* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */
+	val = sdhci_readl(host, ESDHC_TBCTL);
+	val &= ~ESDHC_TB_MODE_MASK;
+	val |= ESDHC_TB_MODE_SW;
+	sdhci_writel(host, val, ESDHC_TBCTL);
+
+	esdhc->in_sw_tuning = true;
+	ret = sdhci_execute_tuning(mmc, opcode);
+	esdhc->in_sw_tuning = false;
+	return ret;
+}
+
 static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+	u8 window_start, window_end;
+	int ret, retries = 1;
 	bool hs400_tuning;
 	unsigned int clk;
 	u32 val;
-	int ret;
 
 	/* For tuning mode, the sd clock divisor value
 	 * must be larger than 3 according to reference manual.
@@ -846,39 +1022,84 @@
 	if (host->clock > clk)
 		esdhc_of_set_clock(host, clk);
 
-	if (esdhc->quirk_limited_clk_division &&
-	    host->flags & SDHCI_HS400_TUNING)
-		esdhc_of_set_clock(host, host->clock);
-
 	esdhc_tuning_block_enable(host, true);
 
+	/*
+	 * The eSDHC controller takes the data timeout value into account
+	 * during tuning. If the SD card is too slow sending the response, the
+	 * timer will expire and a "Buffer Read Ready" interrupt without data
+	 * is triggered. This leads to tuning errors.
+	 *
+	 * Just set the timeout to the maximum value because the core will
+	 * already take care of it in sdhci_send_tuning().
+	 */
+	sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
+
 	hs400_tuning = host->flags & SDHCI_HS400_TUNING;
-	ret = sdhci_execute_tuning(mmc, opcode);
 
-	if (hs400_tuning) {
-		val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
-		val |= ESDHC_FLW_CTL_BG;
-		sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
-	}
+	do {
+		if (esdhc->quirk_limited_clk_division &&
+		    hs400_tuning)
+			esdhc_of_set_clock(host, host->clock);
 
-	if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
+		/* Do HW tuning */
+		val = sdhci_readl(host, ESDHC_TBCTL);
+		val &= ~ESDHC_TB_MODE_MASK;
+		val |= ESDHC_TB_MODE_3;
+		sdhci_writel(host, val, ESDHC_TBCTL);
 
-		/* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
-		 * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO
-		 */
-		val = sdhci_readl(host, ESDHC_TBPTR);
-		val = (val & ~((0x7f << 8) | 0x7f)) |
-		(3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8);
-		sdhci_writel(host, val, ESDHC_TBPTR);
+		ret = sdhci_execute_tuning(mmc, opcode);
+		if (ret)
+			break;
 
-		/* program the software tuning mode by setting
-		 * TBCTL[TB_MODE]=2'h3
+		/* If HW tuning fails and triggers erratum,
+		 * try workaround.
 		 */
-		val = sdhci_readl(host, ESDHC_TBCTL);
-		val |= 0x3;
-		sdhci_writel(host, val, ESDHC_TBCTL);
-		sdhci_execute_tuning(mmc, opcode);
+		ret = host->tuning_err;
+		if (ret == -EAGAIN &&
+		    (esdhc->quirk_tuning_erratum_type1 ||
+		     esdhc->quirk_tuning_erratum_type2)) {
+			/* Recover HS400 tuning flag */
+			if (hs400_tuning)
+				host->flags |= SDHCI_HS400_TUNING;
+			pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n",
+				mmc_hostname(mmc));
+			/* Do SW tuning */
+			esdhc_prepare_sw_tuning(host, &window_start,
+						&window_end);
+			ret = esdhc_execute_sw_tuning(mmc, opcode,
+						      window_start,
+						      window_end);
+			if (ret)
+				break;
+
+			/* Retry both HW/SW tuning with reduced clock. */
+			ret = host->tuning_err;
+			if (ret == -EAGAIN && retries) {
+				/* Recover HS400 tuning flag */
+				if (hs400_tuning)
+					host->flags |= SDHCI_HS400_TUNING;
+
+				clk = host->max_clk / (esdhc->div_ratio + 1);
+				esdhc_of_set_clock(host, clk);
+				pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n",
+					mmc_hostname(mmc));
+			} else {
+				break;
+			}
+		} else {
+			break;
+		}
+	} while (retries--);
+
+	if (ret) {
+		esdhc_tuning_block_enable(host, false);
+	} else if (hs400_tuning) {
+		val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
+		val |= ESDHC_FLW_CTL_BG;
+		sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
 	}
+
 	return ret;
 }
 
@@ -893,10 +1114,11 @@
 
 static u32 esdhc_irq(struct sdhci_host *host, u32 intmask)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 	u32 command;
 
-	if (of_find_compatible_node(NULL, NULL,
-				"fsl,p2020-esdhc")) {
+	if (esdhc->quirk_trans_complete_erratum) {
 		command = SDHCI_GET_CMD(sdhci_readw(host,
 					SDHCI_COMMAND));
 		if (command == MMC_WRITE_MULTIPLE_BLOCK &&
@@ -1010,6 +1232,8 @@
 
 static struct soc_device_attribute soc_unreliable_pulse_detection[] = {
 	{ .family = "QorIQ LX2160A", .revision = "1.0", },
+	{ .family = "QorIQ LX2160A", .revision = "2.0", },
+	{ .family = "QorIQ LS1028A", .revision = "1.0", },
 	{ },
 };
 
@@ -1049,6 +1273,12 @@
 	if (match)
 		esdhc->clk_fixup = match->data;
 	np = pdev->dev.of_node;
+
+	if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
+		esdhc->quirk_delay_before_data_reset = true;
+		esdhc->quirk_trans_complete_erratum = true;
+	}
+
 	clk = of_clk_get(np, 0);
 	if (!IS_ERR(clk)) {
 		/*
@@ -1114,10 +1344,15 @@
 
 	pltfm_host = sdhci_priv(host);
 	esdhc = sdhci_pltfm_priv(pltfm_host);
-	if (soc_device_match(soc_fixup_tuning))
-		esdhc->quirk_fixup_tuning = true;
+	if (soc_device_match(soc_tuning_erratum_type1))
+		esdhc->quirk_tuning_erratum_type1 = true;
+	else
+		esdhc->quirk_tuning_erratum_type1 = false;
+
+	if (soc_device_match(soc_tuning_erratum_type2))
+		esdhc->quirk_tuning_erratum_type2 = true;
 	else
-		esdhc->quirk_fixup_tuning = false;
+		esdhc->quirk_tuning_erratum_type2 = false;
 
 	if (esdhc->vendor_ver == VENDOR_V_22)
 		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
@@ -1126,8 +1361,8 @@
 		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
 
 	if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
-		host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
-		host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+		host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
+		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 	}
 
 	if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
@@ -1170,6 +1405,7 @@
 static struct platform_driver sdhci_esdhc_driver = {
 	.driver = {
 		.name = "sdhci-esdhc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_esdhc_of_match,
 		.pm = &esdhc_of_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-of-hlwd.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-of-hlwd.c
@@ -80,6 +80,7 @@
 static struct platform_driver sdhci_hlwd_driver = {
 	.driver = {
 		.name = "sdhci-hlwd",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_hlwd_of_match,
 		.pm = &sdhci_pltfm_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-omap.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-omap.c
@@ -675,7 +675,8 @@
 {
 	struct mmc_host *mmc = host->mmc;
 
-	mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+	if (!IS_ERR(mmc->supply.vmmc))
+		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 }
 
 static int sdhci_omap_enable_dma(struct sdhci_host *host)
@@ -1134,6 +1135,9 @@
 	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 	host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
 
+	/* R1B responses is required to properly manage HW busy detection. */
+	mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
+
 	ret = sdhci_setup_host(host);
 	if (ret)
 		goto err_put_sync;
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pci-core.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pci-core.c
@@ -21,11 +21,15 @@
 #include <linux/mmc/mmc.h>
 #include <linux/scatterlist.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/gpio.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/debugfs.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/sdhci-pci-data.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 
 #ifdef CONFIG_X86
 #include <asm/iosf_mbi.h>
@@ -230,6 +234,14 @@
 	sdhci_dumpregs(mmc_priv(mmc));
 }
 
+static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask)
+{
+	if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
+	    host->mmc->cqe_private)
+		cqhci_deactivate(host->mmc);
+	sdhci_reset(host, mask);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Hardware specific quirk handling                                          *
@@ -247,12 +259,8 @@
 static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
 {
 	slot->host->caps =
-		((0x21 << SDHCI_TIMEOUT_CLK_SHIFT)
-			& SDHCI_TIMEOUT_CLK_MASK) |
-
-		((0x21 << SDHCI_CLOCK_BASE_SHIFT)
-			& SDHCI_CLOCK_BASE_MASK) |
-
+		FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) |
+		FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) |
 		SDHCI_TIMEOUT_CLK_UNIT |
 		SDHCI_CAN_VDD_330 |
 		SDHCI_CAN_DO_HISPD |
@@ -508,8 +516,11 @@
 	int	drv_strength;
 	bool	d3_retune;
 	bool	rpm_retune_ok;
+	bool	needs_pwr_off;
 	u32	glk_rx_ctrl1;
 	u32	glk_tun_val;
+	u32	active_ltr;
+	u32	idle_ltr;
 };
 
 static const guid_t intel_dsm_guid =
@@ -599,6 +610,9 @@
 	struct sdhci_pci_slot *slot = sdhci_priv(host);
 	struct intel_host *intel_host = sdhci_pci_priv(slot);
 
+	if (!(mmc_driver_type_mask(intel_host->drv_strength) & card_drv))
+		return 0;
+
 	return intel_host->drv_strength;
 }
 
@@ -630,9 +644,25 @@
 static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
 				  unsigned short vdd)
 {
+	struct sdhci_pci_slot *slot = sdhci_priv(host);
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
 	int cntr;
 	u8 reg;
 
+	/*
+	 * Bus power may control card power, but a full reset still may not
+	 * reset the power, whereas a direct write to SDHCI_POWER_CONTROL can.
+	 * That might be needed to initialize correctly, if the card was left
+	 * powered on previously.
+	 */
+	if (intel_host->needs_pwr_off) {
+		intel_host->needs_pwr_off = false;
+		if (mode != MMC_POWER_OFF) {
+			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+			usleep_range(10000, 12500);
+		}
+	}
+
 	sdhci_set_power(host, mode, vdd);
 
 	if (mode == MMC_POWER_OFF)
@@ -652,6 +682,15 @@
 	}
 }
 
+static void sdhci_intel_set_uhs_signaling(struct sdhci_host *host,
+					  unsigned int timing)
+{
+	/* Set UHS timing to SDR25 for High Speed mode */
+	if (timing == MMC_TIMING_MMC_HS || timing == MMC_TIMING_SD_HS)
+		timing = MMC_TIMING_UHS_SDR25;
+	sdhci_set_uhs_signaling(host, timing);
+}
+
 #define INTEL_HS400_ES_REG 0x78
 #define INTEL_HS400_ES_BIT BIT(0)
 
@@ -708,7 +747,7 @@
 	.enable_dma		= sdhci_pci_enable_dma,
 	.set_bus_width		= sdhci_set_bus_width,
 	.reset			= sdhci_reset,
-	.set_uhs_signaling	= sdhci_set_uhs_signaling,
+	.set_uhs_signaling	= sdhci_intel_set_uhs_signaling,
 	.hw_reset		= sdhci_pci_hw_reset,
 };
 
@@ -717,8 +756,8 @@
 	.set_power		= sdhci_intel_set_power,
 	.enable_dma		= sdhci_pci_enable_dma,
 	.set_bus_width		= sdhci_set_bus_width,
-	.reset			= sdhci_reset,
-	.set_uhs_signaling	= sdhci_set_uhs_signaling,
+	.reset			= sdhci_cqhci_reset,
+	.set_uhs_signaling	= sdhci_intel_set_uhs_signaling,
 	.hw_reset		= sdhci_pci_hw_reset,
 	.irq			= sdhci_cqhci_irq,
 };
@@ -751,6 +790,108 @@
 	return 0;
 }
 
+#define INTEL_ACTIVELTR		0x804
+#define INTEL_IDLELTR		0x808
+
+#define INTEL_LTR_REQ		BIT(15)
+#define INTEL_LTR_SCALE_MASK	GENMASK(11, 10)
+#define INTEL_LTR_SCALE_1US	(2 << 10)
+#define INTEL_LTR_SCALE_32US	(3 << 10)
+#define INTEL_LTR_VALUE_MASK	GENMASK(9, 0)
+
+static void intel_cache_ltr(struct sdhci_pci_slot *slot)
+{
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
+	struct sdhci_host *host = slot->host;
+
+	intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR);
+	intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR);
+}
+
+static void intel_ltr_set(struct device *dev, s32 val)
+{
+	struct sdhci_pci_chip *chip = dev_get_drvdata(dev);
+	struct sdhci_pci_slot *slot = chip->slots[0];
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
+	struct sdhci_host *host = slot->host;
+	u32 ltr;
+
+	pm_runtime_get_sync(dev);
+
+	/*
+	 * Program latency tolerance (LTR) accordingly what has been asked
+	 * by the PM QoS layer or disable it in case we were passed
+	 * negative value or PM_QOS_LATENCY_ANY.
+	 */
+	ltr = readl(host->ioaddr + INTEL_ACTIVELTR);
+
+	if (val == PM_QOS_LATENCY_ANY || val < 0) {
+		ltr &= ~INTEL_LTR_REQ;
+	} else {
+		ltr |= INTEL_LTR_REQ;
+		ltr &= ~INTEL_LTR_SCALE_MASK;
+		ltr &= ~INTEL_LTR_VALUE_MASK;
+
+		if (val > INTEL_LTR_VALUE_MASK) {
+			val >>= 5;
+			if (val > INTEL_LTR_VALUE_MASK)
+				val = INTEL_LTR_VALUE_MASK;
+			ltr |= INTEL_LTR_SCALE_32US | val;
+		} else {
+			ltr |= INTEL_LTR_SCALE_1US | val;
+		}
+	}
+
+	if (ltr == intel_host->active_ltr)
+		goto out;
+
+	writel(ltr, host->ioaddr + INTEL_ACTIVELTR);
+	writel(ltr, host->ioaddr + INTEL_IDLELTR);
+
+	/* Cache the values into lpss structure */
+	intel_cache_ltr(slot);
+out:
+	pm_runtime_put_autosuspend(dev);
+}
+
+static bool intel_use_ltr(struct sdhci_pci_chip *chip)
+{
+	switch (chip->pdev->device) {
+	case PCI_DEVICE_ID_INTEL_BYT_EMMC:
+	case PCI_DEVICE_ID_INTEL_BYT_EMMC2:
+	case PCI_DEVICE_ID_INTEL_BYT_SDIO:
+	case PCI_DEVICE_ID_INTEL_BYT_SD:
+	case PCI_DEVICE_ID_INTEL_BSW_EMMC:
+	case PCI_DEVICE_ID_INTEL_BSW_SDIO:
+	case PCI_DEVICE_ID_INTEL_BSW_SD:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static void intel_ltr_expose(struct sdhci_pci_chip *chip)
+{
+	struct device *dev = &chip->pdev->dev;
+
+	if (!intel_use_ltr(chip))
+		return;
+
+	dev->power.set_latency_tolerance = intel_ltr_set;
+	dev_pm_qos_expose_latency_tolerance(dev);
+}
+
+static void intel_ltr_hide(struct sdhci_pci_chip *chip)
+{
+	struct device *dev = &chip->pdev->dev;
+
+	if (!intel_use_ltr(chip))
+		return;
+
+	dev_pm_qos_hide_latency_tolerance(dev);
+	dev->power.set_latency_tolerance = NULL;
+}
+
 static void byt_probe_slot(struct sdhci_pci_slot *slot)
 {
 	struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
@@ -765,6 +906,43 @@
 	ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
 
 	device_property_read_u32(dev, "max-frequency", &mmc->f_max);
+
+	if (!mmc->slotno) {
+		slot->chip->slots[mmc->slotno] = slot;
+		intel_ltr_expose(slot->chip);
+	}
+}
+
+static void byt_add_debugfs(struct sdhci_pci_slot *slot)
+{
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
+	struct mmc_host *mmc = slot->host->mmc;
+	struct dentry *dir = mmc->debugfs_root;
+
+	if (!intel_use_ltr(slot->chip))
+		return;
+
+	debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr);
+	debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr);
+
+	intel_cache_ltr(slot);
+}
+
+static int byt_add_host(struct sdhci_pci_slot *slot)
+{
+	int ret = sdhci_add_host(slot->host);
+
+	if (!ret)
+		byt_add_debugfs(slot);
+	return ret;
+}
+
+static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead)
+{
+	struct mmc_host *mmc = slot->host->mmc;
+
+	if (!mmc->slotno)
+		intel_ltr_hide(slot->chip);
 }
 
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
@@ -782,11 +960,19 @@
 	return 0;
 }
 
+static bool glk_broken_cqhci(struct sdhci_pci_slot *slot)
+{
+	return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
+	       (dmi_match(DMI_BIOS_VENDOR, "LENOVO") ||
+		dmi_match(DMI_SYS_VENDOR, "IRBIS"));
+}
+
 static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
 	int ret = byt_emmc_probe_slot(slot);
 
-	slot->host->mmc->caps2 |= MMC_CAP2_CQE;
+	if (!glk_broken_cqhci(slot))
+		slot->host->mmc->caps2 |= MMC_CAP2_CQE;
 
 	if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {
 		slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES,
@@ -838,6 +1024,8 @@
 	if (ret)
 		goto cleanup;
 
+	byt_add_debugfs(slot);
+
 	return 0;
 
 cleanup:
@@ -964,6 +1152,14 @@
 	return 0;
 }
 
+static void byt_needs_pwr_off(struct sdhci_pci_slot *slot)
+{
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
+	u8 reg = sdhci_readb(slot->host, SDHCI_POWER_CONTROL);
+
+	intel_host->needs_pwr_off = reg  & SDHCI_POWER_ON;
+}
+
 static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 {
 	byt_probe_slot(slot);
@@ -981,6 +1177,8 @@
 	    slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3)
 		slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V;
 
+	byt_needs_pwr_off(slot);
+
 	return 0;
 }
 
@@ -1015,6 +1213,8 @@
 #endif
 	.allow_runtime_pm = true,
 	.probe_slot	= byt_emmc_probe_slot,
+	.add_host	= byt_add_host,
+	.remove_slot	= byt_remove_slot,
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 			  SDHCI_QUIRK_NO_LED,
 	.quirks2	= SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
@@ -1028,6 +1228,7 @@
 	.allow_runtime_pm	= true,
 	.probe_slot		= glk_emmc_probe_slot,
 	.add_host		= glk_emmc_add_host,
+	.remove_slot		= byt_remove_slot,
 #ifdef CONFIG_PM_SLEEP
 	.suspend		= sdhci_cqhci_suspend,
 	.resume			= sdhci_cqhci_resume,
@@ -1058,6 +1259,8 @@
 			  SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.allow_runtime_pm = true,
 	.probe_slot	= ni_byt_sdio_probe_slot,
+	.add_host	= byt_add_host,
+	.remove_slot	= byt_remove_slot,
 	.ops		= &sdhci_intel_byt_ops,
 	.priv_size	= sizeof(struct intel_host),
 };
@@ -1075,6 +1278,8 @@
 			SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.allow_runtime_pm = true,
 	.probe_slot	= byt_sdio_probe_slot,
+	.add_host	= byt_add_host,
+	.remove_slot	= byt_remove_slot,
 	.ops		= &sdhci_intel_byt_ops,
 	.priv_size	= sizeof(struct intel_host),
 };
@@ -1094,6 +1299,8 @@
 	.allow_runtime_pm = true,
 	.own_cd_for_runtime_pm = true,
 	.probe_slot	= byt_sd_probe_slot,
+	.add_host	= byt_add_host,
+	.remove_slot	= byt_remove_slot,
 	.ops		= &sdhci_intel_byt_ops,
 	.priv_size	= sizeof(struct intel_host),
 };
@@ -1584,17 +1791,67 @@
 		}
 	}
 
+	pci_dev_put(smbus_dev);
+
 	if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ)
 		chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
 
 	return 0;
 }
 
+static u32 sdhci_read_present_state(struct sdhci_host *host)
+{
+	return sdhci_readl(host, SDHCI_PRESENT_STATE);
+}
+
+static void amd_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	struct sdhci_pci_slot *slot = sdhci_priv(host);
+	struct pci_dev *pdev = slot->chip->pdev;
+	u32 present_state;
+
+	/*
+	 * SDHC 0x7906 requires a hard reset to clear all internal state.
+	 * Otherwise it can get into a bad state where the DATA lines are always
+	 * read as zeros.
+	 */
+	if (pdev->device == 0x7906 && (mask & SDHCI_RESET_ALL)) {
+		pci_clear_master(pdev);
+
+		pci_save_state(pdev);
+
+		pci_set_power_state(pdev, PCI_D3cold);
+		pr_debug("%s: power_state=%u\n", mmc_hostname(host->mmc),
+			pdev->current_state);
+		pci_set_power_state(pdev, PCI_D0);
+
+		pci_restore_state(pdev);
+
+		/*
+		 * SDHCI_RESET_ALL says the card detect logic should not be
+		 * reset, but since we need to reset the entire controller
+		 * we should wait until the card detect logic has stabilized.
+		 *
+		 * This normally takes about 40ms.
+		 */
+		readx_poll_timeout(
+			sdhci_read_present_state,
+			host,
+			present_state,
+			present_state & SDHCI_CD_STABLE,
+			10000,
+			100000
+		);
+	}
+
+	return sdhci_reset(host, mask);
+}
+
 static const struct sdhci_ops amd_sdhci_pci_ops = {
 	.set_clock			= sdhci_set_clock,
 	.enable_dma			= sdhci_pci_enable_dma,
 	.set_bus_width			= sdhci_set_bus_width,
-	.reset				= sdhci_reset,
+	.reset				= amd_sdhci_reset,
 	.set_uhs_signaling		= sdhci_set_uhs_signaling,
 };
 
@@ -1673,6 +1930,11 @@
 	SDHCI_PCI_DEVICE(INTEL, CML_EMMC,  intel_glk_emmc),
 	SDHCI_PCI_DEVICE(INTEL, CML_SD,    intel_byt_sd),
 	SDHCI_PCI_DEVICE(INTEL, CMLH_SD,   intel_byt_sd),
+	SDHCI_PCI_DEVICE(INTEL, JSL_EMMC,  intel_glk_emmc),
+	SDHCI_PCI_DEVICE(INTEL, JSL_SD,    intel_byt_sd),
+	SDHCI_PCI_DEVICE(INTEL, LKF_EMMC,  intel_glk_emmc),
+	SDHCI_PCI_DEVICE(INTEL, LKF_SD,    intel_byt_sd),
+	SDHCI_PCI_DEVICE(INTEL, ADL_EMMC,  intel_glk_emmc),
 	SDHCI_PCI_DEVICE(O2, 8120,     o2),
 	SDHCI_PCI_DEVICE(O2, 8220,     o2),
 	SDHCI_PCI_DEVICE(O2, 8221,     o2),
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pci-gli.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pci-gli.c
@@ -26,6 +26,9 @@
 #define   SDHCI_GLI_9750_DRIVING_2    GENMASK(27, 26)
 #define   GLI_9750_DRIVING_1_VALUE    0xFFF
 #define   GLI_9750_DRIVING_2_VALUE    0x3
+#define   SDHCI_GLI_9750_SEL_1        BIT(29)
+#define   SDHCI_GLI_9750_SEL_2        BIT(31)
+#define   SDHCI_GLI_9750_ALL_RST      (BIT(24)|BIT(25)|BIT(28)|BIT(30))
 
 #define SDHCI_GLI_9750_PLL	      0x864
 #define   SDHCI_GLI_9750_PLL_TX2_INV    BIT(23)
@@ -122,6 +125,8 @@
 				    GLI_9750_DRIVING_1_VALUE);
 	driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2,
 				    GLI_9750_DRIVING_2_VALUE);
+	driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST);
+	driving_value |= SDHCI_GLI_9750_SEL_2;
 	sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING);
 
 	sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4;
@@ -262,10 +267,26 @@
 	return 0;
 }
 
+static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
+{
+	int ret;
+
+	ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1,
+				    PCI_IRQ_MSI | PCI_IRQ_MSIX);
+	if (ret < 0) {
+		pr_warn("%s: enable PCI MSI failed, error=%d\n",
+		       mmc_hostname(slot->host->mmc), ret);
+		return;
+	}
+
+	slot->host->irq = pci_irq_vector(slot->chip->pdev, 0);
+}
+
 static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
 {
 	struct sdhci_host *host = slot->host;
 
+	gli_pcie_enable_msi(slot);
 	slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
 	sdhci_enable_v4_mode(host);
 
@@ -276,6 +297,7 @@
 {
 	struct sdhci_host *host = slot->host;
 
+	gli_pcie_enable_msi(slot);
 	slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
 	sdhci_enable_v4_mode(host);
 
@@ -296,8 +318,13 @@
 	 *
 	 * Wait 5ms after set 1.8V signal enable in Host Control 2 register
 	 * to ensure 1.8V signal enable bit is set by GL9750/GL9755.
+	 *
+	 * ...however, the controller in the NUC10i3FNK4 (a 9755) requires
+	 * slightly longer than 5ms before the control register reports that
+	 * 1.8V is ready, and far longer still before the card will actually
+	 * work reliably.
 	 */
-	usleep_range(5000, 5500);
+	usleep_range(100000, 110000);
 }
 
 static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask)
@@ -317,6 +344,18 @@
 	return value;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
+{
+	struct sdhci_pci_slot *slot = chip->slots[0];
+
+	pci_free_irq_vectors(slot->chip->pdev);
+	gli_pcie_enable_msi(slot);
+
+	return sdhci_pci_resume_host(chip);
+}
+#endif
+
 static const struct sdhci_ops sdhci_gl9755_ops = {
 	.set_clock		= sdhci_set_clock,
 	.enable_dma		= sdhci_pci_enable_dma,
@@ -331,6 +370,9 @@
 	.quirks2	= SDHCI_QUIRK2_BROKEN_DDR50,
 	.probe_slot	= gli_probe_slot_gl9755,
 	.ops            = &sdhci_gl9755_ops,
+#ifdef CONFIG_PM_SLEEP
+	.resume         = sdhci_pci_gli_resume,
+#endif
 };
 
 static const struct sdhci_ops sdhci_gl9750_ops = {
@@ -349,4 +391,7 @@
 	.quirks2	= SDHCI_QUIRK2_BROKEN_DDR50,
 	.probe_slot	= gli_probe_slot_gl9750,
 	.ops            = &sdhci_gl9750_ops,
+#ifdef CONFIG_PM_SLEEP
+	.resume         = sdhci_pci_gli_resume,
+#endif
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pci-o2micro.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -31,6 +31,7 @@
 #define O2_SD_CAPS		0xE0
 #define O2_SD_ADMA1		0xE2
 #define O2_SD_ADMA2		0xE7
+#define O2_SD_MISC_CTRL2	0xF0
 #define O2_SD_INF_MOD		0xF1
 #define O2_SD_MISC_CTRL4	0xFC
 #define O2_SD_TUNING_CTRL	0x300
@@ -145,6 +146,8 @@
 
 	if (!(sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1) & O2_PLL_LOCK_STATUS))
 		sdhci_o2_enable_internal_clock(host);
+	else
+		sdhci_o2_wait_card_detect_stable(host);
 
 	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
 }
@@ -561,6 +564,12 @@
 			slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
 		}
 
+		if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) {
+			slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
+			host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
+			host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+		}
+
 		host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
 
 		if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
@@ -769,6 +778,12 @@
 		/* Set Tuning Windows to 5 */
 		pci_write_config_byte(chip->pdev,
 				O2_SD_TUNING_CTRL, 0x55);
+		//Adjust 1st and 2nd CD debounce time
+		pci_read_config_dword(chip->pdev, O2_SD_MISC_CTRL2, &scratch_32);
+		scratch_32 &= 0xFFE7FFFF;
+		scratch_32 |= 0x00180000;
+		pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL2, scratch_32);
+		pci_write_config_dword(chip->pdev, O2_SD_DETECT_SETTING, 1);
 		/* Lock WP */
 		ret = pci_read_config_byte(chip->pdev,
 					   O2_SD_LOCK_WP, &scratch);
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pci.h
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pci.h
@@ -55,6 +55,11 @@
 #define PCI_DEVICE_ID_INTEL_CML_EMMC	0x02c4
 #define PCI_DEVICE_ID_INTEL_CML_SD	0x02f5
 #define PCI_DEVICE_ID_INTEL_CMLH_SD	0x06f5
+#define PCI_DEVICE_ID_INTEL_JSL_EMMC	0x4dc4
+#define PCI_DEVICE_ID_INTEL_JSL_SD	0x4df8
+#define PCI_DEVICE_ID_INTEL_LKF_EMMC	0x98c4
+#define PCI_DEVICE_ID_INTEL_LKF_SD	0x98f8
+#define PCI_DEVICE_ID_INTEL_ADL_EMMC	0x54c4
 
 #define PCI_DEVICE_ID_SYSKONNECT_8000	0x8000
 #define PCI_DEVICE_ID_VIA_95D0		0x95d0
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pxav2.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pxav2.c
@@ -226,6 +226,7 @@
 static struct platform_driver sdhci_pxav2_driver = {
 	.driver		= {
 		.name	= "sdhci-pxav2",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(sdhci_pxav2_of_match),
 		.pm	= &sdhci_pltfm_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-pxav3.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-pxav3.c
@@ -567,6 +567,7 @@
 static struct platform_driver sdhci_pxav3_driver = {
 	.driver		= {
 		.name	= "sdhci-pxav3",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(sdhci_pxav3_of_match),
 		.pm	= &sdhci_pxav3_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-s3c.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-s3c.c
@@ -784,6 +784,7 @@
 	.id_table	= sdhci_s3c_driver_ids,
 	.driver		= {
 		.name	= "s3c-sdhci",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(sdhci_s3c_dt_match),
 		.pm	= &sdhci_s3c_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-sirf.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-sirf.c
@@ -220,6 +220,7 @@
 static struct platform_driver sdhci_sirf_driver = {
 	.driver		= {
 		.name	= "sdhci-sirf",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_sirf_of_match,
 		.pm	= &sdhci_pltfm_pmops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-spear.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-spear.c
@@ -183,6 +183,7 @@
 static struct platform_driver sdhci_driver = {
 	.driver = {
 		.name	= "sdhci",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &sdhci_pm_ops,
 		.of_match_table = of_match_ptr(sdhci_spear_id_table),
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-sprd.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-sprd.c
@@ -223,13 +223,19 @@
 	div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
 	sdhci_enable_clk(host, div);
 
-	/* enable auto gate sdhc_enable_auto_gate */
 	val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
-	mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
-	       SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
-	if (mask != (val & mask)) {
-		val |= mask;
-		sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
+	mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
+	/* Enable CLK_AUTO when the clock is greater than 400K. */
+	if (clk > 400000) {
+		if (mask != (val & mask)) {
+			val |= mask;
+			sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
+		}
+	} else {
+		if (val & mask) {
+			val &= ~mask;
+			sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
+		}
 	}
 }
 
@@ -295,7 +301,7 @@
 
 static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
 {
-	return 400000;
+	return 100000;
 }
 
 static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
@@ -379,11 +385,33 @@
 	return 0;
 }
 
+static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode,
+				 unsigned short vdd)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	switch (mode) {
+	case MMC_POWER_OFF:
+		mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, 0);
+
+		mmc_regulator_disable_vqmmc(mmc);
+		break;
+	case MMC_POWER_ON:
+		mmc_regulator_enable_vqmmc(mmc);
+		break;
+	case MMC_POWER_UP:
+		mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, vdd);
+		break;
+	}
+}
+
 static struct sdhci_ops sdhci_sprd_ops = {
 	.read_l = sdhci_sprd_readl,
 	.write_l = sdhci_sprd_writel,
+	.write_w = sdhci_sprd_writew,
 	.write_b = sdhci_sprd_writeb,
 	.set_clock = sdhci_sprd_set_clock,
+	.set_power = sdhci_sprd_set_power,
 	.get_max_clock = sdhci_sprd_get_max_clock,
 	.get_min_clock = sdhci_sprd_get_min_clock,
 	.set_bus_width = sdhci_set_bus_width,
@@ -430,7 +458,7 @@
 	}
 
 	if (IS_ERR(sprd_host->pinctrl))
-		return 0;
+		goto reset;
 
 	switch (ios->signal_voltage) {
 	case MMC_SIGNAL_VOLTAGE_180:
@@ -458,6 +486,8 @@
 
 	/* Wait for 300 ~ 500 us for pin state stable */
 	usleep_range(300, 500);
+
+reset:
 	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
 	return 0;
@@ -625,6 +655,10 @@
 	host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
 			 SDHCI_SUPPORT_DDR50);
 
+	ret = mmc_regulator_get_supply(host->mmc);
+	if (ret)
+		goto pm_runtime_disable;
+
 	ret = sdhci_setup_host(host);
 	if (ret)
 		goto pm_runtime_disable;
@@ -665,14 +699,14 @@
 {
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
-	struct mmc_host *mmc = host->mmc;
 
-	mmc_remove_host(mmc);
+	sdhci_remove_host(host, 0);
+
 	clk_disable_unprepare(sprd_host->clk_sdio);
 	clk_disable_unprepare(sprd_host->clk_enable);
 	clk_disable_unprepare(sprd_host->clk_2x_enable);
 
-	mmc_free_host(mmc);
+	sdhci_pltfm_free(pdev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-st.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-st.c
@@ -521,6 +521,7 @@
 	.remove = sdhci_st_remove,
 	.driver = {
 		   .name = "sdhci-st",
+		   .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		   .pm = &sdhci_st_pmops,
 		   .of_match_table = of_match_ptr(st_sdhci_match),
 		  },
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-tegra.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-tegra.c
@@ -24,6 +24,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/ktime.h>
 
+#include "sdhci-cqhci.h"
 #include "sdhci-pltfm.h"
 #include "cqhci.h"
 
@@ -100,6 +101,12 @@
 #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP			BIT(8)
 #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING		BIT(9)
 
+/*
+ * NVQUIRK_HAS_TMCLK is for SoC's having separate timeout clock for Tegra
+ * SDMMC hardware data timeout.
+ */
+#define NVQUIRK_HAS_TMCLK				BIT(10)
+
 /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
 #define SDHCI_TEGRA_CQE_BASE_ADDR			0xF000
 
@@ -130,6 +137,7 @@
 struct sdhci_tegra {
 	const struct sdhci_tegra_soc_data *soc_data;
 	struct gpio_desc *power_gpio;
+	struct clk *tmclk;
 	bool ddr_signaling;
 	bool pad_calib_required;
 	bool pad_control_available;
@@ -333,23 +341,6 @@
 	}
 }
 
-static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
-					      struct mmc_ios *ios)
-{
-	struct sdhci_host *host = mmc_priv(mmc);
-	u32 val;
-
-	val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-	if (ios->enhanced_strobe)
-		val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-	else
-		val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-
-	sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-}
-
 static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -357,7 +348,7 @@
 	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
 	u32 misc_ctrl, clk_ctrl, pad_ctrl;
 
-	sdhci_reset(host, mask);
+	sdhci_and_cqhci_reset(host, mask);
 
 	if (!(mask & SDHCI_RESET_ALL))
 		return;
@@ -386,7 +377,7 @@
 			misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
 		if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
 			misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
-		if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
+		if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
 			clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
 	}
 
@@ -761,6 +752,32 @@
 	}
 }
 
+static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
+					      struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u32 val;
+
+	val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+
+	if (ios->enhanced_strobe) {
+		val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+		/*
+		 * When CMD13 is sent from mmc_select_hs400es() after
+		 * switching to HS400ES mode, the bus is operating at
+		 * either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR.
+		 * To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI
+		 * interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host
+		 * controller CAR clock and the interface clock are rate matched.
+		 */
+		tegra_sdhci_set_clock(host, MMC_HS200_MAX_DTR);
+	} else {
+		val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+	}
+
+	sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+}
+
 static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1370,7 +1387,6 @@
 
 static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
 	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
 		  SDHCI_QUIRK_NO_HISPD_BIT |
 		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@@ -1386,7 +1402,8 @@
 		    NVQUIRK_HAS_PADCALIB |
 		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
 		    NVQUIRK_ENABLE_SDR50 |
-		    NVQUIRK_ENABLE_SDR104,
+		    NVQUIRK_ENABLE_SDR104 |
+		    NVQUIRK_HAS_TMCLK,
 	.min_tap_delay = 106,
 	.max_tap_delay = 185,
 };
@@ -1407,7 +1424,6 @@
 
 static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
 	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
 		  SDHCI_QUIRK_NO_HISPD_BIT |
 		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@@ -1424,6 +1440,7 @@
 		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
 		    NVQUIRK_ENABLE_SDR50 |
 		    NVQUIRK_ENABLE_SDR104 |
+		    NVQUIRK_HAS_TMCLK |
 		    NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING,
 	.min_tap_delay = 84,
 	.max_tap_delay = 136,
@@ -1436,7 +1453,8 @@
 		    NVQUIRK_HAS_PADCALIB |
 		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
 		    NVQUIRK_ENABLE_SDR50 |
-		    NVQUIRK_ENABLE_SDR104,
+		    NVQUIRK_ENABLE_SDR104 |
+		    NVQUIRK_HAS_TMCLK,
 	.min_tap_delay = 96,
 	.max_tap_delay = 139,
 };
@@ -1552,6 +1570,9 @@
 	if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
 		host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+	/* R1B responses is required to properly manage HW busy detection. */
+	host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
+
 	tegra_sdhci_parse_dt(host);
 
 	tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
@@ -1561,6 +1582,43 @@
 		goto err_power_req;
 	}
 
+	/*
+	 * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host
+	 * timeout clock and SW can choose TMCLK or SDCLK for hardware
+	 * data timeout through the bit USE_TMCLK_FOR_DATA_TIMEOUT of
+	 * the register SDHCI_TEGRA_VENDOR_SYS_SW_CTRL.
+	 *
+	 * USE_TMCLK_FOR_DATA_TIMEOUT bit default is set to 1 and SDMMC uses
+	 * 12Mhz TMCLK which is advertised in host capability register.
+	 * With TMCLK of 12Mhz provides maximum data timeout period that can
+	 * be achieved is 11s better than using SDCLK for data timeout.
+	 *
+	 * So, TMCLK is set to 12Mhz and kept enabled all the time on SoC's
+	 * supporting separate TMCLK.
+	 */
+
+	if (soc_data->nvquirks & NVQUIRK_HAS_TMCLK) {
+		clk = devm_clk_get(&pdev->dev, "tmclk");
+		if (IS_ERR(clk)) {
+			rc = PTR_ERR(clk);
+			if (rc == -EPROBE_DEFER)
+				goto err_power_req;
+
+			dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc);
+			clk = NULL;
+		}
+
+		clk_set_rate(clk, 12000000);
+		rc = clk_prepare_enable(clk);
+		if (rc) {
+			dev_err(&pdev->dev,
+				"failed to enable tmclk: %d\n", rc);
+			goto err_power_req;
+		}
+
+		tegra_host->tmclk = clk;
+	}
+
 	clk = devm_clk_get(mmc_dev(host->mmc), NULL);
 	if (IS_ERR(clk)) {
 		rc = PTR_ERR(clk);
@@ -1604,6 +1662,7 @@
 err_rst_get:
 	clk_disable_unprepare(pltfm_host->clk);
 err_clk_get:
+	clk_disable_unprepare(tegra_host->tmclk);
 err_power_req:
 err_parse_dt:
 	sdhci_pltfm_free(pdev);
@@ -1621,6 +1680,7 @@
 	reset_control_assert(tegra_host->rst);
 	usleep_range(2000, 4000);
 	clk_disable_unprepare(pltfm_host->clk);
+	clk_disable_unprepare(tegra_host->tmclk);
 
 	sdhci_pltfm_free(pdev);
 
@@ -1686,6 +1746,7 @@
 static struct platform_driver sdhci_tegra_driver = {
 	.driver		= {
 		.name	= "sdhci-tegra",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_tegra_dt_match,
 		.pm	= &sdhci_tegra_dev_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci-xenon.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci-xenon.c
@@ -167,7 +167,12 @@
 	/* Disable tuning request and auto-retuning again */
 	xenon_retune_setup(host);
 
-	xenon_set_acg(host, true);
+	/*
+	 * The ACG should be turned off at the early init time, in order
+	 * to solve a possible issues with the 1.8V regulator stabilization.
+	 * The feature is enabled in later stage.
+	 */
+	xenon_set_acg(host, false);
 
 	xenon_set_sdclk_off_idle(host, sdhc_id, false);
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci.c
@@ -9,6 +9,7 @@
  *     - JMicron (hardware and technical support)
  */
 
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/ktime.h>
 #include <linux/highmem.h>
@@ -109,6 +110,9 @@
 		}
 	}
 
+	if (host->ops->dump_vendor_regs)
+		host->ops->dump_vendor_regs(host);
+
 	SDHCI_DUMP("============================================\n");
 }
 EXPORT_SYMBOL_GPL(sdhci_dumpregs);
@@ -152,7 +156,7 @@
 	u32 present;
 
 	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
-	    !mmc_card_is_removable(host->mmc))
+	    !mmc_card_is_removable(host->mmc) || mmc_can_gpio_cd(host->mmc))
 		return;
 
 	if (enable) {
@@ -331,6 +335,7 @@
 	if (soft) {
 		/* force clock reconfiguration */
 		host->clock = 0;
+		host->reinit_uhs = true;
 		mmc->ops->set_ios(mmc, &mmc->ios);
 	}
 }
@@ -474,7 +479,7 @@
 {
 	unsigned long flags;
 	size_t blksize, len, chunk;
-	u32 uninitialized_var(scratch);
+	u32 scratch;
 	u8 *buf;
 
 	DBG("PIO reading\n");
@@ -749,7 +754,19 @@
 			len -= offset;
 		}
 
-		BUG_ON(len > 65536);
+		/*
+		 * The block layer forces a minimum segment size of PAGE_SIZE,
+		 * so 'len' can be too big here if PAGE_SIZE >= 64KiB. Write
+		 * multiple descriptors, noting that the ADMA table is sized
+		 * for 4KiB chunks anyway, so it will be big enough.
+		 */
+		while (len > host->max_adma) {
+			int n = 32 * 1024; /* 32KiB*/
+
+			__sdhci_adma_write_desc(host, &desc, addr, n, ADMA2_TRAN_VALID);
+			addr += n;
+			len -= n;
+		}
 
 		/* tran, valid */
 		if (len)
@@ -981,7 +998,7 @@
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
-static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
 {
 	if (enable)
 		host->ier |= SDHCI_INT_DATA_TIMEOUT;
@@ -990,28 +1007,31 @@
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_data_timeout_irq);
 
-static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
-	u8 count;
+	bool too_big = false;
+	u8 count = sdhci_calc_timeout(host, cmd, &too_big);
 
-	if (host->ops->set_timeout) {
-		host->ops->set_timeout(host, cmd);
-	} else {
-		bool too_big = false;
-
-		count = sdhci_calc_timeout(host, cmd, &too_big);
+	if (too_big &&
+	    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+		sdhci_calc_sw_timeout(host, cmd);
+		sdhci_set_data_timeout_irq(host, false);
+	} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
+		sdhci_set_data_timeout_irq(host, true);
+	}
 
-		if (too_big &&
-		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
-			sdhci_calc_sw_timeout(host, cmd);
-			sdhci_set_data_timeout_irq(host, false);
-		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
-			sdhci_set_data_timeout_irq(host, true);
-		}
+	sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+}
+EXPORT_SYMBOL_GPL(__sdhci_set_timeout);
 
-		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
-	}
+static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	if (host->ops->set_timeout)
+		host->ops->set_timeout(host, cmd);
+	else
+		__sdhci_set_timeout(host, cmd);
 }
 
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -1087,6 +1107,8 @@
 		}
 	}
 
+	sdhci_config_dma(host);
+
 	if (host->flags & SDHCI_REQ_USE_DMA) {
 		int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
 
@@ -1106,8 +1128,6 @@
 		}
 	}
 
-	sdhci_config_dma(host);
-
 	if (!(host->flags & SDHCI_REQ_USE_DMA)) {
 		int flags;
 
@@ -1159,9 +1179,11 @@
 	/*
 	 * In case of Version 4.10 or later, use of 'Auto CMD Auto
 	 * Select' is recommended rather than use of 'Auto CMD12
-	 * Enable' or 'Auto CMD23 Enable'.
+	 * Enable' or 'Auto CMD23 Enable'. We require Version 4 Mode
+	 * here because some controllers (e.g sdhci-of-dwmshc) expect it.
 	 */
-	if (host->version >= SDHCI_SPEC_410 && (use_cmd12 || use_cmd23)) {
+	if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
+	    (use_cmd12 || use_cmd23)) {
 		*mode |= SDHCI_TRNS_AUTO_SEL;
 
 		ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -1506,6 +1528,10 @@
 	u16 preset = 0;
 
 	switch (host->timing) {
+	case MMC_TIMING_MMC_HS:
+	case MMC_TIMING_SD_HS:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED);
+		break;
 	case MMC_TIMING_UHS_SDR12:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
 		break;
@@ -1549,10 +1575,9 @@
 
 			clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
 			pre_val = sdhci_get_preset_value(host);
-			div = (pre_val & SDHCI_PRESET_SDCLK_FREQ_MASK)
-				>> SDHCI_PRESET_SDCLK_FREQ_SHIFT;
+			div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
 			if (host->clk_mul &&
-				(pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) {
+				(pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
 				clk = SDHCI_PROG_CLOCK_MODE;
 				real_div = div + 1;
 				clk_mul = host->clk_mul;
@@ -1732,6 +1757,12 @@
 			break;
 		case MMC_VDD_32_33:
 		case MMC_VDD_33_34:
+		/*
+		 * 3.4 ~ 3.6V are valid only for those platforms where it's
+		 * known that the voltage range is supported by hardware.
+		 */
+		case MMC_VDD_34_35:
+		case MMC_VDD_35_36:
 			pwr = SDHCI_POWER_330;
 			break;
 		default:
@@ -1871,9 +1902,7 @@
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
 	else if (timing == MMC_TIMING_UHS_SDR12)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-	else if (timing == MMC_TIMING_SD_HS ||
-		 timing == MMC_TIMING_MMC_HS ||
-		 timing == MMC_TIMING_UHS_SDR25)
+	else if (timing == MMC_TIMING_UHS_SDR25)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 	else if (timing == MMC_TIMING_UHS_SDR50)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
@@ -1886,11 +1915,46 @@
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
+static bool sdhci_timing_has_preset(unsigned char timing)
+{
+	switch (timing) {
+	case MMC_TIMING_UHS_SDR12:
+	case MMC_TIMING_UHS_SDR25:
+	case MMC_TIMING_UHS_SDR50:
+	case MMC_TIMING_UHS_SDR104:
+	case MMC_TIMING_UHS_DDR50:
+	case MMC_TIMING_MMC_DDR52:
+		return true;
+	};
+	return false;
+}
+
+static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
+{
+	return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+	       sdhci_timing_has_preset(timing);
+}
+
+static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
+{
+	/*
+	 * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
+	 * Frequency. Check if preset values need to be enabled, or the Driver
+	 * Strength needs updating. Note, clock changes are handled separately.
+	 */
+	return !host->preset_enabled &&
+	       (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+}
+
 void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
+	bool reinit_uhs = host->reinit_uhs;
+	bool turning_on_clk = false;
 	u8 ctrl;
 
+	host->reinit_uhs = false;
+
 	if (ios->power_mode == MMC_POWER_UNDEFINED)
 		return;
 
@@ -1916,6 +1980,8 @@
 		sdhci_enable_preset_value(host, false);
 
 	if (!ios->clock || ios->clock != host->clock) {
+		turning_on_clk = ios->clock && !host->clock;
+
 		host->ops->set_clock(host, ios->clock);
 		host->clock = ios->clock;
 
@@ -1942,6 +2008,17 @@
 
 	host->ops->set_bus_width(host, ios->bus_width);
 
+	/*
+	 * Special case to avoid multiple clock changes during voltage
+	 * switching.
+	 */
+	if (!reinit_uhs &&
+	    turning_on_clk &&
+	    host->timing == ios->timing &&
+	    host->version >= SDHCI_SPEC_300 &&
+	    !sdhci_presetable_values_change(host, ios))
+		return;
+
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
 	if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
@@ -1985,6 +2062,7 @@
 			}
 
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+			host->drv_type = ios->drv_type;
 		} else {
 			/*
 			 * According to SDHC Spec v3.00, if the Preset Value
@@ -2012,19 +2090,14 @@
 		host->ops->set_uhs_signaling(host, ios->timing);
 		host->timing = ios->timing;
 
-		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
-				((ios->timing == MMC_TIMING_UHS_SDR12) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR25) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR50) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR104) ||
-				 (ios->timing == MMC_TIMING_UHS_DDR50) ||
-				 (ios->timing == MMC_TIMING_MMC_DDR52))) {
+		if (sdhci_preset_needed(host, ios->timing)) {
 			u16 preset;
 
 			sdhci_enable_preset_value(host, true);
 			preset = sdhci_get_preset_value(host);
-			ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
-				>> SDHCI_PRESET_DRV_SHIFT;
+			ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
+						  preset);
+			host->drv_type = ios->drv_type;
 		}
 
 		/* Re-enable SD Clock */
@@ -2408,8 +2481,8 @@
 		sdhci_send_tuning(host, opcode);
 
 		if (!host->tuning_done) {
-			pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
-				mmc_hostname(host->mmc));
+			pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n",
+				 mmc_hostname(host->mmc));
 			sdhci_abort_tuning(host, opcode);
 			return -ETIMEDOUT;
 		}
@@ -2645,6 +2718,37 @@
 	}
 
 	/*
+	 * The controller needs a reset of internal state machines
+	 * upon error conditions.
+	 */
+	if (sdhci_needs_reset(host, mrq)) {
+		/*
+		 * Do not finish until command and data lines are available for
+		 * reset. Note there can only be one other mrq, so it cannot
+		 * also be in mrqs_done, otherwise host->cmd and host->data_cmd
+		 * would both be null.
+		 */
+		if (host->cmd || host->data_cmd) {
+			spin_unlock_irqrestore(&host->lock, flags);
+			return true;
+		}
+
+		/* Some controllers need this kick or reset won't work here */
+		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+			/* This is to force an update */
+			host->ops->set_clock(host, host->clock);
+
+		/*
+		 * Spec says we should do both at the same time, but Ricoh
+		 * controllers do not like that.
+		 */
+		sdhci_do_reset(host, SDHCI_RESET_CMD);
+		sdhci_do_reset(host, SDHCI_RESET_DATA);
+
+		host->pending_reset = false;
+	}
+
+	/*
 	 * Always unmap the data buffers if they were mapped by
 	 * sdhci_prepare_data() whenever we finish with a request.
 	 * This avoids leaking DMA mappings on error.
@@ -2696,35 +2800,6 @@
 		}
 	}
 
-	/*
-	 * The controller needs a reset of internal state machines
-	 * upon error conditions.
-	 */
-	if (sdhci_needs_reset(host, mrq)) {
-		/*
-		 * Do not finish until command and data lines are available for
-		 * reset. Note there can only be one other mrq, so it cannot
-		 * also be in mrqs_done, otherwise host->cmd and host->data_cmd
-		 * would both be null.
-		 */
-		if (host->cmd || host->data_cmd) {
-			spin_unlock_irqrestore(&host->lock, flags);
-			return true;
-		}
-
-		/* Some controllers need this kick or reset won't work here */
-		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
-			/* This is to force an update */
-			host->ops->set_clock(host, host->clock);
-
-		/* Spec says we should do both at the same time, but Ricoh
-		   controllers do not like that. */
-		sdhci_do_reset(host, SDHCI_RESET_CMD);
-		sdhci_do_reset(host, SDHCI_RESET_DATA);
-
-		host->pending_reset = false;
-	}
-
 	host->mrqs_done[i] = NULL;
 
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -3300,6 +3375,7 @@
 		sdhci_init(host, 0);
 		host->pwr = 0;
 		host->clock = 0;
+		host->reinit_uhs = true;
 		mmc->ops->set_ios(mmc, &mmc->ios);
 	} else {
 		sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
@@ -3362,6 +3438,7 @@
 		/* Force clock and power re-program */
 		host->pwr = 0;
 		host->clock = 0;
+		host->reinit_uhs = true;
 		mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
 		mmc->ops->set_ios(mmc, &mmc->ios);
 
@@ -3553,6 +3630,7 @@
 	 * descriptor for each segment, plus 1 for a nop end descriptor.
 	 */
 	host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
+	host->max_adma = 65536;
 
 	return host;
 }
@@ -3595,14 +3673,19 @@
 	u16 v;
 	u64 dt_caps_mask = 0;
 	u64 dt_caps = 0;
+	u32 dt_quirks2 = 0;
 
 	if (host->read_caps)
 		return;
 
 	host->read_caps = true;
 
-	if (debug_quirks)
-		host->quirks = debug_quirks;
+	of_property_read_u32(mmc_dev(host->mmc)->of_node,
+			     "sdhci-extra-quirks2", &dt_quirks2);
+	host->quirks2 |= dt_quirks2;
+
+	if (dt_quirks2)
+		dev_dbg(mmc_dev(host->mmc), "applying extra quirks2: 0x%08x\n", dt_quirks2);
 
 	if (debug_quirks2)
 		host->quirks2 = debug_quirks2;
@@ -3758,6 +3841,9 @@
 		       mmc_hostname(mmc), host->version);
 	}
 
+	if (host->quirks & SDHCI_QUIRK_BROKEN_CQE)
+		mmc->caps2 &= ~MMC_CAP2_CQE;
+
 	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
 		host->flags |= SDHCI_USE_SDMA;
 	else if (!(host->caps & SDHCI_CAN_DO_SDMA))
@@ -3859,11 +3945,9 @@
 	}
 
 	if (host->version >= SDHCI_SPEC_300)
-		host->max_clk = (host->caps & SDHCI_CLOCK_V3_BASE_MASK)
-			>> SDHCI_CLOCK_BASE_SHIFT;
+		host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps);
 	else
-		host->max_clk = (host->caps & SDHCI_CLOCK_BASE_MASK)
-			>> SDHCI_CLOCK_BASE_SHIFT;
+		host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps);
 
 	host->max_clk *= 1000000;
 	if (host->max_clk == 0 || host->quirks &
@@ -3881,8 +3965,7 @@
 	 * In case of Host Controller v3.00, find out whether clock
 	 * multiplier is supported.
 	 */
-	host->clk_mul = (host->caps1 & SDHCI_CLOCK_MUL_MASK) >>
-			SDHCI_CLOCK_MUL_SHIFT;
+	host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1);
 
 	/*
 	 * In case the value in Clock Multiplier is 0, then programmable
@@ -3901,11 +3984,13 @@
 	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;
 
@@ -3913,8 +3998,7 @@
 		mmc->f_max = max_clk;
 
 	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-		host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >>
-					SDHCI_TIMEOUT_CLK_SHIFT;
+		host->timeout_clk = FIELD_GET(SDHCI_TIMEOUT_CLK_MASK, host->caps);
 
 		if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
 			host->timeout_clk *= 1000;
@@ -4040,8 +4124,10 @@
 	}
 
 	if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
-	    (host->caps1 & SDHCI_SUPPORT_HS400))
-		mmc->caps2 |= MMC_CAP2_HS400;
+	    (host->caps1 & SDHCI_SUPPORT_HS400)) {
+		if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS400))
+			mmc->caps2 |= MMC_CAP2_HS400;
+	}
 
 	if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
 	    (IS_ERR(mmc->supply.vqmmc) ||
@@ -4066,8 +4152,8 @@
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
 
 	/* Initial value for re-tuning timer count */
-	host->tuning_count = (host->caps1 & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
-			     SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+	host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK,
+				       host->caps1);
 
 	/*
 	 * In case Re-tuning Timer is not disabled, the actual value of
@@ -4077,8 +4163,7 @@
 		host->tuning_count = 1 << (host->tuning_count - 1);
 
 	/* Re-tuning mode supported by the Host Controller */
-	host->tuning_mode = (host->caps1 & SDHCI_RETUNING_MODE_MASK) >>
-			     SDHCI_RETUNING_MODE_SHIFT;
+	host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1);
 
 	ocr_avail = 0;
 
@@ -4100,35 +4185,32 @@
 
 			curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
 			max_current_caps =
-				(curr << SDHCI_MAX_CURRENT_330_SHIFT) |
-				(curr << SDHCI_MAX_CURRENT_300_SHIFT) |
-				(curr << SDHCI_MAX_CURRENT_180_SHIFT);
+				FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, curr) |
+				FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, curr) |
+				FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, curr);
 		}
 	}
 
 	if (host->caps & SDHCI_CAN_VDD_330) {
 		ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
-		mmc->max_current_330 = ((max_current_caps &
-				   SDHCI_MAX_CURRENT_330_MASK) >>
-				   SDHCI_MAX_CURRENT_330_SHIFT) *
-				   SDHCI_MAX_CURRENT_MULTIPLIER;
+		mmc->max_current_330 = FIELD_GET(SDHCI_MAX_CURRENT_330_MASK,
+						 max_current_caps) *
+						SDHCI_MAX_CURRENT_MULTIPLIER;
 	}
 	if (host->caps & SDHCI_CAN_VDD_300) {
 		ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
 
-		mmc->max_current_300 = ((max_current_caps &
-				   SDHCI_MAX_CURRENT_300_MASK) >>
-				   SDHCI_MAX_CURRENT_300_SHIFT) *
-				   SDHCI_MAX_CURRENT_MULTIPLIER;
+		mmc->max_current_300 = FIELD_GET(SDHCI_MAX_CURRENT_300_MASK,
+						 max_current_caps) *
+						SDHCI_MAX_CURRENT_MULTIPLIER;
 	}
 	if (host->caps & SDHCI_CAN_VDD_180) {
 		ocr_avail |= MMC_VDD_165_195;
 
-		mmc->max_current_180 = ((max_current_caps &
-				   SDHCI_MAX_CURRENT_180_MASK) >>
-				   SDHCI_MAX_CURRENT_180_SHIFT) *
-				   SDHCI_MAX_CURRENT_MULTIPLIER;
+		mmc->max_current_180 = FIELD_GET(SDHCI_MAX_CURRENT_180_MASK,
+						 max_current_caps) *
+						SDHCI_MAX_CURRENT_MULTIPLIER;
 	}
 
 	/* If OCR set by host, use it instead. */
@@ -4201,10 +4283,12 @@
 	 * be larger than 64 KiB though.
 	 */
 	if (host->flags & SDHCI_USE_ADMA) {
-		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
+		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
+			host->max_adma = 65532; /* 32-bit alignment */
 			mmc->max_seg_size = 65535;
-		else
+		} else {
 			mmc->max_seg_size = 65536;
+		}
 	} else {
 		mmc->max_seg_size = mmc->max_req_size;
 	}
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci.h
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci.h
@@ -9,6 +9,7 @@
 #ifndef __SDHCI_HW_H
 #define __SDHCI_HW_H
 
+#include <linux/bits.h>
 #include <linux/scatterlist.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
@@ -199,12 +200,10 @@
 #define  SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000
 
 #define SDHCI_CAPABILITIES	0x40
-#define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
-#define  SDHCI_TIMEOUT_CLK_SHIFT 0
+#define  SDHCI_TIMEOUT_CLK_MASK		GENMASK(5, 0)
 #define  SDHCI_TIMEOUT_CLK_UNIT	0x00000080
-#define  SDHCI_CLOCK_BASE_MASK	0x00003F00
-#define  SDHCI_CLOCK_V3_BASE_MASK	0x0000FF00
-#define  SDHCI_CLOCK_BASE_SHIFT	8
+#define  SDHCI_CLOCK_BASE_MASK		GENMASK(13, 8)
+#define  SDHCI_CLOCK_V3_BASE_MASK	GENMASK(15, 8)
 #define  SDHCI_MAX_BLOCK_MASK	0x00030000
 #define  SDHCI_MAX_BLOCK_SHIFT  16
 #define  SDHCI_CAN_DO_8BIT	0x00040000
@@ -225,26 +224,20 @@
 #define  SDHCI_DRIVER_TYPE_A	0x00000010
 #define  SDHCI_DRIVER_TYPE_C	0x00000020
 #define  SDHCI_DRIVER_TYPE_D	0x00000040
-#define  SDHCI_RETUNING_TIMER_COUNT_MASK	0x00000F00
-#define  SDHCI_RETUNING_TIMER_COUNT_SHIFT	8
+#define  SDHCI_RETUNING_TIMER_COUNT_MASK	GENMASK(11, 8)
 #define  SDHCI_USE_SDR50_TUNING			0x00002000
-#define  SDHCI_RETUNING_MODE_MASK		0x0000C000
-#define  SDHCI_RETUNING_MODE_SHIFT		14
-#define  SDHCI_CLOCK_MUL_MASK	0x00FF0000
-#define  SDHCI_CLOCK_MUL_SHIFT	16
+#define  SDHCI_RETUNING_MODE_MASK		GENMASK(15, 14)
+#define  SDHCI_CLOCK_MUL_MASK			GENMASK(23, 16)
 #define  SDHCI_CAN_DO_ADMA3	0x08000000
 #define  SDHCI_SUPPORT_HS400	0x80000000 /* Non-standard */
 
 #define SDHCI_CAPABILITIES_1	0x44
 
 #define SDHCI_MAX_CURRENT		0x48
-#define  SDHCI_MAX_CURRENT_LIMIT	0xFF
-#define  SDHCI_MAX_CURRENT_330_MASK	0x0000FF
-#define  SDHCI_MAX_CURRENT_330_SHIFT	0
-#define  SDHCI_MAX_CURRENT_300_MASK	0x00FF00
-#define  SDHCI_MAX_CURRENT_300_SHIFT	8
-#define  SDHCI_MAX_CURRENT_180_MASK	0xFF0000
-#define  SDHCI_MAX_CURRENT_180_SHIFT	16
+#define  SDHCI_MAX_CURRENT_LIMIT	GENMASK(7, 0)
+#define  SDHCI_MAX_CURRENT_330_MASK	GENMASK(7, 0)
+#define  SDHCI_MAX_CURRENT_300_MASK	GENMASK(15, 8)
+#define  SDHCI_MAX_CURRENT_180_MASK	GENMASK(23, 16)
 #define   SDHCI_MAX_CURRENT_MULTIPLIER	4
 
 /* 4C-4F reserved for more max current */
@@ -261,18 +254,16 @@
 
 /* 60-FB reserved */
 
+#define SDHCI_PRESET_FOR_HIGH_SPEED	0x64
 #define SDHCI_PRESET_FOR_SDR12 0x66
 #define SDHCI_PRESET_FOR_SDR25 0x68
 #define SDHCI_PRESET_FOR_SDR50 0x6A
 #define SDHCI_PRESET_FOR_SDR104        0x6C
 #define SDHCI_PRESET_FOR_DDR50 0x6E
 #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
-#define SDHCI_PRESET_DRV_MASK  0xC000
-#define SDHCI_PRESET_DRV_SHIFT  14
-#define SDHCI_PRESET_CLKGEN_SEL_MASK   0x400
-#define SDHCI_PRESET_CLKGEN_SEL_SHIFT	10
-#define SDHCI_PRESET_SDCLK_FREQ_MASK   0x3FF
-#define SDHCI_PRESET_SDCLK_FREQ_SHIFT	0
+#define SDHCI_PRESET_DRV_MASK		GENMASK(15, 14)
+#define SDHCI_PRESET_CLKGEN_SEL		BIT(10)
+#define SDHCI_PRESET_SDCLK_FREQ_MASK	GENMASK(9, 0)
 
 #define SDHCI_SLOT_INT_STATUS	0xFC
 
@@ -348,7 +339,8 @@
 
 /*
  * Maximum segments assuming a 512KiB maximum requisition size and a minimum
- * 4KiB page size.
+ * 4KiB page size. Note this also allows enough for multiple descriptors in
+ * case of PAGE_SIZE >= 64KiB.
  */
 #define SDHCI_MAX_SEGS		128
 
@@ -409,6 +401,8 @@
 #define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15)
 /* Controller reports inverted write-protect state */
 #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16)
+/* Controller has unusable command queue engine */
+#define SDHCI_QUIRK_BROKEN_CQE				(1<<17)
 /* Controller does not like fast PIO transfers */
 #define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)
 /* Controller does not have a LED */
@@ -482,6 +476,9 @@
  * block count.
  */
 #define SDHCI_QUIRK2_USE_32BIT_BLK_CNT			(1<<18)
+/* HS400 should not be used */
+#define SDHCI_QUIRK2_BROKEN_HS400				(1<<30)
+
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
@@ -526,6 +523,8 @@
 
 	unsigned int clock;	/* Current clock (MHz) */
 	u8 pwr;			/* Current voltage */
+	u8 drv_type;		/* Current UHS-I driver type */
+	bool reinit_uhs;	/* Force UHS-related re-initialization */
 
 	bool runtime_suspended;	/* Host is runtime suspended */
 	bool bus_on;		/* Bus power prevents runtime suspend */
@@ -544,6 +543,7 @@
 	unsigned int blocks;	/* remaining PIO blocks */
 
 	int sg_count;		/* Mapped sg entries */
+	int max_adma;		/* Max. length in ADMA descriptor */
 
 	void *adma_table;	/* ADMA descriptor table */
 	void *align_buffer;	/* Bounce buffer */
@@ -644,6 +644,7 @@
 	void	(*voltage_switch)(struct sdhci_host *host);
 	void	(*adma_write_desc)(struct sdhci_host *host, void **desc,
 				   dma_addr_t addr, int len, unsigned int cmd);
+	void    (*dump_vendor_regs)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -793,5 +794,7 @@
 void sdhci_reset_tuning(struct sdhci_host *host);
 void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
 void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
+void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable);
+void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
 
 #endif /* __SDHCI_HW_H */
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci_am654.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci_am654.c
@@ -227,8 +227,6 @@
 		 */
 		case MMC_TIMING_SD_HS:
 		case MMC_TIMING_MMC_HS:
-		case MMC_TIMING_UHS_SDR12:
-		case MMC_TIMING_UHS_SDR25:
 			val &= ~SDHCI_CTRL_HISPD;
 		}
 	}
@@ -236,6 +234,22 @@
 	writeb(val, host->ioaddr + reg);
 }
 
+static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int err = sdhci_execute_tuning(mmc, opcode);
+
+	if (err)
+		return err;
+	/*
+	 * Tuning data remains in the buffer after tuning.
+	 * Do a command and data reset to get rid of it
+	 */
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+	return 0;
+}
+
 static struct sdhci_ops sdhci_am654_ops = {
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@@ -249,8 +263,7 @@
 
 static const struct sdhci_pltfm_data sdhci_am654_pdata = {
 	.ops = &sdhci_am654_ops,
-	.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
-		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
@@ -272,8 +285,7 @@
 
 static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
 	.ops = &sdhci_j721e_8bit_ops,
-	.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
-		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
@@ -295,8 +307,7 @@
 
 static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
 	.ops = &sdhci_j721e_4bit_ops,
-	.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
-		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
@@ -480,6 +491,8 @@
 		goto pm_runtime_put;
 	}
 
+	host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning;
+
 	ret = sdhci_am654_init(host);
 	if (ret)
 		goto pm_runtime_put;
--- linux-ein-5.4.0.orig/drivers/mmc/host/sdhci_f_sdh30.c
+++ linux-ein-5.4.0/drivers/mmc/host/sdhci_f_sdh30.c
@@ -50,9 +50,16 @@
 	bool enable_cmd_dat_delay;
 };
 
+static void *sdhci_f_sdhost_priv(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return sdhci_pltfm_priv(pltfm_host);
+}
+
 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
 {
-	struct f_sdhost_priv *priv = sdhci_priv(host);
+	struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host);
 	u32 ctrl = 0;
 
 	usleep_range(2500, 3000);
@@ -85,7 +92,7 @@
 
 static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
 {
-	struct f_sdhost_priv *priv = sdhci_priv(host);
+	struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host);
 	u32 ctl;
 
 	if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
@@ -109,31 +116,32 @@
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
+static const struct sdhci_pltfm_data sdhci_f_sdh30_pltfm_data = {
+	.ops = &sdhci_f_sdh30_ops,
+	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
+		| SDHCI_QUIRK_INVERTED_WRITE_PROTECT,
+	.quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE
+		|  SDHCI_QUIRK2_TUNING_WORK_AROUND,
+};
+
 static int sdhci_f_sdh30_probe(struct platform_device *pdev)
 {
 	struct sdhci_host *host;
 	struct device *dev = &pdev->dev;
-	struct resource *res;
-	int irq, ctrl = 0, ret = 0;
+	int ctrl = 0, ret = 0;
 	struct f_sdhost_priv *priv;
+	struct sdhci_pltfm_host *pltfm_host;
 	u32 reg = 0;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
+	host = sdhci_pltfm_init(pdev, &sdhci_f_sdh30_pltfm_data,
+				sizeof(struct f_sdhost_priv));
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
-	priv = sdhci_priv(host);
+	pltfm_host = sdhci_priv(host);
+	priv = sdhci_pltfm_priv(pltfm_host);
 	priv->dev = dev;
 
-	host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
-		       SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
-	host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
-			SDHCI_QUIRK2_TUNING_WORK_AROUND;
-
 	priv->enable_cmd_dat_delay = device_property_read_bool(dev,
 						"fujitsu,cmd-dat-delay-select");
 
@@ -141,19 +149,6 @@
 	if (ret)
 		goto err;
 
-	platform_set_drvdata(pdev, host);
-
-	host->hw_name = "f_sdh30";
-	host->ops = &sdhci_f_sdh30_ops;
-	host->irq = irq;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->ioaddr)) {
-		ret = PTR_ERR(host->ioaddr);
-		goto err;
-	}
-
 	if (dev_of_node(dev)) {
 		sdhci_get_of_property(pdev);
 
@@ -194,6 +189,9 @@
 	if (reg & SDHCI_CAN_DO_8BIT)
 		priv->vendor_hs200 = F_SDH30_EMMC_HS200;
 
+	if (!(reg & SDHCI_TIMEOUT_CLK_MASK))
+		host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
+
 	ret = sdhci_add_host(host);
 	if (ret)
 		goto err_add_host;
@@ -205,23 +203,22 @@
 err_clk:
 	clk_disable_unprepare(priv->clk_iface);
 err:
-	sdhci_free_host(host);
+	sdhci_pltfm_free(pdev);
+
 	return ret;
 }
 
 static int sdhci_f_sdh30_remove(struct platform_device *pdev)
 {
 	struct sdhci_host *host = platform_get_drvdata(pdev);
-	struct f_sdhost_priv *priv = sdhci_priv(host);
-
-	sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
-			  0xffffffff);
+	struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host);
+	struct clk *clk_iface = priv->clk_iface;
+	struct clk *clk = priv->clk;
 
-	clk_disable_unprepare(priv->clk_iface);
-	clk_disable_unprepare(priv->clk);
+	sdhci_pltfm_unregister(pdev);
 
-	sdhci_free_host(host);
-	platform_set_drvdata(pdev, NULL);
+	clk_disable_unprepare(clk_iface);
+	clk_disable_unprepare(clk);
 
 	return 0;
 }
@@ -245,6 +242,7 @@
 static struct platform_driver sdhci_f_sdh30_driver = {
 	.driver = {
 		.name = "f_sdh30",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(f_sdh30_dt_ids),
 		.acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids),
 		.pm	= &sdhci_pltfm_pmops,
--- linux-ein-5.4.0.orig/drivers/mmc/host/sh_mmcif.c
+++ linux-ein-5.4.0/drivers/mmc/host/sh_mmcif.c
@@ -1395,7 +1395,7 @@
 	irq[0] = platform_get_irq(pdev, 0);
 	irq[1] = platform_get_irq_optional(pdev, 1);
 	if (irq[0] < 0)
-		return -ENXIO;
+		return irq[0];
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	reg = devm_ioremap_resource(dev, res);
@@ -1560,6 +1560,7 @@
 	.remove		= sh_mmcif_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm	= &sh_mmcif_dev_pm_ops,
 		.of_match_table = sh_mmcif_of_match,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/sunxi-mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/sunxi-mmc.c
@@ -1314,8 +1314,8 @@
 		return ret;
 
 	host->irq = platform_get_irq(pdev, 0);
-	if (host->irq <= 0) {
-		ret = -EINVAL;
+	if (host->irq < 0) {
+		ret = host->irq;
 		goto error_disable_mmc;
 	}
 
@@ -1456,9 +1456,11 @@
 	struct sunxi_mmc_host *host = mmc_priv(mmc);
 
 	mmc_remove_host(mmc);
-	pm_runtime_force_suspend(&pdev->dev);
-	disable_irq(host->irq);
-	sunxi_mmc_disable(host);
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev)) {
+		disable_irq(host->irq);
+		sunxi_mmc_disable(host);
+	}
 	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 	mmc_free_host(mmc);
 
@@ -1511,6 +1513,7 @@
 static struct platform_driver sunxi_mmc_driver = {
 	.driver = {
 		.name	= "sunxi-mmc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = of_match_ptr(sunxi_mmc_of_match),
 		.pm = &sunxi_mmc_pm_ops,
 	},
--- linux-ein-5.4.0.orig/drivers/mmc/host/tmio_mmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/tmio_mmc.c
@@ -221,6 +221,7 @@
 static struct platform_driver tmio_mmc_driver = {
 	.driver = {
 		.name = "tmio-mmc",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm = &tmio_mmc_dev_pm_ops,
 	},
 	.probe = tmio_mmc_probe,
--- linux-ein-5.4.0.orig/drivers/mmc/host/tmio_mmc_core.c
+++ linux-ein-5.4.0/drivers/mmc/host/tmio_mmc_core.c
@@ -1184,7 +1184,7 @@
 	if (ret == -EPROBE_DEFER)
 		return ret;
 
-	mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
+	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_4_BIT_DATA | pdata->capabilities;
 	mmc->caps2 |= pdata->capabilities2;
 	mmc->max_segs = pdata->max_segs ? : 32;
 	mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
@@ -1285,12 +1285,14 @@
 	cancel_work_sync(&host->done);
 	cancel_delayed_work_sync(&host->delayed_reset_work);
 	tmio_mmc_release_dma(host);
+	tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
 
-	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	if (host->native_hotplug)
 		pm_runtime_put_noidle(&pdev->dev);
-	pm_runtime_put_sync(&pdev->dev);
+
 	pm_runtime_disable(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/toshsd.c
+++ linux-ein-5.4.0/drivers/mmc/host/toshsd.c
@@ -651,7 +651,9 @@
 	if (ret)
 		goto unmap;
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto free_irq;
 
 	base = pci_resource_start(pdev, 0);
 	dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq);
@@ -660,6 +662,8 @@
 
 	return 0;
 
+free_irq:
+	free_irq(pdev->irq, host);
 unmap:
 	pci_iounmap(pdev, host->ioaddr);
 release:
--- linux-ein-5.4.0.orig/drivers/mmc/host/uniphier-sd.c
+++ linux-ein-5.4.0/drivers/mmc/host/uniphier-sd.c
@@ -614,11 +614,6 @@
 		}
 	}
 
-	ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED,
-			       dev_name(dev), host);
-	if (ret)
-		goto free_host;
-
 	if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)
 		host->dma_ops = &uniphier_sd_internal_dma_ops;
 	else
@@ -644,10 +639,19 @@
 
 	ret = tmio_mmc_host_probe(host);
 	if (ret)
-		goto free_host;
+		goto disable_clk;
+
+	ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED,
+			       dev_name(dev), host);
+	if (ret)
+		goto remove_host;
 
 	return 0;
 
+remove_host:
+	tmio_mmc_host_remove(host);
+disable_clk:
+	uniphier_sd_clk_disable(host);
 free_host:
 	tmio_mmc_host_free(host);
 
@@ -660,6 +664,7 @@
 
 	tmio_mmc_host_remove(host);
 	uniphier_sd_clk_disable(host);
+	tmio_mmc_host_free(host);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mmc/host/usdhi6rol0.c
+++ linux-ein-5.4.0/drivers/mmc/host/usdhi6rol0.c
@@ -1743,8 +1743,10 @@
 	irq_cd = platform_get_irq_byname(pdev, "card detect");
 	irq_sd = platform_get_irq_byname(pdev, "data");
 	irq_sdio = platform_get_irq_byname(pdev, "SDIO");
-	if (irq_sd < 0 || irq_sdio < 0)
-		return -ENODEV;
+	if (irq_sd < 0)
+		return irq_sd;
+	if (irq_sdio < 0)
+		return irq_sdio;
 
 	mmc = mmc_alloc_host(sizeof(struct usdhi6_host), dev);
 	if (!mmc)
@@ -1803,6 +1805,7 @@
 
 	version = usdhi6_read(host, USDHI6_VERSION);
 	if ((version & 0xfff) != 0xa0d) {
+		ret = -EPERM;
 		dev_err(dev, "Version not recognized %x\n", version);
 		goto e_clk_off;
 	}
@@ -1860,10 +1863,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:
@@ -1892,6 +1897,7 @@
 	.remove		= usdhi6_remove,
 	.driver		= {
 		.name	= "usdhi6rol0",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = usdhi6_of_match,
 	},
 };
--- linux-ein-5.4.0.orig/drivers/mmc/host/via-sdmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/via-sdmmc.c
@@ -319,6 +319,8 @@
 /* some devices need a very long delay for power to stabilize */
 #define VIA_CRDR_QUIRK_300MS_PWRDELAY	0x0001
 
+#define VIA_CMD_TIMEOUT_MS		1000
+
 static const struct pci_device_id via_ids[] = {
 	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
@@ -551,14 +553,17 @@
 {
 	void __iomem *addrbase;
 	struct mmc_data *data;
+	unsigned int timeout_ms;
 	u32 cmdctrl = 0;
 
 	WARN_ON(host->cmd);
 
 	data = cmd->data;
-	mod_timer(&host->timer, jiffies + HZ);
 	host->cmd = cmd;
 
+	timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : VIA_CMD_TIMEOUT_MS;
+	mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout_ms));
+
 	/*Command index*/
 	cmdctrl = cmd->opcode << 8;
 
@@ -852,6 +857,9 @@
 {
 	BUG_ON(intmask == 0);
 
+	if (!host->data)
+		return;
+
 	if (intmask & VIA_CRDR_SDSTS_DT)
 		host->data->error = -ETIMEDOUT;
 	else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC))
@@ -1146,7 +1154,9 @@
 	    pcidev->subsystem_device == 0x3891)
 		sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY;
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto unmap;
 
 	return 0;
 
@@ -1254,11 +1264,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-ein-5.4.0.orig/drivers/mmc/host/vub300.c
+++ linux-ein-5.4.0/drivers/mmc/host/vub300.c
@@ -576,7 +576,7 @@
 				GET_SYSTEM_PORT_STATUS,
 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				0x0000, 0x0000, &vub300->system_port_status,
-				sizeof(vub300->system_port_status), HZ);
+				sizeof(vub300->system_port_status), 1000);
 	if (sizeof(vub300->system_port_status) == retval)
 		new_system_port_status(vub300);
 }
@@ -1241,7 +1241,7 @@
 						SET_INTERRUPT_PSEUDOCODE,
 						USB_DIR_OUT | USB_TYPE_VENDOR |
 						USB_RECIP_DEVICE, 0x0000, 0x0000,
-						xfer_buffer, xfer_length, HZ);
+						xfer_buffer, xfer_length, 1000);
 			kfree(xfer_buffer);
 			if (retval < 0)
 				goto copy_error_message;
@@ -1284,7 +1284,7 @@
 						SET_TRANSFER_PSEUDOCODE,
 						USB_DIR_OUT | USB_TYPE_VENDOR |
 						USB_RECIP_DEVICE, 0x0000, 0x0000,
-						xfer_buffer, xfer_length, HZ);
+						xfer_buffer, xfer_length, 1000);
 			kfree(xfer_buffer);
 			if (retval < 0)
 				goto copy_error_message;
@@ -1715,6 +1715,9 @@
 	int bytes = 3 & less_cmd;
 	int words = less_cmd >> 2;
 	u8 *r = vub300->resp.response.command_response;
+
+	if (!resp_len)
+		return;
 	if (bytes == 3) {
 		cmd->resp[words] = (r[1 + (words << 2)] << 24)
 			| (r[2 + (words << 2)] << 16)
@@ -1991,7 +1994,7 @@
 		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
 				SET_CLOCK_SPEED,
 				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				0x00, 0x00, buf, buf_array_size, HZ);
+				0x00, 0x00, buf, buf_array_size, 1000);
 	if (retval != 8) {
 		dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
 			" %dkHz failed with retval=%d\n", kHzClock, retval);
@@ -2013,14 +2016,14 @@
 		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
 				SET_SD_POWER,
 				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				0x0000, 0x0000, NULL, 0, HZ);
+				0x0000, 0x0000, NULL, 0, 1000);
 		/* must wait for the VUB300 u-proc to boot up */
 		msleep(600);
 	} else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
 		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
 				SET_SD_POWER,
 				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				0x0001, 0x0000, NULL, 0, HZ);
+				0x0001, 0x0000, NULL, 0, 1000);
 		msleep(600);
 		vub300->card_powered = 1;
 	} else if (ios->power_mode == MMC_POWER_ON) {
@@ -2049,6 +2052,7 @@
 		return;
 	kref_get(&vub300->kref);
 	if (enable) {
+		set_current_state(TASK_RUNNING);
 		mutex_lock(&vub300->irq_mutex);
 		if (vub300->irqs_queued) {
 			vub300->irqs_queued -= 1;
@@ -2064,6 +2068,7 @@
 			vub300_queue_poll_work(vub300, 0);
 		}
 		mutex_unlock(&vub300->irq_mutex);
+		set_current_state(TASK_INTERRUPTIBLE);
 	} else {
 		vub300->irq_enabled = 0;
 	}
@@ -2282,14 +2287,14 @@
 				GET_HC_INF0,
 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				0x0000, 0x0000, &vub300->hc_info,
-				sizeof(vub300->hc_info), HZ);
+				sizeof(vub300->hc_info), 1000);
 	if (retval < 0)
 		goto error5;
 	retval =
-		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
 				SET_ROM_WAIT_STATES,
 				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
+				firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
 	if (retval < 0)
 		goto error5;
 	dev_info(&vub300->udev->dev,
@@ -2304,16 +2309,17 @@
 				GET_SYSTEM_PORT_STATUS,
 				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				0x0000, 0x0000, &vub300->system_port_status,
-				sizeof(vub300->system_port_status), HZ);
+				sizeof(vub300->system_port_status), 1000);
 	if (retval < 0) {
-		goto error4;
+		goto error5;
 	} else if (sizeof(vub300->system_port_status) == retval) {
 		vub300->card_present =
 			(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
 		vub300->read_only =
 			(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
 	} else {
-		goto error4;
+		retval = -EINVAL;
+		goto error5;
 	}
 	usb_set_intfdata(interface, vub300);
 	INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2336,8 +2342,13 @@
 			 "USB vub300 remote SDIO host controller[%d]"
 			 "connected with no SD/SDIO card inserted\n",
 			 interface_to_InterfaceNumber(interface));
-	mmc_add_host(mmc);
+	retval = mmc_add_host(mmc);
+	if (retval)
+		goto error6;
+
 	return 0;
+error6:
+	del_timer_sync(&vub300->inactivity_timer);
 error5:
 	mmc_free_host(mmc);
 	/*
--- linux-ein-5.4.0.orig/drivers/mmc/host/wbsd.c
+++ linux-ein-5.4.0/drivers/mmc/host/wbsd.c
@@ -1701,7 +1701,15 @@
 	 */
 	wbsd_init_device(host);
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		if (!pnp)
+			wbsd_chip_poweroff(host);
+
+		wbsd_release_resources(host);
+		wbsd_free_mmc(dev);
+		return ret;
+	}
 
 	pr_info("%s: W83L51xD", mmc_hostname(mmc));
 	if (host->chip_id != 0)
@@ -1903,6 +1911,7 @@
 	.resume		= wbsd_platform_resume,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/mmc/host/wmt-sdmmc.c
+++ linux-ein-5.4.0/drivers/mmc/host/wmt-sdmmc.c
@@ -849,7 +849,7 @@
 	if (IS_ERR(priv->clk_sdmmc)) {
 		dev_err(&pdev->dev, "Error getting clock\n");
 		ret = PTR_ERR(priv->clk_sdmmc);
-		goto fail5;
+		goto fail5_and_a_half;
 	}
 
 	ret = clk_prepare_enable(priv->clk_sdmmc);
@@ -859,13 +859,20 @@
 	/* configure the controller to a known 'ready' state */
 	wmt_reset_hardware(mmc);
 
-	mmc_add_host(mmc);
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto fail7;
 
 	dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
 
 	return 0;
+fail7:
+	clk_disable_unprepare(priv->clk_sdmmc);
 fail6:
 	clk_put(priv->clk_sdmmc);
+fail5_and_a_half:
+	dma_free_coherent(&pdev->dev, mmc->max_blk_count * 16,
+			  priv->dma_desc_buffer, priv->dma_desc_device_addr);
 fail5:
 	free_irq(dma_irq, priv);
 fail4:
@@ -990,6 +997,7 @@
 	.remove = wmt_mci_remove,
 	.driver = {
 		.name = DRIVER_NAME,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm = wmt_mci_pm_ops,
 		.of_match_table = wmt_mci_dt_ids,
 	},
--- linux-ein-5.4.0.orig/drivers/mtd/chips/Kconfig
+++ linux-ein-5.4.0/drivers/mtd/chips/Kconfig
@@ -55,12 +55,14 @@
 	  LITTLE_ENDIAN_BYTE, if the bytes are reversed.
 
 config MTD_CFI_NOSWAP
+	depends on !ARCH_IXP4XX || CPU_BIG_ENDIAN
 	bool "NO"
 
 config MTD_CFI_BE_BYTE_SWAP
 	bool "BIG_ENDIAN_BYTE"
 
 config MTD_CFI_LE_BYTE_SWAP
+	depends on !ARCH_IXP4XX
 	bool "LITTLE_ENDIAN_BYTE"
 
 endchoice
--- linux-ein-5.4.0.orig/drivers/mtd/chips/cfi_cmdset_0001.c
+++ linux-ein-5.4.0/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -420,8 +420,25 @@
 		extra_size = 0;
 
 		/* Protection Register info */
-		extra_size += (extp->NumProtectionFields - 1) *
-			      sizeof(struct cfi_intelext_otpinfo);
+		if (extp->NumProtectionFields) {
+			struct cfi_intelext_otpinfo *otp =
+				(struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+			extra_size += (extp->NumProtectionFields - 1) *
+				sizeof(struct cfi_intelext_otpinfo);
+
+			if (extp_size >= sizeof(*extp) + extra_size) {
+				int i;
+
+				/* Do some byteswapping if necessary */
+				for (i = 0; i < extp->NumProtectionFields - 1; i++) {
+					otp->ProtRegAddr = le32_to_cpu(otp->ProtRegAddr);
+					otp->FactGroups = le16_to_cpu(otp->FactGroups);
+					otp->UserGroups = le16_to_cpu(otp->UserGroups);
+					otp++;
+				}
+			}
+		}
 	}
 
 	if (extp->MinorVersion >= '1') {
@@ -695,14 +712,16 @@
 	 */
 	if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
 	    && extp->FeatureSupport & (1 << 9)) {
+		int offs = 0;
 		struct cfi_private *newcfi;
 		struct flchip *chip;
 		struct flchip_shared *shared;
-		int offs, numregions, numparts, partshift, numvirtchips, i, j;
+		int numregions, numparts, partshift, numvirtchips, i, j;
 
 		/* Protection Register info */
-		offs = (extp->NumProtectionFields - 1) *
-		       sizeof(struct cfi_intelext_otpinfo);
+		if (extp->NumProtectionFields)
+			offs = (extp->NumProtectionFields - 1) *
+			       sizeof(struct cfi_intelext_otpinfo);
 
 		/* Burst Read info */
 		offs += extp->extra[offs+1]+2;
--- linux-ein-5.4.0.orig/drivers/mtd/chips/cfi_cmdset_0002.c
+++ linux-ein-5.4.0/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -59,6 +59,10 @@
 #define CFI_SR_WBASB		BIT(3)
 #define CFI_SR_SLSB		BIT(1)
 
+enum cfi_quirks {
+	CFI_QUIRK_DQ_TRUE_DATA = BIT(0),
+};
+
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 #if !FORCE_WORD_WRITE
@@ -119,23 +123,27 @@
 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
 	u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ;
 
-	return extp->MinorVersion >= '5' &&
+	return extp && extp->MinorVersion >= '5' &&
 		(extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG;
 }
 
-static void cfi_check_err_status(struct map_info *map, struct flchip *chip,
-				 unsigned long adr)
+static int cfi_check_err_status(struct map_info *map, struct flchip *chip,
+				unsigned long adr)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status;
 
 	if (!cfi_use_status_reg(cfi))
-		return;
+		return 0;
 
 	cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
 			 cfi->device_type, NULL);
 	status = map_read(map, adr);
 
+	/* The error bits are invalid while the chip's busy */
+	if (!map_word_bitsset(map, status, CMD(CFI_SR_DRB)))
+		return 0;
+
 	if (map_word_bitsset(map, status, CMD(0x3a))) {
 		unsigned long chipstatus = MERGESTATUS(status);
 
@@ -151,7 +159,12 @@
 		if (chipstatus & CFI_SR_SLSB)
 			pr_err("%s sector write protected, status %lx\n",
 			       map->name, chipstatus);
+
+		/* Erase/Program status bits are set on the operation failure */
+		if (chipstatus & (CFI_SR_ESB | CFI_SR_PSB))
+			return 1;
 	}
+	return 0;
 }
 
 /* #define DEBUG_CFI_FEATURES */
@@ -423,6 +436,15 @@
 		mtd->name);
 }
 
+static void fixup_quirks(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	if (cfi->mfr == CFI_MFR_AMD && cfi->id == 0x0c01)
+		cfi->quirks |= CFI_QUIRK_DQ_TRUE_DATA;
+}
+
 /* Used to fix CFI-Tables of chips without Extended Query Tables */
 static struct cfi_fixup cfi_nopri_fixup_table[] = {
 	{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
@@ -461,6 +483,7 @@
 #if !FORCE_WORD_WRITE
 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
 #endif
+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_quirks },
 	{ 0, 0, NULL }
 };
 static struct cfi_fixup jedec_fixup_table[] = {
@@ -785,26 +808,29 @@
 	kfree(mtd->eraseregions);
 	kfree(mtd);
 	kfree(cfi->cmdset_priv);
-	kfree(cfi->cfiq);
 	return NULL;
 }
 
 /*
- * Return true if the chip is ready.
+ * Return true if the chip is ready and has the correct value.
  *
  * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
  * non-suspended sector) and is indicated by no toggle bits toggling.
  *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
  * Note that anything more complicated than checking if no bits are toggling
  * (including checking DQ5 for an error status) is tricky to get working
  * correctly and is therefore not done	(particularly with interleaved chips
  * as each chip must be checked independently of the others).
  */
 static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
-			       unsigned long addr)
+			       unsigned long addr, map_word *expected)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word d, t;
+	int ret;
 
 	if (cfi_use_status_reg(cfi)) {
 		map_word ready = CMD(CFI_SR_DRB);
@@ -814,61 +840,32 @@
 		 */
 		cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
 				 cfi->device_type, NULL);
-		d = map_read(map, addr);
+		t = map_read(map, addr);
 
-		return map_word_andequal(map, d, ready, ready);
+		return map_word_andequal(map, t, ready, ready);
 	}
 
 	d = map_read(map, addr);
 	t = map_read(map, addr);
 
-	return map_word_equal(map, d, t);
+	ret = map_word_equal(map, d, t);
+
+	if (!ret || !expected)
+		return ret;
+
+	return map_word_equal(map, t, *expected);
 }
 
-/*
- * Return true if the chip is ready and has the correct value.
- *
- * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
- * non-suspended sector) and it is indicated by no bits toggling.
- *
- * Error are indicated by toggling bits or bits held with the wrong value,
- * or with bits toggling.
- *
- * Note that anything more complicated than checking if no bits are toggling
- * (including checking DQ5 for an error status) is tricky to get working
- * correctly and is therefore not done	(particularly with interleaved chips
- * as each chip must be checked independently of the others).
- *
- */
 static int __xipram chip_good(struct map_info *map, struct flchip *chip,
-			      unsigned long addr, map_word expected)
+			      unsigned long addr, map_word *expected)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	map_word oldd, curd;
-
-	if (cfi_use_status_reg(cfi)) {
-		map_word ready = CMD(CFI_SR_DRB);
-		map_word err = CMD(CFI_SR_PSB | CFI_SR_ESB);
-		/*
-		 * For chips that support status register, check device
-		 * ready bit and Erase/Program status bit to know if
-		 * operation succeeded.
-		 */
-		cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
-				 cfi->device_type, NULL);
-		curd = map_read(map, addr);
-
-		if (map_word_andequal(map, curd, ready, ready))
-			return !map_word_bitsset(map, curd, err);
-
-		return 0;
-	}
+	map_word *datum = expected;
 
-	oldd = map_read(map, addr);
-	curd = map_read(map, addr);
+	if (cfi->quirks & CFI_QUIRK_DQ_TRUE_DATA)
+		datum = NULL;
 
-	return	map_word_equal(map, oldd, curd) &&
-		map_word_equal(map, curd, expected);
+	return chip_ready(map, chip, addr, datum);
 }
 
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
@@ -885,7 +882,7 @@
 
 	case FL_STATUS:
 		for (;;) {
-			if (chip_ready(map, chip, adr))
+			if (chip_ready(map, chip, adr, NULL))
 				break;
 
 			if (time_after(jiffies, timeo)) {
@@ -923,7 +920,7 @@
 		chip->state = FL_ERASE_SUSPENDING;
 		chip->erase_suspended = 1;
 		for (;;) {
-			if (chip_ready(map, chip, adr))
+			if (chip_ready(map, chip, adr, NULL))
 				break;
 
 			if (time_after(jiffies, timeo)) {
@@ -1455,7 +1452,7 @@
 	/* wait for chip to become ready */
 	timeo = jiffies + msecs_to_jiffies(2);
 	for (;;) {
-		if (chip_ready(map, chip, adr))
+		if (chip_ready(map, chip, adr, NULL))
 			break;
 
 		if (time_after(jiffies, timeo)) {
@@ -1691,7 +1688,7 @@
 		 * "chip_good" to avoid the failure due to scheduling.
 		 */
 		if (time_after(jiffies, timeo) &&
-		    !chip_good(map, chip, adr, datum)) {
+		    !chip_good(map, chip, adr, &datum)) {
 			xip_enable(map, chip, adr);
 			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
 			xip_disable(map, chip, adr);
@@ -1699,8 +1696,11 @@
 			break;
 		}
 
-		if (chip_good(map, chip, adr, datum))
+		if (chip_good(map, chip, adr, &datum)) {
+			if (cfi_check_err_status(map, chip, adr))
+				ret = -EIO;
 			break;
+		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
 		UDELAY(map, chip, adr, 1);
@@ -1773,7 +1773,6 @@
 	ret = do_write_oneword_once(map, chip, adr, datum, mode, cfi);
 	if (ret) {
 		/* reset on all failures. */
-		cfi_check_err_status(map, chip, adr);
 		map_write(map, CMD(0xF0), chip->start);
 		/* FIXME - should have reset delay before continuing */
 
@@ -1969,13 +1968,18 @@
 		 * "chip_good" to avoid the failure due to scheduling.
 		 */
 		if (time_after(jiffies, timeo) &&
-		    !chip_good(map, chip, adr, datum)) {
+		    !chip_good(map, chip, adr, &datum)) {
+			pr_err("MTD %s(): software timeout, address:0x%.8lx.\n",
+			       __func__, adr);
 			ret = -EIO;
 			break;
 		}
 
-		if (chip_good(map, chip, adr, datum))
+		if (chip_good(map, chip, adr, &datum)) {
+			if (cfi_check_err_status(map, chip, adr))
+				ret = -EIO;
 			break;
+		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
 		UDELAY(map, chip, adr, 1);
@@ -2071,12 +2075,8 @@
 				chip->word_write_time);
 
 	ret = do_write_buffer_wait(map, chip, adr, datum);
-	if (ret) {
-		cfi_check_err_status(map, chip, adr);
+	if (ret)
 		do_write_buffer_reset(map, chip, cfi);
-		pr_err("MTD %s(): software timeout, address:0x%.8lx.\n",
-		       __func__, adr);
-	}
 
 	xip_enable(map, chip, adr);
 
@@ -2184,7 +2184,7 @@
 	 * If the driver thinks the chip is idle, and no toggle bits
 	 * are changing, then the chip is actually idle for sure.
 	 */
-	if (chip->state == FL_READY && chip_ready(map, chip, adr))
+	if (chip->state == FL_READY && chip_ready(map, chip, adr, NULL))
 		return 0;
 
 	/*
@@ -2201,7 +2201,7 @@
 
 		/* wait for the chip to become ready */
 		for (i = 0; i < jiffies_to_usecs(timeo); i++) {
-			if (chip_ready(map, chip, adr))
+			if (chip_ready(map, chip, adr, NULL))
 				return 0;
 
 			udelay(1);
@@ -2265,15 +2265,15 @@
 	map_write(map, datum, adr);
 
 	for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
-		if (chip_ready(map, chip, adr))
+		if (chip_ready(map, chip, adr, NULL))
 			break;
 
 		udelay(1);
 	}
 
-	if (!chip_good(map, chip, adr, datum)) {
+	if (!chip_ready(map, chip, adr, &datum) ||
+	    cfi_check_err_status(map, chip, adr)) {
 		/* reset on all failures. */
-		cfi_check_err_status(map, chip, adr);
 		map_write(map, CMD(0xF0), chip->start);
 		/* FIXME - should have reset delay before continuing */
 
@@ -2413,6 +2413,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
 	int retry_cnt = 0;
+	map_word datum = map_word_ff(map);
 
 	adr = cfi->addr_unlock1;
 
@@ -2467,8 +2468,11 @@
 			chip->erase_suspended = 0;
 		}
 
-		if (chip_good(map, chip, adr, map_word_ff(map)))
+		if (chip_ready(map, chip, adr, &datum)) {
+			if (cfi_check_err_status(map, chip, adr))
+				ret = -EIO;
 			break;
+		}
 
 		if (time_after(jiffies, timeo)) {
 			printk(KERN_WARNING "MTD %s(): software timeout\n",
@@ -2483,7 +2487,6 @@
 	/* Did we succeed? */
 	if (ret) {
 		/* reset on all failures. */
-		cfi_check_err_status(map, chip, adr);
 		map_write(map, CMD(0xF0), chip->start);
 		/* FIXME - should have reset delay before continuing */
 
@@ -2510,6 +2513,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
 	int retry_cnt = 0;
+	map_word datum = map_word_ff(map);
 
 	adr += chip->start;
 
@@ -2564,8 +2568,11 @@
 			chip->erase_suspended = 0;
 		}
 
-		if (chip_good(map, chip, adr, map_word_ff(map)))
+		if (chip_ready(map, chip, adr, &datum)) {
+			if (cfi_check_err_status(map, chip, adr))
+				ret = -EIO;
 			break;
+		}
 
 		if (time_after(jiffies, timeo)) {
 			printk(KERN_WARNING "MTD %s(): software timeout\n",
@@ -2580,7 +2587,6 @@
 	/* Did we succeed? */
 	if (ret) {
 		/* reset on all failures. */
-		cfi_check_err_status(map, chip, adr);
 		map_write(map, CMD(0xF0), chip->start);
 		/* FIXME - should have reset delay before continuing */
 
@@ -2756,7 +2762,7 @@
 	 */
 	timeo = jiffies + msecs_to_jiffies(2000);	/* 2s max (un)locking */
 	for (;;) {
-		if (chip_ready(map, chip, adr))
+		if (chip_ready(map, chip, adr, NULL))
 			break;
 
 		if (time_after(jiffies, timeo)) {
--- linux-ein-5.4.0.orig/drivers/mtd/devices/docg3.c
+++ linux-ein-5.4.0/drivers/mtd/devices/docg3.c
@@ -1975,9 +1975,14 @@
 		dev_err(dev, "No I/O memory resource defined\n");
 		return ret;
 	}
-	base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
 
 	ret = -ENOMEM;
+	base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
+	if (!base) {
+		dev_err(dev, "devm_ioremap dev failed\n");
+		return ret;
+	}
+
 	cascade = devm_kcalloc(dev, DOC_MAX_NBFLOORS, sizeof(*cascade),
 			       GFP_KERNEL);
 	if (!cascade)
--- linux-ein-5.4.0.orig/drivers/mtd/devices/mchp23k256.c
+++ linux-ein-5.4.0/drivers/mtd/devices/mchp23k256.c
@@ -64,15 +64,17 @@
 	struct spi_transfer transfer[2] = {};
 	struct spi_message message;
 	unsigned char command[MAX_CMD_SIZE];
-	int ret;
+	int ret, cmd_len;
 
 	spi_message_init(&message);
 
+	cmd_len = mchp23k256_cmdsz(flash);
+
 	command[0] = MCHP23K256_CMD_WRITE;
 	mchp23k256_addr2cmd(flash, to, command);
 
 	transfer[0].tx_buf = command;
-	transfer[0].len = mchp23k256_cmdsz(flash);
+	transfer[0].len = cmd_len;
 	spi_message_add_tail(&transfer[0], &message);
 
 	transfer[1].tx_buf = buf;
@@ -88,8 +90,8 @@
 	if (ret)
 		return ret;
 
-	if (retlen && message.actual_length > sizeof(command))
-		*retlen += message.actual_length - sizeof(command);
+	if (retlen && message.actual_length > cmd_len)
+		*retlen += message.actual_length - cmd_len;
 
 	return 0;
 }
@@ -101,16 +103,18 @@
 	struct spi_transfer transfer[2] = {};
 	struct spi_message message;
 	unsigned char command[MAX_CMD_SIZE];
-	int ret;
+	int ret, cmd_len;
 
 	spi_message_init(&message);
 
+	cmd_len = mchp23k256_cmdsz(flash);
+
 	memset(&transfer, 0, sizeof(transfer));
 	command[0] = MCHP23K256_CMD_READ;
 	mchp23k256_addr2cmd(flash, from, command);
 
 	transfer[0].tx_buf = command;
-	transfer[0].len = mchp23k256_cmdsz(flash);
+	transfer[0].len = cmd_len;
 	spi_message_add_tail(&transfer[0], &message);
 
 	transfer[1].rx_buf = buf;
@@ -126,8 +130,8 @@
 	if (ret)
 		return ret;
 
-	if (retlen && message.actual_length > sizeof(command))
-		*retlen += message.actual_length - sizeof(command);
+	if (retlen && message.actual_length > cmd_len)
+		*retlen += message.actual_length - cmd_len;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/mtd/devices/phram.c
+++ linux-ein-5.4.0/drivers/mtd/devices/phram.c
@@ -243,22 +243,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-ein-5.4.0.orig/drivers/mtd/devices/spear_smi.c
+++ linux-ein-5.4.0/drivers/mtd/devices/spear_smi.c
@@ -592,6 +592,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)
 {
@@ -614,7 +634,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-ein-5.4.0.orig/drivers/mtd/devices/st_spi_fsm.c
+++ linux-ein-5.4.0/drivers/mtd/devices/st_spi_fsm.c
@@ -2116,10 +2116,12 @@
 		(long long)fsm->mtd.size, (long long)(fsm->mtd.size >> 20),
 		fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10));
 
-	return mtd_device_register(&fsm->mtd, NULL, 0);
-
+	ret = mtd_device_register(&fsm->mtd, NULL, 0);
+	if (ret) {
 err_clk_unprepare:
-	clk_disable_unprepare(fsm->clk);
+		clk_disable_unprepare(fsm->clk);
+	}
+
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/mtd/lpddr/lpddr2_nvm.c
+++ linux-ein-5.4.0/drivers/mtd/lpddr/lpddr2_nvm.c
@@ -393,6 +393,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
  */
@@ -422,6 +433,8 @@
 
 	/* lpddr2_nvm address range */
 	add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!add_range)
+		return -ENODEV;
 
 	/* Populate map_info data structure */
 	*map = (struct map_info) {
@@ -433,6 +446,7 @@
 		.pfow_base	= OW_BASE_ADDRESS,
 		.fldrv_priv	= pcm_data,
 	};
+
 	if (IS_ERR(map->virt))
 		return PTR_ERR(map->virt);
 
@@ -444,22 +458,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-ein-5.4.0.orig/drivers/mtd/lpddr/lpddr_cmds.c
+++ linux-ein-5.4.0/drivers/mtd/lpddr/lpddr_cmds.c
@@ -68,7 +68,6 @@
 	shared = kmalloc_array(lpddr->numchips, sizeof(struct flchip_shared),
 						GFP_KERNEL);
 	if (!shared) {
-		kfree(lpddr);
 		kfree(mtd);
 		return NULL;
 	}
--- linux-ein-5.4.0.orig/drivers/mtd/maps/Kconfig
+++ linux-ein-5.4.0/drivers/mtd/maps/Kconfig
@@ -303,7 +303,7 @@
 
 config MTD_IXP4XX
 	tristate "CFI Flash device mapped on Intel IXP4xx based systems"
-	depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
+	depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX && MTD_CFI_ADV_OPTIONS
 	help
 	  This enables MTD access to flash devices on platforms based
 	  on Intel's IXP4xx family of network processors such as the
--- linux-ein-5.4.0.orig/drivers/mtd/maps/physmap-core.c
+++ linux-ein-5.4.0/drivers/mtd/maps/physmap-core.c
@@ -533,6 +533,17 @@
 		if (info->probe_type) {
 			info->mtds[i] = do_map_probe(info->probe_type,
 						     &info->maps[i]);
+
+			/* Fall back to mapping region as ROM */
+			if (!info->mtds[i] && IS_ENABLED(CONFIG_MTD_ROM) &&
+			    strcmp(info->probe_type, "map_rom")) {
+				dev_warn(&dev->dev,
+					 "map_probe() failed for type %s\n",
+					 info->probe_type);
+
+				info->mtds[i] = do_map_probe("map_rom",
+							     &info->maps[i]);
+			}
 		} else {
 			int j;
 
--- linux-ein-5.4.0.orig/drivers/mtd/maps/physmap-versatile.c
+++ linux-ein-5.4.0/drivers/mtd/maps/physmap-versatile.c
@@ -93,6 +93,7 @@
 		return -ENODEV;
 	}
 	ebi_base = of_iomap(ebi, 0);
+	of_node_put(ebi);
 	if (!ebi_base)
 		return -ENODEV;
 
@@ -207,6 +208,7 @@
 
 		versatile_flashprot = (enum versatile_flashprot)devid->data;
 		rmap = syscon_node_to_regmap(sysnp);
+		of_node_put(sysnp);
 		if (IS_ERR(rmap))
 			return PTR_ERR(rmap);
 
--- linux-ein-5.4.0.orig/drivers/mtd/maps/pxa2xx-flash.c
+++ linux-ein-5.4.0/drivers/mtd/maps/pxa2xx-flash.c
@@ -66,6 +66,7 @@
 	if (!info->map.virt) {
 		printk(KERN_WARNING "Failed to ioremap %s\n",
 		       info->map.name);
+		kfree(info);
 		return -ENOMEM;
 	}
 	info->map.cached = ioremap_cache(info->map.phys, info->map.size);
@@ -87,6 +88,7 @@
 		iounmap((void *)info->map.virt);
 		if (info->map.cached)
 			iounmap(info->map.cached);
+		kfree(info);
 		return -EIO;
 	}
 	info->mtd->dev.parent = &pdev->dev;
--- linux-ein-5.4.0.orig/drivers/mtd/mtd_blkdevs.c
+++ linux-ein-5.4.0/drivers/mtd/mtd_blkdevs.c
@@ -533,7 +533,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)
@@ -576,7 +576,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-ein-5.4.0.orig/drivers/mtd/mtdblock.c
+++ linux-ein-5.4.0/drivers/mtd/mtdblock.c
@@ -150,7 +150,7 @@
 				mtdblk->cache_state = STATE_EMPTY;
 				ret = mtd_read(mtd, sect_start, sect_size,
 					       &retlen, mtdblk->cache_data);
-				if (ret)
+				if (ret && !mtd_is_bitflip(ret))
 					return ret;
 				if (retlen != sect_size)
 					return -EIO;
@@ -185,8 +185,12 @@
 	pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
 			mtd->name, pos, len);
 
-	if (!sect_size)
-		return mtd_read(mtd, pos, len, &retlen, buf);
+	if (!sect_size) {
+		ret = mtd_read(mtd, pos, len, &retlen, buf);
+		if (ret && !mtd_is_bitflip(ret))
+			return ret;
+		return 0;
+	}
 
 	while (len > 0) {
 		unsigned long sect_start = (pos/sect_size)*sect_size;
@@ -206,7 +210,7 @@
 			memcpy (buf, mtdblk->cache_data + offset, size);
 		} else {
 			ret = mtd_read(mtd, pos, size, &retlen, buf);
-			if (ret)
+			if (ret && !mtd_is_bitflip(ret))
 				return ret;
 			if (retlen != size)
 				return -EIO;
--- linux-ein-5.4.0.orig/drivers/mtd/mtdchar.c
+++ linux-ein-5.4.0/drivers/mtd/mtdchar.c
@@ -354,9 +354,6 @@
 	uint32_t retlen;
 	int ret = 0;
 
-	if (!(file->f_mode & FMODE_WRITE))
-		return -EPERM;
-
 	if (length > 4096)
 		return -EINVAL;
 
@@ -641,6 +638,48 @@
 
 	pr_debug("MTD_ioctl\n");
 
+	/*
+	 * 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)))
@@ -688,9 +727,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;
@@ -983,9 +1019,6 @@
 		ret = 0;
 		break;
 	}
-
-	default:
-		ret = -ENOTTY;
 	}
 
 	return ret;
@@ -1029,6 +1062,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-ein-5.4.0.orig/drivers/mtd/mtdcore.c
+++ linux-ein-5.4.0/drivers/mtd/mtdcore.c
@@ -563,7 +563,7 @@
 
 	config.id = -1;
 	config.dev = &mtd->dev;
-	config.name = mtd->name;
+	config.name = dev_name(&mtd->dev);
 	config.owner = THIS_MODULE;
 	config.reg_read = mtd_nvmem_reg_read;
 	config.size = mtd->size;
@@ -673,8 +673,10 @@
 	dev_set_drvdata(&mtd->dev, mtd);
 	of_node_get(mtd_get_of_node(mtd));
 	error = device_register(&mtd->dev);
-	if (error)
+	if (error) {
+		put_device(&mtd->dev);
 		goto fail_added;
+	}
 
 	/* Add the nvmem provider */
 	error = mtd_nvmem_add(mtd);
@@ -727,8 +729,6 @@
 
 	mutex_lock(&mtd_table_mutex);
 
-	debugfs_remove_recursive(mtd->dbg.dfs_dir);
-
 	if (idr_find(&mtd_idr, mtd->index) != mtd) {
 		ret = -ENODEV;
 		goto out_error;
@@ -744,6 +744,8 @@
 		       mtd->index, mtd->name, mtd->usecount);
 		ret = -EBUSY;
 	} else {
+		debugfs_remove_recursive(mtd->dbg.dfs_dir);
+
 		/* Try to remove the NVMEM provider */
 		if (mtd->nvmem)
 			nvmem_unregister(mtd->nvmem);
@@ -825,6 +827,9 @@
 
 	/* Prefer parsed partitions over driver-provided fallback */
 	ret = parse_mtd_partitions(mtd, types, parser_data);
+	if (ret == -EPROBE_DEFER)
+		goto out;
+
 	if (ret > 0)
 		ret = 0;
 	else if (nr_parts)
--- linux-ein-5.4.0.orig/drivers/mtd/mtdoops.c
+++ linux-ein-5.4.0/drivers/mtd/mtdoops.c
@@ -279,12 +279,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-ein-5.4.0.orig/drivers/mtd/nand/bbt.c
+++ linux-ein-5.4.0/drivers/mtd/nand/bbt.c
@@ -123,7 +123,7 @@
 		unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
 
 		pos[1] &= ~GENMASK(rbits - 1, 0);
-		pos[1] |= val >> rbits;
+		pos[1] |= val >> (bits_per_block - rbits);
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/onenand/generic.c
+++ linux-ein-5.4.0/drivers/mtd/nand/onenand/generic.c
@@ -53,7 +53,12 @@
 	}
 
 	info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
-	info->onenand.irq = platform_get_irq(pdev, 0);
+
+	err = platform_get_irq(pdev, 0);
+	if (err < 0)
+		goto out_iounmap;
+
+	info->onenand.irq = err;
 
 	info->mtd.dev.parent = &pdev->dev;
 	info->mtd.priv = &info->onenand;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/onenand/omap2.c
+++ linux-ein-5.4.0/drivers/mtd/nand/onenand/omap2.c
@@ -328,7 +328,8 @@
 	struct dma_async_tx_descriptor *tx;
 	dma_cookie_t cookie;
 
-	tx = dmaengine_prep_dma_memcpy(c->dma_chan, dst, src, count, 0);
+	tx = dmaengine_prep_dma_memcpy(c->dma_chan, dst, src, count,
+				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
 	if (!tx) {
 		dev_err(&c->pdev->dev, "Failed to prepare DMA memcpy\n");
 		return -EIO;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/onenand/onenand_base.c
+++ linux-ein-5.4.0/drivers/mtd/nand/onenand/onenand_base.c
@@ -1248,44 +1248,44 @@
 
 	stats = mtd->ecc_stats;
 
- 	/* Read-while-load method */
+	/* Read-while-load method */
 
- 	/* Do first load to bufferRAM */
- 	if (read < len) {
- 		if (!onenand_check_bufferram(mtd, from)) {
+	/* Do first load to bufferRAM */
+	if (read < len) {
+		if (!onenand_check_bufferram(mtd, from)) {
 			this->command(mtd, ONENAND_CMD_READ, from, writesize);
- 			ret = this->wait(mtd, FL_READING);
- 			onenand_update_bufferram(mtd, from, !ret);
+			ret = this->wait(mtd, FL_READING);
+			onenand_update_bufferram(mtd, from, !ret);
 			if (mtd_is_eccerr(ret))
 				ret = 0;
- 		}
- 	}
+		}
+	}
 
 	thislen = min_t(int, writesize, len - read);
 	column = from & (writesize - 1);
 	if (column + thislen > writesize)
 		thislen = writesize - column;
 
- 	while (!ret) {
- 		/* If there is more to load then start next load */
- 		from += thislen;
- 		if (read + thislen < len) {
+	while (!ret) {
+		/* If there is more to load then start next load */
+		from += thislen;
+		if (read + thislen < len) {
 			this->command(mtd, ONENAND_CMD_READ, from, writesize);
- 			/*
- 			 * Chip boundary handling in DDP
- 			 * Now we issued chip 1 read and pointed chip 1
+			/*
+			 * Chip boundary handling in DDP
+			 * Now we issued chip 1 read and pointed chip 1
 			 * bufferram so we have to point chip 0 bufferram.
- 			 */
- 			if (ONENAND_IS_DDP(this) &&
- 			    unlikely(from == (this->chipsize >> 1))) {
- 				this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
- 				boundary = 1;
- 			} else
- 				boundary = 0;
- 			ONENAND_SET_PREV_BUFFERRAM(this);
- 		}
- 		/* While load is going, read from last bufferRAM */
- 		this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+			 */
+			if (ONENAND_IS_DDP(this) &&
+			    unlikely(from == (this->chipsize >> 1))) {
+				this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
+				boundary = 1;
+			} else
+				boundary = 0;
+			ONENAND_SET_PREV_BUFFERRAM(this);
+		}
+		/* While load is going, read from last bufferRAM */
+		this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
 
 		/* Read oob area if needed */
 		if (oobbuf) {
@@ -1301,24 +1301,24 @@
 			oobcolumn = 0;
 		}
 
- 		/* See if we are done */
- 		read += thislen;
- 		if (read == len)
- 			break;
- 		/* Set up for next read from bufferRAM */
- 		if (unlikely(boundary))
- 			this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
- 		ONENAND_SET_NEXT_BUFFERRAM(this);
- 		buf += thislen;
+		/* See if we are done */
+		read += thislen;
+		if (read == len)
+			break;
+		/* Set up for next read from bufferRAM */
+		if (unlikely(boundary))
+			this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
+		ONENAND_SET_NEXT_BUFFERRAM(this);
+		buf += thislen;
 		thislen = min_t(int, writesize, len - read);
- 		column = 0;
- 		cond_resched();
- 		/* Now wait for load */
- 		ret = this->wait(mtd, FL_READING);
- 		onenand_update_bufferram(mtd, from, !ret);
+		column = 0;
+		cond_resched();
+		/* Now wait for load */
+		ret = this->wait(mtd, FL_READING);
+		onenand_update_bufferram(mtd, from, !ret);
 		if (mtd_is_eccerr(ret))
 			ret = 0;
- 	}
+	}
 
 	/*
 	 * Return success, if no ECC failures, else -EBADMSG
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -402,6 +402,7 @@
 
 	dma_async_issue_pending(nc->dmac);
 	wait_for_completion(&finished);
+	dma_unmap_single(nc->dev, buf_dma, len, dir);
 
 	return 0;
 
@@ -813,10 +814,12 @@
 							  NULL, 0,
 							  chip->ecc.strength);
 
-		if (ret >= 0)
+		if (ret >= 0) {
+			mtd->ecc_stats.corrected += ret;
 			max_bitflips = max(ret, max_bitflips);
-		else
+		} else {
 			mtd->ecc_stats.failed++;
+		}
 
 		databuf += chip->ecc.size;
 		eccbuf += chip->ecc.bytes;
@@ -2002,13 +2005,15 @@
 	nc->mck = of_clk_get(dev->parent->of_node, 0);
 	if (IS_ERR(nc->mck)) {
 		dev_err(dev, "Failed to retrieve MCK clk\n");
-		return PTR_ERR(nc->mck);
+		ret = PTR_ERR(nc->mck);
+		goto out_release_dma;
 	}
 
 	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
 	if (!np) {
 		dev_err(dev, "Missing or invalid atmel,smc property\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out_release_dma;
 	}
 
 	nc->smc = syscon_node_to_regmap(np);
@@ -2016,10 +2021,16 @@
 	if (IS_ERR(nc->smc)) {
 		ret = PTR_ERR(nc->smc);
 		dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
-		return ret;
+		goto out_release_dma;
 	}
 
 	return 0;
+
+out_release_dma:
+	if (nc->dmac)
+		dma_release_channel(nc->dmac);
+
+	return ret;
 }
 
 static int
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -197,6 +197,7 @@
 	unsigned int		max_page_size;
 	const unsigned int	*page_sizes;
 	unsigned int		max_oob;
+	u32			ecc_level_shift;
 	u32			features;
 
 	/* for low-power standby/resume only */
@@ -487,6 +488,34 @@
 	INTFC_CTLR_READY		= BIT(31),
 };
 
+/***********************************************************************
+ * NAND ACC CONTROL bitfield
+ *
+ * Some bits have remained constant throughout hardware revision, while
+ * others have shifted around.
+ ***********************************************************************/
+
+/* Constant for all versions (where supported) */
+enum {
+	/* See BRCMNAND_HAS_CACHE_MODE */
+	ACC_CONTROL_CACHE_MODE				= BIT(22),
+
+	/* See BRCMNAND_HAS_PREFETCH */
+	ACC_CONTROL_PREFETCH				= BIT(23),
+
+	ACC_CONTROL_PAGE_HIT				= BIT(24),
+	ACC_CONTROL_WR_PREEMPT				= BIT(25),
+	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
+	ACC_CONTROL_RD_ERASED				= BIT(27),
+	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
+	ACC_CONTROL_WR_ECC				= BIT(30),
+	ACC_CONTROL_RD_ECC				= BIT(31),
+};
+
+#define	ACC_CONTROL_ECC_SHIFT			16
+/* Only for v7.2 */
+#define	ACC_CONTROL_ECC_EXT_SHIFT		13
+
 static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
 {
 	return brcmnand_readl(ctrl->nand_base + offs);
@@ -537,8 +566,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;
 	}
 
@@ -589,6 +619,12 @@
 	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
 		ctrl->features |= BRCMNAND_HAS_WP;
 
+	/* v7.2 has different ecc level shift in the acc register */
+	if (ctrl->nand_version == 0x0702)
+		ctrl->ecc_level_shift = ACC_CONTROL_ECC_EXT_SHIFT;
+	else
+		ctrl->ecc_level_shift = ACC_CONTROL_ECC_SHIFT;
+
 	return 0;
 }
 
@@ -751,30 +787,6 @@
 	return 0;
 }
 
-/***********************************************************************
- * NAND ACC CONTROL bitfield
- *
- * Some bits have remained constant throughout hardware revision, while
- * others have shifted around.
- ***********************************************************************/
-
-/* Constant for all versions (where supported) */
-enum {
-	/* See BRCMNAND_HAS_CACHE_MODE */
-	ACC_CONTROL_CACHE_MODE				= BIT(22),
-
-	/* See BRCMNAND_HAS_PREFETCH */
-	ACC_CONTROL_PREFETCH				= BIT(23),
-
-	ACC_CONTROL_PAGE_HIT				= BIT(24),
-	ACC_CONTROL_WR_PREEMPT				= BIT(25),
-	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
-	ACC_CONTROL_RD_ERASED				= BIT(27),
-	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
-	ACC_CONTROL_WR_ECC				= BIT(30),
-	ACC_CONTROL_RD_ECC				= BIT(31),
-};
-
 static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
 {
 	if (ctrl->nand_version == 0x0702)
@@ -785,18 +797,15 @@
 		return GENMASK(5, 0);
 }
 
-#define NAND_ACC_CONTROL_ECC_SHIFT	16
-#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
-
 static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
 {
 	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
 
-	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+	mask <<= ACC_CONTROL_ECC_SHIFT;
 
 	/* v7.2 includes additional ECC levels */
-	if (ctrl->nand_version >= 0x0702)
-		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+	if (ctrl->nand_version == 0x0702)
+		mask |= 0x7 << ACC_CONTROL_ECC_EXT_SHIFT;
 
 	return mask;
 }
@@ -810,8 +819,8 @@
 
 	if (en) {
 		acc_control |= ecc_flags; /* enable RD/WR ECC */
-		acc_control |= host->hwcfg.ecc_level
-			       << NAND_ACC_CONTROL_ECC_SHIFT;
+		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
+		acc_control |= host->hwcfg.ecc_level << ctrl->ecc_level_shift;
 	} else {
 		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
 		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
@@ -890,6 +899,14 @@
 		cpu_relax();
 	} while (time_after(limit, jiffies));
 
+	/*
+	 * do a final check after time out in case the CPU was busy and the driver
+	 * did not get enough time to perform the polling to avoid false alarms
+	 */
+	val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
+	if ((val & mask) == expected_val)
+		return 0;
+
 	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
 		 expected_val, val & mask);
 
@@ -1019,11 +1036,14 @@
 		if (!section) {
 			/*
 			 * Small-page NAND use byte 6 for BBI while large-page
-			 * NAND use byte 0.
+			 * NAND use bytes 0 and 1.
 			 */
-			if (cfg->page_size > 512)
-				oobregion->offset++;
-			oobregion->length--;
+			if (cfg->page_size > 512) {
+				oobregion->offset += 2;
+				oobregion->length -= 2;
+			} else {
+				oobregion->length--;
+			}
 		}
 	}
 
@@ -1269,19 +1289,33 @@
 			     const u8 *oob, int sas, int sector_1k)
 {
 	int tbytes = sas << sector_1k;
-	int j;
+	int j, k = 0;
+	u32 last = 0xffffffff;
+	u8 *plast = (u8 *)&last;
 
 	/* Adjust OOB values for 1K sector size */
 	if (sector_1k && (i & 0x01))
 		tbytes = max(0, tbytes - (int)ctrl->max_oob);
 	tbytes = min_t(int, tbytes, ctrl->max_oob);
 
-	for (j = 0; j < tbytes; j += 4)
+	/*
+	 * tbytes may not be multiple of words. Make sure we don't read out of
+	 * the boundary and stop at last word.
+	 */
+	for (j = 0; (j + 3) < tbytes; j += 4)
 		oob_reg_write(ctrl, j,
 				(oob[j + 0] << 24) |
 				(oob[j + 1] << 16) |
 				(oob[j + 2] <<  8) |
 				(oob[j + 3] <<  0));
+
+	/* handle the remaing bytes */
+	while (j < tbytes)
+		plast[k++] = oob[j++];
+
+	if (tbytes & 0x3)
+		oob_reg_write(ctrl, (tbytes & ~0x3), (__force u32)cpu_to_be32(last));
+
 	return tbytes;
 }
 
@@ -1327,7 +1361,17 @@
 
 	dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr);
 
-	BUG_ON(ctrl->cmd_pending != 0);
+	/*
+	 * If we came here through _panic_write and there is a pending
+	 * command, try to wait for it. If it times out, rather than
+	 * hitting BUG_ON, just return so we don't crash while crashing.
+	 */
+	if (oops_in_progress) {
+		if (ctrl->cmd_pending &&
+			bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0))
+			return;
+	} else
+		BUG_ON(ctrl->cmd_pending != 0);
 	ctrl->cmd_pending = cmd;
 
 	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
@@ -1752,7 +1796,7 @@
 					mtd->oobsize / trans,
 					host->hwcfg.sector_size_1k);
 
-		if (!ret) {
+		if (ret != -EBADMSG) {
 			*err_addr = brcmnand_get_uncorrecc_addr(ctrl);
 
 			if (*err_addr)
@@ -1787,28 +1831,31 @@
 static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
 		  struct nand_chip *chip, void *buf, u64 addr)
 {
-	int i, sas;
-	void *oob = chip->oob_poi;
+	struct mtd_oob_region ecc;
+	int i;
 	int bitflips = 0;
 	int page = addr >> chip->page_shift;
 	int ret;
+	void *ecc_bytes;
 	void *ecc_chunk;
 
 	if (!buf)
 		buf = nand_get_data_buf(chip);
 
-	sas = mtd->oobsize / chip->ecc.steps;
-
 	/* read without ecc for verification */
 	ret = chip->ecc.read_page_raw(chip, buf, true, page);
 	if (ret)
 		return ret;
 
-	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
+	for (i = 0; i < chip->ecc.steps; i++) {
 		ecc_chunk = buf + chip->ecc.size * i;
-		ret = nand_check_erased_ecc_chunk(ecc_chunk,
-						  chip->ecc.size,
-						  oob, sas, NULL, 0,
+
+		mtd_ooblayout_ecc(mtd, i, &ecc);
+		ecc_bytes = chip->oob_poi + ecc.offset;
+
+		ret = nand_check_erased_ecc_chunk(ecc_chunk, chip->ecc.size,
+						  ecc_bytes, ecc.length,
+						  NULL, 0,
 						  chip->ecc.strength);
 		if (ret < 0)
 			return ret;
@@ -2154,7 +2201,7 @@
 
 	tmp = nand_readreg(ctrl, acc_control_offs);
 	tmp &= ~brcmnand_ecc_level_mask(ctrl);
-	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
+	tmp |= cfg->ecc_level << ctrl->ecc_level_shift;
 	tmp &= ~brcmnand_spare_area_mask(ctrl);
 	tmp |= cfg->spare_area_size;
 	nand_writereg(ctrl, acc_control_offs, tmp);
@@ -2357,6 +2404,12 @@
 
 	ret = brcmstb_choose_ecc_layout(host);
 
+	/* If OOB is written with ECC enabled it will cause ECC errors */
+	if (is_hamming_ecc(host->ctrl, &host->hwcfg)) {
+		chip->ecc.write_oob = brcmnand_write_oob_raw;
+		chip->ecc.read_oob = brcmnand_read_oob_raw;
+	}
+
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/cafe_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/cafe_nand.c
@@ -757,7 +757,7 @@
 			  "CAFE NAND", mtd);
 	if (err) {
 		dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-		goto out_ior;
+		goto out_free_rs;
 	}
 
 	/* Disable master reset, enable NAND clock */
@@ -801,6 +801,8 @@
 	/* Disable NAND IRQ in global IRQ mask register */
 	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
 	free_irq(pdev->irq, mtd);
+ out_free_rs:
+	free_rs(cafe->rs);
  out_ior:
 	pci_iounmap(pdev, cafe->mmio);
  out_free_mtd:
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/diskonchip.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/diskonchip.c
@@ -1609,13 +1609,10 @@
 		numchips = doc2001_init(mtd);
 
 	if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
-		/* DBB note: i believe nand_release is necessary here, as
+		/* DBB note: i believe nand_cleanup is necessary here, as
 		   buffers may have been allocated in nand_base.  Check with
 		   Thomas. FIX ME! */
-		/* nand_release will call mtd_device_unregister, but we
-		   haven't yet added it.  This is handled without incident by
-		   mtd_device_unregister, as far as I can tell. */
-		nand_release(nand);
+		nand_cleanup(nand);
 		goto fail;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -21,7 +21,7 @@
 
 #define ERR_BYTE		0xFF /* Value returned for read
 					bytes when read failed	*/
-#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
+#define IFC_TIMEOUT_MSECS	1000 /* Maximum timeout to wait
 					for IFC NAND Machine	*/
 
 struct fsl_ifc_ctrl;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/fsl_upm.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/fsl_upm.c
@@ -62,7 +62,6 @@
 static void fun_wait_rnb(struct fsl_upm_nand *fun)
 {
 	if (fun->rnb_gpio[fun->mchip_number] >= 0) {
-		struct mtd_info *mtd = nand_to_mtd(&fun->chip);
 		int cnt = 1000000;
 
 		while (--cnt && !fun_chip_ready(&fun->chip))
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/fsmc_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/fsmc_nand.c
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-direction.h>
 #include <linux/dma-mapping.h>
@@ -93,6 +94,14 @@
 
 #define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
 
+/*
+ * According to SPEAr300 Reference Manual (RM0082)
+ *  TOUDEL = 7ns (Output delay from the flip-flops to the board)
+ *  TINDEL = 5ns (Input delay from the board to the flipflop)
+ */
+#define TOUTDEL	7000
+#define TINDEL	5000
+
 struct fsmc_nand_timings {
 	u8 tclr;
 	u8 tar;
@@ -277,7 +286,7 @@
 {
 	unsigned long hclk = clk_get_rate(host->clk);
 	unsigned long hclkn = NSEC_PER_SEC / hclk;
-	u32 thiz, thold, twait, tset;
+	u32 thiz, thold, twait, tset, twait_min;
 
 	if (sdrt->tRC_min < 30000)
 		return -EOPNOTSUPP;
@@ -309,13 +318,6 @@
 	else if (tims->thold > FSMC_THOLD_MASK)
 		tims->thold = FSMC_THOLD_MASK;
 
-	twait = max(sdrt->tRP_min, sdrt->tWP_min);
-	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
-	if (tims->twait == 0)
-		tims->twait = 1;
-	else if (tims->twait > FSMC_TWAIT_MASK)
-		tims->twait = FSMC_TWAIT_MASK;
-
 	tset = max(sdrt->tCS_min - sdrt->tWP_min,
 		   sdrt->tCEA_max - sdrt->tREA_max);
 	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
@@ -324,6 +326,21 @@
 	else if (tims->tset > FSMC_TSET_MASK)
 		tims->tset = FSMC_TSET_MASK;
 
+	/*
+	 * According to SPEAr300 Reference Manual (RM0082) which gives more
+	 * information related to FSMSC timings than the SPEAr600 one (RM0305),
+	 *   twait >= tCEA - (tset * TCLK) + TOUTDEL + TINDEL
+	 */
+	twait_min = sdrt->tCEA_max - ((tims->tset + 1) * hclkn * 1000)
+		    + TOUTDEL + TINDEL;
+	twait = max3(sdrt->tRP_min, sdrt->tWP_min, twait_min);
+
+	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+	if (tims->twait == 0)
+		tims->twait = 1;
+	else if (tims->twait > FSMC_TWAIT_MASK)
+		tims->twait = FSMC_TWAIT_MASK;
+
 	return 0;
 }
 
@@ -650,6 +667,9 @@
 						instr->ctx.waitrdy.timeout_ms);
 			break;
 		}
+
+		if (instr->delay_ns)
+			ndelay(instr->delay_ns);
 	}
 
 	return ret;
@@ -1066,11 +1086,13 @@
 		host->read_dma_chan = dma_request_channel(mask, filter, NULL);
 		if (!host->read_dma_chan) {
 			dev_err(&pdev->dev, "Unable to get read dma channel\n");
+			ret = -ENODEV;
 			goto disable_clk;
 		}
 		host->write_dma_chan = dma_request_channel(mask, filter, NULL);
 		if (!host->write_dma_chan) {
 			dev_err(&pdev->dev, "Unable to get write dma channel\n");
+			ret = -ENODEV;
 			goto release_dma_read_chan;
 		}
 	}
@@ -1159,9 +1181,14 @@
 static int fsmc_nand_resume(struct device *dev)
 {
 	struct fsmc_nand_data *host = dev_get_drvdata(dev);
+	int ret;
 
 	if (host) {
-		clk_prepare_enable(host->clk);
+		ret = clk_prepare_enable(host->clk);
+		if (ret) {
+			dev_err(dev, "failed to enable clk\n");
+			return ret;
+		}
 		if (host->dev_timings)
 			fsmc_nand_setup(host, host->dev_timings);
 		nand_reset(&host->nand, 0);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -148,6 +148,12 @@
 	struct resources *r = &this->resources;
 	int ret;
 
+	ret = pm_runtime_get_sync(this->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(this->dev);
+		return ret;
+	}
+
 	ret = gpmi_reset_block(r->gpmi_regs, false);
 	if (ret)
 		goto err_out;
@@ -179,8 +185,9 @@
 	 */
 	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
 
-	return 0;
 err_out:
+	pm_runtime_mark_last_busy(this->dev);
+	pm_runtime_put_autosuspend(this->dev);
 	return ret;
 }
 
@@ -535,8 +542,10 @@
 		return ret;
 
 	ret = pm_runtime_get_sync(this->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_autosuspend(this->dev);
 		return ret;
+	}
 
 	/*
 	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
@@ -636,14 +645,16 @@
 				     const struct nand_sdr_timings *sdr)
 {
 	struct gpmi_nfc_hardware_timing *hw = &this->hw;
+	struct resources *r = &this->resources;
 	unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
 	unsigned int period_ps, reference_period_ps;
 	unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
 	unsigned int tRP_ps;
 	bool use_half_period;
 	int sample_delay_ps, sample_delay_factor;
-	u16 busy_timeout_cycles;
+	unsigned int busy_timeout_cycles;
 	u8 wrn_dly_sel;
+	u64 busy_timeout_ps;
 
 	if (sdr->tRC_min >= 30000) {
 		/* ONFI non-EDO modes [0-3] */
@@ -659,18 +670,21 @@
 		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
 	}
 
+	hw->clk_rate = clk_round_rate(r->clock[0], hw->clk_rate);
+
 	/* SDR core timings are given in picoseconds */
 	period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
 
 	addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
 	data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
 	data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
-	busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+	busy_timeout_ps = max(sdr->tBERS_max, sdr->tPROG_max);
+	busy_timeout_cycles = TO_CYCLES(busy_timeout_ps, period_ps);
 
 	hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
 		      BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
 		      BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
-	hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
+	hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(DIV_ROUND_UP(busy_timeout_cycles, 4096));
 
 	/*
 	 * Derive NFC ideal delay from {3}:
@@ -701,14 +715,32 @@
 			      (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
 }
 
-static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
+static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
 {
 	struct gpmi_nfc_hardware_timing *hw = &this->hw;
 	struct resources *r = &this->resources;
 	void __iomem *gpmi_regs = r->gpmi_regs;
 	unsigned int dll_wait_time_us;
+	int ret;
+
+	/* Clock dividers do NOT guarantee a clean clock signal on its output
+	 * during the change of the divide factor on i.MX6Q/UL/SX. On i.MX7/8,
+	 * all clock dividers provide these guarantee.
+	 */
+	if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this))
+		clk_disable_unprepare(r->clock[0]);
+
+	ret = clk_set_rate(r->clock[0], hw->clk_rate);
+	if (ret) {
+		dev_err(this->dev, "cannot set clock rate to %lu Hz: %d\n", hw->clk_rate, ret);
+		return ret;
+	}
 
-	clk_set_rate(r->clock[0], hw->clk_rate);
+	if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) {
+		ret = clk_prepare_enable(r->clock[0]);
+		if (ret)
+			return ret;
+	}
 
 	writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
 	writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
@@ -727,6 +759,8 @@
 
 	/* Wait for the DLL to settle. */
 	udelay(dll_wait_time_us);
+
+	return 0;
 }
 
 static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
@@ -1175,15 +1209,6 @@
 		r->clock[i] = clk;
 	}
 
-	if (GPMI_IS_MX6(this))
-		/*
-		 * Set the default value for the gpmi clock.
-		 *
-		 * If you want to use the ONFI nand which is in the
-		 * Synchronous Mode, you should change the clock as you need.
-		 */
-		clk_set_rate(r->clock[0], 22000000);
-
 	return 0;
 
 err_clock:
@@ -2399,7 +2424,7 @@
 	void *buf_read = NULL;
 	const void *buf_write = NULL;
 	bool direct = false;
-	struct completion *completion;
+	struct completion *dma_completion, *bch_completion;
 	unsigned long to;
 
 	this->ntransfers = 0;
@@ -2407,8 +2432,10 @@
 		this->transfers[i].direction = DMA_NONE;
 
 	ret = pm_runtime_get_sync(this->dev);
-	if (ret < 0)
+	if (ret < 0) {
+		pm_runtime_put_noidle(this->dev);
 		return ret;
+	}
 
 	/*
 	 * This driver currently supports only one NAND chip. Plus, dies share
@@ -2418,7 +2445,9 @@
 	 */
 	if (this->hw.must_apply_timings) {
 		this->hw.must_apply_timings = false;
-		gpmi_nfc_apply_timings(this);
+		ret = gpmi_nfc_apply_timings(this);
+		if (ret)
+			goto out_pm;
 	}
 
 	dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs);
@@ -2491,22 +2520,24 @@
 		       this->resources.bch_regs + HW_BCH_FLASH0LAYOUT1);
 	}
 
+	desc->callback = dma_irq_callback;
+	desc->callback_param = this;
+	dma_completion = &this->dma_done;
+	bch_completion = NULL;
+
+	init_completion(dma_completion);
+
 	if (this->bch && buf_read) {
 		writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
 		       this->resources.bch_regs + HW_BCH_CTRL_SET);
-		completion = &this->bch_done;
-	} else {
-		desc->callback = dma_irq_callback;
-		desc->callback_param = this;
-		completion = &this->dma_done;
+		bch_completion = &this->bch_done;
+		init_completion(bch_completion);
 	}
 
-	init_completion(completion);
-
 	dmaengine_submit(desc);
 	dma_async_issue_pending(get_dma_chan(this));
 
-	to = wait_for_completion_timeout(completion, msecs_to_jiffies(1000));
+	to = wait_for_completion_timeout(dma_completion, msecs_to_jiffies(1000));
 	if (!to) {
 		dev_err(this->dev, "DMA timeout, last DMA\n");
 		gpmi_dump_info(this);
@@ -2514,6 +2545,16 @@
 		goto unmap;
 	}
 
+	if (this->bch && buf_read) {
+		to = wait_for_completion_timeout(bch_completion, msecs_to_jiffies(1000));
+		if (!to) {
+			dev_err(this->dev, "BCH timeout, last DMA\n");
+			gpmi_dump_info(this);
+			ret = -ETIMEDOUT;
+			goto unmap;
+		}
+	}
+
 	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
 	       this->resources.bch_regs + HW_BCH_CTRL_CLR);
 	gpmi_clear_bch(this);
@@ -2535,6 +2576,7 @@
 
 	this->bch = false;
 
+out_pm:
 	pm_runtime_mark_last_busy(this->dev);
 	pm_runtime_put_autosuspend(this->dev);
 
@@ -2575,7 +2617,7 @@
 	this->bch_geometry.auxiliary_size = 128;
 	ret = gpmi_alloc_dma_buffer(this);
 	if (ret)
-		goto err_out;
+		return ret;
 
 	nand_controller_init(&this->base);
 	this->base.ops = &gpmi_nand_controller_ops;
@@ -2722,6 +2764,10 @@
 		return ret;
 	}
 
+	/* Set flag to get timing setup restored for next exec_op */
+	if (this->hw.clk_rate)
+		this->hw.must_apply_timings = true;
+
 	/* re-init the BCH registers */
 	ret = bch_set_geometry(this);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h
@@ -36,25 +36,25 @@
 void ingenic_ecc_release(struct ingenic_ecc *ecc);
 struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np);
 #else /* CONFIG_MTD_NAND_INGENIC_ECC */
-int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
+static inline int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
 			  struct ingenic_ecc_params *params,
 			  const u8 *buf, u8 *ecc_code)
 {
 	return -ENODEV;
 }
 
-int ingenic_ecc_correct(struct ingenic_ecc *ecc,
+static inline int ingenic_ecc_correct(struct ingenic_ecc *ecc,
 			struct ingenic_ecc_params *params, u8 *buf,
 			u8 *ecc_code)
 {
 	return -ENODEV;
 }
 
-void ingenic_ecc_release(struct ingenic_ecc *ecc)
+static inline void ingenic_ecc_release(struct ingenic_ecc *ecc)
 {
 }
 
-struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
+static inline struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
 {
 	return ERR_PTR(-ENODEV);
 }
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c
@@ -376,7 +376,7 @@
 
 	ret = mtd_device_register(mtd, NULL, 0);
 	if (ret) {
-		nand_release(chip);
+		nand_cleanup(chip);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/marvell_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/marvell_nand.c
@@ -707,7 +707,7 @@
 	 * In case the interrupt was not served in the required time frame,
 	 * check if the ISR was not served or if something went actually wrong.
 	 */
-	if (ret && !pending) {
+	if (!ret && !pending) {
 		dev_err(nfc->dev, "Timeout waiting for RB signal\n");
 		return -ETIMEDOUT;
 	}
@@ -1109,6 +1109,7 @@
 		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
 	};
 	unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
+	u8 status;
 	int ret;
 
 	/* NFCv2 needs more information about the operation being executed */
@@ -1142,7 +1143,18 @@
 
 	ret = marvell_nfc_wait_op(chip,
 				  PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max));
-	return ret;
+	if (ret)
+		return ret;
+
+	/* Check write status on the chip side */
+	ret = nand_status_op(chip, &status);
+	if (ret)
+		return ret;
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
 }
 
 static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
@@ -1570,6 +1582,7 @@
 	int data_len = lt->data_bytes;
 	int spare_len = lt->spare_bytes;
 	int chunk, ret;
+	u8 status;
 
 	marvell_nfc_select_target(chip, chip->cur_cs);
 
@@ -1607,6 +1620,14 @@
 	if (ret)
 		return ret;
 
+	/* Check write status on the chip side */
+	ret = nand_status_op(chip, &status);
+	if (ret)
+		return ret;
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
 	return 0;
 }
 
@@ -2401,6 +2422,12 @@
 			NDTR1_WAIT_MODE;
 	}
 
+	/*
+	 * Reset nfc->selected_chip so the next command will cause the timing
+	 * registers to be updated in marvell_nfc_select_target().
+	 */
+	nfc->selected_chip = NULL;
+
 	return 0;
 }
 
@@ -2630,7 +2657,7 @@
 	chip->controller = &nfc->controller;
 	nand_set_flash_node(chip, np);
 
-	if (!of_property_read_bool(np, "marvell,nand-keep-config"))
+	if (of_property_read_bool(np, "marvell,nand-keep-config"))
 		chip->options |= NAND_KEEP_TIMINGS;
 
 	mtd = nand_to_mtd(chip);
@@ -2664,7 +2691,7 @@
 		ret = mtd_device_register(mtd, NULL, 0);
 	if (ret) {
 		dev_err(dev, "failed to register mtd device: %d\n", ret);
-		nand_release(chip);
+		nand_cleanup(chip);
 		return ret;
 	}
 
@@ -2673,6 +2700,16 @@
 	return 0;
 }
 
+static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
+{
+	struct marvell_nand_chip *entry, *temp;
+
+	list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
+		nand_release(&entry->chip);
+		list_del(&entry->node);
+	}
+}
+
 static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
 {
 	struct device_node *np = dev->of_node;
@@ -2707,21 +2744,16 @@
 		ret = marvell_nand_chip_init(dev, nfc, nand_np);
 		if (ret) {
 			of_node_put(nand_np);
-			return ret;
+			goto cleanup_chips;
 		}
 	}
 
 	return 0;
-}
 
-static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
-{
-	struct marvell_nand_chip *entry, *temp;
+cleanup_chips:
+	marvell_nand_chips_cleanup(nfc);
 
-	list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
-		nand_release(&entry->chip);
-		list_del(&entry->node);
-	}
+	return ret;
 }
 
 static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
@@ -2823,10 +2855,6 @@
 		regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
 				   GENCONF_CLK_GATING_CTRL_ND_GATE,
 				   GENCONF_CLK_GATING_CTRL_ND_GATE);
-
-		regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
-				   GENCONF_ND_CLK_CTRL_EN,
-				   GENCONF_ND_CLK_CTRL_EN);
 	}
 
 	/* Configure the DMA if appropriate */
@@ -2975,8 +3003,10 @@
 		return ret;
 
 	ret = clk_prepare_enable(nfc->reg_clk);
-	if (ret < 0)
+	if (ret < 0) {
+		clk_disable_unprepare(nfc->core_clk);
 		return ret;
+	}
 
 	/*
 	 * Reset nfc->selected_chip so the next command will cause the timing
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/meson_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/meson_nand.c
@@ -72,6 +72,7 @@
 #define GENCMDIADDRH(aih, addr)		((aih) | (((addr) >> 16) & 0xffff))
 
 #define DMA_DIR(dir)		((dir) ? NFC_CMD_N2M : NFC_CMD_M2N)
+#define DMA_ADDR_ALIGN		8
 
 #define ECC_CHECK_RETURN_FF	(-1)
 
@@ -172,6 +173,7 @@
 
 	dma_addr_t daddr;
 	dma_addr_t iaddr;
+	u32 info_bytes;
 
 	unsigned long assigned_cs;
 };
@@ -275,7 +277,7 @@
 
 	if (raw) {
 		len = mtd->writesize + mtd->oobsize;
-		cmd = (len & GENMASK(5, 0)) | scrambler | DMA_DIR(dir);
+		cmd = (len & GENMASK(13, 0)) | scrambler | DMA_DIR(dir);
 		writel(cmd, nfc->reg_base + NFC_REG_CMD);
 		return;
 	}
@@ -454,7 +456,7 @@
 		if (ECC_ERR_CNT(*info) != ECC_UNCORRECTABLE) {
 			mtd->ecc_stats.corrected += ECC_ERR_CNT(*info);
 			*bitflips = max_t(u32, *bitflips, ECC_ERR_CNT(*info));
-			*correct_bitmap |= 1 >> i;
+			*correct_bitmap |= BIT_ULL(i);
 			continue;
 		}
 		if ((nand->options & NAND_NEED_SCRAMBLING) &&
@@ -499,6 +501,7 @@
 					 nfc->daddr, datalen, dir);
 			return ret;
 		}
+		nfc->info_bytes = infolen;
 		cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr);
 		writel(cmd, nfc->reg_base + NFC_REG_CMD);
 
@@ -510,14 +513,16 @@
 }
 
 static void meson_nfc_dma_buffer_release(struct nand_chip *nand,
-					 int infolen, int datalen,
+					 int datalen, int infolen,
 					 enum dma_data_direction dir)
 {
 	struct meson_nfc *nfc = nand_get_controller_data(nand);
 
 	dma_unmap_single(nfc->dev, nfc->daddr, datalen, dir);
-	if (infolen)
+	if (infolen) {
 		dma_unmap_single(nfc->dev, nfc->iaddr, infolen, dir);
+		nfc->info_bytes = 0;
+	}
 }
 
 static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
@@ -536,7 +541,7 @@
 	if (ret)
 		goto out;
 
-	cmd = NFC_CMD_N2M | (len & GENMASK(5, 0));
+	cmd = NFC_CMD_N2M | (len & GENMASK(13, 0));
 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
 
 	meson_nfc_drain_cmd(nfc);
@@ -560,7 +565,7 @@
 	if (ret)
 		return ret;
 
-	cmd = NFC_CMD_M2N | (len & GENMASK(5, 0));
+	cmd = NFC_CMD_M2N | (len & GENMASK(13, 0));
 	writel(cmd, nfc->reg_base + NFC_REG_CMD);
 
 	meson_nfc_drain_cmd(nfc);
@@ -706,6 +711,8 @@
 		usleep_range(10, 15);
 		/* info is updated by nfc dma engine*/
 		smp_rmb();
+		dma_sync_single_for_cpu(nfc->dev, nfc->iaddr, nfc->info_bytes,
+					DMA_FROM_DEVICE);
 		ret = *info & ECC_COMPLETE;
 	} while (!ret);
 }
@@ -800,7 +807,7 @@
 			u8 *data = buf + i * ecc->size;
 			u8 *oob = nand->oob_poi + i * (ecc->bytes + 2);
 
-			if (correct_bitmap & (1 << i))
+			if (correct_bitmap & BIT_ULL(i))
 				continue;
 			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
 							  oob, ecc->bytes + 2,
@@ -832,6 +839,9 @@
 
 static bool meson_nfc_is_buffer_dma_safe(const void *buffer)
 {
+	if ((uintptr_t)buffer % DMA_ADDR_ALIGN)
+		return false;
+
 	if (virt_addr_valid(buffer) && (!object_is_on_stack(buffer)))
 		return true;
 	return false;
@@ -1041,9 +1051,12 @@
 
 	ret = clk_set_rate(nfc->device_clk, 24000000);
 	if (ret)
-		goto err_phase_rx;
+		goto err_disable_rx;
 
 	return 0;
+
+err_disable_rx:
+	clk_disable_unprepare(nfc->phase_rx);
 err_phase_rx:
 	clk_disable_unprepare(nfc->phase_tx);
 err_phase_tx:
@@ -1164,7 +1177,6 @@
 	struct meson_nfc *nfc = nand_get_controller_data(nand);
 	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
 	struct mtd_info *mtd = nand_to_mtd(nand);
-	int nsectors = mtd->writesize / 1024;
 	int ret;
 
 	if (!mtd->name) {
@@ -1182,7 +1194,7 @@
 	nand->options |= NAND_NO_SUBPAGE_WRITE;
 
 	ret = nand_ecc_choose_conf(nand, nfc->data->ecc_caps,
-				   mtd->oobsize - 2 * nsectors);
+				   mtd->oobsize - 2);
 	if (ret) {
 		dev_err(nfc->dev, "failed to ECC init\n");
 		return -EINVAL;
@@ -1301,7 +1313,6 @@
 		if (ret)
 			return ret;
 
-		meson_nfc_free_buffer(&meson_chip->nand);
 		nand_cleanup(&meson_chip->nand);
 		list_del(&meson_chip->node);
 	}
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/mpc5121_nfc.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -290,7 +290,6 @@
 /* Control chips select signal on ADS5121 board */
 static void ads5121_select_chip(struct nand_chip *nand, int chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(nand);
 	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
 	u8 v;
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/mtk_ecc.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/mtk_ecc.c
@@ -43,6 +43,7 @@
 
 struct mtk_ecc_caps {
 	u32 err_mask;
+	u32 err_shift;
 	const u8 *ecc_strength;
 	const u32 *ecc_regs;
 	u8 num_ecc_strength;
@@ -76,7 +77,7 @@
 };
 
 static const u8 ecc_strength_mt7622[] = {
-	4, 6, 8, 10, 12, 14, 16
+	4, 6, 8, 10, 12
 };
 
 enum mtk_ecc_regs {
@@ -221,7 +222,7 @@
 	for (i = 0; i < sectors; i++) {
 		offset = (i >> 2) << 2;
 		err = readl(ecc->regs + ECC_DECENUM0 + offset);
-		err = err >> ((i % 4) * 8);
+		err = err >> ((i % 4) * ecc->caps->err_shift);
 		err &= ecc->caps->err_mask;
 		if (err == ecc->caps->err_mask) {
 			/* uncorrectable errors */
@@ -449,6 +450,7 @@
 
 static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
 	.err_mask = 0x3f,
+	.err_shift = 8,
 	.ecc_strength = ecc_strength_mt2701,
 	.ecc_regs = mt2701_ecc_regs,
 	.num_ecc_strength = 20,
@@ -459,6 +461,7 @@
 
 static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
 	.err_mask = 0x7f,
+	.err_shift = 8,
 	.ecc_strength = ecc_strength_mt2712,
 	.ecc_regs = mt2712_ecc_regs,
 	.num_ecc_strength = 23,
@@ -468,10 +471,11 @@
 };
 
 static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
-	.err_mask = 0x3f,
+	.err_mask = 0x1f,
+	.err_shift = 5,
 	.ecc_strength = ecc_strength_mt7622,
 	.ecc_regs = mt7622_ecc_regs,
-	.num_ecc_strength = 7,
+	.num_ecc_strength = 5,
 	.ecc_mode_shift = 4,
 	.parity_bits = 13,
 	.pg_irq_sel = 0,
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/mtk_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/mtk_nand.c
@@ -1419,7 +1419,7 @@
 	ret = mtd_device_register(mtd, NULL, 0);
 	if (ret) {
 		dev_err(dev, "mtd parse partition error\n");
-		nand_release(nand);
+		nand_cleanup(nand);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/nand_base.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/nand_base.c
@@ -292,12 +292,16 @@
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	int last_page = ((mtd->erasesize - mtd->writesize) >>
 			 chip->page_shift) & chip->pagemask;
+	unsigned int bbm_flags = NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE
+		| NAND_BBM_LASTPAGE;
 
+	if (page == 0 && !(chip->options & bbm_flags))
+		return 0;
 	if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
 		return 0;
-	else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
+	if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
 		return 1;
-	else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
+	if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
 		return last_page;
 
 	return -EINVAL;
@@ -727,8 +731,14 @@
 int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
 		      unsigned long timeout_ms)
 {
-	/* Wait until R/B pin indicates chip is ready or timeout occurs */
-	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
+
+	/*
+	 * Wait until R/B pin indicates chip is ready or timeout occurs.
+	 * +1 below is necessary because if we are now in the last fraction
+	 * of jiffy and msecs_to_jiffies is 1 then we will wait only that
+	 * small jiffy fraction - possibly leading to false timeout.
+	 */
+	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms) + 1;
 	do {
 		if (gpiod_get_value_cansleep(gpiod))
 			return 0;
@@ -5903,6 +5913,8 @@
 	    chip->ecc.algo == NAND_ECC_BCH)
 		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
+	nanddev_cleanup(&chip->base);
+
 	/* Free bad block table memory */
 	kfree(chip->bbt);
 	kfree(chip->data_buf);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/nand_ecc.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/nand_ecc.c
@@ -131,7 +131,7 @@
 	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
 	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
 	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
-	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
+	uint32_t rp17;
 	uint32_t par;		/* the cumulative parity for all data */
 	uint32_t tmppar;	/* the cumulative parity for this iteration;
 				   for rp12, rp14 and rp16 at the end of the
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/nand_micron.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/nand_micron.c
@@ -446,8 +446,10 @@
 	if (ret)
 		goto err_free_manuf_data;
 
+	chip->options |= NAND_BBM_FIRSTPAGE;
+
 	if (mtd->writesize == 2048)
-		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
+		chip->options |= NAND_BBM_SECONDPAGE;
 
 	ondie = micron_supports_on_die_ecc(chip);
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/nand_onfi.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/nand_onfi.c
@@ -173,7 +173,7 @@
 		}
 
 		if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
-				le16_to_cpu(p->crc)) {
+		    le16_to_cpu(p[i].crc)) {
 			if (i)
 				memcpy(p, &p[i], sizeof(*p));
 			break;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/nand_timings.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/nand_timings.c
@@ -314,10 +314,9 @@
 		/* microseconds -> picoseconds */
 		timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
 		timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
-		timings->tR_max = 1000000ULL * 200000000ULL;
 
-		/* nanoseconds -> picoseconds */
-		timings->tCCS_min = 1000UL * 500000;
+		timings->tR_max = 200000000;
+		timings->tCCS_min = 500000;
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/omap_elm.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/omap_elm.c
@@ -174,17 +174,17 @@
 			switch (info->bch_type) {
 			case BCH8_ECC:
 				/* syndrome fragment 0 = ecc[9-12B] */
-				val = cpu_to_be32(*(u32 *) &ecc[9]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[9]);
 				elm_write_reg(info, offset, val);
 
 				/* syndrome fragment 1 = ecc[5-8B] */
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[5]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[5]);
 				elm_write_reg(info, offset, val);
 
 				/* syndrome fragment 2 = ecc[1-4B] */
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[1]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[1]);
 				elm_write_reg(info, offset, val);
 
 				/* syndrome fragment 3 = ecc[0B] */
@@ -194,35 +194,35 @@
 				break;
 			case BCH4_ECC:
 				/* syndrome fragment 0 = ecc[20-52b] bits */
-				val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
+				val = ((__force u32)cpu_to_be32(*(u32 *)&ecc[3]) >> 4) |
 					((ecc[2] & 0xf) << 28);
 				elm_write_reg(info, offset, val);
 
 				/* syndrome fragment 1 = ecc[0-20b] bits */
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 12;
 				elm_write_reg(info, offset, val);
 				break;
 			case BCH16_ECC:
-				val = cpu_to_be32(*(u32 *) &ecc[22]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[22]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[18]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[18]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[14]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[14]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[10]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[10]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[6]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[6]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[2]);
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[2]);
 				elm_write_reg(info, offset, val);
 				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16;
+				val = (__force u32)cpu_to_be32(*(u32 *)&ecc[0]) >> 16;
 				elm_write_reg(info, offset, val);
 				break;
 			default:
@@ -411,6 +411,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-ein-5.4.0.orig/drivers/mtd/nand/raw/orion_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/orion_nand.c
@@ -180,7 +180,7 @@
 	mtd->name = "orion_nand";
 	ret = mtd_device_register(mtd, board->parts, board->nr_parts);
 	if (ret) {
-		nand_release(nc);
+		nand_cleanup(nc);
 		goto no_dev;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/oxnas_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/oxnas_nand.c
@@ -32,6 +32,7 @@
 	void __iomem *io_base;
 	struct clk *clk;
 	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+	unsigned int nchips;
 };
 
 static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
@@ -79,9 +80,9 @@
 	struct nand_chip *chip;
 	struct mtd_info *mtd;
 	struct resource *res;
-	int nchips = 0;
 	int count = 0;
 	int err = 0;
+	int i;
 
 	/* Allocate memory for the device structure (and zero it) */
 	oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
@@ -140,17 +141,15 @@
 			goto err_release_child;
 
 		err = mtd_device_register(mtd, NULL, 0);
-		if (err) {
-			nand_release(chip);
-			goto err_release_child;
-		}
+		if (err)
+			goto err_cleanup_nand;
 
-		oxnas->chips[nchips] = chip;
-		++nchips;
+		oxnas->chips[oxnas->nchips] = chip;
+		++oxnas->nchips;
 	}
 
 	/* Exit if no chips found */
-	if (!nchips) {
+	if (!oxnas->nchips) {
 		err = -ENODEV;
 		goto err_clk_unprepare;
 	}
@@ -159,8 +158,17 @@
 
 	return 0;
 
+err_cleanup_nand:
+	nand_cleanup(chip);
 err_release_child:
 	of_node_put(nand_np);
+
+	for (i = 0; i < oxnas->nchips; i++) {
+		chip = oxnas->chips[i];
+		WARN_ON(mtd_device_unregister(nand_to_mtd(chip)));
+		nand_cleanup(chip);
+	}
+
 err_clk_unprepare:
 	clk_disable_unprepare(oxnas->clk);
 	return err;
@@ -169,9 +177,13 @@
 static int oxnas_nand_remove(struct platform_device *pdev)
 {
 	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+	struct nand_chip *chip;
+	int i;
 
-	if (oxnas->chips[0])
-		nand_release(oxnas->chips[0]);
+	for (i = 0; i < oxnas->nchips; i++) {
+		chip = oxnas->chips[i];
+		nand_release(chip);
+	}
 
 	clk_disable_unprepare(oxnas->clk);
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/pasemi_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/pasemi_nand.c
@@ -146,7 +146,7 @@
 	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
 		dev_err(dev, "Unable to register MTD device\n");
 		err = -ENODEV;
-		goto out_lpc;
+		goto out_cleanup_nand;
 	}
 
 	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
@@ -154,6 +154,8 @@
 
 	return 0;
 
+ out_cleanup_nand:
+	nand_cleanup(chip);
  out_lpc:
 	release_region(lpcctl, 4);
  out_ior:
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/plat_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/plat_nand.c
@@ -92,7 +92,7 @@
 	if (!err)
 		return err;
 
-	nand_release(&data->chip);
+	nand_cleanup(&data->chip);
 out:
 	if (pdata->ctrl.remove)
 		pdata->ctrl.remove(pdev);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/qcom_nandc.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2,7 +2,6 @@
 /*
  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  */
-
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/bitops.h>
@@ -459,11 +458,13 @@
  * among different NAND controllers.
  * @ecc_modes - ecc mode for NAND
  * @is_bam - whether NAND controller is using BAM
+ * @is_qpic - whether NAND CTRL is part of qpic IP
  * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
  */
 struct qcom_nandc_props {
 	u32 ecc_modes;
 	bool is_bam;
+	bool is_qpic;
 	u32 dev_cmd_reg_start;
 };
 
@@ -1568,6 +1569,8 @@
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	int i;
 
+	nandc_read_buffer_sync(nandc, true);
+
 	for (i = 0; i < cw_cnt; i++) {
 		u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
 
@@ -2751,7 +2754,8 @@
 	u32 nand_ctrl;
 
 	/* kill onenand */
-	nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+	if (!nandc->props->is_qpic)
+		nandc_write(nandc, SFLASHC_BURST_CFG, 0);
 	nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
 		    NAND_DEV_CMD_VLD_VAL);
 
@@ -2845,7 +2849,7 @@
 	struct device *dev = nandc->dev;
 	struct device_node *dn = dev->of_node, *child;
 	struct qcom_nand_host *host;
-	int ret;
+	int ret = -ENODEV;
 
 	for_each_available_child_of_node(dn, child) {
 		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
@@ -2863,10 +2867,7 @@
 		list_add_tail(&host->node, &nandc->host_list);
 	}
 
-	if (list_empty(&nandc->host_list))
-		return -ENODEV;
-
-	return 0;
+	return ret;
 }
 
 /* parse custom DT properties here */
@@ -2942,10 +2943,6 @@
 	if (!nandc->base_dma)
 		return -ENXIO;
 
-	ret = qcom_nandc_alloc(nandc);
-	if (ret)
-		goto err_nandc_alloc;
-
 	ret = clk_prepare_enable(nandc->core_clk);
 	if (ret)
 		goto err_core_clk;
@@ -2954,6 +2951,10 @@
 	if (ret)
 		goto err_aon_clk;
 
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		goto err_nandc_alloc;
+
 	ret = qcom_nandc_setup(nandc);
 	if (ret)
 		goto err_setup;
@@ -2965,15 +2966,14 @@
 	return 0;
 
 err_setup:
+	qcom_nandc_unalloc(nandc);
+err_nandc_alloc:
 	clk_disable_unprepare(nandc->aon_clk);
 err_aon_clk:
 	clk_disable_unprepare(nandc->core_clk);
 err_core_clk:
-	qcom_nandc_unalloc(nandc);
-err_nandc_alloc:
-	dma_unmap_resource(dev, res->start, resource_size(res),
+	dma_unmap_resource(dev, nandc->base_dma, resource_size(res),
 			   DMA_BIDIRECTIONAL, 0);
-
 	return ret;
 }
 
@@ -3007,12 +3007,14 @@
 static const struct qcom_nandc_props ipq4019_nandc_props = {
 	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
 	.is_bam = true,
+	.is_qpic = true,
 	.dev_cmd_reg_start = 0x0,
 };
 
 static const struct qcom_nandc_props ipq8074_nandc_props = {
 	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
 	.is_bam = true,
+	.is_qpic = true,
 	.dev_cmd_reg_start = 0x7000,
 };
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/s3c2410.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/s3c2410.c
@@ -291,7 +291,7 @@
 	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
 	int tacls, twrph0, twrph1;
 	unsigned long clkrate = clk_get_rate(info->clk);
-	unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
+	unsigned long set, cfg, mask;
 	unsigned long flags;
 
 	/* calculate the timing information for the controller */
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/sh_flctl.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/sh_flctl.c
@@ -384,7 +384,8 @@
 	dma_addr_t dma_addr;
 	dma_cookie_t cookie;
 	uint32_t reg;
-	int ret;
+	int ret = 0;
+	unsigned long time_left;
 
 	if (dir == DMA_FROM_DEVICE) {
 		chan = flctl->chan_fifo0_rx;
@@ -425,13 +426,14 @@
 		goto out;
 	}
 
-	ret =
+	time_left =
 	wait_for_completion_timeout(&flctl->dma_complete,
 				msecs_to_jiffies(3000));
 
-	if (ret <= 0) {
+	if (time_left == 0) {
 		dmaengine_terminate_all(chan);
 		dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+		ret = -ETIMEDOUT;
 	}
 
 out:
@@ -441,7 +443,7 @@
 
 	dma_unmap_single(chan->device->dev, dma_addr, len, dir);
 
-	/* ret > 0 is success */
+	/* ret == 0 is success */
 	return ret;
 }
 
@@ -465,7 +467,7 @@
 
 	/* initiate DMA transfer */
 	if (flctl->chan_fifo0_rx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
+		!flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE))
 			goto convert;	/* DMA success */
 
 	/* do polling transfer */
@@ -524,7 +526,7 @@
 
 	/* initiate DMA transfer */
 	if (flctl->chan_fifo0_tx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
+		!flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE))
 			return;	/* DMA success */
 
 	/* do polling transfer */
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/sharpsl.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/sharpsl.c
@@ -183,7 +183,7 @@
 	return 0;
 
 err_add:
-	nand_release(this);
+	nand_cleanup(this);
 
 err_scan:
 	iounmap(sharpsl->io);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/socrates_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/socrates_nand.c
@@ -169,7 +169,7 @@
 	if (!res)
 		return res;
 
-	nand_release(nand_chip);
+	nand_cleanup(nand_chip);
 
 out:
 	iounmap(host->io_base);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -37,6 +37,7 @@
 /* Max ECC buffer length */
 #define FMC2_MAX_ECC_BUF_LEN		(FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
 
+#define FMC2_TIMEOUT_US			1000
 #define FMC2_TIMEOUT_MS			1000
 
 /* Timings */
@@ -53,6 +54,8 @@
 #define FMC2_PMEM			0x88
 #define FMC2_PATT			0x8c
 #define FMC2_HECCR			0x94
+#define FMC2_ISR			0x184
+#define FMC2_ICR			0x188
 #define FMC2_CSQCR			0x200
 #define FMC2_CSQCFGR1			0x204
 #define FMC2_CSQCFGR2			0x208
@@ -118,6 +121,12 @@
 #define FMC2_PATT_ATTHIZ(x)		(((x) & 0xff) << 24)
 #define FMC2_PATT_DEFAULT		0x0a0a0a0a
 
+/* Register: FMC2_ISR */
+#define FMC2_ISR_IHLF			BIT(1)
+
+/* Register: FMC2_ICR */
+#define FMC2_ICR_CIHLF			BIT(1)
+
 /* Register: FMC2_CSQCR */
 #define FMC2_CSQCR_CSQSTART		BIT(0)
 
@@ -1322,6 +1331,31 @@
 		stm32_fmc2_set_buswidth_16(fmc2, true);
 }
 
+static int stm32_fmc2_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
+{
+	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
+	const struct nand_sdr_timings *timings;
+	u32 isr, sr;
+
+	/* Check if there is no pending requests to the NAND flash */
+	if (readl_relaxed_poll_timeout_atomic(fmc2->io_base + FMC2_SR, sr,
+					      sr & FMC2_SR_NWRF, 1,
+					      FMC2_TIMEOUT_US))
+		dev_warn(fmc2->dev, "Waitrdy timeout\n");
+
+	/* Wait tWB before R/B# signal is low */
+	timings = nand_get_sdr_timings(&chip->data_interface);
+	ndelay(PSEC_TO_NSEC(timings->tWB_max));
+
+	/* R/B# signal is low, clear high level flag */
+	writel_relaxed(FMC2_ICR_CIHLF, fmc2->io_base + FMC2_ICR);
+
+	/* Wait R/B# signal is high */
+	return readl_relaxed_poll_timeout_atomic(fmc2->io_base + FMC2_ISR,
+						 isr, isr & FMC2_ISR_IHLF,
+						 5, 1000 * timeout_ms);
+}
+
 static int stm32_fmc2_exec_op(struct nand_chip *chip,
 			      const struct nand_operation *op,
 			      bool check_only)
@@ -1366,8 +1400,8 @@
 			break;
 
 		case NAND_OP_WAITRDY_INSTR:
-			ret = nand_soft_waitrdy(chip,
-						instr->ctx.waitrdy.timeout_ms);
+			ret = stm32_fmc2_waitrdy(chip,
+						 instr->ctx.waitrdy.timeout_ms);
 			break;
 		}
 	}
@@ -1558,6 +1592,9 @@
 	if (IS_ERR(sdrt))
 		return PTR_ERR(sdrt);
 
+	if (sdrt->tRC_min < 30000)
+		return -EOPNOTSUPP;
+
 	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
 		return 0;
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/sunxi_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1587,7 +1587,7 @@
 	if (section < ecc->steps)
 		oobregion->length = 4;
 	else
-		oobregion->offset = mtd->oobsize - oobregion->offset;
+		oobregion->length = mtd->oobsize - oobregion->offset;
 
 	return 0;
 }
@@ -2003,7 +2003,7 @@
 	ret = mtd_device_register(mtd, NULL, 0);
 	if (ret) {
 		dev_err(dev, "failed to register mtd device: %d\n", ret);
-		nand_release(nand);
+		nand_cleanup(nand);
 		return ret;
 	}
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/tmio_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/tmio_nand.c
@@ -448,7 +448,7 @@
 	if (!retval)
 		return retval;
 
-	nand_release(nand_chip);
+	nand_cleanup(nand_chip);
 
 err_irq:
 	tmio_hw_stop(dev, tmio);
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/vf610_nfc.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/vf610_nfc.c
@@ -850,8 +850,10 @@
 	}
 
 	of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
-	if (!of_id)
-		return -ENODEV;
+	if (!of_id) {
+		err = -ENODEV;
+		goto err_disable_clk;
+	}
 
 	nfc->variant = (enum vf610_nfc_variant)of_id->data;
 
--- linux-ein-5.4.0.orig/drivers/mtd/nand/raw/xway_nand.c
+++ linux-ein-5.4.0/drivers/mtd/nand/raw/xway_nand.c
@@ -210,7 +210,7 @@
 
 	err = mtd_device_register(mtd, NULL, 0);
 	if (err)
-		nand_release(&data->chip);
+		nand_cleanup(&data->chip);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/mtd/nand/spi/core.c
+++ linux-ein-5.4.0/drivers/mtd/nand/spi/core.c
@@ -568,18 +568,18 @@
 static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
 {
 	struct spinand_device *spinand = nand_to_spinand(nand);
+	u8 marker[2] = { };
 	struct nand_page_io_req req = {
 		.pos = *pos,
-		.ooblen = 2,
+		.ooblen = sizeof(marker),
 		.ooboffs = 0,
-		.oobbuf.in = spinand->oobbuf,
+		.oobbuf.in = marker,
 		.mode = MTD_OPS_RAW,
 	};
 
-	memset(spinand->oobbuf, 0, 2);
 	spinand_select_target(spinand, pos->target);
 	spinand_read_page(spinand, &req, false);
-	if (spinand->oobbuf[0] != 0xff || spinand->oobbuf[1] != 0xff)
+	if (marker[0] != 0xff || marker[1] != 0xff)
 		return true;
 
 	return false;
@@ -603,15 +603,16 @@
 static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
 {
 	struct spinand_device *spinand = nand_to_spinand(nand);
+	u8 marker[2] = { };
 	struct nand_page_io_req req = {
 		.pos = *pos,
 		.ooboffs = 0,
-		.ooblen = 2,
-		.oobbuf.out = spinand->oobbuf,
+		.ooblen = sizeof(marker),
+		.oobbuf.out = marker,
+		.mode = MTD_OPS_RAW,
 	};
 	int ret;
 
-	/* Erase block before marking it bad. */
 	ret = spinand_select_target(spinand, pos->target);
 	if (ret)
 		return ret;
@@ -620,9 +621,6 @@
 	if (ret)
 		return ret;
 
-	spinand_erase_op(spinand, pos);
-
-	memset(spinand->oobbuf, 0, 2);
 	return spinand_write_page(spinand, &req);
 }
 
@@ -1051,6 +1049,10 @@
 
 	mtd->oobavail = ret;
 
+	/* Propagate ECC information to mtd_info */
+	mtd->ecc_strength = nand->eccreq.strength;
+	mtd->ecc_step_size = nand->eccreq.step_size;
+
 	return 0;
 
 err_cleanup_nanddev:
@@ -1131,12 +1133,14 @@
 	{ .name = "spi-nand" },
 	{ /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(spi, spinand_ids);
 
 #ifdef CONFIG_OF
 static const struct of_device_id spinand_of_ids[] = {
 	{ .compatible = "spi-nand" },
 	{ /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, spinand_of_ids);
 #endif
 
 static struct spi_mem_driver spinand_drv = {
--- linux-ein-5.4.0.orig/drivers/mtd/nand/spi/gigadevice.c
+++ linux-ein-5.4.0/drivers/mtd/nand/spi/gigadevice.c
@@ -21,7 +21,7 @@
 #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR	(7 << 4)
 
 static SPINAND_OP_VARIANTS(read_cache_variants,
-		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -29,7 +29,7 @@
 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
 static SPINAND_OP_VARIANTS(read_cache_variants_f,
-		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
@@ -201,7 +201,7 @@
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
+		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
 				     gd5fxgq4xa_ecc_get_status)),
 	SPINAND_INFO("GD5F2GQ4xA", 0xF2,
@@ -210,7 +210,7 @@
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
+		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
 				     gd5fxgq4xa_ecc_get_status)),
 	SPINAND_INFO("GD5F4GQ4xA", 0xF4,
@@ -219,7 +219,7 @@
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
+		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
 				     gd5fxgq4xa_ecc_get_status)),
 	SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
@@ -228,7 +228,7 @@
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
+		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
 				     gd5fxgq4uexxg_ecc_get_status)),
 	SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
@@ -237,7 +237,7 @@
 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
 					      &write_cache_variants,
 					      &update_cache_variants),
-		     0,
+		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
 				     gd5fxgq4ufxxg_ecc_get_status)),
 };
--- linux-ein-5.4.0.orig/drivers/mtd/nand/spi/macronix.c
+++ linux-ein-5.4.0/drivers/mtd/nand/spi/macronix.c
@@ -116,6 +116,22 @@
 					      &update_cache_variants),
 		     SPINAND_HAS_QE_BIT,
 		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX35LF2GE4AD", 0x26,
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+	SPINAND_INFO("MX35LF4GE4AD", 0x37,
+		     NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
 };
 
 static int macronix_spinand_detect(struct spinand_device *spinand)
--- linux-ein-5.4.0.orig/drivers/mtd/nand/spi/micron.c
+++ linux-ein-5.4.0/drivers/mtd/nand/spi/micron.c
@@ -12,7 +12,7 @@
 
 #define SPINAND_MFR_MICRON		0x2c
 
-#define MICRON_STATUS_ECC_MASK		GENMASK(7, 4)
+#define MICRON_STATUS_ECC_MASK		GENMASK(6, 4)
 #define MICRON_STATUS_ECC_NO_BITFLIPS	(0 << 4)
 #define MICRON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)
 #define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
--- linux-ein-5.4.0.orig/drivers/mtd/nand/spi/toshiba.c
+++ linux-ein-5.4.0/drivers/mtd/nand/spi/toshiba.c
@@ -60,7 +60,7 @@
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
 	u8 mbf = 0;
-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf);
 
 	switch (status & STATUS_ECC_MASK) {
 	case STATUS_ECC_NO_BITFLIPS:
@@ -79,7 +79,7 @@
 		if (spi_mem_exec_op(spinand->spimem, &op))
 			return nand->eccreq.strength;
 
-		mbf >>= 4;
+		mbf = *(spinand->scratchbuf) >> 4;
 
 		if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
 			return nand->eccreq.strength;
--- linux-ein-5.4.0.orig/drivers/mtd/parsers/afs.c
+++ linux-ein-5.4.0/drivers/mtd/parsers/afs.c
@@ -126,8 +126,8 @@
 	 * Static checks cannot see that we bail out if we have an error
 	 * reading the footer.
 	 */
-	u_int uninitialized_var(iis_ptr);
-	u_int uninitialized_var(img_ptr);
+	u_int iis_ptr;
+	u_int img_ptr;
 	u_int ptr;
 	size_t sz;
 	int ret;
@@ -370,10 +370,8 @@
 	return i;
 
 out_free_parts:
-	while (i >= 0) {
+	while (--i >= 0)
 		kfree(parts[i].name);
-		i--;
-	}
 	kfree(parts);
 	*pparts = NULL;
 	return ret;
--- linux-ein-5.4.0.orig/drivers/mtd/parsers/cmdlinepart.c
+++ linux-ein-5.4.0/drivers/mtd/parsers/cmdlinepart.c
@@ -218,12 +218,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-ein-5.4.0.orig/drivers/mtd/parsers/parser_imagetag.c
+++ linux-ein-5.4.0/drivers/mtd/parsers/parser_imagetag.c
@@ -83,6 +83,7 @@
 			pr_err("invalid rootfs address: %*ph\n",
 				(int)sizeof(buf->flash_image_start),
 				buf->flash_image_start);
+			ret = -EINVAL;
 			goto out;
 		}
 
@@ -92,6 +93,7 @@
 			pr_err("invalid kernel address: %*ph\n",
 				(int)sizeof(buf->kernel_address),
 				buf->kernel_address);
+			ret = -EINVAL;
 			goto out;
 		}
 
@@ -100,6 +102,7 @@
 			pr_err("invalid kernel length: %*ph\n",
 				(int)sizeof(buf->kernel_length),
 				buf->kernel_length);
+			ret = -EINVAL;
 			goto out;
 		}
 
@@ -108,6 +111,7 @@
 			pr_err("invalid total length: %*ph\n",
 				(int)sizeof(buf->total_length),
 				buf->total_length);
+			ret = -EINVAL;
 			goto out;
 		}
 
--- linux-ein-5.4.0.orig/drivers/mtd/parsers/redboot.c
+++ linux-ein-5.4.0/drivers/mtd/parsers/redboot.c
@@ -45,6 +45,7 @@
 static void parse_redboot_of(struct mtd_info *master)
 {
 	struct device_node *np;
+	struct device_node *npart;
 	u32 dirblock;
 	int ret;
 
@@ -52,7 +53,12 @@
 	if (!np)
 		return;
 
-	ret = of_property_read_u32(np, "fis-index-block", &dirblock);
+	npart = of_get_child_by_name(np, "partitions");
+	if (!npart)
+		return;
+
+	ret = of_property_read_u32(npart, "fis-index-block", &dirblock);
+	of_node_put(npart);
 	if (ret)
 		return;
 
--- linux-ein-5.4.0.orig/drivers/mtd/parsers/sharpslpart.c
+++ linux-ein-5.4.0/drivers/mtd/parsers/sharpslpart.c
@@ -165,10 +165,10 @@
 
 static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
 {
-	unsigned int block_num, log_num, phymax;
+	unsigned int block_num, phymax;
+	int i, ret, log_num;
 	loff_t block_adr;
 	u8 *oob;
-	int i, ret;
 
 	oob = kzalloc(mtd->oobsize, GFP_KERNEL);
 	if (!oob)
--- linux-ein-5.4.0.orig/drivers/mtd/sm_ftl.c
+++ linux-ein-5.4.0/drivers/mtd/sm_ftl.c
@@ -1097,9 +1097,9 @@
 {
 	struct sm_ftl *ftl = dev->priv;
 
-	mutex_lock(&ftl->mutex);
 	del_timer_sync(&ftl->timer);
 	cancel_work_sync(&ftl->flush_work);
+	mutex_lock(&ftl->mutex);
 	sm_cache_flush(ftl);
 	mutex_unlock(&ftl->mutex);
 }
--- linux-ein-5.4.0.orig/drivers/mtd/spi-nor/cadence-quadspi.c
+++ linux-ein-5.4.0/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -34,6 +34,7 @@
 
 /* Quirks */
 #define CQSPI_NEEDS_WR_DELAY		BIT(0)
+#define CQSPI_DISABLE_DAC_MODE		BIT(1)
 
 /* Capabilities mask */
 #define CQSPI_BASE_HWCAPS_MASK					\
@@ -77,9 +78,6 @@
 	dma_addr_t		mmap_phys_base;
 
 	int			current_cs;
-	int			current_page_size;
-	int			current_erase_size;
-	int			current_addr_width;
 	unsigned long		master_ref_clk_hz;
 	bool			is_decoded_cs;
 	u32			fifo_depth;
@@ -475,7 +473,7 @@
 	/* Setup dummy clock cycles */
 	dummy_clk = nor->read_dummy;
 	if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
-		dummy_clk = CQSPI_DUMMY_CLKS_MAX;
+		return -EOPNOTSUPP;
 
 	if (dummy_clk / 8) {
 		reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
@@ -736,32 +734,6 @@
 	writel(reg, reg_base + CQSPI_REG_CONFIG);
 }
 
-static void cqspi_configure_cs_and_sizes(struct spi_nor *nor)
-{
-	struct cqspi_flash_pdata *f_pdata = nor->priv;
-	struct cqspi_st *cqspi = f_pdata->cqspi;
-	void __iomem *iobase = cqspi->iobase;
-	unsigned int reg;
-
-	/* configure page size and block size. */
-	reg = readl(iobase + CQSPI_REG_SIZE);
-	reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
-	reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
-	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
-	reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
-	reg |= (ilog2(nor->mtd.erasesize) << CQSPI_REG_SIZE_BLOCK_LSB);
-	reg |= (nor->addr_width - 1);
-	writel(reg, iobase + CQSPI_REG_SIZE);
-
-	/* configure the chip select */
-	cqspi_chipselect(nor);
-
-	/* Store the new configuration of the controller */
-	cqspi->current_page_size = nor->page_size;
-	cqspi->current_erase_size = nor->mtd.erasesize;
-	cqspi->current_addr_width = nor->addr_width;
-}
-
 static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz,
 					   const unsigned int ns_val)
 {
@@ -867,18 +839,13 @@
 	int switch_cs = (cqspi->current_cs != f_pdata->cs);
 	int switch_ck = (cqspi->sclk != sclk);
 
-	if ((cqspi->current_page_size != nor->page_size) ||
-	    (cqspi->current_erase_size != nor->mtd.erasesize) ||
-	    (cqspi->current_addr_width != nor->addr_width))
-		switch_cs = 1;
-
 	if (switch_cs || switch_ck)
 		cqspi_controller_enable(cqspi, 0);
 
 	/* Switch chip select. */
 	if (switch_cs) {
 		cqspi->current_cs = f_pdata->cs;
-		cqspi_configure_cs_and_sizes(nor);
+		cqspi_chipselect(nor);
 	}
 
 	/* Setup baudrate divisor and delays */
@@ -1201,7 +1168,7 @@
 	cqspi_controller_enable(cqspi, 1);
 }
 
-static void cqspi_request_mmap_dma(struct cqspi_st *cqspi)
+static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
 {
 	dma_cap_mask_t mask;
 
@@ -1210,10 +1177,16 @@
 
 	cqspi->rx_chan = dma_request_chan_by_mask(&mask);
 	if (IS_ERR(cqspi->rx_chan)) {
-		dev_err(&cqspi->pdev->dev, "No Rx DMA available\n");
+		int ret = PTR_ERR(cqspi->rx_chan);
+
+		if (ret != -EPROBE_DEFER)
+			dev_err(&cqspi->pdev->dev, "No Rx DMA available\n");
 		cqspi->rx_chan = NULL;
+		return ret;
 	}
 	init_completion(&cqspi->rx_dma_complete);
+
+	return 0;
 }
 
 static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
@@ -1291,13 +1264,17 @@
 
 		f_pdata->registered = true;
 
-		if (mtd->size <= cqspi->ahb_size) {
+		if (mtd->size <= cqspi->ahb_size &&
+		    !(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) {
 			f_pdata->use_direct_mode = true;
 			dev_dbg(nor->dev, "using direct mode for %s\n",
 				mtd->name);
 
-			if (!cqspi->rx_chan)
-				cqspi_request_mmap_dma(cqspi);
+			if (!cqspi->rx_chan) {
+				ret = cqspi_request_mmap_dma(cqspi);
+				if (ret == -EPROBE_DEFER)
+					goto err;
+			}
 		}
 	}
 
@@ -1464,17 +1441,30 @@
 static int cqspi_suspend(struct device *dev)
 {
 	struct cqspi_st *cqspi = dev_get_drvdata(dev);
+	struct spi_master *master = dev_get_drvdata(dev);
+	int ret;
 
+	ret = spi_master_suspend(master);
 	cqspi_controller_enable(cqspi, 0);
-	return 0;
+
+	clk_disable_unprepare(cqspi->clk);
+
+	return ret;
 }
 
 static int cqspi_resume(struct device *dev)
 {
 	struct cqspi_st *cqspi = dev_get_drvdata(dev);
+	struct spi_master *master = dev_get_drvdata(dev);
 
-	cqspi_controller_enable(cqspi, 1);
-	return 0;
+	clk_prepare_enable(cqspi->clk);
+	cqspi_wait_idle(cqspi);
+	cqspi_controller_init(cqspi);
+
+	cqspi->current_cs = -1;
+	cqspi->sclk = 0;
+
+	return spi_master_resume(master);
 }
 
 static const struct dev_pm_ops cqspi__dev_pm_ops = {
@@ -1489,6 +1479,7 @@
 
 static const struct cqspi_driver_platdata cdns_qspi = {
 	.hwcaps_mask = CQSPI_BASE_HWCAPS_MASK,
+	.quirks = CQSPI_DISABLE_DAC_MODE,
 };
 
 static const struct cqspi_driver_platdata k2g_qspi = {
--- linux-ein-5.4.0.orig/drivers/mtd/spi-nor/hisi-sfc.c
+++ linux-ein-5.4.0/drivers/mtd/spi-nor/hisi-sfc.c
@@ -396,8 +396,10 @@
 
 	for_each_available_child_of_node(dev->of_node, np) {
 		ret = hisi_spi_nor_register(np, host);
-		if (ret)
+		if (ret) {
+			of_node_put(np);
 			goto fail;
+		}
 
 		if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
 			dev_warn(dev, "Flash device number exceeds the maximum chipselect number\n");
@@ -472,7 +474,6 @@
 
 	hisi_spi_nor_unregister_all(host);
 	mutex_destroy(&host->lock);
-	clk_disable_unprepare(host->clk);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/mtd/spi-nor/intel-spi-pci.c
+++ linux-ein-5.4.0/drivers/mtd/spi-nor/intel-spi-pci.c
@@ -61,6 +61,7 @@
 
 static const struct pci_device_id intel_spi_pci_ids[] = {
 	{ PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info },
+	{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
 	{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
--- linux-ein-5.4.0.orig/drivers/mtd/spi-nor/intel-spi.c
+++ linux-ein-5.4.0/drivers/mtd/spi-nor/intel-spi.c
@@ -113,7 +113,7 @@
 #define ERASE_OPCODE_SHIFT		8
 #define ERASE_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
 #define ERASE_64K_OPCODE_SHIFT		16
-#define ERASE_64K_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
+#define ERASE_64K_OPCODE_MASK		(0xff << ERASE_64K_OPCODE_SHIFT)
 
 #define INTEL_SPI_TIMEOUT		5000 /* ms */
 #define INTEL_SPI_FIFO_SZ		64
--- linux-ein-5.4.0.orig/drivers/mtd/spi-nor/spi-nor.c
+++ linux-ein-5.4.0/drivers/mtd/spi-nor/spi-nor.c
@@ -1010,15 +1010,18 @@
 			continue;
 
 		erase = &map->erase_type[i];
-
-		/* Don't erase more than what the user has asked for. */
-		if (erase->size > len)
+		if (!erase->size)
 			continue;
 
 		/* Alignment is not mandatory for overlaid regions */
-		if (region->offset & SNOR_OVERLAID_REGION)
+		if (region->offset & SNOR_OVERLAID_REGION &&
+		    region->size <= len)
 			return erase;
 
+		/* Don't erase more than what the user has asked for. */
+		if (erase->size > len)
+			continue;
+
 		spi_nor_div_by_erase_size(erase, addr, &rem);
 		if (rem)
 			continue;
@@ -1152,6 +1155,7 @@
 			goto destroy_erase_cmd_list;
 
 		if (prev_erase != erase ||
+		    erase->size != cmd->size ||
 		    region->offset & SNOR_OVERLAID_REGION) {
 			cmd = spi_nor_init_erase_cmd(region, erase);
 			if (IS_ERR(cmd)) {
@@ -2199,6 +2203,7 @@
 
 	/* Fujitsu */
 	{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
+	{ "mb85rq4ml", INFO(0x047f29, 0, 128 * 1024, 4, SPI_NOR_NO_ERASE) },
 
 	/* GigaDevice */
 	{
@@ -2267,6 +2272,10 @@
 			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) },
+	{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512,
+			    SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			    SPI_NOR_4B_OPCODES)
+		       .fixups = &is25lp256_fixups },
 
 	/* Macronix */
 	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -2310,15 +2319,16 @@
 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "n25q256ax1",  INFO(0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
 	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+	{ "mt25qu512a",  INFO6(0x20bb20, 0x104400, 64 * 1024, 1024,
+			       SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
+			       SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K |
+			      SPI_NOR_QUAD_READ) },
 	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ "mt25ql02g",   INFO(0x20ba22, 0, 64 * 1024, 4096,
 			      SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
 			      NO_CHIP_ERASE) },
-	{ "mt25qu512a (n25q512a)", INFO(0x20bb20, 0, 64 * 1024, 1024,
-					SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
-					SPI_NOR_QUAD_READ |
-					SPI_NOR_4B_OPCODES) },
 	{ "mt25qu02g",   INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 
 	/* Micron */
@@ -2544,7 +2554,7 @@
 			size_t *retlen, u_char *buf)
 {
 	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-	int ret;
+	ssize_t ret;
 
 	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
 
@@ -2865,7 +2875,7 @@
  */
 static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
 {
-	int ret;
+	ssize_t ret;
 
 	while (len) {
 		ret = spi_nor_read_data(nor, addr, len, buf);
@@ -3699,7 +3709,7 @@
 	int i;
 
 	for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
-		if (!(erase_type & BIT(i)))
+		if (!(erase[i].size && erase_type & BIT(erase[i].idx)))
 			continue;
 		if (region->size & erase[i].size_mask) {
 			spi_nor_region_mark_overlay(region);
@@ -3769,6 +3779,7 @@
 		offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
 			 region[i].size;
 	}
+	spi_nor_region_mark_end(&region[i - 1]);
 
 	save_uniform_erase_type = map->uniform_erase_type;
 	map->uniform_erase_type = spi_nor_sort_erase_mask(map,
@@ -3792,8 +3803,6 @@
 		if (!(regions_erase_type & BIT(erase[i].idx)))
 			spi_nor_set_erase_type(&erase[i], 0, 0xFF);
 
-	spi_nor_region_mark_end(&region[i - 1]);
-
 	return 0;
 }
 
@@ -4443,11 +4452,10 @@
 
 	memcpy(&sfdp_params, &nor->params, sizeof(sfdp_params));
 
-	if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
+	if (spi_nor_parse_sfdp(nor, &nor->params)) {
+		memcpy(&nor->params, &sfdp_params, sizeof(nor->params));
 		nor->addr_width = 0;
 		nor->flags &= ~SNOR_F_4B_OPCODES;
-	} else {
-		memcpy(&nor->params, &sfdp_params, sizeof(nor->params));
 	}
 }
 
@@ -4544,9 +4552,7 @@
 
 static void spansion_post_sfdp_fixups(struct spi_nor *nor)
 {
-	struct mtd_info *mtd = &nor->mtd;
-
-	if (mtd->size <= SZ_16M)
+	if (nor->params.size <= SZ_16M)
 		return;
 
 	nor->flags |= SNOR_F_4B_OPCODES;
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/build.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/build.c
@@ -350,9 +350,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);
@@ -381,7 +378,6 @@
 	else
 		ret = -EINVAL;
 
-	ubi_put_device(ubi);
 	return ret;
 }
 
@@ -471,6 +467,7 @@
 			err = ubi_add_volume(ubi, ubi->volumes[i]);
 			if (err) {
 				ubi_err(ubi, "cannot add volume %d", i);
+				ubi->volumes[i] = NULL;
 				goto out_volumes;
 			}
 		}
@@ -664,6 +661,21 @@
 						ubi->vid_hdr_aloffset;
 	}
 
+	/*
+	 * Memory allocation for VID header is ubi->vid_hdr_alsize
+	 * which is described in comments in io.c.
+	 * Make sure VID header shift + UBI_VID_HDR_SIZE not exceeds
+	 * ubi->vid_hdr_alsize, so that all vid header operations
+	 * won't access memory out of bounds.
+	 */
+	if ((ubi->vid_hdr_shift + UBI_VID_HDR_SIZE) > ubi->vid_hdr_alsize) {
+		ubi_err(ubi, "Invalid VID header offset %d, VID header shift(%d)"
+			" + VID header size(%zu) > VID header aligned size(%d).",
+			ubi->vid_hdr_offset, ubi->vid_hdr_shift,
+			UBI_VID_HDR_SIZE, ubi->vid_hdr_alsize);
+		return -EINVAL;
+	}
+
 	/* Similar for the data offset */
 	ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;
 	ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
@@ -853,6 +865,13 @@
 		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;
+	}
+
 	if (ubi_num == UBI_DEV_NUM_AUTO) {
 		/* Search for an empty slot in the @ubi_devices array */
 		for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
@@ -956,9 +975,6 @@
 			goto out_detach;
 	}
 
-	/* Make device "available" before it becomes accessible via sysfs */
-	ubi_devices[ubi_num] = ubi;
-
 	err = uif_init(ubi);
 	if (err)
 		goto out_detach;
@@ -1003,6 +1019,7 @@
 	wake_up_process(ubi->bgt_thread);
 	spin_unlock(&ubi->wl_lock);
 
+	ubi_devices[ubi_num] = ubi;
 	ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
 	return ubi_num;
 
@@ -1011,7 +1028,6 @@
 out_uif:
 	uif_close(ubi);
 out_detach:
-	ubi_devices[ubi_num] = NULL;
 	ubi_wl_close(ubi);
 	ubi_free_internal_volumes(ubi);
 	vfree(ubi->vtbl);
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/debug.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/debug.c
@@ -392,9 +392,6 @@
 {
 	struct ubi_device *ubi = s->private;
 
-	if (*pos == 0)
-		return SEQ_START_TOKEN;
-
 	if (*pos < ubi->peb_count)
 		return pos;
 
@@ -408,8 +405,6 @@
 {
 	struct ubi_device *ubi = s->private;
 
-	if (v == SEQ_START_TOKEN)
-		return pos;
 	(*pos)++;
 
 	if (*pos < ubi->peb_count)
@@ -431,11 +426,8 @@
 	int err;
 
 	/* If this is the start, print a header */
-	if (iter == SEQ_START_TOKEN) {
-		seq_puts(s,
-			 "physical_block_number\terase_count\tblock_status\tread_status\n");
-		return 0;
-	}
+	if (*block_number == 0)
+		seq_puts(s, "physical_block_number\terase_count\n");
 
 	err = ubi_io_is_bad(ubi, *block_number);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/eba.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/eba.c
@@ -599,7 +599,7 @@
 	int err, pnum, scrub = 0, vol_id = vol->vol_id;
 	struct ubi_vid_io_buf *vidb;
 	struct ubi_vid_hdr *vid_hdr;
-	uint32_t uninitialized_var(crc);
+	uint32_t crc;
 
 	err = leb_read_lock(ubi, vol_id, lnum);
 	if (err)
@@ -947,7 +947,7 @@
 				  int offset, int len)
 {
 	struct ubi_device *ubi = vol->ubi;
-	int pnum, opnum, err, vol_id = vol->vol_id;
+	int pnum, opnum, err, err2, vol_id = vol->vol_id;
 
 	pnum = ubi_wl_get_peb(ubi);
 	if (pnum < 0) {
@@ -982,10 +982,19 @@
 out_put:
 	up_read(&ubi->fm_eba_sem);
 
-	if (err && pnum >= 0)
-		err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
-	else if (!err && opnum >= 0)
-		err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
+	if (err && pnum >= 0) {
+		err2 = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
+		if (err2) {
+			ubi_warn(ubi, "failed to return physical eraseblock %d, error %d",
+				 pnum, err2);
+		}
+	} else if (!err && opnum >= 0) {
+		err2 = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
+		if (err2) {
+			ubi_warn(ubi, "failed to return physical eraseblock %d, error %d",
+				 opnum, err2);
+		}
+	}
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/fastmap-wl.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/fastmap-wl.c
@@ -39,6 +39,13 @@
 	return victim;
 }
 
+static inline void return_unused_peb(struct ubi_device *ubi,
+				     struct ubi_wl_entry *e)
+{
+	wl_tree_add(e, &ubi->free);
+	ubi->free_count++;
+}
+
 /**
  * return_unused_pool_pebs - returns unused PEB to the free tree.
  * @ubi: UBI device description object
@@ -52,23 +59,10 @@
 
 	for (i = pool->used; i < pool->size; i++) {
 		e = ubi->lookuptbl[pool->pebs[i]];
-		wl_tree_add(e, &ubi->free);
-		ubi->free_count++;
+		return_unused_peb(ubi, e);
 	}
 }
 
-static int anchor_pebs_available(struct rb_root *root)
-{
-	struct rb_node *p;
-	struct ubi_wl_entry *e;
-
-	ubi_rb_for_each_entry(p, e, root, u.rb)
-		if (e->pnum < UBI_FM_MAX_START)
-			return 1;
-
-	return 0;
-}
-
 /**
  * ubi_wl_get_fm_peb - find a physical erase block with a given maximal number.
  * @ubi: UBI device description object
@@ -277,8 +271,26 @@
 int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
 {
 	struct ubi_work *wrk;
+	struct ubi_wl_entry *anchor;
 
 	spin_lock(&ubi->wl_lock);
+
+	/* Do we already have an anchor? */
+	if (ubi->fm_anchor) {
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	}
+
+	/* See if we can find an anchor PEB on the list of free PEBs */
+	anchor = ubi_wl_get_fm_peb(ubi, 1);
+	if (anchor) {
+		ubi->fm_anchor = anchor;
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	}
+
+	/* No luck, trigger wear leveling to produce a new anchor PEB */
+	ubi->fm_do_produce_anchor = 1;
 	if (ubi->wl_scheduled) {
 		spin_unlock(&ubi->wl_lock);
 		return 0;
@@ -294,7 +306,6 @@
 		return -ENOMEM;
 	}
 
-	wrk->anchor = 1;
 	wrk->func = &wear_leveling_worker;
 	__schedule_ubi_work(ubi, wrk);
 	return 0;
@@ -356,6 +367,11 @@
 	return_unused_pool_pebs(ubi, &ubi->fm_pool);
 	return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
 
+	if (ubi->fm_anchor) {
+		return_unused_peb(ubi, ubi->fm_anchor);
+		ubi->fm_anchor = NULL;
+	}
+
 	if (ubi->fm) {
 		for (i = 0; i < ubi->fm->used_blocks; i++)
 			kfree(ubi->fm->e[i]);
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/fastmap.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/fastmap.c
@@ -64,7 +64,7 @@
 		return 0;
 
 	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
-		if (test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {
+		if (!test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {
 			ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
 			ret = -EINVAL;
 		}
@@ -468,7 +468,9 @@
 			if (err == UBI_IO_FF_BITFLIPS)
 				scrub = 1;
 
-			add_aeb(ai, free, pnum, ec, scrub);
+			ret = add_aeb(ai, free, pnum, ec, scrub);
+			if (ret)
+				goto out;
 			continue;
 		} else if (err == 0 || err == UBI_IO_BITFLIPS) {
 			dbg_bld("Found non empty PEB:%i in pool", pnum);
@@ -638,8 +640,10 @@
 		if (fm_pos >= fm_size)
 			goto fail_bad;
 
-		add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum),
-			be32_to_cpu(fmec->ec), 0);
+		ret = add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum),
+			      be32_to_cpu(fmec->ec), 0);
+		if (ret)
+			goto fail;
 	}
 
 	/* read EC values from used list */
@@ -649,8 +653,10 @@
 		if (fm_pos >= fm_size)
 			goto fail_bad;
 
-		add_aeb(ai, &used, be32_to_cpu(fmec->pnum),
-			be32_to_cpu(fmec->ec), 0);
+		ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum),
+			      be32_to_cpu(fmec->ec), 0);
+		if (ret)
+			goto fail;
 	}
 
 	/* read EC values from scrub list */
@@ -660,8 +666,10 @@
 		if (fm_pos >= fm_size)
 			goto fail_bad;
 
-		add_aeb(ai, &used, be32_to_cpu(fmec->pnum),
-			be32_to_cpu(fmec->ec), 1);
+		ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum),
+			      be32_to_cpu(fmec->ec), 1);
+		if (ret)
+			goto fail;
 	}
 
 	/* read EC values from erase list */
@@ -671,8 +679,10 @@
 		if (fm_pos >= fm_size)
 			goto fail_bad;
 
-		add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum),
-			be32_to_cpu(fmec->ec), 1);
+		ret = add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum),
+			      be32_to_cpu(fmec->ec), 1);
+		if (ret)
+			goto fail;
 	}
 
 	ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
@@ -1137,7 +1147,7 @@
 	struct rb_node *tmp_rb;
 	int ret, i, j, free_peb_count, used_peb_count, vol_count;
 	int scrub_peb_count, erase_peb_count;
-	unsigned long *seen_pebs = NULL;
+	unsigned long *seen_pebs;
 
 	fm_raw = ubi->fm_buf;
 	memset(ubi->fm_buf, 0, ubi->fm_size);
@@ -1151,7 +1161,7 @@
 	dvbuf = new_fm_vbuf(ubi, UBI_FM_DATA_VOLUME_ID);
 	if (!dvbuf) {
 		ret = -ENOMEM;
-		goto out_kfree;
+		goto out_free_avbuf;
 	}
 
 	avhdr = ubi_get_vid_hdr(avbuf);
@@ -1160,7 +1170,7 @@
 	seen_pebs = init_seen(ubi);
 	if (IS_ERR(seen_pebs)) {
 		ret = PTR_ERR(seen_pebs);
-		goto out_kfree;
+		goto out_free_dvbuf;
 	}
 
 	spin_lock(&ubi->volumes_lock);
@@ -1328,7 +1338,7 @@
 	ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avbuf);
 	if (ret) {
 		ubi_err(ubi, "unable to write vid_hdr to fastmap SB!");
-		goto out_kfree;
+		goto out_free_seen;
 	}
 
 	for (i = 0; i < new_fm->used_blocks; i++) {
@@ -1350,7 +1360,7 @@
 		if (ret) {
 			ubi_err(ubi, "unable to write vid_hdr to PEB %i!",
 				new_fm->e[i]->pnum);
-			goto out_kfree;
+			goto out_free_seen;
 		}
 	}
 
@@ -1360,7 +1370,7 @@
 		if (ret) {
 			ubi_err(ubi, "unable to write fastmap to PEB %i!",
 				new_fm->e[i]->pnum);
-			goto out_kfree;
+			goto out_free_seen;
 		}
 	}
 
@@ -1370,10 +1380,13 @@
 	ret = self_check_seen(ubi, seen_pebs);
 	dbg_bld("fastmap written!");
 
-out_kfree:
-	ubi_free_vid_buf(avbuf);
-	ubi_free_vid_buf(dvbuf);
+out_free_seen:
 	free_seen(seen_pebs);
+out_free_dvbuf:
+	ubi_free_vid_buf(dvbuf);
+out_free_avbuf:
+	ubi_free_vid_buf(avbuf);
+
 out:
 	return ret;
 }
@@ -1540,14 +1553,6 @@
 		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);
@@ -1618,7 +1623,8 @@
 	}
 
 	spin_lock(&ubi->wl_lock);
-	tmp_e = ubi_wl_get_fm_peb(ubi, 1);
+	tmp_e = ubi->fm_anchor;
+	ubi->fm_anchor = NULL;
 	spin_unlock(&ubi->wl_lock);
 
 	if (old_fm) {
@@ -1670,6 +1676,9 @@
 	up_write(&ubi->work_sem);
 	up_write(&ubi->fm_protect);
 	kfree(old_fm);
+
+	ubi_ensure_anchor_pebs(ubi);
+
 	return ret;
 
 err:
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/ubi.h
+++ linux-ein-5.4.0/drivers/mtd/ubi/ubi.h
@@ -491,6 +491,8 @@
  * @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
+ * @fm_anchor: The next anchor PEB to use for fastmap
+ * @fm_do_produce_anchor: If true produce an anchor PEB in wl
  *
  * @used: RB-tree of used physical eraseblocks
  * @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -599,6 +601,8 @@
 	struct work_struct fm_work;
 	int fm_work_scheduled;
 	int fast_attach;
+	struct ubi_wl_entry *fm_anchor;
+	int fm_do_produce_anchor;
 
 	/* Wear-leveling sub-system's stuff */
 	struct rb_root used;
@@ -789,7 +793,6 @@
  * @vol_id: the volume ID on which this erasure is being performed
  * @lnum: the logical eraseblock number
  * @torture: if the physical eraseblock has to be tortured
- * @anchor: produce a anchor PEB to by used by fastmap
  *
  * The @func pointer points to the worker function. If the @shutdown argument is
  * not zero, the worker has to free the resources and exit immediately as the
@@ -805,7 +808,6 @@
 	int vol_id;
 	int lnum;
 	int torture;
-	int anchor;
 };
 
 #include "debug.h"
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/vmt.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/vmt.c
@@ -56,16 +56,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 */
@@ -103,7 +98,6 @@
 	vol->ref_count -= 1;
 	ubi_assert(vol->ref_count >= 0);
 	spin_unlock(&ubi->volumes_lock);
-	ubi_put_device(ubi);
 	return ret;
 }
 
@@ -315,7 +309,6 @@
 	ubi->volumes[vol_id] = NULL;
 	ubi->vol_count -= 1;
 	spin_unlock(&ubi->volumes_lock);
-	ubi_eba_destroy_table(eba_tbl);
 out_acc:
 	spin_lock(&ubi->volumes_lock);
 	ubi->rsvd_pebs -= vol->reserved_pebs;
@@ -471,7 +464,7 @@
 		for (i = 0; i < -pebs; i++) {
 			err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
 			if (err)
-				goto out_acc;
+				goto out_free;
 		}
 		spin_lock(&ubi->volumes_lock);
 		ubi->rsvd_pebs += pebs;
@@ -519,8 +512,10 @@
 		ubi->avail_pebs += pebs;
 		spin_unlock(&ubi->volumes_lock);
 	}
+	return err;
+
 out_free:
-	kfree(new_eba_tbl);
+	ubi_eba_destroy_table(new_eba_tbl);
 	return err;
 }
 
@@ -587,6 +582,7 @@
 	if (err) {
 		ubi_err(ubi, "cannot add character device for volume %d, error %d",
 			vol_id, err);
+		vol_release(&vol->dev);
 		return err;
 	}
 
@@ -597,15 +593,14 @@
 	vol->dev.groups = volume_dev_groups;
 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
 	err = device_register(&vol->dev);
-	if (err)
-		goto out_cdev;
+	if (err) {
+		cdev_del(&vol->cdev);
+		put_device(&vol->dev);
+		return err;
+	}
 
 	self_check_volumes(ubi);
 	return err;
-
-out_cdev:
-	cdev_del(&vol->cdev);
-	return err;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/wl.c
+++ linux-ein-5.4.0/drivers/mtd/ubi/wl.c
@@ -339,13 +339,6 @@
 		}
 	}
 
-	/* If no fastmap has been written and this WL entry can be used
-	 * as anchor PEB, hold it back and return the second best WL entry
-	 * such that fastmap can use the anchor PEB later. */
-	if (prev_e && !ubi->fm_disabled &&
-	    !ubi->fm && e->pnum < UBI_FM_MAX_START)
-		return prev_e;
-
 	return e;
 }
 
@@ -583,6 +576,7 @@
  * @vol_id: the volume ID that last used this PEB
  * @lnum: the last used logical eraseblock number for the PEB
  * @torture: if the physical eraseblock has to be tortured
+ * @nested: denotes whether the work_sem is already held
  *
  * This function returns zero in case of success and a %-ENOMEM in case of
  * failure.
@@ -656,9 +650,6 @@
 {
 	int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
 	int erase = 0, keep = 0, vol_id = -1, lnum = -1;
-#ifdef CONFIG_MTD_UBI_FASTMAP
-	int anchor = wrk->anchor;
-#endif
 	struct ubi_wl_entry *e1, *e2;
 	struct ubi_vid_io_buf *vidb;
 	struct ubi_vid_hdr *vid_hdr;
@@ -698,11 +689,7 @@
 	}
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
-	/* Check whether we need to produce an anchor PEB */
-	if (!anchor)
-		anchor = !anchor_pebs_available(&ubi->free);
-
-	if (anchor) {
+	if (ubi->fm_do_produce_anchor) {
 		e1 = find_anchor_wl_entry(&ubi->used);
 		if (!e1)
 			goto out_cancel;
@@ -719,6 +706,7 @@
 		self_check_in_wl_tree(ubi, e1, &ubi->used);
 		rb_erase(&e1->u.rb, &ubi->used);
 		dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum);
+		ubi->fm_do_produce_anchor = 0;
 	} else if (!ubi->scrub.rb_node) {
 #else
 	if (!ubi->scrub.rb_node) {
@@ -892,8 +880,11 @@
 
 	err = do_sync_erase(ubi, e1, vol_id, lnum, 0);
 	if (err) {
-		if (e2)
+		if (e2) {
+			spin_lock(&ubi->wl_lock);
 			wl_entry_destroy(ubi, e2);
+			spin_unlock(&ubi->wl_lock);
+		}
 		goto out_ro;
 	}
 
@@ -975,11 +966,11 @@
 	spin_lock(&ubi->wl_lock);
 	ubi->move_from = ubi->move_to = NULL;
 	ubi->move_to_put = ubi->wl_scheduled = 0;
+	wl_entry_destroy(ubi, e1);
+	wl_entry_destroy(ubi, e2);
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_free_vid_buf(vidb);
-	wl_entry_destroy(ubi, e1);
-	wl_entry_destroy(ubi, e2);
 
 out_ro:
 	ubi_ro_mode(ubi);
@@ -1051,7 +1042,6 @@
 		goto out_cancel;
 	}
 
-	wrk->anchor = 0;
 	wrk->func = &wear_leveling_worker;
 	if (nested)
 		__schedule_ubi_work(ubi, wrk);
@@ -1071,8 +1061,6 @@
  * __erase_worker - physical eraseblock erase worker function.
  * @ubi: UBI device description object
  * @wl_wrk: the work object
- * @shutdown: non-zero if the worker has to free memory and exit
- * because the WL sub-system is shutting down
  *
  * This function erases a physical eraseblock and perform torture testing if
  * needed. It also takes care about marking the physical eraseblock bad if
@@ -1093,8 +1081,15 @@
 	err = sync_erase(ubi, e, wl_wrk->torture);
 	if (!err) {
 		spin_lock(&ubi->wl_lock);
-		wl_tree_add(e, &ubi->free);
-		ubi->free_count++;
+
+		if (!ubi->fm_anchor && e->pnum < UBI_FM_MAX_START) {
+			ubi->fm_anchor = e;
+			ubi->fm_do_produce_anchor = 0;
+		} else {
+			wl_tree_add(e, &ubi->free);
+			ubi->free_count++;
+		}
+
 		spin_unlock(&ubi->wl_lock);
 
 		/*
@@ -1115,16 +1110,20 @@
 		int err1;
 
 		/* Re-schedule the LEB for erasure */
-		err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false);
+		err1 = schedule_erase(ubi, e, vol_id, lnum, 0, true);
 		if (err1) {
+			spin_lock(&ubi->wl_lock);
 			wl_entry_destroy(ubi, e);
+			spin_unlock(&ubi->wl_lock);
 			err = err1;
 			goto out_ro;
 		}
 		return err;
 	}
 
+	spin_lock(&ubi->wl_lock);
 	wl_entry_destroy(ubi, e);
+	spin_unlock(&ubi->wl_lock);
 	if (err != -EIO)
 		/*
 		 * If this is not %-EIO, we have no idea what to do. Scheduling
@@ -1240,6 +1239,18 @@
 retry:
 	spin_lock(&ubi->wl_lock);
 	e = ubi->lookuptbl[pnum];
+	if (!e) {
+		/*
+		 * This wl entry has been removed for some errors by other
+		 * process (eg. wear leveling worker), corresponding process
+		 * (except __erase_worker, which cannot concurrent with
+		 * ubi_wl_put_peb) will set ubi ro_mode at the same time,
+		 * just ignore this wl entry.
+		 */
+		spin_unlock(&ubi->wl_lock);
+		up_read(&ubi->fm_protect);
+		return 0;
+	}
 	if (e == ubi->move_from) {
 		/*
 		 * User is putting the physical eraseblock which was selected to
@@ -1636,6 +1647,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;
 		}
@@ -1882,6 +1906,9 @@
 	if (err)
 		goto out_free;
 
+#ifdef CONFIG_MTD_UBI_FASTMAP
+	ubi_ensure_anchor_pebs(ubi);
+#endif
 	return 0;
 
 out_free:
--- linux-ein-5.4.0.orig/drivers/mtd/ubi/wl.h
+++ linux-ein-5.4.0/drivers/mtd/ubi/wl.h
@@ -2,7 +2,6 @@
 #ifndef UBI_WL_H
 #define UBI_WL_H
 #ifdef CONFIG_MTD_UBI_FASTMAP
-static int anchor_pebs_available(struct rb_root *root);
 static void update_fastmap_work_fn(struct work_struct *wrk);
 static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root);
 static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);
--- linux-ein-5.4.0.orig/drivers/mxc/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/Kconfig
@@ -0,0 +1,43 @@
+# drivers/mxc/Kconfig
+
+if ARCH_MXC
+
+menu "MXC support drivers"
+
+config MXC_SIM
+	tristate "MXC SIM support"
+	default n
+	help
+	Say Y to get MXC SIM support.
+
+config MXC_IPU
+	bool "Image Processing Unit Driver"
+	select MXC_IPU_V3
+	help
+	  If you plan to use the Image Processing unit, say
+	  Y here. IPU is needed by Framebuffer and V4L2 drivers.
+
+# drivers common to MXC and MX8 go here:
+
+if ARM64
+source "drivers/mxc/hantro/Kconfig"
+source "drivers/mxc/hantro_845/Kconfig"
+source "drivers/mxc/hantro_845_h1/Kconfig"
+source "drivers/mxc/hantro_vc8000e/Kconfig"
+source "drivers/mxc/vpu_malone/Kconfig"
+source "drivers/mxc/vpu_windsor/Kconfig"
+source "drivers/mxc/xuvi/Kconfig"
+endif
+
+source "drivers/mxc/gpu-viv/Kconfig"
+source "drivers/mxc/vpu/Kconfig"
+source "drivers/mxc/sim/Kconfig"
+source "drivers/mxc/mlb/Kconfig"
+source "drivers/mxc/ipu3/Kconfig"
+source "drivers/mxc/hdmi-cec/Kconfig"
+source "drivers/mxc/mipi/Kconfig"
+
+endmenu
+
+endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/Makefile
+++ linux-ein-5.4.0/drivers/mxc/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_MXC_GPU_VIV) += gpu-viv/
+obj-$(CONFIG_MXC_HANTRO) += hantro/
+obj-$(CONFIG_MXC_HANTRO_845) += hantro_845/
+obj-$(CONFIG_MXC_HANTRO_845_H1) += hantro_845_h1/
+obj-$(CONFIG_MXC_HANTRO_VC8000E) += hantro_vc8000e/
+obj-$(CONFIG_MXC_VPU_MALONE) += vpu_malone/
+obj-$(CONFIG_MXC_VPU_WINDSOR) += vpu_windsor/
+obj-$(CONFIG_MXC_VPU) += vpu/
+obj-$(CONFIG_MXC_SIM) += sim/
+obj-$(CONFIG_MXC_MLB) += mlb/
+obj-$(CONFIG_MXC_IPU_V3) += ipu3/
+obj-$(CONFIG_MXC_HDMI_CEC) += hdmi-cec/
+obj-$(CONFIG_MXC_MIPI_CSI2) += mipi/
+obj-$(CONFIG_MXC_IMX_DMX_HW) += xuvi/
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/Kbuild
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/Kbuild
@@ -0,0 +1,332 @@
+##############################################################################
+#
+#    The MIT License (MIT)
+#
+#    Copyright (c) 2014 - 2020 Vivante 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
+#    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.
+#
+##############################################################################
+#
+#    The GPL License (GPL)
+#
+#    Copyright (C) 2014 - 2020 Vivante 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.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software Foundation,
+#    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+#
+#    Note: This software is released under dual MIT and GPL licenses. A
+#    recipient may use this file under the terms of either the MIT license or
+#    GPL License. If you wish to use only one license not the other, you can
+#    indicate your decision by deleting one of the above license notices in your
+#    version of this file.
+#
+##############################################################################
+
+
+#
+# Linux build file for kernel HAL driver.
+#
+AQROOT ?= $(srctree)/drivers/mxc/gpu-viv
+
+ifeq ($(CONFIG_MXC_GPU_VIV),)
+    CONFIG_MXC_GPU_VIV=m
+endif
+
+include $(AQROOT)/config
+
+soc_vendor    := $(firstword $(subst -, ,$(SOC_PLATFORM)))
+soc_board     := $(lastword  $(subst -, ,$(SOC_PLATFORM)))
+
+KERNEL_DIR ?= $(TOOL_DIR)/kernel
+
+OS_KERNEL_DIR   := hal/os/linux/kernel
+ARCH_KERNEL_DIR := hal/kernel/arch
+ARCH_VG_KERNEL_DIR := hal/kernel/archvg
+HAL_KERNEL_DIR  := hal/kernel
+TA_DIR          := hal/security_v1
+HOST := $(shell hostname)
+
+MODULE_NAME ?= galcore
+CUSTOMER_ALLOCATOR_OBJS    ?=
+ALLOCATOR_ARRAY_H_LOCATION ?= $(OS_KERNEL_DIR)/allocator/default/
+SOC_PLATFORM_LOCATION      ?= $(OS_KERNEL_DIR)/platform/$(soc_vendor)
+
+# Set common platform driver source
+SOC_PLATFORM_OBJS ?= $(SOC_PLATFORM_LOCATION)/gc_hal_kernel_platform_$(soc_board).o
+# Include platform config if exists.
+-include $(AQROOT)/$(SOC_PLATFORM_LOCATION)/gc_hal_kernel_platform_$(soc_board).config
+
+ifeq ($(CONFIG_KASAN),)
+EXTRA_CFLAGS += -Werror -Wno-implicit-fallthrough
+endif
+
+OBJS := $(OS_KERNEL_DIR)/gc_hal_kernel_device.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_linux.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_math.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_os.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_debug.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_debugfs.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_allocator.o \
+        $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_user_memory.o \
+        $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_dma.o \
+        $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_gfp.o \
+        $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_reserved_mem.o \
+        $(OS_KERNEL_DIR)/gc_hal_kernel_driver.o
+
+# Source files for soc platform board
+OBJS += $(SOC_PLATFORM_OBJS)
+
+ifneq ($(CONFIG_DMA_SHARED_BUFFER),)
+OBJS += $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_dmabuf.o
+endif
+
+ifneq ($(CONFIG_IOMMU_SUPPORT),)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_iommu.o
+endif
+
+ifneq ($(CONFIG_DRM),)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_drm.o
+endif
+
+OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_db.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_event.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_power.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_security_v1.o
+
+OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_context.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_func.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_func_flop_reset.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_async_fe.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_mc_fe.o \
+        $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_waitlink_fe.o
+
+ifeq ($(VIVANTE_ENABLE_3D), 1)
+OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_recorder.o
+endif
+
+ifneq ($(CONFIG_ARM64),)
+ifeq ($(CONFIG_ANDROID),)
+VIVANTE_ENABLE_VG=0
+endif
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG), 1)
+OBJS +=\
+          $(HAL_KERNEL_DIR)/gc_hal_kernel_vg.o\
+          $(HAL_KERNEL_DIR)/gc_hal_kernel_command_vg.o\
+          $(HAL_KERNEL_DIR)/gc_hal_kernel_interrupt_vg.o\
+          $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu_vg.o\
+          $(ARCH_VG_KERNEL_DIR)/gc_hal_kernel_hardware_command_vg.o\
+          $(ARCH_VG_KERNEL_DIR)/gc_hal_kernel_hardware_vg.o
+endif
+
+ifneq ($(CONFIG_SYNC),)
+EXTRA_CFLAGS += -Idrivers/staging/android
+EXTRA_CFLAGS += -DgcdLINUX_SYNC_FILE=1
+
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_sync.o
+else
+  ifneq ($(CONFIG_SYNC_FILE),)
+  EXTRA_CFLAGS += -DgcdLINUX_SYNC_FILE=1
+  OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_sync.o
+  endif
+endif
+
+ifeq ($(SECURITY), 1)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_security_channel.o \
+        $(HAL_KERNEL_DIR)/gc_hal_kernel_security.o
+endif
+
+ifneq ($(CUSTOMER_ALLOCATOR_OBJS),)
+OBJS += $(CUSTOMER_ALLOCATOR_OBJS)
+endif
+
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_security_channel_emulator.o \
+        $(TA_DIR)/gc_hal_ta.o \
+        $(TA_DIR)/gc_hal_ta_hardware.o \
+        $(TA_DIR)/gc_hal_ta_mmu.o \
+        $(TA_DIR)/os/emulator/gc_hal_ta_emulator.o
+
+ifeq ($(KERNELRELEASE), )
+
+.PHONY: all clean install
+
+# Define targets.
+all:
+	@$(MAKE) V=$(V) ARCH=$(ARCH_TYPE) -C $(KERNEL_DIR) M=`pwd` modules
+
+clean:
+	@rm -rf $(OBJS)
+	@rm -rf modules.order Module.symvers .tmp_versions
+	@find $(AQROOT) -name ".gc_*.cmd" | xargs rm -f
+
+install: all
+	@mkdir -p $(SDK_DIR)/drivers
+	@cp $(MODULE_NAME).ko $(SDK_DIR)/drivers
+
+else
+
+
+EXTRA_CFLAGS += -DLINUX -DDRIVER
+
+ifeq ($(FLAREON),1)
+EXTRA_CFLAGS += -DFLAREON
+endif
+
+ifeq ($(DEBUG), 1)
+EXTRA_CFLAGS += -DDBG=1 -DDEBUG -D_DEBUG
+else
+EXTRA_CFLAGS += -DDBG=0
+endif
+
+ifeq ($(NO_DMA_COHERENT), 1)
+EXTRA_CFLAGS += -DNO_DMA_COHERENT
+endif
+
+ifeq ($(CONFIG_DOVE_GPU), 1)
+EXTRA_CFLAGS += -DCONFIG_DOVE_GPU=1
+endif
+
+ifneq ($(USE_PLATFORM_DRIVER), 0)
+EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=1
+else
+EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=0
+endif
+
+EXTRA_CFLAGS += -DVIVANTE_PROFILER=1
+EXTRA_CFLAGS += -DVIVANTE_PROFILER_CONTEXT=1
+
+ifeq ($(ENABLE_GPU_CLOCK_BY_DRIVER), 1)
+EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=1
+else
+EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=0
+endif
+
+ifeq ($(USE_NEW_LINUX_SIGNAL), 1)
+EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=1
+else
+EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=0
+endif
+
+ifeq ($(USE_LINUX_PCIE), 1)
+EXTRA_CFLAGS += -DUSE_LINUX_PCIE=1
+else
+EXTRA_CFLAGS += -DUSE_LINUX_PCIE=0
+endif
+
+ifeq ($(CACHE_FUNCTION_UNIMPLEMENTED), 1)
+EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=1
+else
+EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=0
+endif
+
+ifeq ($(VIVANTE_ENABLE_3D),0)
+EXTRA_CFLAGS += -DgcdENABLE_3D=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_3D=1
+endif
+
+ifeq ($(VIVANTE_ENABLE_2D),0)
+EXTRA_CFLAGS += -DgcdENABLE_2D=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_2D=1
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG),0)
+EXTRA_CFLAGS += -DgcdENABLE_VG=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_VG=1
+endif
+
+ifeq ($(USE_BANK_ALIGNMENT), 1)
+    EXTRA_CFLAGS += -DgcdENABLE_BANK_ALIGNMENT=1
+    ifneq ($(BANK_BIT_START), 0)
+	        ifneq ($(BANK_BIT_END), 0)
+	            EXTRA_CFLAGS += -DgcdBANK_BIT_START=$(BANK_BIT_START)
+	            EXTRA_CFLAGS += -DgcdBANK_BIT_END=$(BANK_BIT_END)
+	        endif
+    endif
+
+    ifneq ($(BANK_CHANNEL_BIT), 0)
+        EXTRA_CFLAGS += -DgcdBANK_CHANNEL_BIT=$(BANK_CHANNEL_BIT)
+    endif
+endif
+
+ifeq ($(FPGA_BUILD), 1)
+EXTRA_CFLAGS += -DgcdFPGA_BUILD=1
+else
+EXTRA_CFLAGS += -DgcdFPGA_BUILD=0
+endif
+
+ifeq ($(SECURITY), 1)
+EXTRA_CFLAGS += -DgcdSECURITY=1
+endif
+
+ifneq ($(CONFIG_DRM), )
+EXTRA_CFLAGS += -DgcdENABLE_DRM=$(VIVANTE_ENABLE_DRM)
+else
+EXTRA_CFLAGS += -DgcdENABLE_DRM=0
+endif
+
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/inc
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/arch
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/inc
+EXTRA_CFLAGS += -I$(AQROOT)/hal/os/linux/kernel
+EXTRA_CFLAGS += -I$(AQROOT)/$(ALLOCATOR_ARRAY_H_LOCATION)
+EXTRA_CFLAGS += -I$(AQROOT)/hal/security_v1/
+EXTRA_CFLAGS += -I$(AQROOT)/$(SOC_PLATFORM_LOCATION)
+
+ifneq ($(CONFIG_ARM), )
+EXTRA_CFLAGS += -Iarch/arm/mm
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG), 1)
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/archvg
+endif
+
+EXTRA_CFLAGS += -DHOST=\"$(HOST)\"
+
+EXTRA_CFLAGS += -DgcdENABLE_TRUST_APPLICATION=1
+
+obj-$(CONFIG_MXC_GPU_VIV) = $(MODULE_NAME).o
+
+$(MODULE_NAME)-objs  = $(OBJS)
+
+endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/Kconfig
@@ -0,0 +1,10 @@
+menu "MXC Vivante GPU support"
+
+config MXC_GPU_VIV
+	tristate "MXC Vivante GPU support"
+	default y
+
+	---help---
+         Say Y to get the GPU driver support.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/config
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/config
@@ -0,0 +1,71 @@
+##############################################################################
+#
+#    The MIT License (MIT)
+#
+#    Copyright (c) 2014 - 2020 Vivante 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
+#    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.
+#
+##############################################################################
+#
+#    The GPL License (GPL)
+#
+#    Copyright (C) 2014 - 2020 Vivante 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.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software Foundation,
+#    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+#
+#    Note: This software is released under dual MIT and GPL licenses. A
+#    recipient may use this file under the terms of either the MIT license or
+#    GPL License. If you wish to use only one license not the other, you can
+#    indicate your decision by deleting one of the above license notices in your
+#    version of this file.
+#
+##############################################################################
+
+
+ARCH_TYPE                         ?= arm
+SDK_DIR                           ?= $(AQROOT)/build/sdk
+VIVANTE_ENABLE_3D                 ?= 1
+VIVANTE_ENABLE_2D                 ?= 1
+VIVANTE_ENABLE_VG                 ?= 1
+VIVANTE_ENABLE_DRM                ?= 1
+NO_DMA_COHERENT                   ?= 0
+USE_PLATFORM_DRIVER               ?= 1
+ENABLE_GPU_CLOCK_BY_DRIVER        ?= 0
+CACHE_FUNCTION_UNIMPLEMENTED      ?= 0
+USE_BANK_ALIGNMENT                ?= 1
+BANK_BIT_START                    ?= 13
+BANK_BIT_END                      ?= 15
+BANK_CHANNEL_BIT                  ?= 12
+SECURITY                          ?= 0
+SOC_PLATFORM                      ?= freescale-imx
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c
@@ -0,0 +1,5465 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+#include "gc_hal_kernel_buffer.h"
+
+/******************************************************************************\
+******************************** Debugging Macro *******************************
+\******************************************************************************/
+
+/* Zone used for header/footer. */
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+
+/******************************************************************************\
+************************** Context State Buffer Helpers ************************
+\******************************************************************************/
+
+#define _STATE(reg)                                                            \
+    _State(\
+        Context, index, \
+        reg ## _Address >> 2, \
+        reg ## _ResetValue, \
+        reg ## _Count, \
+        gcvFALSE, gcvFALSE                                                     \
+        )
+
+#define _STATE_COUNT(reg, count)                                               \
+    _State(\
+        Context, index, \
+        reg ## _Address >> 2, \
+        reg ## _ResetValue, \
+        count, \
+        gcvFALSE, gcvFALSE                                                     \
+        )
+
+#define _STATE_COUNT_OFFSET(reg, offset, count)                                \
+    _State(\
+        Context, index, \
+        (reg ## _Address >> 2) + offset, \
+        reg ## _ResetValue, \
+        count, \
+        gcvFALSE, gcvFALSE                                                     \
+        )
+
+#define _STATE_MIRROR_COUNT(reg, mirror, count)                                \
+    _StateMirror(\
+        Context, \
+        reg ## _Address >> 2, \
+        count, \
+        mirror ## _Address >> 2                                                \
+        )
+
+#define _STATE_HINT(reg)                                                       \
+    _State(\
+        Context, index, \
+        reg ## _Address >> 2, \
+        reg ## _ResetValue, \
+        reg ## _Count, \
+        gcvFALSE, gcvTRUE                                                      \
+        )
+
+#define _STATE_HINT_BLOCK(reg, block, count)                                   \
+    _State(\
+        Context, index, \
+        (reg ## _Address >> 2) + (block << reg ## _BLK), \
+        reg ## _ResetValue, \
+        count, \
+        gcvFALSE, gcvTRUE                                                      \
+        )
+
+#define _STATE_COUNT_OFFSET_HINT(reg, offset, count)                           \
+    _State(\
+        Context, index, \
+        (reg ## _Address >> 2) + offset, \
+        reg ## _ResetValue, \
+        count, \
+        gcvFALSE, gcvTRUE                                                      \
+        )
+
+#define _STATE_X(reg)                                                          \
+    _State(\
+        Context, index, \
+        reg ## _Address >> 2, \
+        reg ## _ResetValue, \
+        reg ## _Count, \
+        gcvTRUE, gcvFALSE                                                      \
+        )
+
+#define _STATE_INIT_VALUE(reg, value)                                          \
+    _State(\
+        Context, index, \
+        reg ## _Address >> 2, \
+        value, \
+        reg ## _Count, \
+        gcvFALSE, gcvFALSE                                                     \
+        )
+
+#define _STATE_INIT_VALUE_BLOCK(reg, value, block, count)                      \
+    _State(\
+        Context, index, \
+        (reg ## _Address >> 2) + (block << reg ## _BLK), \
+        value, \
+        count, \
+        gcvFALSE, gcvFALSE                                                     \
+        )
+
+
+#define _CLOSE_RANGE()                                                         \
+    _TerminateStateBlock(Context, index)
+
+#define _ENABLE(reg, field)                                                    \
+    do                                                                         \
+    {                                                                          \
+        if (gcmVERIFYFIELDVALUE(data, reg, MASK_ ## field, ENABLED))           \
+        {                                                                      \
+            enable |= gcmFIELDMASK(reg, field);                                \
+        }                                                                      \
+    }                                                                          \
+    while (gcvFALSE)
+
+#define _BLOCK_COUNT(reg)                                                      \
+    ((reg ## _Count) >> (reg ## _BLK))
+
+
+/******************************************************************************\
+*********************** Support Functions and Definitions **********************
+\******************************************************************************/
+
+#define gcdSTATE_MASK \
+    (gcmSETFIELDVALUE(0, AQ_COMMAND_NOP_COMMAND, OPCODE, NOP) | 0xC0FFEE)
+
+#if gcdENABLE_3D
+static gctUINT32
+_TerminateStateBlock(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Index
+    )
+{
+    gctUINT32_PTR buffer;
+    gctUINT32 align;
+
+    /* Determine if we need alignment. */
+    align = (Index & 1) ? 1 : 0;
+
+    /* Address correct index. */
+    buffer = (Context->buffer == gcvNULL)
+        ? gcvNULL
+        : Context->buffer->logical;
+
+    /* Flush the current state block; make sure no pairing with the states
+       to follow happens. */
+    if (align && (buffer != gcvNULL))
+    {
+        buffer[Index] = 0xDEADDEAD;
+    }
+
+    /* Reset last address. */
+    Context->lastAddress = ~0U;
+
+    /* Return alignment requirement. */
+    return align;
+}
+#endif
+
+
+#if gcdENABLE_3D
+static gctUINT32
+_FlushPipe(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Index,
+    IN gcePIPE_SELECT Pipe
+    )
+{
+    gctUINT32 flushSlots;
+    gctBOOL txCacheFix;
+    gctBOOL fcFlushStall;
+    gctBOOL iCacheInvalidate;
+    gctBOOL halti5;
+    gctBOOL snapPages;
+    gctBOOL hwTFB;
+    gctBOOL blt;
+    gctBOOL peTSFlush;
+    gctBOOL multiCluster;
+
+    txCacheFix
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_TEX_CACHE_FLUSH_FIX);
+
+    fcFlushStall
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_FC_FLUSH_STALL);
+
+    iCacheInvalidate
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE);
+
+    halti5
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI5);
+
+    snapPages
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SNAPPAGE_CMD_FIX) &&
+          gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SNAPPAGE_CMD);
+
+    hwTFB
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HW_TFB);
+
+    blt
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_BLT_ENGINE);
+    multiCluster
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_MULTI_CLUSTER);
+
+    peTSFlush
+        = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX);
+
+    flushSlots = blt ? 10 : 6;
+
+    if (Pipe == gcvPIPE_3D)
+    {
+        if (!txCacheFix)
+        {
+            /* Semaphore stall */
+            flushSlots += blt ? 8 : 4;
+        }
+
+        /* VST cache */
+        flushSlots += 2;
+    }
+
+    if (fcFlushStall)
+    {
+        /* Flush tile status cache. */
+        flushSlots += blt ? ((!peTSFlush) ? 14 :10) : 6;
+    }
+
+    if (iCacheInvalidate && !halti5)
+    {
+        flushSlots += blt ? 16 : 12;
+    }
+
+    if (hwTFB)
+    {
+        flushSlots += 2;
+    }
+
+    /* Snap pages */
+    if (snapPages)
+    {
+        flushSlots += 2;
+    }
+
+    if (Context->buffer != gcvNULL)
+    {
+        gctUINT32_PTR buffer;
+
+        /* Address correct index. */
+        buffer = Context->buffer->logical + Index;
+
+        if (Pipe == gcvPIPE_3D && !txCacheFix)
+        {
+            if (blt)
+            {
+                /* Semaphore from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+            else
+            {
+                /* Semaphore from FE to PE. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to PE. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+        }
+
+        /* Flush the current pipe. */
+        *buffer++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        *buffer++
+            = (Pipe == gcvPIPE_2D)
+                ?
+   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                :   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                  | (multiCluster ?
+ 0 : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+        if (hwTFB)
+        {
+             *buffer++
+                 = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                 | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x7003) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                 | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+             *buffer++
+                 = 0x1;
+        }
+
+        /* Flush VST in separate cmd. */
+        if (Pipe == gcvPIPE_3D)
+        {
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+        }
+
+        /* Semaphore from FE to PE. */
+        if (blt)
+        {
+            /* Semaphore from FE to BLT. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            /* Stall from FE to BLT. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+        else
+        {
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            /* Stall from FE to PE. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+        }
+
+        if (fcFlushStall)
+        {
+            if (!peTSFlush && blt)
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+            else
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+
+            /* Semaphore from FE to PE. */
+            if (blt)
+            {
+                /* Semaphore from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+            else
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to PE. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+        }
+
+        if (iCacheInvalidate && !halti5)
+        {
+            /* Invalidate I$ after pipe is stalled */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+
+            /* Semaphore from FE to PE. */
+            if (blt)
+            {
+                /* Semaphore from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to BLT. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+            else
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to PE. */
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+        }
+
+        if (snapPages)
+        {
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x13 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x04 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+            *buffer++
+                = 0;
+        }
+    }
+
+    /* Number of slots taken by flushing pipe. */
+    return flushSlots;
+}
+#endif
+
+#if gcdENABLE_3D
+static gctUINT32
+_SemaphoreStall(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Index
+    )
+{
+    gctBOOL blt = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_BLT_ENGINE);
+    if (Context->buffer != gcvNULL)
+    {
+        gctUINT32_PTR buffer;
+
+        /* Address correct index. */
+        buffer = Context->buffer->logical + Index;
+
+        if (blt)
+        {
+            /* Semaphore from FE to BLT. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            /* Stall from FE to BLT. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+        else
+        {
+            /* Semaphore from FE to PE. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+            /* Stall from FE to PE. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            *buffer
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+        }
+    }
+
+    /* Semaphore/stall takes 4 slots. */
+    return (blt ? 8 : 4);
+}
+#endif
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gctUINT32
+_SwitchPipe(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Index,
+    IN gcePIPE_SELECT Pipe
+    )
+{
+    gctUINT32 slots = 2;
+
+    if (Context->buffer != gcvNULL)
+    {
+        gctUINT32_PTR buffer;
+
+        /* Address correct index. */
+        buffer = Context->buffer->logical + Index;
+
+        /* LoadState(AQPipeSelect, 1), pipe. */
+        *buffer++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer
+            = (Pipe == gcvPIPE_2D)
+                ? 0x1
+                : 0x0;
+    }
+
+    Context->pipeSelectBytes = slots * gcmSIZEOF(gctUINT32);
+
+    return slots;
+}
+#endif
+
+#if gcdENABLE_3D
+static gctUINT32
+_State(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Index,
+    IN gctUINT32 Address,
+    IN gctUINT32 Value,
+    IN gctUINT32 Size,
+    IN gctBOOL FixedPoint,
+    IN gctBOOL Hinted
+    )
+{
+    gctUINT32_PTR buffer;
+    gctUINT32 align;
+    gctUINT32 i;
+
+    /* Determine if we need alignment. */
+    align = (Index & 1) ? 1 : 0;
+
+    /* Address correct index. */
+    buffer = (Context->buffer == gcvNULL)
+        ? gcvNULL
+        : Context->buffer->logical;
+
+    if ((buffer == gcvNULL) && (Address + Size > Context->maxState))
+    {
+        /* Determine maximum state. */
+        Context->maxState = Address + Size;
+    }
+
+    if (buffer == gcvNULL)
+    {
+        /* Update number of states. */
+        Context->numStates += Size;
+    }
+
+    /* Do we need a new entry? */
+    if ((Address != Context->lastAddress) || (FixedPoint != Context->lastFixed))
+    {
+        if (buffer != gcvNULL)
+        {
+            if (align)
+            {
+                /* Add filler. */
+                buffer[Index++] = 0xDEADDEAD;
+            }
+
+            /* LoadState(Address, Count). */
+            gcmkASSERT((Index & 1) == 0);
+
+            if (FixedPoint)
+            {
+                buffer[Index]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+            }
+            else
+            {
+                buffer[Index]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+            }
+
+            /* Walk all the states. */
+            for (i = 0; i < (gctUINT32)Size; i += 1)
+            {
+                /* Set state to uninitialized value. */
+                buffer[Index + 1 + i] = Value;
+
+                /* Set index in state mapping table. */
+                Context->map[Address + i].index = (gctUINT)Index + 1 + i;
+            }
+        }
+
+        /* Save information for this LoadState. */
+        Context->lastIndex   = (gctUINT)Index;
+        Context->lastAddress = Address + (gctUINT32)Size;
+        Context->lastSize    = Size;
+        Context->lastFixed   = FixedPoint;
+
+        /* Return size for load state. */
+        return align + 1 + Size;
+    }
+
+    /* Append this state to the previous one. */
+    if (buffer != gcvNULL)
+    {
+        /* Update last load state. */
+        buffer[Context->lastIndex] =
+            ((((gctUINT32) (buffer[Context->lastIndex])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Context->lastSize + Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        /* Walk all the states. */
+        for (i = 0; i < (gctUINT32)Size; i += 1)
+        {
+            /* Set state to uninitialized value. */
+            buffer[Index + i] = Value;
+
+            /* Set index in state mapping table. */
+            Context->map[Address + i].index = (gctUINT)Index + i;
+        }
+    }
+
+    /* Update last address and size. */
+    Context->lastAddress += (gctUINT32)Size;
+    Context->lastSize    += Size;
+
+    /* Return number of slots required. */
+    return Size;
+}
+
+static gctUINT32
+_StateMirror(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Address,
+    IN gctUINT32 Size,
+    IN gctUINT32 AddressMirror
+    )
+{
+    gctUINT32 i;
+
+    /* Process when buffer is set. */
+    if (Context->buffer != gcvNULL)
+    {
+        /* Walk all states. */
+        for (i = 0; i < Size; i++)
+        {
+            /* Copy the mapping address. */
+            Context->map[Address + i].index =
+                Context->map[AddressMirror + i].index;
+        }
+    }
+
+    /* Return the number of required maps. */
+    return Size;
+}
+
+static void
+_UpdateUnifiedReg(
+    IN gckCONTEXT Context,
+    IN gctUINT32 Address,
+    IN gctUINT32 Size,
+    IN gctUINT32 Count
+    )
+{
+    gctUINT base;
+    gctUINT nopCount;
+    gctUINT32_PTR nop;
+    gcsCONTEXT_PTR buffer;
+    gcsSTATE_MAP_PTR map;
+    gctUINT i;
+
+    /* Get the current context buffer. */
+    buffer = Context->buffer;
+
+    /* Get the state map. */
+    map = Context->map;
+
+    base = map[Address].index;
+
+    if (Count > 1024)
+    {
+        buffer->logical[base - 1]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1024) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        buffer->logical[base + 1024 + 1]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Count - 1024) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address + 1024) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        /* Determine the number of NOP commands. */
+        nopCount = (Size / 2) - (Count / 2);
+        /* Determine the location of the first NOP. */
+        nop = &buffer->logical[base + (Count | 1) + 2];
+
+        /* Fill the unused space with NOPs. */
+        for (i = 0; i < nopCount; i += 1)
+        {
+            if (nop >= buffer->logical + Context->totalSize)
+            {
+                break;
+            }
+
+            /* Generate a NOP command. */
+            *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            /* Advance. */
+            nop += 2;
+        }
+    }
+    else
+    {
+        buffer->logical[base - 1]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        /* Determine the number of NOP commands. */
+        nopCount = (Size / 2) - (Count / 2) + Size / 1024;
+
+        /* Determine the location of the first NOP. */
+        nop = &buffer->logical[base + (Count | 1)];
+
+        /* Fill the unused space with NOPs. */
+        for (i = 0; i < nopCount; i += 1)
+        {
+            if (nop >= buffer->logical + Context->totalSize)
+            {
+                break;
+            }
+
+            /* Generate a NOP command. */
+            *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            /* Advance. */
+            nop += 2;
+        }
+    }
+}
+#endif
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+
+static gceSTATUS
+_InitializeNoShaderAndPixelEngine(
+    IN gckCONTEXT Context
+    )
+{
+    gctUINT32_PTR buffer;
+    gctUINT32 index;
+
+#if gcdENABLE_3D
+    gctBOOL halti5;
+    gctBOOL hasSecurity;
+    gctBOOL hasRobustness;
+    gctBOOL multiCluster;
+    gctUINT clusterAliveMask;
+#endif
+
+    gckHARDWARE hardware;
+
+    gcmkHEADER();
+
+    hardware = Context->hardware;
+
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Reset the buffer index. */
+    index = 0;
+
+    /* Reset the last state address. */
+    Context->lastAddress = ~0U;
+
+    /* Get the buffer pointer. */
+    buffer = (Context->buffer == gcvNULL)
+        ? gcvNULL
+        : Context->buffer->logical;
+
+
+    /**************************************************************************/
+    /* Build 2D states. *******************************************************/
+
+
+#if gcdENABLE_3D
+    /**************************************************************************/
+    /* Build 3D states. *******************************************************/
+
+    halti5 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI5);
+    hasSecurity = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SECURITY);
+    hasRobustness = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_ROBUSTNESS);
+    multiCluster = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_CLUSTER);
+    clusterAliveMask = hardware->identity.clusterAvailMask & hardware->options.userClusterMask;
+
+    /* Store the 3D entry index. */
+    Context->entryOffset3D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+    /* Switch to 3D pipe. */
+    index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+    if (multiCluster)
+    {
+        index += _State(Context, index, (0x03910 >> 2) + (0 << 2), ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (clusterAliveMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))), 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03908 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))), 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Current context pointer. */
+#if gcdDEBUG
+    index += _State(Context, index, 0x03850 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+#endif
+
+    index += _FlushPipe(Context, index, gcvPIPE_3D);
+
+    /* Global states. */
+    if (hasSecurity)
+    {
+        index += _State(Context, index, 0x03900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+        index += _State(Context, index, 0x03904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        gctUINT32 uscControl = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1))))))) << (0 ?
+ 20:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16)));
+        index += _State(Context, index, 0x03888 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x038C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+
+        uscControl |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (hardware->options.uscL1CacheRatio) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        if (multiCluster)
+        {
+            uscControl |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1))))))) << (0 ?
+ 11:8))) | (((gctUINT32) ((gctUINT32) (hardware->options.uscAttribCacheRatio) & ((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8)));
+        }
+        index += _State(Context, index, 0x03884 >> 2, uscControl, 1, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        index += _State(Context, index, 0x03820 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03828 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0382C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03834 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03854 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _CLOSE_RANGE();
+
+    /* Memory Controller */
+    index += _State(Context, index, 0x01654 >> 2, 0x00200000, 1, gcvFALSE, gcvFALSE);
+
+    if (hasSecurity || hasRobustness)
+    {
+        index += _State(Context, index, 0x001AC >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))), 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Semaphore/stall. */
+    index += _SemaphoreStall(Context, index);
+#endif
+
+    /**************************************************************************/
+    /* Link to another address. ***********************************************/
+
+    Context->linkIndex3D = (gctUINT)index;
+
+    if (buffer != gcvNULL)
+    {
+        buffer[index + 0]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        buffer[index + 1]
+            = 0;
+    }
+
+    index += 2;
+
+    /* Store the end of the context buffer. */
+    Context->bufferSize = index * gcmSIZEOF(gctUINT32);
+
+
+    /**************************************************************************/
+    /* Pipe switch for the case where neither 2D nor 3D are used. *************/
+
+    /* Store the 3D entry index. */
+    Context->entryOffsetXDFrom2D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+    /* Switch to 3D pipe. */
+    index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+    /* Store the location of the link. */
+    Context->linkIndexXD = (gctUINT)index;
+
+    if (buffer != gcvNULL)
+    {
+        buffer[index + 0]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        buffer[index + 1]
+            = 0;
+    }
+
+    index += 2;
+
+
+    /**************************************************************************/
+    /* Save size for buffer. **************************************************/
+
+    Context->totalSize = index * gcmSIZEOF(gctUINT32);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+}
+
+static gceSTATUS
+_InitializeContextBuffer(
+    IN gckCONTEXT Context
+    )
+{
+    gctUINT32_PTR buffer = gcvNULL;
+    gctUINT32 index;
+
+#if gcdENABLE_3D
+    gctBOOL halti0, halti1, halti2, halti3, halti4, halti5;
+    gctUINT i;
+    gctUINT vertexUniforms, fragmentUniforms;
+    gctBOOL unifiedUniform;
+    gctBOOL hasGS, hasTS;
+    gctBOOL genericAttrib;
+    gctBOOL hasICache;
+    gctBOOL hasICachePrefetch;
+    gctUINT numRT = 0;
+    gctUINT numSamplers = 32;
+    gctBOOL hasTXdesc;
+    gctBOOL hasSecurity;
+    gctBOOL hasRobustness;
+    gctBOOL multiCluster;
+    gctBOOL smallBatch;
+    gctBOOL multiCoreBlockSetCfg2;
+    gctUINT clusterAliveMask;
+    gctBOOL hasPSCSThrottle;
+    gctBOOL hasMsaaFragOperation;
+    gctBOOL newGPipe;
+#endif
+
+    gckHARDWARE hardware;
+
+    gcmkHEADER();
+
+    hardware = Context->hardware;
+
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    if (!hardware->options.hasShader)
+    {
+        return _InitializeNoShaderAndPixelEngine(Context);
+    }
+
+    /* Reset the buffer index. */
+    index = 0;
+
+    /* Reset the last state address. */
+    Context->lastAddress = ~0U;
+
+    /* Get the buffer pointer. */
+    buffer = (Context->buffer == gcvNULL)
+        ? gcvNULL
+        : Context->buffer->logical;
+
+
+    /**************************************************************************/
+    /* Build 2D states. *******************************************************/
+
+
+#if gcdENABLE_3D
+    /**************************************************************************/
+    /* Build 3D states. *******************************************************/
+
+    halti0 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI0);
+    halti1 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI1);
+    halti2 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI2);
+    halti3 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI3);
+    halti4 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI4);
+    halti5 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI5);
+    hasGS  = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_GEOMETRY_SHADER);
+    hasTS  = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TESSELLATION);
+    genericAttrib = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_GENERIC_ATTRIB);
+    hasICache = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE);
+    hasTXdesc = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_DESCRIPTOR);
+    hasSecurity = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SECURITY);
+    hasRobustness = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_ROBUSTNESS);
+    hasICachePrefetch = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SH_INSTRUCTION_PREFETCH);
+    multiCluster = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_CLUSTER);
+    smallBatch = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SMALL_BATCH) && hardware->options.smallBatch;
+    multiCoreBlockSetCfg2 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2);
+    clusterAliveMask = hardware->identity.clusterAvailMask & hardware->options.userClusterMask;
+    hasPSCSThrottle = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PSCS_THROTTLE);
+    hasMsaaFragOperation = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MSAA_FRAGMENT_OPERATION);
+    newGPipe = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_NEW_GPIPE);
+
+    /* Multi render target. */
+    if (Context->hardware->identity.chipModel == gcv880 &&
+        Context->hardware->identity.chipRevision == 0x5124 &&
+        Context->hardware->identity.customerID == 0x103)
+    {
+        numRT = 16;
+    }
+    else if (halti2 ||
+            ((Context->hardware->identity.chipModel == gcv900) &&
+            (Context->hardware->identity.chipRevision == 0x5250)))
+    {
+        numRT = 8;
+    }
+    else if (halti0)
+    {
+        numRT = 4;
+    }
+    else
+    {
+        numRT = 1;
+    }
+
+    if (hasGS && hasTS)
+    {
+        numSamplers = 80;
+    }
+
+    /* Query how many uniforms can support. */
+    gcmCONFIGUREUNIFORMS2(Context->hardware->identity.chipModel,
+                         Context->hardware->identity.chipRevision,
+                         halti5,
+                         smallBatch,
+                         Context->hardware->identity.numConstants,
+                         unifiedUniform,
+                         vertexUniforms,
+                         fragmentUniforms);
+
+#if !gcdENABLE_UNIFIED_CONSTANT
+    if (Context->hardware->identity.numConstants > 256)
+    {
+        unifiedUniform = gcvTRUE;
+    }
+    else
+    {
+        unifiedUniform = gcvFALSE;
+    }
+#endif
+
+    /* Store the 3D entry index. */
+    Context->entryOffset3D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+    /* Switch to 3D pipe. */
+    index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+    if (multiCluster)
+    {
+        index += _State(Context, index, (0x03910 >> 2) + (0 << 2), ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (clusterAliveMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))), 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03908 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))), 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Current context pointer. */
+#if gcdDEBUG
+    index += _State(Context, index, 0x03850 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+#endif
+
+    index += _FlushPipe(Context, index, gcvPIPE_3D);
+
+    /* Global states. */
+    if (hasSecurity)
+    {
+        index += _State(Context, index, 0x03900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+        index += _State(Context, index, 0x03904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _State(Context, index, 0x03814 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE);
+    index += _CLOSE_RANGE();
+    index += _State(Context, index, 0x03818 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0381C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti5)
+    {
+        gctUINT32 uscControl = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1))))))) << (0 ?
+ 20:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 20:16) - (0 ?
+ 20:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16)));
+        index += _State(Context, index, 0x03888 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x038C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+
+        uscControl |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (hardware->options.uscL1CacheRatio) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        if (multiCluster)
+        {
+            uscControl |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1))))))) << (0 ?
+ 11:8))) | (((gctUINT32) ((gctUINT32) (hardware->options.uscAttribCacheRatio) & ((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8)));
+        }
+        index += _State(Context, index, 0x03884 >> 2, uscControl, 1, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        index += _State(Context, index, 0x03820 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03828 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0382C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03834 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03854 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasGS)
+    {
+        index += _State(Context, index, 0x0388C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _State(Context, index, 0x0384C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    /* Front End states. */
+    if (halti5)
+    {
+        index += _State(Context, index, 0x17800 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+        index += _State(Context, index, 0x007C4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x007D0 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x007D8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x17A80 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+        if (genericAttrib || newGPipe)
+        {
+            index += _State(Context, index, 0x17880 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17900 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17980 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17A00 >> 2, 0x3F800000, 32, gcvFALSE, gcvFALSE);
+        }
+    }
+    else
+    {
+        index += _State(Context, index, 0x00600 >> 2, 0x00000000, (halti0 ? 16 : 12), gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+        if (genericAttrib)
+        {
+            index += _State(Context, index, 0x006C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x00700 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x00740 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x00780 >> 2, 0x3F800000, 16, gcvFALSE, gcvFALSE);
+        }
+    }
+
+    if (halti2 || (Context->hardware->identity.streamCount > 8))
+    {
+        index += _State(Context, index, 0x14600 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14640 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14680 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+    }
+    else if (Context->hardware->identity.streamCount > 1)
+    {
+        index += _State(Context, index, 0x00680 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x006A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        index += _State(Context, index, 0x0064C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x00650 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    }
+    index += _State(Context, index, 0x00644 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x00648 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    if (halti1)
+    {
+        index += _State(Context, index, 0x00678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0067C >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+    }
+    index += _CLOSE_RANGE();
+
+    if (hasRobustness)
+    {
+        index += _State(Context, index, 0x146C0 >> 2, 0x00000000, 16, gcvFALSE, gcvTRUE);
+        index += _CLOSE_RANGE();
+        index += _State(Context, index, 0x007F8 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _CLOSE_RANGE();
+    }
+
+    /* WD */
+    if (multiCluster)
+    {
+        index += _State(Context, index, 0x18404 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))), 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x008B8 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (smallBatch ?
+ 0x0 : 0x1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (smallBatch ?
+ 0x0 : 0x1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), 1, gcvFALSE, gcvFALSE);
+
+        index += _State(Context, index, 0x15600 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        /* This register is programed by all chips, which program all DECODE_SELECT as VS
+        ** except SAMPLER_DECODE_SELECT.
+        */
+        index += _State(Context, index, 0x00860 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasICache)
+    {
+        /* I-Cache states. */
+        index += _State(Context, index, 0x00868 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0086C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0304C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01028 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+
+        if (hasICachePrefetch)
+        {
+            if (halti5)
+            {
+                index += _State(Context, index, 0x15604 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+                index += _State(Context, index, 0x01094 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+            }
+            else
+            {
+                index += _State(Context, index, 0x00890 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+                index += _State(Context, index, 0x0104C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+            }
+            index += _CLOSE_RANGE();
+        }
+    }
+
+    if (multiCluster)
+    {
+        index += _State(Context, index, 0x010A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Vertex Shader states. */
+    index += _State(Context, index, 0x00804 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00808 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))), 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0080C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00830 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x00898 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x008A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00870 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x008A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x008C0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x008E0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        index += _State(Context, index, 0x00810 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00820 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+    }
+
+    if (multiCluster)
+    {
+        index += _State(Context, index, 0x007FC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x15608 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _CLOSE_RANGE();
+
+    /* GS */
+    if (hasGS)
+    {
+        index += _State(Context, index, 0x01100 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01104 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01108 >> 2, 0x01000001, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0110C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01110 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01114 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x0111C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01140 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01144 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01148 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0114C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01154 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01120 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+    }
+
+    /* TCS & TES */
+    if (hasTS)
+    {
+        index += _State(Context, index, 0x007C0 >> 2, 0x00000003, 1, gcvFALSE, gcvFALSE);
+
+        index += _State(Context, index, 0x14A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A40 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A00 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A08 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x14A10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A20 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A44 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14A4C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+        index += _CLOSE_RANGE();
+
+        index += _State(Context, index, 0x14B18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B0C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x14B14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B40 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14B34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+        index += _State(Context, index, 0x14B00 >> 2, 0x00040000, 1, gcvFALSE, gcvFALSE);
+
+    }
+
+    index += _CLOSE_RANGE();
+
+    /* TFB */
+    if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HW_TFB))
+    {
+        index += _State(Context, index, 0x1C000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x1C008 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x1C040 >> 2) + (0 << 4), 0x00000000, 4, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x1C080 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x1C0C0 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x1C100 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x1C800 >> 2, 0x00000000, 128*4, gcvFALSE, gcvFALSE);
+
+        index += _State(Context, index, 0x1C014 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _CLOSE_RANGE();
+
+    }
+
+    /* Primitive Assembly states. */
+    index += _State(Context, index, 0x00A00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00A04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A0C >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00A10 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A1C >> 2, 0x3F000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A28 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A30 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A38 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A3C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A80 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A84 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00A8C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00A88 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x00AA8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00A90 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+    }
+    else
+    {
+        index += _State(Context, index, 0x00A40 >> 2, 0x00000000, Context->hardware->identity.varyingsCount, gcvFALSE, gcvFALSE);
+    }
+
+    if (multiCluster)
+    {
+        index += _State(Context, index, 0x00AAC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _State(Context, index, 0x03A00 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x03A04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x03A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (multiCoreBlockSetCfg2)
+    {
+        index += _State(Context, index, 0x03A0C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x03A10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Setup states. */
+    index += _State(Context, index, 0x00C00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00C04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00C08 >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00C0C >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00C10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00C14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00C18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00C1C >> 2, 0x42000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00C20 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+    index += _State(Context, index, 0x00C24 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+
+    /* Raster states. */
+    index += _State(Context, index, 0x00E00 >> 2, 0x000000F1, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E10 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E40 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E08 >> 2, ((((gctUINT32) (0x17000031)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (smallBatch ?
+ 0x0 : 0x1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))), 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00E20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti2)
+    {
+        index += _State(Context, index, 0x00E0C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x00E34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+
+    /* Pixel Shader states. */
+    index += _State(Context, index, 0x01004 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0100C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01010 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01030 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01034 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti2)
+    {
+        index += _State(Context, index, 0x01040 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+    }
+
+    if (numRT == 16)
+    {
+        index += _State(Context, index, 0x0102C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x010C8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x010CC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+    else if (numRT == 8)
+    {
+        index += _State(Context, index, 0x0102C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01038 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasMsaaFragOperation)
+    {
+        index += _State(Context, index, 0x01054 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01060 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x01080 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01058 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01098 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasPSCSThrottle)
+    {
+        index += _State(Context, index, 0x0109C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _CLOSE_RANGE();
+
+    /* Texture states. */
+    if (hasTXdesc)
+    {
+        /* Texture descriptor states */
+        index += _State(Context, index, 0x14C40 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+        if (smallBatch)
+        {
+            index += _State(Context, index, 0x010B0 >> 2, numSamplers, 1, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x010B4 >> 2, numSamplers, 1, gcvFALSE, gcvFALSE);
+
+            index += _State(Context, index, 0x16000 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x16200 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x16400 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x16600 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x16800 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+            index += _State(Context, index, (0x15800 >> 2) + (0 << 0), 0x00000000, numSamplers, gcvFALSE, gcvTRUE);
+            index += _State(Context, index, 0x15A00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+            index += _CLOSE_RANGE();
+        }
+        else
+        {
+            index += _State(Context, index, 0x16C00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x16E00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17000 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17200 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x17400 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+            index += _State(Context, index, (0x15C00 >> 2) + (0 << 0), 0x00000000, numSamplers, gcvFALSE, gcvTRUE);
+            index += _State(Context, index, 0x15E00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+            index += _CLOSE_RANGE();
+
+            _StateMirror(Context, 0x16000 >> 2, numSamplers , 0x16C00 >> 2);
+            _StateMirror(Context, 0x16200 >> 2, numSamplers , 0x16E00 >> 2);
+            _StateMirror(Context, 0x16400 >> 2, numSamplers , 0x17000 >> 2);
+            _StateMirror(Context, 0x16600 >> 2, numSamplers , 0x17200 >> 2);
+            _StateMirror(Context, 0x16800 >> 2, numSamplers , 0x17400 >> 2);
+            _StateMirror(Context, 0x15800 >> 2, numSamplers , 0x15C00 >> 2);
+            _StateMirror(Context, 0x15A00 >> 2, numSamplers , 0x15E00 >> 2);
+        }
+    }
+    else
+    {
+        index += _State(Context, index, 0x02000 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02040 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02080 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x020C0 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02100 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02140 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02180 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x021C0 >> 2, 0x00321000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02200 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x02240 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, (0x02400 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02440 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02480 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x024C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02500 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02540 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02580 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x025C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02600 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02640 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02680 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x026C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02700 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x02740 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+        index += _CLOSE_RANGE();
+
+        if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TEXTURE_LINEAR))
+        {
+            /*
+             * Linear stride LODn will overwrite LOD0 on GC880,GC2000.
+             * And only LOD0 is valid for this register.
+             */
+            gctUINT count = halti1 ? 14 : 1;
+
+            for (i = 0; i < 12; i += 1)
+            {
+                index += _State(Context, index, (0x02C00 >> 2) + i * 16, 0x00000000, count, gcvFALSE, gcvFALSE);
+            }
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SUPPORT_GCREGTX))
+        {
+            gctUINT texBlockCount;
+            gctUINT gcregTXLogSizeResetValue;
+
+            /* Enable the integer filter pipe for all texture samplers
+               so that the floating point filter clock will shut off until
+               we start using the floating point filter.
+            */
+            gcregTXLogSizeResetValue = ((((gctUINT32) (0x00000000)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ?
+ 29:29))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29)));
+
+            /* New texture block. */
+            index += _State(Context, index, 0x10000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10100 >> 2, gcregTXLogSizeResetValue, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10380 >> 2, 0x00321000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10400 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10480 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+
+            if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_FILTER))
+            {
+                index += _State(Context, index, 0x12000 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE);
+                index += _State(Context, index, 0x12400 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE);
+            }
+
+            texBlockCount = ((512) >> (4));
+
+            for (i = 0; i < texBlockCount; i += 1)
+            {
+                index += _State(Context, index, (0x10800 >> 2) + (i << 4), 0x00000000, 14, gcvFALSE, gcvTRUE);
+            }
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_TEX_BASELOD))
+        {
+            index += _State(Context, index, 0x10700 >> 2, 0x00000F00, 32, gcvFALSE, gcvFALSE);
+        }
+
+        if (halti3 ||
+            gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_SUPPORT_DEC))
+        {
+            index += _State(Context, index, 0x10780 >> 2, 0x00030000, 32, gcvFALSE, gcvFALSE);
+        }
+
+        if (halti4)
+        {
+            index += _State(Context, index, 0x11200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x11280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_FRAC_PRECISION_6BIT))
+        {
+            index += _State(Context, index, 0x11000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x11080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x11100 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x11180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x11300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+        }
+
+        /* ASTC */
+        if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TEXTURE_ASTC))
+        {
+            index += _State(Context, index, 0x10500 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10580 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10600 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x10680 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+        }
+    }
+
+    if (halti3)
+    {
+        index += _State(Context, index, 0x14C00 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+    }
+
+    /* Thread walker states. */
+    index += _State(Context, index, 0x00900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00908 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0090C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00910 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00914 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00918 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x00924 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0091C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SHADER_ENHANCEMENTS2))
+    {
+        index += _State(Context, index, 0x00940 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00944 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00948 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0094C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00950 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00954 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x00958 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0095C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00960 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _CLOSE_RANGE();
+
+    /* VS/PS Start/End PC register */
+    if (halti5)
+    {
+        index += _State(Context, index, 0x00874 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x008BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0087C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x01090 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+    }
+    else if (hasICache)
+    {
+        /* New Shader instruction PC registers(20bit). */
+        index += _State(Context, index, 0x00874 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00878 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x0087C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00880 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+    }
+    else
+    {
+        if (Context->hardware->identity.instructionCount <= 256)
+        {
+            /* old shader instruction PC registers (12bit)*/
+            index += _State(Context, index, 0x00800 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x00838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+            index += _CLOSE_RANGE();
+
+            index += _State(Context, index, 0x01000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x01018 >> 2, 0x01000000, 1, gcvFALSE, gcvFALSE);
+            index += _CLOSE_RANGE();
+        }
+        else
+        {
+            /* New Shader instruction PC registers (16bit) */
+            index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+            index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE);
+            index += _CLOSE_RANGE();
+        }
+    }
+
+
+    if (!hasICachePrefetch)
+    {
+        /* This unified one need SELECT bit to steer */
+        if (Context->hardware->identity.instructionCount > 1024)
+        {
+            for (i = 0;
+                 i < Context->hardware->identity.instructionCount << 2;
+                 i += 256 << 2
+                 )
+            {
+                index += _State(Context, index, (0x20000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+                index += _CLOSE_RANGE();
+            }
+        }
+        /* This unified one is steered by base adddress, it's automatical. */
+        else if (Context->hardware->identity.instructionCount > 256)
+        {
+            /* VS instruction memory. */
+            for (i = 0;
+                 i < Context->hardware->identity.instructionCount << 2;
+                 i += 256 << 2
+                 )
+            {
+                index += _State(Context, index, (0x0C000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+                index += _CLOSE_RANGE();
+            }
+
+            _StateMirror(Context, 0x08000 >> 2, Context->hardware->identity.instructionCount << 2 , 0x0C000 >> 2);
+        }
+        /* if (Context->hardware->identity.instructionCount <= 256). This is non-unified one. */
+        else
+        {
+            index += _State(Context, index, 0x04000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE);
+            index += _CLOSE_RANGE();
+            index += _State(Context, index, 0x06000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE);
+            index += _CLOSE_RANGE();
+        }
+    }
+
+    if (unifiedUniform)
+    {
+        gctINT numConstants = Context->hardware->identity.numConstants;
+
+        /* Base Offset register */
+        index += _State(Context, index, 0x01024 >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x00864 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+
+        if (smallBatch)
+        {
+            index += _State(Context, index, 0x010AC >> 2, numConstants, 1, gcvFALSE, gcvFALSE);
+        }
+
+        for (i = 0;
+             numConstants > 0;
+             i += 256 << 2,
+             numConstants -= 256
+             )
+        {
+            if (halti5)
+            {
+                if (numConstants >= 256)
+                {
+                    if (smallBatch)
+                    {
+                        index += _State(Context, index, (0x34000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+                    }
+                    else
+                    {
+                        index += _State(Context, index, (0x36000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+                    }
+                }
+                else
+                {
+                    if (smallBatch)
+                    {
+                        index += _State(Context, index, (0x34000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE);
+                    }
+                    else
+                    {
+                        index += _State(Context, index, (0x36000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE);
+                    }
+                }
+                index += _CLOSE_RANGE();
+            }
+            else
+            {
+                if (numConstants >= 256)
+                {
+                    index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+                }
+                else
+                {
+                    index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE);
+                }
+
+                index += _CLOSE_RANGE();
+            }
+        }
+
+        if (halti5 && !smallBatch)
+        {
+            _StateMirror(Context, 0x34000 >> 2, Context->hardware->identity.numConstants << 2 , 0x36000 >> 2);
+        }
+    }
+#if gcdENABLE_UNIFIED_CONSTANT
+    else
+#endif
+    {
+        index += _State(Context, index, 0x05000 >> 2, 0x00000000, vertexUniforms * 4, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x07000 >> 2, 0x00000000, fragmentUniforms * 4, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti1)
+    {
+        index += _State(Context, index, 0x00884 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x008B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Store the index of the "XD" entry. */
+    Context->entryOffsetXDFrom3D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+
+    /* Pixel Engine states. */
+    index += _State(Context, index, 0x01400 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01404 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01408 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0140C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01414 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01418 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0141C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01420 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01424 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01428 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x0142C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01434 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01454 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01458 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x014A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x014A8 >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x014AC >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+
+    if(gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALF_FLOAT_PIPE) )
+    {
+        index += _State(Context, index, 0x014B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x014B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+    index += _State(Context, index, 0x014A4 >> 2, 0x000E400C, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01580 >> 2, 0x00000000, 3, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x014B8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+    if (halti3)
+    {
+        index += _State(Context, index, 0x0103C >> 2, 0x76543210, 1, gcvFALSE, gcvFALSE);
+    }
+
+    index += _State(Context, index, (0x01460 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+
+    if (Context->hardware->identity.pixelPipes == 1)
+    {
+        index += _State(Context, index, 0x01430 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x01410 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    }
+
+    if (Context->hardware->identity.pixelPipes > 1 || halti0)
+    {
+        index += _State(Context, index, (0x01480 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+    }
+
+    for (i = 0; i < 3; i++)
+    {
+        index += _State(Context, index, (0x01500 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+    }
+
+    if (numRT == 16)
+    {
+        for (i = 0; i < 15; i++)
+        {
+            index += _State(Context, index, (0x17C00 >> 2) + (i << 0), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+        }
+        index += _State(Context, index, 0x17C40 >> 2, 0x00000000, 15, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x17C80 >> 2, 0x03012000, 15, gcvFALSE, gcvFALSE);
+    }
+    else if (numRT == 8)
+    {
+        for (i = 0; i < 7; i++)
+        {
+          index += _State(Context, index, (0x14800 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+        }
+        index += _State(Context, index, 0x14900 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+    }
+
+
+    if (halti3)
+    {
+        index += _State(Context, index, 0x014BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti4)
+    {
+        index += _State(Context, index, 0x014C0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasGS)
+    {
+        index += _State(Context, index, 0x038A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+    }
+
+    if (halti5)
+    {
+        index += _State(Context, index, 0x14920 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14940 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14960 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x14980 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x149A0 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+    }
+
+    if (hasRobustness)
+    {
+        index += _State(Context, index, 0x149C0 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, 0x014C4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    }
+
+    /* Memory Controller */
+    index += _State(Context, index, 0x01654 >> 2, 0x00200000, 1, gcvFALSE, gcvFALSE);
+
+    index += _CLOSE_RANGE();
+    index += _State(Context, index, 0x01658 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x0165C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x01660 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01664 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x01668 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x0166C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x016A4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x016AC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x016A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01720 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+    index += _State(Context, index, 0x01740 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+    index += _State(Context, index, 0x01760 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+
+
+    if (halti2)
+    {
+        index += _State(Context, index, 0x01780 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, 0x016BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, (0x017A0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, (0x017C0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x017E0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE);
+        index += _State(Context, index, (0x01A00 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, (0x01A20 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+        index += _State(Context, index, (0x01A40 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+    }
+
+    index += _CLOSE_RANGE();
+
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_BUG_FIXES18))
+    {
+        index += _State(Context, index, 0x03860 >> 2, 0x6, 1, gcvFALSE, gcvFALSE);
+        index += _CLOSE_RANGE();
+    }
+
+    if (halti3)
+    {
+        index += _State(Context, index, 0x01A80 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+        index += _CLOSE_RANGE();
+    }
+
+    if (hasSecurity || hasRobustness)
+    {
+        index += _State(Context, index, 0x001AC >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))), 1, gcvFALSE, gcvFALSE);
+    }
+
+    /* Semaphore/stall. */
+    index += _SemaphoreStall(Context, index);
+#endif
+
+    /**************************************************************************/
+    /* Link to another address. ***********************************************/
+
+    Context->linkIndex3D = (gctUINT)index;
+
+    if (buffer != gcvNULL)
+    {
+        buffer[index + 0]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        buffer[index + 1]
+            = 0;
+    }
+
+    index += 2;
+
+    /* Store the end of the context buffer. */
+    Context->bufferSize = index * gcmSIZEOF(gctUINT32);
+
+
+    /**************************************************************************/
+    /* Pipe switch for the case where neither 2D nor 3D are used. *************/
+
+    /* Store the 3D entry index. */
+    Context->entryOffsetXDFrom2D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+    /* Switch to 3D pipe. */
+    index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+    /* Store the location of the link. */
+    Context->linkIndexXD = (gctUINT)index;
+
+    if (buffer != gcvNULL)
+    {
+        buffer[index + 0]
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        buffer[index + 1]
+            = 0;
+    }
+
+    index += 2;
+
+
+    /**************************************************************************/
+    /* Save size for buffer. **************************************************/
+
+    Context->totalSize = index * gcmSIZEOF(gctUINT32);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+#endif
+
+static gceSTATUS
+_DestroyContext(
+    IN gckCONTEXT Context
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (Context != gcvNULL)
+    {
+        gcsCONTEXT_PTR bufferHead;
+
+        /* Free context buffers. */
+        for (bufferHead = Context->buffer; Context->buffer != gcvNULL;)
+        {
+            /* Get a shortcut to the current buffer. */
+            gcsCONTEXT_PTR buffer = Context->buffer;
+
+            /* Get the next buffer. */
+            gcsCONTEXT_PTR next = buffer->next;
+
+            /* Last item? */
+            if (next == bufferHead)
+            {
+                next = gcvNULL;
+            }
+
+            /* Destroy the signal. */
+            if (buffer->signal != gcvNULL)
+            {
+                /* Wait until the context buffer becomes available;
+                   this avoid GPU hang due to context command corruption */
+                gcmkONERROR(gckOS_WaitSignal(
+                    Context->os, buffer->signal, gcvFALSE, gcvINFINITE
+                ));
+
+                gcmkONERROR(gckOS_DestroySignal(
+                    Context->os, buffer->signal
+                    ));
+
+                buffer->signal = gcvNULL;
+            }
+
+            /* Free state delta map. */
+            if (buffer->logical != gcvNULL)
+            {
+                gckKERNEL kernel = Context->hardware->kernel;
+
+#if gcdCAPTURE_ONLY_MODE
+                gceDATABASE_TYPE dbType;
+                gctUINT32 processID;
+#endif
+
+                /* End cpu access. */
+                gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                    kernel,
+                    buffer->videoMem,
+                    0,
+                    gcvFALSE,
+                    gcvFALSE
+                    ));
+
+                /* Synchronized unlock. */
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                    kernel,
+                    buffer->videoMem,
+                    0,
+                    gcvNULL
+                    ));
+
+#if gcdCAPTURE_ONLY_MODE
+                /* Encode surface type and pool to database type. */
+                dbType = gcvDB_VIDEO_MEMORY
+                       | (gcvVIDMEM_TYPE_GENERIC << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+                       | (buffer->videoMem->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+                gcmkONERROR(gckOS_GetProcessID(&processID));
+
+                gcmkONERROR(
+                    gckKERNEL_RemoveProcessDB(kernel,
+                        processID,
+                        dbType,
+                        buffer->videoMem));
+#endif
+
+                /* Free video memory. */
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                    kernel,
+                    buffer->videoMem
+                    ));
+
+                buffer->logical = gcvNULL;
+            }
+
+            /* Free context buffer. */
+            gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, buffer));
+
+            /* Remove from the list. */
+            Context->buffer = next;
+        }
+
+        /* Mark the gckCONTEXT object as unknown. */
+        Context->object.type = gcvOBJ_UNKNOWN;
+
+        /* Free the gckCONTEXT object. */
+        gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context));
+    }
+
+OnError:
+    return status;
+}
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gceSTATUS
+_AllocateContextBuffer(
+    IN gckCONTEXT Context,
+    IN gcsCONTEXT_PTR Buffer
+    )
+{
+    gceSTATUS status;
+    gckKERNEL kernel = Context->hardware->kernel;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gctSIZE_T totalSize = Context->totalSize;
+    gctUINT32 allocFlag = 0;
+
+#if gcdCAPTURE_ONLY_MODE
+    gceDATABASE_TYPE dbType;
+    gctUINT32 processID;
+#endif
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+    /* Allocate video memory node for command buffers. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+        kernel,
+        64,
+        gcvVIDMEM_TYPE_COMMAND,
+        allocFlag,
+        &totalSize,
+        &pool,
+        &Buffer->videoMem
+        ));
+
+#if gcdCAPTURE_ONLY_MODE
+    gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, Buffer->videoMem, &Context->buffer->handle));
+
+    /* Encode surface type and pool to database type. */
+    dbType = gcvDB_VIDEO_MEMORY
+           | (gcvVIDMEM_TYPE_GENERIC << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+           | (pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    /* Record in process db. */
+    gcmkONERROR(
+            gckKERNEL_AddProcessDB(kernel,
+                                   processID,
+                                   dbType,
+                                   Buffer->videoMem,
+                                   gcvNULL,
+                                   totalSize));
+#endif
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+        kernel,
+        Buffer->videoMem,
+        &Buffer->address
+        ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        kernel,
+        Buffer->videoMem,
+        gcvFALSE,
+        gcvFALSE,
+        (gctPOINTER *)&Buffer->logical
+        ));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+#endif
+
+/******************************************************************************\
+**************************** Context Management API ****************************
+\******************************************************************************/
+
+/******************************************************************************\
+**
+**  gckCONTEXT_Construct
+**
+**  Construct a new gckCONTEXT object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Current process ID.
+**
+**      gckHARDWARE Hardware
+**          Pointer to gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gckCONTEXT * Context
+**          Pointer to a variable thet will receive the gckCONTEXT object
+**          pointer.
+*/
+#if (gcdENABLE_3D || gcdENABLE_2D)
+gceSTATUS
+gckCONTEXT_Construct(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 ProcessID,
+    OUT gckCONTEXT * Context
+    )
+{
+    gceSTATUS status;
+    gckCONTEXT context = gcvNULL;
+    gctUINT32 allocationSize;
+    gctUINT i;
+    gctPOINTER pointer = gcvNULL;
+
+    gcmkHEADER_ARG("Os=%p Hardware=%p", Os, Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Context != gcvNULL);
+
+
+    /**************************************************************************/
+    /* Allocate and initialize basic fields of gckCONTEXT. ********************/
+
+    /* The context object size. */
+    allocationSize = gcmSIZEOF(struct _gckCONTEXT);
+
+    /* Allocate the object. */
+    gcmkONERROR(gckOS_Allocate(
+        Os, allocationSize, &pointer
+        ));
+
+    context = pointer;
+
+    /* Reset the entire object. */
+    gcmkONERROR(gckOS_ZeroMemory(context, allocationSize));
+
+    /* Initialize the gckCONTEXT object. */
+    context->object.type = gcvOBJ_CONTEXT;
+    context->os          = Os;
+    context->hardware    = Hardware;
+
+
+#if !gcdENABLE_3D
+    context->entryPipe = gcvPIPE_2D;
+    context->exitPipe  = gcvPIPE_2D;
+#elif gcdCMD_NO_2D_CONTEXT
+    context->entryPipe = gcvPIPE_3D;
+    context->exitPipe  = gcvPIPE_3D;
+#else
+    context->entryPipe
+        = (((((gctUINT32) (context->hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) )
+            ? gcvPIPE_2D
+            : gcvPIPE_3D;
+    context->exitPipe = gcvPIPE_3D;
+#endif
+
+    /* Get the command buffer requirements. */
+    gcmkONERROR(gckHARDWARE_QueryCommandBuffer(
+        Hardware,
+        gcvENGINE_RENDER,
+        &context->alignment,
+        &context->reservedHead,
+        gcvNULL
+        ));
+
+    /**************************************************************************/
+    /* Get the size of the context buffer. ************************************/
+
+    gcmkONERROR(_InitializeContextBuffer(context));
+
+    if (context->maxState > 0)
+    {
+        /**************************************************************************/
+        /* Allocate and reset the state mapping table. ****************************/
+        if (context->hardware->kernel->command->stateMap == gcvNULL)
+        {
+            /* Allocate the state mapping table. */
+            gcmkONERROR(gckOS_Allocate(
+                Os,
+                gcmSIZEOF(gcsSTATE_MAP) * context->maxState,
+                &pointer
+                ));
+
+            context->map = pointer;
+
+            /* Zero the state mapping table. */
+            gcmkONERROR(gckOS_ZeroMemory(
+                context->map, gcmSIZEOF(gcsSTATE_MAP) * context->maxState
+                ));
+
+            context->hardware->kernel->command->stateMap = pointer;
+        }
+        else
+        {
+            context->map = context->hardware->kernel->command->stateMap;
+        }
+    }
+
+    /**************************************************************************/
+    /* Allocate the context and state delta buffers. **************************/
+
+    for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i += 1)
+    {
+        /* Allocate a context buffer. */
+        gcsCONTEXT_PTR buffer;
+
+        /* Allocate the context buffer structure. */
+        gcmkONERROR(gckOS_Allocate(
+            Os,
+            gcmSIZEOF(gcsCONTEXT),
+            &pointer
+            ));
+
+        buffer = pointer;
+
+        /* Reset the context buffer structure. */
+        gcmkVERIFY_OK(gckOS_ZeroMemory(
+            buffer, gcmSIZEOF(gcsCONTEXT)
+            ));
+
+        /* Append to the list. */
+        if (context->buffer == gcvNULL)
+        {
+            buffer->next    = buffer;
+            context->buffer = buffer;
+        }
+        else
+        {
+            buffer->next          = context->buffer->next;
+            context->buffer->next = buffer;
+        }
+
+        /* Set the number of delta in the order of creation. */
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+        buffer->num = i;
+#endif
+
+        /* Create the busy signal. */
+        gcmkONERROR(gckOS_CreateSignal(
+            Os, gcvFALSE, &buffer->signal
+            ));
+
+        /* Set the signal, buffer is currently not busy. */
+        gcmkONERROR(gckOS_Signal(
+            Os, buffer->signal, gcvTRUE
+            ));
+
+        /* Create a new physical context buffer. */
+        gcmkONERROR(_AllocateContextBuffer(
+            context, buffer
+            ));
+
+        /* Set gckEVENT object pointer. */
+        buffer->eventObj = Hardware->kernel->eventObj;
+
+        /* Set the pointers to the LINK commands. */
+        if (context->linkIndex2D != 0)
+        {
+            buffer->link2D = &buffer->logical[context->linkIndex2D];
+        }
+
+        if (context->linkIndex3D != 0)
+        {
+            buffer->link3D = &buffer->logical[context->linkIndex3D];
+        }
+
+        if (context->linkIndexXD != 0)
+        {
+            gctPOINTER xdLink;
+            gctUINT32 xdEntryAddress;
+            gctUINT32 xdEntrySize;
+            gctUINT32 linkBytes;
+
+            /* Determine LINK parameters. */
+            xdLink
+                = &buffer->logical[context->linkIndexXD];
+
+            xdEntryAddress
+                = buffer->address
+                + context->entryOffsetXDFrom3D;
+
+            xdEntrySize
+                = context->bufferSize
+                - context->entryOffsetXDFrom3D;
+
+            /* Query LINK size. */
+            gcmkONERROR(gckWLFE_Link(
+                Hardware, gcvNULL, 0, 0, &linkBytes, gcvNULL, gcvNULL
+                ));
+
+            /* Generate a LINK. */
+            gcmkONERROR(gckWLFE_Link(
+                Hardware,
+                xdLink,
+                xdEntryAddress,
+                xdEntrySize,
+                &linkBytes,
+                gcvNULL,
+                gcvNULL
+                ));
+        }
+    }
+
+
+    /**************************************************************************/
+    /* Initialize the context buffers. ****************************************/
+
+    /* Initialize the current context buffer. */
+    gcmkONERROR(_InitializeContextBuffer(context));
+
+    /* Make all created contexts equal. */
+    {
+        gcsCONTEXT_PTR currContext, tempContext;
+
+        /* Set the current context buffer. */
+        currContext = context->buffer;
+
+        /* Get the next context buffer. */
+        tempContext = currContext->next;
+
+        /* Loop through all buffers. */
+        while (tempContext != currContext)
+        {
+            if (tempContext == gcvNULL)
+            {
+                gcmkONERROR(gcvSTATUS_NOT_FOUND);
+            }
+
+            /* Copy the current context. */
+            gckOS_MemCopy(
+                tempContext->logical,
+                currContext->logical,
+                context->totalSize
+                );
+
+            /* Get the next context buffer. */
+            tempContext = tempContext->next;
+        }
+    }
+
+    /* Return pointer to the gckCONTEXT object. */
+    *Context = context;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Context=0x%08X", *Context);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back on error. */
+    gcmkVERIFY_OK(_DestroyContext(context));
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+#endif
+
+/******************************************************************************\
+**
+**  gckCONTEXT_Destroy
+**
+**  Destroy a gckCONTEXT object.
+**
+**  INPUT:
+**
+**      gckCONTEXT Context
+**          Pointer to an gckCONTEXT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCONTEXT_Destroy(
+    IN gckCONTEXT Context
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Context=%p", Context);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+    /* Destroy the context and all related objects. */
+    status = _DestroyContext(Context);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return status;
+}
+
+/******************************************************************************\
+**
+**  gckCONTEXT_Update
+**
+**  Merge all pending state delta buffers into the current context buffer.
+**
+**  INPUT:
+**
+**      gckCONTEXT Context
+**          Pointer to an gckCONTEXT object.
+**
+**      gctUINT32 ProcessID
+**          Current process ID.
+**
+**      gcsSTATE_DELTA_PTR StateDelta
+**          Pointer to the state delta.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCONTEXT_Update(
+    IN gckCONTEXT Context,
+    IN gctUINT32 ProcessID,
+    IN gcsSTATE_DELTA_PTR StateDelta
+    )
+{
+#if gcdENABLE_3D
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsSTATE_DELTA _stateDelta;
+    gckKERNEL kernel;
+    gcsCONTEXT_PTR buffer;
+    gcsSTATE_MAP_PTR map;
+    gctBOOL needCopy = gcvFALSE;
+    gcsSTATE_DELTA_PTR uDelta = gcvNULL;
+    gcsSTATE_DELTA_PTR kDelta = gcvNULL;
+    gcsSTATE_DELTA_RECORD_PTR record;
+    gcsSTATE_DELTA_RECORD_PTR recordArray = gcvNULL;
+    gctUINT elementCount;
+    gctUINT address;
+    gctUINT32 mask;
+    gctUINT32 data;
+    gctUINT index;
+    gctUINT i, j;
+    gctUINT32 dirtyRecordArraySize = 0;
+
+    gcmkHEADER_ARG(
+        "Context=%p ProcessID=%d StateDelta=%p",
+        Context, ProcessID, StateDelta
+        );
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+    /* Get a shortcut to the kernel object. */
+    kernel = Context->hardware->kernel;
+
+    /* Check wehther we need to copy the structures or not. */
+    gcmkONERROR(gckOS_QueryNeedCopy(Context->os, ProcessID, &needCopy));
+
+    /* Get the current context buffer. */
+    buffer = Context->buffer;
+
+    /* Wait until the context buffer becomes available; this will
+       also reset the signal and mark the buffer as busy. */
+    gcmkONERROR(gckOS_WaitSignal(
+        Context->os, buffer->signal, gcvFALSE, gcvINFINITE
+        ));
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE) && 1 && gcdENABLE_3D
+    /* Update current context token. */
+    buffer->logical[Context->map[0x0E14].index]
+        = (gctUINT32)gcmPTR2INT32(Context);
+#endif
+
+    if (StateDelta != gcvNULL)
+    {
+        /* Get the state map. */
+        map = Context->map;
+
+        /* Get the first delta item. */
+        uDelta = StateDelta;
+
+        /* Reset the vertex stream count. */
+        elementCount = 0;
+
+        /* Merge all pending deltas. */
+        {
+            /* Get access to the state delta. */
+            gcmkONERROR(gckKERNEL_OpenUserData(
+                kernel, needCopy,
+                &_stateDelta,
+                uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+                (gctPOINTER *) &kDelta
+                ));
+
+            dirtyRecordArraySize
+                = gcmSIZEOF(gcsSTATE_DELTA_RECORD) * kDelta->recordCount;
+
+            if (dirtyRecordArraySize)
+            {
+                /* Get access to the state records. */
+                gcmkONERROR(gckOS_MapUserPointer(
+                    kernel->os,
+                    gcmUINT64_TO_PTR(kDelta->recordArray),
+                    dirtyRecordArraySize,
+                    (gctPOINTER *) &recordArray
+                    ));
+
+                if (recordArray == gcvNULL)
+                {
+                    gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+                }
+
+                /* Merge all pending states. */
+                for (j = 0; j < kDelta->recordCount; j += 1)
+                {
+                    if (j >= Context->numStates)
+                    {
+                        break;
+                    }
+
+                    /* Get the current state record. */
+                    record = &recordArray[j];
+
+                    /* Get the state address. */
+                    gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->address, &address));
+
+                    /* Make sure the state is a part of the mapping table. */
+                    if (address >= Context->maxState)
+                    {
+                        gcmkTRACE(
+                            gcvLEVEL_ERROR,
+                            "%s(%d): State 0x%04X (0x%04X) is not mapped.\n",
+                            __FUNCTION__, __LINE__,
+                            address, address << 2
+                            );
+
+                        continue;
+                    }
+
+                    /* Get the state index. */
+                    index = map[address].index;
+
+                    /* Skip the state if not mapped. */
+                    if (index == 0)
+                    {
+                        continue;
+                    }
+
+                    /* Get the data mask. */
+                    gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->mask, &mask));
+
+                    /* Get the new data value. */
+                    gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->data, &data));
+
+                    /* Masked states that are being completly reset or regular states. */
+                    if ((mask == 0) || (mask == ~0U))
+                    {
+                        /* Process special states. */
+                        if (address == 0x0595)
+                        {
+                            /* Force auto-disable to be disabled. */
+                            data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+                            data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+                            data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1))))))) << (0 ?
+ 13:13))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:13) - (0 ? 13:13) + 1))))))) << (0 ? 13:13)));
+                        }
+
+                        /* Set new data. */
+                        buffer->logical[index] = data;
+                    }
+
+                    /* Masked states that are being set partially. */
+                    else
+                    {
+                        buffer->logical[index]
+                            = (~mask & buffer->logical[index])
+                            | (mask & data);
+                    }
+                }
+            }
+
+            /* Get the element count. */
+            if (kDelta->elementCount != 0)
+            {
+                elementCount = kDelta->elementCount;
+            }
+
+            if (dirtyRecordArraySize)
+            {
+                /* Get access to the state records. */
+                gcmkONERROR(gckOS_UnmapUserPointer(
+                    kernel->os,
+                    gcmUINT64_TO_PTR(kDelta->recordArray),
+                    dirtyRecordArraySize,
+                    recordArray
+                    ));
+
+                recordArray = gcvNULL;
+            }
+
+            /* Close access to the current state delta. */
+            gcmkONERROR(gckKERNEL_CloseUserData(
+                kernel, needCopy,
+                gcvTRUE,
+                uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+                (gctPOINTER *) &kDelta
+                ));
+        }
+
+        /* Hardware disables all input attribute when the attribute 0 is programmed,
+           it then reenables those attributes that were explicitely programmed by
+           the software. Because of this we cannot program the entire array of
+           values, otherwise we'll get all attributes reenabled, but rather program
+           only those that are actully needed by the software.
+           elementCount = attribCount + 1 to make sure 0 is a flag to indicate if UMD
+           touches it.
+        */
+        if (elementCount != 0)
+        {
+            gctUINT base;
+            gctUINT nopCount;
+            gctUINT32_PTR nop;
+            gctUINT fe2vsCount;
+            gctUINT attribCount = elementCount -1;
+            gctUINT32 feAttributeStatgeAddr = 0x0180;
+            if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI5))
+            {
+                fe2vsCount = 32;
+                base = map[0x5E00].index;
+                feAttributeStatgeAddr = 0x5E00;
+            }
+            else if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI0))
+            {
+                fe2vsCount = 16;
+                base = map[0x0180].index;
+            }
+            else
+            {
+                fe2vsCount = 12;
+                base = map[0x0180].index;
+            }
+
+            /* Set the proper state count. */
+            if (attribCount == 0)
+            {
+                gcmkASSERT(gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_ZERO_ATTRIB_SUPPORT));
+
+                buffer->logical[base - 1]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (feAttributeStatgeAddr) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                /* Set the proper state count. */
+                buffer->logical[base + 1] =
+                        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01F2) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+                buffer->logical[base + 2] = 0x1;
+                attribCount = 3;
+            }
+            else
+            {
+                buffer->logical[base - 1]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (attribCount) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                         | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (feAttributeStatgeAddr) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+            }
+
+            /* Determine the number of NOP commands. */
+            nopCount = (fe2vsCount / 2) - (attribCount / 2);
+            /* Determine the location of the first NOP. */
+            nop = &buffer->logical[base + (attribCount | 1)];
+
+            /* Fill the unused space with NOPs. */
+            for (i = 0; i < nopCount; i += 1)
+            {
+                if (nop >= buffer->logical + Context->totalSize)
+                {
+                    break;
+                }
+
+                /* Generate a NOP command. */
+                *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                /* Advance. */
+                nop += 2;
+            }
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SMALL_BATCH) &&
+            Context->hardware->options.smallBatch)
+        {
+            gctUINT numConstant = (gctUINT)Context->hardware->identity.numConstants;
+            gctUINT32 constCount = 0;
+
+            /* Get the const number after merge. */
+            index = map[0x042B].index;
+            data = buffer->logical[index];
+            constCount = (((((gctUINT32) (data)) >> (0 ? 8:0)) & ((gctUINT32) ((((1 ? 8:0) - (0 ? 8:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:0) - (0 ? 8:0) + 1)))))) );
+
+            _UpdateUnifiedReg(Context, 0xD000, numConstant << 2, constCount << 2);
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SMALL_BATCH) &&
+            Context->hardware->options.smallBatch)
+        {
+            gctUINT numSamplers = 80;
+            gctUINT32 samplerCount = 0;
+
+            /* Get the sampler number after merge. */
+            index = map[0x042C].index;
+            data = buffer->logical[index];
+            samplerCount = (((((gctUINT32) (data)) >> (0 ? 6:0)) & ((gctUINT32) ((((1 ? 6:0) - (0 ? 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1)))))) );
+
+            _UpdateUnifiedReg(Context, 0x5800, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5880, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5900, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5980, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5A00, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5600, numSamplers, samplerCount);
+            _UpdateUnifiedReg(Context, 0x5680, numSamplers, samplerCount);
+        }
+    }
+
+    /* Schedule an event to mark the context buffer as available. */
+    gcmkONERROR(gckEVENT_Signal(
+        buffer->eventObj, buffer->signal, gcvKERNEL_PIXEL
+        ));
+
+    /* Advance to the next context buffer. */
+    Context->buffer = buffer->next;
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Get access to the state records. */
+    if (kDelta != gcvNULL && recordArray != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+            kernel->os,
+            gcmUINT64_TO_PTR(kDelta->recordArray),
+            dirtyRecordArraySize,
+            (gctPOINTER *) &recordArray
+            ));
+    }
+
+    /* Close access to the current state delta. */
+    gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+        kernel, needCopy,
+        gcvTRUE,
+        uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+        (gctPOINTER *) &kDelta
+        ));
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+#else
+    return gcvSTATUS_OK;
+#endif
+}
+
+gceSTATUS
+gckCONTEXT_MapBuffer(
+    IN gckCONTEXT Context,
+    OUT gctUINT64 *Logicals,
+    OUT gctUINT32 *Bytes
+    )
+{
+    gceSTATUS status;
+    int i = 0;
+    gckKERNEL kernel = Context->hardware->kernel;
+    gctPOINTER logical;
+    gcsCONTEXT_PTR buffer;
+
+    gcmkHEADER_ARG("Context=%p", Context);
+
+    buffer = Context->buffer;
+
+    for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i++)
+    {
+        /* Lock for userspace CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            kernel,
+            buffer->videoMem,
+            gcvFALSE,
+            gcvTRUE,
+            &logical
+            ));
+
+        Logicals[i] = gcmPTR_TO_UINT64(logical);
+        buffer = buffer->next;
+    }
+
+    *Bytes = (gctUINT)Context->totalSize;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_context_h_
+#define __gc_hal_kernel_context_h_
+
+#include "gc_hal_kernel_buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maps state locations within the context buffer. */
+typedef struct _gcsSTATE_MAP * gcsSTATE_MAP_PTR;
+typedef struct _gcsSTATE_MAP
+{
+    /* Index of the state in the context buffer. */
+    gctUINT                     index;
+
+    /* State mask. */
+    gctUINT32                   mask;
+}
+gcsSTATE_MAP;
+
+/* Context buffer. */
+typedef struct _gcsCONTEXT * gcsCONTEXT_PTR;
+typedef struct _gcsCONTEXT
+{
+    /* For debugging: the number of context buffer in the order of creation. */
+    gctUINT                     num;
+
+    /* Pointer to gckEVENT object. */
+    gckEVENT                    eventObj;
+
+    /* Context busy signal. */
+    gctSIGNAL                   signal;
+
+    /* Video memory of the context buffer. */
+    gckVIDMEM_NODE              videoMem;
+
+#if gcdCAPTURE_ONLY_MODE
+    gctUINT32                   handle;
+#endif
+
+    /* Logical address of the context buffer. */
+    gctUINT32_PTR               logical;
+
+    /* Hardware address of the context buffer. */
+    gctUINT32                   address;
+
+    /* Pointer to the LINK commands. */
+    gctPOINTER                  link2D;
+    gctPOINTER                  link3D;
+
+    /* Next context buffer. */
+    gcsCONTEXT_PTR              next;
+}
+gcsCONTEXT;
+
+typedef struct _gcsRECORD_ARRAY_MAP * gcsRECORD_ARRAY_MAP_PTR;
+struct  _gcsRECORD_ARRAY_MAP
+{
+    /* User pointer key. */
+    gctUINT64                   key;
+
+    /* Kernel memory buffer. */
+    gcsSTATE_DELTA_RECORD_PTR   kData;
+
+    /* Next map. */
+    gcsRECORD_ARRAY_MAP_PTR     next;
+
+};
+
+#define USE_SW_RESET 1
+
+/* gckCONTEXT structure that hold the current context. */
+struct _gckCONTEXT
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Pointer to gckHARDWARE object. */
+    gckHARDWARE                 hardware;
+
+    /* Command buffer alignment. */
+    gctUINT32                   alignment;
+    gctUINT32                   reservedHead;
+
+    /* Context buffer metrics. */
+    gctSIZE_T                   maxState;
+    gctUINT32                   numStates;
+    gctUINT32                   totalSize;
+    gctUINT32                   bufferSize;
+    gctUINT32                   linkIndex2D;
+    gctUINT32                   linkIndex3D;
+    gctUINT32                   linkIndexXD;
+    gctUINT32                   entryOffset3D;
+    gctUINT32                   entryOffsetXDFrom2D;
+    gctUINT32                   entryOffsetXDFrom3D;
+
+    /* State mapping. */
+    gcsSTATE_MAP_PTR            map;
+
+    /* List of context buffers. */
+    gcsCONTEXT_PTR              buffer;
+
+    /* Requested pipe select for context. */
+    gcePIPE_SELECT              entryPipe;
+    gcePIPE_SELECT              exitPipe;
+
+    /* Variables used for building state buffer. */
+    gctUINT32                   lastAddress;
+    gctSIZE_T                   lastSize;
+    gctUINT32                   lastIndex;
+    gctBOOL                     lastFixed;
+
+    gctUINT32                   pipeSelectBytes;
+
+    gcsPROFILER_COUNTERS_PART1    latestProfiler_part1;
+    gcsPROFILER_COUNTERS_PART1    histroyProfiler_part1;
+    gcsPROFILER_COUNTERS_PART1    preProfiler_part1;
+    gcsPROFILER_COUNTERS_PART2    latestProfiler_part2;
+    gcsPROFILER_COUNTERS_PART2    histroyProfiler_part2;
+    gcsPROFILER_COUNTERS_PART2    preProfiler_part2;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_context_h_ */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c
@@ -0,0 +1,16293 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+#include "gc_feature_database.h"
+#include <gc_hal_kernel_debug.h>
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+/*
+There is a afifo that is receiving the “write-done” signal coming from AXI bus for each write request from GPU.
+In normal situation, these “write-done” are coming back in several cycles apart since the write request is generally multiple bursts.
+Things are working as expected in normal frequency working mode for AXI and GPU core clock.
+When the AXI clock is much faster than the GPU core clock, and the “write-done” traffic coming to GPU grouped together,
+This afifo could become full for it has depth of 5 entries, and GPU clock is too slow to latch-in the data.
+This causes the problem observed in the ticket.
+Suggest to keep AXI to GPU core clocks ratio not more than 2:1.
+*/
+#define MIN_FSCALE_LIMIT               32
+
+typedef struct _gcsiDEBUG_REGISTERS * gcsiDEBUG_REGISTERS_PTR;
+typedef struct _gcsiDEBUG_REGISTERS
+{
+    gctSTRING       module;
+    gctUINT         index;
+    gctUINT         shift;
+    gctUINT         data;
+    gctUINT         count;
+    gctUINT32       pipeMask;
+    gctUINT32       selectStart;
+    gctBOOL         avail;
+    gctBOOL         inCluster;
+}
+gcsiDEBUG_REGISTERS;
+
+typedef struct _gcsFE_STACK
+{
+    gctSTRING       name;
+    gctINT          count;
+    gctUINT32       highSelect;
+    gctUINT32       lowSelect;
+    gctUINT32       linkSelect;
+    gctUINT32       clear;
+    gctUINT32       next;
+}
+gcsFE_STACK;
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gctBOOL
+_IsHardwareMatch(
+    IN gckHARDWARE Hardware,
+    IN gctINT32 ChipModel,
+    IN gctUINT32 ChipRevision
+    )
+{
+    return ((Hardware->identity.chipModel == ChipModel) &&
+            (Hardware->identity.chipRevision == ChipRevision));
+}
+
+static gceSTATUS
+_ResetGPU(
+    IN gckHARDWARE Hardware,
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+static void
+_GetEcoID(
+    IN gckHARDWARE Hardware,
+    IN OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+    )
+{
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x000E8,
+        &Identity->ecoID
+        ));
+
+    if (_IsHardwareMatch(Hardware, 0x1000, 0x5037) && (Identity->chipDate == 0x20120617))
+    {
+        Identity->ecoID = 1;
+    }
+
+    if (_IsHardwareMatch(Hardware, 0x320, 0x5303) && (Identity->chipDate == 0x20140511))
+    {
+        Identity->ecoID = 1;
+    }
+
+}
+
+static gceSTATUS
+_IdentifyHardwareByDatabase(
+    IN gckHARDWARE Hardware,
+    IN gckOS Os,
+    IN gckDEVICE Device,
+    IN gceCORE Core,
+    OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+    )
+{
+    gceSTATUS status;
+    gctUINT32 chipIdentity;
+    gctUINT32 debugControl0;
+    gctUINT32 chipInfo;
+    gcsFEATURE_DATABASE *database;
+    gctUINT i = 0;
+
+    gcmkHEADER_ARG("Os=0x%x", Os);
+
+    /* Get chip date. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00028, &Identity->chipDate));
+
+    /***************************************************************************
+    ** Get chip ID and revision.
+    */
+
+    /* Read chip identity register. */
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                             0x00018,
+                             &chipIdentity));
+
+    /* Special case for older graphic cores. */
+    if (((((gctUINT32) (chipIdentity)) >> (0 ?
+ 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+    {
+        Identity->chipModel    = gcv500;
+        Identity->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+    }
+
+    else
+    {
+        /* Read chip identity register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x00020,
+                                 (gctUINT32_PTR) &Identity->chipModel));
+
+        if (((Identity->chipModel & 0xFF00) == 0x0400)
+          && (Identity->chipModel != 0x0420)
+          && (Identity->chipModel != 0x0428))
+        {
+            Identity->chipModel = (gceCHIPMODEL) (Identity->chipModel & 0x0400);
+        }
+
+        /* Read CHIP_REV register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x00024,
+                                 &Identity->chipRevision));
+
+        if ((Identity->chipModel    == gcv300)
+        &&  (Identity->chipRevision == 0x2201)
+        )
+        {
+            gctUINT32 chipDate;
+            gctUINT32 chipTime;
+
+            /* Read date and time registers. */
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Os, Core,
+                                     0x00028,
+                                     &chipDate));
+
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Os, Core,
+                                     0x0002C,
+                                     &chipTime));
+
+            if ((chipDate == 0x20080814) && (chipTime == 0x12051100))
+            {
+                /* This IP has an ECO; put the correct revision in it. */
+                Identity->chipRevision = 0x1051;
+            }
+        }
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x000A8,
+                                 &Identity->productID));
+    }
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "Identity: chipModel=%X",
+                   Identity->chipModel);
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "Identity: chipRevision=%X",
+                   Identity->chipRevision);
+
+    _GetEcoID(Hardware, Identity);
+
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00030,
+                                &Identity->customerID));
+
+     /*get hw minor features*/
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x0001C,
+                                &Identity->chipFeatures));
+
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00034,
+                                &Identity->chipMinorFeatures));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00074,
+                                &Identity->chipMinorFeatures1));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00084,
+                                &Identity->chipMinorFeatures2));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00088,
+                                &Identity->chipMinorFeatures3));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x00094,
+                                &Identity->chipMinorFeatures4));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x000A0,
+                                &Identity->chipMinorFeatures5));
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                                0x000DC,
+                                &Identity->chipMinorFeatures6));
+
+    /***************************************************************************
+    ** Get chip features.
+    */
+
+    database =
+    Hardware->featureDatabase =
+    gcQueryFeatureDB(
+        Hardware->identity.chipModel,
+        Hardware->identity.chipRevision,
+        Hardware->identity.productID,
+        Hardware->identity.ecoID,
+        Hardware->identity.customerID);
+
+    if (database == gcvNULL)
+    {
+        gcmkPRINT("[galcore]: Feature database is not found,"
+                  "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x, customerID=0x%x",
+                  Hardware->identity.chipModel,
+                  Hardware->identity.chipRevision,
+                  Hardware->identity.productID,
+                  Hardware->identity.ecoID,
+                  Hardware->identity.customerID);
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    else if (database->chipVersion != Hardware->identity.chipRevision)
+    {
+        gcmkPRINT("[galcore]: Warning: chipRevision mismatch, database chipRevision=0x%x register read chipRevision=0x%x\n",
+                  database->chipVersion, Hardware->identity.chipRevision);
+    }
+
+
+    Identity->pixelPipes                    = database->NumPixelPipes;
+    Identity->resolvePipes                  = database->NumResolvePipes;
+    Identity->instructionCount              = database->InstructionCount;
+    Identity->numConstants                  = database->NumberOfConstants;
+    Identity->varyingsCount                 = database->VaryingCount;
+    Identity->gpuCoreCount                  = database->CoreCount;
+    Identity->streamCount                   = database->Streams;
+    Identity->clusterAvailMask              = database->ClusterAliveMask;
+
+    if (gcmIS_SUCCESS(gckOS_QueryOption(Hardware->os, "sRAMBases", Device->sRAMBases[0])))
+    {
+        gckOS_MemCopy(
+            Identity->sRAMBases,
+            Device->sRAMBases[Core],
+            sizeof(gctUINT64) * gcvSRAM_INTER_COUNT
+            );
+    }
+    else
+    {
+        for (i = 0; i < gcvSRAM_INTER_COUNT; i++)
+        {
+            Identity->sRAMBases[i] = gcvINVALID_PHYSICAL_ADDRESS;
+        }
+    }
+
+    if (gcmIS_SUCCESS(gckOS_QueryOption(Hardware->os, "sRAMSizes", (gctUINT64 *)Device->sRAMSizes[0])))
+    {
+        gckOS_MemCopy(
+            Identity->sRAMSizes,
+            Device->sRAMSizes[Core],
+            sizeof(gctUINT32) * gcvSRAM_INTER_COUNT
+            );
+    }
+
+    for (i = gcvSRAM_INTERNAL0; i < gcvSRAM_INTER_COUNT; i++)
+    {
+        if (Identity->sRAMSizes[i])
+        {
+            break;
+        }
+    }
+
+    /* If module parameter doesn't set per-core SRAM sizes. */
+    if (i == gcvSRAM_INTER_COUNT)
+    {
+        gctUINT j = 0;
+        for (i = Core; i < gcvCORE_COUNT; i++)
+        {
+            for (j = gcvSRAM_INTERNAL0; j < gcvSRAM_INTER_COUNT; j++)
+            {
+                /* Try to get SRAM sizes from database. */
+                Device->sRAMSizes[i][j] = Identity->sRAMSizes[j] = database->VIP_SRAM_SIZE;
+            }
+        }
+    }
+
+    gckOS_QueryOption(Hardware->os, "extSRAMBases", Device->extSRAMBases);
+
+    gckOS_QueryOption(Hardware->os, "extSRAMSizes", (gctUINT64 *)Device->extSRAMSizes);
+
+    for (i = gcvSRAM_EXTERNAL0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        if (Device->extSRAMSizes[i])
+        {
+            break;
+        }
+    }
+
+    /* If module parameter doesn't set external SRAM sizes. */
+    if (i == gcvSRAM_EXT_COUNT)
+    {
+        for (i = gcvSRAM_EXTERNAL0; i < gcvSRAM_EXT_COUNT; i++)
+        {
+            /* Try to get SRAM sizes from database. */
+            Device->extSRAMSizes[i] = database->AXI_SRAM_SIZE;
+        }
+    }
+
+    if (Identity->chipModel == gcv320)
+    {
+        gctUINT32 data;
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os,
+                                 Core,
+                                 0x0002C,
+                                 &data));
+
+        if ((data != 33956864) &&
+            ((Identity->chipRevision == 0x5007) ||
+            (Identity->chipRevision == 0x5220)))
+        {
+            Hardware->maxOutstandingReads = 0xFF &
+                (Identity->chipRevision == 0x5220 ? 8 :
+                (Identity->chipRevision == 0x5007 ? 12 : 0));
+        }
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv880, 0x5107))
+    {
+        Hardware->maxOutstandingReads = 0x00010;
+    }
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00470, &debugControl0));
+
+    if (debugControl0 & (1 << 16))
+    {
+        Identity->chipFlags |= gcvCHIP_FLAG_MSAA_COHERENCEY_ECO_FIX;
+    }
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x000A4, &chipInfo));
+
+    if (((((gctUINT32) (chipInfo)) >> (0 ?
+ 21:21) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))))
+    {
+        Identity->chipFlags |= gcvCHIP_AXI_BUS128_BITS;
+    }
+
+    gckOS_QueryOption(Os, "platformFlagBits", &Identity->platformFlagBits);
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_GetHardwareSignature(
+    IN gckHARDWARE Hardware,
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gcsHARDWARE_SIGNATURE * Signature
+    )
+{
+    gceSTATUS status;
+
+    gctUINT32 chipIdentity;
+
+    gcmkHEADER_ARG("Os=0x%x", Os);
+
+    /***************************************************************************
+    ** Get chip ID and revision.
+    */
+
+    /* Read chip identity register. */
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                             0x00018,
+                             &chipIdentity));
+
+    /* Special case for older graphic cores. */
+    if (((((gctUINT32) (chipIdentity)) >> (0 ?
+ 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+    {
+        Signature->chipModel    = gcv500;
+        Signature->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+    }
+
+    else
+    {
+        /* Read chip identity register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x00020,
+                                 (gctUINT32_PTR) &Signature->chipModel));
+
+        /* Read CHIP_REV register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x00024,
+                                 &Signature->chipRevision));
+    }
+
+    /***************************************************************************
+    ** Get chip features.
+    */
+
+    /* Read chip feature register. */
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Os, Core,
+                             0x0001C,
+                             &Signature->chipFeatures));
+
+    if (((Signature->chipModel == gcv500) && (Signature->chipRevision < 2))
+    ||  ((Signature->chipModel == gcv300) && (Signature->chipRevision < 0x2000))
+    )
+    {
+        /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */
+        Signature->chipMinorFeatures  = 0;
+        Signature->chipMinorFeatures1 = 0;
+        Signature->chipMinorFeatures2 = 0;
+    }
+    else
+    {
+        /* Read chip minor feature register #0. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Os, Core,
+                                 0x00034,
+                                 &Signature->chipMinorFeatures));
+
+        if (((((gctUINT32) (Signature->chipMinorFeatures)) >> (0 ?
+ 21:21) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))
+        )
+        {
+            /* Read chip minor features register #1. */
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Os, Core,
+                                     0x00074,
+                                     &Signature->chipMinorFeatures1));
+
+            /* Read chip minor features register #2. */
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Os, Core,
+                                     0x00084,
+                                     &Signature->chipMinorFeatures2));
+        }
+        else
+        {
+            /* Chip doesn't has minor features register #1 or 2 or 3 or 4 or 5. */
+            Signature->chipMinorFeatures1 = 0;
+            Signature->chipMinorFeatures2 = 0;
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/* Set to 1 to enable module clock gating debug function.
+*  Following options take effect when it is set to 1.
+*/
+#define gcdDEBUG_MODULE_CLOCK_GATING          0
+/* Set to 1 to disable module clock gating of all modules. */
+#define gcdDISABLE_MODULE_CLOCK_GATING        0
+/* Set to 1 to disable module clock gating of each module. */
+#define gcdDISABLE_STARVE_MODULE_CLOCK_GATING 0
+#define gcdDISABLE_FE_CLOCK_GATING            0
+#define gcdDISABLE_PE_CLOCK_GATING            0
+#define gcdDISABLE_SH_CLOCK_GATING            0
+#define gcdDISABLE_PA_CLOCK_GATING            0
+#define gcdDISABLE_SE_CLOCK_GATING            0
+#define gcdDISABLE_RA_CLOCK_GATING            0
+#define gcdDISABLE_RA_EZ_CLOCK_GATING         0
+#define gcdDISABLE_RA_HZ_CLOCK_GATING         0
+#define gcdDISABLE_TX_CLOCK_GATING            0
+#define gcdDISABLE_TFB_CLOCK_GATING           0
+#define gcdDISABLE_GPIPE_CLOCK_GATING         0
+#define gcdDISABLE_BLT_CLOCK_GATING           0
+#define gcdDISABLE_TPG_CLOCK_GATING           0
+#define gcdDISABLE_VX_CLOCK_GATING            0
+
+#if gcdDEBUG_MODULE_CLOCK_GATING
+gceSTATUS
+_ConfigureModuleLevelClockGating(
+    gckHARDWARE Hardware
+    )
+{
+    gctUINT32 data;
+
+    gcmkVERIFY_OK(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             Hardware->powerBaseAddress
+                             + 0x00104,
+                             &data));
+
+#if gcdDISABLE_FE_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+#endif
+
+#if gcdDISABLE_PE_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)));
+#endif
+
+#if gcdDISABLE_SH_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+#endif
+
+#if gcdDISABLE_PA_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+#endif
+
+#if gcdDISABLE_SE_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+#endif
+
+#if gcdDISABLE_RA_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+#endif
+
+#if gcdDISABLE_TX_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+#endif
+
+#if gcdDISABLE_RA_EZ_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+#endif
+
+#if gcdDISABLE_RA_HZ_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)));
+#endif
+
+#if gcdDISABLE_TFB_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+#endif
+
+#if gcdDISABLE_GPIPE_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)));
+#endif
+
+#if gcdDISABLE_BLT_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)));
+#endif
+
+#if gcdDISABLE_TPG_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ?
+ 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18)));
+#endif
+
+#if gcdDISABLE_VX_CLOCK_GATING
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ?
+ 21:21))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)));
+#endif
+
+    gcmkVERIFY_OK(
+        gckOS_WriteRegisterEx(Hardware->os,
+                              Hardware->core,
+                              Hardware->powerBaseAddress
+                              + 0x00104,
+                              data));
+
+#if gcdDISABLE_STARVE_MODULE_CLOCK_GATING
+    gcmkVERIFY_OK(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             Hardware->powerBaseAddress +
+                             0x00100,
+                             &data));
+
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)));
+
+    gcmkVERIFY_OK(
+        gckOS_WriteRegisterEx(Hardware->os,
+                              Hardware->core,
+                              Hardware->powerBaseAddress
+                              + 0x00100,
+                              data));
+
+#endif
+
+#if gcdDISABLE_MODULE_CLOCK_GATING
+    gcmkVERIFY_OK(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             Hardware->powerBaseAddress +
+                             0x00100,
+                             &data));
+
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+
+    gcmkVERIFY_OK(
+        gckOS_WriteRegisterEx(Hardware->os,
+                              Hardware->core,
+                              Hardware->powerBaseAddress
+                              + 0x00100,
+                              data));
+#endif
+
+    return gcvSTATUS_OK;
+}
+#endif
+
+static void
+_PowerStateTimerFunc(
+    gctPOINTER Data
+    )
+{
+    gckHARDWARE hardware = (gckHARDWARE)Data;
+
+    gcmkVERIFY_OK(gckHARDWARE_SetPowerState(hardware, hardware->nextPowerState));
+}
+
+static gceSTATUS
+_VerifyDMA(
+    IN gckOS Os,
+    IN gceCORE Core,
+    gctUINT32_PTR Address1,
+    gctUINT32_PTR Address2,
+    gctUINT32_PTR State1,
+    gctUINT32_PTR State2
+    )
+{
+    gceSTATUS status;
+    gctUINT32 i;
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State1));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State1));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address1));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address1));
+
+    for (i = 0; i < 500; i += 1)
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State2));
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State2));
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address2));
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address2));
+
+        if (*Address1 != *Address2)
+        {
+            break;
+        }
+
+        if (*State1 != *State2)
+        {
+            break;
+        }
+    }
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_DumpDebugRegisters(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gcsiDEBUG_REGISTERS_PTR Descriptor
+    )
+{
+/* If this value is changed, print formats need to be changed too. */
+#define REG_PER_LINE 8
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 select;
+    gctUINT i, j, pipe;
+    gctUINT32 datas[REG_PER_LINE];
+    gctUINT32 oldControl, control;
+
+    gcmkHEADER_ARG("Os=0x%X Descriptor=0x%X", Os, Descriptor);
+
+    /* Record control. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x0, &oldControl));
+
+    for (pipe = 0; pipe < 4; pipe++)
+    {
+        if (!Descriptor->avail)
+        {
+            continue;
+        }
+        if (!(Descriptor->pipeMask & (1 << pipe)))
+        {
+            continue;
+        }
+
+        gcmkPRINT_N(8, "    %s[%d] debug registers:\n", Descriptor->module, pipe);
+
+        /* Switch pipe. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x0, &control));
+        control &= ~(0xF << 20);
+        control |= (pipe << 20);
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x0, control));
+
+        gcmkASSERT(!(Descriptor->count % REG_PER_LINE));
+
+        for (i = 0; i < Descriptor->count; i += REG_PER_LINE)
+        {
+            /* Select of first one in the group. */
+            select = i + Descriptor->selectStart;
+
+            /* Read a group of registers. */
+            for (j = 0; j < REG_PER_LINE; j++)
+            {
+                /* Shift select to right position. */
+                gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, (select + j) << Descriptor->shift));
+                gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &datas[j]));
+            }
+
+            gcmkPRINT_N(32, "    [%02X] %08X %08X %08X %08X %08X %08X %08X %08X\n",
+                        select, datas[0], datas[1], datas[2], datas[3], datas[4], datas[5], datas[6], datas[7]);
+        }
+    }
+
+    /* Restore control. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x0, oldControl));
+
+OnError:
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_DumpLinkStack(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gcsiDEBUG_REGISTERS_PTR Descriptor
+    )
+{
+    /* Get wrptr */
+    gctUINT32 shift = Descriptor->shift;
+    gctUINT32 pointerSelect = 0xE << shift;
+    gctUINT32 pointer, wrPtr, rdPtr, links[16];
+    gctUINT32 stackSize = 16;
+    gctUINT32 oldestPtr = 0;
+    gctUINT32 i;
+
+    gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, pointerSelect));
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &pointer));
+
+    wrPtr = (pointer & 0xF0) >> 4;
+    rdPtr = pointer & 0xF;
+
+    /* Move rdptr to the oldest one (next one to the latest one. ) */
+    oldestPtr = (wrPtr + 1) % stackSize;
+
+    while (rdPtr != oldestPtr)
+    {
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0x0));
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xF << shift));
+
+
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, pointerSelect));
+        gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &pointer));
+
+        rdPtr = pointer & 0xF;
+    }
+
+    gcmkPRINT("    Link stack:");
+
+    /* Read from stack bottom*/
+    for (i = 0; i < stackSize; i++)
+    {
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xD << shift));
+        gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &links[i]));
+
+        /* Advance rdPtr. */
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0x0));
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xF << shift));
+    }
+
+    /* Print. */
+    for (i = 0; i < stackSize; i += 4)
+    {
+        gcmkPRINT_N(32, "      [0x%02X] 0x%08X [0x%02X] 0x%08X [0x%02X] 0x%08X [0x%02X] 0x%08X\n",
+                    i, links[i], i + 1, links[i + 1], i + 2, links[i + 2], i + 3, links[i + 3]);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DumpFEStack(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gcsiDEBUG_REGISTERS_PTR Descriptor
+    )
+{
+    gctUINT i;
+    gctINT j;
+    gctUINT32 stack[32][2];
+    gctUINT32 link[32];
+
+    static gcsFE_STACK _feStacks[] =
+    {
+        { "PRE_STACK", 32, 0x1A, 0x9A, 0x00, 0x1B, 0x1E },
+        { "CMD_STACK", 32, 0x1C, 0x9C, 0x1E, 0x1D, 0x1E },
+    };
+
+    for (i = 0; i < gcmCOUNTOF(_feStacks); i++)
+    {
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].clear));
+
+        for (j = 0; j < _feStacks[i].count; j++)
+        {
+            gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].highSelect));
+
+            gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &stack[j][0]));
+
+            gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].lowSelect));
+
+            gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &stack[j][1]));
+
+            gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].next));
+
+            if (_feStacks[i].linkSelect)
+            {
+                gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].linkSelect));
+
+                gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &link[j]));
+            }
+        }
+
+        gcmkPRINT("  %s:", _feStacks[i].name);
+
+        for (j = 31; j >= 3; j -= 4)
+        {
+            gcmkPRINT("    %08X %08X %08X %08X %08X %08X %08X %08X",
+                      stack[j][0], stack[j][1], stack[j - 1][0], stack[j - 1][1],
+                      stack[j - 2][0], stack[j - 2][1], stack[j - 3][0], stack[j - 3][1]);
+        }
+
+        if (_feStacks[i].linkSelect)
+        {
+            gcmkPRINT("  LINK_STACK:");
+
+            for (j = 31; j >= 3; j -= 4)
+            {
+                gcmkPRINT("    %08X %08X %08X %08X %08X %08X %08X %08X",
+                          link[j], link[j], link[j - 1], link[j - 1],
+                          link[j - 2], link[j - 2], link[j - 3], link[j - 3]);
+            }
+        }
+
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_IsGPUPresent(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gcsHARDWARE_SIGNATURE signature;
+    gctUINT32 control;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x00000,
+                                     &control));
+
+    control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+    control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      control));
+
+    gckOS_ZeroMemory((gctPOINTER)&signature, gcmSIZEOF(gcsHARDWARE_SIGNATURE));
+
+    /* Identify the hardware. */
+    gcmkONERROR(_GetHardwareSignature(Hardware,
+                                      Hardware->os,
+                                      Hardware->core,
+                                      &signature));
+
+    /* Check if these are the same values as saved before. */
+    if ((Hardware->signature.chipModel          != signature.chipModel)
+    ||  (Hardware->signature.chipRevision       != signature.chipRevision)
+    ||  (Hardware->signature.chipFeatures       != signature.chipFeatures)
+    ||  (Hardware->signature.chipMinorFeatures  != signature.chipMinorFeatures)
+    ||  (Hardware->signature.chipMinorFeatures1 != signature.chipMinorFeatures1)
+    ||  (Hardware->signature.chipMinorFeatures2 != signature.chipMinorFeatures2)
+    )
+    {
+        gcmkPRINT("[galcore]: GPU is not present.");
+        gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_FlushCache(
+    gckHARDWARE Hardware,
+    gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gctUINT32 bytes, requested;
+    gctPOINTER buffer;
+
+    /* Get the size of the flush command. */
+    gcmkONERROR(gckHARDWARE_Flush(Hardware,
+                                  gcvFLUSH_ALL,
+                                  gcvNULL,
+                                  &requested));
+
+    /* Reserve space in the command queue. */
+    gcmkONERROR(gckCOMMAND_Reserve(Command,
+                                   requested,
+                                   &buffer,
+                                   &bytes));
+
+    /* Append a flush. */
+    gcmkONERROR(gckHARDWARE_Flush(
+        Hardware, gcvFLUSH_ALL, buffer, &bytes
+        ));
+
+    /* Execute the command queue. */
+    gcmkONERROR(gckCOMMAND_Execute(Command, requested));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gctBOOL
+_IsGPUIdle(
+    IN gctUINT32 Idle
+    )
+{
+    return Idle == 0x7FFFFFFF;
+}
+
+static gctBOOL
+_QueryFeatureDatabase(
+    IN gckHARDWARE Hardware,
+    IN gceFEATURE Feature
+    )
+{
+    gctBOOL available;
+
+    gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+
+    gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature);
+
+     /* Only features needed by common kernel logic added here. */
+    switch (Feature)
+    {
+    case gcvFEATURE_END_EVENT:
+        available = gcvFALSE;
+        break;
+
+    case gcvFEATURE_MC20:
+        available = database->REG_MC20;
+        break;
+
+    case gcvFEATURE_EARLY_Z:
+        available = database->REG_NoEZ == 0;
+        break;
+
+    case gcvFEATURE_HZ:
+        available = database->REG_HierarchicalZ;
+        break;
+
+    case gcvFEATURE_NEW_HZ:
+        available = database->REG_NewHZ;
+        break;
+
+    case gcvFEATURE_FAST_MSAA:
+        available = database->REG_FastMSAA;
+        break;
+
+    case gcvFEATURE_SMALL_MSAA:
+        available = database->REG_SmallMSAA;
+        break;
+
+    case gcvFEATURE_DYNAMIC_FREQUENCY_SCALING:
+        /* This feature doesn't apply for 2D cores. */
+        available = database->REG_DynamicFrequencyScaling && database->REG_Pipe3D;
+
+        if (Hardware->identity.chipModel == gcv1000 &&
+            (Hardware->identity.chipRevision == 0x5039 ||
+            Hardware->identity.chipRevision == 0x5040))
+        {
+            available = gcvFALSE;
+        }
+        break;
+
+    case gcvFEATURE_ACE:
+        available = database->REG_ACE;
+        break;
+
+    case gcvFEATURE_HALTI2:
+        available = database->REG_Halti2;
+        break;
+
+    case gcvFEATURE_PIPE_2D:
+        available = database->REG_Pipe2D;
+        break;
+
+    case gcvFEATURE_PIPE_3D:
+#if gcdENABLE_3D
+        available = database->REG_Pipe3D;
+#else
+        available = gcvFALSE;
+#endif
+        break;
+
+    case gcvFEATURE_FC_FLUSH_STALL:
+        available = database->REG_FcFlushStall;
+        break;
+
+    case gcvFEATURE_BLT_ENGINE:
+        available = database->REG_BltEngine;
+       break;
+
+    case gcvFEATURE_HALTI0:
+        available = database->REG_Halti0;
+        break;
+
+    case gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG:
+        available = database->REG_FEAllowStallPrefetchEng;
+        break;
+
+    case gcvFEATURE_MMU:
+#if gcdCAPTURE_ONLY_MODE
+        available = gcvTRUE;
+#else
+        available = database->REG_MMU;
+#endif
+
+        break;
+
+    case gcvFEATURE_FENCE_64BIT:
+        available = database->FENCE_64BIT;
+        break;
+
+    case gcvFEATURE_TEX_BASELOD:
+        available = database->REG_Halti2;
+
+        if (_IsHardwareMatch(Hardware, gcv900, 0x5250))
+        {
+            available = gcvTRUE;
+        }
+        break;
+
+    case gcvFEATURE_TEX_CACHE_FLUSH_FIX:
+        available = database->REG_Halti5;
+        break;
+
+    case gcvFEATURE_BUG_FIXES1:
+        available = database->REG_BugFixes1;
+        break;
+
+    case gcvFEATURE_MULTI_SOURCE_BLT:
+        available = database->REG_MultiSourceBlt;
+        break;
+
+    case gcvFEATURE_HALTI5:
+        available = database->REG_Halti5;
+        break;
+
+    case gcvFEATURE_FAST_CLEAR:
+        available = database->REG_FastClear;
+
+        if (Hardware->identity.chipModel == gcv700)
+        {
+            available = gcvFALSE;
+        }
+        break;
+
+    case gcvFEATURE_BUG_FIXES7:
+        available = database->REG_BugFixes7;
+        break;
+
+    case gcvFEATURE_ZCOMPRESSION:
+        available = database->REG_ZCompression;
+        break;
+
+    case gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE:
+        available = database->REG_InstructionCache;
+        break;
+
+    case gcvFEATURE_YUV420_TILER:
+        available = database->REG_YUV420Tiler;
+        break;
+
+    case gcvFEATURE_2DPE20:
+        available = database->REG_2DPE20;
+        break;
+
+    case gcvFEATURE_DITHER_AND_FILTER_PLUS_ALPHA_2D:
+        available = database->REG_DitherAndFilterPlusAlpha2D;
+        break;
+
+    case gcvFEATURE_ONE_PASS_2D_FILTER:
+        available = database->REG_OnePass2DFilter;
+        break;
+
+    case gcvFEATURE_HALTI1:
+        available = database->REG_Halti1;
+        break;
+
+    case gcvFEATURE_HALTI3:
+        available = database->REG_Halti3;
+        break;
+
+    case gcvFEATURE_HALTI4:
+        available = database->REG_Halti4;
+        break;
+
+    case gcvFEATURE_GEOMETRY_SHADER:
+        available = database->REG_GeometryShader;
+        break;
+
+    case gcvFEATURE_TESSELLATION:
+        available = database->REG_TessellationShaders;
+        break;
+
+    case gcvFEATURE_GENERIC_ATTRIB:
+        available = database->REG_Generics;
+        break;
+
+    case gcvFEATURE_TEXTURE_LINEAR:
+        available = database->REG_LinearTextureSupport;
+        break;
+
+    case gcvFEATURE_TX_FILTER:
+        available = database->REG_TXFilter;
+        break;
+
+    case gcvFEATURE_TX_SUPPORT_DEC:
+        available = database->REG_TXSupportDEC;
+        break;
+
+    case gcvFEATURE_TX_FRAC_PRECISION_6BIT:
+        available = database->REG_TX6bitFrac;
+        break;
+
+    case gcvFEATURE_TEXTURE_ASTC:
+        available = database->REG_TXEnhancements4 && !database->NO_ASTC;
+        break;
+
+    case gcvFEATURE_SHADER_ENHANCEMENTS2:
+        available = database->REG_SHEnhancements2;
+        break;
+
+    case gcvFEATURE_BUG_FIXES18:
+        available = database->REG_BugFixes18;
+        break;
+
+    case gcvFEATURE_64K_L2_CACHE:
+        available = gcvFALSE;
+        break;
+
+    case gcvFEATURE_BUG_FIXES4:
+        available = database->REG_BugFixes4;
+        break;
+
+    case gcvFEATURE_BUG_FIXES12:
+        available = database->REG_BugFixes12;
+        break;
+
+    case gcvFEATURE_HW_TFB:
+        available = database->HWTFB;
+        break;
+
+    case gcvFEATURE_SNAPPAGE_CMD_FIX:
+        available = database->SH_SNAP2PAGE_FIX;
+        break;
+
+    case gcvFEATURE_SECURITY:
+        available = database->SECURITY;
+        break;
+
+    case gcvFEATURE_TX_DESCRIPTOR:
+        available = database->REG_Halti5;
+        break;
+
+    case gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX:
+        available = database->TX_DESC_CACHE_CLOCKGATE_FIX;
+        break;
+
+    case gcvFEATURE_ROBUSTNESS:
+        available = database->ROBUSTNESS;
+        break;
+
+    case gcvFEATURE_SNAPPAGE_CMD:
+        available = database->SNAPPAGE_CMD;
+        break;
+
+    case gcvFEATURE_HALF_FLOAT_PIPE:
+        available = database->REG_HalfFloatPipe;
+        break;
+
+    case gcvFEATURE_SH_INSTRUCTION_PREFETCH:
+        available = database->SH_ICACHE_PREFETCH;
+        break;
+
+    case gcvFEATURE_FE_NEED_DUMMYDRAW:
+        available = database->FE_NEED_DUMMYDRAW;
+
+        if (_IsHardwareMatch(Hardware, gcv600, 0x4653))
+        {
+            available = gcvTRUE;
+        }
+
+        break;
+
+    case gcvFEATURE_DEC300_COMPRESSION:
+        available = database->REG_DEC;
+        break;
+
+    case gcvFEATURE_DEC400_COMPRESSION:
+        available = database->G2D_DEC400;
+        break;
+
+    case gcvFEATURE_TPC_COMPRESSION:
+        available = database->REG_ThirdPartyCompression;
+        break;
+
+    case gcvFEATURE_TPCV11_COMPRESSION:
+        available = database->G2D_3rd_PARTY_COMPRESSION_1_1;
+        break;
+
+    case gcvFEATURE_USC_DEFER_FILL_FIX:
+        available = database->USC_DEFER_FILL_FIX;
+        break;
+
+    case gcvFEATURE_USC:
+        available = database->REG_Halti5;
+        break;
+
+    case gcvFEATURE_RA_CG_FIX:
+        available = database->RA_CG_FIX;
+        break;
+
+    case gcvFEATURE_MULTI_CLUSTER:
+        available = database->MULTI_CLUSTER;
+        break;
+
+    case gcvFEATURE_ZERO_ATTRIB_SUPPORT:
+        available = database->REG_Halti4;
+        break;
+
+    case gcvFEATURE_SH_CLOCK_GATE_FIX:
+        available = database->SH_CLOCK_GATE_FIX;
+        break;
+
+    case gcvFEATURE_GPIPE_CLOCK_GATE_FIX:
+        available = gcvFALSE;
+        break;
+
+    case gcvFEATURE_NEW_GPIPE:
+        available = database->NEW_GPIPE;
+        break;
+
+    case gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2:
+        available = database->MULTI_CORE_BLOCK_SET_CONFIG2;
+        break;
+
+    case gcvFEATURE_SECURITY_AHB:
+        available = database->SECURITY_AHB;
+        break;
+
+    case gcvFEATURE_SMALL_BATCH:
+        available = database->SMALLBATCH;
+        break;
+
+    case gcvFEATURE_ASYNC_BLIT:
+        available = database->ASYNC_BLT;
+        break;
+
+    case gcvFEATURE_PSCS_THROTTLE:
+        available = database->PSCS_THROTTLE;
+        break;
+
+    case gcvFEATURE_SEPARATE_LS:
+        available = database->SEPARATE_LS;
+        break;
+
+    case gcvFEATURE_MCFE:
+        available = database->MCFE;
+        break;
+
+    case gcvFEATURE_COMPUTE_ONLY:
+        available = database->COMPUTE_ONLY;
+        break;
+
+    case gcvFEATURE_USC_FULLCACHE_FIX:
+        available = database->USC_FULL_CACHE_FIX;
+        break;
+
+    case gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX:
+        available = database->PE_TILE_CACHE_FLUSH_FIX;
+        break;
+
+    case gcvFEATURE_TILE_STATUS_2BITS:
+        available = database->REG_TileStatus2Bits;
+        break;
+
+    case gcvFEATURE_128BTILE:
+        available = database->CACHE128B256BPERLINE;
+        break;
+
+    case gcvFEATURE_COMPRESSION_DEC400:
+        available = database->DEC400;
+        break;
+
+    case gcvFEATURE_SUPPORT_GCREGTX:
+        available = database->REG_Halti1;
+
+        if (Hardware->identity.chipModel == gcv880 &&
+            ((Hardware->identity.chipRevision & 0xfff0) == 0x5120))
+        {
+            available = gcvTRUE;
+        }
+        break;
+
+    case gcvFEATURE_MSAA_FRAGMENT_OPERATION:
+        available = database->MSAA_FRAGMENT_OPERATION;
+        break;
+
+    case gcvFEATURE_OCB_COUNTER:
+        available = database->OCB_COUNTER;
+        break;
+
+    case gcvFEATURE_AI_GPU:
+        available = database->AI_GPU;
+        break;
+
+    case gcvFEATURE_NN_ENGINE:
+        available = database->NNCoreCount > 0;
+        break;
+
+    case gcvFEATURE_TP_ENGINE:
+        available = database->TP_ENGINE;
+        break;
+
+    case gcvFEATURE_HI_REORDER_FIX:
+        available = database->HI_REORDER_FIX;
+        break;
+
+    case gcvFEATURE_EVIS2_FLOP_RESET_FIX:
+        available = database->EVIS2_FLOP_RESET_FIX;
+        break;
+
+    case gcvFEATURE_USC_ASYNC_CP_RTN_FLOP_RESET_FIX:
+        available = database->USC_ASYNC_CP_RTN_FLOP_RESET_FIX;
+        break;
+
+    case gcvFEATURE_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX:
+        available = database->USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX;
+        break;
+
+    default:
+        gcmkFATAL("Invalid feature has been requested.");
+        available = gcvFALSE;
+    }
+
+    gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE);
+    return available;
+}
+
+static void
+_ConfigurePolicyID(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 policyID;
+    gctUINT32 auxBit = ~0U;
+    gctUINT32 axiConfig;
+    gckOS os = Hardware->os;
+    gceCORE core = Hardware->core;
+    gctUINT32 i;
+    gctUINT32 offset;
+    gctUINT32 shift;
+    gctUINT32 currentAxiConfig;
+
+    status = gckOS_GetPolicyID(os, gcvVIDMEM_TYPE_GENERIC, &policyID, &axiConfig);
+
+    if (status == gcvSTATUS_NOT_SUPPORTED)
+    {
+        /* No customized policyID setting. */
+        return;
+    }
+
+    for (i = 0; i < 16; i++)
+    {
+        /* Mapping 16 surface type.*/
+        status = gckOS_GetPolicyID(os, (gceVIDMEM_TYPE) i, &policyID, &axiConfig);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            if (auxBit == ~0U)
+            {
+                /* There is a customized policyID setting for this type. */
+                auxBit = (policyID >> 4) & 0x1;
+            }
+            else
+            {
+                /* Check whether this bit changes. */
+                if (auxBit != ((policyID >> 4) & 0x1))
+                {
+                    gcmkPRINT("[galcore]: AUX_BIT changes");
+                    return;
+                }
+            }
+
+            offset = policyID >> 1;
+
+            shift  = (policyID & 0x1) * 16;
+
+            axiConfig &= 0xFFFF;
+
+            gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+                os,
+                core,
+                (0x0070 + offset) << 2,
+                &currentAxiConfig
+                ));
+
+            currentAxiConfig |= (axiConfig << shift);
+
+            gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+                os,
+                core,
+                (0x0070 + offset) << 2,
+                currentAxiConfig
+                ));
+        }
+    }
+
+    if (auxBit != ~0U)
+    {
+        gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+            os,
+            core,
+            0x000EC,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (auxBit) & ((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8)))
+            ));
+    }
+}
+/****************************
+** Initialise hardware options
+*/
+static void
+_SetHardwareOptions(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT64 data = 0;
+    gcsHAL_QUERY_CHIP_OPTIONS *options = &Hardware->options;
+    gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+    gctBOOL featureUSC = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC) ? gcvTRUE : gcvFALSE;
+    gctBOOL featureSeparateLS = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SEPARATE_LS) ? gcvTRUE : gcvFALSE;
+    gctBOOL featureComputeOnly = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_COMPUTE_ONLY) ? gcvTRUE : gcvFALSE;
+    gctBOOL featureTS = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TESSELLATION) ? gcvTRUE : gcvFALSE;
+    gctUINT32 featureL1CacheSize = database->L1CacheSize;
+    gctUINT32 featureUSCMaxPages = database->USC_MAX_PAGES;
+
+
+    status = gckOS_QueryOption(Hardware->os, "powerManagement", &data);
+    options->powerManagement = (data != 0);
+
+    if (status == gcvSTATUS_NOT_SUPPORTED)
+    {
+        /* Enable power management by default. */
+        options->powerManagement = gcvTRUE;
+    }
+
+    /* Disable profiler by default */
+    status = gckOS_QueryOption(Hardware->os, "gpuProfiler", &data);
+    options->gpuProfiler = (data != 0);
+
+    if (status == gcvSTATUS_NOT_SUPPORTED)
+    {
+        /* Disable profiler by default */
+        options->gpuProfiler= gcvFALSE;
+    }
+
+    status = gckOS_QueryOption(Hardware->os, "mmu", &data);
+    options->enableMMU = (data != 0);
+
+    if (status == gcvSTATUS_NOT_SUPPORTED)
+    {
+        /* Disable MMU if we can't get result from OS layer query */
+        options->enableMMU = gcvFALSE;
+    }
+
+    gcmCONFIGUSC2(gcmk, featureUSC, featureSeparateLS, featureComputeOnly, featureTS,
+                 featureL1CacheSize, featureUSCMaxPages,
+                 Hardware->options.uscAttribCacheRatio, Hardware->options.uscL1CacheRatio);
+
+    status = gckOS_QueryOption(Hardware->os, "smallBatch", &data);
+    options->smallBatch = (data != 0);
+
+    if (status == gcvSTATUS_NOT_SUPPORTED)
+    {
+        options->smallBatch = gcvTRUE;
+    }
+
+    status = gckOS_QueryOption(Hardware->os, "userClusterMask", &data);
+    options->userClusterMask = (gctUINT32)data;
+
+    if (status == gcvSTATUS_NOT_SUPPORTED || (options->userClusterMask == 0))
+    {
+        /* use all clusters identified in database */
+        options->userClusterMask = Hardware->identity.clusterAvailMask;
+    }
+    else if (options->userClusterMask & (~Hardware->identity.clusterAvailMask))
+    {
+        gcmkPRINT("%s(%d): user cluster mask(0x%x) must be a subset of available clusters(0x%x),ignored it!",
+                  __FUNCTION__, __LINE__, options->userClusterMask, Hardware->identity.clusterAvailMask);
+        options->userClusterMask= Hardware->identity.clusterAvailMask;
+    }
+
+    options->secureMode = gcvSECURE_NONE;
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY))
+    {
+        gcmkASSERT(gcvSTATUS_TRUE == gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB));
+
+        options->secureMode = gcvSECURE_IN_NORMAL;
+
+        status = gckOS_QueryOption(Hardware->os, "TA", &data);
+
+        if (gcmIS_SUCCESS(status) && data)
+        {
+            options->secureMode = gcvSECURE_IN_TA;
+        }
+    }
+    else if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB))
+    {
+        options->secureMode = gcvSECURE_IN_NORMAL;
+    }
+
+    options->hasShader = database->NumShaderCores;
+
+    return;
+}
+
+/*
+* State timer helper must be called with powerMutex held.
+*/
+static void
+gckSTATETIMER_Reset(
+    IN gcsSTATETIMER * StateTimer,
+    IN gctUINT64 Start
+    )
+{
+    gctUINT64 now;
+
+    if (Start)
+    {
+        now = Start;
+    }
+    else
+    {
+        gckOS_GetProfileTick(&now);
+    }
+
+    StateTimer->recent = StateTimer->start = now;
+
+    gckOS_ZeroMemory(StateTimer->elapse, gcmSIZEOF(StateTimer->elapse));
+}
+
+gceSTATUS
+gckHARDWARE_StartTimerReset(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcmkHEADER();
+
+    gckSTATETIMER_Reset(&Hardware->powerStateCounter, 0);
+
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+gckSTATETIMER_Accumulate(
+    IN gcsSTATETIMER * StateTimer,
+    IN gceCHIPPOWERSTATE OldState
+    )
+{
+    gctUINT64 now;
+    gctUINT64 elapse;
+
+    gckOS_GetProfileTick(&now);
+
+    elapse = now - StateTimer->recent;
+
+    StateTimer->recent = now;
+
+    StateTimer->elapse[OldState] += elapse;
+}
+
+static void
+gckSTATETIMER_Query(
+    IN gcsSTATETIMER * StateTimer,
+    IN gceCHIPPOWERSTATE State,
+    OUT gctUINT64_PTR On,
+    OUT gctUINT64_PTR Off,
+    OUT gctUINT64_PTR Idle,
+    OUT gctUINT64_PTR Suspend
+    )
+{
+    gckSTATETIMER_Accumulate(StateTimer, State);
+
+    *On      = StateTimer->elapse[gcvPOWER_ON];
+    *Off     = StateTimer->elapse[gcvPOWER_OFF];
+    *Idle    = StateTimer->elapse[gcvPOWER_IDLE];
+    *Suspend = StateTimer->elapse[gcvPOWER_SUSPEND];
+}
+
+static gceSTATUS
+_InitPageTableArray(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=%p", Hardware);
+
+    if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+    {
+        gcePOOL pool = gcvPOOL_DEFAULT;
+        gctUINT32 flags = gcvALLOC_FLAG_CONTIGUOUS;
+
+#if defined(CONFIG_ZONE_DMA32) || defined(CONFIG_ZONE_DMA)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+        flags |= gcvALLOC_FLAG_4GB_ADDR;
+#endif
+#endif
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+        flags |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+        Hardware->pagetableArray.size = 1024;
+
+        /* Allocate mmu table array within 32bit space */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            Hardware->kernel,
+            64,
+            gcvVIDMEM_TYPE_COMMAND,
+            flags,
+            &Hardware->pagetableArray.size,
+            &pool,
+            &Hardware->pagetableArray.videoMem
+            ));
+
+        /* Lock for kernel side CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            Hardware->kernel,
+            Hardware->pagetableArray.videoMem,
+            gcvFALSE,
+            gcvFALSE,
+            &Hardware->pagetableArray.logical
+            ));
+
+        /* Get CPU physical address. */
+        gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+            Hardware->kernel,
+            Hardware->pagetableArray.videoMem,
+            0,
+            &Hardware->pagetableArray.address
+            ));
+
+        /* Convert to GPU physical address. */
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+            Hardware->os,
+            Hardware->pagetableArray.address,
+            &Hardware->pagetableArray.address
+            ));
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (Hardware->pagetableArray.videoMem)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            Hardware->kernel,
+            Hardware->pagetableArray.videoMem
+            ));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_SetupSRAMVidMem(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT i;
+
+    for (i = gcvSRAM_INTERNAL0; i < gcvSRAM_INTER_COUNT; i++)
+    {
+        if (Hardware->identity.sRAMSizes[i] &&
+           (Hardware->identity.sRAMBases[i] != gcvINVALID_PHYSICAL_ADDRESS))
+        {
+            /* If the internal SRAM usage is memory block. */
+            status = gckVIDMEM_Construct(
+                Hardware->os,
+                Hardware->identity.sRAMBases[i],
+                Hardware->identity.sRAMSizes[i],
+                64,
+                0,
+                &Hardware->sRAMVidMem[i]
+                );
+
+            if (gcmIS_ERROR(status))
+            {
+                Hardware->identity.sRAMSizes[i] = 0;
+                Hardware->sRAMVidMem[i] = gcvNULL;
+            }
+            else
+            {
+                char sRAMName[20];
+                gctUINT64 data = 0;
+                gctBOOL sRAMRequested;
+
+                gcmkSPRINTF(sRAMName, gcmSIZEOF(sRAMName) - 1, "Galcore core%d sram%d", Hardware->core, i);
+                status = gckOS_QueryOption(Hardware->os, "sRAMRequested", (gctUINT64 *)&data);
+                sRAMRequested = (status == gcvSTATUS_OK) ? (data != 0) : gcvFALSE;
+
+                gcmkONERROR(gckOS_RequestReservedMemory(
+                    Hardware->os,
+                    Hardware->identity.sRAMBases[i],
+                    Hardware->identity.sRAMSizes[i],
+                    sRAMName,
+                    sRAMRequested,
+                    &Hardware->sRAMPhysical[i]
+                    ));
+
+                Hardware->sRAMVidMem[i]->physical = Hardware->sRAMPhysical[i];
+            }
+        }
+    }
+
+OnError:
+    return status;
+}
+
+/******************************************************************************\
+****************************** gckHARDWARE API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckHARDWARE_Construct
+**
+**  Construct a new gckHARDWARE object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an initialized gckOS object.
+**
+**      gceCORE Core
+**          Specified core.
+**
+**  OUTPUT:
+**
+**      gckHARDWARE * Hardware
+**          Pointer to a variable that will hold the pointer to the gckHARDWARE
+**          object.
+*/
+gceSTATUS
+gckHARDWARE_Construct(
+    IN gckOS Os,
+    IN gckDEVICE Device,
+    IN gceCORE Core,
+    OUT gckHARDWARE * Hardware
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware = gcvNULL;
+    gctUINT16 data = 0xff00;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT    i;
+
+    gcmkHEADER_ARG("Os=0x%x", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+    /* Enable the GPU. */
+    gcmkONERROR(gckOS_SetGPUPower(Os, Core, gcvTRUE, gcvTRUE));
+    gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                      Core,
+                                      0x00000,
+                                      0x00010900));
+
+    /* Allocate the gckHARDWARE object. */
+    gcmkONERROR(gckOS_Allocate(Os,
+                               gcmSIZEOF(struct _gckHARDWARE),
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckHARDWARE));
+
+    hardware = (gckHARDWARE) pointer;
+
+    /* Initialize the gckHARDWARE object. */
+    hardware->object.type = gcvOBJ_HARDWARE;
+    hardware->os          = Os;
+    hardware->core        = Core;
+
+    gcmkONERROR(_GetHardwareSignature(hardware, Os, Core, &hardware->signature));
+
+    /* Identify the hardware. */
+    gcmkONERROR(_IdentifyHardwareByDatabase(hardware, Os, Device, Core, &hardware->identity));
+
+    /* Setup SRAM memory heap. */
+    gcmkONERROR(_SetupSRAMVidMem(hardware));
+
+    _SetHardwareOptions(hardware);
+
+    hardware->mmuVersion = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MMU);
+
+    /* Get the system's physical base address for old MMU */
+    if (hardware->mmuVersion == 0)
+    {
+        gcmkONERROR(gckOS_GetBaseAddress(Os, &hardware->baseAddress));
+    }
+
+    /* Determine the hardware type */
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_3D)
+     && gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_2D)
+    )
+    {
+        hardware->type = gcvHARDWARE_3D2D;
+    }
+    else if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_2D))
+    {
+        hardware->type = gcvHARDWARE_2D;
+    }
+    else if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_AI_GPU))
+    {
+        hardware->type = gcvHARDWARE_3D;
+    }
+    else if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_NN_ENGINE)
+     || gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TP_ENGINE)
+    )
+    {
+        hardware->type = gcvHARDWARE_VIP;
+    }
+    else
+    {
+        hardware->type = gcvHARDWARE_3D;
+    }
+
+    hardware->powerBaseAddress
+        = ((hardware->identity.chipModel   == gcv300)
+        && (hardware->identity.chipRevision < 0x2000))
+            ? 0x0100
+            : 0x0000;
+
+
+    /* _ResetGPU need powerBaseAddress. */
+    status = _ResetGPU(hardware, Os, Core);
+    if (status != gcvSTATUS_OK)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "_ResetGPU failed: status=%d\n", status);
+    }
+
+#if gcdDEC_ENABLE_AHB
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, gcvCORE_DEC, 0x18180, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)))));
+#endif
+
+    hardware->hasL2Cache = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_64K_L2_CACHE);
+
+    if (!hardware->hasL2Cache)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          Core,
+                                          0x0055C,
+                                          0x00FFFFFF));
+    }
+
+    hardware->powerMutex = gcvNULL;
+
+    /* Determine whether bug fixes #1 are present. */
+    hardware->extraEventStates = (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_BUG_FIXES1) == gcvFALSE);
+
+    /* Check if big endian */
+    hardware->bigEndian = (*(gctUINT8 *)&data == 0xff);
+
+    /* Initialize the fast clear. */
+    gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1));
+
+#if !gcdENABLE_128B_MERGE
+
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_SOURCE_BLT))
+    {
+        /* 128B merge is turned on by default. Disable it. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, 0));
+    }
+
+#endif
+
+#if (gcdFPGA_BUILD && 1)
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TPCV11_COMPRESSION))
+    {
+        gctUINT32 data;
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00558, &data));
+        data |= 0x1 << 27;
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, data));
+    }
+#endif
+
+    {
+        gctUINT32 value;
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00090, &value));
+#if gcdDEC_ENABLE_AHB
+        if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_DEC300_COMPRESSION))
+        {
+            value |= ~0xFFFFFFBF;
+        }
+        else
+#endif
+        {
+            value &= 0xFFFFFFBF;
+        }
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00090, value));
+    }
+
+    /* Set power state to ON. */
+    hardware->chipPowerState  = gcvPOWER_ON;
+    hardware->clockState      = gcvTRUE;
+    hardware->powerState      = gcvTRUE;
+    hardware->lastWaitLink    = ~0U;
+    hardware->lastEnd         = ~0U;
+    hardware->globalSemaphore = gcvNULL;
+#if gcdENABLE_FSCALE_VAL_ADJUST
+    hardware->powerOnFscaleVal = 64;
+#endif
+
+    gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex));
+    gcmkONERROR(gckOS_CreateSemaphore(Os, &hardware->globalSemaphore));
+
+    gcmkVERIFY_OK(gckOS_CreateTimer(Os,
+                                    _PowerStateTimerFunc,
+                                    (gctPOINTER)hardware,
+                                    &hardware->powerStateTimer));
+
+    for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+    {
+        gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pageTableDirty[i]));
+    }
+
+    gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pendingEvent));
+
+
+#if defined(LINUX) || defined(__QNXNTO__) || defined(UNDER_CE)
+    if (hardware->mmuVersion)
+    {
+        hardware->stallFEPrefetch
+            = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG);
+    }
+    else
+#endif
+    {
+        hardware->stallFEPrefetch =
+            _QueryFeatureDatabase(hardware, gcvFEATURE_MCFE) == gcvFALSE;
+    }
+
+    hardware->minFscaleValue = 1;
+    hardware->waitCount = 200;
+
+    if (_IsHardwareMatch(hardware, gcv600, 0x4653)
+        || _IsHardwareMatch(hardware, gcv400, 0x4645))
+    {
+        hardware->minFscaleValue = MIN_FSCALE_LIMIT;
+    }
+
+#if gcdLINK_QUEUE_SIZE
+    gcmkONERROR(gckQUEUE_Allocate(hardware->os, &hardware->linkQueue, gcdLINK_QUEUE_SIZE));
+#endif
+
+    /* Initialize FEs, either MCFE or wait-link FE. */
+    if (_QueryFeatureDatabase(hardware, gcvFEATURE_MCFE))
+    {
+        hardware->mcfeChannels[0] = gcvMCFE_CHANNEL_SYSTEM;
+        hardware->mcfeChannels[1] = gcvMCFE_CHANNEL_SHADER;
+        hardware->mcfeChannels[2] = gcvMCFE_CHANNEL_NN;
+        hardware->mcfeChannels[3] = gcvMCFE_CHANNEL_TP;
+
+        hardware->mcfeChannelCount = 4;
+
+        gcmkONERROR(gckMCFE_Construct(hardware, &hardware->mcFE));
+    }
+    else
+    {
+        gcmkONERROR(gckWLFE_Construct(hardware, &hardware->wlFE));
+    }
+
+    if (_QueryFeatureDatabase(hardware, gcvFEATURE_ASYNC_BLIT))
+    {
+        gcmkONERROR(gckASYNC_FE_Construct(hardware, &hardware->asyncFE));
+    }
+
+    /* Construct hardware function */
+    gcmkONERROR(gckFUNCTION_Construct(hardware));
+
+    /* Return pointer to the gckHARDWARE object. */
+    *Hardware = hardware;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (hardware != gcvNULL)
+    {
+        /* Turn off the power. */
+        gcmkVERIFY_OK(gckOS_SetGPUPower(Os, Core, gcvFALSE, gcvFALSE));
+
+        if (hardware->globalSemaphore != gcvNULL)
+        {
+            /* Destroy the global semaphore. */
+            gcmkVERIFY_OK(gckOS_DestroySemaphore(Os,
+                                                 hardware->globalSemaphore));
+        }
+
+        if (hardware->powerMutex != gcvNULL)
+        {
+            /* Destroy the power mutex. */
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex));
+        }
+
+        if (hardware->powerStateTimer != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerStateTimer));
+            gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerStateTimer));
+        }
+
+        for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+        {
+            if (hardware->pageTableDirty[i] != gcvNULL)
+            {
+                gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty[i]));
+            }
+        }
+
+        if (hardware->pendingEvent != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pendingEvent));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, hardware));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_PostConstruct(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT i;
+
+    /* Initialize MMU page table array. */
+    gcmkONERROR(_InitPageTableArray(Hardware));
+
+    for (i = 0; i < gcvFUNCTION_EXECUTION_NUM; i++)
+    {
+        gctBOOL funcVaild = gcvFALSE;
+
+        gckFUNCTION_Validate(&Hardware->functions[i], &funcVaild);
+        if (funcVaild)
+        {
+            gcmkONERROR(gckFUNCTION_Init(&Hardware->functions[i]));
+        }
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    for (i = 0; i < gcvFUNCTION_EXECUTION_NUM; i++)
+    {
+        gckFUNCTION_Release(&Hardware->functions[i]);
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_PreDestroy
+**
+**  Prepare destroying an gckHARDWARE object.
+**  This is to destroy resources relevant to other modules such as MMU.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object that needs to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_PreDestroy(
+    IN gckHARDWARE Hardware
+    )
+{
+    gcmkHEADER_ARG("%x", Hardware);
+
+    gcmkVERIFY_OK(gckFUNCTION_Destory(Hardware));
+
+    if (Hardware->pagetableArray.videoMem)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+            Hardware->kernel,
+            Hardware->pagetableArray.videoMem,
+            0,
+            gcvFALSE,
+            gcvFALSE
+            ));
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            Hardware->kernel,
+            Hardware->pagetableArray.videoMem
+            ));
+
+        Hardware->pagetableArray.videoMem = gcvNULL;
+        Hardware->pagetableArray.logical  = gcvNULL;
+    }
+
+    if (Hardware->wlFE)
+    {
+        gckWLFE_Destroy(Hardware, Hardware->wlFE);
+        Hardware->wlFE = gcvNULL;
+    }
+
+    if (Hardware->asyncFE)
+    {
+        gckASYNC_FE_Destroy(Hardware, Hardware->asyncFE);
+        Hardware->asyncFE = gcvNULL;
+    }
+
+    if (Hardware->mcFE)
+    {
+        gckMCFE_Destroy(Hardware, Hardware->mcFE);
+        Hardware->mcFE = gcvNULL;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_Destroy
+**
+**  Destroy an gckHARDWARE object.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object that needs to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Destroy(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT i;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Destroy the power semaphore. */
+    gcmkVERIFY_OK(gckOS_DestroySemaphore(Hardware->os,
+                                         Hardware->globalSemaphore));
+
+    /* Destroy the power mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex));
+
+    gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerStateTimer));
+    gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerStateTimer));
+
+    for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+    {
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty[i]));
+    }
+
+    gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pendingEvent));
+
+#if gcdLINK_QUEUE_SIZE
+    gckQUEUE_Free(Hardware->os, &Hardware->linkQueue);
+#endif
+
+    /* Mark the object as unknown. */
+    Hardware->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the object. */
+    gcmkONERROR(gcmkOS_SAFE_FREE(Hardware->os, Hardware));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_GetType
+**
+**  Get the hardware type.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gceHARDWARE_TYPE * Type
+**          Pointer to a variable that receives the type of hardware object.
+*/
+gceSTATUS
+gckHARDWARE_GetType(
+    IN gckHARDWARE Hardware,
+    OUT gceHARDWARE_TYPE * Type
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+    gcmkVERIFY_ARGUMENT(Type != gcvNULL);
+
+    *Type = Hardware->type;
+
+    gcmkFOOTER_ARG("*Type=%d", *Type);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_InitializeHardware
+**
+**  Initialize the hardware.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_InitializeHardware(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 control;
+    gctUINT32 data;
+    gctUINT32 regPMC = 0;
+    gctUINT32 i;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Disable isolate GPU bit. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      ((((gctUINT32) (0x00010900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)))));
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x00000,
+                                     &control));
+
+    /* Enable debug register. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)))));
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB) &&
+        (Hardware->options.secureMode == gcvSECURE_IN_NORMAL))
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x003A8,
+                                          ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))));
+    }
+    /* Reset memory counters. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0003C,
+                                      ~0U));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0003C,
+                                      0));
+
+    if (Hardware->mmuVersion == 0)
+    {
+        /* Program the base addesses. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x0041C,
+                                          Hardware->baseAddress));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00418,
+                                          Hardware->baseAddress));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00428,
+                                          Hardware->baseAddress));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00420,
+                                          Hardware->baseAddress));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00424,
+                                          Hardware->baseAddress));
+    }
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     Hardware->powerBaseAddress +
+                                     0x00100,
+                                     &data));
+
+    /* Enable clock gating. */
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+    if ((Hardware->identity.chipRevision == 0x4301)
+    ||  (Hardware->identity.chipRevision == 0x4302)
+    )
+    {
+        /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2
+        ** revisions. */
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+    }
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      Hardware->powerBaseAddress
+                                      + 0x00100,
+                                      data));
+
+    /* Initialize FE. */
+    if (Hardware->wlFE)
+    {
+        gckWLFE_Initialize(Hardware, Hardware->wlFE);
+    }
+    else if (Hardware->mcFE)
+    {
+        gckMCFE_Initialize(Hardware, gcvFALSE, Hardware->mcFE);
+    }
+
+    if (Hardware->asyncFE)
+    {
+        gckASYNC_FE_Initialize(Hardware, Hardware->asyncFE);
+    }
+
+#if gcdENABLE_3D
+    /* Disable PE clock gating on revs < 5.0 when HZ is present without a
+    ** bug fix. */
+    if ((Hardware->identity.chipRevision < 0x5000)
+    &&  gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HZ)
+    &&  !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES4)
+    )
+    {
+        if (regPMC == 0)
+        {
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     Hardware->powerBaseAddress
+                                     + 0x00104,
+                                     &regPMC));
+        }
+
+        /* Disable PE clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)));
+    }
+#endif
+
+    if (Hardware->identity.chipModel == gcv4000 &&
+        ((Hardware->identity.chipRevision == 0x5208) || (Hardware->identity.chipRevision == 0x5222)))
+    {
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x0010C,
+                                  ((((gctUINT32) (0x015B0880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ?
+ 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23)))));
+    }
+
+    if ((Hardware->identity.chipModel == gcv1000 &&
+         (Hardware->identity.chipRevision == 0x5039 ||
+          Hardware->identity.chipRevision == 0x5040))
+        ||
+        (Hardware->identity.chipModel == gcv2000 &&
+         Hardware->identity.chipRevision == 0x5140)
+       )
+    {
+        gctUINT32 pulseEater;
+
+        pulseEater = ((((gctUINT32) (0x015B0880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x0010C,
+                                  ((((gctUINT32) (pulseEater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)))));
+    }
+
+    if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI2) == gcvSTATUS_FALSE)
+     || (Hardware->identity.chipRevision < 0x5422)
+    )
+    {
+        if (regPMC == 0)
+        {
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     Hardware->powerBaseAddress
+                                     + 0x00104,
+                                     &regPMC));
+        }
+
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1))))))) << (0 ?
+ 15:15))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15)));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv2000, 0x5108))
+    {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 0x00480,
+                                 &data));
+
+        /* Set FE bus to one, TX bus to zero */
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00480,
+                                  data));
+    }
+
+    /* AHBDEC400 */
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_DEC400EX_COMPRESSION))
+    {
+        data = 0x0201018A;
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            Hardware->os,
+            Hardware->core,
+            0x00800,
+            data));
+
+        data = 0x003FC810;
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1))))))) << (0 ?
+ 6:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1))))))) << (0 ? 6:0)));
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:7) - (0 ?
+ 13:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:7) - (0 ?
+ 13:7) + 1))))))) << (0 ?
+ 13:7))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 13:7) - (0 ?
+ 13:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:7) - (0 ? 13:7) + 1))))))) << (0 ? 13:7)));
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            Hardware->os,
+            Hardware->core,
+            0x00808,
+            data));
+    }
+
+#if !gcdCAPTURE_ONLY_MODE
+    gcmkONERROR(
+        gckHARDWARE_SetMMU(Hardware,
+                           Hardware->kernel->mmu));
+#endif
+
+    if (Hardware->mcFE)
+    {
+        /* Reinitialize MCFE, now MMU is enabled. */
+        gckMCFE_Initialize(Hardware, gcvTRUE, Hardware->mcFE);
+    }
+
+    if (Hardware->identity.chipModel >= gcv400
+    &&  Hardware->identity.chipModel != gcv420
+    &&  !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES12))
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        /* Disable PA clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+    }
+
+    /* Limit 2D outstanding request. */
+    if (Hardware->maxOutstandingReads)
+    {
+        gctUINT32 data;
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 0x00414,
+                                 &data));
+
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->maxOutstandingReads & 0xFF) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)));
+
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00414,
+                                  data));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv1000, 0x5035))
+    {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 0x00414,
+                                 &data));
+
+        /* Disable HZ-L2. */
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)));
+
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00414,
+                                  data));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv4000, 0x5222)
+     || _IsHardwareMatch(Hardware, gcv2000, 0x5108)
+     || _IsHardwareMatch(Hardware, gcv7000, 0x6202)
+     || _IsHardwareMatch(Hardware, gcv7000, 0x6203)
+     || (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TX_DESCRIPTOR)
+       && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX)
+        )
+    )
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        /* Disable TX clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+    }
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NEW_GPIPE) &&
+        !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_GPIPE_CLOCK_GATE_FIX))
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        /* Disable GPIPE clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv880, 0x5106))
+    {
+        Hardware->kernel->timeOut = 140 * 1000;
+    }
+
+    if (regPMC == 0)
+    {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+    }
+
+    /* Disable RA HZ clock gating. */
+    regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)));
+
+    /* Disable RA EZ clock gating. */
+    regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+
+    if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5)
+       && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_RA_CG_FIX)
+        )
+       )
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        /* Disable RA clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+    }
+
+    if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5)
+       && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SH_CLOCK_GATE_FIX)
+        )
+       )
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        /* Disable SH clock gating. */
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv7000, 0x6202))
+    {
+        if (regPMC == 0)
+        {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &regPMC));
+        }
+
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+
+        regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+
+        gcmkVERIFY_OK(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress +
+                                 0x00100,
+                                 &data));
+
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+
+        gcmkVERIFY_OK(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  Hardware->powerBaseAddress
+                                  + 0x00100,
+                                  data));
+    }
+
+    if (regPMC != 0)
+    {
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  Hardware->powerBaseAddress
+                                  + 0x00104,
+                                  regPMC));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv2000, 0x5108)
+     || (_IsHardwareMatch(Hardware, gcv2000, 0xffff5450))
+     || _IsHardwareMatch(Hardware, gcv320, 0x5007)
+     || _IsHardwareMatch(Hardware, gcv320, 0x5303)
+     || _IsHardwareMatch(Hardware, gcv880, 0x5106)
+     || _IsHardwareMatch(Hardware, gcv400, 0x4645)
+    )
+    {
+        /* Update GPU AXI cache atttribute. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00008,
+                                          0x00002200));
+    }
+
+    if ((Hardware->identity.chipRevision > 0x5420)
+     && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D))
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x0010C,
+                                     &data));
+
+        /* Disable internal DFS. */
+        data =
+#if gcdDVFS
+            ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ?
+ 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18))) |
+#endif
+            ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) |
+            ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0010C,
+                                      data));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv2500, 0x5422))
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(
+            Hardware->os, Hardware->core, 0x00090, &data));
+
+        /* AXI switch setup to SPLIT_TO64 mode */
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            Hardware->os, Hardware->core, 0x00090, data));
+    }
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_ENGINE) &&
+        (!gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HI_REORDER_FIX) ||
+        (((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->AXI_SRAM_SIZE == 0))
+        )
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(
+            Hardware->os, Hardware->core, 0x00090, &data));
+
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            Hardware->os, Hardware->core, 0x00090, data));
+    }
+	/* Disable RA SE clock gating */
+	if (_IsHardwareMatch(Hardware, gcv7000, 0x6202))
+	{
+		gcmkVERIFY_OK(
+			gckOS_ReadRegisterEx(Hardware->os,
+								 Hardware->core,
+								 Hardware->powerBaseAddress
+								 + 0x00104,
+								 &data));
+		data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ?
+ 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5)));
+
+		data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ?
+ 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6)));
+
+		gcmkVERIFY_OK(
+			gckOS_WriteRegisterEx(Hardware->os,
+								  Hardware->core,
+								  Hardware->powerBaseAddress
+								  + 0x00104,
+								  data));
+	}
+
+    _ConfigurePolicyID(Hardware);
+
+#if gcdDEBUG_MODULE_CLOCK_GATING
+    _ConfigureModuleLevelClockGating(Hardware);
+#endif
+
+    /* Perfrom hardware functions */
+    for (i = 0; i < gcvFUNCTION_EXECUTION_NUM; i++)
+    {
+        gctBOOL funcVaild = gcvFALSE;
+
+        /* Skip functions since it will perform at special place */
+        if (i == gcvFUNCTION_EXECUTION_MMU || i == gcvFUNCTION_EXECUTION_FLUSH)
+        {
+            continue;
+        }
+
+        gckFUNCTION_Validate(&Hardware->functions[i], &funcVaild);
+        if (funcVaild)
+        {
+            gckFUNCTION_Execute(&Hardware->functions[i]);
+            gckFUNCTION_Execute(&Hardware->functions[gcvFUNCTION_EXECUTION_FLUSH]);
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryMemory
+**
+**  Query the amount of memory available on the hardware.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * InternalSize
+**          Pointer to a variable that will hold the size of the internal video
+**          memory in bytes.  If 'InternalSize' is gcvNULL, no information of the
+**          internal memory will be returned.
+**
+**      gctUINT32 * InternalBaseAddress
+**          Pointer to a variable that will hold the hardware's base address for
+**          the internal video memory.  This pointer cannot be gcvNULL if
+**          'InternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * InternalAlignment
+**          Pointer to a variable that will hold the hardware's base address for
+**          the internal video memory.  This pointer cannot be gcvNULL if
+**          'InternalSize' is also non-gcvNULL.
+**
+**      gctSIZE_T * ExternalSize
+**          Pointer to a variable that will hold the size of the external video
+**          memory in bytes.  If 'ExternalSize' is gcvNULL, no information of the
+**          external memory will be returned.
+**
+**      gctUINT32 * ExternalBaseAddress
+**          Pointer to a variable that will hold the hardware's base address for
+**          the external video memory.  This pointer cannot be gcvNULL if
+**          'ExternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * ExternalAlignment
+**          Pointer to a variable that will hold the hardware's base address for
+**          the external video memory.  This pointer cannot be gcvNULL if
+**          'ExternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * HorizontalTileSize
+**          Number of horizontal pixels per tile.  If 'HorizontalTileSize' is
+**          gcvNULL, no horizontal pixel per tile will be returned.
+**
+**      gctUINT32 * VerticalTileSize
+**          Number of vertical pixels per tile.  If 'VerticalTileSize' is
+**          gcvNULL, no vertical pixel per tile will be returned.
+*/
+gceSTATUS
+gckHARDWARE_QueryMemory(
+    IN gckHARDWARE Hardware,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * InternalBaseAddress,
+    OUT gctUINT32 * InternalAlignment,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ExternalBaseAddress,
+    OUT gctUINT32 * ExternalAlignment,
+    OUT gctUINT32 * HorizontalTileSize,
+    OUT gctUINT32 * VerticalTileSize
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (InternalSize != gcvNULL)
+    {
+        /* No internal memory. */
+        *InternalSize = 0;
+    }
+
+    if (ExternalSize != gcvNULL)
+    {
+        /* No external memory. */
+        *ExternalSize = 0;
+    }
+
+    if (HorizontalTileSize != gcvNULL)
+    {
+        /* 4x4 tiles. */
+        *HorizontalTileSize = 4;
+    }
+
+    if (VerticalTileSize != gcvNULL)
+    {
+        /* 4x4 tiles. */
+        *VerticalTileSize = 4;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x "
+                   "*InternalAlignment=0x%08x *ExternalSize=%lu "
+                   "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x "
+                   "*HorizontalTileSize=%u *VerticalTileSize=%u",
+                   gcmOPT_VALUE(InternalSize),
+                   gcmOPT_VALUE(InternalBaseAddress),
+                   gcmOPT_VALUE(InternalAlignment),
+                   gcmOPT_VALUE(ExternalSize),
+                   gcmOPT_VALUE(ExternalBaseAddress),
+                   gcmOPT_VALUE(ExternalAlignment),
+                   gcmOPT_VALUE(HorizontalTileSize),
+                   gcmOPT_VALUE(VerticalTileSize));
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryChipIdentity
+**
+**  Query the identity of the hardware.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+**          Pointer to the identity structure.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryChipIdentity(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Identity != gcvNULL);
+
+    *Identity = Hardware->identity;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryChipOptions
+**
+**  Query the options of the hardware.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+**          Pointer to the identity structure.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryChipOptions(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Options != gcvNULL);
+
+    *Options = Hardware->options;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+**  gckHARDWARE_SplitMemory
+**
+**  Split a hardware specific memory address into a pool and offset.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**      gctUINT32 Address
+**          Address in hardware specific format.
+**
+**  OUTPUT:
+**
+**      gcePOOL * Pool
+**          Pointer to a variable that will hold the pool type for the address.
+**
+**      gctUINT32 * Offset
+**          Pointer to a variable that will hold the offset for the address.
+*/
+gceSTATUS
+gckHARDWARE_SplitMemory(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    OUT gcePOOL * Pool,
+    OUT gctUINT32 * Offset
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x Addres=0x%08x", Hardware, Address);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Offset != gcvNULL);
+
+    if (Hardware->mmuVersion == 0)
+    {
+        /* Dispatch on memory type. */
+        switch ((((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) ))
+        {
+        case 0x0:
+            /* System memory. */
+            *Pool = gcvPOOL_SYSTEM;
+            break;
+
+        case 0x1:
+            /* Virtual memory. */
+            *Pool = gcvPOOL_VIRTUAL;
+            break;
+
+        default:
+            /* Invalid memory type. */
+            gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
+            return gcvSTATUS_INVALID_ARGUMENT;
+        }
+
+        /* Return offset of address. */
+        *Offset = (((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) );
+    }
+    else
+    {
+        *Pool = gcvPOOL_SYSTEM;
+        *Offset = Address;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Pool=%d *Offset=0x%08x", *Pool, *Offset);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_PipeSelect
+**
+**  Append a PIPESELECT command at the specified user logical memory.
+**
+**  WARNING: Only for writing to USERSPACE!
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          the PIPESELECT command at or gcvNULL just to query the size of the
+**          PIPESELECT command.
+**
+**      gcePIPE_SELECT Pipe
+**          Pipe value to select.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the PIPESELECT command.
+**          If 'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the PIPESELECT command.  If 'Bytes' is gcvNULL, nothing will be
+**          returned.
+*/
+gceSTATUS
+gckHARDWARE_PipeSelect(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gcePIPE_SELECT Pipe,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%d *Bytes=%lu",
+                   Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    /* Append a PipeSelect. */
+    if (Logical != gcvNULL)
+    {
+        gctUINT32 flush, stall;
+
+        if (*Bytes < 32)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        flush = (Pipe == gcvPIPE_2D)
+              ?
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+              : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+
+        stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+        /* LoadState(AQFlush, 1), flush. */
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 1,
+            flush
+            ));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "0x%x: FLUSH 0x%x", logical, flush);
+
+        /* LoadState(AQSempahore, 1), stall. */
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 2,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 3,
+            stall
+            ));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "0x%x: SEMAPHORE 0x%x", logical + 2, stall);
+
+        /* Stall, stall. */
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 4,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 5,
+            stall
+            ));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "0x%x: STALL 0x%x", logical + 4, stall);
+
+        /* LoadState(AQPipeSelect, 1), pipe. */
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 6,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            logical + 7,
+            (Pipe == gcvPIPE_2D)
+            ? 0x1
+            : 0x0
+            ));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "0x%x: PIPE %d", logical + 6, Pipe);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the PIPESELECT command. */
+        *Bytes = 32;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_FenceRender(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FenceAddress,
+    IN gctUINT64 FenceData,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gckOS os = Hardware->os;
+    gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+    gctUINT32 dataLow = (gctUINT32)FenceData;
+    gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+    if (logical)
+    {
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E1A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            FenceAddress
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E26) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            dataHigh
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E1B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            dataLow
+            );
+    }
+
+    if (Bytes)
+    {
+        *Bytes = gcdRENDER_FENCE_LENGTH;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FenceBlt(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FenceAddress,
+    IN gctUINT64 FenceData,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gckOS os = Hardware->os;
+    gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+    gctUINT32 dataLow = (gctUINT32)FenceData;
+    gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+    if (logical)
+    {
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5029) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            FenceAddress
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            dataHigh
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            dataLow
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            );
+    }
+
+    if (Bytes)
+    {
+        *Bytes = gcdBLT_FENCE_LENGTH;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_Fence
+**
+**  Append a HW FENCE states at the specified user logical memory.
+**
+**  WARNING: Only for writing to USERSPACE!
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gceENGINE Engine
+**          Engine type, render or 3d-blit currently.
+**
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          the PIPESELECT command at or gcvNULL just to query the size of the
+**          PIPESELECT command.
+**
+**      gctUINT32 FenceAddress
+**          GPU address to write out the data.
+**
+**      gctUINT64 FenceData
+**          The 64bit data to write out.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the PIPESELECT command.
+**          If 'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the PIPESELECT command.  If 'Bytes' is gcvNULL, nothing will be
+**          returned.
+*/
+gceSTATUS
+gckHARDWARE_Fence(
+    IN gckHARDWARE Hardware,
+    IN gceENGINE  Engine,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FenceAddress,
+    IN gctUINT64 FenceData,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    if (Engine == gcvENGINE_RENDER)
+    {
+        return _FenceRender(Hardware, Logical, FenceAddress, FenceData, Bytes);
+    }
+    else
+    {
+         return _FenceBlt(Hardware, Logical, FenceAddress, FenceData, Bytes);
+    }
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_UpdateQueueTail
+**
+**  Update the tail of the command queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Logical address of the start of the command queue.
+**
+**      gctUINT32 Offset
+**          Offset into the command queue of the tail (last command).
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_UpdateQueueTail(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Offset
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x",
+                   Hardware, Logical, Offset);
+
+    /* Verify the hardware. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Force a barrier. */
+    gcmkONERROR(
+        gckOS_MemoryBarrier(Hardware->os, Logical));
+
+    /* Notify gckKERNEL object of change. */
+    gcmkONERROR(
+        gckKERNEL_Notify(Hardware->kernel,
+                         gcvNOTIFY_COMMAND_QUEUE));
+
+    if (status == gcvSTATUS_CHIP_NOT_READY)
+    {
+        gcmkONERROR(gcvSTATUS_DEVICE);
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+static void
+_ResumeWaitLinkFE(
+    gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 resume;
+    gctUINT32 bytes;
+    gctUINT32 idle;
+
+    /* Make sure FE is idle. */
+    do
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             0x00004,
+                             &idle));
+    }
+    while (idle != 0x7FFFFFFF);
+
+    gcmkDUMP(Hardware->os, "@[register.wait 0x%05X 0x%08X 0x%08X]",
+             0x00004,
+             ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (~0U) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+             idle);
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                         Hardware->core,
+                         0x00664,
+                         &resume));
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                         Hardware->core,
+                         0x00664,
+                         &resume));
+
+    bytes = Hardware->hasL2Cache ? 24 : 16;
+
+    /* Start Command Parser. */
+    gckWLFE_AtomicExecute(Hardware, resume, bytes);
+
+OnError:
+    return;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_Interrupt
+**
+**  Process an interrupt. This function will read the interrupt acknowledge
+**  register, stores the data, and return whether the interrupt is from us.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Interrupt(
+    IN gckHARDWARE Hardware
+    )
+{
+    gctUINT32 data = 0;
+    gctUINT32 dataEx = 0;
+    gceSTATUS status;
+    gceSTATUS statusEx;
+
+    /*
+     * Notice:
+     * In isr here.
+     * We should return success when either FE or AsyncFE reports correct
+     * interrupts, so that isr can wake up threadRoutine for either FE.
+     * That means, only need return ERROR when both FEs reports ERROR.
+     */
+    /* Read AQIntrAcknowledge register. */
+    status = gckOS_ReadRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00010,
+                                  &data);
+
+    if (gcmIS_ERROR(status))
+    {
+        goto OnError;
+    }
+
+    if (data == 0)
+    {
+        /* Not our interrupt. */
+        status = gcvSTATUS_NOT_OUR_INTERRUPT;
+    }
+    else
+    {
+#if gcdINTERRUPT_STATISTIC
+        gckOS_AtomClearMask(Hardware->pendingEvent, data);
+#endif
+
+        if (data & (1 << 29))
+        {
+            /* Event ID 29 is not a normal event, but for invalidating pipe. */
+            _ResumeWaitLinkFE(Hardware);
+            data &= ~(1 << 29);
+        }
+
+        /* Inform gckEVENT of the interrupt. */
+        status = gckEVENT_Interrupt(Hardware->kernel->eventObj, data);
+    }
+
+    if (!Hardware->asyncFE)
+    {
+        /* Done. */
+        goto OnError;
+    }
+
+    /* Read BLT interrupt. */
+    statusEx = gckOS_ReadRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x000D4,
+        &dataEx
+        );
+
+    if (gcmIS_ERROR(statusEx))
+    {
+        /*
+         * Do not overwrite status here, so that former status from
+         * AQIntrAck is returned.
+         */
+        goto OnError;
+    }
+
+    /*
+     * This bit looks useless now, we can use this check if this interrupt is
+     * from FE.
+     */
+    dataEx &= ~0x80000000;
+
+    /*
+     * Descriptor fetched, update counter.
+     * We can't do this at dataEx != 0 only, because read HW acknowledge
+     * register will overwrite 0x007E4. If one
+     * interrupt we don't read it, we will miss it for ever.
+     */
+    gckASYNC_FE_UpdateAvaiable(Hardware);
+
+    /* Do not need report NOT_OUT_INTERRUPT error if dataEx is 0. */
+    if (dataEx)
+    {
+        statusEx = gckEVENT_Interrupt(Hardware->kernel->asyncEvent, dataEx);
+
+        if (gcmIS_SUCCESS(statusEx))
+        {
+            /* At least AsyncFE is success, treat all as success. */
+            status = gcvSTATUS_OK;
+        }
+    }
+
+OnError:
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_Notify
+**
+**  This functions will handle the event notifications.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Notify(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=%p", Hardware);
+
+    /* Handle events. */
+    status = gckEVENT_Notify(Hardware->kernel->eventObj, 0);
+
+    if (Hardware->asyncFE)
+    {
+        status = gckEVENT_Notify(Hardware->kernel->asyncEvent, 0);
+    }
+
+     gcmkFOOTER();
+     return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryCommandBuffer
+**
+**  Query the command buffer alignment and number of reserved bytes.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Alignment
+**          Pointer to a variable receiving the alignment for each command.
+**
+**      gctSIZE_T * ReservedHead
+**          Pointer to a variable receiving the number of reserved bytes at the
+**          head of each command buffer.
+**
+**      gctSIZE_T * ReservedTail
+**          Pointer to a variable receiving the number of bytes reserved at the
+**          tail of each command buffer.
+*/
+gceSTATUS
+gckHARDWARE_QueryCommandBuffer(
+    IN gckHARDWARE Hardware,
+    IN gceENGINE Engine,
+    OUT gctUINT32 * Alignment,
+    OUT gctUINT32 * ReservedHead,
+    OUT gctUINT32 * ReservedTail
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (Alignment != gcvNULL)
+    {
+        /* Align every 8 bytes. */
+        *Alignment = 8;
+    }
+
+    if (ReservedHead != gcvNULL)
+    {
+        /* Reserve space for SelectPipe(). */
+        *ReservedHead = 32;
+    }
+
+    if (ReservedTail != gcvNULL)
+    {
+        if (Engine == gcvENGINE_RENDER)
+        {
+            gcmkFOOTER_NO();
+            return gcvSTATUS_NOT_SUPPORTED;
+        }
+        else
+        {
+            *ReservedTail = gcdBLT_FENCE_LENGTH;
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu",
+                   gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead),
+                   gcmOPT_VALUE(ReservedTail));
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QuerySystemMemory
+**
+**  Query the command buffer alignment and number of reserved bytes.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * SystemSize
+**          Pointer to a variable that receives the maximum size of the system
+**          memory.
+**
+**      gctUINT32 * SystemBaseAddress
+**          Poinetr to a variable that receives the base address for system
+**          memory.
+*/
+gceSTATUS
+gckHARDWARE_QuerySystemMemory(
+    IN gckHARDWARE Hardware,
+    OUT gctSIZE_T * SystemSize,
+    OUT gctUINT32 * SystemBaseAddress
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (SystemSize != gcvNULL)
+    {
+        /* Maximum system memory can be 2GB. */
+        *SystemSize = 1U << 31;
+    }
+
+    if (SystemBaseAddress != gcvNULL)
+    {
+        /* Set system memory base address. */
+        *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)));
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu",
+                   gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress));
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_SetMMU
+**
+**  Set the page table base address.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gckMMU Mmu
+**          Pointer to mmu object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_SetMMU(
+    IN gckHARDWARE Hardware,
+    IN gckMMU Mmu
+    )
+{
+    gceSTATUS status;
+    gctUINT32 address = 0;
+
+    gcmkHEADER_ARG("Hardware=0x%x Mmu=0x%x", Hardware, Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (Hardware->mmuVersion == 0)
+    {
+        /* mmu v0 only support 1 level translation, only uses stlb level mapping. */
+        gcmkSAFECASTPHYSADDRT(address, Mmu->dynamicArea4K.stlbPhysical);
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "Setting page table to 0x%08X",
+                       address);
+
+        /* Trigger a possible dummy draw. */
+        Hardware->kernel->command->dummyDraw = gcvTRUE;
+
+        /* Write the AQMemoryFePageTable register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00400,
+                                  address));
+
+        /* Write the AQMemoryRaPageTable register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00410,
+                                  address));
+
+        /* Write the AQMemoryTxPageTable register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00404,
+                                  address));
+
+
+        /* Write the AQMemoryPePageTable register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00408,
+                                  address));
+
+        /* Write the AQMemoryPezPageTable register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x0040C,
+                                  address));
+    }
+    else
+    {
+        gctBOOL mmuValid = gcvTRUE;
+
+        gcmkONERROR(gckFUNCTION_Validate(&Hardware->functions[gcvFUNCTION_EXECUTION_MMU], &mmuValid));
+
+        if (mmuValid)
+        {
+            gctBOOL hwMmuDisabled = gcvTRUE;
+
+            /* Force Disable MMU to guarantee setup command be read from physical addr */
+            if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+            {
+                gctUINT32 regMmuCtrl = 0;
+                gcmkONERROR(gckOS_ReadRegisterEx(
+                    Hardware->os,
+                    Hardware->core,
+                    0x00388,
+                    &regMmuCtrl
+                    ));
+
+                hwMmuDisabled = ((((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0x1)
+                           ? gcvFALSE
+                           : gcvTRUE;
+            }
+            else
+            {
+                gctUINT32 regMmuCtrl = 0;
+
+                gcmkONERROR(gckOS_ReadRegisterEx(
+                    Hardware->os,
+                    Hardware->core,
+                    0x0018C,
+                    &regMmuCtrl
+                    ));
+
+                hwMmuDisabled = ((((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0x1)
+                              ? gcvFALSE
+                              : gcvTRUE;
+            }
+
+            if (hwMmuDisabled)
+            {
+                gcmkONERROR(gckFUNCTION_Execute(&Hardware->functions[gcvFUNCTION_EXECUTION_MMU]));
+
+                /* Enable MMU. */
+                if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+                {
+                    gcmkONERROR(gckOS_WriteRegisterEx_NoDump(
+                        Hardware->os,
+                        Hardware->core,
+                        0x00388,
+                        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                        ));
+                }
+                else
+                {
+                    gcmkONERROR(gckOS_WriteRegisterEx(
+                        Hardware->os,
+                        Hardware->core,
+                        0x0018C,
+                        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (gcvTRUE) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                        ));
+                }
+
+                /* Trigger a possible dummy draw. */
+                Hardware->kernel->command->dummyDraw = gcvTRUE;
+            }
+        }
+
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_FlushMMU
+**
+**  Flush the page table.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_FlushMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 SubsequentBytes,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status;
+    gctUINT32_PTR buffer;
+    gctUINT32 flushSize;
+    gctBOOL bltEngine = gcvFALSE;
+    gctBOOL multiCluster = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    if (Hardware->mmuVersion == 0)
+    {
+        flushSize = 8;
+    }
+    else
+    {
+        flushSize = 10 * 4;
+
+        bltEngine    = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE);
+        multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+
+        if (bltEngine)
+        {
+            flushSize +=  4 * 4;
+
+            if (multiCluster)
+            {
+                flushSize += 2 * 4;
+            }
+        }
+    }
+
+    if (Logical)
+    {
+        if (*Bytes < flushSize)
+        {
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Flush the memory controller. */
+        if (Hardware->mmuVersion == 0)
+        {
+            buffer = (gctUINT32_PTR)Logical;
+
+            buffer[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            buffer[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+        }
+        else
+        {
+            gctUINT32 count;
+            gctUINT32 offset = 2;
+            gctUINT32 prefetchCount = 4;
+            gctUINT32 semaphore, stall;
+
+            if (bltEngine)
+            {
+                prefetchCount += 2;
+                if (multiCluster)
+                {
+                    prefetchCount++;
+                }
+            }
+
+            buffer = (gctUINT32_PTR)Logical;
+
+            count = SubsequentBytes >> 3;
+
+            /* LINK to next slot to flush FE FIFO. */
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (prefetchCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++ = Address + offset * gcmSIZEOF(gctUINT32);
+
+            /* Flush MMU cache. */
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) &  ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))));
+
+            if (bltEngine)
+            {
+                /* Blt lock. */
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                if (multiCluster)
+                {
+                    *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x50CE) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)));
+                }
+            }
+
+            /* Arm the PE-FE Semaphore. */
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            semaphore = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+            if (Hardware->stallFEPrefetch)
+            {
+                semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28)));
+            }
+
+            if (bltEngine)
+            {
+                semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+            else
+            {
+                semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+
+            *buffer++ = semaphore;
+
+            /* STALL FE until PE is done flushing. */
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+            stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+            if (Hardware->stallFEPrefetch)
+            {
+               stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28)));
+            }
+
+            if (bltEngine)
+            {
+                stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+            else
+            {
+                stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+
+            *buffer++ = stall;
+
+            if (bltEngine)
+            {
+                /* Blt unlock. */
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+
+            /* LINK to next slot to flush FE FIFO. */
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (count) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *buffer++ = Address + flushSize;
+        }
+    }
+
+    if (Bytes)
+    {
+        *Bytes = flushSize;
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_FlushAsyncMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32 semaphore, stall;
+    gctUINT32_PTR buffer;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    if (Logical != gcvNULL)
+    {
+        buffer = (gctUINT32_PTR) Logical;
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 1,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 2,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+          ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 3,
+            (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) &  ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))))
+            ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 4,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            ));
+
+        semaphore = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+        if (Hardware->stallFEPrefetch)
+        {
+            semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28)));
+        }
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 5,
+            semaphore));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 6,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            ));
+
+        stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+        if (Hardware->stallFEPrefetch)
+        {
+           stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28)));
+        }
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 7,
+            stall));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 8,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+          ));
+
+        gcmkONERROR(gckOS_WriteMemory(
+            Hardware->os,
+            buffer + 9,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            ));
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the PIPESELECT command. */
+        *Bytes = 40;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_FlushMcfeMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status;
+    gctUINT32_PTR buffer;
+    gctUINT32 flushSize;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* MCFE with old mmu? nonsense!. */
+    gcmkASSERT(Hardware->mmuVersion > 0);
+
+    flushSize = 4 * 6;
+
+    if (Logical)
+    {
+        if (*Bytes < flushSize)
+        {
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        buffer = (gctUINT32_PTR)Logical;
+
+        /* Flush MMU cache. */
+        *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer++ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) &  ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))));
+
+        /*
+         * System channel can only take one command at a time, Trigger and
+         * SubmitJob are not required.
+         */
+
+        /* AQHiIdle to trigger. */
+        *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0001) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer++ = 0;
+
+        /* SubmitJob. */
+        *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) (0x001 & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    }
+
+    if (Bytes)
+    {
+        *Bytes = flushSize;
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_BuildVirtualAddress
+**
+**  Build a virtual address.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gctUINT32 Index
+**          Index into page table.
+**
+**      gctUINT32 Offset
+**          Offset into page.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Pointer to a variable receiving te hardware address.
+*/
+gceSTATUS
+gckHARDWARE_BuildVirtualAddress(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Index,
+    IN gctUINT32 Offset,
+    OUT gctUINT32 * Address
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    /* Build virtual address. */
+    *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+             | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:0) - (0 ?
+ 30:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:0) - (0 ?
+ 30:0) + 1))))))) << (0 ?
+ 30:0))) | (((gctUINT32) ((gctUINT32) (Offset | (Index << 12)) & ((gctUINT32) ((((1 ?
+ 30:0) - (0 ?
+ 30:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0)));
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Address=0x%08x", *Address);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_GetIdle(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Wait,
+    OUT gctUINT32 * Data
+    )
+{
+    gceSTATUS status;
+    gctUINT32 idle = 0;
+    gctINT retry, poll, pollCount;
+    gctUINT32 address;
+
+    gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+
+    /* If we have to wait, try 100 polls per millisecond. */
+    pollCount = Wait ? 100 : 1;
+
+    /* At most, try for 1 second. */
+    for (retry = 0; retry < 1000; ++retry)
+    {
+        /* If we have to wait, try 100 polls per millisecond. */
+        for (poll = pollCount; poll > 0; --poll)
+        {
+            /* Read register. */
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle));
+
+            /* Read the current FE address. */
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00664,
+                                             &address));
+
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00664,
+                                             &address));
+
+            /* See if we have to wait for FE idle. */
+            if (_IsGPUIdle(idle)
+             && (address == Hardware->lastEnd + 8)
+             )
+            {
+                /* FE is idle. */
+                break;
+            }
+        }
+
+        /* Check if we need to wait for FE and FE is busy. */
+        if (Wait && !_IsGPUIdle(idle))
+        {
+            /* Wait a little. */
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                           "%s: Waiting for idle: 0x%08X",
+                           __FUNCTION__, idle);
+
+            gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1));
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    /* Return idle to caller. */
+    *Data = idle;
+
+#if defined(EMULATOR)
+    /* Wait a little while until CModel FE gets END.
+     * END is supposed to be appended by caller.
+     */
+    gckOS_Delay(Hardware->os, 100);
+#endif
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Data=0x%08x", *Data);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/* Flush the caches. */
+gceSTATUS
+gckHARDWARE_Flush(
+    IN gckHARDWARE Hardware,
+    IN gceKERNEL_FLUSH Flush,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32 pipe;
+    gctUINT32 flush = 0;
+    gctUINT32 flushVST = 0;
+    gctBOOL flushTileStatus;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+    gctBOOL halti5;
+    gctBOOL flushICache;
+    gctBOOL flushTXDescCache;
+    gctBOOL flushTFB;
+    gctBOOL hwTFB;
+    gctBOOL blt;
+    gctBOOL peTSFlush;
+    gctBOOL multiCluster;
+
+    gcmkHEADER_ARG("Hardware=0x%x Flush=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Flush, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Get current pipe. */
+    pipe = Hardware->kernel->command->pipeSelect;
+
+    halti5 = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5);
+
+    hwTFB = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HW_TFB);
+
+    blt = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE);
+    multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+
+    peTSFlush = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX);
+
+    /* Flush tile status cache. */
+    flushTileStatus = Flush & gcvFLUSH_TILE_STATUS;
+
+    /* Flush Icache for halti5 hardware as we dont do it when program or context switches*/
+    flushICache = (Flush & gcvFLUSH_ICACHE) && halti5;
+
+    /* Flush texture descriptor cache */
+    flushTXDescCache = Flush & gcvFLUSH_TXDESC;
+
+    /* Flush USC cache for TFB client */
+    flushTFB = (Flush & gcvFLUSH_TFBHEADER) && hwTFB;
+
+    /* Flush TFB for vertex buffer */
+    if (Flush & gcvFLUSH_VERTEX)
+    {
+        if (hwTFB)
+        {
+            flushTFB = gcvTRUE;
+        }
+
+        if (multiCluster)
+        {
+            flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 14:14) - (0 ?
+ 14:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 14:14) - (0 ?
+ 14:14) + 1))))))) << (0 ?
+ 14:14))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 14:14) - (0 ?
+ 14:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 14:14) - (0 ? 14:14) + 1))))))) << (0 ? 14:14)));
+        }
+    }
+
+    /* Flush 3D color cache. */
+    if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0))
+    {
+        flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+    }
+
+    /* Flush 3D depth cache. */
+    if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0))
+    {
+        flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+    }
+
+    /* Flush 3D texture cache. */
+    if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0))
+    {
+        flush |= multiCluster ?
+ 0 : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)));
+        flushVST = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+    }
+
+    /* Flush 2D cache. */
+    if ((Flush & gcvFLUSH_2D) && (pipe == 0x1))
+    {
+        flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+    }
+
+    /* Flush L2 cache. */
+    if ((Flush & gcvFLUSH_L2) && (pipe == 0x0))
+    {
+        flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+    }
+
+    /* Vertex buffer and texture could be touched by SHL1 for SSBO and image load/store */
+    if ((Flush & (gcvFLUSH_VERTEX | gcvFLUSH_TEXTURE)) && (pipe == 0x0))
+    {
+        if (Hardware->identity.chipModel != 0x8000 || Hardware->identity.chipRevision != 0x7120 || !Hardware->options.enableNNTPParallel)
+        {
+            flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+        }
+        else
+        {
+            flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+        }
+    }
+
+    /* See if there is a valid flush. */
+    if ((flush == 0) &&
+        (flushTileStatus == gcvFALSE) &&
+        (flushICache == gcvFALSE) &&
+        (flushTXDescCache == gcvFALSE) &&
+        (flushTFB == gcvFALSE))
+    {
+        if (Bytes != gcvNULL)
+        {
+            /* No bytes required. */
+            *Bytes = 0;
+        }
+    }
+    else
+    {
+        gctBOOL appendNop = gcvFALSE;
+        gctUINT32 reserveBytes = 0;
+        gctBOOL txCacheFix = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TEX_CACHE_FLUSH_FIX)
+                           ? gcvTRUE : gcvFALSE;
+
+        /* Determine reserve bytes. */
+        if (!txCacheFix || flushICache || flushTXDescCache)
+        {
+            /* Semaphore/Stall */
+            reserveBytes += blt ? (8 * gcmSIZEOF(gctUINT32)) : (4 * gcmSIZEOF(gctUINT32));
+        }
+
+        if (flush)
+        {
+            reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        if (flushVST)
+        {
+            reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        if (flushTileStatus)
+        {
+            reserveBytes += (!peTSFlush && blt) ? 6 * gcmSIZEOF(gctUINT32) : 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        if (flushICache)
+        {
+            reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        if (flushTXDescCache)
+        {
+            reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        if (flushTFB)
+        {
+            reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+        }
+
+        /* Semaphore/Stall */
+        reserveBytes += blt ? (8 * gcmSIZEOF(gctUINT32)) : (4 * gcmSIZEOF(gctUINT32));
+
+        if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MCFE) && (reserveBytes & 8))
+        {
+            appendNop = gcvTRUE;
+            reserveBytes += 8;
+        }
+
+        /* Copy to command queue. */
+        if (Logical != gcvNULL)
+        {
+            if (*Bytes < reserveBytes)
+            {
+                /* Command queue too small. */
+                gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+            }
+
+            if (!txCacheFix || flushICache || flushTXDescCache)
+            {
+                if (blt)
+                {
+                    /* Semaphore from FE to BLT. */
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                    /* Stall from FE to BLT. */
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+                }
+                else
+                {
+                    /* Semaphore. */
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                    /* Stall. */
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+                }
+            }
+
+            if (flush)
+            {
+                /* Append LOAD_STATE to AQFlush. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *logical++ = flush;
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: FLUSH 0x%x", logical - 1, flush);
+            }
+
+            if (flushVST)
+            {
+                /* Append LOAD_STATE to AQFlush. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *logical++ = flushVST;
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: FLUSH 0x%x", logical - 1, flush);
+            }
+
+            if (flushTileStatus)
+            {
+                if (!peTSFlush && blt)
+                {
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+                }
+                else
+                {
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                    *logical++
+                        = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+                }
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                               "0x%x: FLUSH TILE STATUS 0x%x", logical - 1, logical[-1]);
+            }
+
+            if (flushICache)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                               "0x%x: FLUSH Icache 0x%x", logical - 1, logical[-1]);
+
+            }
+
+            if (flushTXDescCache)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5311) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)));
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                               "0x%x: FLUSH Icache 0x%x", logical - 1, logical[-1]);
+
+            }
+
+            if (flushTFB)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x7003) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *logical++
+                    = 0x1;
+
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                               "0x%x: FLUSH TFB cache 0x%x", logical - 1, logical[-1]);
+
+            }
+
+            if (blt)
+            {
+                /* Semaphore from FE to BLT. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall from FE to BLT. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+            }
+            else
+            {
+                /* Semaphore. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+                /* Stall. */
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+            if (appendNop)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+            }
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* bytes required. */
+            *Bytes = reserveBytes;
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_SetFastClear(
+    IN gckHARDWARE Hardware,
+    IN gctINT Enable,
+    IN gctINT Compression
+    )
+{
+#if gcdENABLE_3D
+    gctUINT32 debug;
+    gceSTATUS status;
+    gceCOMPRESSION_OPTION compression = (Compression == -1) ? gcvCOMPRESSION_OPTION_DEFAULT : (gceCOMPRESSION_OPTION)Compression;
+
+    gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d",
+                   Hardware, Enable, Compression);
+
+    /* Only process if fast clear is available. */
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_FAST_CLEAR))
+    {
+        if (Enable == -1)
+        {
+            /* Determine automatic value for fast clear. */
+            Enable = ((Hardware->identity.chipModel    != gcv500)
+                     || (Hardware->identity.chipRevision >= 3)
+                     ) ? 1 : 0;
+        }
+
+        if (compression == gcvCOMPRESSION_OPTION_DEFAULT)
+        {
+            /* Determine automatic value for compression. */
+            if (Enable)
+            {
+                if (gcvSTATUS_FALSE == gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ZCOMPRESSION))
+                {
+                    compression &= ~gcvCOMPRESSION_OPTION_DEPTH;
+                }
+            }
+            else
+            {
+                compression = gcvCOMPRESSION_OPTION_NONE;
+            }
+        }
+
+        /* Read AQMemoryDebug register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &debug));
+
+        /* Set fast clear bypass. */
+        debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)));
+
+        if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES7) ||
+            (Hardware->identity.chipModel >= gcv4000))
+        {
+            /* Set compression bypass. */
+            debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ?
+ 21:21))) | (((gctUINT32) ((gctUINT32) ((gcvCOMPRESSION_OPTION_NONE == compression) ?
+ 1 : 0) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)));
+        }
+
+        /* Write back AQMemoryDebug register. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  0x00414,
+                                  debug));
+
+        /* Store fast clear and comprersison flags. */
+        Hardware->options.allowFastClear   = Enable;
+        Hardware->options.allowCompression = compression;
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                       "FastClear=%d Compression=%d", Enable, Compression);
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+#else
+    return gcvSTATUS_OK;
+#endif
+}
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+static gctCONST_STRING
+_PowerEnum(gceCHIPPOWERSTATE State)
+{
+    const gctCONST_STRING baseStates[] =
+    {
+        "ON",
+        "IDLE",
+        "SUSPEND",
+        "OFF",
+        "ON[auto]",
+    };
+
+    const gctCONST_STRING broadcastStates[] =
+    {
+        "",
+        "IDLE[broadcast]",
+        "SUSPEND[broadcast]",
+        "OFF[broadcast]",
+    };
+
+    const gctCONST_STRING timeoutStates[] =
+    {
+        "",
+        "IDLE[timeout]",
+        "SUSPEND[timeout]",
+        "OFF[timeout]",
+    };
+
+    gcmSTATIC_ASSERT(gcvPOWER_ON == 0 && gcvPOWER_IDLE == 1 &&
+                     gcvPOWER_SUSPEND == 2 && gcvPOWER_OFF == 3 &&
+                     gcvPOWER_ON_AUTO == 4,
+                     "array subscript does not match");
+
+    if (State & gcvPOWER_FLAG_BROADCAST)
+    {
+        return broadcastStates[State & ~gcvPOWER_FLAG_BROADCAST];
+    }
+    else if (State & gcvPOWER_FLAG_TIMEOUT)
+    {
+        return timeoutStates[State & ~gcvPOWER_FLAG_TIMEOUT];
+    }
+    else if ((State >= gcvPOWER_ON) && (State <= gcvPOWER_ON_AUTO))
+    {
+        return baseStates[State - gcvPOWER_ON];
+    }
+
+    return "unknown";
+}
+#endif
+
+static gceSTATUS
+_PmClockOn(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL * RequireInit
+    )
+{
+    gceSTATUS status;
+
+    /* Turn on the power. */
+    gcmkONERROR(gckOS_SetGPUPower(Hardware->os, Hardware->core,
+                                  gcvTRUE, gcvTRUE));
+
+    Hardware->clockState = Hardware->powerState = gcvTRUE;
+
+    /* Check if GPU is present and awake. */
+    while (_IsGPUPresent(Hardware) == gcvSTATUS_GPU_NOT_RESPONDING)
+    {
+        /* Turn off the power and clock. */
+        gcmkONERROR(gckOS_SetGPUPower(Hardware->os, Hardware->core,
+                                      gcvFALSE, gcvFALSE));
+
+        Hardware->clockState = Hardware->powerState = gcvFALSE;
+
+        /* Wait a little. */
+        gckOS_Delay(Hardware->os, 1);
+
+        /* Turn on the power and clock. */
+        gcmkONERROR(gckOS_SetGPUPower(Hardware->os, Hardware->core,
+                                      gcvTRUE, gcvTRUE));
+
+        Hardware->clockState = Hardware->powerState = gcvTRUE;
+
+        if (RequireInit)
+        {
+            *RequireInit = gcvTRUE;
+        }
+    }
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_PmClockOff(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL PowerState
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_SetGPUPower(Hardware->os, Hardware->core,
+                                  gcvFALSE, PowerState));
+
+    Hardware->clockState = gcvFALSE;
+    Hardware->powerState = PowerState;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_PmClockControl(
+    IN gckHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    )
+{
+    gceSTATUS status;
+    gctUINT32 clock;
+
+    static const gctUINT clocks[4] =
+    {
+        /* gcvPOWER_ON */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))),
+
+        /* gcvPOWER_IDLE */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))),
+
+        /* gcvPOWER_SUSPEND */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))),
+
+        /* gcvPOWER_OFF */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) |
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))),
+
+    };
+
+    clock = clocks[State];
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+    if (State == gcvPOWER_ON)
+    {
+        clock = ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (Hardware->powerOnFscaleVal) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)));
+    }
+#endif
+
+    if (Hardware->clockState && Hardware->powerState
+#if gcdDVFS
+    /* Don't touch clock control if dynamic frequency scaling is available. */
+    && !gckHARDWARE_IsFeatureAvailable(Hardware,
+                                       gcvFEATURE_DYNAMIC_FREQUENCY_SCALING)
+#endif
+    )
+    {
+        if ((State == gcvPOWER_OFF) &&
+            (Hardware->identity.chipModel == gcv4000) &&
+            ((Hardware->identity.chipRevision == 0x5208) ||
+             (Hardware->identity.chipRevision == 0x5222)))
+        {
+            clock &= ~2U;
+        }
+
+        /* Write the clock control register. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core,
+                                          0x00000,
+                                          clock));
+
+        clock = ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+
+        /* Done loading the frequency scaler. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core,
+                                          0x00000,
+                                          clock));
+#if gcdENABLE_FSCALE_VAL_ADJUST
+        if (State == gcvPOWER_ON)
+        {
+            gcmkVERIFY_OK(
+                gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x0010C,
+                                     &clock));
+
+            /* fscaleSh_clkSh = clkSh[7 :1 ];
+               fscaleShLoad_clkSh = clkSh [0 ];
+               enableAutoSh_clkSh = clkSh[16 ];
+               disableAuto_clkSh = clkSh[17 ];
+            */
+            gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                              Hardware->core,
+                                              0x0010C,
+                                              (clock & ~0xFE) | (Hardware->powerOnFscaleVal << 1) | 0x20001
+                                              ));
+
+            gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                              Hardware->core,
+                                              0x0010C,
+                                              clock));
+        }
+#endif
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_PmInitializeGPU(
+    IN gckHARDWARE Hardware,
+    IN gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+
+    /* Initialize hardware. */
+    gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware));
+
+    gcmkONERROR(gckHARDWARE_SetFastClear(Hardware,
+                                         Hardware->options.allowFastClear,
+                                         Hardware->options.allowCompression));
+
+    /* Force the command queue to reload the next context. */
+    Command->currContext = gcvNULL;
+
+OnError:
+    return status;
+}
+
+/*
+ * Notice: this function may return gcvSTATUS_NOT_READY, which is not an error,
+ * but either not success.
+ */
+static gceSTATUS
+_PmStallCommand(
+    gckHARDWARE Hardware,
+    gckCOMMAND Command,
+    gctBOOL Broadcast
+    )
+{
+    gceSTATUS status;
+    gctBOOL idle;
+
+    if (Broadcast)
+    {
+        /* Check for idle. */
+        gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle));
+
+        if (!idle)
+        {
+            status = gcvSTATUS_CHIP_NOT_READY;
+            goto OnError;
+        }
+    }
+    else
+    {
+        /* Wait to finish all commands. */
+        status = gckCOMMAND_Stall(Command, gcvTRUE);
+
+        if (!gcmIS_SUCCESS(status))
+        {
+            goto OnError;
+        }
+
+        for (;;)
+        {
+            gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle));
+
+            if (idle)
+            {
+                break;
+            }
+
+            gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1));
+        }
+    }
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_PmFlushCache(
+    gckHARDWARE Hardware,
+    gckCOMMAND Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (Hardware->clockState == gcvFALSE)
+    {
+        /* Turn on the GPU power. */
+        gcmkONERROR(gckOS_SetGPUPower(Hardware->os, Hardware->core,
+                                      gcvTRUE, gcvTRUE));
+
+        Hardware->clockState = gcvTRUE;
+
+        /* Clock control, to ON state. */
+        gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_ON));
+    }
+
+    if (_IsHardwareMatch(Hardware, gcv400, 0x4645))
+    {
+        gcmkONERROR(gckCOMMAND_Start(Command));
+
+        gcmkONERROR(_FlushCache(Hardware, Command));
+        gckOS_Delay(gcvNULL, 1);
+
+        /* Stop the command parser. */
+        gcmkONERROR(gckCOMMAND_Stop(Command));
+    }
+    else
+    {
+        gcmkONERROR(gckFUNCTION_Execute(&Hardware->functions[gcvFUNCTION_EXECUTION_FLUSH]));
+        gckOS_Delay(gcvNULL, 1);
+    }
+
+OnError:
+    return status;
+}
+
+/*
+ * Put power to on direction:
+ * Off -> Suspend
+ * Off            -> Idle
+ * Off                    -> On
+ *        Suspend -> Idle
+ *        Suspend         -> On
+ *                   Idle -> On
+ */
+static gceSTATUS
+_PmSetPowerOnDirection(
+    IN gckHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    )
+{
+    gceSTATUS status;
+    gckCOMMAND command = Hardware->kernel->command;
+    gctBOOL clockOn = gcvFALSE;
+    gctBOOL requireInit = gcvFALSE;
+
+    switch (Hardware->chipPowerState)
+    {
+    case gcvPOWER_OFF:
+        if (State == gcvPOWER_SUSPEND)
+        {
+            gcmkONERROR(_PmClockOn(Hardware, gcvNULL));
+            clockOn = gcvTRUE;
+
+            /* Clock control, put to suspend. */
+            gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_SUSPEND));
+
+            /* Initialize GPU. */
+            gcmkONERROR(_PmInitializeGPU(Hardware, command));
+
+            /* Suspend: clock off, power on. */
+            gcmkONERROR(_PmClockOff(Hardware, gcvTRUE));
+            break;
+        }
+
+        requireInit = gcvTRUE;
+
+        /* FALLTHRU */
+
+    case gcvPOWER_SUSPEND:
+        /* Clock on. */
+        gcmkONERROR(_PmClockOn(Hardware, &requireInit));
+        clockOn = gcvTRUE;
+
+        /* Clock control, put to target state (On or idle). */
+        gcmkONERROR(_PmClockControl(Hardware, State));
+
+        /* Delay. */
+        gcmkONERROR(gckOS_Delay(Hardware->os, gcdPOWER_CONTROL_DELAY));
+
+        if (requireInit)
+        {
+            /* Initialize. */
+            gcmkONERROR(_PmInitializeGPU(Hardware, command));
+        }
+
+        /* Start. */
+        gcmkONERROR(gckCOMMAND_Start(command));
+        break;
+
+    case gcvPOWER_IDLE:
+        /* Clock control, put to ON state. */
+        gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_ON));
+        break;
+
+    default:
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (clockOn)
+    {
+        gctBOOL powerState =
+            (Hardware->chipPowerState == gcvPOWER_SUSPEND);
+
+        _PmClockOff(Hardware, powerState);
+    }
+
+    return status;
+}
+
+/*
+ * Put power to off direction:
+ * On -> Idle
+ * On         -> Suspend
+ * On                    -> Off
+ *       Idle -> Suspend
+ *       Idle            -> Off
+ *               Suspend -> Off
+ */
+static gceSTATUS
+_PmSetPowerOffDirection(
+    IN gckHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State,
+    IN gctBOOL Broadcast
+    )
+{
+    gceSTATUS status;
+    gckCOMMAND command = Hardware->kernel->command;
+
+    switch (Hardware->chipPowerState)
+    {
+    case gcvPOWER_ON:
+        if(Hardware->kernel->threadInitialized == gcvTRUE)
+        {
+            /* Stall. */
+            status = _PmStallCommand(Hardware, command, Broadcast);
+
+            if (!gcmIS_SUCCESS(status))
+            {
+                /* abort for error and NOT READY. */
+                goto OnError;
+            }
+        }
+
+        if (State == gcvPOWER_IDLE)
+        {
+            gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_IDLE));
+            break;
+        }
+
+        /* FALLTHRU */
+
+    case gcvPOWER_IDLE:
+        /* Stop. */
+        gcmkONERROR(gckCOMMAND_Stop(command));
+
+        if (State == gcvPOWER_SUSPEND)
+        {
+            /* Clock control, put to suspend state. */
+            gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_SUSPEND));
+
+            /* Power on, clock off. */
+            gcmkONERROR(_PmClockOff(Hardware, gcvTRUE));
+            break;
+        }
+
+        /* FALLTHRU */
+
+    case gcvPOWER_SUSPEND:
+        if(Hardware->kernel->threadInitialized == gcvTRUE)
+        {
+            /* Flush. */
+            gcmkONERROR(_PmFlushCache(Hardware, command));
+        }
+
+        /* Clock control. */
+        gcmkONERROR(_PmClockControl(Hardware, gcvPOWER_OFF));
+
+        /* Power off, clock off. */
+        gcmkONERROR(_PmClockOff(Hardware, gcvFALSE));
+
+        break;
+
+    default:
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_SetPowerState
+**
+**  Set GPU to a specified power state.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gceCHIPPOWERSTATE State
+**          Power State.
+**
+*/
+gceSTATUS
+gckHARDWARE_SetPowerState(
+    IN gckHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    )
+{
+    gceSTATUS status;
+    gckCOMMAND command = gcvNULL;
+    gckOS os;
+    gctBOOL acquired = gcvFALSE;
+    gctBOOL mutexAcquired = gcvFALSE;
+    gctBOOL broadcast = gcvFALSE;
+    gctBOOL timeout = gcvFALSE;
+    gceCHIPPOWERSTATE state = gcvPOWER_INVALID;
+
+    /*
+     * Acquire globalSempahore when set to to global OFF, IDLE, SUSPEND, then
+     * can not switch to non-global state unless global ON comes and release
+     * the globalSemaphore.
+     */
+    gctBOOL global = gcvFALSE;
+    gctBOOL globalAcquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State);
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "Switching to power state %d(%s)",
+                   State, _PowerEnum(State));
+#endif
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    os = Hardware->os;
+    command = Hardware->kernel->command;
+
+    /* Convert power state. */
+    switch (State)
+    {
+    case gcvPOWER_ON:
+    case gcvPOWER_OFF:
+    case gcvPOWER_IDLE:
+    case gcvPOWER_SUSPEND:
+        global = gcvTRUE;
+        state  = State;
+        break;
+
+    case gcvPOWER_ON_AUTO:
+        state = gcvPOWER_ON;
+        break;
+
+    case gcvPOWER_OFF_TIMEOUT:
+    case gcvPOWER_IDLE_TIMEOUT:
+    case gcvPOWER_SUSPEND_TIMEOUT:
+        timeout   = gcvTRUE;
+        /* FALLTHRU */
+    case gcvPOWER_OFF_BROADCAST:
+    case gcvPOWER_IDLE_BROADCAST:
+    case gcvPOWER_SUSPEND_BROADCAST:
+        broadcast = gcvTRUE;
+        state     = State & ~(gcvPOWER_FLAG_BROADCAST | gcvPOWER_FLAG_TIMEOUT);
+        break;
+
+    case gcvPOWER_INVALID:
+        /* Canceled, nothing to do. */
+        status = gcvSTATUS_OK;
+        goto OnError;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (global == gcvFALSE &&
+        Hardware->options.powerManagement == gcvFALSE &&
+        (Hardware->chipPowerState == gcvPOWER_ON || state != gcvPOWER_ON))
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    if (broadcast)
+    {
+        /* Try to acquire the power mutex. */
+        status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0);
+
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+            /* Pm in progress, abort. */
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+    }
+    else
+    {
+        /* Acquire the power mutex. */
+        status = gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE);
+    }
+
+    gcmkONERROR(status);
+    mutexAcquired = gcvTRUE;
+
+    if (Hardware->chipPowerState == state)
+    {
+        /* No state change. */
+        gckOS_ReleaseMutex(os, Hardware->powerMutex)
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    if (broadcast &&
+        state == gcvPOWER_SUSPEND && Hardware->chipPowerState == gcvPOWER_OFF)
+    {
+        /* Do nothing, donot change chipPowerState. */
+        gckOS_ReleaseMutex(os, Hardware->powerMutex)
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    if (timeout)
+    {
+        if (Hardware->nextPowerState == gcvPOWER_INVALID)
+        {
+            /* delayed power state change is canceled. */
+            gckOS_ReleaseMutex(os, Hardware->powerMutex)
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+    }
+
+    if (global)
+    {
+        if (state != gcvPOWER_ON)
+        {
+            /*
+             * Switch to global non-ON (OFF, IDLE or SUSPEND), try acquire the
+             * global semaphore if it has not been acquired.
+             */
+            status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+
+            if (status == gcvSTATUS_OK)
+            {
+                globalAcquired = gcvTRUE;
+            }
+            else if (status == gcvSTATUS_TIMEOUT)
+            {
+                /*
+                 * Ignore and leave globalSemaphore not acquired in this try.
+                 * In this condition, power state is changing between global
+                 * OFF, SUSPEND and IDLE, which is allowed.
+                 */
+                gcmkASSERT(Hardware->chipPowerState != gcvPOWER_ON);
+            }
+            else
+            {
+                /* Other errors. */
+                gcmkONERROR(status);
+            }
+        }
+    }
+    else
+    {
+        /* Try to acquire the global semaphore. */
+        status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+            /* In global SUSPEND, IDLE, or OFF state. */
+            gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+            mutexAcquired = gcvFALSE;
+
+            if (broadcast)
+            {
+                /* Abort power state change. */
+                gcmkFOOTER_NO();
+                return gcvSTATUS_OK;
+            }
+
+            /*
+             * Only ON_AUTO can run here.
+             * ON_AUTO state can not be skipped, either can not change a global
+             * state.
+             * So we need to wait until global ON state here.
+             */
+            gcmkONERROR(gckOS_AcquireSemaphore(os, Hardware->globalSemaphore));
+            globalAcquired = gcvTRUE;
+
+            /* Acquire the power mutex. */
+            gcmkONERROR(gckOS_AcquireMutex(os,
+                                           Hardware->powerMutex,
+                                           gcvINFINITE));
+            mutexAcquired = gcvTRUE;
+
+            if (Hardware->chipPowerState == state)
+            {
+                /* Done. */
+                status = gcvSTATUS_OK;
+                goto OnError;
+            }
+        }
+        else
+        {
+            /* Check error. */
+            gcmkONERROR(status);
+        }
+
+        /* We just check if in non-global state, but need not to acquire it. */
+        gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore));
+        globalAcquired = gcvFALSE;
+    }
+
+    if (Hardware->chipPowerState == gcvPOWER_ON)
+    {
+        /* Switch from power ON to other non-runnable states. */
+        if (broadcast)
+        {
+            gctINT32 atomValue;
+
+            /* Try to acquire the semaphore to block/sync with commit. */
+            status = gckOS_TryAcquireSemaphore(os, command->powerSemaphore);
+
+            if (gcmIS_ERROR(status))
+            {
+                status = gcvSTATUS_CHIP_NOT_READY;
+                goto OnError;
+            }
+
+            acquired = gcvTRUE;
+
+            /* Check commit atom, abort when commit is in progress. */
+            gcmkONERROR(gckOS_AtomGet(Hardware->os,
+                                      command->atomCommit,
+                                      &atomValue));
+
+            if (atomValue > 0)
+            {
+                status = gcvSTATUS_CHIP_NOT_READY;
+                goto OnError;
+            }
+        }
+        else
+        {
+            /* Acquire/wait the semaphore to block/sync with command commit. */
+            gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+            acquired = gcvTRUE;
+        }
+    }
+
+    /* Do hardware power state change. */
+    if (Hardware->chipPowerState < state)
+    {
+        /* On to off direction. */
+        gcmkONERROR(_PmSetPowerOffDirection(Hardware, state, broadcast));
+    }
+    else
+    {
+        /* Off to on direction. */
+        gcmkONERROR(_PmSetPowerOnDirection(Hardware, state));
+    }
+
+    if (status == gcvSTATUS_CHIP_NOT_READY)
+    {
+        /* CHIP_NOT_READY is not an error, either not success. */
+        goto OnError;
+    }
+
+    if (state == gcvPOWER_ON)
+    {
+        /* Switched to power ON from other non-runnable states. */
+        gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore));
+        acquired = gcvFALSE;
+
+        if (global)
+        {
+            /*
+             * Global semaphore should be acquired already before, when
+             * global OFF, IDLE or SUSPEND.
+             */
+            status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+            if (status != gcvSTATUS_TIMEOUT && Hardware->isLastPowerGlobal)
+            {
+                gcmkONERROR(status);
+            }
+
+            /* Switched to global ON, now release the global semaphore. */
+            gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore));
+            globalAcquired = gcvFALSE;
+        }
+    }
+
+    gckSTATETIMER_Accumulate(&Hardware->powerStateCounter,
+                             Hardware->chipPowerState);
+
+    /* Save the new power state. */
+    Hardware->chipPowerState = state;
+    Hardware->isLastPowerGlobal = global;
+
+#if gcdDVFS
+    if (state == gcvPOWER_ON && Hardware->kernel->dvfs)
+    {
+        gckDVFS_Start(Hardware->kernel->dvfs);
+    }
+#endif
+
+    if (!broadcast)
+    {
+        /*
+         * Cancel delayed power state change.
+         * Stop timer is not as good as set as no state change. Timer may run
+         * into this function already when try to to stop the timer.
+         */
+        Hardware->nextPowerState = gcvPOWER_INVALID;
+    }
+
+#if gcdPOWEROFF_TIMEOUT
+    if (state == gcvPOWER_IDLE || state == gcvPOWER_SUSPEND)
+    {
+        /* Delayed power off. */
+        Hardware->nextPowerState = gcvPOWER_OFF_TIMEOUT;
+
+        /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */
+        gcmkVERIFY_OK(gckOS_StartTimer(os, Hardware->powerStateTimer, gcdPOWEROFF_TIMEOUT));
+    }
+#endif
+
+    /* Release the power mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release semaphore. */
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+                                             command->powerSemaphore));
+    }
+
+    if (globalAcquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+                                             Hardware->globalSemaphore));
+    }
+
+    if (mutexAcquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryPowerState
+**
+**  Get GPU power state.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gceCHIPPOWERSTATE* State
+**          Power State.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryPowerState(
+    IN gckHARDWARE Hardware,
+    OUT gceCHIPPOWERSTATE* State
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(State != gcvNULL);
+
+    /* Return the statue. */
+    *State = Hardware->chipPowerState;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*State=%d", *State);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_EnablePowerManagement
+**
+**  Configure GPU power management function.
+**  Only used in driver initialization stage.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gctBOOL Enable
+**          Power Mangement Enabling State.
+**
+*/
+gceSTATUS
+gckHARDWARE_EnablePowerManagement(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Enable
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (_IsHardwareMatch(Hardware, gcv7000, 0x6008))
+    {
+        Enable = gcvFALSE;
+    }
+
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE));
+
+    Hardware->options.powerManagement = Enable;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_SetGpuProfiler
+**
+**  Configure GPU profiler function.
+**  Only used in driver initialization stage.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gctBOOL GpuProfiler
+**          GOU Profiler State.
+**
+*/
+gceSTATUS
+gckHARDWARE_SetGpuProfiler(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL GpuProfiler
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (GpuProfiler == gcvTRUE)
+    {
+        gctUINT32 data = 0;
+
+        /* Need to disable clock gating when doing profiling. */
+        gcmkVERIFY_OK(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress +
+                                 0x00100,
+                                 &data));
+
+        data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+
+        gcmkVERIFY_OK(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  Hardware->powerBaseAddress
+                                  + 0x00100,
+                                  data));
+    }
+
+    Hardware->options.gpuProfiler= GpuProfiler;
+
+    if (GpuProfiler == gcvTRUE)
+    {
+        Hardware->waitCount = 200 * 100;
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+gceSTATUS
+gckHARDWARE_SetFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32   FscaleValue,
+    IN gctUINT32   ShaderFscaleValue
+    )
+{
+    gceSTATUS status;
+    gctUINT32 clock;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x FscaleValue=%d", Hardware, FscaleValue);
+
+    gcmkVERIFY_ARGUMENT(FscaleValue > 0 && FscaleValue <= 64);
+
+    gcmkONERROR(
+        gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE));
+    acquired =  gcvTRUE;
+
+    Hardware->kernel->timeOut = Hardware->kernel->timeOut * Hardware->powerOnFscaleVal / 64;
+
+    Hardware->powerOnFscaleVal = FscaleValue;
+
+    Hardware->kernel->timeOut = Hardware->kernel->timeOut * 64 / Hardware->powerOnFscaleVal;
+
+    if (Hardware->chipPowerState == gcvPOWER_ON)
+    {
+        gctUINT32 data;
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+                                 Hardware->core,
+                                 Hardware->powerBaseAddress
+                                 + 0x00104,
+                                 &data));
+
+        /* Disable all clock gating. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  Hardware->powerBaseAddress
+                                  + 0x00104,
+                                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)))
+                                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)))));
+
+        /* Scale the core clock. */
+        clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (FscaleValue) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00000,
+                                          clock));
+
+        /* Done loading the frequency scaler. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00000,
+                                          ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)))));
+
+        /* A option to support shader clock scaling. */
+        if (ShaderFscaleValue != ~0U && ShaderFscaleValue > 0 && ShaderFscaleValue < 64)
+        {
+            /* Scale the shader clock. */
+            clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1))))))) << (0 ?
+ 7:1))) | (((gctUINT32) ((gctUINT32) (ShaderFscaleValue) & ((gctUINT32) ((((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:1) - (0 ? 7:1) + 1))))))) << (0 ? 7:1)))
+                  | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+
+            gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                              Hardware->core,
+                                              0x0010C,
+                                              clock));
+
+            /* Done loading the frequency scaler. */
+            gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                              Hardware->core,
+                                              0x0010C,
+                                              ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+        }
+
+        /* Restore all clock gating. */
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os,
+                                  Hardware->core,
+                                  Hardware->powerBaseAddress
+                                  + 0x00104,
+                                  data));
+    }
+
+    gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT * FscaleValue,
+    IN gctUINT * MinFscaleValue,
+    IN gctUINT * MaxFscaleValue
+    )
+{
+    *FscaleValue = Hardware->powerOnFscaleVal;
+    *MinFscaleValue = Hardware->minFscaleValue;
+    *MaxFscaleValue = 64;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_SetMinFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT MinFscaleValue
+    )
+{
+    if (_IsHardwareMatch(Hardware, gcv600, 0x4653)
+        || _IsHardwareMatch(Hardware, gcv400, 0x4645))
+    {
+        if (MinFscaleValue < MIN_FSCALE_LIMIT)
+        {
+            MinFscaleValue = MIN_FSCALE_LIMIT;
+        }
+    }
+
+    if (MinFscaleValue >= 1 && MinFscaleValue <= 64)
+    {
+        Hardware->minFscaleValue = MinFscaleValue;
+    }
+
+    return gcvSTATUS_OK;
+}
+#endif
+
+gceSTATUS
+gckHARDWARE_QueryIdle(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL_PTR IsIdle
+    )
+{
+    gceSTATUS status;
+    gctUINT32 idle;
+#if !gcdSECURITY
+    gctUINT32 address;
+    gctUINT32 dmaLow;
+    gctUINT32 opCode;
+#endif
+    gctBOOL isIdle = gcvFALSE;
+
+#if gcdINTERRUPT_STATISTIC
+    gckEVENT eventObj = Hardware->kernel->eventObj;
+    gctINT32 pendingInterrupt;
+#endif
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+#if gcdCAPTURE_ONLY_MODE
+    *IsIdle = gcvTRUE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+#endif
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL);
+
+    do
+    {
+        /* We are idle when the power is not ON. */
+        if (Hardware->chipPowerState != gcvPOWER_ON)
+        {
+            isIdle = gcvTRUE;
+            break;
+        }
+
+        if (Hardware->mcFE)
+        {
+            gctBOOL isIdle;
+
+            gcmkONERROR(gckMCFE_HardwareIdle(Hardware, &isIdle));
+
+            if(!isIdle)
+            {
+                break;
+            }
+        }
+        else
+        {
+            /* Read idle register. */
+            gcmkONERROR(
+                gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle));
+
+            /* Pipe must be idle. */
+            if ((idle | (1 << 14)) != 0x7ffffffe)
+            {
+                /* Something is busy. */
+                break;
+            }
+
+#if gcdSECURITY
+            isIdle = gcvTRUE;
+            break;
+#else
+            /* Read the current FE address. */
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00664,
+                                             &address));
+
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00664,
+                                             &address));
+
+            /* Test if address is inside the last WAIT/LINK sequence. */
+            if ((address < Hardware->lastWaitLink) ||
+                (address >= (gctUINT64)Hardware->lastWaitLink + 16))
+            {
+                /* FE is not in WAIT/LINK yet. */
+                break;
+            }
+
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00668,
+                                             &dmaLow));
+
+            gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                             Hardware->core,
+                                             0x00668,
+                                             &dmaLow));
+
+            opCode = dmaLow >> 27;
+
+            /* Test if current command buffer is WAIT/LINK . */
+            if (opCode != 0x7 && opCode != 0x8)
+            {
+                /* FE is not in WAIT/LINK yet. */
+                break;
+            }
+#endif
+        } /* end of else */
+
+#if gcdINTERRUPT_STATISTIC
+        gcmkONERROR(gckOS_AtomGet(
+            Hardware->os,
+            eventObj->interruptCount,
+            &pendingInterrupt
+            ));
+
+        if (pendingInterrupt)
+        {
+            /* Pending interrupts, not idle. */
+            break;
+        }
+
+        if (Hardware->asyncFE)
+        {
+            gckEVENT asyncEvent = Hardware->kernel->asyncEvent;
+
+            gcmkONERROR(gckOS_AtomGet(
+                Hardware->os,
+                asyncEvent->interruptCount,
+                &pendingInterrupt
+                ));
+
+            if (pendingInterrupt)
+            {
+                /* Pending async FE interrupts, not idle. */
+                break;
+            }
+        }
+#endif
+
+        /* Is really idle. */
+        isIdle = gcvTRUE;
+    }
+    while (gcvFALSE);
+
+    *IsIdle = isIdle;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+** Handy macros that will help in reading those debug registers.
+*/
+#define gcmkREAD_DEBUG_REGISTER_PART1(control, block, index, data) \
+    gcmkONERROR(\
+        gckOS_WriteRegisterEx(Hardware->os, \
+                              Hardware->core, \
+                              GC_DEBUG_CONTROL##control##_Address, \
+                              gcmSETFIELD(0, \
+                                          GC_DEBUG_CONTROL##control, \
+                                          block, \
+                                          index))); \
+    gcmkONERROR(\
+        gckOS_ReadRegisterEx(Hardware->os, \
+                             Hardware->core, \
+                             GC_DEBUG_SIGNALS_##block##_Address, \
+                             &profiler_part1->data))
+
+#define gcmkREAD_DEBUG_REGISTER_PART2(control, block, index, data) \
+    gcmkONERROR(\
+        gckOS_WriteRegisterEx(Hardware->os, \
+                              Hardware->core, \
+                              GC_DEBUG_CONTROL##control##_Address, \
+                              gcmSETFIELD(0, \
+                                          GC_DEBUG_CONTROL##control, \
+                                          block, \
+                                          index))); \
+    gcmkONERROR(\
+        gckOS_ReadRegisterEx(Hardware->os, \
+                             Hardware->core, \
+                             GC_DEBUG_SIGNALS_##block##_Address, \
+                             &profiler_part2->data))
+
+#define gcmkREAD_DEBUG_REGISTER_N(control, block, index, data) \
+    gcmkONERROR(\
+        gckOS_WriteRegisterEx(Hardware->os, \
+                              Hardware->core, \
+                              GC_DEBUG_CONTROL##control##_Address, \
+                              gcmSETFIELD(0, \
+                                          GC_DEBUG_CONTROL##control, \
+                                          block, \
+                                          index))); \
+    gcmkONERROR(\
+        gckOS_ReadRegisterEx(Hardware->os, \
+                             Hardware->core, \
+                             GC_DEBUG_SIGNALS_##block##_Address, \
+                             &data))
+
+#define gcmkRESET_DEBUG_REGISTER(control, block, value) \
+    gcmkONERROR(\
+        gckOS_WriteRegisterEx(Hardware->os, \
+                              Hardware->core, \
+                              GC_DEBUG_CONTROL##control##_Address, \
+                              gcmSETFIELD(0, \
+                                          GC_DEBUG_CONTROL##control, \
+                                          block, \
+                                          value))); \
+    gcmkONERROR(\
+        gckOS_WriteRegisterEx(Hardware->os, \
+                              Hardware->core, \
+                              GC_DEBUG_CONTROL##control##_Address, \
+                              gcmSETFIELD(0, \
+                                          GC_DEBUG_CONTROL##control, \
+                                          block, \
+                                          0)))
+
+static gctUINT32
+CalcDelta(
+    IN gctUINT32 newval,
+    IN gctUINT32 oldval
+    )
+{
+    if (newval >= oldval)
+    {
+        return newval - oldval;
+    }
+    else
+    {
+        return (gctUINT32)((gctUINT64)newval + 0x100000000ll - oldval);
+    }
+}
+
+
+#if USE_SW_RESET
+#define gcmkRESET_PROFILE_DATA_PART1(counterName) \
+    temp = profiler_part1->counterName; \
+    profiler_part1->counterName = CalcDelta(temp, Context->preProfiler_part1.counterName); \
+    Context->preProfiler_part1.counterName = temp
+#endif
+
+#define gcmkUPDATE_PROFILE_DATA_PART1(data) \
+    profilerHistroy_part1->data += profiler_part1->data
+#define gcmkUPDATE_PROFILE_DATA_PART2(data) \
+    profilerHistroy_part2->data += profiler_part2->data
+
+gceSTATUS
+gckHARDWARE_QueryContextProfile(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Reset,
+    IN gckCONTEXT Context,
+    OUT gcsPROFILER_COUNTERS_PART1 * Counters_part1,
+    OUT gcsPROFILER_COUNTERS_PART2 * Counters_part2
+)
+{
+    gceSTATUS status;
+    gckCOMMAND command = Hardware->kernel->command;
+    gcsPROFILER_COUNTERS_PART1 * profiler_part1 = Counters_part1;
+    gcsPROFILER_COUNTERS_PART2 * profiler_part2 = Counters_part2;
+
+    gcmkHEADER_ARG("Hardware=0x%x Counters_part1=0x%x, Counters_part2=0x%x", Hardware, Counters_part1, Counters_part2);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (!Context)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+    /* Acquire the context sequnence mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        command->os, command->mutexContextSeq, gcvINFINITE
+        ));
+
+    /* Read the counters. */
+    if (Counters_part1)
+    {
+        gcmkVERIFY_OK(gckOS_MemCopy(
+            profiler_part1, &Context->histroyProfiler_part1, gcmSIZEOF(gcsPROFILER_COUNTERS_PART1)
+            ));
+    }
+    else if (Counters_part2)
+    {
+        gcmkVERIFY_OK(gckOS_MemCopy(
+            profiler_part2, &Context->histroyProfiler_part2, gcmSIZEOF(gcsPROFILER_COUNTERS_PART2)
+            ));
+    }
+
+    /* Reset counters. */
+    if (Reset)
+    {
+        if (Counters_part1)
+        {
+            gcmkVERIFY_OK(gckOS_ZeroMemory(
+                &Context->histroyProfiler_part1, gcmSIZEOF(gcsPROFILER_COUNTERS_PART1)
+                ));
+        }
+        else if (Counters_part2)
+        {
+            gcmkVERIFY_OK(gckOS_ZeroMemory(
+                &Context->histroyProfiler_part2, gcmSIZEOF(gcsPROFILER_COUNTERS_PART2)
+                ));
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(
+        command->os, command->mutexContextSeq
+        ));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_UpdateContextProfile(
+    IN gckHARDWARE Hardware,
+    IN gckCONTEXT Context
+)
+{
+    gceSTATUS status;
+    gcsPROFILER_COUNTERS_PART1 * profiler_part1 = &Context->latestProfiler_part1;
+    gcsPROFILER_COUNTERS_PART1 * profilerHistroy_part1 = &Context->histroyProfiler_part1;
+    gcsPROFILER_COUNTERS_PART2 * profiler_part2 = &Context->latestProfiler_part2;
+    gcsPROFILER_COUNTERS_PART2 * profilerHistroy_part2 = &Context->histroyProfiler_part2;
+    gceCHIPMODEL chipModel;
+    gctUINT32 chipRevision;
+    gctUINT32 i;
+    gctUINT32 resetValue = 0xF;
+    gctBOOL newCounters0 = gcvFALSE;
+    gctUINT32 clock;
+    gctUINT32 colorKilled = 0, colorDrawn = 0, depthKilled = 0, depthDrawn = 0;
+    gctUINT32 totalRead, totalWrite;
+    gctUINT32 mc_axi_max_min_latency;
+    gctUINT32 temp;
+    gckCOMMAND command = Hardware->kernel->command;
+    gctBOOL mutexAcquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x Context=0x%x", Hardware, Context);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+    /* Acquire the context sequnence mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        command->os, command->mutexContextSeq, gcvINFINITE
+        ));
+    mutexAcquired = gcvTRUE;
+
+    chipModel = Hardware->identity.chipModel;
+    chipRevision = Hardware->identity.chipRevision;
+    if ((chipModel == gcv5000 && chipRevision == 0x5434) || (chipModel == gcv3000 && chipRevision == 0x5435))
+    {
+        resetValue = 0xFF;
+        newCounters0 = gcvTRUE;
+    }
+    if (chipModel == gcv2100 || chipModel == gcv2000 || chipModel == gcv880)
+    {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00438,
+            &profiler_part2->hi_total_cycle_count));
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00078,
+            &profiler_part2->hi_total_idle_cycle_count));
+    }
+    else
+    {
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00078,
+            &profiler_part2->hi_total_cycle_count));
+
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x0007C,
+            &profiler_part2->hi_total_idle_cycle_count));
+    }
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_cycle_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_idle_cycle_count);
+
+    /* Read clock control register. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x00000,
+                                     &clock));
+
+    profiler_part2->hi_total_read_8B_count = 0;
+    profiler_part2->hi_total_write_8B_count = 0;
+    profiler_part2->hi_total_readOCB_16B_count = 0;
+    profiler_part2->hi_total_writeOCB_16B_count = 0;
+    profiler_part1->pe0_pixel_count_drawn_by_color_pipe = 0;
+    profiler_part1->pe0_pixel_count_drawn_by_depth_pipe = 0;
+    profiler_part1->pe0_pixel_count_killed_by_color_pipe = 0;
+    profiler_part1->pe0_pixel_count_killed_by_depth_pipe = 0;
+    profiler_part1->pe1_pixel_count_drawn_by_color_pipe = 0;
+    profiler_part1->pe1_pixel_count_drawn_by_depth_pipe = 0;
+    profiler_part1->pe1_pixel_count_killed_by_color_pipe = 0;
+    profiler_part1->pe1_pixel_count_killed_by_depth_pipe = 0;
+
+    /* Walk through all avaiable pixel pipes. */
+    for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+    {
+        /* Select proper pipe. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00000,
+            ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ?
+ 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20)))));
+
+        /* BW */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00040,
+            &totalRead));
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00044,
+            &totalWrite));
+
+        profiler_part2->hi_total_read_8B_count += totalRead;
+        profiler_part2->hi_total_write_8B_count += totalWrite;
+
+        /* OCB-only BW */
+        if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_OCB_COUNTER))
+        {
+            if (Hardware->identity.customerID == 0x7e ||
+                Hardware->identity.customerID == 0x7d)
+            {
+                gcmkONERROR(
+                    gckOS_ReadRegisterEx(Hardware->os,
+                    Hardware->core,
+                    0x17E00,
+                    &totalRead));
+                gcmkONERROR(
+                    gckOS_ReadRegisterEx(Hardware->os,
+                    Hardware->core,
+                    0x17E10,
+                    &totalWrite));
+            }
+            else
+            {
+                gcmkONERROR(
+                    gckOS_ReadRegisterEx(Hardware->os,
+                    Hardware->core,
+                    0x005C0,
+                    &totalRead));
+                gcmkONERROR(
+                    gckOS_ReadRegisterEx(Hardware->os,
+                    Hardware->core,
+                    0x005D0,
+                    &totalWrite));
+
+            }
+        }
+        else
+        {
+            totalRead = 0;
+            totalWrite = 0;
+        }
+
+
+        profiler_part2->hi_total_readOCB_16B_count += totalRead;
+        profiler_part2->hi_total_writeOCB_16B_count += totalWrite;
+
+        /* PE */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorKilled));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthKilled));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &colorDrawn));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &depthDrawn));
+
+
+        if (i == 0)
+        {
+            profiler_part1->pe0_pixel_count_killed_by_color_pipe = colorKilled;
+            profiler_part1->pe0_pixel_count_killed_by_depth_pipe = depthKilled;
+            profiler_part1->pe0_pixel_count_drawn_by_color_pipe = colorDrawn;
+            profiler_part1->pe0_pixel_count_drawn_by_depth_pipe = depthDrawn;
+        }
+        else if (i == 1)
+        {
+            profiler_part1->pe1_pixel_count_killed_by_color_pipe = colorKilled;
+            profiler_part1->pe1_pixel_count_killed_by_depth_pipe = depthKilled;
+            profiler_part1->pe1_pixel_count_drawn_by_color_pipe = colorDrawn;
+            profiler_part1->pe1_pixel_count_drawn_by_depth_pipe = depthDrawn;
+        }
+    }
+
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_read_8B_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_write_8B_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_readOCB_16B_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi_total_writeOCB_16B_count);
+#if USE_SW_RESET
+    gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_color_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_depth_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_color_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_depth_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_color_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_depth_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_color_pipe);
+    gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_depth_pipe);
+#endif
+    gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_color_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_depth_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_color_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_depth_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_color_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_depth_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_color_pipe);
+    gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_depth_pipe);
+
+    /* Reset clock control register. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+        Hardware->core,
+        0x00000,
+        clock));
+
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0));
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00078, 0));
+
+#if !USE_SW_RESET
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+));
+#endif
+
+    /* FE */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_draw_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_out_vertex_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_cache_miss_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_cache_lk_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_stall_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_process_count));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+));
+
+    gcmkUPDATE_PROFILE_DATA_PART1(fe_draw_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(fe_out_vertex_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(fe_cache_miss_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(fe_cache_lk_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(fe_process_count);
+
+    /* SH */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_inst_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_rendered_pixel_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_inst_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_rendered_vertice_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_branch_inst_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_texld_inst_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_branch_inst_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_texld_inst_counter));
+    if (newCounters0)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_non_idle_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_process_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_non_idle_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (22) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_process_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->shader_cycle_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (23) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_non_idle_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (25) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (26) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_process_count));
+    }
+#if USE_SW_RESET
+    gcmkRESET_PROFILE_DATA_PART1(ps_inst_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ps_rendered_pixel_counter);
+    gcmkRESET_PROFILE_DATA_PART1(vs_inst_counter);
+    gcmkRESET_PROFILE_DATA_PART1(vs_rendered_vertice_counter);
+    gcmkRESET_PROFILE_DATA_PART1(vs_branch_inst_counter);
+    gcmkRESET_PROFILE_DATA_PART1(vs_texld_inst_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ps_branch_inst_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ps_texld_inst_counter);
+    if (newCounters0)
+    {
+        gcmkRESET_PROFILE_DATA_PART1(vs_non_idle_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(vs_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(vs_stall_count);
+        gcmkRESET_PROFILE_DATA_PART1(vs_process_count);
+        gcmkRESET_PROFILE_DATA_PART1(ps_non_idle_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(ps_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(ps_stall_count);
+        gcmkRESET_PROFILE_DATA_PART1(ps_process_count);
+        gcmkRESET_PROFILE_DATA_PART1(shader_cycle_count);
+        gcmkRESET_PROFILE_DATA_PART1(tx_non_idle_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(tx_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(tx_stall_count);
+        gcmkRESET_PROFILE_DATA_PART1(tx_process_count);
+    }
+#endif
+    gcmkUPDATE_PROFILE_DATA_PART1(ps_inst_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ps_rendered_pixel_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(vs_inst_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(vs_rendered_vertice_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(vs_branch_inst_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(vs_texld_inst_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ps_branch_inst_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ps_texld_inst_counter);
+    if (newCounters0)
+    {
+        gcmkUPDATE_PROFILE_DATA_PART1(vs_non_idle_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(vs_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(vs_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(vs_process_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ps_non_idle_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ps_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ps_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ps_process_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(shader_cycle_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(tx_non_idle_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(tx_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(tx_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(tx_process_count);
+    }
+#if !USE_SW_RESET
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24)))
+));
+#endif
+
+    /* PA */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_input_vtx_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_input_prim_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_output_prim_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_depth_clipped_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_trivial_rejected_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_culled_prim_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_droped_prim_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_frustum_clipped_prim_counter));
+    if (newCounters0)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_non_idle_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_process_count));
+    }
+#if USE_SW_RESET
+    gcmkRESET_PROFILE_DATA_PART1(pa_input_vtx_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_input_prim_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_output_prim_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_depth_clipped_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_trivial_rejected_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_culled_prim_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_droped_prim_counter);
+    gcmkRESET_PROFILE_DATA_PART1(pa_frustum_clipped_prim_counter);
+    if (newCounters0)
+    {
+        gcmkRESET_PROFILE_DATA_PART1(pa_non_idle_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(pa_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(pa_stall_count);
+        gcmkRESET_PROFILE_DATA_PART1(pa_process_count);
+    }
+#endif
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_input_vtx_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_input_prim_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_output_prim_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_depth_clipped_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_trivial_rejected_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_culled_prim_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_droped_prim_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(pa_frustum_clipped_prim_counter);
+    if (newCounters0)
+    {
+        gcmkUPDATE_PROFILE_DATA_PART1(pa_non_idle_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(pa_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(pa_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(pa_process_count);
+    }
+#if !USE_SW_RESET
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+));
+#endif
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_clipped_triangle_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_clipped_line_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_culled_triangle_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_culled_lines_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_trivial_rejected_line_count));
+    if (newCounters0)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_receive_triangle_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_send_triangle_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_receive_lines_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_send_lines_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_process_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_non_idle_starve_count));
+    }
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8)))
+));
+
+    gcmkUPDATE_PROFILE_DATA_PART1(se_clipped_triangle_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(se_clipped_line_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(se_culled_triangle_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(se_culled_lines_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(se_trivial_rejected_line_count);
+    if (newCounters0)
+    {
+        gcmkUPDATE_PROFILE_DATA_PART1(se_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_receive_triangle_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_send_triangle_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_receive_lines_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_send_lines_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_process_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(se_non_idle_starve_count);
+    }
+
+    /* RA */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_valid_pixel_count_to_render));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_total_quad_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_valid_quad_count_after_early_z));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_input_prim_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_pipe_cache_miss_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_prefetch_cache_miss_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_eez_culled_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_pipe_hz_cache_miss_counter));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_prefetch_hz_cache_miss_counter));
+    if (newCounters0)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_non_idle_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_starve_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_stall_count));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_process_count));
+    }
+#if USE_SW_RESET
+    gcmkRESET_PROFILE_DATA_PART1(ra_valid_pixel_count_to_render);
+    gcmkRESET_PROFILE_DATA_PART1(ra_total_quad_count);
+    gcmkRESET_PROFILE_DATA_PART1(ra_valid_quad_count_after_early_z);
+    gcmkRESET_PROFILE_DATA_PART1(ra_input_prim_count);
+    gcmkRESET_PROFILE_DATA_PART1(ra_pipe_cache_miss_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ra_prefetch_cache_miss_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ra_eez_culled_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ra_pipe_hz_cache_miss_counter);
+    gcmkRESET_PROFILE_DATA_PART1(ra_prefetch_hz_cache_miss_counter);
+    if (newCounters0)
+    {
+        gcmkRESET_PROFILE_DATA_PART1(ra_non_idle_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(ra_starve_count);
+        gcmkRESET_PROFILE_DATA_PART1(ra_stall_count);
+        gcmkRESET_PROFILE_DATA_PART1(ra_process_count);
+    }
+#endif
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_valid_pixel_count_to_render);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_total_quad_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_valid_quad_count_after_early_z);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_input_prim_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_pipe_cache_miss_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_prefetch_cache_miss_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_eez_culled_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_pipe_hz_cache_miss_counter);
+    gcmkUPDATE_PROFILE_DATA_PART1(ra_prefetch_hz_cache_miss_counter);
+    if (newCounters0)
+    {
+        gcmkUPDATE_PROFILE_DATA_PART1(ra_non_idle_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ra_starve_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ra_stall_count);
+        gcmkUPDATE_PROFILE_DATA_PART1(ra_process_count);
+    }
+#if !USE_SW_RESET
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+));
+#endif
+
+    /* TX */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_bilinear_requests));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_trilinear_requests));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_discarded_texture_requests));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_texture_requests));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc0_miss_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc0_request_byte_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc1_miss_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc1_request_byte_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24)))
+));
+
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_total_bilinear_requests);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_total_trilinear_requests);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_total_discarded_texture_requests);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_total_texture_requests);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_mc0_miss_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_mc0_request_byte_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_mc1_miss_count);
+    gcmkUPDATE_PROFILE_DATA_PART1(tx_mc1_request_byte_count);
+
+    /* MC */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_colorpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_sentout_from_colorpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_colorpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_sentout_from_colorpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_colorpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_depthpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_sentout_from_depthpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_depthpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_sentout_from_depthpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_depthpipe));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_others));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_others));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_from_others));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_others));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_fe_read_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (22) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_mmu_read_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (23) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_blt_read_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (24) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh0_read_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (25) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh1_read_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (26) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_pe_write_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (27) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_blt_write_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (28) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh0_write_bandwidth));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (29) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh1_write_bandwidth));
+
+    /* Reset counters. */
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1));
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+));
+
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_colorpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_sentout_from_colorpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_colorpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_sentout_from_colorpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_colorpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_depthpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_sentout_from_depthpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_depthpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_sentout_from_depthpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_depthpipe);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_others);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_others);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_from_others);
+    gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_others);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_fe_read_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_mmu_read_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_blt_read_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_sh0_read_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_sh1_read_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_pe_write_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_blt_write_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_sh0_write_bandwidth);
+    gcmkUPDATE_PROFILE_DATA_PART2(mc_sh1_write_bandwidth);
+
+    /* read latency counters */
+    if (newCounters0)
+    {
+        /* latency */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x0056C,
+            &mc_axi_max_min_latency));
+
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00570,
+            &profiler_part2->mcc_axi_total_latency));
+
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00574,
+            &profiler_part2->mcc_axi_sample_count));
+
+        /* Reset Latency counters */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00568,
+            0x10a));
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+            Hardware->core,
+            0x00568,
+            0xa));
+
+        profiler_part2->mcc_axi_min_latency = (mc_axi_max_min_latency & 0xffff0000) >> 16;
+        profiler_part2->mcc_axi_max_latency = (mc_axi_max_min_latency & 0x0000ffff);
+        if (profiler_part2->mcc_axi_min_latency == 4095)
+            profiler_part2->mcc_axi_min_latency = 0;
+
+        gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_min_latency);
+        gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_max_latency);
+        gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_total_latency);
+        gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_sample_count);
+    }
+
+    /* HI */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_read_request_stalled));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_write_request_stalled));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_write_data_stalled));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8)))
+));
+
+    gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_read_request_stalled);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_write_request_stalled);
+    gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_write_data_stalled);
+
+    /* L2 */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi0_read_request_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi0_write_request_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi1_write_request_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_read_transactions_request_by_axi0));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_read_transactions_request_by_axi1));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_write_transactions_request_by_axi0));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_write_transactions_request_by_axi1));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_minmax_latency));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_total_latency));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_total_request_count));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_minmax_latency));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_total_latency));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_total_request_count));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478,   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+));
+
+    profiler_part2->l2_axi0_min_latency = (profiler_part2->l2_axi0_minmax_latency & 0xffff0000) >> 16;
+    profiler_part2->l2_axi0_max_latency = (profiler_part2->l2_axi0_minmax_latency & 0x0000ffff);
+    profiler_part2->l2_axi1_min_latency = (profiler_part2->l2_axi0_minmax_latency & 0xffff0000) >> 16;
+    profiler_part2->l2_axi1_max_latency = (profiler_part2->l2_axi0_minmax_latency & 0x0000ffff);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi0_read_request_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi1_read_request_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi0_write_request_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi1_write_request_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_read_transactions_request_by_axi0);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_read_transactions_request_by_axi1);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_write_transactions_request_by_axi0);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_total_write_transactions_request_by_axi1);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_min_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_max_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_total_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_total_request_count);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_min_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_max_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_total_latency);
+    gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_total_request_count);
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(
+        command->os, command->mutexContextSeq
+        ));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mutexAcquired)
+    {
+        gckOS_ReleaseMutex(
+            command->os, command->mutexContextSeq
+            );
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+gckHARDWARE_InitProfiler(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 control;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x00000,
+                                     &control));
+    /* Enable debug register. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)))));
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_ResetGPU(
+    IN gckHARDWARE Hardware,
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    gctUINT32 control, idle;
+    gceSTATUS status;
+    gctUINT32 count = 0;
+    gctUINT32 mmuEnabled;
+
+    while (count < 2)
+    {
+        /* Disable clock gating. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    Hardware->powerBaseAddress +
+                    0x00104,
+                    0x00000000));
+
+        control = ((((gctUINT32) (0x015B0880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)));
+
+        /* Disable pulse-eater. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    0x0010C,
+                    control));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    0x0010C,
+                    ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    0x0010C,
+                    control));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    0x00000,
+                    ((((gctUINT32) (0x00010900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)))));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    Core,
+                    0x00000,
+                    0x00010900));
+
+        /* Wait for clock being stable. */
+        gcmkONERROR(gckOS_Delay(Os, 1));
+
+        /* Isolate the GPU. */
+        control = ((((gctUINT32) (0x00010900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          Core,
+                                          0x00000,
+                                          control));
+
+        if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB) &&
+            (Hardware->options.secureMode == gcvSECURE_IN_NORMAL))
+        {
+            gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                              Core,
+                                              0x003A8,
+                                              ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+        }
+        else
+        {
+            /* Set soft reset. */
+            gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                              Core,
+                                              0x00000,
+                                              ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))));
+        }
+
+#if gcdFPGA_BUILD
+        /* Wait more time on FPGA for reset as lower frequency */
+        gcmkONERROR(gckOS_Delay(Os, 10));
+#else
+        /* Wait for reset. */
+        gcmkONERROR(gckOS_Delay(Os, 1));
+#endif
+        /* Reset soft reset bit. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          Core,
+                                          0x00000,
+                                          ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))));
+
+        /* Reset GPU isolation. */
+        control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          Core,
+                                          0x00000,
+                                          control));
+
+        /* Read idle register. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Os,
+                                         Core,
+                                         0x00004,
+                                         &idle));
+
+
+        if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0)
+        {
+            continue;
+        }
+
+        gcmkDUMP(Os, "@[register.wait 0x%05X 0x%08X 0x%08X]",
+                 0x00004,
+                 ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (~0U) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+                 idle);
+
+        /* Read reset register. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Os,
+                                         Core,
+                                         0x00000,
+                                         &control));
+        if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0)
+        ||  ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0)
+        )
+        {
+            continue;
+        }
+
+        gcmkDUMP(Os, "@[register.wait 0x%05X 0x%08X 0x%08X]",
+                 0x00000,
+                 ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (~0U) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+                 | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (~0U) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))),
+                 control);
+
+        /* Force Disable MMU to guarantee setup command be read from physical addr */
+        if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+        {
+            gctUINT32 regMmuCtrl = 0;
+            gcmkONERROR(gckOS_ReadRegisterEx(
+                Hardware->os,
+                Hardware->core,
+                0x00388,
+                &regMmuCtrl
+                ));
+
+            mmuEnabled = (((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) );
+        }
+        else
+        {
+            gctUINT32 regMmuCtrl = 0;
+
+            gcmkONERROR(gckOS_ReadRegisterEx(
+                Hardware->os,
+                Hardware->core,
+                0x0018C,
+                &regMmuCtrl
+                ));
+
+            mmuEnabled = (((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) );
+        }
+
+        if (mmuEnabled)
+        {
+            /* Not reset properly, reset again. */
+            continue;
+        }
+
+        count++;
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+
+OnError:
+
+    /* Return the error. */
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_Reset(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL);
+
+    /* Record context ID in debug register before reset. */
+    gcmkONERROR(gckHARDWARE_UpdateContextID(Hardware));
+
+    /* Hardware reset. */
+    status = gckOS_ResetGPU(Hardware->os, Hardware->core);
+
+    if (gcmIS_ERROR(status))
+    {
+        if (Hardware->identity.chipRevision < 0x4600)
+        {
+            /* Not supported - we need the isolation bit. */
+            gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+        }
+
+        /* Soft reset. */
+        gcmkONERROR(_ResetGPU(Hardware, Hardware->os, Hardware->core));
+    }
+
+    /* Force the command queue to reload the next context. */
+    Hardware->kernel->command->currContext = gcvNULL;
+
+    /* Initialize hardware. */
+    gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware));
+
+    /* Jump to address into which GPU should run if it doesn't stuck. */
+    if (Hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_Execute(Hardware, Hardware->kernel->restoreAddress, 16));
+    }
+
+    gcmkPRINT("[galcore]: recovery done");
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkPRINT("[galcore]: Hardware not reset successfully, give up");
+
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetBaseAddress(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32_PTR BaseAddress
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
+
+    /* Get the base address from the OS. */
+    *BaseAddress = Hardware->baseAddress;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_NeedBaseAddress(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 State,
+    OUT gctBOOL_PTR NeedBase
+    )
+{
+    gctBOOL need = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL);
+
+    /* Make sure this is a load state. */
+    if (((((gctUINT32) (State)) >> (0 ?
+ 31:27) & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))))
+    {
+#if gcdENABLE_3D
+        /* Get the state address. */
+        switch ((((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) ))
+        {
+        case 0x0596:
+        case 0x0597:
+        case 0x0599:
+        case 0x059A:
+        case 0x05A9:
+            /* These states need a TRUE physical address if MC20 fix is not there */
+            need = (gcvSTATUS_FALSE == gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MC20));
+            break;
+        }
+#else
+        /* 2D addresses don't need a base address. */
+#endif
+    }
+
+    /* Return the flag. */
+    *NeedBase = need;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_IsFeatureAvailable
+**
+**  Verifies whether the specified feature is available in hardware.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gceFEATURE Feature
+**          Feature to be verified.
+*/
+gceSTATUS
+gckHARDWARE_IsFeatureAvailable(
+    IN gckHARDWARE Hardware,
+    IN gceFEATURE Feature
+    )
+{
+    gctBOOL available;
+
+    gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    available = _QueryFeatureDatabase(Hardware, Feature);
+
+    /* Return result. */
+    gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE);
+    return available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE;
+}
+
+gceSTATUS
+gckHARDWARE_QueryMcfe(
+    IN gckHARDWARE Hardware,
+    OUT const gceMCFE_CHANNEL_TYPE * Channels[],
+    OUT gctUINT32 * Count
+    )
+{
+    if (!_QueryFeatureDatabase(Hardware, gcvFEATURE_MCFE))
+    {
+        /* No MCFE feature. */
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    if (Channels)
+    {
+        *Channels = Hardware->mcfeChannels;
+    }
+
+    if (Count)
+    {
+        *Count = Hardware->mcfeChannelCount;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+**  gckHARDWARE_DumpMMUException
+**
+**  Dump the MMU debug info on an MMU exception.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_DumpMMUException(
+    IN gckHARDWARE Hardware
+    )
+{
+    gctUINT32 mmu       = 0;
+    gctUINT32 mmuStatus = 0;
+    gctUINT32 address   = 0;
+    gctUINT32 i         = 0;
+    gctUINT32 mtlb      = 0;
+    gctUINT32 stlb      = 0;
+    gctUINT32 offset    = 0;
+    gctUINT32 mmuStatusRegAddress;
+    gctUINT32 mmuExceptionAddress;
+    gceAREA_TYPE areaType = gcvAREA_TYPE_UNKNOWN;
+    gctUINT32 stlbShift;
+    gctUINT32 stlbMask;
+    gctUINT32 pgoffMask;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+#if gcdENABLE_TRUST_APPLICATION
+    if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+    {
+        gcmkVERIFY_OK(gckKERNEL_SecurityDumpMMUException(Hardware->kernel));
+
+        gckMMU_DumpRecentFreedAddress(Hardware->kernel->mmu);
+
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+    else
+#endif
+    if (Hardware->options.secureMode == gcvSECURE_NONE)
+    {
+        mmuStatusRegAddress = 0x00188;
+        mmuExceptionAddress = 0x00190;
+    }
+    else
+    {
+        mmuStatusRegAddress = 0x00384;
+        mmuExceptionAddress = 0x00380;
+    }
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    gcmkPRINT("GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n",
+              Hardware->core,
+              Hardware->identity.chipModel,
+              Hardware->identity.chipRevision);
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("***   MMU ERROR DUMP   ***\n");
+    gcmkPRINT("**************************\n");
+
+
+    gcmkVERIFY_OK(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             mmuStatusRegAddress,
+                             &mmuStatus));
+
+    gcmkPRINT("  MMU status = 0x%08X\n", mmuStatus);
+
+    for (i = 0; i < 4; i += 1)
+    {
+        mmu = mmuStatus & 0xF;
+        mmuStatus >>= 4;
+
+        if (mmu == 0)
+        {
+            continue;
+        }
+
+        switch (mmu)
+        {
+        case 1:
+              gcmkPRINT("  MMU%d: slave not present\n", i);
+              break;
+
+        case 2:
+              gcmkPRINT("  MMU%d: page not present\n", i);
+              break;
+
+        case 3:
+              gcmkPRINT("  MMU%d: write violation\n", i);
+              break;
+
+        case 4:
+              gcmkPRINT("  MMU%d: out of bound", i);
+              break;
+
+        case 5:
+              gcmkPRINT("  MMU%d: read security violation", i);
+              break;
+
+        case 6:
+              gcmkPRINT("  MMU%d: write security violation", i);
+              break;
+
+        default:
+              gcmkPRINT("  MMU%d: unknown state\n", i);
+        }
+
+        if (Hardware->options.secureMode == gcvSECURE_NONE)
+        {
+            gcmkVERIFY_OK(
+                gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     mmuExceptionAddress + i * 4,
+                                     &address));
+        }
+        else
+        {
+            gcmkVERIFY_OK(
+                gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     mmuExceptionAddress,
+                                     &address));
+        }
+
+        gckMMU_GetAreaType(Hardware->kernel->mmu, address, &areaType);
+
+        if (areaType == gcvAREA_TYPE_UNKNOWN)
+        {
+            gcmkPRINT("  MMU%d: exception address = 0x%08X, it is not mapped.\n", i, address);
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+
+        pgoffMask = (areaType == gcvAREA_TYPE_4K) ? gcdMMU_OFFSET_4K_MASK : gcdMMU_OFFSET_1M_MASK;
+        stlbShift = (areaType == gcvAREA_TYPE_4K) ? gcdMMU_STLB_4K_SHIFT : gcdMMU_STLB_1M_SHIFT;
+        stlbMask  = (areaType == gcvAREA_TYPE_4K) ? gcdMMU_STLB_4K_MASK : gcdMMU_STLB_1M_MASK;
+
+        mtlb   = (address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+        stlb   = (address & stlbMask) >> stlbShift;
+        offset =  address & pgoffMask;
+
+        gcmkPRINT("  MMU%d: exception address = 0x%08X\n", i, address);
+
+        gcmkPRINT("    MTLB entry = %d\n", mtlb);
+
+        gcmkPRINT("    STLB entry = %d\n", stlb);
+
+        gcmkPRINT("    Offset = 0x%08X (%d)\n", offset, offset);
+
+        gckMMU_DumpPageTableEntry(Hardware->kernel->mmu, areaType, address);
+
+        gckMMU_DumpRecentFreedAddress(Hardware->kernel->mmu);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_HandleFault(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gctUINT32 mmu, mmuStatus, address = gcvINVALID_ADDRESS, i = 0;
+    gctUINT32 mmuStatusRegAddress;
+    gctUINT32 mmuExceptionAddress;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    if (Hardware->options.secureMode == gcvSECURE_NONE)
+    {
+        mmuStatusRegAddress = 0x00188;
+        mmuExceptionAddress = 0x00190;
+    }
+    else
+    {
+        mmuStatusRegAddress = 0x00384;
+        mmuExceptionAddress = 0x00380;
+    }
+
+    /* Get MMU exception address. */
+#if gcdENABLE_TRUST_APPLICATION
+    if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+    {
+        gckKERNEL_ReadMMUException(Hardware->kernel, &mmuStatus, &address);
+    }
+    else
+#endif
+    {
+        gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os,
+            Hardware->core,
+            mmuStatusRegAddress,
+            &mmuStatus
+            ));
+
+        gcmkPRINT("  MMU status = 0x%08X\n", mmuStatus);
+
+        for (i = 0; i < 4; i += 1)
+        {
+            mmu = mmuStatus & 0xF;
+            mmuStatus >>= 4;
+
+            if (mmu == 0)
+            {
+                continue;
+            }
+
+            gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+                Hardware->os,
+                Hardware->core,
+                mmuExceptionAddress + i * 4,
+                &address
+                ));
+
+            break;
+        }
+    }
+
+    if (address != gcvINVALID_ADDRESS)
+    {
+        gckVIDMEM_NODE nodeObject = gcvNULL;
+        gctUINT32 offset = 0;
+        gctPHYS_ADDR_T physicalAddress = 0;
+        gceAREA_TYPE areaType;
+        gctUINT32 pageMask;
+        gcePAGE_TYPE pageType;
+
+        gckMMU_GetAreaType(Hardware->kernel->mmu, address, &areaType);
+
+        pageMask = (areaType == gcvAREA_TYPE_4K) ? gcdMMU_PAGE_4K_MASK : gcdMMU_PAGE_1M_MASK;
+        pageType = (areaType == gcvAREA_TYPE_4K) ? gcvPAGE_TYPE_4K : gcvPAGE_TYPE_1M;
+
+#if gcdENABLE_TRUST_APPLICATION
+        address &= ~gcdMMU_PAGE_4K_MASK;
+#else
+        address &= ~pageMask;
+#endif
+
+        /* Try to allocate memory and setup map for exception address. */
+        gcmkONERROR(gckVIDMEM_NODE_Find(
+            Hardware->kernel,
+            address,
+            &nodeObject,
+            &offset
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+            Hardware->kernel,
+            nodeObject,
+            offset,
+            &physicalAddress
+            ));
+
+#if gcdENABLE_TRUST_APPLICATION
+        if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+        {
+            gckKERNEL_HandleMMUException(
+                Hardware->kernel,
+                mmuStatus,
+                physicalAddress,
+                address
+                );
+        }
+        else
+#endif
+        {
+            gctUINT32_PTR entry;
+
+            /* Setup page table. */
+            gcmkONERROR(gckMMU_GetPageEntry(Hardware->kernel->mmu, pageType, address, &entry));
+
+            gckMMU_SetPage(Hardware->kernel->mmu, physicalAddress, pageType, gcvTRUE, entry);
+
+            /* Resume hardware execution. */
+            gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+                Hardware->os,
+                Hardware->core,
+                mmuExceptionAddress + i * 4,
+                *entry
+                ));
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_DumpMCFEState(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    gctUINT32 i, j, data = 0, array[8] = { 0 };
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER();
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("*****   MCFE STATE   *****\n");
+    gcmkPRINT("**************************\n");
+
+    /* Fetch address of channels. */
+    gcmkPRINT("Channel fetch addresses:\n");
+    gcmkPRINT("     [00]        [01]        [02]        [03]\n");
+
+    for (i = 0; i < 4; i++)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x3 + 2 * i));
+    }
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 4; j++)
+        {
+            gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x2 + 2 * j));
+            gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &array[j]));
+        }
+
+        gcmkPRINT("  0x%08X  0x%08X  0x%08X  0x%08X\n", array[0], array[1], array[2], array[3]);
+    }
+
+    /* Command data of channels. */
+    gcmkPRINT_N(0, "Channel command data:\n");
+    gcmkPRINT_N(0, "           [00]                    [01]                    [02]                    [03]\n");
+    gcmkPRINT_N(0, "     [Low        High]       [Low        High]       [Low        High]       [Low        High]\n");
+
+
+    for (i = 0; i < 4; i++)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x11 + 4 * i));
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x11 + 4 * i + 2));
+    }
+
+    for (i = 0; i < 32; i++)
+    {
+        for (j = 0; j < 4; j++)
+        {
+            gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x10 + 4 * j));
+            gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &array[j * 2]));
+
+            gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x10 + 4 * j + 2));
+            gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &array[j * 2 + 1]));
+        }
+
+        gcmkPRINT_N(0, "  0x%08X  0x%08X  0x%08X  0x%08X  0x%08X  0x%08X  0x%08X  0x%08X\n",
+                    array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7]);
+    }
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x00));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "0x00: 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x01));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "0x01: 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0A));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "WaitSemaphore: 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0B));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "WaitEventID(channel 0 and 1): 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0C));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "WaitEventID(channel 2 and 3): 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0D));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "DecodeState: 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0E));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "DebugSelect(0x0E): 0x%08X\n", data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x0F));
+    gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+    gcmkPRINT_N(0, "DebugSelect(0x0F): 0x%08X\n", data);
+
+    for (i = 0; i < 9; i++)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x470, 0x20 + i));
+        gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x450, &data));
+        gcmkPRINT_N(0, "DebugSelect(0x%02X): 0x%08X\n", 0x20 + i, data);
+    }
+
+OnError:
+    gcmkFOOTER();
+
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_DumpGPUState
+**
+**  Dump the GPU debug registers.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHARDWARE_DumpGPUState(
+    IN gckHARDWARE Hardware
+    )
+{
+    static gctCONST_STRING _cmdState[] =
+    {
+        "PAR_IDLE_ST", "PAR_DEC_ST", "PAR_ADR0_ST", "PAR_LOAD0_ST",
+        "PAR_ADR1_ST", "PAR_LOAD1_ST", "PAR_3DADR_ST", "PAR_3DCMD_ST",
+        "PAR_3DCNTL_ST", "PAR_3DIDXCNTL_ST", "PAR_INITREQDMA_ST", "PAR_DRAWIDX_ST",
+        "PAR_DRAW_ST", "PAR_2DRECT0_ST", "PAR_2DRECT1_ST", "PAR_2DDATA0_ST",
+        "PAR_2DDATA1_ST", "PAR_WAITFIFO_ST", "PAR_WAIT_ST", "PAR_LINK_ST",
+        "PAR_END_ST", "PAR_STALL_ST", "INVALID_PAR_ST", "INVALID_PAR_ST",
+        "INVALID_PAR_ST", "INVALID_PAR_ST", "INVALID_PAR_ST", "INVALID_PAR_ST",
+        "INVALID_PAR_ST", "INVALID_PAR_ST", "INVALID_PAR_ST", "INVALID_PAR_ST"
+    };
+
+    static gctCONST_STRING _cmdDmaState[] =
+    {
+        "CMD_IDLE_ST", "CMD_START_ST", "CMD_REQ_ST", "CMD_END_ST"
+    };
+
+    static gctCONST_STRING _cmdFetState[] =
+    {
+        "FET_IDLE_ST", "FET_RAMVALID_ST", "FET_VALID_ST", "INVALID_FET_ST"
+    };
+
+    static gctCONST_STRING _reqDmaState[] =
+    {
+        "REQ_IDLE_ST", "REQ_WAITIDX_ST", "REQ_CAL_ST", "INVALID_REQ_ST"
+    };
+
+    static gctCONST_STRING _calState[] =
+    {
+        "CAL_IDLE_ST", "CAL_LDADR_ST", "CAL_IDXCALC_ST", "INVALID_CAL_ST"
+    };
+
+    static gctCONST_STRING _veReqState[] =
+    {
+        "VER_IDLE_ST", "VER_CKCACHE_ST", "VER_MISS_ST", "INVALID_VER_ST"
+    };
+
+    enum
+    {
+        RA_INDEX      = 0,
+        TX_INDEX      = 1,
+        FE_INDEX      = 2,
+        PE_INDEX      = 3,
+        DE_INDEX      = 4,
+        SH_INDEX      = 5,
+        PA_INDEX      = 6,
+        SE_INDEX      = 7,
+        MC_INDEX      = 8,
+        HI_INDEX      = 9,
+        TPG_INDEX     = 10,
+        TFB_INDEX     = 11,
+        USC_INDEX     = 12,
+        L2_INDEX      = 13,
+        BLT_INDEX     = 14,
+        WD_INDEX      = 15,
+        VTXDATA_INDEX = 16,
+        DIR_INDEX     = 17,
+        PPA_INDEX     = 18,
+        NN_INDEX      = 19,
+        MODULE_MAX_INDEX,
+    };
+
+    /* must keep order correctly for _dbgRegs, we need ajust some value base on the index */
+    static gcsiDEBUG_REGISTERS _dbgRegs[MODULE_MAX_INDEX] =
+    {
+        { "RA", 0x474, 16, 0x448, 256, 0x1, 0x00, gcvTRUE, gcvTRUE  },
+        { "TX", 0x474, 24, 0x44C, 128, 0x1, 0x00, gcvTRUE, gcvTRUE  },
+        { "FE", 0x470, 0, 0x450, 256, 0x1, 0x00, gcvTRUE, gcvFALSE },
+        { "PE", 0x470, 16, 0x454, 256, 0x3, 0x00, gcvTRUE, gcvTRUE  },
+        { "DE", 0x470, 8, 0x458, 256, 0x1, 0x00, gcvTRUE, gcvFALSE },
+        { "SH", 0x470, 24, 0x45C, 256, 0x1, 0x00, gcvTRUE, gcvTRUE  },
+        { "PA", 0x474, 0, 0x460, 256, 0x1, 0x00, gcvTRUE, gcvTRUE  },
+        { "SE", 0x474, 8, 0x464, 256, 0x1, 0x00, gcvTRUE, gcvTRUE  },
+        { "MC", 0x478, 0, 0x468, 256, 0x3, 0x00, gcvTRUE, gcvTRUE  },
+        { "HI", 0x478, 8, 0x46C, 256, 0x1, 0x00, gcvTRUE, gcvFALSE },
+        { "TPG", 0x474, 24, 0x44C, 32, 0x2, 0x80, gcvFALSE, gcvTRUE  },
+        { "TFB", 0x474, 24, 0x44C, 32, 0x2, 0xA0, gcvFALSE, gcvTRUE  },
+        { "USC", 0x474, 24, 0x44C, 64, 0x2, 0xC0, gcvFALSE, gcvTRUE  },
+        { "L2", 0x478, 0, 0x564, 256, 0x1, 0x00, gcvTRUE, gcvFALSE },
+        { "BLT", 0x478, 24, 0x1A4, 256, 0x1, 0x00, gcvFALSE, gcvTRUE  },
+        { "WD", 0xF0, 16, 0xF4, 256, 0x1, 0x00, gcvFALSE, gcvFALSE },
+        { "VTXDATA", 0x474, 24, 0x44C, 64, 0x1, 0x40, gcvFALSE, gcvTRUE  },
+        { "DIR", 0xF0, 24, 0xF8, 256, 0x1, 0x00, gcvFALSE, gcvTRUE  },
+        { "PPA", 0x474, 0, 0x598, 256, 0x1, 0x00, gcvFALSE, gcvTRUE  },
+        { "NN", 0x474, 24, 0x44C, 256, 0x2, 0x00, gcvFALSE, gcvTRUE  },
+
+    };
+
+    static gctUINT32 _otherRegs[] =
+    {
+        0x040, 0x044, 0x04C, 0x050, 0x054, 0x058, 0x05C, 0x060,
+        0x43c, 0x440, 0x444, 0x414, 0x100
+    };
+
+    gceSTATUS status;
+    gctUINT32 idle = 0, axi = 0;
+    gctUINT32 dmaAddress1 = 0, dmaAddress2 = 0;
+    gctUINT32 dmaState1 = 0, dmaState2 = 0;
+    gctUINT32 dmaLow = 0, dmaHigh = 0;
+    gctUINT32 cmdState = 0, cmdDmaState = 0, cmdFetState = 0;
+    gctUINT32 dmaReqState = 0, calState = 0, veReqState = 0;
+    gctUINT i;
+    gctUINT pipe = 0, pipeMask = 0x1;
+    static const gctUINT maxNumOfPipes = 4;
+    gctUINT32 control = 0, oldControl = 0;
+    gckOS os = Hardware->os;
+    gceCORE core = Hardware->core;
+    gceSTATUS hwTFB = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HW_TFB);
+    gceSTATUS usc = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC);
+    gceSTATUS multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+    gceSTATUS bltEngine = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE);
+    gceSTATUS gsShader = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_GEOMETRY_SHADER);
+    gceSTATUS nnEngine = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_ENGINE);
+
+    gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+    gcmkPRINT_N(12, "GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n",
+                core,
+                Hardware->identity.chipModel,
+                Hardware->identity.chipRevision);
+
+    /* Reset register values. */
+    idle        = axi         =
+    dmaState1   = dmaState2   =
+    dmaAddress1 = dmaAddress2 =
+    dmaLow      = dmaHigh     = 0;
+
+    switch (Hardware->identity.pixelPipes)
+    {
+    case 2:
+        pipeMask = 0x3;
+        break;
+    case 1:
+        pipeMask = 0x1;
+        break;
+    default:
+        gcmkASSERT(0);
+    }
+    /* Verify whether DMA is running. */
+    gcmkONERROR(_VerifyDMA(
+        os, core, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
+        ));
+
+    cmdState    =  dmaState2        & 0x1F;
+    cmdDmaState = (dmaState2 >>  8) & 0x03;
+    cmdFetState = (dmaState2 >> 10) & 0x03;
+    dmaReqState = (dmaState2 >> 12) & 0x03;
+    calState    = (dmaState2 >> 14) & 0x03;
+    veReqState  = (dmaState2 >> 16) & 0x03;
+
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00004, &idle));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0000C, &axi));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00668, &dmaLow));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00668, &dmaLow));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0066C, &dmaHigh));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0066C, &dmaHigh));
+
+    gcmkPRINT_N(0, "**************************\n");
+    gcmkPRINT_N(0, "***   GPU STATE DUMP   ***\n");
+    gcmkPRINT_N(0, "**************************\n");
+
+    gcmkPRINT_N(4, "  axi      = 0x%08X\n", axi);
+
+    gcmkPRINT_N(4, "  idle     = 0x%08X\n", idle);
+    if ((idle & 0x00000001) == 0) gcmkPRINT_N(0, "    FE not idle\n");
+    if ((idle & 0x00000002) == 0) gcmkPRINT_N(0, "    DE not idle\n");
+    if ((idle & 0x00000004) == 0) gcmkPRINT_N(0, "    PE not idle\n");
+    if ((idle & 0x00000008) == 0) gcmkPRINT_N(0, "    SH not idle\n");
+    if ((idle & 0x00000010) == 0) gcmkPRINT_N(0, "    PA not idle\n");
+    if ((idle & 0x00000020) == 0) gcmkPRINT_N(0, "    SE not idle\n");
+    if ((idle & 0x00000040) == 0) gcmkPRINT_N(0, "    RA not idle\n");
+    if ((idle & 0x00000080) == 0) gcmkPRINT_N(0, "    TX not idle\n");
+    if ((idle & 0x00000100) == 0) gcmkPRINT_N(0, "    VG not idle\n");
+    if ((idle & 0x00000200) == 0) gcmkPRINT_N(0, "    IM not idle\n");
+    if ((idle & 0x00000400) == 0) gcmkPRINT_N(0, "    FP not idle\n");
+    if ((idle & 0x00000800) == 0) gcmkPRINT_N(0, "    TS not idle\n");
+    if ((idle & 0x00001000) == 0) gcmkPRINT_N(0, "    BL not idle\n");
+    if ((idle & 0x00002000) == 0) gcmkPRINT_N(0, "    ASYNCFE not idle\n");
+    if ((idle & 0x00004000) == 0) gcmkPRINT_N(0, "    MC not idle\n");
+    if ((idle & 0x00008000) == 0) gcmkPRINT_N(0, "    PPA not idle\n");
+    if ((idle & 0x00010000) == 0) gcmkPRINT_N(0, "    DC not idle\n");
+    if ((idle & 0x00020000) == 0) gcmkPRINT_N(0, "    WD not idle\n");
+    if ((idle & 0x00040000) == 0) gcmkPRINT_N(0, "    NN not idle\n");
+    if ((idle & 0x00080000) == 0) gcmkPRINT_N(0, "    TP not idle\n");
+    if ((idle & 0x80000000) != 0) gcmkPRINT_N(0, "    AXI low power mode\n");
+
+    if ((dmaAddress1 == dmaAddress2)
+     && (dmaState1 == dmaState2))
+    {
+        gcmkPRINT_N(0, "  DMA appears to be stuck at this address:\n");
+        gcmkPRINT_N(4, "    0x%08X\n", dmaAddress1);
+    }
+    else
+    {
+        if (dmaAddress1 == dmaAddress2)
+        {
+            gcmkPRINT_N(0, "  DMA address is constant, but state is changing:\n");
+            gcmkPRINT_N(4, "    0x%08X\n", dmaState1);
+            gcmkPRINT_N(4, "    0x%08X\n", dmaState2);
+        }
+        else
+        {
+            gcmkPRINT_N(0, "  DMA is running; known addresses are:\n");
+            gcmkPRINT_N(4, "    0x%08X\n", dmaAddress1);
+            gcmkPRINT_N(4, "    0x%08X\n", dmaAddress2);
+        }
+    }
+
+    gcmkPRINT_N(4, "  dmaLow   = 0x%08X\n", dmaLow);
+    gcmkPRINT_N(4, "  dmaHigh  = 0x%08X\n", dmaHigh);
+    gcmkPRINT_N(4, "  dmaState = 0x%08X\n", dmaState2);
+    gcmkPRINT_N(8, "    command state       = %d (%s)\n", cmdState, _cmdState   [cmdState]);
+    gcmkPRINT_N(8, "    command DMA state   = %d (%s)\n", cmdDmaState, _cmdDmaState[cmdDmaState]);
+    gcmkPRINT_N(8, "    command fetch state = %d (%s)\n", cmdFetState, _cmdFetState[cmdFetState]);
+    gcmkPRINT_N(8, "    DMA request state   = %d (%s)\n", dmaReqState, _reqDmaState[dmaReqState]);
+    gcmkPRINT_N(8, "    cal state           = %d (%s)\n", calState, _calState   [calState]);
+    gcmkPRINT_N(8, "    VE request state    = %d (%s)\n", veReqState, _veReqState [veReqState]);
+
+    gcmkPRINT_N(0, "  Debug registers:\n");
+
+    if (bltEngine)
+    {
+        _dbgRegs[BLT_INDEX].avail = gcvTRUE;
+    }
+    if (hwTFB)
+    {
+        _dbgRegs[TFB_INDEX].avail = gcvTRUE;
+    }
+    if (usc)
+    {
+        _dbgRegs[USC_INDEX].avail = gcvTRUE;
+    }
+    if (gsShader)
+    {
+        _dbgRegs[TPG_INDEX].avail = gcvTRUE;
+    }
+    if (multiCluster)
+    {
+        _dbgRegs[WD_INDEX].avail = gcvTRUE;
+        _dbgRegs[DIR_INDEX].avail = gcvTRUE;
+        _dbgRegs[VTXDATA_INDEX].avail = gcvTRUE;
+        _dbgRegs[PPA_INDEX].avail = gcvTRUE;
+        _dbgRegs[FE_INDEX].index = 0xF0;
+        _dbgRegs[HI_INDEX].index = 0xF0;
+        /*spare 64 DWORDS debug values from TX for VTXDATA prefetch in USC */
+        _dbgRegs[TX_INDEX].count = 64;
+
+        for (i = 0; i < gcmCOUNTOF(_dbgRegs); i++)
+        {
+            if (_dbgRegs[i].inCluster)
+            {
+                _dbgRegs[i].pipeMask =
+                    Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask;
+            }
+        }
+        pipeMask = Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask;
+    }
+    if (nnEngine)
+    {
+        _dbgRegs[NN_INDEX].avail = gcvTRUE;
+    }
+
+    for (i = 0; i < gcmCOUNTOF(_dbgRegs); i += 1)
+    {
+        gcmkONERROR(_DumpDebugRegisters(os, core, &_dbgRegs[i]));
+    }
+
+    /* Record control. */
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0, &oldControl));
+
+    for (pipe = 0; pipe < maxNumOfPipes; pipe++)
+    {
+        if (((1 << pipe) & pipeMask) == 0)
+            continue;
+
+        gcmkPRINT_N(4, "    Other Registers[%d]:\n", pipe);
+
+        /* Switch pipe. */
+        gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0, &control));
+        control &= ~(0xF << 20);
+        control |= (pipe << 20);
+        gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, control));
+
+        for (i = 0; i < gcmCOUNTOF(_otherRegs); i += 1)
+        {
+            gctUINT32 read;
+            gcmkONERROR(gckOS_ReadRegisterEx(os, core, _otherRegs[i], &read));
+            gcmkPRINT_N(12, "      [0x%04X] 0x%08X\n", _otherRegs[i], read);
+        }
+
+         if (Hardware->mmuVersion)
+         {
+             gcmkPRINT("    MMU status from MC[%d]:", pipe);
+             gckHARDWARE_DumpMMUException(Hardware);
+         }
+    }
+
+    /* MCFE state. */
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MCFE))
+    {
+        gcmkVERIFY_OK(_DumpMCFEState(os, core));
+    }
+
+    /* Restore control. */
+    gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, oldControl));
+
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI0))
+    {
+        /* FE debug register. */
+        gcmkVERIFY_OK(_DumpLinkStack(os, core, &_dbgRegs[2]));
+    }
+
+    _DumpFEStack(os, core, &_dbgRegs[2]);
+
+    gcmkPRINT_N(0, "**************************\n");
+    gcmkPRINT_N(0, "*****   SW COUNTERS  *****\n");
+    gcmkPRINT_N(0, "**************************\n");
+    gcmkPRINT_N(4, "    Execute Count = 0x%08X\n", Hardware->executeCount);
+    gcmkPRINT_N(4, "    Execute Addr  = 0x%08X\n", Hardware->lastExecuteAddress);
+    gcmkPRINT_N(4, "    End     Addr  = 0x%08X\n", Hardware->lastEnd);
+
+    /* dump stack. */
+    gckOS_DumpCallStack(os);
+
+OnError:
+
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckHARDWARE_ReadPerformanceRegister(
+    IN gckHARDWARE Hardware,
+    IN gctUINT PerformanceAddress,
+    IN gctUINT IndexAddress,
+    IN gctUINT IndexShift,
+    IN gctUINT Index,
+    OUT gctUINT32_PTR Value
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x PerformanceAddress=0x%x IndexAddress=0x%x "
+                   "IndexShift=%u Index=%u",
+                   Hardware, PerformanceAddress, IndexAddress, IndexShift,
+                   Index);
+
+    /* Write the index. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      IndexAddress,
+                                      Index << IndexShift));
+
+    /* Read the register. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     PerformanceAddress,
+                                     Value));
+
+    /* Test for reset. */
+    if (Index == 15)
+    {
+        /* Index another register to get out of reset. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, IndexAddress, 0));
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Value=0x%x", *Value);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetFrameInfo(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_FRAME_INFO * FrameInfo
+    )
+{
+    gceSTATUS status;
+    gctUINT i, clock;
+    gcsHAL_FRAME_INFO info;
+#if gcdFRAME_DB_RESET
+    gctUINT reset;
+#endif
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Get profile tick. */
+    gcmkONERROR(gckOS_GetProfileTick(&info.ticks));
+
+    /* Read SH counters and reset them. */
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        4,
+        &info.shaderCycles));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        9,
+        &info.vsInstructionCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        12,
+        &info.vsTextureCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        7,
+        &info.psInstructionCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        14,
+        &info.psTextureCount));
+#if gcdFRAME_DB_RESET
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0045C,
+        0x00470,
+        24,
+        15,
+        &reset));
+#endif
+
+    /* Read PA counters and reset them. */
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        3,
+        &info.vertexCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        4,
+        &info.primitiveCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        7,
+        &info.rejectedPrimitives));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        8,
+        &info.culledPrimitives));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        6,
+        &info.clippedPrimitives));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        5,
+        &info.outPrimitives));
+#if gcdFRAME_DB_RESET
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00460,
+        0x00474,
+        0,
+        15,
+        &reset));
+#endif
+
+    /* Read RA counters and reset them. */
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        3,
+        &info.inPrimitives));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        11,
+        &info.culledQuadCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        1,
+        &info.totalQuadCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        2,
+        &info.quadCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        0,
+        &info.totalPixelCount));
+#if gcdFRAME_DB_RESET
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00448,
+        0x00474,
+        16,
+        15,
+        &reset));
+#endif
+
+    /* Read TX counters and reset them. */
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        0,
+        &info.bilinearRequests));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        1,
+        &info.trilinearRequests));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        8,
+        &info.txHitCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        9,
+        &info.txMissCount));
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        6,
+        &info.txBytes8));
+#if gcdFRAME_DB_RESET
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x0044C,
+        0x00474,
+        24,
+        15,
+        &reset));
+#endif
+
+    /* Read clock control register. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x00000,
+                                     &clock));
+
+    /* Walk through all avaiable pixel pipes. */
+    for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+    {
+        /* Select proper pipe. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00000,
+                                          ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ?
+ 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20)))));
+
+        /* Read cycle registers. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00078,
+                                         &info.cycles[i]));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x0007C,
+                                         &info.idleCycles[i]));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00438,
+                                         &info.mcCycles[i]));
+
+        /* Read bandwidth registers. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x0005C,
+                                         &info.readRequests[i]));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00040,
+                                         &info.readBytes8[i]));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00050,
+                                         &info.writeRequests[i]));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00044,
+                                         &info.writeBytes8[i]));
+
+        /* Read PE counters. */
+        gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+            Hardware,
+            0x00454,
+            0x00470,
+            16,
+            0,
+            &info.colorKilled[i]));
+        gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+            Hardware,
+            0x00454,
+            0x00470,
+            16,
+            2,
+            &info.colorDrawn[i]));
+        gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+            Hardware,
+            0x00454,
+            0x00470,
+            16,
+            1,
+            &info.depthKilled[i]));
+        gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+            Hardware,
+            0x00454,
+            0x00470,
+            16,
+            3,
+            &info.depthDrawn[i]));
+    }
+
+    /* Zero out remaning reserved counters. */
+    for (; i < 8; ++i)
+    {
+        info.readBytes8[i]    = 0;
+        info.writeBytes8[i]   = 0;
+        info.cycles[i]        = 0;
+        info.idleCycles[i]    = 0;
+        info.mcCycles[i]      = 0;
+        info.readRequests[i]  = 0;
+        info.writeRequests[i] = 0;
+        info.colorKilled[i]   = 0;
+        info.colorDrawn[i]    = 0;
+        info.depthKilled[i]   = 0;
+        info.depthDrawn[i]    = 0;
+    }
+
+    /* Reset clock control register. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      clock));
+
+    /* Reset cycle and bandwidth counters. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0003C,
+                                      1));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0003C,
+                                      0));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00078,
+                                      0));
+
+#if gcdFRAME_DB_RESET
+    /* Reset PE counters. */
+    gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+        Hardware,
+        0x00454,
+        0x00470,
+        16,
+        15,
+        &reset));
+#endif
+
+    /* Copy to user. */
+    gcmkONERROR(gckOS_CopyToUserData(Hardware->os,
+                                     &info,
+                                     FrameInfo,
+                                     gcmSIZEOF(info)));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_DumpGpuProfile(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT clock, i;
+    gctUINT32 totalRead, totalWrite, read, write;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Read clock control register. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x00000,
+                                      &clock));
+
+    totalRead = 0;
+    totalWrite = 0;
+
+    /* Walk through all avaiable pixel pipes. */
+    for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+    {
+        /* Select proper pipe. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00000,
+                                          ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ?
+ 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ?
+ 23:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20)))));
+
+        /* BW */
+        gcmkONERROR(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             0x00040,
+                             &read));
+        totalRead += read;
+
+        gcmkONERROR(
+        gckOS_ReadRegisterEx(Hardware->os,
+                             Hardware->core,
+                             0x00044,
+                             &write));
+        totalWrite += write;
+     }
+
+     gcmkPRINT("==============GPU Profile: read request : %d\n", totalRead);
+     gcmkPRINT("==============GPU Profile: write request: %d\n", totalWrite);
+
+     /* Reset clock control register. */
+     gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                       Hardware->core,
+                                       0x00000,
+                                       clock));
+    /* Reset counters. */
+    gcmkONERROR(
+       gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1));
+    gcmkONERROR(
+       gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+#if gcdDVFS
+#define READ_FROM_EATER1 0
+
+gceSTATUS
+gckHARDWARE_QueryLoad(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32 * Load
+    )
+{
+    gctUINT32 debug1;
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Load != gcvNULL);
+
+    gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+    if (Hardware->chipPowerState == gcvPOWER_ON)
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00110,
+                                         Load));
+#if READ_FROM_EATER1
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00134,
+                                         Load));
+#endif
+
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00114,
+                                         &debug1));
+
+        /* Patch result of 0x110 with result of 0x114. */
+        if ((debug1 & 0xFF) == 1)
+        {
+            *Load &= ~0xFF;
+            *Load |= 1;
+        }
+
+        if (((debug1 & 0xFF00) >> 8) == 1)
+        {
+            *Load &= ~(0xFF << 8);
+            *Load |= 1 << 8;
+        }
+
+        if (((debug1 & 0xFF0000) >> 16) == 1)
+        {
+            *Load &= ~(0xFF << 16);
+            *Load |= 1 << 16;
+        }
+
+        if (((debug1 & 0xFF000000) >> 24) == 1)
+        {
+            *Load &= ~(0xFF << 24);
+            *Load |= 1 << 24;
+        }
+    }
+    else
+    {
+        status = gcvSTATUS_INVALID_REQUEST;
+    }
+
+OnError:
+
+    gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_SetDVFSPeroid(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32 Frequency
+    )
+{
+    gceSTATUS status;
+    gctUINT32 period;
+    gctUINT32 eater;
+
+#if READ_FROM_EATER1
+    gctUINT32 period1;
+    gctUINT32 eater1;
+#endif
+
+    gcmkHEADER_ARG("Hardware=0x%X Frequency=%d", Hardware, Frequency);
+
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    period = 0;
+
+    while((64 << period) < (gcdDVFS_ANAYLSE_WINDOW * Frequency * 1000) )
+    {
+        period++;
+    }
+
+#if READ_FROM_EATER1
+    /*
+    *  Peroid = F * 1000 * 1000 / (60 * 16 * 1024);
+    */
+    period1 = Frequency * 6250 / 6114;
+#endif
+
+    gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+    if (Hardware->chipPowerState == gcvPOWER_ON)
+    {
+        /* Get current configure. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x0010C,
+                                         &eater));
+
+        /* Change peroid. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x0010C,
+                                          ((((gctUINT32) (eater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (period) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8)))));
+
+#if READ_FROM_EATER1
+        /* Config eater1. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                         Hardware->core,
+                                         0x00130,
+                                         &eater1));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                          Hardware->core,
+                                          0x00130,
+                                          ((((gctUINT32) (eater1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (period1) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16)))));
+#endif
+    }
+    else
+    {
+        status = gcvSTATUS_INVALID_REQUEST;
+    }
+
+OnError:
+    gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_InitDVFS(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 data;
+
+    gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                     Hardware->core,
+                                     0x0010C,
+                                     &data));
+
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ?
+ 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:18) - (0 ? 18:18) + 1))))))) << (0 ? 18:18)));
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)));
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ?
+ 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23)));
+    data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)));
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "DVFS Configure=0x%X",
+                   data);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+                                      Hardware->core,
+                                      0x0010C,
+                                      data));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+#endif
+
+gceSTATUS
+gckHARDWARE_ExecuteFunctions(
+    IN gcsFUNCTION_EXECUTION_PTR Execution
+    )
+{
+    gceSTATUS status;
+    gctUINT32 idle;
+    gctUINT32 i, timer = 0, delay = 1;
+    gctUINT32 address;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+#if gcdCAPTURE_ONLY_MODE
+    return gcvSTATUS_OK;
+#endif
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(hardware->os, "#[function: %s]", Execution->funcName);
+#endif
+
+    for (i  = 0; i < Execution->funcCmdCount; i++)
+    {
+        address = Execution->funcCmd[i].address;
+
+        /* Execute prepared command sequence. */
+        if (hardware->mcFE)
+        {
+            gcmkONERROR(gckMCFE_Execute(hardware, gcvFALSE, 0, address, Execution->funcCmd[i].bytes));
+        }
+        else
+        {
+            gcmkONERROR(gckWLFE_Execute(hardware, address, Execution->funcCmd[i].bytes));
+        }
+
+#if gcdLINK_QUEUE_SIZE
+        {
+            gcuQUEUEDATA data;
+
+            gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+            data.linkData.start    = address;
+            data.linkData.end      = address + Execution->funcCmd[i].bytes;
+            data.linkData.linkLow  = 0;
+            data.linkData.linkHigh = 0;
+
+            gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+        }
+#endif
+
+#if gcdDUMP_IN_KERNEL
+        gcmkDUMP_BUFFER(
+            hardware->os,
+            gcvDUMP_BUFFER_KERNEL_COMMAND,
+            Execution->funcCmd[i].logical,
+            Execution->funcCmd[i].address,
+            Execution->funcCmd[i].bytes
+            );
+#endif
+
+        /* Wait until GPU idle. */
+        do
+        {
+            gckOS_Delay(hardware->os, delay);
+
+            gcmkONERROR(gckOS_ReadRegisterEx(
+                hardware->os,
+                hardware->core,
+                0x00004,
+                &idle));
+
+            timer += delay;
+            delay *= 2;
+
+#if gcdGPU_TIMEOUT
+            if (timer >= hardware->kernel->timeOut)
+            {
+                gckHARDWARE_DumpGPUState(hardware);
+
+                if (hardware->kernel->command)
+                {
+                    gckCOMMAND_DumpExecutingBuffer(hardware->kernel->command);
+                }
+
+                /* Even if hardware is not reset correctly, let software
+                ** continue to avoid software stuck. Software will timeout again
+                ** and try to recover GPU in next timeout.
+                */
+                gcmkONERROR(gcvSTATUS_DEVICE);
+            }
+#endif
+        }
+        while (!_IsGPUIdle(idle));
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_QueryStateTimer(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT64_PTR On,
+    OUT gctUINT64_PTR Off,
+    OUT gctUINT64_PTR Idle,
+    OUT gctUINT64_PTR Suspend
+    )
+{
+    gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+    gckSTATETIMER_Query(
+        &Hardware->powerStateCounter,
+        Hardware->chipPowerState,
+        On, Off, Idle, Suspend);
+
+    gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_WaitFence(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT64 FenceData,
+    IN gctUINT32 FenceAddress,
+    OUT gctUINT32 *Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+    gctUINT32 dataLow = (gctUINT32)FenceData;
+    gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+    if (logical)
+    {
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01FD) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *logical++
+            = dataHigh;
+
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01FA) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *logical++
+            = dataLow;
+
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Hardware->waitCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ?
+ 17:16))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:16) - (0 ? 17:16) + 1))))))) << (0 ? 17:16)));
+
+        *logical++
+            = FenceAddress;
+    }
+    else
+    {
+        *Bytes = 6 * gcmSIZEOF(gctUINT32);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_UpdateContextID(
+    IN gckHARDWARE Hardware
+    )
+{
+    static gcsiDEBUG_REGISTERS fe = { "FE", 0x470, 0, 0x450, 256, 0x1, 0x00, gcvTRUE, gcvFALSE};
+    gckOS os = Hardware->os;
+    gceCORE core = Hardware->core;
+    gctUINT32 contextIDLow, contextIDHigh;
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_WriteRegisterEx(os, core, fe.index, 0x53 << fe.shift));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, fe.data, &contextIDLow));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(os, core, fe.index, 0x54 << fe.shift));
+    gcmkONERROR(gckOS_ReadRegisterEx(os, core, fe.data, &contextIDHigh));
+
+    Hardware->contextID = ((gctUINT64)contextIDHigh << 32) + contextIDLow;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_DummyDraw(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gceDUMMY_DRAW_TYPE DummyDrawType,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32 dummyDraw_gc400[] = {
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0193) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0194) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0180) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x8 & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (4 * gcmSIZEOF(float)) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E05) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0202) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0208) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0201) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0204) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x1000) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x0, 0x0, 0x0, 0x0,
+        0xDEADDEAD,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0203) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1))))))) << (0 ?
+ 6:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:0) - (0 ?
+ 6:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1))))))) << (0 ? 6:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0200) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        1,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x000F003F,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1))))))) << (0 ?
+ 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 11:8) - (0 ?
+ 11:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0500) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:8) - (0 ?
+ 9:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:8) - (0 ?
+ 9:8) + 1))))))) << (0 ?
+ 9:8))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 9:8) - (0 ?
+ 9:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:8) - (0 ? 9:8) + 1))))))) << (0 ? 9:8)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ?
+ 17:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:16) - (0 ? 17:16) + 1))))))) << (0 ? 17:16))),
+
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0300) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0301) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0302) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0303) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0289) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x05 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1))))))) << (0 ?
+ 23:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ? 23:0))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1))))))) << (0 ?
+ 23:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:0) - (0 ?
+ 23:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ? 23:0))),
+        };
+
+    gctUINT32 dummyDraw_v60[] = {
+
+        /* Semaphore from FE to PE. */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+        /* Stall from FE to PE. */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E06) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 14:12) - (0 ?
+ 14:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 14:12) - (0 ?
+ 14:12) + 1))))))) << (0 ?
+ 14:12))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 14:12) - (0 ?
+ 14:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 14:12) - (0 ? 14:12) + 1))))))) << (0 ? 14:12)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ?
+ 17:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 17:16) - (0 ?
+ 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:16) - (0 ? 17:16) + 1))))))) << (0 ? 17:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:4) - (0 ?
+ 7:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:4) - (0 ?
+ 7:4) + 1))))))) << (0 ?
+ 7:4))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:4) - (0 ?
+ 7:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:4) - (0 ? 7:4) + 1))))))) << (0 ? 7:4))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0401) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x0,
+        0x2,
+        0x0,
+        0x0,
+        0x0,
+        0x0,
+        (gctUINT32)~0x0,
+
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xffffffff,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E07) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        2,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E08) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        2,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0420) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0424) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        1,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0403) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        3,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E21) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x2000) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1 << 2) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x07801033,0x3fc00900,0x00000040,0x00390008,
+        (gctUINT32)~0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x0,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0241) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (31) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0244) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (31) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0247) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+
+        (32+(4*(((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->NumShaderCores)-1))/(4*(((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->NumShaderCores)),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0248) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        1,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))),
+
+        /* Semaphore from FE to PE. */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+        /* Stall from FE to PE. */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+        /* Invalidate I cache.*/
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))),
+
+        /* SubmitJob. */
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+    };
+
+    gctUINT32 bytes = 0;
+    gctUINT32_PTR dummyDraw = gcvNULL;
+
+
+    switch(DummyDrawType)
+    {
+    case gcvDUMMY_DRAW_GC400:
+        dummyDraw = dummyDraw_gc400;
+        bytes = gcmSIZEOF(dummyDraw_gc400);
+        *(dummyDraw + 1) = Address;
+        break;
+    case gcvDUMMY_DRAW_V60:
+        dummyDraw = dummyDraw_v60;
+        bytes = gcmSIZEOF(dummyDraw_v60);
+        if (_QueryFeatureDatabase(Hardware, gcvFEATURE_MCFE))
+        {
+            gctUINT32 submitJob;
+
+            submitJob = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) (0x001 & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            if (bytes & 8)
+            {
+                /* To keep 16 byte alignment. */
+                bytes -= 8;
+            }
+
+            dummyDraw[(bytes >> 2) - 2] = submitJob;
+        }
+        break;
+    default:
+        /* other chip no need dummy draw.*/
+        gcmkASSERT(0);
+        break;
+    };
+
+    if (Logical != gcvNULL)
+    {
+        gckOS_MemCopy(Logical, dummyDraw, bytes);
+    }
+
+    *Bytes = bytes;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_EnterQueryClock(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT64 *McStart,
+    OUT gctUINT64 *ShStart
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT64 mcStart, shStart;
+
+    gcmkONERROR(gckOS_GetTime(&mcStart));
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0));
+
+    *McStart = mcStart;
+
+    if (Hardware->core <= gcvCORE_3D_MAX)
+    {
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, 0xFFU << 24));
+
+        gcmkONERROR(gckOS_GetTime(&shStart));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, 0x4U << 24));
+
+        *ShStart = shStart;
+    }
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_ExitQueryClock(
+    IN gckHARDWARE Hardware,
+    IN gctUINT64 McStart,
+    IN gctUINT64 ShStart,
+    OUT gctUINT32 *McClk,
+    OUT gctUINT32 *ShClk
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT64 mcEnd, shEnd;
+    gctUINT32 mcCycle, shCycle;
+    gctUINT64 mcFreq, shFreq = 0;
+
+    gcmkONERROR(gckOS_GetTime(&mcEnd));
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00438, &mcCycle));
+
+    if (mcCycle == 0)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    /* cycle = (gctUINT64)cycle * 1000000 / (end - start); */
+    mcFreq = ((gctUINT64)mcCycle * ((1000000U << 12) / (gctUINT32)(mcEnd - McStart))) >> 12;
+
+    *McClk = (gctUINT32)mcFreq;
+
+    if (Hardware->core <= gcvCORE_3D_MAX)
+    {
+        gcmkONERROR(gckOS_GetTime(&shEnd));
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &shCycle));
+
+        if (!shCycle)
+        {
+            /*TODO: [VIV] Query SH cycle not support for old chips */
+            *ShClk = *McClk;
+            return gcvSTATUS_OK;
+        }
+
+        if (!ShStart)
+        {
+            gcmkONERROR(gcvSTATUS_GENERIC_IO);
+        }
+
+        shFreq = ((gctUINT64)shCycle * ((1000000U << 12) / (gctUINT32)(shEnd - ShStart))) >> 12;
+    }
+
+    *ShClk = (gctUINT32)shFreq;
+
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryFrequency
+**
+**  Query current hardware frequency.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryFrequency(
+    IN gckHARDWARE Hardware
+    )
+{
+    gctUINT64 mcStart, shStart;
+    gctUINT32 mcClk, shClk;
+    gceSTATUS status;
+    gctUINT64 powerManagement = 0;
+    gctBOOL globalAcquired = gcvFALSE;
+    gceCHIPPOWERSTATE statesStored, state;
+
+    gcmkHEADER_ARG("Hardware=0x%p", Hardware);
+
+    gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+    mcStart = shStart = 0;
+    mcClk   = shClk   = 0;
+
+    powerManagement = Hardware->options.powerManagement;
+
+    if (powerManagement)
+    {
+        gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+            Hardware, gcvFALSE
+            ));
+    }
+
+    gcmkONERROR(gckHARDWARE_QueryPowerState(
+        Hardware, &statesStored
+        ));
+
+    gcmkONERROR(gckHARDWARE_SetPowerState(
+        Hardware, gcvPOWER_ON_AUTO
+        ));
+
+    /* Grab the global semaphore. */
+    gcmkONERROR(gckOS_AcquireSemaphore(
+        Hardware->os, Hardware->globalSemaphore
+        ));
+
+    globalAcquired = gcvTRUE;
+
+    gckHARDWARE_EnterQueryClock(Hardware, &mcStart, &shStart);
+
+    gcmkONERROR(gckOS_Delay(Hardware->os, 50));
+
+    if (mcStart)
+    {
+        gckHARDWARE_ExitQueryClock(Hardware,
+                                   mcStart, shStart,
+                                   &mcClk, &shClk);
+
+        Hardware->mcClk = mcClk;
+        Hardware->shClk = shClk;
+    }
+
+    /* Release the global semaphore. */
+    gcmkONERROR(gckOS_ReleaseSemaphore(
+        Hardware->os, Hardware->globalSemaphore
+        ));
+
+    globalAcquired = gcvFALSE;
+
+    switch(statesStored)
+    {
+    case gcvPOWER_OFF:
+        state = gcvPOWER_OFF_BROADCAST;
+        break;
+    case gcvPOWER_IDLE:
+        state = gcvPOWER_IDLE_BROADCAST;
+        break;
+    case gcvPOWER_SUSPEND:
+        state = gcvPOWER_SUSPEND_BROADCAST;
+        break;
+    case gcvPOWER_ON:
+        state = gcvPOWER_ON_AUTO;
+        break;
+    default:
+        state = statesStored;
+        break;
+    }
+
+    if (powerManagement)
+    {
+        gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+            Hardware, gcvTRUE
+            ));
+    }
+
+    gcmkONERROR(gckHARDWARE_SetPowerState(
+        Hardware, state
+        ));
+
+    gcmkFOOTER_NO();
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (globalAcquired)
+    {
+        /* Release the global semaphore. */
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+            Hardware->os, Hardware->globalSemaphore
+            ));
+    }
+
+    gcmkFOOTER();
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Set MC and SH clock
+**
+** Core   : which core clock do you want to set
+** mcScale: MC clock scale
+** shScale: SH clock scale
+*/
+gceSTATUS
+gckHARDWARE_SetClock(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Core,
+    IN gctUINT32 MCScale,
+    IN gctUINT32 SHScale
+    )
+{
+    gceSTATUS status;
+    gctUINT64 powerManagement = 0;
+    gctBOOL globalAcquired = gcvFALSE;
+    gctUINT32 org;
+    gctUINT32 core = Core;
+    gctUINT32 mcScale = MCScale;
+    gctUINT32 shScale = SHScale;
+
+    gcmkHEADER();
+
+    status = gckOS_QueryOption(Hardware->os, "powerManagement", &powerManagement);
+    if (gcmIS_ERROR(status))
+    {
+        powerManagement = 0;
+    }
+
+    if (powerManagement)
+    {
+        gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+            Hardware, gcvFALSE
+            ));
+
+        gcmkPRINT("Warning: Power management status will be changed forever!\n");
+    }
+
+    gcmkONERROR(gckHARDWARE_SetPowerState(
+        Hardware, gcvPOWER_ON_AUTO
+        ));
+
+    /* Grab the global semaphore. */
+    gcmkONERROR(gckOS_AcquireSemaphore(
+        Hardware->os, Hardware->globalSemaphore
+        ));
+
+    globalAcquired = gcvTRUE;
+
+    if (mcScale > 0 && mcScale <= 64)
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, core, 0x00000, &org));
+
+        org = ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (mcScale) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ?
+ 8:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)));
+
+        /* Write the clock control register. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, core,
+                            0x00000,
+                            ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)))));
+
+        /* Done loading the frequency scaler. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, core,
+                            0x00000,
+                            ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)))));
+
+        /* Need to change 0x0010C when it is introduced. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, core, 0x0010C, &org));
+
+        /* Never impact shader clk. */
+        org = 0x01020800 | (org & 0xFF);
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, core, 0x0010C, org));
+    }
+
+    /* set SH clock */
+    if (shScale > 0 && shScale <= 64)
+    {
+        gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, core, 0x0010C, &org));
+
+        org = ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1))))))) << (0 ?
+ 7:1))) | (((gctUINT32) ((gctUINT32) (shScale) & ((gctUINT32) ((((1 ?
+ 7:1) - (0 ?
+ 7:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:1) - (0 ? 7:1) + 1))))))) << (0 ? 7:1)));
+        org = ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+        org = ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)));
+
+        /* Write the clock control register. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, core,
+                            0x0010C,
+                            ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+
+        /* Done loading the frequency scaler. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, core,
+                            0x0010C,
+                            ((((gctUINT32) (org)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+    }
+
+    /* Release the global semaphore. */
+    gcmkONERROR(gckOS_ReleaseSemaphore(
+        Hardware->os, Hardware->globalSemaphore
+        ));
+
+    globalAcquired = gcvFALSE;
+
+    gcmkFOOTER_NO();
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (globalAcquired)
+    {
+        /* Release the global semaphore. */
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+            Hardware->os, Hardware->globalSemaphore
+            ));
+    }
+
+    gcmkFOOTER_NO();
+
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h
@@ -0,0 +1,324 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_h_
+#define __gc_hal_kernel_hardware_h_
+
+#include "gc_hal_kernel_hardware_func.h"
+
+#if gcdENABLE_VG
+#include "gc_hal_kernel_hardware_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EVENT_ID_INVALIDATE_PIPE    29
+
+typedef enum {
+    gcvHARDWARE_FUNCTION_MMU,
+    gcvHARDWARE_FUNCTION_FLUSH,
+
+    gcvHARDWARE_FUNCTION_NUM,
+}
+gceHARDWARE_FUNCTION;
+
+typedef struct _gckASYNC_FE *   gckASYNC_FE;
+typedef struct _gckWLFE *       gckWLFE;
+typedef struct _gckMCFE *       gckMCFE;
+
+typedef struct _gcsSTATETIMER
+{
+    gctUINT64                   start;
+    gctUINT64                   recent;
+
+    /* Elapse of each power state. */
+    gctUINT64                   elapse[4];
+}
+gcsSTATETIMER;
+
+typedef struct _gcsHARDWARE_SIGNATURE
+{
+    /* Chip model. */
+    gceCHIPMODEL                chipModel;
+
+    /* Revision value.*/
+    gctUINT32                   chipRevision;
+
+    /* Supported feature fields. */
+    gctUINT32                   chipFeatures;
+
+    /* Supported minor feature fields. */
+    gctUINT32                   chipMinorFeatures;
+
+    /* Supported minor feature 1 fields. */
+    gctUINT32                   chipMinorFeatures1;
+
+    /* Supported minor feature 2 fields. */
+    gctUINT32                   chipMinorFeatures2;
+}
+gcsHARDWARE_SIGNATURE;
+
+typedef struct _gcsMMU_TABLE_ARRAY_ENTRY
+{
+    gctUINT32                   low;
+    gctUINT32                   high;
+}
+gcsMMU_TABLE_ARRAY_ENTRY;
+
+typedef struct _gcsHARDWARE_PAGETABLE_ARRAY
+{
+    /* Number of entries in page table array. */
+    gctUINT                     num;
+
+    /* Video memory node. */
+    gckVIDMEM_NODE              videoMem;
+
+    /* Size in bytes of array. */
+    gctSIZE_T                   size;
+
+    /* Physical address of array. */
+    gctPHYS_ADDR_T              address;
+
+    /* Logical address of array. */
+    gctPOINTER                  logical;
+}
+gcsHARDWARE_PAGETABLE_ARRAY;
+
+/* gckHARDWARE object. */
+struct _gckHARDWARE
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gctKERNEL object. */
+    gckKERNEL                   kernel;
+
+    /* Pointer to gctOS object. */
+    gckOS                       os;
+
+    /* Core */
+    gceCORE                     core;
+
+    /* Type */
+    gceHARDWARE_TYPE            type;
+
+    /* Chip characteristics. */
+    gcsHAL_QUERY_CHIP_IDENTITY  identity;
+    gcsHAL_QUERY_CHIP_OPTIONS   options;
+    gctUINT32                   powerBaseAddress;
+    gctBOOL                     extraEventStates;
+
+    /* Big endian */
+    gctBOOL                     bigEndian;
+
+    /* Base address. */
+    gctUINT32                   baseAddress;
+
+    /* FE modules. */
+    gckWLFE                     wlFE;
+    gckASYNC_FE                 asyncFE;
+    gckMCFE                     mcFE;
+
+    /* Chip status */
+    gctPOINTER                  powerMutex;
+    gceCHIPPOWERSTATE           chipPowerState;
+    gctBOOL                     clockState;
+    gctBOOL                     powerState;
+    gctPOINTER                  globalSemaphore;
+    gctBOOL                     isLastPowerGlobal;
+
+    /* Wait Link FE only. */
+    gctUINT32                   lastWaitLink;
+    gctUINT32                   lastEnd;
+
+    gctUINT32                   mmuVersion;
+
+    gceCHIPPOWERSTATE           nextPowerState;
+    gctPOINTER                  powerStateTimer;
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+    gctUINT32                   powerOnFscaleVal;
+#endif
+    gctPOINTER                  pageTableDirty[gcvENGINE_GPU_ENGINE_COUNT];
+
+#if gcdLINK_QUEUE_SIZE
+    struct _gckQUEUE            linkQueue;
+#endif
+    gctBOOL                     stallFEPrefetch;
+
+    gctUINT32                   minFscaleValue;
+    gctUINT                     waitCount;
+
+    gctUINT32                   mcClk;
+    gctUINT32                   shClk;
+
+    gctPOINTER                  pendingEvent;
+
+    gcsFUNCTION_EXECUTION_PTR   functions;
+
+    gcsSTATETIMER               powerStateCounter;
+    gctUINT32                   executeCount;
+    gctUINT32                   lastExecuteAddress;
+
+    /* Head for hardware list in gckMMU. */
+    gcsLISTHEAD                 mmuHead;
+
+    /* Internal SRAMs info. */
+    gckVIDMEM                   sRAMVidMem[gcvSRAM_INTER_COUNT];
+    gctPHYS_ADDR                sRAMPhysical[gcvSRAM_INTER_COUNT];
+
+    gctPOINTER                  featureDatabase;
+    gctBOOL                     hasL2Cache;
+
+    /* MCFE channel bindings, temporary. */
+    gceMCFE_CHANNEL_TYPE        mcfeChannels[64];
+    gctUINT32                   mcfeChannelCount;
+
+    gcsHARDWARE_SIGNATURE       signature;
+
+    gctUINT32                   maxOutstandingReads;
+
+    gcsHARDWARE_PAGETABLE_ARRAY pagetableArray;
+
+    gctUINT64                   contextID;
+};
+
+gceSTATUS
+gckHARDWARE_GetBaseAddress(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32_PTR BaseAddress
+    );
+
+gceSTATUS
+gckHARDWARE_NeedBaseAddress(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 State,
+    OUT gctBOOL_PTR NeedBase
+    );
+
+gceSTATUS
+gckHARDWARE_GetFrameInfo(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_FRAME_INFO * FrameInfo
+    );
+
+gceSTATUS
+gckHARDWARE_DumpGpuProfile(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_HandleFault(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_ExecuteFunctions(
+    IN gcsFUNCTION_EXECUTION_PTR Execution
+    );
+
+gceSTATUS
+gckHARDWARE_DummyDraw(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gceDUMMY_DRAW_TYPE DummyDrawType,
+    IN OUT gctUINT32 * Bytes
+    );
+
+gceSTATUS
+gckHARDWARE_EnterQueryClock(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT64 *McStart,
+    OUT gctUINT64 *ShStart
+    );
+
+gceSTATUS
+gckHARDWARE_ExitQueryClock(
+    IN gckHARDWARE Hardware,
+    IN gctUINT64 McStart,
+    IN gctUINT64 ShStart,
+    OUT gctUINT32 *McClk,
+    OUT gctUINT32 *ShClk
+    );
+
+gceSTATUS
+gckHARDWARE_QueryFrequency(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_SetClock(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Core,
+    IN gctUINT32 MCScale,
+    IN gctUINT32 SHScale
+    );
+
+#define gcmkWRITE_MEMORY(logical, data) \
+    do { \
+    gcmkVERIFY_OK(gckOS_WriteMemory(os, logical, data)); \
+    logical++; \
+    }\
+    while (0) ; \
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_hardware_h_ */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_async_fe.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_async_fe.c
@@ -0,0 +1,666 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+struct _gckASYNC_FE
+{
+    /* Number of free descriptors. */
+    gctPOINTER                  freeDscriptors;
+};
+
+gceSTATUS
+gckASYNC_FE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckASYNC_FE * FE
+    )
+{
+    gceSTATUS status;
+    gctUINT32 data;
+    gckASYNC_FE fe;
+
+    gcmkHEADER();
+
+    gcmkONERROR(gckOS_Allocate(Hardware->os,
+                               gcmSIZEOF(struct _gckASYNC_FE),
+                               (gctPOINTER *)&fe));
+    gckOS_ZeroMemory(fe, gcmSIZEOF(struct _gckASYNC_FE));
+
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x007E4,
+       &data
+        ));
+
+    gcmkONERROR(gckOS_AtomConstruct(Hardware->os, &fe->freeDscriptors));
+
+    data = (((((gctUINT32) (data)) >> (0 ? 6:0)) & ((gctUINT32) ((((1 ? 6:0) - (0 ? 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1)))))) );
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE, "free descriptor=%d", data);
+
+    gcmkONERROR(gckOS_AtomSet(Hardware->os, fe->freeDscriptors, data));
+
+    /* Enable interrupts. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x000D8, ~0U));
+
+    *FE = fe;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (fe)
+    {
+        if (fe->freeDscriptors)
+        {
+            gckOS_AtomDestroy(Hardware->os, fe->freeDscriptors);
+        }
+        gcmkOS_SAFE_FREE(Hardware->os, fe);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+void
+gckASYNC_FE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckASYNC_FE FE
+    )
+{
+    if (FE->freeDscriptors)
+    {
+        gcmkOS_SAFE_FREE(Hardware->os, FE->freeDscriptors);
+    }
+
+    gcmkOS_SAFE_FREE(Hardware->os, FE);
+}
+
+gceSTATUS
+gckASYNC_FE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gckASYNC_FE FE
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckASYNC_FE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append NOP. */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the NOP command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckASYNC_FE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT size;
+    gctUINT32 destination = 0;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+    gctBOOL blt;
+    gctBOOL extraEventStates;
+    gctBOOL multiCluster;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu",
+                   Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+    gcmkVERIFY_ARGUMENT(Event < 32);
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE))
+    {
+        /* Send all event from blt. */
+        if (FromWhere == gcvKERNEL_PIXEL)
+        {
+            FromWhere = gcvKERNEL_BLT;
+        }
+    }
+
+    blt = FromWhere == gcvKERNEL_BLT ? gcvTRUE : gcvFALSE;
+
+    multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+
+    /* Determine the size of the command. */
+
+    extraEventStates = Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL);
+
+    size = extraEventStates
+         ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */
+         : 8;
+
+    if (blt)
+    {
+        size += 16;
+        if (multiCluster)
+            size += 8;
+    }
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < size)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        switch (FromWhere)
+        {
+        case gcvKERNEL_COMMAND:
+            /* From command processor. */
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+            break;
+
+        case gcvKERNEL_PIXEL:
+            /* From pixel engine. */
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+            break;
+
+        case gcvKERNEL_BLT:
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+            break;
+
+        default:
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            if (multiCluster)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x50CE) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)));
+            }
+        }
+
+        /* Append EVENT(Event, destination). */
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *logical++
+            = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+
+
+        /* Make sure the event ID gets written out before GPU can access it. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, logical + 1));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+        {
+            gctPHYS_ADDR_T phys;
+            gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys);
+            gckOS_CPUPhysicalToGPUPhysical(Hardware->os, phys, &phys);
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                           "0x%08x: EVENT %d", phys, Event);
+        }
+#endif
+
+        /* Append the extra states. These are needed for the chips that do not
+        ** support back-to-back events due to the async interface. The extra
+        ** states add the necessary delay to ensure that event IDs do not
+        ** collide. */
+        if (extraEventStates)
+        {
+            *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+        }
+
+#if gcdINTERRUPT_STATISTIC
+        if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues))
+        {
+            gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event);
+        }
+#endif
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the EVENT command. */
+        *Bytes = size;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+void
+gckASYNC_FE_UpdateAvaiable(
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 data;
+    gctINT32 oldValue;
+    gckASYNC_FE fe = Hardware->asyncFE;
+
+    status = gckOS_ReadRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x007E4,
+        &data
+        );
+
+    if (gcmIS_SUCCESS(status))
+    {
+        data = (((((gctUINT32) (data)) >> (0 ? 6:0)) & ((gctUINT32) ((((1 ? 6:0) - (0 ? 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1)))))) );
+
+        while (data--)
+        {
+            gckOS_AtomIncrement(Hardware->os, fe->freeDscriptors, &oldValue);
+        }
+    }
+}
+
+gceSTATUS
+gckASYNC_FE_ReserveSlot(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL * Available
+    )
+{
+    gctINT32 oldValue;
+    gckASYNC_FE fe = Hardware->asyncFE;
+
+    gckOS_AtomDecrement(Hardware->os, fe->freeDscriptors, &oldValue);
+
+    if (oldValue > 0)
+    {
+        /* Get one slot. */
+        *Available = gcvTRUE;
+    }
+    else
+    {
+        /* No available slot, restore decreased one.*/
+        gckOS_AtomIncrement(Hardware->os, fe->freeDscriptors, &oldValue);
+        *Available = gcvFALSE;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckASYNC_FE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Hardware=%p Address=%x Bytes=%lu", Hardware, Address, Bytes);
+
+    gcmkONERROR(gckOS_WriteRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x007DC,
+        Address
+        ));
+
+    gcmkONERROR(gckOS_MemoryBarrier(
+        Hardware->os,
+        gcvNULL
+        ));
+
+    gcmkONERROR(gckOS_WriteRegisterEx(
+        Hardware->os,
+        Hardware->core,
+        0x007E0,
+        Address + Bytes
+        ));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_fe.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_fe.h
@@ -0,0 +1,296 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_fe_h_
+#define __gc_hal_kernel_hardware_fe_h_
+
+#include "gc_hal.h"
+
+/******************************************************************************/
+/* Wait-Link FE commands. */
+
+/* Construct Wait-Link FE. */
+gceSTATUS
+gckWLFE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckWLFE * FE
+    );
+
+void
+gckWLFE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckWLFE FE
+    );
+
+/* Initialize Wait-Link FE, when hardware reset. */
+gceSTATUS
+gckWLFE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gckWLFE FE
+    );
+
+
+/* Add a WAIT/LINK pair in the command queue. */
+gceSTATUS
+gckWLFE_WaitLink(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 Offset,
+    IN OUT gctUINT32 * Bytes,
+    OUT gctUINT32 * WaitOffset,
+    OUT gctUINT32 * WaitBytes
+    );
+
+/* Add a LINK command in the command queue. */
+gceSTATUS
+gckWLFE_Link(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT32 FetchSize,
+    IN OUT gctUINT32 * Bytes,
+    OUT gctUINT32 * Low,
+    OUT gctUINT32 * High
+    );
+
+/* Add an END command in the command queue. */
+gceSTATUS
+gckWLFE_End(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Add a NOP command in the command queue. */
+gceSTATUS
+gckWLFE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    );
+
+/* Add an EVENT command in the command queue. */
+gceSTATUS
+gckWLFE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    );
+
+gceSTATUS
+gckWLFE_ChipEnable(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gceCORE_3D_MASK ChipEnable,
+    IN OUT gctSIZE_T * Bytes
+    );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckWLFE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+/* Atomic version or IRQ routine. */
+gceSTATUS
+gckWLFE_AtomicExecute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+/******************************************************************************/
+/* ASync FE commands. */
+
+gceSTATUS
+gckASYNC_FE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckASYNC_FE * FE
+    );
+
+void
+gckASYNC_FE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckASYNC_FE FE
+    );
+
+/* Initialize Async FE, when hardware reset. */
+gceSTATUS
+gckASYNC_FE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gckASYNC_FE FE
+    );
+
+/* Add a NOP command in the command queue. */
+gceSTATUS
+gckASYNC_FE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    );
+
+/* Add an EVENT command in the command queue. */
+gceSTATUS
+gckASYNC_FE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckASYNC_FE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gckASYNC_FE_ReserveSlot(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL * Available
+    );
+
+void
+gckASYNC_FE_UpdateAvaiable(
+    IN gckHARDWARE Hardware
+    );
+
+/******************************************************************************/
+/* MC FE commands. */
+
+/* One MCFE includes max 64 engine, each engine contains 2 channels. */
+gceSTATUS
+gckMCFE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckMCFE * FE
+    );
+
+void
+gckMCFE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckMCFE FE
+    );
+
+/* Initialize MC FE, when hardware reset. */
+gceSTATUS
+gckMCFE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL MMUEnabled,
+    IN gckMCFE FE
+    );
+
+/* Add a NOP command in the command queue. */
+gceSTATUS
+gckMCFE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    );
+
+/* Add an EVENT command in the command queue. */
+gceSTATUS
+gckMCFE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Add a SendSemaphore command in the command queue. */
+gceSTATUS
+gckMCFE_SendSemaphore(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 SemaId,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Add a WaitSemaphore command in the command queue. */
+gceSTATUS
+gckMCFE_WaitSemaphore(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 SemaId,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckMCFE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Priority,
+    IN gctUINT32 ChannelId,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+/* Query hardware module idle */
+gceSTATUS
+gckMCFE_HardwareIdle(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL_PTR IsIdle
+    );
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func.c
@@ -0,0 +1,11066 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_hardware.h"
+
+#if gcdFLOP_RESET
+#include "gc_hal_kernel_hardware_func_flop_reset.h"
+#else
+#if gcdINITIALIZE_PPU
+#if !gcdINITIALIZE_PPU_C
+static gctUINT32 ppuMem0[] =
+{
+    0x00010000
+};
+
+static gctUINT32 ppuMem1[] =
+{
+    0x00010000
+};
+
+static gctUINT32 ppuMem2[] =
+{
+    0x38011039, 0x39200804, 0xC0A90050, 0x74000008, 0x38021039, 0x39202804, 0xC0A90050, 0x74000008,
+    0x38031039, 0x39204804, 0xC0A90050, 0x74000008, 0xB8017005, 0x002018FC, 0x01C900C0, 0x40390098,
+    0xB8027005, 0x002028FC, 0x01C90140, 0x40390098, 0xB8037005, 0x002038FC, 0x01C901C0, 0x40390098,
+    0x04041036, 0x00000804, 0x4000047A, 0x00000002, 0x0400100C, 0x3FC04804, 0x40AB0440, 0x2000007A,
+    0x38000835, 0x39207804, 0x41E80050, 0x00390018, 0x04041036, 0x00001804, 0x4000047A, 0x00000002,
+    0x0400100C, 0x3FC04804, 0x40AB0440, 0x2000007A, 0x38000835, 0x39207804, 0x41E80050, 0x00390028,
+    0x04041036, 0x00002804, 0x4000047A, 0x00000002, 0x0400100C, 0x3FC04804, 0x40AB0440, 0x2000007A,
+    0x38000835, 0x39207804, 0x41E80050, 0x00390038
+};
+
+static gctUINT32 ppuMem3[] =
+{
+    0x7E7E7E7E, 0x797B7E7F, 0x79797879, 0x7D7C7B7A, 0x80818181, 0x7B7C7D7F, 0x83817C79, 0x7C7D8082,
+    0x7C7C7D7D, 0x7D7D7C7C, 0x81818181, 0x7D7D7F80, 0x73777E83, 0x71717171, 0x7E7A7574, 0x8A888782,
+    0x7475797B, 0x8D888078, 0x8F92918F, 0x787B8189, 0x908E8781, 0x787B838C, 0x7A767576, 0x85868581,
+    0x817F8185, 0x87838181, 0x8182878D, 0x787C8181, 0x807A787A, 0x8B878483, 0x8D8A8787, 0x8885878D,
+    0x817E7D7D, 0x81828483, 0x7C7D7D7E, 0x69686D76, 0x6E6D6C6C, 0x70727271, 0x74727172, 0x74757675,
+    0x6F6E7072, 0x70717170, 0x6E6E7073, 0x78767471, 0x7A77726F, 0x84817F7C, 0x93949596, 0x8D8D9092,
+    0x8F8F8D88, 0xB3A79991, 0xABB4BABD, 0x8D9199A2, 0x77737274, 0x676F787A, 0x78716862, 0x7577797A,
+    0x74747474, 0x78777675, 0x78797A7A, 0x74747576, 0x817C7977, 0x82848685, 0x787A7D80, 0x8886807A,
+    0x79858D91, 0x6D6A696E, 0x676D7471, 0x5659646A, 0x3E3B3F45, 0x44484A46, 0x675B504A, 0x82807A72,
+    0x71777C80, 0x6868696C, 0x716E6D6B, 0x7F7B7773, 0x87909391, 0x908F8A85, 0x9596938F, 0x89898C91,
+    0x89878584, 0x92908E8C, 0x99999693, 0x7B818993, 0x7A818582, 0x928B8078, 0x928A8D97, 0xA5968F93,
+    0x939DA5AB, 0x8F8D8A8C, 0x8D8B8A8C, 0x85878B8D, 0x7C7D8082, 0x7F807F7E, 0x85858382, 0x787B7F83,
+    0x72717475, 0x9B928378, 0x9EB4B6AB, 0x8C898589, 0x998F8A8E, 0x686D7E93, 0x6A6A6865, 0x65646568,
+    0x64676868, 0x60616162, 0x7A7A7268, 0x72767878, 0x6C717577, 0x716A6466, 0x7D7E7B78, 0x7A777679,
+    0x8484817F, 0x7A7E8183, 0x89807E84, 0x8080868D, 0x60505069, 0x7074857A, 0x968D7A69, 0x8E8C8D93,
+    0x6D6D7A8D, 0x8A7E7470, 0x7C7D7F80, 0x7A7A7A7B, 0x7A7A7C7C, 0x74757678, 0x7C7A7775, 0x75777A7C,
+    0x7A7A7978, 0x7A7A7A7A, 0x81817C7A, 0x7D7E7F81, 0x8D898581, 0x8185898D, 0x7374787B, 0x79797674,
+    0x797A7A7B, 0x79797878, 0x807F7D7C, 0x7D7E7F80, 0x78797A7A, 0x79797878, 0x77787878, 0x76767677,
+    0x77777778, 0x76767676, 0x78767574, 0x7F7E7C7A, 0x797B7D7F, 0x76767677, 0x807E7C7A, 0x82828181,
+    0x7C7F8183, 0x7979797A, 0x84807B79, 0x8E8D8C88, 0x88888888, 0x86878788, 0x82818384, 0x85868684,
+    0x87878787, 0x87878786, 0x767B8185, 0x72717173, 0x7F818282, 0x76787A7C, 0x76767676, 0x74747576,
+    0x78736E6A, 0x77787A7A, 0x78757474, 0x85827F7B, 0x8D8E8D8D, 0x8184878C, 0x87837F7C, 0x82848788,
+    0x80818182, 0x7E7E7F7F, 0x8985817E, 0x8C8C8D8C, 0x8B8A8A8B, 0x7A80878B, 0x86817D7B, 0x8D8D8C89,
+    0x87888785, 0x82828386, 0x89848181, 0x9293938F, 0x8D8D8F92, 0x868A8E8F, 0x89837F7C, 0x8C8E8F8D,
+    0x78808689, 0x63666A71, 0x5F5C5F63, 0x73726E67, 0x75727274, 0x68696E74, 0x6C6B6C6B, 0x83837D73,
+    0x686B7074, 0x807A716A, 0x81828180, 0x676C747C, 0x68626060, 0x7D7C7A72, 0x7074787A, 0x7F79716E,
+    0x6E6A7585, 0x686E7474, 0x5C646665, 0x4F4C4C52, 0x63615A53, 0x786F6763, 0x7A7F8385, 0x77757475,
+    0x6B6E7171, 0x65646467, 0x6662605F, 0x736E6A68, 0x79797877, 0x74757779, 0x78747170, 0x7B7D7D7B,
+    0x7F7B7B7E, 0x7C818483, 0x8B878585, 0x92939491, 0x99949190, 0x90959B9D, 0x6C717E8A, 0x7E7D7870,
+    0x81828282, 0x84828080, 0x71727C87, 0x7D7A7774, 0x676F7E88, 0x837B7068, 0x84888A8B, 0x7A7A7C80,
+    0x76747373, 0x76787979, 0x6E6E7072, 0x87817A73, 0x8385878A, 0x797B8082, 0x8989837D, 0x7E7C7D83,
+    0x817B7A7B, 0x757F8788, 0x6F727476, 0x6D6D6D6E, 0x707A7A75, 0x62626368, 0x62636566, 0x67656362,
+    0x6E6E6E6E, 0x7E78726E, 0x817F7E7D, 0x908D8A86, 0x82818488, 0x8A8C8B87, 0x8184878A, 0x807F7E7F,
+    0x84858787, 0x767A7F82, 0x6C6C6C6C, 0x7674716E, 0x76787A7A, 0x70717274, 0x6E6D6E70, 0x7D7B7772,
+    0x807B7A78, 0x878D8E87, 0x79828989, 0x74777774, 0x4E545E67, 0x6B645A50, 0x8A796C68, 0x63718490,
+    0x7068615C, 0x74747675, 0x7C787471, 0x82828180, 0x7A7B7B7B, 0x74757779, 0x858B877E, 0x7B747077,
+    0x6F717980, 0x74767572, 0x6E6F6F6F, 0x696A6B6D, 0x565C6060, 0x605F5A55, 0x5F5F5E5D, 0x66646160,
+    0x736E6A68, 0x7C7F7E7A, 0x75757879, 0x79797877, 0x71717375, 0x6C6E7273, 0x6D6B6A69, 0x71706F6E,
+    0x66686A6B, 0x61616263, 0x7F7F7365, 0x61697379, 0x6B67625D, 0x69696B6C, 0x7776716B, 0x75737274,
+    0x6E788082, 0x6F696365, 0x6E6F7172, 0x6E6D6B6B, 0x74625E6F, 0x74767679, 0x77787979, 0x7F7B7876,
+    0x7C7D7D7C, 0x6E71757A, 0x63626262, 0x6C6A6865, 0x7C827C72, 0x76747173, 0x74706F6F, 0x74777A78,
+    0x6A6F7274, 0x56595E64, 0x615E775C, 0x61625E6E, 0x694F8559, 0x13285176, 0x1910261C, 0x16201313,
+    0x29191017, 0x567B8219, 0x836E967A, 0x6B6C7087, 0x726C6862, 0x71827477, 0x10171091, 0x13252F10,
+    0x1010171C, 0x17101923, 0x60847A58, 0x66735684, 0x6E6A6868, 0x79777471, 0x5C747B77, 0x5676866C,
+    0x5C67616B, 0x102D1F14, 0x67251028, 0x955B7689, 0x8A8B8B8C, 0x8989898A, 0x936E9489, 0x79778177,
+    0x102A6A6E, 0x10151310, 0x1E131214, 0x13131F1D, 0x817C8D8B, 0x71706368, 0x696E7479, 0x7A746E69,
+    0x7D807E7C, 0x73737478, 0x79797572, 0x60646C74, 0x7870596B, 0x7B8D9A93, 0x777A7274, 0x105F6880,
+    0x10181829, 0x78604720, 0x65696D6E, 0x56585C60, 0x8D685B55, 0x8E78A599, 0x21107F71, 0x1024102F,
+    0x10101B2D, 0x13251618, 0x634F5C16, 0x44567A3C, 0x5B565350, 0x5D5D5D5C, 0x5E5C5C5C, 0x69686461,
+    0x73716F6E, 0x7A797775, 0x56677099, 0x465D624C, 0x1F134859, 0x10191910, 0x10101010, 0x10101010,
+    0x71939610, 0x8F574661, 0x7A7C7B7A, 0x7B797778, 0x6068886D, 0x705F7971, 0x18101925, 0x1F10101D,
+    0x1B1A1F10, 0x6C4C1F13, 0x6866686A, 0x5D545A6B, 0x5A5A5959, 0x57585959, 0x6C625953, 0x6D6F7171,
+    0x44586863, 0x4C4E3C58, 0x101F2613, 0x101D1110, 0x161F1019, 0x4F191310, 0x6056617B, 0x4A505F6C,
+    0x855B3E60, 0x3F4A3E78, 0x107A3849, 0x1B101A27, 0x1910101A, 0x102B101F, 0x5E6F1112, 0x67626263,
+    0x65625E5C, 0x5F626466, 0x7A808588, 0x4A556472, 0x66629274, 0x4E464873, 0x6E673E56, 0x102F6E57,
+    0x1B101810, 0x13131C19, 0x101E1019, 0x35685021, 0x75676D6E, 0x5981667E, 0x463E4E4F, 0x105C6350,
+    0x19111822, 0x21101E10, 0x21232323, 0x18191A1E, 0x1D101E12, 0x674E4810, 0x66747368, 0x7C6E5D59,
+    0x6B6B6A6A, 0x6F6E6B6A, 0x7F80776E, 0x74707077, 0x51107274, 0x10171E18, 0x19191919, 0x19191919,
+    0x191B1C1C, 0x17171819, 0x646A6268, 0x6A726C74, 0x73637362, 0x32485C51, 0x2E1A1017, 0x1F131023,
+    0x2A103114, 0x564A121C, 0x4C45374F, 0x35425A64, 0x6D614E40, 0x4550606C, 0x3D454B50, 0x282A2F35,
+    0x7B797979, 0x7D7F807E, 0x7B7B7B7B, 0x7F7E7D7C, 0x80808180, 0x7B7C7E7F, 0x83817C79, 0x7E7F8182,
+    0x7A7A7A7B, 0x7B7A7A7A, 0x817F7D7C, 0x83838281, 0x777D7E7A, 0x7B746E6E, 0x807F7E7D, 0x83838281,
+    0x7A7A7D7F, 0x918D857E, 0x9192918F, 0x7D81868D, 0x8D8D8883, 0x75798088, 0x837D7977, 0x8A8C8D89,
+    0x84828285, 0x87838183, 0x7E81878D, 0x81838280, 0x8B878481, 0x9393928F, 0x8F939595, 0x8787898C,
+    0x82808080, 0x83848684, 0x82828283, 0x6E6E737C, 0x6F6E6E6E, 0x72737371, 0x75737272, 0x7A7A7A79,
+    0x72737476, 0x70727373, 0x6D6C6E71, 0x7877746F, 0x6F717475, 0x8C847A72, 0x8E8F9090, 0x87888A8C,
+    0x8A87837F, 0xB1A5968D, 0xA4ABB1B4, 0x878C939B, 0x78757578, 0x6870787A, 0x837A6E66, 0x8B8B8B89,
+    0x74747575, 0x79787675, 0x78797A7A, 0x76767777, 0x817D7B7A, 0x7E818383, 0x77747476, 0x8C89847D,
+    0x74818C91, 0x6C68666A, 0x6D70726A, 0x5C5E666C, 0x564A494C, 0x6A707168, 0x746E6866, 0x81817D79,
+    0x787B7E80, 0x6E6F7174, 0x7473706E, 0x7F7B7875, 0x878D8D8A, 0x8D8D8985, 0x99988F87, 0x797D8591,
+    0x85817E7C, 0x93918D8A, 0x98999894, 0x7A7F8791, 0x70747472, 0x938B7D72, 0x8D888C96, 0x9C8F888D,
+    0x979C9FA1, 0x8E8D8E91, 0x8D8C8C8D, 0x87898C8E, 0x7A7B7F82, 0x8482807C, 0x8181807E, 0x74767B80,
+    0x72727374, 0x84817B75, 0x949F9988, 0x8D8B8687, 0x938D898C, 0x74717A8B, 0x6B6D7074, 0x65676869,
+    0x68686765, 0x5B5C6064, 0x787A746A, 0x78787474, 0x787B7B7B, 0x7C777374, 0x84858381, 0x807E7E81,
+    0x8483817E, 0x7C7F8283, 0x877E7B7D, 0x787E878B, 0x524F4B5A, 0x6661685E, 0x948D7A6B, 0x8D8B8C91,
+    0x6E6A788C, 0x7F7C7A77, 0x7B7C7D7E, 0x7B7B7B7B, 0x7B7C7E7E, 0x7777787A, 0x74747576, 0x76757474,
+    0x7A797878, 0x7A7A7A7A, 0x807E7A78, 0x7B7C7D7F, 0x87868381, 0x81838687, 0x7374797D, 0x7A7A7774,
+    0x7B7C7D7D, 0x7A7A7A7B, 0x7F7E7D7D, 0x7C7C7E7F, 0x78797A7A, 0x78787878, 0x77787878, 0x76767677,
+    0x74747575, 0x74747474, 0x77747473, 0x7D7C7A79, 0x787A7B7C, 0x77767677, 0x7D7D7D7C, 0x81807E7D,
+    0x80818283, 0x7B7B7C7E, 0x8683817F, 0x8B8B8A88, 0x88888787, 0x85868787, 0x81818183, 0x85868684,
+    0x86878787, 0x85858585, 0x787C8082, 0x75747475, 0x7F7F7F7F, 0x7C7D7E7F, 0x7F7F7E7E, 0x7C7C7E7F,
+    0x7A797472, 0x7375797B, 0x7A787675, 0x8583817D, 0x8B8C8C8B, 0x7F818588, 0x87837E7B, 0x81848788,
+    0x7E808181, 0x81807F7E, 0x8784817E, 0x8B8C8B8A, 0x8A8A8A8B, 0x7A7F8689, 0x85817E7C, 0x89898887,
+    0x8184888B, 0x87868281, 0x88858281, 0x8D8D8D8B, 0x8B8B8C8D, 0x86888C8D, 0x87838180, 0x83868989,
+    0x797E8285, 0x6C6E6F74, 0x5F5C6064, 0x73726E66, 0x76757475, 0x62636973, 0x6E696763, 0x8A8A8378,
+    0x646E7A82, 0x79726862, 0x787A7978, 0x5E636B74, 0x615B5A5C, 0x7273726B, 0x7C7C7A78, 0x817E7B7B,
+    0x6D6A7584, 0x686C7172, 0x61636668, 0x5053585D, 0x605B5047, 0x776F6662, 0x7F7F7C7A, 0x75777A7D,
+    0x6B6E6F6E, 0x65646568, 0x68666564, 0x736F6B68, 0x7A797876, 0x7B7C7C7B, 0x70707375, 0x7A797673,
+    0x7F7A7B7E, 0x7E838785, 0x8B878585, 0x9092928F, 0x99939190, 0x8E949A9C, 0x72757D85, 0x807F7C76,
+    0x81807F7F, 0x86868482, 0x70717B87, 0x7A787573, 0x6C717B83, 0x8A83796F, 0x85898C8D, 0x7A7A7D81,
+    0x74747677, 0x6F727474, 0x6E6C6E6F, 0x89847A73, 0x82848789, 0x787A7E81, 0x83817A73, 0x7A7A7A80,
+    0x817A7979, 0x77808788, 0x70737475, 0x6D6D6E6E, 0x6E777773, 0x62626266, 0x5F606262, 0x63626160,
+    0x6B6B6B6A, 0x817A726D, 0x797B8185, 0x8D88817B, 0x81818589, 0x8E8E8C87, 0x8286898C, 0x81818181,
+    0x80818284, 0x73767B7F, 0x6C6B6C6C, 0x7574716E, 0x7678797A, 0x71727374, 0x6A6A6D6F, 0x7A78746E,
+    0x7877797A, 0x8B8E8B81, 0x7A818685, 0x777A7A77, 0x4C505A62, 0x6F695D52, 0x87786D69, 0x6571838D,
+    0x746F6761, 0x74747677, 0x7A777473, 0x7A7B7B7B, 0x77767575, 0x7A7A7A79, 0x868B8781, 0x7E79767C,
+    0x6F71797F, 0x74757572, 0x6E6F7070, 0x696A6B6D, 0x545E6363, 0x53514F4E, 0x5E5D5C5A, 0x5D5D5D5E,
+    0x6A64615F, 0x777B7B74, 0x6C6E7174, 0x696B6D6D, 0x6C6A6C6E, 0x6C6E6F6E, 0x6A686868, 0x6E6E6D6C,
+    0x696C6E6E, 0x64646668, 0x7B7B7165, 0x61687076, 0x6A67625D, 0x62646769, 0x716C655F, 0x76747373,
+    0x71797C7D, 0x6D69676A, 0x7072716F, 0x6F6E6C6E, 0x74625D6E, 0x76787779, 0x77767676, 0x79797877,
+    0x7A7B7C7C, 0x6F727478, 0x71706F6F, 0x79787573, 0x7B7A7977, 0x6D6F7479, 0x6E6E7072, 0x7875726F,
+    0x6D717475, 0x5B5D6268, 0x615C6759, 0x61685E6E, 0x7A7D5C44, 0xD6144E6D, 0xDDE5E2EB, 0xE4EBEBEB,
+    0xEBDCE3EB, 0x8F6E73DD, 0x64518573, 0x6766626E, 0x6E676260, 0x74887C71, 0xE7DD3B61, 0xE7E9CCEB,
+    0xDCE1EBEB, 0xEBDEDCE2, 0x606F8774, 0x6371687F, 0x6D6A6868, 0x7674726F, 0x80817C79, 0x61748786,
+    0x78635A4E, 0xEBE5D014, 0x86C8E5E7, 0x6E748F7B, 0x77777778, 0x75757676, 0x7E647F74, 0x7470656D,
+    0xE1444A68, 0xE9CED7EB, 0xE6DDDDDD, 0xE7EAE9E8, 0x874A7282, 0x9F7E876E, 0x696E7478, 0x79746E69,
+    0x7C808180, 0x6E6E7076, 0x6B6E6E6F, 0x5E606267, 0x5F5C646D, 0x6E76716E, 0x73796A73, 0x17496762,
+    0xDEEBDFE4, 0x899AC9D7, 0x6267696B, 0x56575A5E, 0x6B5C656F, 0x83687A6F, 0xD31A7483, 0xEAD3E5E7,
+    0xEBEBDEE0, 0xEBE4EBDF, 0x692F63E8, 0x534A584E, 0x58565554, 0x5C5C5B5A, 0x5E5C5C5C, 0x65646260,
+    0x6B696868, 0x70706E6D, 0x7A707474, 0x4E4A543B, 0xC41B564C, 0xE9E5EBC4, 0xE8E8E8E8, 0xE8E8E8E8,
+    0x8F556FEB, 0x6E7A7593, 0x5B5F6E7B, 0x61646560, 0x4A727E51, 0x6B54585E, 0xE1EBD52E, 0xE4EBE7E8,
+    0xE6E8EBEA, 0x6668E6EB, 0x4E5D5E4F, 0x6E6C5F4F, 0x53535252, 0x53535454, 0x635C5653, 0x67686867,
+    0x375B6352, 0x44505A4F, 0xEBE2D820, 0xEAE6D6CC, 0xDCE8E5E8, 0x6FE8E2EB, 0x45556166, 0x43504E43,
+    0x495A525A, 0x4E4D4276, 0x2B446056, 0xD0EBEBDC, 0xDCE4EBD1, 0xEBE2D2EB, 0x438CE3D5, 0x60626E6E,
+    0x625E5956, 0x5D606264, 0x74736F6C, 0x5E626970, 0x6E6C8561, 0x4A4B496C, 0x7A63582A, 0xE929566C,
+    0xDDD9EBE9, 0xE2EBE2EB, 0xE7DEDBEB, 0x785A54DC, 0x7B74715E, 0x687B5673, 0x443E5154, 0x1462654E,
+    0xEBE3E3E4, 0xEBE3EBE7, 0xE2E3E3E3, 0xDFDFE0E1, 0xE8E0E9E2, 0x636C60C8, 0x727B786E, 0x7C746867,
+    0x58575D62, 0x7D776C60, 0x7C7C746D, 0x6B6B6E75, 0xD0347668, 0xEBEBE4CA, 0xE9E9E9E9, 0xE9E9E9E9,
+    0xE9E9E9E9, 0xE8E8E8E8, 0x5B5D5756, 0x61646062, 0x50485064, 0x104D4946, 0xDFE9EAE8, 0xEBEBEADB,
+    0xD7EADEEB, 0x4876D4E3, 0x5B4E4958, 0x3F4B616D, 0x6960534A, 0x4E56626A, 0x3F474D50, 0x2C2E3238,
+    0x79747372, 0x8483817E, 0x7F808181, 0x807F7F7F, 0x80818080, 0x7D7E7F80, 0x82817C79, 0x80808182,
+    0x77777878, 0x78787777, 0x817C7A77, 0x8B8A8785, 0x7A817C74, 0x877A6D6F, 0x82858789, 0x7C7D7E81,
+    0x81818284, 0x95918A84, 0x93928F8D, 0x87898E92, 0x8A8D8C89, 0x75787D84, 0x938A8380, 0x999B9C99,
+    0x898A8A8B, 0x89848286, 0x7E81888F, 0x8C8A8681, 0x9699958F, 0x999E9E98, 0x8F9B9F9D, 0x84888A89,
+    0x83828283, 0x87878786, 0x8A8A8989, 0x74747A84, 0x706E6F71, 0x74747472, 0x79747373, 0x8383817D,
+    0x787A7C7F, 0x6F727476, 0x68686B6E, 0x7876726D, 0x686D747A, 0x9387776B, 0x898B8B8C, 0x82848687,
+    0x84837F7A, 0xA59A8D85, 0x999FA3A5, 0x83868C92, 0x7A797A7D, 0x6E747A7C, 0x8A837A73, 0x8A8B8D8D,
+    0x74757778, 0x79787674, 0x78787878, 0x78787878, 0x817E7C7B, 0x7F818383, 0x7A777778, 0x8081817F,
+    0x6B788287, 0x68635F62, 0x73757066, 0x65686C6E, 0x75656062, 0x8B929389, 0x7D7E8081, 0x7D7D7C7C,
+    0x81818180, 0x76787B7F, 0x79787674, 0x7D7B7A79, 0x84868581, 0x8B8B8884, 0x8E938C83, 0x6C6D7481,
+    0x817D7A78, 0x8D8C8885, 0x93949391, 0x8183878E, 0x6E6F706F, 0x8D898074, 0x8C898D96, 0x8D838188,
+    0x9D9C9894, 0x8C8F9399, 0x8A898887, 0x8286898A, 0x787C8389, 0x7C7A7977, 0x7E7E7B7A, 0x6F73777C,
+    0x78726F6F, 0x8182827F, 0x8F958E81, 0x8E8D8887, 0x8B8B8989, 0x7F787882, 0x6B6E757B, 0x6A6C6E6C,
+    0x686A6867, 0x56585D63, 0x777A736A, 0x7D7A7473, 0x8686827F, 0x87868484, 0x88898887, 0x83838487,
+    0x85838180, 0x7D7E8184, 0x81818180, 0x5E6C7B81, 0x49514A4C, 0x6259574A, 0x938D7E71, 0x8C8A8B8F,
+    0x736A788D, 0x747C8481, 0x7A7A7B7B, 0x7D7C7B7B, 0x7D7E7F80, 0x797A7A7B, 0x6B6E7477, 0x77746E6B,
+    0x79787777, 0x7979797A, 0x7E7C7975, 0x7A7A7A7C, 0x81818282, 0x82828181, 0x74767B80, 0x7D7B7975,
+    0x80818181, 0x7C7C7E7F, 0x7E7E7D7D, 0x7A7B7C7D, 0x78797A7B, 0x76767677, 0x77777777, 0x76767676,
+    0x71727272, 0x70707171, 0x7472706F, 0x7A797875, 0x77797A7A, 0x76767676, 0x7A7A7B7B, 0x7F7C7A78,
+    0x84838382, 0x80818283, 0x87878685, 0x87878787, 0x87878786, 0x85858687, 0x81808181, 0x86878684,
+    0x85868787, 0x82828384, 0x797A7C7D, 0x76767778, 0x7F7D7A7A, 0x84838281, 0x87878786, 0x84858787,
+    0x80817F7E, 0x6E72787D, 0x7F7C7A79, 0x86858381, 0x86878787, 0x7A7C8083, 0x86817C79, 0x81838787,
+    0x7E818284, 0x7D7C7C7C, 0x8581807E, 0x8A8A8887, 0x88888989, 0x7B7F8487, 0x8381807F, 0x83848484,
+    0x7E7F8488, 0x81828280, 0x8784817E, 0x87878687, 0x87878786, 0x87878788, 0x87878686, 0x7A7E8387,
+    0x777A7D7F, 0x75757475, 0x5F5E6266, 0x72706C65, 0x78797675, 0x5D5E6470, 0x6C65605C, 0x89898376,
+    0x6874818A, 0x6E6A6462, 0x71716E6D, 0x5F63696E, 0x5A55575C, 0x61656863, 0x867F756E, 0x84868788,
+    0x6E6E7884, 0x686C7071, 0x6865676B, 0x5761696C, 0x5C564A3E, 0x7068605C, 0x837F7872, 0x73767B81,
+    0x6B6E6F6F, 0x65646568, 0x6F6F6E6E, 0x7573706F, 0x7E7A7775, 0x86858381, 0x686E787F, 0x7C78706A,
+    0x8078797C, 0x878D8F8A, 0x8B878686, 0x8D8F8F8E, 0x96928F8E, 0x8B909799, 0x7A7A7D81, 0x82817F7C,
+    0x84807E7F, 0x8D8E8E8A, 0x6F717A86, 0x79777473, 0x7474787C, 0x928D847A, 0x85898D8E, 0x7A7B7E81,
+    0x6E717477, 0x68696C6E, 0x69656464, 0x89837A71, 0x8386888A, 0x787A7F81, 0x7C79716B, 0x7676787A,
+    0x837C7979, 0x79808788, 0x72747677, 0x6B6C6E6F, 0x6C73736E, 0x62626263, 0x5C5D5E5F, 0x5F5E5C5C,
+    0x62606060, 0x7D766D65, 0x6E72797E, 0x83807972, 0x7F7F8489, 0x918F8A84, 0x81848788, 0x81818080,
+    0x7D7F8181, 0x7274797C, 0x6C6C6C6C, 0x7473706E, 0x76777878, 0x73747475, 0x66686C6F, 0x76746E69,
+    0x77747575, 0x8A8D8B81, 0x83878786, 0x80828381, 0x5457626B, 0x6E6A6259, 0x83766E6E, 0x67718189,
+    0x7A786F68, 0x75747579, 0x76767474, 0x72737476, 0x74716F6E, 0x83817D78, 0x878A8886, 0x82818183,
+    0x6F71787E, 0x73747573, 0x6E6E6F70, 0x69696B6C, 0x525C6261, 0x4D4D4B4B, 0x5D5C5B59, 0x56585B5C,
+    0x615A5858, 0x71797A6E, 0x6262676B, 0x5E626564, 0x625F6061, 0x6B6A6865, 0x6B696868, 0x6F6E6E6D,
+    0x6E707172, 0x68686A6C, 0x76756E65, 0x62676D72, 0x6867625D, 0x5B5D6266, 0x6F69625E, 0x70727373,
+    0x77797774, 0x6A6A6D71, 0x7576726E, 0x6F6E6E71, 0x73625D6B, 0x76787777, 0x75727272, 0x787A7B7A,
+    0x78797A7A, 0x72737476, 0x78767676, 0x7E7D7B7A, 0x80787B85, 0x626B7A83, 0x6A6A6968, 0x7974706C,
+    0x71747778, 0x6264686C, 0x6A645A5F, 0x50625B72, 0x58896E95, 0xE9162710, 0xE8E1EBEB, 0xE4EBE2E6,
+    0xE1DFEBE2, 0x101028E7, 0x68454A10, 0x72625669, 0x7C776C6A, 0x5174806E, 0xD8D12810, 0xE8EBCAEB,
+    0xE4EAEBDE, 0xEBE5E2D8, 0x87645811, 0x7363697C, 0x6B6A6969, 0x706F6E6C, 0x6E768768, 0x7A78928C,
+    0x94726577, 0xEBD2E015, 0x5CD4EBE0, 0x6F8D9355, 0x6C6C6C6C, 0x6B6B6B6B, 0x797A7D63, 0x1F1C1050,
+    0xD0121326, 0xEBEBEBE7, 0xE8EBEBEB, 0xE5EBDAE3, 0x552E2519, 0x8770725F, 0x676A7074, 0x74706A66,
+    0x777B7D7D, 0x696A6D72, 0x5E646B6F, 0x615F5C5B, 0x6C5C6A5E, 0x82857A7A, 0x605F5B68, 0x3972666E,
+    0xEAEBE5EA, 0x7A92D6E6, 0x5E626365, 0x5456575B, 0x7058504F, 0x7C727179, 0xE21B2B10, 0xEBD2E8E5,
+    0xE0E8E6E8, 0xE5E5D0D7, 0x633438DA, 0x63505362, 0x56545454, 0x5C5B5957, 0x5D5C5C5B, 0x5F5F5F5E,
+    0x61605F5E, 0x63636262, 0x8B636352, 0x635A6349, 0xDE103B15, 0xEBE4E4EB, 0xEBEBEBEB, 0xEBEBEBEB,
+    0x1A132DCC, 0x70552812, 0x4E5C6D77, 0x7D6E594C, 0x146E8866, 0x1A101030, 0xD6E7E33E, 0xE8E2DEEB,
+    0xEBE6DDCC, 0x1728D6EB, 0x5B52341A, 0x56443841, 0x4D4D4C4C, 0x504F4F4E, 0x56555353, 0x5E5D5C59,
+    0x363F3B44, 0x1013665B, 0xEBEAE531, 0xEBE0E4E8, 0xE5E2EBEB, 0x32DDD6EB, 0x6256392C, 0x4B413844,
+    0x394E525A, 0x5A4A4D70, 0x25191F2A, 0xE0EBEBDF, 0xE3E7EBE4, 0xEBE2E4EB, 0x1434CDEB, 0x6F7B7D53,
+    0x645E5853, 0x5F626567, 0x716D635C, 0x6C6C6D70, 0x66686C4E, 0x5860505B, 0x78637D76, 0xDE2C1E15,
+    0xE8E3EBE8, 0xE5E5E5E9, 0xEBEBEBE2, 0x10112DEB, 0x6F4D3510, 0x7A856379, 0x3E435E67, 0x10555642,
+    0xEBEAEBEB, 0xE3E4E8EA, 0xE2E2E2E2, 0xE3E3E3E3, 0xE4DEE6EB, 0x7D7926DD, 0x7E817A72, 0x77767577,
+    0x50525D67, 0x7F77695A, 0x7A79746F, 0x65686E75, 0xE5295C55, 0xEBE7EBE8, 0xE6E6E6E6, 0xE6E6E6E6,
+    0xE8E8E8E8, 0xEAEAE9E9, 0x5352534C, 0x5151544D, 0x26194F48, 0x1114294F, 0xEBDDD9EB, 0xE6E4E8EB,
+    0xD6E9E1EB, 0x104ABBE9, 0x503A4345, 0x66676866, 0x65605B59, 0x565C6568, 0x40464B4F, 0x3133363A,
+    0x78737070, 0x8887847F, 0x83868788, 0x7E7F8081, 0x81818181, 0x7F7F8081, 0x817F7B79, 0x80808081,
+    0x75767777, 0x77777675, 0x827D7976, 0x8F8E8B87, 0x7A7E7A74, 0x8B817574, 0x85898D8E, 0x7A7B7D81,
+    0x81818284, 0x93908A85, 0x938E8987, 0x91939696, 0x878C8E8F, 0x787A7D81, 0x988F8783, 0xA4A4A39F,
+    0x8E939699, 0x8C868388, 0x83878D93, 0x8F8D8985, 0x90999A93, 0x8F98988F, 0x8F9D9C91, 0x82878786,
+    0x85838485, 0x88898887, 0x8E8E8D8D, 0x78797F88, 0x72707273, 0x77787774, 0x7C777575, 0x8B8A8782,
+    0x7E818689, 0x6D70757A, 0x62626568, 0x76736E68, 0x6E707477, 0x92887C72, 0x8B8C8D8D, 0x84858788,
+    0x82868581, 0x9088807E, 0x8F929394, 0x8385888C, 0x7E7D8082, 0x757A7F80, 0x8A87817D, 0x80818588,
+    0x7476797A, 0x77767474, 0x77777676, 0x79797878, 0x7E7B7A7A, 0x81828281, 0x81818182, 0x6E747A80,
+    0x6871787A, 0x6B666262, 0x7879726C, 0x6E767674, 0x81797474, 0x878C8D8A, 0x7E82878A, 0x7C7B7A7B,
+    0x87858280, 0x7A7E8286, 0x7B7C7A7A, 0x7A7A797A, 0x81807E7B, 0x8C8B8784, 0x7B898D8C, 0x6F68636B,
+    0x80808181, 0x7F7F7F80, 0x8B898582, 0x92908D8D, 0x8F919598, 0x8E959993, 0x8C8A8C92, 0x807A7C87,
+    0xA19B9189, 0x888E989F, 0x8B8A8782, 0x7D848A8C, 0x757A8186, 0x75757474, 0x81817F7D, 0x71747A7E,
+    0x7A716D6B, 0x81868884, 0x767A7A77, 0x82817C76, 0x86898A8B, 0x817C7A7F, 0x6E707476, 0x7474726F,
+    0x686D6F6F, 0x5F5D5E62, 0x7574726F, 0x7D7A7775, 0x8D8C8780, 0x888B8C8C, 0x8C8B8A89, 0x8386888B,
+    0x85828182, 0x7D7D8084, 0x7A818481, 0x50627276, 0x55605A59, 0x726F6E5A, 0x8D8A7E74, 0x8786868A,
+    0x786F7A8C, 0x737D8887, 0x7A7A7A7A, 0x7E7D7B7A, 0x7C7E7E7F, 0x797A7A7B, 0x686D7377, 0x77736D68,
+    0x78787776, 0x78787979, 0x7C7B7874, 0x79797A7B, 0x7B7D8183, 0x83817D7B, 0x76797E82, 0x807E7A77,
+    0x82838383, 0x7D7E8081, 0x7B7C7C7C, 0x7A7A7A7B, 0x77797A7B, 0x75757576, 0x76767676, 0x76767676,
+    0x6F6F6F6F, 0x6E6E6E6E, 0x706E6D6C, 0x75747472, 0x76777979, 0x73737474, 0x76777574, 0x7A787574,
+    0x87858280, 0x82848787, 0x85868687, 0x82838384, 0x86858584, 0x84848586, 0x81808181, 0x87878785,
+    0x84858687, 0x7E7F8182, 0x79797979, 0x76777879, 0x7F7B7977, 0x86858481, 0x88878787, 0x85868787,
+    0x85868583, 0x72757B81, 0x8481807E, 0x86868786, 0x7F818283, 0x7577797C, 0x85807A76, 0x80828587,
+    0x7F828486, 0x7274777B, 0x81807E7D, 0x88878684, 0x87878787, 0x7D808285, 0x8181807F, 0x7D7E8081,
+    0x837F7E80, 0x757C8487, 0x84817B76, 0x82828384, 0x83828180, 0x87868584, 0x84858686, 0x70757C81,
+    0x72747577, 0x79777473, 0x61616468, 0x716E6A65, 0x7B7B7774, 0x5F5F6572, 0x6462615F, 0x7A7A756C,
+    0x777A7B7C, 0x686A6E74, 0x746F6B68, 0x6E717475, 0x615D6269, 0x5E666C69, 0x81766961, 0x85878988,
+    0x6F737B84, 0x6B6D6F6F, 0x6E69696D, 0x68707675, 0x63635B52, 0x6C645D5E, 0x7E7C7874, 0x7374787B,
+    0x6A6F7476, 0x66646265, 0x7576736E, 0x73747474, 0x807B7875, 0x8E8D8985, 0x6972808A, 0x847D736A,
+    0x7D787A80, 0x80878B87, 0x8C8A8887, 0x8C8D8D8D, 0x928D8C8B, 0x858B9294, 0x7B7B7B7C, 0x7F7E7D7B,
+    0x837C7A7A, 0x8F92928D, 0x6F707983, 0x79777473, 0x7C777677, 0x94928C83, 0x82878B8D, 0x797A7C80,
+    0x6D6F7477, 0x68686A6C, 0x6E67625F, 0x87847E76, 0x82838687, 0x7A7C7F81, 0x7474716F, 0x73737374,
+    0x857F7A78, 0x7C818788, 0x74787A7B, 0x66686C70, 0x6A706F69, 0x64646264, 0x5C5D5E5F, 0x5A5A5A5B,
+    0x54515152, 0x736C6259, 0x6B686B6E, 0x7C7A7771, 0x7A7B8084, 0x8A87837E, 0x7B7D7F80, 0x7C7B7A7A,
+    0x77797A7C, 0x6E707476, 0x6D6C6C6B, 0x7473716E, 0x76767676, 0x75757676, 0x63666C71, 0x726F6A66,
+    0x827B7774, 0x8990938C, 0x91918F8D, 0x8C8E9091, 0x6E737C85, 0x73747470, 0x81777476, 0x67707D85,
+    0x7F7D746D, 0x7674747A, 0x74747575, 0x6E6E7173, 0x736F6D6C, 0x88857F79, 0x87878788, 0x86878989,
+    0x7071777D, 0x70737473, 0x6B6D6E6E, 0x6868696A, 0x5A5D6162, 0x6264625C, 0x5C5C5C5C, 0x56585B5C,
+    0x5C565657, 0x6C76796B, 0x5C595C5F, 0x61646662, 0x59565656, 0x6866625D, 0x6F6E6D6D, 0x74737271,
+    0x70727374, 0x696A6C6E, 0x6E6E6A65, 0x6265686C, 0x6868625E, 0x585C6066, 0x6C645E5B, 0x6C6E7271,
+    0x7A78726D, 0x6B6E7278, 0x7B7B746E, 0x6E6D6F75, 0x71625E6A, 0x73757474, 0x726D6C6E, 0x7C7F7F7A,
+    0x74767779, 0x74747474, 0x74737372, 0x78777674, 0x897F8391, 0x636B7D8D, 0x6D66615E, 0x75767673,
+    0x73767879, 0x696A6D70, 0x605E4C65, 0x51585367, 0x4F5C4E45, 0xE2E4D342, 0xEBEBE8DC, 0xE8E7E2EB,
+    0xC8D7EBE2, 0xEBEBD0EB, 0x7B8CDFDE, 0x78706471, 0x80816A68, 0x28567456, 0xE2EBEAEB, 0xD7EBEBD8,
+    0xEBE4E6E3, 0xE5E5EBDF, 0x6858CAE6, 0x6D657D65, 0x6868696A, 0x6A696968, 0x6E5C6D65, 0x96949381,
+    0x70687C93, 0xE5EBDB32, 0x63C4D4CA, 0x6A767A63, 0x6B6B6B6B, 0x6B6B6B6B, 0x716E6E55, 0xEBB43E68,
+    0xEBC6E7EB, 0xC7DFEBE5, 0xEBEBE8E4, 0xD6EBDEEB, 0x62EBE1D6, 0x767A536E, 0x62666C70, 0x6E6B6662,
+    0x70717171, 0x6E6E6E6F, 0x5C636E74, 0x67635E5B, 0x5D596D67, 0x65636463, 0x68625B71, 0x15535C71,
+    0xDBE4E1EA, 0x828FD7DA, 0x575A5B5C, 0x51525456, 0x695D5757, 0x686B4A69, 0xEBE0BB3A, 0xE8E9DEE6,
+    0xE9E9E6EB, 0xE1EBEBEB, 0x69DCCFEB, 0x4B3E444A, 0x5451504F, 0x5C5A5856, 0x5C5C5B5B, 0x58595B5C,
+    0x58585857, 0x5A595959, 0x5046546A, 0x4950363A, 0xE5EBE110, 0xC5EBD4E6, 0xE7E7E7E7, 0xE7E7E7E7,
+    0xEBEBD3E7, 0x6475D6E0, 0x64635B53, 0x7C716562, 0x1E457A8E, 0xDFEBEBC5, 0xE3E3EBC7, 0xEBE6E5EB,
+    0xEBE8E5DB, 0xEBE0EBDC, 0x40125DE0, 0x3E486060, 0x4B4B4B4B, 0x4E4D4C4C, 0x4D4F5154, 0x5654504E,
+    0x4E6D4C4D, 0xDF392F31, 0xC3E4E0E3, 0xE0DEEBEB, 0xEBE1E2DC, 0xE1EBE7D2, 0x4A165EE8, 0x45536868,
+    0x4D4E535C, 0x3631524E, 0xD7DC2E3E, 0xEBCBDCEB, 0xE6E7E5EB, 0xC3E4EBEB, 0xEBEBDAEB, 0x7557466E,
+    0x6E68615C, 0x66696E70, 0x6F6E6863, 0x5F62666C, 0x585B5B55, 0x747C6756, 0x5B495256, 0xE1EBC329,
+    0xEBEBD2C9, 0xEBE2EBEB, 0xD4DCEBE8, 0xEBEBC5EB, 0x5A6AC1E2, 0x8D96746E, 0x474D6B74, 0x145F5E4A,
+    0xE8E4EBE9, 0xEBEBE0EB, 0xE7E7E8E8, 0xE7E8E8E8, 0xEBEBE0E7, 0x6E7742EB, 0x807C7671, 0x6C71797E,
+    0x67696E70, 0x726E6A67, 0x71707071, 0x62676D70, 0xE7255C5E, 0xE6E1EBEB, 0xEBEBEBEB, 0xEBEBEBEB,
+    0xEBEBEBEB, 0xEBEBEBEB, 0x4B4A5751, 0x3A404C3E, 0xCE453E49, 0xE6E3DDE5, 0xD9E4E9EB, 0xDCEBEBD9,
+    0xE1EBEBCA, 0xD1DDEBEB, 0x5043574F, 0x6E6B6861, 0x63606162, 0x585E6466, 0x3D414548, 0x32333538,
+    0x7B757372, 0x8A898781, 0x85888C8D, 0x7C7D7F81, 0x82828282, 0x7F808181, 0x7D7D7A79, 0x7F7D7C7D,
+    0x77787979, 0x79797877, 0x85807C7A, 0x908F8D89, 0x78777A7F, 0x8786827D, 0x86898C8D, 0x7D7E8082,
+    0x7A7A7B7D, 0x8886817B, 0x90888380, 0x96999997, 0x82878B8E, 0x7A7B7C7F, 0x8B85807D, 0x9D9A9691,
+    0x8F969EA4, 0x8D878488, 0x8C8E9294, 0x8C8C8C8B, 0x818D918D, 0x878D8980, 0x8E99917F, 0x85888785,
+    0x86848585, 0x88898A88, 0x8C8C8A8B, 0x76767C86, 0x74737374, 0x7A7B7A78, 0x7D7A7878, 0x8D8C8883,
+    0x81868B8E, 0x696E747B, 0x5C5C6063, 0x736F6862, 0x7C797471, 0x8B888480, 0x8E909191, 0x88898B8D,
+    0x858B8B88, 0x7F7A787C, 0x89888787, 0x87878888, 0x81818284, 0x7C7F8283, 0x8786817E, 0x84848687,
+    0x76787A7C, 0x76757474, 0x76767676, 0x77777777, 0x78777778, 0x7A7A7B7A, 0x8684807D, 0x70757E84,
+    0x71747574, 0x77736E6E, 0x7C7D7879, 0x76858279, 0x7A7A7673, 0x7A767475, 0x7A7D8182, 0x7E7C7A7A,
+    0x8583817F, 0x7D7F8184, 0x7C7E7F7E, 0x7877777A, 0x817C7A7A, 0x8F8D8986, 0x7A8C9598, 0x8074686B,
+    0x83888D8E, 0x7174787D, 0x837C7673, 0xA49E948B, 0xBABDC4C9, 0x96A6B6BA, 0x89868284, 0x7A787C86,
+    0xA1998D83, 0x878D98A0, 0x9B99938C, 0x848E999B, 0x7474777A, 0x79787775, 0x7D7E7D7C, 0x6F72767A,
+    0x706B696B, 0x6F747876, 0x706A6A6A, 0x8A8C877B, 0x84898D8E, 0x7C7F8181, 0x78787470, 0x7D7A7575,
+    0x69717679, 0x7A736966, 0x6D6F7A84, 0x7C7B7872, 0x8C8D8881, 0x82878B8B, 0x8C888787, 0x80858B8D,
+    0x817C7A7C, 0x807D7E82, 0x767C7F7B, 0x66717875, 0x6E747377, 0x818D967E, 0x88877F78, 0x83818084,
+    0x7A757B86, 0x757C8482, 0x7979797A, 0x7C7B7A7A, 0x7A7B7B7C, 0x77787879, 0x6D6F7375, 0x75736F6D,
+    0x78787776, 0x78787979, 0x7E7C7976, 0x7A7A7B7D, 0x7A7D8184, 0x84817D7A, 0x797B8084, 0x82817E7A,
+    0x82838485, 0x7C7D7F81, 0x7A7A7A7B, 0x7979797A, 0x76787A7A, 0x74747475, 0x76767675, 0x76767676,
+    0x6F6F6F6F, 0x6E6E6E6E, 0x6E6D6C6B, 0x7271706F, 0x72747575, 0x6C6D6E70, 0x75746F6B, 0x75737273,
+    0x8985807C, 0x8285888A, 0x81818181, 0x80808080, 0x84838382, 0x83838484, 0x82818182, 0x88888785,
+    0x82848686, 0x797A7D80, 0x7A7A7978, 0x797A7A7A, 0x7E7B7A79, 0x83828181, 0x81818181, 0x80808181,
+    0x88868280, 0x80828688, 0x87868584, 0x85868787, 0x777A7D7E, 0x6F707274, 0x827D7672, 0x7E818385,
+    0x7E818181, 0x686C7279, 0x7F7D7C7B, 0x86858381, 0x82838382, 0x7C7C7E80, 0x7D7D7C7C, 0x78797A7C,
+    0x807A7979, 0x71798183, 0x817B7570, 0x80818283, 0x7E7C7B7B, 0x85848381, 0x7D7E7F80, 0x696E747A,
+    0x6A6C6E70, 0x77746F6C, 0x6566686B, 0x706E6B68, 0x7F7D7773, 0x6A686E78, 0x62686D6E, 0x686A6862,
+    0x8A807167, 0x6872808A, 0x736E6865, 0x74767776, 0x716C7077, 0x70777D7A, 0x756C625D, 0x7F80807D,
+    0x6E757C81, 0x6C6D6D6D, 0x726E6D6E, 0x7A7A7A77, 0x70797873, 0x6A625E63, 0x74767879, 0x7A767372,
+    0x68727A80, 0x66626062, 0x79787168, 0x6F747878, 0x817C7A78, 0x908E8A86, 0x727A8790, 0x8D867A73,
+    0x7A7A8087, 0x6E757C7D, 0x8D8D8B8A, 0x898A8B8C, 0x8D898787, 0x7E848C8E, 0x76767677, 0x77777676,
+    0x7C757374, 0x898C8C86, 0x6E6E7580, 0x77747371, 0x7F797574, 0x8E8E8B86, 0x7C808589, 0x7476797A,
+    0x7173777A, 0x6D6E6F70, 0x7E766E6A, 0x85868683, 0x7B7A797A, 0x7C7E7F7E, 0x6E71767A, 0x6E6D6D6C,
+    0x867E7772, 0x84878989, 0x777C7F80, 0x61646A71, 0x6C706E67, 0x6C6B6868, 0x60626465, 0x5C5C5C5E,
+    0x4F4C4D4F, 0x6A655C55, 0x64616266, 0x7575736C, 0x7877797A, 0x7A7A7A79, 0x73747474, 0x77767474,
+    0x6F707374, 0x67696C6E, 0x6D6B6A69, 0x7474716F, 0x76757474, 0x79787877, 0x65686F74, 0x6F6E6966,
+    0x87817B77, 0x8B939690, 0x99959291, 0x92939699, 0x8C8C9094, 0x878B8D8D, 0x7E79797E, 0x666D7981,
+    0x807E756E, 0x7775767A, 0x74747575, 0x6E6F7072, 0x74706E6E, 0x87847E79, 0x85828387, 0x868A8D8A,
+    0x7071767B, 0x6E717473, 0x68696B6C, 0x68686868, 0x6B67686B, 0x81858377, 0x5C5C5E60, 0x5B5C5D5C,
+    0x59565859, 0x65737668, 0x5A565657, 0x63666662, 0x57555453, 0x67635F5A, 0x6F6E6E6D, 0x74747371,
+    0x6F717272, 0x68686B6E, 0x68676565, 0x66656567, 0x6C6B6762, 0x5D5F6469, 0x675C5550, 0x6E6F716E,
+    0x7A756E69, 0x6F72767A, 0x81807972, 0x6B6D727A, 0x6F646069, 0x6E727070, 0x6C68696D, 0x7B7C7A74,
+    0x72737475, 0x76747472, 0x77767676, 0x76767677, 0x8D83838D, 0x6F707C8C, 0x716A6768, 0x74787B79,
+    0x73747677, 0x6E6E6F71, 0x62655878, 0x69565C6B, 0x1410164B, 0xE8E2C73D, 0xD0EBD5EB, 0xEAEAEBEB,
+    0xEBEBD0D8, 0xD4DCEBD0, 0x6A7ADEEB, 0x5762636C, 0x52706977, 0x10274110, 0xE0CBE8EB, 0xEBE0E6EB,
+    0xDBC3DAEB, 0xE8EBEBC3, 0x3835C1EB, 0x6E4E5031, 0x66686869, 0x64646465, 0x8C5C5A75, 0x8C907670,
+    0x311D8B7B, 0xCBEBC525, 0x81DDE3EB, 0x605F687C, 0x67676767, 0x67676767, 0x21155B6F, 0xEBB0222B,
+    0xC0EBE0E3, 0xEBEBE8E0, 0xDADBE0E4, 0xD5EBBFE2, 0x1DC5DEEB, 0x59431E25, 0x61646A6E, 0x6B686360,
+    0x6B686564, 0x7776746F, 0x61666F75, 0x68666361, 0x5A5F6A75, 0x736E6E64, 0x63685363, 0x101C2D3F,
+    0xE9EBE6E7, 0x6171D6E2, 0x51525252, 0x4F505050, 0x5754443D, 0x1D371047, 0xCAD7B939, 0xE4E6EBE7,
+    0xEBEBE2E8, 0xE4D8EADB, 0x2EDEEAEB, 0x32293113, 0x53504D4B, 0x57575656, 0x5B5C5B5B, 0x54555759,
+    0x55555555, 0x55555555, 0x51694B5F, 0x1B371054, 0xCCEBDC2B, 0xE3E6DCEB, 0xE9E9E9E9, 0xE9E9E9E9,
+    0xE0E8EBE4, 0x6C63E8DC, 0x65676E75, 0x535A6265, 0x19152410, 0xDBE2EBCA, 0xE6E9D1EB, 0xD7E9E8D2,
+    0xDAEBEBEB, 0xDEE2DEE7, 0x40104ED0, 0x3B44564F, 0x4A4B4C4C, 0x4C4C4B4A, 0x4A4D5155, 0x514F4B49,
+    0x16412F3C, 0xE0341F19, 0xE3E7BEEB, 0xEBEBE4D0, 0xDBE2EBE5, 0xEBE9E0E7, 0x491356E2, 0x313F5050,
+    0x44566257, 0x2E13483A, 0xEBE61910, 0xE7EBEBD1, 0xE2EBDFDD, 0xEBE8EBDC, 0xE7EBD6EB, 0x633C1035,
+    0x7A746D68, 0x6F73787A, 0x6C6E6F70, 0x49515D67, 0x55505363, 0x70727463, 0x1A191051, 0xE8D2D03E,
+    0xCAE0E4EB, 0xE2EADDEB, 0xEBEBDFEB, 0xD2EBDDD0, 0x5F7ADCEB, 0x7A786267, 0x535C7880, 0x105A5E50,
+    0xEBE6EBE7, 0xCADBC7EB, 0xE8E8E8E9, 0xE3E6E8E9, 0xCBE8DBE3, 0x79817DC3, 0x77726E6E, 0x61687379,
+    0x88837568, 0x72747A83, 0x65666B6F, 0x61646867, 0xD1104A50, 0xE8E3E8DE, 0xE2E2E2E2, 0xE2E2E2E2,
+    0xE5E5E6E6, 0xE4E4E4E5, 0x484A5F5E, 0x293C5040, 0xD63A101C, 0xE8EBE3E4, 0xDEEBEBEA, 0xDFEBE7D7,
+    0xE8EBEBE4, 0xEAD2EBD5, 0x40342A10, 0x6164695F, 0x62616264, 0x555B6264, 0x383D4043, 0x30303134,
+    0x7F797574, 0x89898885, 0x85878B8C, 0x7D7E7F81, 0x81828282, 0x7C7D7F81, 0x7A7A7977, 0x7B7A7879,
+    0x7C7C7D7D, 0x7D7D7C7C, 0x87848180, 0x8E8D8D8A, 0x77747E89, 0x81878A82, 0x8788898A, 0x7F808285,
+    0x6E707476, 0x7C79746F, 0x8C837D7A, 0x94979994, 0x7C808589, 0x7F7F7D7C, 0x7F7D7B7A, 0x8E8B8581,
+    0x8A8E979F, 0x8D878587, 0x91929191, 0x888A8D8F, 0x7D868B8A, 0x8E8F887E, 0x8B8F887B, 0x88898786,
+    0x89878686, 0x888A8C8C, 0x81828284, 0x6E6E737B, 0x78747372, 0x7E7F7E7C, 0x7B79797A, 0x87878480,
+    0x7F83888B, 0x666B7279, 0x58585C61, 0x716D655C, 0x837D756F, 0x88878787, 0x8E909191, 0x88898B8D,
+    0x888D8A86, 0x7A797980, 0x8482807F, 0x89888787, 0x84838485, 0x7D808384, 0x81817F7D, 0x81817F80,
+    0x797A7A7A, 0x7A7A7979, 0x77787878, 0x75767677, 0x70727577, 0x6C6E6F70, 0x8881746B, 0x81828689,
+    0x76767472, 0x7E7A7675, 0x83857F85, 0x7A8E897C, 0x7579736C, 0x7E746C6E, 0x75757576, 0x7A797876,
+    0x7C7C7C7C, 0x7F7F7E7D, 0x7C808282, 0x78767678, 0x857D797A, 0x93908E8C, 0x929B9E9C, 0x8F888387,
+    0x878E9396, 0x72747A81, 0x7D777370, 0xAAA19387, 0xC1C6CACA, 0x8E9EB0BA, 0x857E7977, 0x7E7C7F84,
+    0x9C958A81, 0x888D959C, 0xABABA49A, 0x8F9DA8AB, 0x74777A7D, 0x71737474, 0x6A6C6D6E, 0x5F616468,
+    0x62606062, 0x62656665, 0x81746E6C, 0x9699988E, 0x858C8F8D, 0x767F8483, 0x81817A73, 0x817D7A7C,
+    0x6F757B7E, 0x978A796E, 0x686F869A, 0x817D776E, 0x858A8983, 0x7B828583, 0x857F7C7B, 0x757D8789,
+    0x7A716E70, 0x827D7B7E, 0x777B7C7B, 0x7F7F7C78, 0x7E818189, 0x808E9F8D, 0x88898581, 0x84818183,
+    0x7A7A7B7F, 0x797B7E7D, 0x797A7A7A, 0x7A7A7979, 0x77787979, 0x75757676, 0x74747474, 0x74747474,
+    0x79787777, 0x7979797A, 0x81817C7A, 0x7D7E7F81, 0x7F818284, 0x8482817F, 0x7C7E8185, 0x8382817E,
+    0x7F818385, 0x7A7A7B7D, 0x78787979, 0x7A797878, 0x76777879, 0x74747474, 0x75757575, 0x76767676,
+    0x71727272, 0x70707171, 0x6F6E6E6E, 0x7070706F, 0x70717272, 0x696A6C6E, 0x75746E68, 0x716F6E72,
+    0x88837B76, 0x7F83878A, 0x7B7B7B7B, 0x7F7E7D7B, 0x82818181, 0x82828283, 0x82818182, 0x87878785,
+    0x81848585, 0x74777A7E, 0x7B797776, 0x7F7F7E7D, 0x7F7E7D7C, 0x7F7F807F, 0x7A7B7D7E, 0x7C7B7A7A,
+    0x8B86807B, 0x8D8E8F8E, 0x86878787, 0x81818385, 0x7074787A, 0x6A6A6B6E, 0x807A736E, 0x7B7E8182,
+    0x787A7978, 0x63676E74, 0x7E7B7A79, 0x81818180, 0x7C7F8080, 0x74747578, 0x77767574, 0x74747576,
+    0x6D6B6E70, 0x74747470, 0x7A777474, 0x7F81817F, 0x77747578, 0x8081817D, 0x7A7B7B7C, 0x696E7479,
+    0x6465686A, 0x746F6A66, 0x6D6E6F70, 0x72716F6E, 0x837E7874, 0x7A797B81, 0x68737C81, 0x68696866,
+    0x8F816F62, 0x6D788792, 0x6966625F, 0x67686A6B, 0x77707074, 0x7F858781, 0x6E6C6C6C, 0x78787673,
+    0x6E767C7D, 0x6E6D6A69, 0x72716F6E, 0x7E7B7774, 0x6D7A7B78, 0x5E56525B, 0x6E727577, 0x807A736E,
+    0x68737D83, 0x63605D60, 0x7F7C7368, 0x777F8280, 0x807D7C7B, 0x8C8A8783, 0x7C81898F, 0x8C88827D,
+    0x7A7A7E81, 0x777B7E7E, 0x8D8D8D8B, 0x8787878A, 0x8A878585, 0x7980878B, 0x74737373, 0x70737576,
+    0x7D777575, 0x898A8884, 0x6E6E7681, 0x73717170, 0x7C777473, 0x84858581, 0x74767C81, 0x6E717373,
+    0x71717374, 0x71737373, 0x88837C78, 0x7D818789, 0x78747271, 0x8081807C, 0x686F7981, 0x6A6A6968,
+    0x857C736C, 0x88888988, 0x7A7F8182, 0x5D626A72, 0x70726E67, 0x7674706E, 0x6A6C6D6E, 0x66666868,
+    0x59585A5C, 0x6A68635D, 0x57596168, 0x6867635C, 0x78746F6C, 0x6A6E7478, 0x6B696868, 0x72706E6D,
+    0x6C6E7072, 0x6567696B, 0x6B686765, 0x7473716E, 0x76747372, 0x7B7A7978, 0x6A6E747A, 0x6F6E6C69,
+    0x7A767574, 0x83888981, 0x918B8786, 0x8C8C8E92, 0x908C8988, 0x92939493, 0x7A777A81, 0x636A747B,
+    0x7F7B736C, 0x7A797A7D, 0x74757677, 0x71717273, 0x74737171, 0x817F7B78, 0x807C7E81, 0x83878A87,
+    0x7171757A, 0x6C707474, 0x67686869, 0x6B696868, 0x736E6E71, 0x888E8D81, 0x5F606367, 0x5F616261,
+    0x56565B5A, 0x606E7263, 0x59565555, 0x5E5E5E5C, 0x5A5A5857, 0x62605C5B, 0x68676665, 0x6D6C6B69,
+    0x6E6E6E6E, 0x6466686B, 0x62606164, 0x6A666362, 0x73726F6C, 0x66686B6F, 0x6E68625E, 0x6D6E7070,
+    0x74716D6A, 0x79797977, 0x82817A75, 0x696E777F, 0x6F666269, 0x6C706F6E, 0x68686A6E, 0x7373716D,
+    0x70707171, 0x76757472, 0x80818181, 0x7A7B7D7F, 0x84807A79, 0x7B75757F, 0x74757A7F, 0x70747675,
+    0x6F707172, 0x6F6F6E6E, 0x74766F80, 0x54285C79, 0xE6C81A56, 0xE5CBEBE0, 0x212CBBE8, 0x101E1010,
+    0x1D191F30, 0xEBEBDE10, 0x6B78D4DC, 0x7D7E7472, 0x646F5C6F, 0xEAE8C937, 0xE4EBE4E4, 0x25101FD6,
+    0x23172710, 0xCFEBBF26, 0xE0D2EBD6, 0x936E7AB5, 0x63656868, 0x5F5F6062, 0x60567A55, 0x7A68625B,
+    0xC6117F6A, 0xEBE4EBB5, 0x66DDE0DE, 0x626A5F67, 0x61616060, 0x62626261, 0xBF386560, 0xE2EBD5E9,
+    0x1CDEEBEB, 0x101A2419, 0x161C1914, 0xEBC92225, 0xEBE9EBE6, 0x7560D7E4, 0x6064696D, 0x69676260,
+    0x68626060, 0x7A78746E, 0x62646A70, 0x60626262, 0x6E6C5F60, 0x4B645C72, 0x62716E62, 0xE8DE3A6D,
+    0xE6E8DCDB, 0x646FE1E5, 0x4D4C4C4C, 0x4F4E4E4D, 0x55544D4F, 0xDCD63E5F, 0xEBCCEBDB, 0x152DC6EB,
+    0x101D2512, 0xDEC52731, 0xD0EBD7E9, 0x5772D6E1, 0x504F4D4B, 0x55555452, 0x595B5C5C, 0x51535557,
+    0x53535353, 0x53535353, 0x5B724E56, 0xE3C5316D, 0xE6C5EBE4, 0x1927C2EB, 0x10101010, 0x10101010,
+    0xEBEAD11B, 0x6A56EBEB, 0x565C666D, 0x4A4D5154, 0xD0E3CA44, 0xEBC7E8EB, 0x312525C1, 0x17212613,
+    0x221A1016, 0xEBE9EBCA, 0xE8EBDBD0, 0x5A585674, 0x494A4A4B, 0x4D4C4A4A, 0x4B4E5254, 0x4F4D4B4A,
+    0x2D3B455E, 0xD6C9EBC6, 0xEBEBDFC7, 0x1010111B, 0x12101010, 0xB7EBEBEB, 0xDDE7CCC8, 0x48474062,
+    0x3A495653, 0x99134062, 0xE6E5EBE5, 0x24D9EBDA, 0x20211816, 0xCA31171F, 0xEADCEBDF, 0x7DC7E2E5,
+    0x7A756F6B, 0x72757A7B, 0x6C6E7275, 0x444E5C66, 0x5245455E, 0x553B5F6C, 0xDECA106B, 0xEBD4EBCB,
+    0x1E1FB0D1, 0x102A1913, 0x1013101B, 0xE4EBC410, 0x6070CED2, 0x6060616D, 0x66697D7E, 0x105D6962,
+    0xCDDAEBEB, 0x103741B3, 0x15121111, 0x10131818, 0x101B1714, 0x756D561F, 0x6E6A6D73, 0x60656D70,
+    0x998B6F58, 0x80828A96, 0x62656C72, 0x64666764, 0xDF236268, 0xEAE8EBE8, 0x1F1F1F1F, 0x1F1F1F1F,
+    0x14151515, 0x13131314, 0x5257696C, 0x27496457, 0xEBE2E3E0, 0xEBD7D1EB, 0x25191013, 0x17101018,
+    0xBC151014, 0xEBE0EBEB, 0x58B7E5EB, 0x675D5B54, 0x615F5F5F, 0x52585E62, 0x393F4447, 0x2C2D3034,
+    0x817A7674, 0x87898A87, 0x82848687, 0x80808081, 0x7F818181, 0x797A7B7D, 0x76777776, 0x77757474,
+    0x81818283, 0x83828181, 0x89878584, 0x8D8D8D8B, 0x7A7A838D, 0x81878983, 0x88898988, 0x7D7F8387,
+    0x696D7275, 0x76736E69, 0x877F7A7A, 0x8D919390, 0x7B7D8186, 0x8786837F, 0x7A7E7F7F, 0x7F7C7978,
+    0x807E848C, 0x89878583, 0x918F8C89, 0x898B8D90, 0x83868A8D, 0x97928B86, 0x81828689, 0x88888783,
+    0x8D898786, 0x898C8F8F, 0x7577787A, 0x6664686F, 0x7A757270, 0x81818280, 0x7776787A, 0x7E7D7C79,
+    0x797B7F81, 0x65696F74, 0x56575C61, 0x706B635B, 0x7C7A7876, 0x8D89837F, 0x888A8A8B, 0x81838587,
+    0x8C8D867E, 0x7E7C7E84, 0x817E7C7A, 0x87868583, 0x84858586, 0x797B8083, 0x74767778, 0x77747272,
+    0x7D7A7877, 0x81818180, 0x7A7B7C7D, 0x74757678, 0x6C6E7376, 0x6667686A, 0x8C867669, 0x81808288,
+    0x77797877, 0x7F7A7675, 0x8C8E858A, 0x7A91897D, 0x797B756E, 0x82797172, 0x7A7A7978, 0x78797A7A,
+    0x73747679, 0x83807A75, 0x7C818587, 0x7A777677, 0x8D817A79, 0x93939595, 0xA9A79E95, 0x99999EA5,
+    0x8A8D8F90, 0x81838587, 0x7C7A7B7C, 0x9F988C81, 0xAEB7B1A8, 0x8287929F, 0x827E7A7A, 0x83818182,
+    0x958F8781, 0x8E909396, 0xA8AAA59B, 0x8D9AA5A6, 0x71798187, 0x6365686C, 0x595C5F61, 0x52525456,
+    0x59575656, 0x605F5D5B, 0x78706862, 0x82817E7C, 0x858E8F89, 0x757E8181, 0x82817C77, 0x82807E80,
+    0x757A7E80, 0x9F928176, 0x7275879A, 0x85827E78, 0x7B848783, 0x747B7D7A, 0x827A7473, 0x6E798588,
+    0x72686468, 0x7D767476, 0x7677787A, 0x867C7474, 0x878D878B, 0x7E828F89, 0x83878582, 0x807D7C7F,
+    0x7E7E7D7B, 0x7C7E7F7E, 0x797A7C7D, 0x76777778, 0x76767777, 0x74747475, 0x79787675, 0x75767879,
+    0x7A797878, 0x7A7A7A7A, 0x8685817E, 0x81828385, 0x86858584, 0x84858586, 0x80818385, 0x83838381,
+    0x7A7E8184, 0x78787778, 0x76767677, 0x7A7A7876, 0x75767777, 0x75747474, 0x75747474, 0x76767675,
+    0x74747575, 0x74747474, 0x73747474, 0x72727273, 0x74747473, 0x70717374, 0x7476716C, 0x706D6C6F,
+    0x87807772, 0x7A7F8588, 0x78777878, 0x7D7C7A79, 0x8181807F, 0x81818182, 0x81808181, 0x84858482,
+    0x81838485, 0x7174787D, 0x77747270, 0x83817F7B, 0x81818181, 0x7D7E7F80, 0x787A7E81, 0x7F7C7A78,
+    0x8F8B8682, 0x8D8F9191, 0x82858789, 0x7B7B7D80, 0x6B6F7476, 0x66666768, 0x7D776F6A, 0x797B8081,
+    0x70737475, 0x5F62676B, 0x7D7A7875, 0x7E7F807F, 0x757B7E7F, 0x6868696E, 0x6F6E6C6A, 0x6F6F7070,
+    0x62626669, 0x7D776E66, 0x73747A81, 0x7E7F7D78, 0x706D7074, 0x797C7E79, 0x78787878, 0x686C7276,
+    0x61626568, 0x736E6862, 0x76777676, 0x75747475, 0x88817A79, 0x8987898B, 0x757D8587, 0x75777673,
+    0x83807A76, 0x74787E83, 0x6B6A6866, 0x6365686A, 0x766E6C6C, 0x83868781, 0x73757C81, 0x7C7A7874,
+    0x6F7A7E7C, 0x72706C69, 0x6F707070, 0x75747270, 0x6771706B, 0x5B534E56, 0x74747474, 0x7C797674,
+    0x68737B80, 0x5F5D5C60, 0x817F7468, 0x838A8A84, 0x7F7E7F7F, 0x84838180, 0x83848688, 0x81828383,
+    0x7D7A7878, 0x88878681, 0x8B8D8C8A, 0x82828387, 0x89878585, 0x777D8689, 0x7D777474, 0x72798081,
+    0x82807E7D, 0x8D8B8986, 0x73747E89, 0x72717274, 0x77737170, 0x7A7B7C7A, 0x6B6D7378, 0x686B6D6C,
+    0x736E6B6A, 0x7F7F7D79, 0x8B87827F, 0x7C81868A, 0x81807F7F, 0x83858584, 0x6A707B84, 0x6C6D6D6A,
+    0x837D746D, 0x81818284, 0x7A7F8181, 0x5E626B74, 0x74757068, 0x817E7974, 0x76767675, 0x75757676,
+    0x6D6D7073, 0x7272716E, 0x585C666E, 0x595C5C5B, 0x7C74685E, 0x6068737B, 0x615E5C5C, 0x6B696764,
+    0x68696C6E, 0x62636667, 0x68646260, 0x72706E6B, 0x75747271, 0x7D7C7A78, 0x70747A80, 0x71706F6E,
+    0x6F6D6C6B, 0x747A7C76, 0x81787372, 0x817F8083, 0x8382807C, 0x82818182, 0x7573767D, 0x62687177,
+    0x7E786F69, 0x7D7D7F80, 0x74767879, 0x71727274, 0x74737271, 0x7A797876, 0x7A76777A, 0x7F838581,
+    0x7171757A, 0x6A6E7374, 0x68686868, 0x6E6D6A68, 0x74747473, 0x7F83827B, 0x696A6E71, 0x62676A6B,
+    0x565A5D5B, 0x5F6D7062, 0x59595755, 0x56565657, 0x5B5C5C5A, 0x5A595758, 0x5E5C5C5B, 0x6262615F,
+    0x6B6C6C6C, 0x61636669, 0x5D5B5D63, 0x6E686260, 0x7A7A7A78, 0x6E6F7276, 0x7B7D7A77, 0x6C6D7076,
+    0x6E6C6D6E, 0x827F7A73, 0x837F7A76, 0x6B737C83, 0x6F686268, 0x6E73706F, 0x6B6B6C6D, 0x6E6E6D6C,
+    0x706E6E6E, 0x76757472, 0x7D7F7F80, 0x7475787A, 0x76787168, 0x7E746C6E, 0x7A828788, 0x65666870,
+    0x6B6B6C6C, 0x6E6E6D6B, 0x6C6C7470, 0x56105A76, 0xE2EB211E, 0xDCE4DCDC, 0x6653E3EB, 0x62745042,
+    0x57597F52, 0xE9DBDB2E, 0x1E3FC7EB, 0x7E755332, 0x667D7290, 0xE8E8CE29, 0xD0DAEBE1, 0x876E67EB,
+    0x6B6C7E62, 0xC7EBCC43, 0xE6DAEAEB, 0x60688BEB, 0x62636668, 0x5C5C5D5F, 0x15196231, 0x13101E23,
+    0xEB101C19, 0xEBC5EBE7, 0x5FEBEBE9, 0x5766565E, 0x5D5D5D5C, 0x5F5F5E5E, 0xCF13635C, 0xD1E5E9E7,
+    0x41E2EBE5, 0x44716E39, 0x565C5044, 0xEBD72C54, 0xEBC1E2E8, 0x8656EBE2, 0x5D616669, 0x65625F5C,
+    0x62606162, 0x6D6E6C68, 0x5D5E6368, 0x55595C5D, 0x5756574C, 0x1F4C1047, 0x10101710, 0xE1DA103E,
+    0xE3E8E7EB, 0x676FE9E7, 0x4B4A4949, 0x50504F4D, 0x535A5150, 0xDEDD2556, 0xE7E1EBEB, 0x657EE2E8,
+    0x2B4A6350, 0xE8E12852, 0xE7E6EBE2, 0x4B40D1EB, 0x4A494949, 0x5C59534E, 0x575A5C5C, 0x51525355,
+    0x51515151, 0x52525251, 0x1E104060, 0xEBBD261A, 0xE1EBE6E8, 0x2E74EBD6, 0x53535353, 0x53535353,
+    0xEBE0D51D, 0x1F2FC0DC, 0x55514A42, 0x4B4C4F53, 0xDCDED424, 0xD9ABEBE3, 0x453755EB, 0x382F3B38,
+    0x404F3943, 0xE8E2D0CF, 0xCAE8EAEB, 0x48595153, 0x4949494A, 0x52504D4A, 0x4F505152, 0x4D4D4E4E,
+    0x19475D5C, 0xE9EBE4CA, 0xEBEAE4EB, 0x5E5F6867, 0x1D33344C, 0xEBDCE9E9, 0xD1EBE8EB, 0x545F4B4E,
+    0x4A42464A, 0xE920436E, 0xEBC3EBE9, 0x4FE9EBE2, 0x4444424E, 0xDC423C45, 0xD7EBEBD7, 0xA2EBEBDA,
+    0x706B6662, 0x6C6E7172, 0x696D6E6E, 0x444C5762, 0x51424258, 0x6A1A4971, 0xEBEB141C, 0xD0EBDDD0,
+    0x756EE4EB, 0x565E6354, 0x4C5F5C39, 0xE9DCE148, 0x203CCFEB, 0x746A5F49, 0x83777A70, 0x30849287,
+    0xEBE7EBEB, 0x3D6866E5, 0x625B5655, 0x61666A68, 0x5E646D50, 0x4E736666, 0x6A69737F, 0x69696C6D,
+    0x92866F5C, 0x81828790, 0x62656C72, 0x61626362, 0xD4104953, 0xE9E0E6E1, 0x61616161, 0x61616161,
+    0x72727171, 0x73737372, 0x60696F71, 0x25557271, 0xE9EBD8DF, 0xEBEBE9DE, 0x4A605E50, 0x6A6D563F,
+    0xCC305161, 0xDEE9CAE3, 0x5CDAEBEA, 0x5C596762, 0x5F5C5A58, 0x55585C5F, 0x424A5156, 0x2B2D3139,
+    0x827A7572, 0x87898A88, 0x81818181, 0x82828181, 0x7D7E7F80, 0x7576787A, 0x74757676, 0x74737172,
+    0x85868687, 0x87868685, 0x8A888786, 0x8D8D8D8C, 0x7F81888E, 0x83848481, 0x8A8B8A89, 0x7A7D8287,
+    0x6A6E7479, 0x77736E69, 0x857E7A7A, 0x868B8E8C, 0x7E7D8185, 0x8E8D8983, 0x7A7F8181, 0x72707074,
+    0x7871737A, 0x86868581, 0x8E8B8682, 0x8C8D8D8F, 0x8583878D, 0x938D8787, 0x77778799, 0x8585847F,
+    0x908C8887, 0x8A8D9193, 0x6D6F7174, 0x5F5D6067, 0x7C76716E, 0x81838482, 0x73747679, 0x76767574,
+    0x74757778, 0x64686E71, 0x56575C62, 0x706B635B, 0x72757A7F, 0x938A7E74, 0x81838484, 0x7A7C7E80,
+    0x8D8C8279, 0x807F8187, 0x7E7C7A79, 0x82828181, 0x84868686, 0x74777C81, 0x6A6C6E6E, 0x78746E6B,
+    0x817B7774, 0x88878784, 0x7C7E8081, 0x7476777A, 0x6A6E7275, 0x67686969, 0x90908376, 0x72717784,
+    0x7A7F8181, 0x817D7878, 0x92968889, 0x7990877D, 0x7A7C7973, 0x7A747073, 0x88888786, 0x7D7F8387,
+    0x6D6E7375, 0x87817870, 0x7C828789, 0x7B797677, 0x94847A78, 0x93959A9D, 0xB2A9998E, 0x9BA0AAB1,
+    0x8C898887, 0x92918F8D, 0x7C818689, 0x938D837D, 0xA5B0A594, 0x837F808E, 0x83838485, 0x87838182,
+    0x908B8580, 0x93939392, 0x989D9992, 0x818D9797, 0x6A747E85, 0x60616265, 0x575C5F62, 0x52525354,
+    0x55555453, 0x58565554, 0x6868615A, 0x786E6464, 0x85918F84, 0x787E7E7C, 0x7F7C7A78, 0x83828180,
+    0x7A7E807F, 0x998D7F78, 0x817B818C, 0x87878787, 0x737E8381, 0x70767771, 0x877D7775, 0x727E8B8E,
+    0x6E646266, 0x746E6C70, 0x706D6B6E, 0x87776C6E, 0x919B8E8A, 0x867D8386, 0x777B7B7A, 0x74727073,
+    0x83827F7B, 0x7F818383, 0x797B7D7E, 0x74747577, 0x75767676, 0x74747474, 0x7B7A7776, 0x76777A7B,
+    0x7A7A7978, 0x7A7A7A7A, 0x89878481, 0x85858687, 0x8A888684, 0x8486888A, 0x82828385, 0x83848483,
+    0x777B8083, 0x76757474, 0x75747575, 0x7A7A7876, 0x74757676, 0x75757474, 0x75747474, 0x76767675,
+    0x77777778, 0x76767676, 0x76777878, 0x74747475, 0x7A797776, 0x7A7A7A7A, 0x74787572, 0x706C6A6E,
+    0x867E746E, 0x777C8387, 0x76767677, 0x7C7B7A77, 0x81807F7F, 0x81818181, 0x7F7E8081, 0x81828281,
+    0x81838484, 0x6F73777C, 0x736E6B69, 0x85827D78, 0x82828383, 0x7D7E7F81, 0x7A7D8184, 0x82807B7A,
+    0x93928F8D, 0x86898D92, 0x7F838789, 0x7777797B, 0x686D7274, 0x64636365, 0x7C756D68, 0x787A7E7F,
+    0x6A707578, 0x5C5C6064, 0x7D7A7674, 0x7C7D7F7F, 0x71797D7F, 0x5F5F6168, 0x6A686563, 0x6C6C6C6C,
+    0x68676868, 0x8A82766D, 0x6E73818D, 0x7C7C7A73, 0x6C686C73, 0x747A7C76, 0x6F6F6F6F, 0x60646A6E,
+    0x60616467, 0x746F6862, 0x7D7D7B7A, 0x78787A7B, 0x8B827D7D, 0x92919291, 0x7E828687, 0x8285837F,
+    0x757D878D, 0x78757271, 0x7A7A7978, 0x7174767A, 0x79716E6E, 0x84868681, 0x797F8890, 0x84827E7A,
+    0x747F827F, 0x78756F6D, 0x6E6E7073, 0x6A6C6E6E, 0x6E757068, 0x69615B62, 0x7C7A7571, 0x7374787B,
+    0x6971787A, 0x5C5C5C62, 0x7A797064, 0x878C897F, 0x7D7F8181, 0x7E7E7D7D, 0x86848281, 0x777B8185,
+    0x7B797775, 0x8683807D, 0x898C8B89, 0x7F7F8184, 0x89878686, 0x767D868A, 0x877F7A79, 0x78828D8E,
+    0x83828181, 0x8D898684, 0x7A7D8793, 0x74747679, 0x726F6E6E, 0x74767675, 0x65676D73, 0x65686868,
+    0x7A6F6866, 0x92918D84, 0x8D898582, 0x86888B8D, 0x90929395, 0x86888C8E, 0x6E727C85, 0x70737370,
+    0x83817972, 0x78787A80, 0x7B7F8080, 0x60646C74, 0x78787169, 0x87847E79, 0x7F7D7B7A, 0x81818181,
+    0x7A7C8083, 0x787A7B7B, 0x68696F75, 0x565D6568, 0x80746256, 0x5B657480, 0x59565351, 0x6563615C,
+    0x5E606366, 0x5A5B5D5E, 0x65615D5C, 0x706E6C69, 0x75737170, 0x7E7D7B79, 0x74797F83, 0x72727373,
+    0x746E6A66, 0x6B747C7A, 0x746A6464, 0x78757578, 0x7B828381, 0x6D6C6D73, 0x726E7279, 0x62676F74,
+    0x7D756E68, 0x80818281, 0x7577797A, 0x71717273, 0x74737170, 0x74757574, 0x77737476, 0x7B80817E,
+    0x71717579, 0x696E7374, 0x68686869, 0x716F6D6A, 0x787B7A75, 0x7A7A7976, 0x7474777A, 0x666C7375,
+    0x595D605C, 0x626F7162, 0x595C5855, 0x54515155, 0x595C5B59, 0x52515155, 0x57565554, 0x5C5B5A58,
+    0x6A6B6B6A, 0x60626568, 0x5B575C63, 0x7168625F, 0x7F818181, 0x7374767A, 0x8184817D, 0x70707279,
+    0x69696D71, 0x8882796F, 0x827C7876, 0x6E768185, 0x71696268, 0x70757370, 0x6F6E6D6A, 0x706F6E6F,
+    0x706E6D6C, 0x76757472, 0x71737474, 0x65686A6E, 0x6D746F63, 0x7A706562, 0x808A8781, 0x59585E6E,
+    0x68686868, 0x6E6C6A68, 0x62627E76, 0xB0377E7F, 0xE8EBD6E6, 0x201E19E8, 0x3F661012, 0x59484F5C,
+    0x81639143, 0xBB31151E, 0xD2CAEBD6, 0x6280A2CA, 0x747D6177, 0xE3EBE53A, 0x1035E2DB, 0x58605839,
+    0x744E617C, 0x17101C10, 0xE5EBE2E3, 0x61616EEB, 0x60626566, 0x5A5B5C5D, 0xBE43496E, 0xE7EBDED3,
+    0xEBE5DBE4, 0xE2EBE9D2, 0x68E8E0DF, 0x535B4C69, 0x5C5B5B5B, 0x5C5C5C5C, 0xEB196A46, 0xE0E0EBE2,
+    0x4D301014, 0x555F6659, 0x8D765950, 0x10421086, 0xDFE4EBE5, 0x8563EAE1, 0x595C6265, 0x615E5B58,
+    0x5E5E6265, 0x5E606160, 0x595A5E62, 0x4E53585A, 0x423C5C4F, 0xC3D82844, 0xEBE5CBEB, 0xEBDFE2DF,
+    0xE9E7E0E3, 0x3D52E5EB, 0x4C4A4948, 0x5251504E, 0x56625754, 0xE8E91F56, 0x28EAE5D6, 0x3D572110,
+    0x626E5253, 0x10103336, 0xE2E9D821, 0x6D39DCE9, 0x44424344, 0x6660564B, 0x56595C5D, 0x52525254,
+    0x50505050, 0x51515150, 0xDA354533, 0xCFEAEBDD, 0x1C241FD9, 0x7D381020, 0x56565656, 0x56565656,
+    0xDB391912, 0xEBE7EBE8, 0x4C6891B0, 0x44474644, 0xEBE6E61A, 0x192BD6DB, 0x49614831, 0x3D515B41,
+    0x103C473A, 0xEBBF1E2D, 0xE8E7DCEB, 0x555C5A6F, 0x4A4A4949, 0x5756514E, 0x52525150, 0x4C4E5051,
+    0x25384446, 0xE5EBD5EB, 0x101528D2, 0x62566E5E, 0x11565371, 0xEB101716, 0xDFE8DAEA, 0x39372B4C,
+    0x5856523D, 0xCA21473C, 0xDBE7DCEB, 0x4124102E, 0x3E645B5B, 0x13145431, 0xEBC31029, 0x52D6EBE4,
+    0x645F5A56, 0x65666868, 0x62676562, 0x3E434B57, 0x594C4F62, 0xA6254A7B, 0xE5E7E7D2, 0x351932EB,
+    0x52681610, 0x625C607A, 0x58687246, 0xC2181716, 0xD6D2EBBB, 0xA08FA1CB, 0x8D818275, 0x1E798F8D,
+    0xE9DCE4E8, 0x5A7E69E9, 0x6358524F, 0x686D706D, 0x67628C6D, 0x648E4A75, 0x6B6D7A8A, 0x74706E6D,
+    0x8481786F, 0x74757980, 0x5C60666A, 0x57595B5C, 0xE8206074, 0xEBDDE7EB, 0x5C5C5C5C, 0x5C5C5C5C,
+    0x6E6D6C6C, 0x7171706E, 0x64726E6D, 0x1B52727A, 0xE6E4EBE2, 0x182BC8EB, 0x554C4245, 0x6E5D4A4C,
+    0x21324644, 0xE3D37515, 0x4CE5EBEB, 0x55516056, 0x5D5B5653, 0x595A5B5C, 0x49545D62, 0x2B2E353E,
+    0x877B7574, 0x828A9290, 0x81818181, 0x84838281, 0x7A7C7D7E, 0x77777879, 0x74747576, 0x78777574,
+    0x87888989, 0x81808183, 0x8C87817B, 0x8A8B8C8D, 0x84858787, 0x89878684, 0x878B8D8D, 0x7C7E8184,
+    0x6B717A82, 0x756E6868, 0x817C7774, 0x82838584, 0x82818284, 0x8D8D8A87, 0x6F757D83, 0x6E6E6E6D,
+    0x7F7C7B7A, 0x88878481, 0x8E8B8784, 0x898C8E90, 0x85868788, 0x918E8A87, 0x767A848C, 0x87847F79,
+    0x8F87878A, 0x969B9E99, 0x6D737A7F, 0x68676768, 0x7978746E, 0x74797B7A, 0x6C6B6E6F, 0x7A79746F,
+    0x686E767C, 0x68686666, 0x6D6C6660, 0x7A746D6B, 0x6E7B7F79, 0x817B7068, 0x7A7B8185, 0x7A7B7C7B,
+    0x817D7A7A, 0x7A7F8485, 0x7C787575, 0x757A7E7F, 0x7D7D7F80, 0x797A7D7E, 0x6A6C6F72, 0x7B776F6B,
+    0x7E7A7776, 0x87878783, 0x7B7F8386, 0x7A7A7979, 0x6F747576, 0x6766676A, 0x8F908A7F, 0x71697387,
+    0x85838180, 0x81828485, 0x88898B8D, 0x81848788, 0x747A7A77, 0x79716B6C, 0x99999894, 0x8F969A9A,
+    0x746C6D7D, 0x8F877A74, 0x7C848889, 0x7B767374, 0x93908880, 0x81889193, 0x91878382, 0xA5A6A59C,
+    0x96959493, 0x90929395, 0x7E818890, 0x8F87817E, 0x989F9F9B, 0x8886868D, 0x87888D91, 0x85878887,
+    0x83848687, 0x908D8985, 0x8785878A, 0x7E858B8B, 0x63697176, 0x5C5D5F61, 0x595C5D5E, 0x53545657,
+    0x52535353, 0x52525252, 0x50515353, 0x6B625750, 0x817F756D, 0x7D7A797C, 0x817B7A7F, 0x85818184,
+    0x807D7C7E, 0x89848181, 0x86878681, 0x81888B88, 0x73747A80, 0x8387877C, 0x8E817A7D, 0x8C8F9598,
+    0x827E7D88, 0x7174747A, 0x6B615C62, 0x7E6F686E, 0x8B8D8A83, 0x767F8687, 0x7B777271, 0x66646A75,
+    0x9A8E7A74, 0x8F918F94, 0x75797E83, 0x6F727474, 0x76767474, 0x7B7A7776, 0x74787B7D, 0x7A767372,
+    0x7A797776, 0x7A7A7B7B, 0x88878481, 0x86868687, 0x88878584, 0x84858788, 0x84838383, 0x85858584,
+    0x747A8083, 0x71707071, 0x716F7174, 0x77797975, 0x73737577, 0x79797875, 0x72747678, 0x78767472,
+    0x77777778, 0x7A797878, 0x7E7E7A78, 0x78787A7C, 0x7A787675, 0x7A7A7A7A, 0x787A7674, 0x6B6B6E73,
+    0x867C7471, 0x747C878B, 0x7173777A, 0x7C797471, 0x7F7C7A79, 0x81818181, 0x7A7C7F81, 0x817F7C7A,
+    0x81808080, 0x71767D81, 0x736E6967, 0x81807C78, 0x81828383, 0x82828181, 0x747B8184, 0x80797270,
+    0x93908B88, 0x888C9093, 0x8286898C, 0x72757A7F, 0x686B6E71, 0x60616264, 0x706B6865, 0x7C7A7874,
+    0x5F6E797F, 0x57535054, 0x807B7169, 0x7C7B7C7F, 0x737A7B81, 0x5F5D585F, 0x68676360, 0x6C6B6969,
+    0x81756F70, 0x83818386, 0x6A6E7A84, 0x7D7B776F, 0x6C686D72, 0x69707573, 0x68746D61, 0x64564B54,
+    0x60616262, 0x75706862, 0x7C7A7878, 0x74787B7E, 0x87838589, 0x878D908D, 0x81818283, 0x87868482,
+    0x72798185, 0x7D78726F, 0x8787847D, 0x77808787, 0x79727072, 0x80838581, 0x777D8386, 0x87807774,
+    0x7C818587, 0x7F7B7979, 0x68686F79, 0x706E6D6B, 0x8A937E64, 0x8E776671, 0x80838586, 0x7475787C,
+    0x6970767A, 0x5C5D5F63, 0x747A7263, 0x787F7D74, 0x7F81807A, 0x81848480, 0x87848281, 0x7E818587,
+    0x80848381, 0x85797075, 0x8C8D8C8C, 0x87888A8B, 0x87878787, 0x87878787, 0x8D808085, 0x74899D9E,
+    0x7E776C62, 0x85828181, 0x818A8C8A, 0x6E6E7076, 0x73716E6C, 0x7A787574, 0x68696F77, 0x62626468,
+    0x746C6662, 0x9591887F, 0x8E8C867F, 0x8A88888B, 0x93939494, 0x85878C8F, 0x74757E89, 0x7C7A7978,
+    0x8A827B7A, 0x73757E89, 0x7D7F8080, 0x676B7178, 0x6E747471, 0x7676736D, 0x827C7875, 0x898A8A87
+};
+
+static gctUINT32 ppuMem4[] =
+{
+    0x7E83898D, 0x807E7B7B, 0x84817F7F, 0x5C687A83, 0x7E766C66, 0x616A777F, 0x5C5B5856, 0x625F5C5C,
+    0x52515A62, 0x52585C58, 0x60585554, 0x70716F69, 0x71696A6E, 0x787F827D, 0x72747D87, 0x6D6D6E71,
+    0x877F736A, 0x6A737F87, 0x6B686868, 0x7A78746E, 0x767A7B7C, 0x67696E72, 0x716E6E6E, 0x686E7274,
+    0x7A75706C, 0x7D7D7D7C, 0x7477797A, 0x6E6E6E70, 0x72716F6E, 0x74747473, 0x75747474, 0x75757575,
+    0x72747475, 0x70707071, 0x6E6A6868, 0x76767572, 0x78757678, 0x7D7F7F7C, 0x81807D7A, 0x686E787F,
+    0x625E6062, 0x67696B68, 0x62625C55, 0x5352555C, 0x5C5C5B59, 0x5052565A, 0x56504F50, 0x68625E5C,
+    0x7B7E7468, 0x6260626E, 0x59565B62, 0x726B645E, 0x7D818283, 0x76757679, 0x72747472, 0x726F6E6E,
+    0x73727170, 0x87817A75, 0x7C74757A, 0x747F8786, 0x706A686E, 0x747B7872, 0x78747475, 0x6F747A7B,
+    0x706D6C6C, 0x72737473, 0x74797874, 0x66626269, 0x6A6A6B6B, 0x6D6C6A6A, 0x807B7168, 0x5C636F7A,
+    0x62636566, 0x65646362, 0x61516277, 0xE0226E5C, 0xE5EAE6E2, 0x48627ACA, 0x4C514837, 0x4E4E4A46,
+    0x78575350, 0xE610687C, 0xDFE2DBE0, 0x504E58EB, 0x1026109F, 0xEBE6BD38, 0x7483AEEB, 0x5E5A5561,
+    0x716D645C, 0x1834566C, 0xE8EBE2E6, 0x181531D3, 0x5B5D6162, 0x605D5C5A, 0xD1154469, 0xEBE8E8EB,
+    0xCDEBDCEB, 0xEBDDEBDC, 0x5DE6E8EB, 0x47594A56, 0x5C5C5550, 0x5D71564A, 0xEB10616A, 0xE3EBD5EB,
+    0x3E524456, 0x64645C56, 0x8C716370, 0x2E5C4E55, 0xE7E8E9EB, 0x6788B7D9, 0x50535B60, 0x605C5651,
+    0x5C5D5E5F, 0x52545659, 0x57565554, 0x4B4E5256, 0x4A705252, 0xEBD8173F, 0xCDDFEBD4, 0xE5EBDCEB,
+    0xE8EBE2EB, 0x4A57E5EB, 0x4E4C4B4B, 0x5251504F, 0x3B105F60, 0xEBC93914, 0x5DDFCBEB, 0x4B58522C,
+    0x6259504A, 0x314A6369, 0xEBCECA29, 0x1043E4D6, 0x4F483E5C, 0x685E5D3A, 0x565B5C5C, 0x4E4D4D50,
+    0x50504E4E, 0x4D4E5050, 0xDC193F49, 0xEBE3EAE2, 0x6F7457C9, 0x50465B4B, 0x5860686E, 0x53535254,
+    0xE715402F, 0xE0EBEBE9, 0x385662DF, 0x29403755, 0xDDEBEB16, 0x5F3FE7EB, 0x553D4245, 0x2A4D4853,
+    0x446F233E, 0xD9C93E3B, 0xC5EBE5E8, 0x434F4C71, 0x4547494A, 0x5D564E47, 0x504F5256, 0x4E515554,
+    0x56105012, 0xC4EBE8DB, 0x314B87BB, 0x565A523D, 0x524A5648, 0x8725235A, 0xCBEBE6EB, 0x23331A53,
+    0x5B51394C, 0xE8103F5C, 0xD9E2EBE5, 0x504C293C, 0x4A544B40, 0x513E3D40, 0xE9E11948, 0x5CE9DEEB,
+    0x615D5957, 0x67676664, 0x4D84534D, 0x38584348, 0x5E3E595A, 0xDE16627A, 0xE1EBD4E9, 0x52607CD6,
+    0x5D63686C, 0x5A585758, 0x6D5F6552, 0xE619767C, 0xEBEBE6E3, 0x7E626FDE, 0x8E938083, 0x31315410,
+    0xE8EAEBE8, 0x84875FD3, 0x686C7174, 0x6F6D6967, 0x5C5A5E5E, 0x60636A68, 0x76666462, 0x74876868,
+    0x857A627F, 0x836B5C93, 0x695F6462, 0x124D515B, 0xDB28121D, 0xE4E3E9E6, 0x4A4A4A4A, 0x4A4A4A4A,
+    0x8B626B68, 0x5458807A, 0x7878736F, 0x145D526A, 0xD8EBEAB7, 0x648DCADE, 0x4A544A61, 0x5D56474F,
+    0x3B476A43, 0xE8EB123C, 0x4DE2EBE6, 0x55536059, 0x55555454, 0x59585756, 0x45555C5C, 0x3B322D34,
+    0x8078726F, 0x81858786, 0x7F808080, 0x8181807F, 0x7C7D7E7E, 0x7C7C7C7C, 0x7A7A7A7B, 0x7D7C7A7A,
+    0x83878787, 0x7A7A7B7F, 0x8B867E79, 0x8C8C8D8D, 0x84868789, 0x87868484, 0x86878989, 0x7A7B7F82,
+    0x696D767F, 0x756E6968, 0x7A777574, 0x80807E7C, 0x817F8081, 0x8B8A8884, 0x7A7E8286, 0x71737578,
+    0x807D7B7A, 0x88878582, 0x8F8D8887, 0x888B8D8F, 0x87878889, 0x8E8C8987, 0x74777E85, 0x89878179,
+    0x938D8B8B, 0x9A9B9B99, 0x787E858A, 0x74747474, 0x6F737472, 0x6D6F706E, 0x67656668, 0x74736F6A,
+    0x686A6E72, 0x65666767, 0x74736D66, 0x817A7474, 0x707A7E7C, 0x7B746C69, 0x73737475, 0x74747474,
+    0x7B787676, 0x74797E7F, 0x75727171, 0x73757878, 0x76747474, 0x78797A79, 0x6F747574, 0x7C756E6C,
+    0x7B787675, 0x8181817F, 0x7A7C7E80, 0x79787879, 0x73777A7A, 0x69696A6E, 0x93948D80, 0x776E778B,
+    0x85878582, 0x86838182, 0x85858687, 0x80828485, 0x70777A7A, 0x756F696A, 0xA3A29F9B, 0x989EA4A4,
+    0x77717382, 0x90897D77, 0x7E858B8D, 0x817E7A79, 0x94948F88, 0x747E8890, 0x7A737274, 0x9C999387,
+    0x90929496, 0x95939290, 0x81848C93, 0x8B857F7F, 0x8D91918E, 0x89858285, 0x8B8D9093, 0x8B8C8D8C,
+    0x81828384, 0x86858382, 0x85818184, 0x79808788, 0x60646B6F, 0x5A5B5C5D, 0x585A5B5B, 0x55555657,
+    0x51525253, 0x50505051, 0x484C5051, 0x5B544B47, 0x78756A5F, 0x8D827876, 0x817C8188, 0x787A8083,
+    0x7B787A80, 0x8D878280, 0x8E93938F, 0x82878B8C, 0x77777D81, 0x8A8E8C81, 0x978A8688, 0x96999F9F,
+    0x9593939D, 0x7A7C7E88, 0x6D646269, 0x7D6F686D, 0x858A8781, 0x6F757B80, 0x76736D6B, 0x61606671,
+    0x98887571, 0x92949395, 0x75797E81, 0x70727474, 0x77777675, 0x817E7A78, 0x7A7E8182, 0x79777576,
+    0x807E7D7C, 0x80818181, 0x85858280, 0x81818284, 0x85848382, 0x82838485, 0x83828181, 0x87868584,
+    0x777A7F81, 0x76757474, 0x74737374, 0x76777775, 0x74747576, 0x77787876, 0x71727474, 0x74747271,
+    0x74747474, 0x76767574, 0x7F7F7B79, 0x78797A7D, 0x76757474, 0x77777777, 0x7A7B7B7A, 0x7B7A7A7A,
+    0x79706E71, 0x78808683, 0x6F727579, 0x7975726F, 0x7C7A7877, 0x80807F7E, 0x76787A7C, 0x7C7A7876,
+    0x83817F7F, 0x7D818485, 0x7A777574, 0x7F7E7D7B, 0x81828383, 0x81818181, 0x777B8082, 0x837F7976,
+    0x8F8E8D8C, 0x8B8C8D8F, 0x82868A8D, 0x73767A7F, 0x65696E71, 0x5F5F6062, 0x6863615F, 0x73716E6B,
+    0x69717474, 0x5C5A5A60, 0x7E7A716A, 0x7B7A7B7D, 0x7277767C, 0x63625C62, 0x6E6A6662, 0x7372706F,
+    0x887F7979, 0x8686898D, 0x6467737E, 0x7979746B, 0x67666C74, 0x666C706E, 0x75796857, 0x5B545462,
+    0x5F5C5C5D, 0x74716B64, 0x7C7A7877, 0x777A7D7E, 0x807A7A7E, 0x868A8D87, 0x83818386, 0x8B8B8986,
+    0x76777C81, 0x7C7D7C79, 0x7A7F817F, 0x777B7C7A, 0x7A747172, 0x7B808481, 0x71747577, 0x7C787471,
+    0x7A7B7D7F, 0x7F7E7B7A, 0x696B7178, 0x69666568, 0x898B7C6C, 0x93867A7E, 0x84888B8C, 0x76787B80,
+    0x6E737679, 0x61626568, 0x73796F5E, 0x787B7770, 0x7E7F7D79, 0x85878680, 0x8C888789, 0x898D908F,
+    0x8B8F8D8C, 0x827A7780, 0x8F8E8E8E, 0x9090908F, 0x84848687, 0x84858585, 0x81797E87, 0x7585928F,
+    0x7F786C63, 0x7F7F7F81, 0x71747675, 0x71737371, 0x7474716E, 0x7B797775, 0x6868717A, 0x66666868,
+    0x69666362, 0x7E7B756F, 0x8C8B8580, 0x86858689, 0x8B898887, 0x8C8C8C8C, 0x7A7A818A, 0x7F7E7E7D,
+    0x91877D7A, 0x6E758391, 0x78797877, 0x6E707476, 0x6E747673, 0x696C6C6B, 0x8178706C, 0x8D8D8D88,
+    0x7D82878B, 0x7F7C7A7A, 0x918D8887, 0x747D8990, 0x817F7A78, 0x686F7980, 0x65626263, 0x6C6E6E6A,
+    0x5B5B6065, 0x575C5E5D, 0x635C5653, 0x7474716B, 0x76757473, 0x88837C78, 0x6C6E747E, 0x6A696B6D,
+    0x817B746E, 0x6B717A80, 0x6F6F6F70, 0x74737170, 0x74747575, 0x6F707173, 0x79726F70, 0x71798080,
+    0x76746F6D, 0x7A7A7A79, 0x72747778, 0x6D6C6D6E, 0x6E6D6C6B, 0x6E6E6E6E, 0x6E6E6E6E, 0x6F6F6E6E,
+    0x73747475, 0x6E6F7072, 0x6D6A6A6A, 0x73747370, 0x7A757271, 0x8383827F, 0x77787A7D, 0x686D7275,
+    0x5F5E6164, 0x5B5E6262, 0x66635D57, 0x5C5C5E62, 0x5B595858, 0x5155595C, 0x56504E50, 0x67625D5B,
+    0x747A746D, 0x68626168, 0x5B575B62, 0x746E6862, 0x75797C7E, 0x7F7A7674, 0x75797A7C, 0x74737272,
+    0x827E7874, 0x82828383, 0x7E78787A, 0x7A818785, 0x73727075, 0x767A746F, 0x7A787675, 0x70747A7C,
+    0x73706E6E, 0x70727475, 0x7074706B, 0x6C686669, 0x696A6C6E, 0x6467696A, 0x74706C69, 0x62666E73,
+    0x5F606162, 0x6261605F, 0x695D6671, 0xC7216E61, 0xEAEBE6DF, 0x35567ACD, 0x50565147, 0x4D51514D,
+    0x7367574A, 0xE912505B, 0xE8EBE8EB, 0x755850EB, 0xE0D12B6C, 0xE4EBEBD6, 0x5637252C, 0x52535860,
+    0x68676462, 0x4C5A666A, 0xD6A81F1C, 0xEAE2C5EB, 0x595B5E61, 0x605D5B58, 0xD7356073, 0xE8E5EBEB,
+    0x2BCAEBE1, 0xCEEBCF1F, 0x5CE5E8EB, 0x45584854, 0x5759534F, 0x4A624D44, 0xE52D6867, 0xE0DCDCEB,
+    0x5559505C, 0x775D4F56, 0x6351767D, 0x235E5679, 0x23201310, 0x6E553726, 0x484D5256, 0x55504A47,
+    0x57595A5A, 0x51525456, 0x54545352, 0x4A4C5052, 0x556B4A47, 0xE6DC3356, 0xEBEBE5EA, 0x1922EBCA,
+    0xE8EBE2EB, 0x4A57E5EB, 0x504F4E4D, 0x52525150, 0xD03C5F54, 0xE1EBCAD2, 0x443116E0, 0x3946403B,
+    0x4D4C4E4E, 0x5D625F56, 0xDF251610, 0xE1D5EBE5, 0x4B505CB5, 0x4F4D4B41, 0x53555554, 0x504F4E50,
+    0x504F4E4D, 0x4E4F5050, 0xEB254868, 0xEAD1DFEB, 0x5A444DEB, 0x472F4B4E, 0x54585958, 0x514F4D4F,
+    0xEB1E5555, 0xE0E3D0DE, 0x444F5CEB, 0x2E513B5D, 0xC9D0E627, 0x5442E3E7, 0x5151543D, 0x4A5E4442,
+    0x2B50453D, 0x1E16102A, 0x351E1018, 0x48565444, 0x44454849, 0x4E4A4543, 0x51505357, 0x50545656,
+    0xE0E8EA18, 0x2EC8E8EB, 0x69614A36, 0x53525662, 0x4D565B54, 0x2B3D4E50, 0xEBE4BC42, 0x5EC3C1D7,
+    0x605D4338, 0xEB153D5D, 0xE8E8EBE2, 0x4B4C2F38, 0x5650444D, 0x525B5750, 0xE0E83052, 0x55E4EBE5,
+    0x5A565250, 0x5E5E5E5C, 0x4B6B415C, 0x5852434A, 0x52395056, 0xEB326068, 0xEBEADCE8, 0x683A6CEB,
+    0x585A5C5C, 0x56565657, 0x6A5C524C, 0xCF216E62, 0xEBEBE9EA, 0x816E7EE8, 0x7C69637A, 0xEBD7C72D,
+    0xEBE3E0E9, 0x7C8768E9, 0x6E747A80, 0x76736E6C, 0x314F7280, 0x937B5B3A, 0x7C616168, 0x54736673,
+    0x8C766E6B, 0x545D7887, 0x665D625F, 0x10484A55, 0xE9C6EBEB, 0xD6EBE7D5, 0x69696969, 0x69696969,
+    0x6B6E686A, 0x725A4D5D, 0x67656568, 0x2C695661, 0x19181110, 0x7F644125, 0x63626367, 0x50564C59,
+    0x5348624B, 0xEBDD1348, 0x6DDED8E2, 0x4E444F64, 0x4E505152, 0x4A4A4B4C, 0x434E514F, 0x38312E35,
+    0x7D7A7571, 0x8482807F, 0x7C7E7F80, 0x7B7B7B7C, 0x807F7E7D, 0x83828181, 0x81818182, 0x81818181,
+    0x7F838585, 0x7474767A, 0x89837B76, 0x8C8C8C8C, 0x8386888A, 0x81818181, 0x81828282, 0x75787B7F,
+    0x66676E78, 0x76716C68, 0x74747475, 0x7F7C7A77, 0x7E7C7C7D, 0x88878682, 0x8D8D8D8D, 0x8083888B,
+    0x817D7A7A, 0x87878683, 0x8F8D8A87, 0x878A8D8F, 0x88898A8B, 0x8A898988, 0x79797E83, 0x8E8C877F,
+    0x93918E8C, 0x98979594, 0x7D82898E, 0x7D7D7C7B, 0x69717778, 0x65676765, 0x62626264, 0x69696865,
+    0x6F6D6B6A, 0x686B6F70, 0x7D7A736B, 0x85807A7A, 0x73797C80, 0x746D686C, 0x6D6C6A69, 0x706E6E6D,
+    0x7A777474, 0x71767C7D, 0x6D6C6D6E, 0x6F70706E, 0x706C6A69, 0x79797874, 0x767B7A76, 0x7B746E6F,
+    0x76747474, 0x7A7A7A7A, 0x76767676, 0x76767676, 0x767D8182, 0x6667696E, 0x91938B7B, 0x7A707687,
+    0x84878582, 0x827F7D7F, 0x7E7C7B7C, 0x7E808180, 0x6D73797C, 0x736E6968, 0xA7A6A39F, 0x9BA2A8A9,
+    0x7C767987, 0x938E827C, 0x81878D93, 0x87868381, 0x9093928D, 0x7079838B, 0x746E6D6E, 0x928F897F,
+    0x888D9398, 0x9D978F89, 0x878C939A, 0x88838184, 0x80818180, 0x8B86817F, 0x8A8C8E91, 0x8B8B8C8B,
+    0x81818181, 0x7D7E7F81, 0x7E7A7A7B, 0x6F767E81, 0x5B5E6367, 0x58595959, 0x56575758, 0x55555656,
+    0x50515152, 0x4D4E4F50, 0x42474B4C, 0x4E48413E, 0x6D6A5F54, 0x9787756D, 0x7E7A818C, 0x84878986,
+    0x7A75777C, 0x9C948A82, 0x969E9F9E, 0x81858A8F, 0x79787C80, 0x91938F83, 0x9A908C8D, 0x999DA1A2,
+    0x9B999399, 0x8483828D, 0x6E696A71, 0x7D6F686D, 0x80878781, 0x696C6F76, 0x74706A66, 0x5F60666F,
+    0x8C7C6965, 0x8588878A, 0x76797D80, 0x70727474, 0x75757574, 0x86817B77, 0x81848585, 0x7E7C7C7E,
+    0x8281807F, 0x82828382, 0x83838180, 0x7F7F7F81, 0x81818181, 0x81818181, 0x83818181, 0x87878584,
+    0x7A7C7E80, 0x7D7C7A7A, 0x76777877, 0x75747474, 0x77757575, 0x74767879, 0x6F6F6F6F, 0x6F6F6F6F,
+    0x72717070, 0x74747473, 0x80807C7A, 0x78797A7D, 0x75757575, 0x78777675, 0x837F7B7A, 0x87888987,
+    0x6962676E, 0x7B818178, 0x6C6E7274, 0x74726E6C, 0x7A777574, 0x7E7D7D7B, 0x7476797A, 0x7A797674,
+    0x83807E7E, 0x85878787, 0x81818282, 0x7C7D7F80, 0x81828282, 0x81818181, 0x7C7B7D7F, 0x89878480,
+    0x8C8D8E8F, 0x8D8C8C8B, 0x8185898D, 0x74767A7E, 0x61676D70, 0x5E5D5C5D, 0x625E5C5B, 0x6E6C6865,
+    0x7577726B, 0x6463666E, 0x7D7A746E, 0x79797A7C, 0x7576747A, 0x6A696468, 0x78746E6A, 0x7B7A7A7A,
+    0x8C837E7C, 0x84868B8E, 0x5F616E7A, 0x78787468, 0x63646E76, 0x64696C68, 0x7C7A6855, 0x5A585E6E,
+    0x645D5C5C, 0x7675736C, 0x7C7A7877, 0x7A7D7F7F, 0x7B747477, 0x83878A85, 0x807E8287, 0x8F8F8D87,
+    0x7F7E8388, 0x81858784, 0x68727A7E, 0x73716B66, 0x7C747170, 0x767C8382, 0x676A6F73, 0x6B6A6867,
+    0x76727273, 0x8181817C, 0x7176797A, 0x625E5F68, 0x7D77706C, 0x8D8A8681, 0x84888B8D, 0x77797C80,
+    0x6E707273, 0x6466686B, 0x747A705F, 0x7778746E, 0x79787774, 0x8686827C, 0x8C88898C, 0x92949592,
+    0x8E949697, 0x817B7A83, 0x8A888787, 0x8F8E8D8C, 0x80818487, 0x7F818181, 0x72727F8D, 0x7A81837C,
+    0x8480766F, 0x787A7D82, 0x69696B6B, 0x7276766F, 0x7A787574, 0x807E7B7A, 0x6666707C, 0x68696B6A,
+    0x63656869, 0x6C696764, 0x89898681, 0x81818186, 0x8481807F, 0x8E8D8A87, 0x7F7B8188, 0x80808182,
+    0x93887E7A, 0x67748794, 0x72716F6E, 0x73747473, 0x6F757674, 0x6164676A, 0x7C716761, 0x8F8E8C86,
+    0x7B818689, 0x7D7B7A79, 0x88878481, 0x8B8A8988, 0x8386888B, 0x767A7E81, 0x6E686C71, 0x767C7F79,
+    0x666B6E6F, 0x5E5D5F62, 0x6F68615C, 0x7D7B7874, 0x80827D76, 0x8F857B7A, 0x6A6A6F77, 0x6A69696B,
+    0x7975716E, 0x7174777A, 0x7477797A, 0x6A6B6E71, 0x6F6D6C6C, 0x7A787572, 0x8177767A, 0x7A858E8D,
+    0x72717070, 0x78777574, 0x6F727577, 0x6A6A6B6D, 0x68696A6B, 0x62636466, 0x63636262, 0x64646463,
+    0x73747373, 0x6E6E7072, 0x6C6B6C6D, 0x6E6E6F6E, 0x78716A65, 0x8B88847F, 0x6C727C85, 0x66686A6A,
+    0x5D5E6164, 0x55585C5E, 0x67625C59, 0x65666868, 0x57555658, 0x54585C5C, 0x56504E50, 0x645F5C59,
+    0x6C747470, 0x6E665E61, 0x5C565C64, 0x706E6A65, 0x6D6F7476, 0x8881766E, 0x8D8D8F90, 0x8184888B,
+    0x8B867E77, 0x7D81868A, 0x7F7B7A7A, 0x7F818281, 0x7A7F7D81, 0x76756D6D, 0x82817C79, 0x74767B80
+};
+
+static gctUINT32 ppuMem5[] =
+{
+    0x7573706F, 0x6C707476, 0x6E6E6A64, 0x706B6869, 0x67666768, 0x61646868, 0x6868696A, 0x65666868,
+    0x5D5E5F5F, 0x5F5F5E5D, 0x5C65635C, 0xBF245040, 0xD5DEE0E1, 0x415C7BBA, 0x54575652, 0x4E565A56,
+    0x5A47464E, 0xE3246557, 0xE4E6E9EA, 0x715A58E7, 0xEBE71F6A, 0xEBE9DFDE, 0x625D5954, 0x5C535662,
+    0x5D626869, 0x6264625E, 0xEBDE254E, 0xD6E8D9E3, 0x56595C5F, 0x5D5C5856, 0xAB355D5A, 0xDED5D3C6,
+    0x46BBEBDA, 0xD4EBE019, 0x5AE5E8EA, 0x44574752, 0x5155514F, 0x3150433D, 0xB7191D10, 0xE8E1EBEA,
+    0x74655437, 0x5F575C5D, 0x694F6365, 0x43627A7C, 0x504D5054, 0x61626059, 0x4C505456, 0x56514B49,
+    0x54555656, 0x51515253, 0x50515151, 0x4A4C4D4F, 0x435C5665, 0xC0B72E45, 0xEBE4E7EB, 0x1F46EBD9,
+    0xE8EBE2EB, 0x4A57E5EB, 0x51515050, 0x53525252, 0xD0104F5F, 0xEBEBEBEB, 0x25565FBB, 0x524A6E59,
+    0x4A4C4B49, 0x625E564D, 0xDD102568, 0xEBE5E1D2, 0x45445EEB, 0x464C454B, 0x52535352, 0x54525050,
+    0x504F4D4D, 0x50505050, 0xC526445B, 0xEBD6D6D6, 0x5B594FB7, 0x3D364A44, 0x51514A44, 0x4E4B4A4D,
+    0xE7206347, 0xEAE8D9E5, 0x3E3D41E8, 0x25421036, 0xEBE9EA1D, 0x6C4CCAE0, 0x5F4E5344, 0x505B4D5C,
+    0x6E705548, 0x38434762, 0x45414848, 0x4A424A51, 0x44464747, 0x4A484444, 0x52505458, 0x50545756,
+    0xD9EBE910, 0x47E6E8DC, 0x3A273956, 0x4D687863, 0x4A46474B, 0x34495652, 0xEBE7E317, 0x43E5EBEB,
+    0x68605944, 0xD0125D82, 0xEBE0E2E9, 0x3C5C5B4C, 0x3833444C, 0x3842504D, 0xEBE81024, 0x61C9DAE5,
+    0x5758595B, 0x5E5C5A58, 0x122A104B, 0x45251010, 0x4D455D6A, 0xB5305453, 0xE4EBE1EB, 0x484565C2,
+    0x56514E4D, 0x565A5C5B, 0x62504E63, 0xDF45825C, 0xDEDCE8EB, 0x807179DD, 0x5E546893, 0xEBE6D121,
+    0xEBE8E9EB, 0x988F6DDD, 0x6F767F84, 0x77746E6D, 0x55576081, 0x626D5646, 0x805C6172, 0x2C5D667B,
+    0x29102012, 0x64676E2E, 0x62595E5A, 0x10444550, 0xEBD2E0E2, 0xD6E2D0EB, 0x57575757, 0x57575757,
+    0x5A746F61, 0x7E70554F, 0x5C56585D, 0x4977615D, 0x68594F5B, 0x6374726A, 0x615E665C, 0x4D594B51,
+    0x5554672B, 0xEBDA317A, 0x4EDFEBEB, 0x4459553E, 0x44484B4D, 0x3A3B3D40, 0x3F45433E, 0x38323036,
+    0x7777726D, 0x827B7574, 0x7A7D8081, 0x75767779, 0x817F7D7B, 0x87878583, 0x85868787, 0x82828384,
+    0x7D818282, 0x73737478, 0x88827B75, 0x88898A8A, 0x81848788, 0x7A7B7C7E, 0x7C7C7C7B, 0x7274777A,
+    0x6462676E, 0x79746F6A, 0x79797A7A, 0x817F7C7A, 0x7F7D7D7E, 0x88888783, 0x93918F8E, 0x8C8F9394,
+    0x817E7B7A, 0x87878684, 0x8D8C8887, 0x888A8D8E, 0x8B8C8C8C, 0x8787888A, 0x7F7D8184, 0x92908C85,
+    0x8D8D8D8E, 0x8D8D8E8D, 0x7A7D848A, 0x80807D7A, 0x6E777B7B, 0x6468696A, 0x62626466, 0x61626362,
+    0x77726C68, 0x6E72787A, 0x817F766E, 0x817D7A7D, 0x74757980, 0x6F68666E, 0x66676563, 0x6C686564,
+    0x847E7A77, 0x767D8487, 0x686B6E71, 0x6E6C6A68, 0x706C6969, 0x797A7975, 0x797B7A77, 0x7A767374,
+    0x716F6E6F, 0x75767674, 0x71706F6F, 0x78767473, 0x747B7F81, 0x6566686E, 0x82878171, 0x766A6D7A,
+    0x8283817F, 0x7374797E, 0x76727070, 0x7E7E7D7A, 0x6B70777C, 0x73706D6A, 0xA2A19D99, 0x969DA3A4,
+    0x7F7A7A86, 0x98948780, 0x86878D92, 0x87898A88, 0x878A8986, 0x7F848787, 0x938D8987, 0x999B9B98,
+    0x82889198, 0xA2998D84, 0x898D939A, 0x83808085, 0x827F7E7D, 0x918E8A86, 0x81838486, 0x7E7F8081,
+    0x82817E7C, 0x7A7C8081, 0x74747477, 0x656B7274, 0x57595D60, 0x57575757, 0x54555656, 0x52525354,
+    0x4E505050, 0x4A4A4B4D, 0x41454848, 0x4E48413F, 0x64625B54, 0x8D806F67, 0x7C798087, 0x93928F87,
+    0x83818081, 0xA2978C87, 0x93999FA3, 0x7C82898E, 0x7876797A, 0x92938F82, 0x9C938D8C, 0x969BA2A3,
+    0x97938B8E, 0x807D7B87, 0x6F6D6F75, 0x7E726B6E, 0x7C858682, 0x6564676F, 0x736F6761, 0x6062686F,
+    0x8A7D6860, 0x797B7B83, 0x76797B7E, 0x71727374, 0x73737374, 0x87817A74, 0x87878583, 0x86858586,
+    0x86858584, 0x87878787, 0x85868584, 0x80808182, 0x80818181, 0x81818180, 0x83828282, 0x85858484,
+    0x7E7D7E7E, 0x8382817F, 0x767C7E7F, 0x74716F71, 0x7A777574, 0x7074797A, 0x6E6E6D6B, 0x6B6D6E6E,
+    0x74737271, 0x77777675, 0x7F7F7C7A, 0x7576797C, 0x73747475, 0x76757474, 0x857E7976, 0x747A8387,
+    0x615D626A, 0x7A7B776D, 0x68696C6E, 0x726F6B68, 0x77747372, 0x7C7B7A79, 0x73747678, 0x78767473,
+    0x807E7D7C, 0x84848381, 0x84868787, 0x7C7D8081, 0x81818181, 0x7E7F8081, 0x807B7A7B, 0x8D8D8C87,
+    0x8A8C8D8E, 0x8B8B8989, 0x7F82878A, 0x7274797B, 0x5D646B6F, 0x5D5C5A5A, 0x65625F5E, 0x74716E68,
+    0x7C7C756D, 0x6E6C6E74, 0x7B7A7774, 0x74757679, 0x7B77737A, 0x73716E72, 0x81807B78, 0x7E7F8081,
+    0x8B847E7B, 0x83878C8E, 0x60616E7B, 0x797A756A, 0x62636E79, 0x686B6C67, 0x76766C60, 0x6865656D,
+    0x70686565, 0x7C7F807A, 0x7D7A7A7A, 0x7B7D7F7F, 0x7C767578, 0x81878985, 0x76757D85, 0x8E8D8980,
+    0x85878D92, 0x85878786, 0x5F6A767D, 0x6E685F5B, 0x7C746E6D, 0x737A8283, 0x5F636B72, 0x65656360,
+    0x746B6767, 0x8386857F, 0x81868481, 0x635F6371, 0x70686769, 0x8083847C, 0x7C7F8182, 0x7575777A,
+    0x72727170, 0x6B6D6F71, 0x767B766A, 0x74787673, 0x706F6E6E, 0x807E7A74, 0x85838383, 0x8D8D8B87,
+    0x81878D93, 0x7A747279, 0x82828181, 0x7C7D8081, 0x7C7C8185, 0x7D7F817F, 0x686F8292, 0x7F7E786E,
+    0x87888581, 0x72757A82, 0x74787773, 0x70767975, 0x7E7B7976, 0x87858180, 0x6B687380, 0x6B6E7271,
+    0x68676768, 0x7E7A746D, 0x87888784, 0x7D7D7F83, 0x7A7A7B7B, 0x83817F7C, 0x807B7D83, 0x7C7E8183,
+    0x8B817B7A, 0x6371838D, 0x6E6D6C6C, 0x7271706E, 0x6E737372, 0x62636669, 0x756C625D, 0x8D89847D,
+    0x7B808487, 0x7C7A7979, 0x75797A7A, 0x93887B74, 0x81858D92, 0x8482817F, 0x7A75787C, 0x81878984,
+    0x6F797D7D, 0x63605E63, 0x817C746E, 0x8A878583, 0x8785807B, 0x86858687, 0x7271757B, 0x706F7072,
+    0x75726F6D, 0x7A7A7978, 0x767A7C7D, 0x62656B71, 0x69666463, 0x807B756F, 0x847A7D84, 0x7E8A9491,
+    0x70717475, 0x77767472, 0x6D707477, 0x68696A6B, 0x63686C6E, 0x56575A5E, 0x59585858, 0x5B5B5A5A,
+    0x72706E6D, 0x6E6F7172, 0x6C6C6E6F, 0x696B6D6D, 0x716B645F, 0x8A847C76, 0x666F7F8B, 0x5F626263,
+    0x605E5F61, 0x5C5E6161, 0x645E5B59, 0x67696B69, 0x5251575D, 0x55595B58, 0x55504F50, 0x625D5A58,
+    0x676F7270, 0x71675D5D, 0x5B565C66, 0x69696863, 0x686A6E70, 0x8B82756C, 0xA09E9B9A, 0x8A929BA0,
+    0x81817D7A, 0x7C7C7D80, 0x7E7F7C7A, 0x82807C7C, 0x828C8A8B, 0x716E676D, 0x85847D76, 0x74757A80,
+    0x76736F6E, 0x6A6E7477, 0x6E706C67, 0x6B676468, 0x65646362, 0x68676665, 0x67696A69, 0x64626263,
+    0x62626262, 0x63636262, 0x644F5468, 0x2A10827B, 0x2D211F20, 0x5350443E, 0x5A58544F, 0x50585E5C,
+    0x6B615447, 0xEA104450, 0xEBE9EBE1, 0x575F79EB, 0xE5D9106C, 0xE2EBE5E4, 0x5063746E, 0x66534D4F,
+    0x5B626666, 0x56585756, 0xEBEB1A69, 0xE3EBEBD8, 0x54585D61, 0x59565453, 0x30165A5A, 0x10101B21,
+    0x492D1F1C, 0xE2E0DB26, 0x59E6E9EA, 0x43584850, 0x4E51504E, 0x1C443F3B, 0xEBD9E9E8, 0x1531C7E7,
+    0x6758683B, 0x4C5E694B, 0x62595C64, 0x626C4C45, 0x56494A50, 0x46576865, 0x4F525659, 0x5755504E,
+    0x52535354, 0x52525252, 0x50505151, 0x4E4E4E4F, 0x5C5C3F39, 0x10301252, 0x12101E10, 0x15392A30,
+    0xE8EBE2EB, 0x4A57E5EB, 0x53535353, 0x53535353, 0xE010544E, 0xEAE3EBEA, 0x5A533CEB, 0x3E464447,
+    0x4E4F4B47, 0x4D4C4B4C, 0xD6184E4F, 0xE8E5E6DC, 0x47304AE4, 0x4D524C4A, 0x50515252, 0x51505050,
+    0x4F4E4D4D, 0x50505050, 0x35114B4F, 0x1019251F, 0x637F4C48, 0x434E513C, 0x544F463F, 0x4D4E5053,
+    0xDD256E3D, 0xDEEBEBEB, 0x584F47EA, 0xE6D02543, 0xE2EBEBB9, 0x323C3126, 0x4C284458, 0x30333C5F,
+    0x4949243C, 0x3A573E4A, 0x464F6056, 0x58373D4F, 0x49484645, 0x5955504B, 0x51515559, 0x4C505554,
+    0xDEE0E842, 0x51E8E6E7, 0x5A514842, 0x4B515A5D, 0x3C34494F, 0x623E4453, 0xD3D9EB1C, 0x3EDFD1DC,
+    0x50555F38, 0xEB2F6071, 0xE9E3DAE6, 0x31433F2D, 0x59585647, 0x3A3D4253, 0xEAE71666, 0x87E7E5E8,
+    0x5A5F666A, 0x615E5A58, 0xEBD1335E, 0xB2DCE6EB, 0x515E7380, 0x491C4B4A, 0x2A2C1310, 0x3654442C,
+    0x50494648, 0x4F565B59, 0x7E989D95, 0xE8103F47, 0xEBE9EBE2, 0x78717AE8, 0x615A6E94, 0xE4E3D624,
+    0x2A29ABEB, 0x84784C2C, 0x757B8186, 0x7A787474, 0x5A535B70, 0x896F5C5B, 0x775E6978, 0x15576876,
+    0xE1E2EBEB, 0x4F6BA3BB, 0x695C6260, 0x1250565E, 0xEBE8E8EB, 0x102A4DDE, 0x5B5B5B5B, 0x5B5B5B5B,
+    0x66595D4F, 0x4E56695B, 0x4E48494B, 0x3D5C4D4A, 0x666C583E, 0x61767564, 0x2F4C5B68, 0x5A553528,
+    0x30445953, 0xDFEB183F, 0x59D3E3DE, 0x3E3D4147, 0x3E424547, 0x3334373A, 0x3B3E3833, 0x3E383436,
+    0x6E6D6761, 0x8078706E, 0x7A7E8182, 0x73747477, 0x817F7C7A, 0x87878684, 0x86878787, 0x81818284,
+    0x7D818181, 0x75747679, 0x87827C77, 0x83848687, 0x7D808284, 0x7475777A, 0x77777675, 0x70727476,
+    0x68626268, 0x7D79746E, 0x83828180, 0x86868584, 0x86838383, 0x8D8D8C89, 0x8B89898A, 0x888A8C8C,
+    0x82807E7D, 0x87878684, 0x8D8B8886, 0x8A8B8D8D, 0x8C8D8D8C, 0x8787898B, 0x827F8081, 0x9493918A,
+    0x86878C92, 0x81868988, 0x74767D83, 0x82817E79, 0x7B81817E, 0x686E7477, 0x63636567, 0x64656665,
+    0x7A746E6A, 0x6E747A7D, 0x82817A73, 0x7D7A7A7D, 0x7473767D, 0x6E686971, 0x61626362, 0x68645F5E,
+    0x8D867E7A, 0x7C858D91, 0x686E7477, 0x6E6B6867, 0x726F6E6E, 0x77787875, 0x75757677, 0x75767776,
+    0x6C696869, 0x7374736F, 0x6E6C6C6C, 0x7B797471, 0x7075797A, 0x6565676B, 0x747C7A6C, 0x7367656D,
+    0x81807D7B, 0x656D777F, 0x716C6868, 0x7E7E7B77, 0x6F72777C, 0x77767470, 0x99999590, 0x8F969B9B,
+    0x7F79767F, 0x96958A81, 0x8987878B, 0x81878D8D, 0x7E7F7F7D, 0x93928B82, 0xA8A5A2A1, 0xA6A8ABAB,
+    0x80858D94, 0xA2998D82, 0x85898F95, 0x7C7A7A81, 0x88828181, 0x93949490, 0x7A7B7A7A, 0x71727478,
+    0x807C7976, 0x7A7B7F81, 0x6C6F7478, 0x6063686A, 0x5556595C, 0x56565656, 0x51535454, 0x4D4E4F50,
+    0x4B4D4E4E, 0x4848494A, 0x44474847, 0x504A4442, 0x5E5B5857, 0x78736B63, 0x83807E7D, 0x86898A87,
+    0x8C8E8B88, 0x968B8185, 0x898C949D, 0x787F878A, 0x7A777878, 0x90938E83, 0xA098908A, 0x949BA3A5,
+    0x999A9396, 0x71717385, 0x72707175, 0x7E746E70, 0x767E807F, 0x605D5F69, 0x746F655C, 0x62666C71,
+    0x93897166, 0x7C7C7C87, 0x77797A7B, 0x72727374, 0x72737475, 0x85807874, 0x8A888683, 0x87878889,
+    0x8C8C8C8C, 0x8D8D8D8C, 0x898A8A89, 0x84848486, 0x82828384, 0x84838282, 0x85858686, 0x82838384,
+    0x807F7D7D, 0x85848381, 0x767E8385, 0x74706E6F, 0x7C797574, 0x6D72797C, 0x716E6C69, 0x696C6E71,
+    0x7A787574, 0x7C7C7C7B, 0x7D7D7B79, 0x7374767A, 0x70717273, 0x7271706F, 0x78777676, 0x5C656F76,
+    0x62616367, 0x74716C66, 0x64636566, 0x716E6A66, 0x74727070, 0x7B7A7876, 0x70727476, 0x76747270,
+    0x7B7A7A79, 0x81807E7C, 0x81818181, 0x7D7E8081, 0x7F807F7F, 0x7A7B7D7F, 0x817A7877, 0x8D8E8E89,
+    0x898A8A8A, 0x87888889, 0x7B7F8487, 0x70737578, 0x5C62696E, 0x5E5C5958, 0x6D686664, 0x7C7A7671,
+    0x7C7F7B76, 0x74717175, 0x76777675, 0x6F6F7174, 0x7E746E76, 0x7C7B777A, 0x86878583, 0x7A7A7D81,
+    0x8A857E7A, 0x868B8E8E, 0x6365727E, 0x7778746C, 0x5F616B75, 0x696C6C65, 0x71736E6A, 0x78736E6E,
+    0x7E777474, 0x82878986, 0x7E7C7B7B, 0x797B7F80, 0x7A737274, 0x81868884, 0x6D6E7781, 0x89878175,
+    0x8D908E8C, 0x82828489, 0x676F797E, 0x6A656060, 0x7A706A68, 0x727A8181, 0x6666686B, 0x68696B69,
+    0x74686261, 0x85878781, 0x8C8F8C88, 0x69676D7D, 0x716C6C6E, 0x7A7D7E79, 0x73737474, 0x76757474,
+    0x7B7A7776, 0x78797A7B, 0x777A7B78, 0x6F767A77, 0x6C6A6A6B, 0x7674706E, 0x7E7E7A77, 0x86827E7D,
+    0x7B7E8287, 0x68686D75, 0x7A7A7A79, 0x6E717478, 0x7A77797A, 0x8182817E, 0x68728391, 0x807A7168,
+    0x81858787, 0x6F71757A, 0x838B8476, 0x7276787A, 0x7D7A7674, 0x89878380, 0x736F7884, 0x6E737979,
+    0x72696462, 0x9F988C7E, 0x84878787, 0x7B7C7E81, 0x7475787A, 0x76757473, 0x817B7B80, 0x797C8185,
+    0x7A777778, 0x67717B7E, 0x6C6B6B6C, 0x71706E6D, 0x6A6E6F71, 0x63626266, 0x6E696461, 0x84807973,
+    0x7A7E8285, 0x7A7A7979, 0x7A80817E, 0x90857A76, 0x7A81898F, 0x83817D7A, 0x84818182, 0x8A8B8A87,
+    0x717D8384, 0x6C656165, 0x8B867E78, 0x94928E8D, 0x8680848B, 0x7C879290, 0x7D7D8085, 0x7877787C,
+    0x7473706E, 0x7A797877, 0x74777979, 0x5E62686E, 0x63605E5E, 0x7B787169, 0x7E777B83, 0x818B918B,
+    0x7072777B, 0x78777472, 0x6B6E7477, 0x68696A6A, 0x60666A6D, 0x5052565A, 0x53525151, 0x56555554,
+    0x706D6A68, 0x70717271, 0x6D6E6F71, 0x686A6C6D, 0x69686664, 0x7A746E6A, 0x646C7982, 0x5C5E6061,
+    0x64626060, 0x63656666, 0x625D5C5C, 0x66696B68, 0x50525C64, 0x55575754, 0x55505051, 0x605C5857,
+    0x676D6D6A, 0x6E675F5F, 0x5A545B64, 0x68696863, 0x69696C6D, 0x857E746C, 0x928F8F8F, 0x848A9093,
+    0x71757A7E, 0x7F7A736F, 0x8082807B, 0x847F7A7A, 0x86918E8E, 0x6868636E, 0x7F7B726A, 0x7776777B,
+    0x78746F6D, 0x6C71777A, 0x6E74736F, 0x625F5E65, 0x62656461, 0x66615C5D, 0x6D6E6862, 0x63606065,
+    0x68686867, 0x69696968, 0x585F5652, 0x76466A54, 0x565A6671, 0x7372715F, 0x645F5449, 0x52585F63,
+    0x64444043, 0xEB115C68, 0xE2DCEBE2, 0x665766D8, 0xEBEB1369, 0xE5EBE9E8, 0x50545543, 0x5350585A,
+    0x5E605D58, 0x5C5D5D5C, 0xE0E8106E, 0xEBE2EBDD, 0x53596064, 0x53515050, 0x4A3E604D, 0x6C66624F,
+    0x594D4F4B, 0xE6EBEA1D, 0x58E7EBEB, 0x43594950, 0x4E4F4F4E, 0x1344443F, 0xE6EBEAEB, 0x6A68E8E3,
+    0x2C105058, 0x12182512, 0x15101918, 0x52581C1A, 0x4D565550, 0x6B594744, 0x484A5157, 0x4D4D4C4A,
+    0x50505152, 0x50504F4F, 0x50505151, 0x53525150, 0x56565660, 0x64694B5B, 0x5F656E5D, 0x374B484A,
+    0xE8EBE2EB, 0x4A57E5EB, 0x54545454, 0x53535353, 0xEB2D6C44, 0xEBE5EBE2, 0x304547DA, 0x48394743
+};
+#endif
+
+#define PATCH_OFFSET_0 29
+#define PATCH_OFFSET_1 31
+#define PATCH_OFFSET_2 83
+#define PATCH_OFFSET_3 11
+#define PATCH_OFFSET_4 17
+#define PATCH_OFFSET_5 23
+#define PATCH_OFFSET_6 33
+
+static gctUINT32 ppuCmd0_0xA0[] = {
+    0x0801028A,
+    0x00000011,
+    0x08010E13,
+    0x00000002,
+    0x08010E4E,
+    0x00400000,
+    0x08010E4F,
+    0x00000000,
+    0x08010E50,
+    0x00000000,
+    0x10000000,
+    0x00000000
+};
+
+static gctUINT32 ppuCmd1_0xA0[] = {
+    0x08010E03,
+    0x00000C23,
+    0x08010E03,
+    0x00000C23,
+    0x08010594,
+    0x00000001,
+    0x10000000,
+    0x00000000
+};
+
+static gctUINT32 ppuCmd2_0xA0[] = {
+    0x08015580,
+    0x00000002,
+    0x08010E02,
+    0x00000701,
+    0x48000000,
+    0x00000701,
+    0x0804D800,
+    0x7388C280,
+    0x00000080,
+    0x00800080,
+    0x444051F0,
+    0x18000000,
+    0x0804D804,
+    0x00004000,
+    0x00000000,
+    0x10DA10B0,
+    0x00000000,
+    0x18000000,
+    0x0804D808,
+    0x738902C0,
+    0x00000040,
+    0x00400040,
+    0x444051F0,
+    0x18000000,
+    0x0804D80C,
+    0x00001000,
+    0x00000000,
+    0x10DA10B0,
+    0x00000000,
+    0x18000000,
+    0x0804D810,
+    0x73891300,
+    0x00000040,
+    0x00400040,
+    0x444051F0,
+    0x18000000,
+    0x0804D814,
+    0x00001000,
+    0x00000000,
+    0x10DA10B0,
+    0x00000000,
+    0x18000000,
+    0x0801D818,
+    0x7388BF40,
+    0x0801D819,
+    0x7388BF80,
+    0x0804D81C,
+    0x73892340,
+    0x00000080,
+    0x00400040,
+    0x44405071,
+    0x18000000,
+    0x0804D820,
+    0x00002000,
+    0x00000003,
+    0x10DD10B0,
+    0x00000000,
+    0x18000000,
+    0x0804D824,
+    0x11111111,
+    0x00000000,
+    0x03020100,
+    0x07060504,
+    0x18000000,
+    0x0804D828,
+    0x22222222,
+    0x00000000,
+    0x00000000,
+    0x00000400,
+    0x18000000,
+    0x0804D82C,
+    0x00000001,
+    0x00000001,
+    0x00000001,
+    0x00000001,
+    0x18000000,
+    0x0804D830,
+    0x00000001,
+    0x00000001,
+    0x00000001,
+    0x00000001,
+    0x18000000,
+    0x080102A4,
+    0x00000000,
+    0x08010420,
+    0x00000000,
+    0x08010427,
+    0x00000000,
+    0x08010416,
+    0x00000000,
+    0x08010409,
+    0x00000000,
+    0x0801021F,
+    0x00000000,
+    0x08010424,
+    0x00000010,
+    0x0801040A,
+    0x7388C000,
+    0x08015580,
+    0x00000002,
+    0x0801021A,
+    0x00000001,
+    0x08010425,
+    0x0000000F,
+    0x08030402,
+    0x00001F01,
+    0x00000005,
+    0x00000F00,
+    0x08010228,
+    0x00000000,
+    0x0801028C,
+    0x00000100,
+    0x08010E07,
+    0x00000000,
+    0x0801040C,
+    0x00000000,
+    0x0801020C,
+    0x0F3F0000,
+    0x08010201,
+    0x00000001,
+    0x080102AA,
+    0x00000000,
+    0x08010E22,
+    0x007F0000,
+    0x08010412,
+    0x00000000,
+    0x08010E27,
+    0xFFFFFFFF,
+    0x08010240,
+    0x03000002,
+    0x08010249,
+    0x00000000,
+    0x08010247,
+    0x00000002,
+    0x0801024B,
+    0x00000000,
+    0x0801024D,
+    0x00000000,
+    0x0801024F,
+    0x00000000,
+    0x08010256,
+    0x00000008,
+    0x08010257,
+    0x00000001,
+    0x08010258,
+    0x00000000,
+    0x08060250,
+    0x00000000,
+    0x0000003F,
+    0xFFFFFFFF,
+    0x00000007,
+    0x00000000,
+    0x000003FF,
+    0x18000000,
+    0x08010248,
+    0xBADABEEB,
+    0x08010E03,
+    0x00000024,
+    0x08010E02,
+    0x00000701,
+    0x48000000,
+    0x00000701,
+    0x08010E03,
+    0x00000C23,
+    0x08010E03,
+    0x00000C23,
+    0x08010594,
+    0x00000001,
+    0x10000000,
+    0x00000000
+};
+
+static gctUINT32 ppuCmd3_0xA0[] = {
+    0x08010E03,
+    0x00000C23,
+    0x08010E03,
+    0x00000C23,
+    0x08010594,
+    0x00000001,
+    0x10000000,
+    0x00000000
+};
+
+static gctUINT32 ppuMem0_0xA0[] = {
+    0x7E83898D,
+    0x807E7B7B,
+    0x84817F7F,
+    0x5C687A83,
+    0x7E766C66,
+    0x616A777F,
+    0x5C5B5856,
+    0x625F5C5C,
+    0x52515A62,
+    0x52585C58,
+    0x60585554,
+    0x70716F69,
+    0x71696A6E,
+    0x787F827D,
+    0x72747D87,
+    0x6D6D6E71,
+    0x877F736A,
+    0x6A737F87,
+    0x6B686868,
+    0x7A78746E,
+    0x767A7B7C,
+    0x67696E72,
+    0x716E6E6E,
+    0x686E7274,
+    0x7A75706C,
+    0x7D7D7D7C,
+    0x7477797A,
+    0x6E6E6E70,
+    0x72716F6E,
+    0x74747473,
+    0x75747474,
+    0x75757575,
+    0x72747475,
+    0x70707071,
+    0x6E6A6868,
+    0x76767572,
+    0x78757678,
+    0x7D7F7F7C,
+    0x81807D7A,
+    0x686E787F,
+    0x625E6062,
+    0x67696B68,
+    0x62625C55,
+    0x5352555C,
+    0x5C5C5B59,
+    0x5052565A,
+    0x56504F50,
+    0x68625E5C,
+    0x7B7E7468,
+    0x6260626E,
+    0x59565B62,
+    0x726B645E,
+    0x7D818283,
+    0x76757679,
+    0x72747472,
+    0x726F6E6E,
+    0x73727170,
+    0x87817A75,
+    0x7C74757A,
+    0x747F8786,
+    0x706A686E,
+    0x747B7872,
+    0x78747475,
+    0x6F747A7B,
+    0x706D6C6C,
+    0x72737473,
+    0x74797874,
+    0x66626269,
+    0x6A6A6B6B,
+    0x6D6C6A6A,
+    0x807B7168,
+    0x5C636F7A,
+    0x62636566,
+    0x65646362,
+    0x61516277,
+    0xE0226E5C,
+    0xE5EAE6E2,
+    0x48627ACA,
+    0x4C514837,
+    0x4E4E4A46,
+    0x78575350,
+    0xE610687C,
+    0xDFE2DBE0,
+    0x504E58EB,
+    0x1026109F,
+    0xEBE6BD38,
+    0x7483AEEB,
+    0x5E5A5561,
+    0x716D645C,
+    0x1834566C,
+    0xE8EBE2E6,
+    0x181531D3,
+    0x5B5D6162,
+    0x605D5C5A,
+    0xD1154469,
+    0xEBE8E8EB,
+    0xCDEBDCEB,
+    0xEBDDEBDC,
+    0x5DE6E8EB,
+    0x47594A56,
+    0x5C5C5550,
+    0x5D71564A,
+    0xEB10616A,
+    0xE3EBD5EB,
+    0x3E524456,
+    0x64645C56,
+    0x8C716370,
+    0x2E5C4E55,
+    0xE7E8E9EB,
+    0x6788B7D9,
+    0x50535B60,
+    0x605C5651,
+    0x5C5D5E5F,
+    0x52545659,
+    0x57565554,
+    0x4B4E5256,
+    0x4A705252,
+    0xEBD8173F,
+    0xCDDFEBD4,
+    0xE5EBDCEB,
+    0xE8EBE2EB,
+    0x4A57E5EB,
+    0x4E4C4B4B,
+    0x5251504F,
+    0x3B105F60,
+    0xEBC93914,
+    0x5DDFCBEB,
+    0x4B58522C,
+    0x6259504A,
+    0x314A6369,
+    0xEBCECA29,
+    0x1043E4D6,
+    0x4F483E5C,
+    0x685E5D3A,
+    0x565B5C5C,
+    0x4E4D4D50,
+    0x50504E4E,
+    0x4D4E5050,
+    0xDC193F49,
+    0xEBE3EAE2,
+    0x6F7457C9,
+    0x50465B4B,
+    0x5860686E,
+    0x53535254,
+    0xE715402F,
+    0xE0EBEBE9,
+    0x385662DF,
+    0x29403755,
+    0xDDEBEB16,
+    0x5F3FE7EB,
+    0x553D4245,
+    0x2A4D4853,
+    0x446F233E,
+    0xD9C93E3B,
+    0xC5EBE5E8,
+    0x434F4C71,
+    0x4547494A,
+    0x5D564E47,
+    0x504F5256,
+    0x4E515554,
+    0x56105012,
+    0xC4EBE8DB,
+    0x314B87BB,
+    0x565A523D,
+    0x524A5648,
+    0x8725235A,
+    0xCBEBE6EB,
+    0x23331A53,
+    0x5B51394C,
+    0xE8103F5C,
+    0xD9E2EBE5,
+    0x504C293C,
+    0x4A544B40,
+    0x513E3D40,
+    0xE9E11948,
+    0x5CE9DEEB,
+    0x615D5957,
+    0x67676664,
+    0x4D84534D,
+    0x38584348,
+    0x5E3E595A,
+    0xDE16627A,
+    0xE1EBD4E9,
+    0x52607CD6,
+    0x5D63686C,
+    0x5A585758,
+    0x6D5F6552,
+    0xE619767C,
+    0xEBEBE6E3,
+    0x7E626FDE,
+    0x8E938083,
+    0x31315410,
+    0xE8EAEBE8,
+    0x84875FD3,
+    0x686C7174,
+    0x6F6D6967,
+    0x5C5A5E5E,
+    0x60636A68,
+    0x76666462,
+    0x74876868,
+    0x857A627F,
+    0x836B5C93,
+    0x695F6462,
+    0x124D515B,
+    0xDB28121D,
+    0xE4E3E9E6,
+    0x4A4A4A4A,
+    0x4A4A4A4A,
+    0x8B626B68,
+    0x5458807A,
+    0x7878736F,
+    0x145D526A,
+    0xD8EBEAB7,
+    0x648DCADE,
+    0x4A544A61,
+    0x5D56474F,
+    0x3B476A43,
+    0xE8EB123C,
+    0x4DE2EBE6,
+    0x55536059,
+    0x55555454,
+    0x59585756,
+    0x45555C5C,
+    0x3B322D34,
+    0x8078726F,
+    0x81858786,
+    0x7F808080,
+    0x8181807F,
+    0x7C7D7E7E,
+    0x7C7C7C7C,
+    0x7A7A7A7B,
+    0x7D7C7A7A,
+    0x83878787,
+    0x7A7A7B7F,
+    0x8B867E79,
+    0x8C8C8D8D,
+    0x84868789,
+    0x87868484,
+    0x86878989,
+    0x7A7B7F82,
+    0x696D767F,
+    0x756E6968,
+    0x7A777574,
+    0x80807E7C,
+    0x817F8081,
+    0x8B8A8884,
+    0x7A7E8286,
+    0x71737578,
+    0x807D7B7A,
+    0x88878582,
+    0x8F8D8887,
+    0x888B8D8F,
+    0x87878889,
+    0x8E8C8987,
+    0x74777E85,
+    0x89878179,
+    0x938D8B8B,
+    0x9A9B9B99,
+    0x787E858A,
+    0x74747474,
+    0x6F737472,
+    0x6D6F706E,
+    0x67656668,
+    0x74736F6A,
+    0x686A6E72,
+    0x65666767,
+    0x74736D66,
+    0x817A7474,
+    0x707A7E7C,
+    0x7B746C69,
+    0x73737475,
+    0x74747474,
+    0x7B787676,
+    0x74797E7F,
+    0x75727171,
+    0x73757878,
+    0x76747474,
+    0x78797A79,
+    0x6F747574,
+    0x7C756E6C,
+    0x7B787675,
+    0x8181817F,
+    0x7A7C7E80,
+    0x79787879,
+    0x73777A7A,
+    0x69696A6E,
+    0x93948D80,
+    0x776E778B,
+    0x85878582,
+    0x86838182,
+    0x85858687,
+    0x80828485,
+    0x70777A7A,
+    0x756F696A,
+    0xA3A29F9B,
+    0x989EA4A4,
+    0x77717382,
+    0x90897D77,
+    0x7E858B8D,
+    0x817E7A79,
+    0x94948F88,
+    0x747E8890,
+    0x7A737274,
+    0x9C999387,
+    0x90929496,
+    0x95939290,
+    0x81848C93,
+    0x8B857F7F,
+    0x8D91918E,
+    0x89858285,
+    0x8B8D9093,
+    0x8B8C8D8C,
+    0x81828384,
+    0x86858382,
+    0x85818184,
+    0x79808788,
+    0x60646B6F,
+    0x5A5B5C5D,
+    0x585A5B5B,
+    0x55555657,
+    0x51525253,
+    0x50505051,
+    0x484C5051,
+    0x5B544B47,
+    0x78756A5F,
+    0x8D827876,
+    0x817C8188,
+    0x787A8083,
+    0x7B787A80,
+    0x8D878280,
+    0x8E93938F,
+    0x82878B8C,
+    0x77777D81,
+    0x8A8E8C81,
+    0x978A8688,
+    0x96999F9F,
+    0x9593939D,
+    0x7A7C7E88,
+    0x6D646269,
+    0x7D6F686D,
+    0x858A8781,
+    0x6F757B80,
+    0x76736D6B,
+    0x61606671,
+    0x98887571,
+    0x92949395,
+    0x75797E81,
+    0x70727474,
+    0x77777675,
+    0x817E7A78,
+    0x7A7E8182,
+    0x79777576,
+    0x807E7D7C,
+    0x80818181,
+    0x85858280,
+    0x81818284,
+    0x85848382,
+    0x82838485,
+    0x83828181,
+    0x87868584,
+    0x777A7F81,
+    0x76757474,
+    0x74737374,
+    0x76777775,
+    0x74747576,
+    0x77787876,
+    0x71727474,
+    0x74747271,
+    0x74747474,
+    0x76767574,
+    0x7F7F7B79,
+    0x78797A7D,
+    0x76757474,
+    0x77777777,
+    0x7A7B7B7A,
+    0x7B7A7A7A,
+    0x79706E71,
+    0x78808683,
+    0x6F727579,
+    0x7975726F,
+    0x7C7A7877,
+    0x80807F7E,
+    0x76787A7C,
+    0x7C7A7876,
+    0x83817F7F,
+    0x7D818485,
+    0x7A777574,
+    0x7F7E7D7B,
+    0x81828383,
+    0x81818181,
+    0x777B8082,
+    0x837F7976,
+    0x8F8E8D8C,
+    0x8B8C8D8F,
+    0x82868A8D,
+    0x73767A7F,
+    0x65696E71,
+    0x5F5F6062,
+    0x6863615F,
+    0x73716E6B,
+    0x69717474,
+    0x5C5A5A60,
+    0x7E7A716A,
+    0x7B7A7B7D,
+    0x7277767C,
+    0x63625C62,
+    0x6E6A6662,
+    0x7372706F,
+    0x887F7979,
+    0x8686898D,
+    0x6467737E,
+    0x7979746B,
+    0x67666C74,
+    0x666C706E,
+    0x75796857,
+    0x5B545462,
+    0x5F5C5C5D,
+    0x74716B64,
+    0x7C7A7877,
+    0x777A7D7E,
+    0x807A7A7E,
+    0x868A8D87,
+    0x83818386,
+    0x8B8B8986,
+    0x76777C81,
+    0x7C7D7C79,
+    0x7A7F817F,
+    0x777B7C7A,
+    0x7A747172,
+    0x7B808481,
+    0x71747577,
+    0x7C787471,
+    0x7A7B7D7F,
+    0x7F7E7B7A,
+    0x696B7178,
+    0x69666568,
+    0x898B7C6C,
+    0x93867A7E,
+    0x84888B8C,
+    0x76787B80,
+    0x6E737679,
+    0x61626568,
+    0x73796F5E,
+    0x787B7770,
+    0x7E7F7D79,
+    0x85878680,
+    0x8C888789,
+    0x898D908F,
+    0x8B8F8D8C,
+    0x827A7780,
+    0x8F8E8E8E,
+    0x9090908F,
+    0x84848687,
+    0x84858585,
+    0x81797E87,
+    0x7585928F,
+    0x7F786C63,
+    0x7F7F7F81,
+    0x71747675,
+    0x71737371,
+    0x7474716E,
+    0x7B797775,
+    0x6868717A,
+    0x66666868,
+    0x69666362,
+    0x7E7B756F,
+    0x8C8B8580,
+    0x86858689,
+    0x8B898887,
+    0x8C8C8C8C,
+    0x7A7A818A,
+    0x7F7E7E7D,
+    0x91877D7A,
+    0x6E758391,
+    0x78797877,
+    0x6E707476,
+    0x6E747673,
+    0x696C6C6B,
+    0x8178706C,
+    0x8D8D8D88,
+    0x7D82878B,
+    0x7F7C7A7A,
+    0x918D8887,
+    0x747D8990,
+    0x817F7A78,
+    0x686F7980,
+    0x65626263,
+    0x6C6E6E6A,
+    0x5B5B6065,
+    0x575C5E5D,
+    0x635C5653,
+    0x7474716B,
+    0x76757473,
+    0x88837C78,
+    0x6C6E747E,
+    0x6A696B6D,
+    0x817B746E,
+    0x6B717A80,
+    0x6F6F6F70,
+    0x74737170,
+    0x74747575,
+    0x6F707173,
+    0x79726F70,
+    0x71798080,
+    0x76746F6D,
+    0x7A7A7A79,
+    0x72747778,
+    0x6D6C6D6E,
+    0x6E6D6C6B,
+    0x6E6E6E6E,
+    0x6E6E6E6E,
+    0x6F6F6E6E,
+    0x73747475,
+    0x6E6F7072,
+    0x6D6A6A6A,
+    0x73747370,
+    0x7A757271,
+    0x8383827F,
+    0x77787A7D,
+    0x686D7275,
+    0x5F5E6164,
+    0x5B5E6262,
+    0x66635D57,
+    0x5C5C5E62,
+    0x5B595858,
+    0x5155595C,
+    0x56504E50,
+    0x67625D5B,
+    0x747A746D,
+    0x68626168,
+    0x5B575B62,
+    0x746E6862,
+    0x75797C7E,
+    0x7F7A7674,
+    0x75797A7C,
+    0x74737272,
+    0x827E7874,
+    0x82828383,
+    0x7E78787A,
+    0x7A818785,
+    0x73727075,
+    0x767A746F,
+    0x7A787675,
+    0x70747A7C,
+    0x73706E6E,
+    0x70727475,
+    0x7074706B,
+    0x6C686669,
+    0x696A6C6E,
+    0x6467696A,
+    0x74706C69,
+    0x62666E73,
+    0x5F606162,
+    0x6261605F,
+    0x695D6671,
+    0xC7216E61,
+    0xEAEBE6DF,
+    0x35567ACD,
+    0x50565147,
+    0x4D51514D,
+    0x7367574A,
+    0xE912505B,
+    0xE8EBE8EB,
+    0x755850EB,
+    0xE0D12B6C,
+    0xE4EBEBD6,
+    0x5637252C,
+    0x52535860,
+    0x68676462,
+    0x4C5A666A,
+    0xD6A81F1C,
+    0xEAE2C5EB,
+    0x595B5E61,
+    0x605D5B58,
+    0xD7356073,
+    0xE8E5EBEB,
+    0x2BCAEBE1,
+    0xCEEBCF1F,
+    0x5CE5E8EB,
+    0x45584854,
+    0x5759534F,
+    0x4A624D44,
+    0xE52D6867,
+    0xE0DCDCEB,
+    0x5559505C,
+    0x775D4F56,
+    0x6351767D,
+    0x235E5679,
+    0x23201310,
+    0x6E553726,
+    0x484D5256,
+    0x55504A47,
+    0x57595A5A,
+    0x51525456,
+    0x54545352,
+    0x4A4C5052,
+    0x556B4A47,
+    0xE6DC3356,
+    0xEBEBE5EA,
+    0x1922EBCA,
+    0xE8EBE2EB,
+    0x4A57E5EB,
+    0x504F4E4D,
+    0x52525150,
+    0xD03C5F54,
+    0xE1EBCAD2,
+    0x443116E0,
+    0x3946403B,
+    0x4D4C4E4E,
+    0x5D625F56,
+    0xDF251610,
+    0xE1D5EBE5,
+    0x4B505CB5,
+    0x4F4D4B41,
+    0x53555554,
+    0x504F4E50,
+    0x504F4E4D,
+    0x4E4F5050,
+    0xEB254868,
+    0xEAD1DFEB,
+    0x5A444DEB,
+    0x472F4B4E,
+    0x54585958,
+    0x514F4D4F,
+    0xEB1E5555,
+    0xE0E3D0DE,
+    0x444F5CEB,
+    0x2E513B5D,
+    0xC9D0E627,
+    0x5442E3E7,
+    0x5151543D,
+    0x4A5E4442,
+    0x2B50453D,
+    0x1E16102A,
+    0x351E1018,
+    0x48565444,
+    0x44454849,
+    0x4E4A4543,
+    0x51505357,
+    0x50545656,
+    0xE0E8EA18,
+    0x2EC8E8EB,
+    0x69614A36,
+    0x53525662,
+    0x4D565B54,
+    0x2B3D4E50,
+    0xEBE4BC42,
+    0x5EC3C1D7,
+    0x605D4338,
+    0xEB153D5D,
+    0xE8E8EBE2,
+    0x4B4C2F38,
+    0x5650444D,
+    0x525B5750,
+    0xE0E83052,
+    0x55E4EBE5,
+    0x5A565250,
+    0x5E5E5E5C,
+    0x4B6B415C,
+    0x5852434A,
+    0x52395056,
+    0xEB326068,
+    0xEBEADCE8,
+    0x683A6CEB,
+    0x585A5C5C,
+    0x56565657,
+    0x6A5C524C,
+    0xCF216E62,
+    0xEBEBE9EA,
+    0x816E7EE8,
+    0x7C69637A,
+    0xEBD7C72D,
+    0xEBE3E0E9,
+    0x7C8768E9,
+    0x6E747A80,
+    0x76736E6C,
+    0x314F7280,
+    0x937B5B3A,
+    0x7C616168,
+    0x54736673,
+    0x8C766E6B,
+    0x545D7887,
+    0x665D625F,
+    0x10484A55,
+    0xE9C6EBEB,
+    0xD6EBE7D5,
+    0x69696969,
+    0x69696969,
+    0x6B6E686A,
+    0x725A4D5D,
+    0x67656568,
+    0x2C695661,
+    0x19181110,
+    0x7F644125,
+    0x63626367,
+    0x50564C59,
+    0x5348624B,
+    0xEBDD1348,
+    0x6DDED8E2,
+    0x4E444F64,
+    0x4E505152,
+    0x4A4A4B4C,
+    0x434E514F,
+    0x38312E35,
+    0x7D7A7571,
+    0x8482807F,
+    0x7C7E7F80,
+    0x7B7B7B7C,
+    0x807F7E7D,
+    0x83828181,
+    0x81818182,
+    0x81818181,
+    0x7F838585,
+    0x7474767A,
+    0x89837B76,
+    0x8C8C8C8C,
+    0x8386888A,
+    0x81818181,
+    0x81828282,
+    0x75787B7F,
+    0x66676E78,
+    0x76716C68,
+    0x74747475,
+    0x7F7C7A77,
+    0x7E7C7C7D,
+    0x88878682,
+    0x8D8D8D8D,
+    0x8083888B,
+    0x817D7A7A,
+    0x87878683,
+    0x8F8D8A87,
+    0x878A8D8F,
+    0x88898A8B,
+    0x8A898988,
+    0x79797E83,
+    0x8E8C877F,
+    0x93918E8C,
+    0x98979594,
+    0x7D82898E,
+    0x7D7D7C7B,
+    0x69717778,
+    0x65676765,
+    0x62626264,
+    0x69696865,
+    0x6F6D6B6A,
+    0x686B6F70,
+    0x7D7A736B,
+    0x85807A7A,
+    0x73797C80,
+    0x746D686C,
+    0x6D6C6A69,
+    0x706E6E6D,
+    0x7A777474,
+    0x71767C7D,
+    0x6D6C6D6E,
+    0x6F70706E,
+    0x706C6A69,
+    0x79797874,
+    0x767B7A76,
+    0x7B746E6F,
+    0x76747474,
+    0x7A7A7A7A,
+    0x76767676,
+    0x76767676,
+    0x767D8182,
+    0x6667696E,
+    0x91938B7B,
+    0x7A707687,
+    0x84878582,
+    0x827F7D7F,
+    0x7E7C7B7C,
+    0x7E808180,
+    0x6D73797C,
+    0x736E6968,
+    0xA7A6A39F,
+    0x9BA2A8A9,
+    0x7C767987,
+    0x938E827C,
+    0x81878D93,
+    0x87868381,
+    0x9093928D,
+    0x7079838B,
+    0x746E6D6E,
+    0x928F897F,
+    0x888D9398,
+    0x9D978F89,
+    0x878C939A,
+    0x88838184,
+    0x80818180,
+    0x8B86817F,
+    0x8A8C8E91,
+    0x8B8B8C8B,
+    0x81818181,
+    0x7D7E7F81,
+    0x7E7A7A7B,
+    0x6F767E81,
+    0x5B5E6367,
+    0x58595959,
+    0x56575758,
+    0x55555656,
+    0x50515152,
+    0x4D4E4F50,
+    0x42474B4C,
+    0x4E48413E,
+    0x6D6A5F54,
+    0x9787756D,
+    0x7E7A818C,
+    0x84878986,
+    0x7A75777C,
+    0x9C948A82,
+    0x969E9F9E,
+    0x81858A8F,
+    0x79787C80,
+    0x91938F83,
+    0x9A908C8D,
+    0x999DA1A2,
+    0x9B999399,
+    0x8483828D,
+    0x6E696A71,
+    0x7D6F686D,
+    0x80878781,
+    0x696C6F76,
+    0x74706A66,
+    0x5F60666F,
+    0x8C7C6965,
+    0x8588878A,
+    0x76797D80,
+    0x70727474,
+    0x75757574,
+    0x86817B77,
+    0x81848585,
+    0x7E7C7C7E,
+    0x8281807F,
+    0x82828382,
+    0x83838180,
+    0x7F7F7F81,
+    0x81818181,
+    0x81818181,
+    0x83818181,
+    0x87878584,
+    0x7A7C7E80,
+    0x7D7C7A7A,
+    0x76777877,
+    0x75747474,
+    0x77757575,
+    0x74767879,
+    0x6F6F6F6F,
+    0x6F6F6F6F,
+    0x72717070,
+    0x74747473,
+    0x80807C7A,
+    0x78797A7D,
+    0x75757575,
+    0x78777675,
+    0x837F7B7A,
+    0x87888987,
+    0x6962676E,
+    0x7B818178,
+    0x6C6E7274,
+    0x74726E6C,
+    0x7A777574,
+    0x7E7D7D7B,
+    0x7476797A,
+    0x7A797674,
+    0x83807E7E,
+    0x85878787,
+    0x81818282,
+    0x7C7D7F80,
+    0x81828282,
+    0x81818181,
+    0x7C7B7D7F,
+    0x89878480,
+    0x8C8D8E8F,
+    0x8D8C8C8B,
+    0x8185898D,
+    0x74767A7E,
+    0x61676D70,
+    0x5E5D5C5D,
+    0x625E5C5B,
+    0x6E6C6865,
+    0x7577726B,
+    0x6463666E,
+    0x7D7A746E,
+    0x79797A7C,
+    0x7576747A,
+    0x6A696468,
+    0x78746E6A,
+    0x7B7A7A7A,
+    0x8C837E7C,
+    0x84868B8E,
+    0x5F616E7A,
+    0x78787468,
+    0x63646E76,
+    0x64696C68,
+    0x7C7A6855,
+    0x5A585E6E,
+    0x645D5C5C,
+    0x7675736C,
+    0x7C7A7877,
+    0x7A7D7F7F,
+    0x7B747477,
+    0x83878A85,
+    0x807E8287,
+    0x8F8F8D87,
+    0x7F7E8388,
+    0x81858784,
+    0x68727A7E,
+    0x73716B66,
+    0x7C747170,
+    0x767C8382,
+    0x676A6F73,
+    0x6B6A6867,
+    0x76727273,
+    0x8181817C,
+    0x7176797A,
+    0x625E5F68,
+    0x7D77706C,
+    0x8D8A8681,
+    0x84888B8D,
+    0x77797C80,
+    0x6E707273,
+    0x6466686B,
+    0x747A705F,
+    0x7778746E,
+    0x79787774,
+    0x8686827C,
+    0x8C88898C,
+    0x92949592,
+    0x8E949697,
+    0x817B7A83,
+    0x8A888787,
+    0x8F8E8D8C,
+    0x80818487,
+    0x7F818181,
+    0x72727F8D,
+    0x7A81837C,
+    0x8480766F,
+    0x787A7D82,
+    0x69696B6B,
+    0x7276766F,
+    0x7A787574,
+    0x807E7B7A,
+    0x6666707C,
+    0x68696B6A,
+    0x63656869,
+    0x6C696764,
+    0x89898681,
+    0x81818186,
+    0x8481807F,
+    0x8E8D8A87,
+    0x7F7B8188,
+    0x80808182,
+    0x93887E7A,
+    0x67748794,
+    0x72716F6E,
+    0x73747473,
+    0x6F757674,
+    0x6164676A,
+    0x7C716761,
+    0x8F8E8C86,
+    0x7B818689,
+    0x7D7B7A79,
+    0x88878481,
+    0x8B8A8988,
+    0x8386888B,
+    0x767A7E81,
+    0x6E686C71,
+    0x767C7F79,
+    0x666B6E6F,
+    0x5E5D5F62,
+    0x6F68615C,
+    0x7D7B7874,
+    0x80827D76,
+    0x8F857B7A,
+    0x6A6A6F77,
+    0x6A69696B,
+    0x7975716E,
+    0x7174777A,
+    0x7477797A,
+    0x6A6B6E71,
+    0x6F6D6C6C,
+    0x7A787572,
+    0x8177767A,
+    0x7A858E8D,
+    0x72717070,
+    0x78777574,
+    0x6F727577,
+    0x6A6A6B6D,
+    0x68696A6B,
+    0x62636466,
+    0x63636262,
+    0x64646463,
+    0x73747373,
+    0x6E6E7072,
+    0x6C6B6C6D,
+    0x6E6E6F6E,
+    0x78716A65,
+    0x8B88847F,
+    0x6C727C85,
+    0x66686A6A,
+    0x5D5E6164,
+    0x55585C5E,
+    0x67625C59,
+    0x65666868,
+    0x57555658,
+    0x54585C5C,
+    0x56504E50,
+    0x645F5C59,
+    0x6C747470,
+    0x6E665E61,
+    0x5C565C64,
+    0x706E6A65,
+    0x6D6F7476,
+    0x8881766E,
+    0x8D8D8F90,
+    0x8184888B,
+    0x8B867E77,
+    0x7D81868A,
+    0x7F7B7A7A,
+    0x7F818281,
+    0x7A7F7D81,
+    0x76756D6D,
+    0x82817C79,
+    0x74767B80
+};
+
+static gctUINT32 ppuMem1_0xA0[] = {
+    0x00010000
+};
+
+static gctUINT32 ppuMem2_0xA0[] = {
+    0x00010000
+};
+
+static gctUINT32 ppuMem3_0xA0[] = {
+    0x38011039,
+    0x39200804,
+    0xC0A90050,
+    0x74000008,
+    0x38021039,
+    0x39202804,
+    0xC0A90050,
+    0x74000008,
+    0x38031039,
+    0x39204804,
+    0xC0A90050,
+    0x74000008,
+    0xB8017005,
+    0x002018FC,
+    0x01C900C0,
+    0x40390098,
+    0xB8027005,
+    0x002028FC,
+    0x01C90140,
+    0x40390098,
+    0xB8037005,
+    0x002038FC,
+    0x01C901C0,
+    0x40390098,
+    0x02001001,
+    0x15408804,
+    0x40000010,
+    0x76FFDFF8,
+    0x04041036,
+    0x00000804,
+    0x4154007A,
+    0x00000000,
+    0x0400100C,
+    0x3FC04804,
+    0x40010440,
+    0x2000007A,
+    0x38000835,
+    0x39207804,
+    0x41E80050,
+    0x00390018,
+    0x04041036,
+    0x00001804,
+    0x4154007A,
+    0x00000000,
+    0x0400100C,
+    0x3FC04804,
+    0x40010440,
+    0x2000007A,
+    0x38000835,
+    0x39207804,
+    0x41E80050,
+    0x00390028,
+    0x04041036,
+    0x00002804,
+    0x4154007A,
+    0x00000000,
+    0x0400100C,
+    0x3FC04804,
+    0x40010440,
+    0x2000007A,
+    0x38000835,
+    0x39207804,
+    0x41E80050,
+    0x00390038
+};
+
+#endif
+
+#if gcdRESET_USC1
+
+#if gcdRESET_USC_C
+
+#include "gc_hal_kernel_hardware_func_usc.h"
+#endif
+
+#if !gcdRESET_USC_C
+static gctUINT32 nnBuffer0[] = {
+    0x8010010c, 0x07383fc2, 0xc1000000, 0x00a01000,
+    0x08e00008, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000800, 0x40000000,
+    0x00e700ff, 0x00000040, 0x00000000, 0x03ffffff,
+    0x00000000, 0x03ffffff, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static gctUINT32 nnBuffer1[] = {
+    0x8040010c, 0x07383fd5, 0x01000000, 0x00a00e00,
+    0x08700008, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000800, 0x00000000,
+    0x00e701fe, 0x00000070, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static gctUINT32 nnBuffer2[] = {
+    0x8080010c, 0x07383fd5, 0x01000000, 0x00a01000,
+    0x09000008, 0x00000000, 0x00000000, 0x00000000
+};
+
+static gctUINT32 nnBuffer3[] = {
+    0x8010010e, 0x07383fc2, 0xc1000000, 0x00a01000,
+    0x08e00008, 0x00000000, 0x00000000, 0x00000000,
+    0x00143000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000800, 0x00000000,
+    0x00e700ff, 0x00000040, 0x00000000, 0x03ffffff,
+    0x00000000, 0x03ffffff, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+#endif
+
+#define NN_BUFFER_IDX       0
+#define KERNEL_BUFFER_IDX   1
+#define INPUT_BUFFER_IDX    2
+#define RESULT_BUFFER_IDX   3
+#define SRAM_BUFFER_IDX_C   4
+
+#define PATCH_KERNEL_OFFSET 5
+#define PATCH_INPUT_OFFSET  6
+#define PATCH_RESULT_OFFSET 7
+#endif
+
+#if gcdRESET_USC2
+static gctUINT32 instBuffer[] = {
+    0x04021009, 0x00200000, 0x80000000, 0x20000048,
+    0x02021009, 0x00200000, 0x80000000, 0x20154048,
+    0x07801009, 0x00200000, 0x80000000, 0x20390008,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008,
+    0x02021001, 0x2aa02800, 0x80000000, 0x202a8048,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008,
+    0x02021001, 0x2aa02800, 0x80000000, 0x202a8048,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008,
+    0x02021001, 0x2aa02800, 0x80000000, 0x202a8048,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008,
+    0x02021001, 0x2aa02800, 0x80000000, 0x202a8048,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008,
+    0x02021001, 0x2aa02800, 0x80000000, 0x202a8048,
+    0x07801033, 0x3fe02800, 0x81540140, 0x00390008
+};
+
+#define INST_BUFFER_IDX         0
+#define OUTPUT_BUFFER_IDX       1
+#define SRAM_BUFFER_IDX         2
+#endif
+#endif
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+#define gcmSEMAPHORESTALL(buffer) \
+        do \
+        { \
+            /* Arm the PE-FE Semaphore. */ \
+            *buffer++ \
+                = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+                | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, 1) \
+                | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, 0x0E02); \
+            \
+            *buffer++ \
+                = gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END) \
+                | gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE);\
+            \
+            /* STALL FE until PE is done flushing. */ \
+            *buffer++ \
+                = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+            \
+            *buffer++ \
+                = gcmSETFIELDVALUE(0, STALL_STALL, SOURCE, FRONT_END) \
+                | gcmSETFIELDVALUE(0, STALL_STALL, DESTINATION, PIXEL_ENGINE); \
+        } while(0)
+
+#if gcdFLOP_RESET
+static gceSTATUS
+_FuncRelease(
+    IN OUT gcsFUNCTION_EXECUTION_PTR Execution
+    )
+{
+    gckHARDWARE hardware = gcvNULL;
+    gcsFUNCTION_COMMAND_PTR command = gcvNULL;
+    gcsFUNCTION_EXECUTION_DATA_PTR data = gcvNULL;
+    gctUINT8 i, j;
+
+    if (!Execution || !Execution->funcCmd)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    hardware = (gckHARDWARE)Execution->hardware;
+
+    for (i = 0; i < Execution->funcCmdCount; i++)
+    {
+        command = &Execution->funcCmd[i];
+
+        /* Free data buffers. */
+        if (command->data)
+        {
+            for (j = 0; j < command->dataCount; j++)
+            {
+                data = &command->data[j];
+
+                if (data->bufVidMem)
+                {
+                    if (data->address)
+                    {
+                        /* Synchroneous unlock. */
+                        gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                            hardware->kernel,
+                            data->bufVidMem,
+                            0,
+                            gcvNULL
+                            ));
+                        data->address = 0;
+                    }
+
+                    if (data->logical)
+                    {
+                        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                            hardware->kernel,
+                            data->bufVidMem,
+                            0,
+                            gcvFALSE,
+                            gcvFALSE
+                            ));
+                        data->logical = gcvNULL;
+                    }
+
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                        hardware->kernel,
+                        data->bufVidMem
+                        ));
+                    data->bufVidMem = gcvNULL;
+                }
+            }
+
+            gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)command->data));
+            command->data = gcvNULL;
+            command->dataCount = 0;
+        }
+
+        /* Free command. */
+        if (command->funcVidMem)
+        {
+            if (command->address)
+            {
+                /* Synchroneous unlock. */
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                    hardware->kernel,
+                    command->funcVidMem,
+                    0,
+                    gcvNULL
+                    ));
+                command->address = 0;
+            }
+
+            if (command->logical)
+            {
+                gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                    hardware->kernel,
+                    command->funcVidMem,
+                    0,
+                    gcvFALSE,
+                    gcvFALSE
+                    ));
+                command->logical = gcvNULL;
+            }
+
+            gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                hardware->kernel,
+                command->funcVidMem
+                ));
+            command->funcVidMem = gcvNULL;
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    Execution->funcCmd = gcvNULL;
+    Execution->funcCmdCount = 0;
+
+    return gcvSTATUS_OK;
+}
+#endif
+
+static gceSTATUS
+_FuncExecute(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    return gckHARDWARE_ExecuteFunctions(Execution);
+}
+
+static gceSTATUS
+_FuncValidate_MMU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    if ((hardware->mmuVersion > 0) &&
+        hardware->options.enableMMU &&
+        (hardware->options.secureMode != gcvSECURE_IN_TA))
+    {
+        Execution->valid = gcvTRUE;
+    }
+    else
+    {
+        Execution->valid = gcvFALSE;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_MMU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gctUINT8 i;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    if (Execution->funcCmd)
+    {
+        for (i = 0; i < Execution->funcCmdCount; i++)
+        {
+            if (Execution->funcCmd[i].funcVidMem)
+            {
+                if (Execution->funcCmd[i].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[i].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[0].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[i].funcVidMem
+                            ));
+                Execution->funcCmd[i].funcVidMem = gcvNULL;
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ProgramMMUStates(
+    IN gckHARDWARE Hardware,
+    IN gckMMU Mmu,
+    IN gceMMU_MODE Mode,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 config, address;
+    gctUINT32 extMtlb, extSafeAddress, configEx = 0;
+    gctPHYS_ADDR_T physical;
+    gctUINT32_PTR buffer;
+    gctBOOL ace;
+    gctUINT32 reserveBytes = 0;
+
+    gctBOOL config2D;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Hardware->mmuVersion != 0);
+
+    ace = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ACE);
+
+    switch (Hardware->options.secureMode)
+    {
+    case gcvSECURE_IN_NORMAL:
+        reserveBytes = 8 + 4 * 4;
+        break;
+    case gcvSECURE_NONE:
+        reserveBytes = 16 + 4 * 4;
+        if (ace)
+        {
+            reserveBytes += 8;
+        }
+        break;
+    case gcvSECURE_IN_TA:
+    default:
+        gcmkASSERT(gcvFALSE);
+        gcmkPRINT("%s(%d): secureMode is wrong", __FUNCTION__, __LINE__);
+        break;
+    }
+
+    config2D =  gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D)
+             && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_2D);
+
+    if (config2D)
+    {
+        reserveBytes +=
+            /* Pipe Select. */
+            4 * 4
+            /* Configure MMU States. */
+          + 4 * 4
+            /* Semaphore stall */
+          + 4 * 8;
+
+        if (ace)
+        {
+            reserveBytes += 8;
+        }
+    }
+
+    reserveBytes += 8;
+
+    physical = Mmu->mtlbPhysical;
+
+    config  = (gctUINT32)(physical & 0xFFFFFFFF);
+    extMtlb = (gctUINT32)(physical >> 32);
+
+    /* more than 40bit physical address */
+    if (extMtlb & 0xFFFFFF00)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    physical = Mmu->safePagePhysical;
+
+    address = (gctUINT32)(physical & 0xFFFFFFFF);
+    extSafeAddress = (gctUINT32)(physical >> 32);
+
+    if (address & 0x3F)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+    }
+
+    /* more than 40bit physical address */
+    if (extSafeAddress & 0xFFFFFF00)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (ace)
+    {
+        configEx = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (extSafeAddress) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+                 | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (extMtlb) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)));
+    }
+
+    switch (Mode)
+    {
+    case gcvMMU_MODE_1K:
+        if (config & 0x3FF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    case gcvMMU_MODE_4K:
+        if (config & 0xFFF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (Logical != gcvNULL)
+    {
+        buffer = (gctUINT32_PTR)Logical;
+
+        if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+        {
+            gcsMMU_TABLE_ARRAY_ENTRY * entry;
+            entry = (gcsMMU_TABLE_ARRAY_ENTRY *) Hardware->pagetableArray.logical;
+
+            /* Setup page table array entry. */
+            if (Hardware->bigEndian)
+            {
+                entry->low = gcmBSWAP32(config);
+                entry->high = gcmBSWAP32(extMtlb);
+            }
+            else
+            {
+                entry->low = config;
+                entry->high = extMtlb;
+            }
+
+            gcmkDUMP(Mmu->os, "#[mmu: page table array]");
+
+            gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                     (unsigned long long)Hardware->pagetableArray.address, entry->low, 4);
+
+            gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                     (unsigned long long)Hardware->pagetableArray.address + 4, entry->high, 4);
+
+            gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+                Hardware->kernel,
+                Hardware->pagetableArray.videoMem,
+                0,
+                entry,
+                8
+                ));
+
+            /* Setup command buffer to load index 0 of page table array. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++
+                = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))));
+        }
+        else
+        {
+            gcmkASSERT(Hardware->options.secureMode == gcvSECURE_NONE);
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = config;
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = address;
+
+            if (ace)
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *buffer++
+                    = configEx;
+            }
+        }
+
+        *buffer++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E12) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+
+        do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+
+        if (config2D)
+        {
+            /* LoadState(AQPipeSelect, 1), pipe. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = 0x1;
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = config;
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = address;
+
+            if (ace)
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *buffer++
+                    = configEx;
+            }
+
+            do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+
+            /* LoadState(AQPipeSelect, 1), pipe. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = 0x0;
+
+            do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+        }
+
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        *Bytes = reserveBytes;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_NO();
+    return status;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_ProgramMMUStatesMCFE(
+    IN gckHARDWARE Hardware,
+    IN gckMMU Mmu,
+    IN gceMMU_MODE Mode,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 config, address;
+    gctUINT32 extMtlb, extSafeAddress, configEx = 0;
+    gctPHYS_ADDR_T physical;
+    gctUINT32_PTR buffer;
+    gctBOOL ace;
+    gctUINT32 reserveBytes = 0;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Hardware->mmuVersion != 0);
+
+    ace = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ACE);
+
+    switch (Hardware->options.secureMode)
+    {
+    case gcvSECURE_IN_NORMAL:
+        reserveBytes = 8;
+        reserveBytes += 8;
+        break;
+    case gcvSECURE_NONE:
+        reserveBytes = 16;;
+        if (ace)
+        {
+            reserveBytes += 8;
+            reserveBytes += 8;
+        }
+        break;
+    case gcvSECURE_IN_TA:
+    default:
+        gcmkASSERT(gcvFALSE);
+        gcmkPRINT("%s(%d): secureMode is wrong", __FUNCTION__, __LINE__);
+        break;
+    }
+
+    physical = Mmu->mtlbPhysical;
+
+    config  = (gctUINT32)(physical & 0xFFFFFFFF);
+    extMtlb = (gctUINT32)(physical >> 32);
+
+    /* more than 40bit physical address */
+    if (extMtlb & 0xFFFFFF00)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    physical = Mmu->safePagePhysical;
+
+    address = (gctUINT32)(physical & 0xFFFFFFFF);
+    extSafeAddress = (gctUINT32)(physical >> 32);
+
+    if (address & 0x3F)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+    }
+
+    /* more than 40bit physical address */
+    if (extSafeAddress & 0xFFFFFF00)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (ace)
+    {
+        configEx = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (extSafeAddress) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (extMtlb) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)));
+    }
+
+    switch (Mode)
+    {
+    case gcvMMU_MODE_1K:
+        if (config & 0x3FF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    case gcvMMU_MODE_4K:
+        if (config & 0xFFF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (Logical != gcvNULL)
+    {
+        buffer = (gctUINT32_PTR)Logical;
+
+        if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+        {
+            gcsMMU_TABLE_ARRAY_ENTRY * entry;
+            entry = (gcsMMU_TABLE_ARRAY_ENTRY *) Hardware->pagetableArray.logical;
+
+            /* Setup page table array entry. */
+            if (Hardware->bigEndian)
+            {
+                entry->low = gcmBSWAP32(config);
+                entry->high = gcmBSWAP32(extMtlb);
+            }
+            else
+            {
+                entry->low = config;
+                entry->high = extMtlb;
+            }
+
+            gcmkDUMP(Mmu->os, "#[mmu: page table array]");
+
+            gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                     (unsigned long long)Hardware->pagetableArray.address, entry->low, 4);
+
+            gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                     (unsigned long long)Hardware->pagetableArray.address + 4, entry->high, 4);
+
+            gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+                Hardware->kernel,
+                Hardware->pagetableArray.videoMem,
+                0,
+                entry,
+                8
+                ));
+
+            /* Setup command buffer to load index 0 of page table array. */
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++
+                = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))));
+
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+            *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+        }
+        else
+        {
+            gcmkASSERT(Hardware->options.secureMode == gcvSECURE_NONE);
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = config;
+
+            *buffer++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *buffer++ = address;
+
+            if (ace)
+            {
+                *buffer++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+                *buffer++ = configEx;
+
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+                *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+            }
+        }
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        *Bytes = reserveBytes;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_NO();
+    return status;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_FuncInit_MMU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status;
+    gctUINT32 mmuBytes = 0;
+    gctUINT32 tailBytes;
+    gctUINT32 flags = gcvALLOC_FLAG_CONTIGUOUS;
+    gceMMU_MODE mode;
+    gcePOOL pool;
+    gctPHYS_ADDR_T physical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+#if gcdENABLE_MMU_1KMODE
+    mode = gcvMMU_MODE_1K;
+#else
+    mode = gcvMMU_MODE_4K;
+#endif
+
+    flags |= gcvALLOC_FLAG_4GB_ADDR;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    flags |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+#if !gcdCAPTURE_ONLY_MODE
+    pool = gcvPOOL_DEFAULT;
+#else
+    pool = gcvPOOL_VIRTUAL;
+#endif
+
+    Execution->funcCmdCount = 1;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    Execution->funcCmd[0].funcVidMemBytes = 1024;
+    /* Allocate mmu command buffer within 32bit space */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                hardware->kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                flags,
+                &Execution->funcCmd[0].funcVidMemBytes,
+                &pool,
+                &Execution->funcCmd[0].funcVidMem
+                ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        hardware->kernel,
+        Execution->funcCmd[0].funcVidMem,
+        gcvFALSE,
+        gcvFALSE,
+        &Execution->funcCmd[0].logical
+        ));
+
+    /* Get CPU physical address. */
+    gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+        hardware->kernel,
+        Execution->funcCmd[0].funcVidMem,
+        0,
+        &physical
+        ));
+
+    /* Convert to GPU physical address. */
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+        hardware->os,
+        physical,
+        &physical
+        ));
+
+    if (physical & 0xFFFFFFFF00000000ULL)
+    {
+        gcmkFATAL("%s(%d): Command buffer physical address (0x%llx) for MMU setup exceeds 32bits, "
+                  "please rebuild kernel with CONFIG_ZONE_DMA32=y or CONFIG_ZONE_DMA=y or both.",
+                  __FUNCTION__, __LINE__, physical);
+
+        gcmkFATAL("Some Archs, for ARM64, the setting is special:\n"
+                    "kernel version   ZONE_DMA   ZONE_DMA32\n"
+                    "3.7  - 3.14        no          yes\n"
+                    "3.15 - 4.15        yes         no\n"
+                    "4.16 - 5.4.5       no          yes\n"
+                    "5.5.rc1 -          yes         yes\n");
+
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    gcmkSAFECASTPHYSADDRT(Execution->funcCmd[0].address, physical);
+
+    if (hardware->mcFE)
+    {
+        gcmkONERROR(_ProgramMMUStatesMCFE(
+            hardware,
+            hardware->kernel->mmu,
+            mode,
+            Execution->funcCmd[0].logical,
+            &mmuBytes
+            ));
+    }
+    else
+    {
+        gcmkONERROR(_ProgramMMUStates(
+            hardware,
+            hardware->kernel->mmu,
+            mode,
+            Execution->funcCmd[0].logical,
+            &mmuBytes
+            ));
+    }
+
+    Execution->funcCmd[0].endAddress = Execution->funcCmd[0].address + mmuBytes;
+    Execution->funcCmd[0].endLogical = (gctUINT8_PTR)Execution->funcCmd[0].logical + mmuBytes;
+
+    if (hardware->wlFE)
+    {
+        tailBytes = (gctUINT32)(Execution->funcCmd[0].funcVidMemBytes - mmuBytes);
+        gcmkONERROR(gckWLFE_End(
+            hardware, Execution->funcCmd[0].endLogical,
+            Execution->funcCmd[0].endAddress,
+            &tailBytes));
+    }
+    else
+    {
+        tailBytes = 0;
+    }
+
+    Execution->funcCmd[0].bytes = mmuBytes + tailBytes;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        hardware->kernel,
+        Execution->funcCmd[0].funcVidMem,
+        0,
+        Execution->funcCmd[0].logical,
+        Execution->funcCmd[0].bytes
+        ));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    _FuncRelease_MMU(Execution);
+
+    return status;
+}
+
+static gceSTATUS
+_FuncExecute_MMU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 address = 0;
+    gctUINT32 idle;
+    gctUINT32 timer = 0, delay = 1;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gckMMU mmu = hardware->kernel->mmu;
+
+    /* Prepared command sequence contains an END,
+    ** so update lastEnd and store executeCount to END command.
+    */
+    gctUINT32_PTR endLogical = (gctUINT32_PTR)Execution->funcCmd[0].endLogical;
+
+    hardware->lastEnd = Execution->funcCmd[0].endAddress;
+
+    if (hardware->wlFE)
+    {
+        /* Append a executeCount in End command, MCFE does not support such End command. */
+        *(endLogical + 1) = hardware->executeCount + 1;
+    }
+
+    if (hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+    {
+        gctUINT32 extSafeAddress;
+        /* Set up base address of page table array. */
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x0038C,
+            (gctUINT32)(hardware->pagetableArray.address & 0xFFFFFFFF)
+            ));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x00390,
+            (gctUINT32)((hardware->pagetableArray.address >> 32) & 0xFFFFFFFF)
+            ));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x00394,
+            1
+            ));
+
+        address = (gctUINT32)(mmu->safePagePhysical & 0xFFFFFFFF);
+        extSafeAddress = (gctUINT32)(mmu->safePagePhysical >> 32);
+
+        if (address & 0x3F)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        /* more than 40bit physical address */
+        if (extSafeAddress & 0xFFFFFF00)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+        }
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x0039C,
+            address
+            ));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x00398,
+            address
+            ));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x003A0,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)extSafeAddress) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)extSafeAddress) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1))))))) << (0 ?
+ 15:15))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15)))
+            ));
+    }
+
+    gckFUNCTION_Dump(Execution);
+
+    /* Execute prepared command sequence. */
+    if (hardware->mcFE)
+    {
+        gcmkONERROR(gckMCFE_Execute(
+            hardware,
+            gcvFALSE,
+            0,
+            Execution->funcCmd[0].address,
+            Execution->funcCmd[0].bytes
+            ));
+    }
+    else
+    {
+        gcmkONERROR(gckWLFE_Execute(
+            hardware,
+            Execution->funcCmd[0].address,
+            Execution->funcCmd[0].bytes
+            ));
+    }
+
+#if gcdLINK_QUEUE_SIZE
+    {
+        gcuQUEUEDATA data;
+
+        gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+        data.linkData.start    = Execution->funcCmd[0].address;
+        data.linkData.end      = Execution->funcCmd[0].address + Execution->funcCmd[0].bytes;
+        data.linkData.linkLow  = 0;
+        data.linkData.linkHigh = 0;
+
+        gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+    }
+#endif
+
+    /* Wait until MMU configure finishes. */
+    do
+    {
+        gckOS_Delay(hardware->os, delay);
+
+        gcmkONERROR(gckOS_ReadRegisterEx(
+            hardware->os,
+            hardware->core,
+            0x00004,
+            &idle));
+
+        timer += delay;
+        delay *= 2;
+
+#if gcdGPU_TIMEOUT
+        if (timer >= hardware->kernel->timeOut)
+        {
+            gckHARDWARE_DumpGPUState(hardware);
+
+            if (hardware->kernel->command)
+            {
+                gckCOMMAND_DumpExecutingBuffer(hardware->kernel->command);
+            }
+
+            /* Even if hardware is not reset correctly, let software
+            ** continue to avoid software stuck. Software will timeout again
+            ** and try to recover GPU in next timeout.
+            */
+            gcmkONERROR(gcvSTATUS_DEVICE);
+        }
+#endif
+    }
+    while (!(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ));
+
+    gcmkDUMP(hardware->os, "@[register.wait 0x%05X 0x%08X 0x%08X]",
+             0x00004,
+             ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (~0U) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+             idle);
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_FuncValidate_Flush(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    Execution->valid = gcvTRUE;
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_Flush(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gctUINT8 i;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    if (Execution->funcCmd)
+    {
+        for (i = 0; i < Execution->funcCmdCount; i++)
+        {
+            if (Execution->funcCmd[i].funcVidMem)
+            {
+                if (Execution->funcCmd[i].address)
+                {
+                    /* Synchroneous unlock. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[i].funcVidMem,
+                                0,
+                                gcvNULL
+                                ));
+                     Execution->funcCmd[i].address = 0;
+                }
+
+                if (Execution->funcCmd[i].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[i].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[i].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[i].funcVidMem
+                            ));
+
+                Execution->funcCmd[i].funcVidMem = gcvNULL;
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncInit_Flush(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 flushBytes = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 endBytes = 0;
+    gctUINT32 address;
+    gctUINT32 allocFlag = 0;
+    gcePOOL pool;
+    gctUINT8_PTR logical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+#if !gcdCAPTURE_ONLY_MODE
+    pool = gcvPOOL_DEFAULT;
+#else
+    pool = gcvPOOL_VIRTUAL;
+#endif
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+    Execution->funcCmdCount = 1;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    Execution->funcCmd[0].funcVidMemBytes = 1024;
+    /* Allocate video memory node for aux functions. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                hardware->kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag,
+                &Execution->funcCmd[0].funcVidMemBytes,
+                &pool,
+                &Execution->funcCmd[0].funcVidMem
+                ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                &Execution->funcCmd[0].address
+                ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                gcvFALSE,
+                gcvFALSE,
+                &Execution->funcCmd[0].logical
+                ));
+    /*
+    ** All cache flush command sequence.
+    */
+    logical = (gctUINT8_PTR)Execution->funcCmd[0].logical;
+    address = Execution->funcCmd[0].address;
+
+    /* Get the size of the flush command. */
+    gcmkONERROR(gckHARDWARE_Flush(hardware, gcvFLUSH_ALL, gcvNULL, &flushBytes));
+
+    /* Append a flush. */
+    gcmkONERROR(gckHARDWARE_Flush(hardware, gcvFLUSH_ALL, logical, &flushBytes));
+
+    offset += flushBytes;
+    logical += offset;
+    address += offset;
+
+    if (hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(hardware, logical, address, &endBytes));
+    }
+
+    Execution->funcCmd[0].bytes = flushBytes + endBytes;
+    Execution->funcCmd[0].endAddress = Execution->funcCmd[0].address + flushBytes;
+    Execution->funcCmd[0].endLogical = (gctUINT8_PTR)Execution->funcCmd[0].logical + flushBytes;
+
+    return gcvSTATUS_OK;
+OnError:
+    _FuncRelease_Flush(Execution);
+
+    return status;
+}
+
+#if gcdFLOP_RESET
+static gceSTATUS
+_FuncValidate_FlopReset(
+    IN gcsFUNCTION_EXECUTION_PTR Execution
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+#ifndef EMULATOR
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+#endif
+
+#ifdef EMULATOR
+    Execution->valid = gcvFALSE;
+#else
+    Execution->valid = gcvFALSE;
+
+    if (hardware->type == gcvHARDWARE_VIP &&
+        (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_EVIS2_FLOP_RESET_FIX) ||
+        !gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX) ||
+        !gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_ASYNC_CP_RTN_FLOP_RESET_FIX)))
+    {
+        Execution->valid = gcvTRUE;
+    }
+#endif
+
+    return status;
+}
+
+static gceSTATUS
+_FuncInit_FlopReset(
+    IN gcsFUNCTION_EXECUTION_PTR Execution
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT32 index = 0;
+    gctBOOL doPPU = gcvFALSE;
+    gctBOOL doNN = gcvFALSE;
+    gctBOOL doTP = gcvFALSE;
+    gctUINT32 allocFlag = gcvALLOC_FLAG_NONE;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+
+    Execution->funcCmdCount = 0;
+
+#if gcdFLOP_RESET_PPU
+    /* PPU is always there. */
+    doPPU = gcvTRUE;
+    Execution->funcCmdCount++;
+#endif
+
+#if gcdFLOP_RESET_NN
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_NN_ENGINE) && (hardware->identity.customerID == 0x9f))
+    {
+        doNN = gcvTRUE;
+        Execution->funcCmdCount++;
+    }
+#endif
+
+#if gcdFLOP_RESET_TP
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TP_ENGINE) && (hardware->identity.customerID == 0x9f))
+    {
+        doTP = gcvTRUE;
+        Execution->funcCmdCount++;
+    }
+#endif
+
+    if (!Execution->funcCmdCount)
+    {
+        /* Nothing to do. */
+        return gcvSTATUS_OK;
+    }
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(
+        hardware->os,
+        gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+        (gctPOINTER *)&pointer
+        ));
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    gcmkONERROR(gckOS_ZeroMemory(
+        (gctPOINTER)pointer,
+        gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount
+        ));
+
+    pool = gcvPOOL_DEFAULT;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+    if (doPPU)
+    {
+        gcmkONERROR(gckHARDWARE_ResetFlopWithPPU(
+            hardware,
+            allocFlag,
+            &pool,
+            &Execution->funcCmd[index++]
+            ));
+    }
+
+    if (doNN)
+    {
+        gcmkONERROR(gckHARDWARE_ResetFlopWithNN(
+            hardware,
+            allocFlag,
+            &pool,
+            &Execution->funcCmd[index++]
+            ));
+    }
+
+    if (doTP)
+    {
+        gcmkONERROR(gckHARDWARE_ResetFlopWithTP(
+            hardware,
+            allocFlag,
+            &pool,
+            &Execution->funcCmd[index++]
+            ));
+    }
+
+    gcmkASSERT(index <= Execution->funcCmdCount);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    _FuncRelease(Execution);
+
+    return status;
+}
+#else
+#if gcdINITIALIZE_PPU
+
+#if gcdINITIALIZE_PPU_C
+#include "gc_hal_kernel_hardware_func_ppu.h"
+#endif
+
+static gceSTATUS
+_FuncValidate_PPU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+#ifdef EMULATOR
+    Execution->valid = gcvFALSE;
+#else
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    Execution->valid = gcvFALSE;
+    if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_EVIS2_FLOP_RESET_FIX))
+    {
+#if gcdINITIALIZE_PPU_C
+        Execution->valid = gcvTRUE;
+#else
+        if (hardware->identity.customerID == 0x21 ||
+            hardware->identity.customerID == 0x25 ||
+            hardware->identity.customerID == 0x86
+            )
+        {
+            Execution->valid = gcvTRUE;
+        }
+#endif
+    }
+#endif
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_PPU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT32 i, j;
+
+    if (Execution->funcCmd)
+    {
+#if gcdINITIALIZE_PPU_C
+
+        gctUINT32 pass = gcvTRUE;
+
+        for (i = 0; i < (64 * 6 / 4); i ++)
+        {
+            if (((gctUINT32_PTR)(Execution->funcCmd[0].data[OUTPUT_PPU_IDX].logical))[i] != 0x02020202)
+            {
+                pass = gcvFALSE;
+                gcmkPRINT("Incorrect Result:[%d] 0x%08x\n", i, ((gctUINT32_PTR)(Execution->funcCmd[0].data[OUTPUT_PPU_IDX].logical))[i]);
+            }
+        }
+        gcmkPRINT("PPU %s!\n", pass?"PASS":"FAIL");
+
+#endif
+
+        for (j = 0; j < Execution->funcCmdCount; j++)
+        {
+            if (Execution->funcCmd[j].data)
+            {
+                for (i = 0; i < 7; i++)
+                {
+                    if (Execution->funcCmd[j].data[i].bufVidMem)
+                    {
+                        if (Execution->funcCmd[j].data[i].logical)
+                        {
+                            gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                );
+                            Execution->funcCmd[j].data[i].logical = gcvNULL;
+                        }
+                        if (Execution->funcCmd[j].data[i].address)
+                        {
+                            gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvNULL
+                                );
+                            Execution->funcCmd[j].data[i].address = 0;
+                        }
+
+                        gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].data[i].bufVidMem
+                            );
+                    }
+                }
+
+                gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[j].data));
+                Execution->funcCmd[j].data = gcvNULL;
+            }
+
+            if (Execution->funcCmd[j].funcVidMem)
+            {
+                if (Execution->funcCmd[j].address)
+                {
+                    /* Synchroneous unlock. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvNULL
+                                ));
+                     Execution->funcCmd[j].address = 0;
+                }
+
+                if (Execution->funcCmd[j].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[j].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].funcVidMem
+                            ));
+
+                Execution->funcCmd[j].funcVidMem = gcvNULL;
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_PatchPPUBuffer(
+    IN gcsFUNCTION_EXECUTION_PTR Execution
+#if gcdINITIALIZE_PPU_C
+,
+    IN gctUINT32 Width,
+    IN gctUINT32 Height,
+    OUT gctUINT32_PTR Bytes,
+    OUT gctUINT32_PTR RegCount
+#endif
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+#if !gcdINITIALIZE_PPU_C
+    gctUINT32_PTR command = (gctUINT32_PTR)Execution->funcCmd[0].logical;
+    gctUINT32 commandPatchOffsets[7] = {0};
+#endif
+    gctUINT32_PTR patchBuffers[7] = {NULL};
+    gctSIZE_T patchBufferSizes[7] = {0};
+    gctUINT32 i;
+    gctUINT32 allocFlag = 0;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT32 patchSize = 7;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+#if gcdINITIALIZE_PPU_C
+    gctUINT32 j = 0;
+    gctUINT32 data_type = 0x7, item_size = 1;
+    patchBuffers[INPUT_PPU_IDX]         = NULL;
+    patchBuffers[OUTPUT_PPU_IDX]     = NULL;
+    patchBuffers[INST_PPU_IDX]         = NULL;
+
+    patchBufferSizes[INPUT_PPU_IDX]     = Width * Height * item_size;
+    patchBufferSizes[OUTPUT_PPU_IDX] = Width * Height * item_size;
+    patchBufferSizes[INST_PPU_IDX]     = 4 * 4 * gcmSIZEOF(gctUINT32);
+
+#else
+    patchBuffers[0] = ppuMem0;
+    patchBuffers[1] = ppuMem1;
+    patchBuffers[2] = ppuMem2;
+    patchBuffers[3] = ppuMem3;
+    patchBuffers[4] = ppuMem4;
+    patchBuffers[5] = ppuMem5;
+    patchBuffers[6] = gcvNULL;
+
+    patchBufferSizes[0] = gcmSIZEOF(ppuMem0);
+    patchBufferSizes[1] = gcmSIZEOF(ppuMem1);
+    patchBufferSizes[2] = gcmSIZEOF(ppuMem2);
+    patchBufferSizes[3] = gcmSIZEOF(ppuMem3);
+    patchBufferSizes[4] = gcmSIZEOF(ppuMem4);
+    patchBufferSizes[5] = gcmSIZEOF(ppuMem5);
+    patchBufferSizes[6] = 1024 * 6;
+
+    commandPatchOffsets[0] = PATCH_OFFSET_0;
+    commandPatchOffsets[1] = PATCH_OFFSET_1;
+    commandPatchOffsets[2] = PATCH_OFFSET_2;
+    commandPatchOffsets[3] = PATCH_OFFSET_3;
+    commandPatchOffsets[4] = PATCH_OFFSET_4;
+    commandPatchOffsets[5] = PATCH_OFFSET_5;
+    commandPatchOffsets[6] = PATCH_OFFSET_6;
+#endif
+
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * patchSize,
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * patchSize);
+
+    Execution->funcCmd[0].data = (gcsFUNCTION_EXECUTION_DATA_PTR)pointer;
+
+    for (i = 0; i < patchSize; i++)
+    {
+#if gcdINITIALIZE_PPU_C
+        if (patchBufferSizes[i] <= 0)
+            continue;
+#endif
+        /* Allocate memory for buffers. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            hardware->kernel,
+            64,
+            gcvVIDMEM_TYPE_BITMAP,
+            allocFlag,
+            &patchBufferSizes[i],
+            &pool,
+            &Execution->funcCmd[0].data[i].bufVidMem
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            gcvFALSE,
+            gcvFALSE,
+            &Execution->funcCmd[0].data[i].logical
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            &Execution->funcCmd[0].data[i].address
+            ));
+
+#if gcdINITIALIZE_PPU_C
+        gckOS_ZeroMemory(Execution->funcCmd[0].data[i].logical, patchBufferSizes[i]);
+
+        if (patchBuffers[i])
+        {
+            gckOS_MemCopy(Execution->funcCmd[0].data[i].logical, patchBuffers[i], patchBufferSizes[i]);
+        }
+        else if (i == INST_PPU_IDX)
+        {
+            gcoHwFunc_SH_CMD(hardware, data_type, (gctUINT32_PTR)Execution->funcCmd[0].data[i].logical, Bytes, RegCount);
+        }
+        else
+        {
+            for (j = 0; j < patchBufferSizes[i]/4; j++)
+                ((gctUINT32_PTR)(Execution->funcCmd[0].data[i].logical))[j] = 0x01010101;
+        }
+#else
+        /* patch the buffer */
+        command[commandPatchOffsets[i]] = Execution->funcCmd[0].data[i].address;
+#endif
+    }
+
+    return status;
+OnError:
+    if (Execution->funcCmd[0].data)
+    {
+        for (i = 0; i < patchSize; i++)
+        {
+            if (Execution->funcCmd[0].data[i].bufVidMem)
+            {
+                if (Execution->funcCmd[0].data[i].logical)
+                {
+                    gckVIDMEM_NODE_UnlockCPU(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvFALSE,
+                        gcvFALSE
+                        );
+                    Execution->funcCmd[0].data[i].logical = gcvNULL;
+                }
+                if (Execution->funcCmd[0].data[i].address)
+                {
+                    gckVIDMEM_NODE_Unlock(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvNULL
+                        );
+                    Execution->funcCmd[0].data[i].address = 0;
+                }
+
+                gckVIDMEM_NODE_Dereference(
+                    hardware->kernel,
+                    Execution->funcCmd[0].data[i].bufVidMem
+                    );
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[0].data));
+        Execution->funcCmd[0].data = gcvNULL;
+    }
+
+    return status;
+}
+
+gceSTATUS
+_InitializePPU(
+    IN gcsFUNCTION_EXECUTION_PTR Execution,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPOINTER logical = Execution->funcCmd[0].logical;
+#if gcdINITIALIZE_PPU_C
+    gctUINT32 width = 64, height = 6, stride = 64;
+    gctUINT32 count = 0, regCount = 0;
+    gcsFEATURE_DATABASE * db = (gcsFEATURE_DATABASE *)((gckHARDWARE)Execution->hardware)->featureDatabase;
+
+    gctINT32 workDim = 0x2, valueOrder = 0x2;
+    gctUINT32 groupsizeX = 1, groupsizeY = 1, groupsizeZ = 0;
+    gctUINT32 globalscaleX = 4, globalscaleY = 1, globalscaleZ = 0;
+    gctUINT32 groupcountX = gcmALIGN_NP2(width, globalscaleX)/globalscaleX, groupcountY = gcmALIGN_NP2(height, globalscaleY)/globalscaleY, groupcountZ = 0;
+    gctUINT32 globaloffsetX = 0, globaloffsetY = 0, globaloffsetZ = 0;
+    gctUINT32 threadAllocation = gcmALIGN_NP2(groupsizeX * groupsizeY, db->NumShaderCores * 4)/db->NumShaderCores * 4;
+
+    /* Patch the command. */
+    if (logical)
+    {
+        status = _PatchPPUBuffer(Execution, width, height, &count, &regCount);
+    }
+
+    if (count > 0 && regCount > 0)
+    {
+#endif
+#if gcdINITIALIZE_PPU_C
+    gctUINT32 flushCommands[] = {
+#else
+    static gctUINT32 flushCommands[] = {
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000011,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E13) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+#else
+        0x00000002,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5580) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))),
+#else
+        0x00000002,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+#else
+        0x00000701,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+#else
+        0x00000701,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        Execution->funcCmd[0].data[0].address, stride, (height << 16 | width),
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1))))))) << (0 ?
+ 5:4))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1))))))) << (0 ?
+ 9:6))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:6) - (0 ? 9:6) + 1))))))) << (0 ? 9:6)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1))))))) << (0 ?
+ 11:10))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:10) - (0 ? 11:10) + 1))))))) << (0 ? 11:10)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x1) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1))))))) << (0 ?
+ 18:16))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:16) - (0 ? 18:16) + 1))))))) << (0 ? 18:16)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1))))))) << (0 ?
+ 22:20))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:20) - (0 ? 22:20) + 1))))))) << (0 ? 22:20)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28))),
+#else
+        0xD8000340, 0x00000080, 0x00800080, 0x444051F0,
+#endif
+        0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+#if gcdINITIALIZE_PPU_C
+
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x04) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        Execution->funcCmd[0].data[1].address, stride, (height << 16 | width),
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1))))))) << (0 ?
+ 5:4))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1))))))) << (0 ?
+ 9:6))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:6) - (0 ? 9:6) + 1))))))) << (0 ? 9:6)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1))))))) << (0 ?
+ 11:10))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:10) - (0 ? 11:10) + 1))))))) << (0 ? 11:10)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x1) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1))))))) << (0 ?
+ 18:16))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:16) - (0 ? 18:16) + 1))))))) << (0 ? 18:16)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1))))))) << (0 ?
+ 22:20))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:20) - (0 ? 22:20) + 1))))))) << (0 ? 22:20)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)))
+              | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28))),
+#else
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x08) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xD8004380, 0x00000040, 0x00400040, 0x444051F0,
+#endif
+        0xFFFFFFFF,
+
+#if gcdINITIALIZE_PPU_C
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x08) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x55555555, 0x00000000, // TCfg
+        0x01234567, 0x89abcdef, 0x55555555, 0x01234567, 0x89abcdef, // BinSelect
+        0x00000000, // AccumType, ConstantType, and PostShift
+        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // Constant
+        0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (workDim) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (valueOrder) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24))),
+#else
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x10) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xD80053C0, 0x00000040, 0x00400040, 0x444051F0, 0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x18) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xD8000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x19) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xD8000040,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x1C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xD8006400, 0x00000080, 0x00400040, 0x44405071, 0x00000003, 0x00002000, 0x00000000, 0x00000000, 0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x24) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x11111111, 0x00000000, 0x03020100, 0x07060504, 0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x28) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x22222222, 0x00000000, 0x00000000, 0x00000400, 0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x2C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000001, 0x00000001, 0x00000001, 0x00000001, 0xFFFFFFFF,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x30) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000001, 0x00000001, 0x00000001, 0x00000001, 0xFFFFFFFF,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))),
+#else
+        0x0000001F,
+#endif
+
+#if !gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x02A4) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+#endif
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0420) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))),
+#else
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0420) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0403) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        regCount,
+#else
+        0x00000005,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0416) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0409) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0424) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        count/4,
+#else
+        0x0000000F,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        Execution->funcCmd[0].data[2].address,
+#else
+        0xD8000100,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5580) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0x1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))),
+#else
+        0x00000002,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+#else
+        0x00000001,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0425) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        count/4 - 1,
+#else
+        0x0000000E,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0402) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+#if gcdINITIALIZE_PPU_C
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) ((gctUINT32) (~0) & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+#else
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00001F01, 0x00000005, 0x00000F00,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0228) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x02AA) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+#if !gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000100,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E07) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+#if !gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x0F3F0000,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0201) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0))),
+#else
+        0x00000001,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E22) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0412) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0x2) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24))),
+#else
+        0x03000002,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0249) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0247) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        threadAllocation,
+#else
+        0x00000001,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globaloffsetX,
+#else
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globaloffsetY,
+#else
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globaloffsetZ,
+#else
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0256) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globalscaleX,
+#else
+        0x00000008,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0257) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globalscaleY,
+#else
+        0x00000001,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0258) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        globalscaleZ,
+#else
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0250) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        groupcountX - 1, groupcountY - 1, groupcountZ - 1,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (groupsizeX - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (groupsizeY - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0))),
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (groupsizeZ - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0))),
+#else
+        0x00000000, 0x0000003F, 0xFFFFFFFF, 0x00000007, 0x00000000, 0x000003FF,
+#endif
+        0x00000000,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0248) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+        0xBADABEEB,
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))),
+#else
+        0x00000C20,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+#else
+        0x00000701,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+#else
+        0x00000701,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))),
+#else
+        0x00000C23,
+#endif
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))),
+#else
+        0x00000C23,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))),
+#else
+        0x00000001,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11))),
+#else
+        0x00000C23,
+#endif
+
+#if !gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E13) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))),
+#if gcdINITIALIZE_PPU_C
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+#else
+        0x00000000,
+#endif
+
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+        0x00000000,
+#endif
+    };
+#if gcdINITIALIZE_PPU_C
+
+
+        *Bytes = gcmSIZEOF(flushCommands);
+
+        gckOS_MemCopy(logical, flushCommands, *Bytes);
+    }
+#else
+    *Bytes = gcmSIZEOF(flushCommands) - 8;
+    /* Patch the command. */
+    if (logical)
+    {
+        gckOS_MemCopy(logical, flushCommands, *Bytes);
+        status = _PatchPPUBuffer(Execution);
+    }
+#endif
+    return status;
+}
+
+static gceSTATUS
+_FuncInit_PPU(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 ppuBytes = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 endBytes = 0;
+    gctUINT32 address;
+    gctUINT32 allocFlag = 0;
+    gcePOOL pool;
+    gctUINT8_PTR logical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+    pool = gcvPOOL_DEFAULT;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+    Execution->funcCmdCount = 1;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    Execution->funcCmd[0].funcVidMemBytes = 1024;
+    /* Allocate video memory node for aux functions. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                hardware->kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag,
+                &Execution->funcCmd[0].funcVidMemBytes,
+                &pool,
+                &Execution->funcCmd[0].funcVidMem
+                ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                &Execution->funcCmd[0].address
+                ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                gcvFALSE,
+                gcvFALSE,
+                &Execution->funcCmd[0].logical
+                ));
+    /*
+    ** All cache flush command sequence.
+    */
+    logical = (gctUINT8_PTR)Execution->funcCmd[0].logical;
+    address = Execution->funcCmd[0].address;
+    /* Append a flush. */
+    gcmkONERROR(_InitializePPU(Execution, &ppuBytes));
+
+    offset += ppuBytes;
+    logical += offset;
+    address += offset;
+
+    if (hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(hardware, logical, address, &endBytes));
+    }
+
+    Execution->funcCmd[0].bytes = ppuBytes + endBytes;
+    Execution->funcCmd[0].endAddress = Execution->funcCmd[0].address + ppuBytes;
+    Execution->funcCmd[0].endLogical = (gctUINT8_PTR)Execution->funcCmd[0].logical + ppuBytes;
+
+    return gcvSTATUS_OK;
+OnError:
+    _FuncRelease_PPU(Execution);
+
+    return status;
+}
+
+static gceSTATUS
+_FuncValidate_PPU_0xA0(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+#ifdef EMULATOR
+    Execution->valid = gcvFALSE;
+#else
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    Execution->valid = gcvFALSE;
+    if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_EVIS2_FLOP_RESET_FIX))
+    {
+        if (hardware->identity.customerID == 0xA0)
+        {
+            Execution->valid = gcvTRUE;
+        }
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_PPU_0xA0(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT32 i, j;
+
+    if (Execution->funcCmd)
+    {
+        for (j = 0; j < Execution->funcCmdCount; j++)
+        {
+            if (Execution->funcCmd[j].data)
+            {
+                for (i = 0; i < 7; i++)
+                {
+                    if (Execution->funcCmd[j].data[i].bufVidMem)
+                    {
+                        if (Execution->funcCmd[j].data[i].logical)
+                        {
+                            gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                );
+                            Execution->funcCmd[j].data[i].logical = gcvNULL;
+                        }
+                        if (Execution->funcCmd[j].data[i].address)
+                        {
+                            gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvNULL
+                                );
+                            Execution->funcCmd[j].data[i].address = 0;
+                        }
+
+                        gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].data[i].bufVidMem
+                            );
+                    }
+                }
+
+                gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[j].data));
+                Execution->funcCmd[j].data = gcvNULL;
+            }
+
+            if (Execution->funcCmd[j].funcVidMem)
+            {
+                if (Execution->funcCmd[j].address)
+                {
+                    /* Synchroneous unlock. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvNULL
+                                ));
+                     Execution->funcCmd[j].address = 0;
+                }
+
+                if (Execution->funcCmd[j].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[j].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].funcVidMem
+                            ));
+
+                Execution->funcCmd[j].funcVidMem = gcvNULL;
+            }
+        }
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_PatchPPUBuffer_0xA0(
+    IN gctPOINTER Hardware,
+    IN gcsFUNCTION_COMMAND *funcCmd
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gctUINT32_PTR command = (gctUINT32_PTR)funcCmd->logical;
+    gctUINT32 commandPatchOffsets[7];
+    gctUINT32_PTR patchBuffers[7];
+    gctSIZE_T patchBufferSizes[7];
+    gctUINT32 i;
+    gctUINT32 allocFlag = 0;
+    gckHARDWARE hardware = (gckHARDWARE)Hardware;
+    gctPOINTER pointer = gcvNULL;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+    patchBuffers[0] = gcvNULL;
+    patchBuffers[1] = ppuMem0_0xA0;
+    patchBuffers[2] = gcvNULL;
+    patchBuffers[3] = ppuMem1_0xA0;
+    patchBuffers[4] = ppuMem2_0xA0;
+    patchBuffers[5] = gcvNULL;
+    patchBuffers[6] = ppuMem3_0xA0;
+
+    patchBufferSizes[0] = 32*1024;
+    patchBufferSizes[1] = gcmSIZEOF(ppuMem0_0xA0);;
+    patchBufferSizes[2] = 32*1024;
+    patchBufferSizes[3] = gcmSIZEOF(ppuMem1_0xA0);
+    patchBufferSizes[4] = gcmSIZEOF(ppuMem2_0xA0);
+    patchBufferSizes[5] = 32*1024;
+    patchBufferSizes[6] = gcmSIZEOF(ppuMem3_0xA0);
+
+    commandPatchOffsets[0] = 7;
+    commandPatchOffsets[1] = 19;
+    commandPatchOffsets[2] = 31;
+    commandPatchOffsets[3] = 43;
+    commandPatchOffsets[4] = 45;
+    commandPatchOffsets[5] = 47;
+    commandPatchOffsets[6] = 97;
+
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 7,
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 7);
+
+    funcCmd->data = (gcsFUNCTION_EXECUTION_DATA_PTR)pointer;
+
+    for (i = 0; i < 7; i++)
+    {
+        /* Allocate memory for buffers. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            hardware->kernel,
+            64,
+            gcvVIDMEM_TYPE_BITMAP,
+            allocFlag,
+            &patchBufferSizes[i],
+            &pool,
+            &funcCmd->data[i].bufVidMem
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            hardware->kernel,
+            funcCmd->data[i].bufVidMem,
+            gcvFALSE,
+            gcvFALSE,
+            &funcCmd->data[i].logical
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+            hardware->kernel,
+            funcCmd->data[i].bufVidMem,
+            &funcCmd->data[i].address
+            ));
+
+        gckOS_ZeroMemory(funcCmd->data[i].logical, patchBufferSizes[i]);
+
+        if (patchBuffers[i])
+        {
+            gckOS_MemCopy(funcCmd->data[i].logical, patchBuffers[i], patchBufferSizes[i]);
+        }
+        /* patch the buffer */
+        command[commandPatchOffsets[i]] = funcCmd->data[i].address;
+    }
+
+    return status;
+OnError:
+    if (funcCmd->data)
+    {
+        for (i = 0; i < 7; i++)
+        {
+            if (funcCmd->data[i].bufVidMem)
+            {
+                if (funcCmd->data[i].logical)
+                {
+                    gckVIDMEM_NODE_UnlockCPU(
+                        hardware->kernel,
+                        funcCmd->data[i].bufVidMem,
+                        0,
+                        gcvFALSE,
+                        gcvFALSE
+                        );
+                    funcCmd->data[i].logical = gcvNULL;
+                }
+                if (funcCmd->data[i].address)
+                {
+                    gckVIDMEM_NODE_Unlock(
+                        hardware->kernel,
+                        funcCmd->data[i].bufVidMem,
+                        0,
+                        gcvNULL
+                        );
+                    funcCmd->data[i].address = 0;
+                }
+
+                gckVIDMEM_NODE_Dereference(
+                    hardware->kernel,
+                    funcCmd->data[i].bufVidMem
+                    );
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, funcCmd->data));
+        funcCmd->data = gcvNULL;
+    }
+
+    return status;
+}
+
+gceSTATUS
+_InitializePPU_0xA0(
+    IN gcsFUNCTION_EXECUTION_PTR Execution,
+    IN gctUINT32 Index,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPOINTER logical = Execution->funcCmd[Index].logical;
+
+    switch(Index)
+    {
+    case 0:
+        *Bytes = gcmSIZEOF(ppuCmd0_0xA0);
+        if (logical)
+        {
+            gckOS_MemCopy(logical, ppuCmd0_0xA0, *Bytes);
+        }
+        break;
+    case 1:
+        *Bytes = gcmSIZEOF(ppuCmd1_0xA0);
+        if (logical)
+        {
+            gckOS_MemCopy(logical, ppuCmd1_0xA0, *Bytes);
+        }
+        break;
+    case 2:
+        *Bytes = gcmSIZEOF(ppuCmd2_0xA0);
+        if (logical)
+        {
+            gckOS_MemCopy(logical, ppuCmd2_0xA0, *Bytes);
+            status = _PatchPPUBuffer_0xA0(Execution->hardware, &Execution->funcCmd[2]);
+        }
+        break;
+    case 3:
+        *Bytes = gcmSIZEOF(ppuCmd3_0xA0);
+        if (logical)
+        {
+            gckOS_MemCopy(logical, ppuCmd3_0xA0, *Bytes);
+        }
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+        break;
+    }
+
+    *Bytes = *Bytes - 8;
+    return status;
+}
+
+static gceSTATUS
+_FuncInit_PPU_0xA0(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 ppuBytes = 0;
+    gctUINT32 endBytes = 0;
+    gctUINT32 address;
+    gctUINT32 i, allocFlag = 0;
+    gcePOOL pool;
+    gctUINT8_PTR logical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+    pool = gcvPOOL_DEFAULT;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+    Execution->funcCmdCount = 4;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    for (i = 0; i < Execution->funcCmdCount; i++)
+    {
+        Execution->funcCmd[i].funcVidMemBytes = 1024;
+        /* Allocate video memory node for aux functions. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                    hardware->kernel,
+                    64,
+                    gcvVIDMEM_TYPE_COMMAND,
+                    allocFlag,
+                    &Execution->funcCmd[i].funcVidMemBytes,
+                    &pool,
+                    &Execution->funcCmd[i].funcVidMem
+                    ));
+
+        /* Lock for GPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+                    hardware->kernel,
+                    Execution->funcCmd[i].funcVidMem,
+                    &Execution->funcCmd[i].address
+                    ));
+
+        /* Lock for kernel side CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                    hardware->kernel,
+                    Execution->funcCmd[i].funcVidMem,
+                    gcvFALSE,
+                    gcvFALSE,
+                    &Execution->funcCmd[i].logical
+                    ));
+        /*
+        ** All cache flush command sequence.
+        */
+        logical = (gctUINT8_PTR)Execution->funcCmd[i].logical;
+        address = Execution->funcCmd[i].address;
+
+        /* Append a flush. */
+        gcmkONERROR(_InitializePPU_0xA0(Execution, i, &ppuBytes));
+
+        logical += ppuBytes;
+        address += ppuBytes;
+
+        if (hardware->wlFE)
+        {
+            gcmkONERROR(gckWLFE_End(hardware, gcvNULL, ~0U, &endBytes));
+            gcmkONERROR(gckWLFE_End(hardware, logical, address, &endBytes));
+        }
+
+        Execution->funcCmd[i].bytes = ppuBytes + endBytes;
+        Execution->funcCmd[i].endAddress = Execution->funcCmd[i].address + ppuBytes;
+        Execution->funcCmd[i].endLogical = (gctUINT8_PTR)Execution->funcCmd[i].logical + ppuBytes;
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    _FuncRelease_PPU_0xA0(Execution);
+
+    return status;
+}
+
+#endif
+
+#if gcdRESET_USC1
+gceSTATUS
+_InitializeUSC(
+    IN gcsFUNCTION_EXECUTION_PTR Execution,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32 i;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gctUINT32_PTR flushCommands = gcvNULL;
+    gctUINT32_PTR nnCommands = gcvNULL;
+    gctSIZE_T patchBufferSizes[5];
+    gceSTATUS status = gcvSTATUS_OK;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT8_PTR logical = (gctUINT8_PTR)Execution->funcCmd[0].logical;
+    gctPOINTER pointer = gcvNULL;
+
+#if gcdRESET_USC_C
+    gcsFEATURE_DATABASE * db = (gcsFEATURE_DATABASE *)(hardware->featureDatabase);
+    gctUINT32 sram_size = db->AXI_SRAM_SIZE + db->VIP_SRAM_SIZE;
+    USC_NN_TYPE hw_type = (db->NN_XYDP0) ? USC_NN_TYPE_V8 :
+        (
+        (db->VIP_V7)?USC_NN_TYPE_V7:USC_NN_TYPE_V6
+        );
+
+    gctUINT32 item_size = 2, core_count = 0;
+    gctUINT8 data_type = 0;
+    gctUINT32 filterSize = 0, biasSize = 4, filterTotalCount = 1, zdp = (db->NN_ZDP3)?3:1, size = 64;
+
+    gcmkONERROR(_InitializeUSC_NNCommands(hardware, hw_type, 0, 0, 0, &data_type, &item_size, &core_count, &patchBufferSizes[NN_BUFFER_IDX], &nnCommands));
+
+    filterSize = 2 * 2 * 1 * item_size;
+    size = gcmALIGN_NP2(((filterSize + biasSize +  3) * filterTotalCount + 3), 64);
+
+    patchBufferSizes[INPUT_BUFFER_IDX] = gcmALIGN_NP2(3 * 2 * item_size, 64);
+    patchBufferSizes[RESULT_BUFFER_IDX] = gcmALIGN_NP2(2 * 1 * item_size, 64);
+
+    /*v8*/
+    if (hw_type == USC_NN_TYPE_V8)
+        /*head(align to 64) + body(align to 64) + tail(align to 64)*/
+        patchBufferSizes[KERNEL_BUFFER_IDX] = 64 + gcmALIGN_NP2((gcmALIGN_NP2(filterSize, zdp * 3) * (zdp * 3) * filterTotalCount) + (1 * (16 / item_size)), 64) + 64;
+    else
+        /*head(align to 64) + body(align to 64)*/
+        patchBufferSizes[KERNEL_BUFFER_IDX] = size + 64;
+
+    patchBufferSizes[SRAM_BUFFER_IDX_C] = (sram_size > 0) ? sram_size : (128 * 1024);
+
+#else
+    gctUINT32 idx = 0;
+
+    if (hardware->identity.customerID == 0x86)
+    {
+        patchBufferSizes[NN_BUFFER_IDX] = gcmSIZEOF(nnBuffer0);
+        nnCommands = nnBuffer0;
+    }
+    else if (hardware->identity.customerID == 0x25)
+    {
+        patchBufferSizes[NN_BUFFER_IDX] = gcmSIZEOF(nnBuffer1);
+        nnCommands = nnBuffer1;
+    }
+    else if (hardware->identity.customerID == 0x21)
+    {
+        patchBufferSizes[NN_BUFFER_IDX] = gcmSIZEOF(nnBuffer2);
+        nnCommands = nnBuffer2;
+    }
+    else if (hardware->identity.customerID == 0xA0)
+    {
+        patchBufferSizes[NN_BUFFER_IDX] = gcmSIZEOF(nnBuffer3);
+        nnCommands = nnBuffer3;
+    }
+    else
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    patchBufferSizes[INPUT_BUFFER_IDX] =
+    patchBufferSizes[KERNEL_BUFFER_IDX] =
+    patchBufferSizes[RESULT_BUFFER_IDX] = 512 * 1024;
+    patchBufferSizes[SRAM_BUFFER_IDX_C] = 0;
+#endif
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               160 * gcmSIZEOF(gctUINT32),
+                               (gctPOINTER *)&flushCommands));
+
+    gckOS_ZeroMemory((gctPOINTER)flushCommands, 160 * gcmSIZEOF(gctUINT32));
+
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 5,
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 5);
+
+    Execution->funcCmd[0].data = (gcsFUNCTION_EXECUTION_DATA_PTR)pointer;
+
+    for (i = 0; i < 5; i++)
+    {
+        if (patchBufferSizes[i] == 0)
+        {
+            continue;
+        }
+        /* Allocate memory for buffers. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            hardware->kernel,
+            64,
+            gcvVIDMEM_TYPE_COMMAND,
+            gcvALLOC_FLAG_NONE,
+            &patchBufferSizes[i],
+            &pool,
+            &Execution->funcCmd[0].data[i].bufVidMem
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            gcvFALSE,
+            gcvFALSE,
+            &Execution->funcCmd[0].data[i].logical
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            &Execution->funcCmd[0].data[i].address
+            ));
+
+        gcmkONERROR(gckOS_ZeroMemory(Execution->funcCmd[0].data[i].logical, patchBufferSizes[i]));
+    }
+#if gcdRESET_USC_C
+    if(Execution->funcCmd[0].data[KERNEL_BUFFER_IDX].logical)
+    {
+        _InitializeUSC_NNKernel(hardware, hw_type, data_type, item_size, core_count, (gctUINT32_PTR)Execution->funcCmd[0].data[KERNEL_BUFFER_IDX].logical);
+
+#if gcdDUMP_IN_KERNEL
+        gcmkDUMP(hardware->os, "#[reset usc: nn kernel]");
+        gcmkDUMP_BUFFER(
+            hardware->os,
+            gcvDUMP_BUFFER_KERNEL_COMMAND,
+            Execution->funcCmd[0].data[KERNEL_BUFFER_IDX].logical,
+            Execution->funcCmd[0].data[KERNEL_BUFFER_IDX].address,
+            patchBufferSizes[KERNEL_BUFFER_IDX]
+            );
+#endif
+    }
+
+    if (Execution->funcCmd[0].data[INPUT_BUFFER_IDX].logical)
+    {
+        gctUINT32 i = 0, offset = 0;
+                          /*uint8, fp16, int8, uint16, int16, uint4, int4, bf16*/
+        gctUINT32 value[] = {1, 0x3c00, 1, 1, 1, 1, 1, 0x3f80};
+
+        if (hw_type == USC_NN_TYPE_V8)
+            value[0x4] = 0x81;
+
+        for (i = 0; i < (3 * 2); i ++)
+            _BitValue((gctUINT8_PTR*)&(Execution->funcCmd[0].data[INPUT_BUFFER_IDX].logical), value[data_type], &offset, item_size * 8);
+
+#if gcdDUMP_IN_KERNEL
+        gcmkDUMP(hardware->os, "#[reset usc: nn input]");
+        gcmkDUMP_BUFFER(
+            hardware->os,
+            gcvDUMP_BUFFER_KERNEL_COMMAND,
+            Execution->funcCmd[0].data[INPUT_BUFFER_IDX].logical,
+            Execution->funcCmd[0].data[INPUT_BUFFER_IDX].address,
+            patchBufferSizes[INPUT_BUFFER_IDX]
+            );
+#endif
+    }
+
+#endif
+
+    /* Patch NN command */
+    nnCommands[PATCH_KERNEL_OFFSET] = Execution->funcCmd[0].data[KERNEL_BUFFER_IDX].address >> 6;
+    nnCommands[PATCH_INPUT_OFFSET] = Execution->funcCmd[0].data[INPUT_BUFFER_IDX].address;
+    nnCommands[PATCH_RESULT_OFFSET] = Execution->funcCmd[0].data[RESULT_BUFFER_IDX].address;
+
+    gckOS_MemCopy(Execution->funcCmd[0].data[NN_BUFFER_IDX].logical, nnCommands, patchBufferSizes[NN_BUFFER_IDX]);
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(hardware->os, "#[reset usc: nn instruction]");
+    gcmkDUMP_BUFFER(
+        hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        Execution->funcCmd[0].data[NN_BUFFER_IDX].logical,
+        Execution->funcCmd[0].data[NN_BUFFER_IDX].address,
+        patchBufferSizes[NN_BUFFER_IDX]
+        );
+#endif
+
+#if gcdRESET_USC_C
+    _InitializeUSC_NNCmdBuffer(
+        hardware,
+        hw_type,
+        flushCommands,
+        Execution->funcCmd[0].data[NN_BUFFER_IDX].address,
+        Execution->funcCmd[0].data[SRAM_BUFFER_IDX_C].address,
+        Bytes);
+#else
+    /* construct command */
+    if (hardware->identity.customerID == 0x21)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000000;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000040;
+    }
+    else if (hardware->identity.customerID == 0xA0)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0xf0800000;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000000;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E50) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000000;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000040;
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0529) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0xfffffe7f;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0500) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x04011311;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0501) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0502) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x3f800000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0503) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x4b7fffff;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0504) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    if (hardware->identity.customerID == 0x21)
+    {
+        flushCommands[idx++] = 0x000a0000;
+    }
+    else
+    {
+        flushCommands[idx++] = 0x00000000;
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0520) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    if (hardware->identity.customerID == 0x21)
+    {
+        flushCommands[idx++] = 0x000a0000;
+    }
+    else
+    {
+        flushCommands[idx++] = 0x00000000;
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0505) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000500;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0506) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00070007;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x050B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x05102f0a;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E06) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x050C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0518) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x050D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000500;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0300) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0301) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0302) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x43a00000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0303) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x43700000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0308) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x43a07800;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0309) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x4370f000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0595) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00400000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0380) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000004;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0515) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0516) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0518) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0520) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    if (hardware->identity.customerID == 0x21)
+    {
+        flushCommands[idx++] = 0x000a0000;
+    }
+    else
+    {
+        flushCommands[idx++] = 0x00000000;
+    }
+
+    if (hardware->identity.customerID == 0x86)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x0000008c;
+    }
+    else if (hardware->identity.customerID == 0xA0)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0x00000008;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0xf0800000;
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0428) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = Execution->funcCmd[0].data[NN_BUFFER_IDX].address;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000040;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    flushCommands[idx++] = 0x00000000;
+
+    *Bytes = idx * 4 - 8;
+#endif
+    /* Copy command to command buffer */
+    gckOS_MemCopy(logical, flushCommands, *Bytes);
+
+    if (flushCommands)
+    {
+        gckOS_Free(hardware->os, flushCommands);
+        flushCommands = gcvNULL;
+    }
+    return status;
+
+OnError:
+    if (flushCommands)
+    {
+        gckOS_Free(hardware->os, flushCommands);
+        flushCommands = gcvNULL;
+    }
+
+    if (Execution->funcCmd[0].data)
+    {
+        for (i = 0; i < 5; i++)
+        {
+            if (Execution->funcCmd[0].data[i].bufVidMem)
+            {
+                if (Execution->funcCmd[0].data[i].logical)
+                {
+                    gckVIDMEM_NODE_UnlockCPU(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvFALSE,
+                        gcvFALSE
+                        );
+                    Execution->funcCmd[0].data[i].logical = gcvNULL;
+                }
+                if (Execution->funcCmd[0].data[i].address)
+                {
+                    gckVIDMEM_NODE_Unlock(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvNULL
+                        );
+                    Execution->funcCmd[0].data[i].address = 0;
+                }
+
+                gckVIDMEM_NODE_Dereference(
+                    hardware->kernel,
+                    Execution->funcCmd[0].data[i].bufVidMem
+                    );
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[0].data));
+        Execution->funcCmd[0].data = gcvNULL;
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_FuncValidate_USC(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+#ifdef EMULATOR
+    Execution->valid = gcvFALSE;
+#else
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    Execution->valid = gcvFALSE;
+    if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_ASYNC_CP_RTN_FLOP_RESET_FIX))
+    {
+#if gcdRESET_USC_C
+        Execution->valid = gcvTRUE;
+#else
+        if (hardware->identity.customerID == 0x21 ||
+            hardware->identity.customerID == 0x25 ||
+            hardware->identity.customerID == 0x86 ||
+            hardware->identity.customerID == 0xA0
+            )
+        {
+            Execution->valid = gcvTRUE;
+        }
+#endif
+    }
+#endif
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_USC(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT32 i = 0, j = 0;
+
+    if (Execution->funcCmd)
+    {
+#if gcdRESET_USC_C
+        if (Execution->funcCmd[0].data)
+        {
+            if (*((gctUINT32_PTR)(Execution->funcCmd[0].data[3].logical)) == 0x00000404    /*INT8*/
+                || *((gctUINT32_PTR)(Execution->funcCmd[0].data[3].logical)) == 0x00040004 /*INT16*/
+                || *((gctUINT32_PTR)(Execution->funcCmd[0].data[3].logical)) == 0x44004400 /*FP16*/
+                )
+            {
+                gcmkPRINT("USC PASS! ");
+            }
+        }
+#endif
+
+        for (j = 0; j < Execution->funcCmdCount; j++)
+        {
+            if (Execution->funcCmd[j].data)
+            {
+                for (i = 0; i < 5; i++)
+                {
+                    if (Execution->funcCmd[j].data[i].bufVidMem)
+                    {
+                        if (Execution->funcCmd[j].data[i].logical)
+                        {
+                            gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                );
+                            Execution->funcCmd[j].data[i].logical = gcvNULL;
+                        }
+                        if (Execution->funcCmd[j].data[i].address)
+                        {
+                            gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvNULL
+                                );
+                            Execution->funcCmd[j].data[i].address = 0;
+                        }
+
+                        gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].data[i].bufVidMem
+                            );
+                    }
+                }
+
+                gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[j].data));
+                Execution->funcCmd[j].data = gcvNULL;
+            }
+
+            if (Execution->funcCmd[j].funcVidMem)
+            {
+                if (Execution->funcCmd[j].address)
+                {
+                    /* Synchroneous unlock. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvNULL
+                                ));
+                     Execution->funcCmd[j].address = 0;
+                }
+
+                if (Execution->funcCmd[j].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[j].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].funcVidMem
+                            ));
+
+                Execution->funcCmd[j].funcVidMem = gcvNULL;
+            }
+        }
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncInit_USC(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 uscBytes = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 endBytes = 0;
+    gctUINT32 address;
+    gctUINT32 allocFlag = 0;
+    gcePOOL pool;
+    gctPOINTER logical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+    pool = gcvPOOL_DEFAULT;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+    Execution->funcCmdCount = 1;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    Execution->funcCmd[0].funcVidMemBytes = 1024;
+    /* Allocate video memory node for aux functions. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                hardware->kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag,
+                &Execution->funcCmd[0].funcVidMemBytes,
+                &pool,
+                &Execution->funcCmd[0].funcVidMem
+                ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                &Execution->funcCmd[0].address
+                ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                gcvFALSE,
+                gcvFALSE,
+                &Execution->funcCmd[0].logical
+                ));
+    /*
+    ** All cache flush command sequence.
+    */
+    logical = Execution->funcCmd[0].logical;
+    address = Execution->funcCmd[0].address;
+    /* Append a flush. */
+    gcmkONERROR(_InitializeUSC(Execution, &uscBytes));
+
+    offset += uscBytes;
+    address += offset;
+    logical = (gctUINT8_PTR)logical + offset;
+
+    if (hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(hardware, logical, address, &endBytes));
+    }
+
+    Execution->funcCmd[0].bytes = uscBytes + endBytes;
+    Execution->funcCmd[0].endAddress = Execution->funcCmd[0].address + uscBytes;
+    Execution->funcCmd[0].endLogical = (gctUINT8_PTR)Execution->funcCmd[0].logical + uscBytes;
+
+    return gcvSTATUS_OK;
+OnError:
+    _FuncRelease_USC(Execution);
+
+    return status;
+}
+#endif
+#if gcdRESET_USC2
+gceSTATUS
+_InitializeUSC2(
+    IN gcsFUNCTION_EXECUTION_PTR Execution,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32 i, idx = 0;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gctUINT32_PTR flushCommands = gcvNULL;
+    gctSIZE_T patchBufferSizes[3];
+    gceSTATUS status = gcvSTATUS_OK;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT8_PTR logical = (gctUINT8_PTR)Execution->funcCmd[0].logical;
+    gctPOINTER pointer = gcvNULL;
+
+    patchBufferSizes[INST_BUFFER_IDX] = gcmSIZEOF(instBuffer);
+    patchBufferSizes[OUTPUT_BUFFER_IDX] = 1024;
+    patchBufferSizes[SRAM_BUFFER_IDX] = 128 * 1024;
+
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               128 * gcmSIZEOF(gctUINT32),
+                               (gctPOINTER *)&flushCommands));
+
+    gckOS_ZeroMemory((gctPOINTER)flushCommands, 128 * gcmSIZEOF(gctUINT32));
+
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 3,
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * 3);
+
+    Execution->funcCmd[0].data = (gcsFUNCTION_EXECUTION_DATA_PTR)pointer;
+
+    for (i = 0; i < 3; i++)
+    {
+        /* Allocate memory for buffers. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            hardware->kernel,
+            64,
+            gcvVIDMEM_TYPE_BITMAP,
+            gcvALLOC_FLAG_NONE,
+            &patchBufferSizes[i],
+            &pool,
+            &Execution->funcCmd[0].data[i].bufVidMem
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            gcvFALSE,
+            gcvFALSE,
+            &Execution->funcCmd[0].data[i].logical
+            ));
+
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+            hardware->kernel,
+            Execution->funcCmd[0].data[i].bufVidMem,
+            &Execution->funcCmd[0].data[i].address
+            ));
+
+        gcmkONERROR(gckOS_ZeroMemory(Execution->funcCmd[0].data[i].logical, patchBufferSizes[i]));
+    }
+
+    gckOS_MemCopy(Execution->funcCmd[0].data[INST_BUFFER_IDX].logical, instBuffer, patchBufferSizes[INST_BUFFER_IDX]);
+
+    /* construct command */
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                            | gcvCORE_3D_ALL_MASK;
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (0x14) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0x00000002;
+    flushCommands[idx++] = 0x075bcd15;
+    flushCommands[idx++] = 0x00001000;
+    flushCommands[idx++] = 0x00010000;
+    flushCommands[idx++] = 0x00020000;
+    flushCommands[idx++] = 0x00030000;
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0x00000002;
+    flushCommands[idx++] = 0x00000004;
+    flushCommands[idx++] = 0x0000000c;
+    flushCommands[idx++] = 0x00000003;
+    flushCommands[idx++] = 0x00000003;
+    flushCommands[idx++] = 0x0000000f;
+    flushCommands[idx++] = Execution->funcCmd[0].data[OUTPUT_BUFFER_IDX].address;
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000080;
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0xffffffff;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                            | gcvCORE_3D_ALL_MASK;
+    flushCommands[idx++] = 0xf7f38c3c;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0424) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x0000000e;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0402) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0x00000003;
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = Execution->funcCmd[0].data[INST_BUFFER_IDX].address;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0409) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000010;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000001;
+
+    if (hardware->identity.customerID == 0xA0)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = Execution->funcCmd[0].data[SRAM_BUFFER_IDX].address;
+    }
+    else
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                                | gcvCORE_3D_ALL_MASK;
+        flushCommands[idx++] = 0x00000000;
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E21) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000300;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x02000001;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0247) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000001;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0249) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0250) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0253) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000000;
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0256) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0x00000001;
+    flushCommands[idx++] = 0x00000001;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000020;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0248) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000001;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000020;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x0000004f;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    flushCommands[idx++] = 0x00000000;
+
+    *Bytes = idx * 4 - 8;
+    /* Copy command to command buffer */
+    gckOS_MemCopy(logical, flushCommands, *Bytes);
+    if (flushCommands)
+    {
+        gckOS_Free(hardware->os, flushCommands);
+        flushCommands = gcvNULL;
+    }
+
+    return status;
+OnError:
+    if (flushCommands)
+    {
+        gckOS_Free(hardware->os, flushCommands);
+        flushCommands = gcvNULL;
+    }
+
+    if (Execution->funcCmd[0].data)
+    {
+        for (i = 0; i < 3; i++)
+        {
+            if (Execution->funcCmd[0].data[i].bufVidMem)
+            {
+                if (Execution->funcCmd[0].data[i].logical)
+                {
+                    gckVIDMEM_NODE_UnlockCPU(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvFALSE,
+                        gcvFALSE
+                        );
+                    Execution->funcCmd[0].data[i].logical = gcvNULL;
+                }
+                if (Execution->funcCmd[0].data[i].address)
+                {
+                    gckVIDMEM_NODE_Unlock(
+                        hardware->kernel,
+                        Execution->funcCmd[0].data[i].bufVidMem,
+                        0,
+                        gcvNULL
+                        );
+                    Execution->funcCmd[0].data[i].address = 0;
+                }
+
+                gckVIDMEM_NODE_Dereference(
+                    hardware->kernel,
+                    Execution->funcCmd[0].data[i].bufVidMem
+                    );
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[0].data));
+        Execution->funcCmd[0].data = gcvNULL;
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_FuncValidate_USC2(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+#ifdef EMULATOR
+    Execution->valid = gcvFALSE;
+#else
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    Execution->valid = gcvFALSE;
+    if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX))
+    {
+        if (hardware->identity.customerID == 0x21 ||
+            hardware->identity.customerID == 0x25 ||
+            hardware->identity.customerID == 0x86 ||
+            hardware->identity.customerID == 0xA0
+            )
+        {
+            Execution->valid = gcvTRUE;
+        }
+    }
+#endif
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncRelease_USC2(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctUINT32 i, j;
+
+    if (Execution->funcCmd)
+    {
+        for (j = 0; j < Execution->funcCmdCount; j++)
+        {
+            if (Execution->funcCmd[j].data)
+            {
+                for (i = 0; i < 3; i++)
+                {
+                    if (Execution->funcCmd[j].data[i].bufVidMem)
+                    {
+                        if (Execution->funcCmd[j].data[i].logical)
+                        {
+                            gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                );
+                            Execution->funcCmd[j].data[i].logical = gcvNULL;
+                        }
+                        if (Execution->funcCmd[j].data[i].address)
+                        {
+                            gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].data[i].bufVidMem,
+                                0,
+                                gcvNULL
+                                );
+                            Execution->funcCmd[j].data[i].address = 0;
+                        }
+
+                        gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].data[i].bufVidMem
+                            );
+                    }
+                }
+
+                gcmkVERIFY_OK(gckOS_Free(hardware->os, Execution->funcCmd[j].data));
+                Execution->funcCmd[j].data = gcvNULL;
+            }
+
+            if (Execution->funcCmd[j].funcVidMem)
+            {
+                if (Execution->funcCmd[j].address)
+                {
+                    /* Synchroneous unlock. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvNULL
+                                ));
+                     Execution->funcCmd[j].address = 0;
+                }
+
+                if (Execution->funcCmd[j].logical)
+                {
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                                hardware->kernel,
+                                Execution->funcCmd[j].funcVidMem,
+                                0,
+                                gcvFALSE,
+                                gcvFALSE
+                                ));
+                    Execution->funcCmd[j].logical = gcvNULL;
+                }
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                            hardware->kernel,
+                            Execution->funcCmd[j].funcVidMem
+                            ));
+
+                Execution->funcCmd[j].funcVidMem = gcvNULL;
+            }
+        }
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, (gctPOINTER)Execution->funcCmd));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FuncInit_USC2(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 uscBytes = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 endBytes = 0;
+    gctUINT32 address;
+    gctUINT32 allocFlag = 0;
+    gcePOOL pool;
+    gctPOINTER logical;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+    gctPOINTER pointer = gcvNULL;
+
+    pool = gcvPOOL_DEFAULT;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+    Execution->funcCmdCount = 1;
+
+    /* Allocate the gcsFUNCTION_COMMAND buffer */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                           gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount,
+                           (gctPOINTER *)&pointer));
+
+    gckOS_ZeroMemory((gctPOINTER)pointer, gcmSIZEOF(gcsFUNCTION_COMMAND) * Execution->funcCmdCount);
+
+    Execution->funcCmd = (gcsFUNCTION_COMMAND_PTR)pointer;
+
+    Execution->funcCmd[0].funcVidMemBytes = 1024;
+    /* Allocate video memory node for aux functions. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                hardware->kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag,
+                &Execution->funcCmd[0].funcVidMemBytes,
+                &pool,
+                &Execution->funcCmd[0].funcVidMem
+                ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                &Execution->funcCmd[0].address
+                ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                hardware->kernel,
+                Execution->funcCmd[0].funcVidMem,
+                gcvFALSE,
+                gcvFALSE,
+                &Execution->funcCmd[0].logical
+                ));
+    /*
+    ** All cache flush command sequence.
+    */
+    logical = Execution->funcCmd[0].logical;
+    address = Execution->funcCmd[0].address;
+    /* Append a flush. */
+    gcmkONERROR(_InitializeUSC2(Execution, &uscBytes));
+
+    offset += uscBytes;
+    address += offset;
+    logical = (gctUINT8_PTR)logical + offset;
+
+    if (hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(hardware, logical, address, &endBytes));
+    }
+
+    Execution->funcCmd[0].bytes = uscBytes + endBytes;
+    Execution->funcCmd[0].endAddress = Execution->funcCmd[0].address + uscBytes;
+    Execution->funcCmd[0].endLogical = (gctUINT8_PTR)Execution->funcCmd[0].logical + uscBytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    _FuncRelease_USC2(Execution);
+
+    return status;
+}
+
+#endif
+#endif
+
+/*******************************************************************************
+**
+**  gckFUNCTION_Construct
+**
+**  Generate command buffer snippets which will be used by gckHARDWARE, by which
+**  gckHARDWARE can manipulate GPU by FE command without using gckCOMMAND to avoid
+**  race condition and deadlock.
+**
+**  Notice:
+**  1. Each snippet can only be executed when GPU is idle.
+**  2. Execution is triggered by AHB (0x658)
+**  3. Each snippet followed by END so software can sync with GPU by checking GPU
+**     idle
+**  4. It is transparent to gckCOMMAND command buffer.
+**
+**  Existing Snippets:
+**  1. MMU Configure
+**     For new MMU, after GPU is reset, FE execute this command sequence to enable MMU.
+*/
+gceSTATUS gckFUNCTION_Construct(IN         gctPOINTER Hardware)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckHARDWARE hardware = (gckHARDWARE)Hardware;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT i;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+    /* Allocate the gcsFUNCTION_EXECUTION object. */
+    gcmkONERROR(gckOS_Allocate(hardware->os,
+                               gcmSIZEOF(gcsFUNCTION_EXECUTION) * gcvFUNCTION_EXECUTION_NUM,
+                               &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION) * gcvFUNCTION_EXECUTION_NUM);
+
+    hardware->functions = (gcsFUNCTION_EXECUTION_PTR)pointer;
+
+    for (i = 0; i < gcvFUNCTION_EXECUTION_NUM; i++)
+    {
+        gcsFUNCTION_EXECUTION_PTR func = &hardware->functions[i];
+
+        func->hardware = hardware;
+        func->funcId = (gceFUNCTION_EXECUTION)i;
+        func->funcCmd = gcvNULL;
+
+        /* Init functions API pointer */
+        switch (i)
+        {
+        case gcvFUNCTION_EXECUTION_MMU:
+            gckOS_MemCopy(func->funcName, "set mmu", 8);
+            func->funcExecution.init = _FuncInit_MMU;
+            func->funcExecution.validate = _FuncValidate_MMU;
+            func->funcExecution.execute = _FuncExecute_MMU;
+            func->funcExecution.release = _FuncRelease_MMU;
+            break;
+
+        case gcvFUNCTION_EXECUTION_FLUSH:
+            gckOS_MemCopy(func->funcName, "flush", 6);
+            func->funcExecution.init = _FuncInit_Flush;
+            func->funcExecution.validate = _FuncValidate_Flush;
+            func->funcExecution.execute = _FuncExecute;
+            func->funcExecution.release = _FuncRelease_Flush;
+            break;
+
+#if gcdFLOP_RESET
+        case gcvFUNCTION_EXECUTION_FLOP_RESET:
+            gckOS_MemCopy(func->funcName, "flop reset", 11);
+            func->funcExecution.init = _FuncInit_FlopReset;
+            func->funcExecution.validate = _FuncValidate_FlopReset;
+            func->funcExecution.execute = _FuncExecute;
+            func->funcExecution.release = _FuncRelease;
+            break;
+#else
+#if gcdINITIALIZE_PPU
+        case gcvFUNCTION_EXECUTION_INITIALIZE_PPU:
+            gckOS_MemCopy(func->funcName, "init ppu", 9);
+            switch(hardware->identity.customerID)
+            {
+            case 0xA0:
+                func->funcExecution.init = _FuncInit_PPU_0xA0;
+                func->funcExecution.validate = _FuncValidate_PPU_0xA0;
+                func->funcExecution.execute = _FuncExecute;
+                func->funcExecution.release = _FuncRelease_PPU_0xA0;
+                break;
+            default:
+                func->funcExecution.init = _FuncInit_PPU;
+                func->funcExecution.validate = _FuncValidate_PPU;
+                func->funcExecution.execute = _FuncExecute;
+                func->funcExecution.release = _FuncRelease_PPU;
+                break;
+            }
+            break;
+#endif
+#if gcdRESET_USC1
+        case gcvFUNCTION_EXECUTION_RESET_USC:
+            gckOS_MemCopy(func->funcName, "reset usc", 10);
+            func->funcExecution.init = _FuncInit_USC;
+            func->funcExecution.validate = _FuncValidate_USC;
+            func->funcExecution.execute = _FuncExecute;
+            func->funcExecution.release = _FuncRelease_USC;
+            break;
+#endif
+#if gcdRESET_USC2
+
+        case gcvFUNCTION_EXECUTION_RESET_USC2:
+            gckOS_MemCopy(func->funcName, "reset usc2", 11);
+            func->funcExecution.init = _FuncInit_USC2;
+            func->funcExecution.validate = _FuncValidate_USC2;
+            func->funcExecution.execute = _FuncExecute;
+            func->funcExecution.release = _FuncRelease_USC2;
+            break;
+#endif
+#endif
+
+        default:
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    if (hardware->functions)
+    {
+        gcmkVERIFY_OK(gckOS_Free(hardware->os, hardware->functions));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gckFUNCTION_Destory(IN    gctPOINTER Hardware)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckHARDWARE hardware = (gckHARDWARE)Hardware;
+    gctUINT i;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+    for (i = 0; i < gcvFUNCTION_EXECUTION_NUM; i++)
+    {
+        gckFUNCTION_Release(&hardware->functions[i]);
+    }
+
+    gcmkVERIFY_OK(gckOS_Free(hardware->os, hardware->functions));
+    hardware->functions = gcvNULL;
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gckFUNCTION_Validate(IN gcsFUNCTION_EXECUTION_PTR Execution,
+                                       IN OUT gctBOOL_PTR Valid)
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+
+    gcmkHEADER_ARG("Execution=0x%x", Execution);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Execution != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Valid != gcvNULL);
+
+    if (Execution->funcExecution.validate)
+    {
+        status = Execution->funcExecution.validate(Execution);
+        *Valid = Execution->valid;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gckFUNCTION_Init(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+
+    gcmkHEADER_ARG("Execution=0x%x", Execution);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Execution != gcvNULL);
+
+    Execution->inited = gcvTRUE;
+    if (Execution->funcExecution.init)
+    {
+        status = Execution->funcExecution.init(Execution);
+    }
+
+    if (status != gcvSTATUS_OK)
+    {
+        Execution->inited = gcvFALSE;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gckFUNCTION_Execute(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+
+    gcmkHEADER_ARG("Execution=0x%x", Execution);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Execution != gcvNULL);
+
+    if (Execution->inited && Execution->funcExecution.execute)
+    {
+        status = Execution->funcExecution.execute(Execution);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gckFUNCTION_Release(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+
+    gcmkHEADER_ARG("Execution=0x%x", Execution);
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Execution != gcvNULL);
+
+    if (Execution->inited && Execution->funcExecution.release)
+    {
+        status = Execution->funcExecution.release(Execution);
+    }
+
+    Execution->inited = gcvFALSE;
+
+    gcmkFOOTER();
+    return status;
+}
+
+void
+gckFUNCTION_Dump(IN gcsFUNCTION_EXECUTION_PTR Execution)
+{
+#if gcdDUMP_IN_KERNEL
+    gctUINT32 i;
+    gckHARDWARE hardware = (gckHARDWARE)Execution->hardware;
+
+    if (!Execution || !Execution->funcCmd)
+    {
+        return;
+    }
+
+    gcmkDUMP(hardware->os, "#[function: %s]", Execution->funcName);
+    for (i = 0; i < Execution->funcCmdCount; i++)
+    {
+        gcmkDUMP_BUFFER(
+            hardware->os,
+            gcvDUMP_BUFFER_KERNEL_COMMAND,
+            Execution->funcCmd[i].logical,
+            Execution->funcCmd[i].address,
+            Execution->funcCmd[i].bytes
+            );
+    }
+#endif
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_func_h_
+#define __gc_hal_kernel_hardware_func_h_
+#include "gc_hal.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define gcdFLOP_RESET           1
+#define gcdFLOP_RESET_PPU       1
+#define gcdFLOP_RESET_NN        1
+#define gcdFLOP_RESET_TP        1
+
+/*
+ * The following macros are for old FLOP
+ * reset path.
+ * Use gcdFLOP_RESET=1 for the new path.
+ * The related code will be removed as long
+ * as the new path is stable.
+ */
+#define gcdINITIALIZE_PPU       1
+#define gcdINITIALIZE_PPU_C     0
+#define gcdRESET_USC1           1
+#define gcdRESET_USC_C          0
+#define gcdRESET_USC2           1
+
+typedef struct _gcsFUNCTION_EXECUTION * gcsFUNCTION_EXECUTION_PTR;
+
+typedef enum {
+    gcvFUNCTION_EXECUTION_MMU,
+    gcvFUNCTION_EXECUTION_FLUSH,
+#if gcdFLOP_RESET
+    gcvFUNCTION_EXECUTION_FLOP_RESET,
+#else
+#if gcdRESET_USC1
+    gcvFUNCTION_EXECUTION_RESET_USC,
+#endif
+#if gcdRESET_USC2
+    gcvFUNCTION_EXECUTION_RESET_USC2,
+#endif
+#if gcdINITIALIZE_PPU
+    gcvFUNCTION_EXECUTION_INITIALIZE_PPU,
+#endif
+#endif
+
+    gcvFUNCTION_EXECUTION_NUM
+}
+gceFUNCTION_EXECUTION;
+
+typedef struct {
+    /* Data Vidmem object */
+    gckVIDMEM_NODE      bufVidMem;
+
+    /* Total bytes of the data. */
+    gctSIZE_T           bufVidMemBytes;
+
+    /* Entry of the data. */
+    gctUINT32           address;
+
+    /* CPU address of the data. */
+    gctPOINTER          logical;
+
+    /* Actually bytes of the data. */
+    gctSIZE_T           bytes;
+}
+gcsFUNCTION_EXECUTION_DATA, *gcsFUNCTION_EXECUTION_DATA_PTR;
+
+typedef struct {
+    gceSTATUS (*validate)(IN gcsFUNCTION_EXECUTION_PTR Execution);
+    gceSTATUS (*init)(IN gcsFUNCTION_EXECUTION_PTR Execution);
+    gceSTATUS (*execute)(IN gcsFUNCTION_EXECUTION_PTR Execution);
+    gceSTATUS (*release)(IN gcsFUNCTION_EXECUTION_PTR Execution);
+}
+gcsFUNCTION_API, *gcsFUNCTION_API_PTR;
+
+typedef struct _gcsFUNCTION_COMMAND
+{
+    /* Function Vidmem object */
+    gckVIDMEM_NODE              funcVidMem;
+
+    /* Total bytes of the function. */
+    gctSIZE_T                   funcVidMemBytes;
+
+    /* Entry of the function. */
+    gctUINT32                   address;
+
+    /* CPU address of the function. */
+    gctPOINTER                  logical;
+
+    /* Actually bytes of the function. */
+    gctUINT32                   bytes;
+
+    /* Hardware address of END in this function. */
+    gctUINT32                   endAddress;
+
+    /* Logical of END in this function. */
+    gctUINT8_PTR                endLogical;
+
+    /* Function private data */
+    gctUINT32                   dataCount;
+    gcsFUNCTION_EXECUTION_DATA_PTR data;
+}
+gcsFUNCTION_COMMAND, *gcsFUNCTION_COMMAND_PTR;
+
+typedef struct _gcsFUNCTION_EXECUTION
+{
+    gctPOINTER                  hardware;
+
+    /* Function name */
+    gctCHAR                     funcName[16];
+
+    /* Function ID */
+    gceFUNCTION_EXECUTION       funcId;
+
+    /* Function count */
+    gctUINT8                    funcCmdCount;
+
+    /* Function array */
+    gcsFUNCTION_COMMAND_PTR     funcCmd;
+
+    /* API of functions */
+    gcsFUNCTION_API funcExecution;
+
+    /* Need this function or not */
+    gctBOOL valid;
+
+    /* Function has inited */
+    gctBOOL inited;
+}
+gcsFUNCTION_EXECUTION;
+
+gceSTATUS gckFUNCTION_Construct(IN         gctPOINTER Hardware);
+gceSTATUS gckFUNCTION_Destory(IN    gctPOINTER Hardware);
+
+gceSTATUS gckFUNCTION_Validate(IN gcsFUNCTION_EXECUTION_PTR Execution,
+                                       IN OUT gctBOOL_PTR Valid);
+gceSTATUS gckFUNCTION_Init(IN gcsFUNCTION_EXECUTION_PTR Execution);
+gceSTATUS gckFUNCTION_Execute(IN gcsFUNCTION_EXECUTION_PTR Execution);
+gceSTATUS gckFUNCTION_Release(IN gcsFUNCTION_EXECUTION_PTR Execution);
+void gckFUNCTION_Dump(IN gcsFUNCTION_EXECUTION_PTR Execution);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_flop_reset.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_flop_reset.c
@@ -0,0 +1,7020 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include <gc_hal.h>
+#include <gc_feature_database.h>
+
+#include "gc_hal_kernel_hardware_func_flop_reset.h"
+
+/*
+ * Flop reset.
+ *
+ * The flops can be reset with PPU, NN and TP programs.
+ * PPU:
+ *   Requirements:
+ *   1. DP inst with all bins enabled.
+ *   2. Load inst which has at least two shader group,
+ *      and every thread should load from different 64-byte address.
+ *   3. Stroe inst which has at least 6 threads, whose addresses are
+ *      from different 64-byte address and flush.
+ *   Case:
+ *   * InImage: 64x6 = {1}, unsigned int8
+ *   * OutImage: 64x6, unsigned int8
+ *   * OutImage = InImage + InImage
+ * NN:
+ *   Requirements:
+ *   1. A XYDP6 case.
+ *   2. NN cmd that uses only 1 core and make othere core's kernel size
+ *      to be 0.
+ *   Case:
+ *   * Input: 3x2x1 = {1}
+ *   * Kernel: 2x2x1 = {1}
+ *   * Output: 2x1x1
+ * TP:
+ *   Requirements:
+ *   1. Run TP fc on all TP cores.
+ *   Case:
+ *   * Input: 1x1x2 = {1}
+ *   * Kernel: 1x1x2x64 = {1}
+ *   * Output: 1x64
+ */
+
+/*
+ * PPU.
+ */
+#define PPU_IMAGE_XSIZE 64
+#define PPU_IMAGE_YSIZE 6
+#define PPU_IMAGE_DATA 0x01010101
+#define MAX_PPU_INSTRUCTION_COUNT 16
+#define MAX_PPU_COMMAND_NUM 128
+
+#define GCREG_SH_INSTRUCTION_TYPE_INVALID (~0U)
+
+typedef enum _gceFLOP_RESET_PPU_DATA {
+    gcvFLOP_RESET_PPU_INSTRUCTION = 0,
+    gcvFLOP_RESET_PPU_INPUT       = 1,
+    gcvFLOP_RESET_PPU_OUTPUT      = 2,
+    gcvFLOP_RESET_PPU_DATA_NUM
+}
+gceFLOP_RESET_PPU_DATA;
+
+/*
+ * NN convolution.
+ */
+#define MAX_NN_COMMAND_NUM 64
+
+#define NN_KERNEL_XSIZE 2
+#define NN_KERNEL_YSIZE 2
+#define NN_KERNEL_ZSIZE 1
+
+#define NN_INPUT_XSIZE 3
+#define NN_INPUT_YSIZE 2
+#define NN_INPUT_ZSIZE 1
+
+#define NN_OUTPUT_XSIZE 2
+#define NN_OUTPUT_YSIZE 1
+#define NN_OUTPUT_ZSIZE 1
+
+typedef enum _gceVIP_ARCH_TYPE {
+    gcvVIP_ARCH_TYPE_V6,
+    gcvVIP_ARCH_TYPE_V7,
+    gcvVIP_ARCH_TYPE_V8
+}
+gceVIP_ARCH_TYPE;
+
+typedef enum _gceFLOP_RESET_NN_DATA {
+    gcvFLOP_RESET_NN_INSTRUCTION = 0,
+    gcvFLOP_RESET_NN_INPUT       = 1,
+    gcvFLOP_RESET_NN_OUTPUT      = 2,
+    gcvFLOP_RESET_NN_KERNEL      = 3,
+    gcvFLOP_RESET_NN_DATA_NUM
+}
+gceFLOP_RESET_NN_DATA;
+
+#define TP_KERNEL_XSIZE 1
+#define TP_KERNEL_YSIZE 1
+#define TP_KERNEL_ZSIZE 2
+#define TP_KENREL_UNITS 64
+
+#define TP_INPUT_XSIZE 1
+#define TP_INPUT_YSIZE 1
+#define TP_INPUT_ZSIZE 2
+
+#define TP_OUTPUT_XSIZE 1
+#define TP_OUTPUT_YSIZE 64
+#define TP_OUTPUT_ZSIZE 1
+
+typedef enum _gceFLOP_RESET_TP_DATA {
+    gcvFLOP_RESET_TP_INSTRUCTION = 0,
+    gcvFLOP_RESET_TP_INPUT       = 1,
+    gcvFLOP_RESET_TP_OUTPUT      = 2,
+    gcvFLOP_RESET_TP_KERNEL      = 3,
+    gcvFLOP_RESET_TP_DATA_NUM
+}
+gceFLOP_RESET_TP_DATA;
+
+static gceSTATUS
+_AllocateVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    IN OUT gctSIZE_T *Bytes,
+    OUT gckVIDMEM_NODE *Node,
+    OUT gctPOINTER *Logical,
+    OUT gctUINT32 *Address
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes = 0;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+
+    if (!Bytes || *Bytes == 0)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (Pool)
+    {
+        pool = *Pool;
+    }
+
+    bufferBytes = *Bytes;
+
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+        Kernel,
+        64,
+        Type,
+        AllocFlag,
+        &bufferBytes,
+        &pool,
+        &bufferNode
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        Kernel,
+        bufferNode,
+        gcvFALSE,
+        gcvFALSE,
+        &bufferLogical
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+        Kernel,
+        bufferNode,
+        &bufferAddress
+        ));
+
+    gcmkONERROR(gckOS_ZeroMemory(bufferLogical, bufferBytes));
+
+    *Bytes = bufferBytes;
+
+    if (Pool)
+    {
+        *Pool = pool;
+    }
+
+    if (Node)
+    {
+        *Node = bufferNode;
+    }
+
+    if (Logical)
+    {
+        *Logical = bufferLogical;
+    }
+
+    if (Address)
+    {
+        *Address = bufferAddress;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        if (bufferAddress)
+        {
+            gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                Kernel,
+                bufferNode,
+                0,
+                gcvNULL
+                ));
+        }
+
+        if (bufferLogical)
+        {
+            gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                Kernel,
+                bufferNode,
+                0,
+                gcvFALSE,
+                gcvFALSE
+                ));
+        }
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            Kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_FreeVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE Node
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Node)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+        Kernel,
+        Node,
+        0,
+        gcvNULL
+        ));
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+        Kernel,
+        Node,
+        0,
+        gcvFALSE,
+        gcvFALSE
+        ));
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+        Kernel,
+        Node
+        ));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_BitValue(
+    IN gctUINT8_PTR *Base,
+    IN gctUINT32 Value,
+    IN gctUINT32_PTR Offset,
+    IN gctUINT Length
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32_PTR msb = (gctUINT32_PTR)(*Base) + 1, lsb = (gctUINT32_PTR)(*Base);
+
+    gcmkASSERT(*Offset <= 32 && Length <= 32);
+
+    if ((*Offset) < 32)
+    {
+        gctUINT32 end = (*Offset) + Length, data = *lsb;
+
+        if (end < 32)
+        {
+            /************************************************************************
+             *       offset    32           64                                      *
+             *     _________________________                                        *
+             *    |_____|////|_|____________|                                       *
+             *              end                                                     *
+             ************************************************************************/
+            data  = (*lsb & ((1 << *Offset) - 1));
+            data |= (*lsb & ~((1 << end) - 1));
+            data |= (Value << *Offset);
+
+            *lsb = data;
+            *Offset = end;
+        }
+        else if (end < 64)
+        {
+            /************************************************************************
+             *       offset    32           64                                      *
+             *     _________________________                                        *
+             *    |_____|//////|//|_________|                                       *
+             *                   end                                                *
+             ************************************************************************/
+            gctUINT32 length_m = end - 32;
+            gctUINT32 data_l = (*lsb & ((1 << *Offset) - 1));
+            gctUINT32 data_m = (*msb & ~((1 << length_m) - 1));
+
+            data_l |= (Value << *Offset);
+            data_m |= (Value >> (32 - *Offset));
+
+            *lsb = data_l;
+
+            if (end > 32)
+                *msb = data_m;
+
+            *Offset = length_m;
+
+            *Base = (gctUINT8_PTR)msb;
+        }
+
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_GetVIPCoreInfo(
+    IN gckHARDWARE Hardware,
+    OUT gceVIP_ARCH_TYPE *ArchType,
+    OUT gctUINT8 *DataType,
+    OUT gctUINT32 *CoreCount,
+    OUT gctUINT32 *Zdp,
+    OUT gctUINT32 *KernelBurstSize
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcsFEATURE_DATABASE *database = (gcsFEATURE_DATABASE *)(Hardware->featureDatabase);
+    gceVIP_ARCH_TYPE archType;
+    gctUINT8 dataType = 0x0;
+    gctUINT32 coreCount = 0;
+    gctUINT32 zdp = 1;
+    gctUINT32 kernelBurstSize;
+
+    gcmkASSERT(database);
+
+    /* Choose one supported format. */
+    if (database->NNCoreCount_INT8 > 0)
+    {
+        dataType = 0x0;
+        coreCount = database->NNCoreCount_INT8;
+    }
+    else if (database->NNCoreCount_INT16 > 0)
+    {
+        dataType = 0x4;
+        coreCount = database->NNCoreCount_INT16;
+    }
+    else if (database->NNCoreCount_FLOAT16 > 0)
+    {
+        dataType = 0x1;
+        coreCount = database->NNCoreCount_FLOAT16;
+    }
+    else if (database->NNCoreCount_BFLOAT > 0)
+    {
+        dataType = 0x7;
+        coreCount = database->NNCoreCount_BFLOAT;
+    }
+    else
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (database->NN_XYDP0)
+    {
+        archType = gcvVIP_ARCH_TYPE_V8;
+    }
+    else if (database->VIP_V7)
+    {
+        archType = gcvVIP_ARCH_TYPE_V7;
+    }
+    else
+    {
+        archType = gcvVIP_ARCH_TYPE_V6;
+    }
+
+    zdp = database->NN_ZDP3 ? 3 : 1;
+
+    kernelBurstSize = database->DDR_KERNEL_BURST_SIZE;
+
+    if (ArchType)
+    {
+        *ArchType = archType;
+    }
+
+    if (DataType)
+    {
+        *DataType = dataType;
+    }
+
+    if (CoreCount)
+    {
+        *CoreCount = coreCount;
+    }
+
+    if (Zdp)
+    {
+        *Zdp = zdp;
+    }
+
+    if (KernelBurstSize)
+    {
+        *KernelBurstSize = kernelBurstSize;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_GetMapIndex(
+    gctUINT8 DataType,
+    gctUINT32_PTR Index
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Index)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    switch (DataType)
+    {
+    case 0x1:
+        *Index = 1;
+        break;
+
+    case 0x7:
+        *Index = 2;
+        break;
+
+    default:
+        *Index = 0;
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_GetNNDataSize(
+   IN gctUINT8 DataType,
+   OUT gctUINT32_PTR DataSize
+   )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!DataSize)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    switch (DataType)
+    {
+    case 0x2:
+    case 0x0:
+        *DataSize = 1;
+        break;
+
+    case 0x4:
+    case 0x1:
+    case 0x7:
+        *DataSize = 2;
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*
+ * PPU.
+ */
+static gceSTATUS
+_ProgramPPUInput(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 InImageXSize,
+    IN gctUINT32 InImageYSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 itemBytes = 1; /* U8 format. */
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+    gctUINT32 *buffer = gcvNULL;
+    gctUINT32 i;
+
+    bufferBytes = bytes = InImageXSize * InImageYSize * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    buffer = (gctUINT32_PTR)bufferLogical;
+
+    /* Fill the data. */
+    for (i = 0; i < bytes / 4; i++)
+    {
+        buffer[i] = PPU_IMAGE_DATA;
+    }
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: ppu input]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramPPUOutput(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Width,
+    IN gctUINT32 Height,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 itemBytes = 1;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+
+    bufferBytes = bytes = Width * Height * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bufferBytes
+        ));
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gctUINT32
+_SETBITS(
+    IN gctUINT32 Data,
+    IN gctUINT32 Start,
+    IN gctUINT32 End,
+    IN gctUINT32 Value
+    )
+{
+    gctUINT32 data = Data;
+    gctUINT32 mask;
+
+    if (End >= Start)
+    {
+        mask =  ((~0ULL >> (63 - End + Start)) << Start);
+        data &= ~mask;
+        data |= ((Value) << Start) & mask;
+        return data;
+    }
+    else
+    {
+        mask =  ((~0ULL >> (63 - Start + End)) << End);
+        data &= ~mask;
+        data |= ((Value) << End) & mask;
+        return data;
+    }
+}
+
+static gctUINT32
+_SETBIT(
+    IN gctUINT32 Data,
+    IN gctUINT32 Position,
+    IN gctUINT32 Value
+    )
+{
+    gctUINT32 data;
+
+    data = _SETBITS(Data, Position, Position, Value);
+
+    return data;
+}
+
+static gctUINT32
+_GETBITS(
+    IN gctUINT32 Data,
+    IN gctUINT32 Start,
+    IN gctUINT32 End
+    )
+{
+    gctUINT32 data = Data;
+    gctUINT32 mask;
+
+    if (End >= Start)
+    {
+        mask = (~0ULL >> (63 - (End - Start)));
+        return (data >> Start) & mask;
+    }
+    else
+    {
+        mask = (~0ULL >> (63 - (Start - End)));
+        return (data >> End) & mask;;
+    }
+}
+
+static gctUINT32
+_GETBIT(
+    IN gctUINT32 Data,
+    IN gctUINT32 Position
+    )
+{
+    gctUINT32 data;
+
+    data = _GETBITS(Data, Position, Position);
+
+    return data;
+}
+
+static gceSTATUS
+gckPPU_SetImmediate(
+    IN gctUINT32 Where,
+    IN gctUINT32 Value,
+    IN gctUINT32 Type,
+    IN OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    switch (Where)
+    {
+    case 0:
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1))))))) << (0 ?
+ 20:12))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 8, 0)) & ((gctUINT32) ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:12) - (0 ? 20:12) + 1))))))) << (0 ? 20:12)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1))))))) << (0 ?
+ 29:22))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 16, 9)) & ((gctUINT32) ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:22) - (0 ? 29:22) + 1))))))) << (0 ? 29:22)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 17)) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 18)) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 19) | (Type << 1)) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))))) << (0 ?
+ 5:3))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:3) - (0 ? 5:3) + 1))))))) << (0 ? 5:3)));
+        break;
+
+    case 1:
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1))))))) << (0 ?
+ 15:7))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 8, 0)) & ((gctUINT32) ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:7) - (0 ? 15:7) + 1))))))) << (0 ? 15:7)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1))))))) << (0 ?
+ 24:17))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 16, 9)) & ((gctUINT32) ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:17) - (0 ? 24:17) + 1))))))) << (0 ? 24:17)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))))) << (0 ?
+ 25:25))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 17)) & ((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:25) - (0 ? 25:25) + 1))))))) << (0 ? 25:25)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 18)) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1))))))) << (0 ?
+ 29:27))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 19) | (Type << 1)) & ((gctUINT32) ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:27) - (0 ? 29:27) + 1))))))) << (0 ? 29:27)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        break;
+
+    case 2:
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1))))))) << (0 ?
+ 12:4))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 8, 0)) & ((gctUINT32) ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:4) - (0 ? 12:4) + 1))))))) << (0 ? 12:4)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1))))))) << (0 ?
+ 21:14))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Value, 16, 9)) & ((gctUINT32) ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:14) - (0 ? 21:14) + 1))))))) << (0 ? 21:14)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 17)) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ?
+ 23:23))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 18)) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1))))))) << (0 ?
+ 27:25))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Value, 19) | (Type << 1)) & ((gctUINT32) ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:25) - (0 ? 27:25) + 1))))))) << (0 ? 27:25)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28)));
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+gckPPU_SetInstructionType(
+    IN gctUINT32 Type,
+    OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ?
+ 21:21))) | (((gctUINT32) ((gctUINT32) (_GETBIT(Type, 0)) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)));
+    Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1))))))) << (0 ?
+ 31:30))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Type, 2, 1)) & ((gctUINT32) ((((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:30) - (0 ? 31:30) + 1))))))) << (0 ? 31:30)));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+gckPPU_IsEndOfBB(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 OpCode,
+    OUT gctUINT32_PTR Inst
+)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcsFEATURE_DATABASE *database = (gcsFEATURE_DATABASE *)Hardware->featureDatabase;
+    gctUINT32 bits = 0;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (!database->SH_END_OF_BB)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    switch (OpCode)
+    {
+    case 0x09:
+    case 0x56:
+    case 0x0A:
+    case 0x0B:
+    case 0x0F:
+    case 0x31:
+    case 0x10:
+        bits = _SETBITS(Inst[1], 3, 3, 1);
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1))))))) << (0 ?
+ 10:3))) | (((gctUINT32) ((gctUINT32) (bits) & ((gctUINT32) ((((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:3) - (0 ? 10:3) + 1))))))) << (0 ? 10:3)));
+        break;
+
+    case 0x65:
+    case 0x66:
+    case 0x67:
+    case 0x68:
+    case 0x69:
+    case 0x6A:
+    case 0x6B:
+    case 0x6C:
+    case 0x46:
+        bits = _SETBITS(Inst[0], 2, 2, 1);
+        Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))))) << (0 ?
+ 10:6))) | (((gctUINT32) ((gctUINT32) (bits) & ((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:6) - (0 ? 10:6) + 1))))))) << (0 ? 10:6)));
+        break;
+
+    case 0x32:
+    case 0x39:
+    case 0x33:
+    case 0x3A:
+    case 0x79:
+    case 0x34:
+    case 0x7A:
+    case 0x35:
+        bits = _SETBITS(Inst[0], 2, 2, 1);
+        Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))))) << (0 ?
+ 10:6))) | (((gctUINT32) ((gctUINT32) (bits) & ((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:6) - (0 ? 10:6) + 1))))))) << (0 ? 10:6)));
+        break;
+
+    default:
+        if (OpCode != 0x16 &&
+            OpCode != 0x24 &&
+            OpCode != 0x14 &&
+            OpCode != 0x15 &&
+            OpCode != 0x17)
+        {
+            bits = _SETBITS(Inst[0], 2, 2, 1);
+            Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))))) << (0 ?
+ 10:6))) | (((gctUINT32) ((gctUINT32) (bits) & ((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:6) - (0 ? 10:6) + 1))))))) << (0 ? 10:6)));
+        }
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+gckPPU_AddOpCode(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 OpCode,
+    IN gctUINT32 Extended,
+    IN gctUINT32 Type,
+    IN OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (_GETBITS(OpCode, 5, 0)) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0)));
+    Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (_GETBIT(OpCode, 6)) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)));
+
+    switch (OpCode)
+    {
+    case 0x7F:
+        gcmkONERROR(gckPPU_SetImmediate(2, Extended, 0x2, Inst));
+        break;
+
+    case 0x45:
+        Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1))))))) << (0 ?
+ 15:13))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Extended, 2, 0)) & ((gctUINT32) ((((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:13) - (0 ? 15:13) + 1))))))) << (0 ? 15:13)));
+        Inst[0] = _SETBIT(Inst[0], 31, _GETBIT(Extended, 3));
+        Inst[1] = _SETBITS(Inst[1], 1, 0, _GETBITS(Extended, 5, 4));
+        break;
+
+    case 0x31:
+    case 0x09:
+    case 0x0F:
+        Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))))) << (0 ?
+ 10:6))) | (((gctUINT32) ((gctUINT32) (_GETBITS(Extended, 4, 0)) & ((gctUINT32) ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:6) - (0 ? 10:6) + 1))))))) << (0 ? 10:6)));
+        break;
+
+    default:
+        break;
+    }
+
+    if (Type != GCREG_SH_INSTRUCTION_TYPE_INVALID)
+    {
+        gcmkONERROR(gckPPU_SetInstructionType(Type, Inst));
+    }
+
+    gcmkONERROR(gckPPU_IsEndOfBB(Hardware, OpCode, Inst));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+gckPPU_SetDestination(
+    IN gctUINT32 Address,
+    IN gctUINT32 WriteEnable,
+    IN gctUINT32 Saturate,
+    IN OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)));
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1))))))) << (0 ?
+ 22:16))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:16) - (0 ? 22:16) + 1))))))) << (0 ? 22:16)));
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1))))))) << (0 ?
+ 26:23))) | (((gctUINT32) ((gctUINT32) (WriteEnable) & ((gctUINT32) ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:23) - (0 ? 26:23) + 1))))))) << (0 ? 26:23)));
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) ((gctUINT32) (Saturate) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+#define gcdVX_ENABLE ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+#define gcdVX_ENABLE4(X, Y, Z, W) ((1 << (X)) | (1 << (Y)) | (1 << (Z)) | (1 << (W)))
+#define gcdVX_ENABLE1(X) (1 << (X))
+#define gcdVX_ENABLE2(X, Y) ((1 << (X)) | (1 << (Y)))
+#define gcdVX_ENABLE3(X, Y, Z) ((1 << (X)) | (1 << (Y)) | (1 << (Z)))
+#define gcdVX_SWIZZLE (0 | (1 << 2) | (2 << 4) | (3 << 6))
+#define gcdVX_SWIZZLE1(X) ((X) | ((X) << 2) | ((X) << 4) | ((X) << 6))
+#define gcdVX_SWIZZLE2(X, Y) ((X) | ((Y) << 2) | ((Y) << 4) | ((Y) << 6))
+#define gcdVX_SWIZZLE4(X, Y, Z, W) ((X) | ((Y) << 2) | ((Z) << 4) | ((W) << 6))
+
+static gctUINT32
+gckPPU_GetPixel(
+    IN gctUINT32 Format
+    )
+{
+    gctUINT32 pixel = 0;
+
+    switch(Format)
+    {
+    case 0x7:
+        pixel = 15;
+        break;
+
+    case 0x3:
+    case 0x6:
+        pixel = 7;
+        break;
+
+    default:
+        pixel = 15;
+        break;
+    }
+
+    return pixel;
+}
+
+gceSTATUS
+gckPPU_SetEVIS(
+    IN gctUINT32 Start,
+    IN gctUINT32 End,
+    IN gctUINT32 Evis,
+    IN OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    Inst[0] = ((((gctUINT32) (Inst[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1))))))) << (0 ?
+ 26:23))) | (((gctUINT32) ((gctUINT32) (Start) & ((gctUINT32) ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:23) - (0 ? 26:23) + 1))))))) << (0 ? 26:23)));
+    Inst[0] = _SETBITS(Inst[0], 30, 27, End);
+    Inst[1] = _SETBITS(Inst[1], 10, 2, Evis);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+gckPPU_SetSource(
+    IN gctUINT32 Where,
+    IN gctUINT32 Address,
+    IN gctUINT32 Swizzle,
+    IN gctUINT32 Type,
+    IN gctBOOL Negate,
+    IN gctBOOL Absolute,
+    IN gctUINT32 Relative,
+    IN OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    switch (Where)
+    {
+    case 0:
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1))))))) << (0 ?
+ 20:12))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:12) - (0 ? 20:12) + 1))))))) << (0 ? 20:12)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1))))))) << (0 ?
+ 29:22))) | (((gctUINT32) ((gctUINT32) (Swizzle) & ((gctUINT32) ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:22) - (0 ? 29:22) + 1))))))) << (0 ? 29:22)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (Negate) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)));
+        Inst[1] = ((((gctUINT32) (Inst[1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (Absolute) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (Relative) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))))) << (0 ?
+ 5:3))) | (((gctUINT32) ((gctUINT32) (Type) & ((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:3) - (0 ? 5:3) + 1))))))) << (0 ? 5:3)));
+        break;
+
+    case 1:
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1))))))) << (0 ?
+ 15:7))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:7) - (0 ? 15:7) + 1))))))) << (0 ? 15:7)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1))))))) << (0 ?
+ 24:17))) | (((gctUINT32) ((gctUINT32) (Swizzle) & ((gctUINT32) ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:17) - (0 ? 24:17) + 1))))))) << (0 ? 24:17)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))))) << (0 ?
+ 25:25))) | (((gctUINT32) ((gctUINT32) (Negate) & ((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:25) - (0 ? 25:25) + 1))))))) << (0 ? 25:25)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (Absolute) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)));
+        Inst[2] = ((((gctUINT32) (Inst[2])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1))))))) << (0 ?
+ 29:27))) | (((gctUINT32) ((gctUINT32) (Relative) & ((gctUINT32) ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:27) - (0 ? 29:27) + 1))))))) << (0 ? 29:27)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (Type) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+        break;
+
+    case 2:
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1))))))) << (0 ?
+ 12:4))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:4) - (0 ? 12:4) + 1))))))) << (0 ? 12:4)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1))))))) << (0 ?
+ 21:14))) | (((gctUINT32) ((gctUINT32) (Swizzle) & ((gctUINT32) ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:14) - (0 ? 21:14) + 1))))))) << (0 ? 21:14)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ?
+ 22:22))) | (((gctUINT32) ((gctUINT32) (Negate) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:22) - (0 ? 22:22) + 1))))))) << (0 ? 22:22)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ?
+ 23:23))) | (((gctUINT32) ((gctUINT32) (Absolute) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1))))))) << (0 ?
+ 27:25))) | (((gctUINT32) ((gctUINT32) (Relative) & ((gctUINT32) ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:25) - (0 ? 27:25) + 1))))))) << (0 ? 27:25)));
+        Inst[3] = ((((gctUINT32) (Inst[3])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (Type) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28)));
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        break;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static const gctUINT32 NEGATE_FLAG   = 1 << 0;
+static const gctUINT32 ABSOLUTE_FLAG = 1 << 1;
+
+static gceSTATUS
+gckPPU_SetUniform(
+    IN gctUINT32 Where,
+    IN gctUINT32 Address,
+    IN gctUINT32 Swizzle,
+    IN gctUINT32 Modifiers,
+    OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctBOOL negate = (Modifiers & NEGATE_FLAG) ? gcvTRUE : gcvFALSE;
+    gctBOOL absolute = (Modifiers & ABSOLUTE_FLAG) ? gcvTRUE : gcvFALSE;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkONERROR(gckPPU_SetSource(
+        Where,
+        Address,
+        Swizzle,
+        0x2,
+        negate,
+        absolute,
+        0,
+        Inst
+        ));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckPPU_SetTempReg(
+    IN gctUINT32 Where,
+    IN gctUINT32 Address,
+    IN gctUINT32 Swizzle,
+    IN gctUINT32 Modifiers,
+    OUT gctUINT32_PTR Inst
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctBOOL negate = (Modifiers & NEGATE_FLAG) ? gcvTRUE : gcvFALSE;
+    gctBOOL absolute = (Modifiers & ABSOLUTE_FLAG) ? gcvTRUE : gcvFALSE;
+
+    if (!Inst)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkONERROR(gckPPU_SetSource(
+        Where,
+        Address,
+        Swizzle,
+        0x0,
+        negate,
+        absolute,
+        0,
+        Inst
+        ));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+
+static gceSTATUS
+_ProgramPPUInstruction(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 DataType,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gctUINT32 *InstCount,
+    OUT gctUINT32 *RegCount,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+
+    gctUINT32 instCount = 0;
+    gctUINT32_PTR inst = gcvNULL;
+
+    gctUINT32 inImage1DataType = DataType;
+    gctUINT32 inImage2DataType = DataType;
+    gctUINT32 outImageDataType = DataType;
+
+    if (!Data || !InstCount || !RegCount)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    bufferBytes = bytes = gcmSIZEOF(gctUINT32) * MAX_PPU_INSTRUCTION_COUNT;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    inst = (gctUINT32_PTR)bufferLogical;
+
+    /* img_load.u8 r1, c0, r0.xy */
+    gcmkONERROR(gckPPU_AddOpCode(Hardware, 0x79, 0, inImage1DataType, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetDestination(1, gcdVX_ENABLE, gcvFALSE, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetEVIS(0, gckPPU_GetPixel(inImage1DataType), 1, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetUniform(0, 0, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &inst[instCount]));
+    instCount += 4;
+
+    /*img_load.u8 r2, c0, r0.xy */
+    gcmkONERROR(gckPPU_AddOpCode(Hardware, 0x79, 0, inImage2DataType, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetDestination(2, gcdVX_ENABLE, gcvFALSE, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetEVIS(0, gckPPU_GetPixel(inImage2DataType), 1, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetUniform(0, 0, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &inst[instCount]));
+    instCount += 4;
+
+    /* dp2x8 r1, r1, r2, c3_512 */
+    gcmkONERROR(gckPPU_AddOpCode(Hardware, 0x45, 0x0B, outImageDataType, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetDestination(1, gcdVX_ENABLE, gcvFALSE, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetEVIS(0, 7, (inImage1DataType | (inImage2DataType << 3)), &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(0, 1, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(1, 2, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetSource (2, 2, gcdVX_SWIZZLE, 0x4, gcvFALSE, gcvFALSE, 0, &inst[instCount]));
+    instCount += 4;
+
+    /* img_store.u8 r1, c2, r0.xy, r1 */
+    gcmkONERROR(gckPPU_AddOpCode(Hardware, 0x7A, 0, outImageDataType, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetEVIS(0, gckPPU_GetPixel(outImageDataType), 1, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetUniform(0, 1, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &inst[instCount]));
+    gcmkONERROR(gckPPU_SetTempReg(2, 1, gcdVX_SWIZZLE, 0, &inst[instCount]));
+    instCount += 4;
+
+    bytes = gcmSIZEOF(gctUINT32) * instCount;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: ppu instruction]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    *InstCount = instCount;
+    *RegCount = 0x3;
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramPPUCommand(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Stride,
+    IN gctUINT32 Width,
+    IN gctUINT32 Height,
+    IN gctUINT32 WorkDim,
+    IN gctUINT32 ValueOrder,
+    IN gctUINT32 GroupSizeX,
+    IN gctUINT32 GroupSizeY,
+    IN gctUINT32 GroupSizeZ,
+    IN gctUINT32 GlobalScaleX,
+    IN gctUINT32 GlobalScaleY,
+    IN gctUINT32 GlobalScaleZ,
+    IN gctUINT32 GlobalOffsetX,
+    IN gctUINT32 GlobalOffsetY,
+    IN gctUINT32 GlobalOffsetZ,
+    IN gctUINT32 ThreadAllocation,
+    IN gctUINT32 InImageAddress,
+    IN gctUINT32 OutImageAddress,
+    IN gctUINT32 InstAddress,
+    IN gctUINT32 InstCount,
+    IN gctUINT32 RegCount,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes = 0;
+    gctUINT32 bytes = 0;
+    gctUINT8_PTR endLogical;
+    gctUINT32 endAddress;
+    gctUINT32 endBytes = 0;
+    gctUINT32_PTR commands = gcvNULL;
+    gctUINT32 index = 0;
+    gctUINT32 groupCountX = (Width +  GlobalScaleX - 1) / GlobalScaleX;
+    gctUINT32 groupCountY = (Height +  GlobalScaleY - 1) / GlobalScaleY;
+    gctUINT32 groupCountZ = 0;
+
+    if (!Command)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    bufferBytes = gcmSIZEOF(gctUINT32) * MAX_PPU_COMMAND_NUM;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    commands = (gctUINT32_PTR)bufferLogical;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E13) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = InImageAddress;
+    commands[index++] = Stride;
+    commands[index++] = Height << 16 | Width;
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1))))))) << (0 ?
+ 5:4))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1))))))) << (0 ?
+ 9:6))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:6) - (0 ? 9:6) + 1))))))) << (0 ? 9:6)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1))))))) << (0 ?
+ 11:10))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:10) - (0 ? 11:10) + 1))))))) << (0 ? 11:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x1) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1))))))) << (0 ?
+ 18:16))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:16) - (0 ? 18:16) + 1))))))) << (0 ? 18:16)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1))))))) << (0 ?
+ 22:20))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:20) - (0 ? 22:20) + 1))))))) << (0 ? 22:20)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28)));
+
+    commands[index++] = 0xFFFFFFFF;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x04) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = OutImageAddress;
+    commands[index++] = Stride;
+    commands[index++] = Height << 16 | Width;
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1))))))) << (0 ?
+ 5:4))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1))))))) << (0 ?
+ 9:6))) | (((gctUINT32) ((gctUINT32) (0x7) & ((gctUINT32) ((((1 ?
+ 9:6) - (0 ?
+ 9:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:6) - (0 ? 9:6) + 1))))))) << (0 ? 9:6)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1))))))) << (0 ?
+ 11:10))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 11:10) - (0 ?
+ 11:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:10) - (0 ? 11:10) + 1))))))) << (0 ? 11:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x1) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1))))))) << (0 ?
+ 18:16))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 18:16) - (0 ?
+ 18:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:16) - (0 ? 18:16) + 1))))))) << (0 ? 18:16)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1))))))) << (0 ?
+ 22:20))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 22:20) - (0 ?
+ 22:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 22:20) - (0 ? 22:20) + 1))))))) << (0 ? 22:20)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))))) << (0 ?
+ 30:28))) | (((gctUINT32) ((gctUINT32) (0x4) & ((gctUINT32) ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:28) - (0 ? 30:28) + 1))))))) << (0 ? 30:28)));
+
+    commands[index++] = 0xFFFFFFFF;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0xD800 + 0x08) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x55555555;
+    commands[index++] = 0x00000000; /* TCfg. */
+    commands[index++] = 0x01234567;
+    commands[index++] = 0x89abcdef;
+    commands[index++] = 0x55555555;
+    commands[index++] = 0x01234567;
+    commands[index++] = 0x89abcdef; /* BinSelect. */
+    commands[index++] = 0x00000000; /* AccumType, ConstantType, and PostShift. */
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000;
+    commands[index++] = 0x00000000; /* Constant. */
+
+    commands[index++] = 0xFFFFFFFF;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0x2) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x2) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0420) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0403) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = RegCount;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0416) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0409) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0424) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = InstCount / 4;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = InstAddress;
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5))
+    {
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5580) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+    }
+    else
+    {
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)));
+    }
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0425) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = InstCount / 4 - 1;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0402) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) ((gctUINT32) (~0) & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0228) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x02AA) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E07) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0201) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ? 5:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E22) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0412) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0x2) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 6:4) - (0 ?
+ 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ?
+ 26:24))) | (((gctUINT32) ((gctUINT32) (0x3) & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ?
+ 26:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:24) - (0 ? 26:24) + 1))))))) << (0 ? 26:24)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0249) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0247) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ThreadAllocation;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalOffsetX;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024D) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalOffsetY;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x024F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalOffsetZ;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0256) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalScaleX;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0257) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalScaleY;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0258) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = GlobalScaleZ;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0250) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = groupCountX - 1;
+    commands[index++] = groupCountY - 1;
+    commands[index++] = groupCountZ - 1;
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (GroupSizeX - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (GroupSizeY - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (GroupSizeZ - 1) & ((gctUINT32) ((((1 ?
+ 9:0) - (0 ?
+ 9:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ? 9:0)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0248) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0xBADABEEB;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ?
+ 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ?
+ 10:10) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1))))))) << (0 ? 10:10)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ?
+ 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1))))))) << (0 ? 11:11)));
+
+    bytes = gcmSIZEOF(gctUINT32) * index;
+
+    endLogical = (gctUINT8_PTR)bufferLogical + bytes;
+    endAddress = bufferAddress + bytes;
+
+    if (Hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(Hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(Hardware, endLogical, endAddress, &endBytes));
+    }
+
+    bytes += endBytes;
+
+    gcmkASSERT(bytes <= bufferBytes);
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+    Command->funcVidMem = bufferNode;
+    Command->funcVidMemBytes = bufferBytes;
+    Command->logical = bufferLogical;
+    Command->address = bufferAddress;
+    Command->bytes = bytes;
+    Command->endAddress = endAddress;
+    Command->endLogical = endLogical;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+/*
+**  gckHARDWARE_ResetFlopWithPPU
+**
+**  Generate the command to do PPU program as follows.
+**      InImage: 64x6 = {1}, unsigned int8
+**      OutImage: 64x6, unsigned int8
+**      OutImage = InImage + InImage
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**
+**      gctUINT32 AllocFlag
+**
+**      gcePOOL *Pool
+**
+**  OUTPUT:
+**
+**      gcePOOL *Pool
+**
+**      gcsFUNCTION_COMMAND *Command
+*/
+gceSTATUS
+gckHARDWARE_ResetFlopWithPPU(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND *Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 dataType = 0x7;
+    gcsFEATURE_DATABASE *database = gcvNULL;
+    gctUINT32 numShaderCores;
+    gctUINT32 stride, width, height;
+    gctUINT32 workDim;
+    gctUINT32 valueOrder;
+    gctUINT32 groupSizeX, groupSizeY, groupSizeZ;
+    gctUINT32 globalScaleX, globalScaleY, globalScaleZ;
+    gctUINT32 globalOffsetX, globalOffsetY, globalOffsetZ;
+    gctUINT32 threadAllocation;
+    gctUINT32 inImageAddress = 0, outImageAddress = 0, instAddress = 0;
+    gctUINT32 instCount = 0, regCount = 0;
+    gctUINT32 dataCount;
+    gctPOINTER pointer = gcvNULL;
+    gcsFUNCTION_EXECUTION_DATA *data = gcvNULL;
+    gctUINT32 i;
+
+    /* Exectution data. */
+    dataCount = gcvFLOP_RESET_PPU_DATA_NUM;
+    gcmkASSERT(dataCount > 0);
+
+    gcmkONERROR(gckOS_Allocate(
+        Hardware->os,
+        gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount,
+        &pointer
+        ));
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount);
+    data = (gcsFUNCTION_EXECUTION_DATA_PTR)pointer;
+
+    database = (gcsFEATURE_DATABASE *)Hardware->featureDatabase;
+
+    numShaderCores = database->NumShaderCores;
+
+    stride = PPU_IMAGE_XSIZE * 1;
+    width = PPU_IMAGE_XSIZE;
+    height = PPU_IMAGE_YSIZE;
+
+    gcmkONERROR(_ProgramPPUInput(
+        Hardware,
+        width,
+        height,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_PPU_INPUT]
+        ));
+
+    gcmkONERROR(_ProgramPPUOutput(
+        Hardware,
+        width,
+        height,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_PPU_OUTPUT]
+        ));
+
+    gcmkONERROR(_ProgramPPUInstruction(
+        Hardware,
+        dataType,
+        AllocFlag,
+        Pool,
+        &instCount,
+        &regCount,
+        &data[gcvFLOP_RESET_PPU_INSTRUCTION]
+        ));
+
+    workDim = 0x2;
+    valueOrder = 0x2;
+    groupSizeX = 1;
+    groupSizeY = 1;
+    groupSizeZ = 0;
+    globalScaleX = 4;
+    globalScaleY = 1;
+    globalScaleZ = 0;
+    globalOffsetX = 0;
+    globalOffsetY = 0;
+    globalOffsetZ = 0;
+    threadAllocation = (groupSizeX * groupSizeY + numShaderCores * 4 - 1) / (numShaderCores * 4);
+    inImageAddress = data[gcvFLOP_RESET_PPU_INPUT].address;
+    outImageAddress = data[gcvFLOP_RESET_PPU_OUTPUT].address;
+    instAddress = data[gcvFLOP_RESET_PPU_INSTRUCTION].address;
+
+    gcmkONERROR(_ProgramPPUCommand(
+        Hardware,
+        stride,
+        width,
+        height,
+        workDim,
+        valueOrder,
+        groupSizeX,
+        groupSizeY,
+        groupSizeZ,
+        globalScaleX,
+        globalScaleY,
+        globalScaleZ,
+        globalOffsetX,
+        globalOffsetY,
+        globalOffsetZ,
+        threadAllocation,
+        inImageAddress,
+        outImageAddress,
+        instAddress,
+        instCount,
+        regCount,
+        AllocFlag,
+        Pool,
+        Command
+        ));
+
+    Command->data = data;
+    Command->dataCount = dataCount;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (Command->funcVidMem)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            Command->funcVidMem
+            ));
+        Command->funcVidMem = gcvNULL;
+    }
+
+    if (data)
+    {
+        for (i = 0; i < dataCount; i++)
+        {
+            if (data[i].bufVidMem)
+            {
+                gcmkVERIFY_OK(_FreeVideoMemory(
+                    Hardware->kernel,
+                    data[i].bufVidMem
+                    ));
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(Hardware->os, data));
+    }
+
+    return status;
+}
+
+/*
+ * NN
+ */
+static gceSTATUS
+_ProgramNNKernel(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT32 CoreCount,
+    IN gctUINT32 Zdp,
+    IN gctUINT8 DataType,
+    IN gctUINT32 KernelXSize,
+    IN gctUINT32 KernelYSize,
+    IN gctUINT32 KernelZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 filterBytes = 0;
+    gctUINT8_PTR kernels = gcvNULL;
+    gctUINT32 offset = 0;
+    gctUINT8_PTR kernelStreamSizePtr = gcvNULL;
+    gctUINT32 filterTotalCount = 1;
+    gctUINT32 itemBytes = 1;
+    gctUINT32 biasBytes = 4;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    filterBytes = KernelXSize * KernelYSize * KernelZSize * itemBytes;
+
+    /* Kernel buffer. */
+    if (gcvVIP_ARCH_TYPE_V8 == ArchType)
+    {
+        /* Head (align to 64) + body (align to 64) + tail (align to 64). */
+        gcmkASSERT(Zdp == 1 || Zdp == 3);
+        bufferBytes = 64 + gcmALIGN_NP2((gcmALIGN_NP2(filterBytes, Zdp * 3) * (Zdp * 3) * filterTotalCount) + (1 * (16 / itemBytes)), 64) + 64;
+    }
+    else
+    {
+        /* Head (align to 64) + body (align to 64). */
+        bufferBytes = 64 + gcmALIGN_NP2(((filterBytes + biasBytes +  3) * filterTotalCount + 3), 64);
+    }
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    kernels = (gctUINT8_PTR)bufferLogical;
+
+    /* V8 huffman encoder. */
+    if (gcvVIP_ARCH_TYPE_V8 == ArchType)
+    {
+        gctUINT32 i = 0;
+        gctUINT8 rlt[][18] = {
+            {0}, /* uint8 */
+            {1, 1, 0, 1}, /* fp16 */
+            {7, 1}, /* int8 */
+            {0}, /* uint16 */
+            {3, 1, 0, 1}, /* int16 */
+            {0}, /* uint4 */
+            {0}, /* int4 */
+            {1, 1, 0, 1}    /* bf16 */
+        };
+        gctUINT8 map[][9] = {
+            {1, 8, 7, 0, 4, 5, 6, 2, 3},
+            {1, 5, 0, 7, 8, 2, 6, 3, 4},
+            {1, 0, 7, 8, 4, 5, 6, 2, 3},
+        };
+        gctBOOL bit16 = DataType == 0x4 ||
+                        DataType == 0x1  ||
+                        DataType == 0x7;
+        gctBOOL fp16 = DataType == 0x1;
+        gctUINT32 index = 0;
+
+        if (Hardware->identity.customerID == 0x9f)
+        {
+            rlt[0][0] = 3;
+            rlt[0][1] = 1;
+            rlt[0][3] = 1;
+        }
+
+        gcmkONERROR(_GetMapIndex(DataType, &index));
+
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 1));        /* precode */
+        gcmkONERROR(_BitValue(&kernels, bit16, &offset, 1));    /* bit16 */
+        gcmkONERROR(_BitValue(&kernels, fp16, &offset, 1));     /* fp16 */
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 1));        /* reserved */
+        gcmkONERROR(_BitValue(&kernels, 1, &offset, 4));        /* version, 1 */
+        gcmkONERROR(_BitValue(&kernels, 4, &offset, 8));        /* zero run length size */
+
+        for (i = 0; i < 18; i++)
+        {
+            /* Zero run length x 18. */
+            gcmkONERROR(_BitValue(&kernels, rlt[DataType][i], &offset, 8));
+        }
+
+        for (i = 0; i < 4; i++)
+        {
+            /* Map x 4. */
+            gcmkONERROR(_BitValue(&kernels, (map[index][2 * i + 1] << 4) + map[index][2 * i], &offset, 8));
+        }
+
+        /* Avg bias */
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 16));
+
+        /* Reserved, must zero. */
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 16));
+
+        kernelStreamSizePtr = kernels;
+
+        for (i = 0; i < CoreCount; i ++)
+        {
+            /* Stream size. */
+            gcmkONERROR(_BitValue(&kernels, 0, &offset, 32));
+        }
+
+        kernels = (gctUINT8_PTR)bufferLogical + gcmALIGN_NP2((gctUINT32)((gctUINT8_PTR)kernels - (gctUINT8_PTR)bufferLogical), 64);
+
+        switch (DataType)
+        {
+        case 0x4:
+            /* Huffman data: 00000018 00924600 */
+            gcmkONERROR(_BitValue(&kernels, 0x04058000, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x640101fc, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x00001200, &offset, 32));
+
+            /* Only on core, stream size. */
+            gcmkONERROR(_BitValue(&kernelStreamSizePtr, 0x0000006d, &offset, 32));
+
+            break;
+
+        case 0x0:
+        case 0x2:
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0xec000038, &offset, 32));
+
+            /* Only on core, stream size. */
+            gcmkONERROR(_BitValue(&kernelStreamSizePtr, 0x35, &offset, 32));
+
+            break;
+
+        case 0x1:
+            /* Huffman data: 0009db68 000006c0 000001f0 00000900 00024000. */
+            gcmkONERROR(_BitValue(&kernels, 0x0009db68, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x000006c0, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x000001f0, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x00000900, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x00024000, &offset, 32));
+
+            /* Only on core, stream size. */
+            gcmkONERROR(_BitValue(&kernelStreamSizePtr, 0x000000a3, &offset, 32));
+
+            break;
+
+        case 0x7:
+            /* Huffman data: 0007fff8 7f00fdfc c0397f00 0900001f 40000000 00000002. */
+            gcmkONERROR(_BitValue(&kernels, 0x0007fff8, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x7f00fdfc, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0xc0397f00, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x0900001f, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x40000000, &offset, 32));
+            /* Huffman data. */
+            gcmkONERROR(_BitValue(&kernels, 0x00000002, &offset, 32));
+
+            /* Only on core, stream size. */
+            gcmkONERROR(_BitValue(&kernelStreamSizePtr, 0x000000b2, &offset, 32));
+
+            break;
+
+        default:
+            gcmkFATAL("Huffman encode not support this format! Please check!");
+            break;
+        }
+    }
+    else
+    {
+        gctBOOL zeroAll = gcvFALSE;
+        gctUINT8 zrl = 0;
+        gctUINT16 vzNum = 1;
+        gctUINT32 bias = 0;
+        gctUINT32 totalSize = gcmALIGN_NP2((filterTotalCount * (filterBytes + biasBytes +  3) + 3), 64);
+
+        gckOS_ZeroMemory(kernels, totalSize + 64);
+
+        *((gctUINT32_PTR)kernels) = totalSize;
+        kernels += totalSize;
+        if (zeroAll)
+        {
+            /*
+             * Zrl & coreFilterCount, both compressed weight and bias are zero,
+             * the size (1 * 1 * 2 * 2 + 4 ) < 64, aligned to 64.
+             */
+            *((gctUINT32_PTR)kernels) = (vzNum << (8 * itemBytes));
+        }
+        else
+        {
+            gctINT16 value = (DataType == 0x1) ? 0x3c00 /*1.0f*/ : 1;
+            gctUINT32 i = 0;
+
+            _BitValue(&kernels, zrl, &offset, 8);
+            _BitValue(&kernels, vzNum, &offset, 16);
+            _BitValue(&kernels, value, &offset, 8 * itemBytes);
+            _BitValue(&kernels, bias, &offset, 32);
+
+            if (DataType == 0x3 ||
+                DataType == 0x4)
+            {
+                _BitValue(&kernels, 0, &offset, 16);
+            }
+
+            for (i = 1; i < filterBytes / itemBytes; i++)
+            {
+                _BitValue(&kernels, value, &offset, 8 * itemBytes);
+            }
+        }
+    }
+
+    bytes = kernels + (offset + 7) / 8 - (gctUINT8_PTR)bufferLogical;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: nn kernel]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramNNInput(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT8 DataType,
+    IN gctUINT32 InImageXSize,
+    IN gctUINT32 InImageYSize,
+    IN gctUINT32 InImageZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA_PTR Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 inputSize = InImageXSize * InImageYSize * InImageZSize;
+    gctUINT32 itemBytes = 0;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+    gctUINT8_PTR buffer = gcvNULL;
+
+    gctUINT32 i = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 value[] = {
+        1, /* uint8 */
+        0x3c00, /* fp16 */
+        1, /* int8 */
+        1, /* uint16 */
+        1, /* int16 */
+        1, /* uint4 */
+        1, /* int4 */
+        0x3f80  /* bf16 */
+    };
+
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    bufferBytes = inputSize * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    if (gcvVIP_ARCH_TYPE_V8 == ArchType)
+    {
+        value[0x4] = 0x81;
+    }
+
+    buffer = (gctUINT8_PTR)bufferLogical;
+
+    for (i = 0; i < inputSize; i++)
+    {
+        _BitValue(&buffer, value[DataType], &offset, itemBytes * 8);
+    }
+
+    bytes = buffer + (offset + 7) / 8 - (gctUINT8_PTR)bufferLogical;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: nn input]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkVERIFY_OK(_FreeVideoMemory(
+        Hardware->kernel,
+        bufferNode
+        ));
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramNNOutput(
+    IN gckHARDWARE Hardware,
+    IN gctUINT8 DataType,
+    IN gctUINT32 OutputXSize,
+    IN gctUINT32 OutputYSize,
+    IN gctUINT32 OutputZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 itemBytes = 0;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+
+    if (!Data)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    bufferBytes = bytes = OutputXSize * OutputYSize * OutputZSize * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkVERIFY_OK(_FreeVideoMemory(
+        Hardware->kernel,
+        bufferNode
+        ));
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramNNInstruction(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT8 DataType,
+    IN gctUINT32 InImageXSize,
+    IN gctUINT32 InImageYSize,
+    IN gctUINT32 OutImageXSize,
+    IN gctUINT32 OutImageYSize,
+    IN gctUINT32 OutImageZSize,
+    IN gctUINT32 KernelXSize,
+    IN gctUINT32 KernelYSize,
+    IN gctUINT32 KernelZSize,
+    IN gctUINT32 InImageAddress,
+    IN gctUINT32 OutImageAddress,
+    IN gctUINT32 KernelAddress,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA_PTR Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckOS os = Hardware->os;
+
+    gctUINT32 itemBytes;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+    gctUINT32 *command = gcvNULL;
+
+    gctUINT8 kernelDataType;
+    gctUINT8 inImageDataType;
+    gctUINT8 outImageDataType;
+
+    gctUINT32 kernelsPerCore = 1;
+
+    gctUINT32 nnLayerFlush = 1;
+    gctUINT32 noZOffset = 0;
+    gctUINT32 imageEndAddress = 2048;
+    gctUINT32 postShift = 0;
+    gctUINT32 postShiftBit56 = 0;
+    gctUINT8 coefZP = 0;
+    gctUINT8 outputZP = 0;
+
+    bufferBytes = bytes = gcmSIZEOF(gctUINT32) * ((ArchType == gcvVIP_ARCH_TYPE_V6) ? 16 : 32);
+
+    /* Allocate buffer. */
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    command = (gctUINT32_PTR)bufferLogical;
+
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    kernelDataType   =
+    inImageDataType  =
+    outImageDataType = DataType;
+
+    switch (ArchType)
+    {
+    case gcvVIP_ARCH_TYPE_V8:
+        noZOffset = 1;
+        outputZP = 0;
+        postShift = (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_FLOAT_POST_MULT)) ? 0x1f : 0;
+        postShiftBit56 = (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_FLOAT_POST_MULT)) ? 3 : 0;
+        break;
+
+    case gcvVIP_ARCH_TYPE_V7:
+    case gcvVIP_ARCH_TYPE_V6:
+        postShift = (DataType == 0x2) ? 15 : 0;
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+        break;
+    }
+
+    /* gcregNNInstWord0 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (noZOffset) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1))))))) << (0 ?
+ 5:2))) | (((gctUINT32) ((gctUINT32) (KernelXSize) & ((gctUINT32) ((((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:2) - (0 ? 5:2) + 1))))))) << (0 ? 5:2)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1))))))) << (0 ?
+ 19:6))) | (((gctUINT32) ((gctUINT32) ((KernelZSize & 0x3FFF)) & ((gctUINT32) ((((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:6) - (0 ? 19:6) + 1))))))) << (0 ? 19:6)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1))))))) << (0 ?
+ 26:20))) | (((gctUINT32) ((gctUINT32) (kernelsPerCore) & ((gctUINT32) ((((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:20) - (0 ? 26:20) + 1))))))) << (0 ? 26:20)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1))))))) << (0 ?
+ 28:27))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 28:27) - (0 ? 28:27) + 1))))))) << (0 ? 28:27)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ?
+ 29:29))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (nnLayerFlush) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+        );
+
+    /* gcregNNInstWord1 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1))))))) << (0 ?
+ 18:6))) | (((gctUINT32) ((gctUINT32) (InImageXSize) & ((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:6) - (0 ? 18:6) + 1))))))) << (0 ? 18:6)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1))))))) << (0 ?
+ 31:19))) | (((gctUINT32) ((gctUINT32) (InImageYSize) & ((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:19) - (0 ? 31:19) + 1))))))) << (0 ? 31:19)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (kernelDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (inImageDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (outImageDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+        );
+
+    /* gcregNNInstWord2 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ?
+ 24:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))))) << (0 ?
+ 25:25))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:25) - (0 ? 25:25) + 1))))))) << (0 ? 25:25)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))))) << (0 ?
+ 5:3))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:3) - (0 ? 5:3) + 1))))))) << (0 ? 5:3)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1))))))) << (0 ?
+ 23:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:8) - (0 ? 23:8) + 1))))))) << (0 ? 23:8)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) ((gctUINT32) (postShift) & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+        );
+
+    /* gcregNNInstWord3 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1))))))) << (0 ?
+ 18:6))) | (((gctUINT32) ((gctUINT32) (OutImageXSize) & ((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:6) - (0 ? 18:6) + 1))))))) << (0 ? 18:6)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1))))))) << (0 ?
+ 31:19))) | (((gctUINT32) ((gctUINT32) (OutImageYSize) & ((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:19) - (0 ? 31:19) + 1))))))) << (0 ? 31:19)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+        );
+
+    /* gcregNNInstWord4 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1))))))) << (0 ?
+ 13:0))) | (((gctUINT32) ((gctUINT32) (OutImageZSize) & ((gctUINT32) ((((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:0) - (0 ? 13:0) + 1))))))) << (0 ? 13:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1))))))) << (0 ?
+ 24:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:18) - (0 ? 24:18) + 1))))))) << (0 ? 24:18)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1))))))) << (0 ?
+ 31:25))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:25) - (0 ? 31:25) + 1))))))) << (0 ? 31:25)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) ((0 >> 3) & 0x1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) ((0 >> 3) & 0x1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)))
+        );
+
+    /* gcregNNInstWord5 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1))))))) << (0 ?
+ 31:26))) | (((gctUINT32) ((gctUINT32) (((KernelZSize >> 14) & 0x3F)) & ((gctUINT32) ((((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:26) - (0 ? 31:26) + 1))))))) << (0 ? 31:26)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) ((KernelAddress >> 6)) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+        );
+
+    /* gcregNNInstWord6 */
+    gcmkWRITE_MEMORY(command, InImageAddress);
+
+    /* gcregNNInstWord7 */
+    gcmkWRITE_MEMORY(command, OutImageAddress);
+
+    /* gcregNNInstWord8 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1))))))) << (0 ?
+ 15:12))) | (((gctUINT32) ((gctUINT32) (KernelYSize) & ((gctUINT32) ((((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1))))))) << (0 ? 15:12)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (OutImageYSize) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16)))
+        );
+
+    /* gcregNNInstWord9 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* gcregNNInstWord10 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* gcregNNInstWord11 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* gcregNNInstWord12 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* gcregNNInstWord13 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* gcregNNInstWord14 */
+    gcmkWRITE_MEMORY(command, imageEndAddress);
+
+    /* gcregNNInstWord15 */
+    gcmkWRITE_MEMORY(
+        command,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1))))))) << (0 ?
+ 17:2))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:2) - (0 ? 17:2) + 1))))))) << (0 ? 17:2)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 2) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 2) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ?
+ 21:21))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 2) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1))))))) << (0 ?
+ 27:22))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:22) - (0 ? 27:22) + 1))))))) << (0 ? 27:22)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) ((gctUINT32) (postShiftBit56) & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28)))
+        );
+
+    /* V7 or V8 */
+    if (ArchType == gcvVIP_ARCH_TYPE_V7 ||
+        ArchType == gcvVIP_ARCH_TYPE_V8)
+    {
+        /* gcregNNInstWord16 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (InImageXSize * itemBytes) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (InImageYSize) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16)))
+            );
+
+        /* gcregNNInstWord17 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (OutImageXSize * itemBytes) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24)))
+            );
+
+        /* gcregNNInstWord18 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0 >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ?
+ 29:29))) | (((gctUINT32) ((gctUINT32) ((0 >> 4) & 0x1) & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) ((0 >> 4) & 0x1) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1))))))) << (0 ?
+ 28:28))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 28:28) - (0 ? 28:28) + 1))))))) << (0 ? 28:28)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 3) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+            );
+
+        /* 25:0 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0xFFFFFFFF >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 3) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+            );
+
+        /* GCREG_NN_INST_WORD20 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0 >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 3) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+            );
+
+        /* 25:0 */
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0xFFFFFFFF >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+            );
+
+        /*GCREG_NN_INST_WORD22*/
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (coefZP) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (outputZP) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1))))))) << (0 ?
+ 25:18))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:18) - (0 ? 25:18) + 1))))))) << (0 ? 25:18)))
+            );
+
+        /*GCREG_NN_INST_WORD23*/
+        gcmkWRITE_MEMORY(command, 0);
+
+        /*GCREG_NN_INST_WORD24*/
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1))))))) << (0 ?
+ 31:4))) | (((gctUINT32) ((gctUINT32) (0 >> 4) & ((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:4) - (0 ? 31:4) + 1))))))) << (0 ? 31:4)))
+            );
+
+        /*GCREG_NN_INST_WORD25*/
+        gcmkWRITE_MEMORY(
+            command,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1))))))) << (0 ?
+ 31:4))) | (((gctUINT32) ((gctUINT32) (0 >> 4) & ((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:4) - (0 ? 31:4) + 1))))))) << (0 ? 31:4)))
+            );
+    }
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: nn instruction]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramNNCommand(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT32 KernelBurstSize,
+    IN gctUINT32 InstAddress,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes;
+    gctUINT32 bytes;
+    gctUINT8_PTR endLogical;
+    gctUINT32 endAddress;
+    gctUINT32 endBytes = 0;
+    gcsFEATURE_DATABASE *database = (gcsFEATURE_DATABASE *)(Hardware->featureDatabase);
+    gctUINT32 index = 0;
+    gctINT32 disableZDPN = 1, disableSWTiling = 1;
+    gctBOOL enableNNStride = gcvFALSE;
+    gctUINT32 smallBatch;
+    gctUINT32 ddrBurstSize;
+    gctUINT32 *commands = gcvNULL;
+
+    bufferBytes = gcmSIZEOF(gctUINT32) * MAX_NN_COMMAND_NUM;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    commands = (gctUINT32 *)bufferLogical;
+
+    disableZDPN = (database->NN_ZDP3 || database->NN_ZDP6) ? 0 : 1;
+
+    enableNNStride = database->NN_STRIDE_SUPPORT;
+    disableSWTiling = enableNNStride ? 0 : 1;
+
+    if (Hardware->identity.chipModel == 0x8000 &&
+        Hardware->identity.chipRevision == 0x7120 &&
+        (Hardware->identity.customerID == 0x80 ||
+         Hardware->identity.customerID == 0x92))
+    {
+        smallBatch = 0x0;
+    }
+    else
+    {
+        smallBatch = (database->NN_SMALLBATCH_PHASE1 && database->NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX)
+                     ? 0x0 : 0x1;
+    }
+
+    switch(KernelBurstSize)
+    {
+    case 256:
+        ddrBurstSize = 0x2;
+        break;
+
+    case 64:
+    default:
+        ddrBurstSize = 0x0;
+        break;
+    }
+
+    commands = (gctUINT32_PTR)bufferLogical;
+
+    if (gcvVIP_ARCH_TYPE_V6 == ArchType)
+    {
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        commands[index++] = 0;
+
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+    }
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = Hardware->options.sRAMGPUVirtAddrs[0];
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E50) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0x00000000;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (disableZDPN) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (disableSWTiling) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (smallBatch) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1))))))) << (0 ?
+ 6:5))) | (((gctUINT32) ((gctUINT32) (ddrBurstSize) & ((gctUINT32) ((((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:5) - (0 ? 6:5) + 1))))))) << (0 ? 6:5)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E54) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0428) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1))))))) << (0 ?
+ 31:6))) | (((gctUINT32) ((gctUINT32) ((InstAddress >> 6)) & ((gctUINT32) ((((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:6) - (0 ? 31:6) + 1))))))) << (0 ? 31:6)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0429) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = 0;
+
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    commands[index++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+
+    bytes = gcmSIZEOF(gctUINT32) * index;
+
+    endLogical = (gctUINT8_PTR)bufferLogical + bytes;
+    endAddress = bufferAddress + bytes;
+
+    if (Hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(Hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(Hardware, endLogical, endAddress, &endBytes));
+    }
+
+    bytes += endBytes;
+
+    gcmkASSERT(bytes <= bufferBytes);
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+    Command->funcVidMem = bufferNode;
+    Command->funcVidMemBytes = bufferBytes;
+    Command->logical = bufferLogical;
+    Command->address = bufferAddress;
+    Command->bytes = bytes;
+    Command->endAddress = endAddress;
+    Command->endLogical = endLogical;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkONERROR(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckHARDWARE_ResetFlopWithNN(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND *Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 kernelXSize = NN_KERNEL_XSIZE;
+    gctUINT32 kernelYSize = NN_KERNEL_YSIZE;
+    gctUINT32 kernelZSize = NN_KERNEL_ZSIZE;
+
+    gctUINT32 inImageXSize = NN_INPUT_XSIZE;
+    gctUINT32 inImageYSize = NN_INPUT_YSIZE;
+    gctUINT32 inImageZSize = NN_INPUT_ZSIZE;
+
+    gctUINT32 outImageXSize = NN_OUTPUT_XSIZE;
+    gctUINT32 outImageYSize = NN_OUTPUT_YSIZE;
+    gctUINT32 outImageZSize = NN_OUTPUT_ZSIZE;
+
+    gctUINT32 i;
+    gctPOINTER pointer = gcvNULL;
+
+    gceVIP_ARCH_TYPE archType;
+    gctUINT8 dataType;
+    gctUINT32 coreCount = 0;
+    gctUINT32 itemBytes = 0;
+    gctUINT32 zdp = 1;
+    gctUINT32 kernelBurstSize;
+    gcsFUNCTION_EXECUTION_DATA_PTR data = gcvNULL;
+    gctUINT32 dataCount = 0;
+
+    if (!Command)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkONERROR(_GetVIPCoreInfo(
+        Hardware,
+        &archType,
+        &dataType,
+        &coreCount,
+        &zdp,
+        &kernelBurstSize
+        ));
+
+    gcmkONERROR(_GetNNDataSize(dataType, &itemBytes));
+
+    /* Exectution data. */
+    dataCount = gcvFLOP_RESET_NN_DATA_NUM;
+    gcmkASSERT(dataCount > 0);
+
+    gcmkONERROR(gckOS_Allocate(
+        Hardware->os,
+        gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount,
+        &pointer
+        ));
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount);
+    data = (gcsFUNCTION_EXECUTION_DATA *)pointer;
+
+    /* Kernel. */
+    gcmkONERROR(_ProgramNNKernel(
+        Hardware,
+        archType,
+        coreCount,
+        zdp,
+        dataType,
+        kernelXSize,
+        kernelYSize,
+        kernelZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_NN_KERNEL]
+        ));
+
+    /* Input. */
+    gcmkONERROR(_ProgramNNInput(
+        Hardware,
+        archType,
+        dataType,
+        inImageXSize,
+        inImageYSize,
+        inImageZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_NN_INPUT]
+        ));
+
+    /* Output. */
+    gcmkONERROR(_ProgramNNOutput(
+        Hardware,
+        dataType,
+        outImageXSize,
+        outImageYSize,
+        outImageZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_NN_OUTPUT]
+        ));
+
+    /* Commands. */
+    gcmkONERROR(_ProgramNNInstruction(
+        Hardware,
+        archType,
+        dataType,
+        inImageXSize,
+        inImageYSize,
+        outImageXSize,
+        outImageYSize,
+        outImageZSize,
+        kernelXSize,
+        kernelYSize,
+        kernelZSize,
+        data[gcvFLOP_RESET_NN_INPUT].address,
+        data[gcvFLOP_RESET_NN_OUTPUT].address,
+        data[gcvFLOP_RESET_NN_KERNEL].address,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_NN_INSTRUCTION]
+        ));
+
+    gcmkONERROR(_ProgramNNCommand(
+        Hardware,
+        archType,
+        kernelBurstSize,
+        data[gcvFLOP_RESET_NN_INSTRUCTION].address,
+        AllocFlag,
+        Pool,
+        Command
+        ));
+
+    Command->data = data;
+    Command->dataCount = dataCount;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (Command && Command->funcVidMem)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            Command->funcVidMem
+            ));
+        Command->funcVidMem = gcvNULL;
+    }
+
+    if (data)
+    {
+        for (i = 0; i < dataCount; i++)
+        {
+            if (data[i].bufVidMem)
+            {
+                gcmkVERIFY_OK(_FreeVideoMemory(
+                    Hardware->kernel,
+                    data[i].bufVidMem
+                    ));
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(Hardware->os, data));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramTPKernel(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT32 CoreCount,
+    IN gctUINT32 Zdp,
+    IN gctUINT8 DataType,
+    IN gctUINT32 KernelXSize,
+    IN gctUINT32 KernelYSize,
+    IN gctUINT32 KernelZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress =0;
+    gctSIZE_T bufferBytes = 0x3C0;
+    gctUINT32 *buffer = gcvNULL;
+    gctUINT32 i;
+
+
+    /* hardcode */
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    buffer = (gctUINT32_PTR)bufferLogical;
+
+    /* Fill the data. */
+    for (i = 0; i < bufferBytes / 4; i++)
+    {
+        buffer[i] = 0;
+    }
+
+    buffer[0] = 0x01150410;
+    buffer[1] = buffer[81] = buffer[161] = 0x00000100;
+    buffer[5] = buffer[85] = buffer[165] = 0x26543780;
+    buffer[6] = buffer[86] = buffer[166] = 0x000000ff;
+    buffer[7] = buffer[87] = buffer[167] = 0x0006801a;
+    buffer[48] = buffer[128] = buffer[208] = 0x00024938;
+    buffer[64] = buffer[144] = buffer[224] = 0x00024938;
+    buffer[80] = buffer[160] = 0x01140410;
+
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bufferBytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: TP kernel]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bufferBytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bufferBytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramTPInput(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT8 DataType,
+    IN gctUINT32 InImageXSize,
+    IN gctUINT32 InImageYSize,
+    IN gctUINT32 InImageZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA_PTR Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 inputSize = InImageXSize * InImageYSize * InImageZSize;
+    gctUINT32 itemBytes = 0;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+    gctUINT8_PTR buffer = gcvNULL;
+
+    gctUINT32 i = 0;
+    gctUINT32 offset = 0;
+    gctUINT32 value[] = {
+        0xff, /* uint8, the case set scale = 0.003921569*/
+        0x3c00, /* fp16 */
+        1, /* int8 */
+        1, /* uint16 */
+        1, /* int16 */
+        1, /* uint4 */
+        1, /* int4 */
+        0x3f80  /* bf16 */
+    };
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    bufferBytes = inputSize * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    if (gcvVIP_ARCH_TYPE_V8 == ArchType)
+    {
+        value[0x4] = 0x81;
+    }
+
+    buffer = (gctUINT8_PTR)bufferLogical;
+
+    for (i = 0; i < inputSize; i++)
+    {
+        _BitValue(&buffer, value[DataType], &offset, itemBytes * 8);
+    }
+
+    bytes = buffer + (offset + 7) / 8 - (gctUINT8_PTR)bufferLogical;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: TP input]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkVERIFY_OK(_FreeVideoMemory(
+        Hardware->kernel,
+        bufferNode
+        ));
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramTPOutput(
+    IN gckHARDWARE Hardware,
+    IN gctUINT8 DataType,
+    IN gctUINT32 OutputXSize,
+    IN gctUINT32 OutputYSize,
+    IN gctUINT32 OutputZSize,
+    IN gctUINT32 AllocFlag,
+    IN OUT gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA *Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 itemBytes = 0;
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+
+    if (!Data)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gcmkONERROR(_GetNNDataSize(DataType, &itemBytes));
+
+    bufferBytes = bytes = OutputXSize * OutputYSize * OutputZSize * itemBytes;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_BITMAP,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkVERIFY_OK(_FreeVideoMemory(
+        Hardware->kernel,
+        bufferNode
+        ));
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramTPInstruction(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT8 DataType,
+    IN gctUINT32 InImageXSize,
+    IN gctUINT32 InImageYSize,
+    IN gctUINT32 OutImageXSize,
+    IN gctUINT32 OutImageYSize,
+    IN gctUINT32 OutImageZSize,
+    IN gctUINT32 KernelXSize,
+    IN gctUINT32 KernelYSize,
+    IN gctUINT32 KernelZSize,
+    IN gctUINT32 InImageAddress,
+    IN gctUINT32 OutImageAddress,
+    IN gctUINT32 KernelAddress,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_EXECUTION_DATA_PTR Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes, bytes;
+    gctUINT32 *command = gcvNULL;
+    gctUINT32 i;
+
+    bufferBytes = bytes = 0x180;
+
+    /* Allocate buffer. */
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    command = (gctUINT32_PTR)bufferLogical;
+
+    /* Fill the data. */
+    for (i = 0; i < bufferBytes / 4; i++)
+    {
+        command[i] = 0;
+    }
+
+    for (i = 0; i < 3; i++)
+    {
+        command[0] = command[2] = command[3] = command[20] = 0x00000001;
+        command[1] = 0x00020001;
+        command[8] = command[9] = command[16] = command[19] = 0x00010001;
+        command[10] = InImageAddress;
+        command[24] = 0x0000240a;
+        command[26] = command[28] = 0x03ffffff;
+        command[30] = 0x00008100;
+        command = command + 32;
+    }
+
+    command = (gctUINT32_PTR)bufferLogical;
+
+    command[6] = 0xa0002a1b;
+    command[38] = command[70] = 0xa000281b;
+    command[12] = command[44] = 0xc0000002;
+    command[76] = 0x80000002;
+    command[22] = 0x00010016;
+    command[54] = command[86] = 0x00010015;
+    command[11] = KernelAddress;
+    command[43] = KernelAddress + 0x140;
+    command[75] = KernelAddress + 0x280;
+    command[13] = OutImageAddress;
+    command[45] = OutImageAddress + 0x16;
+    command[77] = OutImageAddress + 0x2b;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+#if gcdDUMP_IN_KERNEL
+    gcmkDUMP(Hardware->os, "#[flop reset: TP instruction]");
+    gcmkDUMP_BUFFER(
+        Hardware->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        bufferLogical,
+        bufferAddress,
+        bytes
+        );
+#endif
+
+    Data->bufVidMem = bufferNode;
+    Data->bufVidMemBytes = bufferBytes;
+    Data->address = bufferAddress;
+    Data->logical = bufferLogical;
+    Data->bytes = bytes;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ProgramTPCommand(
+    IN gckHARDWARE Hardware,
+    IN gceVIP_ARCH_TYPE ArchType,
+    IN gctUINT32 InstAddress,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gckVIDMEM_NODE bufferNode = gcvNULL;
+    gctPOINTER bufferLogical = gcvNULL;
+    gctUINT32 bufferAddress = 0;
+    gctSIZE_T bufferBytes;
+    gctUINT32 bytes;
+    gctUINT32 *commands;
+
+    gctUINT8_PTR endLogical;
+    gctUINT32 endAddress;
+    gctUINT32 endBytes = 0;
+    gctUINT32 i = 0;
+    gctUINT32 k;
+
+    bufferBytes = gcmSIZEOF(gctUINT32) * 64;
+
+    gcmkONERROR(_AllocateVideoMemory(
+        Hardware->kernel,
+        gcvVIDMEM_TYPE_COMMAND,
+        AllocFlag,
+        Pool,
+        &bufferBytes,
+        &bufferNode,
+        &bufferLogical,
+        &bufferAddress
+        ));
+
+    commands = (gctUINT32_PTR)bufferLogical;
+    for (i = 0; i < 3; i++)
+    {
+        k = 14 * i;
+        commands[0 + k] = 0x08010e4e;
+        commands[1 + k] = 0x00400000;
+        commands[2 + k] = 0x08010e4f;
+        commands[3 + k] = 0x00000000;
+        commands[4 + k] = 0x08010e50;
+        commands[5 + k] = 0x00000000;
+        commands[6 + k] = 0x08010e53;
+        commands[7 + k] = 0x00000000;
+        commands[8 + k] = 0x08010e54;
+        commands[9 + k] = 0x00000008;
+        commands[10 + k] = 0x08010e27;
+        commands[11 + k] = 0x00000000;
+        commands[12 + k] = 0x0801042e;
+    }
+
+    commands[13] = (InstAddress & 0xffffffC0) | (0x1);
+    commands[27] = ((InstAddress + 0x80) & 0xffffffC0) | (0x1);
+    commands[37] = 0x00000000;
+    commands[41] = ((InstAddress + 0x100) & 0xffffffC0);
+    commands[42] = 0x08010429;
+    commands[43] = 0;
+    commands[44] = 0x08010E03;
+    commands[45] = 0x20;
+
+    bytes = 46 * 4;
+
+    endLogical = (gctUINT8_PTR)bufferLogical + bytes;
+    endAddress = bufferAddress + bytes;
+
+    if (Hardware->wlFE)
+    {
+        gcmkONERROR(gckWLFE_End(Hardware, gcvNULL, ~0U, &endBytes));
+        gcmkONERROR(gckWLFE_End(Hardware, endLogical, endAddress, &endBytes));
+    }
+
+    bytes += endBytes;
+
+    gcmkASSERT(bytes <= bufferBytes);
+
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Hardware->kernel,
+        bufferNode,
+        0,
+        bufferLogical,
+        bytes
+        ));
+
+    Command->funcVidMem = bufferNode;
+    Command->funcVidMemBytes = bufferBytes;
+    Command->logical = bufferLogical;
+    Command->address = bufferAddress;
+    Command->bytes = bytes;
+    Command->endAddress = endAddress;
+    Command->endLogical = endLogical;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (bufferNode)
+    {
+        gcmkONERROR(_FreeVideoMemory(
+            Hardware->kernel,
+            bufferNode
+            ));
+    }
+
+    return status;
+}
+
+/*
+ * TP.
+ */
+gceSTATUS
+gckHARDWARE_ResetFlopWithTP(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT32 kernelXSize = TP_KERNEL_XSIZE;
+    gctUINT32 kernelYSize = TP_KERNEL_YSIZE;
+    gctUINT32 kernelZSize = TP_KERNEL_ZSIZE;
+
+    gctUINT32 inImageXSize = TP_INPUT_XSIZE;
+    gctUINT32 inImageYSize = TP_INPUT_YSIZE;
+    gctUINT32 inImageZSize = TP_INPUT_ZSIZE;
+
+    gctUINT32 outImageXSize = TP_OUTPUT_XSIZE;
+    gctUINT32 outImageYSize = TP_OUTPUT_YSIZE;
+    gctUINT32 outImageZSize = TP_OUTPUT_ZSIZE;
+
+    gctUINT32 i;
+    gctPOINTER pointer = gcvNULL;
+
+    gceVIP_ARCH_TYPE archType = gcvVIP_ARCH_TYPE_V8;
+    gctUINT8 dataType;
+    gctUINT32 coreCount = 0;
+    gctUINT32 zdp = 1;
+    gctUINT32 itemBytes = 0;
+    gcsFUNCTION_EXECUTION_DATA_PTR data = gcvNULL;
+    gctUINT32 dataCount = 0;
+
+    if (!Command)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    dataType = 0x0;
+
+    gcmkONERROR(_GetNNDataSize(dataType, &itemBytes));
+
+    /* Exectution data. */
+    dataCount = gcvFLOP_RESET_TP_DATA_NUM;
+    gcmkASSERT(dataCount > 0);
+
+    gcmkONERROR(gckOS_Allocate(
+        Hardware->os,
+        gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount,
+        &pointer
+        ));
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsFUNCTION_EXECUTION_DATA) * dataCount);
+    data = (gcsFUNCTION_EXECUTION_DATA *)pointer;
+
+    /* Kernel. */
+    gcmkONERROR(_ProgramTPKernel(
+        Hardware,
+        archType,
+        coreCount,
+        zdp,
+        dataType,
+        kernelXSize,
+        kernelYSize,
+        kernelZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_TP_KERNEL]
+        ));
+
+    /* Input. */
+    gcmkONERROR(_ProgramTPInput(
+        Hardware,
+        archType,
+        dataType,
+        inImageXSize,
+        inImageYSize,
+        inImageZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_TP_INPUT]
+        ));
+
+    /* Output. */
+    gcmkONERROR(_ProgramTPOutput(
+        Hardware,
+        dataType,
+        outImageXSize,
+        outImageYSize,
+        outImageZSize,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_TP_OUTPUT]
+        ));
+
+    /* Commands. */
+    gcmkONERROR(_ProgramTPInstruction(
+        Hardware,
+        archType,
+        dataType,
+        inImageXSize,
+        inImageYSize,
+        outImageXSize,
+        outImageYSize,
+        outImageZSize,
+        kernelXSize,
+        kernelYSize,
+        kernelZSize,
+        data[gcvFLOP_RESET_TP_INPUT].address,
+        data[gcvFLOP_RESET_TP_OUTPUT].address,
+        data[gcvFLOP_RESET_TP_KERNEL].address,
+        AllocFlag,
+        Pool,
+        &data[gcvFLOP_RESET_TP_INSTRUCTION]
+        ));
+
+    gcmkONERROR(_ProgramTPCommand(
+        Hardware,
+        archType,
+        data[gcvFLOP_RESET_TP_INSTRUCTION].address,
+        AllocFlag,
+        Pool,
+        Command
+        ));
+
+    Command->data = data;
+    Command->dataCount = dataCount;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (Command && Command->funcVidMem)
+    {
+        gcmkVERIFY_OK(_FreeVideoMemory(
+            Hardware->kernel,
+            Command->funcVidMem
+            ));
+        Command->funcVidMem = gcvNULL;
+    }
+
+    if (data)
+    {
+        for (i = 0; i < dataCount; i++)
+        {
+            if (data[i].bufVidMem)
+            {
+                gcmkVERIFY_OK(_FreeVideoMemory(
+                    Hardware->kernel,
+                    data[i].bufVidMem
+                    ));
+            }
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(Hardware->os, data));
+    }
+
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_flop_reset.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_flop_reset.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_func_flop_reset_h_
+#define __gc_hal_kernel_hardware_func_flop_reset_h_
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_hardware.h"
+
+gceSTATUS
+gckHARDWARE_ResetFlopWithPPU(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    );
+
+gceSTATUS
+gckHARDWARE_ResetFlopWithNN(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    );
+
+gceSTATUS
+gckHARDWARE_ResetFlopWithTP(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 AllocFlag,
+    IN gcePOOL *Pool,
+    OUT gcsFUNCTION_COMMAND_PTR Command
+    );
+#ifdef __cplusplus
+}
+#endif
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_ppu.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_ppu.h
@@ -0,0 +1,1157 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+//#include "gc_hal_user_hardware_precomp.h"
+//#include "gc_hal_user.h"
+/*
+**
+*/
+#if gcdINITIALIZE_PPU
+
+#define gcdRESET_PPU_SH         1
+
+
+#define INPUT_PPU_IDX            0
+#define OUTPUT_PPU_IDX            1
+#define INST_PPU_IDX            2
+
+#include "gc_feature_database.h"
+
+#define GCREG_SH_INSTRUCTION_TYPE_INVALID ~0U
+
+#define gcdVX_ENABLE ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+#define gcdVX_ENABLE4(X, Y, Z, W) ((1 << (X)) | (1 << (Y)) | (1 << (Z)) | (1 << (W)))
+#define gcdVX_ENABLE1(X) (1 << (X))
+#define gcdVX_ENABLE2(X, Y) ((1 << (X)) | (1 << (Y)))
+#define gcdVX_ENABLE3(X, Y, Z) ((1 << (X)) | (1 << (Y)) | (1 << (Z)))
+#define gcdVX_SWIZZLE (0 | (1 << 2) | (2 << 4) | (3 << 6))
+#define gcdVX_SWIZZLE1(X) ((X) | ((X) << 2) | ((X) << 4) | ((X) << 6))
+#define gcdVX_SWIZZLE2(X, Y) ((X) | ((Y) << 2) | ((Y) << 4) | ((Y) << 6))
+#define gcdVX_SWIZZLE4(X, Y, Z, W) ((X) | ((Y) << 2) | ((Z) << 4) | ((W) << 6))
+
+
+#define GETBIT(data, position) (((data) >> (position)) & 0x1)
+
+#define SETBIT(data, position, value)   (\
+            ((data) & (~((1ULL) << position)))   \
+             |  \
+             (((value) << position) & ((1ULL) << position))   \
+             )
+
+#define _START(reg_field)       (0 ? reg_field)
+#define _END(reg_field)         (1 ? reg_field)
+#define _GETSIZE(reg_field)     (_END(reg_field) - _START(reg_field) + 1)
+#define _ALIGN(data, reg_field) ((gctUINT32)(data) << _START(reg_field))
+#define _MASK(reg_field)        ((_GETSIZE(reg_field) == 32) \
+                                    ?  ~0 \
+                                    : (gctUINT32)(~((gctUINT64)(~0) << _GETSIZE(reg_field))))
+
+#define AQSETFIELD(data, reg, field, value) \
+(\
+    ((gctUINT32)(data) & ~_ALIGN(_MASK(reg##_##field), reg##_##field)) \
+        | \
+    _ALIGN((gctUINT32)(value) & _MASK(reg##_##field), reg##_##field) \
+)
+
+#define AQSETFIELDVALUE(data, reg, field, value) \
+(\
+    ((gctUINT32)(data) & ~_ALIGN(_MASK(reg##_##field), reg##_##field)) \
+        | \
+    _ALIGN(reg##_##field##_##value & _MASK(reg##_##field), reg##_##field) \
+)
+
+gctUINT32 HwFunc_SETBITS(
+    IN gctUINT32 Data,
+    IN const unsigned int Start,
+    IN const unsigned int End,
+    IN const gctUINT32 Value
+    )
+{
+    gctUINT32 data = Data;
+    if (End >= Start)
+    {
+        gctUINT32 _Mask =  ((~0ULL >> (63 - End + Start)) << Start);
+        data &= ~_Mask;
+        data |= ((Value) << Start) & _Mask;
+        return data;
+    }
+    else
+    {
+        gctUINT32 _Mask =  ((~0ULL >> (63 - Start + End)) << End);
+        data &= ~_Mask;
+        data |= ((Value) << End) & _Mask;
+        return data;
+    }
+}
+
+gctUINT32 HwFunc_GETBITS(
+    IN gctUINT32 Data,
+    IN const unsigned int Start,
+    IN const unsigned int End
+    )
+{
+    gctUINT32 data = Data;
+    if (End >= Start)
+    {
+        gctUINT32 _Mask = (~0ULL >> (63 - (End - Start)));
+        return (data >> Start) & _Mask;
+    }
+    else
+    {
+        gctUINT32 _Mask = (~0ULL >> (63 - (Start - End)));
+        return (data >> End) & _Mask;;
+    }
+}
+
+gceSTATUS
+_InitializePPU_SetImmediate(
+    IN gctUINT32                            Where,
+    IN gctUINT32                            Value,
+    IN gctUINT32                            Type,
+    IN OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Where=0x%x", Where);
+
+    switch (Where)
+    {
+        case 0:
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1))))) << (0 ?
+ 20:12))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 8, 0)) & ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 20:12) - (0 ? 20:12) + 1))))) << (0 ? 20:12)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1))))) << (0 ?
+ 29:22))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 16, 9)) & ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:22) - (0 ? 29:22) + 1))))) << (0 ? 29:22)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))) << (0 ?
+ 30:30))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 17)) & ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:30) - (0 ? 30:30) + 1))))) << (0 ? 30:30)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))) << (0 ?
+ 31:31))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 18)) & ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:31) - (0 ? 31:31) + 1))))) << (0 ? 31:31)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))) << (0 ?
+ 2:0))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 19) | (Type << 1)) & ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))) << (0 ? 2:0)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))) << (0 ?
+ 5:3))) | ((gctUINT32)((gctUINT32)(0x7) & ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:3) - (0 ? 5:3) + 1))))) << (0 ? 5:3)));
+            break;
+
+        case 1:
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1))))) << (0 ?
+ 15:7))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 8, 0)) & ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:7) - (0 ? 15:7) + 1))))) << (0 ? 15:7)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1))))) << (0 ?
+ 24:17))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 16, 9)) & ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 24:17) - (0 ? 24:17) + 1))))) << (0 ? 24:17)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))) << (0 ?
+ 25:25))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 17)) & ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 25:25) - (0 ? 25:25) + 1))))) << (0 ? 25:25)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))) << (0 ?
+ 26:26))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 18)) & ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:26) - (0 ? 26:26) + 1))))) << (0 ? 26:26)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1))))) << (0 ?
+ 29:27))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 19) | (Type << 1)) & ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:27) - (0 ? 29:27) + 1))))) << (0 ? 29:27)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))) << (0 ?
+ 2:0))) | ((gctUINT32)((gctUINT32)(0x7) & ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))) << (0 ? 2:0)));
+            break;
+
+        case 2:
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1))))) << (0 ?
+ 12:4))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 8, 0)) & ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:4) - (0 ? 12:4) + 1))))) << (0 ? 12:4)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1))))) << (0 ?
+ 21:14))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Value, 16, 9)) & ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:14) - (0 ? 21:14) + 1))))) << (0 ? 21:14)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))) << (0 ?
+ 22:22))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 17)) & ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:22) - (0 ? 22:22) + 1))))) << (0 ? 22:22)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))) << (0 ?
+ 23:23))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 18)) & ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 23:23) - (0 ? 23:23) + 1))))) << (0 ? 23:23)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1))))) << (0 ?
+ 27:25))) | ((gctUINT32)((gctUINT32)(GETBIT(Value, 19) | (Type << 1)) & ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 27:25) - (0 ? 27:25) + 1))))) << (0 ? 27:25)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))) << (0 ?
+ 30:28))) | ((gctUINT32)((gctUINT32)(0x7) & ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:28) - (0 ? 30:28) + 1))))) << (0 ? 30:28)));
+            break;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+_InitializePPU_SetInstructionType(
+    IN gctUINT32                            Type,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Type=0x%x", Type);
+
+    binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))) << (0 ?
+ 21:21))) | ((gctUINT32)((gctUINT32)(GETBIT(Type, 0)) & ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:21) - (0 ? 21:21) + 1))))) << (0 ? 21:21)));
+    binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1))))) << (0 ?
+ 31:30))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Type, 2, 1)) & ((((1 ?
+ 31:30) - (0 ?
+ 31:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:30) - (0 ? 31:30) + 1))))) << (0 ? 31:30)));
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+_InitializePPU_IsEndOfBB(
+    IN gckHARDWARE                            Hardware,
+    IN gctUINT32                            Opcode,
+    OUT gctUINT32_PTR                        binary
+)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcmkHEADER_ARG("Opcode=0x%x", Opcode);
+
+    if (binary != NULL)
+    {
+        if (((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->SH_END_OF_BB)
+        {
+            switch (Opcode)
+            {
+            case 0x09:
+            case 0x56:
+            case 0x0A:
+            case 0x0B:
+            case 0x0F:
+            case 0x31:
+            case 0x10:
+                binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1))))) << (0 ?
+ 10:3))) | ((gctUINT32)((gctUINT32)(HwFunc_SETBITS(binary[1], 3, 3, 1)) & ((((1 ?
+ 10:3) - (0 ?
+ 10:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:3) - (0 ? 10:3) + 1))))) << (0 ? 10:3)));
+                break;
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x46:
+                binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))) << (0 ?
+ 10:6))) | ((gctUINT32)((gctUINT32)(HwFunc_SETBITS(binary[0], 2, 2, 1)) & ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ? 10:6) + 1))))) << (0 ? 10:6)));
+                break;
+            case 0x32:
+            case 0x39:
+            case 0x33:
+            case 0x3A:
+            case 0x79:
+            case 0x34:
+            case 0x7A:
+            case 0x35:
+                binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))) << (0 ?
+ 10:6))) | ((gctUINT32)((gctUINT32)(HwFunc_SETBITS(binary[0], 2, 2, 1)) & ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ? 10:6) + 1))))) << (0 ? 10:6)));
+                break;
+            default:
+                if (Opcode != 0x16 &&
+                    Opcode != 0x24 &&
+                    Opcode != 0x14 &&
+                    Opcode != 0x15 &&
+                    Opcode != 0x17)
+                    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))) << (0 ?
+ 10:6))) | ((gctUINT32)((gctUINT32)(HwFunc_SETBITS(binary[0], 2, 2, 1)) & ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ? 10:6) + 1))))) << (0 ? 10:6)));
+                break;
+            }
+        }
+    }
+
+//OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+gceSTATUS
+_InitializePPU_AddOpcode(
+    IN gckHARDWARE                            Hardware,
+    IN gctUINT32                            Opcode,
+    IN gctUINT32                            Extended,
+    IN gctINT32                             Type,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Opcode=0x%x", Opcode);
+
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1))))) << (0 ?
+ 5:0))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Opcode, 5, 0)) & ((((1 ?
+ 5:0) - (0 ?
+ 5:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:0) - (0 ? 5:0) + 1))))) << (0 ? 5:0)));
+    binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))) << (0 ?
+ 16:16))) | ((gctUINT32)((gctUINT32)(GETBIT(Opcode, 6)) & ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 16:16) - (0 ? 16:16) + 1))))) << (0 ? 16:16)));
+    if (Opcode == 0x7F)
+    {
+        gcmkONERROR(_InitializePPU_SetImmediate(2, Extended, 0x2, binary));
+    }
+    else if (Opcode == 0x45)
+    {
+        binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1))))) << (0 ?
+ 15:13))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Extended, 2, 0)) & ((((1 ?
+ 15:13) - (0 ?
+ 15:13) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:13) - (0 ? 15:13) + 1))))) << (0 ? 15:13)));
+        binary[0] = SETBIT(binary[0], 31, GETBIT(Extended, 3));
+        binary[1] = HwFunc_SETBITS(binary[1], 1, 0, HwFunc_GETBITS(Extended, 5, 4));
+    }
+    else if (Opcode == 0x31 || Opcode == 0x09 || Opcode == 0x0F)
+    {
+        binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1))))) << (0 ?
+ 10:6))) | ((gctUINT32)((gctUINT32)(HwFunc_GETBITS(Extended, 4, 0)) & ((((1 ?
+ 10:6) - (0 ?
+ 10:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 10:6) - (0 ? 10:6) + 1))))) << (0 ? 10:6)));
+    }
+
+    if((gctUINT32)Type != GCREG_SH_INSTRUCTION_TYPE_INVALID)
+        gcmkONERROR(_InitializePPU_SetInstructionType(Type, binary));
+
+    gcmkONERROR(_InitializePPU_IsEndOfBB(Hardware, Opcode, binary));
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+_InitializePPU_SetDestination(
+    IN gctUINT32                            Address,
+    IN gctUINT32                            Enable,
+    IN gctBOOL                              Saturate,
+    IN OUT gctUINT32_PTR                    binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Address=0x%x", Address);
+
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))) << (0 ?
+ 12:12))) | ((gctUINT32)((gctUINT32)(1) & ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:12) - (0 ? 12:12) + 1))))) << (0 ? 12:12)));
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1))))) << (0 ?
+ 22:16))) | ((gctUINT32)((gctUINT32)(Address) & ((((1 ?
+ 22:16) - (0 ?
+ 22:16) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:16) - (0 ? 22:16) + 1))))) << (0 ? 22:16)));
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1))))) << (0 ?
+ 26:23))) | ((gctUINT32)((gctUINT32)(Enable) & ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:23) - (0 ? 26:23) + 1))))) << (0 ? 26:23)));
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))) << (0 ?
+ 11:11))) | ((gctUINT32)((gctUINT32)(Saturate) & ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 11:11) - (0 ? 11:11) + 1))))) << (0 ? 11:11)));
+
+    gcmkFOOTER();
+    return status;
+}
+
+#define gcdVX_ENABLE ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
+static gctUINT32 _InitializePPU_GetPixel(gctUINT32 format)
+{
+    gctUINT32 pixel = 0;
+    switch(format)
+    {
+    case 0x7:
+        pixel = 15;
+        break;
+    case 0x3:
+    case 0x6:
+        pixel = 7;
+        break;
+    default:
+        pixel = 15;
+        break;
+    }
+
+    return pixel;
+}
+
+gceSTATUS
+_InitializePPU_SetEVIS(
+    IN gctUINT32                            Start,
+    IN gctUINT32                            End,
+    IN gctUINT32                            Evis,
+    IN OUT gctUINT32_PTR                    binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Evis=0x%x", Evis);
+
+    binary[0] = (((gctUINT32)(binary[0]) & ~((gctUINT32)(((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1))))) << (0 ?
+ 26:23))) | ((gctUINT32)((gctUINT32)(Start) & ((((1 ?
+ 26:23) - (0 ?
+ 26:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:23) - (0 ? 26:23) + 1))))) << (0 ? 26:23)));
+    binary[0] = HwFunc_SETBITS(binary[0], 30, 27, End);
+    binary[1] = HwFunc_SETBITS(binary[1], 10, 2, Evis);
+
+    gcmkFOOTER();
+    return status;
+}
+
+#define HwFunc_SETSOURCE(Where, Common_I, REL_ADR_I, TYPE_I, Address, Swizzle, Type, Negate, Absolute, Relative, Binary) \
+    binary[Common_I] = AQSETFIELD(binary[Common_I], AQ_INST, SRCWhere_VALID, 1); \
+            binary[Common_I] = AQSETFIELD(binary[Common_I], AQ_INST, SRC0_ADR, Address); \
+            binary[Common_I] = AQSETFIELD(binary[Common_I], AQ_INST, SRC0_SWIZZLE, Swizzle); \
+            binary[Common_I] = AQSETFIELD(binary[Common_I], AQ_INST, SRC0_MODIFIER_NEG, Negate); \
+            binary[Common_I] = AQSETFIELD(binary[Common_I], AQ_INST, SRC0_MODIFIER_ABS, Absolute); \
+            binary[REL_ADR_I] = AQSETFIELD(binary[REL_ADR_I], AQ_INST, SRC0_REL_ADR, Relative); \
+            binary[TYPE_I] = AQSETFIELD(binary[TYPE_I], AQ_INST, SRC0_TYPE, Type);
+
+gceSTATUS
+_InitializePPU_SetSource(
+    IN gctUINT32                            Where,
+    IN gctUINT32                            Address,
+    IN gctUINT32                            Swizzle,
+    IN gctUINT32                            Type,
+    IN gctBOOL                              Negate,
+    IN gctBOOL                              Absolute,
+    IN gctUINT32                            Relative,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Where=0x%x", Where);
+    switch (Where)
+    {
+        case 0:
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1))))) << (0 ?
+ 11:11))) | ((gctUINT32)((gctUINT32)(1) & ((((1 ?
+ 11:11) - (0 ?
+ 11:11) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 11:11) - (0 ? 11:11) + 1))))) << (0 ? 11:11)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1))))) << (0 ?
+ 20:12))) | ((gctUINT32)((gctUINT32)(Address) & ((((1 ?
+ 20:12) - (0 ?
+ 20:12) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 20:12) - (0 ? 20:12) + 1))))) << (0 ? 20:12)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1))))) << (0 ?
+ 29:22))) | ((gctUINT32)((gctUINT32)(Swizzle) & ((((1 ?
+ 29:22) - (0 ?
+ 29:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:22) - (0 ? 29:22) + 1))))) << (0 ? 29:22)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))) << (0 ?
+ 30:30))) | ((gctUINT32)((gctUINT32)(Negate) & ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:30) - (0 ? 30:30) + 1))))) << (0 ? 30:30)));
+            binary[1] = (((gctUINT32)(binary[1]) & ~((gctUINT32)(((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))) << (0 ?
+ 31:31))) | ((gctUINT32)((gctUINT32)(Absolute) & ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 31:31) - (0 ? 31:31) + 1))))) << (0 ? 31:31)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))) << (0 ?
+ 2:0))) | ((gctUINT32)((gctUINT32)(Relative) & ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))) << (0 ? 2:0)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))) << (0 ?
+ 5:3))) | ((gctUINT32)((gctUINT32)(Type) & ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 5:3) - (0 ? 5:3) + 1))))) << (0 ? 5:3)));
+            break;
+
+        case 1:
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))) << (0 ?
+ 6:6))) | ((gctUINT32)((gctUINT32)(1) & ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 6:6) - (0 ? 6:6) + 1))))) << (0 ? 6:6)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1))))) << (0 ?
+ 15:7))) | ((gctUINT32)((gctUINT32)(Address) & ((((1 ?
+ 15:7) - (0 ?
+ 15:7) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 15:7) - (0 ? 15:7) + 1))))) << (0 ? 15:7)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1))))) << (0 ?
+ 24:17))) | ((gctUINT32)((gctUINT32)(Swizzle) & ((((1 ?
+ 24:17) - (0 ?
+ 24:17) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 24:17) - (0 ? 24:17) + 1))))) << (0 ? 24:17)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))) << (0 ?
+ 25:25))) | ((gctUINT32)((gctUINT32)(Negate) & ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 25:25) - (0 ? 25:25) + 1))))) << (0 ? 25:25)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))) << (0 ?
+ 26:26))) | ((gctUINT32)((gctUINT32)(Absolute) & ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 26:26) - (0 ? 26:26) + 1))))) << (0 ? 26:26)));
+            binary[2] = (((gctUINT32)(binary[2]) & ~((gctUINT32)(((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1))))) << (0 ?
+ 29:27))) | ((gctUINT32)((gctUINT32)(Relative) & ((((1 ?
+ 29:27) - (0 ?
+ 29:27) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 29:27) - (0 ? 29:27) + 1))))) << (0 ? 29:27)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))) << (0 ?
+ 2:0))) | ((gctUINT32)((gctUINT32)(Type) & ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 2:0) - (0 ? 2:0) + 1))))) << (0 ? 2:0)));
+            break;
+
+        case 2:
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))) << (0 ?
+ 3:3))) | ((gctUINT32)((gctUINT32)(1) & ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 3:3) - (0 ? 3:3) + 1))))) << (0 ? 3:3)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1))))) << (0 ?
+ 12:4))) | ((gctUINT32)((gctUINT32)(Address) & ((((1 ?
+ 12:4) - (0 ?
+ 12:4) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 12:4) - (0 ? 12:4) + 1))))) << (0 ? 12:4)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1))))) << (0 ?
+ 21:14))) | ((gctUINT32)((gctUINT32)(Swizzle) & ((((1 ?
+ 21:14) - (0 ?
+ 21:14) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:14) - (0 ? 21:14) + 1))))) << (0 ? 21:14)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1))))) << (0 ?
+ 22:22))) | ((gctUINT32)((gctUINT32)(Negate) & ((((1 ?
+ 22:22) - (0 ?
+ 22:22) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 22:22) - (0 ? 22:22) + 1))))) << (0 ? 22:22)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1))))) << (0 ?
+ 23:23))) | ((gctUINT32)((gctUINT32)(Absolute) & ((((1 ?
+ 23:23) - (0 ?
+ 23:23) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 23:23) - (0 ? 23:23) + 1))))) << (0 ? 23:23)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1))))) << (0 ?
+ 27:25))) | ((gctUINT32)((gctUINT32)(Relative) & ((((1 ?
+ 27:25) - (0 ?
+ 27:25) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 27:25) - (0 ? 27:25) + 1))))) << (0 ? 27:25)));
+            binary[3] = (((gctUINT32)(binary[3]) & ~((gctUINT32)(((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1))))) << (0 ?
+ 30:28))) | ((gctUINT32)((gctUINT32)(Type) & ((((1 ?
+ 30:28) - (0 ?
+ 30:28) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 30:28) - (0 ? 30:28) + 1))))) << (0 ? 30:28)));
+            break;
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static const gctUINT32 NEGATE_FLAG   = 1 << 0;
+static const gctUINT32 ABSOLUTE_FLAG = 1 << 1;
+
+gceSTATUS
+_InitializePPU_SetUniform(
+    IN gctUINT32                            Where,
+    IN gctUINT32                            Address,
+    IN gctUINT32                            Swizzle,
+    IN gctUINT32                            Modifiers,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctBOOL negate   = (Modifiers & NEGATE_FLAG  ) ? gcvTRUE : gcvFALSE;
+    gctBOOL absolute = (Modifiers & ABSOLUTE_FLAG) ? gcvTRUE : gcvFALSE;
+    gcmkHEADER_ARG("Where=0x%x", Where);
+
+    gcmkONERROR(_InitializePPU_SetSource(Where, Address, Swizzle, 0x2, negate, absolute, 0, binary));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+_InitializePPU_SetTempReg(
+    IN gctUINT32                            Where,
+    IN gctUINT32                            Address,
+    IN gctUINT32                            Swizzle,
+    IN gctUINT32                            Modifiers,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctBOOL negate   = (Modifiers & NEGATE_FLAG  ) ? gcvTRUE : gcvFALSE;
+    gctBOOL absolute = (Modifiers & ABSOLUTE_FLAG) ? gcvTRUE : gcvFALSE;
+    gcmkHEADER_ARG("Where=0x%x", Where);
+
+    gcmkONERROR(_InitializePPU_SetSource(Where, Address, Swizzle, 0x0, negate, absolute, 0, binary));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+_InitializePPU_SetSourceBin(
+    IN gctUINT32                            SourceBin,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("SourceBin=0x%x", SourceBin);
+
+    binary[1] = HwFunc_SETBITS(binary[1], 25, 22, SourceBin);
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+_InitializePPU_SetImmediateValue(
+    IN gctUINT32                            Where,
+    IN gctUINT32                            Value,
+    OUT gctUINT32_PTR                        binary
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctINT32 raw = (((gctUINT32)(0) & ~((gctUINT32)(((((1 ?
+ 19:0) - (0 ?
+ 19:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 19:0) - (0 ?
+ 19:0) + 1))))) << (0 ?
+ 19:0))) | ((gctUINT32)((gctUINT32)(Value) & ((((1 ?
+ 19:0) - (0 ?
+ 19:0) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 19:0) - (0 ?
+ 19:0) + 1))))) << (0 ?
+ 19:0))) | (((gctUINT32)(0) & ~((gctUINT32)(((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1))))) << (0 ?
+ 21:20))) | ((gctUINT32)(0x2 & ((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0 : (gctUINT32)(~((gctUINT64)(~0) << ((1 ?
+ 21:20) - (0 ? 21:20) + 1))))) << (0 ? 21:20)));
+
+    gcmkHEADER_ARG("Where=0x%x", Where);
+
+    gcmkONERROR(_InitializePPU_SetSource(Where, HwFunc_GETBITS(raw, 8, 0), HwFunc_GETBITS(raw, 16, 9), 0x7, GETBIT(raw, 17), GETBIT(raw, 18), HwFunc_GETBITS(raw, 21, 19), binary));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS gcoHwFunc_SH_CMD(
+    IN gckHARDWARE            Hardware,
+    IN gctUINT32            Data_type,
+    IN OUT gctUINT32_PTR    binarys,
+    OUT  gctUINT32_PTR        command_count,
+    OUT  gctUINT32_PTR        reg_count
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 count = 0;
+    gctUINT32 Input1 = Data_type;
+    gctUINT32 Input2 = Data_type;
+    gctUINT32 Output = Data_type;
+
+    gcmkHEADER_ARG("binarys=0x%x", binarys);
+
+    /* a. DP instruction with all bin */
+    /* b. Store to 6 line which size are 64 bytes and flush out */
+
+    /*img_load.u8 r1, c0, r0.xy*/
+    gcmkONERROR(_InitializePPU_AddOpcode(Hardware, 0x79, 0, Input1, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetDestination(1, gcdVX_ENABLE, gcvFALSE, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetEVIS(0, _InitializePPU_GetPixel(Input1), 1, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetUniform(0, 0, gcdVX_SWIZZLE, 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &binarys[count]));
+    count += 4;
+
+    /*img_load.u8 r2, c0, r0.xy */
+    gcmkONERROR(_InitializePPU_AddOpcode(Hardware, 0x79, 0, Input2, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetDestination(2, gcdVX_ENABLE, gcvFALSE, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetEVIS(0, _InitializePPU_GetPixel(Input2), 1, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetUniform(0, 0, gcdVX_SWIZZLE, 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &binarys[count]));
+    count += 4;
+
+    /* dp2x8 r1, r1, r2, c3_512 */
+    gcmkONERROR(_InitializePPU_AddOpcode(Hardware, 0x45, 0x0B, Output, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetDestination(1, gcdVX_ENABLE, gcvFALSE, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetEVIS(0, 7, (Input1 | (Input2 << 3)), &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(0, 1, gcdVX_SWIZZLE, 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(1, 2, gcdVX_SWIZZLE, 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetSource (2, 2, gcdVX_SWIZZLE, 0x4, gcvFALSE, gcvFALSE, 0, &binarys[count]));
+    count += 4;
+
+
+    /*img_store.u8 r1, c2, r0.xy, r1*/
+    gcmkONERROR(_InitializePPU_AddOpcode(Hardware, 0x7A, 0, Output, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetEVIS(0, _InitializePPU_GetPixel(Output), 1, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetUniform(0, 1, gcdVX_SWIZZLE, 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(1, 0, gcdVX_SWIZZLE2(0, 1), 0, &binarys[count]));
+    gcmkONERROR(_InitializePPU_SetTempReg(2, 1, gcdVX_SWIZZLE, 0, &binarys[count]));
+    count += 4;
+
+    *command_count = count;
+    *reg_count = 0x3;
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+#endif /*gcdINITIALIZE_PPU*/
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_usc.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_func_usc.h
@@ -0,0 +1,1723 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+//#include "gc_hal_user_hardware_precomp.h"
+//#include "gc_hal_user.h"
+/*
+**
+*/
+#if gcdRESET_USC1
+
+#if gcdRESET_USC_C
+
+#include "gc_feature_database.h"
+
+#define USC_DEBUG 0
+
+typedef enum _USC_NN_TYPE
+{
+    USC_NN_TYPE_V6,
+    USC_NN_TYPE_V7,
+    USC_NN_TYPE_V8,
+}
+USC_NN_TYPE;
+gceSTATUS
+_InitializeUSC_NNCommands(
+    IN gckHARDWARE Hardware,
+    IN USC_NN_TYPE hw_type,
+    IN gctUINT32 kernelAddress,
+    IN gctUINT32 inImageAddress,
+    IN gctUINT32 outImageAddress,
+    IN OUT gctUINT8_PTR data_type,
+    IN OUT gctUINT32_PTR item_size,
+    IN OUT gctUINT32_PTR core_count,
+    IN OUT gctSIZE_T_PTR patchBufferSizes,
+    IN OUT gctUINT32_PTR* nnCommands
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckOS os = Hardware->os;
+
+    gctUINT32_PTR command = *nnCommands;
+
+    gctUINT8 kernelDataType = *data_type;
+    gctUINT8 inImageDataType = *data_type;
+    gctUINT8 outImageDataType = *data_type;
+
+    gctUINT32 kernelsPerCore = 1;
+
+    gctUINT32 inImageXSize = 3;
+    gctUINT32 inImageYSize = 2;
+
+    gctUINT32 outImageXSize = 2;
+    gctUINT32 outImageYSize = 1;
+    gctUINT32 outImageZSize = 1;
+
+    gctUINT32 kernelXYSize = 2;
+    gctUINT32 kernelZSize = 1;
+
+    gctUINT32 nn_layer_flush = 1, noZOffset = 0, size = gcmSIZEOF(gctUINT32) * ((hw_type == USC_NN_TYPE_V6)?16:32);
+    gctUINT32 imageEndAddress = 2048, post_shift = 0, post_shift_bit56 = 0;
+    gctUINT8 coefZP = 0, outputZP = 0;
+    gcsFEATURE_DATABASE * db = (gcsFEATURE_DATABASE *)Hardware->featureDatabase;
+    gctUINT32 config = 0, index = 0;
+    gctUINT32 configuration[][3] = {
+        /*item size, data type, core count*/
+        {1, 0x2, db->NNCoreCount_INT8},
+        {2, 0x4, db->NNCoreCount_INT16},
+        {2, 0x1, db->NNCoreCount_FLOAT16},
+        {2, 0x7, db->NNCoreCount_BFLOAT},
+    };
+
+    *patchBufferSizes = size;
+
+    if (command == NULL)
+    {
+        gcmkONERROR(gckOS_Allocate(os, size, (gctPOINTER*)(&command)));
+        gcmkONERROR(gckOS_ZeroMemory(command, size));
+
+        *nnCommands = command;
+    }
+
+    gcmkASSERT(command != NULL);
+
+    for (index = 0; index < gcmCOUNTOF(configuration); index ++)
+    {
+        if(configuration[index][2] > 0)
+            break;
+    }
+
+    if (index == gcmCOUNTOF(configuration))
+         gcmkASSERT("Hardware not support NN!");
+#if USC_DEBUG
+    gcmkPRINT("The hardware(0x%0x) support %d\n", db->customerID, index);
+    gcmkPRINT("\tcore int8  %d\n\tcore int16 %d\n\tcore fp16  %d\n\tcore bfp16 %d\n",
+        db->NNCoreCount_INT8, db->NNCoreCount_INT16, db->NNCoreCount_FLOAT16, db->NNCoreCount_BFLOAT);
+
+#endif
+    *item_size = configuration [index][0];
+    *data_type = (gctUINT8)configuration[index][1];
+    *core_count = configuration[index][2];
+
+    kernelDataType = *data_type;
+    inImageDataType = *data_type;
+    outImageDataType = *data_type;
+
+    switch (hw_type)
+    {
+    case USC_NN_TYPE_V8:
+        noZOffset = 1;
+        outputZP = 0;
+        post_shift = (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_FLOAT_POST_MULT))?0x1f:0;
+        post_shift_bit56 = (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NN_FLOAT_POST_MULT))?3:0;
+
+        break;
+    case USC_NN_TYPE_V7:
+    case USC_NN_TYPE_V6:
+        post_shift = (*data_type == 0x2)?15:0;
+        break;
+    default:
+        break;
+    }
+
+    /* gcregNNInstWord0 */
+    gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (noZOffset) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1))))))) << (0 ?
+ 5:2))) | (((gctUINT32) ((gctUINT32) (kernelXYSize) & ((gctUINT32) ((((1 ?
+ 5:2) - (0 ?
+ 5:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:2) - (0 ? 5:2) + 1))))))) << (0 ? 5:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1))))))) << (0 ?
+ 19:6))) | (((gctUINT32) ((gctUINT32) ((kernelZSize & 0x3FFF)) & ((gctUINT32) ((((1 ?
+ 19:6) - (0 ?
+ 19:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:6) - (0 ? 19:6) + 1))))))) << (0 ? 19:6)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1))))))) << (0 ?
+ 26:20))) | (((gctUINT32) ((gctUINT32) (kernelsPerCore) & ((gctUINT32) ((((1 ?
+ 26:20) - (0 ?
+ 26:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:20) - (0 ? 26:20) + 1))))))) << (0 ? 26:20)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1))))))) << (0 ?
+ 28:27))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 28:27) - (0 ?
+ 28:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 28:27) - (0 ? 28:27) + 1))))))) << (0 ? 28:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ?
+ 29:29))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (nn_layer_flush) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))));
+
+
+    config =   ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1))))))) << (0 ?
+ 18:6))) | (((gctUINT32) ((gctUINT32) (inImageXSize) & ((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:6) - (0 ? 18:6) + 1))))))) << (0 ? 18:6)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1))))))) << (0 ?
+ 31:19))) | (((gctUINT32) ((gctUINT32) (inImageYSize) & ((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:19) - (0 ? 31:19) + 1))))))) << (0 ? 31:19)))
+
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 1) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 1) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 1) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (kernelDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (inImageDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (outImageDataType & 0x1) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+    /* gcregNNInstWord1 */
+    gcmkWRITE_MEMORY(command, config);
+
+    /* gcregNNInstWord2 */
+    gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ?
+ 24:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1))))))) << (0 ?
+ 25:25))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 25:25) - (0 ?
+ 25:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:25) - (0 ? 25:25) + 1))))))) << (0 ? 25:25)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ?
+ 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1))))))) << (0 ?
+ 5:3))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 5:3) - (0 ?
+ 5:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:3) - (0 ? 5:3) + 1))))))) << (0 ? 5:3)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1))))))) << (0 ?
+ 23:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:8) - (0 ?
+ 23:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:8) - (0 ? 23:8) + 1))))))) << (0 ? 23:8)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) ((gctUINT32) (post_shift) & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))));
+
+    /* gcregNNInstWord3 */
+     gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1))))))) << (0 ?
+ 18:6))) | (((gctUINT32) ((gctUINT32) (outImageXSize) & ((gctUINT32) ((((1 ?
+ 18:6) - (0 ?
+ 18:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 18:6) - (0 ? 18:6) + 1))))))) << (0 ? 18:6)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1))))))) << (0 ?
+ 31:19))) | (((gctUINT32) ((gctUINT32) (outImageYSize) & ((gctUINT32) ((((1 ?
+ 31:19) - (0 ?
+ 31:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:19) - (0 ? 31:19) + 1))))))) << (0 ? 31:19)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))));
+
+    /* gcregNNInstWord4 */
+    gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1))))))) << (0 ?
+ 13:0))) | (((gctUINT32) ((gctUINT32) (outImageZSize) & ((gctUINT32) ((((1 ?
+ 13:0) - (0 ?
+ 13:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:0) - (0 ? 13:0) + 1))))))) << (0 ? 13:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1))))))) << (0 ?
+ 15:14))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 15:14) - (0 ?
+ 15:14) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:14) - (0 ? 15:14) + 1))))))) << (0 ? 15:14)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1))))))) << (0 ?
+ 24:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 24:18) - (0 ?
+ 24:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:18) - (0 ? 24:18) + 1))))))) << (0 ? 24:18)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1))))))) << (0 ?
+ 31:25))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 31:25) - (0 ?
+ 31:25) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:25) - (0 ? 31:25) + 1))))))) << (0 ? 31:25)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) ((0 >> 3) & 0x1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) ((0 >> 3) & 0x1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))));
+
+
+    /* gcregNNInstWord5 */
+    gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1))))))) << (0 ?
+ 31:26))) | (((gctUINT32) ((gctUINT32) (((kernelZSize >> 14) & 0x3F)) & ((gctUINT32) ((((1 ?
+ 31:26) - (0 ?
+ 31:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:26) - (0 ? 31:26) + 1))))))) << (0 ? 31:26)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) ((kernelAddress >> 6)) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0))));
+
+    /* gcregNNInstWord6 */
+    gcmkWRITE_MEMORY(command, inImageAddress);
+    /* gcregNNInstWord7 */
+    gcmkWRITE_MEMORY(command, outImageAddress);
+
+    gcmkWRITE_MEMORY(command,
+                     /* gcmSETFIELD (0, GCREG_NN_INST_WORD8, IMAGE_CACHING_MODE, imageCachingMode)
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:2) - (0 ?
+ 3:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:2) - (0 ?
+ 3:2) + 1))))))) << (0 ?
+ 3:2))) | (((gctUINT32) ((gctUINT32) (kernelCachingMode) & ((gctUINT32) ((((1 ?
+ 3:2) - (0 ?
+ 3:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:2) - (0 ? 3:2) + 1))))))) << (0 ? 3:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1))))))) << (0 ?
+ 5:4))) | (((gctUINT32) ((gctUINT32) (partialCacheDataUnit) & ((gctUINT32) ((((1 ?
+ 5:4) - (0 ?
+ 5:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:6) - (0 ?
+ 11:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:6) - (0 ?
+ 11:6) + 1))))))) << (0 ?
+ 11:6))) | (((gctUINT32) ((gctUINT32) (kernelPatternMsb) & ((gctUINT32) ((((1 ?
+ 11:6) - (0 ?
+ 11:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:6) - (0 ? 11:6) + 1))))))) << (0 ? 11:6)))
+                    | */((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1))))))) << (0 ?
+ 15:12))) | (((gctUINT32) ((gctUINT32) (kernelXYSize) & ((gctUINT32) ((((1 ?
+ 15:12) - (0 ?
+ 15:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1))))))) << (0 ? 15:12)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (outImageYSize) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))));
+
+    /* 31:0 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* 31:0 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* 31:0 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* CREG_NN_INST_WORD12_KERNEL_CACHE_END_ADDRESS */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* 31:0 */
+    gcmkWRITE_MEMORY(command, 0);
+
+    /* GCREG_NN_INST_WORD14, IMAGE_END_ADDRESS */
+    gcmkWRITE_MEMORY(command, imageEndAddress);
+
+
+    /*1:0*/
+    gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1))))))) << (0 ?
+ 17:2))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 17:2) - (0 ?
+ 17:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:2) - (0 ? 17:2) + 1))))))) << (0 ? 17:2)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 2) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 2) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ?
+ 21:21))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 2) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ?
+ 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1))))))) << (0 ?
+ 27:22))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 27:22) - (0 ?
+ 27:22) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:22) - (0 ? 27:22) + 1))))))) << (0 ? 27:22)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ?
+ 29:28))) | (((gctUINT32) ((gctUINT32) (post_shift_bit56) & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ?
+ 29:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:28) - (0 ? 29:28) + 1))))))) << (0 ? 29:28))));
+
+    /* V7 or V8 */
+    if (hw_type == USC_NN_TYPE_V7 || hw_type == USC_NN_TYPE_V8)
+    {
+        /*GCREG_NN_INST_WORD16*/
+        gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (inImageXSize * (*item_size)) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ?
+ 31:16))) | (((gctUINT32) ((gctUINT32) (inImageYSize) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ?
+ 31:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:16) - (0 ? 31:16) + 1))))))) << (0 ? 31:16))));
+
+        /*GCREG_NN_INST_WORD17*/
+        gcmkWRITE_MEMORY(command, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (outImageXSize * (*item_size)) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ? 31:24))));
+
+
+        /*GCREG_NN_INST_WORD18*/
+        gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0 >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ?
+ 29:29))) | (((gctUINT32) ((gctUINT32) ((0 >> 4) & 0x1) & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ?
+ 29:29) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 29:29) - (0 ? 29:29) + 1))))))) << (0 ? 29:29)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) ((0 >> 4) & 0x1) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1))))))) << (0 ?
+ 28:28))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 28:28) - (0 ? 28:28) + 1))))))) << (0 ? 28:28)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (kernelDataType >> 3) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))));
+
+        /*25:0*/
+         gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0xFFFFFFFF >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1))))))) << (0 ?
+ 30:30))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 30:30) - (0 ?
+ 30:30) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 30:30) - (0 ? 30:30) + 1))))))) << (0 ? 30:30)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) ((gctUINT32) (inImageDataType >> 3) & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))));
+
+        /*GCREG_NN_INST_WORD20*/
+        gcmkWRITE_MEMORY(command, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0 >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0)))
+                        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ?
+ 26:26))) | (((gctUINT32) ((gctUINT32) (outImageDataType >> 3) & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ?
+ 26:26) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))));
+
+        /*25:0*/
+        gcmkWRITE_MEMORY(command, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1))))))) << (0 ?
+ 25:0))) | (((gctUINT32) ((gctUINT32) (0xFFFFFFFF >> 6) & ((gctUINT32) ((((1 ?
+ 25:0) - (0 ?
+ 25:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:0) - (0 ? 25:0) + 1))))))) << (0 ? 25:0))));
+
+        /*GCREG_NN_INST_WORD22*/
+        gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (coefZP) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (outputZP) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ?
+ 15:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ? 15:8)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ?
+ 17:17))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ?
+ 17:17) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1))))))) << (0 ?
+ 25:18))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 25:18) - (0 ?
+ 25:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:18) - (0 ? 25:18) + 1))))))) << (0 ? 25:18))));
+
+        /*GCREG_NN_INST_WORD23*/
+        gcmkWRITE_MEMORY(command, 0);
+
+        /*GCREG_NN_INST_WORD24*/
+        gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1))))))) << (0 ?
+ 31:4))) | (((gctUINT32) ((gctUINT32) (0 >> 4) & ((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:4) - (0 ? 31:4) + 1))))))) << (0 ? 31:4))));
+
+        /*GCREG_NN_INST_WORD25*/
+        gcmkWRITE_MEMORY(command,
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 3:0) - (0 ?
+ 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1))))))) << (0 ?
+ 31:4))) | (((gctUINT32) ((gctUINT32) (0 >> 4) & ((gctUINT32) ((((1 ?
+ 31:4) - (0 ?
+ 31:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:4) - (0 ? 31:4) + 1))))))) << (0 ? 31:4))));
+    }
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+_BitValue(
+    IN gctUINT8_PTR* base,
+    IN gctUINT32 value,
+    IN gctUINT32_PTR offset,
+    IN gctUINT length)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32_PTR msb = (gctUINT32_PTR)(*base) + 1, lsb = (gctUINT32_PTR)(*base);
+
+    gcmkASSERT(*offset <= 32 && length <= 32);
+
+    if ((*offset) < 32)
+    {
+        gctUINT32 end = (*offset) + length, data = *lsb;
+
+        if (end < 32)
+        {
+            /************************************************************************
+             *       offset    32           64                                      *
+             *     _________________________                                        *
+             *    |_____|////|_|____________|                                       *
+             *              end                                                     *
+             ************************************************************************/
+            data  = (*lsb & ((1 << *offset) - 1));
+            data |= (*lsb & ~((1 << end) - 1));
+            data |= (value << *offset);
+
+            *lsb = data;
+            *offset = end;
+        }
+        else if (end < 64)
+        {
+            /************************************************************************
+             *       offset    32           64                                      *
+             *     _________________________                                        *
+             *    |_____|//////|//|_________|                                       *
+             *                   end                                                *
+             ************************************************************************/
+            gctUINT32 length_m = end - 32;
+            gctUINT32 data_l = (*lsb & ((1 << *offset) - 1));
+            gctUINT32 data_m = (*msb & ~((1 << length_m) - 1));
+
+            data_l |= (value << *offset);
+            data_m |= (value >> length_m);
+
+            *lsb = data_l;
+
+            if (end > 32)
+                *msb = data_m;
+
+            *offset = length_m;
+
+            *base = (gctUINT8_PTR)msb;
+        }
+
+    }
+
+    return status;
+}
+
+gceSTATUS
+_InitializeUSC_NNKernel(
+    IN gckHARDWARE Hardware,
+    IN USC_NN_TYPE hw_type,
+    IN gctUINT8 data_type,
+    IN gctUINT32 item_size,
+    IN gctUINT32 core_count,
+    IN OUT gctUINT32_PTR nnKernels
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gctUINT8_PTR kernels = (gctUINT8_PTR)nnKernels;
+    gctUINT8_PTR kernel_stream_size_ptr = 0;
+    gctUINT32 filterTotalCount = 1, filterSize = 2 * 2 * 1 * item_size, biasSize = 4;
+
+    /* v8 huffman encoder */
+    if (USC_NN_TYPE_V8 == hw_type)
+    {
+        gctUINT32 i = 0, offset = 0;
+                          /*uint8, fp16, int8, uint16, int16, uint4, int4, bf16*/
+        gctUINT8 rlt[][18] = {{0}, {1, 1, 0, 1}, {7, 1}, {0}, {3, 1, 0, 1}, {0}, {0}, {1, 1, 0, 1} };
+        gctUINT8 map[][9] = {
+            {1, 8, 7, 0, 4, 5, 6, 2, 3},
+            {1, 5, 0, 7, 8, 2, 6, 3, 4},
+            {1, 0, 7, 8, 4, 5, 6, 2, 3},
+        };
+        gctBOOL bit16 = (data_type == 0x4) || data_type == (0x1) || data_type == (0x7);
+        gctBOOL fp16 = (data_type == 0x1);
+        gctUINT32 index = (data_type == 0x1)?1:((data_type == 0x7)?2:0);
+
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 1));/*precode*/
+        gcmkONERROR(_BitValue(&kernels, bit16, &offset, 1));/*bit16*/
+        gcmkONERROR(_BitValue(&kernels, fp16, &offset, 1));/*fp16*/
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 1));/*reserve*/
+        gcmkONERROR(_BitValue(&kernels, 1, &offset, 4));/*version, 1*/
+        gcmkONERROR(_BitValue(&kernels, 4, &offset, 8));/*zero run length size*/
+
+        for(i = 0; i < 18; i++)
+            gcmkONERROR(_BitValue(&kernels, rlt[data_type][i], &offset, 8));/*zero run length x 18*/
+
+        for(i = 0; i < 4; i++)
+        {
+            gcmkONERROR(_BitValue(&kernels, (map[index][2 * i + 1] << 4) + map[index][2 * i], &offset, 8));/*map x 4*/
+        }
+
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 16));/*avg bias*/
+
+        gcmkONERROR(_BitValue(&kernels, 0, &offset, 16));/*reserved, must zero*/
+
+        kernel_stream_size_ptr = kernels;
+        for (i = 0; i < core_count; i ++)
+            gcmkONERROR(_BitValue(&kernels, 0, &offset, 32));/*stream size*/
+
+        kernels = (gctUINT8_PTR)nnKernels + gcmALIGN_NP2((gctUINT32)((gctUINT32_PTR)kernels - nnKernels), 64);
+
+        switch (data_type)
+        {
+            case 0x4:
+                gcmkONERROR(_BitValue(&kernels, 0x04058000, &offset, 32));/*huffman data*/ /*00000018 00924600*/
+                gcmkONERROR(_BitValue(&kernels, 0x640101fc, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x00001200, &offset, 32));/*huffman data*/
+
+                gcmkONERROR(_BitValue(&kernel_stream_size_ptr, 0x0000006d, &offset, 32));/*only on core, stream size*/
+
+
+                break;
+            case 0x0:
+            case 0x2:
+                gcmkONERROR(_BitValue(&kernels, 0xec000038, &offset, 32));/*huffman data*/
+
+                gcmkONERROR(_BitValue(&kernel_stream_size_ptr, 0x35, &offset, 32));/*only on core, stream size*/
+
+                break;
+            case 0x1:
+                gcmkONERROR(_BitValue(&kernels, 0x0009db68, &offset, 32));/*huffman data*/ /*0009db68 000006c0 000001f0 00000900 00024000*/
+                gcmkONERROR(_BitValue(&kernels, 0x000006c0, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x000001f0, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x00000900, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x00024000, &offset, 32));/*huffman data*/
+
+                gcmkONERROR(_BitValue(&kernel_stream_size_ptr, 0x000000a3, &offset, 32));/*only on core, stream size*/
+
+                break;
+            case 0x7:
+                gcmkONERROR(_BitValue(&kernels, 0x0007fff8, &offset, 32));/*huffman data*/ /*0007fff8 7f00fdfc c0397f00 0900001f 40000000 00000002*/
+                gcmkONERROR(_BitValue(&kernels, 0x7f00fdfc, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0xc0397f00, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x0900001f, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x40000000, &offset, 32));/*huffman data*/
+                gcmkONERROR(_BitValue(&kernels, 0x00000002, &offset, 32));/*huffman data*/
+
+                gcmkONERROR(_BitValue(&kernel_stream_size_ptr, 0x000000b2, &offset, 32));/*only on core, stream size*/
+
+                break;
+            default:
+                gcmkASSERT("Huffman encode not support this format! Please check!");
+                break;
+        }
+
+
+    }
+    else
+    {
+        gctBOOL zero_all = gcvFALSE;
+        gctUINT8 zrl = 0;
+        gctUINT16 vznum = 1;
+        gctUINT32 bias = 0;
+        gctUINT32 total_size = gcmALIGN_NP2((filterTotalCount * (filterSize  +  biasSize +  3) + 3), 64);//1 + 2 + *item_size;;
+
+        gckOS_ZeroMemory(kernels, total_size + 64);
+
+        *((gctUINT32_PTR)kernels) = total_size;
+        kernels += total_size;
+        if (zero_all)
+            *((gctUINT32_PTR)kernels) = (vznum << (8 * item_size));/*zrl & coreFilterCount, both compressed weight and bias are zero, the size(1 * 1 * 2 * 2 + 4 ) < 64, align to 64*/
+        else
+        {
+            gctINT16 value = (data_type == 0x1)?0x3c00/*1.0f*/:1;
+            gctUINT32 i = 0, offset = 0;
+
+            _BitValue(&kernels, zrl, &offset, 8);
+            _BitValue(&kernels, vznum, &offset, 16);
+            _BitValue(&kernels, value, &offset, 8 * item_size);
+            _BitValue(&kernels, bias, &offset, 32);
+            if (data_type == 0x3 || data_type == 0x4)
+                _BitValue(&kernels, 0, &offset, 16);
+
+            for (i = 1; i < filterSize/item_size; i ++)
+                _BitValue(&kernels, value, &offset, 8 * item_size);
+        }
+
+    }
+OnError:
+    return status;
+}
+static gceSTATUS _InitializeUSC_NNCmdBuffer(IN gckHARDWARE    Hardware,
+                                            IN USC_NN_TYPE    hw_type,
+                                            IN gctUINT32_PTR  flushCommands,
+                                            IN gctUINT32      CmdAddress,
+                                            IN gctUINT32      SramRemapAddress,
+                                            OUT gctUINT32_PTR Bytes)
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsFEATURE_DATABASE *db = (gcsFEATURE_DATABASE *)(Hardware->featureDatabase);
+    gctUINT32 idx = 0, kernel_brust_size = db->DDR_KERNEL_BURST_SIZE;
+    gctINT32 disableZDPN = 1, disableSWTiling = 1, smallBatch = 1, ddrBurstSize = 0;
+    gctBOOL enableNNStride = gcvFALSE;
+
+    disableZDPN = (db->NN_ZDP3 || db->NN_ZDP6) ? 0 : 1;
+
+    enableNNStride = db->NN_STRIDE_SUPPORT;
+    disableSWTiling = enableNNStride ? 0 : 1;
+
+    switch(kernel_brust_size)
+    {
+    case 256:
+        ddrBurstSize = 0x2;
+        break;
+    case 64:
+        ddrBurstSize = 0x0;
+        break;
+    default:
+        break;
+    }
+
+    if (Hardware->identity.chipModel == 0x8000 && Hardware->identity.chipRevision == 0x7120 &&
+            (Hardware->identity.customerID == 0x80 || Hardware->identity.customerID == 0x92))
+        smallBatch = 0x0;
+    else
+        smallBatch = (db->NN_SMALLBATCH_PHASE1 && db->NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX)
+                     ? 0x0 : 0x1;
+
+    if (hw_type == USC_NN_TYPE_V6)
+    {
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = 0;
+
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+        flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+    }
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = SramRemapAddress;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4F) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E50) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = 0x00000000;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E4C) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (disableZDPN) & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+              |  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (disableSWTiling) & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+              |  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (smallBatch) & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+              |  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1))))))) << (0 ?
+ 6:5))) | (((gctUINT32) ((gctUINT32) (ddrBurstSize) & ((gctUINT32) ((((1 ?
+ 6:5) - (0 ?
+ 6:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:5) - (0 ? 6:5) + 1))))))) << (0 ? 6:5)))
+              |  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)));
+
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E54) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+          | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0428) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1))))))) << (0 ?
+ 31:6))) | (((gctUINT32) ((gctUINT32) ((CmdAddress >> 6)) & ((gctUINT32) ((((1 ?
+ 31:6) - (0 ?
+ 31:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:6) - (0 ? 31:6) + 1))))))) << (0 ? 31:6)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0429) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    flushCommands[idx++] = 0;
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+    flushCommands[idx++] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+
+    *Bytes = idx * 4;
+
+    /* Return the status. */
+    return status;
+}
+#endif /*gcdRESET_USC_C*/
+
+#endif /*gcdRESET_USC1*/
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c
@@ -0,0 +1,889 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+typedef struct _gcsMCFE_DESCRIPTOR
+{
+    gctUINT32       start;
+    gctUINT32       end;
+}
+gcsMCFE_DESCRIPTOR;
+
+/* 2^DepthExp = Depth. */
+#define MCFE_RINGBUF_DEPTH_EXP         9
+/* Depth. */
+#define MCFE_RINGBUF_DEPTH             (1 << MCFE_RINGBUF_DEPTH_EXP)
+/* MCFE descriptor size in bytes, fixed 8. */
+#define MCFE_COMMAND_DESC_SIZE         8
+/* FIFO size in bytes. */
+#define MCFE_RINGBUF_SIZE              (MCFE_RINGBUF_DEPTH * MCFE_COMMAND_DESC_SIZE)
+
+typedef struct _gcsMCFE_RING_BUF
+{
+    gckVIDMEM_NODE  ringBufVideoMem;
+    gctUINT32       ringBufAddress;
+    gctUINT32 *     ringBufLogical;
+    gctSIZE_T       ringBufBytes;
+
+    gctUINT32       gpuAddress;
+    gctPHYS_ADDR_T  physical;
+
+    /* Read ptr should be often out-of-date. */
+    gctUINT32       readPtr;
+    gctUINT32       writePtr;
+}
+gcsMCFE_RING_BUF;
+
+typedef struct _gcsMCFE_CHANNEL
+{
+    gceMCFE_CHANNEL_TYPE binding;
+    gcsMCFE_RING_BUF stdRingBuf;
+    gcsMCFE_RING_BUF priRingBuf;
+}
+gcsMCFE_CHANNEL;
+
+struct _gckMCFE
+{
+    gctUINT32 channelCount;
+    gctBOOL   mmuEnabled;
+
+    /*
+     * Channels must be the last field.
+     * Will allocate struct size according to channel count.
+     */
+    gcsMCFE_CHANNEL channels[1];
+};
+
+static gcmINLINE gctUINT32
+_NextPtr(
+    gctUINT32 Ptr
+    )
+{
+    return (Ptr + 1) & (MCFE_RINGBUF_DEPTH - 1);
+}
+
+static gceSTATUS
+_AllocateDescRingBuf(
+    gckHARDWARE Hardware,
+    gcsMCFE_RING_BUF * Channel
+    )
+{
+    gceSTATUS status;
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gckKERNEL kernel = Hardware->kernel;
+    gctUINT32 allocFlag = 0;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+    Channel->ringBufBytes = MCFE_RINGBUF_SIZE;
+
+    /* Allocate video memory node for mcfe ring buffer. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+        kernel,
+        64,
+        gcvVIDMEM_TYPE_COMMAND,
+        allocFlag,
+        &Channel->ringBufBytes,
+        &pool,
+        &Channel->ringBufVideoMem
+        ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+        kernel,
+        Channel->ringBufVideoMem,
+        &Channel->gpuAddress
+        ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        kernel,
+        Channel->ringBufVideoMem,
+        gcvFALSE,
+        gcvFALSE,
+        (gctPOINTER *)&Channel->ringBufLogical
+        ));
+
+    /* Get CPU physical address. */
+    gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+        kernel,
+        Channel->ringBufVideoMem,
+        0,
+        &Channel->physical
+        ));
+
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+        Hardware->os, Channel->physical, &Channel->physical));
+
+    if (Channel->physical > 0xffffffffull)
+    {
+        gcmkPRINT("%s(%d): MCFE ring buffer physical over 4G: 0x%llx",
+            __FUNCTION__, __LINE__, (unsigned long long)Channel->physical);
+    }
+
+    /* Default to use physical. */
+    Channel->ringBufAddress = (gctUINT32)Channel->physical;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static void
+_DestroyDescRingBuf(
+    gckHARDWARE Hardware,
+    gcsMCFE_RING_BUF * Channel
+    )
+{
+    gckKERNEL kernel = Hardware->kernel;
+
+    if (Channel->ringBufVideoMem)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+            kernel,
+            Channel->ringBufVideoMem,
+            0,
+            gcvFALSE,
+            gcvFALSE
+            ));
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            kernel,
+            Channel->ringBufVideoMem
+            ));
+
+        Channel->ringBufVideoMem = gcvNULL;
+        Channel->ringBufLogical  = gcvNULL;
+    }
+}
+
+static gcmINLINE void
+_DestroyMCFE(
+    IN gckHARDWARE Hardware,
+    IN gckMCFE FE
+    )
+{
+    if (FE)
+    {
+        gctUINT i;
+
+        for (i = 0; i < FE->channelCount; i++)
+        {
+            if (FE->channels[i].binding)
+            {
+                _DestroyDescRingBuf(Hardware, &FE->channels[i].stdRingBuf);
+                _DestroyDescRingBuf(Hardware, &FE->channels[i].priRingBuf);
+            }
+        }
+
+        gcmkOS_SAFE_FREE(Hardware->os, FE);
+    }
+}
+
+
+static gceSTATUS
+_ConstructChannel(
+    IN gckHARDWARE Hardware,
+    IN gceMCFE_CHANNEL_TYPE ChannelType,
+    IN gcsMCFE_CHANNEL * Channel
+    )
+{
+    Channel->binding = ChannelType;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMCFE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckMCFE *FE
+    )
+{
+    gceSTATUS status;
+    gckMCFE fe = gcvNULL;
+    gctUINT32 i;
+    gctSIZE_T size = sizeof(struct _gckMCFE);
+
+    if (Hardware->mcfeChannelCount > 1)
+    {
+        size += sizeof(gcsMCFE_CHANNEL) * (Hardware->mcfeChannelCount - 1);
+    }
+
+    gcmkONERROR(gckOS_Allocate(Hardware->os,
+                               size,
+                               (gctPOINTER *)&fe));
+
+    gckOS_ZeroMemory(fe, size);
+
+    fe->channelCount = Hardware->mcfeChannelCount;
+
+    for (i = 0; i < fe->channelCount; i++)
+    {
+        gcmkONERROR(
+            _ConstructChannel(Hardware,
+                              Hardware->mcfeChannels[i],
+                              &fe->channels[i]));
+    }
+
+    /* Enable all events. */
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os,
+                              Hardware->core,
+                              0x00014,
+                              0xFFFFFFFF));
+
+    *FE = fe;
+    return gcvSTATUS_OK;
+
+OnError:
+    _DestroyMCFE(Hardware, fe);
+    return status;
+}
+
+void
+gckMCFE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckMCFE FE
+    )
+{
+    _DestroyMCFE(Hardware, FE);
+}
+
+static gceSTATUS
+_ProgramDescRingBuf(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL MMUEnabled,
+    IN gcsMCFE_RING_BUF * Channel,
+    IN gctUINT32 Index,
+    IN gctBOOL Priority
+    )
+{
+    gctUINT32 ringBufStartReg;
+    gctUINT32 depthExpReg;
+    gctUINT32 readPtrReg;
+    gctUINT32 writePtrReg;
+    gctUINT32 data = 0;
+
+    if (Priority)
+    {
+        ringBufStartReg = 0x02800;
+        depthExpReg     = 0x02900;
+        readPtrReg      = 0x02B00;
+        writePtrReg     = 0x02A00;
+    }
+    else
+    {
+        ringBufStartReg = 0x02400;
+        depthExpReg     = 0x02500;
+        readPtrReg      = 0x02700;
+        writePtrReg     = 0x02600;
+    }
+
+    ringBufStartReg += Index << 2;
+    depthExpReg     += Index << 2;
+    readPtrReg      += Index << 2;
+    writePtrReg     += Index << 2;
+
+    Channel->ringBufAddress = MMUEnabled ? Channel->gpuAddress
+                            : (gctUINT32)Channel->physical;
+
+    /* Channel ringBuf start address. */
+    gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+        Hardware->os, Hardware->core, ringBufStartReg, Channel->ringBufAddress));
+
+    /* Channel ringBuf depth (exponent of 2). */
+    gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+        Hardware->os, Hardware->core, depthExpReg, MCFE_RINGBUF_DEPTH_EXP));
+
+    /* The RD ptr could keep unchanged, read and compute WR ptr. */
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, readPtrReg, &data));
+
+    /* Priority ring buffer write ptr. */
+    /* gcmkVERIFY_OK(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, writePtrReg, data)); */
+
+    /* No valid descriptor initially. */
+    Channel->readPtr = Channel->writePtr = data;
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_InitializeChannel(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL MMUEnabled,
+    IN gcsMCFE_CHANNEL * Channel,
+    IN gctUINT32 Index
+    )
+{
+    gceSTATUS status;
+
+    /* Allocate ring buffer descriptor memory. */
+    if (!Channel->stdRingBuf.ringBufVideoMem)
+    {
+        gcmkONERROR(_AllocateDescRingBuf(Hardware, &Channel->stdRingBuf));
+    }
+
+    /* No priority channel in system engine. */
+    if (!Channel->priRingBuf.ringBufVideoMem && Index != 0)
+    {
+        gcmkONERROR(_AllocateDescRingBuf(Hardware, &Channel->priRingBuf));
+    }
+
+    gcmkONERROR(_ProgramDescRingBuf(Hardware, MMUEnabled, &Channel->stdRingBuf, Index, gcvFALSE));
+
+    /* No priority channel in system engine. */
+    if (Channel->binding != gcvMCFE_CHANNEL_SYSTEM)
+    {
+        gcmkONERROR(_ProgramDescRingBuf(Hardware, MMUEnabled, &Channel->priRingBuf, Index, gcvTRUE));
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    /* It's OK to leave ringBuf memory not free'd here. */
+    return status;
+}
+
+gceSTATUS
+gckMCFE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL MMUEnabled,
+    IN gckMCFE FE
+    )
+{
+    gctUINT32 i;
+    gceSTATUS status;
+
+    for (i = 0; i < FE->channelCount; i++)
+    {
+        if (FE->channels[i].binding)
+        {
+            gcmkONERROR(_InitializeChannel(Hardware, MMUEnabled, &FE->channels[i], i));
+        }
+    }
+
+    FE->mmuEnabled = MMUEnabled;
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckMCFE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append NOP. */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+        logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the NOP command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+gckMCFE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT size;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu",
+                   Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+    gcmkVERIFY_ARGUMENT(Event < 32);
+
+    /* Ignored. */
+    (void)FromWhere;
+
+    size = 8;
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < size)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append EVENT(Event). */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) (0x006 & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                   | Event;
+
+        logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+        {
+            gctPHYS_ADDR_T phys;
+            gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys);
+            gckOS_CPUPhysicalToGPUPhysical(Hardware->os, phys, &phys);
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                           "0x%08x: EVENT %d", phys, Event);
+        }
+#endif
+
+#if gcdINTERRUPT_STATISTIC
+        if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues))
+        {
+            gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event);
+        }
+#endif
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the EVENT command. */
+        *Bytes = size;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMCFE_SendSemaphore(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 SemaId,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x SemaId=%u *Bytes=%lu",
+                   Hardware, Logical, SemaId, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+    gcmkVERIFY_ARGUMENT(SemaId < 0xFFFF);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append SEND_SEMAPHORE(SemaId). */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) (0x002 & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                   | SemaId;
+
+        logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMCFE_WaitSemaphore(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 SemaId,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x SemaId=%u *Bytes=%lu",
+                   Hardware, Logical, SemaId, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+    gcmkVERIFY_ARGUMENT(SemaId < 0xFFFF);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append WAIT_SEMAPHORE(SemaId). */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                   | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) (0x003 & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                   | SemaId;
+
+        logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMCFE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Priority,
+    IN gctUINT32 ChannelId,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gctUINT32 regBase;
+    gcsMCFE_DESCRIPTOR *desc;
+    gcsMCFE_CHANNEL * channel  = &Hardware->mcFE->channels[ChannelId];
+    gcsMCFE_RING_BUF * ringBuf = Priority ? &channel->priRingBuf
+                              : &channel->stdRingBuf;
+
+    /* No priority channel in system channel by design. */
+    gcmkASSERT(!(channel->binding == gcvMCFE_CHANNEL_SYSTEM && Priority == 1));
+
+    while (_NextPtr(ringBuf->writePtr) == ringBuf->readPtr)
+    {
+        gctUINT32 data;
+        regBase = Priority ? 0x02B00
+                : 0x02700;
+
+        gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os,
+                                           Hardware->core,
+                                           regBase + ChannelId * 4,
+                                           &data));
+
+        ringBuf->readPtr = data;
+
+        if (_NextPtr(ringBuf->writePtr) == ringBuf->readPtr)
+        {
+            gcmkPRINT("%s: MCFE channel %s-%d ringBuf is full!",
+                      __FUNCTION__,
+                      Priority ? "Pri" : "Std",
+                      ChannelId);
+
+            gckOS_Delay(Hardware->os, 100);
+        }
+    }
+
+    regBase = Priority ? 0x02A00
+            : 0x02600;
+
+    /* ringBufLogical is in uint32, 2 uint32 contributes 1 descriptr. */
+    desc = (gcsMCFE_DESCRIPTOR *)&ringBuf->ringBufLogical[ringBuf->writePtr * 2];
+    desc->start = Address;
+    desc->end   = Address + Bytes;
+
+    gcmkDUMP(Hardware->os,
+             "#[descriptor %d: channel %s-%d]",
+             ringBuf->writePtr,
+             Priority ? "Pri" : "Std",
+             ChannelId);
+
+    gcmkDUMP_BUFFER(Hardware->os,
+                    gcvDUMP_BUFFER_KERNEL_COMMAND,
+                    desc,
+                    ringBuf->ringBufAddress + ringBuf->writePtr * 8,
+                    8);
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(Hardware->kernel,
+                                            ringBuf->ringBufVideoMem,
+                                            0,
+                                            desc,
+                                            8));
+
+    ringBuf->writePtr = _NextPtr(ringBuf->writePtr);
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "0x%08X - 0x%08X: %06d bytes, Channel=%s-%d",
+                   desc->start, desc->end, Bytes,
+                   Priority ? "Pri" : "Std", ChannelId);
+
+    gcmkVERIFY_OK(gckOS_WriteRegisterEx(Hardware->os,
+                                        Hardware->core,
+                                        regBase + ChannelId * 4,
+                                        ringBuf->writePtr));
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMCFE_HardwareIdle(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL_PTR isIdle
+    )
+{
+    gceSTATUS status;
+    gctUINT32 idle;
+    gctUINT32 regRBase;
+    gctUINT32 readPtr;
+    gctUINT32 ChannelId = 0;
+    gctBOOL Priority = gcvFALSE;
+    gcsMCFE_CHANNEL * channel  = &Hardware->mcFE->channels[ChannelId];
+    gcsMCFE_RING_BUF * ringBuf = Priority ? &channel->priRingBuf
+                              : &channel->stdRingBuf;
+
+    gcmkHEADER();
+
+    *isIdle = gcvTRUE;
+
+    /* Read idle register. */
+    gcmkONERROR(
+        gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle));
+
+    /* Pipe must be idle. */
+    if ((idle | (1 << 14)) != 0x7fffffff)
+    {
+        /* Something is busy. */
+        *isIdle = gcvFALSE;
+        return status;
+    }
+
+    regRBase = Priority ? 0x02B00
+        : 0x02700;
+
+    gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+                                       Hardware->core,
+                                       regRBase + ChannelId * 4,
+                                       &readPtr));
+
+    if (readPtr != ringBuf->writePtr)
+    {
+        *isIdle = gcvFALSE;
+    }
+
+    gcmkFOOTER();
+
+OnError:
+    return status;
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_waitlink_fe.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_waitlink_fe.c
@@ -0,0 +1,1758 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+gceSTATUS
+gckWLFE_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckWLFE * FE
+    )
+{
+    /* Just a non-null value. */
+    *FE = (gckWLFE)(gctUINTPTR_T)1;
+    return gcvSTATUS_OK;
+}
+
+void
+gckWLFE_Destroy(
+    IN gckHARDWARE Hardware,
+    IN gckWLFE FE
+    )
+{
+    gcmkASSERT(FE);
+}
+
+gceSTATUS
+gckWLFE_Initialize(
+    IN gckHARDWARE Hardware,
+    IN gckWLFE FE
+    )
+{
+    gcmkASSERT(FE);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_WaitLink
+**
+**  Append a WAIT/LINK command sequence at the specified location in the command
+**  queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          WAIT/LINK command sequence at or gcvNULL just to query the size of the
+**          WAIT/LINK command sequence.
+**
+**      gctUINT32 Address
+**          GPU address of current location inside the command queue.
+**
+**      gctUINT32 Offset
+**          Offset into command buffer required for alignment.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the WAIT/LINK command
+**          sequence.  If 'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          by the WAIT/LINK command sequence.  If 'Bytes' is gcvNULL, nothing will
+**          be returned.
+**
+**      gctUINT32 * WaitOffset
+**          Pointer to a variable that will receive the offset of the WAIT command
+**          from the specified logcial pointer.
+**          If 'WaitOffset' is gcvNULL nothing will be returned.
+**
+**      gctSIZE_T * WaitSize
+**          Pointer to a variable that will receive the number of bytes used by
+**          the WAIT command.  If 'LinkSize' is gcvNULL nothing will be returned.
+*/
+gceSTATUS
+gckWLFE_WaitLink(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 Offset,
+    IN OUT gctUINT32 * Bytes,
+    OUT gctUINT32 * WaitOffset,
+    OUT gctUINT32 * WaitSize
+    )
+{
+    gceSTATUS status;
+    gctUINT32_PTR logical;
+    gctUINT32 bytes;
+    gctBOOL useL2;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x *Bytes=%lu",
+                   Hardware, Logical, Offset, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical != gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+    useL2 = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_64K_L2_CACHE);
+
+    /* Compute number of bytes required. */
+    if (useL2)
+    {
+        bytes = gcmALIGN(Offset + 24, 8) - Offset;
+    }
+    else
+    {
+        bytes = gcmALIGN(Offset + 16, 8) - Offset;
+    }
+
+    /* Cast the input pointer. */
+    logical = (gctUINT32_PTR) Logical;
+
+    if (logical != gcvNULL)
+    {
+        /* Not enough space? */
+        if (*Bytes < bytes)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        gcmkASSERT(Address != ~0U);
+
+        /* Store the WAIT/LINK address. */
+        Hardware->lastWaitLink = Address;
+
+        /* Append WAIT(count). */
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Hardware->waitCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        logical++;
+
+        if (useL2)
+        {
+            /* LoadState(AQFlush, 1), flush. */
+            *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+            *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+        }
+
+        /* Append LINK(2, address). */
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        *logical++ = Address;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_HARDWARE,
+            "0x%08x: WAIT %u", Address, Hardware->waitCount
+            );
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_HARDWARE,
+            "0x%08x: LINK 0x%08x, #%lu",
+            Address + 8, Address, bytes
+            );
+
+        if (WaitOffset != gcvNULL)
+        {
+            /* Return the offset pointer to WAIT command. */
+            *WaitOffset = 0;
+        }
+
+        if (WaitSize != gcvNULL)
+        {
+            /* Return number of bytes used by the WAIT command. */
+            if (useL2)
+            {
+                *WaitSize = 16;
+            }
+            else
+            {
+                *WaitSize = 8;
+            }
+        }
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the WAIT/LINK command
+        ** sequence. */
+        *Bytes = bytes;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu *WaitOffset=0x%x *WaitSize=%lu",
+                   gcmOPT_VALUE(Bytes), gcmOPT_VALUE(WaitOffset),
+                   gcmOPT_VALUE(WaitSize));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckWLFE_InvalidatePipe(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT size;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+    gctBOOL blt = gcvFALSE;
+    gctBOOL multiCluster = gcvFALSE;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE))
+    {
+        /* Send all event from blt. */
+        blt = gcvTRUE;
+        multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+    }
+
+    /* Determine the size of the command. */
+    size = Hardware->extraEventStates
+         ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */
+         : 8;
+
+    if (blt)
+    {
+        size += 16;
+        if (multiCluster)
+            size += 8;
+    }
+
+    /* END. */
+    size += 8;
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < size)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            if (multiCluster)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x50CE) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)));
+            }
+        }
+
+        /* Append EVENT(Event, PE_SRC). */
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (EVENT_ID_INVALIDATE_PIPE) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+        {
+            gctPHYS_ADDR_T phys;
+            gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys);
+            gckOS_CPUPhysicalToGPUPhysical(Hardware->os, phys, &phys);
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                           "0x%08x: EVENT %d", phys, EVENT_ID_INVALIDATE_PIPE);
+        }
+#endif
+
+        /* Append the extra states. These are needed for the chips that do not
+        ** support back-to-back events due to the async interface. The extra
+        ** states add the necessary delay to ensure that event IDs do not
+        ** collide. */
+        if (Hardware->extraEventStates)
+        {
+            *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+        }
+
+#if gcdINTERRUPT_STATISTIC
+        if (EVENT_ID_INVALIDATE_PIPE < gcmCOUNTOF(Hardware->kernel->eventObj->queues))
+        {
+            gckOS_AtomSetMask(Hardware->pendingEvent, 1 << EVENT_ID_INVALIDATE_PIPE);
+        }
+#endif
+
+        /* Append END. */
+        *logical++ =
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        /* Record the count of execution which is finised by this END. */
+        *logical++ =
+            Hardware->executeCount;
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical);
+
+        /* Make sure the CPU writes out the data to memory. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, Logical));
+
+        Hardware->lastEnd = Address + size - 8;
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the EVENT command. */
+        *Bytes = size;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+void
+gckWLFE_DoneInvalidatePipe(
+    gckHARDWARE Hardware
+    )
+{
+    gctUINT32 resume;
+    gctUINT32 bytes;
+    gctUINT32 idle;
+    gctUINT32 pageSize = Hardware->kernel->command->pageSize;
+
+    gcmkASSERT(Hardware->wlFE);
+
+    /* Make sure FE is idle. */
+    do
+    {
+        gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+            Hardware->os,
+            Hardware->core,
+            0x00004,
+            &idle));
+    }
+    while (idle != 0x7FFFFFFF);
+
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+            Hardware->os,
+            Hardware->core,
+            0x00664,
+            &resume));
+
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+            Hardware->os,
+            Hardware->core,
+            0x00664,
+            &resume));
+
+    gcmkVERIFY_OK(gckWLFE_WaitLink(
+            Hardware,
+            gcvNULL,
+            ~0U,
+            resume & (pageSize - 1),
+            &bytes,
+            gcvNULL,
+            gcvNULL
+            ));
+
+    /* Start Command Parser. */
+    gcmkVERIFY_OK(gckWLFE_Execute(
+        Hardware,
+        resume,
+        bytes
+        ));
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_Link
+**
+**  Append a LINK command at the specified location in the command queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          the LINK command at or gcvNULL just to query the size of the LINK
+**          command.
+**
+**      gctUINT32 FetchAddress
+**          Hardware address of destination of LINK.
+**
+**      gctSIZE_T FetchSize
+**          Number of bytes in destination of LINK.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the LINK command.  If
+**          'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the LINK command.  If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckWLFE_Link(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT32 FetchSize,
+    IN OUT gctUINT32 * Bytes,
+    OUT gctUINT32 * Low,
+    OUT gctUINT32 * High
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T bytes;
+    gctUINT32 link;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu "
+                   "*Bytes=%lu",
+                   Hardware, Logical, FetchAddress, FetchSize,
+                   gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        gcmkONERROR(
+            gckOS_WriteMemory(Hardware->os, logical + 1, FetchAddress));
+
+        if (High)
+        {
+            *High = FetchAddress;
+        }
+
+        /* Make sure the address got written before the LINK command. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, logical + 1));
+
+        /* Compute number of 64-byte aligned bytes to fetch. */
+        bytes = gcmALIGN(FetchAddress + FetchSize, 64) - FetchAddress;
+
+        /* Append LINK(bytes / 8), FetchAddress. */
+        link = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+             | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+        gcmkONERROR(
+            gckOS_WriteMemory(Hardware->os, logical, link));
+
+        if (Low)
+        {
+            *Low = link;
+        }
+
+        /* Memory barrier. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, logical));
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the LINK command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_End
+**
+**  Append an END command at the specified location in the command queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          END command at or gcvNULL just to query the size of the END command.
+**
+**      gctUINT32 Address
+**          GPU address of current location inside the command queue.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the END command.  If
+**          'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the END command.  If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckWLFE_End(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gctUINT32 address;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append END. */
+        logical[0] =
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        /* Record the count of execution which is finised by this END. */
+        logical[1] =
+            Hardware->executeCount;
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical);
+
+        /* Make sure the CPU writes out the data to memory. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, Logical));
+
+        gcmkASSERT(Address != ~0U);
+        address = Address;
+
+        Hardware->lastEnd = address;
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the END command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_Nop
+**
+**  Append a NOP command at the specified location in the command queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          NOP command at or gcvNULL just to query the size of the NOP command.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the NOP command.  If
+**          'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the NOP command.  If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckWLFE_Nop(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+                   Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append NOP. */
+        logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the NOP command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_Event
+**
+**  Append an EVENT command at the specified location in the command queue.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to an gckHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command queue to append
+**          the EVENT command at or gcvNULL just to query the size of the EVENT
+**          command.
+**
+**      gctUINT8 Event
+**          Event ID to program.
+**
+**      gceKERNEL_WHERE FromWhere
+**          Location of the pipe to send the event.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the EVENT command.  If
+**          'Logical' is gcvNULL, this argument will be ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the EVENT command.  If 'Bytes' is gcvNULL, nothing will be
+**          returned.
+*/
+gceSTATUS
+gckWLFE_Event(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT8 Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT size;
+    gctUINT32 destination = 0;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+    gctBOOL blt;
+    gctBOOL extraEventStates;
+    gctBOOL multiCluster;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu",
+                   Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+    gcmkVERIFY_ARGUMENT(Event < 32);
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE))
+    {
+        /* Send all event from blt. */
+        if (FromWhere == gcvKERNEL_PIXEL)
+        {
+            FromWhere = gcvKERNEL_BLT;
+        }
+    }
+
+    blt = FromWhere == gcvKERNEL_BLT ? gcvTRUE : gcvFALSE;
+
+    multiCluster = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MULTI_CLUSTER);
+
+    /* Determine the size of the command. */
+
+    extraEventStates = Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL);
+
+    size = extraEventStates
+         ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */
+         : 8;
+
+    if (blt)
+    {
+        size += 16;
+        if (multiCluster)
+            size += 8;
+    }
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < size)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        switch (FromWhere)
+        {
+        case gcvKERNEL_COMMAND:
+            /* From command processor. */
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+            break;
+
+        case gcvKERNEL_PIXEL:
+            /* From pixel engine. */
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+            break;
+
+        case gcvKERNEL_BLT:
+            destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 7:7) - (0 ?
+ 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+            break;
+
+        default:
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+            if (multiCluster)
+            {
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x50CE) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+                *logical++
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->identity.clusterAvailMask & Hardware->options.userClusterMask) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)));
+            }
+        }
+
+        /* Append EVENT(Event, destination). */
+        *logical++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *logical++
+            = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+        if (blt)
+        {
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+            *logical++
+                = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+
+
+        /* Make sure the event ID gets written out before GPU can access it. */
+        gcmkONERROR(
+            gckOS_MemoryBarrier(Hardware->os, logical + 1));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+        {
+            gctPHYS_ADDR_T phys;
+            gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys);
+            gckOS_CPUPhysicalToGPUPhysical(Hardware->os, phys, &phys);
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                           "0x%08x: EVENT %d", phys, Event);
+        }
+#endif
+
+        /* Append the extra states. These are needed for the chips that do not
+        ** support back-to-back events due to the async interface. The extra
+        ** states add the necessary delay to ensure that event IDs do not
+        ** collide. */
+        if (extraEventStates)
+        {
+            *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                       | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+            *logical++ = 0;
+        }
+
+#if gcdINTERRUPT_STATISTIC
+        if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues))
+        {
+            gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event);
+        }
+#endif
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the EVENT command. */
+        *Bytes = size;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckWLFE_ChipEnable(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gceCORE_3D_MASK ChipEnable,
+    IN OUT gctSIZE_T * Bytes
+    )
+{
+    gckOS os = Hardware->os;
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x ChipEnable=0x%x *Bytes=%lu",
+                   Hardware, Logical, ChipEnable, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    gcmkASSERT(Hardware->wlFE);
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append CHIPENABLE. */
+        gcmkWRITE_MEMORY(
+            logical,
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | ChipEnable
+            );
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: CHIPENABLE 0x%x", Logical, ChipEnable);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the CHIPENABLE command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckWLFE_Execute
+**
+**  Kickstart the hardware's command processor with an initialized command
+**  buffer.
+**
+**  INPUT:
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**      gctUINT32 Address
+**          Hardware address of command buffer.
+**
+**      gctUINT32 Bytes
+**          Number of bytes for the prefetch unit (until after the first LINK).
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckWLFE_Execute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status;
+    gctUINT32 control;
+
+    gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Bytes=%lu",
+                   Hardware, Address, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    gcmkASSERT(Hardware->wlFE);
+
+    /* Enable all events. */
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00014, ~0U));
+
+    /* Write address register. */
+    gcmkONERROR(
+        gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00654, Address));
+
+    /* Build control register. */
+    control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+    /* Set big endian */
+    if (Hardware->bigEndian)
+    {
+        control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1))))))) << (0 ?
+ 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20)));
+    }
+
+    /* Make sure writing to command buffer and previous AHB register is done. */
+    gcmkONERROR(gckOS_MemoryBarrier(Hardware->os, gcvNULL));
+
+    /* Write control register. */
+    switch (Hardware->options.secureMode)
+    {
+    case gcvSECURE_NONE:
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+        break;
+    case gcvSECURE_IN_NORMAL:
+
+#if defined(__KERNEL__)
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+#endif
+        gcmkONERROR(
+            gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x003A4, control));
+        break;
+#if gcdENABLE_TRUST_APPLICATION
+    case gcvSECURE_IN_TA:
+        /* Send message to TA. */
+        gcmkONERROR(gckKERNEL_SecurityStartCommand(Hardware->kernel, Address, (gctUINT32)Bytes));
+        break;
+#endif
+    default:
+        break;
+    }
+
+    /* Increase execute count. */
+    Hardware->executeCount++;
+
+    /* Record last execute address. */
+    Hardware->lastExecuteAddress = Address;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                  "Started command buffer @ 0x%08x",
+                  Address);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckWLFE_AtomicExecute(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gctUINT32 control;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /* Enable all events. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00014, ~0U));
+
+    /* Write address register. */
+    gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00654, Address));
+
+    /* Build control register. */
+    control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+    /* Set big endian */
+    if (Hardware->bigEndian)
+    {
+        control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1))))))) << (0 ?
+ 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 21:20) - (0 ?
+ 21:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20)));
+    }
+
+    /* Make sure writing to command buffer and previous AHB register is done. */
+    gcmkONERROR(gckOS_MemoryBarrier(Hardware->os, gcvNULL));
+
+    /* Write control register. */
+    switch (Hardware->options.secureMode)
+    {
+    case gcvSECURE_NONE:
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+        break;
+    case gcvSECURE_IN_NORMAL:
+
+#if defined(__KERNEL__)
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+#endif
+        gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x003A4, control));
+        break;
+#if gcdENABLE_TRUST_APPLICATION
+    case gcvSECURE_IN_TA:
+        /* Send message to TA. */
+        gcmkONERROR(gckKERNEL_SecurityStartCommand(Hardware->kernel, Address, (gctUINT32)Bytes));
+        break;
+#endif
+    default:
+        break;
+    }
+
+    /* Increase execute count. */
+    Hardware->executeCount++;
+
+    /* Record last execute address. */
+    Hardware->lastExecuteAddress = Address;
+
+    /* Success. */
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    return status;
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c
@@ -0,0 +1,721 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+/*
+ *                          -----------------------
+ *                          HARDWARE STATE RECORDER
+ *                          -----------------------
+ *
+ * State mirror buffer is used to 'mirror' hardware states since hardware
+ * states can't be dumpped. It is a context buffer which stores 'global'
+ * context.
+ *
+ * For each commit, state recorder
+ * 1) Records context buffer (if there is) and command buffers in this commit.
+ * 2) Parse those buffers to estimate the state changed.
+ * 3) Stores result to a mirror buffer.
+ *
+ * == Commit 0 ====================================================================
+ *
+ *      Context Buffer 0
+ *
+ *      Command Buffer 0
+ *
+ *      Mirror Buffer  0  <- Context Buffer 0 + Command Buffer 0
+ *
+ * == Commit 1 ====================================================================
+ *
+ *      Command Buffer 1
+ *
+ *      Mirror Buffer  1  <- Command buffer 1 + Mirror Buffer 0
+ *
+ * == Commit 2 ====================================================================
+ *
+ *      Context Buffer 2 (optional)
+ *
+ *      Command Buffer 2
+ *
+ *      Mirror  Buffer 2  <- Command buffer 2 + Context Buffer 2 + Mirror Buffer 1
+ *
+ * == Commit N ====================================================================
+ *
+ * For Commit N, these buffers are needed to reproduce hardware's behavior in
+ * this commit.
+ *
+ *  Mirror  Buffer [N - 1] : State Mirror accumlated by past commits,
+ *                           which is used to restore hardware state.
+ *  Context Buffer [N]     :
+ *  Command Buffer [N]     : Command buffer executed by hardware in this commit.
+ *
+ *  If sequence of states programming matters, hardware's behavior can't be reproduced,
+ *  but the state values stored in mirror buffer are assuring.
+ */
+
+/* Queue size. */
+#define gcdNUM_RECORDS  6
+
+typedef struct _gcsPARSER_HANDLER * gckPARSER_HANDLER;
+
+typedef void
+(*HandlerFunction)(
+    IN gckPARSER_HANDLER Handler,
+    IN gctUINT32 Addr,
+    IN gctUINT32 Data
+    );
+
+typedef struct _gcsPARSER_HANDLER
+{
+    gctUINT32           type;
+    gctUINT32           cmd;
+    gctPOINTER          private;
+    HandlerFunction     function;
+}
+gcsPARSER_HANDLER;
+
+typedef struct _gcsPARSER * gckPARSER;
+typedef struct _gcsPARSER
+{
+    gctUINT8_PTR        currentCmdBufferAddr;
+
+    /* Current command. */
+    gctUINT32           lo;
+    gctUINT32           hi;
+
+    gctUINT8            cmdOpcode;
+    gctUINT16           cmdAddr;
+    gctUINT32           cmdSize;
+    gctUINT32           cmdRectCount;
+    gctUINT8            skip;
+    gctUINT32           skipCount;
+
+    gctBOOL             allow;
+    gctBOOL             stop;
+
+    /* Callback used by parser to handle a command. */
+    gckPARSER_HANDLER   commandHandler;
+}
+gcsPARSER;
+
+typedef struct _gcsMIRROR
+{
+    gctUINT32_PTR       logical[gcdNUM_RECORDS];
+    gctUINT32           bytes;
+    gcsSTATE_MAP_PTR    map;
+    gctSIZE_T           maxState;
+}
+gcsMIRROR;
+
+typedef struct _gcsDELTA
+{
+    gctUINT64           commitStamp;
+    gctUINT32_PTR       command;
+    gctUINT32           commandBytes;
+    gctUINT32_PTR       context;
+    gctUINT32           contextBytes;
+}
+gcsDELTA;
+
+typedef struct _gcsRECORDER
+{
+    gckOS               os;
+    gcsMIRROR           mirror;
+    gcsDELTA            deltas[gcdNUM_RECORDS];
+
+    /* Index of current record. */
+    gctUINT             index;
+
+    /* Number of records. */
+    gctUINT             num;
+
+    /* Plugin used by gckPARSER. */
+    gcsPARSER_HANDLER   recorderHandler;
+    gckPARSER           parser;
+}
+gcsRECORDER;
+
+
+/******************************************************************************\
+***************************** Command Buffer Parser ****************************
+\******************************************************************************/
+
+/*
+** Command buffer parser checks command buffer in FE's view to make sure there
+** is no format error.
+**
+** Parser provide a callback mechnisam, so plug-in can be added to implement
+** other functions.
+*/
+
+static void
+_HandleLoadState(
+    IN OUT gckPARSER Parser
+    )
+{
+    gctUINT i;
+    gctUINT32_PTR data = (gctUINT32_PTR)Parser->currentCmdBufferAddr;
+    gctUINT32 cmdAddr = Parser->cmdAddr;
+
+    if (Parser->commandHandler == gcvNULL
+     || Parser->commandHandler->cmd != 0x01
+    )
+    {
+        /* No handler for this command. */
+        return;
+    }
+
+    for (i = 0; i < Parser->cmdSize; i++)
+    {
+        Parser->commandHandler->function(Parser->commandHandler, cmdAddr, *data);
+
+        /* Advance to next state. */
+        cmdAddr++;
+        data++;
+    }
+}
+
+static void
+_GetCommand(
+    IN OUT gckPARSER Parser
+    )
+{
+    gctUINT32 * buffer = (gctUINT32 *)Parser->currentCmdBufferAddr;
+
+    gctUINT16 cmdRectCount;
+    gctUINT16 cmdDataCount;
+
+    Parser->hi = buffer[0];
+    Parser->lo = buffer[1];
+
+    Parser->cmdOpcode = (((((gctUINT32) (Parser->hi)) >> (0 ? 31:27)) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) );
+    Parser->cmdRectCount = 1;
+
+    switch (Parser->cmdOpcode)
+    {
+    case 0x01:
+        /* Extract count. */
+        Parser->cmdSize = (((((gctUINT32) (Parser->hi)) >> (0 ? 25:16)) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1)))))) );
+        if (Parser->cmdSize == 0)
+        {
+            /* 0 means 1024. */
+            Parser->cmdSize = 1024;
+        }
+        Parser->skip = (Parser->cmdSize & 0x1) ? 0 : 1;
+
+        /* Extract address. */
+        Parser->cmdAddr = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) );
+
+        Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 4;
+        Parser->skipCount = Parser->cmdSize + Parser->skip;
+        break;
+
+     case 0x05:
+        Parser->cmdSize   = 4;
+        Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+        break;
+
+    case 0x06:
+        Parser->cmdSize   = 5;
+        Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+        break;
+
+    case 0x0C:
+        Parser->cmdSize   = 3;
+        Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+        break;
+
+    case 0x09:
+        Parser->cmdSize   = 2;
+        Parser->cmdAddr   = 0x0F16;
+        Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+        break;
+
+     case 0x04:
+        Parser->cmdSize = 1;
+        Parser->cmdAddr = 0x0F06;
+
+        cmdRectCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) );
+        cmdDataCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 26:16)) & ((gctUINT32) ((((1 ? 26:16) - (0 ? 26:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:16) - (0 ? 26:16) + 1)))))) );
+
+        Parser->skipCount = gcmALIGN(Parser->cmdSize, 2)
+                          + cmdRectCount * 2
+                          + gcmALIGN(cmdDataCount, 2);
+
+        Parser->cmdRectCount = cmdRectCount;
+        break;
+
+    case 0x03:
+        Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+        Parser->skipCount = 0;
+        break;
+
+    case 0x02:
+        Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+        Parser->skipCount = 0;
+        break;
+
+    case 0x07:
+        Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+        Parser->skipCount = 0;
+        break;
+
+    case 0x08:
+        /* Commands after LINK isn't executed, skip them. */
+        Parser->stop = gcvTRUE;
+        break;
+
+    default:
+        /* Unknown command is a risk. */
+        Parser->allow = gcvFALSE;
+        break;
+    }
+}
+
+static void
+_ParseCommand(
+    IN OUT gckPARSER Parser
+    )
+{
+    switch(Parser->cmdOpcode)
+    {
+    case 0x01:
+        _HandleLoadState(Parser);
+        break;
+    case 0x05:
+    case 0x06:
+    case 0x0C:
+        break;
+    case 0x04:
+        break;
+    default:
+        break;
+    }
+
+    /* Advance to next command. */
+    Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr
+                                 + (Parser->skipCount << 2);
+}
+
+gceSTATUS
+gckPARSER_Parse(
+    IN gckPARSER Parser,
+    IN gctUINT8_PTR Buffer,
+    IN gctUINT32 Bytes
+    )
+{
+    gckPARSER parser = Parser;
+    gctUINT8_PTR end = (gctUINT8_PTR)Buffer + Bytes;
+
+    /* Initialize parser. */
+    parser->currentCmdBufferAddr = (gctUINT8_PTR)Buffer;
+    parser->skip = 0;
+    parser->allow = gcvTRUE;
+    parser->stop  = gcvFALSE;
+
+    /* Go through command buffer until reaching the end
+    ** or meeting an error. */
+    do
+    {
+        _GetCommand(parser);
+
+        _ParseCommand(parser);
+    }
+    while ((parser->currentCmdBufferAddr < end)
+        && (parser->allow == gcvTRUE)
+        && (parser->stop == gcvFALSE)
+        );
+
+    if (parser->allow == gcvFALSE)
+    {
+        /* Error detected. */
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckPARSER_RegisterCommandHandler
+**
+**  Register a command handler which will be called when parser get a command.
+**
+*/
+gceSTATUS
+gckPARSER_RegisterCommandHandler(
+    IN gckPARSER Parser,
+    IN gckPARSER_HANDLER Handler
+    )
+{
+    Parser->commandHandler = Handler;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckPARSER_Construct(
+    IN gckOS Os,
+    IN gckPARSER_HANDLER Handler,
+    OUT gckPARSER * Parser
+    )
+{
+    gceSTATUS status;
+    gckPARSER pointer;
+
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsPARSER), (gctPOINTER *)&pointer));
+
+    /* Put it here temp, should have a more general plug-in mechnisam. */
+    pointer->commandHandler = Handler;
+
+    *Parser = pointer;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+void
+gckPARSER_Destroy(
+    IN gckOS Os,
+    IN gckPARSER Parser
+    )
+{
+    gcmkOS_SAFE_FREE(Os, Parser);
+}
+
+/******************************************************************************\
+**************************** Hardware States Recorder **************************
+\******************************************************************************/
+
+static void
+_RecodeState(
+    IN gckPARSER_HANDLER Handler,
+    IN gctUINT32 Addr,
+    IN gctUINT32 Data
+    )
+{
+    gcmkVERIFY_OK(gckRECORDER_UpdateMirror(Handler->private, Addr, Data));
+}
+
+static gctUINT
+_Previous(
+    IN gctUINT Index
+    )
+{
+    if (Index == 0)
+    {
+        return gcdNUM_RECORDS - 1;
+    }
+
+    return Index - 1;
+}
+
+static gctUINT
+_Next(
+    IN gctUINT Index
+    )
+{
+    return (Index + 1) % gcdNUM_RECORDS;
+}
+
+gceSTATUS
+gckRECORDER_Construct(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    OUT gckRECORDER * Recorder
+    )
+{
+    gceSTATUS status;
+    gckCONTEXT context = gcvNULL;
+    gckRECORDER recorder = gcvNULL;
+    gctSIZE_T mapSize;
+    gctUINT i;
+
+    gcmkONERROR(gckCONTEXT_Construct(Os, Hardware, 0, &context));
+
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsRECORDER), (gctPOINTER *)&recorder));
+
+    gckOS_ZeroMemory(recorder, gcmSIZEOF(gcsRECORDER));
+
+    /* Copy state map. */
+    recorder->mirror.maxState = context->maxState;
+
+    mapSize = context->maxState * gcmSIZEOF(gcsSTATE_MAP);
+
+    gcmkONERROR(gckOS_Allocate(Os, mapSize, (gctPOINTER *)&recorder->mirror.map));
+
+    gckOS_MemCopy(recorder->mirror.map, context->map, mapSize);
+
+    /* Copy context buffer. */
+    recorder->mirror.bytes = context->totalSize;
+
+    for (i = 0; i < gcdNUM_RECORDS; i++)
+    {
+        gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->mirror.logical[i]));
+        gckOS_MemCopy(recorder->mirror.logical[i], context->buffer->logical, context->totalSize);
+    }
+
+    for (i = 0; i < gcdNUM_RECORDS; i++)
+    {
+        gcmkONERROR(gckOS_Allocate(Os, gcdCMD_BUFFER_SIZE, (gctPOINTER *)&recorder->deltas[i].command));
+        gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->deltas[i].context));
+    }
+
+    recorder->index = 0;
+    recorder->num   = 0;
+
+    /* Initialize Parser plugin. */
+    recorder->recorderHandler.cmd = 0x01;
+    recorder->recorderHandler.private = recorder;
+    recorder->recorderHandler.function = _RecodeState;
+
+    gcmkONERROR(gckPARSER_Construct(Os, &recorder->recorderHandler, &recorder->parser));
+
+    recorder->os = Os;
+
+    *Recorder = recorder;
+
+    gckCONTEXT_Destroy(context);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (context)
+    {
+        gckCONTEXT_Destroy(context);
+    }
+
+    if (recorder)
+    {
+        gckRECORDER_Destory(Os, recorder);
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckRECORDER_Destory(
+    IN gckOS Os,
+    IN gckRECORDER Recorder
+    )
+{
+    gctUINT i;
+
+    if (Recorder->mirror.map)
+    {
+        gcmkOS_SAFE_FREE(Os, Recorder->mirror.map);
+    }
+
+    for (i = 0; i < gcdNUM_RECORDS; i++)
+    {
+        if (Recorder->mirror.logical[i])
+        {
+            gcmkOS_SAFE_FREE(Os, Recorder->mirror.logical[i]);
+        }
+    }
+
+    for (i = 0; i < gcdNUM_RECORDS; i++)
+    {
+        if (Recorder->deltas[i].command)
+        {
+            gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].command);
+        }
+
+        if (Recorder->deltas[i].context)
+        {
+            gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].context);
+        }
+    }
+
+    if (Recorder->parser)
+    {
+        gckPARSER_Destroy(Os, Recorder->parser);
+    }
+
+    gcmkOS_SAFE_FREE(Os, Recorder);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckRECORDER_UpdateMirror(
+    IN gckRECORDER Recorder,
+    IN gctUINT32 State,
+    IN gctUINT32 Data
+    )
+{
+    gctUINT32 index;
+    gcsSTATE_MAP_PTR map = Recorder->mirror.map;
+    gctUINT32_PTR buffer = Recorder->mirror.logical[Recorder->index];
+
+    if (State >= Recorder->mirror.maxState)
+    {
+        /* Ignore them just like HW does. */
+        return gcvSTATUS_OK;
+    }
+
+    index = map[State].index;
+
+    if (index)
+    {
+        buffer[index] = Data;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+void
+gckRECORDER_AdvanceIndex(
+    IN gckRECORDER Recorder,
+    IN gctUINT64 CommitStamp
+    )
+{
+    /* Get next record. */
+    gctUINT next = (Recorder->index + 1) % gcdNUM_RECORDS;
+
+    /* Record stamp of this commit. */
+    Recorder->deltas[Recorder->index].commitStamp = CommitStamp;
+
+    /* Mirror of next record is mirror of this record and delta in next record. */
+    gckOS_MemCopy(Recorder->mirror.logical[next],
+        Recorder->mirror.logical[Recorder->index], Recorder->mirror.bytes);
+
+    /* Advance to next record. */
+    Recorder->index = next;
+
+    Recorder->num = gcmMIN(Recorder->num + 1, gcdNUM_RECORDS - 1);
+
+
+    /* Reset delta. */
+    Recorder->deltas[Recorder->index].commandBytes = 0;
+    Recorder->deltas[Recorder->index].contextBytes = 0;
+}
+
+void
+gckRECORDER_Record(
+    IN gckRECORDER Recorder,
+    IN gctUINT8_PTR CommandBuffer,
+    IN gctUINT32 CommandBytes,
+    IN gctUINT8_PTR ContextBuffer,
+    IN gctUINT32 ContextBytes
+    )
+{
+    gcsDELTA * delta = &Recorder->deltas[Recorder->index];
+
+    if (CommandBytes != 0xFFFFFFFF)
+    {
+        gckPARSER_Parse(Recorder->parser, CommandBuffer, CommandBytes);
+        gckOS_MemCopy(delta->command, CommandBuffer, CommandBytes);
+        delta->commandBytes = CommandBytes;
+    }
+
+    if (ContextBytes != 0xFFFFFFFF)
+    {
+        gckPARSER_Parse(Recorder->parser, ContextBuffer, ContextBytes);
+        gckOS_MemCopy(delta->context, ContextBuffer, ContextBytes);
+        delta->contextBytes = ContextBytes;
+    }
+}
+
+void
+gckRECORDER_Dump(
+    IN gckRECORDER Recorder
+    )
+{
+    gctUINT last = Recorder->index;
+    gctUINT previous;
+    gctUINT i;
+    gcsMIRROR *mirror = &Recorder->mirror;
+    gcsDELTA *delta;
+    gckOS os = Recorder->os;
+
+    for (i = 0; i < Recorder->num; i++)
+    {
+        last = _Previous(last);
+    }
+
+    for (i = 0; i < Recorder->num; i++)
+    {
+        delta = &Recorder->deltas[last];
+
+        /* Dump record */
+        gcmkPRINT("#[commit %llu]", delta->commitStamp);
+
+        if (delta->commitStamp)
+        {
+            previous = _Previous(last);
+
+            gcmkPRINT("#[mirror]");
+            gckOS_DumpBuffer(os, gcvDUMP_BUFFER_KERNEL_CONTEXT, mirror->logical[previous], ~0U, mirror->bytes);
+            gcmkPRINT("#[kernel.execute]");
+        }
+
+        if (delta->contextBytes)
+        {
+            gckOS_DumpBuffer(os, gcvDUMP_BUFFER_KERNEL_CONTEXT, delta->context, ~0U, delta->contextBytes);
+            gcmkPRINT("#[kernel.execute]");
+        }
+
+        gckOS_DumpBuffer(os, gcvDUMP_BUFFER_KERNEL_COMMAND, delta->command, ~0U, delta->commandBytes);
+        gcmkPRINT("#[kernel.execute]");
+
+        last = _Next(last);
+    }
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c
@@ -0,0 +1,1411 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+
+#if gcdENABLE_VG
+
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_COMMAND
+
+/******************************************************************************\
+****************************** gckVGCOMMAND API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_InitializeInfo
+**
+**  Initialize architecture dependent command buffer information.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to the Command object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckVGCOMMAND_InitializeInfo(
+    IN gckVGCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Command=0x%x", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    do
+    {
+        /* Reset interrupts. */
+        Command->info.feBufferInt   = -1;
+        Command->info.tsOverflowInt = -1;
+
+        /* Set command buffer attributes. */
+        Command->info.addressAlignment = 64;
+        Command->info.commandAlignment = 8;
+
+        /* Determine command alignment address mask. */
+        Command->info.addressMask = ((((gctUINT32) (Command->info.addressAlignment - 1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0 ) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+        /* Query the number of bytes needed by the STATE command. */
+        gcmkERR_BREAK(gckVGCOMMAND_StateCommand(
+            Command, 0x0, gcvNULL, (gctUINT32)~0, 0,
+            &Command->info.stateCommandSize
+            ));
+
+        /* Query the number of bytes needed by the RESTART command. */
+        gcmkERR_BREAK(gckVGCOMMAND_RestartCommand(
+            Command, gcvNULL, (gctUINT32)~0, 0,
+            &Command->info.restartCommandSize
+            ));
+
+        /* Query the number of bytes needed by the FETCH command. */
+        gcmkERR_BREAK(gckVGCOMMAND_FetchCommand(
+            Command, gcvNULL, (gctUINT32)~0, 0,
+            &Command->info.fetchCommandSize
+            ));
+
+        /* Query the number of bytes needed by the CALL command. */
+        gcmkERR_BREAK(gckVGCOMMAND_CallCommand(
+            Command, gcvNULL, (gctUINT32)~0, 0,
+            &Command->info.callCommandSize
+            ));
+
+        /* Query the number of bytes needed by the RETURN command. */
+        gcmkERR_BREAK(gckVGCOMMAND_ReturnCommand(
+            Command, gcvNULL,
+            &Command->info.returnCommandSize
+            ));
+
+        /* Query the number of bytes needed by the EVENT command. */
+        gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+            Command, gcvNULL, gcvBLOCK_PIXEL, -1,
+            &Command->info.eventCommandSize
+            ));
+
+        /* Query the number of bytes needed by the END command. */
+        gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+            Command, gcvNULL, -1,
+            &Command->info.endCommandSize
+            ));
+
+        /* Determine the tail reserve size. */
+        Command->info.staticTailSize = gcmMAX(
+            Command->info.fetchCommandSize,
+            gcmMAX(
+                Command->info.returnCommandSize,
+                Command->info.endCommandSize
+                )
+            );
+
+        /* Determine the maximum tail size. */
+        Command->info.dynamicTailSize
+            = Command->info.staticTailSize
+            + Command->info.eventCommandSize * gcvBLOCK_COUNT;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_StateCommand
+**
+**  Append a STATE command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to an gckVGCOMMAND object.
+**
+**      gctUINT32 Pipe
+**          Harwdare destination pipe.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          STATE command at or gcvNULL to query the size of the command.
+**
+**      gctUINT32 Address
+**          Starting register address of the state buffer.
+**          If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gctUINT32 Count
+**          Number of states in state buffer.
+**          If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the STATE command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the STATE command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_StateCommand(
+    IN gckVGCOMMAND Command,
+    IN gctUINT32 Pipe,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 Count,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Pipe=0x%x Logical=0x%x Address=0x%x Count=0x%x Bytes = 0x%x",
+                   Command, Pipe, Logical, Address, Count, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append STATE. */
+            gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1))))))) << (0 ?
+ 11:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ?
+ 27:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) ((gctUINT32) (Pipe) & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12)))
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the STATE command. */
+            *Bytes = 4 * (Count + 1);
+        }
+    }
+    else
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append LOAD_STATE. */
+            gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the STATE command. */
+            *Bytes = 4 * (Count + 1);
+        }
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_RestartCommand
+**
+**  Form a RESTART command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to an gckVGCOMMAND object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          RESTART command at or gcvNULL to query the size of the command.
+**
+**      gctUINT32 FetchAddress
+**          The address of another command buffer to be executed by this RESTART
+**          command.  If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gctUINT FetchCount
+**          The number of 64-bit data quantities in another command buffer to
+**          be executed by this RESTART command.  If 'Logical' is gcvNULL, this
+**          argument is ignored.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the RESTART command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the RESTART command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_RestartCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+                   Command, Logical, FetchAddress, FetchCount, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+            gctUINT32 beginEndMark;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Determine Begin/End flag. */
+            beginEndMark = (FetchCount > 0)
+                ?
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ?
+ 24:24))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24)))
+                : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ?
+ 24:24))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ?
+ 24:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24)));
+
+            /* Append RESTART. */
+            gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x9 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0)))
+                | beginEndMark
+                );
+
+            gckOS_WriteMemory(
+                Command->os,
+                &buffer[1],
+                FetchAddress
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the RESTART command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_FetchCommand
+**
+**  Form a FETCH command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to an gckVGCOMMAND object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          FETCH command at or gcvNULL to query the size of the command.
+**
+**      gctUINT32 FetchAddress
+**          The address of another command buffer to be executed by this FETCH
+**          command.  If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gctUINT FetchCount
+**          The number of 64-bit data quantities in another command buffer to
+**          be executed by this FETCH command.  If 'Logical' is gcvNULL, this
+**          argument is ignored.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the FETCH command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the FETCH command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_FetchCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+                   Command, Logical, FetchAddress, FetchCount, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append FETCH. */
+            gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x5 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0)))
+                );
+
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[1],
+                gcmkFIXADDRESS(FetchAddress)
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the FETCH command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append LINK. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                );
+
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[1],
+                gcmkFIXADDRESS(FetchAddress)
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the LINK command. */
+            *Bytes = 8;
+        }
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_CallCommand
+**
+**  Append a CALL command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to an gckVGCOMMAND object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          CALL command at or gcvNULL to query the size of the command.
+**
+**      gctUINT32 FetchAddress
+**          The address of another command buffer to be executed by this CALL
+**          command.  If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gctUINT FetchCount
+**          The number of 64-bit data quantities in another command buffer to
+**          be executed by this CALL command.  If 'Logical' is gcvNULL, this
+**          argument is ignored.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the CALL command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the CALL command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_CallCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+                   Command, Logical, FetchAddress, FetchCount, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append CALL. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x6 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ?
+ 20:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ? 20:0)))
+                );
+
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[1],
+                gcmkFIXADDRESS(FetchAddress)
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the CALL command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_ReturnCommand
+**
+**  Append a RETURN command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to an gckVGCOMMAND object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          RETURN command at or gcvNULL to query the size of the command.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the RETURN command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the RETURN command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_ReturnCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x  Bytes = 0x%x",
+                   Command, Logical, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append RETURN. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x7 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the RETURN command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_EventCommand
+**
+**  Form an EVENT command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to the Command object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          EVENT command at or gcvNULL to query the size of the command.
+**
+**      gctINT32 InterruptId
+**          The ID of the interrupt to generate.
+**          If 'Logical' is gcvNULL, this argument is ignored.
+**
+**      gceBLOCK Block
+**          Block that will generate the interrupt.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the EVENT command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the END command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_EventCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gceBLOCK Block,
+    IN gctINT32 InterruptId,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x Block=0x%x InterruptId=0x%x Bytes = 0x%x",
+                   Command, Logical, Block, InterruptId, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        typedef struct _gcsEVENTSTATES
+        {
+            /* Chips before VG21 use these values. */
+            gctUINT     eventFromFE;
+            gctUINT     eventFromPE;
+
+            /* VG21 chips and later use SOURCE field. */
+            gctUINT     eventSource;
+        }
+        gcsEVENTSTATES;
+
+        static gcsEVENTSTATES states[] =
+        {
+            /* gcvBLOCK_COMMAND */
+            {
+                (gctUINT)~0,
+                (gctUINT)~0,
+                (gctUINT)~0
+            },
+
+            /* gcvBLOCK_TESSELLATOR */
+            {
+                0x0,
+                0x1,
+                0x10
+            },
+
+            /* gcvBLOCK_TESSELLATOR2 */
+            {
+                0x0,
+                0x1,
+                0x12
+            },
+
+            /* gcvBLOCK_TESSELLATOR3 */
+            {
+                0x0,
+                0x1,
+                0x14
+            },
+
+            /* gcvBLOCK_RASTER */
+            {
+                0x0,
+                0x1,
+                0x07,
+            },
+
+            /* gcvBLOCK_VG */
+            {
+                0x0,
+                0x1,
+                0x0F
+            },
+
+            /* gcvBLOCK_VG2 */
+            {
+                0x0,
+                0x1,
+                0x11
+            },
+
+            /* gcvBLOCK_VG3 */
+            {
+                0x0,
+                0x1,
+                0x13
+            },
+
+            /* gcvBLOCK_PIXEL */
+            {
+                0x0,
+                0x1,
+                0x07
+            },
+        };
+
+        /* Verify block ID. */
+        gcmkVERIFY_ARGUMENT(gcmIS_VALID_INDEX(Block, states));
+
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Verify the event ID. */
+            gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+            gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))));
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append EVENT. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1))))))) << (0 ?
+ 11:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 11:0) - (0 ?
+ 11:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ? 11:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ?
+ 27:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 27:16) - (0 ?
+ 27:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 27:16) - (0 ? 27:16) + 1))))))) << (0 ? 27:16)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ?
+ 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12)))
+                );
+
+            /* Determine chip version. */
+            if (Command->vg21)
+            {
+                /* Get the event source for the block. */
+                gctUINT eventSource = states[Block].eventSource;
+
+                /* Supported? */
+                if (eventSource == ~0)
+                {
+                    gcmkFOOTER_NO();
+                    return gcvSTATUS_NOT_SUPPORTED;
+                }
+
+                buffer[1]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) ((gctUINT32) (eventSource) & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ?
+ 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+            }
+            else
+            {
+                /* Get the event source for the block. */
+                gctUINT eventFromFE = states[Block].eventFromFE;
+                gctUINT eventFromPE = states[Block].eventFromPE;
+
+                /* Supported? */
+                if (eventFromFE == ~0)
+                {
+                    gcmkFOOTER_NO();
+                    return gcvSTATUS_NOT_SUPPORTED;
+                }
+
+                buffer[1]
+                    = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (eventFromFE) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (eventFromPE) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+            }
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Make sure the events are directly supported for the block. */
+            if (states[Block].eventSource == ~0)
+            {
+                gcmkFOOTER_NO();
+                return gcvSTATUS_NOT_SUPPORTED;
+            }
+
+            /* Return number of bytes required by the END command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Verify the event ID. */
+            gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+            gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))));
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append EVENT. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                );
+
+            /* Determine event source. */
+            if (Block == gcvBLOCK_COMMAND)
+            {
+               gckOS_WriteMemory(
+                    Command->os,
+                    &buffer[1],
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ?
+ 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+                    );
+            }
+            else
+            {
+               gckOS_WriteMemory(
+                    Command->os,
+                    &buffer[1],
+                      ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                    | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+                    );
+            }
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the EVENT and END commands. */
+            *Bytes = 8;
+        }
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGCOMMAND_EndCommand
+**
+**  Form an END command at the specified location in the command buffer.
+**
+**  INPUT:
+**
+**      gckVGCOMMAND Command
+**          Pointer to the Command object.
+**
+**      gctPOINTER Logical
+**          Pointer to the current location inside the command buffer to append
+**          END command at or gcvNULL to query the size of the command.
+**
+**      gctINT32 InterruptId
+**          The ID of the interrupt to generate.
+**          If 'Logical' is gcvNULL, this argument will be ignored.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to the number of bytes available for the END command.
+**          If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that will receive the number of bytes required
+**          for the END command.  If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_EndCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctINT32 InterruptId,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gcmkHEADER_ARG("Command=0x%x Logical=0x%x InterruptId=0x%x Bytes = 0x%x",
+                   Command, Logical, InterruptId, Bytes);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->fe20)
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR buffer;
+
+            /* Verify the event ID. */
+            gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+
+            /* Cast the buffer pointer. */
+            buffer = (gctUINT32_PTR) Logical;
+
+            /* Append END. */
+           gckOS_WriteMemory(
+                Command->os,
+                &buffer[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ?
+ 31:28))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ?
+ 31:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:28) - (0 ? 31:28) + 1))))))) << (0 ? 31:28)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the END command. */
+            *Bytes = 8;
+        }
+    }
+    else
+    {
+        if (Logical != gcvNULL)
+        {
+            gctUINT32_PTR memory;
+
+            /* Verify the event ID. */
+            gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+
+            /* Cast the buffer pointer. */
+            memory = (gctUINT32_PTR) Logical;
+
+            /* Append EVENT. */
+           gckOS_WriteMemory(
+                Command->os,
+                &memory[0],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+                );
+
+           gckOS_WriteMemory(
+                Command->os,
+                &memory[1],
+                  ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ?
+ 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ?
+ 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+                );
+
+            /* Append END. */
+           gckOS_WriteMemory(
+                Command->os,
+                &memory[2],
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+                );
+        }
+
+        if (Bytes != gcvNULL)
+        {
+            /* Return number of bytes required by the EVENT and END commands. */
+            *Bytes = 16;
+        }
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+#endif /* gcdENABLE_VG */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h
@@ -0,0 +1,353 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_command_vg_h_
+#define __gc_hal_kernel_hardware_command_vg_h_
+
+/******************************************************************************\
+******************* Task and Interrupt Management Structures. ******************
+\******************************************************************************/
+
+/* Task storage header. */
+typedef struct _gcsTASK_STORAGE * gcsTASK_STORAGE_PTR;
+typedef struct _gcsTASK_STORAGE
+{
+    /* Next allocated storage buffer. */
+    gcsTASK_STORAGE_PTR         next;
+}
+gcsTASK_STORAGE;
+
+/* Task container header. */
+typedef struct _gcsTASK_CONTAINER * gcsTASK_CONTAINER_PTR;
+typedef struct _gcsTASK_CONTAINER
+{
+    /* The number of tasks left to be processed in the container. */
+    gctINT                      referenceCount;
+
+    /* Size of the buffer. */
+    gctUINT                     size;
+
+    /* Link to the previous and the next allocated containers. */
+    gcsTASK_CONTAINER_PTR       allocPrev;
+    gcsTASK_CONTAINER_PTR       allocNext;
+
+    /* Link to the previous and the next containers in the free list. */
+    gcsTASK_CONTAINER_PTR       freePrev;
+    gcsTASK_CONTAINER_PTR       freeNext;
+}
+gcsTASK_CONTAINER;
+
+/* Kernel space task master table entry. */
+typedef struct _gcsBLOCK_TASK_ENTRY * gcsBLOCK_TASK_ENTRY_PTR;
+typedef struct _gcsBLOCK_TASK_ENTRY
+{
+    /* Pointer to the current task container for the block. */
+    gcsTASK_CONTAINER_PTR       container;
+
+    /* Pointer to the current task data within the container. */
+    gcsTASK_HEADER_PTR          task;
+
+    /* Pointer to the last link task within the container. */
+    gcsTASK_LINK_PTR            link;
+
+    /* Number of interrupts allocated for this block. */
+    gctUINT                     interruptCount;
+
+    /* The index of the current interrupt. */
+    gctUINT                     interruptIndex;
+
+    /* Interrupt semaphore. */
+    gctSEMAPHORE                interruptSemaphore;
+
+    /* Interrupt value array. */
+    gctINT32                    interruptArray[32];
+}
+gcsBLOCK_TASK_ENTRY;
+
+
+/******************************************************************************\
+********************* Command Queue Management Structures. *********************
+\******************************************************************************/
+
+/* Command queue kernel element pointer. */
+typedef struct _gcsKERNEL_CMDQUEUE * gcsKERNEL_CMDQUEUE_PTR;
+
+/* Command queue object handler function type. */
+typedef gceSTATUS (* gctOBJECT_HANDLER) (
+    gckVGKERNEL Kernel,
+    gcsKERNEL_CMDQUEUE_PTR Entry
+    );
+
+/* Command queue kernel element. */
+typedef struct _gcsKERNEL_CMDQUEUE
+{
+    /* The number of buffers in the queue. */
+    gcsCMDBUFFER_PTR            commandBuffer;
+
+    /* Pointer to the object handler function. */
+    gctOBJECT_HANDLER           handler;
+}
+gcsKERNEL_CMDQUEUE;
+
+/* Command queue header. */
+typedef struct _gcsKERNEL_QUEUE_HEADER * gcsKERNEL_QUEUE_HEADER_PTR;
+typedef struct _gcsKERNEL_QUEUE_HEADER
+{
+    /* The size of the buffer in bytes. */
+    gctUINT                     size;
+
+    /* The number of pending entries to be processed. */
+    volatile gctUINT            pending;
+
+    /* The current command queue entry. */
+    gcsKERNEL_CMDQUEUE_PTR      currentEntry;
+
+    /* Next buffer. */
+    gcsKERNEL_QUEUE_HEADER_PTR  next;
+}
+gcsKERNEL_QUEUE_HEADER;
+
+
+/******************************************************************************\
+******************************* gckVGCOMMAND Object *******************************
+\******************************************************************************/
+
+/* gckVGCOMMAND object. */
+struct _gckVGCOMMAND
+{
+    /***************************************************************************
+    ** Object data and pointers.
+    */
+
+    gcsOBJECT                   object;
+    gckVGKERNEL                 kernel;
+    gckOS                       os;
+    gckVGHARDWARE                   hardware;
+
+    /* Features. */
+    gctBOOL                     fe20;
+    gctBOOL                     vg20;
+    gctBOOL                     vg21;
+
+
+    /***************************************************************************
+    ** Enable command queue dumping.
+    */
+
+    gctBOOL                     enableDumping;
+
+
+    /***************************************************************************
+    ** Bus Error interrupt.
+    */
+
+    gctINT32                    busErrorInt;
+
+
+    /***************************************************************************
+    ** Command buffer information.
+    */
+
+    gcsCOMMAND_BUFFER_INFO      info;
+
+
+    /***************************************************************************
+    ** Synchronization objects.
+    */
+
+    gctPOINTER                  queueMutex;
+    gctPOINTER                  taskMutex;
+    gctPOINTER                  commitMutex;
+
+
+    /***************************************************************************
+    ** Task management.
+    */
+
+    /* The head of the storage buffer linked list. */
+    gcsTASK_STORAGE_PTR         taskStorage;
+
+    /* Allocation size. */
+    gctUINT                     taskStorageGranularity;
+    gctUINT                     taskStorageUsable;
+
+    /* The free container list. */
+    gcsTASK_CONTAINER_PTR       taskFreeHead;
+    gcsTASK_CONTAINER_PTR       taskFreeTail;
+
+    /* Task table */
+    gcsBLOCK_TASK_ENTRY         taskTable[gcvBLOCK_COUNT];
+
+
+    /***************************************************************************
+    ** Command queue.
+    */
+
+    /* Pointer to the allocated queue memory. */
+    gcsKERNEL_QUEUE_HEADER_PTR  queue;
+
+    /* Pointer to the current available queue from which new queue entries
+       will be allocated. */
+    gcsKERNEL_QUEUE_HEADER_PTR  queueHead;
+
+    /* If different from queueHead, points to the command queue which is
+       currently being executed by the hardware. */
+    gcsKERNEL_QUEUE_HEADER_PTR  queueTail;
+
+    /* Points to the queue to merge the tail with when the tail is processed. */
+    gcsKERNEL_QUEUE_HEADER_PTR  mergeQueue;
+
+    /* Queue overflow counter. */
+    gctUINT                     queueOverflow;
+
+
+    /***************************************************************************
+    ** Context.
+    */
+
+    /* Context counter used for unique ID. */
+    gctUINT64                   contextCounter;
+
+    /* Current context ID. */
+    gctUINT64                   currentContext;
+
+    /* Command queue power semaphore. */
+    gctPOINTER                  powerSemaphore;
+    gctINT32                    powerStallInt;
+    gcsCMDBUFFER_PTR            powerStallBuffer;
+    gctSIGNAL                   powerStallSignal;
+
+};
+
+/******************************************************************************\
+************************ gckVGCOMMAND Object Internal API. ***********************
+\******************************************************************************/
+
+/* Initialize architecture dependent command buffer information. */
+gceSTATUS
+gckVGCOMMAND_InitializeInfo(
+    IN gckVGCOMMAND Command
+    );
+
+/* Form a STATE command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_StateCommand(
+    IN gckVGCOMMAND Command,
+    IN gctUINT32 Pipe,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 Count,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form a RESTART command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_RestartCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form a FETCH command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_FetchCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form a CALL command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_CallCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FetchAddress,
+    IN gctUINT FetchCount,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form a RETURN command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_ReturnCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form an EVENT command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_EventCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gceBLOCK Block,
+    IN gctINT32 InterruptId,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Form an END command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_EndCommand(
+    IN gckVGCOMMAND Command,
+    IN gctPOINTER Logical,
+    IN gctINT32 InterruptId,
+    IN OUT gctUINT32 * Bytes
+    );
+
+#endif  /* __gc_hal_kernel_hardware_command_h_ */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c
@@ -0,0 +1,2384 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#include "gc_feature_database.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE    gcvZONE_HARDWARE
+
+typedef enum
+{
+    gcvPOWER_FLAG_INITIALIZE    = 1 << 0,
+    gcvPOWER_FLAG_STALL         = 1 << 1,
+    gcvPOWER_FLAG_STOP          = 1 << 2,
+    gcvPOWER_FLAG_START         = 1 << 3,
+    gcvPOWER_FLAG_RELEASE       = 1 << 4,
+    gcvPOWER_FLAG_DELAY         = 1 << 5,
+    gcvPOWER_FLAG_SAVE          = 1 << 6,
+    gcvPOWER_FLAG_ACQUIRE       = 1 << 7,
+    gcvPOWER_FLAG_POWER_OFF     = 1 << 8,
+    gcvPOWER_FLAG_CLOCK_OFF     = 1 << 9,
+    gcvPOWER_FLAG_CLOCK_ON      = 1 << 10,
+    gcvPOWER_FLAG_NOP           = 1 << 11,
+}
+gcePOWER_FLAGS;
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_ResetGPU(
+    IN gckOS Os
+    )
+{
+    gctUINT32 control, idle;
+    gceSTATUS status;
+
+    /* Read register. */
+    gcmkONERROR(gckOS_ReadRegisterEx(Os,
+                                     gcvCORE_VG,
+                                     0x00000,
+                                     &control));
+
+    for (;;)
+    {
+        /* Disable clock gating. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                    gcvCORE_VG,
+                    0x00104,
+                    0x00000000));
+
+        /* Wait for clock being stable. */
+        gcmkONERROR(gckOS_Delay(Os, 1));
+
+        /* Isolate the GPU. */
+        control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          gcvCORE_VG,
+                                          0x00000,
+                                          control));
+
+        /* Set soft reset. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          gcvCORE_VG,
+                                          0x00000,
+                                          ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))));
+
+        /* Wait for reset. */
+        gcmkONERROR(gckOS_Delay(Os, 1));
+
+        /* Reset soft reset bit. */
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          gcvCORE_VG,
+                                          0x00000,
+                                          ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ?
+ 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ?
+ 12:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12)))));
+
+        /* Reset GPU isolation. */
+        control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ?
+ 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ?
+ 19:19) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19)));
+
+        gcmkONERROR(gckOS_WriteRegisterEx(Os,
+                                          gcvCORE_VG,
+                                          0x00000,
+                                          control));
+
+        /* Read idle register. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Os,
+                                         gcvCORE_VG,
+                                         0x00004,
+                                         &idle));
+
+        if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0)
+        {
+            continue;
+        }
+
+        /* Read reset register. */
+        gcmkONERROR(gckOS_ReadRegisterEx(Os,
+                                         gcvCORE_VG,
+                                         0x00000,
+                                         &control));
+
+        if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0)
+        ||  ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0)
+        )
+        {
+            continue;
+        }
+
+        /* GPU is idle. */
+        break;
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+
+OnError:
+
+    /* Return the error. */
+    return status;
+}
+
+
+static gceSTATUS
+_IdentifyHardware(
+    IN gckOS Os,
+    IN gckVGHARDWARE Hardware,
+    OUT gceCHIPMODEL * ChipModel,
+    OUT gctUINT32 * ChipRevision,
+    OUT gctUINT32 * ChipFeatures,
+    OUT gctUINT32 * ChipMinorFeatures,
+    OUT gctUINT32 * ChipMinorFeatures2
+    )
+{
+    gceSTATUS status;
+    gctUINT32 chipIdentity;
+
+    do
+    {
+        /* Read chip identity register. */
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG, 0x00018, &chipIdentity));
+
+        /* Special case for older graphic cores. */
+        if (((((gctUINT32) (chipIdentity)) >> (0 ?
+ 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+        {
+            *ChipModel    = gcv500;
+            *ChipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+        }
+
+        else
+        {
+            /* Read chip identity register. */
+            gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG,
+                                            0x00020,
+                                            (gctUINT32 *) ChipModel));
+
+            /* Read CHIP_REV register. */
+            gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG,
+                                            0x00024,
+                                            ChipRevision));
+        }
+
+        /* Read chip feature register. */
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x0001C, ChipFeatures
+            ));
+
+        /* Read chip minor feature register. */
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x00034, ChipMinorFeatures
+            ));
+
+        /* Read chip minor feature register #2. */
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x00074, ChipMinorFeatures2
+            ));
+
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x000A8, &Hardware->productID
+            ));
+
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x000E8, &Hardware->ecoID
+            ));
+
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(
+            Os, gcvCORE_VG, 0x00030, &Hardware->customerID
+            ));
+
+        gcmkTRACE(
+            gcvLEVEL_VERBOSE,
+            "ChipModel=0x%08X\n"
+            "ChipRevision=0x%08X\n"
+            "ChipFeatures=0x%08X\n"
+            "ChipMinorFeatures=0x%08X\n"
+            "ChipMinorFeatures2=0x%08X\n",
+            *ChipModel,
+            *ChipRevision,
+            *ChipFeatures,
+            *ChipMinorFeatures,
+            *ChipMinorFeatures2
+            );
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Return the status. */
+    return status;
+}
+
+#if gcdPOWEROFF_TIMEOUT
+void
+_VGPowerTimerFunction(
+    gctPOINTER Data
+    )
+{
+    gckVGHARDWARE hardware = (gckVGHARDWARE)Data;
+    gcmkVERIFY_OK(
+        gckVGHARDWARE_SetPowerState(hardware, gcvPOWER_OFF_TIMEOUT));
+}
+#endif
+
+/******************************************************************************\
+****************************** gckVGHARDWARE API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_Construct
+**
+**  Construct a new gckVGHARDWARE object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an initialized gckOS object.
+**
+**  OUTPUT:
+**
+**      gckVGHARDWARE * Hardware
+**          Pointer to a variable that will hold the pointer to the gckVGHARDWARE
+**          object.
+*/
+gceSTATUS
+gckVGHARDWARE_Construct(
+    IN gckOS Os,
+    OUT gckVGHARDWARE * Hardware
+    )
+{
+    gckVGHARDWARE hardware = gcvNULL;
+    gceSTATUS status;
+    gceCHIPMODEL chipModel;
+    gctUINT32 chipRevision;
+    gctUINT32 chipFeatures;
+    gctUINT32 chipMinorFeatures;
+    gctUINT32 chipMinorFeatures2;
+    gcsFEATURE_DATABASE * database;
+
+    gcmkHEADER_ARG("Os=0x%x Hardware=0x%x ", Os, Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+    do
+    {
+        gcmkERR_BREAK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvTRUE, gcvTRUE));
+
+        status = _ResetGPU(Os);
+
+        if (status != gcvSTATUS_OK)
+        {
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                "_ResetGPU failed: status=%d\n", status);
+        }
+
+        /* Allocate the gckVGHARDWARE object. */
+        gcmkERR_BREAK(gckOS_Allocate(Os,
+            gcmSIZEOF(struct _gckVGHARDWARE), (gctPOINTER *) &hardware
+            ));
+
+        /* Identify the hardware. */
+        gcmkERR_BREAK(_IdentifyHardware(Os, hardware,
+            &chipModel, &chipRevision,
+            &chipFeatures, &chipMinorFeatures, &chipMinorFeatures2
+            ));
+
+        /* Initialize the gckVGHARDWARE object. */
+        hardware->object.type = gcvOBJ_HARDWARE;
+        hardware->os = Os;
+
+        /* Set chip identity. */
+        hardware->chipModel          = chipModel;
+        hardware->chipRevision       = chipRevision;
+        hardware->chipFeatures       = chipFeatures;
+        hardware->chipMinorFeatures  = chipMinorFeatures;
+        hardware->chipMinorFeatures2 = chipMinorFeatures2;
+
+        hardware->powerMutex            = gcvNULL;
+        hardware->chipPowerState        = gcvPOWER_ON;
+        hardware->chipPowerStateGlobal  = gcvPOWER_ON;
+        hardware->clockState            = gcvTRUE;
+        hardware->powerState            = gcvTRUE;
+
+#if gcdPOWEROFF_TIMEOUT
+        hardware->powerOffTime          = 0;
+        hardware->powerOffTimeout       = gcdPOWEROFF_TIMEOUT;
+
+        gcmkVERIFY_OK(gckOS_CreateTimer(Os,
+                                        _VGPowerTimerFunction,
+                                        (gctPOINTER)hardware,
+                                        &hardware->powerOffTimer));
+#endif
+
+        database = hardware->featureDatabase = gcQueryFeatureDB(
+            hardware->chipModel,
+            hardware->chipRevision,
+            hardware->productID,
+            hardware->ecoID,
+            hardware->customerID
+        );
+
+        if (database == gcvNULL)
+        {
+            gcmkPRINT("[galcore]: Feature database is not found,"
+                      "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x",
+                      hardware->chipModel,
+                      hardware->chipRevision,
+                      hardware->productID,
+                      hardware->ecoID);
+            /* gcmkERR_BREAK(gcvSTATUS_NOT_FOUND); */
+        }
+
+        /* Determine whether FE 2.0 is present. */
+        hardware->fe20 = ((((gctUINT32) (hardware->chipFeatures)) >> (0 ?
+ 28:28) & ((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1)))))) == (0x1  & ((gctUINT32) ((((1 ?
+ 28:28) - (0 ?
+ 28:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 28:28) - (0 ? 28:28) + 1)))))));
+
+        /* Determine whether VG 2.0 is present. */
+        hardware->vg20 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ?
+ 13:13) & ((gctUINT32) ((((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1)))))) == (0x1  & ((gctUINT32) ((((1 ?
+ 13:13) - (0 ?
+ 13:13) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:13) - (0 ? 13:13) + 1)))))));
+
+        /* Determine whether VG 2.1 is present. */
+        hardware->vg21 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ?
+ 18:18) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1)))))) == (0x1  & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ?
+ 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ? 18:18) + 1)))))));
+
+        /* Determine whether fc is present. */
+        hardware->fc = (((((gctUINT32) (hardware->chipFeatures)) >> (0 ? 0:0 )) & ((gctUINT32) ((((1 ? 0:0 ) - (0 ? 0:0 ) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0 ) - (0 ? 0:0 ) + 1)))))) );
+
+
+        /* Set default event mask. */
+        hardware->eventMask = 0xFFFFFFFF;
+
+        gcmkERR_BREAK(gckOS_AtomConstruct(Os, &hardware->pageTableDirty));
+
+        /* Set fast clear to auto. */
+        gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(hardware, -1));
+
+        gcmkERR_BREAK(gckOS_CreateMutex(Os, &hardware->powerMutex));
+
+        /* Enable power management by default. */
+        hardware->options.powerManagement = gcvTRUE;
+
+        /* Return pointer to the gckVGHARDWARE object. */
+        *Hardware = hardware;
+
+        gcmkFOOTER_NO();
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+#if gcdPOWEROFF_TIMEOUT
+    if (hardware != gcvNULL && hardware->powerOffTimer != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer));
+        gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerOffTimer));
+    }
+#endif
+
+    gcmkVERIFY_OK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvFALSE, gcvFALSE));
+
+    if (hardware != gcvNULL && hardware->pageTableDirty != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty));
+    }
+
+    if (hardware != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_Free(Os, hardware));
+    }
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_Destroy
+**
+**  Destroy an gckVGHARDWARE object.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object that needs to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_Destroy(
+    IN gckVGHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=0x%x ", Hardware);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Mark the object as unknown. */
+    Hardware->object.type = gcvOBJ_UNKNOWN;
+
+    if (Hardware->powerMutex != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_DeleteMutex(
+            Hardware->os, Hardware->powerMutex));
+    }
+
+#if gcdPOWEROFF_TIMEOUT
+    gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer));
+    gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerOffTimer));
+#endif
+
+    if (Hardware->pageTableDirty != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty));
+    }
+
+    /* Free the object. */
+    status = gckOS_Free(Hardware->os, Hardware);
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_QueryMemory
+**
+**  Query the amount of memory available on the hardware.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * InternalSize
+**          Pointer to a variable that will hold the size of the internal video
+**          memory in bytes.  If 'InternalSize' is gcvNULL, no information of the
+**          internal memory will be returned.
+**
+**      gctUINT32 * InternalBaseAddress
+**          Pointer to a variable that will hold the hardware's base address for
+**          the internal video memory.  This pointer cannot be gcvNULL if
+**          'InternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * InternalAlignment
+**          Pointer to a variable that will hold the hardware's base address for
+**          the internal video memory.  This pointer cannot be gcvNULL if
+**          'InternalSize' is also non-gcvNULL.
+**
+**      gctSIZE_T * ExternalSize
+**          Pointer to a variable that will hold the size of the external video
+**          memory in bytes.  If 'ExternalSize' is gcvNULL, no information of the
+**          external memory will be returned.
+**
+**      gctUINT32 * ExternalBaseAddress
+**          Pointer to a variable that will hold the hardware's base address for
+**          the external video memory.  This pointer cannot be gcvNULL if
+**          'ExternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * ExternalAlignment
+**          Pointer to a variable that will hold the hardware's base address for
+**          the external video memory.  This pointer cannot be gcvNULL if
+**          'ExternalSize' is also non-gcvNULL.
+**
+**      gctUINT32 * HorizontalTileSize
+**          Number of horizontal pixels per tile.  If 'HorizontalTileSize' is
+**          gcvNULL, no horizontal pixel per tile will be returned.
+**
+**      gctUINT32 * VerticalTileSize
+**          Number of vertical pixels per tile.  If 'VerticalTileSize' is
+**          gcvNULL, no vertical pixel per tile will be returned.
+*/
+gceSTATUS
+gckVGHARDWARE_QueryMemory(
+    IN gckVGHARDWARE Hardware,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * InternalBaseAddress,
+    OUT gctUINT32 * InternalAlignment,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ExternalBaseAddress,
+    OUT gctUINT32 * ExternalAlignment,
+    OUT gctUINT32 * HorizontalTileSize,
+    OUT gctUINT32 * VerticalTileSize
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x InternalSize=0x%x InternalBaseAddress=0x%x InternalAlignment=0x%x"
+        "ExternalSize=0x%x ExternalBaseAddress=0x%x ExternalAlignment=0x%x HorizontalTileSize=0x%x VerticalTileSize=0x%x",
+        Hardware, InternalSize, InternalBaseAddress, InternalAlignment,
+        ExternalSize, ExternalBaseAddress, ExternalAlignment, HorizontalTileSize, VerticalTileSize);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (InternalSize != gcvNULL)
+    {
+        /* No internal memory. */
+        *InternalSize = 0;
+    }
+
+    if (ExternalSize != gcvNULL)
+    {
+        /* No external memory. */
+        *ExternalSize = 0;
+    }
+
+    if (HorizontalTileSize != gcvNULL)
+    {
+        /* 4x4 tiles. */
+        *HorizontalTileSize = 4;
+    }
+
+    if (VerticalTileSize != gcvNULL)
+    {
+        /* 4x4 tiles. */
+        *VerticalTileSize = 4;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_QueryChipIdentity
+**
+**  Query the identity of the hardware.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gceCHIPMODEL * ChipModel
+**          If 'ChipModel' is not gcvNULL, the variable it points to will
+**          receive the model of the chip.
+**
+**      gctUINT32 * ChipRevision
+**          If 'ChipRevision' is not gcvNULL, the variable it points to will
+**          receive the revision of the chip.
+**
+**      gctUINT32 * ChipFeatures
+**          If 'ChipFeatures' is not gcvNULL, the variable it points to will
+**          receive the feature set of the chip.
+**
+**      gctUINT32 * ChipMinorFeatures
+**          If 'ChipMinorFeatures' is not gcvNULL, the variable it points to
+**          will receive the minor feature set of the chip.
+**
+**      gctUINT32 * ChipMinorFeatures2
+**          If 'ChipMinorFeatures2' is not gcvNULL, the variable it points to
+**          will receive the minor feature set of the chip.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_QueryChipIdentity(
+    IN gckVGHARDWARE Hardware,
+    OUT gceCHIPMODEL * ChipModel,
+    OUT gctUINT32 * ChipRevision,
+    OUT gctUINT32 * ProductID,
+    OUT gctUINT32 * EcoID,
+    OUT gctUINT32* CustomerID,
+    OUT gctUINT32* ChipFeatures,
+    OUT gctUINT32* ChipMinorFeatures,
+    OUT gctUINT32* ChipMinorFeatures2
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x ChipModel=0x%x ChipRevision=0x%x ChipFeatures = 0x%x ChipMinorFeatures = 0x%x ChipMinorFeatures2 = 0x%x",
+                   Hardware, ChipModel, ChipRevision, ChipFeatures, ChipMinorFeatures, ChipMinorFeatures2);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Return chip model. */
+    if (ChipModel != gcvNULL)
+    {
+        *ChipModel = Hardware->chipModel;
+    }
+
+    /* Return revision number. */
+    if (ChipRevision != gcvNULL)
+    {
+        *ChipRevision = Hardware->chipRevision;
+    }
+
+    /* Return feature set. */
+    if (ChipFeatures != gcvNULL)
+    {
+        gctUINT32 features = Hardware->chipFeatures;
+
+        if (Hardware->fc)
+        {
+            features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->options.allowFastClear) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+        }
+
+        /* Mark 2D pipe as available for GC500.0 since it did not have this *\
+        \* bit.                                                             */
+        if ((Hardware->chipModel == gcv500)
+        &&  (Hardware->chipRevision == 0)
+        )
+        {
+            features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+        }
+
+        /* Mark 2D pipe as available for GC300 since it did not have this   *\
+        \* bit.                                                             */
+        if (Hardware->chipModel == gcv300)
+        {
+            features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 9:9) - (0 ?
+ 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+        }
+
+        *ChipFeatures = features;
+    }
+
+    /* Return minor feature set. */
+    if (ChipMinorFeatures != gcvNULL)
+    {
+        *ChipMinorFeatures = Hardware->chipMinorFeatures;
+    }
+
+    /* Return minor feature set #2. */
+    if (ChipMinorFeatures2 != gcvNULL)
+    {
+        *ChipMinorFeatures2 = Hardware->chipMinorFeatures2;
+    }
+
+    if (ProductID != gcvNULL)
+    {
+        *ProductID = Hardware->productID;
+    }
+
+    if (EcoID != gcvNULL)
+    {
+        *EcoID = Hardware->ecoID;
+    }
+
+    if (CustomerID != gcvNULL)
+    {
+        *CustomerID = Hardware->customerID;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_ConvertFormat
+**
+**  Convert an API format to hardware parameters.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object.
+**
+**      gceSURF_FORMAT Format
+**          API format to convert.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * BitsPerPixel
+**          Pointer to a variable that will hold the number of bits per pixel.
+**
+**      gctUINT32 * BytesPerTile
+**          Pointer to a variable that will hold the number of bytes per tile.
+*/
+gceSTATUS
+gckVGHARDWARE_ConvertFormat(
+    IN gckVGHARDWARE Hardware,
+    IN gceSURF_FORMAT Format,
+    OUT gctUINT32 * BitsPerPixel,
+    OUT gctUINT32 * BytesPerTile
+    )
+{
+    gctUINT32 bitsPerPixel;
+    gctUINT32 bytesPerTile;
+
+    gcmkHEADER_ARG("Hardware=0x%x Format=0x%x BitsPerPixel=0x%x BytesPerTile = 0x%x",
+                   Hardware, Format, BitsPerPixel, BytesPerTile);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Dispatch on format. */
+    switch (Format)
+    {
+    case gcvSURF_A1:
+    case gcvSURF_L1:
+        /* 1-bpp format. */
+        bitsPerPixel  = 1;
+        bytesPerTile  = (1 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_A4:
+        /* 4-bpp format. */
+        bitsPerPixel  = 4;
+        bytesPerTile  = (4 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_INDEX8:
+    case gcvSURF_A8:
+    case gcvSURF_L8:
+        /* 8-bpp format. */
+        bitsPerPixel  = 8;
+        bytesPerTile  = (8 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_YV12:
+        /* 12-bpp planar YUV formats. */
+        bitsPerPixel  = 12;
+        bytesPerTile  = (12 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_NV12:
+        /* 12-bpp planar YUV formats. */
+        bitsPerPixel  = 12;
+        bytesPerTile  = (12 * 4 * 4) / 8;
+        break;
+
+    /* 4444 variations. */
+    case gcvSURF_X4R4G4B4:
+    case gcvSURF_A4R4G4B4:
+    case gcvSURF_R4G4B4X4:
+    case gcvSURF_R4G4B4A4:
+    case gcvSURF_B4G4R4X4:
+    case gcvSURF_B4G4R4A4:
+    case gcvSURF_X4B4G4R4:
+    case gcvSURF_A4B4G4R4:
+
+    /* 1555 variations. */
+    case gcvSURF_X1R5G5B5:
+    case gcvSURF_A1R5G5B5:
+    case gcvSURF_R5G5B5X1:
+    case gcvSURF_R5G5B5A1:
+    case gcvSURF_X1B5G5R5:
+    case gcvSURF_A1B5G5R5:
+    case gcvSURF_B5G5R5X1:
+    case gcvSURF_B5G5R5A1:
+
+    /* 565 variations. */
+    case gcvSURF_R5G6B5:
+    case gcvSURF_B5G6R5:
+
+    case gcvSURF_A8L8:
+    case gcvSURF_YUY2:
+    case gcvSURF_UYVY:
+#if gcdVG_ONLY
+    case gcvSURF_YV16:
+#endif
+    case gcvSURF_D16:
+        /* 16-bpp format. */
+        bitsPerPixel  = 16;
+        bytesPerTile  = (16 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_X8R8G8B8:
+    case gcvSURF_A8R8G8B8:
+    case gcvSURF_X8B8G8R8:
+    case gcvSURF_A8B8G8R8:
+    case gcvSURF_R8G8B8X8:
+    case gcvSURF_R8G8B8A8:
+    case gcvSURF_B8G8R8X8:
+    case gcvSURF_B8G8R8A8:
+    case gcvSURF_D32:
+        /* 32-bpp format. */
+        bitsPerPixel  = 32;
+        bytesPerTile  = (32 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_D24S8:
+        /* 24-bpp format. */
+        bitsPerPixel  = 32;
+        bytesPerTile  = (32 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_DXT1:
+    case gcvSURF_ETC1:
+        bitsPerPixel  = 4;
+        bytesPerTile  = (4 * 4 * 4) / 8;
+        break;
+
+    case gcvSURF_DXT2:
+    case gcvSURF_DXT3:
+    case gcvSURF_DXT4:
+    case gcvSURF_DXT5:
+        bitsPerPixel  = 8;
+        bytesPerTile  = (8 * 4 * 4) / 8;
+        break;
+
+    default:
+        /* Invalid format. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    /* Set the result. */
+    if (BitsPerPixel != gcvNULL)
+    {
+        * BitsPerPixel = bitsPerPixel;
+    }
+
+    if (BytesPerTile != gcvNULL)
+    {
+        * BytesPerTile = bytesPerTile;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_SplitMemory
+**
+**  Split a hardware specific memory address into a pool and offset.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object.
+**
+**      gctUINT32 Address
+**          Address in hardware specific format.
+**
+**  OUTPUT:
+**
+**      gcePOOL * Pool
+**          Pointer to a variable that will hold the pool type for the address.
+**
+**      gctUINT32 * Offset
+**          Pointer to a variable that will hold the offset for the address.
+*/
+gceSTATUS
+gckVGHARDWARE_SplitMemory(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Address,
+    OUT gcePOOL * Pool,
+    OUT gctUINT32 * Offset
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Pool=0x%x Offset = 0x%x",
+                   Hardware, Address, Pool, Offset);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Offset != gcvNULL);
+
+    /* Dispatch on memory type. */
+    switch ((((((gctUINT32) (Address)) >> (0 ? 1:0)) & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1)))))) ))
+    {
+    case 0x0:
+        /* System memory. */
+        *Pool = gcvPOOL_SYSTEM;
+        break;
+
+    case 0x2:
+        /* Virtual memory. */
+        *Pool = gcvPOOL_VIRTUAL;
+        break;
+
+    default:
+        /* Invalid memory type. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    /* Return offset of address. */
+    *Offset = ((((gctUINT32) (Address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_Execute
+**
+**  Kickstart the hardware's command processor with an initialized command
+**  buffer.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to the gckVGHARDWARE object.
+**
+**      gctUINT32 Address
+**          Address of the command buffer.
+**
+**      gctSIZE_T Count
+**          Number of command-sized data units to be executed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_Execute(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Count
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Count=0x%x",
+                   Hardware, Address, Count);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    do
+    {
+        /* Enable all events. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(
+            Hardware->os,
+            gcvCORE_VG,
+            0x00014,
+            Hardware->eventMask
+            ));
+
+        if (Hardware->fe20)
+        {
+            /* Write address register. */
+            gcmkERR_BREAK(gckOS_WriteRegisterEx(
+                Hardware->os,
+                gcvCORE_VG,
+                0x00500,
+                gcmkFIXADDRESS(Address)
+                ));
+
+            /* Write control register. */
+            gcmkERR_BREAK(gckOS_WriteRegisterEx(
+                Hardware->os,
+                gcvCORE_VG,
+                0x00504,
+                Count
+                ));
+        }
+        else
+        {
+            /* Write address register. */
+            gcmkERR_BREAK(gckOS_WriteRegisterEx(
+                Hardware->os,
+                gcvCORE_VG,
+                0x00654,
+                gcmkFIXADDRESS(Address)
+                ));
+
+            /* Write control register. */
+            gcmkERR_BREAK(gckOS_WriteRegisterEx(
+                Hardware->os,
+                gcvCORE_VG,
+                0x00658,
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) |
+                ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+                ));
+        }
+
+        /* Success. */
+        gcmkFOOTER();
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_ConvertLogical
+**
+**  Convert a logical system address into a hardware specific address.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Hardware
+**          Pointer to an gckVGHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Logical address to convert.
+**
+**      gctBOOL InUserSpace
+**          gcvTRUE if the memory in user space.
+**
+**      gctUINT32* Address
+**          Return hardware specific address.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_ConvertLogical(
+    IN gckVGHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctBOOL InUserSpace,
+    OUT gctUINT32 * Address
+    )
+{
+    gctPHYS_ADDR_T physical;
+    gctUINT32 address;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x InUserSpace=%d Address=0x%x",
+                   Hardware, Logical, InUserSpace, Address);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    do
+    {
+        /* Convert logical address into a physical address. */
+        if (InUserSpace)
+        {
+            gcmkERR_BREAK(gckOS_UserLogicalToPhysical(
+                Hardware->os, Logical, &physical
+                ));
+        }
+        else
+        {
+            gcmkERR_BREAK(gckOS_GetPhysicalAddress(
+                Hardware->os, Logical, &physical
+                ));
+        }
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Hardware->os, physical, &physical));
+
+        gcmkSAFECASTPHYSADDRT(address, physical);
+
+        /* Return hardware specific address. */
+        *Address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+        /* Success. */
+        gcmkFOOTER();
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_QuerySystemMemory
+**
+**  Query the command buffer alignment and number of reserved bytes.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Harwdare
+**          Pointer to an gckVGHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * SystemSize
+**          Pointer to a variable that receives the maximum size of the system
+**          memory.
+**
+**      gctUINT32 * SystemBaseAddress
+**          Poinetr to a variable that receives the base address for system
+**          memory.
+*/
+gceSTATUS gckVGHARDWARE_QuerySystemMemory(
+    IN gckVGHARDWARE Hardware,
+    OUT gctSIZE_T * SystemSize,
+    OUT gctUINT32 * SystemBaseAddress
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x SystemSize=0x%x SystemBaseAddress=0x%x",
+                   Hardware, SystemSize, SystemBaseAddress);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (SystemSize != gcvNULL)
+    {
+        /* Maximum system memory can be 2GB. */
+        *SystemSize = (gctSIZE_T)(1 << 31);
+    }
+
+    if (SystemBaseAddress != gcvNULL)
+    {
+        /* Set system memory base address. */
+        *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_SetMMU
+**
+**  Set the page table base address.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Harwdare
+**          Pointer to an gckVGHARDWARE object.
+**
+**      gctPOINTER Logical
+**          Logical address of the page table.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckVGHARDWARE_SetMMU(
+    IN gckVGHARDWARE Hardware,
+    IN gctPOINTER Logical
+    )
+{
+    gceSTATUS status;
+    gctUINT32 address = 0;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x",
+                   Hardware, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    do
+    {
+        /* Convert the logical address into an hardware address. */
+        gcmkERR_BREAK(gckVGHARDWARE_ConvertLogical(Hardware, Logical,
+                                      gcvFALSE, &address));
+
+        /* Write the AQMemoryFePageTable register. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                      0x00400,
+                                      gcmkFIXADDRESS(address)));
+
+        /* Write the AQMemoryTxPageTable register. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                      0x00404,
+                                      gcmkFIXADDRESS(address)));
+
+        /* Write the AQMemoryPePageTable register. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                      0x00408,
+                                      gcmkFIXADDRESS(address)));
+
+        /* Write the AQMemoryPezPageTable register. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                      0x0040C,
+                                      gcmkFIXADDRESS(address)));
+
+        /* Write the AQMemoryRaPageTable register. */
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                      0x00410,
+                                      gcmkFIXADDRESS(address)));
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_FlushMMU
+**
+**  Flush the page table.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Harwdare
+**          Pointer to an gckVGHARDWARE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckVGHARDWARE_FlushMMU(
+    IN gckVGHARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gckVGCOMMAND command;
+
+    gcmkHEADER_ARG("Hardware=0x%x ", Hardware);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    do
+    {
+        gcsCMDBUFFER_PTR commandBuffer;
+        gctUINT32_PTR buffer;
+
+        /* Create a shortcut to the command buffer object. */
+        command = Hardware->kernel->command;
+
+        /* Allocate command buffer space. */
+        gcmkERR_BREAK(gckVGCOMMAND_Allocate(
+            command, 8, &commandBuffer, (gctPOINTER *) &buffer
+            ));
+
+        gckOS_WriteMemory(
+            Hardware->os,
+            &buffer[0],
+              ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)))
+            );
+
+        gckOS_WriteMemory(
+            Hardware->os,
+            &buffer[1],
+              ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 1:1) - (0 ?
+ 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 2:2) - (0 ?
+ 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 3:3) - (0 ?
+ 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 4:4) - (0 ?
+ 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+            );
+
+        gcmkERR_BREAK(gckVGCOMMAND_Execute(
+            command,
+            commandBuffer
+            ));
+    }
+    while(gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_BuildVirtualAddress
+**
+**  Build a virtual address.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Harwdare
+**          Pointer to an gckVGHARDWARE object.
+**
+**      gctUINT32 Index
+**          Index into page table.
+**
+**      gctUINT32 Offset
+**          Offset into page.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Pointer to a variable receiving te hardware address.
+*/
+gceSTATUS gckVGHARDWARE_BuildVirtualAddress(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Index,
+    IN gctUINT32 Offset,
+    OUT gctUINT32 * Address
+    )
+{
+    gctUINT32 address;
+
+    gcmkHEADER_ARG("Hardware=0x%x Index=0x%x Offset=0x%x Address=0x%x",
+                   Hardware, Index, Offset, Address);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    /* Build virtual address. */
+    address = (Index << 12) | Offset;
+
+    /* Set virtual type. */
+    address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 1:0) - (0 ?
+ 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+    /* Set the result. */
+    *Address = address;
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGHARDWARE_GetIdle(
+    IN gckVGHARDWARE Hardware,
+    OUT gctUINT32 * Data
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=0x%x Data=0x%x", Hardware, Data);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+    /* Read register and return. */
+    status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, Data);
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVGHARDWARE_SetFastClear(
+    IN gckVGHARDWARE Hardware,
+    IN gctINT Enable
+    )
+{
+    gctUINT32 debug;
+    gceSTATUS status;
+
+    if (!Hardware->fc)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    do
+    {
+        if (Enable == -1)
+        {
+            Enable = (Hardware->chipModel > gcv500) ||
+                ((Hardware->chipModel == gcv500) && (Hardware->chipRevision >= 3));
+        }
+
+        gcmkERR_BREAK(gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG,
+                                        0x00414,
+                    &debug));
+
+        debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ?
+ 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ?
+ 20:20) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20)));
+
+#ifdef AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION
+        debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION)));
+#endif
+
+        gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+                                     0x00414,
+                     debug));
+
+        Hardware->options.allowFastClear = Enable;
+
+        status = gcvFALSE;
+    }
+    while (gcvFALSE);
+
+    return status;
+}
+
+gceSTATUS
+gckVGHARDWARE_ReadInterrupt(
+    IN gckVGHARDWARE Hardware,
+    OUT gctUINT32_PTR IDs
+    )
+{
+    gceSTATUS status;
+    gcmkHEADER_ARG("Hardware=0x%x IDs=0x%x", Hardware, IDs);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(IDs != gcvNULL);
+
+    /* Read AQIntrAcknowledge register. */
+    status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG,
+                              0x00010,
+                              IDs);
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS _CommandStall(
+    gckVGHARDWARE Hardware)
+{
+    gceSTATUS status;
+    gckVGCOMMAND command;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    do
+    {
+        gctUINT32_PTR buffer;
+        command = Hardware->kernel->command;
+
+        /* Allocate command buffer space. */
+        gcmkERR_BREAK(gckVGCOMMAND_Allocate(
+            command, 8, &command->powerStallBuffer,
+            (gctPOINTER *) &buffer
+            ));
+
+        gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+            command, buffer, gcvBLOCK_PIXEL,
+            command->powerStallInt, gcvNULL));
+
+        gcmkERR_BREAK(gckVGCOMMAND_Execute(
+            command,
+            command->powerStallBuffer
+            ));
+
+        /* Wait the signal. */
+        gcmkERR_BREAK(gckOS_WaitSignal(
+            command->os,
+            command->powerStallSignal,
+            gcvFALSE,
+            command->kernel->kernel->timeOut));
+
+
+    }
+    while(gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_SetPowerState
+**
+**  Set GPU to a specified power state.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gceCHIPPOWERSTATE State
+**          Power State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_SetPowerState(
+    IN gckVGHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    )
+{
+    gceSTATUS status;
+    gckVGCOMMAND command = gcvNULL;
+    gckOS os;
+    gctUINT flag/*, clock*/;
+
+    gctBOOL acquired        = gcvFALSE;
+    gctBOOL commitMutex     = gcvFALSE;
+    gctBOOL mutexAcquired   = gcvFALSE;
+
+#if gcdPOWEROFF_TIMEOUT
+    gctBOOL timeout = gcvFALSE;
+    gctBOOL isAfter = gcvFALSE;
+    gctUINT32 currentTime;
+#endif
+
+    gctBOOL broadcast = gcvFALSE;
+    gctUINT32 process, thread;
+    gctBOOL global = gcvFALSE;
+
+#if gcdENABLE_PROFILING
+    gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime,
+              initTime, offTime, startTime, totalTime;
+#endif
+
+    /* State transition flags. */
+    static const gctUINT flags[4][4] =
+    {
+        /* gcvPOWER_ON           */
+        {   /* ON                */ 0,
+            /* IDLE              */ gcvPOWER_FLAG_NOP,
+            /* SUSPEND           */ gcvPOWER_FLAG_ACQUIRE   |
+                                    gcvPOWER_FLAG_STALL     |
+                                    gcvPOWER_FLAG_STOP      |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+            /* OFF               */ gcvPOWER_FLAG_ACQUIRE   |
+                                    gcvPOWER_FLAG_STALL     |
+                                    gcvPOWER_FLAG_STOP      |
+                                    gcvPOWER_FLAG_POWER_OFF |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+        },
+
+        /* gcvPOWER_IDLE         */
+        {   /* ON                */ gcvPOWER_FLAG_NOP,
+            /* IDLE              */ 0,
+            /* SUSPEND           */ gcvPOWER_FLAG_ACQUIRE   |
+                                    gcvPOWER_FLAG_STOP      |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+            /* OFF               */ gcvPOWER_FLAG_ACQUIRE   |
+                                    gcvPOWER_FLAG_STOP      |
+                                    gcvPOWER_FLAG_POWER_OFF |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+        },
+
+        /* gcvPOWER_SUSPEND      */
+        {   /* ON                */ gcvPOWER_FLAG_START     |
+                                    gcvPOWER_FLAG_RELEASE   |
+                                    gcvPOWER_FLAG_DELAY     |
+                                    gcvPOWER_FLAG_CLOCK_ON,
+            /* IDLE              */ gcvPOWER_FLAG_START     |
+                                    gcvPOWER_FLAG_DELAY     |
+                                    gcvPOWER_FLAG_RELEASE   |
+                                    gcvPOWER_FLAG_CLOCK_ON,
+            /* SUSPEND           */ 0,
+            /* OFF               */ gcvPOWER_FLAG_SAVE      |
+                                    gcvPOWER_FLAG_POWER_OFF |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+        },
+
+        /* gcvPOWER_OFF          */
+        {   /* ON                */ gcvPOWER_FLAG_INITIALIZE |
+                                    gcvPOWER_FLAG_START      |
+                                    gcvPOWER_FLAG_RELEASE    |
+                                    gcvPOWER_FLAG_DELAY,
+            /* IDLE              */ gcvPOWER_FLAG_INITIALIZE |
+                                    gcvPOWER_FLAG_START      |
+                                    gcvPOWER_FLAG_RELEASE    |
+                                    gcvPOWER_FLAG_DELAY,
+            /* SUSPEND           */ gcvPOWER_FLAG_INITIALIZE |
+                                    gcvPOWER_FLAG_CLOCK_OFF,
+            /* OFF               */ 0,
+        },
+    };
+
+    gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State);
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "Switching to power state %d",
+                   State);
+#endif
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    /* Get the gckOS object pointer. */
+    os = Hardware->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Get the gckCOMMAND object pointer. */
+    gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL);
+    command = Hardware->kernel->command;
+    gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND);
+
+    if (Hardware->options.powerManagement == gcvFALSE)
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /* Start profiler. */
+    gcmkPROFILE_INIT(freq, time);
+
+    /* Convert the broadcast power state. */
+    switch (State)
+    {
+    case gcvPOWER_IDLE_BROADCAST:
+        /* Convert to IDLE and note we are inside broadcast. */
+        State     = gcvPOWER_IDLE;
+        broadcast = gcvTRUE;
+        break;
+
+    case gcvPOWER_SUSPEND_BROADCAST:
+        /* Convert to SUSPEND and note we are inside broadcast. */
+        State     = gcvPOWER_SUSPEND;
+        broadcast = gcvTRUE;
+        break;
+
+    case gcvPOWER_OFF_BROADCAST:
+        /* Convert to OFF and note we are inside broadcast. */
+        State     = gcvPOWER_OFF;
+        broadcast = gcvTRUE;
+        break;
+
+    case gcvPOWER_ON_AUTO:
+        /* Convert to ON and note we are inside recovery. */
+        State = gcvPOWER_ON;
+        break;
+
+    case gcvPOWER_ON:
+    case gcvPOWER_IDLE:
+    case gcvPOWER_SUSPEND:
+    case gcvPOWER_OFF:
+        /* Mark as global power management. */
+        global = gcvTRUE;
+        break;
+
+#if gcdPOWEROFF_TIMEOUT
+    case gcvPOWER_OFF_TIMEOUT:
+        /* Convert to OFF and note we are inside broadcast. */
+        State     = gcvPOWER_OFF;
+        broadcast = gcvTRUE;
+        /* Check time out */
+        timeout = gcvTRUE;
+        break;
+#endif
+
+    default:
+        break;
+    }
+
+    /* Get current process and thread IDs. */
+    gcmkONERROR(gckOS_GetProcessID(&process));
+    gcmkONERROR(gckOS_GetThreadID(&thread));
+
+    /* Acquire the power mutex. */
+    if (broadcast)
+    {
+        /* Try to acquire the power mutex. */
+        status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0);
+
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+            /* Check if we already own this mutex. */
+            if ((Hardware->powerProcess == process)
+            &&  (Hardware->powerThread  == thread)
+            )
+            {
+                /* Bail out on recursive power management. */
+                gcmkFOOTER_NO();
+                return gcvSTATUS_OK;
+            }
+            else if (State == gcvPOWER_IDLE)
+            {
+                /* gcvPOWER_IDLE_BROADCAST is from IST,
+                ** so waiting here will cause deadlock,
+                ** if lock holder call gckCOMMAND_Stall() */
+                gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+            }
+            else
+            {
+                /* Acquire the power mutex. */
+                gcmkONERROR(gckOS_AcquireMutex(os,
+                                               Hardware->powerMutex,
+                                               gcvINFINITE));
+            }
+        }
+    }
+    else
+    {
+        /* Acquire the power mutex. */
+        gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE));
+    }
+
+    /* Get time until mtuex acquired. */
+    gcmkPROFILE_QUERY(time, mutexTime);
+
+    Hardware->powerProcess = process;
+    Hardware->powerThread  = thread;
+    mutexAcquired          = gcvTRUE;
+
+    /* Grab control flags and clock. */
+    flag  = flags[Hardware->chipPowerState][State];
+    /*clock = clocks[State];*/
+
+#if gcdPOWEROFF_TIMEOUT
+    if (timeout)
+    {
+        gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+        gcmkONERROR(
+            gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter));
+
+        /* powerOffTime is pushed forward, give up.*/
+        if (isAfter
+        /* Expect a transition start from IDLE. */
+        ||  (Hardware->chipPowerState == gcvPOWER_ON)
+        ||  (Hardware->chipPowerState == gcvPOWER_OFF)
+        )
+        {
+            /* Release the power mutex. */
+            gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+            /* No need to do anything. */
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+    }
+#endif
+
+    if (flag == 0)
+    {
+        /* Release the power mutex. */
+        gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+        /* No need to do anything. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /* internal power control */
+    if (!global)
+    {
+        if (Hardware->chipPowerStateGlobal == gcvPOWER_OFF)
+        {
+            /* Release the power mutex. */
+            gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+            /* No need to do anything. */
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+    }
+    else
+    {
+        if (flag & gcvPOWER_FLAG_ACQUIRE)
+        {
+            /* Acquire the power management semaphore. */
+            gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+            acquired = gcvTRUE;
+
+            /* avoid acquiring again. */
+            flag &= ~gcvPOWER_FLAG_ACQUIRE;
+        }
+    }
+
+    if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON))
+    {
+        /* Turn on the power. */
+        gcmkONERROR(gckOS_SetGPUPower(os, gcvCORE_VG, gcvTRUE, gcvTRUE));
+
+        /* Mark clock and power as enabled. */
+        Hardware->clockState = gcvTRUE;
+        Hardware->powerState = gcvTRUE;
+    }
+
+    /* Get time until powered on. */
+    gcmkPROFILE_QUERY(time, onTime);
+
+    if (flag & gcvPOWER_FLAG_STALL)
+    {
+        /* Acquire the mutex. */
+        gcmkONERROR(gckOS_AcquireMutex(
+            command->os,
+            command->commitMutex,
+            gcvINFINITE
+            ));
+
+        commitMutex = gcvTRUE;
+
+        gcmkONERROR(_CommandStall(Hardware));
+    }
+
+    /* Get time until stalled. */
+    gcmkPROFILE_QUERY(time, stallTime);
+
+    if (flag & gcvPOWER_FLAG_ACQUIRE)
+    {
+        /* Acquire the power management semaphore. */
+        gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+
+        acquired = gcvTRUE;
+    }
+
+
+    /* Get time until stopped. */
+    gcmkPROFILE_QUERY(time, stopTime);
+
+
+    if (flag & gcvPOWER_FLAG_DELAY)
+    {
+        /* Wait for the specified amount of time to settle coming back from
+        ** power-off or suspend state. */
+        gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY));
+    }
+
+    /* Get time until delayed. */
+    gcmkPROFILE_QUERY(time, delayTime);
+
+    if (flag & gcvPOWER_FLAG_INITIALIZE)
+    {
+
+        /* Initialize GPU here, replaced by InitializeHardware later */
+        gcmkONERROR(gckVGHARDWARE_SetMMU(Hardware, Hardware->kernel->mmu->pageTableLogical));
+        gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(Hardware, -1));
+
+        /* Force the command queue to reload the next context. */
+        command->currentContext = 0;
+    }
+
+    /* Get time until initialized. */
+    gcmkPROFILE_QUERY(time, initTime);
+
+    if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF))
+    {
+        /* Turn off the GPU power. */
+        gcmkONERROR(
+            gckOS_SetGPUPower(os,
+                              gcvCORE_VG,
+                              (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+                                                               : gcvTRUE,
+                              (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+                                                               : gcvTRUE));
+
+        /* Save current hardware power and clock states. */
+        Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+                                                                : gcvTRUE;
+        Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+                                                                : gcvTRUE;
+    }
+
+    /* Get time until off. */
+    gcmkPROFILE_QUERY(time, offTime);
+
+
+    /* Get time until started. */
+    gcmkPROFILE_QUERY(time, startTime);
+
+    if (flag & gcvPOWER_FLAG_RELEASE)
+    {
+        /* Release the power management semaphore. */
+        gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore));
+        acquired = gcvFALSE;
+    }
+
+    /* Save the new power state. */
+    Hardware->chipPowerState = State;
+
+    if (global)
+    {
+        /* Save the new power state. */
+        Hardware->chipPowerStateGlobal = State;
+    }
+
+    if (commitMutex)
+    {
+        /* Acquire the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            command->os,
+            command->commitMutex
+            ));
+    }
+
+#if gcdPOWEROFF_TIMEOUT
+    /* Reset power off time */
+    gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+    Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout;
+
+    if (State == gcvPOWER_IDLE)
+    {
+        /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */
+        gcmkVERIFY_OK(gckOS_StartTimer(os,
+                                       Hardware->powerOffTimer,
+                                       Hardware->powerOffTimeout));
+    }
+    else
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer");
+
+        /* Cancel running timer when GPU enters ON or OFF. */
+        gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer));
+    }
+#endif
+
+    /* Release the power mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+    /* Get total time. */
+    gcmkPROFILE_QUERY(time, totalTime);
+#if gcdENABLE_PROFILING
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu",
+                   freq, mutexTime, onTime, stallTime, stopTime);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+                   "  delay:%llu init:%llu off:%llu start:%llu total:%llu",
+                   delayTime, initTime, offTime, startTime, totalTime);
+#endif
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+
+    if (acquired)
+    {
+        /* Release semaphore. */
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+                                             command->powerSemaphore));
+    }
+
+    if (mutexAcquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+    }
+
+    if (commitMutex)
+    {
+        /* Acquire the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            command->os,
+            command->commitMutex
+            ));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHARDWARE_QueryPowerState
+**
+**  Get GPU power state.
+**
+**  INPUT:
+**
+**      gckHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gceCHIPPOWERSTATE* State
+**          Power State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_QueryPowerManagementState(
+    IN gckVGHARDWARE Hardware,
+    OUT gceCHIPPOWERSTATE* State
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(State != gcvNULL);
+
+    /* Return the statue. */
+    *State = Hardware->chipPowerState;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*State=%d", *State);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGHARDWARE_EnablePowerManagement
+**
+**  Configure GPU power management function.
+**  Only used in driver initialization stage.
+**
+**  INPUT:
+**
+**      gckVGHARDWARE Harwdare
+**          Pointer to an gckHARDWARE object.
+**
+**      gctBOOL Enable
+**          Power Mangement Enabling State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_EnablePowerManagement(
+    IN gckVGHARDWARE Hardware,
+    IN gctBOOL Enable
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    Hardware->options.powerManagement = Enable;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+#if gcdPOWEROFF_TIMEOUT
+gceSTATUS
+gckVGHARDWARE_SetPowerOffTimeout(
+    IN gckVGHARDWARE  Hardware,
+    IN gctUINT32    Timeout
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout);
+
+    Hardware->powerOffTimeout = Timeout;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerOffTimeout(
+    IN gckVGHARDWARE  Hardware,
+    OUT gctUINT32*  Timeout
+    )
+{
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    *Timeout = Hardware->powerOffTimeout;
+
+    gcmkFOOTER_ARG("*Timeout=%d", *Timeout);
+    return gcvSTATUS_OK;
+}
+#endif
+
+gceSTATUS
+gckVGHARDWARE_QueryIdle(
+    IN gckVGHARDWARE Hardware,
+    OUT gctBOOL_PTR IsIdle
+    )
+{
+    gceSTATUS status;
+    gctUINT32 idle;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL);
+
+    /* We are idle when the power is not ON. */
+    if (Hardware->chipPowerState != gcvPOWER_ON)
+    {
+        *IsIdle = gcvTRUE;
+    }
+
+    else
+    {
+        /* Read idle register. */
+        gcmkONERROR(
+            gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, &idle));
+
+        /* Pipe must be idle. */
+        if (((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) != 1)
+        ||  ((((((gctUINT32) (idle)) >> (0 ? 8:8)) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1)))))) ) != 1)
+        ||  ((((((gctUINT32) (idle)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ) != 1)
+        ||  ((((((gctUINT32) (idle)) >> (0 ? 10:10)) & ((gctUINT32) ((((1 ? 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1)))))) ) != 1)
+        ||  ((((((gctUINT32) (idle)) >> (0 ? 11:11)) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1)))))) ) != 1)
+        )
+        {
+            /* Something is busy. */
+            *IsIdle = gcvFALSE;
+        }
+
+        else
+        {
+            *IsIdle = gcvTRUE;
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+#endif /* gcdENABLE_VG */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_vg_h_
+#define __gc_hal_kernel_hardware_vg_h_
+
+/* gckHARDWARE object. */
+struct _gckVGHARDWARE
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckKERNEL object. */
+    gckVGKERNEL                 kernel;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Chip characteristics. */
+    gceCHIPMODEL                chipModel;
+    gctUINT32                   chipRevision;
+    gctUINT32                   productID;
+    gctUINT32                   ecoID;
+    gctUINT32                   customerID;
+    gctUINT32                   chipFeatures;
+    gctUINT32                   chipMinorFeatures;
+    gctUINT32                   chipMinorFeatures2;
+
+    /* Features. */
+    gctBOOL                     fe20;
+    gctBOOL                     vg20;
+    gctBOOL                     vg21;
+    gctBOOL                     fc;
+
+    /* Event mask. */
+    gctUINT32                   eventMask;
+
+    gctBOOL                     clockState;
+    gctBOOL                     powerState;
+    gctPOINTER                  powerMutex;
+    gctUINT32                   powerProcess;
+    gctUINT32                   powerThread;
+    gceCHIPPOWERSTATE           chipPowerState;
+    gceCHIPPOWERSTATE           chipPowerStateGlobal;
+    gctPOINTER                  pageTableDirty;
+#if gcdPOWEROFF_TIMEOUT
+    gctUINT32                   powerOffTime;
+    gctUINT32                   powerOffTimeout;
+    gctPOINTER                  powerOffTimer;
+#endif
+
+    gcsHAL_QUERY_CHIP_OPTIONS   options;
+
+    gctPOINTER                  featureDatabase;
+};
+
+#endif /* __gc_hal_kernel_hardware_h_ */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
@@ -0,0 +1,5888 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdDEC_ENABLE_AHB
+#include "viv_dec300_main.h"
+#endif
+
+#if gcdCAPTURE_ONLY_MODE
+#include "arch/gc_hal_kernel_context.h"
+#endif
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+/*******************************************************************************
+***** Version Signature *******************************************************/
+
+#define _gcmTXT2STR(t) #t
+#define gcmTXT2STR(t) _gcmTXT2STR(t)
+const char * _VERSION = "\n\0$VERSION$"
+                        gcmTXT2STR(gcvVERSION_MAJOR) "."
+                        gcmTXT2STR(gcvVERSION_MINOR) "."
+                        gcmTXT2STR(gcvVERSION_PATCH) ":"
+                        gcmTXT2STR(gcvVERSION_BUILD) "$\n";
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#define gcmDEFINE2TEXT(d) #d
+gctCONST_STRING _DispatchText[] =
+{
+    gcmDEFINE2TEXT(gcvHAL_CHIP_INFO),
+    gcmDEFINE2TEXT(gcvHAL_VERSION),
+    gcmDEFINE2TEXT(gcvHAL_SET_TIMEOUT),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_IDENTITY),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_OPTION),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_FREQUENCY),
+    gcmDEFINE2TEXT(gcvHAL_ALLOCATE_NON_PAGED_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_FREE_NON_PAGED_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_WRAP_USER_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_RELEASE_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_LOCK_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_UNLOCK_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_EXPORT_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_NAME_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_IMPORT_VIDEO_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_MAP_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_UNMAP_MEMORY),
+    gcmDEFINE2TEXT(gcvHAL_CACHE),
+    gcmDEFINE2TEXT(gcvHAL_ATTACH),
+    gcmDEFINE2TEXT(gcvHAL_DETACH),
+    gcmDEFINE2TEXT(gcvHAL_EVENT_COMMIT),
+    gcmDEFINE2TEXT(gcvHAL_COMMIT),
+    gcmDEFINE2TEXT(gcvHAL_COMMIT_DONE),
+    gcmDEFINE2TEXT(gcvHAL_USER_SIGNAL),
+    gcmDEFINE2TEXT(gcvHAL_SIGNAL),
+    gcmDEFINE2TEXT(gcvHAL_WRITE_DATA),
+    gcmDEFINE2TEXT(gcvHAL_READ_REGISTER),
+    gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER),
+    gcmDEFINE2TEXT(gcvHAL_READ_REGISTER_EX),
+    gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER_EX),
+    gcmDEFINE2TEXT(gcvHAL_GET_PROFILE_SETTING),
+    gcmDEFINE2TEXT(gcvHAL_SET_PROFILE_SETTING),
+    gcmDEFINE2TEXT(gcvHAL_READ_PROFILER_REGISTER_SETTING),
+    gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1),
+    gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2),
+    gcmDEFINE2TEXT(gcvHAL_PROFILE_REGISTERS_2D),
+    gcmDEFINE2TEXT(gcvHAL_SET_POWER_MANAGEMENT_STATE),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_POWER_MANAGEMENT_STATE),
+    gcmDEFINE2TEXT(gcvHAL_CONFIG_POWER_MANAGEMENT),
+    gcmDEFINE2TEXT(gcvHAL_GET_BASE_ADDRESS),
+    gcmDEFINE2TEXT(gcvHAL_SET_IDLE),
+    gcmDEFINE2TEXT(gcvHAL_RESET),
+    gcmDEFINE2TEXT(gcvHAL_SET_DEBUG_LEVEL_ZONE),
+    gcmDEFINE2TEXT(gcvHAL_DEBUG_DUMP),
+    gcmDEFINE2TEXT(gcvHAL_UPDATE_DEBUG_CALLBACK),
+    gcmDEFINE2TEXT(gcvHAL_CONFIG_CTX_FRAMEWORK),
+    gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_STATE),
+    gcmDEFINE2TEXT(gcvHAL_DUMP_EVENT),
+    gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_PROFILE),
+    gcmDEFINE2TEXT(gcvHAL_TIMESTAMP),
+    gcmDEFINE2TEXT(gcvHAL_DATABASE),
+    gcmDEFINE2TEXT(gcvHAL_GET_FRAME_INFO),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_COMMAND_BUFFER),
+    gcmDEFINE2TEXT(gcvHAL_SET_FSCALE_VALUE),
+    gcmDEFINE2TEXT(gcvHAL_GET_FSCALE_VALUE),
+    gcmDEFINE2TEXT(gcvHAL_QUERY_RESET_TIME_STAMP),
+    gcmDEFINE2TEXT(gcvHAL_CREATE_NATIVE_FENCE),
+    gcmDEFINE2TEXT(gcvHAL_WAIT_NATIVE_FENCE),
+    gcmDEFINE2TEXT(gcvHAL_SHBUF),
+    gcmDEFINE2TEXT(gcvHAL_GET_GRAPHIC_BUFFER_FD),
+    gcmDEFINE2TEXT(gcvHAL_SET_VIDEO_MEMORY_METADATA),
+    gcmDEFINE2TEXT(gcvHAL_GET_VIDEO_MEMORY_FD),
+    gcmDEFINE2TEXT(gcvHAL_DESTROY_MMU),
+    gcmDEFINE2TEXT(gcvHAL_WAIT_FENCE),
+    gcmDEFINE2TEXT(gcvHAL_DEVICE_MUTEX),
+    gcmDEFINE2TEXT(gcvHAL_DEC200_TEST),
+    gcmDEFINE2TEXT(gcvHAL_DEC300_READ),
+    gcmDEFINE2TEXT(gcvHAL_DEC300_WRITE),
+    gcmDEFINE2TEXT(gcvHAL_DEC300_FLUSH),
+    gcmDEFINE2TEXT(gcvHAL_DEC300_FLUSH_WAIT),
+};
+#endif
+
+#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
+void
+_MonitorTimerFunction(
+    gctPOINTER Data
+    )
+{
+    gckKERNEL kernel = (gckKERNEL)Data;
+    gctINT32 pendingInterrupt;
+    gctBOOL reset = gcvFALSE;
+    gctINT32 mask;
+    gctUINT32 advance = kernel->timeOut/2;
+
+#if gcdENABLE_VG
+    if (kernel->core == gcvCORE_VG)
+    {
+        return;
+    }
+#endif
+
+    if (kernel->monitorTimerStop)
+    {
+        /* Stop. */
+        return;
+    }
+
+    gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+
+    if (pendingInterrupt < 0)
+    {
+        gctINT i = 0 - pendingInterrupt;
+        gctINT pendingMask;
+
+        gcmkVERIFY_OK(gckOS_AtomGet(
+            kernel->os,
+            kernel->hardware->pendingEvent,
+            &pendingMask
+            ));
+
+        gcmkPRINT("[galcore]: Number of pending interrupt is %d mask is %x",
+                  pendingInterrupt, pendingMask);
+
+        while (i--)
+        {
+            /* Ignore counting which should not exist. */
+            gckOS_AtomIncrement(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+        }
+
+        gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+    }
+
+    if (kernel->monitoring == gcvFALSE)
+    {
+        if (pendingInterrupt)
+        {
+            /* Begin to mointor GPU state. */
+            kernel->monitoring = gcvTRUE;
+
+            /* Record current state. */
+            kernel->lastCommitStamp = kernel->eventObj->lastCommitStamp;
+            kernel->restoreAddress  = kernel->hardware->lastWaitLink;
+            gcmkVERIFY_OK(gckOS_AtomGet(
+                kernel->os,
+                kernel->hardware->pendingEvent,
+                &kernel->restoreMask
+                ));
+
+            /* Clear timeout. */
+            kernel->timer = 0;
+        }
+    }
+    else
+    {
+        if (pendingInterrupt)
+        {
+            gcmkVERIFY_OK(gckOS_AtomGet(
+                kernel->os,
+                kernel->hardware->pendingEvent,
+                &mask
+                ));
+
+            if (kernel->eventObj->lastCommitStamp == kernel->lastCommitStamp
+             && kernel->hardware->lastWaitLink    == kernel->restoreAddress
+             && mask                              == kernel->restoreMask
+            )
+            {
+                /* GPU state is not changed, accumlate timeout. */
+                kernel->timer += advance;
+
+                if (kernel->timer >= kernel->timeOut)
+                {
+                    /* GPU stuck, trigger reset. */
+                    reset = gcvTRUE;
+                }
+            }
+            else
+            {
+                /* GPU state changed, cancel current timeout.*/
+                kernel->monitoring = gcvFALSE;
+            }
+        }
+        else
+        {
+            /* GPU finish all jobs, cancel current timeout*/
+            kernel->monitoring = gcvFALSE;
+        }
+    }
+
+    if (reset)
+    {
+        gckKERNEL_Recovery(kernel);
+
+        /* Work in this timeout is done. */
+        kernel->monitoring = gcvFALSE;
+    }
+
+    gcmkVERIFY_OK(gckOS_StartTimer(kernel->os, kernel->monitorTimer, advance));
+}
+#endif
+
+void
+_DumpDriverConfigure(
+    IN gckKERNEL Kernel
+    )
+{
+    gcmkPRINT_N(0, "**************************\n");
+    gcmkPRINT_N(0, "***   GPU DRV CONFIG   ***\n");
+    gcmkPRINT_N(0, "**************************\n");
+
+    gcmkPRINT("Galcore version %d.%d.%d.%d\n",
+              gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
+
+    gckOS_DumpParam();
+}
+
+void
+_DumpState(
+    IN gckKERNEL Kernel
+    )
+{
+    /* Dump GPU Debug registers. */
+    gcmkVERIFY_OK(gckHARDWARE_DumpGPUState(Kernel->hardware));
+
+    /* Dump Pending event. */
+    gcmkVERIFY_OK(gckEVENT_Dump(Kernel->eventObj));
+
+    /* Dump Process DB. */
+    gcmkVERIFY_OK(gckKERNEL_DumpProcessDB(Kernel));
+
+#if gcdRECORD_COMMAND
+    /* Dump record. */
+    gckRECORDER_Dump(Kernel->command->recorder);
+#endif
+
+    if (Kernel->command)
+    {
+        gcmkVERIFY_OK(gckCOMMAND_DumpExecutingBuffer(Kernel->command));
+    }
+}
+
+gceSTATUS
+gckKERNEL_GetHardwareType(
+    IN gckKERNEL Kernel,
+    OUT gceHARDWARE_TYPE *Type
+    )
+{
+    gceHARDWARE_TYPE type;
+    gcmkHEADER();
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+#if gcdENABLE_VG
+    if (Kernel->vg)
+    {
+        type =  gcvHARDWARE_VG;
+    }
+    else
+#endif
+    {
+        type = Kernel->hardware->type;
+    }
+
+    *Type = type;
+
+    gcmkFOOTER_ARG("type=%d", type);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_SetRecovery(
+    IN gckKERNEL Kernel,
+    IN gctBOOL  Recovery,
+    IN gctUINT32 StuckDump
+    )
+{
+    Kernel->recovery = Recovery;
+
+    if (Recovery == gcvFALSE)
+    {
+        /* Dump stuck information if Recovery is disabled. */
+        Kernel->stuckDump = gcmMAX(StuckDump, gcvSTUCK_DUMP_USER_COMMAND);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_Construct
+**
+**  Construct a new gckKERNEL object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gceCORE Core
+**          Specified core.
+**
+**      IN gctPOINTER Context
+**          Pointer to a driver defined context.
+**
+**      IN gckDB SharedDB,
+**          Pointer to a shared DB.
+**
+**  OUTPUT:
+**
+**      gckKERNEL * Kernel
+**          Pointer to a variable that will hold the pointer to the gckKERNEL
+**          object.
+*/
+
+gceSTATUS
+gckKERNEL_Construct(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT ChipID,
+    IN gctPOINTER Context,
+    IN gckDEVICE Device,
+    IN gckDB SharedDB,
+    OUT gckKERNEL * Kernel
+    )
+{
+    gckKERNEL kernel = gcvNULL;
+    gceSTATUS status;
+    gctSIZE_T i;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT64 data;
+    gctUINT32 recovery;
+    gctUINT32 stuckDump;
+    gctUINT64 dynamicMap = 1;
+
+    gcmkHEADER_ARG("Os=%p Context=%p", Os, Context);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+
+    /* Allocate the gckKERNEL object. */
+    gcmkONERROR(gckOS_Allocate(Os,
+                               gcmSIZEOF(struct _gckKERNEL),
+                               &pointer));
+
+    /* Zero the object. */
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckKERNEL));
+
+    kernel = pointer;
+
+    /* Initialize the gckKERNEL object. */
+    kernel->object.type = gcvOBJ_KERNEL;
+    kernel->os          = Os;
+    kernel->core        = Core;
+    kernel->device      = Device;
+    kernel->chipID      = ChipID;
+    kernel->threadInitialized = gcvTRUE;
+
+#if gcdENABLE_TRUST_APPLICATION
+    /* Connect to security service for this GPU. */
+    gcmkONERROR(gckKERNEL_SecurityOpen(kernel, kernel->core, &kernel->securityChannel));
+#endif
+
+    if (SharedDB == gcvNULL)
+    {
+        gcmkONERROR(gckOS_Allocate(Os,
+                                   gcmSIZEOF(struct _gckDB),
+                                   &pointer));
+
+        kernel->db               = pointer;
+        kernel->dbCreated        = gcvTRUE;
+        kernel->db->freeDatabase = gcvNULL;
+        kernel->db->freeRecord   = gcvNULL;
+        kernel->db->dbMutex      = gcvNULL;
+        kernel->db->lastDatabase = gcvNULL;
+        kernel->db->idleTime     = 0;
+        kernel->db->lastIdle     = 0;
+        kernel->db->lastSlowdown = 0;
+
+        for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+        {
+            kernel->db->db[i] = gcvNULL;
+        }
+
+        /* Construct a database mutex. */
+        gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->dbMutex));
+
+        /* Construct a video memory name database. */
+        gcmkONERROR(gckKERNEL_CreateIntegerDatabase(
+            kernel,
+            512,
+            &kernel->db->nameDatabase
+            ));
+
+        /* Construct a video memory name database mutex. */
+        gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->nameDatabaseMutex));
+
+        /* Construct a pointer name database. */
+        gcmkONERROR(gckKERNEL_CreateIntegerDatabase(
+            kernel,
+            512,
+            &kernel->db->pointerDatabase
+            ));
+
+        /* Initialize video memory node list. */
+        gcsLIST_Init(&kernel->db->videoMemList);
+
+        gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->videoMemListMutex));
+    }
+    else
+    {
+        kernel->db               = SharedDB;
+        kernel->dbCreated        = gcvFALSE;
+    }
+
+    for (i = 0; i < gcmCOUNTOF(kernel->timers); ++i)
+    {
+        kernel->timers[i].startTime = 0;
+        kernel->timers[i].stopTime = 0;
+    }
+
+    gcmkONERROR(gckOS_CreateMutex(Os, &kernel->vidMemBlockMutex));
+
+    /* Save context. */
+    kernel->context = Context;
+
+    /* Construct atom holding number of clients. */
+    kernel->atomClients = gcvNULL;
+    gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients));
+
+    kernel->recovery  = gcvTRUE;
+    kernel->stuckDump = gcvSTUCK_DUMP_NONE;
+
+    /* Override default recovery and stuckDump setting. */
+    status = gckOS_QueryOption(Os, "recovery", &data);
+    recovery = (gctUINT32)data;
+
+    if (gcmIS_SUCCESS(status))
+    {
+        status = gckOS_QueryOption(Os, "stuckDump", &data);
+        stuckDump = (gctUINT32)data;
+
+        gcmkASSERT(status == gcvSTATUS_OK);
+
+        _SetRecovery(kernel, recovery, stuckDump);
+    }
+
+    status = gckOS_QueryOption(Os, "sRAMLoopMode", &data);
+    kernel->sRAMLoopMode = (status == gcvSTATUS_OK) ? data : 0;
+
+    /* Need the kernel reference before gckKERNEL_Construct() completes.
+       gckOS_MapPagesEx() is called to map kernel virtual command buffers. */
+    *Kernel = kernel;
+
+#if gcdENABLE_VG
+    kernel->vg = gcvNULL;
+
+    if (Core == gcvCORE_VG)
+    {
+        gctPHYS_ADDR_T contiguousBase;
+        gctSIZE_T contiguousSize = 0;
+
+        /* Construct the gckMMU object. */
+        gcmkONERROR(
+            gckVGKERNEL_Construct(Os, Context, kernel, &kernel->vg));
+
+        kernel->timeOut = gcdGPU_TIMEOUT;
+
+        status = gckOS_QueryOption(Os, "contiguousBase", &contiguousBase);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            status = gckOS_QueryOption(Os, "contiguousSize", &data);
+            contiguousSize = (gctSIZE_T)data;
+        }
+
+        if (gcmIS_SUCCESS(status) && contiguousSize)
+        {
+            gctUINT64 gpuContiguousBase;
+
+            gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(Os, contiguousBase, &gpuContiguousBase));
+
+            gcmkSAFECASTPHYSADDRT(kernel->contiguousBaseAddress, gpuContiguousBase);
+        }
+    }
+    else
+#endif
+    {
+        /* Construct the gckHARDWARE object. */
+        gcmkONERROR(
+            gckHARDWARE_Construct(Os, kernel->device, kernel->core, &kernel->hardware));
+
+        /* Set pointer to gckKERNEL object in gckHARDWARE object. */
+        kernel->hardware->kernel = kernel;
+
+        kernel->sRAMIndex = 0;
+        kernel->extSRAMIndex = 0;
+
+        for (i = gcvSRAM_INTERNAL0; i < gcvSRAM_INTER_COUNT; i++)
+        {
+            kernel->sRAMVidMem[i]    = kernel->hardware->sRAMVidMem[i];
+            kernel->sRAMPhysical[i]  = kernel->hardware->sRAMPhysical[i];
+            kernel->sRAMPhysFaked[i] = gcvFALSE;
+        }
+
+        kernel->timeOut = kernel->hardware->type == gcvHARDWARE_2D
+                        ? gcdGPU_2D_TIMEOUT
+                        : gcdGPU_TIMEOUT
+                        ;
+
+#if gcdSHARED_PAGETABLE
+        /* Construct the gckMMU object. */
+        gcmkONERROR(
+            gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+#else
+        if (Device == gcvNULL)
+        {
+            /* Construct the gckMMU object. */
+            gcmkONERROR(
+                gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+        }
+        else
+        {
+            gcmkONERROR(gckDEVICE_GetMMU(Device, kernel->hardware->type, &kernel->mmu));
+
+            if (kernel->mmu == gcvNULL)
+            {
+                gcmkONERROR(
+                    gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+
+                gcmkONERROR(
+                    gckDEVICE_SetMMU(Device, kernel->hardware->type, kernel->mmu));
+            }
+        }
+
+        gcmkONERROR(
+            gckMMU_SetupSRAM(kernel->mmu, kernel->hardware, kernel->device));
+
+        status = gckOS_QueryOption(Os, "mmuDynamicMap", &dynamicMap);
+        if (dynamicMap && kernel->hardware->mmuVersion && !kernel->mmu->dynamicAreaSetuped)
+        {
+            gcmkONERROR(
+                gckMMU_SetupDynamicSpace(kernel->mmu));
+
+            kernel->mmu->dynamicAreaSetuped = gcvTRUE;
+        }
+
+        if (kernel->hardware->mmuVersion > 0)
+        {
+            /* Flush MTLB table. */
+            gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+                kernel,
+                kernel->mmu->mtlbVideoMem,
+                0,
+                kernel->mmu->mtlbLogical,
+                kernel->mmu->mtlbSize
+                ));
+        }
+#endif
+
+        kernel->contiguousBaseAddress = kernel->mmu->contiguousBaseAddress;
+        kernel->externalBaseAddress   = kernel->mmu->externalBaseAddress;
+
+        /* Construct the gckCOMMAND object, either MCFE or wait-link FE can exist. */
+        if (gckHARDWARE_IsFeatureAvailable(kernel->hardware, gcvFEATURE_MCFE))
+        {
+            /* Construct the gckCOMMAND object for multi-channel FE. */
+            gcmkONERROR(gckCOMMAND_Construct(kernel, gcvHW_FE_MULTI_CHANNEL, &kernel->command));
+
+            /* Construct gckEVENT for multi-channel FE. */
+            gcmkONERROR(gckEVENT_Construct(kernel, kernel->command, &kernel->eventObj));
+        }
+        else
+        {
+            /* Construct the gckCOMMAND object for legacy wait-link FE. */
+            gcmkONERROR(gckCOMMAND_Construct(kernel, gcvHW_FE_WAIT_LINK, &kernel->command));
+
+            /* Construct the gckEVENT object. */
+            gcmkONERROR(gckEVENT_Construct(kernel, kernel->command, &kernel->eventObj));
+        }
+
+        if (gckHARDWARE_IsFeatureAvailable(kernel->hardware, gcvFEATURE_ASYNC_BLIT))
+        {
+            /* Construct the gckCOMMAND object for BLT engine. */
+            gcmkONERROR(gckCOMMAND_Construct(kernel, gcvHW_FE_ASYNC, &kernel->asyncCommand));
+
+            /* Construct gckEVENT for BLT. */
+            gcmkONERROR(gckEVENT_Construct(kernel, kernel->asyncCommand, &kernel->asyncEvent));
+        }
+
+        gcmkVERIFY_OK(gckOS_GetTime(&kernel->resetTimeStamp));
+
+        /* Post construct hardware elements after MMU settle. */
+        gcmkONERROR(gckHARDWARE_PostConstruct(kernel->hardware));
+
+        /* Initialize the GPU. */
+        gcmkONERROR(
+            gckHARDWARE_InitializeHardware(kernel->hardware));
+
+#if gcdDVFS
+        if (gckHARDWARE_IsFeatureAvailable(kernel->hardware,
+                                           gcvFEATURE_DYNAMIC_FREQUENCY_SCALING))
+        {
+            gcmkONERROR(gckDVFS_Construct(kernel->hardware, &kernel->dvfs));
+            gcmkONERROR(gckDVFS_Start(kernel->dvfs));
+        }
+#endif
+
+#if COMMAND_PROCESSOR_VERSION == 1
+        if (kernel->command)
+        {
+            /* Start the command queue. */
+            gcmkONERROR(gckCOMMAND_Start(kernel->command));
+        }
+
+        if (kernel->asyncCommand)
+        {
+            /* Start the async command queue. */
+            gcmkONERROR(gckCOMMAND_Start(kernel->asyncCommand));
+        }
+#endif
+    }
+
+#if VIVANTE_PROFILER
+    /* Initialize profile setting */
+    kernel->profileEnable = gcvFALSE;
+    kernel->profileCleanRegister = gcvTRUE;
+#endif
+
+#if gcdLINUX_SYNC_FILE
+    gcmkONERROR(gckOS_CreateSyncTimeline(Os, Core, &kernel->timeline));
+#endif
+
+#if gcdSECURITY
+    /* Connect to security service for this GPU. */
+    gcmkONERROR(gckKERNEL_SecurityOpen(kernel, kernel->core, &kernel->securityChannel));
+#endif
+
+#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
+    if (kernel->timeOut)
+    {
+        gcmkVERIFY_OK(gckOS_CreateTimer(
+            Os,
+            (gctTIMERFUNCTION)_MonitorTimerFunction,
+            (gctPOINTER)kernel,
+            &kernel->monitorTimer
+            ));
+
+        kernel->monitoring  = gcvFALSE;
+
+        kernel->monitorTimerStop = gcvFALSE;
+
+        gcmkVERIFY_OK(gckOS_StartTimer(
+            Os,
+            kernel->monitorTimer,
+            100
+            ));
+    }
+#endif
+
+    /* Return pointer to the gckKERNEL object. */
+    *Kernel = kernel;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Kernel=%p", *Kernel);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (kernel != gcvNULL)
+    {
+        gckOS_SetGPUPower(Os, kernel->core, gcvFALSE, gcvFALSE);
+        gckKERNEL_Destroy(kernel);
+    }
+    *Kernel = gcvNULL;
+
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_Destroy
+**
+**  Destroy an gckKERNEL object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_Destroy(
+    IN gckKERNEL Kernel
+    )
+{
+    gctSIZE_T i;
+    gcsDATABASE_PTR database, databaseNext;
+    gcsDATABASE_RECORD_PTR record, recordNext;
+
+    gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+#if QNX_SINGLE_THREADED_DEBUGGING
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->debugMutex));
+#endif
+
+    if (Kernel->monitorTimer)
+    {
+        /* Stop and destroy monitor timer. */
+        gcmkVERIFY_OK(gckOS_StopTimer(Kernel->os, Kernel->monitorTimer));
+        gcmkVERIFY_OK(gckOS_DestroyTimer(Kernel->os, Kernel->monitorTimer));
+    }
+
+#if gcdENABLE_VG
+    if (Kernel->vg)
+    {
+        gcmkVERIFY_OK(gckVGKERNEL_Destroy(Kernel->vg));
+    }
+    else
+#endif
+    {
+        if (Kernel->command)
+        {
+            /* Destroy the gckCOMMNAND object. */
+            gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command));
+        }
+
+        if (Kernel->asyncCommand)
+        {
+            gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->asyncCommand));
+        }
+
+        if (Kernel->asyncEvent)
+        {
+            gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->asyncEvent));
+        }
+
+        if (Kernel->eventObj)
+        {
+            /* Destroy the gckEVENT object. */
+            gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->eventObj));
+        }
+
+        if (Kernel->hardware)
+        {
+            /* Destroy hardware resources before destroying MMU. */
+            gcmkVERIFY_OK(gckHARDWARE_PreDestroy(Kernel->hardware));
+        }
+
+        if (Kernel->mmu)
+        {
+#if gcdSHARED_PAGETABLE
+            /* Destroy the gckMMU object. */
+            gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));
+#else
+            if (Kernel->mmu->hardware == Kernel->hardware)
+            {
+                /* Destroy the gckMMU object. */
+                gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));
+            }
+#endif
+        }
+
+        if (Kernel->hardware)
+        {
+            /* Destroy the gckHARDWARE object. */
+            gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware));
+        }
+    }
+
+    if (Kernel->atomClients)
+    {
+        /* Detsroy the client atom. */
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients));
+    }
+
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->vidMemBlockMutex));
+
+    /* Destroy the database. */
+    if (Kernel->dbCreated)
+    {
+        for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
+        {
+            if (Kernel->db->db[i] != gcvNULL)
+            {
+                gcmkVERIFY_OK(
+                    gckKERNEL_DestroyProcessDB(Kernel, Kernel->db->db[i]->processID));
+            }
+        }
+
+        /* Free all databases. */
+        for (database = Kernel->db->freeDatabase;
+             database != gcvNULL;
+             database = databaseNext)
+        {
+            databaseNext = database->next;
+
+            if (database->counterMutex)
+            {
+                gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->counterMutex));
+            }
+
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, database));
+        }
+
+        if (Kernel->db->lastDatabase != gcvNULL)
+        {
+            if (Kernel->db->lastDatabase->counterMutex)
+            {
+                gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->lastDatabase->counterMutex));
+            }
+
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db->lastDatabase));
+        }
+
+        /* Free all database records. */
+        for (record = Kernel->db->freeRecord; record != gcvNULL; record = recordNext)
+        {
+            recordNext = record->next;
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
+        }
+
+        if (Kernel->db->dbMutex)
+        {
+            /* Destroy the database mutex. */
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->dbMutex));
+        }
+
+        if (Kernel->db->nameDatabase)
+        {
+            /* Destroy video memory name database. */
+            gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->nameDatabase));
+        }
+
+        if (Kernel->db->nameDatabaseMutex)
+        {
+            /* Destroy video memory name database mutex. */
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->nameDatabaseMutex));
+        }
+
+        if (Kernel->db->pointerDatabase)
+        {
+            /* Destroy id-pointer database. */
+            gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->pointerDatabase));
+        }
+
+        if (Kernel->db->videoMemListMutex)
+        {
+            /* Destroy video memory list mutex. */
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->videoMemListMutex));
+        }
+
+        /* Destroy the database. */
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db));
+
+        /* Notify stuck timer to quit. */
+        Kernel->monitorTimerStop = gcvTRUE;
+    }
+
+#if gcdDVFS
+    if (Kernel->dvfs)
+    {
+        gcmkVERIFY_OK(gckDVFS_Stop(Kernel->dvfs));
+        gcmkVERIFY_OK(gckDVFS_Destroy(Kernel->dvfs));
+    }
+#endif
+
+#if gcdLINUX_SYNC_FILE
+    if (Kernel->timeline)
+    {
+        gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Kernel->os, Kernel->timeline));
+    }
+#endif
+
+#if gcdSECURITY
+    if (Kernel->securityChannel)
+    {
+        gcmkVERIFY_OK(gckKERNEL_SecurityClose(Kernel->securityChannel));
+    }
+#endif
+
+    /* Mark the gckKERNEL object as unknown. */
+    Kernel->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckKERNEL object. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_AllocateVideoMemory
+**
+**  Walk requested pools to allocate video memory.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      gckVIDMEM_NODE * NodeObject
+**          Pointer to a variable receiving video memory represetation.
+*/
+gceSTATUS
+gckKERNEL_AllocateVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Alignment,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    IN OUT gcePOOL * Pool,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gcePOOL pool;
+    gckVIDMEM videoMemory;
+    gctINT loopCount;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctBOOL contiguous = gcvFALSE;
+    gctBOOL cacheable = gcvFALSE;
+    gctBOOL secure = gcvFALSE;
+    gctBOOL fastPools = gcvFALSE;
+#if gcdENABLE_GPU_1M_PAGE
+    gctBOOL virtualPool4K = gcvFALSE;
+#endif
+    gctBOOL hasFastPools = gcvFALSE;
+    gctSIZE_T bytes = *Bytes;
+
+    gcmkHEADER_ARG("Kernel=%p *Pool=%d *Bytes=%lu Alignment=%lu Type=%d",
+                   Kernel, *Pool, *Bytes, Alignment, Type);
+
+    *NodeObject = gcvNULL;
+
+    /* Check flags. */
+    contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+    cacheable  = Flag & gcvALLOC_FLAG_CACHEABLE;
+    secure     = Flag & gcvALLOC_FLAG_SECURITY;
+
+    if (Flag & gcvALLOC_FLAG_FAST_POOLS)
+    {
+        fastPools = gcvTRUE;
+        Flag &= ~gcvALLOC_FLAG_FAST_POOLS;
+    }
+
+    if (Flag & gcvALLOC_FLAG_4K_PAGES)
+    {
+#if gcdENABLE_GPU_1M_PAGE
+        virtualPool4K = gcvTRUE;
+#endif
+        Flag &= ~gcvALLOC_FLAG_4K_PAGES;
+    }
+
+#if gcdALLOC_ON_FAULT
+    if (Type == gcvVIDMEM_COLOR_BUFFER)
+    {
+        Flag |= gcvALLOC_FLAG_ALLOC_ON_FAULT;
+    }
+#endif
+
+    if (Flag & gcvALLOC_FLAG_ALLOC_ON_FAULT)
+    {
+        *Pool = gcvPOOL_VIRTUAL;
+    }
+
+#ifdef __QNXNTO__
+    if (Flag & gcvALLOC_FLAG_4GB_ADDR) {
+        /* Use the Virtual pool, since the system pool may be allocated above 4G limit */
+        *Pool = gcvPOOL_VIRTUAL;
+    }
+#endif
+    if (Flag & gcvALLOC_FLAG_DMABUF_EXPORTABLE)
+    {
+        gctSIZE_T pageSize = 0;
+        gckOS_GetPageSize(Kernel->os, &pageSize);
+
+        /* Usually, the exported dmabuf might be later imported to DRM,
+        ** while DRM requires input size to be page aligned.
+        */
+        bytes = gcmALIGN(bytes, pageSize);
+    }
+
+    if (Type == gcvVIDMEM_TYPE_COMMAND)
+    {
+#if gcdALLOC_CMD_FROM_RESERVE || gcdSECURITY || gcdDISABLE_GPU_VIRTUAL_ADDRESS || !USE_KERNEL_VIRTUAL_BUFFERS
+        Flag |= gcvALLOC_FLAG_CONTIGUOUS;
+#endif
+    }
+
+    if (Type == gcvVIDMEM_TYPE_TILE_STATUS)
+    {
+        gctBOOL tileStatusInVirtual;
+
+#if gcdENABLE_VG
+        if (Kernel->vg)
+        {
+            tileStatusInVirtual = gcvFALSE;
+        }
+        else
+#endif
+        {
+            tileStatusInVirtual =
+                gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_MC20);
+        }
+
+        if (!tileStatusInVirtual)
+        {
+            /* Must be contiguous if not support virtual tile status. */
+            Flag |= gcvALLOC_FLAG_CONTIGUOUS;
+        }
+    }
+
+AllocateMemory:
+
+#if gcdCAPTURE_ONLY_MODE
+    if (*Pool != gcvPOOL_VIRTUAL)
+    {
+        *Pool = gcvPOOL_SYSTEM;
+    }
+#endif
+
+    /* Get initial pool. */
+    switch (pool = *Pool)
+    {
+    case gcvPOOL_DEFAULT:
+    case gcvPOOL_LOCAL:
+        pool      = gcvPOOL_LOCAL_INTERNAL;
+        loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
+        break;
+
+    case gcvPOOL_UNIFIED:
+        pool      = gcvPOOL_SYSTEM;
+        loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
+        break;
+
+    default:
+        loopCount = 1;
+        break;
+    }
+
+    while (loopCount-- > 0)
+    {
+        if (pool == gcvPOOL_VIRTUAL)
+        {
+            /* Try contiguous virtual first. */
+#if gcdCONTIGUOUS_SIZE_LIMIT
+            if (bytes > gcdCONTIGUOUS_SIZE_LIMIT && contiguous == gcvFALSE)
+            {
+                status = gcvSTATUS_OUT_OF_MEMORY;
+            }
+            else
+#endif
+#if gcdENABLE_GPU_1M_PAGE
+            if (!virtualPool4K && Kernel->core != gcvCORE_VG && Kernel->hardware->mmuVersion)
+            {
+                /* Create a gckVIDMEM_NODE from contiguous memory. */
+                status = gckVIDMEM_NODE_AllocateVirtualChunk(
+                            Kernel,
+                            pool,
+                            Type,
+                            Flag | gcvALLOC_FLAG_CONTIGUOUS,
+                            &bytes,
+                            &nodeObject);
+
+                if (gcmIS_SUCCESS(status))
+                {
+                    /* Memory allocated. */
+                    break;
+                }
+            }
+#endif
+            {
+                /* Create a gckVIDMEM_NODE from contiguous memory. */
+                status = gckVIDMEM_NODE_AllocateVirtual(
+                            Kernel,
+                            pool,
+                            Type,
+                            Flag | gcvALLOC_FLAG_CONTIGUOUS,
+                            &bytes,
+                            &nodeObject);
+            }
+
+            if (gcmIS_SUCCESS(status))
+            {
+                /* Memory allocated. */
+                break;
+            }
+
+            if (contiguous)
+            {
+                break;
+            }
+
+#if gcdENABLE_GPU_1M_PAGE
+            /* Try non-contiguous virtual chunk. */
+            if (!virtualPool4K && Kernel->hardware->mmuVersion && Kernel->core != gcvCORE_VG)
+            {
+                /* Create a gckVIDMEM_NODE from contiguous memory. */
+                status = gckVIDMEM_NODE_AllocateVirtualChunk(
+                            Kernel,
+                            pool,
+                            Type,
+                            Flag | gcvALLOC_FLAG_NON_CONTIGUOUS,
+                            &bytes,
+                            &nodeObject);
+
+                if (gcmIS_SUCCESS(status))
+                {
+                    /* Memory allocated. */
+                    break;
+                }
+            }
+#endif
+            /* Try non-contiguous virtual. */
+            /* Create a gckVIDMEM_NODE for virtual memory. */
+            gcmkONERROR(
+                gckVIDMEM_NODE_AllocateVirtual(Kernel,
+                                               pool,
+                                               Type,
+                                               Flag | gcvALLOC_FLAG_NON_CONTIGUOUS,
+                                               &bytes, &nodeObject));
+
+            /* Success. */
+            break;
+        }
+        /* gcvPOOL_SYSTEM/gcvPOOL_SRAM can't be cacheable. */
+        else if (cacheable == gcvFALSE && secure == gcvFALSE)
+        {
+#ifdef EMULATOR
+            /* Cmodel only support 1 SRAM currently. */
+            Kernel->sRAMIndex = 0;
+            Kernel->extSRAMIndex = 0;
+#endif
+
+            /* Get pointer to gckVIDMEM object for pool. */
+            status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);
+
+            if (gcmIS_SUCCESS(status))
+            {
+                /* Allocate memory. */
+                if ((Flag & videoMemory->capability) != Flag)
+                {
+                    status = gcvSTATUS_NOT_SUPPORTED;
+
+                }
+#if defined(gcdLINEAR_SIZE_LIMIT)
+                /* 512 KB */
+                else if (bytes > gcdLINEAR_SIZE_LIMIT)
+                {
+                    status = gcvSTATUS_OUT_OF_MEMORY;
+                }
+#endif
+                else
+                {
+                    hasFastPools = gcvTRUE;
+                    status = gckVIDMEM_NODE_AllocateLinear(Kernel,
+                                                           videoMemory,
+                                                           pool,
+                                                           Type,
+                                                           Flag,
+                                                           Alignment,
+                                                           (pool == gcvPOOL_SYSTEM ||
+                                                            pool == gcvPOOL_INTERNAL_SRAM ||
+                                                            pool == gcvPOOL_EXTERNAL_SRAM),
+                                                           &bytes,
+                                                           &nodeObject);
+                }
+
+                if (gcmIS_SUCCESS(status))
+                {
+                    /* Memory allocated. */
+                    break;
+                }
+#if gcdCAPTURE_ONLY_MODE
+                else
+                {
+                    gcmkPRINT("Capture only mode: Out of Memory");
+                }
+#endif
+
+            }
+        }
+
+        if (pool == gcvPOOL_LOCAL_INTERNAL)
+        {
+            /* Advance to external memory. */
+            pool = gcvPOOL_LOCAL_EXTERNAL;
+        }
+
+        else
+        if (pool == gcvPOOL_LOCAL_EXTERNAL)
+        {
+            if (Kernel->sRAMLoopMode)
+            {
+                /* Advance to Internal SRAM memory block. */
+                pool = gcvPOOL_INTERNAL_SRAM;
+            }
+            else
+            {
+                /* Advance to contiguous reserved memory. */
+                pool = gcvPOOL_SYSTEM;
+            }
+        }
+
+        else
+        if (pool == gcvPOOL_INTERNAL_SRAM)
+        {
+            if (Kernel->sRAMIndex < gcvSRAM_INTER_COUNT - 1 && !Kernel->sRAMPhysFaked[Kernel->sRAMIndex])
+            {
+                Kernel->sRAMIndex++;
+                loopCount++;
+            }
+            else
+            {
+                /* Advance to contiguous reserved memory. */
+                pool = gcvPOOL_SYSTEM;
+            }
+        }
+
+        else
+        if (pool == gcvPOOL_SYSTEM)
+        {
+            /* Do not go ahead to try relative slow pools */
+            if (fastPools && hasFastPools)
+            {
+                status = gcvSTATUS_OUT_OF_MEMORY;
+                break;
+            }
+
+            /* Advance to virtual memory. */
+            pool = gcvPOOL_VIRTUAL;
+        }
+
+        else
+        {
+            /* Out of pools. */
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+
+    if (nodeObject == gcvNULL)
+    {
+        if (contiguous)
+        {
+            /* Broadcast OOM message. */
+            status = gckOS_Broadcast(Kernel->os, Kernel->hardware, gcvBROADCAST_OUT_OF_MEMORY);
+
+            if (gcmIS_SUCCESS(status))
+            {
+                /* Get some memory. */
+                gckOS_Delay(gcvNULL, 1);
+                goto AllocateMemory;
+            }
+        }
+
+        /* Nothing allocated. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+#if gcdCAPTURE_ONLY_MODE
+    nodeObject->captureSize = bytes;
+#endif
+
+    /* Return node and pool used for allocation. */
+    *Pool  = pool;
+    *Bytes = bytes;
+    *NodeObject  = nodeObject;
+
+    /* Return status. */
+    gcmkFOOTER_ARG("*Pool=%d *NodeObject=%p", *Pool, *NodeObject);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  _AllocateLinearMemory
+**
+**  Private function to allocate the requested amount of video memory, output
+**  video memory handle.
+*/
+gceSTATUS
+_AllocateLinearMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctUINT32 handle = 0;
+    gceDATABASE_TYPE dbType;
+    gcePOOL pool = (gcePOOL)Interface->u.AllocateLinearVideoMemory.pool;
+    gctSIZE_T bytes = (gctSIZE_T)Interface->u.AllocateLinearVideoMemory.bytes;
+    gctUINT32 alignment = Interface->u.AllocateLinearVideoMemory.alignment;
+    gceVIDMEM_TYPE type = (Interface->u.AllocateLinearVideoMemory.type & 0xFF);
+    gctUINT32 flag = Interface->u.AllocateLinearVideoMemory.flag;
+    gctUINT64 mappingInOne  = 1;
+    gctBOOL isContiguous;
+
+    gcmkHEADER_ARG("Kernel=%p pool=%d bytes=%lu alignment=%lu type=%d",
+                   Kernel, pool, bytes, alignment, type);
+
+    gcmkVERIFY_ARGUMENT(bytes != 0);
+
+    if (Interface->u.AllocateLinearVideoMemory.sRAMIndex >= 0)
+    {
+        Kernel->sRAMIndex = Interface->u.AllocateLinearVideoMemory.sRAMIndex;
+    }
+
+    if (Interface->u.AllocateLinearVideoMemory.extSRAMIndex >= 0)
+    {
+        Kernel->extSRAMIndex = Interface->u.AllocateLinearVideoMemory.extSRAMIndex;
+    }
+
+    gckOS_QueryOption(Kernel->os, "allMapInOne", &mappingInOne);
+    if (mappingInOne == 0)
+    {
+        /* TODO: it should page align if driver uses dynamic mapping for mapped user memory.
+         * it should be adjusted with different os.
+         */
+        alignment = gcmALIGN(alignment, 4096);
+    }
+
+    /* Allocate video memory node. */
+    gcmkONERROR(
+        gckKERNEL_AllocateVideoMemory(Kernel,
+                                      alignment,
+                                      type,
+                                      flag,
+                                      &bytes,
+                                      &pool,
+                                      &nodeObject));
+
+    /* Allocate handle for this video memory. */
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Allocate(Kernel, nodeObject, &handle));
+
+    /* Return node and pool used for allocation. */
+    Interface->u.AllocateLinearVideoMemory.node = handle;
+    Interface->u.AllocateLinearVideoMemory.pool = pool;
+    Interface->u.AllocateLinearVideoMemory.bytes = bytes;
+
+    /* Encode surface type and pool to database type. */
+    dbType = gcvDB_VIDEO_MEMORY
+           | (type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+           | (pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+    gcmkONERROR(gckVIDMEM_NODE_IsContiguous(Kernel, nodeObject, &isContiguous));
+
+    if (isContiguous)
+    {
+        dbType |= (gcvDB_CONTIGUOUS << gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT);
+    }
+
+    /* Record in process db. */
+    gcmkONERROR(
+            gckKERNEL_AddProcessDB(Kernel,
+                                   ProcessID,
+                                   dbType,
+                                   gcmINT2PTR(handle),
+                                   gcvNULL,
+                                   bytes));
+
+    /* Return status. */
+    gcmkFOOTER_ARG("pool=%d node=0x%x", pool, handle);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (handle)
+    {
+        /* Destroy handle allocated. */
+        gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle));
+    }
+
+    if (nodeObject)
+    {
+        /* Free video memory allocated. */
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, nodeObject));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _ReleaseVideoMemory
+**
+**  Release handle of a video memory.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          ProcessID of current process.
+**
+**      gctUINT32 Handle
+**          Handle of video memory.
+**
+**  OUTPUT:
+**
+**          Nothing.
+*/
+gceSTATUS
+_ReleaseVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject;
+    gceDATABASE_TYPE type;
+    gctBOOL isContiguous;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d Handle=%d",
+                   Kernel, ProcessID, Handle);
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Handle, &nodeObject));
+
+    type = gcvDB_VIDEO_MEMORY
+         | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+         | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+    gcmkONERROR(gckVIDMEM_NODE_IsContiguous(Kernel, nodeObject, &isContiguous));
+
+    if (isContiguous)
+    {
+        type |= (gcvDB_CONTIGUOUS << gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT);
+    }
+
+    gcmkONERROR(
+        gckKERNEL_RemoveProcessDB(Kernel,
+            ProcessID,
+            type,
+            gcmINT2PTR(Handle)));
+
+    gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Handle);
+
+    gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _LockVideoMemory
+**
+**      Lock a video memory node. It will generate a cpu virtual address used
+**      by software and a GPU address used by GPU.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gceCORE Core
+**          GPU to which video memory is locked.
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that defines the command to
+**          be dispatched.
+**
+**  OUTPUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+**          returned.
+*/
+static gceSTATUS
+_LockVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gceCORE Core,
+    IN gctUINT32 ProcessID,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gctUINT32 handle;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctBOOL referenced = gcvFALSE;
+    gctUINT32 address = gcvINVALID_ADDRESS;
+    gctPOINTER logical = gcvNULL;
+    gctPHYS_ADDR_T physical = gcvINVALID_PHYSICAL_ADDRESS;
+    gctUINT32 gid = 0;
+    gctBOOL asynchronous = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d",
+                   Kernel, ProcessID);
+
+    handle = Interface->u.LockVideoMemory.node;
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, handle, &nodeObject));
+
+    /* Ref node. */
+    gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, nodeObject));
+    referenced = gcvTRUE;
+
+#if gcdCAPTURE_ONLY_MODE
+    if (Interface->u.LockVideoMemory.queryCapSize)
+    {
+        Interface->u.LockVideoMemory.captureSize = nodeObject->captureSize;
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        nodeObject->captureLogical = Interface->u.LockVideoMemory.captureLogical;
+    }
+#endif
+
+    /* Lock for userspace CPU userspace. */
+    gcmkONERROR(
+        gckVIDMEM_NODE_LockCPU(Kernel,
+                               nodeObject,
+                               Interface->u.LockVideoMemory.cacheable,
+                               gcvTRUE,
+                               &logical));
+
+    /* Lock for GPU address. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(Kernel, nodeObject, &address));
+
+    /* Get CPU physical address. */
+    gcmkONERROR(gckVIDMEM_NODE_GetPhysical(Kernel, nodeObject, 0, &physical));
+    gcmkONERROR(gckVIDMEM_NODE_GetGid(Kernel, nodeObject, &gid));
+
+    Interface->u.LockVideoMemory.address = address;
+    Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(logical);
+    Interface->u.LockVideoMemory.physicalAddress = physical;
+    Interface->u.LockVideoMemory.gid = gid;
+
+    gcmkONERROR(
+        gckKERNEL_AddProcessDB(Kernel,
+                               ProcessID,
+                               gcvDB_VIDEO_MEMORY_LOCKED,
+                               gcmINT2PTR(handle),
+                               logical,
+                               0));
+
+    /* Ref handle. */
+    gckVIDMEM_HANDLE_Reference(Kernel, ProcessID, handle);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (logical)
+    {
+        gckVIDMEM_NODE_UnlockCPU(Kernel, nodeObject, ProcessID, gcvTRUE, gcvFALSE);
+    }
+
+    if (address != gcvINVALID_ADDRESS)
+    {
+        gckVIDMEM_NODE_Unlock(Kernel, nodeObject, ProcessID, &asynchronous);
+
+        if (asynchronous)
+        {
+            gckVIDMEM_NODE_Unlock(Kernel, nodeObject, ProcessID, gcvNULL);
+        }
+    }
+
+    if (referenced)
+    {
+        gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _UnlockVideoMemory
+**
+**      Unlock a video memory node.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          ProcessID of current process.
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that defines the command to
+**          be dispatched.
+**
+**  OUTPUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+**          returned.
+*/
+static gceSTATUS
+_UnlockVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject;
+    gcuVIDMEM_NODE_PTR node;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gctSIZE_T bytes;
+    gctUINT64 mappingInOne = 1;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d",
+                   Kernel, ProcessID);
+
+    Interface->u.UnlockVideoMemory.pool = gcvPOOL_UNKNOWN;
+    Interface->u.UnlockVideoMemory.bytes = 0;
+
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+        Kernel,
+        ProcessID,
+        (gctUINT32)Interface->u.UnlockVideoMemory.node,
+        &nodeObject
+        ));
+
+    gckOS_QueryOption(Kernel->os, "allMapInOne", &mappingInOne);
+    /* Unlock CPU. */
+    gcmkONERROR(gckVIDMEM_NODE_UnlockCPU(
+        Kernel, nodeObject, ProcessID, gcvTRUE, mappingInOne == 1));
+
+    /* Unlock video memory. */
+    gcmkONERROR(gckVIDMEM_NODE_Unlock(
+        Kernel,
+        nodeObject,
+        ProcessID,
+        &Interface->u.UnlockVideoMemory.asynchroneous
+        ));
+
+    /* Leave deref handle and deref node in later operation. */
+
+    node = nodeObject->node;
+
+    vidMemBlock = node->VirtualChunk.parent;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        bytes = node->VidMem.bytes;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        bytes = node->VirtualChunk.bytes;
+    }
+    else
+    {
+        bytes = node->Virtual.bytes;
+    }
+
+    Interface->u.UnlockVideoMemory.pool  = nodeObject->pool;
+    Interface->u.UnlockVideoMemory.bytes = bytes;
+
+#if gcdCAPTURE_ONLY_MODE
+    Interface->u.UnlockVideoMemory.captureLogical = nodeObject->captureLogical;
+#endif
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /*
+     * Unlikely to fail expect error node or unlocked, there's no error roll
+     * back requried for those two conditions.
+     */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _BottomHalfUnlockVideoMemory
+**
+**  Unlock video memory from gpu.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID owning this memory.
+**
+**      gceVIDMEM_TYPE
+**          Video memory allocation type.
+**
+**      gctPOINTER Pointer
+**          Video memory to be unlock.
+*/
+static gceSTATUS
+_BottomHalfUnlockVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Node
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    /* Remove record from process db. */
+    gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+        Kernel,
+        ProcessID,
+        gcvDB_VIDEO_MEMORY_LOCKED,
+        gcmINT2PTR(Node)
+        ));
+
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+        Kernel,
+        ProcessID,
+        Node,
+        &nodeObject
+        ));
+
+    /* Deref handle. */
+    gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Node);
+
+#if gcdENABLE_VG
+    if (Kernel->vg != gcvNULL)
+    {
+        /* Unlock video memory, synced. */
+        gcmkONERROR(gckVIDMEM_NODE_Unlock(Kernel, nodeObject, ProcessID, gcvNULL));
+
+        /* Deref node. */
+        gcmkONERROR(gckVIDMEM_NODE_Dereference(Kernel, nodeObject));
+    }
+    else
+#endif
+    {
+        /* Perform asynchronous unlock */
+        gcmkONERROR(gckEVENT_Unlock(Kernel->eventObj, gcvKERNEL_PIXEL, nodeObject));
+
+        /* Submit the event queue. */
+        gcmkONERROR(gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE));
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_WrapUserMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gceDATABASE_TYPE type;
+    gctUINT32 handle = 0;
+    gctBOOL isContiguous;
+
+    gcmkONERROR(
+        gckVIDMEM_NODE_WrapUserMemory(Kernel,
+                                      &Interface->u.WrapUserMemory.desc,
+                                      Interface->u.WrapUserMemory.type,
+                                      &nodeObject,
+                                      &Interface->u.WrapUserMemory.bytes));
+
+    /* Create handle representation for userspace. */
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Allocate(Kernel,
+                                  nodeObject,
+                                  &handle));
+
+    type = gcvDB_VIDEO_MEMORY
+         | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+         | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+    gcmkONERROR(gckVIDMEM_NODE_IsContiguous(Kernel, nodeObject, &isContiguous));
+
+    if (isContiguous)
+    {
+        type |= (gcvDB_CONTIGUOUS << gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT);
+    }
+
+    gcmkONERROR(
+        gckKERNEL_AddProcessDB(Kernel,
+                               ProcessID,
+                               type,
+                               gcmINT2PTR(handle),
+                               gcvNULL,
+                               (gctSIZE_T)Interface->u.WrapUserMemory.bytes));
+
+    Interface->u.WrapUserMemory.node = handle;
+    return gcvSTATUS_OK;
+
+OnError:
+    if (handle)
+    {
+        gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle);
+    }
+
+    if (nodeObject)
+    {
+        gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+    }
+
+    return status;
+}
+
+static gceSTATUS
+_ExportVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel,
+                                ProcessID,
+                                Interface->u.ExportVideoMemory.node,
+                                &nodeObject));
+
+    gcmkONERROR(
+        gckVIDMEM_NODE_Export(Kernel,
+                              nodeObject,
+                              Interface->u.ExportVideoMemory.flags,
+                              gcvNULL,
+                              &Interface->u.ExportVideoMemory.fd));
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_NameVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel,
+                                ProcessID,
+                                Interface->u.NameVideoMemory.handle,
+                                &nodeObject));
+
+    gcmkONERROR(
+        gckVIDMEM_NODE_Name(Kernel,
+                            nodeObject,
+                            &Interface->u.NameVideoMemory.name));
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_ImportVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctUINT32 handle = 0;
+
+    gcmkONERROR(
+        gckVIDMEM_NODE_Import(Kernel,
+                              Interface->u.ImportVideoMemory.name,
+                              &nodeObject));
+
+    /* Create handle representation for userspace. */
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Allocate(Kernel,
+                                  nodeObject,
+                                  &handle));
+
+    gcmkONERROR(
+        gckKERNEL_AddProcessDB(Kernel,
+                               ProcessID,
+                               gcvDB_VIDEO_MEMORY,
+                               gcmINT2PTR(handle),
+                               gcvNULL,
+                               0));
+
+    Interface->u.ImportVideoMemory.handle = handle;
+    return gcvSTATUS_OK;
+
+OnError:
+    if (handle)
+    {
+        gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle);
+    }
+
+    if (nodeObject)
+    {
+        gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_SetVidMemMetadata
+**
+**  Set/Get metadata to/from gckVIDMEM_NODE object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          ProcessID of current process.
+**
+**  INOUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a interface structure
+*/
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+#include <linux/dma-buf.h>
+
+gceSTATUS
+_SetVidMemMetadata(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    INOUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gckVIDMEM_NODE nodeObj = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d", Kernel, ProcessID);
+
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Interface->u.SetVidMemMetadata.node, &nodeObj));
+
+    if (Interface->u.SetVidMemMetadata.readback)
+    {
+        Interface->u.SetVidMemMetadata.ts_fd            = nodeObj->metadata.ts_fd;
+        Interface->u.SetVidMemMetadata.fc_enabled       = nodeObj->metadata.fc_enabled;
+        Interface->u.SetVidMemMetadata.fc_value         = nodeObj->metadata.fc_value;
+        Interface->u.SetVidMemMetadata.fc_value_upper   = nodeObj->metadata.fc_value_upper;
+        Interface->u.SetVidMemMetadata.compressed       = nodeObj->metadata.compressed;
+        Interface->u.SetVidMemMetadata.compress_format  = nodeObj->metadata.compress_format;
+    }
+    else
+    {
+        if ((nodeObj->metadata.ts_fd >= 0) && (nodeObj->metadata.ts_dma_buf != NULL)
+            && !(IS_ERR(nodeObj->metadata.ts_dma_buf))) {
+            dma_buf_put(nodeObj->metadata.ts_dma_buf);
+        }
+
+        nodeObj->metadata.ts_fd             = Interface->u.SetVidMemMetadata.ts_fd;
+
+        if (nodeObj->metadata.ts_fd >= 0)
+        {
+            nodeObj->metadata.ts_dma_buf    = dma_buf_get(nodeObj->metadata.ts_fd);
+
+            if (IS_ERR(nodeObj->metadata.ts_dma_buf))
+            {
+                gcmkONERROR(gcvSTATUS_NOT_FOUND);
+            }
+        }
+        else
+        {
+            nodeObj->metadata.ts_dma_buf    = NULL;
+        }
+
+        nodeObj->metadata.fc_enabled        = Interface->u.SetVidMemMetadata.fc_enabled;
+        nodeObj->metadata.fc_value          = Interface->u.SetVidMemMetadata.fc_value;
+        nodeObj->metadata.fc_value_upper    = Interface->u.SetVidMemMetadata.fc_value_upper;
+        nodeObj->metadata.compressed        = Interface->u.SetVidMemMetadata.compressed;
+        nodeObj->metadata.compress_format   = Interface->u.SetVidMemMetadata.compress_format;
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+#else
+
+gceSTATUS
+_SetVidMemMetadata(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    INOUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gcmkFATAL("The kernel did NOT support CONFIG_DMA_SHARED_BUFFER");
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+#endif
+
+static gceSTATUS
+_GetVideoMemoryFd(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel,
+                                ProcessID,
+                                Interface->u.GetVideoMemoryFd.handle,
+                                &nodeObject));
+
+    gcmkONERROR(
+        gckVIDMEM_NODE_GetFd(Kernel,
+                             nodeObject,
+                             &Interface->u.GetVideoMemoryFd.fd));
+
+    /* No need to add it to processDB because OS will release all fds when
+    ** process quits.
+    */
+OnError:
+    return status;
+}
+
+
+gceSTATUS
+gckKERNEL_QueryDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gctINT i;
+
+    gceDATABASE_TYPE type[2] = {
+        gcvDB_VIDEO_MEMORY | (gcvPOOL_SYSTEM << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
+        gcvDB_VIDEO_MEMORY | (gcvPOOL_VIRTUAL << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
+    };
+
+    gcmkHEADER();
+
+    /* Query video memory. */
+    gcmkONERROR(
+        gckKERNEL_QueryProcessDB(Kernel,
+                                 Interface->u.Database.processID,
+                                 !Interface->u.Database.validProcessID,
+                                 gcvDB_VIDEO_MEMORY,
+                                 &Interface->u.Database.vidMem));
+
+    /* Query non-paged memory. */
+    gcmkONERROR(
+        gckKERNEL_QueryProcessDB(Kernel,
+                                 Interface->u.Database.processID,
+                                 !Interface->u.Database.validProcessID,
+                                 gcvDB_NON_PAGED,
+                                 &Interface->u.Database.nonPaged));
+
+    /* Query contiguous memory. */
+    gcmkONERROR(
+        gckKERNEL_QueryProcessDB(Kernel,
+                                 Interface->u.Database.processID,
+                                 !Interface->u.Database.validProcessID,
+                                 gcvDB_CONTIGUOUS,
+                                 &Interface->u.Database.contiguous));
+
+    /* Query GPU idle time. */
+    gcmkONERROR(
+        gckKERNEL_QueryProcessDB(Kernel,
+                                 Interface->u.Database.processID,
+                                 !Interface->u.Database.validProcessID,
+                                 gcvDB_IDLE,
+                                 &Interface->u.Database.gpuIdle));
+    for (i = 0; i < 2; i++)
+    {
+        /* Query each video memory pool. */
+        gcmkONERROR(
+            gckKERNEL_QueryProcessDB(Kernel,
+                                     Interface->u.Database.processID,
+                                     !Interface->u.Database.validProcessID,
+                                     type[i],
+                                     &Interface->u.Database.vidMemPool[i]));
+    }
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gckKERNEL_DumpVidMemUsage(Kernel, Interface->u.Database.processID);
+#endif
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_ConfigPowerManagement(
+    IN gckKERNEL Kernel,
+    IN OUT gcsHAL_INTERFACE * Interface
+)
+{
+    gceSTATUS status;
+    gctBOOL enable = Interface->u.ConfigPowerManagement.enable;
+
+    gcmkHEADER();
+
+    gcmkONERROR(gckHARDWARE_EnablePowerManagement(Kernel->hardware, enable));
+
+    if (enable == gcvFALSE)
+    {
+        gcmkONERROR(
+            gckHARDWARE_SetPowerState(Kernel->hardware, gcvPOWER_ON));
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+
+static gceSTATUS
+gckKERNEL_CacheOperation(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Node,
+    IN gceCACHEOPERATION Operation,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gctSIZE_T offset = 0;
+    void *memHandle;
+
+    gcmkHEADER_ARG("Kernel=%p pid=%u Node=%u op=%d Logical=%p Bytes=0x%lx",
+                   Kernel, ProcessID, Node, Operation, Logical, Bytes);
+
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(Kernel,
+                                        ProcessID,
+                                        Node,
+                                        &nodeObject));
+
+    node = nodeObject->node;
+
+    vidMemBlock = node->VirtualChunk.parent;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        static gctBOOL printed;
+
+        if (!printed)
+        {
+            printed = gcvTRUE;
+            gcmkPRINT("[galcore]: %s: Flush Video Memory", __FUNCTION__);
+        }
+
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        memHandle = vidMemBlock->physical;
+        offset = node->VirtualChunk.offset;
+    }
+    else
+    {
+        memHandle = node->Virtual.physical;
+    }
+
+    switch (Operation)
+    {
+    case gcvCACHE_FLUSH:
+        /* Clean and invalidate the cache. */
+        status = gckOS_CacheFlush(Kernel->os,
+                                  ProcessID,
+                                  memHandle,
+                                  offset,
+                                  Logical,
+                                  Bytes);
+        break;
+    case gcvCACHE_CLEAN:
+        /* Clean the cache. */
+        status = gckOS_CacheClean(Kernel->os,
+                                  ProcessID,
+                                  memHandle,
+                                  offset,
+                                  Logical,
+                                  Bytes);
+        break;
+    case gcvCACHE_INVALIDATE:
+        /* Invalidate the cache. */
+        status = gckOS_CacheInvalidate(Kernel->os,
+                                       ProcessID,
+                                       memHandle,
+                                       offset,
+                                       Logical,
+                                       Bytes);
+        break;
+
+    case gcvCACHE_MEMORY_BARRIER:
+        status = gckOS_MemoryBarrier(Kernel->os, Logical);
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        break;
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_WaitFence(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE node;
+    gckCOMMAND command = Kernel->command;
+    gckCOMMAND asyncCommand = Kernel->asyncCommand;
+    gckFENCE fence = gcvNULL;
+    gctUINT i;
+
+    gcmkASSERT(command != gcvNULL);
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Kernel,
+                                ProcessID,
+                                Interface->u.WaitFence.handle,
+                                &node));
+
+    gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, node));
+
+    /* Wait for fence of all engines. */
+    for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+    {
+        gckFENCE_SYNC sync = &node->sync[i];
+
+        if (i == gcvENGINE_RENDER)
+        {
+            fence = command->fence;
+        }
+        else
+        {
+            fence = asyncCommand->fence;
+        }
+
+        gcmkONERROR(gckVIDMEM_NODE_InvalidateCache(
+            Kernel,
+            fence->videoMem,
+            0,
+            fence->logical,
+            8
+            ));
+
+        if (sync->commitStamp <= *(gctUINT64_PTR)fence->logical)
+        {
+            continue;
+        }
+        else
+        {
+            gckOS_Signal(Kernel->os, sync->signal, gcvFALSE);
+
+            gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, &fence->mutex, gcvINFINITE));
+
+            /* Add to waiting list. */
+            gcsLIST_AddTail(&sync->head, &fence->waitingList);
+
+            gcmkASSERT(sync->inList == gcvFALSE);
+
+            sync->inList = gcvTRUE;
+
+            gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, &fence->mutex));
+
+            /* Wait. */
+            status = gckOS_WaitSignal(
+                Kernel->os,
+                sync->signal,
+                gcvTRUE,
+                Interface->u.WaitFence.timeOut
+                );
+
+            gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, &fence->mutex, gcvINFINITE));
+
+            if (sync->inList)
+            {
+                gcsLIST_Del(&sync->head);
+                sync->inList = gcvFALSE;
+            }
+
+            gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, &fence->mutex));
+        }
+    }
+
+    gckVIDMEM_NODE_Dereference(Kernel, node);
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_Commit(
+    IN gckDEVICE Device,
+    IN gceHARDWARE_TYPE HwType,
+    IN gceENGINE Engine,
+    IN gctUINT32 ProcessId,
+    IN OUT gcsHAL_COMMIT * Commit
+    )
+{
+    gceSTATUS status;
+    gcsHAL_SUBCOMMIT *subCommit = &Commit->subCommit;
+    gcsHAL_SUBCOMMIT _subCommit;
+    gctPOINTER userPtr = gcvNULL;
+    gctBOOL needCopy = gcvFALSE;
+    gckKERNEL kernel;
+
+    gcmkVERIFY_OK(gckOS_QueryNeedCopy(Device->os, ProcessId, &needCopy));
+
+    do
+    {
+        gckCOMMAND command;
+        gckEVENT eventObj;
+        gctUINT64 next;
+
+        /* Skip the first nested sub-commit struct. */
+        if (userPtr)
+        {
+            /* Copy/map sub-commit from user. */
+            if (needCopy)
+            {
+                subCommit = &_subCommit;
+
+                status = gckOS_CopyFromUserData(
+                    Device->os,
+                    subCommit,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_SUBCOMMIT)
+                    );
+            }
+            else
+            {
+                status = gckOS_MapUserPointer(
+                    Device->os,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_SUBCOMMIT),
+                    (gctPOINTER *)&subCommit
+                    );
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                userPtr = gcvNULL;
+
+                gcmkONERROR(status);
+            }
+        }
+
+        if (subCommit->coreId >= gcvCORE_COUNT)
+        {
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        /* Determine the objects. */
+        if (HwType == gcvHARDWARE_3D || HwType == gcvHARDWARE_3D2D || HwType == gcvHARDWARE_VIP)
+        {
+            kernel = Device->coreInfoArray[subCommit->coreId].kernel;
+        }
+        else
+        {
+            kernel = Device->map[HwType].kernels[subCommit->coreId];
+        }
+
+        if (Engine == gcvENGINE_BLT)
+        {
+            command  = kernel->asyncCommand;
+            eventObj = kernel->asyncEvent;
+        }
+        else
+        {
+            command  = kernel->command;
+            eventObj = kernel->eventObj;
+        }
+
+        /* Commit command buffers. */
+        {
+            gcmkONERROR(gckOS_Broadcast(kernel->os,
+                                        kernel->hardware,
+                                        gcvBROADCAST_GPU_COMMIT));
+
+            status = gckCOMMAND_Commit(command,
+                                       subCommit,
+                                       ProcessId,
+                                       Commit->shared,
+                                       &Commit->commitStamp,
+                                       &Commit->contextSwitched);
+
+            if (status != gcvSTATUS_INTERRUPTED)
+            {
+                gcmkONERROR(status);
+            }
+
+            /* Commit events. */
+            status = gckEVENT_Commit(
+                eventObj,
+                gcmUINT64_TO_PTR(subCommit->queue),
+                kernel->hardware->options.powerManagement
+                );
+
+            if (status != gcvSTATUS_INTERRUPTED)
+            {
+                gcmkONERROR(status);
+            }
+        }
+
+        next = subCommit->next;
+
+        /* Unmap user pointer if mapped. */
+        if (!needCopy && userPtr)
+        {
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Device->os,
+                userPtr,
+                gcmSIZEOF(gcsHAL_SUBCOMMIT),
+                subCommit
+                ));
+        }
+
+        /* Advance to next sub-commit from user. */
+        userPtr = gcmUINT64_TO_PTR(next);
+    }
+    while (userPtr);
+
+    subCommit = &Commit->subCommit;
+    userPtr = gcvNULL;
+
+    if (HwType == gcvHARDWARE_3D || HwType == gcvHARDWARE_3D2D || HwType == gcvHARDWARE_VIP)
+    {
+        kernel = Device->coreInfoArray[subCommit->coreId].kernel;
+    }
+    else
+    {
+        kernel = Device->map[HwType].kernels[subCommit->coreId];
+    }
+
+    if (!kernel->hardware->options.gpuProfiler || !kernel->profileEnable)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    do
+    {
+        gctUINT64 next;
+
+        /* Skip the first nested sub-commit struct. */
+        if (userPtr)
+        {
+            /* Copy/map sub-commit from user. */
+            if (needCopy)
+            {
+                subCommit = &_subCommit;
+
+                status = gckOS_CopyFromUserData(
+                    Device->os,
+                    subCommit,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_SUBCOMMIT)
+                    );
+            }
+            else
+            {
+                status = gckOS_MapUserPointer(
+                    Device->os,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_SUBCOMMIT),
+                    (gctPOINTER *)&subCommit
+                    );
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                userPtr = gcvNULL;
+
+                gcmkONERROR(status);
+            }
+        }
+
+        if (HwType == gcvHARDWARE_3D || HwType == gcvHARDWARE_3D2D || HwType == gcvHARDWARE_VIP)
+        {
+            kernel = Device->coreInfoArray[subCommit->coreId].kernel;
+        }
+        else
+        {
+            kernel = Device->map[HwType].kernels[subCommit->coreId];
+        }
+
+        if ((kernel->hardware->options.gpuProfiler == gcvTRUE) &&
+            (kernel->profileEnable == gcvTRUE))
+        {
+            gcmkONERROR(gckCOMMAND_Stall(kernel->command, gcvTRUE));
+
+            if (kernel->command->currContext)
+            {
+                gcmkONERROR(gckHARDWARE_UpdateContextProfile(
+                            kernel->hardware,
+                            kernel->command->currContext));
+            }
+        }
+
+        next = subCommit->next;
+
+        /* Unmap user pointer if mapped. */
+        if (!needCopy && userPtr)
+        {
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Device->os,
+                userPtr,
+                gcmSIZEOF(gcsHAL_SUBCOMMIT),
+                subCommit
+                ));
+        }
+
+        /* Advance to next sub-commit from user. */
+        userPtr = gcmUINT64_TO_PTR(next);
+    }
+    while (userPtr);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (!needCopy && userPtr)
+    {
+        gckOS_UnmapUserPointer(
+            Device->os,
+            userPtr,
+            gcmSIZEOF(gcsHAL_SUBCOMMIT),
+            subCommit
+            );
+    }
+
+    return status;
+}
+
+#ifdef __linux__
+typedef struct _gcsGRRAPHIC_BUFFER_PARCLE
+{
+    gcsFDPRIVATE base;
+    gckKERNEL kernel;
+
+    gckVIDMEM_NODE node[3];
+    gctSHBUF  shBuf;
+    gctINT32  signal;
+}
+gcsGRAPHIC_BUFFER_PARCLE;
+
+static void
+_ReleaseGraphicBuffer(
+    gckKERNEL Kernel,
+    gcsGRAPHIC_BUFFER_PARCLE * Parcle
+    )
+{
+    gctUINT i;
+
+    for (i = 0; i < 3; i++)
+    {
+        if (Parcle->node[i])
+        {
+            gckVIDMEM_NODE_Dereference(Kernel, Parcle->node[i]);
+        }
+    }
+
+    if (Parcle->shBuf)
+    {
+        gckKERNEL_DestroyShBuffer(Kernel, Parcle->shBuf);
+    }
+
+    if (Parcle->signal)
+    {
+        gckOS_DestroyUserSignal(Kernel->os, Parcle->signal);
+    }
+
+    gcmkOS_SAFE_FREE(Kernel->os, Parcle);
+}
+
+static gctINT
+_FdReleaseGraphicBuffer(
+    gcsFDPRIVATE_PTR Private
+    )
+{
+    gcsGRAPHIC_BUFFER_PARCLE * parcle = (gcsGRAPHIC_BUFFER_PARCLE *) Private;
+
+    _ReleaseGraphicBuffer(parcle->kernel, parcle);
+    return 0;
+}
+
+static gceSTATUS
+_GetGraphicBufferFd(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Node[3],
+    IN gctUINT64 ShBuf,
+    IN gctUINT64 Signal,
+    OUT gctINT32 * Fd
+    )
+{
+    gceSTATUS status;
+    gctUINT i;
+    gcsGRAPHIC_BUFFER_PARCLE * parcle = gcvNULL;
+
+    gcmkONERROR(gckOS_Allocate(
+        Kernel->os,
+        gcmSIZEOF(gcsGRAPHIC_BUFFER_PARCLE),
+        (gctPOINTER *)&parcle
+        ));
+
+    gckOS_ZeroMemory(parcle, sizeof(gcsGRAPHIC_BUFFER_PARCLE));
+
+    parcle->base.release = _FdReleaseGraphicBuffer;
+    parcle->kernel = Kernel;
+
+    for (i = 0; i < 3 && Node[i] != 0; i++)
+    {
+        gckVIDMEM_NODE nodeObject = gcvNULL;
+
+        gcmkONERROR(
+            gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Node[i], &nodeObject));
+
+        gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, nodeObject));
+
+        parcle->node[i] = nodeObject;
+    }
+
+    if (ShBuf)
+    {
+        gctSHBUF shBuf = gcmUINT64_TO_PTR(ShBuf);
+
+        gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf));
+        parcle->shBuf = shBuf;
+    }
+
+    if (Signal)
+    {
+        gctSIGNAL signal = gcmUINT64_TO_PTR(Signal);
+
+        gcmkONERROR(
+            gckOS_MapSignal(Kernel->os,
+                            signal,
+                            (gctHANDLE)(gctUINTPTR_T)ProcessID,
+                            &signal));
+
+        parcle->signal= (gctINT32)Signal;
+    }
+
+    gcmkONERROR(gckOS_GetFd("viv-gr", &parcle->base, Fd));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (parcle)
+    {
+        _ReleaseGraphicBuffer(Kernel, parcle);
+    }
+    return status;
+}
+#endif
+
+/*******************************************************************************
+**
+**  gckKERNEL_Dispatch
+**
+**  Dispatch a command received from the user HAL layer.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that defines the command to
+**          be dispatched.
+**
+**  OUTPUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+**          returned.
+*/
+gceSTATUS
+gckKERNEL_Dispatch(
+    IN gckKERNEL Kernel,
+    IN gckDEVICE Device,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPHYS_ADDR physical = gcvNULL;
+    gctSIZE_T bytes;
+    gctPOINTER logical = gcvNULL;
+#if (gcdENABLE_3D || gcdENABLE_2D)
+    gckCONTEXT context = gcvNULL;
+#endif
+    gckKERNEL kernel = Kernel;
+    gctUINT32 processID;
+#if !USE_NEW_LINUX_SIGNAL
+    gctSIGNAL   signal;
+#endif
+
+    gctBOOL powerMutexAcquired = gcvFALSE;
+    gctBOOL commitMutexAcquired = gcvFALSE;
+    gctBOOL idle = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=%p Interface=%p", Kernel, Interface);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+                   "Dispatching command %d (%s)",
+                   Interface->command, _DispatchText[Interface->command]);
+
+    gcmSTATIC_ASSERT(gcvHAL_DESTROY_MMU == gcmCOUNTOF(_DispatchText) - 1,
+                     "DispatchText array does not match command codes");
+#endif
+#if QNX_SINGLE_THREADED_DEBUGGING
+    gckOS_AcquireMutex(Kernel->os, Kernel->debugMutex, gcvINFINITE);
+#endif
+
+    /* Get the current process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    /* Dispatch on command. */
+    switch (Interface->command)
+    {
+    case gcvHAL_GET_BASE_ADDRESS:
+        /* Get base address. */
+        Interface->u.GetBaseAddress.baseAddress = Kernel->hardware->baseAddress;
+        Interface->u.GetBaseAddress.flatMappingRangeCount = Kernel->mmu->gpuPhysicalRangeCount;
+        if (Kernel->mmu->gpuPhysicalRangeCount)
+        {
+            gckOS_MemCopy(Interface->u.GetBaseAddress.flatMappingRanges, Kernel->mmu->gpuPhysicalRanges,
+                gcmSIZEOF(gcsFLAT_MAPPING_RANGE) * Kernel->mmu->gpuPhysicalRangeCount);
+        }
+        break;
+
+    case gcvHAL_QUERY_VIDEO_MEMORY:
+        /* Query video memory size. */
+        gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface));
+        break;
+
+    case gcvHAL_QUERY_CHIP_IDENTITY:
+        /* Query chip identity. */
+        gcmkONERROR(
+            gckHARDWARE_QueryChipIdentity(
+                Kernel->hardware,
+                &Interface->u.QueryChipIdentity));
+        break;
+
+    case gcvHAL_QUERY_CHIP_FREQUENCY:
+        /* Query chip clock. */
+        gcmkONERROR(
+            gckHARDWARE_QueryFrequency(Kernel->hardware));
+
+        Interface->u.QueryChipFrequency.mcClk = Kernel->hardware->mcClk;
+        Interface->u.QueryChipFrequency.shClk = Kernel->hardware->shClk;
+        break;
+
+    case gcvHAL_MAP_MEMORY:
+        physical = gcmINT2PTR(Interface->u.MapMemory.physName);
+
+        /* Map memory. */
+        gcmkONERROR(
+            gckKERNEL_MapMemory(Kernel,
+                                physical,
+                                (gctSIZE_T) Interface->u.MapMemory.bytes,
+                                &logical));
+
+        Interface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical);
+
+        gcmkVERIFY_OK(
+            gckKERNEL_AddProcessDB(Kernel,
+                                   processID, gcvDB_MAP_MEMORY,
+                                   logical,
+                                   physical,
+                                   (gctSIZE_T) Interface->u.MapMemory.bytes));
+        break;
+
+    case gcvHAL_UNMAP_MEMORY:
+        physical = gcmINT2PTR(Interface->u.UnmapMemory.physName);
+
+        gcmkVERIFY_OK(
+            gckKERNEL_RemoveProcessDB(Kernel,
+                                      processID, gcvDB_MAP_MEMORY,
+                                      gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical)));
+
+        /* Unmap memory. */
+        gcmkONERROR(
+            gckKERNEL_UnmapMemory(Kernel,
+                                  physical,
+                                  (gctSIZE_T) Interface->u.UnmapMemory.bytes,
+                                  gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical),
+                                  processID));
+        break;
+
+    case gcvHAL_ALLOCATE_NON_PAGED_MEMORY:
+        bytes = (gctSIZE_T) Interface->u.AllocateNonPagedMemory.bytes;
+
+        /* Allocate non-paged memory. */
+        gcmkONERROR(
+            gckOS_AllocateNonPagedMemory(
+                Kernel->os,
+                gcvTRUE,
+                gcvALLOC_FLAG_CONTIGUOUS,
+                &bytes,
+                &physical,
+                &logical));
+
+        Interface->u.AllocateNonPagedMemory.bytes    = bytes;
+        Interface->u.AllocateNonPagedMemory.logical  = gcmPTR_TO_UINT64(logical);
+        Interface->u.AllocateNonPagedMemory.physName = gcmPTR_TO_NAME(physical);
+
+        gcmkVERIFY_OK(
+            gckKERNEL_AddProcessDB(Kernel,
+                                   processID, gcvDB_NON_PAGED,
+                                   logical,
+                                   gcmINT2PTR(Interface->u.AllocateNonPagedMemory.physName),
+                                   bytes));
+        break;
+
+    case gcvHAL_FREE_NON_PAGED_MEMORY:
+        physical = gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physName);
+
+        gcmkVERIFY_OK(
+            gckKERNEL_RemoveProcessDB(Kernel,
+                                      processID, gcvDB_NON_PAGED,
+                                      gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+
+        /* Free non-paged memory. */
+        gcmkONERROR(
+            gckOS_FreeNonPagedMemory(Kernel->os,
+                                     physical,
+                                     gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical),
+                                     (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes));
+
+        gcmRELEASE_NAME(Interface->u.FreeNonPagedMemory.physName);
+        break;
+
+    case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY:
+        /* Allocate memory. */
+        gcmkONERROR(_AllocateLinearMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_RELEASE_VIDEO_MEMORY:
+        /* Release video memory. */
+        gcmkONERROR(_ReleaseVideoMemory(
+            Kernel, processID,
+            (gctUINT32)Interface->u.ReleaseVideoMemory.node
+            ));
+    break;
+
+    case gcvHAL_LOCK_VIDEO_MEMORY:
+        /* Lock video memory. */
+        gcmkONERROR(_LockVideoMemory(Kernel, Kernel->core, processID, Interface));
+        break;
+
+    case gcvHAL_UNLOCK_VIDEO_MEMORY:
+        /* Unlock video memory. */
+        gcmkONERROR(_UnlockVideoMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY:
+        gcmkERR_BREAK(_BottomHalfUnlockVideoMemory(Kernel, processID,
+                                                   Interface->u.BottomHalfUnlockVideoMemory.type,
+                                                   Interface->u.BottomHalfUnlockVideoMemory.node));
+        break;
+
+    case gcvHAL_EVENT_COMMIT:
+        if (!Interface->commitMutex)
+        {
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os,
+                Kernel->device->commitMutex,
+                gcvINFINITE
+                ));
+
+            commitMutexAcquired = gcvTRUE;
+        }
+        /* Commit an event queue. */
+        if (Interface->engine == gcvENGINE_BLT)
+        {
+            if (!gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_ASYNC_BLIT))
+            {
+                gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+            }
+
+            gcmkONERROR(gckEVENT_Commit(
+                Kernel->asyncEvent, gcmUINT64_TO_PTR(Interface->u.Event.queue), gcvFALSE));
+        }
+        else
+        {
+            gcmkONERROR(gckEVENT_Commit(
+                Kernel->eventObj, gcmUINT64_TO_PTR(Interface->u.Event.queue), gcvFALSE));
+        }
+
+        if (!Interface->commitMutex)
+        {
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+            commitMutexAcquired = gcvFALSE;
+        }
+        break;
+
+    case gcvHAL_COMMIT:
+        if (!Interface->commitMutex)
+        {
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os,
+                Device->commitMutex,
+                gcvINFINITE
+                ));
+            commitMutexAcquired = gcvTRUE;
+        }
+
+        gcmkONERROR(_Commit(Device,
+                            Kernel->hardware->type,
+                            Interface->engine,
+                            processID,
+                            &Interface->u.Commit));
+
+        if (!Interface->commitMutex)
+        {
+            gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Device->commitMutex));
+            commitMutexAcquired = gcvFALSE;
+        }
+        break;
+
+#if !USE_NEW_LINUX_SIGNAL
+    case gcvHAL_USER_SIGNAL:
+        /* Dispatch depends on the user signal subcommands. */
+        switch(Interface->u.UserSignal.command)
+        {
+        case gcvUSER_SIGNAL_CREATE:
+            /* Create a signal used in the user space. */
+            gcmkONERROR(
+                gckOS_CreateUserSignal(Kernel->os,
+                                       Interface->u.UserSignal.manualReset,
+                                       &Interface->u.UserSignal.id));
+
+            gcmkVERIFY_OK(
+                gckKERNEL_AddProcessDB(Kernel,
+                                       processID, gcvDB_SIGNAL,
+                                       gcmINT2PTR(Interface->u.UserSignal.id),
+                                       gcvNULL,
+                                       0));
+            break;
+
+        case gcvUSER_SIGNAL_DESTROY:
+            gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+                Kernel,
+                processID, gcvDB_SIGNAL,
+                gcmINT2PTR(Interface->u.UserSignal.id)));
+
+            /* Destroy the signal. */
+            gcmkONERROR(
+                gckOS_DestroyUserSignal(Kernel->os,
+                                        Interface->u.UserSignal.id));
+            break;
+
+        case gcvUSER_SIGNAL_SIGNAL:
+            /* Signal the signal. */
+            gcmkONERROR(
+                gckOS_SignalUserSignal(Kernel->os,
+                                       Interface->u.UserSignal.id,
+                                       Interface->u.UserSignal.state));
+            break;
+
+        case gcvUSER_SIGNAL_WAIT:
+            /* Wait on the signal. */
+            status = gckOS_WaitUserSignal(Kernel->os,
+                                          Interface->u.UserSignal.id,
+                                          Interface->u.UserSignal.wait);
+            break;
+
+        case gcvUSER_SIGNAL_MAP:
+            gcmkONERROR(
+                gckOS_MapSignal(Kernel->os,
+                               (gctSIGNAL)(gctUINTPTR_T)Interface->u.UserSignal.id,
+                               (gctHANDLE)(gctUINTPTR_T)processID,
+                               &signal));
+
+            gcmkVERIFY_OK(
+                gckKERNEL_AddProcessDB(Kernel,
+                                       processID, gcvDB_SIGNAL,
+                                       gcmINT2PTR(Interface->u.UserSignal.id),
+                                       gcvNULL,
+                                       0));
+            break;
+
+        case gcvUSER_SIGNAL_UNMAP:
+            gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+                Kernel,
+                processID, gcvDB_SIGNAL,
+                gcmINT2PTR(Interface->u.UserSignal.id)));
+
+            /* Destroy the signal. */
+            gcmkONERROR(
+                gckOS_DestroyUserSignal(Kernel->os,
+                                        Interface->u.UserSignal.id));
+            break;
+
+        default:
+            /* Invalid user signal command. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+        break;
+#endif
+
+    case gcvHAL_SET_POWER_MANAGEMENT_STATE:
+        /* Set the power management state. */
+        gcmkONERROR(
+            gckHARDWARE_SetPowerState(Kernel->hardware,
+                                      Interface->u.SetPowerManagement.state));
+        break;
+
+    case gcvHAL_QUERY_POWER_MANAGEMENT_STATE:
+        /* Chip is not idle. */
+        Interface->u.QueryPowerManagement.isIdle = gcvFALSE;
+
+        /* Query the power management state. */
+        gcmkONERROR(gckHARDWARE_QueryPowerState(
+            Kernel->hardware,
+            &Interface->u.QueryPowerManagement.state));
+
+        /* Query the idle state. */
+        gcmkONERROR(
+            gckHARDWARE_QueryIdle(Kernel->hardware,
+                                  &Interface->u.QueryPowerManagement.isIdle));
+        break;
+
+    case gcvHAL_READ_REGISTER:
+#if gcdREGISTER_READ_FROM_USER
+        {
+            gceCHIPPOWERSTATE power;
+
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
+            powerMutexAcquired = gcvTRUE;
+            gcmkONERROR(gckHARDWARE_QueryPowerState(Kernel->hardware,
+                                                              &power));
+            if (power == gcvPOWER_ON)
+            {
+                /* Read a register. */
+                gcmkONERROR(gckOS_ReadRegisterEx(
+                    Kernel->os,
+                    Kernel->core,
+                    Interface->u.ReadRegisterData.address,
+                    &Interface->u.ReadRegisterData.data));
+            }
+            else
+            {
+                /* Chip is in power-state. */
+                Interface->u.ReadRegisterData.data = 0;
+                status = gcvSTATUS_CHIP_NOT_READY;
+            }
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+            powerMutexAcquired = gcvFALSE;
+        }
+#else
+        /* No access from user land to read registers. */
+        Interface->u.ReadRegisterData.data = 0;
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+
+    case gcvHAL_WRITE_REGISTER:
+#if gcdREGISTER_WRITE_FROM_USER
+        {
+            gceCHIPPOWERSTATE power;
+
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
+            powerMutexAcquired = gcvTRUE;
+            gcmkONERROR(gckHARDWARE_QueryPowerState(Kernel->hardware,
+                                                                  &power));
+            if (power == gcvPOWER_ON)
+            {
+                /* Write a register. */
+                gcmkONERROR(
+                    gckOS_WriteRegisterEx(Kernel->os,
+                                          Kernel->core,
+                                          Interface->u.WriteRegisterData.address,
+                                          Interface->u.WriteRegisterData.data));
+            }
+            else
+            {
+                /* Chip is in power-state. */
+                Interface->u.WriteRegisterData.data = 0;
+                status = gcvSTATUS_CHIP_NOT_READY;
+            }
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+            powerMutexAcquired = gcvFALSE;
+        }
+#else
+        /* No access from user land to write registers. */
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+
+    case gcvHAL_RESET:
+        /* Reset the hardware. */
+        gcmkONERROR(
+            gckHARDWARE_Reset(Kernel->hardware));
+        break;
+
+    case gcvHAL_SET_DEBUG_LEVEL_ZONE:
+        /* Set debug level and zones. */
+        gckOS_SetDebugLevel(Interface->u.DebugLevelZone.level);
+        gckOS_SetDebugZones(Interface->u.DebugLevelZone.zones,
+                            Interface->u.DebugLevelZone.enable);
+        break;
+
+    case gcvHAL_DEBUG_DUMP:
+        gckOS_DumpBuffer(Kernel->os,
+                         Interface->u.DebugDump.type,
+                         gcmUINT64_TO_PTR(Interface->u.DebugDump.ptr),
+                         Interface->u.DebugDump.address,
+                         Interface->u.DebugDump.size);
+        status = gcvSTATUS_OK;
+        break;
+
+    case gcvHAL_DUMP_GPU_STATE:
+        {
+            gceCHIPPOWERSTATE power;
+
+            _DumpDriverConfigure(Kernel);
+
+            gcmkONERROR(gckHARDWARE_QueryPowerState(
+                Kernel->hardware,
+                &power
+                ));
+
+            if (power == gcvPOWER_ON)
+            {
+                Interface->u.ReadRegisterData.data = 1;
+
+                _DumpState(Kernel);
+            }
+            else
+            {
+                Interface->u.ReadRegisterData.data = 0;
+                status = gcvSTATUS_CHIP_NOT_READY;
+
+                gcmkPRINT("[galcore]: Can't dump state if GPU isn't POWER ON.");
+            }
+        }
+        break;
+
+    case gcvHAL_DUMP_EVENT:
+        break;
+
+    case gcvHAL_CACHE:
+        logical = gcmUINT64_TO_PTR(Interface->u.Cache.logical);
+        bytes = (gctSIZE_T) Interface->u.Cache.bytes;
+
+        gcmkONERROR(gckKERNEL_CacheOperation(Kernel,
+                                             processID,
+                                             Interface->u.Cache.node,
+                                             Interface->u.Cache.operation,
+                                             logical,
+                                             bytes));
+        break;
+
+    case gcvHAL_TIMESTAMP:
+        /* Check for invalid timer. */
+        if ((Interface->u.TimeStamp.timer >= gcmCOUNTOF(Kernel->timers))
+        ||  (Interface->u.TimeStamp.request != 2))
+        {
+            Interface->u.TimeStamp.timeDelta = 0;
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        /* Return timer results and reset timer. */
+        {
+            gcsTIMER_PTR timer = &(Kernel->timers[Interface->u.TimeStamp.timer]);
+            gctUINT64 timeDelta = 0;
+
+            if (timer->stopTime < timer->startTime )
+            {
+                Interface->u.TimeStamp.timeDelta = 0;
+                gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
+            }
+
+            timeDelta = timer->stopTime - timer->startTime;
+
+            /* Check truncation overflow. */
+            Interface->u.TimeStamp.timeDelta = (gctINT32) timeDelta;
+            /*bit0~bit30 is available*/
+            if (timeDelta>>31)
+            {
+                Interface->u.TimeStamp.timeDelta = 0;
+                gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
+            }
+
+            status = gcvSTATUS_OK;
+        }
+        break;
+
+    case gcvHAL_DATABASE:
+        gcmkONERROR(gckKERNEL_QueryDatabase(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_VERSION:
+        Interface->u.Version.major = gcvVERSION_MAJOR;
+        Interface->u.Version.minor = gcvVERSION_MINOR;
+        Interface->u.Version.patch = gcvVERSION_PATCH;
+        Interface->u.Version.build = gcvVERSION_BUILD;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+                       "KERNEL version %s", gcvVERSION_STRING);
+#endif
+        break;
+
+    case gcvHAL_CHIP_INFO:
+        /* Only if not support multi-core */
+        Interface->u.ChipInfo.count = 1;
+        Interface->u.ChipInfo.types[0] = Kernel->hardware->type;
+        break;
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+    case gcvHAL_ATTACH:
+        if (Kernel->command)
+        {
+#if gcdCAPTURE_ONLY_MODE
+           gckVIDMEM_NODE nodeObject = gcvNULL;
+
+           if (Interface->u.Attach.queryCapSize)
+           {
+                /* Attach user process. */
+                gcmkONERROR(
+                    gckCOMMAND_Attach(Kernel->command,
+                                      &context,
+                                      &bytes,
+                                      &Interface->u.Attach.numStates,
+                                      processID));
+
+                Interface->u.Attach.maxState = bytes;
+                Interface->u.Attach.context = gcmPTR_TO_NAME(context);
+
+                gcmkONERROR(
+                    gckVIDMEM_HANDLE_Lookup(Kernel, processID, context->buffer->handle, &nodeObject));
+
+                Interface->u.Attach.captureSize = nodeObject->captureSize;
+                break;
+            }
+            else
+            {
+                gctUINT i = 0;
+                context = gcmNAME_TO_PTR(Interface->u.Attach.context);
+
+                for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; ++i)
+                {
+                    gcsCONTEXT_PTR buffer = context->buffer;
+
+                    gckOS_CopyToUserData(Kernel->os, buffer->logical, Interface->u.Attach.contextLogical[i], Interface->u.Attach.captureSize);
+
+                    buffer = buffer->next;
+                }
+            }
+
+#else
+            /* Attach user process. */
+            gcmkONERROR(
+                gckCOMMAND_Attach(Kernel->command,
+                                  &context,
+                                  &bytes,
+                                  &Interface->u.Attach.numStates,
+                                  processID));
+
+            Interface->u.Attach.maxState = bytes;
+            Interface->u.Attach.context = gcmPTR_TO_NAME(context);
+#endif
+
+            if (Interface->u.Attach.map)
+            {
+                if (context != gcvNULL)
+                {
+#if gcdCAPTURE_ONLY_MODE
+                    gctUINT i = 0;
+
+                    for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; ++i)
+                    {
+                        Interface->u.Attach.logicals[i] = gcmPTR_TO_UINT64(Interface->u.Attach.contextLogical[i]);
+                    }
+
+                    Interface->u.Attach.bytes = (gctUINT)context->totalSize;
+#else
+                    if (Kernel->command->feType == gcvHW_FE_WAIT_LINK)
+                    {
+                        gcmkVERIFY_OK(
+                            gckCONTEXT_MapBuffer(context,
+                                                Interface->u.Attach.logicals,
+                                                &Interface->u.Attach.bytes));
+                    }
+#endif
+                }
+                else
+                {
+                    gctUINT i;
+
+                    for (i = 0; i < gcmCOUNTOF(Interface->u.Attach.logicals); i++)
+                    {
+                        Interface->u.Attach.logicals[i] = 0;
+                    }
+
+                    Interface->u.Attach.bytes = 0;
+                }
+            }
+
+            gcmkVERIFY_OK(
+                gckKERNEL_AddProcessDB(Kernel,
+                                       processID, gcvDB_CONTEXT,
+                                       gcmINT2PTR(Interface->u.Attach.context),
+                                       gcvNULL,
+                                       0));
+        }
+        break;
+#endif
+
+    case gcvHAL_DETACH:
+        if (Kernel->command)
+        {
+            gcmkVERIFY_OK(
+                gckKERNEL_RemoveProcessDB(Kernel,
+                                  processID, gcvDB_CONTEXT,
+                                  gcmINT2PTR(Interface->u.Detach.context)));
+
+            /* Detach user process. */
+            gcmkONERROR(
+                gckCOMMAND_Detach(Kernel->command,
+                                  gcmNAME_TO_PTR(Interface->u.Detach.context)));
+
+            gcmRELEASE_NAME(Interface->u.Detach.context);
+        }
+        break;
+
+    case gcvHAL_GET_FRAME_INFO:
+        gcmkONERROR(gckHARDWARE_GetFrameInfo(
+                    Kernel->hardware,
+                    gcmUINT64_TO_PTR(Interface->u.GetFrameInfo.frameInfo)));
+        break;
+
+    case gcvHAL_DUMP_GPU_PROFILE:
+        gcmkONERROR(gckHARDWARE_DumpGpuProfile(Kernel->hardware));
+        break;
+
+    case gcvHAL_SET_FSCALE_VALUE:
+#if gcdENABLE_FSCALE_VAL_ADJUST
+        /* Wait for HW idle, otherwise it is not safe. */
+        gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE));
+
+        for (;;)
+        {
+            gcmkONERROR(gckHARDWARE_QueryIdle(Kernel->hardware, &idle));
+
+            if (idle)
+            {
+                break;
+            }
+
+            gcmkVERIFY_OK(gckOS_Delay(Kernel->os, 1));
+        }
+
+        status = gckHARDWARE_SetFscaleValue(Kernel->hardware,
+                                            Interface->u.SetFscaleValue.value,
+                                            Interface->u.SetFscaleValue.shValue);
+#else
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+    case gcvHAL_GET_FSCALE_VALUE:
+#if gcdENABLE_FSCALE_VAL_ADJUST
+        status = gckHARDWARE_GetFscaleValue(Kernel->hardware,
+                                            &Interface->u.GetFscaleValue.value,
+                                            &Interface->u.GetFscaleValue.minValue,
+                                            &Interface->u.GetFscaleValue.maxValue);
+#else
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+
+    case gcvHAL_EXPORT_VIDEO_MEMORY:
+        /* Unlock video memory. */
+        gcmkONERROR(_ExportVideoMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_NAME_VIDEO_MEMORY:
+        gcmkONERROR(_NameVideoMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_IMPORT_VIDEO_MEMORY:
+        gcmkONERROR(_ImportVideoMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_SET_VIDEO_MEMORY_METADATA:
+        gcmkONERROR(_SetVidMemMetadata(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_GET_VIDEO_MEMORY_FD:
+        gcmkONERROR(_GetVideoMemoryFd(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_QUERY_RESET_TIME_STAMP:
+        Interface->u.QueryResetTimeStamp.timeStamp = Kernel->resetTimeStamp;
+        Interface->u.QueryResetTimeStamp.contextID = Kernel->hardware->contextID;
+        break;
+
+#if gcdLINUX_SYNC_FILE
+    case gcvHAL_CREATE_NATIVE_FENCE:
+        {
+            gctINT fenceFD;
+            gctSIGNAL signal =
+                gcmUINT64_TO_PTR(Interface->u.CreateNativeFence.signal);
+
+            gcmkONERROR(
+                gckOS_CreateNativeFence(Kernel->os,
+                                        Kernel->timeline,
+                                        signal,
+                                        &fenceFD));
+
+            Interface->u.CreateNativeFence.fenceFD = fenceFD;
+        }
+        break;
+
+    case gcvHAL_WAIT_NATIVE_FENCE:
+        {
+            gctINT fenceFD;
+            gctUINT32 timeout;
+
+            fenceFD = Interface->u.WaitNativeFence.fenceFD;
+            timeout = Interface->u.WaitNativeFence.timeout;
+
+            gcmkONERROR(
+                gckOS_WaitNativeFence(Kernel->os,
+                                      Kernel->timeline,
+                                      fenceFD,
+                                      timeout));
+        }
+        break;
+#endif
+
+    case gcvHAL_SHBUF:
+        {
+            gctSHBUF shBuf;
+            gctPOINTER uData;
+            gctUINT32 bytes;
+
+            switch (Interface->u.ShBuf.command)
+            {
+            case gcvSHBUF_CREATE:
+                bytes = Interface->u.ShBuf.bytes;
+
+                /* Create. */
+                gcmkONERROR(gckKERNEL_CreateShBuffer(Kernel, bytes, &shBuf));
+
+                Interface->u.ShBuf.id = gcmPTR_TO_UINT64(shBuf);
+
+                gcmkVERIFY_OK(
+                    gckKERNEL_AddProcessDB(Kernel,
+                                           processID,
+                                           gcvDB_SHBUF,
+                                           shBuf,
+                                           gcvNULL,
+                                           0));
+                break;
+
+            case gcvSHBUF_DESTROY:
+                shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+
+                /* Check db first to avoid illegal destroy in the process. */
+                gcmkONERROR(
+                    gckKERNEL_RemoveProcessDB(Kernel,
+                                              processID,
+                                              gcvDB_SHBUF,
+                                              shBuf));
+
+                gcmkONERROR(gckKERNEL_DestroyShBuffer(Kernel, shBuf));
+                break;
+
+            case gcvSHBUF_MAP:
+                shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+
+                /* Map for current process access. */
+                gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf));
+
+                gcmkVERIFY_OK(
+                    gckKERNEL_AddProcessDB(Kernel,
+                                           processID,
+                                           gcvDB_SHBUF,
+                                           shBuf,
+                                           gcvNULL,
+                                           0));
+                break;
+
+            case gcvSHBUF_WRITE:
+                shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+                uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
+                bytes = Interface->u.ShBuf.bytes;
+
+                /* Write. */
+                gcmkONERROR(
+                    gckKERNEL_WriteShBuffer(Kernel, shBuf, uData, bytes));
+                break;
+
+            case gcvSHBUF_READ:
+                shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+                uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
+                bytes = Interface->u.ShBuf.bytes;
+
+                /* Read. */
+                gcmkONERROR(
+                    gckKERNEL_ReadShBuffer(Kernel,
+                                           shBuf,
+                                           uData,
+                                           bytes,
+                                           &bytes));
+
+                /* Return copied size. */
+                Interface->u.ShBuf.bytes = bytes;
+                break;
+
+            default:
+                gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+                break;
+            }
+        }
+        break;
+
+#ifdef __linux__
+    case gcvHAL_GET_GRAPHIC_BUFFER_FD:
+        gcmkONERROR(_GetGraphicBufferFd(
+            Kernel,
+            processID,
+            Interface->u.GetGraphicBufferFd.node,
+            Interface->u.GetGraphicBufferFd.shBuf,
+            Interface->u.GetGraphicBufferFd.signal,
+            &Interface->u.GetGraphicBufferFd.fd
+            ));
+        break;
+#endif
+
+
+    case gcvHAL_CONFIG_POWER_MANAGEMENT:
+        gcmkONERROR(gckKERNEL_ConfigPowerManagement(Kernel, Interface));
+        break;
+
+    case gcvHAL_WRAP_USER_MEMORY:
+        gcmkONERROR(_WrapUserMemory(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_WAIT_FENCE:
+        gcmkONERROR(_WaitFence(Kernel, processID, Interface));
+        break;
+
+    case gcvHAL_DEVICE_MUTEX:
+        if (Interface->u.DeviceMutex.isMutexLocked)
+        {
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os,
+                Kernel->device->commitMutex,
+                gcvINFINITE
+                ));
+        }
+        else
+        {
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+        }
+        break;
+
+#if gcdDEC_ENABLE_AHB
+    case gcvHAL_DEC300_READ:
+        gcmkONERROR(viv_dec300_read(
+            Interface->u.DEC300Read.enable,
+            Interface->u.DEC300Read.readId,
+            Interface->u.DEC300Read.format,
+            Interface->u.DEC300Read.strides,
+            Interface->u.DEC300Read.is3D,
+            Interface->u.DEC300Read.isMSAA,
+            Interface->u.DEC300Read.clearValue,
+            Interface->u.DEC300Read.isTPC,
+            Interface->u.DEC300Read.isTPCCompressed,
+            Interface->u.DEC300Read.surfAddrs,
+            Interface->u.DEC300Read.tileAddrs
+            ));
+        break;
+
+    case gcvHAL_DEC300_WRITE:
+        gcmkONERROR(viv_dec300_write(
+            Interface->u.DEC300Write.enable,
+            Interface->u.DEC300Write.readId,
+            Interface->u.DEC300Write.writeId,
+            Interface->u.DEC300Write.format,
+            Interface->u.DEC300Write.surfAddr,
+            Interface->u.DEC300Write.tileAddr
+            ));
+        break;
+
+    case gcvHAL_DEC300_FLUSH:
+        gcmkONERROR(viv_dec300_flush(0));
+        break;
+
+    case gcvHAL_DEC300_FLUSH_WAIT:
+        gcmkONERROR(viv_dec300_flush_done(&Interface->u.DEC300FlushWait.done));
+        break;
+#endif
+
+
+    case gcvHAL_QUERY_CHIP_OPTION:
+        /* Query chip options. */
+        gcmkONERROR(
+            gckHARDWARE_QueryChipOptions(
+                Kernel->hardware,
+                &Interface->u.QueryChipOptions));
+        break;
+
+    default:
+        /* Invalid command. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+OnError:
+    /* Save status. */
+    Interface->status = status;
+
+#if QNX_SINGLE_THREADED_DEBUGGING
+    gckOS_ReleaseMutex(Kernel->os, Kernel->debugMutex);
+#endif
+
+    if (powerMutexAcquired == gcvTRUE)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+    }
+
+    if (commitMutexAcquired == gcvTRUE)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_AttachProcess
+**
+**  Attach or detach a process.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctBOOL Attach
+**          gcvTRUE if a new process gets attached or gcFALSE when a process
+**          gets detatched.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_AttachProcess(
+    IN gckKERNEL Kernel,
+    IN gctBOOL Attach
+    )
+{
+    gceSTATUS status;
+    gctUINT32 processID;
+
+    gcmkHEADER_ARG("Kernel=%p Attach=%d", Kernel, Attach);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Get current process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    gcmkONERROR(gckKERNEL_AttachProcessEx(Kernel, Attach, processID));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_AttachProcessEx
+**
+**  Attach or detach a process with the given PID. Can be paired with gckKERNEL_AttachProcess
+**     provided the programmer is aware of the consequences.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctBOOL Attach
+**          gcvTRUE if a new process gets attached or gcFALSE when a process
+**          gets detatched.
+**
+**      gctUINT32 PID
+**          PID of the process to attach or detach.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_AttachProcessEx(
+    IN gckKERNEL Kernel,
+    IN gctBOOL Attach,
+    IN gctUINT32 PID
+    )
+{
+    gceSTATUS status;
+    gctINT32 old;
+
+    gcmkHEADER_ARG("Kernel=%p Attach=%d PID=%d", Kernel, Attach, PID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    if (Attach)
+    {
+        /* Increment the number of clients attached. */
+        gcmkONERROR(
+            gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old));
+
+        if (old == 0)
+        {
+#if gcdENABLE_VG
+            if (Kernel->vg == gcvNULL)
+#endif
+            {
+                gcmkONERROR(gckOS_Broadcast(Kernel->os,
+                                            Kernel->hardware,
+                                            gcvBROADCAST_FIRST_PROCESS));
+            }
+        }
+
+        if (Kernel->dbCreated)
+        {
+            /* Create the process database. */
+            gcmkONERROR(gckKERNEL_CreateProcessDB(Kernel, PID));
+        }
+    }
+    else
+    {
+        if (Kernel->dbCreated)
+        {
+            /* Clean up the process database. */
+            gcmkONERROR(gckKERNEL_DestroyProcessDB(Kernel, PID));
+
+            /* Save the last know process ID. */
+            Kernel->db->lastProcessID = PID;
+        }
+
+#if gcdENABLE_VG
+        if (Kernel->vg == gcvNULL)
+#endif
+        {
+            status = gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE);
+
+            if (status == gcvSTATUS_INTERRUPTED && Kernel->eventObj->submitTimer)
+            {
+                gcmkONERROR(gckOS_StartTimer(Kernel->os,
+                                             Kernel->eventObj->submitTimer,
+                                             1));
+            }
+            else
+            {
+                gcmkONERROR(status);
+            }
+        }
+
+        /* Decrement the number of clients attached. */
+        gcmkONERROR(
+            gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old));
+
+        if (old == 1)
+        {
+#if gcdENABLE_VG
+            if (Kernel->vg == gcvNULL)
+#endif
+            {
+                /* Last client detached, switch to SUSPEND power state. */
+                gcmkONERROR(gckOS_Broadcast(Kernel->os,
+                                            Kernel->hardware,
+                                            gcvBROADCAST_LAST_PROCESS));
+            }
+        }
+
+        if (Kernel->timeoutPID == PID)
+        {
+            Kernel->timeOut = Kernel->hardware->type == gcvHARDWARE_2D
+                            ? gcdGPU_2D_TIMEOUT
+                            : gcdGPU_TIMEOUT;
+
+            gcmkVERIFY_OK(gckOS_StopTimer(Kernel->os, Kernel->monitorTimer));
+
+            gcmkVERIFY_OK(gckOS_StartTimer(Kernel->os, Kernel->monitorTimer, 100));
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_Recovery
+**
+**  Try to recover the GPU from a fatal error.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_Recovery(
+    IN gckKERNEL Kernel
+    )
+{
+    gceSTATUS status;
+    gckEVENT eventObj;
+    gckHARDWARE hardware;
+    gctUINT32 mask = 0;
+    gctUINT32 i = 0, count = 0;
+#if gcdINTERRUPT_STATISTIC
+    gctINT32 oldValue;
+#endif
+
+    gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+    /* Validate the arguemnts. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Grab gckEVENT object. */
+    eventObj = Kernel->eventObj;
+    gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT);
+
+    /* Grab gckHARDWARE object. */
+    hardware = Kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    if (Kernel->stuckDump == gcvSTUCK_DUMP_NONE)
+    {
+        gcmkPRINT("[galcore]: GPU[%d] hang, automatic recovery.", Kernel->core);
+    }
+    else if (Kernel->stuckDump == gcvSTUCK_DUMP_ALL_CORE)
+    {
+        gckDEVICE device = Kernel->device;
+        gckKERNEL kernel = gcvNULL;
+
+        gcmkASSERT(device != gcvNULL);
+
+        gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->device->stuckDumpMutex, gcvINFINITE));
+
+        for (i = 0; i < device->coreNum; i++)
+        {
+            kernel = device->coreInfoArray[i].kernel;
+            gcmkASSERT(kernel != gcvNULL);
+
+            _DumpDriverConfigure(kernel);
+            _DumpState(kernel);
+        }
+
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->device->stuckDumpMutex));
+    }
+    else
+    {
+        gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->device->stuckDumpMutex, gcvINFINITE));
+
+        _DumpDriverConfigure(Kernel);
+        _DumpState(Kernel);
+
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->device->stuckDumpMutex));
+    }
+
+    if (Kernel->recovery == gcvFALSE)
+    {
+        gcmkPRINT("[galcore]: Stop driver to keep scene.");
+
+        /* Stop monitor timer. */
+        Kernel->monitorTimerStop = gcvTRUE;
+
+        /* Success. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /* Issuing a soft reset for the GPU. */
+    gcmkONERROR(gckHARDWARE_Reset(hardware));
+
+    mask = Kernel->restoreMask;
+
+    for (i = 0; i < 32; i++)
+    {
+        if (mask & (1 << i))
+        {
+            count++;
+        }
+    }
+
+    /* Handle all outstanding events now. */
+    gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, mask));
+
+#if gcdINTERRUPT_STATISTIC
+    while (count--)
+    {
+        gcmkONERROR(gckOS_AtomDecrement(
+            Kernel->os,
+            eventObj->interruptCount,
+            &oldValue
+            ));
+    }
+
+    gckOS_AtomClearMask(Kernel->hardware->pendingEvent, mask);
+#endif
+
+    gcmkONERROR(gckEVENT_Notify(eventObj, 1));
+
+    gcmkVERIFY_OK(gckOS_GetTime(&Kernel->resetTimeStamp));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_OpenUserData
+**
+**  Get access to the user data.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctBOOL NeedCopy
+**          The flag indicating whether or not the data should be copied.
+**
+**      gctPOINTER StaticStorage
+**          Pointer to the kernel storage where the data is to be copied if
+**          NeedCopy is gcvTRUE.
+**
+**      gctPOINTER UserPointer
+**          User pointer to the data.
+**
+**      gctSIZE_T Size
+**          Size of the data.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * KernelPointer
+**          Pointer to the kernel pointer that will be pointing to the data.
+*/
+gceSTATUS
+gckKERNEL_OpenUserData(
+    IN gckKERNEL Kernel,
+    IN gctBOOL NeedCopy,
+    IN gctPOINTER StaticStorage,
+    IN gctPOINTER UserPointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG(
+        "Kernel=%p NeedCopy=%d StaticStorage=%p "
+        "UserPointer=%p Size=%lu KernelPointer=%p",
+        Kernel, NeedCopy, StaticStorage, UserPointer, Size, KernelPointer
+        );
+
+    /* Validate the arguemnts. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(!NeedCopy || (StaticStorage != gcvNULL));
+    gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+
+    if (NeedCopy)
+    {
+        /* Copy the user data to the static storage. */
+        gcmkONERROR(gckOS_CopyFromUserData(
+            Kernel->os, StaticStorage, UserPointer, Size
+            ));
+
+        /* Set the kernel pointer. */
+        * KernelPointer = StaticStorage;
+    }
+    else
+    {
+        gctPOINTER pointer = gcvNULL;
+
+        /* Map the user pointer. */
+        gcmkONERROR(gckOS_MapUserPointer(
+            Kernel->os, UserPointer, Size, &pointer
+            ));
+
+        /* Set the kernel pointer. */
+        * KernelPointer = pointer;
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_CloseUserData
+**
+**  Release resources associated with the user data connection opened by
+**  gckKERNEL_OpenUserData.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctBOOL NeedCopy
+**          The flag indicating whether or not the data should be copied.
+**
+**      gctBOOL FlushData
+**          If gcvTRUE, the data is written back to the user.
+**
+**      gctPOINTER UserPointer
+**          User pointer to the data.
+**
+**      gctSIZE_T Size
+**          Size of the data.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * KernelPointer
+**          Kernel pointer to the data.
+*/
+gceSTATUS
+gckKERNEL_CloseUserData(
+    IN gckKERNEL Kernel,
+    IN gctBOOL NeedCopy,
+    IN gctBOOL FlushData,
+    IN gctPOINTER UserPointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPOINTER pointer;
+
+    gcmkHEADER_ARG(
+        "Kernel=%p NeedCopy=%d FlushData=%d "
+        "UserPointer=%p Size=%lu KernelPointer=%p",
+        Kernel, NeedCopy, FlushData, UserPointer, Size, KernelPointer
+        );
+
+    /* Validate the arguemnts. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+
+    /* Get a shortcut to the kernel pointer. */
+    pointer = * KernelPointer;
+
+    if (pointer != gcvNULL)
+    {
+        if (NeedCopy)
+        {
+            if (FlushData)
+            {
+                gcmkONERROR(gckOS_CopyToUserData(
+                    Kernel->os, * KernelPointer, UserPointer, Size
+                    ));
+            }
+        }
+        else
+        {
+            /* Unmap record from kernel memory. */
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Kernel->os,
+                UserPointer,
+                Size,
+                * KernelPointer
+                ));
+        }
+
+        /* Reset the kernel pointer. */
+        * KernelPointer = gcvNULL;
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+gckQUEUE_Dequeue(
+    IN gckQUEUE LinkQueue
+    )
+{
+    gcmkASSERT(LinkQueue->count == LinkQueue->size);
+
+    LinkQueue->count--;
+    LinkQueue->front = (LinkQueue->front + 1) % gcdLINK_QUEUE_SIZE;
+}
+
+void
+gckQUEUE_Enqueue(
+    IN gckQUEUE LinkQueue,
+    IN gcuQUEUEDATA *Data
+    )
+{
+    gcuQUEUEDATA * datas = LinkQueue->datas;
+
+    if (LinkQueue->count == LinkQueue->size)
+    {
+        gckQUEUE_Dequeue(LinkQueue);
+    }
+
+    gcmkASSERT(LinkQueue->count < LinkQueue->size);
+
+    LinkQueue->count++;
+
+    datas[LinkQueue->rear] = *Data;
+
+    LinkQueue->rear = (LinkQueue->rear + 1) % LinkQueue->size;
+}
+
+void
+gckQUEUE_GetData(
+    IN gckQUEUE LinkQueue,
+    IN gctUINT32 Index,
+    OUT gcuQUEUEDATA ** Data
+    )
+{
+    gcuQUEUEDATA * datas = LinkQueue->datas;
+
+    gcmkASSERT(Index < LinkQueue->size);
+
+    *Data = &datas[(Index + LinkQueue->front) % LinkQueue->size];
+}
+
+gceSTATUS
+gckQUEUE_Allocate(
+    IN gckOS Os,
+    IN gckQUEUE Queue,
+    IN gctUINT32 Size
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_Allocate(
+        Os,
+        gcmSIZEOF(struct _gckLINKDATA) * Size,
+        (gctPOINTER *)&Queue->datas
+        ));
+
+    Queue->size = Size;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckQUEUE_Free(
+    IN gckOS Os,
+    IN gckQUEUE Queue
+    )
+{
+    if (Queue->datas)
+    {
+        gcmkVERIFY_OK(gckOS_Free(Os, (gctPOINTER)Queue->datas));
+    }
+
+    return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+*************************** Pointer - ID translation ***************************
+\******************************************************************************/
+
+/* The capacity is 32 initially, double when expand, but no more than 512. */
+#define gcdID_TABLE_MAX_EXPAND    512
+
+typedef struct _gcsINTEGERDB * gckINTEGERDB;
+typedef struct _gcsINTEGERDB
+{
+    gckOS        os;
+    gctPOINTER * table;
+    gctUINT32 *  bitmap;
+    gctPOINTER   mutex;
+    gctUINT32    capacity;
+    gctUINT32    nextId;
+    gctUINT32    freeCount;
+}
+gcsINTEGERDB;
+
+gceSTATUS
+gckKERNEL_CreateIntegerDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Capacity,
+    OUT gctPOINTER * Database
+    )
+{
+    gceSTATUS status;
+    gckINTEGERDB database = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p Capacity=%u Datbase=%p", Kernel, Capacity, Database);
+
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Database != gcvNULL);
+
+    /* round up to 32 alignment. */
+    Capacity = (Capacity + 31) & ~31;
+
+    /* Allocate a database. */
+    gcmkONERROR(gckOS_Allocate(
+        Kernel->os, gcmSIZEOF(gcsINTEGERDB), (gctPOINTER *)&database));
+
+    gcmkONERROR(gckOS_ZeroMemory(database, gcmSIZEOF(gcsINTEGERDB)));
+
+    /* Allocate a pointer table. */
+    gcmkONERROR(gckOS_Allocate(
+        Kernel->os,
+        gcmSIZEOF(gctPOINTER) * Capacity,
+        (gctPOINTER *)&database->table
+        ));
+
+    /* Allocate bitmap. */
+    gcmkONERROR(gckOS_Allocate(
+        Kernel->os, Capacity / 8, (gctPOINTER *)&database->bitmap));
+
+    gcmkONERROR(gckOS_ZeroMemory(database->bitmap, Capacity / 8));
+
+    /* Allocate a database mutex. */
+    gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->mutex));
+
+    /* Initialize. */
+    database->os        = Kernel->os;
+
+    database->nextId    = 0;
+    database->freeCount = Capacity;
+    database->capacity  = Capacity;
+
+    *Database = database;
+
+    gcmkFOOTER_ARG("*Database=0x%08X", *Database);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Rollback. */
+    if (database)
+    {
+        if (database->table)
+        {
+            gckOS_Free(Kernel->os, database->table);
+        }
+
+        if (database->bitmap)
+        {
+            gckOS_Free(Kernel->os, database->bitmap);
+        }
+
+        gckOS_Free(Kernel->os, database);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_DestroyIntegerDatabase(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Database
+    )
+{
+    gckINTEGERDB database = Database;
+
+    gcmkHEADER_ARG("Kernel=%p Datbase=%p", Kernel, Database);
+
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Database != gcvNULL);
+
+    /* Destroy pointer table. */
+    gcmkOS_SAFE_FREE(Kernel->os, database->table);
+    gcmkOS_SAFE_FREE(Kernel->os, database->bitmap);
+
+    /* Destroy database mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->mutex));
+
+    /* Destroy database. */
+    gckOS_Free(Kernel->os, database);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckKERNEL_AllocateIntegerId(
+    IN gctPOINTER Database,
+    IN gctPOINTER Pointer,
+    OUT gctUINT32 * Id
+    )
+{
+    gceSTATUS status;
+    gckINTEGERDB database = Database;
+    gctUINT32 pos;
+    gctUINT32 n, i;
+    gckOS os = database->os;
+    gctPOINTER * table = gcvNULL;
+
+    gcmkHEADER_ARG("Database=%p Pointer=%p", Database, Pointer);
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+
+    if (database->freeCount < 1)
+    {
+        gctUINT32 * bitmap = gcvNULL;
+        gctUINT32 expand;
+        gctUINT32 capacity;
+
+        expand = database->capacity < gcdID_TABLE_MAX_EXPAND
+               ? database->capacity : gcdID_TABLE_MAX_EXPAND;
+
+        capacity = database->capacity + expand;
+
+        /* Extend table. */
+        gcmkONERROR(
+            gckOS_Allocate(os,
+                           gcmSIZEOF(gctPOINTER) * capacity,
+                           (gctPOINTER *)&table));
+
+        gcmkONERROR(
+            gckOS_Allocate(os, capacity / 32 * sizeof(gctUINT32), (gctPOINTER *)&bitmap));
+
+        gckOS_ZeroMemory(bitmap + database->capacity / 32, expand / 8);
+
+        /* Copy data from old table. */
+        gckOS_MemCopy(table,
+                      database->table,
+                      database->capacity * gcmSIZEOF(gctPOINTER));
+
+        gckOS_MemCopy(bitmap,
+                      database->bitmap,
+                      database->capacity / 32 * sizeof(gctUINT32));
+
+        gckOS_Free(os, database->table);
+        gckOS_Free(os, database->bitmap);
+
+        /* Update databse with new allocated table. */
+        database->table      = table;
+        database->bitmap     = bitmap;
+        database->nextId     = database->capacity;
+        database->capacity   = capacity;
+        database->freeCount += expand;
+    }
+
+    pos = database->nextId;
+    n = pos >> 5;
+    i = pos & 31;
+
+    while (database->bitmap[n] & (1u << i))
+    {
+        pos++;
+
+        if (pos == database->capacity)
+        {
+            /* Wrap to the begin. */
+            pos = 0;
+        }
+
+        n = pos >> 5;
+        i = pos & 31;
+    }
+
+    /* Connect id with pointer. */
+    database->table[pos] = Pointer;
+    database->bitmap[n] |= (1u << i);
+
+    *Id = pos + 1;
+
+    database->nextId = (pos + 1) % database->capacity;
+    database->freeCount--;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+
+    gcmkFOOTER_ARG("*Id=%u", *Id);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (table)
+    {
+        gckOS_Free(os, table);
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_FreeIntegerId(
+    IN gctPOINTER Database,
+    IN gctUINT32 Id
+    )
+{
+    gceSTATUS status;
+    gckINTEGERDB database = Database;
+    gckOS os = database->os;
+    gctUINT32 pos = Id - 1;
+    gctUINT32 n, i;
+
+    gcmkHEADER_ARG("Database=%p Id=%d", Database, Id);
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+
+    n = pos >> 5;
+    i = pos & 31;
+
+    if (pos >= database->capacity || (database->bitmap[n] & (1u << i)) == 0)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+
+    /* Clear id. */
+    database->bitmap[n] &= ~(1u << i);
+    database->table[pos] = gcvNULL;
+
+    ++database->freeCount;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_QueryIntegerId(
+    IN gctPOINTER Database,
+    IN gctUINT32 Id,
+    OUT gctPOINTER * Pointer
+    )
+{
+    gceSTATUS status;
+    gckINTEGERDB database = Database;
+    gckOS os = database->os;
+    gctUINT32 pos = Id - 1;
+    gctUINT32 n, i;
+
+    gcmkHEADER_ARG("Database=%p Id=%d", Database, Id);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+
+    n = pos >> 5;
+    i = pos & 31;
+
+    if (pos >= database->capacity || (database->bitmap[n] & (1u << i)) == 0)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+
+    *Pointer = database->table[pos];
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+
+    gcmkFOOTER_ARG("*Pointer=0x%08X", *Pointer);
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+
+gctUINT32
+gckKERNEL_AllocateNameFromPointer(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Pointer
+    )
+{
+    gceSTATUS status;
+    gctUINT32 name;
+    gctPOINTER database = Kernel->db->pointerDatabase;
+
+    gcmkHEADER_ARG("Kernel=%p Pointer=%p", Kernel, Pointer);
+
+    gcmkONERROR(gckKERNEL_AllocateIntegerId(database, Pointer, &name));
+
+    gcmkFOOTER_ARG("name=%d", name);
+    return name;
+
+OnError:
+    gcmkFOOTER();
+    return 0;
+}
+
+gctPOINTER
+gckKERNEL_QueryPointerFromName(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name
+    )
+{
+    gceSTATUS status;
+    gctPOINTER pointer = gcvNULL;
+    gctPOINTER database = Kernel->db->pointerDatabase;
+
+    gcmkHEADER_ARG("Kernel=%p Name=%d", Kernel, Name);
+
+    /* Lookup in database to get pointer. */
+    gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, &pointer));
+
+    gcmkFOOTER_ARG("pointer=0x%X", pointer);
+    return pointer;
+
+OnError:
+    gcmkFOOTER();
+    return gcvNULL;
+}
+
+gceSTATUS
+gckKERNEL_DeleteName(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name
+    )
+{
+    gctPOINTER database = Kernel->db->pointerDatabase;
+
+    gcmkHEADER_ARG("Kernel=%p Name=%p", Kernel, Name);
+
+    /* Free name if exists. */
+    gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Name));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+***** Shared Buffer ************************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckKERNEL_CreateShBuffer
+**
+**  Create shared buffer.
+**  The shared buffer can be used across processes. Other process needs call
+**  gckKERNEL_MapShBuffer before use it.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctUINT32 Size
+**          Specify the shared buffer size.
+**
+**  OUTPUT:
+**
+**      gctSHBUF * ShBuf
+**          Pointer to hold return shared buffer handle.
+*/
+gceSTATUS
+gckKERNEL_CreateShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Size,
+    OUT gctSHBUF * ShBuf
+    )
+{
+    gceSTATUS status;
+    gcsSHBUF_PTR shBuf = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p, Size=%u", Kernel, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    if (Size == 0)
+    {
+        /* Invalid size. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+    else if (Size > 1024)
+    {
+        /* Limite shared buffer size. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    /* Create a shared buffer structure. */
+    gcmkONERROR(
+        gckOS_Allocate(Kernel->os,
+                       sizeof (gcsSHBUF),
+                       (gctPOINTER *)&shBuf));
+
+    /* Initialize shared buffer. */
+    shBuf->id        = 0;
+    shBuf->reference = gcvNULL;
+    shBuf->size      = Size;
+    shBuf->data      = gcvNULL;
+
+    /* Allocate integer id for this shared buffer. */
+    gcmkONERROR(
+        gckKERNEL_AllocateIntegerId(Kernel->db->pointerDatabase,
+                                    shBuf,
+                                    &shBuf->id));
+
+    /* Allocate atom. */
+    gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &shBuf->reference));
+
+    /* Set default reference count to 1. */
+    gcmkVERIFY_OK(gckOS_AtomSet(Kernel->os, shBuf->reference, 1));
+
+    /* Return integer id. */
+    *ShBuf = (gctSHBUF)(gctUINTPTR_T)shBuf->id;
+
+    gcmkFOOTER_ARG("*ShBuf=%u", shBuf->id);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Error roll back. */
+    if (shBuf != gcvNULL)
+    {
+        if (shBuf->id != 0)
+        {
+            gcmkVERIFY_OK(
+                gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
+                                        shBuf->id));
+        }
+
+        gcmkOS_SAFE_FREE(Kernel->os, shBuf);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_DestroyShBuffer
+**
+**  Destroy shared buffer.
+**  This will decrease reference of specified shared buffer and do actual
+**  destroy when no reference on it.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSHBUF ShBuf
+**          Specify the shared buffer to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_DestroyShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf
+    )
+{
+    gceSTATUS status;
+    gcsSHBUF_PTR shBuf;
+    gctINT32 oldValue = 0;
+
+    gcmkHEADER_ARG("Kernel=%p ShBuf=%u",
+                   Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+    /* Find shared buffer structure. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+                                 (gctUINT32)(gctUINTPTR_T)ShBuf,
+                                 (gctPOINTER)&shBuf));
+
+    gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+    /* Decrease the reference count. */
+    gckOS_AtomDecrement(Kernel->os, shBuf->reference, &oldValue);
+
+    if (oldValue == 1)
+    {
+        /* Free integer id. */
+        gcmkVERIFY_OK(
+            gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
+                                    shBuf->id));
+
+        /* Free atom. */
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, shBuf->reference));
+
+        if (shBuf->data)
+        {
+            gcmkOS_SAFE_FREE(Kernel->os, shBuf->data);
+            shBuf->data = gcvNULL;
+        }
+
+        /* Free the shared buffer. */
+        gcmkOS_SAFE_FREE(Kernel->os, shBuf);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_MapShBuffer
+**
+**  Map shared buffer into this process so that it can be used in this process.
+**  This will increase reference count on the specified shared buffer.
+**  Call gckKERNEL_DestroyShBuffer to dereference.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSHBUF ShBuf
+**          Specify the shared buffer to be mapped.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_MapShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf
+    )
+{
+    gceSTATUS status;
+    gcsSHBUF_PTR shBuf;
+    gctINT32 oldValue = 0;
+
+    gcmkHEADER_ARG("Kernel=%p ShBuf=%u",
+                   Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+    /* Find shared buffer structure. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+                                 (gctUINT32)(gctUINTPTR_T)ShBuf,
+                                 (gctPOINTER)&shBuf));
+
+    gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+    /* Increase the reference count. */
+    gckOS_AtomIncrement(Kernel->os, shBuf->reference, &oldValue);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_WriteShBuffer
+**
+**  Write user data into shared buffer.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSHBUF ShBuf
+**          Specify the shared buffer to be written to.
+**
+**      gctPOINTER UserData
+**          User mode pointer to hold the source data.
+**
+**      gctUINT32 ByteCount
+**          Specify number of bytes to write. If this is larger than
+**          shared buffer size, gcvSTATUS_INVALID_ARGUMENT is returned.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_WriteShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf,
+    IN gctPOINTER UserData,
+    IN gctUINT32 ByteCount
+    )
+{
+    gceSTATUS status;
+    gcsSHBUF_PTR shBuf = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p ShBuf=%u UserData=%p ByteCount=%u",
+                   Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+    /* Find shared buffer structure. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+                                 (gctUINT32)(gctUINTPTR_T)ShBuf,
+                                 (gctPOINTER)&shBuf));
+
+    gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+    if ((ByteCount > shBuf->size) ||
+        (ByteCount == 0) ||
+        (UserData  == gcvNULL))
+    {
+        /* Exceeds buffer max size or invalid. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (shBuf->data == gcvNULL)
+    {
+        /* Allocate buffer data when first time write. */
+        gcmkONERROR(gckOS_Allocate(Kernel->os, ByteCount, &shBuf->data));
+    }
+
+    /* Copy data from user. */
+    gcmkONERROR(
+        gckOS_CopyFromUserData(Kernel->os,
+                               shBuf->data,
+                               UserData,
+                               ByteCount));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (shBuf && shBuf->data)
+    {
+        gcmkOS_SAFE_FREE(Kernel->os, shBuf->data);
+        shBuf->data = gcvNULL;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_ReadShBuffer
+**
+**  Read data from shared buffer and copy to user pointer.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSHBUF ShBuf
+**          Specify the shared buffer to be read from.
+**
+**      gctPOINTER UserData
+**          User mode pointer to save output data.
+**
+**      gctUINT32 ByteCount
+**          Specify number of bytes to read.
+**          If this is larger than shared buffer size, only avaiable bytes are
+**          copied. If smaller, copy requested size.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * BytesRead
+**          Pointer to hold how many bytes actually read from shared buffer.
+*/
+gceSTATUS
+gckKERNEL_ReadShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf,
+    IN gctPOINTER UserData,
+    IN gctUINT32 ByteCount,
+    OUT gctUINT32 * BytesRead
+    )
+{
+    gceSTATUS status;
+    gcsSHBUF_PTR shBuf;
+    gctUINT32 bytes;
+
+    gcmkHEADER_ARG("Kernel=%p ShBuf=%u UserData=%p ByteCount=%u",
+                   Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+    /* Find shared buffer structure. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+                                 (gctUINT32)(gctUINTPTR_T)ShBuf,
+                                 (gctPOINTER)&shBuf));
+
+    gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+    if (shBuf->data == gcvNULL)
+    {
+        *BytesRead = 0;
+
+        /* No data in shared buffer, skip copy. */
+        status = gcvSTATUS_SKIP;
+        goto OnError;
+    }
+    else if (ByteCount == 0)
+    {
+        /* Invalid size to read. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    /* Determine bytes to copy. */
+    bytes = (ByteCount < shBuf->size) ? ByteCount : shBuf->size;
+
+    /* Copy data to user. */
+    gcmkONERROR(
+        gckOS_CopyToUserData(Kernel->os,
+                             shBuf->data,
+                             UserData,
+                             bytes));
+
+    /* Return copied size. */
+    *BytesRead = bytes;
+
+    gcmkFOOTER_ARG("*BytesRead=%u", bytes);
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************\
+*************************** List Helper *****************************************
+\*******************************************************************************/
+
+static void
+_ListAdd(
+    gcsLISTHEAD_PTR New,
+    gcsLISTHEAD_PTR Prev,
+    gcsLISTHEAD_PTR Next
+    )
+{
+    Next->prev = New;
+    New->next  = Next;
+    New->prev  = Prev;
+    Prev->next = New;
+}
+
+void
+_ListDel(
+    gcsLISTHEAD_PTR Prev,
+    gcsLISTHEAD_PTR Next
+    )
+{
+    Next->prev = Prev;
+    Prev->next = Next;
+}
+
+void
+gcsLIST_Init(
+    gcsLISTHEAD_PTR Node
+    )
+{
+    Node->prev = Node;
+    Node->next = Node;
+}
+
+void
+gcsLIST_Add(
+    gcsLISTHEAD_PTR New,
+    gcsLISTHEAD_PTR Head
+    )
+{
+    _ListAdd(New, Head, Head->next);
+}
+
+void
+gcsLIST_AddTail(
+    gcsLISTHEAD_PTR New,
+    gcsLISTHEAD_PTR Head
+    )
+{
+    _ListAdd(New, Head->prev, Head);
+}
+
+void
+gcsLIST_Del(
+    gcsLISTHEAD_PTR Node
+    )
+{
+    _ListDel(Node->prev, Node->next);
+}
+
+gctBOOL
+gcsLIST_Empty(
+    gcsLISTHEAD_PTR Head
+    )
+{
+    return Head->next == Head;
+}
+
+/*******************************************************************************\
+********************************* Fence *****************************************
+\*******************************************************************************/
+
+gceSTATUS
+gckFENCE_Create(
+    IN gckOS Os,
+    IN gckKERNEL Kernel,
+    OUT gckFENCE * Fence
+    )
+{
+    gceSTATUS status;
+
+#if !gcdCAPTURE_ONLY_MODE
+    gcePOOL pool = gcvPOOL_DEFAULT;
+#else
+    gcePOOL pool = gcvPOOL_VIRTUAL;
+#endif
+
+    gckFENCE fence = gcvNULL;
+    gctSIZE_T size = 8;
+    gctUINT32 allocFlag = gcvALLOC_FLAG_CONTIGUOUS;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsFENCE), (gctPOINTER *)&fence));
+    gcmkONERROR(gckOS_ZeroMemory(fence, gcmSIZEOF(gcsFENCE)));
+    gcmkONERROR(gckOS_CreateMutex(Os, (gctPOINTER *)&fence->mutex));
+
+    fence->kernel = Kernel;
+
+    /* Allocate video memory node for fence. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+        Kernel,
+        64,
+        gcvVIDMEM_TYPE_FENCE,
+        allocFlag,
+        &size,
+        &pool,
+        &fence->videoMem
+        ));
+
+    /* Lock for GPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_Lock(
+        Kernel,
+        fence->videoMem,
+        &fence->address
+        ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        Kernel,
+        fence->videoMem,
+        gcvFALSE,
+        gcvFALSE,
+        &fence->logical
+        ));
+
+    gcsLIST_Init(&fence->waitingList);
+
+    *Fence = fence;
+
+    return gcvSTATUS_OK;
+OnError:
+    if (fence)
+    {
+        gckFENCE_Destory(Os, fence);
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckFENCE_Destory(
+    IN gckOS Os,
+    OUT gckFENCE Fence
+    )
+{
+    if (Fence->mutex)
+    {
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Fence->mutex));
+    }
+
+    if (Fence->logical)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+            Fence->kernel,
+            Fence->videoMem,
+            0,
+            gcvFALSE,
+            gcvFALSE
+            ));
+
+        /* Synchronueous unlock. */
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+            Fence->kernel,
+            Fence->videoMem,
+            0,
+            gcvNULL
+            ));
+
+        /* Free video memory. */
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            Fence->kernel,
+            Fence->videoMem
+            ));
+    }
+
+    gcmkOS_SAFE_FREE(Os, Fence);
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckFENCE_Signal
+**
+**  Signal all completed nodes.
+**
+**
+*/
+gceSTATUS
+gckFENCE_Signal(
+    IN gckOS Os,
+    IN gckFENCE Fence
+    )
+{
+    gcsLISTHEAD_PTR list = &Fence->waitingList;
+    gcsLISTHEAD_PTR nodeHead, nodeTemp;
+    gckFENCE_SYNC sync;
+    gckOS os = Os;
+    gctUINT64 stamp = *(gctUINT64 *)Fence->logical;
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(os, Fence->mutex, gcvINFINITE));
+
+    gcmkLIST_FOR_EACH_SAFE(nodeHead, nodeTemp, list)
+    {
+        sync = gcmCONTAINEROF(nodeHead, struct _gcsFENCE_SYNC, head);
+
+        /* Signal all nodes which are complete. */
+        if (sync->commitStamp <= stamp && sync->inList)
+        {
+            /* Signal. */
+            gckOS_Signal(os, sync->signal, gcvTRUE);
+
+            /* Remove from wait list. */
+            gcsLIST_Del(nodeHead);
+
+            /* Mark node not in waiting list. */
+            sync->inList = gcvFALSE;
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Fence->mutex));
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Construct(
+    IN gckOS Os,
+    OUT gckDEVICE * Device
+    )
+{
+    gceSTATUS status;
+    gckDEVICE device;
+    gctUINT i, j;
+
+    gcmkHEADER();
+
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsDEVICE), (gctPOINTER *)&device));
+
+    gckOS_ZeroMemory(device, gcmSIZEOF(gcsDEVICE));
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        device->coreInfoArray[i].type = gcvHARDWARE_INVALID;
+
+        /* Initialize internal SRAM. */
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            device->sRAMBases[i][j] = gcvINVALID_PHYSICAL_ADDRESS;
+            device->sRAMSizes[i][j] = 0;
+            device->sRAMPhysFaked[i][j] = gcvFALSE;
+        }
+    }
+
+    /* Initialize external SRAM. */
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        device->extSRAMGPUBases[i] = gcvINVALID_PHYSICAL_ADDRESS;
+        device->extSRAMBases[i] = gcvINVALID_PHYSICAL_ADDRESS;
+        device->extSRAMSizes[i] = 0;
+    }
+
+    device->defaultHwType = gcvHARDWARE_INVALID;
+
+    gcmkONERROR(gckOS_CreateMutex(Os, &device->stuckDumpMutex));
+    gcmkONERROR(gckOS_CreateMutex(Os, &device->commitMutex));
+
+    device->os = Os;
+    device->showSRAMMapInfo = 0;
+
+    *Device = device;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+
+    if (device != gcvNULL)
+    {
+        gckDEVICE_Destroy(Os, device);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckDEVICE_AddCore(
+    IN gckDEVICE Device,
+    IN gceCORE Core,
+    IN gctUINT ChipID,
+    IN gctPOINTER Context,
+    IN gckKERNEL * Kernel
+    )
+{
+    gceSTATUS status;
+    gcsCORE_INFO * info = Device->coreInfoArray;
+    gceHARDWARE_TYPE type = (gceHARDWARE_TYPE)((gctUINT)gcvHARDWARE_INVALID);
+    gctUINT32 index = Device->coreNum;
+    gctUINT32 i;
+    gcsCORE_LIST *coreList;
+    gceHARDWARE_TYPE kernelType;
+    gceHARDWARE_TYPE defaultHwType;
+    gckKERNEL kernel;
+
+    gcmkHEADER_ARG("Device=%p Core=%d ChipID=%d Context=%p Kernel=%p",
+        Device, Core, ChipID, Context, Kernel);
+
+    gcmkASSERT(Device->coreNum < gcvCORE_COUNT);
+
+    if (Core >= gcvCORE_MAJOR && Core <= gcvCORE_3D_MAX)
+    {
+        /* Chip ID is only used for 3D cores. */
+        if (ChipID == gcvCHIP_ID_DEFAULT)
+        {
+            /* Apply default chipID if it is not set. */
+            ChipID = Core;
+        }
+    }
+
+    /* Construct gckKERNEL for this core. */
+    gcmkONERROR(gckKERNEL_Construct(
+        Device->os, Core, ChipID, Context, Device, Device->database, Kernel));
+
+    kernel = *Kernel;
+
+    if (Device->database == gcvNULL)
+    {
+        Device->database = kernel->db;
+    }
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(kernel,
+                                  &kernelType));
+
+    if (kernelType >= gcvHARDWARE_NUM_TYPES)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    info[index].type = kernelType;
+    info[index].core = Core;
+    info[index].kernel = kernel;
+    info[index].chipID = ChipID;
+
+    if (index == 0)
+    {
+        /* First core, map all type/core to it. */
+        for (; type != gcvHARDWARE_NUM_TYPES; type = (gceHARDWARE_TYPE)((gctUINT)type + 1))
+        {
+            Device->map[type].num = 0;
+
+            for (i = 0 ; i < 4; i++)
+            {
+                Device->map[type].kernels[i] = kernel;
+            }
+        }
+    }
+
+    /* Get core list of this type. */
+    coreList = &Device->map[kernelType];
+
+    /* Setup gceHARDWARE_TYPE to gceCORE mapping. */
+    coreList->kernels[coreList->num++] = kernel;
+
+    defaultHwType = kernelType;
+    if (kernelType == gcvHARDWARE_3D2D)
+    {
+        coreList = &Device->map[gcvHARDWARE_3D];
+        coreList->kernels[coreList->num++] = kernel;
+        defaultHwType = gcvHARDWARE_3D;
+    }
+
+    /* Advance total core number. */
+    Device->coreNum++;
+
+    /* Default HW type was chosen: 3D > 2D > VG */
+    if (Device->defaultHwType == gcvHARDWARE_INVALID)
+    {
+        Device->defaultHwType = defaultHwType;
+    }
+    else if (Device->defaultHwType > defaultHwType)
+    {
+        Device->defaultHwType = defaultHwType;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckDEVICE_ChipInfo(
+    IN gckDEVICE Device,
+    IN gcsHAL_INTERFACE_PTR Interface
+    )
+{
+    gctUINT i;
+    gcsCORE_INFO * info = Device->coreInfoArray;
+
+    for (i = 0; i < Device->coreNum; i++)
+    {
+        Interface->u.ChipInfo.types[i] = info[i].type;
+        Interface->u.ChipInfo.ids[i] = info[i].chipID;
+
+        Interface->u.ChipInfo.coreIndexs[i] = info[i].core;
+    }
+
+    Interface->u.ChipInfo.count = Device->coreNum;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Version(
+    IN gckDEVICE Device,
+    IN gcsHAL_INTERFACE_PTR Interface
+    )
+{
+    Interface->u.Version.major = gcvVERSION_MAJOR;
+    Interface->u.Version.minor = gcvVERSION_MINOR;
+    Interface->u.Version.patch = gcvVERSION_PATCH;
+    Interface->u.Version.build = gcvVERSION_BUILD;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+                   "KERNEL version %s", gcvVERSION_STRING);
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Destroy(
+    IN gckOS Os,
+    IN gckDEVICE Device
+    )
+{
+    gctINT i;
+    gcsCORE_INFO * info = Device->coreInfoArray;
+
+    for (i = Device->coreNum - 1; i >= 0 ; i--)
+    {
+        if (info[i].kernel != gcvNULL)
+        {
+            gckKERNEL_Destroy(info[i].kernel);
+        }
+    }
+
+    if (Device->commitMutex)
+    {
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Device->commitMutex));
+    }
+    if (Device->stuckDumpMutex)
+    {
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Device->stuckDumpMutex));
+    }
+
+    gcmkOS_SAFE_FREE(Os, Device);
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+gckDEVICE_SetTimeOut(
+    IN gckDEVICE Device,
+    IN gcsHAL_INTERFACE_PTR Interface
+    )
+{
+#if gcdGPU_TIMEOUT
+    gckKERNEL kernel;
+    gctUINT i;
+    gceHARDWARE_TYPE type = Interface->hardwareType;
+    gcsCORE_LIST *coreList;
+    gctUINT32 processID = 0;
+    gcsCORE_INFO *info = Device->coreInfoArray;
+
+    coreList = &Device->map[type];
+
+    /* Get the current process ID. */
+    gckOS_GetProcessID(&processID);
+
+    for (i = 0; i < Device->coreNum; i++)
+    {
+        if (type == gcvHARDWARE_3D || type == gcvHARDWARE_3D2D || type == gcvHARDWARE_VIP)
+        {
+            kernel = info[i].kernel;
+        }
+        else
+        {
+            kernel = coreList->kernels[i];
+        }
+
+        kernel->timeOut = Interface->u.SetTimeOut.timeOut;
+
+        kernel->timeoutPID = processID;
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Dispatch(
+    IN gckDEVICE Device,
+    IN gcsHAL_INTERFACE_PTR Interface
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gckKERNEL kernel;
+    gceHARDWARE_TYPE type = Interface->hardwareType;
+    gctUINT32 coreIndex = Interface->coreIndex;
+
+    switch (Interface->command)
+    {
+    case gcvHAL_CHIP_INFO:
+        status = gckDEVICE_ChipInfo(Device, Interface);
+        break;
+
+    case gcvHAL_VERSION:
+        status = gckDEVICE_Version(Device, Interface);
+        break;
+
+    case gcvHAL_SET_TIMEOUT:
+        status = gckDEVICE_SetTimeOut(Device, Interface);
+        break;
+
+    default:
+        status = gcvSTATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    if (gcmIS_SUCCESS(status))
+    {
+        /* Dispatch handled in this layer. */
+        Interface->status = status;
+    }
+    else
+    {
+        /* Need go through gckKERNEL dispatch. */
+        if (type == gcvHARDWARE_3D || type == gcvHARDWARE_3D2D || type == gcvHARDWARE_VIP)
+        {
+            kernel = Device->coreInfoArray[coreIndex].kernel;
+        }
+        else
+        {
+            kernel = Device->map[type].kernels[coreIndex];
+        }
+
+#if gcdENABLE_VG
+        if (kernel->vg)
+        {
+            status = gckVGKERNEL_Dispatch(kernel, Interface);
+        }
+        else
+#endif
+        {
+            status = gckKERNEL_Dispatch(kernel, Device, Interface);
+        }
+
+        /* Interface->status is handled in gckKERNEL_Dispatch(). */
+    }
+
+    return status;
+}
+
+#if VIVANTE_PROFILER
+gceSTATUS
+gckDEVICE_Profiler_Dispatch(
+    IN gckDEVICE Device,
+    IN gcsHAL_PROFILER_INTERFACE_PTR Interface
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gckKERNEL kernel;
+    gctUINT32 coreIndex = Interface->coreIndex;
+
+    kernel = Device->coreInfoArray[coreIndex].kernel;
+
+    /* Dispatch on profiler command. */
+    switch (Interface->command)
+    {
+    case gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1:
+        /* Read profile data according to the context. */
+        gcmkONERROR(
+            gckHARDWARE_QueryContextProfile(
+                kernel->hardware,
+                kernel->profileCleanRegister,
+                gcmNAME_TO_PTR(Interface->u.RegisterProfileData_part1.context),
+                &Interface->u.RegisterProfileData_part1.Counters,
+                gcvNULL));
+
+        status = gcvSTATUS_OK;
+        break;
+
+    case gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2:
+        /* Read profile data according to the context. */
+        gcmkONERROR(
+            gckHARDWARE_QueryContextProfile(
+                kernel->hardware,
+                kernel->profileCleanRegister,
+                gcmNAME_TO_PTR(Interface->u.RegisterProfileData_part2.context),
+                gcvNULL,
+                &Interface->u.RegisterProfileData_part2.Counters));
+
+        status = gcvSTATUS_OK;
+        break;
+
+    case gcvHAL_GET_PROFILE_SETTING:
+        /* Get profile setting */
+        Interface->u.GetProfileSetting.enable = kernel->profileEnable;
+
+        status = gcvSTATUS_OK;
+        break;
+
+    case gcvHAL_SET_PROFILE_SETTING:
+        /* Set profile setting */
+        if(kernel->hardware->options.gpuProfiler)
+        {
+            kernel->profileEnable = Interface->u.SetProfileSetting.enable;
+
+            if (kernel->profileEnable)
+            {
+                gcmkONERROR(gckHARDWARE_InitProfiler(kernel->hardware));
+            }
+        }
+        else
+        {
+            status = gcvSTATUS_NOT_SUPPORTED;
+            break;
+        }
+
+        status = gcvSTATUS_OK;
+        break;
+
+    case gcvHAL_READ_PROFILER_REGISTER_SETTING:
+        kernel->profileCleanRegister = Interface->u.SetProfilerRegisterClear.bclear;
+        status = gcvSTATUS_OK;
+        break;
+
+    default:
+        /* Invalid command. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+OnError:
+    /* Save status. */
+    Interface->status = status;
+
+    /* Return the status. */
+    return status;
+}
+#endif
+
+gceSTATUS
+gckDEVICE_GetMMU(
+    IN gckDEVICE Device,
+    IN gceHARDWARE_TYPE Type,
+    IN gckMMU *Mmu
+    )
+{
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(Type < gcvHARDWARE_NUM_TYPES);
+
+    *Mmu = Device->mmus[Type];
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_SetMMU(
+    IN gckDEVICE Device,
+    IN gceHARDWARE_TYPE Type,
+    IN gckMMU Mmu
+    )
+{
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(Type < gcvHARDWARE_NUM_TYPES);
+
+    Device->mmus[Type] = Mmu;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_MapInTrustApplicaiton(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Logical,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 GPUAddress,
+    IN gctSIZE_T PageCount
+    )
+{
+    gceSTATUS status;
+    gctUINT32 * physicalArrayLogical = gcvNULL;
+    gctSIZE_T bytes;
+    gctPOINTER logical = Logical;
+    gctUINT32 i;
+    gctSIZE_T pageSize;
+    gctUINT32 pageMask;
+
+    gcmkHEADER();
+
+    gcmkVERIFY_OK(gckOS_GetPageSize(Kernel->os, &pageSize));
+
+    pageMask = (gctUINT32)pageSize - 1;
+
+    bytes = PageCount * gcmSIZEOF(gctUINT32);
+
+     gcmkONERROR(gckOS_Allocate(
+        Kernel->os,
+        bytes,
+        (gctPOINTER *)&physicalArrayLogical
+        ));
+
+    /* Fill in physical array. */
+    for (i = 0; i < PageCount; i++)
+    {
+        gctPHYS_ADDR_T phys;
+        status = gckOS_GetPhysicalFromHandle(
+            Kernel->os,
+            Physical,
+            i * 4096,
+            &phys
+            );
+
+        if (status == gcvSTATUS_NOT_SUPPORTED)
+        {
+            gcmkONERROR(gckOS_GetPhysicalAddress(
+                Kernel->os,
+                logical,
+                &phys
+                ));
+
+            gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Kernel->os, phys, &phys));
+        }
+
+        phys &= ~pageMask;
+
+        gcmkSAFECASTPHYSADDRT(physicalArrayLogical[i], phys);
+
+        logical = (gctUINT8_PTR)logical + 4096;
+    }
+
+    gcmkONERROR(gckKERNEL_SecurityMapMemory(
+        Kernel,
+        physicalArrayLogical,
+        0,
+        (gctUINT32)PageCount,
+        &GPUAddress
+        ));
+
+    gcmkVERIFY_OK(gckOS_Free(
+        Kernel->os,
+        physicalArrayLogical
+        ));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (physicalArrayLogical != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_Free(
+            Kernel->os,
+            (gctPOINTER)physicalArrayLogical
+            ));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h
@@ -0,0 +1,2450 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_h_
+#define __gc_hal_kernel_h_
+
+#include "gc_hal.h"
+#include "gc_hal_kernel_hardware.h"
+#include "gc_hal_kernel_hardware_fe.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel_mutex.h"
+#include "gc_hal_metadata.h"
+
+#if gcdENABLE_VG
+#include "gc_hal_kernel_vg.h"
+#endif
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+#include "gc_hal_security_interface.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+***** New MMU Defination *******************************************************/
+
+#if gcdENABLE_MMU_1KMODE
+/* 1k mode */
+#define gcdMMU_MTLB_SHIFT           24
+#define gcdMMU_STLB_4K_SHIFT        12
+#define gcdMMU_STLB_64K_SHIFT       16
+#define gcdMMU_STLB_1M_SHIFT        20
+#define gcdMMU_STLB_16M_SHIFT       24
+
+#define gcdMMU_MTLB_BITS            (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS         gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS         (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS        gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS        (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+#define gcdMMU_PAGE_1M_BITS         gcdMMU_STLB_1M_SHIFT
+#define gcdMMU_STLB_1M_BITS        (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_1M_BITS)
+#define gcdMMU_PAGE_16M_BITS        gcdMMU_STLB_16M_SHIFT
+#define gcdMMU_STLB_16M_BITS        4
+
+
+#define gcdMMU_MTLB_ENTRY_NUM       (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE            (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM    (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE         (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE         (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM   (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE        (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE        (1 << gcdMMU_STLB_64K_SHIFT)
+#define gcdMMU_STLB_1M_ENTRY_NUM   (1 << gcdMMU_STLB_1M_BITS)
+#define gcdMMU_STLB_1M_SIZE        (gcdMMU_STLB_1M_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_1M_SIZE        (1 << gcdMMU_STLB_1M_SHIFT)
+#define gcdMMU_STLB_16M_ENTRY_NUM   (1 << gcdMMU_STLB_16M_BITS)
+#define gcdMMU_STLB_16M_SIZE        (gcdMMU_STLB_16M_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_16M_SIZE        (1 << gcdMMU_STLB_16M_SHIFT)
+
+
+#define gcdMMU_MTLB_MASK            (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK         ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK         (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK        ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK        (gcdMMU_PAGE_64K_SIZE - 1)
+#define gcdMMU_STLB_1M_MASK        ((~((1U << gcdMMU_STLB_1M_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_1M_MASK        (gcdMMU_PAGE_1M_SIZE - 1)
+#define gcdMMU_STLB_16M_MASK        0x0F000000
+#define gcdMMU_PAGE_16M_MASK        (gcdMMU_PAGE_16M_SIZE - 1)
+
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS       (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK       ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_64K_BITS      (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_64K_BITS)
+#define gcdMMU_OFFSET_64K_MASK      ((1U << gcdMMU_OFFSET_64K_BITS) - 1)
+#define gcdMMU_OFFSET_1M_BITS      (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_1M_BITS)
+#define gcdMMU_OFFSET_1M_MASK      ((1U << gcdMMU_OFFSET_1M_BITS) - 1)
+#define gcdMMU_OFFSET_16M_BITS      (32 - gcdMMU_MTLB_BITS)
+#define gcdMMU_OFFSET_16M_MASK      ((1U << gcdMMU_OFFSET_16M_BITS) - 1)
+
+
+#define gcdMMU_MTLB_ENTRY_HINTS_BITS 6
+#define gcdMMU_MTLB_ENTRY_STLB_MASK  (~((1U << gcdMMU_MTLB_ENTRY_HINTS_BITS) - 1))
+
+#define gcdMMU_MTLB_PRESENT         0x00000001
+#define gcdMMU_MTLB_EXCEPTION       0x00000002
+#define gcdMMU_MTLB_4K_PAGE         (0 << 2)
+#define gcdMMU_MTLB_64K_PAGE        (1 << 2)
+#define gcdMMU_MTLB_1M_PAGE         (2 << 2)
+#define gcdMMU_MTBL_16M_PAGE        (3 << 2)
+
+#define gcdMMU_STLB_PRESENT         0x00000001
+#define gcdMMU_STLB_EXCEPTION       0x00000002
+#define gcdMMU_STBL_WRITEABLE       0x00000004
+
+#else /* 4K mode */
+
+#define gcdMMU_MTLB_SHIFT           22
+#define gcdMMU_STLB_4K_SHIFT        12
+#define gcdMMU_STLB_64K_SHIFT       16
+
+#define gcdMMU_MTLB_BITS            (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS         gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS         (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS        gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS        (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+
+#define gcdMMU_MTLB_ENTRY_NUM       (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE            (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM    (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE         (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE         (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM   (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE        (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE        (1 << gcdMMU_STLB_64K_SHIFT)
+
+#define gcdMMU_MTLB_MASK            (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK         ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK         (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK        ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK        (gcdMMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS       (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK       ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_64K_BITS      (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_64K_BITS)
+#define gcdMMU_OFFSET_64K_MASK      ((1U << gcdMMU_OFFSET_64K_BITS) - 1)
+
+#define gcdMMU_MTLB_ENTRY_HINTS_BITS 6
+#define gcdMMU_MTLB_ENTRY_STLB_MASK  (~((1U << gcdMMU_MTLB_ENTRY_HINTS_BITS) - 1))
+
+#define gcdMMU_MTLB_PRESENT         0x00000001
+#define gcdMMU_MTLB_EXCEPTION       0x00000002
+#define gcdMMU_MTLB_4K_PAGE         (0 << 2)
+#define gcdMMU_MTLB_64K_PAGE        (1 << 2)
+
+
+#define gcdMMU_STLB_PRESENT         0x00000001
+#define gcdMMU_STLB_EXCEPTION       0x00000002
+#define gcdMMU_STLB_WRITEABLE       0x00000004
+
+#endif
+
+#define gcd1M_PAGE_SIZE (1 << 20)
+#define gcd1M_PAGE_SHIFT 20
+
+/*******************************************************************************
+***** Stuck Dump Level ********************************************************/
+
+/* Dump nonthing when stuck happens. */
+#define gcvSTUCK_DUMP_NONE          0
+
+/* Dump GPU state and memory near stuck point. */
+#define gcvSTUCK_DUMP_NEARBY_MEMORY 1
+
+/* Beside gcvSTUCK_DUMP_NEARBY_MEMORY, dump context buffer and user command buffer. */
+#define gcvSTUCK_DUMP_USER_COMMAND  2
+
+/* Beside gcvSTUCK_DUMP_USER_COMMAND, commit will be stall
+** to make sure command causing stuck isn't missed. */
+#define gcvSTUCK_DUMP_STALL_COMMAND 3
+
+/* Beside gcvSTUCK_DUMP_USER_COMMAND, dump kernel command buffer. */
+#define gcvSTUCK_DUMP_ALL_COMMAND   4
+
+/* Dump all the cores with level 4 dump. */
+#define gcvSTUCK_DUMP_ALL_CORE      5
+
+/*******************************************************************************
+***** Page table **************************************************************/
+
+#define gcvPAGE_TABLE_DIRTY_BIT_OTHER   (1 << 0)
+#define gcvPAGE_TABLE_DIRTY_BIT_FE      (1 << 1)
+
+/*******************************************************************************
+***** Process Database Management *********************************************/
+
+typedef enum _gceDATABASE_TYPE
+{
+    gcvDB_VIDEO_MEMORY = 1,             /* Video memory created. */
+    gcvDB_COMMAND_BUFFER,               /* Command Buffer. */
+    gcvDB_NON_PAGED,                    /* Non paged memory. */
+    gcvDB_CONTIGUOUS,                   /* Contiguous memory. */
+    gcvDB_SIGNAL,                       /* Signal. */
+    gcvDB_VIDEO_MEMORY_LOCKED,          /* Video memory locked. */
+    gcvDB_CONTEXT,                      /* Context */
+    gcvDB_IDLE,                         /* GPU idle. */
+    gcvDB_MAP_MEMORY,                   /* Map memory */
+    gcvDB_MAP_USER_MEMORY,              /* Map user memory */
+    gcvDB_SHBUF,                        /* Shared buffer. */
+
+    gcvDB_NUM_TYPES,
+}
+gceDATABASE_TYPE;
+
+#define gcdDATABASE_TYPE_MASK           0x000000FF
+#define gcdDB_VIDEO_MEMORY_TYPE_MASK    0x0000FF00
+#define gcdDB_VIDEO_MEMORY_TYPE_SHIFT   8
+
+#define gcdDB_VIDEO_MEMORY_POOL_MASK    0x00FF0000
+#define gcdDB_VIDEO_MEMORY_POOL_SHIFT   16
+
+#define gcdDB_VIDEO_MEMORY_DBTYPE_MASK  0xFF000000
+#define gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT 24
+
+typedef struct _gcsDATABASE_RECORD *    gcsDATABASE_RECORD_PTR;
+typedef struct _gcsDATABASE_RECORD
+{
+    /* Pointer to kernel. */
+    gckKERNEL                           kernel;
+
+    /* Pointer to next database record. */
+    gcsDATABASE_RECORD_PTR              next;
+
+    /* Type of record. */
+    gceDATABASE_TYPE                    type;
+
+    /* Data for record. */
+    gctPOINTER                          data;
+    gctPHYS_ADDR                        physical;
+    gctSIZE_T                           bytes;
+}
+gcsDATABASE_RECORD;
+
+typedef struct _gcsDATABASE *           gcsDATABASE_PTR;
+typedef struct _gcsDATABASE
+{
+    /* Pointer to next entry is hash list. */
+    gcsDATABASE_PTR                     next;
+    gctSIZE_T                           slot;
+
+    /* Process ID. */
+    gctUINT32                           processID;
+
+    /* Open-Close ref count */
+    gctPOINTER                          refs;
+
+    /* Already mark for delete and cannot reenter */
+    gctBOOL                             deleted;
+
+    /* Sizes to query. */
+    gcsDATABASE_COUNTERS                vidMem;
+    gcsDATABASE_COUNTERS                nonPaged;
+    gcsDATABASE_COUNTERS                contiguous;
+    gcsDATABASE_COUNTERS                mapUserMemory;
+    gcsDATABASE_COUNTERS                mapMemory;
+
+    gcsDATABASE_COUNTERS                vidMemType[gcvVIDMEM_TYPE_COUNT];
+    /* Counter for each video memory pool. */
+    gcsDATABASE_COUNTERS                vidMemPool[gcvPOOL_NUMBER_OF_POOLS];
+    gctPOINTER                          counterMutex;
+
+    /* Idle time management. */
+    gctUINT64                           lastIdle;
+    gctUINT64                           idle;
+
+    /* Pointer to database. */
+    gcsDATABASE_RECORD_PTR              list[48];
+
+    gctPOINTER                          handleDatabase;
+    gctPOINTER                          handleDatabaseMutex;
+}
+gcsDATABASE;
+
+typedef struct _gcsFDPRIVATE *          gcsFDPRIVATE_PTR;
+typedef struct _gcsFDPRIVATE
+{
+    gctINT                              (* release) (gcsFDPRIVATE_PTR Private);
+}
+gcsFDPRIVATE;
+
+typedef struct _gcsRECORDER * gckRECORDER;
+
+
+/* Create a process database that will contain all its allocations. */
+gceSTATUS
+gckKERNEL_CreateProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID
+    );
+
+/* Add a record to the process database. */
+gceSTATUS
+gckKERNEL_AddProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Size
+    );
+
+/* Remove a record to the process database. */
+gceSTATUS
+gckKERNEL_RemoveProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer
+    );
+
+/* Destroy the process database. */
+gceSTATUS
+gckKERNEL_DestroyProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID
+    );
+
+/* Find a record to the process database. */
+gceSTATUS
+gckKERNEL_FindProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 ThreadID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer,
+    OUT gcsDATABASE_RECORD_PTR Record
+    );
+
+/* Query the process database. */
+gceSTATUS
+gckKERNEL_QueryProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL LastProcessID,
+    IN gceDATABASE_TYPE Type,
+    OUT gcuDATABASE_INFO * Info
+    );
+
+/* Dump the process database. */
+gceSTATUS
+gckKERNEL_DumpProcessDB(
+    IN gckKERNEL Kernel
+    );
+
+/* Dump the video memory usage for process specified. */
+gceSTATUS
+gckKERNEL_DumpVidMemUsage(
+    IN gckKERNEL Kernel,
+    IN gctINT32 ProcessID
+    );
+
+gceSTATUS
+gckKERNEL_FindDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL LastProcessID,
+    OUT gcsDATABASE_PTR * Database
+    );
+
+gceSTATUS
+gckKERNEL_FindHandleDatbase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    OUT gctPOINTER * HandleDatabase,
+    OUT gctPOINTER * HandleDatabaseMutex
+    );
+
+gceSTATUS
+gckMMU_GetPageEntry(
+    IN gckMMU Mmu,
+    IN gcePAGE_TYPE PageType,
+    IN gctUINT32 Address,
+    IN gctUINT32_PTR *PageTable
+    );
+
+gceSTATUS
+gckMMU_SetupSRAM(
+    IN gckMMU Mmu,
+    IN gckHARDWARE Hardware,
+    IN gckDEVICE Device
+    );
+
+gceSTATUS
+gckMMU_SetupDynamicSpace(
+    IN gckMMU Mmu
+    );
+
+void
+gckMMU_DumpRecentFreedAddress(
+    IN gckMMU Mmu
+    );
+
+gceSTATUS
+gckKERNEL_CreateIntegerDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Capacity,
+    OUT gctPOINTER * Database
+    );
+
+gceSTATUS
+gckKERNEL_DestroyIntegerDatabase(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Database
+    );
+
+gceSTATUS
+gckKERNEL_AllocateIntegerId(
+    IN gctPOINTER Database,
+    IN gctPOINTER Pointer,
+    OUT gctUINT32 * Id
+    );
+
+gceSTATUS
+gckKERNEL_FreeIntegerId(
+    IN gctPOINTER Database,
+    IN gctUINT32 Id
+    );
+
+gceSTATUS
+gckKERNEL_QueryIntegerId(
+    IN gctPOINTER Database,
+    IN gctUINT32 Id,
+    OUT gctPOINTER * Pointer
+    );
+
+/* Pointer rename  */
+gctUINT32
+gckKERNEL_AllocateNameFromPointer(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Pointer
+    );
+
+gctPOINTER
+gckKERNEL_QueryPointerFromName(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name
+    );
+
+gceSTATUS
+gckKERNEL_DeleteName(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name
+    );
+
+/*******************************************************************************
+********* Timer Management ****************************************************/
+typedef struct _gcsTIMER *           gcsTIMER_PTR;
+typedef struct _gcsTIMER
+{
+    /* Start and Stop time holders. */
+    gctUINT64                           startTime;
+    gctUINT64                           stopTime;
+}
+gcsTIMER;
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+
+/* gckDB object. */
+struct _gckDB
+{
+    /* Database management. */
+    gcsDATABASE_PTR             db[16];
+    gctPOINTER                  dbMutex;
+    gcsDATABASE_PTR             freeDatabase;
+    gcsDATABASE_RECORD_PTR      freeRecord;
+    gcsDATABASE_PTR             lastDatabase;
+    gctUINT32                   lastProcessID;
+    gctUINT64                   lastIdle;
+    gctUINT64                   idleTime;
+    gctUINT64                   lastSlowdown;
+    gctUINT64                   lastSlowdownIdle;
+
+    gctPOINTER                  nameDatabase;
+    gctPOINTER                  nameDatabaseMutex;
+
+    gctPOINTER                  pointerDatabase;
+
+    gcsLISTHEAD                 videoMemList;
+    gctPOINTER                  videoMemListMutex;
+};
+
+typedef struct _gckCOMMAND *        gckCOMMAND;
+
+typedef struct _gckEVENT *      gckEVENT;
+
+/* gckKERNEL object. */
+struct _gckKERNEL
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Pointer to gckDEVICE object. */
+    gckDEVICE                   device;
+
+    /* Pointer to gckHARDWARE object. */
+    gckHARDWARE                 hardware;
+
+    /* Core */
+    gceCORE                     core;
+    gctUINT                     chipID;
+
+    /* Main command module, event and context. */
+    gckCOMMAND                  command;
+    gckEVENT                    eventObj;
+    gctPOINTER                  context;
+
+    /* Async FE command and event modules. */
+    gckCOMMAND                  asyncCommand;
+    gckEVENT                    asyncEvent;
+
+    /* Pointer to gckMMU object. */
+    gckMMU                      mmu;
+
+    /* Arom holding number of clients. */
+    gctPOINTER                  atomClients;
+
+#if VIVANTE_PROFILER
+    /* Enable profiling */
+    gctBOOL                     profileEnable;
+    /* Clear profile register or not*/
+    gctBOOL                     profileCleanRegister;
+#endif
+
+#ifdef QNX_SINGLE_THREADED_DEBUGGING
+    gctPOINTER                  debugMutex;
+#endif
+
+    /* Database management. */
+    gckDB                       db;
+    gctBOOL                     dbCreated;
+
+    gctUINT64                   resetTimeStamp;
+
+    /* Pointer to gckEVENT object. */
+    gcsTIMER                    timers[8];
+    gctUINT32                   timeOut;
+
+#if gcdENABLE_VG
+    gckVGKERNEL                 vg;
+#endif
+
+#if gcdDVFS
+    gckDVFS                     dvfs;
+#endif
+
+#if gcdLINUX_SYNC_FILE
+    gctHANDLE                   timeline;
+#endif
+
+    /* Enable recovery. */
+    gctBOOL                     recovery;
+
+    /* Level of dump information after stuck. */
+    gctUINT                     stuckDump;
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+    gctUINT32                   securityChannel;
+#endif
+
+    /* Timer to monitor GPU stuck. */
+    gctPOINTER                  monitorTimer;
+
+    /* Flag to quit monitor timer. */
+    gctBOOL                     monitorTimerStop;
+
+    /* Monitor states. */
+    gctBOOL                     monitoring;
+    gctUINT32                   lastCommitStamp;
+    gctUINT32                   timer;
+    gctUINT32                   restoreAddress;
+    gctINT32                    restoreMask;
+
+    gckVIDMEM_BLOCK             vidMemBlock;
+    gctPOINTER                  vidMemBlockMutex;
+
+    gctUINT32                   contiguousBaseAddress;
+    gctUINT32                   externalBaseAddress;
+    gctUINT32                   internalBaseAddress;
+
+    /* External shared SRAM. */
+    gctUINT32                   extSRAMBaseAddresses[gcvSRAM_EXT_COUNT];
+    gctUINT32                   extSRAMIndex;
+
+    /* Per core SRAM description. */
+    gctUINT32                   sRAMIndex;
+    gckVIDMEM                   sRAMVidMem[gcvSRAM_INTER_COUNT];
+    gctPHYS_ADDR                sRAMPhysical[gcvSRAM_INTER_COUNT];
+    gctUINT32                   sRAMBaseAddresses[gcvSRAM_INTER_COUNT];
+    gctUINT32                   sRAMSizes[gcvSRAM_INTER_COUNT];
+    gctBOOL                     sRAMPhysFaked[gcvSRAM_INTER_COUNT];
+    gctUINT64                   sRAMLoopMode;
+
+    gctUINT32                   timeoutPID;
+    gctBOOL                     threadInitialized;
+};
+
+struct _FrequencyHistory
+{
+    gctUINT32                   frequency;
+    gctUINT32                   count;
+};
+
+/* gckDVFS object. */
+struct _gckDVFS
+{
+    gckOS                       os;
+    gckHARDWARE                 hardware;
+    gctPOINTER                  timer;
+    gctUINT32                   pollingTime;
+    gctBOOL                     stop;
+    gctUINT32                   totalConfig;
+    gctUINT32                   loads[8];
+    gctUINT8                    currentScale;
+    struct _FrequencyHistory    frequencyHistory[16];
+};
+
+typedef struct _gcsFENCE * gckFENCE;
+typedef struct _gcsFENCE
+{
+    /* Pointer to required object. */
+    gckKERNEL                   kernel;
+
+    /* Fence location. */
+    gckVIDMEM_NODE              videoMem;
+    gctPOINTER                  logical;
+    gctUINT32                   address;
+
+    gcsLISTHEAD                 waitingList;
+    gctPOINTER                  mutex;
+}
+gcsFENCE;
+
+/* A sync point attached to fence. */
+typedef struct _gcsFENCE_SYNC * gckFENCE_SYNC;
+typedef struct _gcsFENCE_SYNC
+{
+    /* Stamp of commit access this node. */
+    gctUINT64                   commitStamp;
+
+    /* Attach to waiting list. */
+    gcsLISTHEAD                 head;
+
+    gctPOINTER                  signal;
+
+    gctBOOL                     inList;
+}
+gcsFENCE_SYNC;
+
+typedef struct _gcsCOMMAND_QUEUE
+{
+    gctSIGNAL               signal;
+    gckVIDMEM_NODE          videoMem;
+    gctPOINTER              logical;
+    gctUINT32               address;
+}
+gcsCOMMAND_QUEUE;
+
+/* gckCOMMAND object. */
+struct _gckCOMMAND
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to required object. */
+    gckKERNEL                   kernel;
+    gckOS                       os;
+
+    gceHW_FE_TYPE               feType;
+
+    /* Number of bytes per page. */
+    gctUINT32                   pageSize;
+
+    /* Current pipe select. */
+    gcePIPE_SELECT              pipeSelect;
+
+    /* Command queue running flag. */
+    gctBOOL                     running;
+
+    /* Idle flag and commit stamp. */
+    gctBOOL                     idle;
+    gctUINT64                   commitStamp;
+
+    /* Command queue mutex. */
+    gctPOINTER                  mutexQueue;
+
+    /* Context switching mutex. */
+    gctPOINTER                  mutexContext;
+
+    /* Context sequence mutex. */
+    gctPOINTER                  mutexContextSeq;
+
+    /* Command queue power semaphore. */
+    gctPOINTER                  powerSemaphore;
+
+    /* Command queues. */
+    gcsCOMMAND_QUEUE            queues[gcdCOMMAND_QUEUES];
+
+    /* Current queue. */
+    gckVIDMEM_NODE              videoMem;
+    gctPOINTER                  logical;
+    gctUINT32                   address;
+
+    gctUINT32                   offset;
+    gctINT                      index;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gctUINT                     wrapCount;
+#endif
+
+    /* The command queue is new. */
+    gctBOOL                     newQueue;
+
+    /* Context management. */
+    gckCONTEXT                  currContext;
+    gctPOINTER                  stateMap;
+
+    /* Pointer to last WAIT command. */
+    /* Wait-Link FE only. */
+    struct
+    {
+        gckVIDMEM_NODE          videoMem;
+        gctUINT32               offset;
+        gctPOINTER              logical;
+        gctUINT32               address;
+        gctUINT32               size;
+    }
+    waitPos;
+
+    /* MCFE. */
+    gctUINT32                   totalSemaId;
+
+    /*
+     * freeSemaId   ------>  [pendingSema]
+     * ^                    freePos -->+ +
+     * |                    ^          | |
+     * |                    |          | |
+     * |                    nextPos ---+ |
+     * |                                 |
+     * |                                 |
+     * |                                 v
+     * nextSemaId <----------------------+
+     *
+     * Terminology:
+     * 'freeSemaId': the top (final) free sema id can be used, signaled already.
+     * 'nextSemaId': the next sema id to be used.
+     * 'pendingSema': the used semaphores which are tracked in the ring.
+     *
+     * 3 Id sections:
+     * Id(s) between 'nextSemaId' and 'freeSemaId':
+     * Available for immediate use.
+     *
+     * Id(s) between 'freeSemaId' (exclusive) and 'pendingSema':
+     * To be signed, will be available to use later.
+     *
+     * Id(s) between 'pendingSema' and 'nextSemaId':
+     * The semaphores just used, not tracking in pendingSema ring.
+     *
+     * Conditions:
+     * 'nextSemaId' = 'freeSemaId':
+     * Using the final free semaphore, means the ring is full of used ones.
+     *
+     * 'freeSemaId' + 1 = 'nextSemaId':
+     * Can use 'freeSema' + 1 to 'freeSema'(loop back), means empty ring,
+     * ie, no used one.
+     */
+
+    /* MCFE semaphore id tracking ring. */
+    gctUINT32                   nextSemaId;
+    gctUINT32                   freeSemaId;
+
+    gctUINT32                   semaMinThreshhold;
+
+    /* pending semaphore id tracking ring. */
+    struct
+    {
+        gctUINT32               semaId;
+        gctSIGNAL               signal;
+    }
+    pendingSema[8];
+
+    gctUINT32                   nextPendingPos;
+    gctUINT32                   freePendingPos;
+
+    /* semaphore id (array index) to handle value map. */
+    gctUINT32 *                 semaHandleMap;
+
+    /*
+     * Dirty channels, ie channels ever submitted commands.
+     * Need sync to (send semaphore to) system channel.
+     */
+    gctUINT64                   dirtyChannel[2];
+
+    /*
+     * Sync channels, need sync from (wait semaphore from) the system
+     * channel before its own jobs.
+     */
+    gctUINT64                   syncChannel[2];
+
+    /* Command buffer alignment. */
+    gctUINT32                   alignment;
+
+    /* Commit counter. */
+    gctPOINTER                  atomCommit;
+
+    /* Kernel process ID. */
+    gctUINT32                   kernelProcessID;
+
+#if gcdRECORD_COMMAND
+    gckRECORDER                 recorder;
+#endif
+
+    gckFENCE                    fence;
+
+    gctBOOL                     dummyDraw;
+};
+
+typedef struct _gcsEVENT *      gcsEVENT_PTR;
+
+/* Structure holding one event to be processed. */
+typedef struct _gcsEVENT
+{
+    /* Pointer to next event in queue. */
+    gcsEVENT_PTR                next;
+
+    /* Event information. */
+    gcsHAL_INTERFACE            info;
+
+    /* Process ID owning the event. */
+    gctUINT32                   processID;
+
+#ifdef __QNXNTO__
+    /* Kernel. */
+    gckKERNEL                   kernel;
+#endif
+
+    gctBOOL                     fromKernel;
+}
+gcsEVENT;
+
+/* Structure holding a list of events to be processed by an interrupt. */
+typedef struct _gcsEVENT_QUEUE * gcsEVENT_QUEUE_PTR;
+typedef struct _gcsEVENT_QUEUE
+{
+    /* Time stamp. */
+    gctUINT64                   stamp;
+
+    /* Source of the event. */
+    gceKERNEL_WHERE             source;
+
+    /* Pointer to head of event queue. */
+    gcsEVENT_PTR                head;
+
+    /* Pointer to tail of event queue. */
+    gcsEVENT_PTR                tail;
+
+    /* Next list of events. */
+    gcsEVENT_QUEUE_PTR          next;
+
+    /* Current commit stamp. */
+    gctUINT64                   commitStamp;
+}
+gcsEVENT_QUEUE;
+
+/*
+    gcdREPO_LIST_COUNT defines the maximum number of event queues with different
+    hardware module sources that may coexist at the same time. Only two sources
+    are supported - gcvKERNEL_COMMAND and gcvKERNEL_PIXEL. gcvKERNEL_COMMAND
+    source is used only for managing the kernel command queue and is only issued
+    when the current command queue gets full. Since we commit event queues every
+    time we commit command buffers, in the worst case we can have up to three
+    pending event queues:
+        - gcvKERNEL_PIXEL
+        - gcvKERNEL_COMMAND (queue overflow)
+        - gcvKERNEL_PIXEL
+*/
+#define gcdREPO_LIST_COUNT      3
+
+
+/* gckEVENT object. */
+struct _gckEVENT
+{
+    /* The object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to required objects. */
+    gckOS                       os;
+    gckKERNEL                   kernel;
+
+    /* Pointer to COMMAND object, either one of the 3. */
+    gckCOMMAND                  command;
+
+    /* Submit function pointer, different for different command module. */
+    gceSTATUS                (* submitEvent)(gckEVENT, gctBOOL, gctBOOL);
+
+    /* Time stamp. */
+    gctUINT64                   stamp;
+    gctUINT32                   lastCommitStamp;
+
+    /* Queue mutex. */
+    gctPOINTER                  eventQueueMutex;
+
+    /* Array of event queues. */
+    gcsEVENT_QUEUE              queues[29];
+    gctINT32                    freeQueueCount;
+    gctUINT8                    lastID;
+
+    /* Pending events. */
+    gctPOINTER                  pending;
+
+    /* List of free event structures and its mutex. */
+    gcsEVENT_PTR                freeEventList;
+    gctSIZE_T                   freeEventCount;
+    gctPOINTER                  freeEventMutex;
+
+    /* Event queues. */
+    gcsEVENT_QUEUE_PTR          queueHead;
+    gcsEVENT_QUEUE_PTR          queueTail;
+    gcsEVENT_QUEUE_PTR          freeList;
+    gcsEVENT_QUEUE              repoList[gcdREPO_LIST_COUNT];
+    gctPOINTER                  eventListMutex;
+
+    gctPOINTER                  submitTimer;
+
+#if gcdINTERRUPT_STATISTIC
+    gctPOINTER                  interruptCount;
+#endif
+
+    gctINT                      notifyState;
+};
+
+/* Construct a new gckEVENT object. */
+gceSTATUS
+gckEVENT_Construct(
+    IN gckKERNEL Kernel,
+    IN gckCOMMAND Command,
+    OUT gckEVENT * Event
+    );
+
+/* Destroy an gckEVENT object. */
+gceSTATUS
+gckEVENT_Destroy(
+    IN gckEVENT Event
+    );
+
+/* Reserve the next available hardware event. */
+gceSTATUS
+gckEVENT_GetEvent(
+    IN gckEVENT Event,
+    IN gctBOOL Wait,
+    OUT gctUINT8 * EventID,
+    IN gceKERNEL_WHERE Source
+   );
+
+/* Add a new event to the list of events. */
+gceSTATUS
+gckEVENT_AddList(
+    IN gckEVENT Event,
+    IN gcsHAL_INTERFACE_PTR Interface,
+    IN gceKERNEL_WHERE FromWhere,
+    IN gctBOOL AllocateAllowed,
+    IN gctBOOL FromKernel
+    );
+
+/* Schedule a FreeVideoMemory event. */
+gceSTATUS
+gckEVENT_FreeVideoMemory(
+    IN gckEVENT Event,
+    IN gcuVIDMEM_NODE_PTR VideoMemory,
+    IN gceKERNEL_WHERE FromWhere
+    );
+
+/* Schedule a signal event. */
+gceSTATUS
+gckEVENT_Signal(
+    IN gckEVENT Event,
+    IN gctSIGNAL Signal,
+    IN gceKERNEL_WHERE FromWhere
+    );
+
+/* Schedule an Unlock event. */
+gceSTATUS
+gckEVENT_Unlock(
+    IN gckEVENT Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN gctPOINTER Node
+    );
+
+gceSTATUS
+gckEVENT_CommitDone(
+    IN gckEVENT Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN gckCONTEXT Context
+    );
+
+gceSTATUS
+gckEVENT_Submit(
+    IN gckEVENT Event,
+    IN gctBOOL Wait,
+    IN gctBOOL FromPower
+    );
+
+gceSTATUS
+gckEVENT_Commit(
+    IN gckEVENT Event,
+    IN gcsQUEUE_PTR Queue,
+    IN gctBOOL Forced
+    );
+
+/* Event callback routine. */
+gceSTATUS
+gckEVENT_Notify(
+    IN gckEVENT Event,
+    IN gctUINT32 IDs
+    );
+
+/* Event callback routine. */
+gceSTATUS
+gckEVENT_Interrupt(
+    IN gckEVENT Event,
+    IN gctUINT32 IDs
+    );
+
+gceSTATUS
+gckEVENT_Dump(
+    IN gckEVENT Event
+    );
+
+/* Free all events belonging to a process. */
+gceSTATUS
+gckEVENT_FreeProcess(
+    IN gckEVENT Event,
+    IN gctUINT32 ProcessID
+    );
+
+/* gcuVIDMEM_NODE structure. */
+typedef union _gcuVIDMEM_NODE
+{
+    /* Allocated from gckVIDMEM. */
+    struct _gcsVIDMEM_NODE_VIDMEM
+    {
+        /* Owner of this node. */
+        gckVIDMEM               parent;
+
+        /* Dual-linked list of nodes. */
+        gcuVIDMEM_NODE_PTR      next;
+        gcuVIDMEM_NODE_PTR      prev;
+
+        /* Dual linked list of free nodes. */
+        gcuVIDMEM_NODE_PTR      nextFree;
+        gcuVIDMEM_NODE_PTR      prevFree;
+
+        /* Information for this node. */
+        gctSIZE_T               offset;
+
+        gctUINT32               address;
+        gctSIZE_T               bytes;
+        gctUINT32               alignment;
+
+        /* Client virtual address. */
+        gctPOINTER              logical;
+
+        /* Process ID owning this memory. */
+        gctUINT32               processID;
+
+        /* Locked counter. */
+        gctINT32                locked;
+
+        /* Memory pool. */
+        gcePOOL                 pool;
+
+        /* Kernel virtual address. */
+        gctPOINTER              kvaddr;
+
+        /* mdl record pointer. */
+        gctPHYS_ADDR            physical;
+
+#if gcdENABLE_VG
+        gctPOINTER              kernelVirtual;
+#endif
+    }
+    VidMem;
+
+    /* Allocated from gckOS. */
+    struct _gcsVIDMEM_NODE_VIRTUAL
+    {
+        /* Pointer to gckKERNEL object. */
+        gckKERNEL               kernel;
+
+        /* Information for this node. */
+        /* Contiguously allocated? */
+        gctBOOL                 contiguous;
+        /* mdl record pointer... a kmalloc address. Process agnostic. */
+        gctPHYS_ADDR            physical;
+        gctSIZE_T               bytes;
+
+        /* do_mmap_pgoff address... mapped per-process. */
+        gctPOINTER              logical;
+
+        /* Kernel virtual address. */
+        gctPOINTER              kvaddr;
+
+#if gcdENABLE_VG
+        /* Physical address of this node, only meaningful when it is contiguous. */
+        gctUINT64               physicalAddress;
+
+        /* Kernel logical of this node. */
+        gctPOINTER              kernelVirtual;
+#endif
+
+        /* Customer private handle */
+        gctUINT32               gid;
+
+        /* Page table information. */
+        /* Used only when node is not contiguous */
+        gctSIZE_T               pageCount;
+
+        /* Used only when node is not contiguous */
+        gctPOINTER              pageTables[gcvHARDWARE_NUM_TYPES];
+        /* Actual physical address */
+        gctUINT32               addresses[gcvHARDWARE_NUM_TYPES];
+
+        /* Locked counter. */
+        gctINT32                lockeds[gcvHARDWARE_NUM_TYPES];
+
+        /* MMU page size type */
+        gcePAGE_TYPE            pageType;
+
+        gceVIDMEM_TYPE          type;
+
+        /* Secure GPU virtual address. */
+        gctBOOL                 secure;
+
+        gctBOOL                 onFault;
+    }
+    Virtual;
+
+    struct _gcsVIDMEM_NODE_VIRTUAL_CHUNK
+    {
+        /* Owner of this chunk */
+        gckVIDMEM_BLOCK         parent;
+
+        /* Pointer to gckKERNEL object. */
+        gckKERNEL               kernel;
+
+        /* Dual-linked list of chunk. */
+        gcuVIDMEM_NODE_PTR      next;
+        gcuVIDMEM_NODE_PTR      prev;
+
+        /* Dual linked list of free chunk. */
+        gcuVIDMEM_NODE_PTR      nextFree;
+        gcuVIDMEM_NODE_PTR      prevFree;
+
+        /* Information for this chunk. */
+        gctSIZE_T               offset;
+        gctUINT32               addresses[gcvHARDWARE_NUM_TYPES];
+        gctINT32                lockeds[gcvHARDWARE_NUM_TYPES];
+        gctSIZE_T               bytes;
+
+        /* Mapped user logical */
+        gctPOINTER              logical;
+
+        /* Kernel virtual address. */
+        gctPOINTER              kvaddr;
+
+        /* Locked counter. */
+    }
+    VirtualChunk;
+
+}
+gcuVIDMEM_NODE;
+
+/* gckVIDMEM object. */
+struct _gckVIDMEM
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* mdl record pointer... a kmalloc address. Process agnostic. */
+    gctPHYS_ADDR                physical;
+
+    /* Information for this video memory heap. */
+    gctPHYS_ADDR_T              physicalBase;
+    gctSIZE_T                   bytes;
+    gctSIZE_T                   freeBytes;
+    gctSIZE_T                   minFreeBytes;
+
+    /* caps inherit from its allocator, ~0u if allocator was not applicable. */
+    gctUINT32                   capability;
+
+    /* Mapping for each type of surface. */
+    gctINT                      mapping[gcvVIDMEM_TYPE_COUNT];
+
+    /* Sentinel nodes for up to 8 banks. */
+    gcuVIDMEM_NODE              sentinel[8];
+
+    /* Allocation threshold. */
+    gctSIZE_T                   threshold;
+
+    /* The heap mutex. */
+    gctPOINTER                  mutex;
+};
+
+/* gckVIDMEM_BLOCK object. */
+typedef struct _gcsVIDMEM_BLOCK
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* linked list of nodes. */
+    gckVIDMEM_BLOCK             next;
+
+    /* Contiguously allocated? */
+    gctBOOL                     contiguous;
+
+    /* Customer private handle */
+    gctUINT32                   gid;
+
+    /* mdl record pointer... a kmalloc address. Process agnostic. */
+    gctPHYS_ADDR                physical;
+
+    /* Information for this video memory virtual block. */
+    gctSIZE_T                   bytes;
+    gctSIZE_T                   freeBytes;
+
+    /* 1M page count. */
+    gctUINT32                   pageCount;
+
+    /* Gpu virtual base of this video memory heap. */
+    gctUINT32                   addresses[gcvHARDWARE_NUM_TYPES];
+    gctPOINTER                  pageTables[gcvHARDWARE_NUM_TYPES];
+
+    /* TODO: */
+    gceVIDMEM_TYPE              type;
+
+    /* Virtual chunk. */
+    gcuVIDMEM_NODE              node;
+
+    gctPOINTER                  mutex;
+
+    gctBOOL                     secure;
+    gctBOOL                     onFault;
+}
+gcsVIDMEM_BLOCK;
+
+typedef struct _gcsVIDMEM_NODE
+{
+    _VIV_VIDMEM_METADATA        metadata;
+
+    /* Pointer to gcuVIDMEM_NODE. */
+    gcuVIDMEM_NODE_PTR          node;
+
+    /* Pointer to gckKERNEL object. */
+    gckKERNEL                   kernel;
+
+    /* Mutex to protect node. */
+    gctPOINTER                  mutex;
+
+    /* Reference count. */
+    gctPOINTER                  reference;
+
+    /* Name for client to import. */
+    gctUINT32                   name;
+
+    /* Link in _gckDB::videoMemList. */
+    gcsLISTHEAD                 link;
+
+    /* dma_buf */
+    gctPOINTER                  dmabuf;
+
+    /* Video memory allocation type. */
+    gceVIDMEM_TYPE              type;
+
+    /* Pool from which node is allocated. */
+    gcePOOL                     pool;
+
+    gcsFENCE_SYNC               sync[gcvENGINE_GPU_ENGINE_COUNT];
+
+    /* For DRM usage */
+    gctUINT64                   timeStamp;
+    gckVIDMEM_NODE              tsNode;
+    gctUINT32                   tilingMode;
+    gctUINT32                   tsMode;
+    gctUINT32                   tsCacheMode;
+    gctUINT64                   clearValue;
+
+#if gcdCAPTURE_ONLY_MODE
+    gctSIZE_T                   captureSize;
+    gctPOINTER                  captureLogical;
+#endif
+}
+gcsVIDMEM_NODE;
+
+typedef struct _gcsVIDMEM_HANDLE * gckVIDMEM_HANDLE;
+typedef struct _gcsVIDMEM_HANDLE
+{
+    /* Pointer to gckVIDMEM_NODE. */
+    gckVIDMEM_NODE              node;
+
+    /* Handle for current process. */
+    gctUINT32                   handle;
+
+    /* Reference count for this handle. */
+    gctPOINTER                  reference;
+}
+gcsVIDMEM_HANDLE;
+
+typedef struct _gcsSHBUF * gcsSHBUF_PTR;
+typedef struct _gcsSHBUF
+{
+    /* ID. */
+    gctUINT32                   id;
+
+    /* Reference count. */
+    gctPOINTER                  reference;
+
+    /* Data size. */
+    gctUINT32                   size;
+
+    /* Data. */
+    gctPOINTER                  data;
+}
+gcsSHBUF;
+
+typedef struct _gcsCORE_INFO
+{
+    gceHARDWARE_TYPE            type;
+    gceCORE                     core;
+    gckKERNEL                   kernel;
+    gctUINT                     chipID;
+}
+gcsCORE_INFO;
+
+typedef struct _gcsCORE_LIST
+{
+    gckKERNEL                   kernels[gcvCORE_COUNT];
+    gctUINT32                   num;
+}
+gcsCORE_LIST;
+
+/* A gckDEVICE is a group of cores (gckKERNEL in software). */
+typedef struct _gcsDEVICE
+{
+    gcsCORE_INFO                coreInfoArray[gcvCORE_COUNT];
+    gctUINT32                   coreNum;
+    gcsCORE_LIST                map[gcvHARDWARE_NUM_TYPES];
+    gceHARDWARE_TYPE            defaultHwType;
+
+    gckOS                       os;
+
+    /* Process resource database. */
+    gckDB                       database;
+
+    /* Same hardware type shares one MMU. */
+    gckMMU                      mmus[gcvHARDWARE_NUM_TYPES];
+
+    /* Physical address of internal SRAMs. */
+    gctUINT64                   sRAMBases[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    /* Internal SRAMs' size. */
+    gctUINT32                   sRAMSizes[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    /* GPU/VIP virtual address of internal SRAMs. */
+    gctUINT32                   sRAMBaseAddresses[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    gctBOOL                     sRAMPhysFaked[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+
+    /* CPU physical address of external SRAMs. */
+    gctUINT64                   extSRAMBases[gcvSRAM_EXT_COUNT];
+    /* GPU physical address of external SRAMs. */
+    gctUINT64                   extSRAMGPUBases[gcvSRAM_EXT_COUNT];
+    /* External SRAMs' size. */
+    gctUINT32                   extSRAMSizes[gcvSRAM_EXT_COUNT];
+    /* GPU/VIP virtual address of external SRAMs. */
+    gctUINT32                   extSRAMBaseAddresses[gcvSRAM_EXT_COUNT];
+    /* MDL. */
+    gctPHYS_ADDR                extSRAMPhysical[gcvSRAM_EXT_COUNT];
+    /* IntegerId. */
+    gctUINT32                   extSRAMGPUPhysNames[gcvSRAM_EXT_COUNT];
+
+    /* Show SRAM mapping info or not. */
+    gctUINT                     showSRAMMapInfo;
+
+    /* Mutex to make sure stuck dump for multiple cores doesn't interleave. */
+    gctPOINTER                  stuckDumpMutex;
+
+    /* Mutex for multi-core combine mode command submission */
+    gctPOINTER                  commitMutex;
+}
+gcsDEVICE;
+
+/* video memory pool functions. */
+/* Construct a new gckVIDMEM object. */
+gceSTATUS
+gckVIDMEM_Construct(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T PhysicalBase,
+    IN gctSIZE_T Bytes,
+    IN gctSIZE_T Threshold,
+    IN gctSIZE_T Banking,
+    OUT gckVIDMEM * Memory
+    );
+
+/* Destroy an gckVDIMEM object. */
+gceSTATUS
+gckVIDMEM_Destroy(
+    IN gckVIDMEM Memory
+    );
+
+
+gceSTATUS
+gckVIDMEM_HANDLE_Allocate(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE Node,
+    OUT gctUINT32 * Handle
+    );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Reference(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle
+    );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Dereference(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle
+    );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle,
+    OUT gckVIDMEM_NODE * Node
+    );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup2(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database,
+    IN gctUINT32 Handle,
+    OUT gckVIDMEM_NODE * Node
+    );
+
+/* video memory node functions. */
+gceSTATUS
+gckVIDMEM_NODE_AllocateLinear(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM VideoMemory,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN gctUINT32 Alignment,
+    IN gctBOOL Specified,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_AllocateVirtual(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_AllocateVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Reference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE Node
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Dereference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE Node
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetReference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT32 * ReferenceCount
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Lock(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 *Address
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Unlock(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 ProcessID,
+    IN OUT gctBOOL * Asynchroneous
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_CleanCache(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_InvalidateCache(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetLockCount(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT32 * LockCount
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_LockCPU(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctBOOL Cacheable,
+    IN gctBOOL FromUser,
+    OUT gctPOINTER * Logical
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_UnlockCPU(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL FromUser,
+    IN gctBOOL Defer
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetPhysical(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * PhysicalAddress
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetGid(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 * Gid
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetSize(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctSIZE_T * Size
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetType(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gceVIDMEM_TYPE * Type,
+    OUT gcePOOL * Pool
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Export(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctINT32 Flags,
+    OUT gctPOINTER *DmaBuf,
+    OUT gctINT32 *FD
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Name(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 * Name
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Import(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name,
+    OUT gckVIDMEM_NODE * NodeObject
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetFd(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT * Fd
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_WrapUserMemory(
+    IN gckKERNEL Kernel,
+    IN gcsUSER_MEMORY_DESC_PTR Desc,
+    IN gceVIDMEM_TYPE Type,
+    OUT gckVIDMEM_NODE * NodeObject,
+    OUT gctUINT64 * Bytes
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_SetCommitStamp(
+    IN gckKERNEL Kernel,
+    IN gceENGINE Engine,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT64 CommitStamp
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_GetCommitStamp(
+    IN gckKERNEL Kernel,
+    IN gceENGINE Engine,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT64_PTR CommitStamp
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_Find(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Address,
+    OUT gckVIDMEM_NODE * NodeObject,
+    OUT gctUINT32 * Offset
+    );
+
+gceSTATUS
+gckVIDMEM_NODE_IsContiguous(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctBOOL * Contiguous
+    );
+
+typedef struct _gcsADDRESS_AREA * gcsADDRESS_AREA_PTR;
+typedef struct _gcsADDRESS_AREA
+{
+    /* Page table / STLB table information. */
+    gctSIZE_T                   stlbSize;
+    gckVIDMEM_NODE              stlbVideoMem;
+    gctUINT32_PTR               stlbLogical;
+    gctUINT32                   stlbEntries;
+    /* stlb physical address. */
+    gctPHYS_ADDR_T              stlbPhysical;
+
+    /* Free entries. */
+    gctUINT32                   heapList;
+    gctBOOL                     freeNodes;
+
+    gceAREA_TYPE                areaType;
+
+    gctUINT32                   mappingStart;
+    gctUINT32                   mappingEnd;
+
+    gctUINT32_PTR               mapLogical;
+}
+gcsADDRESS_AREA;
+
+/* gckMMU object. */
+struct _gckMMU
+{
+    /* The object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Pointer to gckHARDWARE object. */
+    gckHARDWARE                 hardware;
+
+    /* The page table mutex. */
+    gctPOINTER                  pageTableMutex;
+
+    /* Master TLB information. */
+    gctSIZE_T                   mtlbSize;
+    gckVIDMEM_NODE              mtlbVideoMem;
+    gctUINT32_PTR               mtlbLogical;
+    gctUINT32                   mtlbEntries;
+    /* mtlb physical address. */
+    gctPHYS_ADDR_T              mtlbPhysical;
+
+    /* memory pool used for page table */
+    gcePOOL                     pool;
+
+    gctPOINTER                  staticSTLB;
+    gctBOOL                     enabled;
+
+    gctSIZE_T                   safePageSize;
+    gckVIDMEM_NODE              safePageVideoMem;
+    gctPOINTER                  safePageLogical;
+    gctUINT32                   safeAddress;
+    /* Safe page physical address. */
+    gctPHYS_ADDR_T              safePagePhysical;
+
+    /* GPU physical address flat mapping area. */
+    gctUINT32                   gpuPhysicalRangeCount;
+    gcsFLAT_MAPPING_RANGE       gpuPhysicalRanges[gcdMAX_FLAT_MAPPING_COUNT];
+
+    /* GPU virtual address flat mapping area*/
+    gctUINT32                   gpuAddressRangeCount;
+    gcsFLAT_MAPPING_RANGE       gpuAddressRanges[gcdMAX_FLAT_MAPPING_COUNT];
+
+    /* List of hardware which uses this MMU. */
+    gcsLISTHEAD                 hardwareList;
+
+    struct _gckQUEUE            recentFreedAddresses;
+
+    gcsADDRESS_AREA             dynamicArea1M;
+    gcsADDRESS_AREA             dynamicArea4K;
+    gcsADDRESS_AREA             secureArea;
+
+    gctBOOL                     dynamicAreaSetuped;
+
+    gctBOOL                     sRAMMapped;
+
+    gctUINT32                   contiguousBaseAddress;
+    gctUINT32                   externalBaseAddress;
+    gctUINT32                   internalBaseAddress;
+};
+
+
+gceSTATUS
+gckOS_CreateKernelMapping(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    );
+
+gceSTATUS
+gckOS_DestroyKernelMapping(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical
+    );
+
+gceSTATUS
+gckOS_GetFd(
+    IN gctSTRING Name,
+    IN gcsFDPRIVATE_PTR Private,
+    OUT gctINT *Fd
+    );
+
+/*******************************************************************************
+**
+**  gckOS_ReadMappedPointer
+**
+**  Read pointer mapped from user pointer which returned by gckOS_MapUserPointer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Address
+**          Pointer returned by gckOS_MapUserPointer.
+**
+**      gctUINT32_PTR Data
+**          Pointer to hold 32 bits data.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_ReadMappedPointer(
+    IN gckOS Os,
+    IN gctPOINTER Address,
+    IN gctUINT32_PTR Data
+    );
+
+gceSTATUS
+gckKERNEL_AttachProcess(
+    IN gckKERNEL Kernel,
+    IN gctBOOL Attach
+    );
+
+gceSTATUS
+gckKERNEL_AttachProcessEx(
+    IN gckKERNEL Kernel,
+    IN gctBOOL Attach,
+    IN gctUINT32 PID
+    );
+
+gceSTATUS
+gckKERNEL_AllocateVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Alignment,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    IN OUT gcePOOL * Pool,
+    OUT gckVIDMEM_NODE * NodeObject
+    );
+
+gceSTATUS
+gckHARDWARE_QueryIdle(
+    IN gckHARDWARE Hardware,
+    OUT gctBOOL_PTR IsIdle
+    );
+
+gceSTATUS
+gckHARDWARE_WaitFence(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT64 FenceData,
+    IN gctUINT32 FenceAddress,
+    OUT gctUINT32 *Bytes
+    );
+
+gceSTATUS
+gckHARDWARE_UpdateContextID(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_QueryMcfe(
+    IN gckHARDWARE Hardware,
+    OUT const gceMCFE_CHANNEL_TYPE * Channels[],
+    OUT gctUINT32 * Count
+    );
+
+#if gcdSECURITY
+gceSTATUS
+gckKERNEL_SecurityOpen(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPU,
+    OUT gctUINT32 *Channel
+    );
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+    IN gctUINT32 Channel
+    );
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+    IN gctUINT32 Channel,
+    IN OUT gcsTA_INTERFACE * Interface
+    );
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+    IN gckKERNEL Kernel
+    );
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Bytes,
+    OUT gctUINT32 * Handle
+    );
+
+gceSTATUS
+gckKERNEL_SecurityExecute(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Buffer,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 *PhysicalArray,
+    IN gctUINT32 PageCount,
+    OUT gctUINT32 * GPUAddress
+    );
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPUAddress,
+    IN gctUINT32 PageCount
+    );
+
+#endif
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_SecurityOpen(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPU,
+    OUT gctUINT32 *Channel
+    );
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+    IN gctUINT32 Channel
+    );
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+    IN gctUINT32 Channel,
+    IN OUT gcsTA_INTERFACE * Interface
+    );
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 *PhysicalArray,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 PageCount,
+    OUT gctUINT32 * GPUAddress
+    );
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPUAddress,
+    IN gctUINT32 PageCount
+    );
+
+gceSTATUS
+gckKERNEL_SecurityDumpMMUException(
+    IN gckKERNEL Kernel
+    );
+
+gceSTATUS
+gckKERNEL_ReadMMUException(
+    IN gckKERNEL Kernel,
+    IN gctUINT32_PTR MMUStatus,
+    IN gctUINT32_PTR MMUException
+    );
+
+gceSTATUS
+gckKERNEL_HandleMMUException(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 MMUStatus,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 GPUAddres
+    );
+#endif
+
+gceSTATUS
+gckKERNEL_CreateShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Size,
+    OUT gctSHBUF * ShBuf
+    );
+
+gceSTATUS
+gckKERNEL_DestroyShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf
+    );
+
+gceSTATUS
+gckKERNEL_MapShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf
+    );
+
+gceSTATUS
+gckKERNEL_WriteShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf,
+    IN gctPOINTER UserData,
+    IN gctUINT32 ByteCount
+    );
+
+gceSTATUS
+gckKERNEL_ReadShBuffer(
+    IN gckKERNEL Kernel,
+    IN gctSHBUF ShBuf,
+    IN gctPOINTER UserData,
+    IN gctUINT32 ByteCount,
+    OUT gctUINT32 * BytesRead
+    );
+
+gceSTATUS
+gckKERNEL_GetHardwareType(
+    IN gckKERNEL Kernel,
+    OUT gceHARDWARE_TYPE *Type
+    );
+
+/******************************************************************************\
+******************************* gckCONTEXT Object *******************************
+\******************************************************************************/
+
+gceSTATUS
+gckCONTEXT_Construct(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 ProcessID,
+    OUT gckCONTEXT * Context
+    );
+
+gceSTATUS
+gckCONTEXT_Destroy(
+    IN gckCONTEXT Context
+    );
+
+gceSTATUS
+gckCONTEXT_Update(
+    IN gckCONTEXT Context,
+    IN gctUINT32 ProcessID,
+    IN gcsSTATE_DELTA_PTR StateDelta
+    );
+
+gceSTATUS
+gckCONTEXT_MapBuffer(
+    IN gckCONTEXT Context,
+    OUT gctUINT64 *Logicals,
+    OUT gctUINT32 *Bytes
+    );
+
+void
+gckQUEUE_Enqueue(
+    IN gckQUEUE LinkQueue,
+    IN gcuQUEUEDATA *Data
+    );
+
+void
+gckQUEUE_GetData(
+    IN gckQUEUE LinkQueue,
+    IN gctUINT32 Index,
+    OUT gcuQUEUEDATA ** Data
+    );
+
+gceSTATUS
+gckQUEUE_Allocate(
+    IN gckOS Os,
+    IN gckQUEUE Queue,
+    IN gctUINT32 Size
+    );
+
+gceSTATUS
+gckQUEUE_Free(
+    IN gckOS Os,
+    IN gckQUEUE Queue
+    );
+
+/******************************************************************************\
+****************************** gckRECORDER Object ******************************
+\******************************************************************************/
+gceSTATUS
+gckRECORDER_Construct(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    OUT gckRECORDER * Recorder
+    );
+
+gceSTATUS
+gckRECORDER_Destory(
+    IN gckOS Os,
+    IN gckRECORDER Recorder
+    );
+
+void
+gckRECORDER_AdvanceIndex(
+    gckRECORDER Recorder,
+    gctUINT64   CommitStamp
+    );
+
+void
+gckRECORDER_Record(
+    gckRECORDER Recorder,
+    gctUINT8_PTR CommandBuffer,
+    gctUINT32 CommandBytes,
+    gctUINT8_PTR ContextBuffer,
+    gctUINT32 ContextBytes
+    );
+
+void
+gckRECORDER_Dump(
+    gckRECORDER Recorder
+    );
+
+gceSTATUS
+gckRECORDER_UpdateMirror(
+    gckRECORDER Recorder,
+    gctUINT32 State,
+    gctUINT32 Data
+    );
+
+/******************************************************************************\
+****************************** gckCOMMAND Object *******************************
+\******************************************************************************/
+
+/* Construct a new gckCOMMAND object. */
+gceSTATUS
+gckCOMMAND_Construct(
+    IN gckKERNEL Kernel,
+    IN gceHW_FE_TYPE FeType,
+    OUT gckCOMMAND * Command
+    );
+
+/* Destroy an gckCOMMAND object. */
+gceSTATUS
+gckCOMMAND_Destroy(
+    IN gckCOMMAND Command
+    );
+
+/* Acquire command queue synchronization objects. */
+gceSTATUS
+gckCOMMAND_EnterCommit(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    );
+
+/* Release command queue synchronization objects. */
+gceSTATUS
+gckCOMMAND_ExitCommit(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    );
+
+/* Start the command queue. */
+gceSTATUS
+gckCOMMAND_Start(
+    IN gckCOMMAND Command
+    );
+
+/* Stop the command queue. */
+gceSTATUS
+gckCOMMAND_Stop(
+    IN gckCOMMAND Command
+    );
+
+/* Commit command buffers. */
+gceSTATUS
+gckCOMMAND_Commit(
+    IN gckCOMMAND Command,
+    IN gcsHAL_SUBCOMMIT * SubCommit,
+    IN gctUINT32 ProcessId,
+    IN gctBOOL Shared,
+    OUT gctUINT64_PTR CommitStamp,
+    INOUT gctBOOL *contextSwitched
+    );
+
+/* Reserve space in the command buffer. */
+gceSTATUS
+gckCOMMAND_Reserve(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequestedBytes,
+    OUT gctPOINTER * Buffer,
+    OUT gctUINT32 * BufferSize
+    );
+
+/*
+ * Execute reserved space in the command buffer.
+ * Wait link FE version.
+ */
+gceSTATUS
+gckCOMMAND_Execute(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequstedBytes
+    );
+
+/*
+ * Execute reserved space in the command buffer.
+ * Async FE version.
+ */
+gceSTATUS
+gckCOMMAND_ExecuteAsync(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequestedBytes
+    );
+
+/*
+ * Execute reserved space in the command buffer.
+ * MC-FE version.
+ */
+gceSTATUS
+gckCOMMAND_ExecuteMultiChannel(
+    IN gckCOMMAND Command,
+    IN gctBOOL Priority,
+    IN gctUINT32 ChannelId,
+    IN gctUINT32 RequstedBytes
+    );
+
+/* Stall the command queue. */
+gceSTATUS
+gckCOMMAND_Stall(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    );
+
+/* Attach user process. */
+gceSTATUS
+gckCOMMAND_Attach(
+    IN gckCOMMAND Command,
+    OUT gckCONTEXT * Context,
+    OUT gctSIZE_T * MaxState,
+    OUT gctUINT32 * NumStates,
+    IN gctUINT32 ProcessID
+    );
+
+/* Dump command buffer being executed by GPU. */
+gceSTATUS
+gckCOMMAND_DumpExecutingBuffer(
+    IN gckCOMMAND Command
+    );
+
+/* Detach user process. */
+gceSTATUS
+gckCOMMAND_Detach(
+    IN gckCOMMAND Command,
+    IN gckCONTEXT Context
+    );
+
+void
+gcsLIST_Init(
+    gcsLISTHEAD_PTR Node
+    );
+
+void
+gcsLIST_Add(
+    gcsLISTHEAD_PTR New,
+    gcsLISTHEAD_PTR Head
+    );
+
+void
+gcsLIST_AddTail(
+    gcsLISTHEAD_PTR New,
+    gcsLISTHEAD_PTR Head
+    );
+
+void
+gcsLIST_Del(
+    gcsLISTHEAD_PTR Node
+    );
+
+gctBOOL
+gcsLIST_Empty(
+    gcsLISTHEAD_PTR Head
+    );
+
+#define gcmkLIST_FOR_EACH(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define gcmkLIST_FOR_EACH_SAFE(pos, n, head) \
+    for (pos = (head)->next, n = pos->next; pos != (head); \
+        pos = n, n = pos->next)
+
+gceSTATUS
+gckFENCE_Create(
+    IN gckOS Os,
+    IN gckKERNEL Kernel,
+    OUT gckFENCE * Fence
+    );
+
+gceSTATUS
+gckFENCE_Destory(
+    IN gckOS Os,
+    OUT gckFENCE Fence
+    );
+
+gceSTATUS
+gckFENCE_Signal(
+    IN gckOS Os,
+    IN gckFENCE Fence
+    );
+
+gceSTATUS
+gckDEVICE_Construct(
+    IN gckOS Os,
+    OUT gckDEVICE * Device
+    );
+
+gceSTATUS
+gckDEVICE_AddCore(
+    IN gckDEVICE Device,
+    IN gceCORE Core,
+    IN gctUINT chipID,
+    IN gctPOINTER Context,
+    IN gckKERNEL * Kernel
+    );
+
+gceSTATUS
+gckDEVICE_Destroy(
+    IN gckOS Os,
+    IN gckDEVICE Device
+    );
+
+gceSTATUS
+gckDEVICE_Dispatch(
+    IN gckDEVICE Device,
+    IN gcsHAL_INTERFACE_PTR Interface
+    );
+
+#if VIVANTE_PROFILER
+gceSTATUS
+gckDEVICE_Profiler_Dispatch(
+    IN gckDEVICE Device,
+    IN gcsHAL_PROFILER_INTERFACE_PTR Interface
+    );
+#endif
+
+gceSTATUS
+gckDEVICE_GetMMU(
+    IN gckDEVICE Device,
+    IN gceHARDWARE_TYPE Type,
+    IN gckMMU *Mmu
+    );
+
+gceSTATUS
+gckDEVICE_SetMMU(
+    IN gckDEVICE Device,
+    IN gceHARDWARE_TYPE Type,
+    IN gckMMU Mmu
+    );
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_MapInTrustApplicaiton(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Logical,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 GPUAddress,
+    IN gctSIZE_T PageCount
+    );
+#endif
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckOS_OpenSecurityChannel(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctUINT32 *Channel
+    );
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+    IN gctUINT32 Channel
+    );
+
+gceSTATUS
+gckOS_CallSecurityService(
+    IN gctUINT32 Channel,
+    IN gcsTA_INTERFACE * Interface
+    );
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+    OUT gctUINT32 Channel
+    );
+
+gceSTATUS
+gckOS_AllocatePageArray(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    OUT gctPOINTER * PageArrayLogical,
+    OUT gctPHYS_ADDR * PageArrayPhysical
+    );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
@@ -0,0 +1,4509 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE            gcvZONE_COMMAND
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  _NewQueue
+**
+**  Allocate a new command queue.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object.
+**
+**      gctBOOL Stalled
+**          Indicate if hardware is stalled already.
+**
+**  OUTPUT:
+**
+**      gckCOMMAND Command
+**          gckCOMMAND object has been updated with a new command queue.
+*/
+static gceSTATUS
+_NewQueue(
+    IN OUT gckCOMMAND Command,
+    IN gctBOOL Stalled
+    )
+{
+    gceSTATUS status;
+    gctINT currentIndex, newIndex;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Switch to the next command buffer. */
+    currentIndex = Command->index;
+    newIndex     = (currentIndex + 1) % gcdCOMMAND_QUEUES;
+
+    /* Wait for availability. */
+    gcmkDUMP(Command->os, "#[kernel.waitsignal]");
+
+    gcmkONERROR(gckOS_WaitSignal(
+        Command->os,
+        Command->queues[newIndex].signal,
+        gcvFALSE,
+        gcvINFINITE
+        ));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    if (newIndex < currentIndex)
+    {
+        Command->wrapCount += 1;
+
+        gcmkTRACE_ZONE_N(
+            gcvLEVEL_INFO, gcvZONE_COMMAND,
+            2 * 4,
+            "%s(%d): queue array wrapped around.\n",
+            __FUNCTION__, __LINE__
+            );
+    }
+
+    gcmkTRACE_ZONE_N(
+        gcvLEVEL_INFO, gcvZONE_COMMAND,
+        3 * 4,
+        "%s(%d): total queue wrap arounds %d.\n",
+        __FUNCTION__, __LINE__, Command->wrapCount
+        );
+
+    gcmkTRACE_ZONE_N(
+        gcvLEVEL_INFO, gcvZONE_COMMAND,
+        3 * 4,
+        "%s(%d): switched to queue %d.\n",
+        __FUNCTION__, __LINE__, newIndex
+        );
+#endif
+
+    /* Update gckCOMMAND object with new command queue. */
+    Command->index    = newIndex;
+    Command->newQueue = gcvTRUE;
+    Command->videoMem = Command->queues[newIndex].videoMem;
+    Command->logical  = Command->queues[newIndex].logical;
+    Command->address  = Command->queues[newIndex].address;
+    Command->offset   = 0;
+
+    if (currentIndex != -1)
+    {
+        if (Stalled)
+        {
+            gckOS_Signal(
+                Command->os,
+                Command->queues[currentIndex].signal,
+                gcvTRUE
+                );
+        }
+        else
+        {
+            /* Mark the command queue as available. */
+            gcmkONERROR(gckEVENT_Signal(
+                Command->kernel->eventObj,
+                Command->queues[currentIndex].signal,
+                gcvKERNEL_COMMAND
+                ));
+        }
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("Command->index=%d", Command->index);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_IncrementCommitAtom(
+    IN gckCOMMAND Command,
+    IN gctBOOL Increment
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware;
+    gctINT32 atomValue;
+    gctBOOL powerAcquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Extract the gckHARDWARE and gckEVENT objects. */
+    hardware = Command->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Grab the power mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        Command->os, hardware->powerMutex, gcvINFINITE
+        ));
+    powerAcquired = gcvTRUE;
+
+    /* Increment the commit atom. */
+    if (Increment)
+    {
+        gcmkONERROR(gckOS_AtomIncrement(
+            Command->os, Command->atomCommit, &atomValue
+            ));
+    }
+    else
+    {
+        gcmkONERROR(gckOS_AtomDecrement(
+            Command->os, Command->atomCommit, &atomValue
+            ));
+    }
+
+    /* Release the power mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(
+        Command->os, hardware->powerMutex
+        ));
+    powerAcquired = gcvFALSE;
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (powerAcquired)
+    {
+        /* Release the power mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            Command->os, hardware->powerMutex
+            ));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_CheckFlushMMU(
+    IN gckCOMMAND Command,
+    IN gckHARDWARE Hardware
+    )
+{
+#if gcdSECURITY
+    return gcvSTATUS_OK;
+#else
+    gceSTATUS status;
+    gctUINT32 oldValue;
+    gctBOOL pause = gcvFALSE;
+
+    gctUINT8_PTR pointer;
+    gctUINT32 address;
+    gctUINT32 eventBytes;
+    gctUINT32 endBytes;
+    gctUINT32 bufferSize;
+    gctUINT32 executeBytes;
+
+    gckOS_AtomicExchange(Command->os,
+                         Hardware->pageTableDirty[gcvENGINE_RENDER],
+                         0,
+                         &oldValue);
+
+    if (oldValue)
+    {
+        /* Page Table is upated, flush mmu before commit. */
+        gctUINT32 flushBytes;
+
+        gcmkONERROR(gckHARDWARE_FlushMMU(
+            Hardware,
+            gcvNULL,
+            gcvINVALID_ADDRESS,
+            0,
+            &flushBytes
+            ));
+
+        gcmkONERROR(gckCOMMAND_Reserve(
+            Command,
+            flushBytes,
+            (gctPOINTER *)&pointer,
+            &bufferSize
+            ));
+
+        /* Pointer to reserved address. */
+        address = Command->address  + Command->offset;
+
+        /*
+         * subsequent 8 bytes are wait-link commands.
+         * Set more existed bytes for now.
+         */
+        gcmkONERROR(gckHARDWARE_FlushMMU(
+            Hardware,
+            pointer,
+            address,
+            (bufferSize - flushBytes),
+            &flushBytes
+            ));
+
+        gcmkONERROR(gckCOMMAND_Execute(Command, flushBytes));
+
+        if ((oldValue & gcvPAGE_TABLE_DIRTY_BIT_FE)
+          && (!Hardware->stallFEPrefetch)
+        )
+        {
+            pause = gcvTRUE;
+        }
+    }
+
+    if (pause)
+    {
+        /* Query size. */
+        gcmkONERROR(gckWLFE_Event(Hardware, gcvNULL, 0, gcvKERNEL_PIXEL, &eventBytes));
+        gcmkONERROR(gckWLFE_End(Hardware, gcvNULL, ~0U, &endBytes));
+
+        executeBytes = eventBytes + endBytes;
+
+        /* Reserve space. */
+        gcmkONERROR(gckCOMMAND_Reserve(
+            Command,
+            executeBytes,
+            (gctPOINTER *)&pointer,
+            &bufferSize
+            ));
+
+        /* Pointer to reserved address. */
+        address = Command->address  + Command->offset;
+
+        /* Append EVENT(29). */
+        gcmkONERROR(gckWLFE_Event(
+            Hardware,
+            pointer,
+            29,
+            gcvKERNEL_PIXEL,
+            &eventBytes
+            ));
+
+        /* Append END. */
+        pointer += eventBytes;
+        address += eventBytes;
+
+        gcmkONERROR(gckWLFE_End(Hardware, pointer, address, &endBytes));
+
+        gcmkONERROR(gckCOMMAND_Execute(Command, executeBytes));
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    return status;
+#endif
+}
+
+/* WaitLink FE only. */
+static gceSTATUS
+_DummyDraw(
+    IN gckCOMMAND Command
+    )
+{
+#if gcdSECURITY
+    return gcvSTATUS_OK;
+#else
+    gceSTATUS status;
+    gckHARDWARE hardware = Command->kernel->hardware;
+
+    gctUINT8_PTR pointer;
+    gctUINT32 bufferSize;
+
+    gctUINT32 dummyDrawBytes;
+    gceDUMMY_DRAW_TYPE dummyDrawType = gcvDUMMY_DRAW_INVALID;
+
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FE_NEED_DUMMYDRAW))
+    {
+        dummyDrawType = gcvDUMMY_DRAW_GC400;
+    }
+
+    if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_DEFER_FILL_FIX) &&
+        gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC))
+    {
+        dummyDrawType = gcvDUMMY_DRAW_V60;
+    }
+
+    if (dummyDrawType != gcvDUMMY_DRAW_INVALID)
+    {
+        gckHARDWARE_DummyDraw(hardware, gcvNULL, Command->queues[0].address, dummyDrawType, &dummyDrawBytes);
+
+        /* Reserve space. */
+        gcmkONERROR(gckCOMMAND_Reserve(
+            Command,
+            dummyDrawBytes,
+            (gctPOINTER *)&pointer,
+            &bufferSize
+            ));
+
+        gckHARDWARE_DummyDraw(hardware, pointer, Command->queues[0].address, dummyDrawType, &dummyDrawBytes);
+
+        gcmkONERROR(gckCOMMAND_Execute(Command, dummyDrawBytes));
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    return status;
+#endif
+}
+
+/*
+ * Wait pending semaphores.
+ *
+ * next == free: full, no more semaphores.
+ * (free + 1) = next: empty
+ */
+static gcmINLINE gceSTATUS
+_WaitPendingMcfeSema(
+    gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    const gctUINT count = gcmCOUNTOF(Command->pendingSema);
+    gctUINT32 nextFreePos;
+    gctUINT32 timeout = gcvINFINITE;
+
+    gcmkHEADER_ARG("freePendingPos=%u nextPendingPos=%u",
+                   Command->freePendingPos, Command->nextPendingPos);
+
+    nextFreePos = (Command->freePendingPos + 1) % count;
+
+    if (nextFreePos == Command->nextPendingPos)
+    {
+        /* No pendings. */
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+
+    while (nextFreePos != Command->nextPendingPos)
+    {
+        /* Timeout is infinite in the first to at least free one slot. */
+        status = gckOS_WaitSignal(Command->os,
+                                  Command->pendingSema[nextFreePos].signal,
+                                  gcvFALSE,
+                                  timeout);
+
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+            /* Timeout out is OK for later pendings. */
+            break;
+        }
+
+        gcmkONERROR(status);
+
+        /* Do not wait for the later slots. */
+        timeout = 0;
+
+        /* More free semaphores can be used. */
+        Command->freeSemaId = Command->pendingSema[nextFreePos].semaId;
+
+        /* Advance free pos. */
+        Command->freePendingPos = nextFreePos;
+        nextFreePos = (nextFreePos + 1) % count;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gctUINT32
+_GetFreeMcfeSemaNum(
+    gckCOMMAND Command
+    )
+{
+    gctUINT32 num = 0;
+
+    if (Command->nextSemaId <= Command->freeSemaId)
+    {
+        num = Command->freeSemaId - Command->nextSemaId;
+    }
+    else
+    {
+        num = Command->totalSemaId - Command->nextSemaId + Command->freeSemaId;
+    }
+
+    return num;
+}
+
+/*
+ * Get next semaphore id in semaphore ring.
+ *
+ * There are semaMinThreshhold semaphores are reserved for system operations,
+ * such as _SyncToSystemChannel etc.
+ * The rest semaphores are regular ones.
+ */
+static gcmINLINE gceSTATUS
+_GetNextMcfeSemaId(
+    gckCOMMAND Command,
+    gctBOOL regularSema,
+    gctUINT32 * SemaId
+    )
+{
+    gctUINT32 freeSemaNum = 0;
+
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /*
+     * See the comments in struct definition.
+     * wait when run out of semaphores.
+     */
+    freeSemaNum = _GetFreeMcfeSemaNum(Command);
+
+    if ((regularSema && (freeSemaNum <= Command->semaMinThreshhold)) ||
+        (!regularSema && (freeSemaNum == 0)))
+    {
+        gcmkONERROR(_WaitPendingMcfeSema(Command));
+    }
+
+    gcmkASSERT(Command->nextSemaId != Command->freeSemaId);
+
+    /* Output the semaphore ID. */
+    *SemaId = Command->nextSemaId;
+
+    /* Advance to next. */
+    if (++Command->nextSemaId == Command->totalSemaId)
+    {
+        Command->nextSemaId = 0;
+    }
+
+OnError:
+    return status;
+}
+
+/*
+ * Get next pending pos in pending semaphore tracking ring.
+ */
+static gcmINLINE gceSTATUS
+_GetNextPendingPos(
+    gckCOMMAND Command,
+    gctUINT32 * Pos
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /* Wait when out of pending ring. */
+    if (Command->nextPendingPos == Command->freePendingPos)
+    {
+        /* Run out of pending semaphore tracking ring. */
+        gcmkONERROR(_WaitPendingMcfeSema(Command));
+    }
+
+    gcmkASSERT(Command->nextPendingPos != Command->freePendingPos);
+
+    *Pos = Command->nextPendingPos;
+
+    /* Advance to next. */
+    if (++Command->nextPendingPos == gcmCOUNTOF(Command->pendingSema))
+    {
+        Command->nextPendingPos = 0;
+    }
+
+OnError:
+    return status;
+}
+
+/*
+ * Sync specific channels to system channel.
+ * Record semaphores to pendingSema structure.
+ * 'SyncChannel' is cleared upon function return.
+ */
+static gceSTATUS
+_SyncToSystemChannel(
+    gckCOMMAND Command,
+    gctUINT64 SyncChannel[2]
+    )
+{
+    gceSTATUS status;
+    gckKERNEL kernel = Command->kernel;
+    gckHARDWARE hardware = kernel->hardware;
+    gctUINT8 semaId[128];
+    gctUINT32 semaCount = 0;
+    gctUINT32 reqBytes = 0;
+    gctUINT32 bytes = 0;
+    gctUINT8_PTR buffer;
+    gctUINT32 i;
+    gctUINT32 pri;
+
+    /* Ignore system channel. */
+    SyncChannel[0] &= ~((gctUINT64)1ull);
+    SyncChannel[1] &= ~((gctUINT64)1ull);
+
+    if (!SyncChannel[0] && !SyncChannel[1])
+    {
+        return gcvSTATUS_OK;
+    }
+
+    /* Query SendSemaphore command size. */
+    gckMCFE_SendSemaphore(hardware, gcvNULL, 0, &reqBytes);
+
+    for (pri = 0; pri < 2; pri++)
+    {
+        for (i = 1; i < 64 && SyncChannel[pri]; i++)
+        {
+            gctUINT32 id;
+
+            if (!(SyncChannel[pri] & (1ull << i)))
+            {
+                continue;
+            }
+
+            /* Get a free semaphore id. */
+            gcmkONERROR(_GetNextMcfeSemaId(Command, gcvFALSE, &id));
+            semaId[semaCount++] = (gctUINT8)id;
+
+            gcmkONERROR(gckCOMMAND_Reserve(Command, reqBytes, (gctPOINTER *)&buffer, &bytes));
+
+            /* Send semaphore executed in specified channel. */
+            gckMCFE_SendSemaphore(hardware, buffer, id, &bytes);
+
+            gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(Command, pri, i, reqBytes));
+
+            /* Remove the sync'ed channel. */
+            SyncChannel[pri] &= ~(1ull << i);
+        }
+    }
+
+    if (semaCount > 0)
+    {
+        gctUINT32 pos = 0;
+        gckEVENT eventObj = kernel->eventObj;
+        gctUINT32 bufferLen = 0;
+
+        /* Query WaitSemaphore command size. */
+        gckMCFE_WaitSemaphore(hardware, gcvNULL, 0, &reqBytes);
+        reqBytes *= semaCount;
+
+        gcmkONERROR(gckCOMMAND_Reserve(Command, reqBytes, (gctPOINTER *)&buffer, &bufferLen));
+
+        for (i = 0; i < semaCount; i++)
+        {
+            bytes = bufferLen;
+
+            /* Wait semaphores executed in fixed system channel. */
+            gckMCFE_WaitSemaphore(hardware, buffer, semaId[i], &bytes);
+
+            buffer    += bytes;
+            bufferLen -= bytes;
+        }
+
+        gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(Command, 0, 0, reqBytes));
+
+        /* Now upload the pending semaphore tracking ring. */
+        gcmkONERROR(_GetNextPendingPos(Command, &pos));
+
+        /* Update latest pending semaphore id. */
+        Command->pendingSema[pos].semaId = (gctUINT32)semaId[semaCount - 1];
+
+        /* Send the signal by event. */
+        gcmkONERROR(gckEVENT_Signal(
+            eventObj,
+            Command->pendingSema[pos].signal,
+            gcvKERNEL_PIXEL
+            ));
+
+        gcmkONERROR(gckEVENT_Submit(
+            eventObj,
+            gcvTRUE,
+            gcvFALSE
+            ));
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gcmINLINE gceSTATUS
+_SyncFromSystemChannel(
+    gckCOMMAND Command,
+    gctBOOL Priority,
+    gctUINT32 ChannelId
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware = Command->kernel->hardware;
+    gctUINT32 reqBytes = 0;
+    gctUINT32 bytes = 0;
+    gctUINT8_PTR buffer;
+    gctUINT32 id;
+
+    if (!(Command->syncChannel[Priority ? 1 : 0] & (1ull << ChannelId)))
+    {
+        /* No need to sync. */
+        return gcvSTATUS_OK;
+    }
+
+    /* Get a semaphore. */
+    gcmkONERROR(_GetNextMcfeSemaId(Command, gcvFALSE, &id));
+
+    /* Send the semaphore in system channel. */
+    gckMCFE_SendSemaphore(hardware, gcvNULL, 0, &reqBytes);
+
+    gcmkONERROR(gckCOMMAND_Reserve(
+        Command,
+        reqBytes,
+        (gctPOINTER *)&buffer,
+        &bytes
+        ));
+
+    gckMCFE_SendSemaphore(hardware, buffer, id, &bytes);
+
+    gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(Command, gcvFALSE, 0, reqBytes));
+
+    /* Wait the semaphore in specific channel. */
+    gckMCFE_WaitSemaphore(hardware, gcvNULL, 0, &reqBytes);
+
+    gcmkONERROR(gckCOMMAND_Reserve(
+        Command,
+        reqBytes,
+        (gctPOINTER *)&buffer,
+        &bytes
+        ));
+
+    gckMCFE_WaitSemaphore(hardware, buffer, id, &bytes);
+
+    gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(
+        Command,
+        Priority,
+        ChannelId,
+        reqBytes
+        ));
+
+    /* Clear the sync flag. */
+    Command->syncChannel[Priority ? 1 : 0] &= ~(1ull << ChannelId);
+
+    /* Can not track the semaphore here. */
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_CheckFlushMcfeMMU(
+    IN gckCOMMAND Command,
+    IN gckHARDWARE Hardware
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 oldValue;
+    gctUINT32 reqBytes;
+    gctUINT32 bytes;
+    gctUINT8_PTR buffer;
+    gctUINT32 id = 0;
+
+    gckOS_AtomicExchange(Command->os,
+                         Hardware->pageTableDirty[gcvENGINE_RENDER],
+                         0,
+                         &oldValue);
+
+    if (!oldValue)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    /*
+     * We had sync'ed to system channel in every commit, see comments in Commit.
+     * It should not run into sync again here, unless there's some other place
+     * causes channels dirty. Let's check it here.
+     */
+    gcmkONERROR(_SyncToSystemChannel(Command, Command->dirtyChannel));
+
+    /* Query flush Mcfe MMU cache command bytes. */
+    gcmkONERROR(gckHARDWARE_FlushMcfeMMU(Hardware, gcvNULL, &reqBytes));
+
+    /* Query semaphore command bytes. */
+    gcmkONERROR(
+        gckMCFE_SendSemaphore(Hardware, gcvNULL, 0, &bytes));
+    reqBytes += bytes;
+
+    gcmkONERROR(
+        gckMCFE_WaitSemaphore(Hardware, gcvNULL, 0, &bytes));
+    reqBytes += bytes;
+
+    /* Get a semaphore. */
+    gcmkONERROR(_GetNextMcfeSemaId(Command, gcvFALSE, &id));
+
+    /* Request command buffer for system channel. */
+    gcmkONERROR(gckCOMMAND_Reserve(
+        Command,
+        reqBytes,
+        (gctPOINTER *)&buffer,
+        &bytes
+        ));
+
+    /* Do flush mmu. */
+    gckHARDWARE_FlushMcfeMMU(Hardware, buffer, &bytes);
+    buffer += bytes;
+
+    /* Send and wait semaphore in the system channel itself. */
+    gcmkONERROR(gckMCFE_SendSemaphore(Hardware, buffer, id, &bytes));
+    buffer += bytes;
+
+    gcmkONERROR(gckMCFE_WaitSemaphore(Hardware, buffer, id, &bytes));
+
+    /* Execute flush mmu and send semaphores. */
+    gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(Command, 0, 0, reqBytes));
+
+    /* Need sync from system channel. */
+    Command->syncChannel[0] = ~1ull;
+    Command->syncChannel[1] = ~1ull;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*
+ * Find sema id from the map.
+ * Returns semaphore Id, ie the array index of semaHandleMap.
+ * -1 if not found.
+ */
+static gcmINLINE gctINT32
+_FindSemaIdFromMap(
+    IN gckCOMMAND Command,
+    IN gctUINT32 SemaHandle
+    )
+{
+    gctUINT32 semaId = Command->nextSemaId;
+
+    do
+    {
+        /*
+         * Only need to check semaId between signaledId (inclusive) and
+         * nextSemaId (exclusive).
+         */
+        semaId = (semaId == 0) ? (Command->totalSemaId - 1) : (semaId - 1);
+
+        if (Command->semaHandleMap[semaId] == SemaHandle)
+        {
+            return (gctINT32)semaId;
+        }
+    }
+    while (semaId != Command->freeSemaId);
+
+    return -1;
+}
+
+/* Put together patch list handling variables. */
+typedef struct _gcsPATCH_LIST_VARIABLE
+{
+    /* gcvHAL_PATCH_VIDMEM_TIMESTAMP. */
+    gctUINT64 maxAsyncTimestamp;
+
+    /* gcvHAL_PATCH_MCFE_SEMAPHORE. */
+    gctBOOL semaUsed;
+}
+gcsPATCH_LIST_VARIABLE;
+
+/* Patch item handler typedef. */
+typedef gceSTATUS
+(* PATCH_ITEM_HANDLER)(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gctPOINTER Patch,
+    IN gcsPATCH_LIST_VARIABLE * PatchListVar
+    );
+
+static const gctUINT32 _PatchItemSize[] =
+{
+    0,
+    (gctUINT32)sizeof(gcsHAL_PATCH_VIDMEM_ADDRESS),
+    (gctUINT32)sizeof(gcsHAL_PATCH_MCFE_SEMAPHORE),
+    (gctUINT32)sizeof(gcsHAL_PATCH_VIDMEM_TIMESTAMP),
+};
+
+static gceSTATUS
+_HandleVidmemAddressPatch(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gctPOINTER Patch,
+    IN gcsPATCH_LIST_VARIABLE * PatchListVar
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsHAL_PATCH_VIDMEM_ADDRESS * patch = Patch;
+
+    gcmkHEADER_ARG("Command=%p location=0x%x node=0x%x offset=%x",
+                   Command, patch->location, patch->node, patch->offset);
+
+    (void)status;
+    (void)patch;
+
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_HandleMCFESemaphorePatch(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gctPOINTER Patch,
+    IN gcsPATCH_LIST_VARIABLE * PatchListVar
+    )
+{
+    gckHARDWARE hardware = Command->kernel->hardware;
+    gctINT32 index;
+    gctUINT32 semaId;
+    gceSTATUS status;
+    gctUINT32 bytes = 8;
+    gctUINT32 buffer[2];
+    gctUINT8_PTR location;
+    gcsHAL_PATCH_MCFE_SEMAPHORE * patch = (gcsHAL_PATCH_MCFE_SEMAPHORE *)Patch;
+
+    gcmkHEADER_ARG("Command=%p location=0x%x semaHandle=%d",
+                   Command, patch->location, patch->semaHandle);
+
+    index = _FindSemaIdFromMap(Command, patch->semaHandle);
+
+    if (index < 0)
+    {
+        status = _GetNextMcfeSemaId(Command, gcvTRUE, &semaId);
+
+        if (gcmIS_ERROR(status))
+        {
+            gcmkONERROR(_SyncToSystemChannel(Command, Command->dirtyChannel));
+            gcmkONERROR(_GetNextMcfeSemaId(Command, gcvTRUE, &semaId));
+        }
+
+        Command->semaHandleMap[semaId] = patch->semaHandle;
+    }
+    else
+    {
+        semaId = (gctUINT32)index;
+
+        /* One send must match one wait, will assign new id next time. */
+        Command->semaHandleMap[semaId] = 0;
+    }
+
+    if (patch->sendSema)
+    {
+        gcmkONERROR(gckMCFE_SendSemaphore(hardware, buffer, semaId, &bytes));
+    }
+    else
+    {
+        gcmkONERROR(gckMCFE_WaitSemaphore(hardware, buffer, semaId, &bytes));
+    }
+
+    gcmkASSERT(bytes == 8);
+
+    location = gcmUINT64_TO_PTR(CommandBuffer->logical + patch->location);
+
+    /* Patch the command buffer. */
+    gckOS_WriteMemory(Command->os, location, buffer[0]);
+    gckOS_WriteMemory(Command->os, location + 4, buffer[1]);
+
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_HandleTimestampPatch(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gctPOINTER Patch,
+    IN gcsPATCH_LIST_VARIABLE * PatchListVar
+    )
+{
+    gceSTATUS status;
+    gctUINT32 processID;
+    gckVIDMEM_NODE videoMem = gcvNULL;
+    gcsHAL_PATCH_VIDMEM_TIMESTAMP * patch = Patch;
+    gceENGINE engine = Command->feType == gcvHW_FE_ASYNC ? gcvENGINE_BLT
+                     : gcvENGINE_RENDER;
+
+    gcmkHEADER_ARG("Command=%p node=0x%x", Command, patch->handle);
+
+    /* Get the current process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    gcmkONERROR(
+        gckVIDMEM_HANDLE_Lookup(Command->kernel,
+                                processID,
+                                patch->handle,
+                                &videoMem));
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Reference(Command->kernel, videoMem));
+
+    /* Touch video memory node. */
+    gcmkVERIFY_OK(
+        gckVIDMEM_NODE_SetCommitStamp(Command->kernel,
+                                      engine,
+                                      videoMem,
+                                      Command->commitStamp));
+
+    if ((engine == gcvENGINE_RENDER) && Command->kernel->asyncCommand)
+    {
+        /* Find the latest timestamp of the nodes used in async FE. */
+        gctUINT64 stamp = 0;
+
+        /* Get stamp touched async command buffer. */
+        gcmkVERIFY_OK(
+            gckVIDMEM_NODE_GetCommitStamp(Command->kernel,
+                                          gcvENGINE_BLT,
+                                          videoMem,
+                                          &stamp));
+
+        /* Find latest one. */
+        if (PatchListVar->maxAsyncTimestamp < stamp)
+        {
+            PatchListVar->maxAsyncTimestamp = stamp;
+        }
+    }
+
+OnError:
+    if (videoMem)
+    {
+        gckVIDMEM_NODE_Dereference(Command->kernel, videoMem);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_HandlePatchListSingle(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gcsHAL_PATCH_LIST * PatchList,
+    IN gctBOOL NeedCopy,
+    IN gcsPATCH_LIST_VARIABLE * PatchListVar
+    )
+{
+    gceSTATUS status;
+    /* 256 bytes for storage. */
+    gctUINT64 storage[32];
+    gctPOINTER kArray = gcvNULL;
+    gctPOINTER userPtr = gcvNULL;
+    gctUINT32 index = 0;
+    gctUINT32 count = 0;
+    gctUINT32 itemSize = 0;
+    gctUINT32 batchCount = 0;
+
+    static const PATCH_ITEM_HANDLER patchHandler[] =
+    {
+        gcvNULL,
+        _HandleVidmemAddressPatch,
+        _HandleMCFESemaphorePatch,
+        _HandleTimestampPatch,
+    };
+    PATCH_ITEM_HANDLER handler;
+
+    gcmkHEADER_ARG("Command=%p CommandBuffer=%p PatchList=%p type=%d",
+                   Command, CommandBuffer, PatchList, PatchList->type);
+
+    if (PatchList->type >= gcmCOUNTOF(_PatchItemSize) || PatchList->type >= gcmCOUNTOF(patchHandler))
+    {
+        /* Exceeds buffer max size. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    itemSize = _PatchItemSize[PatchList->type];
+
+    batchCount = (gctUINT32)(sizeof(storage) / itemSize);
+
+    handler = patchHandler[PatchList->type];
+
+    while (index < PatchList->count)
+    {
+        gctUINT i;
+        gctUINT8_PTR ptr;
+
+        /* Determine batch count, don't handle too many in one batch. */
+        count = PatchList->count - index;
+
+        if (count > batchCount)
+        {
+            count = batchCount;
+        }
+
+        userPtr = gcmUINT64_TO_PTR(PatchList->patchArray + itemSize * index);
+
+        /* Copy/map a patch array batch from user. */
+        if (NeedCopy)
+        {
+            kArray = storage;
+
+            status = gckOS_CopyFromUserData(
+                Command->os,
+                kArray,
+                userPtr,
+                itemSize * count
+                );
+        }
+        else
+        {
+            status = gckOS_MapUserPointer(
+                Command->os,
+                userPtr,
+                itemSize * count,
+                (gctPOINTER *)&kArray
+                );
+        }
+
+        if (gcmIS_ERROR(status))
+        {
+            userPtr = gcvNULL;
+            gcmkONERROR(status);
+        }
+
+        /* Advance to next batch. */
+        index += count;
+
+        ptr = (gctUINT8_PTR)kArray;
+
+        for (i = 0; i < count; i++)
+        {
+            /* Call handler. */
+            gcmkONERROR(
+                handler(Command, CommandBuffer, ptr, PatchListVar));
+
+            /* Advance to next patch. */
+            ptr += itemSize;
+        }
+
+        /* Unmap user pointer if mapped. */
+        if (!NeedCopy)
+        {
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Command->os,
+                userPtr,
+                itemSize * count,
+                kArray
+                ));
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (!NeedCopy && userPtr)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+            Command->os,
+            userPtr,
+            itemSize * count,
+            kArray
+            ));
+
+        userPtr = gcvNULL;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_HandlePatchList(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    OUT gcsPATCH_LIST_VARIABLE * PatchListVar
+    )
+{
+    gceSTATUS status;
+    gctBOOL needCopy = gcvFALSE;
+    gcsHAL_PATCH_LIST storage;
+    gcsHAL_PATCH_LIST * kPatchList = gcvNULL;
+    gctPOINTER userPtr = gcmUINT64_TO_PTR(CommandBuffer->patchHead);
+
+    gcmkHEADER_ARG("Command=%p CommandBuffer=%p", Command, CommandBuffer);
+
+    /* Check wehther we need to copy the structures or not. */
+    gcmkONERROR(gckOS_QueryNeedCopy(Command->os, 0, &needCopy));
+
+    while (userPtr)
+    {
+        gctUINT64 next;
+
+        /* Copy/map a patch from user. */
+        if (needCopy)
+        {
+            kPatchList = &storage;
+
+            status = gckOS_CopyFromUserData(
+                Command->os,
+                kPatchList,
+                userPtr,
+                sizeof(gcsHAL_PATCH_LIST)
+                );
+        }
+        else
+        {
+            status = gckOS_MapUserPointer(
+                Command->os,
+                userPtr,
+                sizeof(gcsHAL_PATCH_LIST),
+                (gctPOINTER *)&kPatchList
+                );
+        }
+
+        if (gcmIS_ERROR(status))
+        {
+            userPtr = gcvNULL;
+            gcmkONERROR(status);
+        }
+
+        /* Do handle patch. */
+        gcmkASSERT(kPatchList->type < gcvHAL_PATCH_TYPE_COUNT);
+
+        gcmkONERROR(
+            _HandlePatchListSingle(Command,
+                                   CommandBuffer,
+                                   kPatchList,
+                                   needCopy,
+                                   PatchListVar));
+
+        next = kPatchList->next;
+
+        /* Unmap user pointer if mapped. */
+        if (!needCopy)
+        {
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Command->os,
+                userPtr,
+                sizeof(gcsHAL_PATCH_LIST),
+                kPatchList
+                ));
+        }
+
+        /* Advance to next patch from user. */
+        userPtr = gcmUINT64_TO_PTR(next);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (!needCopy && userPtr)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+            Command->os,
+            userPtr,
+            sizeof(gcsHAL_PATCH_LIST),
+            kPatchList
+            ));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_WaitForAsyncCommandStamp(
+    IN gckCOMMAND Command,
+    IN gctUINT64 Stamp
+    )
+{
+    gctUINT32 bytes;
+    gceSTATUS status;
+    gctUINT32 fenceAddress;
+    gctUINT32 bufferSize;
+    gctPOINTER pointer;
+    gckCOMMAND asyncCommand = Command->kernel->asyncCommand;
+
+    gcmkHEADER_ARG("Stamp = 0x%llx", Stamp);
+
+    if (*(gctUINT64 *)asyncCommand->fence->logical >= Stamp)
+    {
+        /* Already satisfied, skip. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    fenceAddress = asyncCommand->fence->address;
+
+    gcmkONERROR(gckHARDWARE_WaitFence(
+        Command->kernel->hardware,
+        gcvNULL,
+        Stamp,
+        fenceAddress,
+        &bytes
+        ));
+
+    gcmkONERROR(gckCOMMAND_Reserve(
+        Command,
+        bytes,
+        &pointer,
+        &bufferSize
+        ));
+
+    gcmkONERROR(gckHARDWARE_WaitFence(
+        Command->kernel->hardware,
+        pointer,
+        Stamp,
+        fenceAddress,
+        &bytes
+        ));
+
+    gcmkONERROR(gckCOMMAND_Execute(Command, bytes));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/******************************************************************************\
+****************************** gckCOMMAND API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Construct
+**
+**  Construct a new gckCOMMAND object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      gckCOMMAND * Command
+**          Pointer to a variable that will hold the pointer to the gckCOMMAND
+**          object.
+*/
+gceSTATUS
+gckCOMMAND_Construct(
+    IN gckKERNEL Kernel,
+    IN gceHW_FE_TYPE FeType,
+    OUT gckCOMMAND * Command
+    )
+{
+    gckOS os;
+    gckCOMMAND command = gcvNULL;
+    gceSTATUS status;
+    gctINT i;
+    gctPOINTER pointer = gcvNULL;
+    gctSIZE_T pageSize;
+
+    gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Command != gcvNULL);
+
+    /* Extract the gckOS object. */
+    os = Kernel->os;
+
+    /* Allocate the gckCOMMAND structure. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckCOMMAND), &pointer));
+    command = pointer;
+
+    /* Reset the entire object. */
+    gcmkONERROR(gckOS_ZeroMemory(command, gcmSIZEOF(struct _gckCOMMAND)));
+
+    /* Initialize the gckCOMMAND object.*/
+    command->object.type    = gcvOBJ_COMMAND;
+    command->kernel         = Kernel;
+    command->os             = os;
+
+    command->feType         = FeType;
+
+    /* Get the command buffer requirements. */
+    gcmkONERROR(gckHARDWARE_QueryCommandBuffer(
+        Kernel->hardware,
+        gcvENGINE_RENDER,
+        &command->alignment,
+        gcvNULL,
+        gcvNULL
+        ));
+
+    /* Create the command queue mutex. */
+    gcmkONERROR(gckOS_CreateMutex(os, &command->mutexQueue));
+
+    /* Create the context switching mutex. */
+    gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContext));
+
+    /* Create the context switching mutex. */
+    gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContextSeq));
+
+    /* Create the power management semaphore. */
+    gcmkONERROR(gckOS_CreateSemaphore(os, &command->powerSemaphore));
+
+    /* Create the commit atom. */
+    gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit));
+
+    /* Get the page size from teh OS. */
+    gcmkONERROR(gckOS_GetPageSize(os, &pageSize));
+
+    gcmkSAFECASTSIZET(command->pageSize, pageSize);
+
+    /* Get process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&command->kernelProcessID));
+
+    /* Set hardware to pipe 0. */
+    command->pipeSelect = gcvPIPE_INVALID;
+
+    /* Pre-allocate the command queues. */
+    for (i = 0; i < gcdCOMMAND_QUEUES; ++i)
+    {
+#if !gcdCAPTURE_ONLY_MODE
+        gcePOOL pool = gcvPOOL_DEFAULT;
+#else
+        gcePOOL pool = gcvPOOL_VIRTUAL;
+#endif
+
+        gctSIZE_T size = pageSize;
+        gckVIDMEM_NODE videoMem = gcvNULL;
+        gctUINT32 allocFlag = 0;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+        allocFlag = gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+        /* Allocate video memory node for command buffers. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+            Kernel,
+            64,
+            gcvVIDMEM_TYPE_COMMAND,
+            allocFlag,
+            &size,
+            &pool,
+            &videoMem
+            ));
+
+        command->queues[i].videoMem = videoMem;
+
+        /* Lock for GPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_Lock(
+            Kernel,
+            videoMem,
+            &command->queues[i].address
+            ));
+
+        /* Lock for kernel side CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            Kernel,
+            videoMem,
+            gcvFALSE,
+            gcvFALSE,
+            &command->queues[i].logical
+            ));
+
+        gcmkONERROR(gckOS_CreateSignal(
+            os, gcvFALSE, &command->queues[i].signal
+            ));
+
+        gcmkONERROR(gckOS_Signal(
+            os, command->queues[i].signal, gcvTRUE
+            ));
+    }
+
+#if gcdRECORD_COMMAND
+    gcmkONERROR(gckRECORDER_Construct(os, Kernel->hardware, &command->recorder));
+#endif
+
+    gcmkONERROR(gckFENCE_Create(
+        os, Kernel, &command->fence
+        ));
+
+    /* No command queue in use yet. */
+    command->index    = -1;
+    command->logical  = gcvNULL;
+    command->newQueue = gcvFALSE;
+
+    /* Query mcfe semaphore count. */
+    if (FeType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        command->totalSemaId = 128;
+
+        /* Empty sema id ring. */
+        command->nextSemaId = 0;
+        command->freeSemaId = command->totalSemaId - 1;
+
+        command->semaMinThreshhold = 16;
+
+        /* Create signals. */
+        for (i = 0; i < (gctINT)gcmCOUNTOF(command->pendingSema); i++)
+        {
+            gcmkONERROR(gckOS_CreateSignal(
+                os,
+                gcvFALSE,
+                &command->pendingSema[i].signal
+                ));
+        }
+
+        /* Empty pending sema tracking ring. */
+        command->nextPendingPos = 0;
+        command->freePendingPos = gcmCOUNTOF(command->pendingSema) - 1;
+
+        /* Allocate sema handle mapping. */
+        gcmkONERROR(gckOS_Allocate(
+            os,
+            command->totalSemaId * sizeof(gctUINT32),
+            &pointer
+            ));
+
+        command->semaHandleMap = (gctUINT32 *)pointer;
+
+        gcmkVERIFY_OK(gckOS_ZeroMemory(
+            command->semaHandleMap,
+            command->totalSemaId * sizeof(gctUINT32)
+            ));
+    }
+
+    /* Command is not yet running. */
+    command->running = gcvFALSE;
+
+    /* Command queue is idle. */
+    command->idle = gcvTRUE;
+
+    /* Commit stamp start from 1. */
+    command->commitStamp = 1;
+
+    command->dummyDraw = gcvTRUE;
+
+    /* Return pointer to the gckCOMMAND object. */
+    *Command = command;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Command=0x%x", *Command);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (command != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckCOMMAND_Destroy(command));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Destroy
+**
+**  Destroy an gckCOMMAND object.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Destroy(
+    IN gckCOMMAND Command
+    )
+{
+    gctINT i;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Stop the command queue. */
+    gcmkVERIFY_OK(gckCOMMAND_Stop(Command));
+
+    for (i = 0; i < gcdCOMMAND_QUEUES; ++i)
+    {
+        if (Command->queues[i].signal)
+        {
+            gcmkVERIFY_OK(gckOS_DestroySignal(
+                Command->os, Command->queues[i].signal
+                ));
+        }
+
+        if (Command->queues[i].logical)
+        {
+            gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                Command->kernel,
+                Command->queues[i].videoMem,
+                0,
+                gcvFALSE,
+                gcvFALSE
+                ));
+
+            gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+                Command->kernel,
+                Command->queues[i].videoMem,
+                0,
+                gcvNULL
+                ));
+
+            gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                Command->kernel,
+                Command->queues[i].videoMem
+                ));
+
+            Command->queues[i].videoMem = gcvNULL;
+            Command->queues[i].logical  = gcvNULL;
+        }
+    }
+
+    if (Command->mutexContext)
+    {
+        /* Delete the context switching mutex. */
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext));
+    }
+
+    if (Command->mutexContextSeq != gcvNULL)
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContextSeq));
+
+    if (Command->mutexQueue)
+    {
+        /* Delete the command queue mutex. */
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue));
+    }
+
+    if (Command->powerSemaphore)
+    {
+        /* Destroy the power management semaphore. */
+        gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore));
+    }
+
+    if (Command->atomCommit)
+    {
+        /* Destroy the commit atom. */
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit));
+    }
+
+#if gcdRECORD_COMMAND
+    gckRECORDER_Destory(Command->os, Command->recorder);
+#endif
+
+    if (Command->stateMap)
+    {
+        gcmkOS_SAFE_FREE(Command->os, Command->stateMap);
+    }
+
+    if (Command->semaHandleMap)
+    {
+        gcmkOS_SAFE_FREE(Command->os, Command->semaHandleMap);
+    }
+
+    if (Command->fence)
+    {
+        gcmkVERIFY_OK(gckFENCE_Destory(Command->os, Command->fence));
+    }
+
+    /* Mark object as unknown. */
+    Command->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckCOMMAND object. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, Command));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_EnterCommit
+**
+**  Acquire command queue synchronization objects.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object to destroy.
+**
+**      gctBOOL FromPower
+**          Determines whether the call originates from inside the power
+**          management or not.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_EnterCommit(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware;
+    gctBOOL atomIncremented = gcvFALSE;
+    gctBOOL semaAcquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Extract the gckHARDWARE and gckEVENT objects. */
+    hardware = Command->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    if (!FromPower)
+    {
+        /* Increment COMMIT atom to let power management know that a commit is
+        ** in progress. */
+        gcmkONERROR(_IncrementCommitAtom(Command, gcvTRUE));
+        atomIncremented = gcvTRUE;
+
+        /* Notify the system the GPU has a commit. */
+        gcmkONERROR(gckOS_Broadcast(Command->os,
+                                    hardware,
+                                    gcvBROADCAST_GPU_COMMIT));
+
+        /* Acquire the power management semaphore. */
+        gcmkONERROR(gckOS_AcquireSemaphore(Command->os,
+                                           Command->powerSemaphore));
+        semaAcquired = gcvTRUE;
+    }
+
+    /* Grab the conmmand queue mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Command->os,
+                                   Command->mutexQueue,
+                                   gcvINFINITE));
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (semaAcquired)
+    {
+        /* Release the power management semaphore. */
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+            Command->os, Command->powerSemaphore
+            ));
+    }
+
+    if (atomIncremented)
+    {
+        /* Decrement the commit atom. */
+        gcmkVERIFY_OK(_IncrementCommitAtom(
+            Command, gcvFALSE
+            ));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_ExitCommit
+**
+**  Release command queue synchronization objects.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object to destroy.
+**
+**      gctBOOL FromPower
+**          Determines whether the call originates from inside the power
+**          management or not.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_ExitCommit(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Release the power mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue));
+
+    if (!FromPower)
+    {
+        /* Release the power management semaphore. */
+        gcmkONERROR(gckOS_ReleaseSemaphore(Command->os,
+                                           Command->powerSemaphore));
+
+        /* Decrement the commit atom. */
+        gcmkONERROR(_IncrementCommitAtom(Command, gcvFALSE));
+    }
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_StartWaitLinkFE(
+    IN gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware;
+    gctUINT32 waitOffset = 0;
+    gctUINT32 waitLinkBytes;
+    gctPOINTER logical;
+    gctUINT32 address;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->running)
+    {
+        /* Command queue already running. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /* Extract the gckHARDWARE object. */
+    hardware = Command->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Query the size of WAIT/LINK command sequence. */
+    gcmkONERROR(gckWLFE_WaitLink(
+        hardware,
+        gcvNULL,
+        ~0U,
+        Command->offset,
+        &waitLinkBytes,
+        gcvNULL,
+        gcvNULL
+        ));
+
+    if ((Command->pageSize - Command->offset < waitLinkBytes)
+     || (Command->logical == gcvNULL)
+     )
+    {
+        /* Start at beginning of a new queue. */
+        gcmkONERROR(_NewQueue(Command, gcvTRUE));
+    }
+
+    logical  = (gctUINT8_PTR) Command->logical + Command->offset;
+    address  =                Command->address + Command->offset;
+
+    /* Append WAIT/LINK. */
+    gcmkONERROR(gckWLFE_WaitLink(
+        hardware,
+        logical,
+        address,
+        0,
+        &waitLinkBytes,
+        &waitOffset,
+        &Command->waitPos.size
+        ));
+
+    /* Update wait command position. */
+    Command->waitPos.videoMem = Command->videoMem;
+    Command->waitPos.offset   = Command->offset + waitOffset;
+    Command->waitPos.logical  = (gctUINT8_PTR) logical  + waitOffset;
+    Command->waitPos.address  =                address  + waitOffset;
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Command->kernel,
+        Command->videoMem,
+        Command->offset,
+        logical,
+        waitLinkBytes
+        ));
+
+    /* Adjust offset. */
+    Command->offset   += waitLinkBytes;
+    Command->newQueue = gcvFALSE;
+
+    gcmkDUMP(Command->os, "#[wait-link: fe start]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        logical,
+        address,
+        waitLinkBytes
+        );
+
+#if gcdSECURITY
+    /* Start FE by calling security service. */
+    gckKERNEL_SecurityStartCommand(
+        Command->kernel
+        );
+#else
+
+#if !gcdCAPTURE_ONLY_MODE
+    /* Enable command processor. */
+    gcmkONERROR(gckWLFE_Execute(
+        hardware,
+        address,
+        waitLinkBytes
+        ));
+#endif
+
+#endif
+
+    /* Command queue is running. */
+    Command->running = gcvTRUE;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_StartAsyncFE(
+    IN gckCOMMAND Command
+    )
+{
+    if ((Command->pageSize <= Command->offset) ||
+        (Command->logical == gcvNULL))
+    {
+        /* Start at beginning of a new queue. */
+        gcmkVERIFY_OK(_NewQueue(Command, gcvTRUE));
+    }
+
+    /* Command queue is running. */
+    Command->running = gcvTRUE;
+
+    /* Nothing to do. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_StartMCFE(
+    IN gckCOMMAND Command
+    )
+{
+    if ((Command->pageSize <= Command->offset) ||
+        (Command->logical == gcvNULL))
+    {
+        /* Start at beginning of a new queue. */
+        gcmkVERIFY_OK(_NewQueue(Command, gcvTRUE));
+    }
+
+    /* Command queue is running. */
+    Command->running = gcvTRUE;
+
+    /* Nothing to do. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Start
+**
+**  Start up the command queue.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object to start.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Start(
+    IN gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    if (Command->feType == gcvHW_FE_WAIT_LINK)
+    {
+        gcmkONERROR(_StartWaitLinkFE(Command));
+    }
+    else if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        gcmkONERROR(_StartMCFE(Command));
+    }
+    else
+    {
+        gcmkONERROR(_StartAsyncFE(Command));
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+
+}
+
+static gceSTATUS
+_StopWaitLinkFE(
+    IN gckCOMMAND Command
+    )
+{
+    gckHARDWARE hardware;
+    gceSTATUS status;
+    gctUINT32 idle;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Extract the gckHARDWARE object. */
+    hardware = Command->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Replace last WAIT with END. */
+    gcmkONERROR(gckWLFE_End(
+        hardware,
+        Command->waitPos.logical,
+        Command->waitPos.address,
+        &Command->waitPos.size
+        ));
+
+    gcmkDUMP(Command->os, "#[end: fe stop]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        Command->waitPos.logical,
+        Command->waitPos.address,
+        Command->waitPos.size
+        );
+
+#if gcdSECURITY
+    gcmkONERROR(gckKERNEL_SecurityExecute(
+        Command->kernel, Command->waitPos.logical, 8
+        ));
+#endif
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(Command->kernel->hardware,
+                                            Command->logical,
+                                            Command->offset));
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Command->kernel,
+        Command->waitPos.videoMem,
+        Command->waitPos.offset,
+        Command->waitPos.logical,
+        Command->waitPos.size
+        ));
+
+    /* Wait for idle. */
+    gcmkONERROR(gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle));
+
+    /* Command queue is no longer running. */
+    Command->running = gcvFALSE;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_StopAsyncFE(
+    IN gckCOMMAND Command
+    )
+{
+    gckHARDWARE hardware;
+    gceSTATUS status;
+    gctUINT32 idle;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    hardware = Command->kernel->hardware;
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(hardware,
+                                            Command->logical,
+                                            Command->offset));
+
+    /* Wait for idle. */
+    gcmkONERROR(gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle));
+
+    /* Command queue is no longer running. */
+    Command->running = gcvFALSE;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_StopMCFE(
+    IN gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    hardware = Command->kernel->hardware;
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(hardware,
+                                            Command->logical,
+                                            Command->offset));
+
+    /* Command queue is no longer running. */
+    Command->running = gcvFALSE;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Stop
+**
+**  Stop the command queue.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object to stop.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Stop(
+    IN gckCOMMAND Command
+    )
+{
+    if (!Command->running)
+    {
+        /* Command queue is not running. */
+        return gcvSTATUS_OK;
+    }
+
+    if (Command->feType == gcvHW_FE_WAIT_LINK)
+    {
+        return _StopWaitLinkFE(Command);
+    }
+    else if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        return _StopMCFE(Command);
+    }
+    else
+    {
+        return _StopAsyncFE(Command);
+    }
+}
+
+static gceSTATUS
+_CommitWaitLinkOnce(
+    IN gckCOMMAND Command,
+    IN gckCONTEXT Context,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer,
+    IN gcsSTATE_DELTA_PTR StateDelta,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL Shared,
+    INOUT gctBOOL *contextSwitched
+    )
+{
+    gceSTATUS status;
+    gctBOOL commitEntered = gcvFALSE;
+    gctBOOL contextAcquired = gcvFALSE;
+    gckHARDWARE hardware;
+    gcsPATCH_LIST_VARIABLE patchListVar = {0, 0};
+
+    gcsCONTEXT_PTR contextBuffer;
+    gctUINT8_PTR commandBufferLogical = gcvNULL;
+    gctUINT32 commandBufferAddress = 0;
+    gckVIDMEM_NODE commandBufferVideoMem = gcvNULL;
+    gctUINT8_PTR commandBufferTail = gcvNULL;
+    gctUINT commandBufferSize;
+    gctUINT32 linkBytes;
+    gctSIZE_T bytes;
+    gctUINT32 offset;
+    gctPOINTER entryLogical;
+    gctUINT32 entryAddress;
+    gctUINT32 entryBytes;
+    gctUINT32 exitAddress;
+    gctUINT32 exitBytes;
+    gctPOINTER waitLinkLogical;
+    gctUINT32 waitLinkAddress;
+    gctUINT32 waitLinkBytes;
+    gctUINT32 waitOffset;
+    gctUINT32 waitSize;
+
+#if gcdCAPTURE_ONLY_MODE
+    gctINT i;
+#endif
+
+#ifdef __QNXNTO__
+    gctPOINTER userCommandBufferLogical       = gcvNULL;
+    gctBOOL    userCommandBufferLogicalMapped = gcvFALSE;
+#endif
+
+#if gcdDUMP_IN_KERNEL
+    gctPOINTER contextDumpLogical = gcvNULL;
+# endif
+    gctUINT32 exitLinkLow = 0, exitLinkHigh = 0;
+    gctUINT32 entryLinkLow = 0, entryLinkHigh = 0;
+    gctUINT32 commandLinkLow = 0, commandLinkHigh = 0;
+
+    gcmkHEADER_ARG("Command=%p CommandBuffer=%p ProcessID=%d",
+        Command, CommandBuffer, ProcessID
+        );
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    gcmkASSERT(Command->feType == gcvHW_FE_WAIT_LINK);
+
+    /* Acquire the command queue. */
+    gcmkONERROR(gckCOMMAND_EnterCommit(Command, gcvFALSE));
+    commitEntered = gcvTRUE;
+
+    /* Acquire the context switching mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        Command->os, Command->mutexContext, gcvINFINITE
+        ));
+    contextAcquired = gcvTRUE;
+
+    /* Extract the gckHARDWARE and gckEVENT objects. */
+    hardware = Command->kernel->hardware;
+
+
+    gcmkONERROR(
+        _HandlePatchList(Command, CommandBuffer, &patchListVar));
+
+    /* Query the size of LINK command. */
+    gcmkONERROR(gckWLFE_Link(
+        hardware, gcvNULL, 0, 0, &linkBytes, gcvNULL, gcvNULL
+        ));
+
+    /* Compute the command buffer entry and the size. */
+    commandBufferLogical
+        = (gctUINT8_PTR) gcmUINT64_TO_PTR(CommandBuffer->logical)
+        +                CommandBuffer->startOffset;
+
+    commandBufferAddress = CommandBuffer->address
+                         + CommandBuffer->startOffset;
+
+#ifdef __QNXNTO__
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+        Command->kernel,
+        ProcessID,
+        CommandBuffer->videoMemNode,
+        &commandBufferVideoMem
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        Command->kernel,
+        commandBufferVideoMem,
+        gcvFALSE,
+        gcvFALSE,
+        &userCommandBufferLogical
+        ));
+
+    commandBufferLogical = (gctUINT8_PTR)userCommandBufferLogical + CommandBuffer->startOffset;
+    userCommandBufferLogicalMapped =gcvTRUE;
+#endif
+
+    commandBufferSize = CommandBuffer->size;
+
+    gcmkONERROR(_CheckFlushMMU(Command, hardware));
+
+    if (Command->dummyDraw == gcvTRUE &&
+        Context != gcvNULL)
+    {
+        Command->dummyDraw = gcvFALSE;
+        gcmkONERROR(_DummyDraw(Command));
+    }
+
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FENCE_64BIT) &&
+        Command->kernel->asyncCommand &&
+        patchListVar.maxAsyncTimestamp != 0)
+    {
+        gcmkONERROR(_WaitForAsyncCommandStamp(
+            Command,
+            patchListVar.maxAsyncTimestamp
+            ));
+    }
+
+    /* Get the current offset. */
+    offset = Command->offset;
+
+    /* Compute number of bytes left in current kernel command queue. */
+    bytes = Command->pageSize - offset;
+
+    /* Query the size of WAIT/LINK command sequence. */
+    gcmkONERROR(gckWLFE_WaitLink(
+        hardware,
+        gcvNULL,
+        ~0U,
+        offset,
+        &waitLinkBytes,
+        gcvNULL,
+        gcvNULL
+        ));
+
+    /* Is there enough space in the current command queue? */
+    if (bytes < waitLinkBytes)
+    {
+        /* No, create a new one. */
+        gcmkONERROR(_NewQueue(Command, gcvFALSE));
+
+        /* Get the new current offset. */
+        offset = Command->offset;
+
+        /* Recompute the number of bytes in the new kernel command queue. */
+        bytes = Command->pageSize - offset;
+        gcmkASSERT(bytes >= waitLinkBytes);
+    }
+
+    /* Compute the location if WAIT/LINK command sequence. */
+    waitLinkLogical  = (gctUINT8_PTR) Command->logical  + offset;
+    waitLinkAddress  =                Command->address  + offset;
+
+    /* Context switch required? */
+    if (Context == gcvNULL)
+    {
+        /* See if we have to switch pipes for the command buffer. */
+        if (CommandBuffer->entryPipe == (gctUINT32)(Command->pipeSelect))
+        {
+            /* Skip reserved head bytes. */
+            offset = CommandBuffer->reservedHead;
+        }
+        else
+        {
+            gctUINT32 pipeBytes = CommandBuffer->reservedHead;
+
+            /* The current hardware and the entry command buffer pipes
+            ** are different, switch to the correct pipe. */
+            gcmkONERROR(gckHARDWARE_PipeSelect(
+                Command->kernel->hardware,
+                commandBufferLogical,
+                CommandBuffer->entryPipe,
+                &pipeBytes
+                ));
+
+            /* Do not skip pipe switching sequence. */
+            offset = 0;
+
+            /* Reserved bytes in userspace must be exact for a pipeSelect. */
+            gcmkASSERT(pipeBytes == CommandBuffer->reservedHead);
+        }
+
+        /* Compute the entry. */
+        entryLogical  =                commandBufferLogical  + offset;
+        entryAddress  =                commandBufferAddress  + offset;
+        entryBytes    =                commandBufferSize     - offset;
+
+        Command->currContext = gcvNULL;
+    }
+#if gcdDEBUG_OPTION && gcdDEBUG_FORCE_CONTEXT_UPDATE
+    else if (1)
+#else
+    else if (Command->currContext != Context)
+#endif
+    {
+        /* Get the current context buffer. */
+        contextBuffer = Context->buffer;
+
+        /* Yes, merge in the deltas. */
+        gcmkONERROR(gckCONTEXT_Update(Context, ProcessID, StateDelta));
+
+        /***************************************************************
+        ** SWITCHING CONTEXT.
+        */
+
+        /* Determine context buffer entry offset. */
+        offset = (Command->pipeSelect == gcvPIPE_3D)
+
+            /* Skip pipe switching sequence. */
+            ? Context->entryOffset3D + Context->pipeSelectBytes
+
+            /* Do not skip pipe switching sequence. */
+            : Context->entryOffset3D;
+
+        /* Compute the entry. */
+        entryLogical  = (gctUINT8_PTR) contextBuffer->logical  + offset;
+        entryAddress  =                contextBuffer->address  + offset;
+        entryBytes    =                Context->bufferSize     - offset;
+
+        /* See if we have to switch pipes between the context
+            and command buffers. */
+        if (CommandBuffer->entryPipe == gcvPIPE_3D)
+        {
+            /* Skip reserved head bytes. */
+            offset = CommandBuffer->reservedHead;
+        }
+        else
+        {
+            gctUINT32 pipeBytes = CommandBuffer->reservedHead;
+
+            /* The current hardware and the initial context pipes are
+                different, switch to the correct pipe. */
+            gcmkONERROR(gckHARDWARE_PipeSelect(
+                Command->kernel->hardware,
+                commandBufferLogical,
+                CommandBuffer->entryPipe,
+                &pipeBytes
+                ));
+
+            /* Do not skip pipe switching sequence. */
+            offset = 0;
+
+            /* Reserved bytes in userspace must be exact for a pipeSelect. */
+            gcmkASSERT(pipeBytes == CommandBuffer->reservedHead);
+        }
+
+        /* Generate a LINK from the context buffer to
+            the command buffer. */
+        gcmkONERROR(gckWLFE_Link(
+            hardware,
+            contextBuffer->link3D,
+            commandBufferAddress + offset,
+            commandBufferSize    - offset,
+            &linkBytes,
+            &commandLinkLow,
+            &commandLinkHigh
+            ));
+
+#if gcdCAPTURE_ONLY_MODE
+        for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; ++i)
+        {
+            gcsCONTEXT_PTR buffer = contextBuffer;
+
+            gckOS_CopyToUserData(Command->os, buffer->logical, CommandBuffer->contextLogical[i], Context->bufferSize);
+
+            buffer = buffer->next;
+        }
+#endif
+
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            contextBuffer->videoMem,
+            entryAddress - contextBuffer->address,
+            entryLogical,
+            entryBytes
+            ));
+
+        /* Update the current context. */
+        Command->currContext = Context;
+
+        if (contextSwitched)
+        {
+            *contextSwitched = gcvTRUE;
+        }
+
+#if gcdDUMP_IN_KERNEL
+        contextDumpLogical = entryLogical;
+#endif
+
+#if gcdSECURITY
+        /* Commit context buffer to trust zone. */
+        gckKERNEL_SecurityExecute(
+            Command->kernel,
+            entryLogical,
+            entryBytes - 8
+            );
+#endif
+
+#if gcdRECORD_COMMAND
+        gckRECORDER_Record(
+            Command->recorder,
+            gcvNULL,
+            0xFFFFFFFF,
+            entryLogical,
+            entryBytes
+            );
+#endif
+    }
+
+    /* Same context. */
+    else
+    {
+        /* See if we have to switch pipes for the command buffer. */
+        if (CommandBuffer->entryPipe == (gctUINT32)(Command->pipeSelect))
+        {
+            /* Skip reserved head bytes. */
+            offset = CommandBuffer->reservedHead;
+        }
+        else
+        {
+            gctUINT32 pipeBytes = CommandBuffer->reservedHead;
+
+            /* The current hardware and the entry command buffer pipes
+            ** are different, switch to the correct pipe. */
+            gcmkONERROR(gckHARDWARE_PipeSelect(
+                Command->kernel->hardware,
+                commandBufferLogical,
+                CommandBuffer->entryPipe,
+                &pipeBytes
+                ));
+
+            /* Do not skip pipe switching sequence. */
+            offset = 0;
+
+            /* Reserved bytes in userspace must be exact for a pipeSelect. */
+            gcmkASSERT(pipeBytes == CommandBuffer->reservedHead);
+        }
+
+        /* Compute the entry. */
+        entryLogical  =                commandBufferLogical  + offset;
+        entryAddress  =                commandBufferAddress  + offset;
+        entryBytes    =                commandBufferSize     - offset;
+    }
+
+    (void)entryLogical;
+
+    /* Determine the location to jump to for the command buffer being
+    ** scheduled. */
+    if (Command->newQueue)
+    {
+        /* New command queue, jump to the beginning of it. */
+        /* Some extra commands (at beginning) are required for new queue. */
+        exitAddress  = Command->address;
+        exitBytes    = Command->offset + waitLinkBytes;
+    }
+    else
+    {
+        /* Still within the preexisting command queue, jump to the new
+           WAIT/LINK command sequence. */
+        exitAddress  = waitLinkAddress;
+        exitBytes    = waitLinkBytes;
+    }
+
+    /* Add a new WAIT/LINK command sequence. When the command buffer which is
+       currently being scheduled is fully executed by the GPU, the FE will
+       jump to this WAIT/LINK sequence. */
+    gcmkONERROR(gckWLFE_WaitLink(
+        hardware,
+        waitLinkLogical,
+        waitLinkAddress,
+        offset,
+        &waitLinkBytes,
+        &waitOffset,
+        &waitSize
+        ));
+
+    if (Command->newQueue)
+    {
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            0,
+            Command->logical,
+            exitBytes
+            ));
+    }
+    else
+    {
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            Command->offset,
+            waitLinkLogical,
+            exitBytes
+            ));
+    }
+
+    /* Determine the location of the TAIL in the command buffer. */
+    commandBufferTail
+        = commandBufferLogical
+        + commandBufferSize
+        - CommandBuffer->reservedTail;
+
+    /* Generate command which writes out commit stamp. */
+    if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FENCE_64BIT))
+    {
+        gctUINT32 bytes;
+
+        gcmkONERROR(gckHARDWARE_Fence(
+            hardware,
+            gcvENGINE_RENDER,
+            commandBufferTail,
+            Command->fence->address,
+            Command->commitStamp,
+            &bytes
+            ));
+
+        commandBufferTail += bytes;
+    }
+
+    /* Generate a LINK from the end of the command buffer being scheduled
+       back to the kernel command queue. */
+#if !gcdSECURITY
+    if (Shared == gcvFALSE)
+    {
+        gcmkONERROR(gckWLFE_Link(
+            hardware,
+            commandBufferTail,
+            exitAddress,
+            exitBytes,
+            &linkBytes,
+            &exitLinkLow,
+            &exitLinkHigh
+            ));
+    }
+    else
+    {
+        gctUINT8_PTR link = commandBufferTail + CommandBuffer->exitIndex * 16;
+        gctSIZE_T bytes = 8;
+
+        gcmkONERROR(gckWLFE_ChipEnable(
+            hardware,
+            link,
+            (gceCORE_3D_MASK)(1 << hardware->kernel->chipID),
+            &bytes
+            ));
+
+        link += bytes;
+
+        gcmkONERROR(gckWLFE_Link(
+            hardware,
+            link,
+            exitAddress,
+            exitBytes,
+            &linkBytes,
+            &exitLinkLow,
+            &exitLinkHigh
+            ));
+
+        link += linkBytes;
+    }
+#endif
+
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+        Command->kernel,
+        ProcessID,
+        CommandBuffer->videoMemNode,
+        &commandBufferVideoMem
+        ));
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Command->kernel,
+        commandBufferVideoMem,
+        CommandBuffer->startOffset,
+        commandBufferLogical,
+        commandBufferSize
+        ));
+
+#if gcdRECORD_COMMAND
+    gckRECORDER_Record(
+        Command->recorder,
+        commandBufferLogical + offset,
+        commandBufferSize - offset,
+        gcvNULL,
+        0xFFFFFFFF
+        );
+
+    gckRECORDER_AdvanceIndex(Command->recorder, Command->commitStamp);
+#endif
+
+#if gcdSECURITY
+    /* Submit command buffer to trust zone. */
+    gckKERNEL_SecurityExecute(
+        Command->kernel,
+        commandBufferLogical + offset,
+        commandBufferSize    - offset - 8
+        );
+#else
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /*
+     * Skip link to entryAddress.
+     * Instead, we directly link to final wait link position.
+     */
+    gcmkONERROR(gckWLFE_Link(
+        hardware,
+        Command->waitPos.logical,
+        waitLinkAddress,
+        waitLinkBytes,
+        &Command->waitPos.size,
+        &entryLinkLow,
+        &entryLinkHigh
+        ));
+#  else
+    /* Generate a LINK from the previous WAIT/LINK command sequence to the
+       entry determined above (either the context or the command buffer).
+       This LINK replaces the WAIT instruction from the previous WAIT/LINK
+       pair, therefore we use WAIT metrics for generation of this LINK.
+       This action will execute the entire sequence. */
+    gcmkONERROR(gckWLFE_Link(
+        hardware,
+        Command->waitPos.logical,
+        entryAddress,
+        entryBytes,
+        &Command->waitPos.size,
+        &entryLinkLow,
+        &entryLinkHigh
+        ));
+#  endif
+#endif
+
+#if gcdLINK_QUEUE_SIZE
+    /* TODO: What's it? */
+    if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_USER_COMMAND)
+    {
+        gcuQUEUEDATA data;
+
+        gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+        data.linkData.start    = entryAddress;
+        data.linkData.end      = entryAddress + entryBytes;
+        data.linkData.linkLow  = entryLinkLow;
+        data.linkData.linkHigh = entryLinkHigh;
+
+        gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+
+        if (commandBufferAddress + offset != entryAddress)
+        {
+             data.linkData.start    =  commandBufferAddress + offset;
+             data.linkData.end      =  commandBufferAddress + commandBufferSize;
+             data.linkData.linkLow  = commandLinkLow;
+             data.linkData.linkHigh = commandLinkHigh;
+
+            gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+        }
+
+        if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_ALL_COMMAND)
+        {
+            data.linkData.start    = exitAddress;
+            data.linkData.end      = exitAddress + exitBytes;
+            data.linkData.linkLow  = exitLinkLow;
+            data.linkData.linkHigh = exitLinkHigh;
+
+            /* Dump kernel command.*/
+            gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+        }
+    }
+#endif
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Command->kernel,
+        Command->waitPos.videoMem,
+        Command->waitPos.offset,
+        Command->waitPos.logical,
+        Command->waitPos.size
+        ));
+
+    if (entryAddress != commandBufferAddress + offset)
+    {
+        gcmkDUMP(Command->os, "#[context]");
+        gcmkDUMP_BUFFER(
+            Command->os,
+            gcvDUMP_BUFFER_KERNEL_CONTEXT,
+            contextDumpLogical,
+            entryAddress,
+            entryBytes
+            );
+
+        /* execute context. */
+        gcmkDUMP(Command->os,
+            "@[execute 0 0 0x%08X 0x%08X]",
+            entryAddress + offset,
+            entryBytes - offset - 8
+            );
+    }
+
+    gcmkDUMP(Command->os, "#[command: user]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_COMMAND,
+        commandBufferLogical + offset,
+        commandBufferAddress + offset,
+        commandBufferSize - offset
+        );
+
+    /* execute user commands. */
+    gcmkDUMP(
+        Command->os,
+        "@[execute 0 0 0x%08X 0x%08X]",
+        commandBufferAddress
+            + CommandBuffer->reservedHead,
+        commandBufferSize
+            - CommandBuffer->reservedHead
+            - CommandBuffer->reservedTail
+        );
+
+    gcmkDUMP(Command->os, "#[wait-link]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        waitLinkLogical,
+        waitLinkAddress,
+        waitLinkBytes
+        );
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    gcmkDUMP(
+        Command->os,
+        "#[null driver: below command skipped link to 0x%08X 0x%08X]",
+        entryAddress,
+        entryBytes
+        );
+#endif
+
+    gcmkDUMP(Command->os, "#[link: break prev wait-link]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        Command->waitPos.logical,
+        Command->waitPos.address,
+        Command->waitPos.size
+        );
+
+    /* Update the current pipe. */
+    Command->pipeSelect = CommandBuffer->exitPipe;
+
+    /* Update command queue offset. */
+    Command->offset  += waitLinkBytes;
+    Command->newQueue = gcvFALSE;
+
+    /* Update address of last WAIT. */
+    Command->waitPos.videoMem = Command->videoMem;
+    Command->waitPos.offset   = Command->offset - waitLinkBytes + waitOffset;
+    Command->waitPos.logical  = (gctUINT8_PTR)waitLinkLogical  + waitOffset;
+    Command->waitPos.address  = waitLinkAddress  + waitOffset;
+    Command->waitPos.size     = waitSize;
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+        hardware, Command->logical, Command->offset
+        ));
+
+    /* Release the context switching mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+    contextAcquired = gcvFALSE;
+
+    /* Release the command queue. */
+    gcmkONERROR(gckCOMMAND_ExitCommit(Command, gcvFALSE));
+    commitEntered = gcvFALSE;
+
+    if (status == gcvSTATUS_INTERRUPTED)
+    {
+        gcmkTRACE(
+            gcvLEVEL_INFO,
+            "%s(%d): Intterupted in gckEVENT_Submit",
+            __FUNCTION__, __LINE__
+            );
+        status = gcvSTATUS_OK;
+    }
+    else
+    {
+        gcmkONERROR(status);
+    }
+
+#ifdef __QNXNTO__
+    if(userCommandBufferLogicalMapped)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+            Command->kernel,
+            commandBufferVideoMem,
+            ProcessID,
+            gcvFALSE,
+            gcvFALSE
+            ));
+
+        userCommandBufferLogicalMapped =gcvFALSE;
+    }
+#endif
+
+    /* Return status. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (contextAcquired)
+    {
+        /* Release the context switching mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+    }
+
+    if (commitEntered)
+    {
+        /* Release the command queue mutex. */
+        gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Command, gcvFALSE));
+    }
+
+#ifdef __QNXNTO__
+    if (userCommandBufferLogicalMapped)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+            Command->os,
+            userCommandBufferLogical,
+            0,
+            commandBufferLogical));
+    }
+#endif
+
+    /* Return status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_CommitAsyncOnce(
+    IN gckCOMMAND Command,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer
+    )
+{
+    gceSTATUS       status;
+    gckHARDWARE     hardware = Command->kernel->hardware;
+    gctBOOL         available = gcvFALSE;
+    gctBOOL         acquired = gcvFALSE;
+    gctUINT8_PTR    commandBufferLogical;
+    gctUINT8_PTR    commandBufferTail;
+    gctUINT         commandBufferSize;
+    gctUINT32       commandBufferAddress;
+    gctUINT32       fenceBytes;
+    gctUINT32       oldValue;
+    gctUINT32       flushBytes;
+    gcsPATCH_LIST_VARIABLE patchListVar = {0, 0};
+
+    gcmkHEADER();
+
+    gcmkVERIFY_OK(
+        _HandlePatchList(Command, CommandBuffer, &patchListVar));
+
+    gckOS_AtomicExchange(Command->os,
+                         hardware->pageTableDirty[gcvENGINE_BLT],
+                         0,
+                         &oldValue);
+
+    if (oldValue)
+    {
+        gckHARDWARE_FlushAsyncMMU(hardware, gcvNULL, &flushBytes);
+
+        gcmkASSERT(flushBytes <= CommandBuffer->reservedHead);
+
+        /* Compute the command buffer entry to insert the flushMMU commands. */
+        commandBufferLogical = (gctUINT8_PTR)gcmUINT64_TO_PTR(CommandBuffer->logical)
+                             + CommandBuffer->startOffset
+                             + CommandBuffer->reservedHead
+                             - flushBytes;
+
+        commandBufferAddress = CommandBuffer->address
+                             + CommandBuffer->startOffset
+                             + CommandBuffer->reservedHead
+                             - flushBytes;
+
+        gckHARDWARE_FlushAsyncMMU(hardware, commandBufferLogical, &flushBytes);
+    }
+    else
+    {
+        /* Compute the command buffer entry. */
+        commandBufferLogical = (gctUINT8_PTR)gcmUINT64_TO_PTR(CommandBuffer->logical)
+                             + CommandBuffer->startOffset
+                             + CommandBuffer->reservedHead;
+
+        commandBufferAddress = CommandBuffer->address
+                             + CommandBuffer->startOffset
+                             + CommandBuffer->reservedHead;
+
+        flushBytes = 0;
+    }
+
+    commandBufferTail = (gctUINT8_PTR)gcmUINT64_TO_PTR(CommandBuffer->logical)
+                      + CommandBuffer->startOffset
+                      + CommandBuffer->size
+                      - CommandBuffer->reservedTail;
+
+    gcmkONERROR(gckHARDWARE_Fence(
+        hardware,
+        gcvENGINE_BLT,
+        commandBufferTail,
+        Command->fence->address,
+        Command->commitStamp,
+        &fenceBytes
+        ));
+
+    gcmkASSERT(fenceBytes <= CommandBuffer->reservedTail);
+
+    commandBufferSize = CommandBuffer->size
+                      - CommandBuffer->reservedHead
+                      - CommandBuffer->reservedTail
+                      + flushBytes
+                      + fenceBytes;
+
+    gckOS_AcquireMutex(Command->os, Command->mutexContext, gcvINFINITE);
+    acquired = gcvTRUE;
+
+    /* Acquire a slot. */
+    for (;;)
+    {
+        gcmkONERROR(gckASYNC_FE_ReserveSlot(hardware, &available));
+
+        if (available)
+        {
+            break;
+        }
+        else
+        {
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE, "No available slot, have to wait");
+
+            gckOS_Delay(Command->os, 1);
+        }
+    }
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /* Skip submit to hardware for NULL driver. */
+    gcmkDUMP(Command->os, "#[null driver: below command is skipped]");
+#endif
+
+    gcmkDUMP(Command->os, "#[async-command: user]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_ASYNC_COMMAND,
+        commandBufferLogical,
+        commandBufferAddress,
+        commandBufferSize
+        );
+
+    gcmkDUMP(
+        Command->os,
+        "@[execute 1 0 0x%08X 0x%08X]",
+        commandBufferAddress
+            + CommandBuffer->reservedHead,
+        CommandBuffer->size
+            - CommandBuffer->reservedHead
+            - CommandBuffer->reservedTail
+        );
+
+#if !gcdNULL_DRIVER
+    /* Execute command buffer. */
+    gckASYNC_FE_Execute(hardware, commandBufferAddress, commandBufferSize);
+#endif
+
+    gckOS_ReleaseMutex(Command->os, Command->mutexContext);
+    acquired = gcvFALSE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gckOS_ReleaseMutex(Command->os, Command->mutexContext);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_CommitMultiChannelOnce(
+    IN gckCOMMAND Command,
+    IN gckCONTEXT Context,
+    IN gcsHAL_COMMAND_LOCATION * CommandBuffer
+    )
+{
+    gceSTATUS    status;
+    gctBOOL      acquired = gcvFALSE;
+    gctUINT8_PTR commandBufferLogical;
+    gctUINT      commandBufferSize;
+    gctUINT32    commandBufferAddress;
+    gckHARDWARE  hardware;
+    gctUINT64    bit;
+    gcsPATCH_LIST_VARIABLE patchListVar = {0, 0};
+
+    gcmkHEADER_ARG("priority=%d channelId=%d videoMemNode=%u size=0x%x patchHead=%p",
+                   CommandBuffer->priority, CommandBuffer->channelId,
+                   CommandBuffer->videoMemNode, CommandBuffer->size,
+                   gcmUINT64_TO_PTR(CommandBuffer->patchHead));
+
+    gcmkASSERT(Command->feType == gcvHW_FE_MULTI_CHANNEL);
+
+    hardware = Command->kernel->hardware;
+
+    gcmkVERIFY_OK(
+        _HandlePatchList(Command, CommandBuffer, &patchListVar));
+
+    /* Check flush mcfe MMU cache. */
+    gcmkONERROR(_CheckFlushMcfeMMU(Command, hardware));
+
+    /* Compute the command buffer entry and the size. */
+    commandBufferLogical
+        = (gctUINT8_PTR) gcmUINT64_TO_PTR(CommandBuffer->logical)
+        +                CommandBuffer->startOffset
+        +                CommandBuffer->reservedHead;
+
+    commandBufferAddress = CommandBuffer->address
+                         + CommandBuffer->startOffset
+                         + CommandBuffer->reservedHead;
+
+    /* reservedTail bytes are not used, because fence not enable. */
+    commandBufferSize
+        = CommandBuffer->size
+        - CommandBuffer->reservedHead
+        - CommandBuffer->reservedTail;
+
+    if (commandBufferSize & 8)
+    {
+        /*
+         * Need 16 byte alignment for MCFE command size.
+         * command is already 8 byte aligned, if not 16 byte aligned,
+         * we need append 8 bytes.
+         */
+        gctUINT32 nop[2];
+        gctSIZE_T bytes = 8;
+        gctUINT8_PTR tail = commandBufferLogical + commandBufferSize;
+
+        gckMCFE_Nop(hardware, nop, &bytes);
+        gcmkASSERT(bytes == 8);
+
+        gckOS_WriteMemory(Command->os, tail, nop[0]);
+        gckOS_WriteMemory(Command->os, tail + 4, nop[1]);
+
+        commandBufferSize += 8;
+    }
+
+    /* Large command buffer size does not make sense. */
+    gcmkASSERT(commandBufferSize < 0x800000);
+
+
+    if (CommandBuffer->channelId != 0)
+    {
+        /* Sync from the system channel. */
+        gcmkONERROR(_SyncFromSystemChannel(
+            Command,
+            (gctBOOL)CommandBuffer->priority,
+            (gctUINT32)CommandBuffer->channelId
+            ));
+    }
+
+    Command->currContext = Context;
+
+    gckOS_AcquireMutex(Command->os, Command->mutexQueue, gcvINFINITE);
+    acquired = gcvTRUE;
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /* Skip submit to hardware for NULL driver. */
+    gcmkDUMP(Command->os, "#[null driver: below command is skipped]");
+#endif
+
+    gcmkDUMP(Command->os, "#[mcfe-command: user]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_COMMAND,
+        commandBufferLogical,
+        commandBufferAddress,
+        commandBufferSize
+        );
+
+    gcmkDUMP(Command->os,
+             "@[execute %d %d 0x%08X 0x%08X]",
+             CommandBuffer->channelId,
+             CommandBuffer->priority,
+             commandBufferAddress,
+             commandBufferSize);
+
+#if !gcdNULL_DRIVER
+    /* Execute command buffer. */
+    gcmkONERROR(gckMCFE_Execute(
+        hardware,
+        (gctBOOL)CommandBuffer->priority,
+        (gctUINT32)CommandBuffer->channelId,
+        commandBufferAddress,
+        commandBufferSize
+        ));
+#endif
+
+    bit = 1ull << CommandBuffer->channelId;
+
+    /* This channel is dirty. */
+    Command->dirtyChannel[CommandBuffer->priority ? 1 : 0] |= bit;
+
+    gckOS_ReleaseMutex(Command->os, Command->mutexQueue);
+    acquired = gcvFALSE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gckOS_ReleaseMutex(Command->os, Command->mutexQueue);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Commit
+**
+**  Commit command buffers to the command queue.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to a gckCOMMAND object.
+**
+**      gcsHAL_SUBCOMMIT * SubCommit
+**          Commit information, includes context, delta, and command buffer
+*           locations.
+**
+**      gctUINT32 ProcessID
+**          Current process ID.
+**
+**  OUTPUT:
+**      gctBOOL *contextSwitched
+**          pass context Switch flag to upper
+*/
+gceSTATUS
+gckCOMMAND_Commit(
+    IN gckCOMMAND Command,
+    IN gcsHAL_SUBCOMMIT * SubCommit,
+    IN gctUINT32 ProcessId,
+    IN gctBOOL Shared,
+    OUT gctUINT64_PTR CommitStamp,
+    INOUT gctBOOL *contextSwitched
+    )
+{
+    gceSTATUS status;
+    gcsSTATE_DELTA_PTR delta = gcmUINT64_TO_PTR(SubCommit->delta);
+    gckCONTEXT context = gcvNULL;
+    gcsHAL_COMMAND_LOCATION *cmdLoc = &SubCommit->commandBuffer;
+    gcsHAL_COMMAND_LOCATION _cmdLoc;
+    gctPOINTER userPtr = gcvNULL;
+    gctBOOL needCopy = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p SubCommit=%p delta=%p context=%u pid=%u",
+                   Command, SubCommit, delta, SubCommit->context, ProcessId);
+
+    gcmkVERIFY_OK(gckOS_QueryNeedCopy(Command->os, ProcessId, &needCopy));
+
+    if (SubCommit->context)
+    {
+        context = gckKERNEL_QueryPointerFromName(
+            Command->kernel,
+            (gctUINT32)(SubCommit->context)
+            );
+    }
+
+    do
+    {
+        gctUINT64 next;
+
+        /* Skip the first nested one. */
+        if (userPtr)
+        {
+            /* Copy/map command buffer location from user. */
+            if (needCopy)
+            {
+                cmdLoc = &_cmdLoc;
+
+                status = gckOS_CopyFromUserData(
+                    Command->os,
+                    cmdLoc,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_COMMAND_LOCATION)
+                    );
+            }
+            else
+            {
+                status = gckOS_MapUserPointer(
+                    Command->os,
+                    userPtr,
+                    gcmSIZEOF(gcsHAL_COMMAND_LOCATION),
+                    (gctPOINTER *)&cmdLoc
+                    );
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                userPtr = gcvNULL;
+
+                gcmkONERROR(status);
+            }
+        }
+
+        if (Command->feType == gcvHW_FE_WAIT_LINK)
+        {
+            /* Commit command buffers. */
+            status = _CommitWaitLinkOnce(Command,
+                                         context,
+                                         cmdLoc,
+                                         delta,
+                                         ProcessId,
+                                         Shared,
+                                         contextSwitched);
+        }
+        else if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+        {
+            status = _CommitMultiChannelOnce(Command, context, cmdLoc);
+        }
+        else
+        {
+            gcmkASSERT(Command->feType == gcvHW_FE_ASYNC);
+
+            status = _CommitAsyncOnce(Command, cmdLoc);
+        }
+
+        if (status != gcvSTATUS_INTERRUPTED)
+        {
+            gcmkONERROR(status);
+        }
+
+        /* Do not need context or delta for later commands. */
+        context = gcvNULL;
+        delta   = gcvNULL;
+
+        next    = cmdLoc->next;
+
+        /* Unmap user pointer if mapped. */
+        if (!needCopy && userPtr)
+        {
+            gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                Command->os,
+                userPtr,
+                gcmSIZEOF(gcsHAL_COMMAND_LOCATION),
+                cmdLoc
+                ));
+        }
+
+        /* Advance to next command buffer location from user. */
+        userPtr = gcmUINT64_TO_PTR(next);
+    }
+    while (userPtr);
+
+    if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        /*
+         * Semphore synchronization.
+         *
+         * Here we blindly sync dirty other channels to the system channel.
+         * The scenario to sync channels to the system channel:
+         * 1. Need to sync channels who sent semaphores.
+         * 2. Need to sync dirty channels when event(interrupt) is to sent.
+         * 3. Need to sync dirty channels when system channel need run something
+         *    such as flush mmu.
+         *
+         * When power management is on, blindly sync dirty channels is OK because
+         * there's always a event(intrrupt).
+         *
+         * The only condition we sync more than needed is:
+         * a. power manangement is off.
+         * b. no user event is attached when commit.
+         * c. no user event is to be submitted in next ioctl.
+         * That's a rare condition.
+         *
+         * Conclusion is that, blindly sync dirty channels is a good choice for
+         * now.
+         */
+        gcmkONERROR(_SyncToSystemChannel(Command, Command->dirtyChannel));
+    }
+
+    /* Output commit stamp. */
+    *CommitStamp = Command->commitStamp;
+    Command->commitStamp++;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (!needCopy && userPtr)
+    {
+        gckOS_UnmapUserPointer(
+            Command->os,
+            userPtr,
+            gcmSIZEOF(gcsHAL_COMMAND_LOCATION),
+            cmdLoc
+            );
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Reserve
+**
+**  Reserve space in the command queue.  Also acquire the command queue mutex.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object.
+**
+**      gctSIZE_T RequestedBytes
+**          Number of bytes previously reserved.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Buffer
+**          Pointer to a variable that will receive the address of the reserved
+**          space.
+**
+**      gctSIZE_T * BufferSize
+**          Pointer to a variable that will receive the number of bytes
+**          available in the command queue.
+*/
+gceSTATUS
+gckCOMMAND_Reserve(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequestedBytes,
+    OUT gctPOINTER * Buffer,
+    OUT gctUINT32 * BufferSize
+    )
+{
+    gceSTATUS status;
+    gctUINT32 bytes;
+    gctUINT32 requiredBytes;
+    gctUINT32 requestedAligned;
+
+    gcmkHEADER_ARG("Command=%p RequestedBytes=%lu", Command, RequestedBytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    if (Command->feType == gcvHW_FE_WAIT_LINK)
+    {
+        /* Compute aligned number of reuested bytes. */
+        requestedAligned = gcmALIGN(RequestedBytes, Command->alignment);
+
+        /* Another WAIT/LINK command sequence will have to be appended after
+           the requested area being reserved. Compute the number of bytes
+           required for WAIT/LINK at the location after the reserved area. */
+        gcmkONERROR(gckWLFE_WaitLink(
+            Command->kernel->hardware,
+            gcvNULL,
+            ~0U,
+            Command->offset + requestedAligned,
+            &requiredBytes,
+            gcvNULL,
+            gcvNULL
+            ));
+
+        /* Compute total number of bytes required. */
+        requiredBytes += requestedAligned;
+    }
+    else
+    {
+        requiredBytes = gcmALIGN(RequestedBytes, 8);
+    }
+
+    /* Compute number of bytes available in command queue. */
+    bytes = Command->pageSize - Command->offset;
+
+    /* Is there enough space in the current command queue? */
+    if (bytes < requiredBytes)
+    {
+        /* Create a new command queue. */
+        gcmkONERROR(_NewQueue(Command, gcvFALSE));
+
+        /* Recompute the number of bytes in the new kernel command queue. */
+        bytes = Command->pageSize - Command->offset;
+
+        /* Still not enough space? */
+        if (bytes < requiredBytes)
+        {
+            /* Rare case, not enough room in command queue. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+    }
+
+    /* Return pointer to empty slot command queue. */
+    *Buffer = (gctUINT8 *) Command->logical + Command->offset;
+
+    /* Return number of bytes left in command queue. */
+    *BufferSize = bytes;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Execute
+**
+**  Execute a previously reserved command queue by appending a WAIT/LINK command
+**  sequence after it and modifying the last WAIT into a LINK command.  The
+**  command FIFO mutex will be released whether this function succeeds or not.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object.
+**
+**      gctSIZE_T RequestedBytes
+**          Number of bytes previously reserved.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Execute(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequestedBytes
+    )
+{
+    gceSTATUS status;
+
+    gctUINT8_PTR waitLinkLogical;
+    gctUINT32 waitLinkAddress;
+    gctUINT32 waitLinkOffset;
+    gctUINT32 waitLinkBytes;
+
+    gctUINT32 waitOffset;
+    gctUINT32 waitBytes;
+
+    gctUINT32 linkLow, linkHigh;
+
+    gctPOINTER execLogical;
+    gctUINT32 execAddress;
+    gctUINT32 execBytes;
+
+    gcmkHEADER_ARG("Command=%p RequestedBytes=%lu", Command, RequestedBytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Compute offset for WAIT/LINK. */
+    waitLinkOffset = Command->offset + RequestedBytes;
+
+    /* Compute number of bytes left in command queue. */
+    waitLinkBytes = Command->pageSize - waitLinkOffset;
+
+    /* Compute the location if WAIT/LINK command sequence. */
+    waitLinkLogical  = (gctUINT8_PTR) Command->logical  + waitLinkOffset;
+    waitLinkAddress  =                Command->address  + waitLinkOffset;
+
+    /* Append WAIT/LINK in command queue. */
+    gcmkONERROR(gckWLFE_WaitLink(
+        Command->kernel->hardware,
+        waitLinkLogical,
+        waitLinkAddress,
+        waitLinkOffset,
+        &waitLinkBytes,
+        &waitOffset,
+        &waitBytes
+        ));
+
+
+    /* Determine the location to jump to for the command buffer being
+    ** scheduled. */
+    if (Command->newQueue)
+    {
+        /* New command queue, jump to the beginning of it. */
+        execLogical  = Command->logical;
+        execAddress  = Command->address;
+        execBytes    = Command->offset + RequestedBytes + waitLinkBytes;
+
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            0,
+            execLogical,
+            execBytes
+            ));
+    }
+    else
+    {
+        /* Still within the preexisting command queue, jump directly to the
+           reserved area. */
+        execLogical  = (gctUINT8 *) Command->logical  + Command->offset;
+        execAddress  =              Command->address  + Command->offset;
+        execBytes    = RequestedBytes + waitLinkBytes;
+
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            Command->offset,
+            execLogical,
+            execBytes
+            ));
+    }
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /*
+     * Skip link to execAddress.
+     * Instead, we directly link to final wait link position.
+     */
+    gcmkONERROR(gckWLFE_Link(
+        Command->kernel->hardware,
+        Command->waitPos.logical,
+        waitLinkAddress,
+        waitLinkBytes,
+        &Command->waitPos.size,
+        &linkLow,
+        &linkHigh
+        ));
+#else
+    /* Convert the last WAIT into a LINK. */
+    gcmkONERROR(gckWLFE_Link(
+        Command->kernel->hardware,
+        Command->waitPos.logical,
+        execAddress,
+        execBytes,
+        &Command->waitPos.size,
+        &linkLow,
+        &linkHigh
+        ));
+#endif
+
+    gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+        Command->kernel,
+        Command->waitPos.videoMem,
+        Command->waitPos.offset,
+        Command->waitPos.logical,
+        Command->waitPos.size
+        ));
+
+#if gcdLINK_QUEUE_SIZE
+    if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_ALL_COMMAND)
+    {
+        gcuQUEUEDATA data;
+
+        gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+        data.linkData.start    = execAddress;
+        data.linkData.end      = execAddress + execBytes;
+        data.linkData.linkLow  = linkLow;
+        data.linkData.linkHigh = linkHigh;
+
+        gckQUEUE_Enqueue(&Command->kernel->hardware->linkQueue, &data);
+    }
+#endif
+
+    gcmkDUMP(Command->os, "#[command: kernel execute]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        execLogical,
+        execAddress,
+        execBytes
+        );
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    gcmkDUMP(Command->os,
+             "#[null driver: below command skipped link to 0x%08X 0x%08X]",
+             execAddress,
+             execBytes);
+#endif
+
+    gcmkDUMP(Command->os, "#[link: break prev wait-link]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        Command->waitPos.logical,
+        Command->waitPos.address,
+        Command->waitPos.size
+        );
+
+    /* Update the pointer to the last WAIT. */
+    Command->waitPos.videoMem = Command->videoMem;
+    Command->waitPos.offset  = waitLinkOffset + waitOffset;
+    Command->waitPos.logical = (gctUINT8_PTR)waitLinkLogical  + waitOffset;
+    Command->waitPos.address = waitLinkAddress  + waitOffset;
+    Command->waitPos.size    = waitBytes;
+
+    /* Update the command queue. */
+    Command->offset  += RequestedBytes + waitLinkBytes;
+    Command->newQueue = gcvFALSE;
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+        Command->kernel->hardware, Command->logical, Command->offset
+        ));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckCOMMAND_ExecuteAsync(
+    IN gckCOMMAND Command,
+    IN gctUINT32 RequestedBytes
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware;
+    gctBOOL available;
+    gctPOINTER execLogical;
+    gctUINT32 execAddress;
+    gctUINT32 execBytes;
+
+    hardware = Command->kernel->hardware;
+
+    /* Determine the location to jump to for the command buffer being
+    ** scheduled. */
+    if (Command->newQueue)
+    {
+        /* New command queue, jump to the beginning of it. */
+        execLogical  = Command->logical;
+        execAddress  = Command->address;
+        execBytes    = Command->offset + RequestedBytes;
+
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            0,
+            execLogical,
+            execBytes
+            ));
+    }
+    else
+    {
+        /* Still within the preexisting command queue, jump directly to the
+           reserved area. */
+        execLogical  = (gctUINT8 *) Command->logical  + Command->offset;
+        execAddress  =              Command->address  + Command->offset;
+        execBytes    = RequestedBytes;
+
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            Command->offset,
+            execLogical,
+            execBytes
+            ));
+    }
+
+    /* Acquire a slot. */
+    for (;;)
+    {
+        gcmkONERROR(gckASYNC_FE_ReserveSlot(hardware, &available));
+
+        if (available)
+        {
+            break;
+        }
+        else
+        {
+            gckOS_Delay(Command->os, 1);
+        }
+    }
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /* Skip submit to hardware for NULL driver. */
+    gcmkDUMP(Command->os, "#[null driver: below command is skipped]");
+#endif
+
+    gcmkDUMP(Command->os, "#[async-command: kernel execute]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        execLogical,
+        execAddress,
+        execBytes
+        );
+
+#if !gcdNULL_DRIVER
+    /* Send descriptor. */
+    gckASYNC_FE_Execute(hardware, execAddress, execBytes);
+#endif
+
+    /* Update the command queue. */
+    Command->offset   += RequestedBytes;
+    Command->newQueue  = gcvFALSE;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckCOMMAND_ExecuteMultiChannel(
+    IN gckCOMMAND Command,
+    IN gctBOOL Priority,
+    IN gctUINT32 ChannelId,
+    IN gctUINT32 RequestedBytes
+    )
+{
+    gceSTATUS status;
+    gctPOINTER execLogical;
+    gctUINT32 execAddress;
+    gctUINT32 execBytes;
+
+    /* Determine the location to jump to for the command buffer being
+    ** scheduled. */
+    if (Command->newQueue)
+    {
+        /* New command queue, jump to the beginning of it. */
+        execLogical  = Command->logical;
+        execAddress  = Command->address;
+        execBytes    = Command->offset + RequestedBytes;
+    }
+    else
+    {
+        /* Still within the preexisting command queue, jump directly to the
+           reserved area. */
+        execLogical  = (gctUINT8 *) Command->logical  + Command->offset;
+        execAddress  =              Command->address  + Command->offset;
+        execBytes    = RequestedBytes;
+    }
+
+    if (execBytes & 8)
+    {
+        gctSIZE_T bytes = 8;
+        gctUINT8_PTR tail = (gctUINT8_PTR)execLogical + execBytes;
+
+        gckMCFE_Nop(Command->kernel->hardware, tail, &bytes);
+        gcmkASSERT(bytes == 8);
+
+        execBytes += 8;
+        RequestedBytes += 8;
+    }
+
+    if (Command->newQueue)
+    {
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            0,
+            execLogical,
+            execBytes
+            ));
+    }
+    else
+    {
+        gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+            Command->kernel,
+            Command->videoMem,
+            Command->offset,
+            execLogical,
+            execBytes
+            ));
+    }
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+    /* Skip submit to hardware for NULL driver. */
+    gcmkDUMP(Command->os, "#[null driver: below command is skipped]");
+#endif
+
+    gcmkDUMP(Command->os, "#[mcfe-command: kernel execute]");
+    gcmkDUMP_BUFFER(
+        Command->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        execLogical,
+        execAddress,
+        execBytes
+        );
+
+    gcmkDUMP(Command->os,
+             "@[execute %u %u 0x%08X 0x%08X]",
+             ChannelId, Priority, execAddress, execBytes);
+
+#if !gcdNULL_DRIVER
+    /* Send descriptor. */
+    gcmkONERROR(
+        gckMCFE_Execute(Command->kernel->hardware,
+                        Priority,
+                        ChannelId,
+                        execAddress,
+                        execBytes));
+#endif
+
+    /* Update the command queue. */
+    Command->offset   += RequestedBytes;
+    Command->newQueue  = gcvFALSE;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Stall
+**
+**  The calling thread will be suspended until the command queue has been
+**  completed.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to an gckCOMMAND object.
+**
+**      gctBOOL FromPower
+**          Determines whether the call originates from inside the power
+**          management or not.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Stall(
+    IN gckCOMMAND Command,
+    IN gctBOOL FromPower
+    )
+{
+    gckOS os;
+    gckHARDWARE hardware;
+    gckEVENT eventObject;
+    gceSTATUS status;
+    gctSIGNAL signal = gcvNULL;
+    gctUINT timer = 0;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Extract the gckOS object pointer. */
+    os = Command->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Extract the gckHARDWARE object pointer. */
+    hardware = Command->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Extract the gckEVENT object pointer. */
+    eventObject = Command->kernel->eventObj;
+    gcmkVERIFY_OBJECT(eventObject, gcvOBJ_EVENT);
+
+    /* Allocate the signal. */
+    gcmkONERROR(gckOS_CreateSignal(os, gcvTRUE, &signal));
+
+    /* Append the EVENT command to trigger the signal. */
+    gcmkONERROR(gckEVENT_Signal(eventObject, signal, gcvKERNEL_PIXEL));
+
+    /* Submit the event queue. */
+    gcmkONERROR(gckEVENT_Submit(eventObject, gcvTRUE, FromPower));
+
+    gcmkDUMP(Command->os, "#[kernel.stall]");
+
+    if (status == gcvSTATUS_CHIP_NOT_READY)
+    {
+        /* Error. */
+        goto OnError;
+    }
+
+    do
+    {
+        /* Wait for the signal. */
+        status = gckOS_WaitSignal(os, signal, !FromPower, gcdGPU_ADVANCETIMER);
+
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+            gctUINT32 idle;
+
+            /* Read idle register. */
+            gcmkVERIFY_OK(gckHARDWARE_GetIdle(
+                hardware, gcvFALSE, &idle
+                ));
+
+            gcmkTRACE(
+                gcvLEVEL_ERROR,
+                "%s(%d): idle=%08x",
+                __FUNCTION__, __LINE__, idle
+                );
+
+            gcmkVERIFY_OK(gckOS_MemoryBarrier(os, gcvNULL));
+#endif
+
+            /* Advance timer. */
+            timer += gcdGPU_ADVANCETIMER;
+        }
+        else if (status == gcvSTATUS_INTERRUPTED)
+        {
+            gcmkONERROR(gcvSTATUS_INTERRUPTED);
+        }
+
+    }
+    while (gcmIS_ERROR(status));
+
+    /* Bail out on timeout. */
+    if (gcmIS_ERROR(status))
+    {
+        /* Broadcast the stuck GPU. */
+        gcmkONERROR(gckOS_Broadcast(
+            os, hardware, gcvBROADCAST_GPU_STUCK
+            ));
+    }
+
+    /* Delete the signal. */
+    gcmkVERIFY_OK(gckOS_DestroySignal(os, signal));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (signal != gcvNULL)
+    {
+        /* Free the signal. */
+        gcmkVERIFY_OK(gckOS_DestroySignal(os, signal));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gceSTATUS
+_AttachWaitLinkFECommand(
+    IN gckCOMMAND Command,
+    OUT gckCONTEXT * Context,
+    OUT gctSIZE_T * MaxState,
+    OUT gctUINT32 * NumStates,
+    IN gctUINT32 ProcessID
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Acquire the context switching mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        Command->os, Command->mutexContext, gcvINFINITE
+        ));
+    acquired = gcvTRUE;
+
+    /* Construct a gckCONTEXT object. */
+    gcmkONERROR(gckCONTEXT_Construct(
+        Command->os,
+        Command->kernel->hardware,
+        ProcessID,
+        Context
+        ));
+
+    /* Return the number of states in the context. */
+    * MaxState  = (* Context)->maxState;
+    * NumStates = (* Context)->numStates;
+
+    /* Release the context switching mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+    acquired = gcvFALSE;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Context=0x%x", *Context);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Release mutex. */
+    if (acquired)
+    {
+        /* Release the context switching mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+        acquired = gcvFALSE;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Attach
+**
+**  Attach user process.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to a gckCOMMAND object.
+**
+**      gctUINT32 ProcessID
+**          Current process ID.
+**
+**  OUTPUT:
+**
+**      gckCONTEXT * Context
+**          Pointer to a variable that will receive a pointer to a new
+**          gckCONTEXT object.
+**
+**      gctSIZE_T * StateCount
+**          Pointer to a variable that will receive the number of states
+**          in the context buffer.
+*/
+gceSTATUS
+gckCOMMAND_Attach(
+    IN gckCOMMAND Command,
+    OUT gckCONTEXT * Context,
+    OUT gctSIZE_T * MaxState,
+    OUT gctUINT32 * NumStates,
+    IN gctUINT32 ProcessID
+    )
+{
+    gctUINT32 allocationSize;
+    gctPOINTER pointer;
+    gceSTATUS status;
+
+    if (Command->feType == gcvHW_FE_WAIT_LINK)
+    {
+        status = _AttachWaitLinkFECommand(Command,
+                                        Context,
+                                        MaxState,
+                                        NumStates,
+                                        ProcessID);
+    }
+    else if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        /*
+         * For mcfe, we only allocate context which is used to
+         * store profile counters.
+         */
+        allocationSize = gcmSIZEOF(struct _gckCONTEXT);
+
+        /* Allocate the object. */
+        gckOS_Allocate(Command->os, allocationSize, &pointer);
+        if (!pointer)
+        {
+            return gcvSTATUS_OUT_OF_MEMORY;
+        }
+        *Context = pointer;
+        /* Reset the entire object. */
+        gckOS_ZeroMemory(*Context, allocationSize);
+
+        /* Initialize the gckCONTEXT object. */
+        (*Context)->object.type = gcvOBJ_CONTEXT;
+        (*Context)->os          = Command->os;
+        (*Context)->hardware    = Command->kernel->hardware;
+        *MaxState  = 0;
+        *NumStates = 0;
+
+        status = gcvSTATUS_OK;
+    }
+    else
+    {
+        /* Nothing to do. */
+        *Context   = gcvNULL;
+        *MaxState  = 0;
+        *NumStates = 0;
+
+        status = gcvSTATUS_OK;
+    }
+
+    return status;
+}
+#endif
+
+static gceSTATUS
+_DetachWaitLinkFECommand(
+    IN gckCOMMAND Command,
+    IN gckCONTEXT Context
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p Context=%p", Command, Context);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    /* Acquire the context switching mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(
+        Command->os, Command->mutexContext, gcvINFINITE
+        ));
+    acquired = gcvTRUE;
+
+    /* Construct a gckCONTEXT object. */
+    gcmkONERROR(gckCONTEXT_Destroy(Context));
+
+    if (Command->currContext == Context)
+    {
+        /* Detach from gckCOMMAND object if the destoryed context is current context. */
+        Command->currContext = gcvNULL;
+    }
+
+    /* Release the context switching mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+    acquired = gcvFALSE;
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Release mutex. */
+    if (acquired)
+    {
+        /* Release the context switching mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+        acquired = gcvFALSE;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_Detach
+**
+**  Detach user process.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to a gckCOMMAND object.
+**
+**      gckCONTEXT Context
+**          Pointer to a gckCONTEXT object to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Detach(
+    IN gckCOMMAND Command,
+    IN gckCONTEXT Context
+    )
+{
+    if (Command->feType == gcvHW_FE_WAIT_LINK)
+    {
+        return _DetachWaitLinkFECommand(Command, Context);
+    }
+    else if (Command->feType == gcvHW_FE_MULTI_CHANNEL)
+    {
+        gcmkOS_SAFE_FREE(Context->os, Context);
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        /* Nothing to do. */
+        return gcvSTATUS_OK;
+    }
+}
+
+static void
+_DumpBuffer(
+    IN gctPOINTER Buffer,
+    IN gctUINT32 GpuAddress,
+    IN gctSIZE_T Size
+    )
+{
+    gctSIZE_T i, line, left;
+    gctUINT32_PTR data = Buffer;
+
+    line = Size / 32;
+    left = Size % 32;
+
+    for (i = 0; i < line; i++)
+    {
+        gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X %08X %08X",
+                  GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+        data += 8;
+        GpuAddress += 8 * 4;
+    }
+
+    switch(left)
+    {
+        case 28:
+            gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X %08X",
+                      GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
+            break;
+        case 24:
+            gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X",
+                      GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5]);
+            break;
+        case 20:
+            gcmkPRINT("%08X : %08X %08X %08X %08X %08X",
+                      GpuAddress, data[0], data[1], data[2], data[3], data[4]);
+            break;
+        case 16:
+            gcmkPRINT("%08X : %08X %08X %08X %08X",
+                      GpuAddress, data[0], data[1], data[2], data[3]);
+            break;
+        case 12:
+            gcmkPRINT("%08X : %08X %08X %08X",
+                      GpuAddress, data[0], data[1], data[2]);
+            break;
+        case 8:
+            gcmkPRINT("%08X : %08X %08X",
+                      GpuAddress, data[0], data[1]);
+            break;
+        case 4:
+            gcmkPRINT("%08X : %08X",
+                      GpuAddress, data[0]);
+            break;
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+**  gckCOMMAND_DumpExecutingBuffer
+**
+**  Dump the command buffer which GPU is executing.
+**
+**  INPUT:
+**
+**      gckCOMMAND Command
+**          Pointer to a gckCOMMAND object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckCOMMAND_DumpExecutingBuffer(
+    IN gckCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctUINT32 gpuAddress;
+    gctPOINTER entry = gcvNULL;
+    gckOS os = Command->os;
+    gckKERNEL kernel = Command->kernel;
+    gctUINT32 i;
+    gckQUEUE queue = &kernel->hardware->linkQueue;
+    gctSIZE_T bytes;
+    gctUINT32 offset;
+    gctPOINTER entryDump;
+    gctUINT8 processName[24] = {0};
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("**** COMMAND BUF DUMP ****\n");
+    gcmkPRINT("**************************\n");
+
+    gcmkPRINT("  Submitted commit stamp = %lld", Command->commitStamp - 1);
+    gcmkPRINT("  Executed commit stamp  = %lld", *(gctUINT64_PTR)Command->fence->logical);
+
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(os, kernel->core, 0x664, &gpuAddress));
+    gcmkVERIFY_OK(gckOS_ReadRegisterEx(os, kernel->core, 0x664, &gpuAddress));
+
+    gcmkPRINT("DMA Address 0x%08X", gpuAddress);
+
+    /* Find GPU address in video memory list. */
+    status = gckVIDMEM_NODE_Find(kernel, gpuAddress, &nodeObject, &offset);
+
+    if (gcmIS_SUCCESS(status) && nodeObject->type == gcvVIDMEM_TYPE_COMMAND)
+    {
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+            kernel,
+            nodeObject,
+            gcvFALSE,
+            gcvFALSE,
+            &entryDump
+            ));
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_GetSize(
+            kernel,
+            nodeObject,
+            &bytes
+            ));
+
+        gcmkPRINT("Command buffer around 0x%08X:", gpuAddress);
+
+        /* Align to 4096. */
+        offset &= 0xfffff000;
+        gpuAddress &= 0xfffff000;
+
+        /* Dump max 4096 bytes. */
+        bytes = (bytes - offset) > 4096 ? 4096 : (bytes - offset);
+
+        /* Kernel address of page where stall point stay. */
+        entryDump = (gctUINT8_PTR)entryDump + offset;
+
+        _DumpBuffer(entryDump, gpuAddress, bytes);
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+            kernel,
+            nodeObject,
+            0,
+            gcvFALSE,
+            gcvFALSE
+            ));
+    }
+    else
+    {
+        gcmkPRINT("Can not find command buffer around 0x%08X.\n", gpuAddress);
+    }
+
+    /* new line. */
+    gcmkPRINT("");
+
+    gcmkPRINT("Kernel command buffers:");
+
+    for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+    {
+        entry = Command->queues[i].logical;
+        gpuAddress = Command->queues[i].address;
+
+        gcmkPRINT("command buffer %d at 0x%08X size %u",
+                  i, gpuAddress, Command->pageSize);
+        _DumpBuffer(entry, gpuAddress, Command->pageSize);
+    }
+
+    /* new line. */
+    gcmkPRINT("");
+
+    if (queue->count)
+    {
+        gcmkPRINT("Dump Level is %d, dump %d valid record in link queue:",
+                  Command->kernel->stuckDump, queue->count);
+    }
+
+    for (i = 0; i < queue->count; i++)
+    {
+        gcuQUEUEDATA * queueData;
+        gckLINKDATA linkData;
+
+        gckQUEUE_GetData(queue, i, &queueData);
+
+        linkData = &queueData->linkData;
+
+        /* Get gpu address of this command buffer. */
+        gpuAddress = linkData->start;
+        bytes = linkData->end - gpuAddress;
+
+        processName[0] = '\0';
+        gckOS_GetProcessNameByPid(linkData->pid, sizeof(processName), processName);
+
+        gcmkPRINT("Link record %d: [%08X - %08X] from command %08X %08X pid %u (%s):",
+                  i,
+                  linkData->start,
+                  linkData->end,
+                  linkData->linkLow,
+                  linkData->linkHigh,
+                  linkData->pid,
+                  processName);
+
+        /* Find GPU address in video memory list. */
+        status = gckVIDMEM_NODE_Find(kernel, gpuAddress, &nodeObject, &offset);
+
+        if (gcmIS_SUCCESS(status) && nodeObject->type == gcvVIDMEM_TYPE_COMMAND)
+        {
+            gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                kernel,
+                nodeObject,
+                gcvFALSE,
+                gcvFALSE,
+                &entryDump
+                ));
+
+            /* Kernel address of page where stall point stay. */
+            entryDump = (gctUINT8_PTR)entryDump + offset;
+
+            _DumpBuffer(entryDump, gpuAddress, bytes);
+
+            gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                kernel,
+                nodeObject,
+                0,
+                gcvFALSE,
+                gcvFALSE
+                ));
+        }
+        else
+        {
+            gcmkPRINT("Not found");
+        }
+
+        /* new line. */
+        gcmkPRINT("");
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c
@@ -0,0 +1,3922 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#define _GC_OBJ_ZONE            gcvZONE_COMMAND
+
+#ifdef __QNXNTO__
+extern gceSTATUS
+drv_signal_mgr_add(
+    gctUINT32 Pid,
+    gctINT32 Coid,
+    gctINT32 Rcvid,
+    gctUINT64 Signal,
+    gctPOINTER *Handle);
+#endif
+
+/******************************************************************************\
+*********************************** Debugging **********************************
+\******************************************************************************/
+
+#define gcvDISABLE_TIMEOUT      1
+#define gcvDUMP_COMMAND_BUFFER  0
+#define gcvDUMP_COMMAND_LINES   0
+
+
+#if gcvDEBUG || defined(EMULATOR) || gcvDISABLE_TIMEOUT
+#   define gcvQUEUE_TIMEOUT ~0
+#else
+#   define gcvQUEUE_TIMEOUT 10
+#endif
+
+
+/******************************************************************************\
+********************************** Definitions *********************************
+\******************************************************************************/
+
+/* Minimum buffer size. */
+#define gcvMINUMUM_BUFFER \
+    gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + \
+    gcmSIZEOF(gcsKERNEL_CMDQUEUE) * 2
+
+#define gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
+    static gceSTATUS \
+    _EventHandler_##Block##_##Number( \
+        IN gckVGKERNEL Kernel \
+        )
+
+#define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \
+    gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
+    { \
+        return _EventHandler_Block( \
+            Kernel, \
+            &Kernel->command->taskTable[gcvBLOCK_##Block], \
+            gcvFALSE \
+            ); \
+    }
+
+#define gcmDEFINE_INTERRUPT_HANDLER_ENTRY(Block, Number) \
+    { gcvBLOCK_##Block, _EventHandler_##Block##_##Number }
+
+/* Block interrupt handling table entry. */
+typedef struct _gcsBLOCK_INTERRUPT_HANDLER * gcsBLOCK_INTERRUPT_HANDLER_PTR;
+typedef struct _gcsBLOCK_INTERRUPT_HANDLER
+{
+    gceBLOCK                block;
+    gctINTERRUPT_HANDLER    handler;
+}
+gcsBLOCK_INTERRUPT_HANDLER;
+
+/* Queue control functions. */
+typedef struct _gcsQUEUE_UPDATE_CONTROL * gcsQUEUE_UPDATE_CONTROL_PTR;
+typedef struct _gcsQUEUE_UPDATE_CONTROL
+{
+    gctOBJECT_HANDLER       execute;
+    gctOBJECT_HANDLER       update;
+    gctOBJECT_HANDLER       lastExecute;
+    gctOBJECT_HANDLER       lastUpdate;
+}
+gcsQUEUE_UPDATE_CONTROL;
+
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_FlushMMU(
+    IN gckVGCOMMAND Command
+    )
+{
+    gceSTATUS status;
+    gctUINT32 oldValue;
+    gckVGHARDWARE hardware = Command->hardware;
+
+    gcmkONERROR(gckOS_AtomicExchange(Command->os,
+                                     hardware->pageTableDirty,
+                                     0,
+                                     &oldValue));
+
+    if (oldValue)
+    {
+        /* Page Table is upated, flush mmu before commit. */
+        gcmkONERROR(gckVGHARDWARE_FlushMMU(hardware));
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_WaitForIdle(
+    IN gckVGCOMMAND Command,
+    IN gcsKERNEL_QUEUE_HEADER_PTR Queue
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 idle;
+    gctUINT timeout = 0;
+
+    /* Loop while not idle. */
+    while (Queue->pending)
+    {
+        /* Did we reach the timeout limit? */
+        if (timeout == gcvQUEUE_TIMEOUT)
+        {
+            /* Hardware is probably dead... */
+            return gcvSTATUS_TIMEOUT;
+        }
+
+        /* Sleep for 100ms. */
+        gcmkERR_BREAK(gckOS_Delay(Command->os, 100));
+
+        /* Not the first loop? */
+        if (timeout > 0)
+        {
+            /* Read IDLE register. */
+            gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command->hardware, &idle));
+
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_COMMAND,
+                "%s: timeout, IDLE=%08X\n",
+                __FUNCTION__, idle
+                );
+        }
+
+        /* Increment the timeout counter. */
+        timeout += 1;
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gctINT32
+_GetNextInterrupt(
+    IN gckVGCOMMAND Command,
+    IN gceBLOCK Block
+    )
+{
+    gctUINT index;
+    gcsBLOCK_TASK_ENTRY_PTR entry;
+    gctINT32 interrupt;
+
+    /* Get the block entry. */
+    entry = &Command->taskTable[Block];
+
+    /* Make sure we have initialized interrupts. */
+    gcmkASSERT(entry->interruptCount > 0);
+
+    /* Decrement the interrupt usage semaphore. */
+    gcmkVERIFY_OK(gckOS_DecrementSemaphore(
+        Command->os, entry->interruptSemaphore
+        ));
+
+    /* Get the value index. */
+    index = entry->interruptIndex;
+
+    /* Get the interrupt value. */
+    interrupt = entry->interruptArray[index];
+
+    /* Must be a valid value. */
+    gcmkASSERT((interrupt >= 0) && (interrupt <= 31));
+
+    /* Advance the index to the next value. */
+    index += 1;
+
+    /* Set the new index. */
+    entry->interruptIndex = (index == entry->interruptCount)
+        ? 0
+        : index;
+
+    /* Return interrupt value. */
+    return interrupt;
+}
+
+
+/******************************************************************************\
+***************************** Task Storage Management **************************
+\******************************************************************************/
+
+/* Minimum task buffer size. */
+#define gcvMIN_TASK_BUFFER \
+( \
+    gcmSIZEOF(gcsTASK_CONTAINER) + 128 \
+)
+
+/* Free list terminator. */
+#define gcvFREE_TASK_TERMINATOR \
+( \
+    (gcsTASK_CONTAINER_PTR) gcmINT2PTR(~0) \
+)
+
+
+/*----------------------------------------------------------------------------*/
+/*------------------- Allocated Task Buffer List Management ------------------*/
+
+static void
+_InsertTaskBuffer(
+    IN gcsTASK_CONTAINER_PTR AddAfter,
+    IN gcsTASK_CONTAINER_PTR Buffer
+    )
+{
+    gcsTASK_CONTAINER_PTR addBefore;
+
+    /* Cannot add before the first buffer. */
+    gcmkASSERT(AddAfter != gcvNULL);
+
+    /* Create a shortcut to the next buffer. */
+    addBefore = AddAfter->allocNext;
+
+    /* Initialize the links. */
+    Buffer->allocPrev = AddAfter;
+    Buffer->allocNext = addBefore;
+
+    /* Link to the previous buffer. */
+    AddAfter->allocNext = Buffer;
+
+    /* Link to the next buffer. */
+    if (addBefore != gcvNULL)
+    {
+        addBefore->allocPrev = Buffer;
+    }
+}
+
+static void
+_RemoveTaskBuffer(
+    IN gcsTASK_CONTAINER_PTR Buffer
+    )
+{
+    gcsTASK_CONTAINER_PTR prev;
+    gcsTASK_CONTAINER_PTR next;
+
+    /* Cannot remove the first buffer. */
+    gcmkASSERT(Buffer->allocPrev != gcvNULL);
+
+    /* Create shortcuts to the previous and next buffers. */
+    prev = Buffer->allocPrev;
+    next = Buffer->allocNext;
+
+    /* Tail buffer? */
+    if (next == gcvNULL)
+    {
+        /* Remove from the list. */
+        prev->allocNext = gcvNULL;
+    }
+
+    /* Buffer from the middle. */
+    else
+    {
+        prev->allocNext = next;
+        next->allocPrev = prev;
+    }
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*--------------------- Free Task Buffer List Management ---------------------*/
+
+static void
+_AppendToFreeList(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_CONTAINER_PTR Buffer
+    )
+{
+    /* Cannot be a part of the free list already. */
+    gcmkASSERT(Buffer->freePrev == gcvNULL);
+    gcmkASSERT(Buffer->freeNext == gcvNULL);
+
+    /* First buffer to add? */
+    if (Command->taskFreeHead == gcvNULL)
+    {
+        /* Terminate the links. */
+        Buffer->freePrev = gcvFREE_TASK_TERMINATOR;
+        Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
+
+        /* Initialize the list pointer. */
+        Command->taskFreeHead = Command->taskFreeTail = Buffer;
+    }
+
+    /* Not the first, add after the tail. */
+    else
+    {
+        /* Initialize the new tail buffer. */
+        Buffer->freePrev = Command->taskFreeTail;
+        Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
+
+        /* Add after the tail. */
+        Command->taskFreeTail->freeNext = Buffer;
+        Command->taskFreeTail = Buffer;
+    }
+}
+
+static void
+_RemoveFromFreeList(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_CONTAINER_PTR Buffer
+    )
+{
+    /* Has to be a part of the free list. */
+    gcmkASSERT(Buffer->freePrev != gcvNULL);
+    gcmkASSERT(Buffer->freeNext != gcvNULL);
+
+    /* Head buffer? */
+    if (Buffer->freePrev == gcvFREE_TASK_TERMINATOR)
+    {
+        /* Tail buffer as well? */
+        if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
+        {
+            /* Reset the list pointer. */
+            Command->taskFreeHead = Command->taskFreeTail = gcvNULL;
+        }
+
+        /* No, just the head. */
+        else
+        {
+            /* Update the head. */
+            Command->taskFreeHead = Buffer->freeNext;
+
+            /* Terminate the next buffer. */
+            Command->taskFreeHead->freePrev = gcvFREE_TASK_TERMINATOR;
+        }
+    }
+
+    /* Not the head. */
+    else
+    {
+        /* Tail buffer? */
+        if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
+        {
+            /* Update the tail. */
+            Command->taskFreeTail = Buffer->freePrev;
+
+            /* Terminate the previous buffer. */
+            Command->taskFreeTail->freeNext = gcvFREE_TASK_TERMINATOR;
+        }
+
+        /* A buffer in the middle. */
+        else
+        {
+            /* Remove the buffer from the list. */
+            Buffer->freePrev->freeNext = Buffer->freeNext;
+            Buffer->freeNext->freePrev = Buffer->freePrev;
+        }
+    }
+
+    /* Reset free list pointers. */
+    Buffer->freePrev = gcvNULL;
+    Buffer->freeNext = gcvNULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*-------------------------- Task Buffer Allocation --------------------------*/
+
+static void
+_SplitTaskBuffer(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_CONTAINER_PTR Buffer,
+    IN gctUINT Size
+    )
+{
+    /* Determine the size of the new buffer. */
+    gctINT splitBufferSize = Buffer->size - Size;
+    gcmkASSERT(splitBufferSize >= 0);
+
+    /* Is the split buffer big enough to become a separate buffer? */
+    if (splitBufferSize >= gcvMIN_TASK_BUFFER)
+    {
+        /* Place the new path data. */
+        gcsTASK_CONTAINER_PTR splitBuffer = (gcsTASK_CONTAINER_PTR)
+        (
+            (gctUINT8_PTR) Buffer + Size
+        );
+
+        /* Set the trimmed buffer size. */
+        Buffer->size = Size;
+
+        /* Initialize the split buffer. */
+        splitBuffer->referenceCount = 0;
+        splitBuffer->size           = splitBufferSize;
+        splitBuffer->freePrev       = gcvNULL;
+        splitBuffer->freeNext       = gcvNULL;
+
+        /* Link in. */
+        _InsertTaskBuffer(Buffer, splitBuffer);
+        _AppendToFreeList(Command, splitBuffer);
+    }
+}
+
+static gceSTATUS
+_AllocateTaskContainer(
+    IN gckVGCOMMAND Command,
+    IN gctUINT Size,
+    OUT gcsTASK_CONTAINER_PTR * Buffer
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p Size=0x%x, Buffer =%p", Command, Size, Buffer);
+
+    /* Verify arguments. */
+    gcmkVERIFY_ARGUMENT(Buffer != gcvNULL);
+
+    do
+    {
+        gcsTASK_STORAGE_PTR storage;
+        gcsTASK_CONTAINER_PTR buffer;
+
+        /* Adjust the size. */
+        Size += gcmSIZEOF(gcsTASK_CONTAINER);
+
+        /* Adjust the allocation size if not big enough. */
+        if (Size > Command->taskStorageUsable)
+        {
+            Command->taskStorageGranularity
+                = gcmALIGN(Size + gcmSIZEOF(gcsTASK_STORAGE), 1024);
+
+            Command->taskStorageUsable
+                = Command->taskStorageGranularity - gcmSIZEOF(gcsTASK_STORAGE);
+        }
+
+        /* Is there a free buffer available? */
+        else if (Command->taskFreeHead != gcvNULL)
+        {
+            /* Set the initial free buffer. */
+            gcsTASK_CONTAINER_PTR buffer = Command->taskFreeHead;
+
+            do
+            {
+                /* Is the buffer big enough? */
+                if (buffer->size >= Size)
+                {
+                    /* Remove the buffer from the free list. */
+                    _RemoveFromFreeList(Command, buffer);
+
+                    /* Split the buffer. */
+                    _SplitTaskBuffer(Command, buffer, Size);
+
+                    /* Set the result. */
+                    * Buffer = buffer;
+
+                    gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer);
+                    /* Success. */
+                    return gcvSTATUS_OK;
+                }
+
+                /* Get the next free buffer. */
+                buffer = buffer->freeNext;
+            }
+            while (buffer != gcvFREE_TASK_TERMINATOR);
+        }
+
+        /* Allocate a container. */
+        gcmkERR_BREAK(gckOS_Allocate(
+            Command->os,
+            Command->taskStorageGranularity,
+            (gctPOINTER *) &storage
+            ));
+
+        /* Link in the storage buffer. */
+        storage->next = Command->taskStorage;
+        Command->taskStorage = storage;
+
+        /* Place the task buffer. */
+        buffer = (gcsTASK_CONTAINER_PTR) (storage + 1);
+
+        /* Determine the size of the buffer. */
+        buffer->size
+            = Command->taskStorageGranularity
+            - gcmSIZEOF(gcsTASK_STORAGE);
+
+        /* Initialize the task buffer. */
+        buffer->referenceCount = 0;
+        buffer->allocPrev      = gcvNULL;
+        buffer->allocNext      = gcvNULL;
+        buffer->freePrev       = gcvNULL;
+        buffer->freeNext       = gcvNULL;
+
+        /* Split the buffer. */
+        _SplitTaskBuffer(Command, buffer, Size);
+
+        /* Set the result. */
+        * Buffer = buffer;
+
+        gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer);
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+static void
+_FreeTaskContainer(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_CONTAINER_PTR Buffer
+    )
+{
+    gcsTASK_CONTAINER_PTR prev;
+    gcsTASK_CONTAINER_PTR next;
+    gcsTASK_CONTAINER_PTR merged;
+
+    gctUINT32 mergedSize;
+
+    /* Verify arguments. */
+    gcmkASSERT(Buffer != gcvNULL);
+    gcmkASSERT(Buffer->freePrev == gcvNULL);
+    gcmkASSERT(Buffer->freeNext == gcvNULL);
+
+    /* Get shortcuts to the previous and next path data buffers. */
+    prev = Buffer->allocPrev;
+    next = Buffer->allocNext;
+
+    /* Is the previous path data buffer already free? */
+    if (prev && prev->freeNext)
+    {
+        /* The previous path data buffer is the one that remains. */
+        merged = prev;
+
+        /* Is the next path data buffer already free? */
+        if (next && next->freeNext)
+        {
+            /* Merge all three path data buffers into the previous. */
+            mergedSize = prev->size + Buffer->size + next->size;
+
+            /* Remove the next path data buffer. */
+            _RemoveFromFreeList(Command, next);
+            _RemoveTaskBuffer(next);
+        }
+        else
+        {
+            /* Merge the current path data buffer into the previous. */
+            mergedSize = prev->size + Buffer->size;
+        }
+
+        /* Delete the current path data buffer. */
+        _RemoveTaskBuffer(Buffer);
+
+        /* Set new size. */
+        merged->size = mergedSize;
+    }
+    else
+    {
+        /* The current path data buffer is the one that remains. */
+        merged = Buffer;
+
+        /* Is the next buffer already free? */
+        if (next && next->freeNext)
+        {
+            /* Merge the next into the current. */
+            mergedSize = Buffer->size + next->size;
+
+            /* Remove the next buffer. */
+            _RemoveFromFreeList(Command, next);
+            _RemoveTaskBuffer(next);
+
+            /* Set new size. */
+            merged->size = mergedSize;
+        }
+
+        /* Add the current buffer into the free list. */
+        _AppendToFreeList(Command, merged);
+    }
+}
+
+gceSTATUS
+_RemoveRecordFromProcesDB(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_HEADER_PTR Task
+    )
+{
+    gceSTATUS status;
+    gcsTASK_PTR task = (gcsTASK_PTR)((gctUINT8_PTR)Task - sizeof(gcsTASK));
+    gcsTASK_FREE_VIDEO_MEMORY_PTR freeVideoMemory;
+    gcsTASK_UNLOCK_VIDEO_MEMORY_PTR unlockVideoMemory;
+    gctINT pid;
+    gctUINT32 size,id;
+    gctUINT32 handle;
+    gckKERNEL kernel = Command->kernel->kernel;
+    gckVIDMEM_NODE unlockNode = gcvNULL;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gceDATABASE_TYPE type;
+
+    /* Get the total size of all tasks. */
+
+    gcmkVERIFY_OK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+    gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &task->size, &size));
+
+    do
+    {
+        gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &Task->id, &id));
+        switch (id)
+        {
+        case gcvTASK_FREE_VIDEO_MEMORY:
+            freeVideoMemory = (gcsTASK_FREE_VIDEO_MEMORY_PTR)Task;
+
+            gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &freeVideoMemory->node, &handle));
+
+            status = gckVIDMEM_HANDLE_Lookup(
+                Command->kernel->kernel,
+                pid,
+                handle,
+                &nodeObject);
+
+            if (gcmIS_ERROR(status))
+            {
+                return status;
+            }
+
+            gckVIDMEM_HANDLE_Dereference(kernel, pid, handle);
+            gcmkVERIFY_OK(gckOS_WriteMemory(Command->os, &freeVideoMemory->node, gcmALL_TO_UINT32(nodeObject)));
+
+            type = gcvDB_VIDEO_MEMORY
+                | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+                | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+            /* Remove record from process db. */
+            gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+                Command->kernel->kernel,
+                pid,
+                type,
+                gcmINT2PTR(handle)));
+
+            /* Advance to next task. */
+            size -= sizeof(gcsTASK_FREE_VIDEO_MEMORY);
+            Task = (gcsTASK_HEADER_PTR)(freeVideoMemory + 1);
+
+            break;
+        case gcvTASK_UNLOCK_VIDEO_MEMORY:
+            unlockVideoMemory = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR)Task;
+
+            gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &unlockVideoMemory->node, &handle));
+            /* Remove record from process db. */
+            gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+                Command->kernel->kernel,
+                pid,
+                gcvDB_VIDEO_MEMORY_LOCKED,
+                gcmUINT64_TO_PTR(handle)));
+
+
+            status = gckVIDMEM_HANDLE_Lookup(
+                Command->kernel->kernel,
+                pid,
+                handle,
+                &unlockNode);
+
+            if (gcmIS_ERROR(status))
+            {
+                return status;
+            }
+
+            gckVIDMEM_HANDLE_Dereference(kernel, pid, handle);
+            gcmkVERIFY_OK(gckOS_WriteMemory(Command->os, &unlockVideoMemory->node, gcmALL_TO_UINT32(unlockNode)));
+
+            /* Advance to next task. */
+            size -= sizeof(gcsTASK_UNLOCK_VIDEO_MEMORY);
+            Task = (gcsTASK_HEADER_PTR)(unlockVideoMemory + 1);
+
+            break;
+        default:
+            /* Skip the whole task. */
+            size = 0;
+            break;
+        }
+    }
+    while(size);
+
+    return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+********************************* Task Scheduling ******************************
+\******************************************************************************/
+
+static gceSTATUS
+_ScheduleTasks(
+    IN gckVGCOMMAND Command,
+    IN gcsTASK_MASTER_TABLE_PTR TaskTable,
+    IN gctUINT8_PTR PreviousEnd
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        gctINT block;
+        gcsTASK_CONTAINER_PTR container;
+        gcsTASK_MASTER_ENTRY_PTR userTaskEntry;
+        gcsBLOCK_TASK_ENTRY_PTR kernelTaskEntry;
+        gcsTASK_PTR userTask;
+        gcsTASK userTaskObject;
+        gctUINT8_PTR kernelTask;
+        gctINT32 interrupt;
+        gctUINT8_PTR eventCommand;
+        gctBOOL needCopy = gcvFALSE;
+        gctINT pid;
+#ifdef __QNXNTO__
+        gcsTASK_PTR oldUserTask = gcvNULL;
+        gctPOINTER pointer;
+#endif
+
+        /* Nothing to schedule? */
+        if (TaskTable->size == 0)
+        {
+            status = gcvSTATUS_OK;
+            break;
+        }
+
+        /* Acquire the mutex. */
+        gcmkERR_BREAK(gckOS_AcquireMutex(
+            Command->os,
+            Command->taskMutex,
+            gcvINFINITE
+            ));
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "%s(%d)\n",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkVERIFY_OK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+        gcmkVERIFY_OK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+        do
+        {
+            gcmkTRACE_ZONE(
+                    gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                "  number of tasks scheduled   = %d\n"
+                "  size of event data in bytes = %d\n",
+                TaskTable->count,
+                TaskTable->size
+                );
+
+            /* Allocate task buffer. */
+            gcmkERR_BREAK(_AllocateTaskContainer(
+                Command,
+                TaskTable->size,
+                &container
+                ));
+
+            /* Determine the task data pointer. */
+            kernelTask = (gctUINT8_PTR) (container + 1);
+
+            /* Initialize the reference count. */
+            container->referenceCount = TaskTable->count;
+
+            /* Process tasks. */
+            for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
+            {
+                /* Get the current user table entry. */
+                userTaskEntry = &TaskTable->table[block];
+
+                /* Are there tasks scheduled? */
+                if (userTaskEntry->head == gcvNULL)
+                {
+                    /* No, skip to the next block. */
+                    continue;
+                }
+
+                gcmkTRACE_ZONE(
+                        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                        "  processing tasks for block %d\n",
+                        block
+                    );
+
+                /* Get the current kernel table entry. */
+                kernelTaskEntry = &Command->taskTable[block];
+
+                /* Are there tasks for the current block scheduled? */
+                if (kernelTaskEntry->container == gcvNULL)
+                {
+                    gcmkTRACE_ZONE(
+                        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                        "  first task container for the block added\n",
+                        block
+                        );
+
+                    /* Nothing yet, set the container buffer pointer. */
+                    kernelTaskEntry->container = container;
+                    kernelTaskEntry->task      = (gcsTASK_HEADER_PTR) kernelTask;
+                }
+
+                /* Yes, append to the end. */
+                else
+                {
+                    kernelTaskEntry->link->cotainer = container;
+                    kernelTaskEntry->link->task     = (gcsTASK_HEADER_PTR) kernelTask;
+                }
+
+                /* Set initial task. */
+                userTask = userTaskEntry->head;
+
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                    "  copying user tasks over to the kernel\n"
+                    );
+
+                /* Copy tasks. */
+                do
+                {
+                    gcsTASK_HEADER_PTR taskHeader;
+#ifdef __QNXNTO__
+                    oldUserTask = userTask;
+
+                    gcmkERR_BREAK(gckOS_MapUserPointer(
+                                Command->os,
+                                oldUserTask,
+                                0,
+                                &pointer));
+
+                    userTask = pointer;
+#endif
+                    taskHeader = (gcsTASK_HEADER_PTR) (userTask + 1);
+                    if(needCopy)
+                    {
+                        gcmkERR_BREAK(gckOS_CopyFromUserData(
+                                    Command->os,
+                                    &userTaskObject,
+                                    userTask,
+                                    gcmSIZEOF(gcsTASK)
+                                    ));
+                        userTask = &userTaskObject;
+                    }
+
+                    gcmkVERIFY_OK(_RemoveRecordFromProcesDB(Command, taskHeader));
+
+                    gcmkTRACE_ZONE(
+                            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                            "    task ID = %d, size = %d\n",
+                            ((gcsTASK_HEADER_PTR) (userTask + 1))->id,
+                            userTask->size
+                            );
+
+                    /* Copy the task data. */
+                    if(needCopy)
+                    {
+                        gcmkERR_BREAK(gckOS_CopyFromUserData(
+                                    Command->os,
+                                    kernelTask,
+                                    taskHeader,
+                                    userTask->size
+                                    ));
+                    }
+                    else
+                    {
+
+                        gcmkERR_BREAK(gckOS_MemCopy(
+                                    kernelTask, taskHeader, userTask->size
+                                    ));
+                    }
+#ifdef __QNXNTO__
+                    if (taskHeader->id == gcvTASK_SIGNAL)
+                    {
+                        gcsTASK_SIGNAL_PTR taskSignal = (gcsTASK_SIGNAL_PTR)kernelTask;
+                        gctPOINTER signal;
+                        gctUINT32 pid;
+
+                        gcmkVERIFY_OK(gckOS_GetProcessID(&pid));
+
+                        taskSignal->coid  = TaskTable->coid;
+                        taskSignal->rcvid = TaskTable->rcvid;
+
+                        gcmkERR_BREAK(drv_signal_mgr_add(
+                                    pid,
+                                    taskSignal->coid,
+                                    taskSignal->rcvid,
+                                    gcmPTR_TO_UINT64(taskSignal->signal),
+                                    &signal));
+
+                        taskSignal->signal = signal;
+                    }
+#endif
+
+                    /* Advance to the next task. */
+                    kernelTask += userTask->size;
+                    userTask    = userTask->next;
+
+#ifdef __QNXNTO__
+                    gcmkERR_BREAK(gckOS_UnmapUserPointer(
+                        Command->os,
+                        oldUserTask,
+                        0,
+                        pointer));
+#endif
+                }
+                while (userTask != gcvNULL);
+
+                /* Update link pointer in the header. */
+                kernelTaskEntry->link = (gcsTASK_LINK_PTR) kernelTask;
+
+                /* Initialize link task. */
+                kernelTaskEntry->link->id       = gcvTASK_LINK;
+                kernelTaskEntry->link->cotainer = gcvNULL;
+                kernelTaskEntry->link->task     = gcvNULL;
+
+                /* Advance the task data pointer. */
+                kernelTask += gcmSIZEOF(gcsTASK_LINK);
+            }
+        }
+        while (gcvFALSE);
+
+        /* Release the mutex. */
+        gcmkERR_BREAK(gckOS_ReleaseMutex(
+                    Command->os,
+                    Command->taskMutex
+                    ));
+
+        /* Assign interrupts to the blocks. */
+        eventCommand = PreviousEnd;
+
+        for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
+        {
+            /* Get the current user table entry. */
+            userTaskEntry = &TaskTable->table[block];
+
+            /* Are there tasks scheduled? */
+            if (userTaskEntry->head == gcvNULL)
+            {
+                /* No, skip to the next block. */
+                continue;
+            }
+
+            /* Get the interrupt number. */
+            interrupt = _GetNextInterrupt(Command, block);
+
+            gcmkTRACE_ZONE(
+                    gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                    "%s(%d): block = %d interrupt = %d\n",
+                    __FUNCTION__, __LINE__,
+                    block, interrupt
+                );
+
+            /* Determine the command position. */
+            eventCommand -= Command->info.eventCommandSize;
+
+            /* Append an EVENT command. */
+            gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+                Command, eventCommand, block, interrupt, gcvNULL
+                ));
+        }
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+
+/******************************************************************************\
+******************************** Memory Management *****************************
+\******************************************************************************/
+
+static gceSTATUS
+_HardwareToKernel(
+    IN gckOS Os,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN gctUINT32 Address,
+    OUT gctPOINTER * KernelPointer
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM memory;
+    gctUINT32 offset;
+    gctUINT32 nodePhysical;
+    gctPOINTER *logical;
+    gctSIZE_T bytes;
+    status = gcvSTATUS_OK;
+
+    memory = Node->VidMem.parent;
+
+    if (memory->object.type == gcvOBJ_VIDMEM)
+    {
+        nodePhysical = (gctUINT32)memory->physicalBase
+                     + (gctUINT32)Node->VidMem.offset
+                     + Node->VidMem.alignment;
+        bytes = Node->VidMem.bytes;
+        logical = &Node->VidMem.kernelVirtual;
+    }
+    else
+    {
+        gcmkSAFECASTPHYSADDRT(nodePhysical, Node->Virtual.physicalAddress);
+        bytes = Node->Virtual.bytes;
+        logical = &Node->Virtual.kernelVirtual;
+    }
+
+    if (*logical == gcvNULL)
+    {
+        status = gckOS_MapPhysical(Os, nodePhysical, bytes, logical);
+
+        if (gcmkIS_ERROR(status))
+        {
+            return status;
+        }
+    }
+
+    offset = Address - nodePhysical;
+    *KernelPointer = (gctPOINTER)((gctUINT8_PTR)(*logical) + offset);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_ConvertUserCommandBufferPointer(
+    IN gckVGCOMMAND Command,
+    IN gcsCMDBUFFER_PTR UserCommandBuffer,
+    OUT gcsCMDBUFFER_PTR * KernelCommandBuffer
+    )
+{
+    gceSTATUS status, last;
+    gcsCMDBUFFER_PTR mappedUserCommandBuffer = gcvNULL;
+    gcsCMDBUFFER _CommandBufferObject;
+    gckKERNEL kernel = Command->kernel->kernel;
+    gctUINT32 pid;
+    gckVIDMEM_NODE node;
+    gctBOOL needCopy = gcvFALSE;
+
+    gckOS_GetProcessID(&pid);
+
+    do
+    {
+        gctUINT32 headerAddress;
+
+        gcmkERR_BREAK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+        if(needCopy)
+        {
+            gcmkERR_BREAK(gckOS_CopyFromUserData(
+                        Command->os,
+                        &_CommandBufferObject,
+                        UserCommandBuffer,
+                        gcmSIZEOF(gcsCMDBUFFER)
+                        ));
+            mappedUserCommandBuffer = &_CommandBufferObject;
+        }
+        else
+        {
+            /* Map the command buffer structure into the kernel space. */
+            gcmkERR_BREAK(gckOS_MapUserPointer(
+                        Command->os,
+                        UserCommandBuffer,
+                        gcmSIZEOF(gcsCMDBUFFER),
+                        (gctPOINTER *) &mappedUserCommandBuffer
+                        ));
+        }
+        /* Determine the address of the header. */
+        headerAddress
+            = mappedUserCommandBuffer->address
+            - mappedUserCommandBuffer->bufferOffset;
+
+        gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(
+                    kernel,
+                    pid,
+                    gcmPTR2INT32(mappedUserCommandBuffer->node),
+                    &node));
+
+        /* Translate the logical address to the kernel space. */
+        gcmkERR_BREAK(_HardwareToKernel(
+                    Command->os,
+                    node->node,
+                    headerAddress,
+                    (gctPOINTER *) KernelCommandBuffer
+            ));
+    }
+    while (gcvFALSE);
+
+    /* Unmap the user command buffer. */
+    if (mappedUserCommandBuffer != gcvNULL && needCopy == gcvFALSE)
+    {
+        gcmkCHECK_STATUS(gckOS_UnmapUserPointer(
+                    Command->os,
+                    UserCommandBuffer,
+                    gcmSIZEOF(gcsCMDBUFFER),
+                    mappedUserCommandBuffer
+                    ));
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_AllocateLinear(
+    IN gckVGCOMMAND Command,
+    IN gctUINT Size,
+    IN gctUINT Alignment,
+    OUT gcuVIDMEM_NODE_PTR * Node,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Logical
+    )
+{
+    gceSTATUS status, last;
+    gctPOINTER logical;
+    gctPHYS_ADDR physical;
+    gctUINT32 address;
+    gctSIZE_T size = Size;
+    gctPHYS_ADDR_T paddr;
+
+    do
+    {
+        gcmkERR_BREAK(gckOS_AllocateNonPagedMemory(
+            Command->os,
+            gcvFALSE,
+            gcvALLOC_FLAG_CONTIGUOUS,
+            &size,
+            &physical,
+            &logical
+            ));
+
+        gcmkERR_BREAK(gckOS_GetPhysicalFromHandle(Command->os, physical, 0, &paddr));
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Command->os, paddr, &paddr));
+
+        gcmkSAFECASTPHYSADDRT(address, paddr);
+
+        /* Set return values. */
+        * Node    = physical;
+        * Address = address;
+        * Logical = logical;
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (physical != gcvNULL)
+    {
+        /* Free the command buffer. */
+        gcmkCHECK_STATUS(gckOS_FreeNonPagedMemory(Command->os, physical, logical, size));
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_FreeLinear(
+    IN gckVGKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN gctPOINTER Logical
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    do
+    {
+        gcmkERR_BREAK(gckOS_FreeNonPagedMemory(Kernel->os, Node, Logical, 1));
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+gceSTATUS
+_AllocateCommandBuffer(
+    IN gckVGCOMMAND Command,
+    IN gctSIZE_T Size,
+    OUT gcsCMDBUFFER_PTR * CommandBuffer
+    )
+{
+    gceSTATUS status, last;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gcsCMDBUFFER_PTR commandBuffer = gcvNULL;
+
+    do
+    {
+        gctUINT alignedHeaderSize;
+        gctUINT requestedSize;
+        gctUINT allocationSize;
+        gctUINT32 address = 0;
+        gctUINT8_PTR endCommand;
+
+        /* Determine the aligned header size. */
+        alignedHeaderSize
+            = (gctUINT32)gcmALIGN(gcmSIZEOF(gcsCMDBUFFER), Command->info.addressAlignment);
+
+        /* Align the requested size. */
+        requestedSize
+            = (gctUINT32)gcmALIGN(Size, Command->info.commandAlignment);
+
+        /* Determine the size of the buffer to allocate. */
+        allocationSize
+            = alignedHeaderSize
+            + requestedSize
+            + (gctUINT32)Command->info.staticTailSize;
+
+        /* Allocate the command buffer. */
+        gcmkERR_BREAK(_AllocateLinear(
+            Command,
+            allocationSize,
+            Command->info.addressAlignment,
+            &node,
+            &address,
+            (gctPOINTER *) &commandBuffer
+            ));
+
+        /* Initialize the structure. */
+        commandBuffer->completion    = gcvVACANT_BUFFER;
+        commandBuffer->node          = node;
+        commandBuffer->address       = address + alignedHeaderSize;
+        commandBuffer->bufferOffset  = alignedHeaderSize;
+        commandBuffer->size          = requestedSize;
+        commandBuffer->offset        = requestedSize;
+        commandBuffer->nextAllocated = gcvNULL;
+        commandBuffer->nextSubBuffer = gcvNULL;
+
+        /* Determine the data count. */
+        commandBuffer->dataCount
+            = (requestedSize + Command->info.staticTailSize)
+            / Command->info.commandAlignment;
+
+        /* Determine the location of the END command. */
+        endCommand
+            = (gctUINT8_PTR) commandBuffer
+            + alignedHeaderSize
+            + requestedSize;
+
+        /* Append an END command. */
+        gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+            Command,
+            endCommand,
+            Command->info.feBufferInt,
+            gcvNULL
+            ));
+
+        /* Set the return pointer. */
+        * CommandBuffer = commandBuffer;
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (node != gcvNULL)
+    {
+        /* Free the command buffer. */
+        gcmkCHECK_STATUS(_FreeLinear(Command->kernel, node, commandBuffer));
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_FreeCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsCMDBUFFER_PTR CommandBuffer
+    )
+{
+    gceSTATUS status;
+
+    /* Free the buffer. */
+    status = _FreeLinear(Kernel, CommandBuffer->node, CommandBuffer);
+
+    /* Return status. */
+    return status;
+}
+
+
+/******************************************************************************\
+****************************** TS Overflow Handler *****************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_TSOverflow(
+    IN gckVGKERNEL Kernel
+    )
+{
+    gcmkTRACE(
+        gcvLEVEL_ERROR,
+        "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n",
+        __FUNCTION__, __LINE__
+        );
+
+    return gcvSTATUS_OK;
+}
+
+
+/******************************************************************************\
+****************************** Bus Error Handler *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_BusError(
+    IN gckVGKERNEL Kernel
+    )
+{
+    gcmkTRACE(
+        gcvLEVEL_ERROR,
+        "%s(%d): **** BUS ERROR ENCOUNTERED ****\n",
+        __FUNCTION__, __LINE__
+        );
+
+    return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+****************************** Power Stall Handler *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_PowerStall(
+    IN gckVGKERNEL Kernel
+    )
+{
+    /* Signal. */
+    return gckOS_Signal(
+        Kernel->os,
+        Kernel->command->powerStallSignal,
+        gcvTRUE);
+}
+
+/******************************************************************************\
+******************************** Task Routines *********************************
+\******************************************************************************/
+
+typedef gceSTATUS (* gctTASKROUTINE) (
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskLink(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskCluster(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskIncrement(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskDecrement(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskSignal(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskLockdown(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskUnlockVideoMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskFreeVideoMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gceSTATUS
+_TaskFreeContiguousMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    );
+
+static gctTASKROUTINE _taskRoutine[] =
+{
+    _TaskLink,                  /* gcvTASK_LINK                   */
+    _TaskCluster,               /* gcvTASK_CLUSTER                */
+    _TaskIncrement,             /* gcvTASK_INCREMENT              */
+    _TaskDecrement,             /* gcvTASK_DECREMENT              */
+    _TaskSignal,                /* gcvTASK_SIGNAL                 */
+    _TaskLockdown,              /* gcvTASK_LOCKDOWN               */
+    _TaskUnlockVideoMemory,     /* gcvTASK_UNLOCK_VIDEO_MEMORY    */
+    _TaskFreeVideoMemory,       /* gcvTASK_FREE_VIDEO_MEMORY      */
+    _TaskFreeContiguousMemory,  /* gcvTASK_FREE_CONTIGUOUS_MEMORY */
+};
+
+static gceSTATUS
+_TaskLink(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    /* Cast the task pointer. */
+    gcsTASK_LINK_PTR task = (gcsTASK_LINK_PTR) TaskHeader->task;
+
+    /* Save the pointer to the container. */
+    gcsTASK_CONTAINER_PTR container = TaskHeader->container;
+
+    /* No more tasks in the list? */
+    if (task->task == gcvNULL)
+    {
+        /* Reset the entry. */
+        TaskHeader->container = gcvNULL;
+        TaskHeader->task      = gcvNULL;
+        TaskHeader->link      = gcvNULL;
+    }
+    else
+    {
+        /* Update the entry. */
+        TaskHeader->container = task->cotainer;
+        TaskHeader->task      = task->task;
+    }
+
+    /* Decrement the task buffer reference. */
+    gcmkASSERT(container->referenceCount >= 0);
+    if (container->referenceCount == 0)
+    {
+        /* Free the container. */
+        _FreeTaskContainer(Command, container);
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_TaskCluster(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /* Cast the task pointer. */
+    gcsTASK_CLUSTER_PTR cluster = (gcsTASK_CLUSTER_PTR) TaskHeader->task;
+
+    /* Get the number of tasks. */
+    gctUINT taskCount = cluster->taskCount;
+
+    /* Advance to the next task. */
+    TaskHeader->task = (gcsTASK_HEADER_PTR) (cluster + 1);
+
+    /* Perform all tasks in the cluster. */
+    while (taskCount)
+    {
+        /* Perform the current task. */
+        gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+            Command,
+            TaskHeader
+            ));
+
+        /* Update the task count. */
+        taskCount -= 1;
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskIncrement(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_INCREMENT_PTR task = (gcsTASK_INCREMENT_PTR) TaskHeader->task;
+
+        /* Convert physical into logical address. */
+        gctUINT32_PTR logical;
+        gcmkERR_BREAK(gckOS_MapPhysical(
+            Command->os,
+            task->address,
+            gcmSIZEOF(gctUINT32),
+            (gctPOINTER *) &logical
+            ));
+
+        /* Increment data. */
+        (* logical) += 1;
+
+        /* Unmap the physical memory. */
+        gcmkERR_BREAK(gckOS_UnmapPhysical(
+            Command->os,
+            logical,
+            gcmSIZEOF(gctUINT32)
+            ));
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskDecrement(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_DECREMENT_PTR task = (gcsTASK_DECREMENT_PTR) TaskHeader->task;
+
+        /* Convert physical into logical address. */
+        gctUINT32_PTR logical;
+        gcmkERR_BREAK(gckOS_MapPhysical(
+            Command->os,
+            task->address,
+            gcmSIZEOF(gctUINT32),
+            (gctPOINTER *) &logical
+            ));
+
+        /* Decrement data. */
+        (* logical) -= 1;
+
+        /* Unmap the physical memory. */
+        gcmkERR_BREAK(gckOS_UnmapPhysical(
+            Command->os,
+            logical,
+            gcmSIZEOF(gctUINT32)
+            ));
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskSignal(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_SIGNAL_PTR task = (gcsTASK_SIGNAL_PTR) TaskHeader->task;
+
+
+        /* Map the signal into kernel space. */
+#ifdef __QNXNTO__
+        status = gckOS_UserSignal(
+            Command->os, task->signal, task->rcvid, task->coid
+            );
+#else
+        status = gckOS_UserSignal(
+            Command->os, task->signal, task->process
+            );
+#endif /* __QNXNTO__ */
+
+        if (gcmIS_ERROR(status))
+        {
+            if (status == gcvSTATUS_NOT_FOUND)
+            {
+                status = gcvSTATUS_OK;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskLockdown(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+    gctUINT32_PTR userCounter   = gcvNULL;
+    gctUINT32_PTR kernelCounter = gcvNULL;
+    gctSIGNAL signal            = gcvNULL;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_LOCKDOWN_PTR task = (gcsTASK_LOCKDOWN_PTR) TaskHeader->task;
+
+        /* Convert physical addresses into logical. */
+        gcmkERR_BREAK(gckOS_MapPhysical(
+            Command->os,
+            task->userCounter,
+            gcmSIZEOF(gctUINT32),
+            (gctPOINTER *) &userCounter
+            ));
+
+        gcmkERR_BREAK(gckOS_MapPhysical(
+            Command->os,
+            task->kernelCounter,
+            gcmSIZEOF(gctUINT32),
+            (gctPOINTER *) &kernelCounter
+            ));
+
+        /* Update the kernel counter. */
+        (* kernelCounter) += 1;
+
+        /* Are the counters equal? */
+        if ((* userCounter) == (* kernelCounter))
+        {
+            /* Map the signal into kernel space. */
+            gcmkERR_BREAK(gckOS_MapSignal(
+                Command->os, task->signal, task->process, &signal
+                ));
+
+            if (signal == gcvNULL)
+            {
+                /* Signal. */
+                gcmkERR_BREAK(gckOS_Signal(
+                    Command->os, task->signal, gcvTRUE
+                    ));
+            }
+            else
+            {
+                /* Signal. */
+                gcmkERR_BREAK(gckOS_Signal(
+                    Command->os, signal, gcvTRUE
+                    ));
+            }
+        }
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Destroy the mapped signal. */
+    if (signal != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_DestroySignal(
+            Command->os, signal
+            ));
+    }
+
+    /* Unmap the physical memory. */
+    if (kernelCounter != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapPhysical(
+            Command->os,
+            kernelCounter,
+            gcmSIZEOF(gctUINT32)
+            ));
+    }
+
+    if (userCounter != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_UnmapPhysical(
+            Command->os,
+            userCounter,
+            gcmSIZEOF(gctUINT32)
+            ));
+    }
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskUnlockVideoMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        gctUINT32 processID;
+
+        /* Cast the task pointer. */
+        gcsTASK_UNLOCK_VIDEO_MEMORY_PTR task
+            = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR) TaskHeader->task;
+
+        gckOS_GetProcessID(&processID);
+
+        /* Unlock video memory. */
+        gcmkERR_BREAK(gckVIDMEM_NODE_Unlock(
+            Command->kernel->kernel,
+            (gckVIDMEM_NODE)gcmUINT64_TO_PTR(task->node),
+            processID,
+            gcvNULL));
+
+        gcmkERR_BREAK(gckVIDMEM_NODE_Dereference(
+            Command->kernel->kernel,
+            gcmUINT64_TO_PTR(task->node)));
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskFreeVideoMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_FREE_VIDEO_MEMORY_PTR task
+            = (gcsTASK_FREE_VIDEO_MEMORY_PTR) TaskHeader->task;
+
+        /* Free video memory. */
+        gcmkERR_BREAK(gckVIDMEM_NODE_Dereference(
+            Command->kernel->kernel,
+            gcmINT2PTR(task->node)));
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_TaskFreeContiguousMemory(
+    gckVGCOMMAND Command,
+    gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the task pointer. */
+        gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR task
+            = (gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR) TaskHeader->task;
+
+        /* Free contiguous memory. */
+        gcmkERR_BREAK(gckOS_FreeNonPagedMemory(
+            Command->os, task->physical, task->logical, task->bytes
+            ));
+
+        /* Update the reference counter. */
+        TaskHeader->container->referenceCount -= 1;
+
+        /* Update the task pointer. */
+        TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+/******************************************************************************\
+************ Hardware Block Interrupt Handlers For Scheduled Events ************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_Block(
+    IN gckVGKERNEL Kernel,
+    IN gcsBLOCK_TASK_ENTRY_PTR TaskHeader,
+    IN gctBOOL ProcessAll
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK, last;
+
+    gcmkHEADER_ARG("Kernel=%p TaskHeader=%p ProcessAll=0x%x", Kernel, TaskHeader, ProcessAll);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    if (TaskHeader->task == gcvNULL)
+    {
+        gcmkFOOTER();
+        return gcvSTATUS_OK;
+    }
+
+    do
+    {
+        gckVGCOMMAND command;
+
+        /* Get the command buffer object. */
+        command = Kernel->command;
+
+        /* Increment the interrupt usage semaphore. */
+        gcmkERR_BREAK(gckOS_IncrementSemaphore(
+            command->os, TaskHeader->interruptSemaphore
+            ));
+
+        /* Acquire the mutex. */
+        gcmkERR_BREAK(gckOS_AcquireMutex(
+            command->os,
+            command->taskMutex,
+            gcvINFINITE
+            ));
+
+        /* Verify inputs. */
+        gcmkASSERT(TaskHeader            != gcvNULL);
+        gcmkASSERT(TaskHeader->container != gcvNULL);
+        gcmkASSERT(TaskHeader->task      != gcvNULL);
+        gcmkASSERT(TaskHeader->link      != gcvNULL);
+
+        /* Process tasks. */
+        do
+        {
+            /* Process the current task. */
+            gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+                command,
+                TaskHeader
+                ));
+
+            /* Is the next task is LINK? */
+            if (TaskHeader->task->id == gcvTASK_LINK)
+            {
+                gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+                    command,
+                    TaskHeader
+                    ));
+
+                /* Done. */
+                break;
+            }
+        }
+        while (ProcessAll);
+
+        /* Release the mutex. */
+        gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+            command->os,
+            command->taskMutex
+            ));
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+gcmDECLARE_INTERRUPT_HANDLER(COMMAND, 0)
+{
+    gceSTATUS status, last;
+
+    gcmkHEADER_ARG("Kernel=%p ", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+
+    do
+    {
+        gckVGCOMMAND command;
+        gcsKERNEL_QUEUE_HEADER_PTR mergeQueue;
+        gcsKERNEL_QUEUE_HEADER_PTR queueTail;
+        gcsKERNEL_CMDQUEUE_PTR entry;
+        gctUINT entryCount;
+
+        /* Get the command buffer object. */
+        command = Kernel->command;
+
+        /* Acquire the mutex. */
+        gcmkERR_BREAK(gckOS_AcquireMutex(
+            command->os,
+            command->queueMutex,
+            gcvINFINITE
+            ));
+
+        /* Get the current queue. */
+        queueTail = command->queueTail;
+
+        /* Get the current queue entry. */
+        entry = queueTail->currentEntry;
+
+        /* Get the number of entries in the queue. */
+        entryCount = queueTail->pending;
+
+        /* Process all entries. */
+        while (entryCount > 0)
+        {
+            /* Call post-execution function. */
+            status = entry->handler(Kernel, entry);
+
+            /* Failed? */
+            if (gcmkIS_ERROR(status))
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_ERROR,
+                    gcvZONE_COMMAND,
+                    "[%s] line %d: post action failed.\n",
+                    __FUNCTION__, __LINE__
+                    );
+            }
+
+            /* Executed the next buffer? */
+            if (status == gcvSTATUS_EXECUTED)
+            {
+                /* Update the queue. */
+                queueTail->pending      = entryCount;
+                queueTail->currentEntry = entry;
+
+                /* Success. */
+                status = gcvSTATUS_OK;
+
+                /* Break out of the loop. */
+                break;
+            }
+
+            /* Advance to the next entry. */
+            entry      += 1;
+            entryCount -= 1;
+
+            /* Last entry? */
+            if (entryCount == 0)
+            {
+                /* Reset the queue to idle. */
+                queueTail->pending = 0;
+
+                /* Get a shortcut to the queue to merge with. */
+                mergeQueue = command->mergeQueue;
+
+                /* Merge the queues if necessary. */
+                if (mergeQueue != queueTail)
+                {
+                    gcmkASSERT(mergeQueue < queueTail);
+                    gcmkASSERT(mergeQueue->next == queueTail);
+
+                    mergeQueue->size
+                        += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+                        + queueTail->size;
+
+                    mergeQueue->next = queueTail->next;
+                }
+
+                /* Advance to the next queue. */
+                queueTail = queueTail->next;
+
+                /* Did it wrap around? */
+                if (command->queue == queueTail)
+                {
+                    /* Reset merge queue. */
+                    command->mergeQueue = queueTail;
+                }
+
+                /* Set new queue. */
+                command->queueTail = queueTail;
+
+                /* Is the next queue scheduled? */
+                if (queueTail->pending > 0)
+                {
+                    gcsCMDBUFFER_PTR commandBuffer;
+
+                    /* The first entry must be a command buffer. */
+                    commandBuffer = queueTail->currentEntry->commandBuffer;
+
+                    /* Start the command processor. */
+                    status = gckVGHARDWARE_Execute(
+                        command->hardware,
+                        commandBuffer->address,
+                        commandBuffer->dataCount
+                        );
+
+                    /* Failed? */
+                    if (gcmkIS_ERROR(status))
+                    {
+                        gcmkTRACE_ZONE(
+                            gcvLEVEL_ERROR,
+                            gcvZONE_COMMAND,
+                            "[%s] line %d: failed to start the next queue.\n",
+                            __FUNCTION__, __LINE__
+                            );
+                    }
+                }
+                else
+                {
+                    status = gckVGHARDWARE_SetPowerState(
+                                Kernel->command->hardware, gcvPOWER_IDLE_BROADCAST
+                                );
+                }
+
+                /* Break out of the loop. */
+                break;
+            }
+        }
+
+        /* Release the mutex. */
+        gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+            command->os,
+            command->queueMutex
+            ));
+    }
+    while (gcvFALSE);
+
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+/* Define standard block interrupt handlers. */
+gcmDEFINE_INTERRUPT_HANDLER(TESSELLATOR, 0)
+gcmDEFINE_INTERRUPT_HANDLER(VG,          0)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       0)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       1)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       2)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       3)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       4)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       5)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       6)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       7)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       8)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL,       9)
+
+/* The entries in the array are arranged by event priority. */
+static gcsBLOCK_INTERRUPT_HANDLER _blockHandlers[] =
+{
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(TESSELLATOR, 0),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(VG,          0),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       0),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       1),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       2),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       3),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       4),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       5),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       6),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       7),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       8),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL,       9),
+    gcmDEFINE_INTERRUPT_HANDLER_ENTRY(COMMAND,     0),
+};
+
+
+/******************************************************************************\
+************************* Static Command Buffer Handlers ***********************
+\******************************************************************************/
+
+static gceSTATUS
+_UpdateStaticCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s(%d)\n",
+        __FUNCTION__, __LINE__
+        );
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ExecuteStaticCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        gcsCMDBUFFER_PTR commandBuffer;
+
+        /* Cast the command buffer header. */
+        commandBuffer = Entry->commandBuffer;
+
+        /* Set to update the command buffer next time. */
+        Entry->handler = _UpdateStaticCommandBuffer;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+            __FUNCTION__, __LINE__,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            );
+
+        /* Start the command processor. */
+        gcmkERR_BREAK(gckVGHARDWARE_Execute(
+            Kernel->hardware,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            ));
+
+        /* Success. */
+        return gcvSTATUS_EXECUTED;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_UpdateLastStaticCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+#if gcvDEBUG || gcdFORCE_MESSAGES
+    /* Get the command buffer header. */
+    gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+    /* Validate the command buffer. */
+    gcmkASSERT(commandBuffer->completion != gcvNULL);
+    gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
+
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s(%d): processing all tasks scheduled for FE.\n",
+        __FUNCTION__, __LINE__
+        );
+
+    /* Perform scheduled tasks. */
+    return _EventHandler_Block(
+        Kernel,
+        &Kernel->command->taskTable[gcvBLOCK_COMMAND],
+        gcvTRUE
+        );
+}
+
+static gceSTATUS
+_ExecuteLastStaticCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the command buffer header. */
+        gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+        /* Set to update the command buffer next time. */
+        Entry->handler = _UpdateLastStaticCommandBuffer;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+            __FUNCTION__, __LINE__,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            );
+
+        /* Start the command processor. */
+        gcmkERR_BREAK(gckVGHARDWARE_Execute(
+            Kernel->hardware,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            ));
+
+        /* Success. */
+        return gcvSTATUS_EXECUTED;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+
+/******************************************************************************\
+************************* Dynamic Command Buffer Handlers **********************
+\******************************************************************************/
+
+static gceSTATUS
+_UpdateDynamicCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s(%d)\n",
+        __FUNCTION__, __LINE__
+        );
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ExecuteDynamicCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the command buffer header. */
+        gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+        /* Set to update the command buffer next time. */
+        Entry->handler = _UpdateDynamicCommandBuffer;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+            __FUNCTION__, __LINE__,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            );
+
+        /* Start the command processor. */
+        gcmkERR_BREAK(gckVGHARDWARE_Execute(
+            Kernel->hardware,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            ));
+
+        /* Success. */
+        return gcvSTATUS_EXECUTED;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_UpdateLastDynamicCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+#if gcvDEBUG || gcdFORCE_MESSAGES
+    /* Get the command buffer header. */
+    gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+    /* Validate the command buffer. */
+    gcmkASSERT(commandBuffer->completion != gcvNULL);
+    gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
+
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s(%d): processing all tasks scheduled for FE.\n",
+        __FUNCTION__, __LINE__
+        );
+
+    /* Perform scheduled tasks. */
+    return _EventHandler_Block(
+        Kernel,
+        &Kernel->command->taskTable[gcvBLOCK_COMMAND],
+        gcvTRUE
+        );
+}
+
+static gceSTATUS
+_ExecuteLastDynamicCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Cast the command buffer header. */
+        gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+        /* Set to update the command buffer next time. */
+        Entry->handler = _UpdateLastDynamicCommandBuffer;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+            __FUNCTION__, __LINE__,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            );
+
+        /* Start the command processor. */
+        gcmkERR_BREAK(gckVGHARDWARE_Execute(
+            Kernel->hardware,
+            commandBuffer->address,
+            commandBuffer->dataCount
+            ));
+
+        /* Success. */
+        return gcvSTATUS_EXECUTED;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+
+/******************************************************************************\
+********************************* Other Handlers *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_FreeKernelCommandBuffer(
+    IN gckVGKERNEL Kernel,
+    IN gcsKERNEL_CMDQUEUE_PTR Entry
+    )
+{
+    gceSTATUS status;
+
+    /* Free the command buffer. */
+    status = _FreeCommandBuffer(Kernel, Entry->commandBuffer);
+
+    /* Return status. */
+    return status;
+}
+
+
+/******************************************************************************\
+******************************* Queue Management *******************************
+\******************************************************************************/
+
+#if gcvDUMP_COMMAND_BUFFER
+static void
+_DumpCommandQueue(
+    IN gckVGCOMMAND Command,
+    IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader,
+    IN gctUINT EntryCount
+    )
+{
+    gcsKERNEL_CMDQUEUE_PTR entry;
+    gctUINT queueIndex;
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+    static gctUINT arrayCount = 0;
+#endif
+
+    /* Is dumpinng enabled? */
+    if (!Commad->enableDumping)
+    {
+        return;
+    }
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_COMMAND,
+        "COMMAND QUEUE DUMP: %d entries\n", EntryCount
+        );
+#endif
+
+    /* Get the pointer to the first entry. */
+    entry = QueueHeader->currentEntry;
+
+    /* Iterate through the queue. */
+    for (queueIndex = 0; queueIndex < EntryCount; queueIndex += 1)
+    {
+        gcsCMDBUFFER_PTR buffer;
+        gctUINT bufferCount;
+        gctUINT bufferIndex;
+        gctUINT i, count;
+        gctUINT size;
+        gctUINT32_PTR data;
+
+#if gcvDUMP_COMMAND_LINES
+        gctUINT lineNumber;
+#endif
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_COMMAND,
+            "ENTRY %d\n", queueIndex
+            );
+#endif
+
+        /* Reset the count. */
+        bufferCount = 0;
+
+        /* Set the initial buffer. */
+        buffer = entry->commandBuffer;
+
+        /* Loop through all subbuffers. */
+        while (buffer)
+        {
+            /* Update the count. */
+            bufferCount += 1;
+
+            /* Advance to the next subbuffer. */
+            buffer = buffer->nextSubBuffer;
+        }
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+        if (bufferCount > 1)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO,
+                gcvZONE_COMMAND,
+                "  COMMAND BUFFER SET: %d buffers.\n",
+                bufferCount
+                );
+        }
+#endif
+
+        /* Reset the buffer index. */
+        bufferIndex = 0;
+
+        /* Set the initial buffer. */
+        buffer = entry->commandBuffer;
+
+        /* Loop through all subbuffers. */
+        while (buffer)
+        {
+            /* Determine the size of the buffer. */
+            size = buffer->dataCount * Command->info.commandAlignment;
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+            /* A single buffer? */
+            if (bufferCount == 1)
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_INFO,
+                    gcvZONE_COMMAND,
+                    "  COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n",
+                    buffer->dataCount,
+                    buffer->dataCount,
+                    size,
+                    buffer->address
+                    );
+            }
+            else
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_INFO,
+                    gcvZONE_COMMAND,
+                    "  COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n",
+                    bufferIndex,
+                    buffer->dataCount,
+                    buffer->dataCount,
+                    size,
+                    buffer->address
+                    );
+            }
+#endif
+
+            /* Determine the number of double words to print. */
+            count = size / 4;
+
+            /* Determine the buffer location. */
+            data = (gctUINT32_PTR)
+            (
+                (gctUINT8_PTR) buffer + buffer->bufferOffset
+            );
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO,
+                gcvZONE_COMMAND,
+                "unsigned int _" gcvCOMMAND_BUFFER_NAME "_%d[] =\n",
+                arrayCount
+                );
+
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO,
+                gcvZONE_COMMAND,
+                "{\n"
+                );
+
+            arrayCount += 1;
+#endif
+
+#if gcvDUMP_COMMAND_LINES
+            /* Reset the line number. */
+            lineNumber = 0;
+#endif
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+            count -= 2;
+#endif
+
+            for (i = 0; i < count; i += 1)
+            {
+                if ((i % 8) == 0)
+                {
+#if defined(gcvCOMMAND_BUFFER_NAME)
+                    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\t");
+#else
+                    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "    ");
+#endif
+                }
+
+#if gcvDUMP_COMMAND_LINES
+                if (lineNumber == gcvDUMP_COMMAND_LINES)
+                {
+                    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " . . . . . . . . .\n");
+                    break;
+                }
+#endif
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "0x%08X", data[i]);
+
+                if (i + 1 == count)
+                {
+                    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\n");
+
+#if gcvDUMP_COMMAND_LINES
+                    lineNumber += 1;
+#endif
+                }
+                else
+                {
+                    if (((i + 1) % 8) == 0)
+                    {
+                        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ",\n");
+
+#if gcvDUMP_COMMAND_LINES
+                        lineNumber += 1;
+#endif
+                    }
+                    else
+                    {
+                        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ", ");
+                    }
+                }
+            }
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO,
+                gcvZONE_COMMAND,
+                "};\n\n"
+                );
+#endif
+
+            /* Advance to the next subbuffer. */
+            buffer = buffer->nextSubBuffer;
+            bufferIndex += 1;
+        }
+
+        /* Advance to the next entry. */
+        entry += 1;
+    }
+}
+#endif
+
+static gceSTATUS
+_LockCurrentQueue(
+    IN gckVGCOMMAND Command,
+    OUT gcsKERNEL_CMDQUEUE_PTR * Entries,
+    OUT gctUINT_PTR EntryCount
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        gcsKERNEL_QUEUE_HEADER_PTR queueHead;
+
+        /* Get a shortcut to the head of the queue. */
+        queueHead = Command->queueHead;
+
+        /* Is the head buffer still being worked on? */
+        if (queueHead->pending)
+        {
+            /* Increment overflow count. */
+            Command->queueOverflow += 1;
+
+            /* Wait until the head becomes idle. */
+            gcmkERR_BREAK(_WaitForIdle(Command, queueHead));
+        }
+
+        /* Acquire the mutex. */
+        gcmkERR_BREAK(gckOS_AcquireMutex(
+            Command->os,
+            Command->queueMutex,
+            gcvINFINITE
+            ));
+
+        /* Determine the first queue entry. */
+        queueHead->currentEntry = (gcsKERNEL_CMDQUEUE_PTR)
+        (
+            (gctUINT8_PTR) queueHead + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+        );
+
+        /* Set the pointer to the first entry. */
+        * Entries = queueHead->currentEntry;
+
+        /* Determine the number of available entries. */
+        * EntryCount = queueHead->size / gcmSIZEOF(gcsKERNEL_CMDQUEUE);
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+static gceSTATUS
+_UnlockCurrentQueue(
+    IN gckVGCOMMAND Command,
+    IN gctUINT EntryCount
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+#if !gcdENABLE_INFINITE_SPEED_HW
+        gcsKERNEL_QUEUE_HEADER_PTR queueTail;
+        gcsKERNEL_QUEUE_HEADER_PTR queueHead;
+        gcsKERNEL_QUEUE_HEADER_PTR queueNext;
+        gctUINT queueSize;
+        gctUINT newSize;
+        gctUINT unusedSize;
+
+        /* Get shortcut to the head and to the tail of the queue. */
+        queueTail = Command->queueTail;
+        queueHead = Command->queueHead;
+
+        /* Dump the command buffer. */
+#if gcvDUMP_COMMAND_BUFFER
+        _DumpCommandQueue(Command, queueHead, EntryCount);
+#endif
+
+        /* Get a shortcut to the current queue size. */
+        queueSize = queueHead->size;
+
+        /* Determine the new queue size. */
+        newSize = EntryCount * gcmSIZEOF(gcsKERNEL_CMDQUEUE);
+        gcmkASSERT(newSize <= queueSize);
+
+        /* Determine the size of the unused area. */
+        unusedSize = queueSize - newSize;
+
+        /* Is the unused area big enough to become a buffer? */
+        if (unusedSize >= gcvMINUMUM_BUFFER)
+        {
+            gcsKERNEL_QUEUE_HEADER_PTR nextHead;
+
+            /* Place the new header. */
+            nextHead = (gcsKERNEL_QUEUE_HEADER_PTR)
+            (
+                (gctUINT8_PTR) queueHead
+                    + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+                    + newSize
+            );
+
+            /* Initialize the buffer. */
+            nextHead->size    = unusedSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
+            nextHead->pending = 0;
+
+            /* Link the buffer in. */
+            nextHead->next  = queueHead->next;
+            queueHead->next = nextHead;
+            queueNext       = nextHead;
+
+            /* Update the size of the current buffer. */
+            queueHead->size = newSize;
+        }
+
+        /* Not big enough. */
+        else
+        {
+            /* Determine the next queue. */
+            queueNext = queueHead->next;
+        }
+
+        /* Mark the buffer as busy. */
+        queueHead->pending = EntryCount;
+
+        /* Advance to the next buffer. */
+        Command->queueHead = queueNext;
+
+        /* Start the command processor if the queue was empty. */
+        if (queueTail == queueHead)
+        {
+            gcsCMDBUFFER_PTR commandBuffer;
+
+            /* The first entry must be a command buffer. */
+            commandBuffer = queueTail->currentEntry->commandBuffer;
+
+            /* Start the command processor. */
+            gcmkERR_BREAK(gckVGHARDWARE_Execute(
+                Command->hardware,
+                commandBuffer->address,
+                commandBuffer->dataCount
+                ));
+        }
+
+        /* The queue was not empty. */
+        else
+        {
+            /* Advance the merge buffer if needed. */
+            if (queueHead == Command->mergeQueue)
+            {
+                Command->mergeQueue = queueNext;
+            }
+        }
+#endif
+
+        /* Release the mutex. */
+        gcmkERR_BREAK(gckOS_ReleaseMutex(
+            Command->os,
+            Command->queueMutex
+            ));
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Return status. */
+    return status;
+}
+
+
+
+/******************************************************************************\
+****************************** gckVGCOMMAND API Code *****************************
+\******************************************************************************/
+gceSTATUS
+gckVGCOMMAND_Construct(
+    IN gckVGKERNEL Kernel,
+    IN gctUINT TaskGranularity,
+    IN gctUINT QueueSize,
+    OUT gckVGCOMMAND * Command
+    )
+{
+    gceSTATUS status, last;
+    gckVGCOMMAND command = gcvNULL;
+    gcsKERNEL_QUEUE_HEADER_PTR queue;
+    gctUINT i, j;
+
+    gcmkHEADER_ARG("Kernel=%p TaskGranularity=0x%x QueueSize=0x%x Command=%p",
+        Kernel, TaskGranularity, QueueSize, Command);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(QueueSize >= gcvMINUMUM_BUFFER);
+    gcmkVERIFY_ARGUMENT(Command != gcvNULL);
+
+    do
+    {
+        /***********************************************************************
+        ** Generic object initialization.
+        */
+
+        /* Allocate the gckVGCOMMAND structure. */
+        gcmkERR_BREAK(gckOS_Allocate(
+            Kernel->os,
+            gcmSIZEOF(struct _gckVGCOMMAND),
+            (gctPOINTER *) &command
+            ));
+
+        /* Initialize the object. */
+        command->object.type = gcvOBJ_COMMAND;
+
+        /* Set the object pointers. */
+        command->kernel      = Kernel;
+        command->os          = Kernel->os;
+        command->hardware    = Kernel->hardware;
+
+        /* Reset pointers. */
+        command->queue       = gcvNULL;
+        command->queueMutex  = gcvNULL;
+        command->taskMutex   = gcvNULL;
+        command->commitMutex = gcvNULL;
+
+        command->powerStallBuffer   = gcvNULL;
+        command->powerStallSignal   = gcvNULL;
+        command->powerSemaphore     = gcvNULL;
+
+        /* Reset context states. */
+        command->contextCounter = 0;
+        command->currentContext = 0;
+
+        /* Enable command buffer dumping. */
+        command->enableDumping = gcvTRUE;
+
+        /* Set features. */
+        command->fe20 = Kernel->hardware->fe20;
+        command->vg20 = Kernel->hardware->vg20;
+        command->vg21 = Kernel->hardware->vg21;
+
+        /* Reset task table .*/
+        gcmkVERIFY_OK(gckOS_ZeroMemory(
+            command->taskTable, gcmSIZEOF(command->taskTable)
+            ));
+
+        /* Query command buffer attributes. */
+        gcmkERR_BREAK(gckVGCOMMAND_InitializeInfo(command));
+
+        /* Create the control mutexes. */
+        gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->queueMutex));
+        gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->taskMutex));
+        gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->commitMutex));
+
+        /* Create the power management semaphore. */
+        gcmkERR_BREAK(gckOS_CreateSemaphore(Kernel->os,
+            &command->powerSemaphore));
+
+        gcmkERR_BREAK(gckOS_CreateSignal(Kernel->os,
+            gcvFALSE, &command->powerStallSignal));
+
+        /***********************************************************************
+        ** Command queue initialization.
+        */
+
+        /* Allocate the command queue. */
+        gcmkERR_BREAK(gckOS_Allocate(
+            Kernel->os,
+            QueueSize,
+            (gctPOINTER *) &command->queue
+            ));
+
+        /* Initialize the command queue. */
+        queue = command->queue;
+
+        queue->size    = QueueSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
+        queue->pending = 0;
+        queue->next    = queue;
+
+        command->queueHead  =
+        command->queueTail  =
+        command->mergeQueue = command->queue;
+
+        command->queueOverflow = 0;
+
+
+        /***********************************************************************
+        ** Enable TS overflow interrupt.
+        */
+
+        command->info.tsOverflowInt = 0;
+        gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+            Kernel->interrupt,
+            &command->info.tsOverflowInt,
+            _EventHandler_TSOverflow
+            ));
+
+        /* Mask out the interrupt. */
+        /* Kernel->hardware->eventMask &= ~(1 << command->info.tsOverflowInt); */
+
+
+        /***********************************************************************
+        ** Enable Bus Error interrupt.
+        */
+
+        /* Hardwired to bit 31. */
+        command->busErrorInt = 31;
+
+        /* Enable the interrupt. */
+        gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+            Kernel->interrupt,
+            &command->busErrorInt,
+            _EventHandler_BusError
+            ));
+
+
+        command->powerStallInt = 30;
+        /* Enable the interrupt. */
+        gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+            Kernel->interrupt,
+            &command->powerStallInt,
+            _EventHandler_PowerStall
+            ));
+
+        /***********************************************************************
+        ** Task management initialization.
+        */
+
+        command->taskStorage            = gcvNULL;
+        command->taskStorageGranularity = TaskGranularity;
+        command->taskStorageUsable      = TaskGranularity - gcmSIZEOF(gcsTASK_STORAGE);
+
+        command->taskFreeHead = gcvNULL;
+        command->taskFreeTail = gcvNULL;
+
+        /* Enable block handlers. */
+        for (i = 0; i < gcmCOUNTOF(_blockHandlers); i += 1)
+        {
+            /* Get the target hardware block. */
+            gceBLOCK block = _blockHandlers[i].block;
+
+            /* Get the interrupt array entry. */
+            gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[block];
+
+            /* Determine the interrupt value index. */
+            gctUINT index = entry->interruptCount;
+
+            /* Create the block semaphore. */
+            if (entry->interruptSemaphore == gcvNULL)
+            {
+                gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
+                    command->os, &entry->interruptSemaphore
+                    ));
+            }
+
+            /* Enable auto-detection. */
+            entry->interruptArray[index] = -1;
+
+            /* Enable interrupt for the block. */
+            gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+                Kernel->interrupt,
+                &entry->interruptArray[index],
+                _blockHandlers[i].handler
+                ));
+
+            /* Update the number of registered interrupts. */
+            entry->interruptCount += 1;
+
+            /* Inrement the semaphore to allow the usage of the registered
+               interrupt. */
+            gcmkERR_BREAK(gckOS_IncrementSemaphore(
+                command->os, entry->interruptSemaphore
+                ));
+
+        }
+
+        /* Error? */
+        if (gcmkIS_ERROR(status))
+        {
+            break;
+        }
+
+        /* Get the FE interrupt. */
+        command->info.feBufferInt
+            = command->taskTable[gcvBLOCK_COMMAND].interruptArray[0];
+
+        /* Return gckVGCOMMAND object pointer. */
+        *Command = command;
+
+        gcmkFOOTER_ARG("*Command=0x%x",*Command);
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (command != gcvNULL)
+    {
+        /* Disable block handlers. */
+        for (i = 0; i < gcvBLOCK_COUNT; i += 1)
+        {
+            /* Get the task table entry. */
+            gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[i];
+
+            /* Destroy the semaphore. */
+            if (entry->interruptSemaphore != gcvNULL)
+            {
+                gcmkCHECK_STATUS(gckOS_DestroySemaphore(
+                    command->os, entry->interruptSemaphore
+                    ));
+            }
+
+            /* Disable all enabled interrupts. */
+            for (j = 0; j < entry->interruptCount; j += 1)
+            {
+                /* Must be a valid value. */
+                gcmkASSERT(entry->interruptArray[j] >= 0);
+                gcmkASSERT(entry->interruptArray[j] <= 31);
+
+                /* Disable the interrupt. */
+                gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+                    Kernel->interrupt,
+                    entry->interruptArray[j]
+                    ));
+            }
+        }
+
+        /* Disable the bus error interrupt. */
+        gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+            Kernel->interrupt,
+            command->busErrorInt
+            ));
+
+        /* Disable TS overflow interrupt. */
+        if (command->info.tsOverflowInt != -1)
+        {
+            gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+                Kernel->interrupt,
+                command->info.tsOverflowInt
+                ));
+        }
+
+        /* Delete the commit mutex. */
+        if (command->commitMutex != gcvNULL)
+        {
+            gcmkCHECK_STATUS(gckOS_DeleteMutex(
+                Kernel->os, command->commitMutex
+                ));
+        }
+
+        /* Delete the command queue mutex. */
+        if (command->taskMutex != gcvNULL)
+        {
+            gcmkCHECK_STATUS(gckOS_DeleteMutex(
+                Kernel->os, command->taskMutex
+                ));
+        }
+
+        /* Delete the command queue mutex. */
+        if (command->queueMutex != gcvNULL)
+        {
+            gcmkCHECK_STATUS(gckOS_DeleteMutex(
+                Kernel->os, command->queueMutex
+                ));
+        }
+
+        /* Delete the command queue. */
+        if (command->queue != gcvNULL)
+        {
+            gcmkCHECK_STATUS(gckOS_Free(
+                Kernel->os, command->queue
+                ));
+        }
+
+        if (command->powerSemaphore != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_DestroySemaphore(
+                Kernel->os, command->powerSemaphore));
+        }
+
+        if (command->powerStallSignal != gcvNULL)
+        {
+            /* Create the power management semaphore. */
+            gcmkVERIFY_OK(gckOS_DestroySignal(
+                Kernel->os,
+                command->powerStallSignal));
+        }
+
+        /* Free the gckVGCOMMAND structure. */
+        gcmkCHECK_STATUS(gckOS_Free(
+            Kernel->os, command
+            ));
+    }
+
+    gcmkFOOTER();
+    /* Return the error. */
+    return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Destroy(
+    OUT gckVGCOMMAND Command
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Command=%p", Command);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+    do
+    {
+        gctUINT i;
+        gcsTASK_STORAGE_PTR nextStorage;
+
+        if (Command->queueHead != gcvNULL)
+        {
+            /* Wait until the head becomes idle. */
+            gcmkERR_BREAK(_WaitForIdle(Command, Command->queueHead));
+        }
+
+        /* Disable block handlers. */
+        for (i = 0; i < gcvBLOCK_COUNT; i += 1)
+        {
+            /* Get the interrupt array entry. */
+            gcsBLOCK_TASK_ENTRY_PTR entry = &Command->taskTable[i];
+
+            /* Determine the index of the last interrupt in the array. */
+            gctINT index = entry->interruptCount - 1;
+
+            /* Destroy the semaphore. */
+            if (entry->interruptSemaphore != gcvNULL)
+            {
+                gcmkERR_BREAK(gckOS_DestroySemaphore(
+                    Command->os, entry->interruptSemaphore
+                    ));
+            }
+
+            /* Disable all enabled interrupts. */
+            while (index >= 0)
+            {
+                /* Must be a valid value. */
+                gcmkASSERT(entry->interruptArray[index] >= 0);
+                gcmkASSERT(entry->interruptArray[index] <= 31);
+
+                /* Disable the interrupt. */
+                gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+                    Command->kernel->interrupt,
+                    entry->interruptArray[index]
+                    ));
+
+                /* Update to the next interrupt. */
+                index                 -= 1;
+                entry->interruptCount -= 1;
+            }
+
+            /* Error? */
+            if (gcmkIS_ERROR(status))
+            {
+                break;
+            }
+        }
+
+        /* Error? */
+        if (gcmkIS_ERROR(status))
+        {
+            break;
+        }
+
+        /* Disable the bus error interrupt. */
+        gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+            Command->kernel->interrupt,
+            Command->busErrorInt
+            ));
+
+        /* Disable TS overflow interrupt. */
+        if (Command->info.tsOverflowInt != -1)
+        {
+            gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+                Command->kernel->interrupt,
+                Command->info.tsOverflowInt
+                ));
+
+            Command->info.tsOverflowInt = -1;
+        }
+
+        /* Delete the commit mutex. */
+        if (Command->commitMutex != gcvNULL)
+        {
+            gcmkERR_BREAK(gckOS_DeleteMutex(
+                Command->os, Command->commitMutex
+                ));
+
+            Command->commitMutex = gcvNULL;
+        }
+
+        /* Delete the command queue mutex. */
+        if (Command->taskMutex != gcvNULL)
+        {
+            gcmkERR_BREAK(gckOS_DeleteMutex(
+                Command->os, Command->taskMutex
+                ));
+
+            Command->taskMutex = gcvNULL;
+        }
+
+        /* Delete the command queue mutex. */
+        if (Command->queueMutex != gcvNULL)
+        {
+            gcmkERR_BREAK(gckOS_DeleteMutex(
+                Command->os, Command->queueMutex
+                ));
+
+            Command->queueMutex = gcvNULL;
+        }
+
+        if (Command->powerSemaphore != gcvNULL)
+        {
+            /* Destroy the power management semaphore. */
+            gcmkERR_BREAK(gckOS_DestroySemaphore(
+                Command->os, Command->powerSemaphore));
+        }
+
+        if (Command->powerStallSignal != gcvNULL)
+        {
+            /* Create the power management semaphore. */
+            gcmkERR_BREAK(gckOS_DestroySignal(
+                Command->os,
+                Command->powerStallSignal));
+        }
+
+        if (Command->queue != gcvNULL)
+        {
+            /* Delete the command queue. */
+            gcmkERR_BREAK(gckOS_Free(
+                Command->os, Command->queue
+                ));
+        }
+
+        /* Destroy all allocated buffers. */
+        while (Command->taskStorage)
+        {
+            /* Copy the buffer pointer. */
+            nextStorage = Command->taskStorage->next;
+
+            /* Free the current container. */
+            gcmkERR_BREAK(gckOS_Free(
+                Command->os, Command->taskStorage
+                ));
+
+            /* Advance to the next one. */
+            Command->taskStorage = nextStorage;
+        }
+
+        /* Error? */
+        if (gcmkIS_ERROR(status))
+        {
+            break;
+        }
+
+        /* Mark the object as unknown. */
+        Command->object.type = gcvOBJ_UNKNOWN;
+
+        /* Free the gckVGCOMMAND structure. */
+        gcmkERR_BREAK(gckOS_Free(Command->os, Command));
+
+        gcmkFOOTER_NO();
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Restore the object type if failed. */
+    Command->object.type = gcvOBJ_COMMAND;
+
+    gcmkFOOTER();
+    /* Return the error. */
+    return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_QueryCommandBuffer(
+    IN gckVGCOMMAND Command,
+    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+    )
+{
+    gcmkHEADER_ARG("Command=%p Information=%p", Command, Information);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+    gcmkVERIFY_ARGUMENT(Information != gcvNULL);
+
+    /* Copy the information. */
+    gcmkVERIFY_OK(gckOS_MemCopy(
+        Information, &Command->info, sizeof(gcsCOMMAND_BUFFER_INFO)
+        ));
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGCOMMAND_Allocate(
+    IN gckVGCOMMAND Command,
+    IN gctSIZE_T Size,
+    OUT gcsCMDBUFFER_PTR * CommandBuffer,
+    OUT gctPOINTER * Data
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p Size=0x%x CommandBuffer=%p Data=0x%x",
+        Command, Size, CommandBuffer, Data);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+    gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+    do
+    {
+        /* Allocate the buffer. */
+        gcmkERR_BREAK(_AllocateCommandBuffer(Command, Size, CommandBuffer));
+
+        /* Determine the data pointer. */
+        * Data = (gctUINT8_PTR) (*CommandBuffer) + (* CommandBuffer)->bufferOffset;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Free(
+    IN gckVGCOMMAND Command,
+    IN gcsCMDBUFFER_PTR CommandBuffer
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p CommandBuffer=%p",
+        Command, CommandBuffer);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+    gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
+
+    /* Free command buffer. */
+    status = _FreeCommandBuffer(Command->kernel, CommandBuffer);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Execute(
+    IN gckVGCOMMAND Command,
+    IN gcsCMDBUFFER_PTR CommandBuffer
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Command=%p CommandBuffer=%p",
+        Command, CommandBuffer);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+    gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
+
+    do
+    {
+        gctUINT queueLength;
+        gcsKERNEL_CMDQUEUE_PTR kernelEntry;
+
+        /* Lock the current queue. */
+        gcmkERR_BREAK(_LockCurrentQueue(
+            Command, &kernelEntry, &queueLength
+            ));
+
+        /* Set the buffer. */
+        kernelEntry->commandBuffer = CommandBuffer;
+        kernelEntry->handler = _FreeKernelCommandBuffer;
+
+        /* Lock the current queue. */
+        gcmkERR_BREAK(_UnlockCurrentQueue(
+            Command, 1
+            ));
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Commit(
+    IN gckVGCOMMAND Command,
+    IN gcsVGCONTEXT_PTR Context,
+    IN gcsVGCMDQUEUE_PTR Queue,
+    IN gctUINT EntryCount,
+    IN gcsTASK_MASTER_TABLE_PTR TaskTable
+    )
+{
+    /*
+        The first buffer is executed through a direct gckVGHARDWARE_Execute call,
+        therefore only an update is needed after the execution is over. All
+        consequent buffers need to be executed upon the first update call from
+        the FE interrupt handler.
+    */
+    static gcsQUEUE_UPDATE_CONTROL _dynamicBuffer[] =
+    {
+        {
+            _UpdateDynamicCommandBuffer,
+            _UpdateDynamicCommandBuffer,
+            _UpdateLastDynamicCommandBuffer,
+            _UpdateLastDynamicCommandBuffer
+        },
+        {
+            _ExecuteDynamicCommandBuffer,
+            _UpdateDynamicCommandBuffer,
+            _ExecuteLastDynamicCommandBuffer,
+            _UpdateLastDynamicCommandBuffer
+        }
+    };
+
+    static gcsQUEUE_UPDATE_CONTROL _staticBuffer[] =
+    {
+        {
+            _UpdateStaticCommandBuffer,
+            _UpdateStaticCommandBuffer,
+            _UpdateLastStaticCommandBuffer,
+            _UpdateLastStaticCommandBuffer
+        },
+        {
+            _ExecuteStaticCommandBuffer,
+            _UpdateStaticCommandBuffer,
+            _ExecuteLastStaticCommandBuffer,
+            _UpdateLastStaticCommandBuffer
+        }
+    };
+
+    gceSTATUS status, last;
+    struct _gcsTASK_MASTER_TABLE  _TaskTable;
+#ifdef __QNXNTO__
+    gcsVGCONTEXT_PTR userContext = gcvNULL;
+    gctBOOL userContextMapped = gcvFALSE;
+    gcsTASK_MASTER_TABLE_PTR userTaskTable = gcvNULL;
+    gctBOOL userTaskTableMapped = gcvFALSE;
+    gctPOINTER pointer = gcvNULL;
+#endif
+    struct _gcsVGCONTEXT  _Context;
+    gctBOOL needCopy = gcvFALSE;
+
+    gcmkHEADER_ARG("Command=%p Context=%p Queue=%p EntryCount=0x%x TaskTable=%p",
+            Command, Context, Queue, EntryCount, TaskTable);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+    gcmkVERIFY_ARGUMENT(Context != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+    gcmkVERIFY_ARGUMENT(EntryCount > 1);
+
+    do
+    {
+        gctBOOL haveFETasks;
+        gctUINT queueSize = 0;
+        gcsVGCMDQUEUE_PTR mappedQueue=gcvNULL;
+        gcsVGCMDQUEUE_PTR userEntry=gcvNULL;
+        gcsKERNEL_CMDQUEUE_PTR kernelEntry;
+        gcsQUEUE_UPDATE_CONTROL_PTR queueControl;
+        gctUINT currentLength;
+        gctUINT queueLength;
+        gctUINT entriesQueued;
+        gctUINT8_PTR previousEnd;
+        gctBOOL previousDynamic;
+        gctBOOL previousExecuted;
+        gctUINT controlIndex;
+        gctINT pid;
+#ifdef __QNXNTO__
+        /* Map the context into the kernel space. */
+        userContext = Context;
+
+        gcmkERR_BREAK(gckOS_MapUserPointer(
+                    Command->os,
+                    userContext,
+                    gcmSIZEOF(*userContext),
+                    &pointer));
+
+        Context = pointer;
+
+        userContextMapped = gcvTRUE;
+
+        /* Map the taskTable into the kernel space. */
+        userTaskTable = TaskTable;
+
+        gcmkERR_BREAK(gckOS_MapUserPointer(
+                    Command->os,
+                    userTaskTable,
+                    gcmSIZEOF(*userTaskTable),
+                    &pointer));
+
+        TaskTable = pointer;
+
+        userTaskTableMapped = gcvTRUE;
+
+        /* Update the signal info. */
+        TaskTable->coid  = Context->coid;
+        TaskTable->rcvid = Context->rcvid;
+#endif
+
+        gcmkERR_BREAK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+        gcmkERR_BREAK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+        if(needCopy)
+        {
+            gcmkERR_BREAK(gckOS_CopyFromUserData(
+                        Command->os,
+                        &_TaskTable,
+                        TaskTable,
+                        gcmSIZEOF(struct _gcsTASK_MASTER_TABLE)
+                        ));
+            TaskTable = &_TaskTable;
+            /* Determine whether there are FE tasks to be performed. */
+            gcmkERR_BREAK(gckOS_CopyFromUserData(
+                        Command->os,
+                        &_Context,
+                        Context,
+                        gcmSIZEOF(struct _gcsVGCONTEXT)
+                        ));
+            Context = &_Context;
+        }
+
+        gcmkERR_BREAK(gckVGHARDWARE_SetPowerState(
+                    Command->hardware, gcvPOWER_ON_AUTO
+                    ));
+
+        /* Acquire the power semaphore. */
+        gcmkERR_BREAK(gckOS_AcquireSemaphore(
+                    Command->os, Command->powerSemaphore
+                    ));
+
+        /* Acquire the mutex. */
+        status = gckOS_AcquireMutex(
+                Command->os,
+                Command->commitMutex,
+                gcvINFINITE
+                );
+
+        if (gcmIS_ERROR(status))
+        {
+            gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+                        Command->os, Command->powerSemaphore));
+            break;
+        }
+
+        do
+        {
+            gcmkERR_BREAK(_FlushMMU(Command));
+
+            /* Assign a context ID if not yet assigned. */
+            if (Context->id == 0)
+            {
+                /* Assign the next context number. */
+                Context->id = ++ Command->contextCounter;
+                /* See if we overflowed. */
+                if (Command->contextCounter == 0)
+                {
+                    /* We actually did overflow, wow... */
+                    status = gcvSTATUS_OUT_OF_RESOURCES;
+                    break;
+                }
+            }
+
+            /* The first entry in the queue is always the context buffer.
+               Verify whether the user context is the same as the current
+               context and if that's the case, skip the first entry. */
+            if (Context->id == Command->currentContext)
+            {
+                /* Same context as before, skip the first entry. */
+                EntryCount -= 1;
+                Queue      += 1;
+
+                /* Set the signal to avoid user waiting. */
+#ifdef __QNXNTO__
+                gcmkERR_BREAK(gckOS_UserSignal(
+                            Command->os,
+                            Context->userSignal,
+                            Context->rcvid,
+                            Context->coid
+                            ));
+#else
+                gcmkERR_BREAK(gckOS_UserSignal(
+                            Command->os, Context->signal, Context->process
+                            ));
+#endif
+            }
+            else
+            {
+                /* Different user context - keep the first entry.
+                   Set the user context as the current one. */
+                Command->currentContext = Context->id;
+            }
+
+            /* Reset pointers. */
+            queueControl = gcvNULL;
+            previousEnd  = gcvNULL;
+
+            haveFETasks = (TaskTable->table[gcvBLOCK_COMMAND].head != gcvNULL);
+
+            /* Determine the size of the queue. */
+            queueSize = EntryCount * gcmSIZEOF(gcsVGCMDQUEUE);
+            if(needCopy)
+            {
+                gctPOINTER pointer = gcvNULL;
+                gcmkERR_BREAK(gckOS_Allocate(
+                            Command->os,
+                            queueSize,
+                            &pointer
+                            ));
+                userEntry = pointer;
+                mappedQueue = pointer;
+                gcmkERR_BREAK(gckOS_CopyFromUserData(
+                            Command->os,
+                            userEntry,
+                            Queue,
+                            queueSize
+                            ));
+            }
+            else
+            {
+                /* Map the command queue into the kernel space. */
+                gcmkERR_BREAK(gckOS_MapUserPointer(
+                            Command->os,
+                            Queue,
+                            queueSize,
+                            (gctPOINTER *) &mappedQueue
+                            ));
+                userEntry = mappedQueue;
+            }
+            /* Set the first entry. */
+
+            /* Process the command queue. */
+            while (EntryCount)
+            {
+                /* Lock the current queue. */
+                gcmkERR_BREAK(_LockCurrentQueue(
+                            Command, &kernelEntry, &queueLength
+                            ));
+
+                /* Determine the number of entries to process. */
+                currentLength = (queueLength < EntryCount)
+                    ? queueLength
+                    : EntryCount;
+
+                /* Update the number of the entries left to process. */
+                EntryCount -= currentLength;
+
+                /* Reset previous flags. */
+                previousDynamic  = gcvFALSE;
+                previousExecuted = gcvFALSE;
+
+                /* Set the initial control index. */
+                controlIndex = 0;
+
+                /* Process entries. */
+                for (entriesQueued = 0; entriesQueued < currentLength; entriesQueued += 1)
+                {
+                    /* Get the kernel pointer to the command buffer header. */
+                    gcsCMDBUFFER_PTR commandBuffer = gcvNULL;
+                    gcmkERR_BREAK(_ConvertUserCommandBufferPointer(
+                                Command,
+                                userEntry->commandBuffer,
+                                &commandBuffer
+                                ));
+
+                    /* Is it a dynamic command buffer? */
+                    if (userEntry->dynamic)
+                    {
+                        /* Select dynamic buffer control functions. */
+                        queueControl = &_dynamicBuffer[controlIndex];
+                    }
+
+                    /* No, a static command buffer. */
+                    else
+                    {
+                        /* Select static buffer control functions. */
+                        queueControl = &_staticBuffer[controlIndex];
+                    }
+
+                    /* Set the command buffer pointer to the entry. */
+                    kernelEntry->commandBuffer = commandBuffer;
+
+                    /* If the previous entry was a dynamic command buffer,
+                       link it to the current. */
+                    if (previousDynamic)
+                    {
+                        gcmkERR_BREAK(gckVGCOMMAND_FetchCommand(
+                                    Command,
+                                    previousEnd,
+                                    commandBuffer->address,
+                                    commandBuffer->dataCount,
+                                    gcvNULL
+                                    ));
+
+                        /* The buffer will be auto-executed, only need to
+                           update it after it has been executed. */
+                        kernelEntry->handler = queueControl->update;
+
+                        /* The buffer is only being updated. */
+                        previousExecuted = gcvFALSE;
+                    }
+                    else
+                    {
+                        /* Set the buffer up for execution. */
+                        kernelEntry->handler = queueControl->execute;
+
+                        /* The buffer is being updated. */
+                        previousExecuted = gcvTRUE;
+                    }
+
+                    /* The current buffer's END command becomes the last END. */
+                    previousEnd
+                        = ((gctUINT8_PTR) commandBuffer)
+                        + commandBuffer->bufferOffset
+                        + commandBuffer->dataCount * Command->info.commandAlignment
+                        - Command->info.staticTailSize;
+
+                    /* Update the last entry info. */
+                    previousDynamic = userEntry->dynamic;
+
+                    /* Advance entries. */
+                    userEntry   ++;
+                    kernelEntry ++;
+
+                    /* Update the control index. */
+                    controlIndex = 1;
+                }
+
+                /* If the previous entry was a dynamic command buffer,
+                   terminate it with an END. */
+                if (previousDynamic)
+                {
+                    gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+                                Command,
+                                previousEnd,
+                                Command->info.feBufferInt,
+                                gcvNULL
+                                ));
+                }
+
+                /* Last buffer? */
+                if (EntryCount == 0)
+                {
+                    /* Modify the last command buffer's routines to handle
+                       tasks if any.*/
+                    if (haveFETasks)
+                    {
+                        if (previousExecuted)
+                        {
+                            kernelEntry[-1].handler = queueControl->lastExecute;
+                        }
+                        else
+                        {
+                            kernelEntry[-1].handler = queueControl->lastUpdate;
+                        }
+                    }
+
+                    /* Release the mutex. */
+                    gcmkERR_BREAK(gckOS_ReleaseMutex(
+                                Command->os,
+                                Command->queueMutex
+                                ));
+                    /* Add a semaphore stall after PE EVENT (Before the END). */
+                    {
+                        gctUINT32_PTR memory = (gctUINT32_PTR)(previousEnd - 0x10);
+                        *memory++ = 0x10000007;
+                        *memory++ = 0;
+
+                        *memory++ = 0x20000007;
+                        *memory++ = 0;
+                    }
+                    /* Schedule tasks. */
+                    gcmkERR_BREAK(_ScheduleTasks(Command, TaskTable, previousEnd - 0x10));
+
+                    /* Acquire the mutex. */
+                    gcmkERR_BREAK(gckOS_AcquireMutex(
+                                Command->os,
+                                Command->queueMutex,
+                                gcvINFINITE
+                                ));
+                }
+
+                /* Unkock and schedule the current queue for execution. */
+                gcmkERR_BREAK(_UnlockCurrentQueue(
+                            Command, currentLength
+                            ));
+            }
+        }
+        while (gcvFALSE);
+
+        if (mappedQueue)
+        {
+            if(!needCopy)
+            {
+                /* Unmap the user command buffer. */
+                gcmkERR_BREAK(gckOS_UnmapUserPointer(
+                            Command->os,
+                            Queue,
+                            queueSize,
+                            mappedQueue
+                            ));
+            }
+            else
+            {
+                gcmkERR_BREAK(gckOS_Free(Command->os, mappedQueue));
+            }
+        }
+
+        /* Release the mutex. */
+        gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+                    Command->os,
+                    Command->commitMutex
+                    ));
+
+        gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+                    Command->os, Command->powerSemaphore));
+    }
+    while (gcvFALSE);
+#ifdef __QNXNTO__
+    if (userContextMapped)
+    {
+        /* Unmap the user context. */
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                    Command->os,
+                    userContext,
+                    gcmSIZEOF(*userContext),
+                    Context));
+    }
+
+    if (userTaskTableMapped)
+    {
+        /* Unmap the user taskTable. */
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+                    Command->os,
+                    userTaskTable,
+                    gcmSIZEOF(*userTaskTable),
+                    TaskTable));
+    }
+#endif
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+#endif /* gcdENABLE_VG */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
@@ -0,0 +1,1722 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_DATABASE
+
+/*******************************************************************************
+***** Private fuctions ********************************************************/
+
+#define _GetSlot(database, x) \
+    (gctUINT32)(gcmPTR_TO_UINT64(x) % gcmCOUNTOF(database->list))
+
+/*******************************************************************************
+**  gckKERNEL_FindDatabase
+**
+**  Find a database identified by a process ID and move it to the head of the
+**  hash list.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          ProcessID that identifies the database.
+**
+**      gctBOOL LastProcessID
+**          gcvTRUE if searching for the last known process ID.  gcvFALSE if
+**          we need to search for the process ID specified by the ProcessID
+**          argument.
+**
+**  OUTPUT:
+**
+**      gcsDATABASE_PTR * Database
+**          Pointer to a variable receiving the database structure pointer on
+**          success.
+*/
+gceSTATUS
+gckKERNEL_FindDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL LastProcessID,
+    OUT gcsDATABASE_PTR * Database
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database, previous;
+    gctSIZE_T slot;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d LastProcessID=%d",
+                   Kernel, ProcessID, LastProcessID);
+
+    /* Compute the hash for the database. */
+    slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Check whether we are getting the last known database. */
+    if (LastProcessID)
+    {
+        /* Use last database. */
+        database = Kernel->db->lastDatabase;
+
+        if (database == gcvNULL)
+        {
+            /* Database not found. */
+            gcmkONERROR(gcvSTATUS_INVALID_DATA);
+        }
+    }
+    else
+    {
+        /* Walk the hash list. */
+        for (previous = gcvNULL, database = Kernel->db->db[slot];
+             database != gcvNULL;
+             database = database->next)
+        {
+            if (database->processID == ProcessID)
+            {
+                /* Found it! */
+                break;
+            }
+
+            previous = database;
+        }
+
+        if (database == gcvNULL)
+        {
+            /* Database not found. */
+            gcmkONERROR(gcvSTATUS_INVALID_DATA);
+        }
+
+        if (previous != gcvNULL)
+        {
+            /* Move database to the head of the hash list. */
+            previous->next   = database->next;
+            database->next   = Kernel->db->db[slot];
+            Kernel->db->db[slot] = database;
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+    /* Return the database. */
+    *Database = database;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Database=0x%x", *Database);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_DeinitDatabase
+**
+**  De-init a database structure.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gcsDATABASE_PTR Database
+**          Pointer to the database structure to deinit.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+static gceSTATUS
+gckKERNEL_DeinitDatabase(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gcmkHEADER_ARG("Kernel=%p Database=%p", Kernel, Database);
+
+    if (Database)
+    {
+        Database->deleted = gcvFALSE;
+
+        /* Destory handle db. */
+        if (Database->refs)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Database->refs));
+            Database->refs = gcvNULL;
+        }
+
+        if (Database->handleDatabase)
+        {
+            gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Database->handleDatabase));
+            Database->handleDatabase = gcvNULL;
+        }
+
+        if (Database->handleDatabaseMutex)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Database->handleDatabaseMutex));
+            Database->handleDatabaseMutex = gcvNULL;
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**  gckKERNEL_NewRecord
+**
+**  Create a new database record structure and insert it to the head of the
+**  database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gcsDATABASE_PTR Database
+**          Pointer to a database structure.
+**
+**  OUTPUT:
+**
+**      gcsDATABASE_RECORD_PTR * Record
+**          Pointer to a variable receiving the database record structure
+**          pointer on success.
+*/
+static gceSTATUS
+gckKERNEL_NewRecord(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database,
+    IN gctUINT32 Slot,
+    OUT gcsDATABASE_RECORD_PTR * Record
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gcsDATABASE_RECORD_PTR record = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p Database=%p", Kernel, Database);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (Kernel->db->freeRecord != gcvNULL)
+    {
+        /* Allocate the record from the free list. */
+        record             = Kernel->db->freeRecord;
+        Kernel->db->freeRecord = record->next;
+    }
+    else
+    {
+        gctPOINTER pointer = gcvNULL;
+
+        /* Allocate the record from the heap. */
+        gcmkONERROR(gckOS_Allocate(Kernel->os,
+                                   gcmSIZEOF(gcsDATABASE_RECORD),
+                                   &pointer));
+
+        record = pointer;
+    }
+
+    /* Insert the record in the database. */
+    record->next         = Database->list[Slot];
+    Database->list[Slot] = record;
+
+    /* Release the database mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+    /* Return the record. */
+    *Record = record;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Record=0x%x", *Record);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+    if (record != gcvNULL)
+    {
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_DeleteRecord
+**
+**  Remove a database record from the database and delete its structure.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gcsDATABASE_PTR Database
+**          Pointer to a database structure.
+**
+**      gceDATABASE_TYPE Type
+**          Type of the record to remove.
+**
+**      gctPOINTER Data
+**          Data of the record to remove.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T_PTR Bytes
+**          Pointer to a variable that receives the size of the record deleted.
+**          Can be gcvNULL if the size is not required.
+*/
+static gceSTATUS
+gckKERNEL_DeleteRecord(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Data,
+    OUT gctSIZE_T_PTR Bytes OPTIONAL
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gcsDATABASE_RECORD_PTR record, previous;
+    gctUINT32 slot = _GetSlot(Database, Data);
+
+    gcmkHEADER_ARG("Kernel=%p Database=%p Type=%d Data=%p",
+                   Kernel, Database, Type, Data);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Scan the database for this record. */
+    for (record = Database->list[slot], previous = gcvNULL;
+         record != gcvNULL;
+         record = record->next
+    )
+    {
+        if ((record->type == Type)
+        &&  (record->data == Data)
+        )
+        {
+            /* Found it! */
+            break;
+        }
+
+        previous = record;
+    }
+
+    if (record == gcvNULL)
+    {
+        /* Ouch!  This record is not found? */
+        gcmkONERROR(gcvSTATUS_INVALID_DATA);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return size of record. */
+        *Bytes = record->bytes;
+    }
+
+    /* Remove record from database. */
+    if (previous == gcvNULL)
+    {
+        Database->list[slot] = record->next;
+    }
+    else
+    {
+        previous->next = record->next;
+    }
+
+    /* Insert record in free list. */
+    record->next       = Kernel->db->freeRecord;
+    Kernel->db->freeRecord = record;
+
+    /* Release the database mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_FindRecord
+**
+**  Find a database record from the database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gcsDATABASE_PTR Database
+**          Pointer to a database structure.
+**
+**      gceDATABASE_TYPE Type
+**          Type of the record to remove.
+**
+**      gctPOINTER Data
+**          Data of the record to remove.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T_PTR Bytes
+**          Pointer to a variable that receives the size of the record deleted.
+**          Can be gcvNULL if the size is not required.
+*/
+static gceSTATUS
+gckKERNEL_FindRecord(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Data,
+    OUT gcsDATABASE_RECORD_PTR Record
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gcsDATABASE_RECORD_PTR record;
+    gctUINT32 slot = _GetSlot(Database, Data);
+
+    gcmkHEADER_ARG("Kernel=%p Database=%p Type=%d Data=%p",
+                   Kernel, Database, Type, Data);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Scan the database for this record. */
+    for (record = Database->list[slot];
+         record != gcvNULL;
+         record = record->next
+    )
+    {
+        if ((record->type == Type)
+        &&  (record->data == Data)
+        )
+        {
+            /* Found it! */
+            break;
+        }
+    }
+
+    if (record == gcvNULL)
+    {
+        /* Ouch!  This record is not found? */
+        gcmkONERROR(gcvSTATUS_INVALID_DATA);
+    }
+
+    if (Record != gcvNULL)
+    {
+        /* Return information of record. */
+        gcmkONERROR(
+            gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
+    }
+
+    /* Release the database mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+    /* Success. */
+    gcmkFOOTER_ARG("Record=0x%x", Record);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+***** Public API **************************************************************/
+
+/*******************************************************************************
+**  gckKERNEL_CreateProcessDB
+**
+**  Create a new process database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_CreateProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsDATABASE_PTR database = gcvNULL;
+    gctPOINTER pointer = gcvNULL;
+    gctBOOL acquired = gcvFALSE;
+    gctSIZE_T slot;
+    gctUINT32 i;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d", Kernel, ProcessID);
+
+    /* Compute the hash for the database. */
+    slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Walk the hash list. */
+    for (database = Kernel->db->db[slot];
+         database != gcvNULL;
+         database = database->next)
+    {
+        if (database->processID == ProcessID)
+        {
+            gctINT32 oldVal = 0;
+
+            if (database->deleted)
+            {
+                gcmkFATAL("%s(%d): DB of Process=0x%x cannot be reentered since it was in deletion\n",
+                          __FUNCTION__, __LINE__, ProcessID);
+                gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+            }
+
+            gcmkVERIFY_OK(gckOS_AtomIncrement(Kernel->os, database->refs, &oldVal));
+            goto OnExit;
+        }
+    }
+
+    if (Kernel->db->freeDatabase)
+    {
+        /* Allocate a database from the free list. */
+        database = Kernel->db->freeDatabase;
+        Kernel->db->freeDatabase = database->next;
+    }
+    else
+    {
+        /* Allocate a new database from the heap. */
+        gcmkONERROR(gckOS_Allocate(Kernel->os,
+                                   gcmSIZEOF(gcsDATABASE),
+                                   &pointer));
+
+        gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsDATABASE));
+
+        database = pointer;
+
+        gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->counterMutex));
+    }
+
+    /* Initialize the database. */
+    /* Save the hash slot. */
+    database->slot                      = slot;
+    database->processID                 = ProcessID;
+    database->vidMem.bytes              = 0;
+    database->vidMem.maxBytes           = 0;
+    database->vidMem.totalBytes         = 0;
+    database->vidMem.freeCount          = 0;
+    database->vidMem.allocCount         = 0;
+
+    database->nonPaged.bytes            = 0;
+    database->nonPaged.maxBytes         = 0;
+    database->nonPaged.totalBytes       = 0;
+    database->nonPaged.freeCount        = 0;
+    database->nonPaged.allocCount       = 0;
+
+    database->mapMemory.bytes           = 0;
+    database->mapMemory.maxBytes        = 0;
+    database->mapMemory.totalBytes      = 0;
+    database->mapMemory.freeCount       = 0;
+    database->mapMemory.allocCount      = 0;
+
+    for (i = 0; i < gcmCOUNTOF(database->list); i++)
+    {
+        database->list[i] = gcvNULL;
+    }
+
+    for (i = 0; i < gcvVIDMEM_TYPE_COUNT; i++)
+    {
+        database->vidMemType[i].bytes = 0;
+        database->vidMemType[i].maxBytes = 0;
+        database->vidMemType[i].totalBytes = 0;
+        database->vidMemType[i].freeCount = 0;
+        database->vidMemType[i].allocCount = 0;
+    }
+
+    for (i = 0; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+    {
+        database->vidMemPool[i].bytes = 0;
+        database->vidMemPool[i].maxBytes = 0;
+        database->vidMemPool[i].totalBytes = 0;
+        database->vidMemPool[i].freeCount = 0;
+        database->vidMemPool[i].allocCount = 0;
+    }
+
+    gcmkASSERT(database->refs == gcvNULL);
+    gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &database->refs));
+    gcmkONERROR(gckOS_AtomSet(Kernel->os, database->refs, 1));
+
+    gcmkASSERT(database->handleDatabase == gcvNULL);
+    gcmkONERROR(gckKERNEL_CreateIntegerDatabase(Kernel, 64, &database->handleDatabase));
+
+    gcmkASSERT(database->handleDatabaseMutex == gcvNULL);
+    gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->handleDatabaseMutex));
+
+    /* Insert the database into the hash. */
+    database->next = Kernel->db->db[slot];
+    Kernel->db->db[slot] = database;
+
+    /* Reset idle timer. */
+    Kernel->db->lastIdle = 0;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        gcmkVERIFY_OK(gckKERNEL_DeinitDatabase(Kernel, database));
+
+        if (pointer)
+        {
+            gcmkOS_SAFE_FREE(Kernel->os, pointer);
+        }
+    }
+
+OnExit:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_AddProcessDB
+**
+**  Add a record to a process database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**      gceDATABASE_TYPE TYPE
+**          Type of the record to add.
+**
+**      gctPOINTER Pointer
+**          Data of the record to add.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of the record to add.
+**
+**      gctSIZE_T Size
+**          Size of the record to add.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_AddProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gcsDATABASE_RECORD_PTR record = gcvNULL;
+    gcsDATABASE_COUNTERS * count;
+    gctUINT32 vidMemType;
+    gcePOOL vidMemPool;
+    gceDATABASE_TYPE vidMemDbType;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d Type=%d Pointer=%p "
+                   "Physical=%p Size=%lu",
+                   Kernel, ProcessID, Type, Pointer, Physical, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Decode type. */
+    vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
+    vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+    vidMemDbType = (Type & gcdDB_VIDEO_MEMORY_DBTYPE_MASK) >> gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT;
+
+    Type &= gcdDATABASE_TYPE_MASK;
+
+    /* Special case the idle record. */
+    if (Type == gcvDB_IDLE)
+    {
+        gctUINT64 time;
+
+        /* Get the current profile time. */
+        gcmkONERROR(gckOS_GetProfileTick(&time));
+
+        if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
+        {
+            /* Out of idle, adjust time it was idle. */
+            Kernel->db->idleTime += time - Kernel->db->lastIdle;
+            Kernel->db->lastIdle  = 0;
+        }
+        else if (ProcessID == 1)
+        {
+            /* Save current idle time. */
+            Kernel->db->lastIdle = time;
+        }
+
+#if gcdDYNAMIC_SPEED
+        {
+            /* Test for first call. */
+            if (Kernel->db->lastSlowdown == 0)
+            {
+                /* Save milliseconds. */
+                Kernel->db->lastSlowdown     = time;
+                Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
+            }
+            else
+            {
+                /* Compute ellapsed time in milliseconds. */
+                gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
+
+                /* Test for end of period. */
+                if (delta >= gcdDYNAMIC_SPEED)
+                {
+                    /* Compute number of idle milliseconds. */
+                    gctUINT idle = gckOS_ProfileToMS(
+                        Kernel->db->idleTime  - Kernel->db->lastSlowdownIdle);
+
+                    /* Broadcast to slow down the GPU. */
+                    gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
+                                                              Kernel->hardware,
+                                                              idle,
+                                                              delta));
+
+                    /* Save current time. */
+                    Kernel->db->lastSlowdown     = time;
+                    Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
+                }
+            }
+        }
+#endif
+
+        /* Success. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+    /* Find the database. */
+    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+    /* Create a new record in the database. */
+    gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record));
+
+    /* Initialize the record. */
+    record->kernel   = Kernel;
+    record->type     = Type;
+    record->data     = Pointer;
+    record->physical = Physical;
+    record->bytes    = Size;
+
+    /* Get pointer to counters. */
+    switch (Type)
+    {
+    case gcvDB_VIDEO_MEMORY:
+        count = &database->vidMem;
+        break;
+
+    case gcvDB_NON_PAGED:
+        count = &database->nonPaged;
+        break;
+
+    case gcvDB_CONTIGUOUS:
+        count = &database->contiguous;
+        break;
+
+    case gcvDB_MAP_MEMORY:
+        count = &database->mapMemory;
+        break;
+
+    case gcvDB_MAP_USER_MEMORY:
+        count = &database->mapUserMemory;
+        break;
+
+    default:
+        count = gcvNULL;
+        break;
+    }
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+    if (count != gcvNULL)
+    {
+        /* Adjust counters. */
+        count->totalBytes += Size;
+        count->bytes      += Size;
+        count->allocCount++;
+
+        if (count->bytes > count->maxBytes)
+        {
+            count->maxBytes = count->bytes;
+        }
+    }
+
+    if (Type == gcvDB_VIDEO_MEMORY)
+    {
+        count = &database->vidMemType[vidMemType];
+
+        /* Adjust counters. */
+        count->totalBytes += Size;
+        count->bytes      += Size;
+        count->allocCount++;
+
+        if (count->bytes > count->maxBytes)
+        {
+            count->maxBytes = count->bytes;
+        }
+
+        count = &database->vidMemPool[vidMemPool];
+
+        /* Adjust counters. */
+        count->totalBytes += Size;
+        count->bytes      += Size;
+        count->allocCount++;
+
+        if (count->bytes > count->maxBytes)
+        {
+            count->maxBytes = count->bytes;
+        }
+
+        if (vidMemDbType == gcvDB_CONTIGUOUS)
+        {
+            count = &database->contiguous;
+
+            /* Adjust counters. */
+            count->totalBytes += Size;
+            count->bytes      += Size;
+            count->allocCount++;
+
+            if (count->bytes > count->maxBytes)
+            {
+                count->maxBytes = count->bytes;
+            }
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_RemoveProcessDB
+**
+**  Remove a record from a process database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**      gceDATABASE_TYPE TYPE
+**          Type of the record to remove.
+**
+**      gctPOINTER Pointer
+**          Data of the record to remove.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_RemoveProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gctSIZE_T bytes = 0;
+    gctUINT32 vidMemType;
+    gcePOOL vidMemPool;
+    gceDATABASE_TYPE vidMemDbType;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d Type=%d Pointer=%p",
+                   Kernel, ProcessID, Type, Pointer);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+    /* Decode type. */
+    vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
+    vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+    vidMemDbType = (Type & gcdDB_VIDEO_MEMORY_DBTYPE_MASK) >> gcdDB_VIDEO_MEMORY_DBTYPE_SHIFT;
+
+    Type &= gcdDATABASE_TYPE_MASK;
+
+    /* Find the database. */
+    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+    /* Delete the record. */
+    gcmkONERROR(
+        gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+    /* Update counters. */
+    switch (Type)
+    {
+    case gcvDB_VIDEO_MEMORY:
+        database->vidMem.bytes -= bytes;
+        database->vidMem.freeCount++;
+        database->vidMemType[vidMemType].bytes -= bytes;
+        database->vidMemType[vidMemType].freeCount++;
+        database->vidMemPool[vidMemPool].bytes -= bytes;
+        database->vidMemPool[vidMemPool].freeCount++;
+
+        if (vidMemDbType == gcvDB_CONTIGUOUS)
+        {
+            database->contiguous.bytes -= bytes;
+            database->contiguous.freeCount++;
+        }
+
+        break;
+
+    case gcvDB_NON_PAGED:
+        database->nonPaged.bytes -= bytes;
+        database->nonPaged.freeCount++;
+        break;
+
+    case gcvDB_CONTIGUOUS:
+        database->contiguous.bytes -= bytes;
+        database->contiguous.freeCount++;
+        break;
+
+    case gcvDB_MAP_MEMORY:
+        database->mapMemory.bytes -= bytes;
+        database->mapMemory.freeCount++;
+        break;
+
+    case gcvDB_MAP_USER_MEMORY:
+        database->mapUserMemory.bytes -= bytes;
+        database->mapUserMemory.freeCount++;
+        break;
+
+    default:
+        break;
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_FindProcessDB
+**
+**  Find a record from a process database.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**      gceDATABASE_TYPE TYPE
+**          Type of the record to remove.
+**
+**      gctPOINTER Pointer
+**          Data of the record to remove.
+**
+**  OUTPUT:
+**
+**      gcsDATABASE_RECORD_PTR Record
+**          Copy of record.
+*/
+gceSTATUS
+gckKERNEL_FindProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 ThreadID,
+    IN gceDATABASE_TYPE Type,
+    IN gctPOINTER Pointer,
+    OUT gcsDATABASE_RECORD_PTR Record
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d Type=%d Pointer=%p",
+                   Kernel, ProcessID, ThreadID, Type, Pointer);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+    /* Find the database. */
+    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+    /* Find the record. */
+    gcmkONERROR(
+        gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_DestroyProcessDB
+**
+**  Destroy a process database.  If the database contains any records, the data
+**  inside those records will be deleted as well.  This aids in the cleanup if
+**  a process has died unexpectedly or has memory leaks.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_DestroyProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckKERNEL kernel = Kernel;
+    gcsDATABASE_PTR previous = gcvNULL;
+    gcsDATABASE_PTR database = gcvNULL;
+    gcsDATABASE_PTR db = gcvNULL;
+    gctBOOL acquired = gcvFALSE;
+    gctSIZE_T slot;
+    gctUINT32 i;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d", Kernel, ProcessID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Compute the hash for the database. */
+    slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Walk the hash list. */
+    for (database = Kernel->db->db[slot];
+         database != gcvNULL;
+         database = database->next)
+    {
+        if (database->processID == ProcessID)
+        {
+            break;
+        }
+    }
+
+    if (database)
+    {
+        gctINT32 oldVal = 0;
+        gcmkONERROR(gckOS_AtomDecrement(Kernel->os, database->refs, &oldVal));
+        if (oldVal != 1)
+        {
+            goto OnExit;
+        }
+
+        /* Mark it for delete so disallow reenter until really delete it */
+        gcmkASSERT(!database->deleted);
+        database->deleted = gcvTRUE;
+    }
+    else
+    {
+        gcmkFATAL("%s(%d): DB destroy of Process=0x%x cannot match with creation\n",
+                  __FUNCTION__, __LINE__, ProcessID);
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+
+#if gcdCAPTURE_ONLY_MODE
+    gcmkPRINT("Capture only mode: The max allocation from System Pool is %llu bytes", database->vidMemPool[gcvPOOL_SYSTEM].maxBytes);
+#endif
+
+    /* Cannot remove the database from the hash list
+    ** since later records deinit need to access from the hash
+    */
+
+    gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    acquired = gcvFALSE;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+                   "DB(%d): VidMem: total=%lu max=%lu",
+                   ProcessID, database->vidMem.totalBytes,
+                   database->vidMem.maxBytes);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+                   "DB(%d): NonPaged: total=%lu max=%lu",
+                   ProcessID, database->nonPaged.totalBytes,
+                   database->nonPaged.maxBytes);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+                   "DB(%d): Idle time=%llu",
+                   ProcessID, Kernel->db->idleTime);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+                   "DB(%d): Map: total=%lu max=%lu",
+                   ProcessID, database->mapMemory.totalBytes,
+                   database->mapMemory.maxBytes);
+
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                       "Process %d has entries in its database:",
+                       ProcessID);
+    }
+
+    for (i = 0; i < gcmCOUNTOF(database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR record, next;
+
+        /* Walk all records. */
+        for (record = database->list[i]; record != gcvNULL; record = next)
+        {
+            gctBOOL asynchronous = gcvTRUE;
+            gckVIDMEM_NODE nodeObject;
+            gctPHYS_ADDR physical;
+            gctUINT32 handle;
+
+            /* Next next record. */
+            next = record->next;
+
+            /* Dispatch on record type. */
+            switch (record->type)
+            {
+            case gcvDB_VIDEO_MEMORY:
+                gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
+                                                      ProcessID,
+                                                      gcmPTR2INT32(record->data),
+                                                      &nodeObject));
+
+                /* Free the video memory. */
+                gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+                                                           ProcessID,
+                                                           gcmPTR2INT32(record->data)));
+
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+                                                         nodeObject));
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: VIDEO_MEMORY 0x%x (status=%d)",
+                               record->data, status);
+                break;
+
+            case gcvDB_NON_PAGED:
+                physical = gcmNAME_TO_PTR(record->physical);
+
+                /* Free the non paged memory. */
+                status = gckOS_FreeNonPagedMemory(Kernel->os,
+                                                  physical,
+                                                  record->data,
+                                                  record->bytes);
+
+                gcmRELEASE_NAME(record->physical);
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
+                               record->data, record->bytes, status);
+                break;
+
+            case gcvDB_SIGNAL:
+#if USE_NEW_LINUX_SIGNAL
+                status = gcvSTATUS_NOT_SUPPORTED;
+#else
+                /* Free the user signal. */
+                status = gckOS_DestroyUserSignal(Kernel->os,
+                                                 gcmPTR2INT32(record->data));
+#endif /* USE_NEW_LINUX_SIGNAL */
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: SIGNAL %d (status=%d)",
+                               (gctINT)(gctUINTPTR_T)record->data, status);
+                break;
+
+            case gcvDB_VIDEO_MEMORY_LOCKED:
+                handle = gcmPTR2INT32(record->data);
+
+                gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
+                                                      ProcessID,
+                                                      handle,
+                                                      &nodeObject));
+
+                /* Unlock CPU. */
+                gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU(
+                    record->kernel, nodeObject, ProcessID, gcvTRUE, gcvFALSE));
+
+                /* Unlock what we still locked */
+                status = gckVIDMEM_NODE_Unlock(record->kernel,
+                                               nodeObject,
+                                               ProcessID,
+                                               &asynchronous);
+
+#if gcdENABLE_VG
+                if (record->kernel->core == gcvCORE_VG)
+                {
+                    if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
+                    {
+                        status = gckVIDMEM_NODE_Unlock(record->kernel,
+                                                       nodeObject,
+                                                       ProcessID,
+                                                       gcvNULL);
+                    }
+
+                    /* Deref handle. */
+                    gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+                                                               ProcessID,
+                                                               handle));
+
+                    /* Deref node. */
+                    gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+                                                             nodeObject));
+                }
+                else
+#endif
+                {
+                    /* Deref handle. */
+                    gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+                                                               ProcessID,
+                                                               handle));
+
+                    if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
+                    {
+                        /* Schedule unlock: will unlock and deref node later. */
+                        status = gckEVENT_Unlock(record->kernel->eventObj,
+                                                 gcvKERNEL_PIXEL,
+                                                 nodeObject);
+                    }
+                    else
+                    {
+                        /* Deref node */
+                        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+                                                                 nodeObject));
+                    }
+                }
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
+                               record->data, status);
+                break;
+
+            case gcvDB_CONTEXT:
+                status = gckCOMMAND_Detach(record->kernel->command, gcmNAME_TO_PTR(record->data));
+                gcmRELEASE_NAME(record->data);
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: CONTEXT 0x%x (status=%d)",
+                               record->data, status);
+                break;
+
+            case gcvDB_MAP_MEMORY:
+                /* Unmap memory. */
+                status = gckKERNEL_UnmapMemory(record->kernel,
+                                               record->physical,
+                                               record->bytes,
+                                               record->data,
+                                               ProcessID);
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: MAP MEMORY %d (status=%d)",
+                               gcmPTR2INT32(record->data), status);
+                break;
+
+            case gcvDB_SHBUF:
+                /* Free shared buffer. */
+                status = gckKERNEL_DestroyShBuffer(record->kernel,
+                                                   (gctSHBUF) record->data);
+
+                gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+                               "DB: SHBUF %u (status=%d)",
+                               (gctUINT32)(gctUINTPTR_T) record->data, status);
+                break;
+
+            default:
+                gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
+                               "DB: Correcupted record=0x%08x type=%d",
+                               record, record->type);
+                break;
+            }
+
+            /* Delete the record. */
+            gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
+                                               database,
+                                               record->type,
+                                               record->data,
+                                               gcvNULL));
+        }
+    }
+
+    gcmkONERROR(gckKERNEL_DestroyProcessReservedUserMap(Kernel, ProcessID));
+
+    /* Acquire the database mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Walk the hash list. */
+    for (db = Kernel->db->db[slot];
+         db != gcvNULL;
+         db = db->next)
+    {
+        if (db->processID == ProcessID)
+        {
+            break;
+        }
+        previous = db;
+    }
+
+    if (db != database || !db->deleted)
+    {
+        gcmkFATAL("%s(%d): DB of Process=0x%x corrupted after found in deletion\n",
+                  __FUNCTION__, __LINE__, ProcessID);
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+
+    /* Remove the database from the hash list. */
+    if (previous)
+    {
+        previous->next = database->next;
+    }
+    else
+    {
+        Kernel->db->db[slot] = database->next;
+    }
+
+    /* Deinit current database. */
+    gcmkVERIFY_OK(gckKERNEL_DeinitDatabase(Kernel, database));
+
+    if (Kernel->db->lastDatabase)
+    {
+        /* Insert last database to the free list. */
+        Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
+        Kernel->db->freeDatabase       = Kernel->db->lastDatabase;
+    }
+
+    /* Update last database to current one. */
+    Kernel->db->lastDatabase = database;
+
+OnError:
+OnExit:
+    if (acquired)
+    {
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+    }
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckKERNEL_QueryProcessDB
+**
+**  Query a process database for the current usage of a particular record type.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to a gckKERNEL object.
+**
+**      gctUINT32 ProcessID
+**          Process ID used to identify the database.
+**
+**      gctBOOL LastProcessID
+**          gcvTRUE if searching for the last known process ID.  gcvFALSE if
+**          we need to search for the process ID specified by the ProcessID
+**          argument.
+**
+**      gceDATABASE_TYPE Type
+**          Type of the record to query.
+**
+**  OUTPUT:
+**
+**      gcuDATABASE_INFO * Info
+**          Pointer to a variable that receives the requested information.
+*/
+gceSTATUS
+gckKERNEL_QueryProcessDB(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL LastProcessID,
+    IN gceDATABASE_TYPE Type,
+    OUT gcuDATABASE_INFO * Info
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gcePOOL vidMemPool;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d Type=%d Info=%p",
+                   Kernel, ProcessID, Type, Info);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Info != gcvNULL);
+
+    /* Deocde pool. */
+    vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+
+    Type &= gcdDATABASE_TYPE_MASK;
+
+    /* Find the database. */
+    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+    /* Get pointer to counters. */
+    switch (Type)
+    {
+    case gcvDB_VIDEO_MEMORY:
+        if (vidMemPool != gcvPOOL_UNKNOWN)
+        {
+            gckOS_MemCopy(&Info->counters,
+                          &database->vidMemPool[vidMemPool],
+                          gcmSIZEOF(database->vidMemPool[vidMemPool]));
+        }
+        else
+        {
+            gckOS_MemCopy(&Info->counters,
+                          &database->vidMem,
+                          gcmSIZEOF(database->vidMem));
+        }
+        break;
+
+    case gcvDB_NON_PAGED:
+        gckOS_MemCopy(&Info->counters,
+                                  &database->nonPaged,
+                                  gcmSIZEOF(database->vidMem));
+        break;
+
+    case gcvDB_CONTIGUOUS:
+        gckOS_MemCopy(&Info->counters,
+                                  &database->contiguous,
+                                  gcmSIZEOF(database->vidMem));
+        break;
+
+    case gcvDB_IDLE:
+        Info->time           = Kernel->db->idleTime;
+        Kernel->db->idleTime = 0;
+        break;
+
+    case gcvDB_MAP_MEMORY:
+        gckOS_MemCopy(&Info->counters,
+                                  &database->mapMemory,
+                                  gcmSIZEOF(database->mapMemory));
+        break;
+
+    default:
+        break;
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_FindHandleDatbase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    OUT gctPOINTER * HandleDatabase,
+    OUT gctPOINTER * HandleDatabaseMutex
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d",
+                   Kernel, ProcessID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Find the database. */
+    gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+    *HandleDatabase = database->handleDatabase;
+    *HandleDatabaseMutex = database->handleDatabaseMutex;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_DumpProcessDB(
+    IN gckKERNEL Kernel
+    )
+{
+    gcsDATABASE_PTR database;
+    gctINT i, pid;
+    gctUINT8 name[24];
+
+    gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+    /* Acquire the database mutex. */
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("***  PROCESS DB DUMP   ***\n");
+    gcmkPRINT("**************************\n");
+
+    gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME");
+    /* Walk the databases. */
+    for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
+    {
+        for (database = Kernel->db->db[i];
+             database != gcvNULL;
+             database = database->next)
+        {
+            pid = database->processID;
+
+            gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name)));
+
+            gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+            gcmkPRINT_N(8, "%-8d%s\n", pid, name);
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+void
+_DumpCounter(
+    IN gcsDATABASE_COUNTERS * Counter,
+    IN gctCONST_STRING Name
+    )
+{
+    gcmkPRINT("%s:", Name);
+    gcmkPRINT("  Currently allocated : %10lld", Counter->bytes);
+    gcmkPRINT("  Maximum allocated   : %10lld", Counter->maxBytes);
+    gcmkPRINT("  Total allocated     : %10lld", Counter->totalBytes);
+}
+
+gceSTATUS
+gckKERNEL_DumpVidMemUsage(
+    IN gckKERNEL Kernel,
+    IN gctINT32 ProcessID
+    )
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gcsDATABASE_COUNTERS * counter;
+    gctUINT32 i = 0;
+
+    static gctCONST_STRING vidmemTypes[] = {
+        "GENERIC",
+        "INDEX",
+        "VERTEX",
+        "TEXTURE",
+        "RENDER_TARGET",
+        "DEPTH",
+        "BITMAP",
+        "TILE_STATUS",
+        "IMAGE",
+        "MASK",
+        "SCISSOR",
+        "HIERARCHICAL_DEPTH",
+        "ICACHE",
+        "TXDESC",
+        "FENCE",
+        "TFBHEADER",
+        "COMMAND",
+    };
+
+    gcmkHEADER_ARG("Kernel=%p ProcessID=%d",
+                   Kernel, ProcessID);
+
+    gcmSTATIC_ASSERT(gcmCOUNTOF(vidmemTypes) == gcvVIDMEM_TYPE_COUNT,
+                     "Video memory type mismatch");
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Find the database. */
+    gcmkONERROR(
+        gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+    gcmkPRINT("VidMem Usage (Process %d):", ProcessID);
+
+    /* Get pointer to counters. */
+    counter = &database->vidMem;
+
+    _DumpCounter(counter, "Total Video Memory");
+
+    for (i = 0; i < gcvVIDMEM_TYPE_COUNT; i++)
+    {
+        counter = &database->vidMemType[i];
+
+        _DumpCounter(counter, vidmemTypes[i]);
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
@@ -0,0 +1,2392 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include "gc_hal_kernel_buffer.h"
+
+#ifdef __QNXNTO__
+#include "gc_hal_kernel_qnx.h"
+#endif
+
+#define _GC_OBJ_ZONE                    gcvZONE_EVENT
+
+#define gcdEVENT_ALLOCATION_COUNT       (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
+#define gcdEVENT_MIN_THRESHOLD          4
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+
+static gcmINLINE gceSTATUS
+gckEVENT_AllocateQueue(
+    IN gckEVENT Event,
+    OUT gcsEVENT_QUEUE_PTR * Queue
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+
+    /* Do we have free queues? */
+    if (Event->freeList == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    /* Move one free queue from the free list. */
+    * Queue = Event->freeList;
+    Event->freeList = Event->freeList->next;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckEVENT_FreeQueue(
+    IN gckEVENT Event,
+    OUT gcsEVENT_QUEUE_PTR Queue
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+
+    /* Move one free queue from the free list. */
+    Queue->next = Event->freeList;
+    Event->freeList = Queue;
+
+    /* Success. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckEVENT_FreeRecord(
+    IN gckEVENT Event,
+    IN gcsEVENT_PTR Record
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Event->os,
+                                   Event->freeEventMutex,
+                                   gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Push the record on the free list. */
+    Record->next           = Event->freeEventList;
+    Event->freeEventList   = Record;
+    Event->freeEventCount += 1;
+
+    /* Release the mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+gckEVENT_IsEmpty(
+    IN gckEVENT Event,
+    OUT gctBOOL_PTR IsEmpty
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T i;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
+
+    /* Assume the event queue is empty. */
+    *IsEmpty = gcvTRUE;
+
+    /* Walk the event queue. */
+    for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+    {
+        /* Check whether this event is in use. */
+        if (Event->queues[i].head != gcvNULL)
+        {
+            /* The event is in use, hence the queue is not empty. */
+            *IsEmpty = gcvFALSE;
+            break;
+        }
+    }
+
+    /* Try acquiring the mutex. */
+    status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
+    if (status == gcvSTATUS_TIMEOUT)
+    {
+        /* Timeout - queue is no longer empty. */
+        *IsEmpty = gcvFALSE;
+    }
+    else
+    {
+        /* Bail out on error. */
+        gcmkONERROR(status);
+
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_TryToIdleGPU(
+    IN gckEVENT Event
+    )
+{
+    gceSTATUS status;
+    gctBOOL empty = gcvFALSE, idle = gcvFALSE;
+    gctBOOL powerLocked = gcvFALSE;
+    gckHARDWARE hardware;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+    /* Grab gckHARDWARE object. */
+    hardware = Event->kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Check whether the event queue is empty. */
+    gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
+
+    if (empty)
+    {
+        status = gckOS_AcquireMutex(hardware->os, hardware->powerMutex, 0);
+        if (status == gcvSTATUS_TIMEOUT)
+        {
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OK;
+        }
+
+        powerLocked = gcvTRUE;
+
+        /* Query whether the hardware is idle. */
+        gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
+
+        gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
+        powerLocked = gcvFALSE;
+
+        if (idle)
+        {
+            /* Inform the system of idle GPU. */
+            gcmkONERROR(gckOS_Broadcast(Event->os,
+                                        Event->kernel->hardware,
+                                        gcvBROADCAST_GPU_IDLE));
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (powerLocked)
+    {
+        gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+__RemoveRecordFromProcessDB(
+    IN gckEVENT Event,
+    IN gcsEVENT_PTR Record
+    )
+{
+    gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+    gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+    switch (Record->info.command)
+    {
+    case gcvHAL_UNLOCK_VIDEO_MEMORY:
+        gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+            Event->kernel,
+            Record->processID,
+            gcvDB_VIDEO_MEMORY_LOCKED,
+            gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node)));
+        break;
+
+    default:
+        break;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ReleaseVideoMemoryHandle(
+    IN gckKERNEL Kernel,
+    IN OUT gcsEVENT_PTR Record,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE nodeObject;
+    gctUINT32 handle;
+
+    switch(Interface->command)
+    {
+    case gcvHAL_UNLOCK_VIDEO_MEMORY:
+        handle = (gctUINT32)Interface->u.UnlockVideoMemory.node;
+
+        gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+            Kernel, Record->processID, handle, &nodeObject));
+
+        Record->info.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(nodeObject);
+
+        gckVIDMEM_HANDLE_Dereference(Kernel, Record->processID, handle);
+        break;
+
+    default:
+        break;
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _QueryFlush
+**
+**  Check the type of surfaces which will be released by current event and
+**  determine the cache needed to flush.
+**
+*/
+static gceSTATUS
+_QueryFlush(
+    IN gckEVENT Event,
+    IN gcsEVENT_PTR Record,
+    OUT gceKERNEL_FLUSH *Flush
+    )
+{
+    gceKERNEL_FLUSH flush = 0;
+    gckVIDMEM_NODE nodeObject;
+
+    gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+    gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+    while (Record != gcvNULL)
+    {
+        switch (Record->info.command)
+        {
+        case gcvHAL_UNLOCK_VIDEO_MEMORY:
+            nodeObject = gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node);
+
+            switch (nodeObject->type)
+            {
+            case gcvVIDMEM_TYPE_TILE_STATUS:
+                flush |= gcvFLUSH_TILE_STATUS;
+                break;
+            case gcvVIDMEM_TYPE_COLOR_BUFFER:
+                flush |= gcvFLUSH_COLOR;
+                break;
+            case gcvVIDMEM_TYPE_DEPTH_BUFFER:
+                flush |= gcvFLUSH_DEPTH;
+                break;
+            case gcvVIDMEM_TYPE_TEXTURE:
+                flush |= gcvFLUSH_TEXTURE;
+                break;
+            case gcvVIDMEM_TYPE_ICACHE:
+                flush |= gcvFLUSH_ICACHE;
+                break;
+            case gcvVIDMEM_TYPE_TXDESC:
+                flush |= gcvFLUSH_TXDESC;
+                break;
+            case gcvVIDMEM_TYPE_FENCE:
+                flush |= gcvFLUSH_FENCE;
+                break;
+            case gcvVIDMEM_TYPE_VERTEX_BUFFER:
+                flush |= gcvFLUSH_VERTEX;
+                break;
+            case gcvVIDMEM_TYPE_TFBHEADER:
+                flush |= gcvFLUSH_TFBHEADER;
+                break;
+            case gcvVIDMEM_TYPE_GENERIC:
+                flush = gcvFLUSH_ALL;
+                goto Out;
+            default:
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+
+        Record = Record->next;
+    }
+
+Out:
+    *Flush = flush;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+void
+_SubmitTimerFunction(
+    gctPOINTER Data
+    )
+{
+    gckEVENT event = (gckEVENT)Data;
+    gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
+}
+
+/******************************************************************************\
+******************************* gckEVENT API Code *******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckEVENT_Construct
+**
+**  Construct a new gckEVENT object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      gckEVENT * Event
+**          Pointer to a variable that receives the gckEVENT object pointer.
+*/
+gceSTATUS
+gckEVENT_Construct(
+    IN gckKERNEL Kernel,
+    IN gckCOMMAND Command,
+    OUT gckEVENT * Event
+    )
+{
+    gckOS os;
+    gceSTATUS status;
+    gckEVENT eventObj = gcvNULL;
+    int i;
+    gcsEVENT_PTR record;
+    gctPOINTER pointer = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Event != gcvNULL);
+
+    /* Extract the pointer to the gckOS object. */
+    os = Kernel->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Allocate the gckEVENT object. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
+
+    eventObj = pointer;
+
+    /* Reset the object. */
+    gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
+
+    /* Initialize the gckEVENT object. */
+    eventObj->object.type = gcvOBJ_EVENT;
+    eventObj->kernel      = Kernel;
+    eventObj->os          = os;
+    eventObj->command     = Command;
+
+    /* Create the mutexes. */
+    gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex));
+    gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex));
+    gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex));
+
+    /* Create a bunch of event reccords. */
+    for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
+    {
+        /* Allocate an event record. */
+        gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
+
+        record = pointer;
+
+        /* Push it on the free list. */
+        record->next              = eventObj->freeEventList;
+        eventObj->freeEventList   = record;
+        eventObj->freeEventCount += 1;
+    }
+
+    /* Initialize the free list of event queues. */
+    for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
+    {
+        eventObj->repoList[i].next = eventObj->freeList;
+        eventObj->freeList = &eventObj->repoList[i];
+    }
+
+    eventObj->freeQueueCount = gcmCOUNTOF(eventObj->queues);
+
+    gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending));
+
+    gcmkVERIFY_OK(gckOS_CreateTimer(os,
+                                    _SubmitTimerFunction,
+                                    (gctPOINTER)eventObj,
+                                    &eventObj->submitTimer));
+
+#if gcdINTERRUPT_STATISTIC
+    gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->interruptCount));
+    gcmkONERROR(gckOS_AtomSet(os,eventObj->interruptCount, 0));
+#endif
+
+    eventObj->notifyState = -1;
+
+    /* Return pointer to the gckEVENT object. */
+    *Event = eventObj;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Event=0x%x", *Event);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (eventObj != gcvNULL)
+    {
+        if (eventObj->eventQueueMutex != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
+        }
+
+        if (eventObj->freeEventMutex != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
+        }
+
+        if (eventObj->eventListMutex != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
+        }
+
+        while (eventObj->freeEventList != gcvNULL)
+        {
+            record = eventObj->freeEventList;
+            eventObj->freeEventList = record->next;
+
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
+        }
+
+        if (eventObj->pending != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending));
+        }
+
+#if gcdINTERRUPT_STATISTIC
+        if (eventObj->interruptCount)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->interruptCount));
+        }
+#endif
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Destroy
+**
+**  Destroy an gckEVENT object.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Destroy(
+    IN gckEVENT Event
+    )
+{
+    gcsEVENT_PTR record;
+    gcsEVENT_QUEUE_PTR queue;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+    if (Event->submitTimer != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer));
+        gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer));
+    }
+
+    /* Delete the queue mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
+
+    /* Free all free events. */
+    while (Event->freeEventList != gcvNULL)
+    {
+        record = Event->freeEventList;
+        Event->freeEventList = record->next;
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
+    }
+
+    /* Delete the free mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
+
+    /* Free all pending queues. */
+    while (Event->queueHead != gcvNULL)
+    {
+        /* Get the current queue. */
+        queue = Event->queueHead;
+
+        /* Free all pending events. */
+        while (queue->head != gcvNULL)
+        {
+            record      = queue->head;
+            queue->head = record->next;
+
+            gcmkTRACE_ZONE_N(
+                gcvLEVEL_WARNING, gcvZONE_EVENT,
+                gcmSIZEOF(record) + gcmSIZEOF(queue->source),
+                "Event record 0x%x is still pending for %d.",
+                record, queue->source
+                );
+
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
+        }
+
+        /* Remove the top queue from the list. */
+        if (Event->queueHead == Event->queueTail)
+        {
+            Event->queueHead =
+            Event->queueTail = gcvNULL;
+        }
+        else
+        {
+            Event->queueHead = Event->queueHead->next;
+        }
+
+        /* Free the queue. */
+        gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
+    }
+
+    /* Delete the list mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
+
+    gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending));
+
+#if gcdINTERRUPT_STATISTIC
+    gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->interruptCount));
+#endif
+
+    /* Mark the gckEVENT object as unknown. */
+    Event->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckEVENT object. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_GetEvent
+**
+**  Reserve the next available hardware event.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctBOOL Wait
+**          Set to gcvTRUE to force the function to wait if no events are
+**          immediately available.
+**
+**      gceKERNEL_WHERE Source
+**          Source of the event.
+**
+**  OUTPUT:
+**
+**      gctUINT8 * EventID
+**          Reserved event ID.
+*/
+#define gcdINVALID_EVENT_PTR    ((gcsEVENT_PTR)gcvMAXUINTPTR_T)
+
+gceSTATUS
+gckEVENT_GetEvent(
+    IN gckEVENT Event,
+    IN gctBOOL Wait,
+    OUT gctUINT8 * EventID,
+    IN gceKERNEL_WHERE Source
+    )
+{
+    gctINT i, id;
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
+
+    while (gcvTRUE)
+    {
+        /* Grab the queue mutex. */
+        gcmkONERROR(gckOS_AcquireMutex(Event->os,
+                                       Event->eventQueueMutex,
+                                       gcvINFINITE));
+        acquired = gcvTRUE;
+
+        /* Walk through all events. */
+        id = Event->lastID;
+        for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+        {
+            gctINT nextID = id + 1;
+
+            if (nextID == gcmCOUNTOF(Event->queues))
+            {
+                nextID = 0;
+            }
+
+            if (Event->queues[id].head == gcvNULL)
+            {
+                *EventID = (gctUINT8) id;
+
+                Event->lastID = (gctUINT8) nextID;
+
+                /* Save time stamp of event. */
+                Event->queues[id].head   = gcdINVALID_EVENT_PTR;
+                Event->queues[id].stamp  = ++(Event->stamp);
+                Event->queues[id].source = Source;
+
+                /* Decrease the number of free events. */
+                --Event->freeQueueCount;
+
+#if gcdDYNAMIC_SPEED
+                if (Event->freeQueueCount <= gcdDYNAMIC_EVENT_THRESHOLD)
+                {
+                    gcmkONERROR(gckOS_BroadcastHurry(
+                        Event->os,
+                        Event->kernel->hardware,
+                        gcdDYNAMIC_EVENT_THRESHOLD - Event->freeQueueCount));
+                }
+#endif
+
+                /* Release the queue mutex. */
+                gcmkONERROR(gckOS_ReleaseMutex(Event->os,
+                                               Event->eventQueueMutex));
+
+                /* Success. */
+                gcmkTRACE_ZONE_N(
+                    gcvLEVEL_INFO, gcvZONE_EVENT,
+                    gcmSIZEOF(id),
+                    "Using id=%d",
+                    id
+                    );
+
+                gcmkFOOTER_ARG("*EventID=%u", *EventID);
+                return gcvSTATUS_OK;
+            }
+
+            id = nextID;
+        }
+
+#if gcdDYNAMIC_SPEED
+        /* No free events, speed up the GPU right now! */
+        gcmkONERROR(gckOS_BroadcastHurry(Event->os,
+                                         Event->kernel->hardware,
+                                         gcdDYNAMIC_EVENT_THRESHOLD));
+#endif
+
+        /* Release the queue mutex. */
+        gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+        acquired = gcvFALSE;
+
+        /* Fail if wait is not requested. */
+        if (!Wait)
+        {
+            /* Out of resources. */
+            gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        /* Delay a while. */
+        gcmkONERROR(gckOS_Delay(Event->os, 1));
+    }
+
+OnError:
+    if (acquired)
+    {
+        /* Release the queue mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_AllocateRecord
+**
+**  Allocate a record for the new event.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctBOOL AllocateAllowed
+**          State for allocation if out of free events.
+**
+**  OUTPUT:
+**
+**      gcsEVENT_PTR * Record
+**          Allocated event record.
+*/
+static gcmINLINE gceSTATUS
+gckEVENT_AllocateRecord(
+    IN gckEVENT Event,
+    IN gctBOOL AllocateAllowed,
+    OUT gcsEVENT_PTR * Record
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gctINT i;
+    gcsEVENT_PTR record;
+    gctPOINTER pointer = gcvNULL;
+
+    gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Test if we are below the allocation threshold. */
+    if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) ||
+         (Event->freeEventCount == 0) )
+    {
+        /* Allocate a bunch of records. */
+        for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
+        {
+            /* Allocate an event record. */
+            gcmkONERROR(gckOS_Allocate(Event->os,
+                                       gcmSIZEOF(gcsEVENT),
+                                       &pointer));
+
+            record = pointer;
+
+            /* Push it on the free list. */
+            record->next           = Event->freeEventList;
+            Event->freeEventList   = record;
+            Event->freeEventCount += 1;
+        }
+    }
+
+    *Record                = Event->freeEventList;
+    Event->freeEventList   = Event->freeEventList->next;
+    Event->freeEventCount -= 1;
+
+    /* Release the mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_AddList
+**
+**  Add a new event to the list of events.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gcsHAL_INTERFACE_PTR Interface
+**          Pointer to the interface for the event to be added.
+**
+**      gceKERNEL_WHERE FromWhere
+**          Place in the pipe where the event needs to be generated.
+**
+**      gctBOOL AllocateAllowed
+**          State for allocation if out of free events.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_AddList(
+    IN gckEVENT Event,
+    IN gcsHAL_INTERFACE_PTR Interface,
+    IN gceKERNEL_WHERE FromWhere,
+    IN gctBOOL AllocateAllowed,
+    IN gctBOOL FromKernel
+    )
+{
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gcsEVENT_PTR record = gcvNULL;
+    gcsEVENT_QUEUE_PTR queue;
+
+    gcmkHEADER_ARG("Event=0x%x Interface=0x%x",
+                   Event, Interface);
+
+    gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE,
+                    "FromWhere=%d AllocateAllowed=%d",
+                    FromWhere, AllocateAllowed);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+    /* Verify the event command. */
+    gcmkASSERT
+        (  (Interface->command == gcvHAL_WRITE_DATA)
+        || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY)
+        || (Interface->command == gcvHAL_SIGNAL)
+        || (Interface->command == gcvHAL_TIMESTAMP)
+        || (Interface->command == gcvHAL_COMMIT_DONE)
+        || (Interface->command == gcvHAL_DESTROY_MMU)
+        );
+
+    /* Validate the source. */
+    if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
+    {
+        /* Invalid argument. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    /* Allocate a free record. */
+    gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
+
+    /* Termninate the record. */
+    record->next = gcvNULL;
+
+    /* Record the committer. */
+    record->fromKernel = FromKernel;
+
+    /* Copy the event interface into the record. */
+    gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info));
+
+    /* Get process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&record->processID));
+
+    if (FromKernel == gcvFALSE)
+    {
+        gcmkONERROR(__RemoveRecordFromProcessDB(Event, record));
+
+        /* Handle is belonged to current process, it must be released now. */
+        status = _ReleaseVideoMemoryHandle(Event->kernel, record, Interface);
+
+        if (gcmIS_ERROR(status))
+        {
+            /* Ingore error because there are other events in the queue. */
+            status = gcvSTATUS_OK;
+            goto OnError;
+        }
+    }
+
+#ifdef __QNXNTO__
+    record->kernel = Event->kernel;
+#endif
+
+    /* Acquire the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Do we need to allocate a new queue? */
+    if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere))
+    {
+        /* Allocate a new queue. */
+        gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
+
+        /* Initialize the queue. */
+        queue->source = FromWhere;
+        queue->head   = gcvNULL;
+        queue->next   = gcvNULL;
+
+        /* Attach it to the list of allocated queues. */
+        if (Event->queueTail == gcvNULL)
+        {
+            Event->queueHead =
+            Event->queueTail = queue;
+        }
+        else
+        {
+            Event->queueTail->next = queue;
+            Event->queueTail       = queue;
+        }
+    }
+    else
+    {
+        queue = Event->queueTail;
+    }
+
+    /* Attach the record to the queue. */
+    if (queue->head == gcvNULL)
+    {
+        queue->head = record;
+        queue->tail = record;
+    }
+    else
+    {
+        queue->tail->next = record;
+        queue->tail       = record;
+    }
+
+    /* Release the mutex. */
+    gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+    }
+
+    if (record != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Unlock
+**
+**  Schedule an event to unlock virtual memory.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gceKERNEL_WHERE FromWhere
+**          Place in the pipe where the event needs to be generated.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
+**          to unlock.
+**
+**      gceVIDMEM_TYPE Type
+**          Video memory allocation type to unlock.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Unlock(
+    IN gckEVENT Event,
+    IN gceKERNEL_WHERE FromWhere,
+    IN gctPOINTER Node
+    )
+{
+    gceSTATUS status;
+    gcsHAL_INTERFACE iface;
+
+    gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x",
+                   Event, FromWhere, Node);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+    /* Mark the event as an unlock. */
+    iface.command                           = gcvHAL_UNLOCK_VIDEO_MEMORY;
+    iface.u.UnlockVideoMemory.node          = gcmPTR_TO_UINT64(Node);
+    iface.u.UnlockVideoMemory.asynchroneous = 0;
+
+    /* Append it to the queue. */
+    gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Signal
+**
+**  Schedule an event to trigger a signal.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctSIGNAL Signal
+**          Pointer to the signal to trigger.
+**
+**      gceKERNEL_WHERE FromWhere
+**          Place in the pipe where the event needs to be generated.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Signal(
+    IN gckEVENT Event,
+    IN gctSIGNAL Signal,
+    IN gceKERNEL_WHERE FromWhere
+    )
+{
+    gceSTATUS status;
+    gcsHAL_INTERFACE iface;
+
+    gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
+                   Event, Signal, FromWhere);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+    /* Mark the event as a signal. */
+    iface.command            = gcvHAL_SIGNAL;
+    iface.u.Signal.signal    = gcmPTR_TO_UINT64(Signal);
+    iface.u.Signal.auxSignal = 0;
+    iface.u.Signal.process   = 0;
+
+#ifdef __QNXNTO__
+    iface.u.Signal.coid      = 0;
+    iface.u.Signal.rcvid     = 0;
+
+    gcmkONERROR(gckOS_SignalPending(Event->os, Signal));
+#endif
+
+    /* Append it to the queue. */
+    gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Submit
+**
+**  Submit the current event queue to the GPU.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctBOOL Wait
+**          Submit requires one vacant event; if Wait is set to not zero,
+**          and there are no vacant events at this time, the function will
+**          wait until an event becomes vacant so that submission of the
+**          queue is successful.
+**
+**      gctBOOL FromPower
+**          Determines whether the call originates from inside the power
+**          management or not.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Submit(
+    IN gckEVENT Event,
+    IN gctBOOL Wait,
+    IN gctBOOL FromPower
+    )
+{
+    gceSTATUS status;
+    gctUINT8 id = 0xFF;
+    gcsEVENT_QUEUE_PTR queue;
+    gctBOOL acquired = gcvFALSE;
+    gckCOMMAND command = gcvNULL;
+    gctBOOL commitEntered = gcvFALSE;
+    gctUINT32 bytes;
+    gctPOINTER buffer;
+    gctUINT32 executeBytes;
+    gctUINT32 flushBytes;
+
+#if gcdINTERRUPT_STATISTIC
+    gctINT32 oldValue;
+#endif
+
+#if gcdSECURITY
+    gctPOINTER reservedBuffer;
+#endif
+
+    gckHARDWARE hardware;
+
+    gceKERNEL_FLUSH flush = gcvFALSE;
+    gctUINT64 commitStamp;
+
+    gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
+
+    /* Get gckCOMMAND object. */
+    command = Event->command;
+    hardware = Event->kernel->hardware;
+
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    gckOS_GetTicks(&Event->lastCommitStamp);
+
+    /* Are there event queues? */
+    if (Event->queueHead != gcvNULL)
+    {
+        /* Acquire the command queue. */
+        gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
+        commitEntered = gcvTRUE;
+
+        /* Get current commit stamp. */
+        commitStamp = command->commitStamp;
+
+        if (commitStamp)
+        {
+            commitStamp -= 1;
+        }
+
+        /* Process all queues. */
+        while (Event->queueHead != gcvNULL)
+        {
+            /* Acquire the list mutex. */
+            gcmkONERROR(gckOS_AcquireMutex(Event->os,
+                                           Event->eventListMutex,
+                                           gcvINFINITE));
+            acquired = gcvTRUE;
+
+            /* Get the current queue. */
+            queue = Event->queueHead;
+
+            /* Allocate an event ID. */
+            gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
+
+            /* Copy event list to event ID queue. */
+            Event->queues[id].head   = queue->head;
+
+            /* Update current commit stamp. */
+            Event->queues[id].commitStamp = commitStamp;
+
+            /* Remove the top queue from the list. */
+            if (Event->queueHead == Event->queueTail)
+            {
+                Event->queueHead = gcvNULL;
+                Event->queueTail = gcvNULL;
+            }
+            else
+            {
+                Event->queueHead = Event->queueHead->next;
+            }
+
+            /* Free the queue. */
+            gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
+
+            /* Release the list mutex. */
+            gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+            acquired = gcvFALSE;
+
+
+            if (command->feType == gcvHW_FE_WAIT_LINK)
+            {
+                /* Determine cache needed to flush. */
+                gcmkVERIFY_OK(_QueryFlush(Event, Event->queues[id].head, &flush));
+
+                /* Get the size of the hardware event. */
+                gcmkONERROR(gckWLFE_Event(
+                    hardware,
+                    gcvNULL,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+
+                /* Get the size of flush command. */
+                gcmkONERROR(gckHARDWARE_Flush(
+                    hardware,
+                    flush,
+                    gcvNULL,
+                    &flushBytes
+                    ));
+
+                bytes += flushBytes;
+            }
+            else if (command->feType == gcvHW_FE_ASYNC)
+            {
+                /* Get the size of the hardware event. */
+                gcmkONERROR(gckASYNC_FE_Event(
+                    hardware,
+                    gcvNULL,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+            }
+            else
+            {
+                /* Get the size of the hardware event. */
+                gcmkONERROR(gckMCFE_Event(
+                    hardware,
+                    gcvNULL,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+            }
+
+            /* Total bytes need to execute. */
+            executeBytes = bytes;
+
+            /* Reserve space in the command queue. */
+            gcmkONERROR(gckCOMMAND_Reserve(command, bytes, &buffer, &bytes));
+#if gcdSECURITY
+            reservedBuffer = buffer;
+#endif
+
+#if gcdINTERRUPT_STATISTIC
+            gcmkVERIFY_OK(gckOS_AtomIncrement(
+                Event->os,
+                Event->interruptCount,
+                &oldValue
+                ));
+#endif
+
+            if (command->feType == gcvHW_FE_WAIT_LINK)
+            {
+                /* Set the flush in the command queue. */
+                gcmkONERROR(gckHARDWARE_Flush(
+                    hardware,
+                    flush,
+                    buffer,
+                    &flushBytes
+                    ));
+
+                /* Advance to next command. */
+                buffer = (gctUINT8_PTR)buffer + flushBytes;
+
+                /* Set the hardware event in the command queue. */
+                gcmkONERROR(gckWLFE_Event(
+                    hardware,
+                    buffer,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+
+#if gcdSECURITY
+                gckKERNEL_SecurityExecute(
+                    Event->kernel,
+                    reservedBuffer,
+                    executeBytes
+                    );
+#else
+                /* Execute the hardware event. */
+                gcmkONERROR(gckCOMMAND_Execute(command, executeBytes));
+#endif
+            }
+            else if (command->feType == gcvHW_FE_ASYNC)
+            {
+                /* Set the hardware event in the command queue. */
+                gcmkONERROR(gckASYNC_FE_Event(
+                    hardware,
+                    buffer,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+
+                /* Execute the hardware event. */
+                gcmkONERROR(gckCOMMAND_ExecuteAsync(command, executeBytes));
+            }
+            else
+            {
+                /* Set the hardware event in the command queue. */
+                gcmkONERROR(gckMCFE_Event(
+                    hardware,
+                    buffer,
+                    id,
+                    Event->queues[id].source,
+                    &bytes
+                    ));
+
+                /* Execute the hardware event. */
+                gcmkONERROR(gckCOMMAND_ExecuteMultiChannel(command, 0, 0, executeBytes));
+            }
+
+#if gcdNULL_DRIVER || gcdCAPTURE_ONLY_MODE
+            /* Notify immediately on infinite hardware. */
+            gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
+
+            gcmkONERROR(gckEVENT_Notify(Event, 0));
+#endif
+        }
+
+        /* Release the command queue. */
+        gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
+
+#if !gcdNULL_DRIVER
+        if (!FromPower)
+        {
+            gcmkVERIFY_OK(_TryToIdleGPU(Event));
+        }
+#endif
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Need to unroll the mutex acquire. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+    }
+
+    if (commitEntered)
+    {
+        /* Release the command queue mutex. */
+        gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
+    }
+
+    if (id != 0xFF)
+    {
+        /* Need to unroll the event allocation. */
+        Event->queues[id].head = gcvNULL;
+    }
+
+    if (status == gcvSTATUS_GPU_NOT_RESPONDING)
+    {
+        /* Broadcast GPU stuck. */
+        status = gckOS_Broadcast(Event->os,
+                                 Event->kernel->hardware,
+                                 gcvBROADCAST_GPU_STUCK);
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Commit
+**
+**  Commit an event queue from the user.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gcsQUEUE_PTR Queue
+**          User event queue.
+**
+**      gctBOOL Forced
+**          Force fire a event. There won't be interrupt if there's no events
+            queued. Force a event by append a dummy one if this parameter is on.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Commit(
+    IN gckEVENT Event,
+    IN gcsQUEUE_PTR Queue,
+    IN gctBOOL Forced
+    )
+{
+    gceSTATUS status;
+    gcsQUEUE_PTR record = gcvNULL, next;
+    gctUINT32 processID;
+    gctBOOL needCopy = gcvFALSE;
+    gctPOINTER pointer = gcvNULL;
+
+    gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+    /* Get the current process ID. */
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    /* Query if we need to copy the client data. */
+    gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
+
+    /* Loop while there are records in the queue. */
+    while (Queue != gcvNULL)
+    {
+        gcsQUEUE queue;
+
+        if (needCopy)
+        {
+            /* Point to stack record. */
+            record = &queue;
+
+            /* Copy the data from the client. */
+            gcmkONERROR(gckOS_CopyFromUserData(Event->os,
+                                               record,
+                                               Queue,
+                                               gcmSIZEOF(gcsQUEUE)));
+        }
+        else
+        {
+
+            /* Map record into kernel memory. */
+            gcmkONERROR(gckOS_MapUserPointer(Event->os,
+                                             Queue,
+                                             gcmSIZEOF(gcsQUEUE),
+                                             &pointer));
+
+            record = pointer;
+        }
+
+        /* Append event record to event queue. */
+        gcmkONERROR(
+            gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE));
+
+        /* Next record in the queue. */
+        next = gcmUINT64_TO_PTR(record->next);
+
+        if (!needCopy)
+        {
+            /* Unmap record from kernel memory. */
+            gcmkONERROR(
+                gckOS_UnmapUserPointer(Event->os,
+                                       Queue,
+                                       gcmSIZEOF(gcsQUEUE),
+                                       (gctPOINTER *) record));
+            record = gcvNULL;
+        }
+
+        Queue = next;
+    }
+
+    if (Forced && Event->queueHead == gcvNULL)
+    {
+        gcsHAL_INTERFACE iface;
+        iface.command = gcvHAL_COMMIT_DONE;
+
+        gcmkONERROR(gckEVENT_AddList(Event, &iface, gcvKERNEL_PIXEL, gcvFALSE, gcvTRUE));
+    }
+
+    /* Submit the event list. */
+    gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
+
+    /* Success */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (pointer)
+    {
+        /* Roll back. */
+        gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
+                                             Queue,
+                                             gcmSIZEOF(gcsQUEUE),
+                                             (gctPOINTER*)pointer));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Interrupt
+**
+**  Called by the interrupt service routine to store the triggered interrupt
+**  mask to be later processed by gckEVENT_Notify.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctUINT32 Data
+**          Mask for the 32 interrupts.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Interrupt(
+    IN gckEVENT Event,
+    IN gctUINT32 Data
+    )
+{
+    /* Combine current interrupt status with pending flags. */
+    gckOS_AtomSetMask(Event->pending, Data);
+
+#if gcdINTERRUPT_STATISTIC
+    {
+        gctINT j = 0;
+        gctINT32 oldValue;
+
+        for (j = 0; j < gcmCOUNTOF(Event->queues); j++)
+        {
+            if ((Data & (1 << j)))
+            {
+                gckOS_AtomDecrement(Event->os,
+                                    Event->interruptCount,
+                                    &oldValue);
+            }
+        }
+    }
+#endif
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckEVENT_Notify
+**
+**  Process all triggered interrupts.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_Notify(
+    IN gckEVENT Event,
+    IN gctUINT32 IDs
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctINT i;
+    gcsEVENT_QUEUE * queue;
+    gctUINT mask = 0;
+    gctBOOL acquired = gcvFALSE;
+    gctSIGNAL signal;
+    gctUINT pending = 0;
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+    gctINT eventNumber = 0;
+#endif
+    gckVIDMEM_NODE nodeObject;
+
+    gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+    gcmDEBUG_ONLY(
+        if (IDs != 0)
+        {
+            for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+            {
+                if (Event->queues[i].head != gcvNULL)
+                {
+                    gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                                   "Queue(%d): stamp=%llu source=%d",
+                                   i,
+                                   Event->queues[i].stamp,
+                                   Event->queues[i].source);
+                }
+            }
+        }
+    );
+
+    /* Begin of event handling. */
+    Event->notifyState = 0;
+
+    for (;;)
+    {
+        gcsEVENT_PTR record;
+
+        /* Grab the mutex queue. */
+        gcmkONERROR(gckOS_AcquireMutex(Event->os,
+                                       Event->eventQueueMutex,
+                                       gcvINFINITE));
+        acquired = gcvTRUE;
+
+        gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending);
+
+        if (pending == 0)
+        {
+            /* Release the mutex queue. */
+            gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+            acquired = gcvFALSE;
+
+            /* No more pending interrupts - done. */
+            break;
+        }
+
+        if (pending & 0x80000000)
+        {
+            gcmkPRINT("AXI BUS ERROR");
+            gckHARDWARE_DumpGPUState(Event->kernel->hardware);
+            pending &= 0x7FFFFFFF;
+        }
+
+        if ((pending & 0x40000000) && Event->kernel->hardware->mmuVersion)
+        {
+#if gcdUSE_MMU_EXCEPTION
+#if gcdALLOC_ON_FAULT
+            status = gckHARDWARE_HandleFault(Event->kernel->hardware);
+#endif
+            if (gcmIS_ERROR(status))
+            {
+                /* Dump error is fault can't be handle. */
+                gckHARDWARE_DumpMMUException(Event->kernel->hardware);
+
+                gckHARDWARE_DumpGPUState(Event->kernel->hardware);
+            }
+#endif
+
+            pending &= 0xBFFFFFFF;
+        }
+
+        gcmkTRACE_ZONE_N(
+            gcvLEVEL_INFO, gcvZONE_EVENT,
+            gcmSIZEOF(pending),
+            "Pending interrupts 0x%x",
+            pending
+            );
+
+        queue = gcvNULL;
+
+        gcmDEBUG_ONLY(
+            if (IDs == 0)
+            {
+                for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+                {
+                    if (Event->queues[i].head != gcvNULL)
+                    {
+                        gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                                       "Queue(%d): stamp=%llu source=%d",
+                                       i,
+                                       Event->queues[i].stamp,
+                                       Event->queues[i].source);
+                    }
+                }
+            }
+        );
+
+        /* Find the oldest pending interrupt. */
+        for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+        {
+            if ((Event->queues[i].head != gcvNULL)
+            &&  (pending & (1 << i))
+            )
+            {
+                if ((queue == gcvNULL)
+                ||  (Event->queues[i].stamp < queue->stamp)
+                )
+                {
+                    queue = &Event->queues[i];
+                    mask  = 1 << i;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+                    eventNumber = i;
+#endif
+                }
+            }
+        }
+
+        if (queue == gcvNULL)
+        {
+            gcmkTRACE_ZONE_N(
+                gcvLEVEL_ERROR, gcvZONE_EVENT,
+                gcmSIZEOF(pending),
+                "Interrupts 0x%x are not pending.",
+                pending
+                );
+
+            gckOS_AtomClearMask(Event->pending, pending);
+
+            /* Release the mutex queue. */
+            gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+            acquired = gcvFALSE;
+            break;
+        }
+
+        /* Check whether there is a missed interrupt. */
+        for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+        {
+            if ((Event->queues[i].head != gcvNULL)
+            &&  (Event->queues[i].stamp < queue->stamp)
+            &&  (Event->queues[i].source <= queue->source)
+            )
+            {
+                gcmkTRACE_N(
+                    gcvLEVEL_ERROR,
+                    gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
+                    "Event %d lost (stamp %llu)",
+                    i, Event->queues[i].stamp
+                    );
+
+                /* Use this event instead. */
+                queue = &Event->queues[i];
+                mask  = 0;
+            }
+        }
+
+        if (mask != 0)
+        {
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+            gcmkTRACE_ZONE_N(
+                gcvLEVEL_INFO, gcvZONE_EVENT,
+                gcmSIZEOF(eventNumber),
+                "Processing interrupt %d",
+                eventNumber
+                );
+#endif
+        }
+
+        gckOS_AtomClearMask(Event->pending, mask);
+
+        if (!gckHARDWARE_IsFeatureAvailable(Event->kernel->hardware, gcvFEATURE_FENCE_64BIT))
+        {
+            /* Write out commit stamp.*/
+            *(gctUINT64 *)(Event->kernel->command->fence->logical) = queue->commitStamp;
+        }
+
+        /* Signal clients waiting for fence. */
+        gcmkVERIFY_OK(gckFENCE_Signal(
+            Event->os,
+            Event->kernel->command->fence
+            ));
+
+        /* Grab the event head. */
+        record = queue->head;
+
+        /* Now quickly clear its event list. */
+        queue->head = gcvNULL;
+
+        /* Increase the number of free events. */
+        Event->freeQueueCount++;
+
+        /* Release the mutex queue. */
+        gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+        acquired = gcvFALSE;
+
+        /* Walk all events for this interrupt. */
+        while (record != gcvNULL)
+        {
+            gcsEVENT_PTR recordNext;
+#ifndef __QNXNTO__
+            gctPOINTER logical;
+#endif
+            /* Grab next record. */
+            recordNext = record->next;
+
+#ifdef __QNXNTO__
+            /*
+             * Assign record->processID as the pid for this galcore thread.
+             * Used in the OS calls which do not take a pid.
+             */
+            drv_thread_specific_key_assign(record->processID, 0);
+#endif
+            gcmkTRACE_ZONE_N(
+                gcvLEVEL_INFO, gcvZONE_EVENT,
+                gcmSIZEOF(record->info.command),
+                "Processing event type: %d",
+                record->info.command
+                );
+
+            switch (record->info.command)
+            {
+            case gcvHAL_WRITE_DATA:
+#ifndef __QNXNTO__
+                /* Convert physical into logical address. */
+                gcmkERR_BREAK(
+                    gckOS_MapPhysical(Event->os,
+                                      record->info.u.WriteData.address,
+                                      gcmSIZEOF(gctUINT32),
+                                      &logical));
+
+                /* Write data. */
+                gcmkERR_BREAK(
+                    gckOS_WriteMemory(Event->os,
+                                      logical,
+                                      record->info.u.WriteData.data));
+
+                /* Unmap the physical memory. */
+                gcmkERR_BREAK(
+                    gckOS_UnmapPhysical(Event->os,
+                                        logical,
+                                        gcmSIZEOF(gctUINT32)));
+#else
+                /* Write data. */
+                gcmkERR_BREAK(
+                    gckOS_WriteMemory(Event->os,
+                                      gcmUINT64_TO_PTR(record->info.u.WriteData.address),
+                                      record->info.u.WriteData.data));
+#endif
+                break;
+
+            case gcvHAL_UNLOCK_VIDEO_MEMORY:
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                               "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
+                               record->info.u.UnlockVideoMemory.node);
+
+                nodeObject = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node);
+
+                /* Unlock, sync'ed. */
+                status = gckVIDMEM_NODE_Unlock(
+                    Event->kernel,
+                    nodeObject,
+                    record->processID,
+                    gcvNULL
+                    );
+
+                /* Deref node. */
+                status = gckVIDMEM_NODE_Dereference(Event->kernel, nodeObject);
+                break;
+
+            case gcvHAL_SIGNAL:
+                signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                               "gcvHAL_SIGNAL: 0x%x",
+                               signal);
+
+#ifdef __QNXNTO__
+                if ((record->info.u.Signal.coid == 0)
+                &&  (record->info.u.Signal.rcvid == 0)
+                )
+                {
+                    /* Kernel signal. */
+                    gcmkERR_BREAK(
+                        gckOS_SignalPulse(Event->os,
+                                          signal));
+                }
+                else
+                {
+                    /* User signal. */
+                    gcmkERR_BREAK(
+                        gckOS_UserSignal(Event->os,
+                                         signal,
+                                         record->info.u.Signal.rcvid,
+                                         record->info.u.Signal.coid));
+                }
+#else
+                /* Set signal. */
+                if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL)
+                {
+                    /* Kernel signal. */
+                    gcmkERR_BREAK(
+                        gckOS_Signal(Event->os,
+                                     signal,
+                                     gcvTRUE));
+                }
+                else
+                {
+                    /* User signal. */
+                    gcmkERR_BREAK(
+                        gckOS_UserSignal(Event->os,
+                                         signal,
+                                         gcmUINT64_TO_PTR(record->info.u.Signal.process)));
+                }
+
+                gcmkASSERT(record->info.u.Signal.auxSignal == 0);
+#endif
+                break;
+
+            case gcvHAL_TIMESTAMP:
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                               "gcvHAL_TIMESTAMP: %d %d",
+                               record->info.u.TimeStamp.timer,
+                               record->info.u.TimeStamp.request);
+
+                /* Process the timestamp. */
+                switch (record->info.u.TimeStamp.request)
+                {
+                case 0:
+                    status = gckOS_GetTime(&Event->kernel->timers[
+                                           record->info.u.TimeStamp.timer].
+                                           stopTime);
+                    break;
+
+                case 1:
+                    status = gckOS_GetTime(&Event->kernel->timers[
+                                           record->info.u.TimeStamp.timer].
+                                           startTime);
+                    break;
+
+                default:
+                    gcmkTRACE_ZONE_N(
+                        gcvLEVEL_ERROR, gcvZONE_EVENT,
+                        gcmSIZEOF(record->info.u.TimeStamp.request),
+                        "Invalid timestamp request: %d",
+                        record->info.u.TimeStamp.request
+                        );
+
+                    status = gcvSTATUS_INVALID_ARGUMENT;
+                    break;
+                }
+                break;
+
+            case gcvHAL_COMMIT_DONE:
+                break;
+
+            default:
+                /* Invalid argument. */
+                gcmkTRACE_ZONE_N(
+                    gcvLEVEL_ERROR, gcvZONE_EVENT,
+                    gcmSIZEOF(record->info.command),
+                    "Unknown event type: %d",
+                    record->info.command
+                    );
+
+                status = gcvSTATUS_INVALID_ARGUMENT;
+                break;
+            }
+
+            /* Make sure there are no errors generated. */
+            if (gcmIS_ERROR(status))
+            {
+                gcmkTRACE_ZONE_N(
+                    gcvLEVEL_WARNING, gcvZONE_EVENT,
+                    gcmSIZEOF(status),
+                    "Event produced status: %d(%s)",
+                    status, gckOS_DebugStatus2Name(status));
+            }
+
+            /* Free the event. */
+            gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
+
+            /* Advance to next record. */
+            record = recordNext;
+        }
+
+        gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+                       "Handled interrupt 0x%x", mask);
+    }
+
+    if (IDs == 0)
+    {
+        gcmkONERROR(_TryToIdleGPU(Event));
+    }
+
+    /* End of event handling. */
+    Event->notifyState = -1;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+    }
+
+    /* End of event handling. */
+    Event->notifyState = -1;
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckEVENT_FreeProcess
+**
+**  Free all events owned by a particular process ID.
+**
+**  INPUT:
+**
+**      gckEVENT Event
+**          Pointer to an gckEVENT object.
+**
+**      gctUINT32 ProcessID
+**          Process ID of the process to be freed up.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckEVENT_FreeProcess(
+    IN gckEVENT Event,
+    IN gctUINT32 ProcessID
+    )
+{
+    gctSIZE_T i;
+    gctBOOL acquired = gcvFALSE;
+    gcsEVENT_PTR record, next;
+    gceSTATUS status;
+    gcsEVENT_PTR deleteHead, deleteTail;
+
+    gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+    /* Walk through all queues. */
+    for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+    {
+        if (Event->queues[i].head != gcvNULL)
+        {
+            /* Grab the event queue mutex. */
+            gcmkONERROR(gckOS_AcquireMutex(Event->os,
+                                           Event->eventQueueMutex,
+                                           gcvINFINITE));
+            acquired = gcvTRUE;
+
+            /* Grab the mutex head. */
+            record                = Event->queues[i].head;
+            Event->queues[i].head = gcvNULL;
+            Event->queues[i].tail = gcvNULL;
+            deleteHead            = gcvNULL;
+            deleteTail            = gcvNULL;
+
+            while (record != gcvNULL)
+            {
+                next = record->next;
+                if (record->processID == ProcessID)
+                {
+                    if (deleteHead == gcvNULL)
+                    {
+                        deleteHead = record;
+                    }
+                    else
+                    {
+                        deleteTail->next = record;
+                    }
+
+                    deleteTail = record;
+                }
+                else
+                {
+                    if (Event->queues[i].head == gcvNULL)
+                    {
+                        Event->queues[i].head = record;
+                    }
+                    else
+                    {
+                        Event->queues[i].tail->next = record;
+                    }
+
+                    Event->queues[i].tail = record;
+                }
+
+                record->next = gcvNULL;
+                record = next;
+            }
+
+            /* Release the mutex queue. */
+            gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+            acquired = gcvFALSE;
+
+            /* Loop through the entire list of events. */
+            for (record = deleteHead; record != gcvNULL; record = next)
+            {
+                /* Get the next event record. */
+                next = record->next;
+
+                /* Free the event record. */
+                gcmkONERROR(gckEVENT_FreeRecord(Event, record));
+            }
+        }
+    }
+
+    gcmkONERROR(_TryToIdleGPU(Event));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Release the event queue mutex. */
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+_PrintRecord(
+    gcsEVENT_PTR record
+    )
+{
+    switch (record->info.command)
+    {
+    case gcvHAL_WRITE_DATA:
+        gcmkPRINT("      gcvHAL_WRITE_DATA");
+       break;
+
+    case gcvHAL_UNLOCK_VIDEO_MEMORY:
+        gcmkPRINT("      gcvHAL_UNLOCK_VIDEO_MEMORY");
+        break;
+
+    case gcvHAL_SIGNAL:
+        gcmkPRINT("      gcvHAL_SIGNAL process=%lld signal=0x%llx",
+                  record->info.u.Signal.process,
+                  record->info.u.Signal.signal);
+        break;
+
+    case gcvHAL_TIMESTAMP:
+        gcmkPRINT("      gcvHAL_TIMESTAMP");
+        break;
+
+    case gcvHAL_COMMIT_DONE:
+        gcmkPRINT("      gcvHAL_COMMIT_DONE");
+        break;
+
+    case gcvHAL_DESTROY_MMU:
+        gcmkPRINT("      gcvHAL_DESTORY_MMU mmu=%p",
+                  gcmUINT64_TO_PTR(record->info.u.DestroyMmu.mmu));
+
+        break;
+    default:
+        gcmkPRINT("      Illegal Event %d", record->info.command);
+        break;
+    }
+}
+
+/*******************************************************************************
+** gckEVENT_Dump
+**
+** Dump record in event queue when stuck happens.
+** No protection for the event queue.
+**/
+gceSTATUS
+gckEVENT_Dump(
+    IN gckEVENT Event
+    )
+{
+    gcsEVENT_QUEUE_PTR queueHead = Event->queueHead;
+    gcsEVENT_QUEUE_PTR queue;
+    gcsEVENT_PTR record = gcvNULL;
+    gctINT i;
+#if gcdINTERRUPT_STATISTIC
+    gctINT32 pendingInterrupt;
+    gctUINT32 intrAcknowledge;
+#endif
+    gctINT32 pending;
+
+    gcmkHEADER_ARG("Event=0x%x", Event);
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("***  EVENT STATE DUMP  ***\n");
+    gcmkPRINT("**************************\n");
+
+    gcmkPRINT("  Unsumbitted Event:");
+    while(queueHead)
+    {
+        queue = queueHead;
+        record = queueHead->head;
+
+        gcmkPRINT("    [%p]:", queue);
+        while(record)
+        {
+            _PrintRecord(record);
+            record = record->next;
+        }
+
+        if (queueHead == Event->queueTail)
+        {
+            queueHead = gcvNULL;
+        }
+        else
+        {
+            queueHead = queueHead->next;
+        }
+    }
+
+    gcmkPRINT("  Untriggered Event:");
+    for (i = 0; i < gcmCOUNTOF(Event->queues); i++)
+    {
+        queue = &Event->queues[i];
+        record = queue->head;
+
+        gcmkPRINT("    [%d]:", i);
+        while(record)
+        {
+            _PrintRecord(record);
+            record = record->next;
+        }
+    }
+
+#if gcdINTERRUPT_STATISTIC
+    gckOS_AtomGet(Event->os, Event->interruptCount, &pendingInterrupt);
+    gcmkPRINT("  Number of Pending Interrupt: %d", pendingInterrupt);
+
+    if (Event->kernel->recovery == 0)
+    {
+        gceSTATUS status;
+
+        status = gckOS_ReadRegisterEx(
+                    Event->os,
+                    Event->kernel->core,
+                    0x10,
+                    &intrAcknowledge
+                    );
+        if (gcmIS_ERROR(status))
+        {
+            gcmkPRINT("  READ INTR_ACKNOWLEDGE ERROR!");
+        }
+        else
+        {
+            gcmkPRINT("  INTR_ACKNOWLEDGE=0x%x", intrAcknowledge);
+        }
+    }
+#endif
+
+    gcmkPRINT("  Notify State=%d", Event->notifyState);
+
+    gckOS_AtomGet(Event->os, Event->pending, &pending);
+
+    gcmkPRINT("  Pending=0x%x", pending);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c
@@ -0,0 +1,888 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+/**
+**  @file
+**  gckHEAP object for kernel HAL layer.  The heap implemented here is an arena-
+**  based memory allocation.  An arena-based memory heap allocates data quickly
+**  from specified arenas and reduces memory fragmentation.
+**
+*/
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE            gcvZONE_HEAP
+
+/*******************************************************************************
+***** Structures ***************************************************************
+*******************************************************************************/
+#define gcdIN_USE               ((gcskNODE_PTR)gcvMAXUINTPTR_T)
+
+typedef struct _gcskNODE *      gcskNODE_PTR;
+typedef struct _gcskNODE
+{
+    /* Number of byets in node. */
+    gctSIZE_T                   bytes;
+
+    /* Pointer to next free node, or gcvNULL to mark the node as freed, or
+    ** gcdIN_USE to mark the node as used. */
+    gcskNODE_PTR                next;
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Time stamp of allocation. */
+    gctUINT64                   timeStamp;
+#endif
+}
+gcskNODE;
+
+typedef struct _gcskHEAP    *   gcskHEAP_PTR;
+typedef struct _gcskHEAP
+{
+    /* Linked list. */
+    gcskHEAP_PTR                next;
+    gcskHEAP_PTR                prev;
+
+    /* Heap size. */
+    gctSIZE_T                   size;
+
+    /* Free list. */
+    gcskNODE_PTR                freeList;
+}
+gcskHEAP;
+
+struct _gckHEAP
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to a gckOS object. */
+    gckOS                       os;
+
+    /* Locking mutex. */
+    gctPOINTER                  mutex;
+
+    /* Allocation parameters. */
+    gctSIZE_T                   allocationSize;
+
+    /* Heap list. */
+    gcskHEAP_PTR                heap;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    gctUINT64                   timeStamp;
+#endif
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Profile information. */
+    gctUINT32                   allocCount;
+    gctUINT64                   allocBytes;
+    gctUINT64                   allocBytesMax;
+    gctUINT64                   allocBytesTotal;
+    gctUINT32                   heapCount;
+    gctUINT32                   heapCountMax;
+    gctUINT64                   heapMemory;
+    gctUINT64                   heapMemoryMax;
+#endif
+};
+
+/*******************************************************************************
+***** Static Support Functions *************************************************
+*******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+static gctSIZE_T
+_DumpHeap(
+    IN gcskHEAP_PTR Heap
+    )
+{
+    gctPOINTER p;
+    gctSIZE_T leaked = 0;
+
+    /* Start at first node. */
+    for (p = Heap + 1;;)
+    {
+        /* Convert the pointer. */
+        gcskNODE_PTR node = (gcskNODE_PTR) p;
+
+        /* Check if this is a used node. */
+        if (node->next == gcdIN_USE)
+        {
+            /* Print the leaking node. */
+            gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_HEAP,
+                           "Detected leaking: node=0x%x bytes=%lu timeStamp=%llu "
+                           "(%08X %c%c%c%c)",
+                           node, node->bytes, node->timeStamp,
+                           ((gctUINT32_PTR) (node + 1))[0],
+                           gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[0]),
+                           gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[1]),
+                           gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[2]),
+                           gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[3]));
+
+            /* Add leaking byte count. */
+            leaked += node->bytes;
+        }
+
+        /* Test for end of heap. */
+        if (node->bytes == 0)
+        {
+            break;
+        }
+
+        else
+        {
+            /* Move to next node. */
+            p = (gctUINT8_PTR) node + node->bytes;
+        }
+    }
+
+    /* Return the number of leaked bytes. */
+    return leaked;
+}
+#endif
+
+static gceSTATUS
+_CompactKernelHeap(
+    IN gckHEAP Heap
+    )
+{
+    gcskHEAP_PTR heap, next;
+    gctPOINTER p;
+    gcskHEAP_PTR freeList = gcvNULL;
+
+    gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+    /* Walk all the heaps. */
+    for (heap = Heap->heap; heap != gcvNULL; heap = next)
+    {
+        gcskNODE_PTR lastFree = gcvNULL;
+
+        /* Zero out the free list. */
+        heap->freeList = gcvNULL;
+
+        /* Start at the first node. */
+        for (p = (gctUINT8_PTR) (heap + 1);;)
+        {
+            /* Convert the pointer. */
+            gcskNODE_PTR node = (gcskNODE_PTR) p;
+
+            gcmkASSERT(p <= (gctPOINTER) ((gctUINT8_PTR) (heap + 1) + heap->size));
+
+            /* Test if this node not used. */
+            if (node->next != gcdIN_USE)
+            {
+                /* Test if this is the end of the heap. */
+                if (node->bytes == 0)
+                {
+                    break;
+                }
+
+                /* Test of this is the first free node. */
+                else if (lastFree == gcvNULL)
+                {
+                    /* Initialzie the free list. */
+                    heap->freeList = node;
+                    lastFree       = node;
+                }
+
+                else
+                {
+                    /* Test if this free node is contiguous with the previous
+                    ** free node. */
+                    if ((gctUINT8_PTR) lastFree + lastFree->bytes == p)
+                    {
+                        /* Just increase the size of the previous free node. */
+                        lastFree->bytes += node->bytes;
+                    }
+                    else
+                    {
+                        /* Add to linked list. */
+                        lastFree->next = node;
+                        lastFree       = node;
+                    }
+                }
+            }
+
+            /* Move to next node. */
+            p = (gctUINT8_PTR) node + node->bytes;
+        }
+
+        /* Mark the end of the chain. */
+        if (lastFree != gcvNULL)
+        {
+            lastFree->next = gcvNULL;
+        }
+
+        /* Get next heap. */
+        next = heap->next;
+
+        /* Check if the entire heap is free. */
+        if ((heap->freeList != gcvNULL)
+        &&  (heap->freeList->bytes == heap->size - gcmSIZEOF(gcskNODE))
+        )
+        {
+            /* Remove the heap from the linked list. */
+            if (heap->prev == gcvNULL)
+            {
+                Heap->heap = next;
+            }
+            else
+            {
+                heap->prev->next = next;
+            }
+
+            if (heap->next != gcvNULL)
+            {
+                heap->next->prev = heap->prev;
+            }
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+            /* Update profiling. */
+            Heap->heapCount  -= 1;
+            Heap->heapMemory -= heap->size + gcmSIZEOF(gcskHEAP);
+#endif
+
+            /* Add this heap to the list of heaps that need to be freed. */
+            heap->next = freeList;
+            freeList   = heap;
+        }
+    }
+
+    if (freeList != gcvNULL)
+    {
+        /* Release the mutex, remove any chance for a dead lock. */
+        gcmkVERIFY_OK(
+            gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+        /* Free all heaps in the free list. */
+        for (heap = freeList; heap != gcvNULL; heap = next)
+        {
+            /* Get pointer to the next heap. */
+            next = heap->next;
+
+            /* Free the heap. */
+            gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
+                           "Freeing heap 0x%x (%lu bytes)",
+                           heap, heap->size + gcmSIZEOF(gcskHEAP));
+            gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap));
+        }
+
+        /* Acquire the mutex again. */
+        gcmkVERIFY_OK(
+            gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+***** gckHEAP API Code *********************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckHEAP_Construct
+**
+**  Construct a new gckHEAP object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctSIZE_T AllocationSize
+**          Minimum size per arena.
+**
+**  OUTPUT:
+**
+**      gckHEAP * Heap
+**          Pointer to a variable that will hold the pointer to the gckHEAP
+**          object.
+*/
+gceSTATUS
+gckHEAP_Construct(
+    IN gckOS Os,
+    IN gctSIZE_T AllocationSize,
+    OUT gckHEAP * Heap
+    )
+{
+    gceSTATUS status;
+    gckHEAP heap = gcvNULL;
+    gctPOINTER pointer = gcvNULL;
+
+    gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Heap != gcvNULL);
+
+    /* Allocate the gckHEAP object. */
+    gcmkONERROR(gckOS_AllocateMemory(Os,
+                                     gcmSIZEOF(struct _gckHEAP),
+                                     &pointer));
+
+    heap = pointer;
+
+    /* Initialize the gckHEAP object. */
+    heap->object.type    = gcvOBJ_HEAP;
+    heap->os             = Os;
+    heap->allocationSize = AllocationSize;
+    heap->heap           = gcvNULL;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    heap->timeStamp      = 0;
+#endif
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Zero the counters. */
+    heap->allocCount      = 0;
+    heap->allocBytes      = 0;
+    heap->allocBytesMax   = 0;
+    heap->allocBytesTotal = 0;
+    heap->heapCount       = 0;
+    heap->heapCountMax    = 0;
+    heap->heapMemory      = 0;
+    heap->heapMemoryMax   = 0;
+#endif
+
+    /* Create the mutex. */
+    gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex));
+
+    /* Return the pointer to the gckHEAP object. */
+    *Heap = heap;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Heap=0x%x", *Heap);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (heap != gcvNULL)
+    {
+        /* Free the heap structure. */
+        gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHEAP_Destroy
+**
+**  Destroy a gckHEAP object.
+**
+**  INPUT:
+**
+**      gckHEAP Heap
+**          Pointer to a gckHEAP object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckHEAP_Destroy(
+    IN gckHEAP Heap
+    )
+{
+    gcskHEAP_PTR heap;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    gctSIZE_T leaked = 0;
+#endif
+
+    gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+    for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap)
+    {
+        /* Unlink heap from linked list. */
+        Heap->heap = heap->next;
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+        /* Check for leaked memory. */
+        leaked += _DumpHeap(heap);
+#endif
+
+        /* Free the heap. */
+        gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap));
+    }
+
+    /* Free the mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex));
+
+    /* Free the heap structure. */
+    gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap));
+
+    /* Success. */
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    gcmkFOOTER_ARG("leaked=%lu", leaked);
+#else
+    gcmkFOOTER_NO();
+#endif
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckHEAP_Allocate
+**
+**  Allocate data from the heap.
+**
+**  INPUT:
+**
+**      gckHEAP Heap
+**          Pointer to a gckHEAP object.
+**
+**      IN gctSIZE_T Bytes
+**          Number of byte to allocate.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Memory
+**          Pointer to a variable that will hold the address of the allocated
+**          memory.
+*/
+gceSTATUS
+gckHEAP_Allocate(
+    IN gckHEAP Heap,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    )
+{
+    gctBOOL acquired = gcvFALSE;
+    gcskHEAP_PTR heap;
+    gceSTATUS status;
+    gctSIZE_T bytes;
+    gcskNODE_PTR node, used, prevFree = gcvNULL;
+    gctPOINTER memory = gcvNULL;
+
+    gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    /* Determine number of bytes required for a node. */
+    bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+    acquired = gcvTRUE;
+
+    /* Check if this allocation is bigger than the default allocation size. */
+    if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE))
+    {
+        /* Adjust allocation size. */
+        Heap->allocationSize = bytes * 2;
+    }
+
+    else if (Heap->heap != gcvNULL)
+    {
+        gctINT i;
+
+        /* 2 retries, since we might need to compact. */
+        for (i = 0; i < 2; ++i)
+        {
+            /* Walk all the heaps. */
+            for (heap = Heap->heap; heap != gcvNULL; heap = heap->next)
+            {
+                /* Check if this heap has enough bytes to hold the request. */
+                if (bytes <= heap->size - gcmSIZEOF(gcskNODE))
+                {
+                    prevFree = gcvNULL;
+
+                    /* Walk the chain of free nodes. */
+                    for (node = heap->freeList;
+                         node != gcvNULL;
+                         node = node->next
+                    )
+                    {
+                        gcmkASSERT(node->next != gcdIN_USE);
+
+                        /* Check if this free node has enough bytes. */
+                        if (node->bytes >= bytes)
+                        {
+                            /* Use the node. */
+                            goto UseNode;
+                        }
+
+                        /* Save current free node for linked list management. */
+                        prevFree = node;
+                    }
+                }
+            }
+
+            if (i == 0)
+            {
+                /* Compact the heap. */
+                gcmkVERIFY_OK(_CompactKernelHeap(Heap));
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "===== KERNEL HEAP =====");
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Number of allocations           : %12u",
+                               Heap->allocCount);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Number of bytes allocated       : %12llu",
+                               Heap->allocBytes);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Maximum allocation size         : %12llu",
+                               Heap->allocBytesMax);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Total number of bytes allocated : %12llu",
+                               Heap->allocBytesTotal);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Number of heaps                 : %12u",
+                               Heap->heapCount);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Heap memory in bytes            : %12llu",
+                               Heap->heapMemory);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Maximum number of heaps         : %12u",
+                               Heap->heapCountMax);
+                gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+                               "Maximum heap memory in bytes    : %12llu",
+                               Heap->heapMemoryMax);
+#endif
+            }
+        }
+    }
+
+    /* Release the mutex. */
+    gcmkONERROR(
+        gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+    acquired = gcvFALSE;
+
+    /* Allocate a new heap. */
+    gcmkONERROR(
+        gckOS_AllocateMemory(Heap->os,
+                             Heap->allocationSize,
+                             &memory));
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
+                   "Allocated heap 0x%x (%lu bytes)",
+                   memory, Heap->allocationSize);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+    acquired = gcvTRUE;
+
+    /* Use the allocated memory as the heap. */
+    heap = (gcskHEAP_PTR) memory;
+
+    /* Insert this heap to the head of the chain. */
+    heap->next = Heap->heap;
+    heap->prev = gcvNULL;
+    heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP);
+
+    if (heap->next != gcvNULL)
+    {
+        heap->next->prev = heap;
+    }
+    Heap->heap = heap;
+
+    /* Mark the end of the heap. */
+    node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap
+                          + Heap->allocationSize
+                          - gcmSIZEOF(gcskNODE)
+                          );
+    node->bytes = 0;
+    node->next  = gcvNULL;
+
+    /* Create a free list. */
+    node           = (gcskNODE_PTR) (heap + 1);
+    heap->freeList = node;
+
+    /* Initialize the free list. */
+    node->bytes = heap->size - gcmSIZEOF(gcskNODE);
+    node->next  = gcvNULL;
+
+    /* No previous free. */
+    prevFree = gcvNULL;
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Update profiling. */
+    Heap->heapCount  += 1;
+    Heap->heapMemory += Heap->allocationSize;
+
+    if (Heap->heapCount > Heap->heapCountMax)
+    {
+        Heap->heapCountMax = Heap->heapCount;
+    }
+    if (Heap->heapMemory > Heap->heapMemoryMax)
+    {
+        Heap->heapMemoryMax = Heap->heapMemory;
+    }
+#endif
+
+UseNode:
+    /* Verify some stuff. */
+    gcmkASSERT(heap != gcvNULL);
+    gcmkASSERT(node != gcvNULL);
+    gcmkASSERT(node->bytes >= bytes);
+
+    if (heap->prev != gcvNULL)
+    {
+        /* Unlink the heap from the linked list. */
+        heap->prev->next = heap->next;
+        if (heap->next != gcvNULL)
+        {
+            heap->next->prev = heap->prev;
+        }
+
+        /* Move the heap to the front of the list. */
+        heap->next       = Heap->heap;
+        heap->prev       = gcvNULL;
+        Heap->heap       = heap;
+        heap->next->prev = heap;
+    }
+
+    /* Check if there is enough free space left after usage for another free
+    ** node. */
+    if (node->bytes - bytes >= gcmSIZEOF(gcskNODE))
+    {
+        /* Allocated used space from the back of the free list. */
+        used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes);
+
+        /* Adjust the number of free bytes. */
+        node->bytes -= bytes;
+        gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE));
+    }
+    else
+    {
+        /* Remove this free list from the chain. */
+        if (prevFree == gcvNULL)
+        {
+            heap->freeList = node->next;
+        }
+        else
+        {
+            prevFree->next = node->next;
+        }
+
+        /* Consume the entire free node. */
+        used  = (gcskNODE_PTR) node;
+        bytes = node->bytes;
+    }
+
+    /* Mark node as used. */
+    used->bytes     = bytes;
+    used->next      = gcdIN_USE;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+    used->timeStamp = ++Heap->timeStamp;
+#endif
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Update profile counters. */
+    Heap->allocCount      += 1;
+    Heap->allocBytes      += bytes;
+    Heap->allocBytesMax    = gcmMAX(Heap->allocBytes, Heap->allocBytesMax);
+    Heap->allocBytesTotal += bytes;
+#endif
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(
+        gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+    /* Return pointer to memory. */
+    *Memory = used + 1;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(
+            gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+    }
+
+    if (memory != gcvNULL)
+    {
+        /* Free the heap memory. */
+        gckOS_FreeMemory(Heap->os, memory);
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckHEAP_Free
+**
+**  Free allocated memory from the heap.
+**
+**  INPUT:
+**
+**      gckHEAP Heap
+**          Pointer to a gckHEAP object.
+**
+**      IN gctPOINTER Memory
+**          Pointer to memory to free.
+**
+**  OUTPUT:
+**
+**      NOTHING.
+*/
+gceSTATUS
+gckHEAP_Free(
+    IN gckHEAP Heap,
+    IN gctPOINTER Memory
+    )
+{
+    gcskNODE_PTR node;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(
+        gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+    /* Pointer to structure. */
+    node = (gcskNODE_PTR) Memory - 1;
+
+    /* Mark the node as freed. */
+    node->next = gcvNULL;
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY || gcmIS_DEBUG(gcdDEBUG_CODE)
+    /* Update profile counters. */
+    Heap->allocBytes -= node->bytes;
+#endif
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(
+        gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY
+gceSTATUS
+gckHEAP_ProfileStart(
+    IN gckHEAP Heap
+    )
+{
+    gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+
+    /* Zero the counters. */
+    Heap->allocCount      = 0;
+    Heap->allocBytes      = 0;
+    Heap->allocBytesMax   = 0;
+    Heap->allocBytesTotal = 0;
+    Heap->heapCount       = 0;
+    Heap->heapCountMax    = 0;
+    Heap->heapMemory      = 0;
+    Heap->heapMemoryMax   = 0;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHEAP_ProfileEnd(
+    IN gckHEAP Heap,
+    IN gctCONST_STRING Title
+    )
+{
+    gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+    gcmkVERIFY_ARGUMENT(Title != gcvNULL);
+
+    gcmkPRINT("\n");
+    gcmkPRINT("=====[ HEAP - %s ]=====", Title);
+    gcmkPRINT("Number of allocations           : %12u",   Heap->allocCount);
+    gcmkPRINT("Number of bytes allocated       : %12llu", Heap->allocBytes);
+    gcmkPRINT("Maximum allocation size         : %12llu", Heap->allocBytesMax);
+    gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal);
+    gcmkPRINT("Number of heaps                 : %12u",   Heap->heapCount);
+    gcmkPRINT("Heap memory in bytes            : %12llu", Heap->heapMemory);
+    gcmkPRINT("Maximum number of heaps         : %12u",   Heap->heapCountMax);
+    gcmkPRINT("Maximum heap memory in bytes    : %12llu", Heap->heapMemoryMax);
+    gcmkPRINT("==============================================");
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+#endif /* VIVANTE_PROFILER_SYSTEM_MEMORY */
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c
@@ -0,0 +1,911 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+/******************************************************************************\
+*********************** Support Functions and Definitions **********************
+\******************************************************************************/
+
+/* Interruot statistics will be accumulated if not zero. */
+#define gcmENABLE_INTERRUPT_STATISTICS 0
+
+#define _GC_OBJ_ZONE    gcvZONE_INTERRUPT
+
+/* Object structure. */
+struct _gckVGINTERRUPT
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* gckVGKERNEL pointer. */
+    gckVGKERNEL                 kernel;
+
+    /* gckOS pointer. */
+    gckOS                       os;
+
+    /* Interrupt handlers. */
+    gctINTERRUPT_HANDLER        handlers[32];
+
+    /* Main interrupt handler thread. */
+    gctTHREAD                   handler;
+    gctBOOL                     terminate;
+
+    /* Interrupt FIFO. */
+    gctSEMAPHORE                fifoValid;
+    gctUINT32                   fifo[256];
+    gctUINT                     fifoItems;
+    gctUINT8                    head;
+    gctUINT8                    tail;
+
+    /* Interrupt statistics. */
+#if gcmENABLE_INTERRUPT_STATISTICS
+    gctUINT                     maxFifoItems;
+    gctUINT                     fifoOverflow;
+    gctUINT                     maxSimultaneous;
+    gctUINT                     multipleCount;
+#endif
+};
+
+
+/*******************************************************************************
+**
+**  _ProcessInterrupt
+**
+**  The interrupt processor.
+**
+**  INPUT:
+**
+**      ThreadParameter
+**          Pointer to the gckVGINTERRUPT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+static void
+_ProcessInterrupt(
+    gckVGINTERRUPT Interrupt,
+    gctUINT_PTR TriggeredCount
+    )
+#else
+static void
+_ProcessInterrupt(
+    gckVGINTERRUPT Interrupt
+    )
+#endif
+{
+    gceSTATUS status;
+    gctUINT32 triggered;
+    gctUINT i;
+
+    /* Advance to the next entry. */
+    Interrupt->tail      += 1;
+    Interrupt->fifoItems -= 1;
+
+    /* Get the interrupt value. */
+    triggered = Interrupt->fifo[Interrupt->tail];
+    gcmkASSERT(triggered != 0);
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s: triggered=0x%08X\n",
+        __FUNCTION__,
+        triggered
+        );
+
+    /* Walk through all possible interrupts. */
+    for (i = 0; i < gcmSIZEOF(Interrupt->handlers); i += 1)
+    {
+        /* Test if interrupt happened. */
+        if ((triggered & 1) == 1)
+        {
+#if gcmENABLE_INTERRUPT_STATISTICS
+            if (TriggeredCount != gcvNULL)
+            {
+                (* TriggeredCount) += 1;
+            }
+#endif
+
+            /* Make sure we have valid handler. */
+            if (Interrupt->handlers[i] == gcvNULL)
+            {
+                gcmkTRACE(
+                    gcvLEVEL_ERROR,
+                    "%s: Interrupt %d isn't registered.\n",
+                    __FUNCTION__, i
+                    );
+            }
+            else
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                    "%s: interrupt=%d\n",
+                    __FUNCTION__,
+                    i
+                    );
+
+                /* Call the handler. */
+                status = Interrupt->handlers[i] (Interrupt->kernel);
+
+                if (gcmkIS_ERROR(status))
+                {
+                    /* Failed to signal the semaphore. */
+                    gcmkTRACE(
+                        gcvLEVEL_ERROR,
+                        "%s: Error %d incrementing the semaphore #%d.\n",
+                        __FUNCTION__, status, i
+                        );
+                }
+            }
+        }
+
+        /* Next interrupt. */
+        triggered >>= 1;
+
+        /* No more interrupts to handle? */
+        if (triggered == 0)
+        {
+            break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+**  _MainInterruptHandler
+**
+**  The main interrupt thread serves the interrupt FIFO and calls registered
+**  handlers for the interrupts that occured. The handlers are called in the
+**  sequence interrupts occured with the exception when multiple interrupts
+**  occured at the same time. In that case the handler calls are "sorted" by
+**  the interrupt number therefore giving the interrupts with lower numbers
+**  higher priority.
+**
+**  INPUT:
+**
+**      ThreadParameter
+**          Pointer to the gckVGINTERRUPT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+static gctTHREADFUNCRESULT gctTHREADFUNCTYPE
+_MainInterruptHandler(
+    gctTHREADFUNCPARAMETER ThreadParameter
+    )
+{
+    gceSTATUS status;
+    gckVGINTERRUPT interrupt;
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+    gctUINT count;
+#endif
+
+    /* Cast the object. */
+    interrupt = (gckVGINTERRUPT) ThreadParameter;
+
+    /* Enter the loop. */
+    while (gcvTRUE)
+    {
+        /* Wait for an interrupt. */
+        status = gckOS_DecrementSemaphore(interrupt->os, interrupt->fifoValid);
+
+        /* Error? */
+        if (gcmkIS_ERROR(status))
+        {
+            break;
+        }
+
+        /* System termination request? */
+        if (status == gcvSTATUS_TERMINATE)
+        {
+            break;
+        }
+
+        /* Driver is shutting down? */
+        if (interrupt->terminate)
+        {
+            break;
+        }
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+        /* Reset triggered count. */
+        count = 0;
+
+        /* Process the interrupt. */
+        _ProcessInterrupt(interrupt, &count);
+
+        /* Update conters. */
+        if (count > interrupt->maxSimultaneous)
+        {
+            interrupt->maxSimultaneous = count;
+        }
+
+        if (count > 1)
+        {
+            interrupt->multipleCount += 1;
+        }
+#else
+        /* Process the interrupt. */
+        _ProcessInterrupt(interrupt);
+#endif
+    }
+
+    return 0;
+}
+
+
+/*******************************************************************************
+**
+**  _StartInterruptHandler / _StopInterruptHandler
+**
+**  Main interrupt handler routine control.
+**
+**  INPUT:
+**
+**      ThreadParameter
+**          Pointer to the gckVGINTERRUPT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+static gceSTATUS
+_StartInterruptHandler(
+    gckVGINTERRUPT Interrupt
+    )
+{
+    gceSTATUS status, last;
+
+    do
+    {
+        /* Objects must not be already created. */
+        gcmkASSERT(Interrupt->fifoValid == gcvNULL);
+        gcmkASSERT(Interrupt->handler   == gcvNULL);
+
+        /* Reset the termination request. */
+        Interrupt->terminate = gcvFALSE;
+
+#if !gcdENABLE_INFINITE_SPEED_HW
+        /* Construct the fifo semaphore. */
+        gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
+            Interrupt->os, &Interrupt->fifoValid
+            ));
+
+        /* Start the interrupt handler thread. */
+        gcmkERR_BREAK(gckOS_StartThread(
+            Interrupt->os,
+            _MainInterruptHandler,
+            Interrupt,
+            &Interrupt->handler
+            ));
+#endif
+
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (Interrupt->fifoValid != gcvNULL)
+    {
+        gcmkCHECK_STATUS(gckOS_DestroySemaphore(
+            Interrupt->os, Interrupt->fifoValid
+            ));
+
+        Interrupt->fifoValid = gcvNULL;
+    }
+
+    /* Return the status. */
+    return status;
+}
+
+static gceSTATUS
+_StopInterruptHandler(
+    gckVGINTERRUPT Interrupt
+    )
+{
+    gceSTATUS status;
+
+    do
+    {
+        /* Does the thread exist? */
+        if (Interrupt->handler == gcvNULL)
+        {
+            /* The semaphore must be NULL as well. */
+            gcmkASSERT(Interrupt->fifoValid == gcvNULL);
+
+            /* Success. */
+            status = gcvSTATUS_OK;
+            break;
+        }
+
+        /* The semaphore must exist as well. */
+        gcmkASSERT(Interrupt->fifoValid != gcvNULL);
+
+        /* Set the termination request. */
+        Interrupt->terminate = gcvTRUE;
+
+        /* Unlock the thread. */
+        gcmkERR_BREAK(gckOS_IncrementSemaphore(
+            Interrupt->os, Interrupt->fifoValid
+            ));
+
+        /* Wait until the thread quits. */
+        gcmkERR_BREAK(gckOS_StopThread(
+            Interrupt->os,
+            Interrupt->handler
+            ));
+
+        /* Destroy the semaphore. */
+        gcmkERR_BREAK(gckOS_DestroySemaphore(
+            Interrupt->os, Interrupt->fifoValid
+            ));
+
+        /* Reset handles. */
+        Interrupt->handler   = gcvNULL;
+        Interrupt->fifoValid = gcvNULL;
+    }
+    while (gcvFALSE);
+
+    /* Return the status. */
+    return status;
+}
+
+
+/******************************************************************************\
+***************************** Interrupt Object API *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_Construct
+**
+**  Construct an interrupt object.
+**
+**  INPUT:
+**
+**      Kernel
+**          Pointer to the gckVGKERNEL object.
+**
+**  OUTPUT:
+**
+**      Interrupt
+**          Pointer to the new gckVGINTERRUPT object.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Construct(
+    IN gckVGKERNEL Kernel,
+    OUT gckVGINTERRUPT * Interrupt
+    )
+{
+    gceSTATUS status;
+    gckVGINTERRUPT interrupt = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=0x%x Interrupt=0x%x", Kernel, Interrupt);
+
+    /* Verify argeuments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Interrupt != gcvNULL);
+
+    do
+    {
+        /* Allocate the gckVGINTERRUPT structure. */
+        gcmkERR_BREAK(gckOS_Allocate(
+            Kernel->os,
+            gcmSIZEOF(struct _gckVGINTERRUPT),
+            (gctPOINTER *) &interrupt
+            ));
+
+        /* Reset the object data. */
+        gcmkVERIFY_OK(gckOS_ZeroMemory(
+            interrupt, gcmSIZEOF(struct _gckVGINTERRUPT)
+            ));
+
+        /* Initialize the object. */
+        interrupt->object.type = gcvOBJ_INTERRUPT;
+
+        /* Initialize the object pointers. */
+        interrupt->kernel = Kernel;
+        interrupt->os     = Kernel->os;
+
+        /* Initialize the current FIFO position. */
+        interrupt->head = (gctUINT8)~0;
+        interrupt->tail = (gctUINT8)~0;
+
+        /* Start the thread. */
+        gcmkERR_BREAK(_StartInterruptHandler(interrupt));
+
+        /* Return interrupt object. */
+        *Interrupt = interrupt;
+
+        gcmkFOOTER_ARG("*Interrup=0x%x", *Interrupt);
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (interrupt != gcvNULL)
+    {
+        /* Free the gckVGINTERRUPT structure. */
+        gcmkVERIFY_OK(gckOS_Free(interrupt->os, interrupt));
+    }
+
+    gcmkFOOTER();
+
+    /* Return the status. */
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_Destroy
+**
+**  Destroy an interrupt object.
+**
+**  INPUT:
+**
+**      Interrupt
+**          Pointer to the gckVGINTERRUPT object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Destroy(
+    IN gckVGINTERRUPT Interrupt
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+    do
+    {
+        /* Stop the interrupt thread. */
+        gcmkERR_BREAK(_StopInterruptHandler(Interrupt));
+
+        /* Mark the object as unknown. */
+        Interrupt->object.type = gcvOBJ_UNKNOWN;
+
+        /* Free the gckVGINTERRUPT structure. */
+        gcmkERR_BREAK(gckOS_Free(Interrupt->os, Interrupt));
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+
+    /* Return the status. */
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_DumpState
+**
+**  Print the current state of the interrupt manager.
+**
+**  INPUT:
+**
+**      Interrupt
+**          Pointer to a gckVGINTERRUPT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+#if gcvDEBUG
+gceSTATUS
+gckVGINTERRUPT_DumpState(
+    IN gckVGINTERRUPT Interrupt
+    )
+{
+    gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+    /* Print the header. */
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "%s: INTERRUPT OBJECT STATUS\n",
+        __FUNCTION__
+        );
+
+    /* Print statistics. */
+#if gcmENABLE_INTERRUPT_STATISTICS
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "  Maximum number of FIFO items accumulated at a single time: %d\n",
+        Interrupt->maxFifoItems
+        );
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "  Interrupt FIFO overflow happened times: %d\n",
+        Interrupt->fifoOverflow
+        );
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "  Maximum number of interrupts simultaneously generated: %d\n",
+        Interrupt->maxSimultaneous
+        );
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "  Number of times when there were multiple interrupts generated: %d\n",
+        Interrupt->multipleCount
+        );
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+        "  The current number of entries in the FIFO: %d\n",
+        Interrupt->fifoItems
+        );
+
+    /* Print the FIFO contents. */
+    if (Interrupt->fifoItems != 0)
+    {
+        gctUINT8 index;
+        gctUINT8 last;
+
+        gcmkTRACE_ZONE(
+            gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+            "  FIFO current contents:\n"
+            );
+
+        /* Get the current pointers. */
+        index = Interrupt->tail;
+        last  = Interrupt->head;
+
+        while (index != last)
+        {
+            /* Advance to the next entry. */
+            index += 1;
+
+            gcmkTRACE_ZONE(
+                gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+                "    %d: 0x%08X\n",
+                index, Interrupt->fifo[index]
+                );
+        }
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+#endif
+
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_Enable
+**
+**  Enable the specified interrupt.
+**
+**  INPUT:
+**
+**      Interrupt
+**          Pointer to a gckVGINTERRUPT object.
+**
+**      Id
+**          Pointer to the variable that holds the interrupt number to be
+**          registered in range 0..31.
+**          If the value is less then 0, gckVGINTERRUPT_Enable will attempt
+**          to find an unused interrupt. If such interrupt is found, the number
+**          will be assigned to the variable if the functuion call succeedes.
+**
+**      Handler
+**          Pointer to the handler to register for the interrupt.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Enable(
+    IN gckVGINTERRUPT Interrupt,
+    IN OUT gctINT32_PTR Id,
+    IN gctINTERRUPT_HANDLER Handler
+    )
+{
+    gceSTATUS status;
+    gctINT32 i;
+
+    gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x Handler=0x%x", Interrupt, Id, Handler);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+    gcmkVERIFY_ARGUMENT(Id != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Handler != gcvNULL);
+
+    do
+    {
+        /* See if we need to allocate an ID. */
+        if (*Id < 0)
+        {
+            /* Find the first unused interrupt handler. */
+            for (i = 0; i < gcmCOUNTOF(Interrupt->handlers); ++i)
+            {
+                if (Interrupt->handlers[i] == gcvNULL)
+                {
+                    break;
+                }
+            }
+
+            /* No unused innterrupts? */
+            if (i == gcmCOUNTOF(Interrupt->handlers))
+            {
+                status = gcvSTATUS_OUT_OF_RESOURCES;
+                break;
+            }
+
+            /* Update the interrupt ID. */
+            *Id = i;
+        }
+
+        /* Make sure the ID is in range. */
+        else if (*Id >= gcmCOUNTOF(Interrupt->handlers))
+        {
+            status = gcvSTATUS_INVALID_ARGUMENT;
+            break;
+        }
+
+        /* Set interrupt handler. */
+        Interrupt->handlers[*Id] = Handler;
+
+        /* Success. */
+        status = gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_Disable
+**
+**  Disable the specified interrupt.
+**
+**  INPUT:
+**
+**      Interrupt
+**          Pointer to a gckVGINTERRUPT object.
+**
+**      Id
+**          Interrupt number to be disabled in range 0..31.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Disable(
+    IN gckVGINTERRUPT Interrupt,
+    IN gctINT32 Id
+    )
+{
+    gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x", Interrupt, Id);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+    gcmkVERIFY_ARGUMENT((Id >= 0) && (Id < gcmCOUNTOF(Interrupt->handlers)));
+
+    /* Reset interrupt handler. */
+    Interrupt->handlers[Id] = gcvNULL;
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+**  gckVGINTERRUPT_Enque
+**
+**  Read the interrupt status register and put the value in the interrupt FIFO.
+**
+**  INPUT:
+**
+**      Interrupt
+**          Pointer to a gckVGINTERRUPT object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+#ifndef __QNXNTO__
+gceSTATUS
+gckVGINTERRUPT_Enque(
+    IN gckVGINTERRUPT Interrupt
+    )
+#else
+gceSTATUS
+gckVGINTERRUPT_Enque(
+    IN gckVGINTERRUPT Interrupt,
+    OUT gckOS *Os,
+    OUT gctSEMAPHORE *Semaphore
+    )
+#endif
+{
+    gceSTATUS status;
+    gctUINT32 triggered;
+
+    gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+#ifdef __QNXNTO__
+    *Os = gcvNULL;
+    *Semaphore = gcvNULL;
+#endif
+
+    do
+    {
+        /* Read interrupt status register. */
+        gcmkERR_BREAK(gckVGHARDWARE_ReadInterrupt(
+            Interrupt->kernel->hardware, &triggered
+            ));
+
+        /* Mask out TS overflow interrupt */
+        triggered &= 0xfffffffe;
+
+        /* No interrupts to process? */
+        if (triggered == 0)
+        {
+            status = gcvSTATUS_NOT_OUR_INTERRUPT;
+            break;
+        }
+
+        /* FIFO overflow? */
+        if (Interrupt->fifoItems == gcmCOUNTOF(Interrupt->fifo))
+        {
+#if gcmENABLE_INTERRUPT_STATISTICS
+            Interrupt->fifoOverflow += 1;
+#endif
+
+            /* OR the interrupt with the last value in the FIFO. */
+            Interrupt->fifo[Interrupt->head] |= triggered;
+
+            /* Success (kind of). */
+            status = gcvSTATUS_OK;
+        }
+        else
+        {
+            /* Advance to the next entry. */
+            Interrupt->head      += 1;
+            Interrupt->fifoItems += 1;
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+            if (Interrupt->fifoItems > Interrupt->maxFifoItems)
+            {
+                Interrupt->maxFifoItems = Interrupt->fifoItems;
+            }
+#endif
+
+            /* Set the new value. */
+            Interrupt->fifo[Interrupt->head] = triggered;
+
+#ifndef __QNXNTO__
+            /* Increment the FIFO semaphore. */
+            gcmkERR_BREAK(gckOS_IncrementSemaphore(
+                Interrupt->os, Interrupt->fifoValid
+                ));
+#else
+            *Os = Interrupt->os;
+            *Semaphore = Interrupt->fifoValid;
+#endif
+
+            /* Windows kills our threads prematurely when the application
+               exists. Verify here that the thread is still alive. */
+            status = gckOS_VerifyThread(Interrupt->os, Interrupt->handler);
+
+            /* Has the thread been prematurely terminated? */
+            if (status != gcvSTATUS_OK)
+            {
+                /* Process all accumulated interrupts. */
+                while (Interrupt->head != Interrupt->tail)
+                {
+#if gcmENABLE_INTERRUPT_STATISTICS
+                    /* Process the interrupt. */
+                    _ProcessInterrupt(Interrupt, gcvNULL);
+#else
+                    /* Process the interrupt. */
+                    _ProcessInterrupt(Interrupt);
+#endif
+                }
+
+                /* Set success. */
+                status = gcvSTATUS_OK;
+            }
+        }
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+#endif /* gcdENABLE_VG */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
@@ -0,0 +1,3411 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_MMU
+
+typedef enum _gceMMU_TYPE
+{
+    gcvMMU_USED     = (0 << 4),
+    gcvMMU_SINGLE   = (1 << 4),
+    gcvMMU_FREE     = (2 << 4),
+}
+gceMMU_TYPE;
+
+/* VIP SRAM start virtual address. */
+#define gcdRESERVE_START (4 << 10)
+#define gcdRESERVE_ALIGN (4 << 10)
+
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+
+#define gcmENTRY_COUNT(x) ((x & 0xFFFFFF00) >> 8)
+
+#define gcdMMU_TABLE_DUMP       0
+
+#define gcdVERTEX_START      (128 << 10)
+
+typedef struct _gcsMMU_STLB_CHUNK *gcsMMU_STLB_CHUNK_PTR;
+
+typedef struct _gcsMMU_STLB_CHUNK
+{
+    gckVIDMEM_NODE  videoMem;
+    gctUINT32_PTR   logical;
+    gctSIZE_T       size;
+    gctPHYS_ADDR_T  physBase;
+    gctSIZE_T       pageCount;
+    gctUINT32       mtlbIndex;
+    gctUINT32       mtlbEntryNum;
+    gcsMMU_STLB_CHUNK_PTR next;
+} gcsMMU_STLB_CHUNK;
+
+#if gcdSHARED_PAGETABLE
+typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR;
+typedef struct _gcsSharedPageTable
+{
+    /* Shared gckMMU object. */
+    gckMMU          mmu;
+
+    /* Hardwares which use this shared pagetable. */
+    gckHARDWARE     hardwares[gcdMAX_GPU_COUNT];
+
+    /* Number of cores use this shared pagetable. */
+    gctUINT32       reference;
+}
+gcsSharedPageTable;
+
+static gcsSharedPageTable_PTR sharedPageTable = gcvNULL;
+#endif
+
+typedef struct _gcsFreeSpaceNode * gcsFreeSpaceNode_PTR;
+typedef struct _gcsFreeSpaceNode
+{
+    gctUINT32       start;
+    gctINT32        entries;
+}
+gcsFreeSpaceNode;
+
+#if gcdENDIAN_BIG
+
+#  define _WritePageEntry(pageEntry, entryValue) \
+    *(gctUINT32_PTR)(pageEntry) = gcmBSWAP32((gctUINT32)(entryValue))
+
+#  define _ReadPageEntry(pageEntry) \
+    gcmBSWAP32(*(gctUINT32_PTR)(pageEntry))
+
+#else
+
+#  define _WritePageEntry(pageEntry, entryValue) \
+    *(gctUINT32_PTR)(pageEntry) = (gctUINT32)(entryValue)
+
+#  define _ReadPageEntry(pageEntry) \
+    *(gctUINT32_PTR)(pageEntry)
+
+#endif
+
+static gceSTATUS
+_FillPageTable(
+    IN gctUINT32_PTR PageTable,
+    IN gctUINT32     PageCount,
+    IN gctUINT32     EntryValue
+)
+{
+    gctUINT i;
+
+    for (i = 0; i < PageCount; i++)
+    {
+        _WritePageEntry(PageTable + i, EntryValue);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FillMap(
+    IN gctUINT32_PTR Map,
+    IN gctUINT32     PageCount,
+    IN gctUINT32     EntryValue
+)
+{
+    gctUINT i;
+
+    for (i = 0; i < PageCount; i++)
+    {
+        Map[i] = EntryValue;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_Link(
+    IN gcsADDRESS_AREA_PTR Area,
+    IN gctUINT32 Index,
+    IN gctUINT32 Next
+    )
+{
+    if (Index >= Area->stlbEntries)
+    {
+        /* Just move heap pointer. */
+        Area->heapList = Next;
+    }
+    else
+    {
+        /* Address page table. */
+        gctUINT32_PTR map = Area->mapLogical;
+
+        /* Dispatch on node type. */
+        switch (gcmENTRY_TYPE(map[Index]))
+        {
+        case gcvMMU_SINGLE:
+            /* Set single index. */
+            map[Index] = (Next << 8) | gcvMMU_SINGLE;
+            break;
+
+        case gcvMMU_FREE:
+            /* Set index. */
+            map[Index + 1] = Next;
+            break;
+
+        default:
+            gcmkFATAL("MMU table correcupted at index %u!", Index);
+            return gcvSTATUS_HEAP_CORRUPTED;
+        }
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_AddFree(
+    IN gcsADDRESS_AREA_PTR Area,
+    IN gctUINT32 Index,
+    IN gctUINT32 Node,
+    IN gctUINT32 Count
+    )
+{
+    gctUINT32_PTR map = Area->mapLogical;
+
+    if (Count == 1)
+    {
+        /* Initialize a single page node. */
+        map[Node] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
+    }
+    else
+    {
+        /* Initialize the node. */
+        map[Node + 0] = (Count << 8) | gcvMMU_FREE;
+        map[Node + 1] = ~0U;
+    }
+
+    /* Append the node. */
+    return _Link(Area, Index, Node);
+}
+
+static gceSTATUS
+_Collect(
+    IN gcsADDRESS_AREA_PTR Area
+    )
+{
+    gctUINT32_PTR map = Area->mapLogical;
+    gceSTATUS status;
+    gctUINT32 i, previous, start = 0, count = 0;
+
+    previous = Area->heapList = ~0U;
+    Area->freeNodes = gcvFALSE;
+
+    /* Walk the entire page table. */
+    for (i = 0; i < Area->stlbEntries; ++i)
+    {
+        /* Dispatch based on type of page. */
+        switch (gcmENTRY_TYPE(map[i]))
+        {
+        case gcvMMU_USED:
+            /* Used page, so close any open node. */
+            if (count > 0)
+            {
+                /* Add the node. */
+                gcmkONERROR(_AddFree(Area, previous, start, count));
+
+                /* Reset the node. */
+                previous = start;
+                count    = 0;
+            }
+            break;
+
+        case gcvMMU_SINGLE:
+            /* Single free node. */
+            if (count++ == 0)
+            {
+                /* Start a new node. */
+                start = i;
+            }
+            break;
+
+        case gcvMMU_FREE:
+            /* A free node. */
+            if (count == 0)
+            {
+                /* Start a new node. */
+                start = i;
+            }
+
+            /* Advance the count. */
+            count += map[i] >> 8;
+
+            /* Advance the index into the page table. */
+            i     += (map[i] >> 8) - 1;
+            break;
+
+        default:
+            gcmkFATAL("MMU page table correcupted at index %u!", i);
+            return gcvSTATUS_HEAP_CORRUPTED;
+        }
+    }
+
+    /* See if we have an open node left. */
+    if (count > 0)
+    {
+        /* Add the node to the list. */
+        gcmkONERROR(_AddFree(Area, previous, start, count));
+    }
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
+                   "Performed a garbage collection of the MMU heap.");
+
+    /* Success. */
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the staus. */
+    return status;
+}
+
+static gctUINT32
+_SetPage(gctUINT32 PageAddress, gctUINT32 PageAddressExt, gctBOOL Writable)
+{
+    gctUINT32 entry = PageAddress
+                    /* AddressExt */
+                    | (PageAddressExt << 4)
+                    /* Ignore exception */
+                    | (0 << 1)
+                    /* Present */
+                    | (1 << 0);
+
+    if (Writable)
+    {
+        /* writable */
+        entry |= (1 << 2);
+    }
+#if gcdUSE_MMU_EXCEPTION
+    else
+    {
+        /* If this page is read only, set exception bit to make exception happens
+        ** when writing to it. */
+        entry |= gcdMMU_STLB_EXCEPTION;
+    }
+#endif
+
+    return entry;
+}
+
+static gctUINT32
+_MtlbOffset(
+    gctUINT32 Address
+    )
+{
+    return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+}
+
+gctUINT32
+_AddressToIndex(
+    IN gcsADDRESS_AREA_PTR Area,
+    IN gctUINT32 Address
+    )
+{
+
+    gctUINT32 stlbShift = (Area->areaType == gcvAREA_TYPE_1M) ? gcdMMU_STLB_1M_SHIFT : gcdMMU_STLB_4K_SHIFT;
+    gctUINT32 stlbMask  = (Area->areaType == gcvAREA_TYPE_1M) ? gcdMMU_STLB_1M_MASK : gcdMMU_STLB_4K_MASK;
+    gctUINT32 stlbEntryNum = (Area->areaType == gcvAREA_TYPE_1M) ? gcdMMU_STLB_1M_ENTRY_NUM : gcdMMU_STLB_4K_ENTRY_NUM;
+    gctUINT32 mtlbOffset = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+    gctUINT32 stlbOffset = (Address & stlbMask) >> stlbShift;
+
+    return (mtlbOffset - Area->mappingStart) * stlbEntryNum + stlbOffset;
+}
+
+static gctUINT32_PTR
+_StlbEntry(
+    gcsADDRESS_AREA_PTR Area,
+    gctUINT32 Address
+    )
+{
+    gctUINT32 index = _AddressToIndex(Area, Address);
+
+    return &Area->stlbLogical[index];
+}
+
+static gctBOOL
+_IsRangeInsected(
+    gctUINT64 baseAddress1,
+    gctSIZE_T size1,
+    gctUINT64 baseAddress2,
+    gctSIZE_T size2
+    )
+{
+    gctUINT64 endAddress1 = baseAddress1 + size1 - 1;
+    gctUINT64 endAddress2 = baseAddress2 + size2 - 1;
+
+    if (!size1 || !size2)
+    {
+        return gcvFALSE;
+    }
+
+    return (((baseAddress2 <= endAddress1) && (endAddress2 >= baseAddress1)) ||
+            ((baseAddress1 <= endAddress2) && (endAddress1 >= baseAddress2)));
+}
+
+static gceSTATUS
+_FillFlatMappingInMap(
+    gcsADDRESS_AREA_PTR Area,
+    gctUINT32 Index,
+    gctUINT32 NumPages
+    )
+{
+    gceSTATUS status;
+    gctUINT32 i;
+    gctBOOL gotIt = gcvFALSE;
+    gctUINT32 index = Index;
+    gctUINT32_PTR map = Area->mapLogical;
+    gctUINT32 previous = ~0U;
+
+    /* Find node which contains index. */
+    for (i = 0; !gotIt && (i < Area->stlbEntries);)
+    {
+        gctUINT32 numPages;
+
+        switch (gcmENTRY_TYPE(map[i]))
+        {
+        case gcvMMU_SINGLE:
+            if (i == index)
+            {
+                gotIt = gcvTRUE;
+            }
+            else
+            {
+                previous = i;
+                i = map[i] >> 8;
+            }
+            break;
+
+        case gcvMMU_FREE:
+            numPages = map[i] >> 8;
+            if (index >= i && index + NumPages - 1 < i + numPages)
+            {
+                gotIt = gcvTRUE;
+            }
+            else
+            {
+                previous = i;
+                i = map[i + 1];
+            }
+            break;
+
+        case gcvMMU_USED:
+            i++;
+            break;
+
+        default:
+            gcmkFATAL("MMU table correcupted at index %u!", index);
+            gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+    }
+
+    switch (gcmENTRY_TYPE(map[i]))
+    {
+    case gcvMMU_SINGLE:
+        /* Unlink single node from free list. */
+        gcmkONERROR(
+            _Link(Area, previous, map[i] >> 8));
+        break;
+
+    case gcvMMU_FREE:
+        /* Split the node. */
+        {
+            gctUINT32 start;
+            gctUINT32 next = map[i+1];
+            gctUINT32 total = map[i] >> 8;
+            gctUINT32 countLeft = index - i;
+            gctUINT32 countRight = total - countLeft - NumPages;
+
+            if (countLeft)
+            {
+                start = i;
+                _AddFree(Area, previous, start, countLeft);
+                previous = start;
+            }
+
+            if (countRight)
+            {
+                start = index + NumPages;
+                _AddFree(Area, previous, start, countRight);
+                previous = start;
+            }
+
+            _Link(Area, previous, next);
+        }
+        break;
+    }
+
+    _FillMap(&map[index], NumPages, gcvMMU_USED);
+
+    return gcvSTATUS_OK;
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_CollectFreeSpace(
+    IN gckMMU Mmu,
+    OUT gcsFreeSpaceNode_PTR *Array,
+    OUT gctINT * Size
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPOINTER pointer = gcvNULL;
+    gcsFreeSpaceNode_PTR array = gcvNULL;
+    gcsFreeSpaceNode_PTR node = gcvNULL;
+    gctINT size = 0;
+    gctINT i = 0;
+
+    for (i = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+    {
+        if (!Mmu->mtlbLogical[i])
+        {
+            if (!node)
+            {
+                /* This is the first entry of the free space. */
+                node += 1;
+                size++;
+
+            }
+        }
+        else if (node)
+        {
+            /* Reset the start. */
+            node = gcvNULL;
+        }
+    }
+
+    /* Allocate memory for the array. */
+    gcmkONERROR(gckOS_Allocate(Mmu->os,
+                               gcmSIZEOF(*array) * size,
+                               &pointer));
+
+    array = (gcsFreeSpaceNode_PTR)pointer;
+    node  = gcvNULL;
+
+    for (i = 0, size = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+    {
+        if (!Mmu->mtlbLogical[i])
+        {
+            if (!node)
+            {
+                /* This is the first entry of the free space. */
+                node = &array[size++];
+
+                node->start   = i;
+                node->entries = 0;
+            }
+
+            node->entries++;
+        }
+        else if (node)
+        {
+            /* Reset the start. */
+            node = gcvNULL;
+        }
+    }
+
+#if gcdMMU_TABLE_DUMP
+    for (i = 0; i < size; i++)
+    {
+        gckOS_Print("%s(%d): [%d]: start=%d, entries=%d.\n",
+                __FUNCTION__, __LINE__,
+                i,
+                array[i].start,
+                array[i].entries);
+    }
+#endif
+
+    *Array = array;
+    *Size  = size;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (pointer != gcvNULL)
+    {
+        gckOS_Free(Mmu->os, pointer);
+    }
+
+    return status;
+}
+
+gceSTATUS
+_GetMtlbFreeSpace(
+    IN gckMMU Mmu,
+    IN gctUINT32 NumEntries,
+    OUT gctUINT32 *MtlbStart,
+    OUT gctUINT32 *MtlbEnd
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsFreeSpaceNode_PTR nodeArray = gcvNULL;
+    gctINT i, nodeArraySize = 0;
+    gctINT numEntries = gcdMMU_MTLB_ENTRY_NUM;
+    gctINT32 mStart = -1;
+    gctINT32 mEnd = -1;
+
+    gcmkONERROR(_CollectFreeSpace(Mmu, &nodeArray, &nodeArraySize));
+
+    /* Find the smallest space for NumEntries */
+    for (i = 0; i < nodeArraySize; i++)
+    {
+        if (nodeArray[i].entries < numEntries && NumEntries <= (gctUINT32)nodeArray[i].entries)
+        {
+            numEntries = nodeArray[i].entries;
+
+            mStart = nodeArray[i].start;
+            mEnd   = nodeArray[i].start + NumEntries - 1;
+        }
+    }
+
+    if (mStart == -1 && mEnd == -1)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    *MtlbStart = (gctUINT32)mStart;
+    *MtlbEnd   = (gctUINT32)mEnd;
+
+OnError:
+    if (nodeArray)
+    {
+        gckOS_Free(Mmu->os, (gctPOINTER)nodeArray);
+    }
+
+    return status;
+}
+
+static gcePOOL _GetPageTablePool(IN gckOS Os)
+{
+    gcePOOL pool = gcvPOOL_DEFAULT;
+    gctUINT64 data = 0;
+    gceSTATUS status;
+
+    status = gckOS_QueryOption(Os, "mmuPageTablePool", &data);
+
+    if (status  == gcvSTATUS_OK)
+    {
+        if (data == 1)
+        {
+            pool = gcvPOOL_VIRTUAL;
+        }
+    }
+
+    return pool;
+}
+
+static gceSTATUS
+_FillFlatMapping(
+    IN gckMMU Mmu,
+    IN gctUINT64 PhysBase,
+    IN gctSIZE_T Size,
+    IN gctBOOL   reserved,
+    IN gctBOOL   ableToShift,
+    OUT gctUINT32 *GpuBaseAddress
+    )
+{
+    gceSTATUS status;
+    gctUINT32 mtlb;
+    gctUINT32 physBase;
+    gckKERNEL kernel = Mmu->hardware->kernel;
+    gcsADDRESS_AREA_PTR area = &Mmu->dynamicArea4K;
+    gctBOOL physicalRangeOverlapped = gcvFALSE;
+    gctBOOL virtualRangeOverlapped = gcvFALSE;
+    gctBOOL specificFlatMapping = gcvFALSE;
+    gctBOOL needShiftMapping = gcvFALSE;
+    gctUINT64 flatBase = PhysBase;
+    gctUINT32 flatSize = (gctUINT32) Size;
+    gctUINT64 base = flatBase;
+    gctUINT64 end  = base + flatSize;
+    gctUINT32 reqVirtualBase = 0;
+    gctUINT32 flatVirtualBase = 0;
+    gctUINT32 i;
+
+    /************************ Get flat mapping type and range. ************************/
+    {
+        for (i = 0; i < Mmu->gpuPhysicalRangeCount; i++)
+        {
+            if (base < Mmu->gpuPhysicalRanges[i].start)
+            {
+                if (end > Mmu->gpuPhysicalRanges[i].start)
+                {
+                    physicalRangeOverlapped = gcvTRUE;
+                    if (Mmu->gpuPhysicalRanges[i].flag == gcvFLATMAP_DIRECT)
+                    {
+                        /* Overlapped part is direct mapping, continue direct mapping */
+                        end = Mmu->gpuPhysicalRanges[i].start;
+                    }
+                    else
+                    {
+                        /* Overlapped part is shift mapping, do entire shift mapping */
+                        needShiftMapping = gcvTRUE;
+                    }
+                }
+
+                flatSize = (gctUINT32) (end - base);
+            }
+            else if (end > Mmu->gpuPhysicalRanges[i].end)
+            {
+                if (base < Mmu->gpuPhysicalRanges[i].end)
+                {
+                    physicalRangeOverlapped = gcvTRUE;
+                    if (Mmu->gpuPhysicalRanges[i].flag == gcvFLATMAP_DIRECT)
+                    {
+                        /* Overlapped part is direct mapping, continue direct mapping */
+                        base = Mmu->gpuPhysicalRanges[i].end + 1;
+                    }
+                    else
+                    {
+                        /* Overlapped part is shift mapping, do entire shift mapping */
+                        needShiftMapping = gcvTRUE;
+                    }
+
+                }
+
+                flatBase = base;
+                flatSize = (gctUINT32) (end - base);
+            }
+            else
+            {
+                /* it is already inside existing flat mapping ranges. */
+                flatSize = 0;
+            }
+
+            if (flatSize == 0)
+            {
+                if (GpuBaseAddress)
+                {
+                    *GpuBaseAddress = (gctUINT32) PhysBase;
+                }
+
+                return gcvSTATUS_OK;
+            }
+        }
+    }
+
+    /* overwrite the orignal parameters */
+    PhysBase = flatBase;
+    physBase = (gctUINT32)flatBase;
+
+    mtlb = _MtlbOffset(physBase);
+
+    if (GpuBaseAddress)
+    {
+        reqVirtualBase = *GpuBaseAddress;
+    }
+
+    /*
+     * if no partcial physical range overlap to request entire shift mapping,
+     * it is specific shift mapping or directly mapping by default.
+     */
+    if (!needShiftMapping)
+    {
+        flatVirtualBase = reqVirtualBase ? reqVirtualBase : (gctUINT32)flatBase;
+    }
+
+    for (i = 0; i < Mmu->gpuAddressRangeCount; i++)
+    {
+        if (_IsRangeInsected(flatVirtualBase, flatSize,
+            Mmu->gpuAddressRanges[i].start,  Mmu->gpuAddressRanges[i].size))
+        {
+            virtualRangeOverlapped = gcvTRUE;
+        }
+    }
+
+    /* If gpu virtual range overlapped or gpu physical over 4G, still need entire shift mapping */
+    if ((!physicalRangeOverlapped && virtualRangeOverlapped) ||
+        PhysBase + flatSize - 1 > 0xffffffff)
+    {
+        needShiftMapping = gcvTRUE;
+    }
+
+    if (needShiftMapping && !ableToShift)
+    {
+        /*
+         * Return without mapping any address.
+         * By now, only physBase physSize could run here.
+         */
+        return gcvSTATUS_OK;
+    }
+
+    specificFlatMapping = (reqVirtualBase && !virtualRangeOverlapped && !physicalRangeOverlapped);
+
+    /************************ Setup flat mapping in dynamic range. ****************/
+    if (area->mappingStart != gcvINVALID_ADDRESS && mtlb >= area->mappingStart && mtlb < area->mappingEnd && !needShiftMapping)
+    {
+        /* This path is useless now, keep it 4K page size */
+
+        gctUINT32_PTR stlbEntry;
+
+        stlbEntry = _StlbEntry(area, physBase);
+
+        /* Must be aligned to page. */
+        gcmkASSERT((flatSize & 0xFFF) == 0);
+
+        for (i = 0; i < (flatSize / gcdMMU_PAGE_4K_SIZE); i++)
+        {
+            /* Flat mapping in page table. */
+            _WritePageEntry(stlbEntry, _SetPage(physBase + i * gcdMMU_PAGE_4K_SIZE, 0, gcvTRUE));
+#if gcdMMU_TABLE_DUMP
+            gckOS_Print("%s(%d): insert MTLB[%d] STLB[%d]: %08x\n",
+                __FUNCTION__, __LINE__,
+                (physBase & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT,
+                ((physBase & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT) + i,
+                _ReadPageEntry(stlbEntry));
+#endif
+            stlbEntry++;
+        }
+
+#if gcdDUMP_IN_KERNEL
+        {
+            gctPHYS_ADDR_T physical;
+            gctUINT32 data = _SetPage(physBase, 0, gcvTRUE) & ~0xF;
+            gctUINT32 step = (_SetPage(physBase + gcdMMU_PAGE_4K_SIZE, 0, gcvTRUE) & ~0xF) - data;
+            gctUINT32 mask = _SetPage(physBase, 0, gcvTRUE) & 0xF;
+
+            physical  = area->stlbPhysical + 4 * _AddressToIndex(area, physBase);
+
+            gcmkDUMP(Mmu->os,
+                     "#[mmu-stlb: flat-mapping in dynamic: 0x%08X - 0x%08X]",
+                     physBase, physBase - 1 + flatSize);
+
+            gcmkDUMP(Mmu->os,
+                     "@[physical.step 0x%010llX 0x%08X 0x%08lX 0x%08X 0x%08X",
+                     (unsigned long long)physical, data,
+                     (unsigned long)(flatSize / gcdMMU_PAGE_4K_SIZE * sizeof(gctUINT32)),
+                     step, mask);
+        }
+#endif
+
+        /* Flat mapping in map. */
+        _FillFlatMappingInMap(area, _AddressToIndex(area, physBase), flatSize / gcdMMU_PAGE_4K_SIZE);
+
+        return gcvSTATUS_OK;
+    }
+
+    /************************ Setup flat mapping in non dynamic range. **************/
+    {
+        gctBOOL mutex = gcvFALSE;
+        gctUINT32 physBaseExt = (gctUINT32) (PhysBase >> 32);
+        gctUINT32 start = physBase & ~gcdMMU_PAGE_1M_MASK;
+        gctUINT32 end = (gctUINT32) (physBase + flatSize - 1) & ~gcdMMU_PAGE_1M_MASK;
+        gctUINT32 mStart = start >> gcdMMU_MTLB_SHIFT;
+        gctUINT32 mEnd = end >> gcdMMU_MTLB_SHIFT;
+        gctUINT32 sStart = (start & gcdMMU_STLB_1M_MASK) >> gcdMMU_STLB_1M_SHIFT;
+        gctUINT32 sEnd = (end & gcdMMU_STLB_1M_MASK) >> gcdMMU_STLB_1M_SHIFT;
+        gctPHYS_ADDR_T physical;
+        gcsMMU_STLB_CHUNK_PTR newStlbChunk = gcvNULL;
+        gctUINT32 stlbIndex = 0;
+        gctUINT32 totalNewStlbs = 0;
+        gctINT32 firstMtlbEntry = -1;
+        gctUINT32 mtlbCurEntry;
+        gcsMMU_STLB_CHUNK_PTR curStlbChunk = gcvNULL;
+        gceFLATMAP_FLAG mapFlag = gcvFLATMAP_DIRECT;
+        enum
+        {
+            COLOR_NONE   = 0,
+            COLOR_RED    = 1, /* occupied entry */
+            COLOR_BLUE   = 2, /* empty entry */
+            COLOR_MAX    = COLOR_BLUE,
+        } lastColor = COLOR_NONE;
+        gctUINT32 colorNumber = 0;
+
+        /* Grab the mutex. */
+        gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+        mutex = gcvTRUE;
+
+        if (needShiftMapping)
+        {
+            gctUINT32 mEntries;
+            gctUINT32 sEntries;
+
+            mEntries = (flatSize + (1 << gcdMMU_MTLB_SHIFT) - 1) / (1 << gcdMMU_MTLB_SHIFT);
+
+            gcmkONERROR(_GetMtlbFreeSpace(Mmu, mEntries, &mStart, &mEnd));
+
+            sStart = 0;
+            sEntries = (flatSize + gcdMMU_PAGE_1M_SIZE - 1) / gcdMMU_PAGE_1M_SIZE;
+            sEnd = (sEntries - 1) % gcdMMU_STLB_1M_ENTRY_NUM;
+            mapFlag = gcvFLATMAP_SHIFT;
+        }
+
+        if (specificFlatMapping)
+        {
+            start    = reqVirtualBase & ~gcdMMU_PAGE_1M_MASK;
+            end      = (reqVirtualBase + flatSize - 1) & ~gcdMMU_PAGE_1M_MASK;
+            mStart   = start >> gcdMMU_MTLB_SHIFT;
+            mEnd     = end >> gcdMMU_MTLB_SHIFT;
+            sStart   = (start & gcdMMU_STLB_1M_MASK) >> gcdMMU_STLB_1M_SHIFT;
+            sEnd     = (end & gcdMMU_STLB_1M_MASK) >> gcdMMU_STLB_1M_SHIFT;
+            mapFlag  = gcvFLATMAP_SHIFT;
+        }
+
+        /* No matter direct mapping or shift mapping or specific mapping, store gpu virtual ranges */
+        flatVirtualBase = (mStart << gcdMMU_MTLB_SHIFT)
+                        | (sStart << gcdMMU_STLB_1M_SHIFT)
+                        | (physBase & gcdMMU_PAGE_1M_MASK);
+
+        /* Return GPU virtual base address if necessary */
+        if (GpuBaseAddress)
+        {
+            *GpuBaseAddress = flatVirtualBase;
+        }
+
+        mtlbCurEntry = mStart;
+
+        /* find all new stlbs, part of new flat mapping range may already have stlbs*/
+        while (mtlbCurEntry <= mEnd)
+        {
+            if (*(Mmu->mtlbLogical + mtlbCurEntry) == 0)
+            {
+                if (lastColor != COLOR_BLUE)
+                {
+                    if (colorNumber < COLOR_MAX)
+                    {
+                        lastColor = COLOR_BLUE;
+                        colorNumber++;
+                    }
+                    else
+                    {
+                        gcmkPRINT("There is a hole in new flat mapping range, which is not correct");
+                    }
+                }
+
+                totalNewStlbs++;
+                if (-1 == firstMtlbEntry)
+                {
+                    firstMtlbEntry = mtlbCurEntry;
+                }
+            }
+            else
+            {
+                if (lastColor != COLOR_RED)
+                {
+                    if (colorNumber < COLOR_MAX)
+                    {
+                        lastColor = COLOR_RED;
+                        colorNumber++;
+                    }
+                    else
+                    {
+                        gcmkPRINT("There is a hole in new flat mapping range, which is not correct");
+                    }
+                }
+            }
+            mtlbCurEntry++;
+        }
+
+        /* Need allocate a new chunk of stlbs */
+        if (totalNewStlbs)
+        {
+            gcePOOL pool = Mmu->pool;
+            gctUINT32 allocFlag = gcvALLOC_FLAG_CONTIGUOUS;
+
+            gcmkONERROR(
+                gckOS_Allocate(Mmu->os,
+                               sizeof(struct _gcsMMU_STLB_CHUNK),
+                               (gctPOINTER *)&newStlbChunk));
+
+            newStlbChunk->mtlbEntryNum = totalNewStlbs;
+            newStlbChunk->next = gcvNULL;
+            newStlbChunk->videoMem = gcvNULL;
+            newStlbChunk->logical = gcvNULL;
+            newStlbChunk->size = gcdMMU_STLB_1M_SIZE * newStlbChunk->mtlbEntryNum;
+            newStlbChunk->pageCount = 0;
+            newStlbChunk->mtlbIndex = firstMtlbEntry;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+            allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+            allocFlag |= gcvALLOC_FLAG_4GB_ADDR;
+
+            gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                kernel,
+                gcdMMU_STLB_1M_SIZE,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag | gcvALLOC_FLAG_4K_PAGES,
+                &newStlbChunk->size,
+                &pool,
+                &newStlbChunk->videoMem));
+
+            /* Lock for kernel side CPU access. */
+            gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                kernel,
+                newStlbChunk->videoMem,
+                gcvFALSE,
+                gcvFALSE,
+                (gctPOINTER *)&newStlbChunk->logical));
+
+            gcmkONERROR(gckOS_ZeroMemory(newStlbChunk->logical, newStlbChunk->size));
+
+            /* Get CPU physical address. */
+            gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+                kernel,
+                newStlbChunk->videoMem,
+                0,
+                &physical));
+
+            gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+                Mmu->os,
+                physical,
+                &physical));
+
+            newStlbChunk->physBase = physical;
+        }
+
+        while (mStart <= mEnd)
+        {
+            gctUINT32 last = (mStart == mEnd) ? sEnd : (gcdMMU_STLB_1M_ENTRY_NUM - 1);
+            gctPHYS_ADDR_T stlbPhyBase;
+            gctUINT32_PTR stlbLogical;
+
+            gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM);
+
+            if (*(Mmu->mtlbLogical + mStart) == 0)
+            {
+                gctUINT32 mtlbEntry;
+                curStlbChunk = newStlbChunk;
+                stlbPhyBase = curStlbChunk->physBase + (stlbIndex * gcdMMU_STLB_1M_SIZE);
+                stlbLogical = (gctUINT32_PTR)((gctUINT8_PTR)curStlbChunk->logical + (stlbIndex * gcdMMU_STLB_1M_SIZE));
+
+                physical  = stlbPhyBase
+                          /* 1MB page size */
+                          | (1 << 3)
+                          /* Ignore exception */
+                          | (0 << 1)
+                          /* Present */
+                          | (1 << 0);
+
+                gcmkSAFECASTPHYSADDRT(mtlbEntry, physical);
+
+                _WritePageEntry(Mmu->mtlbLogical + mStart, mtlbEntry);
+
+#if gcdMMU_TABLE_DUMP
+                gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
+                    __FUNCTION__, __LINE__,
+                    mStart,
+                    _ReadPageEntry(Mmu->mtlbLogical + mStart));
+
+                gckOS_Print("%s(%d): STLB: logical:%08x -> physical:%08x\n",
+                        __FUNCTION__, __LINE__,
+                        stlbLogical,
+                        stlbPhyBase);
+#endif
+
+                gcmkDUMP(Mmu->os, "#[mmu-mtlb: flat-mapping, slot: %d]", mStart);
+
+                gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                         (unsigned long long)Mmu->mtlbPhysical + mStart * 4,
+                         Mmu->mtlbLogical[mStart], 4);
+
+                ++stlbIndex;
+            }
+            else
+            {
+                gctUINT32 mtlbEntry = _ReadPageEntry(Mmu->mtlbLogical + mStart);
+                gctUINT stlbOffset;
+
+                curStlbChunk = (gcsMMU_STLB_CHUNK_PTR)Mmu->staticSTLB;
+
+                while (curStlbChunk)
+                {
+                    if ((mStart >= curStlbChunk->mtlbIndex) &&
+                        (mStart < (curStlbChunk->mtlbIndex + curStlbChunk->mtlbEntryNum)))
+                    {
+                        break;
+                    }
+                    curStlbChunk = curStlbChunk->next;
+                }
+                gcmkASSERT(curStlbChunk);
+
+                if (!curStlbChunk)
+                    gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+
+                stlbOffset = mStart - curStlbChunk->mtlbIndex;
+
+                stlbPhyBase = curStlbChunk->physBase + (stlbOffset * gcdMMU_STLB_1M_SIZE);
+                stlbLogical = (gctUINT32_PTR)((gctUINT8_PTR)curStlbChunk->logical + (stlbOffset * gcdMMU_STLB_1M_SIZE));
+                if (stlbPhyBase != (mtlbEntry & gcdMMU_MTLB_ENTRY_STLB_MASK))
+                {
+                    gcmkASSERT(0);
+                }
+            }
+
+#if gcdDUMP_IN_KERNEL
+            /* Start index. */
+            i = sStart;
+
+            gcmkDUMP(Mmu->os, "#[mmu-stlb: flat-mapping: 0x%08X - 0x%08X]",
+                     start, start + (last - sStart) * gcdMMU_PAGE_1M_SIZE - 1);
+#endif
+
+            while (sStart <= last)
+            {
+                gcmkASSERT(!(start & gcdMMU_PAGE_1M_MASK));
+                if (reserved)
+                {
+                    /* program NOT_PRESENT | EXCEPTION  for reserved entries */
+                    _WritePageEntry(stlbLogical + sStart, 1 << 1);
+                }
+                else
+                {
+                    _WritePageEntry(stlbLogical + sStart, _SetPage(start, physBaseExt, gcvTRUE));
+                }
+#if gcdMMU_TABLE_DUMP
+                gckOS_Print("%s(%d): insert STLB[%d]: %08x\n",
+                    __FUNCTION__, __LINE__,
+                    sStart,
+                    _ReadPageEntry(stlbLogical + sStart));
+#endif
+                /* next page. */
+                start += gcdMMU_PAGE_1M_SIZE;
+                if (start == 0)
+                {
+                    physBaseExt++;
+                }
+                sStart++;
+                curStlbChunk->pageCount++;
+            }
+
+#if gcdDUMP_IN_KERNEL
+            {
+                gctUINT32 data = stlbLogical[i] & ~0xF;
+                gctUINT32 step = (last > i) ? (stlbLogical[i + 1] - stlbLogical[i]) : 0;
+                gctUINT32 mask = stlbLogical[i] & 0xF;
+
+                gcmkDUMP(Mmu->os,
+                         "@[physical.step 0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X]",
+                         (unsigned long long)stlbPhyBase + i * 4,
+                         data, (last - i) * 4, step, mask);
+            }
+#endif
+
+            gcmkONERROR(gckVIDMEM_NODE_CleanCache(
+                kernel,
+                curStlbChunk->videoMem,
+                0,
+                curStlbChunk->logical,
+                curStlbChunk->size
+                ));
+
+            sStart = 0;
+            ++mStart;
+        }
+
+        gcmkASSERT(totalNewStlbs == stlbIndex);
+
+        if (newStlbChunk)
+        {
+            /* Insert the stlbChunk into staticSTLB. */
+            if (Mmu->staticSTLB == gcvNULL)
+            {
+                Mmu->staticSTLB = newStlbChunk;
+            }
+            else
+            {
+                gcmkASSERT(newStlbChunk != gcvNULL);
+                gcmkASSERT(newStlbChunk->next == gcvNULL);
+                newStlbChunk->next = Mmu->staticSTLB;
+                Mmu->staticSTLB = newStlbChunk;
+            }
+        }
+
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+#if gcdENABLE_TRUST_APPLICATION
+        if (Mmu->hardware->options.secureMode == gcvSECURE_IN_TA)
+        {
+            gckKERNEL_SecurityMapMemory(Mmu->hardware->kernel, gcvNULL, physBase, flatSize / gcdMMU_PAGE_4K_SIZE, &physBase);
+        }
+#endif
+
+        /* Store the gpu physical ranges */
+        Mmu->gpuPhysicalRanges[Mmu->gpuPhysicalRangeCount].start = flatBase;
+        Mmu->gpuPhysicalRanges[Mmu->gpuPhysicalRangeCount].end   = flatBase + flatSize - 1;
+        Mmu->gpuPhysicalRanges[Mmu->gpuPhysicalRangeCount].size  = flatSize;
+        Mmu->gpuPhysicalRanges[Mmu->gpuPhysicalRangeCount].flag  = mapFlag;
+        Mmu->gpuPhysicalRangeCount++;
+
+        gcmkASSERT(Mmu->gpuPhysicalRangeCount <= gcdMAX_FLAT_MAPPING_COUNT);
+
+        /* Store the gpu virtual ranges */
+        Mmu->gpuAddressRanges[Mmu->gpuAddressRangeCount].start = flatVirtualBase;
+        Mmu->gpuAddressRanges[Mmu->gpuAddressRangeCount].end   = flatVirtualBase + flatSize - 1;
+        Mmu->gpuAddressRanges[Mmu->gpuAddressRangeCount].size  = flatSize;
+        Mmu->gpuAddressRanges[Mmu->gpuAddressRangeCount].flag  = mapFlag;
+        Mmu->gpuAddressRangeCount++;
+
+        gcmkASSERT(Mmu->gpuAddressRangeCount <= gcdMAX_FLAT_MAPPING_COUNT);
+
+        return gcvSTATUS_OK;
+OnError:
+        /* Roll back the allocation.
+        ** We don't need roll back mtlb programming as gckmONERROR
+        ** is only used during allocation time.
+        */
+        if (newStlbChunk)
+        {
+            if (newStlbChunk->videoMem)
+            {
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+                    kernel,
+                    newStlbChunk->videoMem
+                    ));
+            }
+
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, newStlbChunk));
+        }
+        if (mutex)
+        {
+            /* Release the mutex. */
+            gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+        }
+        return status;
+    }
+}
+
+static gceSTATUS
+_SetupAddressArea(
+    IN gckOS Os,
+    IN gcsADDRESS_AREA_PTR Area,
+    IN gctUINT32 NumMTLBEntries
+    )
+{
+    gceSTATUS status;
+    gctUINT32_PTR map;
+    gctUINT32 stlbSize = (Area->areaType == gcvAREA_TYPE_1M)
+                       ? gcdMMU_STLB_1M_SIZE : gcdMMU_STLB_4K_SIZE;
+
+    gcmkHEADER();
+    Area->stlbSize = NumMTLBEntries * stlbSize;
+
+    gcmkSAFECASTSIZET(Area->stlbEntries, Area->stlbSize / gcmSIZEOF(gctUINT32));
+
+    gcmkONERROR(gckOS_Allocate(Os, Area->stlbSize, (void **)&Area->mapLogical));
+
+    /* Initialization. */
+    map      = Area->mapLogical;
+    map[0]   = (Area->stlbEntries << 8) | gcvMMU_FREE;
+    map[1]   = ~0U;
+    Area->heapList  = 0;
+    Area->freeNodes = gcvFALSE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_ConstructDynamicStlb(
+    IN gckMMU Mmu,
+    IN gcsADDRESS_AREA_PTR Area,
+    IN gctUINT32 NumEntries
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctBOOL acquired = gcvFALSE;
+    gckKERNEL kernel = Mmu->hardware->kernel;
+    gctUINT32 allocFlag = gcvALLOC_FLAG_CONTIGUOUS;
+    gcePOOL pool = Mmu->pool;
+    gctUINT32 address;
+    gctUINT32 mtlbEntry;
+    gctUINT32 i;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+    allocFlag |= gcvALLOC_FLAG_4GB_ADDR;
+
+    /* Construct Slave TLB. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                kernel,
+                64,
+                gcvVIDMEM_TYPE_COMMAND,
+                allocFlag | gcvALLOC_FLAG_4K_PAGES,
+                &Area->stlbSize,
+                &pool,
+                &Area->stlbVideoMem));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                kernel,
+                Area->stlbVideoMem,
+                gcvFALSE,
+                gcvFALSE,
+                (gctPOINTER *)&Area->stlbLogical));
+
+#if gcdUSE_MMU_EXCEPTION
+    gcmkONERROR(_FillPageTable(Area->stlbLogical,
+                               Area->stlbEntries,
+                               /* Enable exception */
+                               1 << 1));
+#else
+    /* Invalidate all entries. */
+    gcmkONERROR(gckOS_ZeroMemory(Area->stlbLogical,
+                Area->stlbSize));
+#endif
+
+    /* Get stlb table physical. */
+    gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+                kernel,
+                Area->stlbVideoMem,
+                0,
+                &Area->stlbPhysical));
+
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Mmu->os,
+                  Area->stlbPhysical,
+                  &Area->stlbPhysical));
+
+    if (Area->areaType == gcvAREA_TYPE_1M)
+    {
+        gcmkDUMP(Mmu->os, "#[mmu: 1M page size dynamic space: 0x%08X - 0x%08X]",
+                 (Area->mappingStart << gcdMMU_MTLB_SHIFT),
+                 (Area->mappingEnd << gcdMMU_MTLB_SHIFT) - 1);
+    }
+    else
+    {
+        gcmkDUMP(Mmu->os, "#[mmu: 4K page size dynamic space: 0x%08X - 0x%08X]",
+                 (Area->mappingStart << gcdMMU_MTLB_SHIFT),
+                 (Area->mappingEnd << gcdMMU_MTLB_SHIFT) - 1);
+    }
+
+    gcmkDUMP(Mmu->os, "#[mmu-stlb]");
+
+    gcmkDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 0x%08lX]",
+             (unsigned long long)Area->stlbPhysical,
+             Area->stlbLogical[0],
+             (unsigned long)Area->stlbSize);
+
+    gcmkSAFECASTPHYSADDRT(address, Area->stlbPhysical);
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Map to Master TLB. */
+    for (i = Area->mappingStart;
+         i < Area->mappingStart + NumEntries;
+         i++)
+    {
+        if (Area->areaType == gcvAREA_TYPE_1M)
+        {
+            mtlbEntry = address
+                      /* 1M page size */
+                      | (1 << 3)
+                      /*Ignore exception */
+                      | (0 << 1)
+                      /* Present */
+                      | (1 << 0);
+
+            address += gcdMMU_STLB_1M_SIZE;
+        }
+        else
+        {
+            mtlbEntry = address
+                      /* 4KB page size */
+                      | (0 << 2)
+                      /*Ignore exception */
+                      | (0 << 1)
+                      /* Present */
+                      | (1 << 0);
+
+            address += gcdMMU_STLB_4K_SIZE;
+        }
+
+        _WritePageEntry(Mmu->mtlbLogical + i, mtlbEntry);
+
+#if gcdMMU_TABLE_DUMP
+        gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
+                __FUNCTION__, __LINE__,
+                i,
+                _ReadPageEntry(Mmu->mtlbLogical + i));
+#endif
+    }
+
+    gcmkDUMP(Mmu->os, "#[mmu-mtlb: slot: %d - %d]",
+             Area->mappingStart, Area->mappingEnd - 1);
+
+#if gcdDUMP_IN_KERNEL
+    {
+        gctUINT32 data = Mmu->mtlbLogical[Area->mappingStart] & ~0x3F;
+        gctUINT32 step = 0;
+        gctUINT32 mask = Mmu->mtlbLogical[Area->mappingStart] & 0x3F;
+
+        if (NumEntries > 1)
+        {
+            step = Mmu->mtlbLogical[Area->mappingStart + 1]
+                 - Mmu->mtlbLogical[Area->mappingStart];
+        }
+
+        gcmkDUMP(Mmu->os,
+                 "@[physical.step 0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X]",
+                 (unsigned long long)(Mmu->mtlbPhysical + Area->mappingStart * 4),
+                 data, NumEntries * 4, step, mask);
+    }
+#endif
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckMMU_SetupDynamicSpace(
+    IN gckMMU Mmu
+    )
+{
+    gceSTATUS status;
+    gcsFreeSpaceNode_PTR nodeArray = gcvNULL;
+    gctINT i, nodeArraySize = 0;
+    gctINT numEntries = 0;
+    gckKERNEL kernel = Mmu->hardware->kernel;
+    gcsADDRESS_AREA_PTR area4K = &Mmu->dynamicArea4K;
+#if gcdENABLE_GPU_1M_PAGE
+    gcsADDRESS_AREA_PTR area1M = &Mmu->dynamicArea1M;
+    gctINT numEntries1M;
+#endif
+
+    /* Find all the free address space. */
+    gcmkONERROR(_CollectFreeSpace(Mmu, &nodeArray, &nodeArraySize));
+
+    for (i = 0; i < nodeArraySize; i++)
+    {
+        if (nodeArray[i].entries > numEntries)
+        {
+            area4K->mappingStart = nodeArray[i].start;
+            numEntries           = nodeArray[i].entries;
+            area4K->mappingEnd   = area4K->mappingStart + numEntries - 1;
+        }
+    }
+
+    gckOS_Free(Mmu->os, (gctPOINTER)nodeArray);
+
+#if gcdENABLE_TRUST_APPLICATION
+    if (gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_SECURITY) == gcvSTATUS_TRUE)
+    {
+        /* Setup secure address area when needed. */
+        gctUINT32 secureAreaSize = gcdMMU_SECURE_AREA_SIZE;
+        gcsADDRESS_AREA_PTR secureArea = &Mmu->secureArea;
+
+        gcmkASSERT(numEntries > (gctINT)secureAreaSize);
+
+        secureArea->mappingStart = area4K->mappingStart
+                                 + (numEntries - secureAreaSize);
+
+        gcmkONERROR(_SetupAddressArea(Mmu->os, secureArea, secureAreaSize));
+
+        numEntries -= secureAreaSize;
+        area4K->mappingEnd -= secureAreaSize;
+    }
+#endif
+
+#if gcdENABLE_GPU_1M_PAGE
+    numEntries1M = numEntries >> 1;
+    area1M->mappingStart = area4K->mappingStart + (numEntries - numEntries1M);
+    area1M->mappingEnd   = area1M->mappingStart + numEntries1M - 1;
+    area1M->areaType     = gcvAREA_TYPE_1M;
+    numEntries           -= numEntries1M;
+    area4K->mappingEnd   -= numEntries1M;
+
+    gcmkONERROR(_SetupAddressArea(Mmu->os, area1M, numEntries1M));
+
+    gcmkONERROR(_ConstructDynamicStlb(Mmu, area1M, numEntries1M));
+#endif
+
+    area4K->areaType = gcvAREA_TYPE_4K;
+
+    /* Setup normal address area. */
+    gcmkONERROR(_SetupAddressArea(Mmu->os, area4K, numEntries));
+
+    gcmkONERROR(_ConstructDynamicStlb(Mmu, area4K, numEntries));
+
+    return gcvSTATUS_OK;
+
+OnError:
+#if gcdENABLE_GPU_1M_PAGE
+    if (area1M->mapLogical)
+    {
+        gcmkVERIFY_OK(
+            gckOS_Free(Mmu->os, (gctPOINTER) area1M->mapLogical));
+    }
+
+    if (area1M->stlbVideoMem)
+    {
+        gcmkVERIFY_OK(
+            gckVIDMEM_NODE_Dereference(kernel,
+                                       area1M->stlbVideoMem));
+    }
+#endif
+
+    if (area4K->mapLogical)
+    {
+        gcmkVERIFY_OK(
+            gckOS_Free(Mmu->os, (gctPOINTER) area4K->mapLogical));
+    }
+
+    if (area4K->stlbVideoMem)
+    {
+        gcmkVERIFY_OK(
+            gckVIDMEM_NODE_Dereference(kernel,
+                                       area4K->stlbVideoMem));
+    }
+
+    return status;
+}
+
+gctUINT32
+_GetPageCountOfUsedNode(
+    gctUINT32_PTR Node
+    )
+{
+    gctUINT32 count;
+
+    count = gcmENTRY_COUNT(*Node);
+
+    if ((count << 8) == (~((1U<<8)-1)))
+    {
+        count = 1;
+    }
+
+    return count;
+}
+
+static gcsADDRESS_AREA_PTR
+_GetProcessArea(
+    IN gckMMU Mmu,
+    IN gcePAGE_TYPE PageType,
+    IN gctBOOL Secure
+    )
+{
+#if gcdENABLE_TRUST_APPLICATION
+    if (Secure == gcvTRUE)
+    {
+        return &Mmu->secureArea;
+    }
+#endif
+
+    if (PageType == gcvPAGE_TYPE_1M)
+    {
+        return &Mmu->dynamicArea1M;
+    }
+    else
+    {
+        return &Mmu->dynamicArea4K;
+    }
+}
+
+/*******************************************************************************
+**
+**  _Construct
+**
+**  Construct a new gckMMU object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSIZE_T MmuSize
+**          Number of bytes for the page table.
+**
+**  OUTPUT:
+**
+**      gckMMU * Mmu
+**          Pointer to a variable that receives the gckMMU object pointer.
+*/
+gceSTATUS
+_Construct(
+    IN gckKERNEL Kernel,
+    IN gctSIZE_T MmuSize,
+    OUT gckMMU * Mmu
+    )
+{
+    gckOS os;
+    gckHARDWARE hardware;
+    gceSTATUS status;
+    gckMMU mmu = gcvNULL;
+    gctUINT32_PTR map;
+    gctPOINTER pointer = gcvNULL;
+    gctPHYS_ADDR_T physBase;
+    gctSIZE_T physSize;
+    gctPHYS_ADDR_T contiguousBase;
+    gctSIZE_T contiguousSize = 0;
+    gctPHYS_ADDR_T externalBase;
+    gctSIZE_T externalSize = 0;
+    gctUINT32 gpuAddress;
+    gctPHYS_ADDR_T gpuPhysical;
+    gcsADDRESS_AREA_PTR area = gcvNULL;
+    gcePOOL pool;
+    gctUINT64 data;
+    gctUINT32 allocFlag = gcvALLOC_FLAG_CONTIGUOUS;
+    gctUINT64 mmuEnabled;
+
+    gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(MmuSize > 0);
+    gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
+
+    /* Extract the gckOS object pointer. */
+    os = Kernel->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Extract the gckHARDWARE object pointer. */
+    hardware = Kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Allocate memory for the gckMMU object. */
+    gcmkONERROR(gckOS_Allocate(os, sizeof(struct _gckMMU), &pointer));
+
+    gckOS_ZeroMemory(pointer, sizeof(struct _gckMMU));
+
+    mmu = pointer;
+
+    /* Initialize the gckMMU object. */
+    mmu->object.type      = gcvOBJ_MMU;
+    mmu->os               = os;
+    mmu->hardware         = hardware;
+    mmu->pageTableMutex   = gcvNULL;
+    mmu->mtlbLogical      = gcvNULL;
+    mmu->staticSTLB       = gcvNULL;
+    mmu->enabled          = gcvFALSE;
+
+    mmu->dynamicAreaSetuped = gcvFALSE;
+    mmu->pool = _GetPageTablePool(mmu->os);
+    gcsLIST_Init(&mmu->hardwareList);
+
+    /* Use 4K page size for MMU version 0. */
+    area = &mmu->dynamicArea4K;
+    area->mapLogical  = gcvNULL;
+    area->stlbLogical = gcvNULL;
+
+    /* Create the page table mutex. */
+    gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex));
+
+    gcmkONERROR(gckOS_QueryOption(os, "mmu", &mmuEnabled));
+
+    if (hardware->mmuVersion == 0)
+    {
+        area->stlbSize = MmuSize;
+
+        /* Construct address space management table. */
+        gcmkONERROR(gckOS_Allocate(mmu->os,
+                                   area->stlbSize,
+                                   &pointer));
+
+        area->mapLogical = pointer;
+
+        pool = mmu->pool;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+        allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+        /* Construct page table read by GPU. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                    Kernel,
+                    4096,
+                    gcvVIDMEM_TYPE_COMMAND,
+                    allocFlag,
+                    &area->stlbSize,
+                    &pool,
+                    &area->stlbVideoMem));
+
+        /* Lock for kernel side CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                    Kernel,
+                    area->stlbVideoMem,
+                    gcvFALSE,
+                    gcvFALSE,
+                    &pointer));
+
+        area->stlbLogical = pointer;
+
+        /* Get CPU physical address. */
+        gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+                    Kernel,
+                    area->stlbVideoMem,
+                    0,
+                    &area->stlbPhysical));
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(mmu->os,
+                    area->stlbPhysical,
+                    &area->stlbPhysical));
+
+        /* Compute number of entries in page table. */
+        gcmkSAFECASTSIZET(area->stlbEntries, area->stlbSize / sizeof(gctUINT32));
+
+        /* Mark all pages as free. */
+        map      = area->mapLogical;
+
+        _FillPageTable(area->stlbLogical, area->stlbEntries, mmu->safeAddress);
+
+        gcmkDUMP(mmu->os,
+                 "#[mmu0: fill with safe address]");
+
+        gcmkDUMP(mmu->os,
+                 "@[physical.fill 0x%010llX 0x%08X 0x%08lX]",
+                 (unsigned long long)area->stlbPhysical,
+                 area->stlbLogical[0],
+                 (unsigned long)area->stlbSize);
+
+        map[0] = (area->stlbEntries << 8) | gcvMMU_FREE;
+        map[1] = ~0U;
+        area->heapList  = 0;
+        area->freeNodes = gcvFALSE;
+
+        status = gckOS_QueryOption(mmu->os, "contiguousBase", &contiguousBase);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            status = gckOS_QueryOption(mmu->os, "contiguousSize", &data);
+            contiguousSize = (gctSIZE_T)data;
+        }
+
+        if (gcmIS_SUCCESS(status) && contiguousSize)
+        {
+            /* Convert to GPU address. */
+            mmu->contiguousBaseAddress = (gctUINT32)(contiguousBase - Kernel->hardware->baseAddress);
+        }
+    }
+    else
+    {
+        mmu->mtlbSize = gcdMMU_MTLB_SIZE;
+
+        pool = mmu->pool;
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+        allocFlag |= gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+        allocFlag |= gcvALLOC_FLAG_4GB_ADDR;
+
+        /* 1K mode is 1024 byte aligned. */
+        gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+                    Kernel,
+                    1024,
+                    gcvVIDMEM_TYPE_COMMAND,
+                    allocFlag | gcvALLOC_FLAG_4K_PAGES,
+                    &mmu->mtlbSize,
+                    &pool,
+                    &mmu->mtlbVideoMem));
+
+        /* Lock for kernel side CPU access. */
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+                    Kernel,
+                    mmu->mtlbVideoMem,
+                    gcvFALSE,
+                    gcvFALSE,
+                    &pointer));
+
+        mmu->mtlbLogical = pointer;
+
+        mmu->dynamicArea4K.mappingStart = gcvINVALID_ADDRESS;
+        mmu->dynamicArea1M.mappingStart = gcvINVALID_ADDRESS;
+
+        /* Get mtlb table physical. */
+        gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+                    Kernel,
+                    mmu->mtlbVideoMem,
+                    0,
+                    &mmu->mtlbPhysical));
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+                      mmu->os,
+                      mmu->mtlbPhysical,
+                      &mmu->mtlbPhysical));
+
+        /* Invalid all the entries. */
+        gcmkONERROR(
+            gckOS_ZeroMemory(pointer, mmu->mtlbSize));
+
+        gcmkONERROR(
+            gckOS_QueryOption(mmu->os, "physBase", &physBase));
+
+        gcmkONERROR(
+            gckOS_QueryOption(mmu->os, "physSize", &data));
+        physSize = (gctSIZE_T)data;
+
+        gcmkONERROR(
+            gckOS_CPUPhysicalToGPUPhysical(mmu->os, physBase, &gpuPhysical));
+
+        gcmkSAFECASTPHYSADDRT(gpuAddress, gpuPhysical);
+
+        if (physSize)
+        {
+            /* Setup user specified flat mapping. */
+            gcmkONERROR(_FillFlatMapping(mmu, gpuAddress, physSize, gcvFALSE, gcvFALSE, gcvNULL));
+        }
+
+#if !(0 || gcdCAPTURE_ONLY_MODE)
+        if (!_ReadPageEntry(mmu->mtlbLogical + 0))
+        {
+            gctUINT32 mtlbEntry;
+            /*
+             * Reserved the first mtlb.
+             * 1MB page size, Ingore exception, Not Present.
+             */
+            mtlbEntry = (1 << 3)
+                      | (0 << 1)
+                      | (0 << 0);
+
+            _WritePageEntry(mmu->mtlbLogical + 0, mtlbEntry);
+
+            gcmkDUMP(mmu->os, "#[mmu-mtlb: reserved 16M space, slot: 0]");
+            gcmkDUMP(mmu->os,
+                     "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+                     (unsigned long long)mmu->mtlbPhysical,
+                     mmu->mtlbLogical[0], 4);
+
+            /* Store the gpu virtual ranges */
+            mmu->gpuAddressRanges[mmu->gpuAddressRangeCount].start = 0;
+            mmu->gpuAddressRanges[mmu->gpuAddressRangeCount].end   = (16 << 20) - 1;
+            mmu->gpuAddressRanges[mmu->gpuAddressRangeCount].size  = (16 << 20);
+            mmu->gpuAddressRanges[mmu->gpuAddressRangeCount].flag  = gcvFLATMAP_DIRECT;
+            mmu->gpuAddressRangeCount++;
+        }
+#endif
+
+        status = gckOS_QueryOption(mmu->os, "contiguousBase", &contiguousBase);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            status = gckOS_QueryOption(mmu->os, "contiguousSize", &data);
+            contiguousSize = (gctSIZE_T)data;
+        }
+
+        if (gcmIS_SUCCESS(status) && contiguousSize)
+        {
+            gctUINT64 gpuContiguousBase;
+            gctUINT32 contiguousBaseAddress = 0;
+
+            gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(mmu->os, contiguousBase, &gpuContiguousBase));
+
+            /* Setup flat mapping for reserved memory (VIDMEM). */
+            gcmkONERROR(_FillFlatMapping(mmu, gpuContiguousBase, contiguousSize, gcvFALSE, gcvTRUE, &contiguousBaseAddress));
+
+            if (mmuEnabled)
+            {
+                mmu->contiguousBaseAddress = contiguousBaseAddress;
+            }
+            else
+            {
+                gcmkSAFECASTPHYSADDRT(mmu->contiguousBaseAddress, gpuContiguousBase);
+            }
+        }
+
+        status = gckOS_QueryOption(mmu->os, "externalBase", &externalBase);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            status = gckOS_QueryOption(mmu->os, "externalSize", &data);
+            externalSize = (gctSIZE_T)data;
+        }
+
+        if (gcmIS_SUCCESS(status) && externalSize)
+        {
+            gctUINT64 gpuExternalBase;
+            gctUINT32 externalBaseAddress = 0;
+
+            gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(mmu->os, externalBase, &gpuExternalBase));
+
+            /* Setup flat mapping for external memory. */
+            gcmkONERROR(_FillFlatMapping(mmu, gpuExternalBase, externalSize, gcvFALSE, gcvTRUE, &externalBaseAddress));
+
+            mmu->externalBaseAddress = externalBaseAddress;
+        }
+    }
+
+    /* A 64 byte for safe address, we use 256 here. */
+    mmu->safePageSize = 256;
+
+    pool = mmu->pool;
+
+    /* Allocate safe page from video memory. */
+    gcmkONERROR(gckKERNEL_AllocateVideoMemory(
+        Kernel,
+        256,
+        gcvVIDMEM_TYPE_COMMAND,
+        gcvALLOC_FLAG_CONTIGUOUS | gcvALLOC_FLAG_4K_PAGES | gcvALLOC_FLAG_4GB_ADDR,
+        &mmu->safePageSize,
+        &pool,
+        &mmu->safePageVideoMem
+        ));
+
+    /* Lock for kernel side CPU access. */
+    gcmkONERROR(gckVIDMEM_NODE_LockCPU(
+        Kernel,
+        mmu->safePageVideoMem,
+        gcvFALSE,
+        gcvFALSE,
+        &mmu->safePageLogical
+        ));
+
+    /* Get CPU physical address. */
+    gcmkONERROR(gckVIDMEM_NODE_GetPhysical(
+        Kernel,
+        mmu->safePageVideoMem,
+        0,
+        &mmu->safePagePhysical
+        ));
+
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
+        os,
+        mmu->safePagePhysical,
+        &mmu->safePagePhysical
+        ));
+
+    gcmkSAFECASTPHYSADDRT(mmu->safeAddress, mmu->safePagePhysical);
+
+    gckOS_ZeroMemory(mmu->safePageLogical, mmu->safePageSize);
+
+    gcmkDUMP(mmu->os, "#[safe page]");
+    gcmkDUMP(mmu->os,
+            "@[physical.fill 0x%010llX 0x%08X 0x%08lX]",
+            (unsigned long long)mmu->safePagePhysical,
+            0,
+            (unsigned long)mmu->safePageSize);
+
+    gcmkDUMP_BUFFER(
+        mmu->os,
+        gcvDUMP_BUFFER_KERNEL_COMMAND,
+        mmu->safePageLogical,
+        mmu->safeAddress,
+        mmu->safePageSize
+        );
+
+    gcmkONERROR(gckQUEUE_Allocate(os, &mmu->recentFreedAddresses, 16));
+
+    mmu->sRAMMapped = gcvFALSE;
+
+    /* Return the gckMMU object pointer. */
+    *Mmu = mmu;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (mmu != gcvNULL)
+    {
+        if (area != gcvNULL && area->mapLogical != gcvNULL)
+        {
+            gcmkVERIFY_OK(
+                gckOS_Free(os, (gctPOINTER) area->mapLogical));
+
+            gcmkVERIFY_OK(
+                gckVIDMEM_NODE_Dereference(Kernel,
+                                           area->stlbVideoMem));
+        }
+
+        if (mmu->mtlbLogical != gcvNULL)
+        {
+            gcmkVERIFY_OK(
+                gckVIDMEM_NODE_Dereference(Kernel,
+                                           mmu->mtlbVideoMem));
+        }
+
+        if (mmu->pageTableMutex != gcvNULL)
+        {
+            /* Delete the mutex. */
+            gcmkVERIFY_OK(
+                gckOS_DeleteMutex(os, mmu->pageTableMutex));
+        }
+
+        gcmkVERIFY_OK(gckQUEUE_Free(os, &mmu->recentFreedAddresses));
+
+        /* Mark the gckMMU object as unknown. */
+        mmu->object.type = gcvOBJ_UNKNOWN;
+
+        /* Free the allocates memory. */
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, mmu));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_FreeAddressArea(
+    gckKERNEL Kernel,
+    gcsADDRESS_AREA * Area
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (Area->mapLogical != gcvNULL)
+    {
+        gcmkVERIFY_OK(
+            gckOS_Free(Kernel->os, (gctPOINTER) Area->mapLogical));
+    }
+
+    if (Area->stlbLogical != gcvNULL)
+    {
+        /* Free page table. */
+        gcmkVERIFY_OK(
+            gckVIDMEM_NODE_Dereference(Kernel,
+                                       Area->stlbVideoMem));
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+**  _Destroy
+**
+**  Destroy a gckMMU object.
+**
+**  INPUT:
+**
+**      gckMMU Mmu
+**          Pointer to an gckMMU object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+_Destroy(
+    IN gckMMU Mmu
+    )
+{
+    gckKERNEL kernel = Mmu->hardware->kernel;
+
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+    while (Mmu->staticSTLB != gcvNULL)
+    {
+        gcsMMU_STLB_CHUNK_PTR pre = Mmu->staticSTLB;
+        Mmu->staticSTLB = pre->next;
+
+        if (pre->videoMem)
+        {
+            gcmkVERIFY_OK(
+                gckVIDMEM_NODE_Dereference(kernel,
+                                           pre->videoMem));
+        }
+
+        if (pre->mtlbEntryNum != 0)
+        {
+            gctUINT i;
+            for (i = 0; i < pre->mtlbEntryNum; ++i)
+            {
+                _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex + i, 0);
+#if gcdMMU_TABLE_DUMP
+                gckOS_Print("%s(%d): clean MTLB[%d]\n",
+                    __FUNCTION__, __LINE__,
+                    pre->mtlbIndex + i);
+#endif
+            }
+
+            gcmkDUMP(Mmu->os,
+                     "#[mmu-mtlb: clean up slot: %d - %d]",
+                     pre->mtlbIndex,
+                     pre->mtlbIndex + pre->mtlbEntryNum - 1);
+
+            gcmkDUMP(Mmu->os,
+                     "@[physical.fill 0x%010llX 0x%08X 0x%08lX]",
+                     (unsigned long long)(Mmu->mtlbPhysical + pre->mtlbIndex * 4),
+                     Mmu->mtlbLogical[pre->mtlbIndex],
+                     (unsigned long)(pre->mtlbEntryNum * 4));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
+    }
+
+    if (Mmu->hardware->mmuVersion != 0)
+    {
+        gcmkVERIFY_OK(
+            gckVIDMEM_NODE_Dereference(kernel,
+                                       Mmu->mtlbVideoMem));
+    }
+
+    /* Free address area. */
+    gcmkVERIFY_OK(_FreeAddressArea(kernel, &Mmu->dynamicArea4K));
+#if gcdENABLE_GPU_1M_PAGE
+    gcmkVERIFY_OK(_FreeAddressArea(kernel, &Mmu->dynamicArea1M));
+#endif
+    gcmkVERIFY_OK(_FreeAddressArea(kernel, &Mmu->secureArea));
+
+    /* Delete the page table mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex));
+
+    if (Mmu->safePageLogical != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(
+            kernel,
+            Mmu->safePageVideoMem
+            ));
+    }
+
+    gcmkVERIFY_OK(gckQUEUE_Free(Mmu->os, &Mmu->recentFreedAddresses));
+
+    /* Mark the gckMMU object as unknown. */
+    Mmu->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckMMU object. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, Mmu));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** _AdjstIndex
+**
+**  Adjust the index from which we search for a usable node to make sure
+**  index allocated is greater than Start.
+*/
+gceSTATUS
+_AdjustIndex(
+    IN gckMMU Mmu,
+    IN gctUINT32 Index,
+    IN gctUINT32 PageCount,
+    IN gctUINT32 Start,
+    OUT gctUINT32 * IndexAdjusted
+    )
+{
+    gceSTATUS status;
+    gctUINT32 index = Index;
+    gcsADDRESS_AREA_PTR area = &Mmu->dynamicArea4K;
+    gctUINT32_PTR map = area->mapLogical;
+
+    gcmkHEADER();
+
+    for (; index < area->stlbEntries;)
+    {
+        gctUINT32 result = 0;
+        gctUINT32 nodeSize = 0;
+
+        if (index >= Start)
+        {
+            break;
+        }
+
+        switch (gcmENTRY_TYPE(map[index]))
+        {
+        case gcvMMU_SINGLE:
+            nodeSize = 1;
+            break;
+
+        case gcvMMU_FREE:
+            nodeSize = map[index] >> 8;
+            break;
+
+        default:
+            gcmkFATAL("MMU table correcupted at index %u!", index);
+            gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        if (nodeSize > PageCount)
+        {
+            result = index + (nodeSize - PageCount);
+
+            if (result >= Start)
+            {
+                break;
+            }
+        }
+
+        switch (gcmENTRY_TYPE(map[index]))
+        {
+        case gcvMMU_SINGLE:
+            index = map[index] >> 8;
+            break;
+
+        case gcvMMU_FREE:
+            index = map[index + 1];
+            break;
+
+        default:
+            gcmkFATAL("MMU table correcupted at index %u!", index);
+            gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+    }
+
+    *IndexAdjusted = index;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMMU_Construct(
+    IN gckKERNEL Kernel,
+    IN gctSIZE_T MmuSize,
+    OUT gckMMU * Mmu
+    )
+{
+#if gcdSHARED_PAGETABLE
+    gceSTATUS status;
+    gctPOINTER pointer;
+
+    gcmkHEADER_ARG("Kernel=0x%08x", Kernel);
+
+    if (sharedPageTable == gcvNULL)
+    {
+        gcmkONERROR(
+                gckOS_Allocate(Kernel->os,
+                               sizeof(struct _gcsSharedPageTable),
+                               &pointer));
+        sharedPageTable = pointer;
+
+        gcmkONERROR(
+                gckOS_ZeroMemory(sharedPageTable,
+                    sizeof(struct _gcsSharedPageTable)));
+
+        gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu));
+    }
+
+    *Mmu = sharedPageTable->mmu;
+
+    sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware;
+
+    sharedPageTable->reference++;
+
+    gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (sharedPageTable)
+    {
+        if (sharedPageTable->mmu)
+        {
+            gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable));
+    }
+
+    gcmkFOOTER();
+    return status;
+#else
+    return _Construct(Kernel, MmuSize, Mmu);
+#endif
+}
+
+gceSTATUS
+gckMMU_Destroy(
+    IN gckMMU Mmu
+    )
+{
+#if gcdSHARED_PAGETABLE
+    gckOS os = Mmu->os;
+
+    sharedPageTable->reference--;
+
+    if (sharedPageTable->reference == 0)
+    {
+        if (sharedPageTable->mmu)
+        {
+            gcmkVERIFY_OK(_Destroy(Mmu));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, sharedPageTable));
+    }
+
+    return gcvSTATUS_OK;
+#else
+    return _Destroy(Mmu);
+#endif
+}
+
+/*******************************************************************************
+**
+**  gckMMU_AllocatePages
+**
+**  Allocate pages inside the page table.
+**
+**  INPUT:
+**
+**      gckMMU Mmu
+**          Pointer to an gckMMU object.
+**
+**      gctSIZE_T PageCount
+**          Number of pages to allocate.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * PageTable
+**          Pointer to a variable that receives the base address of the page
+**          table.
+**
+**      gctUINT32 * Address
+**          Pointer to a variable that receives the hardware specific address.
+*/
+gceSTATUS
+_AllocatePages(
+    IN gckMMU Mmu,
+    IN gctSIZE_T PageCount,
+    IN gceVIDMEM_TYPE Type,
+    IN gcePAGE_TYPE PageType,
+    IN gctBOOL Secure,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status;
+    gctBOOL mutex = gcvFALSE;
+    gctUINT32 index = 0, previous = ~0U, left;
+    gctUINT32_PTR map;
+    gctBOOL gotIt;
+    gctUINT32 address;
+    gctUINT32 pageCount;
+    gcsADDRESS_AREA_PTR area = _GetProcessArea(Mmu, PageType, Secure);
+
+    gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+
+    if (PageCount > area->stlbEntries)
+    {
+        /* Not enough pages avaiable. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    gcmkSAFECASTSIZET(pageCount, PageCount);
+
+#if gcdBOUNDARY_CHECK
+    /* Extra pages as bounary. */
+    pageCount += gcdBOUNDARY_CHECK * 2;
+#endif
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+    mutex = gcvTRUE;
+
+    /* Cast pointer to page table. */
+    for (map = area->mapLogical, gotIt = gcvFALSE; !gotIt;)
+    {
+        index = area->heapList;
+
+        if ((Mmu->hardware->mmuVersion == 0) &&
+            (Type == gcvVIDMEM_TYPE_VERTEX_BUFFER))
+        {
+            gcmkONERROR(_AdjustIndex(
+                Mmu,
+                index,
+                pageCount,
+                gcdVERTEX_START / gcmSIZEOF(gctUINT32),
+                &index
+                ));
+        }
+
+        /* Walk the heap list. */
+        for (; !gotIt && (index < area->stlbEntries);)
+        {
+            /* Check the node type. */
+            switch (gcmENTRY_TYPE(map[index]))
+            {
+            case gcvMMU_SINGLE:
+                /* Single odes are valid if we only need 1 page. */
+                if (pageCount == 1)
+                {
+                    gotIt = gcvTRUE;
+                }
+                else
+                {
+                    /* Move to next node. */
+                    previous = index;
+                    index    = map[index] >> 8;
+                }
+                break;
+
+            case gcvMMU_FREE:
+                /* Test if the node has enough space. */
+                if (pageCount <= (map[index] >> 8))
+                {
+                    gotIt = gcvTRUE;
+                }
+                else
+                {
+                    /* Move to next node. */
+                    previous = index;
+                    index    = map[index + 1];
+                }
+                break;
+
+            default:
+                gcmkFATAL("MMU table correcupted at index %u!", index);
+                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+            }
+        }
+
+        /* Test if we are out of memory. */
+        if (index >= area->stlbEntries)
+        {
+            if (area->freeNodes)
+            {
+                /* Time to move out the trash! */
+                gcmkONERROR(_Collect(area));
+
+                /* We are going to search from start, so reset previous to start. */
+                previous = ~0U;
+            }
+            else
+            {
+                /* Out of resources. */
+                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+            }
+        }
+    }
+
+    switch (gcmENTRY_TYPE(map[index]))
+    {
+    case gcvMMU_SINGLE:
+        /* Unlink single node from free list. */
+        gcmkONERROR(
+            _Link(area, previous, map[index] >> 8));
+        break;
+
+    case gcvMMU_FREE:
+        /* Check how many pages will be left. */
+        left = (map[index] >> 8) - pageCount;
+        switch (left)
+        {
+        case 0:
+            /* The entire node is consumed, just unlink it. */
+            gcmkONERROR(
+                _Link(area, previous, map[index + 1]));
+            break;
+
+        case 1:
+            /* One page will remain.  Convert the node to a single node and
+            ** advance the index. */
+            map[index] = (map[index + 1] << 8) | gcvMMU_SINGLE;
+            index ++;
+            break;
+
+        default:
+            /* Enough pages remain for a new node.  However, we will just adjust
+            ** the size of the current node and advance the index. */
+            map[index] = (left << 8) | gcvMMU_FREE;
+            index += left;
+            break;
+        }
+        break;
+    }
+
+    /* Mark node as used. */
+    gcmkONERROR(_FillMap(&map[index], pageCount, gcvMMU_USED));
+
+#if gcdBOUNDARY_CHECK
+    index += gcdBOUNDARY_CHECK;
+#endif
+
+    /* Record pageCount of allocated node at the beginning of node. */
+    if (pageCount == 1)
+    {
+        map[index] = (~((1U<<8)-1)) | gcvMMU_USED;
+    }
+    else
+    {
+        map[index] = (pageCount << 8) | gcvMMU_USED;
+    }
+
+    if (area->stlbLogical != gcvNULL)
+    {
+        /* Return pointer to page table. */
+        *PageTable = &area->stlbLogical[index];
+    }
+    else
+    {
+        /* Page table for secure area is handled in trust application. */
+        *PageTable = gcvNULL;
+    }
+
+    /* Build virtual address. */
+    if (Mmu->hardware->mmuVersion == 0)
+    {
+        gcmkONERROR(
+                gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address));
+    }
+    else
+    {
+        gctUINT32 num = (PageType == gcvPAGE_TYPE_1M) ? gcdMMU_STLB_1M_ENTRY_NUM : gcdMMU_STLB_4K_ENTRY_NUM;
+        gctUINT32 shift = (PageType == gcvPAGE_TYPE_1M) ? gcdMMU_STLB_1M_SHIFT : gcdMMU_STLB_4K_SHIFT;
+        gctUINT32 masterOffset = index / num + area->mappingStart;
+        gctUINT32 slaveOffset = index % num;
+
+        address = (masterOffset << gcdMMU_MTLB_SHIFT)
+                | (slaveOffset << shift);
+    }
+
+    if (Address != gcvNULL)
+    {
+        *Address = address;
+    }
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+    /* Success. */
+    gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
+                   *PageTable, gcmOPT_VALUE(Address));
+    return gcvSTATUS_OK;
+
+OnError:
+
+    if (mutex)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckMMU_FreePages
+**
+**  Free pages inside the page table.
+**
+**  INPUT:
+**
+**      gckMMU Mmu
+**          Pointer to an gckMMU object.
+**
+**      gctPOINTER PageTable
+**          Base address of the page table to free.
+**
+**      gctSIZE_T PageCount
+**          Number of pages to free.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+_FreePages(
+    IN gckMMU Mmu,
+    IN gctBOOL Secure,
+    IN gcePAGE_TYPE PageType,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctSIZE_T PageCount
+    )
+{
+    gctUINT32 index;
+    gctUINT32_PTR node;
+    gceSTATUS status;
+    gctBOOL acquired = gcvFALSE;
+    gctUINT32 pageCount;
+    gcuQUEUEDATA data;
+    gcsADDRESS_AREA_PTR area = _GetProcessArea(Mmu, PageType, gcvFALSE);
+    gctUINT32 pageSize = (PageType == gcvPAGE_TYPE_1M)
+                       ? gcdMMU_PAGE_1M_SIZE : gcdMMU_PAGE_4K_SIZE;
+
+    gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu",
+                   Mmu, PageTable, PageCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+    gcmkSAFECASTSIZET(pageCount, PageCount);
+
+#if gcdBOUNDARY_CHECK
+    pageCount += gcdBOUNDARY_CHECK * 2;
+#endif
+
+    /* Get the node by index. */
+    index = (gctUINT32)((gctUINT32_PTR)PageTable - area->stlbLogical);
+
+    node = area->mapLogical + index;
+
+    if (pageCount != _GetPageCountOfUsedNode(node))
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+    }
+
+#if gcdBOUNDARY_CHECK
+    node -= gcdBOUNDARY_CHECK;
+#endif
+
+    gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (Mmu->hardware->mmuVersion == 0)
+    {
+        _FillPageTable(PageTable, pageCount, Mmu->safeAddress);
+    }
+
+    if (pageCount == 1)
+    {
+       /* Single page node. */
+        node[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
+
+        if (PageTable != gcvNULL)
+        {
+#if gcdUSE_MMU_EXCEPTION
+        /* Enable exception */
+        _WritePageEntry(PageTable, (1 << 1));
+#else
+        _WritePageEntry(PageTable, 0);
+#endif
+        }
+    }
+    else
+    {
+        /* Mark the node as free. */
+        node[0] = (pageCount << 8) | gcvMMU_FREE;
+        node[1] = ~0U;
+
+        if (PageTable != gcvNULL)
+        {
+#if gcdUSE_MMU_EXCEPTION
+            /* Enable exception */
+            gcmkVERIFY_OK(_FillPageTable(PageTable, (gctUINT32)PageCount, 1 << 1));
+#else
+            gcmkVERIFY_OK(_FillPageTable(PageTable, (gctUINT32)PageCount, 0));
+#endif
+        }
+    }
+
+    gcmkDUMP(Mmu->os,
+             "#[mmu-stlb: free 0x%08X - 0x%08X]",
+             Address, Address + pageCount * pageSize - 1);
+
+    gcmkDUMP(Mmu->os,
+             "@[physical.fill 0x%010llX 0x%08X 0x%08X]",
+             (unsigned long long)(area->stlbPhysical + index * 4),
+             *(gctUINT32_PTR)PageTable,
+             pageCount * 4);
+
+    /* We have free nodes. */
+    area->freeNodes = gcvTRUE;
+
+    /* Record freed address range. */
+    data.addressData.start = Address;
+    data.addressData.end = Address + (gctUINT32)PageCount * pageSize;
+    gckQUEUE_Enqueue(&Mmu->recentFreedAddresses, &data);
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+    acquired = gcvFALSE;
+
+#if gcdENABLE_TRUST_APPLICATION
+    if (Mmu->hardware->options.secureMode == gcvSECURE_IN_TA)
+    {
+        gckKERNEL_SecurityUnmapMemory(Mmu->hardware->kernel, Address, (gctUINT32)PageCount);
+    }
+#endif
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMMU_AllocatePages(
+    IN gckMMU Mmu,
+    IN gctSIZE_T PageCount,
+    IN gcePAGE_TYPE PageType,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    )
+{
+    return gckMMU_AllocatePagesEx(
+                Mmu, PageCount, gcvVIDMEM_TYPE_GENERIC, PageType, gcvFALSE, PageTable, Address);
+}
+
+gceSTATUS
+gckMMU_AllocatePagesEx(
+    IN gckMMU Mmu,
+    IN gctSIZE_T PageCount,
+    IN gceVIDMEM_TYPE Type,
+    IN gcePAGE_TYPE PageType,
+    IN gctBOOL Secure,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    )
+{
+#if gcdDISABLE_GPU_VIRTUAL_ADDRESS
+    gcmkPRINT("GPU virtual address is disabled.");
+    return gcvSTATUS_NOT_SUPPORTED;
+#else
+    return _AllocatePages(Mmu, PageCount, Type, PageType, Secure, PageTable, Address);
+#endif
+}
+
+gceSTATUS
+gckMMU_FreePages(
+    IN gckMMU Mmu,
+    IN gctBOOL Secure,
+    IN gcePAGE_TYPE PageType,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctSIZE_T PageCount
+    )
+{
+    return _FreePages(Mmu, Secure, PageType, Address, PageTable, PageCount);
+}
+
+gceSTATUS
+gckMMU_SetPage(
+    IN gckMMU Mmu,
+    IN gctPHYS_ADDR_T PageAddress,
+    IN gcePAGE_TYPE PageType,
+    IN gctBOOL Writable,
+    IN gctUINT32 *PageEntry
+    )
+{
+    gctUINT32 addressExt;
+    gctUINT32 address;
+
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+
+    if (PageType == gcvPAGE_TYPE_1M)
+    {
+        gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFFFF));
+    }
+    else
+    {
+        gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+    }
+
+    /* [31:0]. */
+    address    = (gctUINT32)(PageAddress & 0xFFFFFFFF);
+    /* [39:32]. */
+    addressExt = (gctUINT32)((PageAddress >> 32) & 0xFF);
+
+    if (Mmu->hardware->mmuVersion == 0)
+    {
+        _WritePageEntry(PageEntry, address);
+    }
+    else
+    {
+        _WritePageEntry(PageEntry, _SetPage(address, addressExt, gcvTRUE));
+    }
+
+#ifdef DUMP_IN_KERNEL
+    {
+        gctUINT32 *stlbLogical = (PageType == gcvPAGE_TYPE_1M)
+                               ? Mmu->dynamicArea1M.stlbLogical
+                               : Mmu->dynamicArea4K.stlbLogical;
+
+        gctPHYS_ADDR_T stlbPhysical = (PageType == gcvPAGE_TYPE_1M)
+                                    ? Mmu->dynamicArea1M.stlbPhysical
+                                    : Mmu->dynamicArea4K.stlbPhysical;
+
+        gctPHYS_ADDR_T physical = stlbPhysical + (stlbLogical - PageEntry) * 4;
+
+        gckDUMP(Mmu->os, "@[physical.fill 0x%010llX 0x%08X 4",
+                physical, *PageEntry);
+    }
+#endif
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMMU_Flush(
+    IN gckMMU Mmu,
+    IN gceVIDMEM_TYPE Type
+    )
+{
+    gckHARDWARE hardware;
+    gctUINT32 mask;
+    gctINT i;
+
+    if (Type == gcvVIDMEM_TYPE_VERTEX_BUFFER ||
+        Type == gcvVIDMEM_TYPE_INDEX_BUFFER ||
+        Type == gcvVIDMEM_TYPE_COMMAND)
+    {
+        mask = gcvPAGE_TABLE_DIRTY_BIT_FE;
+    }
+    else
+    {
+        mask = gcvPAGE_TABLE_DIRTY_BIT_OTHER;
+    }
+
+#if gcdSHARED_PAGETABLE
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        gctUINT j;
+        hardware = sharedPageTable->hardwares[i];
+        if (hardware)
+        {
+            for (j = 0; j < gcvENGINE_GPU_ENGINE_COUNT; j++)
+            {
+                gcmkVERIFY_OK(gckOS_AtomSetMask(hardware->pageTableDirty[j], mask));
+            }
+        }
+    }
+#else
+    hardware = Mmu->hardware;
+
+    for (i = 0 ; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+    {
+        gcmkVERIFY_OK(
+            gckOS_AtomSetMask(hardware->pageTableDirty[i], mask));
+    }
+
+    {
+        gcsLISTHEAD_PTR hardwareHead;
+        gcmkLIST_FOR_EACH(hardwareHead, &Mmu->hardwareList)
+        {
+            hardware = gcmCONTAINEROF(hardwareHead, struct _gckHARDWARE, mmuHead);
+
+            if (hardware != Mmu->hardware)
+            {
+                for (i = 0 ; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+                {
+                    gcmkVERIFY_OK(
+                        gckOS_AtomSetMask(hardware->pageTableDirty[i], mask));
+                }
+            }
+        }
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMMU_DumpPageTableEntry(
+    IN gckMMU Mmu,
+    IN gceAREA_TYPE AreaType,
+    IN gctUINT32 Address
+    )
+{
+    gctUINT32_PTR pageTable;
+    gctUINT32 index;
+    gctUINT32 mtlb, stlb;
+    gcsADDRESS_AREA_PTR area = (AreaType == gcvAREA_TYPE_4K)
+                             ? &Mmu->dynamicArea4K : &Mmu->dynamicArea1M;
+
+    gctUINT32 stlbShift = (AreaType == gcvAREA_TYPE_4K)
+                        ? gcdMMU_STLB_4K_SHIFT : gcdMMU_STLB_1M_SHIFT;
+
+    gctUINT32 stlbMask  = (AreaType == gcvAREA_TYPE_4K)
+                        ? gcdMMU_STLB_4K_MASK : gcdMMU_STLB_1M_MASK;
+
+    gctUINT32 stlbEntryNum = (AreaType == gcvAREA_TYPE_4K)
+                           ? gcdMMU_STLB_4K_ENTRY_NUM : gcdMMU_STLB_1M_ENTRY_NUM;
+
+    gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address);
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+    gcmkASSERT(Mmu->hardware->mmuVersion > 0);
+
+    mtlb = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+
+    if (AreaType != gcvAREA_TYPE_FLATMAP)
+    {
+        stlb = (Address & stlbMask) >> stlbShift;
+
+        pageTable = area->stlbLogical;
+
+        index = (mtlb - area->mappingStart)
+              * stlbEntryNum
+              + stlb;
+
+        gcmkPRINT("    Page table entry = 0x%08X", _ReadPageEntry(pageTable + index));
+    }
+    else
+    {
+        gcsMMU_STLB_CHUNK_PTR stlbChunkObj = Mmu->staticSTLB;
+        gctUINT32 entry = Mmu->mtlbLogical[mtlb];
+
+        stlb = (Address & gcdMMU_STLB_1M_MASK) >> gcdMMU_STLB_1M_SHIFT;
+
+        entry &= 0xFFFFFFF0;
+
+        while (stlbChunkObj)
+        {
+            gctUINT i;
+            gctBOOL found = gcvFALSE;
+            for (i = 0; i < stlbChunkObj->mtlbEntryNum; ++i)
+            {
+                gctPHYS_ADDR_T stlbPhysBase = stlbChunkObj->physBase + (i * gcdMMU_STLB_1M_SIZE);
+                gctUINT32_PTR stlbLogical =
+                    (gctUINT32_PTR)((gctUINT8_PTR)stlbChunkObj->logical + (i * gcdMMU_STLB_1M_SIZE));
+                if (entry == stlbPhysBase)
+                {
+                    gcmkPRINT("    Page table entry = 0x%08X", stlbLogical[stlb]);
+                    found = gcvTRUE;
+                    break;
+                }
+            }
+            if (found)
+                break;
+            stlbChunkObj = stlbChunkObj->next;
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+void
+gckMMU_CheckSaftPage(
+    IN gckMMU Mmu
+    )
+{
+    gctUINT8_PTR safeLogical = Mmu->safePageLogical;
+    gctUINT32 offsets[] = {
+        0,
+        64,
+        128,
+        256,
+        2560,
+        4000
+    };
+
+    gctUINT32 i = 0;
+
+    while (i < gcmCOUNTOF(offsets))
+    {
+        if (safeLogical[offsets[i]] != 0)
+        {
+            gcmkPRINT("%s(%d) safe page is over written [%d] = %x",
+                      __FUNCTION__, __LINE__, i, safeLogical[offsets[i]]);
+        }
+    }
+}
+
+void
+gckMMU_DumpAddressSpace(
+    IN gckMMU Mmu
+    )
+{
+    gctUINT i;
+    gctUINT next;
+    /* TODO: */
+    gcsADDRESS_AREA_PTR area = &Mmu->dynamicArea4K;
+    gctUINT32_PTR map = area->mapLogical;
+    gctBOOL used = gcvFALSE;
+    gctUINT32 numPages;
+
+    /* Grab the mutex. */
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+
+    /* Find node which contains index. */
+    for (i = 0; i < area->stlbEntries; i = next)
+    {
+        switch (gcmENTRY_TYPE(map[i]))
+        {
+        case gcvMMU_SINGLE:
+            numPages = 1;
+            next = i + numPages;
+            used = gcvFALSE;
+            break;
+
+        case gcvMMU_FREE:
+            numPages = map[i] >> 8;
+            next = i + numPages;
+            used = gcvFALSE;
+            break;
+
+        case gcvMMU_USED:
+            numPages = 1;
+            next = i + numPages;
+            used = gcvTRUE;
+            break;
+
+        default:
+            gcmkFATAL("MMU table correcupted at index %u!", i);
+            return;
+        }
+
+        if (!used)
+        {
+            gcmkPRINT("Available Range [%d - %d)", i, i + numPages);
+        }
+    }
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+}
+
+void
+gckMMU_DumpRecentFreedAddress(
+    IN gckMMU Mmu
+    )
+{
+    gckQUEUE queue = &Mmu->recentFreedAddresses;
+    gctUINT32 i;
+    gcuQUEUEDATA *data;
+
+    if (queue->count)
+    {
+        gcmkPRINT("    Recent %d freed GPU address ranges:", queue->count);
+
+        for (i = 0; i < queue->count; i++)
+        {
+            gckQUEUE_GetData(queue, i, &data);
+
+            gcmkPRINT("      [%08X - %08X]", data->addressData.start, data->addressData.end);
+        }
+    }
+}
+
+gceSTATUS
+gckMMU_FillFlatMapping(
+    IN gckMMU Mmu,
+    IN gctUINT64 PhysBase,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status;
+    gckHARDWARE hardware = Mmu->hardware;
+
+    if (hardware->mmuVersion)
+    {
+        gcmkONERROR(_FillFlatMapping(Mmu, PhysBase, Size, gcvFALSE, gcvTRUE, gcvNULL));
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckMMU_IsFlatMapped(
+    IN gckMMU Mmu,
+    IN gctUINT64 Physical,
+    IN gctUINT32 Address,
+    OUT gctBOOL *In
+    )
+{
+    gceSTATUS status;
+    gctUINT32 i;
+    gctBOOL inFlatmapping = gcvFALSE;
+
+    gcmkHEADER();
+
+    gcmkVERIFY_ARGUMENT(In != gcvNULL);
+
+    if (gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_MMU) == gcvFALSE)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+    {
+        for (i = 0; i < Mmu->gpuPhysicalRangeCount; i++)
+        {
+            if ((Physical >= Mmu->gpuPhysicalRanges[i].start) &&
+                (Physical <= Mmu->gpuPhysicalRanges[i].end))
+            {
+                inFlatmapping = gcvTRUE;
+                break;
+            }
+        }
+    }
+
+    if (Address != gcvINVALID_ADDRESS)
+    {
+        for (i = 0; i < Mmu->gpuAddressRangeCount; i++)
+        {
+            if ((Address >= Mmu->gpuAddressRanges[i].start) &&
+                (Address <= Mmu->gpuAddressRanges[i].end))
+            {
+                inFlatmapping = gcvTRUE;
+                break;
+            }
+        }
+    }
+
+    *In = inFlatmapping;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckMMU_SetupSRAM(
+    IN gckMMU Mmu,
+    IN gckHARDWARE Hardware,
+    IN gckDEVICE Device
+    )
+{
+    gctBOOL needMapInternalSRAM = gcvFALSE;
+    gctPHYS_ADDR_T reservedBase = gcvINVALID_PHYSICAL_ADDRESS;
+    gctUINT32 reservedSize = 0;
+    gctUINT i = 0;
+    gctUINT j = 0;
+    gceSTATUS status;
+    gckKERNEL kernel = Hardware->kernel;
+
+    gcmkHEADER_ARG("Mmu=0x%x Hardware=0x%x", Mmu, Hardware);
+
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    if (Hardware->mmuVersion == 0)
+    {
+        gcmkONERROR(gcvSTATUS_OK);
+    }
+
+    if (!Mmu->sRAMMapped)
+    {
+        gctUINT32 address = gcvINVALID_ADDRESS;
+        gctUINT32 size    = 0;
+
+        /* Map all the SRAMs in MMU table. */
+        for (i = 0; i < gcvCORE_COUNT; i++)
+        {
+            for (j = gcvSRAM_INTERNAL0; j < gcvSRAM_INTER_COUNT; j++)
+            {
+                reservedBase = Device->sRAMBases[i][j];
+                reservedSize = Device->sRAMSizes[i][j];
+
+                Device->sRAMBaseAddresses[i][j] = 0;
+
+                needMapInternalSRAM = reservedSize && (reservedBase != gcvINVALID_PHYSICAL_ADDRESS);
+
+                /* Map the internal SRAM. */
+                if (needMapInternalSRAM)
+                {
+                    /*
+                     * Default gpu virtual base = 0.
+                     * It can be specified if not conflict with existing mapping.
+                     */
+                    gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(
+                        Mmu->os,
+                        reservedBase,
+                        &reservedBase
+                        ));
+
+                    gcmkONERROR(_FillFlatMapping(
+                        Mmu,
+                        reservedBase,
+                        reservedSize,
+                        gcvTRUE,
+                        gcvTRUE,
+                        &Device->sRAMBaseAddresses[i][j]
+                        ));
+
+                    Device->sRAMBases[i][j] = reservedBase;
+                }
+                else if (reservedSize && reservedBase == gcvINVALID_PHYSICAL_ADDRESS)
+                {
+                    /*
+                     * Reserve the internal SRAM range in first reserved MMU mtlb,
+                     * when CPU physical base address is not specified, which means it is reserve usage.
+                     */
+                    Device->sRAMBaseAddresses[i][j] = (address == gcvINVALID_ADDRESS) ? gcdRESERVE_START :
+                                                      address + gcmALIGN(size, gcdRESERVE_ALIGN);
+
+                    Device->sRAMBases[i][j] = address = Device->sRAMBaseAddresses[i][j];
+
+                    size = Device->sRAMSizes[i][j];
+
+                    Device->sRAMPhysFaked[i][j] = gcvTRUE;
+                }
+
+#if gcdCAPTURE_ONLY_MODE
+                Device->sRAMPhysFaked[i][j] = gcvTRUE;
+#endif
+            }
+        }
+
+        /* Map all the external SRAMs in MMU table. */
+        for (i = gcvSRAM_EXTERNAL0; i < gcvSRAM_EXT_COUNT; i++)
+        {
+            if (Device->extSRAMSizes[i] &&
+               (Device->extSRAMBases[i] != gcvINVALID_PHYSICAL_ADDRESS))
+            {
+
+                Device->extSRAMBaseAddresses[i] = 0;
+
+                gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(
+                    Mmu->os,
+                    Device->extSRAMBases[i],
+                    &Device->extSRAMGPUBases[i]
+                    ));
+
+                gcmkONERROR(_FillFlatMapping(
+                    Mmu,
+                    Device->extSRAMGPUBases[i],
+                    Device->extSRAMSizes[i],
+                    gcvFALSE,
+                    gcvTRUE,
+                    &Device->extSRAMBaseAddresses[i]
+                    ));
+
+                Device->extSRAMGPUPhysNames[i] = gckKERNEL_AllocateNameFromPointer(kernel, Device->extSRAMPhysical[i]);
+            }
+        }
+        Mmu->sRAMMapped = gcvTRUE;
+    }
+
+    /* Get per core SRAM hardware base address. */
+    for (i = gcvSRAM_INTERNAL0; i < gcvSRAM_INTER_COUNT; i++)
+    {
+        if (Device->sRAMSizes[Hardware->core][i] &&
+           (Device->sRAMBaseAddresses[Hardware->core][i]))
+        {
+            kernel->sRAMBaseAddresses[i] = Device->sRAMBaseAddresses[Hardware->core][i];
+            kernel->sRAMSizes[i] = Hardware->options.sRAMSizes[i]
+                                 = Device->sRAMSizes[Hardware->core][i];
+
+            kernel->sRAMPhysFaked[i] = Device->sRAMPhysFaked[Hardware->core][i];
+            Hardware->options.sRAMGPUVirtAddrs[i] = Device->sRAMBaseAddresses[Hardware->core][i];
+
+            /* If the internal SRAM usage is reserve. */
+            if (kernel->sRAMPhysFaked[i])
+            {
+                /* Use virtual address as the faked physical address which will never be accessed. */
+                status = gckVIDMEM_Construct(
+                    Mmu->os,
+                    (gctPHYS_ADDR_T)kernel->sRAMBaseAddresses[i],
+                    kernel->sRAMSizes[i],
+                    64,
+                    0,
+                    &kernel->sRAMVidMem[i]
+                    );
+
+                if (gcmIS_ERROR(status))
+                {
+                    kernel->sRAMSizes[i] = 0;
+                    kernel->sRAMVidMem[i] = gcvNULL;
+                }
+                else
+                {
+                    gcmkONERROR(gckOS_RequestReservedMemory(
+                        Mmu->os,
+                        (gctPHYS_ADDR_T)kernel->sRAMBaseAddresses[i],
+                        kernel->sRAMSizes[i],
+                        "Per core SRAM reserve usage region",
+                        gcvTRUE,
+                        &kernel->sRAMPhysical[i]
+                        ));
+
+                    kernel->sRAMVidMem[i]->physical = kernel->sRAMPhysical[i];
+                }
+            }
+
+            if (Device->showSRAMMapInfo)
+            {
+                gcmkPRINT("Galcore Info: MMU mapped core %d SRAM[%d] hardware virtual address=0x%x size=0x%x",
+                    Hardware->core,
+                    i,
+                    kernel->sRAMBaseAddresses[i],
+                    kernel->sRAMSizes[i]
+                    );
+            }
+        }
+    }
+
+    for (i = gcvSRAM_EXTERNAL0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        if (Device->extSRAMSizes[i] &&
+            (Device->extSRAMBases[i] != gcvINVALID_PHYSICAL_ADDRESS))
+        {
+            kernel->extSRAMBaseAddresses[i] = Device->extSRAMBaseAddresses[i];
+
+            Hardware->options.extSRAMGPUVirtAddrs[i] = Device->extSRAMBaseAddresses[i];
+            Hardware->options.extSRAMSizes[i] = Device->extSRAMSizes[i];
+            Hardware->options.extSRAMGPUPhysAddrs[i] = Device->extSRAMBases[i];
+            Hardware->options.extSRAMGPUPhysNames[i] = Device->extSRAMGPUPhysNames[i];
+
+            if (Device->showSRAMMapInfo)
+            {
+                gcmkPRINT("Galcore Info: MMU mapped external shared SRAM[%d] CPU base=0x%llx GPU virtual address=0x%x size=0x%x",
+                    i,
+                    Device->extSRAMBases[i],
+                    kernel->extSRAMBaseAddresses[i],
+                    Device->extSRAMSizes[i]
+                    );
+            }
+        }
+    }
+
+    gcsLIST_Add(&Hardware->mmuHead, &Mmu->hardwareList);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the error. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+gckMMU_GetPageEntry(
+    IN gckMMU Mmu,
+    IN gcePAGE_TYPE PageType,
+    IN gctUINT32 Address,
+    IN gctUINT32_PTR *PageTable
+    )
+{
+    gctUINT32_PTR pageTable;
+    gctUINT32 index;
+    gctUINT32 mtlbOffset, stlbOffset;
+    gcsADDRESS_AREA_PTR area = _GetProcessArea(Mmu, PageType, gcvFALSE);
+
+    gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address);
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+    gcmkASSERT(Mmu->hardware->mmuVersion > 0);
+
+    mtlbOffset = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+
+    if (mtlbOffset >= area->mappingStart)
+    {
+        gctUINT32 stlbShift = (PageType == gcvPAGE_TYPE_1M) ? gcdMMU_STLB_1M_SHIFT : gcdMMU_STLB_4K_SHIFT;
+        gctUINT32 stlbMask  = (PageType == gcvPAGE_TYPE_1M) ? gcdMMU_STLB_1M_MASK : gcdMMU_STLB_4K_MASK;
+        gctUINT32 stlbEntryNum = (PageType == gcvPAGE_TYPE_1M) ? gcdMMU_STLB_1M_ENTRY_NUM : gcdMMU_STLB_4K_ENTRY_NUM;
+
+        stlbOffset = (Address & stlbMask) >> stlbShift;
+
+        pageTable = area->stlbLogical;
+
+        index = (mtlbOffset - area->mappingStart) * stlbEntryNum + stlbOffset;
+
+        *PageTable = pageTable + index;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMMU_GetAreaType(
+    IN gckMMU Mmu,
+    IN gctUINT32 GpuAddress,
+    OUT gceAREA_TYPE *AreaType
+    )
+{
+    gctUINT32 mtlbIndex;
+    gctBOOL flatMapped;
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsADDRESS_AREA_PTR area4K = &Mmu->dynamicArea4K;
+#if gcdENABLE_GPU_1M_PAGE
+    gcsADDRESS_AREA_PTR area1M = &Mmu->dynamicArea1M;
+#endif
+
+    mtlbIndex = _MtlbOffset(GpuAddress);
+
+    gcmkONERROR(gckMMU_IsFlatMapped(Mmu, gcvINVALID_PHYSICAL_ADDRESS, GpuAddress, &flatMapped));
+
+    if (flatMapped)
+    {
+        *AreaType = gcvAREA_TYPE_FLATMAP;
+    }
+#if gcdENABLE_GPU_1M_PAGE
+    else if (mtlbIndex >= area1M->mappingStart && mtlbIndex <= area1M->mappingEnd)
+    {
+        *AreaType = gcvAREA_TYPE_1M;
+    }
+#endif
+    else if (mtlbIndex >= area4K->mappingStart && mtlbIndex <= area4K->mappingEnd)
+    {
+        *AreaType = gcvAREA_TYPE_4K;
+    }
+    else
+    {
+        *AreaType = gcvAREA_TYPE_UNKNOWN;
+    }
+
+OnError:
+    return status;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c
@@ -0,0 +1,557 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE    gcvZONE_MMU
+
+/*******************************************************************************
+**
+**  gckVGMMU_Construct
+**
+**  Construct a new gckVGMMU object.
+**
+**  INPUT:
+**
+**      gckVGKERNEL Kernel
+**          Pointer to an gckVGKERNEL object.
+**
+**      gctSIZE_T MmuSize
+**          Number of bytes for the page table.
+**
+**  OUTPUT:
+**
+**      gckVGMMU * Mmu
+**          Pointer to a variable that receives the gckVGMMU object pointer.
+*/
+gceSTATUS gckVGMMU_Construct(
+    IN gckVGKERNEL Kernel,
+    IN gctUINT32 MmuSize,
+    OUT gckVGMMU * Mmu
+    )
+{
+    gckOS os;
+    gckVGHARDWARE hardware;
+    gceSTATUS status;
+    gckVGMMU mmu;
+    gctUINT32 * pageTable;
+    gctUINT32 i;
+
+    gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(MmuSize > 0);
+    gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
+
+    /* Extract the gckOS object pointer. */
+    os = Kernel->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Extract the gckVGHARDWARE object pointer. */
+    hardware = Kernel->hardware;
+    gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+    /* Allocate memory for the gckVGMMU object. */
+    status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu);
+
+    if (status < 0)
+    {
+        /* Error. */
+        gcmkFATAL(
+            "%s(%d): could not allocate gckVGMMU object.",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkFOOTER();
+        return status;
+    }
+
+    /* Initialize the gckVGMMU object. */
+    mmu->object.type = gcvOBJ_MMU;
+    mmu->os = os;
+    mmu->hardware = hardware;
+
+    /* Create the mutex. */
+    status = gckOS_CreateMutex(os, &mmu->mutex);
+
+    if (status < 0)
+    {
+        /* Roll back. */
+        mmu->object.type = gcvOBJ_UNKNOWN;
+        gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+        gcmkFOOTER();
+        /* Error. */
+        return status;
+    }
+
+    /* Allocate the page table. */
+    mmu->pageTableSize = (gctUINT32)MmuSize;
+    status = gckOS_AllocateNonPagedMemory(os,
+                                          gcvFALSE,
+                                          gcvALLOC_FLAG_CONTIGUOUS,
+                                          &mmu->pageTableSize,
+                                          &mmu->pageTablePhysical,
+                                          &mmu->pageTableLogical);
+
+    if (status < 0)
+    {
+        /* Roll back. */
+        gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
+
+        mmu->object.type = gcvOBJ_UNKNOWN;
+        gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+        /* Error. */
+        gcmkFATAL(
+            "%s(%d): could not allocate page table.",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkFOOTER();
+        return status;
+    }
+
+    /* Compute number of entries in page table. */
+    mmu->entryCount = (gctUINT32)mmu->pageTableSize / sizeof(gctUINT32);
+    mmu->entry = 0;
+
+    /* Mark the entire page table as available. */
+    pageTable = (gctUINT32 *) mmu->pageTableLogical;
+    for (i = 0; i < mmu->entryCount; i++)
+    {
+        pageTable[i] = (gctUINT32)~0;
+    }
+
+    /* Set page table address. */
+    status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical);
+
+    if (status < 0)
+    {
+        /* Free the page table. */
+        gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(mmu->os,
+                                               mmu->pageTablePhysical,
+                                               mmu->pageTableLogical,
+                                               mmu->pageTableSize));
+
+        /* Roll back. */
+        gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
+
+        mmu->object.type = gcvOBJ_UNKNOWN;
+        gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+        /* Error. */
+        gcmkFATAL(
+            "%s(%d): could not program page table.",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkFOOTER();
+        return status;
+    }
+
+    /* Return the gckVGMMU object pointer. */
+    *Mmu = mmu;
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_MMU,
+        "%s(%d): %u entries at %p.(0x%08X)\n",
+        __FUNCTION__, __LINE__,
+        mmu->entryCount,
+        mmu->pageTableLogical,
+        mmu->pageTablePhysical
+        );
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGMMU_Destroy
+**
+**  Destroy a nAQMMU object.
+**
+**  INPUT:
+**
+**      gckVGMMU Mmu
+**          Pointer to an gckVGMMU object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckVGMMU_Destroy(
+    IN gckVGMMU Mmu
+    )
+{
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+    /* Free the page table. */
+    gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(Mmu->os,
+                                           Mmu->pageTablePhysical,
+                                           Mmu->pageTableLogical,
+                                           Mmu->pageTableSize));
+
+    /* Roll back. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex));
+
+    /* Mark the gckVGMMU object as unknown. */
+    Mmu->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckVGMMU object. */
+    gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu));
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVGMMU_AllocatePages
+**
+**  Allocate pages inside the page table.
+**
+**  INPUT:
+**
+**      gckVGMMU Mmu
+**          Pointer to an gckVGMMU object.
+**
+**      gctSIZE_T PageCount
+**          Number of pages to allocate.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * PageTable
+**          Pointer to a variable that receives the base address of the page
+**          table.
+**
+**      gctUINT32 * Address
+**          Pointer to a variable that receives the hardware specific address.
+*/
+gceSTATUS gckVGMMU_AllocatePages(
+    IN gckVGMMU Mmu,
+    IN gctSIZE_T PageCount,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status;
+    gctUINT32 tail, index, i;
+    gctUINT32 * table;
+    gctBOOL allocated = gcvFALSE;
+
+    gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
+        Mmu, PageCount, PageTable, Address);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_MMU,
+        "%s(%d): %u pages.\n",
+        __FUNCTION__, __LINE__,
+        PageCount
+        );
+
+    if (PageCount > Mmu->entryCount)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_MMU,
+            "%s(%d): page table too small for %u pages.\n",
+            __FUNCTION__, __LINE__,
+            PageCount
+            );
+
+        gcmkFOOTER_NO();
+        /* Not enough pages avaiable. */
+        return gcvSTATUS_OUT_OF_RESOURCES;
+    }
+
+    /* Grab the mutex. */
+    status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE);
+
+    if (status < 0)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_MMU,
+            "%s(%d): could not acquire mutex.\n"
+            ,__FUNCTION__, __LINE__
+            );
+
+        gcmkFOOTER();
+        /* Error. */
+        return status;
+    }
+
+    /* Compute the tail for this allocation. */
+    tail = Mmu->entryCount - (gctUINT32)PageCount;
+
+    /* Walk all entries until we find enough slots. */
+    for (index = Mmu->entry; index <= tail;)
+    {
+        /* Access page table. */
+        table = (gctUINT32 *) Mmu->pageTableLogical + index;
+
+        /* See if all slots are available. */
+        for (i = 0; i < PageCount; i++, table++)
+        {
+            if (*table != ~0)
+            {
+                /* Start from next slot. */
+                index += i + 1;
+                break;
+            }
+        }
+
+        if (i == PageCount)
+        {
+            /* Bail out if we have enough page entries. */
+            allocated = gcvTRUE;
+            break;
+        }
+    }
+
+    if (!allocated)
+    {
+        if (status >= 0)
+        {
+            /* Walk all entries until we find enough slots. */
+            for (index = 0; index <= tail;)
+            {
+                /* Access page table. */
+                table = (gctUINT32 *) Mmu->pageTableLogical + index;
+
+                /* See if all slots are available. */
+                for (i = 0; i < PageCount; i++, table++)
+                {
+                    if (*table != ~0)
+                    {
+                        /* Start from next slot. */
+                        index += i + 1;
+                        break;
+                    }
+                }
+
+                if (i == PageCount)
+                {
+                    /* Bail out if we have enough page entries. */
+                    allocated = gcvTRUE;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!allocated && (status >= 0))
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_MMU,
+            "%s(%d): not enough free pages for %u pages.\n",
+            __FUNCTION__, __LINE__,
+            PageCount
+            );
+
+        /* Not enough empty slots available. */
+        status = gcvSTATUS_OUT_OF_RESOURCES;
+    }
+
+    if (status >= 0)
+    {
+        /* Build virtual address. */
+        status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware,
+                                                 index,
+                                                 0,
+                                                 Address);
+
+        if (status >= 0)
+        {
+            /* Update current entry into page table. */
+            Mmu->entry = index + (gctUINT32)PageCount;
+
+            /* Return pointer to page table. */
+            *PageTable = (gctUINT32 *)  Mmu->pageTableLogical + index;
+
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_MMU,
+                "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
+                __FUNCTION__, __LINE__,
+                PageCount,
+                index,
+                *Address,
+                *PageTable
+                );
+            }
+    }
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex));
+    gcmkFOOTER();
+
+    /* Return status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGMMU_FreePages
+**
+**  Free pages inside the page table.
+**
+**  INPUT:
+**
+**      gckVGMMU Mmu
+**          Pointer to an gckVGMMU object.
+**
+**      gctPOINTER PageTable
+**          Base address of the page table to free.
+**
+**      gctSIZE_T PageCount
+**          Number of pages to free.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckVGMMU_FreePages(
+    IN gckVGMMU Mmu,
+    IN gctPOINTER PageTable,
+    IN gctSIZE_T PageCount
+    )
+{
+    gctUINT32 * table;
+
+    gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
+        Mmu, PageTable, PageCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_MMU,
+        "%s(%d): freeing %u pages at index %u @ %p.\n",
+        __FUNCTION__, __LINE__,
+        PageCount,
+        ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical),
+        PageTable
+        );
+
+    /* Convert pointer. */
+    table = (gctUINT32 *) PageTable;
+
+    /* Mark the page table entries as available. */
+    while (PageCount-- > 0)
+    {
+        *table++ = (gctUINT32)~0;
+    }
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGMMU_SetPage(
+    IN gckVGMMU Mmu,
+    IN gctUINT32 PageAddress,
+    IN gctUINT32 *PageEntry
+    )
+{
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+    gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+    gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+    *PageEntry = PageAddress;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGMMU_Flush(
+   IN gckVGMMU Mmu
+   )
+{
+    gckVGHARDWARE hardware;
+
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    hardware = Mmu->hardware;
+    gcmkVERIFY_OK(
+        gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+#endif /* gcdENABLE_VG */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c
@@ -0,0 +1,381 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_POWER
+
+/******************************************************************************\
+************************ Dynamic Voltage Frequency Setting *********************
+\******************************************************************************/
+#if gcdDVFS
+static gctUINT32
+_GetLoadHistory(
+    IN gckDVFS Dvfs,
+    IN gctUINT32 Select,
+    IN gctUINT32 Index
+)
+{
+    return Dvfs->loads[Index];
+}
+
+static void
+_IncreaseScale(
+    IN gckDVFS Dvfs,
+    IN gctUINT32 Load,
+    OUT gctUINT8 *Scale
+    )
+{
+    if (Dvfs->currentScale < 32)
+    {
+        *Scale = Dvfs->currentScale + 8;
+    }
+    else
+    {
+        *Scale = Dvfs->currentScale + 8;
+        *Scale = gcmMIN(64, *Scale);
+    }
+}
+
+static void
+_RecordFrequencyHistory(
+    gckDVFS Dvfs,
+    gctUINT32 Frequency
+    )
+{
+    gctUINT32 i = 0;
+
+    struct _FrequencyHistory *history = Dvfs->frequencyHistory;
+
+    for (i = 0; i < 16; i++)
+    {
+        if (history->frequency == Frequency)
+        {
+            break;
+        }
+
+        if (history->frequency == 0)
+        {
+            history->frequency = Frequency;
+            break;
+        }
+
+        history++;
+    }
+
+    if (i < 16)
+    {
+        history->count++;
+    }
+}
+
+static gctUINT32
+_GetFrequencyHistory(
+    gckDVFS Dvfs,
+    gctUINT32 Frequency
+    )
+{
+    gctUINT32 i = 0;
+
+    struct _FrequencyHistory * history = Dvfs->frequencyHistory;
+
+    for (i = 0; i < 16; i++)
+    {
+        if (history->frequency == Frequency)
+        {
+            break;
+        }
+
+        history++;
+    }
+
+    if (i < 16)
+    {
+        return history->count;
+    }
+
+    return 0;
+}
+
+static void
+_Policy(
+    IN gckDVFS Dvfs,
+    IN gctUINT32 Load,
+    OUT gctUINT8 *Scale
+    )
+{
+    gctUINT8 load[4], nextLoad;
+    gctUINT8 scale;
+
+    /* Last 4 history. */
+    load[0] = (Load & 0xFF);
+    load[1] = (Load & 0xFF00) >> 8;
+    load[2] = (Load & 0xFF0000) >> 16;
+    load[3] = (Load & 0xFF000000) >> 24;
+
+    /* Determine target scale. */
+    if (load[0] > 54)
+    {
+        _IncreaseScale(Dvfs, Load, &scale);
+    }
+    else
+    {
+        nextLoad = (load[0] + load[1] + load[2] + load[3])/4;
+
+        scale = Dvfs->currentScale * (nextLoad) / 54;
+
+        scale = gcmMAX(1, scale);
+        scale = gcmMIN(64, scale);
+    }
+
+    Dvfs->totalConfig++;
+
+    Dvfs->loads[(load[0]-1)/8]++;
+
+    *Scale = scale;
+
+
+    if (Dvfs->totalConfig % 100 == 0)
+    {
+        gcmkPRINT("=======================================================");
+        gcmkPRINT("GPU Load:       %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
+                                   8, 16, 24, 32, 40, 48, 56, 64);
+        gcmkPRINT("                %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
+                  _GetLoadHistory(Dvfs,2, 0),
+                  _GetLoadHistory(Dvfs,2, 1),
+                  _GetLoadHistory(Dvfs,2, 2),
+                  _GetLoadHistory(Dvfs,2, 3),
+                  _GetLoadHistory(Dvfs,2, 4),
+                  _GetLoadHistory(Dvfs,2, 5),
+                  _GetLoadHistory(Dvfs,2, 6),
+                  _GetLoadHistory(Dvfs,2, 7)
+                  );
+
+        gcmkPRINT("Frequency(MHz)  %-8d %-8d %-8d %-8d %-8d",
+                  58, 120, 240, 360, 480);
+        gcmkPRINT("                %-8d %-8d %-8d %-8d %-8d",
+                  _GetFrequencyHistory(Dvfs, 58),
+                  _GetFrequencyHistory(Dvfs,120),
+                  _GetFrequencyHistory(Dvfs,240),
+                  _GetFrequencyHistory(Dvfs,360),
+                  _GetFrequencyHistory(Dvfs,480)
+                  );
+    }
+}
+
+static void
+_TimerFunction(
+    gctPOINTER Data
+    )
+{
+    gceSTATUS status;
+    gckDVFS dvfs = (gckDVFS) Data;
+    gckHARDWARE hardware = dvfs->hardware;
+    gctUINT32 value;
+    gctUINT32 frequency;
+    gctUINT8 scale;
+    gctUINT32 t1, t2, consumed;
+
+    gckOS_GetTicks(&t1);
+
+    gcmkONERROR(gckHARDWARE_QueryLoad(hardware, &value));
+
+    /* determine target sacle. */
+    _Policy(dvfs, value, &scale);
+
+    /* Set frequency and voltage. */
+    gcmkONERROR(gckOS_SetGPUFrequency(hardware->os, hardware->core, scale));
+
+    /* Query real frequency. */
+    gcmkONERROR(
+        gckOS_QueryGPUFrequency(hardware->os,
+                                hardware->core,
+                                &frequency,
+                                &dvfs->currentScale));
+
+    _RecordFrequencyHistory(dvfs, frequency);
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_POWER,
+                   "Current frequency = %d",
+                   frequency);
+
+    /* Set period. */
+    gcmkONERROR(gckHARDWARE_SetDVFSPeroid(hardware, frequency));
+
+OnError:
+    /* Determine next querying time. */
+    gckOS_GetTicks(&t2);
+
+    consumed = gcmMIN(((long)t2 - (long)t1), 5);
+
+    if (dvfs->stop == gcvFALSE)
+    {
+        gcmkVERIFY_OK(gckOS_StartTimer(hardware->os,
+                                       dvfs->timer,
+                                       dvfs->pollingTime - consumed));
+    }
+
+    return;
+}
+
+gceSTATUS
+gckDVFS_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckDVFS * Dvfs
+    )
+{
+    gceSTATUS status;
+    gctPOINTER pointer;
+    gckDVFS dvfs = gcvNULL;
+    gckOS os = Hardware->os;
+
+    gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+    gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+    /* Allocate a gckDVFS manager. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer));
+
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS));
+
+    dvfs = pointer;
+
+    /* Initialization. */
+    dvfs->hardware = Hardware;
+    dvfs->pollingTime = gcdDVFS_POLLING_TIME;
+    dvfs->os = Hardware->os;
+    dvfs->currentScale = 64;
+
+    /* Create a polling timer. */
+    gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer));
+
+    /* Initialize frequency and voltage adjustment helper. */
+    gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core));
+
+    /* Return result. */
+    *Dvfs = dvfs;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (dvfs)
+    {
+        if (dvfs->timer)
+        {
+            gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer));
+        }
+
+        gcmkOS_SAFE_FREE(os, dvfs);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckDVFS_Destroy(
+    IN gckDVFS Dvfs
+    )
+{
+    gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+    gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+    /* Deinitialize helper fuunction. */
+    gcmkVERIFY_OK(gckOS_FinishGPUFrequency(Dvfs->os, Dvfs->hardware->core));
+
+    /* DestroyTimer. */
+    gcmkVERIFY_OK(gckOS_DestroyTimer(Dvfs->os, Dvfs->timer));
+
+    gcmkOS_SAFE_FREE(Dvfs->os, Dvfs);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDVFS_Start(
+    IN gckDVFS Dvfs
+    )
+{
+    gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+    gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+    gckHARDWARE_InitDVFS(Dvfs->hardware);
+
+    Dvfs->stop = gcvFALSE;
+
+    gckOS_StartTimer(Dvfs->os, Dvfs->timer, Dvfs->pollingTime);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDVFS_Stop(
+    IN gckDVFS Dvfs
+    )
+{
+    gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+    gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+    Dvfs->stop = gcvTRUE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_precomp_h_
+#define __gc_hal_kernel_precomp_h_
+
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel.h"
+
+#endif /* __gc_hal_kernel_precomp_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c
@@ -0,0 +1,286 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+
+
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+#if gcdSECURITY
+
+/*
+** Open a security service channel.
+*/
+gceSTATUS
+gckKERNEL_SecurityOpen(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPU,
+    OUT gctUINT32 *Channel
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_OpenSecurityChannel(Kernel->os, Kernel->core, Channel));
+    gcmkONERROR(gckOS_InitSecurityChannel(*Channel));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+    IN gctUINT32 Channel
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+    IN gctUINT32 Channel,
+    IN OUT gcsTA_INTERFACE * Interface
+)
+{
+    gceSTATUS status;
+    gcmkHEADER();
+
+    gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+    gckOS_CallSecurityService(Channel, Interface);
+
+    status = Interface->result;
+
+    gcmkONERROR(status);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+    IN gckKERNEL Kernel
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_START_COMMAND;
+    iface.u.StartCommand.gpu = Kernel->core;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Bytes,
+    OUT gctUINT32 * Handle
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_ALLOCATE_SECRUE_MEMORY;
+    iface.u.AllocateSecurityMemory.bytes = Bytes;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    *Handle = iface.u.AllocateSecurityMemory.memory_handle;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityExecute(
+    IN gckKERNEL Kernel,
+    IN gctPOINTER Buffer,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status;
+#if defined(LINUX)
+    gctPHYS_ADDR_T physical;
+    gctUINT32 address;
+#endif
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_EXECUTE;
+    iface.u.Execute.command_buffer = (gctUINT32 *)Buffer;
+    iface.u.Execute.gpu = Kernel->core;
+    iface.u.Execute.command_buffer_length = Bytes;
+
+#if defined(LINUX)
+    gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, Buffer, &physical));
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Kernel->os, physical, &physical));
+    gcmkSAFECASTPHYSADDRT(address, physical);
+
+    iface.u.Execute.command_buffer = (gctUINT32 *)address;
+#endif
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    /* Update queue tail pointer. */
+    gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+        Kernel->hardware, 0, 0
+        ));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 *PhysicalArray,
+    IN gctUINT32 PageCount,
+    OUT gctUINT32 * GPUAddress
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+#if defined(LINUX)
+    gctPHYS_ADDR_T physical;
+    gctUINT32 address;
+#endif
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_MAP_MEMORY;
+
+#if defined(LINUX)
+    gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, PhysicalArray, &physical));
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Kernel->os, physical, &physical));
+    gcmkSAFECASTPHYSADDRT(address, physical);
+    iface.u.MapMemory.physicals = (gctUINT32 *)address;
+#endif
+
+    iface.u.MapMemory.pageCount = PageCount;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    *GPUAddress = iface.u.MapMemory.gpuAddress;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPUAddress,
+    IN gctUINT32 PageCount
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_UNMAP_MEMORY;
+
+    iface.u.UnmapMemory.gpuAddress = GPUAddress;
+    iface.u.UnmapMemory.pageCount  = PageCount;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c
@@ -0,0 +1,320 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+
+
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+#if gcdENABLE_TRUST_APPLICATION
+
+/*
+** Open a security service channel.
+*/
+gceSTATUS
+gckKERNEL_SecurityOpen(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPU,
+    OUT gctUINT32 *Channel
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_OpenSecurityChannel(Kernel->os, Kernel->core, Channel));
+    gcmkONERROR(gckOS_InitSecurityChannel(*Channel));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+    IN gctUINT32 Channel
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+    IN gctUINT32 Channel,
+    IN OUT gcsTA_INTERFACE * Interface
+)
+{
+    gceSTATUS status;
+    gcmkHEADER();
+
+    gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+    gckOS_CallSecurityService(Channel, Interface);
+
+    status = Interface->result;
+
+    gcmkONERROR(status);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_START_COMMAND;
+    iface.u.StartCommand.gpu = Kernel->core;
+    iface.u.StartCommand.address = Address;
+    iface.u.StartCommand.bytes = Bytes;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Bytes,
+    OUT gctUINT32 * Handle
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_ALLOCATE_SECRUE_MEMORY;
+    iface.u.AllocateSecurityMemory.bytes = Bytes;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    *Handle = iface.u.AllocateSecurityMemory.memory_handle;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 *PhysicalArray,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 PageCount,
+    OUT gctUINT32 * GPUAddress
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_MAP_MEMORY;
+
+    iface.u.MapMemory.physicals = PhysicalArray;
+    iface.u.MapMemory.physical = Physical;
+    iface.u.MapMemory.pageCount = PageCount;
+    iface.u.MapMemory.gpuAddress = *GPUAddress;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityDumpMMUException(
+    IN gckKERNEL Kernel
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_DUMP_MMU_EXCEPTION;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 GPUAddress,
+    IN gctUINT32 PageCount
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_UNMAP_MEMORY;
+
+    iface.u.UnmapMemory.gpuAddress = GPUAddress;
+    iface.u.UnmapMemory.pageCount  = PageCount;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_ReadMMUException(
+    IN gckKERNEL Kernel,
+    IN gctUINT32_PTR MMUStatus,
+    IN gctUINT32_PTR MMUException
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_READ_MMU_EXCEPTION;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    *MMUStatus = iface.u.ReadMMUException.mmuStatus;
+    *MMUException = iface.u.ReadMMUException.mmuException;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckKERNEL_HandleMMUException(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 MMUStatus,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 GPUAddress
+    )
+{
+    gceSTATUS status;
+    gcsTA_INTERFACE iface;
+
+    gcmkHEADER();
+
+    iface.command = KERNEL_HANDLE_MMU_EXCEPTION;
+
+    iface.u.HandleMMUException.mmuStatus = MMUStatus;
+    iface.u.HandleMMUException.physical = Physical;
+    iface.u.HandleMMUException.gpuAddress = GPUAddress;
+
+    gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+
+
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c
@@ -0,0 +1,514 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE            gcdZONE_VG
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckKERNEL_Construct
+**
+**  Construct a new gckKERNEL object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      IN gctPOINTER Context
+**          Pointer to a driver defined context.
+**
+**  OUTPUT:
+**
+**      gckKERNEL * Kernel
+**          Pointer to a variable that will hold the pointer to the gckKERNEL
+**          object.
+*/
+gceSTATUS gckVGKERNEL_Construct(
+    IN gckOS Os,
+    IN gctPOINTER Context,
+    IN gckKERNEL  inKernel,
+    OUT gckVGKERNEL * Kernel
+    )
+{
+    gceSTATUS status;
+    gckVGKERNEL kernel = gcvNULL;
+
+    gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+
+    do
+    {
+        /* Allocate the gckKERNEL object. */
+        gcmkERR_BREAK(gckOS_Allocate(
+            Os,
+            sizeof(struct _gckVGKERNEL),
+            (gctPOINTER *) &kernel
+            ));
+
+        /* Initialize the gckKERNEL object. */
+        kernel->object.type = gcvOBJ_KERNEL;
+        kernel->os          = Os;
+        kernel->context     = Context;
+        kernel->hardware    = gcvNULL;
+        kernel->interrupt   = gcvNULL;
+        kernel->command     = gcvNULL;
+        kernel->mmu         = gcvNULL;
+        kernel->kernel      = inKernel;
+
+        /* Construct the gckVGHARDWARE object. */
+        gcmkERR_BREAK(gckVGHARDWARE_Construct(
+            Os, &kernel->hardware
+            ));
+
+        /* Set pointer to gckKERNEL object in gckVGHARDWARE object. */
+        kernel->hardware->kernel = kernel;
+
+        /* Construct the gckVGINTERRUPT object. */
+        gcmkERR_BREAK(gckVGINTERRUPT_Construct(
+            kernel, &kernel->interrupt
+            ));
+
+        /* Construct the gckVGCOMMAND object. */
+        gcmkERR_BREAK(gckVGCOMMAND_Construct(
+            kernel, gcmKB2BYTES(8), gcmKB2BYTES(2), &kernel->command
+            ));
+
+        /* Construct the gckVGMMU object. */
+        gcmkERR_BREAK(gckVGMMU_Construct(
+            kernel, gcmKB2BYTES(gcdGC355_VGMMU_MEMORY_SIZE_KB), &kernel->mmu
+            ));
+
+        /* Return pointer to the gckKERNEL object. */
+        *Kernel = kernel;
+
+        gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel);
+        /* Success. */
+        return gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    /* Roll back. */
+    if (kernel != gcvNULL)
+    {
+        if (kernel->mmu != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckVGMMU_Destroy(kernel->mmu));
+        }
+
+        if (kernel->command != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckVGCOMMAND_Destroy(kernel->command));
+        }
+
+        if (kernel->interrupt != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckVGINTERRUPT_Destroy(kernel->interrupt));
+        }
+
+        if (kernel->hardware != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckVGHARDWARE_Destroy(kernel->hardware));
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(Os, kernel));
+    }
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_Destroy
+**
+**  Destroy an gckKERNEL object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckVGKERNEL_Destroy(
+    IN gckVGKERNEL Kernel
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    do
+    {
+        /* Destroy the gckVGMMU object. */
+        if (Kernel->mmu != gcvNULL)
+        {
+            gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu));
+            Kernel->mmu = gcvNULL;
+        }
+
+        /* Destroy the gckVGCOMMAND object. */
+        if (Kernel->command != gcvNULL)
+        {
+            gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command));
+            Kernel->command = gcvNULL;
+        }
+
+        /* Destroy the gckVGINTERRUPT object. */
+        if (Kernel->interrupt != gcvNULL)
+        {
+            gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt));
+            Kernel->interrupt = gcvNULL;
+        }
+
+        /* Destroy the gckVGHARDWARE object. */
+        if (Kernel->hardware != gcvNULL)
+        {
+            gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware));
+            Kernel->hardware = gcvNULL;
+        }
+
+        /* Mark the gckKERNEL object as unknown. */
+        Kernel->object.type = gcvOBJ_UNKNOWN;
+
+        /* Free the gckKERNEL object. */
+        gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel));
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+
+    /* Return status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVGKERNEL_Dispatch
+**
+**  Dispatch a command received from the user HAL layer.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that defines the command to
+**          be dispatched.
+**
+**  OUTPUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+**          returned.
+*/
+gceSTATUS gckVGKERNEL_Dispatch(
+    IN gckKERNEL Kernel,
+    IN OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gceSTATUS status;
+    gcsHAL_INTERFACE * kernelInterface = Interface;
+    gctUINT32 processID;
+    gctBOOL powerMutexAcquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%x Interface=0x%x ", Kernel, Interface);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+
+    /* Dispatch on command. */
+    switch (Interface->command)
+    {
+    case gcvHAL_QUERY_CHIP_IDENTITY:
+        /* Query chip identity. */
+        gcmkERR_BREAK(gckVGHARDWARE_QueryChipIdentity(
+            Kernel->vg->hardware,
+            &kernelInterface->u.QueryChipIdentity.chipModel,
+            &kernelInterface->u.QueryChipIdentity.chipRevision,
+            &kernelInterface->u.QueryChipIdentity.productID,
+            &kernelInterface->u.QueryChipIdentity.ecoID,
+            &kernelInterface->u.QueryChipIdentity.customerID,
+            &kernelInterface->u.QueryChipIdentity.chipFeatures,
+            &kernelInterface->u.QueryChipIdentity.chipMinorFeatures,
+            &kernelInterface->u.QueryChipIdentity.chipMinorFeatures2
+            ));
+        break;
+
+    case gcvHAL_QUERY_COMMAND_BUFFER:
+        /* Query command buffer information. */
+        gcmkERR_BREAK(gckKERNEL_QueryCommandBuffer(
+            Kernel,
+            &kernelInterface->u.QueryCommandBuffer.information
+            ));
+        break;
+
+    case gcvHAL_USER_SIGNAL:
+#if !USE_NEW_LINUX_SIGNAL
+        /* Dispatch depends on the user signal subcommands. */
+        switch(Interface->u.UserSignal.command)
+        {
+        case gcvUSER_SIGNAL_CREATE:
+            /* Create a signal used in the user space. */
+            gcmkERR_BREAK(
+                gckOS_CreateUserSignal(Kernel->os,
+                                       Interface->u.UserSignal.manualReset,
+                                       &Interface->u.UserSignal.id));
+
+            gcmkVERIFY_OK(
+                gckKERNEL_AddProcessDB(Kernel,
+                                       processID, gcvDB_SIGNAL,
+                                       gcmINT2PTR(Interface->u.UserSignal.id),
+                                       gcvNULL,
+                                       0));
+            break;
+
+        case gcvUSER_SIGNAL_DESTROY:
+            gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+                Kernel,
+                processID, gcvDB_SIGNAL,
+                gcmINT2PTR(Interface->u.UserSignal.id)));
+
+            /* Destroy the signal. */
+            gcmkERR_BREAK(
+                gckOS_DestroyUserSignal(Kernel->os,
+                                        Interface->u.UserSignal.id));
+
+            break;
+
+        case gcvUSER_SIGNAL_SIGNAL:
+            /* Signal the signal. */
+            gcmkERR_BREAK(
+                gckOS_SignalUserSignal(Kernel->os,
+                                       Interface->u.UserSignal.id,
+                                       Interface->u.UserSignal.state));
+            break;
+
+        case gcvUSER_SIGNAL_WAIT:
+            /* Wait on the signal. */
+            status = gckOS_WaitUserSignal(Kernel->os,
+                                          Interface->u.UserSignal.id,
+                                          Interface->u.UserSignal.wait);
+            break;
+
+        default:
+            /* Invalid user signal command. */
+            gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT);
+        }
+#endif
+        break;
+
+        case gcvHAL_READ_REGISTER:
+#if gcdREGISTER_READ_FROM_USER
+        {
+            gceCHIPPOWERSTATE power;
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->vg->hardware->powerMutex, gcvINFINITE));
+            powerMutexAcquired = gcvTRUE;
+            gcmkONERROR(gckVGHARDWARE_QueryPowerManagementState(Kernel->vg->hardware,
+                &power));
+            if (power == gcvPOWER_ON)
+            {
+                /* Read a register. */
+                gcmkONERROR(gckOS_ReadRegisterEx(
+                    Kernel->os,
+                    Kernel->core,
+                    Interface->u.ReadRegisterData.address,
+                    &Interface->u.ReadRegisterData.data));
+            }
+            else
+            {
+                /* Chip is in power-state. */
+                Interface->u.ReadRegisterData.data = 0;
+                status = gcvSTATUS_CHIP_NOT_READY;
+            }
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+            powerMutexAcquired = gcvFALSE;
+        }
+#else
+        /* No access from user land to read registers. */
+        Interface->u.ReadRegisterData.data = 0;
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+    case gcvHAL_WRITE_REGISTER:
+#if gcdREGISTER_WRITE_FROM_USER
+        {
+            gceCHIPPOWERSTATE power;
+            gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->vg->hardware->powerMutex, gcvINFINITE));
+            powerMutexAcquired = gcvTRUE;
+            gcmkONERROR(gckVGHARDWARE_QueryPowerManagementState(Kernel->vg->hardware,
+                &power));
+            if (power == gcvPOWER_ON)
+            {
+                /* Write a register. */
+                gcmkONERROR(
+                    gckOS_WriteRegisterEx(Kernel->os,
+                    Kernel->core,
+                    Interface->u.WriteRegisterData.address,
+                    Interface->u.WriteRegisterData.data));
+            }
+            else
+            {
+                /* Chip is in power-state. */
+                Interface->u.WriteRegisterData.data = 0;
+                status = gcvSTATUS_CHIP_NOT_READY;
+            }
+            gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+            powerMutexAcquired = gcvFALSE;
+        }
+#else
+        /* No access from user land to write registers. */
+        status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+        break;
+
+    case gcvHAL_COMMIT:
+        /* Commit a command and context buffer. */
+        gcmkERR_BREAK(gckVGCOMMAND_Commit(
+            Kernel->vg->command,
+            gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.context),
+            gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.queue),
+            kernelInterface->u.VGCommit.entryCount,
+            gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.taskTable)
+            ));
+        break;
+
+    case gcvHAL_GET_BASE_ADDRESS:
+       /* Get base address. */
+        gcmkONERROR(
+            gckOS_GetBaseAddress(Kernel->os,
+                                 &Interface->u.GetBaseAddress.baseAddress));
+        break;
+
+    case gcvHAL_EVENT_COMMIT:
+        gcmkERR_BREAK(gcvSTATUS_NOT_SUPPORTED);
+        break;
+
+    default:
+        /* Invalid command, try gckKERNEL_Dispatch */
+        status = gckKERNEL_Dispatch(Kernel, gcvNULL, Interface);
+    }
+
+OnError:
+    /* Save status. */
+    kernelInterface->status = status;
+    if (powerMutexAcquired == gcvTRUE)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+    }
+    gcmkFOOTER();
+
+    /* Return the status. */
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_QueryCommandBuffer
+**
+**  Query command buffer attributes.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckVGHARDWARE object.
+**
+**  OUTPUT:
+**
+**      gcsCOMMAND_BUFFER_INFO_PTR Information
+**          Pointer to the information structure to receive buffer attributes.
+*/
+gceSTATUS
+gckKERNEL_QueryCommandBuffer(
+    IN gckKERNEL Kernel,
+    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x",
+                   Kernel, Information);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Get the information. */
+    status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information);
+
+    gcmkFOOTER();
+    /* Return status. */
+    return status;
+}
+
+#endif /* gcdENABLE_VG */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_vg_h_
+#define __gc_hal_kernel_vg_h_
+
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel_hardware.h"
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+
+/* gckKERNEL object. */
+struct _gckVGKERNEL
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Pointer to gckHARDWARE object. */
+    gckVGHARDWARE                   hardware;
+
+    /* Pointer to gckINTERRUPT object. */
+    gckVGINTERRUPT              interrupt;
+
+    /* Pointer to gckCOMMAND object. */
+    gckVGCOMMAND                    command;
+
+    /* Pointer to context. */
+    gctPOINTER                  context;
+
+    /* Pointer to gckMMU object. */
+    gckVGMMU                        mmu;
+
+    gckKERNEL                   kernel;
+};
+
+/* gckMMU object. */
+struct _gckVGMMU
+{
+    /* The object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to gckOS object. */
+    gckOS                       os;
+
+    /* Pointer to gckHARDWARE object. */
+    gckVGHARDWARE                   hardware;
+
+    /* The page table mutex. */
+    gctPOINTER                  mutex;
+
+    /* Page table information. */
+    gctSIZE_T                   pageTableSize;
+    gctPHYS_ADDR                pageTablePhysical;
+    gctPOINTER                  pageTableLogical;
+
+    /* Allocation index. */
+    gctUINT32                   entryCount;
+    gctUINT32                   entry;
+};
+
+#endif /* __gc_hal_kernel_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c
@@ -0,0 +1,4835 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if defined(__QNXNTO__)
+#include "gc_hal_kernel_qnx.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/slogcodes.h>
+#include <time.h>
+
+extern unsigned int slogUsageInterval;
+extern const uint64_t slogLowWaterFPC;
+#endif
+
+#define _GC_OBJ_ZONE    gcvZONE_VIDMEM
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  _Split
+**
+**  Split a node on the required byte boundary.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to the node to split.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to keep in the node.
+**
+**  OUTPUT:
+**
+**      Nothing.
+**
+**  RETURNS:
+**
+**      gctBOOL
+**          gcvTRUE if the node was split successfully, or gcvFALSE if there is an
+**          error.
+**
+*/
+static gctBOOL
+_Split(
+    IN gckOS Os,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcuVIDMEM_NODE_PTR node;
+    gctPOINTER pointer = gcvNULL;
+
+    /* Make sure the byte boundary makes sense. */
+    if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes))
+    {
+        return gcvFALSE;
+    }
+
+    /* Allocate a new gcuVIDMEM_NODE object. */
+    if (gcmIS_ERROR(gckOS_Allocate(Os,
+                                   gcmSIZEOF(gcuVIDMEM_NODE),
+                                   &pointer)))
+    {
+        /* Error. */
+        return gcvFALSE;
+    }
+
+    node = pointer;
+
+    /* Initialize gcuVIDMEM_NODE structure. */
+    node->VidMem.offset    = Node->VidMem.offset + Bytes;
+    node->VidMem.bytes     = Node->VidMem.bytes  - Bytes;
+    node->VidMem.alignment = 0;
+    node->VidMem.locked    = 0;
+    node->VidMem.parent    = Node->VidMem.parent;
+    node->VidMem.pool      = Node->VidMem.pool;
+    node->VidMem.processID = 0;
+    node->VidMem.logical   = gcvNULL;
+    node->VidMem.kvaddr    = gcvNULL;
+
+    /* Insert node behind specified node. */
+    node->VidMem.next = Node->VidMem.next;
+    node->VidMem.prev = Node;
+    Node->VidMem.next = node->VidMem.next->VidMem.prev = node;
+
+    /* Insert free node behind specified node. */
+    node->VidMem.nextFree = Node->VidMem.nextFree;
+    node->VidMem.prevFree = Node;
+    Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node;
+
+    /* Adjust size of specified node. */
+    Node->VidMem.bytes = Bytes;
+
+    /* Success. */
+    return gcvTRUE;
+}
+
+/*******************************************************************************
+**
+**  _Merge
+**
+**  Merge two adjacent nodes together.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to the first of the two nodes to merge.
+**
+**  OUTPUT:
+**
+**      Nothing.
+**
+*/
+static gceSTATUS
+_Merge(
+    IN gckOS Os,
+    IN gcuVIDMEM_NODE_PTR Node
+    )
+{
+    gcuVIDMEM_NODE_PTR node;
+    gceSTATUS status;
+
+    /* Save pointer to next node. */
+    node = Node->VidMem.next;
+
+    /* This is a good time to make sure the heap is not corrupted. */
+    if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset)
+    {
+        /* Corrupted heap. */
+        gcmkASSERT(
+            Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset);
+        return gcvSTATUS_HEAP_CORRUPTED;
+    }
+
+    /* Adjust byte count. */
+    Node->VidMem.bytes += node->VidMem.bytes;
+
+    /* Unlink next node from linked list. */
+    Node->VidMem.next     = node->VidMem.next;
+    Node->VidMem.nextFree = node->VidMem.nextFree;
+
+    Node->VidMem.next->VidMem.prev         =
+    Node->VidMem.nextFree->VidMem.prevFree = Node;
+
+    /* Free next node. */
+    status = gcmkOS_SAFE_FREE(Os, node);
+    return status;
+}
+
+/******************************************************************************\
+******************************* gckVIDMEM API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckVIDMEM_Construct
+**
+**  Construct a new gckVIDMEM object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR_T PhysicalBase
+**          Base physical address for the video memory heap.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes in the video memory heap.
+**
+**      gctSIZE_T Threshold
+**          Minimum number of bytes beyond am allocation before the node is
+**          split.  Can be used as a minimum alignment requirement.
+**
+**      gctSIZE_T BankSize
+**          Number of bytes per physical memory bank.  Used by bank
+**          optimization.
+**
+**  OUTPUT:
+**
+**      gckVIDMEM * Memory
+**          Pointer to a variable that will hold the pointer to the gckVIDMEM
+**          object.
+*/
+gceSTATUS
+gckVIDMEM_Construct(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T PhysicalBase,
+    IN gctSIZE_T Bytes,
+    IN gctSIZE_T Threshold,
+    IN gctSIZE_T BankSize,
+    OUT gckVIDMEM * Memory
+    )
+{
+    gckVIDMEM memory = gcvNULL;
+    gceSTATUS status;
+    gcuVIDMEM_NODE_PTR node;
+    gctINT i, banks = 0;
+    gctPOINTER pointer = gcvNULL;
+    gctUINT32 heapBytes;
+    gctUINT32 bankSize;
+    gctUINT32 base = 0;
+
+    gcmkHEADER_ARG("Os=0x%x PhysicalBase=%12llx Bytes=%lu Threshold=%lu "
+                   "BankSize=%lu",
+                   Os, PhysicalBase, Bytes, Threshold, BankSize);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    if (BankSize == 0)
+    {
+        /* set two banks in 16:1 */
+        BankSize = Bytes >> 4;
+    }
+
+    gcmkSAFECASTSIZET(heapBytes, Bytes);
+    gcmkSAFECASTSIZET(bankSize, BankSize);
+
+    /* Allocate the gckVIDMEM object. */
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer));
+    gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckVIDMEM));
+
+    memory = pointer;
+
+    /* Initialize the gckVIDMEM object. */
+    memory->object.type = gcvOBJ_VIDMEM;
+    memory->os          = Os;
+
+    /* Set video memory heap information. */
+    memory->physicalBase = PhysicalBase;
+    memory->bytes        = heapBytes;
+    memory->freeBytes    = heapBytes;
+    memory->minFreeBytes = heapBytes;
+    memory->capability   = ~0u;
+    memory->threshold    = Threshold;
+    memory->mutex        = gcvNULL;
+
+    /* Walk all possible banks. */
+    for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i)
+    {
+        gctUINT32 bytes;
+
+        if (BankSize == 0)
+        {
+            /* Use all bytes for the first bank. */
+            bytes = heapBytes;
+        }
+        else
+        {
+            /* Compute number of bytes for this bank. */
+            bytes = gcmALIGN(base + 1, bankSize) - base;
+
+            if (bytes > heapBytes)
+            {
+                /* Make sure we don't exceed the total number of bytes. */
+                bytes = heapBytes;
+            }
+        }
+
+        if (bytes == 0)
+        {
+            /* Mark heap is not used. */
+            memory->sentinel[i].VidMem.next     =
+            memory->sentinel[i].VidMem.prev     =
+            memory->sentinel[i].VidMem.nextFree =
+            memory->sentinel[i].VidMem.prevFree = gcvNULL;
+            continue;
+        }
+
+        /* Allocate one gcuVIDMEM_NODE union. */
+        gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
+
+        node = pointer;
+
+        /* Initialize gcuVIDMEM_NODE union. */
+        node->VidMem.parent    = memory;
+
+        node->VidMem.next      =
+        node->VidMem.prev      =
+        node->VidMem.nextFree  =
+        node->VidMem.prevFree  = &memory->sentinel[i];
+
+        node->VidMem.offset    = base;
+        node->VidMem.bytes     = bytes;
+        node->VidMem.alignment = 0;
+        node->VidMem.pool      = gcvPOOL_UNKNOWN;
+
+        node->VidMem.locked    = 0;
+
+        node->VidMem.processID = 0;
+        node->VidMem.logical   = gcvNULL;
+
+#if gcdENABLE_VG
+        node->VidMem.kernelVirtual = gcvNULL;
+#endif
+        node->VidMem.kvaddr    = gcvNULL;
+
+        /* Initialize the linked list of nodes. */
+        memory->sentinel[i].VidMem.next     =
+        memory->sentinel[i].VidMem.prev     =
+        memory->sentinel[i].VidMem.nextFree =
+        memory->sentinel[i].VidMem.prevFree = node;
+
+        /* Mark sentinel. */
+        memory->sentinel[i].VidMem.bytes = 0;
+
+        if (bankSize == (heapBytes >> 4))
+        {
+            bankSize = heapBytes;
+        }
+
+        /* Adjust address for next bank. */
+        base += bytes;
+        heapBytes   -= bytes;
+        banks ++;
+    }
+
+    /* Assign all the bank mappings. */
+    memory->mapping[gcvVIDMEM_TYPE_COLOR_BUFFER]    = banks - 1;
+    memory->mapping[gcvVIDMEM_TYPE_BITMAP]          = banks - 1;
+
+    if (banks > 7) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_DEPTH_BUFFER]    = banks - 1;
+    memory->mapping[gcvVIDMEM_TYPE_HZ_BUFFER]       = banks - 1;
+
+    if (banks > 6) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_TEXTURE]         = banks - 1;
+
+    if (banks > 5) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_VERTEX_BUFFER]   = banks - 1;
+
+    if (banks > 4) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_INDEX_BUFFER]    = banks - 1;
+
+    if (banks > 3) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_TILE_STATUS]     = banks - 1;
+
+    if (banks > 2) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_COMMAND]         = banks - 1;
+
+    if (banks > 1) --banks;
+    memory->mapping[gcvVIDMEM_TYPE_GENERIC]         = 0;
+
+#if gcdENABLE_VG
+    memory->mapping[gcvVIDMEM_TYPE_IMAGE]   = 0;
+    memory->mapping[gcvVIDMEM_TYPE_MASK]    = 0;
+    memory->mapping[gcvVIDMEM_TYPE_SCISSOR] = 0;
+#endif
+    memory->mapping[gcvVIDMEM_TYPE_ICACHE]      = 0;
+    memory->mapping[gcvVIDMEM_TYPE_TXDESC]      = 0;
+    memory->mapping[gcvVIDMEM_TYPE_FENCE]       = 0;
+    memory->mapping[gcvVIDMEM_TYPE_TFBHEADER]   = 0;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] INDEX:         bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_INDEX_BUFFER]);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] VERTEX:        bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_VERTEX_BUFFER]);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] TEXTURE:       bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_TEXTURE]);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] RENDER_TARGET: bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_COLOR_BUFFER]);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] DEPTH:         bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_DEPTH_BUFFER]);
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "[GALCORE] TILE_STATUS:   bank %d",
+                  memory->mapping[gcvVIDMEM_TYPE_TILE_STATUS]);
+
+    /* Allocate the mutex. */
+    gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex));
+
+    /* Return pointer to the gckVIDMEM object. */
+    *Memory = memory;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (memory != gcvNULL)
+    {
+        if (memory->mutex != gcvNULL)
+        {
+            /* Delete the mutex. */
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex));
+        }
+
+        for (i = 0; i < banks; ++i)
+        {
+            /* Free the heap. */
+            gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL);
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next));
+        }
+
+        /* Free the object. */
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_Destroy
+**
+**  Destroy an gckVIDMEM object.
+**
+**  INPUT:
+**
+**      gckVIDMEM Memory
+**          Pointer to an gckVIDMEM object to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckVIDMEM_Destroy(
+    IN gckVIDMEM Memory
+    )
+{
+    gcuVIDMEM_NODE_PTR node, next;
+    gctINT i;
+
+    gcmkHEADER_ARG("Memory=0x%x", Memory);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
+
+    /* Walk all sentinels. */
+    for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
+    {
+        /* Bail out of the heap is not used. */
+        if (Memory->sentinel[i].VidMem.next == gcvNULL)
+        {
+            break;
+        }
+
+        /* Walk all the nodes until we reach the sentinel. */
+        for (node = Memory->sentinel[i].VidMem.next;
+             node->VidMem.bytes != 0;
+             node = next)
+        {
+            /* Save pointer to the next node. */
+            next = node->VidMem.next;
+
+            /* Free the node. */
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node));
+        }
+    }
+
+    /* Free the mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex));
+
+    /* Mark the object as unknown. */
+    Memory->object.type = gcvOBJ_UNKNOWN;
+
+    /* Free the gckVIDMEM object. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_BANK_ALIGNMENT
+
+#if !gcdBANK_BIT_START
+#error gcdBANK_BIT_START not defined.
+#endif
+
+#if !gcdBANK_BIT_END
+#error gcdBANK_BIT_END not defined.
+#endif
+/*******************************************************************************
+**  _GetSurfaceBankAlignment
+**
+**  Return the required offset alignment required to the make BaseAddress
+**  aligned properly.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to gcoOS object.
+**
+**      gceVIDMEM_TYPE Type
+**          Type of allocation.
+**
+**      gctUINT32 BaseAddress
+**          Base address of current video memory node.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR AlignmentOffset
+**          Pointer to a variable that will hold the number of bytes to skip in
+**          the current video memory node in order to make the alignment bank
+**          aligned.
+*/
+static gceSTATUS
+_GetSurfaceBankAlignment(
+    IN gckKERNEL Kernel,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 BaseAddress,
+    OUT gctUINT32_PTR AlignmentOffset
+    )
+{
+    gctUINT32 bank;
+    /* To retrieve the bank. */
+    static const gctUINT32 bankMask = (0xFFFFFFFF << gcdBANK_BIT_START)
+                                    ^ (0xFFFFFFFF << (gcdBANK_BIT_END + 1));
+
+    /* To retrieve the bank and all the lower bytes. */
+    static const gctUINT32 byteMask = ~(0xFFFFFFFF << (gcdBANK_BIT_END + 1));
+
+    gcmkHEADER_ARG("Type=%d BaseAddress=0x%x ", Type, BaseAddress);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(AlignmentOffset != gcvNULL);
+
+    switch (Type)
+    {
+    case gcvVIDMEM_TYPE_COLOR_BUFFER:
+    case gcvVIDMEM_TYPE_TEXTURE:
+    case gcvVIDMEM_TYPE_BITMAP:
+        bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
+
+        /* Align to the first bank. */
+        *AlignmentOffset = (bank == 0) ?
+            0 :
+            ((1 << (gcdBANK_BIT_END + 1)) + 0) -  (BaseAddress & byteMask);
+        break;
+
+    case gcvVIDMEM_TYPE_DEPTH_BUFFER:
+        bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
+
+        /* Align to the third bank. */
+        *AlignmentOffset = (bank == 2) ?
+            0 :
+            ((1 << (gcdBANK_BIT_END + 1)) + (2 << gcdBANK_BIT_START)) -  (BaseAddress & byteMask);
+
+        /* Minimum 256 byte alignment needed for fast_msaa. */
+        if ((gcdBANK_CHANNEL_BIT > 7) ||
+            ((gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_FAST_MSAA) != gcvSTATUS_TRUE) &&
+             (gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_SMALL_MSAA) != gcvSTATUS_TRUE)))
+        {
+            /* Add a channel offset at the channel bit. */
+            *AlignmentOffset += (1 << gcdBANK_CHANNEL_BIT);
+        }
+        break;
+
+    default:
+        /* no alignment needed. */
+        *AlignmentOffset = 0;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_ARG("*AlignmentOffset=%u", *AlignmentOffset);
+    return gcvSTATUS_OK;
+}
+#endif
+
+static gcuVIDMEM_NODE_PTR
+_FindNode(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM Memory,
+    IN gctINT Bank,
+    IN gctSIZE_T Bytes,
+    IN gceVIDMEM_TYPE Type,
+    IN OUT gctUINT32_PTR Alignment
+    )
+{
+    gcuVIDMEM_NODE_PTR node;
+    gctUINT32 alignment;
+
+#if gcdENABLE_BANK_ALIGNMENT
+    gctUINT32 bankAlignment;
+    gceSTATUS status;
+#endif
+
+    if (Memory->sentinel[Bank].VidMem.nextFree == gcvNULL)
+    {
+        /* No free nodes left. */
+        return gcvNULL;
+    }
+
+#if gcdENABLE_BANK_ALIGNMENT
+    /* Walk all free nodes until we have one that is big enough or we have
+    ** reached the sentinel. */
+    for (node = Memory->sentinel[Bank].VidMem.nextFree;
+         node->VidMem.bytes != 0;
+         node = node->VidMem.nextFree)
+    {
+        if (node->VidMem.bytes < Bytes)
+        {
+            continue;
+        }
+
+        gcmkONERROR(_GetSurfaceBankAlignment(
+            Kernel,
+            Type,
+            (gctUINT32)(node->VidMem.parent->physicalBase + node->VidMem.offset),
+            &bankAlignment));
+
+        bankAlignment = gcmALIGN(bankAlignment, *Alignment);
+
+        /* Compute number of bytes to skip for alignment. */
+        alignment = (*Alignment == 0)
+                  ? 0
+                  : (*Alignment - (node->VidMem.offset % *Alignment));
+
+        if (alignment == *Alignment)
+        {
+            /* Node is already aligned. */
+            alignment = 0;
+        }
+
+        if (node->VidMem.bytes >= Bytes + alignment + bankAlignment)
+        {
+            /* This node is big enough. */
+            *Alignment = alignment + bankAlignment;
+            return node;
+        }
+    }
+#endif
+
+    /* Walk all free nodes until we have one that is big enough or we have
+       reached the sentinel. */
+    for (node = Memory->sentinel[Bank].VidMem.nextFree;
+         node->VidMem.bytes != 0;
+         node = node->VidMem.nextFree)
+    {
+        gctUINT offset;
+
+        gctINT modulo;
+
+        gcmkSAFECASTSIZET(offset, node->VidMem.offset);
+
+        modulo = gckMATH_ModuloInt(offset, *Alignment);
+
+        /* Compute number of bytes to skip for alignment. */
+        alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo);
+
+        if (alignment == *Alignment)
+        {
+            /* Node is already aligned. */
+            alignment = 0;
+        }
+
+        if (node->VidMem.bytes >= Bytes + alignment)
+        {
+            /* This node is big enough. */
+            *Alignment = alignment;
+            return node;
+        }
+    }
+
+#if gcdENABLE_BANK_ALIGNMENT
+OnError:
+#endif
+    /* Not enough memory. */
+    return gcvNULL;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_AllocateLinear
+**
+**  Allocate linear memory from the gckVIDMEM object.
+**
+**  INPUT:
+**
+**      gckVIDMEM Memory
+**          Pointer to an gckVIDMEM object.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to allocate.
+**
+**      gctUINT32 Alignment
+**          Byte alignment for allocation.
+**
+**      gceVIDMEM_TYPE Type
+**          Type of surface to allocate (use by bank optimization).
+**
+**      gctUINT32 Flag
+**          Flag of allocatetion.
+**
+**      gctBOOL Specified
+**          If user must use this pool, it should set Specified to gcvTRUE,
+**          otherwise allocator may reserve some memory for other usage, such
+**          as small block size allocation request.
+**
+**  OUTPUT:
+**
+**      gcuVIDMEM_NODE_PTR * Node
+**          Pointer to a variable that will hold the allocated memory node.
+*/
+static gceSTATUS
+gckVIDMEM_AllocateLinear(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM Memory,
+    IN gctSIZE_T Bytes,
+    IN gctUINT32 Alignment,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN gctBOOL Specified,
+    OUT gcuVIDMEM_NODE_PTR * Node
+    )
+{
+    gceSTATUS status;
+    gcuVIDMEM_NODE_PTR node;
+    gctUINT32 alignment;
+    gctINT bank, i;
+    gctBOOL acquired = gcvFALSE;
+    gctUINT64 mappingInOne = 1;
+
+    gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d",
+                   Memory, Bytes, Alignment, Type);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Type < gcvVIDMEM_TYPE_COUNT);
+
+    /* Acquire the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE));
+
+    acquired = gcvTRUE;
+#if defined(__QNXNTO__)
+    if (slogUsageInterval > 0) {
+        static gctSIZE_T lowwaterFPC = ~0;
+        static time_t last_slog_time;
+        int do_slog_now = 0;
+        time_t this_slog_time = time(NULL);
+
+        if (Memory->freeBytes < lowwaterFPC) {
+            if (Memory->freeBytes < slogLowWaterFPC) {
+                do_slog_now = 1;
+            }
+            lowwaterFPC = Memory->freeBytes;
+        }
+
+        if (abs(this_slog_time - last_slog_time) > slogUsageInterval) {
+            do_slog_now = 1;
+        }
+
+        if (do_slog_now) {
+            last_slog_time = this_slog_time;
+            slogf(_SLOGC_GRAPHICS_GL, _SLOG_INFO, "%s: Memory->freeBytes = %u, lowest Memory->freeBytes = %u",
+                    __FUNCTION__, (unsigned) Memory->freeBytes, (unsigned) lowwaterFPC);
+        }
+    }
+#endif
+    if (Bytes > Memory->freeBytes)
+    {
+        /* Not enough memory. */
+        status = gcvSTATUS_OUT_OF_MEMORY;
+        goto OnError;
+    }
+
+#if gcdSMALL_BLOCK_SIZE
+    if ((Memory->freeBytes < (Memory->bytes/gcdRATIO_FOR_SMALL_MEMORY))
+    &&  (Bytes >= gcdSMALL_BLOCK_SIZE)
+    &&  (Specified == gcvFALSE)
+    )
+    {
+        /* The left memory is for small memory.*/
+        status = gcvSTATUS_OUT_OF_MEMORY;
+        goto OnError;
+    }
+#endif
+
+    /* Find the default bank for this surface type. */
+    gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping));
+    bank      = Memory->mapping[Type];
+    alignment = Alignment;
+
+    /* Find a free node in the default bank. */
+    node = _FindNode(Kernel, Memory, bank, Bytes, Type, &alignment);
+
+    /* Out of memory? */
+    if (node == gcvNULL)
+    {
+        /* Walk all lower banks. */
+        for (i = bank - 1; i >= 0; --i)
+        {
+            /* Find a free node inside the current bank. */
+            node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
+            if (node != gcvNULL)
+            {
+                break;
+            }
+        }
+    }
+
+    if (node == gcvNULL)
+    {
+        /* Walk all upper banks. */
+        for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i)
+        {
+            if (Memory->sentinel[i].VidMem.nextFree == gcvNULL)
+            {
+                /* Abort when we reach unused banks. */
+                break;
+            }
+
+            /* Find a free node inside the current bank. */
+            node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
+            if (node != gcvNULL)
+            {
+                break;
+            }
+        }
+    }
+
+    if (node == gcvNULL)
+    {
+        /* Out of memory. */
+        status = gcvSTATUS_OUT_OF_MEMORY;
+        goto OnError;
+    }
+
+    /* Do we have an alignment? */
+    if (alignment > 0)
+    {
+        /* Split the node so it is aligned. */
+        if (_Split(Memory->os, node, alignment))
+        {
+            /* Successful split, move to aligned node. */
+            node = node->VidMem.next;
+
+            /* Remove alignment. */
+            alignment = 0;
+        }
+    }
+
+    /* Do we have enough memory after the allocation to split it? */
+    if (node->VidMem.bytes - Bytes > Memory->threshold)
+    {
+        /* Adjust the node size. */
+        _Split(Memory->os, node, Bytes);
+    }
+
+    /* Remove the node from the free list. */
+    node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree;
+    node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree;
+    node->VidMem.nextFree                  =
+    node->VidMem.prevFree                  = gcvNULL;
+
+    /* Fill in the information. */
+    node->VidMem.alignment = alignment;
+    node->VidMem.parent    = Memory;
+    node->VidMem.logical   = gcvNULL;
+    gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID));
+
+    /* Adjust the number of free bytes. */
+    Memory->freeBytes   -= node->VidMem.bytes;
+
+    if (Memory->freeBytes < Memory->minFreeBytes)
+    {
+        Memory->minFreeBytes = Memory->freeBytes;
+    }
+
+#if gcdENABLE_VG
+    node->VidMem.kernelVirtual = gcvNULL;
+#endif
+    gckOS_QueryOption(Memory->os, "allMapInOne", &mappingInOne);
+    if (!mappingInOne)
+    {
+        gcmkONERROR(gckOS_RequestReservedMemory(
+                Memory->os,
+                Memory->physicalBase + node->VidMem.offset,
+                node->VidMem.bytes,
+                "gal reserved memory",
+                gcvTRUE,
+                &node->VidMem.physical
+                ));
+    }
+
+    /* Release the mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
+
+    /* Return the pointer to the node. */
+    *Node = node;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                   "Allocated %u bytes @ 0x%x [0x%08X]",
+                   node->VidMem.bytes, node, node->VidMem.offset);
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Node=0x%x", *Node);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+     /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_AllocateVirtual
+**
+**  Construct a new gcuVIDMEM_NODE union for virtual memory.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctSIZE_T Bytes
+**          Number of byte to allocate.
+**
+**  OUTPUT:
+**
+**      gcuVIDMEM_NODE_PTR * Node
+**          Pointer to a variable that receives the gcuVIDMEM_NODE union pointer.
+*/
+static gceSTATUS
+gckVIDMEM_AllocateVirtual(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Flag,
+    IN gctSIZE_T Bytes,
+    OUT gcuVIDMEM_NODE_PTR * Node
+    )
+{
+    gckOS os;
+    gceSTATUS status;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gctPOINTER pointer = gcvNULL;
+    gctINT i;
+
+    gcmkHEADER_ARG("Kernel=0x%x Flag=%x Bytes=%lu", Kernel, Flag, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+    /* Extract the gckOS object pointer. */
+    os = Kernel->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Allocate an gcuVIDMEM_NODE union. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
+
+    node = pointer;
+
+    /* Initialize gcuVIDMEM_NODE union for virtual memory. */
+    node->Virtual.kernel        = Kernel;
+    node->Virtual.contiguous    = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+    node->Virtual.logical       = gcvNULL;
+    node->Virtual.kvaddr        = gcvNULL;
+    node->Virtual.bytes         = Bytes;
+#if gcdENABLE_VG
+    node->Virtual.kernelVirtual = gcvNULL;
+#endif
+    node->Virtual.secure        = (Flag & gcvALLOC_FLAG_SECURITY) != 0;
+    node->Virtual.onFault       = (Flag & gcvALLOC_FLAG_ALLOC_ON_FAULT) != 0;
+
+    for (i = 0; i < gcvHARDWARE_NUM_TYPES; i++)
+    {
+        node->Virtual.lockeds[i]        = 0;
+        node->Virtual.pageTables[i]     = gcvNULL;
+    }
+
+    /* Allocate the virtual memory. */
+    gcmkONERROR(
+        gckOS_AllocatePagedMemory(os,
+                                  Flag,
+                                  &node->Virtual.bytes,
+                                  &node->Virtual.gid,
+                                  &node->Virtual.physical));
+
+    /* Calculate required GPU page (4096) count. */
+    /* Assume start address is 4096 aligned. */
+    node->Virtual.pageCount = (gctSIZE_T)(((gctUINT64)node->Virtual.bytes + (4096 - 1)) >> 12);
+
+    /* Return pointer to the gcuVIDMEM_NODE union. */
+    *Node = node;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                   "Created virtual node 0x%x for %u bytes @ 0x%x",
+                   node, Bytes, node->Virtual.physical);
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Node=0x%x", *Node);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Roll back. */
+    if (node != gcvNULL)
+    {
+        /* Free the structure. */
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_AddToBlockList(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    VidMemBlock->next   = Kernel->vidMemBlock;
+    Kernel->vidMemBlock = VidMemBlock;
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_RemoveFromBlockList(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    gckVIDMEM_BLOCK vidMemBlock;
+    gckVIDMEM_BLOCK previous = gcvNULL;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    for (vidMemBlock = Kernel->vidMemBlock; vidMemBlock != gcvNULL; vidMemBlock = vidMemBlock->next)
+    {
+        if (vidMemBlock->addresses[hwType] == VidMemBlock->addresses[hwType])
+        {
+            if (previous)
+            {
+                previous->next = vidMemBlock->next;
+            }
+            else
+            {
+                Kernel->vidMemBlock = vidMemBlock->next;
+            }
+            vidMemBlock->next = gcvNULL;
+
+            break;
+        }
+        previous = vidMemBlock;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gckVIDMEM_BLOCK
+_FindFreeBlock(
+    IN gckKERNEL Kernel,
+    IN gctBOOL Contiguous,
+    IN gctSIZE_T Bytes
+    )
+{
+    gckVIDMEM_BLOCK vidMemBlock;
+
+    for (vidMemBlock = Kernel->vidMemBlock; vidMemBlock != gcvNULL; vidMemBlock = vidMemBlock->next)
+    {
+        if ((vidMemBlock->freeBytes >= Bytes) && (Contiguous == vidMemBlock->contiguous))
+        {
+            /* Found the block */
+            break;
+        }
+    }
+
+    return vidMemBlock;
+}
+
+static gceSTATUS
+_SplitVirtualChunk(
+    IN gckOS Os,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gctPOINTER pointer;
+    gctINT i;
+
+    if ((Bytes <= 0) || (Bytes > Node->VirtualChunk.bytes))
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    /* Allocate a new gcuVIDMEM_NODE object. */
+    gcmkONERROR(gckOS_Allocate(Os,
+                               gcmSIZEOF(gcuVIDMEM_NODE),
+                               &pointer));
+
+    node = pointer;
+
+    /* Intialize the new gcuVIDMEM_NODE. */
+    node->VirtualChunk.offset = Node->VirtualChunk.offset + Bytes;
+    node->VirtualChunk.bytes  = Node->VirtualChunk.bytes - Bytes;
+    node->VirtualChunk.parent = Node->VirtualChunk.parent;
+    node->VirtualChunk.kernel = Node->VirtualChunk.kernel;
+    node->VirtualChunk.kvaddr = gcvNULL;
+
+    for (i = 0; i < gcvHARDWARE_NUM_TYPES; i++)
+    {
+        node->VirtualChunk.lockeds[i] = 0;
+    }
+
+    /* Insert chunk behind specified chunk. */
+    node->VirtualChunk.next  = Node->VirtualChunk.next;
+    node->VirtualChunk.prev  = Node;
+    Node->VirtualChunk.next = node->VirtualChunk.next->VirtualChunk.prev = node;
+
+    /* Insert free chunk behind specified chunk. */
+    node->VirtualChunk.nextFree  = Node->VirtualChunk.nextFree;
+    node->VirtualChunk.prevFree  = Node;
+    Node->VirtualChunk.nextFree = node->VirtualChunk.nextFree->VirtualChunk.prevFree = node;
+
+    /* Adjust size of specified chunk. */
+    Node->VirtualChunk.bytes = Bytes;
+
+OnError:
+    return status;
+}
+
+static gceSTATUS
+_MergeVirtualChunk(
+    IN gckOS Os,
+    IN gcuVIDMEM_NODE_PTR Node
+    )
+{
+    gcuVIDMEM_NODE_PTR node;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    node = Node->VirtualChunk.next;
+
+    if (Node->VirtualChunk.offset + Node->VirtualChunk.bytes != node->VirtualChunk.offset)
+    {
+        /* Corrupted heap. */
+        gcmkASSERT(
+            Node->VirtualChunk.offset + Node->VirtualChunk.bytes == node->VirtualChunk.offset);
+
+        return gcvSTATUS_HEAP_CORRUPTED;
+    }
+
+    /* Merge. */
+    Node->VirtualChunk.bytes += node->VirtualChunk.bytes;
+
+    /* Unlink next node from linked list. */
+    Node->VirtualChunk.next     = node->VirtualChunk.next;
+    Node->VirtualChunk.nextFree = node->VirtualChunk.nextFree;
+
+    Node->VirtualChunk.next->VirtualChunk.prev         =
+    Node->VirtualChunk.nextFree->VirtualChunk.prevFree = Node;
+
+    /* Free the next node. */
+    status = gcmkOS_SAFE_FREE(Os, node);
+    return status;
+}
+
+static gctBOOL
+_IsVidMemBlockFree(
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    return (VidMemBlock->freeBytes == VidMemBlock->bytes);
+}
+
+static gcuVIDMEM_NODE_PTR
+_FindVirtualChunkNode(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK VidMemBlock,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcuVIDMEM_NODE_PTR node;
+
+    if (VidMemBlock->node.VirtualChunk.nextFree == gcvNULL)
+    {
+        /* No free chunk left. */
+        return gcvNULL;
+    }
+
+    for (node = VidMemBlock->node.VirtualChunk.nextFree;
+         node->VirtualChunk.bytes != 0;
+         node = node->VirtualChunk.nextFree)
+    {
+        if (node->VirtualChunk.bytes >= Bytes)
+        {
+            /* Got it. */
+            return node;
+        }
+    }
+
+    return gcvNULL;
+}
+
+/*******************************************************************************
+**
+** _ConvertPhysical
+**
+**  Convert CPU physical to GPU address for video node.
+**
+**  INPUT:
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to a gcuVIDMEM_NODE union.
+**
+**      gceCORE Core
+**          Id of current GPU.
+**
+**      gctPHYS_ADDR_T PhysicalAddress
+**          CPU physical address
+**
+**  OUTPUT:
+**      gctUINT32 * Address
+**          A pointer hold the GPU address.
+*/
+static gceSTATUS
+_ConvertPhysical(
+    IN gckKERNEL Kernel,
+    IN gceCORE Core,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN gckVIDMEM_BLOCK VidMemBlock,
+    IN gctPHYS_ADDR_T PhysicalAddress,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status;
+    gctUINT64 physical = 0;
+
+    gcmkHEADER_ARG("Node=0x%X", Node);
+
+    if ((Node && !Node->Virtual.contiguous) ||
+        (VidMemBlock && !VidMemBlock->contiguous))
+    {
+        /* non-contiguous, mapping is required. */
+        status = gcvSTATUS_NOT_SUPPORTED;
+        goto OnError;
+    }
+
+    if ((Node && Node->Virtual.secure) ||
+        (VidMemBlock && VidMemBlock->secure))
+    {
+        /* Secure, mapping is forced. */
+        status = gcvSTATUS_NOT_SUPPORTED;
+        goto OnError;
+    }
+
+    /* Convert to GPU physical address. */
+    gckOS_CPUPhysicalToGPUPhysical(Kernel->os, PhysicalAddress, &physical);
+
+#if gcdENABLE_VG
+    if (Core == gcvCORE_VG)
+    {
+        /* VG MMU can always support contiguous. */
+        *Address = (gctUINT32)physical;
+        gcmkFOOTER_ARG("*Address=0x%X", *Address);
+        return gcvSTATUS_OK;
+    }
+#endif
+
+    if ((physical > gcvMAXUINT32) ||
+        (Node && (physical + Node->Virtual.bytes - 1 > gcvMAXUINT32)) ||
+        (VidMemBlock && (physical + VidMemBlock->bytes - 1 > gcvMAXUINT32)))
+    {
+        /* Above 4G (32bit), mapping is required currently. */
+        status = gcvSTATUS_NOT_SUPPORTED;
+        goto OnError;
+    }
+
+    if (!gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_MMU))
+    {
+        if (physical < Kernel->hardware->baseAddress)
+        {
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        /* Subtract baseAddress to get a GPU address used for programming. */
+        physical -= Kernel->hardware->baseAddress;
+
+        /* 2G upper is virtual space, better to move to gckHARDWARE section. */
+        if (Node && (physical + Node->Virtual.bytes > 0x80000000U))
+        {
+            /* End is above 2G, ie virtual space. */
+            status = gcvSTATUS_NOT_SUPPORTED;
+            goto OnError;
+        }
+
+        *Address = (gctUINT32)physical;
+
+        gcmkFOOTER_ARG("*Address=0x%X", *Address);
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        gctBOOL flatMapped;
+
+        gcmkONERROR(gckMMU_IsFlatMapped(Kernel->mmu, physical, gcvINVALID_ADDRESS, &flatMapped));
+
+        if (!flatMapped)
+        {
+            status = gcvSTATUS_NOT_SUPPORTED;
+            goto OnError;
+        }
+
+        *Address = (gctUINT32)physical;
+
+        gcmkFOOTER_ARG("*Address=0x%X", *Address);
+        return gcvSTATUS_OK;
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_MapVidMemBlock(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctPHYS_ADDR_T physAddr;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkHEADER_ARG("Kernel=%p VidMemBlock=%p", Kernel, VidMemBlock);
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    gcmkVERIFY_ARGUMENT(VidMemBlock != gcvNULL);
+    gcmkASSERT(VidMemBlock->pageCount > 0);
+
+    gcmkONERROR(
+        gckOS_GetPhysicalFromHandle(os,
+                                    VidMemBlock->physical,
+                                    0,
+                                    &physAddr));
+
+    status = _ConvertPhysical(Kernel,
+                              Kernel->core,
+                              gcvNULL,
+                              VidMemBlock,
+                              physAddr,
+                              &VidMemBlock->addresses[hwType]);
+    if (gcmIS_ERROR(status))
+    {
+        /* Allocate pages inside the MMU. */
+        gcmkONERROR(
+            gckMMU_AllocatePagesEx(Kernel->mmu,
+                                   VidMemBlock->pageCount,
+                                   VidMemBlock->type,
+                                   gcvPAGE_TYPE_1M,
+                                   VidMemBlock->secure,
+                                   &VidMemBlock->pageTables[hwType],
+                                   &VidMemBlock->addresses[hwType]));
+
+        if (VidMemBlock->onFault != gcvTRUE)
+        {
+            /* Map the pages. */
+            gcmkONERROR(
+                gckOS_Map1MPages(os,
+                                 Kernel->core,
+                                 VidMemBlock->physical,
+                                 VidMemBlock->pageCount,
+                                 VidMemBlock->addresses[hwType],
+                                 VidMemBlock->pageTables[hwType],
+                                 gcvTRUE,
+                                 VidMemBlock->type));
+        }
+
+        gcmkONERROR(gckMMU_Flush(Kernel->mmu, VidMemBlock->type));
+
+        /* Calculate the GPU virtual address. */
+        VidMemBlock->addresses[hwType] |= (gctUINT32) (physAddr & ((1 << 20) - 1));
+    }
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                   "Mapped video memory block 0x%x to 0x%08X",
+                   VidMemBlock,
+                   VidMemBlock->addresses[hwType]);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (VidMemBlock->pageTables[hwType] != gcvNULL)
+    {
+        /* Free the pages from the MMU. */
+        gcmkVERIFY_OK(
+            gckMMU_FreePages(Kernel->mmu,
+                             VidMemBlock->secure,
+                             gcvPAGE_TYPE_1M,
+                             VidMemBlock->addresses[hwType],
+                             VidMemBlock->pageTables[hwType],
+                             VidMemBlock->pageCount));
+
+        VidMemBlock->pageTables[hwType] = gcvNULL;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_UnmapVidMemBlock(
+    IN gckMMU Mmu,
+    IN gceHARDWARE_TYPE HwType,
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Mmu=%p VidMemBlock=%p", Mmu, VidMemBlock);
+
+    gcmkVERIFY_ARGUMENT(VidMemBlock != gcvNULL);
+
+    if (VidMemBlock->pageTables[HwType] != gcvNULL)
+    {
+        /* Free the pages from the MMU. */
+        gcmkONERROR(
+            gckMMU_FreePages(Mmu,
+                             VidMemBlock->secure,
+                             gcvPAGE_TYPE_1M,
+                             VidMemBlock->addresses[HwType],
+                             VidMemBlock->pageTables[HwType],
+                             VidMemBlock->pageCount));
+
+        VidMemBlock->pageTables[HwType] = gcvNULL;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_BLOCK_Construct(
+    IN gckKERNEL Kernel,
+    IN gctSIZE_T BlockSize,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    OUT gckVIDMEM_BLOCK * VidMemBlock
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckOS os = Kernel->os;
+    gctPOINTER pointer;
+    gctINT i;
+
+    gcmkHEADER_ARG("Kernel=0x%x BlockSize=%lu Type=%x Flag=%x", Kernel, BlockSize, Type);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(BlockSize > 0);
+    gcmkVERIFY_ARGUMENT(VidMemBlock != gcvNULL);
+
+    /* Allocate an gckVIDMEM_BLOCK object. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_BLOCK), &pointer));
+
+    vidMemBlock = pointer;
+
+    /* Initialize the gckVIDMEM_BLOCK object. */
+    vidMemBlock->object.type = gcvOBJ_VIDMEM_BLOCK;
+    vidMemBlock->os          = os;
+    vidMemBlock->bytes       = BlockSize;
+    vidMemBlock->freeBytes   = BlockSize;
+    /* 1M page count. */
+    vidMemBlock->pageCount   = (gctUINT32)(BlockSize >> 20);
+    vidMemBlock->type        = Type;
+    vidMemBlock->contiguous  = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+    vidMemBlock->secure      = (Flag & gcvALLOC_FLAG_SECURITY) != 0;
+    vidMemBlock->onFault     = (Flag & gcvALLOC_FLAG_ALLOC_ON_FAULT) != 0;
+    vidMemBlock->mutex       = gcvNULL;
+    vidMemBlock->physical    = gcvNULL;
+
+    for (i = 0; i < gcvHARDWARE_NUM_TYPES; i++)
+    {
+        vidMemBlock->pageTables[i] = gcvNULL;
+    }
+
+    /* Allocate the mutex. */
+    gcmkONERROR(gckOS_CreateMutex(os, &vidMemBlock->mutex));
+
+    /* Allocate one gcuVIDMEM_NODE union. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
+
+    node = pointer;
+
+    if (!vidMemBlock->contiguous)
+    {
+        Flag |= gcvALLOC_FLAG_1M_PAGES;
+    }
+
+    /* Alloc 1M page size aligned memory block. */
+    gcmkONERROR(
+        gckOS_AllocatePagedMemory(os,
+                                  Flag,
+                                  &BlockSize,
+                                  &vidMemBlock->gid,
+                                  &vidMemBlock->physical));
+
+    /* Map current hardware mmu table with 1M pages for this video memory block. */
+    gcmkONERROR(gckVIDMEM_MapVidMemBlock(Kernel, vidMemBlock));
+
+    /* Initialize gcuVIDMEM_NODE union for virtual memory. */
+    node->VirtualChunk.kernel     = Kernel;
+    node->VirtualChunk.offset     = 0;
+    node->VirtualChunk.bytes      = BlockSize;
+    node->VirtualChunk.kvaddr     = gcvNULL;
+    node->VirtualChunk.logical    = gcvNULL;
+    node->VirtualChunk.parent     = vidMemBlock;
+
+    for (i = 0; i < gcvHARDWARE_NUM_TYPES; i++)
+    {
+        node->VirtualChunk.lockeds[i] = 0;
+    }
+
+    /* Initialize the virtual chunk linked-list. */
+    node->VirtualChunk.next     =
+    node->VirtualChunk.prev     =
+    node->VirtualChunk.nextFree =
+    node->VirtualChunk.prevFree = &vidMemBlock->node;
+
+    vidMemBlock->node.VirtualChunk.next =
+    vidMemBlock->node.VirtualChunk.prev =
+    vidMemBlock->node.VirtualChunk.nextFree =
+    vidMemBlock->node.VirtualChunk.prevFree = node;
+
+    vidMemBlock->node.VirtualChunk.bytes = 0;
+
+    *VidMemBlock = vidMemBlock;
+
+    gcmkFOOTER_ARG("*VidMemBlock=0x%x", *VidMemBlock);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (vidMemBlock != gcvNULL)
+    {
+        if (vidMemBlock->mutex)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(os, vidMemBlock->mutex));
+        }
+
+        if (vidMemBlock->physical)
+        {
+            gcmkVERIFY_OK(gckOS_FreePagedMemory(os,
+                                                vidMemBlock->physical,
+                                                vidMemBlock->bytes));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, vidMemBlock));
+    }
+
+    if (node != gcvNULL)
+    {
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_BLOCK_Destroy(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK VidMemBlock
+    )
+{
+    gckDEVICE device = Kernel->device;
+    gctINT i;
+
+    gcmkHEADER_ARG("Kernel=%p VidMemBlock=%p", Kernel, VidMemBlock);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+    gcmkVERIFY_ARGUMENT(VidMemBlock != gcvNULL);
+
+    if (VidMemBlock->physical)
+    {
+        gcmkVERIFY_OK(gckOS_FreePagedMemory(Kernel->os,
+                                            VidMemBlock->physical,
+                                            VidMemBlock->bytes));
+    }
+
+    for (i = 0; i < gcvHARDWARE_NUM_TYPES; i++)
+    {
+        if (VidMemBlock->pageTables[i])
+        {
+            gcmkVERIFY_OK(_UnmapVidMemBlock(device->mmus[i], i, VidMemBlock));
+        }
+    }
+
+    /* Free the mutex. */
+    gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, VidMemBlock->mutex));
+
+    /* Free the virtual chunk. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, VidMemBlock->node.VirtualChunk.next));
+
+    /* Free the video memory block. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, VidMemBlock));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_AllocateVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_BLOCK  VidMemBlock,
+    IN gceVIDMEM_TYPE Type,
+    INOUT gctSIZE_T *Bytes,
+    OUT gcuVIDMEM_NODE_PTR *Node
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node;
+    gctSIZE_T bytes;
+
+    gcmkHEADER_ARG("Kernel=%p VidMemBlock=%p Type=%x Bytes=%zx",
+        Kernel, VidMemBlock, Type, *Bytes);
+
+    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+    gcmkVERIFY_ARGUMENT(VidMemBlock != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Type < gcvVIDMEM_TYPE_COUNT);
+
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, VidMemBlock->mutex, gcvINFINITE));
+
+    acquired = gcvTRUE;
+
+    bytes = gcmALIGN(*Bytes, 4096);
+
+    if (bytes > VidMemBlock->freeBytes)
+    {
+        /* No enough memory. */
+        status = gcvSTATUS_OUT_OF_MEMORY;
+        goto OnError;
+    }
+
+    node = _FindVirtualChunkNode(Kernel, VidMemBlock, bytes);
+    if (node == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    if (node->VirtualChunk.bytes > bytes)
+    {
+        /* Split the chunk. */
+        _SplitVirtualChunk(Kernel->os, node, bytes);
+    }
+
+    /* Remove the chunk from the free list. */
+    node->VirtualChunk.prevFree->VirtualChunk.nextFree = node->VirtualChunk.nextFree;
+    node->VirtualChunk.nextFree->VirtualChunk.prevFree = node->VirtualChunk.prevFree;
+    node->VirtualChunk.nextFree = node->VirtualChunk.prevFree = gcvNULL;
+
+    /* Fill in the information. */
+    node->VirtualChunk.parent = VidMemBlock;
+
+    VidMemBlock->freeBytes -= node->VirtualChunk.bytes;
+
+    *Bytes = bytes;
+    *Node  = node;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, VidMemBlock->mutex));
+    }
+
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_AllocateVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN gctSIZE_T Bytes,
+    OUT gcuVIDMEM_NODE_PTR * Node
+    )
+{
+    gckOS os;
+    gceSTATUS status;
+    gcuVIDMEM_NODE_PTR node;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gctSIZE_T blockSize;
+    gctBOOL acquired = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%x Flag=%x Bytes=%lu", Kernel, Flag, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+    /* Extract the gckOS object pointer. */
+    os = Kernel->os;
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Acquire the vidMem block mutex */
+    gcmkONERROR(gckOS_AcquireMutex(os, Kernel->vidMemBlockMutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Find the free vidmem block. */
+    vidMemBlock = _FindFreeBlock(Kernel, Bytes, Flag & gcvALLOC_FLAG_CONTIGUOUS);
+    if (!vidMemBlock)
+    {
+        /* Not found, construct new block. */
+        blockSize = gcmALIGN(Bytes, gcd1M_PAGE_SIZE);
+
+        gcmkONERROR(
+            gckVIDMEM_BLOCK_Construct(Kernel,
+                                      blockSize,
+                                      Type,
+                                      Flag,
+                                      &vidMemBlock));
+
+        gcmkONERROR(_AddToBlockList(Kernel, vidMemBlock));
+    }
+
+    /* Allocate virtual chunk node in the found block. */
+    gcmkONERROR(
+        _AllocateVirtualChunk(Kernel,
+                              vidMemBlock,
+                              Type,
+                              &Bytes,
+                              &node));
+
+    /* Return pointer to the gcuVIDMEM_NODE union. */
+    *Node = node;
+
+    /* Release the vidMem block mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Kernel->vidMemBlockMutex));
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                   "Created virtual node 0x%x for %u bytes @ 0x%x",
+                   node, Bytes, node->Virtual.physical);
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Node=0x%x", *Node);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the vidMem block mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Kernel->vidMemBlockMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_Free
+**
+**  Free an allocated video memory node.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to a gcuVIDMEM_NODE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+static gceSTATUS
+gckVIDMEM_Free(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node
+    )
+{
+    gceSTATUS status;
+    gckKERNEL kernel = gcvNULL;
+    gckVIDMEM memory = gcvNULL;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gcuVIDMEM_NODE_PTR node;
+    gctBOOL mutexAcquired = gcvFALSE;
+    gctBOOL vbMutexAcquired = gcvFALSE;
+    gctBOOL vbListMutexAcquired = gcvFALSE;
+    gctUINT64 mappingInOne = 1;
+
+    gcmkHEADER_ARG("Node=0x%x", Node);
+
+    /* Verify the arguments. */
+    if ((Node == gcvNULL)
+    ||  (Node->VidMem.parent == gcvNULL)
+    )
+    {
+        /* Invalid object. */
+        gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+    }
+
+    vidMemBlock = Node->VirtualChunk.parent;
+
+    /**************************** Video Memory ********************************/
+
+    if (Node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        /* Extract pointer to gckVIDMEM object owning the node. */
+        memory = Node->VidMem.parent;
+
+        /* Acquire the mutex. */
+        gcmkONERROR(
+            gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
+
+        mutexAcquired = gcvTRUE;
+
+        if (Node->VidMem.kvaddr)
+        {
+#if gcdCAPTURE_ONLY_MODE
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Node->VidMem.kvaddr));
+#else
+
+            gcmkONERROR(
+                gckOS_DestroyKernelMapping(Kernel->os,
+                                           Node->VidMem.parent->physical,
+                                           Node->VidMem.kvaddr));
+#endif
+
+            Node->VidMem.kvaddr = gcvNULL;
+        }
+
+#ifdef __QNXNTO__
+        /* Unmap the video memory. */
+        if (Node->VidMem.logical != gcvNULL)
+        {
+            gckKERNEL_UnmapVideoMemory(
+                Kernel,
+                Node->VidMem.pool,
+                Node->VidMem.physical,
+                Node->VidMem.logical,
+                Node->VidMem.processID,
+                Node->VidMem.bytes
+                );
+
+            Node->VidMem.logical = gcvNULL;
+        }
+
+        /* Reset. */
+        Node->VidMem.processID = 0;
+
+        /* Don't try to re-free an already freed node. */
+        if ((Node->VidMem.nextFree == gcvNULL)
+        &&  (Node->VidMem.prevFree == gcvNULL)
+        )
+#endif
+        {
+#if gcdENABLE_VG
+            if (Node->VidMem.kernelVirtual)
+            {
+                gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                        "%s(%d) Unmap %x from kernel space.",
+                        __FUNCTION__, __LINE__,
+                        Node->VidMem.kernelVirtual);
+
+                gcmkVERIFY_OK(
+                    gckOS_UnmapPhysical(memory->os,
+                                        Node->VidMem.kernelVirtual,
+                                        Node->VidMem.bytes));
+
+                Node->VidMem.kernelVirtual = gcvNULL;
+            }
+#endif
+
+            /* Check if Node is already freed. */
+            if (Node->VidMem.nextFree)
+            {
+                /* Node is alread freed. */
+                gcmkONERROR(gcvSTATUS_INVALID_DATA);
+            }
+
+            /* Update the number of free bytes. */
+            memory->freeBytes += Node->VidMem.bytes;
+
+            /* Find the next free node. */
+            for (node = Node->VidMem.next;
+                 node != gcvNULL && node->VidMem.nextFree == gcvNULL;
+                 node = node->VidMem.next) ;
+
+            if (node == gcvNULL)
+            {
+                gcmkONERROR(gcvSTATUS_INVALID_DATA);
+            }
+
+            /* Insert this node in the free list. */
+            Node->VidMem.nextFree = node;
+            Node->VidMem.prevFree = node->VidMem.prevFree;
+
+            Node->VidMem.prevFree->VidMem.nextFree =
+            node->VidMem.prevFree                  = Node;
+
+            /* Is the next node a free node and not the sentinel? */
+            if ((Node->VidMem.next == Node->VidMem.nextFree)
+            &&  (Node->VidMem.next->VidMem.bytes != 0)
+            )
+            {
+                /* Merge this node with the next node. */
+                gcmkONERROR(_Merge(memory->os, node = Node));
+                gcmkASSERT(node->VidMem.nextFree != node);
+                gcmkASSERT(node->VidMem.prevFree != node);
+            }
+
+            /* Is the previous node a free node and not the sentinel? */
+            if ((Node->VidMem.prev == Node->VidMem.prevFree)
+            &&  (Node->VidMem.prev->VidMem.bytes != 0)
+            )
+            {
+                /* Merge this node with the previous node. */
+                gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev));
+                gcmkASSERT(node->VidMem.nextFree != node);
+                gcmkASSERT(node->VidMem.prevFree != node);
+            }
+        }
+
+        gckOS_QueryOption(memory->os, "allMapInOne", &mappingInOne);
+        if (!mappingInOne)
+        {
+            gckOS_ReleaseReservedMemory(memory->os, Node->VidMem.physical);
+            Node->VidMem.physical = gcvNULL;
+        }
+
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                       "Node 0x%x is freed.",
+                       Node);
+
+        /* Success. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        /* Acquire the vidMem block mutex */
+        gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->vidMemBlockMutex, gcvINFINITE));
+        vbListMutexAcquired = gcvTRUE;
+
+        if (vidMemBlock)
+        {
+            gckOS os = vidMemBlock->os;
+
+            gcmkONERROR(gckOS_AcquireMutex(os, vidMemBlock->mutex, gcvINFINITE));
+            vbMutexAcquired = gcvTRUE;
+            kernel = Node->VirtualChunk.kernel;
+
+            if (Node->VirtualChunk.kvaddr)
+            {
+                gcmkONERROR(
+                    gckOS_DestroyKernelMapping(kernel->os,
+                                               vidMemBlock->physical,
+                                               Node->VirtualChunk.kvaddr));
+
+                Node->VirtualChunk.kvaddr = gcvNULL;
+            }
+
+            /* Handle the free chunk in the linked-list */
+            {
+                /* Check if chunk is in free list. */
+                if (Node->VirtualChunk.nextFree)
+                {
+                    /* Chunk is already freed. */
+                    gcmkONERROR(gcvSTATUS_INVALID_DATA);
+                }
+
+                vidMemBlock->freeBytes += Node->VirtualChunk.bytes;
+
+                /* Find the next free chunk. */
+                for (node = Node->VirtualChunk.next;
+                     node != gcvNULL && node->VirtualChunk.nextFree == gcvNULL;
+                     node = node->VirtualChunk.next);
+
+                if (node == gcvNULL)
+                {
+                    gcmkONERROR(gcvSTATUS_INVALID_DATA);
+                }
+
+                /* Insert this chunk in the free list. */
+                Node->VirtualChunk.nextFree = node;
+                Node->VirtualChunk.prevFree = node->VirtualChunk.prevFree;
+
+                Node->VirtualChunk.prevFree->VirtualChunk.nextFree =
+                node->VirtualChunk.prevFree = Node;
+
+                /* Is the next chunk a free chunk. */
+                if ((Node->VirtualChunk.next == Node->VirtualChunk.nextFree)
+                &&  (Node->VirtualChunk.next->VirtualChunk.bytes != 0)
+                )
+                {
+                    /* Merge this chunk with the next chunk. */
+                    gcmkONERROR(_MergeVirtualChunk(os, node = Node));
+                    gcmkASSERT(node->VirtualChunk.nextFree != node);
+                    gcmkASSERT(node->VirtualChunk.prevFree != node);
+                }
+
+                /* Is the previous chunk a free chunk. */
+                if ((Node->VirtualChunk.prev == Node->VirtualChunk.prevFree)
+                &&  (Node->VirtualChunk.prev->VirtualChunk.bytes != 0)
+                )
+                {
+                    /* Merge this chunk with the previous chunk. */
+                    gcmkONERROR(_MergeVirtualChunk(os, node = Node->VirtualChunk.prev));
+                    gcmkASSERT(node->VirtualChunk.nextFree != node);
+                    gcmkASSERT(node->VirtualChunk.prevFree != node);
+                }
+            }
+
+            /* Release the mutex. */
+            gcmkVERIFY_OK(gckOS_ReleaseMutex(os, vidMemBlock->mutex));
+
+            /* Only free the vidmem block when all the chunks are freed. */
+            if (_IsVidMemBlockFree(vidMemBlock))
+            {
+                gcmkONERROR(_RemoveFromBlockList(kernel, vidMemBlock));
+
+                gcmkONERROR(gckVIDMEM_BLOCK_Destroy(kernel, vidMemBlock));
+            }
+        }
+
+        /* Release the vidMem block mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->vidMemBlockMutex));
+
+        /* Success. */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    /*************************** Virtual Memory *******************************/
+
+    /* Get gckKERNEL object. */
+    kernel = Node->Virtual.kernel;
+
+    /* Verify the gckKERNEL object pointer. */
+    gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL);
+
+#if gcdENABLE_VG
+    if (Node->Virtual.kernelVirtual)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                "%s(%d) Unmap %x from kernel space.",
+                __FUNCTION__, __LINE__,
+                Node->Virtual.kernelVirtual);
+
+        gcmkVERIFY_OK(
+            gckOS_UnmapPhysical(kernel->os,
+                                Node->Virtual.kernelVirtual,
+                                Node->Virtual.bytes));
+
+        Node->Virtual.kernelVirtual = gcvNULL;
+    }
+#endif
+
+    if (Node->Virtual.kvaddr)
+    {
+        gcmkVERIFY_OK(
+            gckOS_DestroyKernelMapping(kernel->os,
+                                       Node->Virtual.physical,
+                                       Node->Virtual.kvaddr));
+    }
+
+    /* Free the virtual memory. */
+    gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os,
+                                        Node->Virtual.physical,
+                                        Node->Virtual.bytes));
+
+    /* Delete the gcuVIDMEM_NODE union. */
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(kernel->os, Node));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mutexAcquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            memory->os, memory->mutex
+            ));
+    }
+
+    if (vbMutexAcquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            vidMemBlock->os, vidMemBlock->mutex
+            ));
+    }
+
+    if (vbListMutexAcquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(
+            vidMemBlock->os, Kernel->vidMemBlockMutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_Lock
+**
+**  Lock a video memory node and return its hardware specific address.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to a gcuVIDMEM_NODE union.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Pointer to a variable that will hold the hardware specific address.
+**
+**      gctUINT32 * PhysicalAddress
+**          Pointer to a variable that will hold the bus address of a contiguous
+**          video node.
+*/
+static gceSTATUS
+gckVIDMEM_Lock(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    OUT gctUINT32 * Address
+    )
+{
+    gcmkHEADER_ARG("Kernel=%p Node=%p", Kernel, Node);
+
+    /* Increment the lock count. */
+    if (Node->VidMem.locked++ == 0)
+    {
+        gctUINT32 address;
+        gctUINT32 offset = (gctUINT32)Node->VidMem.offset;
+
+        switch (Node->VidMem.pool)
+        {
+        case gcvPOOL_LOCAL_EXTERNAL:
+            address = Kernel->externalBaseAddress + offset;
+            break;
+        case gcvPOOL_LOCAL_INTERNAL:
+            address = Kernel->internalBaseAddress + offset;
+            break;
+        case gcvPOOL_INTERNAL_SRAM:
+            address = Kernel->sRAMBaseAddresses[Kernel->sRAMIndex] + offset;
+            break;
+        case gcvPOOL_EXTERNAL_SRAM:
+            address = Kernel->extSRAMBaseAddresses[Kernel->extSRAMIndex] + offset;
+            break;
+        default:
+            gcmkASSERT(Node->VidMem.pool == gcvPOOL_SYSTEM);
+            /*FALLTHRU*/
+        case gcvPOOL_SYSTEM:
+            address = Kernel->contiguousBaseAddress + offset;
+            break;
+        }
+
+        /* Save address. */
+        Node->VidMem.address = address;
+    }
+
+    *Address = Node->VidMem.address;
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "Locked node 0x%x (%d) @ 0x%08X",
+                  Node,
+                  Node->VidMem.locked,
+                  *Address);
+
+    gcmkFOOTER_ARG("*Address=0x%08X", *Address);
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+gckVIDMEM_LockVirtual(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status;
+    gctPHYS_ADDR_T physicalAddress;
+    gctBOOL locked = gcvFALSE;
+    gckOS os = Kernel->os;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkHEADER_ARG("Kernel=%p Node=%p", Kernel, Node);
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    gcmkONERROR(
+        gckOS_GetPhysicalFromHandle(os,
+                                    Node->Virtual.physical,
+                                    0,
+                                    &physicalAddress));
+
+#if gcdENABLE_VG
+    Node->Virtual.physicalAddress = physicalAddress;
+#endif
+
+    /* Increment the lock count. */
+    if (Node->Virtual.lockeds[hwType]++ == 0)
+    {
+        locked = gcvTRUE;
+
+        status = _ConvertPhysical(
+            Kernel,
+            Kernel->core,
+            Node,
+            gcvNULL,
+            physicalAddress,
+            &Node->Virtual.addresses[hwType]
+            );
+
+        if (gcmIS_ERROR(status))
+        {
+            /* Do GPU address mapping. */
+#if gcdSECURITY
+            gctPHYS_ADDR physicalArrayPhysical;
+            gctPOINTER physicalArrayLogical;
+
+            gcmkONERROR(gckOS_AllocatePageArray(
+                os,
+                Node->Virtual.physical,
+                Node->Virtual.pageCount,
+                &physicalArrayLogical,
+                &physicalArrayPhysical
+                ));
+
+            gcmkONERROR(gckKERNEL_SecurityMapMemory(
+                Kernel,
+                physicalArrayLogical,
+                Node->Virtual.pageCount,
+                &Node->Virtual.addresses[hwType]
+                ));
+
+            gcmkONERROR(gckOS_FreeNonPagedMemory(
+                os,
+                physicalArrayPhysical,
+                physicalArrayLogical,
+                1
+                ));
+#else
+#if gcdENABLE_VG
+            if (Kernel->vg != gcvNULL)
+            {
+                /* Allocate pages inside the MMU. */
+                gcmkONERROR(
+                    gckVGMMU_AllocatePages(Kernel->vg->mmu,
+                                           Node->Virtual.pageCount,
+                                           &Node->Virtual.pageTables[hwType],
+                                           &Node->Virtual.addresses[hwType]));
+            }
+            else
+#endif
+            {
+                /* Allocate pages inside the MMU. */
+                gcmkONERROR(
+                    gckMMU_AllocatePagesEx(Kernel->mmu,
+                                           Node->Virtual.pageCount,
+                                           Node->Virtual.type,
+                                           gcvPAGE_TYPE_4K,
+                                           Node->Virtual.secure,
+                                           &Node->Virtual.pageTables[hwType],
+                                           &Node->Virtual.addresses[hwType]));
+            }
+
+            if (Node->Virtual.onFault != gcvTRUE)
+            {
+#if gcdENABLE_TRUST_APPLICATION
+#if gcdENABLE_VG
+                if (Kernel->core != gcvCORE_VG && Kernel->hardware->options.secureMode == gcvSECURE_IN_TA)
+#else
+                if (Kernel->hardware->options.secureMode == gcvSECURE_IN_TA)
+#endif
+                {
+                    gcmkONERROR(gckKERNEL_MapInTrustApplicaiton(
+                        Kernel,
+                        Node->Virtual.logical,
+                        Node->Virtual.physical,
+                        Node->Virtual.addresses[hwType],
+                        Node->Virtual.pageCount
+                        ));
+                }
+                else
+#endif
+                {
+                    gcmkDUMP(os, "#[mmu: dynamic mapping: address=0x%08X pageCount=%lu]",
+                             Node->Virtual.addresses[hwType],
+                             (unsigned long)Node->Virtual.pageCount);
+
+                    /* Map the pages. */
+                    gcmkONERROR(gckOS_MapPagesEx(os,
+                        Kernel->core,
+                        Node->Virtual.physical,
+                        Node->Virtual.pageCount,
+                        Node->Virtual.addresses[hwType],
+                        Node->Virtual.pageTables[hwType],
+                        gcvTRUE,
+                        Node->Virtual.type));
+                }
+            }
+
+#if gcdENABLE_VG
+            if (Kernel->core == gcvCORE_VG)
+            {
+                gcmkONERROR(gckVGMMU_Flush(Kernel->vg->mmu));
+            }
+            else
+#endif
+            {
+                gcmkONERROR(gckMMU_Flush(Kernel->mmu, Node->Virtual.type));
+            }
+#endif
+
+            /* GPU MMU page size is fixed at 4096 now. */
+            Node->Virtual.addresses[hwType] |= (gctUINT32)physicalAddress & (4096 - 1);
+        }
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                       "Mapped virtual node 0x%x to 0x%08X",
+                       Node,
+                       Node->Virtual.addresses[hwType]);
+    }
+
+    /* Return hardware address. */
+    *Address = Node->Virtual.addresses[hwType];
+
+    gcmkFOOTER_ARG("*Address=0x%08X", *Address);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (locked)
+    {
+        if (Node->Virtual.pageTables[hwType] != gcvNULL)
+        {
+#if gcdENABLE_VG
+            if (Kernel->vg != gcvNULL)
+            {
+                /* Free the pages from the MMU. */
+                gcmkVERIFY_OK(
+                    gckVGMMU_FreePages(Kernel->vg->mmu,
+                                     Node->Virtual.pageTables[hwType],
+                                     Node->Virtual.pageCount));
+            }
+            else
+#endif
+            {
+                /* Free the pages from the MMU. */
+                gcmkVERIFY_OK(
+                    gckMMU_FreePages(Kernel->mmu,
+                                     Node->Virtual.secure,
+                                     gcvPAGE_TYPE_4K,
+                                     Node->Virtual.addresses[hwType],
+                                     Node->Virtual.pageTables[hwType],
+                                     Node->Virtual.pageCount));
+            }
+
+            Node->Virtual.pageTables[hwType] = gcvNULL;
+        }
+
+        Node->Virtual.lockeds[hwType]--;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_LockVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckVIDMEM_BLOCK vidMemBlock = Node->VirtualChunk.parent;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkHEADER_ARG("Kernel=%p Node=%p", Kernel, Node);
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    gcmkASSERT(vidMemBlock != gcvNULL);
+
+    /* Increment the lock count. */
+    if (Node->VirtualChunk.lockeds[hwType]++ == 0)
+    {
+        if (!vidMemBlock->pageTables[hwType])
+        {
+            /* Map current hardware mmu table with 1M pages for this video memory block. */
+            gcmkONERROR(gckVIDMEM_MapVidMemBlock(Kernel, vidMemBlock));
+        }
+
+        Node->VirtualChunk.addresses[hwType] = vidMemBlock->addresses[hwType]
+                                             + (gctUINT32)Node->VirtualChunk.offset;
+    }
+
+    /* Return hardware address. */
+    *Address = Node->VirtualChunk.addresses[hwType];
+
+    gcmkFOOTER_ARG("*Address=0x%08X", *Address);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_Unlock
+**
+**  Unlock a video memory node.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcuVIDMEM_NODE_PTR Node
+**          Pointer to a locked gcuVIDMEM_NODE union.
+**
+**      gctBOOL * Asynchroneous
+**          Pointer to a variable specifying whether the surface should be
+**          unlocked asynchroneously or not.
+**
+**  OUTPUT:
+**
+**      gctBOOL * Asynchroneous
+**          Pointer to a variable receiving the number of bytes used in the
+**          command buffer specified by 'Commands'.  If gcvNULL, there is no
+**          command buffer.
+*/
+static gceSTATUS
+gckVIDMEM_Unlock(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN OUT gctBOOL * Asynchroneous
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Node=0x%x *Asynchroneous=%d",
+                   Node, gcmOPT_VALUE(Asynchroneous));
+
+    if (Node->VidMem.locked <= 0)
+    {
+        /* The surface was not locked. */
+        gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED);
+    }
+
+    if (Asynchroneous != gcvNULL)
+    {
+        /* Schedule an event to sync with GPU. */
+        *Asynchroneous = gcvTRUE;
+    }
+    else
+    {
+        /* Decrement the lock count. */
+        Node->VidMem.locked--;
+    }
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "Unlocked node %p (%d)",
+                  Node,
+                  Node->VidMem.locked);
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_UnlockVirtual(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN OUT gctBOOL * Asynchroneous
+    )
+{
+    gceSTATUS status;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkHEADER_ARG("Node=0x%x *Asynchroneous=%d",
+                   Node, gcmOPT_VALUE(Asynchroneous));
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    if (Asynchroneous != gcvNULL)
+    {
+        /* Schedule the surface to be unlocked. */
+        *Asynchroneous = gcvTRUE;
+    }
+    else
+    {
+        if (Node->Virtual.lockeds[hwType] == 0)
+        {
+            gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED);
+        }
+
+        /* Decrement lock count. */
+        --Node->Virtual.lockeds[hwType];
+
+        /* See if we can unlock the resources. */
+        if (Node->Virtual.lockeds[hwType] == 0)
+        {
+            gctUINT32 address;
+
+            /* Adjust address to page aligned for underlying functions. */
+            address = Node->Virtual.addresses[hwType] & ~(4096 - 1);
+
+#if gcdSECURITY
+            if (Node->Virtual.addresses[hwType] > 0x80000000U)
+            {
+                gcmkONERROR(gckKERNEL_SecurityUnmapMemory(
+                    Kernel,
+                    address,
+                    Node->Virtual.pageCount
+                    ));
+            }
+#else
+            /* Free the page table. */
+            if (Node->Virtual.pageTables[hwType] != gcvNULL)
+            {
+#if gcdENABLE_VG
+                if (Kernel->vg != gcvNULL)
+                {
+                    gcmkONERROR(
+                        gckVGMMU_FreePages(Kernel->vg->mmu,
+                                         Node->Virtual.pageTables[hwType],
+                                         Node->Virtual.pageCount));
+                }
+                else
+#endif
+                {
+                    gcmkONERROR(
+                        gckMMU_FreePages(Kernel->mmu,
+                                         Node->Virtual.secure,
+                                         gcvPAGE_TYPE_4K,
+                                         address,
+                                         Node->Virtual.pageTables[hwType],
+                                         Node->Virtual.pageCount));
+                }
+
+                gcmkONERROR(gckOS_UnmapPages(
+                    Kernel->os,
+                    Node->Virtual.pageCount,
+                    address
+                    ));
+
+                /* Mark page table as freed. */
+                Node->Virtual.pageTables[hwType] = gcvNULL;
+            }
+#endif
+        }
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                       "Unmapped virtual node %p from 0x%08X",
+                       Node, Node->Virtual.addresses[hwType]);
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+gckVIDMEM_UnlockVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR Node,
+    IN OUT gctBOOL * Asynchroneous
+    )
+{
+    gceSTATUS status;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkHEADER_ARG("Node=0x%x *Asynchroneous=%d",
+                   Node, gcmOPT_VALUE(Asynchroneous));
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    if (Asynchroneous != gcvNULL)
+    {
+        /* Schedule an event to sync with GPU. */
+        *Asynchroneous = gcvTRUE;
+    }
+    else
+    {
+        if (Node->VirtualChunk.lockeds[hwType] == 0)
+        {
+            /* The surface was not locked. */
+            gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED);
+        }
+
+        /* Unmap and free pages when video memory free. */
+
+        /* Decrement the lock count. */
+        --Node->VirtualChunk.lockeds[hwType];
+    }
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+                  "Unlocked node %p (%d)",
+                  Node,
+                  Node->VirtualChunk.lockeds[hwType]);
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+/*******************************************************************************
+**
+**  gckVIDMEM_HANDLE_Allocate
+**
+**  Allocate a handle for a gckVIDMEM_NODE object.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gckVIDMEM_NODE Node
+**          Pointer to a gckVIDMEM_NODE object.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Handle
+**          Pointer to a variable receiving a handle represent this
+**          gckVIDMEM_NODE in userspace.
+*/
+gceSTATUS
+gckVIDMEM_HANDLE_Allocate(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE Node,
+    OUT gctUINT32 * Handle
+    )
+{
+    gceSTATUS status;
+    gctUINT32 processID           = 0;
+    gctPOINTER pointer            = gcvNULL;
+    gctPOINTER handleDatabase     = gcvNULL;
+    gctPOINTER mutex              = gcvNULL;
+    gctUINT32 handle              = 0;
+    gckVIDMEM_HANDLE handleObject = gcvNULL;
+    gckOS os                      = Kernel->os;
+
+    gcmkHEADER_ARG("Kernel=0x%X, Node=0x%X", Kernel, Node);
+
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    /* Allocate a gckVIDMEM_HANDLE object. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_HANDLE), &pointer));
+
+    gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_HANDLE)));
+
+    handleObject = pointer;
+
+    gcmkONERROR(gckOS_AtomConstruct(os, &handleObject->reference));
+
+    /* Set default reference count to 1. */
+    gckOS_AtomSet(os, handleObject->reference, 1);
+
+    gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
+
+    gcmkONERROR(
+        gckKERNEL_FindHandleDatbase(Kernel,
+                                    processID,
+                                    &handleDatabase,
+                                    &mutex));
+
+    /* Allocate a handle for this object. */
+    gcmkONERROR(
+        gckKERNEL_AllocateIntegerId(handleDatabase, handleObject, &handle));
+
+    handleObject->node = Node;
+    handleObject->handle = handle;
+
+    *Handle = handle;
+
+    gcmkFOOTER_ARG("*Handle=%d", *Handle);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (handleObject != gcvNULL)
+    {
+        if (handleObject->reference != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(os, handleObject->reference));
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, handleObject));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Reference(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_HANDLE handleObject = gcvNULL;
+    gctPOINTER database           = gcvNULL;
+    gctPOINTER mutex              = gcvNULL;
+    gctINT32 oldValue             = 0;
+    gctBOOL acquired              = gcvFALSE;
+
+    gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
+
+    gcmkONERROR(
+        gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Translate handle to gckVIDMEM_HANDLE object. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+    /* Increase the reference count. */
+    gckOS_AtomIncrement(Kernel->os, handleObject->reference, &oldValue);
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Dereference(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle
+    )
+{
+    gceSTATUS status;
+    gctPOINTER handleDatabase     = gcvNULL;
+    gctPOINTER mutex              = gcvNULL;
+    gctINT32 oldValue             = 0;
+    gckVIDMEM_HANDLE handleObject = gcvNULL;
+    gctBOOL acquired              = gcvFALSE;
+
+    gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
+
+    gcmkONERROR(
+        gckKERNEL_FindHandleDatbase(Kernel,
+                                    ProcessID,
+                                    &handleDatabase,
+                                    &mutex));
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Translate handle to gckVIDMEM_HANDLE. */
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(handleDatabase, Handle, (gctPOINTER *)&handleObject));
+
+    gckOS_AtomDecrement(Kernel->os, handleObject->reference, &oldValue);
+
+    if (oldValue == 1)
+    {
+        /* Remove handle from database if this is the last reference. */
+        gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(handleDatabase, Handle));
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    if (oldValue == 1)
+    {
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, handleObject->reference));
+        gcmkOS_SAFE_FREE(Kernel->os, handleObject);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN gctUINT32 Handle,
+    OUT gckVIDMEM_NODE * Node
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_HANDLE handleObject = gcvNULL;
+    gckVIDMEM_NODE node           = gcvNULL;
+    gctPOINTER database           = gcvNULL;
+    gctPOINTER mutex              = gcvNULL;
+    gctBOOL acquired              = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%X ProcessID=%d Handle=%d",
+                   Kernel, ProcessID, Handle);
+
+    gcmkONERROR(
+        gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+    node = handleObject->node;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    *Node = node;
+
+    gcmkFOOTER_ARG("*Node=%d", *Node);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup2(
+    IN gckKERNEL Kernel,
+    IN gcsDATABASE_PTR Database,
+    IN gctUINT32 Handle,
+    OUT gckVIDMEM_NODE * Node
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_HANDLE handleObject = gcvNULL;
+    gckVIDMEM_NODE node           = gcvNULL;
+    gctPOINTER database           = gcvNULL;
+    gctPOINTER mutex              = gcvNULL;
+    gctBOOL acquired              = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%X Database=%p Handle=%d",
+                   Kernel, Database, Handle);
+
+    database = Database->handleDatabase;
+    mutex = Database->handleDatabaseMutex;
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    gcmkONERROR(
+        gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+    node = handleObject->node;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    *Node = node;
+
+    gcmkFOOTER_ARG("*Node=%d", *Node);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+static gceSTATUS
+gckVIDMEM_NODE_Construct(
+    IN gckKERNEL Kernel,
+    IN gcuVIDMEM_NODE_PTR VideoNode,
+    IN gceVIDMEM_TYPE Type,
+    IN gcePOOL Pool,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE node = gcvNULL;
+    gctPOINTER pointer  = gcvNULL;
+    gckOS os = Kernel->os;
+    gctUINT i;
+
+    /* Construct a node. */
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_NODE), &pointer));
+
+    gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_NODE)));
+
+    node = pointer;
+
+    node->metadata.magic = VIV_VIDMEM_METADATA_MAGIC;
+    node->metadata.ts_fd = -1;
+
+    node->node = VideoNode;
+    node->kernel = Kernel;
+    node->type = Type;
+    node->pool = Pool;
+
+    gcmkONERROR(gckOS_AtomConstruct(os, &node->reference));
+
+    gcmkONERROR(gckOS_CreateMutex(os, &node->mutex));
+
+    for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+    {
+        gcmkONERROR(gckOS_CreateSignal(os, gcvFALSE, &node->sync[i].signal));
+    }
+
+    /* Reference is 1 by default . */
+    gckOS_AtomSet(os, node->reference, 1);
+
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(Kernel->os,
+                           Kernel->db->videoMemListMutex,
+                           gcvINFINITE));
+
+    /* Add into video memory node list. */
+    gcsLIST_Add(&node->link, &Kernel->db->videoMemList);
+
+    gcmkVERIFY_OK(
+        gckOS_ReleaseMutex(Kernel->os, Kernel->db->videoMemListMutex));
+
+    *NodeObject = node;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (node != gcvNULL)
+    {
+        if (node->mutex)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mutex));
+        }
+
+        if (node->reference != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_AtomDestroy(os, node->reference));
+        }
+
+        for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+        {
+            if (node->sync[i].signal != gcvNULL)
+            {
+                gcmkVERIFY_OK(gckOS_DestroySignal(os, node->sync[i].signal));
+            }
+        }
+
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_AllocateLinear(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM VideoMemory,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN gctUINT32 Alignment,
+    IN gctBOOL Specified,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T bytes = *Bytes;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p VideoMemory=%p Pool=%d Alignment=%d Type=%d *Bytes=%u",
+                   Kernel, VideoMemory, Pool, Alignment, Type, bytes);
+
+    gcmkONERROR(
+        gckVIDMEM_AllocateLinear(Kernel,
+                                 VideoMemory,
+                                 bytes,
+                                 Alignment,
+                                 Type,
+                                 Flag,
+                                 Specified,
+                                 &node));
+
+    /* Update pool. */
+    node->VidMem.pool = Pool;
+    bytes = node->VidMem.bytes;
+
+    /* Construct a node. */
+    gcmkONERROR(
+        gckVIDMEM_NODE_Construct(Kernel, node, Type, Pool, &nodeObject));
+
+    *Bytes = bytes;
+    *NodeObject = nodeObject;
+
+    gcmkFOOTER_ARG("*Bytes=%u *NodeObject=%p", bytes, nodeObject);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (node)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_AllocateVirtual(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T bytes = *Bytes;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p Pool=%d Type=%d Flag=%x *Bytes=%u",
+                   Kernel, Pool, Type, Flag, bytes);
+
+    gcmkONERROR(
+        gckVIDMEM_AllocateVirtual(Kernel, Flag, bytes, &node));
+
+    /* Update type. */
+    node->Virtual.type = Type;
+    bytes = node->Virtual.bytes;
+
+    /* Construct a node. */
+    gcmkONERROR(
+        gckVIDMEM_NODE_Construct(Kernel, node, Type, Pool, &nodeObject));
+
+    *Bytes = bytes;
+    *NodeObject = nodeObject;
+
+    gcmkFOOTER_ARG("*Bytes=%u *NodeObject=%p", bytes, nodeObject);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (node)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_AllocateVirtualChunk(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T bytes = *Bytes;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p Pool=%d Type=%d Flag=%x *Bytes=%u",
+                   Kernel, Pool, Type, Flag, bytes);
+
+    gcmkONERROR(
+        gckVIDMEM_AllocateVirtualChunk(Kernel, Type, Flag, bytes, &node));
+
+    bytes = node->VirtualChunk.bytes;
+
+    /* Construct a node. */
+    gcmkONERROR(
+        gckVIDMEM_NODE_Construct(Kernel, node, Type, Pool, &nodeObject));
+
+    *Bytes = bytes;
+    *NodeObject = nodeObject;
+
+    gcmkFOOTER_ARG("*Bytes=%u *NodeObject=%p", bytes, nodeObject);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (node)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Reference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject
+    )
+{
+    gctINT32 oldValue;
+    gcmkHEADER_ARG("Kernel=0x%X NodeObject=0x%X", Kernel, NodeObject);
+
+    gcmkVERIFY_ARGUMENT(NodeObject != gcvNULL);
+
+    gckOS_AtomIncrement(Kernel->os, NodeObject->reference, &oldValue);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Dereference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject
+    )
+{
+    gctINT32 oldValue   = 0;
+    gctPOINTER database = Kernel->db->nameDatabase;
+    gctPOINTER mutex    = Kernel->db->nameDatabaseMutex;
+    gctUINT i;
+
+    gcmkHEADER_ARG("Kernel=0x%X NodeObject=0x%X", Kernel, NodeObject);
+    gcmkVERIFY_ARGUMENT(NodeObject != gcvNULL);
+
+    gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+
+    gcmkVERIFY_OK(gckOS_AtomDecrement(Kernel->os, NodeObject->reference, &oldValue));
+
+    if (oldValue == 1 && NodeObject->name)
+    {
+        /* Free name if exists. */
+        gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, NodeObject->name));
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+
+    if (oldValue == 1)
+    {
+        gcmkVERIFY_OK(
+            gckOS_AcquireMutex(Kernel->os,
+                               Kernel->db->videoMemListMutex,
+                               gcvINFINITE));
+
+        /* Remove from video memory node list. */
+        gcsLIST_Del(&NodeObject->link);
+
+        gcmkVERIFY_OK(
+            gckOS_ReleaseMutex(Kernel->os, Kernel->db->videoMemListMutex));
+
+        /* Free gcuVIDMEM_NODE. */
+        gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, NodeObject->node));
+
+        gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, NodeObject->reference));
+
+        gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, NodeObject->mutex));
+
+        for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+        {
+            if (NodeObject->sync[i].signal != gcvNULL)
+            {
+                gcmkVERIFY_OK(gckOS_DestroySignal(Kernel->os, NodeObject->sync[i].signal));
+            }
+        }
+
+        /* Should not cause recursive call since tsNode->tsNode should be NULL */
+        if (NodeObject->tsNode)
+        {
+            gcmkASSERT(!NodeObject->tsNode->tsNode);
+            gckVIDMEM_NODE_Dereference(Kernel, NodeObject->tsNode);
+        }
+
+        gcmkOS_SAFE_FREE(Kernel->os, NodeObject);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetReference(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT32 * ReferenceCount
+    )
+{
+    gctINT32 value;
+
+    gckOS_AtomGet(Kernel->os, NodeObject->reference, &value);
+
+    *ReferenceCount = value;
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Lock(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 * Address
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    gcmkHEADER_ARG("NodeObject=%p", NodeObject);
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(os, NodeObject->mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        gcmkONERROR(gckVIDMEM_Lock(Kernel, node, Address));
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        gcmkONERROR(gckVIDMEM_LockVirtualChunk(Kernel, node, Address));
+    }
+    else
+    {
+        gcmkONERROR(gckVIDMEM_LockVirtual(Kernel, node, Address));
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+
+    gcmkFOOTER_ARG("*Address=0x%08X", *Address);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Unlock(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 ProcessID,
+    IN OUT gctBOOL * Asynchroneous
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    gcmkHEADER_ARG("NodeObject=%p Asynchroneous=%p", NodeObject, Asynchroneous);
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(os, NodeObject->mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        gcmkONERROR(gckVIDMEM_Unlock(Kernel, node, Asynchroneous));
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        gcmkONERROR(gckVIDMEM_UnlockVirtualChunk(Kernel, node, Asynchroneous));
+    }
+    else
+    {
+        gcmkONERROR(gckVIDMEM_UnlockVirtual(Kernel, node, Asynchroneous));
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+
+    gcmkFOOTER_ARG("*Asynchroneous=0x%08X", gcmOPT_VALUE(Asynchroneous));
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_CleanCache(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gctPHYS_ADDR physHandle = gcvNULL;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Kernel=%p NodeObject=%d Offset=0x%llx Logical=%p Bytes=0x%llx",
+                   Kernel, NodeObject, Offset, Logical, Bytes);
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        gcmkONERROR(gckOS_MemoryBarrier(Kernel->os, Logical));
+
+        /* Reserved pool can't be cacheable */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        physHandle = vidMemBlock->physical;
+    }
+    else
+    {
+        physHandle = node->Virtual.physical;
+    }
+
+    gcmkONERROR(gckOS_CacheFlush(
+        Kernel->os,
+        0,
+        physHandle,
+        Offset,
+        Logical,
+        Bytes
+        ));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_InvalidateCache(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gctPHYS_ADDR physHandle = gcvNULL;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Kernel=%p NodeObject=%d Offset=0x%llx Logical=%p Bytes=0x%llx",
+                   Kernel, NodeObject, Offset, Logical, Bytes);
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        /* Reserved pool can't be cacheable */
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        physHandle = vidMemBlock->physical;
+    }
+    else
+    {
+        physHandle = node->Virtual.physical;
+    }
+
+    gcmkONERROR(gckOS_CacheInvalidate(
+        Kernel->os,
+        0,
+        physHandle,
+        Offset,
+        Logical,
+        Bytes
+        ));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetLockCount(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT32 * LockCount
+    )
+{
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gctINT32 lockCount = 0;
+    gctINT i = 0;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        lockCount = node->VidMem.locked;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        for (; i < gcvHARDWARE_NUM_TYPES; i++)
+        {
+            lockCount += node->VirtualChunk.lockeds[i];
+        }
+    }
+    else
+    {
+
+        for (; i < gcvHARDWARE_NUM_TYPES; i++)
+        {
+            lockCount += node->Virtual.lockeds[i];
+        }
+    }
+
+    *LockCount = lockCount;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_LockCPU(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctBOOL Cacheable,
+    IN gctBOOL FromUser,
+    OUT gctPOINTER * Logical
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gctPOINTER logical = gcvNULL;
+
+    gcmkHEADER_ARG("NodeObject=%p", NodeObject);
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(os, NodeObject->mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        if (Cacheable == gcvTRUE)
+        {
+            gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+        }
+
+        if (FromUser)
+        {
+#if gcdCAPTURE_ONLY_MODE
+            node->VidMem.logical = NodeObject->captureLogical;
+#else
+            /* Map video memory pool to user space. */
+            gcmkONERROR(
+                gckKERNEL_MapVideoMemory(Kernel,
+                                         gcvTRUE,
+                                         node->VidMem.pool,
+                                         node->VidMem.physical,
+                                         (gctUINT32)node->VidMem.offset,
+                                         (gctUINT32)node->VidMem.bytes,
+                                         &node->VidMem.logical));
+#endif
+
+            logical = node->VidMem.logical;
+        }
+        else
+        {
+            /* Map video memory pool to kernel space. */
+            if (!node->VidMem.kvaddr)
+            {
+#if gcdCAPTURE_ONLY_MODE
+                gcmkONERROR(gckOS_Allocate(os,
+                                           node->VidMem.bytes,
+                                           &node->VidMem.kvaddr));
+#else
+                gcmkONERROR(
+                    gckOS_CreateKernelMapping(os,
+                                              node->VidMem.parent->physical,
+                                              node->VidMem.offset,
+                                              node->VidMem.bytes,
+                                              &node->VidMem.kvaddr));
+#endif
+            }
+
+            logical = node->VidMem.kvaddr;
+        }
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        if (FromUser)
+        {
+            /* Lock the entire vidmem block. */
+            gcmkONERROR(
+                gckOS_LockPages(os,
+                                vidMemBlock->physical,
+                                vidMemBlock->bytes,
+                                Cacheable,
+                                &logical));
+
+            /* Get the logical with offset in block. */
+            logical = (uint8_t *)logical + node->VirtualChunk.offset;
+            node->VirtualChunk.logical = logical;
+        }
+        else
+        {
+            /* Map once and will cancel map when free. */
+            if (!node->VirtualChunk.kvaddr)
+            {
+                gcmkONERROR(
+                    gckOS_CreateKernelMapping(os,
+                                              vidMemBlock->physical,
+                                              node->VirtualChunk.offset,
+                                              node->VirtualChunk.bytes,
+                                              &node->VirtualChunk.kvaddr));
+            }
+
+            logical = node->VirtualChunk.kvaddr;
+        }
+    }
+    else
+    {
+        if (FromUser)
+        {
+            gcmkONERROR(
+                gckOS_LockPages(os,
+                                node->Virtual.physical,
+                                node->Virtual.bytes,
+                                Cacheable,
+                                &logical));
+
+            node->Virtual.logical = logical;
+        }
+        else
+        {
+            /* Map once and will cancel map when free. */
+            if (!node->Virtual.kvaddr)
+            {
+                gcmkONERROR(
+                    gckOS_CreateKernelMapping(os,
+                                              node->Virtual.physical,
+                                              0,
+                                              node->Virtual.bytes,
+                                              &node->Virtual.kvaddr));
+            }
+
+            logical = node->Virtual.kvaddr;
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+
+    *Logical = logical;
+
+    gcmkFOOTER_ARG("*Logical=%p", logical);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_UnlockCPU(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 ProcessID,
+    IN gctBOOL FromUser,
+    IN gctBOOL Defer
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    gcmkHEADER_ARG("NodeObject=%p", NodeObject);
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(os, NodeObject->mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        if (FromUser)
+        {
+#if gcdCAPTURE_ONLY_MODE || defined __QNXNTO__
+            /* Do nothing here. */
+#else
+            if (!Defer)
+            {
+                /* Unmap the video memory. */
+                if (node->VidMem.logical != gcvNULL)
+                {
+                    gckKERNEL_UnmapVideoMemory(
+                        Kernel,
+                        node->VidMem.pool,
+                        node->VidMem.physical,
+                        node->VidMem.logical,
+                        node->VidMem.processID,
+                        node->VidMem.bytes
+                        );
+
+                    node->VidMem.logical = gcvNULL;
+                }
+                /* Reset. */
+                node->VidMem.processID = 0;
+            }
+#endif
+        }
+        else
+        {
+            /*
+             * Kernel side may lock for CPU access for multiple times. Since
+             * we don't have lock counts currently, we don't cancel CPU
+             * mapping here, and will cancel at 'free' instead.
+             */
+            /*
+            gcmkONERROR(
+                gckOS_DestroyKernelMapping(os,
+                                           node->VidMem.parent->physical,
+                                           node->VidMem.kvaddr));
+
+            node->VidMem.kvaddr = gcvNULL;
+             */
+        }
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        if (FromUser)
+        {
+            gcmkONERROR(
+                gckOS_UnlockPages(os,
+                                  vidMemBlock->physical,
+                                  vidMemBlock->bytes,
+                                  node->VirtualChunk.logical));
+        }
+        else
+        {
+            /* Nothing to do. */
+        }
+    }
+    else
+    {
+        if (FromUser)
+        {
+            gcmkONERROR(
+                gckOS_UnlockPages(os,
+                                  node->Virtual.physical,
+                                  node->Virtual.bytes,
+                                  node->Virtual.logical));
+        }
+        else
+        {
+            /*
+             * Kernel side may lock for CPU access for multiple times. Since
+             * we don't have lock counts currently, we don't cancel CPU
+             * mapping here, and will cancel at 'free' instead.
+             */
+            /*
+            gcmkONERROR(
+                gckOS_DestroyKernelMapping(os,
+                                           node->Virtual.physical,
+                                           node->Virtual.kvaddr));
+
+            node->Virtual.kvaddr = gcvNULL;
+             */
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetPhysical(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * PhysicalAddress
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    gcmkHEADER_ARG("NodeObject=%p", NodeObject);
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        if (Offset >= node->VidMem.bytes)
+        {
+            /* Exceeds node size. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        *PhysicalAddress = node->VidMem.parent->physicalBase
+                         + node->VidMem.offset
+                         + Offset;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        if (Offset >= node->VirtualChunk.bytes)
+        {
+            /* Exceeds node size. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        gcmkONERROR(
+            gckOS_GetPhysicalFromHandle(os,
+                                        vidMemBlock->physical,
+                                        (gctUINT32)node->VirtualChunk.offset + Offset,
+                                        PhysicalAddress));
+    }
+    else
+    {
+        if (Offset >= node->Virtual.bytes)
+        {
+            /* Exceeds node size. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        gcmkONERROR(
+            gckOS_GetPhysicalFromHandle(os,
+                                        node->Virtual.physical,
+                                        Offset,
+                                        PhysicalAddress));
+    }
+
+    gcmkFOOTER_ARG("*PhysicalAddress=0x%llx", *PhysicalAddress);
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetGid(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 * Gid
+    )
+{
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        *Gid = 0;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        *Gid = vidMemBlock->gid;
+    }
+    else
+    {
+        *Gid = node->Virtual.gid;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetSize(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctSIZE_T * Size
+    )
+{
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        *Size = node->VidMem.bytes;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        *Size = node->VirtualChunk.bytes;
+    }
+    else
+    {
+        *Size = node->Virtual.bytes;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetType(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gceVIDMEM_TYPE * Type,
+    OUT gcePOOL * Pool
+    )
+{
+    if (Type)
+    {
+        *Type = NodeObject->type;
+    }
+
+    if (Pool)
+    {
+        *Pool = NodeObject->pool;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+
+/*******************************************************************************
+**
+**
+** Code for dma_buf ops
+**
+**
+*******************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/mm_types.h>
+#include <linux/dma-buf.h>
+
+static struct sg_table *_dmabuf_map(struct dma_buf_attachment *attachment,
+                                    enum dma_data_direction direction)
+{
+    struct sg_table *sgt = gcvNULL;
+    struct dma_buf *dmabuf = attachment->dmabuf;
+    gckVIDMEM_NODE nodeObject = dmabuf->priv;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    do
+    {
+        gcuVIDMEM_NODE_PTR node = nodeObject->node;
+        gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+        gctPHYS_ADDR physical = gcvNULL;
+        gctSIZE_T offset = 0;
+        gctSIZE_T bytes = 0;
+
+        if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+        {
+            physical = node->VidMem.parent->physical;
+            offset = node->VidMem.offset;
+            bytes = node->VidMem.bytes;
+        }
+        else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+        {
+            physical = vidMemBlock->physical;
+            offset = node->VirtualChunk.offset;
+            bytes = node->VirtualChunk.bytes;
+        }
+        else
+        {
+            physical = node->Virtual.physical;
+            offset = 0;
+            bytes = node->Virtual.bytes;
+        }
+
+        gcmkERR_BREAK(gckOS_MemoryGetSGT(nodeObject->kernel->os, physical, offset, bytes, (gctPOINTER*)&sgt));
+
+        if (dma_map_sg(attachment->dev, sgt->sgl, sgt->nents, direction) == 0)
+        {
+            sg_free_table(sgt);
+            kfree(sgt);
+            sgt = gcvNULL;
+            gcmkERR_BREAK(gcvSTATUS_GENERIC_IO);
+        }
+    }
+    while (gcvFALSE);
+
+    return sgt;
+}
+
+static void _dmabuf_unmap(struct dma_buf_attachment *attachment,
+                          struct sg_table *sgt,
+                          enum dma_data_direction direction)
+{
+    dma_unmap_sg(attachment->dev, sgt->sgl, sgt->nents, direction);
+
+    sg_free_table(sgt);
+    kfree(sgt);
+}
+
+static int _dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+    gckVIDMEM_NODE nodeObject = dmabuf->priv;
+    gcuVIDMEM_NODE_PTR node = nodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gctPHYS_ADDR physical = gcvNULL;
+    gctSIZE_T skipPages = vma->vm_pgoff;
+    gctSIZE_T numPages = PAGE_ALIGN(vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        physical = node->VidMem.parent->physical;
+        skipPages += (node->VidMem.offset >> PAGE_SHIFT);
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        physical  = vidMemBlock->physical;
+        skipPages += (node->VirtualChunk.offset >> PAGE_SHIFT);
+    }
+    else
+    {
+        physical = node->Virtual.physical;
+    }
+
+    gcmkONERROR(gckOS_MemoryMmap(nodeObject->kernel->os, physical, skipPages, numPages, vma));
+
+OnError:
+    return gcmIS_ERROR(status) ? -EINVAL : 0;
+}
+
+static void _dmabuf_release(struct dma_buf *dmabuf)
+{
+    gckVIDMEM_NODE nodeObject = dmabuf->priv;
+
+    if (nodeObject->metadata.ts_dma_buf)
+    {
+        dma_buf_put(nodeObject->metadata.ts_dma_buf);
+        nodeObject->metadata.ts_dma_buf = NULL;
+    }
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(nodeObject->kernel, nodeObject));
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,5,7)
+static void *_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long offset)
+{
+    gckVIDMEM_NODE nodeObject = dmabuf->priv;
+    gcuVIDMEM_NODE_PTR node = nodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gctINT8_PTR kvaddr = gcvNULL;
+    gctPHYS_ADDR physical = gcvNULL;
+    gctSIZE_T bytes = 0;
+
+    offset = (offset << PAGE_SHIFT);
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        physical = node->VidMem.parent->physical;
+        offset += node->VidMem.offset;
+        bytes = node->VidMem.bytes;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        physical = vidMemBlock->physical;
+        offset += node->VirtualChunk.offset;
+        bytes = node->VirtualChunk.bytes;
+    }
+    else
+    {
+        physical = node->Virtual.physical;
+        bytes = node->Virtual.bytes;
+    }
+
+    if (gcmIS_SUCCESS(gckOS_CreateKernelMapping(
+            nodeObject->kernel->os, physical, 0, bytes, (gctPOINTER*)&kvaddr)))
+    {
+        kvaddr += offset;
+    }
+
+    return (gctPOINTER)kvaddr;
+}
+
+static void _dmabuf_kunmap(struct dma_buf *dmabuf, unsigned long offset, void *ptr)
+{
+    gckVIDMEM_NODE nodeObject = dmabuf->priv;
+    gcuVIDMEM_NODE_PTR node = nodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+    gctINT8_PTR kvaddr = (gctINT8_PTR)ptr - (offset << PAGE_SHIFT);
+    gctPHYS_ADDR physical = gcvNULL;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        physical = node->VidMem.parent->physical;
+        kvaddr -= node->VidMem.offset;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        physical = vidMemBlock->physical;
+        kvaddr -= node->VirtualChunk.offset;
+    }
+    else
+    {
+        physical = node->Virtual.physical;
+    }
+
+    gcmkVERIFY_OK(gckOS_DestroyKernelMapping(
+            nodeObject->kernel->os, physical, (gctPOINTER*)&kvaddr));
+}
+#endif
+
+static struct dma_buf_ops _dmabuf_ops =
+{
+    .map_dma_buf = _dmabuf_map,
+    .unmap_dma_buf = _dmabuf_unmap,
+    .mmap = _dmabuf_mmap,
+    .release = _dmabuf_release,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(5,5,7)
+#  elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)
+    .map = _dmabuf_kmap,
+    .unmap = _dmabuf_kunmap,
+#  elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+    .map_atomic = _dmabuf_kmap,
+    .unmap_atomic = _dmabuf_kunmap,
+    .map = _dmabuf_kmap,
+    .unmap = _dmabuf_kunmap,
+#  else
+    .kmap_atomic = _dmabuf_kmap,
+    .kunmap_atomic = _dmabuf_kunmap,
+    .kmap = _dmabuf_kmap,
+    .kunmap = _dmabuf_kunmap,
+#  endif
+};
+#endif
+
+gceSTATUS
+gckVIDMEM_NODE_Export(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctINT32 Flags,
+    OUT gctPOINTER *DmaBuf,
+    OUT gctINT32 *FD
+    )
+{
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+    gceSTATUS status = gcvSTATUS_OK;
+    struct dma_buf *dmabuf = gcvNULL;
+
+    gcmkHEADER_ARG("Kernel=%p NodeObject=0x%x", Kernel, NodeObject);
+
+    dmabuf = NodeObject->dmabuf;
+    if (!dmabuf)
+    {
+        gctSIZE_T bytes = 0;
+        gctPHYS_ADDR physical = gcvNULL;
+        gcuVIDMEM_NODE_PTR node = NodeObject->node;
+        gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+        if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+        {
+            physical = node->VidMem.parent->physical;
+            bytes = node->VidMem.bytes;
+            /* Align export size. when allocate memory from VIDMEM, the actual node size may not same with aligned size. */
+            bytes = bytes & ~(PAGE_SIZE - 1);
+        }
+        else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+        {
+            physical = vidMemBlock->physical;
+            bytes = node->VirtualChunk.bytes;
+        }
+        else
+        {
+            physical = node->Virtual.physical;
+            bytes = node->Virtual.bytes;
+        }
+
+        /* Donot really get SGT, just check if the allocator support GetSGT. */
+        gcmkONERROR(gckOS_MemoryGetSGT(Kernel->os, physical, 0, 0, NULL));
+
+        {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+            DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+            exp_info.ops = &_dmabuf_ops;
+            exp_info.size = bytes;
+            exp_info.flags = Flags;
+            exp_info.priv = NodeObject;
+            dmabuf = dma_buf_export(&exp_info);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+            dmabuf = dma_buf_export(NodeObject, &_dmabuf_ops, bytes, Flags, NULL);
+#else
+            dmabuf = dma_buf_export(NodeObject, &_dmabuf_ops, bytes, Flags);
+#endif
+        }
+
+        if (IS_ERR(dmabuf))
+        {
+            gcmkONERROR(gcvSTATUS_GENERIC_IO);
+        }
+
+        /* Reference this gckVIDMEM_NODE object. */
+        gckVIDMEM_NODE_Reference(Kernel, NodeObject);
+        NodeObject->dmabuf = dmabuf;
+    }
+
+    if (DmaBuf)
+    {
+        *DmaBuf = NodeObject->dmabuf;
+    }
+
+    if (FD)
+    {
+        gctINT fd = dma_buf_fd(dmabuf, Flags);
+
+        if (fd < 0)
+        {
+            gcmkONERROR(gcvSTATUS_GENERIC_IO);
+        }
+
+        *FD = fd;
+    }
+
+OnError:
+    gcmkFOOTER_ARG("*DmaBuf=%p *FD=0x%x", gcmOPT_POINTER(DmaBuf), gcmOPT_VALUE(FD));
+    return status;
+#else
+    gcmkFATAL("The kernel did NOT support CONFIG_DMA_SHARED_BUFFER");
+    return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Name(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT32 * Name
+    )
+{
+    gceSTATUS status;
+    gctUINT32 name      = 0;
+    gctPOINTER database = Kernel->db->nameDatabase;
+    gctPOINTER mutex    = Kernel->db->nameDatabaseMutex;
+    gctBOOL acquired    = gcvFALSE;
+    gctBOOL referenced  = gcvFALSE;
+    gcmkHEADER_ARG("Kernel=0x%X NodeObject=%p", Kernel, NodeObject);
+
+    gcmkVERIFY_ARGUMENT(Name != gcvNULL);
+
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, NodeObject));
+    referenced = gcvTRUE;
+
+    if (NodeObject->name == 0)
+    {
+        /* Name this node. */
+        gcmkONERROR(gckKERNEL_AllocateIntegerId(database, NodeObject, &name));
+        NodeObject->name = name;
+    }
+    else
+    {
+        name = NodeObject->name;
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, NodeObject));
+
+    *Name = name;
+
+    gcmkFOOTER_ARG("*Name=%d", *Name);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (referenced)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, NodeObject));
+    }
+
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Import(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Name,
+    OUT gckVIDMEM_NODE * NodeObject
+    )
+{
+    gceSTATUS status;
+    gckVIDMEM_NODE node = gcvNULL;
+    gctPOINTER database = Kernel->db->nameDatabase;
+    gctPOINTER mutex    = Kernel->db->nameDatabaseMutex;
+    gctBOOL acquired    = gcvFALSE;
+    gctBOOL referenced  = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name);
+
+    gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    /* Lookup in database to get the node. */
+    gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, (gctPOINTER *)&node));
+
+    /* Reference the node. */
+    gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, node));
+    referenced = gcvTRUE;
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    acquired = gcvFALSE;
+
+    *NodeObject = node;
+    gcmkFOOTER_ARG("*NodeObject=%p", node);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (referenced)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
+    }
+
+    if (acquired)
+    {
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+typedef struct _gcsVIDMEM_NODE_FDPRIVATE
+{
+    gcsFDPRIVATE   base;
+    gckKERNEL      kernel;
+    gckVIDMEM_NODE node;
+}
+gcsVIDMEM_NODE_FDPRIVATE;
+
+
+static gctINT
+_ReleaseFdPrivate(
+    gcsFDPRIVATE_PTR FdPrivate
+    )
+{
+    /* Cast private info. */
+    gcsVIDMEM_NODE_FDPRIVATE * private = (gcsVIDMEM_NODE_FDPRIVATE *) FdPrivate;
+
+    gckVIDMEM_NODE_Dereference(private->kernel, private->node);
+    gckOS_Free(private->kernel->os, private);
+
+    return 0;
+}
+
+
+/*******************************************************************************
+**
+**  gckVIDMEM_NODE_GetFd
+**
+**  Attach a gckVIDMEM_NODE object to a native fd.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Fd
+**          Pointer to a variable receiving a native fd from os.
+*/
+gceSTATUS
+gckVIDMEM_NODE_GetFd(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctINT * Fd
+    )
+{
+    gceSTATUS status;
+    gctBOOL referenced  = gcvFALSE;
+    gcsVIDMEM_NODE_FDPRIVATE * fdPrivate = gcvNULL;
+    gcmkHEADER_ARG("Kernel=0x%X NodeObject=%d", Kernel, NodeObject);
+
+    /* Reference node object. */
+    gcmkVERIFY_OK(gckVIDMEM_NODE_Reference(Kernel, NodeObject));
+    referenced = gcvTRUE;
+
+    /* Allocated fd owns a reference. */
+    gcmkONERROR(gckOS_Allocate(
+        Kernel->os,
+        gcmSIZEOF(gcsVIDMEM_NODE_FDPRIVATE),
+        (gctPOINTER *)&fdPrivate
+        ));
+
+    fdPrivate->base.release = _ReleaseFdPrivate;
+    fdPrivate->kernel = Kernel;
+    fdPrivate->node = NodeObject;
+
+    /* Allocated fd owns a reference. */
+    gcmkONERROR(gckOS_GetFd("vidmem", &fdPrivate->base, Fd));
+
+    gcmkFOOTER_ARG("*Fd=%d", *Fd);
+    return gcvSTATUS_OK;
+
+OnError:
+    if (referenced)
+    {
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, NodeObject));
+    }
+
+    if (fdPrivate)
+    {
+        gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, fdPrivate));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_WrapUserMemory(
+    IN gckKERNEL Kernel,
+    IN gcsUSER_MEMORY_DESC_PTR Desc,
+    IN gceVIDMEM_TYPE Type,
+    OUT gckVIDMEM_NODE * NodeObject,
+    OUT gctUINT64 * Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gctBOOL found = gcvFALSE;
+
+    gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+    gcmkVERIFY_ARGUMENT(Desc != gcvNULL);
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+    if (Desc->flag & gcvALLOC_FLAG_DMABUF)
+    {
+        struct dma_buf *dmabuf;
+        int fd = (int)Desc->handle;
+
+        if (fd >= 0)
+        {
+            /* Import dma buf handle. */
+            dmabuf = dma_buf_get(fd);
+
+            if (IS_ERR(dmabuf))
+                return PTR_ERR(dmabuf);
+
+            Desc->handle = -1;
+            Desc->dmabuf = gcmPTR_TO_UINT64(dmabuf);
+
+            dma_buf_put(dmabuf);
+        }
+        else
+        {
+            if (!Desc->dmabuf)
+            {
+                gcmkPRINT("Wrap user memory: invalid dmabuf from user.\n");
+
+                gcmkFOOTER();
+                return gcvSTATUS_INVALID_ARGUMENT;
+            }
+
+            dmabuf = gcmUINT64_TO_PTR(Desc->dmabuf);
+        }
+
+        if (dmabuf->ops == &_dmabuf_ops)
+        {
+            gctBOOL referenced = gcvFALSE;
+            nodeObject = dmabuf->priv;
+
+            do
+            {
+                /* Reference the node. */
+                gcmkERR_BREAK(gckVIDMEM_NODE_Reference(Kernel, nodeObject));
+                referenced = gcvTRUE;
+                found = gcvTRUE;
+
+                *NodeObject = nodeObject;
+                *Bytes = (gctUINT64)dmabuf->size;
+            }
+            while (gcvFALSE);
+
+            if (gcmIS_ERROR(status) && referenced)
+            {
+                gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, nodeObject));
+            }
+        }
+    }
+#endif
+
+    if (!found)
+    {
+        gckOS os = Kernel->os;
+        gcuVIDMEM_NODE_PTR node = gcvNULL;
+
+        do
+        {
+            gctSIZE_T pageCountCpu = 0;
+            gctSIZE_T pageSizeCpu = 0;
+            gctPHYS_ADDR_T physicalAddress = 0;
+
+            gcmkVERIFY_OK(gckOS_GetPageSize(os, &pageSizeCpu));
+
+            /* Allocate an gcuVIDMEM_NODE union. */
+            gcmkERR_BREAK(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER*)&node));
+            gckOS_ZeroMemory(node, gcmSIZEOF(gcuVIDMEM_NODE));
+
+            /* Initialize gcuVIDMEM_NODE union for virtual memory. */
+            node->Virtual.kernel = Kernel;
+
+            /* Wrap Memory. */
+            gcmkERR_BREAK(
+                gckOS_WrapMemory(os,
+                                 Desc,
+                                 &node->Virtual.bytes,
+                                 &node->Virtual.physical,
+                                 &node->Virtual.contiguous,
+                                 &pageCountCpu));
+
+            /* Get base physical address. */
+            gcmkERR_BREAK(
+                gckOS_GetPhysicalFromHandle(os,
+                                            node->Virtual.physical,
+                                            0,
+                                            &physicalAddress));
+
+            /* Allocate handle for this video memory. */
+            gcmkERR_BREAK(gckVIDMEM_NODE_Construct(
+                Kernel,
+                node,
+                Type,
+                gcvPOOL_VIRTUAL,
+                &nodeObject
+                ));
+
+            node->Virtual.pageCount = (pageCountCpu * pageSizeCpu -
+                    (physicalAddress & (pageSizeCpu - 1) & ~(4096 - 1))) >> 12;
+
+            *NodeObject = nodeObject;
+            *Bytes = (gctUINT64)node->Virtual.bytes;
+        }
+        while (gcvFALSE);
+
+        if (gcmIS_ERROR(status) && node)
+        {
+            /* Free the structure. */
+            gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+        }
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_SetCommitStamp(
+    IN gckKERNEL Kernel,
+    IN gceENGINE Engine,
+    IN gckVIDMEM_NODE NodeObject,
+    IN gctUINT64 CommitStamp
+    )
+{
+    NodeObject->sync[Engine].commitStamp = CommitStamp;
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_GetCommitStamp(
+    IN gckKERNEL Kernel,
+    IN gceENGINE Engine,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctUINT64_PTR CommitStamp
+    )
+{
+    *CommitStamp = NodeObject->sync[Engine].commitStamp;
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckVIDMEM_NODE_Find
+**
+**  Find gckVIDMEM_NODE object according to GPU address of specified core.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Kernel object, specifies core.
+**
+**      gctUINT32 Address
+**          GPU address to search.
+**
+**  OUTPUT:
+**
+**      gckVIDMEM_NODE * NodeObject
+**          Pointer to a variable hold found video memory node.
+**
+**      gctUINT32 * Offset
+**          The offset of specified GPU address in found video memory node.
+*/
+gceSTATUS
+gckVIDMEM_NODE_Find(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Address,
+    OUT gckVIDMEM_NODE * NodeObject,
+    OUT gctUINT32 * Offset
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_FOUND;
+    gckVIDMEM_NODE nodeObject = gcvNULL;
+    gcuVIDMEM_NODE_PTR node = gcvNULL;
+    gckVIDMEM_BLOCK vidMemBlock = gcvNULL;
+    gcsLISTHEAD_PTR pos;
+    gceHARDWARE_TYPE hwType;
+
+    gcmkVERIFY_OK(
+        gckKERNEL_GetHardwareType(Kernel,
+                                  &hwType));
+
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(Kernel->os,
+                           Kernel->db->videoMemListMutex,
+                           gcvINFINITE));
+
+    gcmkLIST_FOR_EACH(pos, &Kernel->db->videoMemList)
+    {
+        nodeObject = (gckVIDMEM_NODE)gcmCONTAINEROF(pos, struct _gcsVIDMEM_NODE, link);
+        node = nodeObject->node;
+        vidMemBlock = node->VirtualChunk.parent;
+
+        if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+        {
+            if (!node->VidMem.locked)
+            {
+                /* Don't check against unlocked node. */
+                continue;
+            }
+
+            if (Address >= node->VidMem.address &&
+                Address <= node->VidMem.address + node->VidMem.bytes - 1)
+            {
+                *NodeObject = nodeObject;
+
+                if (Offset)
+                {
+                    *Offset = Address - node->VidMem.address;
+                }
+
+                status = gcvSTATUS_OK;
+                break;
+            }
+        }
+        else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+        {
+            if (!node->VirtualChunk.lockeds[hwType])
+            {
+                /* Don't check against unlocked node. */
+                continue;
+            }
+
+            if (Address >= node->VirtualChunk.addresses[hwType] &&
+                Address <= node->VirtualChunk.addresses[hwType] + node->VirtualChunk.bytes - 1)
+            {
+                *NodeObject = nodeObject;
+
+                if (Offset)
+                {
+                    *Offset = Address - node->VirtualChunk.addresses[hwType];
+                }
+
+                status = gcvSTATUS_OK;
+                break;
+            }
+        }
+        else
+        {
+            if (!node->Virtual.lockeds[hwType])
+            {
+                /* Don't check against unlocked node. */
+                continue;
+            }
+
+            if (Address >= node->Virtual.addresses[hwType] &&
+                (Address <= node->Virtual.addresses[hwType] + node->Virtual.bytes - 1))
+            {
+                *NodeObject = nodeObject;
+
+                if (Offset)
+                {
+                    *Offset = Address - node->Virtual.addresses[hwType];
+                }
+
+                status = gcvSTATUS_OK;
+                break;
+            }
+        }
+    }
+
+    gcmkVERIFY_OK(
+        gckOS_ReleaseMutex(Kernel->os, Kernel->db->videoMemListMutex));
+
+    return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_IsContiguous(
+    IN gckKERNEL Kernel,
+    IN gckVIDMEM_NODE NodeObject,
+    OUT gctBOOL * Contiguous
+    )
+{
+    gceSTATUS status;
+    gckOS os = Kernel->os;
+    gctBOOL acquired = gcvFALSE;
+    gcuVIDMEM_NODE_PTR node = NodeObject->node;
+    gckVIDMEM_BLOCK vidMemBlock = node->VirtualChunk.parent;
+
+    gcmkHEADER();
+
+    /* Grab the mutex. */
+    gcmkONERROR(gckOS_AcquireMutex(os, NodeObject->mutex, gcvINFINITE));
+    acquired = gcvTRUE;
+
+    *Contiguous = gcvFALSE;
+
+    if (node->VidMem.parent->object.type == gcvOBJ_VIDMEM)
+    {
+        *Contiguous = gcvTRUE;
+    }
+    else if (vidMemBlock && vidMemBlock->object.type == gcvOBJ_VIDMEM_BLOCK)
+    {
+        if (vidMemBlock->contiguous)
+        {
+            *Contiguous = gcvTRUE;
+        }
+    }
+    else
+    {
+        if (node->Virtual.contiguous)
+        {
+            *Contiguous = gcvTRUE;
+        }
+    }
+
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(os, NodeObject->mutex));
+    }
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h
@@ -0,0 +1,21171 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+/*Auto created on 2020-11-13 13:24*/
+#ifndef _gc_feature_database_h_
+#define _gc_feature_database_h_
+
+typedef struct
+{
+    /* Chip ID. */
+    gctUINT32 chipID;
+    gctUINT32 chipVersion;
+    gctUINT32 productID;
+    gctUINT32 ecoID;
+    gctUINT32 customerID;
+    gctUINT32 patchVersion;
+    const char *productName;
+    gctUINT32 formalRelease;
+    gctUINT32 TempRegisters;
+    gctUINT32 ThreadCount;
+    gctUINT32 NumShaderCores;
+    gctUINT32 InstructionCount;
+    gctUINT32 NumberOfConstants;
+    gctUINT32 CoreCount;
+    gctUINT32 LocalStorageSize;
+    gctUINT32 LocalStorageSize_1;
+    gctUINT32 LocalStorageSize_2;
+    gctUINT32 L1CacheSize;
+    gctUINT32 L1CacheSize_1;
+    gctUINT32 L1CacheSize_2;
+    gctUINT32 InstructionMemorySize;
+    gctUINT32 ShaderPCLength;
+    gctUINT32 USC_MAX_PAGES;
+    gctUINT32 USC_MAX_PAGES_1;
+    gctUINT32 USC_MAX_PAGES_2;
+    gctUINT32 NumPixelPipes;
+    gctUINT32 USC_CACHE_CONTROLLERS;
+    gctUINT32 USC_CACHE_CONTROLLERS_1;
+    gctUINT32 USC_CACHE_CONTROLLERS_2;
+    gctUINT32 USC_BANKS;
+    gctUINT32 USC_BANKS_1;
+    gctUINT32 USC_BANKS_2;
+    gctUINT32 Streams;
+    gctUINT32 VaryingCount;
+    gctUINT32 VertexOutputBufferSize;
+    gctUINT32 BufferSize;
+    gctUINT32 VertexCacheSize;
+    gctUINT32 NumResolvePipes;
+    gctUINT32 RESULT_WINDOW_MAX_SIZE;
+    gctUINT32 ClusterAliveMask;
+    gctUINT32 G2D_DEC400_MINOR;
+    gctUINT32 NNMadPerCore;
+    gctUINT32 NNCoreCount;
+    gctUINT32 NNCoreCount_INT8;
+    gctUINT32 NNCoreCount_INT16;
+    gctUINT32 NNCoreCount_FLOAT16;
+    gctUINT32 NNCoreCount_BFLOAT;
+    gctUINT32 NNInputBufferDepth;
+    gctUINT32 NNAccumBufferDepth;
+    gctUINT32 TPEngine_PwlLUTCount;
+    gctUINT32 TPEngine_PwlLUTSize;
+    gctUINT32 VIP_SRAM_SIZE;
+    gctUINT32 TPEngine_CoreCount;
+    gctUINT32 AXI_SRAM_SIZE;
+    gctUINT32 NN_INIMAGE_OFFSET_BITS;
+    gctUINT32 TP_REORDER_INIMAGE_SIZE;
+    gctUINT32 TPLite_CoreCount;
+    gctUINT32 NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE;
+    gctUINT32 NNFP16_XYDP_X;
+    gctUINT32 NNFP16_XYDP_Y;
+    gctUINT32 NNFP16_ZDP;
+    gctUINT32 NN_LANES_PER_OUT_CYCLE;
+    gctUINT32 MAX_OT_NUMBER;
+    gctUINT32 PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE;
+    gctUINT32 EQUIVALENT_VIP_SRAM_WIDTH_INBYTE;
+    gctUINT32 TP_ZRL_BITS;
+    gctUINT32 NN_ZRL_BITS;
+    gctUINT32 LATENCY_HIDING_AT_FULL_AXI_BW;
+    gctUINT32 AXI_BUS_WIDTH;
+    gctUINT32 NN_KERNEL_X_SIZE;
+    gctUINT32 NN_KERNEL_Y_SIZE;
+    gctUINT32 NN_FC_KERNEL_Y_SIZE;
+    gctUINT32 NN_KERNEL_Z_SIZE;
+    gctUINT32 NN_X_OFFSET;
+    gctUINT32 NN_Y_OFFSET;
+    gctUINT32 DDR_KERNEL_BURST_SIZE;
+    gctUINT32 OUTIMAGE_X_STRIDE_BITS;
+    gctUINT32 OUTIMAGE_Y_STRIDE_BITS;
+    gctUINT32 INIMAGE_X_STRIDE_BITS;
+    gctUINT32 IMIMAGE_Y_STRIDE_BITS;
+    gctUINT32 OUTIMAGE_X_SIZE_BITS;
+    gctUINT32 OUTIMAGE_Y_SIZE_BITS;
+    gctUINT32 OUTIMAGE_Z_SIZE_BITS;
+    gctUINT32 INIMAGE_X_SIZE_BITS;
+    gctUINT32 INIMAGE_Y_SIZE_BITS;
+    gctUINT32 MAX_TILE_X_SIZE;
+    gctUINT32 NN_CLUSTER_NUM_FOR_POWER_CONTROL;
+    gctUINT32 NN_IN_LINES_PER_CYCLE;
+    gctUINT32 REG_FastClear:1;
+    gctUINT32 REG_SpecialAntiAliasing:1;
+    gctUINT32 REG_Pipe3D:1;
+    gctUINT32 REG_DXTTextureCompression:1;
+    gctUINT32 REG_DebugMode:1;
+    gctUINT32 REG_ZCompression:1;
+    gctUINT32 REG_YUV420Filter:1;
+    gctUINT32 REG_MSAA:1;
+    gctUINT32 REG_DC:1;
+    gctUINT32 REG_Pipe2D:1;
+    gctUINT32 REG_ETC1TextureCompression:1;
+    gctUINT32 REG_FastScaler:1;
+    gctUINT32 REG_HighDynamicRange:1;
+    gctUINT32 REG_YUV420Tiler:1;
+    gctUINT32 REG_ModuleCG:1;
+    gctUINT32 REG_MinArea:1;
+    gctUINT32 REG_NoEZ:1;
+    gctUINT32 REG_No422Texture:1;
+    gctUINT32 REG_BufferInterleaving:1;
+    gctUINT32 REG_ByteWrite2D:1;
+    gctUINT32 REG_NoScaler:1;
+    gctUINT32 REG_YUY2Averaging:1;
+    gctUINT32 REG_HalfPECache:1;
+    gctUINT32 REG_HalfTXCache:1;
+    gctUINT32 REG_YUY2RenderTarget:1;
+    gctUINT32 REG_Mem32BitSupport:1;
+    gctUINT32 REG_PipeVG:1;
+    gctUINT32 REG_VGTS:1;
+    gctUINT32 REG_FE20:1;
+    gctUINT32 REG_ByteWrite3D:1;
+    gctUINT32 REG_RsYuvTarget:1;
+    gctUINT32 REG_FE20BitIndex:1;
+    gctUINT32 REG_FlipY:1;
+    gctUINT32 REG_DualReturnBus:1;
+    gctUINT32 REG_EndiannessConfig:1;
+    gctUINT32 REG_Texture8K:1;
+    gctUINT32 REG_CorrectTextureConverter:1;
+    gctUINT32 REG_SpecialMsaaLod:1;
+    gctUINT32 REG_FastClearFlush:1;
+    gctUINT32 REG_2DPE20:1;
+    gctUINT32 REG_CorrectAutoDisable:1;
+    gctUINT32 REG_Render8K:1;
+    gctUINT32 REG_TileStatus2Bits:1;
+    gctUINT32 REG_SeparateTileStatusWhenInterleaved:1;
+    gctUINT32 REG_SuperTiled32x32:1;
+    gctUINT32 REG_VG20:1;
+    gctUINT32 REG_TSExtendedCommands:1;
+    gctUINT32 REG_CompressionFifoFixed:1;
+    gctUINT32 REG_ExtraShaderInstructions0:1;
+    gctUINT32 REG_VGFilter:1;
+    gctUINT32 REG_VG21:1;
+    gctUINT32 REG_ShaderGetsW:1;
+    gctUINT32 REG_ExtraShaderInstructions1:1;
+    gctUINT32 REG_DefaultReg0:1;
+    gctUINT32 REG_MC20:1;
+    gctUINT32 REG_ShaderMSAASideband:1;
+    gctUINT32 REG_BugFixes0:1;
+    gctUINT32 REG_VAA:1;
+    gctUINT32 REG_BypassInMSAA:1;
+    gctUINT32 REG_HierarchicalZ:1;
+    gctUINT32 REG_NewTexture:1;
+    gctUINT32 REG_A8TargetSupport:1;
+    gctUINT32 REG_CorrectStencil:1;
+    gctUINT32 REG_EnhanceVR:1;
+    gctUINT32 REG_RSUVSwizzle:1;
+    gctUINT32 REG_V2Compression:1;
+    gctUINT32 REG_VGDoubleBuffer:1;
+    gctUINT32 REG_BugFixes1:1;
+    gctUINT32 REG_BugFixes2:1;
+    gctUINT32 REG_TextureStride:1;
+    gctUINT32 REG_BugFixes3:1;
+    gctUINT32 REG_CorrectAutoDisable1:1;
+    gctUINT32 REG_AutoRestartTS:1;
+    gctUINT32 REG_BugFixes4:1;
+    gctUINT32 REG_L2Windowing:1;
+    gctUINT32 REG_HalfFloatPipe:1;
+    gctUINT32 REG_PixelDither:1;
+    gctUINT32 REG_TwoStencilReference:1;
+    gctUINT32 REG_ExtendedPixelFormat:1;
+    gctUINT32 REG_CorrectMinMaxDepth:1;
+    gctUINT32 REG_DitherAndFilterPlusAlpha2D:1;
+    gctUINT32 REG_BugFixes5:1;
+    gctUINT32 REG_New2D:1;
+    gctUINT32 REG_NewFloatingPointArithmetic:1;
+    gctUINT32 REG_TextureHorizontalAlignmentSelect:1;
+    gctUINT32 REG_NonPowerOfTwo:1;
+    gctUINT32 REG_LinearTextureSupport:1;
+    gctUINT32 REG_Halti0:1;
+    gctUINT32 REG_CorrectOverflowVG:1;
+    gctUINT32 REG_NegativeLogFix:1;
+    gctUINT32 REG_ResolveOffset:1;
+    gctUINT32 REG_OkToGateAxiClock:1;
+    gctUINT32 REG_MMU:1;
+    gctUINT32 REG_WideLine:1;
+    gctUINT32 REG_BugFixes6:1;
+    gctUINT32 REG_FcFlushStall:1;
+    gctUINT32 REG_LineLoop:1;
+    gctUINT32 REG_LogicOp:1;
+    gctUINT32 REG_SeamlessCubeMap:1;
+    gctUINT32 REG_SuperTiledTexture:1;
+    gctUINT32 REG_LinearPE:1;
+    gctUINT32 REG_RectPrimitive:1;
+    gctUINT32 REG_Composition:1;
+    gctUINT32 REG_CorrectAutoDisableCountWidth:1;
+    gctUINT32 REG_PESwizzle:1;
+    gctUINT32 REG_EndEvent:1;
+    gctUINT32 REG_S1S8:1;
+    gctUINT32 REG_Halti1:1;
+    gctUINT32 REG_RGB888:1;
+    gctUINT32 REG_TX_YUVAssembler:1;
+    gctUINT32 REG_DynamicFrequencyScaling:1;
+    gctUINT32 REG_TXFilter:1;
+    gctUINT32 REG_FullDirectFB:1;
+    gctUINT32 REG_OnePass2DFilter:1;
+    gctUINT32 REG_ThreadWalkerInPS:1;
+    gctUINT32 REG_TileFiller:1;
+    gctUINT32 REG_YUVStandard:1;
+    gctUINT32 REG_MultiSourceBlt:1;
+    gctUINT32 REG_YUVConversion:1;
+    gctUINT32 REG_FlushFixed2D:1;
+    gctUINT32 REG_Interleaver:1;
+    gctUINT32 REG_MixedStreams:1;
+    gctUINT32 REG_L2CacheFor2D420:1;
+    gctUINT32 REG_BugFixes7:1;
+    gctUINT32 REG_NoIndexPattern:1;
+    gctUINT32 REG_TextureTileStatus:1;
+    gctUINT32 REG_DecompressZ16:1;
+    gctUINT32 REG_BugFixes8:1;
+    gctUINT32 REG_DERotationStallFix:1;
+    gctUINT32 REG_OclOnly:1;
+    gctUINT32 REG_NewFeatures0:1;
+    gctUINT32 REG_InstructionCache:1;
+    gctUINT32 REG_GeometryShader:1;
+    gctUINT32 REG_TexCompressionSupertiled:1;
+    gctUINT32 REG_Generics:1;
+    gctUINT32 REG_BugFixes9:1;
+    gctUINT32 REG_FastMSAA:1;
+    gctUINT32 REG_WClip:1;
+    gctUINT32 REG_BugFixes10:1;
+    gctUINT32 REG_UnifiedSamplers:1;
+    gctUINT32 REG_BugFixes11:1;
+    gctUINT32 REG_PerformanceCounters:1;
+    gctUINT32 REG_ExtraShaderInstructions2:1;
+    gctUINT32 REG_BugFixes12:1;
+    gctUINT32 REG_BugFixes13:1;
+    gctUINT32 REG_DEEnhancements1:1;
+    gctUINT32 REG_ACE:1;
+    gctUINT32 REG_TXEnhancements1:1;
+    gctUINT32 REG_SHEnhancements1:1;
+    gctUINT32 REG_SHEnhancements2:1;
+    gctUINT32 REG_PEEnhancements1:1;
+    gctUINT32 REG_DEEnhancements2:1;
+    gctUINT32 REG_BugFixes14:1;
+    gctUINT32 REG_PowerOptimizations0:1;
+    gctUINT32 REG_NewHZ:1;
+    gctUINT32 REG_BugFixes15:1;
+    gctUINT32 REG_DEEnhancements3:1;
+    gctUINT32 REG_SHEnhancements3:1;
+    gctUINT32 REG_SHEnhancements4:1;
+    gctUINT32 REG_TXEnhancements2:1;
+    gctUINT32 REG_FEEnhancements1:1;
+    gctUINT32 REG_PEEnhancements2:1;
+    gctUINT32 REG_PAEnhancements1:1;
+    gctUINT32 REG_DENoGamma:1;
+    gctUINT32 REG_PAEnhancements2:1;
+    gctUINT32 REG_DEEnhancements4:1;
+    gctUINT32 REG_PEEnhancements3:1;
+    gctUINT32 REG_HIEnhancements1:1;
+    gctUINT32 REG_TXEnhancements3:1;
+    gctUINT32 REG_SHEnhancements5:1;
+    gctUINT32 REG_FEEnhancements2:1;
+    gctUINT32 REG_BugFixes16:1;
+    gctUINT32 REG_DEEnhancements5:1;
+    gctUINT32 REG_TXEnhancements4:1;
+    gctUINT32 REG_PEEnhancements4:1;
+    gctUINT32 REG_MCEnhancements1:1;
+    gctUINT32 REG_Halti2:1;
+    gctUINT32 REG_DEMirrorRotate:1;
+    gctUINT32 REG_SmallMSAA:1;
+    gctUINT32 REG_BugFixes17:1;
+    gctUINT32 REG_Rasterizer2:1;
+    gctUINT32 REG_DualPipeOPF:1;
+    gctUINT32 REG_MultiSrcV2:1;
+    gctUINT32 REG_CSCV2:1;
+    gctUINT32 REG_PAEnhancements3:1;
+    gctUINT32 REG_BugFixes18:1;
+    gctUINT32 REG_Compression2D:1;
+    gctUINT32 REG_Probe:1;
+    gctUINT32 REG_MediumPrecision:1;
+    gctUINT32 REG_DESupertile:1;
+    gctUINT32 REG_BugFixes19:1;
+    gctUINT32 REG_SHEnhancements6:1;
+    gctUINT32 REG_SHEnhancements7:1;
+    gctUINT32 REG_BugFixes20:1;
+    gctUINT32 REG_DEAddress40:1;
+    gctUINT32 REG_MiniMMUFix:1;
+    gctUINT32 REG_EEZ:1;
+    gctUINT32 REG_BugFixes21:1;
+    gctUINT32 REG_ExtraVgCaps:1;
+    gctUINT32 REG_MultiSrcV15:1;
+    gctUINT32 REG_BugFixes22:1;
+    gctUINT32 REG_Halti3:1;
+    gctUINT32 REG_TessellationShaders:1;
+    gctUINT32 REG_OPF9Tap:1;
+    gctUINT32 REG_MultiSrcV2StrQuad:1;
+    gctUINT32 REG_SeperateSRCAndDstCache:1;
+    gctUINT32 REG_Halti4:1;
+    gctUINT32 REG_RAWriteDepth:1;
+    gctUINT32 REG_AndroidOnly:1;
+    gctUINT32 REG_HasChipProductReg:1;
+    gctUINT32 REG_TXSupportDEC:1;
+    gctUINT32 REG_S8MSAACompression:1;
+    gctUINT32 REG_BugFixesIn544:1;
+    gctUINT32 REG_L2CacheRemove:1;
+    gctUINT32 REG_FEAllowRndVtxCnt:1;
+    gctUINT32 REG_CubeMapFL28:1;
+    gctUINT32 REG_TX6bitFrac:1;
+    gctUINT32 REG_FEAllowStallPrefetchEng:1;
+    gctUINT32 REG_ThirdPartyCompression:1;
+    gctUINT32 REG_RSS8:1;
+    gctUINT32 REG_MSAACoherencyCheck:1;
+    gctUINT32 REG_Halti5:1;
+    gctUINT32 REG_Evis:1;
+    gctUINT32 REG_BltEngine:1;
+    gctUINT32 REG_BugFixes23:1;
+    gctUINT32 REG_BugFixes24:1;
+    gctUINT32 REG_DEC:1;
+    gctUINT32 REG_VSTileNV12:1;
+    gctUINT32 REG_VSTileNV12_10BIT:1;
+    gctUINT32 REG_DisableVIP:1;
+    gctUINT32 RenderTarget8:1;
+    gctUINT32 TxLodFlowCorrection:1;
+    gctUINT32 FaceLod:1;
+    gctUINT32 MultiCoreSemaphoreStallV2:1;
+    gctUINT32 VMSAA:1;
+    gctUINT32 ChipEnableLink:1;
+    gctUINT32 MULTI_SRC_BLT_1_5_ENHANCEMENT:1;
+    gctUINT32 MULTI_SRC_BLT_BILINEAR_FILTER:1;
+    gctUINT32 RA_HZEZ_CLOCK_CONTROL:1;
+    gctUINT32 CACHE128B256BPERLINE:1;
+    gctUINT32 V4Compression:1;
+    gctUINT32 DE2D_MAJOR_SUPER_TILE:1;
+    gctUINT32 PE2D_MAJOR_SUPER_TILE:1;
+    gctUINT32 PE_32BPC_COLORMASK_FIX:1;
+    gctUINT32 ALPHA_BLENDING_OPT:1;
+    gctUINT32 NEW_GPIPE:1;
+    gctUINT32 PIPELINE_32_ATTRIBUTES:1;
+    gctUINT32 MSAA_SHADING:1;
+    gctUINT32 NO_ANISTRO_FILTER:1;
+    gctUINT32 NO_ASTC:1;
+    gctUINT32 NO_DXT:1;
+    gctUINT32 HWTFB:1;
+    gctUINT32 RA_DEPTH_WRITE_MSAA1X_FIX:1;
+    gctUINT32 EZHZ_CLOCKGATE_FIX:1;
+    gctUINT32 SH_SNAP2PAGE_FIX:1;
+    gctUINT32 SH_HALFDEPENDENCY_FIX:1;
+    gctUINT32 USC_MCFILL_FIX:1;
+    gctUINT32 TPG_TCPERF_FIX:1;
+    gctUINT32 USC_MDFIFO_OVERFLOW_FIX:1;
+    gctUINT32 SH_TEXLD_BARRIER_IN_CS_FIX:1;
+    gctUINT32 RS_NEW_BASEADDR:1;
+    gctUINT32 PE_8bpp_DUALPIPE_FIX:1;
+    gctUINT32 SH_ADVANCED_INSTR:1;
+    gctUINT32 SH_FLAT_INTERPOLATION_DUAL16_FIX:1;
+    gctUINT32 USC_CONTINUOUS_FLUS_FIX:1;
+    gctUINT32 SH_SUPPORT_V4:1;
+    gctUINT32 SH_SUPPORT_ALPHA_KILL:1;
+    gctUINT32 PE_NO_ALPHA_TEST:1;
+    gctUINT32 TX_LOD_NEAREST_SELECT:1;
+    gctUINT32 SH_FIX_LDEXP:1;
+    gctUINT32 SUPPORT_MOVAI:1;
+    gctUINT32 SH_SNAP2PAGE_MAXPAGES_FIX:1;
+    gctUINT32 PE_RGBA16I_FIX:1;
+    gctUINT32 BLT_8bpp_256TILE_FC_FIX:1;
+    gctUINT32 PE_64bit_FENCE_FIX:1;
+    gctUINT32 USC_FULL_CACHE_FIX:1;
+    gctUINT32 TX_YUV_ASSEMBLER_10BIT:1;
+    gctUINT32 FE_32bit_INDEX_FIX:1;
+    gctUINT32 BLT_64bpp_MASKED_CLEAR_FIX:1;
+    gctUINT32 SECURITY:1;
+    gctUINT32 ROBUSTNESS:1;
+    gctUINT32 USC_ATOMIC_FIX:1;
+    gctUINT32 SH_PSO_MSAA1x_FIX:1;
+    gctUINT32 USC_VX_PERF_FIX:1;
+    gctUINT32 USC_GOS_ADDR_FIX:1;
+    gctUINT32 TX_8bit_UVFrac:1;
+    gctUINT32 TX_DESC_CACHE_CLOCKGATE_FIX:1;
+    gctUINT32 RSBLT_MSAA_DECOMPRESSION:1;
+    gctUINT32 TX_INTEGER_COORDINATE:1;
+    gctUINT32 DRAWID:1;
+    gctUINT32 PSIO_SAMPLEMASK_IN_R0ZW_FIX:1;
+    gctUINT32 TX_INTEGER_COORDINATE_V2:1;
+    gctUINT32 MULTI_CORE_BLOCK_SET_CONFIG:1;
+    gctUINT32 SNAPPAGE_CMD:1;
+    gctUINT32 SH_NO_INDEX_CONST_ON_A0:1;
+    gctUINT32 SH_NO_ONECONST_LIMIT:1;
+    gctUINT32 SH_IMG_LDST_ON_TEMP:1;
+    gctUINT32 COMPUTE_ONLY:1;
+    gctUINT32 SH_IMG_LDST_CLAMP:1;
+    gctUINT32 SH_ICACHE_ALLOC_COUNT_FIX:1;
+    gctUINT32 SH_ICACHE_PREFETCH:1;
+    gctUINT32 PE2D_SEPARATE_CACHE:1;
+    gctUINT32 PE_MSAA_OQ_FIX:1;
+    gctUINT32 PSIO_MSAA_CL_FIX:1;
+    gctUINT32 USC_DEFER_FILL_FIX:1;
+    gctUINT32 SH_CLOCK_GATE_FIX:1;
+    gctUINT32 FE_NEED_DUMMYDRAW:1;
+    gctUINT32 PE2D_LINEAR_YUV420_OUTPUT:1;
+    gctUINT32 PE2D_LINEAR_YUV420_10BIT:1;
+    gctUINT32 MULTI_CLUSTER:1;
+    gctUINT32 SH_MULTI_WG_PACK:1;
+    gctUINT32 SH_DUAL16_SAMPLEMASK_ZW:1;
+    gctUINT32 TPG_TRIVIAL_MODE_FIX:1;
+    gctUINT32 TX_ASTC_MULTISLICE_FIX:1;
+    gctUINT32 FE_ROBUST_FIX:1;
+    gctUINT32 SH_GPIPE_ACCESS_FULLTEMPS:1;
+    gctUINT32 PSIO_INTERLOCK:1;
+    gctUINT32 PA_WIDELINE_FIX:1;
+    gctUINT32 WIDELINE_HELPER_FIX:1;
+    gctUINT32 G2D_3rd_PARTY_COMPRESSION_1_1:1;
+    gctUINT32 TX_FLUSH_L1CACHE:1;
+    gctUINT32 PE_DITHER_FIX2:1;
+    gctUINT32 SH_TEXLD_U_FIX:1;
+    gctUINT32 MC_FCCACHE_BYTEMASK:1;
+    gctUINT32 SH_MULTI_WG_PACK_FIX:1;
+    gctUINT32 PE_ADVANCE_BLEND_PART0:1;
+    gctUINT32 FE_PATCHLIST_FETCH_FIX:1;
+    gctUINT32 RA_CG_FIX:1;
+    gctUINT32 DEC400:1;
+    gctUINT32 LS_SUPPORT_PERCOMP_DEPENDENCY:1;
+    gctUINT32 MULTI_CORE_BLOCK_SET_CONFIG2:1;
+    gctUINT32 PE_VMSAA_COVERAGE_CACHE_FIX:1;
+    gctUINT32 SECURITY_AHB:1;
+    gctUINT32 MULTICORE_SEMAPHORESTALL_V3:1;
+    gctUINT32 SMALLBATCH:1;
+    gctUINT32 SH_CMPLX:1;
+    gctUINT32 SH_IDIV0_SWZL_EHS:1;
+    gctUINT32 TX_LERP_LESS_BIT:1;
+    gctUINT32 SH_GM_ENDIAN:1;
+    gctUINT32 SH_GM_USC_UNALLOC:1;
+    gctUINT32 SH_END_OF_BB:1;
+    gctUINT32 TX_BORDER_CLAMP_FIX:1;
+    gctUINT32 SH_IMG_LD_LASTPIXEL_FIX:1;
+    gctUINT32 ASYNC_BLT:1;
+    gctUINT32 ASYNC_FE_FENCE_FIX:1;
+    gctUINT32 PSCS_THROTTLE:1;
+    gctUINT32 SEPARATE_LS:1;
+    gctUINT32 WIDELINE_TRIANGLE_EMU:1;
+    gctUINT32 FENCE_32BIT:1;
+    gctUINT32 FENCE_64BIT:1;
+    gctUINT32 PE_DEPTH_ONLY_OQFIX:1;
+    gctUINT32 TX_SEAMLESS_CUBE:1;
+    gctUINT32 TX_SNORM_SUPPORT:1;
+    gctUINT32 SH_SCATTER_GATHER:1;
+    gctUINT32 HWMANAGED_LS:1;
+    gctUINT32 SH_IMAGE_ENABLE_FIX:1;
+    gctUINT32 MSAA_FRAGMENT_OPERATION:1;
+    gctUINT32 PE_TILE_CACHE_FLUSH_FIX:1;
+    gctUINT32 BLT_YUV_OUTPUT:1;
+    gctUINT32 SH_IO_CG_FIX:1;
+    gctUINT32 PE_SWIZZLE:1;
+    gctUINT32 SH_ROBUSTNESS_FIX:1;
+    gctUINT32 USC_ATOMIC_FIX2:1;
+    gctUINT32 PE_A8B8G8R8:1;
+    gctUINT32 MULTIVIEW_RENDER:1;
+    gctUINT32 FE_DRAW_DIRECT:1;
+    gctUINT32 TX_VKBORDER_MODE:1;
+    gctUINT32 TX_UNNORMALIZED_COORD:1;
+    gctUINT32 PA_LINECLIP_FIX:1;
+    gctUINT32 TX_8bit_UVFrac_ROUNDING_FIX:1;
+    gctUINT32 MP_ARCH:1;
+    gctUINT32 TX_NO_FIXED_FILTER:1;
+    gctUINT32 SHARE_Z:1;
+    gctUINT32 DE_2D_FAST_CLEAR:1;
+    gctUINT32 DE_TILESTATUS_ROTATION_FIX:1;
+    gctUINT32 TX_CLEAR_PENDING_FIX:1;
+    gctUINT32 HI1_L2_CACHE:1;
+    gctUINT32 USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX:1;
+    gctUINT32 FORMAT_10BIT_CROSS_4K:1;
+    gctUINT32 FORMAT_P010LSB_I010:1;
+    gctUINT32 ENDIAN_CONTROL:1;
+    gctUINT32 G2D_RGB_PLANAR:1;
+    gctUINT32 G2D_DEC400EX:1;
+    gctUINT32 G2D_NO_YUV420_SOURCE:1;
+    gctUINT32 G2D_YUV420_101010:1;
+    gctUINT32 SH_VX2_FLOATING_MAD_FIX:1;
+    gctUINT32 TS_FC_VULKAN_SUPPORT:1;
+    gctUINT32 MSAA_FLOAT_64BIT:1;
+    gctUINT32 INDIRECT_COMPUTE_ZERODIM_FIX:1;
+    gctUINT32 Q_CHANNEL_SUPPORT:1;
+    gctUINT32 MMU_PAGE_DESCRIPTOR:1;
+    gctUINT32 YUV_LINEAR_TO_TILE_ROTATE:1;
+    gctUINT32 VEC2_IMULIMAD32_SUPPORT:1;
+    gctUINT32 VEC4_IMULIMAD32_SUPPORT:1;
+    gctUINT32 VEC2_IDIVIMOD16_SUPPORT:1;
+    gctUINT32 DST_TEX_I2F_F2I_INST_DEPRECATE:1;
+    gctUINT32 ALU_FP16_INSTRUCTIONS:1;
+    gctUINT32 DUAL16_14BIT_PC_SUPPORT:1;
+    gctUINT32 LDST_CONV_4ROUNDING_MODES:1;
+    gctUINT32 FULL_PACK_MODE_SUPPORT:1;
+    gctUINT32 DEPTH_FLOAT32_SUPPORT:1;
+    gctUINT32 FP32_TO_FP16_CONV_FIX:1;
+    gctUINT32 VG_TS_CULLING:1;
+    gctUINT32 VG_FP25:1;
+    gctUINT32 VG_AYUV_INPUT_OUTPUT:1;
+    gctUINT32 VG_DOUBLE_IMAGE:1;
+    gctUINT32 VG_RECTANGLE_STRIPE_MODE:1;
+    gctUINT32 VG_MMU:1;
+    gctUINT32 VG_IM_FILTER:1;
+    gctUINT32 VG_IM_YUV_PACKET:1;
+    gctUINT32 VG_IM_YUV_PLANAR:1;
+    gctUINT32 VG_PE_YUV_PACKET:1;
+    gctUINT32 VG_COLOR_PRECISION_8_BIT:1;
+    gctUINT32 VG_RESOLVE_ENGINE:1;
+    gctUINT32 VG_PE_COLOR_KEY:1;
+    gctUINT32 VG_IM_INDEX_FORMAT:1;
+    gctUINT32 VG_RESOLUTION_8K:1;
+    gctUINT32 VG_IMAGE_16K:1;
+    gctUINT32 VG_FORMAT_ARGB2222:1;
+    gctUINT32 G2D_DEC400:1;
+    gctUINT32 DC_OVERLAY_SCALING:1;
+    gctUINT32 DC_SOURCE_ROTATION:1;
+    gctUINT32 DC_TILED:1;
+    gctUINT32 DC_YUV_L1:1;
+    gctUINT32 DC_D30_OUTPUT:1;
+    gctUINT32 DC_MMU:1;
+    gctUINT32 DC_COMPRESSION:1;
+    gctUINT32 DC_QOS:1;
+    gctUINT32 VIP_HW_FINAL_RELEASE:1;
+    gctUINT32 NN_SINGLEPORT_ACCUMBUFFER:1;
+    gctUINT32 NN_STRIDE_SUPPORT:1;
+    gctUINT32 SWTILING_PHASE1:1;
+    gctUINT32 SWTILING_PHASE2:1;
+    gctUINT32 TP_SIMPLE_INT16:1;
+    gctUINT32 TP_REAL_INT16:1;
+    gctUINT32 TP_ROI_POOLING:1;
+    gctUINT32 TP_MAX_POOLING_STRIDE1:1;
+    gctUINT32 TP_LRN:1;
+    gctUINT32 TP_REORDER:1;
+    gctUINT32 TF_QUANTIZATION:1;
+    gctUINT32 NN_NONZERO_BORDER:1;
+    gctUINT32 NN_MIRROR_BORDER:1;
+    gctUINT32 AI_GPU:1;
+    gctUINT32 EVIS_NO_ABSDIFF:1;
+    gctUINT32 EVIS_NO_BITREPLACE:1;
+    gctUINT32 EVIS_NO_BOXFILTER:1;
+    gctUINT32 EVIS_NO_CORDIAC:1;
+    gctUINT32 EVIS_NO_DP32:1;
+    gctUINT32 EVIS_NO_FILTER:1;
+    gctUINT32 EVIS_NO_IADD:1;
+    gctUINT32 EVIS_NO_SELECTADD:1;
+    gctUINT32 EVIS_LERP_7OUTPUT:1;
+    gctUINT32 EVIS_ACCSQ_8OUTPUT:1;
+    gctUINT32 EVIS_VX2:1;
+    gctUINT32 TP_ENGINE:1;
+    gctUINT32 VIP_V7:1;
+    gctUINT32 TP_TENSOR_ADD_MUL:1;
+    gctUINT32 NN_DEPTHWISE_INT16XINT8:1;
+    gctUINT32 NN_DEPTHWISE_8BIT_VIP_V7:1;
+    gctUINT32 TP_SOFTMAX:1;
+    gctUINT32 NN_23BITS_POST_MULTIPLIER_VIP_V7:1;
+    gctUINT32 TP_23BITS_POST_MULTIPLIER_VIP_V7:1;
+    gctUINT32 CONV_INT16X8BIT_VIP_V7:1;
+    gctUINT32 NN_REMOVE_POOLING:1;
+    gctUINT32 NN_40BIT_BIAS:1;
+    gctUINT32 TP_REMOVE_USC:1;
+    gctUINT32 NN_ZDP6:1;
+    gctUINT32 NN_XYDP9:1;
+    gctUINT32 NN_FIRST_PIXEL_POOLING:1;
+    gctUINT32 NN_ZDP3:1;
+    gctUINT32 NN_XYDP6:1;
+    gctUINT32 SWTILING_PHASE3:1;
+    gctUINT32 MCFE:1;
+    gctUINT32 USC_STAY_LRU:1;
+    gctUINT32 COEF_COMPRESSION_ENHANCEMENT:1;
+    gctUINT32 TP_COEF_COMPRESSION_ENHANCEMENT:1;
+    gctUINT32 NN_COEF_DECOMPRESS_PERF2X:1;
+    gctUINT32 TP_SMALLBATCH_PHASE1:1;
+    gctUINT32 OCB_COUNTER:1;
+    gctUINT32 SCALER:1;
+    gctUINT32 SCALER_4K:1;
+    gctUINT32 INPUT_4BIT:1;
+    gctUINT32 NN_NO_Z_LOCATION_OFFSET:1;
+    gctUINT32 OCB_REMAP_PHYSICAL_ADDRESS:1;
+    gctUINT32 NN_SLOW_OUTPUT:1;
+    gctUINT32 NO_NARROW_POST_PROCESS_PIPE:1;
+    gctUINT32 TP_NN_PROBE:1;
+    gctUINT32 NN_DEPTHWISE_SUPPORT:1;
+    gctUINT32 NN_XYDP0:1;
+    gctUINT32 NN_WRITE_WITHOUT_USC:1;
+    gctUINT32 NN_HW_LIMITATION_NATIVE_KER_1x2_2x1:1;
+    gctUINT32 NN_SMALLBATCH_PHASE1:1;
+    gctUINT32 NN_SLICE_PADDING_TO_64BYTE_ALIGN:1;
+    gctUINT32 NN_DW_1x1_CONV_MERGE:1;
+    gctUINT32 TP_BFLOAT16:1;
+    gctUINT32 TP_23BITS_POST_MULTIPLIER:1;
+    gctUINT32 NN_TRANSPOSE:1;
+    gctUINT32 NN_ZDP_TRANSPOSE_CH9_ONLY:1;
+    gctUINT32 USE_SINGLE_PORT_VIPSRAM:1;
+    gctUINT32 NN_LEAKY_RELU:1;
+    gctUINT32 NN_PRELU:1;
+    gctUINT32 NN_PER_CHANNEL_QUANT:1;
+    gctUINT32 NN_PER_CHANNEL_QUANT_ASYM:1;
+    gctUINT32 NN_ASYMMETRIC_INT8:1;
+    gctUINT32 NN_FLOAT_POST_MULT:1;
+    gctUINT32 PRELU_LEAKLY_RELU_CLAMP:1;
+    gctUINT32 TPLITE_BFLOAT16:1;
+    gctUINT32 PREPROCESS_IMG_BUF_640BYTE_LIMIT:1;
+    gctUINT32 TP_KERNEL_1BYTE_ALGIN:1;
+    gctUINT32 BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE:1;
+    gctUINT32 NN_COMPRESSION_BYPASSS:1;
+    gctUINT32 TP_3_USC:1;
+    gctUINT32 BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE:1;
+    gctUINT32 NN_NATIVE_STRIDE_TWO:1;
+    gctUINT32 NN_TENSOR_ADD:1;
+    gctUINT32 NN_FLOAT32_IO:1;
+    gctUINT32 TP_FLOAT32_IO:1;
+    gctUINT32 NN_SMALL_BATCH_PHASE2:1;
+    gctUINT32 TILE_ACCESS_CAPABILITY:1;
+    gctUINT32 FAST_DP3_PREPROCESSOR:1;
+    gctUINT32 DEPTHWISE_SUPPORT_16BIT_FORMAT:1;
+    gctUINT32 NN_SUPPORT_ALU_LUT:1;
+    gctUINT32 NN_ENHANCED_MAX_POOLING:1;
+    gctUINT32 NN_TRANSPOSE_PHASE2:1;
+    gctUINT32 TPLITE_SUPPORT_TP_DATA_TRANSPOSE:1;
+    gctUINT32 NN_SUPPORT_CONV_1D:1;
+    gctUINT32 USE_VIPSRAM_FOR_KERNEL_STREAMING:1;
+    gctUINT32 NN_SUPPORT_DUMMY_TILE:1;
+    gctUINT32 NN_SUPPORT_KERNEL_1BYTE_ALIGN:1;
+    gctUINT32 NN_1x1_NON_POOLING_PACKING:1;
+    gctUINT32 NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING:1;
+    gctUINT32 NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2:1;
+    gctUINT32 NN_MP_INTER_CONNECT_RING:1;
+    gctUINT32 NN_SUPPORT_BATCH:1;
+    gctUINT32 NN_2D_AVERAGE_OUTPUT:1;
+    gctUINT32 NN_JOB_CANCELATION:1;
+    gctUINT32 NN_DISTRIBUTED_VIPSRAM:1;
+    gctUINT32 NN_FC_ENHANCEMENT:1;
+    gctUINT32 VIP_DEC400:1;
+    gctUINT32 NN_PER3DTILE_BUBBLE_FIX:1;
+    gctUINT32 NN_CACHELINE_MODE_PERF_FIX:1;
+    gctUINT32 NN_CONV1x1_PERF_FIX:1;
+    gctUINT32 TP_REORDER_FIX:1;
+    gctUINT32 NN_CONVOUT_FIFO_DEPTH_FIX:1;
+    gctUINT32 NN_ZXDP3_KERNEL_READ_CONFLICT_FIX:1;
+    gctUINT32 NN_ZDP3_NO_COMPRESS_FIX:1;
+    gctUINT32 NN_ASYNC_COPY_PERF_FIX:1;
+    gctUINT32 HI_REORDER_FIX:1;
+    gctUINT32 INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX:1;
+    gctUINT32 TP_REORDER_LAYER_SUSPEND_FIX:1;
+    gctUINT32 NN_ASYNC_COPY_MERGE_FIX:1;
+    gctUINT32 USC_INVALIDATE_CACHE_LINE_FIX:1;
+    gctUINT32 NN_REQ_SLOWARBITRATION_FIX:1;
+    gctUINT32 IMAGE_PARTIAL_CACHE_FIX:1;
+    gctUINT32 FULLCACHE_KERNELHEAD_FIX:1;
+    gctUINT32 NN_ZDP_INIMAGE_SIZE_FIX:1;
+    gctUINT32 IDLE_BEFORE_FLUSH_COMPLETE_FIX:1;
+    gctUINT32 NO_FLUSH_USC_FIX:1;
+    gctUINT32 SMALL_BATCH_FLOPS_RESET_FIX:1;
+    gctUINT32 SMALL_BATCH_DISBLE_FIX:1;
+    gctUINT32 OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX:1;
+    gctUINT32 IMAGE_NOT_PACKED_IN_SRAM_FIX:1;
+    gctUINT32 COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX:1;
+    gctUINT32 USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX:1;
+    gctUINT32 LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX:1;
+    gctUINT32 KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX:1;
+    gctUINT32 USC_BOTTLENECK_FIX:1;
+    gctUINT32 KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX:1;
+    gctUINT32 NN_TILE_NUM_BIGGER_THAN_1024_FIX:1;
+    gctUINT32 KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX:1;
+    gctUINT32 NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX:1;
+    gctUINT32 TP_REORDER_INTILE_X_SIZE_512_FIX:1;
+    gctUINT32 IMG_POP_PIPELINE_PAUSE_FIX:1;
+    gctUINT32 FULLCACHE_KERNEL_INTERLEAVE_FIX:1;
+    gctUINT32 V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX:1;
+    gctUINT32 V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX:1;
+    gctUINT32 DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX:1;
+    gctUINT32 DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX:1;
+    gctUINT32 TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX:1;
+    gctUINT32 EVIS2_FLOP_RESET_FIX:1;
+    gctUINT32 OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX:1;
+    gctUINT32 USC_ASYNC_CP_RTN_FLOP_RESET_FIX:1;
+    gctUINT32 IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX:1;
+    gctUINT32 NEGATIVE_POST_SHIFT_FIX:1;
+    gctUINT32 INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX:1;
+    gctUINT32 IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX:1;
+    gctUINT32 BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX:1;
+    gctUINT32 INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX:1;
+    gctUINT32 TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX:1;
+    gctUINT32 NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE:1;
+    gctUINT32 NN_IN_TILE_DATA_IS_ALL_PAD_FIX:1;
+    gctUINT32 NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX:1;
+    gctUINT32 TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX:1;
+    gctUINT32 NN_KERNEL_1x1_NO_PAD_FIX:1;
+    gctUINT32 NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX:1;
+    gctUINT32 TP_NOT_FULL_USE_CACHE_LINE_FIX:1;
+    gctUINT32 SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX:1;
+    gctUINT32 BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX:1;
+    gctUINT32 NN_INTERLEVE8:1;
+    gctUINT32 NN_FP16_ALU:1;
+    gctUINT32 NN_INT16_ALU:1;
+    gctUINT32 NN_INT8_SCALE:1;
+    gctUINT32 NN_POWER_ISOLATION:1;
+    gctUINT32 ZRL_7BIT:1;
+    gctUINT32 NN_SMALLBATCH:1;
+    gctUINT32 TP_SMALLBATCH:1;
+    gctUINT32 ZRL_8BIT:1;
+    gctUINT32 DDR_BURST_LEN_256B:1;
+    gctUINT32 XY_OFFSET_LIMITATION_FIX:1;
+    gctUINT32 NN_NONZERO_MIRROR_BORDER:1;
+    gctUINT32 IMAGE_PARTIAL_CACHE:1;
+} gcsFEATURE_DATABASE;
+
+static gcsFEATURE_DATABASE gChipInfo[] = {
+    /* gc320_5007 */
+    {
+        0x320, /* ChipID */
+        0x5007, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x8, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x0, /* gcFEATURE_BIT_REG_MMU */
+        0x0, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc320_5303 */
+    {
+        0x320, /* ChipID */
+        0x5303, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc320_5341 */
+    {
+        0x320, /* ChipID */
+        0x5341, /* ChipRevision */
+        0x3202, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc355_v121_rc5 */
+    {
+        0x355, /* ChipID */
+        0x1215, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x1, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x1, /* gcFEATURE_BIT_REG_PipeVG */
+        0x1, /* gcFEATURE_BIT_REG_VGTS */
+        0x1, /* gcFEATURE_BIT_REG_FE20 */
+        0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x0, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x0, /* gcFEATURE_BIT_REG_Render8K */
+        0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x1, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x1, /* gcFEATURE_BIT_REG_VG21 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x1, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x1, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x0, /* gcFEATURE_BIT_REG_PixelDither */
+        0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x0, /* gcFEATURE_BIT_REG_MMU */
+        0x0, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc400_4645 */
+    {
+        0x400, /* ChipID */
+        0x4645, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x4, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x80, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x4, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_FastScaler */
+        0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x1, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x0, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x1, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc520l_5341_rc1b */
+    {
+        0x520, /* ChipID */
+        0x5341, /* ChipRevision */
+        0x5202, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc520l_5341_rc1c */
+    {
+        0x520, /* ChipID */
+        0x5341, /* ChipRevision */
+        0x5202, /* ProductID */
+        0x0, /* EcoID */
+        0x204, /* CustomerID */
+        0x3, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x1, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x1, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x1, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc520l_5341_rc1i */
+    {
+        0x520, /* ChipID */
+        0x5341, /* ChipRevision */
+        0x5202, /* ProductID */
+        0x1, /* EcoID */
+        0x204, /* CustomerID */
+        0x3, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x1, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x1, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x1, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x1, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x1, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x1, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000nanoultra_4_6_5_rc3a */
+    {
+        0x600, /* ChipID */
+        0x4653, /* ChipRevision */
+        0x70005, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x1, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x4, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_FastScaler */
+        0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x1, /* gcFEATURE_BIT_REG_MinArea */
+        0x1, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x1, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000nanoultra_4_6_5_rc3e */
+    {
+        0x600, /* ChipID */
+        0x4653, /* ChipRevision */
+        0x70005, /* ProductID */
+        0x0, /* EcoID */
+        0x102, /* CustomerID */
+        0x5, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x100, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x4, /* gcFEATURE_VALUE_Streams */
+        0x8, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_FastScaler */
+        0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x1, /* gcFEATURE_BIT_REG_MinArea */
+        0x1, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x0, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x0, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc880_5106 */
+    {
+        0x880, /* ChipID */
+        0x5106, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x8, /* gcFEATURE_VALUE_Streams */
+        0xb, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_FastScaler */
+        0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x0, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc2000_5108 */
+    {
+        0x2000, /* ChipID */
+        0x5108, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x4, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x8, /* gcFEATURE_VALUE_Streams */
+        0xb, /* gcFEATURE_VALUE_VaryingCount */
+        0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x1, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x0, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x0, /* gcFEATURE_BIT_REG_LineLoop */
+        0x0, /* gcFEATURE_BIT_REG_LogicOp */
+        0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x0, /* gcFEATURE_BIT_REG_LinearPE */
+        0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x0, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x0, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x0, /* gcFEATURE_BIT_REG_TileFiller */
+        0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x0, /* gcFEATURE_BIT_REG_Interleaver */
+        0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_ACE */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x0, /* gcFEATURE_BIT_REG_NewHZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x0, /* gcFEATURE_BIT_REG_EEZ */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc2000_ffff5450 */
+    {
+        0x2000, /* ChipID */
+        0xffff5450, /* ChipRevision */
+        0x0, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x8, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x4, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x0, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x0, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x0, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x0, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000L_5514 */
+    {
+        0x3000, /* ChipID */
+        0x5514, /* ChipRevision */
+        0x70002, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x4, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x0, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x0, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000XSVX_6008 */
+    {
+        0x7000, /* ChipID */
+        0x6008, /* ChipRevision */
+        0x70008, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x7, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x800, /* gcFEATURE_VALUE_ThreadCount */
+        0x8, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x40, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x1f, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x1, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000XSVX_6009 */
+    {
+        0x7000, /* ChipID */
+        0x6009, /* ChipRevision */
+        0x70008, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x9, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x800, /* gcFEATURE_VALUE_ThreadCount */
+        0x8, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x40, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x1f, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x1, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000XSVX_6009 */
+    {
+        0x7000, /* ChipID */
+        0x6009, /* ChipRevision */
+        0x70008, /* ProductID */
+        0x1, /* EcoID */
+        0x0, /* CustomerID */
+        0x9, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x800, /* gcFEATURE_VALUE_ThreadCount */
+        0x8, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x40, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x1f, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x1, /* gcFEATURE_BIT_HWTFB */
+        0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY */
+        0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000UL_6200 */
+    {
+        0x7000, /* ChipID */
+        0x6202, /* ChipRevision */
+        0x70003, /* ProductID */
+        0x0, /* EcoID */
+        0x0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x2, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x10, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x8, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* GCNANOULTRA31 */
+    {
+        0x7000, /* ChipID */
+        0x6205, /* ChipRevision */
+        0x70007, /* ProductID */
+        0x0, /* EcoID */
+        0x12, /* CustomerID */
+        0x0, /* PatchVersion */
+        "GCNANOULTRA31", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x1, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x1, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x1, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x1, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x1, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x1, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x1, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x1, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x1, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* GCNANOULTRA31 */
+    {
+        0x7000, /* ChipID */
+        0x6205, /* ChipRevision */
+        0x70007, /* ProductID */
+        0x1, /* EcoID */
+        0x12, /* CustomerID */
+        0x0, /* PatchVersion */
+        "GCNANOULTRA31", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x1, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x1, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x1, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x1, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x1, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x1, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x1, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x1, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x1, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000ULN_v122 */
+    {
+        0x7000, /* ChipID */
+        0x6203, /* ChipRevision */
+        0x70003, /* ProductID */
+        0x0, /* EcoID */
+        0x4, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x2, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x1, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000ULN_v123 */
+    {
+        0x7000, /* ChipID */
+        0x6204, /* ChipRevision */
+        0x70003, /* ProductID */
+        0x0, /* EcoID */
+        0x11, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x2, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x1, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x1, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000ULN_v123 */
+    {
+        0x7000, /* ChipID */
+        0x6204, /* ChipRevision */
+        0x70003, /* ProductID */
+        0x1, /* EcoID */
+        0x11, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x200, /* gcFEATURE_VALUE_ThreadCount */
+        0x2, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x0, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x0, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x0, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x1, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x1, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000L_DEC400 */
+    {
+        0x7000, /* ChipID */
+        0x6214, /* ChipRevision */
+        0x70002, /* ProductID */
+        0x0, /* EcoID */
+        0x30, /* CustomerID */
+        0x8, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x1, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x1, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc7000L_DEC400 */
+    {
+        0x7000, /* ChipID */
+        0x6214, /* ChipRevision */
+        0x70002, /* ProductID */
+        0x1, /* EcoID */
+        0x30, /* CustomerID */
+        0x8, /* PatchVersion */
+        "", /* ProductName */
+        0x1, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x400, /* gcFEATURE_VALUE_ThreadCount */
+        0x4, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x8, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x0, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x1, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x1, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc8200_6305_pid0x70 */
+    {
+        0x8200, /* ChipID */
+        0x6305, /* ChipRevision */
+        0x82008, /* ProductID */
+        0x0, /* EcoID */
+        0x70, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x800, /* gcFEATURE_VALUE_ThreadCount */
+        0x10, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x40, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x3, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x1, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x1, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x1, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* gc8203_6401_pid0x70 */
+    {
+        0x8200, /* ChipID */
+        0x6401, /* ChipRevision */
+        0x82008, /* ProductID */
+        0x0, /* EcoID */
+        0x70, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x800, /* gcFEATURE_VALUE_ThreadCount */
+        0x10, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x40, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x10, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x3, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x0, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x0, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x0, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x0, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x0, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x0, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x0, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x0, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x0, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x0, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x0, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x0, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x0, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x0, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x0, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x0, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x1, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x0, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x0, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x1, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x1, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x0, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x1, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x1, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x0, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x1, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x1, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x1, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x1, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x1, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x1, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x1, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x1, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x1, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x1, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x1, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x0, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x0, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x0, /* gcFEATURE_BIT_TP_LRN */
+        0x0, /* gcFEATURE_BIT_TP_REORDER */
+        0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x0, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x0, /* gcFEATURE_BIT_TP_ENGINE */
+        0x0, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x0, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x0, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x0, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x0, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x0, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x0, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x0, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x0, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x0, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x0, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x0, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x0, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x0, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x0, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x0, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x0, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x0, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x0, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x1, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x0, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* vipnano-si+ */
+    {
+        0x8000, /* ChipID */
+        0x8002, /* ChipRevision */
+        0x5080009, /* ProductID */
+        0x6000000, /* EcoID */
+        0x9f, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x10, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x1, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x2, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x8, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x9, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x20, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x40000, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x3, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x5, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x200, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x8, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x1, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x1, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x1, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x10, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x40, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x40, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x20, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x8, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x8, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x80, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x10, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0xf, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0xf, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0xf, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0xfffff, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x1f, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x1f, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x100, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x10, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0xd, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0xe, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x40, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x1, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x3, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x1, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x1, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x1, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x1, /* gcFEATURE_BIT_TP_LRN */
+        0x1, /* gcFEATURE_BIT_TP_REORDER */
+        0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x1, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x1, /* gcFEATURE_BIT_TP_ENGINE */
+        0x1, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x1, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x1, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x1, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x1, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x1, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x1, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x1, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x1, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x1, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x1, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x1, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x1, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x1, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x1, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x1, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x1, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x1, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x1, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x1, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x1, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x1, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x1, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x1, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x1, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x1, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x1, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x1, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x1, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x1, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x1, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x1, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x1, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x1, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x1, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x1, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+    /* vipnano-si+ */
+    {
+        0x8000, /* ChipID */
+        0x8002, /* ChipRevision */
+        0x5080009, /* ProductID */
+        0x6000000, /* EcoID */
+        0xa0, /* CustomerID */
+        0x0, /* PatchVersion */
+        "", /* ProductName */
+        0x0, /* FormalRelease */
+        0x40, /* gcFEATURE_VALUE_TempRegisters */
+        0x100, /* gcFEATURE_VALUE_ThreadCount */
+        0x1, /* gcFEATURE_VALUE_NumShaderCores */
+        0x200, /* gcFEATURE_VALUE_InstructionCount */
+        0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+        0x1, /* gcFEATURE_VALUE_CoreCount */
+        0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_1 */
+        0x0, /* gcFEATURE_VALUE_LocalStorageSize_2 */
+        0x10, /* gcFEATURE_VALUE_L1CacheSize */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_1 */
+        0x0, /* gcFEATURE_VALUE_L1CacheSize_2 */
+        0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+        0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+        0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_1 */
+        0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES_2 */
+        0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+        0x1, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_CACHE_CONTROLLERS_2 */
+        0x2, /* gcFEATURE_VALUE_USC_BANKS */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_1 */
+        0x0, /* gcFEATURE_VALUE_USC_BANKS_2 */
+        0x8, /* gcFEATURE_VALUE_Streams */
+        0x10, /* gcFEATURE_VALUE_VaryingCount */
+        0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+        0x0, /* gcFEATURE_VALUE_BufferSize */
+        0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+        0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+        0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+        0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+        0x0, /* gcFEATURE_VALUE_G2D_DEC400_MINOR */
+        0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+        0x6, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+        0x0, /* gcFEATURE_VALUE_NNCoreCount_BFLOAT */
+        0x9, /* gcFEATURE_VALUE_NNInputBufferDepth */
+        0x20, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+        0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+        0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+        0x40000, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+        0x3, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+        0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+        0x5, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+        0x200, /* gcFEATURE_VALUE_TP_REORDER_INIMAGE_SIZE */
+        0x0, /* gcFEATURE_VALUE_TPLite_CoreCount */
+        0x8, /* gcFEATURE_VALUE_NN_PREPROCESSOR_MAX_SEGMENT_PER_CYCLE */
+        0x1, /* gcFEATURE_VALUE_NNFP16_XYDP_X */
+        0x1, /* gcFEATURE_VALUE_NNFP16_XYDP_Y */
+        0x1, /* gcFEATURE_VALUE_NNFP16_ZDP */
+        0x10, /* gcFEATURE_VALUE_NN_LANES_PER_OUT_CYCLE */
+        0x40, /* gcFEATURE_VALUE_MAX_OT_NUMBER */
+        0x40, /* gcFEATURE_VALUE_PHYSICAL_VIP_SRAM_WIDTH_IN_BYTE */
+        0x20, /* gcFEATURE_VALUE_EQUIVALENT_VIP_SRAM_WIDTH_INBYTE */
+        0x8, /* gcFEATURE_VALUE_TP_ZRL_BITS */
+        0x8, /* gcFEATURE_VALUE_NN_ZRL_BITS */
+        0x80, /* gcFEATURE_VALUE_LATENCY_HIDING_AT_FULL_AXI_BW */
+        0x10, /* gcFEATURE_VALUE_AXI_BUS_WIDTH */
+        0xf, /* gcFEATURE_VALUE_NN_KERNEL_X_SIZE */
+        0xf, /* gcFEATURE_VALUE_NN_KERNEL_Y_SIZE */
+        0xf, /* gcFEATURE_VALUE_NN_FC_KERNEL_Y_SIZE */
+        0xfffff, /* gcFEATURE_VALUE_NN_KERNEL_Z_SIZE */
+        0x1f, /* gcFEATURE_VALUE_NN_X_OFFSET */
+        0x1f, /* gcFEATURE_VALUE_NN_Y_OFFSET */
+        0x100, /* gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE */
+        0x10, /* gcFEATURE_VALUE_OUTIMAGE_X_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_OUTIMAGE_Y_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_INIMAGE_X_STRIDE_BITS */
+        0x10, /* gcFEATURE_VALUE_IMIMAGE_Y_STRIDE_BITS */
+        0xd, /* gcFEATURE_VALUE_OUTIMAGE_X_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_OUTIMAGE_Y_SIZE_BITS */
+        0xe, /* gcFEATURE_VALUE_OUTIMAGE_Z_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_INIMAGE_X_SIZE_BITS */
+        0xd, /* gcFEATURE_VALUE_INIMAGE_Y_SIZE_BITS */
+        0x40, /* gcFEATURE_VALUE_MAX_TILE_X_SIZE */
+        0x1, /* gcFEATURE_VALUE_NN_CLUSTER_NUM_FOR_POWER_CONTROL */
+        0x3, /* gcFEATURE_VALUE_NN_IN_LINES_PER_CYCLE */
+        0x0, /* gcFEATURE_BIT_REG_FastClear */
+        0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+        0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+        0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+        0x0, /* gcFEATURE_BIT_REG_DebugMode */
+        0x1, /* gcFEATURE_BIT_REG_ZCompression */
+        0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+        0x1, /* gcFEATURE_BIT_REG_MSAA */
+        0x0, /* gcFEATURE_BIT_REG_DC */
+        0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+        0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+        0x1, /* gcFEATURE_BIT_REG_FastScaler */
+        0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+        0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+        0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+        0x0, /* gcFEATURE_BIT_REG_MinArea */
+        0x0, /* gcFEATURE_BIT_REG_NoEZ */
+        0x0, /* gcFEATURE_BIT_REG_No422Texture */
+        0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+        0x0, /* gcFEATURE_BIT_REG_NoScaler */
+        0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+        0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+        0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+        0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+        0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+        0x0, /* gcFEATURE_BIT_REG_PipeVG */
+        0x0, /* gcFEATURE_BIT_REG_VGTS */
+        0x0, /* gcFEATURE_BIT_REG_FE20 */
+        0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+        0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+        0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+        0x1, /* gcFEATURE_BIT_REG_FlipY */
+        0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+        0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+        0x1, /* gcFEATURE_BIT_REG_Texture8K */
+        0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+        0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+        0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+        0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+        0x1, /* gcFEATURE_BIT_REG_Render8K */
+        0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+        0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+        0x0, /* gcFEATURE_BIT_REG_VG20 */
+        0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+        0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+        0x0, /* gcFEATURE_BIT_REG_VGFilter */
+        0x0, /* gcFEATURE_BIT_REG_VG21 */
+        0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+        0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+        0x1, /* gcFEATURE_BIT_REG_MC20 */
+        0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+        0x0, /* gcFEATURE_BIT_REG_VAA */
+        0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+        0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+        0x0, /* gcFEATURE_BIT_REG_NewTexture */
+        0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+        0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+        0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+        0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+        0x1, /* gcFEATURE_BIT_REG_V2Compression */
+        0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+        0x0, /* gcFEATURE_BIT_REG_TextureStride */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+        0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+        0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+        0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+        0x1, /* gcFEATURE_BIT_REG_PixelDither */
+        0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+        0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+        0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+        0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+        0x0, /* gcFEATURE_BIT_REG_New2D */
+        0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+        0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+        0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+        0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+        0x1, /* gcFEATURE_BIT_REG_Halti0 */
+        0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+        0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+        0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+        0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+        0x1, /* gcFEATURE_BIT_REG_MMU */
+        0x1, /* gcFEATURE_BIT_REG_WideLine */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+        0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+        0x1, /* gcFEATURE_BIT_REG_LineLoop */
+        0x1, /* gcFEATURE_BIT_REG_LogicOp */
+        0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+        0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+        0x1, /* gcFEATURE_BIT_REG_LinearPE */
+        0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+        0x0, /* gcFEATURE_BIT_REG_Composition */
+        0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+        0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+        0x1, /* gcFEATURE_BIT_REG_EndEvent */
+        0x1, /* gcFEATURE_BIT_REG_S1S8 */
+        0x1, /* gcFEATURE_BIT_REG_Halti1 */
+        0x0, /* gcFEATURE_BIT_REG_RGB888 */
+        0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+        0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+        0x0, /* gcFEATURE_BIT_REG_TXFilter */
+        0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+        0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+        0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+        0x1, /* gcFEATURE_BIT_REG_TileFiller */
+        0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+        0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+        0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+        0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+        0x1, /* gcFEATURE_BIT_REG_Interleaver */
+        0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+        0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+        0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+        0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+        0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+        0x0, /* gcFEATURE_BIT_REG_OclOnly */
+        0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+        0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+        0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+        0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+        0x1, /* gcFEATURE_BIT_REG_Generics */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+        0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+        0x0, /* gcFEATURE_BIT_REG_WClip */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+        0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+        0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+        0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_ACE */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+        0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+        0x1, /* gcFEATURE_BIT_REG_NewHZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+        0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+        0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+        0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+        0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+        0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+        0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+        0x1, /* gcFEATURE_BIT_REG_Halti2 */
+        0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+        0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+        0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+        0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+        0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+        0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+        0x0, /* gcFEATURE_BIT_REG_Compression2D */
+        0x0, /* gcFEATURE_BIT_REG_Probe */
+        0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+        0x0, /* gcFEATURE_BIT_REG_DESupertile */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+        0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+        0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+        0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+        0x1, /* gcFEATURE_BIT_REG_EEZ */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+        0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+        0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+        0x1, /* gcFEATURE_BIT_REG_Halti3 */
+        0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+        0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+        0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+        0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+        0x1, /* gcFEATURE_BIT_REG_Halti4 */
+        0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+        0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+        0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+        0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+        0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+        0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+        0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+        0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+        0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+        0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+        0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+        0x1, /* gcFEATURE_BIT_REG_RSS8 */
+        0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+        0x1, /* gcFEATURE_BIT_REG_Halti5 */
+        0x1, /* gcFEATURE_BIT_REG_Evis */
+        0x0, /* gcFEATURE_BIT_REG_BltEngine */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+        0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+        0x0, /* gcFEATURE_BIT_REG_DEC */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+        0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+        0x0, /* gcFEATURE_BIT_REG_DisableVIP */
+        0x0, /* gcFEATURE_BIT_RenderTarget8 */
+        0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+        0x0, /* gcFEATURE_BIT_FaceLod */
+        0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+        0x1, /* gcFEATURE_BIT_VMSAA */
+        0x0, /* gcFEATURE_BIT_ChipEnableLink */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+        0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+        0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+        0x1, /* gcFEATURE_BIT_V4Compression */
+        0x0, /* gcFEATURE_BIT_DE2D_MAJOR_SUPER_TILE */
+        0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+        0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+        0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+        0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+        0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+        0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+        0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+        0x1, /* gcFEATURE_BIT_NO_ASTC */
+        0x0, /* gcFEATURE_BIT_NO_DXT */
+        0x0, /* gcFEATURE_BIT_HWTFB */
+        0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+        0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+        0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+        0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+        0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+        0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+        0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+        0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+        0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+        0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+        0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+        0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+        0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+        0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+        0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+        0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+        0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+        0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+        0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY */
+        0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+        0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+        0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+        0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+        0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+        0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+        0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+        0x1, /* gcFEATURE_BIT_DRAWID */
+        0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+        0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+        0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+        0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+        0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+        0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+        0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+        0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+        0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+        0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+        0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+        0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+        0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+        0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+        0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+        0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+        0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+        0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+        0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+        0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+        0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+        0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+        0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+        0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+        0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+        0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+        0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+        0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+        0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+        0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+        0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+        0x0, /* gcFEATURE_BIT_DEC400 */
+        0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+        0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+        0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+        0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+        0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+        0x0, /* gcFEATURE_BIT_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_SH_CMPLX */
+        0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+        0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+        0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+        0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+        0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+        0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+        0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+        0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+        0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+        0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+        0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+        0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+        0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+        0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+        0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+        0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+        0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+        0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+        0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+        0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+        0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+        0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+        0x1, /* gcFEATURE_BIT_SH_IO_CG_FIX */
+        0x0, /* gcFEATURE_BIT_PE_SWIZZLE */
+        0x0, /* gcFEATURE_BIT_SH_ROBUSTNESS_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX2 */
+        0x0, /* gcFEATURE_BIT_PE_A8B8G8R8 */
+        0x0, /* gcFEATURE_BIT_MULTIVIEW_RENDER */
+        0x0, /* gcFEATURE_BIT_FE_DRAW_DIRECT */
+        0x0, /* gcFEATURE_BIT_TX_VKBORDER_MODE */
+        0x0, /* gcFEATURE_BIT_TX_UNNORMALIZED_COORD */
+        0x0, /* gcFEATURE_BIT_PA_LINECLIP_FIX */
+        0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac_ROUNDING_FIX */
+        0x0, /* gcFEATURE_BIT_MP_ARCH */
+        0x0, /* gcFEATURE_BIT_TX_NO_FIXED_FILTER */
+        0x0, /* gcFEATURE_BIT_SHARE_Z */
+        0x0, /* gcFEATURE_BIT_DE_2D_FAST_CLEAR */
+        0x0, /* gcFEATURE_BIT_DE_TILESTATUS_ROTATION_FIX */
+        0x0, /* gcFEATURE_BIT_TX_CLEAR_PENDING_FIX */
+        0x0, /* gcFEATURE_BIT_HI1_L2_CACHE */
+        0x0, /* gcFEATURE_BIT_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_FORMAT_10BIT_CROSS_4K */
+        0x0, /* gcFEATURE_BIT_FORMAT_P010LSB_I010 */
+        0x0, /* gcFEATURE_BIT_ENDIAN_CONTROL */
+        0x0, /* gcFEATURE_BIT_G2D_RGB_PLANAR */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400EX */
+        0x0, /* gcFEATURE_BIT_G2D_NO_YUV420_SOURCE */
+        0x0, /* gcFEATURE_BIT_G2D_YUV420_101010 */
+        0x0, /* gcFEATURE_BIT_SH_VX2_FLOATING_MAD_FIX */
+        0x0, /* gcFEATURE_BIT_TS_FC_VULKAN_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MSAA_FLOAT_64BIT */
+        0x0, /* gcFEATURE_BIT_INDIRECT_COMPUTE_ZERODIM_FIX */
+        0x0, /* gcFEATURE_BIT_Q_CHANNEL_SUPPORT */
+        0x0, /* gcFEATURE_BIT_MMU_PAGE_DESCRIPTOR */
+        0x0, /* gcFEATURE_BIT_YUV_LINEAR_TO_TILE_ROTATE */
+        0x0, /* gcFEATURE_BIT_VEC2_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC4_IMULIMAD32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_VEC2_IDIVIMOD16_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DST_TEX_I2F_F2I_INST_DEPRECATE */
+        0x0, /* gcFEATURE_BIT_ALU_FP16_INSTRUCTIONS */
+        0x0, /* gcFEATURE_BIT_DUAL16_14BIT_PC_SUPPORT */
+        0x0, /* gcFEATURE_BIT_LDST_CONV_4ROUNDING_MODES */
+        0x0, /* gcFEATURE_BIT_FULL_PACK_MODE_SUPPORT */
+        0x0, /* gcFEATURE_BIT_DEPTH_FLOAT32_SUPPORT */
+        0x0, /* gcFEATURE_BIT_FP32_TO_FP16_CONV_FIX */
+        0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+        0x0, /* gcFEATURE_BIT_VG_FP25 */
+        0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+        0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+        0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+        0x0, /* gcFEATURE_BIT_VG_MMU */
+        0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+        0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+        0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+        0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+        0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+        0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+        0x0, /* gcFEATURE_BIT_VG_IMAGE_16K */
+        0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+        0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+        0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+        0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+        0x0, /* gcFEATURE_BIT_DC_TILED */
+        0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+        0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+        0x0, /* gcFEATURE_BIT_DC_MMU */
+        0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+        0x0, /* gcFEATURE_BIT_DC_QOS */
+        0x1, /* gcFEATURE_BIT_VIP_HW_FINAL_RELEASE */
+        0x1, /* gcFEATURE_BIT_NN_SINGLEPORT_ACCUMBUFFER */
+        0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+        0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+        0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+        0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+        0x1, /* gcFEATURE_BIT_TP_LRN */
+        0x1, /* gcFEATURE_BIT_TP_REORDER */
+        0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+        0x0, /* gcFEATURE_BIT_NN_NONZERO_BORDER */
+        0x1, /* gcFEATURE_BIT_NN_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_AI_GPU */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+        0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+        0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+        0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+        0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+        0x1, /* gcFEATURE_BIT_TP_ENGINE */
+        0x1, /* gcFEATURE_BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_TENSOR_ADD_MUL */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_INT16XINT8 */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_SOFTMAX */
+        0x0, /* gcFEATURE_BIT_NN_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_CONV_INT16X8BIT_VIP_V7 */
+        0x0, /* gcFEATURE_BIT_NN_REMOVE_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_40BIT_BIAS */
+        0x0, /* gcFEATURE_BIT_TP_REMOVE_USC */
+        0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+        0x1, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+        0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+        0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+        0x1, /* gcFEATURE_BIT_SWTILING_PHASE3 */
+        0x0, /* gcFEATURE_BIT_MCFE */
+        0x0, /* gcFEATURE_BIT_USC_STAY_LRU */
+        0x1, /* gcFEATURE_BIT_COEF_COMPRESSION_ENHANCEMENT */
+        0x1, /* gcFEATURE_BIT_TP_COEF_COMPRESSION_ENHANCEMENT */
+        0x1, /* gcFEATURE_BIT_NN_COEF_DECOMPRESS_PERF2X */
+        0x1, /* gcFEATURE_BIT_TP_SMALLBATCH_PHASE1 */
+        0x1, /* gcFEATURE_BIT_OCB_COUNTER */
+        0x0, /* gcFEATURE_BIT_SCALER */
+        0x0, /* gcFEATURE_BIT_SCALER_4K */
+        0x0, /* gcFEATURE_BIT_INPUT_4BIT */
+        0x1, /* gcFEATURE_BIT_NN_NO_Z_LOCATION_OFFSET */
+        0x1, /* gcFEATURE_BIT_OCB_REMAP_PHYSICAL_ADDRESS */
+        0x1, /* gcFEATURE_BIT_NN_SLOW_OUTPUT */
+        0x1, /* gcFEATURE_BIT_NO_NARROW_POST_PROCESS_PIPE */
+        0x0, /* gcFEATURE_BIT_TP_NN_PROBE */
+        0x1, /* gcFEATURE_BIT_NN_DEPTHWISE_SUPPORT */
+        0x1, /* gcFEATURE_BIT_NN_XYDP0 */
+        0x1, /* gcFEATURE_BIT_NN_WRITE_WITHOUT_USC */
+        0x1, /* gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1 */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH_PHASE1 */
+        0x0, /* gcFEATURE_BIT_NN_SLICE_PADDING_TO_64BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_DW_1x1_CONV_MERGE */
+        0x0, /* gcFEATURE_BIT_TP_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_TP_23BITS_POST_MULTIPLIER */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_ZDP_TRANSPOSE_CH9_ONLY */
+        0x0, /* gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_LEAKY_RELU */
+        0x0, /* gcFEATURE_BIT_NN_PRELU */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT */
+        0x0, /* gcFEATURE_BIT_NN_PER_CHANNEL_QUANT_ASYM */
+        0x0, /* gcFEATURE_BIT_NN_ASYMMETRIC_INT8 */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT_POST_MULT */
+        0x0, /* gcFEATURE_BIT_PRELU_LEAKLY_RELU_CLAMP */
+        0x0, /* gcFEATURE_BIT_TPLITE_BFLOAT16 */
+        0x0, /* gcFEATURE_BIT_PREPROCESS_IMG_BUF_640BYTE_LIMIT */
+        0x0, /* gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN */
+        0x0, /* gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE */
+        0x0, /* gcFEATURE_BIT_NN_COMPRESSION_BYPASSS */
+        0x0, /* gcFEATURE_BIT_TP_3_USC */
+        0x0, /* gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE */
+        0x0, /* gcFEATURE_BIT_NN_NATIVE_STRIDE_TWO */
+        0x0, /* gcFEATURE_BIT_NN_TENSOR_ADD */
+        0x0, /* gcFEATURE_BIT_NN_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_TP_FLOAT32_IO */
+        0x0, /* gcFEATURE_BIT_NN_SMALL_BATCH_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TILE_ACCESS_CAPABILITY */
+        0x0, /* gcFEATURE_BIT_FAST_DP3_PREPROCESSOR */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_SUPPORT_16BIT_FORMAT */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_ALU_LUT */
+        0x0, /* gcFEATURE_BIT_NN_ENHANCED_MAX_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_TRANSPOSE_PHASE2 */
+        0x0, /* gcFEATURE_BIT_TPLITE_SUPPORT_TP_DATA_TRANSPOSE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV_1D */
+        0x0, /* gcFEATURE_BIT_USE_VIPSRAM_FOR_KERNEL_STREAMING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_DUMMY_TILE */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_KERNEL_1BYTE_ALIGN */
+        0x0, /* gcFEATURE_BIT_NN_1x1_NON_POOLING_PACKING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BOTH_CONV_NATIVE_STRIDE2_AND_POOLING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_CONV1x1_AND_NATIVE_CONV_STRIDE2 */
+        0x0, /* gcFEATURE_BIT_NN_MP_INTER_CONNECT_RING */
+        0x0, /* gcFEATURE_BIT_NN_SUPPORT_BATCH */
+        0x0, /* gcFEATURE_BIT_NN_2D_AVERAGE_OUTPUT */
+        0x0, /* gcFEATURE_BIT_NN_JOB_CANCELATION */
+        0x0, /* gcFEATURE_BIT_NN_DISTRIBUTED_VIPSRAM */
+        0x0, /* gcFEATURE_BIT_NN_FC_ENHANCEMENT */
+        0x0, /* gcFEATURE_BIT_VIP_DEC400 */
+        0x1, /* gcFEATURE_BIT_NN_PER3DTILE_BUBBLE_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CACHELINE_MODE_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CONV1x1_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_FIX */
+        0x1, /* gcFEATURE_BIT_NN_CONVOUT_FIFO_DEPTH_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZDP3_NO_COMPRESS_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ASYNC_COPY_PERF_FIX */
+        0x1, /* gcFEATURE_BIT_HI_REORDER_FIX */
+        0x1, /* gcFEATURE_BIT_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_LAYER_SUSPEND_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ASYNC_COPY_MERGE_FIX */
+        0x1, /* gcFEATURE_BIT_USC_INVALIDATE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_REQ_SLOWARBITRATION_FIX */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE_FIX */
+        0x0, /* gcFEATURE_BIT_FULLCACHE_KERNELHEAD_FIX */
+        0x1, /* gcFEATURE_BIT_NN_ZDP_INIMAGE_SIZE_FIX */
+        0x1, /* gcFEATURE_BIT_IDLE_BEFORE_FLUSH_COMPLETE_FIX */
+        0x1, /* gcFEATURE_BIT_NO_FLUSH_USC_FIX */
+        0x1, /* gcFEATURE_BIT_SMALL_BATCH_FLOPS_RESET_FIX */
+        0x0, /* gcFEATURE_BIT_SMALL_BATCH_DISBLE_FIX */
+        0x1, /* gcFEATURE_BIT_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX */
+        0x1, /* gcFEATURE_BIT_IMAGE_NOT_PACKED_IN_SRAM_FIX */
+        0x1, /* gcFEATURE_BIT_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX */
+        0x0, /* gcFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX */
+        0x0, /* gcFEATURE_BIT_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX */
+        0x1, /* gcFEATURE_BIT_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX */
+        0x0, /* gcFEATURE_BIT_USC_BOTTLENECK_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX */
+        0x1, /* gcFEATURE_BIT_NN_TILE_NUM_BIGGER_THAN_1024_FIX */
+        0x0, /* gcFEATURE_BIT_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX */
+        0x1, /* gcFEATURE_BIT_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX */
+        0x1, /* gcFEATURE_BIT_TP_REORDER_INTILE_X_SIZE_512_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_POP_PIPELINE_PAUSE_FIX */
+        0x1, /* gcFEATURE_BIT_FULLCACHE_KERNEL_INTERLEAVE_FIX */
+        0x0, /* gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX */
+        0x0, /* gcFEATURE_BIT_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX */
+        0x1, /* gcFEATURE_BIT_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX */
+        0x0, /* gcFEATURE_BIT_EVIS2_FLOP_RESET_FIX */
+        0x1, /* gcFEATURE_BIT_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX */
+        0x0, /* gcFEATURE_BIT_USC_ASYNC_CP_RTN_FLOP_RESET_FIX */
+        0x1, /* gcFEATURE_BIT_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX */
+        0x1, /* gcFEATURE_BIT_NEGATIVE_POST_SHIFT_FIX */
+        0x0, /* gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX */
+        0x0, /* gcFEATURE_BIT_IMG_CAHCE_MODE_MUST_0_IN_IMG_DIRECT_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX */
+        0x1, /* gcFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX */
+        0x0, /* gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX */
+        0x1, /* gcFEATURE_BIT_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE */
+        0x1, /* gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX */
+        0x1, /* gcFEATURE_BIT_TP_FC_KERNEL_STREAM_MUST_LESS_THAN_OR_EQUAL_TO_64BYTE_WHEN_1BYTE_ALGINE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_KERNEL_1x1_NO_PAD_FIX */
+        0x0, /* gcFEATURE_BIT_NN_DEPTHWISE_AFTER_16BIT_LAYER_LIMIT_FIX */
+        0x0, /* gcFEATURE_BIT_TP_NOT_FULL_USE_CACHE_LINE_FIX */
+        0x0, /* gcFEATURE_BIT_SH_MOVAI_MOVAR_UNUSED_COMPONENTS_WRITE_DIRTY_DATA_FIX */
+        0x0, /* gcFEATURE_BIT_BURST_COLLECT_CONSUMES_MC_DATA_WIDTH_PER_CYCLE_FIX */
+        0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+        0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+        0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+        0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+        0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+        0x0, /* gcFEATURE_BIT_ZRL_7BIT */
+        0x0, /* gcFEATURE_BIT_NN_SMALLBATCH */
+        0x0, /* gcFEATURE_BIT_TP_SMALLBATCH */
+        0x1, /* gcFEATURE_BIT_ZRL_8BIT */
+        0x0, /* gcFEATURE_BIT_DDR_BURST_LEN_256B */
+        0x1, /* gcFEATURE_BIT_XY_OFFSET_LIMITATION_FIX */
+        0x1, /* gcFEATURE_BIT_NN_NONZERO_MIRROR_BORDER */
+        0x0, /* gcFEATURE_BIT_IMAGE_PARTIAL_CACHE */
+    },
+};
+
+static inline gcsFEATURE_DATABASE*
+gcQueryFeatureDB(
+    gctUINT32 ChipID,
+    gctUINT32 ChipVersion,
+    gctUINT32 ProductID,
+    gctUINT32 EcoID,
+    gctUINT32 CustomerID
+    )
+{
+    gctINT entryNum = sizeof(gChipInfo) / sizeof(gChipInfo[0]);
+    gctINT i;
+
+    /* check formal release entries first */
+    for (i = 0; i < entryNum; ++i)
+    {
+
+        if ((gChipInfo[i].chipID == ChipID)
+            && (gChipInfo[i].chipVersion == ChipVersion)
+            && (gChipInfo[i].productID == ProductID)
+            && (gChipInfo[i].ecoID == EcoID)
+            && (gChipInfo[i].customerID == CustomerID)
+            && (gChipInfo[i].formalRelease)
+           )
+        {
+            return &gChipInfo[i];
+        }
+    }
+
+    /* check informal release entries if we dont find in formal entries */
+    for (i = 0; i < entryNum; ++i)
+    {
+
+        if ((gChipInfo[i].chipID == ChipID)
+            && ((gChipInfo[i].chipVersion & 0xFFF0) == (ChipVersion & 0xFFF0))
+            && (gChipInfo[i].productID == ProductID)
+            && (gChipInfo[i].ecoID == EcoID)
+            && (gChipInfo[i].customerID == CustomerID)
+            && (!gChipInfo[i].formalRelease)
+           )
+        {
+            return &gChipInfo[i];
+        }
+    }
+
+    return gcvNULL;
+}
+#endif /* _gc_feature_database_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
@@ -0,0 +1,2171 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_h_
+#define __gc_hal_h_
+
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+#include "gc_hal_base.h"
+#include "gc_hal_profiler.h"
+#include "gc_hal_driver.h"
+#if gcdENABLE_3D
+#include "gc_hal_statistics.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+******************************* Alignment Macros *******************************
+\******************************************************************************/
+
+/* Alignment with a non-power of two value. */
+#define gcmALIGN_NP2(n, align) (((n) + (align) - 1) - (((n) + (align) - 1) % (align)))
+
+#define gcmALIGN_NP2_SAFE(n, align)                                        \
+(\
+    (gcmALIGN_NP2((n) & ~0ULL, (align) & ~0ULL) ^ gcmALIGN_NP2(n, align)) ?   \
+        (n) : gcmALIGN_NP2(n, align)                                       \
+)
+
+/* Alignment with a power of two value. */
+#define gcmALIGN(n, align) (((n) + ((align) - 1)) & ~((align) - 1))
+
+#define gcmALIGN_SAFE(n, align)                                        \
+(\
+    (gcmALIGN((n) & ~0ULL, (align) & ~0ULL) ^ gcmALIGN(n, align)) ?    \
+         (n) : gcmALIGN(n, align)                                      \
+)
+
+#define gcmALIGN_BASE(n, align) \
+(\
+    ((n) & ~((align) - 1)) \
+)
+
+/******************************************************************************\
+***************************** Element Count Macro *****************************
+\******************************************************************************/
+
+#define gcmSIZEOF(a) \
+(\
+    (gctSIZE_T) (sizeof(a)) \
+)
+
+#define gcmCOUNTOF(a) \
+(\
+    sizeof(a) / sizeof(a[0]) \
+)
+
+/******************************************************************************\
+********************************* Cast Macro **********************************
+\******************************************************************************/
+#define gcmNAME_TO_PTR(na) \
+        gckKERNEL_QueryPointerFromName(kernel, gcmALL_TO_UINT32(na))
+
+#define gcmPTR_TO_NAME(ptr) \
+        gckKERNEL_AllocateNameFromPointer(kernel, ptr)
+
+#define gcmRELEASE_NAME(na) \
+        gckKERNEL_DeleteName(kernel, gcmALL_TO_UINT32(na))
+
+#define gcmALL_TO_UINT32(t) \
+(\
+    (gctUINT32) (gctUINTPTR_T) (t)\
+)
+
+#define gcmPTR_TO_UINT64(p) \
+(\
+    (gctUINT64) (gctUINTPTR_T) (p)\
+)
+
+#define gcmUINT64_TO_PTR(u) \
+(\
+    (gctPOINTER) (gctUINTPTR_T) (u)\
+)
+
+#define gcmUINT64_TO_TYPE(u, t) \
+(\
+    (t) (gctUINTPTR_T) (u)\
+)
+
+/******************************************************************************\
+******************************** Useful Macro *********************************
+\******************************************************************************/
+
+#define gcvINVALID_ADDRESS              ~0U
+#define gcvINVALID_VALUE                0xCCCCCCCC
+
+#define gcvINVALID_PHYSICAL_ADDRESS     ~0ULL
+
+#define gcmGET_PRE_ROTATION(rotate) \
+    ((rotate) & (~(gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y)))
+
+#define gcmGET_POST_ROTATION(rotate) \
+    ((rotate) & (gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y))
+
+typedef struct _gckHARDWARE *       gckHARDWARE;
+
+#define gcdMAX_GPU_COUNT               gcvCORE_COUNT
+
+#define gcdMAX_SURF_LAYERS             4
+
+#define gcdMAX_DRAW_BUFFERS            16
+
+#define gcdMAX_3DGPU_COUNT             8
+
+#define gcdMAX_MAJOR_CORE_COUNT        8
+
+#define gcdMAX_VERTEX_STREAM_COUNT     4
+/*******************************************************************************
+**
+**  gcmVERIFY_OBJECT
+**
+**      Assert if an object is invalid or is not of the specified type.  If the
+**      object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT
+**      will be returned from the current function.  In retail mode this macro
+**      does nothing.
+**
+**  ARGUMENTS:
+**
+**      obj     Object to test.
+**      t       Expected type of the object.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#define _gcmVERIFY_OBJECT(prefix, obj, t) \
+    if ((obj) == gcvNULL) \
+    { \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+                      #prefix "VERIFY_OBJECT failed: NULL"); \
+        prefix##TRACE(gcvLEVEL_ERROR, "  expected: %c%c%c%c", \
+                      gcmCC_PRINT(t)); \
+        prefix##ASSERT((obj) != gcvNULL); \
+        prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \
+        return gcvSTATUS_INVALID_OBJECT; \
+    } \
+    else if (((gcsOBJECT*) (obj))->type != t) \
+    { \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+                      #prefix "VERIFY_OBJECT failed: %c%c%c%c", \
+                      gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \
+        prefix##TRACE(gcvLEVEL_ERROR, "  expected: %c%c%c%c", \
+                      gcmCC_PRINT(t)); \
+        prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \
+        prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \
+        return gcvSTATUS_INVALID_OBJECT; \
+    }
+
+#   define gcmVERIFY_OBJECT(obj, t)     _gcmVERIFY_OBJECT(gcm, obj, t)
+#   define gcmkVERIFY_OBJECT(obj, t)    _gcmVERIFY_OBJECT(gcmk, obj, t)
+#else
+#   define gcmVERIFY_OBJECT(obj, t)     do {} while (gcvFALSE)
+#   define gcmkVERIFY_OBJECT(obj, t)    do {} while (gcvFALSE)
+#endif
+
+/******************************************************************************/
+/*VERIFY_OBJECT if special return expected*/
+/******************************************************************************/
+#ifndef EGL_API_ANDROID
+#   define _gcmVERIFY_OBJECT_RETURN(prefix, obj, t, retVal) \
+        do \
+        { \
+            if ((obj) == gcvNULL) \
+            { \
+                prefix##PRINT_VERSION(); \
+                prefix##TRACE(gcvLEVEL_ERROR, \
+                              #prefix "VERIFY_OBJECT_RETURN failed: NULL"); \
+                prefix##TRACE(gcvLEVEL_ERROR, "  expected: %c%c%c%c", \
+                              gcmCC_PRINT(t)); \
+                prefix##ASSERT((obj) != gcvNULL); \
+                prefix##FOOTER_ARG("retVal=%d", retVal); \
+                return retVal; \
+            } \
+            else if (((gcsOBJECT*) (obj))->type != t) \
+            { \
+                prefix##PRINT_VERSION(); \
+                prefix##TRACE(gcvLEVEL_ERROR, \
+                              #prefix "VERIFY_OBJECT_RETURN failed: %c%c%c%c", \
+                              gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \
+                prefix##TRACE(gcvLEVEL_ERROR, "  expected: %c%c%c%c", \
+                              gcmCC_PRINT(t)); \
+                prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \
+                prefix##FOOTER_ARG("retVal=%d", retVal); \
+                return retVal; \
+            } \
+        } \
+        while (gcvFALSE)
+#   define gcmVERIFY_OBJECT_RETURN(obj, t, retVal) \
+                            _gcmVERIFY_OBJECT_RETURN(gcm, obj, t, retVal)
+#   define gcmkVERIFY_OBJECT_RETURN(obj, t, retVal) \
+                            _gcmVERIFY_OBJECT_RETURN(gcmk, obj, t, retVal)
+#else
+#   define gcmVERIFY_OBJECT_RETURN(obj, t)     do {} while (gcvFALSE)
+#   define gcmVERIFY_OBJECT_RETURN(obj, t)    do {} while (gcvFALSE)
+#endif
+
+/******************************************************************************\
+********************************** gckOS Object *********************************
+\******************************************************************************/
+
+/* Construct a new gckOS object. */
+gceSTATUS
+gckOS_Construct(
+    IN gctPOINTER Context,
+    OUT gckOS * Os
+    );
+
+/* Destroy an gckOS object. */
+gceSTATUS
+gckOS_Destroy(
+    IN gckOS Os
+    );
+
+/* Query the video memory. */
+gceSTATUS
+gckOS_QueryVideoMemory(
+    IN gckOS Os,
+    OUT gctPHYS_ADDR * InternalAddress,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctPHYS_ADDR * ExternalAddress,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctPHYS_ADDR * ContiguousAddress,
+    OUT gctSIZE_T * ContiguousSize
+    );
+
+/* Allocate memory from the heap. */
+gceSTATUS
+gckOS_Allocate(
+    IN gckOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    );
+
+/* Free allocated memory. */
+gceSTATUS
+gckOS_Free(
+    IN gckOS Os,
+    IN gctPOINTER Memory
+    );
+
+/* Wrapper for allocation memory.. */
+gceSTATUS
+gckOS_AllocateMemory(
+    IN gckOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    );
+
+/* Wrapper for freeing memory. */
+gceSTATUS
+gckOS_FreeMemory(
+    IN gckOS Os,
+    IN gctPOINTER Memory
+    );
+
+/* Allocate paged memory. */
+gceSTATUS
+gckOS_AllocatePagedMemory(
+    IN gckOS Os,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctUINT32 * Gid,
+    OUT gctPHYS_ADDR * Physical
+    );
+
+/* Lock pages. */
+gceSTATUS
+gckOS_LockPages(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctBOOL Cacheable,
+    OUT gctPOINTER * Logical
+    );
+
+/* Map pages. */
+gceSTATUS
+gckOS_MapPagesEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctBOOL Writable,
+    IN gceVIDMEM_TYPE Type
+    );
+
+/* Map 1M pages. */
+gceSTATUS
+gckOS_Map1MPages(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctBOOL Writable,
+    IN gceVIDMEM_TYPE Type
+    );
+
+gceSTATUS
+gckOS_UnmapPages(
+    IN gckOS Os,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address
+    );
+
+/* Unlock pages. */
+gceSTATUS
+gckOS_UnlockPages(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical
+    );
+
+/* Free paged memory. */
+gceSTATUS
+gckOS_FreePagedMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes
+    );
+
+/* Allocate non-paged memory. */
+gceSTATUS
+gckOS_AllocateNonPagedMemory(
+    IN gckOS Os,
+    IN gctBOOL InUserSpace,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctPHYS_ADDR * Physical,
+    OUT gctPOINTER * Logical
+    );
+
+/* Free non-paged memory. */
+gceSTATUS
+gckOS_FreeNonPagedMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+/* Reserved memory. */
+gceSTATUS
+gckOS_RequestReservedMemory(
+    gckOS Os,
+    gctPHYS_ADDR_T Start,
+    gctSIZE_T Size,
+    const char * Name,
+    gctBOOL Requested,
+    gctPOINTER * MemoryHandle
+    );
+
+void
+gckOS_ReleaseReservedMemory(
+    gckOS Os,
+    gctPOINTER MemoryHandle
+    );
+
+/* Get the number fo bytes per page. */
+gceSTATUS
+gckOS_GetPageSize(
+    IN gckOS Os,
+    OUT gctSIZE_T * PageSize
+    );
+
+/* Get the physical address of a corresponding logical address. */
+gceSTATUS
+gckOS_GetPhysicalAddress(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Address
+    );
+
+/* Get real physical address from handle. */
+gceSTATUS
+gckOS_GetPhysicalFromHandle(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * PhysicalAddress
+    );
+
+/* Get the physical address of a corresponding user logical address. */
+gceSTATUS
+gckOS_UserLogicalToPhysical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Address
+    );
+
+/* Map physical memory. */
+gceSTATUS
+gckOS_MapPhysical(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    );
+
+/* Unmap previously mapped physical memory. */
+gceSTATUS
+gckOS_UnmapPhysical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+/* Read data from a hardware register. */
+gceSTATUS
+gckOS_ReadRegister(
+    IN gckOS Os,
+    IN gctUINT32 Address,
+    OUT gctUINT32 * Data
+    );
+
+/* Read data from a hardware register. */
+gceSTATUS
+gckOS_ReadRegisterEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    OUT gctUINT32 * Data
+    );
+
+/* Write data to a hardware register. */
+gceSTATUS
+gckOS_WriteRegister(
+    IN gckOS Os,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    );
+
+/* Write data to a hardware register. */
+gceSTATUS
+gckOS_WriteRegisterEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    );
+
+/* Write data to a hardware register without dump. */
+gceSTATUS
+gckOS_WriteRegisterEx_NoDump(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    );
+
+#ifdef __QNXNTO__
+static gcmINLINE gceSTATUS
+gckOS_WriteMemory(
+    IN gckOS Os,
+    IN gctPOINTER Address,
+    IN gctUINT32 Data
+    )
+{
+    /* Write memory. */
+    *(gctUINT32 *)Address = Data;
+    return gcvSTATUS_OK;
+}
+
+#else
+/* Write data to a 32-bit memory location. */
+gceSTATUS
+gckOS_WriteMemory(
+    IN gckOS Os,
+    IN gctPOINTER Address,
+    IN gctUINT32 Data
+    );
+#endif
+
+/* Map physical memory into the process space. */
+gceSTATUS
+gckOS_MapMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    );
+
+/* Unmap physical memory from the specified process space. */
+gceSTATUS
+gckOS_UnmapMemoryEx(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical,
+    IN gctUINT32 PID
+    );
+
+/* Unmap physical memory from the process space. */
+gceSTATUS
+gckOS_UnmapMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical
+    );
+
+/* Delete a mutex. */
+gceSTATUS
+gckOS_DeleteMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex
+    );
+
+/* Acquire a mutex. */
+gceSTATUS
+gckOS_AcquireMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex,
+    IN gctUINT32 Timeout
+    );
+
+/* Release a mutex. */
+gceSTATUS
+gckOS_ReleaseMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex
+    );
+
+/* Atomically exchange a pair of 32-bit values. */
+gceSTATUS
+gckOS_AtomicExchange(
+    IN gckOS Os,
+    IN OUT gctUINT32_PTR Target,
+    IN gctUINT32 NewValue,
+    OUT gctUINT32_PTR OldValue
+    );
+
+/* Atomically exchange a pair of pointers. */
+gceSTATUS
+gckOS_AtomicExchangePtr(
+    IN gckOS Os,
+    IN OUT gctPOINTER * Target,
+    IN gctPOINTER NewValue,
+    OUT gctPOINTER * OldValue
+    );
+
+gceSTATUS
+gckOS_AtomSetMask(
+    IN gctPOINTER Atom,
+    IN gctUINT32 Mask
+    );
+
+gceSTATUS
+gckOS_AtomClearMask(
+    IN gctPOINTER Atom,
+    IN gctUINT32 Mask
+    );
+
+gceSTATUS
+gckOS_DumpCallStack(
+    IN gckOS Os
+    );
+
+gceSTATUS
+gckOS_GetProcessNameByPid(
+    IN gctINT Pid,
+    IN gctSIZE_T Length,
+    OUT gctUINT8_PTR String
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomConstruct
+**
+**  Create an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Atom
+**          Pointer to a variable receiving the constructed atom.
+*/
+gceSTATUS
+gckOS_AtomConstruct(
+    IN gckOS Os,
+    OUT gctPOINTER * Atom
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomDestroy
+**
+**  Destroy an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomDestroy(
+    IN gckOS Os,
+    OUT gctPOINTER Atom
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomGet
+**
+**  Get the 32-bit value protected by an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable the receives the value of the atom.
+*/
+gceSTATUS
+gckOS_AtomGet(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomSet
+**
+**  Set the 32-bit value protected by an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**      gctINT32 Value
+**          The value of the atom.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomSet(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    IN gctINT32 Value
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomIncrement
+**
+**  Atomically increment the 32-bit integer value inside an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable the receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomIncrement(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    );
+
+/*******************************************************************************
+**
+**  gckOS_AtomDecrement
+**
+**  Atomically decrement the 32-bit integer value inside an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable the receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomDecrement(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    );
+
+/* Delay a number of milliseconds. */
+gceSTATUS
+gckOS_Delay(
+    IN gckOS Os,
+    IN gctUINT32 Delay
+    );
+
+/* Get time in milliseconds. */
+gceSTATUS
+gckOS_GetTicks(
+    OUT gctUINT32_PTR Time
+    );
+
+/* Compare time value. */
+gceSTATUS
+gckOS_TicksAfter(
+    IN gctUINT32 Time1,
+    IN gctUINT32 Time2,
+    OUT gctBOOL_PTR IsAfter
+    );
+
+/* Get time in microseconds. */
+gceSTATUS
+gckOS_GetTime(
+    OUT gctUINT64_PTR Time
+    );
+
+/* Memory barrier. */
+gceSTATUS
+gckOS_MemoryBarrier(
+    IN gckOS Os,
+    IN gctPOINTER Address
+    );
+
+/* Map user pointer. */
+gceSTATUS
+gckOS_MapUserPointer(
+    IN gckOS Os,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    );
+
+/* Unmap user pointer. */
+gceSTATUS
+gckOS_UnmapUserPointer(
+    IN gckOS Os,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size,
+    IN gctPOINTER KernelPointer
+    );
+
+/*******************************************************************************
+**
+**  gckOS_QueryNeedCopy
+**
+**  Query whether the memory can be accessed or mapped directly or it has to be
+**  copied.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Process ID of the current process.
+**
+**  OUTPUT:
+**
+**      gctBOOL_PTR NeedCopy
+**          Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
+**          gcvFALSE if the memory can be accessed or mapped dircetly.
+*/
+gceSTATUS
+gckOS_QueryNeedCopy(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    OUT gctBOOL_PTR NeedCopy
+    );
+
+/*******************************************************************************
+**
+**  gckOS_CopyFromUserData
+**
+**  Copy data from user to kernel memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER KernelPointer
+**          Pointer to kernel memory.
+**
+**      gctPOINTER Pointer
+**          Pointer to user memory.
+**
+**      gctSIZE_T Size
+**          Number of bytes to copy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_CopyFromUserData(
+    IN gckOS Os,
+    IN gctPOINTER KernelPointer,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size
+    );
+
+/*******************************************************************************
+**
+**  gckOS_CopyToUserData
+**
+**  Copy data from kernel to user memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER KernelPointer
+**          Pointer to kernel memory.
+**
+**      gctPOINTER Pointer
+**          Pointer to user memory.
+**
+**      gctSIZE_T Size
+**          Number of bytes to copy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_CopyToUserData(
+    IN gckOS Os,
+    IN gctPOINTER KernelPointer,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size
+    );
+
+gceSTATUS
+gckOS_SuspendInterrupt(
+    IN gckOS Os
+    );
+
+gceSTATUS
+gckOS_SuspendInterruptEx(
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+gceSTATUS
+gckOS_ResumeInterrupt(
+    IN gckOS Os
+    );
+
+gceSTATUS
+gckOS_ResumeInterruptEx(
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+/* Get the base address for the physical memory. */
+gceSTATUS
+gckOS_GetBaseAddress(
+    IN gckOS Os,
+    OUT gctUINT32_PTR BaseAddress
+    );
+
+/* Perform a memory copy. */
+gceSTATUS
+gckOS_MemCopy(
+    IN gctPOINTER Destination,
+    IN gctCONST_POINTER Source,
+    IN gctSIZE_T Bytes
+    );
+
+/* Zero memory. */
+gceSTATUS
+gckOS_ZeroMemory(
+    IN gctPOINTER Memory,
+    IN gctSIZE_T Bytes
+    );
+
+/*******************************************************************************
+**
+**  gckOS_GetProcessID
+**
+**  Get current process ID.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR ProcessID
+**          Pointer to the variable that receives the process ID.
+*/
+gceSTATUS
+gckOS_GetProcessID(
+    OUT gctUINT32_PTR ProcessID
+    );
+
+gceSTATUS
+gckOS_GetCurrentProcessID(
+    OUT gctUINT32_PTR ProcessID
+    );
+
+/*******************************************************************************
+**
+**  gckOS_GetThreadID
+**
+**  Get current thread ID.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR ThreadID
+**          Pointer to the variable that receives the thread ID.
+*/
+gceSTATUS
+gckOS_GetThreadID(
+    OUT gctUINT32_PTR ThreadID
+    );
+
+/******************************************************************************\
+********************************** Signal Object *********************************
+\******************************************************************************/
+
+/* Create a signal. */
+gceSTATUS
+gckOS_CreateSignal(
+    IN gckOS Os,
+    IN gctBOOL ManualReset,
+    OUT gctSIGNAL * Signal
+    );
+
+/* Destroy a signal. */
+gceSTATUS
+gckOS_DestroySignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    );
+
+/* Signal a signal. */
+gceSTATUS
+gckOS_Signal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctBOOL State
+    );
+
+/* Wait for a signal. */
+gceSTATUS
+gckOS_WaitSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctBOOL Interruptable,
+    IN gctUINT32 Wait
+    );
+
+#ifdef __QNXNTO__
+gceSTATUS
+gckOS_SignalPulse(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    );
+
+gceSTATUS
+gckOS_SignalPending(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    );
+#endif
+
+/* Map a user signal to the kernel space. */
+gceSTATUS
+gckOS_MapSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctHANDLE Process,
+    OUT gctSIGNAL * MappedSignal
+    );
+
+/* Unmap a user signal */
+gceSTATUS
+gckOS_UnmapSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    );
+
+/* Get scatter-gather table from memory. */
+gceSTATUS
+gckOS_MemoryGetSGT(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    );
+
+/* Map a page range of memory to user space. */
+gceSTATUS
+gckOS_MemoryMmap(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    INOUT gctPOINTER Vma
+    );
+
+/* Wrap a user memory to gctPHYS_ADDR. */
+gceSTATUS
+gckOS_WrapMemory(
+    IN gckOS Os,
+    IN gcsUSER_MEMORY_DESC_PTR Desc,
+    OUT gctSIZE_T *Bytes,
+    OUT gctPHYS_ADDR * Physical,
+    OUT gctBOOL *Contiguous,
+    OUT gctSIZE_T * PageCountCpu
+    );
+
+gceSTATUS
+gckOS_GetPolicyID(
+    IN gckOS Os,
+    IN gceVIDMEM_TYPE Type,
+    OUT gctUINT32_PTR PolicyID,
+    OUT gctUINT32_PTR AXIConfig
+    );
+
+/******************************************************************************\
+************************** Android Native Fence Sync ***************************
+\******************************************************************************/
+gceSTATUS
+gckOS_CreateSyncTimeline(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctHANDLE * Timeline
+    );
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+    IN gckOS Os,
+    IN gctHANDLE Timeline
+    );
+
+gceSTATUS
+gckOS_CreateNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctSIGNAL Signal,
+    OUT gctINT * FenceFD
+    );
+
+gceSTATUS
+gckOS_WaitNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    );
+
+#if !USE_NEW_LINUX_SIGNAL
+/* Create signal to be used in the user space. */
+gceSTATUS
+gckOS_CreateUserSignal(
+    IN gckOS Os,
+    IN gctBOOL ManualReset,
+    OUT gctINT * SignalID
+    );
+
+/* Destroy signal used in the user space. */
+gceSTATUS
+gckOS_DestroyUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID
+    );
+
+/* Wait for signal used in the user space. */
+gceSTATUS
+gckOS_WaitUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID,
+    IN gctUINT32 Wait
+    );
+
+/* Signal a signal used in the user space. */
+gceSTATUS
+gckOS_SignalUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID,
+    IN gctBOOL State
+    );
+#endif /* USE_NEW_LINUX_SIGNAL */
+
+/* Set a signal owned by a process. */
+#if defined(__QNXNTO__)
+gceSTATUS
+gckOS_UserSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctINT Recvid,
+    IN gctINT Coid
+    );
+#else
+gceSTATUS
+gckOS_UserSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctHANDLE Process
+    );
+#endif
+
+/******************************************************************************\
+** Cache Support
+*/
+
+gceSTATUS
+gckOS_CacheClean(
+    gckOS Os,
+    gctUINT32 ProcessID,
+    gctPHYS_ADDR Handle,
+    gctSIZE_T Offset,
+    gctPOINTER Logical,
+    gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gckOS_CacheFlush(
+    gckOS Os,
+    gctUINT32 ProcessID,
+    gctPHYS_ADDR Handle,
+    gctSIZE_T Offset,
+    gctPOINTER Logical,
+    gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gckOS_CacheInvalidate(
+    gckOS Os,
+    gctUINT32 ProcessID,
+    gctPHYS_ADDR Handle,
+    gctSIZE_T Offset,
+    gctPOINTER Logical,
+    gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gckOS_CPUPhysicalToGPUPhysical(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T CPUPhysical,
+    IN gctPHYS_ADDR_T * GPUPhysical
+    );
+
+gceSTATUS
+gckOS_GPUPhysicalToCPUPhysical(
+    IN gckOS Os,
+    IN gctUINT32 GPUPhysical,
+    IN gctPHYS_ADDR_T * CPUPhysical
+    );
+
+gceSTATUS
+gckOS_QueryOption(
+    IN gckOS Os,
+    IN gctCONST_STRING Option,
+    OUT gctUINT64 * Value
+    );
+
+/******************************************************************************\
+** Debug Support
+*/
+
+void
+gckOS_SetDebugLevel(
+    IN gctUINT32 Level
+    );
+
+void
+gckOS_SetDebugZone(
+    IN gctUINT32 Zone
+    );
+
+void
+gckOS_SetDebugLevelZone(
+    IN gctUINT32 Level,
+    IN gctUINT32 Zone
+    );
+
+void
+gckOS_SetDebugZones(
+    IN gctUINT32 Zones,
+    IN gctBOOL Enable
+    );
+
+void
+gckOS_SetDebugFile(
+    IN gctCONST_STRING FileName
+    );
+
+gceSTATUS
+gckOS_Broadcast(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gceBROADCAST Reason
+    );
+
+gceSTATUS
+gckOS_BroadcastHurry(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT Urgency
+    );
+
+gceSTATUS
+gckOS_BroadcastCalibrateSpeed(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT Idle,
+    IN gctUINT Time
+    );
+
+/*******************************************************************************
+**
+**  gckOS_SetGPUPower
+**
+**  Set the power of the GPU on or off.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gceCORE Core
+**          GPU whose power is set.
+**
+**      gctBOOL Clock
+**          gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
+**
+**      gctBOOL Power
+**          gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUPower(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctBOOL Clock,
+    IN gctBOOL Power
+    );
+
+gceSTATUS
+gckOS_ResetGPU(
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+gceSTATUS
+gckOS_PrepareGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+gceSTATUS
+gckOS_FinishGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core
+    );
+
+gceSTATUS
+gckOS_QueryGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctUINT32 * Frequency,
+    OUT gctUINT8 * Scale
+    );
+
+gceSTATUS
+gckOS_SetGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT8 Scale
+    );
+
+/*******************************************************************************
+** Semaphores.
+*/
+
+/* Create a new semaphore. */
+gceSTATUS
+gckOS_CreateSemaphore(
+    IN gckOS Os,
+    OUT gctPOINTER * Semaphore
+    );
+
+#if gcdENABLE_VG
+gceSTATUS
+gckOS_CreateSemaphoreVG(
+    IN gckOS Os,
+    OUT gctPOINTER * Semaphore
+    );
+#endif
+
+/* Delete a semahore. */
+gceSTATUS
+gckOS_DestroySemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    );
+
+/* Acquire a semahore. */
+gceSTATUS
+gckOS_AcquireSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    );
+
+/* Try to acquire a semahore. */
+gceSTATUS
+gckOS_TryAcquireSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    );
+
+/* Release a semahore. */
+gceSTATUS
+gckOS_ReleaseSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    );
+
+/*******************************************************************************
+** Timer API.
+*/
+
+typedef void (*gctTIMERFUNCTION)(gctPOINTER);
+
+/* Create a timer. */
+gceSTATUS
+gckOS_CreateTimer(
+    IN gckOS Os,
+    IN gctTIMERFUNCTION Function,
+    IN gctPOINTER Data,
+    OUT gctPOINTER * Timer
+    );
+
+/* Destory a timer. */
+gceSTATUS
+gckOS_DestroyTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer
+    );
+
+/* Start a timer. */
+gceSTATUS
+gckOS_StartTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer,
+    IN gctUINT32 Delay
+    );
+
+/* Stop a timer. */
+gceSTATUS
+gckOS_StopTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer
+    );
+
+/******************************************************************************\
+********************************* gckHEAP Object ********************************
+\******************************************************************************/
+
+typedef struct _gckHEAP *       gckHEAP;
+
+/* Construct a new gckHEAP object. */
+gceSTATUS
+gckHEAP_Construct(
+    IN gckOS Os,
+    IN gctSIZE_T AllocationSize,
+    OUT gckHEAP * Heap
+    );
+
+/* Destroy an gckHEAP object. */
+gceSTATUS
+gckHEAP_Destroy(
+    IN gckHEAP Heap
+    );
+
+/* Allocate memory. */
+gceSTATUS
+gckHEAP_Allocate(
+    IN gckHEAP Heap,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Node
+    );
+
+/* Free memory. */
+gceSTATUS
+gckHEAP_Free(
+    IN gckHEAP Heap,
+    IN gctPOINTER Node
+    );
+
+/* Profile the heap. */
+gceSTATUS
+gckHEAP_ProfileStart(
+    IN gckHEAP Heap
+    );
+
+gceSTATUS
+gckHEAP_ProfileEnd(
+    IN gckHEAP Heap,
+    IN gctCONST_STRING Title
+    );
+
+typedef struct _gckVIDMEM *         gckVIDMEM;
+typedef struct _gckKERNEL *         gckKERNEL;
+typedef struct _gckDB *             gckDB;
+typedef struct _gckDVFS *           gckDVFS;
+typedef struct _gckMMU *            gckMMU;
+typedef struct _gcsDEVICE *         gckDEVICE;
+
+/******************************************************************************\
+******************************** gckKERNEL Object ******************************
+\******************************************************************************/
+
+struct _gcsHAL_INTERFACE;
+
+/* Construct a new gckKERNEL object. */
+gceSTATUS
+gckKERNEL_Construct(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT ChipID,
+    IN gctPOINTER Context,
+    IN gckDEVICE Device,
+    IN gckDB SharedDB,
+    OUT gckKERNEL * Kernel
+    );
+
+/* Destroy an gckKERNEL object. */
+gceSTATUS
+gckKERNEL_Destroy(
+    IN gckKERNEL Kernel
+    );
+
+/* Dispatch a user-level command. */
+gceSTATUS
+gckKERNEL_Dispatch(
+    IN gckKERNEL Kernel,
+    IN gckDEVICE Device,
+    IN OUT struct _gcsHAL_INTERFACE * Interface
+    );
+
+/* Query Database requirements. */
+gceSTATUS
+    gckKERNEL_QueryDatabase(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 ProcessID,
+    IN OUT gcsHAL_INTERFACE * Interface
+    );
+
+/* Query the video memory. */
+gceSTATUS
+gckKERNEL_QueryVideoMemory(
+    IN gckKERNEL Kernel,
+    OUT struct _gcsHAL_INTERFACE * Interface
+    );
+
+/* Lookup the gckVIDMEM object for a pool. */
+gceSTATUS
+gckKERNEL_GetVideoMemoryPool(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    OUT gckVIDMEM * VideoMemory
+    );
+
+/* Map dedicated video memory node. */
+gceSTATUS
+gckKERNEL_MapVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctBOOL InUserSpace,
+    IN gcePOOL Pool,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 Offset,
+    IN gctUINT32 Bytes,
+    OUT gctPOINTER * Logical
+    );
+
+/* Unmap dedicated video memory. */
+gceSTATUS
+gckKERNEL_UnmapVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Pid,
+    IN gctSIZE_T Bytes
+    );
+
+/* Map memory. */
+gceSTATUS
+gckKERNEL_MapMemory(
+    IN gckKERNEL Kernel,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    );
+
+/* Unmap memory. */
+gceSTATUS
+gckKERNEL_UnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID
+    );
+/* Destroy reserved mem when destroy process*/
+gceSTATUS
+gckKERNEL_DestroyProcessReservedUserMap(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Pid
+    );
+
+/* Notification of events. */
+gceSTATUS
+gckKERNEL_Notify(
+    IN gckKERNEL Kernel,
+    IN gceNOTIFY Notifcation
+    );
+
+/*******************************************************************************
+**
+**  gckKERNEL_Recovery
+**
+**  Try to recover the GPU from a fatal error.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_Recovery(
+    IN gckKERNEL Kernel
+    );
+
+/* Get access to the user data. */
+gceSTATUS
+gckKERNEL_OpenUserData(
+    IN gckKERNEL Kernel,
+    IN gctBOOL NeedCopy,
+    IN gctPOINTER StaticStorage,
+    IN gctPOINTER UserPointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    );
+
+/* Release resources associated with the user data connection. */
+gceSTATUS
+gckKERNEL_CloseUserData(
+    IN gckKERNEL Kernel,
+    IN gctBOOL NeedCopy,
+    IN gctBOOL FlushData,
+    IN gctPOINTER UserPointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    );
+
+gceSTATUS
+gckDVFS_Construct(
+    IN gckHARDWARE Hardware,
+    OUT gckDVFS * Frequency
+    );
+
+gceSTATUS
+gckDVFS_Destroy(
+    IN gckDVFS Dvfs
+    );
+
+gceSTATUS
+gckDVFS_Start(
+    IN gckDVFS Dvfs
+    );
+
+gceSTATUS
+gckDVFS_Stop(
+    IN gckDVFS Dvfs
+    );
+
+/******************************************************************************\
+******************************* gckHARDWARE Object *****************************
+\******************************************************************************/
+
+/* Construct a new gckHARDWARE object. */
+gceSTATUS
+gckHARDWARE_Construct(
+    IN gckOS Os,
+    IN gckDEVICE Device,
+    IN gceCORE Core,
+    OUT gckHARDWARE * Hardware
+    );
+
+/* Post hardware resource allocation after gckHARDWARE object constructed. */
+gceSTATUS
+gckHARDWARE_PostConstruct(
+    IN gckHARDWARE Hardware
+    );
+
+/* Pre-destroy hardwre resource before destroying an gckHARDWARE object. */
+gceSTATUS
+gckHARDWARE_PreDestroy(
+    IN gckHARDWARE Hardware
+    );
+
+/* Destroy an gckHARDWARE object. */
+gceSTATUS
+gckHARDWARE_Destroy(
+    IN gckHARDWARE Hardware
+    );
+
+/* Get hardware type. */
+gceSTATUS
+gckHARDWARE_GetType(
+    IN gckHARDWARE Hardware,
+    OUT gceHARDWARE_TYPE * Type
+    );
+
+/* Query system memory requirements. */
+gceSTATUS
+gckHARDWARE_QuerySystemMemory(
+    IN gckHARDWARE Hardware,
+    OUT gctSIZE_T * SystemSize,
+    OUT gctUINT32 * SystemBaseAddress
+    );
+
+/* Build virtual address. */
+gceSTATUS
+gckHARDWARE_BuildVirtualAddress(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Index,
+    IN gctUINT32 Offset,
+    OUT gctUINT32 * Address
+    );
+
+/* Query command buffer requirements. */
+gceSTATUS
+gckHARDWARE_QueryCommandBuffer(
+    IN gckHARDWARE Hardware,
+    IN gceENGINE Engine,
+    OUT gctUINT32 * Alignment,
+    OUT gctUINT32 * ReservedHead,
+    OUT gctUINT32 * ReservedTail
+    );
+
+/* Add a PIPESELECT command in the command queue. */
+gceSTATUS
+gckHARDWARE_PipeSelect(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gcePIPE_SELECT Pipe,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Query the available memory. */
+gceSTATUS
+gckHARDWARE_QueryMemory(
+    IN gckHARDWARE Hardware,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * InternalBaseAddress,
+    OUT gctUINT32 * InternalAlignment,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ExternalBaseAddress,
+    OUT gctUINT32 * ExternalAlignment,
+    OUT gctUINT32 * HorizontalTileSize,
+    OUT gctUINT32 * VerticalTileSize
+    );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gckHARDWARE_QueryChipIdentity(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+    );
+
+gceSTATUS
+gckHARDWARE_QueryChipOptions(
+    IN gckHARDWARE Hardware,
+    OUT gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+    );
+
+
+/* Split a harwdare specific address into API stuff. */
+gceSTATUS
+gckHARDWARE_SplitMemory(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Address,
+    OUT gcePOOL * Pool,
+    OUT gctUINT32 * Offset
+    );
+
+/* Update command queue tail pointer. */
+gceSTATUS
+gckHARDWARE_UpdateQueueTail(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Offset
+    );
+
+/* Interrupt manager. */
+gceSTATUS
+gckHARDWARE_Interrupt(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_Notify(
+    IN gckHARDWARE Hardware
+    );
+
+/* Program MMU. */
+gceSTATUS
+gckHARDWARE_SetMMU(
+    IN gckHARDWARE Hardware,
+    IN gckMMU Mmu
+    );
+
+/* Flush the MMU. */
+gceSTATUS
+gckHARDWARE_FlushMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address,
+    IN gctUINT32 SubsequentBytes,
+    IN OUT gctUINT32 * Bytes
+    );
+
+gceSTATUS
+gckHARDWARE_FlushAsyncMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    );
+
+gceSTATUS
+gckHARDWARE_FlushMcfeMMU(
+    IN gckHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Get idle register. */
+gceSTATUS
+gckHARDWARE_GetIdle(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Wait,
+    OUT gctUINT32 * Data
+    );
+
+/* Flush the caches. */
+gceSTATUS
+gckHARDWARE_Flush(
+    IN gckHARDWARE Hardware,
+    IN gceKERNEL_FLUSH Flush,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    );
+
+/* Enable/disable fast clear. */
+gceSTATUS
+gckHARDWARE_SetFastClear(
+    IN gckHARDWARE Hardware,
+    IN gctINT Enable,
+    IN gctINT Compression
+    );
+
+gceSTATUS
+gckHARDWARE_ReadInterrupt(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32_PTR IDs
+    );
+
+/*
+* State timer helper.
+*/
+gceSTATUS
+gckHARDWARE_StartTimerReset(
+    IN gckHARDWARE Hardware
+    );
+
+/* Power management. */
+gceSTATUS
+gckHARDWARE_SetPowerState(
+    IN gckHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    );
+
+gceSTATUS
+gckHARDWARE_QueryPowerState(
+    IN gckHARDWARE Hardware,
+    OUT gceCHIPPOWERSTATE* State
+    );
+
+gceSTATUS
+gckHARDWARE_EnablePowerManagement(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gckHARDWARE_SetGpuProfiler(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL GpuProfiler
+    );
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+gceSTATUS
+gckHARDWARE_SetFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32   FscaleValue,
+    IN gctUINT32   ShaderFscaleValue
+    );
+
+gceSTATUS
+gckHARDWARE_GetFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT * FscaleValue,
+    IN gctUINT * MinFscaleValue,
+    IN gctUINT * MaxFscaleValue
+    );
+
+gceSTATUS
+gckHARDWARE_SetMinFscaleValue(
+    IN gckHARDWARE Hardware,
+    IN gctUINT MinFscaleValue
+    );
+#endif
+
+gceSTATUS
+gckHARDWARE_InitializeHardware(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_Reset(
+    IN gckHARDWARE Hardware
+    );
+
+/* Check for Hardware features. */
+gceSTATUS
+gckHARDWARE_IsFeatureAvailable(
+    IN gckHARDWARE Hardware,
+    IN gceFEATURE Feature
+    );
+
+gceSTATUS
+gckHARDWARE_DumpMMUException(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_DumpGPUState(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_InitDVFS(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckHARDWARE_QueryLoad(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT32 * Load
+    );
+
+gceSTATUS
+gckHARDWARE_SetDVFSPeroid(
+    IN gckHARDWARE Hardware,
+    IN gctUINT32 Frequency
+    );
+
+gceSTATUS
+gckHARDWARE_QueryStateTimer(
+    IN gckHARDWARE Hardware,
+    OUT gctUINT64_PTR On,
+    OUT gctUINT64_PTR Off,
+    OUT gctUINT64_PTR Idle,
+    OUT gctUINT64_PTR Suspend
+    );
+
+gceSTATUS
+gckHARDWARE_Fence(
+    IN gckHARDWARE Hardware,
+    IN gceENGINE Engine,
+    IN gctPOINTER Logical,
+    IN gctUINT32 FenceAddress,
+    IN gctUINT64 FenceData,
+    IN OUT gctUINT32 * Bytes
+    );
+
+#if !gcdENABLE_VG
+/******************************************************************************\
+***************************** gckINTERRUPT Object ******************************
+\******************************************************************************/
+
+typedef struct _gckINTERRUPT *  gckINTERRUPT;
+
+typedef gceSTATUS (* gctINTERRUPT_HANDLER)(
+    IN gckKERNEL Kernel
+    );
+
+gceSTATUS
+gckINTERRUPT_Construct(
+    IN gckKERNEL Kernel,
+    OUT gckINTERRUPT * Interrupt
+    );
+
+gceSTATUS
+gckINTERRUPT_Destroy(
+    IN gckINTERRUPT Interrupt
+    );
+
+gceSTATUS
+gckINTERRUPT_SetHandler(
+    IN gckINTERRUPT Interrupt,
+    IN OUT gctINT32_PTR Id,
+    IN gctINTERRUPT_HANDLER Handler
+    );
+
+gceSTATUS
+gckINTERRUPT_Notify(
+    IN gckINTERRUPT Interrupt,
+    IN gctBOOL Valid
+    );
+#endif
+
+/******************************************************************************\
+********************************* gckMMU Object ********************************
+\******************************************************************************/
+
+/* Construct a new gckMMU object. */
+gceSTATUS
+gckMMU_Construct(
+    IN gckKERNEL Kernel,
+    IN gctSIZE_T MmuSize,
+    OUT gckMMU * Mmu
+    );
+
+/* Destroy an gckMMU object. */
+gceSTATUS
+gckMMU_Destroy(
+    IN gckMMU Mmu
+    );
+
+/* Allocate pages inside the MMU. */
+gceSTATUS
+gckMMU_AllocatePages(
+    IN gckMMU Mmu,
+    IN gctSIZE_T PageCount,
+    IN gcePAGE_TYPE PageType,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    );
+
+gceSTATUS
+gckMMU_AllocatePagesEx(
+    IN gckMMU Mmu,
+    IN gctSIZE_T PageCount,
+    IN gceVIDMEM_TYPE Type,
+    IN gcePAGE_TYPE PageType,
+    IN gctBOOL Secure,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    );
+
+/* Remove a page table from the MMU. */
+gceSTATUS
+gckMMU_FreePages(
+    IN gckMMU Mmu,
+    IN gctBOOL Secure,
+    IN gcePAGE_TYPE PageType,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctSIZE_T PageCount
+    );
+
+/* Set the MMU page with info. */
+gceSTATUS
+gckMMU_SetPage(
+   IN gckMMU Mmu,
+   IN gctPHYS_ADDR_T PageAddress,
+   IN gcePAGE_TYPE PageType,
+   IN gctBOOL Writable,
+   IN gctUINT32 *PageEntry
+   );
+
+gceSTATUS
+gckMMU_Flush(
+    IN gckMMU Mmu,
+    IN gceVIDMEM_TYPE Type
+    );
+
+gceSTATUS
+gckMMU_DumpPageTableEntry(
+    IN gckMMU Mmu,
+    IN gceAREA_TYPE AreaType,
+    IN gctUINT32 Address
+    );
+
+gceSTATUS
+gckMMU_FillFlatMapping(
+    IN gckMMU Mmu,
+    IN gctUINT64 PhysBase,
+    IN gctSIZE_T Size
+    );
+
+gceSTATUS
+gckMMU_IsFlatMapped(
+    IN gckMMU Mmu,
+    IN gctUINT64 Physical,
+    IN gctUINT32 Address,
+    OUT gctBOOL *In
+    );
+
+gceSTATUS
+gckMMU_GetAreaType(
+    IN gckMMU Mmu,
+    IN gctUINT32 GpuAddress,
+    OUT gceAREA_TYPE *AreaType
+    );
+
+gceSTATUS
+gckHARDWARE_QueryContextProfile(
+    IN gckHARDWARE Hardware,
+    IN gctBOOL Reset,
+    IN gckCONTEXT Context,
+    OUT gcsPROFILER_COUNTERS_PART1 * Counters_part1,
+    OUT gcsPROFILER_COUNTERS_PART2 * Counters_part2
+    );
+
+gceSTATUS
+gckHARDWARE_UpdateContextProfile(
+    IN gckHARDWARE Hardware,
+    IN gckCONTEXT Context
+    );
+
+gceSTATUS
+gckHARDWARE_InitProfiler(
+    IN gckHARDWARE Hardware
+    );
+
+gceSTATUS
+gckOS_DetectProcessByName(
+    IN gctCONST_POINTER Name
+    );
+
+void
+gckOS_DumpParam(
+    void
+    );
+
+#ifdef __cplusplus
+}
+#endif
+
+#if gcdENABLE_VG
+#include "gc_hal_vg.h"
+#endif
+
+#endif /* __gc_hal_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h
@@ -0,0 +1,5818 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_base_h_
+#define __gc_hal_base_h_
+
+#include "gc_hal_enum.h"
+#include "gc_hal_types.h"
+#include "gc_hal_debug_zones.h"
+#include "shared/gc_hal_base_shared.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gckOS *                 gckOS;
+typedef struct _gcoHAL *                gcoHAL;
+typedef struct _gcoOS *                 gcoOS;
+typedef struct _gco2D *                 gco2D;
+typedef struct gcsATOM *                gcsATOM_PTR;
+
+typedef struct _gco3D *                 gco3D;
+typedef struct _gcoCL *                 gcoCL;
+typedef struct _gcoVX *                 gcoVX;
+typedef struct _gcsFAST_FLUSH *         gcsFAST_FLUSH_PTR;
+
+typedef struct _gcoSURF *               gcoSURF;
+typedef struct _gcsSURF_NODE *          gcsSURF_NODE_PTR;
+typedef struct _gcsSURF_FORMAT_INFO *   gcsSURF_FORMAT_INFO_PTR;
+typedef struct _gcsPOINT *              gcsPOINT_PTR;
+typedef struct _gcsSIZE *               gcsSIZE_PTR;
+typedef struct _gcsRECT *               gcsRECT_PTR;
+typedef struct _gcsBOUNDARY *           gcsBOUNDARY_PTR;
+typedef struct _gcoHARDWARE *           gcoHARDWARE;
+typedef union  _gcuVIDMEM_NODE *        gcuVIDMEM_NODE_PTR;
+typedef struct _gcsVIDMEM_NODE *        gckVIDMEM_NODE;
+typedef struct _gcsVIDMEM_BLOCK *       gckVIDMEM_BLOCK;
+
+#if gcdENABLE_VG
+typedef struct _gcoVG *                 gcoVG;
+typedef struct _gcsCOMPLETION_SIGNAL *  gcsCOMPLETION_SIGNAL_PTR;
+typedef struct _gcsCONTEXT_MAP *        gcsCONTEXT_MAP_PTR;
+#else
+typedef void *                          gcoVG;
+#endif
+
+typedef struct _gcoFENCE *              gcoFENCE;
+typedef struct _gcsSYNC_CONTEXT *       gcsSYNC_CONTEXT_PTR;
+
+typedef struct _gcsUSER_MEMORY_DESC *   gcsUSER_MEMORY_DESC_PTR;
+
+/* Immuatable features from database */
+typedef struct _gcsNN_FIXED_FEATURE
+{
+    gctUINT  vipCoreCount;
+    gctUINT  nnCoreCount;           /* total nn core count */
+    gctUINT  nnCoreCountInt8;       /* total nn core count supporting int8 */
+    gctUINT  nnCoreCountInt16;      /* total nn core count supporting int16 */
+    gctUINT  nnCoreCountFloat16;    /* total nn core count supporting float16 */
+    gctUINT  nnCoreCountBFloat16;    /* total nn core count supporting Bfloat16 */
+    gctUINT  nnMadPerCore;
+    gctUINT  nnInputBufferDepth;
+    gctUINT  nnAccumBufferDepth;
+    gctUINT  nnFCNonPrunAccel;
+    gctUINT  nnInImageOffsetBits;
+    gctUINT  tpCoreCount; /* full-function core count */
+    gctUINT  tpPwlLUTCount;
+    gctUINT  tpPwlLUTSize;
+    gctUINT  vip7Version;
+    gctUINT  vipBrickMode;
+    gctUINT  tpReorderInImageSize;
+    gctUINT  tpliteCoreCount; /* fc-only core count */
+    gctUINT  nnFP16XYDPX;
+    gctUINT  nnFP16XYDPY;
+    gctUINT  nnFP16ZDP;
+    gctUINT  zrlBits;
+    gctUINT  uscCacheControllers;
+    gctUINT  uscBanks;
+    gctUINT  nnLanesPerOutCycle;
+    gctUINT  maxOTNumber;
+    gctUINT  physicalVipSramWidthInByte;
+    gctUINT  equivalentVipsramWidthInByte;
+    gctUINT  shaderCoreCount;
+    gctUINT  latencyHidingAtFullAxiBw;
+    gctUINT  axiBusWidth;
+    gctUINT  nnMaxKXSize;
+    gctUINT  nnMaxKYSize;
+    gctUINT  nnMaxKZSize;
+} gcsNN_FIXED_FEATURE;
+
+/* Features can be customized from outside */
+typedef struct _gcsNN_CUSTOMIZED_FEATURE
+{
+    gctUINT  vipSRAMSize;
+    gctUINT  axiSRAMSize;
+    gctFLOAT ddrReadBWLimit;
+    gctFLOAT ddrWriteBWLimit;
+    gctFLOAT ddrTotalBWLimit;
+    gctFLOAT axiSramReadBWLimit;
+    gctFLOAT axiSramWriteBWLimit;
+    gctFLOAT axiSramTotalBWLimit;
+    gctFLOAT axiBusReadBWLimit;
+    gctFLOAT axiBusWriteBWLimit;
+    gctFLOAT axiBusTotalBWLimit;
+    gctUINT  vipSWTiling;
+    gctFLOAT ddrLatency;
+    gctUINT  freqInMHZ;
+    gctUINT  axiClockFreqInMHZ;
+    gctUINT  maxSocOTNumber;/*max SOC outstanding transfer number*/
+    gctUINT  nnWriteWithoutUSC;
+    gctUINT  depthWiseSupport;
+    gctUINT  vipVectorPrune;
+    gctUINT  ddrKernelBurstSize;
+} gcsNN_CUSTOMIZED_FEATURE;
+
+/* Features are unified (hardcoded) for hardwares */
+typedef struct _gcsNN_UNIFIED_FEATURE
+{
+    gctUINT  nnUSCCacheSize;
+    gctUINT  nnCmdSizeInBytes;
+    gctUINT  tpCmdSizeInBytes;
+    gctUINT  vipCoefDecodePerf;
+    gctUINT  vipCachedReadFromSram;
+    gctUINT  vipImagePartialCache;
+    gctUINT  lanesPerConv;
+    gctUINT  maxTileSize;
+    gctUINT  fullCacheKernelHeadFix : 1;
+    gctUINT  conv1x1HalfPerformance : 1;
+    gctUINT  per3DTileBubbleFix : 1;
+    gctUINT  cacheLineModeDisabled : 1;
+    gctUINT  tpReOrderFix : 1;
+    gctUINT  zdp3NoCompressFix : 1;
+    gctUINT  asyncCopyPerfFix : 1;
+    gctUINT  accurateTileBW : 1;
+    gctUINT  zxdp3KernelReadConflictFix : 1;
+    gctUINT  axiSramSlowedDownByAddr:1;
+    gctUINT  slowNNReqArbitrationFix:1;
+    gctUINT  singlePortAccBuffer : 1;
+    gctUINT  convOutFifoDepthFix : 1;
+    gctUINT  smallBatchEnable : 1;
+    gctUINT  axiSramOnlySWTiling : 1;
+    gctUINT  imageNotPackedInSram : 1;
+    gctUINT  coefDeltaCordOverFlowZRL8BitFix : 1;
+    gctUINT  lowEfficiencyOfIDWriteImgBufFix : 1;
+    gctUINT  xyOffsetLimitationFix : 1;
+    gctUINT  kernelPerCoreLTOneThirdCoefFix : 1;
+    gctUINT  diffConditionForCachelineModePreFix : 1;
+} gcsNN_UNIFIED_FEATURE;
+
+/* Features are derived from above ones */
+typedef struct _gcsNN_DERIVIED_FEATURE
+{
+    gctUINT  nnDPAmount;
+    gctUINT  nnXYDPX;
+    gctUINT  nnXYDPY;
+    gctUINT  nnZDP;
+    gctFLOAT totalLatency;
+    gctFLOAT internalLatency;
+    gctFLOAT ddrReadBWInBytePerCycle;
+    gctFLOAT ddrWriteBWInBytePerCycle;
+} gcsNN_DERIVED_FEATURE;
+
+/******************************************************************************\
+********************* Share obj lock/unlock macros. ****************************
+\******************************************************************************/
+#define gcmLOCK_SHARE_OBJ(Obj) \
+{ \
+    if(Obj->sharedLock != gcvNULL)\
+    {\
+        (gcoOS_AcquireMutex(\
+                     gcvNULL, Obj->sharedLock, gcvINFINITE));\
+    }\
+}
+
+
+#define gcmUNLOCK_SHARE_OBJ(Obj)\
+{\
+    if(Obj->sharedLock != gcvNULL)\
+    {\
+        (gcoOS_ReleaseMutex(gcvNULL, Obj->sharedLock));\
+    }\
+}
+
+typedef struct _gcsSystemInfo
+{
+    /* memory latency number for SH data fetch, in SH cycle*/
+    gctUINT32 memoryLatencySH;
+}
+gcsSystemInfo;
+
+
+#define gcPLS_INITIALIZER \
+{ \
+    gcvNULL, /* gcoOS object.      */ \
+    gcvNULL, /* gcoHAL object.     */ \
+    0, /* internalSize       */ \
+    0, /* internalPhysName   */ \
+    gcvNULL, /* internalLogical    */ \
+    0, /* externalSize       */ \
+    0, /* externalPhysName   */ \
+    gcvNULL, /* externalLogical    */ \
+    0, /* contiguousSize     */ \
+    0, /* contiguousPhysName */ \
+    gcvNULL, /* contiguousLogical  */ \
+    gcvNULL, /* eglDisplayInfo     */ \
+    gcvNULL, /* eglSurfaceInfo     */ \
+    gcvSURF_A8R8G8B8,/* eglConfigFormat    */ \
+    gcvNULL, /* reference          */ \
+    0, /* processID          */ \
+    0, /* threadID           */ \
+    gcvFALSE, /* exiting            */ \
+    gcvFALSE, /* Special flag for NP2 texture. */ \
+    gcvFALSE, /* device open.       */ \
+    gcvNULL, /* destructor         */ \
+    gcvNULL, /* accessLock         */ \
+    gcvNULL, /* GL FE compiler lock*/ \
+    gcvNULL, /* CL FE compiler lock*/ \
+    gcvNULL, /* VX context lock    */ \
+    gcvPATCH_NOTINIT,/* global patchID     */ \
+    gcvNULL, /* global fenceID*/ \
+    gcvNULL, /* mainThreadHandle */ \
+    gcvFALSE, /* memory profile flag */ \
+    gcvNULL, /* profileLock;        */ \
+    0, /* allocCount;         */ \
+    0, /* allocSize;          */ \
+    0, /* maxAllocSize;       */ \
+    0, /* freeCount;          */ \
+    0, /* freeSize;           */ \
+    0, /* currentSize;        */ \
+    0, /* video_allocCount;   */ \
+    0, /* video_allocSize;    */ \
+    0, /* video_maxAllocSize; */ \
+    0, /* video_freeCount;    */ \
+    0, /* video_freeSize;     */ \
+    0, /* video_currentSize;  */ \
+}
+
+/******************************************************************************\
+******************************* Thread local storage *************************
+\******************************************************************************/
+
+typedef struct _gcsDRIVER_TLS * gcsDRIVER_TLS_PTR;
+
+typedef struct _gcsDRIVER_TLS
+{
+    void (* destructor)(gcsDRIVER_TLS_PTR Tls);
+}
+gcsDRIVER_TLS;
+
+typedef struct _gcsTLS * gcsTLS_PTR;
+
+typedef struct _gcsTLS
+{
+    gceHARDWARE_TYPE            currentType;
+    gceHARDWARE_TYPE            targetType;
+
+    /* To which core device control is called,
+    * it is index in a hardware type.
+    */
+    gctUINT32                   currentCoreIndex;
+
+    /* Current 3D hardwre of this thread */
+    gcoHARDWARE                 currentHardware;
+
+    /* Default 3D hardware of this thread */
+    gcoHARDWARE                 defaultHardware;
+
+    /* Only for separated 3D and 2D */
+    gcoHARDWARE                 hardware2D;
+#if gcdENABLE_VG
+    gcoVGHARDWARE               vg;
+    gcoVG                       engineVG;
+#endif /* gcdENABLE_VG */
+#if gcdENABLE_3D
+    gco3D                       engine3D;
+#endif
+#if gcdENABLE_2D
+    gco2D                       engine2D;
+#if gcdDUMP_2D
+    gctUINT32                   newDump2DFlag;
+#endif
+
+#endif
+    gcoVX                       engineVX;
+
+    gctBOOL                     copied;
+
+    /* libGAL.so handle */
+    gctHANDLE                   handle;
+
+    /* If true, do not releas 2d engine and hardware in hal layer */
+    gctBOOL                     release2DUpper;
+
+    /* Driver tls. */
+    gcsDRIVER_TLS_PTR           driverTLS[gcvTLS_KEY_COUNT];
+}
+gcsTLS;
+
+typedef struct _gcsSURF_VIEW
+{
+    gcoSURF surf;
+    gctUINT firstSlice;
+    gctUINT numSlices;
+}gcsSURF_VIEW;
+
+/* gcsHAL_Limits*/
+typedef struct _gcsHAL_LIMITS
+{
+    /* chip info */
+    gceCHIPMODEL    chipModel;
+    gctUINT32       chipRevision;
+    gctUINT32       featureCount;
+    gctUINT32       *chipFeatures;
+
+    /* target caps */
+    gctUINT32         maxWidth;
+    gctUINT32         maxHeight;
+    gctUINT32         multiTargetCount;
+    gctUINT32         maxSamples;
+
+}gcsHAL_LIMITS;
+
+
+typedef struct _gcsHAL_CHIPIDENTITY
+{
+    gceCHIPMODEL                chipModel;
+    gctUINT32                   chipRevision;
+    gctUINT32                   productID;
+    gctUINT32                   customerID;
+    gctUINT32                   ecoID;
+    gceCHIP_FLAG                chipFlags;
+    gctUINT64                   platformFlagBits;
+}
+gcsHAL_CHIPIDENTITY;
+
+/******************************************************************************\
+********************************* gcoHAL Object *********************************
+\******************************************************************************/
+
+/* Construct a new gcoHAL object. */
+gceSTATUS
+gcoHAL_ConstructEx(
+    IN gctPOINTER Context,
+    IN gcoOS Os,
+    OUT gcoHAL * Hal
+    );
+
+/* Destroy an gcoHAL object. */
+gceSTATUS
+gcoHAL_DestroyEx(
+    IN gcoHAL Hal
+    );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoHAL_Construct(
+    IN gctPOINTER Context,
+    IN gcoOS Os,
+    OUT gcoHAL * Hal
+    );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoHAL_Destroy(
+    IN gcoHAL Hal
+    );
+
+/* Get HAL options */
+gceSTATUS
+gcoHAL_GetOption(
+     IN gcoHAL Hal,
+     IN gceOPTION Option
+     );
+
+gceSTATUS
+gcoHAL_FrameInfoOps(
+    IN gcoHAL Hal,
+    IN gceFRAMEINFO FrameInfo,
+    IN gceFRAMEINFO_OP Op,
+    IN OUT gctUINT * Val
+    );
+
+/* Set HAL options */
+gceSTATUS
+gcoHAL_SetOption(
+     IN gcoHAL Hal,
+     IN gceOPTION Option,
+     IN gctBOOL Value
+    );
+
+gceSTATUS
+gcoHAL_GetHardware(
+    IN gcoHAL Hal,
+    OUT gcoHARDWARE* Hw
+    );
+
+#if gcdENABLE_2D
+/* Get pointer to gco2D object. */
+gceSTATUS
+gcoHAL_Get2DEngine(
+    IN gcoHAL Hal,
+    OUT gco2D * Engine
+    );
+#endif
+
+#if gcdENABLE_3D
+gceSTATUS
+gcoHAL_GetSpecialHintData(
+    IN gcoHAL Hal,
+    OUT gctINT * Hint
+    );
+/*
+** Deprecated(Don't use it), keep it here for external library(libgcu.so)
+*/
+gceSTATUS
+gcoHAL_Get3DEngine(
+    IN gcoHAL Hal,
+    OUT gco3D * Engine
+    );
+#endif /* gcdENABLE_3D */
+
+
+gceSTATUS
+gcoHAL_GetProductName(
+    IN gcoHAL Hal,
+    OUT gctSTRING *ProductName,
+    OUT gctUINT *PID
+    );
+
+gceSTATUS
+gcoHAL_GetProductNameWithHardware(
+    IN  gcoHARDWARE Hardware,
+    OUT gctSTRING *ProductName,
+    OUT gctUINT *PID
+    );
+
+gceSTATUS
+gcoHAL_SetFscaleValue(
+    IN gcoHAL Hal,
+    IN gctUINT CoreIndex,
+    IN gctUINT FscaleValue,
+    IN gctUINT ShaderFscaleValue
+    );
+
+gceSTATUS
+gcoHAL_GetFscaleValue(
+    OUT gctUINT * FscaleValue,
+    OUT gctUINT * MinFscaleValue,
+    OUT gctUINT * MaxFscaleValue
+    );
+
+gceSTATUS
+gcoHAL_SetBltNP2Texture(
+    gctBOOL enable
+    );
+
+gceSTATUS
+gcoHAL_ExportVideoMemory(
+    IN gctUINT32 Handle,
+    IN gctUINT32 Flags,
+    OUT gctINT32 * FD
+    );
+
+gceSTATUS
+gcoHAL_NameVideoMemory(
+    IN gctUINT32 Handle,
+    OUT gctUINT32 * Name
+    );
+
+gceSTATUS
+gcoHAL_ImportVideoMemory(
+    IN gctUINT32 Name,
+    OUT gctUINT32 * Handle
+    );
+
+gceSTATUS
+gcoHAL_GetVideoMemoryFd(
+    IN gctUINT32 Handle,
+    OUT gctINT * Fd
+    );
+
+/* Verify whether the specified feature is available in hardware. */
+gceSTATUS
+gcoHAL_IsFeatureAvailable(
+    IN gcoHAL Hal,
+    IN gceFEATURE Feature
+    );
+
+gceSTATUS
+gcoHAL_IsFeatureAvailableWithHardware(
+    IN  gcoHARDWARE Hardware,
+    IN gceFEATURE Feature
+    );
+
+gceSTATUS
+gcoHAL_IsFeatureAvailable1(
+    IN gcoHAL Hal,
+    IN gceFEATURE Feature
+    );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gcoHAL_QueryChipIdentity(
+    IN gcoHAL Hal,
+    OUT gceCHIPMODEL* ChipModel,
+    OUT gctUINT32* ChipRevision,
+    OUT gctUINT32* ChipFeatures,
+    OUT gctUINT32* ChipMinorFeatures
+    );
+
+gceSTATUS gcoHAL_QueryChipIdentityWithHardware(
+    IN  gcoHARDWARE Hardware,
+    OUT gceCHIPMODEL* ChipModel,
+    OUT gctUINT32* ChipRevision
+    );
+
+gceSTATUS gcoHAL_QueryChipIdentityEx(
+    IN gcoHAL Hal,
+    IN gctUINT32 SizeOfParam,
+    OUT gcsHAL_CHIPIDENTITY *ChipIdentity
+    );
+
+
+gceSTATUS
+gcoHAL_QuerySuperTileMode(
+    OUT gctUINT32_PTR SuperTileMode
+    );
+
+gceSTATUS
+gcoHAL_QueryChipAxiBusWidth(
+    OUT gctBOOL * AXI128Bits
+    );
+
+gceSTATUS
+gcoHAL_QueryMultiGPUAffinityConfig(
+    IN gceHARDWARE_TYPE Type,
+    OUT gceMULTI_GPU_MODE *Mode,
+    OUT gctUINT32_PTR CoreIndex
+    );
+
+gceSTATUS
+gcoHAL_QuerySRAM(
+    IN gcoHAL Hal,
+    IN gcePOOL Type,
+    OUT gctUINT32 *Size,
+    OUT gctUINT32 *GPUVirtAddr,
+    OUT gctPHYS_ADDR_T *GPUPhysAddr,
+    OUT gctUINT32 *GPUPhysName,
+    OUT gctPHYS_ADDR_T *CPUPhysAddr
+    );
+
+#ifdef LINUX
+gctINT32
+gcoOS_EndRecordAllocation(void);
+void
+gcoOS_RecordAllocation(void);
+void
+gcoOS_AddRecordAllocation(gctSIZE_T Size);
+#endif
+
+/* Query the amount of video memory. */
+gceSTATUS
+gcoHAL_QueryVideoMemory(
+    IN gcoHAL Hal,
+    OUT gctUINT32 * InternalPhysName,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * ExternalPhysName,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ContiguousPhysName,
+    OUT gctSIZE_T * ContiguousSize
+    );
+
+/* Map video memory. */
+gceSTATUS
+gcoHAL_MapMemory(
+    IN gcoHAL Hal,
+    IN gctUINT32 PhysName,
+    IN gctSIZE_T NumberOfBytes,
+    OUT gctPOINTER * Logical
+    );
+
+/* Unmap video memory. */
+gceSTATUS
+gcoHAL_UnmapMemory(
+    IN gcoHAL Hal,
+    IN gctUINT32 PhysName,
+    IN gctSIZE_T NumberOfBytes,
+    IN gctPOINTER Logical
+    );
+
+/* Schedule an unmap of a buffer mapped through its physical address. */
+gceSTATUS
+gcoHAL_ScheduleUnmapMemory(
+    IN gcoHAL Hal,
+    IN gctUINT32 PhysName,
+    IN gctSIZE_T NumberOfBytes,
+    IN gctPOINTER Logical
+    );
+
+/* Allocate video memory. */
+gceSTATUS
+gcoOS_AllocateVideoMemory(
+    IN gcoOS Os,
+    IN gctBOOL InUserSpace,
+    IN gctBOOL InCacheable,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctUINT32 * Physical,
+    OUT gctPOINTER * Logical,
+    OUT gctPOINTER * Handle
+    );
+
+/* Free video memory. */
+gceSTATUS
+gcoOS_FreeVideoMemory(
+    IN gcoOS Os,
+    IN gctPOINTER Handle
+    );
+
+/* Lock video memory. */
+gceSTATUS
+gcoOS_LockVideoMemory(
+    IN gcoOS Os,
+    IN gctPOINTER Handle,
+    IN gctBOOL InUserSpace,
+    IN gctBOOL InCacheable,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Logical
+    );
+
+/* Commit the current command buffer. */
+gceSTATUS
+gcoHAL_Commit(
+    IN gcoHAL Hal,
+    IN gctBOOL Stall
+    );
+
+#if gcdENABLE_3D
+/* Sencd fence command. */
+gceSTATUS
+gcoHAL_SendFence(
+    IN gcoHAL Hal
+    );
+#endif /* gcdENABLE_3D */
+
+/* Query the tile capabilities. */
+gceSTATUS
+gcoHAL_QueryTiled(
+    IN gcoHAL Hal,
+    OUT gctINT32 * TileWidth2D,
+    OUT gctINT32 * TileHeight2D,
+    OUT gctINT32 * TileWidth3D,
+    OUT gctINT32 * TileHeight3D
+    );
+
+gceSTATUS
+gcoHAL_Compact(
+    IN gcoHAL Hal
+    );
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY
+gceSTATUS
+gcoHAL_ProfileStart(
+    IN gcoHAL Hal
+    );
+
+gceSTATUS
+gcoHAL_ProfileEnd(
+    IN gcoHAL Hal,
+    IN gctCONST_STRING Title
+    );
+#endif
+
+/* Power Management */
+gceSTATUS
+gcoHAL_SetPowerManagementState(
+    IN gcoHAL Hal,
+    IN gceCHIPPOWERSTATE State
+    );
+
+gceSTATUS
+gcoHAL_QueryPowerManagementState(
+    IN gcoHAL Hal,
+    OUT gceCHIPPOWERSTATE *State
+    );
+
+/* Set the filter type for filter blit. */
+gceSTATUS
+gcoHAL_SetFilterType(
+    IN gcoHAL Hal,
+    IN gceFILTER_TYPE FilterType
+    );
+
+/* Call the kernel HAL layer. */
+gceSTATUS
+gcoHAL_Call(
+    IN gcoHAL Hal,
+    IN OUT gcsHAL_INTERFACE_PTR Interface
+    );
+
+/* Schedule an event. */
+gceSTATUS
+gcoHAL_ScheduleEvent(
+    IN gcoHAL Hal,
+    IN OUT gcsHAL_INTERFACE_PTR Interface
+    );
+
+/* Request a start/stop timestamp. */
+gceSTATUS
+gcoHAL_SetTimer(
+    IN gcoHAL Hal,
+    IN gctUINT32 Index,
+    IN gctBOOL Start
+    );
+
+/* Get Time delta from a Timer in microseconds. */
+gceSTATUS
+gcoHAL_GetTimerTime(
+    IN gcoHAL Hal,
+    IN gctUINT32 Timer,
+    OUT gctINT32_PTR TimeDelta
+    );
+
+/* set timeout value. */
+gceSTATUS
+gcoHAL_SetTimeOut(
+    IN gcoHAL Hal,
+    IN gctUINT32 timeOut
+    );
+
+gceSTATUS
+gcoHAL_SetHardwareType(
+    IN gcoHAL Hal,
+    IN gceHARDWARE_TYPE HardwardType
+    );
+
+gceSTATUS
+gcoHAL_GetHardwareType(
+    IN gcoHAL Hal,
+    OUT gceHARDWARE_TYPE * HardwardType
+    );
+
+gceSTATUS
+gcoHAL_QueryChipCount(
+    IN gcoHAL Hal,
+    OUT gctINT32 * Count
+    );
+
+gceSTATUS
+gcoHAL_Query3DCoreCount(
+    IN gcoHAL       Hal,
+    OUT gctUINT32  *Count
+    );
+
+gceSTATUS
+gcoHAL_QueryCluster(
+    IN gcoHAL       Hal,
+    OUT gctINT32   *ClusterMinID,
+    OUT gctINT32   *ClusterMaxID,
+    OUT gctUINT32  *ClusterCount,
+    OUT gctUINT32  *ClusterIDWidth
+    );
+
+gceSTATUS
+gcoHAL_QueryCoreCount(
+    IN gcoHAL Hal,
+    IN gceHARDWARE_TYPE Type,
+    OUT gctUINT *Count,
+    OUT gctUINT_PTR ChipIDs
+    );
+
+gceSTATUS
+gcoHAL_QuerySeparated2D(
+    IN gcoHAL Hal
+    );
+
+gceSTATUS
+gcoHAL_QueryHybrid2D(
+    IN gcoHAL Hal
+    );
+
+gceSTATUS
+gcoHAL_Is3DAvailable(
+    IN gcoHAL Hal
+    );
+
+/* Get pointer to gcoVG object. */
+gceSTATUS
+gcoHAL_GetVGEngine(
+    IN gcoHAL Hal,
+    OUT gcoVG * Engine
+    );
+
+gceSTATUS
+gcoHAL_QueryChipLimits(
+    IN gcoHAL           Hal,
+    IN gctINT32         Chip,
+    OUT gcsHAL_LIMITS   *Limits);
+
+gceSTATUS
+gcoHAL_QueryChipFeature(
+    IN gcoHAL       Hal,
+    IN gctINT32     Chip,
+    IN gceFEATURE   Feature);
+
+gceSTATUS
+gcoHAL_SetCoreIndex(
+    IN gcoHAL Hal,
+    IN gctUINT32 Core
+    );
+
+gceSTATUS
+gcoHAL_GetCurrentCoreIndex(
+    IN gcoHAL Hal,
+    OUT gctUINT32 *Core
+    );
+
+gceSTATUS
+gcoHAL_ConvertCoreIndexGlobal(
+    IN gcoHAL Hal,
+    IN gceHARDWARE_TYPE Type,
+    IN gctUINT32 CoreCount,
+    IN gctUINT32 *LocalCoreIndexs,
+    OUT gctUINT32 *GlobalCoreIndexs
+    );
+
+gceSTATUS
+gcoHAL_ConvertCoreIndexLocal(
+    IN gcoHAL Hal,
+    IN gceHARDWARE_TYPE Type,
+    IN gctUINT32 CoreCount,
+    IN gctUINT32 *GlobalCoreIndexs,
+    OUT gctUINT32 *LocalCoreIndexs
+    );
+
+gceSTATUS
+gcoHAL_SelectChannel(
+    IN gcoHAL Hal,
+    IN gctBOOL Priority,
+    IN gctUINT32 ChannelId
+    );
+
+gceSTATUS
+gcoHAL_MCFESemaphore(
+    IN gctUINT32        SemaHandle,
+    IN gctBOOL          SendSema
+    );
+
+gceSTATUS
+gcoHAL_AllocateMCFESemaphore(
+    OUT gctUINT32 *     SemaHandle
+    );
+
+gceSTATUS
+gcoHAL_FreeMCFESemaphore(
+    IN gctUINT32        SemaHandle
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Shared Buffer --------------------------------------------------------*/
+
+/* Create shared buffer. */
+gceSTATUS
+gcoHAL_CreateShBuffer(
+    IN gctUINT32 Size,
+    OUT gctSHBUF * ShBuf
+    );
+
+/* Destroy shared buffer. */
+gceSTATUS
+gcoHAL_DestroyShBuffer(
+    IN gctSHBUF ShBuf
+    );
+
+/* Map shared buffer to current process. */
+gceSTATUS
+gcoHAL_MapShBuffer(
+    IN gctSHBUF ShBuf
+    );
+
+/* Write user data to shared buffer. */
+gceSTATUS
+gcoHAL_WriteShBuffer(
+    IN gctSHBUF ShBuf,
+    IN gctCONST_POINTER Data,
+    IN gctUINT32 ByteCount
+    );
+
+/* Read user data from shared buffer. */
+gceSTATUS
+gcoHAL_ReadShBuffer(
+    IN gctSHBUF ShBuf,
+    IN gctPOINTER Data,
+    IN gctUINT32 BytesCount,
+    OUT gctUINT32 * BytesRead
+    );
+
+/* Config power management to be enabled or disabled. */
+gceSTATUS
+gcoHAL_ConfigPowerManagement(
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gcoHAL_AllocateVideoMemory(
+    IN gctUINT Alignment,
+    IN gceVIDMEM_TYPE Type,
+    IN gctUINT32 Flag,
+    IN gcePOOL Pool,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctUINT32_PTR Node
+    );
+
+gceSTATUS
+gcoHAL_LockVideoMemory(
+    IN gctUINT32 Node,
+    IN gctBOOL Cacheable,
+    IN gceENGINE engine,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Logical
+    );
+
+gceSTATUS
+gcoHAL_UnlockVideoMemory(
+    IN gctUINT32 Node,
+    IN gceVIDMEM_TYPE Type,
+    IN gceENGINE engine
+    );
+
+gceSTATUS
+gcoHAL_ReleaseVideoMemory(
+    IN gctUINT32 Node
+    );
+
+#if gcdENABLE_3D || gcdENABLE_VG
+/* Query the target capabilities. */
+gceSTATUS
+gcoHAL_QueryTargetCaps(
+    IN gcoHAL Hal,
+    OUT gctUINT * MaxWidth,
+    OUT gctUINT * MaxHeight,
+    OUT gctUINT * MultiTargetCount,
+    OUT gctUINT * MaxSamples
+    );
+#endif
+
+gceSTATUS
+gcoHAL_WrapUserMemory(
+    IN gcsUSER_MEMORY_DESC_PTR UserMemoryDesc,
+    IN gceVIDMEM_TYPE Type,
+    OUT gctUINT32_PTR Node
+    );
+
+gceSTATUS
+gcoHAL_QueryResetTimeStamp(
+    OUT gctUINT64_PTR ResetTimeStamp,
+    OUT gctUINT64_PTR ContextID
+    );
+
+gceSTATUS
+gcoHAL_WaitFence(
+    IN gctUINT32 Handle,
+    IN gctUINT32 TimeOut
+    );
+
+#if gcdENABLE_2D
+gceSTATUS
+gcoHAL_AttachExternalMemory(
+    IN gcoHAL Hal,
+    IN gcsEXTERNAL_MEMORY_INFO * External,
+    OUT gctPOINTER * Handle,
+    OUT gctUINT32_PTR GPU2DAddress
+    );
+
+gceSTATUS
+gcoHAL_DetachExternalMemory(
+    IN gcoHAL Hal,
+    IN gctPOINTER * Handle
+    );
+#endif
+
+gceSTATUS
+gcoHAL_ScheduleSignal(
+    IN gctSIGNAL Signal,
+    IN gctSIGNAL AuxSignal,
+    IN gctINT ProcessID,
+    IN gceKERNEL_WHERE FromWhere
+    );
+
+gceSTATUS
+gcoHAL_GetGraphicBufferFd(
+    IN gctUINT32 Node[3],
+    IN gctSHBUF ShBuf,
+    IN gctSIGNAL Signal,
+    OUT gctINT32 * Fd
+    );
+
+gceSTATUS
+gcoHAL_AlignToTile(
+    IN OUT gctUINT32 * Width,
+    IN OUT gctUINT32 * Height,
+    IN  gceSURF_TYPE Type,
+    IN  gceSURF_FORMAT Format
+    );
+
+/******************************************************************************\
+********************************** gcoOS Object *********************************
+\******************************************************************************/
+/* Lock PLS access */
+gceSTATUS
+gcoOS_LockPLS(
+    void
+    );
+
+/* Unlock PLS access */
+gceSTATUS
+gcoOS_UnLockPLS(
+    void
+    );
+
+/* Get PLS value for given key */
+gctPOINTER
+gcoOS_GetPLSValue(
+    IN gcePLS_VALUE key
+    );
+
+/* Set PLS value of a given key */
+void
+gcoOS_SetPLSValue(
+    IN gcePLS_VALUE key,
+    OUT gctPOINTER value
+    );
+
+/* Lock GL FE compiler access */
+gceSTATUS
+gcoOS_LockGLFECompiler(
+    void
+    );
+
+/* Unlock GL FE compiler access */
+gceSTATUS
+gcoOS_UnLockGLFECompiler(
+    void
+    );
+
+/* Lock CL FE compiler access */
+gceSTATUS
+gcoOS_LockCLFECompiler(
+    void
+    );
+
+/* Unlock CL FE compiler access */
+gceSTATUS
+gcoOS_UnLockCLFECompiler(
+    void
+    );
+
+gceSTATUS
+gcoOS_GetTLS(
+    OUT gcsTLS_PTR * TLS
+    );
+
+/* Copy the TLS from a source thread. */
+gceSTATUS
+gcoOS_CopyTLS(
+    IN gcsTLS_PTR Source
+    );
+
+/* Query the thread local storage. */
+gceSTATUS
+gcoOS_QueryTLS(
+    OUT gcsTLS_PTR * TLS
+    );
+
+/* Get access to driver tls. */
+gceSTATUS
+gcoOS_GetDriverTLS(
+    IN gceTLS_KEY Key,
+    OUT gcsDRIVER_TLS_PTR * TLS
+    );
+
+/*
+ * Set driver tls.
+ * May cause memory leak if 'destructor' not set.
+ */
+gceSTATUS
+gcoOS_SetDriverTLS(
+    IN gceTLS_KEY Key,
+    IN gcsDRIVER_TLS * TLS
+    );
+
+/* Destroy the objects associated with the current thread. */
+void
+gcoOS_FreeThreadData(
+    void
+    );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoOS_Construct(
+    IN gctPOINTER Context,
+    OUT gcoOS * Os
+    );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoOS_Destroy(
+    IN gcoOS Os
+    );
+
+/* Deprecated API: please use gcoHAL_GetBaseAddr() instead.
+**                 This API was kept only for legacy BSP usage.
+**
+** Get the base address for the physical memory.
+*/
+gceSTATUS
+gcoOS_GetBaseAddress(
+    IN gcoOS Os,
+    OUT gctUINT32_PTR BaseAddress
+    );
+
+/* Allocate memory from the heap. */
+gceSTATUS
+gcoOS_Allocate(
+    IN gcoOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    );
+
+/* Get allocated memory size. */
+gceSTATUS
+gcoOS_GetMemorySize(
+    IN gcoOS Os,
+    IN gctPOINTER Memory,
+    OUT gctSIZE_T_PTR MemorySize
+    );
+
+/* Free allocated memory. */
+gceSTATUS
+gcoOS_Free(
+    IN gcoOS Os,
+    IN gctPOINTER Memory
+    );
+
+/* Allocate memory. */
+gceSTATUS
+gcoOS_AllocateSharedMemory(
+    IN gcoOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    );
+
+/* Free memory. */
+gceSTATUS
+gcoOS_FreeSharedMemory(
+    IN gcoOS Os,
+    IN gctPOINTER Memory
+    );
+
+/* Allocate memory. */
+gceSTATUS
+gcoOS_AllocateMemory(
+    IN gcoOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    );
+
+/* Free memory. */
+gceSTATUS
+gcoOS_FreeMemory(
+    IN gcoOS Os,
+    IN gctPOINTER Memory
+    );
+
+/* Device I/O Control call to the kernel HAL layer. */
+gceSTATUS
+gcoOS_DeviceControl(
+    IN gcoOS Os,
+    IN gctUINT32 IoControlCode,
+    IN gctPOINTER InputBuffer,
+    IN gctSIZE_T InputBufferSize,
+    IN gctPOINTER OutputBuffer,
+    IN gctSIZE_T OutputBufferSize
+    );
+
+#define gcmOS_SAFE_FREE(os, mem) \
+    gcoOS_Free(os, mem); \
+    mem = gcvNULL
+
+#define gcmOS_SAFE_FREE_SHARED_MEMORY(os, mem) \
+    gcoOS_FreeSharedMemory(os, mem); \
+    mem = gcvNULL
+
+#define gcmkOS_SAFE_FREE(os, mem) \
+    gckOS_Free(os, mem); \
+    mem = gcvNULL
+
+#define gcdMAX_PATH 512
+
+/* Open a file. */
+gceSTATUS
+gcoOS_Open(
+    IN gcoOS Os,
+    IN gctCONST_STRING FileName,
+    IN gceFILE_MODE Mode,
+    OUT gctFILE * File
+    );
+
+/* Close a file. */
+gceSTATUS
+gcoOS_Close(
+    IN gcoOS Os,
+    IN gctFILE File
+    );
+
+/* Remove a file. */
+gceSTATUS
+gcoOS_Remove(
+    IN gcoOS Os,
+    IN gctCONST_STRING FileName
+    );
+
+/* Read data from a file. */
+gceSTATUS
+gcoOS_Read(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctSIZE_T ByteCount,
+    IN gctPOINTER Data,
+    OUT gctSIZE_T * ByteRead
+    );
+
+/* Write data to a file. */
+gceSTATUS
+gcoOS_Write(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctSIZE_T ByteCount,
+    IN gctCONST_POINTER Data
+    );
+
+/* Flush data to a file. */
+gceSTATUS
+gcoOS_Flush(
+    IN gcoOS Os,
+    IN gctFILE File
+    );
+
+/* Close a file descriptor. */
+gceSTATUS
+gcoOS_CloseFD(
+    IN gcoOS Os,
+    IN gctINT FD
+    );
+
+/* Scan a file. */
+gceSTATUS
+gcoOS_FscanfI(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctCONST_STRING Format,
+    OUT gctUINT *result
+    );
+
+/* Dup file descriptor to another. */
+gceSTATUS
+gcoOS_DupFD(
+    IN gcoOS Os,
+    IN gctINT FD,
+    OUT gctINT * FD2
+    );
+
+/* Lock a file. */
+gceSTATUS
+gcoOS_LockFile(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctBOOL Shared,
+    IN gctBOOL Block
+    );
+
+/* Unlock a file. */
+gceSTATUS
+gcoOS_UnlockFile(
+    IN gcoOS Os,
+    IN gctFILE File
+    );
+
+/* Create an endpoint for communication. */
+gceSTATUS
+gcoOS_Socket(
+    IN gcoOS Os,
+    IN gctINT Domain,
+    IN gctINT Type,
+    IN gctINT Protocol,
+    OUT gctINT *SockFd
+    );
+
+/* Close a socket. */
+gceSTATUS
+gcoOS_CloseSocket(
+    IN gcoOS Os,
+    IN gctINT SockFd
+    );
+
+/* Initiate a connection on a socket. */
+gceSTATUS
+gcoOS_Connect(
+    IN gcoOS Os,
+    IN gctINT SockFd,
+    IN gctCONST_POINTER HostName,
+    IN gctUINT Port);
+
+/* Shut down part of connection on a socket. */
+gceSTATUS
+gcoOS_Shutdown(
+    IN gcoOS Os,
+    IN gctINT SockFd,
+    IN gctINT How
+    );
+
+/* Send a message on a socket. */
+gceSTATUS
+gcoOS_Send(
+    IN gcoOS Os,
+    IN gctINT SockFd,
+    IN gctSIZE_T ByteCount,
+    IN gctCONST_POINTER Data,
+    IN gctINT Flags
+    );
+
+/* Initiate a connection on a socket. */
+gceSTATUS
+gcoOS_WaitForSend(
+    IN gcoOS Os,
+    IN gctINT SockFd,
+    IN gctINT Seconds,
+    IN gctINT MicroSeconds);
+
+/* Get environment variable value. */
+gceSTATUS
+gcoOS_GetEnv(
+    IN gcoOS Os,
+    IN gctCONST_STRING VarName,
+    OUT gctSTRING * Value
+    );
+
+/* Set environment variable value. */
+gceSTATUS
+gcoOS_SetEnv(
+    IN gcoOS Os,
+    IN gctCONST_STRING VarName,
+    IN gctSTRING Value
+    );
+
+/* Get current working directory. */
+gceSTATUS
+gcoOS_GetCwd(
+    IN gcoOS Os,
+    IN gctINT SizeInBytes,
+    OUT gctSTRING Buffer
+    );
+
+/* Get file status info. */
+gceSTATUS
+gcoOS_Stat(
+    IN gcoOS Os,
+    IN gctCONST_STRING FileName,
+    OUT gctPOINTER Buffer
+    );
+
+/* Set the current position of a file. */
+gceSTATUS
+gcoOS_Seek(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctUINT32 Offset,
+    IN gceFILE_WHENCE Whence
+    );
+
+/* Set the current position of a file. */
+gceSTATUS
+gcoOS_SetPos(
+    IN gcoOS Os,
+    IN gctFILE File,
+    IN gctUINT32 Position
+    );
+
+/* Get the current position of a file. */
+gceSTATUS
+gcoOS_GetPos(
+    IN gcoOS Os,
+    IN gctFILE File,
+    OUT gctUINT32 * Position
+    );
+
+/* Same as strstr. */
+gceSTATUS
+gcoOS_StrStr(
+    IN gctCONST_STRING String,
+    IN gctCONST_STRING SubString,
+    OUT gctSTRING * Output
+    );
+
+/* Find the last occurance of a character inside a string. */
+gceSTATUS
+gcoOS_StrFindReverse(
+    IN gctCONST_STRING String,
+    IN gctINT8 Character,
+    OUT gctSTRING * Output
+    );
+
+gceSTATUS
+gcoOS_StrDup(
+    IN gcoOS Os,
+    IN gctCONST_STRING String,
+    OUT gctSTRING * Target
+    );
+
+/* Copy a string. */
+gceSTATUS
+gcoOS_StrCopySafe(
+    IN gctSTRING Destination,
+    IN gctSIZE_T DestinationSize,
+    IN gctCONST_STRING Source
+    );
+
+/* Append a string. */
+gceSTATUS
+gcoOS_StrCatSafe(
+    IN gctSTRING Destination,
+    IN gctSIZE_T DestinationSize,
+    IN gctCONST_STRING Source
+    );
+
+/* Compare two strings. */
+gceSTATUS
+gcoOS_StrCmp(
+    IN gctCONST_STRING String1,
+    IN gctCONST_STRING String2
+    );
+
+/* Compare characters of two strings. */
+gceSTATUS
+gcoOS_StrNCmp(
+    IN gctCONST_STRING String1,
+    IN gctCONST_STRING String2,
+    IN gctSIZE_T Count
+    );
+
+/* Convert string to float. */
+gceSTATUS
+gcoOS_StrToFloat(
+    IN gctCONST_STRING String,
+    OUT gctFLOAT * Float
+    );
+
+/* Convert hex string to integer. */
+gceSTATUS gcoOS_HexStrToInt(
+    IN gctCONST_STRING String,
+    OUT gctINT * Int
+    );
+
+/* Convert hex string to float. */
+gceSTATUS
+gcoOS_HexStrToFloat(
+    IN gctCONST_STRING String,
+    OUT gctFLOAT * Float
+    );
+
+/* Convert string to integer. */
+gceSTATUS
+gcoOS_StrToInt(
+    IN gctCONST_STRING String,
+    OUT gctINT * Int
+    );
+
+gceSTATUS
+gcoOS_MemCmp(
+    IN gctCONST_POINTER Memory1,
+    IN gctCONST_POINTER Memory2,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gcoOS_PrintStrSafe(
+    OUT gctSTRING String,
+    IN gctSIZE_T StringSize,
+    IN OUT gctUINT * Offset,
+    IN gctCONST_STRING Format,
+    ...
+    );
+
+gceSTATUS
+gcoOS_LoadLibrary(
+    IN gcoOS Os,
+    IN gctCONST_STRING Library,
+    OUT gctHANDLE * Handle
+    );
+
+gceSTATUS
+gcoOS_FreeLibrary(
+    IN gcoOS Os,
+    IN gctHANDLE Handle
+    );
+
+gceSTATUS
+gcoOS_GetProcAddress(
+    IN gcoOS Os,
+    IN gctHANDLE Handle,
+    IN gctCONST_STRING Name,
+    OUT gctPOINTER * Function
+    );
+
+gceSTATUS
+gcoOS_Compact(
+    IN gcoOS Os
+    );
+
+gceSTATUS
+gcoOS_AddSignalHandler (
+    IN gceSignalHandlerType SignalHandlerType
+    );
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY
+gceSTATUS
+gcoOS_ProfileStart(
+    IN gcoOS Os
+    );
+
+gceSTATUS
+gcoOS_ProfileEnd(
+    IN gcoOS Os,
+    IN gctCONST_STRING Title
+    );
+
+gceSTATUS
+gcoOS_SetProfileSetting(
+        IN gcoOS Os,
+        IN gctBOOL Enable,
+        IN gctCONST_STRING FileName
+        );
+#endif
+
+/* Get the amount of physical system memory */
+gceSTATUS
+gcoOS_GetPhysicalSystemMemorySize(
+    OUT gctSIZE_T * PhysicalSystemMemorySize
+    );
+
+/* Query the video memory. */
+gceSTATUS
+gcoOS_QueryVideoMemory(
+    IN gcoOS Os,
+    OUT gctUINT32 * InternalPhysName,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * ExternalPhysName,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ContiguousPhysName,
+    OUT gctSIZE_T * ContiguousSize
+    );
+
+gceSTATUS
+gcoOS_QueryCurrentProcessName(
+    OUT gctSTRING Name,
+    IN gctSIZE_T Size
+    );
+
+
+/*----------------------------------------------------------------------------*/
+/*----- Atoms ----------------------------------------------------------------*/
+
+/* Construct an atom. */
+gceSTATUS
+gcoOS_AtomConstruct(
+    IN gcoOS Os,
+    OUT gcsATOM_PTR * Atom
+    );
+
+/* Destroy an atom. */
+gceSTATUS
+gcoOS_AtomDestroy(
+    IN gcoOS Os,
+    IN gcsATOM_PTR Atom
+    );
+
+/* Get the 32-bit value protected by an atom. */
+gceSTATUS
+gcoOS_AtomGet(
+    IN gcoOS Os,
+    IN gcsATOM_PTR Atom,
+    OUT gctINT32_PTR Value
+    );
+
+/* Set the 32-bit value protected by an atom. */
+gceSTATUS
+gcoOS_AtomSet(
+    IN gcoOS Os,
+    IN gcsATOM_PTR Atom,
+    IN gctINT32 Value
+    );
+
+/* Increment an atom. */
+gceSTATUS
+gcoOS_AtomIncrement(
+    IN gcoOS Os,
+    IN gcsATOM_PTR Atom,
+    OUT gctINT32_PTR OldValue
+    );
+
+/* Decrement an atom. */
+gceSTATUS
+gcoOS_AtomDecrement(
+    IN gcoOS Os,
+    IN gcsATOM_PTR Atom,
+    OUT gctINT32_PTR OldValue
+    );
+
+gctHANDLE
+gcoOS_GetCurrentProcessID(
+    void
+    );
+
+gctHANDLE
+gcoOS_GetCurrentThreadID(
+    void
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Time -----------------------------------------------------------------*/
+
+/* Get the number of milliseconds since the system started. */
+gctUINT32
+gcoOS_GetTicks(
+    void
+    );
+
+/* Get time in microseconds. */
+gceSTATUS
+gcoOS_GetTime(
+    gctUINT64_PTR Time
+    );
+
+/* Get CPU usage in microseconds. */
+gceSTATUS
+gcoOS_GetCPUTime(
+    gctUINT64_PTR CPUTime
+    );
+
+/* Get memory usage. */
+gceSTATUS
+gcoOS_GetMemoryUsage(
+    gctUINT32_PTR MaxRSS,
+    gctUINT32_PTR IxRSS,
+    gctUINT32_PTR IdRSS,
+    gctUINT32_PTR IsRSS
+    );
+
+/* Delay a number of microseconds. */
+gceSTATUS
+gcoOS_Delay(
+    IN gcoOS Os,
+    IN gctUINT32 Delay
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Threads --------------------------------------------------------------*/
+
+#ifdef _WIN32
+/* Cannot include windows.h here becuase "near" and "far"
+ * which are used in gcsDEPTH_INFO, are defined to nothing in WinDef.h.
+ * So, use the real value of DWORD and WINAPI, instead.
+ * DWORD is unsigned long, and WINAPI is __stdcall.
+ * If these two are change in WinDef.h, the following two typdefs
+ * need to be changed, too.
+ */
+typedef unsigned long gctTHREAD_RETURN;
+typedef unsigned long (__stdcall * gcTHREAD_ROUTINE)(void * Argument);
+#else
+typedef void * gctTHREAD_RETURN;
+typedef void * (* gcTHREAD_ROUTINE)(void *);
+#endif
+
+/* Create a new thread. */
+gceSTATUS
+gcoOS_CreateThread(
+    IN gcoOS Os,
+    IN gcTHREAD_ROUTINE Worker,
+    IN gctPOINTER Argument,
+    OUT gctPOINTER * Thread
+    );
+
+/* Close a thread. */
+gceSTATUS
+gcoOS_CloseThread(
+    IN gcoOS Os,
+    IN gctPOINTER Thread
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Mutexes --------------------------------------------------------------*/
+
+/* Create a new mutex. */
+gceSTATUS
+gcoOS_CreateMutex(
+    IN gcoOS Os,
+    OUT gctPOINTER * Mutex
+    );
+
+/* Delete a mutex. */
+gceSTATUS
+gcoOS_DeleteMutex(
+    IN gcoOS Os,
+    IN gctPOINTER Mutex
+    );
+
+/* Acquire a mutex. */
+gceSTATUS
+gcoOS_AcquireMutex(
+    IN gcoOS Os,
+    IN gctPOINTER Mutex,
+    IN gctUINT32 Timeout
+    );
+
+/* Release a mutex. */
+gceSTATUS
+gcoOS_ReleaseMutex(
+    IN gcoOS Os,
+    IN gctPOINTER Mutex
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Signals --------------------------------------------------------------*/
+
+/* Create a signal. */
+gceSTATUS
+gcoOS_CreateSignal(
+    IN gcoOS Os,
+    IN gctBOOL ManualReset,
+    OUT gctSIGNAL * Signal
+    );
+
+/* Destroy a signal. */
+gceSTATUS
+gcoOS_DestroySignal(
+    IN gcoOS Os,
+    IN gctSIGNAL Signal
+    );
+
+/* Signal a signal. */
+gceSTATUS
+gcoOS_Signal(
+    IN gcoOS Os,
+    IN gctSIGNAL Signal,
+    IN gctBOOL State
+    );
+
+/* Wait for a signal. */
+gceSTATUS
+gcoOS_WaitSignal(
+    IN gcoOS Os,
+    IN gctSIGNAL Signal,
+    IN gctUINT32 Wait
+    );
+
+/* Map a signal from another process */
+gceSTATUS
+gcoOS_MapSignal(
+    IN gctSIGNAL  RemoteSignal,
+    OUT gctSIGNAL * LocalSignal
+    );
+
+/* Unmap a signal mapped from another process */
+gceSTATUS
+gcoOS_UnmapSignal(
+    IN gctSIGNAL Signal
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Android Native Fence -------------------------------------------------*/
+
+/* Create native fence. */
+gceSTATUS
+gcoOS_CreateNativeFence(
+    IN gcoOS Os,
+    IN gctSIGNAL Signal,
+    OUT gctINT * FenceFD
+    );
+
+/* (CPU) Wait on native fence. */
+gceSTATUS
+gcoOS_ClientWaitNativeFence(
+    IN gcoOS Os,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    );
+
+/* (GPU) Wait on native fence. */
+gceSTATUS
+gcoOS_WaitNativeFence(
+    IN gcoOS Os,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    );
+
+/*----------------------------------------------------------------------------*/
+/*----- Memory Access and Cache ----------------------------------------------*/
+
+/* Write a register. */
+gceSTATUS
+gcoOS_WriteRegister(
+    IN gcoOS Os,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    );
+
+/* Read a register. */
+gceSTATUS
+gcoOS_ReadRegister(
+    IN gcoOS Os,
+    IN gctUINT32 Address,
+    OUT gctUINT32 * Data
+    );
+
+gceSTATUS
+gcoOS_CacheClean(
+    IN gcoOS Os,
+    IN gctUINT32 Node,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gcoOS_CacheFlush(
+    IN gcoOS Os,
+    IN gctUINT32 Node,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gcoOS_CacheInvalidate(
+    IN gcoOS Os,
+    IN gctUINT32 Node,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gcoOS_MemoryBarrier(
+    IN gcoOS Os,
+    IN gctPOINTER Logical
+    );
+
+gceSTATUS
+gcoOS_CPUPhysicalToGPUPhysical(
+    IN gctPHYS_ADDR_T CPUPhysical,
+    OUT gctPHYS_ADDR_T * GPUPhysical
+    );
+
+gceSTATUS
+gcoOS_QuerySystemInfo(
+    IN gcoOS Os,
+    OUT gcsSystemInfo *Info
+    );
+
+
+/*----------------------------------------------------------------------------*/
+/*----- Profile --------------------------------------------------------------*/
+
+gceSTATUS
+gckOS_GetProfileTick(
+    OUT gctUINT64_PTR Tick
+    );
+
+gceSTATUS
+gckOS_QueryProfileTickRate(
+    OUT gctUINT64_PTR TickRate
+    );
+
+gctUINT32
+gckOS_ProfileToMS(
+    IN gctUINT64 Ticks
+    );
+
+gceSTATUS
+gcoOS_GetProfileTick(
+    OUT gctUINT64_PTR Tick
+    );
+
+gceSTATUS
+gcoOS_QueryProfileTickRate(
+    OUT gctUINT64_PTR TickRate
+    );
+
+#if gcdSTATIC_LINK && defined(WIN32)
+void gcoOS_ModuleConstructor(
+    void
+    );
+
+void gcoOS_ModuleDestructor(
+    void
+    );
+#endif
+
+#define _gcmPROFILE_INIT(prefix, freq, start) \
+    do { \
+        prefix ## OS_QueryProfileTickRate(&(freq)); \
+        prefix ## OS_GetProfileTick(&(start)); \
+    } while (gcvFALSE)
+
+#define _gcmPROFILE_QUERY(prefix, start, ticks) \
+    do { \
+        prefix ## OS_GetProfileTick(&(ticks)); \
+        (ticks) = ((ticks) > (start)) ? ((ticks) - (start)) \
+                                      : (~0ull - (start) + (ticks) + 1); \
+    } while (gcvFALSE)
+
+#if gcdENABLE_PROFILING
+#   define gcmkPROFILE_INIT(freq, start)    _gcmPROFILE_INIT(gck, freq, start)
+#   define gcmkPROFILE_QUERY(start, ticks)  _gcmPROFILE_QUERY(gck, start, ticks)
+#   define gcmPROFILE_INIT(freq, start)     _gcmPROFILE_INIT(gco, freq, start)
+#   define gcmPROFILE_QUERY(start, ticks)   _gcmPROFILE_QUERY(gco, start, ticks)
+#   define gcmPROFILE_ONLY(x)               x
+#   define gcmPROFILE_ELSE(x)               do { } while (gcvFALSE)
+#   define gcmPROFILE_DECLARE_ONLY(x)       x
+#   define gcmPROFILE_DECLARE_ELSE(x)       typedef x
+#else
+#   define gcmkPROFILE_INIT(start, freq)    do { } while (gcvFALSE)
+#   define gcmkPROFILE_QUERY(start, ticks)  do { } while (gcvFALSE)
+#   define gcmPROFILE_INIT(start, freq)     do { } while (gcvFALSE)
+#   define gcmPROFILE_QUERY(start, ticks)   do { } while (gcvFALSE)
+#   define gcmPROFILE_ONLY(x)               do { } while (gcvFALSE)
+#   define gcmPROFILE_ELSE(x)               x
+#   define gcmPROFILE_DECLARE_ONLY(x)       do { } while (gcvFALSE)
+#   define gcmPROFILE_DECLARE_ELSE(x)       x
+#endif
+
+/*******************************************************************************
+**  gcoMATH object
+*/
+
+#define gcdPI                   3.14159265358979323846f
+
+/* Kernel. */
+gctINT
+gckMATH_ModuloInt(
+    IN gctINT X,
+    IN gctINT Y
+    );
+
+/* User. */
+gctUINT32
+gcoMATH_Log2in5dot5(
+    IN gctINT X
+    );
+
+
+gctFLOAT
+gcoMATH_UIntAsFloat(
+    IN gctUINT32 X
+    );
+
+gctUINT32
+gcoMATH_FloatAsUInt(
+    IN gctFLOAT X
+    );
+
+gctBOOL
+gcoMATH_CompareEqualF(
+    IN gctFLOAT X,
+    IN gctFLOAT Y
+    );
+
+gctUINT16
+gcoMATH_UInt8AsFloat16(
+    IN gctUINT8 X
+    );
+
+gctUINT32
+gcoMATH_Float16ToFloat(
+    IN gctUINT16 In
+    );
+
+gctUINT16
+gcoMATH_FloatToFloat16(
+    IN gctUINT32 In
+    );
+
+gctUINT32
+gcoMATH_Float11ToFloat(
+    IN gctUINT32 In
+    );
+
+gctUINT16
+gcoMATH_FloatToFloat11(
+    IN gctUINT32 In
+    );
+
+gctUINT32
+gcoMATH_Float10ToFloat(
+    IN gctUINT32 In
+    );
+
+gctUINT16
+gcoMATH_FloatToFloat10(
+    IN gctUINT32 In
+    );
+
+gctUINT32
+gcoMATH_Float14ToFloat(
+    IN gctUINT16 In
+    );
+
+/******************************************************************************\
+**************************** Coordinate Structures *****************************
+\******************************************************************************/
+
+typedef struct _gcsPOINT
+{
+    gctINT32                    x;
+    gctINT32                    y;
+}
+gcsPOINT;
+
+typedef struct _gcsSIZE
+{
+    gctINT32                    width;
+    gctINT32                    height;
+}
+gcsSIZE;
+
+typedef struct _gcsRECT
+{
+    gctINT32                    left;
+    gctINT32                    top;
+    gctINT32                    right;
+    gctINT32                    bottom;
+}
+gcsRECT;
+
+typedef struct _gcsPIXEL
+{
+    union
+    {
+        struct
+        {
+            gctFLOAT r, g, b, a;
+        } f;
+        struct
+        {
+            gctINT32 r, g, b, a;
+        } i;
+        struct
+        {
+            gctUINT32 r, g, b, a;
+        } ui;
+    } color;
+
+    gctFLOAT  d;
+    gctUINT32 s;
+
+} gcsPIXEL;
+
+/******************************************************************************\
+********************************* gcoSURF Object ********************************
+\******************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/*------------------------------- gcoSURF Common ------------------------------*/
+
+/* Color format component parameters. */
+typedef struct _gcsFORMAT_COMPONENT
+{
+    gctUINT8                    start;
+    gctUINT8                    width;
+}
+gcsFORMAT_COMPONENT;
+
+/* RGBA color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_RGBA
+{
+    gcsFORMAT_COMPONENT         alpha;
+    gcsFORMAT_COMPONENT         red;
+    gcsFORMAT_COMPONENT         green;
+    gcsFORMAT_COMPONENT         blue;
+}
+gcsFORMAT_CLASS_TYPE_RGBA;
+
+/* YUV color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_YUV
+{
+    gcsFORMAT_COMPONENT         y;
+    gcsFORMAT_COMPONENT         u;
+    gcsFORMAT_COMPONENT         v;
+}
+gcsFORMAT_CLASS_TYPE_YUV;
+
+/* Index color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_INDEX
+{
+    gcsFORMAT_COMPONENT         value;
+}
+gcsFORMAT_CLASS_TYPE_INDEX;
+
+/* Luminance color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE
+{
+    gcsFORMAT_COMPONENT         alpha;
+    gcsFORMAT_COMPONENT         value;
+}
+gcsFORMAT_CLASS_TYPE_LUMINANCE;
+
+/* Bump map color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_BUMP
+{
+    gcsFORMAT_COMPONENT         alpha;
+    gcsFORMAT_COMPONENT         l;
+    gcsFORMAT_COMPONENT         v;
+    gcsFORMAT_COMPONENT         u;
+    gcsFORMAT_COMPONENT         q;
+    gcsFORMAT_COMPONENT         w;
+}
+gcsFORMAT_CLASS_TYPE_BUMP;
+
+/* Depth and stencil format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH
+{
+    gcsFORMAT_COMPONENT         depth;
+    gcsFORMAT_COMPONENT         stencil;
+}
+gcsFORMAT_CLASS_TYPE_DEPTH;
+
+/* Intensity format class. */
+typedef struct _gcsFORMAT_CLASs_TYPE_INTENSITY
+{
+    gcsFORMAT_COMPONENT         value;
+}
+gcsFORMAT_CLASs_TYPE_INTENSITY;
+
+typedef union _gcuPIXEL_FORMAT_CLASS
+{
+    gcsFORMAT_CLASS_TYPE_BUMP       bump;
+    gcsFORMAT_CLASS_TYPE_RGBA       rgba;
+    gcsFORMAT_CLASS_TYPE_YUV        yuv;
+    gcsFORMAT_CLASS_TYPE_LUMINANCE  lum;
+    gcsFORMAT_CLASS_TYPE_INDEX      index;
+    gcsFORMAT_CLASS_TYPE_DEPTH      depth;
+    gcsFORMAT_CLASs_TYPE_INTENSITY  intensity;
+}
+gcuPIXEL_FORMAT_CLASS;
+
+/* Format parameters. */
+typedef struct _gcsSURF_FORMAT_INFO
+{
+    /* Name of the format */
+    gctCONST_STRING             formatName;
+
+    /* Format code and class. */
+    gceSURF_FORMAT              format;
+    gceFORMAT_CLASS             fmtClass;
+
+    /* Format data type */
+    gceFORMAT_DATATYPE          fmtDataType;
+
+    /* The size of one pixel in bits. */
+    gctUINT8                    bitsPerPixel;
+
+    /* Pixel block dimensions. */
+    gctUINT                     blockWidth;
+    gctUINT                     blockHeight;
+
+    /* Pixel block size in bits. */
+    gctUINT                     blockSize;
+
+    /* Some formats are larger than what the GPU can support.      */
+    /* These formats are read in the number of layers specified.   */
+    gctUINT8                    layers;
+
+    /* The format is faked and software will interpret it differently
+    ** with HW. Most of them can't be blendable(PE) or filterable(TX).
+    */
+    gctBOOL                     fakedFormat;
+
+    /* Some formats have two neighbour pixels interleaved together. */
+    /* To describe such format, set the flag to 1 and add another   */
+    /* like this one describing the odd pixel format.               */
+    gctBOOL                     interleaved;
+
+    /* sRGB format. */
+    gctBOOL                     sRGB;
+
+    /* How GPU read from big-endian host memory */
+    gceENDIAN_HINT              endian;
+
+    /* Format components. */
+    gcuPIXEL_FORMAT_CLASS       u;
+
+    /* Format components. */
+    gcuPIXEL_FORMAT_CLASS       uOdd;
+
+    /* Render format. */
+    gceSURF_FORMAT              closestRenderFormat;
+    /*gctCLOSEST_FORMAT           dynamicClosestRenderFormat;*/
+    gctUINT                     renderFormat;
+    const gceTEXTURE_SWIZZLE  * pixelSwizzle;
+
+    /* Texture format. */
+    gceSURF_FORMAT              closestTXFormat;
+    gctUINT                     txFormat;
+    const gceTEXTURE_SWIZZLE  * txSwizzle;
+    gctBOOL                     txIntFilter;
+}
+gcsSURF_FORMAT_INFO;
+
+/* Frame buffer information. */
+typedef struct _gcsSURF_FRAMEBUFFER
+{
+    gctPOINTER                  logical;
+    gctUINT                     width, height;
+    gctINT                      stride;
+    gceSURF_FORMAT              format;
+}
+gcsSURF_FRAMEBUFFER;
+
+/* Generic pixel component descriptors. */
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX;
+
+/* Construct a new gcoSURF object. */
+gceSTATUS
+gcoSURF_Construct(
+    IN gcoHAL Hal,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gctUINT Depth,
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format,
+    IN gcePOOL Pool,
+    OUT gcoSURF * Surface
+    );
+
+/* Destroy an gcoSURF object. */
+gceSTATUS
+gcoSURF_Destroy(
+    IN gcoSURF Surface
+    );
+
+/* Map user-allocated surface. */
+gceSTATUS
+gcoSURF_MapUserSurface(
+    IN gcoSURF Surface,
+    IN gctUINT Alignment,
+    IN gctPOINTER Logical,
+    IN gctPHYS_ADDR_T Physical
+    );
+
+/* Wrapp surface with known logical/GPU address */
+gceSTATUS
+gcoSURF_WrapSurface(
+    IN gcoSURF Surface,
+    IN gctUINT Alignment,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Address
+    );
+
+
+/* Query vid mem node info. */
+gceSTATUS
+gcoSURF_QueryVidMemNode(
+    IN gcoSURF Surface,
+    OUT gctUINT32 * Node,
+    OUT gcePOOL * Pool,
+    OUT gctSIZE_T_PTR Bytes,
+    OUT gctUINT32 * TsNode,
+    OUT gcePOOL * TsPool,
+    OUT gctSIZE_T_PTR TsBytes
+    );
+
+/* Set the color type of the surface. */
+gceSTATUS
+gcoSURF_SetColorType(
+    IN gcoSURF Surface,
+    IN gceSURF_COLOR_TYPE ColorType
+    );
+
+/* Get the color type of the surface. */
+gceSTATUS
+gcoSURF_GetColorType(
+    IN gcoSURF Surface,
+    OUT gceSURF_COLOR_TYPE *ColorType
+    );
+
+/* Set the color space of the surface. */
+gceSTATUS
+gcoSURF_SetColorSpace(
+    IN gcoSURF Surface,
+    IN gceSURF_COLOR_SPACE ColorSpace
+    );
+
+/* Get the color space of the surface. */
+gceSTATUS
+gcoSURF_GetColorSpace(
+    IN gcoSURF Surface,
+    OUT gceSURF_COLOR_SPACE *ColorSpace
+    );
+
+
+/* Set the surface ration angle. */
+gceSTATUS
+gcoSURF_SetRotation(
+    IN gcoSURF Surface,
+    IN gceSURF_ROTATION Rotation
+    );
+
+gceSTATUS
+gcoSURF_IsValid(
+    IN gcoSURF Surface
+    );
+
+#if gcdENABLE_3D
+/* Verify and return the state of the tile status mechanism. */
+gceSTATUS
+gcoSURF_IsTileStatusSupported(
+    IN gcoSURF Surface
+    );
+
+/* Verify if surface has tile status enabled. */
+gceSTATUS
+gcoSURF_IsTileStatusEnabled(
+    IN gcsSURF_VIEW *SurfView
+    );
+
+/* Verify if surface is compressed. */
+gceSTATUS
+gcoSURF_IsCompressed(
+    IN gcsSURF_VIEW *SurfView
+    );
+
+/* Enable tile status for the specified surface on zero slot. */
+gceSTATUS
+gcoSURF_EnableTileStatus(
+    IN gcsSURF_VIEW *Surface
+    );
+
+/* Enable tile status for the specified surface on specified slot. */
+gceSTATUS
+gcoSURF_EnableTileStatusEx(
+    IN gcsSURF_VIEW *surfView,
+    IN gctUINT RtIndex
+    );
+
+/* Disable tile status for the specified surface. */
+gceSTATUS
+gcoSURF_DisableTileStatus(
+    IN gcsSURF_VIEW *SurfView,
+    IN gctBOOL Decompress
+    );
+
+/* Flush tile status cache for the specified surface. */
+gceSTATUS
+gcoSURF_FlushTileStatus(
+    IN gcsSURF_VIEW *SurfView,
+    IN gctBOOL Decompress
+    );
+#endif /* gcdENABLE_3D */
+
+/* Get surface size. */
+gceSTATUS
+gcoSURF_GetSize(
+    IN gcoSURF Surface,
+    OUT gctUINT * Width,
+    OUT gctUINT * Height,
+    OUT gctUINT * Depth
+    );
+
+/* Get surface information */
+gceSTATUS
+gcoSURF_GetInfo(
+    IN gcoSURF Surface,
+    IN gceSURF_INFO_TYPE InfoType,
+    IN OUT gctINT32 *Value
+    );
+
+/* Get surface aligned sizes. */
+gceSTATUS
+gcoSURF_GetAlignedSize(
+    IN gcoSURF Surface,
+    OUT gctUINT * Width,
+    OUT gctUINT * Height,
+    OUT gctINT * Stride
+    );
+
+/* Get alignments. */
+gceSTATUS
+gcoSURF_GetAlignment(
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format,
+    OUT gctUINT * AddressAlignment,
+    OUT gctUINT * XAlignment,
+    OUT gctUINT * YAlignment
+    );
+
+gceSTATUS
+gcoSURF_AlignResolveRect(
+    IN gcoSURF Surf,
+    IN gcsPOINT_PTR RectOrigin,
+    IN gcsPOINT_PTR RectSize,
+    OUT gcsPOINT_PTR AlignedOrigin,
+    OUT gcsPOINT_PTR AlignedSize
+    );
+
+/* Get surface type and format. */
+gceSTATUS
+gcoSURF_GetFormat(
+    IN gcoSURF Surface,
+    OUT OPTIONAL gceSURF_TYPE * Type,
+    OUT OPTIONAL gceSURF_FORMAT * Format
+    );
+
+/* Get surface information */
+gceSTATUS
+gcoSURF_GetFormatInfo(
+    IN gcoSURF Surface,
+    OUT gcsSURF_FORMAT_INFO_PTR * formatInfo
+    );
+
+/* Get Surface pack format */
+gceSTATUS
+gcoSURF_GetPackedFormat(
+    IN gcoSURF Surface,
+    OUT gceSURF_FORMAT * Format
+    );
+
+/* Get surface tiling. */
+gceSTATUS
+gcoSURF_GetTiling(
+    IN gcoSURF Surface,
+    OUT gceTILING * Tiling
+    );
+
+/* Get bottom buffer offset bytes. */
+gceSTATUS
+gcoSURF_GetBottomBufferOffset(
+    IN gcoSURF Surface,
+    OUT gctUINT_PTR BottomBufferOffset
+    );
+
+/* Lock the surface. */
+gceSTATUS
+gcoSURF_Lock(
+    IN gcoSURF Surface,
+    IN OUT gctUINT32 * Address,
+    IN OUT gctPOINTER * Memory
+    );
+
+/* Unlock the surface. */
+gceSTATUS
+gcoSURF_Unlock(
+    IN gcoSURF Surface,
+    IN gctPOINTER Memory
+    );
+
+/*. Query surface flags.*/
+gceSTATUS
+gcoSURF_QueryFlags(
+    IN gcoSURF Surface,
+    IN gceSURF_FLAG Flag
+    );
+
+gceSTATUS
+gcoSURF_QueryHints(
+    IN gcoSURF Surface,
+    IN gceSURF_TYPE Hints
+    );
+
+/* Return pixel format parameters; Info is required to be a pointer to an
+ * array of at least two items because some formats have up to two records
+ * of description. */
+gceSTATUS
+gcoSURF_QueryFormat(
+    IN gceSURF_FORMAT Format,
+    OUT gcsSURF_FORMAT_INFO_PTR * Info
+    );
+
+/* Compute the color pixel mask. */
+gceSTATUS
+gcoSURF_ComputeColorMask(
+    IN gcsSURF_FORMAT_INFO_PTR Format,
+    OUT gctUINT32_PTR ColorMask
+    );
+
+/* Flush the surface. */
+gceSTATUS
+gcoSURF_Flush(
+    IN gcoSURF Surface
+    );
+
+/* Fill surface from it's tile status buffer. */
+gceSTATUS
+gcoSURF_FillFromTile(
+    IN gcsSURF_VIEW *SurView
+    );
+
+/* Fill surface with a value. */
+gceSTATUS
+gcoSURF_Fill(
+    IN gcoSURF Surface,
+    IN gcsPOINT_PTR Origin,
+    IN gcsSIZE_PTR Size,
+    IN gctUINT32 Value,
+    IN gctUINT32 Mask
+    );
+
+/* Alpha blend two surfaces together. */
+gceSTATUS
+gcoSURF_Blend(
+    IN gcoSURF SrcSurf,
+    IN gcoSURF DstSurf,
+    IN gcsPOINT_PTR SrcOrigin,
+    IN gcsPOINT_PTR DstOrigin,
+    IN gcsSIZE_PTR Size,
+    IN gceSURF_BLEND_MODE Mode
+    );
+
+/* Create a new gcoSURF wrapper object. */
+gceSTATUS
+gcoSURF_ConstructWrapper(
+    IN gcoHAL Hal,
+    OUT gcoSURF * Surface
+    );
+
+/* Set surface flags.*/
+gceSTATUS
+gcoSURF_SetFlags(
+    IN gcoSURF Surface,
+    IN gceSURF_FLAG Flag,
+    IN gctBOOL Value
+    );
+
+/* Set the underlying buffer for the surface wrapper. */
+gceSTATUS
+gcoSURF_SetBuffer(
+    IN gcoSURF Surface,
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT Stride,
+    IN gctPOINTER Logical,
+    IN gctUINT64 Physical
+    );
+
+/* Set the size of the surface in pixels and map the underlying buffer. */
+gceSTATUS
+gcoSURF_SetWindow(
+    IN gcoSURF Surface,
+    IN gctUINT X,
+    IN gctUINT Y,
+    IN gctUINT Width,
+    IN gctUINT Height
+    );
+
+/* Set the size of the surface in pixels and map the underlying buffer. */
+gceSTATUS
+gcoSURF_SetImage(
+    IN gcoSURF Surface,
+    IN gctUINT X,
+    IN gctUINT Y,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gctUINT Depth
+    );
+
+/* Set width/height alignment of the surface directly and calculate stride/size. This is only for dri backend now. Please be careful before use. */
+gceSTATUS
+gcoSURF_SetAlignment(
+    IN gcoSURF Surface,
+    IN gctUINT Width,
+    IN gctUINT Height
+    );
+
+/* Increase reference count of the surface. */
+gceSTATUS
+gcoSURF_ReferenceSurface(
+    IN gcoSURF Surface
+    );
+
+/* Get surface reference count. */
+gceSTATUS
+gcoSURF_QueryReferenceCount(
+    IN gcoSURF Surface,
+    OUT gctINT32 * ReferenceCount
+    );
+
+/* Set surface orientation. */
+gceSTATUS
+gcoSURF_SetOrientation(
+    IN gcoSURF Surface,
+    IN gceORIENTATION Orientation
+    );
+
+/* Query surface orientation. */
+gceSTATUS
+gcoSURF_QueryOrientation(
+    IN gcoSURF Surface,
+    OUT gceORIENTATION * Orientation
+    );
+
+gceSTATUS
+gcoSURF_NODE_Cache(
+    IN gcsSURF_NODE_PTR Node,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    );
+
+gceSTATUS
+gcsSURF_NODE_SetHardwareAddress(
+    IN gcsSURF_NODE_PTR Node,
+    IN gctUINT32 Address
+    );
+
+gceSTATUS
+gcsSURF_NODE_GetHardwareAddress(
+    IN gcsSURF_NODE_PTR Node,
+    OUT gctUINT32_PTR Physical,
+    OUT gctUINT32_PTR Physical2,
+    OUT gctUINT32_PTR Physical3,
+    OUT gctUINT32_PTR PhysicalBottom
+    );
+
+gctUINT32
+gcsSURF_NODE_GetHWAddress(
+    IN gcsSURF_NODE_PTR Node
+    );
+
+/* Lock and unlock surface node */
+gceSTATUS
+gcoSURF_LockNode(
+    IN gcsSURF_NODE_PTR Node,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Memory
+    );
+
+gceSTATUS
+gcoSURF_UnLockNode(
+    IN gcsSURF_NODE_PTR Node,
+    IN gceSURF_TYPE Type
+    );
+
+/* Perform CPU cache operation on surface node */
+gceSTATUS
+gcoSURF_NODE_CPUCacheOperation(
+    IN gcsSURF_NODE_PTR Node,
+    IN gceSURF_TYPE Type,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Length,
+    IN gceCACHEOPERATION Operation
+    );
+
+/* Perform CPU cache operation on surface */
+gceSTATUS
+gcoSURF_CPUCacheOperation(
+    IN gcoSURF Surface,
+    IN gceCACHEOPERATION Operation
+    );
+
+
+gceSTATUS
+gcoSURF_Swap(
+    IN gcoSURF Surface1,
+    IN gcoSURF Surface2
+    );
+
+gceSTATUS
+gcoSURF_ResetSurWH(
+    IN gcoSURF Surface,
+    IN gctUINT oriw,
+    IN gctUINT orih,
+    IN gctUINT alignw,
+    IN gctUINT alignh,
+    IN gceSURF_FORMAT fmt
+);
+
+/* Update surface timestamp. */
+gceSTATUS
+gcoSURF_UpdateTimeStamp(
+    IN gcoSURF Surface
+    );
+
+/* Query surface current timestamp. */
+gceSTATUS
+gcoSURF_QueryTimeStamp(
+    IN gcoSURF Surface,
+    OUT gctUINT64 * TimeStamp
+    );
+
+/*
+ * Allocate shared buffer for this surface, so that
+ * surface states can be shared across processes.
+ */
+gceSTATUS
+gcoSURF_AllocShBuffer(
+    IN gcoSURF Surface,
+    OUT gctSHBUF * ShBuf
+    );
+
+/* Bind shared buffer to this surface */
+gceSTATUS
+gcoSURF_BindShBuffer(
+    IN gcoSURF Surface,
+    IN gctSHBUF ShBuf
+    );
+
+/* Push surface shared states to shared buffer. */
+gceSTATUS
+gcoSURF_PushSharedInfo(
+    IN gcoSURF Surface
+    );
+
+/* Pop shared states from shared buffer. */
+gceSTATUS
+gcoSURF_PopSharedInfo(
+    IN gcoSURF Surface
+    );
+
+#if (gcdENABLE_3D || gcdENABLE_VG)
+/* Copy surface. */
+gceSTATUS
+gcoSURF_Copy(
+    IN gcoSURF Surface,
+    IN gcoSURF Source
+    );
+
+/* Set number of samples for a gcoSURF object. */
+gceSTATUS
+gcoSURF_SetSamples(
+    IN gcoSURF Surface,
+    IN gctUINT Samples
+    );
+
+/* Get the number of samples per pixel. */
+gceSTATUS
+gcoSURF_GetSamples(
+    IN gcoSURF Surface,
+    OUT gctUINT_PTR Samples
+    );
+
+/* Append tile status buffer to user pool surface. */
+gceSTATUS
+gcoSURF_AppendTileStatus(
+    IN gcoSURF Surface
+    );
+#endif
+
+gceSTATUS
+gcoSURF_WrapUserMemory(
+    IN gcoHAL Hal,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gctUINT Stride,
+    IN gctUINT Depth,
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT32 Handle,
+    IN gctUINT32 Flag,
+    OUT gcoSURF * Surface
+    );
+
+gceSTATUS
+gcoSURF_WrapUserMultiBuffer(
+    IN gcoHAL Hal,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT Stride[3],
+    IN gctUINT32 Handle[3],
+    IN gctUINT BufferOffset[3],
+    IN gctUINT32 Flag,
+    OUT gcoSURF * Surface
+    );
+
+gceSTATUS
+gcoSURF_UpdateMetadata(
+    IN gcoSURF Surface,
+    IN gctINT TsFD
+    );
+
+#define MAX_SURF_MIX_SRC_NUM 64
+gceSTATUS
+gcoSURF_MixSurfacesCPU(
+    IN gcoSURF TargetSurface,
+    IN gctUINT TargetSliceIndex,
+    IN gcoSURF *SourceSurface,
+    IN gctUINT *SourceSliceIndices,
+    IN gctFLOAT *Weights,
+    IN gctINT Count
+    );
+
+/******************************************************************************\
+******************************* Hash Structure ******************************
+\******************************************************************************/
+
+typedef struct _gcsHASH_MD5CTX
+{
+    gctBOOL   bigEndian;
+    gctSIZE_T bytes;     /* Number of bytes processed */
+    gctUINT32 states[4];
+    gctUINT8  buffer[64];
+} gcsHASH_MD5CTX;
+
+void gcsHASH_MD5Init(
+    gcsHASH_MD5CTX *ctx
+    );
+void gcsHASH_MD5Update(
+    gcsHASH_MD5CTX *ctx,
+    const void *data,
+    gctSIZE_T bytes
+    );
+void gcsHASH_MD5Final(
+    gcsHASH_MD5CTX *ctx,
+    gctUINT8 digest[16]
+    );
+
+
+/******************************************************************************\
+******************************* gcsRECT Structure ******************************
+\******************************************************************************/
+
+/* Initialize rectangle structure. */
+gceSTATUS
+gcsRECT_Set(
+    OUT gcsRECT_PTR Rect,
+    IN gctINT32 Left,
+    IN gctINT32 Top,
+    IN gctINT32 Right,
+    IN gctINT32 Bottom
+    );
+
+/* Return the width of the rectangle. */
+gceSTATUS
+gcsRECT_Width(
+    IN gcsRECT_PTR Rect,
+    OUT gctINT32 * Width
+    );
+
+/* Return the height of the rectangle. */
+gceSTATUS
+gcsRECT_Height(
+    IN gcsRECT_PTR Rect,
+    OUT gctINT32 * Height
+    );
+
+/* Ensure that top left corner is to the left and above the right bottom. */
+gceSTATUS
+gcsRECT_Normalize(
+    IN OUT gcsRECT_PTR Rect
+    );
+
+/* Compare two rectangles. */
+gceSTATUS
+gcsRECT_IsEqual(
+    IN gcsRECT_PTR Rect1,
+    IN gcsRECT_PTR Rect2,
+    OUT gctBOOL * Equal
+    );
+
+/* Compare the sizes of two rectangles. */
+gceSTATUS
+gcsRECT_IsOfEqualSize(
+    IN gcsRECT_PTR Rect1,
+    IN gcsRECT_PTR Rect2,
+    OUT gctBOOL * EqualSize
+    );
+
+gceSTATUS
+gcsRECT_RelativeRotation(
+    IN gceSURF_ROTATION Orientation,
+    IN OUT gceSURF_ROTATION *Relation);
+
+gceSTATUS
+
+gcsRECT_Rotate(
+
+    IN OUT gcsRECT_PTR Rect,
+
+    IN gceSURF_ROTATION Rotation,
+
+    IN gceSURF_ROTATION toRotation,
+
+    IN gctINT32 SurfaceWidth,
+
+    IN gctINT32 SurfaceHeight
+
+    );
+
+/******************************************************************************\
+**************************** gcsBOUNDARY Structure *****************************
+\******************************************************************************/
+
+typedef struct _gcsBOUNDARY
+{
+    gctINT                      x;
+    gctINT                      y;
+    gctINT                      width;
+    gctINT                      height;
+}
+gcsBOUNDARY;
+
+/******************************************************************************\
+********************************* gcoHEAP Object ********************************
+\******************************************************************************/
+
+typedef struct _gcoHEAP *       gcoHEAP;
+
+/* Construct a new gcoHEAP object. */
+gceSTATUS
+gcoHEAP_Construct(
+    IN gcoOS Os,
+    IN gctSIZE_T AllocationSize,
+    OUT gcoHEAP * Heap
+    );
+
+/* Destroy an gcoHEAP object. */
+gceSTATUS
+gcoHEAP_Destroy(
+    IN gcoHEAP Heap
+    );
+
+/* Allocate memory. */
+gceSTATUS
+gcoHEAP_Allocate(
+    IN gcoHEAP Heap,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Node
+    );
+
+gceSTATUS
+gcoHEAP_GetMemorySize(
+    IN gcoHEAP Heap,
+    IN gctPOINTER Memory,
+    OUT gctSIZE_T_PTR MemorySize
+    );
+
+/* Free memory. */
+gceSTATUS
+gcoHEAP_Free(
+    IN gcoHEAP Heap,
+    IN gctPOINTER Node
+    );
+
+#if (VIVANTE_PROFILER_SYSTEM_MEMORY  || gcdDEBUG)
+/* Profile the heap. */
+gceSTATUS
+gcoHEAP_ProfileStart(
+    IN gcoHEAP Heap
+    );
+
+gceSTATUS
+gcoHEAP_ProfileEnd(
+    IN gcoHEAP Heap,
+    IN gctCONST_STRING Title
+    );
+#endif
+
+/******************************************************************************\
+******************************* Debugging Macros *******************************
+\******************************************************************************/
+
+void
+gcoOS_SetDebugLevel(
+    IN gctUINT32 Level
+    );
+
+void
+gcoOS_GetDebugLevel(
+    OUT gctUINT32_PTR DebugLevel
+    );
+
+void
+gcoOS_GetDebugZone(
+    IN gctUINT32 Zone,
+    OUT gctUINT32_PTR DebugZone
+    );
+
+void
+gcoOS_SetDebugZone(
+    IN gctUINT32 Zone
+    );
+
+void
+gcoOS_SetDebugFile(
+    IN gctCONST_STRING FileName
+    );
+
+void
+gcoOS_EnableDebugDump(
+    IN gctBOOL Enable
+    );
+
+gctFILE
+gcoOS_ReplaceDebugFile(
+    IN gctFILE fp
+    );
+
+/*******************************************************************************
+**
+**  gcmFATAL
+**
+**      Print a message to the debugger and execute a break point.
+**
+**  ARGUMENTS:
+**
+**      message Message.
+**      ...     Optional arguments.
+*/
+
+void
+gckOS_DebugFatal(
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+void
+gcoOS_DebugFatal(
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_FATAL)
+#   define gcmFATAL             gcoOS_DebugFatal
+#   define gcmkFATAL            gckOS_DebugFatal
+#elif gcdHAS_ELLIPSIS
+#   define gcmFATAL(...)
+#   define gcmkFATAL(...)
+#else
+    gcmINLINE static void
+    __dummy_fatal(
+        IN gctCONST_STRING Message,
+        ...
+        )
+    {
+    }
+#   define gcmFATAL             __dummy_fatal
+#   define gcmkFATAL            __dummy_fatal
+#endif
+
+#define gcmENUM2TEXT(e)         case e: return #e
+
+/*******************************************************************************
+**
+**  gcmTRACE
+**
+**      Print a message to the debugfer if the correct level has been set.  In
+**      retail mode this macro does nothing.
+**
+**  ARGUMENTS:
+**
+**      level   Level of message.
+**      message Message.
+**      ...     Optional arguments.
+*/
+#define gcvLEVEL_NONE           -1
+#define gcvLEVEL_ERROR          0
+#define gcvLEVEL_WARNING        1
+#define gcvLEVEL_INFO           2
+#define gcvLEVEL_VERBOSE        3
+
+void
+gckOS_DebugTrace(
+    IN gctUINT32 Level,
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+void
+gcoOS_DebugTrace(
+    IN gctUINT32 Level,
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#   define gcmTRACE             gcoOS_DebugTrace
+#   define gcmkTRACE            gckOS_DebugTrace
+#   define gcmkTRACE_N(Level, ArgumentSize, ...) \
+        gckOS_DebugTrace(Level, __VA_ARGS__)
+#elif gcdHAS_ELLIPSIS
+#   define gcmTRACE(...)
+#   define gcmkTRACE(...)
+#   define gcmkTRACE_N(...)
+#else
+    gcmINLINE static void
+    __dummy_trace(
+        IN gctUINT32 Level,
+        IN gctCONST_STRING Message,
+        ...
+        )
+    {
+    }
+
+    gcmINLINE static void
+    __dummy_trace_n(
+        IN gctUINT32 Level,
+        IN gctUINT ArgumentSize,
+        IN gctCONST_STRING Message,
+        ...
+        )
+    {
+    }
+
+#   define gcmTRACE             __dummy_trace
+#   define gcmkTRACE            __dummy_trace
+#   define gcmkTRACE_N          __dummy_trace_n
+#endif
+
+/*******************************************************************************
+**
+**  gcmTRACE_ZONE
+**
+**      Print a message to the debugger if the correct level and zone has been
+**      set.  In retail mode this macro does nothing.
+**
+**  ARGUMENTS:
+**
+**      Level   Level of message.
+**      Zone    Zone of message.
+**      Message Message.
+**      ...     Optional arguments.
+*/
+
+void
+gckOS_DebugTraceZone(
+    IN gctUINT32 Level,
+    IN gctUINT32 Zone,
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+void
+gcoOS_DebugTraceZone(
+    IN gctUINT32 Level,
+    IN gctUINT32 Zone,
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#   define gcmTRACE_ZONE            gcoOS_DebugTraceZone
+#   define gcmkTRACE_ZONE           gckOS_DebugTraceZone
+#   define gcmkTRACE_ZONE_N(Level, Zone, ArgumentSize, ...) \
+        gckOS_DebugTraceZone(Level, Zone, __VA_ARGS__)
+#elif gcdHAS_ELLIPSIS
+#   define gcmTRACE_ZONE(...)
+#   define gcmkTRACE_ZONE(...)
+#   define gcmkTRACE_ZONE_N(...)
+#else
+    gcmINLINE static void
+    __dummy_trace_zone(
+        IN gctUINT32 Level,
+        IN gctUINT32 Zone,
+        IN gctCONST_STRING Message,
+        ...
+        )
+    {
+    }
+
+    gcmINLINE static void
+    __dummy_trace_zone_n(
+        IN gctUINT32 Level,
+        IN gctUINT32 Zone,
+        IN gctUINT ArgumentSize,
+        IN gctCONST_STRING Message,
+        ...
+        )
+    {
+    }
+
+#   define gcmTRACE_ZONE            __dummy_trace_zone
+#   define gcmkTRACE_ZONE           __dummy_trace_zone
+#   define gcmkTRACE_ZONE_N         __dummy_trace_zone_n
+#endif
+
+
+/*******************************************************************************
+**
+**  gcmDEBUG_ONLY
+**
+**      Execute a statement or function only in DEBUG mode.
+**
+**  ARGUMENTS:
+**
+**      f       Statement or function to execute.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+#   define gcmDEBUG_ONLY(f)         f
+#else
+#   define gcmDEBUG_ONLY(f)
+#endif
+
+
+/*******************************************************************************
+**
+**  gcmSTACK_PUSH
+**  gcmSTACK_POP
+**  gcmSTACK_DUMP
+**  gcmSTACK_REMOVE
+**
+**      Push or pop a function with entry arguments on the trace stack.
+**
+**  ARGUMENTS:
+**
+**      Function    Name of function.
+**      Line        Line number.
+**      Text        Optional text.
+**      ...         Optional arguments for text.
+**
+**      Thread      Thread id.
+*/
+void
+gcoOS_StackPush(
+    IN gctINT8_PTR Identity,
+    IN gctCONST_STRING Function,
+    IN gctINT Line,
+    IN gctCONST_STRING Text,
+    ...
+    );
+
+void
+gcoOS_StackPop(
+    IN gctINT8_PTR Identity,
+    IN gctCONST_STRING Function
+    );
+
+void
+gcoOS_StackDump(
+    void);
+
+void
+gcoOS_StackRemove(
+    IN gctHANDLE Thread
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_STACK)
+#   define gcmSTACK_PUSH            gcoOS_StackPush
+#   define gcmSTACK_POP             gcoOS_StackPop
+#   define gcmSTACK_DUMP            gcoOS_StackDump
+#   define gcmSTACK_REMOVE          gcoOS_StackRemove
+#elif gcdHAS_ELLIPSIS
+#   define gcmSTACK_PUSH(...)
+#   define gcmSTACK_POP(...)
+#   define gcmSTACK_DUMP()
+#   define gcmSTACK_REMOVE(...)
+#else
+    gcmINLINE static void
+    __dummy_stack_push(
+        IN gctCONST_STRING Function,
+        IN gctINT Line,
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+
+    gcmINLINE static void
+    __dummy_stack_pop(
+        IN gctINT8_PTR Identity,
+        IN gctCONST_STRING Function
+        );
+
+    gcmINLINE static void
+    __dummy_stack_remove(
+        IN gctHANDLE Thread
+        );
+
+#   define gcmSTACK_PUSH            __dummy_stack_push
+#   define gcmSTACK_POP(a,b)        __dummy_stack_pop
+#   define gcmSTACK_DUMP()
+#   define gcmSTACK_REMOVE(a)       __dummy_stack_remove
+#endif
+
+
+/*******************************************************************************
+**
+**  gcmBINARY_TRACE
+**
+**      Push or pop a function with entry arguments on the trace stack.
+**
+**  ARGUMENTS:
+**
+**      Function    Name of function
+**      Line        Line number
+**      Text        Optional text
+**      ...         Optional arguments for text.
+*/
+void
+gcoOS_BinaryTrace(
+    IN gctCONST_STRING Function,
+    IN gctINT Line,
+    IN gctCONST_STRING Text OPTIONAL,
+    ...
+    );
+
+void
+gckOS_BinaryTrace(
+    IN gctCONST_STRING Function,
+    IN gctINT Line,
+    IN gctCONST_STRING Text OPTIONAL,
+    ...
+    );
+
+#if gcdBINARY_TRACE
+#   define gcmBINARY_TRACE          gcoOS_BinaryTrace
+#   define gcmkBINARY_TRACE         gckOS_BinaryTrace
+#elif gcdHAS_ELLIPSIS
+#   define gcmBINARY_TRACE(Function, Line, Text, ...)
+#   define gcmkBINARY_TRACE(Function, Line, Text, ...)
+#else
+    gcmINLINE static void
+    __dummy_binary_trace(
+        IN gctCONST_STRING Function,
+        IN gctINT Line,
+        IN gctCONST_STRING Text,
+        )
+    {
+    }
+
+#   define gcmBINARY_TRACE          __dummy_binary_trace
+#   define gcmkBINARY_TRACE         __dummy_binary_trace
+#endif
+
+
+/*******************************************************************************
+**
+**  gcmSYSTRACE_BEGIN
+**  gcmSYSTRACE_END
+**
+**      Systrace is a performance tunning tool on linux.
+**
+**  ARGUMENTS:
+**
+**      FuncName Function name
+**      Zone     Systrace zone. Only specified zones are traced.
+*/
+
+void
+gcoOS_SysTraceBegin(
+    IN gctUINT32 Zone,
+    IN gctCONST_STRING FuncName
+    );
+
+void
+gcoOS_SysTraceEnd(
+    IN gctUINT32 Zone
+    );
+
+#if defined(LINUX) && gcdSYSTRACE
+#   define gcmSYSTRACE_BEGIN    gcoOS_SysTraceBegin
+#   define gcmSYSTRACE_END      gcoOS_SysTraceEnd
+#elif gcdHAS_ELLIPSIS
+#   define gcmSYSTRACE_BEGIN(...)
+#   define gcmSYSTRACE_END(...)
+#else
+    gcmINLINE static void
+    __dummy_systrace_begin(
+        IN gctUINT32 Zone,
+        IN gctCONST_STRING FuncName
+        )
+    {
+    }
+
+    gcmINLINE static void
+    __dummy_systrace_end(
+        IN gctUINT32 Zone
+        )
+    {
+    }
+
+#   define gcmSYSTRACE_BEGIN        __dummy_systrace_begin
+#   define gcmSYSTRACE_END          __dummy_systrace_end
+#endif
+
+
+/******************************************************************************\
+******************************** Logging Macros ********************************
+\******************************************************************************/
+
+#define gcdHEADER_LEVEL             gcvLEVEL_VERBOSE
+
+/* Always enable header/footer when systrace build is on */
+#if defined(LINUX) && gcdSYSTRACE
+#undef gcdEMPTY_HEADER_FOOTER
+#endif
+
+#ifndef gcdEMPTY_HEADER_FOOTER
+#define gcdEMPTY_HEADER_FOOTER 0
+#endif
+
+#if gcdENABLE_PROFILING
+void
+gcoOS_ProfileDB(
+    IN gctCONST_STRING Function,
+    IN OUT gctBOOL_PTR Initialized
+    );
+
+#define gcmHEADER() \
+    gctINT8 __user__ = 1; \
+    static gctBOOL __profile__initialized__ = gcvFALSE; \
+    gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__)
+
+#define gcmHEADER_ARG(...) \
+    gctINT8 __user__ = 1; \
+    static gctBOOL __profile__initialized__ = gcvFALSE; \
+    gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+    gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__)
+
+#define gcmFOOTER() \
+    gcmSTACK_POP(&__user__, __FUNCTION__); \
+    gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_NO() \
+    gcmSTACK_POP(&__user__, __FUNCTION__); \
+    gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_ARG(...) \
+    gcmSTACK_POP(&__user__, __FUNCTION__); \
+    gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_KILL() \
+    gcmSTACK_POP(&__user__, __FUNCTION__); \
+    gcoOS_ProfileDB(gcvNULL, gcvNULL)
+
+#else /* !gcdENABLE_PROFILING */
+
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmHEADER()
+#elif gcdHAS_ELLIPSIS
+#define gcmHEADER() \
+    gctINT8 __user__ = 1; \
+    gctINT8_PTR __user_ptr__ = &__user__; \
+    gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmSYSTRACE_BEGIN(_GC_OBJ_ZONE, __FUNCTION__); \
+    gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                  "++%s(%d)", __FUNCTION__, __LINE__)
+#else
+    gcmINLINE static void
+    __dummy_header(void)
+    {
+    }
+#   define gcmHEADER                   __dummy_header
+#endif
+
+#if gcdHAS_ELLIPSIS
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmHEADER_ARG(Text, ...)
+#else
+#   define gcmHEADER_ARG(Text, ...) \
+        gctINT8 __user__ = 1; \
+        gctINT8_PTR __user_ptr__ = &__user__; \
+        gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+        gcmSYSTRACE_BEGIN(_GC_OBJ_ZONE, __FUNCTION__); \
+        gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+        gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                      "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__)
+#endif
+#else
+    gcmINLINE static void
+    __dummy_header_arg(
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+#   define gcmHEADER_ARG                __dummy_header_arg
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmFOOTER()
+#elif gcdHAS_ELLIPSIS
+#   define gcmFOOTER() \
+    gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+    gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+    gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                  "--%s(%d): status=%d(%s)", \
+                  __FUNCTION__, __LINE__, \
+                  status, gcoOS_DebugStatus2Name(status)); \
+    *__user_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_footer(void)
+    {
+    }
+#   define gcmFOOTER                    __dummy_footer
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmFOOTER_NO()
+#elif gcdHAS_ELLIPSIS
+#define gcmFOOTER_NO() \
+    gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+    gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+    gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                  "--%s(%d)", __FUNCTION__, __LINE__); \
+    *__user_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_footer_no(void)
+    {
+    }
+#   define gcmFOOTER_NO                 __dummy_footer_no
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmFOOTER_KILL()
+#elif gcdHAS_ELLIPSIS
+#define gcmFOOTER_KILL() \
+    gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+    gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+    gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                  "--%s(%d)", __FUNCTION__, __LINE__); \
+    *__user_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_footer_kill(void)
+    {
+    }
+#   define gcmFOOTER_KILL               __dummy_footer_kill
+#endif
+
+#if gcdHAS_ELLIPSIS
+#if gcdEMPTY_HEADER_FOOTER
+#   define gcmFOOTER_ARG(Text, ...)
+#else
+#   define gcmFOOTER_ARG(Text, ...) \
+        gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+        gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+        gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+        gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                      "--%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__); \
+        *__user_ptr__ -= 1
+#endif
+#else
+    gcmINLINE static void
+    __dummy_footer_arg(
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+#   define gcmFOOTER_ARG                __dummy_footer_arg
+#endif
+
+#endif /* gcdENABLE_PROFILING */
+
+#if gcdHAS_ELLIPSIS
+#define gcmkHEADER() \
+    gctINT8 __kernel__ = 1; \
+    gctINT8_PTR __kernel_ptr__ = &__kernel__; \
+    gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                   "++%s(%d)", __FUNCTION__, __LINE__)
+#else
+    gcmINLINE static void
+    __dummy_kheader(void)
+    {
+    }
+#   define gcmkHEADER                  __dummy_kheader
+#endif
+
+#if gcdHAS_ELLIPSIS
+#   define gcmkHEADER_ARG(Text, ...) \
+        gctINT8 __kernel__ = 1; \
+        gctINT8_PTR __kernel_ptr__ = &__kernel__; \
+        gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+        gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                       "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__)
+#else
+    gcmINLINE static void
+    __dummy_kheader_arg(
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+#   define gcmkHEADER_ARG               __dummy_kheader_arg
+#endif
+
+#if gcdHAS_ELLIPSIS
+#define gcmkFOOTER() \
+    gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, status); \
+    gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                   "--%s(%d): status=%d(%s)", \
+                   __FUNCTION__, __LINE__, status, gckOS_DebugStatus2Name(status)); \
+    *__kernel_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_kfooter(void)
+    {
+    }
+#   define gcmkFOOTER                   __dummy_kfooter
+#endif
+
+#if gcdHAS_ELLIPSIS
+#define gcmkFOOTER_NO() \
+    gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+    gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                   "--%s(%d)", __FUNCTION__, __LINE__); \
+    *__kernel_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_kfooter_no(void)
+    {
+    }
+#   define gcmkFOOTER_NO                __dummy_kfooter_no
+#endif
+
+#if gcdHAS_ELLIPSIS
+#   define gcmkFOOTER_ARG(Text, ...) \
+        gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+        gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+                       "--%s(%d): " Text, \
+                       __FUNCTION__, __LINE__, __VA_ARGS__); \
+        *__kernel_ptr__ -= 1
+#else
+    gcmINLINE static void
+    __dummy_kfooter_arg(
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+#   define gcmkFOOTER_ARG               __dummy_kfooter_arg
+#endif
+
+#define gcmOPT_VALUE(ptr)               (((ptr) == gcvNULL) ? 0 : *(ptr))
+#define gcmOPT_VALUE_INDEX(ptr, index)  (((ptr) == gcvNULL) ? 0 : ptr[index])
+#define gcmOPT_POINTER(ptr)             (((ptr) == gcvNULL) ? gcvNULL : *(ptr))
+#define gcmOPT_STRING(ptr)              (((ptr) == gcvNULL) ? "(nil)" : (ptr))
+
+void
+gckOS_Print(
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+void
+gcoOS_Print(
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+#define gcmPRINT                gcoOS_Print
+#define gcmkPRINT               gckOS_Print
+#define gcmkPRINT_N(ArgumentSize, ...) gckOS_Print(__VA_ARGS__)
+
+#if gcdHAS_ELLIPSIS
+#   define gcmPRINT_ONCE(Text, ...)         \
+    {                                       \
+        static gctBOOL _once = gcvFALSE;    \
+        if (!_once)                         \
+        {                                   \
+            gcmPRINT(Text, __VA_ARGS__);    \
+            _once = gcvTRUE;                \
+        }                                   \
+    }                                       \
+
+#else
+    gcmINLINE static void
+    __dummy_printonce_arg(
+        IN gctCONST_STRING Text,
+        ...
+        )
+    {
+    }
+#   define gcmPRINT_ONCE               __dummy_printonce_arg
+#endif
+
+#if gcdFEATURE_SANITYCHECK
+#define gcmFEATURE_CHECKED                gcmPRINT_ONCE
+#else
+#define gcmFEATURE_CHECKED(Text, ...)
+#endif
+
+#if gcdPRINT_VERSION
+#   define gcmPRINT_VERSION()       do { \
+                                        _gcmPRINT_VERSION(gcm); \
+                                        gcmSTACK_DUMP(); \
+                                    } while (0)
+#   define gcmkPRINT_VERSION()      _gcmPRINT_VERSION(gcmk)
+#   define _gcmPRINT_VERSION(prefix) \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+                      "Vivante HAL version %s", \
+                      gcvVERSION_STRING)
+#else
+#   define gcmPRINT_VERSION()       do { gcmSTACK_DUMP(); } while (gcvFALSE)
+#   define gcmkPRINT_VERSION()      do { } while (gcvFALSE)
+#endif
+
+void
+gckOS_Dump(
+    IN gckOS Os,
+    IN gctCONST_STRING Format,
+    ...
+    );
+
+void
+gckOS_DumpBuffer(
+    IN gckOS Os,
+    IN gceDUMP_BUFFER_TYPE Type,
+    IN gctPOINTER Buffer,
+    IN gctUINT64 Address,
+    IN gctSIZE_T Size
+    );
+
+#if gcdDUMP_IN_KERNEL
+#   define gcmkDUMP             gckOS_Dump
+
+#   define gcmkDUMP_BUFFER      gckOS_DumpBuffer
+#else
+#   define gcmkDUMP(...)        do {} while (0)
+#   define gcmkDUMP_BUFFER(...) do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_FRAMERATE
+**
+**      Print average frame rate
+**
+*/
+gceSTATUS
+gcoOS_DumpFrameRate(
+    void
+    );
+#   define gcmDUMP_FRAMERATE        gcoOS_DumpFrameRate
+
+/*******************************************************************************
+**
+**  gcoOS_SetDumpFlag
+**
+**      Dump print switch.
+**
+**  ARGUMENTS:
+**
+**      DumpState
+**          True to enable dump prints.
+*/
+
+gceSTATUS
+gcoOS_SetDumpFlag(
+    IN gctBOOL DumpState
+    );
+
+/*******************************************************************************
+**
+**  gcmDUMP
+**
+**      Print a dump message.
+**
+**  ARGUMENTS:
+**
+**      gctSTRING   Message.
+**
+**      ...         Optional arguments.
+*/
+
+#if gcdDUMP
+gceSTATUS
+gcoOS_Dump(
+    IN gcoOS Os,
+    IN gctCONST_STRING String,
+    ...
+    );
+#  define gcmDUMP               gcoOS_Dump
+#else
+#  define gcmDUMP(...)          do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_BUFFER
+**
+**      Print a buffer to the dump.
+**
+**  ARGUMENTS:
+**
+**      gctSTRING Tag
+**          Tag for dump.
+**
+**      gctUINT32 Address
+**          GPU address of buffer.
+**
+**      gctPOINTER Logical
+**          Logical address of buffer.
+**
+**      gctUINT32 Offset
+**          Offset into buffer.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes.
+*/
+
+#if gcdDUMP
+gceSTATUS
+gcoOS_DumpBuffer(
+    IN gcoOS Os,
+    IN gceDUMP_BUFFER_TYPE Type,
+    IN gctUINT32 Address,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes
+    );
+#   define gcmDUMP_BUFFER       gcoOS_DumpBuffer
+#else
+#   define gcmDUMP_BUFFER(...)  do {} while (0)
+#endif
+
+#if gcdDUMP
+void
+gcoOS_DumpLock(
+    void
+    );
+#   define gcmDUMP_LOCK         gcoOS_DumpLock
+#else
+#   define gcmDUMP_LOCK(...)    do {} while (0)
+#endif
+
+#if gcdDUMP
+void
+gcoOS_DumpUnlock(
+    void
+    );
+#   define gcmDUMP_UNLOCK       gcoOS_DumpUnlock
+#else
+#   define gcmDUMP_UNLOCK(...)  do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_API
+**
+**      Print a dump message for a high level API prefixed by the function name.
+**
+**  ARGUMENTS:
+**
+**      gctSTRING   Message.
+**
+**      ...         Optional arguments.
+*/
+gceSTATUS gcoOS_DumpApi(IN gctCONST_STRING String, ...);
+#if gcdDUMP_API
+#   define gcmDUMP_API          gcoOS_DumpApi
+#else
+#   define gcmDUMP_API(...)     do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_API_ARRAY
+**
+**      Print an array of data.
+**
+**  ARGUMENTS:
+**
+**      gctUINT32_PTR   Pointer to array.
+**      gctUINT32       Size.
+*/
+gceSTATUS gcoOS_DumpArray(IN gctCONST_POINTER Data, IN gctUINT32 Size);
+#if gcdDUMP_API
+#   define gcmDUMP_API_ARRAY        gcoOS_DumpArray
+#else
+#   define gcmDUMP_API_ARRAY(...)   do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_API_ARRAY_TOKEN
+**
+**      Print an array of data terminated by a token.
+**
+**  ARGUMENTS:
+**
+**      gctUINT32_PTR   Pointer to array.
+**      gctUINT32       Termination.
+*/
+gceSTATUS gcoOS_DumpArrayToken(IN gctCONST_POINTER Data, IN gctUINT32 Termination);
+#if gcdDUMP_API
+#   define gcmDUMP_API_ARRAY_TOKEN      gcoOS_DumpArrayToken
+#else
+#   define gcmDUMP_API_ARRAY_TOKEN(...) do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmDUMP_API_DATA
+**
+**      Print an array of bytes.
+**
+**  ARGUMENTS:
+**
+**      gctCONST_POINTER    Pointer to array.
+**      gctSIZE_T           Size.
+*/
+gceSTATUS gcoOS_DumpApiData(IN gctCONST_POINTER Data, IN gctSIZE_T Size);
+#if gcdDUMP_API
+#   define gcmDUMP_API_DATA         gcoOS_DumpApiData
+#else
+#   define gcmDUMP_API_DATA(...)    do {} while (0)
+#endif
+
+/*******************************************************************************
+** gcmDUMP_2D_COMMAND
+**
+**      Print the 2D command buffer.
+**
+**  ARGUMENTS:
+**
+**      gctUINT32_PTR       Pointer to the command buffer.
+**      gctUINT32           Command buffer size.
+*/
+gceSTATUS gcoOS_Dump2DCommand(IN gctUINT32_PTR Command, IN gctUINT32 Size);
+#if gcdDUMP_2D
+#   define gcmDUMP_2D_COMMAND(cmd, size) \
+        if (Hardware->newDump2DLevel > 1) \
+            gcoOS_Dump2DCommand(cmd, size)
+#else
+#   define gcmDUMP_2D_COMMAND(...)  do {} while (0)
+#endif
+
+/*******************************************************************************
+** gcmDUMP_2D_SURFACE
+**
+**      Print the 2D surface memory.
+**
+**  ARGUMENTS:
+**
+**      gctBOOL             Src.
+**      gctUINT32           Address.
+*/
+gceSTATUS gcoOS_Dump2DSurface(IN gctBOOL Src, IN gctUINT32 Address);
+#if gcdDUMP_2D
+#   define gcmDUMP_2D_SURFACE(src, addr) \
+        if (Hardware->newDump2DLevel > 2) \
+           gcoOS_Dump2DSurface(src, addr)
+#else
+#   define gcmDUMP_2D_SURFACE(...)  do {} while (0)
+#endif
+
+/*******************************************************************************
+** gcmDUMP_ADD_MEMORY_INFO
+**
+**      Record the memory info.
+**
+**  ARGUMENTS:
+**
+**      gctUINT32           Address.
+**      gctSIZE_T           Size.
+*/
+gceSTATUS gcfAddMemoryInfo(IN gctUINT32 GPUAddress, IN gctPOINTER Logical, IN gctUINT64 Physical, IN gctUINT32 Size);
+#if gcdDUMP_2D
+#   define gcmDUMP_ADD_MEMORY_INFO  gcfAddMemoryInfo
+#else
+#   define gcmDUMP_ADD_MEMORY_INFO(...) do {} while (0)
+#endif
+
+/*******************************************************************************
+** gcmDUMP_DEL_MEMORY_INFO
+**
+**      Record the memory info.
+**
+**  ARGUMENTS:
+**
+**      gctUINT32           Address.
+*/
+gceSTATUS gcfDelMemoryInfo(IN gctUINT32 Address);
+#if gcdDUMP_2D
+#   define gcmDUMP_DEL_MEMORY_INFO  gcfDelMemoryInfo
+#else
+#   define gcmDUMP_DEL_MEMORY_INFO(...) do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmTRACE_RELEASE
+**
+**      Print a message to the shader debugger.
+**
+**  ARGUMENTS:
+**
+**      message Message.
+**      ...     Optional arguments.
+*/
+
+#define gcmTRACE_RELEASE                gcoOS_DebugShaderTrace
+
+void
+gcoOS_DebugShaderTrace(
+    IN gctCONST_STRING Message,
+    ...
+    );
+
+void
+gcoOS_SetDebugShaderFiles(
+    IN gctCONST_STRING VSFileName,
+    IN gctCONST_STRING FSFileName
+    );
+
+void
+gcoOS_SetDebugShaderFileType(
+    IN gctUINT32 ShaderType
+    );
+
+void
+gcoOS_EnableDebugBuffer(
+    IN gctBOOL Enable
+    );
+
+/*******************************************************************************
+**
+**  gcmBREAK
+**
+**      Break into the debugger.  In retail mode this macro does nothing.
+**
+**  ARGUMENTS:
+**
+**      None.
+*/
+
+void
+gcoOS_DebugBreak(
+    void
+    );
+
+void
+gckOS_DebugBreak(
+    void
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_BREAK)
+#   define gcmBREAK             gcoOS_DebugBreak
+#   define gcmkBREAK            gckOS_DebugBreak
+#else
+#   define gcmBREAK()
+#   define gcmkBREAK()
+#endif
+
+/*******************************************************************************
+**
+**  gcmASSERT
+**
+**      Evaluate an expression and break into the debugger if the expression
+**      evaluates to false.  In retail mode this macro does nothing.
+**
+**  ARGUMENTS:
+**
+**      exp     Expression to evaluate.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+#   define _gcmASSERT(prefix, exp) \
+        do \
+        { \
+            if (!(exp)) \
+            { \
+                prefix##TRACE(gcvLEVEL_ERROR, \
+                              #prefix "ASSERT at %s(%d)", \
+                              __FUNCTION__, __LINE__); \
+                prefix##TRACE(gcvLEVEL_ERROR, \
+                              "(%s)", #exp); \
+                prefix##BREAK(); \
+            } \
+        } \
+        while (gcvFALSE)
+#   define gcmASSERT(exp)           _gcmASSERT(gcm, exp)
+#   define gcmkASSERT(exp)          _gcmASSERT(gcmk, exp)
+#else
+#   define gcmASSERT(exp)
+#   define gcmkASSERT(exp)
+#endif
+
+/*******************************************************************************
+**
+**  gcmSTATIC_ASSERT
+**
+**      Tests a software assertion at compile time. If the specific constant
+**      expression is false, the compiler displays the specified message and
+**      the compilation fails with an error, otherwise the declaration has
+**      no effect.
+**      Static assert is suitable for both user and kernel space.
+**
+**  ARGUMENTS:
+**
+**      exp     Constant expression.
+**      message Error message displayed on assertion failure.
+*/
+#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4))
+#   define gcmSTATIC_ASSERT(constExp, message) \
+        do \
+        { \
+            _Static_assert((constExp), message); \
+        } \
+        while (0)
+
+#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
+#   define gcmSTATIC_ASSERT(constExp, message) \
+        static_assert((constExp), message)
+
+#else
+#   define gcmSTATIC_ASSERT(constExp, message) \
+        do {} while (0)
+#endif
+
+/*******************************************************************************
+**
+**  gcmVERIFY
+**
+**      Verify if an expression returns true.  If the expression does not
+**      evaluates to true, an assertion will happen in debug mode.
+**
+**  ARGUMENTS:
+**
+**      exp     Expression to evaluate.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+#   define gcmVERIFY(exp)           gcmASSERT(exp)
+#   define gcmkVERIFY(exp)          gcmkASSERT(exp)
+#else
+#   define gcmVERIFY(exp)           (void)exp
+#   define gcmkVERIFY(exp)          (void)exp
+#endif
+
+/*******************************************************************************
+**
+**  gcmVERIFY_OK
+**
+**      Verify a fucntion returns gcvSTATUS_OK.  If the function does not return
+**      gcvSTATUS_OK, an assertion will happen in debug mode.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+
+void
+gcoOS_Verify(
+    IN gceSTATUS status
+    );
+
+void
+gckOS_Verify(
+    IN gceSTATUS status
+    );
+
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+#   define gcmVERIFY_OK(func) \
+        do \
+        { \
+            gceSTATUS verifyStatus = func; \
+            gcoOS_Verify(verifyStatus); \
+            if (verifyStatus != gcvSTATUS_OK) \
+            { \
+                gcmTRACE(\
+                    gcvLEVEL_ERROR, \
+                    "gcmVERIFY_OK(%d): function returned %d", \
+                    __LINE__, verifyStatus \
+                    ); \
+            } \
+            gcmASSERT(verifyStatus == gcvSTATUS_OK); \
+        } \
+        while (gcvFALSE)
+#   define gcmkVERIFY_OK(func) \
+        do \
+        { \
+            gceSTATUS verifyStatus = func; \
+            if (verifyStatus != gcvSTATUS_OK) \
+            { \
+                gcmkTRACE(\
+                    gcvLEVEL_ERROR, \
+                    "gcmkVERIFY_OK(%d): function returned %d", \
+                    __LINE__, verifyStatus \
+                    ); \
+            } \
+            gckOS_Verify(verifyStatus); \
+            gcmkASSERT(verifyStatus == gcvSTATUS_OK); \
+        } \
+        while (gcvFALSE)
+#else
+#   define gcmVERIFY_OK(func)       func
+#   define gcmkVERIFY_OK(func)      func
+#endif
+
+gctCONST_STRING
+gcoOS_DebugStatus2Name(
+    gceSTATUS status
+    );
+
+gctCONST_STRING
+gckOS_DebugStatus2Name(
+    gceSTATUS status
+    );
+
+/*******************************************************************************
+**
+**  gcmERR_BREAK
+**
+**      Executes a break statement on error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of gceSTATUS type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _gcmERR_BREAK(prefix, func){ \
+    status = func; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        prefix##PRINT_VERSION(); \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+            #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \
+            status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+        break; \
+    } \
+    do { } while (gcvFALSE); \
+    }
+
+#define _gcmkERR_BREAK(prefix, func){ \
+    status = func; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        prefix##PRINT_VERSION(); \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+            #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \
+            status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+        break; \
+    } \
+    do { } while (gcvFALSE); \
+    }
+
+#define gcmERR_BREAK(func)          _gcmERR_BREAK(gcm, func)
+#define gcmkERR_BREAK(func)         _gcmkERR_BREAK(gcmk, func)
+
+/*******************************************************************************
+**
+**  gcmERR_RETURN
+**
+**      Executes a return on error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of gceSTATUS type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _gcmERR_RETURN(prefix, func) \
+    status = func; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        prefix##PRINT_VERSION(); \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+            #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+            status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+        prefix##FOOTER(); \
+        return status; \
+    } \
+    do { } while (gcvFALSE)
+#define _gcmkERR_RETURN(prefix, func) \
+    status = func; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        prefix##PRINT_VERSION(); \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+            #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+            status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+        prefix##FOOTER(); \
+        return status; \
+    } \
+    do { } while (gcvFALSE)
+#define gcmERR_RETURN(func)         _gcmERR_RETURN(gcm, func)
+#define gcmkERR_RETURN(func)        _gcmkERR_RETURN(gcmk, func)
+
+
+/*******************************************************************************
+**
+**  gcmONERROR
+**
+**      Jump to the error handler in case there is an error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of gceSTATUS type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _gcmONERROR(prefix, func) \
+    do \
+    { \
+        status = func; \
+        if (gcmIS_ERROR(status)) \
+        { \
+            prefix##PRINT_VERSION(); \
+            prefix##TRACE(gcvLEVEL_ERROR, \
+                #prefix "ONERROR: status=%d(%s) @ %s(%d)", \
+                status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+            goto OnError; \
+        } \
+    } \
+    while (gcvFALSE)
+#define _gcmkONERROR(prefix, func) \
+    do \
+    { \
+        status = func; \
+        if (gcmIS_ERROR(status)) \
+        { \
+            prefix##PRINT_VERSION(); \
+            prefix##TRACE(gcvLEVEL_ERROR, \
+                #prefix "ONERROR: status=%d(%s) @ %s(%d)", \
+                status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+            goto OnError; \
+        } \
+    } \
+    while (gcvFALSE)
+#define gcmONERROR(func)            _gcmONERROR(gcm, func)
+#define gcmkONERROR(func)           _gcmkONERROR(gcmk, func)
+
+#define gcmGET_INDEX_SIZE(type, size) \
+    switch (type) \
+    { \
+    case gcvINDEX_8: \
+        size = 1; \
+        break; \
+    case gcvINDEX_16: \
+        size = 2; \
+        break; \
+    case gcvINDEX_32: \
+        size = 4; \
+        break; \
+    default: \
+        gcmONERROR(gcvSTATUS_INVALID_ARGUMENT); \
+    } \
+
+/*******************************************************************************
+**
+**  gcmkSAFECASTSIZET
+**
+**      Check wether value of a gctSIZE_T varible beyond the capability
+**      of 32bits GPU hardware.
+**
+**  ASSUMPTIONS:
+**
+**
+**
+**  ARGUMENTS:
+**
+**      x   A gctUINT32 variable
+**      y   A gctSIZE_T variable
+*/
+#define gcmkSAFECASTSIZET(x, y) \
+    do \
+    { \
+        gctUINT32 tmp = (gctUINT32)(y); \
+        if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \
+        { \
+            gcmkASSERT(tmp <= gcvMAXUINT32); \
+        } \
+        (x) = tmp; \
+    } \
+    while (gcvFALSE)
+
+#define gcmSAFECASTSIZET(x, y) \
+    do \
+    { \
+        gctUINT32 tmp = (gctUINT32)(y); \
+        if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \
+        { \
+            gcmASSERT(tmp <= gcvMAXUINT32); \
+        } \
+        (x) = tmp; \
+    } \
+    while (gcvFALSE)
+
+/*******************************************************************************
+**
+**  gcmkSAFECASTPHYSADDRT
+**
+**      Check whether value of a gctPHYS_ADDR_T variable beyond the capability
+**      of 32bits GPU hardware.
+**
+**  ASSUMPTIONS:
+**
+**
+**
+**  ARGUMENTS:
+**
+**      x   A gctUINT32 variable
+**      y   A gctPHYS_ADDR_T variable
+*/
+#define gcmkSAFECASTPHYSADDRT(x, y) \
+    do \
+    { \
+    gctUINT32 tmp = (gctUINT32)(y); \
+    if (gcmSIZEOF(gctPHYS_ADDR_T) > gcmSIZEOF(gctUINT32)) \
+    { \
+        gcmkASSERT(tmp <= gcvMAXUINT32); \
+    } \
+    (x) = tmp; \
+    } \
+    while (gcvFALSE)
+
+/*******************************************************************************
+**
+**  gcmSAFECASTPHYSADDRT
+**
+**      Check whether value of a gctPHYS_ADDR_T variable beyond the capability
+**      of 32bits GPU hardware.
+**
+**  ASSUMPTIONS:
+**
+**
+**
+**  ARGUMENTS:
+**
+**      x   A gctUINT32 variable
+**      y   A gctPHYS_ADDR_T variable
+*/
+#define gcmSAFECASTPHYSADDRT(x, y) \
+    do \
+    { \
+        gctUINT32 tmp = (gctUINT32)(y); \
+        if (gcmSIZEOF(gctPHYS_ADDR_T) > gcmSIZEOF(gctUINT32)) \
+        { \
+            gcmASSERT(tmp <= gcvMAXUINT32); \
+        } \
+        (x) = tmp; \
+    } \
+    while (gcvFALSE)
+
+/*******************************************************************************
+**
+**  gcmVERIFY_LOCK
+**
+**      Verifies whether the surface is locked.
+**
+**  ARGUMENTS:
+**
+**      surfaceInfo Pointer to the surface iniformational structure.
+*/
+#define gcmVERIFY_LOCK(surfaceInfo) \
+    if (!surfaceInfo->node.valid) \
+    { \
+        gcmONERROR(gcvSTATUS_MEMORY_UNLOCKED); \
+    } \
+
+/*******************************************************************************
+**
+**  gcmVERIFY_NODE_LOCK
+**
+**      Verifies whether the surface node is locked.
+**
+**  ARGUMENTS:
+**
+**      surfaceInfo Pointer to the surface iniformational structure.
+*/
+#define gcmVERIFY_NODE_LOCK(surfaceNode) \
+    if (!(surfaceNode)->valid) \
+    { \
+        status = gcvSTATUS_MEMORY_UNLOCKED; \
+        break; \
+    } \
+    do { } while (gcvFALSE)
+
+/*******************************************************************************
+**
+**  gcmBADOBJECT_BREAK
+**
+**      Executes a break statement on bad object.
+**
+**  ARGUMENTS:
+**
+**      obj     Object to test.
+**      t       Expected type of the object.
+*/
+#define gcmBADOBJECT_BREAK(obj, t) \
+    if ((obj == gcvNULL) \
+    ||  (((gcsOBJECT *)(obj))->type != t) \
+    ) \
+    { \
+        status = gcvSTATUS_INVALID_OBJECT; \
+        break; \
+    } \
+    do { } while (gcvFALSE)
+
+/*******************************************************************************
+**
+**  gcmCHECK_STATUS
+**
+**      Executes a break statement on error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of gceSTATUS type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _gcmCHECK_STATUS(prefix, func) \
+    do \
+    { \
+        last = func; \
+        if (gcmIS_ERROR(last)) \
+        { \
+            prefix##TRACE(gcvLEVEL_ERROR, \
+                #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \
+                last, gcoOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \
+            status = last; \
+        } \
+    } \
+    while (gcvFALSE)
+#define _gcmkCHECK_STATUS(prefix, func) \
+    do \
+    { \
+        last = func; \
+        if (gcmIS_ERROR(last)) \
+        { \
+            prefix##TRACE(gcvLEVEL_ERROR, \
+                #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \
+                last, gckOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \
+            status = last; \
+        } \
+    } \
+    while (gcvFALSE)
+#define gcmCHECK_STATUS(func)       _gcmCHECK_STATUS(gcm, func)
+#define gcmkCHECK_STATUS(func)      _gcmkCHECK_STATUS(gcmk, func)
+
+/*******************************************************************************
+**
+**  gcmVERIFY_ARGUMENT
+**
+**      Assert if an argument does not apply to the specified expression.  If
+**      the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be
+**      returned from the current function.  In retail mode this macro does
+**      nothing.
+**
+**  ARGUMENTS:
+**
+**      arg     Argument to evaluate.
+*/
+#   define _gcmVERIFY_ARGUMENT(prefix, arg) \
+       do \
+       { \
+           if (!(arg)) \
+           { \
+               prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \
+               prefix##ASSERT(arg); \
+               prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \
+               return gcvSTATUS_INVALID_ARGUMENT; \
+           } \
+       } \
+       while (gcvFALSE)
+#   define gcmVERIFY_ARGUMENT(arg)     _gcmVERIFY_ARGUMENT(gcm, arg)
+#   define gcmkVERIFY_ARGUMENT(arg)    _gcmVERIFY_ARGUMENT(gcmk, arg)
+
+/*******************************************************************************
+**
+**  gcmDEBUG_VERIFY_ARGUMENT
+**
+**      Works just like gcmVERIFY_ARGUMENT, but is only valid in debug mode.
+**      Use this to verify arguments inside non-public API functions.
+*/
+#if gcdDEBUG
+#   define gcmDEBUG_VERIFY_ARGUMENT(arg)    _gcmVERIFY_ARGUMENT(gcm, arg)
+#   define gcmkDEBUG_VERIFY_ARGUMENT(arg)   _gcmkVERIFY_ARGUMENT(gcm, arg)
+#else
+#   define gcmDEBUG_VERIFY_ARGUMENT(arg)
+#   define gcmkDEBUG_VERIFY_ARGUMENT(arg)
+#endif
+
+/*******************************************************************************
+**
+**  gcmVERIFY_ARGUMENT_RETURN
+**
+**      Assert if an argument does not apply to the specified expression.  If
+**      the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be
+**      returned from the current function.  In retail mode this macro does
+**      nothing.
+**
+**  ARGUMENTS:
+**
+**      arg     Argument to evaluate.
+*/
+#   define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \
+       do \
+       { \
+           if (!(arg)) \
+           { \
+               prefix##TRACE(gcvLEVEL_ERROR, \
+                             #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \
+               prefix##ASSERT(arg); \
+               prefix##FOOTER_ARG("value=%d", value); \
+               return value; \
+           } \
+       } \
+       while (gcvFALSE)
+#   define gcmVERIFY_ARGUMENT_RETURN(arg, value) \
+                _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value)
+#   define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \
+                _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value)
+
+#define MAX_LOOP_COUNT 0x7FFFFFFF
+
+/******************************************************************************\
+****************************** User Debug Option ******************************
+\******************************************************************************/
+
+typedef struct _gcsUSER_DEBUG_OPTION
+{
+    gceDEBUG_MSG        debugMsg;
+}
+gcsUSER_DEBUG_OPTION;
+
+gcsUSER_DEBUG_OPTION *
+gcoHAL_GetUserDebugOption(
+    void
+    );
+
+#if gcdHAS_ELLIPSIS
+#define gcmUSER_DEBUG_MSG(level, ...) \
+    do \
+    { \
+        if (level <= gcoHAL_GetUserDebugOption()->debugMsg) \
+        { \
+            gcoOS_Print(__VA_ARGS__); \
+        } \
+    } while (gcvFALSE)
+
+#define gcmUSER_DEBUG_ERROR_MSG(...)   gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_ERROR, "Error: " __VA_ARGS__)
+#define gcmUSER_DEBUG_WARNING_MSG(...) gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_WARNING, "Warring: " __VA_ARGS__)
+#else
+#define gcmUSER_DEBUG_MSG
+#define gcmUSER_DEBUG_ERROR_MSG
+#define gcmUSER_DEBUG_WARNING_MSG
+#endif
+
+/*******************************************************************************
+**
+**  A set of macros to aid state loading.
+**
+**  ARGUMENTS:
+**
+**      CommandBuffer   Pointer to a gcoCMDBUF object.
+**      StateDelta      Pointer to a gcsSTATE_DELTA state delta structure.
+**      Memory          Destination memory pointer of gctUINT32_PTR type.
+**      PartOfContext   Whether or not the state is a part of the context.
+**      FixedPoint      Whether or not the state is of the fixed point format.
+**      Count           Number of consecutive states to be loaded.
+**      Address         State address.
+**      Data            Data to be set to the state.
+*/
+
+/*----------------------------------------------------------------------------*/
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+
+#   define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) \
+        CommandBuffer->lastLoadStatePtr     = gcmPTR_TO_UINT64(Memory); \
+        CommandBuffer->lastLoadStateAddress = Address; \
+        CommandBuffer->lastLoadStateCount   = Count
+
+#   define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) \
+        gcmASSERT(\
+            (gctUINT) (Memory  - gcmUINT64_TO_TYPE(CommandBuffer->lastLoadStatePtr, gctUINT32_PTR) - 1) \
+            == \
+            (gctUINT) (Address - CommandBuffer->lastLoadStateAddress) \
+            ); \
+        \
+        gcmASSERT(CommandBuffer->lastLoadStateCount > 0); \
+        \
+        CommandBuffer->lastLoadStateCount -= 1
+
+#   define gcmVERIFYLOADSTATEDONE(CommandBuffer) \
+        gcmASSERT(CommandBuffer->lastLoadStateCount == 0);
+
+#   define gcmDEFINELOADSTATEBASE() \
+        gctUINT32_PTR LoadStateBase;
+
+#   define gcmSETLOADSTATEBASE(CommandBuffer, OutSide) \
+        if (OutSide) \
+        {\
+            LoadStateBase = (gctUINT32_PTR)*OutSide; \
+        }\
+        else\
+        {\
+            LoadStateBase = (gctUINT_PTR)CommandBuffer->buffer;\
+        }
+
+
+#   define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory) \
+        gcmASSERT(((Memory - LoadStateBase) & 1) == 0);
+
+#   define gcmUNSETLOADSTATEBASE() \
+        LoadStateBase = LoadStateBase;
+
+#else
+
+#   define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count)
+#   define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address)
+#   define gcmVERIFYLOADSTATEDONE(CommandBuffer)
+
+#   define gcmDEFINELOADSTATEBASE()
+#   define gcmSETLOADSTATEBASE(CommandBuffer, OutSide)
+#   define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory)
+#   define gcmUNSETLOADSTATEBASE()
+
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+/* This style of dump is deprecated. */
+#   define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data)
+
+#define gcmDEFINESTATEBUFFER(CommandBuffer, StateDelta, Memory, ReserveSize) \
+    gctSIZE_T ReserveSize; \
+    gcoCMDBUF CommandBuffer; \
+    gctUINT32_PTR Memory; \
+    gcsSTATE_DELTA_PTR StateDelta; \
+    gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+#define gcmBEGINSTATEBUFFER(Hardware, CommandBuffer, StateDelta, Memory, ReserveSize) \
+{ \
+    gcmONERROR(gcoBUFFER_Reserve(\
+        Hardware->engine[CurrentEngine].buffer, ReserveSize, gcvTRUE, gcvCOMMAND_3D, &CommandBuffer \
+        )); \
+    \
+    Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \
+    \
+    StateDelta = Hardware->delta; \
+    \
+}
+
+#define gcmENDSTATEBUFFER(Hardware, CommandBuffer, Memory, ReserveSize) \
+{ \
+    gcmASSERT(\
+        gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT8_PTR) + ReserveSize \
+        == \
+         (gctUINT8_PTR) Memory \
+        ); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, Count) \
+{ \
+    gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \
+    gcmASSERT((gctUINT32)Count <= 1024); \
+    \
+    gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+    \
+    gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count); \
+    \
+    *Memory++ \
+        = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \
+}
+
+#define gcmENDSTATEBATCH(CommandBuffer, Memory) \
+{ \
+    gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+    \
+    gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+    \
+    gcmSAFECASTSIZET(__temp_data32__, Data); \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcoHARDWARE_UpdateDelta(\
+        StateDelta, Address, 0, __temp_data32__ \
+        ); \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Mask, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcoHARDWARE_UpdateDelta(\
+        StateDelta, Address, Mask, __temp_data32__ \
+        ); \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+
+#define gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \
+}
+
+#define gcmSETFILLER(CommandBuffer, Memory) \
+{ \
+    gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+    \
+    *(gctUINT32_PTR)Memory = 0x18000000; \
+    Memory += 1; \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSINGLESTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                          Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Data); \
+    gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                          Address, Mask, Data) \
+{ \
+    gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Mask, Data); \
+    gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+
+#define gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                              Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data); \
+    gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+
+
+#define gcmSETSEMASTALLPIPE(StateDelta, CommandBuffer, Memory, Data) \
+{ \
+    gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, gcvFALSE, 0x0E02, Data); \
+    \
+    *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+    \
+    *Memory++ = Data; \
+    \
+    gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \
+        gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \
+        gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \
+}
+
+/*******************************************************************************
+**
+**  gcmSETSTARTDECOMMAND
+**
+**      Form a START_DE command.
+**
+**  ARGUMENTS:
+**
+**      Memory          Destination memory pointer of gctUINT32_PTR type.
+**      Count           Number of the rectangles.
+*/
+
+#define gcmSETSTARTDECOMMAND(Memory, Count) \
+{ \
+    *Memory++ \
+        = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \
+        | gcmSETFIELD     (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \
+        | gcmSETFIELD     (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \
+    \
+    *Memory++ = 0xDEADDEED; \
+}
+
+/*****************************************
+** Temp command buffer macro
+*/
+#define gcmDEFINESTATEBUFFER_NEW(CommandBuffer, StateDelta, Memory) \
+    gcmDEFINELOADSTATEBASE() \
+    gcsTEMPCMDBUF CommandBuffer = gcvNULL; \
+    gctUINT32_PTR Memory; \
+    gcsSTATE_DELTA_PTR StateDelta; \
+    gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+
+#define gcmBEGINSTATEBUFFER_NEW(Hardware, CommandBuffer, StateDelta, Memory, OutSide) \
+{ \
+    if (OutSide) \
+    {\
+        Memory = (gctUINT32_PTR)*OutSide; \
+    }\
+    else \
+    {\
+        gcmONERROR(gcoBUFFER_StartTEMPCMDBUF(\
+            Hardware->engine[CurrentEngine].buffer, Hardware->engine[CurrentEngine].queue, &CommandBuffer \
+            ));\
+        \
+        Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \
+        \
+    }\
+    StateDelta = Hardware->tempDelta; \
+    \
+    gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\
+}
+
+#define gcmENDSTATEBUFFER_NEW(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+    if (OutSide) \
+    {\
+        *OutSide = Memory; \
+    }\
+    else \
+    {\
+        CommandBuffer->currentByteSize = (gctUINT32)((gctUINT8_PTR)Memory -  \
+                                         (gctUINT8_PTR)CommandBuffer->buffer); \
+        \
+        gcmONERROR(gcoBUFFER_EndTEMPCMDBUF(Hardware->engine[CurrentEngine].buffer, gcvFALSE));\
+        if (Hardware->constructType != gcvHARDWARE_2D) \
+        { \
+            gcoHARDWARE_UpdateTempDelta(Hardware);\
+        } \
+    }\
+    gcmUNSETLOADSTATEBASE()\
+}
+
+#define gcmDEFINECTRLSTATEBUFFER(CommandBuffer, Memory)                         \
+    gcmDEFINELOADSTATEBASE()                                                    \
+    gcsTEMPCMDBUF CommandBuffer = gcvNULL;                                      \
+    gctUINT32_PTR Memory;                                                       \
+    gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+#define gcmBEGINCTRLSTATEBUFFER(Hardware, CommandBuffer, Memory, OutSide)       \
+{                                                                               \
+    if (OutSide)                                                                \
+    {                                                                           \
+        Memory = (gctUINT32_PTR)*OutSide;                                       \
+    }                                                                           \
+    else                                                                        \
+    {                                                                           \
+        gcmONERROR(gcoBUFFER_StartTEMPCMDBUF(\
+            Hardware->engine[CurrentEngine].buffer, \
+            Hardware->engine[CurrentEngine].queue, &CommandBuffer               \
+            ));                                                                 \
+                                                                                \
+        Memory = (gctUINT32_PTR)(CommandBuffer->buffer);                        \
+    }                                                                           \
+    gcmSETLOADSTATEBASE(CommandBuffer,OutSide);                                 \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, Count) \
+{ \
+    gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory);\
+    gcmASSERT((gctUINT32)Count <= 1024); \
+    \
+    *Memory++ \
+        = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \
+        | gcmSETFIELD     (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \
+}
+
+#define gcmENDSTATEBATCH_NEW(CommandBuffer, Memory) \
+    gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory);
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmSAFECASTSIZET(__temp_data32__, Data); \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcoHARDWARE_UpdateDelta(\
+        StateDelta, Address, 0, __temp_data32__ \
+        ); \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                                Address, Mask, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcoHARDWARE_UpdateDelta(\
+        StateDelta, Address, Mask, __temp_data32__ \
+        ); \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+
+#define gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \
+}
+
+#define gcmSETFILLER_NEW(CommandBuffer, Memory) \
+{ \
+    *(gctUINT32_PTR)Memory = 0x18000000; \
+    Memory += 1; \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSINGLESTATE_DUMMY(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                                Address, Data) \
+ { \
+    gctUINT32 __temp_data32__; \
+    __temp_data32__ = Data ; \
+    gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory); \
+    *Memory++ = \
+        (gctUINT32)(0) | (0xFFFF & Address); \
+    *Memory++ = __temp_data32__; \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                              Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Data); \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                                      Address, Mask, Data) \
+{ \
+    gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Mask, Data); \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+
+#define gcmSETSINGLECTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                              Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data); \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+
+
+#define gcmSETSEMASTALLPIPE_NEW(StateDelta, CommandBuffer, Memory, Data) \
+{ \
+    gcmSETSINGLECTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, gcvFALSE, 0x0E02, Data); \
+    \
+    *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+    \
+    *Memory++ = Data; \
+    \
+    gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \
+        gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \
+        gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \
+}
+
+#define gcmSETSTARTDECOMMAND_NEW(CommandBuffer, Memory, Count) \
+{ \
+    *Memory++ \
+        = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \
+        | gcmSETFIELD     (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \
+        | gcmSETFIELD     (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \
+    \
+    *Memory++ = 0xDEADDEED; \
+    \
+}
+
+#define gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                                Address, Mask, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSINGLESTATE_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                              Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Data); \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                                      Address, Mask, Data) \
+{ \
+    gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Mask, Data); \
+    gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+    \
+    gcmSAFECASTSIZET(__temp_data32__, Data); \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                        Address, Mask, Data) \
+{ \
+    gctUINT32 __temp_data32__; \
+    \
+    gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+    \
+    __temp_data32__ = Data; \
+    \
+    *Memory++ = __temp_data32__; \
+    \
+    gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+}
+
+#define gcmSETSINGLESTATE_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                          Address, Data) \
+{ \
+    gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Data); \
+    gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                          Address, Mask, Data) \
+{ \
+    gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+    gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+                    Address, Mask, Data); \
+    gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmDEFINESTATEBUFFER_NEW_FAST(CommandBuffer, Memory) \
+    gcmDEFINELOADSTATEBASE() \
+    gcsTEMPCMDBUF CommandBuffer = gcvNULL; \
+    gctUINT32_PTR Memory;
+
+#define gcmDEFINESTATEBUFFER_FAST(CommandBuffer, Memory, ReserveSize) \
+    gctSIZE_T ReserveSize; \
+    gcoCMDBUF CommandBuffer; \
+    gctUINT32_PTR Memory;
+
+#define gcmBEGINSTATEBUFFER_FAST(Hardware, CommandBuffer, Memory, ReserveSize) \
+{ \
+    gcmONERROR(gcoBUFFER_Reserve(\
+    Hardware->engine[gcvENGINE_RENDER].buffer, ReserveSize, gcvTRUE, &CommandBuffer \
+        )); \
+    \
+    Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \
+    \
+}
+
+#define gcmBEGINSTATEBUFFER_NEW_FAST(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+    if (OutSide) \
+    {\
+        Memory = (gctUINT32_PTR)*OutSide; \
+    }\
+    else \
+    {\
+        gcmONERROR(gcoBUFFER_StartTEMPCMDBUF(\
+            Hardware->engine[gcvENGINE_RENDER].buffer, Hardware->engine[gcvENGINE_RENDER].queue, &CommandBuffer \
+            ));\
+        \
+        Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \
+        \
+    }\
+    \
+    gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\
+}
+
+#define gcmENDSTATEBUFFER_NEW_FAST(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+    if (OutSide) \
+    {\
+        *OutSide = Memory; \
+    }\
+    else \
+    {\
+        CommandBuffer->currentByteSize = (gctUINT32)((gctUINT8_PTR)Memory -  \
+                                         (gctUINT8_PTR)CommandBuffer->buffer); \
+        \
+        gcmONERROR(gcoBUFFER_EndTEMPCMDBUF(Hardware->engine[gcvENGINE_RENDER].buffer, gcvFALSE));\
+    }\
+    gcmUNSETLOADSTATEBASE()\
+}
+
+/*******************************************************************************
+**
+**  gcmCONFIGUREUNIFORMS
+**
+**      Configure uniforms according to chip and numConstants.
+*/
+#if !gcdENABLE_UNIFIED_CONSTANT
+#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, NumConstants, \
+             UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \
+{ \
+    if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+        ConstMax     = 320; \
+    } \
+    else if (NumConstants == 320) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+        ConstMax     = 320; \
+    } \
+    /* All GC1000 series chips can only support 64 uniforms for ps on non-unified const mode. */ \
+    else if (NumConstants > 256 && ChipModel == gcv1000) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+        ConstMax     = 320; \
+    } \
+    else if (NumConstants > 256) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 256; \
+        PsConstMax   = 256; \
+        ConstMax     = 512; \
+    } \
+    else if (NumConstants == 256) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 256; \
+        PsConstMax   = 256; \
+        ConstMax     = 512; \
+    } \
+    else \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 168; \
+        PsConstMax   = 64; \
+        ConstMax     = 232; \
+    } \
+}
+#else
+#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, Halti5Avail, SmallBatch, NumConstants, \
+             UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \
+{ \
+    if (NumConstants > 256) \
+    { \
+        UnifiedConst = gcvTRUE; \
+        if (SmallBatch) \
+        { \
+            VsConstBase  = 0xD000; \
+            PsConstBase  = 0xD000; \
+        } \
+        else if (Halti5Avail) \
+        { \
+            VsConstBase  = 0xD000; \
+            PsConstBase  = 0xD800; \
+        } \
+        else \
+        {\
+            VsConstBase  = 0xC000; \
+            PsConstBase  = 0xC000; \
+        }\
+        if ((ChipModel == gcv880) && ((ChipRevision & 0xfff0) == 0x5120)) \
+        { \
+            VsConstMax   = 512; \
+            PsConstMax   = 64; \
+            ConstMax     = 576; \
+        } \
+        else \
+        { \
+            VsConstMax   = gcmMIN(512, NumConstants - 64); \
+            PsConstMax   = gcmMIN(512, NumConstants - 64); \
+            ConstMax     = NumConstants; \
+        } \
+    } \
+    else if (NumConstants == 256) \
+    { \
+        if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+        { \
+            UnifiedConst = gcvFALSE; \
+            VsConstBase  = 0x1400; \
+            PsConstBase  = 0x1C00; \
+            VsConstMax   = 256; \
+            PsConstMax   = 64; \
+            ConstMax     = 320; \
+        } \
+        else \
+        { \
+            UnifiedConst = gcvFALSE; \
+            VsConstBase  = 0x1400; \
+            PsConstBase  = 0x1C00; \
+            VsConstMax   = 256; \
+            PsConstMax   = 256; \
+            ConstMax     = 512; \
+        } \
+    } \
+    else \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstBase  = 0x1400; \
+        PsConstBase  = 0x1C00; \
+        VsConstMax   = 168; \
+        PsConstMax   = 64; \
+        ConstMax     = 232; \
+    } \
+}
+#endif
+
+/*******************************************************************************
+**
+**  gcmCONFIGUREUNIFORMS2
+**  only fix clang build error
+**
+**      Configure uniforms according to chip and numConstants.
+*/
+#if !gcdENABLE_UNIFIED_CONSTANT
+#define gcmCONFIGUREUNIFORMS2(ChipModel, ChipRevision, NumConstants, \
+             UnifiedConst, VsConstMax, PsConstMax) \
+{ \
+    if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+    } \
+    else if (NumConstants == 320) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+    } \
+    /* All GC1000 series chips can only support 64 uniforms for ps on non-unified const mode. */ \
+    else if (NumConstants > 256 && ChipModel == gcv1000) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 256; \
+        PsConstMax   = 64; \
+    } \
+    else if (NumConstants > 256) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 256; \
+        PsConstMax   = 256; \
+    } \
+    else if (NumConstants == 256) \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 256; \
+        PsConstMax   = 256; \
+    } \
+    else \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 168; \
+        PsConstMax   = 64; \
+    } \
+}
+#else
+#define gcmCONFIGUREUNIFORMS2(ChipModel, ChipRevision, Halti5Avail, SmallBatch, NumConstants, \
+             UnifiedConst, VsConstMax, PsConstMax) \
+{ \
+    if (NumConstants > 256) \
+    { \
+        UnifiedConst = gcvTRUE; \
+        if ((ChipModel == gcv880) && ((ChipRevision & 0xfff0) == 0x5120)) \
+        { \
+            VsConstMax   = 512; \
+            PsConstMax   = 64; \
+        } \
+        else \
+        { \
+            VsConstMax   = gcmMIN(512, NumConstants - 64); \
+            PsConstMax   = gcmMIN(512, NumConstants - 64); \
+        } \
+    } \
+    else if (NumConstants == 256) \
+    { \
+        if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+        { \
+            UnifiedConst = gcvFALSE; \
+            VsConstMax   = 256; \
+            PsConstMax   = 64; \
+        } \
+        else \
+        { \
+            UnifiedConst = gcvFALSE; \
+            VsConstMax   = 256; \
+            PsConstMax   = 256; \
+        } \
+    } \
+    else \
+    { \
+        UnifiedConst = gcvFALSE; \
+        VsConstMax   = 168; \
+        PsConstMax   = 64; \
+    } \
+}
+#endif
+
+#define gcmAnyTileStatusEnableForFullMultiSlice(SurfView, anyTsEnableForMultiSlice)\
+{\
+    gctUINT i = 0; \
+    for (; i < (SurfView->surf->requestD); i++)\
+    {\
+        if ((SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) && \
+            (SurfView->surf->tileStatusDisabled[i] == gcvFALSE))\
+        {\
+            *anyTsEnableForMultiSlice = gcvTRUE;\
+            break;\
+        }\
+    }\
+}\
+
+#define gcmAnyTileStatusEnableForMultiSlice(SurfView, anyTsEnableForMultiSlice)\
+{\
+    gctUINT i = SurfView->firstSlice; \
+    for (; i < (SurfView->firstSlice + SurfView->numSlices); i++)\
+    {\
+        if ((SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) && \
+            (SurfView->surf->tileStatusDisabled[i] == gcvFALSE))\
+        {\
+            *anyTsEnableForMultiSlice = gcvTRUE;\
+            break;\
+        }\
+    }\
+}\
+
+#define gcmCanTileStatusEnabledForMultiSlice(SurfView, canTsEnabled)\
+{\
+    if (SurfView->numSlices > 1)\
+    {\
+        if (SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) \
+        {\
+            gctUINT i = 0;\
+            for (; i < SurfView->numSlices; i++)\
+            {\
+                if (SurfView->surf->tileStatusDisabled[i] == gcvTRUE)\
+                {\
+                    *canTsEnabled = gcvFALSE;\
+                    break;\
+                }\
+                if (SurfView->surf->fcValue[i] != SurfView->surf->fcValue[0])\
+                {\
+                    *canTsEnabled = gcvFALSE;\
+                    break;\
+                }\
+                \
+                if (SurfView->surf->fcValueUpper[i] != SurfView->surf->fcValueUpper[0])\
+                {\
+                    *canTsEnabled = gcvFALSE;\
+                    break;\
+                }\
+            }\
+        }\
+        else\
+        {\
+            *canTsEnabled = gcvFALSE;\
+        }\
+    }\
+    else\
+    {\
+        if ((SurfView->surf->tileStatusNode.pool == gcvPOOL_UNKNOWN) || (SurfView->surf->tileStatusDisabled[SurfView->firstSlice] == gcvTRUE))\
+            {\
+                *canTsEnabled = gcvFALSE;\
+            }\
+    }\
+}\
+
+
+#define gcmCONFIGUSC(prefix, featureUSC, featureSeparateLS, featureComputeOnly, \
+    featureTS, featureGS, featureUSCFullCacheFix, featureL1CacheSize, featureUSCMaxPages, \
+    attribCacheRatio, L1CacheRatio) \
+{ \
+    attribCacheRatio = 0x2; \
+    \
+    if (featureUSC) \
+    { \
+        if (featureSeparateLS) \
+        { \
+            L1CacheRatio = 0x0; \
+        } \
+        else \
+        { \
+            gctUINT L1cacheSize; \
+            \
+            if (featureComputeOnly) \
+            { \
+                L1cacheSize = featureL1CacheSize; \
+            } \
+            else \
+            { \
+                gctUINT attribBufSizeInKB; \
+                if (featureTS) \
+                { \
+                    /* GS/TS must be bundled. */ \
+                    prefix##ASSERT(featureGS); \
+                    featureGS = featureGS; \
+                    attribBufSizeInKB = 42; \
+                } \
+                else \
+                { \
+                    prefix##ASSERT(!featureGS); \
+                    attribBufSizeInKB = 8; \
+                } \
+                if (attribBufSizeInKB < featureUSCMaxPages) \
+                { \
+                    L1cacheSize = featureUSCMaxPages - attribBufSizeInKB; \
+                } \
+                else \
+                { \
+                    attribBufSizeInKB -= 2; \
+                    L1cacheSize = 2; \
+                } \
+            } \
+            prefix##ASSERT(L1cacheSize); \
+            if (L1cacheSize >= featureL1CacheSize) \
+            { \
+                L1CacheRatio = 0x0; \
+                prefix##ASSERT(featureUSCFullCacheFix); \
+                featureUSCFullCacheFix = featureUSCFullCacheFix; \
+            } \
+            else \
+            { \
+                static const gctINT s_uscCacheRatio[] = \
+                { \
+                    100000,/* 1.0f */     \
+                    50000, /* 0.5f */     \
+                    25000, /* 0.25f */    \
+                    12500, /* 0.125f */   \
+                    62500, /* 0.0625f */  \
+                    3125, /* 0.03125f */ \
+                    75000, /* 0.75f */    \
+                    0, /*0.0f */      \
+                }; \
+                gctINT maxL1cacheSize = L1cacheSize * 100000; \
+                gctINT delta = 2147483647; /* start with very big delta */ \
+                gctINT i = 0; \
+                gctINT curIndex = -1; \
+                for (; i < gcmCOUNTOF(s_uscCacheRatio); ++i) \
+                { \
+                    gctINT curL1cacheSize = featureL1CacheSize * s_uscCacheRatio[i]; \
+                  \
+                    if ((maxL1cacheSize >= curL1cacheSize) && \
+                        ((maxL1cacheSize - curL1cacheSize) < delta)) \
+                    { \
+                        curIndex = i; \
+                        delta = maxL1cacheSize - curL1cacheSize; \
+                    } \
+                } \
+                prefix##ASSERT(-1 != curIndex); \
+                L1CacheRatio = curIndex; \
+            } \
+        } \
+    } \
+} \
+
+#define gcmCONFIGUSC2(prefix, featureUSC, featureSeparateLS, featureComputeOnly, \
+    featureTS, featureL1CacheSize, featureUSCMaxPages, \
+    attribCacheRatio, L1CacheRatio) \
+{ \
+    attribCacheRatio = 0x2; \
+    \
+    if (featureUSC) \
+    { \
+        if (featureSeparateLS) \
+        { \
+            L1CacheRatio = 0x0; \
+        } \
+        else \
+        { \
+            gctUINT L1cacheSize; \
+            \
+            if (featureComputeOnly) \
+            { \
+                L1cacheSize = featureL1CacheSize; \
+            } \
+            else \
+            { \
+                gctUINT attribBufSizeInKB; \
+                if (featureTS) \
+                { \
+                    /* GS/TS must be bundled. */ \
+                    attribBufSizeInKB = 42; \
+                } \
+                else \
+                { \
+                    attribBufSizeInKB = 8; \
+                } \
+                if (attribBufSizeInKB < featureUSCMaxPages) \
+                { \
+                    L1cacheSize = featureUSCMaxPages - attribBufSizeInKB; \
+                } \
+                else \
+                { \
+                    attribBufSizeInKB -= 2; \
+                    L1cacheSize = 2; \
+                } \
+            } \
+            prefix##ASSERT(L1cacheSize); \
+            if (L1cacheSize >= featureL1CacheSize) \
+            { \
+                L1CacheRatio = 0x0; \
+            } \
+            else \
+            { \
+                static const gctINT s_uscCacheRatio[] = \
+                { \
+                    100000,/* 1.0f */     \
+                    50000, /* 0.5f */     \
+                    25000, /* 0.25f */    \
+                    12500, /* 0.125f */   \
+                    62500, /* 0.0625f */  \
+                    3125, /* 0.03125f */ \
+                    75000, /* 0.75f */    \
+                    0, /*0.0f */      \
+                }; \
+                gctINT maxL1cacheSize = L1cacheSize * 100000; \
+                gctINT delta = 2147483647; /* start with very big delta */ \
+                gctINT i = 0; \
+                gctINT curIndex = -1; \
+                for (; i < gcmCOUNTOF(s_uscCacheRatio); ++i) \
+                { \
+                    gctINT curL1cacheSize = featureL1CacheSize * s_uscCacheRatio[i]; \
+                  \
+                    if ((maxL1cacheSize >= curL1cacheSize) && \
+                        ((maxL1cacheSize - curL1cacheSize) < delta)) \
+                    { \
+                        curIndex = i; \
+                        delta = maxL1cacheSize - curL1cacheSize; \
+                    } \
+                } \
+                prefix##ASSERT(-1 != curIndex); \
+                L1CacheRatio = curIndex; \
+            } \
+        } \
+    } \
+} \
+
+#if VIVANTE_PROFILER_SYSTEM_MEMORY
+typedef struct _memory_profile_info
+{
+    struct
+    {
+        gctUINT64     currentSize;
+        gctUINT64     peakSize;
+        gctUINT64     total_allocate;
+        gctUINT64     total_free;
+        gctUINT32     total_allocateCount;
+        gctUINT32     total_freeCount;
+    } system_memory, gpu_memory;
+} memory_profile_info;
+
+gceSTATUS
+gcoOS_GetMemoryProfileInfo(
+    size_t                      size,
+    struct _memory_profile_info *info
+    );
+
+gceSTATUS gcoOS_DumpMemoryProfile(void);
+gceSTATUS gcoOS_InitMemoryProfile(void);
+gceSTATUS gcoOS_DeInitMemoryProfile(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_base_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_debug_zones.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_debug_zones.h
@@ -0,0 +1,329 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_debug_zones_h_
+#define __gc_hal_debug_zones_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+ ************************ Debug Zone Pattern Summary ***************************
+ * A debug zone is an unsigned integer of 32 bit (Bit 31- Bit 0).              *
+ * Bit 31 to 28 defines API, which is 0 for HAL API and has value of 1 - 14    *
+ * for Khronos API. Value 15 (0xF) is reserved for gcdZONE_NONE.               *
+ * Bit 27 to 0 defines subzones of each API. Value 0xFFFFFFF is resevered for  *
+ * gcdZONE_ALL.                                                                *
+ *                                                                             *
+\******************************************************************************/
+
+/* Retrieve API bits 31 to 28 */
+#define gcmZONE_GET_API(zone)             ((zone) >> 28)
+
+/* Retrieve Subzone bits 27 to 0 */
+#define gcmZONE_GET_SUBZONES(zone)        ((zone) << 4)
+
+/******************************************************************************\
+******************************** HAL Zone **************************************
+\******************************************************************************/
+
+#define gcdZONE_API_HAL              ((gctUINT32) 0  << 28)
+
+/******************************************************************************\
+******************************** HAL Subzones **********************************
+\******************************************************************************/
+
+/* Subzones Kernel and User have in common */
+#define gcvZONE_OS              (1 << 0)
+#define gcvZONE_HARDWARE        (1 << 1)
+#define gcvZONE_HEAP            (1 << 2)
+#define gcvZONE_SIGNAL          (1 << 3)
+
+/* Subzones of HAL Kernel */
+#define gcvZONE_KERNEL          (1 << 4)
+#define gcvZONE_VIDMEM          (1 << 5)
+#define gcvZONE_COMMAND         (1 << 6)
+#define gcvZONE_DRIVER          (1 << 7)
+#define gcvZONE_CMODEL          (1 << 8)
+#define gcvZONE_MMU             (1 << 9)
+#define gcvZONE_EVENT           (1 << 10)
+#define gcvZONE_DEVICE          (1 << 11)
+#define gcvZONE_DATABASE        (1 << 12)
+#define gcvZONE_INTERRUPT       (1 << 13)
+#define gcvZONE_POWER           (1 << 14)
+#define gcvZONE_ASYNC_COMMAND   (1 << 15)
+#define gcvZONE_ALLOCATOR       (1 << 16)
+
+/* Subzones of HAL User */
+#define gcdZONE_HAL_API         (1 << 4)
+#define gcdZONE_BUFFER          (1 << 5)
+#define gcdZONE_VGBUFFER        (1 << 6)
+#define gcdZONE_SURFACE         (1 << 7)
+#define gcdZONE_INDEX           (1 << 8)
+#define gcdZONE_STREAM          (1 << 9)
+#define gcdZONE_TEXTURE         (1 << 10)
+#define gcdZONE_2D              (1 << 11)
+#define gcdZONE_3D              (1 << 12)
+#define gcdZONE_COMPILER        (1 << 13)
+#define gcdZONE_MEM             (1 << 14)
+#define gcdZONE_VERTEXARRAY     (1 << 15)
+#define gcdZONE_CL              (1 << 16)
+#define gcdZONE_VG              (1 << 17)
+#define gcdZONE_VX              (1 << 18)
+#define gcdZONE_UTILITY         (1 << 19)
+#define gcdZONE_RECT            (1 << 20)
+#define gcdZONE_BUFOBJ          (1 << 21)
+#define gcdZONE_PROFILER        (1 << 22)
+#define gcdZONE_SHADER          (1 << 23)
+
+
+/******************************************************************************\
+******************************** Khronos API Zones *****************************
+\******************************************************************************/
+
+#define gcdZONE_API_EGL              ((gctUINT32) 1  << 28)
+#define gcdZONE_API_ES11             ((gctUINT32) 2  << 28)
+#define gcdZONE_API_ES30             ((gctUINT32) 3  << 28)
+#define gcdZONE_API_GL40             ((gctUINT32) 4  << 28)
+#define gcdZONE_API_VG3D             ((gctUINT32) 5  << 28)
+#define gcdZONE_API_CL               ((gctUINT32) 6  << 28)
+#define gcdZONE_API_VX               ((gctUINT32) 7  << 28)
+#define gcdZONE_API_VG               ((gctUINT32) 8  << 28)
+
+/******************************************************************************\
+************************* Subzones of Khronos API Zones ************************
+\******************************************************************************/
+
+/* Subzones of EGL API */
+#define gcdZONE_EGL_API              (gcdZONE_API_EGL | (1 << 0))
+#define gcdZONE_EGL_SURFACE          (gcdZONE_API_EGL | (1 << 1))
+#define gcdZONE_EGL_CONTEXT          (gcdZONE_API_EGL | (1 << 2))
+#define gcdZONE_EGL_CONFIG           (gcdZONE_API_EGL | (1 << 3))
+#define gcdZONE_EGL_OS               (gcdZONE_API_EGL | (1 << 4))  /* unused */
+#define gcdZONE_EGL_IMAGE            (gcdZONE_API_EGL | (1 << 5))
+#define gcdZONE_EGL_SWAP             (gcdZONE_API_EGL | (1 << 6))
+#define gcdZONE_EGL_INIT             (gcdZONE_API_EGL | (1 << 7))
+#define gcdZONE_EGL_SYNC             (gcdZONE_API_EGL | (1 << 8))
+#define gcdZONE_EGL_COMPOSE          (gcdZONE_API_EGL | (1 << 9))  /* unused */
+#define gcdZONE_EGL_RENDER_THREAD    (gcdZONE_API_EGL | (1 << 10)) /* unused */
+
+/* Subzones of ES11 API */
+#define gcdZONE_ES11_BUFFER          (gcdZONE_API_ES11 | (1 << 0))
+#define gcdZONE_ES11_CLEAR           (gcdZONE_API_ES11 | (1 << 1))
+#define gcdZONE_ES11_CLIP            (gcdZONE_API_ES11 | (1 << 2))
+#define gcdZONE_ES11_CONTEXT         (gcdZONE_API_ES11 | (1 << 3))
+#define gcdZONE_ES11_DRAW            (gcdZONE_API_ES11 | (1 << 4))
+#define gcdZONE_ES11_ENABLE          (gcdZONE_API_ES11 | (1 << 5))
+#define gcdZONE_ES11_EXTENTION       (gcdZONE_API_ES11 | (1 << 6))
+#define gcdZONE_ES11_FOG             (gcdZONE_API_ES11 | (1 << 7))
+#define gcdZONE_ES11_FRAGMENT        (gcdZONE_API_ES11 | (1 << 8))
+#define gcdZONE_ES11_LIGHT           (gcdZONE_API_ES11 | (1 << 9))
+#define gcdZONE_ES11_MATRIX          (gcdZONE_API_ES11 | (1 << 10))
+#define gcdZONE_ES11_PIXEL           (gcdZONE_API_ES11 | (1 << 11))
+#define gcdZONE_ES11_POLIGON         (gcdZONE_API_ES11 | (1 << 12))
+#define gcdZONE_ES11_LINE            (gcdZONE_API_ES11 | (1 << 13)) /* unused */
+#define gcdZONE_ES11_QUERY           (gcdZONE_API_ES11 | (1 << 14))
+#define gcdZONE_ES11_TEXTURE         (gcdZONE_API_ES11 | (1 << 15))
+#define gcdZONE_ES11_STATES          (gcdZONE_API_ES11 | (1 << 16))
+#define gcdZONE_ES11_STREAM          (gcdZONE_API_ES11 | (1 << 17))
+#define gcdZONE_ES11_VIEWPORT        (gcdZONE_API_ES11 | (1 << 18))
+#define gcdZONE_ES11_SHADER          (gcdZONE_API_ES11 | (1 << 19))
+#define gcdZONE_ES11_HASH            (gcdZONE_API_ES11 | (1 << 20))
+#define gcdZONE_ES11_TRACE           (gcdZONE_API_ES11 | (1 << 21))
+
+/* Subzones of ES30 API */
+#define gcdZONE_ES30_TRACE           (gcdZONE_API_ES30 | (1 << 0))
+#define gcdZONE_ES30_BUFFER          (gcdZONE_API_ES30 | (1 << 1))
+#define gcdZONE_ES30_CLEAR           (gcdZONE_API_ES30 | (1 << 2))
+#define gcdZONE_ES30_CODEC           (gcdZONE_API_ES30 | (1 << 3))
+#define gcdZONE_ES30_CONTEXT         (gcdZONE_API_ES30 | (1 << 4))
+#define gcdZONE_ES30_DEPTH           (gcdZONE_API_ES30 | (1 << 5))
+#define gcdZONE_ES30_DEVICE          (gcdZONE_API_ES30 | (1 << 6))
+#define gcdZONE_ES30_DRAW            (gcdZONE_API_ES30 | (1 << 7))
+#define gcdZONE_ES30_FBO             (gcdZONE_API_ES30 | (1 << 8))
+#define gcdZONE_ES30_PIXEL           (gcdZONE_API_ES30 | (1 << 9))
+#define gcdZONE_ES30_SHADER          (gcdZONE_API_ES30 | (1 << 10))
+#define gcdZONE_ES30_STATE           (gcdZONE_API_ES30 | (1 << 11))
+#define gcdZONE_ES30_TEXTURE         (gcdZONE_API_ES30 | (1 << 12))
+#define gcdZONE_ES30_UTILS           (gcdZONE_API_ES30 | (1 << 13))
+#define gcdZONE_ES30_PROFILER        (gcdZONE_API_ES30 | (1 << 14))
+#define gcdZONE_ES30_CORE            (gcdZONE_API_ES30 | (1 << 15))
+
+/* Subzones of GL40 API */
+#define gcdZONE_GL40_TRACE           (gcdZONE_API_GL40 | (1 << 0))
+#define gcdZONE_GL40_BUFFER          (gcdZONE_API_GL40 | (1 << 1))
+#define gcdZONE_GL40_CLEAR           (gcdZONE_API_GL40 | (1 << 2))  /* unused */
+#define gcdZONE_GL40_CODEC           (gcdZONE_API_GL40 | (1 << 3))
+#define gcdZONE_GL40_CONTEXT         (gcdZONE_API_GL40 | (1 << 4))
+#define gcdZONE_GL40_DEPTH           (gcdZONE_API_GL40 | (1 << 5))
+#define gcdZONE_GL40_DEVICE          (gcdZONE_API_GL40 | (1 << 6))
+#define gcdZONE_GL40_DRAW            (gcdZONE_API_GL40 | (1 << 7))
+#define gcdZONE_GL40_FBO             (gcdZONE_API_GL40 | (1 << 8))
+#define gcdZONE_GL40_PIXEL           (gcdZONE_API_GL40 | (1 << 9))
+#define gcdZONE_GL40_SHADER          (gcdZONE_API_GL40 | (1 << 10))
+#define gcdZONE_GL40_STATE           (gcdZONE_API_GL40 | (1 << 11))
+#define gcdZONE_GL40_TEXTURE         (gcdZONE_API_GL40 | (1 << 12))
+#define gcdZONE_GL40_UTILS           (gcdZONE_API_GL40 | (1 << 13))
+#define gcdZONE_GL40_PROFILER        (gcdZONE_API_GL40 | (1 << 14))
+#define gcdZONE_GL40_CORE            (gcdZONE_API_GL40 | (1 << 15))
+#define gcdZONE_GL40_FIXVERTEX       (gcdZONE_API_GL40 | (1 << 16))
+#define gcdZONE_GL40_FIXFRAG         (gcdZONE_API_GL40 | (1 << 17))
+#define gcdZONE_GL40_HASH            (gcdZONE_API_GL40 | (1 << 18))
+
+/* Subzones of VG3D API  */
+#define gcdZONE_VG3D_CONTEXT           (gcdZONE_API_VG3D | (1 << 0))
+#define gcdZONE_VG3D_DUMP              (gcdZONE_API_VG3D | (1 << 1))
+#define gcdZONE_VG3D_EGL               (gcdZONE_API_VG3D | (1 << 2))
+#define gcdZONE_VG3D_FONT              (gcdZONE_API_VG3D | (1 << 3))
+#define gcdZONE_VG3D_HARDWARE          (gcdZONE_API_VG3D | (1 << 4))
+#define gcdZONE_VG3D_IMAGE             (gcdZONE_API_VG3D | (1 << 5))
+#define gcdZONE_VG3D_MASK              (gcdZONE_API_VG3D | (1 << 6))
+#define gcdZONE_VG3D_MATRIX            (gcdZONE_API_VG3D | (1 << 7))
+#define gcdZONE_VG3D_OBJECT            (gcdZONE_API_VG3D | (1 << 8))
+#define gcdZONE_VG3D_PAINT             (gcdZONE_API_VG3D | (1 << 9))
+#define gcdZONE_VG3D_PATH              (gcdZONE_API_VG3D | (1 << 10))
+#define gcdZONE_VG3D_PROFILER          (gcdZONE_API_VG3D | (1 << 11))
+#define gcdZONE_VG3D_SCANLINE          (gcdZONE_API_VG3D | (1 << 12))
+#define gcdZONE_VG3D_SHADER            (gcdZONE_API_VG3D | (1 << 13))
+#define gcdZONE_VG3D_TESSELLATOR       (gcdZONE_API_VG3D | (1 << 14))
+#define gcdZONE_VG3D_VGU               (gcdZONE_API_VG3D | (1 << 15))
+
+/* Subzones of VG11 API  */
+#define gcdZONE_VG_ARC               (gcdZONE_API_VG | (1 << 0))
+#define gcdZONE_VG_CONTEXT           (gcdZONE_API_VG | (1 << 1))
+#define gcdZONE_VG_DEBUG             (gcdZONE_API_VG | (1 << 2))
+#define gcdZONE_VG_FILTER            (gcdZONE_API_VG | (1 << 3))
+#define gcdZONE_VG_FORMAT            (gcdZONE_API_VG | (1 << 4))
+#define gcdZONE_VG_IMAGE             (gcdZONE_API_VG | (1 << 5))
+#define gcdZONE_VG_MAIN              (gcdZONE_API_VG | (1 << 6))
+#define gcdZONE_VG_MASK              (gcdZONE_API_VG | (1 << 7))
+#define gcdZONE_VG_MATRIX            (gcdZONE_API_VG | (1 << 8))
+#define gcdZONE_VG_MEMORYMGR         (gcdZONE_API_VG | (1 << 9))
+#define gcdZONE_VG_OBJECT            (gcdZONE_API_VG | (1 << 10))
+#define gcdZONE_VG_PAINT             (gcdZONE_API_VG | (1 << 11))
+#define gcdZONE_VG_PATH              (gcdZONE_API_VG | (1 << 12))
+#define gcdZONE_VG_STATE             (gcdZONE_API_VG | (1 << 13))
+#define gcdZONE_VG_STROKE            (gcdZONE_API_VG | (1 << 14))
+#define gcdZONE_VG_TEXT              (gcdZONE_API_VG | (1 << 15))
+#define gcdZONE_VG_VGU               (gcdZONE_API_VG | (1 << 16))
+
+/* Subzones of CL API  */
+#define gcdZONE_CL_COMMAND           (gcdZONE_API_CL | (1 << 0))
+#define gcdZONE_CL_CONTEXT           (gcdZONE_API_CL | (1 << 1))
+#define gcdZONE_CL_DEVICE            (gcdZONE_API_CL | (1 << 2))
+#define gcdZONE_CL_ENQUEUE           (gcdZONE_API_CL | (1 << 3))
+#define gcdZONE_CL_EVENT             (gcdZONE_API_CL | (1 << 4))
+#define gcdZONE_CL_EXT               (gcdZONE_API_CL | (1 << 5))
+#define gcdZONE_CL_GL                (gcdZONE_API_CL | (1 << 6))
+#define gcdZONE_CL_KERNEL            (gcdZONE_API_CL | (1 << 7))
+#define gcdZONE_CL_MEM               (gcdZONE_API_CL | (1 << 8))
+#define gcdZONE_CL_PLATFORM          (gcdZONE_API_CL | (1 << 9))
+#define gcdZONE_CL_PROFILER          (gcdZONE_API_CL | (1 << 10))
+#define gcdZONE_CL_PROGRAM           (gcdZONE_API_CL | (1 << 11))
+#define gcdZONE_CL_SAMPLER           (gcdZONE_API_CL | (1 << 12))
+
+/* Subzones of VX API  */
+#define gcdZONE_VX_ARRAY             (gcdZONE_API_VX | (1 << 0))
+#define gcdZONE_VX_BINARY            (gcdZONE_API_VX | (1 << 1))
+#define gcdZONE_VX_CONTEXT           (gcdZONE_API_VX | (1 << 2))
+#define gcdZONE_VX_CONV              (gcdZONE_API_VX | (1 << 3))
+#define gcdZONE_VX_DELAY             (gcdZONE_API_VX | (1 << 4))
+#define gcdZONE_VX_DIST              (gcdZONE_API_VX | (1 << 5))
+#define gcdZONE_VX_GPULAYER          (gcdZONE_API_VX | (1 << 6))
+#define gcdZONE_VX_GRAPH             (gcdZONE_API_VX | (1 << 7))
+#define gcdZONE_VX_IMAGE             (gcdZONE_API_VX | (1 << 8))
+#define gcdZONE_VX_INTERFACE         (gcdZONE_API_VX | (1 << 9))
+#define gcdZONE_VX_KERNEL            (gcdZONE_API_VX | (1 << 10))
+#define gcdZONE_VX_LAYER             (gcdZONE_API_VX | (1 << 11))
+#define gcdZONE_VX_LUT               (gcdZONE_API_VX | (1 << 12))
+#define gcdZONE_VX_MATRIX            (gcdZONE_API_VX | (1 << 13))
+#define gcdZONE_VX_MEMORY            (gcdZONE_API_VX | (1 << 14))
+#define gcdZONE_VX_METAFMT           (gcdZONE_API_VX | (1 << 15))
+#define gcdZONE_VX_NODE              (gcdZONE_API_VX | (1 << 16))
+#define gcdZONE_VX_OBJARRAY          (gcdZONE_API_VX | (1 << 17))
+#define gcdZONE_VX_PARAM             (gcdZONE_API_VX | (1 << 18))
+#define gcdZONE_VX_PROGRAM           (gcdZONE_API_VX | (1 << 19))
+#define gcdZONE_VX_PYRAMID           (gcdZONE_API_VX | (1 << 20))
+#define gcdZONE_VX_REF               (gcdZONE_API_VX | (1 << 21))
+#define gcdZONE_VX_REMAP             (gcdZONE_API_VX | (1 << 22))
+#define gcdZONE_VX_SCALAR            (gcdZONE_API_VX | (1 << 23))
+#define gcdZONE_VX_TARGET            (gcdZONE_API_VX | (1 << 24))
+#define gcdZONE_VX_TENSOR            (gcdZONE_API_VX | (1 << 25))
+#define gcdZONE_VX_THRESHOLD         (gcdZONE_API_VX | (1 << 26))
+#define gcdZONE_VX_OTHERS            (gcdZONE_API_VX | (1 << 27))
+
+/******************************************************************************\
+******************************** Utility Zones *********************************
+\******************************************************************************/
+
+/* Value for Disabling All Subzones */
+#define gcdZONE_NONE                 0xF0000000
+
+/* Value for Enabling All Subzones */
+#define gcdZONE_ALL                  0x0FFFFFFF
+
+
+/******************************************************************************\
+*********************************** END ****************************************
+\******************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_debug_zones_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "shared/gc_hal_driver_shared.h"
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "shared/gc_hal_driver_vg_shared.h"
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_drm_h_
+#define __gc_hal_drm_h_
+
+#include <uapi/drm/drm.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* creation flag bits. */
+#define DRM_VIV_GEM_CONTIGUOUS      (1u << 0)
+#define DRM_VIV_GEM_CACHED          (1u << 1)
+#define DRM_VIV_GEM_SECURE          (1u << 2)
+#define DRM_VIV_GEM_CMA_LIMIT       (1u << 3)
+
+struct drm_viv_gem_create {
+    __u64 size;
+    __u32 flags;
+    __u32 handle;
+};
+
+struct drm_viv_gem_lock {
+    __u32 handle;
+    __u32 cacheable;
+    __u64 logical;
+};
+
+struct drm_viv_gem_unlock {
+    __u32 handle;
+};
+
+
+#define DRM_VIV_GEM_CLEAN_CACHE         0x01
+#define DRM_VIV_GEM_INVALIDATE_CACHE    0x02
+#define DRM_VIV_GEM_FLUSH_CACHE         0x03
+#define DRM_VIV_GEM_MEMORY_BARRIER      0x04
+
+struct drm_viv_gem_cache {
+    __u32 handle;
+    __u32 op;
+    __u64 logical;
+    __u64 bytes;
+};
+
+
+#define DRM_VIV_GEM_PARAM_POOL      0x00
+#define DRM_VIV_GEM_PARAM_SIZE      0x01
+
+struct drm_viv_gem_query {
+    __u32 handle;
+    __u32 param;
+    __u64 value;
+};
+
+
+struct drm_viv_gem_timestamp {
+    __u32 handle;
+    /* inc count, 0 for query current. */
+    __u32 inc;
+    /* output inc'ed timestamp. */
+    __u64 timestamp;
+};
+
+
+/* basic tiling mode. */
+#define DRM_VIV_GEM_TILING_LINEAR       0x01
+#define DRM_VIV_GEM_TILING_TILED        0x02
+#define DRM_VIV_GEM_TILING_SUPERTILED   0x04
+#define DRM_VIV_GEM_TILING_MINORTILED   0x08
+
+/* tiling mode modifiers. */
+#define DRM_VIV_GEM_TILING_SPLIT    0x10
+#define DRM_VIV_GEM_TILING_X_MAJOR  0x20
+#define DRM_VIV_GEM_TILING_Y_MAJOR  0x40
+#define DRM_VIV_GEM_TILING_SWAP     0x80
+
+/* ts mode. */
+#define DRM_VIV_GEM_TS_NONE         0x00
+#define DRM_VIV_GEM_TS_DISABLED     0x01
+#define DRM_VIV_GEM_TS_NORMAL       0x02
+#define DRM_VIV_GEM_TS_COMPRESSED   0x03
+
+/* ts cache mode. */
+#define DRM_VIV_GEM_TS_CACHE_MODE_64B     0x00
+#define DRM_VIV_GEM_TS_CACHE_MODE_128B    0x01
+#define DRM_VIV_GEM_TS_CACHE_MODE_256B    0x02
+
+struct drm_viv_gem_set_tiling {
+    __u32 handle;
+    __u32 tiling_mode;
+
+    __u32 ts_mode;
+    __u32 ts_cache_mode;
+    __u64 clear_value;
+};
+
+struct drm_viv_gem_get_tiling {
+    __u32 handle;
+    __u32 tiling_mode;
+
+    __u32 ts_mode;
+    __u32 ts_cache_mode;
+    __u64 clear_value;
+};
+
+
+struct drm_viv_gem_attach_aux {
+    __u32 handle;
+    __u32 ts_handle;
+};
+
+
+struct drm_viv_gem_ref_node {
+    __u32 handle;
+
+    /* output. */
+    __u32 node;
+    __u32 ts_node;
+};
+
+
+#define DRM_VIV_GEM_CREATE          0x00
+#define DRM_VIV_GEM_LOCK            0x01
+#define DRM_VIV_GEM_UNLOCK          0x02
+#define DRM_VIV_GEM_CACHE           0x03
+#define DRM_VIV_GEM_QUERY           0x04
+#define DRM_VIV_GEM_TIMESTAMP       0x05
+#define DRM_VIV_GEM_SET_TILING      0x06
+#define DRM_VIV_GEM_GET_TILING      0x07
+#define DRM_VIV_GEM_ATTACH_AUX      0x08
+#define DRM_VIV_GEM_REF_NODE        0x09
+#define DRM_VIV_NUM_IOCTLS          0x0A
+
+#define DRM_IOCTL_VIV_GEM_CREATE        DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_CREATE, struct drm_viv_gem_create)
+#define DRM_IOCTL_VIV_GEM_LOCK          DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_LOCK, struct drm_viv_gem_lock)
+#define DRM_IOCTL_VIV_GEM_UNLOCK        DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_UNLOCK, struct drm_viv_gem_unlock)
+#define DRM_IOCTL_VIV_GEM_CACHE         DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_CACHE, struct drm_viv_gem_cache)
+#define DRM_IOCTL_VIV_GEM_QUERY         DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_QUERY, struct drm_viv_gem_query)
+#define DRM_IOCTL_VIV_GEM_TIMESTAMP     DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_TIMESTAMP, struct drm_viv_gem_timestamp)
+#define DRM_IOCTL_VIV_GEM_SET_TILING    DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_SET_TILING, struct drm_viv_gem_set_tiling)
+#define DRM_IOCTL_VIV_GEM_GET_TILING    DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_GET_TILING, struct drm_viv_gem_get_tiling)
+#define DRM_IOCTL_VIV_GEM_ATTACH_AUX    DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_ATTACH_AUX, struct drm_viv_gem_attach_aux)
+#define DRM_IOCTL_VIV_GEM_REF_NODE      DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_REF_NODE, struct drm_viv_gem_ref_node)
+
+#ifdef __KERNEL__
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
+#define drm_gem_object_unreference_unlocked drm_gem_object_put_locked
+#define drm_dev_unref drm_dev_put
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
+#define drm_gem_object_unreference_unlocked drm_gem_object_put_unlocked
+#define drm_dev_unref drm_dev_put
+#endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __gc_hal_drm_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_dump_h_
+#define __gc_hal_dump_h_
+
+/*
+    gcdDUMP_KEY
+
+        Set this to a string that appears in 'cat /proc/<pid>/cmdline'. E.g. 'camera'.
+        HAL will create dumps for the processes matching this key.
+*/
+#ifndef gcdDUMP_KEY
+#   define gcdDUMP_KEY                          "process"
+#endif
+
+/*
+    gcdDUMP_PATH
+
+        The dump file location. Some processes cannot write to the sdcard.
+        Try apps' data dir, e.g. /data/data/com.android.launcher
+*/
+#ifndef gcdDUMP_PATH
+#if defined(ANDROID)
+#   define gcdDUMP_PATH                         "/mnt/sdcard/"
+#else
+#   define gcdDUMP_PATH                         "./"
+#endif
+#endif
+
+/*
+    gcdDUMP_FILE_IN_KERNEL
+
+        Default dump file for gcdDUMP_IN_KERNEL.
+        The file will be writen globally in kernel side.
+        Can be overwriten in runtime by debugfs:/gc/dump/dump_file
+
+        2 pseudo files:
+        [dmesg]:    means dump to kernel debug message.
+        [ignored]:  means dump ignored, nothing will be dumpped.
+ */
+#ifndef gcdDUMP_FILE_IN_KERNEL
+#  define gcdDUMP_FILE_IN_KERNEL                "[dmesg]"
+#endif
+
+/*
+    gcdDUMP_VERIFY_PER_DRAW
+
+        Sub feature of gcdDUMP.
+        When set to 1, verify RT and images(if used) for every single draw to ease simulation debug.
+        Only valid for ES3 driver for now.
+*/
+#ifndef gcdDUMP_VERIFY_PER_DRAW
+#   define gcdDUMP_VERIFY_PER_DRAW              0
+#endif
+
+/* Standalone dump features below. */
+
+/*
+    gcdDUMP_FRAMERATE
+        When set to a value other than zero, averaqe frame rate will be dumped.
+        The value set is the starting frame that the average will be calculated.
+        This is needed because sometimes first few frames are too slow to be included
+        in the average. Frame count starts from 1.
+*/
+#ifndef gcdDUMP_FRAMERATE
+#   define gcdDUMP_FRAMERATE                    0
+#endif
+
+
+/*
+    gcdDUMP_FRAME_TGA
+
+    When set to a value other than 0, a dump of the frame specified by the value,
+    will be done into frame.tga. Frame count starts from 1.
+ */
+#ifndef gcdDUMP_FRAME_TGA
+#   define gcdDUMP_FRAME_TGA                    0
+#endif
+
+/*
+    gcdDUMP_AHB_ACCESS
+
+        When set to 1, a dump of all AHB register access will be printed to kernel
+        message.
+*/
+#ifndef gcdDUMP_AHB_ACCESS
+#   define gcdDUMP_AHB_ACCESS                   0
+#endif
+
+#endif /* __gc_hal_dump_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h
@@ -0,0 +1,589 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_eglplatform_h_
+#define __gc_hal_eglplatform_h_
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#ifndef WIN32_LEAN_AND_MEAN
+/* #define WIN32_LEAN_AND_MEAN 1 */
+#endif
+#include <windows.h>
+
+typedef HDC                             HALNativeDisplayType;
+typedef HWND                            HALNativeWindowType;
+typedef HBITMAP                         HALNativePixmapType;
+
+typedef struct __BITFIELDINFO
+{
+    BITMAPINFO    bmi;
+    RGBQUAD       bmiColors[2];
+}
+BITFIELDINFO;
+
+#elif /* defined(__APPLE__) || */ defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
+
+#elif defined(WL_EGL_PLATFORM) || defined(EGL_API_WL) /* Wayland */
+
+#elif defined(__GBM__) /* GBM */
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+#elif defined(MIR_EGL_PLATFORM) /* Mir */
+
+#elif defined(__QNXNTO__)
+
+#elif defined(__unix__) || defined(__APPLE__)
+
+#if defined(EGL_API_DFB)
+
+#elif defined(EGL_API_FB)
+
+#elif defined(EGL_API_NULLWS)
+
+
+#else
+
+/* X11 (tetative). */
+#endif
+
+#else
+#error "Platform not recognized"
+#endif
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+
+#include "gc_hal_eglplatform_type.h"
+
+/*******************************************************************************
+** Display. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_GetDisplay(
+    OUT HALNativeDisplayType * Display,
+    IN gctPOINTER Context
+    );
+
+gceSTATUS
+gcoOS_GetDisplayByIndex(
+    IN gctINT DisplayIndex,
+    OUT HALNativeDisplayType * Display,
+    IN gctPOINTER Context
+    );
+
+gceSTATUS
+gcoOS_GetDisplayInfo(
+    IN HALNativeDisplayType Display,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctSIZE_T * Physical,
+    OUT gctINT * Stride,
+    OUT gctINT * BitsPerPixel
+    );
+
+
+
+gceSTATUS
+gcoOS_GetDisplayInfoEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctUINT DisplayInfoSize,
+    OUT halDISPLAY_INFO * DisplayInfo
+    );
+
+gceSTATUS
+gcoOS_GetDisplayVirtual(
+    IN HALNativeDisplayType Display,
+    OUT gctINT * Width,
+    OUT gctINT * Height
+    );
+
+gceSTATUS
+gcoOS_GetDisplayBackbuffer(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    OUT gctPOINTER  *  context,
+    OUT gcoSURF     *  surface,
+    OUT gctUINT * Offset,
+    OUT gctINT * X,
+    OUT gctINT * Y
+    );
+
+gceSTATUS
+gcoOS_SetDisplayVirtual(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctUINT Offset,
+    IN gctINT X,
+    IN gctINT Y
+    );
+
+gceSTATUS
+gcoOS_SetDisplayVirtualEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctPOINTER Context,
+    IN gcoSURF Surface,
+    IN gctUINT Offset,
+    IN gctINT X,
+    IN gctINT Y
+    );
+
+gceSTATUS
+gcoOS_CancelDisplayBackbuffer(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctPOINTER Context,
+    IN gcoSURF Surface,
+    IN gctUINT Offset,
+    IN gctINT X,
+    IN gctINT Y
+    );
+
+gceSTATUS
+gcoOS_SetSwapInterval(
+    IN HALNativeDisplayType Display,
+    IN gctINT Interval
+);
+
+gceSTATUS
+gcoOS_SetSwapIntervalEx(
+    IN HALNativeDisplayType Display,
+    IN gctINT Interval,
+    IN gctPOINTER localDisplay);
+
+gceSTATUS
+gcoOS_GetSwapInterval(
+    IN HALNativeDisplayType Display,
+    IN gctINT_PTR Min,
+    IN gctINT_PTR Max
+);
+
+gceSTATUS
+gcoOS_DisplayBufferRegions(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctINT NumRects,
+    IN gctINT_PTR Rects
+    );
+
+gceSTATUS
+gcoOS_DestroyDisplay(
+    IN HALNativeDisplayType Display
+    );
+
+gceSTATUS
+gcoOS_InitLocalDisplayInfo(
+    IN HALNativeDisplayType Display,
+    IN OUT gctPOINTER * localDisplay
+    );
+
+gceSTATUS
+gcoOS_DeinitLocalDisplayInfo(
+    IN HALNativeDisplayType Display,
+    IN OUT gctPOINTER * localDisplay
+    );
+
+gceSTATUS
+gcoOS_GetDisplayInfoEx2(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctPOINTER  localDisplay,
+    IN gctUINT DisplayInfoSize,
+    OUT halDISPLAY_INFO * DisplayInfo
+    );
+
+gceSTATUS
+gcoOS_GetDisplayBackbufferEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctPOINTER  localDisplay,
+    OUT gctPOINTER  *  context,
+    OUT gcoSURF     *  surface,
+    OUT gctUINT * Offset,
+    OUT gctINT * X,
+    OUT gctINT * Y
+    );
+
+gceSTATUS
+gcoOS_IsValidDisplay(
+    IN HALNativeDisplayType Display
+    );
+
+gceSTATUS
+gcoOS_GetNativeVisualId(
+    IN HALNativeDisplayType Display,
+    OUT gctINT* nativeVisualId
+    );
+
+gctBOOL
+gcoOS_SynchronousFlip(
+    IN HALNativeDisplayType Display
+    );
+
+/*******************************************************************************
+** Windows. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_CreateWindow(
+    IN HALNativeDisplayType Display,
+    IN gctINT X,
+    IN gctINT Y,
+    IN gctINT Width,
+    IN gctINT Height,
+    OUT HALNativeWindowType * Window
+    );
+
+gceSTATUS
+gcoOS_GetWindowInfo(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    OUT gctINT * X,
+    OUT gctINT * Y,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctINT * BitsPerPixel,
+    OUT gctUINT * Offset
+    );
+
+gceSTATUS
+gcoOS_DestroyWindow(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window
+    );
+
+gceSTATUS
+gcoOS_DrawImage(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctINT Left,
+    IN gctINT Top,
+    IN gctINT Right,
+    IN gctINT Bottom,
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctINT BitsPerPixel,
+    IN gctPOINTER Bits
+    );
+
+gceSTATUS
+gcoOS_GetImage(
+    IN HALNativeWindowType Window,
+    IN gctINT Left,
+    IN gctINT Top,
+    IN gctINT Right,
+    IN gctINT Bottom,
+    OUT gctINT * BitsPerPixel,
+    OUT gctPOINTER * Bits
+    );
+
+gceSTATUS
+gcoOS_GetWindowInfoEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    OUT gctINT * X,
+    OUT gctINT * Y,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctINT * BitsPerPixel,
+    OUT gctUINT * Offset,
+    OUT gceSURF_FORMAT * Format,
+    OUT gceSURF_TYPE * Type
+    );
+
+gceSTATUS
+gcoOS_DrawImageEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctINT Left,
+    IN gctINT Top,
+    IN gctINT Right,
+    IN gctINT Bottom,
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctINT BitsPerPixel,
+    IN gctPOINTER Bits,
+    IN gceSURF_FORMAT  Format
+    );
+
+/*
+ * Possiable types:
+ *   gcvSURF_BITMAP
+ *   gcvSURF_RENDER_TARGET
+ *   gcvSURF_RENDER_TARGET_NO_COMPRESSION
+ *   gcvSURF_RENDER_TARGET_NO_TILE_STATUS
+ */
+gceSTATUS
+gcoOS_SetWindowFormat(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gceSURF_TYPE Type,
+    IN gceSURF_FORMAT Format
+    );
+
+
+/*******************************************************************************
+** Pixmaps. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_CreatePixmap(
+    IN HALNativeDisplayType Display,
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctINT BitsPerPixel,
+    OUT HALNativePixmapType * Pixmap
+    );
+
+gceSTATUS
+gcoOS_GetPixmapInfo(
+    IN HALNativeDisplayType Display,
+    IN HALNativePixmapType Pixmap,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctINT * BitsPerPixel,
+    OUT gctINT * Stride,
+    OUT gctPOINTER * Bits
+    );
+
+gceSTATUS
+gcoOS_DrawPixmap(
+    IN HALNativeDisplayType Display,
+    IN HALNativePixmapType Pixmap,
+    IN gctINT Left,
+    IN gctINT Top,
+    IN gctINT Right,
+    IN gctINT Bottom,
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctINT BitsPerPixel,
+    IN gctPOINTER Bits
+    );
+
+gceSTATUS
+gcoOS_DestroyPixmap(
+    IN HALNativeDisplayType Display,
+    IN HALNativePixmapType Pixmap
+    );
+
+gceSTATUS
+gcoOS_GetPixmapInfoEx(
+    IN HALNativeDisplayType Display,
+    IN HALNativePixmapType Pixmap,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctINT * BitsPerPixel,
+    OUT gctINT * Stride,
+    OUT gctPOINTER * Bits,
+    OUT gceSURF_FORMAT * Format
+    );
+
+gceSTATUS
+gcoOS_CopyPixmapBits(
+    IN HALNativeDisplayType Display,
+    IN HALNativePixmapType Pixmap,
+    IN gctUINT DstWidth,
+    IN gctUINT DstHeight,
+    IN gctINT DstStride,
+    IN gceSURF_FORMAT DstFormat,
+    OUT gctPOINTER DstBits
+    );
+
+/*******************************************************************************
+** OS relative. ****************************************************************
+*/
+gceSTATUS
+gcoOS_LoadEGLLibrary(
+    OUT gctHANDLE * Handle
+    );
+
+gceSTATUS
+gcoOS_FreeEGLLibrary(
+    IN gctHANDLE Handle
+    );
+
+gceSTATUS
+gcoOS_ShowWindow(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window
+    );
+
+gceSTATUS
+gcoOS_HideWindow(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window
+    );
+
+gceSTATUS
+gcoOS_SetWindowTitle(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    IN gctCONST_STRING Title
+    );
+
+gceSTATUS
+gcoOS_CapturePointer(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window
+    );
+
+gceSTATUS
+gcoOS_GetEvent(
+    IN HALNativeDisplayType Display,
+    IN HALNativeWindowType Window,
+    OUT halEvent * Event
+    );
+
+gceSTATUS
+gcoOS_CreateClientBuffer(
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctINT Format,
+    IN gctINT Type,
+    OUT gctPOINTER * ClientBuffer
+    );
+
+gceSTATUS
+gcoOS_GetClientBufferInfo(
+    IN gctPOINTER ClientBuffer,
+    OUT gctINT * Width,
+    OUT gctINT * Height,
+    OUT gctINT * Stride,
+    OUT gctPOINTER * Bits
+    );
+
+gceSTATUS
+gcoOS_DestroyClientBuffer(
+    IN gctPOINTER ClientBuffer
+    );
+
+gceSTATUS
+gcoOS_DestroyContext(
+    IN gctPOINTER Display,
+    IN gctPOINTER Context
+    );
+
+gceSTATUS
+gcoOS_CreateContext(
+    IN gctPOINTER LocalDisplay,
+    IN gctPOINTER Context
+    );
+
+gceSTATUS
+gcoOS_MakeCurrent(
+    IN gctPOINTER LocalDisplay,
+    IN HALNativeWindowType DrawDrawable,
+    IN HALNativeWindowType ReadDrawable,
+    IN gctPOINTER Context,
+    IN gcoSURF ResolveTarget
+    );
+
+gceSTATUS
+gcoOS_CreateDrawable(
+    IN gctPOINTER LocalDisplay,
+    IN HALNativeWindowType Drawable
+    );
+
+gceSTATUS
+gcoOS_DestroyDrawable(
+    IN gctPOINTER LocalDisplay,
+    IN HALNativeWindowType Drawable
+    );
+gceSTATUS
+gcoOS_SwapBuffers(
+    IN gctPOINTER LocalDisplay,
+    IN HALNativeWindowType Drawable,
+    IN gcoSURF RenderTarget,
+    IN gcoSURF ResolveTarget,
+    IN gctPOINTER ResolveBits,
+    OUT gctUINT *Width,
+    OUT gctUINT *Height
+    );
+
+gceSTATUS
+gcoOS_ResizeWindow(
+    IN gctPOINTER localDisplay,
+    IN HALNativeWindowType Drawable,
+    IN gctUINT Width,
+    IN gctUINT Height
+    );
+
+gceSTATUS
+gcoOS_RSForSwap(
+    IN gctPOINTER localDisplay,
+    IN HALNativeWindowType Drawable,
+    IN gctPOINTER resolve
+    );
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_eglplatform_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_eglplatform_type_h_
+#define __gc_hal_eglplatform_type_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structure that defined keyboard mapping. */
+typedef struct _halKeyMap
+{
+    /* Normal key. */
+    halKeys normal;
+
+    /* Extended key. */
+    halKeys extended;
+}
+halKeyMap;
+
+/* Event structure. */
+typedef struct _halEvent
+{
+    /* Event type. */
+    halEventType type;
+
+    /* Event data union. */
+    union _halEventData
+    {
+        /* Event data for keyboard. */
+        struct _halKeyboard
+        {
+            /* Scancode. */
+            halKeys scancode;
+
+            /* ASCII characte of the key pressed. */
+            char    key;
+
+            /* Flag whether the key was pressed (1) or released (0). */
+            char    pressed;
+        }
+        keyboard;
+
+        /* Event data for pointer. */
+        struct _halPointer
+        {
+            /* Current pointer coordinate. */
+            int     x;
+            int     y;
+        }
+        pointer;
+
+        /* Event data for mouse buttons. */
+        struct _halButton
+        {
+            /* Left button state. */
+            int     left;
+
+            /* Middle button state. */
+            int     middle;
+
+            /* Right button state. */
+            int     right;
+
+            /* Current pointer coordinate. */
+            int     x;
+            int     y;
+        }
+        button;
+    }
+    data;
+}
+halEvent;
+
+/* VFK_DISPLAY_INFO structure defining information returned by
+   vdkGetDisplayInfoEx. */
+typedef struct _halDISPLAY_INFO
+{
+    /* The size of the display in pixels. */
+    int                         width;
+    int                         height;
+
+    /* The stride of the dispay. -1 is returned if the stride is not known
+    ** for the specified display.*/
+    int                         stride;
+
+    /* The color depth of the display in bits per pixel. */
+    int                         bitsPerPixel;
+
+    /* The logical pointer to the display memory buffer. NULL is returned
+    ** if the pointer is not known for the specified display. */
+    void *                      logical;
+
+    /* The physical address of the display memory buffer. ~0 is returned
+    ** if the address is not known for the specified display. */
+    unsigned long               physical;
+
+    /* Can be wraped as surface. */
+    int                         wrapFB;
+
+    /* FB_MULTI_BUFFER support */
+    int                         multiBuffer;
+    int                         backBufferY;
+
+    /* Tiled buffer / tile status support. */
+    int                         tiledBuffer;
+    int                         tileStatus;
+    int                         compression;
+
+    /* The color info of the display. */
+    unsigned int                alphaLength;
+    unsigned int                alphaOffset;
+    unsigned int                redLength;
+    unsigned int                redOffset;
+    unsigned int                greenLength;
+    unsigned int                greenOffset;
+    unsigned int                blueLength;
+    unsigned int                blueOffset;
+
+    /* Display flip support. */
+    int                         flip;
+}
+halDISPLAY_INFO;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_eglplatform_type_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h
@@ -0,0 +1,2790 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_engine_h_
+#define __gc_hal_engine_h_
+
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+
+
+#if gcdENABLE_3D && gcdENABLE_VG
+#include "gc_hal_engine_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _gcsSURF_RESOLVE_ARGS
+{
+    gceHAL_ARG_VERSION version;
+
+    union _gcsSURF_RESOLVE_ARGS_UNION
+    {
+
+        struct _gcsSURF_RESOLVE_ARG_v2
+        {
+            gctBOOL   yInverted;
+            gctBOOL   directCopy;
+            gctBOOL   resample;
+            gctBOOL   bUploadTex; /* used for upload tex.*/
+            gctBOOL   visualizeDepth; /* convert depth to visible color */
+            gcsPOINT  srcOrigin;
+            gcsPOINT  dstOrigin;
+            gcsPOINT  rectSize;
+            gctUINT   numSlices;
+            gceENGINE engine;     /* 3DBlit engine */
+            gctBOOL   gpuOnly;    /* need only try HW path.*/
+
+            gctBOOL   dump;       /* need dump for verify */
+            gctBOOL   srcSwizzle;    /* src surface format swizzle infomation */
+            gctBOOL   dstSwizzle;    /* dst surface format swizzle infomation */
+            gctBOOL   srcCompressed;   /* src compressed format*/
+            gctBOOL   dstCompressed;   /* dst compressed format*/
+        } v2;
+    } uArgs;
+}
+gcsSURF_RESOLVE_ARGS;
+
+typedef struct _gscBUFFER_VIEW
+{
+    gctUINT32 cmd;
+}gcsBUFFER_VIEW, *gcsBUFFER_VIEW_PTR;
+
+typedef struct _gcsIMAGE_VIEW
+{
+    gctUINT32 cmd;
+}gcsIMAGE_VIEW, *gcsIMAGE_VIEW_PTR;
+
+#if gcdENABLE_3D
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gcoSTREAM *             gcoSTREAM;
+typedef struct _gcoVERTEX *             gcoVERTEX;
+typedef struct _gcoTEXTURE *            gcoTEXTURE;
+typedef struct _gcoINDEX *              gcoINDEX;
+typedef struct _gcsVERTEX_ATTRIBUTES *  gcsVERTEX_ATTRIBUTES_PTR;
+typedef struct _gcoVERTEXARRAY *        gcoVERTEXARRAY;
+typedef struct _gcoBUFOBJ *             gcoBUFOBJ;
+
+#define gcdATTRIBUTE_COUNT              32
+#define gcdVERTEXARRAY_POOL_CAPACITY    32
+
+#define gcvPORGRAM_STAGE_GPIPE (gcvPROGRAM_STAGE_VERTEX_BIT | \
+                                gcvPROGRAM_STAGE_TCS_BIT    | \
+                                gcvPROGRAM_STAGE_TES_BIT    | \
+                                gcvPROGRAM_STAGE_GEOMETRY_BIT)
+
+/******************************************************************************\
+********************************* gcoHAL Object *********************************
+\******************************************************************************/
+
+gceSTATUS
+gcoHAL_QueryShaderCaps(
+    IN  gcoHAL    Hal,
+    OUT gctUINT * UnifiedUniforms,
+    OUT gctUINT * VertUniforms,
+    OUT gctUINT * FragUniforms,
+    OUT gctUINT * Varyings,
+    OUT gctUINT * ShaderCoreCount,
+    OUT gctUINT * ThreadCount,
+    OUT gctUINT * VertInstructionCount,
+    OUT gctUINT * FragInstructionCount
+    );
+
+gceSTATUS
+gcoHAL_QuerySamplerBase(
+                        IN  gcoHAL Hal,
+                        OUT gctUINT32 * VertexCount,
+                        OUT gctINT_PTR VertexBase,
+                        OUT gctUINT32 * FragmentCount,
+                        OUT gctINT_PTR FragmentBase
+                        );
+
+gceSTATUS
+gcoHAL_QueryUniformBase(
+                        IN  gcoHAL Hal,
+                        OUT gctUINT32 * VertexBase,
+                        OUT gctUINT32 * FragmentBase
+                        );
+
+gceSTATUS
+gcoHAL_QueryTextureCaps(
+    IN gcoHAL Hal,
+    OUT gctUINT * MaxWidth,
+    OUT gctUINT * MaxHeight,
+    OUT gctUINT * MaxDepth,
+    OUT gctBOOL * Cubic,
+    OUT gctBOOL * NonPowerOfTwo,
+    OUT gctUINT * VertexSamplers,
+    OUT gctUINT * PixelSamplers
+    );
+
+gceSTATUS
+gcoHAL_QueryTextureMaxAniso(
+    IN gcoHAL Hal,
+    OUT gctUINT * MaxAnisoValue
+    );
+
+gceSTATUS
+gcoHAL_QueryStreamCaps(
+    IN gcoHAL Hal,
+    OUT gctUINT32 * MaxAttributes,
+    OUT gctUINT32 * MaxStreamStride,
+    OUT gctUINT32 * NumberOfStreams,
+    OUT gctUINT32 * Alignment,
+    OUT gctUINT32 * MaxAttribOffset
+    );
+
+/******************************************************************************\
+********************************* gcoSURF Object ********************************
+\******************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/*--------------------------------- gcoSURF 3D --------------------------------*/
+typedef struct _gcsSURF_BLIT_ARGS
+{
+    gcoSURF     srcSurface;
+    gctINT      srcX, srcY, srcZ;
+    gctINT      srcWidth, srcHeight, srcDepth;
+    gcoSURF     dstSurface;
+    gctINT      dstX, dstY, dstZ;
+    gctINT      dstWidth, dstHeight, dstDepth;
+    gctBOOL     xReverse;
+    gctBOOL     yReverse;
+    gctBOOL     scissorTest;
+    gcsRECT     scissor;
+    gctUINT     flags;
+    gctUINT     srcNumSlice, dstNumSlice;
+    gctBOOL     needDecode;
+}
+gcsSURF_BLIT_ARGS;
+
+typedef struct _gcsSURF_CLEAR_ARGS
+{
+    /*
+    ** Color to fill the color portion of the framebuffer when clear
+    ** is called.
+    */
+    struct {
+        gcuVALUE r;
+        gcuVALUE g;
+        gcuVALUE b;
+        gcuVALUE a;
+        /* Color has multiple value type so we must specify it. */
+        gceVALUE_TYPE valueType;
+    } color;
+
+    gcuVALUE depth;
+    gctUINT  stencil;
+
+    gctUINT8 stencilMask;   /* stencil bit-wise mask */
+    gctBOOL depthMask;      /* Depth Write Mask */
+    gctUINT8 colorMask;     /* 4-bit channel Mask: ABGR:MSB->LSB */
+    gcsRECT_PTR clearRect;  /* NULL means full clear */
+    gceCLEAR  flags;        /* clear flags */
+
+    gctUINT32 offset;       /* Offset in surface to cube/array/3D, obsolete in v2 version */
+
+} gcsSURF_CLEAR_ARGS, *gcsSURF_CLEAR_ARGS_PTR;
+
+
+typedef struct _gscSURF_BLITDRAW_BLIT
+{
+    gcoSURF  srcSurface;
+    gcoSURF  dstSurface;
+    gcsRECT  srcRect;
+    gcsRECT  dstRect;
+    gceTEXTURE_FILTER  filterMode;
+    gctBOOL  xReverse;
+    gctBOOL  yReverse;
+    gctBOOL  scissorEnabled;
+    gcsRECT  scissor;
+}gscSURF_BLITDRAW_BLIT;
+
+typedef gceSTATUS (* gctSPLIT_DRAW_FUNC_PTR)(
+    IN gctPOINTER gc,
+    IN gctPOINTER instantDraw,
+    IN gctPOINTER splitDrawInfo
+    );
+
+typedef struct _gcsSPLIT_DRAW_INFO
+{
+    gceSPLIT_DRAW_TYPE     splitDrawType;
+    gctSPLIT_DRAW_FUNC_PTR splitDrawFunc;
+
+    union _gcsSPLIT_DRAW_UNION
+    {
+        /* This path will split many draw.*/
+        struct __gcsSPLIT_DRAW_INFO_TCS
+        {
+            gctPOINTER      indexPtr;
+            gctUINT         indexPerPatch;
+        }info_tcs;
+
+        /* This path split into two draw at most.
+        ** es11 path follow the old code, es30 path
+        ** add more info parameter to record
+        */
+        struct __gcsSPLIT_DRAW_INFO_INDEX_FETCH
+        {
+            gctSIZE_T       instanceCount;
+            gctSIZE_T       splitCount;
+            gcePRIMITIVE    splitPrimMode;
+            gctSIZE_T       splitPrimCount;
+        }info_index_fetch;
+    }u;
+} gcsSPLIT_DRAW_INFO,
+*gcsSPLIT_DRAW_INFO_PTR;
+
+typedef struct _gscSURF_BLITDRAW_ARGS
+{
+    /* always the fist member */
+    gceHAL_ARG_VERSION version;
+
+    union _gcsSURF_BLITDRAW_ARGS_UNION
+    {
+       struct _gscSURF_BLITDRAW_ARG_v1
+       {
+            /* Whether it's clear or blit operation, can be extended. */
+            gceBLITDRAW_TYPE type;
+
+            union _gscSURF_BLITDRAW_UNION
+            {
+                gscSURF_BLITDRAW_BLIT blit;
+
+                struct _gscSURF_BLITDRAW_CLEAR
+                {
+                    gcsSURF_CLEAR_ARGS clearArgs;
+                    gcoSURF rtSurface;
+                    gcoSURF dsSurface;
+                } clear;
+            } u;
+       } v1;
+    } uArgs;
+}
+gcsSURF_BLITDRAW_ARGS;
+
+typedef struct _gcsSURF_BLITBLT_ARGS
+{
+    gctCONST_POINTER    buf;
+    gceSURF_FORMAT      format;
+    gctUINT32           stride;
+    gcoSURF             dstSurf;
+    gcsPOINT            dstOrigin;
+    gcsPOINT            rectSize;
+    gctUINT32           dstOffset;
+}
+gcsSURF_BLITBLT_ARGS;
+
+
+/* CPU Blit with format (including linear <-> tile) conversion*/
+gceSTATUS
+gcoSURF_BlitCPU(
+    gcsSURF_BLIT_ARGS* args
+    );
+
+/* Copy a rectangular area with format conversion. */
+gceSTATUS
+gcoSURF_CopyPixels(
+    IN gcsSURF_VIEW *SrcView,
+    IN gcsSURF_VIEW *DstView,
+    IN gcsSURF_RESOLVE_ARGS *Args
+    );
+
+/* Clear surface function. */
+gceSTATUS
+gcoSURF_Clear(
+    IN gcsSURF_VIEW *SurfView,
+    IN gcsSURF_CLEAR_ARGS_PTR ClearArgs
+    );
+
+/* Preserve pixels from source. */
+gceSTATUS
+gcoSURF_Preserve(
+    IN gcoSURF SrcSurf,
+    IN gcoSURF DstSurf,
+    IN gcsRECT_PTR MaskRect
+    );
+
+/* TO BE REMOVED */
+gceSTATUS
+depr_gcoSURF_Resolve(
+    IN gcoSURF SrcSurface,
+    IN gcoSURF DestSurface,
+    IN gctUINT32 DestAddress,
+    IN gctPOINTER DestBits,
+    IN gctINT DestStride,
+    IN gceSURF_TYPE DestType,
+    IN gceSURF_FORMAT DestFormat,
+    IN gctUINT DestWidth,
+    IN gctUINT DestHeight
+    );
+
+gceSTATUS
+depr_gcoSURF_ResolveRect(
+    IN gcoSURF SrcSurface,
+    IN gcoSURF DstSurface,
+    IN gctUINT32 DstAddress,
+    IN gctPOINTER DstBits,
+    IN gctINT DstStride,
+    IN gceSURF_TYPE DstType,
+    IN gceSURF_FORMAT DstFormat,
+    IN gctUINT DstWidth,
+    IN gctUINT DstHeight,
+    IN gcsPOINT_PTR SrcOrigin,
+    IN gcsPOINT_PTR gcoSURF,
+    IN gcsPOINT_PTR RectSize
+    );
+
+/* Resample surface. */
+gceSTATUS
+gcoSURF_Resample(
+    IN gcoSURF SrcSurf,
+    IN gcoSURF DstSurf,
+    IN gctBOOL sRGBDecode
+    );
+
+/* Resolve rectangular area of a surface. */
+gceSTATUS
+gcoSURF_ResolveRect(
+    IN gcsSURF_VIEW *SrcView,
+    IN gcsSURF_VIEW *DstView,
+    IN gcsSURF_RESOLVE_ARGS *Args
+    );
+
+gceSTATUS
+gcoSURF_GetResolveAlignment(
+    IN gcoSURF Surface,
+    OUT gctUINT *originX,
+    OUT gctUINT *originY,
+    OUT gctUINT *sizeX,
+    OUT gctUINT *sizeY
+    );
+
+gceSTATUS
+gcoSURF_IsHWResolveable(
+    IN gcoSURF SrcSurf,
+    IN gcoSURF DstSurf,
+    IN gcsPOINT_PTR SrcOrigin,
+    IN gcsPOINT_PTR DstOrigin,
+    IN gcsPOINT_PTR RectSize
+    );
+
+/* Set surface resolvability. */
+gceSTATUS
+gcoSURF_SetResolvability(
+    IN gcoSURF Surface,
+    IN gctBOOL Resolvable
+    );
+
+gceSTATUS
+gcoSURF_IsRenderable(
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoSURF_IsFormatRenderableAsRT(
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoBUFOBJ_GetFence(
+    IN gcoBUFOBJ BufObj,
+    IN gceFENCE_TYPE Type
+    );
+
+gceSTATUS
+gcoBUFOBJ_WaitFence(
+    IN gcoBUFOBJ BufObj,
+    IN gceFENCE_TYPE Type
+    );
+
+gceSTATUS
+gcoBUFOBJ_IsFenceEnabled(
+    IN gcoBUFOBJ BufObj
+    );
+
+gceSTATUS
+gcoSURF_GetFence(
+    IN gcoSURF Surface,
+    IN gceFENCE_TYPE Type
+    );
+
+gceSTATUS
+gcoSURF_WaitFence(
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoSTREAM_GetFence(
+    IN gcoSTREAM stream
+    );
+
+gceSTATUS
+gcoSTREAM_WaitFence(
+    IN gcoSTREAM stream
+    );
+
+gceSTATUS
+gcoINDEX_GetFence(
+    IN gcoINDEX Index
+    );
+
+gceSTATUS
+gcoINDEX_WaitFence(
+    IN gcoINDEX Index,
+    IN gceFENCE_TYPE Type
+    );
+
+gceSTATUS
+gcoSURF_DrawBlit(
+    gcsSURF_VIEW *SrcView,
+    gcsSURF_VIEW *DstView,
+    gscSURF_BLITDRAW_BLIT *Args
+    );
+
+gceSTATUS
+gcoSURF_DrawBlitDepth(
+    gcsSURF_VIEW *SrcView,
+    gcsSURF_VIEW *DstView,
+    gscSURF_BLITDRAW_BLIT *Args
+);
+
+
+/******************************************************************************\
+******************************** gcoINDEX Object *******************************
+\******************************************************************************/
+
+/* Construct a new gcoINDEX object. */
+gceSTATUS
+gcoINDEX_Construct(
+    IN gcoHAL Hal,
+    OUT gcoINDEX * Index
+    );
+
+/* Destroy a gcoINDEX object. */
+gceSTATUS
+gcoINDEX_Destroy(
+    IN gcoINDEX Index
+    );
+
+/* Lock index in memory. */
+gceSTATUS
+gcoINDEX_Lock(
+    IN gcoINDEX Index,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Memory
+    );
+
+/* Unlock index that was previously locked with gcoINDEX_Lock. */
+gceSTATUS
+gcoINDEX_Unlock(
+    IN gcoINDEX Index
+    );
+
+/* Upload index data into the memory. */
+gceSTATUS
+gcoINDEX_Load(
+    IN gcoINDEX Index,
+    IN gceINDEX_TYPE IndexType,
+    IN gctUINT32 IndexCount,
+    IN gctPOINTER IndexBuffer
+    );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoINDEX_Bind(
+    IN gcoINDEX Index,
+    IN gceINDEX_TYPE Type
+    );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoINDEX_BindOffset(
+    IN gcoINDEX Index,
+    IN gceINDEX_TYPE Type,
+    IN gctUINT32 Offset
+    );
+
+/* Free existing index buffer. */
+gceSTATUS
+gcoINDEX_Free(
+    IN gcoINDEX Index
+    );
+
+/* Upload data into an index buffer. */
+gceSTATUS
+gcoINDEX_Upload(
+    IN gcoINDEX Index,
+    IN gctCONST_POINTER Buffer,
+    IN gctSIZE_T Bytes
+    );
+
+/* Upload data into an index buffer starting at an offset. */
+gceSTATUS
+gcoINDEX_UploadOffset(
+    IN gcoINDEX Index,
+    IN gctSIZE_T Offset,
+    IN gctCONST_POINTER Buffer,
+    IN gctSIZE_T Bytes
+    );
+
+/*Merge index2 to index1 from 0, index2 must subset of inex1*/
+gceSTATUS
+gcoINDEX_Merge(
+    IN gcoINDEX Index1,
+    IN gcoINDEX Index2
+    );
+
+/*check if index buffer is enough for this draw*/
+gctBOOL
+gcoINDEX_CheckRange(
+    IN gcoINDEX Index,
+    IN gceINDEX_TYPE Type,
+    IN gctINT Count,
+    IN gctUINT32  Indices
+    );
+
+/* Query the index capabilities. */
+gceSTATUS
+gcoINDEX_QueryCaps(
+    OUT gctBOOL * Index8,
+    OUT gctBOOL * Index16,
+    OUT gctBOOL * Index32,
+    OUT gctUINT * MaxIndex
+    );
+
+/* Determine the index range in the current index buffer. */
+gceSTATUS
+gcoINDEX_GetIndexRange(
+    IN gcoINDEX Index,
+    IN gceINDEX_TYPE Type,
+    IN gctSIZE_T Offset,
+    IN gctUINT32 Count,
+    OUT gctUINT32 * MinimumIndex,
+    OUT gctUINT32 * MaximumIndex
+    );
+
+/* Dynamic buffer management. */
+gceSTATUS
+gcoINDEX_SetDynamic(
+    IN gcoINDEX Index,
+    IN gctSIZE_T Bytes,
+    IN gctUINT Buffers
+    );
+
+gceSTATUS
+gcoCLHardware_Construct(void);
+/******************************************************************************\
+********************************** gco3D Object *********************************
+\******************************************************************************/
+
+/* Construct a new gco3D object. */
+gceSTATUS
+gco3D_Construct(
+    IN gcoHAL Hal,
+    IN gctBOOL Robust,
+    OUT gco3D * Engine
+    );
+
+/* Destroy an gco3D object. */
+gceSTATUS
+gco3D_Destroy(
+    IN gco3D Engine
+    );
+
+/* Set 3D API type. */
+gceSTATUS
+gco3D_SetAPI(
+    IN gco3D Engine,
+    IN gceAPI ApiType
+    );
+
+/* Get 3D API type. */
+gceSTATUS
+gco3D_GetAPI(
+    IN gco3D Engine,
+    OUT gceAPI * ApiType
+    );
+
+gceSTATUS
+gco3D_SetTarget(
+    IN gco3D Engine,
+    IN gctUINT32 TargetIndex,
+    IN gcsSURF_VIEW *SurfView,
+    IN gctUINT32 LayerIndex
+    );
+
+gceSTATUS
+gco3D_UnsetTarget(
+    IN gco3D Engine,
+    IN gctUINT32 TargetIndex,
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gco3D_SetPSOutputMapping(
+    IN gco3D Engine,
+    IN gctINT32 * psOutputMapping
+    );
+
+gceSTATUS
+gco3D_SetRenderLayered(
+    IN gco3D Engine,
+    IN gctBOOL Enable,
+    IN gctUINT MaxLayers
+    );
+
+gceSTATUS
+gco3D_SetShaderLayered(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_IsProgramSwitched(
+    IN gco3D Engine
+    );
+
+/* Set depth buffer. */
+gceSTATUS
+gco3D_SetDepth(
+    IN gco3D Engine,
+    IN gcsSURF_VIEW *SurfView
+    );
+
+/* Unset depth buffer. */
+gceSTATUS
+gco3D_UnsetDepth(
+    IN gco3D Engine,
+    IN gcoSURF Surface
+    );
+
+/* Set viewport. */
+gceSTATUS
+gco3D_SetViewport(
+    IN gco3D Engine,
+    IN gctINT32 Left,
+    IN gctINT32 Top,
+    IN gctINT32 Right,
+    IN gctINT32 Bottom
+    );
+
+/* Set scissors. */
+gceSTATUS
+gco3D_SetScissors(
+    IN gco3D Engine,
+    IN gctINT32 Left,
+    IN gctINT32 Top,
+    IN gctINT32 Right,
+    IN gctINT32 Bottom
+    );
+
+/* Set clear color. */
+gceSTATUS
+gco3D_SetClearColor(
+    IN gco3D Engine,
+    IN gctUINT8 Red,
+    IN gctUINT8 Green,
+    IN gctUINT8 Blue,
+    IN gctUINT8 Alpha
+    );
+
+/* Set fixed point clear color. */
+gceSTATUS
+gco3D_SetClearColorX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Red,
+    IN gctFIXED_POINT Green,
+    IN gctFIXED_POINT Blue,
+    IN gctFIXED_POINT Alpha
+    );
+
+/* Set floating point clear color. */
+gceSTATUS
+gco3D_SetClearColorF(
+    IN gco3D Engine,
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+/* Set fixed point clear depth. */
+gceSTATUS
+gco3D_SetClearDepthX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Depth
+    );
+
+/* Set floating point clear depth. */
+gceSTATUS
+gco3D_SetClearDepthF(
+    IN gco3D Engine,
+    IN gctFLOAT Depth
+    );
+
+/* Set clear stencil. */
+gceSTATUS
+gco3D_SetClearStencil(
+    IN gco3D Engine,
+    IN gctUINT32 Stencil
+    );
+
+/* Set shading mode. */
+gceSTATUS
+gco3D_SetShading(
+    IN gco3D Engine,
+    IN gceSHADING Shading
+    );
+
+/* Set blending mode. */
+gceSTATUS
+gco3D_EnableBlending(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set blending function. */
+gceSTATUS
+gco3D_SetBlendFunction(
+    IN gco3D Engine,
+    IN gceBLEND_UNIT Unit,
+    IN gceBLEND_FUNCTION FunctionRGB,
+    IN gceBLEND_FUNCTION FunctionAlpha
+    );
+
+/* Set blending mode. */
+gceSTATUS
+gco3D_SetBlendMode(
+    IN gco3D Engine,
+    IN gceBLEND_MODE ModeRGB,
+    IN gceBLEND_MODE ModeAlpha
+    );
+
+/* Set blending mode for separate rt control */
+gceSTATUS
+gco3D_EnableBlendingIndexed(
+    IN gco3D Engine,
+    IN gctUINT Index,
+    IN gctBOOL Enable
+    );
+
+/* Set blending function for separate rt control */
+gceSTATUS
+gco3D_SetBlendFunctionIndexed(
+    IN gco3D Engine,
+    IN gctUINT Index,
+    IN gceBLEND_UNIT Unit,
+    IN gceBLEND_FUNCTION FunctionRGB,
+    IN gceBLEND_FUNCTION FunctionAlpha
+    );
+
+/* Set blending mode for separate rt control*/
+gceSTATUS
+gco3D_SetBlendModeIndexed(
+    IN gco3D Engine,
+    IN gctUINT Index,
+    IN gceBLEND_MODE ModeRGB,
+    IN gceBLEND_MODE ModeAlpha
+    );
+
+/* Set blending color. */
+gceSTATUS
+gco3D_SetBlendColor(
+    IN gco3D Engine,
+    IN gctUINT Red,
+    IN gctUINT Green,
+    IN gctUINT Blue,
+    IN gctUINT Alpha
+    );
+
+/* Set fixed point blending color. */
+gceSTATUS
+gco3D_SetBlendColorX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Red,
+    IN gctFIXED_POINT Green,
+    IN gctFIXED_POINT Blue,
+    IN gctFIXED_POINT Alpha
+    );
+
+/* Set floating point blending color. */
+gceSTATUS
+gco3D_SetBlendColorF(
+    IN gco3D Engine,
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+/* Set culling mode. */
+gceSTATUS
+gco3D_SetCulling(
+    IN gco3D Engine,
+    IN gceCULL Mode
+    );
+
+/* Enable point size */
+gceSTATUS
+gco3D_SetPointSizeEnable(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set point sprite */
+gceSTATUS
+gco3D_SetPointSprite(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+
+/* Enable/Disable primitive-id. */
+gceSTATUS
+gco3D_SetPrimitiveIdEnable(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set fill mode. */
+gceSTATUS
+gco3D_SetFill(
+    IN gco3D Engine,
+    IN gceFILL Mode
+    );
+
+/* Set depth compare mode. */
+gceSTATUS
+gco3D_SetDepthCompare(
+    IN gco3D Engine,
+    IN gceCOMPARE Compare
+    );
+
+/* Enable depth writing. */
+gceSTATUS
+gco3D_EnableDepthWrite(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set depth mode. */
+gceSTATUS
+gco3D_SetDepthMode(
+    IN gco3D Engine,
+    IN gceDEPTH_MODE Mode
+    );
+
+/* Set depth range. */
+gceSTATUS
+gco3D_SetDepthRangeX(
+    IN gco3D Engine,
+    IN gceDEPTH_MODE Mode,
+    IN gctFIXED_POINT Near,
+    IN gctFIXED_POINT Far
+    );
+
+/* Set depth range. */
+gceSTATUS
+gco3D_SetDepthRangeF(
+    IN gco3D Engine,
+    IN gceDEPTH_MODE Mode,
+    IN gctFLOAT Near,
+    IN gctFLOAT Far
+    );
+
+/* Set last pixel enable */
+gceSTATUS
+gco3D_SetLastPixelEnable(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set depth Bias and Scale */
+gceSTATUS
+gco3D_SetDepthScaleBiasX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT DepthScale,
+    IN gctFIXED_POINT DepthBias
+    );
+
+gceSTATUS
+gco3D_SetDepthScaleBiasF(
+    IN gco3D Engine,
+    IN gctFLOAT DepthScale,
+    IN gctFLOAT DepthBias
+    );
+
+/* Set depth near and far clipping plane. */
+gceSTATUS
+gco3D_SetDepthPlaneF(
+    IN gco3D Engine,
+    IN gctFLOAT Near,
+    IN gctFLOAT Far
+    );
+
+/* Enable or disable dithering. */
+gceSTATUS
+gco3D_EnableDither(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set color write enable bits. */
+gceSTATUS
+gco3D_SetColorWrite(
+    IN gco3D Engine,
+    IN gctUINT8 Enable
+    );
+
+/* Set color write enable bits for separate rt control */
+gceSTATUS
+gco3D_SetColorWriteIndexed(
+    IN gco3D Engine,
+    IN gctUINT Index,
+    IN gctUINT8 Enable
+    );
+
+/* Enable or disable early depth. */
+gceSTATUS
+gco3D_SetEarlyDepth(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Deprecated: Enable or disable all early depth operations. */
+gceSTATUS
+gco3D_SetAllEarlyDepthModes(
+    IN gco3D Engine,
+    IN gctBOOL Disable
+    );
+
+
+gceSTATUS
+gco3D_SetEarlyDepthFromAPP(
+    IN gco3D Engine,
+    IN gctBOOL EarlyDepthFromAPP
+    );
+
+gceSTATUS
+gco3D_SetRADepthWrite(
+    IN gco3D Engine,
+    IN gctBOOL Disable,
+    IN gctBOOL psReadZ,
+    IN gctBOOL psReadW
+    );
+
+gceSTATUS
+gco3D_SetPatchVertices(
+    IN gco3D Engine,
+    IN gctINT PatchVertices
+    );
+
+
+/* Switch dynamic early mode */
+gceSTATUS
+gco3D_SwitchDynamicEarlyDepthMode(
+    IN gco3D Engine
+    );
+
+/* Set dynamic early mode */
+gceSTATUS
+gco3D_DisableDynamicEarlyDepthMode(
+    IN gco3D Engine,
+    IN gctBOOL Disable
+    );
+
+/* Enable or disable depth-only mode. */
+gceSTATUS
+gco3D_SetDepthOnly(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+typedef struct _gcsSTENCIL_INFO * gcsSTENCIL_INFO_PTR;
+typedef struct _gcsSTENCIL_INFO
+{
+    gceSTENCIL_MODE         mode;
+
+    gctUINT8                maskFront;
+    gctUINT8                maskBack;
+    gctUINT8                writeMaskFront;
+    gctUINT8                writeMaskBack;
+
+    gctUINT8                referenceFront;
+
+    gceCOMPARE              compareFront;
+    gceSTENCIL_OPERATION    passFront;
+    gceSTENCIL_OPERATION    failFront;
+    gceSTENCIL_OPERATION    depthFailFront;
+
+    gctUINT8                referenceBack;
+    gceCOMPARE              compareBack;
+    gceSTENCIL_OPERATION    passBack;
+    gceSTENCIL_OPERATION    failBack;
+    gceSTENCIL_OPERATION    depthFailBack;
+}
+gcsSTENCIL_INFO;
+
+/* Set stencil mode. */
+gceSTATUS
+gco3D_SetStencilMode(
+    IN gco3D Engine,
+    IN gceSTENCIL_MODE Mode
+    );
+
+/* Set stencil mask. */
+gceSTATUS
+gco3D_SetStencilMask(
+    IN gco3D Engine,
+    IN gctUINT8 Mask
+    );
+
+/* Set stencil back mask. */
+gceSTATUS
+gco3D_SetStencilMaskBack(
+    IN gco3D Engine,
+    IN gctUINT8 Mask
+    );
+
+/* Set stencil write mask. */
+gceSTATUS
+gco3D_SetStencilWriteMask(
+    IN gco3D Engine,
+    IN gctUINT8 Mask
+    );
+
+/* Set stencil back write mask. */
+gceSTATUS
+gco3D_SetStencilWriteMaskBack(
+    IN gco3D Engine,
+    IN gctUINT8 Mask
+    );
+
+/* Set stencil reference. */
+gceSTATUS
+gco3D_SetStencilReference(
+    IN gco3D Engine,
+    IN gctUINT8 Reference,
+    IN gctBOOL Front
+    );
+
+/* Set stencil compare. */
+gceSTATUS
+gco3D_SetStencilCompare(
+    IN gco3D Engine,
+    IN gceSTENCIL_WHERE Where,
+    IN gceCOMPARE Compare
+    );
+
+/* Set stencil operation on pass. */
+gceSTATUS
+gco3D_SetStencilPass(
+    IN gco3D Engine,
+    IN gceSTENCIL_WHERE Where,
+    IN gceSTENCIL_OPERATION Operation
+    );
+
+/* Set stencil operation on fail. */
+gceSTATUS
+gco3D_SetStencilFail(
+    IN gco3D Engine,
+    IN gceSTENCIL_WHERE Where,
+    IN gceSTENCIL_OPERATION Operation
+    );
+
+/* Set stencil operation on depth fail. */
+gceSTATUS
+gco3D_SetStencilDepthFail(
+    IN gco3D Engine,
+    IN gceSTENCIL_WHERE Where,
+    IN gceSTENCIL_OPERATION Operation
+    );
+
+/* Set all stencil states in one blow. */
+gceSTATUS
+gco3D_SetStencilAll(
+    IN gco3D Engine,
+    IN gcsSTENCIL_INFO_PTR Info
+    );
+
+typedef struct _gcsALPHA_INFO * gcsALPHA_INFO_PTR;
+typedef struct _gcsALPHA_INFO
+{
+    /* Alpha test states. */
+    gctBOOL                 test;
+    gceCOMPARE              compare;
+    gctUINT8                reference;
+    gctFLOAT                floatReference;
+
+    /* Alpha blending states. */
+    gctBOOL                 blend[gcdMAX_DRAW_BUFFERS];
+
+    gceBLEND_FUNCTION       srcFuncColor[gcdMAX_DRAW_BUFFERS];
+    gceBLEND_FUNCTION       srcFuncAlpha[gcdMAX_DRAW_BUFFERS];
+    gceBLEND_FUNCTION       trgFuncColor[gcdMAX_DRAW_BUFFERS];
+    gceBLEND_FUNCTION       trgFuncAlpha[gcdMAX_DRAW_BUFFERS];
+
+    gceBLEND_MODE           modeColor[gcdMAX_DRAW_BUFFERS];
+    gceBLEND_MODE           modeAlpha[gcdMAX_DRAW_BUFFERS];
+
+    gctUINT32               color;
+
+    gctBOOL                 anyBlendEnabled;
+}
+gcsALPHA_INFO;
+
+
+/* Enable or disable alpha test. */
+gceSTATUS
+gco3D_SetAlphaTest(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set alpha test compare. */
+gceSTATUS
+gco3D_SetAlphaCompare(
+    IN gco3D Engine,
+    IN gceCOMPARE Compare
+    );
+
+/* Set alpha test reference in unsigned integer. */
+gceSTATUS
+gco3D_SetAlphaReference(
+    IN gco3D Engine,
+    IN gctUINT8 Reference,
+    IN gctFLOAT FloatReference
+    );
+
+/* Set alpha test reference in fixed point. */
+gceSTATUS
+gco3D_SetAlphaReferenceX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Reference
+    );
+
+/* Set alpha test reference in floating point. */
+gceSTATUS
+gco3D_SetAlphaReferenceF(
+    IN gco3D Engine,
+    IN gctFLOAT Reference
+    );
+
+#if gcdALPHA_KILL_IN_SHADER
+gceSTATUS
+gco3D_SetAlphaKill(
+    IN gco3D Engine,
+    IN gctBOOL AlphaKill,
+    IN gctBOOL ColorKill
+    );
+#endif
+
+/* Enable/Disable anti-alias line. */
+gceSTATUS
+gco3D_SetAntiAliasLine(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set texture slot for anti-alias line. */
+gceSTATUS
+gco3D_SetAALineTexSlot(
+    IN gco3D Engine,
+    IN gctUINT TexSlot
+    );
+
+/* Set anti-alias line width scale. */
+gceSTATUS
+gco3D_SetAALineWidth(
+    IN gco3D Engine,
+    IN gctFLOAT Width
+    );
+
+/* Draw a number of primitives. */
+gceSTATUS
+gco3D_DrawPrimitives(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctSIZE_T StartVertex,
+    IN gctSIZE_T PrimitiveCount
+    );
+
+gceSTATUS
+gco3D_DrawIndirectPrimitives(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctBOOL DrawIndex,
+    IN gctINT BaseOffset,
+    IN gcoBUFOBJ BufObj
+    );
+
+gceSTATUS
+gco3D_MultiDrawIndirectPrimitives(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctBOOL DrawIndex,
+    IN gctINT BaseOffset,
+    IN gctINT DrawCount,
+    IN gctINT Stride,
+    IN gcoBUFOBJ BufObj
+    );
+
+gceSTATUS
+gco3D_DrawInstancedPrimitives(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctBOOL DrawIndex,
+    IN gctINT  StartVertex,
+    IN gctSIZE_T StartIndex,
+    IN gctSIZE_T PrimitiveCount,
+    IN gctSIZE_T VertexCount,
+    IN gctSIZE_T InstanceCount
+    );
+
+gceSTATUS
+gco3D_DrawNullPrimitives(
+    IN gco3D Engine
+    );
+
+gceSTATUS
+gco3D_DrawPrimitivesCount(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctINT* StartVertex,
+    IN gctSIZE_T* VertexCount,
+    IN gctSIZE_T PrimitiveCount
+    );
+
+
+/* Draw a number of primitives using offsets. */
+gceSTATUS
+gco3D_DrawPrimitivesOffset(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctINT32 StartOffset,
+    IN gctSIZE_T PrimitiveCount
+    );
+
+/* Draw a number of indexed primitives. */
+gceSTATUS
+gco3D_DrawIndexedPrimitives(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctSIZE_T BaseVertex,
+    IN gctSIZE_T StartIndex,
+    IN gctSIZE_T PrimitiveCount
+    );
+
+/* Draw a number of indexed primitives using offsets. */
+gceSTATUS
+gco3D_DrawIndexedPrimitivesOffset(
+    IN gco3D Engine,
+    IN gcePRIMITIVE Type,
+    IN gctINT32 BaseOffset,
+    IN gctINT32 StartOffset,
+    IN gctSIZE_T PrimitiveCount
+    );
+
+/* Draw a element from pattern */
+gceSTATUS
+gco3D_DrawPattern(
+    IN gco3D Engine,
+    IN gcsFAST_FLUSH_PTR FastFlushInfo
+    );
+
+/* Enable or disable anti-aliasing. */
+gceSTATUS
+gco3D_SetAntiAlias(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+/* Set msaa samples */
+gceSTATUS
+gco3D_SetSamples(
+    IN gco3D Engine,
+    IN gctUINT32 Samples
+    );
+
+
+/* Write data into the command buffer. */
+gceSTATUS
+gco3D_WriteBuffer(
+    IN gco3D Engine,
+    IN gctCONST_POINTER Data,
+    IN gctSIZE_T Bytes,
+    IN gctBOOL Aligned
+    );
+
+/* Send sempahore and stall until sempahore is signalled. */
+gceSTATUS
+gco3D_Semaphore(
+    IN gco3D Engine,
+    IN gceWHERE From,
+    IN gceWHERE To,
+    IN gceHOW How);
+
+
+/* Explicitly flush shader L1 cache */
+gceSTATUS
+gco3D_FlushSHL1Cache(
+    IN gco3D Engine
+    );
+
+/* Set the subpixels center. */
+gceSTATUS
+gco3D_SetCentroids(
+    IN gco3D Engine,
+    IN gctUINT32 Index,
+    IN gctPOINTER Centroids
+    );
+
+/* query msaa sample coordinates */
+gceSTATUS
+gco3D_GetSampleCoords(
+    IN gco3D Engine,
+    IN gctUINT32 SampleIndex,
+    IN gctBOOL yInverted,
+    OUT gctFLOAT_PTR Coords
+    );
+
+gceSTATUS
+gco3D_SetLogicOp(
+    IN gco3D Engine,
+    IN gctUINT8 Rop
+    );
+
+gceSTATUS
+gco3D_SetQuery(
+    IN gco3D Engine,
+    IN gctUINT32 QueryHeader,
+    IN gceQueryType Type,
+    IN gctBOOL Enable,
+    IN gctUINT32 Index
+    );
+
+gceSTATUS
+gco3D_GetQuery(
+    IN gco3D Engine,
+    IN gceQueryType Type,
+    IN gcsSURF_NODE_PTR Node,
+    IN gctUINT32    Size,
+    IN gctPOINTER   Locked,
+    IN gctUINT32    IndexedId,
+    OUT gctINT32 * Index
+    );
+
+gceSTATUS
+gco3D_SetXfbHeader(
+    IN gco3D Engine,
+    IN gctUINT32 Physical
+    );
+
+gceSTATUS
+gco3D_SetXfbBuffer(
+    IN gco3D Engine,
+    IN gctUINT32 Index,
+    IN gctUINT32 BufferAddr,
+    IN gctUINT32 BufferStride,
+    IN gctUINT32 BufferSize
+    );
+
+gceSTATUS
+gco3D_SetXfbCmd(
+    IN gco3D Engine,
+    IN gceXfbCmd Cmd
+    );
+
+gceSTATUS
+gco3D_SetRasterDiscard(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_SetColorOutCount(
+    IN gco3D Engine,
+    IN gctUINT32 ColorOutCount
+    );
+
+gceSTATUS
+gco3D_SetColorCacheMode(
+    IN gco3D Engine
+    );
+
+gceSTATUS
+gco3D_Set3DEngine(
+    IN gco3D Engine
+    );
+
+gceSTATUS
+gco3D_UnSet3DEngine(
+    IN gco3D Engine
+    );
+
+gceSTATUS
+gco3D_Get3DEngine(
+    OUT gco3D * Engine
+    );
+
+gceSTATUS
+gco3D_QueryReset(
+    IN gco3D Engine,
+    OUT gctBOOL_PTR Innocent
+    );
+
+/* OCL thread walker information. */
+typedef struct _gcsTHREAD_WALKER_INFO * gcsTHREAD_WALKER_INFO_PTR;
+typedef struct _gcsTHREAD_WALKER_INFO
+{
+    gctUINT32   dimensions;
+    gctUINT32   traverseOrder;
+    gctUINT32   enableSwathX;
+    gctUINT32   enableSwathY;
+    gctUINT32   enableSwathZ;
+    gctUINT32   swathSizeX;
+    gctUINT32   swathSizeY;
+    gctUINT32   swathSizeZ;
+    gctUINT32   valueOrder;
+
+    gctUINT32   globalSizeX;
+    gctUINT32   globalOffsetX;
+    gctUINT32   globalSizeY;
+    gctUINT32   globalOffsetY;
+    gctUINT32   globalSizeZ;
+    gctUINT32   globalOffsetZ;
+
+    gctUINT32   globalScaleX;
+    gctUINT32   globalScaleY;
+    gctUINT32   globalScaleZ;
+
+    gctUINT32   workGroupSizeX;
+    gctUINT32   workGroupCountX;
+    gctUINT32   workGroupSizeY;
+    gctUINT32   workGroupCountY;
+    gctUINT32   workGroupSizeZ;
+    gctUINT32   workGroupCountZ;
+
+    gctUINT32   threadAllocation;
+    gctBOOL     barrierUsed;
+    gctUINT32   memoryAccessFlag; /* same as gceMEMORY_ACCESS_FLAG */
+    gctBOOL     indirect;
+    gctUINT32   groupNumberUniformIdx;
+    gctUINT32   baseAddress;
+    gctBOOL     bDual16;
+}
+gcsTHREAD_WALKER_INFO;
+
+#if gcdENABLE_3D && gcdUSE_VX
+/* VX thread walker parameters. */
+typedef struct _gcsVX_THREAD_WALKER_PARAMETERS * gcsVX_THREAD_WALKER_PARAMETERS_PTR;
+
+typedef struct _gcsVX_THREAD_WALKER_PARAMETERS
+{
+    gctUINT32   valueOrder;
+    gctUINT32   workDim;
+
+    gctUINT32   workGroupSizeX;
+    gctUINT32   workGroupCountX;
+
+    gctUINT32   workGroupSizeY;
+    gctUINT32   workGroupCountY;
+
+    gctUINT32   globalOffsetX;
+    gctUINT32   globalScaleX;
+
+    gctUINT32   globalOffsetY;
+    gctUINT32   globalScaleY;
+
+#if gcdVX_OPTIMIZER > 1
+    gctBOOL     tileMode;
+#endif
+}
+gcsVX_THREAD_WALKER_PARAMETERS;
+
+typedef struct _gcsVX_IMAGE_INFO * gcsVX_IMAGE_INFO_PTR;
+
+typedef struct _gcsVX_IMAGE_INFO
+{
+    gctUINT32       format;
+    gctUINT32       rect[4];
+    gctUINT32       width;
+    gctUINT32       height;
+
+    /*arraySize, sliceSize is for imageArray / image3D */
+    gctUINT32       arraySize;
+    gctUINT32       sliceSize;
+
+    gctUINT32       bpp;
+    gctUINT32       planes;
+    gctUINT32       componentCount;
+    gctBOOL         isFloat;
+
+    gctUINT32       uPixels;
+    gctUINT32       vPixels;
+    gceSURF_FORMAT  internalFormat;
+    gctUINT32       border;
+
+    /*vx_imagepatch_addressing_t == (gctUINT32 * 8) */
+    gctUINT32       imagepatch[8 * 3];
+    void            *base_addr[3];
+
+    gctUINT32       stride[3];
+
+    gctPOINTER      logicals[3];
+    gctUINT32       physicals[3];
+    gctUINT32       bytes;
+
+    gcsSURF_NODE_PTR nodes[3];
+
+    gctBOOL         isVXC;
+#if gcdVX_OPTIMIZER
+    gctUINT32       uniformData[3][4];
+#endif
+}
+gcsVX_IMAGE_INFO;
+typedef struct _gcsVX_DISTRIBUTION_INFO * gcsVX_DISTRIBUTION_INFO_PTR;
+
+typedef struct _gcsVX_DISTRIBUTION_INFO
+{
+
+    gctUINT32       logical;
+    gctUINT32       physical;
+    gctUINT32       bytes;
+
+    gcsSURF_NODE_PTR node;
+}
+gcsVX_DISTRIBUTION_INFO;
+#endif
+
+/* Start OCL thread walker. */
+gceSTATUS
+gco3D_InvokeThreadWalker(
+    IN gco3D Engine,
+    IN gcsTHREAD_WALKER_INFO_PTR Info
+    );
+
+gceSTATUS
+gco3D_GetClosestRenderFormat(
+    IN gco3D Engine,
+    IN gceSURF_FORMAT InFormat,
+    OUT gceSURF_FORMAT* OutFormat
+    );
+
+/* Set w clip and w plane limit value. */
+gceSTATUS
+gco3D_SetWClipEnable(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_GetWClipEnable(
+    IN gco3D Engine,
+    OUT gctBOOL * Enable
+    );
+
+gceSTATUS
+gco3D_SetWPlaneLimitF(
+    IN gco3D Engine,
+    IN gctFLOAT Value
+    );
+
+gceSTATUS
+gco3D_SetWPlaneLimitX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Value
+    );
+
+gceSTATUS
+gco3D_SetWPlaneLimit(
+        IN gco3D Engine,
+        IN gctFLOAT Value
+        );
+
+gceSTATUS
+gco3D_PrimitiveRestart(
+    IN gco3D Engine,
+    IN gctBOOL PrimitiveRestart
+    );
+
+gceSTATUS
+gco3D_LoadProgram(
+    IN gco3D Engine,
+    IN gcePROGRAM_STAGE_BIT StageBits,
+    IN gctPOINTER ProgramState
+    );
+
+gceSTATUS
+gco3D_EnableAlphaToCoverage(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_EnableSampleCoverage(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_SetSampleCoverageValue(
+    IN gco3D Engine,
+    IN gctFLOAT CoverageValue,
+    IN gctBOOL Invert
+    );
+
+gceSTATUS
+gco3D_EnableSampleMask(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_SetSampleMask(
+    IN gco3D Engine,
+    IN gctUINT32 SampleMask
+    );
+
+gceSTATUS
+gco3D_EnableSampleShading(
+    IN gco3D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco3D_SetMinSampleShadingValue(
+    IN gco3D Engine,
+    IN gctFLOAT MinSampleShadingValue
+    );
+
+gceSTATUS
+gco3D_SetSampleShading(
+    IN gco3D Engine,
+    IN gctBOOL Enable,
+    IN gctBOOL IsSampleIn,
+    IN gctFLOAT SampleShadingValue
+    );
+
+gceSTATUS
+gco3D_EnableSampleMaskOut(
+    IN gco3D Engine,
+    IN gctBOOL Enable,
+    IN gctINT SampleMaskLoc
+    );
+
+/*----------------------------------------------------------------------------*/
+/*-------------------------- gco3D Fragment Processor ------------------------*/
+
+/* Set the fragment processor configuration. */
+gceSTATUS
+gco3D_SetFragmentConfiguration(
+    IN gco3D Engine,
+    IN gctBOOL ColorFromStream,
+    IN gctBOOL EnableFog,
+    IN gctBOOL EnableSmoothPoint,
+    IN gctUINT32 ClipPlanes
+    );
+
+/* Enable/disable texture stage operation. */
+gceSTATUS
+gco3D_EnableTextureStage(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gctBOOL Enable
+    );
+
+/* Program the channel enable masks for the color texture function. */
+gceSTATUS
+gco3D_SetTextureColorMask(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gctBOOL ColorEnabled,
+    IN gctBOOL AlphaEnabled
+    );
+
+/* Program the channel enable masks for the alpha texture function. */
+gceSTATUS
+gco3D_SetTextureAlphaMask(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gctBOOL ColorEnabled,
+    IN gctBOOL AlphaEnabled
+    );
+
+/* Program the constant fragment color. */
+gceSTATUS
+gco3D_SetFragmentColorX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Red,
+    IN gctFIXED_POINT Green,
+    IN gctFIXED_POINT Blue,
+    IN gctFIXED_POINT Alpha
+    );
+
+gceSTATUS
+gco3D_SetFragmentColorF(
+    IN gco3D Engine,
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+/* Program the constant fog color. */
+gceSTATUS
+gco3D_SetFogColorX(
+    IN gco3D Engine,
+    IN gctFIXED_POINT Red,
+    IN gctFIXED_POINT Green,
+    IN gctFIXED_POINT Blue,
+    IN gctFIXED_POINT Alpha
+    );
+
+gceSTATUS
+gco3D_SetFogColorF(
+    IN gco3D Engine,
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+/* Program the constant texture color. */
+gceSTATUS
+gco3D_SetTetxureColorX(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gctFIXED_POINT Red,
+    IN gctFIXED_POINT Green,
+    IN gctFIXED_POINT Blue,
+    IN gctFIXED_POINT Alpha
+    );
+
+gceSTATUS
+gco3D_SetTetxureColorF(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+/* Configure color texture function. */
+gceSTATUS
+gco3D_SetColorTextureFunction(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gceTEXTURE_FUNCTION Function,
+    IN gceTEXTURE_SOURCE Source0,
+    IN gceTEXTURE_CHANNEL Channel0,
+    IN gceTEXTURE_SOURCE Source1,
+    IN gceTEXTURE_CHANNEL Channel1,
+    IN gceTEXTURE_SOURCE Source2,
+    IN gceTEXTURE_CHANNEL Channel2,
+    IN gctINT Scale
+    );
+
+/* Configure alpha texture function. */
+gceSTATUS
+gco3D_SetAlphaTextureFunction(
+    IN gco3D Engine,
+    IN gctINT Stage,
+    IN gceTEXTURE_FUNCTION Function,
+    IN gceTEXTURE_SOURCE Source0,
+    IN gceTEXTURE_CHANNEL Channel0,
+    IN gceTEXTURE_SOURCE Source1,
+    IN gceTEXTURE_CHANNEL Channel1,
+    IN gceTEXTURE_SOURCE Source2,
+    IN gceTEXTURE_CHANNEL Channel2,
+    IN gctINT Scale
+    );
+
+/******************************************************************************\
+******************************* gcoTEXTURE Object *******************************
+\******************************************************************************/
+
+typedef struct _gcsTEXTURE
+{
+    /* Addressing modes. */
+    gceTEXTURE_ADDRESSING       s;
+    gceTEXTURE_ADDRESSING       t;
+    gceTEXTURE_ADDRESSING       r;
+
+    gceTEXTURE_SWIZZLE          swizzle[gcvTEXTURE_COMPONENT_NUM];
+
+    /* Border color. */
+    gctUINT8                    border[gcvTEXTURE_COMPONENT_NUM];
+
+    /* Filters. */
+    gceTEXTURE_FILTER           minFilter;
+    gceTEXTURE_FILTER           magFilter;
+    gceTEXTURE_FILTER           mipFilter;
+    gctUINT                     anisoFilter;
+
+    /* Level of detail. */
+    gctFLOAT                    lodBias;
+    gctFLOAT                    lodMin;
+    gctFLOAT                    lodMax;
+
+    /* base/max level */
+    gctINT32                    baseLevel;
+    gctINT32                    maxLevel;
+
+    /* depth texture comparison */
+    gceTEXTURE_COMPARE_MODE     compareMode;
+    gceCOMPARE                  compareFunc;
+
+    gceTEXTURE_DS_TEX_MODE      dsTextureMode;
+
+    gceTEXTURE_DS_MODE          dsMode;
+
+    /* sRGB decode */
+    gceTEXTURE_SRGBDECODE       sRGB;
+
+    gcuVALUE                    borderColor[4];
+    gctBOOL                     descDirty;
+}
+gcsTEXTURE, * gcsTEXTURE_PTR;
+
+typedef struct _gcsTEXTURE_BINDTEXTS_ARGS
+{
+    /* must be the first member */
+    gceHAL_ARG_VERSION  version;
+
+}
+gcsTEXTURE_BINDTEXTS_ARGS;
+
+/* Construct a new gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Construct(
+    IN gcoHAL Hal,
+    OUT gcoTEXTURE * Texture
+    );
+
+/* Construct a new gcoTEXTURE object with type information. */
+gceSTATUS
+gcoTEXTURE_ConstructEx(
+    IN gcoHAL Hal,
+    IN gceTEXTURE_TYPE Type,
+    OUT gcoTEXTURE * Texture
+    );
+
+
+/* Construct a new sized gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_ConstructSized(
+    IN gcoHAL Hal,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gctUINT Depth,
+    IN gctUINT Faces,
+    IN gctUINT MipMapCount,
+    IN gcePOOL Pool,
+    OUT gcoTEXTURE * Texture
+    );
+
+/* Destroy an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Destroy(
+    IN gcoTEXTURE Texture
+    );
+
+/* Upload data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Upload(
+    IN gcoTEXTURE Texture,
+    IN gctINT MipMap,
+    IN gceTEXTURE_FACE Face,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctUINT Slice,
+    IN gctCONST_POINTER Memory,
+    IN gctSIZE_T Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_COLOR_SPACE SrcColorSpace
+    );
+
+/* Upload data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadSub(
+    IN gcoTEXTURE Texture,
+    IN gctINT MipMap,
+    IN gceTEXTURE_FACE Face,
+    IN gctSIZE_T X,
+    IN gctSIZE_T Y,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctUINT Slice,
+    IN gctCONST_POINTER Memory,
+    IN gctSIZE_T Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_COLOR_SPACE SrcColorSpace,
+    IN gctUINT32 PhysicalAddress
+    );
+
+
+/* Upload YUV data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadYUV(
+    IN gcoTEXTURE Texture,
+    IN gceTEXTURE_FACE Face,
+    IN gctUINT Width,
+    IN gctUINT Height,
+    IN gctUINT Slice,
+    IN gctPOINTER Memory[3],
+    IN gctINT Stride[3],
+    IN gceSURF_FORMAT Format
+    );
+
+/* Upload compressed data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadCompressed(
+    IN gcoTEXTURE Texture,
+    IN gctINT MipMap,
+    IN gceTEXTURE_FACE Face,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctUINT Slice,
+    IN gctCONST_POINTER Memory,
+    IN gctSIZE_T Bytes
+    );
+
+/* Upload compressed sub data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadCompressedSub(
+    IN gcoTEXTURE Texture,
+    IN gctINT MipMap,
+    IN gceTEXTURE_FACE Face,
+    IN gctSIZE_T XOffset,
+    IN gctSIZE_T YOffset,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctUINT Slice,
+    IN gctCONST_POINTER Memory,
+    IN gctSIZE_T Size
+    );
+
+/* Get gcoSURF object for a mipmap level. */
+gceSTATUS
+gcoTEXTURE_GetMipMap(
+    IN gcoTEXTURE Texture,
+    IN gctUINT MipMap,
+    OUT gcoSURF * Surface
+    );
+
+/* Get gcoSURF object for a mipmap level and face offset. */
+gceSTATUS
+gcoTEXTURE_GetMipMapFace(
+    IN gcoTEXTURE Texture,
+    IN gctUINT MipMap,
+    IN gceTEXTURE_FACE Face,
+    OUT gcoSURF * Surface,
+    OUT gctSIZE_T_PTR Offset
+    );
+
+gceSTATUS
+gcoTEXTURE_GetMipMapSlice(
+    IN gcoTEXTURE Texture,
+    IN gctUINT MipMap,
+    IN gctUINT Slice,
+    OUT gcoSURF * Surface,
+    OUT gctSIZE_T_PTR Offset
+    );
+
+gceSTATUS
+gcoTEXTURE_AddMipMap(
+    IN gcoTEXTURE Texture,
+    IN gctINT Level,
+    IN gctINT InternalFormat,
+    IN gceSURF_FORMAT Format,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctSIZE_T Depth,
+    IN gctUINT Faces,
+    IN gcePOOL Pool,
+    IN gctBOOL Filterable,
+    OUT gcoSURF * Surface
+    );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapEx(
+    IN gcoTEXTURE Texture,
+    IN gctINT Level,
+    IN gctINT InternalFormat,
+    IN gceSURF_FORMAT Format,
+    IN gctSIZE_T Width,
+    IN gctSIZE_T Height,
+    IN gctSIZE_T Depth,
+    IN gctUINT Faces,
+    IN gcePOOL Pool,
+    IN gctUINT32 Samples,
+    IN gctBOOL Protected,
+    IN gctBOOL Filterable,
+    OUT gcoSURF * Surface
+    );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapFromClient(
+    IN gcoTEXTURE Texture,
+    IN gctINT     Level,
+    IN gcoSURF    Surface
+    );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapFromSurface(
+    IN gcoTEXTURE Texture,
+    IN gctINT     Level,
+    IN gcoSURF    Surface
+    );
+
+gceSTATUS
+gcoTEXTURE_LockMipMap(
+    IN gcoTEXTURE Texture,
+    IN gctUINT MipMap,
+    OPTIONAL OUT gctUINT32 * Address,
+    OPTIONAL OUT gctPOINTER * Memory
+    );
+
+gceSTATUS
+gcoTEXTURE_SetEndianHint(
+    IN gcoTEXTURE Texture,
+    IN gceENDIAN_HINT EndianHint
+    );
+
+gceSTATUS
+gcoTEXTURE_Disable(
+    IN gcoHAL Hal,
+    IN gctINT Sampler,
+    IN gctBOOL DefaultInteger
+    );
+
+gceSTATUS
+gcoTEXTURE_Flush(
+    IN gcoTEXTURE Texture
+    );
+
+gceSTATUS
+gcoTEXTURE_FlushVS(
+    IN gcoTEXTURE Texture
+    );
+
+gceSTATUS
+gcoTEXTURE_QueryCaps(
+    IN  gcoHAL    Hal,
+    OUT gctUINT * MaxWidth,
+    OUT gctUINT * MaxHeight,
+    OUT gctUINT * MaxDepth,
+    OUT gctBOOL * Cubic,
+    OUT gctBOOL * NonPowerOfTwo,
+    OUT gctUINT * VertexSamplers,
+    OUT gctUINT * PixelSamplers
+    );
+
+gceSTATUS
+gcoTEXTURE_GetClosestFormat(
+    IN gcoHAL Hal,
+    IN gceSURF_FORMAT InFormat,
+    OUT gceSURF_FORMAT* OutFormat
+    );
+
+gceSTATUS
+gcoTEXTURE_GetClosestFormatEx(
+    IN gcoHAL Hal,
+    IN gceSURF_FORMAT InFormat,
+    IN gceTEXTURE_TYPE TextureType,
+    OUT gceSURF_FORMAT* OutFormat
+    );
+
+gceSTATUS
+gcoTEXTURE_GetFormatInfo(
+    IN gcoTEXTURE Texture,
+    IN gctINT preferLevel,
+    OUT gcsSURF_FORMAT_INFO_PTR * TxFormatInfo
+    );
+
+gceSTATUS
+gcoTEXTURE_GetTextureFormatName(
+    IN gcsSURF_FORMAT_INFO_PTR TxFormatInfo,
+    OUT gctCONST_STRING * TxName
+    );
+
+gceSTATUS
+gcoTEXTURE_RenderIntoMipMap(
+    IN gcoTEXTURE Texture,
+    IN gctINT Level
+    );
+
+gceSTATUS
+gcoTEXTURE_RenderIntoMipMap2(
+    IN gcoTEXTURE Texture,
+    IN gctINT Level,
+    IN gctBOOL Sync
+    );
+
+gceSTATUS
+gcoTEXTURE_IsRenderable(
+    IN gcoTEXTURE Texture,
+    IN gctUINT Level
+    );
+
+gceSTATUS
+gcoTEXTURE_IsComplete(
+    IN gcoTEXTURE Texture,
+    IN gcsTEXTURE_PTR Info,
+    IN gctINT BaseLevel,
+    IN gctINT MaxLevel
+    );
+
+gceSTATUS
+gcoTEXTURE_CheckTexLevel0Attrib(
+    IN gcoTEXTURE Texture,
+    IN gctINT MaxLevel,
+    IN gctINT usedLevel
+    );
+
+gceSTATUS
+gcoTEXTURE_BindTexture(
+    IN gcoTEXTURE Texture,
+    IN gctINT Target,
+    IN gctINT Sampler,
+    IN gcsTEXTURE_PTR Info
+    );
+
+gceSTATUS
+gcoTEXTURE_BindTextureEx(
+    IN gcoTEXTURE Texture,
+    IN gctINT Target,
+    IN gctINT Sampler,
+    IN gcsTEXTURE_PTR Info,
+    IN gctINT textureLayer
+    );
+
+gceSTATUS
+gcoTEXTURE_BindTextureDesc(
+    IN gcoTEXTURE Texture,
+    IN gctINT Sampler,
+    IN gcsTEXTURE_PTR Info,
+    IN gctINT TextureLayer
+    );
+
+gceSTATUS
+gcoTEXTURE_SetDescDirty(
+    IN gcoTEXTURE Texture
+    );
+
+gceSTATUS
+gcoTEXTURE_InitParams(
+    IN gcoHAL Hal,
+    IN gcsTEXTURE_PTR TexParams
+    );
+
+gceSTATUS
+gcoTEXTURE_SetDepthTextureFlag(
+    IN gcoTEXTURE Texture,
+    IN gctBOOL  unsized
+    );
+
+gceSTATUS
+gcoTEXTURE_BindTextureTS(
+    IN gcsTEXTURE_BINDTEXTS_ARGS * args
+    );
+
+gceSTATUS
+gcoTEXTURE_GenerateMipMap(
+    IN gcoTEXTURE Texture,
+    IN gctINT   BaseLevel,
+    IN gctINT   MaxLevel,
+    IN gctBOOL  sRGBDecode
+    );
+
+/******************************************************************************\
+******************************* gcoSTREAM Object ******************************
+\******************************************************************************/
+
+gceSTATUS
+gcoSTREAM_Construct(
+    IN gcoHAL Hal,
+    OUT gcoSTREAM * Stream
+    );
+
+gceSTATUS
+gcoSTREAM_Destroy(
+    IN gcoSTREAM Stream
+    );
+
+gceSTATUS
+gcoSTREAM_Upload(
+    IN gcoSTREAM Stream,
+    IN gctCONST_POINTER Buffer,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    IN gctBOOL Dynamic
+    );
+
+gceSTATUS
+gcoSTREAM_ReAllocBufNode(
+    IN gcoSTREAM Stream
+    );
+
+gceSTATUS
+gcoSTREAM_SetStride(
+    IN gcoSTREAM Stream,
+    IN gctUINT32 Stride
+    );
+
+gceSTATUS
+gcoSTREAM_Node(
+    IN gcoSTREAM Stream,
+    OUT gcsSURF_NODE_PTR * Node
+    );
+
+gceSTATUS
+gcoSTREAM_Lock(
+    IN gcoSTREAM Stream,
+    OUT gctPOINTER * Logical,
+    OUT gctUINT32 * Physical
+    );
+
+gceSTATUS
+gcoSTREAM_Unlock(
+    IN gcoSTREAM Stream
+    );
+
+gceSTATUS
+gcoSTREAM_Reserve(
+    IN gcoSTREAM Stream,
+    IN gctSIZE_T Bytes
+    );
+
+gceSTATUS
+gcoSTREAM_Flush(
+    IN gcoSTREAM Stream
+    );
+
+typedef struct _gcsSTREAM_INFO
+{
+    gctUINT             index;
+    gceVERTEX_FORMAT    format;
+    gctBOOL             normalized;
+    gctUINT             components;
+    gctSIZE_T           size;
+    gctCONST_POINTER    data;
+    gctUINT             stride;
+}
+gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR;
+
+gceSTATUS
+gcoSTREAM_CPUCacheOperation(
+    IN gcoSTREAM Stream,
+    IN gceCACHEOPERATION Operation
+    );
+
+gceSTATUS
+gcoSTREAM_CPUCacheOperation_Range(
+    IN gcoSTREAM Stream,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Length,
+    IN gceCACHEOPERATION Operation
+    );
+
+/******************************************************************************\
+******************************** gcoVERTEX Object ******************************
+\******************************************************************************/
+
+typedef struct _gcsVERTEX_ATTRIBUTES
+{
+    gceVERTEX_FORMAT            format;
+    gctBOOL                     normalized;
+    gctUINT32                   components;
+    gctSIZE_T                   size;
+    gctUINT32                   stream;
+    gctUINT32                   offset;
+    gctUINT32                   stride;
+}
+gcsVERTEX_ATTRIBUTES;
+
+gceSTATUS
+gcoVERTEX_Construct(
+    IN gcoHAL Hal,
+    OUT gcoVERTEX * Vertex
+    );
+
+gceSTATUS
+gcoVERTEX_Destroy(
+    IN gcoVERTEX Vertex
+    );
+
+gceSTATUS
+gcoVERTEX_Reset(
+    IN gcoVERTEX Vertex
+    );
+
+gceSTATUS
+gcoVERTEX_EnableAttribute(
+    IN gcoVERTEX Vertex,
+    IN gctUINT32 Index,
+    IN gceVERTEX_FORMAT Format,
+    IN gctBOOL Normalized,
+    IN gctUINT32 Components,
+    IN gcoSTREAM Stream,
+    IN gctUINT32 Offset,
+    IN gctUINT32 Stride
+    );
+
+gceSTATUS
+gcoVERTEX_DisableAttribute(
+    IN gcoVERTEX Vertex,
+    IN gctUINT32 Index
+    );
+
+gceSTATUS
+gcoVERTEX_Bind(
+    IN gcoVERTEX Vertex
+    );
+
+/*******************************************************************************
+***** gcoVERTEXARRAY Object ***************************************************/
+
+typedef struct _gcsATTRIBUTE
+{
+    /* Enabled. */
+    gctBOOL             enable;
+
+    /* Number of components. */
+    gctINT              size;
+
+    /* Attribute format. */
+    gceVERTEX_FORMAT    format;
+
+    /* Flag whether the attribute is normalized or not. */
+    gctBOOL             normalized;
+
+    /* Stride of the component. */
+    gctSIZE_T           stride;
+
+    /* Divisor of the attribute */
+    gctUINT             divisor;
+
+    /* Pointer to the attribute data. */
+    gctCONST_POINTER    pointer;
+
+    /* Stream object owning the attribute data. */
+    gcoBUFOBJ           stream;
+
+    /* Generic values for attribute. */
+    gctFLOAT            genericValue[4];
+
+    /* Generic size for attribute. */
+    gctINT              genericSize;
+
+    /* Vertex shader linkage. */
+    gctUINT             linkage;
+
+#if gcdUSE_WCLIP_PATCH
+    /* Does it hold positions? */
+    gctBOOL             isPosition;
+#endif
+
+    /* Index to vertex array */
+    gctINT              arrayIdx;
+
+    gceATTRIB_SCHEME    convertScheme;
+
+    /* Pointer to the temporary buffer to be freed */
+    gcoBUFOBJ           tempStream;
+
+    /* Pointer to the temporary memory to be freed */
+    gctCONST_POINTER    tempMemory;
+}
+gcsATTRIBUTE,
+* gcsATTRIBUTE_PTR;
+
+typedef struct _gcsVERTEXARRAY
+{
+    /* Enabled. */
+    gctBOOL             enable;
+
+    /* Number of components. */
+    gctINT              size;
+
+    /* Attribute format. */
+    gceVERTEX_FORMAT    format;
+
+    /* Flag whether the attribute is normalized or not. */
+    gctBOOL             normalized;
+
+    /* Stride of the component. */
+    gctUINT             stride;
+
+    /* Divisor of the attribute */
+    gctUINT             divisor;
+
+    /* Pointer to the attribute data. */
+    gctCONST_POINTER    pointer;
+
+    /* Stream object owning the attribute data. */
+    gcoSTREAM           stream;
+
+    /* Generic values for attribute. */
+    gctFLOAT            genericValue[4];
+
+    /* Generic size for attribute. */
+    gctINT              genericSize;
+
+    /* Vertex shader linkage. */
+    gctUINT             linkage;
+
+    gctBOOL             isPosition;
+}
+gcsVERTEXARRAY,
+* gcsVERTEXARRAY_PTR;
+
+gceSTATUS
+gcoVERTEXARRAY_Construct(
+    IN gcoHAL Hal,
+    OUT gcoVERTEXARRAY * Vertex
+    );
+
+gceSTATUS
+gcoVERTEXARRAY_Destroy(
+    IN gcoVERTEXARRAY Vertex
+    );
+
+/* If don't consider isolation, STREAM_INFO / INDEX_INFO could be
+** include in the struct of instantDraw in chip level.*/
+typedef struct _gcsVERTEXARRAY_STREAM_INFO
+{
+    gctUINT          attribMask;
+    gctSIZE_T        first;
+    gctSIZE_T        count;
+    gcePRIMITIVE     primMode;
+    gctSIZE_T        primCount;
+    gctINT           vertexInstIndex;
+    gctBOOL          instanced;
+    gctSIZE_T        instanceCount;
+
+    union _gcsVERTEXARRAY_STREAM_INFO_UNION
+    {
+        struct _gcsVERTEXARRAY_STREAM_ES11_INFO
+        {
+            gcsVERTEXARRAY_PTR    attributes;
+        }es11;
+
+        struct _gcsVERTEXARRAY_STREAM_ES30_INFO
+        {
+            gcsATTRIBUTE_PTR      attributes;
+        }es30;
+    }u;
+}gcsVERTEXARRAY_STREAM_INFO,
+*gcsVERTEXARRAY_STREAM_INFO_PTR;
+
+typedef const struct _gcsVERTEXARRAY_STREAM_INFO* gcsVERTEXARRAY_STREAM_INFO_CONST_PTR;
+
+typedef struct _gcsVERTEXARRAY_INDEX_INFO
+{
+    gctSIZE_T        count;
+    gceINDEX_TYPE    indexType;
+    gctPOINTER       indexMemory;
+    gctUINT          restartElement;
+
+    union _gcsVERTEXARRAY_INDEX_INFO_UNION
+    {
+        struct _gcsVERTEXARRAY_INDEX_ES11_INFO
+        {
+            gcoINDEX         indexBuffer;
+        }es11;
+
+        struct _gcsVERTEXARRAY_INDEX_ES30_INFO
+        {
+            gcoBUFOBJ        indexBuffer;
+        }es30;
+    }u;
+}gcsVERTEXARRAY_INDEX_INFO,
+*gcsVERTEXARRAY_INDEX_INFO_PTR;
+
+typedef const struct _gcsVERTEXARRAY_INDEX_INFO* gcsVERTEXARRAY_INDEX_INFO_CONST_PTR;
+
+gceSTATUS
+gcoVERTEXARRAY_IndexBind(
+    IN gcoVERTEXARRAY Vertex,
+    IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+    );
+
+gceSTATUS
+gcoVERTEXARRAY_StreamBind(
+    IN gcoVERTEXARRAY Vertex,
+#if gcdUSE_WCLIP_PATCH
+    IN OUT gctFLOAT * WLimitRms,
+    IN OUT gctBOOL * WLimitRmsDirty,
+#endif
+    IN gcsVERTEXARRAY_STREAM_INFO_CONST_PTR StreamInfo,
+    IN gcsVERTEXARRAY_INDEX_INFO_CONST_PTR IndexInfo
+    );
+
+gceSTATUS
+gcoVERTEXARRAY_IndexBind_Ex(
+    IN gcoVERTEXARRAY Vertex,
+    IN OUT gcsVERTEXARRAY_STREAM_INFO_PTR StreamInfo,
+    IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+    );
+
+gceSTATUS
+gcoVERTEXARRAY_StreamBind_Ex(
+    IN gcoVERTEXARRAY Vertex,
+#if gcdUSE_WCLIP_PATCH
+    IN OUT gctFLOAT * WLimitRms,
+    IN OUT gctBOOL * WLimitRmsDirty,
+#endif
+    IN OUT gcsVERTEXARRAY_STREAM_INFO_PTR StreamInfo,
+    IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+    );
+
+gceSTATUS
+gcoVERTEXARRAY_Bind(
+    IN gcoVERTEXARRAY Vertex,
+    IN gctUINT32 EnableBits,
+    IN gcsVERTEXARRAY_PTR VertexArray,
+    IN gctUINT First,
+    IN gctSIZE_T * Count,
+    IN gceINDEX_TYPE IndexType,
+    IN gcoINDEX IndexObject,
+    IN gctPOINTER IndexMemory,
+    IN OUT gcePRIMITIVE * PrimitiveType,
+#if gcdUSE_WCLIP_PATCH
+    IN OUT gctUINT * PrimitiveCount,
+    IN OUT gctFLOAT * wLimitRms,
+    IN OUT gctBOOL * wLimitDirty
+#else
+    IN OUT gctUINT * PrimitiveCount
+#endif
+    );
+
+/* Frame Database */
+gceSTATUS
+gcoHAL_AddFrameDB(
+    void
+    );
+
+gceSTATUS
+gcoHAL_DumpFrameDB(
+    gctCONST_STRING Filename OPTIONAL
+    );
+
+gceSTATUS
+gcoHAL_InitGPUProfile(
+    void
+    );
+
+gceSTATUS
+gcoHAL_DumpGPUProfile(
+    void
+    );
+
+/******************************************************************************
+**********************gcoBUFOBJ object*****************************************
+*******************************************************************************/
+/* Construct a new gcoBUFOBJ object. */
+gceSTATUS
+gcoBUFOBJ_Construct(
+    IN gcoHAL Hal,
+    IN gceBUFOBJ_TYPE Type,
+    OUT gcoBUFOBJ * BufObj
+    );
+
+/* Destroy a gcoBUFOBJ object. */
+gceSTATUS
+gcoBUFOBJ_Destroy(
+    IN gcoBUFOBJ BufObj
+    );
+
+/* Lock pbo in memory. */
+gceSTATUS
+gcoBUFOBJ_Lock(
+    IN gcoBUFOBJ BufObj,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Memory
+    );
+
+/* Lock pbo in memory. */
+gceSTATUS
+gcoBUFOBJ_FastLock(
+    IN gcoBUFOBJ BufObj,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Memory
+    );
+
+/* Unlock pbo that was previously locked with gcoBUFOBJ_Lock. */
+gceSTATUS
+gcoBUFOBJ_Unlock(
+    IN gcoBUFOBJ BufObj
+    );
+
+/* Free existing pbo buffer. */
+gceSTATUS
+gcoBUFOBJ_Free(
+    IN gcoBUFOBJ BufObj
+    );
+
+/* Upload data into an pbo buffer. */
+gceSTATUS
+gcoBUFOBJ_Upload(
+    IN gcoBUFOBJ BufObj,
+    IN gctCONST_POINTER Buffer,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    IN gceBUFOBJ_USAGE Usage
+    );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoBUFOBJ_IndexBind (
+    IN gcoBUFOBJ Index,
+    IN gceINDEX_TYPE Type,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Count,
+    IN gctUINT   RestartElement
+    );
+
+/* Find min and max index for the index buffer */
+gceSTATUS
+gcoBUFOBJ_IndexGetRange(
+    IN gcoBUFOBJ Index,
+    IN gceINDEX_TYPE Type,
+    IN gctSIZE_T Offset,
+    IN gctUINT32 Count,
+    OUT gctUINT32 * MinimumIndex,
+    OUT gctUINT32 * MaximumIndex
+    );
+
+/*  Sets a buffer object as dirty */
+gceSTATUS
+gcoBUFOBJ_SetDirty(
+    IN gcoBUFOBJ BufObj
+    );
+
+/* Creates a new buffer if needed */
+gceSTATUS
+gcoBUFOBJ_AlignIndexBufferWhenNeeded(
+    IN gcoBUFOBJ BufObj,
+    IN gctSIZE_T Offset,
+    OUT gcoBUFOBJ * AlignedBufObj
+    );
+
+/* Cache operations on whole range */
+gceSTATUS
+gcoBUFOBJ_CPUCacheOperation(
+    IN gcoBUFOBJ BufObj,
+    IN gceCACHEOPERATION Operation
+    );
+
+/* Cache operations on a specified range */
+gceSTATUS
+gcoBUFOBJ_CPUCacheOperation_Range(
+    IN gcoBUFOBJ BufObj,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Length,
+    IN gceCACHEOPERATION Operation
+    );
+
+/* Return size of the bufobj */
+gceSTATUS
+gcoBUFOBJ_GetSize(
+    IN gcoBUFOBJ BufObj,
+    OUT gctSIZE_T_PTR Size
+    );
+
+/* Return memory node of the bufobj */
+gceSTATUS
+gcoBUFOBJ_GetNode(
+    IN gcoBUFOBJ BufObj,
+    OUT gcsSURF_NODE_PTR * Node
+    );
+
+gceSTATUS
+gcoBUFOBJ_ReAllocBufNode(
+    IN gcoBUFOBJ BufObj
+    );
+
+/* Handle GPU cache operations */
+gceSTATUS
+gcoBUFOBJ_SetCPUWrite(
+    gcoBUFOBJ BufObj,
+    gctBOOL Value
+    );
+
+/* Dump buffer. */
+void
+gcoBUFOBJ_Dump(
+    IN gcoBUFOBJ BufObj
+    );
+
+#endif /* gcdENABLE_3D */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_engine_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h
@@ -0,0 +1,1059 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_engine_vg_h_
+#define __gc_hal_engine_vg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gc_hal_types.h"
+
+/******************************************************************************\
+******************************** VG Structures *******************************
+\******************************************************************************/
+
+/**
+**  @ingroup    gcoVG
+**
+**  @brief      Definition of the color ramp used by the gradient paints.
+**
+**  The gcsCOLOR_RAMP structure defines the layout of one single color inside
+**  a color ramp which is used by gradient paints.
+*/
+typedef struct _gcsCOLOR_RAMP
+{
+    /** Value for the color stop. */
+    gctFLOAT        stop;
+
+    /** Red color channel value for the color stop. */
+    gctFLOAT        red;
+
+    /** Green color channel value for the color stop. */
+    gctFLOAT        green;
+
+    /** Blue color channel value for the color stop. */
+    gctFLOAT        blue;
+
+    /** Alpha color channel value for the color stop. */
+    gctFLOAT        alpha;
+}
+gcsCOLOR_RAMP, * gcsCOLOR_RAMP_PTR;
+
+/**
+**  @ingroup    gcoVG
+**
+**  @brief      Definition of the color ramp used by the gradient paints in fixed form.
+**
+**  The gcsCOLOR_RAMP structure defines the layout of one single color inside
+**  a color ramp which is used by gradient paints.
+*/
+typedef struct _gcsFIXED_COLOR_RAMP
+{
+    /** Value for the color stop. */
+    gctFIXED_POINT      stop;
+
+    /** Red color channel value for the color stop. */
+    gctFIXED_POINT      red;
+
+    /** Green color channel value for the color stop. */
+    gctFIXED_POINT      green;
+
+    /** Blue color channel value for the color stop. */
+    gctFIXED_POINT      blue;
+
+    /** Alpha color channel value for the color stop. */
+    gctFIXED_POINT      alpha;
+}
+gcsFIXED_COLOR_RAMP, * gcsFIXED_COLOR_RAMP_PTR;
+
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Rectangle structure used by the gcoVG object.
+**
+**  This structure defines the layout of a rectangle.  Make sure width and
+**  height are larger than 0.
+*/
+typedef struct _gcsVG_RECT * gcsVG_RECT_PTR;
+typedef struct _gcsVG_RECT
+{
+    /** Left location of the rectangle. */
+    gctINT      x;
+
+    /** Top location of the rectangle. */
+    gctINT      y;
+
+    /** Width of the rectangle. */
+    gctINT      width;
+
+    /** Height of the rectangle. */
+    gctINT      height;
+}
+gcsVG_RECT;
+
+/**
+**  @ingroup    gcoVG
+**
+**  @brief      Path command buffer attribute structure.
+**
+**  The gcsPATH_BUFFER_INFO structure contains the specifics about
+**  the layout of the path data command buffer.
+*/
+typedef struct _gcsPATH_BUFFER_INFO * gcsPATH_BUFFER_INFO_PTR;
+typedef struct _gcsPATH_BUFFER_INFO
+{
+    gctUINT     reservedForHead;
+    gctUINT     reservedForTail;
+}
+gcsPATH_BUFFER_INFO;
+
+/**
+**  @ingroup    gcoVG
+**
+**  @brief      Definition of the path data container structure.
+**
+**  The gcsPATH structure defines the layout of the path data container.
+*/
+typedef struct _gcsPATH_DATA * gcsPATH_DATA_PTR;
+typedef struct _gcsPATH_DATA
+{
+    /* Data container in command buffer format. */
+    gcsCMDBUFFER    data;
+
+    /* Path data type. */
+    gcePATHTYPE     dataType;
+}
+gcsPATH_DATA;
+
+
+/******************************************************************************\
+********************************* gcoHAL Object ********************************
+\******************************************************************************/
+
+/* Query path data storage attributes. */
+gceSTATUS
+gcoHAL_QueryPathStorage(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    OUT gcsPATH_BUFFER_INFO_PTR Information
+    );
+
+/* Associate a completion signal with the command buffer. */
+gceSTATUS
+gcoHAL_AssociateCompletion(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcsPATH_DATA_PTR PathData
+    );
+
+/* Release the current command buffer completion signal. */
+gceSTATUS
+gcoHAL_DeassociateCompletion(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcsPATH_DATA_PTR PathData
+    );
+
+/* Verify whether the command buffer is still in use. */
+gceSTATUS
+gcoHAL_CheckCompletion(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcsPATH_DATA_PTR PathData
+    );
+
+/* Wait until the command buffer is no longer in use. */
+gceSTATUS
+gcoHAL_WaitCompletion(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcsPATH_DATA_PTR PathData
+    );
+
+/* Flush the pixel cache. */
+gceSTATUS
+gcoHAL_Flush(
+#if gcdGC355_PROFILER
+    IN gcoHAL Hal,
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth
+#else
+    IN gcoHAL Hal
+#endif
+    );
+
+/* Split a harwdare address into pool and offset. */
+gceSTATUS
+gcoHAL_SplitAddress(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT32 Address,
+    OUT gcePOOL * Pool,
+    OUT gctUINT32 * Offset
+    );
+
+/* Combine pool and offset into a harwdare address. */
+gceSTATUS
+gcoHAL_CombineAddress(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcePOOL Pool,
+    IN gctUINT32 Offset,
+    OUT gctUINT32 * Address
+    );
+
+/* Schedule to free linear video memory allocated. */
+gceSTATUS
+gcoHAL_ScheduleVideoMemory(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT32 Node
+    );
+
+/* Free linear video memory allocated with gcoHAL_AllocateLinearVideoMemory. */
+gceSTATUS
+gcoHAL_FreeVideoMemory(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT32 Node,
+    IN gctBOOL asynchroneous
+    );
+
+/* Query command buffer attributes. */
+gceSTATUS
+gcoHAL_QueryCommandBuffer(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+    );
+/* Allocate and lock linear video memory. */
+gceSTATUS
+gcoHAL_AllocateLinearVideoMemory(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT Size,
+    IN gctUINT Alignment,
+    IN gcePOOL Pool,
+    OUT gctUINT32 * Node,
+    OUT gctUINT32 * Address,
+    OUT gctPOINTER * Memory
+    );
+
+/* Align the specified size accordingly to the hardware requirements. */
+gceSTATUS
+gcoHAL_GetAlignedSurfaceSize(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceSURF_TYPE Type,
+    IN OUT gctUINT32_PTR Width,
+    IN OUT gctUINT32_PTR Height
+    );
+
+gceSTATUS
+gcoHAL_ReserveTask(
+    IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceBLOCK Block,
+    IN gctUINT TaskCount,
+    IN gctUINT32 Bytes,
+    OUT gctPOINTER * Memory
+    );
+/******************************************************************************\
+********************************** gcoVG Object ********************************
+\******************************************************************************/
+
+/** @defgroup gcoVG gcoVG
+**
+**  The gcoVG object abstracts the VG hardware pipe.
+*/
+#if gcdGC355_PROFILER
+void
+gcoVG_ProfilerEnableDisable(
+    IN gcoVG Vg,
+    IN gctUINT enableGetAPITimes,
+    IN gctFILE apiTimeFile
+    );
+
+void
+gcoVG_ProfilerTreeDepth(
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth
+    );
+
+void
+gcoVG_ProfilerSetStates(
+    IN gcoVG Vg,
+    IN gctUINT treeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth
+    );
+#endif
+
+gctBOOL
+gcoVG_IsMaskSupported(
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceSURF_FORMAT Format
+    );
+
+gctBOOL
+gcoVG_IsTargetSupported(
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceSURF_FORMAT Format
+    );
+
+gctBOOL
+gcoVG_IsImageSupported(
+#if gcdGC355_PROFILER
+    IN gcoVG Vg,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceSURF_FORMAT Format
+    );
+
+gctUINT8 gcoVG_PackColorComponent(
+#if gcdGC355_PROFILER
+    gcoVG Vg,
+    gctUINT TreeDepth,
+    gctUINT saveLayerTreeDepth,
+    gctUINT varTreeDepth,
+#endif
+    gctFLOAT Value
+    );
+
+gceSTATUS
+gcoVG_Construct(
+    IN gcoHAL Hal,
+    OUT gcoVG * Vg
+    );
+
+gceSTATUS
+gcoVG_Destroy(
+    IN gcoVG Vg
+#if gcdGC355_PROFILER
+,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth
+#endif
+    );
+
+void
+gcoVG_SetTesselationSize(
+    IN gcoVG Vg,
+    IN gctUINT Width,
+    IN gctUINT Height
+    );
+
+gceSTATUS
+gcoVG_SetTarget(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Target,
+    IN gceORIENTATION orientation
+    );
+
+gceSTATUS
+gcoVG_UnsetTarget(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoVG_SetUserToSurface(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT UserToSurface[9]
+    );
+
+gceSTATUS
+gcoVG_SetSurfaceToImage(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT SurfaceToImage[9]
+    );
+
+gceSTATUS
+gcoVG_EnableMask(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gcoVG_SetMask(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Mask
+    );
+
+gceSTATUS
+gcoVG_UnsetMask(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoVG_FlushMask(
+    IN gcoVG Vg
+#if gcdGC355_PROFILER
+,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth
+#endif
+    );
+
+gceSTATUS
+gcoVG_EnableScissor(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gcoVG_SetScissor(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctSIZE_T RectangleCount,
+    IN gcsVG_RECT_PTR Rectangles
+    );
+
+gceSTATUS
+gcoVG_EnableColorTransform(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gcoVG_SetColorTransform(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT ColorTransform[8]
+    );
+
+gceSTATUS
+gcoVG_SetTileFillColor(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT Red,
+    IN gctFLOAT Green,
+    IN gctFLOAT Blue,
+    IN gctFLOAT Alpha
+    );
+
+gceSTATUS
+gcoVG_SetSolidPaint(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT8 Red,
+    IN gctUINT8 Green,
+    IN gctUINT8 Blue,
+    IN gctUINT8 Alpha
+    );
+
+gceSTATUS
+gcoVG_SetLinearPaint(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT Constant,
+    IN gctFLOAT StepX,
+    IN gctFLOAT StepY
+    );
+
+gceSTATUS
+gcoVG_SetRadialPaint(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT LinConstant,
+    IN gctFLOAT LinStepX,
+    IN gctFLOAT LinStepY,
+    IN gctFLOAT RadConstant,
+    IN gctFLOAT RadStepX,
+    IN gctFLOAT RadStepY,
+    IN gctFLOAT RadStepXX,
+    IN gctFLOAT RadStepYY,
+    IN gctFLOAT RadStepXY
+    );
+
+gceSTATUS
+gcoVG_SetPatternPaint(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctFLOAT UConstant,
+    IN gctFLOAT UStepX,
+    IN gctFLOAT UStepY,
+    IN gctFLOAT VConstant,
+    IN gctFLOAT VStepX,
+    IN gctFLOAT VStepY,
+    IN gctBOOL Linear
+    );
+
+gceSTATUS
+gcoVG_SetColorRamp(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF ColorRamp,
+    IN gceTILE_MODE ColorRampSpreadMode
+    );
+
+gceSTATUS
+gcoVG_SetPattern(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctINT32 width,
+    IN gctINT32 height,
+    IN gcoSURF Pattern,
+    IN gceTILE_MODE TileMode,
+    IN gceIMAGE_FILTER Filter
+    );
+
+gceSTATUS
+gcoVG_SetImageMode(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceVG_IMAGE Mode
+    );
+
+gceSTATUS
+gcoVG_SetBlendMode(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceVG_BLEND Mode
+    );
+
+gceSTATUS
+gcoVG_SetRenderingQuality(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceRENDER_QUALITY Quality
+    );
+
+gceSTATUS
+gcoVG_SetFillRule(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceFILL_RULE FillRule
+    );
+
+gceSTATUS
+gcoVG_FinalizePath(
+    IN gcoVG Vg,
+    IN gcsPATH_DATA_PTR PathData
+    );
+
+gceSTATUS
+gcoVG_Clear(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctINT X,
+    IN gctINT Y,
+    IN gctINT Width,
+    IN gctINT Height
+    );
+
+gceSTATUS
+gcoVG_DrawPath(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcsPATH_DATA_PTR PathData,
+    IN gctFLOAT Scale,
+    IN gctFLOAT Bias,
+#if gcdMOVG
+    IN gctUINT32 Width,
+    IN gctUINT32 Height,
+    IN gctFLOAT *Bounds,
+#endif
+    IN gctBOOL SoftwareTesselation
+    );
+
+gceSTATUS
+gcoVG_DrawImage(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gceORIENTATION orientation,
+    IN gcoSURF Source,
+    IN gcsPOINT_PTR SourceOrigin,
+    IN gcsPOINT_PTR TargetOrigin,
+    IN gcsSIZE_PTR SourceSize,
+    IN gctINT SourceX,
+    IN gctINT SourceY,
+    IN gctINT TargetX,
+    IN gctINT TargetY,
+    IN gctINT Width,
+    IN gctINT Height,
+    IN gctBOOL Mask,
+    IN gctBOOL isDrawImage
+    );
+
+gceSTATUS
+gcoVG_TesselateImage(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Image,
+    IN gcsVG_RECT_PTR Rectangle,
+    IN gceIMAGE_FILTER Filter,
+    IN gctBOOL Mask,
+#if gcdMOVG
+    IN gctBOOL SoftwareTesselation,
+    IN gceVG_BLEND BlendMode,
+    IN gctINT Width,
+    IN gctINT Height
+#else
+    IN gctBOOL SoftwareTesselation
+#endif
+    );
+
+gceSTATUS
+gcoVG_DrawSurfaceToImage(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Image,
+    IN const gcsVG_RECT_PTR SrcRectangle,
+    IN const gctFLOAT  DstBounds[4],
+    IN const gctFLOAT DstPoints[8],
+    IN const gctFLOAT ImgMatrix[9],
+    IN const gctFLOAT RectMatrix[9],
+    IN gceIMAGE_FILTER Filter,
+    IN gctBOOL Mask,
+    IN gctBOOL FirstTime
+#if gcdMOVG
+,
+    IN gctINT   TSWidth,
+    IN gctINT   TSHeight
+#endif
+    );
+
+gceSTATUS
+gcoVG_DrawSurfaceToImageMasked(
+    IN gcoVG Vg,
+    IN gcoSURF Image,
+    IN gcsVG_RECT_PTR SrcRect,
+    IN gctINT  X,
+    IN gctINT  Y,
+    IN gctINT  Width,
+    IN gctINT  Height,
+    IN const gctFLOAT Matrix[9]
+    );
+
+gceSTATUS
+gcoVG_Blit(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Source,
+    IN gcoSURF Target,
+    IN gcsVG_RECT_PTR SrcRect,
+    IN gcsVG_RECT_PTR TrgRect,
+    IN gceIMAGE_FILTER Filter,
+    IN gceVG_BLEND Mode
+    );
+
+gceSTATUS
+gcoVG_ColorMatrix(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Source,
+    IN gcoSURF Target,
+    IN const gctFLOAT * Matrix,
+    IN gceCHANNEL ColorChannels,
+    IN gctBOOL FilterLinear,
+    IN gctBOOL FilterPremultiplied,
+    IN gcsPOINT_PTR SourceOrigin,
+    IN gcsPOINT_PTR TargetOrigin,
+    IN gctINT Width,
+    IN gctINT Height
+    );
+
+gceSTATUS
+gcoVG_SeparableConvolve(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Source,
+    IN gcoSURF Target,
+    IN gctINT KernelWidth,
+    IN gctINT KernelHeight,
+    IN gctINT ShiftX,
+    IN gctINT ShiftY,
+    IN const gctINT16 * KernelX,
+    IN const gctINT16 * KernelY,
+    IN gctFLOAT Scale,
+    IN gctFLOAT Bias,
+    IN gceTILE_MODE TilingMode,
+    IN gctFLOAT_PTR FillColor,
+    IN gceCHANNEL ColorChannels,
+    IN gctBOOL FilterLinear,
+    IN gctBOOL FilterPremultiplied,
+    IN gcsPOINT_PTR SourceOrigin,
+    IN gcsPOINT_PTR TargetOrigin,
+    IN gcsSIZE_PTR SourceSize,
+    IN gctINT Width,
+    IN gctINT Height
+    );
+
+gceSTATUS
+gcoVG_GaussianBlur(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gcoSURF Source,
+    IN gcoSURF Target,
+    IN gctFLOAT StdDeviationX,
+    IN gctFLOAT StdDeviationY,
+    IN gceTILE_MODE TilingMode,
+    IN gctFLOAT_PTR FillColor,
+    IN gceCHANNEL ColorChannels,
+    IN gctBOOL FilterLinear,
+    IN gctBOOL FilterPremultiplied,
+    IN gcsPOINT_PTR SourceOrigin,
+    IN gcsPOINT_PTR TargetOrigin,
+    IN gcsSIZE_PTR SourceSize,
+    IN gctINT Width,
+    IN gctINT Height
+    );
+
+gceSTATUS
+gcoVG_EnableDither(
+    IN gcoVG Vg,
+#if gcdGC355_PROFILER
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctBOOL Enable
+    );
+
+/* Color Key States. */
+gceSTATUS
+gcoVG_SetColorKey(
+    IN gcoVG        Vg,
+#if gcdGC355_PROFILER
+    IN gcsPROFILERFUNCNODE *DList,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT32*    Values,
+    IN gctBOOL *    Enables
+);
+
+/* Index Color States. */
+gceSTATUS
+gcoVG_SetColorIndexTable(
+    IN gcoVG        Vg,
+#if gcdGC355_PROFILER
+    IN gcsPROFILERFUNCNODE *DList,
+    IN gctUINT TreeDepth,
+    IN gctUINT saveLayerTreeDepth,
+    IN gctUINT varTreeDepth,
+#endif
+    IN gctUINT32*    Values,
+    IN gctINT32      Count
+);
+
+gceSTATUS
+gcoVG_SetYUV2RGBStdCust(
+    IN gcoVG            Vg,
+    IN gctBOOL          YUV2RGBStdCust
+    );
+
+gceSTATUS
+gcoVG_SetYUV2RGB(
+    IN gcoVG            Vg,
+    IN gctFLOAT         *coef,
+    IN gctFLOAT         *offset,
+    IN gctBOOL          *cfg
+);
+
+gceSTATUS
+gcoVG_SetRGB2YUVParameters(
+    IN gcoVG            Vg,
+    IN gctFLOAT         *coef,
+    IN gctFLOAT         *offset,
+    IN gctBOOL          *cfg
+);
+
+/* VG RS feature support: YUV format conversion. */
+gceSTATUS
+gcoVG_Resolve(
+    IN gcoVG        Vg,
+    IN gcoSURF      Source,
+    IN gcoSURF      Target,
+    IN gctINT       SX,
+    IN gctINT       SY,
+    IN gctINT       DX,
+    IN gctINT       DY,
+    IN gctINT       Width,
+    IN gctINT       Height,
+    IN gctINT       Src_uv,
+    IN gctINT       Src_standard,
+    IN gctINT       Dst_uv,
+    IN gctINT       Dst_standard,
+    IN gctINT       Dst_alpha,
+    IN gctBOOL      Dst_standard_cust
+);
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __gc_hal_vg_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h
@@ -0,0 +1,2224 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_enum_h_
+#define __gc_hal_enum_h_
+
+#include "gc_hal_options.h"
+#include "shared/gc_hal_enum_shared.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* dummy draw type.*/
+typedef enum _gceDUMMY_DRAW_TYPE
+{
+    gcvDUMMY_DRAW_INVALID = 0,
+    gcvDUMMY_DRAW_GC400,
+    gcvDUMMY_DRAW_V60,
+}
+gceDUMMY_DRAW_TYPE;
+
+/* Option Set*/
+typedef enum _gceOPTION
+{
+    /* HW setting. */
+    gcvOPTION_PREFER_ZCONVERT_BYPASS = 0,
+    gcvOPTION_PREFER_TILED_DISPLAY_BUFFER = 1,
+    gcvOPTION_PREFER_GUARDBAND = 2,
+    gcvOPTION_PREFER_TPG_TRIVIALMODEL = 3,
+    gcvOPTION_PREFER_RA_DEPTH_WRITE = 4,
+    gcvOPTION_PREFER_USC_RECONFIG = 5,
+    gcvOPTION_PREFER_DISALBE_HZ = 6,
+
+    /* SW options */
+    gcvOPTION_HW_NULL = 50,
+    gcvOPTION_PRINT_OPTION = 51,
+    gcvOPTION_KERNEL_FENCE = 52,
+    gcvOPTION_ASYNC_PIPE = 53,
+    gcvOPTION_FBO_PREFER_MEM = 54,
+    gcvOPTION_GPU_TEX_UPLOAD = 55,
+    gcvOPTION_GPU_BUFOBJ_UPLOAD = 56,
+    gcvOPTION_NO_Y_INVERT = 60,
+
+    /* OCL option */
+    gcvOPTION_OCL_ASYNC_BLT = 200,
+    gcvOPTION_OCL_IN_THREAD,
+    gcvOPTION_COMPRESSION_DEC400,
+    gcvOPTION_OCL_VIR_SHADER,
+    gcvOPTION_OCL_USE_MULTI_DEVICES,
+
+#if gcdUSE_VX
+    /* OVX options that HAL could access */
+    gcvOPTION_OVX_ENABLE_NN_ZDP3 = 500,
+    gcvOPTION_OVX_ENABLE_NN_ZDP6,
+    gcvOPTION_OVX_ENABLE_NN_STRIDE,
+    gcvOPTION_OVX_USE_MULTI_DEVICES,
+    gcvOPTION_OVX_ENABLE_NN_DDR_BURST_SIZE_256B,
+    gcvOPTION_OVX_ENABLE_NN_DDR_BURST_SIZE_64B,
+#endif
+    /* Insert option above this comment only */
+    gcvOPTION_COUNT                     /* Not a OPTION*/
+}
+gceOPTION;
+
+typedef enum _gceFRAMEINFO
+{
+    /* Total frame count in one run */
+    gcvFRAMEINFO_FRAME_NUM       = 0,
+    /* Total draw count in current frame, including draw/compute */
+    gcvFRAMEINFO_DRAW_NUM        = 1,
+    /* Total compute count in current frame, subset of drawNum */
+    gcvFRAMEINFO_COMPUTE_NUM     = 2,
+    /* Total dual16 draw/compute count in current frame, subset of drawNum */
+    gcvFRAMEINFO_DUAL16_NUM      = 3,
+    /* Current programID is being set. only valid for ES20 driver right now */
+    gcvFRAMEINFO_PROGRAM_ID     = 4,
+
+    gcvFRAMEINFO_COUNT,
+}
+gceFRAMEINFO;
+
+typedef enum _gceFRAMEINFO_OP
+{
+    gcvFRAMEINFO_OP_INC       = 0,
+    gcvFRAMEINFO_OP_DEC       = 1,
+    gcvFRAMEINFO_OP_ZERO      = 2,
+    gcvFRAMEINFO_OP_GET       = 3,
+    gcvFRAMEINFO_OP_SET       = 4,
+    gcvFRAMEINFO_OP_COUNT,
+}
+gceFRAMEINFO_OP;
+
+typedef enum _gceSURF_USAGE
+{
+    gcvSURF_USAGE_UNKNOWN,
+    gcvSURF_USAGE_RESOLVE_AFTER_CPU,
+    gcvSURF_USAGE_RESOLVE_AFTER_3D
+}
+gceSURF_USAGE;
+
+typedef enum _gceSURF_COLOR_SPACE
+{
+    gcvSURF_COLOR_SPACE_UNKNOWN,
+    gcvSURF_COLOR_SPACE_LINEAR,
+    gcvSURF_COLOR_SPACE_NONLINEAR,
+}
+gceSURF_COLOR_SPACE;
+
+typedef enum _gceSURF_COLOR_TYPE
+{
+    gcvSURF_COLOR_UNKNOWN = 0,
+    gcvSURF_COLOR_LINEAR        = 0x01,
+    gcvSURF_COLOR_ALPHA_PRE     = 0x02,
+}
+gceSURF_COLOR_TYPE;
+
+/* Rotation. */
+typedef enum _gceSURF_ROTATION
+{
+    gcvSURF_0_DEGREE = 0,
+    gcvSURF_90_DEGREE,
+    gcvSURF_180_DEGREE,
+    gcvSURF_270_DEGREE,
+    gcvSURF_FLIP_X,
+    gcvSURF_FLIP_Y,
+
+    gcvSURF_POST_FLIP_X = 0x40000000,
+    gcvSURF_POST_FLIP_Y = 0x80000000,
+}
+gceSURF_ROTATION;
+
+/* Surface flag */
+typedef enum _gceSURF_FLAG
+{
+    /* None flag */
+    gcvSURF_FLAG_NONE                = 0x0,
+    /* content is preserved after swap */
+    gcvSURF_FLAG_CONTENT_PRESERVED   = 0x1,
+    /* content is updated after swap*/
+    gcvSURF_FLAG_CONTENT_UPDATED     = 0x2,
+    /* content is y inverted */
+    gcvSURF_FLAG_CONTENT_YINVERTED   = 0x4,
+    /* surface has multiple nodes */
+    gcvSURF_FLAG_MULTI_NODE          = 0x8,
+    /* surface no need do dither when resovle*/
+    gcvSURF_FLAG_DITHER_DISABLED     = 0x10,
+}
+gceSURF_FLAG;
+
+typedef enum _gceMIPMAP_IMAGE_FORMAT
+{
+    gcvUNKNOWN_MIPMAP_IMAGE_FORMAT  = -2
+}
+gceMIPMAP_IMAGE_FORMAT;
+
+typedef enum _gceIMAGE_MEM_TYPE
+{
+    gcvIMAGE_MEM_DEFAULT,
+    gcvIMAGE_MEM_HOST_PTR,
+    gcvIMAGE_MEM_HOST_PTR_UNCACHED,
+    gcvIMAGE_MEM_HOST_PHY_PTR,
+    gcvIMAGE_MEM_HOST_PHY_PTR_UNCACHED,
+}
+gceIMAGE_MEM_TYPE;
+
+typedef enum _gceSURF_YUV_COLOR_SPACE
+{
+    gcvSURF_ITU_REC601,
+    gcvSURF_ITU_REC709,
+    gcvSURF_ITU_REC2020,
+}
+gceSURF_YUV_COLOR_SPACE;
+
+typedef enum _gceSURF_YUV_SAMPLE_RANGE
+{
+    gcvSURF_YUV_FULL_RANGE,
+    gcvSURF_YUV_NARROW_RANGE,
+}
+gceSURF_YUV_SAMPLE_RANGE;
+
+typedef enum _gceSURF_YUV_CHROMA_SITING
+{
+    gcvSURF_YUV_CHROMA_SITING_0,
+    gcvSURF_YUV_CHROMA_SITING_0_5,
+}
+gceSURF_YUV_CHROMA_SITING;
+
+typedef enum _gceSURF_INFO_TYPE
+{
+    gcvSURF_INFO_UNKNOWN   = 0,
+    gcvSURF_INFO_LAYERSIZE = 1,
+    gcvSURF_INFO_SLICESIZE = 2,
+}
+gceSURF_INFO_TYPE;
+
+/* Format modifiers. */
+typedef enum _gceSURF_FORMAT_MODE
+{
+    gcvSURF_FORMAT_OCL          = 0x80000000,
+    gcvSURF_FORMAT_PATCH_BORDER = 0x40000000,
+}
+gceSURF_FORMAT_MODE;
+
+/* Pixel swizzle modes. */
+typedef enum _gceSURF_SWIZZLE
+{
+    gcvSURF_NOSWIZZLE = 0,
+    gcvSURF_ARGB,
+    gcvSURF_ABGR,
+    gcvSURF_RGBA,
+    gcvSURF_BGRA
+}
+gceSURF_SWIZZLE;
+
+/* Transparency modes. */
+typedef enum _gceSURF_TRANSPARENCY
+{
+    /* Valid only for PE 1.0 */
+    gcvSURF_OPAQUE = 0,
+    gcvSURF_SOURCE_MATCH,
+    gcvSURF_SOURCE_MASK,
+    gcvSURF_PATTERN_MASK,
+}
+gceSURF_TRANSPARENCY;
+
+/* Surface Alignment. */
+typedef enum _gceSURF_ALIGNMENT
+{
+    gcvSURF_FOUR = 0,
+    gcvSURF_SIXTEEN,
+    gcvSURF_SUPER_TILED,
+    gcvSURF_SPLIT_TILED,
+    gcvSURF_SPLIT_SUPER_TILED
+}
+gceSURF_ALIGNMENT;
+
+/* Surface Addressing. */
+typedef enum _gceSURF_ADDRESSING
+{
+    gcvSURF_NO_STRIDE_TILED = 0,
+    gcvSURF_NO_STRIDE_LINEAR,
+    gcvSURF_STRIDE_TILED,
+    gcvSURF_STRIDE_LINEAR
+}
+gceSURF_ADDRESSING;
+
+/* Transparency modes. */
+typedef enum _gce2D_TRANSPARENCY
+{
+    /* Valid only for PE 2.0 */
+    gcv2D_OPAQUE = 0,
+    gcv2D_KEYED,
+    gcv2D_MASKED
+}
+gce2D_TRANSPARENCY;
+
+/* Mono packing modes. */
+typedef enum _gceSURF_MONOPACK
+{
+    gcvSURF_PACKED8 = 0,
+    gcvSURF_PACKED16,
+    gcvSURF_PACKED32,
+    gcvSURF_UNPACKED,
+}
+gceSURF_MONOPACK;
+
+/* Blending modes. */
+typedef enum _gceSURF_BLEND_MODE
+{
+    /* Porter-Duff blending modes.                   */
+    /*                         Fsrc      Fdst        */
+    gcvBLEND_CLEAR = 0, /* 0         0           */
+    gcvBLEND_SRC, /* 1         0           */
+    gcvBLEND_DST, /* 0         1           */
+    gcvBLEND_SRC_OVER_DST, /* 1         1 - Asrc    */
+    gcvBLEND_DST_OVER_SRC, /* 1 - Adst  1           */
+    gcvBLEND_SRC_IN_DST, /* Adst      0           */
+    gcvBLEND_DST_IN_SRC, /* 0         Asrc        */
+    gcvBLEND_SRC_OUT_DST, /* 1 - Adst  0           */
+    gcvBLEND_DST_OUT_SRC, /* 0         1 - Asrc    */
+    gcvBLEND_SRC_ATOP_DST, /* Adst      1 - Asrc    */
+    gcvBLEND_DST_ATOP_SRC, /* 1 - Adst  Asrc        */
+    gcvBLEND_SRC_XOR_DST, /* 1 - Adst  1 - Asrc    */
+
+    /* Special blending modes.                       */
+    gcvBLEND_SET, /* DST = 1               */
+    gcvBLEND_SUB            /* DST = DST * (1 - SRC) */
+}
+gceSURF_BLEND_MODE;
+
+/* Per-pixel alpha modes. */
+typedef enum _gceSURF_PIXEL_ALPHA_MODE
+{
+    gcvSURF_PIXEL_ALPHA_STRAIGHT = 0,
+    gcvSURF_PIXEL_ALPHA_INVERSED
+}
+gceSURF_PIXEL_ALPHA_MODE;
+
+/* Global alpha modes. */
+typedef enum _gceSURF_GLOBAL_ALPHA_MODE
+{
+    gcvSURF_GLOBAL_ALPHA_OFF = 0,
+    gcvSURF_GLOBAL_ALPHA_ON,
+    gcvSURF_GLOBAL_ALPHA_SCALE
+}
+gceSURF_GLOBAL_ALPHA_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gceSURF_PIXEL_COLOR_MODE
+{
+    gcvSURF_COLOR_STRAIGHT = 0,
+    gcvSURF_COLOR_MULTIPLY
+}
+gceSURF_PIXEL_COLOR_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE
+{
+    gcv2D_COLOR_MULTIPLY_DISABLE = 0,
+    gcv2D_COLOR_MULTIPLY_ENABLE
+}
+gce2D_PIXEL_COLOR_MULTIPLY_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE
+{
+    gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE = 0,
+    gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA,
+    gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR
+}
+gce2D_GLOBAL_COLOR_MULTIPLY_MODE;
+
+/* Alpha blending factor modes. */
+typedef enum _gceSURF_BLEND_FACTOR_MODE
+{
+    gcvSURF_BLEND_ZERO = 0,
+    gcvSURF_BLEND_ONE,
+    gcvSURF_BLEND_STRAIGHT,
+    gcvSURF_BLEND_INVERSED,
+    gcvSURF_BLEND_COLOR,
+    gcvSURF_BLEND_COLOR_INVERSED,
+    gcvSURF_BLEND_SRC_ALPHA_SATURATED,
+    gcvSURF_BLEND_STRAIGHT_NO_CROSS,
+    gcvSURF_BLEND_INVERSED_NO_CROSS,
+    gcvSURF_BLEND_COLOR_NO_CROSS,
+    gcvSURF_BLEND_COLOR_INVERSED_NO_CROSS,
+    gcvSURF_BLEND_SRC_ALPHA_SATURATED_CROSS
+}
+gceSURF_BLEND_FACTOR_MODE;
+
+/* Alpha blending porter duff rules. */
+typedef enum _gce2D_PORTER_DUFF_RULE
+{
+    gcvPD_CLEAR = 0,
+    gcvPD_SRC,
+    gcvPD_SRC_OVER,
+    gcvPD_DST_OVER,
+    gcvPD_SRC_IN,
+    gcvPD_DST_IN,
+    gcvPD_SRC_OUT,
+    gcvPD_DST_OUT,
+    gcvPD_SRC_ATOP,
+    gcvPD_DST_ATOP,
+    gcvPD_ADD,
+    gcvPD_XOR,
+    gcvPD_DST
+}
+gce2D_PORTER_DUFF_RULE;
+
+/* Alpha blending factor modes. */
+typedef enum _gce2D_YUV_COLOR_MODE
+{
+    gcv2D_YUV_601= 0,
+    gcv2D_YUV_709,
+    gcv2D_YUV_USER_DEFINED,
+    gcv2D_YUV_USER_DEFINED_CLAMP,
+
+    /* Default setting is for src. gcv2D_YUV_DST
+        can be ORed to set dst.
+    */
+    gcv2D_YUV_DST = 0x80000000,
+}
+gce2D_YUV_COLOR_MODE;
+
+/* Nature rotation rules. */
+typedef enum _gce2D_NATURE_ROTATION
+{
+    gcvNR_0_DEGREE = 0,
+    gcvNR_LEFT_90_DEGREE,
+    gcvNR_RIGHT_90_DEGREE,
+    gcvNR_180_DEGREE,
+    gcvNR_FLIP_X,
+    gcvNR_FLIP_Y,
+    gcvNR_TOTAL_RULE,
+}
+gce2D_NATURE_ROTATION;
+
+typedef enum _gce2D_COMMAND
+{
+    gcv2D_CLEAR = 0,
+    gcv2D_LINE,
+    gcv2D_BLT,
+    gcv2D_STRETCH,
+    gcv2D_HOR_FILTER,
+    gcv2D_VER_FILTER,
+    gcv2D_MULTI_SOURCE_BLT,
+    gcv2D_FILTER_BLT,
+}
+gce2D_COMMAND;
+
+typedef enum _gce2D_TILE_STATUS_CONFIG
+{
+    gcv2D_TSC_DISABLE       = 0,
+    gcv2D_TSC_ENABLE        = 0x00000001,
+    gcv2D_TSC_COMPRESSED    = 0x00000002,
+    gcv2D_TSC_DOWN_SAMPLER  = 0x00000004,
+    gcv2D_TSC_2D_COMPRESSED = 0x00000008,
+
+    gcv2D_TSC_DEC_COMPRESSED = 0x00000020,
+    gcv2D_TSC_DEC_TPC        = 0x00000040,
+    gcv2D_TSC_DEC_TPC_COMPRESSED = 0x00000080,
+
+    gcv2D_TSC_V4_COMPRESSED      = 0x00000100,
+    gcv2D_TSC_V4_COMPRESSED_256B = 0x00000200 | gcv2D_TSC_V4_COMPRESSED,
+
+    gcv2D_TSC_DEC_TPC_TILED  = gcv2D_TSC_DEC_COMPRESSED | gcv2D_TSC_DEC_TPC,
+    gcv2D_TSC_DEC_TPC_TILED_COMPRESSED = gcv2D_TSC_DEC_TPC_TILED | gcv2D_TSC_DEC_TPC_COMPRESSED,
+
+    gcv2D_TSC_TPC_COMPRESSED     = 0x00001000,
+    gcv2D_TSC_TPC_COMPRESSED_V10 = gcv2D_TSC_TPC_COMPRESSED | 0x00000400,
+    gcv2D_TSC_TPC_COMPRESSED_V11 = gcv2D_TSC_TPC_COMPRESSED | 0x00000800,
+}
+gce2D_TILE_STATUS_CONFIG;
+
+typedef enum _gce2D_DEC400_MINOR_VERSION
+{
+    gcv2D_DEC400_MINOR_V1 = 1,
+    gcv2D_DEC400_MINOR_V2 = 2,
+    gcv2D_DEC400_MINOR_V3 = 3,
+}
+gce2D_DEC400_MINOR_VERSION;
+
+typedef enum _gce2D_QUERY
+{
+    gcv2D_QUERY_RGB_ADDRESS_MIN_ALIGN       = 0,
+    gcv2D_QUERY_RGB_STRIDE_MIN_ALIGN,
+    gcv2D_QUERY_YUV_ADDRESS_MIN_ALIGN,
+    gcv2D_QUERY_YUV_STRIDE_MIN_ALIGN,
+    gcv2D_QUERY_DEC400_MINOR_VERSION,
+}
+gce2D_QUERY;
+
+typedef enum _gce2D_SUPER_TILE_VERSION
+{
+    gcv2D_SUPER_TILE_VERSION_V1       = 1,
+    gcv2D_SUPER_TILE_VERSION_V2       = 2,
+    gcv2D_SUPER_TILE_VERSION_V3       = 3,
+}
+gce2D_SUPER_TILE_VERSION;
+
+typedef enum _gce2D_STATE
+{
+    gcv2D_STATE_SPECIAL_FILTER_MIRROR_MODE       = 1,
+    gcv2D_STATE_SUPER_TILE_VERSION,
+    gcv2D_STATE_EN_GAMMA,
+    gcv2D_STATE_DE_GAMMA,
+    gcv2D_STATE_MULTI_SRC_BLIT_UNIFIED_DST_RECT,
+    gcv2D_STATE_MULTI_SRC_BLIT_BILINEAR_FILTER,
+    gcv2D_STATE_PROFILE_ENABLE,
+    gcv2D_STATE_XRGB_ENABLE,
+
+    gcv2D_STATE_ARRAY_EN_GAMMA                   = 0x10001,
+    gcv2D_STATE_ARRAY_DE_GAMMA,
+    gcv2D_STATE_ARRAY_CSC_YUV_TO_RGB,
+    gcv2D_STATE_ARRAY_CSC_RGB_TO_YUV,
+
+    gcv2D_STATE_DEC_TPC_NV12_10BIT              = 0x20001,
+    gcv2D_STATE_ARRAY_YUV_SRC_TILE_STATUS_ADDR,
+    gcv2D_STATE_ARRAY_YUV_DST_TILE_STATUS_ADDR,
+}
+gce2D_STATE;
+
+typedef enum _gce2D_STATE_PROFILE
+{
+    gcv2D_STATE_PROFILE_NONE    = 0x0,
+    gcv2D_STATE_PROFILE_COMMAND = 0x1,
+    gcv2D_STATE_PROFILE_SURFACE = 0x2,
+    gcv2D_STATE_PROFILE_ALL     = 0xFFFF,
+}
+gce2D_STATE_PROFILE;
+
+/* Texture object types */
+typedef enum _gceTEXTURE_TYPE
+{
+    gcvTEXTURE_UNKNOWN = 0,
+    gcvTEXTURE_1D,
+    gcvTEXTURE_2D,
+    gcvTEXTURE_3D,
+    gcvTEXTURE_CUBEMAP,
+    gcvTEXTURE_1D_ARRAY,
+    gcvTEXTURE_2D_ARRAY,
+    gcvTEXTURE_2D_MS,
+    gcvTEXTURE_2D_MS_ARRAY,
+    gcvTEXTURE_CUBEMAP_ARRAY,
+    gcvTEXTURE_EXTERNAL
+}
+gceTEXTURE_TYPE;
+
+#if gcdENABLE_3D
+/* Texture functions. */
+typedef enum _gceTEXTURE_FUNCTION
+{
+    gcvTEXTURE_DUMMY = 0,
+    gcvTEXTURE_REPLACE = 0,
+    gcvTEXTURE_MODULATE,
+    gcvTEXTURE_ADD,
+    gcvTEXTURE_ADD_SIGNED,
+    gcvTEXTURE_INTERPOLATE,
+    gcvTEXTURE_SUBTRACT,
+    gcvTEXTURE_DOT3
+}
+gceTEXTURE_FUNCTION;
+
+/* Texture sources. */
+typedef enum _gceTEXTURE_SOURCE
+{
+    gcvCOLOR_FROM_TEXTURE = 0,
+    gcvCOLOR_FROM_CONSTANT_COLOR,
+    gcvCOLOR_FROM_PRIMARY_COLOR,
+    gcvCOLOR_FROM_PREVIOUS_COLOR
+}
+gceTEXTURE_SOURCE;
+
+/* Texture source channels. */
+typedef enum _gceTEXTURE_CHANNEL
+{
+    gcvFROM_COLOR = 0,
+    gcvFROM_ONE_MINUS_COLOR,
+    gcvFROM_ALPHA,
+    gcvFROM_ONE_MINUS_ALPHA
+}
+gceTEXTURE_CHANNEL;
+#endif /* gcdENABLE_3D */
+
+/* Filter types. */
+typedef enum _gceFILTER_TYPE
+{
+    gcvFILTER_SYNC = 0,
+    gcvFILTER_BLUR,
+    gcvFILTER_USER
+}
+gceFILTER_TYPE;
+
+/* Filter pass types. */
+typedef enum _gceFILTER_PASS_TYPE
+{
+    gcvFILTER_HOR_PASS = 0,
+    gcvFILTER_VER_PASS
+}
+gceFILTER_PASS_TYPE;
+
+/* Endian hints. */
+typedef enum _gceENDIAN_HINT
+{
+    gcvENDIAN_NO_SWAP    = 0,
+    gcvENDIAN_SWAP_WORD  = 1,
+    gcvENDIAN_SWAP_DWORD = 2,
+    gcvENDIAN_SWAP_QWORD = 3,
+}
+gceENDIAN_HINT;
+
+/* Tiling modes. */
+typedef enum _gceTILING
+{
+    gcvINVALIDTILED = 0x0, /* Invalid tiling */
+    /* Tiling basic modes enum'ed in power of 2. */
+    gcvLINEAR      = 0x1, /* No    tiling. */
+    gcvTILED       = 0x2, /* 4x4   tiling. */
+    gcvSUPERTILED  = 0x4, /* 64x64 tiling. */
+    gcvMINORTILED  = 0x8, /* 2x2   tiling. */
+
+    /* Tiling special layouts. */
+    gcvTILING_SPLIT_BUFFER = 0x10,
+    gcvTILING_X_MAJOR      = 0x20,
+    gcvTILING_Y_MAJOR      = 0x40,
+    gcvTILING_SWAP         = 0x80,
+
+    /* Tiling combination layouts. */
+    gcvMULTI_TILED      = gcvTILED
+                        | gcvTILING_SPLIT_BUFFER,
+
+    gcvMULTI_SUPERTILED = gcvSUPERTILED
+                        | gcvTILING_SPLIT_BUFFER,
+
+    gcvYMAJOR_SUPERTILED = gcvSUPERTILED
+                         | gcvTILING_Y_MAJOR,
+
+    gcvTILED_8X4           = 0x0100,
+    gcvTILED_4X8           = 0x0100 | gcvTILING_SWAP,
+    gcvTILED_8X8           = 0x0200,
+    gcvTILED_16X4          = 0x0400,
+    gcvTILED_32X4          = 0x0800,
+    gcvTILED_64X4          = 0x1000,
+
+    gcvTILED_8X8_XMAJOR    = gcvTILED_8X8 | gcvTILING_X_MAJOR,
+    gcvTILED_8X8_YMAJOR    = gcvTILED_8X8 | gcvTILING_Y_MAJOR,
+
+    gcvSUPERTILED_128B     = 0x10000 | gcvSUPERTILED,
+    gcvSUPERTILED_256B     = 0x20000 | gcvSUPERTILED,
+}
+gceTILING;
+
+typedef enum _gceCACHE_MODE
+{
+    gcvCACHE_NONE,
+    gcvCACHE_128,
+    gcvCACHE_256,
+}
+gceCACHE_MODE;
+
+#define DEFAULT_CACHE_MODE    gcvCACHE_256
+
+/* 2D pattern type. */
+typedef enum _gce2D_PATTERN
+{
+    gcv2D_PATTERN_SOLID = 0,
+    gcv2D_PATTERN_MONO,
+    gcv2D_PATTERN_COLOR,
+    gcv2D_PATTERN_INVALID
+}
+gce2D_PATTERN;
+
+/* 2D source type. */
+typedef enum _gce2D_SOURCE
+{
+    gcv2D_SOURCE_MASKED = 0,
+    gcv2D_SOURCE_MONO,
+    gcv2D_SOURCE_COLOR,
+    gcv2D_SOURCE_INVALID
+}
+gce2D_SOURCE;
+
+typedef enum _gceMMU_MODE
+{
+    gcvMMU_MODE_1K,
+    gcvMMU_MODE_4K,
+} gceMMU_MODE;
+
+/* gcdDUMP message type. */
+typedef enum _gceDEBUG_MESSAGE_TYPE
+{
+    gcvMESSAGE_TEXT,
+    gcvMESSAGE_DUMP
+}
+gceDEBUG_MESSAGE_TYPE;
+
+/* Shading format. */
+typedef enum _gceSHADING
+{
+    gcvSHADING_SMOOTH,
+    gcvSHADING_FLAT_D3D,
+    gcvSHADING_FLAT_OPENGL,
+}
+gceSHADING;
+
+/* Culling modes. */
+typedef enum _gceCULL
+{
+    gcvCULL_NONE,
+    gcvCULL_CCW,
+    gcvCULL_CW,
+}
+gceCULL;
+
+/* Fill modes. */
+typedef enum _gceFILL
+{
+    gcvFILL_POINT,
+    gcvFILL_WIRE_FRAME,
+    gcvFILL_SOLID,
+}
+gceFILL;
+
+/* Compare modes. */
+typedef enum _gceCOMPARE
+{
+    gcvCOMPARE_INVALID = 0,
+    gcvCOMPARE_NEVER,
+    gcvCOMPARE_NOT_EQUAL,
+    gcvCOMPARE_LESS,
+    gcvCOMPARE_LESS_OR_EQUAL,
+    gcvCOMPARE_EQUAL,
+    gcvCOMPARE_GREATER,
+    gcvCOMPARE_GREATER_OR_EQUAL,
+    gcvCOMPARE_ALWAYS,
+}
+gceCOMPARE;
+
+/* Stencil modes. */
+typedef enum _gceSTENCIL_MODE
+{
+    gcvSTENCIL_NONE,
+    gcvSTENCIL_SINGLE_SIDED,
+    gcvSTENCIL_DOUBLE_SIDED,
+}
+gceSTENCIL_MODE;
+
+/* Stencil operations. */
+typedef enum _gceSTENCIL_OPERATION
+{
+    gcvSTENCIL_KEEP,
+    gcvSTENCIL_REPLACE,
+    gcvSTENCIL_ZERO,
+    gcvSTENCIL_INVERT,
+    gcvSTENCIL_INCREMENT,
+    gcvSTENCIL_DECREMENT,
+    gcvSTENCIL_INCREMENT_SATURATE,
+    gcvSTENCIL_DECREMENT_SATURATE,
+    gcvSTENCIL_OPERATION_INVALID = -1
+}
+gceSTENCIL_OPERATION;
+
+/* Stencil selection. */
+typedef enum _gceSTENCIL_WHERE
+{
+    gcvSTENCIL_FRONT,
+    gcvSTENCIL_BACK,
+}
+gceSTENCIL_WHERE;
+
+/* Texture addressing selection. */
+typedef enum _gceTEXTURE_WHICH
+{
+    gcvTEXTURE_S,
+    gcvTEXTURE_T,
+    gcvTEXTURE_R,
+}
+gceTEXTURE_WHICH;
+
+/* Texture addressing modes. */
+typedef enum _gceTEXTURE_ADDRESSING
+{
+    gcvTEXTURE_INVALID    = 0,
+    gcvTEXTURE_CLAMP,
+    gcvTEXTURE_WRAP,
+    gcvTEXTURE_MIRROR,
+    gcvTEXTURE_BORDER,
+    gcvTEXTURE_MIRROR_ONCE,
+}
+gceTEXTURE_ADDRESSING;
+
+/* Texture filters. */
+typedef enum _gceTEXTURE_FILTER
+{
+    gcvTEXTURE_NONE,
+    gcvTEXTURE_POINT,
+    gcvTEXTURE_LINEAR,
+    gcvTEXTURE_ANISOTROPIC,
+}
+gceTEXTURE_FILTER;
+
+typedef enum _gceTEXTURE_COMPONENT
+{
+    gcvTEXTURE_COMPONENT_R,
+    gcvTEXTURE_COMPONENT_G,
+    gcvTEXTURE_COMPONENT_B,
+    gcvTEXTURE_COMPONENT_A,
+
+    gcvTEXTURE_COMPONENT_NUM,
+} gceTEXTURE_COMPONENT;
+
+/* Texture swizzle modes. */
+typedef enum _gceTEXTURE_SWIZZLE
+{
+    gcvTEXTURE_SWIZZLE_R = 0,
+    gcvTEXTURE_SWIZZLE_G,
+    gcvTEXTURE_SWIZZLE_B,
+    gcvTEXTURE_SWIZZLE_A,
+    gcvTEXTURE_SWIZZLE_0,
+    gcvTEXTURE_SWIZZLE_1,
+
+    gcvTEXTURE_SWIZZLE_INVALID,
+} gceTEXTURE_SWIZZLE;
+
+typedef enum _gceTEXTURE_SRGBDECODE
+{
+    gcvTEXTURE_SRGB_INVALID = 0,
+    gcvTEXTURE_DECODE,
+    gcvTEXTURE_SKIP_DECODE,
+}gceTEXTURE_SRGBDECODE;
+
+typedef enum _gceTEXTURE_COMPARE_MODE
+{
+    gcvTEXTURE_COMPARE_MODE_INVALID  = 0,
+    gcvTEXTURE_COMPARE_MODE_NONE,
+    gcvTEXTURE_COMPARE_MODE_REF,
+} gceTEXTURE_COMPARE_MODE;
+
+typedef enum _gceTEXTURE_DS_MODE
+{
+    gcvTEXTURE_DS_MODE_INVALID = 0,
+    gcvTEXTURE_DS_MODE_DEPTH   = 1,
+    gcvTEXTURE_DS_MODE_STENCIL = 2,
+}gceTEXTURE_DS_MODE;
+
+typedef enum _gceTEXTURE_DS_TEX_MODE
+{
+    gcvTEXTURE_DS_TEXTURE_MODE_LUMINANCE    = 0,
+    gcvTEXTURE_DS_TEXTURE_MODE_INTENSITY,
+    gcvTEXTURE_DS_TEXTURE_MODE_ALPHA,
+    gcvTEXTURE_DS_TEXTURE_MODE_RED,
+
+    gcvTEXTURE_DS_TEXTURE_MODE_INVALID,
+}gceTEXTURE_DS_TEX_MODE;
+
+/* Pixel output swizzle modes. */
+typedef enum _gcePIXEL_SWIZZLE
+{
+    gcvPIXEL_SWIZZLE_R = gcvTEXTURE_SWIZZLE_R,
+    gcvPIXEL_SWIZZLE_G = gcvTEXTURE_SWIZZLE_G,
+    gcvPIXEL_SWIZZLE_B = gcvTEXTURE_SWIZZLE_B,
+    gcvPIXEL_SWIZZLE_A = gcvTEXTURE_SWIZZLE_A,
+
+    gcvPIXEL_SWIZZLE_INVALID,
+} gcePIXEL_SWIZZLE;
+
+/* Primitive types. */
+typedef enum _gcePRIMITIVE
+{
+    gcvPRIMITIVE_POINT_LIST,
+    gcvPRIMITIVE_LINE_LIST,
+    gcvPRIMITIVE_LINE_STRIP,
+    gcvPRIMITIVE_LINE_LOOP,
+    gcvPRIMITIVE_TRIANGLE_LIST,
+    gcvPRIMITIVE_TRIANGLE_STRIP,
+    gcvPRIMITIVE_TRIANGLE_FAN,
+    gcvPRIMITIVE_RECTANGLE,
+    gcvPRIMITIVE_LINES_ADJACENCY,
+    gcvPRIMITIVE_LINE_STRIP_ADJACENCY,
+    gcvPRIMITIVE_TRIANGLES_ADJACENCY,
+    gcvPRIMITIVE_TRIANGLE_STRIP_ADJACENCY,
+    gcvPRIMITIVE_PATCH_LIST,
+}
+gcePRIMITIVE;
+
+/* Index types. */
+typedef enum _gceINDEX_TYPE
+{
+    gcvINDEX_8,
+    gcvINDEX_16,
+    gcvINDEX_32,
+}
+gceINDEX_TYPE;
+
+/* Multi GPU rendering modes. */
+typedef enum _gceMULTI_GPU_RENDERING_MODE
+{
+    gcvMULTI_GPU_RENDERING_MODE_OFF,
+    gcvMULTI_GPU_RENDERING_MODE_SPLIT_WIDTH,
+    gcvMULTI_GPU_RENDERING_MODE_SPLIT_HEIGHT,
+    gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_64x64,
+    gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x64,
+    gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x128,
+    gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED,
+    gcvMULTI_GPU_RENDERING_MODE_INVALID
+}
+gceMULTI_GPU_RENDERING_MODE;
+
+typedef enum _gceMULTI_GPU_MODE
+{
+    gcvMULTI_GPU_MODE_COMBINED    = 0,
+    gcvMULTI_GPU_MODE_INDEPENDENT = 1
+}
+gceMULTI_GPU_MODE;
+
+typedef enum _gceMACHINECODE
+{
+    gcvMACHINECODE_ANTUTU0 = 0x0,
+
+    gcvMACHINECODE_GLB27_RELEASE_0,
+
+    gcvMACHINECODE_GLB25_RELEASE_0,
+    gcvMACHINECODE_GLB25_RELEASE_1,
+
+    /* keep it as the last enum */
+    gcvMACHINECODE_COUNT
+}
+gceMACHINECODE;
+
+typedef enum _gceUNIFORMCVT
+{
+    gcvUNIFORMCVT_NONE = 0,
+    gcvUNIFORMCVT_TO_BOOL,
+    gcvUNIFORMCVT_TO_FLOAT,
+} gceUNIFORMCVT;
+
+typedef enum _gceHAL_ARG_VERSION
+{
+    gcvHAL_ARG_VERSION_V1 = 0x0,
+    gcvHAL_ARG_VERSION_V2,
+}
+gceHAL_ARG_VERSION;
+
+
+/** endian mode  for each 2Bytes
+* endian mode                          endian
+*endian mode0: 0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15
+*endian mode1: 1  0  3  2  5  4  7  6  9  8  11  10  13  12  15  14
+*endian mode2: 2  3  0  1  6  7  4  5  10  11  8  9  14  15  12  13
+*endain mode3: 3  2  1  0  7  6  5  4  11  10  9  8  15  14  13  12
+*endain mode4: 12  13  14  15  8  9  10  11  4  5  6  7  0  1  2  3
+*endain mode5: 13  12  15  14  9  8  11  10  5  4  7  6  1  0  3  2
+*endain mode6: 14  15  12  13  10  11  8  9  6  7  4  5  2  3  0  1
+*endain mode7: 15  14  13  12  11  10  9  8  7  6  5  4  3  2  1  0
+**/
+typedef enum _gceENDIAN_MODE
+{
+    gcvENDIAN_MODE0          = 0x0, /* endian mode0 */
+    gcvENDIAN_MODE1          = 0x1, /* endian mode1 */
+    gcvENDIAN_MODE2          = 0x2, /* endian mode2 */
+    gcvENDIAN_MODE3          = 0x3, /* endian mode3 */
+    gcvENDIAN_MODE4          = 0x4, /* endian mode4 */
+    gcvENDIAN_MODE5          = 0x5, /* endian mode5 */
+    gcvENDIAN_MODE6          = 0x6, /* endian mode6 */
+    gcvENDIAN_MODE7          = 0x7, /* endian mode7 */
+}
+gceENDIAN_MODE;
+
+typedef enum _gceHW_FE_TYPE
+{
+    gcvHW_FE_WAIT_LINK,
+    gcvHW_FE_ASYNC,
+    gcvHW_FE_MULTI_CHANNEL,
+}
+gceHW_FE_TYPE;
+
+typedef enum _gceMCFE_CHANNEL_TYPE
+{
+    gcvMCFE_CHANNEL_NONE = 0,
+    gcvMCFE_CHANNEL_SYSTEM,
+    gcvMCFE_CHANNEL_SHADER,
+    gcvMCFE_CHANNEL_NN,
+    gcvMCFE_CHANNEL_TP,
+
+    gcvMCFE_CHANNEL_3DBLIT = 128,
+}
+gceMCFE_CHANNEL_TYPE;
+
+typedef enum _gcePAGE_TYPE
+{
+    gcvPAGE_TYPE_1M,
+    gcvPAGE_TYPE_4K,
+}
+gcePAGE_TYPE;
+
+typedef enum _gceAREA_TYPE
+{
+    gcvAREA_TYPE_UNKNOWN = 0,
+    gcvAREA_TYPE_FLATMAP,
+    gcvAREA_TYPE_1M,
+    gcvAREA_TYPE_4K,
+}
+gceAREA_TYPE;
+
+/*******************************************************************************
+** Broadcast interface.
+*/
+
+typedef enum _gceBROADCAST
+{
+    /* GPU might be idle. */
+    gcvBROADCAST_GPU_IDLE,
+
+    /* A commit is going to happen. */
+    gcvBROADCAST_GPU_COMMIT,
+
+    /* GPU seems to be stuck. */
+    gcvBROADCAST_GPU_STUCK,
+
+    /* First process gets attached. */
+    gcvBROADCAST_FIRST_PROCESS,
+
+    /* Last process gets detached. */
+    gcvBROADCAST_LAST_PROCESS,
+
+    /* AXI bus error. */
+    gcvBROADCAST_AXI_BUS_ERROR,
+
+    /* Out of memory. */
+    gcvBROADCAST_OUT_OF_MEMORY,
+}
+gceBROADCAST;
+
+/* Notifications. */
+typedef enum _gceNOTIFY
+{
+    gcvNOTIFY_INTERRUPT,
+    gcvNOTIFY_COMMAND_QUEUE,
+}
+gceNOTIFY;
+
+/* Flush flags. */
+typedef enum _gceKERNEL_FLUSH
+{
+    gcvFLUSH_COLOR              = 0x01,
+    gcvFLUSH_DEPTH              = 0x02,
+    gcvFLUSH_TEXTURE            = 0x04,
+    gcvFLUSH_2D                 = 0x08,
+    gcvFLUSH_L2                 = 0x10,
+    gcvFLUSH_TILE_STATUS        = 0x20,
+    gcvFLUSH_ICACHE             = 0x40,
+    gcvFLUSH_TXDESC             = 0x80,
+    gcvFLUSH_FENCE              = 0x100,
+    gcvFLUSH_VERTEX             = 0x200,
+    gcvFLUSH_TFBHEADER          = 0x400,
+    gcvFLUSH_ALL                = gcvFLUSH_COLOR
+                                | gcvFLUSH_DEPTH
+                                | gcvFLUSH_TEXTURE
+                                | gcvFLUSH_2D
+                                | gcvFLUSH_L2
+                                | gcvFLUSH_TILE_STATUS
+                                | gcvFLUSH_ICACHE
+                                | gcvFLUSH_TXDESC
+                                | gcvFLUSH_FENCE
+                                | gcvFLUSH_VERTEX
+                                | gcvFLUSH_TFBHEADER
+}
+gceKERNEL_FLUSH;
+
+typedef enum _gceCOUNTER
+{
+    gcvCOUNTER_FRONT_END,
+    gcvCOUNTER_VERTEX_SHADER,
+    gcvCOUNTER_PRIMITIVE_ASSEMBLY,
+    gcvCOUNTER_SETUP,
+    gcvCOUNTER_RASTERIZER,
+    gcvCOUNTER_PIXEL_SHADER,
+    gcvCOUNTER_TEXTURE,
+    gcvCOUNTER_PIXEL_ENGINE,
+    gcvCOUNTER_MEMORY_CONTROLLER_COLOR,
+    gcvCOUNTER_MEMORY_CONTROLLER_DEPTH,
+    gcvCOUNTER_HOST_INTERFACE0,
+    gcvCOUNTER_HOST_INTERFACE1,
+    gcvCOUNTER_GPUL2_CACHE,
+    gcvCOUNTER_COUNT
+}
+gceCOUNTER;
+
+typedef enum _gceProfilerClient
+{
+    gcvCLIENT_OPENGLES11 = 1,
+    gcvCLIENT_OPENGLES,
+    gcvCLIENT_OPENGL,
+    gcvCLIENT_OPENVG,
+    gcvCLIENT_OPENCL,
+    gcvCLIENT_OPENVX,
+    gcvCLIENT_OPENVK,
+}
+gceProfilerClient;
+
+typedef enum _gceCOUNTER_OPTYPE
+{
+    gcvCOUNTER_OP_DRAW = 0,
+    gcvCOUNTER_OP_BLT = 1,
+    gcvCOUNTER_OP_COMPUTE = 2,
+    gcvCOUNTER_OP_RS = 3,
+    gcvCOUNTER_OP_FINISH = 4,
+    gcvCOUNTER_OP_FRAME = 5,
+    gcvCOUNTER_OP_NONE = 6
+}
+gceCOUNTER_OPTYPE;
+
+typedef enum _gceProbeStatus
+{
+    gcvPROBE_Disabled = 0,
+    gcvPROBE_Paused = 1,
+    gcvPROBE_Enabled = 2,
+}
+gceProbeStatus;
+
+typedef enum _gceProbeCmd
+{
+    gcvPROBECMD_BEGIN = 0,
+    gcvPROBECMD_PAUSE = 1,
+    gcvPROBECMD_RESUME = 2,
+    gcvPROBECMD_END = 3,
+}
+gceProbeCmd;
+
+/*******************************************************************************
+** Events. *********************************************************************
+*/
+
+typedef enum _halEventType
+{
+    /* Keyboard event. */
+    HAL_KEYBOARD,
+
+    /* Mouse move event. */
+    HAL_POINTER,
+
+    /* Mouse button event. */
+    HAL_BUTTON,
+
+    /* Application close event. */
+    HAL_CLOSE,
+
+    /* Application window has been updated. */
+    HAL_WINDOW_UPDATE
+}
+halEventType;
+
+/* Scancodes for keyboard. */
+typedef enum _halKeys
+{
+    HAL_UNKNOWN = -1,
+
+    HAL_BACKSPACE = 0x08,
+    HAL_TAB,
+    HAL_ENTER = 0x0D,
+    HAL_ESCAPE = 0x1B,
+
+    HAL_SPACE = 0x20,
+    HAL_SINGLEQUOTE = 0x27,
+    HAL_PAD_ASTERISK = 0x2A,
+    HAL_COMMA = 0x2C,
+    HAL_HYPHEN,
+    HAL_PERIOD,
+    HAL_SLASH,
+    HAL_0,
+    HAL_1,
+    HAL_2,
+    HAL_3,
+    HAL_4,
+    HAL_5,
+    HAL_6,
+    HAL_7,
+    HAL_8,
+    HAL_9,
+    HAL_SEMICOLON = 0x3B,
+    HAL_EQUAL = 0x3D,
+    HAL_A = 0x41,
+    HAL_B,
+    HAL_C,
+    HAL_D,
+    HAL_E,
+    HAL_F,
+    HAL_G,
+    HAL_H,
+    HAL_I,
+    HAL_J,
+    HAL_K,
+    HAL_L,
+    HAL_M,
+    HAL_N,
+    HAL_O,
+    HAL_P,
+    HAL_Q,
+    HAL_R,
+    HAL_S,
+    HAL_T,
+    HAL_U,
+    HAL_V,
+    HAL_W,
+    HAL_X,
+    HAL_Y,
+    HAL_Z,
+    HAL_LBRACKET,
+    HAL_BACKSLASH,
+    HAL_RBRACKET,
+    HAL_BACKQUOTE = 0x60,
+
+    HAL_F1 = 0x80,
+    HAL_F2,
+    HAL_F3,
+    HAL_F4,
+    HAL_F5,
+    HAL_F6,
+    HAL_F7,
+    HAL_F8,
+    HAL_F9,
+    HAL_F10,
+    HAL_F11,
+    HAL_F12,
+
+    HAL_LCTRL,
+    HAL_RCTRL,
+    HAL_LSHIFT,
+    HAL_RSHIFT,
+    HAL_LALT,
+    HAL_RALT,
+    HAL_CAPSLOCK,
+    HAL_NUMLOCK,
+    HAL_SCROLLLOCK,
+    HAL_PAD_0,
+    HAL_PAD_1,
+    HAL_PAD_2,
+    HAL_PAD_3,
+    HAL_PAD_4,
+    HAL_PAD_5,
+    HAL_PAD_6,
+    HAL_PAD_7,
+    HAL_PAD_8,
+    HAL_PAD_9,
+    HAL_PAD_HYPHEN,
+    HAL_PAD_PLUS,
+    HAL_PAD_SLASH,
+    HAL_PAD_PERIOD,
+    HAL_PAD_ENTER,
+    HAL_SYSRQ,
+    HAL_PRNTSCRN,
+    HAL_BREAK,
+    HAL_UP,
+    HAL_LEFT,
+    HAL_RIGHT,
+    HAL_DOWN,
+    HAL_HOME,
+    HAL_END,
+    HAL_PGUP,
+    HAL_PGDN,
+    HAL_INSERT,
+    HAL_DELETE,
+    HAL_LWINDOW,
+    HAL_RWINDOW,
+    HAL_MENU,
+    HAL_POWER,
+    HAL_SLEEP,
+    HAL_WAKE
+}
+halKeys;
+
+/*!
+ @brief Command codes between kernel module and TrustZone
+ @discussion
+ Critical services must be done in TrustZone to avoid sensitive content leak. Most of kernel module is kept in non-Secure os to minimize
+ code in TrustZone.
+ */
+typedef enum kernel_packet_command {
+    KERNEL_START_COMMAND,
+    KERNEL_SUBMIT,
+    KERNEL_MAP_MEMORY, /* */
+    KERNEL_UNMAP_MEMORY,
+    KERNEL_ALLOCATE_SECRUE_MEMORY, /*! Security memory management. */
+    KERNEL_FREE_SECURE_MEMORY,
+    KERNEL_EXECUTE, /* Execute a command buffer. */
+    KERNEL_DUMP_MMU_EXCEPTION,
+    KERNEL_HANDLE_MMU_EXCEPTION,
+    KERNEL_READ_MMU_EXCEPTION,
+} kernel_packet_command_t;
+
+enum {
+    gcvTA_COMMAND_INIT,
+    gcvTA_COMMAND_DISPATCH,
+
+    gcvTA_CALLBACK_ALLOC_SECURE_MEM,
+    gcvTA_CALLBACK_FREE_SECURE_MEM,
+};
+
+typedef enum {
+    gcvFENCE_TYPE_READ          = 0x1,
+    gcvFENCE_TYPE_WRITE         = 0x2,
+    gcvFENCE_TYPE_ALL           = gcvFENCE_TYPE_READ | gcvFENCE_TYPE_WRITE,
+    gcvFNECE_TYPE_INVALID       = 0x10000,
+}
+gceFENCE_TYPE;
+
+typedef enum _gceTLS_KEY
+{
+    gcvTLS_KEY_EGL,
+    gcvTLS_KEY_OPENGL_ES,
+    gcvTLS_KEY_OPENVG,
+    gcvTLS_KEY_OPENGL,
+    gcvTLS_KEY_OPENCL,
+    gcvTLS_KEY_OPENVX,
+
+    gcvTLS_KEY_COUNT
+}
+gceTLS_KEY;
+
+typedef enum _gcePLS_VALUE
+{
+  gcePLS_VALUE_EGL_DISPLAY_INFO,
+  gcePLS_VALUE_EGL_CONFIG_FORMAT_INFO,
+  gcePLS_VALUE_EGL_DESTRUCTOR_INFO,
+}
+gcePLS_VALUE;
+
+#if gcdENABLE_3D
+/* Blending functions. */
+typedef enum _gceBLEND_FUNCTION
+{
+    gcvBLEND_ZERO,
+    gcvBLEND_ONE,
+    gcvBLEND_SOURCE_COLOR,
+    gcvBLEND_INV_SOURCE_COLOR,
+    gcvBLEND_SOURCE_ALPHA,
+    gcvBLEND_INV_SOURCE_ALPHA,
+    gcvBLEND_TARGET_COLOR,
+    gcvBLEND_INV_TARGET_COLOR,
+    gcvBLEND_TARGET_ALPHA,
+    gcvBLEND_INV_TARGET_ALPHA,
+    gcvBLEND_SOURCE_ALPHA_SATURATE,
+    gcvBLEND_CONST_COLOR,
+    gcvBLEND_INV_CONST_COLOR,
+    gcvBLEND_CONST_ALPHA,
+    gcvBLEND_INV_CONST_ALPHA,
+}
+gceBLEND_FUNCTION;
+
+/* Blending modes. */
+typedef enum _gceBLEND_MODE
+{
+    gcvBLEND_ADD = 0,
+    gcvBLEND_SUBTRACT,
+    gcvBLEND_REVERSE_SUBTRACT,
+    gcvBLEND_MIN,
+    gcvBLEND_MAX,
+    gcvBLEND_MULTIPLY,
+    gcvBLEND_SCREEN,
+    gcvBLEND_OVERLAY,
+    gcvBLEND_DARKEN,
+    gcvBLEND_LIGHTEN,
+    gcvBLEND_COLORDODGE,
+    gcvBLEND_COLORBURN,
+    gcvBLEND_HARDLIGHT,
+    gcvBLEND_SOFTLIGHT,
+    gcvBLEND_DIFFERENCE,
+    gcvBLEND_EXCLUSION,
+    gcvBLEND_HSL_HUE,
+    gcvBLEND_HSL_SATURATION,
+    gcvBLEND_HSL_COLOR,
+    gcvBLEND_HSL_LUMINOSITY,
+
+    gcvBLEND_TOTAL
+}
+gceBLEND_MODE;
+
+/* Depth modes. */
+typedef enum _gceDEPTH_MODE
+{
+    gcvDEPTH_NONE,
+    gcvDEPTH_Z,
+    gcvDEPTH_W,
+}
+gceDEPTH_MODE;
+#endif /* gcdENABLE_3D */
+
+/* API flags. */
+typedef enum _gceAPI
+{
+    gcvAPI_D3D = 1,
+    gcvAPI_OPENGL_ES11,
+    gcvAPI_OPENGL_ES20,
+    gcvAPI_OPENGL_ES30,
+    gcvAPI_OPENGL_ES31,
+    gcvAPI_OPENGL_ES32,
+    gcvAPI_OPENGL,
+    gcvAPI_OPENVG,
+    gcvAPI_OPENCL,
+    gcvAPI_OPENVK,
+}
+gceAPI;
+
+typedef enum _gceWHERE
+{
+    gcvWHERE_COMMAND_PREFETCH = 0,
+    gcvWHERE_COMMAND,
+    gcvWHERE_RASTER,
+    gcvWHERE_PIXEL,
+    gcvWHERE_BLT,
+}
+gceWHERE;
+
+typedef enum _gceHOW
+{
+    gcvHOW_SEMAPHORE            = 0x1,
+    gcvHOW_STALL                = 0x2,
+    gcvHOW_SEMAPHORE_STALL      = 0x3,
+}
+gceHOW;
+
+typedef enum _gceSignalHandlerType
+{
+    gcvHANDLE_SIGFPE_WHEN_SIGNAL_CODE_IS_0        = 0x1,
+}
+gceSignalHandlerType;
+
+typedef enum _gceFILE_MODE
+{
+    gcvFILE_CREATE          = 0,
+    gcvFILE_APPEND,
+    gcvFILE_READ,
+    gcvFILE_CREATETEXT,
+    gcvFILE_APPENDTEXT,
+    gcvFILE_READTEXT,
+}
+gceFILE_MODE;
+
+typedef enum _gceFILE_WHENCE
+{
+    gcvFILE_SEEK_SET,
+    gcvFILE_SEEK_CUR,
+    gcvFILE_SEEK_END
+}
+gceFILE_WHENCE;
+
+/* Color format classes. */
+typedef enum _gceFORMAT_CLASS
+{
+    gcvFORMAT_CLASS_RGBA        = 4500,
+    gcvFORMAT_CLASS_YUV,
+    gcvFORMAT_CLASS_INDEX,
+    gcvFORMAT_CLASS_LUMINANCE,
+    gcvFORMAT_CLASS_BUMP,
+    gcvFORMAT_CLASS_DEPTH,
+    gcvFORMAT_CLASS_ASTC,
+    gcvFORMAT_CLASS_COMPRESSED,
+    gcvFORMAT_CLASS_OTHER,
+    gcvFORMAT_CLASS_INTENSITY
+}
+gceFORMAT_CLASS;
+
+/* Color format data type */
+typedef enum _gceFORMAT_DATATYPE
+{
+    gcvFORMAT_DATATYPE_UNSIGNED_NORMALIZED,
+    gcvFORMAT_DATATYPE_SIGNED_NORMALIZED,
+    gcvFORMAT_DATATYPE_UNSIGNED_INTEGER,
+    gcvFORMAT_DATATYPE_SIGNED_INTEGER,
+    gcvFORMAT_DATATYPE_FLOAT16,
+    gcvFORMAT_DATATYPE_FLOAT32,
+    gcvFORMAT_DATATYPE_FLOAT_E5B9G9R9,
+    gcvFORMAT_DATATYPE_FLOAT_B10G11R11F,
+    gcvFORMAT_DATATYPE_INDEX,
+    gcvFORMAT_DATATYPE_SRGB,
+    gcvFORMAT_DATATYPE_FLOAT32_UINT,
+}
+gceFORMAT_DATATYPE;
+
+typedef enum _gceORIENTATION
+{
+    gcvORIENTATION_TOP_BOTTOM,
+    gcvORIENTATION_BOTTOM_TOP,
+}
+gceORIENTATION;
+
+/* Special enums for width field in gcsFORMAT_COMPONENT. */
+typedef enum _gceCOMPONENT_CONTROL
+{
+    gcvCOMPONENT_NOTPRESENT     = 0x00,
+    gcvCOMPONENT_DONTCARE       = 0x80,
+    gcvCOMPONENT_WIDTHMASK      = 0x7F,
+    gcvCOMPONENT_ODD            = 0x80
+}
+gceCOMPONENT_CONTROL;
+
+/* User option. */
+typedef enum _gceDEBUG_MSG
+{
+    gcvDEBUG_MSG_NONE,
+    gcvDEBUG_MSG_ERROR,
+    gcvDEBUG_MSG_WARNING
+}
+gceDEBUG_MSG;
+
+/* Compressed format now was defined same as dec400d, should be general. */
+typedef enum _VIV_COMPRESS_FMT
+{
+    _VIV_CFMT_ARGB8 = 0,
+    _VIV_CFMT_XRGB8,
+    _VIV_CFMT_AYUV,
+    _VIV_CFMT_UYVY,
+    _VIV_CFMT_YUY2,
+    _VIV_CFMT_YUV_ONLY,
+    _VIV_CFMT_UV_MIX,
+    _VIV_CFMT_ARGB4,
+    _VIV_CFMT_XRGB4,
+    _VIV_CFMT_A1R5G5B5,
+    _VIV_CFMT_X1R5G5B5,
+    _VIV_CFMT_R5G6B5,
+    _VIV_CFMT_Z24S8,
+    _VIV_CFMT_Z24,
+    _VIV_CFMT_Z16,
+    _VIV_CFMT_A2R10G10B10,
+    _VIV_CFMT_BAYER,
+    _VIV_CFMT_SIGNED_BAYER,
+    _VIV_CFMT_VAA16,
+    _VIV_CFMT_S8,
+
+    _VIV_CFMT_MAX,
+} _VIV_COMPRESS_FMT;
+
+typedef enum _gcePROGRAM_STAGE
+{
+    gcvPROGRAM_STAGE_VERTEX         = 0x0,
+    gcvPROGRAM_STAGE_TCS            = 0x1,
+    gcvPROGRAM_STAGE_TES            = 0x2,
+    gcvPROGRAM_STAGE_GEOMETRY       = 0x3,
+    gcvPROGRAM_STAGE_FRAGMENT       = 0x4,
+    gcvPROGRAM_STAGE_GRAPHICS_COUNT = 0x5,
+    gcvPROGRAM_STAGE_COMPUTE        = 0x5,
+    gcvPROGRAM_STAGE_OPENCL         = 0x6,
+    gcvPROGRAM_STAGE_LAST
+}
+gcePROGRAM_STAGE;
+
+typedef enum _gcePROGRAM_STAGE_BIT
+{
+    gcvPROGRAM_STAGE_VERTEX_BIT   = 1 << gcvPROGRAM_STAGE_VERTEX,
+    gcvPROGRAM_STAGE_TCS_BIT      = 1 << gcvPROGRAM_STAGE_TCS,
+    gcvPROGRAM_STAGE_TES_BIT      = 1 << gcvPROGRAM_STAGE_TES,
+    gcvPROGRAM_STAGE_GEOMETRY_BIT = 1 << gcvPROGRAM_STAGE_GEOMETRY,
+    gcvPROGRAM_STAGE_FRAGMENT_BIT = 1 << gcvPROGRAM_STAGE_FRAGMENT,
+    gcvPROGRAM_STAGE_COMPUTE_BIT  = 1 << gcvPROGRAM_STAGE_COMPUTE,
+    gcvPROGRAM_STAGE_OPENCL_BIT   = 1 << gcvPROGRAM_STAGE_OPENCL,
+}
+gcePROGRAM_STAGE_BIT;
+
+typedef enum _gceBLIT_FLAG
+{
+    gcvBLIT_FLAG_SKIP_DEPTH_WRITE   = 1 << 0,
+    gcvBLIT_FLAG_SKIP_STENCIL_WRITE = 1 << 1,
+} gceBLIT_FLAG;
+
+/* Clear flags. */
+typedef enum _gceCLEAR
+{
+    gcvCLEAR_COLOR              = 0x1,
+    gcvCLEAR_DEPTH              = 0x2,
+    gcvCLEAR_STENCIL            = 0x4,
+    gcvCLEAR_HZ                 = 0x8,
+    gcvCLEAR_WITH_GPU_ONLY      = 0x100,
+    gcvCLEAR_WITH_CPU_ONLY      = 0x200,
+    gcvCLEAR_MULTI_SLICES       = 0x400,
+}
+gceCLEAR;
+
+typedef enum _gceBLITDRAW_TYPE
+{
+    gcvBLITDRAW_CLEAR      = 0,
+    gcvBLITDRAW_BLIT       = 1,
+    gcvBLITDRAW_BLIT_DEPTH = 2,
+
+    /* last number, not a real type */
+    gcvBLITDRAW_NUM_TYPE
+ }
+gceBLITDRAW_TYPE;
+
+typedef enum _gceSPLIT_DRAW_TYPE
+{
+    gcvSPLIT_DRAW_UNKNOWN      = 0x0,
+    gcvSPLIT_DRAW_1,
+    gcvSPLIT_DRAW_2,
+    gcvSPLIT_DRAW_3,
+    gcvSPLIT_DRAW_4,
+    gcvSPLIT_DRAW_XFB,
+    gcvSPLIT_DRAW_INDEX_FETCH,
+    gcvSPLIT_DRAW_TCS,
+    gcvSPLIT_DRAW_STIPPLE,
+    gcvSPLIT_DRAW_WIDE_LINE,
+    gcvSPLIT_DRAW_LAST
+}
+gceSPLIT_DRAW_TYPE;
+
+/* Blending targets. */
+typedef enum _gceBLEND_UNIT
+{
+    gcvBLEND_SOURCE,
+    gcvBLEND_TARGET,
+}
+gceBLEND_UNIT;
+
+typedef enum _gceXfbCmd
+{
+    gcvXFBCMD_BEGIN           = 0,
+    gcvXFBCMD_PAUSE           = 1,
+    gcvXFBCMD_RESUME          = 2,
+    gcvXFBCMD_END             = 3,
+    gcvXFBCMD_PAUSE_INCOMMIT  = 4,
+    gcvXFBCMD_RESUME_INCOMMIT = 5,
+    gcvXFBCMD_INVALID         = 6,
+}
+gceXfbCmd;
+
+typedef enum _gceXfbStatus
+{
+    gcvXFB_Disabled = 0,
+    gcvXFB_Paused,
+    gcvXFB_Enabled,
+}
+gceXfbStatus;
+
+typedef enum _gceQueryStatus
+{
+    gcvQUERY_Disabled = 0,
+    gcvQUERY_Paused   = 1,
+    gcvQUERY_Enabled  = 2,
+}
+gceQueryStatus;
+
+typedef enum _gceQueryCmd
+{
+    gcvQUERYCMD_BEGIN   = 0,
+    gcvQUERYCMD_PAUSE   = 1,
+    gcvQUERYCMD_RESUME  = 2,
+    gcvQUERYCMD_END     = 3,
+    gcvQUERYCMD_INVALID = 4,
+}
+gceQueryCmd;
+
+typedef enum _gceQueryType
+{
+    gcvQUERY_OCCLUSION = 0,
+    gcvQUERY_XFB_WRITTEN = 1,
+    gcvQUERY_PRIM_GENERATED = 2,
+    gcvQUERY_MAX_NUM = 3,
+}
+gceQueryType;
+
+/* Cube faces. */
+typedef enum _gceTEXTURE_FACE
+{
+    gcvFACE_NONE = 0,
+    gcvFACE_POSITIVE_X,
+    gcvFACE_NEGATIVE_X,
+    gcvFACE_POSITIVE_Y,
+    gcvFACE_NEGATIVE_Y,
+    gcvFACE_POSITIVE_Z,
+    gcvFACE_NEGATIVE_Z,
+}
+gceTEXTURE_FACE;
+
+typedef enum _gceVERTEX_FORMAT
+{
+    gcvVERTEX_BYTE,
+    gcvVERTEX_UNSIGNED_BYTE,
+    gcvVERTEX_SHORT,
+    gcvVERTEX_UNSIGNED_SHORT,
+    gcvVERTEX_INT,
+    gcvVERTEX_UNSIGNED_INT,
+    gcvVERTEX_FIXED,
+    gcvVERTEX_HALF,
+    gcvVERTEX_FLOAT,
+    gcvVERTEX_DOUBLE,
+    gcvVERTEX_UNSIGNED_INT_10_10_10_2,
+    gcvVERTEX_INT_10_10_10_2,
+    gcvVERTEX_UNSIGNED_INT_2_10_10_10_REV,
+    gcvVERTEX_INT_2_10_10_10_REV,
+    /* integer format */
+    gcvVERTEX_INT8,
+    gcvVERTEX_INT16,
+    gcvVERTEX_INT32,
+}
+gceVERTEX_FORMAT;
+
+/* What the SW converting scheme to create temp attrib */
+typedef enum _gceATTRIB_SCHEME
+{
+    gcvATTRIB_SCHEME_KEEP = 0,
+    gcvATTRIB_SCHEME_2_10_10_10_REV_TO_FLOAT,
+    gcvATTRIB_SCHEME_BYTE_TO_IVEC4,
+    gcvATTRIB_SCHEME_SHORT_TO_IVEC4,
+    gcvATTRIB_SCHEME_INT_TO_IVEC4,
+    gcvATTRIB_SCHEME_UBYTE_TO_UVEC4,
+    gcvATTRIB_SCHEME_USHORT_TO_UVEC4,
+    gcvATTRIB_SCHEME_UINT_TO_UVEC4,
+    gcvATTRIB_SCHEME_DOUBLE_TO_FLOAT,
+} gceATTRIB_SCHEME;
+
+typedef enum _gceBUFOBJ_TYPE
+{
+    gcvBUFOBJ_TYPE_ARRAY_BUFFER = 1,
+    gcvBUFOBJ_TYPE_ELEMENT_ARRAY_BUFFER  = 2,
+    gcvBUFOBJ_TYPE_GENERIC_BUFFER = 100
+
+} gceBUFOBJ_TYPE;
+
+typedef enum _gceBUFOBJ_USAGE
+{
+    gcvBUFOBJ_USAGE_NONE                                = 0x0,
+    gcvBUFOBJ_USAGE_STREAM_DRAW                         = 0x1,
+    gcvBUFOBJ_USAGE_STREAM_READ                         = 0x2,
+    gcvBUFOBJ_USAGE_STREAM_COPY                         = 0x3,
+    gcvBUFOBJ_USAGE_STATIC_DRAW                         = 0x4,
+    gcvBUFOBJ_USAGE_STATIC_READ                         = 0x5,
+    gcvBUFOBJ_USAGE_STATIC_COPY                         = 0x6,
+    gcvBUFOBJ_USAGE_DYNAMIC_DRAW                        = 0x7,
+    gcvBUFOBJ_USAGE_DYNAMIC_READ                        = 0x8,
+    gcvBUFOBJ_USAGE_DYNAMIC_COPY                        = 0x9,
+
+    /* Use 8bits to save the usage. */
+    gcvBUFOBJ_USAGE_MASK                                = 0xFF,
+
+    /* Some special flags. */
+    /* special patch for optimaize performance,
+    ** no fence and duplicate stream to ensure data correct
+    */
+    gcvBUFOBJ_USAGE_FLAG_DISABLE_FENCE_DYNAMIC_STREAM   = 0x100,
+
+    /* This buffer object is used by driver, so we need to copy the data to the logical memory. */
+    gcvBUFOBJ_USAGE_FLAG_DATA_USED_BY_DRIVER            = 0x200,
+
+} gceBUFOBJ_USAGE;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Channel mask values.
+**
+**  This enumeration defines the values for channel mask used in image
+**  filtering.
+*/
+
+/******************************************************************************\
+******************************** VG Enumerations *******************************
+\******************************************************************************/
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Tiling mode for painting and imagig.
+**
+**  This enumeration defines the tiling modes supported by the HAL.  This is
+**  in fact a one-to-one mapping of the OpenVG 1.1 tile modes.
+*/
+typedef enum _gceTILE_MODE
+{
+    gcvTILE_FILL,
+    gcvTILE_PAD,
+    gcvTILE_REPEAT,
+    gcvTILE_REFLECT
+}
+gceTILE_MODE;
+
+/******************************************************************************/
+/** @ingroup gcoVG
+**
+**  @brief  The different paint modes.
+**
+**  This enumeration lists the available paint modes.
+*/
+typedef enum _gcePAINT_TYPE
+{
+    /** Solid color. */
+    gcvPAINT_MODE_SOLID,
+
+    /** Linear gradient. */
+    gcvPAINT_MODE_LINEAR,
+
+    /** Radial gradient. */
+    gcvPAINT_MODE_RADIAL,
+
+    /** Pattern. */
+    gcvPAINT_MODE_PATTERN,
+
+    /** Mode count. */
+    gcvPAINT_MODE_COUNT
+}
+gcePAINT_TYPE;
+
+/**
+** @ingroup gcoVG
+**
+**  @brief Types of path data supported by HAL.
+**
+**  This enumeration defines the types of path data supported by the HAL.
+**  This is in fact a one-to-one mapping of the OpenVG 1.1 path types.
+*/
+typedef enum _gcePATHTYPE
+{
+    gcePATHTYPE_UNKNOWN = -1,
+    gcePATHTYPE_INT8,
+    gcePATHTYPE_INT16,
+    gcePATHTYPE_INT32,
+    gcePATHTYPE_FLOAT
+}
+gcePATHTYPE;
+
+/**
+** @ingroup gcoVG
+**
+**  @brief Supported path segment commands.
+**
+**  This enumeration defines the path segment commands supported by the HAL.
+*/
+typedef enum _gceVGCMD
+{
+    gcvVGCMD_END, /*  0: 0x00           */
+    gcvVGCMD_CLOSE, /*  1: 0x01         */
+    gcvVGCMD_MOVE, /*  2: 0x02          */
+    gcvVGCMD_MOVE_REL, /*  3: 0x03      */
+    gcvVGCMD_LINE, /*  4: 0x04          */
+    gcvVGCMD_LINE_REL, /*  5: 0x05      */
+    gcvVGCMD_QUAD, /*  6: 0x06     */
+    gcvVGCMD_QUAD_REL, /*  7: 0x07 */
+    gcvVGCMD_CUBIC, /*  8: 0x08         */
+    gcvVGCMD_CUBIC_REL, /*  9: 0x09     */
+    gcvVGCMD_BREAK, /* 10: 0x0A         */
+    gcvVGCMD_HLINE, /* 11: ******* R E S E R V E D *******/
+    gcvVGCMD_HLINE_REL, /* 12: ******* R E S E R V E D *******/
+    gcvVGCMD_VLINE, /* 13: ******* R E S E R V E D *******/
+    gcvVGCMD_VLINE_REL, /* 14: ******* R E S E R V E D *******/
+    gcvVGCMD_SQUAD, /* 15: ******* R E S E R V E D *******/
+    gcvVGCMD_SQUAD_REL, /* 16: ******* R E S E R V E D *******/
+    gcvVGCMD_SCUBIC, /* 17: ******* R E S E R V E D *******/
+    gcvVGCMD_SCUBIC_REL, /* 18: ******* R E S E R V E D *******/
+    gcvVGCMD_SCCWARC, /* 19: ******* R E S E R V E D *******/
+    gcvVGCMD_SCCWARC_REL, /* 20: ******* R E S E R V E D *******/
+    gcvVGCMD_SCWARC, /* 21: ******* R E S E R V E D *******/
+    gcvVGCMD_SCWARC_REL, /* 22: ******* R E S E R V E D *******/
+    gcvVGCMD_LCCWARC, /* 23: ******* R E S E R V E D *******/
+    gcvVGCMD_LCCWARC_REL, /* 24: ******* R E S E R V E D *******/
+    gcvVGCMD_LCWARC, /* 25: ******* R E S E R V E D *******/
+    gcvVGCMD_LCWARC_REL, /* 26: ******* R E S E R V E D *******/
+
+    /* The width of the command recognized by the hardware on bits. */
+    gcvVGCMD_WIDTH = 5,
+
+    /* Hardware command mask. */
+    gcvVGCMD_MASK = (1 << gcvVGCMD_WIDTH) - 1,
+
+    /* Command modifiers. */
+    gcvVGCMD_H_MOD   = 1 << gcvVGCMD_WIDTH, /* =  32 */
+    gcvVGCMD_V_MOD   = 2 << gcvVGCMD_WIDTH, /* =  64 */
+    gcvVGCMD_S_MOD   = 3 << gcvVGCMD_WIDTH, /* =  96 */
+    gcvVGCMD_ARC_MOD = 4 << gcvVGCMD_WIDTH, /* = 128 */
+
+    /* Emulated LINE commands. */
+    gcvVGCMD_HLINE_EMUL     = gcvVGCMD_H_MOD | gcvVGCMD_LINE, /* =  36 */
+    gcvVGCMD_HLINE_EMUL_REL = gcvVGCMD_H_MOD | gcvVGCMD_LINE_REL, /* =  37 */
+    gcvVGCMD_VLINE_EMUL     = gcvVGCMD_V_MOD | gcvVGCMD_LINE, /* =  68 */
+    gcvVGCMD_VLINE_EMUL_REL = gcvVGCMD_V_MOD | gcvVGCMD_LINE_REL, /* =  69 */
+
+    /* Emulated SMOOTH commands. */
+    gcvVGCMD_SQUAD_EMUL      = gcvVGCMD_S_MOD | gcvVGCMD_QUAD, /* = 102 */
+    gcvVGCMD_SQUAD_EMUL_REL  = gcvVGCMD_S_MOD | gcvVGCMD_QUAD_REL, /* = 103 */
+    gcvVGCMD_SCUBIC_EMUL     = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC, /* = 104 */
+    gcvVGCMD_SCUBIC_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC_REL, /* = 105 */
+
+    /* Emulation ARC commands. */
+    gcvVGCMD_ARC_LINE     = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE, /* = 132 */
+    gcvVGCMD_ARC_LINE_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE_REL, /* = 133 */
+    gcvVGCMD_ARC_QUAD     = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD, /* = 134 */
+    gcvVGCMD_ARC_QUAD_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD_REL     /* = 135 */
+}
+gceVGCMD;
+typedef enum _gceVGCMD * gceVGCMD_PTR;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Blending modes supported by the HAL.
+**
+**  This enumeration defines the blending modes supported by the HAL.  This is
+**  in fact a one-to-one mapping of the OpenVG 1.1 blending modes.
+*/
+typedef enum _gceVG_BLEND
+{
+    gcvVG_BLEND_SRC,
+    gcvVG_BLEND_SRC_OVER,
+    gcvVG_BLEND_DST_OVER,
+    gcvVG_BLEND_SRC_IN,
+    gcvVG_BLEND_DST_IN,
+    gcvVG_BLEND_MULTIPLY,
+    gcvVG_BLEND_SCREEN,
+    gcvVG_BLEND_DARKEN,
+    gcvVG_BLEND_LIGHTEN,
+    gcvVG_BLEND_ADDITIVE,
+    gcvVG_BLEND_SUBTRACT,
+    gcvVG_BLEND_FILTER
+}
+gceVG_BLEND;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Image modes supported by the HAL.
+**
+**  This enumeration defines the image modes supported by the HAL.  This is
+**  in fact a one-to-one mapping of the OpenVG 1.1 image modes with the addition
+**  of NO IMAGE.
+*/
+typedef enum _gceVG_IMAGE
+{
+    gcvVG_IMAGE_NONE,
+    gcvVG_IMAGE_NORMAL,
+    gcvVG_IMAGE_MULTIPLY,
+    gcvVG_IMAGE_STENCIL,
+    gcvVG_IMAGE_FILTER
+}
+gceVG_IMAGE;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Filter mode patterns and imaging.
+**
+**  This enumeration defines the filter modes supported by the HAL.
+*/
+typedef enum _gceIMAGE_FILTER
+{
+    gcvFILTER_POINT,
+    gcvFILTER_LINEAR,
+    gcvFILTER_BI_LINEAR
+}
+gceIMAGE_FILTER;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Primitive modes supported by the HAL.
+**
+**  This enumeration defines the primitive modes supported by the HAL.
+*/
+typedef enum _gceVG_PRIMITIVE
+{
+    gcvVG_SCANLINE,
+    gcvVG_RECTANGLE,
+    gcvVG_TESSELLATED,
+    gcvVG_TESSELLATED_TILED
+}
+gceVG_PRIMITIVE;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Rendering quality modes supported by the HAL.
+**
+**  This enumeration defines the rendering quality modes supported by the HAL.
+*/
+typedef enum _gceRENDER_QUALITY
+{
+    gcvVG_NONANTIALIASED,
+    gcvVG_2X2_MSAA,
+    gcvVG_2X4_MSAA,
+    gcvVG_4X4_MSAA
+}
+gceRENDER_QUALITY;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Fill rules supported by the HAL.
+**
+**  This enumeration defines the fill rules supported by the HAL.
+*/
+typedef enum _gceFILL_RULE
+{
+    gcvVG_EVEN_ODD,
+    gcvVG_NON_ZERO
+}
+gceFILL_RULE;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Cap styles supported by the HAL.
+**
+**  This enumeration defines the cap styles supported by the HAL.
+*/
+typedef enum _gceCAP_STYLE
+{
+    gcvCAP_BUTT,
+    gcvCAP_ROUND,
+    gcvCAP_SQUARE
+}
+gceCAP_STYLE;
+
+/**
+**  @ingroup gcoVG
+**
+**  @brief  Join styles supported by the HAL.
+**
+**  This enumeration defines the join styles supported by the HAL.
+*/
+typedef enum _gceJOIN_STYLE
+{
+    gcvJOIN_MITER,
+    gcvJOIN_ROUND,
+    gcvJOIN_BEVEL
+}
+gceJOIN_STYLE;
+
+/* Base values for channel mask definitions. */
+#define gcvCHANNEL_X    (0)
+#define gcvCHANNEL_R    (1 << 0)
+#define gcvCHANNEL_G    (1 << 1)
+#define gcvCHANNEL_B    (1 << 2)
+#define gcvCHANNEL_A    (1 << 3)
+
+typedef enum _gceCHANNEL
+{
+    gcvCHANNEL_XXXX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X),
+    gcvCHANNEL_XXXA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A),
+    gcvCHANNEL_XXBX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X),
+    gcvCHANNEL_XXBA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A),
+
+    gcvCHANNEL_XGXX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X),
+    gcvCHANNEL_XGXA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A),
+    gcvCHANNEL_XGBX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X),
+    gcvCHANNEL_XGBA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A),
+
+    gcvCHANNEL_RXXX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X),
+    gcvCHANNEL_RXXA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A),
+    gcvCHANNEL_RXBX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X),
+    gcvCHANNEL_RXBA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A),
+
+    gcvCHANNEL_RGXX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X),
+    gcvCHANNEL_RGXA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A),
+    gcvCHANNEL_RGBX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X),
+    gcvCHANNEL_RGBA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A),
+}
+gceCHANNEL;
+
+/* Defines the statistical data keys monitored by the statistics module */
+typedef enum _gceSTATISTICS
+{
+    gcvFRAME_FPS        =   1,
+}
+gceSTATISTICS;
+
+/* Value types. */
+typedef enum _gceVALUE_TYPE
+{
+    gcvVALUE_UINT = 0x0,
+    gcvVALUE_FIXED,
+    gcvVALUE_FLOAT,
+    gcvVALUE_INT,
+
+    /*
+    ** The value need be unsigned denormalized. clamp (0.0-1.0) should be done first.
+    */
+    gcvVALUE_FLAG_UNSIGNED_DENORM = 0x00010000,
+
+    /*
+    ** The value need be signed denormalized. clamp (-1.0-1.0) should be done first.
+    */
+    gcvVALUE_FLAG_SIGNED_DENORM   = 0x00020000,
+
+    /*
+    ** The value need to gammar
+    */
+    gcvVALUE_FLAG_GAMMAR          = 0x00040000,
+
+    /*
+    ** The value need to convert from float to float16
+    */
+    gcvVALUE_FLAG_FLOAT_TO_FLOAT16 = 0x0080000,
+
+    /*
+    ** Mask for flag field.
+    */
+    gcvVALUE_FLAG_MASK            = 0xFFFF0000,
+}
+gceVALUE_TYPE;
+
+typedef enum _gceTRACEMODE
+{
+    gcvTRACEMODE_NONE     = 0,
+    gcvTRACEMODE_FULL     = 1,
+    gcvTRACEMODE_LOGGER   = 2,
+    gcvTRACEMODE_ALLZONE  = 3,
+    gcvTRACEMODE_PRE      = 4,
+    gcvTRACEMODE_POST     = 5,
+} gceTRACEMODE;
+
+enum
+{
+    /* GPU can't issue more that 32bit physical address */
+    gcvPLATFORM_FLAG_LIMIT_4G_ADDRESS = 1 << 0,
+
+    gcvPLATFORM_FLAG_IMX_MM           = 1 << 1,
+};
+
+/* No special needs. */
+#define gcvALLOC_FLAG_NONE                  0x00000000
+
+/* Physical contiguous. */
+#define gcvALLOC_FLAG_CONTIGUOUS            0x00000001
+/* Physical non contiguous. */
+#define gcvALLOC_FLAG_NON_CONTIGUOUS        0x00000002
+
+/* Should not swap out. */
+#define gcvALLOC_FLAG_NON_PAGED             0x00000004
+
+/* CPU access explicitly needed. */
+#define gcvALLOC_FLAG_CPU_ACCESS            0x00000008
+/* Can be remapped as cacheable. */
+#define gcvALLOC_FLAG_CACHEABLE             0x00000010
+
+/* Need 32bit address. */
+#define gcvALLOC_FLAG_4GB_ADDR              0x00000020
+
+/* Secure buffer. */
+#define gcvALLOC_FLAG_SECURITY              0x00000040
+/* Can be exported as dmabuf-fd */
+#define gcvALLOC_FLAG_DMABUF_EXPORTABLE     0x00000080
+/* Do not try slow pools (gcvPOOL_VIRTUAL) */
+#define gcvALLOC_FLAG_FAST_POOLS            0x00000100
+
+/* Import DMABUF. */
+#define gcvALLOC_FLAG_DMABUF                0x00001000
+/* Import USERMEMORY. */
+#define gcvALLOC_FLAG_USERMEMORY            0x00002000
+/* Import an External Buffer. */
+#define gcvALLOC_FLAG_EXTERNAL_MEMORY       0x00004000
+/* Import linux reserved memory. */
+#define gcvALLOC_FLAG_LINUX_RESERVED_MEM    0x00008000
+
+/* 1M pages unit allocation. */
+#define gcvALLOC_FLAG_1M_PAGES              0x00010000
+
+/* Non 1M pages unit allocation. */
+#define gcvALLOC_FLAG_4K_PAGES              0x00020000
+
+/* Real allocation happens when GPU page fault. */
+#define gcvALLOC_FLAG_ALLOC_ON_FAULT        0x01000000
+/* Alloc with memory limit. */
+#define gcvALLOC_FLAG_MEMLIMIT              0x02000000
+
+/* CMA allocator only */
+#define gcvALLOC_FLAG_CMA_LIMIT             0x04000000
+
+#define gcvALLOC_FLAG_CMA_PREEMPT           0x08000000
+
+/* GL_VIV internal usage */
+#ifndef GL_MAP_BUFFER_OBJ_VIV
+#define GL_MAP_BUFFER_OBJ_VIV       0x10000
+#endif
+
+/* Command buffer usage. */
+#define gcvCOMMAND_2D   (1 << 0)
+#define gcvCOMMAND_3D   (1 << 1)
+
+/* Default chip ID means chip ID same as core index. */
+#define gcvCHIP_ID_DEFAULT             (~0U)
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+typedef struct _gckCONTEXT          * gckCONTEXT;
+typedef struct _gcoCMDBUF           * gcoCMDBUF;
+
+typedef struct _gcsSTATE_DELTA      * gcsSTATE_DELTA_PTR;
+typedef struct _gcsQUEUE            * gcsQUEUE_PTR;
+typedef struct _gcoQUEUE            * gcoQUEUE;
+typedef struct _gcsHAL_INTERFACE    * gcsHAL_INTERFACE_PTR;
+#if VIVANTE_PROFILER
+typedef struct _gcsHAL_PROFILER_INTERFACE    * gcsHAL_PROFILER_INTERFACE_PTR;
+#endif
+typedef struct _gcs2D_PROFILE       * gcs2D_PROFILE_PTR;
+
+#if gcdENABLE_VG
+typedef struct _gcoVGHARDWARE *            gcoVGHARDWARE;
+typedef struct _gcoVGBUFFER *           gcoVGBUFFER;
+typedef struct _gckVGHARDWARE *         gckVGHARDWARE;
+typedef struct _gcsVGCONTEXT *            gcsVGCONTEXT_PTR;
+typedef struct _gcsVGCONTEXT_MAP *        gcsVGCONTEXT_MAP_PTR;
+typedef struct _gcsVGCMDQUEUE *            gcsVGCMDQUEUE_PTR;
+typedef struct _gcsTASK_MASTER_TABLE *    gcsTASK_MASTER_TABLE_PTR;
+typedef struct _gckVGKERNEL *            gckVGKERNEL;
+typedef void *                            gctTHREAD;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_enum_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h
@@ -0,0 +1,323 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_buffer_h_
+#define __gc_hal_kernel_buffer_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+************************ Command Buffer and Event Objects **********************
+\******************************************************************************/
+
+#define gcdRENDER_FENCE_LENGTH                      (6 * gcmSIZEOF(gctUINT32))
+#define gcdBLT_FENCE_LENGTH                         (10 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_FLUSHCACHE_LENGTH               (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_OQ_LENGTH                 (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_XFBWRITTEN_QUERY_LENGTH   (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_PRIMGEN_QUERY_LENGTH      (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_XFB_LENGTH                (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_HW_FENCE_32BIT                  (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_HW_FENCE_64BIT                  (6 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_PROBE_LENGTH              (TOTAL_PROBE_NUMBER * 2 * gcmSIZEOF(gctUINT32))
+
+#define gcdRESUME_OQ_LENGTH                         (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_XFBWRITTEN_QUERY_LENGTH           (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_PRIMGEN_QUERY_LENGTH              (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_XFB_LENGH                         (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_PROBE_LENGH                       (TOTAL_PROBE_NUMBER * 2 * gcmSIZEOF(gctUINT32))
+
+
+/* State delta record. */
+typedef struct _gcsSTATE_DELTA_RECORD * gcsSTATE_DELTA_RECORD_PTR;
+typedef struct _gcsSTATE_DELTA_RECORD
+{
+    /* State address. */
+    gctUINT                     address;
+
+    /* State mask. */
+    gctUINT32                   mask;
+
+    /* State data. */
+    gctUINT32                   data;
+}
+gcsSTATE_DELTA_RECORD;
+
+/* State delta. */
+typedef struct _gcsSTATE_DELTA
+{
+    /* For debugging: the number of delta in the order of creation. */
+    gctUINT                     num;
+
+    /* Main state delta ID. Every time state delta structure gets reinitialized,
+       main ID is incremented. If main state ID overflows, all map entry IDs get
+       reinitialized to make sure there is no potential erroneous match after
+       the overflow.*/
+    gctUINT                     id;
+
+    /* Vertex element count for the delta buffer. */
+    gctUINT                     elementCount;
+
+    /* Number of states currently stored in the record array. */
+    gctUINT                     recordCount;
+
+    /* Record array; holds all modified states in gcsSTATE_DELTA_RECORD. */
+    gctUINT64                   recordArray;
+    gctUINT                     recordSize;
+
+    /* Map entry ID is used for map entry validation. If map entry ID does not
+       match the main state delta ID, the entry and the corresponding state are
+       considered not in use. */
+    gctUINT64                   mapEntryID;
+    gctUINT                     mapEntryIDSize;
+
+    /* If the map entry ID matches the main state delta ID, index points to
+       the state record in the record array. */
+    gctUINT64                   mapEntryIndex;
+}
+gcsSTATE_DELTA;
+
+#define FENCE_NODE_LIST_INIT_COUNT         100
+
+typedef struct _gcsFENCE_APPEND_NODE
+{
+    gcsSURF_NODE_PTR    node;
+    gceFENCE_TYPE       type;
+
+}gcsFENCE_APPEND_NODE;
+
+typedef gcsFENCE_APPEND_NODE   *   gcsFENCE_APPEND_NODE_PTR;
+
+typedef struct _gcsFENCE_LIST    *   gcsFENCE_LIST_PTR;
+
+typedef struct _gcsFENCE_LIST
+{
+    /* Resource that need get fence, but command used this resource not generated */
+    gcsFENCE_APPEND_NODE_PTR        pendingList;
+    gctUINT                         pendingCount;
+    gctUINT                         pendingAllocCount;
+
+    /* Resoure that already generated command in this command buffer but not get fence */
+    gcsFENCE_APPEND_NODE_PTR        onIssueList;
+    gctUINT                         onIssueCount;
+    gctUINT                         onIssueAllocCount;
+}
+gcsFENCE_LIST;
+
+/* Command buffer object. */
+/*
+ * Initial (before put commands):
+ *
+ *    +-------------------------------------------
+ * ...|reservedHead|
+ *    +-------------------------------------------
+ *    ^            ^
+ *    |            |
+ * startOffset   offset
+ *
+ *
+ * After put command, in commit:
+ *
+ *    +------------------------------------------+
+ * .. |reservedHead| .. commands .. |reservedTail| ..
+ *    +------------------------------------------+
+ *    ^                             ^
+ *    |                             |
+ * startOffset                    offset
+ *
+ *
+ * Commit done, becomes initial state:
+ *
+ *    +------------------------------------------+-----------------
+ * .. |reservedHead| .. commands .. |reservedTail|reservedHead| ..
+ *    +------------------------------------------+-----------------
+ *                                               ^            ^
+ *                                               |            |
+ *                                          startOffset    offset
+ *
+ * reservedHead:
+ * Select pipe commands.
+ *
+ * reservedTail:
+ * Link, Fence, ChipEnable
+ *
+ */
+struct _gcoCMDBUF
+{
+    /* The object. */
+    gcsOBJECT                   object;
+
+    /* Commit count. */
+    gctUINT64                   commitCount;
+
+    /* Command buffer entry and exit pipes. */
+    gcePIPE_SELECT              entryPipe;
+    gcePIPE_SELECT              exitPipe;
+
+    /* Feature usage flags. */
+    gctBOOL                     using2D;
+    gctBOOL                     using3D;
+
+    /* Size of reserved head and tail for each commit. */
+    gctUINT32                   reservedHead;
+    gctUINT32                   reservedTail;
+
+    /* Video memory handle of command buffer. */
+    gctUINT32                   videoMemNode;
+
+    /* GPU address of command buffer. */
+    gctUINT32                   address;
+
+    /* Logical address of command buffer. */
+    gctUINT64                   logical;
+
+    /* Number of bytes in command buffer. */
+    gctUINT32                   bytes;
+
+    /* Start offset into the command buffer. */
+    gctUINT32                   startOffset;
+
+    /* Current offset into the command buffer. */
+    gctUINT32                   offset;
+
+    /* Number of free bytes in command buffer. */
+    gctUINT32                   free;
+
+    /* Location of the last reserved area. */
+    gctUINT64                   lastReserve;
+    gctUINT32                   lastOffset;
+
+    /* Last load state command location and hardware address. */
+    gctUINT64                   lastLoadStatePtr;
+    gctUINT32                   lastLoadStateAddress;
+    gctUINT32                   lastLoadStateCount;
+
+    /*
+    * Put pointer type member after this line.
+    */
+
+    /* Completion signal. */
+    gctSIGNAL                   signal;
+
+    /* Link to the siblings. */
+    gcoCMDBUF                   prev;
+    gcoCMDBUF                   next;
+
+    /* Mirror command buffer(s). */
+    gcoCMDBUF                   *mirrors;
+    gctUINT32                   mirrorCount;
+};
+
+typedef struct _gcsQUEUE
+{
+    /* Pointer to next gcsQUEUE structure in gcsQUEUE. */
+    gctUINT64                   next;
+
+    /* Event information. */
+    gcsHAL_INTERFACE            iface;
+}
+gcsQUEUE;
+
+/* A record chunk include multiple records to save allocation. */
+typedef struct _gcsQUEUE_CHUNK
+{
+    struct _gcsQUEUE_CHUNK *    next;
+
+    gcsQUEUE                    record[16];
+}
+gcsQUEUE_CHUNK;
+
+/* Event queue. */
+struct _gcoQUEUE
+{
+    /* The object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to current event queue. */
+    gcsQUEUE_PTR                head;
+    gcsQUEUE_PTR                tail;
+
+    /* List of free records. */
+    gcsQUEUE_PTR                freeList;
+
+    /* chunks of the records. */
+    gcsQUEUE_CHUNK *            chunks;
+
+    #define gcdIN_QUEUE_RECORD_LIMIT 16
+    /* Number of records currently in queue */
+    gctUINT32                   recordCount;
+    /* Number of records which release resource currently in queue */
+    gctUINT32                   tmpBufferRecordCount;
+
+    /* Max size of pending unlock node in vidmem pool not committed */
+    gctUINT                     maxUnlockBytes;
+
+    gceENGINE                   engine;
+};
+
+struct _gcsTEMPCMDBUF
+{
+    gctUINT32 currentByteSize;
+    gctPOINTER buffer;
+    gctBOOL  inUse;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_buffer_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h
@@ -0,0 +1,566 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+/*
+**    Include file for the local memory management.
+*/
+
+#ifndef __gc_hal_mem_h_
+#define __gc_hal_mem_h_
+#if (gcdENABLE_3D || gcdENABLE_VG)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+**  Usage:
+
+    The macros to declare MemPool type and functions are
+    gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix)
+    gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix)
+    gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix)
+
+    The data structures for MemPool are
+    typedef struct _gcsMEM_FS_MEM_POOL *    gcsMEM_FS_MEM_POOL;
+    typedef struct _gcsMEM_VS_MEM_POOL *    gcsMEM_VS_MEM_POOL;
+    typedef struct _gcsMEM_AFS_MEM_POOL *    gcsMEM_AFS_MEM_POOL;
+
+    The MemPool constructor and destructor functions are
+    gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT);
+    gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *);
+    gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL);
+    gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *);
+    gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT);
+    gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *);
+
+    FS:  for Fixed-Size data structures
+    VS:  for Variable-size data structures
+    AFS: for Array of Fixed-Size data structures
+
+
+    // Example 1: For a fixed-size data structure, struct gcsNode.
+    // It is used locally in a file, so the functions are static without prefix.
+    // At top level, declear allocate and free functions.
+    // The first argument is the data type.
+    // The second armument is the short name used in the fuctions.
+    gcmMEM_DeclareFSMemPool(struct gcsNode, Node, );
+
+    // The previous macro creates two inline functions,
+    // _AllocateNode and _FreeNode.
+
+    // In function or struct
+    gcsMEM_FS_MEM_POOL nodeMemPool;
+
+    // In function,
+    struct gcsNode * node;
+    gceSTATUS status;
+
+    // Before using the memory pool, initialize it.
+    // The second argument is the gcoOS object.
+    // The third argument is the number of data structures to allocate for each chunk.
+    status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode));
+    ...
+
+    // Allocate a node.
+    status = _AllocateNode(nodeMemPool, &node);
+    ...
+    // Free a node.
+    _FreeNode(nodeMemPool, node);
+
+    // After using the memory pool, free it.
+    gcfMEM_FreeFSMemPool(&nodeMemPool);
+
+
+    // Example 2: For array of fixed-size data structures, struct gcsNode.
+    // It is used in several files, so the functions are extern with prefix.
+    // At top level, declear allocate and free functions.
+    // The first argument is the data type, and the second one is the short name
+    // used in the fuctions.
+    gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt);
+
+    // The previous macro creates two inline functions,
+    // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray.
+
+    // In function or struct
+    gcsMEM_AFS_MEM_POOL nodeArrayMemPool;
+
+    // In function,
+    struct gcsNode * nodeArray;
+    gceSTATUS status;
+
+    // Before using the array memory pool, initialize it.
+    // The second argument is the gcoOS object, the third is the number of data
+    // structures to allocate for each chunk.
+    status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode));
+    ...
+
+    // Allocate a node array of size 100.
+    status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100);
+    ...
+    // Free a node array.
+    gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray);
+
+    // After using the array memory pool, free it.
+    gcfMEM_FreeAFSMemPool(&nodeArrayMemPool);
+
+*******************************************************************************/
+
+/*******************************************************************************
+**    To switch back to use gcoOS_Allocate and gcoOS_Free, add
+**    #define USE_LOCAL_MEMORY_POOL 0
+**    before including this file.
+*******************************************************************************/
+#ifndef USE_LOCAL_MEMORY_POOL
+/*
+    USE_LOCAL_MEMORY_POOL
+
+    This define enables the local memory management to improve performance.
+*/
+#define USE_LOCAL_MEMORY_POOL        1
+#endif
+
+/*******************************************************************************
+**                            Memory Pool Data Structures
+*******************************************************************************/
+#if USE_LOCAL_MEMORY_POOL
+    typedef struct _gcsMEM_FS_MEM_POOL *    gcsMEM_FS_MEM_POOL;
+    typedef struct _gcsMEM_VS_MEM_POOL *    gcsMEM_VS_MEM_POOL;
+    typedef struct _gcsMEM_AFS_MEM_POOL *    gcsMEM_AFS_MEM_POOL;
+#else
+    typedef gcoOS    gcsMEM_FS_MEM_POOL;
+    typedef gcoOS    gcsMEM_VS_MEM_POOL;
+    typedef gcoOS    gcsMEM_AFS_MEM_POOL;
+#endif
+
+/*******************************************************************************
+**                            Memory Pool Macros
+*******************************************************************************/
+#if USE_LOCAL_MEMORY_POOL
+#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer \
+    ) \
+{ \
+    return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName##List(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type *                    FirstPointer, \
+    Type *                    LastPointer \
+    ) \
+{ \
+    gceSTATUS               status; \
+    gcmHEADER_ARG("MemPool=0x%x FirstPointer=0x%x LastPointer=0x%x", MemPool, FirstPointer, LastPointer); \
+    status = gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+
+#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Size \
+    ) \
+{ \
+    gceSTATUS               status;\
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+    status = gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+ Prefix##_CAllocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Size \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+    gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS               status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pinter); \
+    status = gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+
+#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Count \
+    ) \
+{ \
+    gceSTATUS               status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+    status = gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Count \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+    gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS               status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+
+#else
+
+#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer \
+    ) \
+{ \
+    gceSTATUS               status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcoOS_Allocate(MemPool, \
+                            gcmSIZEOF(Type), \
+                            (gctPOINTER *) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type **                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+                            gcmSIZEOF(Type), \
+                            (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_FS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+
+#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_VS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Size \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+    status = gcoOS_Allocate(MemPool, \
+                            Size, \
+                            (gctPOINTER *) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName(\
+    gcsMEM_VS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Size \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+    gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+                            Size, \
+                            (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_VS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+
+#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Count \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+    status = gcoOS_Allocate(MemPool, \
+                            Count * gcmSIZEOF(Type), \
+                            (gctPOINTER *) Pointer); \
+    gcmFOOTER(); \
+    return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type **                    Pointer, \
+    gctUINT                    Count \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+    gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+                            Count * gcmSIZEOF(Type), \
+                            (gctPOINTER *) Pointer)); \
+    gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \
+    gcmFOOTER(); \
+    return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName(\
+    gcsMEM_AFS_MEM_POOL        MemPool, \
+    Type *                    Pointer \
+    ) \
+{ \
+    gceSTATUS                status; \
+    gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+    status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+    gcmFOOTER(); \
+    return status; \
+}
+#endif
+
+/*******************************************************************************
+**                            Memory Pool Data Functions
+*******************************************************************************/
+gceSTATUS
+gcfMEM_InitFSMemPool(
+    IN gcsMEM_FS_MEM_POOL * MemPool,
+    IN gcoOS                OS,
+    IN gctUINT                NodeCount,
+    IN gctUINT                NodeSize
+    );
+
+gceSTATUS
+gcfMEM_FreeFSMemPool(
+    IN gcsMEM_FS_MEM_POOL * MemPool
+    );
+
+gceSTATUS
+gcfMEM_FSMemPoolGetANode(
+    IN gcsMEM_FS_MEM_POOL    MemPool,
+    OUT gctPOINTER *        Node
+    );
+
+gceSTATUS
+gcfMEM_FSMemPoolFreeANode(
+    IN gcsMEM_FS_MEM_POOL    MemPool,
+    IN gctPOINTER            Node
+    );
+
+gceSTATUS
+gcfMEM_FSMemPoolFreeAList(
+    IN gcsMEM_FS_MEM_POOL    MemPool,
+    IN gctPOINTER            FirstNode,
+    IN gctPOINTER            LastNode
+    );
+
+gceSTATUS
+gcfMEM_InitVSMemPool(
+    IN gcsMEM_VS_MEM_POOL * MemPool,
+    IN gcoOS                OS,
+    IN gctUINT                BlockSize,
+    IN gctBOOL                RecycleFreeNode
+    );
+
+gceSTATUS
+gcfMEM_FreeVSMemPool(
+    IN gcsMEM_VS_MEM_POOL * MemPool
+    );
+
+gceSTATUS
+gcfMEM_VSMemPoolGetANode(
+    IN gcsMEM_VS_MEM_POOL    MemPool,
+    IN gctUINT                Size,
+    IN gctUINT                Alignment,
+    OUT gctPOINTER *        Node
+    );
+
+gceSTATUS
+gcfMEM_VSMemPoolFreeANode(
+    IN gcsMEM_VS_MEM_POOL    MemPool,
+    IN gctPOINTER            Node
+    );
+
+gceSTATUS
+gcfMEM_InitAFSMemPool(
+    IN gcsMEM_AFS_MEM_POOL *MemPool,
+    IN gcoOS                OS,
+    IN gctUINT                NodeCount,
+    IN gctUINT                NodeSize
+    );
+
+gceSTATUS
+gcfMEM_FreeAFSMemPool(
+    IN gcsMEM_AFS_MEM_POOL *MemPool
+    );
+
+gceSTATUS
+gcfMEM_AFSMemPoolGetANode(
+    IN gcsMEM_AFS_MEM_POOL    MemPool,
+    IN gctUINT                Count,
+    OUT gctPOINTER *        Node
+    );
+
+gceSTATUS
+gcfMEM_AFSMemPoolFreeANode(
+    IN gcsMEM_AFS_MEM_POOL    MemPool,
+    IN gctPOINTER            Node
+    );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (gcdENABLE_3D || gcdENABLE_VG) */
+#endif /* __gc_hal_mem_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_metadata.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_metadata.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_metadata_h_
+#define __gc_hal_kernel_metadata_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Macro to combine four characters into a Character Code. */
+#define __FOURCC(a, b, c, d) \
+    ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+
+#define VIV_VIDMEM_METADATA_MAGIC __FOURCC('v', 'i', 'v', 'm')
+
+/* Metadata for cross-device fd share with additional (ts) info. */
+typedef struct _VIV_VIDMEM_METADATA
+{
+    uint32_t magic;
+
+    int32_t  ts_fd;
+    void *   ts_dma_buf;
+
+    uint32_t fc_enabled;
+    uint32_t fc_value;
+    uint32_t fc_value_upper;
+
+    uint32_t compressed;
+    uint32_t compress_format;
+} _VIV_VIDMEM_METADATA;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_metadata_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h
@@ -0,0 +1,1408 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_options_h_
+#define __gc_hal_options_h_
+
+/*
+    gcdSECURITY
+
+*/
+#ifndef gcdSECURITY
+#   define gcdSECURITY                          0
+#endif
+
+/*
+    gcdPRINT_VERSION
+
+        Print HAL version.
+*/
+#ifndef gcdPRINT_VERSION
+#   define gcdPRINT_VERSION                     0
+#endif
+
+/*
+USE_KERNEL_VIRTUAL_BUFFERS
+
+This define enables the use of VM for gckCommand and fence buffers.
+*/
+#ifndef USE_KERNEL_VIRTUAL_BUFFERS
+#if defined(UNDER_CE)
+#   define USE_KERNEL_VIRTUAL_BUFFERS           1
+#else
+#   define USE_KERNEL_VIRTUAL_BUFFERS           1
+#endif
+#endif
+
+/*
+    USE_NEW_LINUX_SIGNAL
+
+        This define enables the Linux kernel signaling between kernel and user.
+*/
+#ifndef USE_NEW_LINUX_SIGNAL
+#   define USE_NEW_LINUX_SIGNAL                 0
+#endif
+
+/*
+    USE_LINUX_PCIE
+
+        This define enables galcore as a Linux PCIE driver.
+*/
+#ifndef USE_LINUX_PCIE
+#   define USE_LINUX_PCIE                       0
+#endif
+
+/*
+    VIVANTE_PROFILER
+
+        This define enables the profiler for hardware counters.
+*/
+#ifndef VIVANTE_PROFILER
+#   define VIVANTE_PROFILER                     1
+#endif
+
+/*
+    gcdUSE_VG
+
+        Enable VG HAL layer (only for GC350).
+*/
+#ifndef gcdUSE_VG
+#   define gcdUSE_VG                            0
+#endif
+
+/*
+    gcdUSE_VX
+
+        Enable VX HAL layer.
+*/
+#ifndef gcdUSE_VX
+#   define gcdUSE_VX                            1
+#endif
+
+/*
+    PROFILE_HAL_COUNTERS
+
+        This define enables HAL counter profiling support.  HW and SHADER
+        counter profiling depends on this.
+*/
+#ifndef PROFILE_HAL_COUNTERS
+#   define PROFILE_HAL_COUNTERS                 1
+#endif
+
+/*
+    PROFILE_HW_COUNTERS
+
+        This define enables HW counter profiling support.
+*/
+#ifndef PROFILE_HW_COUNTERS
+#   define PROFILE_HW_COUNTERS                  1
+#endif
+
+/*
+    PROFILE_SHADER_COUNTERS
+
+        This define enables SHADER counter profiling support.
+*/
+#ifndef PROFILE_SHADER_COUNTERS
+#   define PROFILE_SHADER_COUNTERS              1
+#endif
+
+/*
+    COMMAND_PROCESSOR_VERSION
+
+        The version of the command buffer and task manager.
+*/
+#define COMMAND_PROCESSOR_VERSION               1
+
+/*
+    gcdDUMP
+
+        Dump for hw capture.
+        When set to 1, a dump of all states and memory uploads, as well as other
+        hardware related execution will be printed to the debug console.  This
+        data can be used for playing back applications.
+
+        When set to 2, for vxc, all output memory will be dump.
+
+        Please get tweak settings in gc_hal_dump.h.
+*/
+#ifndef gcdDUMP
+#   define gcdDUMP                              0
+#endif
+
+/*
+    gcdDUMP_IN_KERNEL
+
+        Enhanced feature for hw capture capture.
+        Required for MCFE.
+        When set to 1, all dumps will happen in the kernel.  This is handy if
+        you want the kernel to dump its command buffers as well and the data
+        needs to be in sync.
+
+        Dump in kernel implies kernel command dump.
+        See debugfs:/gc/dump/ for runtime configuration.
+*/
+#ifndef gcdDUMP_IN_KERNEL
+#   define gcdDUMP_IN_KERNEL                    0
+#endif
+
+/*
+    gcdDUMP_2D
+
+        Dump for 2D capture.
+        When set to non-zero, it will dump the 2D command and surface.
+
+        Please get tweak settings in gc_hal_dump.h.
+*/
+#ifndef gcdDUMP_2D
+#   define gcdDUMP_2D                           0
+#endif
+
+/*
+    gcdDUMP_API
+
+        Dump driver level API.
+        When set to 1, a high level dump of the EGL and GL/VG APs's are
+        captured.
+
+        Please get tweak settings in gc_hal_dump.h.
+*/
+#ifndef gcdDUMP_API
+#   define gcdDUMP_API                          0
+#endif
+
+/*
+    gcdDUMP_PER_OPERATION
+
+        Operation based dump.
+
+        Dump the block as below.
+        1. Multiple operations belong to the same SW tiling block.
+        2. Single operation which is NOT in any SW tiling block.
+*/
+#ifndef gcdDUMP_PER_OPERATION
+#   define gcdDUMP_PER_OPERATION                0
+#endif
+
+/*
+    gcdDEBUG_OPTION
+        When set to 1, the debug options are enabled. We must set other MACRO to enable
+        sub case.
+*/
+#ifndef gcdDEBUG_OPTION
+#   define gcdDEBUG_OPTION                      0
+
+#if gcdDEBUG_OPTION
+/*
+    gcdDEBUG_OPTION_KEY
+        The process name of debug application.
+*/
+#ifndef gcdDEBUG_OPTION_KEY
+#          define gcdDEBUG_OPTION_KEY                           "process"
+#       endif
+/*
+    gcdDEBUG_OPTION_NO_GL_DRAWS
+        When set to 1, all glDrawArrays and glDrawElements will be skip.
+*/
+#ifndef gcdDEBUG_OPTION_NO_GL_DRAWS
+#           define gcdDEBUG_OPTION_NO_GL_DRAWS                  0
+#       endif
+/*
+    gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES
+        When set to 1, all DrawPrimitives will be skip.
+*/
+#ifndef gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES
+#           define gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES           0
+#       endif
+/*
+    gcdDEBUG_OPTION_SKIP_SWAP
+        When set to 1, just one out of gcdDEBUG_OPTION_SKIP_FRAMES(such as 1/10) eglSwapBuffers will be resolve,
+        others skip.
+*/
+#ifndef gcdDEBUG_OPTION_SKIP_SWAP
+#           define gcdDEBUG_OPTION_SKIP_SWAP                    0
+#           define gcdDEBUG_OPTION_SKIP_FRAMES                  10
+#       endif
+/*
+    gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET
+        When set to 1, the format of render target will force to RGB565.
+*/
+#ifndef gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET
+#           define gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET    0
+#       endif
+/*
+    gcdDEBUG_OPTION_NONE_TEXTURE
+        When set to 1, the type of texture will be set to 0x0.
+*/
+#ifndef gcdDEBUG_OPTION_NONE_TEXTURE
+#           define gcdDEBUG_OPTION_NONE_TEXTURE                 0
+#       endif
+/*
+    gcdDEBUG_OPTION_NONE_DEPTH
+        When set to 1, the depth format of surface will be set to gcvSURF_UNKNOWN.
+*/
+#ifndef gcdDEBUG_OPTION_NONE_DEPTH
+#           define gcdDEBUG_OPTION_NONE_DEPTH                   0
+#       endif
+
+/*
+    gcdDEBUG_FORCE_CONTEXT_UPDATE
+        When set to 1, context will be updated before every commit.
+*/
+#ifndef gcdDEBUG_FORCE_CONTEXT_UPDATE
+#           define gcdDEBUG_FORCE_CONTEXT_UPDATE                0
+#       endif
+
+
+/*
+    gcdDEBUG_FORCE_CONTEXT_UPDATE
+        When set to 1, pool of each type surface can be specified by
+        changing poolPerType[] in gcsSURF_NODE_Construct.
+*/
+#ifndef gcdDEBUG_OPTION_SPECIFY_POOL
+#           define gcdDEBUG_OPTION_SPECIFY_POOL                 0
+#       endif
+
+#   endif
+#endif
+
+/*
+    gcdENABLE_FSCALE_VAL_ADJUST
+        When non-zero, FSCALE_VAL when gcvPOWER_ON can be adjusted externally.
+ */
+#ifndef gcdENABLE_FSCALE_VAL_ADJUST
+#   define gcdENABLE_FSCALE_VAL_ADJUST          1
+#endif
+
+/*
+    gcdCAPTURE_ONLY_MODE
+        When non-zero, driver is built with capture only mode.
+        1) Set DDR address range in capture file with contiguousBase and contiguoutsSize.
+           Video memory allocation will go through reserved pool with capture only mode.
+        2) Set SRAM address range in capture file with sRAMBases, sRAMSizes and extSRAMBases, extSRAMSizes.
+           Video memory querion will go through reserved pool with capture only mode.
+        3) TODO: SRAM video memory allocation.
+*/
+#ifndef gcdCAPTURE_ONLY_MODE
+#   define gcdCAPTURE_ONLY_MODE                 0
+#endif
+
+/*
+    gcdNULL_DRIVER
+
+    Set to 1 for infinite speed hardware.
+    Set to 2 for bypassing the HAL.
+*/
+#ifndef gcdNULL_DRIVER
+#   define gcdNULL_DRIVER  0
+#endif
+
+/*
+    gcdENABLE_TIMEOUT_DETECTION
+
+        Enable timeout detection.
+*/
+#ifndef gcdENABLE_TIMEOUT_DETECTION
+#   define gcdENABLE_TIMEOUT_DETECTION          0
+#endif
+
+/*
+    gcdCMD_BUFFER_SIZE
+
+        Number of bytes in a command buffer.
+*/
+#ifndef gcdCMD_BUFFER_SIZE
+#if gcdCAPTURE_ONLY_MODE
+#   define gcdCMD_BUFFER_SIZE                   (4 << 10)
+#else
+#   define gcdCMD_BUFFER_SIZE                   (128 << 10)
+#endif
+#endif
+
+/*
+    gcdCMD_BLT_BUFFER_SIZE
+
+        Number of bytes in a command buffer.
+*/
+#ifndef gcdCMD_BLT_BUFFER_SIZE
+#   define gcdCMD_BLT_BUFFER_SIZE                (1 << 10)
+#endif
+
+/*
+    gcdCMD_BUFFERS
+
+        Number of command buffers to use per client.
+*/
+#ifndef gcdCMD_BUFFERS
+#if gcdCAPTURE_ONLY_MODE
+#   define gcdCMD_BUFFERS                       1
+#else
+#   define gcdCMD_BUFFERS                       2
+#endif
+#endif
+
+/*
+    gcdMAX_CMD_BUFFERS
+
+        Maximum number of command buffers to use per client.
+*/
+#ifndef gcdMAX_CMD_BUFFERS
+#   define gcdMAX_CMD_BUFFERS                   8
+#endif
+
+/*
+    gcdCOMMAND_QUEUES
+
+        Number of command queues in the kernel.
+*/
+#ifndef gcdCOMMAND_QUEUES
+#   define gcdCOMMAND_QUEUES                    2
+#endif
+
+/*
+    gcdPOWER_CONTROL_DELAY
+
+        The delay in milliseconds required to wait until the GPU has woke up
+        from a suspend or power-down state.  This is system dependent because
+        the bus clock also needs to stabalize.
+*/
+#ifndef gcdPOWER_CONTROL_DELAY
+#   define gcdPOWER_CONTROL_DELAY               0
+#endif
+
+/*
+    gcdMMU_SIZE
+
+        Size of the MMU page table in bytes.  Each 4 bytes can hold 4kB worth of
+        virtual data.
+*/
+#ifndef gcdMMU_SIZE
+#   define gcdMMU_SIZE                          (2048 << 10)
+#endif
+
+#ifndef gcdGC355_VGMMU_MEMORY_SIZE_KB
+#   define gcdGC355_VGMMU_MEMORY_SIZE_KB   32
+#endif
+
+/*
+    gcdREGISTER_READ_FROM_USER
+    gcdREGISTER_WRITE_FROM_USER
+
+        Set to 1 to allow IOCTL calls to get through from user land.  This
+        should only be in debug or development drops.
+*/
+#ifndef gcdREGISTER_READ_FROM_USER
+#   define gcdREGISTER_READ_FROM_USER           1
+#endif
+
+#ifndef gcdREGISTER_WRITE_FROM_USER
+#   define gcdREGISTER_WRITE_FROM_USER          0
+#endif
+
+/*
+    gcdHEAP_SIZE
+
+        Set the allocation size for the internal heaps.  Each time a heap is
+        full, a new heap will be allocated with this minmimum amount of bytes.
+        The bigger this size, the fewer heaps there are to allocate, the better
+        the performance.  However, heaps won't be freed until they are
+        completely free, so there might be some more memory waste if the size is
+        too big.
+*/
+#ifndef gcdHEAP_SIZE
+#   define gcdHEAP_SIZE                         (64 << 10)
+#endif
+
+/*
+    gcdPOWER_SUSPEND_WHEN_IDLE
+
+        Set to 1 to make GPU enter gcvPOWER_SUSPEND when idle detected,
+        otherwise GPU will enter gcvPOWER_IDLE.
+*/
+#ifndef gcdPOWER_SUSPEND_WHEN_IDLE
+#   define gcdPOWER_SUSPEND_WHEN_IDLE          1
+#endif
+
+#ifndef gcdFPGA_BUILD
+#   define gcdFPGA_BUILD                       0
+#endif
+
+/*
+    gcdGPU_TIMEOUT
+
+        This define specified the number of milliseconds the system will wait
+        before it broadcasts the GPU is stuck.  In other words, it will define
+        the timeout of any operation that needs to wait for the GPU.
+
+        If the value is 0, no timeout will be checked for.
+*/
+#ifndef gcdGPU_TIMEOUT
+#if gcdFPGA_BUILD
+#   define gcdGPU_TIMEOUT                   2000000
+#else
+#   define gcdGPU_TIMEOUT                   20000
+#endif
+#endif
+
+/*
+    gcdGPU_2D_TIMEOUT
+
+        This define specified the number of milliseconds the system will wait
+        before it broadcasts the 2D GPU is stuck.  In other words, it will define
+        the timeout of any operation that needs to wait for the GPU.
+
+        If the value is 0, no timeout will be checked for.
+*/
+#ifndef gcdGPU_2D_TIMEOUT
+#   define gcdGPU_2D_TIMEOUT                4000
+#endif
+
+
+/*
+    gcdGPU_ADVANCETIMER
+
+        it is advance timer.
+*/
+#ifndef gcdGPU_ADVANCETIMER
+#   define gcdGPU_ADVANCETIMER                  250
+#endif
+
+/*
+    gcdSTATIC_LINK
+
+        This define disalbes static linking;
+*/
+#ifndef gcdSTATIC_LINK
+#   define gcdSTATIC_LINK                       0
+#endif
+
+/*
+    gcdUSE_NEW_HEAP
+
+        Setting this define to 1 enables new heap.
+*/
+#ifndef gcdUSE_NEW_HEAP
+#   define gcdUSE_NEW_HEAP                      0
+#endif
+
+/*
+    gcdCMD_NO_2D_CONTEXT
+
+        This define enables no-context 2D command buffer.
+*/
+#ifndef gcdCMD_NO_2D_CONTEXT
+#   define gcdCMD_NO_2D_CONTEXT                 1
+#endif
+
+/*
+    gcdENABLE_BUFFER_ALIGNMENT
+
+    When enabled, video memory is allocated  with atleast 16KB aligment
+    between multiple sub-buffers.
+*/
+#ifndef gcdENABLE_BUFFER_ALIGNMENT
+#if gcdCAPTURE_ONLY_MODE
+#   define gcdENABLE_BUFFER_ALIGNMENT             0
+#else
+#   define gcdENABLE_BUFFER_ALIGNMENT             1
+#endif
+#endif
+
+/*
+    gcdENABLE_BANK_ALIGNMENT
+
+    When enabled, video memory is allocated bank aligned. The vendor can modify
+    _GetSurfaceBankAlignment() and _GetBankOffsetBytes() to define how
+    different types of allocations are bank and channel aligned.
+    When disabled (default), no bank alignment is done.
+    For CAPTURE ONLY MODE, should make sure that gcdENABLE_BANK_ALIGNMENT is disabled.
+*/
+#ifndef gcdENABLE_BANK_ALIGNMENT
+#if gcdCAPTURE_ONLY_MODE
+#   define gcdENABLE_BANK_ALIGNMENT             0
+#else
+#   define gcdENABLE_BANK_ALIGNMENT             0
+#endif
+#endif
+
+/*
+    gcdBANK_BIT_START
+
+    Specifies the start bit of the bank (inclusive).
+*/
+#ifndef gcdBANK_BIT_START
+#   define gcdBANK_BIT_START                    12
+#endif
+
+/*
+    gcdBANK_BIT_END
+
+    Specifies the end bit of the bank (inclusive).
+*/
+#ifndef gcdBANK_BIT_END
+#   define gcdBANK_BIT_END                      14
+#endif
+
+/*
+    gcdBANK_CHANNEL_BIT
+
+    When set, video memory when allocated bank aligned is allocated such that
+    render and depth buffer addresses alternate on the channel bit specified.
+    This option has an effect only when gcdENABLE_BANK_ALIGNMENT is enabled.
+    When disabled (default), no alteration is done.
+*/
+#ifndef gcdBANK_CHANNEL_BIT
+#   define gcdBANK_CHANNEL_BIT                  7
+#endif
+
+/*
+    gcdDYNAMIC_SPEED
+
+        When non-zero, it informs the kernel driver to use the speed throttling
+        broadcasting functions to inform the system the GPU should be spet up or
+        slowed down. It will send a broadcast for slowdown each "interval"
+        specified by this define in milliseconds
+        (gckOS_BroadcastCalibrateSpeed).
+*/
+#ifndef gcdDYNAMIC_SPEED
+#    define gcdDYNAMIC_SPEED                    2000
+#endif
+
+/*
+    gcdDYNAMIC_EVENT_THRESHOLD
+
+        When non-zero, it specifies the maximum number of available events at
+        which the kernel driver will issue a broadcast to speed up the GPU
+        (gckOS_BroadcastHurry).
+*/
+#ifndef gcdDYNAMIC_EVENT_THRESHOLD
+#    define gcdDYNAMIC_EVENT_THRESHOLD          5
+#endif
+
+/*
+    gcdENABLE_PROFILING
+
+        Enable profiling macros.
+*/
+#ifndef gcdENABLE_PROFILING
+#   define gcdENABLE_PROFILING                  0
+#endif
+
+/*
+    gcdENABLE_128B_MERGE
+
+        Enable 128B merge for the BUS control.
+*/
+#ifndef gcdENABLE_128B_MERGE
+#   define gcdENABLE_128B_MERGE                 0
+#endif
+
+/*
+    gcdFRAME_DB
+
+        When non-zero, it specified the number of frames inside the frame
+        database. The frame DB will collect per-frame timestamps and hardware
+        counters.
+*/
+#ifndef gcdFRAME_DB
+#   define gcdFRAME_DB                          0
+#   define gcdFRAME_DB_RESET                    0
+#   define gcdFRAME_DB_NAME                     "/var/log/frameDB.log"
+#endif
+
+/*
+   gcdENABLE_CACHEABLE_COMMAND_BUFFER
+
+        When non-zero, command buffer will be cacheable.
+*/
+#ifndef gcdENABLE_CACHEABLE_COMMAND_BUFFER
+#   define gcdENABLE_CACHEABLE_COMMAND_BUFFER          0
+#endif
+
+/*
+   gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+
+        When non-zero, all video memory will be bufferable by default.
+*/
+#ifndef gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+#if gcdFPGA_BUILD
+#   define gcdENABLE_BUFFERABLE_VIDEO_MEMORY           0
+#else
+#   define gcdENABLE_BUFFERABLE_VIDEO_MEMORY           1
+#endif
+#endif
+
+/*
+    gcdENABLE_INFINITE_SPEED_HW
+            enable the Infinte HW, this is for 2D openVG
+*/
+#ifndef gcdENABLE_INFINITE_SPEED_HW
+#   define gcdENABLE_INFINITE_SPEED_HW          0
+#endif
+
+/*
+    gcdPOWEROFF_TIMEOUT
+
+        When non-zero, GPU will power off automatically from
+        idle state, and gcdPOWEROFF_TIMEOUT is also the default
+        timeout in milliseconds.
+ */
+#ifndef gcdPOWEROFF_TIMEOUT
+#   define gcdPOWEROFF_TIMEOUT                  300
+#endif
+
+/*
+    QNX_SINGLE_THREADED_DEBUGGING
+*/
+#ifndef QNX_SINGLE_THREADED_DEBUGGING
+#   define QNX_SINGLE_THREADED_DEBUGGING        0
+#endif
+
+/*
+    gcdSHARED_RESOLVE_BUFFER_ENABLED
+
+        Use shared resolve buffer for all app buffers.
+*/
+#ifndef gcdSHARED_RESOLVE_BUFFER_ENABLED
+#   define gcdSHARED_RESOLVE_BUFFER_ENABLED     0
+#endif
+
+/*
+     gcdUSE_TRIANGLE_STRIP_PATCH
+ */
+#ifndef gcdUSE_TRIANGLE_STRIP_PATCH
+#   define gcdUSE_TRIANGLE_STRIP_PATCH          1
+#endif
+
+/*
+    gcdSHARED_PAGETABLE
+
+        When non-zero, multiple GPUs in one chip with same MMU use
+        one shared pagetable. So that when accessing same surface,
+        they can use same GPU virtual address.
+*/
+#ifndef gcdSHARED_PAGETABLE
+#   define gcdSHARED_PAGETABLE                  0
+#endif
+
+#ifndef gcdUSE_PVR
+#   define gcdUSE_PVR                           1
+#endif
+
+/*
+    gcdSMALL_BLOCK_SIZE
+
+        When non-zero, a part of VIDMEM will be reserved for requests
+        whose requesting size is less than gcdSMALL_BLOCK_SIZE.
+
+        For Linux, it's the size of a page. If this requeset fallbacks
+        to gcvPOOL_VIRTUAL, memory will be wasted
+        because they allocate a page at least.
+*/
+#ifndef gcdSMALL_BLOCK_SIZE
+#   define gcdSMALL_BLOCK_SIZE                  4096
+#   define gcdRATIO_FOR_SMALL_MEMORY            32
+#endif
+
+/*
+    gcdENABLE_GPU_1M_PAGE
+        When non-zero, GPU page size will be 1M until the pool is out of memory
+        and low-level to 4K pages. When zero, it uses 4k GPU pages.
+*/
+#ifndef gcdENABLE_GPU_1M_PAGE
+#if !gcdSECURITY && defined(LINUX)
+#   define gcdENABLE_GPU_1M_PAGE                0
+#else
+#   define gcdENABLE_GPU_1M_PAGE                0
+#endif
+#endif
+
+/*
+    gcdCONTIGUOUS_SIZE_LIMIT
+        When non-zero, size of video node from gcvPOOL_VIRTUAL contiguous is
+        limited by gcdCONTIGUOUS_SIZE_LIMIT.
+*/
+#ifndef gcdCONTIGUOUS_SIZE_LIMIT
+#   define gcdCONTIGUOUS_SIZE_LIMIT             0
+#endif
+
+/*
+    gcdLINK_QUEUE_SIZE
+
+        When non-zero, driver maintains a queue to record information of
+        latest lined context buffer and command buffer. Data in this queue
+        is be used to debug.
+*/
+#ifndef gcdLINK_QUEUE_SIZE
+#   define gcdLINK_QUEUE_SIZE                   64
+#endif
+
+/*  gcdALPHA_KILL_IN_SHADER
+
+        Enable alpha kill inside the shader. This will be set automatically by the
+        HAL if certain states match a criteria.
+*/
+#ifndef gcdALPHA_KILL_IN_SHADER
+#   define gcdALPHA_KILL_IN_SHADER              1
+#endif
+
+
+#ifndef gcdPRINT_SWAP_TIME
+#   define gcdPRINT_SWAP_TIME                   0
+#endif
+
+/*
+    gcdDVFS
+
+        When non-zero, software will make use of dynamic voltage and
+        frequency feature.
+ */
+#ifndef gcdDVFS
+#   define gcdDVFS                              0
+#   define gcdDVFS_ANAYLSE_WINDOW               4
+#   define gcdDVFS_POLLING_TIME                 (gcdDVFS_ANAYLSE_WINDOW * 4)
+#endif
+
+#ifndef gcdSYNC
+#   define gcdSYNC                              1
+#endif
+
+#ifndef gcdSHADER_SRC_BY_MACHINECODE
+#   define gcdSHADER_SRC_BY_MACHINECODE         1
+#endif
+
+#ifndef gcdGLB27_SHADER_REPLACE_OPTIMIZATION
+#    define gcdGLB27_SHADER_REPLACE_OPTIMIZATION 1
+#endif
+
+
+/*
+    gcdSUPPORT_SWAP_RECTANGLE
+
+        Support swap with a specific rectangle.
+
+        Set the rectangle with eglSetSwapRectangleVIV api.
+        Android only.
+*/
+#ifndef gcdSUPPORT_SWAP_RECTANGLE
+#   define gcdSUPPORT_SWAP_RECTANGLE            1
+#endif
+
+/*
+    gcdGPU_LINEAR_BUFFER_ENABLED
+
+        Use linear buffer for GPU apps so HWC can do 2D composition.
+        Android only.
+*/
+#ifndef gcdGPU_LINEAR_BUFFER_ENABLED
+#   define gcdGPU_LINEAR_BUFFER_ENABLED         1
+#endif
+
+/*
+    gcdENABLE_RENDER_INTO_WINDOW
+
+        Enable Render-Into-Window (ie, No-Resolve) feature on android.
+        NOTE that even if enabled, it still depends on hardware feature and
+        android application behavior. When hardware feature or application
+        behavior can not support render into window mode, it will fail back
+        to normal mode.
+        When Render-Into-Window is finally used, window back buffer of android
+        applications will be allocated matching render target tiling format.
+        Otherwise buffer tiling is decided by the above option
+        'gcdGPU_LINEAR_BUFFER_ENABLED'.
+        Android only for now.
+*/
+#ifndef gcdENABLE_RENDER_INTO_WINDOW
+#   define gcdENABLE_RENDER_INTO_WINDOW         1
+#endif
+
+/*
+    gcdENABLE_RENDER_INTO_WINDOW_WITH_FC
+
+        Enable Direct-rendering (ie, No-Resolve) with tile status.
+        This is expremental and in development stage.
+        This will dynamically check if color compression is available.
+*/
+#ifndef gcdENABLE_RENDER_INTO_WINDOW_WITH_FC
+#   define gcdENABLE_RENDER_INTO_WINDOW_WITH_FC 1
+#endif
+
+/*
+    gcdENABLE_BLIT_BUFFER_PRESERVE
+
+        Render-Into-Window (ie, No-Resolve) does not include preserved swap
+        behavior.  This feature can enable buffer preserve in No-Resolve mode.
+        When enabled, previous buffer (may be part of ) will be resolve-blitted
+        to current buffer.
+*/
+#ifndef gcdENABLE_BLIT_BUFFER_PRESERVE
+#   define gcdENABLE_BLIT_BUFFER_PRESERVE       1
+#endif
+
+/*
+    gcdANDROID_NATIVE_FENCE_SYNC
+
+        Enable android native fence sync. It is introduced since jellybean-4.2.
+        Depends on linux kernel option: CONFIG_SYNC.
+
+        0: Disabled
+        1: Build framework for native fence sync feature, and EGL extension
+        2: Enable async swap buffers for client
+           * Native fence sync for client 'queueBuffer' in EGL, which is
+             'acquireFenceFd' for layer in compositor side.
+        3. Enable async hwcomposer composition.
+           * 'releaseFenceFd' for layer in compositor side, which is native
+             fence sync when client 'dequeueBuffer'
+           * Native fence sync for compositor 'queueBuffer' in EGL, which is
+             'acquireFenceFd' for framebuffer target for DC
+ */
+#ifndef gcdANDROID_NATIVE_FENCE_SYNC
+#   define gcdANDROID_NATIVE_FENCE_SYNC         0
+#endif
+
+#ifndef gcdLINUX_SYNC_FILE
+#   define gcdLINUX_SYNC_FILE                   0
+#endif
+
+/*
+    gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+
+        Enable implicit android native buffer sync.
+
+        For non-HW_RENDER buffer, CPU (or other hardware) and GPU can access
+        the buffer at the same time. This is to add implicit synchronization
+        between CPU (or the hardware) and GPU.
+
+        Eventually, please do not use implicit native buffer sync, but use
+        "fence sync" or "android native fence sync" instead in libgui, which
+        can be enabled in frameworks/native/libs/gui/Android.mk. This kind
+        of synchronization should be done by app but not driver itself.
+
+        Please disable this option when either "fence sync" or
+        "android native fence sync" is enabled.
+ */
+#ifndef gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+#   define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC   1
+#endif
+
+/*
+ * Implicit native buffer sync is not needed when ANDROID_native_fence_sync
+ * is available.
+ */
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#   undef  gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+#   define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC   0
+#endif
+
+/*
+    gcdUSE_WCLIP_PATCH
+
+        Enable wclipping patch.
+*/
+#ifndef gcdUSE_WCLIP_PATCH
+#   define gcdUSE_WCLIP_PATCH                   1
+#endif
+
+#ifndef gcdUSE_NPOT_PATCH
+#   define gcdUSE_NPOT_PATCH                    1
+#endif
+
+/*
+    gcdINTERNAL_COMMENT
+
+        Wrap internal comment, content wrapped by it and the macor itself
+        will be removed in release driver.
+*/
+#ifndef gcdINTERNAL_COMMENT
+#   define gcdINTERNAL_COMMENT                  1
+#endif
+
+/*
+    gcdRTT_DISABLE_FC
+
+        Disable RTT FC support. For test only.
+*/
+#ifndef gcdRTT_DISABLE_FC
+#   define gcdRTT_DISABLE_FC                    0
+#endif
+
+/*
+    gcdFORCE_MIPMAP
+
+        Force generate mipmap for texture.
+*/
+#ifndef gcdFORCE_MIPMAP
+#   define gcdFORCE_MIPMAP                      0
+#endif
+
+/*
+    gcdFORCE_BILINEAR
+
+        Force bilinear for mipfilter.
+*/
+#ifndef gcdFORCE_BILINEAR
+#   define gcdFORCE_BILINEAR                    1
+#endif
+
+/*
+    gcdBINARY_TRACE
+
+        When non-zero, binary trace will be generated.
+
+        When gcdBINARY_TRACE_FILE_SIZE is non-zero, binary trace buffer will
+        be written to a file which size is limited to
+        gcdBINARY_TRACE_FILE_SIZE.
+*/
+#ifndef gcdBINARY_TRACE
+#   define gcdBINARY_TRACE                       0
+#   define gcdBINARY_TRACE_FILE_SIZE             0
+#endif
+
+#ifndef gcdMOVG
+#   define gcdMOVG                              0
+#   define gcdENABLE_TS_DOUBLE_BUFFER           1
+#else
+#if gcdMOVG
+#   define gcdENABLE_TS_DOUBLE_BUFFER           0
+#else
+#       define gcdENABLE_TS_DOUBLE_BUFFER       1
+#endif
+#endif
+
+/*  gcdINTERRUPT_STATISTIC
+ *
+ *  Monitor the event send to GPU and interrupt issued by GPU.
+ */
+
+#ifndef gcdINTERRUPT_STATISTIC
+#if defined(LINUX) || defined(__QNXNTO__) || defined(UNDER_CE) || defined(__VXWORKS__)
+#   define gcdINTERRUPT_STATISTIC               1
+#else
+#   define gcdINTERRUPT_STATISTIC               0
+#endif
+#endif
+
+/*
+    gcdFENCE_WAIT_LOOP_COUNT
+        Wait fence, loop count.
+*/
+#ifndef gcdFENCE_WAIT_LOOP_COUNT
+#   define gcdFENCE_WAIT_LOOP_COUNT 100
+#endif
+
+/*
+    gcdPARTIAL_FAST_CLEAR
+        When it's not zero, partial fast clear is enabled.
+        Depends on gcdHAL_3D_DRAWBLIT, if gcdHAL_3D_DRAWBLIT is not enabled,
+        only available when scissor box is completely aligned.
+        Expremental, under test only. Not ready for production.
+*/
+#ifndef gcdPARTIAL_FAST_CLEAR
+#   define gcdPARTIAL_FAST_CLEAR                0
+#endif
+
+/*
+    gcdREMOVE_SURF_ORIENTATION
+        When it's not zero, we will remove surface orientation function.
+        It wil become to a parameter of resolve function.
+*/
+#ifndef gcdREMOVE_SURF_ORIENTATION
+#   define gcdREMOVE_SURF_ORIENTATION 1
+#endif
+
+
+
+/*
+    gcdTEST_DEC200
+        Test part for DEC200. Remove when release.
+*/
+#ifndef gcdTEST_DEC200
+#   define gcdTEST_DEC200                       0
+#endif
+
+/*
+    gcdPATTERN_FAST_PATH
+         For pattern match
+*/
+#ifndef gcdPATTERN_FAST_PATH
+#   define gcdPATTERN_FAST_PATH       1
+#endif
+
+/*
+    gcdUSE_INPUT_DEVICE
+         disable input devices usage under fb mode to support fb+vdk multi-process
+*/
+#ifndef gcdUSE_INPUT_DEVICE
+#   define gcdUSE_INPUT_DEVICE        0
+#endif
+
+/*
+    gcdPERFORMANCE_ANALYSIS
+
+        When set to 1, driver will pass information through loadstate
+        to HW. This loadstate does not impact HW execution.
+*/
+#ifndef gcdPERFORMANCE_ANALYSIS
+#   define gcdPERFORMANCE_ANALYSIS              0
+#endif
+
+/*
+    gcdFRAMEINFO_STATISTIC
+        When enable, collect frame information.
+*/
+#ifndef gcdFRAMEINFO_STATISTIC
+
+#if (defined(DBG) && DBG) || defined(DEBUG)                || \
+     defined(_DEBUG) || gcdDUMP || gcdPERFORMANCE_ANALYSIS || \
+     (defined(WIN32) && !defined(UNDER_CE))                || \
+     gcdFPGA_BUILD
+
+#   define gcdFRAMEINFO_STATISTIC      1
+#else
+#   define gcdFRAMEINFO_STATISTIC      0
+#endif
+
+#endif
+
+/*
+    gcdDEC_ENABLE_AHB
+        Enable DEC300 compression AHB mode or not.
+*/
+#ifndef gcdDEC_ENABLE_AHB
+#   define gcdDEC_ENABLE_AHB                    0
+#endif
+
+/*
+    gcdENABLE_UNIFIED_CONSTANT
+        Enable unified constant or not.
+*/
+#ifndef gcdENABLE_UNIFIED_CONSTANT
+#   define gcdENABLE_UNIFIED_CONSTANT           1
+#endif
+
+/*
+    Core configurations. By default enable all cores.
+*/
+#ifndef gcdENABLE_3D
+#   define gcdENABLE_3D                         1
+#endif
+
+#ifndef gcdENABLE_2D
+#   define gcdENABLE_2D                         1
+#endif
+
+#ifndef gcdENABLE_VG
+#   define gcdENABLE_VG                         0
+#endif
+
+#ifndef gcdVG_ONLY
+#   define  gcdVG_ONLY  (!gcdENABLE_3D && !gcdENABLE_2D && gcdENABLE_VG)
+#endif
+
+#if defined(WIN32) && !defined(UNDER_CE) && (gcdENABLE_VG == 1)
+
+#ifdef gcdUSE_VX
+#undef gcdUSE_VX
+#endif
+
+#ifdef COMMAND_PROCESSOR_VERSION
+#undef  COMMAND_PROCESSOR_VERSION
+#endif
+
+#ifdef gcdENABLE_TRUST_APPLICATION
+#undef  gcdENABLE_TRUST_APPLICATION
+#endif
+
+#ifdef gcdENABLE_3D
+#undef  gcdENABLE_3D
+#endif
+
+#ifdef gcdENABLE_2D
+#undef  gcdENABLE_2D
+#endif
+
+#define gcdENABLE_3D 0
+#define gcdENABLE_2D 0
+#define gcdUSE_VX 0
+#define COMMAND_PROCESSOR_VERSION 2
+#define gcdENABLE_TRUST_APPLICATION 0
+
+#endif  /* Only for GC355 Cmodel build. */
+
+#ifndef gcdGC355_PROFILER
+#   define gcdGC355_PROFILER                    0
+#endif
+
+/*
+    This definition must be paired with VIVANTE_PROFILER_SYSTEM_MEMORY
+*/
+#ifndef gcdGC355_MEM_PRINT
+#   define gcdGC355_MEM_PRINT                      0
+#else
+#if (!((gcdENABLE_3D == 0) && (gcdENABLE_2D == 0) && (gcdENABLE_VG == 1)))
+#      undef gcdGC355_MEM_PRINT
+#      define gcdGC355_MEM_PRINT                   0
+#   endif
+#endif
+
+
+/*
+    gcdRECORD_COMMAND
+*/
+#ifndef gcdRECORD_COMMAND
+#   define gcdRECORD_COMMAND                    0
+#endif
+
+/*
+    gcdALLOC_CMD_FROM_RESERVE
+
+    Provide a way by which location of command buffer can be
+    specified. This is a DEBUG option to limit command buffer
+    to some memory range.
+*/
+#ifndef gcdALLOC_CMD_FROM_RESERVE
+#   define gcdALLOC_CMD_FROM_RESERVE            0
+#endif
+
+/*
+    gcdBOUNDARY_CHECK
+
+    When enabled, add bounary before and after a range of
+    GPU address. So overflow can be trapped by MMU exception.
+    This is a debug option for new MMU and gcdUSE_MMU_EXCEPTION
+    is enabled.
+*/
+#ifndef gcdBOUNDARY_CHECK
+#   define gcdBOUNDARY_CHECK                    0
+#endif
+
+/*
+    gcdRENDER_QUALITY_CHECK
+
+    When enabled, we disable performance opt patch
+    to get know rendering quality comparing with other vendor.
+*/
+#ifndef gcdRENDER_QUALITY_CHECK
+#   define gcdRENDER_QUALITY_CHECK              0
+#endif
+
+/*
+    gcdSYSTRACE
+
+    When enabled, we embed systrace in function header/footer
+    to gather time information on linux platforms include android.
+    '1' to trace API (EGL, ES11, ES2x, ES3x, etc)
+    '2' to trace HAL (except compiler)
+    '4' to trace HAL compiler
+    See gc_hal_user_debug.c for more detailed trace zones.
+*/
+#ifndef gcdSYSTRACE
+#   define gcdSYSTRACE                          0
+#endif
+
+#ifndef gcdENABLE_APPCTXT_BLITDRAW
+#   define gcdENABLE_APPCTXT_BLITDRAW                     0
+#endif
+
+/*
+    When enabled, use 1K mode for MMU version 2.0. otherwise use 4K mode.
+*/
+#ifndef gcdENABLE_MMU_1KMODE
+#   define gcdENABLE_MMU_1KMODE                  1
+#endif
+
+/*
+    gcdENABLE_TRUST_APPLICATION
+
+    When enabled, trust application is used to handle 'security' registers.
+
+    1) If HW doesn't have robust and security feature, this option is meaningless.
+    2) If HW have robust and security and this option is not enable,
+       security registers are handled by non secure driver. It is for
+       platform doesn't want/need to use trust zone.
+*/
+#ifndef gcdENABLE_TRUST_APPLICATION
+#if (defined(_WIN32) && !defined(UNDER_CE)) || (defined (LINUX) && !defined(EMULATOR))
+#   define gcdENABLE_TRUST_APPLICATION          1
+#else
+#   define gcdENABLE_TRUST_APPLICATION          0
+#endif
+#endif
+
+/* Disable gcdENABLE_TRUST_APPLICATION when oboslete gcdSECURITY enabled. */
+#if gcdSECURITY
+#undef gcdENABLE_TRUST_APPLICATION
+#define gcdENABLE_TRUST_APPLICATION             0
+#endif
+
+#ifndef gcdMMU_SECURE_AREA_SIZE
+#if defined(gcdENABLE_MMU_1KMODE)
+#   define gcdMMU_SECURE_AREA_SIZE              32
+#else
+#   define gcdMMU_SECURE_AREA_SIZE              128
+#endif
+#endif
+
+#ifndef gcdUSE_MMU_EXCEPTION
+#   define gcdUSE_MMU_EXCEPTION                 1
+#endif
+
+#ifndef gcdVX_OPTIMIZER
+#   define gcdVX_OPTIMIZER                      0
+#endif
+
+#ifndef gcdALLOC_ON_FAULT
+#   define gcdALLOC_ON_FAULT                    0
+#endif
+
+/*
+    gcdDISABLE_GPU_VIRTUAL_ADDRESS
+
+        When enabled, disable MMU and all virtual allocated from MMU.
+*/
+#ifndef gcdDISABLE_GPU_VIRTUAL_ADDRESS
+#   define gcdDISABLE_GPU_VIRTUAL_ADDRESS       0
+#endif
+
+/*
+    gcd2D_COMPRESSION_DEC400_ALIGN_MODE
+
+        Only for DEC400 compression.
+        Set 0 as 16bytes aligned. 1 as 32bytes aligned. 2 as 64bytes aligned.
+        Default is 0 which means 32bytes aligned.
+*/
+#ifndef gcd2D_COMPRESSION_DEC400_ALIGN_MODE
+#   define gcd2D_COMPRESSION_DEC400_ALIGN_MODE  1
+#endif
+
+/*
+    gcdENABLE_KERNEL_FENCE
+        When enabled, use kernel fence to do resource tracking.
+*/
+#ifndef gcdENABLE_KENREL_FENCE
+#   define gcdENABLE_KERNEL_FENCE               0
+#endif
+
+/*
+    gcdUSE_VXC_BINARY
+        When enabled, will use prebuilt shader binary in VX driver.
+ */
+#ifndef gcdUSE_VXC_BINARY
+#   define gcdUSE_VXC_BINARY                    0
+#endif
+
+/*
+    gcdFEATURE_SANITYCHECK
+        When enabled, will do hardware feature sanity check, each
+        used hardware feature should be printed out.
+ */
+#ifndef gcdFEATURE_SANITYCHECK
+#   define gcdFEATURE_SANITYCHECK                0
+#endif
+
+
+/*
+    VIVANTE_PROFILER_SYSTEM_MEMORY
+
+        This define enables the profiling data for system memory allocated by driver
+*/
+#ifndef VIVANTE_PROFILER_SYSTEM_MEMORY
+#   define VIVANTE_PROFILER_SYSTEM_MEMORY        1
+#   define VP_MALLOC_OFFSET                     (16)
+
+#endif
+
+#define gcdHAL_TEST 1
+#define gcdUSE_ZWP_SYNCHRONIZATION 1
+
+/*
+    gcdUSE_SINGLE_CONTEXT
+        When enabled, will enable single context.
+ */
+#ifndef gcdUSE_SINGLE_CONTEXT
+#   define gcdUSE_SINGLE_CONTEXT                   0
+#endif
+
+/*
+    gcdKERNEL_QUERY_PERFORMANCE_COUNTER_V8
+        When enabled, will enable query new performance counter of V8.0 in kernel
+        space.
+ */
+#ifndef gcdKERNEL_QUERY_PERFORMANCE_COUNTER_V8
+#   define gcdKERNEL_QUERY_PERFORMANCE_COUNTER_V8  0
+#endif
+
+/*
+    gcdIGNORE_DRIVER_VERSIONS_MISMATCH
+        When enabled, driver will ignore user and kernel driver version mismatch.
+*/
+#ifndef gcdIGNORE_DRIVER_VERSIONS_MISMATCH
+#   define gcdIGNORE_DRIVER_VERSIONS_MISMATCH  1
+#endif
+
+/*
+    gcdEXTERNAL_SRAM_DEFAULT_POOL
+        When enabled, external SRAM can be used for the initial command,
+        but the external SRAM base and size must be set by customer.
+        AXI-SRAM only can be used if pool type is speficied
+        with gcvSRAM_EXTERNAL[X] when allocating video memory.
+*/
+#ifndef gcdEXTERNAL_SRAM_DEFAULT_POOL
+#   define gcdEXTERNAL_SRAM_DEFAULT_POOL 0
+#endif
+
+#endif /* __gc_hal_options_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h
@@ -0,0 +1,926 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_profiler_h_
+#define __gc_hal_profiler_h_
+
+#include "shared/gc_hal_profiler_shared.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GLVERTEX_OBJECT 10
+#define GLVERTEX_OBJECT_BYTES 11
+
+#define GLINDEX_OBJECT 20
+#define GLINDEX_OBJECT_BYTES 21
+
+#define GLTEXTURE_OBJECT 30
+#define GLTEXTURE_OBJECT_BYTES 31
+
+#define GLBUFOBJ_OBJECT 40
+#define GLBUFOBJ_OBJECT_BYTES 41
+
+#define    ES11_CALLS              151
+#define    ES11_DRAWCALLS          (ES11_CALLS             + 1)
+#define    ES11_STATECHANGECALLS   (ES11_DRAWCALLS         + 1)
+#define    ES11_POINTCOUNT         (ES11_STATECHANGECALLS  + 1)
+#define    ES11_LINECOUNT          (ES11_POINTCOUNT        + 1)
+#define    ES11_TRIANGLECOUNT      (ES11_LINECOUNT         + 1)
+
+#define    ES30_CALLS              159
+#define    ES30_DRAWCALLS          (ES30_CALLS             + 1)
+#define    ES30_STATECHANGECALLS   (ES30_DRAWCALLS         + 1)
+#define    ES30_POINTCOUNT         (ES30_STATECHANGECALLS  + 1)
+#define    ES30_LINECOUNT          (ES30_POINTCOUNT        + 1)
+#define    ES30_TRIANGLECOUNT      (ES30_LINECOUNT         + 1)
+
+#define    VG11_CALLS              88
+#define    VG11_DRAWCALLS          (VG11_CALLS              + 1)
+#define    VG11_STATECHANGECALLS   (VG11_DRAWCALLS          + 1)
+#define    VG11_FILLCOUNT          (VG11_STATECHANGECALLS   + 1)
+#define    VG11_STROKECOUNT        (VG11_FILLCOUNT          + 1)
+/* End of Driver API ID Definitions. */
+
+/* HAL & MISC IDs. */
+#define HAL_VERTBUFNEWBYTEALLOC    1
+#define HAL_VERTBUFTOTALBYTEALLOC  (HAL_VERTBUFNEWBYTEALLOC     + 1)
+#define HAL_VERTBUFNEWOBJALLOC     (HAL_VERTBUFTOTALBYTEALLOC   + 1)
+#define HAL_VERTBUFTOTALOBJALLOC   (HAL_VERTBUFNEWOBJALLOC      + 1)
+#define HAL_INDBUFNEWBYTEALLOC     (HAL_VERTBUFTOTALOBJALLOC    + 1)
+#define HAL_INDBUFTOTALBYTEALLOC   (HAL_INDBUFNEWBYTEALLOC      + 1)
+#define HAL_INDBUFNEWOBJALLOC      (HAL_INDBUFTOTALBYTEALLOC    + 1)
+#define HAL_INDBUFTOTALOBJALLOC    (HAL_INDBUFNEWOBJALLOC       + 1)
+#define HAL_TEXBUFNEWBYTEALLOC     (HAL_INDBUFTOTALOBJALLOC     + 1)
+#define HAL_TEXBUFTOTALBYTEALLOC   (HAL_TEXBUFNEWBYTEALLOC      + 1)
+#define HAL_TEXBUFNEWOBJALLOC      (HAL_TEXBUFTOTALBYTEALLOC    + 1)
+#define HAL_TEXBUFTOTALOBJALLOC    (HAL_TEXBUFNEWOBJALLOC       + 1)
+
+#define GPU_CYCLES           1
+#define GPU_READ64BYTE       (GPU_CYCLES         + 1)
+#define GPU_WRITE64BYTE      (GPU_READ64BYTE     + 1)
+#define GPU_TOTALCYCLES      (GPU_WRITE64BYTE    + 1)
+#define GPU_IDLECYCLES       (GPU_TOTALCYCLES    + 1)
+
+#define VS_INSTCOUNT          1
+#define VS_BRANCHINSTCOUNT    (VS_INSTCOUNT          + 1)
+#define VS_TEXLDINSTCOUNT     (VS_BRANCHINSTCOUNT    + 1)
+#define VS_RENDEREDVERTCOUNT  (VS_TEXLDINSTCOUNT     + 1)
+#define VS_SOURCE             (VS_RENDEREDVERTCOUNT  + 1)
+#define VS_NONIDLESTARVECOUNT (VS_SOURCE             + 1)
+#define VS_STARVELCOUNT       (VS_NONIDLESTARVECOUNT + 1)
+#define VS_STALLCOUNT         (VS_STARVELCOUNT       + 1)
+#define VS_PROCESSCOUNT       (VS_STALLCOUNT         + 1)
+
+#define PS_INSTCOUNT          1
+#define PS_BRANCHINSTCOUNT    (PS_INSTCOUNT          + 1)
+#define PS_TEXLDINSTCOUNT     (PS_BRANCHINSTCOUNT    + 1)
+#define PS_RENDEREDPIXCOUNT   (PS_TEXLDINSTCOUNT     + 1)
+#define PS_SOURCE             (PS_RENDEREDPIXCOUNT   + 1)
+#define PS_NONIDLESTARVECOUNT (PS_SOURCE             + 1)
+#define PS_STARVELCOUNT       (PS_NONIDLESTARVECOUNT + 1)
+#define PS_STALLCOUNT         (PS_STARVELCOUNT       + 1)
+#define PS_PROCESSCOUNT       (PS_STALLCOUNT         + 1)
+#define PS_SHADERCYCLECOUNT   (PS_PROCESSCOUNT       + 1)
+
+#define PA_INVERTCOUNT        1
+#define PA_INPRIMCOUNT        (PA_INVERTCOUNT      + 1)
+#define PA_OUTPRIMCOUNT       (PA_INPRIMCOUNT      + 1)
+#define PA_DEPTHCLIPCOUNT     (PA_OUTPRIMCOUNT     + 1)
+#define PA_TRIVIALREJCOUNT    (PA_DEPTHCLIPCOUNT   + 1)
+#define PA_CULLCOUNT          (PA_TRIVIALREJCOUNT  + 1)
+#define PA_NONIDLESTARVECOUNT (PA_CULLCOUNT        + 1)
+#define PA_STARVELCOUNT       (PA_NONIDLESTARVECOUNT + 1)
+#define PA_STALLCOUNT         (PA_STARVELCOUNT     + 1)
+#define PA_PROCESSCOUNT       (PA_STALLCOUNT       + 1)
+
+#define SE_TRIANGLECOUNT        1
+#define SE_LINECOUNT            (SE_TRIANGLECOUNT        + 1)
+#define SE_STARVECOUNT          (SE_LINECOUNT            + 1)
+#define SE_STALLCOUNT           (SE_STARVECOUNT          + 1)
+#define SE_RECEIVETRIANGLECOUNT (SE_STALLCOUNT           + 1)
+#define SE_SENDTRIANGLECOUNT    (SE_RECEIVETRIANGLECOUNT + 1)
+#define SE_RECEIVELINESCOUNT    (SE_SENDTRIANGLECOUNT    + 1)
+#define SE_SENDLINESCOUNT       (SE_RECEIVELINESCOUNT    + 1)
+#define SE_NONIDLESTARVECOUNT   (SE_SENDLINESCOUNT       + 1)
+#define SE_PROCESSCOUNT         (SE_NONIDLESTARVECOUNT   + 1)
+
+#define RA_VALIDPIXCOUNT      1
+#define RA_TOTALQUADCOUNT     (RA_VALIDPIXCOUNT      + 1)
+#define RA_VALIDQUADCOUNTEZ   (RA_TOTALQUADCOUNT     + 1)
+#define RA_TOTALPRIMCOUNT     (RA_VALIDQUADCOUNTEZ   + 1)
+#define RA_PIPECACHEMISSCOUNT (RA_TOTALPRIMCOUNT     + 1)
+#define RA_PREFCACHEMISSCOUNT (RA_PIPECACHEMISSCOUNT + 1)
+#define RA_EEZCULLCOUNT       (RA_PREFCACHEMISSCOUNT + 1)
+#define RA_NONIDLESTARVECOUNT (RA_EEZCULLCOUNT       + 1)
+#define RA_STARVELCOUNT       (RA_NONIDLESTARVECOUNT + 1)
+#define RA_STALLCOUNT         (RA_STARVELCOUNT       + 1)
+#define RA_PROCESSCOUNT       (RA_STALLCOUNT         + 1)
+
+#define TX_TOTBILINEARREQ     1
+#define TX_TOTTRILINEARREQ    (TX_TOTBILINEARREQ      + 1)
+#define TX_TOTDISCARDTEXREQ   (TX_TOTTRILINEARREQ     + 1)
+#define TX_TOTTEXREQ          (TX_TOTDISCARDTEXREQ    + 1)
+#define TX_MEMREADCOUNT       (TX_TOTTEXREQ           + 1)
+#define TX_MEMREADIN8BCOUNT   (TX_MEMREADCOUNT        + 1)
+#define TX_CACHEMISSCOUNT     (TX_MEMREADIN8BCOUNT    + 1)
+#define TX_CACHEHITTEXELCOUNT (TX_CACHEMISSCOUNT      + 1)
+#define TX_CACHEMISSTEXELCOUNT (TX_CACHEHITTEXELCOUNT + 1)
+#define TX_NONIDLESTARVECOUNT  (TX_CACHEMISSTEXELCOUNT+ 1)
+#define TX_STARVELCOUNT        (TX_NONIDLESTARVECOUNT + 1)
+#define TX_STALLCOUNT          (TX_STARVELCOUNT       + 1)
+#define TX_PROCESSCOUNT        (TX_STALLCOUNT         + 1)
+
+#define PE_KILLEDBYCOLOR      1
+#define PE_KILLEDBYDEPTH      (PE_KILLEDBYCOLOR    + 1)
+#define PE_DRAWNBYCOLOR       (PE_KILLEDBYDEPTH    + 1)
+#define PE_DRAWNBYDEPTH       (PE_DRAWNBYCOLOR     + 1)
+
+#define MC_READREQ8BPIPE      1
+#define MC_READREQ8BIP        (MC_READREQ8BPIPE    + 1)
+#define MC_WRITEREQ8BPIPE     (MC_READREQ8BIP      + 1)
+#define MC_AXIMINLATENCY      (MC_WRITEREQ8BPIPE   + 1)
+#define MC_AXIMAXLATENCY      (MC_AXIMINLATENCY    + 1)
+#define MC_AXITOTALLATENCY    (MC_AXIMAXLATENCY    + 1)
+#define MC_AXISAMPLECOUNT     (MC_AXITOTALLATENCY  + 1)
+
+#define AXI_READREQSTALLED    1
+#define AXI_WRITEREQSTALLED   (AXI_READREQSTALLED  + 1)
+#define AXI_WRITEDATASTALLED  (AXI_WRITEREQSTALLED + 1)
+
+#define FE_DRAWCOUNT    1
+#define FE_OUTVERTEXCOUNT     (FE_DRAWCOUNT  + 1)
+#define FE_STALLCOUNT         (FE_OUTVERTEXCOUNT + 1)
+#define FE_STARVECOUNT        (FE_STALLCOUNT + 1)
+
+#define PVS_INSTRCOUNT        1
+#define PVS_ALUINSTRCOUNT     (PVS_INSTRCOUNT      + 1)
+#define PVS_TEXINSTRCOUNT     (PVS_ALUINSTRCOUNT   + 1)
+#define PVS_ATTRIBCOUNT       (PVS_TEXINSTRCOUNT   + 1)
+#define PVS_UNIFORMCOUNT      (PVS_ATTRIBCOUNT     + 1)
+#define PVS_FUNCTIONCOUNT     (PVS_UNIFORMCOUNT    + 1)
+#define PVS_SOURCE            (PVS_FUNCTIONCOUNT   + 1)
+
+#define PPS_INSTRCOUNT       1
+#define PPS_ALUINSTRCOUNT    (PPS_INSTRCOUNT       + 1)
+#define PPS_TEXINSTRCOUNT    (PPS_ALUINSTRCOUNT    + 1)
+#define PPS_ATTRIBCOUNT      (PPS_TEXINSTRCOUNT    + 1)
+#define PPS_UNIFORMCOUNT     (PPS_ATTRIBCOUNT      + 1)
+#define PPS_FUNCTIONCOUNT    (PPS_UNIFORMCOUNT     + 1)
+#define PPS_SOURCE           (PPS_FUNCTIONCOUNT    + 1)
+/* End of MISC Counter IDs. */
+
+
+/* Category Constants. */
+#define VPHEADER        0x010000
+#define VPG_INFO        0x020000
+#define VPG_TIME        0x030000
+#define VPG_MEM         0x040000
+#define VPG_ES11        0x050000
+#define VPG_ES30        0x060000
+#define VPG_VG11        0x070000
+#define VPG_HAL         0x080000
+#define VPG_HW          0x090000
+#define VPG_GPU         0x0a0000
+#define VPG_VS          0x0b0000
+#define VPG_PS          0x0c0000
+#define VPG_PA          0x0d0000
+#define VPG_SETUP       0x0e0000
+#define VPG_RA          0x0f0000
+#define VPG_TX          0x100000
+#define VPG_PE          0x110000
+#define VPG_MC          0x120000
+#define VPG_AXI         0x130000
+#define VPG_PROG        0x140000
+#define VPG_PVS         0x150000
+#define VPG_PPS         0x160000
+#define VPG_ES11_TIME   0x170000
+#define VPG_ES30_TIME   0x180000
+#define VPG_FRAME       0x190000
+#define VPG_ES11_DRAW   0x200000
+#define VPG_ES30_DRAW   0x210000
+#define VPG_VG11_TIME   0x220000
+#define VPG_FE          0x230000
+#define VPG_MULTI_GPU   0x240000
+#define VPNG_FE         0x250000
+#define VPNG_VS         0x260000
+#define VPNG_PS         0x270000
+#define VPNG_PA         0x280000
+#define VPNG_SETUP      0x290000
+#define VPNG_RA         0x2a0000
+#define VPNG_TX         0x2b0000
+#define VPNG_PE         0x2c0000
+#define VPNG_MCC        0x2d0000
+#define VPNG_MCZ        0x2e0000
+#define VPNG_HI         0x2f0000
+#define VPNG_L2         0x300000
+#define VPG_FINISH      0x310000
+#define VPG_END         0xff0000
+
+/* Info. */
+#define VPC_INFOCOMPANY         (VPG_INFO + 1)
+#define VPC_INFOVERSION         (VPC_INFOCOMPANY + 1)
+#define VPC_INFORENDERER        (VPC_INFOVERSION + 1)
+#define VPC_INFOREVISION        (VPC_INFORENDERER + 1)
+#define VPC_INFODRIVER          (VPC_INFOREVISION + 1)
+#define VPC_INFODRIVERMODE      (VPC_INFODRIVER + 1)
+#define VPC_INFOSCREENSIZE      (VPC_INFODRIVERMODE + 1)
+
+/* Counter Constants. */
+#define VPC_ELAPSETIME          (VPG_TIME + 1)
+#define VPC_CPUTIME             (VPC_ELAPSETIME + 1)
+
+#define VPC_MEMMAXRES           (VPG_MEM + 1)
+#define VPC_MEMSHARED           (VPC_MEMMAXRES + 1)
+#define VPC_MEMUNSHAREDDATA     (VPC_MEMSHARED + 1)
+#define VPC_MEMUNSHAREDSTACK    (VPC_MEMUNSHAREDDATA + 1)
+
+/* OpenGL ES11 Statics Counter IDs. */
+#define    VPC_ES11CALLS            (VPG_ES11 +    ES11_CALLS)
+#define    VPC_ES11DRAWCALLS        (VPG_ES11 +    ES11_DRAWCALLS)
+#define    VPC_ES11STATECHANGECALLS (VPG_ES11 +    ES11_STATECHANGECALLS)
+#define    VPC_ES11POINTCOUNT       (VPG_ES11 +    ES11_POINTCOUNT)
+#define    VPC_ES11LINECOUNT        (VPG_ES11 +    ES11_LINECOUNT)
+#define    VPC_ES11TRIANGLECOUNT    (VPG_ES11 +    ES11_TRIANGLECOUNT)
+
+/* OpenGL ES30 Statistics Counter IDs. */
+#define    VPC_ES30CALLS            (VPG_ES30 +    ES30_CALLS)
+#define    VPC_ES30DRAWCALLS        (VPG_ES30 +    ES30_DRAWCALLS)
+#define    VPC_ES30STATECHANGECALLS (VPG_ES30 +    ES30_STATECHANGECALLS)
+#define    VPC_ES30POINTCOUNT       (VPG_ES30 +    ES30_POINTCOUNT)
+#define    VPC_ES30LINECOUNT        (VPG_ES30 +    ES30_LINECOUNT)
+#define    VPC_ES30TRIANGLECOUNT    (VPG_ES30 +    ES30_TRIANGLECOUNT)
+
+/* OpenVG Statistics Counter IDs. */
+#define    VPC_VG11CALLS            (VPG_VG11 +    VG11_CALLS)
+#define    VPC_VG11DRAWCALLS        (VPG_VG11 +    VG11_DRAWCALLS)
+#define    VPC_VG11STATECHANGECALLS (VPG_VG11 +    VG11_STATECHANGECALLS)
+#define    VPC_VG11FILLCOUNT        (VPG_VG11 +    VG11_FILLCOUNT)
+#define    VPC_VG11STROKECOUNT      (VPG_VG11 +    VG11_STROKECOUNT)
+
+/* HAL Counters. */
+#define VPC_HALVERTBUFNEWBYTEALLOC      (VPG_HAL + HAL_VERTBUFNEWBYTEALLOC)
+#define VPC_HALVERTBUFTOTALBYTEALLOC    (VPG_HAL + HAL_VERTBUFTOTALBYTEALLOC)
+#define VPC_HALVERTBUFNEWOBJALLOC       (VPG_HAL + HAL_VERTBUFNEWOBJALLOC)
+#define VPC_HALVERTBUFTOTALOBJALLOC     (VPG_HAL + HAL_VERTBUFTOTALOBJALLOC)
+#define VPC_HALINDBUFNEWBYTEALLOC       (VPG_HAL + HAL_INDBUFNEWBYTEALLOC)
+#define VPC_HALINDBUFTOTALBYTEALLOC     (VPG_HAL + HAL_INDBUFTOTALBYTEALLOC)
+#define VPC_HALINDBUFNEWOBJALLOC        (VPG_HAL + HAL_INDBUFNEWOBJALLOC)
+#define VPC_HALINDBUFTOTALOBJALLOC      (VPG_HAL + HAL_INDBUFTOTALOBJALLOC)
+#define VPC_HALTEXBUFNEWBYTEALLOC       (VPG_HAL + HAL_TEXBUFNEWBYTEALLOC)
+#define VPC_HALTEXBUFTOTALBYTEALLOC     (VPG_HAL + HAL_TEXBUFTOTALBYTEALLOC)
+#define VPC_HALTEXBUFNEWOBJALLOC        (VPG_HAL + HAL_TEXBUFNEWOBJALLOC)
+#define VPC_HALTEXBUFTOTALOBJALLOC      (VPG_HAL + HAL_TEXBUFTOTALOBJALLOC)
+
+/* HW: GPU Counters. */
+#define VPC_GPUCYCLES                   (VPG_GPU + GPU_CYCLES)
+#define VPC_GPUREAD64BYTE               (VPG_GPU + GPU_READ64BYTE)
+#define VPC_GPUWRITE64BYTE              (VPG_GPU + GPU_WRITE64BYTE)
+#define VPC_GPUTOTALCYCLES              (VPG_GPU + GPU_TOTALCYCLES)
+#define VPC_GPUIDLECYCLES               (VPG_GPU + GPU_IDLECYCLES)
+
+/* HW: Shader Counters. */
+#define VPC_VSINSTCOUNT                 (VPG_VS + VS_INSTCOUNT)
+#define VPC_VSBRANCHINSTCOUNT           (VPG_VS + VS_BRANCHINSTCOUNT)
+#define VPC_VSTEXLDINSTCOUNT            (VPG_VS + VS_TEXLDINSTCOUNT)
+#define VPC_VSRENDEREDVERTCOUNT         (VPG_VS + VS_RENDEREDVERTCOUNT)
+#define VPC_VSNONIDLESTARVECOUNT        (VPG_VS + VS_NONIDLESTARVECOUNT)
+#define VPC_VSSTARVELCOUNT              (VPG_VS + VS_STARVELCOUNT)
+#define VPC_VSSTALLCOUNT                (VPG_VS + VS_STALLCOUNT)
+#define VPC_VSPROCESSCOUNT              (VPG_VS + VS_PROCESSCOUNT)
+/* HW: PS Count. */
+#define VPC_PSINSTCOUNT                 (VPG_PS + PS_INSTCOUNT)
+#define VPC_PSBRANCHINSTCOUNT           (VPG_PS + PS_BRANCHINSTCOUNT)
+#define VPC_PSTEXLDINSTCOUNT            (VPG_PS + PS_TEXLDINSTCOUNT)
+#define VPC_PSRENDEREDPIXCOUNT          (VPG_PS + PS_RENDEREDPIXCOUNT)
+#define VPC_PSNONIDLESTARVECOUNT        (VPG_PS + PS_NONIDLESTARVECOUNT)
+#define VPC_PSSTARVELCOUNT              (VPG_PS + PS_STARVELCOUNT)
+#define VPC_PSSTALLCOUNT                (VPG_PS + PS_STALLCOUNT)
+#define VPC_PSPROCESSCOUNT              (VPG_PS + PS_PROCESSCOUNT)
+#define VPC_PSSHADERCYCLECOUNT          (VPG_PS + PS_SHADERCYCLECOUNT)
+
+/* HW: PA Counters. */
+#define VPC_PAINVERTCOUNT               (VPG_PA + PA_INVERTCOUNT)
+#define VPC_PAINPRIMCOUNT               (VPG_PA + PA_INPRIMCOUNT)
+#define VPC_PAOUTPRIMCOUNT              (VPG_PA + PA_OUTPRIMCOUNT)
+#define VPC_PADEPTHCLIPCOUNT            (VPG_PA + PA_DEPTHCLIPCOUNT)
+#define VPC_PATRIVIALREJCOUNT           (VPG_PA + PA_TRIVIALREJCOUNT)
+#define VPC_PACULLCOUNT                 (VPG_PA + PA_CULLCOUNT)
+#define VPC_PANONIDLESTARVECOUNT        (VPG_PA + PA_NONIDLESTARVECOUNT)
+#define VPC_PASTARVELCOUNT              (VPG_PA + PA_STARVELCOUNT)
+#define VPC_PASTALLCOUNT                (VPG_PA + PA_STALLCOUNT)
+#define VPC_PAPROCESSCOUNT              (VPG_PA + PA_PROCESSCOUNT)
+
+/* HW: Setup Counters. */
+#define VPC_SETRIANGLECOUNT             (VPG_SETUP + SE_TRIANGLECOUNT)
+#define VPC_SELINECOUNT                 (VPG_SETUP + SE_LINECOUNT)
+#define VPC_SESTARVECOUNT               (VPG_SETUP + SE_STARVECOUNT)
+#define VPC_SESTALLCOUNT                (VPG_SETUP + SE_STALLCOUNT)
+#define VPC_SERECEIVETRIANGLECOUNT      (VPG_SETUP + SE_RECEIVETRIANGLECOUNT)
+#define VPC_SESENDTRIANGLECOUNT         (VPG_SETUP + SE_SENDTRIANGLECOUNT)
+#define VPC_SERECEIVELINESCOUNT         (VPG_SETUP + SE_RECEIVELINESCOUNT)
+#define VPC_SESENDLINESCOUNT            (VPG_SETUP + SE_SENDLINESCOUNT)
+#define VPC_SENONIDLESTARVECOUNT        (VPG_SETUP + SE_NONIDLESTARVECOUNT)
+#define VPC_SEPROCESSCOUNT              (VPG_SETUP + SE_PROCESSCOUNT)
+
+/* HW: RA Counters. */
+#define VPC_RAVALIDPIXCOUNT             (VPG_RA + RA_VALIDPIXCOUNT)
+#define VPC_RATOTALQUADCOUNT            (VPG_RA + RA_TOTALQUADCOUNT)
+#define VPC_RAVALIDQUADCOUNTEZ          (VPG_RA + RA_VALIDQUADCOUNTEZ)
+#define VPC_RATOTALPRIMCOUNT            (VPG_RA + RA_TOTALPRIMCOUNT)
+#define VPC_RAPIPECACHEMISSCOUNT        (VPG_RA + RA_PIPECACHEMISSCOUNT)
+#define VPC_RAPREFCACHEMISSCOUNT        (VPG_RA + RA_PREFCACHEMISSCOUNT)
+#define VPC_RAEEZCULLCOUNT              (VPG_RA + RA_EEZCULLCOUNT)
+#define VPC_RANONIDLESTARVECOUNT        (VPG_RA + RA_NONIDLESTARVECOUNT)
+#define VPC_RASTARVELCOUNT              (VPG_RA + RA_STARVELCOUNT)
+#define VPC_RASTALLCOUNT                (VPG_RA + RA_STALLCOUNT)
+#define VPC_RAPROCESSCOUNT              (VPG_RA + RA_PROCESSCOUNT)
+
+/* HW: TEX Counters. */
+#define VPC_TXTOTBILINEARREQ            (VPG_TX + TX_TOTBILINEARREQ)
+#define VPC_TXTOTTRILINEARREQ           (VPG_TX + TX_TOTTRILINEARREQ)
+#define VPC_TXTOTDISCARDTEXREQ          (VPG_TX + TX_TOTDISCARDTEXREQ)
+#define VPC_TXTOTTEXREQ                 (VPG_TX + TX_TOTTEXREQ)
+#define VPC_TXMEMREADCOUNT              (VPG_TX + TX_MEMREADCOUNT)
+#define VPC_TXMEMREADIN8BCOUNT          (VPG_TX + TX_MEMREADIN8BCOUNT)
+#define VPC_TXCACHEMISSCOUNT            (VPG_TX + TX_CACHEMISSCOUNT)
+#define VPC_TXCACHEHITTEXELCOUNT        (VPG_TX + TX_CACHEHITTEXELCOUNT)
+#define VPC_TXCACHEMISSTEXELCOUNT       (VPG_TX + TX_CACHEMISSTEXELCOUNT)
+#define VPC_TXNONIDLESTARVECOUNT        (VPG_TX + TX_NONIDLESTARVECOUNT)
+#define VPC_TXSTARVELCOUNT              (VPG_TX + TX_STARVELCOUNT)
+#define VPC_TXSTALLCOUNT                (VPG_TX + TX_STALLCOUNT)
+#define VPC_TXPROCESSCOUNT              (VPG_TX + TX_PROCESSCOUNT)
+
+/* HW: PE Counters. */
+#define VPC_PEKILLEDBYCOLOR             (VPG_PE + PE_KILLEDBYCOLOR)
+#define VPC_PEKILLEDBYDEPTH             (VPG_PE + PE_KILLEDBYDEPTH)
+#define VPC_PEDRAWNBYCOLOR              (VPG_PE + PE_DRAWNBYCOLOR)
+#define VPC_PEDRAWNBYDEPTH              (VPG_PE + PE_DRAWNBYDEPTH)
+
+/* HW: MC Counters. */
+#define VPC_MCREADREQ8BPIPE             (VPG_MC + MC_READREQ8BPIPE)
+#define VPC_MCREADREQ8BIP               (VPG_MC + MC_READREQ8BIP)
+#define VPC_MCWRITEREQ8BPIPE            (VPG_MC + MC_WRITEREQ8BPIPE)
+#define VPC_MCAXIMINLATENCY             (VPG_MC + MC_AXIMINLATENCY)
+#define VPC_MCAXIMAXLATENCY             (VPG_MC + MC_AXIMAXLATENCY)
+#define VPC_MCAXITOTALLATENCY           (VPG_MC + MC_AXITOTALLATENCY)
+#define VPC_MCAXISAMPLECOUNT            (VPG_MC + MC_AXISAMPLECOUNT)
+
+/* HW: AXI Counters. */
+#define VPC_AXIREADREQSTALLED           (VPG_AXI + AXI_READREQSTALLED)
+#define VPC_AXIWRITEREQSTALLED          (VPG_AXI + AXI_WRITEREQSTALLED)
+#define VPC_AXIWRITEDATASTALLED         (VPG_AXI + AXI_WRITEDATASTALLED)
+
+/* HW: FE Counters. */
+#define VPC_FEDRAWCOUNT                 (VPG_FE + FE_DRAWCOUNT)
+#define VPC_FEOUTVERTEXCOUNT            (VPG_FE + FE_OUTVERTEXCOUNT)
+#define VPC_FESTALLCOUNT                (VPG_FE + FE_STALLCOUNT)
+#define VPC_FESTARVECOUNT               (VPG_FE + FE_STARVECOUNT)
+
+/* HW: Shader Counters. */
+#define VPNC_VSINSTCOUNT                 (VPNG_VS + 1)
+#define VPNC_VSBRANCHINSTCOUNT           (VPNG_VS + 2)
+#define VPNC_VSTEXLDINSTCOUNT            (VPNG_VS + 3)
+#define VPNC_VSRENDEREDVERTCOUNT         (VPNG_VS + 4)
+#define VPNC_VSNONIDLESTARVECOUNT        (VPNG_VS + 5)
+#define VPNC_VSSTARVELCOUNT              (VPNG_VS + 6)
+#define VPNC_VSSTALLCOUNT                (VPNG_VS + 7)
+#define VPNC_VSPROCESSCOUNT              (VPNG_VS + 8)
+#define VPNC_VSSHADERCYCLECOUNT          (VPNG_VS + 9)
+#define VPNC_VS_COUNT                    VPNC_VSSHADERCYCLECOUNT - VPNG_VS
+
+/* HW: PS Count. */
+#define VPNC_PSINSTCOUNT                 (VPNG_PS + 1)
+#define VPNC_PSBRANCHINSTCOUNT           (VPNG_PS + 2)
+#define VPNC_PSTEXLDINSTCOUNT            (VPNG_PS + 3)
+#define VPNC_PSRENDEREDPIXCOUNT          (VPNG_PS + 4)
+#define VPNC_PSNONIDLESTARVECOUNT        (VPNG_PS + 5)
+#define VPNC_PSSTARVELCOUNT              (VPNG_PS + 6)
+#define VPNC_PSSTALLCOUNT                (VPNG_PS + 7)
+#define VPNC_PSPROCESSCOUNT              (VPNG_PS + 8)
+#define VPNC_PSSHADERCYCLECOUNT          (VPNG_PS + 9)
+#define VPNC_PS_COUNT                    VPNC_PSSHADERCYCLECOUNT - VPNG_PS
+
+/* HW: PA Counters. */
+#define VPNC_PAINVERTCOUNT               (VPNG_PA + 1)
+#define VPNC_PAINPRIMCOUNT               (VPNG_PA + 2)
+#define VPNC_PAOUTPRIMCOUNT              (VPNG_PA + 3)
+#define VPNC_PADEPTHCLIPCOUNT            (VPNG_PA + 4)
+#define VPNC_PATRIVIALREJCOUNT           (VPNG_PA + 5)
+#define VPNC_PACULLPRIMCOUNT             (VPNG_PA + 6)
+#define VPNC_PADROPPRIMCOUNT             (VPNG_PA + 7)
+#define VPNC_PAFRCLIPPRIMCOUNT           (VPNG_PA + 8)
+#define VPNC_PAFRCLIPDROPPRIMCOUNT       (VPNG_PA + 9)
+#define VPNC_PANONIDLESTARVECOUNT        (VPNG_PA + 10)
+#define VPNC_PASTARVELCOUNT              (VPNG_PA + 11)
+#define VPNC_PASTALLCOUNT                (VPNG_PA + 12)
+#define VPNC_PAPROCESSCOUNT              (VPNG_PA + 13)
+#define VPNC_PA_COUNT                    VPNC_PAPROCESSCOUNT - VPNG_PA
+
+/* HW: Setup Counters. */
+#define VPNC_SECULLTRIANGLECOUNT         (VPNG_SETUP + 1)
+#define VPNC_SECULLLINECOUNT             (VPNG_SETUP + 2)
+#define VPNC_SECLIPTRIANGLECOUNT         (VPNG_SETUP + 3)
+#define VPNC_SECLIPLINECOUNT             (VPNG_SETUP + 4)
+#define VPNC_SESTARVECOUNT               (VPNG_SETUP + 5)
+#define VPNC_SESTALLCOUNT                (VPNG_SETUP + 6)
+#define VPNC_SERECEIVETRIANGLECOUNT      (VPNG_SETUP + 7)
+#define VPNC_SESENDTRIANGLECOUNT         (VPNG_SETUP + 8)
+#define VPNC_SERECEIVELINESCOUNT         (VPNG_SETUP + 9)
+#define VPNC_SESENDLINESCOUNT            (VPNG_SETUP + 10)
+#define VPNC_SENONIDLESTARVECOUNT        (VPNG_SETUP + 11)
+#define VPNC_SETRIVIALREJLINECOUNT       (VPNG_SETUP + 12)
+#define VPNC_SEPROCESSCOUNT              (VPNG_SETUP + 13)
+#define VPNC_SE_COUNT                    VPNC_SEPROCESSCOUNT - VPNG_SETUP
+
+/* HW: RA Counters. */
+#define VPNC_RAVALIDPIXCOUNT             (VPNG_RA + 1)
+#define VPNC_RATOTALQUADCOUNT            (VPNG_RA + 2)
+#define VPNC_RAVALIDQUADCOUNTEZ          (VPNG_RA + 3)
+#define VPNC_RAINPUTPRIMCOUNT            (VPNG_RA + 4)
+#define VPNC_RAPIPECACHEMISSCOUNT        (VPNG_RA + 5)
+#define VPNC_RAPREFCACHEMISSCOUNT        (VPNG_RA + 6)
+#define VPNC_RAPIPEHZCACHEMISSCOUNT      (VPNG_RA + 7)
+#define VPNC_RAPREFHZCACHEMISSCOUNT      (VPNG_RA + 8)
+#define VPNC_RAOUTPUTQUADCOUNT           (VPNG_RA + 9)
+#define VPNC_RAOUTPUTPIXELCOUNT          (VPNG_RA + 10)
+#define VPNC_RAEEZCULLCOUNT              (VPNG_RA + 11)
+#define VPNC_RANONIDLESTARVECOUNT        (VPNG_RA + 12)
+#define VPNC_RASTARVELCOUNT              (VPNG_RA + 13)
+#define VPNC_RASTALLCOUNT                (VPNG_RA + 14)
+#define VPNC_RAPROCESSCOUNT              (VPNG_RA + 15)
+#define VPNC_RA_COUNT                    VPNC_RAPROCESSCOUNT - VPNG_RA
+
+/* HW: TEX Counters. */
+#define VPNC_TXTOTBILINEARREQ            (VPNG_TX + 1)
+#define VPNC_TXTOTTRILINEARREQ           (VPNG_TX + 2)
+#define VPNC_TXTOTDISCARDTEXREQ          (VPNG_TX + 3)
+#define VPNC_TXTOTTEXREQ                 (VPNG_TX + 4)
+#define VPNC_TXMC0MISSCOUNT              (VPNG_TX + 5)
+#define VPNC_TXMC0REQCOUNT               (VPNG_TX + 6)
+#define VPNC_TXMC1MISSCOUNT              (VPNG_TX + 7)
+#define VPNC_TXMC1REQCOUNT               (VPNG_TX + 8)
+#define VPNC_TX_COUNT                    VPNC_TXMC1REQCOUNT - VPNG_TX
+
+/* HW: PE Counters. */
+#define VPNC_PE0KILLEDBYCOLOR             (VPNG_PE + 1)
+#define VPNC_PE0KILLEDBYDEPTH             (VPNG_PE + 2)
+#define VPNC_PE0DRAWNBYCOLOR              (VPNG_PE + 3)
+#define VPNC_PE0DRAWNBYDEPTH              (VPNG_PE + 4)
+#define VPNC_PE1KILLEDBYCOLOR             (VPNG_PE + 5)
+#define VPNC_PE1KILLEDBYDEPTH             (VPNG_PE + 6)
+#define VPNC_PE1DRAWNBYCOLOR              (VPNG_PE + 7)
+#define VPNC_PE1DRAWNBYDEPTH              (VPNG_PE + 8)
+#define VPNC_PE_COUNT                     VPNC_PE1DRAWNBYDEPTH - VPNG_PE
+
+/* HW: MCC Counters. */
+#define VPNC_MCCREADREQ8BCOLORPIPE        (VPNG_MCC + 1)
+#define VPNC_MCCREADREQ8BSOCOLORPIPE      (VPNG_MCC + 2)
+#define VPNC_MCCWRITEREQ8BCOLORPIPE       (VPNG_MCC + 3)
+#define VPNC_MCCREADREQSOCOLORPIPE        (VPNG_MCC + 4)
+#define VPNC_MCCWRITEREQCOLORPIPE         (VPNG_MCC + 5)
+#define VPNC_MCCREADREQ8BDEPTHPIPE        (VPNG_MCC + 6)
+#define VPNC_MCCREADREQ8BSFDEPTHPIPE      (VPNG_MCC + 7)
+#define VPNC_MCCWRITEREQ8BDEPTHPIPE       (VPNG_MCC + 8)
+#define VPNC_MCCREADREQSFDEPTHPIPE        (VPNG_MCC + 9)
+#define VPNC_MCCWRITEREQDEPTHPIPE         (VPNG_MCC + 10)
+#define VPNC_MCCREADREQ8BOTHERPIPE        (VPNG_MCC + 11)
+#define VPNC_MCCWRITEREQ8BOTHERPIPE       (VPNG_MCC + 12)
+#define VPNC_MCCREADREQOTHERPIPE          (VPNG_MCC + 13)
+#define VPNC_MCCWRITEREQOTHERPIPE         (VPNG_MCC + 14)
+#define VPNC_MCCAXIMINLATENCY             (VPNG_MCC + 15)
+#define VPNC_MCCAXIMAXLATENCY             (VPNG_MCC + 16)
+#define VPNC_MCCAXITOTALLATENCY           (VPNG_MCC + 17)
+#define VPNC_MCCAXISAMPLECOUNT            (VPNG_MCC + 18)
+#define VPNC_MCCFEREADBANDWIDTH           (VPNG_MCC + 19)
+#define VPNC_MCCMMUREADBANDWIDTH          (VPNG_MCC + 20)
+#define VPNC_MCCBLTREADBANDWIDTH          (VPNG_MCC + 21)
+#define VPNC_MCCSH0READBANDWIDTH          (VPNG_MCC + 22)
+#define VPNC_MCCSH1READBANDWIDTH          (VPNG_MCC + 23)
+#define VPNC_MCCPEWRITEBANDWIDTH          (VPNG_MCC + 24)
+#define VPNC_MCCBLTWRITEBANDWIDTH         (VPNG_MCC + 25)
+#define VPNC_MCCSH0WRITEBANDWIDTH         (VPNG_MCC + 26)
+#define VPNC_MCCSH1WRITEBANDWIDTH         (VPNG_MCC + 27)
+#define VPNC_MCC_COUNT                    VPNC_MCCSH1WRITEBANDWIDTH - VPNG_MCC
+
+/* HW: MCZ Counters. */
+#define VPNC_MCZREADREQ8BCOLORPIPE        (VPNG_MCZ + 1)
+#define VPNC_MCZREADREQ8BSOCOLORPIPE      (VPNG_MCZ + 2)
+#define VPNC_MCZWRITEREQ8BCOLORPIPE       (VPNG_MCZ + 3)
+#define VPNC_MCZREADREQSOCOLORPIPE        (VPNG_MCZ + 4)
+#define VPNC_MCZWRITEREQCOLORPIPE         (VPNG_MCZ + 5)
+#define VPNC_MCZREADREQ8BDEPTHPIPE        (VPNG_MCZ + 6)
+#define VPNC_MCZREADREQ8BSFDEPTHPIPE      (VPNG_MCZ + 7)
+#define VPNC_MCZWRITEREQ8BDEPTHPIPE       (VPNG_MCZ + 8)
+#define VPNC_MCZREADREQSFDEPTHPIPE        (VPNG_MCZ + 9)
+#define VPNC_MCZWRITEREQDEPTHPIPE         (VPNG_MCZ + 10)
+#define VPNC_MCZREADREQ8BOTHERPIPE        (VPNG_MCZ + 11)
+#define VPNC_MCZWRITEREQ8BOTHERPIPE       (VPNG_MCZ + 12)
+#define VPNC_MCZREADREQOTHERPIPE          (VPNG_MCZ + 13)
+#define VPNC_MCZWRITEREQOTHERPIPE         (VPNG_MCZ + 14)
+#define VPNC_MCZAXIMINLATENCY             (VPNG_MCZ + 15)
+#define VPNC_MCZAXIMAXLATENCY             (VPNG_MCZ + 16)
+#define VPNC_MCZAXITOTALLATENCY           (VPNG_MCZ + 17)
+#define VPNC_MCZAXISAMPLECOUNT            (VPNG_MCZ + 18)
+#define VPNC_MCZ_COUNT                    VPNC_MCZAXISAMPLECOUNT - VPNG_MCZ
+
+/* HW: HI Counters. */
+#define VPNC_HI0READ8BYTE                (VPNG_HI + 1)
+#define VPNC_HI0WRITE8BYTE               (VPNG_HI + 2)
+#define VPNC_HI0READREQ                  (VPNG_HI + 3)
+#define VPNC_HI0WRITEREQ                 (VPNG_HI + 4)
+#define VPNC_HI0AXIREADREQSTALL          (VPNG_HI + 5)
+#define VPNC_HI0AXIWRITEREQSTALL         (VPNG_HI + 6)
+#define VPNC_HI0AXIWRITEDATASTALL        (VPNG_HI + 7)
+#define VPNC_HI1READ8BYTE                (VPNG_HI + 8)
+#define VPNC_HI1WRITE8BYTE               (VPNG_HI + 9)
+#define VPNC_HI1READREQ                  (VPNG_HI + 10)
+#define VPNC_HI1WRITEREQ                 (VPNG_HI + 11)
+#define VPNC_HI1AXIREADREQSTALL          (VPNG_HI + 12)
+#define VPNC_HI1AXIWRITEREQSTALL         (VPNG_HI + 13)
+#define VPNC_HI1AXIWRITEDATASTALL        (VPNG_HI + 14)
+#define VPNC_HITOTALCYCLES               (VPNG_HI + 15)
+#define VPNC_HIIDLECYCLES                (VPNG_HI + 16)
+#define VPNC_HIREAD8BYTE                 (VPNG_HI + 17)
+#define VPNC_HIWRITE8BYTE                (VPNG_HI + 18)
+#define VPNC_HIOCBREAD16BYTE             (VPNG_HI + 19)
+#define VPNC_HIOCBWRITE16BYTE            (VPNG_HI + 20)
+#define VPNC_HI_COUNT                    VPNC_HIOCBWRITE16BYTE - VPNG_HI
+
+/* HW: L2 Counters. */
+#define VPNC_L2AXI0READREQCOUNT          (VPNG_L2 + 1)
+#define VPNC_L2AXI1READREQCOUNT          (VPNG_L2 + 2)
+#define VPNC_L2AXI0WRITEREQCOUNT         (VPNG_L2 + 3)
+#define VPNC_L2AXI1WRITEREQCOUNT         (VPNG_L2 + 4)
+#define VPNC_L2READTRANSREQBYAXI0        (VPNG_L2 + 5)
+#define VPNC_L2READTRANSREQBYAXI1        (VPNG_L2 + 6)
+#define VPNC_L2WRITETRANSREQBYAXI0       (VPNG_L2 + 7)
+#define VPNC_L2WRITETRANSREQBYAXI1       (VPNG_L2 + 8)
+#define VPNC_L2AXI0MINLATENCY            (VPNG_L2 + 9)
+#define VPNC_L2AXI0MAXLATENCY            (VPNG_L2 + 10)
+#define VPNC_L2AXI0TOTLATENCY            (VPNG_L2 + 11)
+#define VPNC_L2AXI0TOTREQCOUNT           (VPNG_L2 + 12)
+#define VPNC_L2AXI1MINLATENCY            (VPNG_L2 + 13)
+#define VPNC_L2AXI1MAXLATENCY            (VPNG_L2 + 14)
+#define VPNC_L2AXI1TOTLATENCY            (VPNG_L2 + 15)
+#define VPNC_L2AXI1TOTREQCOUNT           (VPNG_L2 + 16)
+#define VPNC_L2_COUNT                    VPNC_L2AXI1TOTREQCOUNT - VPNG_L2
+
+/* HW: FE Counters. */
+#define VPNC_FEDRAWCOUNT                 (VPNG_FE + 1)
+#define VPNC_FEOUTVERTEXCOUNT            (VPNG_FE + 2)
+#define VPNC_FECACHEMISSCOUNT            (VPNG_FE + 3)
+#define VPNC_FECACHELKCOUNT              (VPNG_FE + 4)
+#define VPNC_FESTALLCOUNT                (VPNG_FE + 5)
+#define VPNC_FESTARVECOUNT               (VPNG_FE + 6)
+#define VPNC_FEPROCESSCOUNT              (VPNG_FE + 7)
+#define VPNC_FE_COUNT                    VPNC_FEPROCESSCOUNT - VPNG_FE
+
+#define TOTAL_COUNTER_NUMBER             (VPNC_FE_COUNT + VPNC_VS_COUNT + VPNC_PA_COUNT + VPNC_SE_COUNT + VPNC_RA_COUNT \
+                                          + VPNC_PS_COUNT + VPNC_TX_COUNT + VPNC_PE_COUNT + VPNC_MCC_COUNT + VPNC_MCZ_COUNT \
+                                          + VPNC_HI_COUNT + VPNC_L2_COUNT)
+
+#define TOTAL_MODULE_NUMBER              12
+
+/* PROGRAM: Shader program counters. */
+#define VPC_PVSINSTRCOUNT           (VPG_PVS + PVS_INSTRCOUNT)
+#define VPC_PVSALUINSTRCOUNT        (VPG_PVS + PVS_ALUINSTRCOUNT)
+#define VPC_PVSTEXINSTRCOUNT        (VPG_PVS + PVS_TEXINSTRCOUNT)
+#define VPC_PVSATTRIBCOUNT          (VPG_PVS + PVS_ATTRIBCOUNT)
+#define VPC_PVSUNIFORMCOUNT         (VPG_PVS + PVS_UNIFORMCOUNT)
+#define VPC_PVSFUNCTIONCOUNT        (VPG_PVS + PVS_FUNCTIONCOUNT)
+#define VPC_PVSSOURCE               (VPG_PVS + PVS_SOURCE)
+
+#define VPC_PPSINSTRCOUNT           (VPG_PPS + PPS_INSTRCOUNT)
+#define VPC_PPSALUINSTRCOUNT        (VPG_PPS + PPS_ALUINSTRCOUNT)
+#define VPC_PPSTEXINSTRCOUNT        (VPG_PPS + PPS_TEXINSTRCOUNT)
+#define VPC_PPSATTRIBCOUNT          (VPG_PPS + PPS_ATTRIBCOUNT)
+#define VPC_PPSUNIFORMCOUNT         (VPG_PPS + PPS_UNIFORMCOUNT)
+#define VPC_PPSFUNCTIONCOUNT        (VPG_PPS + PPS_FUNCTIONCOUNT)
+#define VPC_PPSSOURCE               (VPG_PPS + PPS_SOURCE)
+
+#define VPC_PROGRAMHANDLE           (VPG_PROG + 1)
+
+#define VPC_ES30_DRAW_NO            (VPG_ES30_DRAW + 1)
+#define VPC_ES11_DRAW_NO            (VPG_ES11_DRAW + 1)
+#define VPC_ES30_GPU_NO             (VPG_MULTI_GPU + 1)
+
+
+#define   MODULE_FRONT_END_COUNTER_NUM                    0x5
+#define   MODULE_VERTEX_SHADER_COUNTER_NUM                0x9
+#define   MODULE_PRIMITIVE_ASSEMBLY_COUNTER_NUM           0xC
+#define   MODULE_SETUP_COUNTER_NUM                        0xD
+#define   MODULE_RASTERIZER_COUNTER_NUM                   0xE
+#define   MODULE_PIXEL_SHADER_COUNTER_NUM                 0x9
+#define   MODULE_TEXTURE_COUNTER_NUM                      0x8
+#define   MODULE_PIXEL_ENGINE_COUNTER_NUM                 0x8
+#define   MODULE_MEMORY_CONTROLLER_COLOR_COUNTER_NUM      0xC
+#define   MODULE_MEMORY_CONTROLLER_DEPTH_COUNTER_NUM      0xC
+#define   MODULE_HOST_INTERFACE0_COUNTER_NUM              0x9
+#define   MODULE_HOST_INTERFACE1_COUNTER_NUM              0x7
+#define   MODULE_GPUL2_CACHE_COUNTER_NUM                  0xE
+#define   TOTAL_PROBE_NUMBER (MODULE_FRONT_END_COUNTER_NUM + MODULE_VERTEX_SHADER_COUNTER_NUM + MODULE_PRIMITIVE_ASSEMBLY_COUNTER_NUM \
+                              + MODULE_SETUP_COUNTER_NUM + MODULE_RASTERIZER_COUNTER_NUM + MODULE_PIXEL_SHADER_COUNTER_NUM \
+                              + MODULE_TEXTURE_COUNTER_NUM + MODULE_PIXEL_ENGINE_COUNTER_NUM + MODULE_MEMORY_CONTROLLER_COLOR_COUNTER_NUM \
+                              + MODULE_MEMORY_CONTROLLER_DEPTH_COUNTER_NUM + MODULE_HOST_INTERFACE0_COUNTER_NUM + MODULE_HOST_INTERFACE1_COUNTER_NUM \
+                              + MODULE_GPUL2_CACHE_COUNTER_NUM)
+
+
+#ifdef ANDROID
+#define DEFAULT_PROFILE_FILE_NAME   "/sdcard/vprofiler.vpd"
+#else
+#define DEFAULT_PROFILE_FILE_NAME   "vprofiler.vpd"
+#endif
+
+#define VPHEADER_VERSION "VP20"
+
+#define VPFILETYPE_GL "10"
+
+#define VPFILETYPE_CL "00"
+
+#if gcdENDIAN_BIG
+#define BIG_ENDIAN_TRANS_INT(x) ((gctUINT32)(\
+        (((gctUINT32)(x) & (gctUINT32)0x000000FFUL) << 24) | \
+        (((gctUINT32)(x) & (gctUINT32)0x0000FF00UL) << 8)  | \
+        (((gctUINT32)(x) & (gctUINT32)0x00FF0000UL) >> 8)  | \
+        (((gctUINT32)(x) & (gctUINT32)0xFF000000UL) >> 24)))
+#else
+#define BIG_ENDIAN_TRANS_INT(x) x
+#endif
+
+/* Write a data value. */
+#define gcmWRITE_VALUE(IntData) \
+    do \
+    { \
+        gceSTATUS status; \
+        gctINT32 value = IntData; \
+        value = BIG_ENDIAN_TRANS_INT(value); \
+        gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(value), &value)); \
+    } \
+    while (gcvFALSE)
+
+#define gcmWRITE_CONST(Const) \
+    do \
+    { \
+        gceSTATUS status; \
+        gctINT32 data = Const; \
+        data = BIG_ENDIAN_TRANS_INT(data); \
+        gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(data), &data)); \
+    } \
+    while (gcvFALSE)
+
+#define gcmWRITE_COUNTER(Counter, Value) \
+    gcmWRITE_CONST(Counter); \
+    gcmWRITE_VALUE(Value)
+
+/* Write a data value. */
+#define gcmRECORD_VALUE(IntData) \
+    do \
+    { \
+        gctINT32 value = IntData; \
+        value = BIG_ENDIAN_TRANS_INT(value); \
+        counterData[counterIndex++] = value; \
+    } \
+    while (gcvFALSE)
+
+#define gcmRECORD_CONST(Const) \
+    do \
+    { \
+        gctINT32 data = Const; \
+        data = BIG_ENDIAN_TRANS_INT(data); \
+        counterData[counterIndex++] = data; \
+    } \
+    while (gcvFALSE)
+
+#define gcmRECORD_COUNTER(Counter, Value) \
+    gcmRECORD_CONST(Counter); \
+    gcmRECORD_VALUE(Value)
+
+/* Write a string value (char*). */
+#define gcmWRITE_STRING(String) \
+    do \
+    { \
+        gceSTATUS status; \
+        gctINT32 length; \
+        length = (gctINT32) gcoOS_StrLen((gctSTRING)String, gcvNULL); \
+        length = BIG_ENDIAN_TRANS_INT(length); \
+        gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(length), &length)); \
+        gcmERR_BREAK(gcoPROFILER_Write(Profiler, length, String)); \
+    } \
+    while (gcvFALSE)
+
+#define gcmWRITE_BUFFER(Size, Buffer) \
+    do \
+    { \
+        gceSTATUS status; \
+        gcmERR_BREAK(gcoPROFILER_Write(Profiler, Size, Buffer)); \
+    } \
+    while (gcvFALSE)
+
+
+#define gcmGET_COUNTER(counter, counterId) \
+    do \
+    { \
+        if (*(memory + (counterId + offset) * (1 << clusterIDWidth)) == 0xdeaddead) \
+        { \
+            counter = 0xdeaddead; \
+        } \
+        else \
+        { \
+            gctUINT32 i; \
+            gctUINT32_PTR Memory = memory; \
+            counter = 0; \
+            Memory = memory + TOTAL_PROBE_NUMBER * CoreId * (1 << clusterIDWidth); \
+            for (i = 0; i < (gctUINT32)(1 << clusterIDWidth); i++) \
+            { \
+                counter += *(Memory + (counterId + offset) * (1 << clusterIDWidth) + i); \
+            } \
+        } \
+    } \
+    while (gcvFALSE)
+
+#define gcmGET_LATENCY_COUNTER(minLatency, maxLatency, counterId) \
+    do \
+    { \
+        if (*(memory + (counterId + offset) * (1 << clusterIDWidth)) == 0xdeaddead) \
+        { \
+            minLatency = maxLatency = 0xdeaddead; \
+        } \
+        else \
+        { \
+            gctUINT32 i; \
+            gctUINT32_PTR Memory = memory; \
+            Memory = memory + TOTAL_PROBE_NUMBER * CoreId * (1 << clusterIDWidth); \
+            for (i = 0; i < (gctUINT32)(1 << clusterIDWidth); i++) \
+            { \
+                maxLatency += ((*(Memory + (counterId + offset) * (1 << clusterIDWidth) + i) & 0xfff000) >> 12); \
+                minLatency += (*(Memory + (counterId + offset) * (1 << clusterIDWidth) + i) & 0x000fff); \
+                if (minLatency == 4095) \
+                    minLatency = 0; \
+            } \
+        } \
+    } \
+    while (gcvFALSE)
+
+#define NumOfPerFrameBuf        16
+#define NumOfPerDrawBuf         128
+
+typedef struct gcsCounterBuffer * gcsCounterBuffer_PTR;
+
+struct gcsCounterBuffer
+{
+    gcsPROFILER_COUNTERS        *counters;
+    gctHANDLE                   couterBufobj;
+    gctUINT32                   probeAddress;
+    gctPOINTER                  logicalAddress;
+    gceCOUNTER_OPTYPE           opType;
+    gctUINT32                   opID;
+    gctUINT32                   startPos;
+    gctUINT32                   endPos;
+    gctUINT32                   dataSize;
+    gctBOOL                     available;
+    gctBOOL                     needDump;
+    gcsCounterBuffer_PTR        next;
+    gcsCounterBuffer_PTR        prev;
+};
+
+typedef struct _gcoPROFILER *        gcoPROFILER;
+
+struct _gcoPROFILER
+{
+    gctBOOL                     enable;
+    gctBOOL                     enablePrint;
+    gctBOOL                     disableProbe;
+    gctBOOL                     probeMode;
+
+    gctFILE                     file;
+    gctCHAR*                    fileName;
+
+    gcsCounterBuffer_PTR        counterBuf;
+    gctUINT32                   bufferCount;
+
+    gctBOOL                     perDrawMode;
+    gctBOOL                     needDump;
+    gctBOOL                     counterEnable;
+
+    gceProfilerClient           profilerClient;
+
+    /*query some features from hw*/
+    gctUINT32                   coreCount;
+    gctUINT32                   shaderCoreCount;
+    gctBOOL                     bHalti4;
+    gctBOOL                     psRenderPixelFix;
+    gctBOOL                     axiBus128bits;
+};
+
+typedef struct _gcsPROBESTATES
+{
+    gceProbeStatus              status;
+    gctUINT32                   probeAddress;
+}gcsPROBESTATES;
+
+/* Construct a Profiler object per context. */
+gceSTATUS
+gcoPROFILER_Construct(
+    OUT gcoPROFILER * Profiler
+    );
+
+gceSTATUS
+gcoPROFILER_Destroy(
+    IN gcoPROFILER Profiler
+    );
+
+gceSTATUS
+gcoPROFILER_Initialize(
+    IN gcoPROFILER Profiler
+    );
+
+gceSTATUS
+gcoPROFILER_Disable(
+    void
+    );
+
+gceSTATUS
+gcoPROFILER_EnableCounters(
+    IN gcoPROFILER Profiler,
+    IN gceCOUNTER_OPTYPE operationType
+    );
+
+gceSTATUS
+gcoPROFILER_End(
+    IN gcoPROFILER Profiler,
+    IN gceCOUNTER_OPTYPE operationType,
+    IN gctUINT32 OpID
+    );
+
+gceSTATUS
+gcoPROFILER_Write(
+    IN gcoPROFILER Profiler,
+    IN gctSIZE_T ByteCount,
+    IN gctCONST_POINTER Data
+    );
+
+gceSTATUS
+gcoPROFILER_Flush(
+    IN gcoPROFILER Profiler
+    );
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_profiler_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h
@@ -0,0 +1,1122 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_raster_h_
+#define __gc_hal_raster_h_
+
+#include "gc_hal_enum.h"
+#include "gc_hal_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gcoBRUSH *                gcoBRUSH;
+typedef struct _gcoBRUSH_CACHE *          gcoBRUSH_CACHE;
+
+/******************************************************************************\
+******************************** gcoBRUSH Object *******************************
+\******************************************************************************/
+
+/* Create a new solid color gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructSingleColor(
+    IN gcoHAL Hal,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 Color,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Create a new monochrome gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructMonochrome(
+    IN gcoHAL Hal,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 FgColor,
+    IN gctUINT32 BgColor,
+    IN gctUINT64 Bits,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Create a color gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructColor(
+    IN gcoHAL Hal,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctPOINTER Address,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Destroy an gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_Destroy(
+    IN gcoBRUSH Brush
+    );
+
+/******************************************************************************\
+******************************** gcoSURF Object *******************************
+\******************************************************************************/
+
+/* Set cipping rectangle. */
+gceSTATUS
+gcoSURF_SetClipping(
+    IN gcoSURF Surface
+    );
+
+/* Clear one or more rectangular areas. */
+gceSTATUS
+gcoSURF_Clear2D(
+    IN gcoSURF DestSurface,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR DestRect,
+    IN gctUINT32 LoColor,
+    IN gctUINT32 HiColor
+    );
+
+/* Draw one or more Bresenham lines. */
+gceSTATUS
+gcoSURF_Line(
+    IN gcoSURF Surface,
+    IN gctUINT32 LineCount,
+    IN gcsRECT_PTR Position,
+    IN gcoBRUSH Brush,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop
+    );
+
+/* Generic rectangular blit. */
+gceSTATUS
+gcoSURF_Blit(
+    IN OPTIONAL gcoSURF SrcSurface,
+    IN gcoSURF DestSurface,
+    IN gctUINT32 RectCount,
+    IN OPTIONAL gcsRECT_PTR SrcRect,
+    IN gcsRECT_PTR DestRect,
+    IN OPTIONAL gcoBRUSH Brush,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN OPTIONAL gceSURF_TRANSPARENCY Transparency,
+    IN OPTIONAL gctUINT32 TransparencyColor,
+    IN OPTIONAL gctPOINTER Mask,
+    IN OPTIONAL gceSURF_MONOPACK MaskPack
+    );
+
+/* Monochrome blit. */
+gceSTATUS
+gcoSURF_MonoBlit(
+    IN gcoSURF DestSurface,
+    IN gctPOINTER Source,
+    IN gceSURF_MONOPACK SourcePack,
+    IN gcsPOINT_PTR SourceSize,
+    IN gcsPOINT_PTR SourceOrigin,
+    IN gcsRECT_PTR DestRect,
+    IN OPTIONAL gcoBRUSH Brush,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gctBOOL ColorConvert,
+    IN gctUINT8 MonoTransparency,
+    IN gceSURF_TRANSPARENCY Transparency,
+    IN gctUINT32 FgColor,
+    IN gctUINT32 BgColor
+    );
+
+/* Filter blit. */
+gceSTATUS
+gcoSURF_FilterBlit(
+    IN gcoSURF SrcSurface,
+    IN gcoSURF DestSurface,
+    IN gcsRECT_PTR SrcRect,
+    IN gcsRECT_PTR DestRect,
+    IN gcsRECT_PTR DestSubRect
+    );
+
+/* Enable alpha blending engine in the hardware and disengage the ROP engine. */
+gceSTATUS
+gcoSURF_EnableAlphaBlend(
+    IN gcoSURF Surface,
+    IN gctUINT8 SrcGlobalAlphaValue,
+    IN gctUINT8 DstGlobalAlphaValue,
+    IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+    IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+    IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+    IN gceSURF_BLEND_FACTOR_MODE DstFactorMode,
+    IN gceSURF_PIXEL_COLOR_MODE SrcColorMode,
+    IN gceSURF_PIXEL_COLOR_MODE DstColorMode
+    );
+
+/* Disable alpha blending engine in the hardware and engage the ROP engine. */
+gceSTATUS
+gcoSURF_DisableAlphaBlend(
+    IN gcoSURF Surface
+    );
+
+gceSTATUS
+gcoSURF_SetDither(
+    IN gcoSURF Surface,
+    IN gctBOOL Dither
+    );
+
+gceSTATUS
+gcoSURF_Set2DSource(
+    gcoSURF Surface,
+    gceSURF_ROTATION Rotation
+    );
+
+gceSTATUS
+gcoSURF_Set2DTarget(
+    gcoSURF Surface,
+    gceSURF_ROTATION Rotation
+    );
+
+/******************************************************************************\
+********************************** gco2D Object *********************************
+\******************************************************************************/
+
+/* Construct a new gco2D object. */
+gceSTATUS
+gco2D_Construct(
+    IN gcoHAL Hal,
+    OUT gco2D * Hardware
+    );
+
+/* Destroy an gco2D object. */
+gceSTATUS
+gco2D_Destroy(
+    IN gco2D Hardware
+    );
+
+/* Sets the maximum number of brushes in the brush cache. */
+gceSTATUS
+gco2D_SetBrushLimit(
+    IN gco2D Hardware,
+    IN gctUINT MaxCount
+    );
+
+/* Flush the brush. */
+gceSTATUS
+gco2D_FlushBrush(
+    IN gco2D Engine,
+    IN gcoBRUSH Brush,
+    IN gceSURF_FORMAT Format
+    );
+
+/* Program the specified solid color brush. */
+gceSTATUS
+gco2D_LoadSolidBrush(
+    IN gco2D Engine,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 Color,
+    IN gctUINT64 Mask
+    );
+
+gceSTATUS
+gco2D_LoadMonochromeBrush(
+    IN gco2D Engine,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 FgColor,
+    IN gctUINT32 BgColor,
+    IN gctUINT64 Bits,
+    IN gctUINT64 Mask
+    );
+
+gceSTATUS
+gco2D_LoadColorBrush(
+    IN gco2D Engine,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctUINT32 Address,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT64 Mask
+    );
+
+/* Configure monochrome source. */
+gceSTATUS
+gco2D_SetMonochromeSource(
+    IN gco2D Engine,
+    IN gctBOOL ColorConvert,
+    IN gctUINT8 MonoTransparency,
+    IN gceSURF_MONOPACK DataPack,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_TRANSPARENCY Transparency,
+    IN gctUINT32 FgColor,
+    IN gctUINT32 BgColor
+    );
+
+/* Configure color source. */
+gceSTATUS
+gco2D_SetColorSource(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_TRANSPARENCY Transparency,
+    IN gctUINT32 TransparencyColor
+    );
+
+/* Configure color source extension for full rotation. */
+gceSTATUS
+gco2D_SetColorSourceEx(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_TRANSPARENCY Transparency,
+    IN gctUINT32 TransparencyColor
+    );
+
+/* Same as gco2D_SetColorSourceEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetColorSource64(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_TRANSPARENCY Transparency,
+    IN gctUINT32 TransparencyColor
+    );
+
+/* Configure color source. */
+gceSTATUS
+gco2D_SetColorSourceAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight,
+    IN gctBOOL CoordRelative
+    );
+
+gceSTATUS
+gco2D_SetColorSourceN(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight,
+    IN gctUINT32 SurfaceNumber
+    );
+
+/* Configure masked color source. */
+gceSTATUS
+gco2D_SetMaskedSource(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_MONOPACK MaskPack
+    );
+
+/* Configure masked color source extension for full rotation. */
+gceSTATUS
+gco2D_SetMaskedSourceEx(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_MONOPACK MaskPack,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight
+    );
+
+/* Same as gco2D_SetMaskedSourceEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetMaskedSource64(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Stride,
+    IN gceSURF_FORMAT Format,
+    IN gctBOOL CoordRelative,
+    IN gceSURF_MONOPACK MaskPack,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight
+    );
+
+/* Setup the source rectangle. */
+gceSTATUS
+gco2D_SetSource(
+    IN gco2D Engine,
+    IN gcsRECT_PTR SrcRect
+    );
+
+/* Set clipping rectangle. */
+gceSTATUS
+gco2D_SetClipping(
+    IN gco2D Engine,
+    IN gcsRECT_PTR Rect
+    );
+
+/* Configure destination. */
+gceSTATUS
+gco2D_SetTarget(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth
+    );
+
+/* Configure destination extension for full rotation. */
+gceSTATUS
+gco2D_SetTargetEx(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctUINT32 Stride,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight
+    );
+
+/* Same as gco2D_SetTargetEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetTarget64(
+    IN gco2D Engine,
+    IN gctUINT32 Address,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Stride,
+    IN gceSURF_ROTATION Rotation,
+    IN gctUINT32 SurfaceWidth,
+    IN gctUINT32 SurfaceHeight
+    );
+
+/* Calculate and program the stretch factors. */
+gceSTATUS
+gco2D_CalcStretchFactor(
+    IN gco2D Engine,
+    IN gctINT32 SrcSize,
+    IN gctINT32 DestSize,
+    OUT gctUINT32_PTR Factor
+    );
+
+gceSTATUS
+gco2D_SetStretchFactors(
+    IN gco2D Engine,
+    IN gctUINT32 HorFactor,
+    IN gctUINT32 VerFactor
+    );
+
+/* Calculate and program the stretch factors based on the rectangles. */
+gceSTATUS
+gco2D_SetStretchRectFactors(
+    IN gco2D Engine,
+    IN gcsRECT_PTR SrcRect,
+    IN gcsRECT_PTR DestRect
+    );
+
+/* Create a new solid color gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructSingleColorBrush(
+    IN gco2D Engine,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 Color,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Create a new monochrome gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructMonochromeBrush(
+    IN gco2D Engine,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctUINT32 ColorConvert,
+    IN gctUINT32 FgColor,
+    IN gctUINT32 BgColor,
+    IN gctUINT64 Bits,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Create a color gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructColorBrush(
+    IN gco2D Engine,
+    IN gctUINT32 OriginX,
+    IN gctUINT32 OriginY,
+    IN gctPOINTER Address,
+    IN gceSURF_FORMAT Format,
+    IN gctUINT64 Mask,
+    gcoBRUSH * Brush
+    );
+
+/* Clear one or more rectangular areas. */
+gceSTATUS
+gco2D_Clear(
+    IN gco2D Engine,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR Rect,
+    IN gctUINT32 Color32,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Draw one or more Bresenham lines. */
+gceSTATUS
+gco2D_Line(
+    IN gco2D Engine,
+    IN gctUINT32 LineCount,
+    IN gcsRECT_PTR Position,
+    IN gcoBRUSH Brush,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Draw one or more Bresenham lines based on the 32-bit color. */
+gceSTATUS
+gco2D_ColorLine(
+    IN gco2D Engine,
+    IN gctUINT32 LineCount,
+    IN gcsRECT_PTR Position,
+    IN gctUINT32 Color32,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Generic blit. */
+gceSTATUS
+gco2D_Blit(
+    IN gco2D Engine,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR Rect,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+gceSTATUS
+gco2D_Blend(
+    IN gco2D Engine,
+    IN gctUINT32 SrcCount,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR Rect,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Batch blit. */
+gceSTATUS
+gco2D_BatchBlit(
+    IN gco2D Engine,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR SrcRect,
+    IN gcsRECT_PTR DestRect,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Stretch blit. */
+gceSTATUS
+gco2D_StretchBlit(
+    IN gco2D Engine,
+    IN gctUINT32 RectCount,
+    IN gcsRECT_PTR Rect,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+/* Monochrome blit. */
+gceSTATUS
+gco2D_MonoBlit(
+    IN gco2D Engine,
+    IN gctPOINTER StreamBits,
+    IN gcsPOINT_PTR StreamSize,
+    IN gcsRECT_PTR StreamRect,
+    IN gceSURF_MONOPACK SrcStreamPack,
+    IN gceSURF_MONOPACK DestStreamPack,
+    IN gcsRECT_PTR DestRect,
+    IN gctUINT32 FgRop,
+    IN gctUINT32 BgRop,
+    IN gceSURF_FORMAT DestFormat
+    );
+
+gceSTATUS
+gco2D_MonoBlitEx(
+    IN gco2D        Engine,
+    IN gctPOINTER   StreamBits,
+    IN gctINT32     StreamStride,
+    IN gctINT32     StreamWidth,
+    IN gctINT32     StreamHeight,
+    IN gctINT32     StreamX,
+    IN gctINT32     StreamY,
+    IN gctUINT32    FgColor,
+    IN gctUINT32    BgColor,
+    IN gcsRECT_PTR  SrcRect,
+    IN gcsRECT_PTR  DstRect,
+    IN gctUINT8     FgRop,
+    IN gctUINT8     BgRop
+    );
+
+/* Set kernel size. */
+gceSTATUS
+gco2D_SetKernelSize(
+    IN gco2D Engine,
+    IN gctUINT8 HorKernelSize,
+    IN gctUINT8 VerKernelSize
+    );
+
+/* Set filter type. */
+gceSTATUS
+gco2D_SetFilterType(
+    IN gco2D Engine,
+    IN gceFILTER_TYPE FilterType
+    );
+
+/* Set the filter kernel by user. */
+gceSTATUS
+gco2D_SetUserFilterKernel(
+    IN gco2D Engine,
+    IN gceFILTER_PASS_TYPE PassType,
+    IN gctUINT16_PTR KernelArray
+    );
+
+/* Select the pass(es) to be done for user defined filter. */
+gceSTATUS
+gco2D_EnableUserFilterPasses(
+    IN gco2D Engine,
+    IN gctBOOL HorPass,
+    IN gctBOOL VerPass
+    );
+
+/* Frees the temporary buffer allocated by filter blit operation. */
+gceSTATUS
+gco2D_FreeFilterBuffer(
+    IN gco2D Engine
+    );
+
+/* Filter blit. */
+gceSTATUS
+gco2D_FilterBlit(
+    IN gco2D Engine,
+    IN gctUINT32 SrcAddress,
+    IN gctUINT SrcStride,
+    IN gctUINT32 SrcUAddress,
+    IN gctUINT SrcUStride,
+    IN gctUINT32 SrcVAddress,
+    IN gctUINT SrcVStride,
+    IN gceSURF_FORMAT SrcFormat,
+    IN gceSURF_ROTATION SrcRotation,
+    IN gctUINT32 SrcSurfaceWidth,
+    IN gcsRECT_PTR SrcRect,
+    IN gctUINT32 DestAddress,
+    IN gctUINT DestStride,
+    IN gceSURF_FORMAT DestFormat,
+    IN gceSURF_ROTATION DestRotation,
+    IN gctUINT32 DestSurfaceWidth,
+    IN gcsRECT_PTR DestRect,
+    IN gcsRECT_PTR DestSubRect
+    );
+
+/* Filter blit extension for full rotation. */
+gceSTATUS
+gco2D_FilterBlitEx(
+    IN gco2D Engine,
+    IN gctUINT32 SrcAddress,
+    IN gctUINT SrcStride,
+    IN gctUINT32 SrcUAddress,
+    IN gctUINT SrcUStride,
+    IN gctUINT32 SrcVAddress,
+    IN gctUINT SrcVStride,
+    IN gceSURF_FORMAT SrcFormat,
+    IN gceSURF_ROTATION SrcRotation,
+    IN gctUINT32 SrcSurfaceWidth,
+    IN gctUINT32 SrcSurfaceHeight,
+    IN gcsRECT_PTR SrcRect,
+    IN gctUINT32 DestAddress,
+    IN gctUINT DestStride,
+    IN gceSURF_FORMAT DestFormat,
+    IN gceSURF_ROTATION DestRotation,
+    IN gctUINT32 DestSurfaceWidth,
+    IN gctUINT32 DestSurfaceHeight,
+    IN gcsRECT_PTR DestRect,
+    IN gcsRECT_PTR DestSubRect
+    );
+
+gceSTATUS
+gco2D_FilterBlitEx2(
+    IN gco2D                Engine,
+    IN gctUINT32_PTR        SrcAddresses,
+    IN gctUINT32            SrcAddressNum,
+    IN gctUINT32_PTR        SrcStrides,
+    IN gctUINT32            SrcStrideNum,
+    IN gceTILING            SrcTiling,
+    IN gceSURF_FORMAT       SrcFormat,
+    IN gceSURF_ROTATION     SrcRotation,
+    IN gctUINT32            SrcSurfaceWidth,
+    IN gctUINT32            SrcSurfaceHeight,
+    IN gcsRECT_PTR          SrcRect,
+    IN gctUINT32_PTR        DestAddresses,
+    IN gctUINT32            DestAddressNum,
+    IN gctUINT32_PTR        DestStrides,
+    IN gctUINT32            DestStrideNum,
+    IN gceTILING            DestTiling,
+    IN gceSURF_FORMAT       DestFormat,
+    IN gceSURF_ROTATION     DestRotation,
+    IN gctUINT32            DestSurfaceWidth,
+    IN gctUINT32            DestSurfaceHeight,
+    IN gcsRECT_PTR          DestRect,
+    IN gcsRECT_PTR          DestSubRect
+    );
+
+/* Enable alpha blending engine in the hardware and disengage the ROP engine. */
+gceSTATUS
+gco2D_EnableAlphaBlend(
+    IN gco2D Engine,
+    IN gctUINT8 SrcGlobalAlphaValue,
+    IN gctUINT8 DstGlobalAlphaValue,
+    IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+    IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+    IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+    IN gceSURF_BLEND_FACTOR_MODE DstFactorMode,
+    IN gceSURF_PIXEL_COLOR_MODE SrcColorMode,
+    IN gceSURF_PIXEL_COLOR_MODE DstColorMode
+    );
+
+/* Enable alpha blending engine in the hardware. */
+gceSTATUS
+gco2D_EnableAlphaBlendAdvanced(
+    IN gco2D Engine,
+    IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+    IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+    IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+    IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+    IN gceSURF_BLEND_FACTOR_MODE DstFactorMode
+    );
+
+/* Enable alpha blending engine with Porter Duff rule. */
+gceSTATUS
+gco2D_SetPorterDuffBlending(
+    IN gco2D Engine,
+    IN gce2D_PORTER_DUFF_RULE Rule
+    );
+
+/* Disable alpha blending engine in the hardware and engage the ROP engine. */
+gceSTATUS
+gco2D_DisableAlphaBlend(
+    IN gco2D Engine
+    );
+
+/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */
+gctUINT32
+gco2D_GetMaximumDataCount(
+    void
+    );
+
+/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */
+gctUINT32
+gco2D_GetMaximumRectCount(
+    void
+    );
+
+/* Returns the pixel alignment of the surface. */
+gceSTATUS
+gco2D_GetPixelAlignment(
+    gceSURF_FORMAT Format,
+    gcsPOINT_PTR Alignment
+    );
+
+/* Retrieve monochrome stream pack size. */
+gceSTATUS
+gco2D_GetPackSize(
+    IN gceSURF_MONOPACK StreamPack,
+    OUT gctUINT32 * PackWidth,
+    OUT gctUINT32 * PackHeight
+    );
+
+/* Flush the 2D pipeline. */
+gceSTATUS
+gco2D_Flush(
+    IN gco2D Engine
+    );
+
+/* Load 256-entry color table for INDEX8 source surfaces. */
+gceSTATUS
+gco2D_LoadPalette(
+    IN gco2D Engine,
+    IN gctUINT FirstIndex,
+    IN gctUINT IndexCount,
+    IN gctPOINTER ColorTable,
+    IN gctBOOL ColorConvert
+    );
+
+/* Enable/disable 2D BitBlt mirrorring. */
+gceSTATUS
+gco2D_SetBitBlitMirror(
+    IN gco2D Engine,
+    IN gctBOOL HorizontalMirror,
+    IN gctBOOL VerticalMirror
+    );
+
+/*
+ * Set the transparency for source, destination and pattern.
+ * It also enable or disable the DFB color key mode.
+ */
+gceSTATUS
+gco2D_SetTransparencyAdvancedEx(
+    IN gco2D Engine,
+    IN gce2D_TRANSPARENCY SrcTransparency,
+    IN gce2D_TRANSPARENCY DstTransparency,
+    IN gce2D_TRANSPARENCY PatTransparency,
+    IN gctBOOL EnableDFBColorKeyMode
+    );
+
+/* Set the transparency for source, destination and pattern. */
+gceSTATUS
+gco2D_SetTransparencyAdvanced(
+    IN gco2D Engine,
+    IN gce2D_TRANSPARENCY SrcTransparency,
+    IN gce2D_TRANSPARENCY DstTransparency,
+    IN gce2D_TRANSPARENCY PatTransparency
+    );
+
+/* Set the source color key. */
+gceSTATUS
+gco2D_SetSourceColorKeyAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 ColorKey
+    );
+
+/* Set the source color key range. */
+gceSTATUS
+gco2D_SetSourceColorKeyRangeAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 ColorKeyLow,
+    IN gctUINT32 ColorKeyHigh
+    );
+
+/* Set the target color key. */
+gceSTATUS
+gco2D_SetTargetColorKeyAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 ColorKey
+    );
+
+/* Set the target color key range. */
+gceSTATUS
+gco2D_SetTargetColorKeyRangeAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 ColorKeyLow,
+    IN gctUINT32 ColorKeyHigh
+    );
+
+/* Set the YUV color space mode. */
+gceSTATUS
+gco2D_SetYUVColorMode(
+    IN gco2D Engine,
+    IN gce2D_YUV_COLOR_MODE Mode
+    );
+
+/* Setup the source global color value in ARGB8 format. */
+gceSTATUS gco2D_SetSourceGlobalColorAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 Color32
+    );
+
+/* Setup the target global color value in ARGB8 format. */
+gceSTATUS gco2D_SetTargetGlobalColorAdvanced(
+    IN gco2D Engine,
+    IN gctUINT32 Color32
+    );
+
+/* Setup the source and target pixel multiply modes. */
+gceSTATUS
+gco2D_SetPixelMultiplyModeAdvanced(
+    IN gco2D Engine,
+    IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha,
+    IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha,
+    IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode,
+    IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha
+    );
+
+/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */
+gceSTATUS
+gco2D_SetAutoFlushCycles(
+    IN gco2D Engine,
+    IN gctUINT32 Cycles
+    );
+
+#if VIVANTE_PROFILER
+/* Read the profile registers available in the 2D engine and sets them in the profile.
+   The function will also reset the pixelsRendered counter every time.
+*/
+gceSTATUS
+gco2D_ProfileEngine(
+    IN gco2D Engine,
+    OPTIONAL gcs2D_PROFILE_PTR Profile
+    );
+#endif
+
+/* Enable or disable 2D dithering. */
+gceSTATUS
+gco2D_EnableDither(
+    IN gco2D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco2D_SetGenericSource(
+    IN gco2D               Engine,
+    IN gctUINT32_PTR       Addresses,
+    IN gctUINT32           AddressNum,
+    IN gctUINT32_PTR       Strides,
+    IN gctUINT32           StrideNum,
+    IN gceTILING           Tiling,
+    IN gceSURF_FORMAT      Format,
+    IN gceSURF_ROTATION    Rotation,
+    IN gctUINT32           SurfaceWidth,
+    IN gctUINT32           SurfaceHeight
+);
+
+gceSTATUS
+gco2D_SetGenericTarget(
+    IN gco2D               Engine,
+    IN gctUINT32_PTR       Addresses,
+    IN gctUINT32           AddressNum,
+    IN gctUINT32_PTR       Strides,
+    IN gctUINT32           StrideNum,
+    IN gceTILING           Tiling,
+    IN gceSURF_FORMAT      Format,
+    IN gceSURF_ROTATION    Rotation,
+    IN gctUINT32           SurfaceWidth,
+    IN gctUINT32           SurfaceHeight
+);
+
+gceSTATUS
+gco2D_SetCurrentSourceIndex(
+    IN gco2D        Engine,
+    IN gctUINT32    SrcIndex
+    );
+
+gceSTATUS
+gco2D_MultiSourceBlit(
+    IN gco2D Engine,
+    IN gctUINT32 SourceMask,
+    IN gcsRECT_PTR DestRect,
+    IN gctUINT32 RectCount
+    );
+
+gceSTATUS
+gco2D_SetROP(
+    IN gco2D Engine,
+    IN gctUINT8 FgRop,
+    IN gctUINT8 BgRop
+    );
+
+gceSTATUS
+gco2D_SetGdiStretchMode(
+    IN gco2D Engine,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gco2D_SetSourceTileStatus(
+    IN gco2D Engine,
+    IN gce2D_TILE_STATUS_CONFIG TSControl,
+    IN gceSURF_FORMAT CompressedFormat,
+    IN gctUINT32 ClearValue,
+    IN gctUINT32 GpuAddress
+    );
+
+gceSTATUS
+gco2D_SetTargetTileStatus(
+    IN gco2D Engine,
+    IN gce2D_TILE_STATUS_CONFIG TileStatusConfig,
+    IN gceSURF_FORMAT CompressedFormat,
+    IN gctUINT32 ClearValue,
+    IN gctUINT32 GpuAddress
+    );
+
+gceSTATUS
+gco2D_QueryU32(
+    IN gco2D Engine,
+    IN gce2D_QUERY Item,
+    OUT gctUINT32_PTR Value
+    );
+
+gceSTATUS
+gco2D_SetStateU32(
+    IN gco2D Engine,
+    IN gce2D_STATE State,
+    IN gctUINT32 Value
+    );
+
+gceSTATUS
+gco2D_SetStateArrayI32(
+    IN gco2D Engine,
+    IN gce2D_STATE State,
+    IN gctINT32_PTR Array,
+    IN gctINT32 ArraySize
+    );
+
+gceSTATUS
+gco2D_SetStateArrayU32(
+    IN gco2D Engine,
+    IN gce2D_STATE State,
+    IN gctUINT32_PTR Array,
+    IN gctINT32 ArraySize
+    );
+
+gceSTATUS
+gco2D_SetTargetRect(
+    IN gco2D Engine,
+    IN gcsRECT_PTR Rect
+    );
+
+gceSTATUS
+gco2D_Set2DEngine(
+    IN gco2D Engine
+    );
+
+gceSTATUS
+gco2D_UnSet2DEngine(
+    IN gco2D Engine
+    );
+
+gceSTATUS
+gco2D_Get2DEngine(
+    OUT gco2D * Engine
+    );
+
+gceSTATUS
+gco2D_Commit(
+    IN gco2D Engine,
+    IN gctBOOL Stall
+    );
+
+gceSTATUS
+gco2D_NatureRotateTranslation(
+    IN gctBOOL IsSrcRot,
+    IN gce2D_NATURE_ROTATION NatureRotation,
+    IN gctINT32 SrcSurfaceWidth,
+    IN gctINT32 SrcSurfaceHeight,
+    IN gctINT32 DstSurfaceWidth,
+    IN gctINT32 DstSurfaceHeight,
+    IN OUT gcsRECT_PTR SrcRect,
+    IN OUT gcsRECT_PTR DstRect,
+    OUT gceSURF_ROTATION * SrcRotation,
+    OUT gceSURF_ROTATION * DstRotation
+    );
+
+/* Set source endian mode. */
+gceSTATUS
+gco2D_SetSourceEndianMode(
+    IN gco2D Engine,
+    IN gceENDIAN_MODE eEndianMode
+    );
+
+/* Set target endian mode. */
+gceSTATUS
+gco2D_SetTargetEndianMode(
+    IN gco2D Engine,
+    IN gceENDIAN_MODE eEndianMode
+    );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_raster_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_SECURITY_INTERFACE_H_
+#define _GC_HAL_SECURITY_INTERFACE_H_
+struct kernel_start_command {
+    kernel_packet_command_t command;      /*! The command (always needs to be the first entry in a structure). */
+    gctUINT8       gpu;                    /*! Which GPU. */
+    gctUINT32      address;
+    gctUINT32      bytes;
+};
+
+/*!
+ @brief gckCOMMAND Object requests TrustZone to submit command buffer.
+ @discussion
+ Code in trustzone will check content of command buffer after copying command buffer to TrustZone.
+ */
+struct kernel_submit {
+    kernel_packet_command_t command;      /*! The command (always needs to be the first entry in a structure). */
+    gctUINT8       gpu;                    /*! Which GPU. */
+    gctUINT8       kernel_command;         /*! Whether it is a kernel command. */
+    gctUINT32      command_buffer_handle;  /*! Handle to command buffer. */
+    gctUINT32      offset;                  /* Offset in command buffer. */
+    gctUINT32 *    command_buffer;         /*! Content of command buffer need to be submit. */
+    gctUINT32      command_buffer_length;  /*! Length of command buffer. */
+};
+
+
+/*!
+ @brief gckVIDMEM Object requests TrustZone to allocate security memory.
+ @discussion
+ Allocate a buffer from security GPU memory.
+ */
+struct kernel_allocate_security_memory {
+    kernel_packet_command_t command;      /*! The command (always needs to be the first entry in a structure). */
+    gctUINT32      bytes;                  /*! Requested bytes. */
+    gctUINT32      memory_handle;          /*! Handle of allocated memory. */
+};
+
+/*!
+ @brief gckVIDMEM Object requests TrustZone to allocate security memory.
+ @discussion
+ Free a video memory buffer from security GPU memory.
+ */
+struct kernel_free_security_memory {
+    kernel_packet_command_t command;      /*! The command (always needs to be the first entry in a structure). */
+    gctUINT32      memory_handle;          /*! Handle of allocated memory. */
+};
+
+struct kernel_execute {
+    kernel_packet_command_t command;      /*! The command (always needs to be the first entry in a structure). */
+    gctUINT8       gpu;                    /*! Which GPU. */
+    gctUINT8       kernel_command;         /*! Whether it is a kernel command. */
+    gctUINT32 *    command_buffer;         /*! Content of command buffer need to be submit. */
+    gctUINT32      command_buffer_length;  /*! Length of command buffer. */
+};
+
+typedef struct kernel_map_scatter_gather {
+    gctUINT32      bytes;
+    gctUINT32      physical;
+    struct kernel_map_scatter_gather *next;
+}
+kernel_map_scatter_gather_t;
+
+struct kernel_map_memory {
+    kernel_packet_command_t command;
+    kernel_map_scatter_gather_t *scatter;
+    gctUINT32       *physicals;
+    gctPHYS_ADDR_T  physical;   /*! Contiguous physical address range. */
+    gctUINT32       pageCount;
+    gctUINT32       gpuAddress;
+};
+
+struct kernel_unmap_memory {
+    gctUINT32       gpuAddress;
+    gctUINT32       pageCount;
+};
+
+struct kernel_read_mmu_exception {
+    gctUINT32       mmuStatus;
+    gctUINT32       mmuException;
+};
+
+struct kernel_handle_mmu_exception {
+    gctUINT32       mmuStatus;
+    gctPHYS_ADDR_T  physical;
+    gctUINT32       gpuAddress;
+};
+
+typedef struct _gcsTA_INTERFACE {
+    kernel_packet_command_t command;
+    union {
+        struct kernel_submit                   Submit;
+        struct kernel_start_command            StartCommand;
+        struct kernel_allocate_security_memory AllocateSecurityMemory;
+        struct kernel_execute                  Execute;
+        struct kernel_map_memory               MapMemory;
+        struct kernel_unmap_memory             UnmapMemory;
+        struct kernel_read_mmu_exception       ReadMMUException;
+        struct kernel_handle_mmu_exception     HandleMMUException;
+    } u;
+    gceSTATUS result;
+} gcsTA_INTERFACE;
+
+#endif
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_statistics_h_
+#define __gc_hal_statistics_h_
+
+
+#define VIV_STAT_ENABLE_STATISTICS              0
+
+/*  Toal number of frames for which the frame time is accounted. We have storage
+    to keep frame times for last this many frames.
+*/
+#define VIV_STAT_FRAME_BUFFER_SIZE              30
+
+
+/*
+    Total number of frames sampled for a mode. This means
+
+    # of frames for HZ Current  : VIV_STAT_EARLY_Z_SAMPLE_FRAMES
+    # of frames for HZ Switched : VIV_STAT_EARLY_Z_SAMPLE_FRAMES
+  +
+  --------------------------------------------------------
+                                : (2 * VIV_STAT_EARLY_Z_SAMPLE_FRAMES) frames needed
+
+    IMPORTANT: This total must be smaller than VIV_STAT_FRAME_BUFFER_SIZE
+*/
+#define VIV_STAT_EARLY_Z_SAMPLE_FRAMES          7
+#define VIV_STAT_EARLY_Z_LATENCY_FRAMES         2
+
+/* Multiplication factor for previous Hz off mode. Make it more than 1.0 to advertise HZ on.*/
+#define VIV_STAT_EARLY_Z_FACTOR                 (1.05f)
+
+/* HAL statistics information. */
+typedef struct _gcsSTATISTICS_EARLYZ
+{
+    gctUINT                     switchBackCount;
+    gctUINT                     nextCheckPoint;
+    gctBOOL                     disabled;
+}
+gcsSTATISTICS_EARLYZ;
+
+
+/* HAL statistics information. */
+typedef struct _gcsSTATISTICS
+{
+    gctUINT64                   frameTime[VIV_STAT_FRAME_BUFFER_SIZE];
+    gctUINT64                   previousFrameTime;
+    gctUINT                     frame;
+    gcsSTATISTICS_EARLYZ        earlyZ;
+}
+gcsSTATISTICS;
+
+
+/* Add a frame based data into current statistics. */
+void
+gcfSTATISTICS_AddData(
+    IN gceSTATISTICS Key,
+    IN gctUINT Value
+    );
+
+/* Marks the frame end and triggers statistical calculations and decisions.*/
+void
+gcfSTATISTICS_MarkFrameEnd (
+    void
+    );
+
+/* Sets whether the dynmaic HZ is disabled or not .*/
+void
+gcfSTATISTICS_DisableDynamicEarlyZ (
+    IN gctBOOL Disabled
+    );
+
+#endif /*__gc_hal_statistics_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_version.h"
+#include "gc_hal_options.h"
+#include "shared/gc_hal_types_shared.h"
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_version_h_
+#define __gc_hal_version_h_
+
+#define gcvVERSION_MAJOR        6
+
+#define gcvVERSION_MINOR        4
+
+#define gcvVERSION_PATCH        3
+
+#define gcvVERSION_BUILD     305572
+
+#define gcvVERSION_STRING    "6.4.3.p1.305572"
+
+#endif /* __gc_hal_version_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h
@@ -0,0 +1,736 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_vg_h_
+#define __gc_hal_vg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+#include "gc_hal_base.h"
+#include "shared/gc_hal_vg_shared.h"
+
+#if gcdENABLE_VG
+
+/* Thread routine type. */
+#if defined(LINUX)
+    typedef gctINT              gctTHREADFUNCRESULT;
+    typedef gctPOINTER          gctTHREADFUNCPARAMETER;
+#   define  gctTHREADFUNCTYPE
+#elif defined(WIN32)
+    typedef gctUINT             gctTHREADFUNCRESULT;
+    typedef gctPOINTER          gctTHREADFUNCPARAMETER;
+#   define  gctTHREADFUNCTYPE   __stdcall
+#elif defined(__QNXNTO__)
+    typedef void *              gctTHREADFUNCRESULT;
+    typedef gctPOINTER          gctTHREADFUNCPARAMETER;
+#   define  gctTHREADFUNCTYPE
+#endif
+
+typedef gctTHREADFUNCRESULT (gctTHREADFUNCTYPE * gctTHREADFUNC) (
+    gctTHREADFUNCPARAMETER ThreadParameter
+    );
+
+
+#if defined(gcvDEBUG)
+#   undef gcvDEBUG
+#endif
+
+#define gcdFORCE_DEBUG 0
+#define gcdFORCE_MESSAGES 0
+
+
+#if DBG || defined(DEBUG) || defined(_DEBUG) || gcdFORCE_DEBUG
+#   define gcvDEBUG 1
+#else
+#   define gcvDEBUG 0
+#endif
+
+#define _gcmERROR_RETURN(prefix, func) \
+    status = func; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        prefix##PRINT_VERSION(); \
+        prefix##TRACE(gcvLEVEL_ERROR, \
+            #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+            status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+        return status; \
+    } \
+    do { } while (gcvFALSE)
+
+#define gcmERROR_RETURN(func)         _gcmERROR_RETURN(gcm, func)
+
+#define gcmLOG_LOCATION()
+
+#define gcmkIS_ERROR(status)        (status < 0)
+
+#define gcmALIGNDOWN(n, align) \
+(\
+    (n) & ~((align) - 1) \
+)
+
+#define gcmIS_VALID_INDEX(Index, Array) \
+    (((gctUINT) (Index)) < gcmCOUNTOF(Array))
+
+
+#define gcmIS_NAN(x) \
+(\
+    ((* (gctUINT32_PTR) &(x)) & 0x7FFFFFFF) == 0x7FFFFFFF \
+)
+
+#define gcmLERP(v1, v2, w) \
+    ((v1) * (w) + (v2) * (1.0f - (w)))
+
+#define gcmINTERSECT(Start1, Start2, Length) \
+    (gcmABS((Start1) - (Start2)) < (Length))
+
+/*******************************************************************************
+**
+**  gcmERR_GOTO
+**
+**      Prints a message and terminates the current loop on error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of gceSTATUS type must be defined.
+**
+**  ARGUMENTS:
+**
+**      Function
+**          Function to evaluate.
+*/
+
+#define gcmERR_GOTO(Function) \
+    status = Function; \
+    if (gcmIS_ERROR(status)) \
+    { \
+        gcmTRACE(\
+            gcvLEVEL_ERROR, \
+            "gcmERR_GOTO: status=%d @ line=%d in function %s.\n", \
+            status, __LINE__, __FUNCTION__ \
+            ); \
+        goto ErrorHandler; \
+    }
+
+#if gcvDEBUG || gcdFORCE_MESSAGES
+#   define gcmVERIFY_BOOLEAN(Expression) \
+        gcmASSERT(\
+            ((Expression) == gcvFALSE ) || \
+            ((Expression) == gcvTRUE  )    \
+            )
+#else
+#   define gcmVERIFY_BOOLEAN(Expression)
+#endif
+
+/*******************************************************************************
+**
+**  gcmVERIFYFIELDFIT
+**
+**      Verify whether the value fits in the field.
+**
+**  ARGUMENTS:
+**
+**      data    Data value.
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Value for field.
+*/
+#define gcmVERIFYFIELDFIT(reg, field, value) \
+    gcmASSERT(\
+        (value) <= gcmFIELDMAX(reg, field) \
+        )
+/*******************************************************************************
+**
+**  gcmFIELDMAX
+**
+**      Get field maximum value.
+**
+**  ARGUMENTS:
+**
+**      reg     Name of register.
+**      field   Name of field within register.
+*/
+#define gcmFIELDMAX(reg, field) \
+(\
+    (gctUINT32) \
+        (\
+        (__gcmGETSIZE(reg##_##field) == 32) \
+                ?  ~0U \
+                : (~(~0U << __gcmGETSIZE(reg##_##field))) \
+        ) \
+)
+
+
+/* ANSI C does not have the 'f' functions, define replacements here. */
+#define gcmSINF(x)                      ((gctFLOAT) sin(x))
+#define gcmCOSF(x)                      ((gctFLOAT) cos(x))
+#define gcmASINF(x)                     ((gctFLOAT) asin(x))
+#define gcmACOSF(x)                     ((gctFLOAT) acos(x))
+#define gcmSQRTF(x)                     ((gctFLOAT) sqrt(x))
+#define gcmFABSF(x)                     ((gctFLOAT) fabs(x))
+#define gcmFMODF(x, y)                  ((gctFLOAT) fmod((x), (y)))
+#define gcmCEILF(x)                     ((gctFLOAT) ceil(x))
+#define gcmFLOORF(x)                    ((gctFLOAT) floor(x))
+
+
+
+/* Fixed point constants. */
+#define gcvZERO_X               ((gctFIXED_POINT) 0x00000000)
+#define gcvHALF_X               ((gctFIXED_POINT) 0x00008000)
+#define gcvONE_X                ((gctFIXED_POINT) 0x00010000)
+#define gcvNEGONE_X             ((gctFIXED_POINT) 0xFFFF0000)
+#define gcvTWO_X                ((gctFIXED_POINT) 0x00020000)
+
+/* Integer constants. */
+#define gcvMAX_POS_INT          ((gctINT) 0x7FFFFFFF)
+#define gcvMAX_NEG_INT          ((gctINT) 0x80000000)
+
+/* Float constants. */
+#define gcvMAX_POS_FLOAT        ((gctFLOAT)  3.4028235e+038)
+#define gcvMAX_NEG_FLOAT        ((gctFLOAT) -3.4028235e+038)
+
+/******************************************************************************\
+***************************** Miscellaneous Macro ******************************
+\******************************************************************************/
+
+#define gcmKB2BYTES(Kilobyte) \
+(\
+    (Kilobyte) << 10 \
+)
+
+#define gcmMB2BYTES(Megabyte) \
+(\
+    (Megabyte) << 20 \
+)
+
+#define gcmMAT(Matrix, Row, Column) \
+(\
+    (Matrix) [(Row) * 3 + (Column)] \
+)
+
+#define gcmMAKE2CHAR(Char1, Char2) \
+(\
+    ((gctUINT16) (gctUINT8) (Char1) << 0) | \
+    ((gctUINT16) (gctUINT8) (Char2) << 8) \
+)
+
+#define gcmMAKE4CHAR(Char1, Char2, Char3, Char4) \
+(\
+    ((gctUINT32)(gctUINT8) (Char1) <<  0) | \
+    ((gctUINT32)(gctUINT8) (Char2) <<  8) | \
+    ((gctUINT32)(gctUINT8) (Char3) << 16) | \
+    ((gctUINT32)(gctUINT8) (Char4) << 24) \
+)
+
+/* some platforms need to fix the physical address for HW to access*/
+#define gcmFIXADDRESS(address) \
+(\
+    (address)\
+)
+
+#define gcmkFIXADDRESS(address) \
+(\
+    (address)\
+)
+
+/*----------------------------------------------------------------------------*/
+/*----------------------------- Semaphore Object -----------------------------*/
+
+/* Increment the value of a semaphore. */
+gceSTATUS
+gckOS_IncrementSemaphore(
+    IN gckOS Os,
+    IN gctSEMAPHORE Semaphore
+    );
+
+/* Decrement the value of a semaphore (waiting might occur). */
+gceSTATUS
+gckOS_DecrementSemaphore(
+    IN gckOS Os,
+    IN gctSEMAPHORE Semaphore
+    );
+
+
+/*----------------------------------------------------------------------------*/
+/*------------------------------- Thread Object ------------------------------*/
+
+/* Start a thread. */
+gceSTATUS
+gckOS_StartThread(
+    IN gckOS Os,
+    IN gctTHREADFUNC ThreadFunction,
+    IN gctPOINTER ThreadParameter,
+    OUT gctTHREAD * Thread
+    );
+
+/* Stop a thread. */
+gceSTATUS
+gckOS_StopThread(
+    IN gckOS Os,
+    IN gctTHREAD Thread
+    );
+
+/* Verify whether the thread is still running. */
+gceSTATUS
+gckOS_VerifyThread(
+    IN gckOS Os,
+    IN gctTHREAD Thread
+    );
+
+
+/* Construct a new gckVGKERNEL object. */
+gceSTATUS
+gckVGKERNEL_Construct(
+    IN gckOS Os,
+    IN gctPOINTER Context,
+    IN gckKERNEL  inKernel,
+    OUT gckVGKERNEL * Kernel
+    );
+
+/* Destroy an gckVGKERNEL object. */
+gceSTATUS
+gckVGKERNEL_Destroy(
+    IN gckVGKERNEL Kernel
+    );
+
+/* Unmap memory. */
+gceSTATUS
+gckKERNEL_UnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID
+    );
+
+/* Dispatch a user-level command. */
+gceSTATUS
+gckVGKERNEL_Dispatch(
+    IN gckKERNEL Kernel,
+    IN OUT struct _gcsHAL_INTERFACE * Interface
+    );
+
+/* Query command buffer requirements. */
+gceSTATUS
+gckKERNEL_QueryCommandBuffer(
+    IN gckKERNEL Kernel,
+    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+    );
+
+/******************************************************************************\
+******************************* gckVGHARDWARE Object ******************************
+\******************************************************************************/
+
+/* Construct a new gckVGHARDWARE object. */
+gceSTATUS
+gckVGHARDWARE_Construct(
+    IN gckOS Os,
+    OUT gckVGHARDWARE * Hardware
+    );
+
+/* Destroy an gckVGHARDWARE object. */
+gceSTATUS
+gckVGHARDWARE_Destroy(
+    IN gckVGHARDWARE Hardware
+    );
+
+/* Query system memory requirements. */
+gceSTATUS
+gckVGHARDWARE_QuerySystemMemory(
+    IN gckVGHARDWARE Hardware,
+    OUT gctSIZE_T * SystemSize,
+    OUT gctUINT32 * SystemBaseAddress
+    );
+
+/* Build virtual address. */
+gceSTATUS
+gckVGHARDWARE_BuildVirtualAddress(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Index,
+    IN gctUINT32 Offset,
+    OUT gctUINT32 * Address
+    );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckVGHARDWARE_Execute(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Address,
+    IN gctUINT32 Count
+    );
+
+/* Query the available memory. */
+gceSTATUS
+gckVGHARDWARE_QueryMemory(
+    IN gckVGHARDWARE Hardware,
+    OUT gctSIZE_T * InternalSize,
+    OUT gctUINT32 * InternalBaseAddress,
+    OUT gctUINT32 * InternalAlignment,
+    OUT gctSIZE_T * ExternalSize,
+    OUT gctUINT32 * ExternalBaseAddress,
+    OUT gctUINT32 * ExternalAlignment,
+    OUT gctUINT32 * HorizontalTileSize,
+    OUT gctUINT32 * VerticalTileSize
+    );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gckVGHARDWARE_QueryChipIdentity(
+    IN gckVGHARDWARE Hardware,
+    OUT gceCHIPMODEL* ChipModel,
+    OUT gctUINT32* ChipRevision,
+    OUT gctUINT32* ProductID,
+    OUT gctUINT32* EcoID,
+    OUT gctUINT32* CustomerID,
+    OUT gctUINT32* ChipFeatures,
+    OUT gctUINT32* ChipMinorFeatures,
+    OUT gctUINT32* ChipMinorFeatures1
+    );
+
+/* Convert an API format. */
+gceSTATUS
+gckVGHARDWARE_ConvertFormat(
+    IN gckVGHARDWARE Hardware,
+    IN gceSURF_FORMAT Format,
+    OUT gctUINT32 * BitsPerPixel,
+    OUT gctUINT32 * BytesPerTile
+    );
+
+/* Split a harwdare specific address into API stuff. */
+gceSTATUS
+gckVGHARDWARE_SplitMemory(
+    IN gckVGHARDWARE Hardware,
+    IN gctUINT32 Address,
+    OUT gcePOOL * Pool,
+    OUT gctUINT32 * Offset
+    );
+
+/* Convert logical address to hardware specific address. */
+gceSTATUS
+gckVGHARDWARE_ConvertLogical(
+    IN gckVGHARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN gctBOOL InUserSpace,
+    OUT gctUINT32 * Address
+    );
+
+/* Program MMU. */
+gceSTATUS
+gckVGHARDWARE_SetMMU(
+    IN gckVGHARDWARE Hardware,
+    IN gctPOINTER Logical
+    );
+
+/* Flush the MMU. */
+gceSTATUS
+gckVGHARDWARE_FlushMMU(
+    IN gckVGHARDWARE Hardware
+    );
+
+/* Get idle register. */
+gceSTATUS
+gckVGHARDWARE_GetIdle(
+    IN gckVGHARDWARE Hardware,
+    OUT gctUINT32 * Data
+    );
+
+/* Flush the caches. */
+gceSTATUS
+gckVGHARDWARE_Flush(
+    IN gckVGHARDWARE Hardware,
+    IN gceKERNEL_FLUSH Flush,
+    IN gctPOINTER Logical,
+    IN OUT gctSIZE_T * Bytes
+    );
+
+/* Enable/disable fast clear. */
+gceSTATUS
+gckVGHARDWARE_SetFastClear(
+    IN gckVGHARDWARE Hardware,
+    IN gctINT Enable
+    );
+
+gceSTATUS
+gckVGHARDWARE_ReadInterrupt(
+    IN gckVGHARDWARE Hardware,
+    OUT gctUINT32_PTR IDs
+    );
+
+/* Power management. */
+gceSTATUS
+gckVGHARDWARE_SetPowerState(
+    IN gckVGHARDWARE Hardware,
+    IN gceCHIPPOWERSTATE State
+    );
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerManagementState(
+    IN gckVGHARDWARE Hardware,
+    OUT gceCHIPPOWERSTATE* State
+    );
+
+gceSTATUS
+gckVGHARDWARE_EnablePowerManagement(
+    IN gckVGHARDWARE Hardware,
+    IN gctBOOL Enable
+    );
+
+gceSTATUS
+gckVGHARDWARE_SetPowerOffTimeout(
+    IN gckVGHARDWARE  Hardware,
+    IN gctUINT32    Timeout
+    );
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerOffTimeout(
+    IN gckVGHARDWARE  Hardware,
+    OUT gctUINT32*  Timeout
+    );
+
+gceSTATUS
+gckVGHARDWARE_QueryIdle(
+    IN gckVGHARDWARE Hardware,
+    OUT gctBOOL_PTR IsIdle
+    );
+/******************************************************************************\
+*************************** Command Buffer Structures **************************
+\******************************************************************************/
+
+/* Vacant command buffer marker. */
+#define gcvVACANT_BUFFER        ((gcsCOMPLETION_SIGNAL_PTR) ((gctSIZE_T)1))
+
+/******************************************************************************\
+***************************** gckVGINTERRUPT Object ******************************
+\******************************************************************************/
+
+typedef struct _gckVGINTERRUPT * gckVGINTERRUPT;
+
+typedef gceSTATUS (* gctINTERRUPT_HANDLER)(
+    IN gckVGKERNEL Kernel
+    );
+
+gceSTATUS
+gckVGINTERRUPT_Construct(
+    IN gckVGKERNEL Kernel,
+    OUT gckVGINTERRUPT * Interrupt
+    );
+
+gceSTATUS
+gckVGINTERRUPT_Destroy(
+    IN gckVGINTERRUPT Interrupt
+    );
+
+gceSTATUS
+gckVGINTERRUPT_Enable(
+    IN gckVGINTERRUPT Interrupt,
+    IN OUT gctINT32_PTR Id,
+    IN gctINTERRUPT_HANDLER Handler
+    );
+
+gceSTATUS
+gckVGINTERRUPT_Disable(
+    IN gckVGINTERRUPT Interrupt,
+    IN gctINT32 Id
+    );
+
+#ifndef __QNXNTO__
+
+gceSTATUS
+gckVGINTERRUPT_Enque(
+    IN gckVGINTERRUPT Interrupt
+    );
+
+#else
+
+gceSTATUS
+gckVGINTERRUPT_Enque(
+    IN gckVGINTERRUPT Interrupt,
+    OUT gckOS *Os,
+    OUT gctSEMAPHORE *Semaphore
+    );
+
+#endif
+
+gceSTATUS
+gckVGINTERRUPT_DumpState(
+    IN gckVGINTERRUPT Interrupt
+    );
+
+
+/******************************************************************************\
+******************************* gckVGCOMMAND Object *******************************
+\******************************************************************************/
+
+typedef struct _gckVGCOMMAND *      gckVGCOMMAND;
+
+/* Construct a new gckVGCOMMAND object. */
+gceSTATUS
+gckVGCOMMAND_Construct(
+    IN gckVGKERNEL Kernel,
+    IN gctUINT TaskGranularity,
+    IN gctUINT QueueSize,
+    OUT gckVGCOMMAND * Command
+    );
+
+/* Destroy an gckVGCOMMAND object. */
+gceSTATUS
+gckVGCOMMAND_Destroy(
+    IN gckVGCOMMAND Command
+    );
+
+/* Query command buffer attributes. */
+gceSTATUS
+gckVGCOMMAND_QueryCommandBuffer(
+    IN gckVGCOMMAND Command,
+    OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+    );
+
+/* Allocate a command queue. */
+gceSTATUS
+gckVGCOMMAND_Allocate(
+    IN gckVGCOMMAND Command,
+    IN gctSIZE_T Size,
+    OUT gcsCMDBUFFER_PTR * CommandBuffer,
+    OUT gctPOINTER * Data
+    );
+
+/* Release memory held by the command queue. */
+gceSTATUS
+gckVGCOMMAND_Free(
+    IN gckVGCOMMAND Command,
+    IN gcsCMDBUFFER_PTR CommandBuffer
+    );
+
+/* Schedule the command queue for execution. */
+gceSTATUS
+gckVGCOMMAND_Execute(
+    IN gckVGCOMMAND Command,
+    IN gcsCMDBUFFER_PTR CommandBuffer
+    );
+
+/* Commit a buffer to the command queue. */
+gceSTATUS
+gckVGCOMMAND_Commit(
+    IN gckVGCOMMAND Command,
+    IN gcsVGCONTEXT_PTR Context,
+    IN gcsVGCMDQUEUE_PTR Queue,
+    IN gctUINT EntryCount,
+    IN gcsTASK_MASTER_TABLE_PTR TaskTable
+    );
+
+/******************************************************************************\
+********************************* gckVGMMU Object ********************************
+\******************************************************************************/
+
+typedef struct _gckVGMMU *          gckVGMMU;
+
+/* Construct a new gckVGMMU object. */
+gceSTATUS
+gckVGMMU_Construct(
+    IN gckVGKERNEL Kernel,
+    IN gctUINT32 MmuSize,
+    OUT gckVGMMU * Mmu
+    );
+
+/* Destroy an gckVGMMU object. */
+gceSTATUS
+gckVGMMU_Destroy(
+    IN gckVGMMU Mmu
+    );
+
+/* Allocate pages inside the MMU. */
+gceSTATUS
+gckVGMMU_AllocatePages(
+    IN gckVGMMU Mmu,
+    IN gctSIZE_T PageCount,
+    OUT gctPOINTER * PageTable,
+    OUT gctUINT32 * Address
+    );
+
+/* Remove a page table from the MMU. */
+gceSTATUS
+gckVGMMU_FreePages(
+    IN gckVGMMU Mmu,
+    IN gctPOINTER PageTable,
+    IN gctSIZE_T PageCount
+    );
+
+/* Set the MMU page with info. */
+gceSTATUS
+gckVGMMU_SetPage(
+   IN gckVGMMU Mmu,
+   IN gctUINT32 PageAddress,
+   IN gctUINT32 *PageEntry
+   );
+
+/* Flush MMU */
+gceSTATUS
+gckVGMMU_Flush(
+   IN gckVGMMU Mmu
+   );
+
+#endif /* gcdENABLE_VG */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __gc_hal_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_base_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_base_shared.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_base_shared_h_
+#define __gc_hal_base_shared_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define gcdEXTERNAL_MEMORY_NAME_MAX 32
+#define gcdEXTERNAL_MEMORY_DATA_MAX 8
+
+typedef struct _gcsEXTERNAL_MEMORY_INFO
+{
+    /* Name of allocator used to attach this memory. */
+    gctCHAR                allocatorName[gcdEXTERNAL_MEMORY_NAME_MAX];
+
+    /* User defined data which will be passed to allocator. */
+    gctUINT32              userData[gcdEXTERNAL_MEMORY_DATA_MAX];
+}
+gcsEXTERNAL_MEMORY_INFO;
+
+#define gcdBINARY_TRACE_MESSAGE_SIZE 240
+
+typedef struct _gcsBINARY_TRACE_MESSAGE * gcsBINARY_TRACE_MESSAGE_PTR;
+typedef struct _gcsBINARY_TRACE_MESSAGE
+{
+    gctUINT32   signature;
+    gctUINT32   pid;
+    gctUINT32   tid;
+    gctUINT32   line;
+    gctUINT32   numArguments;
+    gctUINT8    payload;
+}
+gcsBINARY_TRACE_MESSAGE;
+
+/* gcsOBJECT object defintinon. */
+typedef struct _gcsOBJECT
+{
+    /* Type of an object. */
+    gceOBJECT_TYPE              type;
+}
+gcsOBJECT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_base_shared_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_driver_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_driver_shared.h
@@ -0,0 +1,1298 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_driver_shared_h_
+#define __gc_hal_driver_shared_h_
+
+#include "gc_hal_enum_shared.h"
+#include "gc_hal_types_shared.h"
+
+#if gcdENABLE_VG
+#include "gc_hal_driver_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The number of context buffers per user. */
+#if gcdCAPTURE_ONLY_MODE
+#define gcdCONTEXT_BUFFER_COUNT 1
+#else
+#define gcdCONTEXT_BUFFER_COUNT 2
+#endif
+
+/******************************************************************************\
+******************************* I/O Control Codes ******************************
+\******************************************************************************/
+
+#define gcvHAL_CLASS                    "galcore"
+#define IOCTL_GCHAL_INTERFACE           30000
+#define IOCTL_GCHAL_PROFILER_INTERFACE  30001
+#define IOCTL_GCHAL_TERMINATE           30002
+
+#undef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+/******************************************************************************\
+****************************** Interface Structure *****************************
+\******************************************************************************/
+
+#define gcdMAX_PROFILE_FILE_NAME        128
+#define gcdMAX_FLAT_MAPPING_COUNT       16
+
+/* gcvHAL_CHIP_INFO */
+typedef struct _gcsHAL_CHIP_INFO
+{
+    /* Chip count. */
+    OUT gctINT32                count;
+
+    /* Chip types. */
+    OUT gceHARDWARE_TYPE        types[gcdCHIP_COUNT];
+
+    /* Chip IDs. */
+    OUT gctUINT32               ids[gcvCORE_COUNT];
+
+    OUT gctUINT32               coreIndexs[gcvCORE_COUNT];
+}
+gcsHAL_CHIP_INFO;
+
+/* gcvHAL_VERSION */
+typedef struct _gcsHAL_VERSION
+{
+    /* version: <major>.<minor>.<patch>. */
+    OUT gctINT32                major;
+    OUT gctINT32                minor;
+    OUT gctINT32                patch;
+
+    /* Build version. */
+    OUT gctUINT32               build;
+}
+gcsHAL_VERSION;
+
+/* gcvHAL_SET_TIMEOUT. */
+typedef struct _gcsHAL_SET_TIMEOUT
+{
+    gctUINT32                   timeOut;
+}
+gcsHAL_SET_TIMEOUT;
+
+/* gcvHAL_QUERY_VIDEO_MEMORY */
+typedef struct _gcsHAL_QUERY_VIDEO_MEMORY
+{
+    /* Physical memory address of internal memory. Just a name. */
+    OUT gctUINT32               internalPhysName;
+    /* Size in bytes of internal memory. */
+    OUT gctUINT64               internalSize;
+
+    /* Physical memory address of external memory. Just a name. */
+    OUT gctUINT32               externalPhysName;
+    /* Size in bytes of external memory.*/
+    OUT gctUINT64               externalSize;
+
+    /* Physical memory address of contiguous memory. Just a name. */
+    OUT gctUINT32               contiguousPhysName;
+    /* Size in bytes of contiguous memory.*/
+    OUT gctUINT64               contiguousSize;
+}
+gcsHAL_QUERY_VIDEO_MEMORY;
+
+/* gcvHAL_QUERY_CHIP_IDENTITY */
+typedef struct _gcsHAL_QUERY_CHIP_IDENTITY * gcsHAL_QUERY_CHIP_IDENTITY_PTR;
+typedef struct _gcsHAL_QUERY_CHIP_IDENTITY
+{
+
+    /* Chip model. */
+    gceCHIPMODEL                chipModel;
+
+    /* Revision value.*/
+    gctUINT32                   chipRevision;
+
+    /* Chip date. */
+    gctUINT32                   chipDate;
+
+    /* Supported feature fields. */
+    gctUINT32                   chipFeatures;
+
+    /* Supported minor feature fields. */
+    gctUINT32                   chipMinorFeatures;
+
+    /* Supported minor feature 1 fields. */
+    gctUINT32                   chipMinorFeatures1;
+
+    /* Supported minor feature 2 fields. */
+    gctUINT32                   chipMinorFeatures2;
+
+    /* Supported minor feature 3 fields. */
+    gctUINT32                   chipMinorFeatures3;
+
+    /* Supported minor feature 4 fields. */
+    gctUINT32                   chipMinorFeatures4;
+
+    /* Supported minor feature 5 fields. */
+    gctUINT32                   chipMinorFeatures5;
+
+    /* Supported minor feature 6 fields. */
+    gctUINT32                   chipMinorFeatures6;
+
+    /* Number of streams supported. */
+    gctUINT32                   streamCount;
+
+    /* Number of pixel pipes. */
+    gctUINT32                   pixelPipes;
+
+    /* Number of resolve pipes. */
+    gctUINT32                   resolvePipes;
+
+    /* Number of instructions. */
+    gctUINT32                   instructionCount;
+
+    /* Number of constants. */
+    gctUINT32                   numConstants;
+
+    /* Number of varyings */
+    gctUINT32                   varyingsCount;
+
+    /* Number of 3D GPUs */
+    gctUINT32                   gpuCoreCount;
+
+    /* Physical mask of all AVAILABLE clusters in core.*/
+    gctUINT32                   clusterAvailMask;
+
+    /* Product ID */
+    gctUINT32                   productID;
+
+    /* Special chip flag bits */
+    gceCHIP_FLAG                chipFlags;
+
+    /* ECO ID. */
+    gctUINT32                   ecoID;
+
+    /* Customer ID. */
+    gctUINT32                   customerID;
+
+    /* CPU view physical address and size of SRAMs. */
+    gctUINT64                   sRAMBases[gcvSRAM_INTER_COUNT];
+    gctUINT32                   sRAMSizes[gcvSRAM_INTER_COUNT];
+
+    gctUINT64                   platformFlagBits;
+}
+gcsHAL_QUERY_CHIP_IDENTITY;
+
+/* gcvHAL_QUERY_CHIP_OPTION. */
+typedef struct _gcsHAL_QUERY_CHIP_OPTIONS * gcsHAL_QUERY_CHIP_OPTIONS_PTR;
+typedef struct _gcsHAL_QUERY_CHIP_OPTIONS
+{
+    gctBOOL                     gpuProfiler;
+    gctBOOL                     allowFastClear;
+    gctBOOL                     powerManagement;
+    /* Whether use new MMU. It is meaningless
+    ** for old MMU since old MMU is always enabled.
+    */
+    gctBOOL                     enableMMU;
+    gceCOMPRESSION_OPTION       allowCompression;
+    gctBOOL                     smallBatch;
+    gctUINT32                   uscL1CacheRatio;
+    gctUINT32                   uscAttribCacheRatio;
+    gctUINT32                   userClusterMask;
+
+    /* Internal SRAM. */
+    gctUINT32                   sRAMGPUVirtAddrs[gcvSRAM_INTER_COUNT];
+    gctUINT32                   sRAMSizes[gcvSRAM_INTER_COUNT];
+    gctUINT32                   sRAMCount;
+
+    /* External SRAM. */
+    gctPHYS_ADDR_T              extSRAMCPUPhysAddrs[gcvSRAM_EXT_COUNT];
+    gctPHYS_ADDR_T              extSRAMGPUPhysAddrs[gcvSRAM_EXT_COUNT];
+    gctUINT32                   extSRAMGPUVirtAddrs[gcvSRAM_EXT_COUNT];
+    gctUINT32                   extSRAMGPUPhysNames[gcvSRAM_EXT_COUNT];
+    gctUINT32                   extSRAMSizes[gcvSRAM_EXT_COUNT];
+    gctUINT32                   extSRAMCount;
+
+    gceSECURE_MODE              secureMode;
+    gctBOOL                     enableNNTPParallel;
+    gctUINT                     enableSwtilingPhase1;
+
+    gctBOOL                     hasShader;
+}
+gcsHAL_QUERY_CHIP_OPTIONS;
+
+/* gcvHAL_QUERY_CHIP_FREQUENCY. */
+typedef struct _gcsHAL_QUERY_CHIP_FREQUENCY * gcsHAL_QUERY_CHIP_FREQUENCY_PTR;
+typedef struct _gcsHAL_QUERY_CHIP_FREQUENCY
+{
+    OUT gctUINT32               mcClk;
+    OUT gctUINT32               shClk;
+}
+gcsHAL_QUERY_CHIP_FREQUENCY;
+
+/* Obsolete for userpace. */
+/* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */
+typedef struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY
+{
+    /* Allocation flags. */
+    IN gctUINT32                flags;
+
+    /* Number of bytes to allocate. */
+    IN OUT gctUINT64            bytes;
+
+    /* Physical address of allocation. Just a name. */
+    OUT gctUINT32               physName;
+
+    /* Logical address of allocation. */
+    OUT gctUINT64               logical;
+}
+gcsHAL_ALLOCATE_NON_PAGED_MEMORY;
+
+/* Obsolete for userpace. */
+/* gcvHAL_FREE_NON_PAGED_MEMORY */
+typedef struct _gcsHAL_FREE_NON_PAGED_MEMORY
+{
+    /* Number of bytes allocated. */
+    IN gctUINT64                bytes;
+
+    /* Physical address of allocation. Just a name. */
+    IN gctUINT32                physName;
+
+    /* Logical address of allocation. */
+    IN gctUINT64                logical;
+}
+gcsHAL_FREE_NON_PAGED_MEMORY;
+
+/* Video memory allocation. */
+/* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */
+typedef struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY
+{
+    /* Number of bytes to allocate. */
+    IN OUT gctUINT64            bytes;
+
+    /* Buffer alignment. */
+    IN gctUINT32                alignment;
+
+    /* Type of allocation, see gceVIDMEM_TYPE. */
+    IN gctUINT32                type;
+
+    /* Flag of allocation. */
+    IN gctUINT32                flag;
+
+    /* Memory pool to allocate from. */
+    IN OUT gctUINT32            pool;
+
+    /* Internal SRAM index. */
+    IN gctINT32                 sRAMIndex;
+    /* External SRAM index. */
+    IN gctINT32                 extSRAMIndex;
+
+    /* Allocated video memory. */
+    OUT gctUINT32               node;
+}
+gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY;
+
+typedef struct _gcsUSER_MEMORY_DESC
+{
+    /* Import flag. */
+    gctUINT32                  flag;
+
+    /* gcvALLOC_FLAG_DMABUF */
+    gctUINT32                  handle;
+    gctUINT64                  dmabuf;
+
+    /* gcvALLOC_FLAG_USERMEMORY */
+    gctUINT64                  logical;
+    gctUINT64                  physical;
+    gctUINT32                  size;
+
+    /* gcvALLOC_FLAG_EXTERNAL_MEMORY */
+    gcsEXTERNAL_MEMORY_INFO    externalMemoryInfo;
+}
+gcsUSER_MEMORY_DESC;
+
+/* gcvHAL_WRAP_USER_MEMORY. */
+typedef struct _gcsHAL_WRAP_USER_MEMORY
+{
+    /* Description of user memory. */
+    IN gcsUSER_MEMORY_DESC      desc;
+
+    /* Video memory allocation type. */
+    IN gctUINT32                type;
+
+    /* Output video mmory node. */
+    OUT gctUINT32               node;
+
+    /* size of the node in bytes */
+    OUT gctUINT64               bytes;
+}
+gcsHAL_WRAP_USER_MEMORY;
+
+/* gcvHAL_RELEASE_VIDEO_MEMORY */
+typedef struct _gcsHAL_RELEASE_VIDEO_MEMORY
+{
+    /* Allocated video memory. */
+    IN gctUINT32                node;
+
+#ifdef __QNXNTO__
+    /* Mapped logical address to unmap in user space. */
+    OUT gctUINT64               memory;
+
+    /* Number of bytes to allocated. */
+    OUT gctUINT64               bytes;
+#endif
+}
+gcsHAL_RELEASE_VIDEO_MEMORY;
+
+/* gcvHAL_LOCK_VIDEO_MEMORY */
+typedef struct _gcsHAL_LOCK_VIDEO_MEMORY
+{
+    /* Allocated video memory. */
+    IN gctUINT32                node;
+
+    /* Cache configuration. */
+    /* Only gcvPOOL_VIRTUAL can be configured */
+    IN gctBOOL                  cacheable;
+
+    /* Hardware specific address. */
+    OUT gctUINT32               address;
+
+    /* Mapped logical address. */
+    OUT gctUINT64               memory;
+
+    /* Customer priviate handle*/
+    OUT gctUINT32               gid;
+
+    /* Bus address of a contiguous video node. */
+    OUT gctUINT64               physicalAddress;
+
+#if gcdCAPTURE_ONLY_MODE
+    IN gctBOOL                  queryCapSize;
+    IN gctPOINTER               captureLogical;
+    OUT gctSIZE_T               captureSize;
+#endif
+}
+gcsHAL_LOCK_VIDEO_MEMORY;
+
+/* gcvHAL_UNLOCK_VIDEO_MEMORY */
+typedef struct _gcsHAL_UNLOCK_VIDEO_MEMORY
+{
+    /* Allocated video memory. */
+    IN gctUINT64                node;
+
+    /* Video memory allocation type. */
+    IN gctUINT32                type;
+
+    /* Pool of the unlock node */
+    OUT gctUINT32               pool;
+
+    /* Bytes of the unlock node */
+    OUT gctUINT64               bytes;
+
+    /* Flag to unlock surface asynchroneously. */
+    IN OUT gctBOOL              asynchroneous;
+
+#if gcdCAPTURE_ONLY_MODE
+    OUT gctPOINTER              captureLogical;
+#endif
+}
+gcsHAL_UNLOCK_VIDEO_MEMORY;
+
+/* gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY: */
+typedef struct _gcsHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY
+{
+    /* Allocated video memory. */
+    IN gctUINT32                node;
+
+    /* Video memory allocation type. */
+    IN gctUINT32                type;
+}
+gcsHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY;
+
+/* gcvHAL_EXPORT_VIDEO_MEMORY. */
+typedef struct _gcsHAL_EXPORT_VIDEO_MEMORY
+{
+    /* Allocated video memory. */
+    IN gctUINT32                node;
+
+    /* Export flags */
+    IN gctUINT32                flags;
+
+    /* Exported dma_buf fd */
+    OUT gctINT32                fd;
+}
+gcsHAL_EXPORT_VIDEO_MEMORY;
+
+/* gcvHAL_NAME_VIDEO_MEMORY. */
+typedef struct _gcsHAL_NAME_VIDEO_MEMORY
+{
+    IN gctUINT32                handle;
+    OUT gctUINT32               name;
+}
+gcsHAL_NAME_VIDEO_MEMORY;
+
+/* gcvHAL_IMPORT_VIDEO_MEMORY. */
+typedef struct _gcsHAL_IMPORT_VIDEO_MEMORY
+{
+    IN gctUINT32                name;
+    OUT gctUINT32               handle;
+}
+gcsHAL_IMPORT_VIDEO_MEMORY;
+
+/* gcvHAL_MAP_MEMORY */
+typedef struct _gcsHAL_MAP_MEMORY
+{
+    /* Physical memory address to map. Just a name on Linux/Qnx. */
+    IN gctUINT32                physName;
+
+    /* Number of bytes in physical memory to map. */
+    IN gctUINT64                bytes;
+
+    /* Address of mapped memory. */
+    OUT gctUINT64               logical;
+}
+gcsHAL_MAP_MEMORY;
+
+/* gcvHAL_UNMAP_MEMORY */
+typedef struct _gcsHAL_UNMAP_MEMORY
+{
+    /* Physical memory address to unmap. Just a name on Linux/Qnx. */
+    IN gctUINT32                physName;
+
+    /* Number of bytes in physical memory to unmap. */
+    IN gctUINT64                bytes;
+
+    /* Address of mapped memory to unmap. */
+    IN gctUINT64                logical;
+}
+gcsHAL_UNMAP_MEMORY;
+
+/* gcvHAL_CACHE */
+typedef struct _gcsHAL_CACHE
+{
+    IN gceCACHEOPERATION        operation;
+    IN gctUINT64                process;
+    IN gctUINT64                logical;
+    IN gctUINT64                bytes;
+    IN gctUINT32                node;
+}
+gcsHAL_CACHE;
+
+/* gcvHAL_ATTACH */
+typedef struct _gcsHAL_ATTACH
+{
+    /* Handle of context buffer object. */
+    OUT gctUINT32               context;
+
+    /* Maximum state in the buffer. */
+    OUT gctUINT64               maxState;
+
+    /* Number of states in the buffer. */
+    OUT gctUINT32               numStates;
+
+    /* Map context buffer to user or not. */
+    IN gctBOOL                  map;
+
+    /* Physical of context buffer. */
+    OUT gctUINT64               logicals[2];
+
+    /* Bytes of context buffer. */
+    OUT gctUINT32               bytes;
+
+#if gcdCAPTURE_ONLY_MODE
+    IN gctBOOL                  queryCapSize;
+    IN gctPOINTER               contextLogical[gcdCONTEXT_BUFFER_NUM];
+    OUT gctSIZE_T               captureSize;
+#endif
+}
+gcsHAL_ATTACH;
+
+/* gcvHAL_DETACH */
+typedef struct _gcsHAL_DETACH
+{
+    /* Context buffer object gckCONTEXT. Just a name. */
+    IN gctUINT32                context;
+}
+gcsHAL_DETACH;
+
+
+/* gcvHAL_EVENT_COMMIT. */
+typedef struct _gcsHAL_EVENT_COMMIT
+{
+    /* Event queue in gcsQUEUE. */
+    IN gctUINT64                queue;
+}
+gcsHAL_EVENT_COMMIT;
+
+typedef struct _gcsHAL_COMMAND_LOCATION
+{
+    gctUINT32                   priority;
+    gctUINT32                   channelId;
+
+    gctUINT32                   videoMemNode;
+
+    gctUINT32                   address;
+    gctUINT64                   logical;
+    gctUINT32                   startOffset;
+    /* size includes reservedHead and reservedTail. */
+    gctUINT32                   size;
+
+    gctUINT32                   reservedHead;
+    gctUINT32                   reservedTail;
+
+    /* Pointer to patch list. */
+    gctUINT64                   patchHead;
+
+    /*
+     * Location index of exit commands, ie where to put the chipEnable/link back
+     * commands in the reservedTail area.
+     * It's used in fully shared command buffer for multiple cores.
+     */
+    gctUINT32                   exitIndex;
+    gctUINT32                   entryPipe;
+    gctUINT32                   exitPipe;
+
+    /* struct _gcsHAL_COMMAND_LOCATION * next; */
+    gctUINT64                   next;
+
+#if gcdCAPTURE_ONLY_MODE
+    gctPOINTER                  contextLogical[gcdCONTEXT_BUFFER_NUM];
+#endif
+}
+gcsHAL_COMMAND_LOCATION;
+
+typedef struct _gcsHAL_SUBCOMMIT
+{
+    gctUINT32                   coreId;
+
+    /* user gcsSTATE_DELTA_PTR. */
+    gctUINT64                   delta;
+
+    /* Kernel gckCONTEXT. */
+    gctUINT64                   context;
+
+    /* Event queue in user gcsQUEUE *. */
+    gctUINT64                   queue;
+
+    /* Locate the commands. */
+    gcsHAL_COMMAND_LOCATION     commandBuffer;
+
+    /* struct _gcsHAL_SUBCOMMIT * next; */
+    gctUINT64                   next;
+}
+gcsHAL_SUBCOMMIT;
+
+/* gcvHAL_COMMIT */
+typedef struct _gcsHAL_COMMIT
+{
+    gcsHAL_SUBCOMMIT            subCommit;
+
+    gctBOOL                     shared;
+
+    gctBOOL                     contextSwitched;
+
+    /* Commit stamp of this commit. */
+    OUT gctUINT64               commitStamp;
+}
+gcsHAL_COMMIT;
+
+#if gcdENABLE_VG
+/* gcvHAL_COMMIT */
+typedef struct _gcsHAL_VGCOMMIT
+{
+    /* Context buffer. gcsVGCONTEXT_PTR */
+    IN gctUINT64                context;
+
+    /* Command queue. gcsVGCMDQUEUE_PTR */
+    IN gctUINT64                queue;
+
+    /* Number of entries in the queue. */
+    IN gctUINT32                entryCount;
+
+    /* Task table. gcsTASK_MASTER_TABLE_PTR */
+    IN gctUINT64                taskTable;
+}
+gcsHAL_VGCOMMIT;
+#endif
+
+typedef struct _gcsHAL_COMMIT_DONE
+{
+    IN gctUINT64                context;
+}
+gcsHAL_COMMIT_DONE;
+
+/* gcvHAL_USER_SIGNAL  */
+typedef struct _gcsHAL_USER_SIGNAL
+{
+    /* Command. */
+    gceUSER_SIGNAL_COMMAND_CODES command;
+
+    /* Signal ID. */
+    IN OUT gctINT32             id;
+
+    /* Reset mode. */
+    IN gctBOOL                  manualReset;
+
+    /* Wait timedout. */
+    IN gctUINT32                wait;
+
+    /* State. */
+    IN gctBOOL                  state;
+}
+gcsHAL_USER_SIGNAL;
+
+/* gcvHAL_SIGNAL. */
+typedef struct _gcsHAL_SIGNAL
+{
+    /* Signal handle to signal gctSIGNAL. */
+    IN gctUINT64                signal;
+
+    /* Reserved gctSIGNAL. */
+    IN gctUINT64                auxSignal;
+
+    /* Process owning the signal gctHANDLE. */
+    IN gctUINT64                process;
+
+#if defined(__QNXNTO__)
+    /* Client pulse side-channel connection ID. Set by client in gcoOS_CreateSignal. */
+    IN gctINT32                 coid;
+
+    /* Set by server. */
+    IN gctINT32                 rcvid;
+#endif
+    /* Event generated from where of pipeline */
+    IN gceKERNEL_WHERE          fromWhere;
+}
+gcsHAL_SIGNAL;
+
+/* gcvHAL_WRITE_DATA. */
+typedef struct _gcsHAL_WRITE_DATA
+{
+    /* Address to write data to. */
+    IN gctUINT32                address;
+
+    /* Data to write. */
+    IN gctUINT32                data;
+}
+gcsHAL_WRITE_DATA;
+
+/* gcvHAL_READ_REGISTER */
+typedef struct _gcsHAL_READ_REGISTER
+{
+    /* Logical address of memory to write data to. */
+    IN gctUINT32                address;
+
+    /* Data read. */
+    OUT gctUINT32               data;
+}
+gcsHAL_READ_REGISTER;
+
+/* gcvHAL_WRITE_REGISTER */
+typedef struct _gcsHAL_WRITE_REGISTER
+{
+    /* Logical address of memory to write data to. */
+    IN gctUINT32                address;
+
+    /* Data read. */
+    IN gctUINT32                data;
+}
+gcsHAL_WRITE_REGISTER;
+
+/* gcvHAL_READ_REGISTER_EX */
+typedef struct _gcsHAL_READ_REGISTER_EX
+{
+    /* Logical address of memory to write data to. */
+    IN gctUINT32                address;
+
+    IN gctUINT32                coreSelect;
+
+    /* Data read. */
+    OUT gctUINT32               data[4];
+}
+gcsHAL_READ_REGISTER_EX;
+
+/* gcvHAL_WRITE_REGISTER_EX */
+typedef struct _gcsHAL_WRITE_REGISTER_EX
+{
+    /* Logical address of memory to write data to. */
+    IN gctUINT32                address;
+
+    IN gctUINT32                coreSelect;
+
+    /* Data read. */
+    IN gctUINT32                data[4];
+}
+gcsHAL_WRITE_REGISTER_EX;
+
+#if VIVANTE_PROFILER
+/* gcvHAL_GET_PROFILE_SETTING */
+typedef struct _gcsHAL_GET_PROFILE_SETTING
+{
+    /* Enable profiling */
+    OUT gctBOOL                 enable;
+}
+gcsHAL_GET_PROFILE_SETTING;
+
+/* gcvHAL_SET_PROFILE_SETTING */
+typedef struct _gcsHAL_SET_PROFILE_SETTING
+{
+    /* Enable profiling */
+    IN gctBOOL                  enable;
+}
+gcsHAL_SET_PROFILE_SETTING;
+
+/* gcvHAL_READ_PROFILER_REGISTER_SETTING */
+typedef struct _gcsHAL_READ_PROFILER_REGISTER_SETTING
+{
+    /*Should Clear Register*/
+    IN gctBOOL                  bclear;
+}
+gcsHAL_READ_PROFILER_REGISTER_SETTING;
+
+typedef struct _gcsHAL_READ_ALL_PROFILE_REGISTERS_PART1
+{
+    /* Context buffer object gckCONTEXT. Just a name. */
+    IN gctUINT32                context;
+
+    /* Data read. */
+    OUT gcsPROFILER_COUNTERS_PART1 Counters;
+}
+gcsHAL_READ_ALL_PROFILE_REGISTERS_PART1;
+
+typedef struct _gcsHAL_READ_ALL_PROFILE_REGISTERS_PART2
+{
+    /* Context buffer object gckCONTEXT. Just a name. */
+    IN gctUINT32                context;
+
+    /* Data read. */
+    OUT gcsPROFILER_COUNTERS_PART2 Counters;
+}
+gcsHAL_READ_ALL_PROFILE_REGISTERS_PART2;
+
+/* gcvHAL_PROFILE_REGISTERS_2D */
+typedef struct _gcsHAL_PROFILE_REGISTERS_2D
+{
+    /* Data read in gcs2D_PROFILE. */
+    OUT gctUINT64               hwProfile2D;
+}
+gcsHAL_PROFILE_REGISTERS_2D;
+#endif
+
+/* gcvHAL_SET_POWER_MANAGEMENT_STATE */
+typedef struct _gcsHAL_SET_POWER_MANAGEMENT
+{
+    /* Data read. */
+    IN gceCHIPPOWERSTATE        state;
+}
+gcsHAL_SET_POWER_MANAGEMENT;
+
+/* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */
+typedef struct _gcsHAL_QUERY_POWER_MANAGEMENT
+{
+    /* Data read. */
+    OUT gceCHIPPOWERSTATE       state;
+
+    /* Idle query. */
+    OUT gctBOOL                 isIdle;
+}
+gcsHAL_QUERY_POWER_MANAGEMENT;
+
+/* gcvHAL_CONFIG_POWER_MANAGEMENT. */
+typedef struct _gcsHAL_CONFIG_POWER_MANAGEMENT
+{
+    IN gctBOOL                  enable;
+}
+gcsHAL_CONFIG_POWER_MANAGEMENT;
+
+typedef struct _gcsFLAT_MAPPING_RANGE
+{
+    gctUINT64 start;
+    gctUINT64 end;
+    gctUINT32 size;
+    gceFLATMAP_FLAG flag;
+}
+gcsFLAT_MAPPING_RANGE;
+
+/* gcvHAL_GET_BASE_ADDRESS */
+typedef struct _gcsHAL_GET_BASE_ADDRESS
+{
+    /* Physical memory address of internal memory. */
+    OUT gctUINT32               baseAddress;
+
+    OUT gctUINT32               flatMappingRangeCount;
+
+    OUT gcsFLAT_MAPPING_RANGE   flatMappingRanges[gcdMAX_FLAT_MAPPING_COUNT];
+}
+gcsHAL_GET_BASE_ADDRESS;
+
+typedef struct _gcsHAL_SET_DEBUG_LEVEL_ZONE
+{
+    IN gctUINT32                level;
+    IN gctUINT32                zones;
+    IN gctBOOL                  enable;
+}
+gcsHAL_SET_DEBUG_LEVEL_ZONE;
+
+/* gcvHAL_DEBUG_DUMP. */
+typedef struct _gcsHAL_DEBUG_DUMP
+{
+    /* gceDUMP_BUFFER_TYPE      type. */
+    IN gctUINT32                type;
+
+    IN gctUINT64                ptr;
+    IN gctUINT32                address;
+    IN gctUINT32                size;
+}
+gcsHAL_DEBUG_DUMP;
+
+
+/* gcvHAL_TIMESTAMP */
+typedef struct _gcsHAL_TIMESTAMP
+{
+    /* Timer select. */
+    IN gctUINT32                timer;
+
+    /* Timer request type (0-stop, 1-start, 2-send delta). */
+    IN gctUINT32                request;
+
+    /* Result of delta time in microseconds. */
+    OUT gctINT32                timeDelta;
+}
+gcsHAL_TIMESTAMP;
+
+/* gcvHAL_DATABASE */
+typedef struct _gcsHAL_DATABASE
+{
+    /* Set to gcvTRUE if you want to query a particular process ID.
+    ** Set to gcvFALSE to query the last detached process. */
+    IN gctBOOL                  validProcessID;
+
+    /* Process ID to query. */
+    IN gctUINT32                processID;
+
+    /* Information. */
+    OUT gcuDATABASE_INFO        vidMem;
+    OUT gcuDATABASE_INFO        nonPaged;
+    OUT gcuDATABASE_INFO        contiguous;
+    OUT gcuDATABASE_INFO        gpuIdle;
+
+    /* Detail information about video memory. */
+    OUT gcuDATABASE_INFO        vidMemPool[3];
+}
+gcsHAL_DATABASE;
+
+/* gcvHAL_GET_FRAME_INFO. */
+typedef struct _gcsHAL_GET_FRAME_INFO
+{
+    /* gcsHAL_FRAME_INFO* */
+    OUT gctUINT64     frameInfo;
+}
+gcsHAL_GET_FRAME_INFO;
+
+#if gcdENABLE_VG
+/* gcvHAL_QUERY_COMMAND_BUFFER */
+typedef struct _gcsHAL_QUERY_COMMAND_BUFFER
+{
+    /* Command buffer attributes. */
+    OUT gcsCOMMAND_BUFFER_INFO  information;
+}
+gcsHAL_QUERY_COMMAND_BUFFER;
+#endif
+
+typedef struct _gcsHAL_SET_FSCALE_VALUE
+{
+    IN gctUINT32                value;
+    IN gctUINT32                shValue;
+}
+gcsHAL_SET_FSCALE_VALUE;
+
+typedef struct _gcsHAL_GET_FSCALE_VALUE
+{
+    OUT gctUINT32               value;
+    OUT gctUINT32               minValue;
+    OUT gctUINT32               maxValue;
+}
+gcsHAL_GET_FSCALE_VALUE;
+
+/* gcvHAL_QUERY_RESET_TIME_STAMP. */
+typedef struct _gcsHAL_QUERY_RESET_TIME_STAMP
+{
+    OUT gctUINT64               timeStamp;
+    OUT gctUINT64               contextID;
+}
+gcsHAL_QUERY_RESET_TIME_STAMP;
+
+/* gcvHAL_CREATE_NATIVE_FENCE. */
+typedef struct _gcsHAL_CREATE_NATIVE_FENCE
+{
+    /* Signal id. */
+    IN gctUINT64                signal;
+
+    /* Native fence file descriptor. */
+    OUT gctINT32                fenceFD;
+
+}
+gcsHAL_CREATE_NATIVE_FENCE;
+
+/* gcvHAL_WAIT_NATIVE_FENCE. */
+typedef struct _gcsHAL_WAIT_NATIVE_FENCE
+{
+    /* Native fence file descriptor. */
+    IN gctINT32                 fenceFD;
+
+    /* Wait timeout. */
+    IN gctUINT32                timeout;
+}
+gcsHAL_WAIT_NATIVE_FENCE;
+
+/* gcvHAL_SHBUF. */
+typedef struct _gcsHAL_SHBUF
+{
+    gceSHBUF_COMMAND_CODES      command;
+
+    /* Shared buffer. */
+    IN OUT gctUINT64            id;
+
+    /* User data to be shared. */
+    IN gctUINT64                data;
+
+    /* Data size. */
+    IN OUT gctUINT32            bytes;
+}
+gcsHAL_SHBUF;
+
+/* gcvHAL_GET_GRAPHIC_BUFFER_FD. */
+/*
+ * Fd representation of android graphic buffer contents.
+ * Currently, it is only to reference video nodes, signal, etc to avoid being
+ * destroyed when trasfering across processes.
+ */
+typedef struct _gcsHAL_GET_GRAPHIC_BUFFER_FD
+{
+    /* Max 3 video nodes, node handle here. */
+    IN gctUINT32                node[3];
+
+    /* A shBuf. */
+    IN gctUINT64                shBuf;
+
+    /* A signal. */
+    IN gctUINT64                signal;
+
+    OUT gctINT32                fd;
+}
+gcsHAL_GET_GRAPHIC_BUFFER_FD;
+
+typedef struct _gcsHAL_VIDEO_MEMORY_METADATA
+{
+    /* Allocated video memory. */
+    IN gctUINT32            node;
+
+    IN gctUINT32            readback;
+
+    INOUT gctINT32          ts_fd;
+    INOUT gctUINT32         fc_enabled;
+    INOUT gctUINT32         fc_value;
+    INOUT gctUINT32         fc_value_upper;
+
+    INOUT gctUINT32         compressed;
+    INOUT gctUINT32         compress_format;
+}
+gcsHAL_VIDEO_MEMORY_METADATA;
+
+/* gcvHAL_GET_VIDEO_MEMORY_FD. */
+typedef struct _gcsHAL_GET_VIDEO_MEMORY_FD
+{
+    IN gctUINT32                handle;
+    OUT gctINT32                fd;
+}
+gcsHAL_GET_VIDEO_MEMORY_FD;
+
+/* gcvHAL_DESTROY_MMU. */
+typedef struct _gcsHAL_DESTROY_MMU
+{
+    /* Mmu object. */
+    IN gctUINT64                mmu;
+}
+gcsHAL_DESTROY_MMU;
+
+/* gcvHAL_WAIT_FENCE. */
+typedef struct _gcsHAL_WAIT_FENCE
+{
+    IN gctUINT32                handle;
+    IN gctUINT32                timeOut;
+}
+gcsHAL_WAIT_FENCE;
+
+/* gcvHAL_DEVICE_MUTEX: */
+typedef struct _gcsHAL_DEVICE_MUTEX
+{
+    /* Lock or Release device mutex. */
+    gctBOOL                     isMutexLocked;
+}
+gcsHAL_DEVICE_MUTEX;
+
+
+#if gcdDEC_ENABLE_AHB
+/* gcvHAL_DEC300_READ. */
+typedef struct _gcsHAL_DEC300_READ
+{
+    gctUINT32                   enable;
+    gctUINT32                   readId;
+    gctUINT32                   format;
+    gctUINT32                   strides[3];
+    gctUINT32                   is3D;
+    gctUINT32                   isMSAA;
+    gctUINT32                   clearValue;
+    gctUINT32                   isTPC;
+    gctUINT32                   isTPCCompressed;
+    gctUINT32                   surfAddrs[3];
+    gctUINT32                   tileAddrs[3];
+}
+DEC300Read;
+
+/* gcvHAL_DEC300_WRITE. */
+typedef struct _gcsHAL_DEC300_WRITE
+{
+    gctUINT32                   enable;
+    gctUINT32                   readId;
+    gctUINT32                   writeId;
+    gctUINT32                   format;
+    gctUINT32                   surfAddr;
+    gctUINT32                   tileAddr;
+}
+DEC300Write;
+
+/* gcvHAL_DEC300_FLUSH. */
+typedef struct _gcsHAL_DEC300_FLUSH
+{
+    IN gctUINT8                 useless;
+}
+DEC300Flush;
+
+/* gcvHAL_DEC300_FLUSH_WAIT. */
+typedef struct _gcsHAL_DEC300_FLUSH_WAIT
+{
+    IN gctUINT32                done;
+}
+DEC300FlushWait;
+#endif
+
+
+typedef struct _gcsHAL_INTERFACE
+{
+    /* Command code. */
+    gceHAL_COMMAND_CODES        command;
+
+    /* Hardware type. */
+    gceHARDWARE_TYPE            hardwareType;
+
+    /* Core index for current hardware type. */
+    gctUINT32                   coreIndex;
+
+    /* Status value. */
+    gceSTATUS                   status;
+
+    /* Engine */
+    gceENGINE                   engine;
+
+    /* Ignore information from TSL when doing IO control */
+    gctBOOL                     ignoreTLS;
+
+    /* The mutext already acquired */
+    IN gctBOOL                  commitMutex;
+
+    /* Union of command structures. */
+    union _u
+    {
+        gcsHAL_CHIP_INFO                    ChipInfo;
+        gcsHAL_VERSION                      Version;
+        gcsHAL_SET_TIMEOUT                  SetTimeOut;
+
+        gcsHAL_QUERY_VIDEO_MEMORY           QueryVideoMemory;
+        gcsHAL_QUERY_CHIP_IDENTITY          QueryChipIdentity;
+        gcsHAL_QUERY_CHIP_OPTIONS           QueryChipOptions;
+        gcsHAL_QUERY_CHIP_FREQUENCY         QueryChipFrequency;
+
+        gcsHAL_ALLOCATE_NON_PAGED_MEMORY    AllocateNonPagedMemory;
+        gcsHAL_FREE_NON_PAGED_MEMORY        FreeNonPagedMemory;
+
+        gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY AllocateLinearVideoMemory;
+        gcsHAL_WRAP_USER_MEMORY             WrapUserMemory;
+        gcsHAL_RELEASE_VIDEO_MEMORY         ReleaseVideoMemory;
+
+        gcsHAL_LOCK_VIDEO_MEMORY            LockVideoMemory;
+        gcsHAL_UNLOCK_VIDEO_MEMORY          UnlockVideoMemory;
+        gcsHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY BottomHalfUnlockVideoMemory;
+
+        gcsHAL_EXPORT_VIDEO_MEMORY          ExportVideoMemory;
+        gcsHAL_NAME_VIDEO_MEMORY            NameVideoMemory;
+        gcsHAL_IMPORT_VIDEO_MEMORY          ImportVideoMemory;
+
+        gcsHAL_MAP_MEMORY                   MapMemory;
+        gcsHAL_UNMAP_MEMORY                 UnmapMemory;
+
+        gcsHAL_CACHE                        Cache;
+
+        gcsHAL_ATTACH                       Attach;
+        gcsHAL_DETACH                       Detach;
+
+        gcsHAL_EVENT_COMMIT                 Event;
+        gcsHAL_COMMIT                       Commit;
+#if gcdENABLE_VG
+        gcsHAL_VGCOMMIT                     VGCommit;
+#endif
+        gcsHAL_COMMIT_DONE                  CommitDone;
+
+        gcsHAL_USER_SIGNAL                  UserSignal;
+        gcsHAL_SIGNAL                       Signal;
+
+        gcsHAL_WRITE_DATA                   WriteData;
+        gcsHAL_READ_REGISTER                ReadRegisterData;
+        gcsHAL_WRITE_REGISTER               WriteRegisterData;
+        gcsHAL_READ_REGISTER_EX             ReadRegisterDataEx;
+        gcsHAL_WRITE_REGISTER_EX            WriteRegisterDataEx;
+
+        gcsHAL_SET_POWER_MANAGEMENT         SetPowerManagement;
+        gcsHAL_QUERY_POWER_MANAGEMENT       QueryPowerManagement;
+        gcsHAL_CONFIG_POWER_MANAGEMENT      ConfigPowerManagement;
+
+        gcsHAL_GET_BASE_ADDRESS             GetBaseAddress;
+
+        gcsHAL_SET_DEBUG_LEVEL_ZONE         DebugLevelZone;
+        gcsHAL_DEBUG_DUMP                   DebugDump;
+
+        gcsHAL_TIMESTAMP                    TimeStamp;
+        gcsHAL_DATABASE                     Database;
+
+        gcsHAL_GET_FRAME_INFO               GetFrameInfo;
+
+#if gcdENABLE_VG
+        gcsHAL_QUERY_COMMAND_BUFFER         QueryCommandBuffer;
+#endif
+
+        /* gcsHAL_DUMP_GPU_STATE */
+        /* gcsHAL_DUMP_EVENT */
+
+        gcsHAL_SET_FSCALE_VALUE             SetFscaleValue;
+        gcsHAL_GET_FSCALE_VALUE             GetFscaleValue;
+
+        gcsHAL_QUERY_RESET_TIME_STAMP       QueryResetTimeStamp;
+
+        gcsHAL_CREATE_NATIVE_FENCE          CreateNativeFence;
+        gcsHAL_WAIT_NATIVE_FENCE            WaitNativeFence;
+        gcsHAL_SHBUF                        ShBuf;
+        gcsHAL_GET_GRAPHIC_BUFFER_FD        GetGraphicBufferFd;
+        gcsHAL_VIDEO_MEMORY_METADATA        SetVidMemMetadata;
+        gcsHAL_GET_VIDEO_MEMORY_FD          GetVideoMemoryFd;
+
+        gcsHAL_DESTROY_MMU                  DestroyMmu;
+
+        gcsHAL_WAIT_FENCE                   WaitFence;
+
+        /* gcvHAL_DEVICE_MUTEX: */
+        gcsHAL_DEVICE_MUTEX                 DeviceMutex;
+
+
+#if gcdDEC_ENABLE_AHB
+        gcsHAL_DEC300_READ                  DEC300Read;
+        gcsHAL_DEC300_WRITE                 DEC300Write;
+        gcsHAL_DEC300_FLUSH                 DEC300Flush;
+        gcsHAL_DEC300_FLUSH_WAIT            DEC300FlushWait;
+#endif
+    }
+    u;
+}
+gcsHAL_INTERFACE;
+
+#if VIVANTE_PROFILER
+typedef struct _gcsHAL_PROFILER_INTERFACE
+{
+    /* Command code. */
+    gceHAL_COMMAND_CODES        command;
+
+    /* Hardware type. */
+    gceHARDWARE_TYPE            hardwareType;
+
+    /* Core index for current hardware type. */
+    gctUINT32                   coreIndex;
+
+    /* Status value. */
+    gceSTATUS                   status;
+
+    /* Engine */
+    gceENGINE                   engine;
+
+    /* Ignore information from TSL when doing IO control */
+    gctBOOL                     ignoreTLS;
+
+    /* The mutext already acquired */
+    IN gctBOOL                  commitMutex;
+
+    /* Union of command structures. */
+    union profiler_u
+    {
+        gcsHAL_GET_PROFILE_SETTING              GetProfileSetting;
+        gcsHAL_SET_PROFILE_SETTING              SetProfileSetting;
+        gcsHAL_READ_PROFILER_REGISTER_SETTING   SetProfilerRegisterClear;
+        gcsHAL_READ_ALL_PROFILE_REGISTERS_PART1 RegisterProfileData_part1;
+        gcsHAL_READ_ALL_PROFILE_REGISTERS_PART2 RegisterProfileData_part2;
+        gcsHAL_PROFILE_REGISTERS_2D             RegisterProfileData2D;
+    }
+    u;
+}
+gcsHAL_PROFILER_INTERFACE;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_driver_shared_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_driver_vg_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_driver_vg_shared.h
@@ -0,0 +1,264 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_driver_vg_shared_h_
+#define __gc_hal_driver_vg_shared_h_
+
+#include "gc_hal_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+******************************* I/O Control Codes ******************************
+\******************************************************************************/
+
+#define gcvHAL_CLASS            "galcore"
+#define IOCTL_GCHAL_INTERFACE   30000
+
+/******************************************************************************\
+********************* Command buffer information structure. ********************
+\******************************************************************************/
+
+typedef struct _gcsCOMMAND_BUFFER_INFO * gcsCOMMAND_BUFFER_INFO_PTR;
+typedef struct _gcsCOMMAND_BUFFER_INFO
+{
+    /* FE command buffer interrupt ID. */
+    gctINT32                    feBufferInt;
+
+    /* TS overflow interrupt ID. */
+    gctINT32                    tsOverflowInt;
+
+    /* Alignment and mask for the buffer address. */
+    gctUINT                     addressMask;
+    gctUINT32                    addressAlignment;
+
+    /* Alignment for each command. */
+    gctUINT32                   commandAlignment;
+
+    /* Number of bytes required by the STATE command. */
+    gctUINT32                   stateCommandSize;
+
+    /* Number of bytes required by the RESTART command. */
+    gctUINT32                   restartCommandSize;
+
+    /* Number of bytes required by the FETCH command. */
+    gctUINT32                   fetchCommandSize;
+
+    /* Number of bytes required by the CALL command. */
+    gctUINT32                   callCommandSize;
+
+    /* Number of bytes required by the RETURN command. */
+    gctUINT32                   returnCommandSize;
+
+    /* Number of bytes required by the EVENT command. */
+    gctUINT32                   eventCommandSize;
+
+    /* Number of bytes required by the END command. */
+    gctUINT32                   endCommandSize;
+
+    /* Number of bytes reserved at the tail of a static command buffer. */
+    gctUINT32                   staticTailSize;
+
+    /* Number of bytes reserved at the tail of a dynamic command buffer. */
+    gctUINT32                   dynamicTailSize;
+}
+gcsCOMMAND_BUFFER_INFO;
+
+/******************************************************************************\
+******************************** Task Structures *******************************
+\******************************************************************************/
+
+typedef struct _gcsTASK_HEADER * gcsTASK_HEADER_PTR;
+typedef struct _gcsTASK_HEADER
+{
+    /* Task ID. */
+    IN gceTASK                  id;
+}
+gcsTASK_HEADER;
+
+typedef struct _gcsTASK_LINK * gcsTASK_LINK_PTR;
+typedef struct _gcsTASK_LINK
+{
+    /* Task ID (gcvTASK_LINK). */
+    IN gceTASK                  id;
+
+    /* Pointer to the next task container. */
+    IN gctPOINTER               cotainer;
+
+    /* Pointer to the next task from the next task container. */
+    IN gcsTASK_HEADER_PTR       task;
+}
+gcsTASK_LINK;
+
+typedef struct _gcsTASK_CLUSTER * gcsTASK_CLUSTER_PTR;
+typedef struct _gcsTASK_CLUSTER
+{
+    /* Task ID (gcvTASK_CLUSTER). */
+    IN gceTASK                  id;
+
+    /* Number of tasks in the cluster. */
+    IN gctUINT                  taskCount;
+}
+gcsTASK_CLUSTER;
+
+typedef struct _gcsTASK_INCREMENT * gcsTASK_INCREMENT_PTR;
+typedef struct _gcsTASK_INCREMENT
+{
+    /* Task ID (gcvTASK_INCREMENT). */
+    IN gceTASK                  id;
+
+    /* Address of the variable to increment. */
+    IN gctUINT32                address;
+}
+gcsTASK_INCREMENT;
+
+typedef struct _gcsTASK_DECREMENT * gcsTASK_DECREMENT_PTR;
+typedef struct _gcsTASK_DECREMENT
+{
+    /* Task ID (gcvTASK_DECREMENT). */
+    IN gceTASK                  id;
+
+    /* Address of the variable to decrement. */
+    IN gctUINT32                address;
+}
+gcsTASK_DECREMENT;
+
+typedef struct _gcsTASK_SIGNAL * gcsTASK_SIGNAL_PTR;
+typedef struct _gcsTASK_SIGNAL
+{
+    /* Task ID (gcvTASK_SIGNAL). */
+    IN gceTASK                  id;
+
+    /* Process owning the signal. */
+    IN gctHANDLE                process;
+
+    /* Signal handle to signal. */
+    IN gctSIGNAL                signal;
+
+#if defined(__QNXNTO__)
+    IN gctINT32                 coid;
+    IN gctINT32                 rcvid;
+#endif
+}
+gcsTASK_SIGNAL;
+
+typedef struct _gcsTASK_LOCKDOWN * gcsTASK_LOCKDOWN_PTR;
+typedef struct _gcsTASK_LOCKDOWN
+{
+    /* Task ID (gcvTASK_LOCKDOWN). */
+    IN gceTASK                  id;
+
+    /* Address of the user space counter. */
+    IN gctUINT32                userCounter;
+
+    /* Address of the kernel space counter. */
+    IN gctUINT32                kernelCounter;
+
+    /* Process owning the signal. */
+    IN gctHANDLE                process;
+
+    /* Signal handle to signal. */
+    IN gctSIGNAL                signal;
+}
+gcsTASK_LOCKDOWN;
+
+typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY * gcsTASK_UNLOCK_VIDEO_MEMORY_PTR;
+typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY
+{
+    /* Task ID (gcvTASK_UNLOCK_VIDEO_MEMORY). */
+    IN gceTASK                  id;
+
+    /* Allocated video memory. */
+    IN gctUINT64                node;
+}
+gcsTASK_UNLOCK_VIDEO_MEMORY;
+
+typedef struct _gcsTASK_FREE_VIDEO_MEMORY * gcsTASK_FREE_VIDEO_MEMORY_PTR;
+typedef struct _gcsTASK_FREE_VIDEO_MEMORY
+{
+    /* Task ID (gcvTASK_FREE_VIDEO_MEMORY). */
+    IN gceTASK                  id;
+
+    /* Allocated video memory. */
+    IN gctUINT32                node;
+}
+gcsTASK_FREE_VIDEO_MEMORY;
+
+typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY * gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR;
+typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY
+{
+    /* Task ID (gcvTASK_FREE_CONTIGUOUS_MEMORY). */
+    IN gceTASK                  id;
+
+    /* Number of bytes allocated. */
+    IN gctSIZE_T                bytes;
+
+    /* Physical address of allocation. */
+    IN gctPHYS_ADDR             physical;
+
+    /* Logical address of allocation. */
+    IN gctPOINTER               logical;
+}
+gcsTASK_FREE_CONTIGUOUS_MEMORY;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_driver_vg_shared_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_enum_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_enum_shared.h
@@ -0,0 +1,1922 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_shared_enum_h_
+#define __gc_hal_shared_enum_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Chip models. */
+typedef enum _gceCHIPMODEL
+{
+    gcv200  = 0x0200,
+    gcv300  = 0x0300,
+    gcv320  = 0x0320,
+    gcv328  = 0x0328,
+    gcv350  = 0x0350,
+    gcv355  = 0x0355,
+    gcv400  = 0x0400,
+    gcv410  = 0x0410,
+    gcv420  = 0x0420,
+    gcv428  = 0x0428,
+    gcv450  = 0x0450,
+    gcv500  = 0x0500,
+    gcv520  = 0x0520,
+    gcv530  = 0x0530,
+    gcv600  = 0x0600,
+    gcv620  = 0x0620,
+    gcv700  = 0x0700,
+    gcv800  = 0x0800,
+    gcv860  = 0x0860,
+    gcv880  = 0x0880,
+    gcv900  = 0x0900,
+    gcv1000 = 0x1000,
+    gcv1500 = 0x1500,
+    gcv2000 = 0x2000,
+    gcv2100 = 0x2100,
+    gcv2200 = 0x2200,
+    gcv2500 = 0x2500,
+    gcv3000 = 0x3000,
+    gcv4000 = 0x4000,
+    gcv5000 = 0x5000,
+    gcv5200 = 0x5200,
+    gcv6400 = 0x6400,
+    gcv7000 = 0x7000,
+    gcv7400 = 0x7400,
+    gcv8000 = 0x8000,
+}
+gceCHIPMODEL;
+
+/* Chip features. */
+typedef enum _gceFEATURE
+{
+    gcvFEATURE_PIPE_2D = 0,
+    gcvFEATURE_PIPE_3D,
+    gcvFEATURE_PIPE_VG,
+    gcvFEATURE_DC,
+    gcvFEATURE_HIGH_DYNAMIC_RANGE,
+    gcvFEATURE_MODULE_CG,
+    gcvFEATURE_MIN_AREA,
+    gcvFEATURE_BUFFER_INTERLEAVING,
+    gcvFEATURE_BYTE_WRITE_2D,
+    gcvFEATURE_ENDIANNESS_CONFIG,
+    gcvFEATURE_DUAL_RETURN_BUS,
+    gcvFEATURE_DEBUG_MODE,
+    gcvFEATURE_YUY2_RENDER_TARGET,
+    gcvFEATURE_FRAGMENT_PROCESSOR,
+    gcvFEATURE_2DPE20,
+    gcvFEATURE_FAST_CLEAR,
+    gcvFEATURE_YUV420_TILER,
+    gcvFEATURE_YUY2_AVERAGING,
+    gcvFEATURE_FLIP_Y,
+    gcvFEATURE_EARLY_Z,
+    gcvFEATURE_COMPRESSION,
+    gcvFEATURE_MSAA,
+    gcvFEATURE_SPECIAL_ANTI_ALIASING,
+    gcvFEATURE_SPECIAL_MSAA_LOD,
+    gcvFEATURE_422_TEXTURE_COMPRESSION,
+    gcvFEATURE_DXT_TEXTURE_COMPRESSION,
+    gcvFEATURE_ETC1_TEXTURE_COMPRESSION,
+    gcvFEATURE_CORRECT_TEXTURE_CONVERTER,
+    gcvFEATURE_TEXTURE_8K,
+    gcvFEATURE_SCALER,
+    gcvFEATURE_YUV420_SCALER,
+    gcvFEATURE_SHADER_HAS_W,
+    gcvFEATURE_SHADER_HAS_SIGN,
+    gcvFEATURE_SHADER_HAS_FLOOR,
+    gcvFEATURE_SHADER_HAS_CEIL,
+    gcvFEATURE_SHADER_HAS_SQRT,
+    gcvFEATURE_SHADER_HAS_TRIG,
+    gcvFEATURE_HZ,
+    gcvFEATURE_CORRECT_STENCIL,
+    gcvFEATURE_VG20,
+    gcvFEATURE_VG_FILTER,
+    gcvFEATURE_VG21,
+    gcvFEATURE_VG_DOUBLE_BUFFER,
+    gcvFEATURE_VG_RESOLUTION_8K,
+    gcvFEATURE_MC20,
+    gcvFEATURE_SUPER_TILED,
+    gcvFEATURE_FAST_CLEAR_FLUSH,
+    gcvFEATURE_2D_FILTERBLIT_PLUS_ALPHABLEND,
+    gcvFEATURE_2D_DITHER,
+    gcvFEATURE_2D_A8_TARGET,
+    gcvFEATURE_2D_A8_NO_ALPHA,
+    gcvFEATURE_2D_FILTERBLIT_FULLROTATION,
+    gcvFEATURE_2D_BITBLIT_FULLROTATION,
+    gcvFEATURE_WIDE_LINE,
+    gcvFEATURE_FC_FLUSH_STALL,
+    gcvFEATURE_FULL_DIRECTFB,
+    gcvFEATURE_HALF_FLOAT_PIPE,
+    gcvFEATURE_LINE_LOOP,
+    gcvFEATURE_2D_YUV_BLIT,
+    gcvFEATURE_2D_TILING,
+    gcvFEATURE_NON_POWER_OF_TWO,
+    gcvFEATURE_3D_TEXTURE,
+    gcvFEATURE_TEXTURE_ARRAY,
+    gcvFEATURE_TILE_FILLER,
+    gcvFEATURE_LOGIC_OP,
+    gcvFEATURE_MIXED_STREAMS,
+    gcvFEATURE_2D_MULTI_SOURCE_BLT,
+    gcvFEATURE_END_EVENT,
+    gcvFEATURE_VERTEX_10_10_10_2,
+    gcvFEATURE_TEXTURE_10_10_10_2,
+    gcvFEATURE_TEXTURE_ANISOTROPIC_FILTERING,
+    gcvFEATURE_TEXTURE_FLOAT_HALF_FLOAT,
+    gcvFEATURE_2D_ROTATION_STALL_FIX,
+    gcvFEATURE_2D_MULTI_SOURCE_BLT_EX,
+    gcvFEATURE_BUG_FIXES10,
+    gcvFEATURE_2D_MINOR_TILING,
+    gcvFEATURE_TEX_COMPRRESSION_SUPERTILED, /* Supertiled compressed textures are supported. */
+    gcvFEATURE_FAST_MSAA,
+    gcvFEATURE_BUG_FIXED_INDEXED_TRIANGLE_STRIP,
+    gcvFEATURE_TEXTURE_TILE_STATUS_READ,
+    gcvFEATURE_DEPTH_BIAS_FIX,
+    gcvFEATURE_RECT_PRIMITIVE,
+    gcvFEATURE_BUG_FIXES11,
+    gcvFEATURE_SUPERTILED_TEXTURE,
+    gcvFEATURE_2D_NO_COLORBRUSH_INDEX8,
+    gcvFEATURE_RS_YUV_TARGET,
+    gcvFEATURE_2D_FC_SOURCE, /* For tilestatus compression feature*/
+    gcvFEATURE_2D_CC_NOAA_SOURCE,
+    gcvFEATURE_PE_DITHER_FIX,
+    gcvFEATURE_2D_YUV_SEPARATE_STRIDE,
+    gcvFEATURE_FRUSTUM_CLIP_FIX,
+    gcvFEATURE_TEXTURE_SWIZZLE,
+    gcvFEATURE_PRIMITIVE_RESTART,
+    gcvFEATURE_TEXTURE_LINEAR,
+    gcvFEATURE_TEXTURE_YUV_ASSEMBLER,
+    gcvFEATURE_LINEAR_RENDER_TARGET,
+    gcvFEATURE_SHADER_HAS_ATOMIC,
+    gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE,
+    gcvFEATURE_SHADER_ENHANCEMENTS2,
+    gcvFEATURE_BUG_FIXES7,
+    gcvFEATURE_SHADER_HAS_RTNE,
+    gcvFEATURE_SHADER_HAS_EXTRA_INSTRUCTIONS2,
+    gcvFEATURE_SHADER_ENHANCEMENTS3,
+    gcvFEATURE_DYNAMIC_FREQUENCY_SCALING,
+    gcvFEATURE_SINGLE_BUFFER,
+    gcvFEATURE_OCCLUSION_QUERY,
+    gcvFEATURE_2D_GAMMA,
+    gcvFEATURE_2D_COLOR_SPACE_CONVERSION,
+    gcvFEATURE_2D_SUPER_TILE_VERSION,
+    gcvFEATURE_HALTI0,
+    gcvFEATURE_HALTI1,
+    gcvFEATURE_HALTI2,
+    gcvFEATURE_SUPPORT_GCREGTX,
+    gcvFEATURE_2D_MIRROR_EXTENSION,
+    gcvFEATURE_TEXTURE_ASTC,
+    gcvFEATURE_TEXTURE_ASTC_DECODE_FIX,
+    gcvFEATURE_TEXTURE_ASTC_BASE_LOD_FIX,
+    gcvFEATURE_2D_SUPER_TILE_V1,
+    gcvFEATURE_2D_SUPER_TILE_V2,
+    gcvFEATURE_2D_SUPER_TILE_V3,
+    gcvFEATURE_2D_MULTI_SOURCE_BLT_EX2,
+    gcvFEATURE_NEW_RA,
+    gcvFEATURE_BUG_FIXED_IMPLICIT_PRIMITIVE_RESTART,
+    gcvFEATURE_PE_MULTI_RT_BLEND_ENABLE_CONTROL,
+    gcvFEATURE_SMALL_MSAA, /* An upgraded version of Fast MSAA */
+    gcvFEATURE_VERTEX_INST_ID_AS_ATTRIBUTE,
+    gcvFEATURE_DUAL_16,
+    gcvFEATURE_BRANCH_ON_IMMEDIATE_REG,
+    gcvFEATURE_2D_COMPRESSION,
+    gcvFEATURE_TPC_COMPRESSION,
+    gcvFEATURE_TPCV11_COMPRESSION,
+    gcvFEATURE_DEC_COMPRESSION,
+    gcvFEATURE_DEC300_COMPRESSION,
+    gcvFEATURE_DEC400_COMPRESSION,
+    /*Its a new core for DEC400 compression*/
+    gcvFEATURE_DEC400EX_COMPRESSION,
+    gcvFEATURE_DEC_TPC_COMPRESSION,
+    gcvFEATURE_DEC_COMPRESSION_TILE_NV12_8BIT,
+    gcvFEATURE_DEC_COMPRESSION_TILE_NV12_10BIT,
+    gcvFEATURE_2D_OPF_YUV_OUTPUT,
+    gcvFEATURE_2D_FILTERBLIT_A8_ALPHA,
+    gcvFEATURE_2D_MULTI_SRC_BLT_TO_UNIFIED_DST_RECT,
+    gcvFEATURE_2D_MULTI_SRC_BLT_BILINEAR_FILTER,
+    gcvFEATURE_2D_MULTI_SRC_BLT_1_5_ENHANCEMENT,
+    gcvFEATURE_V2_COMPRESSION_Z16_FIX,
+    gcvFEATURE_VERTEX_INST_ID_AS_INTEGER,
+    gcvFEATURE_2D_YUV_MODE,
+    gcvFEATURE_2D_CACHE_128B256BPERLINE,
+    gcvFEATURE_2D_SEPARATE_CACHE,
+    gcvFEATURE_2D_MAJOR_SUPER_TILE,
+    gcvFEATURE_2D_V4COMPRESSION,
+    gcvFEATURE_2D_VMSAA,
+    gcvFEATURE_2D_10BIT_OUTPUT_LINEAR,
+    gcvFEATURE_2D_YUV420_OUTPUT_LINEAR,
+    gcvFEATURE_ACE,
+    gcvFEATURE_COLOR_COMPRESSION,
+    gcvFEATURE_32BPP_COMPONENT_TEXTURE_CHANNEL_SWIZZLE,
+    gcvFEATURE_64BPP_HW_CLEAR_SUPPORT,
+    gcvFEATURE_TX_LERP_PRECISION_FIX,
+    gcvFEATURE_COMPRESSION_V2,
+    gcvFEATURE_MMU,
+    gcvFEATURE_COMPRESSION_V3,
+    gcvFEATURE_TX_DECOMPRESSOR,
+    gcvFEATURE_MRT_TILE_STATUS_BUFFER,
+    gcvFEATURE_COMPRESSION_V1,
+    gcvFEATURE_V1_COMPRESSION_Z16_DECOMPRESS_FIX,
+    gcvFEATURE_RTT,
+    gcvFEATURE_GENERIC_ATTRIB,
+    gcvFEATURE_2D_ONE_PASS_FILTER,
+    gcvFEATURE_2D_ONE_PASS_FILTER_TAP,
+    gcvFEATURE_2D_POST_FLIP,
+    gcvFEATURE_2D_PIXEL_ALIGNMENT,
+    gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT,
+    gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT_WIDTH,
+    gcvFEATURE_8K_RT,
+    gcvFEATURE_HALTI3,
+    gcvFEATURE_EEZ,
+    gcvFEATURE_INTEGER_SIGNEXT_FIX,
+    gcvFEATURE_PSOUTPUT_MAPPING,
+    gcvFEATURE_8K_RT_FIX,
+    gcvFEATURE_TX_TILE_STATUS_MAPPING,
+    gcvFEATURE_SRGB_RT_SUPPORT,
+    gcvFEATURE_TEXTURE_16K,
+    gcvFEATURE_PA_FARZCLIPPING_FIX,
+    gcvFEATURE_PE_DITHER_COLORMASK_FIX,
+    gcvFEATURE_ZSCALE_FIX,
+    gcvFEATURE_MULTI_PIXELPIPES,
+    gcvFEATURE_PIPE_CL,
+    gcvFEATURE_BUG_FIXES18,
+    gcvFEATURE_UNIFIED_SAMPLERS,
+    gcvFEATURE_CL_PS_WALKER,
+    gcvFEATURE_NEW_HZ,
+    gcvFEATURE_TX_FRAC_PRECISION_6BIT,
+    gcvFEATURE_SH_INSTRUCTION_PREFETCH,
+    gcvFEATURE_PROBE,
+    gcvFEATURE_SINGLE_PIPE_HALTI1,
+    gcvFEATURE_BUG_FIXES8, /* This HW feature is wrong, we can't use this to check integer branch!!!*/
+    gcvFEATURE_2D_ALL_QUAD,
+    gcvFEATURE_SEPARATE_SRC_DST,
+    gcvFEATURE_TX_HOR_ALIGN_SEL,
+    gcvFEATURE_HALTI4,
+    gcvFEATURE_MRT_FC_FIX,
+    gcvFEATURE_TESSELLATION,
+    gcvFEATURE_DRAW_INDIRECT,
+    gcvFEATURE_COMPUTE_INDIRECT,
+    gcvFEATURE_MSAA_TEXTURE,
+    gcvFEATURE_STENCIL_TEXTURE,
+    gcvFEATURE_S8_ONLY_RENDERING,
+    gcvFEATURE_D24S8_SAMPLE_STENCIL,
+    gcvFEATURE_ADVANCED_BLEND_MODE_PART0,
+    gcvFEATURE_RA_DEPTH_WRITE,
+    gcvFEATURE_RS_DS_DOWNSAMPLE_NATIVE_SUPPORT,
+    gcvFEATURE_S8_MSAA_COMPRESSION,
+    gcvFEATURE_MSAA_FRAGMENT_OPERATION,
+    gcvFEATURE_FE_START_VERTEX_SUPPORT,
+    gcvFEATURE_DIVISOR_STREAM_ADDR_FIX,
+    gcvFEATURE_ZERO_ATTRIB_SUPPORT,
+    gcvFEATURE_DANGLING_VERTEX_FIX,
+    gcvFEATURE_PE_DISABLE_COLOR_PIPE,
+    gcvFEATURE_FE_12bit_stride,
+    gcvFEATURE_TX_LOD_GUARDBAND,
+    gcvFEATURE_HAS_PRODUCTID,
+    gcvFEATURE_INTEGER32_FIX,
+    gcvFEATURE_TEXTURE_GATHER,
+    gcvFEATURE_IMG_INSTRUCTION,
+    gcvFEATURE_HELPER_INVOCATION,
+    gcvFEATURE_NO_USER_CSC,
+    gcvFEATURE_ANDROID_ONLY,
+    gcvFEATURE_V2_MSAA_COHERENCY_FIX,
+    gcvFEATURE_BLOCK_SIZE_16x16,
+    gcvFEATURE_TX_SUPPORT_DEC,
+    gcvFEATURE_RSBLT_MSAA_DECOMPRESSION,
+    gcvFEATURE_TILEFILLER_32TILE_ALIGNED,
+    gcvFEATURE_GEOMETRY_SHADER,
+    gcvFEATURE_HALTI5,
+    gcvFEATURE_PIPELINE_32_ATTRIBUTES,
+    gcvFEATURE_USC,
+    gcvFEATURE_CUBEMAP_ARRAY,
+    gcvFEATURE_TX_DESCRIPTOR,
+    gcvFEATURE_SEPARATE_RT_CTRL,
+    gcvFEATURE_RENDER_ARRAY,
+    gcvFEATURE_BLT_ENGINE,
+    gcvFEATURE_TEXTURE_BUFFER,
+    gcvFEATURE_GS_SUPPORT_EMIT,
+    gcvFEATURE_SAMPLER_BASE_OFFSET,
+    gcvFEATURE_IMAGE_OUT_BOUNDARY_FIX,
+    gcvFEATURE_TX_BORDER_CLAMP,
+    gcvFEATURE_MSAA_SHADING,
+    gcvFEATURE_ADVANCED_SH_INST,
+    gcvFEATURE_LOD_FIX_FOR_BASELEVEL,
+    gcvFEATURE_MULTIDRAW_INDIRECT,
+    gcvFEATURE_DRAW_ELEMENTS_BASE_VERTEX,
+    gcvFEATURE_NEW_STEERING_AND_ICACHE_FLUSH, /* Steering base on register base. Trigger-style Icache flush state. */
+    gcvFEATURE_PE_DITHER_FIX2,
+    gcvFEATURE_INDEX_FETCH_FIX,
+    gcvFEATURE_TEX_BASELOD,
+    gcvFEATURE_TEX_SEAMLESS_CUBE,
+    gcvFEATURE_TEX_ETC2,
+    gcvFEATURE_TEX_CUBE_BORDER_LOD,
+    gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG,
+    gcvFEATURE_TX_8BPP_TS_FIX,
+    gcvFEATURE_HW_TFB,
+    gcvFEATURE_COMPRESSION_V4,
+    gcvFEATURE_FENCE_32BIT,
+    gcvFEATURE_FENCE_64BIT,
+    gcvFEATURE_R8_UNORM,
+    gcvFEATURE_TX_DEFAULT_VALUE_FIX,
+    gcvFEATURE_TX_8bit_UVFrac,
+    gcvFEATURE_TX_MIPFILTER_NONE_FIX,
+    gcvFEATURE_MC_STENCIL_CTRL,
+    gcvFEATURE_DEPTH_MATH_FIX,
+    gcvFEATURE_PE_B2B_PIXEL_FIX,
+    gcvFEATURE_TEXTURE_GATHER_OFFSETS,
+    gcvFEATURE_TEX_CACHE_FLUSH_FIX,
+    gcvFEATURE_WIDELINE_HELPER_FIX,
+    gcvFEATURE_LINE_DIAMOND_RULE_FIX,
+    gcvFEATURE_MULTIGPU_SYNC_V2,
+    gcvFEATURE_DRAW_ID,
+    gcvFEATURE_SNAPPAGE_CMD,
+    gcvFEATURE_COMMAND_PREFETCH,
+    gcvFEATURE_SAMPLEPOS_SWIZZLE_FIX,
+    gcvFEATURE_SELECTMAP_SRC0_SWIZZLE_FIX,
+    gcvFEATURE_LOADATTR_OOB_FIX,
+    gcvFEATURE_RA_DEPTH_WRITE_MSAA1X_FIX,
+    gcvFEATURE_MRT_8BIT_DUAL_PIPE_FIX,
+    gcvFEATURE_BUG_FIXES1,
+    gcvFEATURE_MULTI_SOURCE_BLT,
+    gcvFEATURE_ZCOMPRESSION,
+    gcvFEATURE_DITHER_AND_FILTER_PLUS_ALPHA_2D,
+    gcvFEATURE_ONE_PASS_2D_FILTER,
+    gcvFEATURE_TX_FILTER,
+    gcvFEATURE_CHIPENABLE_LINK,
+    gcvFEATURE_TEXTURE_BIAS_LOD_FIX,
+    gcvFEATURE_USE_GL_Z,
+    gcvFEATURE_SUPPORT_INTEGER,
+    /* PARTLY_SUPPORT_INTEGER_BRANCH:
+    **      chips can support all integer types for compare instructions, e.g, CMP, SELECT.
+    ** FULLLY_SUPPORT_INTEGER_BRANCH:
+    **      chips can support all integer types for JMP instruction.
+    ** If PARTLY_SUPPORT_INTEGER_BRANCH is TRUE but FULLLY_SUPPORT_INTEGER_BRANCH is FALSE,
+    ** then this chip can only support INT32/UINT32 JMP instruction.
+    */
+    gcvFEATURE_PARTLY_SUPPORT_INTEGER_BRANCH,
+    gcvFEATURE_FULLLY_SUPPORT_INTEGER_BRANCH,
+    gcvFEATURE_SUPPORT_INTEGER_ATTRIBUTE,
+    gcvFEATURE_SUPPORT_MOVAI,
+    gcvFEATURE_NEED_FIX_FOR_CL_X,
+    gcvFEATURE_NEED_FIX_FOR_CL_XE,
+    gcvFEATURE_HAS_OUTPUT_COUNT_FIX,
+    gcvFEATURE_VARYING_PACKING_LIMITATION,
+    gcvFEATURE_HIGHP_VARYING_SHIFT,
+    gcvFEATURE_BUG_FIXES2,
+    gcvFEATURE_64K_L2_CACHE,
+    gcvFEATURE_128BTILE,
+    gcvFEATURE_ADVANCED_BLEND_OPT,
+    gcvFEATURE_SNAPPAGE_CMD_FIX,
+    gcvFEATURE_L2_CACHE_FOR_2D_420,
+    gcvFEATURE_TILE_STATUS_2BITS,
+    gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS0,
+    gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS1,
+    gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS2,
+    gcvFEATURE_MEDIUM_PRECISION,
+    gcvFEATURE_FE20_BIT_INDEX,
+    gcvFEATURE_BUG_FIXES4,
+    gcvFEATURE_BUG_FIXES12,
+    gcvFEATURE_VMSAA,
+    gcvFEATURE_ROBUST_ATOMIC,
+    gcvFEATURE_32F_COLORMASK_FIX,
+    gcvFEATURE_NEW_GPIPE,
+    gcvFEATURE_RS_NEW_BASEADDR,
+    gcvFEATURE_TX_DXT,
+    gcvFEATURE_SH_FLAT_INTERPOLATION_DUAL16_FIX,
+    gcvFEATURE_EVIS,
+    gcvFEATURE_SH_SUPPORT_V4,
+    gcvFEATURE_SH_SUPPORT_ALPHA_KILL,
+    gcvFEATURE_PE_NO_ALPHA_TEST,
+    gcvFEATURE_SH_SNAP2PAGE_MAXPAGES_FIX,
+    gcvFEATURE_USC_FULLCACHE_FIX,
+    gcvFEATURE_PE_64bit_FENCE_FIX,
+    gcvFEATURE_BLT_8bit_256TILE_FC_FIX,
+    gcvFEATURE_PE_RGBA16I_FIX,
+    gcvFEATURE_BLT_64bpp_MASKED_CLEAR_FIX,
+    gcvFEATURE_SH_PSO_MSAA1x_FIX,
+    gcvFEATURE_USC_ATOMIC_FIX,
+    gcvFEATURE_INDEX_CONST_ON_B0,
+    gcvFEATURE_SH_NO_ONECONST_LIMIT,
+    gcvFEATURE_EVIS_NO_ABSDIFF,
+    gcvFEATURE_EVIS_NO_BITREPLACE,
+    gcvFEATURE_EVIS_NO_BOXFILTER,
+    gcvFEATURE_EVIS_NO_CORDIAC,
+    gcvFEATURE_EVIS_NO_DP32,
+    gcvFEATURE_EVIS_NO_FILTER,
+    gcvFEATURE_EVIS_NO_IADD,
+    gcvFEATURE_EVIS_NO_SELECTADD,
+    gcvFEATURE_EVIS_LERP_7OUTPUT,
+    gcvFEATURE_EVIS_ACCSQ_8OUTPUT,
+    gcvFEATURE_ROBUSTNESS,
+    gcvFEATURE_SECURITY,
+    gcvFEATURE_TX_YUV_ASSEMBLER_10BIT,
+    gcvFEATURE_USC_GOS_ADDR_FIX,
+    gcvFEATURE_SUPPORT_MSAA2X,
+    gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX,
+    gcvFEATURE_TX_INTEGER_COORDINATE,
+    gcvFEATURE_PSIO_SAMPLEMASK_IN_R0ZW_FIX,
+    gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG,
+    gcvFEATURE_SH_IMG_LDST_ON_TEMP,
+    gcvFEATURE_TX_INTEGER_COORDINATE_V2,
+    gcvFEATURE_COMPUTE_ONLY,
+    gcvFEATURE_SH_IMG_LDST_CLAMP,
+    gcvFEATURE_SH_ICACHE_ALLOC_COUNT_FIX,
+    gcvFEATURE_MSAA_OQ_FIX,
+    gcvFEATURE_PE_ENHANCEMENTS2,
+    gcvFEATURE_PSIO_MSAA_CL_FIX,
+    gcvFEATURE_FE_NEED_DUMMYDRAW,
+    gcvFEATURE_MULTI_CLUSTER,
+    gcvFEATURE_PSIO_INTERLOCK,
+    gcvFEATURE_BLIT_COMPRESS_DEST,
+    gcvFEATURE_SH_MULTI_WG_PACK,
+    gcvFEATURE_FE_ROBUST_FIX,
+    gcvFEATURE_TX_ASTC_MULTISLICE_FIX,
+    gcvFEATURE_PSIO_DUAL16_32bpc_FIX,
+    gcvFEATURE_LS_SUPPORT_PER_COMP_DEPENDENCY,
+    gcvFEATURE_COMPRESSION_DEC400,
+    gcvFEATURE_SH_TEXLD_U_FIX,
+    gcvFEATURE_TX_FLUSH_L1CACHE,
+    gcvFEATURE_USC_DEFER_FILL_FIX,
+    gcvFEATURE_MC_FCCACHE_BYTEMASK,
+    gcvFEATURE_SH_MULTI_WG_PACK_FIX,
+    gcvFEATURE_FE_PATCHLIST_FETCH_FIX,
+    gcvFEATURE_RA_CG_FIX,
+    gcvFEATURE_EVIS_VX2,
+    gcvFEATURE_SH_HALF_DEPENDENCY_FIX,
+    gcvFEATURE_FE_BASEINSTANCE,
+    gcvFEATURE_FE_COMPUREINDIRECT_SKIP_UNIFORM,
+    gcvFEATURE_SH_CLOCK_GATE_FIX,
+    gcvFEATURE_GPIPE_CLOCK_GATE_FIX,
+    gcvFEATURE_TP_ENGINE,
+    gcvFEATURE_TX_BORDER_CLAMP_FIX,
+    gcvFEATURE_SH_IMAGE_LD_LAST_PIXEL_FIX,
+    gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2,
+    gcvFEATURE_MULTIGPU_SYNC_V3,
+    gcvFEATURE_PE_VMSAA_COVERAGE_CACHE_FIX,
+    gcvFEATURE_SECURITY_AHB,
+    gcvFEATURE_TX_LERP_LESS_BIT,
+    gcvFEATURE_SMALL_BATCH,
+    gcvFEATURE_SH_IDIV0_SWZL_EHS,
+    gcvFEATURE_SH_CMPLX,
+    gcvFEATURE_VIP_V7,
+    gcvFEATURE_SH_GM_ENDIAN,
+    gcvFEATURE_SH_GM_USC_UNALLOC,
+    gcvFEATURE_SH_END_OF_BB,
+    gcvFEATURE_ASYNC_BLIT,
+    gcvFEATURE_ASYNC_FE_FENCE_FIX,
+    gcvFEATURE_PSCS_THROTTLE,
+    gcvFEATURE_SEPARATE_LS,
+    gcvFEATURE_PA_VARYING_COMPONENT_TOGGLE_FIX,
+    gcvFEATURE_TX_MULTISAMPLER_FC_FIX,
+    gcvFEATURE_WIDELINE_TRIANGLE_EMU,
+    gcvFEATURE_FENCE,
+    gcvFEATURE_MCFE,
+    gcvFEATURE_NN_INTERLEAVE8,
+    gcvFEATURE_TP_REORDER,
+    gcvFEATURE_TP_RTNE,
+    gcvFEATURE_TP_LRN,
+    gcvFEATURE_TP_ROI_POOLING,
+    gcvFEATURE_TP_MAX_POOLING_STRIDE1,
+    gcvFEATURE_NN_BRICK_MODE,
+    gcvFEATURE_NN_BORDER_MODE,
+    gcvFEATURE_NN_FP16_ALU,
+    gcvFEATURE_NN_BF16_ALU,
+    gcvFEATURE_NN_INT16_ALU,
+    gcvFEATURE_NN_ZDP3,
+    gcvFEATURE_NN_ZDP6,
+    gcvFEATURE_PE_DEPTH_ONLY_OQFIX,
+    gcvFEATURE_TX_SNORM_SUPPORT,
+    gcvFEATURE_HWMANAGED_LS,
+    gcvFEATURE_SH_SCATTER_GATHER,
+    gcvFEATURE_NN_POWER_ISOLATION,
+    gcvFEATURE_SWTILING_PHASE1,
+    gcvFEATURE_SWTILING_PHASE2,
+    gcvFEATURE_SWTILING_PHASE3,
+    gcvFEATURE_TF_QUANTIZATION,
+    gcvFEATURE_NN_XYDP9,
+    gcvFEATURE_TP_SIMPLE_INT16,
+    gcvFEATURE_TP_REAL_INT16,
+    gcvFEATURE_NN_FIRST_PIXEL_POOLING,
+    gcvFEATURE_NN_STRIDE_SUPPORT,
+    gcvFEATURE_NN_XYDP6,
+    gcvFEATURE_NN_XYDP0,
+    gcvFEATURE_TP_REORDER_FIX,
+    gcvFEATURE_NN_CONV1x1_PERF_FIX,
+    gcvFEATURE_NN_CACHELINE_MODE_PERF_FIX,
+    gcvFEATURE_NN_PER3DTILE_BUBBLE_FIX,
+    gcvFEATURE_SH_IO_CG_FIX,
+    gcvFEATURE_USC_STAY_LRU,
+    gcvFEATURE_NN_NONZERO_MIRROR_BORDER,
+    gcvFEATURE_NN_COEF_DECOMPRESS_PERF2X,
+    gcvFEATURE_4BIT_INPUT,
+    gcvFEATURE_COEF_COMPRESSION_ENHANCEMENT,
+    gcvFEATURE_NN_ZDP3_NO_COMPRESS_FIX,
+    gcvFEATURE_NN_ASYNC_COPY_PERF_FIX,
+    gcvFEATURE_OCB_COUNTER,
+    gcvFEATURE_NN_ZXDP3_KERNEL_READ_CONFLICT_FIX,
+    gcvFEATURE_NN_FULLCACHE_KERNEL_INTERLEAVE_FIX,
+    gcvFEATURE_DR_JD_DIFF_CONDITION_FOR_CACHELINE_MODE_PRE_FIX,
+    gcvFEATURE_USC_BOTTLENECK_FIX,
+    gcvFEATURE_OCB_REMAP_PHYSICAL_ADDRESS,
+    gcFEATURE_BIT_NN_HW_LIMITATION_NATIVE_KER_1x2_2x1,
+    gcvFEATURE_NN_SLICE_PADDING_TO_64BYTE_ALIGN,
+    gcvFEATURE_NN_DW_1x1_CONV_MERGE,
+    gcvFEATURE_TP_REORDER_LAYER_SUSPEND_FIX,
+    gcvFEATURE_KERNEL_VIP_SRAM_READ_BW_LIMITATION_FIX,
+    gcvFEATURE_IMG_POP_PIPELINE_PAUSE_FIX,
+    gcvFEATURE_NN_SLOW_OUTPUT,
+    gcvFEATURE_NO_NARROW_POST_PROCESS_PIPE,
+    gcvFEATURE_TP_NN_PROBE,
+    gcvFEATURE_TP_23BITS_POST_MULTIPLIER,
+    gcvFEATURE_NN_TRANSPOSE,
+    gcvFEATURE_OUTIMAGE_X_BITWIDTH_LIMIT_FOR_NN_TRANSPOSE_FIX,
+    gcvFEATURE_TP_BFLOAT16,
+    gcvFEATURE_EVIS2_FLOP_RESET_FIX,
+    gcvFEATURE_USC_ASYNC_CP_RTN_FLOP_RESET_FIX,
+    gcvFEATURE_USC_EVICT_CTRL_FIFO_FLOP_RESET_FIX,
+    gcvFEATURE_NEGATIVE_POST_SHIFT_FIX,
+    gcvFEATURE_NN_COMMAND_KERNEL_REQUEST_CONFICT_FIX,
+    gcvFEATURE_NN_LEAKY_RELU,
+    gcvFEATURE_NN_PRELU,
+    gcvFEATURE_NN_NATIVE_STRIDE_TWO,
+    gcvFEATURE_NN_TENSOR_ADD,
+
+    gcvFEATURE_IMAGE_LS_NO_FULLMASK_FIX,
+    gcvFEATURE_BLT_YUV_OUTPUT,
+    gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX,
+    gcvFEATURE_SH_ROBUSTNESS_FIX,
+    gcvFEATURE_USC_ATOMIC_FIX2,
+    gcvFEATURE_MULTIVIEW_RENDER,
+    gcvFEATURE_FE_DRAW_DIRECT,
+    gcvFEATURE_TX_VKBORDER_MODE,
+    gcvFEATURE_TX_UNNORMALIZED_COORD,
+    gcvFEATURE_VG_IMAGE_16K,
+    gcvFEATURE_MULTICORE_CONFIG,
+    gcvFEATURE_PA_LINECLIP_FIX,
+    gcvFEATURE_NN_ENGINE,
+    gcvFEATURE_NN_ASYNC_COPY_MERGE_FIX,
+    gcvFEATURE_NN_CONVOUT_FIFO_DEPTH_FIX,
+    gcvFEATURE_NN_SMALLBATCH_PHASE1,
+    gcvFEATURE_TP_SMALLBATCH_PHASE1,
+    gcvFEATURE_VIP_SCALER,
+    gcvFEATURE_VIP_SCALER_4K,
+    gcvFEATURE_TX_8bit_UVFrac_ROUNDING_FIX,
+    gcvFEATURE_NN_REQ_SLOWARBITRATION_FIX,
+    gcvFEATUER_IMAGE_PARTIAL_CACHE,
+    gcvFEATURE_FULLCACHE_KERNELHEAD_FIX,
+    gcvFEATURE_NN_SINGLEPORT_ACCUMBUFFER,
+    gcvFEATURE_NN_SMALLBATCH,
+    gcvFEATURE_TP_SMALLBATCH,
+    gcvFEATURE_NN_ZDP_INIMAGE_SIZE_FIX,
+    gcvFEATURE_HI_REORDER_FIX,
+    gcvFEATURE_TP_COEF_COMPRESSION_ENHANCEMENT,
+    gcvFEATURE_NN_DEPTHWISE_SUPPORT,
+    gcvFEATURE_IMAGE_NOT_PACKED_IN_SRAM_FIX,
+    gcvFEATURE_IDLE_BEFORE_FLUSH_COMPLETE_FIX,
+    gcvFEATURE_NO_FLUSH_USC_FIX,
+    gcvFEATURE_COEF_DELTA_CORD_OVERFLOW_ZRL_8BIT_FIX,
+    gcvFEATURE_XY_OFFSET_LIMITATION_FIX,
+    gcvFEATURE_USC_INVALIDATE_CACHE_LINE_FIX,
+    gcvFEATURE_LOW_EFFICIENCY_OF_ID_WRITE_IMGBUF_FIX,
+    gcvFEATURE_KERNEL_PER_CORE_LESS_THAN_THIRD_COEF_BUFF_DEPTH_FIX,
+    gcvFEATURE_NN_PER_CHANNEL_QUANT,
+    gcvFEATURE_NN_NO_Z_LOCATION_OFFSET,
+    gcvFEATURE_NN_KERNEL_SIZE_WASTE_IN_PARTIAL_MODE_FIX,
+    gcvFEATURE_INCORRECT_WR_REQ_TO_USC_BETWEEN_REORDER_AND_NORMAL_LAYER_FIX,
+    gcvFEATURE_VIP_DEC400,
+    gcvFEATURE_MAX_POINTSIZE_CLAMP,
+    gcvFEATURE_2D_FAST_CLEAR, /* For tilestatus Fast Clear feature*/
+    gcvFEATURE_NN_PER_CHANNEL_QUANT_ASYM,
+    gcvFEATURE_SMALL_BATCH_FLOPS_RESET_FIX,
+    gcvFEATURE_SMALL_BATCH_DISBLE_FIX,
+    gcvFEATURE_FORMAT_10BIT_CROSS_4K,
+    gcvFEATURE_ENDIAN_CONTROL,
+    gcvFEATURE_SH_VX2_FLOATING_MAD_FIX,
+    gcvFEATURE_PE_A8B8G8R8, /* For PE support A8B8G8R8 format feature*/
+    gcvFEATURE_DEPTHWISE_NEIGHBOR_IMG_DATA_TRANSFER_NOT_EFFICIENT_FIX,
+
+    /* AIGPU feature. */
+    gcvFEATURE_AI_GPU,
+    gcvFEATURE_NN_FAST_FIRST_PIXEL_POOLING,
+    gcvFEATURE_NN_FLOAT_POST_MULT,
+    gcvFEATURE_NN_ASYMMETRIC_INT8,
+
+    gcvFEATURE_FORMAT_YUV_I010, /*support YUVI010 & P010_LSB format*/
+
+    gcFEATURE_BIT_NN_COMPRESSION_BYPASSS,
+    gcFEATURE_BIT_BFLOAT_COEF_COMPRESSION_ZERO_COEFBIT14_INVERSE,
+    gcFEATURE_BIT_TP_KERNEL_1BYTE_ALGIN,
+    gcFEATURE_PREPROCESS_IMG_BUF_640BYTE_LIMIT,
+    gcFEATURE_BIT_TPLITE_BFLOAT16,
+    gcvFEATURE_VIP_HW_FINAL_RELEASE,
+    gcvFEATURE_OUTPUT_CONVERT_UINT8_INT8_TO_UINT16_INT16_FIX,
+    gcvFEATURE_IMG_ADDR_NOT_WRAP_IF_OVER_OCB_ADDR_FIX, /* 2089 */
+    gcFEATURE_BIT_V8_SINGLE_PORT_ACCUMULATION_BUFFER_RW_CONFICT_ZERO_SKIP_PERF_FIX, /* 2043 */
+    gcFEATURE_BIT_BURST_COLLECT_DUMMY_DATA_WASTE_CYCLES_FIX, /* 2111 */
+    gcFEATURE_BIT_TP_ACCESS_VIPSRAM_OT_IS_ONE_FIX, /* 2050 */
+
+
+    gcFEATURE_BIT_USE_SINGLE_PORT_VIPSRAM,
+    gcFEATURE_VALUE_DDR_KERNEL_BURST_SIZE,
+    gcFEATURE_BIT_TILE_ACCESS_CAPABILITY,
+    gcFEATURE_BIT_FAST_DP3_PREPROCESSOR,
+
+    gcvFEATURE_BIT_INIMG_NOT_64BYTE_ALIGN_CACHELINE_MODE_FIX, /* 2112 */
+    gcFEATURE_BIT_DEPTHWISE_16BIT_FORMAT,
+
+    gcvFEATURE_2D_TILESTATUS_ROTATION,/*Fix fastclear feature with rotation*/
+    gcFEATURE_BIT_TP_FC_FLOAT_LAST_PIXEL_NEGATIVE_0_FIX,
+    gcvFEATURE_TS_FC_VULKAN_SUPPORT,
+    gcFEATURE_BIT_V8_ACCUMLATION_READ_OUT_HAS_BUBBLES_PERF_FIX, /* 2044 */
+    gcFEATURE_BIT_MAX_TILE_SIZE,
+    gcvFEATURE_2D_TARGET_MAJOR_SUPER_TILE, /*target support supertile Y major*/
+    gcFEATURE_BIT_INIMAGE_2DTILE_NOT_LESS_160PIXEL_FIX,
+    gcFEATURE_BIT_NN_IN_TILE_DATA_IS_ALL_PAD_FIX, /* 2131 */
+
+    /* TP reorder the int tile x should be less than 512 */
+    gcFEATURE_TP_REORDER_INTILE_X_SIZE_512_FIX,
+    gcFEATURE_NN_WASET_COEF_READ_WRITE_BANDWIDTH_128BYTE_VIPSRAM_IN_FULL_PATIAL_CACHE_MODE,
+    gcFEATURE_BIT_BFP_COEF_AUTO_PAD_INCOMPLETE_ZERO_IN_KZ_PLANE,
+    gcvFEATURE_NN_FLOAT32_IO,
+    gcvFEATURE_TP_FLOAT32_IO,
+
+    gcvFEATURE_BIT_USC_INDIVIDUAL_PORT_WRT_EARLY_EVICT_DATA_CORRUPT_FIX,
+    gcvFEATURE_BIT_NN_TP_INSTR_COMPLETE_IN_SAME_CYCLE_WITH_WAIT_EVENT_FIX,
+
+    /* Insert features above this comment only. */
+    gcvFEATURE_COUNT                /* Not a feature. */
+}
+gceFEATURE;
+
+/* Chip Power Status. */
+typedef enum _gceCHIPPOWERSTATE
+{
+    gcvPOWER_INVALID = -1,
+
+    /* Global/base states. */
+    gcvPOWER_ON = 0,
+    gcvPOWER_IDLE,
+    gcvPOWER_SUSPEND,
+    gcvPOWER_OFF,
+
+    /* Power on but not global or broadcast. */
+    gcvPOWER_ON_AUTO,
+
+    /* Broadcast states. */
+    gcvPOWER_FLAG_BROADCAST    = 0x10,
+    gcvPOWER_IDLE_BROADCAST    = gcvPOWER_IDLE    | gcvPOWER_FLAG_BROADCAST,
+    gcvPOWER_SUSPEND_BROADCAST = gcvPOWER_SUSPEND | gcvPOWER_FLAG_BROADCAST,
+    gcvPOWER_OFF_BROADCAST     = gcvPOWER_OFF     | gcvPOWER_FLAG_BROADCAST,
+
+
+    /* Timeout states. */
+    gcvPOWER_FLAG_TIMEOUT      = 0x20,
+    gcvPOWER_IDLE_TIMEOUT      = gcvPOWER_IDLE    | gcvPOWER_FLAG_TIMEOUT,
+    gcvPOWER_SUSPEND_TIMEOUT   = gcvPOWER_SUSPEND | gcvPOWER_FLAG_TIMEOUT,
+    gcvPOWER_OFF_TIMEOUT       = gcvPOWER_OFF     | gcvPOWER_FLAG_TIMEOUT,
+
+}
+gceCHIPPOWERSTATE;
+
+/* CPU cache operations */
+typedef enum _gceCACHEOPERATION
+{
+    gcvCACHE_CLEAN      = 0x01, /* Flush CPU cache to mem */
+    gcvCACHE_INVALIDATE = 0x02, /* Invalidte CPU cache */
+    gcvCACHE_FLUSH      = gcvCACHE_CLEAN  | gcvCACHE_INVALIDATE, /* Both flush & invalidate */
+    gcvCACHE_MEMORY_BARRIER = 0x04
+}
+gceCACHEOPERATION;
+
+/* Surface types. */
+typedef enum _gceSURF_TYPE
+{
+    gcvSURF_TYPE_UNKNOWN = 0,
+    gcvSURF_INDEX,
+    gcvSURF_VERTEX,
+    gcvSURF_TEXTURE,
+    gcvSURF_RENDER_TARGET,
+    gcvSURF_DEPTH,
+    gcvSURF_BITMAP,
+    gcvSURF_TILE_STATUS,
+    gcvSURF_IMAGE,
+    gcvSURF_MASK,
+    gcvSURF_SCISSOR,
+    gcvSURF_HIERARCHICAL_DEPTH,
+    gcvSURF_ICACHE,
+    gcvSURF_TXDESC,
+    gcvSURF_FENCE,
+    gcvSURF_TFBHEADER,
+    gcvSURF_NUM_TYPES, /* Make sure this is the last one! */
+
+    /* Combinations. */
+    gcvSURF_CMA_LIMIT               = 0x80000000,
+    gcvSURF_NO_TILE_STATUS          = 0x100,
+    gcvSURF_NO_VIDMEM               = 0x200, /* Used to allocate surfaces with no underlying vidmem node.
+                                                   In Android, vidmem node is allocated by another process. */
+    gcvSURF_CACHEABLE               = 0x400, /* Used to allocate a cacheable surface */
+    gcvSURF_TILE_RLV_FENCE          = 0x800, /* create texture fence as tile */
+    gcvSURF_TILE_STATUS_DIRTY       = 0x1000, /* Init tile status to all dirty */
+    gcvSURF_LINEAR                  = 0x2000,
+    gcvSURF_CREATE_AS_TEXTURE       = 0x4000, /* create it as a texture */
+    gcvSURF_PROTECTED_CONTENT       = 0x8000, /* create it as content protected */
+    gcvSURF_CREATE_AS_DISPLAYBUFFER = 0x10000, /*create it as a display buffer surface */
+    gcvSURF_CONTIGUOUS              = 0x20000, /*create it as contiguous */
+    gcvSURF_NO_COMPRESSION          = 0x40000, /* Create it as no compression, valid on when it has tile status. */
+    gcvSURF_DEC                     = 0x80000, /* Surface is DEC compressed */
+    gcvSURF_NO_HZ                   = 0x100000,
+    gcvSURF_3D                      = 0x200000, /* It's 3d surface */
+    gcvSURF_DMABUF_EXPORTABLE       = 0x400000, /* master node can be exported as dma-buf fd */
+    gcvSURF_CACHE_MODE_128          = 0x800000,
+
+    gcvSURF_TEXTURE_LINEAR               = gcvSURF_TEXTURE
+                                         | gcvSURF_LINEAR,
+
+    gcvSURF_RENDER_TARGET_LINEAR         = gcvSURF_RENDER_TARGET
+                                         | gcvSURF_LINEAR,
+
+    gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET
+                                         | gcvSURF_NO_TILE_STATUS,
+
+    gcvSURF_RENDER_TARGET_NO_COMPRESSION = gcvSURF_RENDER_TARGET
+                                         | gcvSURF_NO_COMPRESSION,
+
+    gcvSURF_RENDER_TARGET_TS_DIRTY       = gcvSURF_RENDER_TARGET
+                                         | gcvSURF_TILE_STATUS_DIRTY,
+
+    gcvSURF_DEPTH_NO_TILE_STATUS         = gcvSURF_DEPTH
+                                         | gcvSURF_NO_TILE_STATUS,
+
+    gcvSURF_DEPTH_TS_DIRTY               = gcvSURF_DEPTH
+                                         | gcvSURF_TILE_STATUS_DIRTY,
+
+    /* Supported surface types with no vidmem node. */
+    gcvSURF_BITMAP_NO_VIDMEM             = gcvSURF_BITMAP
+                                         | gcvSURF_NO_VIDMEM,
+
+    gcvSURF_TEXTURE_NO_VIDMEM            = gcvSURF_TEXTURE
+                                         | gcvSURF_NO_VIDMEM,
+
+    /* Cacheable surface types with no vidmem node. */
+    gcvSURF_CACHEABLE_BITMAP_NO_VIDMEM   = gcvSURF_BITMAP_NO_VIDMEM
+                                         | gcvSURF_CACHEABLE,
+
+    gcvSURF_CACHEABLE_BITMAP             = gcvSURF_BITMAP
+                                         | gcvSURF_CACHEABLE,
+
+    gcvSURF_TEXTURE_3D                  = gcvSURF_TEXTURE
+                                         | gcvSURF_3D
+}
+gceSURF_TYPE;
+
+/* Surface formats.
+** Name rules is from MSB->LSB.
+*/
+typedef enum _gceSURF_FORMAT
+{
+    /* Unknown format. */
+    gcvSURF_UNKNOWN             = 0,
+
+    /* Palettized formats. */
+    gcvSURF_INDEX1              = 100,
+    gcvSURF_INDEX4,
+    gcvSURF_INDEX8,
+#if gcdVG_ONLY
+    gcvSURF_INDEX2,
+#endif
+
+    /* RGB formats. */
+    gcvSURF_A2R2G2B2            = 200,
+    gcvSURF_R3G3B2,
+    gcvSURF_A8R3G3B2,
+    gcvSURF_X4R4G4B4,
+    gcvSURF_A4R4G4B4,
+    gcvSURF_R4G4B4A4,
+    gcvSURF_X1R5G5B5,
+    gcvSURF_A1R5G5B5,
+    gcvSURF_R5G5B5A1,
+    gcvSURF_R5G6B5,
+    gcvSURF_R8G8B8,
+    gcvSURF_X8R8G8B8,
+    gcvSURF_A8R8G8B8,
+    gcvSURF_R8G8B8A8,
+    gcvSURF_G8R8G8B8,
+    gcvSURF_R8G8B8G8,
+    gcvSURF_X2R10G10B10,
+    gcvSURF_A2R10G10B10,
+    gcvSURF_R10G10B10A2,
+    gcvSURF_X12R12G12B12,
+    gcvSURF_A12R12G12B12,
+    gcvSURF_X16R16G16B16,
+    gcvSURF_A16R16G16B16,
+    gcvSURF_A32R32G32B32,
+    gcvSURF_R8G8B8X8,
+    gcvSURF_R5G5B5X1,
+    gcvSURF_R4G4B4X4,
+    gcvSURF_X16R16G16B16_2_A8R8G8B8,
+    gcvSURF_A16R16G16B16_2_A8R8G8B8,
+    gcvSURF_A32R32G32B32_2_G32R32F,
+    gcvSURF_A32R32G32B32_4_A8R8G8B8,
+    /* BGR formats. */
+    gcvSURF_A4B4G4R4            = 300,
+    gcvSURF_A1B5G5R5,
+    gcvSURF_B5G6R5,
+    gcvSURF_B8G8R8,
+    gcvSURF_B16G16R16,
+    gcvSURF_X8B8G8R8,
+    gcvSURF_A8B8G8R8,
+    gcvSURF_A2B10G10R10,
+    gcvSURF_X16B16G16R16,
+    gcvSURF_A16B16G16R16,
+    gcvSURF_B32G32R32,
+    gcvSURF_X32B32G32R32,
+    gcvSURF_A32B32G32R32,
+    gcvSURF_B4G4R4A4,
+    gcvSURF_B5G5R5A1,
+    gcvSURF_B8G8R8X8,
+    gcvSURF_B8G8R8A8,
+    gcvSURF_B10G10R10A2,
+    gcvSURF_X4B4G4R4,
+    gcvSURF_X1B5G5R5,
+    gcvSURF_B4G4R4X4,
+    gcvSURF_B5G5R5X1,
+    gcvSURF_X2B10G10R10,
+    gcvSURF_B8G8R8_SNORM,
+    gcvSURF_X8B8G8R8_SNORM,
+    gcvSURF_A8B8G8R8_SNORM,
+    gcvSURF_A8B12G12R12_2_A8R8G8B8,
+
+    /* Compressed formats. */
+    gcvSURF_DXT1                = 400,
+    gcvSURF_DXT2,
+    gcvSURF_DXT3,
+    gcvSURF_DXT4,
+    gcvSURF_DXT5,
+    gcvSURF_CXV8U8,
+    gcvSURF_ETC1,
+    gcvSURF_R11_EAC,
+    gcvSURF_SIGNED_R11_EAC,
+    gcvSURF_RG11_EAC,
+    gcvSURF_SIGNED_RG11_EAC,
+    gcvSURF_RGB8_ETC2,
+    gcvSURF_SRGB8_ETC2,
+    gcvSURF_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+    gcvSURF_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+    gcvSURF_RGBA8_ETC2_EAC,
+    gcvSURF_SRGB8_ALPHA8_ETC2_EAC,
+
+    /* YUV formats. */
+    gcvSURF_YUY2                = 500,
+    gcvSURF_UYVY,
+    gcvSURF_YV12,
+    gcvSURF_I420,
+    gcvSURF_NV12,
+    gcvSURF_NV21,
+    gcvSURF_NV16,
+    gcvSURF_NV61,
+    gcvSURF_YVYU,
+    gcvSURF_VYUY,
+    gcvSURF_AYUV,
+    gcvSURF_YUV420_10_ST,
+    gcvSURF_YUV420_TILE_ST,
+    gcvSURF_YUV420_TILE_10_ST,
+    gcvSURF_NV12_10BIT,
+    gcvSURF_NV21_10BIT,
+    gcvSURF_NV16_10BIT,
+    gcvSURF_NV61_10BIT,
+    gcvSURF_P010,
+    gcvSURF_P010_LSB,
+    gcvSURF_I010,
+#if gcdVG_ONLY
+    gcvSURF_AYUY2,
+    gcvSURF_ANV12,
+    gcvSURF_ANV16,
+    gcvSURF_AUYVY,
+    gcvSURF_YV16,
+#endif
+
+    /* Depth formats. */
+    gcvSURF_D16                 = 600,
+    gcvSURF_D24S8,
+    gcvSURF_D32,
+    gcvSURF_D24X8,
+    gcvSURF_D32F,
+    gcvSURF_S8D32F,
+    gcvSURF_S8D32F_1_G32R32F,
+    gcvSURF_S8D32F_2_A8R8G8B8,
+    gcvSURF_D24S8_1_A8R8G8B8,
+    gcvSURF_S8,
+    gcvSURF_X24S8,
+    gcvSURF_X24S8_1_A8R8G8B8,
+
+    /* Alpha formats. */
+    gcvSURF_A4                  = 700,
+    gcvSURF_A8,
+    gcvSURF_A12,
+    gcvSURF_A16,
+    gcvSURF_A32,
+    gcvSURF_A1,
+
+    /* Luminance formats. */
+    gcvSURF_L4                  = 800,
+    gcvSURF_L8,
+    gcvSURF_L12,
+    gcvSURF_L16,
+    gcvSURF_L32,
+    gcvSURF_L1,
+    gcvSURF_L8_RAW,
+
+    /* Alpha/Luminance formats. */
+    gcvSURF_A4L4                = 900,
+    gcvSURF_A2L6,
+    gcvSURF_A8L8,
+    gcvSURF_A4L12,
+    gcvSURF_A12L12,
+    gcvSURF_A16L16,
+
+    gcvSURF_A8L8_1_A8R8G8B8,
+
+    gcvSURF_A8L8_RAW,
+
+    /* Bump formats. */
+    gcvSURF_L6V5U5              = 1000,
+    gcvSURF_V8U8,
+    gcvSURF_X8L8V8U8,
+    gcvSURF_Q8W8V8U8,
+    gcvSURF_A2W10V10U10,
+    gcvSURF_V16U16,
+    gcvSURF_Q16W16V16U16,
+
+    /* R/RG/RA formats. */
+    gcvSURF_R8                  = 1100,
+    gcvSURF_X8R8,
+    gcvSURF_G8R8,
+    gcvSURF_X8G8R8,
+    gcvSURF_A8R8,
+    gcvSURF_R16,
+    gcvSURF_X16R16,
+    gcvSURF_G16R16,
+    gcvSURF_X16G16R16,
+    gcvSURF_A16R16,
+    gcvSURF_R32,
+    gcvSURF_X32R32,
+    gcvSURF_G32R32,
+    gcvSURF_X32G32R32,
+    gcvSURF_A32R32,
+    gcvSURF_RG16,
+    gcvSURF_R8_SNORM,
+    gcvSURF_G8R8_SNORM,
+
+    gcvSURF_R8_1_X8R8G8B8,
+    gcvSURF_G8R8_1_X8R8G8B8,
+
+    /* Floating point formats. */
+    gcvSURF_R16F                = 1200,
+    gcvSURF_X16R16F,
+    gcvSURF_G16R16F,
+    gcvSURF_X16G16R16F,
+    gcvSURF_B16G16R16F,
+    gcvSURF_X16B16G16R16F,
+    gcvSURF_A16B16G16R16F,
+    gcvSURF_R32F,
+    gcvSURF_X32R32F,
+    gcvSURF_G32R32F,
+    gcvSURF_X32G32R32F,
+    gcvSURF_B32G32R32F,
+    gcvSURF_X32B32G32R32F,
+    gcvSURF_A32B32G32R32F,
+    gcvSURF_A16F,
+    gcvSURF_L16F,
+    gcvSURF_A16L16F,
+    gcvSURF_A16R16F,
+    gcvSURF_A32F,
+    gcvSURF_L32F,
+    gcvSURF_A32L32F,
+    gcvSURF_A32R32F,
+    gcvSURF_E5B9G9R9,
+    gcvSURF_B10G11R11F,
+
+    gcvSURF_X16B16G16R16F_2_A8R8G8B8,
+    gcvSURF_A16B16G16R16F_2_A8R8G8B8,
+    gcvSURF_A16B16G16R16F_2_G16R16F,
+    gcvSURF_G32R32F_2_A8R8G8B8,
+    gcvSURF_X32B32G32R32F_2_G32R32F,
+    gcvSURF_A32B32G32R32F_2_G32R32F,
+    gcvSURF_X32B32G32R32F_4_A8R8G8B8,
+    gcvSURF_A32B32G32R32F_4_A8R8G8B8,
+
+    gcvSURF_R16F_1_A4R4G4B4,
+    gcvSURF_G16R16F_1_A8R8G8B8,
+    gcvSURF_B16G16R16F_2_A8R8G8B8,
+
+    gcvSURF_R32F_1_A8R8G8B8,
+    gcvSURF_B32G32R32F_3_A8R8G8B8,
+    gcvSURF_B10G11R11F_1_A8R8G8B8,
+
+    gcvSURF_A32F_1_R32F,
+    gcvSURF_L32F_1_R32F,
+    gcvSURF_A32L32F_1_G32R32F,
+
+
+
+    /* sRGB format. */
+    gcvSURF_SBGR8               = 1400,
+    gcvSURF_A8_SBGR8,
+    gcvSURF_X8_SBGR8,
+    gcvSURF_A8_SRGB8,
+    gcvSURF_X8_SRGB8,
+
+    /* Integer formats. */
+    gcvSURF_R8I                 = 1500,
+    gcvSURF_R8UI,
+    gcvSURF_R16I,
+    gcvSURF_R16UI,
+    gcvSURF_R32I,
+    gcvSURF_R32UI,
+    gcvSURF_X8R8I,
+    gcvSURF_G8R8I,
+    gcvSURF_X8R8UI,
+    gcvSURF_G8R8UI,
+    gcvSURF_X16R16I,
+    gcvSURF_G16R16I,
+    gcvSURF_X16R16UI,
+    gcvSURF_G16R16UI,
+    gcvSURF_X32R32I,
+    gcvSURF_G32R32I,
+    gcvSURF_X32R32UI,
+    gcvSURF_G32R32UI,
+    gcvSURF_X8G8R8I,
+    gcvSURF_B8G8R8I,
+    gcvSURF_X8G8R8UI,
+    gcvSURF_B8G8R8UI,
+    gcvSURF_X16G16R16I,
+    gcvSURF_B16G16R16I,
+    gcvSURF_X16G16R16UI,
+    gcvSURF_B16G16R16UI,
+    gcvSURF_X32G32R32I,
+    gcvSURF_B32G32R32I,
+    gcvSURF_X32G32R32UI,
+    gcvSURF_B32G32R32UI,
+    gcvSURF_X8B8G8R8I,
+    gcvSURF_A8B8G8R8I,
+    gcvSURF_X8B8G8R8UI,
+    gcvSURF_A8B8G8R8UI,
+    gcvSURF_X16B16G16R16I,
+    gcvSURF_A16B16G16R16I,
+    gcvSURF_X16B16G16R16UI,
+    gcvSURF_A16B16G16R16UI,
+    gcvSURF_X32B32G32R32I,
+    gcvSURF_A32B32G32R32I,
+    gcvSURF_X32B32G32R32UI,
+    gcvSURF_A32B32G32R32UI,
+    gcvSURF_A2B10G10R10UI,
+    gcvSURF_G32R32I_2_A8R8G8B8,
+    gcvSURF_G32R32I_1_G32R32F,
+    gcvSURF_G32R32UI_2_A8R8G8B8,
+    gcvSURF_G32R32UI_1_G32R32F,
+    gcvSURF_X16B16G16R16I_2_A8R8G8B8,
+    gcvSURF_X16B16G16R16I_1_G32R32F,
+    gcvSURF_A16B16G16R16I_2_A8R8G8B8,
+    gcvSURF_A16B16G16R16I_1_G32R32F,
+    gcvSURF_X16B16G16R16UI_2_A8R8G8B8,
+    gcvSURF_X16B16G16R16UI_1_G32R32F,
+    gcvSURF_A16B16G16R16UI_2_A8R8G8B8,
+    gcvSURF_A16B16G16R16UI_1_G32R32F,
+    gcvSURF_X32B32G32R32I_2_G32R32I,
+    gcvSURF_A32B32G32R32I_2_G32R32I,
+    gcvSURF_A32B32G32R32I_2_G32R32F,
+    gcvSURF_X32B32G32R32I_3_A8R8G8B8,
+    gcvSURF_A32B32G32R32I_4_A8R8G8B8,
+    gcvSURF_X32B32G32R32UI_2_G32R32UI,
+    gcvSURF_A32B32G32R32UI_2_G32R32UI,
+    gcvSURF_A32B32G32R32UI_2_G32R32F,
+    gcvSURF_X32B32G32R32UI_3_A8R8G8B8,
+    gcvSURF_A32B32G32R32UI_4_A8R8G8B8,
+    gcvSURF_A2B10G10R10UI_1_A8R8G8B8,
+    gcvSURF_A8B8G8R8I_1_A8R8G8B8,
+    gcvSURF_A8B8G8R8UI_1_A8R8G8B8,
+    gcvSURF_R8I_1_A4R4G4B4,
+    gcvSURF_R8UI_1_A4R4G4B4,
+    gcvSURF_R16I_1_A4R4G4B4,
+    gcvSURF_R16UI_1_A4R4G4B4,
+    gcvSURF_R32I_1_A8R8G8B8,
+    gcvSURF_R32UI_1_A8R8G8B8,
+    gcvSURF_X8R8I_1_A4R4G4B4,
+    gcvSURF_X8R8UI_1_A4R4G4B4,
+    gcvSURF_G8R8I_1_A4R4G4B4,
+    gcvSURF_G8R8UI_1_A4R4G4B4,
+    gcvSURF_X16R16I_1_A4R4G4B4,
+    gcvSURF_X16R16UI_1_A4R4G4B4,
+    gcvSURF_G16R16I_1_A8R8G8B8,
+    gcvSURF_G16R16UI_1_A8R8G8B8,
+    gcvSURF_X32R32I_1_A8R8G8B8,
+    gcvSURF_X32R32UI_1_A8R8G8B8,
+    gcvSURF_X8G8R8I_1_A4R4G4B4,
+    gcvSURF_X8G8R8UI_1_A4R4G4B4,
+    gcvSURF_B8G8R8I_1_A8R8G8B8,
+    gcvSURF_B8G8R8UI_1_A8R8G8B8,
+    gcvSURF_B16G16R16I_2_A8R8G8B8,
+    gcvSURF_B16G16R16I_1_G32R32F,
+    gcvSURF_B16G16R16UI_2_A8R8G8B8,
+    gcvSURF_B16G16R16UI_1_G32R32F,
+    gcvSURF_B32G32R32I_3_A8R8G8B8,
+    gcvSURF_B32G32R32UI_3_A8R8G8B8,
+    gcvSURF_A16B16G16R16_2_A8R8G8B8,
+    gcvSURF_R8G8B8_1_A8R8G8B8,
+    gcvSURF_G16R16_1_A8R8G8B8,
+    gcvSURF_A2B10G10R10_1_A8R8G8B8,
+    gcvSURF_A2R10G10B10_1_A8R8G8B8,
+    gcvSURF_A2W10V10U10_1_A8R8G8B8,
+
+    /* ASTC formats. */
+    gcvSURF_ASTC4x4             = 1600,
+    gcvSURF_ASTC5x4,
+    gcvSURF_ASTC5x5,
+    gcvSURF_ASTC6x5,
+    gcvSURF_ASTC6x6,
+    gcvSURF_ASTC8x5,
+    gcvSURF_ASTC8x6,
+    gcvSURF_ASTC8x8,
+    gcvSURF_ASTC10x5,
+    gcvSURF_ASTC10x6,
+    gcvSURF_ASTC10x8,
+    gcvSURF_ASTC10x10,
+    gcvSURF_ASTC12x10,
+    gcvSURF_ASTC12x12,
+    gcvSURF_ASTC4x4_SRGB,
+    gcvSURF_ASTC5x4_SRGB,
+    gcvSURF_ASTC5x5_SRGB,
+    gcvSURF_ASTC6x5_SRGB,
+    gcvSURF_ASTC6x6_SRGB,
+    gcvSURF_ASTC8x5_SRGB,
+    gcvSURF_ASTC8x6_SRGB,
+    gcvSURF_ASTC8x8_SRGB,
+    gcvSURF_ASTC10x5_SRGB,
+    gcvSURF_ASTC10x6_SRGB,
+    gcvSURF_ASTC10x8_SRGB,
+    gcvSURF_ASTC10x10_SRGB,
+    gcvSURF_ASTC12x10_SRGB,
+    gcvSURF_ASTC12x12_SRGB,
+
+    /* Recompile format*/
+    gcvSURF_L16_1_A4R4G4B4 = 1700,
+    gcvSURF_V16U16_1_A8R8G8B8,
+    gcvSURF_Q8W8V8U8_1_A8R8G8B8,
+    gcvSURF_X8L8V8U8_1_A8R8G8B8,
+    gcvSURF_R3G3B2_1_A8R8G8B8,
+    gcvSURF_A8R3G3B2_1_A8R8G8B8,
+    gcvSURF_W11V11U10_1_A8R8G8B8,
+    gcvSURF_Q16W16V16U16_2_A8R8G8B8,
+    gcvSURF_W11V11U10,
+    gcvSURF_V8U8_1_A4R4G4B4,
+    gcvSURF_A8B8G8R8_1_A8R8G8B8,
+    gcvSURF_A32R32G32B32_1_A8R8G8B8,
+    gcvSURF_X16B16G16R16F_1_A8R8G8B8,
+    gcvSURF_A16B16G16R16F_1_A8R8G8B8,
+    gcvSURF_G32R32F_1_A8R8G8B8,
+    gcvSURF_X32B32G32R32F_1_A8R8G8B8,
+    gcvSURF_A32B32G32R32F_1_A8R8G8B8,
+    gcvSURF_G32R32I_1_A8R8G8B8,
+    gcvSURF_G32R32UI_1_A8R8G8B8,
+    gcvSURF_A32B32G32R32I_1_A8R8G8B8,
+    gcvSURF_A32B32G32R32UI_1_A8R8G8B8,
+    gcvSURF_Q16W16V16U16_1_A8R8G8B8,
+    gcvSURF_A16B16G16R16_1_A8R8G8B8,
+
+    /* Integer formats (2)) */
+    gcvSURF_R10G10B10A2UI   = 1800,
+    gcvSURF_R5G6B5UI,
+    gcvSURF_B5G6R5UI,
+    gcvSURF_R3G3B2UI,
+    gcvSURF_B2G3R3UI,
+    gcvSURF_R4G4B4A4UI,
+    gcvSURF_A4B4G4R4UI,
+    gcvSURF_R5G5B5A1UI,
+    gcvSURF_A1B5G5R5UI,
+    gcvSURF_R8G8B8A8UI,
+
+    /* GL4 formats */
+    gcvSURF_G8              = 1900,
+    gcvSURF_B8,
+    gcvSURF_G32F,
+    gcvSURF_B32F,
+
+    /* Intensity formats */
+    gcvSURF_I4              = 2000,
+    gcvSURF_I8,
+    gcvSURF_I12,
+    gcvSURF_I16,
+}
+gceSURF_FORMAT;
+
+/* Pipes. */
+typedef enum _gcePIPE_SELECT
+{
+    gcvPIPE_INVALID = ~0,
+    gcvPIPE_3D      =  0,
+    gcvPIPE_2D
+}
+gcePIPE_SELECT;
+
+/* Hardware type. */
+typedef enum _gceHARDWARE_TYPE
+{
+    gcvHARDWARE_INVALID,
+    gcvHARDWARE_3D2D,
+    gcvHARDWARE_3D,
+    gcvHARDWARE_2D,
+    gcvHARDWARE_VIP,
+    gcvHARDWARE_VG,
+    gcvHARDWARE_NUM_TYPES,
+}
+gceHARDWARE_TYPE;
+
+/* User signal command codes. */
+typedef enum _gceUSER_SIGNAL_COMMAND_CODES
+{
+    gcvUSER_SIGNAL_CREATE,
+    gcvUSER_SIGNAL_DESTROY,
+    gcvUSER_SIGNAL_SIGNAL,
+    gcvUSER_SIGNAL_WAIT,
+    gcvUSER_SIGNAL_MAP,
+    gcvUSER_SIGNAL_UNMAP,
+}
+gceUSER_SIGNAL_COMMAND_CODES;
+
+/* Shared buffer command codes. */
+typedef enum _gceSHBUF_COMMAND_CODES
+{
+    gcvSHBUF_CREATE,
+    gcvSHBUF_DESTROY,
+    gcvSHBUF_MAP,
+    gcvSHBUF_WRITE,
+    gcvSHBUF_READ,
+}
+gceSHBUF_COMMAND_CODES;
+
+/* Event locations. */
+typedef enum _gceKERNEL_WHERE
+{
+    gcvKERNEL_COMMAND,
+    gcvKERNEL_VERTEX,
+    gcvKERNEL_TRIANGLE,
+    gcvKERNEL_TEXTURE,
+    gcvKERNEL_PIXEL,
+    gcvKERNEL_BLT,
+}
+gceKERNEL_WHERE;
+
+typedef enum _gceBLOCK
+{
+    gcvBLOCK_COMMAND,
+    gcvBLOCK_TESSELLATOR,
+    gcvBLOCK_TESSELLATOR2,
+    gcvBLOCK_TESSELLATOR3,
+    gcvBLOCK_RASTER,
+    gcvBLOCK_VG,
+    gcvBLOCK_VG2,
+    gcvBLOCK_VG3,
+    gcvBLOCK_PIXEL,
+
+    /* Number of defined blocks. */
+    gcvBLOCK_COUNT
+}
+gceBLOCK;
+
+typedef enum _gceCORE_3D_MASK
+{
+    gcvCORE_3D_0_MASK   = (1 << 0),
+    gcvCORE_3D_1_MASK   = (1 << 1),
+
+    gcvCORE_3D_ALL_MASK = (0xFFFF)
+}
+gceCORE_3D_MASK;
+
+typedef enum _gceCORE_3D_ID
+{
+    gcvCORE_3D_0_ID       = 0,
+    gcvCORE_3D_1_ID       = 1,
+
+    gcvCORE_3D_ID_INVALID = ~0UL
+}
+gceCORE_3D_ID;
+
+
+typedef enum _gceCHIP_FLAG
+{
+    gcvCHIP_FLAG_MSAA_COHERENCEY_ECO_FIX = 1 << 0,
+    gcvCHIP_FLAG_GC2000_R2               = 1 << 1,
+    gcvCHIP_AXI_BUS128_BITS              = 1 << 2,
+}
+gceCHIP_FLAG;
+
+/* If different, choose render engine */
+#define PRIORITY_ENGINE(a, b) gcmMIN(a,b)
+
+typedef enum
+{
+    gcvENGINE_RENDER            = 0,
+    gcvENGINE_BLT               = 1,
+    gcvENGINE_GPU_ENGINE_COUNT  = 2,
+    gcvENGINE_CPU               = gcvENGINE_GPU_ENGINE_COUNT,
+    gcvENGINE_ALL_COUNT         = gcvENGINE_CPU + 1,
+    gcvENGINE_INVALID           = gcvENGINE_ALL_COUNT + 0x100
+}
+gceENGINE;
+
+/* CORE enum. */
+typedef enum _gceCORE
+{
+    gcvCORE_MAJOR,
+    gcvCORE_3D1,
+    gcvCORE_3D2,
+    gcvCORE_3D3,
+    gcvCORE_3D4,
+    gcvCORE_3D5,
+    gcvCORE_3D6,
+    gcvCORE_3D7,
+    gcvCORE_3D_MAX = gcvCORE_3D7,
+    gcvCORE_2D,
+    gcvCORE_VG,
+#if gcdDEC_ENABLE_AHB
+    gcvCORE_DEC,
+#endif
+    gcvCORE_COUNT
+}
+gceCORE;
+
+#define gcdCHIP_COUNT               gcvCORE_COUNT
+
+typedef enum _gceSECURE_MODE
+{
+    /* For cores without gcvFEATURE_SECURITY. */
+    gcvSECURE_NONE,
+
+    /* Use registers added in gcvFEATURE_SECURITY in normal driver,
+    ** In this mode, GPU always works under non secure mode and
+    ** should not touch secure buffer. It is used to test basic function.
+    */
+    gcvSECURE_IN_NORMAL,
+
+    /* Make use of gcvFEATURE_SECURITY in trust application. */
+    gcvSECURE_IN_TA
+}
+gceSECURE_MODE;
+
+/* kernel driver compression option, as it's a system global option,
+** it means kernel driver allows the options, NOT necessarily means it must be on.
+*/
+typedef enum _gceCOMPRESSION_OPTION
+{
+    gcvCOMPRESSION_OPTION_NONE       = 0x0, /* No any compression */
+    gcvCOMPRESSION_OPTION_COLOR      = 0x1, /* Compression for non-msaa color format */
+    gcvCOMPRESSION_OPTION_DEPTH      = 0x2, /* Compression for non-msaa depth format */
+    gcvCOMPRESSION_OPTION_MSAA_COLOR = 0x4, /* Compression for msaa color */
+    gcvCOMPRESSION_OPTION_MSAA_DEPTH = 0x8, /* Compression for msaa depth */
+
+    /* default compressio option */
+    gcvCOMPRESSION_OPTION_DEFAULT    = gcvCOMPRESSION_OPTION_DEPTH      |
+                                       gcvCOMPRESSION_OPTION_COLOR      |
+                                       gcvCOMPRESSION_OPTION_MSAA_COLOR |
+                                       gcvCOMPRESSION_OPTION_MSAA_DEPTH,
+}
+gceCOMPRESSION_OPTION;
+
+typedef enum _gceSRAM_INTERNAL
+{
+    gcvSRAM_INTERNAL0 = 0,
+    gcvSRAM_INTERNAL1,
+
+    gcvSRAM_INTER_COUNT
+}
+gceSRAM_INTERNAL;
+
+typedef enum _gceSRAM_EXTERNAL
+{
+    gcvSRAM_EXTERNAL0 = 0,
+    gcvSRAM_EXTERNAL1,
+
+    gcvSRAM_EXT_COUNT
+}
+gceSRAM_EXTERNAL;
+
+typedef enum _gceFLATMAP_FLAG
+{
+    gcvFLATMAP_DIRECT,
+    gcvFLATMAP_SHIFT,
+}
+gceFLATMAP_FLAG;
+
+/* Video memory alloation type. */
+typedef enum _gceVIDMEM_TYPE
+{
+    gcvVIDMEM_TYPE_GENERIC          = gcvSURF_TYPE_UNKNOWN,
+    gcvVIDMEM_TYPE_INDEX_BUFFER     = gcvSURF_INDEX,
+    gcvVIDMEM_TYPE_VERTEX_BUFFER    = gcvSURF_VERTEX,
+    gcvVIDMEM_TYPE_TEXTURE          = gcvSURF_TEXTURE,
+    gcvVIDMEM_TYPE_COLOR_BUFFER     = gcvSURF_RENDER_TARGET,
+    gcvVIDMEM_TYPE_DEPTH_BUFFER     = gcvSURF_DEPTH,
+    gcvVIDMEM_TYPE_BITMAP           = gcvSURF_BITMAP,
+    gcvVIDMEM_TYPE_TILE_STATUS      = gcvSURF_TILE_STATUS,
+    gcvVIDMEM_TYPE_IMAGE            = gcvSURF_IMAGE,
+    gcvVIDMEM_TYPE_MASK             = gcvSURF_MASK,
+    gcvVIDMEM_TYPE_SCISSOR          = gcvSURF_SCISSOR,
+    gcvVIDMEM_TYPE_HZ_BUFFER        = gcvSURF_HIERARCHICAL_DEPTH,
+    gcvVIDMEM_TYPE_ICACHE           = gcvSURF_ICACHE,
+    gcvVIDMEM_TYPE_TXDESC           = gcvSURF_TXDESC,
+    gcvVIDMEM_TYPE_FENCE            = gcvSURF_FENCE,
+    gcvVIDMEM_TYPE_TFBHEADER        = gcvSURF_TFBHEADER,
+    gcvVIDMEM_TYPE_COMMAND,
+    gcvVIDMEM_TYPE_COUNT
+}
+gceVIDMEM_TYPE;
+
+typedef enum _gceTASK
+{
+    gcvTASK_LINK,
+    gcvTASK_CLUSTER,
+    gcvTASK_INCREMENT,
+    gcvTASK_DECREMENT,
+    gcvTASK_SIGNAL,
+    gcvTASK_LOCKDOWN,
+    gcvTASK_UNLOCK_VIDEO_MEMORY,
+    gcvTASK_FREE_VIDEO_MEMORY,
+    gcvTASK_FREE_CONTIGUOUS_MEMORY,
+}
+gceTASK;
+
+/******************************************************************************\
+********************************* Status Codes *********************************
+\******************************************************************************/
+
+typedef enum _gceSTATUS
+{
+    gcvSTATUS_OK                    =   0,
+    gcvSTATUS_FALSE                 =   0,
+    gcvSTATUS_TRUE                  =   1,
+    gcvSTATUS_NO_MORE_DATA          =   2,
+    gcvSTATUS_CACHED                =   3,
+    gcvSTATUS_MIPMAP_TOO_LARGE      =   4,
+    gcvSTATUS_NAME_NOT_FOUND        =   5,
+    gcvSTATUS_NOT_OUR_INTERRUPT     =   6,
+    gcvSTATUS_MISMATCH              =   7,
+    gcvSTATUS_MIPMAP_TOO_SMALL      =   8,
+    gcvSTATUS_LARGER                =   9,
+    gcvSTATUS_SMALLER               =   10,
+    gcvSTATUS_CHIP_NOT_READY        =   11,
+    gcvSTATUS_NEED_CONVERSION       =   12,
+    gcvSTATUS_SKIP                  =   13,
+    gcvSTATUS_DATA_TOO_LARGE        =   14,
+    gcvSTATUS_INVALID_CONFIG        =   15,
+    gcvSTATUS_CHANGED               =   16,
+    gcvSTATUS_NOT_SUPPORT_DITHER    =   17,
+    gcvSTATUS_EXECUTED              =   18,
+    gcvSTATUS_TERMINATE             =   19,
+
+    gcvSTATUS_INVALID_ARGUMENT      =   -1,
+    gcvSTATUS_INVALID_OBJECT        =   -2,
+    gcvSTATUS_OUT_OF_MEMORY         =   -3,
+    gcvSTATUS_MEMORY_LOCKED         =   -4,
+    gcvSTATUS_MEMORY_UNLOCKED       =   -5,
+    gcvSTATUS_HEAP_CORRUPTED        =   -6,
+    gcvSTATUS_GENERIC_IO            =   -7,
+    gcvSTATUS_INVALID_ADDRESS       =   -8,
+    gcvSTATUS_CONTEXT_LOSSED        =   -9,
+    gcvSTATUS_TOO_COMPLEX           =   -10,
+    gcvSTATUS_BUFFER_TOO_SMALL      =   -11,
+    gcvSTATUS_INTERFACE_ERROR       =   -12,
+    gcvSTATUS_NOT_SUPPORTED         =   -13,
+    gcvSTATUS_MORE_DATA             =   -14,
+    gcvSTATUS_TIMEOUT               =   -15,
+    gcvSTATUS_OUT_OF_RESOURCES      =   -16,
+    gcvSTATUS_INVALID_DATA          =   -17,
+    gcvSTATUS_INVALID_MIPMAP        =   -18,
+    gcvSTATUS_NOT_FOUND             =   -19,
+    gcvSTATUS_NOT_ALIGNED           =   -20,
+    gcvSTATUS_INVALID_REQUEST       =   -21,
+    gcvSTATUS_GPU_NOT_RESPONDING    =   -22,
+    gcvSTATUS_TIMER_OVERFLOW        =   -23,
+    gcvSTATUS_VERSION_MISMATCH      =   -24,
+    gcvSTATUS_LOCKED                =   -25,
+    gcvSTATUS_INTERRUPTED           =   -26,
+    gcvSTATUS_DEVICE                =   -27,
+    gcvSTATUS_NOT_MULTI_PIPE_ALIGNED =   -28,
+    gcvSTATUS_OUT_OF_SAMPLER         =   -29,
+
+    /* Linker errors. */
+    gcvSTATUS_GLOBAL_TYPE_MISMATCH              =   -1000,
+    gcvSTATUS_TOO_MANY_ATTRIBUTES               =   -1001,
+    gcvSTATUS_TOO_MANY_UNIFORMS                 =   -1002,
+    gcvSTATUS_TOO_MANY_VARYINGS                 =   -1003,
+    gcvSTATUS_UNDECLARED_VARYING                =   -1004,
+    gcvSTATUS_VARYING_TYPE_MISMATCH             =   -1005,
+    gcvSTATUS_MISSING_MAIN                      =   -1006,
+    gcvSTATUS_NAME_MISMATCH                     =   -1007,
+    gcvSTATUS_INVALID_INDEX                     =   -1008,
+    gcvSTATUS_UNIFORM_MISMATCH                  =   -1009,
+    gcvSTATUS_UNSAT_LIB_SYMBOL                  =   -1010,
+    gcvSTATUS_TOO_MANY_SHADERS                  =   -1011,
+    gcvSTATUS_LINK_INVALID_SHADERS              =   -1012,
+    gcvSTATUS_CS_NO_WORKGROUP_SIZE              =   -1013,
+    gcvSTATUS_LINK_LIB_ERROR                    =   -1014,
+
+    gcvSTATUS_SHADER_VERSION_MISMATCH           =   -1015,
+    gcvSTATUS_TOO_MANY_INSTRUCTION              =   -1016,
+    gcvSTATUS_SSBO_MISMATCH                     =   -1017,
+    gcvSTATUS_TOO_MANY_OUTPUT                   =   -1018,
+    gcvSTATUS_TOO_MANY_INPUT                    =   -1019,
+    gcvSTATUS_NOT_SUPPORT_CL                    =   -1020,
+    gcvSTATUS_NOT_SUPPORT_INTEGER               =   -1021,
+    gcvSTATUS_UNIFORM_TYPE_MISMATCH             =   -1022,
+
+    gcvSTATUS_MISSING_PRIMITIVE_TYPE            =   -1023,
+    gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT       =   -1024,
+    gcvSTATUS_NON_INVOCATION_ID_AS_INDEX        =   -1025,
+    gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH         =   -1026,
+    gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH        =   -1027,
+    gcvSTATUS_LOCATION_ALIASED                  =   -1028,
+    gcvSTATUS_LOCATION_OVERLAP                  =   -1029,
+    gcvSTATUS_LOCATION_NOTCONSISTENT            =   -1030,
+
+    /* Compiler errors. */
+    gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR    =   -2000,
+    gcvSTATUS_COMPILER_FE_PARSER_ERROR          =   -2001,
+
+    /* Recompilation Errors */
+    gcvSTATUS_RECOMPILER_CONVERT_UNIMPLEMENTED  =   -3000,
+}
+gceSTATUS;
+
+/* The patch types. */
+enum _gceHAL_PATCH_TYPE
+{
+    gcvHAL_PATCH_VIDMEM_ADDRESS = 1,
+    gcvHAL_PATCH_MCFE_SEMAPHORE,
+    gcvHAL_PATCH_VIDMEM_TIMESTAMP,
+
+    /* Must be the last one for counting. */
+    gcvHAL_PATCH_TYPE_COUNT,
+};
+
+/******************************************************************************\
+********************************* Command Codes ********************************
+\******************************************************************************/
+
+typedef enum _gceHAL_COMMAND_CODES
+{
+    /*************** Common ***************/
+
+    /* Chip info: count, type and so on. */
+    gcvHAL_CHIP_INFO,
+
+    /* HAL driver version. */
+    gcvHAL_VERSION,
+
+    /* Query chip id and options. */
+    gcvHAL_QUERY_CHIP_IDENTITY,
+    gcvHAL_QUERY_CHIP_OPTION,
+
+    /* Query chip frequency, used by CL. */
+    gcvHAL_QUERY_CHIP_FREQUENCY,
+
+    /* Query system pool video memory, used by CL. */
+    gcvHAL_QUERY_VIDEO_MEMORY,
+
+    /* Memory management. */
+    gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY,
+    gcvHAL_WRAP_USER_MEMORY,
+    gcvHAL_RELEASE_VIDEO_MEMORY,
+    gcvHAL_LOCK_VIDEO_MEMORY,
+    gcvHAL_UNLOCK_VIDEO_MEMORY,
+    gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY,
+    gcvHAL_MAP_MEMORY,
+    gcvHAL_UNMAP_MEMORY,
+
+    /* Cache operations. */
+    gcvHAL_CACHE,
+
+    /* HAL user attach and detach. */
+    gcvHAL_ATTACH,
+    gcvHAL_DETACH,
+
+    /* Event commit. */
+    gcvHAL_EVENT_COMMIT,
+
+    /* User command commit. */
+    gcvHAL_COMMIT,
+
+    /* Set hardware timeout, used by CL. */
+    gcvHAL_SET_TIMEOUT,
+
+    /* User signal operations. */
+    gcvHAL_USER_SIGNAL,
+
+    /* Event signal, commit stall. */
+    gcvHAL_SIGNAL,
+
+    /* Profile related. */
+    gcvHAL_SET_PROFILE_SETTING,
+    gcvHAL_READ_PROFILER_REGISTER_SETTING,
+    gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1,
+    gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2,
+
+    /* Query process database info when debug trace and proflie. */
+    gcvHAL_DATABASE,
+
+    /* Power managment enable/disable. */
+    gcvHAL_CONFIG_POWER_MANAGEMENT,
+
+    /* Debug/dump feature. */
+    gcvHAL_DEBUG_DUMP,
+
+    /*************** Common end ***************/
+
+    /*************** GPU only ***************/
+    /* Register operations, 2D only. */
+    gcvHAL_READ_REGISTER,
+    gcvHAL_WRITE_REGISTER,
+    gcvHAL_PROFILE_REGISTERS_2D,
+
+    /* Get base address for old mmu. */
+    gcvHAL_GET_BASE_ADDRESS,
+
+    /* Read frame database, 3D only. */
+    gcvHAL_GET_FRAME_INFO,
+
+    /* Set video memory meta data. */
+    gcvHAL_SET_VIDEO_MEMORY_METADATA,
+
+    /* Query command buffer, VG only. */
+    gcvHAL_QUERY_COMMAND_BUFFER,
+
+    /* Reset time stamp. */
+    gcvHAL_QUERY_RESET_TIME_STAMP,
+
+    /* Create native fence. */
+    gcvHAL_CREATE_NATIVE_FENCE,
+
+    /* Wait native fence. */
+    gcvHAL_WAIT_NATIVE_FENCE,
+
+    /* Wait until GPU finishes access to a resource. */
+    gcvHAL_WAIT_FENCE,
+
+    /* Video memory node operations. */
+    gcvHAL_EXPORT_VIDEO_MEMORY,
+    gcvHAL_NAME_VIDEO_MEMORY,
+    gcvHAL_IMPORT_VIDEO_MEMORY,
+
+    /* Mutex Operation. */
+    gcvHAL_DEVICE_MUTEX,
+    /*************** GPU only end ***************/
+
+    /*************** DEC only ***************/
+    /* DEC200 test. */
+    gcvHAL_DEC200_TEST,
+
+    /* DEC300 related operations. */
+    gcvHAL_DEC300_READ,
+    gcvHAL_DEC300_WRITE,
+    gcvHAL_DEC300_FLUSH,
+    gcvHAL_DEC300_FLUSH_WAIT,
+    /*************** DEC only end ***************/
+
+    /*************** OS specific ***************/
+
+    /* Android gralloc: shared buffer operations. */
+    gcvHAL_SHBUF,
+
+    /* Android gralloc: get graphic buffer fd. */
+    gcvHAL_GET_GRAPHIC_BUFFER_FD,
+
+    /* Vsimulator only. */
+    gcvHAL_UPDATE_DEBUG_CALLBACK,
+    gcvHAL_CONFIG_CTX_FRAMEWORK,
+
+    /* Non paged memory management backup compatibility, windows, qnx. */
+    gcvHAL_ALLOCATE_NON_PAGED_MEMORY,
+    gcvHAL_FREE_NON_PAGED_MEMORY,
+
+    /* Write user data, windows only. */
+    gcvHAL_WRITE_DATA,
+
+    /*************** OS specific end ***************/
+
+    /*************** Reserved ***************/
+    gcvHAL_SET_IDLE,
+    gcvHAL_RESET,
+
+    /* Command commit done, kernel event only. */
+    gcvHAL_COMMIT_DONE,
+
+    /* Get video memory file description. */
+    gcvHAL_GET_VIDEO_MEMORY_FD,
+
+    /* Get profile setting. */
+    gcvHAL_GET_PROFILE_SETTING,
+
+    /* Read/Write register ex. */
+    gcvHAL_READ_REGISTER_EX,
+    gcvHAL_WRITE_REGISTER_EX,
+
+    /* Power managment state. */
+    gcvHAL_SET_POWER_MANAGEMENT_STATE,
+    gcvHAL_QUERY_POWER_MANAGEMENT_STATE,
+
+    /* Set debug level. */
+    gcvHAL_SET_DEBUG_LEVEL_ZONE,
+
+    /* Dump info. */
+    gcvHAL_DUMP_GPU_STATE,
+    gcvHAL_DUMP_EVENT,
+    gcvHAL_DUMP_GPU_PROFILE,
+
+    /* Timer. */
+    gcvHAL_TIMESTAMP,
+
+    /* FSCALE_VAL. */
+    gcvHAL_SET_FSCALE_VALUE,
+    gcvHAL_GET_FSCALE_VALUE,
+
+    /* Destory MMU. */
+    gcvHAL_DESTROY_MMU,
+    /*************** Reserved end ***************/
+}
+gceHAL_COMMAND_CODES;
+
+/******************************************************************************\
+******************************** gcsOBJECT Object *******************************
+\******************************************************************************/
+
+/* Macro to combine four characters into a Charcater Code. */
+#define gcmCC(c1, c2, c3, c4) \
+(\
+    (char) (c1) \
+    | \
+    ((char) (c2) <<  8) \
+    | \
+    ((char) (c3) << 16) \
+    | \
+    ((char) (c4) << 24) \
+)
+
+/* Type of objects. */
+typedef enum _gceOBJECT_TYPE
+{
+    gcvOBJ_UNKNOWN              = 0,
+    gcvOBJ_2D                   = gcmCC('2','D',' ',' '),
+    gcvOBJ_3D                   = gcmCC('3','D',' ',' '),
+    gcvOBJ_ATTRIBUTE            = gcmCC('A','T','T','R'),
+    gcvOBJ_BRUSHCACHE           = gcmCC('B','R','U','$'),
+    gcvOBJ_BRUSHNODE            = gcmCC('B','R','U','n'),
+    gcvOBJ_BRUSH                = gcmCC('B','R','U','o'),
+    gcvOBJ_BUFFER               = gcmCC('B','U','F','R'),
+    gcvOBJ_COMMAND              = gcmCC('C','M','D',' '),
+    gcvOBJ_COMMANDBUFFER        = gcmCC('C','M','D','B'),
+    gcvOBJ_CONTEXT              = gcmCC('C','T','X','T'),
+    gcvOBJ_DEVICE               = gcmCC('D','E','V',' '),
+    gcvOBJ_DUMP                 = gcmCC('D','U','M','P'),
+    gcvOBJ_EVENT                = gcmCC('E','V','N','T'),
+    gcvOBJ_FUNCTION             = gcmCC('F','U','N','C'),
+    gcvOBJ_HAL                  = gcmCC('H','A','L',' '),
+    gcvOBJ_HARDWARE             = gcmCC('H','A','R','D'),
+    gcvOBJ_HEAP                 = gcmCC('H','E','A','P'),
+    gcvOBJ_INDEX                = gcmCC('I','N','D','X'),
+    gcvOBJ_INTERRUPT            = gcmCC('I','N','T','R'),
+    gcvOBJ_KERNEL               = gcmCC('K','E','R','N'),
+    gcvOBJ_KERNEL_FUNCTION      = gcmCC('K','F','C','N'),
+    gcvOBJ_MEMORYBUFFER         = gcmCC('M','E','M','B'),
+    gcvOBJ_MMU                  = gcmCC('M','M','U',' '),
+    gcvOBJ_OS                   = gcmCC('O','S',' ',' '),
+    gcvOBJ_OUTPUT               = gcmCC('O','U','T','P'),
+    gcvOBJ_PAINT                = gcmCC('P','N','T',' '),
+    gcvOBJ_PATH                 = gcmCC('P','A','T','H'),
+    gcvOBJ_QUEUE                = gcmCC('Q','U','E',' '),
+    gcvOBJ_SAMPLER              = gcmCC('S','A','M','P'),
+    gcvOBJ_SHADER               = gcmCC('S','H','D','R'),
+    gcvOBJ_VIR_SHADER           = gcmCC('V','S','D','R'),
+    gcvOBJ_STREAM               = gcmCC('S','T','R','M'),
+    gcvOBJ_SURF                 = gcmCC('S','U','R','F'),
+    gcvOBJ_TEXTURE              = gcmCC('T','X','T','R'),
+    gcvOBJ_UNIFORM              = gcmCC('U','N','I','F'),
+    gcvOBJ_VARIABLE             = gcmCC('V','A','R','I'),
+    gcvOBJ_VERTEX               = gcmCC('V','R','T','X'),
+    gcvOBJ_VIDMEM               = gcmCC('V','M','E','M'),
+    gcvOBJ_VIDMEM_BLOCK         = gcmCC('V','M','B','K'),
+    gcvOBJ_VG                   = gcmCC('V','G',' ',' '),
+    gcvOBJ_BUFOBJ               = gcmCC('B','U','F','O'),
+    gcvOBJ_UNIFORM_BLOCK        = gcmCC('U','B','L','K'),
+    gcvOBJ_CL                   = gcmCC('C','L',' ',' '),
+    gcvOBJ_STORAGE_BLOCK        = gcmCC('S','B','L','K'),
+    gcvOBJ_IO_BLOCK             = gcmCC('I','O','B','K'),
+}
+gceOBJECT_TYPE;
+
+/* Video memory pool type. */
+typedef enum _gcePOOL
+{
+    gcvPOOL_UNKNOWN = 0,
+    gcvPOOL_DEFAULT,
+    gcvPOOL_LOCAL,
+    gcvPOOL_LOCAL_INTERNAL,
+    gcvPOOL_LOCAL_EXTERNAL,
+    gcvPOOL_UNIFIED,
+    gcvPOOL_SYSTEM,
+    gcvPOOL_SRAM,
+    gcvPOOL_VIRTUAL,
+    gcvPOOL_USER,
+    gcvPOOL_INTERNAL_SRAM,
+    gcvPOOL_EXTERNAL_SRAM,
+
+    gcvPOOL_NUMBER_OF_POOLS
+}
+gcePOOL;
+
+typedef enum _gceDUMP_BUFFER_TYPE
+{
+    gcvDUMP_BUFFER_USER_STRING,
+    gcvDUMP_BUFFER_VERIFY,
+
+    gcvDUMP_BUFFER_MEMORY,
+    gcvDUMP_BUFFER_TEXTURE,
+    gcvDUMP_BUFFER_STREAM,
+    gcvDUMP_BUFFER_INDEX,
+    gcvDUMP_BUFFER_BUFOBJ,
+    gcvDUMP_BUFFER_IMAGE,
+    /* A type of command, but should not execute directly. */
+    gcvDUMP_BUFFER_INSTRUCTION,
+    gcvDUMP_BUFFER_CONTEXT,
+    gcvDUMP_BUFFER_COMMAND,
+    gcvDUMP_BUFFER_ASYNC_COMMAND,
+    gcvDUMP_BUFFER_USER_TYPE_LAST = gcvDUMP_BUFFER_ASYNC_COMMAND,
+
+    gcvDUMP_BUFFER_KERNEL_CONTEXT,
+    gcvDUMP_BUFFER_KERNEL_COMMAND,
+
+    gcvDUMP_BUFFER_PHYSICAL_MEMORY,
+
+    gcvDUMP_BUFFER_TYPE_COUNT,
+}
+gceDUMP_BUFFER_TYPE;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_enum_shared_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_profiler_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_profiler_shared.h
@@ -0,0 +1,281 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_profiler_shared_h_
+#define __gc_hal_profiler_shared_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* HW profile information. */
+typedef struct _gcsPROFILER_COUNTERS_PART1
+{
+    gctUINT32       gpuTotalRead64BytesPerFrame;
+    gctUINT32       gpuTotalWrite64BytesPerFrame;
+
+    /* FE */
+    gctUINT32       fe_draw_count;
+    gctUINT32       fe_out_vertex_count;
+    gctUINT32       fe_cache_miss_count;
+    gctUINT32       fe_cache_lk_count;
+    gctUINT32       fe_stall_count;
+    gctUINT32       fe_starve_count;
+    gctUINT32       fe_process_count;
+
+    /* PE */
+    gctUINT32       pe0_pixel_count_killed_by_color_pipe;
+    gctUINT32       pe0_pixel_count_killed_by_depth_pipe;
+    gctUINT32       pe0_pixel_count_drawn_by_color_pipe;
+    gctUINT32       pe0_pixel_count_drawn_by_depth_pipe;
+    gctUINT32       pe1_pixel_count_killed_by_color_pipe;
+    gctUINT32       pe1_pixel_count_killed_by_depth_pipe;
+    gctUINT32       pe1_pixel_count_drawn_by_color_pipe;
+    gctUINT32       pe1_pixel_count_drawn_by_depth_pipe;
+
+    /* SH */
+    gctUINT32       shader_cycle_count;
+    gctUINT32       vs_shader_cycle_count;
+    gctUINT32       ps_shader_cycle_count;
+    gctUINT32       ps_inst_counter;
+    gctUINT32       ps_rendered_pixel_counter;
+    gctUINT32       vs_inst_counter;
+    gctUINT32       vs_rendered_vertice_counter;
+    gctUINT32       vs_branch_inst_counter;
+    gctUINT32       vs_texld_inst_counter;
+    gctUINT32       ps_branch_inst_counter;
+    gctUINT32       ps_texld_inst_counter;
+    gctUINT32       vs_non_idle_starve_count;
+    gctUINT32       vs_starve_count;
+    gctUINT32       vs_stall_count;
+    gctUINT32       vs_process_count;
+    gctUINT32       ps_non_idle_starve_count;
+    gctUINT32       ps_starve_count;
+    gctUINT32       ps_stall_count;
+    gctUINT32       ps_process_count;
+
+    /* PA */
+    gctUINT32       pa_input_vtx_counter;
+    gctUINT32       pa_input_prim_counter;
+    gctUINT32       pa_output_prim_counter;
+    gctUINT32       pa_depth_clipped_counter;
+    gctUINT32       pa_trivial_rejected_counter;
+    gctUINT32       pa_culled_prim_counter;
+    gctUINT32       pa_droped_prim_counter;
+    gctUINT32       pa_frustum_clipped_prim_counter;
+    gctUINT32       pa_frustum_clipdroped_prim_counter;
+    gctUINT32       pa_non_idle_starve_count;
+    gctUINT32       pa_starve_count;
+    gctUINT32       pa_stall_count;
+    gctUINT32       pa_process_count;
+
+    /* SE */
+    gctUINT32       se_culled_triangle_count;
+    gctUINT32       se_culled_lines_count;
+    gctUINT32       se_clipped_triangle_count;
+    gctUINT32       se_clipped_line_count;
+    gctUINT32       se_starve_count;
+    gctUINT32       se_stall_count;
+    gctUINT32       se_receive_triangle_count;
+    gctUINT32       se_send_triangle_count;
+    gctUINT32       se_receive_lines_count;
+    gctUINT32       se_send_lines_count;
+    gctUINT32       se_process_count;
+    gctUINT32       se_trivial_rejected_line_count;
+    gctUINT32       se_non_idle_starve_count;
+
+    /* RA */
+    gctUINT32       ra_input_prim_count;
+    gctUINT32       ra_total_quad_count;
+    gctUINT32       ra_valid_quad_count_after_early_z;
+    gctUINT32       ra_valid_pixel_count_to_render;
+    gctUINT32       ra_output_valid_quad_count;
+    gctUINT32       ra_output_valid_pixel_count;
+    gctUINT32       ra_pipe_cache_miss_counter;
+    gctUINT32       ra_pipe_hz_cache_miss_counter;
+    gctUINT32       ra_prefetch_cache_miss_counter;
+    gctUINT32       ra_prefetch_hz_cache_miss_counter;
+    gctUINT32       ra_eez_culled_counter;
+    gctUINT32       ra_non_idle_starve_count;
+    gctUINT32       ra_starve_count;
+    gctUINT32       ra_stall_count;
+    gctUINT32       ra_process_count;
+
+    /* TX */
+    gctUINT32       tx_total_bilinear_requests;
+    gctUINT32       tx_total_trilinear_requests;
+    gctUINT32       tx_total_discarded_texture_requests;
+    gctUINT32       tx_total_texture_requests;
+    gctUINT32       tx_mc0_miss_count;
+    gctUINT32       tx_mc0_request_byte_count;
+    gctUINT32       tx_mc1_miss_count;
+    gctUINT32       tx_mc1_request_byte_count;
+    gctUINT32       tx_non_idle_starve_count;
+    gctUINT32       tx_starve_count;
+    gctUINT32       tx_stall_count;
+    gctUINT32       tx_process_count;
+}
+gcsPROFILER_COUNTERS_PART1;
+
+typedef struct _gcsPROFILER_COUNTERS_PART2
+{
+    /* MCC */
+    gctUINT32       mcc_total_read_req_8B_from_colorpipe;
+    gctUINT32       mcc_total_read_req_8B_sentout_from_colorpipe;
+    gctUINT32       mcc_total_write_req_8B_from_colorpipe;
+    gctUINT32       mcc_total_read_req_sentout_from_colorpipe;
+    gctUINT32       mcc_total_write_req_from_colorpipe;
+    gctUINT32       mcc_total_read_req_8B_from_depthpipe;
+    gctUINT32       mcc_total_read_req_8B_sentout_from_depthpipe;
+    gctUINT32       mcc_total_write_req_8B_from_depthpipe;
+    gctUINT32       mcc_total_read_req_sentout_from_depthpipe;
+    gctUINT32       mcc_total_write_req_from_depthpipe;
+    gctUINT32       mcc_total_read_req_8B_from_others;
+    gctUINT32       mcc_total_write_req_8B_from_others;
+    gctUINT32       mcc_total_read_req_from_others;
+    gctUINT32       mcc_total_write_req_from_others;
+    gctUINT32       mcc_axi_total_latency;
+    gctUINT32       mcc_axi_sample_count;
+    gctUINT32       mcc_axi_max_latency;
+    gctUINT32       mcc_axi_min_latency;
+    gctUINT32       mc_fe_read_bandwidth;
+    gctUINT32       mc_mmu_read_bandwidth;
+    gctUINT32       mc_blt_read_bandwidth;
+    gctUINT32       mc_sh0_read_bandwidth;
+    gctUINT32       mc_sh1_read_bandwidth;
+    gctUINT32       mc_pe_write_bandwidth;
+    gctUINT32       mc_blt_write_bandwidth;
+    gctUINT32       mc_sh0_write_bandwidth;
+    gctUINT32       mc_sh1_write_bandwidth;
+
+    /* MCZ */
+    gctUINT32       mcz_total_read_req_8B_from_colorpipe;
+    gctUINT32       mcz_total_read_req_8B_sentout_from_colorpipe;
+    gctUINT32       mcz_total_write_req_8B_from_colorpipe;
+    gctUINT32       mcz_total_read_req_sentout_from_colorpipe;
+    gctUINT32       mcz_total_write_req_from_colorpipe;
+    gctUINT32       mcz_total_read_req_8B_from_depthpipe;
+    gctUINT32       mcz_total_read_req_8B_sentout_from_depthpipe;
+    gctUINT32       mcz_total_write_req_8B_from_depthpipe;
+    gctUINT32       mcz_total_read_req_sentout_from_depthpipe;
+    gctUINT32       mcz_total_write_req_from_depthpipe;
+    gctUINT32       mcz_total_read_req_8B_from_others;
+    gctUINT32       mcz_total_write_req_8B_from_others;
+    gctUINT32       mcz_total_read_req_from_others;
+    gctUINT32       mcz_total_write_req_from_others;
+    gctUINT32       mcz_axi_total_latency;
+    gctUINT32       mcz_axi_sample_count;
+    gctUINT32       mcz_axi_max_latency;
+    gctUINT32       mcz_axi_min_latency;
+
+    /* HI */
+    gctUINT32       hi0_total_read_8B_count;
+    gctUINT32       hi0_total_write_8B_count;
+    gctUINT32       hi0_total_read_request_count;
+    gctUINT32       hi0_total_write_request_count;
+    gctUINT32       hi0_axi_cycles_read_request_stalled;
+    gctUINT32       hi0_axi_cycles_write_request_stalled;
+    gctUINT32       hi0_axi_cycles_write_data_stalled;
+    gctUINT32       hi1_total_read_8B_count;
+    gctUINT32       hi1_total_write_8B_count;
+    gctUINT32       hi1_total_read_request_count;
+    gctUINT32       hi1_total_write_request_count;
+    gctUINT32       hi1_axi_cycles_read_request_stalled;
+    gctUINT32       hi1_axi_cycles_write_request_stalled;
+    gctUINT32       hi1_axi_cycles_write_data_stalled;
+    gctUINT32       hi_total_cycle_count;
+    gctUINT32       hi_total_idle_cycle_count;
+    gctUINT32       hi_total_read_8B_count;
+    gctUINT32       hi_total_write_8B_count;
+    gctUINT32       hi_total_readOCB_16B_count;
+    gctUINT32       hi_total_writeOCB_16B_count;
+
+    /* L2 */
+    gctUINT32       l2_total_axi0_read_request_count;
+    gctUINT32       l2_total_axi1_read_request_count;
+    gctUINT32       l2_total_axi0_write_request_count;
+    gctUINT32       l2_total_axi1_write_request_count;
+    gctUINT32       l2_total_read_transactions_request_by_axi0;
+    gctUINT32       l2_total_read_transactions_request_by_axi1;
+    gctUINT32       l2_total_write_transactions_request_by_axi0;
+    gctUINT32       l2_total_write_transactions_request_by_axi1;
+    gctUINT32       l2_axi0_minmax_latency;
+    gctUINT32       l2_axi0_min_latency;
+    gctUINT32       l2_axi0_max_latency;
+    gctUINT32       l2_axi0_total_latency;
+    gctUINT32       l2_axi0_total_request_count;
+    gctUINT32       l2_axi1_minmax_latency;
+    gctUINT32       l2_axi1_min_latency;
+    gctUINT32       l2_axi1_max_latency;
+    gctUINT32       l2_axi1_total_latency;
+    gctUINT32       l2_axi1_total_request_count;
+}
+gcsPROFILER_COUNTERS_PART2;
+
+typedef struct _gcsPROFILER_COUNTERS
+{
+    gcsPROFILER_COUNTERS_PART1 counters_part1;
+    gcsPROFILER_COUNTERS_PART2 counters_part2;
+}
+gcsPROFILER_COUNTERS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_profiler_shared_h_ */
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_types_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_types_shared.h
@@ -0,0 +1,984 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_types_shared_h_
+#define __gc_hal_types_shared_h_
+
+#if !defined(VIV_KMD)
+#if defined(__KERNEL__)
+#include "linux/version.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+    typedef unsigned long uintptr_t;
+#   endif
+#   include "linux/types.h"
+#elif defined(UNDER_CE)
+#include <crtdefs.h>
+typedef signed char        int8_t;
+typedef short              int16_t;
+typedef int                int32_t;
+typedef long long          int64_t;
+typedef unsigned char      uint8_t;
+typedef unsigned short     uint16_t;
+typedef unsigned int       uint32_t;
+typedef unsigned long long uint64_t;
+#elif defined(_MSC_VER) && (_MSC_VER <= 1500)
+#include <crtdefs.h>
+#include "vadefs.h"
+#elif defined(__QNXNTO__)
+#define _QNX_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#else
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#pragma warning(disable:4127)   /* Conditional expression is constant (do { } while(0)). */
+#pragma warning(disable:4100)   /* Unreferenced formal parameter. */
+#pragma warning(disable:4204)   /* Non-constant aggregate initializer (C99). */
+#pragma warning(disable:4131)   /* Uses old-style declarator. */
+#pragma warning(disable:4206)   /* Translation unit is empty. */
+#pragma warning(disable:4214)   /* Nonstandard extension used :
+                                ** bit field types other than int. */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+**  Platform macros.
+*/
+
+#if defined(__GNUC__)
+#   define gcdHAS_ELLIPSIS      1       /* GCC always has it. */
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#   define gcdHAS_ELLIPSIS      1       /* C99 has it. */
+#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
+#   define gcdHAS_ELLIPSIS      1       /* MSVC 2007+ has it. */
+#elif defined(UNDER_CE)
+#if UNDER_CE >= 600
+#       define gcdHAS_ELLIPSIS  1
+#   else
+#       define gcdHAS_ELLIPSIS  0
+#   endif
+#else
+#   error "gcdHAS_ELLIPSIS: Platform could not be determined"
+#endif
+
+/******************************************************************************\
+************************************ Keyword ***********************************
+\******************************************************************************/
+
+#if defined(ANDROID) && defined(__BIONIC_FORTIFY)
+#if defined(__clang__)
+#       define gcmINLINE            __inline__ __attribute__ ((always_inline)) __attribute__ ((gnu_inline))
+#   else
+#       define gcmINLINE            __inline__ __attribute__ ((always_inline)) __attribute__ ((gnu_inline)) __attribute__ ((artificial))
+#   endif
+#elif ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__APPLE__))
+#   define gcmINLINE            inline      /* C99 keyword. */
+#elif defined(__GNUC__)
+#   define gcmINLINE            __inline__  /* GNU keyword. */
+#elif defined(_MSC_VER) || defined(UNDER_CE)
+#   define gcmINLINE            __inline    /* Internal keyword. */
+#else
+#   error "gcmINLINE: Platform could not be determined"
+#endif
+
+
+/* Possible debug flags. */
+#define gcdDEBUG_NONE           0
+#define gcdDEBUG_ALL            (1 << 0)
+#define gcdDEBUG_FATAL          (1 << 1)
+#define gcdDEBUG_TRACE          (1 << 2)
+#define gcdDEBUG_BREAK          (1 << 3)
+#define gcdDEBUG_ASSERT         (1 << 4)
+#define gcdDEBUG_CODE           (1 << 5)
+#define gcdDEBUG_STACK          (1 << 6)
+
+#define gcmIS_DEBUG(flag)       (gcdDEBUG & (flag | gcdDEBUG_ALL) )
+
+#ifndef gcdDEBUG
+#if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG)
+#       define gcdDEBUG         gcdDEBUG_ALL
+#   else
+#       define gcdDEBUG         gcdDEBUG_NONE
+#   endif
+#endif
+
+#ifdef _USRDLL
+#ifdef _MSC_VER
+#ifdef HAL_EXPORTS
+#           define HALAPI       __declspec(dllexport)
+#       else
+#           define HALAPI       __declspec(dllimport)
+#       endif
+#       define HALDECL          __cdecl
+#   else
+#ifdef HAL_EXPORTS
+#           define HALAPI
+#       else
+#           define HALAPI       extern
+#       endif
+#   endif
+#else
+#   define HALAPI
+#   define HALDECL
+#endif
+
+/******************************************************************************\
+********************************** Common Types ********************************
+\******************************************************************************/
+
+#define gcvFALSE                0
+#define gcvTRUE                 1
+
+#define gcvINFINITE             ((gctUINT32) ~0U)
+
+#define gcvINVALID_HANDLE       ((gctHANDLE) ~0U)
+
+typedef int                     gctBOOL;
+typedef gctBOOL *               gctBOOL_PTR;
+
+typedef int                     gctINT;
+typedef signed char             gctINT8;
+typedef signed short            gctINT16;
+typedef signed int              gctINT32;
+typedef signed long long        gctINT64;
+
+typedef gctINT *                gctINT_PTR;
+typedef gctINT8 *               gctINT8_PTR;
+typedef gctINT16 *              gctINT16_PTR;
+typedef gctINT32 *              gctINT32_PTR;
+typedef gctINT64 *              gctINT64_PTR;
+
+typedef unsigned int            gctUINT;
+typedef unsigned char           gctUINT8;
+typedef unsigned short          gctUINT16;
+typedef unsigned int            gctUINT32;
+typedef unsigned long long      gctUINT64;
+typedef uintptr_t               gctUINTPTR_T;
+typedef ptrdiff_t               gctPTRDIFF_T;
+
+typedef gctUINT *               gctUINT_PTR;
+typedef gctUINT8 *              gctUINT8_PTR;
+typedef gctUINT16 *             gctUINT16_PTR;
+typedef gctUINT32 *             gctUINT32_PTR;
+typedef gctUINT64 *             gctUINT64_PTR;
+
+typedef size_t                  gctSIZE_T;
+typedef gctSIZE_T *             gctSIZE_T_PTR;
+typedef gctUINT32               gctTRACE;
+
+#ifdef __cplusplus
+#   define gcvNULL              0
+#else
+#   define gcvNULL              ((void *) 0)
+#endif
+
+#define gcvMAXINT8              0x7f
+#define gcvMININT8              0x80
+#define gcvMAXINT16             0x7fff
+#define gcvMININT16             0x8000
+#define gcvMAXINT32             0x7fffffff
+#define gcvMININT32             0x80000000
+#define gcvMAXINT64             0x7fffffffffffffff
+#define gcvMININT64             0x8000000000000000
+#define gcvMAXUINT8             0xff
+#define gcvMINUINT8             0x0
+#define gcvMAXUINT16            0xffff
+#define gcvMINUINT16            0x0
+#define gcvMAXUINT32            0xffffffff
+#define gcvMINUINT32            0x0
+#define gcvMAXUINT64            0xffffffffffffffff
+#define gcvMINUINT64            0x0
+#define gcvMAXUINTPTR_T         (~(gctUINTPTR_T)0)
+#define gcvMAXSIZE_T            ((gctSIZE_T)(-1))
+
+typedef float                   gctFLOAT;
+typedef signed int              gctFIXED_POINT;
+typedef float *                 gctFLOAT_PTR;
+
+typedef void *                  gctPHYS_ADDR;
+typedef void *                  gctHANDLE;
+typedef void *                  gctFILE;
+typedef void *                  gctSIGNAL;
+typedef void *                  gctWINDOW;
+typedef void *                  gctIMAGE;
+typedef void *                  gctSHBUF;
+
+typedef void *                  gctSEMAPHORE;
+
+typedef void *                  gctPOINTER;
+typedef const void *            gctCONST_POINTER;
+
+typedef char                    gctCHAR;
+typedef signed char             gctSIGNED_CHAR;
+typedef unsigned char           gctUNSIGNED_CHAR;
+typedef char *                  gctSTRING;
+typedef const char *            gctCONST_STRING;
+
+typedef gctUINT64               gctPHYS_ADDR_T;
+
+typedef struct _gcsCOUNT_STRING
+{
+    gctSIZE_T                   Length;
+    gctCONST_STRING             String;
+}
+gcsCOUNT_STRING;
+
+typedef union _gcuFLOAT_UINT32
+{
+    gctFLOAT    f;
+    gctUINT32   u;
+}
+gcuFLOAT_UINT32;
+
+/* Fixed point constants. */
+#define gcvZERO_X               ((gctFIXED_POINT) 0x00000000)
+#define gcvHALF_X               ((gctFIXED_POINT) 0x00008000)
+#define gcvONE_X                ((gctFIXED_POINT) 0x00010000)
+#define gcvNEGONE_X             ((gctFIXED_POINT) 0xFFFF0000)
+#define gcvTWO_X                ((gctFIXED_POINT) 0x00020000)
+
+
+
+#define gcmFIXEDCLAMP_NEG1_TO_1(_x) \
+    (((_x) < gcvNEGONE_X) \
+        ? gcvNEGONE_X \
+        : (((_x) > gcvONE_X) \
+            ? gcvONE_X \
+            : (_x)))
+
+#define gcmFLOATCLAMP_NEG1_TO_1(_f) \
+    (((_f) < -1.0f) \
+        ? -1.0f \
+        : (((_f) > 1.0f) \
+            ? 1.0f \
+            : (_f)))
+
+
+#define gcmFIXEDCLAMP_0_TO_1(_x) \
+    (((_x) < 0) \
+        ? 0 \
+        : (((_x) > gcvONE_X) \
+            ? gcvONE_X \
+            : (_x)))
+
+#define gcmFLOATCLAMP_0_TO_1(_f) \
+    (((_f) < 0.0f) \
+        ? 0.0f \
+        : (((_f) > 1.0f) \
+            ? 1.0f \
+            : (_f)))
+
+
+/******************************************************************************\
+******************************* Multicast Values *******************************
+\******************************************************************************/
+
+/* Value unions. */
+typedef union _gcuVALUE
+{
+    gctUINT                     uintValue;
+    gctFIXED_POINT              fixedValue;
+    gctFLOAT                    floatValue;
+    gctINT                      intValue;
+}
+gcuVALUE;
+
+
+
+
+/* Stringizing macro. */
+#define gcmSTRING(Value)        #Value
+
+/******************************************************************************\
+******************************* Fixed Point Math *******************************
+\******************************************************************************/
+
+#define gcmXMultiply(x1, x2)            gcoMATH_MultiplyFixed(x1, x2)
+#define gcmXDivide(x1, x2)              gcoMATH_DivideFixed(x1, x2)
+#define gcmXMultiplyDivide(x1, x2, x3)  gcoMATH_MultiplyDivideFixed(x1, x2, x3)
+
+/* 2D Engine profile. */
+typedef struct _gcs2D_PROFILE
+{
+    /* Cycle count.
+       32bit counter incremented every 2D clock cycle.
+       Wraps back to 0 when the counter overflows.
+    */
+    gctUINT32 cycleCount;
+
+    /* Pixels rendered by the 2D engine.
+       Resets to 0 every time it is read. */
+    gctUINT32 pixelsRendered;
+}
+gcs2D_PROFILE;
+
+#define gcmPRINTABLE(c)         ((((c) >= ' ') && ((c) <= '}')) ? ((c) != '%' ?  (c) : ' ') : ' ')
+
+#define gcmCC_PRINT(cc) \
+    gcmPRINTABLE((char) ((cc)        & 0xFF)), \
+    gcmPRINTABLE((char) (((cc) >>  8) & 0xFF)), \
+    gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \
+    gcmPRINTABLE((char) (((cc) >> 24) & 0xFF))
+
+/******************************************************************************\
+****************************** Function Parameters *****************************
+\******************************************************************************/
+
+#define IN
+#define OUT
+#define INOUT
+#define OPTIONAL
+
+/******************************************************************************\
+********************************* Status Macros ********************************
+\******************************************************************************/
+
+#define gcmIS_ERROR(status)         (status < 0)
+#define gcmNO_ERROR(status)         (status >= 0)
+#define gcmIS_SUCCESS(status)       (status == gcvSTATUS_OK)
+
+/******************************************************************************\
+********************************* Field Macros *********************************
+\******************************************************************************/
+
+#define __gcmSTART(reg_field) \
+    (0 ? reg_field)
+
+#define __gcmEND(reg_field) \
+    (1 ? reg_field)
+
+#define __gcmGETSIZE(reg_field) \
+    (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1)
+
+#define __gcmALIGN(data, reg_field) \
+    (((gctUINT32) (data)) << __gcmSTART(reg_field))
+
+#define __gcmMASK(reg_field) \
+    ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \
+        ?  ~0U \
+        : (~(~0U << __gcmGETSIZE(reg_field)))))
+
+/*******************************************************************************
+**
+**  gcmFIELDMASK
+**
+**      Get aligned field mask.
+**
+**  ARGUMENTS:
+**
+**      reg     Name of register.
+**      field   Name of field within register.
+*/
+#define gcmFIELDMASK(reg, field) \
+(\
+    __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+**  gcmGETFIELD
+**
+**      Extract the value of a field from specified data.
+**
+**  ARGUMENTS:
+**
+**      data    Data value.
+**      reg     Name of register.
+**      field   Name of field within register.
+*/
+#define gcmGETFIELD(data, reg, field) \
+(\
+    ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \
+        & __gcmMASK(reg##_##field)) \
+)
+
+/*******************************************************************************
+**
+**  gcmSETFIELD
+**
+**      Set the value of a field within specified data.
+**
+**  ARGUMENTS:
+**
+**      data    Data value.
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Value for field.
+*/
+#define gcmSETFIELD(data, reg, field, value) \
+(\
+    (((gctUINT32) (data)) \
+        & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \
+        |  __gcmALIGN((gctUINT32) (value) \
+            & __gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+**  gcmSETFIELDVALUE
+**
+**      Set the value of a field within specified data with a
+**      predefined value.
+**
+**  ARGUMENTS:
+**
+**      data    Data value.
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Name of the value within the field.
+*/
+#define gcmSETFIELDVALUE(data, reg, field, value) \
+(\
+    (((gctUINT32) (data)) \
+        & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \
+        |  __gcmALIGN(reg##_##field##_##value \
+            & __gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+**  gcmGETMASKEDFIELDMASK
+**
+**      Determine field mask of a masked field.
+**
+**  ARGUMENTS:
+**
+**      reg     Name of register.
+**      field   Name of field within register.
+*/
+#define gcmGETMASKEDFIELDMASK(reg, field) \
+(\
+    gcmSETFIELD(0, reg, field, ~0U) | \
+    gcmSETFIELD(0, reg, MASK_ ## field, ~0U)   \
+)
+
+/*******************************************************************************
+**
+**  gcmSETMASKEDFIELD
+**
+**      Set the value of a masked field with specified data.
+**
+**  ARGUMENTS:
+**
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Value for field.
+*/
+#define gcmSETMASKEDFIELD(reg, field, value) \
+(\
+    gcmSETFIELD     (~0U, reg, field, value) & \
+    gcmSETFIELDVALUE(~0U, reg, MASK_ ## field, ENABLED) \
+)
+
+/*******************************************************************************
+**
+**  gcmSETMASKEDFIELDVALUE
+**
+**      Set the value of a masked field with specified data.
+**
+**  ARGUMENTS:
+**
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Value for field.
+*/
+#define gcmSETMASKEDFIELDVALUE(reg, field, value) \
+(\
+    gcmSETFIELDVALUE(~0U, reg, field, value) & \
+    gcmSETFIELDVALUE(~0U, reg, MASK_ ## field, ENABLED) \
+)
+
+/*******************************************************************************
+**
+**  gcmVERIFYFIELDVALUE
+**
+**      Verify if the value of a field within specified data equals a
+**      predefined value.
+**
+**  ARGUMENTS:
+**
+**      data    Data value.
+**      reg     Name of register.
+**      field   Name of field within register.
+**      value   Name of the value within the field.
+*/
+#define gcmVERIFYFIELDVALUE(data, reg, field, value) \
+(\
+    (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \
+                             __gcmMASK(reg##_##field)) \
+        == \
+    (reg##_##field##_##value & __gcmMASK(reg##_##field)) \
+)
+
+/*******************************************************************************
+**  Bit field macros.
+*/
+
+#define __gcmSTARTBIT(Field) \
+    (1 ? Field )
+
+#define __gcmBITSIZE(Field) \
+    (0 ? Field )
+
+#define __gcmBITMASK(Field) \
+(\
+    (1 << __gcmBITSIZE(Field)) - 1 \
+)
+
+#define gcmGETBITS(Value, Type, Field) \
+(\
+    (((Type) (Value)) >> __gcmSTARTBIT(Field) ) \
+    & \
+    __gcmBITMASK(Field) \
+)
+
+#define gcmSETBITS(Value, Type, Field, NewValue) \
+(\
+    (((Type) (Value)) \
+    & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \
+    ) \
+    | \
+    ((((Type) (NewValue)) \
+      & __gcmBITMASK(Field) \
+      ) << __gcmSTARTBIT(Field) \
+    ) \
+)
+
+/*******************************************************************************
+**
+**  gcmISINREGRANGE
+**
+**      Verify whether the specified address is in the register range.
+**
+**  ARGUMENTS:
+**
+**      Address Address to be verified.
+**      Name    Name of a register.
+*/
+
+#define gcmISINREGRANGE(Address, Name) \
+(\
+    ((Address & (~0U << Name ## _LSB)) == (Name ## _Address >> 2)) \
+)
+
+/******************************************************************************\
+******************************** Ceiling Macro ********************************
+\******************************************************************************/
+#define gcmCEIL(x) (((x) - (gctUINT32)(x)) == 0 ? (gctUINT32)(x) : (gctUINT32)(x) + 1)
+
+/******************************************************************************\
+******************************** Min/Max Macros ********************************
+\******************************************************************************/
+
+#define gcmMIN(x, y)            (((x) <= (y)) ?  (x) :  (y))
+#define gcmMAX(x, y)            (((x) >= (y)) ?  (x) :  (y))
+#define gcmCLAMP(x, min, max)   (((x) < (min)) ? (min) : \
+                                 ((x) > (max)) ? (max) : (x))
+#define gcmABS(x)               (((x) < 0)    ? -(x) :  (x))
+#define gcmNEG(x)               (((x) < 0)    ?  (x) : -(x))
+
+/******************************************************************************\
+******************************** Bit Macro ********************************
+\******************************************************************************/
+#define gcmBITSET(x, bit)         ((x) | (1 << (bit)))
+#define gcmBITCLEAR(x, bit)       ((x) & ~(1 << (bit)))
+#define gcmBITTEST(x, bit)        ((x) & (1 << (bit)))
+
+/*******************************************************************************
+**
+**  gcmPTR2SIZE
+**
+**      Convert a pointer to an integer value.
+**
+**  ARGUMENTS:
+**
+**      p       Pointer value.
+*/
+#define gcmPTR2SIZE(p) \
+(\
+    (gctUINTPTR_T) (p) \
+)
+
+#define gcmPTR2INT32(p) \
+(\
+    (gctUINT32)(gctUINTPTR_T) (p) \
+)
+
+/*******************************************************************************
+**
+**  gcmINT2PTR
+**
+**      Convert an integer value into a pointer.
+**
+**  ARGUMENTS:
+**
+**      v       Integer value.
+*/
+
+#define gcmINT2PTR(i) \
+(\
+    (gctPOINTER) (gctUINTPTR_T)(i) \
+)
+
+/*******************************************************************************
+**
+**  gcmOFFSETOF
+**
+**      Compute the byte offset of a field inside a structure.
+**
+**  ARGUMENTS:
+**
+**      s       Structure name.
+**      field   Field name.
+*/
+#define gcmOFFSETOF(s, field) \
+(\
+    gcmPTR2INT32(& (((struct s *) 0)->field)) \
+)
+
+#define __gcmOFFSETOF(type, field) \
+(\
+    gcmPTR2INT32(& (((type *) 0)->field)) \
+)
+
+/*******************************************************************************
+**
+**  gcmCONTAINEROF
+**
+**      Get containing structure of a member.
+**
+**  ARGUMENTS:
+**
+**      Pointer Pointer of member.
+**      Type    Structure name.
+**      Name    Field name.
+*/
+#define gcmCONTAINEROF(Pointer, Type, Member) \
+(\
+    (Type *)((gctUINTPTR_T)Pointer - __gcmOFFSETOF(Type, Member)) \
+)
+
+/*******************************************************************************
+**
+** gcmBSWAP32
+**
+**      Return a value with all bytes in the 32 bit argument swapped.
+*/
+#if !defined(__KERNEL__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ >= 40300) \
+   && !defined(__VXWORKS__)
+#  define gcmBSWAP32(x)     __builtin_bswap32(x)
+#else
+#  define gcmBSWAP32(x) ((gctUINT32)(\
+        (((gctUINT32)(x) & (gctUINT32)0x000000FFUL) << 24) | \
+        (((gctUINT32)(x) & (gctUINT32)0x0000FF00UL) << 8)  | \
+        (((gctUINT32)(x) & (gctUINT32)0x00FF0000UL) >> 8)  | \
+        (((gctUINT32)(x) & (gctUINT32)0xFF000000UL) >> 24)))
+#endif
+
+/*******************************************************************************
+***** Database ****************************************************************/
+
+typedef struct _gcsDATABASE_COUNTERS
+{
+    /* Number of currently allocated bytes. */
+    gctUINT64                   bytes;
+
+    /* Maximum number of bytes allocated (memory footprint). */
+    gctUINT64                   maxBytes;
+
+    /* Total number of bytes allocated. */
+    gctUINT64                   totalBytes;
+
+    /* The numbers of times video memory was allocated. */
+    gctUINT32                   allocCount;
+
+    /* The numbers of times video memory was freed. */
+    gctUINT32                   freeCount;
+}
+gcsDATABASE_COUNTERS;
+
+typedef struct _gcuDATABASE_INFO
+{
+    /* Counters. */
+    gcsDATABASE_COUNTERS        counters;
+
+    /* Time value. */
+    gctUINT64                   time;
+}
+gcuDATABASE_INFO;
+
+/*******************************************************************************
+***** Frame database **********************************************************/
+
+/* gcsHAL_FRAME_INFO */
+typedef struct _gcsHAL_FRAME_INFO
+{
+    /* Current timer tick. */
+    OUT gctUINT64               ticks;
+
+    /* Bandwidth counters. */
+    OUT gctUINT                 readBytes8[8];
+    OUT gctUINT                 writeBytes8[8];
+
+    /* Counters. */
+    OUT gctUINT                 cycles[8];
+    OUT gctUINT                 idleCycles[8];
+    OUT gctUINT                 mcCycles[8];
+    OUT gctUINT                 readRequests[8];
+    OUT gctUINT                 writeRequests[8];
+
+    /* 3D counters. */
+    OUT gctUINT                 vertexCount;
+    OUT gctUINT                 primitiveCount;
+    OUT gctUINT                 rejectedPrimitives;
+    OUT gctUINT                 culledPrimitives;
+    OUT gctUINT                 clippedPrimitives;
+    OUT gctUINT                 outPrimitives;
+    OUT gctUINT                 inPrimitives;
+    OUT gctUINT                 culledQuadCount;
+    OUT gctUINT                 totalQuadCount;
+    OUT gctUINT                 quadCount;
+    OUT gctUINT                 totalPixelCount;
+
+    /* PE counters. */
+    OUT gctUINT                 colorKilled[8];
+    OUT gctUINT                 colorDrawn[8];
+    OUT gctUINT                 depthKilled[8];
+    OUT gctUINT                 depthDrawn[8];
+
+    /* Shader counters. */
+    OUT gctUINT                 shaderCycles;
+    OUT gctUINT                 vsInstructionCount;
+    OUT gctUINT                 vsTextureCount;
+    OUT gctUINT                 psInstructionCount;
+    OUT gctUINT                 psTextureCount;
+
+    /* Texture counters. */
+    OUT gctUINT                 bilinearRequests;
+    OUT gctUINT                 trilinearRequests;
+    OUT gctUINT                 txBytes8;
+    OUT gctUINT                 txHitCount;
+    OUT gctUINT                 txMissCount;
+}
+gcsHAL_FRAME_INFO;
+
+typedef struct _gckLINKDATA * gckLINKDATA;
+struct _gckLINKDATA
+{
+    gctUINT32                   start;
+    gctUINT32                   end;
+    gctUINT32                   pid;
+    gctUINT32                   linkLow;
+    gctUINT32                   linkHigh;
+};
+
+typedef struct _gckADDRESSDATA * gckADDRESSDATA;
+struct _gckADDRESSDATA
+{
+    gctUINT32                   start;
+    gctUINT32                   end;
+};
+
+typedef union _gcuQUEUEDATA
+{
+    struct _gckLINKDATA         linkData;
+
+    struct _gckADDRESSDATA      addressData;
+}
+gcuQUEUEDATA;
+
+typedef struct _gckQUEUE * gckQUEUE;
+struct _gckQUEUE
+{
+    gcuQUEUEDATA *              datas;
+    gctUINT32                   rear;
+    gctUINT32                   front;
+    gctUINT32                   count;
+    gctUINT32                   size;
+};
+
+typedef struct _gcsLISTHEAD * gcsLISTHEAD_PTR;
+typedef struct _gcsLISTHEAD
+{
+    gcsLISTHEAD_PTR     prev;
+    gcsLISTHEAD_PTR     next;
+}
+gcsLISTHEAD;
+
+/*
+ * 'Patch' here means a mechanism to let kernel side modify user space reserved
+ * command buffer location, or something the like, during the command buffer
+ * commit.
+ *
+ * Reasons of using 'patch':
+ * 1. Some resources/states are managed globally only in kernel side, such as
+ *    MCFE semaphore, etc.
+ * 2. For the sake of security or optimization, like video memory address.
+ *
+ * Patches are arranged in arrays, each array has the same type. The 'patchArray'
+ * in 'gcsHAL_PATCH_LIST' pointers the concrete patch item array.
+ *
+ * NOTICE:
+ * Be aware of the order and values! Tables in gc_hal_user_buffer.c and
+ * gc_hal_kernel_command.c depend on this.
+ */
+/* The patch array. */
+typedef struct _gcsHAL_PATCH_LIST
+{
+    /* Patch type. */
+    gctUINT32           type;
+
+    /* Patch item count. */
+    gctUINT32           count;
+
+    /*
+     * Pointer to the patch items.
+     *
+     * gcsHAL_PATCH_VIDMEM_ADDRESS * patchArray;
+     * gcsHAL_PATCH_MCFE_SEMAPHORE * patchArray;
+     * gcsHAL_PATCH_VIDMEM_TIMESTAMP * patchArray;
+     * ...
+     */
+    gctUINT64           patchArray;
+
+    /* struct _gcsHAL_PATCH_LIST * next; */
+    gctUINT64           next;
+}
+gcsHAL_PATCH_LIST;
+
+/*
+ * Patch a GPU address in the place (gcvHAL_PATCH_VIDMEM_ADDRESS).
+ * Size of a GPU address is always 32 bits.
+ */
+typedef struct _gcsHAL_PATCH_VIDMEM_ADDRESS
+{
+    /* Patch location in the command buffer. */
+    gctUINT32           location;
+
+    /* Handle of the video memory node. */
+    gctUINT32           node;
+
+    /* Address offset in the video memory node. */
+    gctUINT32           offset;
+}
+gcsHAL_PATCH_VIDMEM_ADDRESS;
+
+/*
+ * Patch a MCFE semaphore command in the place (gcvHAL_PATCH_MCFE_SEMAPHORE).
+ * Size of the semaphore command is fixed at _64_ bits!
+ */
+typedef struct _gcsHAL_PATCH_MCFE_SEMAPHORE
+{
+    /* Patch location in the command buffer. */
+    gctUINT32           location;
+
+    /* semaphore direction: 1 = Send, 0 = Wait. */
+    gctUINT32           sendSema;
+
+    /* Handle of the semaphore. */
+    gctUINT32           semaHandle;
+}
+gcsHAL_PATCH_MCFE_SEMAPHORE;
+
+/*
+ * Patch timestamp of given video memory node (gcvHAL_PATCH_VIDMEM_TIMESTAMP).
+ * Pure software-wise, not command relevant.
+ */
+typedef struct _gcsHAL_PATCH_VIDMEM_TIMESTAMP
+{
+    /* Handle of a video memory node. */
+    gctUINT32           handle;
+
+    gctUINT32           flag;
+}
+gcsHAL_PATCH_VIDMEM_TIMESTAMP;
+
+/*
+    gcvFEATURE_DATABASE_DATE_MASK
+
+    Mask used to control which bits of chip date will be used to
+    query feature database, ignore release date for fpga and emulator.
+*/
+#if (gcdFPGA_BUILD || defined(EMULATOR))
+#   define gcvFEATURE_DATABASE_DATE_MASK    (0U)
+#else
+#   define gcvFEATURE_DATABASE_DATE_MASK    (~0U)
+#endif
+
+#if defined(__GNUC__)
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define gcdENDIAN_BIG   1
+#else
+#define gcdENDIAN_BIG   0
+#endif
+#else
+#define gcdENDIAN_BIG   0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_types_shared_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_vg_shared.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/kernel/inc/shared/gc_hal_vg_shared.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_shared_vg_h_
+#define __gc_hal_shared_vg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Command buffer header. */
+typedef struct _gcsCMDBUFFER * gcsCMDBUFFER_PTR;
+typedef struct _gcsCMDBUFFER
+{
+    /* Pointer to the completion signal. */
+    gcsCOMPLETION_SIGNAL_PTR    completion;
+
+    /* The user sets this to the node of the container buffer whitin which
+       this particular command buffer resides. The kernel sets this to the
+       node of the internally allocated buffer. */
+    gcuVIDMEM_NODE_PTR          node;
+
+    /* Command buffer hardware address. */
+    gctUINT32                   address;
+
+    /* The offset of the buffer from the beginning of the header. */
+    gctUINT32                   bufferOffset;
+
+    /* Size of the area allocated for the data portion of this particular
+       command buffer (headers and tail reserves are excluded). */
+    gctUINT32                   size;
+
+    /* Offset into the buffer [0..size]; reflects exactly how much data has
+       been put into the command buffer. */
+    gctUINT                     offset;
+
+    /* The number of command units in the buffer for the hardware to
+       execute. */
+    gctUINT32                   dataCount;
+
+    /* MANAGED BY : user HAL (gcoBUFFER object).
+       USED BY    : user HAL (gcoBUFFER object).
+       Points to the immediate next allocated command buffer. */
+    gcsCMDBUFFER_PTR            nextAllocated;
+
+    /* MANAGED BY : user layers (HAL and drivers).
+       USED BY    : kernel HAL (gcoBUFFER object).
+       Points to the next subbuffer if any. A family of subbuffers are chained
+       together and are meant to be executed inseparably as a unit. Meaning
+       that context switching cannot occur while a chain of subbuffers is being
+       executed. */
+    gcsCMDBUFFER_PTR            nextSubBuffer;
+}
+gcsCMDBUFFER;
+
+/* Command queue element. */
+typedef struct _gcsVGCMDQUEUE
+{
+    /* Pointer to the command buffer header. */
+    gcsCMDBUFFER_PTR            commandBuffer;
+
+    /* Dynamic vs. static command buffer state. */
+    gctBOOL                     dynamic;
+}
+gcsVGCMDQUEUE;
+
+/* Context map entry. */
+typedef struct _gcsVGCONTEXT_MAP
+{
+    /* State index. */
+    gctUINT32                   index;
+
+    /* New state value. */
+    gctUINT32                   data;
+
+    /* Points to the next entry in the mod list. */
+    gcsVGCONTEXT_MAP_PTR            next;
+}
+gcsVGCONTEXT_MAP;
+
+/* gcsVGCONTEXT structure that holds the current context. */
+typedef struct _gcsVGCONTEXT
+{
+    /* Context ID. */
+    gctUINT64                   id;
+
+    /* State caching ebable flag. */
+    gctBOOL                     stateCachingEnabled;
+
+    /* Current pipe. */
+    gctUINT32                   currentPipe;
+
+    /* State map/mod buffer. */
+    gctUINT32                   mapFirst;
+    gctUINT32                   mapLast;
+    gcsVGCONTEXT_MAP_PTR        mapContainer;
+    gcsVGCONTEXT_MAP_PTR        mapPrev;
+    gcsVGCONTEXT_MAP_PTR        mapCurr;
+    gcsVGCONTEXT_MAP_PTR        firstPrevMap;
+    gcsVGCONTEXT_MAP_PTR        firstCurrMap;
+
+    /* Main context buffer. */
+    gcsCMDBUFFER_PTR            header;
+    gctUINT32_PTR               buffer;
+
+    /* Completion signal. */
+    gctHANDLE                   process;
+    gctSIGNAL                   signal;
+
+#if defined(__QNXNTO__)
+    gctSIGNAL                   userSignal;
+    gctINT32                    coid;
+    gctINT32                    rcvid;
+#endif
+}
+gcsVGCONTEXT;
+
+/* User space task header. */
+typedef struct _gcsTASK * gcsTASK_PTR;
+typedef struct _gcsTASK
+{
+    /* Pointer to the next task for the same interrupt in user space. */
+    gcsTASK_PTR                 next;
+
+    /* Size of the task data that immediately follows the structure. */
+    gctUINT                     size;
+
+    /* Task data starts here. */
+    /* ... */
+}
+gcsTASK;
+
+/* User space task master table entry. */
+typedef struct _gcsTASK_MASTER_ENTRY * gcsTASK_MASTER_ENTRY_PTR;
+typedef struct _gcsTASK_MASTER_ENTRY
+{
+    /* Pointers to the head and to the tail of the task chain. */
+    gcsTASK_PTR                 head;
+    gcsTASK_PTR                 tail;
+}
+gcsTASK_MASTER_ENTRY;
+
+/* User space task master table entry. */
+typedef struct _gcsTASK_MASTER_TABLE
+{
+    /* Table with one entry per block. */
+    gcsTASK_MASTER_ENTRY        table[gcvBLOCK_COUNT];
+
+    /* The total number of tasks sckeduled. */
+    gctUINT                     count;
+
+    /* The total size of event data in bytes. */
+    gctUINT                     size;
+
+#if defined(__QNXNTO__)
+    gctINT32                    coid;
+    gctINT32                    rcvid;
+#endif
+}
+gcsTASK_MASTER_TABLE;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __gc_hal_shared_h_ */
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_array_h_
+#define __gc_hal_kernel_allocator_array_h_
+
+extern gceSTATUS
+_GFPAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+extern gceSTATUS
+_UserMemoryAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+extern gceSTATUS
+_ReservedMemoryAllocatorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+extern gceSTATUS
+_DmabufAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+#endif
+
+#ifndef NO_DMA_COHERENT
+extern gceSTATUS
+_DmaAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+#endif
+
+/* Default allocator entry. */
+gcsALLOCATOR_DESC allocatorArray[] =
+{
+    /* GFP allocator. */
+    gcmkDEFINE_ALLOCATOR_DESC("gfp", _GFPAlloctorInit),
+
+    /* User memory importer. */
+    gcmkDEFINE_ALLOCATOR_DESC("user", _UserMemoryAlloctorInit),
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+    /* Dmabuf allocator. */
+    gcmkDEFINE_ALLOCATOR_DESC("dmabuf", _DmabufAlloctorInit),
+#endif
+
+#ifndef NO_DMA_COHERENT
+    gcmkDEFINE_ALLOCATOR_DESC("dma", _DmaAlloctorInit),
+#endif
+
+    gcmkDEFINE_ALLOCATOR_DESC("reserved-mem", _ReservedMemoryAllocatorInit),
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c
@@ -0,0 +1,638 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)
+#include <linux/dma-direct.h>
+#endif
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+typedef struct _gcsDMA_PRIV * gcsDMA_PRIV_PTR;
+typedef struct _gcsDMA_PRIV {
+    atomic_t usage;
+}
+gcsDMA_PRIV;
+
+struct mdl_dma_priv {
+    gctPOINTER kvaddr;
+    dma_addr_t dmaHandle;
+};
+
+/*
+* Debugfs support.
+*/
+static int gc_dma_usage_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckALLOCATOR Allocator = node->device;
+    gcsDMA_PRIV_PTR priv = Allocator->privateData;
+    long long usage = (long long)atomic_read(&priv->usage);
+
+    seq_printf(m, "type        n pages        bytes\n");
+    seq_printf(m, "normal   %10llu %12llu\n", usage, usage * PAGE_SIZE);
+
+    return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+    {"dmausage", gc_dma_usage_show},
+};
+
+static void
+_DebugfsInit(
+    IN gckALLOCATOR Allocator,
+    IN gckDEBUGFS_DIR Root
+    )
+{
+    gcmkVERIFY_OK(
+        gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "dma"));
+
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList),
+        Allocator
+        ));
+}
+
+static void
+_DebugfsCleanup(
+    IN gckALLOCATOR Allocator
+    )
+{
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList)
+        ));
+
+    gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+_DmaAlloc(
+    IN gckALLOCATOR Allocator,
+    INOUT PLINUX_MDL Mdl,
+    IN gctSIZE_T NumPages,
+    IN gctUINT32 Flags
+    )
+{
+    gceSTATUS status;
+    u32 gfp = GFP_KERNEL | gcdNOWARN;
+    gcsDMA_PRIV_PTR allocatorPriv = (gcsDMA_PRIV_PTR)Allocator->privateData;
+
+    struct mdl_dma_priv *mdlPriv=gcvNULL;
+    gckOS os = Allocator->os;
+
+    gcmkHEADER_ARG("Mdl=%p NumPages=0x%zx Flags=0x%x", Mdl, NumPages, Flags);
+
+    gcmkONERROR(gckOS_Allocate(os, sizeof(struct mdl_dma_priv), (gctPOINTER *)&mdlPriv));
+    mdlPriv->kvaddr = gcvNULL;
+
+#if defined(CONFIG_ZONE_DMA32) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+    if (Flags & gcvALLOC_FLAG_4GB_ADDR)
+    {
+        gfp |= __GFP_DMA32;
+    }
+#else
+    if (Flags & gcvALLOC_FLAG_4GB_ADDR)
+    {
+        gfp |= __GFP_DMA;
+    }
+#endif
+
+    mdlPriv->kvaddr
+#if defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC || defined CONFIG_ARM64 || !gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+        = dma_alloc_coherent(galcore_device, NumPages * PAGE_SIZE, &mdlPriv->dmaHandle, gfp);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+        = dma_alloc_wc(galcore_device, NumPages * PAGE_SIZE,  &mdlPriv->dmaHandle, gfp);
+#else
+        = dma_alloc_writecombine(galcore_device, NumPages * PAGE_SIZE,  &mdlPriv->dmaHandle, gfp);
+#endif
+#endif
+
+#ifdef CONFLICT_BETWEEN_BASE_AND_PHYS
+    if ((os->device->baseAddress & 0x80000000) != (mdlPriv->dmaHandle & 0x80000000))
+    {
+        mdlPriv->dmaHandle = (mdlPriv->dmaHandle & ~0x80000000)
+                           | (os->device->baseAddress & 0x80000000);
+    }
+#endif
+
+    if (mdlPriv->kvaddr == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    Mdl->priv = mdlPriv;
+
+    Mdl->dmaHandle = mdlPriv->dmaHandle;
+
+    /* Statistic. */
+    atomic_add(NumPages, &allocatorPriv->usage);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mdlPriv)
+    {
+        gckOS_Free(os, mdlPriv);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_DmaGetSGT(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+    struct page ** pages = gcvNULL;
+    struct page * page = gcvNULL;
+    struct sg_table *sgt = NULL;
+    struct mdl_dma_priv *mdlPriv = (struct mdl_dma_priv*)Mdl->priv;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+    gctSIZE_T skipPages = Offset >> PAGE_SHIFT;     /* skipped pages */
+    gctSIZE_T numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+    gctSIZE_T i;
+
+    gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+    sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+    if (!sgt)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    pages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+    if (!pages)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+#if !defined(phys_to_page)
+    page = virt_to_page(mdlPriv->kvaddr);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+    page = phys_to_page(mdlPriv->dmaHandle);
+#else
+    page = phys_to_page(dma_to_phys(&Allocator->os->device->platform->device->dev, mdlPriv->dmaHandle));
+#endif
+
+    for (i = 0; i < numPages; ++i)
+    {
+        pages[i] = nth_page(page, i + skipPages);
+    }
+
+    if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    *SGT = (gctPOINTER)sgt;
+
+OnError:
+    if (pages)
+    {
+        kfree(pages);
+    }
+
+    if (gcmIS_ERROR(status) && sgt)
+    {
+        kfree(sgt);
+    }
+
+    return status;
+#else
+    return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_DmaFree(
+    IN gckALLOCATOR Allocator,
+    IN OUT PLINUX_MDL Mdl
+    )
+{
+    gckOS os = Allocator->os;
+    struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+    gcsDMA_PRIV_PTR allocatorPriv = (gcsDMA_PRIV_PTR)Allocator->privateData;
+
+#if defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC || defined CONFIG_ARM64 || !gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+    dma_free_coherent(galcore_device, Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+    dma_free_wc(galcore_device, Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#else
+    dma_free_writecombine(galcore_device, Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#endif
+#endif
+
+    gckOS_Free(os, mdlPriv);
+
+    /* Statistic. */
+    atomic_sub(Mdl->numPages, &allocatorPriv->usage);
+}
+
+static gceSTATUS
+_DmaMmap(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctBOOL Cacheable,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    IN struct vm_area_struct *vma
+    )
+{
+    struct mdl_dma_priv *mdlPriv = (struct mdl_dma_priv*)Mdl->priv;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+    gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+    /* map kernel memory to user space.. */
+#if defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC
+    if (remap_pfn_range(
+            vma,
+            vma->vm_start,
+            (mdlPriv->dmaHandle >> PAGE_SHIFT) + skipPages,
+            numPages << PAGE_SHIFT,
+            pgprot_writecombine(vma->vm_page_prot)) < 0)
+#else
+    /* map kernel memory to user space.. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+    /* map kernel memory to user space.. */
+    if (dma_mmap_wc(galcore_device,
+            vma,
+            (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+            mdlPriv->dmaHandle + (skipPages << PAGE_SHIFT),
+            numPages << PAGE_SHIFT) < 0)
+#else
+    /* map kernel memory to user space.. */
+    if (dma_mmap_writecombine(galcore_device,
+            vma,
+            (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+            mdlPriv->dmaHandle + (skipPages << PAGE_SHIFT),
+            numPages << PAGE_SHIFT) < 0)
+#endif
+#endif
+#else
+    /* map kernel memory to user space.. */
+    if (dma_mmap_coherent(galcore_device,
+            vma,
+            (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+            mdlPriv->dmaHandle + (skipPages << PAGE_SHIFT),
+            numPages << PAGE_SHIFT) < 0)
+#endif
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_WARNING, gcvZONE_OS,
+            "%s(%d): dma_mmap_attrs error",
+            __FUNCTION__, __LINE__
+            );
+
+        status = gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+_DmaUnmapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    if (unlikely(current->mm == gcvNULL))
+    {
+        /* Do nothing if process is exiting. */
+        return;
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+    if (vm_munmap((unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): vm_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+#else
+    down_write(&current_mm_mmap_sem);
+    if (do_munmap(current->mm, (unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): do_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+    up_write(&current_mm_mmap_sem);
+#endif
+}
+
+static gceSTATUS
+_DmaMapUser(
+    gckALLOCATOR Allocator,
+    PLINUX_MDL Mdl,
+    PLINUX_MDL_MAP MdlMap,
+    gctBOOL Cacheable
+    )
+{
+    gctPOINTER userLogical = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+    userLogical = (gctPOINTER)vm_mmap(gcvNULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED | MAP_NORESERVE,
+                    0);
+#else
+    down_write(&current_mm_mmap_sem);
+    userLogical = (gctPOINTER)do_mmap_pgoff(gcvNULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED,
+                    0);
+    up_write(&current_mm_mmap_sem);
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): vmaAddr->%p for phys_addr->%p",
+        __FUNCTION__, __LINE__, userLogical, Mdl
+        );
+
+    if (IS_ERR(userLogical))
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_OS,
+            "%s(%d): do_mmap_pgoff error",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    down_write(&current_mm_mmap_sem);
+
+    do
+    {
+        struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+        if (vma == gcvNULL)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): find_vma error",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        gcmkERR_BREAK(_DmaMmap(Allocator, Mdl, Cacheable, 0, Mdl->numPages, vma));
+
+        MdlMap->vmaAddr = userLogical;
+        MdlMap->cacheable = gcvFALSE;
+        MdlMap->vma = vma;
+    }
+    while (gcvFALSE);
+
+    up_write(&current_mm_mmap_sem);
+
+OnError:
+    if (gcmIS_ERROR(status) && userLogical)
+    {
+        _DmaUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_DmaMapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+    *Logical = (uint8_t *)mdlPriv->kvaddr + Offset;
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaUnmapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaCache(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+    case gcvCACHE_FLUSH:
+        _MemoryBarrier();
+        break;
+    case gcvCACHE_INVALIDATE:
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaPhysical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+
+    *Physical = mdlPriv->dmaHandle + Offset;
+
+    return gcvSTATUS_OK;
+}
+
+static void
+_DmaAllocatorDestructor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    _DebugfsCleanup(Allocator);
+
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* Default allocator operations. */
+gcsALLOCATOR_OPERATIONS DmaAllocatorOperations = {
+    .Alloc              = _DmaAlloc,
+    .Free               = _DmaFree,
+    .Mmap               = _DmaMmap,
+    .MapUser            = _DmaMapUser,
+    .UnmapUser          = _DmaUnmapUser,
+    .MapKernel          = _DmaMapKernel,
+    .UnmapKernel        = _DmaUnmapKernel,
+    .Cache              = _DmaCache,
+    .Physical           = _DmaPhysical,
+    .GetSGT             = _DmaGetSGT,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_DmaAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator = gcvNULL;
+    gcsDMA_PRIV_PTR priv = gcvNULL;
+
+    gcmkONERROR(gckALLOCATOR_Construct(Os, &DmaAllocatorOperations, &allocator));
+
+    priv = kzalloc(gcmSIZEOF(gcsDMA_PRIV), GFP_KERNEL | gcdNOWARN);
+
+    if (!priv)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    atomic_set(&priv->usage, 0);
+
+    /* Register private data. */
+    allocator->privateData = priv;
+    allocator->destructor  = _DmaAllocatorDestructor;
+
+    _DebugfsInit(allocator, Parent);
+
+    /*
+     * DMA allocator is only used for NonPaged memory
+     * when NO_DMA_COHERENT is not defined.
+     */
+    allocator->capability = gcvALLOC_FLAG_CONTIGUOUS
+                          | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+#if (defined(CONFIG_ZONE_DMA32) || defined(CONFIG_ZONE_DMA)) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+                          | gcvALLOC_FLAG_4GB_ADDR
+#endif
+                          ;
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (allocator)
+    {
+        kfree(allocator);
+    }
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c
@@ -0,0 +1,557 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/dma-buf.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+/* Descriptor of a dma_buf imported. */
+typedef struct _gcsDMABUF
+{
+    struct dma_buf            * dmabuf;
+    struct dma_buf_attachment * attachment;
+    struct sg_table           * sgt;
+    unsigned long             * pagearray;
+
+    int                         npages;
+    int                         pid;
+    struct list_head            list;
+}
+gcsDMABUF;
+
+struct allocator_priv
+{
+    struct mutex lock;
+    struct list_head buf_list;
+};
+
+/*
+* Debugfs support.
+*/
+static int dma_buf_info_show(struct seq_file* m, void* data)
+{
+    int ret;
+    gcsDMABUF *buf_desc;
+    struct dma_buf_attachment *attach_obj;
+    int count = 0;
+    size_t size = 0;
+    int npages = 0;
+    const char *exp_name;
+
+    gcsINFO_NODE *node = m->private;
+    gckALLOCATOR allocator = node->device;
+    struct allocator_priv *priv = allocator->privateData;
+
+    ret = mutex_lock_interruptible(&priv->lock);
+
+    if (ret)
+        return ret;
+
+    seq_puts(m, "Attached dma-buf objects:\n");
+    seq_puts(m, "   pid     fd    pages     size   exporter attached-devices\n");
+
+    list_for_each_entry(buf_desc, &priv->buf_list, list) {
+        struct dma_buf *buf_obj = buf_desc->dmabuf;
+
+        ret = mutex_lock_interruptible(&buf_obj->lock);
+
+        if (ret) {
+            seq_puts(m,
+                 "ERROR locking buffer object: skipping\n");
+            continue;
+        }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+        exp_name = buf_obj->exp_name;
+#else
+        exp_name = "unknown";
+#endif
+
+        seq_printf(m, "%6d %p %8d %8zu %10s",
+                buf_desc->pid,
+                buf_desc->dmabuf,
+                buf_desc->npages,
+                buf_obj->size,
+                exp_name);
+
+        list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
+            seq_printf(m, " %s", dev_name(attach_obj->dev));
+        }
+        seq_puts(m, "\n");
+
+        count++;
+        size += buf_obj->size;
+        npages += buf_desc->npages;
+
+        mutex_unlock(&buf_obj->lock);
+    }
+
+    seq_printf(m, "\nTotal %d objects, %d pages, %zu bytes\n", count, npages, size);
+
+    mutex_unlock(&priv->lock);
+    return 0;
+}
+
+static gcsINFO _InfoList[] =
+{
+    {"bufinfo", dma_buf_info_show},
+};
+
+static void
+_DebugfsInit(
+    IN gckALLOCATOR Allocator,
+    IN gckDEBUGFS_DIR Root
+    )
+{
+    gcmkVERIFY_OK(
+        gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "dma_buf"));
+
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+        &Allocator->debugfsDir,
+        _InfoList,
+        gcmCOUNTOF(_InfoList),
+        Allocator
+        ));
+}
+
+static void
+_DebugfsCleanup(
+    IN gckALLOCATOR Allocator
+    )
+{
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+        &Allocator->debugfsDir,
+        _InfoList,
+        gcmCOUNTOF(_InfoList)
+        ));
+
+    gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+_DmabufAttach(
+    IN gckALLOCATOR Allocator,
+    IN gcsATTACH_DESC_PTR Desc,
+    IN PLINUX_MDL Mdl
+    )
+{
+    gceSTATUS status;
+
+    gckOS os = Allocator->os;
+
+    struct dma_buf *dmabuf = Desc->dmaBuf.dmabuf;
+    struct sg_table *sgt = NULL;
+    struct dma_buf_attachment *attachment = NULL;
+    int npages = 0;
+    unsigned long *pagearray = NULL;
+    int i, j, k = 0;
+    struct scatterlist *s;
+    struct allocator_priv *priv = Allocator->privateData;
+    gcsDMABUF *buf_desc = NULL;
+
+    gcmkHEADER();
+
+    gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+    if (!dmabuf)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    get_dma_buf(dmabuf);
+    attachment = dma_buf_attach(dmabuf, &os->device->platform->device->dev);
+
+    if (!attachment)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+
+    if (!sgt)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    /* Prepare page array. */
+    /* Get number of pages. */
+    for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+    {
+        npages += (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE;
+    }
+
+    /* Allocate page array. */
+    gcmkONERROR(gckOS_Allocate(os, npages * gcmSIZEOF(*pagearray), (gctPOINTER *)&pagearray));
+
+    /* Fill page array. */
+    for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+    {
+        for (j = 0; j < (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE; j++)
+        {
+            pagearray[k++] = sg_dma_address(s) + j * PAGE_SIZE;
+        }
+    }
+
+    /* Prepare descriptor. */
+    gcmkONERROR(gckOS_Allocate(os, sizeof(gcsDMABUF), (gctPOINTER *)&buf_desc));
+
+    buf_desc->dmabuf = dmabuf;
+    buf_desc->pagearray = pagearray;
+    buf_desc->attachment = attachment;
+    buf_desc->sgt = sgt;
+
+    /* Record in buffer list to support debugfs. */
+    buf_desc->npages = npages;
+    buf_desc->pid    = _GetProcessID();
+
+    mutex_lock(&priv->lock);
+    list_add(&buf_desc->list, &priv->buf_list);
+    mutex_unlock(&priv->lock);
+
+    /* Record page number. */
+    Mdl->numPages = npages;
+
+    Mdl->priv = buf_desc;
+
+    Mdl->contiguous = (sgt->nents == 1) ? gcvTRUE : gcvFALSE;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (pagearray)
+    {
+        gcmkOS_SAFE_FREE(os, pagearray);
+    }
+
+    if (sgt)
+    {
+        dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+
+static void
+_DmabufFree(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl
+    )
+{
+    gcsDMABUF *buf_desc = Mdl->priv;
+    gckOS os = Allocator->os;
+    struct allocator_priv *priv = Allocator->privateData;
+
+    mutex_lock(&priv->lock);
+    list_del(&buf_desc->list);
+    mutex_unlock(&priv->lock);
+
+    dma_buf_unmap_attachment(buf_desc->attachment, buf_desc->sgt, DMA_BIDIRECTIONAL);
+
+    dma_buf_detach(buf_desc->dmabuf, buf_desc->attachment);
+
+    dma_buf_put(buf_desc->dmabuf);
+
+    gckOS_Free(os, buf_desc->pagearray);
+
+    gckOS_Free(os, buf_desc);
+}
+
+static void
+_DmabufUnmapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    gcsDMABUF *buf_desc = Mdl->priv;
+    gctINT8_PTR userLogical = MdlMap->vmaAddr;
+
+    if (unlikely(current->mm == gcvNULL))
+    {
+        /* Do nothing if process is exiting. */
+        return;
+    }
+
+    userLogical -= buf_desc->sgt->sgl->offset;
+    vm_munmap((unsigned long)userLogical, Mdl->numPages << PAGE_SHIFT);
+}
+
+static gceSTATUS
+_DmabufMapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctBOOL Cacheable
+    )
+{
+    gcsDMABUF *buf_desc = Mdl->priv;
+    gctINT8_PTR userLogical = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+    struct file *fd = buf_desc->dmabuf->file;
+    unsigned long flag = 0;
+
+    flag |= (fd->f_mode & FMODE_READ ? PROT_READ : 0);
+    flag |= (fd->f_mode & FMODE_WRITE ? PROT_WRITE : 0);
+
+    userLogical = (gctINT8_PTR)vm_mmap(fd,
+                    0L,
+                    Mdl->numPages << PAGE_SHIFT,
+                    flag,
+                    MAP_SHARED | MAP_NORESERVE,
+                    0);
+
+    if (IS_ERR(userLogical))
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+    userLogical += buf_desc->sgt->sgl->offset;
+
+    /* To make sure the mapping is created. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+    if (access_ok(userLogical, 4))
+#else
+    if (access_ok(VERIFY_READ, userLogical, 4))
+#endif
+    {
+        uint32_t mem;
+        get_user(mem, (uint32_t *)userLogical);
+
+        (void)mem;
+    }
+
+    MdlMap->vmaAddr = (gctPOINTER)userLogical;
+    MdlMap->cacheable = Cacheable;
+
+OnError:
+    if (gcmIS_ERROR(status) && MdlMap->vmaAddr)
+    {
+        _DmabufUnmapUser(Allocator, Mdl, MdlMap, Mdl->numPages << PAGE_SHIFT);
+    }
+    return status;
+}
+
+static gceSTATUS
+_DmabufMapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    /* Kernel doesn't acess video memory. */
+    return gcvSTATUS_NOT_SUPPORTED;
+
+}
+
+static gceSTATUS
+_DmabufUnmapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    /* Kernel doesn't acess video memory. */
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+_DmabufCache(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    gcsDMABUF *buf_desc = Mdl->priv;
+    struct sg_table *sgt = buf_desc->sgt;
+    enum dma_data_direction dir;
+
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+        dir = DMA_TO_DEVICE;
+        dma_sync_sg_for_device(galcore_device, sgt->sgl, sgt->nents, dir);
+        break;
+    case gcvCACHE_FLUSH:
+        dir = DMA_TO_DEVICE;
+        dma_sync_sg_for_device(galcore_device, sgt->sgl, sgt->nents, dir);
+        dir = DMA_FROM_DEVICE;
+        dma_sync_sg_for_cpu(galcore_device, sgt->sgl, sgt->nents, dir);
+        break;
+    case gcvCACHE_INVALIDATE:
+        dir = DMA_FROM_DEVICE;
+        dma_sync_sg_for_cpu(galcore_device, sgt->sgl, sgt->nents, dir);
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_DmabufPhysical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    gcsDMABUF *buf_desc = Mdl->priv;
+    gctUINT32 offsetInPage = Offset & ~PAGE_MASK;
+    gctUINT32 index = Offset / PAGE_SIZE;
+
+    *Physical = buf_desc->pagearray[index] + offsetInPage;
+
+
+    return gcvSTATUS_OK;
+}
+
+/* Default allocator operations. */
+static gcsALLOCATOR_OPERATIONS DmabufAllocatorOperations =
+{
+    .Attach             = _DmabufAttach,
+    .Free               = _DmabufFree,
+    .MapUser            = _DmabufMapUser,
+    .UnmapUser          = _DmabufUnmapUser,
+    .MapKernel          = _DmabufMapKernel,
+    .UnmapKernel        = _DmabufUnmapKernel,
+    .Cache              = _DmabufCache,
+    .Physical           = _DmabufPhysical,
+};
+
+static void
+_DmabufAllocatorDestructor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    _DebugfsCleanup(Allocator);
+
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* Default allocator entry. */
+gceSTATUS
+_DmabufAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator;
+    struct allocator_priv *priv = NULL;
+
+    priv = kmalloc(sizeof (struct allocator_priv), GFP_KERNEL | gcdNOWARN);
+
+    if (!priv)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    mutex_init(&priv->lock);
+    INIT_LIST_HEAD(&priv->buf_list);
+
+    gcmkONERROR(
+        gckALLOCATOR_Construct(Os, &DmabufAllocatorOperations, &allocator));
+
+    allocator->capability = gcvALLOC_FLAG_DMABUF
+                          | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+                          ;
+
+    /* Register private data. */
+    allocator->privateData = priv;
+    allocator->destructor  = _DmabufAllocatorDestructor;
+
+    _DebugfsInit(allocator, Parent);
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (priv)
+    {
+        kfree(priv);
+    }
+
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c
@@ -0,0 +1,1398 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#if defined(CONFIG_X86) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0))
+#include <asm/set_memory.h>
+#endif
+#include "gc_hal_kernel_platform.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+#define gcdDISCRETE_PAGES 0
+
+struct gfp_alloc
+{
+    atomic_t low;
+    atomic_t high;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION (2,6,24)
+struct sg_table
+{
+    struct scatterlist *sgl;
+    unsigned int nents;
+    unsigned int orig_nents;
+};
+#endif
+
+struct gfp_mdl_priv
+{
+    int contiguous;
+
+    union
+    {
+        /* Pointer to a array of pages. */
+        struct
+        {
+            struct page *contiguousPages;
+            dma_addr_t dma_addr;
+            int exact;
+        };
+
+        struct
+        {
+            /* Pointer to a array of pointers to page. */
+            struct page **nonContiguousPages;
+
+            struct page **Pages1M;
+            int numPages1M;
+            int *isExact;
+            struct sg_table sgt;
+        };
+    };
+
+    gcsPLATFORM * platform;
+};
+
+/******************************************************************************\
+************************** GFP Allocator Debugfs ***************************
+\******************************************************************************/
+
+static int gc_usage_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckALLOCATOR Allocator = node->device;
+    struct gfp_alloc *priv = Allocator->privateData;
+    long long low  = (long long)atomic_read(&priv->low);
+    long long high = (long long)atomic_read(&priv->high);
+
+    seq_printf(m, "type        n pages        bytes\n");
+    seq_printf(m, "normal   %10llu %12llu\n", low, low * PAGE_SIZE);
+    seq_printf(m, "HighMem  %10llu %12llu\n", high, high * PAGE_SIZE);
+
+    return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+    {"usage", gc_usage_show},
+};
+
+static void
+_GFPAllocatorDebugfsInit(
+    IN gckALLOCATOR Allocator,
+    IN gckDEBUGFS_DIR Root
+    )
+{
+    gcmkVERIFY_OK(
+        gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "gfp"));
+
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList),
+        Allocator
+        ));
+}
+
+static void
+_GFPAllocatorDebugfsCleanup(
+    IN gckALLOCATOR Allocator
+    )
+{
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList)
+        ));
+
+    gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static void
+_NonContiguousFree(
+    IN struct page ** Pages,
+    IN gctSIZE_T NumPages
+    )
+{
+    gctSIZE_T i;
+
+    gcmkHEADER_ARG("Pages=%p, NumPages=%zx", Pages, NumPages);
+
+    gcmkASSERT(Pages != gcvNULL);
+
+    for (i = 0; i < NumPages; i++)
+    {
+        __free_page(Pages[i]);
+    }
+
+    if (is_vmalloc_addr(Pages))
+    {
+        vfree(Pages);
+    }
+    else
+    {
+        kfree(Pages);
+    }
+
+    gcmkFOOTER_NO();
+}
+
+static gceSTATUS
+_NonContiguousAlloc(
+    IN struct gfp_mdl_priv *MdlPriv,
+    IN gctSIZE_T NumPages,
+    IN gctUINT32 Gfp
+    )
+{
+    struct page ** pages;
+    struct page *p;
+    gctSIZE_T i, size;
+
+    gcmkHEADER_ARG("NumPages=%zx", NumPages);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+    if (NumPages > totalram_pages())
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+    if (NumPages > totalram_pages)
+#else
+    if (NumPages > num_physpages)
+#endif
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    size = NumPages * sizeof(struct page *);
+
+    pages = kmalloc(size, GFP_KERNEL | gcdNOWARN);
+
+    if (!pages)
+    {
+        pages = vmalloc(size);
+
+        if (!pages)
+        {
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OUT_OF_MEMORY;
+        }
+    }
+
+    for (i = 0; i < NumPages; i++)
+    {
+        p = alloc_page(Gfp);
+
+        if (!p)
+        {
+            _NonContiguousFree(pages, i);
+            gcmkFOOTER_NO();
+            return gcvSTATUS_OUT_OF_MEMORY;
+        }
+
+#if gcdDISCRETE_PAGES
+        if (i != 0)
+        {
+            if (page_to_pfn(pages[i-1]) == page_to_pfn(p)-1)
+            {
+                /* Replaced page. */
+                struct page *l = p;
+
+                /* Allocate a page which is not contiguous to previous one. */
+                p = alloc_page(Gfp);
+
+                /* Give replaced page back. */
+                __free_page(l);
+
+                if (!p)
+                {
+                    _NonContiguousFree(pages, i);
+                    gcmkFOOTER_NO();
+                    return gcvSTATUS_OUT_OF_MEMORY;
+                }
+            }
+        }
+#endif
+
+        pages[i] = p;
+    }
+
+    MdlPriv->contiguousPages = (struct page *)pages;
+
+    gcmkFOOTER_ARG("pages=0x%X", pages);
+    return gcvSTATUS_OK;
+}
+
+static void
+_NonContiguous1MPagesFree(
+    IN struct gfp_mdl_priv *MdlPriv,
+    IN gctUINT32 NumPages1M
+    )
+{
+    gctINT i;
+
+    if (MdlPriv->Pages1M && MdlPriv->isExact)
+    {
+        for (i = 0; i < NumPages1M && MdlPriv->Pages1M[i]; i++)
+        {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+            if (MdlPriv->isExact[i] == gcvTRUE)
+            {
+                free_pages_exact(page_address(MdlPriv->Pages1M[i]), gcd1M_PAGE_SIZE);
+            }
+            else
+#endif
+            {
+                __free_pages(MdlPriv->Pages1M[i], get_order(gcd1M_PAGE_SIZE));
+            }
+        }
+    }
+
+    if (MdlPriv->Pages1M)
+    {
+        if (is_vmalloc_addr(MdlPriv->Pages1M))
+        {
+            vfree(MdlPriv->Pages1M);
+        }
+        else
+        {
+            kfree(MdlPriv->Pages1M);
+        }
+        MdlPriv->Pages1M = gcvNULL;
+    }
+
+    if (MdlPriv->isExact)
+    {
+         if (is_vmalloc_addr(MdlPriv->isExact))
+        {
+            vfree(MdlPriv->isExact);
+        }
+        else
+        {
+            kfree(MdlPriv->isExact);
+        }
+    }
+
+    if (MdlPriv->nonContiguousPages)
+    {
+        if (is_vmalloc_addr(MdlPriv->nonContiguousPages))
+        {
+            vfree(MdlPriv->nonContiguousPages);
+        }
+        else
+        {
+            kfree(MdlPriv->nonContiguousPages);
+        }
+        MdlPriv->nonContiguousPages = gcvNULL;
+    }
+}
+
+static gceSTATUS
+_NonContiguous1MPagesAlloc(
+    IN struct gfp_mdl_priv *MdlPriv,
+    IN gctSIZE_T *NumPages,
+    IN gctUINT32 Gfp
+    )
+{
+    gceSTATUS status;
+    size_t numPages1M, num, size;
+    struct page **pages;
+    struct page *page;
+    void *addr = NULL;
+    gctINT i, j;
+
+    MdlPriv->numPages1M = 0;
+
+    numPages1M = ((*NumPages << PAGE_SHIFT) + (gcd1M_PAGE_SIZE - 1)) >> gcd1M_PAGE_SHIFT;
+
+    *NumPages = (numPages1M << gcd1M_PAGE_SHIFT) >> PAGE_SHIFT;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+        if (*NumPages > totalram_pages())
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+        if (*NumPages > totalram_pages)
+#else
+        if (*NumPages > num_physpages)
+#endif
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    num = gcd1M_PAGE_SIZE / PAGE_SIZE;
+
+    size = numPages1M * sizeof(struct page *);
+    MdlPriv->Pages1M = kmalloc(size, GFP_KERNEL | gcdNOWARN);
+    if (!MdlPriv->Pages1M)
+    {
+        MdlPriv->Pages1M = vmalloc(size);
+
+        if (!MdlPriv->Pages1M)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+
+    size = numPages1M * sizeof(int);
+    MdlPriv->isExact = kmalloc(size, GFP_KERNEL | gcdNOWARN);
+    if (!MdlPriv->isExact)
+    {
+        MdlPriv->isExact = vmalloc(size);
+        if (!MdlPriv->isExact)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+    memset(MdlPriv->isExact, 0, size);
+
+    size = *NumPages * sizeof(struct page *);
+    pages = kmalloc(size, GFP_KERNEL | gcdNOWARN);
+    if (!pages)
+    {
+        pages = vmalloc(size);
+        if (!pages)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+    MdlPriv->contiguousPages = (struct page *)pages;
+
+    for (i = 0; i < numPages1M; i++)
+    {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+        addr = alloc_pages_exact(gcd1M_PAGE_SIZE, (Gfp & ~__GFP_HIGHMEM) | __GFP_NORETRY);
+
+        MdlPriv->Pages1M[i] = addr ? virt_to_page(addr) : gcvNULL;
+        if (MdlPriv->Pages1M[i])
+        {
+            MdlPriv->isExact[i] = gcvTRUE;
+        }
+#endif
+
+        if (MdlPriv->Pages1M[i] == gcvNULL)
+        {
+            int order = get_order(gcd1M_PAGE_SIZE);
+
+            if (order >= MAX_ORDER)
+            {
+                gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+            }
+
+            MdlPriv->Pages1M[i] = alloc_pages(Gfp, order);
+        }
+
+        if (MdlPriv->Pages1M[i] == gcvNULL)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        MdlPriv->numPages1M += 1;
+
+        for (j = 0; j < num; j++)
+        {
+            page = nth_page(MdlPriv->Pages1M[i], j);
+            pages[i * num + j] = page;
+        }
+    }
+
+    return gcvSTATUS_OK;
+OnError:
+    _NonContiguous1MPagesFree(MdlPriv, MdlPriv->numPages1M);
+
+    return status;
+}
+
+/***************************************************************************\
+************************ GFP Allocator **********************************
+\***************************************************************************/
+static gceSTATUS
+_GFPAlloc(
+    IN gckALLOCATOR Allocator,
+    INOUT PLINUX_MDL Mdl,
+    IN gctSIZE_T NumPages,
+    IN gctUINT32 Flags
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T i = 0;
+    gctBOOL contiguous = Flags & gcvALLOC_FLAG_CONTIGUOUS;
+    u32 normal_gfp = __GFP_HIGH | __GFP_ATOMIC | __GFP_NORETRY | gcdNOWARN;
+    u32 gfp = (contiguous ? normal_gfp : GFP_KERNEL) | __GFP_HIGHMEM | gcdNOWARN;
+
+    struct gfp_alloc *priv = (struct gfp_alloc *)Allocator->privateData;
+    struct gfp_mdl_priv *mdlPriv = gcvNULL;
+    int result;
+    int low = 0;
+    int high = 0;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p NumPages=%zu Flags=0x%x", Allocator, Mdl, NumPages, Flags);
+
+#ifdef gcdSYS_FREE_MEMORY_LIMIT
+    if (Flags & gcvALLOC_FLAG_MEMLIMIT)
+    {
+        struct sysinfo temsysinfo;
+        si_meminfo(&temsysinfo);
+
+        if ((temsysinfo.freeram < NumPages) || ((temsysinfo.freeram-NumPages) < gcdSYS_FREE_MEMORY_LIMIT))
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+#endif
+
+    mdlPriv = kzalloc(sizeof(struct gfp_mdl_priv), GFP_KERNEL | __GFP_NORETRY);
+
+    if (!mdlPriv)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+#if defined(CONFIG_ZONE_DMA32) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+    if ((Flags & gcvALLOC_FLAG_4GB_ADDR) || (Allocator->os->device->platform->flagBits & gcvPLATFORM_FLAG_LIMIT_4G_ADDRESS))
+    {
+        /* remove __GFP_HIGHMEM bit, add __GFP_DMA32 bit */
+        gfp &= ~__GFP_HIGHMEM;
+        gfp |= __GFP_DMA32;
+    }
+#else
+    if (Flags & gcvALLOC_FLAG_4GB_ADDR || (Allocator->os->device->platform->flagBits & gcvPLATFORM_FLAG_LIMIT_4G_ADDRESS))
+    {
+        /* remove __GFP_HIGHMEM bit, add __GFP_DMA bit */
+        gfp &= ~__GFP_HIGHMEM;
+        gfp |= __GFP_DMA;
+    }
+
+#endif
+
+    if ((Flags & gcvALLOC_FLAG_NON_CONTIGUOUS) && (Flags & gcvALLOC_FLAG_1M_PAGES))
+    {
+        Mdl->pageUnit1M = gcvTRUE;
+    }
+    else
+    {
+        Mdl->pageUnit1M = gcvFALSE;
+    }
+
+    if (contiguous)
+    {
+        size_t bytes = NumPages << PAGE_SHIFT;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+        void *addr = NULL;
+
+        addr = alloc_pages_exact(bytes, (gfp & ~__GFP_HIGHMEM) | __GFP_NORETRY);
+
+        mdlPriv->contiguousPages = addr ? virt_to_page(addr) : gcvNULL;
+
+        if (mdlPriv->contiguousPages)
+        {
+            mdlPriv->exact = gcvTRUE;
+        }
+#endif
+
+        if (mdlPriv->contiguousPages == gcvNULL)
+        {
+            int order = get_order(bytes);
+
+            if (order >= MAX_ORDER)
+            {
+                status = gcvSTATUS_OUT_OF_MEMORY;
+                goto OnError;
+            }
+
+            mdlPriv->contiguousPages = alloc_pages(gfp, order);
+        }
+
+        if (mdlPriv->contiguousPages == gcvNULL)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        mdlPriv->dma_addr = dma_map_page(galcore_device,
+                mdlPriv->contiguousPages, 0, NumPages * PAGE_SIZE,
+                DMA_FROM_DEVICE);
+
+        if (dma_mapping_error(galcore_device, mdlPriv->dma_addr))
+        {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+            if (mdlPriv->exact)
+            {
+                free_pages_exact(page_address(mdlPriv->contiguousPages), bytes);
+            }
+            else
+#endif
+            {
+                __free_pages(mdlPriv->contiguousPages, get_order(bytes));
+            }
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+#if defined(CONFIG_X86)
+        if (!PageHighMem(mdlPriv->contiguousPages))
+        {
+            if (set_memory_wc((unsigned long)page_address(mdlPriv->contiguousPages), NumPages) != 0)
+            {
+                printk("%s(%d): failed to set_memory_wc\n", __func__, __LINE__);
+            }
+        }
+#endif
+    }
+    else
+    {
+        if (Mdl->pageUnit1M)
+        {
+            gcmkONERROR(_NonContiguous1MPagesAlloc(mdlPriv, &NumPages, gfp));
+        }
+        else
+        {
+            status = _NonContiguousAlloc(mdlPriv, NumPages, normal_gfp);
+
+            if (gcmIS_ERROR(status))
+            {
+                gcmkONERROR(_NonContiguousAlloc(mdlPriv, NumPages, gfp));
+            }
+        }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined(ARCH_HAS_SG_CHAIN) || defined(CONFIG_ARCH_HAS_SG_CHAIN))
+        result = sg_alloc_table_from_pages(&mdlPriv->sgt,
+                    mdlPriv->nonContiguousPages, NumPages, 0,
+                    NumPages << PAGE_SHIFT, GFP_KERNEL);
+
+#else
+        result = alloc_sg_list_from_pages(&mdlPriv->sgt.sgl,
+                    mdlPriv->nonContiguousPages, NumPages, 0,
+                    NumPages << PAGE_SHIFT, &mdlPriv->sgt.nents);
+
+        mdlPriv->sgt.orig_nents = mdlPriv->sgt.nents;
+#endif
+        if (result < 0)
+        {
+            if (Mdl->pageUnit1M)
+            {
+                _NonContiguous1MPagesFree(mdlPriv, mdlPriv->numPages1M);
+            }
+            else
+            {
+                _NonContiguousFree(mdlPriv->nonContiguousPages, NumPages);
+            }
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        result = dma_map_sg(galcore_device,
+                    mdlPriv->sgt.sgl, mdlPriv->sgt.nents, DMA_FROM_DEVICE);
+
+        if (result != mdlPriv->sgt.nents)
+        {
+            if (Mdl->pageUnit1M)
+            {
+                _NonContiguous1MPagesFree(mdlPriv, mdlPriv->numPages1M);
+            }
+            else
+            {
+                _NonContiguousFree(mdlPriv->nonContiguousPages, NumPages);
+            }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined (ARCH_HAS_SG_CHAIN) || defined (CONFIG_ARCH_HAS_SG_CHAIN))
+            sg_free_table(&mdlPriv->sgt);
+#else
+            kfree(mdlPriv->sgt.sgl);
+#endif
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+#if defined(CONFIG_X86)
+        if (set_pages_array_wc(mdlPriv->nonContiguousPages, NumPages))
+        {
+            printk("%s(%d): failed to set_pages_array_wc\n", __func__, __LINE__);
+        }
+#endif
+    }
+
+    for (i = 0; i < NumPages; i++)
+    {
+        struct page *page;
+        gctPHYS_ADDR_T phys = 0U;
+
+        if (contiguous)
+        {
+            page = nth_page(mdlPriv->contiguousPages, i);
+        }
+        else
+        {
+            page = mdlPriv->nonContiguousPages[i];
+        }
+
+        SetPageReserved(page);
+
+        phys = page_to_phys(page);
+
+        BUG_ON(!phys);
+
+        if (PageHighMem(page))
+        {
+            high++;
+        }
+        else
+        {
+            low++;
+        }
+    }
+
+    mdlPriv->platform = Allocator->os->device->platform;
+    mdlPriv->contiguous = contiguous;
+    atomic_add(low, &priv->low);
+    atomic_add(high, &priv->high);
+
+    Mdl->priv = mdlPriv;
+    Mdl->numPages = NumPages;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mdlPriv)
+    {
+        kfree(mdlPriv);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_GFPGetSGT(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+    struct page ** pages = gcvNULL;
+    struct page ** tmpPages = gcvNULL;
+    struct sg_table *sgt = NULL;
+    struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+    gctSIZE_T skipPages = Offset >> PAGE_SHIFT;     /* skipped pages */
+    gctSIZE_T numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+    gctSIZE_T i;
+
+    gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+    if (mdlPriv->contiguous)
+    {
+        pages = tmpPages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+        if (!pages)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        for (i = 0; i < numPages; ++i)
+        {
+            pages[i] = nth_page(mdlPriv->contiguousPages, i + skipPages);
+        }
+    }
+    else
+    {
+        pages = &mdlPriv->nonContiguousPages[skipPages];
+    }
+
+    sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+    if (!sgt)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    *SGT = (gctPOINTER)sgt;
+
+OnError:
+    if (tmpPages)
+    {
+        kfree(tmpPages);
+    }
+
+    if (gcmIS_ERROR(status) && sgt)
+    {
+        kfree(sgt);
+    }
+
+    return status;
+#else
+    return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_GFPFree(
+    IN gckALLOCATOR Allocator,
+    IN OUT PLINUX_MDL Mdl
+    )
+{
+    gctSIZE_T i;
+    struct page * page;
+    struct gfp_alloc *priv = (struct gfp_alloc *)Allocator->privateData;
+    struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+    int low  = 0;
+    int high = 0;
+
+    if (mdlPriv->contiguous)
+    {
+        dma_unmap_page(galcore_device, mdlPriv->dma_addr,
+                Mdl->numPages << PAGE_SHIFT, DMA_FROM_DEVICE);
+    }
+    else
+    {
+        dma_unmap_sg(galcore_device, mdlPriv->sgt.sgl, mdlPriv->sgt.nents,
+                DMA_FROM_DEVICE);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined (ARCH_HAS_SG_CHAIN) || defined (CONFIG_ARCH_HAS_SG_CHAIN))
+        sg_free_table(&mdlPriv->sgt);
+#else
+        kfree(mdlPriv->sgt.sgl);
+#endif
+    }
+
+    for (i = 0; i < Mdl->numPages; i++)
+    {
+        if (mdlPriv->contiguous)
+        {
+            page = nth_page(mdlPriv->contiguousPages, i);
+        }
+        else
+        {
+            page = mdlPriv->nonContiguousPages[i];
+        }
+
+        ClearPageReserved(page);
+
+        if (PageHighMem(page))
+        {
+            high++;
+        }
+        else
+        {
+            low++;
+        }
+    }
+
+    atomic_sub(low, &priv->low);
+    atomic_sub(high, &priv->high);
+
+    if (mdlPriv->contiguous)
+    {
+#if defined(CONFIG_X86)
+        if (!PageHighMem(mdlPriv->contiguousPages))
+        {
+            set_memory_wb((unsigned long)page_address(mdlPriv->contiguousPages), Mdl->numPages);
+        }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+        if (mdlPriv->exact == gcvTRUE)
+        {
+            free_pages_exact(page_address(mdlPriv->contiguousPages), Mdl->numPages * PAGE_SIZE);
+        }
+        else
+#endif
+        {
+            __free_pages(mdlPriv->contiguousPages, get_order(Mdl->numPages * PAGE_SIZE));
+        }
+    }
+    else
+    {
+#if defined(CONFIG_X86)
+        set_pages_array_wb(mdlPriv->nonContiguousPages, Mdl->numPages);
+#endif
+
+        if (Mdl->pageUnit1M)
+        {
+            _NonContiguous1MPagesFree(mdlPriv, mdlPriv->numPages1M);
+        }
+        else
+        {
+            _NonContiguousFree(mdlPriv->nonContiguousPages, Mdl->numPages);
+        }
+    }
+
+    kfree(Mdl->priv);
+}
+
+static gceSTATUS
+_GFPMmap(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctBOOL Cacheable,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    IN struct vm_area_struct *vma
+    )
+{
+    struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+    gcsPLATFORM *platform = mdlPriv->platform;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+    vma->vm_flags |= gcdVM_FLAGS;
+
+    if (Cacheable == gcvFALSE)
+    {
+        /* Make this mapping non-cached. */
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#else
+        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
+    }
+
+    if (platform && platform->ops->adjustProt)
+    {
+        platform->ops->adjustProt(vma);
+    }
+
+    gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+    /* Now map all the vmalloc pages to this user address. */
+    if (mdlPriv->contiguous)
+    {
+        /* map kernel memory to user space.. */
+        if (remap_pfn_range(vma,
+                            vma->vm_start,
+                            page_to_pfn(mdlPriv->contiguousPages) + skipPages,
+                            numPages << PAGE_SHIFT,
+                            vma->vm_page_prot) < 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): remap_pfn_range error.",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+    else
+    {
+        gctSIZE_T i;
+        unsigned long start = vma->vm_start;
+
+        for (i = 0; i < numPages; ++i)
+        {
+            unsigned long pfn = page_to_pfn(mdlPriv->nonContiguousPages[i + skipPages]);
+
+            if (remap_pfn_range(vma,
+                                start,
+                                pfn,
+                                PAGE_SIZE,
+                                vma->vm_page_prot) < 0)
+            {
+                gcmkTRACE(
+                    gcvLEVEL_ERROR,
+                    "%s(%d): remap_pfn_range error.",
+                    __FUNCTION__, __LINE__
+                    );
+
+                gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+            }
+
+            start += PAGE_SIZE;
+        }
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+_GFPUnmapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    MdlMap->cacheable = gcvFALSE;
+
+    if (unlikely(current->mm == gcvNULL))
+    {
+        /* Do nothing if process is exiting. */
+        return;
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    if (vm_munmap((unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): vm_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+#else
+    down_write(&current_mm_mmap_sem);
+    if (do_munmap(current->mm, (unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): do_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+    up_write(&current_mm_mmap_sem);
+#endif
+
+    MdlMap->vma = NULL;
+}
+
+static gceSTATUS
+_GFPMapUser(
+    gckALLOCATOR Allocator,
+    PLINUX_MDL Mdl,
+    PLINUX_MDL_MAP MdlMap,
+    gctBOOL Cacheable
+    )
+{
+    gctPOINTER userLogical = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+    userLogical = (gctPOINTER)vm_mmap(NULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED | MAP_NORESERVE,
+                    0);
+#else
+    down_write(&current_mm_mmap_sem);
+    userLogical = (gctPOINTER)do_mmap_pgoff(NULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED,
+                    0);
+    up_write(&current_mm_mmap_sem);
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): vmaAddr->%p for phys_addr->%p",
+        __FUNCTION__, __LINE__,
+        userLogical,
+        Mdl
+        );
+
+    if (IS_ERR(userLogical))
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_OS,
+            "%s(%d): do_mmap_pgoff error",
+            __FUNCTION__, __LINE__
+            );
+
+        userLogical = gcvNULL;
+
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    down_write(&current_mm_mmap_sem);
+
+    do
+    {
+        struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+
+        if (vma == gcvNULL)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): find_vma error",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        gcmkERR_BREAK(_GFPMmap(Allocator, Mdl, Cacheable, 0, Mdl->numPages, vma));
+        MdlMap->vma = vma;
+    }
+    while (gcvFALSE);
+
+    up_write(&current_mm_mmap_sem);
+
+    if (gcmIS_SUCCESS(status))
+    {
+        MdlMap->vmaAddr = userLogical;
+        MdlMap->cacheable = Cacheable;
+    }
+
+OnError:
+    if (gcmIS_ERROR(status) && userLogical)
+    {
+        _GFPUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_GFPMapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    void *addr = 0;
+    gctSIZE_T numPages = Mdl->numPages;
+    struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+    unsigned long pgoff = (Offset >> PAGE_SHIFT);
+    struct page ** pages;
+    gctBOOL free = gcvFALSE;
+    pgprot_t pgprot;
+
+    if (Offset + Bytes > (numPages << PAGE_SHIFT))
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    numPages = ((Offset & ~PAGE_MASK) + Bytes + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+    if (mdlPriv->contiguous)
+    {
+        gctSIZE_T i;
+
+        pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN);
+
+        if (!pages)
+        {
+            return gcvSTATUS_OUT_OF_MEMORY;
+        }
+
+        for (i = 0; i < numPages; i++)
+        {
+            pages[i] = nth_page(mdlPriv->contiguousPages, i + pgoff);
+        }
+
+        free = gcvTRUE;
+    }
+    else
+    {
+        pages = &mdlPriv->nonContiguousPages[pgoff];
+    }
+
+    /* ioremap() can't work on system memory since 2.6.38. */
+    if (Mdl->cacheable)
+    {
+        pgprot = PAGE_KERNEL;
+    }
+    else
+    {
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+        pgprot = pgprot_writecombine(PAGE_KERNEL);
+#else
+        pgprot = pgprot_noncached(PAGE_KERNEL);
+#endif
+    }
+
+    addr = vmap(pages, numPages, 0, pgprot);
+
+    if (free)
+    {
+        kfree(pages);
+    }
+
+    if (addr)
+    {
+        /* Append offset in page. */
+        *Logical = (uint8_t *)addr + (Offset & ~PAGE_MASK);
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        return gcvSTATUS_OUT_OF_MEMORY;
+    }
+}
+
+static gceSTATUS
+_GFPUnmapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    vunmap((void *)((uintptr_t)Logical & PAGE_MASK));
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GFPCache(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+    enum dma_data_direction dir;
+    dma_addr_t dma_addr = (mdlPriv->dma_addr + Offset) & PAGE_MASK;
+    gctSIZE_T bytes = (mdlPriv->dma_addr + Offset + Bytes) - dma_addr;
+    gctINT numPages = GetPageCount(bytes, 0);
+
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+        dir = DMA_TO_DEVICE;
+
+        if (mdlPriv->contiguous)
+        {
+            dma_sync_single_for_device(galcore_device,
+                    dma_addr, numPages << PAGE_SHIFT, dir);
+        }
+        else
+        {
+            dma_sync_sg_for_device(galcore_device,
+                    mdlPriv->sgt.sgl, mdlPriv->sgt.nents, dir);
+        }
+
+        break;
+    case gcvCACHE_FLUSH:
+        dir = DMA_TO_DEVICE;
+
+        if (mdlPriv->contiguous)
+        {
+            dma_sync_single_for_device(galcore_device,
+                    dma_addr, numPages << PAGE_SHIFT, dir);
+        }
+        else
+        {
+            dma_sync_sg_for_device(galcore_device,
+                    mdlPriv->sgt.sgl, mdlPriv->sgt.nents, dir);
+        }
+
+        dir = DMA_FROM_DEVICE;
+
+        if (mdlPriv->contiguous)
+        {
+            dma_sync_single_for_cpu(galcore_device,
+                    dma_addr, numPages << PAGE_SHIFT, dir);
+        }
+        else
+        {
+            dma_sync_sg_for_cpu(galcore_device,
+                    mdlPriv->sgt.sgl, mdlPriv->sgt.nents, dir);
+        }
+
+        break;
+    case gcvCACHE_INVALIDATE:
+        dir = DMA_FROM_DEVICE;
+
+        if (mdlPriv->contiguous)
+        {
+            dma_sync_single_for_cpu(galcore_device,
+                    dma_addr, numPages << PAGE_SHIFT, dir);
+        }
+        else
+        {
+            dma_sync_sg_for_cpu(galcore_device,
+                    mdlPriv->sgt.sgl, mdlPriv->sgt.nents, dir);
+        }
+
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GFPPhysical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+    gctUINT32 offsetInPage = Offset & ~PAGE_MASK;
+    gctUINT32 index = Offset / PAGE_SIZE;
+
+    if (mdlPriv->contiguous)
+    {
+        *Physical = page_to_phys(nth_page(mdlPriv->contiguousPages, index));
+    }
+    else
+    {
+        *Physical = page_to_phys(mdlPriv->nonContiguousPages[index]);
+    }
+
+    *Physical += offsetInPage;
+
+    return gcvSTATUS_OK;
+}
+
+static void
+_GFPAllocatorDestructor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    _GFPAllocatorDebugfsCleanup(Allocator);
+
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* GFP allocator operations. */
+static gcsALLOCATOR_OPERATIONS GFPAllocatorOperations = {
+    .Alloc              = _GFPAlloc,
+    .Free               = _GFPFree,
+    .Mmap               = _GFPMmap,
+    .MapUser            = _GFPMapUser,
+    .UnmapUser          = _GFPUnmapUser,
+    .MapKernel          = _GFPMapKernel,
+    .UnmapKernel        = _GFPUnmapKernel,
+    .Cache              = _GFPCache,
+    .Physical           = _GFPPhysical,
+    .GetSGT             = _GFPGetSGT,
+};
+
+/* GFP allocator entry. */
+gceSTATUS
+_GFPAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator = gcvNULL;
+    struct gfp_alloc *priv = gcvNULL;
+
+    gcmkONERROR(
+        gckALLOCATOR_Construct(Os, &GFPAllocatorOperations, &allocator));
+
+    priv = kzalloc(sizeof(struct gfp_alloc), GFP_KERNEL | gcdNOWARN);
+
+    if (!priv)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    atomic_set(&priv->low,  0);
+    atomic_set(&priv->high, 0);
+
+    /* Register private data. */
+    allocator->privateData = priv;
+    allocator->destructor = _GFPAllocatorDestructor;
+
+    _GFPAllocatorDebugfsInit(allocator, Parent);
+
+    allocator->capability = gcvALLOC_FLAG_CONTIGUOUS
+                          | gcvALLOC_FLAG_NON_CONTIGUOUS
+                          | gcvALLOC_FLAG_CACHEABLE
+                          | gcvALLOC_FLAG_MEMLIMIT
+                          | gcvALLOC_FLAG_ALLOC_ON_FAULT
+                          | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+#if (defined(CONFIG_ZONE_DMA32) || defined(CONFIG_ZONE_DMA)) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+                          | gcvALLOC_FLAG_4GB_ADDR
+#endif
+                          | gcvALLOC_FLAG_1M_PAGES
+                          ;
+
+#if defined(gcdEMULATE_SECURE_ALLOCATOR)
+    allocator->capability |= gcvALLOC_FLAG_SECURITY;
+#endif
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (allocator)
+    {
+        kfree(allocator);
+    }
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c
@@ -0,0 +1,591 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+/*
+ * reserved_mem is for contiguous pool, internal pool and external pool, etc.
+ */
+
+/* mdl private. */
+struct reserved_mem
+{
+    unsigned long start;
+    unsigned long size;
+    unsigned int offset_in_page;
+    char name[32];
+    int  release;
+
+    /* Link together. */
+    struct list_head link;
+};
+
+/* allocator info. */
+struct reserved_mem_alloc
+{
+    /* Record allocated reserved memory regions. */
+    struct list_head region;
+    struct mutex lock;
+};
+
+static int reserved_mem_show(struct seq_file* m, void* data)
+{
+    struct list_head *pos;
+    gcsINFO_NODE *node = m->private;
+    gckALLOCATOR Allocator = node->device;
+    struct reserved_mem_alloc *alloc = Allocator->privateData;
+
+    list_for_each(pos, &alloc->region)
+    {
+        struct reserved_mem * res= list_entry(pos, struct reserved_mem, link);
+
+        seq_printf(m, "0x%08lx-0x%08lx : %s\n",
+            res->start, res->start + res->size -1, res->name);
+    }
+
+    return 0;
+}
+
+static gcsINFO info_list[] =
+{
+    {"reserved-mem", reserved_mem_show},
+};
+
+static void
+reserved_mem_debugfs_init(
+    IN gckALLOCATOR Allocator,
+    IN gckDEBUGFS_DIR Root
+    )
+{
+    gcmkVERIFY_OK(
+        gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "reserved-mem"));
+
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+        &Allocator->debugfsDir,
+        info_list,
+        gcmCOUNTOF(info_list),
+        Allocator
+        ));
+}
+
+static void
+reserved_mem_debugfs_cleanup(
+    IN gckALLOCATOR Allocator
+    )
+{
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+        &Allocator->debugfsDir,
+        info_list,
+        gcmCOUNTOF(info_list)
+        ));
+
+    gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+reserved_mem_alloc(
+    IN gckALLOCATOR Allocator,
+    INOUT PLINUX_MDL Mdl,
+    IN gctSIZE_T NumPages,
+    IN gctUINT32 Flags
+    )
+{
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+reserved_mem_attach(
+    IN gckALLOCATOR Allocator,
+    IN gcsATTACH_DESC_PTR Desc,
+    IN PLINUX_MDL Mdl
+    )
+{
+    struct reserved_mem_alloc *alloc = Allocator->privateData;
+    struct reserved_mem *res;
+    struct resource *region = NULL;
+
+    if (Desc == gcvNULL)
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    res = kzalloc(sizeof(struct reserved_mem), GFP_KERNEL | gcdNOWARN);
+
+    if (!res)
+        return gcvSTATUS_OUT_OF_MEMORY;
+
+    res->start = Desc->reservedMem.start;
+    res->size  = Desc->reservedMem.size;
+    res->offset_in_page = Desc->reservedMem.start & (PAGE_SIZE - 1);
+    strncpy(res->name, Desc->reservedMem.name, sizeof(res->name)-1);
+    res->release = 0;
+
+    if (!Desc->reservedMem.requested)
+    {
+        region = request_mem_region(res->start, res->size, res->name);
+
+        if (!region)
+        {
+            printk("request mem %s(0x%lx - 0x%lx) failed\n",
+                res->name, res->start, res->start + res->size - 1);
+
+            kfree(res);
+            return gcvSTATUS_OUT_OF_RESOURCES;
+        }
+
+        res->release = 1;
+    }
+
+    mutex_lock(&alloc->lock);
+    list_add(&res->link, &alloc->region);
+    mutex_unlock(&alloc->lock);
+
+    Mdl->priv = res;
+
+    if ((res->start + res->size) < 0xFFFFFFFF)
+    {
+        Allocator->capability |= gcvALLOC_FLAG_4GB_ADDR;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static void
+reserved_mem_detach(
+    IN gckALLOCATOR Allocator,
+    IN OUT PLINUX_MDL Mdl
+    )
+{
+    struct reserved_mem_alloc *alloc = Allocator->privateData;
+    struct reserved_mem *res = Mdl->priv;
+
+    /* unlink from region list. */
+    mutex_lock(&alloc->lock);
+    list_del_init(&res->link);
+    mutex_unlock(&alloc->lock);
+
+    if (res->release)
+    {
+        release_mem_region(res->start, res->size);
+    }
+
+    kfree(res);
+}
+
+static gceSTATUS
+reserved_mem_mmap(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctBOOL Cacheable,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    IN struct vm_area_struct *vma
+    )
+{
+    struct reserved_mem *res = (struct reserved_mem*)Mdl->priv;
+    unsigned long pfn;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+    gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+    pfn = (res->start >> PAGE_SHIFT) + skipPages;
+
+    /* Make this mapping non-cached. */
+    vma->vm_flags |= gcdVM_FLAGS;
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+    vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#else
+    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
+
+    if (remap_pfn_range(vma, vma->vm_start,
+            pfn, numPages << PAGE_SHIFT, vma->vm_page_prot) < 0)
+    {
+        gcmkTRACE(
+            gcvLEVEL_ERROR,
+            "%s(%d): remap_pfn_range error.",
+            __FUNCTION__, __LINE__
+            );
+
+        status = gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+reserved_mem_unmap_user(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    struct reserved_mem *res = (struct reserved_mem*)Mdl->priv;
+
+    if (unlikely(!current->mm))
+        return;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+    if (vm_munmap((unsigned long)MdlMap->vmaAddr - res->offset_in_page, res->size) < 0)
+    {
+        printk("%s: vm_munmap failed\n", __func__);
+    }
+#else
+    down_write(&current_mm_mmap_sem);
+    if (do_munmap(current->mm, (unsigned long)MdlMap->vmaAddr - res->offset_in_page, res->size) < 0)
+    {
+        printk("%s: do_munmap failed\n", __func__);
+    }
+    up_write(&current_mm_mmap_sem);
+#endif
+}
+
+static gceSTATUS
+reserved_mem_map_user(
+    gckALLOCATOR Allocator,
+    PLINUX_MDL Mdl,
+    PLINUX_MDL_MAP MdlMap,
+    gctBOOL Cacheable
+    )
+{
+    struct reserved_mem *res = (struct reserved_mem*)Mdl->priv;
+    gctPOINTER userLogical = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+    userLogical = (gctPOINTER)vm_mmap(NULL, 0L, res->size,
+                PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, 0);
+#else
+    down_write(&current_mm_mmap_sem);
+    userLogical = (gctPOINTER)do_mmap_pgoff(NULL, 0L, res->size,
+                PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+    up_write(&current_mm_mmap_sem);
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): vmaAddr->%p for phys_addr->%p",
+        __FUNCTION__, __LINE__, userLogical, Mdl
+        );
+
+    if (IS_ERR(userLogical))
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_OS,
+            "%s(%d): do_mmap_pgoff error",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    down_write(&current_mm_mmap_sem);
+
+    do
+    {
+        struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+        if (vma == gcvNULL)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): find_vma error",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        gcmkERR_BREAK(reserved_mem_mmap(Allocator, Mdl, gcvFALSE, 0, Mdl->numPages, vma));
+
+        MdlMap->vmaAddr = userLogical + res->offset_in_page;
+        MdlMap->cacheable = gcvFALSE;
+        MdlMap->vma = vma;
+    }
+    while (gcvFALSE);
+
+    up_write(&current_mm_mmap_sem);
+
+OnError:
+    if (gcmIS_ERROR(status) && userLogical)
+    {
+        reserved_mem_unmap_user(Allocator, Mdl, userLogical, res->size);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+reserved_mem_map_kernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    struct reserved_mem *res = Mdl->priv;
+    void *vaddr;
+
+    if (Offset + Bytes > res->size)
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+    vaddr = ioremap_wc(res->start + Offset, Bytes);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
+    vaddr = ioremap(res->start + Offset, Bytes);
+#else
+    vaddr = ioremap_nocache(res->start + Offset, Bytes);
+#endif
+#endif
+
+    if (!vaddr)
+    {
+        return gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+    *Logical = vaddr;
+    return gcvSTATUS_OK;;
+}
+
+static gceSTATUS
+reserved_mem_unmap_kernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    iounmap((void *)Logical);
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+reserved_mem_cache_op(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    /* Always WC or UC, safe to use mb. */
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+    case gcvCACHE_FLUSH:
+        _MemoryBarrier();
+        break;
+    case gcvCACHE_INVALIDATE:
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+reserved_mem_get_physical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    struct reserved_mem *res = Mdl->priv;
+    *Physical = res->start + Offset;
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+reserved_mem_GetSGT(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    )
+{
+    struct page * page = gcvNULL;
+    struct sg_table *sgt = NULL;
+    struct reserved_mem *res = Mdl->priv;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+    sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+    if (!sgt)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    page = phys_to_page(res->start);
+
+    if (sg_alloc_table(sgt, 1, GFP_KERNEL)){
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+    sg_set_page(sgt->sgl, page, PAGE_ALIGN(Bytes), Offset);
+
+    *SGT = (gctPOINTER)sgt;
+
+OnError:
+    if (gcmIS_ERROR(status) && sgt)
+    {
+        kfree(sgt);
+    }
+
+    return status;
+}
+
+static void
+reserved_mem_dtor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    reserved_mem_debugfs_cleanup(Allocator);
+
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* GFP allocator operations. */
+static gcsALLOCATOR_OPERATIONS reserved_mem_ops = {
+    .Alloc              = reserved_mem_alloc,
+    .Attach             = reserved_mem_attach,
+    .Free               = reserved_mem_detach,
+    .Mmap               = reserved_mem_mmap,
+    .MapUser            = reserved_mem_map_user,
+    .UnmapUser          = reserved_mem_unmap_user,
+    .MapKernel          = reserved_mem_map_kernel,
+    .UnmapKernel        = reserved_mem_unmap_kernel,
+    .Cache              = reserved_mem_cache_op,
+    .Physical           = reserved_mem_get_physical,
+    .GetSGT             = reserved_mem_GetSGT,
+};
+
+/* GFP allocator entry. */
+gceSTATUS
+_ReservedMemoryAllocatorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator = gcvNULL;
+    struct reserved_mem_alloc *alloc = NULL;
+
+    gcmkONERROR(
+        gckALLOCATOR_Construct(Os, &reserved_mem_ops, &allocator));
+
+    alloc = kzalloc(sizeof(*alloc), GFP_KERNEL | gcdNOWARN);
+
+    if (!alloc)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    INIT_LIST_HEAD(&alloc->region);
+    mutex_init(&alloc->lock);
+
+    /* Register private data. */
+    allocator->privateData = alloc;
+    allocator->destructor = reserved_mem_dtor;
+
+    reserved_mem_debugfs_init(allocator, Parent);
+
+    allocator->capability = gcvALLOC_FLAG_LINUX_RESERVED_MEM
+                          | gcvALLOC_FLAG_CONTIGUOUS
+                          | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+                          | gcvALLOC_FLAG_CPU_ACCESS;
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (allocator)
+    {
+        kfree(allocator);
+    }
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c
@@ -0,0 +1,899 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/scatterlist.h>
+
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/cache.h>
+
+#define _GC_OBJ_ZONE gcvZONE_ALLOCATOR
+
+enum um_desc_type
+{
+    UM_PHYSICAL_MAP,
+    UM_PAGE_MAP,
+    UM_PFN_MAP,
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION (2,6,24)
+struct sg_table
+{
+    struct scatterlist *sgl;
+    unsigned int nents;
+    unsigned int orig_nents;
+};
+#endif
+
+/* Descriptor of a user memory imported. */
+struct um_desc
+{
+    int type;
+
+    union
+    {
+        /* UM_PHYSICAL_MAP. */
+        unsigned long physical;
+
+        /* UM_PAGE_MAP. */
+        struct
+        {
+            struct page **pages;
+            struct sg_table sgt;
+        };
+
+        /* UM_PFN_MAP. */
+        struct
+        {
+            unsigned long *pfns;
+            int *refs;
+        };
+    };
+
+    /* contiguous chunks, does not include padding pages. */
+    int chunk_count;
+
+    unsigned long vm_flags;
+    unsigned long user_vaddr;
+    size_t size;
+    unsigned long offset;
+
+    size_t pageCount;
+    size_t extraPage;
+};
+
+static int import_physical_map(struct um_desc *um, unsigned long phys)
+{
+    um->type = UM_PHYSICAL_MAP;
+    um->physical = phys & PAGE_MASK;
+    um->chunk_count = 1;
+    return 0;
+}
+
+static int import_page_map(struct um_desc *um,
+                unsigned long addr, size_t page_count, size_t size)
+{
+    int i;
+    int result;
+    struct page **pages;
+
+    if ((addr & (cache_line_size() - 1)) || (size & (cache_line_size() - 1)))
+    {
+        /* Not cpu cacheline size aligned, can not support. */
+        return -EINVAL;
+    }
+
+    pages = kzalloc(page_count * sizeof(void *), GFP_KERNEL | gcdNOWARN);
+    if (!pages)
+        return -ENOMEM;
+
+    down_read(&current_mm_mmap_sem);
+
+    result = get_user_pages(
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
+            current,
+            current->mm,
+#endif
+            addr & PAGE_MASK,
+            page_count,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+            FOLL_WRITE,
+#else
+            1,
+            0,
+#endif
+            pages,
+            NULL);
+
+    up_read(&current_mm_mmap_sem);
+
+    if (result < page_count)
+    {
+        for (i = 0; i < result; i++)
+        {
+            if (pages[i])
+            {
+                put_page(pages[i]);
+            }
+        }
+
+        kfree(pages);
+        return -ENODEV;
+    }
+
+    um->chunk_count = 1;
+    for (i = 1; i < page_count; i++)
+    {
+        if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+        {
+            ++um->chunk_count;
+        }
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined(ARCH_HAS_SG_CHAIN) || defined(CONFIG_ARCH_HAS_SG_CHAIN))
+    result = sg_alloc_table_from_pages(&um->sgt, pages, page_count,
+                    addr & ~PAGE_MASK, size, GFP_KERNEL | gcdNOWARN);
+
+#else
+    result = alloc_sg_list_from_pages(&um->sgt.sgl, pages, page_count,
+                    addr & ~PAGE_MASK, size, &um->sgt.nents);
+
+    um->sgt.orig_nents = um->sgt.nents;
+#endif
+    if (unlikely(result < 0))
+    {
+        printk("[galcore]: %s: sg_alloc_table_from_pages failed\n", __FUNCTION__);
+        goto error;
+    }
+
+    result = dma_map_sg(galcore_device, um->sgt.sgl, um->sgt.nents, DMA_TO_DEVICE);
+    if (unlikely(result != um->sgt.nents))
+    {
+        printk("[galcore]: %s: dma_map_sg failed\n", __FUNCTION__);
+        goto error;
+    }
+
+    um->type = UM_PAGE_MAP;
+    um->pages = pages;
+
+    return 0;
+
+error:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined(ARCH_HAS_SG_CHAIN) || defined(CONFIG_ARCH_HAS_SG_CHAIN))
+    sg_free_table(&um->sgt);
+#else
+    kfree(um->sgt.sgl);
+#endif
+
+    if (pages)
+    {
+        kfree(pages);
+    }
+    return result;
+}
+
+
+static int import_pfn_map(struct um_desc *um,
+                unsigned long addr, size_t pfn_count)
+{
+    int i;
+    struct vm_area_struct *vma;
+    unsigned long *pfns;
+    int *refs;
+
+    if (!current->mm)
+        return -ENOTTY;
+
+    down_read(&current_mm_mmap_sem);
+    vma = find_vma(current->mm, addr);
+    up_read(&current_mm_mmap_sem);
+
+    if (!vma)
+        return -ENOTTY;
+
+    pfns = kzalloc(pfn_count * sizeof(unsigned long), GFP_KERNEL | gcdNOWARN);
+
+    if (!pfns)
+        return -ENOMEM;
+
+    refs = kzalloc(pfn_count * sizeof(int), GFP_KERNEL | gcdNOWARN);
+
+    if (!refs)
+    {
+        kfree(pfns);
+        return -ENOMEM;
+    }
+
+    for (i = 0; i < pfn_count; i++)
+    {
+        spinlock_t *ptl;
+        pgd_t *pgd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (5,9,0)
+        p4d_t *p4d;
+#endif
+        pud_t *pud;
+        pmd_t *pmd;
+        pte_t *pte;
+
+        pgd = pgd_offset(current->mm, addr);
+        if (pgd_none(*pgd) || pgd_bad(*pgd))
+            goto err;
+
+#if (defined(CONFIG_CPU_CSKYV2) || defined(CONFIG_X86)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,12,0)
+        pud = pud_offset((p4d_t*)pgd, addr);
+#elif (defined(CONFIG_CPU_CSKYV2)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,11,0)
+        pud = pud_offset((p4d_t*)pgd, addr);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (5,9,0)
+        p4d = p4d_offset(pgd, addr);
+        if (p4d_none(READ_ONCE(*p4d)))
+            goto err;
+
+        pud = pud_offset(p4d, addr);
+#else
+        pud = pud_offset(pgd, addr);
+#endif
+#endif
+        if (pud_none(*pud) || pud_bad(*pud))
+            goto err;
+
+        pmd = pmd_offset(pud, addr);
+        if (pmd_none(*pmd) || pmd_bad(*pmd))
+            goto err;
+
+        pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
+        if (!pte)
+        {
+            spin_unlock(ptl);
+            goto err;
+        }
+
+        if (!pte_present(*pte))
+        {
+            pte_unmap_unlock(pte, ptl);
+            goto err;
+        }
+
+        pfns[i] = pte_pfn(*pte);
+        pte_unmap_unlock(pte, ptl);
+
+        /* Advance to next. */
+        addr += PAGE_SIZE;
+    }
+
+    for (i = 0; i < pfn_count; i++)
+    {
+        if (pfn_valid(pfns[i]))
+        {
+            struct page *page = pfn_to_page(pfns[i]);
+            refs[i] = get_page_unless_zero(page);
+        }
+    }
+
+    um->chunk_count = 1;
+    for (i = 1; i < pfn_count; i++)
+    {
+        if (pfns[i] != pfns[i - 1] + 1)
+        {
+            ++um->chunk_count;
+        }
+    }
+
+    um->type = UM_PFN_MAP;
+    um->pfns = pfns;
+    um->refs = refs;
+    return 0;
+
+err:
+    if (pfns)
+        kfree(pfns);
+
+    if (refs)
+        kfree(refs);
+
+    return -ENOTTY;
+}
+
+static gceSTATUS
+_Import(
+    IN gckOS Os,
+    IN gctPOINTER Memory,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctSIZE_T Size,
+    IN struct um_desc * UserMemory
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    unsigned long vm_flags = 0;
+    struct vm_area_struct *vma = NULL;
+    gctSIZE_T start, end, memory;
+    int result = 0;
+
+    gctSIZE_T extraPage;
+    gctSIZE_T pageCount, i;
+
+    gcmkHEADER_ARG("Os=%p Memory=%p Physical=0x%llx Size=%lu", Os, Memory, Physical, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL || Physical != ~0ULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+
+    memory = (Physical != gcvINVALID_PHYSICAL_ADDRESS) ? Physical : (gctSIZE_T)Memory;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (5,4,0)
+    memory = untagged_addr(memory);
+#endif
+
+    /* Get the number of required pages. */
+    end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+    start = memory >> PAGE_SHIFT;
+    pageCount = end - start;
+
+    /* Allocate extra page to avoid cache overflow */
+#if gcdENABLE_2D
+    extraPage = 2;
+#else
+    extraPage = (((memory + gcmALIGN(Size + 64, 64) + PAGE_SIZE - 1) >> PAGE_SHIFT) > end) ? 1 : 0;
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, _GC_OBJ_ZONE,
+        "%s(%d): pageCount: %d. extraPage: %d",
+        __FUNCTION__, __LINE__,
+        pageCount, extraPage
+        );
+
+    /* Overflow. */
+    if ((memory + Size) < memory)
+    {
+        gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    memory = (gctSIZE_T)Memory;
+
+    if (memory)
+    {
+        gctSIZE_T vaddr = memory;
+
+        for (i = 0; i < pageCount; i++)
+        {
+            u32 data = 0;
+
+            get_user(data, (u32 *)vaddr);
+            put_user(data, (u32 *)vaddr);
+            vaddr += PAGE_SIZE;
+
+            /* Fix QM crash with test_buffers */
+            if (vaddr > memory + Size - 4)
+            {
+                vaddr = memory + Size - 4;
+            }
+        }
+
+        down_read(&current_mm_mmap_sem);
+        vma = find_vma(current->mm, memory);
+        up_read(&current_mm_mmap_sem);
+
+        if (!vma)
+        {
+            /* No such memory, or across vmas. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+#ifdef CONFIG_ARM
+        /* coherent cache in case vivt or vipt-aliasing cache. */
+        __cpuc_flush_user_range(memory, memory + Size, vma->vm_flags);
+#endif
+
+        vm_flags = vma->vm_flags;
+        vaddr = vma->vm_end;
+
+        down_read(&current_mm_mmap_sem);
+        while (vaddr < memory + Size)
+        {
+            vma = find_vma(current->mm, vaddr);
+
+            if (!vma)
+            {
+                /* No such memory. */
+                up_read(&current_mm_mmap_sem);
+                gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+            }
+
+            if ((vma->vm_flags & VM_PFNMAP) != (vm_flags & VM_PFNMAP))
+            {
+                /* Can not support different map type: both PFN and PAGE detected. */
+                up_read(&current_mm_mmap_sem);
+                gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+            }
+
+            vaddr = vma->vm_end;
+        }
+        up_read(&current_mm_mmap_sem);
+    }
+
+    if (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+    {
+        result = import_physical_map(UserMemory, Physical);
+    }
+    else
+    {
+        if (vm_flags & VM_PFNMAP)
+        {
+            result = import_pfn_map(UserMemory, memory, pageCount);
+        }
+        else
+        {
+            result = import_page_map(UserMemory, memory, pageCount, Size);
+        }
+    }
+
+    if (result == -EINVAL)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+    else if (result == -ENOMEM)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+    else if (result < 0)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    if(Os->device->platform->flagBits & gcvPLATFORM_FLAG_LIMIT_4G_ADDRESS )
+    {
+        gctPHYS_ADDR_T addr;
+
+        if (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+        {
+            if(Physical > 0xFFFFFFFFu || Physical + Size > 0xFFFFFFFFu )
+            {
+                gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+            }
+        }
+        else if (vm_flags & VM_PFNMAP)
+        {
+            for(i = 0; i < pageCount; i++)
+            {
+                addr =  UserMemory->pfns[i] << PAGE_SHIFT;
+                if( addr > 0xFFFFFFFFu)
+                {
+                    kfree(UserMemory->pfns);
+                    UserMemory->pfns = gcvNULL;
+                    kfree(UserMemory->refs) ;
+                    UserMemory->refs = gcvNULL;
+                    gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+                }
+            }
+        }
+        else
+        {
+            for (i = 0; i< pageCount; i++)
+            {
+                addr = page_to_phys(UserMemory->pages[i]);
+                if(addr > 0xFFFFFFFFu )
+                {
+                    kfree(UserMemory->pages);
+                    UserMemory->pages = gcvNULL;
+                    gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+                }
+            }
+        }
+    }
+
+    UserMemory->vm_flags = vm_flags;
+    UserMemory->user_vaddr = (unsigned long)Memory;
+    UserMemory->size  = Size;
+    UserMemory->offset = (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+                       ? (Physical & ~PAGE_MASK)
+                       : (memory & ~PAGE_MASK);
+
+    UserMemory->pageCount = pageCount;
+    UserMemory->extraPage = extraPage;
+
+    if (extraPage && UserMemory->type == UM_PAGE_MAP)
+    {
+        /*Add the padding pages */
+        UserMemory->chunk_count++;
+    }
+
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_UserMemoryAttach(
+    IN gckALLOCATOR Allocator,
+    IN gcsATTACH_DESC_PTR Desc,
+    IN PLINUX_MDL Mdl
+    )
+{
+    gceSTATUS status;
+    struct um_desc * userMemory = gcvNULL;
+
+    gckOS os = Allocator->os;
+
+    gcmkHEADER();
+
+    /* Handle is meangless for this importer. */
+    gcmkVERIFY_ARGUMENT(Desc != gcvNULL);
+
+    gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct um_desc), (gctPOINTER *)&userMemory));
+
+    gckOS_ZeroMemory(userMemory, gcmSIZEOF(struct um_desc));
+
+    gcmkONERROR(_Import(os, Desc->userMem.memory, Desc->userMem.physical, Desc->userMem.size, userMemory));
+
+    Mdl->priv = userMemory;
+    Mdl->numPages = userMemory->pageCount + userMemory->extraPage;
+    Mdl->contiguous = (userMemory->chunk_count == 1);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (userMemory != gcvNULL)
+    {
+        gckOS_Free(os,(gctPOINTER)userMemory);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static void release_physical_map(struct um_desc *um)
+{
+}
+
+static void release_page_map(struct um_desc *um)
+{
+    int i;
+    dma_sync_sg_for_device(galcore_device,
+                    um->sgt.sgl, um->sgt.nents, DMA_TO_DEVICE);
+
+    dma_sync_sg_for_cpu(galcore_device,
+                    um->sgt.sgl, um->sgt.nents, DMA_FROM_DEVICE);
+
+    dma_unmap_sg(galcore_device, um->sgt.sgl, um->sgt.nents, DMA_FROM_DEVICE);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,6,0) \
+    && (defined(ARCH_HAS_SG_CHAIN) || defined(CONFIG_ARCH_HAS_SG_CHAIN))
+    sg_free_table(&um->sgt);
+#else
+    kfree(um->sgt.sgl);
+#endif
+
+    for (i = 0; i < um->pageCount; i++)
+    {
+        if (!PageReserved(um->pages[i]))
+        {
+             SetPageDirty(um->pages[i]);
+        }
+
+        put_page(um->pages[i]);
+    }
+
+    kfree(um->pages);
+}
+
+static void release_pfn_map(struct um_desc *um)
+{
+
+    int i;
+
+    for (i = 0; i < um->pageCount; i++)
+    {
+        if (pfn_valid(um->pfns[i]))
+        {
+            struct page *page = pfn_to_page(um->pfns[i]);
+            if (!PageReserved(page))
+            {
+                SetPageDirty(page);
+            }
+
+            if (um->refs[i])
+            {
+                put_page(page);
+            }
+        }
+    }
+
+    kfree(um->pfns);
+    kfree(um->refs);
+}
+
+static void
+_UserMemoryFree(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl
+    )
+{
+    gckOS os = Allocator->os;
+    struct um_desc *userMemory = Mdl->priv;
+
+    gcmkHEADER();
+
+    if (userMemory)
+    {
+        switch (userMemory->type)
+        {
+        case UM_PHYSICAL_MAP:
+            release_physical_map(userMemory);
+            break;
+        case UM_PAGE_MAP:
+            release_page_map(userMemory);
+            break;
+        case UM_PFN_MAP:
+            release_pfn_map(userMemory);
+            break;
+        }
+
+        gcmkOS_SAFE_FREE(os, userMemory);
+    }
+
+    gcmkFOOTER_NO();
+}
+
+static gceSTATUS
+_UserMemoryMapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctBOOL Cacheable
+    )
+{
+    struct um_desc *userMemory = Mdl->priv;
+
+    MdlMap->vmaAddr = (gctPOINTER)userMemory->user_vaddr;
+    MdlMap->cacheable = gcvTRUE;
+
+    return gcvSTATUS_OK;
+}
+
+static void
+_UserMemoryUnmapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    return;
+}
+
+static gceSTATUS
+_UserMemoryMapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    /* Kernel doesn't acess video memory. */
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+_UserMemoryUnmapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    /* Kernel doesn't acess video memory. */
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+_UserMemoryCache(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    struct um_desc *um = Mdl->priv;
+    enum dma_data_direction dir;
+
+    if (um->type != UM_PAGE_MAP)
+    {
+        _MemoryBarrier();
+        return gcvSTATUS_OK;
+    }
+
+#ifdef CONFIG_ARM
+    /* coherent cache in case vivt or vipt-aliasing cache. */
+    __cpuc_flush_user_range(um->user_vaddr,
+                            um->user_vaddr + um->size, um->vm_flags);
+#endif
+
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+        dir = DMA_TO_DEVICE;
+        dma_sync_sg_for_device(galcore_device, um->sgt.sgl, um->sgt.nents, dir);
+        break;
+    case gcvCACHE_FLUSH:
+        dir = DMA_TO_DEVICE;
+        dma_sync_sg_for_device(galcore_device, um->sgt.sgl, um->sgt.nents, dir);
+        dir = DMA_FROM_DEVICE;
+        dma_sync_sg_for_cpu(galcore_device, um->sgt.sgl, um->sgt.nents, dir);
+        break;
+    case gcvCACHE_INVALIDATE:
+        dir = DMA_FROM_DEVICE;
+        dma_sync_sg_for_cpu(galcore_device, um->sgt.sgl, um->sgt.nents, dir);
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_UserMemoryPhysical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    gckOS os = Allocator->os;
+    struct um_desc *userMemory = Mdl->priv;
+    unsigned long offset = Offset + userMemory->offset;
+    gctUINT32 offsetInPage = offset & ~PAGE_MASK;
+    gctUINT32 index = offset / PAGE_SIZE;
+
+    if (index >= userMemory->pageCount)
+    {
+        if (index < userMemory->pageCount + userMemory->extraPage)
+        {
+            *Physical = page_to_phys(os->paddingPage);
+        }
+        else
+        {
+            return gcvSTATUS_INVALID_ARGUMENT;
+        }
+    }
+    else
+    {
+        switch (userMemory->type)
+        {
+        case UM_PHYSICAL_MAP:
+            *Physical = userMemory->physical + (gctPHYS_ADDR_T)index * PAGE_SIZE;
+            break;
+        case UM_PAGE_MAP:
+            *Physical = page_to_phys(userMemory->pages[index]);
+            break;
+        case UM_PFN_MAP:
+            *Physical = (gctPHYS_ADDR_T)userMemory->pfns[index] << PAGE_SHIFT;
+            break;
+        }
+    }
+
+    *Physical += offsetInPage;
+
+    return gcvSTATUS_OK;
+}
+
+static void
+_UserMemoryAllocatorDestructor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* User memory allocator (importer) operations. */
+static gcsALLOCATOR_OPERATIONS UserMemoryAllocatorOperations =
+{
+    .Attach             = _UserMemoryAttach,
+    .Free               = _UserMemoryFree,
+    .MapUser            = _UserMemoryMapUser,
+    .UnmapUser          = _UserMemoryUnmapUser,
+    .MapKernel          = _UserMemoryMapKernel,
+    .UnmapKernel        = _UserMemoryUnmapKernel,
+    .Cache              = _UserMemoryCache,
+    .Physical           = _UserMemoryPhysical,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_UserMemoryAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator;
+
+    gcmkONERROR(
+        gckALLOCATOR_Construct(Os, &UserMemoryAllocatorOperations, &allocator));
+
+    allocator->destructor  = _UserMemoryAllocatorDestructor;
+
+    allocator->capability = gcvALLOC_FLAG_USERMEMORY;
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_array_h_
+#define __gc_hal_kernel_allocator_array_h_
+
+extern gceSTATUS
+_GFPAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+extern gceSTATUS
+_UserMemoryAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+extern gceSTATUS
+_ReservedMemoryAllocatorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+
+#if LINUX_CMA_FSL
+extern gceSTATUS
+_CMAFSLAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+#endif
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+extern gceSTATUS
+_DmabufAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+#endif
+
+#ifndef NO_DMA_COHERENT
+extern gceSTATUS
+_DmaAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    );
+#endif
+
+gcsALLOCATOR_DESC allocatorArray[] =
+{
+    /* GFP allocator. */
+    gcmkDEFINE_ALLOCATOR_DESC("gfp", _GFPAlloctorInit),
+
+#if LINUX_CMA_FSL
+    gcmkDEFINE_ALLOCATOR_DESC("cmafsl", _CMAFSLAlloctorInit),
+#endif
+
+    /* User memory importer. */
+    gcmkDEFINE_ALLOCATOR_DESC("user", _UserMemoryAlloctorInit),
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+    /* Dmabuf allocator. */
+    gcmkDEFINE_ALLOCATOR_DESC("dmabuf", _DmabufAlloctorInit),
+#endif
+
+#ifndef NO_DMA_COHERENT
+    gcmkDEFINE_ALLOCATOR_DESC("dma", _DmaAlloctorInit),
+#endif
+
+    gcmkDEFINE_ALLOCATOR_DESC("reserved-mem", _ReservedMemoryAllocatorInit),
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c
@@ -0,0 +1,640 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,16,0)
+#include <linux/dma-direct.h>
+#endif
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+typedef struct _gcsCMA_PRIV * gcsCMA_PRIV_PTR;
+typedef struct _gcsCMA_PRIV {
+    atomic_t cmasize;
+    gctBOOL cmaLimitRequest;
+}
+gcsCMA_PRIV;
+
+struct mdl_cma_priv {
+    gctPOINTER kvaddr;
+    dma_addr_t physical;
+};
+
+static int gc_cma_usage_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckALLOCATOR Allocator = node->device;
+    gcsCMA_PRIV_PTR priv = Allocator->privateData;
+    long long size = (long long)atomic_read(&priv->cmasize);
+
+    seq_printf(m, "type        n pages        bytes\n");
+    seq_printf(m, "cma      %10llu %12llu\n", size, size * PAGE_SIZE);
+
+    return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+    {"cmausage", gc_cma_usage_show},
+};
+
+static void
+_CMAAllocatorDebugfsInit(
+    IN gckALLOCATOR Allocator,
+    IN gckDEBUGFS_DIR Root
+    )
+{
+    gcmkVERIFY_OK(
+        gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "cma"));
+
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList),
+        Allocator
+        ));
+}
+
+static void
+_CMAAllocatorDebugfsCleanup(
+    IN gckALLOCATOR Allocator
+    )
+{
+    gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+        &Allocator->debugfsDir,
+        InfoList,
+        gcmCOUNTOF(InfoList)
+        ));
+
+    gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+_CMAFSLAlloc(
+    IN gckALLOCATOR Allocator,
+    INOUT PLINUX_MDL Mdl,
+    IN gctSIZE_T NumPages,
+    IN gctUINT32 Flags
+    )
+{
+    gceSTATUS status;
+    u32 gfp = GFP_KERNEL | gcdNOWARN;
+    gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData;
+
+    struct mdl_cma_priv *mdl_priv=gcvNULL;
+    gckOS os = Allocator->os;
+
+    gcmkHEADER_ARG("Mdl=%p NumPages=0x%zx", Mdl, NumPages);
+
+    if (os->allocatorLimitMarker && !(Flags & gcvALLOC_FLAG_CMA_PREEMPT))
+    {
+        if (Flags & gcvALLOC_FLAG_CMA_LIMIT)
+        {
+            priv->cmaLimitRequest = gcvTRUE;
+        }
+        else if (priv->cmaLimitRequest == gcvTRUE)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+        }
+    }
+
+    gcmkONERROR(gckOS_Allocate(os, sizeof(struct mdl_cma_priv), (gctPOINTER *)&mdl_priv));
+    mdl_priv->kvaddr = gcvNULL;
+
+#if defined(CONFIG_ZONE_DMA32) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+    if (Flags & gcvALLOC_FLAG_4GB_ADDR)
+    {
+        gfp |= __GFP_DMA32;
+    }
+#endif
+
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+    mdl_priv->kvaddr = dma_alloc_wc(&os->device->platform->device->dev,
+#else
+    mdl_priv->kvaddr = dma_alloc_writecombine(&os->device->platform->device->dev,
+#endif
+#else
+    mdl_priv->kvaddr = dma_alloc_coherent(&os->device->platform->device->dev,
+#endif
+            NumPages * PAGE_SIZE,
+            &mdl_priv->physical,
+            gfp);
+
+    if (mdl_priv->kvaddr == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    Mdl->priv = mdl_priv;
+    Mdl->dmaHandle = mdl_priv->physical;
+    atomic_add(NumPages, &priv->cmasize);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mdl_priv)
+    {
+        gckOS_Free(os, mdl_priv);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_CMAFSLGetSGT(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+    struct page ** pages = gcvNULL;
+    struct page * page = gcvNULL;
+    struct sg_table *sgt = NULL;
+    struct mdl_cma_priv *mdl_priv = (struct mdl_cma_priv*)Mdl->priv;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+    gctINT skipPages = Offset >> PAGE_SHIFT;     /* skipped pages */
+    gctINT numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+    gctINT i;
+
+    gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+    sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+    if (!sgt)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    pages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+    if (!pages)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+#if !defined(phys_to_page)
+    page = virt_to_page(mdlPriv->kvaddr);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+    page = phys_to_page(mdlPriv->physical);
+#else
+    page = phys_to_page(dma_to_phys(&Allocator->os->device->platform->device->dev, mdl_priv->physical));
+#endif
+
+    for (i = 0; i < numPages; ++i)
+    {
+        pages[i] = nth_page(page, i + skipPages);
+    }
+
+    if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    *SGT = (gctPOINTER)sgt;
+
+OnError:
+    if (pages)
+    {
+        kfree(pages);
+    }
+
+    if (gcmIS_ERROR(status) && sgt)
+    {
+        kfree(sgt);
+    }
+
+    return status;
+#else
+    return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_CMAFSLFree(
+    IN gckALLOCATOR Allocator,
+    IN OUT PLINUX_MDL Mdl
+    )
+{
+    gckOS os = Allocator->os;
+    struct mdl_cma_priv *mdlPriv=(struct mdl_cma_priv *)Mdl->priv;
+    gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData;
+
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+    dma_free_wc(&os->device->platform->device->dev,
+#else
+    dma_free_writecombine(&os->device->platform->device->dev,
+#endif
+#else
+    dma_free_coherent(&os->device->platform->device->dev,
+#endif
+            Mdl->numPages * PAGE_SIZE,
+            mdlPriv->kvaddr,
+            mdlPriv->physical);
+
+    gckOS_Free(os, mdlPriv);
+    atomic_sub(Mdl->numPages, &priv->cmasize);
+}
+
+static gceSTATUS
+_CMAFSLMmap(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctBOOL Cacheable,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    IN struct vm_area_struct *vma
+    )
+{
+    gckOS os = Allocator->os;
+    struct mdl_cma_priv *mdlPriv = (struct mdl_cma_priv*)Mdl->priv;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+    gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+    /* Now map all the vmalloc pages to this user address. */
+    if (Mdl->contiguous)
+    {
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+        /* map kernel memory to user space.. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+        if (dma_mmap_wc(&os->device->platform->device->dev,
+#else
+        if (dma_mmap_writecombine(&os->device->platform->device->dev,
+#endif
+#else
+        if (dma_mmap_coherent(&os->device->platform->device->dev,
+#endif
+            vma,
+            (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+            mdlPriv->physical + (skipPages << PAGE_SHIFT),
+            numPages << PAGE_SHIFT) < 0)
+
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): dma_mmap_attrs error",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+    else
+    {
+        gcmkFATAL("%s(%d): unexpected noncontiguous mdl\n");
+        gcmkONERROR(gcvSTATUS_HEAP_CORRUPTED);
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static void
+_CMAFSLUnmapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctUINT32 Size
+    )
+{
+    if (unlikely(current->mm == gcvNULL))
+    {
+        /* Do nothing if process is exiting. */
+        return;
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+    if (vm_munmap((unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): vm_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+#else
+    down_write(&current_mm_mmap_sem);
+    if (do_munmap(current->mm, (unsigned long)MdlMap->vmaAddr, Size) < 0)
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_WARNING, gcvZONE_OS,
+                "%s(%d): do_munmap failed",
+                __FUNCTION__, __LINE__
+                );
+    }
+    up_write(&current_mm_mmap_sem);
+#endif
+}
+
+static gceSTATUS
+_CMAFSLMapUser(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap,
+    IN gctBOOL Cacheable
+    )
+{
+    gctPOINTER userLogical = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+    userLogical = (gctPOINTER)vm_mmap(gcvNULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED | MAP_NORESERVE,
+                    0);
+#else
+    down_write(&current_mm_mmap_sem);
+    userLogical = (gctPOINTER)do_mmap_pgoff(gcvNULL,
+                    0L,
+                    Mdl->numPages * PAGE_SIZE,
+                    PROT_READ | PROT_WRITE,
+                    MAP_SHARED,
+                    0);
+    up_write(&current_mm_mmap_sem);
+#endif
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): vmaAddr->%p for phys_addr->%p",
+        __FUNCTION__, __LINE__, userLogical, Mdl
+        );
+
+    if (IS_ERR(userLogical))
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_OS,
+            "%s(%d): do_mmap_pgoff error",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    down_write(&current_mm_mmap_sem);
+
+    do
+    {
+        struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+        if (vma == gcvNULL)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): find_vma error",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+        gcmkERR_BREAK(_CMAFSLMmap(Allocator, Mdl, Cacheable, 0, Mdl->numPages, vma));
+        MdlMap->vmaAddr = userLogical;
+        MdlMap->cacheable = Cacheable;
+        MdlMap->vma = vma;
+    }
+    while (gcvFALSE);
+
+    up_write(&current_mm_mmap_sem);
+
+OnError:
+    if (gcmIS_ERROR(status) && userLogical && !IS_ERR(userLogical))
+    {
+        _CMAFSLUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_CMAMapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical
+    )
+{
+    struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv;
+    *Logical = (uint8_t *)mdl_priv->kvaddr + Offset;
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMAUnmapKernel(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctPOINTER Logical
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMACache(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    switch (Operation)
+    {
+    case gcvCACHE_CLEAN:
+    case gcvCACHE_FLUSH:
+        _MemoryBarrier();
+        break;
+    case gcvCACHE_INVALIDATE:
+        break;
+    default:
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMAPhysical(
+    IN gckALLOCATOR Allocator,
+    IN PLINUX_MDL Mdl,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv;
+
+    *Physical = mdl_priv->physical + Offset;
+
+    return gcvSTATUS_OK;
+}
+
+static void
+_CMAAllocatorDestructor(
+    gcsALLOCATOR *Allocator
+    )
+{
+    _CMAAllocatorDebugfsCleanup(Allocator);
+
+    if (Allocator->privateData)
+    {
+        kfree(Allocator->privateData);
+    }
+
+    kfree(Allocator);
+}
+
+/* Default allocator operations. */
+static gcsALLOCATOR_OPERATIONS CMAFSLAllocatorOperations =
+{
+    .Alloc              = _CMAFSLAlloc,
+    .Free               = _CMAFSLFree,
+    .Mmap               = _CMAFSLMmap,
+    .MapUser            = _CMAFSLMapUser,
+    .UnmapUser          = _CMAFSLUnmapUser,
+    .MapKernel          = _CMAMapKernel,
+    .UnmapKernel        = _CMAUnmapKernel,
+    .Cache              = _CMACache,
+    .Physical           = _CMAPhysical,
+    .GetSGT             = _CMAFSLGetSGT,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_CMAFSLAlloctorInit(
+    IN gckOS Os,
+    IN gcsDEBUGFS_DIR *Parent,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator = gcvNULL;
+    gcsCMA_PRIV_PTR priv = gcvNULL;
+
+    gcmkONERROR(
+        gckALLOCATOR_Construct(Os, &CMAFSLAllocatorOperations, &allocator));
+
+    priv = kzalloc(gcmSIZEOF(gcsCMA_PRIV), GFP_KERNEL | gcdNOWARN);
+
+    if (!priv)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    atomic_set(&priv->cmasize, 0);
+
+    /* Register private data. */
+    allocator->privateData = priv;
+    allocator->destructor = _CMAAllocatorDestructor;
+
+    _CMAAllocatorDebugfsInit(allocator, Parent);
+
+    allocator->capability = gcvALLOC_FLAG_CONTIGUOUS
+                          | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+#if defined(CONFIG_ZONE_DMA32) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+                          | gcvALLOC_FLAG_4GB_ADDR
+#endif
+                          ;
+#if defined(CONFIG_ARM64)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+    Os->allocatorLimitMarker = (Os->device->baseAddress + totalram_pages() * PAGE_SIZE) > 0x100000000;
+#else
+    Os->allocatorLimitMarker = (Os->device->baseAddress + totalram_pages * PAGE_SIZE) > 0x100000000;
+#endif
+#else
+    Os->allocatorLimitMarker = gcvFALSE;
+#endif
+    priv->cmaLimitRequest = gcvFALSE;
+
+    if (Os->allocatorLimitMarker)
+    {
+        allocator->capability |= gcvALLOC_FLAG_CMA_LIMIT;
+    }
+
+    allocator->capability |= gcvALLOC_FLAG_CMA_PREEMPT;
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (allocator)
+    {
+        kfree(allocator);
+    }
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c
@@ -0,0 +1,260 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+#include <linux/anon_inodes.h>
+#endif
+#include <linux/file.h>
+
+#include "gc_hal_kernel_allocator_array.h"
+#include "gc_hal_kernel_platform.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+
+/******************************************************************************\
+******************************** Debugfs Support *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_AllocatorDebugfsInit(
+    IN gckOS Os
+    )
+{
+    gceSTATUS status;
+    gckGALDEVICE device = Os->device;
+
+    gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir;
+
+    gcmkONERROR(gckDEBUGFS_DIR_Init(dir, device->debugfsDir.root, "allocators"));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+static void
+_AllocatorDebugfsCleanup(
+    IN gckOS Os
+    )
+{
+    gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir;
+
+    gckDEBUGFS_DIR_Deinit(dir);
+}
+
+/***************************************************************************\
+************************ Allocator management *******************************
+\***************************************************************************/
+
+gceSTATUS
+gckOS_ImportAllocators(
+    gckOS Os
+    )
+{
+    gceSTATUS status;
+    gctUINT i;
+    gckALLOCATOR allocator;
+
+    _AllocatorDebugfsInit(Os);
+
+    INIT_LIST_HEAD(&Os->allocatorList);
+
+    for (i = 0; i < gcmCOUNTOF(allocatorArray); i++)
+    {
+        if (allocatorArray[i].construct)
+        {
+            /* Construct allocator. */
+            status = allocatorArray[i].construct(Os, &Os->allocatorDebugfsDir, &allocator);
+
+            if (gcmIS_ERROR(status))
+            {
+                gcmkPRINT("["DEVICE_NAME"]: Can't construct allocator(%s)",
+                          allocatorArray[i].name);
+
+                continue;
+            }
+
+            allocator->name = allocatorArray[i].name;
+
+            list_add_tail(&allocator->link, &Os->allocatorList);
+        }
+    }
+
+#if gcdDEBUG
+    list_for_each_entry(allocator, &Os->allocatorList, link)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_WARNING, gcvZONE_OS,
+            "%s(%d) Allocator: %s",
+            __FUNCTION__, __LINE__,
+            allocator->name
+            );
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_FreeAllocators(
+    gckOS Os
+    )
+{
+    gckALLOCATOR allocator;
+    gckALLOCATOR temp;
+
+    list_for_each_entry_safe(allocator, temp, &Os->allocatorList, link)
+    {
+        list_del(&allocator->link);
+
+        /* Destroy allocator. */
+        allocator->destructor(allocator);
+    }
+
+    _AllocatorDebugfsCleanup(Os);
+
+    return gcvSTATUS_OK;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION (3,6,0) \
+    || (!defined (ARCH_HAS_SG_CHAIN) && !defined (CONFIG_ARCH_HAS_SG_CHAIN))
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
+                   unsigned int len, unsigned int offset)
+{
+    sg->page = page;
+    sg->offset = offset;
+    sg->length = len;
+}
+
+static inline void sg_mark_end(struct scatterlist *sg)
+{
+    (void)sg;
+}
+#  endif
+
+int
+alloc_sg_list_from_pages(
+    struct scatterlist **sgl,
+    struct page **pages,
+    unsigned int  n_pages,
+    unsigned long offset,
+    unsigned long size,
+    unsigned int  *nents
+    )
+{
+    unsigned int chunks;
+    unsigned int i;
+    unsigned int cur_page;
+    struct scatterlist *s;
+
+    chunks = 1;
+
+    for (i = 1; i < n_pages; ++i)
+    {
+        if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+        {
+            ++chunks;
+        }
+    }
+
+    s = kzalloc(sizeof(struct scatterlist) * chunks, GFP_KERNEL);
+    if (unlikely(!s))
+    {
+        return -ENOMEM;
+    }
+
+    *sgl = s;
+    *nents = chunks;
+
+    cur_page = 0;
+
+    for (i = 0; i < chunks; i++, s++)
+    {
+        unsigned long chunk_size;
+        unsigned int j;
+
+        for (j = cur_page + 1; j < n_pages; j++)
+        {
+            if (page_to_pfn(pages[j]) != page_to_pfn(pages[j - 1]) + 1)
+            {
+                break;
+            }
+        }
+
+        chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
+        sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
+        size -= chunk_size;
+        offset = 0;
+        cur_page = j;
+    }
+
+    sg_mark_end(s - 1);
+
+    return 0;
+}
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h
@@ -0,0 +1,608 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_h_
+#define __gc_hal_kernel_allocator_h_
+
+#include "gc_hal_kernel_linux.h"
+#include <linux/slab.h>
+#include <linux/mm_types.h>
+
+typedef struct _gcsALLOCATOR * gckALLOCATOR;
+typedef union _gcsATTACH_DESC * gcsATTACH_DESC_PTR;
+
+typedef struct _gcsALLOCATOR_OPERATIONS
+{
+    /**************************************************************************
+    **
+    ** Alloc
+    **
+    ** Allocte memory, request size is page aligned.
+    **
+    ** INPUT:
+    **
+    **    gckALLOCATOR Allocator
+    **        Pointer to an gckALLOCATOER object.
+    **
+    **    PLINUX_Mdl
+    **        Pointer to Mdl whichs stores information
+    **        about allocated memory.
+    **
+    **    gctSIZE_T NumPages
+    **        Number of pages need to allocate.
+    **
+    **    gctUINT32 Flag
+    **        Allocation option.
+    **
+    ** OUTPUT:
+    **
+    **      Nothing.
+    **
+    */
+    gceSTATUS
+    (*Alloc)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctSIZE_T NumPages,
+        IN gctUINT32 Flag
+        );
+
+    /**************************************************************************
+    **
+    ** Free
+    **
+    ** Free memory.
+    **
+    ** INPUT:
+    **
+    **     gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **     PLINUX_MDL Mdl
+    **          Mdl which stores information.
+    **
+    ** OUTPUT:
+    **
+    **      Nothing.
+    **
+    */
+    void
+    (*Free)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl
+        );
+
+    /**************************************************************************
+    **
+    ** Mmap
+    **
+    ** Map a page range of the memory to user space.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl.
+    **
+    **      gctSIZE_T skipPages
+    **          Number of page to be skipped from beginning of this memory.
+    **
+    **      gctSIZE_T numPages
+    **          Number of pages to be mapped from skipPages.
+    **
+    ** INOUT:
+    **
+    **      struct vm_area_struct *vma
+    **          Pointer to VMM memory area.
+    **
+    */
+    gceSTATUS
+    (*Mmap)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctBOOL Cacheable,
+        IN gctSIZE_T skipPages,
+        IN gctSIZE_T numPages,
+        IN struct vm_area_struct *vma
+        );
+
+    /**************************************************************************
+    **
+    ** MapUser
+    **
+    ** Map memory to user space.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl.
+    **
+    **      gctBOOL Cacheable
+    **          Whether this mapping is cacheable.
+    **
+    ** OUTPUT:
+    **
+    **      gctPOINTER * UserLogical
+    **          Pointer to user logical address.
+    **
+    **      Nothing.
+    **
+    */
+    gceSTATUS
+    (*MapUser)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN PLINUX_MDL_MAP MdlMap,
+        IN gctBOOL Cacheable
+        );
+
+    /**************************************************************************
+    **
+    ** UnmapUser
+    **
+    ** Unmap address from user address space.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      gctPOINTER Logical
+    **          Address to be unmap
+    **
+    **      gctUINT32 Size
+    **          Size of address space
+    **
+    ** OUTPUT:
+    **
+    **      Nothing.
+    **
+    */
+    void
+    (*UnmapUser)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN PLINUX_MDL_MAP MdlMap,
+        IN gctUINT32 Size
+        );
+
+    /**************************************************************************
+    **
+    ** MapKernel
+    **
+    ** Map memory to kernel space.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl object.
+    **
+    ** OUTPUT:
+    **      gctPOINTER * Logical
+    **          Mapped kernel address.
+    */
+    gceSTATUS
+    (*MapKernel)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctSIZE_T Offset,
+        IN gctSIZE_T Bytes,
+        OUT gctPOINTER *Logical
+        );
+
+    /**************************************************************************
+    **
+    ** UnmapKernel
+    **
+    ** Unmap memory from kernel space.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl object.
+    **
+    **      gctPOINTER Logical
+    **          Mapped kernel address.
+    **
+    ** OUTPUT:
+    **
+    **      Nothing.
+    **
+    */
+    gceSTATUS
+    (*UnmapKernel)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctPOINTER Logical
+        );
+
+    /**************************************************************************
+    **
+    ** Cache
+    **
+    ** Maintain cache coherency.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl object.
+    **
+    **      gctPOINTER Logical
+    **          Logical address, could be user address or kernel address
+    **
+    **      gctSIZE_T Offset
+    **          Physical address.
+    **
+    **      gctUINT32 Bytes
+    **          Size of memory region.
+    **
+    **      gceCACHEOPERATION Opertaion
+    **          Cache operation.
+    **
+    ** OUTPUT:
+    **
+    **      Nothing.
+    **
+    */
+    gceSTATUS (*Cache)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctSIZE_T Offset,
+        IN gctPOINTER Logical,
+        IN gctSIZE_T Bytes,
+        IN gceCACHEOPERATION Operation
+        );
+
+    /**************************************************************************
+    **
+    ** Physical
+    **
+    ** Get physical address from a offset in memory region.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      PLINUX_MDL Mdl
+    **          Pointer to a Mdl object.
+    **
+    **      gctUINT32 Offset
+    **          Offset in this memory region.
+    **
+    ** OUTPUT:
+    **      gctUINT32_PTR Physical
+    **          Physical address.
+    **
+    */
+    gceSTATUS (*Physical)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctUINT32 Offset,
+        OUT gctPHYS_ADDR_T * Physical
+        );
+
+    /**************************************************************************
+    **
+    ** Attach
+    **
+    ** Import memory allocated by an external allocator.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      gctUINT32 Handle
+    **          Handle of the memory.
+    **
+    ** OUTPUT:
+    **      None.
+    **
+    */
+    gceSTATUS (*Attach)(
+        IN gckALLOCATOR Allocator,
+        IN gcsATTACH_DESC_PTR Desc,
+        OUT PLINUX_MDL Mdl
+        );
+
+    /**************************************************************************
+    **
+    ** GetSGT
+    **
+    ** Get scatter-gather table from a range of the memory.
+    **
+    ** INPUT:
+    **      gckALLOCATOR Allocator
+    **          Pointer to an gckALLOCATOER object.
+    **
+    **      gctUINT32 Handle
+    **          Handle of the memory.
+    **
+    **      gctSIZE_T Offset
+    **          Offset to the beginning of this mdl.
+    **
+    **      gctSIZE_T Bytes
+    **          Total bytes form Offset.
+    **
+    ** OUTPUT:
+    **      gctPOINTER *SGT
+    **          scatter-gather table
+    **
+    */
+    gceSTATUS (*GetSGT)(
+        IN gckALLOCATOR Allocator,
+        IN PLINUX_MDL Mdl,
+        IN gctSIZE_T Offset,
+        IN gctSIZE_T Bytes,
+        OUT gctPOINTER *SGT
+        );
+}
+gcsALLOCATOR_OPERATIONS;
+
+/* defination of allocator operations wrapper*/
+#define gcmALLOCATOR_Alloc(Allocator, Mdl, NumPages, Flag)     \
+            (Allocator)->ops->Alloc((Allocator), (Mdl), (NumPages), (Flag))
+
+#define gcmALLOCATOR_Free(Allocator, Mdl)      \
+            (Allocator)->ops->Free((Allocator), (Mdl))
+
+#define gcmALLOCATOR_Mmap(Allocator, Mdl, Cacheable, skipPages, numPages, vma) \
+            (Allocator)->ops->Mmap((Allocator), (Mdl), (Cacheable), (skipPages), (numPages), (vma))
+
+#define gcmALLOCATOR_MapUser(Allocator, Mdl, MdlMap, Cacheable)    \
+            (Allocator)->ops->MapUser((Allocator), (Mdl), (MdlMap), (Cacheable))
+
+#define gcmALLOCATOR_UnmapUser(Allocator, Mdl, MdlMap, Size)   \
+            (Allocator)->ops->UnmapUser((Allocator), (Mdl), (MdlMap), (Size))
+
+#define gcmALLOCATOR_MapKernel(Allocator, Mdl, Offset, Bytes, Logical) \
+            (Allocator)->ops->MapKernel((Allocator), (Mdl), (Offset), (Bytes), (Logical))
+
+#define gcmALLOCATOR_UnmapKernel(Allocator, Mdl, Logical) \
+            (Allocator)->ops->UnmapKernel((Allocator), (Mdl), (Logical))
+
+#define gcmALLOCATOR_Cache(Allocator, Mdl, Offset, Logical, Bytes, Operation)  \
+            (Allocator)->ops->Cache((Allocator), (Mdl), (Offset), (Logical), (Bytes), (Operation))
+
+#define gcmALLOCATOR_Physical(Allocator, Mdl, Offset, Phys)    \
+            (Allocator)->ops->Physical((Allocator), (Mdl), (Offset), (Phys))
+
+#define gcmALLOCATOR_Attach(Allocator, Desc, Mdl)  \
+            (Allocator)->ops->Attach((Allocator), (Desc), (Mdl))
+
+#define gcmALLOCATOR_GetSGT(Allocator, Mdl, Offset, Bytes, SGT) \
+            (Allocator)->ops->GetSGT((Allocator), (Mdl), (Offset), (Bytes), (SGT))
+
+typedef struct _gcsALLOCATOR
+{
+    /* Pointer to gckOS Object. */
+    gckOS                     os;
+
+    /* Name. */
+    gctSTRING                 name;
+
+    /* Operations. */
+    gcsALLOCATOR_OPERATIONS * ops;
+
+    /* Capability of this allocator. */
+    gctUINT32                 capability;
+
+    /* Debugfs entry of this allocator. */
+    gcsDEBUGFS_DIR            debugfsDir;
+
+    /* Private data used by customer allocator. */
+    void *                    privateData;
+
+    /* Allocator destructor. */
+    void                      (*destructor)(struct _gcsALLOCATOR *);
+
+    struct list_head          link;
+}
+gcsALLOCATOR;
+
+typedef struct _gcsALLOCATOR_DESC
+{
+    /* Name of a allocator. */
+    char *                    name;
+
+    /* Entry function to construct a allocator. */
+    gceSTATUS                 (*construct)(gckOS, gcsDEBUGFS_DIR *, gckALLOCATOR *);
+}
+gcsALLOCATOR_DESC;
+
+typedef union _gcsATTACH_DESC
+{
+    /* gcvALLOC_FLAG_DMABUF */
+    struct
+    {
+        gctPOINTER              dmabuf;
+    }
+    dmaBuf;
+
+    /* gcvALLOC_FLAG_USERMEMORY */
+    struct
+    {
+        gctPOINTER              memory;
+        gctPHYS_ADDR_T          physical;
+        gctSIZE_T               size;
+    }
+    userMem;
+
+    /* gcvALLOC_FLAG_EXTERNAL_MEMORY */
+    struct
+    {
+        gcsEXTERNAL_MEMORY_INFO info;
+    }
+    externalMem;
+
+    /* Reserved memory. */
+    struct
+    {
+        unsigned long           start;
+        unsigned long           size;
+        const char *            name;
+        int                     requested;
+    }
+    reservedMem;
+}
+gcsATTACH_DESC;
+
+/*
+* Helpers
+*/
+
+/* Fill a gcsALLOCATOR_DESC structure. */
+#define gcmkDEFINE_ALLOCATOR_DESC(Name, Construct) \
+    { \
+        .name      = Name, \
+        .construct = Construct, \
+    }
+
+/* Construct a allocator. */
+static inline gceSTATUS
+gckALLOCATOR_Construct(
+    IN gckOS Os,
+    IN gcsALLOCATOR_OPERATIONS * Operations,
+    OUT gckALLOCATOR * Allocator
+    )
+{
+    gceSTATUS status;
+    gckALLOCATOR allocator;
+
+    gcmkASSERT(Allocator != gcvNULL);
+    gcmkASSERT
+        (  Operations
+        && (Operations->Alloc || Operations->Attach)
+        && (Operations->Free)
+        && Operations->MapUser
+        && Operations->UnmapUser
+        && Operations->MapKernel
+        && Operations->UnmapKernel
+        && Operations->Cache
+        && Operations->Physical
+        );
+
+    allocator = kzalloc(sizeof(gcsALLOCATOR), GFP_KERNEL | gcdNOWARN);
+    if (unlikely(!allocator))
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Record os. */
+    allocator->os = Os;
+
+    /* Set operations. */
+    allocator->ops = Operations;
+
+    *Allocator = allocator;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION (3,6,0) \
+    || (!defined (ARCH_HAS_SG_CHAIN) && !defined (CONFIG_ARCH_HAS_SG_CHAIN))
+int
+alloc_sg_list_from_pages(
+    struct scatterlist **sgl,
+    struct page **pages,
+    unsigned int  n_pages,
+    unsigned long offset,
+    unsigned long size,
+    unsigned int  *nents
+    );
+#endif
+
+/*
+    How to implement customer allocator
+
+    Build in customer alloctor
+
+        It is recommanded that customer allocator is implmented in independent
+        source file(s) which is specified by CUSOMTER_ALLOCATOR_OBJS in Kbuld.
+
+    Register gcsALLOCATOR
+
+        For each customer specified allocator, a desciption entry must be added
+        to allocatorArray defined in gc_hal_kernel_allocator_array.h.
+
+        An entry in allocatorArray is a gcsALLOCATOR_DESC structure which describes
+        name and constructor of a gckALLOCATOR object.
+
+
+    Implement gcsALLOCATOR_DESC.init()
+
+        In gcsALLOCATOR_DESC.init(), gckALLOCATOR_Construct should be called
+        to create a gckALLOCATOR object, customer specified private data can
+        be put in gcsALLOCATOR.privateData.
+
+
+    Implement gcsALLOCATOR_OPERATIONS
+
+        When call gckALLOCATOR_Construct to create a gckALLOCATOR object, a
+        gcsALLOCATOR_OPERATIONS structure must be provided whose all members
+        implemented.
+
+*/
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.c
@@ -0,0 +1,1306 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include <gc_hal_kernel_debug.h>
+
+/******************************************************************************\
+******************************** Debug Variables *******************************
+\******************************************************************************/
+
+static gceSTATUS _lastError  = gcvSTATUS_OK;
+static gctUINT32 _debugLevel = gcvLEVEL_ERROR;
+/*
+_debugZones config value
+Please Reference define in gc_hal_base.h
+*/
+static gctUINT32 _debugZones = gcdZONE_NONE;
+
+/******************************************************************************\
+********************************* Debug Switches *******************************
+\******************************************************************************/
+
+/*
+    gcdTHREAD_BUFFERS
+
+    When greater then one, will accumulate messages from the specified number
+    of threads in separate output buffers.
+*/
+#define gcdTHREAD_BUFFERS   1
+
+/*
+    gcdSHOW_LINE_NUMBER
+
+    When enabledm each print statement will be preceeded with the current
+    line number.
+*/
+#define gcdSHOW_LINE_NUMBER 0
+
+/*
+    gcdSHOW_PROCESS_ID
+
+    When enabledm each print statement will be preceeded with the current
+    process ID.
+*/
+#define gcdSHOW_PROCESS_ID  0
+
+/*
+    gcdSHOW_THREAD_ID
+
+    When enabledm each print statement will be preceeded with the current
+    thread ID.
+*/
+#define gcdSHOW_THREAD_ID   0
+
+/*
+    gcdSHOW_TIME
+
+    When enabled each print statement will be preceeded with the current
+    high-resolution time.
+*/
+#define gcdSHOW_TIME        0
+
+
+/******************************************************************************\
+****************************** Miscellaneous Macros ****************************
+\******************************************************************************/
+
+#if gcdSHOW_TIME || gcdSHOW_LINE_NUMBER || gcdSHOW_PROCESS_ID || gcdSHOW_THREAD_ID
+#  define gcdHAVEPREFIX     1
+#else
+#  define gcdHAVEPREFIX     0
+#endif
+
+/******************************************************************************\
+****************************** Private Structures ******************************
+\******************************************************************************/
+
+typedef struct _gcsBUFFERED_OUTPUT * gcsBUFFERED_OUTPUT_PTR;
+typedef struct _gcsBUFFERED_OUTPUT
+{
+#if gcdTHREAD_BUFFERS > 1
+    gctUINT32               threadID;
+#endif
+
+#if gcdSHOW_LINE_NUMBER
+    gctUINT                 lineNumber;
+#endif
+
+    gctINT                  indent;
+
+    gcsBUFFERED_OUTPUT_PTR  prev;
+    gcsBUFFERED_OUTPUT_PTR  next;
+}
+gcsBUFFERED_OUTPUT;
+
+static gcsBUFFERED_OUTPUT     _outputBuffer[gcdTHREAD_BUFFERS];
+static gcsBUFFERED_OUTPUT_PTR _outputBufferHead = gcvNULL;
+static gcsBUFFERED_OUTPUT_PTR _outputBufferTail = gcvNULL;
+
+/******************************************************************************\
+******************************* Printing Functions *****************************
+\******************************************************************************/
+
+#if gcdHAVEPREFIX
+
+#if gcdSHOW_TIME
+static gcmINLINE gctUINT64
+_GetTime(
+    void
+    )
+{
+    gctUINT64 time;
+    gckOS_GetProfileTick(&time);
+    return time;
+}
+#    define gcdPREFIX_LEADER        1
+#    define gcdTIMEFORMAT           "%18lld"
+#    define gcdTIMEVALUE            ,_GetTime()
+#  else
+#    define gcdTIMEFORMAT
+#    define gcdTIMEVALUE
+#  endif
+
+#if gcdSHOW_LINE_NUMBER
+#ifndef gcdPREFIX_LEADER
+#      define gcdPREFIX_LEADER      1
+#      define gcdNUMFORMAT          "%8u"
+#    else
+#      define gcdNUMFORMAT          ", %8u"
+#    endif
+#    define gcdNUMVALUE             ,OutputBuffer->lineNumber
+#  else
+#    define gcdNUMFORMAT
+#    define gcdNUMVALUE
+#  endif
+
+#if gcdSHOW_PROCESS_ID
+#ifndef gcdPREFIX_LEADER
+#      define gcdPREFIX_LEADER      1
+#      define gcdPIDFORMAT          "pid=%5u"
+#    else
+#      define gcdPIDFORMAT          ", pid=%5u"
+#    endif
+#    define gcdPIDVALUE             ,gcmkGETPROCESSID()
+#  else
+#    define gcdPIDFORMAT
+#    define gcdPIDVALUE
+#  endif
+
+#if gcdSHOW_THREAD_ID
+#ifndef gcdPREFIX_LEADER
+#      define gcdPREFIX_LEADER      1
+#      define gcdTIDFORMAT          "tid=%5u"
+#    else
+#      define gcdTIDFORMAT          ", tid=%5u"
+#    endif
+#    define gcdTIDVALUE             ,gcmkGETTHREADID()
+#  else
+#    define gcdTIDFORMAT
+#    define gcdTIDVALUE
+#  endif
+
+static gctUINT
+_PrintPrefix(
+    IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+    IN char Buffer[],
+    IN gctUINT Size
+    )
+{
+    gctINT len;
+
+    /* Format the string. */
+    len = gcmkSPRINTF(Buffer,
+                      Size,
+                      "[" gcdTIMEFORMAT gcdNUMFORMAT gcdPIDFORMAT gcdTIDFORMAT "] "
+                      gcdTIMEVALUE gcdNUMVALUE gcdPIDVALUE gcdTIDVALUE);
+
+    if (len > 0)
+    {
+        Buffer[len] = '\0';
+        return (gctUINT)len;
+    }
+
+    return 0;
+}
+#endif
+
+static int
+_AppendIndent(
+    IN gctINT Indent,
+    IN char * Buffer,
+    IN int BufferSize
+    )
+{
+    gctINT i;
+
+    gctINT len    = 0;
+    gctINT indent = Indent % 40;
+
+    for (i = 0; i < indent; i += 1)
+    {
+        Buffer[len++] = ' ';
+    }
+
+    if (indent != Indent)
+    {
+        len += gcmkSPRINTF(
+            Buffer + len, BufferSize - len, " <%d> ", Indent
+            );
+
+        Buffer[len] = '\0';
+    }
+
+    return len;
+}
+
+static gctUINT
+_PrintString(
+    IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+    IN gctINT Indent,
+    IN gctCONST_STRING Message,
+    IN gctPOINTER Data,
+    IN char Buffer[],
+    IN gctUINT Size
+    )
+{
+    gctINT len;
+
+    /* Append the indent string. */
+    len = _AppendIndent(Indent, Buffer, Size);
+
+    /* Format the string. */
+    len += gcmkVSPRINTF(Buffer + len, Size - len, Message, Data);
+    Buffer[len] = '\0';
+
+    /* Add end-of-line if missing. */
+    if (Buffer[len - 1] != '\n')
+    {
+        Buffer[len++] = '\n';
+        Buffer[len] = '\0';
+    }
+
+    return (gctUINT)len;
+}
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+
+static gcmINLINE void
+_InitBuffers(
+    void
+    )
+{
+    int i;
+
+    if (_outputBufferHead == gcvNULL)
+    {
+        for (i = 0; i < gcdTHREAD_BUFFERS; i += 1)
+        {
+            if (_outputBufferTail == gcvNULL)
+            {
+                _outputBufferHead = &_outputBuffer[i];
+            }
+            else
+            {
+                _outputBufferTail->next = &_outputBuffer[i];
+            }
+
+#if gcdTHREAD_BUFFERS > 1
+            _outputBuffer[i].threadID = ~0U;
+#endif
+
+            _outputBuffer[i].prev = _outputBufferTail;
+            _outputBuffer[i].next =  gcvNULL;
+
+            _outputBufferTail = &_outputBuffer[i];
+        }
+    }
+}
+
+static gcmINLINE gcsBUFFERED_OUTPUT_PTR
+_GetOutputBuffer(
+    void
+    )
+{
+    gcsBUFFERED_OUTPUT_PTR outputBuffer;
+
+#if gcdTHREAD_BUFFERS > 1
+    /* Get the current thread ID. */
+    gctUINT32 ThreadID = gcmkGETTHREADID();
+
+    /* Locate the output buffer for the thread. */
+    outputBuffer = _outputBufferHead;
+
+    while (outputBuffer != gcvNULL)
+    {
+        if (outputBuffer->threadID == ThreadID)
+        {
+            break;
+        }
+
+        outputBuffer = outputBuffer->next;
+    }
+
+    /* No matching buffer found? */
+    if (outputBuffer == gcvNULL)
+    {
+        /* Get the tail for the buffer. */
+        outputBuffer = _outputBufferTail;
+
+        /* Move it to the head. */
+        _outputBufferTail       = _outputBufferTail->prev;
+        _outputBufferTail->next = gcvNULL;
+
+        outputBuffer->prev = gcvNULL;
+        outputBuffer->next = _outputBufferHead;
+
+        _outputBufferHead->prev = outputBuffer;
+        _outputBufferHead       = outputBuffer;
+
+        /* Reset the buffer. */
+        outputBuffer->threadID   = ThreadID;
+#if gcdSHOW_LINE_NUMBER
+        outputBuffer->lineNumber = 0;
+#  endif
+    }
+#else
+    outputBuffer = _outputBufferHead;
+#endif
+
+    return outputBuffer;
+}
+
+static void
+_Print(
+    IN gctCONST_STRING Message,
+    IN gctARGUMENTS * Arguments
+    )
+{
+    gcsBUFFERED_OUTPUT_PTR outputBuffer;
+    char buffer[256];
+    char *ptr = buffer;
+    gctINT len = 0;
+    static gcmkDECLARE_MUTEX(printMutex);
+
+    gcmkMUTEX_LOCK(printMutex);
+
+    /* Initialize output buffer list. */
+    _InitBuffers();
+
+    /* Locate the proper output buffer. */
+    outputBuffer = _GetOutputBuffer();
+
+    /* Print prefix. */
+#if gcdHAVEPREFIX
+#if gcdSHOW_LINE_NUMBER
+    /* Update the line number. */
+    outputBuffer->lineNumber += 1;
+#  endif
+
+    /* Print the prefix. */
+    len = _PrintPrefix(outputBuffer, buffer, gcmSIZEOF(buffer));
+    ptr += len;
+#endif
+
+    /* Form the indent string. */
+    if (Message[0] == '-' && Message[1] == '-')
+    {
+        outputBuffer->indent -= 2;
+    }
+
+    /* Print the message. */
+    len += _PrintString(
+        outputBuffer, outputBuffer->indent,
+        Message, ((gctPOINTER) Arguments),
+        ptr, gcmSIZEOF(buffer) - outputBuffer->indent - len
+        );
+
+    gcmkOUTPUT_STRING(buffer);
+
+    /* Check increasing indent. */
+    if (Message[0] == '+' && Message[1] == '+')
+    {
+        outputBuffer->indent += 2;
+    }
+
+    gcmkMUTEX_UNLOCK(printMutex);
+}
+
+
+/******************************************************************************\
+********************************* Debug Macros *********************************
+\******************************************************************************/
+
+#ifdef __QNXNTO__
+
+extern volatile unsigned g_nQnxInIsrs;
+
+#define gcmDEBUGPRINT(Message) \
+{ \
+    if (atomic_add_value(&g_nQnxInIsrs, 1) == 0) \
+    { \
+        gctARGUMENTS __arguments__; \
+        gcmkARGUMENTS_START(__arguments__, Message); \
+        _Print(Message, &__arguments__); \
+        gcmkARGUMENTS_END(__arguments__); \
+    } \
+    atomic_sub(&g_nQnxInIsrs, 1); \
+}
+
+#elif defined(__VXWORKS__)
+#define gcmDEBUGPRINT(Message) \
+{ \
+    printf(Message); \
+}
+
+#else
+
+#define gcmDEBUGPRINT(Message) \
+{ \
+    gctARGUMENTS __arguments__; \
+    gcmkARGUMENTS_START(__arguments__, Message); \
+    _Print(Message, &__arguments__); \
+    gcmkARGUMENTS_END(__arguments__); \
+}
+
+#endif
+
+/******************************************************************************\
+********************************** Debug Code **********************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckOS_Print
+**
+**  Send a message to the debugger.
+**
+**  INPUT:
+**
+**      gctCONST_STRING Message
+**          Pointer to message.
+**
+**      ...
+**          Optional arguments.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_Print(
+    IN gctCONST_STRING Message,
+    ...
+    )
+{
+    gcmDEBUGPRINT(Message);
+}
+
+/*******************************************************************************
+**
+**  gckOS_DebugTrace
+**
+**  Send a leveled message to the debugger.
+**
+**  INPUT:
+**
+**      gctUINT32 Level
+**          Debug level of message.
+**
+**      gctCONST_STRING Message
+**          Pointer to message.
+**
+**      ...
+**          Optional arguments.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_DebugTrace(
+    IN gctUINT32 Level,
+    IN gctCONST_STRING Message,
+    ...
+    )
+{
+    if (Level > _debugLevel)
+    {
+        return;
+    }
+
+    gcmDEBUGPRINT(Message);
+}
+
+/*******************************************************************************
+**
+**  gckOS_DebugTraceZone
+**
+**  Send a leveled and zoned message to the debugger.
+**
+**  INPUT:
+**
+**      gctUINT32 Level
+**          Debug level for message.
+**
+**      gctUINT32 Zone
+**          Debug zone for message.
+**
+**      gctCONST_STRING Message
+**          Pointer to message.
+**
+**      ...
+**          Optional arguments.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_DebugTraceZone(
+    IN gctUINT32 Level,
+    IN gctUINT32 Zone,
+    IN gctCONST_STRING Message,
+    ...
+    )
+{
+    if ((Level > _debugLevel) || !(Zone & _debugZones))
+    {
+        return;
+    }
+
+    gcmDEBUGPRINT(Message);
+}
+
+/*******************************************************************************
+**
+**  gckOS_DebugBreak
+**
+**  Break into the debugger.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+void
+gckOS_DebugBreak(
+    void
+    )
+{
+    gckOS_DebugTrace(gcvLEVEL_ERROR, "%s(%d)", __FUNCTION__, __LINE__);
+}
+
+/*******************************************************************************
+**
+**  gckOS_DebugFatal
+**
+**  Send a message to the debugger and break into the debugger.
+**
+**  INPUT:
+**
+**      gctCONST_STRING Message
+**          Pointer to message.
+**
+**      ...
+**          Optional arguments.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+void
+gckOS_DebugFatal(
+    IN gctCONST_STRING Message,
+    ...
+    )
+{
+    gcmkPRINT_VERSION();
+    gcmDEBUGPRINT(Message);
+
+    /* Break into the debugger. */
+    gckOS_DebugBreak();
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetDebugLevel
+**
+**  Set the debug level.
+**
+**  INPUT:
+**
+**      gctUINT32 Level
+**          New debug level.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_SetDebugLevel(
+    IN gctUINT32 Level
+    )
+{
+    _debugLevel = Level;
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetDebugZone
+**
+**  Set the debug zone.
+**
+**  INPUT:
+**
+**      gctUINT32 Zone
+**          New debug zone.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+void
+gckOS_SetDebugZone(
+    IN gctUINT32 Zone
+    )
+{
+    _debugZones = Zone;
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetDebugLevelZone
+**
+**  Set the debug level and zone.
+**
+**  INPUT:
+**
+**      gctUINT32 Level
+**          New debug level.
+**
+**      gctUINT32 Zone
+**          New debug zone.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_SetDebugLevelZone(
+    IN gctUINT32 Level,
+    IN gctUINT32 Zone
+    )
+{
+    _debugLevel = Level;
+    _debugZones = Zone;
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetDebugZones
+**
+**  Enable or disable debug zones.
+**
+**  INPUT:
+**
+**      gctUINT32 Zones
+**          Debug zones to enable or disable.
+**
+**      gctBOOL Enable
+**          Set to gcvTRUE to enable the zones (or the Zones with the current
+**          zones) or gcvFALSE to disable the specified Zones.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_SetDebugZones(
+    IN gctUINT32 Zones,
+    IN gctBOOL Enable
+    )
+{
+    if (Enable)
+    {
+        /* Enable the zones. */
+        _debugZones |= Zones;
+    }
+    else
+    {
+        /* Disable the zones. */
+        _debugZones &= ~Zones;
+    }
+}
+
+/*******************************************************************************
+**
+**  gckOS_Verify
+**
+**  Called to verify the result of a function call.
+**
+**  INPUT:
+**
+**      gceSTATUS Status
+**          Function call result.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+
+void
+gckOS_Verify(
+    IN gceSTATUS status
+    )
+{
+    _lastError = status;
+}
+
+gctCONST_STRING
+gckOS_DebugStatus2Name(
+    gceSTATUS status
+    )
+{
+    switch (status)
+    {
+    case gcvSTATUS_OK:
+        return "gcvSTATUS_OK";
+    case gcvSTATUS_TRUE:
+        return "gcvSTATUS_TRUE";
+    case gcvSTATUS_NO_MORE_DATA:
+        return "gcvSTATUS_NO_MORE_DATA";
+    case gcvSTATUS_CACHED:
+        return "gcvSTATUS_CACHED";
+    case gcvSTATUS_MIPMAP_TOO_LARGE:
+        return "gcvSTATUS_MIPMAP_TOO_LARGE";
+    case gcvSTATUS_NAME_NOT_FOUND:
+        return "gcvSTATUS_NAME_NOT_FOUND";
+    case gcvSTATUS_NOT_OUR_INTERRUPT:
+        return "gcvSTATUS_NOT_OUR_INTERRUPT";
+    case gcvSTATUS_MISMATCH:
+        return "gcvSTATUS_MISMATCH";
+    case gcvSTATUS_MIPMAP_TOO_SMALL:
+        return "gcvSTATUS_MIPMAP_TOO_SMALL";
+    case gcvSTATUS_LARGER:
+        return "gcvSTATUS_LARGER";
+    case gcvSTATUS_SMALLER:
+        return "gcvSTATUS_SMALLER";
+    case gcvSTATUS_CHIP_NOT_READY:
+        return "gcvSTATUS_CHIP_NOT_READY";
+    case gcvSTATUS_NEED_CONVERSION:
+        return "gcvSTATUS_NEED_CONVERSION";
+    case gcvSTATUS_SKIP:
+        return "gcvSTATUS_SKIP";
+    case gcvSTATUS_DATA_TOO_LARGE:
+        return "gcvSTATUS_DATA_TOO_LARGE";
+    case gcvSTATUS_INVALID_CONFIG:
+        return "gcvSTATUS_INVALID_CONFIG";
+    case gcvSTATUS_CHANGED:
+        return "gcvSTATUS_CHANGED";
+    case gcvSTATUS_NOT_SUPPORT_DITHER:
+        return "gcvSTATUS_NOT_SUPPORT_DITHER";
+
+    case gcvSTATUS_INVALID_ARGUMENT:
+        return "gcvSTATUS_INVALID_ARGUMENT";
+    case gcvSTATUS_INVALID_OBJECT:
+        return "gcvSTATUS_INVALID_OBJECT";
+    case gcvSTATUS_OUT_OF_MEMORY:
+        return "gcvSTATUS_OUT_OF_MEMORY";
+    case gcvSTATUS_MEMORY_LOCKED:
+        return "gcvSTATUS_MEMORY_LOCKED";
+    case gcvSTATUS_MEMORY_UNLOCKED:
+        return "gcvSTATUS_MEMORY_UNLOCKED";
+    case gcvSTATUS_HEAP_CORRUPTED:
+        return "gcvSTATUS_HEAP_CORRUPTED";
+    case gcvSTATUS_GENERIC_IO:
+        return "gcvSTATUS_GENERIC_IO";
+    case gcvSTATUS_INVALID_ADDRESS:
+        return "gcvSTATUS_INVALID_ADDRESS";
+    case gcvSTATUS_CONTEXT_LOSSED:
+        return "gcvSTATUS_CONTEXT_LOSSED";
+    case gcvSTATUS_TOO_COMPLEX:
+        return "gcvSTATUS_TOO_COMPLEX";
+    case gcvSTATUS_BUFFER_TOO_SMALL:
+        return "gcvSTATUS_BUFFER_TOO_SMALL";
+    case gcvSTATUS_INTERFACE_ERROR:
+        return "gcvSTATUS_INTERFACE_ERROR";
+    case gcvSTATUS_NOT_SUPPORTED:
+        return "gcvSTATUS_NOT_SUPPORTED";
+    case gcvSTATUS_MORE_DATA:
+        return "gcvSTATUS_MORE_DATA";
+    case gcvSTATUS_TIMEOUT:
+        return "gcvSTATUS_TIMEOUT";
+    case gcvSTATUS_OUT_OF_RESOURCES:
+        return "gcvSTATUS_OUT_OF_RESOURCES";
+    case gcvSTATUS_INVALID_DATA:
+        return "gcvSTATUS_INVALID_DATA";
+    case gcvSTATUS_INVALID_MIPMAP:
+        return "gcvSTATUS_INVALID_MIPMAP";
+    case gcvSTATUS_NOT_FOUND:
+        return "gcvSTATUS_NOT_FOUND";
+    case gcvSTATUS_NOT_ALIGNED:
+        return "gcvSTATUS_NOT_ALIGNED";
+    case gcvSTATUS_INVALID_REQUEST:
+        return "gcvSTATUS_INVALID_REQUEST";
+    case gcvSTATUS_GPU_NOT_RESPONDING:
+        return "gcvSTATUS_GPU_NOT_RESPONDING";
+    case gcvSTATUS_TIMER_OVERFLOW:
+        return "gcvSTATUS_TIMER_OVERFLOW";
+    case gcvSTATUS_VERSION_MISMATCH:
+        return "gcvSTATUS_VERSION_MISMATCH";
+    case gcvSTATUS_LOCKED:
+        return "gcvSTATUS_LOCKED";
+    case gcvSTATUS_INTERRUPTED:
+        return "gcvSTATUS_INTERRUPTED";
+    case gcvSTATUS_DEVICE:
+        return "gcvSTATUS_DEVICE";
+    case gcvSTATUS_NOT_MULTI_PIPE_ALIGNED:
+        return "gcvSTATUS_NOT_MULTI_PIPE_ALIGNED";
+
+    /* Linker errors. */
+    case gcvSTATUS_GLOBAL_TYPE_MISMATCH:
+        return "gcvSTATUS_GLOBAL_TYPE_MISMATCH";
+    case gcvSTATUS_TOO_MANY_ATTRIBUTES:
+        return "gcvSTATUS_TOO_MANY_ATTRIBUTES";
+    case gcvSTATUS_TOO_MANY_UNIFORMS:
+        return "gcvSTATUS_TOO_MANY_UNIFORMS";
+    case gcvSTATUS_TOO_MANY_VARYINGS:
+        return "gcvSTATUS_TOO_MANY_VARYINGS";
+    case gcvSTATUS_UNDECLARED_VARYING:
+        return "gcvSTATUS_UNDECLARED_VARYING";
+    case gcvSTATUS_VARYING_TYPE_MISMATCH:
+        return "gcvSTATUS_VARYING_TYPE_MISMATCH";
+    case gcvSTATUS_MISSING_MAIN:
+        return "gcvSTATUS_MISSING_MAIN";
+    case gcvSTATUS_NAME_MISMATCH:
+        return "gcvSTATUS_NAME_MISMATCH";
+    case gcvSTATUS_INVALID_INDEX:
+        return "gcvSTATUS_INVALID_INDEX";
+    case gcvSTATUS_UNIFORM_MISMATCH:
+        return "gcvSTATUS_UNIFORM_MISMATCH";
+    case gcvSTATUS_UNSAT_LIB_SYMBOL:
+        return "gcvSTATUS_UNSAT_LIB_SYMBOL";
+    case gcvSTATUS_TOO_MANY_SHADERS:
+        return "gcvSTATUS_TOO_MANY_SHADERS";
+    case gcvSTATUS_LINK_INVALID_SHADERS:
+        return "gcvSTATUS_LINK_INVALID_SHADERS";
+    case gcvSTATUS_CS_NO_WORKGROUP_SIZE:
+        return "gcvSTATUS_CS_NO_WORKGROUP_SIZE";
+    case gcvSTATUS_LINK_LIB_ERROR:
+        return "gcvSTATUS_LINK_LIB_ERROR";
+    case gcvSTATUS_SHADER_VERSION_MISMATCH:
+        return "gcvSTATUS_SHADER_VERSION_MISMATCH";
+    case gcvSTATUS_TOO_MANY_INSTRUCTION:
+        return "gcvSTATUS_TOO_MANY_INSTRUCTION";
+    case gcvSTATUS_SSBO_MISMATCH:
+        return "gcvSTATUS_SSBO_MISMATCH";
+    case gcvSTATUS_TOO_MANY_OUTPUT:
+        return "gcvSTATUS_TOO_MANY_OUTPUT";
+    case gcvSTATUS_TOO_MANY_INPUT:
+        return "gcvSTATUS_TOO_MANY_INPUT";
+    case gcvSTATUS_NOT_SUPPORT_CL:
+        return "gcvSTATUS_NOT_SUPPORT_CL";
+    case gcvSTATUS_NOT_SUPPORT_INTEGER:
+        return "gcvSTATUS_NOT_SUPPORT_INTEGER";
+    case gcvSTATUS_UNIFORM_TYPE_MISMATCH:
+        return "gcvSTATUS_UNIFORM_TYPE_MISMATCH";
+    case gcvSTATUS_MISSING_PRIMITIVE_TYPE:
+        return "gcvSTATUS_MISSING_PRIMITIVE_TYPE";
+    case gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT:
+        return "gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT";
+    case gcvSTATUS_NON_INVOCATION_ID_AS_INDEX:
+        return "gcvSTATUS_NON_INVOCATION_ID_AS_INDEX";
+    case gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH:
+        return "gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH";
+    case gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH:
+        return "gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH";
+
+    /* Compiler errors. */
+    case gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR:
+        return "gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR";
+    case gcvSTATUS_COMPILER_FE_PARSER_ERROR:
+        return "gcvSTATUS_COMPILER_FE_PARSER_ERROR";
+    default:
+        return "nil";
+    }
+}
+
+/*******************************************************************************
+***** Kernel Dump **************************************************************
+*******************************************************************************/
+
+/*
+ * TODO: Dump to file is only valid in linux currently.
+ */
+#ifndef gcmkDUMP_STRING
+#  define gcmkDUMP_STRING(os, s)    gcmkOUTPUT_STRING((s))
+#endif
+
+static gcmkDECLARE_MUTEX(_dumpMutex);
+static gctCHAR _dumpStorage[512];
+
+/*******************************************************************************
+**
+**  gckOS_Dump
+**
+**  Formated print string to dump pool.
+**
+**  INPUT:
+**
+**      gctCONST_STRING Format
+**          String format.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+void
+gckOS_Dump(
+    IN gckOS Os,
+    IN gctCONST_STRING Format,
+    ...
+    )
+{
+    char buffer[256];
+    gctINT len;
+    gctARGUMENTS args;
+
+    gcmkARGUMENTS_START(args, Format);
+    len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer) - 2, Format, &args);
+    gcmkARGUMENTS_END(args);
+
+    if (len > 0)
+    {
+        if (buffer[len - 1] != '\n')
+        {
+            buffer[len] = '\n';
+            buffer[len + 1] = '\0';
+        }
+
+        gcmkMUTEX_LOCK(_dumpMutex);
+        gcmkDUMP_STRING(Os, buffer);
+        gcmkMUTEX_UNLOCK(_dumpMutex);
+    }
+}
+
+static void
+_DumpUserString(
+    IN gckOS Os,
+    IN gctPOINTER UserStr,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctSIZE_T offset = 0;
+    gctSIZE_T length = 0;
+    gctBOOL needCopy = gcvTRUE;
+    const gctSIZE_T maxLength = gcmSIZEOF(_dumpStorage) - 1;
+
+    gcmkVERIFY_OK(gckOS_QueryNeedCopy(Os, 0, &needCopy));
+
+    gcmkMUTEX_LOCK(_dumpMutex);
+
+    while (offset < Size)
+    {
+        length = maxLength < (Size - offset) ? maxLength : (Size - offset);
+
+        /* Copy or map from user. */
+        if (needCopy)
+        {
+            gcmkONERROR(gckOS_CopyFromUserData(
+                Os,
+                _dumpStorage,
+                UserStr,
+                length
+                ));
+        }
+        else
+        {
+            gctPOINTER ptr = gcvNULL;
+
+            gcmkONERROR(gckOS_MapUserPointer(
+                Os,
+                UserStr,
+                length,
+                (gctPOINTER *)&ptr
+                ));
+
+            gckOS_MemCopy(_dumpStorage, ptr, length);
+            gckOS_UnmapUserPointer(Os, UserStr, length, ptr);
+        }
+
+        _dumpStorage[length] = '\0';
+        gcmkDUMP_STRING(Os, _dumpStorage);
+
+        UserStr = (gctUINT8_PTR)UserStr + length;
+        offset += length;
+    }
+
+    gcmkDUMP_STRING(Os, "\n");
+
+OnError:
+    gcmkMUTEX_UNLOCK(_dumpMutex);
+}
+
+static void
+_DumpDataBuffer(
+    IN gckOS Os,
+    IN gceDUMP_BUFFER_TYPE Type,
+    IN gctPOINTER Data,
+    IN gctUINT64 Address,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctSIZE_T offset = 0;
+    gctSIZE_T length = 0;
+    gctBOOL needCopy = gcvTRUE;
+    gctCONST_STRING dumpTag;
+    char buffer[256];
+    const gctSIZE_T maxLength = gcmSIZEOF(_dumpStorage);
+
+    switch (Type)
+    {
+    case gcvDUMP_BUFFER_VERIFY:
+        dumpTag = "verify";
+        break;
+    case gcvDUMP_BUFFER_PHYSICAL_MEMORY:
+        dumpTag = "physical";
+        break;
+    default:
+        dumpTag = "memory";
+        break;
+    }
+
+    if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST)
+    {
+        gcmkVERIFY_OK(gckOS_QueryNeedCopy(Os, 0, &needCopy));
+    }
+
+    gcmkMUTEX_LOCK(_dumpMutex);
+
+    /* Form and print the opening string. */
+    if (Type == gcvDUMP_BUFFER_PHYSICAL_MEMORY)
+    {
+        gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                    "@[%s 0x%010llX 0x%08X\n",
+                    dumpTag, (unsigned long long)Address, (gctUINT32)Size);
+    }
+    else
+    {
+        gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                    "@[%s 0x%08X 0x%08X\n",
+                    dumpTag, (gctUINT32)Address, (gctUINT32)Size);
+    }
+
+    gcmkDUMP_STRING(Os, buffer);
+
+
+    while (offset < Size)
+    {
+        gctPOINTER data = gcvNULL;
+        gctUINT32_PTR ptr;
+        gctUINT8_PTR bytePtr;
+        gctSIZE_T count, tailByteCount;
+
+        length = maxLength < (Size - offset) ? maxLength : (Size - offset);
+        count = length / 4;
+        tailByteCount = length % 4;
+
+        ptr = (gctUINT32_PTR)Data;
+
+        if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST)
+        {
+            /* Copy or map from user. */
+            if (needCopy)
+            {
+                gcmkONERROR(gckOS_CopyFromUserData(
+                    Os,
+                    _dumpStorage,
+                    Data,
+                    length
+                    ));
+
+                ptr = (gctUINT32_PTR)_dumpStorage;
+            }
+            else
+            {
+                gcmkONERROR(gckOS_MapUserPointer(
+                    Os,
+                    Data,
+                    length,
+                    (gctPOINTER *)&data
+                    ));
+
+                ptr = (gctUINT32_PTR)data;
+            }
+        }
+
+        while (count >= 4)
+        {
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        "  0x%08X 0x%08X 0x%08X 0x%08X\n",
+                        ptr[0], ptr[1], ptr[2], ptr[3]);
+
+            ptr   += 4;
+            count -= 4;
+
+            gcmkDUMP_STRING(Os, buffer);
+        }
+
+        switch (count)
+        {
+        case 3:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        "  0x%08X 0x%08X 0x%08X",
+                        ptr[0], ptr[1], ptr[2]);
+            break;
+        case 2:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        "  0x%08X 0x%08X",
+                        ptr[0], ptr[1]);
+            break;
+        case 1:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1, "  0x%08X", ptr[0]);
+            break;
+        }
+
+        if (count > 0)
+        {
+            gcmkDUMP_STRING(Os, buffer);
+        }
+
+        bytePtr = (gctUINT8_PTR)(ptr + count);
+
+        if (!count && tailByteCount)
+        {
+            /* There is an extra space for the new line. */
+            gcmkDUMP_STRING(Os, " ");
+        }
+
+        switch (tailByteCount)
+        {
+        case 3:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        " 0x00%02X%02X%02X",
+                        bytePtr[2], bytePtr[1], bytePtr[0]);
+            break;
+        case 2:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        " 0x0000%02X%02X",
+                        bytePtr[1], bytePtr[0]);
+            break;
+        case 1:
+            gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
+                        " 0x000000%02X", bytePtr[0]);
+            break;
+        }
+
+        if (tailByteCount)
+        {
+            gcmkDUMP_STRING(Os, buffer);
+        }
+
+        if (count || tailByteCount)
+        {
+            gcmkDUMP_STRING(Os, "\n");
+        }
+
+        if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST && !needCopy)
+        {
+            gckOS_UnmapUserPointer(Os, Data, length, data);
+        }
+        /* advance to next batch. */
+        Data    = (gctUINT8_PTR)Data + length;
+        offset += length;
+    }
+
+OnError:
+    gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1, "] -- %s\n", dumpTag);
+    gcmkDUMP_STRING(Os, buffer);
+
+    gcmkMUTEX_UNLOCK(_dumpMutex);
+}
+
+/*******************************************************************************
+**
+**  gckOS_DumpBuffer
+**
+**  Print the contents of the specified buffer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gceDUMP_BUFFER_TYPE Type
+**          Buffer type.
+**
+**      gctPOINTER Buffer
+**          Pointer to the buffer to print.
+**
+**      gctUINT64 Address
+**          Address.
+**
+**      gctUINT Size
+**          Size of the buffer.
+**
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+void
+gckOS_DumpBuffer(
+    IN gckOS Os,
+    IN gceDUMP_BUFFER_TYPE Type,
+    IN gctPOINTER Buffer,
+    IN gctUINT64 Address,
+    IN gctSIZE_T Size
+    )
+{
+    if (!Buffer)
+    {
+        return;
+    }
+
+    /* memory dump below. */
+    if (Type >= gcvDUMP_BUFFER_TYPE_COUNT)
+    {
+        gcmkPRINT("#[ERROR: invalid buffer type]\n");
+        return;
+    }
+
+    if (Type == gcvDUMP_BUFFER_USER_STRING)
+    {
+        _DumpUserString(Os, Buffer, Size);
+    }
+    else
+    {
+        _DumpDataBuffer(Os, Type, Buffer, Address, Size);
+    }
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_debug_h_
+#define __gc_hal_kernel_debug_h_
+
+#include <gc_hal_kernel_linux.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <stdarg.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
+#include <linux/nmi.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** OS-dependent Macros *****************************
+\******************************************************************************/
+
+typedef va_list gctARGUMENTS;
+
+#define gcmkARGUMENTS_START(Arguments, Pointer) \
+    va_start(Arguments, Pointer)
+
+#define gcmkARGUMENTS_END(Arguments) \
+    va_end(Arguments)
+
+#define gcmkARGUMENTS_ARG(Arguments, Type) \
+    va_arg(Arguments, Type)
+
+#define gcmkDECLARE_MUTEX(__mutex__) \
+    DEFINE_MUTEX(__mutex__)
+
+#define gcmkMUTEX_LOCK(__mutex__) \
+    mutex_lock(&__mutex__)
+
+#define gcmkMUTEX_UNLOCK(__mutex__) \
+    mutex_unlock(&__mutex__)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#   define gcmkGETPROCESSID() \
+        task_tgid_vnr(current)
+#else
+#   define gcmkGETPROCESSID() \
+        current->tgid
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#   define gcmkGETTHREADID() \
+        task_pid_vnr(current)
+#else
+#   define gcmkGETTHREADID() \
+        current->pid
+#endif
+
+#define gcmkOUTPUT_STRING(String) \
+    printk("%s", String); \
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
+#define gcmkDUMP_STRING(Os, String) \
+    do \
+    { \
+        mutex_lock(&Os->dumpFilpMutex); \
+        if (Os->dumpTarget == 0) \
+        { \
+            printk("%s", String); \
+        } \
+        else if (Os->dumpFilp && Os->dumpTarget == 1) \
+        { \
+            kernel_write(Os->dumpFilp, String, strlen(String), &Os->dumpFilp->f_pos); \
+        } \
+        mutex_unlock(&Os->dumpFilpMutex); \
+    } \
+    while (0)
+#else
+#define gcmkDUMP_STRING(Os, String) \
+    do \
+    { \
+        mutex_lock(&Os->dumpFilpMutex); \
+        if (Os->dumpTarget == 0) \
+        { \
+            printk("%s", String); \
+        } \
+        else if (Os->dumpFilp && Os->dumpTarget == 1) \
+        { \
+            mm_segment_t oldFs; \
+            oldFs = get_fs(); \
+            set_fs(KERNEL_DS); \
+            vfs_write(Os->dumpFilp, String, strlen(String), &Os->dumpFilp->f_pos); \
+            set_fs(oldFs); \
+        } \
+        mutex_unlock(&Os->dumpFilpMutex); \
+    } \
+    while (0)
+#endif
+
+#define gcmkSPRINTF(Destination, Size, ...) \
+    snprintf(Destination, Size, __VA_ARGS__)
+
+#define gcmkVSPRINTF(Destination, Size, Message, Arguments) \
+    vsnprintf(Destination, Size, Message, *((va_list*)Arguments))
+
+#define gcmkSTRCATSAFE(Destination, Size, String) \
+    strncat(Destination, String, (Size) - 1)
+
+#define gcmkMEMCPY(Destination, Source, Size) \
+    memcpy(Destination, Source, Size)
+
+#define gcmkSTRLEN(String) \
+    strlen(String)
+
+/* If not zero, forces data alignment in the variable argument list
+   by its individual size. */
+#define gcdALIGNBYSIZE      1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_debug_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c
@@ -0,0 +1,229 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <linux/completion.h>
+#include <linux/seq_file.h>
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_debug.h"
+
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+static int gc_debugfs_open(struct inode *inode, struct file *file)
+{
+    gcsINFO_NODE *node = inode->i_private;
+
+    return single_open(file, node->info->show, node);
+}
+
+static ssize_t
+gc_debugfs_write(
+    struct file *file,
+    const char __user *buf,
+    size_t count,
+    loff_t *pos
+    )
+{
+    struct seq_file *s = file->private_data;
+    gcsINFO_NODE *node = s->private;
+    gcsINFO *info = node->info;
+
+    if (info->write)
+    {
+        info->write(buf, count, node);
+    }
+
+    return count;
+}
+
+static const struct file_operations gc_debugfs_operations = {
+    .owner = THIS_MODULE,
+    .open = gc_debugfs_open,
+    .write = gc_debugfs_write,
+    .read = seq_read,
+    .llseek = seq_lseek,
+    .release = single_release,
+};
+
+gceSTATUS
+gckDEBUGFS_DIR_Init(
+    IN gckDEBUGFS_DIR Dir,
+    IN struct dentry *root,
+    IN gctCONST_STRING Name
+    )
+{
+    Dir->root = debugfs_create_dir(Name, root);
+
+    if (!Dir->root)
+    {
+        return gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    INIT_LIST_HEAD(&Dir->nodeList);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEBUGFS_DIR_CreateFiles(
+    IN gckDEBUGFS_DIR Dir,
+    IN gcsINFO * List,
+    IN int count,
+    IN gctPOINTER Data
+    )
+{
+    int i;
+    gcsINFO_NODE * node;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Dir=%p List=%p count=%d Data=%p", Dir, List, count, Data);
+
+    for (i = 0; i < count; i++)
+    {
+        umode_t mode = 0;
+
+        /* Create a node. */
+        node = (gcsINFO_NODE *)kzalloc(sizeof(gcsINFO_NODE), GFP_KERNEL);
+
+        node->info   = &List[i];
+        node->device = Data;
+
+        mode |= List[i].show  ? S_IRUGO : 0;
+        mode |= List[i].write ? S_IWUSR : 0;
+
+        node->entry = debugfs_create_file(
+            List[i].name, mode, Dir->root, node, &gc_debugfs_operations);
+
+        if (!node->entry)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        list_add(&(node->head), &(Dir->nodeList));
+    }
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(Dir, List, count));
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckDEBUGFS_DIR_RemoveFiles(
+    IN gckDEBUGFS_DIR Dir,
+    IN gcsINFO * List,
+    IN int count
+    )
+{
+    int i;
+    gcsINFO_NODE * node;
+    gcsINFO_NODE * temp;
+
+    gcmkHEADER_ARG("Dir=%p List=%p count=%d", Dir, List, count);
+
+    for (i = 0; i < count; i++)
+    {
+        list_for_each_entry_safe(node, temp, &Dir->nodeList, head)
+        {
+            if (node->info == &List[i])
+            {
+                debugfs_remove(node->entry);
+                list_del(&node->head);
+                kfree(node);
+            }
+        }
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+void
+gckDEBUGFS_DIR_Deinit(
+    IN gckDEBUGFS_DIR Dir
+    )
+{
+    if (Dir->root != NULL)
+    {
+        debugfs_remove(Dir->root);
+        Dir->root = NULL;
+    }
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include <stdarg.h>
+
+#ifndef __gc_hal_kernel_debugfs_h_
+#define __gc_hal_kernel_debugfs_h_
+
+ #define MAX_LINE_SIZE 768           /* Max bytes for a line of debug info */
+
+typedef struct _gcsDEBUGFS_DIR *gckDEBUGFS_DIR;
+typedef struct _gcsDEBUGFS_DIR
+{
+    struct dentry *     root;
+    struct list_head    nodeList;
+}
+gcsDEBUGFS_DIR;
+
+typedef struct _gcsINFO
+{
+    const char *        name;
+    int                 (*show)(struct seq_file*, void*);
+    int                 (*write)(const char __user *buf, size_t count, void*);
+}
+gcsINFO;
+
+typedef struct _gcsINFO_NODE
+{
+    gcsINFO *          info;
+    gctPOINTER         device;
+    struct dentry *    entry;
+    struct list_head   head;
+}
+gcsINFO_NODE;
+
+gceSTATUS
+gckDEBUGFS_DIR_Init(
+    IN gckDEBUGFS_DIR Dir,
+    IN struct dentry *root,
+    IN gctCONST_STRING Name
+    );
+
+gceSTATUS
+gckDEBUGFS_DIR_CreateFiles(
+    IN gckDEBUGFS_DIR Dir,
+    IN gcsINFO * List,
+    IN int count,
+    IN gctPOINTER Data
+    );
+
+gceSTATUS
+gckDEBUGFS_DIR_RemoveFiles(
+    IN gckDEBUGFS_DIR Dir,
+    IN gcsINFO * List,
+    IN int count
+    );
+
+void
+gckDEBUGFS_DIR_Deinit(
+    IN gckDEBUGFS_DIR Dir
+    );
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
@@ -0,0 +1,2784 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+
+#define _GC_OBJ_ZONE    gcvZONE_DEVICE
+
+#define DEBUG_FILE          "galcore_trace"
+#define PARENT_FILE         "gpu"
+
+#define gcdDEBUG_FS_WARN    "Experimental debug entry, may be removed in future release, do NOT rely on it!\n"
+
+static gckGALDEVICE galDevice;
+
+extern gcTA globalTA[16];
+
+/******************************************************************************\
+******************************** Debugfs Support *******************************
+\******************************************************************************/
+
+/******************************************************************************\
+***************************** DEBUG SHOW FUNCTIONS *****************************
+\******************************************************************************/
+
+int gc_info_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    int i = 0;
+    gceCHIPMODEL chipModel = 0;
+    gctUINT32 chipRevision = 0;
+    gctUINT32 productID = 0;
+    gctUINT32 ecoID = 0;
+
+    if (!device)
+        return -ENXIO;
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (device->kernels[i])
+        {
+            if (i == gcvCORE_VG)
+            {
+#if gcdENABLE_VG
+                chipModel = device->kernels[i]->vg->hardware->chipModel;
+                chipRevision = device->kernels[i]->vg->hardware->chipRevision;
+#endif
+            }
+            else
+            {
+                chipModel = device->kernels[i]->hardware->identity.chipModel;
+                chipRevision = device->kernels[i]->hardware->identity.chipRevision;
+                productID = device->kernels[i]->hardware->identity.productID;
+                ecoID = device->kernels[i]->hardware->identity.ecoID;
+            }
+
+            seq_printf(m, "gpu      : %d\n", i);
+            seq_printf(m, "model    : %4x\n", chipModel);
+            seq_printf(m, "revision : %4x\n", chipRevision);
+            seq_printf(m, "product  : %4x\n", productID);
+            seq_printf(m, "eco      : %4x\n", ecoID);
+            seq_printf(m, "\n");
+        }
+    }
+
+    return 0;
+}
+
+int gc_clients_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+
+    gckKERNEL kernel = _GetValidKernel(device);
+
+    gcsDATABASE_PTR database;
+    gctINT i, pid;
+    char name[24];
+
+    if (!kernel)
+        return -ENXIO;
+
+    seq_printf(m, "%-8s%s\n", "PID", "NAME");
+    seq_printf(m, "------------------------\n");
+
+    /* Acquire the database mutex. */
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+    /* Walk the databases. */
+    for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+    {
+        for (database = kernel->db->db[i];
+             database != gcvNULL;
+             database = database->next)
+        {
+            pid = database->processID;
+
+            gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+            seq_printf(m, "%-8d%s\n", pid, name);
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+    /* Success. */
+    return 0;
+}
+
+int gc_meminfo_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gckKERNEL kernel = _GetValidKernel(device);
+    gckVIDMEM memory;
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gctUINT32 i;
+
+    gctUINT32 free = 0, used = 0, total = 0, minFree = 0, maxUsed = 0;
+
+    gcsDATABASE_COUNTERS virtualCounter = {0, 0, 0};
+    gcsDATABASE_COUNTERS nonPagedCounter = {0, 0, 0};
+
+    if (!kernel)
+        return -ENXIO;
+
+    status = gckKERNEL_GetVideoMemoryPool(kernel, gcvPOOL_SYSTEM, &memory);
+
+    if (gcmIS_SUCCESS(status))
+    {
+        gcmkVERIFY_OK(
+            gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
+
+        free    = memory->freeBytes;
+        minFree = memory->minFreeBytes;
+        used    = memory->bytes - memory->freeBytes;
+        maxUsed = memory->bytes - memory->minFreeBytes;
+        total   = memory->bytes;
+
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
+    }
+
+    seq_printf(m, "VIDEO MEMORY:\n");
+    seq_printf(m, "  POOL SYSTEM:\n");
+    seq_printf(m, "    Free :    %10u B\n", free);
+    seq_printf(m, "    Used :    %10u B\n", used);
+    seq_printf(m, "    MinFree : %10u B\n", minFree);
+    seq_printf(m, "    MaxUsed : %10u B\n", maxUsed);
+    seq_printf(m, "    Total :   %10u B\n", total);
+
+    /* Acquire the database mutex. */
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+    /* Walk the databases. */
+    for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+    {
+        for (database = kernel->db->db[i];
+             database != gcvNULL;
+             database = database->next)
+        {
+            gcsDATABASE_COUNTERS * counter;
+            counter = &database->vidMemPool[gcvPOOL_VIRTUAL];
+            virtualCounter.bytes += counter->bytes;
+            virtualCounter.maxBytes += counter->maxBytes;
+
+            counter = &database->nonPaged;
+            nonPagedCounter.bytes += counter->bytes;
+            nonPagedCounter.bytes += counter->maxBytes;
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+    seq_printf(m, "  POOL VIRTUAL:\n");
+    seq_printf(m, "    Used :    %10llu B\n", virtualCounter.bytes);
+    seq_printf(m, "    MaxUsed : %10llu B\n", virtualCounter.bytes);
+
+    return 0;
+}
+
+static const char * vidmemTypeStr[gcvVIDMEM_TYPE_COUNT] =
+{
+    "Generic",
+    "Index",
+    "Vertex",
+    "Texture",
+    "RenderTarget",
+    "Depth",
+    "Bitmap",
+    "TileStatus",
+    "Image",
+    "Mask",
+    "Scissor",
+    "HZ",
+    "ICache",
+    "TxDesc",
+    "Fence",
+    "TFBHeader",
+    "Command",
+};
+
+static const char * poolStr[gcvPOOL_NUMBER_OF_POOLS] =
+{
+    "Unknown",
+    "Default",
+    "Local",
+    "Internal",
+    "External",
+    "Unified",
+    "System",
+    "Sram",
+    "Virtual",
+    "User",
+    "Insram",
+    "Exsram",
+};
+
+static void
+_ShowDummyRecord(
+    IN struct seq_file *File,
+    IN gcsDATABASE_PTR Database
+    )
+{
+}
+
+static void
+_ShowVideoMemoryRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+    gctUINT32 handle;
+    gckVIDMEM_NODE nodeObject;
+    gctPHYS_ADDR_T physical;
+    gctINT32 refCount = 0;
+    gctINT32 lockCount = 0;
+    gceSTATUS status;
+
+    seq_printf(m, "Video Memory Node:\n");
+    seq_printf(m, "  handle         nodeObject       size         type     pool     physical  ref lock\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_VIDEO_MEMORY)
+            {
+                continue;
+            }
+
+            handle = gcmPTR2INT32(record->data);
+
+            status = gckVIDMEM_HANDLE_Lookup2(
+                record->kernel,
+                Database,
+                handle,
+                &nodeObject
+                );
+
+            if (gcmIS_ERROR(status))
+            {
+                seq_printf(m, "%6u Invalid Node\n", handle);
+                continue;
+            }
+
+            gcmkONERROR(gckVIDMEM_NODE_GetPhysical(record->kernel, nodeObject, 0, &physical));
+            gcmkONERROR(gckVIDMEM_NODE_GetReference(record->kernel, nodeObject, &refCount));
+            gcmkONERROR(gckVIDMEM_NODE_GetLockCount(record->kernel, nodeObject, &lockCount));
+
+            seq_printf(m, "%#8x %#18lx %10lu %12s %8s %#12llx %4d %4d\n",
+                handle,
+                (unsigned long)nodeObject,
+                (unsigned long)record->bytes,
+                vidmemTypeStr[nodeObject->type],
+                poolStr[nodeObject->pool],
+                physical,
+                refCount,
+                lockCount
+                );
+        }
+    }
+
+OnError:
+    return;
+}
+
+static void
+_ShowCommandBufferRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    return;
+}
+
+static void
+_ShowNonPagedRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+
+    seq_printf(m, "NonPaged Memory:\n");
+    seq_printf(m, "  name              vaddr       size\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_NON_PAGED)
+            {
+                continue;
+            }
+
+            seq_printf(m, "%6u %#18lx %10lu\n",
+                gcmPTR2INT32(record->physical),
+                (unsigned long)record->data,
+                (unsigned long)record->bytes
+                );
+        }
+    }
+}
+
+static void
+_ShowContiguousRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    return;
+}
+
+static void
+_ShowSignalRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+
+    seq_printf(m, "User signal:\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_SIGNAL)
+            {
+                continue;
+            }
+
+            seq_printf(m, "%#10x\n", gcmPTR2INT32(record->data));
+        }
+    }
+}
+
+static void
+_ShowLockRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+    gceSTATUS status;
+    gctUINT32 handle;
+    gckVIDMEM_NODE nodeObject;
+
+    seq_printf(m, "Video Memory Lock:\n");
+    seq_printf(m, "  handle         nodeObject              vaddr\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_VIDEO_MEMORY_LOCKED)
+            {
+                continue;
+            }
+
+            handle = gcmPTR2INT32(record->data);
+
+            status = gckVIDMEM_HANDLE_Lookup2(
+                record->kernel,
+                Database,
+                handle,
+                &nodeObject
+                );
+
+            if (gcmIS_ERROR(status))
+            {
+                nodeObject = gcvNULL;
+            }
+
+            seq_printf(m, "%#8x %#18lx %#18lx\n",
+                handle,
+                (unsigned long)nodeObject,
+                (unsigned long)record->physical
+                );
+        }
+    }
+}
+
+static void
+_ShowContextRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+
+    seq_printf(m, "Context:\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_CONTEXT)
+            {
+                continue;
+            }
+
+            seq_printf(m, "%6u\n", gcmPTR2INT32(record->data));
+        }
+    }
+}
+
+static void
+_ShowMapMemoryRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+
+    seq_printf(m, "Map Memory:\n");
+    seq_printf(m, "  name              vaddr       size\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_MAP_MEMORY)
+            {
+                continue;
+            }
+
+            seq_printf(m, "%#6lx %#18lx %10lu\n",
+                (unsigned long)record->physical,
+                (unsigned long)record->data,
+                (unsigned long)record->bytes
+                );
+        }
+    }
+}
+
+static void
+_ShowMapUserMemoryRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    return;
+}
+
+static void
+_ShowShbufRecord(
+    IN struct seq_file *m,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i;
+
+    seq_printf(m, "ShBuf:\n");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR r = Database->list[i];
+
+        while (r != NULL)
+        {
+            gcsDATABASE_RECORD_PTR record = r;
+            r = r->next;
+
+            if (record->type != gcvDB_SHBUF)
+            {
+                continue;
+            }
+
+            seq_printf(m, "%#8x\n", gcmPTR2INT32(record->data));
+        }
+    }
+}
+
+static void
+_ShowCounters(
+    struct seq_file *File,
+    gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i = 0;
+
+    static const char * otherCounterNames[] = {
+        "AllocNonPaged",
+        "AllocContiguous",
+        "MapUserMemory",
+        "MapMemory",
+    };
+
+    gcsDATABASE_COUNTERS * otherCounters[] = {
+        &Database->nonPaged,
+        &Database->contiguous,
+        &Database->mapUserMemory,
+        &Database->mapMemory,
+    };
+
+    seq_printf(File, "%-16s %16s %16s %16s\n", "", "Current", "Maximum", "Total");
+
+    /* Print surface type counters. */
+    seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+               "All-Types",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvVIDMEM_TYPE_COUNT; i++)
+    {
+        seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+                   vidmemTypeStr[i],
+                   Database->vidMemType[i].bytes,
+                   Database->vidMemType[i].maxBytes,
+                   Database->vidMemType[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print surface pool counters. */
+    seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+               "All-Pools",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+    {
+        seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+                   poolStr[i],
+                   Database->vidMemPool[i].bytes,
+                   Database->vidMemPool[i].maxBytes,
+                   Database->vidMemPool[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print other counters. */
+    for (i = 0; i < gcmCOUNTOF(otherCounterNames); i++)
+    {
+        seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+                   otherCounterNames[i],
+                   otherCounters[i]->bytes,
+                   otherCounters[i]->maxBytes,
+                   otherCounters[i]->totalBytes);
+    }
+    seq_puts(File, "\n");
+}
+
+static int
+_ShowRecord(
+    IN struct seq_file *File,
+    IN gcsDATABASE_PTR Database,
+    IN gcsDATABASE_RECORD_PTR Record
+    )
+{
+    gctUINT32 handle;
+    gckVIDMEM_NODE nodeObject;
+    gctPHYS_ADDR_T physical;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    static const char * recordTypes[gcvDB_NUM_TYPES] = {
+        "Unknown",
+        "VideoMemory",
+        "CommandBuffer",
+        "NonPaged",
+        "Contiguous",
+        "Signal",
+        "VidMemLock",
+        "Context",
+        "Idel",
+        "MapMemory",
+        "MapUserMemory",
+        "ShBuf",
+    };
+
+    handle = gcmPTR2INT32(Record->data);
+
+    if (Record->type == gcvDB_VIDEO_MEMORY || Record->type == gcvDB_VIDEO_MEMORY_LOCKED)
+    {
+        status = gckVIDMEM_HANDLE_Lookup2(
+            Record->kernel,
+            Database,
+            handle,
+            &nodeObject
+        );
+
+        if (gcmIS_ERROR(status))
+        {
+            seq_printf(File, "%6u Invalid Node\n", handle);
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+        gcmkONERROR(gckVIDMEM_NODE_GetPhysical(Record->kernel, nodeObject, 0, &physical));
+    }
+    else
+    {
+        physical = (gctUINT64)(gctUINTPTR_T)Record->physical;
+    }
+
+    seq_printf(File, "%-14s %3d %16x %16zx %16zu\n",
+        recordTypes[Record->type],
+        Record->kernel->core,
+        gcmPTR2INT32(Record->data),
+        (size_t) physical,
+        Record->bytes
+        );
+
+OnError:
+    return status;
+}
+
+static void
+_ShowDataBaseOldFormat(
+    IN struct seq_file *File,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctINT pid;
+    gctUINT i;
+    char name[24];
+
+    /* Process ID and name */
+    pid = Database->processID;
+    gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+    seq_printf(File, "--------------------------------------------------------------------------------\n");
+    seq_printf(File, "Process: %-8d %s\n", pid, name);
+
+    seq_printf(File, "Records:\n");
+
+    seq_printf(File, "%14s %3s %16s %16s %16s\n",
+               "Type", "GPU", "Data/Node", "Physical/Node", "Bytes");
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR record = Database->list[i];
+
+        while (record != NULL)
+        {
+            _ShowRecord(File, Database, record);
+            record = record->next;
+        }
+    }
+
+    seq_printf(File, "Counters:\n");
+
+    _ShowCounters(File, Database);
+}
+
+static void
+_ShowDatabase(
+    IN struct seq_file *File,
+    IN gcsDATABASE_PTR Database
+    )
+{
+    gctINT pid;
+    gctUINT i;
+    char name[24];
+    gctBOOL hasType[gcvDB_NUM_TYPES] = {0,};
+    void (* showFuncs[])(struct seq_file *, gcsDATABASE_PTR) =
+    {
+        _ShowDummyRecord,
+        _ShowVideoMemoryRecord,
+        _ShowCommandBufferRecord,
+        _ShowNonPagedRecord,
+        _ShowContiguousRecord,
+        _ShowSignalRecord,
+        _ShowLockRecord,
+        _ShowContextRecord,
+        _ShowDummyRecord,
+        _ShowMapMemoryRecord,
+        _ShowMapUserMemoryRecord,
+        _ShowShbufRecord,
+    };
+
+    gcmSTATIC_ASSERT(gcmCOUNTOF(showFuncs) == gcvDB_NUM_TYPES,
+                     "DB type mismatch");
+
+    /* Process ID and name */
+    pid = Database->processID;
+    gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+    seq_printf(File, "--------------------------------------------------------------------------------\n");
+    seq_printf(File, "Process: %-8d %s\n", pid, name);
+
+    for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+    {
+        gcsDATABASE_RECORD_PTR record = Database->list[i];
+
+        while (record != NULL)
+        {
+            hasType[record->type] = gcvTRUE;
+            record = record->next;
+        }
+    }
+
+    for (i = 0; i < gcvDB_NUM_TYPES; i++)
+    {
+        if (hasType[i])
+        {
+            showFuncs[i](File, Database);
+        }
+    }
+}
+
+static int
+gc_db_show_old(struct seq_file *m, void *data)
+{
+    gcsDATABASE_PTR database;
+    gctINT i;
+    static gctUINT64 idleTime = 0;
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gckKERNEL kernel = _GetValidKernel(device);
+
+    if (!kernel)
+        return -ENXIO;
+
+    /* Acquire the database mutex. */
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+    if (kernel->db->idleTime)
+    {
+        /* Record idle time if DB upated. */
+        idleTime = kernel->db->idleTime;
+        kernel->db->idleTime = 0;
+    }
+
+    /* Idle time since last call */
+    seq_printf(m, "GPU Idle: %llu ns\n",  idleTime);
+
+    /* Walk the databases. */
+    for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+    {
+        for (database = kernel->db->db[i];
+             database != gcvNULL;
+             database = database->next)
+        {
+            _ShowDataBaseOldFormat(m, database);
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+    return 0 ;
+}
+
+static int
+gc_db_show(struct seq_file *m, void *data)
+{
+    gcsDATABASE_PTR database;
+    gctINT i;
+    static gctUINT64 idleTime = 0;
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gckKERNEL kernel = _GetValidKernel(device);
+
+    if (!kernel)
+        return -ENXIO;
+
+    /* Acquire the database mutex. */
+    gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+    if (kernel->db->idleTime)
+    {
+        /* Record idle time if DB upated. */
+        idleTime = kernel->db->idleTime;
+        kernel->db->idleTime = 0;
+    }
+
+    /* Idle time since last call */
+    seq_printf(m, "GPU Idle: %llu ns\n",  idleTime);
+
+    /* Walk the databases. */
+    for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+    {
+        for (database = kernel->db->db[i];
+             database != gcvNULL;
+             database = database->next)
+        {
+            _ShowDatabase(m, database);
+        }
+    }
+
+    /* Release the database mutex. */
+    gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+    return 0 ;
+}
+
+static int
+gc_version_show(struct seq_file *m, void *data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gcsPLATFORM * platform = gcvNULL;
+
+    if (!device)
+        return -ENXIO;
+
+    platform = device->platform;
+    if (!platform)
+        return -ENXIO;
+
+    seq_printf(m, "%s built at %s\n",  gcvVERSION_STRING, HOST);
+
+    if (platform->name)
+    {
+        seq_printf(m, "Platform path: %s\n", platform->name);
+    }
+    else
+    {
+        seq_printf(m, "Code path: %s\n", __FILE__);
+    }
+
+    return 0 ;
+}
+
+static void print_ull(char dest[32], unsigned long long u)
+{
+    unsigned t[7];
+    int i;
+
+    if (u < 1000)
+    {
+        sprintf(dest, "%27llu", u);
+        return;
+    }
+
+    for (i = 0; i < 7 && u; i++)
+    {
+        t[i] = do_div(u, 1000);
+    }
+
+    dest += sprintf(dest, "%*s", (7 - i) * 4, "");
+    dest += sprintf(dest, "%3u", t[--i]);
+
+    for (i--; i >= 0; i--)
+    {
+        dest += sprintf(dest, ",%03u", t[i]);
+    }
+}
+
+/*******************************************************************************
+**
+** Show PM state timer.
+**
+** Entry is called as 'idle' for compatible reason, it shows more information
+** than idle actually.
+**
+**  Start: Start time of this counting period.
+**  End: End time of this counting peroid.
+**  On: Time GPU stays in gcvPOWER_0N.
+**  Off: Time GPU stays in gcvPOWER_0FF.
+**  Idle: Time GPU stays in gcvPOWER_IDLE.
+**  Suspend: Time GPU stays in gcvPOWER_SUSPEND.
+*/
+static int
+gc_idle_show(struct seq_file *m, void *data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gckKERNEL kernel = _GetValidKernel(device);
+    char str[32];
+
+    gctUINT64 on;
+    gctUINT64 off;
+    gctUINT64 idle;
+    gctUINT64 suspend;
+
+    if (!kernel)
+        return -ENXIO;
+
+    gckHARDWARE_QueryStateTimer(kernel->hardware, &on, &off, &idle, &suspend);
+
+    /* Idle time since last call */
+    print_ull(str, on);
+    seq_printf(m, "On:      %s ns\n",  str);
+    print_ull(str, off);
+    seq_printf(m, "Off:     %s ns\n",  str);
+    print_ull(str, idle);
+    seq_printf(m, "Idle:    %s ns\n",  str);
+    print_ull(str, suspend);
+    seq_printf(m, "Suspend: %s ns\n",  str);
+
+    return 0 ;
+}
+
+extern void
+_DumpState(
+    IN gckKERNEL Kernel
+    );
+
+/*******************************************************************************
+**
+** Show PM state timer.
+**
+** Entry is called as 'idle' for compatible reason, it shows more information
+** than idle actually.
+**
+**  Start: Start time of this counting period.
+**  End: End time of this counting peroid.
+**  On: Time GPU stays in gcvPOWER_0N.
+**  Off: Time GPU stays in gcvPOWER_0FF.
+**  Idle: Time GPU stays in gcvPOWER_IDLE.
+**  Suspend: Time GPU stays in gcvPOWER_SUSPEND.
+*/
+static int dumpCore = 0;
+
+static int
+gc_dump_trigger_show(struct seq_file *m, void *data)
+{
+#if gcdENABLE_3D || gcdENABLE_2D
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gckKERNEL kernel = gcvNULL;
+
+    if (dumpCore >= gcvCORE_MAJOR && dumpCore < gcvCORE_COUNT)
+    {
+        kernel = device->kernels[dumpCore];
+    }
+
+    if (!kernel)
+        return -ENXIO;
+
+#endif
+
+    seq_printf(m, gcdDEBUG_FS_WARN);
+
+#if gcdENABLE_3D || gcdENABLE_2D
+    seq_printf(m, "Get dump from /proc/kmsg or /sys/kernel/debug/gc/galcore_trace\n");
+
+    if (kernel && kernel->hardware->options.powerManagement == gcvFALSE)
+    {
+        _DumpState(kernel);
+    }
+#endif
+
+    return 0;
+}
+
+static int dumpProcess = 0;
+
+static void
+_ShowVideoMemoryOldFormat(
+    struct seq_file *File,
+    gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i = 0;
+
+    static const char * otherCounterNames[] = {
+        "AllocNonPaged",
+        "AllocContiguous",
+        "MapUserMemory",
+        "MapMemory",
+    };
+
+    gcsDATABASE_COUNTERS * otherCounters[] = {
+        &Database->nonPaged,
+        &Database->contiguous,
+        &Database->mapUserMemory,
+        &Database->mapMemory,
+    };
+
+    seq_printf(File, "%-16s %16s %16s %16s\n", "", "Current", "Maximum", "Total");
+
+    /* Print surface type counters. */
+    seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+               "All-Types",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvVIDMEM_TYPE_COUNT; i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   vidmemTypeStr[i],
+                   Database->vidMemType[i].bytes,
+                   Database->vidMemType[i].maxBytes,
+                   Database->vidMemType[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print surface pool counters. */
+    seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+               "All-Pools",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   poolStr[i],
+                   Database->vidMemPool[i].bytes,
+                   Database->vidMemPool[i].maxBytes,
+                   Database->vidMemPool[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print other counters. */
+    for (i = 0; i < gcmCOUNTOF(otherCounterNames); i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   otherCounterNames[i],
+                   otherCounters[i]->bytes,
+                   otherCounters[i]->maxBytes,
+                   otherCounters[i]->totalBytes);
+    }
+    seq_puts(File, "\n");
+}
+
+static void
+_ShowVideoMemory(
+    struct seq_file *File,
+    gcsDATABASE_PTR Database
+    )
+{
+    gctUINT i = 0;
+
+    static const char * otherCounterNames[] = {
+        "AllocNonPaged",
+        "MapMemory",
+    };
+
+    gcsDATABASE_COUNTERS * otherCounters[] = {
+        &Database->nonPaged,
+        &Database->mapMemory,
+    };
+
+    seq_printf(File, "%-16s %16s %16s %16s\n", "", "Current", "Maximum", "Total");
+
+    /* Print surface type counters. */
+    seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+               "All-Types",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvVIDMEM_TYPE_COUNT; i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   vidmemTypeStr[i],
+                   Database->vidMemType[i].bytes,
+                   Database->vidMemType[i].maxBytes,
+                   Database->vidMemType[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print surface pool counters. */
+    seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+               "All-Pools",
+               Database->vidMem.bytes,
+               Database->vidMem.maxBytes,
+               Database->vidMem.totalBytes);
+
+    for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   poolStr[i],
+                   Database->vidMemPool[i].bytes,
+                   Database->vidMemPool[i].maxBytes,
+                   Database->vidMemPool[i].totalBytes);
+    }
+    seq_puts(File, "\n");
+
+    /* Print other counters. */
+    for (i = 0; i < gcmCOUNTOF(otherCounterNames); i++)
+    {
+        seq_printf(File, "%-16s %16llu %16llu %16llu\n",
+                   otherCounterNames[i],
+                   otherCounters[i]->bytes,
+                   otherCounters[i]->maxBytes,
+                   otherCounters[i]->totalBytes);
+    }
+    seq_puts(File, "\n");
+}
+
+static int gc_vidmem_show_old(struct seq_file *m, void *unused)
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    char name[64];
+    int i;
+
+    gckKERNEL kernel = _GetValidKernel(device);
+
+    if (!kernel)
+        return -ENXIO;
+
+    if (dumpProcess == 0)
+    {
+        /* Acquire the database mutex. */
+        gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+        for (i = 0; i < gcmCOUNTOF(kernel->db->db); i++)
+        {
+            for (database = kernel->db->db[i];
+                 database != gcvNULL;
+                 database = database->next)
+            {
+                gckOS_GetProcessNameByPid(database->processID, gcmSIZEOF(name), name);
+                seq_printf(m, "VidMem Usage (Process %u: %s):\n", database->processID, name);
+                _ShowVideoMemoryOldFormat(m, database);
+                seq_puts(m, "\n");
+            }
+        }
+
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+    }
+    else
+    {
+        /* Find the database. */
+        status = gckKERNEL_FindDatabase(kernel, dumpProcess, gcvFALSE, &database);
+
+        if (gcmIS_ERROR(status))
+        {
+            seq_printf(m, "ERROR: process %d not found\n", dumpProcess);
+            return 0;
+        }
+
+        gckOS_GetProcessNameByPid(dumpProcess, gcmSIZEOF(name), name);
+        seq_printf(m, "VidMem Usage (Process %d: %s):\n", dumpProcess, name);
+        _ShowVideoMemoryOldFormat(m, database);
+    }
+
+    return 0;
+}
+
+static int gc_vidmem_show(struct seq_file *m, void *unused)
+{
+    gceSTATUS status;
+    gcsDATABASE_PTR database;
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    char name[64];
+    int i;
+
+    gckKERNEL kernel = _GetValidKernel(device);
+
+    if (!kernel)
+        return -ENXIO;
+
+    if (dumpProcess == 0)
+    {
+        /* Acquire the database mutex. */
+        gcmkVERIFY_OK(
+        gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+        for (i = 0; i < gcmCOUNTOF(kernel->db->db); i++)
+        {
+            for (database = kernel->db->db[i];
+                 database != gcvNULL;
+                 database = database->next)
+            {
+                gckOS_GetProcessNameByPid(database->processID, gcmSIZEOF(name), name);
+                seq_printf(m, "VidMem Usage (Process %u: %s):\n", database->processID, name);
+                _ShowVideoMemory(m, database);
+                seq_puts(m, "\n");
+            }
+        }
+
+        /* Release the database mutex. */
+        gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+    }
+    else
+    {
+        /* Find the database. */
+        status = gckKERNEL_FindDatabase(kernel, dumpProcess, gcvFALSE, &database);
+
+        if (gcmIS_ERROR(status))
+        {
+            seq_printf(m, "ERROR: process %d not found\n", dumpProcess);
+            return 0;
+        }
+
+        gckOS_GetProcessNameByPid(dumpProcess, gcmSIZEOF(name), name);
+        seq_printf(m, "VidMem Usage (Process %d: %s):\n", dumpProcess, name);
+        _ShowVideoMemory(m, database);
+    }
+
+    return 0;
+}
+
+static inline int strtoint_from_user(const char __user *s,
+                        size_t count, int *res)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)
+    int ret = kstrtoint_from_user(s, count, 10, res);
+
+    return ret < 0 ? ret : count;
+#else
+    /* sign, base 2 representation, newline, terminator */
+    char buf[1 + sizeof(long) * 8 + 1 + 1];
+
+    size_t len = min(count, sizeof(buf) - 1);
+
+    if (copy_from_user(buf, s, len))
+        return -EFAULT;
+    buf[len] = '\0';
+
+    *res = (int) simple_strtol(buf, NULL, 0);
+
+    return count;
+#endif
+}
+
+static int gc_vidmem_write(const char __user *buf, size_t count, void* data)
+{
+    return strtoint_from_user(buf, count, &dumpProcess);
+}
+
+static int gc_dump_trigger_write(const char __user *buf, size_t count, void* data)
+{
+    return strtoint_from_user(buf, count, &dumpCore);
+}
+
+static int gc_clk_show(struct seq_file* m, void* data)
+{
+    gcsINFO_NODE *node = m->private;
+    gckGALDEVICE device = node->device;
+    gctUINT i;
+    gceSTATUS status;
+
+    if (!device)
+        return -ENXIO;
+
+    for (i = gcvCORE_MAJOR; i < gcvCORE_COUNT; i++)
+    {
+        if (device->kernels[i])
+        {
+            gckHARDWARE hardware = device->kernels[i]->hardware;
+
+            if (i == gcvCORE_VG)
+            {
+                continue;
+            }
+
+            status = gckHARDWARE_QueryFrequency(hardware);
+            if (gcmIS_ERROR(status))
+            {
+                seq_printf(m, "query gpu%d clock fail.\n", i);
+                continue;
+            }
+
+            if (hardware->mcClk)
+            {
+                seq_printf(m, "gpu%d mc clock: %d HZ.\n", i, hardware->mcClk);
+            }
+
+            if (hardware->shClk)
+            {
+                seq_printf(m, "gpu%d sh clock: %d HZ.\n", i, hardware->shClk);
+            }
+        }
+    }
+
+    return 0;
+}
+
+static gctUINT32 clkScale[2] = {0, 0};
+
+static int _set_clk(const char* buf)
+{
+    gckHARDWARE hardware;
+    gckGALDEVICE device = galDevice;
+    gctINT n, j, k;
+    gctBOOL isSpace = gcvFALSE;
+    char data[20];
+
+    memset(data, 0, 20);
+    n = j = k = 0;
+
+    while (gcvTRUE)
+    {
+        if ((buf[k] >= '0') && (buf[k] <= '9'))
+        {
+            if (isSpace)
+            {
+                data[n++] = ' ';
+                isSpace = gcvFALSE;
+            }
+            data[n++] = buf[k];
+        }
+        else if (buf[k] == ' ')
+        {
+            if (n > 0)
+            {
+                isSpace = gcvTRUE;
+            }
+        }
+        else if (buf[k] == '\n')
+        {
+            break;
+        }
+        else
+        {
+            printk("Error: command format must be this: echo \"0 32 32\" > /sys/kernel/debug/gc/clk\n");
+            return 0;
+        }
+
+        k++;
+
+        if (k >= 20)
+        {
+            break;
+        }
+    }
+
+    if (3 == sscanf(data, "%d %d %d", &dumpCore, &clkScale[0], &clkScale[1])) {
+        printk("Change core:%d MC scale:%d SH scale:%d\n",
+                dumpCore, clkScale[0], clkScale[1]);
+    } else {
+        printk("usage: echo \"0 32 32\" > clk\n");
+        return 0;
+    }
+
+    if (device->kernels[dumpCore])
+    {
+        hardware = device->kernels[dumpCore]->hardware;
+
+        gckHARDWARE_SetClock(hardware, dumpCore, clkScale[0], clkScale[1]);
+    }
+    else
+    {
+        printk("Error: invalid core\n");
+    }
+
+    return 0;
+}
+
+static int gc_clk_write(const char __user *buf, size_t count, void* data)
+{
+    _set_clk(buf);
+
+    return count;
+}
+
+static gcsINFO InfoList[] =
+{
+    {"info", gc_info_show},
+    {"clients", gc_clients_show},
+    {"meminfo", gc_meminfo_show},
+    {"idle", gc_idle_show},
+    {"database", gc_db_show_old},
+    {"database64x", gc_db_show},
+    {"version", gc_version_show},
+    {"vidmem", gc_vidmem_show_old, gc_vidmem_write},
+    {"vidmem64x", gc_vidmem_show, gc_vidmem_write},
+    {"dump_trigger", gc_dump_trigger_show, gc_dump_trigger_write},
+    {"clk", gc_clk_show, gc_clk_write},
+};
+
+static gceSTATUS
+_DebugfsInit(
+    IN gckGALDEVICE Device
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckDEBUGFS_DIR dir = &Device->debugfsDir;
+
+    gcmkONERROR(gckDEBUGFS_DIR_Init(dir, gcvNULL, "gc"));
+    gcmkONERROR(gckDEBUGFS_DIR_CreateFiles(dir, InfoList, gcmCOUNTOF(InfoList), Device));
+
+OnError:
+    return status;
+}
+
+static void
+_DebugfsCleanup(
+    IN gckGALDEVICE Device
+    )
+{
+    gckDEBUGFS_DIR dir = &Device->debugfsDir;
+
+    if (Device->debugfsDir.root)
+    {
+        gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(dir, InfoList, gcmCOUNTOF(InfoList)));
+
+        gckDEBUGFS_DIR_Deinit(dir);
+    }
+}
+
+
+/******************************************************************************\
+*************************** Memory Allocation Wrappers *************************
+\******************************************************************************/
+
+static gceSTATUS
+_AllocateMemory(
+    IN gckGALDEVICE Device,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *Logical,
+    OUT gctPHYS_ADDR *Physical,
+    OUT gctUINT64 *PhysAddr
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctPHYS_ADDR_T physAddr;
+
+    gcmkHEADER_ARG("Device=%p Bytes=0x%zx", Device, Bytes);
+
+    gcmkVERIFY_ARGUMENT(Device != NULL);
+    gcmkVERIFY_ARGUMENT(Logical != NULL);
+    gcmkVERIFY_ARGUMENT(Physical != NULL);
+    gcmkVERIFY_ARGUMENT(PhysAddr != NULL);
+
+    gcmkONERROR(gckOS_AllocateNonPagedMemory(
+        Device->os, gcvFALSE, gcvALLOC_FLAG_CONTIGUOUS, &Bytes, Physical, Logical
+        ));
+
+    gcmkONERROR(gckOS_GetPhysicalFromHandle(
+        Device->os, *Physical, 0, &physAddr
+        ));
+
+    *PhysAddr = physAddr;
+
+OnError:
+    gcmkFOOTER_ARG(
+        "*Logical=%p *Physical=%p *PhysAddr=0x%llx",
+        gcmOPT_POINTER(Logical), gcmOPT_POINTER(Physical), gcmOPT_VALUE(PhysAddr)
+        );
+
+    return status;
+}
+
+static gceSTATUS
+_FreeMemory(
+    IN gckGALDEVICE Device,
+    IN gctPOINTER Logical,
+    IN gctPHYS_ADDR Physical
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Device=%p Logical=%p Physical=%p",
+                   Device, Logical, Physical);
+
+    gcmkVERIFY_ARGUMENT(Device != NULL);
+
+    status = gckOS_FreeNonPagedMemory(
+        Device->os, Physical, Logical,
+        ((PLINUX_MDL) Physical)->numPages * PAGE_SIZE
+        );
+
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_SetupContiguousVidMem(
+    IN gckGALDEVICE Device,
+    IN const gcsMODULE_PARAMETERS * Args
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT64 physAddr = ~0ULL;
+    gckGALDEVICE device = Device;
+
+    gcmkHEADER_ARG("Device=%p Args=%p", Device, Args);
+
+    /* set up the contiguous memory */
+    device->contiguousBase = Args->contiguousBase;
+    device->contiguousSize = Args->contiguousSize;
+
+    if (Args->contiguousSize == 0)
+    {
+        gcmkFOOTER_NO();
+        return gcvSTATUS_OK;
+    }
+
+    if (Args->contiguousBase == 0)
+    {
+        while (device->contiguousSize > 0)
+        {
+            /* Allocate contiguous memory. */
+            status = _AllocateMemory(
+                device,
+                device->contiguousSize,
+                &device->contiguousLogical,
+                &device->contiguousPhysical,
+                &physAddr
+                );
+
+            if (gcmIS_SUCCESS(status))
+            {
+                status = gckVIDMEM_Construct(
+                    device->os,
+                    physAddr,
+                    device->contiguousSize,
+                    64,
+                    Args->bankSize,
+                    &device->contiguousVidMem
+                    );
+
+                if (gcmIS_SUCCESS(status))
+                {
+                    gckALLOCATOR allocator = ((PLINUX_MDL)device->contiguousPhysical)->allocator;
+                    device->contiguousVidMem->capability = allocator->capability | gcvALLOC_FLAG_MEMLIMIT;
+                    device->contiguousVidMem->physical = device->contiguousPhysical;
+                    device->contiguousBase = physAddr;
+                    if (device->contiguousBase > 0xFFFFFFFFULL)
+                    {
+                        device->contiguousVidMem->capability &= ~gcvALLOC_FLAG_4GB_ADDR;
+                    }
+                    break;
+                }
+
+                gcmkONERROR(_FreeMemory(
+                    device,
+                    device->contiguousLogical,
+                    device->contiguousPhysical
+                    ));
+
+                device->contiguousLogical  = gcvNULL;
+                device->contiguousPhysical = gcvNULL;
+            }
+
+            if (device->contiguousSize <= (4 << 20))
+            {
+                device->contiguousSize = 0;
+            }
+            else
+            {
+                device->contiguousSize -= (4 << 20);
+            }
+        }
+    }
+    else
+    {
+        /* Create the contiguous memory heap. */
+        status = gckVIDMEM_Construct(
+            device->os,
+            Args->contiguousBase,
+            Args->contiguousSize,
+            64,
+            Args->bankSize,
+            &device->contiguousVidMem
+            );
+
+        if (gcmIS_ERROR(status))
+        {
+            /* Error, disable contiguous memory pool. */
+            device->contiguousVidMem = gcvNULL;
+            device->contiguousSize   = 0;
+        }
+        else
+        {
+            gckALLOCATOR allocator;
+            gctBOOL contiguousRequested = Args->contiguousRequested;
+
+#if gcdCAPTURE_ONLY_MODE
+            contiguousRequested = gcvTRUE;
+#endif
+
+            gcmkONERROR(gckOS_RequestReservedMemory(
+                device->os, Args->contiguousBase, Args->contiguousSize,
+                "galcore contiguous memory",
+                contiguousRequested,
+                &device->contiguousPhysical
+                ));
+
+            allocator = ((PLINUX_MDL)device->contiguousPhysical)->allocator;
+
+            device->contiguousVidMem->capability = allocator->capability | gcvALLOC_FLAG_MEMLIMIT;
+            device->contiguousVidMem->physical = device->contiguousPhysical;
+            device->requestedContiguousBase = Args->contiguousBase;
+            device->requestedContiguousSize = Args->contiguousSize;
+
+            device->contiguousPhysName = 0;
+            device->contiguousSize = Args->contiguousSize;
+        }
+    }
+
+    if (Args->showArgs)
+    {
+        gcmkPRINT("Galcore Info: ContiguousBase=0x%llx ContiguousSize=0x%zx\n", device->contiguousBase, device->contiguousSize);
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_SetupExternalSRAMVidMem(
+    IN gckGALDEVICE Device
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE device = Device;
+    gctINT32 i, j = 0;
+
+    gcmkHEADER_ARG("Device=%p", Device);
+
+    /* Setup external SRAM memory region. */
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        if (!device->extSRAMSizes[i])
+        {
+            /* Keep this path for internal test, read from feature database. */
+            device->extSRAMSizes[i] = device->device->extSRAMSizes[i];
+        }
+
+        if (device->extSRAMSizes[i] > 0)
+        {
+            /* create the external SRAM memory heap */
+            status = gckVIDMEM_Construct(
+                device->os,
+                device->extSRAMBases[i],
+                device->extSRAMSizes[i],
+                64,
+                0,
+                &device->extSRAMVidMem[i]
+                );
+
+            if (gcmIS_ERROR(status))
+            {
+                /* Error, disable external SRAM heap. */
+                device->extSRAMSizes[i] = 0;
+            }
+            else
+            {
+                char sRAMName[40];
+                snprintf(sRAMName, gcmSIZEOF(sRAMName) - 1, "Galcore external sram%d", i);
+
+#if gcdCAPTURE_ONLY_MODE
+                device->args.sRAMRequested = gcvTRUE;
+#endif
+                /* Map external SRAM memory. */
+                gcmkONERROR(gckOS_RequestReservedMemory(
+                        device->os,
+                        device->extSRAMBases[i], device->extSRAMSizes[i],
+                        sRAMName,
+                        device->args.sRAMRequested,
+                        &device->extSRAMPhysical[i]
+                        ));
+
+                device->extSRAMVidMem[i]->physical = device->extSRAMPhysical[i];
+                device->device->extSRAMPhysical[i] = device->extSRAMPhysical[i];
+
+                for (j = 0; j < gcdMAX_GPU_COUNT; j++)
+                {
+                    if (device->irqLines[j] != -1 && device->kernels[j])
+                    {
+                        device->kernels[j]->hardware->options.extSRAMGPUPhysNames[i] = gckKERNEL_AllocateNameFromPointer(device->kernels[j], device->extSRAMPhysical[i]);
+                    }
+                }
+            }
+        }
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/******************************************************************************\
+******************************* Interrupt Handler ******************************
+\******************************************************************************/
+static irqreturn_t isrRoutine(int irq, void *ctxt)
+{
+    gceSTATUS status;
+    gckGALDEVICE device;
+    gceCORE core = (gceCORE)gcmPTR2INT32(ctxt) - 1;
+
+    device = galDevice;
+
+    /* Call kernel interrupt notification. */
+    status = gckHARDWARE_Interrupt(device->kernels[core]->hardware);
+
+    if (gcmIS_SUCCESS(status))
+    {
+        up(&device->semas[core]);
+        return IRQ_HANDLED;
+    }
+
+    return IRQ_NONE;
+}
+
+static irqreturn_t isrRoutineVG(int irq, void *ctxt)
+{
+#if gcdENABLE_VG
+    gceSTATUS status;
+    gckGALDEVICE device;
+
+    device = galDevice;
+
+    /* Serve the interrupt. */
+    status = gckVGINTERRUPT_Enque(device->kernels[gcvCORE_VG]->vg->interrupt);
+
+    /* Determine the return value. */
+    return (status == gcvSTATUS_NOT_OUR_INTERRUPT)
+        ? IRQ_RETVAL(0)
+        : IRQ_RETVAL(1);
+#else
+    return IRQ_NONE;
+#endif
+}
+
+static const char *isrNames[] =
+{
+    "galcore:0",
+    "galcore:3d-1",
+    "galcore:3d-2",
+    "galcore:3d-3",
+    "galcore:3d-4",
+    "galcore:3d-5",
+    "galcore:3d-6",
+    "galcore:3d-7",
+    "galcore:2d",
+    "galcore:vg",
+#if gcdDEC_ENABLE_AHB
+    "galcore:dec"
+#endif
+};
+
+static gceSTATUS
+_SetupIsr(
+    IN gceCORE Core
+    )
+{
+    gctINT ret = 0;
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE Device = galDevice;
+    irq_handler_t handler;
+
+    gcmkHEADER_ARG("Device=%p Core=%d", Device, Core);
+
+    gcmkVERIFY_ARGUMENT(Device != NULL);
+
+    if (Device->irqLines[Core] < 0)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    gcmSTATIC_ASSERT(gcvCORE_COUNT == gcmCOUNTOF(isrNames),
+                     "isrNames array does not match core types");
+
+    handler = (Core == gcvCORE_VG) ? isrRoutineVG : isrRoutine;
+
+    /*
+     * Hook up the isr based on the irq line.
+     * For shared irq, device-id can not be 0, but CORE_MAJOR value is.
+     * Add by 1 here and subtract by 1 in isr to fix the issue.
+     */
+    ret = request_irq(
+        Device->irqLines[Core], handler, gcdIRQF_FLAG,
+        isrNames[Core], (void *)(uintptr_t)(Core + 1)
+        );
+
+    if (ret != 0)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): Could not register irq line %d (error=%d)\n",
+            __FUNCTION__, __LINE__,
+            Device->irqLines[Core], ret
+            );
+
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    /* Mark ISR as initialized. */
+    Device->isrInitializeds[Core] = gcvTRUE;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+static gceSTATUS
+_ReleaseIsr(
+    IN gceCORE Core
+    )
+{
+    gckGALDEVICE Device = galDevice;
+
+    gcmkHEADER_ARG("Device=%p Core=%d", Device, Core);
+
+    gcmkVERIFY_ARGUMENT(Device != NULL);
+
+    /* release the irq */
+    if (Device->isrInitializeds[Core])
+    {
+        free_irq(Device->irqLines[Core], (void *)(uintptr_t)(Core + 1));
+        Device->isrInitializeds[Core] = gcvFALSE;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+static int threadRoutine(void *ctxt)
+{
+    gckGALDEVICE device = galDevice;
+    gceCORE core = (gceCORE) gcmPTR2INT32(ctxt);
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
+                   "Starting isr Thread with extension=%p",
+                   device);
+
+
+    for (;;)
+    {
+        int down;
+
+        down = down_interruptible(&device->semas[core]);
+        if (down && down != -EINTR)
+        {
+            return down;
+        }
+
+        if (unlikely(device->killThread))
+        {
+            /* The daemon exits. */
+            while (!kthread_should_stop())
+            {
+                gckOS_Delay(device->os, 1);
+            }
+
+            return 0;
+        }
+
+        gckKERNEL_Notify(device->kernels[core], gcvNOTIFY_INTERRUPT);
+    }
+}
+
+static gceSTATUS
+_StartThread(
+    IN gckGALDEVICE Device,
+    IN gceCORE Core
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE device = galDevice;
+    struct task_struct * task;
+
+    if (device->kernels[Core] != gcvNULL)
+    {
+        /* Start the kernel thread. */
+        task = kthread_run(threadRoutine, (void *)Core,
+                "galcore_deamon/%d", Core);
+
+        if (IS_ERR(task))
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): Could not start the kernel thread.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_GENERIC_IO);
+        }
+
+        device->threadCtxts[Core]         = task;
+        device->threadInitializeds[Core] = device->kernels[Core]->threadInitialized = gcvTRUE;
+
+        set_user_nice(task, -20);
+    }
+    else
+    {
+        device->threadInitializeds[Core] = gcvFALSE;
+    }
+
+OnError:
+    return status;
+}
+
+static void
+_StopThread(
+    gckGALDEVICE Device,
+    gceCORE Core
+    )
+{
+    if (Device->threadInitializeds[Core])
+    {
+        Device->killThread = gcvTRUE;
+        up(&Device->semas[Core]);
+
+        kthread_stop(Device->threadCtxts[Core]);
+        Device->threadCtxts[Core]        = gcvNULL;
+        Device->threadInitializeds[Core] = gcvFALSE;
+    }
+}
+
+/*******************************************************************************
+**
+**  gckGALDEVICE_Construct
+**
+**  Constructor.
+**
+**  INPUT:
+**
+**  OUTPUT:
+**
+**      gckGALDEVICE * Device
+**          Pointer to a variable receiving the gckGALDEVICE object pointer on
+**          success.
+*/
+gceSTATUS
+gckGALDEVICE_Construct(
+    IN gcsPLATFORM * Platform,
+    IN const gcsMODULE_PARAMETERS * Args,
+    OUT gckGALDEVICE *Device
+    )
+{
+    gckKERNEL kernel = gcvNULL;
+    gckGALDEVICE device;
+    gctINT32 i;
+
+#if !gcdCAPTURE_ONLY_MODE
+    gceHARDWARE_TYPE type;
+#endif
+
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Platform=%p Args=%p", Platform, Args);
+
+    /* Allocate device structure. */
+    device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN);
+
+    if (!device)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    memset(device, 0, sizeof(struct _gckGALDEVICE));
+
+    device->platform = Platform;
+    device->platform->dev = gcvNULL;
+
+    device->args = *Args;
+
+    /* Clear irq lines. */
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        device->irqLines[i] = -1;
+#if USE_LINUX_PCIE
+        device->bars[i] = -1;
+#endif
+    }
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        device->irqLines[i]                  = Args->irqs[i];
+        device->requestedRegisterMemBases[i] = Args->registerBases[i];
+        device->requestedRegisterMemSizes[i] = Args->registerSizes[i];
+#if USE_LINUX_PCIE
+        device->bars[i]                      = Args->bars[i];
+#endif
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE,
+                       "Get register base %llx of core %d",
+                       Args->registerBases[i], i);
+    }
+
+    device->requestedContiguousBase  = 0;
+    device->requestedContiguousSize  = 0;
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        unsigned long physical;
+        physical = (unsigned long)device->requestedRegisterMemBases[i];
+
+        /* Set up register memory region. */
+        if (physical != 0)
+        {
+            if (Args->registerBasesMapped[i])
+            {
+                device->registerBases[i] = Args->registerBasesMapped[i];
+                device->requestedRegisterMemBases[i] = 0;
+            }
+            else
+            {
+#if USE_LINUX_PCIE
+                gcmkPRINT("register should be mapped in platform layer");
+#endif
+                if (!request_mem_region(physical,
+                        device->requestedRegisterMemSizes[i],
+                        "galcore register region"))
+                {
+                    gcmkTRACE_ZONE(
+                            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                            "%s(%d): Failed to claim %lu bytes @ 0x%llx\n",
+                            __FUNCTION__, __LINE__,
+                            device->requestedRegisterMemSizes[i], physical
+                            );
+
+                    gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+                }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
+                device->registerBases[i] = (gctPOINTER)ioremap(physical, device->requestedRegisterMemSizes[i]);
+#else
+                device->registerBases[i] = (gctPOINTER)ioremap_nocache(physical, device->requestedRegisterMemSizes[i]);
+#endif
+
+                if (device->registerBases[i] == gcvNULL)
+                {
+                    gcmkTRACE_ZONE(
+                            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                            "%s(%d): Unable to map %ld bytes @ 0x%zx\n",
+                            __FUNCTION__, __LINE__,
+                            physical, device->requestedRegisterMemSizes[i]
+                            );
+
+                    gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+                }
+            }
+        }
+    }
+
+    /* Set the base address */
+    device->baseAddress = device->physBase = Args->baseAddress;
+    device->physSize = Args->physSize;
+
+    /* Set the external base address */
+    device->externalBase = Args->externalBase;
+    device->externalSize = Args->externalSize;
+
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        device->extSRAMBases[i] = Args->extSRAMBases[i];
+        device->extSRAMSizes[i] = Args->extSRAMSizes[i];
+    }
+
+    /* Construct the gckOS object. */
+    gcmkONERROR(gckOS_Construct(device, &device->os));
+
+
+    if (device->externalSize > 0)
+    {
+        /* create the external memory heap */
+        status = gckVIDMEM_Construct(
+            device->os,
+            device->externalBase,
+            device->externalSize,
+            64,
+            0,
+            &device->externalVidMem
+            );
+
+        if (gcmIS_ERROR(status))
+        {
+            /* Error, disable external heap. */
+            device->externalSize = 0;
+        }
+        else
+        {
+            /* Map external memory. */
+            gcmkONERROR(gckOS_RequestReservedMemory(
+                    device->os,
+                    device->externalBase, device->externalSize,
+                    "galcore external memory",
+                    gcvTRUE,
+                    &device->externalPhysical
+                    ));
+
+            device->externalVidMem->physical = device->externalPhysical;
+        }
+    }
+
+    /* Construct the gckDEVICE object for os independent core management. */
+    gcmkONERROR(gckDEVICE_Construct(device->os, &device->device));
+
+    device->device->showSRAMMapInfo = Args->showArgs;
+
+    device->platform->dev = device->device;
+
+    if (device->irqLines[gcvCORE_MAJOR] != -1)
+    {
+        gcmkONERROR(gctaOS_ConstructOS(device->os, &device->taos));
+    }
+
+    /* Setup contiguous video memory pool. */
+    gcmkONERROR(_SetupContiguousVidMem(device, Args));
+
+#if gcdEXTERNAL_SRAM_DEFAULT_POOL
+    /* Setup external SRAM video memory pool. */
+    gcmkONERROR(_SetupExternalSRAMVidMem(device));
+#endif
+
+    /* Add core for all available major cores. */
+    for (i = gcvCORE_MAJOR; i <= gcvCORE_3D_MAX; i++)
+    {
+        if (device->irqLines[i] != -1)
+        {
+            gcmkONERROR(gcTA_Construct(
+                device->taos,
+                (gceCORE)i,
+                &globalTA[i]
+                ));
+
+            gcmkONERROR(gckDEVICE_AddCore(
+                device->device,
+                (gceCORE)i,
+                Args->chipIDs[i],
+                device,
+                &device->kernels[i]
+                ));
+
+            gcmkONERROR(gckHARDWARE_SetFastClear(
+                device->kernels[i]->hardware,
+                Args->fastClear,
+                Args->compression
+                ));
+
+            gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+                device->kernels[i]->hardware,
+                Args->powerManagement
+                ));
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+            gcmkONERROR(gckHARDWARE_SetMinFscaleValue(
+                device->kernels[i]->hardware,
+                Args->gpu3DMinClock
+                ));
+#endif
+
+            gcmkONERROR(gckHARDWARE_SetGpuProfiler(
+                device->kernels[i]->hardware,
+                Args->gpuProfiler
+                ));
+        }
+        else
+        {
+            device->kernels[i] = gcvNULL;
+        }
+    }
+
+#if !gcdCAPTURE_ONLY_MODE
+    if (device->irqLines[gcvCORE_2D] != -1)
+    {
+        gcmkONERROR(gckDEVICE_AddCore(
+            device->device,
+            gcvCORE_2D,
+            gcvCHIP_ID_DEFAULT,
+            device,
+            &device->kernels[gcvCORE_2D]
+            ));
+
+        /* Verify the hardware type */
+        gcmkONERROR(gckHARDWARE_GetType(
+            device->kernels[gcvCORE_2D]->hardware,
+            &type
+            ));
+
+        if (type != gcvHARDWARE_2D)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): Unexpected hardware type: %d\n",
+                __FUNCTION__, __LINE__,
+                type
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+            device->kernels[gcvCORE_2D]->hardware,
+            Args->powerManagement
+            ));
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+        gcmkONERROR(gckHARDWARE_SetMinFscaleValue(
+            device->kernels[gcvCORE_2D]->hardware, 1
+            ));
+#endif
+    }
+    else
+    {
+        device->kernels[gcvCORE_2D] = gcvNULL;
+    }
+
+    if (device->irqLines[gcvCORE_VG] != -1)
+    {
+#if gcdENABLE_VG
+        gcmkONERROR(gckDEVICE_AddCore(
+            device->device,
+            gcvCORE_VG,
+            gcvCHIP_ID_DEFAULT,
+            device,
+            &device->kernels[gcvCORE_VG]
+            ));
+
+        gcmkONERROR(gckVGHARDWARE_EnablePowerManagement(
+            device->kernels[gcvCORE_VG]->vg->hardware,
+            Args->powerManagement
+            ));
+#endif
+    }
+    else
+    {
+        device->kernels[gcvCORE_VG] = gcvNULL;
+    }
+#else
+    device->kernels[gcvCORE_2D] = gcvNULL;
+
+    device->kernels[gcvCORE_VG] = gcvNULL;
+#endif
+
+#if !gcdEXTERNAL_SRAM_DEFAULT_POOL
+    /* Setup external SRAM video memory pool. */
+    gcmkONERROR(_SetupExternalSRAMVidMem(device));
+#endif
+
+    /* Initialize the kernel thread semaphores. */
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (device->irqLines[i] != -1 && device->kernels[i])
+        {
+            sema_init(&device->semas[i], 0);
+        }
+    }
+
+    /* Grab the first valid kernel. */
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (device->kernels[i] != gcvNULL)
+        {
+            kernel = device->kernels[i];
+            break;
+        }
+    }
+
+    if (!kernel)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (device->internalPhysical)
+    {
+        device->internalPhysName = gcmPTR_TO_NAME(device->internalPhysical);
+    }
+
+    if (device->externalPhysical)
+    {
+        device->externalPhysName = gcmPTR_TO_NAME(device->externalPhysical);
+    }
+
+    if (device->contiguousPhysical)
+    {
+        device->contiguousPhysName = gcmPTR_TO_NAME(device->contiguousPhysical);
+    }
+
+    gcmkONERROR(_DebugfsInit(device));
+
+    /* Return pointer to the device. */
+    *Device = galDevice = device;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        /* Roll back. */
+        gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckGALDEVICE_Destroy
+**
+**  Class destructor.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      Nothing.
+**
+**  RETURNS:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Destroy(
+    gckGALDEVICE Device)
+{
+    gctINT i, j = 0;
+    gckKERNEL kernel = gcvNULL;
+
+    gcmkHEADER_ARG("Device=%p", Device);
+
+    if (Device != gcvNULL)
+    {
+        /* Grab the first available kernel */
+        for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+        {
+            if (Device->kernels[i])
+            {
+                kernel = Device->kernels[i];
+                break;
+            }
+        }
+
+        if (kernel)
+        {
+            if (Device->internalPhysName != 0)
+            {
+                gcmRELEASE_NAME(Device->internalPhysName);
+                Device->internalPhysName = 0;
+            }
+            if (Device->externalPhysName != 0)
+            {
+                gcmRELEASE_NAME(Device->externalPhysName);
+                Device->externalPhysName = 0;
+            }
+            if (Device->contiguousPhysName != 0)
+            {
+                gcmRELEASE_NAME(Device->contiguousPhysName);
+                Device->contiguousPhysName = 0;
+            }
+        }
+
+        /* Destroy per-core SRAM heap. */
+        for (i = 0; i < gcvCORE_COUNT; i++)
+        {
+            if (Device->kernels[i])
+            {
+                kernel = Device->kernels[i];
+
+                for (j = gcvSRAM_INTERNAL0; j < gcvSRAM_INTER_COUNT; j++)
+                {
+                    if (kernel->sRAMPhysical[j] != gcvNULL)
+                    {
+                        /* Release reserved SRAM memory. */
+                        gckOS_ReleaseReservedMemory(
+                            Device->os,
+                            kernel->sRAMPhysical[j]
+                            );
+
+                        kernel->sRAMPhysical[j] = gcvNULL;
+                    }
+
+                    if (kernel->sRAMVidMem[j] != gcvNULL)
+                    {
+                        /* Destroy the SRAM contiguous heap. */
+                        gcmkVERIFY_OK(gckVIDMEM_Destroy(kernel->sRAMVidMem[j]));
+                        kernel->sRAMVidMem[j] = gcvNULL;
+                    }
+                }
+            }
+        }
+
+        if (Device->device)
+        {
+            gcmkVERIFY_OK(gckDEVICE_Destroy(Device->os, Device->device));
+
+            for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+            {
+                if (globalTA[i])
+                {
+                    gcTA_Destroy(globalTA[i]);
+                    globalTA[i] = gcvNULL;
+                }
+            }
+
+            Device->device = gcvNULL;
+        }
+
+        for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+        {
+            if (Device->kernels[i] != gcvNULL)
+            {
+                Device->kernels[i] = gcvNULL;
+            }
+        }
+
+        if (Device->internalLogical != gcvNULL)
+        {
+            /* Unmap the internal memory. */
+            iounmap(Device->internalLogical);
+            Device->internalLogical = gcvNULL;
+        }
+
+        if (Device->internalVidMem != gcvNULL)
+        {
+            /* Destroy the internal heap. */
+            gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem));
+            Device->internalVidMem = gcvNULL;
+        }
+
+        for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+        {
+            if (Device->extSRAMPhysical[i] != gcvNULL)
+            {
+                gckOS_ReleaseReservedMemory(
+                    Device->os,
+                    Device->extSRAMPhysical[i]
+                    );
+                Device->extSRAMPhysical[i] = gcvNULL;
+            }
+
+            if (Device->extSRAMVidMem[i] != gcvNULL)
+            {
+                gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->extSRAMVidMem[i]));
+                Device->extSRAMVidMem[i] = gcvNULL;
+            }
+        }
+
+        if (Device->externalPhysical != gcvNULL)
+        {
+            gckOS_ReleaseReservedMemory(
+                Device->os,
+                Device->externalPhysical
+                );
+            Device->externalPhysical = gcvNULL;
+        }
+
+        if (Device->externalLogical != gcvNULL)
+        {
+            Device->externalLogical = gcvNULL;
+        }
+
+        if (Device->externalVidMem != gcvNULL)
+        {
+            /* destroy the external heap */
+            gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem));
+            Device->externalVidMem = gcvNULL;
+        }
+
+        /*
+         * Destroy contiguous memory pool after gckDEVICE destroyed. gckDEVICE
+         * may allocates GPU memory types from SYSTEM pool.
+         */
+        if (Device->contiguousPhysical != gcvNULL)
+        {
+            if (Device->requestedContiguousBase == 0)
+            {
+                gcmkVERIFY_OK(_FreeMemory(
+                    Device,
+                    Device->contiguousLogical,
+                    Device->contiguousPhysical
+                    ));
+            }
+            else
+            {
+                gckOS_ReleaseReservedMemory(
+                    Device->os,
+                    Device->contiguousPhysical
+                    );
+                Device->contiguousPhysical = gcvNULL;
+                Device->requestedContiguousBase = 0;
+                Device->requestedContiguousSize = 0;
+            }
+
+            Device->contiguousLogical  = gcvNULL;
+            Device->contiguousPhysical = gcvNULL;
+        }
+
+        if (Device->contiguousVidMem != gcvNULL)
+        {
+            /* Destroy the contiguous heap. */
+            gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem));
+            Device->contiguousVidMem = gcvNULL;
+        }
+
+        for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+        {
+            if (Device->registerBases[i])
+            {
+                /* Unmap register memory. */
+                if (Device->requestedRegisterMemBases[i] != 0)
+                {
+                    iounmap(Device->registerBases[i]);
+
+                    release_mem_region(Device->requestedRegisterMemBases[i],
+                            Device->requestedRegisterMemSizes[i]);
+                }
+
+                Device->registerBases[i] = gcvNULL;
+                Device->requestedRegisterMemBases[i] = 0;
+                Device->requestedRegisterMemSizes[i] = 0;
+            }
+        }
+
+
+        if (Device->taos)
+        {
+            gcmkVERIFY_OK(gctaOS_DestroyOS(Device->taos));
+            Device->taos = gcvNULL;
+        }
+
+        /* Destroy the gckOS object. */
+        if (Device->os != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckOS_Destroy(Device->os));
+            Device->os = gcvNULL;
+        }
+
+        _DebugfsCleanup(Device);
+
+        /* Free the device. */
+        kfree(Device);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckGALDEVICE_Start
+**
+**  Start the gal device, including the following actions: setup the isr routine
+**  and start the daemoni thread.
+**
+**  INPUT:
+**
+**      gckGALDEVICE Device
+**          Pointer to an gckGALDEVICE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+**
+**  RETURNS:
+**
+**      gcvSTATUS_OK
+**          Start successfully.
+*/
+gceSTATUS
+gckGALDEVICE_Start(
+    IN gckGALDEVICE Device
+    )
+{
+    gctUINT i;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Device=%p", Device);
+
+    /* Start the kernel threads. */
+    for (i = 0; i < gcvCORE_COUNT; ++i)
+    {
+        if (i == gcvCORE_VG)
+        {
+            continue;
+        }
+
+        gcmkONERROR(_StartThread(Device, i));
+    }
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        if (Device->kernels[i] == gcvNULL)
+        {
+            continue;
+        }
+
+        /* Setup the ISR routine. */
+        gcmkONERROR(_SetupIsr(i));
+
+        if (i == gcvCORE_VG)
+        {
+#if gcdENABLE_VG
+            /* Switch to SUSPEND power state. */
+            gcmkONERROR(gckVGHARDWARE_SetPowerState(
+                Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF_BROADCAST
+                ));
+#endif
+        }
+        else
+        {
+            /* Switch to SUSPEND power state. */
+            gcmkONERROR(gckHARDWARE_SetPowerState(
+                Device->kernels[i]->hardware, gcvPOWER_OFF_BROADCAST
+                ));
+
+            gcmkONERROR(gckHARDWARE_StartTimerReset(Device->kernels[i]->hardware));
+        }
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckGALDEVICE_Stop
+**
+**  Stop the gal device, including the following actions: stop the daemon
+**  thread, release the irq.
+**
+**  INPUT:
+**
+**      gckGALDEVICE Device
+**          Pointer to an gckGALDEVICE object.
+**
+**  OUTPUT:
+**
+**      Nothing.
+**
+**  RETURNS:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Stop(
+    gckGALDEVICE Device
+    )
+{
+    gctUINT i;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Device=%p", Device);
+
+    gcmkVERIFY_ARGUMENT(Device != NULL);
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        if (Device->kernels[i] == gcvNULL)
+        {
+            continue;
+        }
+
+        if (Device->isrInitializeds[i] == gcvFALSE)
+        {
+            continue;
+        }
+
+        if (i == gcvCORE_VG)
+        {
+#if gcdENABLE_VG
+            /* Switch to OFF power state. */
+            gcmkONERROR(gckVGHARDWARE_SetPowerState(
+                Device->kernels[i]->vg->hardware, gcvPOWER_OFF
+                ));
+#endif
+        }
+        else
+        {
+            gcmkONERROR(gckHARDWARE_EnablePowerManagement(
+                Device->kernels[i]->hardware, gcvTRUE
+                ));
+
+            /* Switch to OFF power state. */
+            gcmkONERROR(gckHARDWARE_SetPowerState(
+                Device->kernels[i]->hardware, gcvPOWER_OFF
+                ));
+
+            gckHARDWARE_StartTimerReset(Device->kernels[i]->hardware);
+        }
+
+        /* Stop the ISR routine. */
+        gcmkONERROR(_ReleaseIsr(i));
+
+    }
+
+    /* Stop the kernel thread. */
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        _StopThread(Device, i);
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_device_h_
+#define __gc_hal_kernel_device_h_
+
+#include "gc_hal_kernel_debugfs.h"
+#include "gc_hal_ta.h"
+
+/******************************************************************************\
+************************** gckGALDEVICE Structure ******************************
+\******************************************************************************/
+
+typedef struct _gckGALDEVICE
+{
+    /* Objects. */
+    gckOS               os;
+    gckKERNEL           kernels[gcdMAX_GPU_COUNT];
+
+    gcsPLATFORM*        platform;
+
+    /* Attributes. */
+    gctPHYS_ADDR_T      internalBase;
+    gctSIZE_T           internalSize;
+    gctPHYS_ADDR        internalPhysical;
+    gctUINT32           internalPhysName;
+    gctPOINTER          internalLogical;
+    gckVIDMEM           internalVidMem;
+
+    gctPHYS_ADDR_T      externalBase;
+    gctSIZE_T           externalSize;
+    gctPHYS_ADDR        externalPhysical;
+    gctUINT32           externalPhysName;
+    gctPOINTER          externalLogical;
+    gckVIDMEM           externalVidMem;
+
+    /* Shared external SRAMs. */
+    gctPHYS_ADDR_T      extSRAMBases[gcvSRAM_EXT_COUNT];
+    gctSIZE_T           extSRAMSizes[gcvSRAM_EXT_COUNT];
+    gctPHYS_ADDR        extSRAMPhysical[gcvSRAM_EXT_COUNT];
+    gckVIDMEM           extSRAMVidMem[gcvSRAM_EXT_COUNT];
+
+    gctPHYS_ADDR_T      contiguousBase;
+    gctSIZE_T           contiguousSize;
+    gctPHYS_ADDR        contiguousPhysical;
+    gctUINT32           contiguousPhysName;
+    gctPOINTER          contiguousLogical;
+    gckVIDMEM           contiguousVidMem;
+
+    /* By request_mem_region. */
+    gctUINT64           requestedContiguousBase;
+    gctSIZE_T           requestedContiguousSize;
+
+    /* IRQ management. */
+    gctINT              irqLines[gcdMAX_GPU_COUNT];
+    gctBOOL             isrInitializeds[gcdMAX_GPU_COUNT];
+
+    /* Register memory. */
+    gctPOINTER          registerBases[gcdMAX_GPU_COUNT];
+    gctSIZE_T           registerSizes[gcdMAX_GPU_COUNT];
+
+    /* By request_mem_region. */
+    gctUINT64           requestedRegisterMemBases[gcdMAX_GPU_COUNT];
+    gctSIZE_T           requestedRegisterMemSizes[gcdMAX_GPU_COUNT];
+
+    gctUINT32           baseAddress;
+    gctUINT32           physBase;
+    gctUINT32           physSize;
+
+
+    /* PCIE Bar */
+    gctINT              bars[gcdMAX_GPU_COUNT];
+
+    /* Thread management. */
+    struct task_struct *threadCtxts[gcdMAX_GPU_COUNT];
+    struct semaphore    semas[gcdMAX_GPU_COUNT];
+    gctBOOL             threadInitializeds[gcdMAX_GPU_COUNT];
+    gctBOOL             killThread;
+
+    /* States before suspend. */
+    gceCHIPPOWERSTATE   statesStored[gcdMAX_GPU_COUNT];
+
+    gcsDEBUGFS_DIR      debugfsDir;
+
+    gckDEVICE           device;
+
+    gcsMODULE_PARAMETERS args;
+
+    /* gctsOs object for trust application. */
+    gctaOS              taos;
+
+#if gcdENABLE_DRM
+    void *              drm;
+#endif
+}
+* gckGALDEVICE;
+
+typedef struct _gcsHAL_PRIVATE_DATA
+{
+    gckGALDEVICE        device;
+    /*
+     * 'fput' schedules actual work in '__fput' in a different thread.
+     * So the process opens the device may not be the same as the one that
+     * closes it.
+     */
+    gctUINT32           pidOpen;
+    gctBOOL             isLocked;
+}
+gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR;
+
+gceSTATUS
+gckGALDEVICE_Start(
+    IN gckGALDEVICE Device
+    );
+
+gceSTATUS
+gckGALDEVICE_Stop(
+    gckGALDEVICE Device
+    );
+
+gceSTATUS
+gckGALDEVICE_Construct(
+    IN gcsPLATFORM * Platform,
+    IN const gcsMODULE_PARAMETERS * Args,
+    OUT gckGALDEVICE *Device
+    );
+
+gceSTATUS
+gckGALDEVICE_Destroy(
+    IN gckGALDEVICE Device
+    );
+
+static gcmINLINE gckKERNEL
+_GetValidKernel(
+    gckGALDEVICE Device
+    )
+{
+    if (Device->kernels[gcvCORE_MAJOR])
+    {
+        return Device->kernels[gcvCORE_MAJOR];
+    }
+    else if (Device->kernels[gcvCORE_2D])
+    {
+        return Device->kernels[gcvCORE_2D];
+    }
+    else if (Device->kernels[gcvCORE_VG])
+    {
+        return Device->kernels[gcvCORE_VG];
+    }
+    else
+    {
+        gcmkASSERT(gcvFALSE);
+        return gcvNULL;
+    }
+}
+
+#endif /* __gc_hal_kernel_device_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
@@ -0,0 +1,1640 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_driver.h"
+
+#include <linux/platform_device.h>
+
+/* Zone used for header/footer. */
+#define _GC_OBJ_ZONE    gcvZONE_DRIVER
+
+MODULE_DESCRIPTION("Vivante Graphics Driver");
+MODULE_LICENSE("Dual MIT/GPL");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
+#endif
+
+static struct class* gpuClass = NULL;
+
+static gcsPLATFORM *platform = NULL;
+
+static gckGALDEVICE galDevice;
+
+static uint major = 199;
+module_param(major, uint, 0644);
+MODULE_PARM_DESC(major, "major device number for GC device");
+
+static int irqLine = -1;
+module_param(irqLine, int, 0644);
+MODULE_PARM_DESC(irqLine, "IRQ number of GC core");
+
+static ulong registerMemBase = 0x80000000;
+module_param(registerMemBase, ulong, 0644);
+MODULE_PARM_DESC(registerMemBase, "Base of bus address of GC core AHB register");
+
+static ulong registerMemSize = 2 << 16;
+module_param(registerMemSize, ulong, 0644);
+MODULE_PARM_DESC(registerMemSize, "Size of bus address range of GC core AHB register");
+
+static int irqLine2D = -1;
+module_param(irqLine2D, int, 0644);
+MODULE_PARM_DESC(irqLine2D, "IRQ number of G2D core if irqLine is used for a G3D core");
+
+static ulong registerMemBase2D = 0x00000000;
+module_param(registerMemBase2D, ulong, 0644);
+MODULE_PARM_DESC(registerMemBase2D, "Base of bus address of G2D core if registerMemBase2D is used for a G3D core");
+
+static ulong registerMemSize2D = 2 << 16;
+module_param(registerMemSize2D, ulong, 0644);
+MODULE_PARM_DESC(registerMemSize2D, "Size of bus address range of G2D core if registerMemSize is used for a G3D core");
+
+static int irqLineVG = -1;
+module_param(irqLineVG, int, 0644);
+MODULE_PARM_DESC(irqLineVG, "IRQ number of VG core");
+
+static ulong registerMemBaseVG = 0x00000000;
+module_param(registerMemBaseVG, ulong, 0644);
+MODULE_PARM_DESC(registerMemBaseVG, "Base of bus address of VG core");
+
+static ulong registerMemSizeVG = 2 << 10;
+module_param(registerMemSizeVG, ulong, 0644);
+MODULE_PARM_DESC(registerMemSizeVG, "Size of bus address range of VG core");
+
+#if gcdDEC_ENABLE_AHB
+static ulong registerMemBaseDEC300 = 0x00000000;
+module_param(registerMemBaseDEC300, ulong, 0644);
+
+static ulong registerMemSizeDEC300 = 2 << 10;
+module_param(registerMemSizeDEC300, ulong, 0644);
+#endif
+
+#ifndef gcdDEFAULT_CONTIGUOUS_SIZE
+#define gcdDEFAULT_CONTIGUOUS_SIZE (4 << 20)
+#endif
+static ulong contiguousSize = gcdDEFAULT_CONTIGUOUS_SIZE;
+module_param(contiguousSize, ulong, 0644);
+MODULE_PARM_DESC(contiguousSize, "Size of memory reserved for GC");
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+static gctPHYS_ADDR_T contiguousBase = 0;
+module_param(contiguousBase, ullong, 0644);
+#else
+static ulong contiguousBase = 0;
+module_param(contiguousBase, ulong, 0644);
+#endif
+MODULE_PARM_DESC(contiguousBase, "Base address of memory reserved for GC, if it is 0, GC driver will try to allocate a buffer whose size defined by contiguousSize");
+
+static ulong externalSize = 0;
+module_param(externalSize, ulong, 0644);
+MODULE_PARM_DESC(externalSize, "Size of external memory, if it is 0, means there is no external pool");
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+static gctPHYS_ADDR_T externalBase = 0;
+module_param(externalBase, ullong, 0644);
+#else
+static ulong externalBase = 0;
+module_param(externalBase, ulong, 0644);
+#endif
+MODULE_PARM_DESC(externalBase, "Base address of external memory");
+
+
+static int fastClear = -1;
+module_param(fastClear, int, 0644);
+MODULE_PARM_DESC(fastClear, "Disable fast clear if set it to 0, enabled by default");
+
+static int compression = -1;
+module_param(compression, int, 0644);
+MODULE_PARM_DESC(compression, "Disable compression if set it to 0, enabled by default");
+
+static int powerManagement = 1;
+module_param(powerManagement, int, 0644);
+MODULE_PARM_DESC(powerManagement, "Disable auto power saving if set it to 0, enabled by default");
+
+static int gpuProfiler = 0;
+module_param(gpuProfiler, int, 0644);
+MODULE_PARM_DESC(gpuProfiler, "Enable profiling support, disabled by default");
+
+static ulong baseAddress = 0;
+module_param(baseAddress, ulong, 0644);
+MODULE_PARM_DESC(baseAddress, "Only used for old MMU, set it to 0 if memory which can be accessed by GPU falls into 0 - 2G, otherwise set it to 0x80000000");
+
+static ulong physSize = 0;
+module_param(physSize, ulong, 0644);
+MODULE_PARM_DESC(physSize, "Obsolete");
+
+static uint recovery = 0;
+module_param(recovery, uint, 0644);
+MODULE_PARM_DESC(recovery, "Recover GPU from stuck (1: Enable, 0: Disable)");
+
+/* Middle needs about 40KB buffer, Maximal may need more than 200KB buffer. */
+static uint stuckDump = 0;
+module_param(stuckDump, uint, 0644);
+MODULE_PARM_DESC(stuckDump, "Level of stuck dump content (1: Minimal, 2: Middle, 3: Maximal)");
+
+static int showArgs = 0;
+module_param(showArgs, int, 0644);
+MODULE_PARM_DESC(showArgs, "Display parameters value when driver loaded");
+
+static int mmu = 1;
+module_param(mmu, int, 0644);
+MODULE_PARM_DESC(mmu, "Disable MMU if set it to 0, enabled by default [Obsolete]");
+
+static int irqs[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = -1};
+module_param_array(irqs, int, NULL, 0644);
+MODULE_PARM_DESC(irqs, "Array of IRQ numbers of multi-GPU");
+
+static uint registerBases[gcvCORE_COUNT];
+module_param_array(registerBases, uint, NULL, 0644);
+MODULE_PARM_DESC(registerBases, "Array of bases of bus address of register of multi-GPU");
+
+static uint registerSizes[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = 2 << 16};
+module_param_array(registerSizes, uint, NULL, 0644);
+MODULE_PARM_DESC(registerSizes, "Array of sizes of bus address range of register of multi-GPU");
+
+static uint chipIDs[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = gcvCHIP_ID_DEFAULT};
+module_param_array(chipIDs, uint, NULL, 0644);
+MODULE_PARM_DESC(chipIDs, "Array of chipIDs of multi-GPU");
+
+static uint type = 0;
+module_param(type, uint, 0664);
+MODULE_PARM_DESC(type, "0 - Char Driver (Default), 1 - Misc Driver");
+
+static int userClusterMask = 0;
+module_param(userClusterMask, int, 0644);
+MODULE_PARM_DESC(userClusterMask, "User defined cluster enable mask");
+
+/* GPU small batch feature. */
+static int smallBatch = 1;
+module_param(smallBatch, int, 0644);
+MODULE_PARM_DESC(smallBatch, "Enable/disable GPU small batch feature, enable by default");
+
+static int allMapInOne = 1;
+module_param(allMapInOne, int, 0644);
+MODULE_PARM_DESC(allMapInOne, "Mapping kernel video memory to user, 0 means mapping every time, otherwise only mapping one time");
+/*******************************************************************************
+***************************** SRAM description *********************************
+*******************************************************************************/
+
+/* Per-core SRAM physical address base, the order of configuration is according to access speed, gcvINVALID_PHYSICAL_ADDRESS means no bus address. */
+static gctPHYS_ADDR_T sRAMBases[gcvSRAM_INTER_COUNT * gcvCORE_COUNT] = {[0 ... gcvSRAM_INTER_COUNT * gcvCORE_COUNT - 1] = gcvINVALID_PHYSICAL_ADDRESS};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+module_param_array(sRAMBases, ullong, NULL, 0644);
+MODULE_PARM_DESC(sRAMBases, "Array of base of bus address of SRAM,INTERNAL, EXTERNAL0, EXTERNAL1..., gcvINVALID_PHYSICAL_ADDRESS means no bus address");
+#endif
+
+/* Per-core SRAM size. */
+static uint sRAMSizes[gcvSRAM_INTER_COUNT * gcvCORE_COUNT] = {[0 ... gcvSRAM_INTER_COUNT * gcvCORE_COUNT - 1] = 0};
+module_param_array(sRAMSizes, uint, NULL, 0644);
+MODULE_PARM_DESC(sRAMSizes, "Array of size of per-core SRAMs, 0 means no SRAM");
+
+/* Shared SRAM physical address bases. */
+static gctPHYS_ADDR_T extSRAMBases[gcvSRAM_EXT_COUNT] = {[0 ... gcvSRAM_EXT_COUNT - 1] = gcvINVALID_PHYSICAL_ADDRESS};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+module_param_array(extSRAMBases, ullong, NULL, 0644);
+MODULE_PARM_DESC(extSRAMBases, "Shared SRAM physical address bases.");
+#endif
+
+/* Shared SRAM sizes. */
+static uint extSRAMSizes[gcvSRAM_EXT_COUNT] = {[0 ... gcvSRAM_EXT_COUNT - 1] = 0};
+module_param_array(extSRAMSizes, uint, NULL, 0644);
+MODULE_PARM_DESC(extSRAMSizes, "Shared SRAM sizes.");
+
+static uint sRAMRequested = 1;
+module_param(sRAMRequested, uint, 0644);
+MODULE_PARM_DESC(sRAMRequested, "Default 1 means AXI-SRAM is already reserved for GPU, 0 means GPU driver need request the memory region.");
+
+static uint mmuPageTablePool = 1;
+module_param(mmuPageTablePool, uint, 0644);
+MODULE_PARM_DESC(mmuPageTablePool, "Default 1 means alloc mmu page table in virsual memory, 0 means auto select memory pool.");
+
+static uint sRAMLoopMode = 0;
+module_param(sRAMLoopMode, uint, 0644);
+MODULE_PARM_DESC(sRAMLoopMode, "Default 0 means SRAM pool must be specified when allocating SRAM memory, 1 means SRAM memory will be looped as default pool.");
+
+static uint mmuDynamicMap = 1;
+module_param(mmuDynamicMap, uint, 0644);
+MODULE_PARM_DESC(mmuDynamicMap, "Default 1 means enable mmu dynamic mapping in virsual memory, 0 means disable dynnamic mapping.");
+
+#if USE_LINUX_PCIE
+static int bar = 1;
+module_param(bar, int, 0644);
+MODULE_PARM_DESC(bar, "PCIE Bar index of GC core");
+
+static int bars[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = -1};
+module_param_array(bars, int, NULL, 0644);
+MODULE_PARM_DESC(bars, "Array of bar index of PCIE platform for multi-GPU");
+
+static uint regOffsets[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = 0};
+module_param_array(regOffsets, uint, NULL, 0644);
+MODULE_PARM_DESC(regOffsets, "Array of register offsets in corresponding BAR space");
+
+static int sRAMBars[gcvSRAM_EXT_COUNT] = {[0 ... gcvSRAM_EXT_COUNT - 1] = -1};
+module_param_array(sRAMBars, int, NULL, 0644);
+MODULE_PARM_DESC(sRAMBars, "Array of SRAM bar index of shared external SRAMs.");
+
+static int sRAMOffsets[gcvSRAM_EXT_COUNT] = {[0 ... gcvSRAM_EXT_COUNT - 1] = -1};
+module_param_array(sRAMOffsets, int, NULL, 0644);
+MODULE_PARM_DESC(sRAMOffsets, "Array of SRAM offset inside bar of shared external SRAMs.");
+#endif
+
+static int gpu3DMinClock = 1;
+static int contiguousRequested = 0;
+static ulong bankSize = 0;
+
+
+static gcsMODULE_PARAMETERS moduleParam;
+
+static void
+_InitModuleParam(
+    gcsMODULE_PARAMETERS * ModuleParam
+    )
+{
+    gctUINT i, j;
+    gcsMODULE_PARAMETERS *p = ModuleParam;
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        p->irqs[i] = irqs[i];
+
+        if (irqs[i] != -1)
+        {
+            p->registerBases[i] = registerBases[i];
+            p->registerSizes[i] = registerSizes[i];
+        }
+#if USE_LINUX_PCIE
+        p->bars[i] = bars[i];
+        p->regOffsets[i] = regOffsets[i];
+#endif
+    }
+
+    /* Check legacy style. */
+#if USE_LINUX_PCIE
+    if (bar != -1)
+    {
+        p->bars[gcvCORE_MAJOR]         = bar;
+    }
+#endif
+
+    if (irqLine != -1)
+    {
+        p->irqs[gcvCORE_MAJOR]          = irqLine;
+        p->registerBases[gcvCORE_MAJOR] = registerMemBase;
+        p->registerSizes[gcvCORE_MAJOR] = registerMemSize;
+    }
+
+    if (irqLine2D != -1)
+    {
+        p->irqs[gcvCORE_2D]          = irqLine2D;
+        p->registerBases[gcvCORE_2D] = registerMemBase2D;
+        p->registerSizes[gcvCORE_2D] = registerMemSize2D;
+    }
+
+    if (irqLineVG != -1)
+    {
+        p->irqs[gcvCORE_VG]          = irqLineVG;
+        p->registerBases[gcvCORE_VG] = registerMemBaseVG;
+        p->registerSizes[gcvCORE_VG] = registerMemSizeVG;
+    }
+
+#if gcdDEC_ENABLE_AHB
+    if (registerMemBaseDEC300 && registerMemSizeDEC300)
+    {
+        p->registerBases[gcvCORE_DEC] = registerMemBaseDEC300;
+        p->registerSizes[gcvCORE_DEC] = registerMemSizeDEC300;
+    }
+#endif
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        /* Not a module param. */
+        p->registerBasesMapped[i] = gcvNULL;
+    }
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        p->chipIDs[i] = chipIDs[i];
+    }
+
+    p->contiguousBase      = contiguousBase;
+    p->contiguousSize      = contiguousSize;
+    p->contiguousRequested = contiguousRequested;   /* not a module param. */
+
+    p->externalBase = externalBase;
+    p->externalSize = externalSize;
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            p->sRAMBases[i][j] = sRAMBases[i * gcvSRAM_INTER_COUNT + j];
+            p->sRAMSizes[i][j] = sRAMSizes[i * gcvSRAM_INTER_COUNT + j];
+        }
+    }
+
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        p->extSRAMBases[i] = extSRAMBases[i];
+        p->extSRAMSizes[i] = extSRAMSizes[i];
+#if USE_LINUX_PCIE
+        p->sRAMBars[i]     = sRAMBars[i];
+        p->sRAMOffsets[i]  = sRAMOffsets[i];
+#endif
+    }
+
+    p->sRAMRequested = sRAMRequested;
+    p->sRAMLoopMode = sRAMLoopMode;
+
+    p->baseAddress = baseAddress;
+    p->physSize    = physSize;
+    p->bankSize    = bankSize;  /* not a module param. */
+
+    p->recovery        = recovery;
+    p->powerManagement = powerManagement;
+
+    p->enableMmu = mmu;
+    p->fastClear = fastClear;
+
+    p->compression = (compression == -1) ? gcvCOMPRESSION_OPTION_DEFAULT
+                   : (gceCOMPRESSION_OPTION)compression;
+    p->gpu3DMinClock   = gpu3DMinClock; /* not a module param. */
+    p->userClusterMask = userClusterMask;
+    p->smallBatch      = smallBatch;
+
+    p->stuckDump   = stuckDump;
+    p->gpuProfiler = gpuProfiler;
+
+    p->deviceType  = type;
+    p->showArgs    = showArgs;
+
+    p->mmuPageTablePool = mmuPageTablePool;
+
+    p->mmuDynamicMap = mmuDynamicMap;
+    p->allMapInOne = allMapInOne;
+#if !gcdENABLE_3D
+    p->irqs[gcvCORE_MAJOR]          = irqLine = -1;
+    p->registerBases[gcvCORE_MAJOR] = registerMemBase = 0;
+    p->registerSizes[gcvCORE_MAJOR] = registerMemSize = 0;
+#endif
+
+#if !gcdENABLE_2D
+    p->irqs[gcvCORE_2D]          = irqLine2D = -1;
+    p->registerBases[gcvCORE_2D] = registerMemBase2D = 0;
+    p->registerSizes[gcvCORE_2D] = registerMemSize2D = 0;
+#endif
+
+#if !gcdENABLE_VG
+    p->irqs[gcvCORE_VG]          = irqLineVG = -1;
+    p->registerBases[gcvCORE_VG] = registerMemBaseVG = 0;
+    p->registerSizes[gcvCORE_VG] = registerMemSizeVG = 0;
+#endif
+}
+
+static void
+_SyncModuleParam(
+    const gcsMODULE_PARAMETERS * ModuleParam
+    )
+{
+    gctUINT i, j;
+    gcsMODULE_PARAMETERS *p = &moduleParam;
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        irqs[i]          = p->irqs[i];
+        registerBases[i] = (ulong)p->registerBases[i];
+        registerSizes[i] = (ulong)p->registerSizes[i];
+ #if USE_LINUX_PCIE
+        bars[i]          = p->bars[i];
+        regOffsets[i]    = p->regOffsets[i];
+ #endif
+    }
+
+    /* Sync to legacy style. */
+
+#if USE_LINUX_PCIE
+    bar               = p->bars[gcvCORE_MAJOR];
+#endif
+    irqLine           = p->irqs[gcvCORE_MAJOR];
+    registerMemBase   = (ulong)p->registerBases[gcvCORE_MAJOR];
+    registerMemSize   = (ulong)p->registerSizes[gcvCORE_MAJOR];
+
+    irqLine2D         = p->irqs[gcvCORE_2D];
+    registerMemBase2D = (ulong)p->registerBases[gcvCORE_2D];
+    registerMemSize2D = (ulong)p->registerSizes[gcvCORE_2D];
+
+    irqLineVG         = p->irqs[gcvCORE_VG];
+    registerMemBaseVG = (ulong)p->registerBases[gcvCORE_VG];
+    registerMemSizeVG = (ulong)p->registerSizes[gcvCORE_VG];
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        p->chipIDs[i] = chipIDs[i];
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+    contiguousBase      = p->contiguousBase;
+    contiguousSize      = p->contiguousSize;
+#else
+    contiguousBase      = (ulong)p->contiguousBase;
+    contiguousSize      = (ulong)p->contiguousSize;
+#endif
+
+    contiguousRequested = p->contiguousRequested;   /* not a module param. */
+
+    externalBase = p->externalBase;
+    externalSize = p->externalSize;
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            sRAMBases[i * gcvSRAM_INTER_COUNT + j] = p->sRAMBases[i][j];
+            sRAMSizes[i * gcvSRAM_INTER_COUNT + j] = p->sRAMSizes[i][j];
+        }
+    }
+
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        extSRAMBases[i] = p->extSRAMBases[i];
+        extSRAMSizes[i] = p->extSRAMSizes[i];
+
+#if USE_LINUX_PCIE
+        sRAMBars[i]     = p->sRAMBars[i];
+        sRAMOffsets[i]  = p->sRAMOffsets[i];
+#endif
+    }
+
+    sRAMRequested = p->sRAMRequested;
+    sRAMLoopMode  = p->sRAMLoopMode;
+
+    baseAddress = (ulong)p->baseAddress;
+    physSize    = p->physSize;
+    bankSize    = p->bankSize;  /* not a module param. */
+
+    recovery        = p->recovery;
+    powerManagement = p->powerManagement;
+
+    mmu             = p->enableMmu;
+    fastClear       = p->fastClear;
+    compression     = p->compression;
+    gpu3DMinClock   = p->gpu3DMinClock; /* not a module param. */
+    userClusterMask = p->userClusterMask;
+    smallBatch      = p->smallBatch;
+
+    stuckDump   = p->stuckDump;
+    gpuProfiler = p->gpuProfiler;
+
+    type        = p->deviceType;
+    showArgs    = p->showArgs;
+
+    mmuPageTablePool = p->mmuDynamicMap;
+    mmuDynamicMap = p->mmuDynamicMap;
+    allMapInOne = p->allMapInOne;
+}
+
+void
+gckOS_DumpParam(
+    void
+    )
+{
+    gctINT i, j;
+
+    printk("Galcore options:\n");
+    if (irqLine != -1)
+    {
+        printk("  irqLine           = %d\n",      irqLine);
+        printk("  registerMemBase   = 0x%08lX\n", registerMemBase);
+        printk("  registerMemSize   = 0x%08lX\n", registerMemSize);
+    }
+
+    if (irqLine2D != -1)
+    {
+        printk("  irqLine2D         = %d\n",      irqLine2D);
+        printk("  registerMemBase2D = 0x%08lX\n", registerMemBase2D);
+        printk("  registerMemSize2D = 0x%08lX\n", registerMemSize2D);
+    }
+
+    if (irqLineVG != -1)
+    {
+        printk("  irqLineVG         = %d\n",      irqLineVG);
+        printk("  registerMemBaseVG = 0x%08lX\n", registerMemBaseVG);
+        printk("  registerMemSizeVG = 0x%08lX\n", registerMemSizeVG);
+    }
+#if USE_LINUX_PCIE
+    if (bar != -1)
+    {
+        printk("  bar               = %d\n",      bar);
+    }
+#endif
+#if gcdDEC_ENABLE_AHB
+    printk("  registerMemBaseDEC300 = 0x%08lX\n", registerMemBaseDEC300);
+    printk("  registerMemSizeDEC300 = 0x%08lX\n", registerMemSizeDEC300);
+#endif
+
+    printk("  contiguousSize    = 0x%08lX\n", contiguousSize);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+    printk("  contiguousBase    = 0x%llX\n",  contiguousBase);
+#else
+    printk("  contiguousBase    = 0x%lX\n",  contiguousBase);
+#endif
+    printk("  externalSize      = 0x%08lX\n", externalSize);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+    printk("  externalBase      = 0x%llX\n",  externalBase);
+#else
+    printk("  externalBase      = 0x%lX\n",  externalBase);
+#endif
+    printk("  bankSize          = 0x%08lX\n", bankSize);
+    printk("  fastClear         = %d\n",      fastClear);
+    printk("  compression       = %d\n",      compression);
+    printk("  powerManagement   = %d\n",      powerManagement);
+    printk("  baseAddress       = 0x%08lX\n", baseAddress);
+    printk("  physSize          = 0x%08lX\n", physSize);
+    printk("  recovery          = %d\n",      recovery);
+    printk("  stuckDump         = %d\n",      stuckDump);
+    printk("  gpuProfiler       = %d\n",      gpuProfiler);
+    printk("  userClusterMask   = 0x%x\n",    userClusterMask);
+    printk("  GPU smallBatch    = %d\n",      smallBatch);
+    printk("  allMapInOne       = %d\n",      allMapInOne);
+
+    printk("  irqs              = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("%d, ", irqs[i]);
+    }
+    printk("\n");
+
+#if USE_LINUX_PCIE
+    printk("  bars              = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("%d, ", bars[i]);
+    }
+    printk("\n");
+
+    printk("  regOffsets        = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("%d, ", regOffsets[i]);
+    }
+    printk("\n");
+
+#endif
+    printk("  registerBases     = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("0x%08X, ", registerBases[i]);
+    }
+    printk("\n");
+
+    printk("  registerSizes     = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("0x%08X, ", registerSizes[i]);
+    }
+    printk("\n");
+
+    printk("  chipIDs           = ");
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("0x%08X, ", chipIDs[i]);
+    }
+    printk("\n");
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        printk("  core %d internal sRAMBases = ", i);
+
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            printk("0x%llX, ", sRAMBases[i * gcvSRAM_INTER_COUNT + j]);
+        }
+        printk("\n");
+    }
+
+    printk("  External sRAMBases = ");
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        printk("0x%llx, ", extSRAMBases[i]);
+    }
+    printk("\n");
+
+    printk("  mmuPageTablePool  = %d\n", mmuPageTablePool);
+    printk("  mmuDynamicMap     = %d\n", mmuDynamicMap);
+
+    printk("Build options:\n");
+    printk("  gcdGPU_TIMEOUT    = %d\n", gcdGPU_TIMEOUT);
+    printk("  gcdGPU_2D_TIMEOUT = %d\n", gcdGPU_2D_TIMEOUT);
+    printk("  gcdINTERRUPT_STATISTIC = %d\n", gcdINTERRUPT_STATISTIC);
+}
+
+static int drv_open(
+    struct inode* inode,
+    struct file* filp
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsHAL_PRIVATE_DATA_PTR data = gcvNULL;
+    gctINT i;
+    gctINT attached = 0;
+
+    gcmkHEADER_ARG("inode=%p filp=%p", inode, filp);
+
+    data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN);
+
+    if (data == gcvNULL)
+    {
+        gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
+        return -ENOMEM;
+    }
+
+    data->isLocked = gcvFALSE;
+    data->device   = galDevice;
+    data->pidOpen  = _GetProcessID();
+
+    /* Attached the process. */
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (galDevice->kernels[i] != gcvNULL)
+        {
+            status = gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE);
+
+            if (gcmIS_ERROR(status))
+            {
+                break;
+            }
+
+            attached = i;
+        }
+    }
+
+    if (gcmIS_ERROR(status))
+    {
+        /* Error. */
+        for (i = 0; i < attached; i++)
+        {
+            if (galDevice->kernels[i] != gcvNULL)
+            {
+                gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE));
+            }
+        }
+        kfree(data);
+        gcmkFOOTER_ARG("status=%d", status);
+        return -ENOTTY;
+    }
+
+    filp->private_data = data;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return 0;
+}
+
+static int drv_release(
+    struct inode* inode,
+    struct file* filp
+    )
+{
+    int ret = -ENOTTY;
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsHAL_PRIVATE_DATA_PTR data;
+    gckGALDEVICE device;
+    gctINT i;
+
+    gcmkHEADER_ARG("inode=%p filp=%p", inode, filp);
+
+    data = filp->private_data;
+
+    if (data == gcvNULL)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): private_data is NULL\n",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    device = data->device;
+
+    if (device == gcvNULL)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): device is NULL\n",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (data->isLocked)
+    {
+        /* Release the mutex. */
+        gcmkONERROR(gckOS_ReleaseMutex(gcvNULL, device->device->commitMutex));
+        data->isLocked = gcvFALSE;
+    }
+
+    /* A process gets detached. */
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (galDevice->kernels[i] != gcvNULL)
+        {
+            gcmkVERIFY_OK(gckKERNEL_AttachProcessEx(
+                galDevice->kernels[i],
+                gcvFALSE,
+                data->pidOpen
+                ));
+        }
+    }
+
+    kfree(data);
+    filp->private_data = NULL;
+
+    /* Success. */
+    ret = 0;
+
+OnError:
+    gcmkFOOTER();
+    return ret;
+}
+
+static long drv_ioctl(
+    struct file* filp,
+    unsigned int ioctlCode,
+    unsigned long arg
+    )
+{
+    long ret = -ENOTTY;
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsHAL_INTERFACE iface;
+
+#if VIVANTE_PROFILER
+    gcsHAL_PROFILER_INTERFACE iface_profiler;
+#endif
+
+    gctUINT32 copyLen;
+    DRIVER_ARGS drvArgs;
+    gckGALDEVICE device;
+    gcsHAL_PRIVATE_DATA_PTR data;
+
+    gcmkHEADER_ARG("filp=%p ioctlCode=%u arg=%lu",filp, ioctlCode, arg);
+
+    data = filp->private_data;
+
+    if (data == gcvNULL)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): private_data is NULL\n",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    device = data->device;
+
+    if (device == gcvNULL)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): device is NULL\n",
+            __FUNCTION__, __LINE__
+            );
+
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    switch (ioctlCode)
+    {
+    case IOCTL_GCHAL_INTERFACE:
+        /* Get the drvArgs. */
+        copyLen = copy_from_user(
+            &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
+            );
+
+        if (copyLen != 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of the input arguments.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        /* Now bring in the gcsHAL_INTERFACE structure. */
+        if ((drvArgs.InputBufferSize  != sizeof(gcsHAL_INTERFACE))
+        ||  (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE))
+        )
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): input or/and output structures are invalid.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        copyLen = copy_from_user(
+            &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE)
+            );
+
+        if (copyLen != 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of input HAL interface.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        if (iface.command == gcvHAL_DEVICE_MUTEX)
+        {
+            if (iface.u.DeviceMutex.isMutexLocked == gcvTRUE)
+            {
+                data->isLocked = gcvTRUE;
+            }
+            else
+            {
+                data->isLocked = gcvFALSE;
+            }
+        }
+
+        status = gckDEVICE_Dispatch(device->device, &iface);
+
+        /* Redo system call after pending signal is handled. */
+        if (status == gcvSTATUS_INTERRUPTED)
+        {
+            ret = -ERESTARTSYS;
+            gcmkONERROR(status);
+        }
+
+        /* Copy data back to the user. */
+        copyLen = copy_to_user(
+            gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE)
+            );
+
+        if (copyLen != 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of output HAL interface.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+        break;
+
+    case IOCTL_GCHAL_PROFILER_INTERFACE:
+#if VIVANTE_PROFILER
+        /* Get the drvArgs. */
+        copyLen = copy_from_user(
+            &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
+            );
+
+        if (copyLen != 0)
+        {
+           gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of the input arguments.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        /* Now bring in the gcsHAL_INTERFACE structure. */
+        if ((drvArgs.InputBufferSize  != sizeof(gcsHAL_PROFILER_INTERFACE))
+        ||  (drvArgs.OutputBufferSize != sizeof(gcsHAL_PROFILER_INTERFACE))
+        )
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): input or/and output structures are invalid.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        copyLen = copy_from_user(
+            &iface_profiler, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_PROFILER_INTERFACE)
+            );
+
+        if (copyLen != 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of input HAL interface.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        status = gckDEVICE_Profiler_Dispatch(device->device, &iface_profiler);
+
+        /* Redo system call after pending signal is handled. */
+        if (status == gcvSTATUS_INTERRUPTED)
+        {
+            ret = -ERESTARTSYS;
+            gcmkONERROR(status);
+        }
+
+        /* Copy data back to the user. */
+        copyLen = copy_to_user(
+            gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface_profiler, sizeof(gcsHAL_PROFILER_INTERFACE)
+            );
+
+        if (copyLen != 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): error copying of output HAL interface.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+#endif
+        break;
+
+    default:
+        gcmkTRACE_ZONE(
+            gcvLEVEL_ERROR, gcvZONE_DRIVER,
+            "%s(%d): unknown command %d\n",
+            __FUNCTION__, __LINE__,
+            ioctlCode
+            );
+
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    /* Success. */
+    ret = 0;
+
+OnError:
+    gcmkFOOTER();
+    return ret;
+}
+
+static struct file_operations driver_fops =
+{
+    .owner      = THIS_MODULE,
+    .open       = drv_open,
+    .release    = drv_release,
+    .unlocked_ioctl = drv_ioctl,
+#ifdef HAVE_COMPAT_IOCTL
+    .compat_ioctl = drv_ioctl,
+#endif
+};
+
+static struct miscdevice gal_device = {
+    .minor = MISC_DYNAMIC_MINOR,
+    .name  = DEVICE_NAME,
+    .fops  = &driver_fops,
+};
+
+static int drv_init(void)
+{
+    int result = -EINVAL;
+    gceSTATUS status;
+    gckGALDEVICE device = gcvNULL;
+    struct class* device_class = gcvNULL;
+
+    gcmkHEADER();
+
+    printk(KERN_INFO "Galcore version %s\n", gcvVERSION_STRING);
+
+    if (showArgs)
+    {
+        gckOS_DumpParam();
+    }
+
+    /* Create the GAL device. */
+    status = gckGALDEVICE_Construct(platform, &moduleParam, &device);
+
+    if (gcmIS_ERROR(status))
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                       "%s(%d): Failed to create the GAL device: status=%d\n",
+                       __FUNCTION__, __LINE__, status);
+
+        goto OnError;
+    }
+
+    /* Start the GAL device. */
+    gcmkONERROR(gckGALDEVICE_Start(device));
+
+    if ((physSize != 0)
+       && (device->kernels[gcvCORE_MAJOR] != gcvNULL)
+       && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0))
+    {
+        /* Reset the base address */
+        device->baseAddress = 0;
+    }
+
+    /* Set global galDevice pointer. */
+    galDevice = device;
+
+    if (type == 1)
+    {
+        /* Register as misc driver. */
+        result = misc_register(&gal_device);
+
+        if (result < 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): misc_register fails.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+    else
+    {
+        /* Register the character device. */
+        result = register_chrdev(major, DEVICE_NAME, &driver_fops);
+
+        if (result < 0)
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): Could not allocate major number for mmap.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        if (major == 0)
+        {
+            major = result;
+        }
+
+        /* Create the device class. */
+        device_class = class_create(THIS_MODULE, CLASS_NAME);
+
+        if (IS_ERR(device_class))
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_DRIVER,
+                "%s(%d): Failed to create the class.\n",
+                __FUNCTION__, __LINE__
+                );
+
+            gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+        }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+        device_create(device_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
+#else
+        device_create(device_class, NULL, MKDEV(major, 0), DEVICE_NAME);
+#endif
+
+        gpuClass  = device_class;
+    }
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_DRIVER,
+        "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n",
+        __FUNCTION__, __LINE__,
+        irqLine, contiguousSize, registerMemBase
+        );
+
+    /* Success. */
+    gcmkFOOTER();
+    return 0;
+
+OnError:
+    /* Roll back. */
+    if (device_class)
+    {
+        device_destroy(device_class, MKDEV(major, 0));
+        class_destroy(device_class);
+    }
+
+    if (result < 0)
+    {
+        if (type == 1)
+        {
+            misc_deregister(&gal_device);
+        }
+        else
+        {
+            unregister_chrdev(result, DEVICE_NAME);
+        }
+    }
+    if (device)
+    {
+        gcmkVERIFY_OK(gckGALDEVICE_Stop(device));
+        gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
+    }
+
+    galcore_device->dma_mask = NULL;
+    galcore_device = NULL;
+
+    gcmkFOOTER();
+    return result;
+}
+
+static void drv_exit(void)
+{
+    gcmkHEADER();
+
+    if (type == 1)
+    {
+        misc_deregister(&gal_device);
+    }
+    else
+    {
+        gcmkASSERT(gpuClass != gcvNULL);
+        device_destroy(gpuClass, MKDEV(major, 0));
+        class_destroy(gpuClass);
+
+        unregister_chrdev(major, DEVICE_NAME);
+    }
+
+    gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice));
+    gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice));
+
+    gcmkFOOTER_NO();
+}
+
+#if gcdENABLE_DRM
+int viv_drm_probe(struct device *dev);
+int viv_drm_remove(struct device *dev);
+#endif
+
+struct device *galcore_device = NULL;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+static int gpu_probe(struct platform_device *pdev)
+#else
+static int __devinit gpu_probe(struct platform_device *pdev)
+#endif
+{
+    int ret = -ENODEV;
+    bool getPowerFlag = gcvFALSE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+    static u64 dma_mask = DMA_BIT_MASK(40);
+#else
+    static u64 dma_mask = DMA_40BIT_MASK;
+#endif
+
+#if gcdCAPTURE_ONLY_MODE
+    gctPHYS_ADDR_T contiguousBaseCap = 0;
+    gctSIZE_T contiguousSizeCap = 0;
+    gctPHYS_ADDR_T sRAMBaseCap[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    gctUINT32 sRAMSizeCap[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    gctPHYS_ADDR_T extSRAMBaseCap[gcvSRAM_EXT_COUNT];
+    gctUINT32 extSRAMSizeCap[gcvSRAM_EXT_COUNT];
+    gctUINT i = 0, j = 0;
+#endif
+
+    gcmkHEADER();
+
+    platform->device = pdev;
+    galcore_device = &pdev->dev;
+
+    galcore_device->dma_mask = &dma_mask;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+    galcore_device->coherent_dma_mask = dma_mask;
+#endif
+
+    if (platform->ops->getPower)
+    {
+        if (gcmIS_ERROR(platform->ops->getPower(platform)))
+        {
+            gcmkFOOTER_NO();
+            return ret;
+        }
+        getPowerFlag = gcvTRUE;
+    }
+
+    /* Gather module parameters. */
+    _InitModuleParam(&moduleParam);
+
+#if gcdCAPTURE_ONLY_MODE
+    contiguousBaseCap = moduleParam.contiguousBase;
+    contiguousSizeCap = moduleParam.contiguousSize;
+
+    gcmkPRINT("Capture only mode is enabled in Hal Kernel.");
+
+    if ((contiguousBaseCap + contiguousSizeCap) > 0x80000000)
+    {
+        gcmkPRINT("Capture only mode: contiguousBase + contiguousSize > 2G, there is error in CModel and old MMU version RTL simulation.");
+    }
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            sRAMBaseCap[i][j] = moduleParam.sRAMBases[i][j];
+            sRAMSizeCap[i][j] = moduleParam.sRAMSizes[i][j];
+        }
+    }
+
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        extSRAMBaseCap[i] = moduleParam.extSRAMBases[i];
+        extSRAMSizeCap[i] = moduleParam.extSRAMSizes[i];
+    }
+#endif
+
+    if (platform->ops->adjustParam)
+    {
+        /* Override default module param. */
+        platform->ops->adjustParam(platform, &moduleParam);
+    }
+
+#if gcdCAPTURE_ONLY_MODE
+    moduleParam.contiguousBase = contiguousBaseCap;
+    moduleParam.contiguousSize = contiguousSizeCap;
+
+    for (i = 0; i < gcvCORE_COUNT; i++)
+    {
+        for (j = 0; j < gcvSRAM_INTER_COUNT; j++)
+        {
+            moduleParam.sRAMBases[i][j] = sRAMBaseCap[i][j];
+            moduleParam.sRAMSizes[i][j] = sRAMSizeCap[i][j];
+        }
+    }
+
+    for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        moduleParam.extSRAMBases[i] = extSRAMBaseCap[i];
+        moduleParam.extSRAMSizes[i] = extSRAMSizeCap[i];
+    }
+#endif
+    /* Update module param because drv_init() uses them directly. */
+    _SyncModuleParam(&moduleParam);
+
+    if (powerManagement == 0)
+    {
+        gcmkPRINT("[galcore warning]: power saveing is disabled.");
+    }
+
+    ret = drv_init();
+
+    if (!ret)
+    {
+        platform_set_drvdata(pdev, galDevice);
+
+#if gcdENABLE_DRM
+        ret = viv_drm_probe(&pdev->dev);
+#endif
+    }
+
+    if (ret < 0)
+    {
+        if(platform->ops->putPower)
+        {
+            if(getPowerFlag == gcvTRUE)
+            {
+                platform->ops->putPower(platform);
+            }
+        }
+
+        gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
+    }
+    else
+    {
+        gcmkFOOTER_NO();
+    }
+
+    gcmkFOOTER_ARG(KERN_INFO "Success ret=%d", ret);
+    return ret;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+static int gpu_remove(struct platform_device *pdev)
+#else
+ static int __devexit gpu_remove(struct platform_device *pdev)
+#endif
+{
+    gcmkHEADER();
+
+#if gcdENABLE_DRM
+    viv_drm_remove(&pdev->dev);
+#endif
+
+    drv_exit();
+
+    if (platform->ops->putPower)
+    {
+        platform->ops->putPower(platform);
+    }
+
+    galcore_device->dma_mask = NULL;
+    galcore_device = NULL;
+    gcmkFOOTER_NO();
+    return 0;
+}
+
+static int gpu_suspend(struct platform_device *dev, pm_message_t state)
+{
+    gceSTATUS status;
+    gckGALDEVICE device;
+    gctINT i;
+
+    device = platform_get_drvdata(dev);
+
+    if (!device)
+    {
+        return -1;
+    }
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (device->kernels[i] != gcvNULL)
+        {
+            /* Store states. */
+#if gcdENABLE_VG
+            if (i == gcvCORE_VG)
+            {
+                status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
+            }
+            else
+#endif
+            {
+                status = gckHARDWARE_QueryPowerState(device->kernels[i]->hardware, &device->statesStored[i]);
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                return -1;
+            }
+
+            /* need pull up power to flush gpu command buffer before suspend */
+#if gcdENABLE_VG
+            if (i == gcvCORE_VG)
+            {
+                status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
+            }
+            else
+#endif
+            {
+                status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_ON);
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                return -1;
+            }
+
+#if gcdENABLE_VG
+            if (i == gcvCORE_VG)
+            {
+                status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
+            }
+            else
+#endif
+            {
+                status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_OFF);
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                return -1;
+            }
+
+        }
+    }
+
+    return 0;
+}
+
+static int gpu_resume(struct platform_device *dev)
+{
+    gceSTATUS status;
+    gckGALDEVICE device;
+    gctINT i;
+    gceCHIPPOWERSTATE   statesStored;
+
+    device = platform_get_drvdata(dev);
+
+    if (!device)
+    {
+        return -1;
+    }
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+    {
+        if (device->kernels[i] != gcvNULL)
+        {
+#if gcdENABLE_VG
+            if (i == gcvCORE_VG)
+            {
+                status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
+            }
+            else
+#endif
+            {
+                status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, gcvPOWER_ON);
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                return -1;
+            }
+
+            /* Convert global state to crossponding internal state. */
+            switch(device->statesStored[i])
+            {
+            case gcvPOWER_ON:
+                statesStored = gcvPOWER_ON_AUTO;
+                break;
+            case gcvPOWER_IDLE:
+                statesStored = gcvPOWER_IDLE_BROADCAST;
+                break;
+            case gcvPOWER_SUSPEND:
+                statesStored = gcvPOWER_SUSPEND_BROADCAST;
+                break;
+            case gcvPOWER_OFF:
+                statesStored = gcvPOWER_OFF_BROADCAST;
+                break;
+            default:
+                statesStored = device->statesStored[i];
+                break;
+            }
+
+            /* Restore states. */
+#if gcdENABLE_VG
+            if (i == gcvCORE_VG)
+            {
+                status = gckVGHARDWARE_SetPowerState(device->kernels[i]->vg->hardware, statesStored);
+            }
+            else
+#endif
+            {
+                gctINT j = 0;
+
+                for (; j < 100; j++)
+                {
+                    status = gckHARDWARE_SetPowerState(device->kernels[i]->hardware, statesStored);
+
+                    if (( statesStored != gcvPOWER_OFF_BROADCAST
+                       && statesStored != gcvPOWER_SUSPEND_BROADCAST)
+                       || status != gcvSTATUS_CHIP_NOT_READY)
+                    {
+                        break;
+                    }
+
+                    gcmkVERIFY_OK(gckOS_Delay(device->kernels[i]->os, 10));
+                };
+            }
+
+            if (gcmIS_ERROR(status))
+            {
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+#if defined(CONFIG_PM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+#ifdef CONFIG_PM_SLEEP
+static int gpu_system_suspend(struct device *dev)
+{
+    pm_message_t state={0};
+    return gpu_suspend(to_platform_device(dev), state);
+}
+
+static int gpu_system_resume(struct device *dev)
+{
+    return gpu_resume(to_platform_device(dev));
+}
+#endif
+
+static const struct dev_pm_ops gpu_pm_ops = {
+    SET_SYSTEM_SLEEP_PM_OPS(gpu_system_suspend, gpu_system_resume)
+};
+#endif
+
+static struct platform_driver gpu_driver = {
+    .probe      = gpu_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+    .remove     = gpu_remove,
+#else
+    .remove     = __devexit_p(gpu_remove),
+#endif
+
+    .suspend    = gpu_suspend,
+    .resume     = gpu_resume,
+
+    .driver     = {
+        .owner = THIS_MODULE,
+        .name   = DEVICE_NAME,
+#if defined(CONFIG_PM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+        .pm     = &gpu_pm_ops,
+#endif
+    }
+};
+
+static int __init gpu_init(void)
+{
+    int ret = 0;
+
+    ret = gckPLATFORM_Init(&gpu_driver, &platform);
+
+    if (ret || !platform)
+    {
+        printk(KERN_ERR "galcore: Soc platform init failed.\n");
+        return -ENODEV;
+    }
+
+    ret = platform_driver_register(&gpu_driver);
+
+    if (ret)
+    {
+        printk(KERN_ERR "galcore: gpu_init() failed to register driver!\n");
+        gckPLATFORM_Terminate(platform);
+        platform = NULL;
+        return -ENODEV;
+    }
+
+    platform->driver = &gpu_driver;
+    return 0;
+}
+
+static void __exit gpu_exit(void)
+{
+    platform_driver_unregister(&gpu_driver);
+
+    gckPLATFORM_Terminate(platform);
+    platform = NULL;
+}
+
+module_init(gpu_init);
+
+module_exit(gpu_exit);
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
@@ -0,0 +1,878 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#if gcdENABLE_DRM
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_ioctl.h>
+#else
+#include <drm/drmP.h>
+#endif
+#include <drm/drm_gem.h>
+#include <linux/dma-buf.h>
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_drm.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+/******************************************************************************\
+******************************* gckKERNEL DRM Code ******************************
+\******************************************************************************/
+
+struct viv_gem_object {
+    struct drm_gem_object base;
+
+    uint32_t              node_handle;
+    gckVIDMEM_NODE        node_object;
+    gctBOOL               cacheable;
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
+struct dma_buf *viv_gem_prime_export(struct drm_gem_object *gem_obj,
+                int flags)
+{
+    struct drm_device *drm = gem_obj->dev;
+#else
+struct dma_buf *viv_gem_prime_export(struct drm_device *drm,
+                struct drm_gem_object *gem_obj,
+                int flags)
+{
+#endif
+    struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    struct dma_buf *dmabuf = gcvNULL;
+    gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+    if (gal_dev)
+    {
+        gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+        gcmkVERIFY_OK(gckVIDMEM_NODE_Export(kernel, viv_obj->node_object, flags,
+                                            (gctPOINTER*)&dmabuf, gcvNULL));
+    }
+
+    return dmabuf;
+}
+
+struct drm_gem_object *viv_gem_prime_import(struct drm_device *drm,
+                                            struct dma_buf *dmabuf)
+{
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj;
+
+    gcsHAL_INTERFACE iface;
+    gckGALDEVICE gal_dev;
+    gckKERNEL kernel;
+    gctUINT32 processID;
+    gckVIDMEM_NODE nodeObject;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gckOS_ZeroMemory(&iface, sizeof(iface));
+    iface.command = gcvHAL_WRAP_USER_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.WrapUserMemory.desc.flag = gcvALLOC_FLAG_DMABUF;
+    iface.u.WrapUserMemory.desc.handle = -1;
+    iface.u.WrapUserMemory.desc.dmabuf = gcmPTR_TO_UINT64(dmabuf);
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+    kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.WrapUserMemory.node, &nodeObject));
+
+    /* ioctl output */
+    gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+    drm_gem_private_object_init(drm, gem_obj, dmabuf->size);
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    viv_obj->node_handle = iface.u.WrapUserMemory.node;
+    viv_obj->node_object = nodeObject;
+
+OnError:
+    return gem_obj;
+}
+
+void viv_gem_free_object(struct drm_gem_object *gem_obj)
+{
+    struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    struct drm_device *drm = gem_obj->dev;
+
+    gcsHAL_INTERFACE iface;
+    gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+    gckOS_ZeroMemory(&iface, sizeof(iface));
+    iface.command = gcvHAL_RELEASE_VIDEO_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.ReleaseVideoMemory.node = viv_obj->node_handle;
+    gcmkVERIFY_OK(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+    drm_gem_object_release(gem_obj);
+    kfree(gem_obj);
+}
+
+static int viv_ioctl_gem_create(struct drm_device *drm, void *data,
+                                struct drm_file *file)
+{
+    int ret = 0;
+    struct drm_viv_gem_create *args = (struct drm_viv_gem_create*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gcsHAL_INTERFACE iface;
+    gckGALDEVICE gal_dev;
+    gckKERNEL kernel;
+    gctUINT32 processID;
+    gckVIDMEM_NODE nodeObject;
+    gctUINT32 flags = gcvALLOC_FLAG_DMABUF_EXPORTABLE;
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT64 alignSize = PAGE_ALIGN(args->size);
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (args->flags & DRM_VIV_GEM_CONTIGUOUS)
+    {
+        flags |= gcvALLOC_FLAG_CONTIGUOUS;
+    }
+    if (args->flags & DRM_VIV_GEM_CACHED)
+    {
+        flags |= gcvALLOC_FLAG_CACHEABLE;
+    }
+    if (args->flags & DRM_VIV_GEM_SECURE)
+    {
+        flags |= gcvALLOC_FLAG_SECURITY;
+    }
+    if (args->flags & DRM_VIV_GEM_CMA_LIMIT)
+    {
+        flags |= gcvALLOC_FLAG_CMA_LIMIT;
+    }
+
+    gckOS_ZeroMemory(&iface, sizeof(iface));
+    iface.command = gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.AllocateLinearVideoMemory.bytes = alignSize;
+    iface.u.AllocateLinearVideoMemory.alignment = 256;
+    iface.u.AllocateLinearVideoMemory.type = gcvVIDMEM_TYPE_GENERIC;
+    iface.u.AllocateLinearVideoMemory.flag = flags;
+    iface.u.AllocateLinearVideoMemory.pool = gcvPOOL_DEFAULT;
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+    kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+    gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.AllocateLinearVideoMemory.node, &nodeObject));
+
+    /* ioctl output */
+    gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+    drm_gem_private_object_init(drm, gem_obj, (size_t)alignSize);
+    ret = drm_gem_handle_create(file, gem_obj, &args->handle);
+
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    viv_obj->node_handle = iface.u.AllocateLinearVideoMemory.node;
+    viv_obj->node_object = nodeObject;
+    viv_obj->cacheable = flags & gcvALLOC_FLAG_CACHEABLE;
+
+    /* drop reference from allocate - handle holds it now */
+    drm_gem_object_unreference_unlocked(gem_obj);
+
+OnError:
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_lock(struct drm_device *drm, void *data,
+                              struct drm_file *file)
+{
+    struct drm_viv_gem_lock *args = (struct drm_viv_gem_lock*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gcsHAL_INTERFACE iface;
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    gckOS_ZeroMemory(&iface, sizeof(iface));
+    iface.command = gcvHAL_LOCK_VIDEO_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.LockVideoMemory.node = viv_obj->node_handle;
+    iface.u.LockVideoMemory.cacheable = args->cacheable;
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+    args->logical = iface.u.LockVideoMemory.memory;
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_unlock(struct drm_device *drm, void *data,
+                                struct drm_file *file)
+{
+    struct drm_viv_gem_unlock *args = (struct drm_viv_gem_unlock*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gcsHAL_INTERFACE iface;
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    memset(&iface, 0, sizeof(iface));
+    iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.UnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+    iface.u.UnlockVideoMemory.type = gcvVIDMEM_TYPE_GENERIC;
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+    memset(&iface, 0, sizeof(iface));
+    iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+    iface.u.BottomHalfUnlockVideoMemory.type = gcvVIDMEM_TYPE_GENERIC;
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_cache(struct drm_device *drm, void *data,
+                               struct drm_file *file)
+{
+    struct drm_viv_gem_cache *args = (struct drm_viv_gem_cache*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gcsHAL_INTERFACE iface;
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+    gceCACHEOPERATION cache_op = 0;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    switch (args->op)
+    {
+    case DRM_VIV_GEM_CLEAN_CACHE:
+        cache_op = gcvCACHE_CLEAN;
+        break;
+    case DRM_VIV_GEM_INVALIDATE_CACHE:
+        cache_op = gcvCACHE_INVALIDATE;
+        break;
+    case DRM_VIV_GEM_FLUSH_CACHE:
+        cache_op = gcvCACHE_FLUSH;
+        break;
+    case DRM_VIV_GEM_MEMORY_BARRIER:
+        cache_op = gcvCACHE_MEMORY_BARRIER;
+        break;
+    default:
+        break;
+    }
+
+    gckOS_ZeroMemory(&iface, sizeof(iface));
+    iface.command = gcvHAL_CACHE;
+    iface.hardwareType = gal_dev->device->defaultHwType;
+    iface.u.Cache.node       = viv_obj->node_handle;
+    iface.u.Cache.operation  = cache_op;
+    iface.u.Cache.logical    = args->logical;
+    iface.u.Cache.bytes      = args->bytes;
+    gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_query(struct drm_device *drm, void *data,
+                               struct drm_file *file)
+{
+    struct drm_viv_gem_query *args = (struct drm_viv_gem_query*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    switch (args->param)
+    {
+    case DRM_VIV_GEM_PARAM_POOL:
+        args->value = (__u64)viv_obj->node_object->pool;
+        break;
+    case DRM_VIV_GEM_PARAM_SIZE:
+        args->value = (__u64)gem_obj->size;
+        break;
+    default:
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_timestamp(struct drm_device *drm, void *data,
+                                       struct drm_file *file)
+{
+    struct drm_viv_gem_timestamp *args = (struct drm_viv_gem_timestamp *)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    viv_obj->node_object->timeStamp += args->inc;
+    args->timestamp = viv_obj->node_object->timeStamp;
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_set_tiling(struct drm_device *drm, void *data,
+                                    struct drm_file *file)
+{
+    struct drm_viv_gem_set_tiling *args = (struct drm_viv_gem_set_tiling*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    viv_obj->node_object->tilingMode    = args->tiling_mode;
+    viv_obj->node_object->tsMode        = args->ts_mode;
+    viv_obj->node_object->tsCacheMode   = args->ts_cache_mode;
+    viv_obj->node_object->clearValue    = args->clear_value;
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_get_tiling(struct drm_device *drm, void *data,
+                                  struct drm_file *file)
+{
+    struct drm_viv_gem_get_tiling *args = (struct drm_viv_gem_get_tiling*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+    args->tiling_mode   = viv_obj->node_object->tilingMode;
+    args->ts_mode       = viv_obj->node_object->tsMode;
+    args->ts_cache_mode = viv_obj->node_object->tsCacheMode;
+    args->clear_value   = viv_obj->node_object->clearValue;
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_attach_aux(struct drm_device *drm, void *data,
+                                    struct drm_file *file)
+{
+    struct drm_viv_gem_attach_aux *args = (struct drm_viv_gem_attach_aux*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+    struct drm_gem_object *gem_ts_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+    gckVIDMEM_NODE nodeObj = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    nodeObj = viv_obj->node_object;
+
+    /* do not support re-attach */
+    if (nodeObj->tsNode)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (args->ts_handle)
+    {
+        struct viv_gem_object *viv_ts_obj;
+        gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+        gcsHAL_INTERFACE iface;
+        gctBOOL is128BTILE = gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_128BTILE);
+        gctBOOL is2BitPerTile = is128BTILE ? gcvFALSE : gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_TILE_STATUS_2BITS);
+        gctBOOL isCompressionDEC400 = gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_COMPRESSION_DEC400);
+        gctPOINTER entry = gcvNULL;
+        gckVIDMEM_NODE ObjNode = gcvNULL;
+        gctUINT32 processID = 0;
+        gctUINT32 tileStatusFiller = (isCompressionDEC400 || ((kernel->hardware->identity.chipModel == gcv500) && (kernel->hardware->identity.chipRevision > 2)))
+                                  ? 0xFFFFFFFF
+                                  : is2BitPerTile ? 0x55555555 : 0x11111111;
+
+        gem_ts_obj = drm_gem_object_lookup(file, args->ts_handle);
+        if (!gem_ts_obj)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_FOUND);
+        }
+        viv_ts_obj = container_of(gem_ts_obj, struct viv_gem_object, base);
+
+        gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, viv_ts_obj->node_object));
+        nodeObj->tsNode = viv_ts_obj->node_object;
+
+        /* Fill tile status node with tileStatusFiller value first time to avoid GPU hang. */
+        /* Lock tile status node. */
+        gckOS_ZeroMemory(&iface, sizeof(iface));
+        iface.command = gcvHAL_LOCK_VIDEO_MEMORY;
+        iface.hardwareType = gal_dev->device->defaultHwType;
+        iface.u.LockVideoMemory.node = viv_ts_obj->node_handle;
+        iface.u.LockVideoMemory.cacheable = viv_ts_obj->cacheable;
+        gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+        gcmkONERROR(gckOS_GetProcessID(&processID));
+        gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, viv_ts_obj->node_handle, &ObjNode));
+        gcmkONERROR(gckVIDMEM_NODE_LockCPU(kernel, ObjNode, gcvFALSE, gcvFALSE, &entry));
+
+        /* Fill tile status node with tileStatusFiller. */
+        memset(entry , tileStatusFiller , (__u64)gem_ts_obj->size);
+        gcmkONERROR(gckVIDMEM_NODE_UnlockCPU(kernel, ObjNode, 0, gcvFALSE, gcvFALSE));
+
+        /* UnLock tile status node. */
+        memset(&iface, 0, sizeof(iface));
+        iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
+        iface.hardwareType = gal_dev->device->defaultHwType;
+        iface.u.UnlockVideoMemory.node = (gctUINT64)viv_ts_obj->node_handle;
+        iface.u.UnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+        gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+        memset(&iface, 0, sizeof(iface));
+        iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY;
+        iface.hardwareType = gal_dev->device->defaultHwType;
+        iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_ts_obj->node_handle;
+        iface.u.BottomHalfUnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+        gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+    }
+
+OnError:
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+
+        if (gem_ts_obj)
+        {
+            drm_gem_object_unreference_unlocked(gem_ts_obj);
+        }
+    }
+    return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_ref_node(struct drm_device *drm, void *data,
+                                 struct drm_file *file)
+{
+    struct drm_viv_gem_ref_node *args = (struct drm_viv_gem_ref_node*)data;
+    struct drm_gem_object *gem_obj = gcvNULL;
+    struct viv_gem_object *viv_obj = gcvNULL;
+
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+    gckKERNEL kernel = gcvNULL;
+    gctUINT32 processID;
+    gckVIDMEM_NODE nodeObj;
+    gctUINT32 nodeHandle = 0, tsNodeHandle = 0;
+    gctBOOL refered = gcvFALSE;
+    int ret = 0;
+
+    gal_dev = (gckGALDEVICE)drm->dev_private;
+    if (!gal_dev)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+    kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+
+    gem_obj = drm_gem_object_lookup(file, args->handle);
+    if (!gem_obj)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+    nodeObj = viv_obj->node_object;
+
+    gcmkONERROR(gckOS_GetProcessID(&processID));
+    gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj, &nodeHandle));
+    gcmkONERROR(
+        gckKERNEL_AddProcessDB(kernel,
+                               processID, gcvDB_VIDEO_MEMORY,
+                               gcmINT2PTR(nodeHandle),
+                               gcvNULL,
+                               0));
+    gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj));
+    refered = gcvTRUE;
+
+    if (nodeObj->tsNode)
+    {
+        gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj->tsNode, &tsNodeHandle));
+        gcmkONERROR(
+            gckKERNEL_AddProcessDB(kernel,
+                                   processID, gcvDB_VIDEO_MEMORY,
+                                   gcmINT2PTR(tsNodeHandle),
+                                   gcvNULL,
+                                   0));
+        gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj->tsNode));
+    }
+    args->node = nodeHandle;
+    args->ts_node = tsNodeHandle;
+
+OnError:
+    if (gcmIS_ERROR(status) && kernel)
+    {
+        gctUINT32 processID;
+
+        gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
+
+        if (tsNodeHandle)
+        {
+            gckVIDMEM_HANDLE_Dereference(kernel, processID, tsNodeHandle);
+        }
+
+        if (nodeHandle)
+        {
+            gckVIDMEM_HANDLE_Dereference(kernel, processID, nodeHandle);
+        }
+
+        if (refered)
+        {
+            gcmkONERROR(gckVIDMEM_NODE_Dereference(kernel, nodeObj));
+        }
+
+        args->node = 0;
+        args->ts_node = 0;
+
+        ret = -ENOTTY;
+    }
+
+    if (gem_obj)
+    {
+        drm_gem_object_unreference_unlocked(gem_obj);
+    }
+
+    return ret;
+}
+
+static const struct drm_ioctl_desc viv_ioctls[] =
+{
+    DRM_IOCTL_DEF_DRV(VIV_GEM_CREATE,        viv_ioctl_gem_create,     DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_LOCK,          viv_ioctl_gem_lock,       DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_UNLOCK,        viv_ioctl_gem_unlock,     DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_CACHE,         viv_ioctl_gem_cache,      DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_QUERY,         viv_ioctl_gem_query,      DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_TIMESTAMP,     viv_ioctl_gem_timestamp,  DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_SET_TILING,    viv_ioctl_gem_set_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_GET_TILING,    viv_ioctl_gem_get_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_ATTACH_AUX,    viv_ioctl_gem_attach_aux, DRM_AUTH | DRM_RENDER_ALLOW),
+    DRM_IOCTL_DEF_DRV(VIV_GEM_REF_NODE,      viv_ioctl_gem_ref_node,   DRM_AUTH | DRM_RENDER_ALLOW),
+};
+
+int viv_drm_open(struct drm_device *drm, struct drm_file *file)
+{
+    gctINT i;
+    gctUINT32 pid = _GetProcessID();
+    gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+    {
+        if (gal_dev->kernels[i])
+        {
+            gcmkONERROR(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvTRUE, pid));
+        }
+    }
+    file->driver_priv = gcmINT2PTR(pid);
+
+OnError:
+    return gcmIS_ERROR(status) ? -ENODEV :  0;
+}
+
+void viv_drm_postclose(struct drm_device *drm, struct drm_file *file)
+{
+    gctINT i;
+    gctUINT32 pid = gcmPTR2SIZE(file->driver_priv);
+    gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+    for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+    {
+        if (gal_dev->kernels[i])
+        {
+            gcmkVERIFY_OK(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvFALSE, pid));
+        }
+    }
+}
+
+static const struct file_operations viv_drm_fops = {
+    .owner              = THIS_MODULE,
+    .open               = drm_open,
+    .release            = drm_release,
+    .unlocked_ioctl     = drm_ioctl,
+#ifdef CONFIG_COMPAT
+    .compat_ioctl       = drm_compat_ioctl,
+#endif
+    .poll               = drm_poll,
+    .read               = drm_read,
+    .llseek             = no_llseek,
+};
+
+static struct drm_driver viv_drm_driver = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
+    .driver_features    = DRIVER_GEM | DRIVER_RENDER,
+#else
+    .driver_features    = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER,
+#endif
+    .open = viv_drm_open,
+    .postclose = viv_drm_postclose,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
+    .gem_free_object_unlocked = viv_gem_free_object,
+#else
+    .gem_free_object    = viv_gem_free_object,
+#endif
+    .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+    .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+    .gem_prime_export   = viv_gem_prime_export,
+    .gem_prime_import   = viv_gem_prime_import,
+    .ioctls             = viv_ioctls,
+    .num_ioctls         = DRM_VIV_NUM_IOCTLS,
+    .fops               = &viv_drm_fops,
+    .name               = "vivante",
+    .desc               = "vivante DRM",
+    .date               = "20170808",
+    .major              = 1,
+    .minor              = 0,
+};
+
+int viv_drm_probe(struct device *dev)
+{
+    int ret = 0;
+    gceSTATUS status = gcvSTATUS_OK;
+    gckGALDEVICE gal_dev = gcvNULL;
+    struct drm_device *drm = gcvNULL;
+
+    gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+    if (!gal_dev)
+    {
+        ret = -ENODEV;
+        gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+    }
+
+    drm = drm_dev_alloc(&viv_drm_driver, dev);
+    if (IS_ERR(drm))
+    {
+        ret = PTR_ERR(drm);
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+    drm->dev_private = (void*)gal_dev;
+
+    ret = drm_dev_register(drm, 0);
+    if (ret)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    gal_dev->drm = (void*)drm;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        if (drm)
+        {
+            drm_dev_unref(drm);
+        }
+        printk(KERN_ERR "galcore: Failed to setup drm device.\n");
+    }
+    return ret;
+}
+
+int viv_drm_remove(struct device *dev)
+{
+    gckGALDEVICE gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+
+    if (gal_dev)
+    {
+        struct drm_device *drm = (struct drm_device*)gal_dev->drm;
+
+        drm_dev_unregister(drm);
+        drm_dev_unref(drm);
+    }
+
+    return 0;
+}
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c
@@ -0,0 +1,236 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_device.h"
+
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+typedef struct _gcsIOMMU
+{
+    struct iommu_domain * domain;
+    struct device *       device;
+}
+gcsIOMMU;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+static int
+_IOMMU_Fault_Handler(
+    struct iommu_domain * Domain,
+    struct device * Dev,
+    unsigned long DomainAddress,
+    int flags,
+    void * args
+    )
+#else
+static int
+_IOMMU_Fault_Handler(
+    struct iommu_domain * Domain,
+    struct device * Dev,
+    unsigned long DomainAddress,
+    int flags
+    )
+#endif
+{
+    return 0;
+}
+
+static int
+_FlatMapping(
+    IN gckIOMMU Iommu
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gctUINT32 physical;
+
+    gcmkHEADER_ARG("Iommu=%p", Iommu);
+
+    for (physical = 0; physical < 0x80000000; physical += PAGE_SIZE)
+    {
+        gcmkTRACE_ZONE(
+            gcvLEVEL_INFO, gcvZONE_OS,
+            "Map %x => %x bytes = %d",
+            physical, physical, PAGE_SIZE
+            );
+
+        gcmkONERROR(gckIOMMU_Map(Iommu, physical, physical, PAGE_SIZE));
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+void
+gckIOMMU_Destory(
+    IN gckOS Os,
+    IN gckIOMMU Iommu
+    )
+{
+    gcmkHEADER_ARG("Os=%p Iommu=%p", Os, Iommu);
+
+    if (Iommu->domain && Iommu->device)
+    {
+        iommu_attach_device(Iommu->domain, Iommu->device);
+    }
+
+    if (Iommu->domain)
+    {
+        iommu_domain_free(Iommu->domain);
+    }
+
+    if (Iommu)
+    {
+        gcmkOS_SAFE_FREE(Os, Iommu);
+    }
+
+    gcmkFOOTER_NO();
+}
+
+gceSTATUS
+gckIOMMU_Construct(
+    IN gckOS Os,
+    OUT gckIOMMU * Iommu
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gckIOMMU iommu = gcvNULL;
+    struct device *dev;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    dev = &Os->device->platform->device->dev;
+
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsIOMMU), (gctPOINTER *)&iommu));
+
+    gckOS_ZeroMemory(iommu, gcmSIZEOF(gcsIOMMU));
+
+    iommu->domain = iommu_domain_alloc(&platform_bus_type);
+
+    if (!iommu->domain)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "iommu_domain_alloc() fail");
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    iommu_set_fault_handler(iommu->domain, _IOMMU_Fault_Handler, dev);
+#else
+    iommu_set_fault_handler(iommu->domain, _IOMMU_Fault_Handler);
+#endif
+
+    if (iommu_attach_device(iommu->domain, dev))
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "iommu_attach_device() fail");
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    iommu->device = dev;
+
+    _FlatMapping(iommu);
+
+    *Iommu = iommu;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        gckIOMMU_Destory(Os, iommu);
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckIOMMU_Map(
+    IN gckIOMMU Iommu,
+    IN gctUINT32 DomainAddress,
+    IN gctUINT32 Physical,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("DomainAddress=%#X, Physical=%#X, Bytes=%d",
+                   DomainAddress, Physical, Bytes);
+
+    if (iommu_map(Iommu->domain, DomainAddress, Physical, Bytes, 0))
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckIOMMU_Unmap(
+    IN gckIOMMU Iommu,
+    IN gctUINT32 DomainAddress,
+    IN gctUINT32 Bytes
+    )
+{
+    gcmkHEADER();
+
+    iommu_unmap(Iommu->domain, DomainAddress, Bytes);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c
@@ -0,0 +1,689 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_KERNEL
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckKERNEL_QueryVideoMemory
+**
+**  Query the amount of video memory.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**  OUTPUT:
+**
+**      gcsHAL_INTERFACE * Interface
+**          Pointer to an gcsHAL_INTERFACE structure that will be filled in with
+**          the memory information.
+*/
+gceSTATUS
+gckKERNEL_QueryVideoMemory(
+    IN gckKERNEL Kernel,
+    OUT gcsHAL_INTERFACE * Interface
+    )
+{
+    gckGALDEVICE device;
+
+    gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Interface != NULL);
+
+    /* Extract the pointer to the gckGALDEVICE class. */
+    device = (gckGALDEVICE) Kernel->context;
+
+    /* Get internal memory size and physical address. */
+    Interface->u.QueryVideoMemory.internalSize = device->internalSize;
+    Interface->u.QueryVideoMemory.internalPhysName = device->internalPhysName;
+
+    /* Get external memory size and physical address. */
+    Interface->u.QueryVideoMemory.externalSize = device->externalSize;
+    Interface->u.QueryVideoMemory.externalPhysName = device->externalPhysName;
+
+    /* Get contiguous memory size and physical address. */
+    Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize;
+    Interface->u.QueryVideoMemory.contiguousPhysName = device->contiguousPhysName;
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_GetVideoMemoryPool
+**
+**  Get the gckVIDMEM object belonging to the specified pool.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcePOOL Pool
+**          Pool to query gckVIDMEM object for.
+**
+**  OUTPUT:
+**
+**      gckVIDMEM * VideoMemory
+**          Pointer to a variable that will hold the pointer to the gckVIDMEM
+**          object belonging to the requested pool.
+*/
+gceSTATUS
+gckKERNEL_GetVideoMemoryPool(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    OUT gckVIDMEM * VideoMemory
+    )
+{
+    gckGALDEVICE device;
+    gckVIDMEM videoMemory;
+
+    gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(VideoMemory != NULL);
+
+    /* Extract the pointer to the gckGALDEVICE class. */
+    device = (gckGALDEVICE) Kernel->context;
+
+    /* Dispatch on pool. */
+    switch (Pool)
+    {
+    case gcvPOOL_LOCAL_INTERNAL:
+        /* Internal memory. */
+        videoMemory = device->internalVidMem;
+        break;
+
+    case gcvPOOL_LOCAL_EXTERNAL:
+        /* External memory. */
+        videoMemory = device->externalVidMem;
+        break;
+
+    case gcvPOOL_SYSTEM:
+        /* System memory. */
+        videoMemory = device->contiguousVidMem;
+        break;
+
+    case gcvPOOL_INTERNAL_SRAM:
+        /* Internal SRAM memory. */
+        videoMemory = Kernel->sRAMVidMem[Kernel->sRAMIndex];
+        break;
+
+    case gcvPOOL_EXTERNAL_SRAM:
+        /* External SRAM memory. */
+        videoMemory = device->extSRAMVidMem[Kernel->extSRAMIndex];
+        break;
+
+    default:
+        /* Unknown pool. */
+        videoMemory = NULL;
+    }
+
+    /* Return pointer to the gckVIDMEM object. */
+    *VideoMemory = videoMemory;
+
+    /* Return status. */
+    gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory);
+    return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_MapMemory
+**
+**  Map video memory into the current process space.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of video memory to map.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to map.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Logical
+**          Pointer to a variable that will hold the base address of the mapped
+**          memory region.
+*/
+gceSTATUS
+gckKERNEL_MapMemory(
+    IN gckKERNEL Kernel,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    )
+{
+    gckKERNEL kernel = Kernel;
+    gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical);
+
+    return gckOS_MapMemory(Kernel->os, physical, Bytes, Logical);
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_UnmapMemory
+**
+**  Unmap video memory from the current process space.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of video memory to map.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to map.
+**
+**      gctPOINTER Logical
+**          Base address of the mapped memory region.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_UnmapMemory(
+    IN gckKERNEL Kernel,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID
+    )
+{
+    gckKERNEL kernel = Kernel;
+    gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical);
+
+    return gckOS_UnmapMemoryEx(Kernel->os, physical, Bytes, Logical, ProcessID);
+}
+
+/****************************************************************************
+**
+**  gckKERNEL_DestroyProcessReservedUserMap
+**
+**  Destroy process reserved memory
+**
+**  INPUT:
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of video memory to map.
+**
+**      gctUINT32 Pid
+**          Process ID.
+*/
+gceSTATUS
+gckKERNEL_DestroyProcessReservedUserMap(
+    IN gckKERNEL Kernel,
+    IN gctUINT32 Pid
+    )
+{
+    gceSTATUS status      = gcvSTATUS_OK;
+    gckGALDEVICE device   = gcvNULL;
+    gctSIZE_T bytes       = 0;
+    gctPHYS_ADDR physHandle = gcvNULL;
+    /* when unmap reserved memory, we don't need real logical*/
+    gctPOINTER Logical = (gctPOINTER)0xFFFFFFFF;
+    gctINT i;
+    PLINUX_MDL mdl;
+    PLINUX_MDL_MAP mdlMap = gcvNULL;
+
+    gcmkHEADER_ARG("Logical=0x%08x pid=%u",
+                   Logical, Pid);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    /* Extract the pointer to the gckGALDEVICE class. */
+    device = (gckGALDEVICE) Kernel->context;
+
+    physHandle = (PLINUX_MDL)device->internalPhysical;
+    bytes = device->internalSize;
+    if (bytes)
+    {
+        mdl = physHandle;
+        mdlMap = FindMdlMap(mdl, Pid);
+        if (mdlMap)
+        {
+            gckOS_UnmapMemoryEx(Kernel->os, physHandle, bytes, Logical, Pid);
+        }
+    }
+
+    physHandle = (PLINUX_MDL)device->externalPhysical;
+    bytes = device->externalSize;
+    if (bytes)
+    {
+        mdl = physHandle;
+        mdlMap = FindMdlMap(mdl, Pid);
+        if (mdlMap)
+        {
+            gckOS_UnmapMemoryEx(Kernel->os, physHandle, bytes, Logical, Pid);
+        }
+    }
+
+    /* System memory. */
+    physHandle = (PLINUX_MDL)device->contiguousPhysical;
+    bytes = device->contiguousSize;
+    if (bytes)
+    {
+        mdl = physHandle;
+        mdlMap = FindMdlMap(mdl, Pid);
+        if (mdlMap)
+        {
+            gckOS_UnmapMemoryEx(Kernel->os, physHandle, bytes, Logical, Pid);
+        }
+    }
+
+    /* External shared SRAM memory. */
+    for(i = 0; i < gcvSRAM_EXT_COUNT; i++)
+    {
+        physHandle = (PLINUX_MDL)device->extSRAMPhysical[i];
+        bytes = device->extSRAMSizes[i];
+        if (bytes)
+        {
+            mdl = physHandle;
+            mdlMap = FindMdlMap(mdl, Pid);
+            if (mdlMap)
+            {
+                gckOS_UnmapMemoryEx(Kernel->os, physHandle, bytes, Logical, Pid);
+            }
+        }
+    }
+
+    /* Per core SRAM reserved usage. */
+    for(i = 0; i < gcvSRAM_INTER_COUNT; i++)
+    {
+        if (!Kernel->sRAMPhysFaked[i])
+        {
+            physHandle = (PLINUX_MDL)Kernel->sRAMPhysical[i];
+            bytes = Kernel->sRAMSizes[i];
+            if (bytes)
+            {
+                mdl = physHandle;
+                mdlMap = FindMdlMap(mdl, Pid);
+                if (mdlMap)
+                {
+                    gckOS_UnmapMemoryEx(Kernel->os, physHandle, bytes, Logical, Pid);
+                }
+            }
+        }
+    }
+
+    /* Retunn the status. */
+    gcmkFOOTER_NO();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_MapVideoMemory
+**
+**  Get the logical address for a hardware specific memory address for the
+**  current process.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gctBOOL InUserSpace
+**          gcvTRUE to map the memory into the user space.
+**
+**      gcePOOL Pool
+**          Specify pool type.
+**
+**      gctUINT32 Offset
+**          Offset to pool start.
+**
+**      gctUINT32 Bytes
+**          Number of bytes to map.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Logical
+**          Pointer to a variable that will hold the logical address of the
+**          specified memory address.
+*/
+gceSTATUS
+gckKERNEL_MapVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gctBOOL InUserSpace,
+    IN gcePOOL Pool,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 Offset,
+    IN gctUINT32 Bytes,
+    OUT gctPOINTER * Logical
+    )
+{
+    gckGALDEVICE device   = gcvNULL;
+    gctSIZE_T bytes       = 0;
+    gctPHYS_ADDR physHandle = gcvNULL;
+    gceSTATUS status      = gcvSTATUS_OK;
+    gctPOINTER logical    = gcvNULL;
+    gctUINT64 mappingInOne  = 1;
+
+    gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Pool=%d Offset=%X Bytes=%X",
+                   Kernel, InUserSpace, Pool, Offset, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+    gcmkVERIFY_ARGUMENT(Logical != NULL);
+
+    if (Physical)
+    {
+        gcmkONERROR(gckOS_QueryOption(Kernel->os, "allMapInOne", &mappingInOne));
+    }
+
+    if (mappingInOne)
+    {
+        /* Extract the pointer to the gckGALDEVICE class. */
+        device = (gckGALDEVICE) Kernel->context;
+
+        /* Dispatch on pool. */
+        switch (Pool)
+        {
+        case gcvPOOL_LOCAL_INTERNAL:
+            physHandle = (PLINUX_MDL)device->internalPhysical;
+            bytes = device->internalSize;
+            break;
+
+        case gcvPOOL_LOCAL_EXTERNAL:
+            physHandle = (PLINUX_MDL)device->externalPhysical;
+            bytes = device->externalSize;
+            break;
+
+        case gcvPOOL_SYSTEM:
+            /* System memory. */
+            physHandle = (PLINUX_MDL)device->contiguousPhysical;
+            bytes = device->contiguousSize;
+            break;
+
+        case gcvPOOL_EXTERNAL_SRAM:
+            /* External shared SRAM memory. */
+            physHandle = (PLINUX_MDL)device->extSRAMPhysical[Kernel->extSRAMIndex];
+            bytes = device->extSRAMSizes[Kernel->extSRAMIndex];
+            break;
+
+        case gcvPOOL_INTERNAL_SRAM:
+            /* Per core SRAM reserved usage. */
+            if (Kernel->sRAMPhysFaked[Kernel->sRAMIndex])
+            {
+                *Logical = gcvNULL;
+
+                gcmkFOOTER_NO();
+                return gcvSTATUS_OK;
+            }
+            /* Per core SRAM memory block. */
+            else
+            {
+                physHandle = (PLINUX_MDL)Kernel->sRAMPhysical[Kernel->sRAMIndex];
+                bytes = Kernel->sRAMSizes[Kernel->sRAMIndex];
+                break;
+            }
+
+        default:
+            /* Invalid memory pool. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+    }
+    else
+    {
+        physHandle = (PLINUX_MDL)Physical;
+        bytes = Bytes;
+        Offset = 0;
+    }
+
+    gcmkONERROR(gckOS_LockPages(Kernel->os, physHandle, bytes, gcvFALSE, &logical));
+    /* Build logical address of specified address. */
+    *Logical = (gctPOINTER)((gctUINT8_PTR)logical + Offset);
+OnError:
+    /* Retunn the status. */
+    gcmkFOOTER_ARG("*Logical=%p", gcmOPT_POINTER(Logical));
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckKERNEL_UnmapVideoMemory
+**
+**  Unmap video memory for the current process.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gcePOOL Pool
+**          Specify pool type.
+
+**      gctUINT32 Address
+**          Hardware specific memory address.
+**
+**      gctUINT32 Pid
+**          Process ID of the current process.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to map.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_UnmapVideoMemory(
+    IN gckKERNEL Kernel,
+    IN gcePOOL Pool,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical,
+    IN gctUINT32 Pid,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status      = gcvSTATUS_OK;
+    gckGALDEVICE device   = gcvNULL;
+    gctSIZE_T bytes       = 0;
+    gctPHYS_ADDR physHandle = gcvNULL;
+    gctUINT64 mappingInOne  = 1;
+
+    gcmkHEADER_ARG("Logical=0x%08x pid=%u Bytes=%u",
+                   Logical, Pid, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    if (Logical == gcvNULL)
+    {
+        return gcvSTATUS_OK;
+    }
+
+    if (Physical)
+    {
+        gcmkONERROR(gckOS_QueryOption(Kernel->os, "allMapInOne", &mappingInOne));
+    }
+
+    if (mappingInOne)
+    {
+        /* Extract the pointer to the gckGALDEVICE class. */
+        device = (gckGALDEVICE) Kernel->context;
+
+        /* Dispatch on pool. */
+        switch (Pool)
+        {
+        case gcvPOOL_LOCAL_INTERNAL:
+            physHandle = (PLINUX_MDL)device->internalPhysical;
+            bytes = device->internalSize;
+            break;
+
+        case gcvPOOL_LOCAL_EXTERNAL:
+            physHandle = (PLINUX_MDL)device->externalPhysical;
+            bytes = device->externalSize;
+            break;
+
+        case gcvPOOL_SYSTEM:
+            /* System memory. */
+            physHandle = (PLINUX_MDL)device->contiguousPhysical;
+            bytes = device->contiguousSize;
+            break;
+
+        case gcvPOOL_EXTERNAL_SRAM:
+            /* External shared SRAM memory. */
+            physHandle = (PLINUX_MDL)device->extSRAMPhysical[Kernel->extSRAMIndex];
+            bytes = device->extSRAMSizes[Kernel->extSRAMIndex];
+            break;
+
+        case gcvPOOL_INTERNAL_SRAM:
+            /* Per core SRAM reserved usage. */
+            if (Kernel->sRAMPhysFaked[Kernel->sRAMIndex])
+            {
+                gcmkFOOTER_NO();
+                return gcvSTATUS_OK;
+            }
+            /* Per core SRAM memory block. */
+            else
+            {
+                physHandle = (PLINUX_MDL)Kernel->sRAMPhysical[Kernel->sRAMIndex];
+                bytes = Kernel->sRAMSizes[Kernel->sRAMIndex];
+                break;
+            }
+
+        default:
+            /* Invalid memory pool. */
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+    }
+    else
+    {
+        physHandle = (PLINUX_MDL)Physical;
+        bytes = Bytes;
+    }
+
+    gcmkONERROR(gckOS_UnlockPages(Kernel->os, physHandle, bytes, Logical));
+
+OnError:
+    /* Retunn the status. */
+    gcmkFOOTER_NO();
+    return status;
+
+}
+
+/*******************************************************************************
+**
+**  gckKERNEL_Notify
+**
+**  This function iscalled by clients to notify the gckKERNRL object of an event.
+**
+**  INPUT:
+**
+**      gckKERNEL Kernel
+**          Pointer to an gckKERNEL object.
+**
+**      gceNOTIFY Notification
+**          Notification event.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckKERNEL_Notify(
+    IN gckKERNEL Kernel,
+    IN gceNOTIFY Notification
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Kernel=%p Notification=%d", Kernel, Notification);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+    /* Dispatch on notifcation. */
+    switch (Notification)
+    {
+    case gcvNOTIFY_INTERRUPT:
+        /* Process the interrupt. */
+#if COMMAND_PROCESSOR_VERSION > 1
+        status = gckINTERRUPT_Notify(Kernel->interrupt, 0);
+#else
+        status = gckHARDWARE_Notify(Kernel->hardware);
+#endif
+        break;
+
+    default:
+        break;
+    }
+
+    /* Success. */
+    gcmkFOOTER();
+    return status;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
@@ -0,0 +1,387 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_linux_h_
+#define __gc_hal_kernel_linux_h_
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+
+#include <linux/idr.h>
+
+#ifdef MODVERSIONS
+#  include <linux/modversions.h>
+#endif
+#include <asm/io.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(4,7,0)
+    #include <linux/uaccess.h>
+#else
+    #include <asm/uaccess.h>
+#endif
+
+#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+#include <linux/clk.h>
+#endif
+
+#define NTSTRSAFE_NO_CCH_FUNCTIONS
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_platform.h"
+#include "gc_hal_kernel_device.h"
+#include "gc_hal_kernel_os.h"
+#include "gc_hal_kernel_debugfs.h"
+#include "gc_hal_ta.h"
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define FIND_TASK_BY_PID(x) find_task_by_vpid(x)
+#else
+#define FIND_TASK_BY_PID(x) find_task_by_pid(x)
+#endif
+
+#ifndef DEVICE_NAME
+#   define DEVICE_NAME              "galcore"
+#endif
+
+#ifndef CLASS_NAME
+#   define CLASS_NAME               "graphics_class"
+#endif
+
+#define GetPageCount(size, offset)     ((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,7,0)
+#define gcdVM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP)
+#else
+#define gcdVM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED)
+#endif
+
+/* Protection bit when mapping memroy to user sapce */
+#define gcmkPAGED_MEMROY_PROT(x)    pgprot_writecombine(x)
+
+#define gcdSUPPRESS_OOM_MESSAGE 1
+
+#if gcdSUPPRESS_OOM_MESSAGE
+#define gcdNOWARN __GFP_NOWARN
+#else
+#define gcdNOWARN 0
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (4, 1, 0)
+#ifdef gcdIRQ_SHARED
+#       define gcdIRQF_FLAG   (IRQF_SHARED | IRQF_TRIGGER_HIGH)
+#   else
+#       define gcdIRQF_FLAG   (IRQF_TRIGGER_HIGH)
+#   endif
+#else
+#ifdef gcdIRQ_SHARED
+#       define gcdIRQF_FLAG   (IRQF_DISABLED | IRQF_SHARED | IRQF_TRIGGER_HIGH)
+#   else
+#       define gcdIRQF_FLAG   (IRQF_DISABLED | IRQF_TRIGGER_HIGH)
+#   endif
+#endif
+
+/* gcdLINUX_SYNC_FILE and CONFIG_SYNC_FILE. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
+#  define dma_fence                         fence
+#  define dma_fence_array                   fence_array
+#  define dma_fence_ops                     fence_ops
+
+#  define dma_fence_default_wait            fence_default_wait
+
+#  define dma_fence_signal(f)               fence_signal(f)
+#  define dma_fence_signal_locked(f)        fence_signal_locked(f)
+#  define dma_fence_get(f)                  fence_get(f)
+#  define dma_fence_put(f)                  fence_put(f)
+#  define dma_fence_is_array(f)             fence_is_array(f)
+#  define dma_fence_is_signaled(f)          fence_is_signaled(f)
+#  define to_dma_fence_array(f)             to_fence_array(f)
+#  define dma_fence_wait_timeout(f, n, t)   fence_wait_timeout((f), (n), (t))
+#  define dma_fence_init(f, o, l, t, s)     fence_init((f), (o), (l), (t), (s))
+#  define dma_fence_context_alloc(s)        fence_context_alloc(s)
+
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
+#define current_mm_mmap_sem current->mm->mmap_lock
+#else
+#define current_mm_mmap_sem current->mm->mmap_sem
+#endif
+
+extern struct device *galcore_device;
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+typedef struct _gcsIOMMU * gckIOMMU;
+
+typedef struct _gcsINTEGER_DB * gcsINTEGER_DB_PTR;
+typedef struct _gcsINTEGER_DB
+{
+    struct idr                  idr;
+    spinlock_t                  lock;
+    gctINT                      curr;
+}
+gcsINTEGER_DB;
+
+struct _gckOS
+{
+    /* Object. */
+    gcsOBJECT                   object;
+
+    /* Pointer to device */
+    gckGALDEVICE                device;
+
+    /* Memory management */
+    struct mutex                mdlMutex;
+    struct list_head            mdlHead;
+
+    /* Kernel process ID. */
+    gctUINT32                   kernelProcessID;
+
+    /* Signal management. */
+
+    /* Lock. */
+    spinlock_t                  signalLock;
+
+    /* signal id database. */
+    gcsINTEGER_DB               signalDB;
+
+    /* workqueue for os timer. */
+    struct workqueue_struct *   workqueue;
+
+    /* Allocate extra page to avoid cache overflow */
+    struct page* paddingPage;
+
+    /* Detect unfreed allocation. */
+    atomic_t                    allocateCount;
+
+    struct list_head            allocatorList;
+
+    gcsDEBUGFS_DIR              allocatorDebugfsDir;
+
+    gctBOOL                     allocatorLimitMarker;
+
+    /* Lock for register access check. */
+    spinlock_t                  registerAccessLock;
+
+    /* External power states. */
+    gctBOOL                     powerStates[gcdMAX_GPU_COUNT];
+
+    /* External clock states. */
+    gctBOOL                     clockStates[gcdMAX_GPU_COUNT];
+
+    /* IOMMU. */
+    gckIOMMU                    iommu;
+
+    /* Dump in kernel. */
+    struct file *               dumpFilp;
+    struct mutex                dumpFilpMutex;
+
+    int                         dumpTarget;
+    char                        dumpFileName[256];
+    gcsDEBUGFS_DIR              dumpDebugfsDir;
+};
+
+typedef struct _gcsSIGNAL * gcsSIGNAL_PTR;
+typedef struct _gcsSIGNAL
+{
+    /* Kernel sync primitive. */
+    volatile unsigned int done;
+    spinlock_t lock;
+
+    wait_queue_head_t wait;
+
+    /* Manual reset flag. */
+    gctBOOL manualReset;
+
+    /* The reference counter. */
+    atomic_t ref;
+
+    /* The owner of the signal. */
+    gctHANDLE process;
+
+    /* ID. */
+    gctUINT32 id;
+
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+    /* Parent timeline. */
+    struct sync_timeline * timeline;
+#  else
+    struct dma_fence *fence;
+#  endif
+#endif
+}
+gcsSIGNAL;
+
+typedef struct _gcsOSTIMER * gcsOSTIMER_PTR;
+typedef struct _gcsOSTIMER
+{
+    struct delayed_work     work;
+    gctTIMERFUNCTION        function;
+    gctPOINTER              data;
+} gcsOSTIMER;
+
+gceSTATUS
+gckOS_ImportAllocators(
+    gckOS Os
+    );
+
+gceSTATUS
+gckOS_FreeAllocators(
+    gckOS Os
+    );
+
+gceSTATUS
+_ConvertLogical2Physical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID,
+    IN PLINUX_MDL Mdl,
+    OUT gctPHYS_ADDR_T * Physical
+    );
+
+gctBOOL
+_QuerySignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    );
+
+static inline gctINT
+_GetProcessID(
+    void
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+    return task_tgid_vnr(current);
+#else
+    return current->tgid;
+#endif
+}
+
+static inline void
+_MemoryBarrier(
+    void
+    )
+{
+#if defined(CONFIG_ARM) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
+    dsb();
+#else
+    mb();
+#endif
+}
+
+static inline void
+_Barrier(
+    void
+    )
+{
+    barrier();
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+static inline int
+is_vmalloc_addr(
+    void *Addr
+    )
+{
+    unsigned long addr = (unsigned long)Addr;
+
+    return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+
+#ifdef CONFIG_IOMMU_SUPPORT
+void
+gckIOMMU_Destory(
+    IN gckOS Os,
+    IN gckIOMMU Iommu
+    );
+
+gceSTATUS
+gckIOMMU_Construct(
+    IN gckOS Os,
+    OUT gckIOMMU * Iommu
+    );
+
+gceSTATUS
+gckIOMMU_Map(
+    IN gckIOMMU Iommu,
+    IN gctUINT32 DomainAddress,
+    IN gctUINT32 Physical,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gckIOMMU_Unmap(
+    IN gckIOMMU Iommu,
+    IN gctUINT32 DomainAddress,
+    IN gctUINT32 Bytes
+    );
+#endif
+
+#endif /* __gc_hal_kernel_linux_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+gctINT
+gckMATH_ModuloInt(
+    IN gctINT X,
+    IN gctINT Y
+    )
+{
+    if(Y ==0) {return 0;}
+    else {return X % Y;}
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _gc_hal_kernel_mutex_h_
+#define _gc_hal_kernel_mutex_h_
+
+#include "gc_hal.h"
+#include <linux/mutex.h>
+
+/* Create a new mutex. */
+#define gckOS_CreateMutex(Os, Mutex)                                        \
+({                                                                          \
+    /* Allocate the mutex structure. */                                     \
+    gceSTATUS _status = gckOS_Allocate(Os, gcmSIZEOF(struct mutex), Mutex); \
+                                                                            \
+    if (gcmIS_SUCCESS(_status))                                             \
+    {                                                                       \
+        /* Initialize the mutex. */                                         \
+        mutex_init(*(struct mutex **)Mutex);                                \
+    }                                                                       \
+                                                                            \
+    _status;                                                                \
+})
+
+#endif
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
@@ -0,0 +1,7560 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_dump.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/irqflags.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
+#include <linux/math64.h>
+#endif
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/anon_inodes.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
+#include <linux/io.h>
+#endif
+
+#if gcdLINUX_SYNC_FILE
+#  include <linux/file.h>
+#  include "gc_hal_kernel_sync.h"
+#endif
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+#include <linux/dma-buf.h>
+#endif
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+#include "gc_hal_kernel_allocator.h"
+
+#define gcmkBUG_ON(x) \
+    do { \
+        if (unlikely(!!(x))) \
+        { \
+            printk("[galcore]: BUG ON @ %s(%d)\n", __func__, __LINE__); \
+            dump_stack(); \
+        } \
+    } while (0)
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+static gctINT
+_GetThreadID(
+    void
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+    return task_pid_vnr(current);
+#else
+    return current->pid;
+#endif
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+static inline PLINUX_MDL_MAP
+_CreateMdlMap(
+    IN PLINUX_MDL Mdl,
+    IN gctINT ProcessID
+    )
+{
+    PLINUX_MDL_MAP mdlMap = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Mdl=%p ProcessID=%d", Mdl, ProcessID);
+
+    mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL | gcdNOWARN);
+    if (mdlMap == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    mdlMap->pid     = ProcessID;
+    mdlMap->vmaAddr = gcvNULL;
+    mdlMap->count   = 0;
+
+    list_add(&mdlMap->link, &Mdl->mapsHead);
+
+OnError:
+    gcmkFOOTER_ARG("ret=%p", mdlMap);
+    return mdlMap;
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+static inline gceSTATUS
+_DestroyMdlMap(
+    IN PLINUX_MDL Mdl,
+    IN PLINUX_MDL_MAP MdlMap
+    )
+{
+    gcmkHEADER_ARG("Mdl=%p MdlMap=%p", Mdl, MdlMap);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL);
+
+    list_del(&MdlMap->link);
+    kfree(MdlMap);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+extern PLINUX_MDL_MAP
+FindMdlMap(
+    IN PLINUX_MDL Mdl,
+    IN gctINT ProcessID
+    )
+{
+    PLINUX_MDL_MAP mdlMap = gcvNULL;
+
+    gcmkHEADER_ARG("Mdl=%p ProcessID=%d", Mdl, ProcessID);
+
+    if (Mdl)
+    {
+        PLINUX_MDL_MAP iter = gcvNULL;
+        list_for_each_entry(iter, &Mdl->mapsHead, link)
+        {
+            if (iter->pid == ProcessID)
+            {
+                mdlMap = iter;
+                break;
+            }
+        }
+    }
+
+    gcmkFOOTER_ARG("ret=%p", mdlMap);
+    return mdlMap;
+}
+
+
+static PLINUX_MDL
+_CreateMdl(
+    IN gckOS Os
+    )
+{
+    PLINUX_MDL mdl;
+
+    gcmkHEADER();
+
+    mdl = (PLINUX_MDL)kzalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL | gcdNOWARN);
+
+    if (mdl)
+    {
+        mdl->os = Os;
+        atomic_set(&mdl->refs, 1);
+        mutex_init(&mdl->mapsMutex);
+        INIT_LIST_HEAD(&mdl->mapsHead);
+    }
+
+    gcmkFOOTER_ARG("%p", mdl);
+    return mdl;
+}
+
+static gceSTATUS
+_DestroyMdl(
+    IN PLINUX_MDL Mdl
+    )
+{
+    gcmkHEADER_ARG("Mdl=%p", Mdl);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Mdl != gcvNULL);
+
+    if (atomic_dec_and_test(&Mdl->refs))
+    {
+        gckOS os = Mdl->os;
+        gckALLOCATOR allocator = Mdl->allocator;
+        PLINUX_MDL_MAP mdlMap, next;
+
+        /* Valid private means alloc/attach successfully */
+        if (Mdl->priv)
+        {
+            if (Mdl->addr)
+            {
+                gcmALLOCATOR_UnmapKernel(allocator, Mdl, Mdl->addr);
+            }
+            gcmALLOCATOR_Free(allocator, Mdl);
+        }
+
+        mutex_lock(&Mdl->mapsMutex);
+        list_for_each_entry_safe(mdlMap, next, &Mdl->mapsHead, link)
+        {
+            gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap));
+        }
+        mutex_unlock(&Mdl->mapsMutex);
+
+        if (Mdl->link.next)
+        {
+            /* Remove the node from global list.. */
+            mutex_lock(&os->mdlMutex);
+            list_del(&Mdl->link);
+            mutex_unlock(&os->mdlMutex);
+        }
+
+        kfree(Mdl);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** Integer Id Management.
+*/
+gceSTATUS
+_AllocateIntegerId(
+    IN gcsINTEGER_DB_PTR Database,
+    IN gctPOINTER KernelPointer,
+    OUT gctUINT32 *Id
+    )
+{
+    int result;
+    gctINT next;
+    unsigned long flags = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+    idr_preload(GFP_KERNEL | gcdNOWARN);
+
+    if(in_irq()){
+        spin_lock(&Database->lock);
+    }else{
+        spin_lock_irqsave(&Database->lock, flags);
+    }
+
+    next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
+
+    result = idr_alloc(&Database->idr, KernelPointer, next, 0, GFP_ATOMIC);
+
+    /* ID allocated should not be 0. */
+    gcmkASSERT(result != 0);
+
+    if (result > 0)
+    {
+        Database->curr = *Id = result;
+    }
+
+    if(in_irq()){
+        spin_unlock(&Database->lock);
+    }else{
+        spin_unlock_irqrestore(&Database->lock, flags);
+    }
+
+    idr_preload_end();
+
+    if (result < 0)
+    {
+        return gcvSTATUS_OUT_OF_RESOURCES;
+    }
+#else
+again:
+    if (idr_pre_get(&Database->idr, GFP_KERNEL | gcdNOWARN) == 0)
+    {
+        return gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+    if(in_irq()){
+        spin_lock(&Database->lock);
+    }else{
+        spin_lock_irqsave(&Database->lock, flags);
+    }
+
+    next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
+
+    /* Try to get a id greater than 0. */
+    result = idr_get_new_above(&Database->idr, KernelPointer, next, Id);
+
+    if (!result)
+    {
+        Database->curr = *Id;
+    }
+
+    if(in_irq()){
+        spin_unlock(&Database->lock);
+    }else{
+        spin_unlock_irqrestore(&Database->lock, flags);
+    }
+
+    if (result == -EAGAIN)
+    {
+        goto again;
+    }
+
+    if (result != 0)
+    {
+        return gcvSTATUS_OUT_OF_RESOURCES;
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_QueryIntegerId(
+    IN gcsINTEGER_DB_PTR Database,
+    IN gctUINT32  Id,
+    OUT gctPOINTER * KernelPointer
+    )
+{
+    gctPOINTER pointer;
+    unsigned long flags = 0;
+
+    if(in_irq()){
+        spin_lock(&Database->lock);
+    }else{
+        spin_lock_irqsave(&Database->lock, flags);
+    }
+
+    pointer = idr_find(&Database->idr, Id);
+
+    if(in_irq()){
+        spin_unlock(&Database->lock);
+    }else{
+        spin_unlock_irqrestore(&Database->lock, flags);
+    }
+
+    if (pointer)
+    {
+        *KernelPointer = pointer;
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        gcmkTRACE_ZONE(
+                gcvLEVEL_ERROR, gcvZONE_OS,
+                "%s(%d) Id = %d is not found",
+                __FUNCTION__, __LINE__, Id);
+
+        return gcvSTATUS_NOT_FOUND;
+    }
+}
+
+gceSTATUS
+_DestroyIntegerId(
+    IN gcsINTEGER_DB_PTR Database,
+    IN gctUINT32 Id
+    )
+{
+    unsigned long flags = 0;
+
+    if(in_irq()){
+        spin_lock(&Database->lock);
+    }else{
+        spin_lock_irqsave(&Database->lock, flags);
+    }
+
+    idr_remove(&Database->idr, Id);
+
+    if(in_irq()){
+        spin_unlock(&Database->lock);
+    }else{
+        spin_unlock_irqrestore(&Database->lock, flags);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+static inline gceSTATUS
+_QueryProcessPageTable(
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Address
+    )
+{
+    unsigned long logical = (unsigned long)Logical;
+    unsigned long offset = logical & ~PAGE_MASK;
+
+    if (is_vmalloc_addr(Logical))
+    {
+        /* vmalloc area. */
+        *Address = page_to_phys(vmalloc_to_page(Logical)) | offset;
+        return gcvSTATUS_OK;
+    }
+    else if (virt_addr_valid(logical))
+    {
+        /* Kernel logical address. */
+        *Address = virt_to_phys(Logical);
+        return gcvSTATUS_OK;
+    }
+    else
+    {
+        /* Try user VM area. */
+        struct vm_area_struct *vma;
+        spinlock_t *ptl;
+        pgd_t *pgd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (5,9,0)
+        p4d_t *p4d;
+#endif
+        pud_t *pud;
+        pmd_t *pmd;
+        pte_t *pte;
+
+        if (!current->mm)
+            return gcvSTATUS_NOT_FOUND;
+
+        down_read(&current_mm_mmap_sem);
+        vma = find_vma(current->mm, logical);
+        up_read(&current_mm_mmap_sem);
+
+        /* To check if mapped to user. */
+        if (!vma)
+            return gcvSTATUS_NOT_FOUND;
+
+        pgd = pgd_offset(current->mm, logical);
+        if (pgd_none(*pgd) || pgd_bad(*pgd))
+            return gcvSTATUS_NOT_FOUND;
+
+#if (defined(CONFIG_CPU_CSKYV2) || defined(CONFIG_X86)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,12,0)
+        pud = pud_offset((p4d_t*)pgd, logical);
+#elif (defined(CONFIG_CPU_CSKYV2)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,11,0)
+        pud = pud_offset((p4d_t*)pgd, logical);
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (5,9,0)
+        p4d = p4d_offset(pgd, logical);
+        if (p4d_none(READ_ONCE(*p4d)))
+            return gcvSTATUS_NOT_FOUND;
+
+        pud = pud_offset(p4d, logical);
+#else
+        pud = pud_offset(pgd, logical);
+#endif
+#endif
+        if (pud_none(*pud) || pud_bad(*pud))
+            return gcvSTATUS_NOT_FOUND;
+
+        pmd = pmd_offset(pud, logical);
+        if (pmd_none(*pmd) || pmd_bad(*pmd))
+            return gcvSTATUS_NOT_FOUND;
+
+        pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl);
+        if (!pte)
+        {
+            spin_unlock(ptl);
+            return gcvSTATUS_NOT_FOUND;
+        }
+
+        if (!pte_present(*pte))
+        {
+            pte_unmap_unlock(pte, ptl);
+            return gcvSTATUS_NOT_FOUND;
+        }
+
+        *Address = (pte_pfn(*pte) << PAGE_SHIFT) | offset;
+        pte_unmap_unlock(pte, ptl);
+
+        return gcvSTATUS_OK;
+    }
+}
+
+
+static gceSTATUS
+_ShrinkMemory(
+    IN gckOS Os
+    )
+{
+    gcsPLATFORM * platform;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    platform = Os->device->platform;
+
+    if (platform && platform->ops->shrinkMemory)
+    {
+        status = platform->ops->shrinkMemory(platform);
+    }
+    else
+    {
+        status = gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+#if gcdDUMP_IN_KERNEL
+
+#define DUMP_TO_KERNEL_DMESG    0
+#define DUMP_TO_FILE            1
+#define DUMP_IGNORE             2
+
+static void set_dump_file(gckOS os, char * fname)
+{
+    if (os->dumpFilp)
+    {
+        /* close exist opened file. */
+        printk("galcore: end dump to file: %s\n", os->dumpFileName);
+
+        filp_close(os->dumpFilp, NULL);
+        os->dumpFilp = NULL;
+    }
+
+    if (fname[0] == '\0' || !strcmp(fname, "[ignored]"))
+    {
+        /* empty or [ignored] means ignored. */
+        printk("galcore: dump ignored\n");
+
+        os->dumpTarget = DUMP_IGNORE;
+        strcpy(os->dumpFileName, "[ignored]");
+    }
+    else if (!strcmp(fname, "[dmesg]"))
+    {
+        /* [dmesg] means dump to kernel dmesg. */
+        printk("galcore: dump to kernel dmesg\n");
+
+        os->dumpTarget = DUMP_TO_KERNEL_DMESG;
+        strcpy(os->dumpFileName, "[dmesg]");
+    }
+    else if (fname[0] != '/')
+    {
+        /* invalid path, switch to kernel dmesg. */
+        printk(KERN_ERR "galcore: invalid path: %s\n", fname);
+        printk(KERN_ERR "galcore: must be absolute path start with '/'\n");
+        printk("galcore: dump to kernel dmesg\n");
+
+        os->dumpTarget = DUMP_TO_KERNEL_DMESG;
+        strcpy(os->dumpFileName, "[dmesg]");
+    }
+    else
+    {
+        /* try open file. */
+        os->dumpFilp = filp_open(fname, O_RDWR | O_CREAT, 0644);
+
+        if (IS_ERR(os->dumpFilp))
+        {
+            printk(KERN_ERR "galcore: failed to open file: %s\n", fname);
+            printk("galcore: dump to kernel dmesg\n");
+
+            os->dumpFilp = NULL;
+            os->dumpTarget = DUMP_TO_KERNEL_DMESG;
+            strcpy(os->dumpFileName, "[dmesg]");
+        }
+        else
+        {
+            printk("galcore: start dump to file: %s\n", fname);
+
+            os->dumpTarget = DUMP_TO_FILE;
+            strcpy(os->dumpFileName, fname);
+        }
+    }
+}
+
+static int dump_file_show(struct seq_file *m, void *unused)
+{
+    gcsINFO_NODE *node = m->private;
+    gckOS os = node->device;
+
+    seq_printf(m, "%s\n", os->dumpFileName);
+    return 0;
+}
+
+static int dump_file_write(const char __user *buf, size_t count, void* data)
+{
+    gcsINFO_NODE *node = data;
+    gckOS os = node->device;
+    char fname[256];
+    size_t len = min(count, sizeof(fname) - 1);
+
+    if (copy_from_user(fname, buf, len))
+    {
+        return -EFAULT;
+    }
+
+    /* Remove tailing space. */
+    while (len > 0 && (fname[len - 1] == '\n' || fname[len - 1] == ' '))
+    {
+        fname[len - 1] = '\0';
+    }
+
+    fname[len] = '\0';
+
+    mutex_lock(&os->dumpFilpMutex);
+    set_dump_file(os, fname);
+    mutex_unlock(&os->dumpFilpMutex);
+
+    return count;
+}
+
+static gcsINFO dumpDebugList[] =
+{
+    {"dump_file", dump_file_show, dump_file_write},
+};
+
+static gceSTATUS
+_DumpDebugfsInit(
+    IN gckOS Os
+    )
+{
+    gceSTATUS status;
+    gckGALDEVICE device = Os->device;
+    gckDEBUGFS_DIR dir = &Os->dumpDebugfsDir;
+
+    gcmkONERROR(gckDEBUGFS_DIR_Init(dir, device->debugfsDir.root, "dump"));
+
+    gcmkONERROR(
+        gckDEBUGFS_DIR_CreateFiles(dir, dumpDebugList,
+                                   gcmCOUNTOF(dumpDebugList), Os));
+
+OnError:
+    return status;
+}
+
+static void
+_DumpDebugfsCleanup(
+    IN gckOS Os
+    )
+{
+    gckDEBUGFS_DIR dir = &Os->dumpDebugfsDir;
+
+    if (dir->root)
+    {
+        gckDEBUGFS_DIR_RemoveFiles(dir, dumpDebugList, gcmCOUNTOF(dumpDebugList));
+        gckDEBUGFS_DIR_Deinit(dir);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+**  gckOS_Construct
+**
+**  Construct a new gckOS object.
+**
+**  INPUT:
+**
+**      gctPOINTER Context
+**          Pointer to the gckGALDEVICE class.
+**
+**  OUTPUT:
+**
+**      gckOS * Os
+**          Pointer to a variable that will hold the pointer to the gckOS object.
+*/
+gceSTATUS
+gckOS_Construct(
+    IN gctPOINTER Context,
+    OUT gckOS * Os
+    )
+{
+    gckOS os = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Context=%p", Context);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Os != gcvNULL);
+
+    /* Allocate the gckOS object. */
+    os = (gckOS)kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL | gcdNOWARN);
+
+    if (os == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Zero the memory. */
+    gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS));
+
+    /* Initialize the gckOS object. */
+    os->object.type = gcvOBJ_OS;
+
+    /* Set device device. */
+    os->device = Context;
+
+    /* Set allocateCount to 0, gckOS_Allocate has not been used yet. */
+    atomic_set(&os->allocateCount, 0);
+
+    /* Initialize the memory lock. */
+    mutex_init(&os->mdlMutex);
+
+    INIT_LIST_HEAD(&os->mdlHead);
+
+    /* Get the kernel process ID. */
+    os->kernelProcessID = _GetProcessID();
+
+    /*
+     * Initialize the signal manager.
+     */
+
+    /* Initialize spinlock. */
+    spin_lock_init(&os->signalLock);
+
+    /* Initialize signal id database lock. */
+    spin_lock_init(&os->signalDB.lock);
+
+    /* Initialize signal id database. */
+    idr_init(&os->signalDB.idr);
+
+    /* Create a workqueue for os timer. */
+    os->workqueue = create_singlethread_workqueue("galcore workqueue");
+
+    if (os->workqueue == gcvNULL)
+    {
+        /* Out of memory. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    os->paddingPage = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN);
+    if (os->paddingPage == gcvNULL)
+    {
+        /* Out of memory. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+    else
+    {
+        SetPageReserved(os->paddingPage);
+    }
+
+    spin_lock_init(&os->registerAccessLock);
+
+    gckOS_ImportAllocators(os);
+
+#if defined(CONFIG_IOMMU_SUPPORT)
+    if (0)
+    {
+        /* Only use IOMMU when internal MMU is not enabled. */
+        if (gcmIS_ERROR(gckIOMMU_Construct(os, &os->iommu)))
+        {
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): Fail to setup IOMMU",
+                __FUNCTION__, __LINE__
+                );
+        }
+    }
+#endif
+
+#if gcdDUMP_IN_KERNEL
+    mutex_init(&os->dumpFilpMutex);
+
+    /* Set default dump file. */
+    set_dump_file(os, gcdDUMP_FILE_IN_KERNEL);
+
+    /* Init debugfs for kernel dump feature. */
+    _DumpDebugfsInit(os);
+#endif
+
+    /* Return pointer to the gckOS object. */
+    *Os = os;
+
+OnError:
+    if (gcmIS_ERROR(status) && os)
+    {
+        if (os->workqueue != gcvNULL)
+        {
+            destroy_workqueue(os->workqueue);
+        }
+
+        kfree(os);
+        os = gcvNULL;
+    }
+
+    /* Return the error. */
+    gcmkFOOTER_ARG("*Os=%p", os);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_Destroy
+**
+**  Destroy an gckOS object.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object that needs to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_Destroy(
+    IN gckOS Os
+    )
+{
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    if (Os->paddingPage != gcvNULL)
+    {
+        ClearPageReserved(Os->paddingPage);
+        __free_page(Os->paddingPage);
+        Os->paddingPage = gcvNULL;
+    }
+
+    /*
+     * Destroy the signal manager.
+     */
+
+    /* Wait for all works done. */
+    flush_workqueue(Os->workqueue);
+
+    /* Destory work queue. */
+    destroy_workqueue(Os->workqueue);
+
+    gckOS_FreeAllocators(Os);
+
+#ifdef CONFIG_IOMMU_SUPPORT
+    if (Os->iommu)
+    {
+        gckIOMMU_Destory(Os, Os->iommu);
+    }
+#endif
+
+    /* Mark the gckOS object as unknown. */
+    Os->object.type = gcvOBJ_UNKNOWN;
+
+
+#if gcdDUMP_IN_KERNEL
+    mutex_lock(&Os->dumpFilpMutex);
+
+    if (Os->dumpFilp)
+    {
+        filp_close(Os->dumpFilp, NULL);
+        Os->dumpFilp = NULL;
+        Os->dumpTarget = DUMP_IGNORE;
+    }
+
+    mutex_unlock(&Os->dumpFilpMutex);
+
+    /* Cleanup debugfs for kernel dump feature. */
+    _DumpDebugfsCleanup(Os);
+#endif
+
+    /* Free the gckOS object. */
+    kfree(Os);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateKernelMapping(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+    gckALLOCATOR allocator = mdl->allocator;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Offset=0x%zx Bytes=0x%zx",
+                   Os, Physical, Offset, Bytes);
+
+    if (mdl->addr)
+    {
+        /* Already mapped whole memory. */
+        *Logical = (gctUINT8_PTR)mdl->addr + Offset;
+    }
+    else
+    {
+        gcmkONERROR(gcmALLOCATOR_MapKernel(allocator, mdl, Offset, Bytes, Logical));
+    }
+
+OnError:
+    gcmkFOOTER_ARG("*Logical=%p", gcmOPT_POINTER(Logical));
+    return status;
+}
+
+gceSTATUS
+gckOS_DestroyKernelMapping(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+    gckALLOCATOR allocator = mdl->allocator;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Logical=%p", Os, Physical, Logical);
+
+    if (mdl->addr)
+    {
+        /* Nothing to do. */
+    }
+    else
+    {
+        gcmALLOCATOR_UnmapKernel(allocator, mdl, Logical);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_Allocate
+**
+**  Allocate memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to allocate.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Memory
+**          Pointer to a variable that will hold the allocated memory location.
+*/
+gceSTATUS
+gckOS_Allocate(
+    IN gckOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Bytes=0x%zx", Os, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory));
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Memory=%p", gcmOPT_POINTER(Memory));
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_Free
+**
+**  Free allocated memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Memory
+**          Pointer to memory allocation to free.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_Free(
+    IN gckOS Os,
+    IN gctPOINTER Memory
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Memory=%p", Os, Memory);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    gcmkONERROR(gckOS_FreeMemory(Os, Memory));
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AllocateMemory
+**
+**  Allocate memory wrapper.
+**
+**  INPUT:
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to allocate.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Memory
+**          Pointer to a variable that will hold the allocated memory location.
+*/
+gceSTATUS
+gckOS_AllocateMemory(
+    IN gckOS Os,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Memory
+    )
+{
+    gctPOINTER memory = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Bytes=0x%zx", Os, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    if (Bytes > PAGE_SIZE)
+    {
+        memory = (gctPOINTER) vmalloc(Bytes);
+    }
+    else
+    {
+        memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL | gcdNOWARN);
+    }
+
+    if (memory == gcvNULL)
+    {
+        /* Out of memory. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Increase count. */
+    atomic_inc(&Os->allocateCount);
+
+    /* Return pointer to the memory allocation. */
+    *Memory = memory;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Memory=%p", gcmOPT_POINTER(Memory));
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_FreeMemory
+**
+**  Free allocated memory wrapper.
+**
+**  INPUT:
+**
+**      gctPOINTER Memory
+**          Pointer to memory allocation to free.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_FreeMemory(
+    IN gckOS Os,
+    IN gctPOINTER Memory
+    )
+{
+    gcmkHEADER_ARG("Os=%p Memory=%p", Os, Memory);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+    /* Free the memory from the OS pool. */
+    if (is_vmalloc_addr(Memory))
+    {
+        vfree(Memory);
+    }
+    else
+    {
+        kfree(Memory);
+    }
+
+    /* Decrease count. */
+    atomic_dec(&Os->allocateCount);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_MapMemory
+**
+**  Map physical memory into the current process.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Start of physical address memory.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to map.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Memory
+**          Pointer to a variable that will hold the logical address of the
+**          mapped memory.
+*/
+gceSTATUS
+gckOS_MapMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    PLINUX_MDL_MAP  mdlMap;
+    PLINUX_MDL      mdl = (PLINUX_MDL) Physical;
+    gckALLOCATOR allocator;
+    gctINT pid = _GetProcessID();
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Bytes=0x%zx", Os, Physical, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != 0);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    mutex_lock(&mdl->mapsMutex);
+
+    mdlMap = FindMdlMap(mdl, pid);
+
+    if (mdlMap == gcvNULL)
+    {
+        mdlMap = _CreateMdlMap(mdl, pid);
+        if (mdlMap == gcvNULL)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+
+    if (mdlMap->vmaAddr == gcvNULL)
+    {
+        allocator = mdl->allocator;
+
+        gcmkONERROR(gcmALLOCATOR_MapUser(allocator, mdl, mdlMap, gcvFALSE));
+    }
+
+    mutex_unlock(&mdl->mapsMutex);
+
+    *Logical = mdlMap->vmaAddr;
+    gcmkFOOTER_ARG("*Logical=%p", Logical);
+    return gcvSTATUS_OK;
+
+OnError:
+    mutex_unlock(&mdl->mapsMutex);
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UnmapMemory
+**
+**  Unmap physical memory out of the current process.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Start of physical address memory.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to unmap.
+**
+**      gctPOINTER Memory
+**          Pointer to a previously mapped memory region.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UnmapMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical
+    )
+{
+    gcmkHEADER_ARG("Os=%p Physical=0%p Bytes=0x%zx Logical=%p",
+                   Os, Physical, Bytes, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != 0);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID());
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+**  gckOS_UnmapMemoryEx
+**
+**  Unmap physical memory in the specified process.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Start of physical address memory.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to unmap.
+**
+**      gctPOINTER Memory
+**          Pointer to a previously mapped memory region.
+**
+**      gctUINT32 PID
+**          Pid of the process that opened the device and mapped this memory.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UnmapMemoryEx(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical,
+    IN gctUINT32 PID
+    )
+{
+    PLINUX_MDL_MAP mdlMap;
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Bytes=0x%zx Logical=%p PID=%d",
+                   Os, Physical, Bytes, Logical, PID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != 0);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(PID != 0);
+
+    if (Logical)
+    {
+        gckALLOCATOR allocator = mdl->allocator;
+
+        mutex_lock(&mdl->mapsMutex);
+
+        mdlMap = FindMdlMap(mdl, PID);
+
+        if (mdlMap == gcvNULL)
+        {
+            mutex_unlock(&mdl->mapsMutex);
+            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+        }
+
+        if (mdlMap->vmaAddr != gcvNULL)
+        {
+            BUG_ON(!allocator || !allocator->ops->UnmapUser);
+            gcmALLOCATOR_UnmapUser(allocator, mdl, mdlMap, mdl->bytes);
+        }
+
+        gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
+
+        mutex_unlock(&mdl->mapsMutex);
+    }
+
+OnError:
+    gcmkFOOTER_NO();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AllocateNonPagedMemory
+**
+**  Allocate a number of pages from non-paged memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctBOOL InUserSpace
+**          gcvTRUE if the pages need to be mapped into user space.
+**
+**      gctUINT32 Flag
+**          Allocation attribute.
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that holds the number of bytes to allocate.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that hold the number of bytes allocated.
+**
+**      gctPHYS_ADDR * Physical
+**          Pointer to a variable that will hold the physical address of the
+**          allocation.
+**
+**      gctPOINTER * Logical
+**          Pointer to a variable that will hold the logical address of the
+**          allocation.
+*/
+gceSTATUS
+gckOS_AllocateNonPagedMemory(
+    IN gckOS Os,
+    IN gctBOOL InUserSpace,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctPHYS_ADDR * Physical,
+    OUT gctPOINTER * Logical
+    )
+{
+    gctSIZE_T bytes;
+    gctSIZE_T numPages;
+    PLINUX_MDL mdl = gcvNULL;
+    PLINUX_MDL_MAP mdlMap = gcvNULL;
+    gctPOINTER addr;
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gckALLOCATOR allocator;
+
+    gcmkHEADER_ARG("Os=%p InUserSpace=%d *Bytes=0x%zx",
+                   Os, InUserSpace, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
+    gcmkVERIFY_ARGUMENT(*Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    /* Align number of bytes to page size. */
+    bytes = gcmALIGN(*Bytes, PAGE_SIZE);
+
+    /* Get total number of pages.. */
+    numPages = GetPageCount(bytes, 0);
+
+    /* Allocate mdl structure */
+    mdl = _CreateMdl(Os);
+    if (mdl == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    gcmkASSERT(Flag & gcvALLOC_FLAG_CONTIGUOUS);
+
+#if gcdENABLE_CACHEABLE_COMMAND_BUFFER
+    Flag &= ~gcvALLOC_FLAG_CACHEABLE;
+#endif
+
+#if LINUX_CMA_FSL
+    Flag |= gcvALLOC_FLAG_CMA_PREEMPT;
+#else
+    Flag |= gcvALLOC_FLAG_4GB_ADDR | gcvALLOC_FLAG_CONTIGUOUS;
+#endif
+
+    /* Walk all allocators. */
+    list_for_each_entry(allocator, &Os->allocatorList, link)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+                       "%s(%d) flag = %x allocator->capability = %x",
+                        __FUNCTION__, __LINE__, Flag, allocator->capability);
+
+#ifndef NO_DMA_COHERENT
+        /* Point to dma coherent allocator. */
+        if (!strcmp(allocator->name, "dma") ||
+            ((Flag & allocator->capability) == Flag && numPages == 1))
+        {
+            status = gcmALLOCATOR_Alloc(allocator, mdl, numPages, Flag);
+
+            if (gcmIS_SUCCESS(status))
+            {
+                mdl->allocator = allocator;
+                break;
+            }
+        }
+#else
+        if ((Flag & allocator->capability) == Flag)
+        {
+            status = gcmALLOCATOR_Alloc(allocator, mdl, numPages, Flag);
+
+            if (gcmIS_SUCCESS(status))
+            {
+                mdl->allocator = allocator;
+                break;
+            }
+        }
+#endif
+    }
+
+    /* Check status. */
+    gcmkONERROR(status);
+
+    mdl->cacheable = Flag & gcvALLOC_FLAG_CACHEABLE;
+
+    mdl->bytes    = bytes;
+    mdl->numPages = numPages;
+
+    mdl->contiguous = gcvTRUE;
+
+    gcmkONERROR(gcmALLOCATOR_MapKernel(allocator, mdl, 0, bytes, &addr));
+
+    if (!strcmp(allocator->name, "gfp"))
+    {
+        /* Trigger a page fault. */
+        memset(addr, 0, numPages * PAGE_SIZE);
+    }
+
+    mdl->addr = addr;
+
+    if (InUserSpace)
+    {
+        mdlMap = _CreateMdlMap(mdl, _GetProcessID());
+
+        if (mdlMap == gcvNULL)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        gcmkONERROR(gcmALLOCATOR_MapUser(allocator, mdl, mdlMap, gcvFALSE));
+
+        *Logical = mdlMap->vmaAddr;
+    }
+    else
+    {
+        *Logical = addr;
+    }
+
+    /*
+     * Add this to a global list.
+     * Will be used by get physical address
+     * and mapuser pointer functions.
+     */
+    mutex_lock(&Os->mdlMutex);
+    list_add_tail(&mdl->link, &Os->mdlHead);
+    mutex_unlock(&Os->mdlMutex);
+
+    /* Return allocated memory. */
+    *Bytes = bytes;
+    *Physical = (gctPHYS_ADDR) mdl;
+
+    /* Success. */
+    status = gcvSTATUS_OK;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        if (mdlMap)
+        {
+            /* Free LINUX_MDL_MAP. */
+            gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
+        }
+
+        if (mdl)
+        {
+            /* Free LINUX_MDL. */
+            gcmkVERIFY_OK(_DestroyMdl(mdl));
+        }
+    }
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Bytes=0x%zx *Physical=%p *Logical=%p",
+                   gcmOPT_VALUE(Bytes), gcmOPT_POINTER(Physical), gcmOPT_POINTER(Logical));
+    return status;
+}
+
+
+/*******************************************************************************
+**
+**  gckOS_FreeNonPagedMemory
+**
+**  Free previously allocated and mapped pages from non-paged memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of the allocated memory.
+**
+**      gctPOINTER Logical
+**          Logical address of the allocated memory.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes allocated.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS gckOS_FreeNonPagedMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+
+    gcmkHEADER_ARG("Os=%p Bytes=0x%zx Physical=%p Logical=%p",
+                   Os, Bytes, Physical, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Physical != 0);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    gcmkVERIFY_OK(_DestroyMdl(mdl));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+static inline gckALLOCATOR
+_FindAllocator(
+    gckOS Os,
+    gctUINT Flag
+    )
+{
+    gckALLOCATOR allocator;
+
+    list_for_each_entry(allocator, &Os->allocatorList, link)
+    {
+        if ((allocator->capability & Flag) == Flag)
+        {
+            return allocator;
+        }
+    }
+
+    return gcvNULL;
+}
+
+gceSTATUS
+gckOS_RequestReservedMemory(
+    gckOS Os,
+    gctPHYS_ADDR_T Start,
+    gctSIZE_T Size,
+    const char * Name,
+    gctBOOL Requested,
+    gctPOINTER * MemoryHandle
+    )
+{
+    PLINUX_MDL mdl = gcvNULL;
+    gceSTATUS status;
+    gckALLOCATOR allocator;
+    gcsATTACH_DESC desc;
+
+    gcmkHEADER_ARG("start=0x%lx size=0x%lx name=%s", Start, Size, Name);
+
+    /* Round up to page size. */
+    Size = (Size + ~PAGE_MASK) & PAGE_MASK;
+
+    mdl = _CreateMdl(Os);
+    if (!mdl)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    desc.reservedMem.start     = Start;
+    desc.reservedMem.size      = Size;
+    desc.reservedMem.name      = Name;
+    desc.reservedMem.requested = Requested;
+
+    allocator = _FindAllocator(Os, gcvALLOC_FLAG_LINUX_RESERVED_MEM);
+    if (!allocator)
+    {
+        gcmkPRINT("reserved-mem allocator not integrated!");
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    /* Call attach. */
+    gcmkONERROR(gcmALLOCATOR_Attach(allocator, &desc, mdl));
+
+    /* Assign alloator. */
+    mdl->allocator  = allocator;
+    mdl->bytes      = Size;
+    mdl->numPages   = Size >> PAGE_SHIFT;
+    mdl->contiguous = gcvTRUE;
+    mdl->addr       = gcvNULL;
+    mdl->dmaHandle  = Start;
+    mdl->gid        = 0;
+
+    /*
+     * Add this to a global list.
+     * Will be used by get physical address
+     * and mapuser pointer functions.
+     */
+    mutex_lock(&Os->mdlMutex);
+    list_add_tail(&mdl->link, &Os->mdlHead);
+    mutex_unlock(&Os->mdlMutex);
+
+    *MemoryHandle = (void *)mdl;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mdl)
+    {
+        gcmkVERIFY_OK(_DestroyMdl(mdl));
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+void
+gckOS_ReleaseReservedMemory(
+    gckOS Os,
+    gctPOINTER MemoryHandle
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)MemoryHandle;
+
+    if (mdl)
+    {
+        gcmkVERIFY_OK(_DestroyMdl(mdl));
+    }
+}
+
+/*******************************************************************************
+**
+**  gckOS_ReadRegister
+**
+**  Read data from a register.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 Address
+**          Address of register.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Data
+**          Pointer to a variable that receives the data read from the register.
+*/
+gceSTATUS
+gckOS_ReadRegister(
+    IN gckOS Os,
+    IN gctUINT32 Address,
+    OUT gctUINT32 * Data
+    )
+{
+    return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
+}
+
+gceSTATUS
+gckOS_ReadRegisterEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    OUT gctUINT32 * Data
+    )
+{
+    if (Address > Os->device->registerSizes[Core] - 1)
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    if (in_irq())
+    {
+        uint32_t data;
+
+        spin_lock(&Os->registerAccessLock);
+
+        if (unlikely(Os->clockStates[Core] == gcvFALSE))
+        {
+            spin_unlock(&Os->registerAccessLock);
+
+            /*
+             * Read register when external clock off:
+             * 1. In shared IRQ, read register may be called and that's not our irq.
+             */
+            return gcvSTATUS_GENERIC_IO;
+        }
+
+        data = readl(Os->device->registerBases[Core]);
+
+        if (unlikely((data & 0x3) == 0x3))
+        {
+            spin_unlock(&Os->registerAccessLock);
+
+            /*
+             * Read register when internal clock off:
+             * a. In shared IRQ, read register may be called and that's not our irq.
+             * b. In some condition, when ISR handled normal FE/PE, PM thread could
+             *    trun off internal clock before ISR read register of async FE. And
+             *    then IRQ handler will call read register with internal clock off.
+             *    So here we just skip for such case.
+             */
+            return gcvSTATUS_GENERIC_IO;
+        }
+
+        *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
+        spin_unlock(&Os->registerAccessLock);
+    }
+    else
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+        if (unlikely(Os->clockStates[Core] == gcvFALSE))
+        {
+            spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+            /*
+             * Read register when external clock off:
+             * 2. In non-irq context, register access should not be called,
+             *    otherwise it's driver bug.
+             */
+            printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+                   __func__, __LINE__, Core);
+            gcmkBUG_ON(1);
+            return gcvSTATUS_GENERIC_IO;
+        }
+
+        *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
+        spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+#if gcdDUMP_AHB_ACCESS
+        /* Dangerous to print in interrupt context, skip. */
+        gcmkPRINT("@[RD %d] %08x %08x", Core, Address, *Data);
+#endif
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_WriteRegisterEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data,
+    IN gctBOOL Dump
+    )
+{
+    if (Address > Os->device->registerSizes[Core] - 1)
+    {
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    if (in_irq())
+    {
+        spin_lock(&Os->registerAccessLock);
+
+        if (unlikely(Os->clockStates[Core] == gcvFALSE))
+        {
+            spin_unlock(&Os->registerAccessLock);
+
+            printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+                   __func__, __LINE__, Core);
+
+            /* Driver bug: register write when clock off. */
+            gcmkBUG_ON(1);
+            return gcvSTATUS_GENERIC_IO;
+        }
+
+        writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
+        spin_unlock(&Os->registerAccessLock);
+    }
+    else
+    {
+        unsigned long flags;
+
+        if (Dump)
+        {
+            gcmkDUMP(Os, "@[register.write %u 0x%05X 0x%08X]", Core, Address, Data);
+        }
+
+        spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+        if (unlikely(Os->clockStates[Core] == gcvFALSE))
+        {
+            spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+            printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+                      __func__, __LINE__, Core);
+
+            /* Driver bug: register write when clock off. */
+            gcmkBUG_ON(1);
+            return gcvSTATUS_GENERIC_IO;
+        }
+
+        writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
+        spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+#if gcdDUMP_AHB_ACCESS
+        /* Dangerous to print in interrupt context, skip. */
+        gcmkPRINT("@[WR %d] %08x %08x", Core, Address, Data);
+#endif
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_WriteRegister
+**
+**  Write data to a register.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 Address
+**          Address of register.
+**
+**      gctUINT32 Data
+**          Data for register.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_WriteRegister(
+    IN gckOS Os,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    )
+{
+    return _WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data, gcvTRUE);
+}
+
+gceSTATUS
+gckOS_WriteRegisterEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    )
+{
+    return _WriteRegisterEx(Os, Core, Address, Data, gcvTRUE);
+}
+
+gceSTATUS
+gckOS_WriteRegisterEx_NoDump(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    )
+{
+    return _WriteRegisterEx(Os, Core, Address, Data, gcvFALSE);
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetPageSize
+**
+**  Get the system's page size.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * PageSize
+**          Pointer to a variable that will receive the system's page size.
+*/
+gceSTATUS gckOS_GetPageSize(
+    IN gckOS Os,
+    OUT gctSIZE_T * PageSize
+    )
+{
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(PageSize != gcvNULL);
+
+    /* Return the page size. */
+    *PageSize = (gctSIZE_T) PAGE_SIZE;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*PageSize=0x%zx", *PageSize);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  _GetPhysicalAddressProcess
+**
+**  Get the physical system address of a corresponding virtual address for a
+**  given process.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gctPOINTER Logical
+**          Logical address.
+**
+**      gctUINT32 ProcessID
+**          Process ID.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Poinetr to a variable that receives the 32-bit physical adress.
+*/
+static gceSTATUS
+_GetPhysicalAddressProcess(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID,
+    OUT gctPHYS_ADDR_T * Address
+    )
+{
+    PLINUX_MDL mdl;
+    gceSTATUS status = gcvSTATUS_INVALID_ADDRESS;
+
+    gcmkHEADER_ARG("Os=%p Logical=%p ProcessID=%d", Os, Logical, ProcessID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    mutex_lock(&Os->mdlMutex);
+
+    if (Os->device->contiguousPhysical)
+    {
+        /* Try the contiguous memory pool. */
+        mdl = (PLINUX_MDL) Os->device->contiguousPhysical;
+
+        mutex_lock(&mdl->mapsMutex);
+
+        status = _ConvertLogical2Physical(Os, Logical, ProcessID, mdl, Address);
+
+        mutex_unlock(&mdl->mapsMutex);
+    }
+
+    if (gcmIS_ERROR(status))
+    {
+        /* Walk all MDLs. */
+        list_for_each_entry(mdl, &Os->mdlHead, link)
+        {
+            mutex_lock(&mdl->mapsMutex);
+
+            status = _ConvertLogical2Physical(Os, Logical, ProcessID, mdl, Address);
+
+            mutex_unlock(&mdl->mapsMutex);
+
+            if (gcmIS_SUCCESS(status))
+            {
+                break;
+            }
+        }
+    }
+
+    mutex_unlock(&Os->mdlMutex);
+
+    gcmkONERROR(status);
+    /* Success. */
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Address=%p", *Address);
+    return status;
+}
+
+
+
+/*******************************************************************************
+**
+**  gckOS_GetPhysicalAddress
+**
+**  Get the physical system address of a corresponding virtual address.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Logical
+**          Logical address.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Poinetr to a variable that receives the 32-bit physical adress.
+*/
+gceSTATUS
+gckOS_GetPhysicalAddress(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Address
+    )
+{
+    gceSTATUS status;
+    gctUINT32 processID;
+
+    gcmkHEADER_ARG("Os=%p Logical=%p", Os, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    /* Query page table of current process first. */
+    status = _QueryProcessPageTable(Logical, Address);
+
+    if (gcmIS_ERROR(status))
+    {
+        /* Get current process ID. */
+        processID = _GetProcessID();
+
+        /* Route through other function. */
+        gcmkONERROR(
+            _GetPhysicalAddressProcess(Os, Logical, processID, Address));
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Address=0x%llx", *Address);
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckOS_GetPhysicalFromHandle(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctUINT32 Offset,
+    OUT gctPHYS_ADDR_T * PhysicalAddress
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+    gckALLOCATOR allocator = mdl->allocator;
+
+    return gcmALLOCATOR_Physical(allocator, mdl, Offset, PhysicalAddress);
+}
+
+
+/*******************************************************************************
+**
+**  gckOS_UserLogicalToPhysical
+**
+**  Get the physical system address of a corresponding user virtual address.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Logical
+**          Logical address.
+**
+**  OUTPUT:
+**
+**      gctUINT32 * Address
+**          Pointer to a variable that receives the 32-bit physical address.
+*/
+gceSTATUS gckOS_UserLogicalToPhysical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Address
+    )
+{
+    return gckOS_GetPhysicalAddress(Os, Logical, Address);
+}
+
+gceSTATUS
+_ConvertLogical2Physical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    IN gctUINT32 ProcessID,
+    IN PLINUX_MDL Mdl,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    gckALLOCATOR allocator = Mdl->allocator;
+    gctUINT32 offset;
+    gceSTATUS status = gcvSTATUS_NOT_FOUND;
+    gctINT8_PTR vBase;
+
+    /* TASK_SIZE is userspace - kernelspace virtual memory split. */
+    if ((gctUINTPTR_T)Logical >= TASK_SIZE)
+    {
+        /* Kernel virtual address. */
+        vBase = Mdl->addr;
+    }
+    else
+    {
+        /* User virtual address. */
+        PLINUX_MDL_MAP map;
+
+        map   = FindMdlMap(Mdl, (gctINT) ProcessID);
+        vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr;
+    }
+
+    /* Is the given address within that range. */
+    if ((vBase != gcvNULL)
+    &&  ((gctINT8_PTR) Logical >= vBase)
+    &&  ((gctINT8_PTR) Logical <  vBase + Mdl->bytes)
+    )
+    {
+        offset = (gctINT8_PTR) Logical - vBase;
+
+        gcmALLOCATOR_Physical(allocator, Mdl, offset, Physical);
+
+        status = gcvSTATUS_OK;
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_MapPhysical
+**
+**  Map a physical address into kernel space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR_T Physical
+**          Physical address of the memory to map.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to map.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Logical
+**          Pointer to a variable that receives the base address of the mapped
+**          memory.
+*/
+gceSTATUS
+gckOS_MapPhysical(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER * Logical
+    )
+{
+    gctPOINTER logical;
+    PLINUX_MDL mdl;
+    gctBOOL found = gcvFALSE;
+    dma_addr_t physical = Physical;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Physical=0x%llx Bytes=0x%zx", Os, Physical, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    mutex_lock(&Os->mdlMutex);
+
+    /* Go through our mapping to see if we know this physical address already. */
+    list_for_each_entry(mdl, &Os->mdlHead, link)
+    {
+        if (mdl->dmaHandle != 0)
+        {
+            if ((physical >= mdl->dmaHandle)
+            &&  (physical <  mdl->dmaHandle + mdl->bytes)
+            &&  (mdl->addr != 0)
+            )
+            {
+                *Logical = mdl->addr + (physical - mdl->dmaHandle);
+                found = gcvTRUE;
+                break;
+            }
+        }
+    }
+
+    mutex_unlock(&Os->mdlMutex);
+
+    if (!found)
+    {
+        unsigned long pfn = physical >> PAGE_SHIFT;
+
+        if (pfn_valid(pfn))
+        {
+            gctUINT32 offset = physical & ~PAGE_MASK;
+            struct page ** pages;
+            struct page * page;
+            gctSIZE_T numPages;
+            gctSIZE_T i;
+            pgprot_t pgprot;
+
+            numPages = GetPageCount(PAGE_ALIGN(offset + Bytes), 0);
+
+            pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN);
+            if (!pages)
+            {
+                gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+            }
+
+            page = pfn_to_page(pfn);
+
+            for (i = 0; i < numPages; i++)
+            {
+                pages[i] = nth_page(page, i);
+            }
+
+#if gcdENABLE_BUFFERABLE_VIDEO_MEMORY
+            pgprot = pgprot_writecombine(PAGE_KERNEL);
+#else
+            pgprot = pgprot_noncached(PAGE_KERNEL);
+#endif
+
+            logical = vmap(pages, numPages, 0, pgprot);
+
+            kfree(pages);
+
+            if (logical == gcvNULL)
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_INFO, gcvZONE_OS,
+                    "%s(%d): Failed to vmap",
+                    __FUNCTION__, __LINE__
+                    );
+
+                /* Out of resources. */
+                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+            }
+
+            logical += offset;
+        }
+        else
+        {
+            /* Map memory as cached memory. */
+            request_mem_region(physical, Bytes, "MapRegion");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
+            logical = (gctPOINTER) ioremap(physical, Bytes);
+#else
+            logical = (gctPOINTER) ioremap_nocache(physical, Bytes);
+#endif
+            if (logical == gcvNULL)
+            {
+                gcmkTRACE_ZONE(
+                    gcvLEVEL_INFO, gcvZONE_OS,
+                    "%s(%d): Failed to ioremap",
+                    __FUNCTION__, __LINE__
+                    );
+
+                /* Out of resources. */
+                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+            }
+        }
+
+        /* Return pointer to mapped memory. */
+        *Logical = logical;
+    }
+
+OnError:
+    /* Success. */
+    gcmkFOOTER_ARG("*Logical=%p", *Logical);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UnmapPhysical
+**
+**  Unmap a previously mapped memory region from kernel memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Logical
+**          Pointer to the base address of the memory to unmap.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes to unmap.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UnmapPhysical(
+    IN gckOS Os,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    PLINUX_MDL  mdl;
+    gctBOOL found = gcvFALSE;
+
+    gcmkHEADER_ARG("Os=%p Logical=%p Bytes=0x%zx", Os, Logical, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+    mutex_lock(&Os->mdlMutex);
+
+    list_for_each_entry(mdl, &Os->mdlHead, link)
+    {
+        if (mdl->addr != gcvNULL)
+        {
+            if ((Logical >= (gctPOINTER)mdl->addr) &&
+                (Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->bytes)))
+            {
+                found = gcvTRUE;
+                break;
+            }
+        }
+    }
+
+    mutex_unlock(&Os->mdlMutex);
+
+    if (!found)
+    {
+        /* Unmap the memory. */
+        vunmap((void *)((unsigned long)Logical & PAGE_MASK));
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DeleteMutex
+**
+**  Delete a mutex.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Mutex
+**          Pointer to the mute to be deleted.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_DeleteMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Mutex=%p", Os, Mutex);
+
+    /* Validate the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+    /* Destroy the mutex. */
+    mutex_destroy((struct mutex *)Mutex);
+
+    /* Free the mutex structure. */
+    gcmkONERROR(gckOS_Free(Os, Mutex));
+
+OnError:
+    /* Return status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AcquireMutex
+**
+**  Acquire a mutex.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Mutex
+**          Pointer to the mutex to be acquired.
+**
+**      gctUINT32 Timeout
+**          Timeout value specified in milliseconds.
+**          Specify the value of gcvINFINITE to keep the thread suspended
+**          until the mutex has been acquired.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AcquireMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex,
+    IN gctUINT32 Timeout
+    )
+{
+    gceSTATUS status = gcvSTATUS_TIMEOUT;
+    gcmkHEADER_ARG("Os=%p Mutex=%p Timeout=%u", Os, Mutex, Timeout);
+
+    /* Validate the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+    if (Timeout == gcvINFINITE)
+    {
+        /* Lock the mutex. */
+        mutex_lock(Mutex);
+
+        /* Success. */
+        status = gcvSTATUS_OK;
+    }
+    else
+    {
+        for (;;)
+        {
+            /* Try to acquire the mutex. */
+            if (mutex_trylock(Mutex))
+            {
+                /* Success. */
+                status = gcvSTATUS_OK;
+                break;
+            }
+
+            if (Timeout-- == 0)
+            {
+                break;
+            }
+
+            /* Wait for 1 millisecond. */
+            gcmkVERIFY_OK(gckOS_Delay(Os, 1));
+        }
+    }
+
+    /* Timeout. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_ReleaseMutex
+**
+**  Release an acquired mutex.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Mutex
+**          Pointer to the mutex to be released.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_ReleaseMutex(
+    IN gckOS Os,
+    IN gctPOINTER Mutex
+    )
+{
+    gcmkHEADER_ARG("Os=%p Mutex=%p", Os, Mutex);
+
+    /* Validate the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+    /* Release the mutex. */
+    mutex_unlock(Mutex);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomicExchange
+**
+**  Atomically exchange a pair of 32-bit values.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      IN OUT gctINT32_PTR Target
+**          Pointer to the 32-bit value to exchange.
+**
+**      IN gctINT32 NewValue
+**          Specifies a new value for the 32-bit value pointed to by Target.
+**
+**      OUT gctINT32_PTR OldValue
+**          The old value of the 32-bit value pointed to by Target.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomicExchange(
+    IN gckOS Os,
+    IN OUT gctUINT32_PTR Target,
+    IN gctUINT32 NewValue,
+    OUT gctUINT32_PTR OldValue
+    )
+{
+    /* Exchange the pair of 32-bit values. */
+    *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomicExchangePtr
+**
+**  Atomically exchange a pair of pointers.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      IN OUT gctPOINTER * Target
+**          Pointer to the 32-bit value to exchange.
+**
+**      IN gctPOINTER NewValue
+**          Specifies a new value for the pointer pointed to by Target.
+**
+**      OUT gctPOINTER * OldValue
+**          The old value of the pointer pointed to by Target.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomicExchangePtr(
+    IN gckOS Os,
+    IN OUT gctPOINTER * Target,
+    IN gctPOINTER NewValue,
+    OUT gctPOINTER * OldValue
+    )
+{
+    /* Exchange the pair of pointers. */
+    *OldValue = (gctPOINTER)(gctUINTPTR_T) atomic_xchg((atomic_t *) Target, (int)(gctUINTPTR_T) NewValue);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomicSetMask
+**
+**  Atomically set mask to Atom
+**
+**  INPUT:
+**      IN OUT gctPOINTER Atom
+**          Pointer to the atom to set.
+**
+**      IN gctUINT32 Mask
+**          Mask to set.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomSetMask(
+    IN gctPOINTER Atom,
+    IN gctUINT32 Mask
+    )
+{
+    gctUINT32 oval, nval;
+
+    do
+    {
+        oval = atomic_read((atomic_t *) Atom);
+        nval = oval | Mask;
+    }
+    while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomClearMask
+**
+**  Atomically clear mask from Atom
+**
+**  INPUT:
+**      IN OUT gctPOINTER Atom
+**          Pointer to the atom to clear.
+**
+**      IN gctUINT32 Mask
+**          Mask to clear.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomClearMask(
+    IN gctPOINTER Atom,
+    IN gctUINT32 Mask
+    )
+{
+    gctUINT32 oval, nval;
+
+    do
+    {
+        oval = atomic_read((atomic_t *) Atom);
+        nval = oval & ~Mask;
+    }
+    while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomConstruct
+**
+**  Create an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Atom
+**          Pointer to a variable receiving the constructed atom.
+*/
+gceSTATUS
+gckOS_AtomConstruct(
+    IN gckOS Os,
+    OUT gctPOINTER * Atom
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+    /* Allocate the atom. */
+    gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom));
+
+    /* Initialize the atom. */
+    atomic_set((atomic_t *) *Atom, 0);
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Atom=%p", *Atom);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomDestroy
+**
+**  Destroy an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom to destroy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomDestroy(
+    IN gckOS Os,
+    OUT gctPOINTER Atom
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Atom=%p", Os, Atom);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+    /* Free the atom. */
+    gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom));
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomGet
+**
+**  Get the 32-bit value protected by an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable the receives the value of the atom.
+*/
+gceSTATUS
+gckOS_AtomGet(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    )
+{
+    /* Return the current value of atom. */
+    *Value = atomic_read((atomic_t *) Atom);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomSet
+**
+**  Set the 32-bit value protected by an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**      gctINT32 Value
+**          The value of the atom.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AtomSet(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    IN gctINT32 Value
+    )
+{
+    /* Set the current value of atom. */
+    atomic_set((atomic_t *) Atom, Value);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomIncrement
+**
+**  Atomically increment the 32-bit integer value inside an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable that receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomIncrement(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    )
+{
+    *Value = atomic_inc_return((atomic_t *) Atom) - 1;
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AtomDecrement
+**
+**  Atomically decrement the 32-bit integer value inside an atom.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gctPOINTER Atom
+**          Pointer to the atom.
+**
+**  OUTPUT:
+**
+**      gctINT32_PTR Value
+**          Pointer to a variable that receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomDecrement(
+    IN gckOS Os,
+    IN gctPOINTER Atom,
+    OUT gctINT32_PTR Value
+    )
+{
+    /* Decrement the atom. */
+    *Value = atomic_dec_return((atomic_t *) Atom) + 1;
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_Delay
+**
+**  Delay execution of the current thread for a number of milliseconds.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 Delay
+**          Delay to sleep, specified in milliseconds.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_Delay(
+    IN gckOS Os,
+    IN gctUINT32 Delay
+    )
+{
+    gcmkHEADER_ARG("Os=%p Delay=%u", Os, Delay);
+
+    if (Delay > 0)
+    {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+        ktime_t delay = ktime_set((Delay / MSEC_PER_SEC), (Delay % MSEC_PER_SEC) * NSEC_PER_MSEC);
+        __set_current_state(TASK_UNINTERRUPTIBLE);
+        schedule_hrtimeout(&delay, HRTIMER_MODE_REL);
+#else
+        msleep(Delay);
+#endif
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetTicks
+**
+**  Get the number of milliseconds since the system started.
+**
+**  INPUT:
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR Time
+**          Pointer to a variable to get time.
+**
+*/
+gceSTATUS
+gckOS_GetTicks(
+    OUT gctUINT32_PTR Time
+    )
+{
+     gcmkHEADER();
+
+    *Time = jiffies_to_msecs(jiffies);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_TicksAfter
+**
+**  Compare time values got from gckOS_GetTicks.
+**
+**  INPUT:
+**      gctUINT32 Time1
+**          First time value to be compared.
+**
+**      gctUINT32 Time2
+**          Second time value to be compared.
+**
+**  OUTPUT:
+**
+**      gctBOOL_PTR IsAfter
+**          Pointer to a variable to result.
+**
+*/
+gceSTATUS
+gckOS_TicksAfter(
+    IN gctUINT32 Time1,
+    IN gctUINT32 Time2,
+    OUT gctBOOL_PTR IsAfter
+    )
+{
+    gcmkHEADER();
+
+    *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetTime
+**
+**  Get the number of microseconds since the system started.
+**
+**  INPUT:
+**
+**  OUTPUT:
+**
+**      gctUINT64_PTR Time
+**          Pointer to a variable to get time.
+**
+*/
+gceSTATUS
+gckOS_GetTime(
+    OUT gctUINT64_PTR Time
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+    struct timespec64 tv;
+    gcmkHEADER();
+
+    /* Return the time of day in microseconds. */
+    ktime_get_real_ts64(&tv);
+    *Time = (tv.tv_sec * 1000000ULL) + (tv.tv_nsec / 1000);
+#else
+    struct timeval tv;
+    gcmkHEADER();
+
+     /* Return the time of day in microseconds. */
+    do_gettimeofday(&tv);
+    *Time = (tv.tv_sec * 1000000ULL) + tv.tv_usec;
+#endif
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_MemoryBarrier
+**
+**  Make sure the CPU has executed everything up to this point and the data got
+**  written to the specified pointer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Address
+**          Address of memory that needs to be barriered.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_MemoryBarrier(
+    IN gckOS Os,
+    IN gctPOINTER Address
+    )
+{
+    _MemoryBarrier();
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AllocatePagedMemory
+**
+**  Allocate memory from the paged pool.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 Flag
+**          Allocation attribute.
+**
+**      gctSIZE_T * Bytes
+**          Number of bytes to allocate.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Return number of bytes actually allocated.
+**
+**      gctUINT32 * Gid
+**          Save the global ID for the piece of allocated memory.
+**
+**      gctPHYS_ADDR * Physical
+**          Pointer to a variable that receives the physical address of the
+**          memory allocation.
+*/
+gceSTATUS
+gckOS_AllocatePagedMemory(
+    IN gckOS Os,
+    IN gctUINT32 Flag,
+    IN OUT gctSIZE_T * Bytes,
+    OUT gctUINT32 * Gid,
+    OUT gctPHYS_ADDR * Physical
+    )
+{
+    gctSIZE_T numPages;
+    PLINUX_MDL mdl = gcvNULL;
+    gctSIZE_T bytes;
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gckALLOCATOR allocator;
+    gctBOOL zoneDMA32 = gcvFALSE;
+
+    gcmkHEADER_ARG("Os=%p Flag=%x *Bytes=0x%zx", Os, Flag, *Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(*Bytes > 0);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+
+    bytes = gcmALIGN(*Bytes, PAGE_SIZE);
+
+    numPages = GetPageCount(bytes, 0);
+
+    mdl = _CreateMdl(Os);
+    if (mdl == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+#if defined(CONFIG_ZONE_DMA32) || defined(CONFIG_ZONE_DMA)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+    zoneDMA32 = gcvTRUE;
+#endif
+#endif
+
+    if ((Flag & gcvALLOC_FLAG_4GB_ADDR) && !zoneDMA32)
+    {
+        Flag &= ~gcvALLOC_FLAG_4GB_ADDR;
+    }
+
+#if defined(CONFIG_ZONE_DMA32) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) \
+    || !defined(LINUX_CMA_FSL) || !LINUX_CMA_FSL
+    /* redirect DMA32 pool for CMA LIMIT request */
+    if (Flag & gcvALLOC_FLAG_CMA_LIMIT)
+    {
+        Flag &= ~gcvALLOC_FLAG_CMA_LIMIT;
+        Flag |= gcvALLOC_FLAG_4GB_ADDR | gcvALLOC_FLAG_CONTIGUOUS;
+    }
+#else
+    if (Flag & gcvALLOC_FLAG_CMA_LIMIT)
+    {
+        if (Os->allocatorLimitMarker)
+        {
+            Flag &= ~gcvALLOC_FLAG_CACHEABLE;
+        }
+        else
+        {
+            Flag &= ~gcvALLOC_FLAG_CMA_LIMIT;
+            Flag |= gcvALLOC_FLAG_CONTIGUOUS;
+        }
+    }
+#endif
+
+    /* Walk all allocators. */
+    list_for_each_entry(allocator, &Os->allocatorList, link)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+                       "%s(%d) flag = %x allocator->capability = %x",
+                        __FUNCTION__, __LINE__, Flag, allocator->capability);
+
+        if ((Flag & allocator->capability) != Flag)
+        {
+            continue;
+        }
+
+        status = gcmALLOCATOR_Alloc(allocator, mdl, numPages, Flag);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            mdl->allocator = allocator;
+            break;
+        }
+    }
+
+    /* Check status. */
+    gcmkONERROR(status);
+
+    mdl->dmaHandle  = 0;
+    mdl->addr       = 0;
+    mdl->bytes      = bytes;
+    mdl->numPages   = numPages;
+    mdl->contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+    mdl->cacheable  = Flag & gcvALLOC_FLAG_CACHEABLE;
+
+    /*
+     * Add this to a global list.
+     * Will be used by get physical address
+     * and mapuser pointer functions.
+     */
+    mutex_lock(&Os->mdlMutex);
+    list_add_tail(&mdl->link, &Os->mdlHead);
+    mutex_unlock(&Os->mdlMutex);
+
+    /* Return allocated bytes. */
+    *Bytes = bytes;
+
+    if (Gid != gcvNULL)
+    {
+        *Gid = mdl->gid;
+    }
+
+    /* Return physical address. */
+    *Physical = (gctPHYS_ADDR) mdl;
+
+    /* Success. */
+    status = gcvSTATUS_OK;
+
+OnError:
+    if (gcmIS_ERROR(status) && mdl)
+    {
+        /* Free the memory. */
+        _DestroyMdl(mdl);
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Physical=%p", *Physical);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_FreePagedMemory
+**
+**  Free memory allocated from the paged pool.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of the allocation.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes of the allocation.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_FreePagedMemory(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Bytes=0x%zx", Os, Physical, Bytes);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+    /* Free the structure... */
+    gcmkVERIFY_OK(_DestroyMdl(mdl));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_LockPages
+**
+**  Lock memory allocated from the paged pool.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of the allocation.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes of the allocation.
+**
+**      gctBOOL Cacheable
+**          Cache mode of mapping.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Logical
+**          Pointer to a variable that receives the address of the mapped
+**          memory.
+*/
+gceSTATUS
+gckOS_LockPages(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctBOOL Cacheable,
+    OUT gctPOINTER * Logical
+    )
+{
+    gceSTATUS       status = gcvSTATUS_OK;
+    PLINUX_MDL      mdl;
+    PLINUX_MDL_MAP  mdlMap;
+    gckALLOCATOR    allocator;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Bytes=0x%zx", Os, Physical, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+    mdl = (PLINUX_MDL)Physical;
+    allocator = mdl->allocator;
+
+    mutex_lock(&mdl->mapsMutex);
+
+    mdlMap = FindMdlMap(mdl, _GetProcessID());
+
+    if (mdlMap == gcvNULL)
+    {
+        mdlMap = _CreateMdlMap(mdl, _GetProcessID());
+
+        if (mdlMap == gcvNULL)
+        {
+            gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+        }
+    }
+
+    if (mdlMap->vmaAddr == gcvNULL)
+    {
+        gcmkONERROR(gcmALLOCATOR_MapUser(allocator, mdl, mdlMap, Cacheable));
+    }
+
+    mdlMap->count++;
+
+    /* Convert pointer to MDL. */
+    *Logical = mdlMap->vmaAddr;
+
+OnError:
+    mutex_unlock(&mdl->mapsMutex);
+    /* Success. */
+    gcmkFOOTER_ARG("*Logical=%p", *Logical);
+    return status;
+}
+
+/* PageCount is GPU page count. */
+gceSTATUS
+gckOS_MapPagesEx(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctBOOL Writable,
+    IN gceVIDMEM_TYPE Type
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    PLINUX_MDL  mdl;
+    gctUINT32*  table;
+    gctUINT32   offset = 0;
+
+    gctUINT32 bytes = PageCount * 4;
+    gckALLOCATOR allocator;
+
+    gctUINT32 policyID = 0;
+    gctUINT32 axiConfig = 0;
+
+    gcsPLATFORM * platform = Os->device->platform;
+
+    gcmkHEADER_ARG("Os=%p Core=%d Physical=%p PageCount=0x%zx Address=0x%x PageTable=%p",
+                   Os, Core, Physical, PageCount, Address, PageTable);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+
+    /* Convert pointer to MDL. */
+    mdl = (PLINUX_MDL)Physical;
+
+    allocator = mdl->allocator;
+
+    gcmkASSERT(allocator != gcvNULL);
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): Physical->0x%X PageCount->0x%X",
+        __FUNCTION__, __LINE__,
+        (gctUINT32)(gctUINTPTR_T)Physical,
+        (gctUINT32)(gctUINTPTR_T)PageCount
+        );
+
+    table = (gctUINT32 *)PageTable;
+
+    if (platform && platform->ops->getPolicyID)
+    {
+        platform->ops->getPolicyID(platform, Type, &policyID, &axiConfig);
+
+        gcmkBUG_ON(policyID > 0x1F);
+
+        /* ID[3:0] is used in STLB. */
+        policyID &= 0xF;
+    }
+
+     /* Get all the physical addresses and store them in the page table. */
+
+    PageCount = PageCount / (PAGE_SIZE / 4096);
+
+    /* Try to get the user pages so DMA can happen. */
+    while (PageCount-- > 0)
+    {
+        gctUINT i;
+        gctPHYS_ADDR_T phys = ~0U;
+
+        gcmALLOCATOR_Physical(allocator, mdl, offset, &phys);
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys));
+
+        if (policyID)
+        {
+            /* AxUSER must not used for address currently. */
+            gcmkBUG_ON((phys >> 32) & 0xF);
+
+            /* Merge policyID to AxUSER[7:4].*/
+            phys |= ((gctPHYS_ADDR_T)policyID << 36);
+        }
+
+#ifdef CONFIG_IOMMU_SUPPORT
+        if (Os->iommu)
+        {
+            /* remove LSB. */
+            phys &= PAGE_MASK;
+
+            gcmkTRACE_ZONE(
+                gcvLEVEL_INFO, gcvZONE_OS,
+                "%s(%d): Setup mapping in IOMMU %x => %x",
+                __FUNCTION__, __LINE__,
+                Address + offset, phys
+                );
+
+            /* When use IOMMU, GPU use system PAGE_SIZE. */
+            gcmkONERROR(gckIOMMU_Map(
+                Os->iommu, Address + offset, phys, PAGE_SIZE));
+        }
+        else
+#endif
+        {
+            /* remove LSB. */
+            phys &= ~(4096ull - 1);
+
+#if gcdENABLE_VG
+            if (Core == gcvCORE_VG)
+            {
+                for (i = 0; i < (PAGE_SIZE / 4096); i++)
+                {
+                    gcmkONERROR(
+                        gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
+                            phys + (i * 4096),
+                            table++));
+                }
+            }
+            else
+#endif
+            {
+                for (i = 0; i < (PAGE_SIZE / 4096); i++)
+                {
+                    gcmkONERROR(
+                        gckMMU_SetPage(Os->device->kernels[Core]->mmu,
+                            phys + (i * 4096),
+                            gcvPAGE_TYPE_4K,
+                            Writable,
+                            table++));
+                }
+            }
+        }
+
+        offset += PAGE_SIZE;
+    }
+
+#if gcdENABLE_VG
+    if (Core == gcvCORE_VG)
+    {
+        gckVGMMU mmu = Os->device->kernels[gcvCORE_VG]->vg->mmu;
+        gctPHYS_ADDR mmuMdl = mmu->pageTablePhysical;
+
+        offset = (gctUINT8_PTR)PageTable - (gctUINT8_PTR)mmu->pageTableLogical;
+
+        gcmkVERIFY_OK(gckOS_CacheClean(
+            Os,
+            _GetProcessID(),
+            mmuMdl,
+            offset,
+            PageTable,
+            bytes
+            ));
+    }
+    else
+#  endif
+    {
+        gckMMU mmu = Os->device->kernels[Core]->mmu;
+        gcsADDRESS_AREA * area = &mmu->dynamicArea4K;
+
+        offset = (gctUINT8_PTR)PageTable - (gctUINT8_PTR)area->stlbLogical;
+
+        /* must be in dynamic area. */
+        gcmkASSERT(offset < area->stlbSize);
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(
+            Os->device->kernels[Core],
+            area->stlbVideoMem,
+            offset,
+            PageTable,
+            bytes
+            ));
+
+        if (mmu->mtlbVideoMem)
+        {
+            /* Flush MTLB table. */
+            gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(
+                Os->device->kernels[Core],
+                mmu->mtlbVideoMem,
+                offset,
+                mmu->mtlbLogical,
+                mmu->mtlbSize
+                ));
+        }
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/* PageCount is GPU page count. */
+gceSTATUS
+gckOS_UnmapPages(
+    IN gckOS Os,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address
+    )
+{
+#ifdef CONFIG_IOMMU_SUPPORT
+    if (Os->iommu)
+    {
+        gcmkVERIFY_OK(gckIOMMU_Unmap(
+            Os->iommu, Address, PageCount * 4096));
+    }
+#endif
+
+    return gcvSTATUS_OK;
+}
+
+/* Map 1M size GPU page */
+gceSTATUS
+gckOS_Map1MPages(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    IN gctUINT32 Address,
+    IN gctPOINTER PageTable,
+    IN gctBOOL Writable,
+    IN gceVIDMEM_TYPE Type
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    PLINUX_MDL mdl;
+    gctUINT32* table;
+    gctUINT32  offset = 0;
+
+    gctSIZE_T bytes = PageCount * 4;
+    gckALLOCATOR allocator;
+
+    gctUINT32 policyID = 0;
+    gctUINT32 axiConfig = 0;
+
+    gcsPLATFORM * platform = Os->device->platform;
+
+    gcmkHEADER_ARG("Os=%p Core=%d Physical=%p PageCount=0x%zx Address=0x%x PageTable=%p",
+                   Os, Core, Physical, PageCount, Address, PageTable);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+    gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+
+    /* Convert pointer to MDL. */
+    mdl = (PLINUX_MDL)Physical;
+
+    allocator = mdl->allocator;
+
+    gcmkASSERT(allocator != gcvNULL);
+
+    gcmkTRACE_ZONE(
+        gcvLEVEL_INFO, gcvZONE_OS,
+        "%s(%d): Physical->0x%X PageCount->0x%X",
+        __FUNCTION__, __LINE__,
+        (gctUINT32)(gctUINTPTR_T)Physical,
+        (gctUINT32)(gctUINTPTR_T)PageCount
+        );
+
+    table = (gctUINT32 *)PageTable;
+
+    if (platform && platform->ops->getPolicyID)
+    {
+        platform->ops->getPolicyID(platform, Type, &policyID, &axiConfig);
+
+        gcmkBUG_ON(policyID > 0x1F);
+
+        /* ID[3:0] is used in STLB. */
+        policyID &= 0xF;
+    }
+
+    while (PageCount-- > 0)
+    {
+        gctPHYS_ADDR_T phys = ~0U;
+
+        gcmALLOCATOR_Physical(allocator, mdl, offset, &phys);
+
+        gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys));
+
+        if (policyID)
+        {
+            /* AxUSER must not used for address currently. */
+            gcmkBUG_ON((phys >> 32) & 0xF);
+
+            /* Merge policyID to AxUSER[7:4].*/
+            phys |= ((gctPHYS_ADDR_T)policyID << 36);
+        }
+
+        /* Get the start physical of 1M page. */
+        phys &= ~((1 << 20) - 1);
+
+        gcmkONERROR(
+            gckMMU_SetPage(Os->device->kernels[Core]->mmu,
+            phys,
+            gcvPAGE_TYPE_1M,
+            Writable,
+            table++));
+
+        offset += gcd1M_PAGE_SIZE;
+    }
+
+    /* Flush the page table cache. */
+    {
+        gckMMU mmu = Os->device->kernels[Core]->mmu;
+        gcsADDRESS_AREA * area = &mmu->dynamicArea1M;
+
+        offset = (gctUINT8_PTR)PageTable - (gctUINT8_PTR)area->stlbLogical;
+
+        /* must be in dynamic area. */
+        gcmkASSERT(offset < area->stlbSize);
+
+        gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(
+            Os->device->kernels[Core],
+            area->stlbVideoMem,
+            offset,
+            PageTable,
+            bytes
+            ));
+
+        if (mmu->mtlbVideoMem)
+        {
+            /* Flush MTLB table. */
+            gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(
+                Os->device->kernels[Core],
+                mmu->mtlbVideoMem,
+                offset,
+                mmu->mtlbLogical,
+                mmu->mtlbSize
+                ));
+        }
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UnlockPages
+**
+**  Unlock memory allocated from the paged pool.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPHYS_ADDR Physical
+**          Physical address of the allocation.
+**
+**      gctSIZE_T Bytes
+**          Number of bytes of the allocation.
+**
+**      gctPOINTER Logical
+**          Address of the mapped memory.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UnlockPages(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Bytes,
+    IN gctPOINTER Logical
+    )
+{
+    PLINUX_MDL_MAP mdlMap;
+    PLINUX_MDL  mdl = (PLINUX_MDL)Physical;
+    gckALLOCATOR allocator = mdl->allocator;
+    gctINT pid = _GetProcessID();
+
+    gcmkHEADER_ARG("Os=%p Physical=%p Bytes=0x%zx Logical=%p",
+                   Os, Physical, Bytes, Logical);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+
+    mutex_lock(&mdl->mapsMutex);
+
+    list_for_each_entry(mdlMap, &mdl->mapsHead, link)
+    {
+        if ((mdlMap->vmaAddr != gcvNULL) && (mdlMap->pid == pid))
+        {
+            if (--mdlMap->count == 0)
+            {
+                gcmALLOCATOR_UnmapUser(
+                    allocator,
+                    mdl,
+                    mdlMap,
+                    mdl->bytes);
+
+                mdlMap->vmaAddr = gcvNULL;
+            }
+        }
+    }
+
+    mutex_unlock(&mdl->mapsMutex);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_MapUserPointer
+**
+**  Map a pointer from the user process into the kernel address space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Pointer
+**          Pointer in user process space that needs to be mapped.
+**
+**      gctSIZE_T Size
+**          Number of bytes that need to be mapped.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * KernelPointer
+**          Pointer to a variable receiving the mapped pointer in kernel address
+**          space.
+*/
+gceSTATUS
+gckOS_MapUserPointer(
+    IN gckOS Os,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size,
+    OUT gctPOINTER * KernelPointer
+    )
+{
+    gcmkHEADER_ARG("Os=%p Pointer=%p Size=0x%zx", Os, Pointer, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+    gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+
+    *KernelPointer = Pointer;
+
+    gcmkFOOTER_ARG("*KernelPointer=%p", *KernelPointer);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UnmapUserPointer
+**
+**  Unmap a user process pointer from the kernel address space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Pointer
+**          Pointer in user process space that needs to be unmapped.
+**
+**      gctSIZE_T Size
+**          Number of bytes that need to be unmapped.
+**
+**      gctPOINTER KernelPointer
+**          Pointer in kernel address space that needs to be unmapped.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UnmapUserPointer(
+    IN gckOS Os,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size,
+    IN gctPOINTER KernelPointer
+    )
+{
+    gcmkHEADER_ARG("Os=%p Pointer=%p Size=0x%zx KernelPointer=%p",
+                   Os, Pointer, Size, KernelPointer);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_QueryNeedCopy
+**
+**  Query whether the memory can be accessed or mapped directly or it has to be
+**  copied.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Process ID of the current process.
+**
+**  OUTPUT:
+**
+**      gctBOOL_PTR NeedCopy
+**          Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
+**          gcvFALSE if the memory can be accessed or mapped dircetly.
+*/
+gceSTATUS
+gckOS_QueryNeedCopy(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    OUT gctBOOL_PTR NeedCopy
+    )
+{
+    gcmkHEADER_ARG("Os=%p ProcessID=%d", Os, ProcessID);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL);
+
+    /* We need to copy data. */
+    *NeedCopy = gcvTRUE;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy);
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_CopyFromUserData
+**
+**  Copy data from user to kernel memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER KernelPointer
+**          Pointer to kernel memory.
+**
+**      gctPOINTER Pointer
+**          Pointer to user memory.
+**
+**      gctSIZE_T Size
+**          Number of bytes to copy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_CopyFromUserData(
+    IN gckOS Os,
+    IN gctPOINTER KernelPointer,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p KernelPointer=%p Pointer=%p Size=0x%zx",
+                   Os, KernelPointer, Pointer, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+
+    /* Copy data from user. */
+    if (copy_from_user(KernelPointer, Pointer, Size) != 0)
+    {
+        /* Could not copy all the bytes. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_CopyToUserData
+**
+**  Copy data from kernel to user memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER KernelPointer
+**          Pointer to kernel memory.
+**
+**      gctPOINTER Pointer
+**          Pointer to user memory.
+**
+**      gctSIZE_T Size
+**          Number of bytes to copy.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_CopyToUserData(
+    IN gckOS Os,
+    IN gctPOINTER KernelPointer,
+    IN gctPOINTER Pointer,
+    IN gctSIZE_T Size
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p KernelPointer=%p Pointer=%p Size=0x%zx",
+                   Os, KernelPointer, Pointer, Size);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Size > 0);
+
+    /* Copy data to user. */
+    if (copy_to_user(Pointer, KernelPointer, Size) != 0)
+    {
+        /* Could not copy all the bytes. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_WriteMemory
+**
+**  Write data to a memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctPOINTER Address
+**          Address of the memory to write to.
+**
+**      gctUINT32 Data
+**          Data for register.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_WriteMemory(
+    IN gckOS Os,
+    IN gctPOINTER Address,
+    IN gctUINT32 Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Address=%p Data=%u", Os, Address, Data);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    /* Write memory. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+    if (access_ok(Address, 4))
+#else
+    if (access_ok(VERIFY_WRITE, Address, 4))
+#endif
+    {
+        /* User address. */
+        if (put_user(Data, (gctUINT32*)Address))
+        {
+            gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+        }
+    }
+    else if (virt_addr_valid(Address) || is_vmalloc_addr(Address))
+    {
+        /* Kernel address. */
+        *(gctUINT32 *)Address = Data;
+    }
+    else
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckOS_ReadMappedPointer(
+    IN gckOS Os,
+    IN gctPOINTER Address,
+    IN gctUINT32_PTR Data
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcmkHEADER_ARG("Os=%p Address=%p Data=%u", Os, Address, Data);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+    /* Write memory. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
+    if (access_ok(Address, 4))
+#else
+    if (access_ok(VERIFY_READ, Address, 4))
+#endif
+    {
+        /* User address. */
+        if (get_user(*Data, (gctUINT32*)Address))
+        {
+            gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+        }
+    }
+    else
+    {
+        /* Kernel address. */
+        *Data = *(gctUINT32_PTR)Address;
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetBaseAddress
+**
+**  Get the base address for the physical memory.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR BaseAddress
+**          Pointer to a variable that will receive the base address.
+*/
+gceSTATUS
+gckOS_GetBaseAddress(
+    IN gckOS Os,
+    OUT gctUINT32_PTR BaseAddress
+    )
+{
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
+
+    /* Return base address. */
+    *BaseAddress = Os->device->baseAddress;
+
+    /* Success. */
+    gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_SuspendInterrupt(
+    IN gckOS Os
+    )
+{
+    return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR);
+}
+
+gceSTATUS
+gckOS_SuspendInterruptEx(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    gcmkHEADER_ARG("Os=%p Core=%d", Os, Core);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    disable_irq(Os->device->irqLines[Core]);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_ResumeInterrupt(
+    IN gckOS Os
+    )
+{
+    return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR);
+}
+
+gceSTATUS
+gckOS_ResumeInterruptEx(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    gcmkHEADER_ARG("Os=%p Core=%d", Os, Core);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    enable_irq(Os->device->irqLines[Core]);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_MemCopy(
+    IN gctPOINTER Destination,
+    IN gctCONST_POINTER Source,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcmkHEADER_ARG("Destination=%p Source=%p Bytes=0x%zx",
+                   Destination, Source, Bytes);
+
+    gcmkVERIFY_ARGUMENT(Destination != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Source != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+    memcpy(Destination, Source, Bytes);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_ZeroMemory(
+    IN gctPOINTER Memory,
+    IN gctSIZE_T Bytes
+    )
+{
+    gcmkHEADER_ARG("Memory=%p Bytes=0x%zx", Memory, Bytes);
+
+    gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+    memset(Memory, 0, Bytes);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+********************************* Cache Control ********************************
+*******************************************************************************/
+static gceSTATUS
+_CacheOperation(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    IN gctPHYS_ADDR Handle,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes,
+    IN gceCACHEOPERATION Operation
+    )
+{
+    PLINUX_MDL mdl = (PLINUX_MDL)Handle;
+    PLINUX_MDL_MAP mdlMap = gcvNULL;
+    gckALLOCATOR allocator;
+
+    if (!mdl || !mdl->allocator)
+    {
+        gcmkPRINT("[galcore]: %s: Logical=%p no mdl", __FUNCTION__, Logical);
+        return gcvSTATUS_INVALID_ARGUMENT;
+    }
+
+    allocator = mdl->allocator;
+
+    if (allocator->ops->Cache)
+    {
+        if (ProcessID)
+        {
+            mutex_lock(&mdl->mapsMutex);
+
+            mdlMap = FindMdlMap(mdl, ProcessID);
+
+            mutex_unlock(&mdl->mapsMutex);
+        }
+
+        if (ProcessID && mdlMap == gcvNULL)
+        {
+            return gcvSTATUS_INVALID_ARGUMENT;
+        }
+
+        if ((!ProcessID && mdl->cacheable) ||
+            (mdlMap && mdlMap->cacheable))
+        {
+            gcmALLOCATOR_Cache(allocator,
+                mdl, Offset, Logical, Bytes, Operation);
+
+            return gcvSTATUS_OK;
+        }
+    }
+
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**  gckOS_CacheClean
+**
+**  Clean the cache for the specified addresses.  The GPU is going to need the
+**  data.  If the system is allocating memory as non-cachable, this function can
+**  be ignored.
+**
+**  ARGUMENTS:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Process ID Logical belongs.
+**
+**      gctPHYS_ADDR Handle
+**          Physical address handle.  If gcvNULL it is video memory.
+**
+**      gctSIZE_T Offset
+**          Offset to this memory block.
+**
+**      gctPOINTER Logical
+**          Logical address to flush.
+**
+**      gctSIZE_T Bytes
+**          Size of the address range in bytes to flush.
+*/
+
+/*
+
+Following patch can be applied to kernel in case cache API is not exported.
+
+diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
+index 054b491..e9e74ec 100644
+--- a/arch/arm/mm/proc-syms.c
++++ b/arch/arm/mm/proc-syms.c
+@@ -30,6 +30,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all);
+ EXPORT_SYMBOL(__cpuc_flush_user_range);
+ EXPORT_SYMBOL(__cpuc_coherent_kern_range);
+ EXPORT_SYMBOL(__cpuc_flush_dcache_area);
++EXPORT_SYMBOL(__glue(_CACHE,_dma_map_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_unmap_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_flush_range));
+ #else
+ EXPORT_SYMBOL(cpu_cache);
+ #endif
+
+*/
+gceSTATUS
+gckOS_CacheClean(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    IN gctPHYS_ADDR Handle,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Os=%p ProcessID=%d Handle=%p Offset=0x%llx Logical=%p Bytes=0x%zx",
+                   Os, ProcessID, Handle, Offset, Logical, Bytes);
+
+    gcmkONERROR(_CacheOperation(Os, ProcessID,
+                                Handle, Offset, Logical, Bytes,
+                                gcvCACHE_CLEAN));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckOS_CacheInvalidate
+**
+**  Invalidate the cache for the specified addresses. The GPU is going to need
+**  data.  If the system is allocating memory as non-cachable, this function can
+**  be ignored.
+**
+**  ARGUMENTS:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Process ID Logical belongs.
+**
+**      gctPHYS_ADDR Handle
+**          Physical address handle.  If gcvNULL it is video memory.
+**
+**      gctPOINTER Logical
+**          Logical address to flush.
+**
+**      gctSIZE_T Bytes
+**          Size of the address range in bytes to flush.
+*/
+gceSTATUS
+gckOS_CacheInvalidate(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    IN gctPHYS_ADDR Handle,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Os=%p ProcessID=%d Handle=%p Offset=0x%llx Logical=%p Bytes=0x%zx",
+                   Os, ProcessID, Handle, Offset, Logical, Bytes);
+
+    gcmkONERROR(_CacheOperation(Os, ProcessID,
+                                Handle, Offset, Logical, Bytes,
+                                gcvCACHE_INVALIDATE));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**  gckOS_CacheFlush
+**
+**  Clean the cache for the specified addresses and invalidate the lines as
+**  well.  The GPU is going to need and modify the data.  If the system is
+**  allocating memory as non-cachable, this function can be ignored.
+**
+**  ARGUMENTS:
+**
+**      gckOS Os
+**          Pointer to gckOS object.
+**
+**      gctUINT32 ProcessID
+**          Process ID Logical belongs.
+**
+**      gctPHYS_ADDR Handle
+**          Physical address handle.  If gcvNULL it is video memory.
+**
+**      gctPOINTER Logical
+**          Logical address to flush.
+**
+**      gctSIZE_T Bytes
+**          Size of the address range in bytes to flush.
+*/
+gceSTATUS
+gckOS_CacheFlush(
+    IN gckOS Os,
+    IN gctUINT32 ProcessID,
+    IN gctPHYS_ADDR Handle,
+    IN gctSIZE_T Offset,
+    IN gctPOINTER Logical,
+    IN gctSIZE_T Bytes
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Os=%p ProcessID=%d Handle=%p Offset=0x%llx Logical=%p Bytes=0x%zx",
+                   Os, ProcessID, Handle, Offset, Logical, Bytes);
+
+    gcmkONERROR(_CacheOperation(Os, ProcessID,
+                                Handle, Offset, Logical, Bytes,
+                                gcvCACHE_FLUSH));
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+********************************* Broadcasting *********************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckOS_Broadcast
+**
+**  System hook for broadcast events from the kernel driver.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**      gceBROADCAST Reason
+**          Reason for the broadcast.  Can be one of the following values:
+**
+**              gcvBROADCAST_GPU_IDLE
+**                  Broadcasted when the kernel driver thinks the GPU might be
+**                  idle.  This can be used to handle power management.
+**
+**              gcvBROADCAST_GPU_COMMIT
+**                  Broadcasted when any client process commits a command
+**                  buffer.  This can be used to handle power management.
+**
+**              gcvBROADCAST_GPU_STUCK
+**                  Broadcasted when the kernel driver hits the timeout waiting
+**                  for the GPU.
+**
+**              gcvBROADCAST_FIRST_PROCESS
+**                  First process is trying to connect to the kernel.
+**
+**              gcvBROADCAST_LAST_PROCESS
+**                  Last process has detached from the kernel.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_Broadcast(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gceBROADCAST Reason
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gceCHIPPOWERSTATE state;
+
+    gcmkHEADER_ARG("Os=%p Hardware=%p Reason=%d", Os, Hardware, Reason);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    switch (Reason)
+    {
+    case gcvBROADCAST_FIRST_PROCESS:
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached");
+        break;
+
+    case gcvBROADCAST_LAST_PROCESS:
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached");
+
+        /* Put GPU OFF. */
+        gcmkONERROR(
+            gckHARDWARE_SetPowerState(Hardware,
+                                      gcvPOWER_OFF_BROADCAST));
+        break;
+
+    case gcvBROADCAST_GPU_IDLE:
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle.");
+#if gcdPOWER_SUSPEND_WHEN_IDLE
+        state = gcvPOWER_SUSPEND_BROADCAST;
+#else
+        state = gcvPOWER_IDLE_BROADCAST;
+#endif
+
+        /* Put GPU IDLE or SUSPEND. */
+        gcmkONERROR(
+            gckHARDWARE_SetPowerState(Hardware, state));
+
+        /* Add idle process DB. */
+        gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
+                                           1,
+                                           gcvDB_IDLE,
+                                           gcvNULL, gcvNULL, 0));
+        break;
+
+    case gcvBROADCAST_GPU_COMMIT:
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived.");
+
+        /* Add busy process DB. */
+        gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
+                                           0,
+                                           gcvDB_IDLE,
+                                           gcvNULL, gcvNULL, 0));
+
+        /* Put GPU ON. */
+        gcmkONERROR(
+            gckHARDWARE_SetPowerState(Hardware, gcvPOWER_ON_AUTO));
+        break;
+
+    case gcvBROADCAST_GPU_STUCK:
+        gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n");
+        gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
+        break;
+
+    case gcvBROADCAST_AXI_BUS_ERROR:
+        gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n");
+        gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware));
+        gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
+        break;
+
+    case gcvBROADCAST_OUT_OF_MEMORY:
+        gcmkTRACE_N(gcvLEVEL_INFO, 0, "gcvBROADCAST_OUT_OF_MEMORY\n");
+
+        status = _ShrinkMemory(Os);
+
+        if (status == gcvSTATUS_NOT_SUPPORTED)
+        {
+            goto OnError;
+        }
+
+        gcmkONERROR(status);
+
+        break;
+
+    default:
+        /* Skip unimplemented broadcast. */
+        break;
+    }
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_BroadcastHurry
+**
+**  The GPU is running too slow.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**      gctUINT Urgency
+**          The higher the number, the higher the urgency to speed up the GPU.
+**          The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_BroadcastHurry(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT Urgency
+    )
+{
+    gcmkHEADER_ARG("Os=%p Hardware=%p Urgency=%u", Os, Hardware, Urgency);
+
+    /* Do whatever you need to do to speed up the GPU now. */
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_BroadcastCalibrateSpeed
+**
+**  Calibrate the speed of the GPU.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gckHARDWARE Hardware
+**          Pointer to the gckHARDWARE object.
+**
+**      gctUINT Idle, Time
+**          Idle/Time will give the percentage the GPU is idle, so you can use
+**          this to calibrate the working point of the GPU.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_BroadcastCalibrateSpeed(
+    IN gckOS Os,
+    IN gckHARDWARE Hardware,
+    IN gctUINT Idle,
+    IN gctUINT Time
+    )
+{
+    gcmkHEADER_ARG("Os=%p Hardware=%p Idle=%u Time=%u",
+                   Os, Hardware, Idle, Time);
+
+    /* Do whatever you need to do to callibrate the GPU speed. */
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+********************************** Semaphores **********************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+**  gckOS_CreateSemaphore
+**
+**  Create a semaphore.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Semaphore
+**          Pointer to the variable that will receive the created semaphore.
+*/
+gceSTATUS
+gckOS_CreateSemaphore(
+    IN gckOS Os,
+    OUT gctPOINTER * Semaphore
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    struct semaphore *sem = gcvNULL;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Allocate the semaphore structure. */
+    sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
+    if (sem == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Initialize the semaphore. */
+    sema_init(sem, 1);
+
+    /* Return to caller. */
+    *Semaphore = (gctPOINTER) sem;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_AcquireSemaphore
+**
+**  Acquire a semaphore.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Semaphore
+**          Pointer to the semaphore thet needs to be acquired.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_AcquireSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    )
+{
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Acquire the semaphore. */
+    down((struct semaphore *) Semaphore);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_TryAcquireSemaphore
+**
+**  Try to acquire a semaphore.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Semaphore
+**          Pointer to the semaphore thet needs to be acquired.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_TryAcquireSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Acquire the semaphore. */
+    if (down_trylock((struct semaphore *) Semaphore))
+    {
+        /* Timeout. */
+        status = gcvSTATUS_TIMEOUT;
+    }
+
+    /* Success. */
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_ReleaseSemaphore
+**
+**  Release a previously acquired semaphore.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Semaphore
+**          Pointer to the semaphore thet needs to be released.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_ReleaseSemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    )
+{
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Release the semaphore. */
+    up((struct semaphore *) Semaphore);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DestroySemaphore
+**
+**  Destroy a semaphore.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Semaphore
+**          Pointer to the semaphore thet needs to be destroyed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_DestroySemaphore(
+    IN gckOS Os,
+    IN gctPOINTER Semaphore
+    )
+{
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+
+     /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Free the sempahore structure. */
+    kfree(Semaphore);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetProcessID
+**
+**  Get current process ID.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR ProcessID
+**          Pointer to the variable that receives the process ID.
+*/
+gceSTATUS
+gckOS_GetProcessID(
+    OUT gctUINT32_PTR ProcessID
+    )
+{
+    /* Get process ID. */
+    *ProcessID = _GetProcessID();
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_GetThreadID
+**
+**  Get current thread ID.
+**
+**  INPUT:
+**
+**      Nothing.
+**
+**  OUTPUT:
+**
+**      gctUINT32_PTR ThreadID
+**          Pointer to the variable that receives the thread ID.
+*/
+gceSTATUS
+gckOS_GetThreadID(
+    OUT gctUINT32_PTR ThreadID
+    )
+{
+    /* Get thread ID. */
+    if (ThreadID != gcvNULL)
+    {
+        *ThreadID = _GetThreadID();
+    }
+
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetGPUPower
+**
+**  Set the power of the GPU on or off.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gceCORE Core
+**          GPU whose power is set.
+**
+**      gctBOOL Clock
+**          gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
+**
+**      gctBOOL Power
+**          gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUPower(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctBOOL Clock,
+    IN gctBOOL Power
+    )
+{
+    gcsPLATFORM * platform;
+
+    gctBOOL powerChange = gcvFALSE;
+    gctBOOL clockChange = gcvFALSE;
+
+    gcmkHEADER_ARG("Os=%p Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    platform = Os->device->platform;
+
+    powerChange = (Power != Os->powerStates[Core]);
+
+    clockChange = (Clock != Os->clockStates[Core]);
+
+    if (powerChange && (Power == gcvTRUE))
+    {
+        if (platform && platform->ops->setPower)
+        {
+            gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
+        }
+
+        Os->powerStates[Core] = Power;
+    }
+
+    if (clockChange)
+    {
+        unsigned long flags;
+
+        if (!Clock)
+        {
+            spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+            /* Record clock off, ahead. */
+            Os->clockStates[Core] = gcvFALSE;
+
+            spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+        }
+
+        if (platform && platform->ops->setClock)
+        {
+            gcmkVERIFY_OK(platform->ops->setClock(platform, Core, Clock));
+        }
+
+        if (Clock)
+        {
+            spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+            /* Record clock on, behind. */
+            Os->clockStates[Core] = gcvTRUE;
+
+            spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+        }
+    }
+
+    if (powerChange && (Power == gcvFALSE))
+    {
+        if (platform && platform->ops->setPower)
+        {
+            gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
+        }
+
+        Os->powerStates[Core] = Power;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_ResetGPU
+**
+**  Reset the GPU.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gckCORE Core
+**          GPU whose power is set.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_ResetGPU(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+    gcsPLATFORM * platform;
+
+    gcmkHEADER_ARG("Os=%p Core=%d", Os, Core);
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    platform = Os->device->platform;
+
+    if (platform && platform->ops->reset)
+    {
+        status = platform->ops->reset(platform, Core);
+    }
+
+    gcmkFOOTER_NO();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_PrepareGPUFrequency
+**
+**  Prepare to set GPU frequency and voltage.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gckCORE Core
+**          GPU whose frequency and voltage will be set.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_PrepareGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_FinishGPUFrequency
+**
+**  Finish GPU frequency setting.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gckCORE Core
+**          GPU whose frequency and voltage is set.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_FinishGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_QueryGPUFrequency
+**
+**  Query the current frequency of the GPU.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gckCORE Core
+**          GPU whose power is set.
+**
+**      gctUINT32 * Frequency
+**          Pointer to a gctUINT32 to obtain current frequency, in MHz.
+**
+**      gctUINT8 * Scale
+**          Pointer to a gctUINT8 to obtain current scale(1 - 64).
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_QueryGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctUINT32 * Frequency,
+    OUT gctUINT8 * Scale
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_SetGPUFrequency
+**
+**  Set frequency and voltage of the GPU.
+**
+**      1. DVFS manager gives the target scale of full frequency, BSP must find
+**         a real frequency according to this scale and board's configure.
+**
+**      2. BSP should find a suitable voltage for this frequency.
+**
+**      3. BSP must make sure setting take effect before this function returns.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to a gckOS object.
+**
+**      gckCORE Core
+**          GPU whose power is set.
+**
+**      gctUINT8 Scale
+**          Target scale of full frequency, range is [1, 64]. 1 means 1/64 of
+**          full frequency and 64 means 64/64 of full frequency.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUFrequency(
+    IN gckOS Os,
+    IN gceCORE Core,
+    IN gctUINT8 Scale
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*----- Profile --------------------------------------------------------------*/
+
+gceSTATUS
+gckOS_GetProfileTick(
+    OUT gctUINT64_PTR Tick
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
+    struct timespec64 time;
+
+    ktime_get_ts64(&time);
+#else
+    struct timespec time;
+
+    ktime_get_ts(&time);
+#endif
+    *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_QueryProfileTickRate(
+    OUT gctUINT64_PTR TickRate
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
+    struct timespec64 res;
+#else
+    struct timespec res;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+    res.tv_sec = 0;
+    res.tv_nsec = hrtimer_resolution;
+#else
+    hrtimer_get_res(CLOCK_MONOTONIC, &res);
+#endif
+
+    *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
+
+    return gcvSTATUS_OK;
+}
+
+gctUINT32
+gckOS_ProfileToMS(
+    IN gctUINT64 Ticks
+    )
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
+    return div_u64(Ticks, 1000000);
+#else
+    gctUINT64 rem = Ticks;
+    gctUINT64 b = 1000000;
+    gctUINT64 res, d = 1;
+    gctUINT32 high = rem >> 32;
+
+    /* Reduce the thing a bit first */
+    res = 0;
+    if (high >= 1000000)
+    {
+        high /= 1000000;
+        res   = (gctUINT64) high << 32;
+        rem  -= (gctUINT64) (high * 1000000) << 32;
+    }
+
+    while (((gctINT64) b > 0) && (b < rem))
+    {
+        b <<= 1;
+        d <<= 1;
+    }
+
+    do
+    {
+        if (rem >= b)
+        {
+            rem -= b;
+            res += d;
+        }
+
+        b >>= 1;
+        d >>= 1;
+    }
+    while (d);
+
+    return (gctUINT32) res;
+#endif
+}
+
+/******************************************************************************\
+******************************* Signal Management ******************************
+\******************************************************************************/
+
+#undef _GC_OBJ_ZONE
+#define _GC_OBJ_ZONE    gcvZONE_SIGNAL
+
+/*******************************************************************************
+**
+**  gckOS_CreateSignal
+**
+**  Create a new signal.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctBOOL ManualReset
+**          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
+**          order to set the signal to nonsignaled state.
+**          If set to gcvFALSE, the signal will automatically be set to
+**          nonsignaled state by gckOS_WaitSignal function.
+**
+**  OUTPUT:
+**
+**      gctSIGNAL * Signal
+**          Pointer to a variable receiving the created gctSIGNAL.
+*/
+gceSTATUS
+gckOS_CreateSignal(
+    IN gckOS Os,
+    IN gctBOOL ManualReset,
+    OUT gctSIGNAL * Signal
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsSIGNAL_PTR signal = gcvNULL;
+
+    gcmkHEADER_ARG("Os=%p ManualReset=%d", Os, ManualReset);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+    /* Create an event structure. */
+    signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN);
+
+    if (signal == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Save the process ID. */
+    signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID();
+
+    signal->done = 0;
+    init_waitqueue_head(&signal->wait);
+    spin_lock_init(&signal->lock);
+    signal->manualReset = ManualReset;
+
+    atomic_set(&signal->ref, 1);
+
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+    signal->timeline = gcvNULL;
+#  else
+    signal->fence = gcvNULL;
+#  endif
+#endif
+
+    gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
+
+    *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id;
+
+OnError:
+    if (gcmIS_ERROR(status) && signal)
+    {
+        kfree(signal);
+    }
+
+    gcmkFOOTER_ARG("*Signal=%p", *Signal);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DestroySignal
+**
+**  Destroy a signal.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to the gctSIGNAL.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_DestroySignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsSIGNAL_PTR signal;
+    gctBOOL acquired = gcvFALSE;
+    unsigned long flags = 0;
+
+    gcmkHEADER_ARG("Os=%p Signal=%p", Os, Signal);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+    if(in_irq()){
+        spin_lock(&Os->signalLock);
+    }else{
+        spin_lock_irqsave(&Os->signalLock, flags);
+    }
+    acquired = gcvTRUE;
+
+    gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+    gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+    if (atomic_dec_and_test(&signal->ref))
+    {
+        gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
+
+        /* Free the sgianl. */
+        kfree(signal);
+    }
+
+    if(in_irq()){
+        spin_unlock(&Os->signalLock);
+    }else{
+        spin_unlock_irqrestore(&Os->signalLock, flags);
+    }
+    acquired = gcvFALSE;
+
+OnError:
+    if (acquired)
+    {
+        /* Release the mutex. */
+        if(in_irq()){
+            spin_unlock(&Os->signalLock);
+        }else{
+            spin_unlock_irqrestore(&Os->signalLock, flags);
+        }
+    }
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_Signal
+**
+**  Set a state of the specified signal.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to the gctSIGNAL.
+**
+**      gctBOOL State
+**          If gcvTRUE, the signal will be set to signaled state.
+**          If gcvFALSE, the signal will be set to nonsignaled state.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_Signal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctBOOL State
+    )
+{
+    gceSTATUS status;
+    gcsSIGNAL_PTR signal;
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+    struct sync_timeline * timeline = gcvNULL;
+#  else
+    struct dma_fence * fence = gcvNULL;
+#  endif
+#endif
+    unsigned long flags = 0;
+
+    gcmkHEADER_ARG("Os=%p Signal=%p State=%d", Os, Signal, State);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+    spin_lock_irqsave(&Os->signalLock, flags);
+
+    status = _QueryIntegerId(&Os->signalDB,
+                             (gctUINT32)(gctUINTPTR_T)Signal,
+                             (gctPOINTER)&signal);
+
+    if (gcmIS_ERROR(status))
+    {
+        spin_unlock_irqrestore(&Os->signalLock, flags);
+        gcmkONERROR(status);
+    }
+
+    /*
+     * Signal saved in event is not referenced. Inc reference here to avoid
+     * concurrent issue: signaling the signal while another thread is destroying
+     * it.
+     */
+    atomic_inc(&signal->ref);
+
+    spin_unlock_irqrestore(&Os->signalLock, flags);
+
+    gcmkONERROR(status);
+
+    gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+    spin_lock(&signal->lock);
+
+    if (State)
+    {
+        signal->done = 1;
+
+        wake_up(&signal->wait);
+
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+        timeline = signal->timeline;
+#  else
+        fence = signal->fence;
+        signal->fence = NULL;
+#  endif
+#endif
+    }
+    else
+    {
+        signal->done = 0;
+    }
+
+    spin_unlock(&signal->lock);
+
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+    /* Signal timeline. */
+    if (timeline)
+    {
+        sync_timeline_signal(timeline);
+    }
+#  else
+    if (fence)
+    {
+        dma_fence_signal(fence);
+        dma_fence_put(fence);
+    }
+#  endif
+#endif
+
+    spin_lock_irqsave(&Os->signalLock, flags);
+
+    if (atomic_dec_and_test(&signal->ref))
+    {
+        gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
+
+        /* Free the sgianl. */
+        kfree(signal);
+    }
+
+    spin_unlock_irqrestore(&Os->signalLock, flags);
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UserSignal
+**
+**  Set the specified signal which is owned by a process to signaled state.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to the gctSIGNAL.
+**
+**      gctHANDLE Process
+**          Handle of process owning the signal.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_UserSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctHANDLE Process
+    )
+{
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Os=%p Signal=%p Process=%p", Os, Signal, Process);
+
+    /* Signal. */
+    status = gckOS_Signal(Os, Signal, gcvTRUE);
+
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_WaitSignal
+**
+**  Wait for a signal to become signaled.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to the gctSIGNAL.
+**
+**      gctUINT32 Wait
+**          Number of milliseconds to wait.
+**          Pass the value of gcvINFINITE for an infinite wait.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_WaitSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctBOOL Interruptable,
+    IN gctUINT32 Wait
+    )
+{
+    gceSTATUS status;
+    gcsSIGNAL_PTR signal = gcvNULL;
+    int done;
+
+    gcmkHEADER_ARG("Os=%p Signal=%p Wait=0x%08X", Os, Signal, Wait);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+    gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+    gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+    spin_lock(&signal->lock);
+    done = signal->done;
+    spin_unlock(&signal->lock);
+
+    /*
+     * Do not need to lock below:
+     * 1. If signal already done, return immediately.
+     * 2. If signal not done, wait_event_xxx will handle correctly even read of
+     *    signal->done is not atomic.
+     *
+     * Rest signal->done do not require lock either:
+     * No other thread can query/wait auto-reseted signal, because that is
+     * logic error.
+     */
+    if (done)
+    {
+        status = gcvSTATUS_OK;
+
+        if (!signal->manualReset)
+        {
+            signal->done = 0;
+        }
+    }
+    else if (Wait == 0)
+    {
+        status = gcvSTATUS_TIMEOUT;
+    }
+    else
+    {
+        /* Convert wait to milliseconds. */
+        long timeout = (Wait == gcvINFINITE)
+                     ? MAX_SCHEDULE_TIMEOUT
+                     : msecs_to_jiffies(Wait);
+
+        long ret;
+
+        if (Interruptable)
+        {
+            ret = wait_event_interruptible_timeout(signal->wait, signal->done, timeout);
+        }
+        else
+        {
+            ret = wait_event_timeout(signal->wait, signal->done, timeout);
+        }
+
+        if (likely(ret > 0))
+        {
+            status = gcvSTATUS_OK;
+
+            if (!signal->manualReset)
+            {
+                /* Auto reset. */
+                signal->done = 0;
+            }
+        }
+        else
+        {
+            status = (ret == -ERESTARTSYS) ? gcvSTATUS_INTERRUPTED
+                   : gcvSTATUS_TIMEOUT;
+        }
+    }
+
+OnError:
+    /* Return status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+_QuerySignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    )
+{
+    /*
+     * This function is called by 'has_signaled' callback of sync_timeline.
+     * By design, 'has_signaled' could be called in interrupt context, but
+     * in current driver, it can be called only when 'gckOS_Signal' and
+     * 'gckOS_CreateNativeFence'. Thus its safe to use normal version of
+     * spinlock for 'Os->signalDB.lock' and 'signal->obj.wait.lock'.
+     */
+    gceSTATUS status;
+    gcsSIGNAL_PTR signal = gcvNULL;
+
+    status = _QueryIntegerId(&Os->signalDB,
+                             (gctUINT32)(gctUINTPTR_T)Signal,
+                             (gctPOINTER)&signal);
+
+    if (gcmIS_SUCCESS(status))
+    {
+        spin_lock(&signal->lock);
+        status = signal->done ? gcvSTATUS_TRUE : gcvSTATUS_FALSE;
+        spin_unlock(&signal->lock);
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_MapSignal
+**
+**  Map a signal in to the current process space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to tha gctSIGNAL to map.
+**
+**      gctHANDLE Process
+**          Handle of process owning the signal.
+**
+**  OUTPUT:
+**
+**      gctSIGNAL * MappedSignal
+**          Pointer to a variable receiving the mapped gctSIGNAL.
+*/
+gceSTATUS
+gckOS_MapSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal,
+    IN gctHANDLE Process,
+    OUT gctSIGNAL * MappedSignal
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsSIGNAL_PTR signal = gcvNULL;
+    unsigned long flags = 0;
+    gcmkHEADER_ARG("Os=%p Signal=%p Process=%p", Os, Signal, Process);
+
+    gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+    gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
+
+    spin_lock_irqsave(&Os->signalLock, flags);
+
+    gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+    if (atomic_inc_return(&signal->ref) <= 1)
+    {
+        /* The previous value is 0, it has been deleted. */
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    *MappedSignal = (gctSIGNAL) Signal;
+
+OnError:
+    spin_unlock_irqrestore(&Os->signalLock, flags);
+
+    gcmkFOOTER_ARG("*MappedSignal=%p", *MappedSignal);
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_UnmapSignal
+**
+**  Unmap a signal .
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctSIGNAL Signal
+**          Pointer to that gctSIGNAL mapped.
+*/
+gceSTATUS
+gckOS_UnmapSignal(
+    IN gckOS Os,
+    IN gctSIGNAL Signal
+    )
+{
+    return gckOS_DestroySignal(Os, Signal);
+}
+
+/*******************************************************************************
+**
+**  gckOS_CreateUserSignal
+**
+**  Create a new signal to be used in the user space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctBOOL ManualReset
+**          If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
+**          order to set the signal to nonsignaled state.
+**          If set to gcvFALSE, the signal will automatically be set to
+**          nonsignaled state by gckOS_WaitSignal function.
+**
+**  OUTPUT:
+**
+**      gctINT * SignalID
+**          Pointer to a variable receiving the created signal's ID.
+*/
+gceSTATUS
+gckOS_CreateUserSignal(
+    IN gckOS Os,
+    IN gctBOOL ManualReset,
+    OUT gctINT * SignalID
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T signal;
+
+    /* Create a new signal. */
+    gcmkONERROR(gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal));
+    *SignalID = (gctINT) signal;
+
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DestroyUserSignal
+**
+**  Destroy a signal to be used in the user space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctINT SignalID
+**          The signal's ID.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_DestroyUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID
+    )
+{
+    return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID);
+}
+
+/*******************************************************************************
+**
+**  gckOS_WaitUserSignal
+**
+**  Wait for a signal used in the user mode to become signaled.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctINT SignalID
+**          Signal ID.
+**
+**      gctUINT32 Wait
+**          Number of milliseconds to wait.
+**          Pass the value of gcvINFINITE for an infinite wait.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_WaitUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID,
+    IN gctUINT32 Wait
+    )
+{
+    return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, gcvTRUE, Wait);
+}
+
+/*******************************************************************************
+**
+**  gckOS_SignalUserSignal
+**
+**  Set a state of the specified signal to be used in the user space.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctINT SignalID
+**          SignalID.
+**
+**      gctBOOL State
+**          If gcvTRUE, the signal will be set to signaled state.
+**          If gcvFALSE, the signal will be set to nonsignaled state.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_SignalUserSignal(
+    IN gckOS Os,
+    IN gctINT SignalID,
+    IN gctBOOL State
+    )
+{
+    return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State);
+}
+
+#if gcdENABLE_VG
+gceSTATUS
+gckOS_CreateSemaphoreVG(
+    IN gckOS Os,
+    OUT gctSEMAPHORE * Semaphore
+    )
+{
+    gceSTATUS status;
+    struct semaphore * newSemaphore;
+
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    do
+    {
+        /* Allocate the semaphore structure. */
+        newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
+        if (newSemaphore == gcvNULL)
+        {
+            gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
+        }
+
+        /* Initialize the semaphore. */
+        sema_init(newSemaphore, 0);
+
+        /* Set the handle. */
+        * Semaphore = (gctSEMAPHORE) newSemaphore;
+
+        /* Success. */
+        status = gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+
+gceSTATUS
+gckOS_IncrementSemaphore(
+    IN gckOS Os,
+    IN gctSEMAPHORE Semaphore
+    )
+{
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    /* Increment the semaphore's count. */
+    up((struct semaphore *) Semaphore);
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DecrementSemaphore(
+    IN gckOS Os,
+    IN gctSEMAPHORE Semaphore
+    )
+{
+    gceSTATUS status;
+    gctINT result;
+
+    gcmkHEADER_ARG("Os=%p Semaphore=%p", Os, Semaphore);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+    do
+    {
+        /* Decrement the semaphore's count. If the count is zero, wait
+           until it gets incremented. */
+        result = down_interruptible((struct semaphore *) Semaphore);
+
+        /* Signal received? */
+        if (result != 0)
+        {
+            status = gcvSTATUS_TERMINATE;
+            break;
+        }
+
+        /* Success. */
+        status = gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+/******************************************************************************\
+******************************** Thread Object *********************************
+\******************************************************************************/
+
+gceSTATUS
+gckOS_StartThread(
+    IN gckOS Os,
+    IN gctTHREADFUNC ThreadFunction,
+    IN gctPOINTER ThreadParameter,
+    OUT gctTHREAD * Thread
+    )
+{
+    gceSTATUS status;
+    struct task_struct * thread;
+
+    gcmkHEADER_ARG("Os=%p", Os);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+    do
+    {
+        /* Create the thread. */
+        thread = kthread_create(
+            ThreadFunction,
+            ThreadParameter,
+            "Vivante Kernel Thread"
+            );
+
+        /* Failed? */
+        if (IS_ERR(thread))
+        {
+            status = gcvSTATUS_GENERIC_IO;
+            break;
+        }
+
+        /* Start the thread. */
+        wake_up_process(thread);
+
+        /* Set the thread handle. */
+        * Thread = (gctTHREAD) thread;
+
+        /* Success. */
+        status = gcvSTATUS_OK;
+    }
+    while (gcvFALSE);
+
+    gcmkFOOTER();
+    /* Return the status. */
+    return status;
+}
+
+gceSTATUS
+gckOS_StopThread(
+    IN gckOS Os,
+    IN gctTHREAD Thread
+    )
+{
+    gcmkHEADER_ARG("Os=%p Thread=%p", Os, Thread);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+    /* Thread should have already been enabled to terminate. */
+    kthread_stop((struct task_struct *) Thread);
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_VerifyThread(
+    IN gckOS Os,
+    IN gctTHREAD Thread
+    )
+{
+    gcmkHEADER_ARG("Os=%p Thread=%p", Os, Thread);
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+    gcmkFOOTER_NO();
+    /* Success. */
+    return gcvSTATUS_OK;
+}
+#endif
+
+/******************************************************************************\
+******************************** Software Timer ********************************
+\******************************************************************************/
+
+void
+_TimerFunction(
+    struct work_struct * work
+    )
+{
+    gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work;
+
+    gctTIMERFUNCTION function = timer->function;
+
+    function(timer->data);
+}
+
+/*******************************************************************************
+**
+**  gckOS_CreateTimer
+**
+**  Create a software timer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctTIMERFUNCTION Function.
+**          Pointer to a call back function which will be called when timer is
+**          expired.
+**
+**      gctPOINTER Data.
+**          Private data which will be passed to call back function.
+**
+**  OUTPUT:
+**
+**      gctPOINTER * Timer
+**          Pointer to a variable receiving the created timer.
+*/
+gceSTATUS
+gckOS_CreateTimer(
+    IN gckOS Os,
+    IN gctTIMERFUNCTION Function,
+    IN gctPOINTER Data,
+    OUT gctPOINTER * Timer
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    gcsOSTIMER_PTR pointer;
+    gcmkHEADER_ARG("Os=%p Function=0%p Data=%p", Os, Function, Data);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+    gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer));
+
+    pointer->function = Function;
+    pointer->data = Data;
+
+    INIT_DELAYED_WORK(&pointer->work, _TimerFunction);
+
+    *Timer = pointer;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DestroyTimer
+**
+**  Destory a software timer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Timer
+**          Pointer to the timer to be destoryed.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_DestroyTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer
+    )
+{
+    gcsOSTIMER_PTR timer;
+
+    gcmkHEADER_ARG("Os=%p Timer=%p", Os, Timer);
+
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+    timer = (gcsOSTIMER_PTR)Timer;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+    cancel_delayed_work_sync(&timer->work);
+#else
+    cancel_delayed_work(&timer->work);
+    flush_workqueue(Os->workqueue);
+#endif
+
+    gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_StartTimer
+**
+**  Schedule a software timer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Timer
+**          Pointer to the timer to be scheduled.
+**
+**      gctUINT32 Delay
+**          Delay in milliseconds.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_StartTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer,
+    IN gctUINT32 Delay
+    )
+{
+    gcsOSTIMER_PTR timer;
+
+    gcmkHEADER_ARG("Os=%p Timer=%p Delay=%u", Os, Timer, Delay);
+
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Delay != 0);
+
+    timer = (gcsOSTIMER_PTR)Timer;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
+    mod_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
+#else
+    if (unlikely(delayed_work_pending(&timer->work)))
+    {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+        cancel_delayed_work_sync(&timer->work);
+#else
+        cancel_delayed_work(&timer->work);
+        flush_workqueue(Os->workqueue);
+#endif
+    }
+
+    queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
+#endif
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_StopTimer
+**
+**  Cancel a unscheduled timer.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to the gckOS object.
+**
+**      gctPOINTER Timer
+**          Pointer to the timer to be cancel.
+**
+**  OUTPUT:
+**
+**      Nothing.
+*/
+gceSTATUS
+gckOS_StopTimer(
+    IN gckOS Os,
+    IN gctPOINTER Timer
+    )
+{
+    gcsOSTIMER_PTR timer;
+    gcmkHEADER_ARG("Os=%p Timer=%p", Os, Timer);
+
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+    timer = (gcsOSTIMER_PTR)Timer;
+
+    cancel_delayed_work(&timer->work);
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_GetProcessNameByPid(
+    IN gctINT Pid,
+    IN gctSIZE_T Length,
+    OUT gctUINT8_PTR String
+    )
+{
+    struct task_struct *task;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /* Get the task_struct of the task with pid. */
+    rcu_read_lock();
+
+    task = FIND_TASK_BY_PID(Pid);
+    if (task)
+    {
+        /* Get name of process. */
+        strncpy(String, task->comm, Length);
+    }
+    else
+    {
+        status = gcvSTATUS_NOT_FOUND;
+    }
+
+    rcu_read_unlock();
+
+    return status;
+}
+
+gceSTATUS
+gckOS_DumpCallStack(
+    IN gckOS Os
+    )
+{
+    gcmkHEADER_ARG("Os=%p", Os);
+
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+    dump_stack();
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+**  gckOS_DetectProcessByName
+**
+**      task->comm maybe part of process name, so this function
+**      can only be used for debugging.
+**
+**  INPUT:
+**
+**      gctCONST_POINTER Name
+**          Pointer to a string to hold name to be check. If the length
+**          of name is longer than TASK_COMM_LEN (16), use part of name
+**          to detect.
+**
+**  OUTPUT:
+**
+**      gcvSTATUS_TRUE if name of current process matches Name.
+**
+*/
+gceSTATUS
+gckOS_DetectProcessByName(
+    IN gctCONST_POINTER Name
+    )
+{
+    char comm[sizeof(current->comm)];
+
+    memset(comm, 0, sizeof(comm));
+
+    gcmkVERIFY_OK(
+        gckOS_GetProcessNameByPid(_GetProcessID(), sizeof(current->comm), comm));
+
+    return strstr(comm, Name) ? gcvSTATUS_TRUE
+                              : gcvSTATUS_FALSE;
+}
+
+#if gcdLINUX_SYNC_FILE
+#ifndef CONFIG_SYNC_FILE
+gceSTATUS
+gckOS_CreateSyncTimeline(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctHANDLE * Timeline
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    struct viv_sync_timeline * timeline;
+    char name[32];
+
+    snprintf(name, 32, "gccore-%u", (unsigned int) Core);
+
+    /* Create viv sync timeline. */
+    timeline = viv_sync_timeline_create(name, Os);
+
+    if (timeline)
+    {
+        *Timeline = (gctHANDLE)timeline;
+    }
+    else
+    {
+        /* Out of memory. */
+        status = gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+
+    return status;
+}
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+    IN gckOS Os,
+    IN gctHANDLE Timeline
+    )
+{
+    struct viv_sync_timeline * timeline;
+    gcmkASSERT(Timeline != gcvNULL);
+
+    /* Destroy timeline. */
+    timeline = (struct viv_sync_timeline *) Timeline;
+    sync_timeline_destroy(&timeline->obj);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctSIGNAL Signal,
+    OUT gctINT * FenceFD
+    )
+{
+    int fd = -1;
+    struct viv_sync_timeline *timeline;
+    struct sync_pt * pt = gcvNULL;
+    struct sync_fence * fence;
+    char name[32];
+    gcsSIGNAL_PTR signal;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Timeline=%p Signal=%p", Os, Timeline, Signal);
+
+    gcmkONERROR(
+        _QueryIntegerId(&Os->signalDB,
+                        (gctUINT32)(gctUINTPTR_T)Signal,
+                        (gctPOINTER)&signal));
+
+    /* Cast timeline. */
+    timeline = (struct viv_sync_timeline *) Timeline;
+
+    fd = get_unused_fd_flags(O_CLOEXEC);
+
+    if (fd < 0)
+    {
+        /* Out of resources. */
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    /* Create viv_sync_pt. */
+    pt = viv_sync_pt_create(timeline, Signal);
+
+    if (pt == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Reference sync_timeline. */
+    signal->timeline = &timeline->obj;
+
+    /* Build fence name. */
+    snprintf(name, 32, "%.16s-signal_%lu",
+             current->comm,
+             (unsigned long)Signal);
+
+    /* Create sync_fence. */
+    fence = sync_fence_create(name, pt);
+
+    if (fence == NULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Install fence to fd. */
+    sync_fence_install(fence, fd);
+
+    *FenceFD = fd;
+    return gcvSTATUS_OK;
+
+OnError:
+    if (gcmIS_ERROR(status))
+    {
+        /* Error roll back. */
+        if (pt)
+        {
+            sync_pt_free(pt);
+        }
+
+        if (fd > 0)
+        {
+            put_unused_fd(fd);
+        }
+    }
+
+    gcmkFOOTER_ARG("*FenceFD=%d", fd);
+    return status;
+}
+
+static void
+_NativeFenceSignaled(
+    struct sync_fence *fence,
+    struct sync_fence_waiter *waiter
+    )
+{
+    kfree(waiter);
+    sync_fence_put(fence);
+}
+
+gceSTATUS
+gckOS_WaitNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    )
+{
+    struct sync_timeline * timeline;
+    struct sync_fence * fence;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    gcmkHEADER_ARG("Os=%p Timeline=%p FenceFD=%d Timeout=%u",
+                   Os, Timeline, FenceFD, Timeout);
+
+    /* Get shortcut. */
+    timeline = (struct sync_timeline *) Timeline;
+
+    /* Get sync fence. */
+    fence = sync_fence_fdget(FenceFD);
+
+    if (!fence)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (sync_fence_wait(fence, 0) == 0)
+    {
+        /* Already signaled. */
+        sync_fence_put(fence);
+
+        goto OnError;
+    }
+    else
+    {
+        gctBOOL wait = gcvFALSE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+        int i;
+
+        for (i = 0; i < fence->num_fences; i++)
+        {
+            struct fence *f = fence->cbs[i].sync_pt;
+            struct sync_pt *pt = container_of(f, struct sync_pt, base);
+
+            /* Do not need to wait on same timeline. */
+            if ((sync_pt_parent(pt) != timeline) && !fence_is_signaled(f))
+            {
+                wait = gcvTRUE;
+                break;
+            }
+        }
+#else
+        {
+            struct list_head *pos;
+            list_for_each(pos, &fence->pt_list_head)
+            {
+                struct sync_pt * pt =
+                container_of(pos, struct sync_pt, pt_list);
+
+                /* Do not need to wait on same timeline. */
+                if (pt->parent != timeline)
+                {
+                    wait = gcvTRUE;
+                    break;
+                }
+            }
+        }
+#endif
+
+        if (wait)
+        {
+            int err;
+            long timeout = (Timeout == gcvINFINITE) ? - 1 : (long) Timeout;
+            err = sync_fence_wait(fence, timeout);
+
+            /* Put the fence. */
+            sync_fence_put(fence);
+
+            switch (err)
+            {
+            case 0:
+                break;
+            case -ETIME:
+                status = gcvSTATUS_TIMEOUT;
+                break;
+            default:
+                gcmkONERROR(gcvSTATUS_GENERIC_IO);
+                break;
+            }
+        }
+        else
+        {
+            int err;
+            struct sync_fence_waiter *waiter;
+            waiter = (struct sync_fence_waiter *)kmalloc(
+                    sizeof (struct sync_fence_waiter), gcdNOWARN | GFP_KERNEL);
+
+            if (!waiter)
+            {
+                sync_fence_put(fence);
+                gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+            }
+
+            /* Schedule a waiter callback. */
+            sync_fence_waiter_init(waiter, _NativeFenceSignaled);
+            err = sync_fence_wait_async(fence, waiter);
+
+            switch (err)
+            {
+            case 0:
+                /* Put fence in callback function. */
+                break;
+            case 1:
+                /* already signaled. */
+                sync_fence_put(fence);
+                break;
+            default:
+                sync_fence_put(fence);
+                gcmkONERROR(gcvSTATUS_GENERIC_IO);
+                break;
+            }
+        }
+    }
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+#  else /* !CONFIG_SYNC_FILE */
+
+gceSTATUS
+gckOS_CreateSyncTimeline(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctHANDLE * Timeline
+    )
+{
+    struct viv_sync_timeline *timeline;
+
+    char name[32];
+
+    snprintf(name, 32, "gccore-%u", (unsigned int) Core);
+    timeline = viv_sync_timeline_create(name, Os);
+
+    if (timeline == gcvNULL)
+    {
+        /* Out of memory. */
+        return gcvSTATUS_OUT_OF_MEMORY;
+    }
+
+    *Timeline = (gctHANDLE) timeline;
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+    IN gckOS Os,
+    IN gctHANDLE Timeline
+    )
+{
+    struct viv_sync_timeline * timeline;
+
+    /* Destroy timeline. */
+    timeline = (struct viv_sync_timeline *) Timeline;
+    viv_sync_timeline_destroy(timeline);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctSIGNAL Signal,
+    OUT gctINT * FenceFD
+    )
+{
+    struct dma_fence *fence = NULL;
+    struct sync_file *sync = NULL;
+    int fd = -1;
+    struct viv_sync_timeline *timeline;
+    gcsSIGNAL_PTR signal = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    /* Create fence. */
+    timeline = (struct viv_sync_timeline *) Timeline;
+
+    gcmkONERROR(
+        _QueryIntegerId(&Os->signalDB,
+                        (gctUINT32)(gctUINTPTR_T)Signal,
+                        (gctPOINTER)&signal));
+
+    fence = viv_fence_create(timeline, signal);
+
+    if (!fence)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Create sync_file. */
+    sync = sync_file_create(fence);
+
+    if (!sync)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    /* Get a unused fd. */
+    fd = get_unused_fd_flags(O_CLOEXEC);
+
+    if (fd < 0)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    fd_install(fd, sync->file);
+
+    *FenceFD = fd;
+    return gcvSTATUS_OK;
+
+OnError:
+    if (sync)
+    {
+        fput(sync->file);
+    }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,68)
+    if (fence)
+    {
+        dma_fence_put(fence);
+    }
+#endif
+
+    if (fd > 0)
+    {
+        put_unused_fd(fd);
+    }
+
+    *FenceFD = -1;
+    return status;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+/**
+ * sync_file_fdget() - get a sync_file from an fd
+ * @fd:     fd referencing a fence
+ *
+ * Ensures @fd references a valid sync_file, increments the refcount of the
+ * backing file. Returns the sync_file or NULL in case of error.
+ */
+static struct sync_file *sync_file_fdget(int fd)
+{
+    struct file *file = fget(fd);
+
+    if (!file)
+        return NULL;
+
+    return file->private_data;
+}
+
+gceSTATUS
+gckOS_WaitNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    )
+{
+    struct viv_sync_timeline *timeline;
+    gceSTATUS status = gcvSTATUS_OK;
+    unsigned int i;
+    unsigned long timeout;
+    unsigned int numFences;
+    struct sync_file *sync_file;
+
+    timeline = (struct viv_sync_timeline *) Timeline;
+
+    sync_file = sync_file_fdget(FenceFD);
+
+    if (!sync_file)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    numFences = sync_file->num_fences;
+
+    timeout = msecs_to_jiffies(Timeout);
+
+    for (i = 0; i < numFences; i++)
+    {
+        struct fence *f = sync_file->cbs[i].fence;
+        fence_get(f);
+
+        if (f->context != timeline->context &&
+            !fence_is_signaled(f))
+        {
+            signed long ret;
+            ret = fence_wait_timeout(f, 1, timeout);
+
+            if (ret == -ERESTARTSYS)
+            {
+                status = gcvSTATUS_INTERRUPTED;
+                fence_put(f);
+                break;
+            }
+            else if (ret <= 0)
+            {
+                status = gcvSTATUS_TIMEOUT;
+                fence_put(f);
+                break;
+            }
+            else
+            {
+                /* wait success. */
+                timeout -= ret;
+            }
+        }
+
+        fence_put(f);
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+#    else
+
+gceSTATUS
+gckOS_WaitNativeFence(
+    IN gckOS Os,
+    IN gctHANDLE Timeline,
+    IN gctINT FenceFD,
+    IN gctUINT32 Timeout
+    )
+{
+    struct viv_sync_timeline *timeline;
+    gceSTATUS status = gcvSTATUS_OK;
+    unsigned int i;
+    unsigned long timeout;
+    unsigned int numFences;
+    struct dma_fence *fence;
+    struct dma_fence **fences;
+
+    timeline = (struct viv_sync_timeline *) Timeline;
+
+    fence = sync_file_get_fence(FenceFD);
+
+    if (!fence)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    if (dma_fence_is_array(fence))
+    {
+        struct dma_fence_array *array = to_dma_fence_array(fence);
+        fences = array->fences;
+        numFences = array->num_fences;
+    }
+    else
+    {
+        fences = &fence;
+        numFences = 1;
+    }
+
+    timeout = msecs_to_jiffies(Timeout);
+
+    for (i = 0; i < numFences; i++)
+    {
+        struct dma_fence *f = fences[i];
+
+        if(!dma_fence_is_signaled(fence))
+        {
+            signed long ret;
+            ret = dma_fence_wait_timeout(f, 1, timeout);
+
+            if (ret == -ERESTARTSYS)
+            {
+                status = gcvSTATUS_INTERRUPTED;
+                break;
+            }
+            else if (ret <= 0)
+            {
+                status = gcvSTATUS_TIMEOUT;
+                break;
+            }
+            else
+            {
+                /* wait success. */
+                timeout -= ret;
+            }
+        }
+    }
+
+    dma_fence_put(fence);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+#    endif
+#  endif
+#endif
+
+#if gcdSECURITY
+gceSTATUS
+gckOS_AllocatePageArray(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T PageCount,
+    OUT gctPOINTER * PageArrayLogical,
+    OUT gctPHYS_ADDR * PageArrayPhysical
+    )
+{
+    gceSTATUS status = gcvSTATUS_OK;
+    PLINUX_MDL  mdl;
+    gctUINT32*  table;
+    gctUINT32   offset;
+    gctSIZE_T   bytes;
+    gckALLOCATOR allocator;
+
+    gcmkHEADER_ARG("Os=%p Physical=%p PageCount=%u",
+                   Os, Physical, PageCount);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+    bytes = PageCount * gcmSIZEOF(gctUINT32);
+    gcmkONERROR(gckOS_AllocateNonPagedMemory(
+        Os,
+        gcvFALSE,
+        gcvALLOC_FLAG_CONTIGUOUS,
+        &bytes,
+        PageArrayPhysical,
+        PageArrayLogical
+        ));
+
+    table = *PageArrayLogical;
+
+    /* Convert pointer to MDL. */
+    mdl = (PLINUX_MDL)Physical;
+
+    allocator = mdl->allocator;
+
+     /* Get all the physical addresses and store them in the page table. */
+
+    offset = 0;
+    PageCount = PageCount / (PAGE_SIZE / 4096);
+
+    /* Try to get the user pages so DMA can happen. */
+    while (PageCount-- > 0)
+    {
+        unsigned long phys = ~0;
+
+        gctPHYS_ADDR_T phys_addr;
+
+        gcmALLOCATOR_Physical(allocator, mdl, offset * PAGE_SIZE, &phys_addr);
+
+        phys = (unsigned long)phys_addr;
+
+        table[offset] = phys & PAGE_MASK;
+
+        offset += 1;
+    }
+
+OnError:
+
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+#endif
+
+gceSTATUS
+gckOS_CPUPhysicalToGPUPhysical(
+    IN gckOS Os,
+    IN gctPHYS_ADDR_T CPUPhysical,
+    OUT gctPHYS_ADDR_T * GPUPhysical
+    )
+{
+    gcsPLATFORM * platform;
+    gcmkHEADER_ARG("CPUPhysical=%p", CPUPhysical);
+
+    platform = Os->device->platform;
+
+    if (platform && platform->ops->getGPUPhysical)
+    {
+        gcmkVERIFY_OK(
+            platform->ops->getGPUPhysical(platform, CPUPhysical, GPUPhysical));
+    }
+    else
+    {
+        *GPUPhysical = CPUPhysical;
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_GPUPhysicalToCPUPhysical(
+    IN gckOS Os,
+    IN gctUINT32 GPUPhysical,
+    IN gctPHYS_ADDR_T * CPUPhysical
+    )
+{
+    gcsPLATFORM * platform;
+    gcmkHEADER_ARG("Os=%p GPUPhysical=0x%x", Os, GPUPhysical);
+
+    platform = Os->device->platform;
+
+    if (platform && platform->ops->getCPUPhysical)
+    {
+        gcmkVERIFY_OK(
+            platform->ops->getCPUPhysical(platform, GPUPhysical, CPUPhysical));
+    }
+    else
+    {
+        *CPUPhysical = GPUPhysical;
+    }
+
+    gcmkFOOTER_ARG("CPUPhysical=0x%llx", gcmOPT_VALUE(CPUPhysical));
+    return gcvSTATUS_OK;
+}
+
+static int fd_release(struct inode *inode, struct file *file)
+{
+    gcsFDPRIVATE_PTR private = (gcsFDPRIVATE_PTR)file->private_data;
+
+    return (private && private->release) ? private->release(private) : 0;
+}
+
+static const struct file_operations fd_fops =
+{
+    .release = fd_release,
+};
+
+gceSTATUS
+gckOS_GetFd(
+    IN gctSTRING Name,
+    IN gcsFDPRIVATE_PTR Private,
+    OUT gctINT * Fd
+    )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    *Fd = anon_inode_getfd(Name, &fd_fops, Private, O_RDWR);
+
+    if (*Fd < 0)
+    {
+        return gcvSTATUS_OUT_OF_RESOURCES;
+    }
+
+    return gcvSTATUS_OK;
+#else
+    return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+gceSTATUS
+gckOS_QueryOption(
+    IN gckOS Os,
+    IN gctCONST_STRING Option,
+    OUT gctUINT64 * Value
+    )
+{
+    gckGALDEVICE device = Os->device;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!strcmp(Option, "physBase"))
+    {
+        *Value = device->physBase;
+    }
+    else if (!strcmp(Option, "physSize"))
+    {
+        *Value = device->physSize;
+    }
+    else if (!strcmp(Option, "mmu"))
+    {
+#if gcdSECURITY
+        *Value = 0;
+#else
+        *Value = device->args.enableMmu;
+#endif
+    }
+    else if (!strcmp(Option, "contiguousSize"))
+    {
+        *Value = device->contiguousSize;
+    }
+    else if (!strcmp(Option, "contiguousBase"))
+    {
+        *Value = device->contiguousBase;
+    }
+    else if (!strcmp(Option, "externalSize"))
+    {
+        *Value = device->externalSize;
+        return gcvSTATUS_OK;
+    }
+    else if (!strcmp(Option, "externalBase"))
+    {
+        *Value = device->externalBase;
+        return gcvSTATUS_OK;
+    }
+    else if (!strcmp(Option, "recovery"))
+    {
+        *Value = device->args.recovery;
+    }
+    else if (!strcmp(Option, "stuckDump"))
+    {
+        *Value = device->args.stuckDump;
+    }
+    else if (!strcmp(Option, "powerManagement"))
+    {
+        *Value = device->args.powerManagement;
+    }
+    else if (!strcmp(Option, "TA"))
+    {
+        *Value = 0;
+    }
+    else if (!strcmp(Option, "gpuProfiler"))
+    {
+        *Value = device->args.gpuProfiler;
+    }
+    else if (!strcmp(Option, "userClusterMask"))
+    {
+        *Value = device->args.userClusterMask;
+    }
+    else if (!strcmp(Option, "smallBatch"))
+    {
+        *Value = device->args.smallBatch;
+    }
+    else if (!strcmp(Option, "sRAMBases"))
+    {
+        memcpy(Value, device->args.sRAMBases, gcmSIZEOF(gctUINT64) * gcvSRAM_INTER_COUNT * gcvCORE_COUNT);
+    }
+    else if (!strcmp(Option, "sRAMSizes"))
+    {
+        memcpy(Value, device->args.sRAMSizes, gcmSIZEOF(gctUINT32) * gcvSRAM_INTER_COUNT * gcvCORE_COUNT);
+    }
+    else if (!strcmp(Option, "extSRAMBases"))
+    {
+        memcpy(Value, device->args.extSRAMBases, gcmSIZEOF(gctUINT64) * gcvSRAM_EXT_COUNT);
+    }
+    else if (!strcmp(Option, "extSRAMSizes"))
+    {
+        memcpy(Value, device->args.extSRAMSizes, gcmSIZEOF(gctUINT32) * gcvSRAM_EXT_COUNT);
+    }
+    else if (!strcmp(Option, "sRAMRequested"))
+    {
+        *Value = device->args.sRAMRequested;
+    }
+    else if (!strcmp(Option, "sRAMLoopMode"))
+    {
+        *Value = device->args.sRAMLoopMode;
+    }
+    else if (!strcmp(Option, "platformFlagBits"))
+    {
+        *Value = device->platform->flagBits;
+    }
+    else if (!strcmp(Option, "mmuPageTablePool"))
+    {
+        *Value = device->args.mmuPageTablePool;
+    }
+    else if (!strcmp(Option, "mmuDynamicMap"))
+    {
+        *Value = device->args.mmuDynamicMap;
+    }
+    else if (!strcmp(Option, "allMapInOne"))
+    {
+        *Value = device->args.allMapInOne;
+    }
+    else
+    {
+        status = gcvSTATUS_NOT_SUPPORTED;
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckOS_MemoryGetSGT(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T Offset,
+    IN gctSIZE_T Bytes,
+    OUT gctPOINTER *SGT
+    )
+{
+    PLINUX_MDL mdl;
+    gckALLOCATOR allocator;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    if (!Physical)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    mdl = (PLINUX_MDL)Physical;
+    allocator = mdl->allocator;
+
+    if (!allocator->ops->GetSGT)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    if (Bytes > 0)
+    {
+        gcmkONERROR(gcmALLOCATOR_GetSGT(allocator, mdl, Offset, Bytes, SGT));
+    }
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gckOS_MemoryMmap(
+    IN gckOS Os,
+    IN gctPHYS_ADDR Physical,
+    IN gctSIZE_T skipPages,
+    IN gctSIZE_T numPages,
+    INOUT gctPOINTER Vma
+    )
+{
+    PLINUX_MDL mdl;
+    PLINUX_MDL_MAP mdlMap;
+    gckALLOCATOR allocator;
+    gceSTATUS status = gcvSTATUS_OK;
+    gctBOOL cacheable = gcvFALSE;
+
+    if (!Physical)
+    {
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    mdl = (PLINUX_MDL)Physical;
+    allocator = mdl->allocator;
+
+    if (!allocator->ops->Mmap)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    mutex_lock(&mdl->mapsMutex);
+
+    mdlMap = FindMdlMap(mdl, _GetProcessID());
+    if (mdlMap)
+    {
+        cacheable = mdlMap->cacheable;
+    }
+
+    mutex_unlock(&mdl->mapsMutex);
+
+    gcmkONERROR(gcmALLOCATOR_Mmap(allocator, mdl, cacheable, skipPages, numPages, Vma));
+
+OnError:
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gckOS_WrapMemory
+**
+**  Import a number of pages allocated by other allocator.
+**
+**  INPUT:
+**
+**      gckOS Os
+**          Pointer to an gckOS object.
+**
+**      gctUINT32 Flag
+**          Memory type.
+**
+**  OUTPUT:
+**
+**      gctSIZE_T * Bytes
+**          Pointer to a variable that hold the number of bytes allocated.
+**
+**      gctPHYS_ADDR * Physical
+**          Pointer to a variable that will hold the physical address of the
+**          allocation.
+*/
+gceSTATUS
+gckOS_WrapMemory(
+    IN gckOS Os,
+    IN gcsUSER_MEMORY_DESC_PTR Desc,
+    OUT gctSIZE_T *Bytes,
+    OUT gctPHYS_ADDR * Physical,
+    OUT gctBOOL *Contiguous,
+    OUT gctSIZE_T * PageCountCpu
+    )
+{
+    PLINUX_MDL mdl = gcvNULL;
+    gceSTATUS status = gcvSTATUS_OUT_OF_MEMORY;
+    gckALLOCATOR allocator;
+    gcsATTACH_DESC desc;
+    gctSIZE_T bytes = 0;
+
+    gcmkHEADER_ARG("Os=%p ", Os);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+    gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+    gcmkVERIFY_ARGUMENT(Desc != gcvNULL);
+
+    mdl = _CreateMdl(Os);
+    if (mdl == gcvNULL)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    if (Desc->flag & gcvALLOC_FLAG_DMABUF)
+    {
+        desc.dmaBuf.dmabuf = gcmUINT64_TO_PTR(Desc->dmabuf);
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+        {
+            struct dma_buf *dmabuf = (struct dma_buf*)desc.dmaBuf.dmabuf;
+            bytes = dmabuf->size;
+        }
+#endif
+    }
+    else if (Desc->flag & gcvALLOC_FLAG_USERMEMORY)
+    {
+        desc.userMem.memory   = gcmUINT64_TO_PTR(Desc->logical);
+        desc.userMem.physical = Desc->physical;
+        desc.userMem.size     = Desc->size;
+        bytes                 = Desc->size;
+    }
+    else if (Desc->flag & gcvALLOC_FLAG_EXTERNAL_MEMORY)
+    {
+        desc.externalMem.info = Desc->externalMemoryInfo;
+    }
+    else
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    /* Walk all allocators. */
+    list_for_each_entry(allocator, &Os->allocatorList, link)
+    {
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+                       "%s(%d) Flag = %x allocator->capability = %x",
+                        __FUNCTION__, __LINE__, Desc->flag, allocator->capability);
+
+        if ((Desc->flag & allocator->capability) != Desc->flag)
+        {
+            status = gcvSTATUS_NOT_SUPPORTED;
+            continue;
+        }
+
+        if (Desc->flag == gcvALLOC_FLAG_EXTERNAL_MEMORY)
+        {
+            /* Use name to match suitable allocator for external memory. */
+            if (!strncmp(Desc->externalMemoryInfo.allocatorName,
+                         allocator->name, gcdEXTERNAL_MEMORY_NAME_MAX))
+            {
+                status = gcvSTATUS_NOT_SUPPORTED;
+                continue;
+            }
+        }
+
+        status = gcmALLOCATOR_Attach(allocator, &desc, mdl);
+
+        if (gcmIS_SUCCESS(status))
+        {
+            mdl->allocator = allocator;
+            break;
+        }
+    }
+
+    /* Check status. */
+    gcmkONERROR(status);
+
+    mdl->dmaHandle  = 0;
+    mdl->addr       = 0;
+
+    mdl->bytes = bytes ? bytes : mdl->numPages * PAGE_SIZE;
+    *Bytes = mdl->bytes;
+
+    /* Return physical address. */
+    *Physical = (gctPHYS_ADDR) mdl;
+
+    *Contiguous = mdl->contiguous;
+
+    if (PageCountCpu)
+    {
+        *PageCountCpu = mdl->numPages;
+    }
+
+    /*
+     * Add this to a global list.
+     * Will be used by get physical address
+     * and mapuser pointer functions.
+     */
+    mutex_lock(&Os->mdlMutex);
+    list_add_tail(&mdl->link, &Os->mdlHead);
+    mutex_unlock(&Os->mdlMutex);
+
+    /* Success. */
+    status = gcvSTATUS_OK;
+
+OnError:
+    if (gcmIS_ERROR(status) && mdl)
+    {
+        /* Free the memory. */
+        _DestroyMdl(mdl);
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_ARG("*Physical=%p", *Physical);
+    return status;
+}
+
+gceSTATUS
+gckOS_GetPolicyID(
+    IN gckOS Os,
+    IN gceVIDMEM_TYPE Type,
+    OUT gctUINT32_PTR PolicyID,
+    OUT gctUINT32_PTR AXIConfig
+    )
+{
+    gcsPLATFORM * platform = Os->device->platform;
+    gceSTATUS status = (platform && platform->ops->getPolicyID)
+                     ? platform->ops->getPolicyID(platform, Type, PolicyID, AXIConfig)
+                     : gcvSTATUS_NOT_SUPPORTED;
+
+    return status;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_os_h_
+#define __gc_hal_kernel_os_h_
+
+typedef struct _LINUX_MDL     LINUX_MDL,     *PLINUX_MDL;
+typedef struct _LINUX_MDL_MAP LINUX_MDL_MAP, *PLINUX_MDL_MAP;
+
+struct _LINUX_MDL_MAP
+{
+    gctINT                  pid;
+
+    /* map references. */
+    gctUINT32               count;
+
+    struct vm_area_struct * vma;
+    gctPOINTER              vmaAddr;
+    gctBOOL                 cacheable;
+
+    struct list_head        link;
+};
+
+struct _LINUX_MDL
+{
+    gckOS                   os;
+
+    atomic_t                refs;
+
+    /* Kernel address. */
+    char *                  addr;
+
+    /* Size and covered page count. */
+    size_t                  bytes;
+    size_t                  numPages;
+
+    gctBOOL                 contiguous;
+    dma_addr_t              dmaHandle;
+    gctBOOL                 cacheable;
+
+    struct mutex            mapsMutex;
+    struct list_head        mapsHead;
+
+    /* Pointer to allocator which allocates memory for this mdl. */
+    void *                  allocator;
+
+    /* Private data used by allocator. */
+    void *                  priv;
+
+    uint                    gid;
+
+    struct list_head        link;
+
+    gctBOOL                 pageUnit1M;
+};
+
+extern PLINUX_MDL_MAP
+FindMdlMap(
+    IN PLINUX_MDL Mdl,
+    IN gctINT PID
+    );
+
+typedef struct _DRIVER_ARGS
+{
+    gctUINT64               InputBuffer;
+    gctUINT64               InputBufferSize;
+    gctUINT64               OutputBuffer;
+    gctUINT64               OutputBufferSize;
+}
+DRIVER_ARGS;
+
+#endif /* __gc_hal_kernel_os_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h
@@ -0,0 +1,315 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _gc_hal_kernel_platform_h_
+#define _gc_hal_kernel_platform_h_
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#if USE_LINUX_PCIE
+#include <linux/pci.h>
+#endif
+
+typedef struct _gcsMODULE_PARAMETERS
+{
+    gctINT                  irqs[gcvCORE_COUNT];
+    gctPHYS_ADDR_T          registerBases[gcvCORE_COUNT];
+    gctSIZE_T               registerSizes[gcvCORE_COUNT];
+    gctINT                  bars[gcvCORE_COUNT];
+
+    gctPOINTER              registerBasesMapped[gcvCORE_COUNT];
+
+    gctUINT                 chipIDs[gcvCORE_COUNT];
+
+    /* Contiguous memory pool. */
+    gctPHYS_ADDR_T          contiguousBase;
+    gctSIZE_T               contiguousSize;
+    gctBOOL                 contiguousRequested;
+
+    /* External memory pool. */
+    gctPHYS_ADDR_T          externalBase;
+    gctSIZE_T               externalSize;
+
+    /* Per-core SRAM. */
+    gctPHYS_ADDR_T          sRAMBases[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+    gctUINT32               sRAMSizes[gcvCORE_COUNT][gcvSRAM_INTER_COUNT];
+
+    /* Shared SRAM. */
+    gctPHYS_ADDR_T          extSRAMBases[gcvSRAM_EXT_COUNT];
+    gctUINT32               extSRAMSizes[gcvSRAM_EXT_COUNT];
+#if USE_LINUX_PCIE
+    gctUINT32               regOffsets[gcvCORE_COUNT];
+    gctINT32                sRAMBars[gcvSRAM_EXT_COUNT];
+    gctINT32                sRAMOffsets[gcvSRAM_EXT_COUNT];
+#endif
+
+    gctBOOL                 sRAMRequested;
+    gctUINT32               sRAMLoopMode;
+
+    gctPHYS_ADDR_T          baseAddress;
+    gctSIZE_T               physSize;
+    gctSIZE_T               bankSize;
+
+    gctUINT                 recovery;
+    gctINT                  powerManagement;
+
+    gctINT                  enableMmu;
+    gctINT                  fastClear;
+    gceCOMPRESSION_OPTION   compression;
+    gctUINT                 gpu3DMinClock;
+    gctUINT                 userClusterMask;
+    gctUINT                 smallBatch;
+
+    /* Debug or other information. */
+    gctUINT                 stuckDump;
+    gctINT                  gpuProfiler;
+
+    /* device type, 0 for char device, 1 for misc device. */
+    gctUINT                 deviceType;
+    gctUINT                 showArgs;
+
+    /* mmu page table pool, 0 mean auto, 1 means virsual*/
+    gctUINT                 mmuPageTablePool;
+
+    gctUINT                 mmuDynamicMap;
+    gctUINT                 allMapInOne;
+}
+gcsMODULE_PARAMETERS;
+
+typedef struct _gcsPLATFORM gcsPLATFORM;
+
+typedef struct _gcsPLATFORM_OPERATIONS
+{
+
+    /*******************************************************************************
+    **
+    **  adjustParam
+    **
+    **  Override content of arguments, if a argument is not changed here, it will
+    **  keep as default value or value set by insmod command line.
+    */
+    gceSTATUS
+    (*adjustParam)(
+        IN gcsPLATFORM * Platform,
+        OUT gcsMODULE_PARAMETERS *Args
+        );
+
+    /*******************************************************************************
+    **
+    **  getPower
+    **
+    **  Prepare power and clock operation.
+    */
+    gceSTATUS
+    (*getPower)(
+        IN gcsPLATFORM * Platform
+        );
+
+    /*******************************************************************************
+    **
+    **  putPower
+    **
+    **  Finish power and clock operation.
+    */
+    gceSTATUS
+    (*putPower)(
+        IN gcsPLATFORM * Platform
+        );
+
+    /*******************************************************************************
+    **
+    **  setPower
+    **
+    **  Set power state of specified GPU.
+    **
+    **  INPUT:
+    **
+    **      gceCORE GPU
+    **          GPU neeed to config.
+    **
+    **      gceBOOL Enable
+    **          Enable or disable power.
+    */
+    gceSTATUS
+    (*setPower)(
+        IN gcsPLATFORM * Platform,
+        IN gceCORE GPU,
+        IN gctBOOL Enable
+        );
+
+    /*******************************************************************************
+    **
+    **  setClock
+    **
+    **  Set clock state of specified GPU.
+    **
+    **  INPUT:
+    **
+    **      gceCORE GPU
+    **          GPU neeed to config.
+    **
+    **      gceBOOL Enable
+    **          Enable or disable clock.
+    */
+    gceSTATUS
+    (*setClock)(
+        IN gcsPLATFORM * Platform,
+        IN gceCORE GPU,
+        IN gctBOOL Enable
+        );
+
+    /*******************************************************************************
+    **
+    **  reset
+    **
+    **  Reset GPU outside.
+    **
+    **  INPUT:
+    **
+    **      gceCORE GPU
+    **          GPU neeed to reset.
+    */
+    gceSTATUS
+    (*reset)(
+        IN gcsPLATFORM * Platform,
+        IN gceCORE GPU
+        );
+
+    /*******************************************************************************
+    **
+    **  getGPUPhysical
+    **
+    **  Convert CPU physical address to GPU physical address if they are
+    **  different.
+    */
+    gceSTATUS
+    (*getGPUPhysical)(
+        IN gcsPLATFORM * Platform,
+        IN gctPHYS_ADDR_T CPUPhysical,
+        OUT gctPHYS_ADDR_T * GPUPhysical
+        );
+
+    /*******************************************************************************
+    **
+    **  getCPUPhysical
+    **
+    **  Convert GPU physical address to CPU physical address if they are
+    **  different.
+    */
+    gceSTATUS
+    (*getCPUPhysical)(
+        IN gcsPLATFORM * Platform,
+        IN gctPHYS_ADDR_T GPUPhysical,
+        OUT gctPHYS_ADDR_T * CPUPhysical
+        );
+
+    /*******************************************************************************
+    **
+    **  adjustProt
+    **
+    **  Override Prot flag when mapping paged memory to userspace.
+    */
+    gceSTATUS
+    (*adjustProt)(
+        IN struct vm_area_struct * vma
+        );
+
+    /*******************************************************************************
+    **
+    **  shrinkMemory
+    **
+    **  Do something to collect memory, eg, act as oom killer.
+    */
+    gceSTATUS
+    (*shrinkMemory)(
+        IN gcsPLATFORM * Platform
+        );
+
+    /*******************************************************************************
+    **
+    ** getPolicyID
+    **
+    ** Get policyID for a specified surface type.
+    */
+    gceSTATUS
+    (*getPolicyID)(
+        IN gcsPLATFORM *Platform,
+        IN gceVIDMEM_TYPE Type,
+        OUT gctUINT32_PTR PolicyID,
+        OUT gctUINT32_PTR AXIConfig
+        );
+}
+gcsPLATFORM_OPERATIONS;
+
+struct _gcsPLATFORM
+{
+    struct platform_device *device;
+    struct platform_driver *driver;
+
+    const char *name;
+    gcsPLATFORM_OPERATIONS* ops;
+
+    /* TODO: Remove AXI-SRAM size from feature database. */
+    gckDEVICE dev;
+
+    /* PLATFORM specific flags */
+    gctUINT32  flagBits;
+
+    void*                   priv;
+};
+
+int gckPLATFORM_Init(struct platform_driver *pdrv, gcsPLATFORM **platform);
+int gckPLATFORM_Terminate(gcsPLATFORM *platform);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c
@@ -0,0 +1,426 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include <linux/slab.h>
+
+#include "tee_client_api.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#define GPU3D_UUID   { 0xcc9f80ea, 0xa836, 0x11e3, { 0x9b, 0x07, 0x78, 0x2b, 0xcb, 0x5c, 0xf3, 0xe3 } }
+
+static const TEEC_UUID gpu3d_uuid = GPU3D_UUID;
+TEEC_Context teecContext;
+
+typedef struct _gcsSecurityChannel
+{
+    gckOS               os;
+    TEEC_Session        session;
+    int *               virtual;
+    TEEC_SharedMemory   inputBuffer;
+    gctUINT32           bytes;
+    gctPOINTER          mutex;
+}
+gcsSecurityChannel;
+
+TEEC_SharedMemory *
+gpu3d_allocate_secure_mem(
+    gckOS Os,
+    unsigned int size
+    )
+{
+    TEEC_Result result;
+    TEEC_Context *context = &teecContext;
+    TEEC_SharedMemory *shm = NULL;
+    void *handle = NULL;
+    gctPHYS_ADDR_T phyAddr;
+    gceSTATUS status;
+    gctSIZE_T bytes = size;
+
+    shm = kmalloc(sizeof(TEEC_SharedMemory), GFP_KERNEL);
+
+    if (NULL == shm)
+    {
+        return NULL;
+    }
+
+    memset(shm, 0, sizeof(TEEC_SharedMemory));
+
+    status = gckOS_AllocatePagedMemory(
+                Os,
+                gcvALLOC_FLAG_SECURITY,
+                &bytes,
+                gcvNULL,
+                (gctPHYS_ADDR *)&handle);
+
+    if (gcmIS_ERROR(status))
+    {
+         kfree(shm);
+         return NULL;
+    }
+
+    status = gckOS_GetPhysicalFromHandle(
+                Os,
+                handle,
+                0,
+                &phyAddr);
+
+    if (gcmIS_ERROR(status))
+    {
+         kfree(shm);
+         return NULL;
+    }
+
+    /* record the handle into shm->user_data */
+    shm->userdata = handle;
+
+    /* [b] Bulk input buffer. */
+    shm->size = size;
+    shm->flags = TEEC_MEM_INPUT;
+
+    /* Use TEE Client API to register the underlying memory buffer. */
+    shm->phyAddr = (void *)(gctUINT32)phyAddr;
+
+    result = TEEC_RegisterSharedMemory(
+            context,
+            shm);
+
+    if (result != TEEC_SUCCESS)
+    {
+        gckOS_FreePagedMemory(Os, (gctPHYS_ADDR)handle, shm->size);
+        kfree(shm);
+        return NULL;
+    }
+
+    return shm;
+}
+
+void gpu3d_release_secure_mem(
+    gckOS Os,
+    void *shm_handle
+    )
+{
+    TEEC_SharedMemory *shm = shm_handle;
+    void * handle;
+
+    if (!shm)
+    {
+        return;
+    }
+
+    handle = shm->userdata;
+
+    TEEC_ReleaseSharedMemory(shm);
+    gckOS_FreePagedMemory(Os, (gctPHYS_ADDR)handle, shm->size);
+
+    kfree(shm);
+
+    return;
+}
+
+static TEEC_Result gpu3d_session_callback(
+    TEEC_Session*   session,
+    uint32_t    commandID,
+    TEEC_Operation* operation,
+    void*   userdata
+    )
+{
+    gcsSecurityChannel *channel = userdata;
+
+    if (channel == gcvNULL)
+    {
+        return TEEC_ERROR_BAD_PARAMETERS;
+    }
+
+    switch (commandID)
+    {
+    case gcvTA_CALLBACK_ALLOC_SECURE_MEM:
+        {
+        uint32_t size = operation->params[0].value.a;
+        TEEC_SharedMemory *shm = NULL;
+
+        shm = gpu3d_allocate_secure_mem(channel->os, size);
+        if (shm == NULL)
+        {
+            return TEEC_ERROR_OUT_OF_MEMORY;
+        }
+
+        /* use the value to save the pointer in client side */
+        operation->params[0].value.a = (uint32_t)shm;
+        operation->params[0].value.b = (uint32_t)shm->phyAddr;
+
+        break;
+        }
+    case gcvTA_CALLBACK_FREE_SECURE_MEM:
+        {
+        TEEC_SharedMemory *shm = (TEEC_SharedMemory *)operation->params[0].value.a;
+
+        gpu3d_release_secure_mem(channel->os, shm);
+        break;
+        }
+    default:
+        break;
+    }
+
+    return TEEC_SUCCESS;
+}
+
+gceSTATUS
+gckOS_OpenSecurityChannel(
+    IN gckOS Os,
+    IN gceCORE GPU,
+    OUT gctUINT32 *Channel
+    )
+{
+    gceSTATUS status;
+    TEEC_Result result;
+    static bool initialized = gcvFALSE;
+    gcsSecurityChannel *channel = gcvNULL;
+
+    TEEC_Operation operation = {0};
+
+    /* Connect to TEE. */
+    if (initialized == gcvFALSE)
+    {
+        result = TEEC_InitializeContext(NULL, &teecContext);
+
+        if (result != TEEC_SUCCESS)
+        {
+            gcmkONERROR(gcvSTATUS_CHIP_NOT_READY);
+        }
+
+        initialized = gcvTRUE;
+    }
+
+    /* Construct channel. */
+    gcmkONERROR(
+        gckOS_Allocate(Os, gcmSIZEOF(*channel), (gctPOINTER *)&channel));
+
+    gckOS_ZeroMemory(channel, gcmSIZEOF(gcsSecurityChannel));
+
+    channel->os = Os;
+
+    gcmkONERROR(gckOS_CreateMutex(Os, &channel->mutex));
+
+    /* Allocate shared memory for passing gcTA_INTERFACE. */
+    channel->bytes = gcmSIZEOF(gcsTA_INTERFACE);
+    channel->virtual = kmalloc(channel->bytes, GFP_KERNEL | __GFP_NOWARN);
+
+    if (!channel->virtual)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+    }
+
+    channel->inputBuffer.size    = channel->bytes;
+    channel->inputBuffer.flags   = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+    channel->inputBuffer.phyAddr = (void *)virt_to_phys(channel->virtual);
+
+    result = TEEC_RegisterSharedMemory(&teecContext, &channel->inputBuffer);
+
+    if (result != TEEC_SUCCESS)
+    {
+        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+    }
+
+    operation.paramTypes = TEEC_PARAM_TYPES(
+            TEEC_VALUE_INPUT,
+            TEEC_NONE,
+            TEEC_NONE,
+            TEEC_NONE);
+
+    operation.params[0].value.a = GPU;
+
+    /* Open session with TEE application. */
+    result = TEEC_OpenSession(
+                &teecContext,
+                &channel->session,
+                &gpu3d_uuid,
+                TEEC_LOGIN_USER,
+                NULL,
+                &operation,
+                NULL);
+
+    /* Prepare callback. */
+    TEEC_RegisterCallback(&channel->session, gpu3d_session_callback, channel);
+
+    *Channel = (gctUINT32)channel;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (channel)
+    {
+        if (channel->virtual)
+        {
+        }
+
+        if (channel->mutex)
+        {
+            gcmkVERIFY_OK(gckOS_DeleteMutex(Os, channel->mutex));
+        }
+
+        gcmkVERIFY_OK(gckOS_Free(Os, channel));
+    }
+
+    return status;
+}
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+    IN gctUINT32 Channel
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CallSecurityService(
+    IN gctUINT32 Channel,
+    IN gcsTA_INTERFACE *Interface
+    )
+{
+    gceSTATUS status;
+    TEEC_Result result;
+    gcsSecurityChannel *channel = (gcsSecurityChannel *)Channel;
+    TEEC_Operation operation = {0};
+
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(Channel != 0);
+
+    gckOS_AcquireMutex(channel->os, channel->mutex, gcvINFINITE);
+
+    gckOS_MemCopy(channel->virtual, Interface, channel->bytes);
+
+    operation.paramTypes = TEEC_PARAM_TYPES(
+            TEEC_MEMREF_PARTIAL_INPUT,
+            TEEC_NONE,
+            TEEC_NONE,
+            TEEC_NONE);
+
+    /* Note: we use the updated size in the MemRef output by the encryption. */
+    operation.params[0].memref.parent = &channel->inputBuffer;
+    operation.params[0].memref.offset = 0;
+    operation.params[0].memref.size = sizeof(gcsTA_INTERFACE);
+    operation.started = true;
+
+    /* Start the commit command within the TEE application. */
+    result = TEEC_InvokeCommand(
+            &channel->session,
+            gcvTA_COMMAND_DISPATCH,
+            &operation,
+            NULL);
+
+    gckOS_MemCopy(Interface, channel->virtual, channel->bytes);
+
+    gckOS_ReleaseMutex(channel->os, channel->mutex);
+
+    if (result != TEEC_SUCCESS)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+    IN gctUINT32 Channel
+    )
+{
+    gceSTATUS status;
+    TEEC_Result result;
+    gcsSecurityChannel *channel = (gcsSecurityChannel *)Channel;
+    TEEC_Operation operation = {0};
+
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(Channel != 0);
+
+    operation.paramTypes = TEEC_PARAM_TYPES(
+            TEEC_MEMREF_PARTIAL_INPUT,
+            TEEC_NONE,
+            TEEC_NONE,
+            TEEC_NONE);
+
+    /* Note: we use the updated size in the MemRef output by the encryption. */
+    operation.params[0].memref.parent = &channel->inputBuffer;
+    operation.params[0].memref.offset = 0;
+    operation.params[0].memref.size = gcmSIZEOF(gcsTA_INTERFACE);
+    operation.started = true;
+
+    /* Start the commit command within the TEE application. */
+    result = TEEC_InvokeCommand(
+            &channel->session,
+            gcvTA_COMMAND_INIT,
+            &operation,
+            NULL);
+
+    if (result != TEEC_SUCCESS)
+    {
+        gcmkONERROR(gcvSTATUS_GENERIC_IO);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#if gcdENABLE_TRUST_APPLICATION
+
+gceSTATUS
+gckOS_OpenSecurityChannel(
+    IN gckOS Os,
+    IN gceCORE Core,
+    OUT gctUINT32 *Channel
+    )
+{
+    *Channel = Core + 1;
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+    OUT gctUINT32 Channel
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+    IN gctUINT32 Channel
+    )
+{
+    return gcvSTATUS_OK;
+}
+
+extern gceSTATUS
+TAEmulator (
+    gceCORE,
+    void *
+    );
+
+gceSTATUS
+gckOS_CallSecurityService(
+    IN gctUINT32 Channel,
+    IN gcsTA_INTERFACE *Interface
+    )
+{
+    gceCORE core;
+    gceSTATUS status;
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(Channel != 0);
+
+    core = (gceCORE)(Channel - 1);
+
+    TAEmulator(core, Interface);
+
+    status = Interface->result;
+
+    gcmkFOOTER();
+    return status;
+}
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c
@@ -0,0 +1,378 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+
+#if gcdLINUX_SYNC_FILE
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+
+#include "gc_hal_kernel_sync.h"
+#include "gc_hal_kernel_linux.h"
+
+#ifndef CONFIG_SYNC_FILE
+
+static struct sync_pt * viv_sync_pt_dup(struct sync_pt *sync_pt)
+{
+    gceSTATUS status;
+    struct viv_sync_pt *pt;
+    struct viv_sync_pt *src;
+    struct viv_sync_timeline *obj;
+
+    src = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+    obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+    obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+    /* Create the new sync_pt. */
+    pt = (struct viv_sync_pt *)
+        sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt));
+
+    pt->stamp  = src->stamp;
+
+    /* Reference signal. */
+    status = gckOS_MapSignal(obj->os,
+                             src->signal,
+                             gcvNULL /* (gctHANDLE) _GetProcessID() */,
+                             &pt->signal);
+
+    if (gcmIS_ERROR(status)) {
+        sync_pt_free((struct sync_pt *)pt);
+        return NULL;
+    }
+
+    return (struct sync_pt *)pt;
+}
+
+static int viv_sync_pt_has_signaled(struct sync_pt *sync_pt)
+{
+    gceSTATUS status;
+    struct viv_sync_pt *pt;
+    struct viv_sync_timeline *obj;
+
+    pt  = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+    obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+    obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+    status = _QuerySignal(obj->os, pt->signal);
+
+    if (gcmIS_ERROR(status)) {
+        /* Error. */
+        return -1;
+    }
+
+    return (int) status;
+}
+
+static int viv_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+    int ret;
+    struct viv_sync_pt *pt1 = (struct viv_sync_pt *)a;
+    struct viv_sync_pt *pt2 = (struct viv_sync_pt *)b;
+
+    ret = (pt1->stamp <  pt2->stamp) ? -1
+        : (pt1->stamp == pt2->stamp) ?  0
+        : 1;
+
+    return ret;
+}
+
+static void viv_sync_pt_free(struct sync_pt *sync_pt)
+{
+    struct viv_sync_pt *pt;
+    struct viv_sync_timeline *obj;
+
+    pt  = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+    obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+    obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+    gckOS_DestroySignal(obj->os, pt->signal);
+}
+
+static void viv_timeline_value_str(struct sync_timeline *timeline,
+                    char *str, int size)
+{
+    struct viv_sync_timeline *obj;
+
+    obj = (struct viv_sync_timeline *)timeline;
+    snprintf(str, size, "stamp_%llu", obj->stamp);
+}
+
+static void viv_pt_value_str(struct sync_pt *sync_pt, char *str, int size)
+{
+    struct viv_sync_pt *pt;
+
+    pt = (struct viv_sync_pt *)sync_pt;
+    snprintf(str, size, "signal_%lu@stamp_%llu",
+            (unsigned long)pt->signal, pt->stamp);
+}
+
+static struct sync_timeline_ops viv_timeline_ops =
+{
+    .driver_name = "viv_gpu_sync",
+    .dup = viv_sync_pt_dup,
+    .has_signaled = viv_sync_pt_has_signaled,
+    .compare = viv_sync_pt_compare,
+    .free_pt = viv_sync_pt_free,
+    .timeline_value_str = viv_timeline_value_str,
+    .pt_value_str = viv_pt_value_str,
+};
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS os)
+{
+    struct viv_sync_timeline * obj;
+
+    obj = (struct viv_sync_timeline *)
+        sync_timeline_create(&viv_timeline_ops, sizeof(struct viv_sync_timeline), name);
+
+    obj->os    = os;
+    obj->stamp = 0;
+
+    return obj;
+}
+
+struct sync_pt * viv_sync_pt_create(struct viv_sync_timeline *obj,
+                        gctSIGNAL Signal)
+{
+    gceSTATUS status;
+    struct viv_sync_pt *pt;
+
+    pt = (struct viv_sync_pt *)
+        sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt));
+
+    pt->stamp = obj->stamp++;
+
+    /* Dup signal. */
+    status = gckOS_MapSignal(obj->os,
+                             Signal,
+                             gcvNULL /* (gctHANDLE) _GetProcessID() */,
+                             &pt->signal);
+
+    if (gcmIS_ERROR(status)) {
+        sync_pt_free((struct sync_pt *)pt);
+        return NULL;
+    }
+
+    return (struct sync_pt *)pt;
+}
+
+#else
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os)
+{
+    struct viv_sync_timeline *timeline;
+
+    timeline = kmalloc(sizeof(struct viv_sync_timeline),
+                    gcdNOWARN | GFP_KERNEL);
+
+    if (!timeline)
+        return NULL;
+
+    strncpy(timeline->name, name, sizeof(timeline->name) - 1);
+    timeline->context = dma_fence_context_alloc(1);
+    atomic64_set(&timeline->seqno, 0);
+    timeline->os = Os;
+
+    return timeline;
+}
+
+void viv_sync_timeline_destroy(struct viv_sync_timeline *timeline)
+{
+    kfree(timeline);
+}
+
+static const char * viv_fence_get_driver_name(struct dma_fence *fence)
+{
+    return "viv_gpu_sync";
+}
+
+static const char * viv_fence_get_timeline_name(struct dma_fence *fence)
+{
+    struct viv_fence *f = (struct viv_fence *)fence;
+    return f->parent->name;
+}
+
+/* Same as fence_signaled. */
+static inline bool __viv_fence_signaled(struct dma_fence *fence)
+{
+    struct viv_fence *f = (struct viv_fence *)fence;
+    struct viv_sync_timeline *timeline = f->parent;
+    gceSTATUS status;
+
+    status = _QuerySignal(timeline->os, f->signal);
+
+    return (status == gcvSTATUS_TRUE) ? true : false;
+}
+
+static bool viv_fence_enable_signaling(struct dma_fence *fence)
+{
+    /* fence is locked already. */
+    return !__viv_fence_signaled(fence);
+}
+
+static bool viv_fence_signaled(struct dma_fence *fence)
+{
+    /* fence could be locked, could be not. */
+    return __viv_fence_signaled(fence);
+}
+
+static void viv_fence_release(struct dma_fence *fence)
+{
+    struct viv_fence *f = (struct viv_fence *)fence;
+    struct viv_sync_timeline *timeline = f->parent;
+
+    if (f->signal)
+        gckOS_DestroySignal(timeline->os, f->signal);
+
+    kfree(fence);
+}
+
+static struct dma_fence_ops viv_fence_ops =
+{
+    .get_driver_name = viv_fence_get_driver_name,
+    .get_timeline_name = viv_fence_get_timeline_name,
+    .enable_signaling = viv_fence_enable_signaling,
+    .signaled = viv_fence_signaled,
+    .wait = dma_fence_default_wait,
+    .release = viv_fence_release,
+};
+
+struct dma_fence * viv_fence_create(struct viv_sync_timeline *timeline,
+                    gcsSIGNAL *signal)
+{
+    gceSTATUS status;
+    struct viv_fence *fence;
+    struct dma_fence *old_fence = NULL;
+    unsigned seqno;
+
+    fence = kzalloc(sizeof(struct viv_fence), gcdNOWARN | GFP_KERNEL);
+
+    if (!fence)
+        return NULL;
+
+    /* Reference signal in fence. */
+    status = gckOS_MapSignal(timeline->os, (gctSIGNAL)(uintptr_t)signal->id,
+                NULL, &fence->signal);
+
+    if (gcmIS_ERROR(status)) {
+        kfree(fence);
+        return NULL;
+    }
+
+    spin_lock_init(&fence->lock);
+
+    fence->parent = timeline;
+
+    seqno = (unsigned)atomic64_inc_return(&timeline->seqno);
+
+    dma_fence_init((struct dma_fence *)fence, &viv_fence_ops,
+            &fence->lock, timeline->context, seqno);
+
+    /*
+     * Reference fence in signal.
+     * Be aware of recursive reference!!
+     */
+    spin_lock(&signal->lock);
+
+    if (signal->fence) {
+        old_fence = signal->fence;
+        signal->fence = NULL;
+    }
+
+    if (!signal->done) {
+        signal->fence = (struct dma_fence*)fence;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,68)
+        dma_fence_get((struct dma_fence*)fence);
+#endif
+    }
+
+    spin_unlock(&signal->lock);
+
+    if (old_fence)
+        dma_fence_put(old_fence);
+
+    if (!signal->fence) {
+        /* Fence already signaled. */
+        gckOS_DestroySignal(timeline->os, fence->signal);
+        fence->signal = NULL;
+
+        dma_fence_signal_locked((struct dma_fence*)fence);
+        dma_fence_put((struct dma_fence*)fence);
+        fence = NULL;
+    }
+
+    return (struct dma_fence*)fence;
+}
+
+#endif
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_sync_h_
+#define __gc_hal_kernel_sync_h_
+
+#include <linux/types.h>
+
+#ifndef CONFIG_SYNC_FILE
+
+/* sync.h is in drivers/staging/android/ for now. */
+#include <sync.h>
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+
+struct viv_sync_timeline
+{
+    /* Parent object. */
+    struct sync_timeline obj;
+
+    /* Timestamp when sync_pt is created. */
+    gctUINT64 stamp;
+
+    /* Pointer to os struct. */
+    gckOS os;
+};
+
+
+struct viv_sync_pt
+{
+    /* Parent object. */
+    struct sync_pt pt;
+
+    /* Reference signal. */
+    gctSIGNAL signal;
+
+    /* Timestamp when sync_pt is created. */
+    gctUINT64 stamp;
+};
+
+/* Create viv_sync_timeline object. */
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os);
+
+/* Create viv_sync_pt object. */
+struct sync_pt * viv_sync_pt_create(struct viv_sync_timeline *obj,
+                        gctSIGNAL signal);
+
+#else
+
+#include <linux/sync_file.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
+#  include <linux/fence.h>
+#  include <linux/fence-array.h>
+#else
+#  include <linux/dma-fence.h>
+#  include <linux/dma-fence-array.h>
+#endif
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+#include "gc_hal_kernel_linux.h"
+
+struct viv_sync_timeline
+{
+    char name[64];
+
+    /* Parent object. */
+    u64 context;
+
+    /* Timestamp when sync_pt is created. */
+    atomic64_t seqno;
+
+    /* Pointer to os struct. */
+    gckOS os;
+};
+
+struct viv_fence
+{
+    /* must be the first. */
+    struct dma_fence base;
+    spinlock_t lock;
+
+    struct viv_sync_timeline *parent;
+
+    /* link with signal. */
+    gctSIGNAL signal;
+};
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os);
+
+void viv_sync_timeline_destroy(struct viv_sync_timeline *timeline);
+
+struct dma_fence * viv_fence_create(struct viv_sync_timeline *timeline,
+                    gcsSIGNAL *signal);
+
+#endif
+
+#endif /* __gc_hal_kernel_sync_h_ */
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c
@@ -0,0 +1,450 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_platform.h"
+
+/* Disable MSI for internal FPGA build except PPC */
+#if gcdFPGA_BUILD && !defined(CONFIG_PPC)
+#define USE_MSI     0
+#else
+#define USE_MSI     1
+#endif
+
+gceSTATUS
+_AdjustParam(
+    IN gcsPLATFORM *Platform,
+    OUT gcsMODULE_PARAMETERS *Args
+    );
+
+gceSTATUS
+_GetGPUPhysical(
+    IN gcsPLATFORM * Platform,
+    IN gctPHYS_ADDR_T CPUPhysical,
+    OUT gctPHYS_ADDR_T *GPUPhysical
+    );
+
+static struct _gcsPLATFORM_OPERATIONS default_ops =
+{
+    .adjustParam   = _AdjustParam,
+    .getGPUPhysical = _GetGPUPhysical,
+};
+
+#if USE_LINUX_PCIE
+
+#define MAX_PCIE_DEVICE 4
+#define MAX_PCIE_BAR    6
+
+typedef struct _gcsBARINFO
+{
+    gctPHYS_ADDR_T base;
+    gctSIZE_T size;
+    gctPOINTER logical;
+}
+gcsBARINFO, *gckBARINFO;
+
+struct _gcsPCIEInfo
+{
+    gcsBARINFO bar[MAX_PCIE_BAR];
+    struct pci_dev *pdev;
+    gctPHYS_ADDR_T sram_bases[gcvSRAM_EXT_COUNT];
+    gctPHYS_ADDR_T sram_gpu_bases[gcvSRAM_EXT_COUNT];
+    uint32_t sram_sizes[gcvSRAM_EXT_COUNT];
+    int sram_bars[gcvSRAM_EXT_COUNT];
+    int sram_offsets[gcvSRAM_EXT_COUNT];
+};
+
+struct _gcsPLATFORM_PCIE
+{
+    struct _gcsPLATFORM base;
+    struct _gcsPCIEInfo pcie_info[MAX_PCIE_DEVICE];
+    unsigned int device_number;
+};
+
+
+struct _gcsPLATFORM_PCIE default_platform =
+{
+    .base =
+    {
+        .name = __FILE__,
+        .ops  = &default_ops,
+    },
+};
+
+void
+_QueryBarInfo(
+    struct pci_dev *Pdev,
+    gctPHYS_ADDR_T *BarAddr,
+    gctSIZE_T *BarSize,
+    gctUINT BarNum
+    )
+{
+    gctUINT addr;
+    gctUINT size;
+
+    /* Read the bar address */
+    if (pci_read_config_dword(Pdev, PCI_BASE_ADDRESS_0 + BarNum * 0x4, &addr) < 0)
+    {
+        return;
+    }
+
+    /* Read the bar size */
+    if (pci_write_config_dword(Pdev, PCI_BASE_ADDRESS_0 + BarNum * 0x4, 0xffffffff) < 0)
+    {
+        return;
+    }
+
+    if (pci_read_config_dword(Pdev, PCI_BASE_ADDRESS_0 + BarNum * 0x4, &size) < 0)
+    {
+        return;
+    }
+
+    size &= 0xfffffff0;
+    size  = ~size;
+    size += 1;
+
+    /* Write back the bar address */
+    if (pci_write_config_dword(Pdev, PCI_BASE_ADDRESS_0 + BarNum * 0x4, addr) < 0)
+    {
+        return;
+    }
+
+    gcmkPRINT("Bar%d addr=0x%x size=0x%x", BarNum, addr, size);
+
+    *BarAddr = addr;
+    *BarSize = size;
+}
+
+#else
+
+static struct _gcsPLATFORM default_platform =
+{
+    .name = __FILE__,
+    .ops  = &default_ops,
+};
+#endif
+
+gceSTATUS
+_AdjustParam(
+    IN gcsPLATFORM *Platform,
+    OUT gcsMODULE_PARAMETERS *Args
+    )
+{
+#if USE_LINUX_PCIE
+    struct _gcsPLATFORM_PCIE *pcie_platform = (struct _gcsPLATFORM_PCIE *)Platform;
+    struct pci_dev *pdev = pcie_platform->pcie_info[0].pdev;
+    unsigned char irqline = pdev->irq;
+    unsigned int i;
+
+    unsigned int dev_index, core_index = 0;
+    int sram_bar, sram_offset;
+
+    if (Args->irqs[gcvCORE_2D] != -1)
+    {
+        Args->irqs[gcvCORE_2D] = irqline;
+    }
+    if (Args->irqs[gcvCORE_MAJOR] != -1)
+    {
+        Args->irqs[gcvCORE_MAJOR] = irqline;
+    }
+
+    for (dev_index = 0; dev_index < pcie_platform->device_number; dev_index++)
+    {
+        struct pci_dev * pcieDev = pcie_platform->pcie_info[dev_index].pdev;
+
+        for (i = 0; i < MAX_PCIE_BAR; i++)
+        {
+            _QueryBarInfo(
+                pcieDev,
+                &pcie_platform->pcie_info[dev_index].bar[i].base,
+                &pcie_platform->pcie_info[dev_index].bar[i].size,
+                i
+                );
+        }
+
+        for (i = 0; i < gcvCORE_COUNT; i++)
+        {
+            if (Args->bars[i] != -1)
+            {
+                Args->irqs[core_index] = pcieDev->irq;
+
+                /* VIV bitfile: Merge last 4 cores to last one bar to support 8 cores. */
+                if (Args->bars[i] == 5)
+                {
+                    Args->registerBasesMapped[4] =
+                    pcie_platform->pcie_info[dev_index].bar[i].logical =
+                        (gctPOINTER)pci_iomap(pcieDev, Args->bars[i], 0x500000);
+                    Args->registerBasesMapped[5] = Args->registerBasesMapped[4] + 0x100000;
+                    Args->registerBasesMapped[6] = Args->registerBasesMapped[5] + 0x100000;
+                    Args->registerBasesMapped[7] = Args->registerBasesMapped[6] + 0x100000;
+
+                    Args->irqs[5] =
+                    Args->irqs[6] =
+                    Args->irqs[7] = Args->irqs[4];
+
+                    continue;
+                }
+
+                if (Args->regOffsets[i])
+                {
+                    gcmkASSERT(Args->regOffsets[i] + Args->registerSizes[core_index]
+                               < pcie_platform->pcie_info[dev_index].bar[Args->bars[i]].size);
+                }
+
+                Args->registerBasesMapped[core_index] =
+                pcie_platform->pcie_info[dev_index].bar[i].logical =
+                    (gctPOINTER)pci_iomap(pcieDev, Args->bars[i], Args->registerSizes[core_index] + Args->regOffsets[i]) + Args->regOffsets[i];
+
+                core_index++;
+            }
+        }
+
+        for (i = 0; i < gcvSRAM_EXT_COUNT; i++)
+        {
+            pcie_platform->pcie_info[dev_index].sram_bases[i] =
+            pcie_platform->pcie_info[dev_index].sram_gpu_bases[i] = Args->extSRAMBases[i];
+
+            pcie_platform->pcie_info[dev_index].sram_sizes[i] = Args->extSRAMSizes[i];
+
+            pcie_platform->pcie_info[dev_index].sram_bars[i] = sram_bar = Args->sRAMBars[i];
+            pcie_platform->pcie_info[dev_index].sram_offsets[i] = sram_offset = Args->sRAMOffsets[i];
+
+            /* Get CPU view SRAM base address from bar address and bar inside offset. */
+            if (sram_bar != -1 && sram_offset != -1)
+            {
+                pcie_platform->pcie_info[dev_index].sram_bases[i] = Args->extSRAMBases[i]
+                                                                  = pcie_platform->pcie_info[dev_index].bar[sram_bar].base
+                                                                  + sram_offset;
+            }
+        }
+    }
+
+    Args->contiguousRequested = gcvTRUE;
+#endif
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_GetGPUPhysical(
+    IN gcsPLATFORM * Platform,
+    IN gctPHYS_ADDR_T CPUPhysical,
+    OUT gctPHYS_ADDR_T *GPUPhysical
+    )
+{
+#if USE_LINUX_PCIE
+    struct _gcsPLATFORM_PCIE *pcie_platform = (struct _gcsPLATFORM_PCIE *)Platform;
+    /* Only support 1 external shared SRAM currently. */
+    gctPHYS_ADDR_T sram_base = pcie_platform->pcie_info[0].sram_bases[0];
+    gctPHYS_ADDR_T sram_gpu_base = pcie_platform->pcie_info[0].sram_gpu_bases[0];
+    uint32_t sram_size = pcie_platform->pcie_info[0].sram_sizes[0];
+
+    /* TODO: We should always set axi sram size by insmod parameters, never from feature database. */
+    if (!sram_size && Platform->dev && Platform->dev->extSRAMSizes[0])
+    {
+        sram_size = Platform->dev->extSRAMSizes[0];
+    }
+
+    if (sram_base != gcvINVALID_PHYSICAL_ADDRESS && sram_gpu_base != gcvINVALID_PHYSICAL_ADDRESS && sram_size)
+    {
+        if ((CPUPhysical >= sram_base) && (CPUPhysical < (sram_base + sram_size)))
+        {
+            *GPUPhysical = CPUPhysical - sram_base + sram_gpu_base;
+        }
+        else
+        {
+            *GPUPhysical = CPUPhysical;
+        }
+    }
+    else
+#endif
+    {
+        *GPUPhysical = CPUPhysical;
+    }
+
+    return gcvSTATUS_OK;
+}
+
+#if USE_LINUX_PCIE
+static const struct pci_device_id vivpci_ids[] = {
+  {
+    .class = 0x000000,
+    .class_mask = 0x000000,
+    .vendor = 0x10ee,
+    .device = 0x7012,
+    .subvendor = PCI_ANY_ID,
+    .subdevice = PCI_ANY_ID,
+    .driver_data = 0
+  }, { /* End: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, vivpci_ids);
+
+
+static int gpu_sub_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+    static u64 dma_mask = DMA_BIT_MASK(40);
+#else
+    static u64 dma_mask = DMA_40BIT_MASK;
+#endif
+
+    gcmkPRINT("PCIE DRIVER PROBED");
+    if (pci_enable_device(pdev)) {
+        printk(KERN_ERR "galcore: pci_enable_device() failed.\n");
+    }
+
+    if (pci_set_dma_mask(pdev, dma_mask)) {
+        printk(KERN_ERR "galcore: Failed to set DMA mask.\n");
+    }
+
+    pci_set_master(pdev);
+
+    if (pci_request_regions(pdev, "galcore")) {
+        printk(KERN_ERR "galcore: Failed to get ownership of BAR region.\n");
+    }
+
+#if USE_MSI
+    if (pci_enable_msi(pdev)) {
+        printk(KERN_ERR "galcore: Failed to enable MSI.\n");
+    }
+#endif
+    default_platform.pcie_info[default_platform.device_number++].pdev = pdev;
+    return 0;
+}
+
+static void gpu_sub_remove(struct pci_dev *pdev)
+{
+    pci_set_drvdata(pdev, NULL);
+#if USE_MSI
+    pci_disable_msi(pdev);
+#endif
+    pci_clear_master(pdev);
+    pci_release_regions(pdev);
+    pci_disable_device(pdev);
+    return;
+}
+
+static struct pci_driver gpu_pci_subdriver = {
+    .name = DEVICE_NAME,
+    .id_table = vivpci_ids,
+    .probe = gpu_sub_probe,
+    .remove = gpu_sub_remove
+};
+
+#endif
+
+static struct platform_device *default_dev;
+
+int gckPLATFORM_Init(struct platform_driver *pdrv,
+            struct _gcsPLATFORM **platform)
+{
+    int ret;
+    default_dev = platform_device_alloc(pdrv->driver.name, -1);
+
+    if (!default_dev) {
+        printk(KERN_ERR "galcore: platform_device_alloc failed.\n");
+        return -ENOMEM;
+    }
+
+    /* Add device */
+    ret = platform_device_add(default_dev);
+    if (ret) {
+        printk(KERN_ERR "galcore: platform_device_add failed.\n");
+        goto put_dev;
+    }
+
+    *platform = (gcsPLATFORM *)&default_platform;
+
+#if USE_LINUX_PCIE
+    ret = pci_register_driver(&gpu_pci_subdriver);
+#endif
+
+    return 0;
+
+put_dev:
+    platform_device_put(default_dev);
+
+    return ret;
+}
+
+int gckPLATFORM_Terminate(struct _gcsPLATFORM *platform)
+{
+    if (default_dev) {
+        platform_device_unregister(default_dev);
+        default_dev = NULL;
+    }
+
+#if USE_LINUX_PCIE
+    {
+        unsigned int dev_index;
+        struct _gcsPLATFORM_PCIE *pcie_platform = (struct _gcsPLATFORM_PCIE *)platform;
+        for (dev_index = 0; dev_index < pcie_platform->device_number; dev_index++)
+        {
+            unsigned int i;
+            for (i = 0; i < MAX_PCIE_BAR; i++)
+            {
+                if (pcie_platform->pcie_info[dev_index].bar[i].logical != 0)
+                {
+                    pci_iounmap(pcie_platform->pcie_info[dev_index].pdev, pcie_platform->pcie_info[dev_index].bar[i].logical);
+                }
+            }
+        }
+
+        pci_unregister_driver(&gpu_pci_subdriver);
+    }
+#endif
+
+    return 0;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.config
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.config
@@ -0,0 +1,3 @@
+ifeq ($(USE_LINUX_PCIE), 1)
+EXTRA_CFLAGS +=-DgcdIRQ_SHARED
+endif
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c
@@ -0,0 +1,1865 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_platform.h"
+#include "gc_hal_kernel_device.h"
+#include "gc_hal_driver.h"
+#include <linux/slab.h>
+#include <linux/pm_qos.h>
+
+#if defined(CONFIG_PM_OPP)
+#include <linux/pm_opp.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#  include <linux/of_platform.h>
+#  include <linux/of_gpio.h>
+#  include <linux/of_address.h>
+#endif
+
+#if USE_PLATFORM_DRIVER
+#   include <linux/platform_device.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+#  define IMX_GPU_SUBSYSTEM   1
+#  include <linux/component.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+#  include <mach/viv_gpu.h>
+#elif defined (CONFIG_PM)
+#  include <linux/pm_runtime.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+#    include <mach/busfreq.h>
+#  elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)
+#    include <linux/busfreq-imx6.h>
+#    include <linux/reset.h>
+#  else
+#      include <linux/busfreq-imx.h>
+#    include <linux/reset.h>
+#  endif
+#endif
+
+#include <linux/clk.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+#include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/svc/misc.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+static struct imx_sc_ipc *gpu_ipcHandle;
+#elif defined(IMX8_SCU_CONTROL)
+#include <soc/imx8/sc/sci.h>
+static sc_ipc_t gpu_ipcHandle;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+#  include <mach/hardware.h>
+#endif
+
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#ifdef CONFIG_DEVICE_THERMAL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#    include <linux/device_cooling.h>
+#    define REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a);
+#    define UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a);
+#  else
+extern int register_thermal_notifier(struct notifier_block *nb);
+extern int unregister_thermal_notifier(struct notifier_block *nb);
+#    define REG_THERMAL_NOTIFIER(a) register_thermal_notifier(a);
+#    define UNREG_THERMAL_NOTIFIER(a) unregister_thermal_notifier(a);
+#  endif
+#endif
+
+#ifndef gcdFSL_CONTIGUOUS_SIZE
+#  define gcdFSL_CONTIGUOUS_SIZE (4 << 20)
+#endif
+
+static int initgpu3DMinClock = 1;
+module_param(initgpu3DMinClock, int, 0644);
+
+struct platform_device *pdevice;
+
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+#  include <linux/kernel.h>
+#  include <linux/mm.h>
+#  include <linux/oom.h>
+#  include <linux/sched.h>
+#  include <linux/profile.h>
+
+struct task_struct *oom_crashpending;
+
+static int
+task_notify_func(struct notifier_block *self, unsigned long val, void *data)
+{
+    struct task_struct *task = data;
+
+    if (task == oom_crashpending) {
+        oom_crashpending = NULL;
+    }
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block task_nb = {
+    .notifier_call  = task_notify_func,
+};
+
+extern struct task_struct *oom_crashpending;
+static unsigned long oom_crashpending_timeout;
+
+static int force_contiguous_lowmem_shrink(IN gckKERNEL Kernel)
+{
+    struct task_struct *p;
+    struct task_struct *selected = NULL;
+    int tasksize;
+        int ret = -1;
+    int min_adj = 0;
+    int selected_tasksize = 0;
+    int selected_oom_adj;
+
+    /* Return if we already have a oom crash pending
+     */
+    if (oom_crashpending &&
+        time_before_eq(jiffies, oom_crashpending_timeout)) {
+        return 0;
+    }
+    selected_oom_adj = min_adj;
+
+    rcu_read_lock();
+
+    for_each_process(p) {
+        struct mm_struct *mm;
+        struct signal_struct *sig;
+                gcuDATABASE_INFO info;
+        int oom_adj;
+
+        task_lock(p);
+        mm = p->mm;
+        sig = p->signal;
+
+        if (!mm || !sig) {
+            task_unlock(p);
+            continue;
+        }
+
+        oom_adj = sig->oom_score_adj;
+
+        if (oom_adj < min_adj) {
+            task_unlock(p);
+            continue;
+        }
+
+        tasksize = 0;
+        task_unlock(p);
+
+        rcu_read_unlock();
+
+        if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK) {
+            tasksize += info.counters.bytes / PAGE_SIZE;
+        }
+
+        rcu_read_lock();
+
+        if (tasksize <= 0)
+            continue;
+
+        printk("<gpu> pid %d (%s), adj %d, size %d \n", p->pid, p->comm, oom_adj, tasksize);
+
+        if (selected) {
+            if (oom_adj < selected_oom_adj)
+                continue;
+            if (oom_adj == selected_oom_adj &&
+                tasksize <= selected_tasksize)
+                continue;
+        }
+        selected = p;
+        selected_tasksize = tasksize;
+        selected_oom_adj = oom_adj;
+    }
+
+    if (selected && selected_oom_adj > 0) {
+        printk("<gpu> send sigkill to %d (%s), adj %d, size %d\n",
+                 selected->pid, selected->comm,
+                 selected_oom_adj, selected_tasksize);
+        oom_crashpending = selected;
+        oom_crashpending_timeout = jiffies + HZ;
+        force_sig(SIGKILL, selected);
+        ret = 0;
+    }
+
+    rcu_read_unlock();
+    return ret;
+}
+
+extern gckKERNEL
+_GetValidKernel(
+  gckGALDEVICE Device
+  );
+
+static gceSTATUS
+_ShrinkMemory(
+    IN gcsPLATFORM * Platform
+    )
+{
+    struct platform_device *pdev;
+    gckGALDEVICE galDevice;
+    gckKERNEL kernel;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    pdev = Platform->device;
+
+    galDevice = platform_get_drvdata(pdev);
+
+    kernel = _GetValidKernel(galDevice);
+
+    if (kernel != gcvNULL)
+    {
+        if (force_contiguous_lowmem_shrink(kernel) != 0)
+            status = gcvSTATUS_OUT_OF_MEMORY;
+    }
+    else
+    {
+        printk("%s: can't find kernel!\n", __FUNCTION__);
+    }
+
+    return status;
+}
+#endif
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
+       void *dummy)
+{
+    static gctUINT orgFscale, minFscale, maxFscale;
+    static gctBOOL bAlreadyTooHot = gcvFALSE;
+    gckHARDWARE hardware;
+    gckGALDEVICE galDevice;
+    gctUINT FscaleVal = orgFscale;
+    gctUINT core = gcvCORE_MAJOR;
+
+    galDevice = platform_get_drvdata(pdevice);
+    if (!galDevice)
+    {
+        /* GPU is not ready, so it is meaningless to change GPU freq. */
+        return NOTIFY_OK;
+    }
+
+    if (!galDevice->kernels[gcvCORE_MAJOR])
+    {
+        return NOTIFY_OK;
+    }
+
+    hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
+
+    if (!hardware)
+    {
+        return NOTIFY_OK;
+    }
+
+    if (event && !bAlreadyTooHot) {
+        gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
+        FscaleVal = minFscale;
+        bAlreadyTooHot = gcvTRUE;
+        printk("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
+    } else if (!event && bAlreadyTooHot) {
+        printk("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
+        bAlreadyTooHot = gcvFALSE;
+    }
+
+    while (galDevice->kernels[core] && core <= gcvCORE_3D_MAX)
+    {
+        gckHARDWARE_SetFscaleValue(galDevice->kernels[core++]->hardware, FscaleVal, ~0U);
+    }
+
+    return NOTIFY_OK;
+}
+
+static struct notifier_block thermal_hot_pm_notifier =
+{
+    .notifier_call = thermal_hot_pm_notify,
+};
+
+static ssize_t gpu3DMinClock_show(struct device_driver *dev, char *buf)
+{
+    gctUINT currentf = 0, minf = 0, maxf = 0;
+    gckGALDEVICE galDevice;
+
+    galDevice = platform_get_drvdata(pdevice);
+
+    if (galDevice->kernels[gcvCORE_MAJOR])
+    {
+         gckHARDWARE_GetFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,
+            &currentf, &minf, &maxf);
+    }
+
+    snprintf(buf, PAGE_SIZE, "%d\n", minf);
+    return strlen(buf);
+}
+
+static ssize_t gpu3DMinClock_store(struct device_driver *dev, const char *buf, size_t count)
+{
+
+    gctINT fields;
+    gctUINT MinFscaleValue;
+    gckGALDEVICE galDevice;
+    gctUINT core = gcvCORE_MAJOR;
+
+    galDevice = platform_get_drvdata(pdevice);
+    if (!galDevice)
+         return -EINVAL;
+
+    fields = sscanf(buf, "%d", &MinFscaleValue);
+
+    if (fields < 1)
+         return -EINVAL;
+
+    while (galDevice->kernels[core] && core <= gcvCORE_3D_MAX)
+    {
+         gckHARDWARE_SetMinFscaleValue(galDevice->kernels[core++]->hardware,MinFscaleValue);
+    }
+
+    return count;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
+static DRIVER_ATTR_RW(gpu3DMinClock);
+#else
+static DRIVER_ATTR(gpu3DMinClock, S_IRUGO | S_IWUSR, gpu3DMinClock_show, gpu3DMinClock_store);
+#endif
+
+static ssize_t gpu3DClockScale_show(struct device_driver *dev, char *buf)
+{
+    gctUINT currentf = 0, minf = 0, maxf = 0;
+    gckGALDEVICE galDevice;
+
+    galDevice = platform_get_drvdata(pdevice);
+
+    if (galDevice->kernels[gcvCORE_MAJOR])
+    {
+         gckHARDWARE_GetFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,
+            &currentf, &minf, &maxf);
+    }
+
+    snprintf(buf, PAGE_SIZE, "%d\n", currentf);
+    return strlen(buf);
+}
+
+static ssize_t gpu3DClockScale_store(struct device_driver *dev, const char *buf, size_t count)
+{
+
+    gctINT fields;
+    gctUINT FscaleValue;
+    gckGALDEVICE galDevice;
+    gctUINT core = gcvCORE_MAJOR;
+
+    galDevice = platform_get_drvdata(pdevice);
+    if (!galDevice)
+         return -EINVAL;
+
+    fields = sscanf(buf, "%d", &FscaleValue);
+
+    if (fields < 1)
+         return -EINVAL;
+
+    while (galDevice->kernels[core] && core <= gcvCORE_3D_MAX)
+    {
+         gckHARDWARE_SetFscaleValue(galDevice->kernels[core++]->hardware,FscaleValue,FscaleValue);
+    }
+
+    return count;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
+static DRIVER_ATTR_RW(gpu3DClockScale);
+#else
+static DRIVER_ATTR(gpu3DClockScale, S_IRUGO | S_IWUSR, gpu3DClockScale_show, gpu3DClockScale_store);
+#endif
+
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+static const struct of_device_id mxs_gpu_dt_ids[] = {
+#ifdef IMX_GPU_SUBSYSTEM
+    { .compatible = "fsl,imx8-gpu-ss", },
+#endif
+    { .compatible = "fsl,imx6q-gpu", }, /*Backward Compatiblity */
+    {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
+#endif
+
+struct gpu_clk
+{
+    struct clk *clk_core;
+    struct clk *clk_shader;
+    struct clk *clk_axi;
+    struct clk *clk_ahb;
+};
+
+#if defined(CONFIG_PM_OPP)
+typedef enum _GOVERN_MODE
+{
+    OVERDRIVE,
+    NOMINAL,
+    UNDERDRIVE,
+    GOVERN_COUNT
+}
+GOVERN_MODE;
+
+static const char *govern_modes[] =
+{
+    "overdrive",
+    "nominal",
+    "underdrive"
+};
+
+struct gpu_govern
+{
+    unsigned long core_clk_freq[GOVERN_COUNT];
+    unsigned long shader_clk_freq[GOVERN_COUNT];
+    struct device* dev;
+    int num_modes;
+    int current_mode;
+};
+#endif
+
+struct imx_priv
+{
+    struct gpu_clk imx_gpu_clks[gcdMAX_GPU_COUNT];
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    /*Power management.*/
+    struct regulator *gpu_regulator;
+#  endif
+#endif
+    /*Run time pm*/
+    struct device *pmdev[gcdMAX_GPU_COUNT];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    struct reset_control *rstc[gcdMAX_GPU_COUNT];
+#endif
+
+    uint32_t sc_gpu_pid[gcdMAX_GPU_COUNT];
+
+    int gpu3dCount;
+
+#ifdef CONFIG_PM
+    int pm_qos_core;
+    struct pm_qos_request pm_qos;
+#endif
+
+#if defined(CONFIG_PM_OPP)
+    struct gpu_govern imx_gpu_govern;
+#endif
+};
+
+static struct imx_priv imxPriv;
+
+#if defined(CONFIG_PM_OPP)
+static ssize_t gpu_govern_show(struct device_driver *dev, char *buf)
+{
+    struct imx_priv *priv = &imxPriv;
+    int i;
+    ssize_t len;
+    int max_modes;
+
+    unsigned long core_freq;
+    unsigned long shader_freq;
+
+    if (priv->imx_gpu_govern.num_modes == GOVERN_COUNT)
+        max_modes = priv->imx_gpu_govern.num_modes - 1;
+    else
+        max_modes = priv->imx_gpu_govern.num_modes;
+
+    len = sprintf(buf, "GPU support %d modes\n", priv->imx_gpu_govern.num_modes);
+
+
+    for (i = priv->imx_gpu_govern.current_mode; i <= max_modes; i++)
+    {
+        core_freq   = priv->imx_gpu_govern.core_clk_freq[i];
+        shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
+
+        len += sprintf(buf + len,
+                "%s:\tcore_clk frequency: %lu\tshader_clk frequency: %lu\n",
+                govern_modes[i], core_freq, shader_freq);
+    }
+
+    len += sprintf(buf + len, "Currently GPU runs on mode %s\n",
+        govern_modes[priv->imx_gpu_govern.current_mode]);
+
+    return len;
+}
+
+static ssize_t gpu_govern_store(struct device_driver *dev, const char *buf, size_t count)
+{
+    unsigned long core_freq = 0;
+    unsigned long shader_freq = 0;
+    struct imx_priv *priv = &imxPriv;
+    int core = gcvCORE_MAJOR;
+    int i;
+
+    for (i = 0; i < GOVERN_COUNT; i++)
+    {
+        if (strstr(buf, govern_modes[i]))
+        {
+            break;
+        }
+    }
+
+    if (i == GOVERN_COUNT)
+    {
+        return count;
+    }
+
+    core_freq   = priv->imx_gpu_govern.core_clk_freq[i];
+    shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
+    priv->imx_gpu_govern.current_mode = i;
+
+    for (core = gcvCORE_MAJOR; core <= gcvCORE_3D_MAX; core++)
+    {
+        struct clk* clk_core   = priv->imx_gpu_clks[core].clk_core;
+        struct clk* clk_shader = priv->imx_gpu_clks[core].clk_shader;
+
+        if (clk_core != NULL && clk_shader != NULL &&
+            core_freq != 0 && shader_freq != 0)
+        {
+#ifdef CONFIG_PM
+            pm_runtime_get_sync(priv->pmdev[core]);
+#endif
+            clk_set_rate(clk_core, core_freq);
+            clk_set_rate(clk_shader, shader_freq);
+#ifdef CONFIG_PM
+            pm_runtime_put_sync(priv->pmdev[core]);
+#endif
+        }
+    }
+
+    return count;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
+static DRIVER_ATTR_RW(gpu_govern);
+#else
+static DRIVER_ATTR(gpu_govern, S_IRUGO | S_IWUSR, gpu_govern_show, gpu_govern_store);
+#endif
+
+int init_gpu_opp_table(struct device *dev)
+{
+    const struct property *prop;
+    const __be32 *val;
+    int nr;
+    int ret = 0;
+    int i, p;
+    struct imx_priv *priv = &imxPriv;
+
+    priv->imx_gpu_govern.num_modes = 0;
+
+    prop = of_find_property(dev->of_node, "operating-points", NULL);
+    if (!prop) {
+        return 0;
+    }
+
+    if (!prop->value) {
+        dev_err(dev, "operating-points invalid. Frequency scaling will not work\n");
+        return -ENODATA;
+    }
+
+    /*
+     * Each OPP is a set of tuples consisting of frequency and
+     * voltage like <freq-kHz vol-uV>.
+     */
+    nr = prop->length / sizeof(u32);
+    if (nr % 2) {
+        dev_err(dev, "%s: Invalid OPP list\n", __func__);
+        return -EINVAL;
+    }
+
+    /*
+     * We handle both cases where UNDERDRIVE is represented by a single tuple
+     * or when it is represented by two. More than 4 tuples means that we have
+     * the current mode defaulting to OVERDRIVE, while less than 3 means only
+     * nominal. Lastly just two tuples means UNDERDRIVE. Note that the tuples
+     * are divisible by 2 (X Y) hence there's no need to test for odd values.
+     */
+    if (nr < 6)
+        priv->imx_gpu_govern.current_mode = UNDERDRIVE;
+    else if (nr == 6 || nr == 8)
+        priv->imx_gpu_govern.current_mode = NOMINAL;
+    else
+        priv->imx_gpu_govern.current_mode = OVERDRIVE;
+
+    val = prop->value;
+
+    for (p = 0, i = priv->imx_gpu_govern.current_mode; nr > 0 && i < GOVERN_COUNT; nr -= 4)
+    {
+        unsigned long core_freq, core_volt, shader_freq, shader_volt;
+
+        core_freq = be32_to_cpup(val++) * 1000;
+        core_volt = be32_to_cpup(val++);
+
+        if (nr == 2)
+        {
+            shader_freq = core_freq;
+            shader_volt = core_volt;
+        }
+        else
+        {
+            shader_freq = be32_to_cpup(val++) * 1000;
+            shader_volt = be32_to_cpup(val++);
+        }
+
+        /* We only register core_clk frequency */
+        if (dev_pm_opp_add(dev, core_freq, core_volt))
+        {
+            dev_warn(dev, "%s: Failed to add OPP %ld\n",
+                 __func__, core_freq);
+            continue;
+        }
+
+        priv->imx_gpu_govern.core_clk_freq[i]   = core_freq;
+        priv->imx_gpu_govern.shader_clk_freq[i] = shader_freq;
+
+        p++;
+    i++;
+    }
+
+    priv->imx_gpu_govern.num_modes = p;
+    priv->imx_gpu_govern.dev = dev;
+
+    if (priv->imx_gpu_govern.num_modes > 0)
+    {
+        ret = driver_create_file(dev->driver, &driver_attr_gpu_govern);
+        if (ret) {
+            dev_err(dev, "create gpu_govern attr failed (%d)\n", ret);
+        return ret;
+    }
+    }
+
+    return ret;
+}
+
+int remove_gpu_opp_table(void)
+{
+    struct imx_priv *priv = &imxPriv;
+    struct device* dev = priv->imx_gpu_govern.dev;
+    int i = 0;
+    int max_modes;
+
+    if (priv->imx_gpu_govern.num_modes == GOVERN_COUNT)
+        max_modes = priv->imx_gpu_govern.num_modes - 1;
+    else
+        max_modes = priv->imx_gpu_govern.num_modes;
+
+    /* if we don't have any modes available we don't have OPP */
+    if (max_modes == 0)
+        return 0;
+
+    for (i = priv->imx_gpu_govern.current_mode; i <= max_modes; i++)
+    {
+        unsigned long core_freq;
+
+        core_freq = priv->imx_gpu_govern.core_clk_freq[i];
+        dev_pm_opp_remove(dev, core_freq);
+    }
+
+    if (i > 0)
+    {
+        driver_remove_file(dev->driver, &driver_attr_gpu_govern);
+    }
+
+    return 0;
+}
+#endif
+
+#ifdef IMX_GPU_SUBSYSTEM
+
+static int use_imx_gpu_subsystem;
+
+/* sub device component ops. */
+static int mxc_gpu_sub_bind(struct device *dev,
+                struct device *master, void *data)
+{
+    return 0;
+}
+
+static void mxc_gpu_sub_unbind(struct device *dev, struct device *master, void *data)
+{
+}
+
+static const struct component_ops mxc_gpu_sub_ops =
+{
+    .bind   = mxc_gpu_sub_bind,
+    .unbind = mxc_gpu_sub_unbind,
+};
+
+/* sub device driver. */
+static const struct of_device_id mxc_gpu_sub_match[] =
+{
+    { .compatible = "fsl,imx8-gpu"},
+    { /* sentinel */ }
+};
+
+static int mxc_gpu_sub_probe(struct platform_device *pdev)
+{
+    return component_add(&pdev->dev, &mxc_gpu_sub_ops);
+}
+
+static int mxc_gpu_sub_remove(struct platform_device *pdev)
+{
+    component_del(&pdev->dev, &mxc_gpu_sub_ops);
+    return 0;
+}
+
+struct platform_driver mxc_gpu_sub_driver =
+{
+    .driver = {
+        .name  = "mxc-gpu",
+        .owner = THIS_MODULE,
+        .of_match_table = mxc_gpu_sub_match,
+    },
+
+    .probe  = mxc_gpu_sub_probe,
+    .remove = mxc_gpu_sub_remove,
+};
+
+static int register_mxc_gpu_sub_driver(void)
+{
+    return use_imx_gpu_subsystem ? platform_driver_register(&mxc_gpu_sub_driver) : 0;
+}
+
+static void unregister_mxc_gpu_sub_driver(void)
+{
+    if (use_imx_gpu_subsystem) {
+        platform_driver_unregister(&mxc_gpu_sub_driver);
+    }
+}
+
+static int patch_param_imx8_subsystem(struct platform_device *pdev,
+                gcsMODULE_PARAMETERS *args)
+{
+    int i = 0;
+    struct resource* res;
+    struct imx_priv *priv = &imxPriv;
+    struct device_node *node = pdev->dev.of_node;
+    struct device_node *core_node;
+    int core = gcvCORE_MAJOR;
+
+    while ((core_node = of_parse_phandle(node, "cores", i++)) != NULL &&
+            core < gcvCORE_COUNT) {
+        struct platform_device *pdev_gpu;
+        int irqLine = -1;
+
+        if (!of_device_is_available(core_node)) {
+            of_node_put(core_node);
+            continue;
+        }
+
+        pdev_gpu = of_find_device_by_node(core_node);
+
+        if (!pdev_gpu)
+            break;
+
+#ifdef CONFIG_PM
+        if(of_device_is_compatible(core_node,"fsl,imx8-vipsi")) {
+            priv->pm_qos_core = core;
+        }
+#endif
+
+        irqLine = platform_get_irq(pdev_gpu, 0);
+
+        if (irqLine < 0)
+            break;
+
+        res = platform_get_resource(pdev_gpu, IORESOURCE_MEM, 0);
+
+        if (!res)
+            break;
+
+        while(!priv->pmdev[core] && core < (gcvCORE_COUNT-1))
+            core++;
+
+        args->irqs[core] = irqLine;
+        args->registerBases[core] = res->start;
+        args->registerSizes[core] = res->end - res->start + 1;
+
+        of_node_put(core_node);
+        ++core;
+    }
+
+    if (core_node)
+        of_node_put(core_node);
+
+    return 0;
+}
+
+static inline int get_power_imx8_subsystem(struct device *pdev)
+{
+    struct imx_priv *priv = &imxPriv;
+    struct clk *clk_core = NULL;
+    struct clk *clk_shader = NULL;
+    struct clk *clk_axi = NULL;
+    struct clk *clk_ahb = NULL;
+
+    /* Initialize the clock structure */
+    int i = 0;
+    struct device_node *node = pdev->of_node;
+    struct device_node *core_node;
+    int core = gcvCORE_MAJOR;
+
+    while ((core_node = of_parse_phandle(node, "cores", i++)) != NULL) {
+        struct platform_device *pdev_gpu = NULL;
+        clk_shader = NULL;
+        clk_core = NULL;
+        clk_axi = NULL;
+        clk_ahb = NULL;
+
+        if (!of_device_is_available(core_node)) {
+            of_node_put(core_node);
+            continue;
+        }
+
+        pdev_gpu = of_find_device_by_node(core_node);
+
+        if (!pdev_gpu)
+            break;
+
+        clk_core = clk_get(&pdev_gpu->dev, "core");
+
+        if (IS_ERR(clk_core)) {
+            printk("galcore: clk_get clk_core failed\n");
+            break;
+        }
+
+        clk_axi = clk_get(&pdev_gpu->dev, "axi");
+
+        if (IS_ERR(clk_axi))
+            clk_axi = NULL;
+
+        clk_ahb = clk_get(&pdev_gpu->dev, "ahb");
+
+        if (IS_ERR(clk_ahb))
+            clk_ahb = NULL;
+
+        clk_shader = clk_get(&pdev_gpu->dev, "shader");
+
+        if (IS_ERR(clk_shader)) {
+            priv->gpu3dCount = core;
+            core = gcvCORE_2D;
+            clk_shader = NULL;
+        }
+
+#if defined(CONFIG_ANDROID) && LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+        /* TODO: freescale BSP issue in some platform like imx8dv. */
+        clk_prepare(clk_core);
+        clk_set_rate(clk_core, 800000000);
+        clk_unprepare(clk_core);
+
+        clk_prepare(clk_shader);
+        clk_set_rate(clk_shader, 800000000);
+        clk_unprepare(clk_shader);
+#endif
+
+        priv->imx_gpu_clks[core].clk_shader = clk_shader;
+        priv->imx_gpu_clks[core].clk_core   = clk_core;
+        priv->imx_gpu_clks[core].clk_axi    = clk_axi;
+        priv->imx_gpu_clks[core].clk_ahb    = clk_ahb;
+
+        if (of_property_read_u32(core_node, "fsl,sc_gpu_pid", &priv->sc_gpu_pid[core])) {
+            priv->sc_gpu_pid[core] = 0;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+        else if (!gpu_ipcHandle) {
+            uint32_t ret = imx_scu_get_handle(&gpu_ipcHandle);
+            if (ret != 0) {
+                printk("galcore: cannot open MU channel to SCU\n");
+                return ret;
+            }
+    }
+#elif defined(IMX8_SCU_CONTROL)
+        else if (!gpu_ipcHandle) {
+            sc_err_t sciErr;
+            uint32_t mu_id;
+            sciErr = sc_ipc_getMuID(&mu_id);
+
+            if (sciErr != SC_ERR_NONE) {
+                printk("galcore; cannot obtain mu id\n");
+                return -EINVAL;
+            }
+
+            sciErr = sc_ipc_open(&gpu_ipcHandle, mu_id);
+
+            if (sciErr != SC_ERR_NONE) {
+                printk("galcore: cannot open MU channel to SCU\n");
+                return -EINVAL;
+            }
+        }
+#endif
+
+#ifdef CONFIG_PM
+        pm_runtime_get_noresume(&pdev_gpu->dev);
+        pm_runtime_set_active(&pdev_gpu->dev);
+        pm_runtime_enable(&pdev_gpu->dev);
+        pm_runtime_put_sync(&pdev_gpu->dev);
+        priv->pmdev[core] = &pdev_gpu->dev;
+#endif
+        of_node_put(core_node);
+        ++core;
+    }
+
+    if (core <= gcvCORE_3D_MAX)
+        priv->gpu3dCount = core;
+
+    if (core_node)
+        of_node_put(core_node);
+
+    return 0;
+}
+
+#endif
+
+static int patch_param_imx6(struct platform_device *pdev,
+                gcsMODULE_PARAMETERS *args)
+{
+    struct resource* res;
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
+
+    if (res)
+        args->irqs[gcvCORE_MAJOR] = res->start;
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
+
+    if (res) {
+        args->registerBases[gcvCORE_MAJOR] = res->start;
+        args->registerSizes[gcvCORE_MAJOR] = res->end - res->start + 1;
+    }
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
+
+    if (res)
+        args->irqs[gcvCORE_2D] = res->start;
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
+
+    if (res) {
+        args->registerBases[gcvCORE_2D] = res->start;
+        args->registerSizes[gcvCORE_2D] = res->end - res->start + 1;
+    }
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
+
+    if (res)
+        args->irqs[gcvCORE_VG] = res->start;
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
+
+    if (res) {
+        args->registerBases[gcvCORE_VG] = res->start;
+        args->registerSizes[gcvCORE_VG] = res->end - res->start + 1;
+    }
+
+    return 0;
+}
+
+static bool is_layerscape;
+
+static int patch_param_ls(struct platform_device *pdev,
+        gcsMODULE_PARAMETERS *args)
+{
+    struct device_node *node = pdev->dev.of_node;
+    struct resource *res;
+    int core = gcvCORE_MAJOR;
+    struct platform_device *pdev_gpu;
+    int irqLine = -1;
+
+    pdev_gpu = of_find_device_by_node(node);
+    if (!pdev_gpu)
+        return gcvSTATUS_DEVICE;
+
+    of_node_put(node);
+
+    irqLine = platform_get_irq(pdev_gpu, 0);
+    if (irqLine < 0)
+        return gcvSTATUS_NOT_FOUND;
+
+    res = platform_get_resource(pdev_gpu, IORESOURCE_MEM, 0);
+    if (!res)
+        return gcvSTATUS_NOT_FOUND;
+
+    args->irqs[core] = irqLine;
+    args->registerBases[core] = res->start;
+    args->registerSizes[core] = res->end - res->start + 1;
+
+    return 0;
+}
+
+static int patch_param(struct platform_device *pdev,
+                gcsMODULE_PARAMETERS *args)
+{
+    struct resource* res;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+    struct device_node *node;
+    struct resource res_mem;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    struct device_node *dn =pdev->dev.of_node;
+    const u32 *prop;
+#else
+    struct viv_gpu_platform_data *pdata;
+#endif
+
+    pdevice = pdev;
+
+    if (is_layerscape) {
+        patch_param_ls(pdev, args);
+    } else {
+#ifdef IMX_GPU_SUBSYSTEM
+        if (pdev->dev.of_node && use_imx_gpu_subsystem)
+            patch_param_imx8_subsystem(pdev, args);
+        else
+#endif
+            patch_param_imx6(pdev, args);
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    if(args->compression == gcvCOMPRESSION_OPTION_DEFAULT)
+    {
+        const u32 *property;
+
+        property = of_get_property(pdev->dev.of_node, "depth-compression", NULL);
+        if (property && *property == 0)
+        {
+            args->compression &= ~gcvCOMPRESSION_OPTION_DEPTH;
+        }
+    }
+#endif
+
+    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
+
+    if (res && !args->baseAddress && !args->physSize) {
+        args->baseAddress = res->start;
+        args->physSize = res->end - res->start + 1;
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+    node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+
+    if (node && !of_address_to_resource(node, 0, &res_mem))
+    {
+        res = &res_mem;
+    }
+    else
+    {
+        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "contiguous_mem");
+    }
+
+    if (node)
+    {
+        of_node_put(node);
+    }
+
+    if (res) {
+        if (args->contiguousBase == 0)
+            args->contiguousBase = res->start;
+
+        if  (args->contiguousSize == ~0U)
+            args->contiguousSize = res->end - res->start + 1;
+    }
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    args->contiguousBase = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    prop = of_get_property(dn, "contiguousbase", NULL);
+
+    if (prop)
+        args->contiguousBase = *prop;
+
+    of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
+#else
+
+    pdata = pdev->dev.platform_data;
+
+    if (pdata) {
+        args->contiguousBase = pdata->reserved_mem_base;
+        args->contiguousSize = pdata->reserved_mem_size;
+    }
+
+#endif
+
+    if (args->contiguousSize == ~0U) {
+       printk("Warning: No contiguous memory is reserverd for gpu.!\n");
+       printk("Warning: Will use default value(%d) for the reserved memory!\n", gcdFSL_CONTIGUOUS_SIZE);
+
+       args->contiguousSize = gcdFSL_CONTIGUOUS_SIZE;
+    }
+
+    args->gpu3DMinClock = initgpu3DMinClock;
+
+    if (args->physSize == 0) {
+#if defined(IMX8_PHYS_BASE)
+        args->baseAddress = IMX8_PHYS_BASE;
+#endif
+
+#if defined(IMX8_PHYS_SIZE)
+        args->physSize = IMX8_PHYS_SIZE;
+#else
+        args->physSize = 0x80000000;
+#endif
+    }
+
+    return 0;
+}
+
+int init_priv(void)
+{
+    memset(&imxPriv, 0, sizeof(imxPriv));
+
+#ifdef CONFIG_PM
+    imxPriv.pm_qos_core = -1;
+#endif
+
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+    task_free_register(&task_nb);
+#  else
+    task_handoff_register(&task_nb);
+#  endif
+#endif
+
+    return 0;
+}
+
+void
+free_priv(void)
+{
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+     task_free_unregister(&task_nb);
+#  else
+    task_handoff_unregister(&task_nb);
+#  endif
+#endif
+}
+
+static int set_clock(int gpu, int enable);
+static int set_power(int gpu, int enable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+static void imx6sx_optimize_qosc_for_GPU(void)
+{
+    struct device_node *np;
+    void __iomem *src_base;
+
+    np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-qosc");
+    if (!np)
+        return;
+
+    src_base = of_iomap(np, 0);
+    WARN_ON(!src_base);
+
+    set_power(gcvCORE_MAJOR, 1);
+    set_clock(gcvCORE_MAJOR, 1);
+
+    writel_relaxed(0, src_base); /* Disable clkgate & soft_rst */
+    writel_relaxed(0, src_base+0x60); /* Enable all masters */
+    writel_relaxed(0, src_base+0x1400); /* Disable clkgate & soft_rst for gpu */
+    writel_relaxed(0x0f000222, src_base+0x1400+0xd0); /* Set Write QoS 2 for gpu */
+    writel_relaxed(0x0f000822, src_base+0x1400+0xe0); /* Set Read QoS 8 for gpu */
+
+    set_clock(gcvCORE_MAJOR, 0);
+    set_power(gcvCORE_MAJOR, 0);
+
+    return;
+}
+#endif
+
+static inline int get_power_imx6(struct device *pdev)
+{
+    struct imx_priv *priv = &imxPriv;
+    struct clk *clk_core = NULL;
+    struct clk *clk_shader = NULL;
+    struct clk *clk_axi = NULL;
+    struct clk *clk_ahb = NULL;
+
+#ifdef CONFIG_RESET_CONTROLLER
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    struct reset_control *rstc;
+
+    rstc = devm_reset_control_get(pdev, "gpu3d");
+    priv->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0)
+    rstc = devm_reset_control_get_shared(pdev, "gpu2d");
+    priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
+    rstc = devm_reset_control_get_shared(pdev, "gpuvg");
+#    else
+    rstc = devm_reset_control_get(pdev, "gpu2d");
+    priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
+    rstc = devm_reset_control_get(pdev, "gpuvg");
+#    endif
+    priv->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
+#  endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+    /* Get gpu regulator */
+    priv->gpu_regulator = regulator_get(pdev, "cpu_vddgpu");
+#  elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    priv->gpu_regulator = devm_regulator_get(pdev, "pu");
+#  endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    if (IS_ERR(priv->gpu_regulator)) {
+       printk("%s: Failed to get gpu regulator\n", __FUNCTION__);
+       return -ENXIO;
+    }
+#  endif
+#endif
+
+    clk_core = clk_get(pdev, "gpu3d_clk");
+
+    if (!IS_ERR(clk_core)) {
+        clk_axi = clk_get(pdev, "gpu3d_axi_clk");
+        clk_shader = clk_get(pdev, "gpu3d_shader_clk");
+
+        if (IS_ERR(clk_shader)) {
+            clk_put(clk_core);
+            clk_core = NULL;
+            clk_shader = NULL;
+            printk("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
+        }
+
+        clk_ahb = clk_get(pdev, "gpu3d_ahb_clk");
+        if (IS_ERR(clk_ahb)) {
+            clk_ahb = NULL;
+        }
+    } else {
+        clk_core = NULL;
+        printk("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
+    }
+
+    priv->imx_gpu_clks[gcvCORE_MAJOR].clk_core = clk_core;
+    priv->imx_gpu_clks[gcvCORE_MAJOR].clk_shader = clk_shader;
+    priv->imx_gpu_clks[gcvCORE_MAJOR].clk_axi = clk_axi;
+    priv->imx_gpu_clks[gcvCORE_MAJOR].clk_ahb = clk_ahb;
+
+    clk_core = clk_get(pdev, "gpu2d_clk");
+
+    if (IS_ERR(clk_core)) {
+        clk_core = NULL;
+        printk("galcore: clk_get 2d core clock failed, disable 2d/vg!\n");
+    } else {
+        clk_axi = clk_get(pdev, "gpu2d_axi_clk");
+        if (IS_ERR(clk_axi)) {
+            clk_axi = NULL;
+            printk("galcore: clk_get 2d axi clock failed, disable 2d\n");
+        }
+        clk_ahb = clk_get(pdev, "gpu2d_ahb_clk");
+        if (IS_ERR(clk_ahb)) {
+            clk_ahb = NULL;
+        }
+
+        priv->imx_gpu_clks[gcvCORE_2D].clk_ahb = clk_ahb;
+        priv->imx_gpu_clks[gcvCORE_2D].clk_core = clk_core;
+        priv->imx_gpu_clks[gcvCORE_2D].clk_axi = clk_axi;
+
+        clk_axi = clk_get(pdev, "openvg_axi_clk");
+
+        if (IS_ERR(clk_axi)) {
+            clk_axi = NULL;
+            printk("galcore: clk_get vg clock failed, disable vg!\n");
+        }
+
+        priv->imx_gpu_clks[gcvCORE_VG].clk_core = clk_core;
+        priv->imx_gpu_clks[gcvCORE_VG].clk_axi = clk_axi;
+    }
+
+#ifdef CONFIG_PM
+    pm_runtime_enable(pdev);
+
+    priv->pmdev[gcvCORE_MAJOR] = pdev;
+    priv->pmdev[gcvCORE_2D]    = pdev;
+    priv->pmdev[gcvCORE_VG]    = pdev;
+#endif
+
+    return 0;
+}
+
+static inline int get_power(struct device *pdev)
+{
+    int ret;
+
+    /*Initialize the clock structure*/
+#ifdef IMX_GPU_SUBSYSTEM
+    if (pdev->of_node && use_imx_gpu_subsystem)
+        ret = get_power_imx8_subsystem(pdev);
+    else
+#endif
+        ret = get_power_imx6(pdev);
+
+    if (ret)
+        return ret;
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+    REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
+
+    ret = driver_create_file(pdev->driver, &driver_attr_gpu3DMinClock);
+
+    if (ret)
+        dev_err(pdev, "create gpu3DMinClock attr failed (%d)\n", ret);
+
+    ret = driver_create_file(pdev->driver, &driver_attr_gpu3DClockScale);
+
+    if (ret)
+        dev_err(pdev, "create gpu3DClockScale attr failed (%d)\n", ret);
+#endif
+
+#if defined(CONFIG_PM_OPP)
+    ret = init_gpu_opp_table(pdev);
+    if (ret)
+        dev_err(pdev, "OPP init failed!\n");
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    imx6sx_optimize_qosc_for_GPU();
+#endif
+
+    return 0;
+}
+
+static inline void put_power(void)
+{
+    int core = 0;
+    struct gpu_clk *imx_clk = NULL;
+    struct imx_priv *priv = &imxPriv;
+    struct device *pmdev_last = NULL;/*legacy gpu device entry for imx6*/
+    struct clk *clk_core_last = NULL;/*vg has same core clk as 2d */
+
+    for (core = 0; core < gcdMAX_GPU_COUNT; core++) {
+        imx_clk = &priv->imx_gpu_clks[core];
+
+        if (imx_clk->clk_core && imx_clk->clk_core != clk_core_last) {
+             clk_put(imx_clk->clk_core);
+             clk_core_last = imx_clk->clk_core;
+             imx_clk->clk_core = NULL;
+        }
+
+        if (imx_clk->clk_shader) {
+             clk_put(imx_clk->clk_shader);
+             imx_clk->clk_shader = NULL;
+        }
+
+        if (imx_clk->clk_axi) {
+             clk_put(imx_clk->clk_axi);
+             imx_clk->clk_axi = NULL;
+        }
+
+        if (imx_clk->clk_ahb) {
+             clk_put(imx_clk->clk_ahb);
+             imx_clk->clk_ahb = NULL;
+        }
+
+#ifdef CONFIG_PM
+        if (priv->pmdev[core] && priv->pmdev[core] != pmdev_last){
+            pm_runtime_disable(priv->pmdev[core]);
+            pmdev_last = priv->pmdev[core];
+        }
+#endif
+    }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+    if (priv->gpu_regulator) {
+       regulator_put(priv->gpu_regulator);
+       priv->gpu_regulator = NULL;
+    }
+#endif
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+    UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
+
+    driver_remove_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock);
+
+    driver_remove_file(pdevice->dev.driver, &driver_attr_gpu3DClockScale);
+#endif
+
+#if defined(CONFIG_PM_OPP)
+    remove_gpu_opp_table();
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)) && defined(IMX8_SCU_CONTROL)
+    if (gpu_ipcHandle)
+        sc_ipc_close(gpu_ipcHandle);
+#endif
+}
+
+static inline int set_power(int gpu, int enable)
+{
+#ifdef CONFIG_PM
+    struct imx_priv* priv = &imxPriv;
+#endif
+
+    struct clk *clk_core = priv->imx_gpu_clks[gpu].clk_core;
+    struct clk *clk_shader = priv->imx_gpu_clks[gpu].clk_shader;
+    struct clk *clk_axi = priv->imx_gpu_clks[gpu].clk_axi;
+    struct clk *clk_ahb = priv->imx_gpu_clks[gpu].clk_ahb;
+
+    if (enable) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+        if (!IS_ERR(priv->gpu_regulator)) {
+            int ret = regulator_enable(priv->gpu_regulator);
+
+            if (ret)
+                printk("%s: fail to enable pu regulator %d!\n", __FUNCTION__, ret);
+        }
+#  else
+        imx_gpc_power_up_pu(true);
+#  endif
+#endif
+
+#ifdef CONFIG_PM
+        pm_runtime_get_sync(priv->pmdev[gpu]);
+        if(priv->pm_qos_core == gpu) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+            cpu_latency_qos_add_request(&priv->pm_qos, 0);
+#else
+            pm_qos_add_request(&(priv->pm_qos), PM_QOS_CPU_DMA_LATENCY, 0);
+#endif
+        }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+        if (priv->sc_gpu_pid[gpu]) {
+            uint32_t ret = imx_sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], IMX_SC_C_ID, gpu);
+            if (ret) {
+                printk("galcore: failed to set gpu id for 3d_%d\n", gpu);
+                return ret;
+            }
+            if (priv->gpu3dCount > 1) {
+                ret = imx_sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], IMX_SC_C_SINGLE_MODE, 0);
+                if (ret) {
+                    printk("galcore: failed to set gpu dual mode for 3d_%d\n", gpu);
+                    return ret;
+                }
+            } else {
+                ret = imx_sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], IMX_SC_C_SINGLE_MODE, 1);
+                if (ret) {
+                printk("galcore: failed to set gpu single mode for 3d_%d\n", gpu);
+                return ret;
+                }
+            }
+        }
+#elif defined(IMX8_SCU_CONTROL)
+        if (priv->sc_gpu_pid[gpu]) {
+            sc_err_t sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_ID, gpu);
+            if (sciErr != SC_ERR_NONE)
+                printk("galcore: failed to set gpu id for 3d_%d\n", gpu);
+
+            if (priv->gpu3dCount > 1) {
+                sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_SINGLE_MODE, 0);
+                if (sciErr != SC_ERR_NONE)
+                    printk("galcore: failed to set gpu dual mode for 3d_%d\n", gpu);
+            } else {
+                sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_SINGLE_MODE, 1);
+                if (sciErr != SC_ERR_NONE)
+                    printk("galcore: failed to set gpu single mode for 3d_%d\n", gpu);
+            }
+        }
+#endif
+        if (clk_core)
+            clk_prepare(clk_core);
+
+        if (clk_shader)
+            clk_prepare(clk_shader);
+
+        if (clk_axi)
+            clk_prepare(clk_axi);
+
+        if (clk_ahb)
+            clk_prepare(clk_ahb);
+    } else {
+        if (clk_core)
+            clk_unprepare(clk_core);
+
+        if (clk_shader)
+            clk_unprepare(clk_shader);
+
+        if (clk_axi)
+            clk_unprepare(clk_axi);
+
+        if (clk_ahb)
+            clk_unprepare(clk_ahb);
+#ifdef CONFIG_PM
+        pm_runtime_put_sync(priv->pmdev[gpu]);
+        if(priv->pm_qos_core == gpu) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+            cpu_latency_qos_remove_request(&priv->pm_qos);
+#else
+            pm_qos_remove_request(&(priv->pm_qos));
+#endif
+        }
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+        if (!IS_ERR(priv->gpu_regulator))
+            regulator_disable(priv->gpu_regulator);
+#  else
+        imx_gpc_power_up_pu(false);
+#  endif
+#endif
+    }
+
+    return 0;
+}
+
+int set_clock(int gpu, int enable)
+{
+    struct imx_priv* priv = &imxPriv;
+    struct clk *clk_core = priv->imx_gpu_clks[gpu].clk_core;
+    struct clk *clk_shader = priv->imx_gpu_clks[gpu].clk_shader;
+    struct clk *clk_axi = priv->imx_gpu_clks[gpu].clk_axi;
+    struct clk *clk_ahb = priv->imx_gpu_clks[gpu].clk_ahb;
+
+    if (enable) {
+        if (clk_core)
+            clk_enable(clk_core);
+
+        if (clk_shader)
+            clk_enable(clk_shader);
+
+        if (clk_axi)
+            clk_enable(clk_axi);
+
+        if (clk_ahb)
+            clk_enable(clk_ahb);
+    } else {
+        if (clk_core)
+            clk_disable(clk_core);
+
+        if (clk_shader)
+            clk_disable(clk_shader);
+
+        if (clk_axi)
+            clk_disable(clk_axi);
+
+        if (clk_ahb)
+            clk_disable(clk_ahb);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_RUNTIME
+static int gpu_runtime_suspend(struct device *dev)
+{
+    release_bus_freq(BUS_FREQ_HIGH);
+    return 0;
+}
+
+static int gpu_runtime_resume(struct device *dev)
+{
+    request_bus_freq(BUS_FREQ_HIGH);
+    return 0;
+}
+#endif
+
+static struct dev_pm_ops gpu_pm_ops;
+#endif
+#endif
+
+
+static int adjust_platform_driver(struct platform_driver *driver)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    driver->driver.of_match_table = mxs_gpu_dt_ids;
+#endif
+
+#ifdef CONFIG_PM
+    /* Override PM callbacks to add runtime PM callbacks. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+    /* Fill local structure with original value. */
+    memcpy(&gpu_pm_ops, driver->driver.pm, sizeof(struct dev_pm_ops));
+
+    /* Add runtime PM callback. */
+#ifdef CONFIG_PM_RUNTIME
+    gpu_pm_ops.runtime_suspend = gpu_runtime_suspend;
+    gpu_pm_ops.runtime_resume = gpu_runtime_resume;
+    gpu_pm_ops.runtime_idle = NULL;
+#endif
+
+    /* Replace callbacks. */
+    driver->driver.pm = &gpu_pm_ops;
+#endif
+#endif
+
+    return 0;
+}
+
+#define SRC_SCR_OFFSET 0
+#define BP_SRC_SCR_GPU3D_RST 1
+#define BP_SRC_SCR_GPU2D_RST 4
+
+static inline int reset_gpu(int gpu)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+    void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
+    uint32_t bit_offset, val;
+
+    if (gpu == gcvCORE_MAJOR)
+        bit_offset = BP_SRC_SCR_GPU3D_RST;
+    else if ((gpu == gcvCORE_VG) ||(gpu == gcvCORE_2D))
+        bit_offset = BP_SRC_SCR_GPU2D_RST;
+    else
+        return -ENXIO;
+
+    val = __raw_readl(src_base + SRC_SCR_OFFSET);
+    val &= ~(1 << (bit_offset));
+    val |= (1 << (bit_offset));
+    __raw_writel(val, src_base + SRC_SCR_OFFSET);
+
+    while ((__raw_readl(src_base + SRC_SCR_OFFSET) & (1 << (bit_offset))) != 0);
+
+    return -ENODEV;
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    struct imx_priv* priv = &imxPriv;
+    struct reset_control *rstc = priv->rstc[gpu];
+
+    if (rstc)
+        reset_control_reset(rstc);
+#else
+    imx_src_reset_gpu((int)gpu);
+#endif
+
+    return 0;
+}
+
+static gceSTATUS
+_AdjustParam(
+    gcsPLATFORM * Platform,
+    gcsMODULE_PARAMETERS *Args
+    )
+{
+    patch_param(Platform->device, Args);
+
+    if ((of_find_compatible_node(NULL, NULL, "fsl,imx8mq-gpu") ||
+    of_find_compatible_node(NULL, NULL, "fsl,imx8mm-gpu") ||
+    of_find_compatible_node(NULL, NULL, "fsl,imx8mn-gpu")) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+        ((Args->baseAddress + totalram_pages() * PAGE_SIZE) > 0x100000000))
+#else
+        ((Args->baseAddress + totalram_pages * PAGE_SIZE) > 0x100000000))
+#endif
+    {
+        Platform->flagBits |= gcvPLATFORM_FLAG_LIMIT_4G_ADDRESS;
+    }
+
+    if (of_find_compatible_node(NULL, NULL, "fsl,imx8mm-gpu"))
+    {
+        Platform->flagBits |= gcvPLATFORM_FLAG_IMX_MM;
+    }
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GetPower(
+    gcsPLATFORM * Platform
+    )
+{
+    int ret = get_power(&Platform->device->dev);
+
+    if (ret)
+        return gcvSTATUS_GENERIC_IO;
+
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_PutPower(
+    gcsPLATFORM * Platform
+    )
+{
+    put_power();
+    return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_SetPower(
+    gcsPLATFORM * Platform,
+    gceCORE GPU,
+    gctBOOL Enable
+    )
+{
+    return set_power((int)GPU, Enable) ? gcvSTATUS_GENERIC_IO
+                : gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_SetClock(
+    gcsPLATFORM * Platform,
+    gceCORE GPU,
+    gctBOOL Enable
+    )
+{
+    set_clock((int)GPU, Enable);
+    return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_Reset(
+    gcsPLATFORM * Platform,
+    gceCORE GPU
+    )
+{
+    int ret;
+
+    ret = reset_gpu((int)GPU);
+
+    if (!ret)
+        return gcvSTATUS_OK;
+    else if (ret == -ENODEV)
+        return gcvSTATUS_NOT_SUPPORTED;
+    else
+        return gcvSTATUS_INVALID_CONFIG;
+}
+
+struct _gcsPLATFORM_OPERATIONS imx_platform_ops =
+{
+    .adjustParam  = _AdjustParam,
+    .getPower     = _GetPower,
+    .putPower     = _PutPower,
+    .setPower     = _SetPower,
+    .setClock     = _SetClock,
+    .reset        = _Reset,
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+    .shrinkMemory = _ShrinkMemory,
+#endif
+};
+
+static struct _gcsPLATFORM imx_platform =
+{
+    .name = __FILE__,
+    .ops  = &imx_platform_ops,
+};
+
+static const struct of_device_id gpu_match[] = {
+    { .compatible = "fsl,ls1028a-gpu"},
+    { /* sentinel */ }
+};
+
+struct _gcsPLATFORM_OPERATIONS ls_platform_ops = {
+    .adjustParam  = _AdjustParam,
+};
+
+static struct _gcsPLATFORM ls_platform = {
+    .name = __FILE__,
+    .ops  = &ls_platform_ops,
+};
+
+int gckPLATFORM_Init(struct platform_driver *pdrv,
+            struct _gcsPLATFORM **platform)
+{
+#ifdef IMX_GPU_SUBSYSTEM
+    if (of_find_compatible_node(NULL, NULL, "fsl,imx8-gpu-ss")) {
+        use_imx_gpu_subsystem = 1;
+
+        if (!of_find_compatible_node(NULL, NULL, "fsl,imx8-gpu")) {
+            printk(KERN_ERR "Incorrect device-tree, please update dtb.");
+            return -EINVAL;
+        }
+    }
+#endif
+
+    if (of_find_compatible_node(NULL, NULL, "fsl,ls1028a-gpu")) {
+        is_layerscape = 1;
+        pdrv->driver.of_match_table = gpu_match;
+        *platform = &ls_platform;
+
+        return 0;
+    }
+
+    adjust_platform_driver(pdrv);
+    init_priv();
+
+#ifdef IMX_GPU_SUBSYSTEM
+    register_mxc_gpu_sub_driver();
+#endif
+
+    *platform = &imx_platform;
+    return 0;
+}
+
+int gckPLATFORM_Terminate(struct _gcsPLATFORM *platform)
+{
+    if (is_layerscape)
+        return 0;
+
+#ifdef IMX_GPU_SUBSYSTEM
+    unregister_mxc_gpu_sub_driver();
+#endif
+    free_priv();
+    return 0;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config
@@ -0,0 +1,29 @@
+EXTRA_CFLAGS += -DgcdDEFAULT_CONTIGUOUS_SIZE=~0U
+EXTRA_CFLAGS += -DgcdFSL_CONTIGUOUS_SIZE=134217728
+
+ifneq ($(CONFIG_ANDROID),)
+# build for android
+EXTRA_CFLAGS += -DgcdANDROID
+endif
+
+EXTRA_CFLAGS += -DgcdANDROID_NATIVE_FENCE_SYNC=2
+
+ifeq ($(CONFIG_SYNC)$(CONFIG_SYNC_FILE),)
+$(warn CONFIG_SYNC or CONFIG_SYNC_FILE is not set in kernel config)
+$(warn Android native fence sync requires CONFIG_SYNC or CONFIG_SYNC_FILE)
+endif
+
+ifneq ($(CONFIG_ARCH_FSL_IMX8QM),)
+EXTRA_CFLAGS += -DIMX8_SCU_CONTROL=1 -DIMX8_PHYS_BASE=0x80000000 -DIMX8_PHYS_SIZE=0x80000000
+endif
+
+EXTRA_CFLAGS += -DLINUX_CMA_FSL=1 -DgcdREGISTER_READ_FROM_USER=1 -DgcdREGISTER_WRITE_FROM_USER=1
+ALLOCATOR_ARRAY_H_LOCATION := $(OS_KERNEL_DIR)/allocator/freescale
+CUSTOMER_ALLOCATOR_OBJS := $(ALLOCATOR_ARRAY_H_LOCATION)/gc_hal_kernel_allocator_cma.o
+
+EXTRA_CFLAGS += -DCLASS_NAME=\"gpu_class\"
+
+EXTRA_CFLAGS += -DgcdGPU_2D_TIMEOUT=20000
+EXTRA_CFLAGS += -DNO_DMA_COHERENT=1
+EXTRA_CFLAGS += -DgcdSYS_FREE_MEMORY_LIMIT=51200
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c
@@ -0,0 +1,348 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal.h"
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/*
+* Responsibility of TA (trust application).
+* 1) Start FE.
+*   When non secure driver asks for start FE. TA enable MMU and start FE.
+*   TA always execute MMU enable processes because it has no idea whether
+*   GPU has been power off.
+*
+* 2) Setup page table
+*   When non secure driver asks for set up GPU address to physical address
+*   mapping, TA check the attribute of physical address and attribute of
+*   GPU address to make sure they are match. Then it change page table.
+*
+*/
+
+gcTA_MMU SharedMmu = gcvNULL;
+
+/*******************************************************************************
+**
+**  gcTA_Construct
+**
+**  Construct a new gcTA object.
+*/
+int
+gcTA_Construct(
+    IN gctaOS Os,
+    IN gceCORE Core,
+    OUT gcTA *TA
+    )
+{
+    gceSTATUS status;
+    gctPOINTER pointer;
+    gcTA ta = gcvNULL;
+
+    gcmkHEADER();
+    gcmkVERIFY_ARGUMENT(TA != gcvNULL);
+
+    /* Construct a gcTA object. */
+    gcmkONERROR(gctaOS_Allocate(sizeof(struct _gcTA), &pointer));
+
+    gctaOS_ZeroMemory(pointer, sizeof(struct _gcTA));
+
+    ta = (gcTA)pointer;
+
+    ta->os = Os;
+    ta->core = Core;
+
+    gcmkONERROR(gctaHARDWARE_Construct(ta, &ta->hardware));
+
+    if (gctaHARDWARE_IsFeatureAvailable(ta->hardware, gcvFEATURE_SECURITY))
+    {
+        if (SharedMmu == gcvNULL)
+        {
+            gcmkONERROR(gctaMMU_Construct(ta, &ta->mmu));
+
+            /* Record shared MMU. */
+            SharedMmu = ta->mmu;
+            ta->destoryMmu = gcvTRUE;
+        }
+        else
+        {
+            ta->mmu = SharedMmu;
+            ta->destoryMmu = gcvFALSE;
+        }
+
+        gcmkONERROR(gctaHARDWARE_PrepareFunctions(ta->hardware));
+    }
+
+    *TA = ta;
+
+    gcmkFOOTER_NO();
+    return 0;
+
+OnError:
+    if (ta)
+    {
+        if (ta->mmu && ta->destoryMmu)
+        {
+            gcmkVERIFY_OK(gctaMMU_Destory(ta->mmu));
+        }
+
+        if (ta->hardware)
+        {
+            gcmkVERIFY_OK(gctaHARDWARE_Destroy(ta->hardware));
+        }
+
+        gcmkVERIFY_OK(gctaOS_Free(ta));
+    }
+    gcmkFOOTER();
+    return status;
+}
+
+/*******************************************************************************
+**
+**  gcTA_Construct
+**
+**  Destroy a gcTA object.
+*/
+int
+gcTA_Destroy(
+    IN gcTA TA
+    )
+{
+    if (TA->mmu && TA->destoryMmu)
+    {
+        gcmkVERIFY_OK(gctaMMU_Destory(TA->mmu));
+    }
+
+    if (TA->hardware)
+    {
+        gcmkVERIFY_OK(gctaHARDWARE_Destroy(TA->hardware));
+    }
+
+    gcmkVERIFY_OK(gctaOS_Free(TA));
+
+    /* Destroy. */
+    return 0;
+}
+
+
+/*
+*   Map a scatter gather list into gpu address space.
+*
+*/
+gceSTATUS
+gcTA_MapMemory(
+    IN gcTA TA,
+    IN gctUINT32 *PhysicalArray,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 PageCount,
+    OUT gctUINT32 *GPUAddress
+    )
+{
+    gceSTATUS status;
+    gcTA_MMU mmu;
+    gctUINT32 pageCount = PageCount;
+    gctUINT32 i;
+    gctUINT32 gpuAddress = *GPUAddress;
+    gctBOOL mtlbSecure = gcvFALSE;
+    gctBOOL physicalSecure = gcvFALSE;
+
+    mmu = TA->mmu;
+
+    /* Fill in page table. */
+    for (i = 0; i < pageCount; i++)
+    {
+        gctUINT32 physical;
+        gctUINT32_PTR entry;
+
+        if (PhysicalArray)
+        {
+            physical = PhysicalArray[i];
+        }
+        else
+        {
+            physical = (gctUINT32)Physical + 4096 * i;
+        }
+
+        gcmkONERROR(gctaMMU_GetPageEntry(mmu, gpuAddress, gcvNULL, &entry, &mtlbSecure));
+
+        status = gctaOS_IsPhysicalSecure(TA->os, physical, &physicalSecure);
+
+        if (gcmIS_SUCCESS(status) && physicalSecure != mtlbSecure)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+        }
+
+        gctaMMU_SetPage(mmu, physical, entry);
+
+        gpuAddress += 4096;
+    }
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gcTA_UnmapMemory(
+    IN gcTA TA,
+    IN gctUINT32 GPUAddress,
+    IN gctUINT32 PageCount
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gctaMMU_FreePages(TA->mmu, GPUAddress, PageCount));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gcTA_StartCommand(
+    IN gcTA TA,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gctaHARDWARE_Execute(TA, Address, Bytes);
+    return gcvSTATUS_OK;
+}
+
+int
+gcTA_Dispatch(
+    IN gcTA TA,
+    IN gcsTA_INTERFACE * Interface
+    )
+{
+    int command = Interface->command;
+
+    gceSTATUS status = gcvSTATUS_OK;
+
+    switch (command)
+    {
+    case KERNEL_START_COMMAND:
+        /* Enable MMU every time FE starts.
+        ** Because if normal world stop GPU and power off GPU, MMU states is reset.
+        */
+        gcmkONERROR(gctaHARDWARE_SetMMU(TA->hardware, TA->mmu->mtlbLogical));
+
+        gcmkONERROR(gcTA_StartCommand(
+            TA,
+            Interface->u.StartCommand.address,
+            Interface->u.StartCommand.bytes
+            ));
+        break;
+
+    case KERNEL_MAP_MEMORY:
+        gcmkONERROR(gcTA_MapMemory(
+            TA,
+            Interface->u.MapMemory.physicals,
+            Interface->u.MapMemory.physical,
+            Interface->u.MapMemory.pageCount,
+            &Interface->u.MapMemory.gpuAddress
+            ));
+
+        break;
+
+    case KERNEL_UNMAP_MEMORY:
+        status = gcTA_UnmapMemory(
+            TA,
+            Interface->u.UnmapMemory.gpuAddress,
+            Interface->u.UnmapMemory.pageCount
+            );
+        break;
+
+    case KERNEL_DUMP_MMU_EXCEPTION:
+        status = gctaHARDWARE_DumpMMUException(TA->hardware);
+        break;
+
+    case KERNEL_HANDLE_MMU_EXCEPTION:
+        status = gctaHARDWARE_HandleMMUException(
+            TA->hardware,
+            Interface->u.HandleMMUException.mmuStatus,
+            Interface->u.HandleMMUException.physical,
+            Interface->u.HandleMMUException.gpuAddress
+            );
+        break;
+
+    case KERNEL_READ_MMU_EXCEPTION:
+        status = gctaHARDWARE_ReadMMUException(
+            TA->hardware,
+            &Interface->u.ReadMMUException.mmuStatus,
+            &Interface->u.ReadMMUException.mmuException
+            );
+        break;
+
+    default:
+        gcmkASSERT(0);
+
+        status = gcvSTATUS_INVALID_ARGUMENT;
+        break;
+    }
+
+OnError:
+    Interface->result = status;
+
+    return 0;
+}
+
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h
@@ -0,0 +1,373 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_TA_H_
+#define _GC_HAL_TA_H_
+#include "gc_hal_types.h"
+#include "gc_hal_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _gctaOS          * gctaOS;
+typedef struct _gcTA            * gcTA;
+
+typedef struct _gcTA_HARDWARE   * gcTA_HARDWARE;
+typedef struct _gcTA_MMU        * gcTA_MMU;
+
+/*
+    Trust Application is a object needed to be created as a context in trust zone.
+    One client for a core.
+*/
+typedef struct _gcTA {
+    /* gctaOS object */
+    gctaOS          os;
+
+    gceCORE         core;
+
+    gcTA_MMU        mmu;
+
+    gcTA_HARDWARE   hardware;
+
+    gctBOOL         destoryMmu;
+} gcsTA;
+
+typedef struct _gcTA_MMU
+{
+    gctaOS          os;
+
+    gctSIZE_T       mtlbBytes;
+    gctPOINTER      mtlbLogical;
+    gctPHYS_ADDR    mtlbPhysical;
+
+    gctPOINTER      stlbs;
+
+    gctPOINTER      safePageLogical;
+    gctPHYS_ADDR    safePagePhysical;
+
+    gctPOINTER      nonSecureSafePageLogical;
+    gctPHYS_ADDR    nonSecureSafePagePhysical;
+
+    gctPOINTER      mutex;
+}
+gcsTA_MMU;
+
+gceSTATUS HALDECL
+TAEmulator(
+    gceCORE Core,
+    void * Interface
+    );
+
+int
+gcTA_Construct(
+    IN gctaOS Os,
+    IN gceCORE Core,
+    OUT gcTA *TA
+);
+
+int
+gcTA_Destroy(
+    IN gcTA TA
+);
+
+int
+gcTA_Dispatch(
+    IN gcTA TA,
+    IN OUT gcsTA_INTERFACE * Interface
+);
+
+/*************************************
+* Porting layer
+*/
+
+gceSTATUS
+gctaOS_ConstructOS(
+    IN gckOS Os,
+    OUT gctaOS *TAos
+    );
+
+gceSTATUS
+gctaOS_DestroyOS(
+    IN gctaOS Os
+    );
+
+gceSTATUS
+gctaOS_Allocate(
+    IN gctUINT32 Bytes,
+    OUT gctPOINTER *Pointer
+    );
+
+gceSTATUS
+gctaOS_Free(
+    IN gctPOINTER Pointer
+    );
+
+gceSTATUS
+gctaOS_AllocateSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T *Bytes,
+    OUT gctPOINTER *Logical,
+    OUT gctPOINTER *Physical
+    );
+
+gceSTATUS
+gctaOS_FreeSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  Bytes,
+    IN gctPOINTER Logical,
+    OUT gctPOINTER Physical
+    );
+
+gceSTATUS
+gctaOS_AllocateNonSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T *Bytes,
+    OUT gctPOINTER *Logical,
+    OUT gctPOINTER *Physical
+    );
+
+gceSTATUS
+gctaOS_FreeNonSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  Bytes,
+    IN gctPOINTER Logical,
+    OUT gctPOINTER Physical
+    );
+
+
+
+gceSTATUS
+gctaOS_GetPhysicalAddress(
+    IN gctaOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Physical
+    );
+
+gceSTATUS gctaOS_WriteRegister(
+    IN gctaOS Os, IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    );
+
+gceSTATUS gctaOS_ReadRegister(
+    IN gctaOS Os, IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 *Data
+    );
+
+gceSTATUS
+gctaOS_MemCopy(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT8_PTR Src,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gctaOS_ZeroMemory(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    );
+
+void
+gctaOS_CacheFlush(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    );
+
+void
+gctaOS_CacheClean(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    );
+
+void
+gctaOS_CacheInvalidate(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gctaOS_IsPhysicalSecure(
+    IN gctaOS Os,
+    IN gctUINT32 Physical,
+    OUT gctBOOL *Secure
+    );
+
+gceSTATUS
+gctaOS_Delay(
+    IN gctaOS Os,
+    IN gctUINT32 Delay
+    );
+
+gceSTATUS
+gctaOS_SetGPUPower(
+    IN gctaOS Os,
+    IN gctUINT32 Core,
+    IN gctBOOL Clock,
+    IN gctBOOL Power
+    );
+
+/*
+** gctaHARDWARE
+*/
+gceSTATUS
+gctaHARDWARE_Construct(
+    IN gcTA TA,
+    OUT gcTA_HARDWARE * Hardware
+    );
+
+gceSTATUS
+gctaHARDWARE_Destroy(
+    IN gcTA_HARDWARE Hardware
+    );
+
+gceSTATUS
+gctaHARDWARE_Execute(
+    IN gcTA TA,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    );
+
+gceSTATUS
+gctaHARDWARE_End(
+    IN gcTA_HARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    );
+
+gceSTATUS
+gctaHARDWARE_SetMMU(
+    IN gcTA_HARDWARE Hardware,
+    IN gctPOINTER Logical
+    );
+
+gceSTATUS
+gctaHARDWARE_IsFeatureAvailable(
+    IN gcTA_HARDWARE Hardware,
+    IN gceFEATURE Feature
+    );
+
+gceSTATUS
+gctaHARDWARE_PrepareFunctions(
+    IN gcTA_HARDWARE Hardware
+    );
+
+gceSTATUS
+gctaHARDWARE_DumpMMUException(
+    IN gcTA_HARDWARE Hardware
+    );
+
+gceSTATUS
+gctaHARDWARE_HandleMMUException(
+    IN gcTA_HARDWARE Hardware,
+    IN gctUINT32 MMUStatus,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 GPUAddress
+    );
+
+gceSTATUS
+gctaHARDWARE_ReadMMUException(
+    IN gcTA_HARDWARE Hardware,
+    OUT gctUINT32_PTR MMUStatus,
+    OUT gctUINT32_PTR MMUException
+    );
+
+gceSTATUS
+gctaMMU_Construct(
+    IN gcTA TA,
+    OUT gcTA_MMU *Mmu
+    );
+
+gceSTATUS
+gctaMMU_Destory(
+    IN gcTA_MMU Mmu
+    );
+
+gceSTATUS
+gctaMMU_SetPage(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 PageAddress,
+    IN gctUINT32 *PageEntry
+    );
+
+gceSTATUS
+gctaMMU_GetPageEntry(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address,
+    OUT gctUINT32_PTR MtlbEntry,
+    OUT gctUINT32_PTR *PageTable,
+    OUT gctBOOL * Secure
+    );
+
+void
+gctaMMU_DumpPagetableEntry(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address
+    );
+
+gceSTATUS
+gctaMMU_FreePages(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address,
+    IN gctUINT32 PageCount
+    );
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c
@@ -0,0 +1,1068 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal_ta_hardware.h"
+#include "gc_hal.h"
+#include "gc_feature_database.h"
+
+
+#define _GC_OBJ_ZONE     1
+#define SRC_MAX          8
+#define RECT_ADDR_OFFSET 3
+
+#define INVALID_ADDRESS  ~0U
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_IdentifyHardwareByDatabase(
+    IN gcTA_HARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gctUINT32 chipIdentity;
+    gcsFEATURE_DATABASE *database;
+    gctaOS os = Hardware->os;
+
+    gcmkHEADER();
+
+    /***************************************************************************
+    ** Get chip ID and revision.
+    */
+
+    /* Read chip identity register. */
+    gcmkONERROR(gctaOS_ReadRegister(os, Hardware->ta->core, 0x00018, &chipIdentity));
+
+    /* Special case for older graphic cores. */
+    if (((((gctUINT32) (chipIdentity)) >> (0 ?
+ 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ?
+ 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+    {
+        Hardware->chipModel    = gcv500;
+        Hardware->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+    }
+
+    else
+    {
+        /* Read chip identity register. */
+        gcmkONERROR(
+            gctaOS_ReadRegister(os, Hardware->ta->core,
+                                 0x00020,
+                                 (gctUINT32_PTR) &Hardware->chipModel));
+
+        if (((Hardware->chipModel & 0xFF00) == 0x0400)
+          && (Hardware->chipModel != 0x0420)
+          && (Hardware->chipModel != 0x0428))
+        {
+            Hardware->chipModel = (gceCHIPMODEL) (Hardware->chipModel & 0x0400);
+        }
+
+        /* Read CHIP_REV register. */
+        gcmkONERROR(
+            gctaOS_ReadRegister(os, Hardware->ta->core,
+                                 0x00024,
+                                 &Hardware->chipRevision));
+
+        if ((Hardware->chipModel    == gcv300)
+        &&  (Hardware->chipRevision == 0x2201)
+        )
+        {
+            gctUINT32 chipDate;
+            gctUINT32 chipTime;
+
+            /* Read date and time registers. */
+            gcmkONERROR(
+                gctaOS_ReadRegister(os, Hardware->ta->core,
+                                     0x00028,
+                                     &chipDate));
+
+            gcmkONERROR(
+                gctaOS_ReadRegister(os, Hardware->ta->core,
+                                     0x0002C,
+                                     &chipTime));
+
+            if ((chipDate == 0x20080814) && (chipTime == 0x12051100))
+            {
+                /* This IP has an ECO; put the correct revision in it. */
+                Hardware->chipRevision = 0x1051;
+            }
+        }
+
+        gcmkONERROR(
+            gctaOS_ReadRegister(os, Hardware->ta->core,
+                                 0x000A8,
+                                 &Hardware->productID));
+    }
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        os, Hardware->ta->core,
+        0x000E8
+,
+        &Hardware->ecoID
+        ));
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        os, Hardware->ta->core,
+        0x00030
+,
+        &Hardware->customerID
+        ));
+
+    /***************************************************************************
+    ** Get chip features.
+    */
+
+    database =
+    Hardware->featureDatabase =
+    gcQueryFeatureDB(
+        Hardware->chipModel,
+        Hardware->chipRevision,
+        Hardware->productID,
+        Hardware->ecoID,
+        Hardware->customerID
+        );
+
+    if (database == gcvNULL)
+    {
+        gcmkPRINT("[galcore]: Feature database is not found,"
+                  "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x, customerID=0x%x",
+                  Hardware->chipModel,
+                  Hardware->chipRevision,
+                  Hardware->productID,
+                  Hardware->ecoID,
+                  Hardware->customerID);
+        gcmkONERROR(gcvSTATUS_NOT_FOUND);
+    }
+    /* Success. */
+    gcmkFOOTER();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+gctaHARDWARE_SetMMUStates(
+    IN gcTA_HARDWARE Hardware,
+    IN gctPOINTER MtlbAddress,
+    IN gceMMU_MODE Mode,
+    IN gctPOINTER SafeAddress,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gceSTATUS status;
+    gctUINT32 config;
+    gctUINT32 extMtlb;
+    gctPHYS_ADDR_T physical;
+    gctUINT32_PTR buffer;
+    gctUINT32 reserveBytes = 2 * 4;
+    gcsMMU_TABLE_ARRAY_ENTRY * entry;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    entry = (gcsMMU_TABLE_ARRAY_ENTRY *) Hardware->pagetableArray.logical;
+
+    /* Convert logical address into physical address. */
+    gcmkONERROR(
+        gctaOS_GetPhysicalAddress(Hardware->os, MtlbAddress, &physical));
+
+    config  = (gctUINT32)(physical & 0xFFFFFFFF);
+    extMtlb = (gctUINT32)(physical >> 32);
+    /* more than 40bit physical address */
+    if (extMtlb & 0xFFFFFF00)
+    {
+        gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    switch (Mode)
+    {
+    case gcvMMU_MODE_1K:
+        if (config & 0x3FF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    case gcvMMU_MODE_4K:
+        if (config & 0xFFF)
+        {
+            gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+        }
+
+        config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+        break;
+
+    default:
+        gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+    }
+
+    if (Logical != gcvNULL)
+    {
+        buffer = Logical;
+
+        /* Setup page table array entry. */
+        entry->low = config;
+        entry->high = extMtlb;
+
+        /* Setup command buffer to load index 0 of page table array. */
+        *buffer++
+            = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)))
+            | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ?
+ 25:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16)));
+
+        *buffer++
+            = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))));
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        *Bytes = reserveBytes;
+    }
+
+    /* Return the status. */
+    gcmkFOOTER_NO();
+    return status;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gctaHARDWARE_End(
+    IN gcTA_HARDWARE Hardware,
+    IN gctPOINTER Logical,
+    IN OUT gctUINT32 * Bytes
+    )
+{
+    gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+    gceSTATUS status;
+
+    gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+        Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+    if (Logical != gcvNULL)
+    {
+        if (*Bytes < 8)
+        {
+            /* Command queue too small. */
+            gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+        }
+
+        /* Append END. */
+        logical[0] =
+            ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ?
+ 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+        /* Record the count of execution which is finised by this END. */
+        logical[1] =
+            0;
+
+        gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical);
+    }
+
+    if (Bytes != gcvNULL)
+    {
+        /* Return number of bytes required by the END command. */
+        *Bytes = 8;
+    }
+
+    /* Success. */
+    gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+
+gceSTATUS
+gctaHARDWARE_Construct(
+    IN gcTA TA,
+    OUT gcTA_HARDWARE * Hardware
+    )
+{
+    gceSTATUS status;
+    gcTA_HARDWARE hardware = gcvNULL;
+
+    gctaOS os = TA->os;
+
+    gcmkONERROR(gctaOS_Allocate(
+        gcmSIZEOF(gcsTA_HARDWARE),
+        (gctPOINTER *)&hardware
+        ));
+
+    gctaOS_ZeroMemory((gctUINT8_PTR)hardware, gcmSIZEOF(gcsTA_HARDWARE));
+
+    hardware->ta = TA;
+    hardware->os = os;
+
+    hardware->pagetableArray.size = 4096;
+
+    hardware->functionBytes = 4096;
+
+    /* Power on GPU. */
+    gctaOS_SetGPUPower(os, TA->core, gcvTRUE, gcvTRUE);
+
+    /*************************************/
+    /********  Get chip information ******/
+    /*************************************/
+    gctaOS_WriteRegister(
+        hardware->ta->os, hardware->ta->core,
+        0x00000,
+        0x00010900
+        );
+
+    gcmkONERROR(_IdentifyHardwareByDatabase(hardware));
+
+    *Hardware = hardware;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (hardware)
+    {
+        gctaOS_Free(hardware);
+    }
+
+    return status;
+}
+
+gceSTATUS
+gctaHARDWARE_Destroy(
+    IN gcTA_HARDWARE Hardware
+    )
+{
+    if (Hardware->pagetableArray.logical)
+    {
+        gctaOS_FreeSecurityMemory(
+            Hardware->ta->os,
+            Hardware->pagetableArray.size,
+            Hardware->pagetableArray.logical,
+            (gctUINT32_PTR)Hardware->pagetableArray.physical
+            );
+    }
+
+    if (Hardware->functionLogical)
+    {
+        gctaOS_FreeSecurityMemory(
+            Hardware->ta->os,
+            Hardware->functionBytes,
+            Hardware->functionLogical,
+            (gctUINT32_PTR)Hardware->functionPhysical
+            );
+    }
+
+    gctaOS_Free(Hardware);
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_Execute(
+    IN gcTA TA,
+    IN gctUINT32 Address,
+    IN gctUINT32 Bytes
+    )
+{
+    gceSTATUS status;
+    gctUINT32 address = Address, control;
+
+    gcmkHEADER_ARG("Address=0x%x Bytes=%lu",
+        Address, Bytes);
+
+    /* Enable all events. */
+    gcmkONERROR(
+        gctaOS_WriteRegister(TA->os, TA->core, 0x00014, ~0U));
+
+    /* Write address register. */
+    gcmkONERROR(
+        gctaOS_WriteRegister(TA->os, TA->core, 0x00654, address));
+
+    /* Build control register. */
+    control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ?
+ 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16)))
+        | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ?
+ 15:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0)));
+
+    /* Write control register. */
+    gcmkONERROR(
+        gctaOS_WriteRegister(TA->os, TA->core, 0x003A4, control));
+
+    gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+        "Started command buffer @ 0x%08x",
+        address);
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    /* Return the status. */
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gctaHARDWARE_MmuEnable(
+    IN gcTA_HARDWARE Hardware
+    )
+{
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x0018C,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1 ) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))));
+
+    return gcvSTATUS_OK;
+}
+
+/*
+* In trust zone, we prepare page table array table and configure base address of
+* it to hardware.
+*/
+gceSTATUS
+gctaHARDWARE_SetMMU(
+    IN gcTA_HARDWARE Hardware,
+    IN gctPOINTER Logical
+    )
+{
+    gcsMMU_TABLE_ARRAY_ENTRY *entry;
+    gcsHARDWARE_FUNCTION *function = &Hardware->functions[0];
+    gctUINT32 delay = 1;
+    gctUINT32 timer = 0;
+    gctUINT32 idle;
+    gctPHYS_ADDR_T mtlbPhysical;
+    gctPHYS_ADDR_T secureSafeAddress;
+    gctPHYS_ADDR_T nonSecureSafeAddress;
+
+    gctaOS_GetPhysicalAddress(Hardware->ta->os, Logical, &mtlbPhysical);
+
+    gctaOS_GetPhysicalAddress(Hardware->ta->os, Hardware->ta->mmu->safePageLogical, &secureSafeAddress);
+
+    gctaOS_GetPhysicalAddress(Hardware->ta->os, Hardware->ta->mmu->nonSecureSafePageLogical, &nonSecureSafeAddress);
+
+    /* not support more than 40bit physical address */
+    if ((secureSafeAddress & 0xFFFFFF0000000000ULL) ||
+        (nonSecureSafeAddress & 0xFFFFFF0000000000ULL))
+    {
+        return (gcvSTATUS_NOT_SUPPORTED);
+    }
+
+    /* Fill entry 0 of page table array. */
+    entry = (gcsMMU_TABLE_ARRAY_ENTRY *)Hardware->pagetableArray.logical;
+
+    entry->low  = (gctUINT32)(mtlbPhysical & 0xFFFFFFFF);
+
+    entry->high = (gctUINT32)(mtlbPhysical >> 32)
+                | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 8:8) - (0 ?
+ 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8)))
+                ;
+
+    /* Set page table base. */
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x0038C,
+        (gctUINT32)(Hardware->pagetableArray.address & 0xFFFFFFFF)
+        );
+
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x00390,
+        (gctUINT32)((Hardware->pagetableArray.address >> 32) & 0xFFFFFFFF)
+        );
+
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x00394
+,
+        1
+        );
+
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x0039C,
+        (gctUINT32)(secureSafeAddress & 0xFFFFFFFF)
+        );
+
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x00398,
+        (gctUINT32)(nonSecureSafeAddress & 0xFFFFFFFF)
+        );
+
+    gctaOS_WriteRegister(
+        Hardware->ta->os, Hardware->ta->core,
+        0x003A0,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)((secureSafeAddress >> 32) & 0xFFFFFFFF)) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ?
+ 23:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ? 23:16)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ?
+ 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ?
+ 31:31) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)((secureSafeAddress >> 32) & 0xFFFFFFFF)) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ?
+ 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+      | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1))))))) << (0 ?
+ 15:15))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 15:15) - (0 ?
+ 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15)))
+        );
+
+    /* Execute prepared command sequence. */
+    gctaHARDWARE_Execute(
+        Hardware->ta,
+        function->address,
+        function->bytes
+        );
+
+    /* Wait until MMU configure finishes. */
+    do
+    {
+        gctaOS_Delay(Hardware->os, delay);
+
+        gctaOS_ReadRegister(
+            Hardware->ta->os, Hardware->ta->core,
+            0x00004,
+            &idle);
+
+        timer += delay;
+        delay *= 2;
+    }
+    while (!(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ));
+
+    /* Enable MMU. */
+    gctaOS_WriteRegister(
+        Hardware->os, Hardware->ta->core,
+        0x00388,
+        ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ?
+ 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+        );
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_PrepareFunctions(
+    IN gcTA_HARDWARE Hardware
+    )
+{
+    gceSTATUS status;
+    gcsHARDWARE_FUNCTION * function;
+    gctUINT32 mmuBytes;
+    gctUINT32 endBytes = 8;
+    gctUINT8_PTR logical;
+    gctPHYS_ADDR_T physical;
+
+    gcmkHEADER();
+
+    /* Allocate page table array. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        Hardware->ta->os,
+        &Hardware->pagetableArray.size,
+        &Hardware->pagetableArray.logical,
+        &Hardware->pagetableArray.physical
+        ));
+
+    gcmkONERROR(gctaOS_GetPhysicalAddress(
+        Hardware->ta->os,
+        Hardware->pagetableArray.logical,
+        &Hardware->pagetableArray.address
+        ));
+
+    /* Allocate GPU functions. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        Hardware->ta->os,
+        &Hardware->functionBytes,
+        &Hardware->functionLogical,
+        &Hardware->functionPhysical
+        ));
+
+    gcmkONERROR(gctaOS_GetPhysicalAddress(
+        Hardware->ta->os,
+        Hardware->functionLogical,
+        &physical
+        ));
+
+    gcmkSAFECASTPHYSADDRT(Hardware->functionAddress, physical);
+
+    function = &Hardware->functions[0];
+
+    function->logical = Hardware->functionLogical;
+
+    function->address = Hardware->functionAddress;
+
+    logical = function->logical;
+
+    gcmkONERROR(gctaHARDWARE_SetMMUStates(
+        Hardware,
+        Hardware->ta->mmu->mtlbLogical,
+        gcvMMU_MODE_4K,
+        Hardware->ta->mmu->safePageLogical,
+        logical,
+        &mmuBytes
+        ));
+
+    logical += 8;
+
+    gcmkONERROR(gctaHARDWARE_End(
+        Hardware,
+        logical,
+        &endBytes
+        ));
+
+    function->bytes = mmuBytes + endBytes;
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gctaHARDWARE_IsFeatureAvailable(
+    IN gcTA_HARDWARE Hardware,
+    IN gceFEATURE Feature
+    )
+{
+    gctBOOL available;
+    gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+
+    switch (Feature)
+    {
+    case gcvFEATURE_SECURITY:
+        available = database->SECURITY;
+        break;
+    default:
+        gcmkFATAL("Invalid feature has been requested.");
+        available = gcvFALSE;
+    }
+
+    return available;
+}
+
+gceSTATUS
+gctaHARDWARE_DumpMMUException(
+    IN gcTA_HARDWARE Hardware
+    )
+{
+    gctUINT32 mmu       = 0;
+    gctUINT32 mmuStatus = 0;
+    gctUINT32 address   = 0;
+    gctUINT32 i         = 0;
+
+    gctUINT32 mmuStatusRegAddress;
+    gctUINT32 mmuExceptionAddress;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    mmuStatusRegAddress = 0x00384;
+    mmuExceptionAddress = 0x00380;
+
+    /* Verify the arguments. */
+    gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+    gcmkPRINT("ChipModel=0x%x ChipRevision=0x%x:\n",
+              Hardware->chipModel,
+              Hardware->chipRevision);
+
+    gcmkPRINT("**************************\n");
+    gcmkPRINT("***   MMU ERROR DUMP   ***\n");
+    gcmkPRINT("**************************\n");
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        Hardware->os, Hardware->ta->core,
+        mmuStatusRegAddress
+,
+        &mmuStatus
+        ));
+
+    gcmkPRINT("  MMU status = 0x%08X\n", mmuStatus);
+
+    for (i = 0; i < 4; i += 1)
+    {
+        mmu = mmuStatus & 0xF;
+        mmuStatus >>= 4;
+
+        if (mmu == 0)
+        {
+            continue;
+        }
+
+        switch (mmu)
+        {
+        case 1:
+              gcmkPRINT("  MMU%d: slave not present\n", i);
+              break;
+
+        case 2:
+              gcmkPRINT("  MMU%d: page not present\n", i);
+              break;
+
+        case 3:
+              gcmkPRINT("  MMU%d: write violation\n", i);
+              break;
+
+        case 4:
+              gcmkPRINT("  MMU%d: out of bound", i);
+              break;
+
+        case 5:
+              gcmkPRINT("  MMU%d: read security violation", i);
+              break;
+
+        case 6:
+              gcmkPRINT("  MMU%d: write security violation", i);
+              break;
+
+        default:
+              gcmkPRINT("  MMU%d: unknown state\n", i);
+        }
+
+        gcmkVERIFY_OK(gctaOS_ReadRegister(
+            Hardware->os, Hardware->ta->core,
+            mmuExceptionAddress + i * 4
+,
+            &address
+            ));
+
+        gcmkPRINT("  MMU%d: exception address = 0x%08X\n", i, address);
+
+        gctaMMU_DumpPagetableEntry(Hardware->ta->mmu, address);
+    }
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_ReadMMUException(
+    IN gcTA_HARDWARE Hardware,
+    OUT gctUINT32_PTR MMUStatus,
+    OUT gctUINT32_PTR MMUException
+    )
+{
+    gctUINT32 mmuStatusRegAddress;
+    gctUINT32 mmuExceptionAddress;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    mmuStatusRegAddress = 0x00384;
+    mmuExceptionAddress = 0x00380;
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        Hardware->os, Hardware->ta->core,
+        mmuStatusRegAddress
+,
+        MMUStatus
+        ));
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        Hardware->os, Hardware->ta->core,
+        mmuExceptionAddress
+,
+        MMUException
+        ));
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_HandleMMUException(
+    IN gcTA_HARDWARE Hardware,
+    IN gctUINT32 MMUStatus,
+    IN gctPHYS_ADDR_T Physical,
+    IN gctUINT32 GPUAddress
+    )
+{
+    gctUINT32 mmu       = 0;
+    gctUINT32 mmuStatus = 0;
+    gctUINT32 mtlbEntry = 0;
+    gctUINT32_PTR stlbEntry;
+    gctBOOL secure;
+
+    gctUINT32 mmuStatusRegAddress;
+    gctUINT32 mmuExceptionAddress;
+
+    gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+    mmuStatusRegAddress = 0x00384;
+    mmuExceptionAddress = 0x00380;
+
+    gcmkVERIFY_OK(gctaOS_ReadRegister(
+        Hardware->os, Hardware->ta->core,
+        mmuStatusRegAddress
+,
+        &mmuStatus
+        ));
+
+    mmu = mmuStatus & 0xF;
+
+    /* Setup page table. */
+
+    gctaMMU_GetPageEntry(
+        Hardware->ta->mmu,
+        GPUAddress,
+        &mtlbEntry,
+        &stlbEntry,
+        &secure
+        );
+
+    gctaMMU_SetPage(
+        Hardware->ta->mmu,
+        (gctUINT32)Physical,
+        stlbEntry
+        );
+
+    switch (mmu)
+    {
+    case 1:
+        gcmkASSERT(mtlbEntry != 0);
+        gctaOS_WriteRegister(
+            Hardware->os, Hardware->ta->core,
+            mmuExceptionAddress
+,
+            mtlbEntry
+            );
+
+        break;
+
+    case 2:
+         gctaOS_WriteRegister(
+            Hardware->os, Hardware->ta->core,
+            mmuExceptionAddress
+,
+            *stlbEntry
+            );
+        break;
+
+    default:
+        gcmkASSERT(0);
+    }
+
+
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_TA_HARDWARE_H_
+#define _GC_HAL_TA_HARDWARE_H_
+#include "gc_hal_types.h"
+#include "gc_hal_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _gcsMMU_TABLE_ARRAY_ENTRY
+{
+    gctUINT32                   low;
+    gctUINT32                   high;
+}
+gcsMMU_TABLE_ARRAY_ENTRY;
+
+typedef struct _gcsHARDWARE_PAGETABLE_ARRAY
+{
+    /* Number of entries in page table array. */
+    gctUINT                     num;
+
+    /* Size in bytes of array. */
+    gctSIZE_T                   size;
+
+    /* Physical address of array. */
+    gctPHYS_ADDR_T              address;
+
+    /* Memory descriptor. */
+    gctPOINTER                  physical;
+
+    /* Logical address of array. */
+    gctPOINTER                  logical;
+}
+gcsHARDWARE_PAGETABLE_ARRAY;
+
+typedef struct _gcsHARWARE_FUNCTION
+{
+    /* Entry of the function. */
+    gctUINT32                   address;
+
+    /* CPU address of the function. */
+    gctUINT8_PTR                logical;
+
+    /* Bytes of the function. */
+    gctUINT32                   bytes;
+
+    /* Hardware address of END in this function. */
+    gctUINT32                   endAddress;
+
+    /* Logical of END in this function. */
+    gctUINT8_PTR                endLogical;
+}
+gcsHARDWARE_FUNCTION;
+
+typedef struct _gcTA_HARDWARE
+{
+    gctaOS                      os;
+    gcTA                        ta;
+
+    gctUINT32                   chipModel;
+    gctUINT32                   chipRevision;
+    gctUINT32                   productID;
+    gctUINT32                   ecoID;
+    gctUINT32                   customerID;
+
+    gctPOINTER                  featureDatabase;
+
+    gcsHARDWARE_PAGETABLE_ARRAY pagetableArray;
+
+    /* Function used by gctaHARDWARE. */
+    gctPHYS_ADDR                functionPhysical;
+    gctPOINTER                  functionLogical;
+    gctUINT32                   functionAddress;
+    gctSIZE_T                   functionBytes;
+
+    gcsHARDWARE_FUNCTION        functions[1];
+}
+gcsTA_HARDWARE;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
@@ -0,0 +1,585 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal.h"
+
+#define _GC_OBJ_ZONE 2
+/*******************************************************************************
+************************************ Define ************************************
+********************************************************************************/
+
+#define gcdMMU_MTLB_SHIFT           22
+#define gcdMMU_STLB_4K_SHIFT        12
+#define gcdMMU_STLB_64K_SHIFT       16
+
+#define gcdMMU_MTLB_BITS            (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS         gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS         (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS        gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS        (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+
+#define gcdMMU_MTLB_ENTRY_NUM       (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE            (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM    (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE         (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE         (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM   (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE        (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE        (1 << gcdMMU_STLB_64K_SHIFT)
+
+#define gcdMMU_MTLB_MASK            (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK         ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK         (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK        ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK        (gcdMMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS       (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK       ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_64K_BITS      (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_64K_BITS)
+#define gcdMMU_OFFSET_64K_MASK      ((1U << gcdMMU_OFFSET_64K_BITS) - 1)
+
+#define gcdMMU_MTLB_PRESENT         0x00000001
+#define gcdMMU_MTLB_EXCEPTION       0x00000002
+#define gcdMMU_MTLB_4K_PAGE         (0 << 2)
+
+#define gcdMMU_STLB_PRESENT         0x00000001
+#define gcdMMU_STLB_EXCEPTION       0x00000002
+#define gcdMMU_STLB_SECURITY        (1 << 4)
+
+#define gcdUSE_MMU_EXCEPTION        1
+
+#define gcdMMU_SECURE_AREA_START    ((gcdMMU_MTLB_ENTRY_NUM - gcdMMU_SECURE_AREA_SIZE) << gcdMMU_MTLB_SHIFT)
+
+typedef enum _gceMMU_TYPE
+{
+    gcvMMU_USED     = (0 << 4),
+    gcvMMU_SINGLE   = (1 << 4),
+    gcvMMU_FREE     = (2 << 4),
+}
+gceMMU_TYPE;
+
+typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR;
+typedef struct _gcsMMU_STLB
+{
+    gctPHYS_ADDR    physical;
+    gctUINT32_PTR   logical;
+    gctSIZE_T       size;
+    gctPHYS_ADDR_T  physBase;
+    gctSIZE_T       pageCount;
+    gctUINT32       mtlbIndex;
+    gctUINT32       mtlbEntryNum;
+    gcsMMU_STLB_PTR next;
+} gcsMMU_STLB;
+
+
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+/*
+* We need flat mapping ta command buffer.
+
+*/
+
+/*
+* Helper
+*/
+gctUINT32
+_MtlbOffset(
+    gctUINT32 Address
+    )
+{
+    return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+}
+
+gctUINT32
+_StlbOffset(
+    gctUINT32 Address
+    )
+{
+    return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+}
+
+static gctUINT32
+_SetPage(gctUINT32 PageAddress)
+{
+    return PageAddress
+           /* writable */
+           | (1 << 2)
+           /* Ignore exception */
+           | (0 << 1)
+           /* Present */
+           | (1 << 0);
+}
+
+static void
+_WritePageEntry(
+    IN gctUINT32_PTR PageEntry,
+    IN gctUINT32     EntryValue
+    )
+{
+    *PageEntry = EntryValue;
+
+    gctaOS_CacheClean((gctUINT8_PTR)PageEntry, gcmSIZEOF(gctUINT32));
+}
+
+static gceSTATUS
+_FillPageTable(
+    IN gctUINT32_PTR PageTable,
+    IN gctUINT32     PageCount,
+    IN gctUINT32     EntryValue
+)
+{
+    gctUINT i;
+
+    for (i = 0; i < PageCount; i++)
+    {
+        _WritePageEntry(PageTable + i, EntryValue);
+    }
+
+    return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_AllocateStlb(
+    IN gctaOS Os,
+    OUT gcsMMU_STLB_PTR *Stlb
+    )
+{
+    gceSTATUS status;
+    gcsMMU_STLB_PTR stlb;
+    gctPOINTER pointer = gcvNULL;
+
+    /* Allocate slave TLB record. */
+    gcmkONERROR(gctaOS_Allocate(gcmSIZEOF(gcsMMU_STLB), &pointer));
+    stlb = pointer;
+
+    stlb->size = gcdMMU_STLB_4K_SIZE;
+
+    /* Allocate slave TLB entries. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        Os,
+        &stlb->size,
+        (gctPOINTER *)&stlb->logical,
+        &stlb->physical
+        ));
+
+    gcmkONERROR(gctaOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase));
+
+#if gcdUSE_MMU_EXCEPTION
+    _FillPageTable(stlb->logical, (gctUINT32)stlb->size / 4, gcdMMU_STLB_EXCEPTION);
+#else
+    gctaOS_ZeroMemory(stlb->logical, (gctUINT32)stlb->size);
+#endif
+
+    *Stlb = stlb;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if(pointer != gcvNULL)
+        gcmkVERIFY_OK(gctaOS_Free(pointer));
+    return status;
+}
+
+gceSTATUS
+gctaMMU_Construct(
+    IN gcTA TA,
+    OUT gcTA_MMU *Mmu
+    )
+{
+    gceSTATUS status;
+    gctSIZE_T bytes = 4096;
+
+    gcTA_MMU mmu = gcvNULL;
+
+    gcmkONERROR(gctaOS_Allocate(
+        gcmSIZEOF(gcsTA_MMU),
+        (gctPOINTER *)&mmu
+        ));
+
+    mmu->mtlbLogical              = gcvNULL;
+    mmu->stlbs                    = gcvNULL;
+    mmu->safePageLogical          = gcvNULL;
+    mmu->nonSecureSafePageLogical = gcvNULL;
+
+    mmu->os = TA->os;
+
+    /* MTLB bytes. */
+    mmu->mtlbBytes = gcdMMU_MTLB_SIZE;
+
+    /* Allocate MTLB. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        TA->os,
+        &mmu->mtlbBytes,
+        &mmu->mtlbLogical,
+        &mmu->mtlbPhysical
+        ));
+
+#if gcdUSE_MMU_EXCEPTION
+    _FillPageTable(mmu->mtlbLogical, (gctUINT32)mmu->mtlbBytes / 4, gcdMMU_STLB_EXCEPTION);
+#else
+    gctaOS_ZeroMemory(mmu->mtlbLogical, (gctUINT32)mmu->mtlbBytes);
+#endif
+
+    /* Allocate a array to store stlbs. */
+    gcmkONERROR(gctaOS_Allocate((gctUINT32)mmu->mtlbBytes, &mmu->stlbs));
+
+    gctaOS_ZeroMemory((gctUINT8_PTR)mmu->stlbs, (gctUINT32)mmu->mtlbBytes);
+
+    /* Allocate security safe page. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        TA->os,
+        &bytes,
+        &mmu->safePageLogical,
+        &mmu->safePagePhysical
+        ));
+
+    gctaOS_ZeroMemory((gctUINT8_PTR)mmu->safePageLogical, (gctUINT32)bytes);
+
+    /* Allocate non security safe page. */
+    gcmkONERROR(gctaOS_AllocateSecurityMemory(
+        TA->os,
+        &bytes,
+        &mmu->nonSecureSafePageLogical,
+        &mmu->nonSecureSafePagePhysical
+        ));
+
+    gctaOS_ZeroMemory((gctUINT8_PTR)mmu->nonSecureSafePageLogical, (gctUINT32)bytes);
+
+    /* gcmkONERROR(gctaOS_CreateMutex(TA->os, &mmu->mutex)); */
+
+    *Mmu = mmu;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (mmu)
+    {
+        if (mmu->safePageLogical)
+        {
+            gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+                TA->os,
+                4096,
+                mmu->safePageLogical,
+                mmu->safePagePhysical
+                ));
+        }
+
+        if (mmu->nonSecureSafePageLogical)
+        {
+            gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+                TA->os,
+                4096,
+                mmu->nonSecureSafePageLogical,
+                mmu->nonSecureSafePagePhysical
+                ));
+        }
+
+        if (mmu->mtlbLogical)
+        {
+            gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+                TA->os,
+                4096,
+                mmu->mtlbLogical,
+                mmu->mtlbPhysical
+                ));
+        }
+
+        if (mmu->stlbs)
+        {
+            gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu->stlbs));
+        }
+
+        gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu));
+    }
+    return status;
+}
+
+gceSTATUS
+gctaMMU_Destory(
+    IN gcTA_MMU Mmu
+    )
+{
+    gctaOS os = Mmu->os;
+
+    if (Mmu->safePageLogical)
+    {
+        gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+            os,
+            4096,
+            Mmu->safePageLogical,
+            Mmu->safePagePhysical
+            ));
+    }
+
+    if (Mmu->nonSecureSafePageLogical)
+    {
+        gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+            os,
+            4096,
+            Mmu->nonSecureSafePageLogical,
+            Mmu->nonSecureSafePagePhysical
+            ));
+    }
+
+    if (Mmu->mtlbLogical)
+    {
+        gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+            os,
+            4096,
+            Mmu->mtlbLogical,
+            Mmu->mtlbPhysical
+            ));
+    }
+
+    if (Mmu->stlbs)
+    {
+        gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)Mmu->stlbs));
+    }
+
+    gcmkVERIFY_OK(gctaOS_Free(Mmu));
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_GetPageEntry(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address,
+    OUT gctUINT32_PTR MtlbEntry,
+    OUT gctUINT32_PTR *PageTable,
+    OUT gctBOOL * Secure
+    )
+{
+    gceSTATUS status;
+    struct _gcsMMU_STLB *stlb;
+    struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+    gctUINT32 offset = _MtlbOffset(Address);
+    gctUINT32 mtlbEntry;
+    gctBOOL secure = Address > gcdMMU_SECURE_AREA_START;
+
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0);
+
+    stlb = stlbs[offset];
+
+    if (stlb == gcvNULL)
+    {
+        gcmkONERROR(_AllocateStlb(Mmu->os, &stlb));
+
+        mtlbEntry = (gctUINT32)(stlb->physBase & 0xFFFFFFFF)
+                  | gcdMMU_MTLB_4K_PAGE
+                  | gcdMMU_MTLB_PRESENT
+                  ;
+
+        if (secure)
+        {
+            /* Secure MTLB. */
+            mtlbEntry |= (1 << 4);
+        }
+
+        /* Insert Slave TLB address to Master TLB entry.*/
+        _WritePageEntry((gctUINT32_PTR)Mmu->mtlbLogical + offset, mtlbEntry);
+
+        /* Record stlb. */
+        stlbs[offset] = stlb;
+
+        if (MtlbEntry)
+        {
+            /* Return entry value of new mtlb entry. */
+            *MtlbEntry = mtlbEntry;
+        }
+    }
+
+    *PageTable = &stlb->logical[_StlbOffset(Address)];
+
+    if (Secure)
+    {
+        *Secure = secure;
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gctaMMU_SetPage(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 PageAddress,
+    IN gctUINT32 *PageEntry
+    )
+{
+    /* gctBOOL secure; */
+
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Verify the arguments. */
+    gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+    gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+    _WritePageEntry(PageEntry, _SetPage(PageAddress));
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_FreePages(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address,
+    IN gctUINT32 PageCount
+    )
+{
+    gceSTATUS status;
+    gctUINT32 i;
+    gctUINT32_PTR entry;
+    gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+    /* Fill in page table. */
+    for (i = 0; i < PageCount; i++)
+    {
+        gcmkONERROR(gctaMMU_GetPageEntry(Mmu, Address, gcvNULL, &entry, gcvNULL));
+
+#if gcdUSE_MMU_EXCEPTION
+        *entry = gcdMMU_STLB_EXCEPTION;
+#else
+        *entry = 0;
+#endif
+
+        Address += 4096;
+    }
+
+    /* Success. */
+    gcmkFOOTER_NO();
+    return gcvSTATUS_OK;
+
+OnError:
+    gcmkFOOTER();
+    return status;
+}
+
+gceSTATUS
+gctaMMU_Enable(
+    IN gcTA_MMU Mmu,
+    IN gcTA TA
+    )
+{
+    gceSTATUS status;
+    gctPHYS_ADDR_T address;
+    gctPHYS_ADDR_T safeAddress;
+
+    gcmkONERROR(gctaOS_GetPhysicalAddress(Mmu->os, Mmu->mtlbLogical, &address));
+
+    gctaOS_GetPhysicalAddress(Mmu->os, Mmu->safePageLogical, &safeAddress);
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+void
+gctaMMU_DumpPagetableEntry(
+    IN gcTA_MMU Mmu,
+    IN gctUINT32 Address
+    )
+{
+    gctUINT32 entry;
+    gctUINT32 mtlb = _MtlbOffset(Address);
+    gctUINT32_PTR mtlbLogical = Mmu->mtlbLogical;
+    gctUINT32_PTR stlbLogical;
+    gcsMMU_STLB_PTR stlb;
+    struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+
+    gctUINT32 stlbOffset   = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+    gctUINT32 offsetInPage = Address & gcdMMU_OFFSET_4K_MASK;
+
+    stlb = stlbs[mtlb];
+
+    gcmkPRINT("    MTLB entry = %d\n", mtlb);
+
+    gcmkPRINT("    STLB entry = %d\n", stlbOffset);
+
+    gcmkPRINT("    Offset = 0x%08X (%d)\n", offsetInPage, offsetInPage);
+
+
+    if (stlb == gcvNULL)
+    {
+        /* Dmp mtlb entry. */
+        entry = mtlbLogical[mtlb];
+
+        gcmkPRINT("   mtlb entry [%d] = %x", mtlb, entry);
+    }
+    else
+    {
+        stlbLogical = stlb->logical;
+
+        gcmkPRINT("    stlb entry = 0x%08X", stlbLogical[stlbOffset]);
+    }
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c
+++ linux-ein-5.4.0/drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c
@@ -0,0 +1,324 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2020 Vivante 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
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2020 Vivante 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.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_base.h"
+#include "gc_hal.h"
+#include "gc_hal_ta.h"
+#include "gc_hal_kernel_mutex.h"
+
+#define _GC_OBJ_ZONE    gcvZONE_OS
+
+gcTA globalTA[16] = { gcvNULL, gcvNULL, gcvNULL, gcvNULL,gcvNULL, gcvNULL, gcvNULL, gcvNULL };
+gctaOS globalTAos;
+
+struct _gctaOS {
+    void *os;
+
+    gctPOINTER dispatchMutex;
+};
+
+gceSTATUS HALDECL
+TAEmulator(
+    gceCORE Core,
+    void * Interface
+    )
+{
+    gckOS_AcquireMutex(globalTAos->os, globalTAos->dispatchMutex, gcvINFINITE);
+
+    gcTA_Dispatch(globalTA[Core], Interface);
+
+    gckOS_ReleaseMutex(globalTAos->os, globalTAos->dispatchMutex);
+    return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gctaOS_ConstructOS(
+    IN gckOS Os,
+    OUT gctaOS *TAos
+    )
+{
+    gctaOS os;
+    gctPOINTER pointer = gcvNULL;
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_AllocateMemory(Os, gcmSIZEOF(struct _gctaOS), &pointer));
+
+    os = (gctaOS)pointer;
+    os->os = Os;
+
+    gcmkONERROR(gckOS_CreateMutex(Os, &os->dispatchMutex));
+
+    *TAos = globalTAos = os;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    if (pointer != gcvNULL)
+    {
+        gcmkVERIFY_OK(gckOS_FreeMemory(Os, pointer));
+    }
+    return status;
+}
+
+gceSTATUS
+gctaOS_DestroyOS(
+    IN gctaOS Os
+    )
+{
+    gckOS os = Os->os;
+
+    gcmkVERIFY_OK(gckOS_DeleteMutex(os, Os->dispatchMutex));
+    gcmkVERIFY_OK(gckOS_FreeMemory(os, Os));
+
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_AllocateSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  *Bytes,
+    OUT gctPOINTER *Logical,
+    OUT gctPOINTER *Physical
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_AllocateNonPagedMemory(Os->os, gcvFALSE, gcvALLOC_FLAG_CONTIGUOUS, Bytes, (gctPHYS_ADDR *)Physical, Logical));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gctaOS_FreeSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  Bytes,
+    IN gctPOINTER Logical,
+    OUT gctPOINTER Physical
+    )
+{
+    gckOS_FreeNonPagedMemory(Os->os, (gctPHYS_ADDR)Physical, Logical, Bytes);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_AllocateNonSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  *Bytes,
+    OUT gctPOINTER *Logical,
+    OUT gctPOINTER *Physical
+    )
+{
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_AllocateNonPagedMemory(Os->os, gcvFALSE, gcvALLOC_FLAG_CONTIGUOUS, Bytes, (gctPHYS_ADDR *)Physical, Logical));
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS
+gctaOS_FreeNonSecurityMemory(
+    IN gctaOS Os,
+    IN gctSIZE_T  Bytes,
+    IN gctPOINTER Logical,
+    OUT gctPOINTER Physical
+    )
+{
+    gckOS_FreeNonPagedMemory(Os->os, (gctPHYS_ADDR)Physical, Logical, Bytes);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_Allocate(
+    IN gctUINT32 Bytes,
+    OUT gctPOINTER *Pointer
+    )
+{
+    return gckOS_AllocateMemory(globalTAos->os, Bytes, Pointer);
+}
+
+gceSTATUS
+gctaOS_Free(
+    IN gctPOINTER Pointer
+    )
+{
+    return gckOS_FreeMemory(globalTAos->os, Pointer);
+}
+
+gceSTATUS
+gctaOS_GetPhysicalAddress(
+    IN gctaOS Os,
+    IN gctPOINTER Logical,
+    OUT gctPHYS_ADDR_T * Physical
+    )
+{
+    gctPHYS_ADDR_T physical;
+    gceSTATUS status;
+
+    gcmkONERROR(gckOS_GetPhysicalAddress(Os->os, Logical, &physical));
+
+    gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os->os, physical, &physical));
+
+    *Physical = physical;
+
+    return gcvSTATUS_OK;
+
+OnError:
+    return status;
+}
+
+gceSTATUS gctaOS_WriteRegister(
+    IN gctaOS Os, IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 Data
+    )
+{
+    return gckOS_WriteRegisterEx(Os->os, Core, Address, Data);
+}
+
+gceSTATUS gctaOS_ReadRegister(
+    IN gctaOS Os, IN gceCORE Core,
+    IN gctUINT32 Address,
+    IN gctUINT32 *Data
+    )
+{
+    return gckOS_ReadRegisterEx(Os->os, Core, Address, Data);
+}
+
+gceSTATUS
+gctaOS_MemCopy(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT8_PTR Src,
+    IN gctUINT32 Bytes
+    )
+{
+    gckOS_MemCopy(Dest, Src, Bytes);
+    return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_ZeroMemory(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    )
+{
+    gckOS_ZeroMemory(Dest, Bytes);
+    return gcvSTATUS_OK;
+}
+
+void
+gctaOS_CacheFlush(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    )
+{
+
+}
+
+void
+gctaOS_CacheClean(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    )
+{
+
+}
+
+void
+gctaOS_CacheInvalidate(
+    IN gctUINT8_PTR Dest,
+    IN gctUINT32 Bytes
+    )
+{
+
+}
+
+gceSTATUS
+gctaOS_IsPhysicalSecure(
+    IN gctaOS Os,
+    IN gctUINT32 Physical,
+    OUT gctBOOL *Secure
+    )
+{
+    return gcvSTATUS_NOT_SUPPORTED;
+}
+
+gceSTATUS
+gctaOS_Delay(
+    IN gctaOS Os,
+    IN gctUINT32 Delay
+    )
+{
+    return gckOS_Delay(Os->os, Delay);
+}
+
+gceSTATUS
+gctaOS_SetGPUPower(
+    IN gctaOS Os,
+    IN gctUINT32 Core,
+    IN gctBOOL Clock,
+    IN gctBOOL Power
+    )
+{
+    return gckOS_SetGPUPower(Os->os, Core, Power, Clock);
+}
+
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/hantro/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) support"
+	depends on ARCH_MXC
+
+config MXC_HANTRO
+	tristate "Support for MXC HANTRO(Video Processing Unit)"
+	default y
+	---help---
+	  VPU codec device.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/hantro/Makefile
+++ linux-ein-5.4.0/drivers/mxc/hantro/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+ccflags-y += -I$(PWD)/./dwl
+
+obj-$(CONFIG_MXC_HANTRO) += hantrodec.o
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro/dwl_defs.h
+++ linux-ein-5.4.0/drivers/mxc/hantro/dwl_defs.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ *    The GPL License (GPL)
+ *
+ *    Copyright (c) 2015-2017, VeriSilicon Inc.
+ *    Copyright (c) 2011-2014, Google Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version 2
+ *    of the License, or (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You may obtain a copy of the GNU General Public License
+ *    Version 2 or later at the following locations:
+ *    http://www.opensource.org/licenses/gpl-license.html
+ *    http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E 31 /* 1 bit */
+#define DWL_VC1_E 29   /* 2 bits */
+#define DWL_JPEG_E 28  /* 1 bit */
+#define DWL_MPEG4_E 26 /* 2 bits */
+#define DWL_H264_E 24  /* 2 bits */
+#define DWL_VP6_E 23   /* 1 bit */
+#define DWL_RV_E 26    /* 2 bits */
+#define DWL_VP8_E 23   /* 1 bit */
+#define DWL_VP7_E 24   /* 1 bit */
+#define DWL_WEBP_E 19  /* 1 bit */
+#define DWL_AVS_E 22   /* 1 bit */
+#if 0
+#define DWL_PP_E       16  /* 1 bit */
+#endif
+#define DWL_PP_E 31    /* 1 bit */
+#define DWL_HEVC_E 5   /* 2 bits */
+#define DWL_VP9_E 3    /* 2 bits */
+
+#define DWL_HEVC_ENA 0  /* 1 bits */
+#define DWL_VP9_ENA 1   /* 1 bits */
+#define DWL_RFC_E 2     /* 1 bits */
+#define DWL_DS_E 3      /* 1 bits */
+#define DWL_HEVC_VER 8  /* 4 bits */
+#define DWL_VP9_PROFILE 12 /* 3 bits */
+#define DWL_RING_E 16   /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC 1
+#define HANTRODEC_IRQ_STAT_DEC_OFF (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG 60
+#define HANTRODECPP_SYNTH_CFG_OFF (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3 56
+#define HANTRODEC_SYNTH_CFG_3_OFF (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT 23
+#define HANTRODEC_CFG_STAT_OFF (HANTRODEC_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E 0x01
+#define HANTRODEC_PP_E 0x01
+#define HANTRODEC_DEC_ABORT 0x20
+#define HANTRODEC_DEC_IRQ_DISABLE 0x10
+#define HANTRODEC_DEC_IRQ 0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC          1
+#define HANTRO_IRQ_STAT_DEC_OFF      (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP           60
+#define HANTRO_IRQ_STAT_PP_OFF       (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG           100
+#define HANTROPP_SYNTH_CFG_OFF       (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG          50
+#define HANTRODEC_SYNTH_CFG_OFF      (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2        54
+#define HANTRODEC_SYNTH_CFG_2_OFF    (HANTRODEC_SYNTH_CFG_2 * 4)
+
+#define HANTRO_DEC_E                 0x01
+#define HANTRO_PP_E                  0x01
+#define HANTRO_DEC_ABORT             0x20
+#define HANTRO_DEC_IRQ_DISABLE       0x10
+#define HANTRO_PP_IRQ_DISABLE        0x10
+#define HANTRO_DEC_IRQ               0x100
+#define HANTRO_PP_IRQ                0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */
--- linux-ein-5.4.0.orig/drivers/mxc/hantro/hantrodec.c
+++ linux-ein-5.4.0/drivers/mxc/hantro/hantrodec.c
@@ -0,0 +1,1949 @@
+/*****************************************************************************
+ *    The GPL License (GPL)
+ *
+ *    Copyright (c) 2015-2018, VeriSilicon Inc.
+ *    Copyright (c) 2011-2014, Google Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version 2
+ *    of the License, or (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You may obtain a copy of the GNU General Public License
+ *    Version 2 or later at the following locations:
+ *    http://www.opensource.org/licenses/gpl-license.html
+ *    http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+
+#include <linux/hantrodec.h>
+#include "dwl_defs.h"
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+//#include <linux/busfreq-imx.h>
+
+#ifdef CONFIG_DEVICE_THERMAL
+#include <linux/device_cooling.h>
+#define HANTRO_REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a)
+#define HANTRO_UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a)
+DEFINE_SPINLOCK(thermal_lock);
+/*1:hot, 0: not hot*/
+static int thermal_event;
+static int thermal_cur;
+static int hantro_clock_ratio = 2;
+static int hantro_dynamic_clock;
+module_param(hantro_clock_ratio, int, 0644);
+module_param(hantro_dynamic_clock, int, 0644);
+MODULE_PARM_DESC(hantro_clock_ratio, "clock ratio 1/N");
+MODULE_PARM_DESC(hantro_dynamic_clock, "enable or disable dynamic clock rate");
+#endif
+
+/*hantro G1 regs config including dec and pp*/
+#define HANTRO_DEC_ORG_REGS             60
+#define HANTRO_PP_ORG_REGS              41
+
+#define HANTRO_DEC_EXT_REGS             27
+#define HANTRO_PP_EXT_REGS              9
+
+#define HANTRO_G1_DEC_TOTAL_REGS        (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS            (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_TOTAL_REGS             155 /*G1 total regs*/
+
+#define HANTRO_DEC_ORG_FIRST_REG        0
+#define HANTRO_DEC_ORG_LAST_REG         59
+#define HANTRO_DEC_EXT_FIRST_REG        119
+#define HANTRO_DEC_EXT_LAST_REG         145
+
+#define HANTRO_PP_ORG_FIRST_REG         60
+#define HANTRO_PP_ORG_LAST_REG          100
+#define HANTRO_PP_EXT_FIRST_REG         146
+#define HANTRO_PP_EXT_LAST_REG          154
+
+/*hantro G2 reg config*/
+#define HANTRO_G2_DEC_REGS                 265 /*G2 total regs*/
+
+#define HANTRO_G2_DEC_FIRST_REG            0
+#define HANTRO_G2_DEC_LAST_REG             (HANTRO_G2_DEC_REGS - 1)
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX             (MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_TOTAL_REGS) * 4)
+
+/********************************************************************
+ *                                              PORTING SEGMENT
+ * NOTES: customer should modify these configuration if do porting to own platform.
+ * Please guarantee the base_addr, io_size,dec_irq belong to same core.
+ ********************************************************************/
+
+#define HXDEC_MAX_CORES                 2
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE              0x38300000
+#define SOCLE_LOGIC_1_BASE              0x38310000
+#define BLK_CTL_BASE                          0x38320000
+
+#define VEXPRESS_LOGIC_0_BASE           0xFC010000
+#define VEXPRESS_LOGIC_1_BASE           0xFC020000
+
+#define DEC_IO_SIZE_0             ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#define DEC_IO_SIZE_1             ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+
+#define HANTRO_G1_DEF_CLK		(600000000)
+#define HANTRO_G2_DEF_CLK		(600000000)
+#define HANTRO_BUS_DEF_CLK	(800000000)
+#define HANTRO_CLK_VOL_THR	(600000000)
+/***********************************************************************/
+
+#define IS_G1(hw_id)    ((hw_id == 0x6731) ? 1:0)
+
+static const int DecHwId[] = {
+	0x8190, /* Legacy HW */
+	0x8170,
+	0x9170,
+	0x9190,
+	0x6731, /* G1 */
+	0x6732 /* G2 */
+};
+
+ulong multicorebase[HXDEC_MAX_CORES] = {
+	SOCLE_LOGIC_0_BASE,
+	SOCLE_LOGIC_1_BASE
+};
+
+
+static struct class *hantro_class;
+#define DEVICE_NAME		"mxc_hantro"
+
+static struct device *hantro_dev;
+static struct clk *hantro_clk_g1;
+static struct clk *hantro_clk_g2;
+static struct clk *hantro_clk_bus;
+//static struct regulator *hantro_regulator;
+
+static int hantro_dbg = -1;
+module_param(hantro_dbg, int, 0644);
+MODULE_PARM_DESC(hantro_dbg, "Debug level (0-1)");
+#undef PDEBUG
+#define PDEBUG(fmt, arg...)     \
+	do {                                      \
+		if (hantro_dbg > 0) { \
+			dev_info(hantro_dev, fmt, ## arg); \
+		} \
+	} while (0)
+
+
+static int hantrodec_major; /* dynamic allocation */
+
+/* here's all the must remember stuff */
+typedef struct {
+	char *buffer;
+	unsigned int iosize[HXDEC_MAX_CORES];
+	volatile u8 *hwregs[HXDEC_MAX_CORES];
+	int irq[HXDEC_MAX_CORES];
+	int hw_id[HXDEC_MAX_CORES];
+	int cores;
+	struct fasync_struct *async_queue_dec;
+	struct fasync_struct *async_queue_pp;
+} hantrodec_t;
+
+static hantrodec_t hantrodec_data; /* dynamic allocation? */
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+
+static void ResetAsic(hantrodec_t *dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+
+static u32 dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+struct semaphore dec_core_sem;
+struct semaphore pp_core_sem;
+
+static int dec_irq;
+static int pp_irq;
+
+atomic_t irq_rx = ATOMIC_INIT(0);
+atomic_t irq_tx = ATOMIC_INIT(0);
+
+static struct file *dec_owner[HXDEC_MAX_CORES];
+static struct file *pp_owner[HXDEC_MAX_CORES];
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+DEFINE_SPINLOCK(owner_lock);
+
+DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+
+DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+#define DWL_CLIENT_TYPE_H264_DEC         1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC        2U
+#define DWL_CLIENT_TYPE_JPEG_DEC         3U
+#define DWL_CLIENT_TYPE_PP               4U
+#define DWL_CLIENT_TYPE_VC1_DEC          5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC        6U
+#define DWL_CLIENT_TYPE_VP6_DEC          7U
+#define DWL_CLIENT_TYPE_AVS_DEC          8U
+#define DWL_CLIENT_TYPE_RV_DEC           9U
+#define DWL_CLIENT_TYPE_VP8_DEC          10U
+#define DWL_CLIENT_TYPE_VP9_DEC          11U
+#define DWL_CLIENT_TYPE_HEVC_DEC         12U
+
+static u32 cfg[HXDEC_MAX_CORES];
+static u32 timeout;
+
+#if 0
+static int hantro_update_voltage(struct device *dev)
+{
+	unsigned long new_vol, old_vol;
+	int ret;
+	unsigned long clk1, clk2;
+
+	clk1 = clk_get_rate(hantro_clk_g1);
+	clk2 = clk_get_rate(hantro_clk_g2);
+
+	if (!clk1 || !clk2)
+		return -1;
+
+	old_vol = regulator_get_voltage(hantro_regulator);
+	if ((clk1 >= HANTRO_CLK_VOL_THR) || (clk2 >= HANTRO_CLK_VOL_THR))
+		new_vol = 1000000; // 1.0v
+	else
+		new_vol = 900000; // 0.9v
+
+	if (old_vol != new_vol)	{
+		ret = regulator_set_voltage_tol(hantro_regulator, new_vol, 0);
+		if (ret)
+			pr_err("failed to set hantro voltage: %ld mV\n", new_vol/1000);
+		else
+			pr_info("update hantro voltage from %ld mV to %ld mV\n", old_vol/1000, new_vol/1000);
+	}
+	return 0;
+}
+#endif
+
+static int hantro_clk_enable(struct device *dev)
+{
+	clk_prepare(hantro_clk_g1);
+	clk_enable(hantro_clk_g1);
+	clk_prepare(hantro_clk_g2);
+	clk_enable(hantro_clk_g2);
+	clk_prepare(hantro_clk_bus);
+	clk_enable(hantro_clk_bus);
+	return 0;
+}
+
+static int hantro_clk_disable(struct device *dev)
+{
+	if (hantro_clk_g1) {
+		clk_disable(hantro_clk_g1);
+		clk_unprepare(hantro_clk_g1);
+	}
+	if (hantro_clk_g2) {
+		clk_disable(hantro_clk_g2);
+		clk_unprepare(hantro_clk_g2);
+	}
+	if (hantro_clk_bus) {
+		clk_disable(hantro_clk_bus);
+		clk_unprepare(hantro_clk_bus);
+	}
+	return 0;
+}
+
+static int hantro_ctrlblk_reset(struct device *dev)
+{
+	volatile u8 *iobase;
+
+	//config G1/G2
+	hantro_clk_enable(dev);
+	iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+	iowrite32(0x3, iobase);  //VPUMIX G1/G2 block soft reset  control
+	iowrite32(0x3, iobase+4); //VPUMIX G1/G2 block clock enable control
+	iowrite32(0xFFFFFFFF, iobase + 0x8); // all G1 fuse dec enable
+	iowrite32(0xFFFFFFFF, iobase + 0xC); // all G1 fuse pp enable
+	iowrite32(0xFFFFFFFF, iobase + 0x10); // all G2 fuse dec enable
+	iounmap(iobase);
+	hantro_clk_disable(dev);
+	return 0;
+}
+
+#ifdef CONFIG_DEVICE_THERMAL
+static int hantro_thermal_check(struct device *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&thermal_lock, flags);
+	if (thermal_event == thermal_cur) {
+		/*nothing to do and return directly*/
+		spin_unlock_irqrestore(&thermal_lock, flags);
+		return 0;
+	}
+	thermal_cur = thermal_event;
+	spin_unlock_irqrestore(&thermal_lock, flags);
+
+	if (thermal_cur) {
+		int ratio = hantro_clock_ratio;
+
+		pr_debug("hantro: too hot, need to decrease clock, ratio: 1/%d\n", ratio);
+		/*clock disable/enable are not required for vpu clock rate operation*/
+		clk_set_rate(hantro_clk_g1, HANTRO_G1_DEF_CLK/ratio);
+		clk_set_rate(hantro_clk_g2, HANTRO_G2_DEF_CLK/ratio);
+		clk_set_rate(hantro_clk_bus, HANTRO_BUS_DEF_CLK/ratio);
+	} else {
+		pr_debug("hantro: not hot again, will restore default clock\n");
+		clk_set_rate(hantro_clk_g1, HANTRO_G1_DEF_CLK);
+		clk_set_rate(hantro_clk_g2, HANTRO_G2_DEF_CLK);
+		clk_set_rate(hantro_clk_bus, HANTRO_BUS_DEF_CLK);
+	}
+	pr_info("hantro: event(%d), g1, g2, bus clock: %ld, %ld, %ld\n", thermal_cur,
+		clk_get_rate(hantro_clk_g1),	clk_get_rate(hantro_clk_g2), clk_get_rate(hantro_clk_bus));
+	//hantro_update_voltage(dev);
+	return 0;
+}
+
+static int hantro_thermal_hot_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&thermal_lock, flags);
+	thermal_event = event;		/*event: 1: hot, 0: cool*/
+	spin_unlock_irqrestore(&thermal_lock, flags);
+	pr_info("hantro receive hot notification event: %ld\n", event);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block hantro_thermal_hot_notifier = {
+	.notifier_call = hantro_thermal_hot_notify,
+};
+#endif  //CONFIG_DEVICE_THERMAL
+
+static void ReadCoreConfig(hantrodec_t *dev)
+{
+	int c;
+	u32 reg, tmp, mask;
+
+	memset(cfg, 0, sizeof(cfg));
+
+	for (c = 0; c < dev->cores; c++) {
+		/* Decoder configuration */
+		if (IS_G1(dev->hw_id[c])) {
+			reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG * 4);
+
+			tmp = (reg >> DWL_H264_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has H264\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+			tmp = (reg >> DWL_JPEG_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has JPEG\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+			tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has MPEG4\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+			tmp = (reg >> DWL_VC1_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VC1\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC : 0;
+
+			tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has MPEG2\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+			tmp = (reg >> DWL_VP6_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VP6\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+			reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+			/* VP7 and WEBP is part of VP8 */
+			mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+			tmp = (reg & mask);
+			if (tmp & (1 << DWL_VP8_E))
+				pr_debug("hantrodec: Core[%d] has VP8\n", c);
+			if (tmp & (1 << DWL_VP7_E))
+				pr_debug("hantrodec: Core[%d] has VP7\n", c);
+			if (tmp & (1 << DWL_WEBP_E))
+				pr_debug("hantrodec: Core[%d] has WebP\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+			tmp = (reg >> DWL_AVS_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has AVS\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC : 0;
+
+			tmp = (reg >> DWL_RV_E) & 0x03U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has RV\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+			/* Post-processor configuration */
+			//reg = ioread32(dev->hwregs[c] + HANTROPP_SYNTH_CFG * 4);
+		} else {
+			reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+			tmp = (reg >> DWL_HEVC_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has HEVC\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+			tmp = (reg >> DWL_VP9_E) & 0x03U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VP9\n", c);
+			cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+		}
+
+		/* Post-processor configuration */
+		reg = ioread32(dev->hwregs[c] + HANTRODECPP_SYNTH_CFG * 4);
+
+		tmp = (reg >> DWL_PP_E) & 0x01U;
+		if (tmp)
+			pr_debug("hantrodec: Core[%d] has PP\n", c);
+		cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+	}
+}
+
+static int CoreHasFormat(const u32 *cfg, int Core, u32 format)
+{
+	return (cfg[Core] & (1 << format)) ? 1 : 0;
+}
+
+int GetDecCore(long Core, hantrodec_t *dev, struct file *filp)
+{
+	int success = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (dec_owner[Core] == NULL) {
+		dec_owner[Core] = filp;
+		success = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return success;
+}
+
+int GetDecCoreAny(long *Core, hantrodec_t *dev, struct file *filp,
+			unsigned long format)
+{
+	int success = 0;
+	long c;
+
+	*Core = -1;
+
+	for (c = 0; c < dev->cores; c++) {
+		/* a free Core that has format */
+		if (CoreHasFormat(cfg, c, format) && GetDecCore(c, dev, filp)) {
+			success = 1;
+			*Core = c;
+			break;
+		}
+	}
+
+	return success;
+}
+int GetDecCoreID(hantrodec_t *dev, struct file *filp,
+			unsigned long format)
+{
+	long c;
+
+	int core_id = -1;
+
+	for (c = 0; c < dev->cores; c++) {
+		/* a Core that has format */
+		if (CoreHasFormat(cfg, c, format)) {
+			core_id = c;
+			break;
+		}
+	}
+	PDEBUG("GetDecCoreID=%d\n", core_id);
+	return core_id;
+}
+
+static int hantrodec_choose_core(int is_g1)
+{
+	volatile unsigned char *reg = NULL;
+	unsigned int blk_base = BLK_CTL_BASE;
+
+	PDEBUG("hantrodec_choose_core\n");
+	if (!request_mem_region(blk_base, 0x1000, "blk_ctl"))	{
+		pr_err("blk_ctl: failed to reserve HW regs\n");
+		return -EBUSY;
+	}
+
+	reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+	if (reg == NULL) {
+		pr_err("blk_ctl: failed to ioremap HW regs\n");
+		release_mem_region(blk_base, 0x1000);
+		return -EBUSY;
+	}
+
+	// G1 use, set to 1; G2 use, set to 0, choose the one you are using
+	if (is_g1)
+		iowrite32(0x1, reg + 0x14);  // VPUMIX only use G1
+	else
+		iowrite32(0x0, reg + 0x14); // VPUMIX only use G2
+
+	if (reg)
+		iounmap((void *)reg);
+	release_mem_region(blk_base, 0x1000);
+	PDEBUG("hantrodec_choose_core OK!\n");
+	return 0;
+}
+
+
+long ReserveDecoder(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+	long Core = -1;
+
+	/* reserve a Core */
+	if (down_interruptible(&dec_core_sem))
+		return -ERESTARTSYS;
+
+	/* lock a Core that has specific format*/
+	if (wait_event_interruptible(hw_queue, GetDecCoreAny(&Core, dev, filp, format) != 0))
+		return -ERESTARTSYS;
+
+	if (IS_G1(dev->hw_id[Core])) {
+		if (0 == hantrodec_choose_core(1))
+			PDEBUG("G1 is reserved\n");
+		else
+			return -1;
+	} else {
+		if (0 == hantrodec_choose_core(0))
+			PDEBUG("G2 is reserved\n");
+		else
+			return -1;
+	}
+
+#ifdef CONFIG_DEVICE_THERMAL
+	if (hantro_dynamic_clock)
+		hantro_thermal_check(hantro_dev);
+#endif
+
+	return Core;
+}
+
+void ReleaseDecoder(hantrodec_t *dev, long Core)
+{
+	u32 status;
+	unsigned long flags;
+
+	status = ioread32(dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+	/* make sure HW is disabled */
+	if (status & HANTRODEC_DEC_E) {
+		pr_info("hantrodec: DEC[%li] still enabled -> reset\n", Core);
+
+		/* abort decoder */
+		status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+		iowrite32(status, dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	dec_owner[Core] = NULL;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	up(&dec_core_sem);
+
+	wake_up_interruptible_all(&hw_queue);
+
+}
+
+long ReservePostProcessor(hantrodec_t *dev, struct file *filp)
+{
+	unsigned long flags;
+
+	long Core = 0;
+
+	/* single Core PP only */
+	if (down_interruptible(&pp_core_sem))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	pp_owner[Core] = filp;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return Core;
+}
+
+void ReleasePostProcessor(hantrodec_t *dev, long Core)
+{
+	unsigned long flags;
+
+	u32 status = ioread32(dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+
+	/* make sure HW is disabled */
+	if (status & HANTRO_PP_E) {
+		pr_info("hantrodec: PP[%li] still enabled -> reset\n", Core);
+
+		/* disable IRQ */
+		status |= HANTRO_PP_IRQ_DISABLE;
+
+		/* disable postprocessor */
+		status &= (~HANTRO_PP_E);
+		iowrite32(0x10, dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	pp_owner[Core] = NULL;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	up(&pp_core_sem);
+}
+
+long ReserveDecPp(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+	/* reserve Core 0, DEC+PP for pipeline */
+	unsigned long flags;
+
+	long Core = 0;
+
+	/* check that Core has the requested dec format */
+	if (!CoreHasFormat(cfg, Core, format))
+		return -EFAULT;
+
+	/* check that Core has PP */
+	if (!CoreHasFormat(cfg, Core, DWL_CLIENT_TYPE_PP))
+		return -EFAULT;
+
+	/* reserve a Core */
+	if (down_interruptible(&dec_core_sem))
+		return -ERESTARTSYS;
+
+	/* wait until the Core is available */
+	if (wait_event_interruptible(hw_queue,	GetDecCore(Core, dev, filp) != 0)) {
+		up(&dec_core_sem);
+		return -ERESTARTSYS;
+	}
+
+	if (down_interruptible(&pp_core_sem)) {
+		ReleaseDecoder(dev, Core);
+		return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+	pp_owner[Core] = filp;
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return Core;
+}
+
+long DecFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret = 0, i;
+
+	u32 id = Core->id;
+
+	if (IS_G1(dev->hw_id[id])) {
+		/* copy original dec regs to kernal space*/
+		ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_DEC_ORG_REGS*4);
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+#ifdef USE_64BIT_ENV
+		/* copy extended dec regs to kernal space*/
+		ret = copy_from_user(dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+				Core->regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+
+		/* write dec regs but the status reg[1] to hardware */
+		/* both original and extended regs need to be written */
+		for (i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+	} else {
+		ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_G2_DEC_REGS*4);
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+
+		/* write all regs but the status reg[1] to hardware */
+		for (i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+	}
+
+	/* write the status register, which may start the decoder */
+	iowrite32(dec_regs[id][1], dev->hwregs[id] + 4);
+
+	PDEBUG("flushed registers on Core %d\n", id);
+
+	return 0;
+}
+
+long DecRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret, i;
+	u32 id = Core->id;
+
+	if (IS_G1(dev->hw_id[id])) {
+		/* user has to know exactly what they are asking for */
+		//if(Core->size != (HANTRO_DEC_ORG_REGS * 4))
+		//  return -EFAULT;
+
+		/* read all registers from hardware */
+		/* both original and extended regs need to be read */
+		for (i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+
+		if (timeout) {
+			/* Enable TIMEOUT bits in Reg[1] */
+			dec_regs[id][1] = 0x40100;
+			/* Reset HW */
+			ResetAsic(dev);
+			timeout = 0;
+		}
+
+		/* put registers to user space*/
+		/* put original registers to user space*/
+		ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+		/*put extended registers to user space*/
+		ret = copy_to_user(Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+				dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+		if (ret) {
+			pr_err("copy_to_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+	} else {
+	/* user has to know exactly what they are asking for */
+		if (Core->size != (HANTRO_G2_DEC_REGS * 4))
+			return -EFAULT;
+
+		/* read all registers from hardware */
+		for (i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+
+		if (timeout) {
+			/* Enable TIMEOUT bits in Reg[1] */
+			dec_regs[id][1] = 0x40100;
+			/* Reset HW */
+			ResetAsic(dev);
+			timeout = 0;
+		}
+
+		/* put registers to user space*/
+		ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_G2_DEC_REGS*4);
+		if (ret) {
+			pr_err("copy_to_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev, int id)
+{
+	unsigned long flags;
+	int rdy = 0;
+
+	const u32 irq_mask = (1 << id);
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	if (dec_irq & irq_mask) {
+		/* reset the wait condition(s) */
+		dec_irq &= ~irq_mask;
+		rdy = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return rdy;
+}
+
+long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	u32 id = Core->id;
+	long ret;
+
+	PDEBUG("wait_event_interruptible DEC[%d]\n", id);
+
+	//ret = wait_event_interruptible_timeout(dec_wait_queue, CheckDecIrq(dev, id), msecs_to_jiffies(200));
+	ret = wait_event_timeout(dec_wait_queue, CheckDecIrq(dev, id), msecs_to_jiffies(200));
+	if (ret == -ERESTARTSYS) {
+		pr_err("DEC[%d]  failed to wait_event interrupted\n", id);
+		return -ERESTARTSYS;
+	} else if (ret == 0) {
+		pr_err("DEC[%d]  wait_event timeout\n", id);
+		timeout = 1;
+	}
+
+	atomic_inc(&irq_tx);
+
+	/* refresh registers */
+	return DecRefreshRegs(dev, Core);
+}
+
+long PPFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret = 0;
+	u32 id = Core->id;
+	u32 i;
+
+	/* copy original dec regs to kernal space*/
+	ret = copy_from_user(dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+			Core->regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+	/* copy extended dec regs to kernal space*/
+	ret = copy_from_user(dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+			Core->regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS*4);
+#endif
+	if (ret) {
+		pr_err("copy_from_user failed, returned %li\n", ret);
+		return -EFAULT;
+	}
+
+	/* write all regs but the status reg[1] to hardware */
+	/* both original and extended regs need to be written */
+	for (i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+		iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+	for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+		iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+	/* write the stat reg, which may start the PP */
+	iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+	dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4);
+
+	return 0;
+}
+
+long PPRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long i, ret;
+	u32 id = Core->id;
+#ifdef USE_64BIT_ENV
+	/* user has to know exactly what they are asking for */
+	if (Core->size != (HANTRO_PP_TOTAL_REGS * 4))
+		return -EFAULT;
+#else
+	/* user has to know exactly what they are asking for */
+	if (Core->size != (HANTRO_PP_ORG_REGS * 4))
+		return -EFAULT;
+#endif
+
+	/* read all registers from hardware */
+	/* both original and extended regs need to be read */
+	for (i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+		dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+	for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+		dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+	/* put registers to user space*/
+	/* put original registers to user space*/
+	ret = copy_to_user(Core->regs + HANTRO_PP_ORG_FIRST_REG,
+			dec_regs[id] + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+	/* put extended registers to user space*/
+	ret = copy_to_user(Core->regs + HANTRO_PP_EXT_FIRST_REG,
+			dec_regs[id] + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS * 4);
+#endif
+	if (ret) {
+		pr_err("copy_to_user failed, returned %li\n", ret);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev, int id)
+{
+	unsigned long flags;
+	int rdy = 0;
+
+	const u32 irq_mask = (1 << id);
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	if (pp_irq & irq_mask) {
+		/* reset the wait condition(s) */
+		pp_irq &= ~irq_mask;
+		rdy = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return rdy;
+}
+
+long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	u32 id = Core->id;
+
+	PDEBUG("wait_event_interruptible PP[%d]\n", id);
+
+	if (wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev, id))) {
+		pr_err("PP[%d]  failed to wait_event_interruptible interrupted\n", id);
+		return -ERESTARTSYS;
+	}
+
+	atomic_inc(&irq_tx);
+
+	/* refresh registers */
+	return PPRefreshRegs(dev, Core);
+}
+
+static int CheckCoreIrq(hantrodec_t *dev, const struct file *filp, int *id)
+{
+	unsigned long flags;
+	int rdy = 0, n = 0;
+
+	do {
+		u32 irq_mask = (1 << n);
+
+		spin_lock_irqsave(&owner_lock, flags);
+
+		if (dec_irq & irq_mask) {
+			if (dec_owner[n] == filp) {
+				/* we have an IRQ for our client */
+
+				/* reset the wait condition(s) */
+				dec_irq &= ~irq_mask;
+
+				/* signal ready Core no. for our client */
+				*id = n;
+
+				rdy = 1;
+
+				spin_unlock_irqrestore(&owner_lock, flags);
+				break;
+			} else if (dec_owner[n] == NULL) {
+				/* zombie IRQ */
+				pr_info("IRQ on Core[%d], but no owner!!!\n", n);
+
+				/* reset the wait condition(s) */
+				dec_irq &= ~irq_mask;
+			}
+		}
+
+		spin_unlock_irqrestore(&owner_lock, flags);
+
+		n++; /* next Core */
+	} while (n < dev->cores);
+
+	return rdy;
+}
+
+long WaitCoreReady(hantrodec_t *dev, const struct file *filp, int *id)
+{
+	PDEBUG("wait_event_interruptible CORE\n");
+
+	if (wait_event_interruptible(dec_wait_queue, CheckCoreIrq(dev, filp, id))) {
+		pr_err("CORE  failed to wait_event_interruptible interrupted\n");
+		return -ERESTARTSYS;
+	}
+
+	atomic_inc(&irq_tx);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *Function name   : hantrodec_ioctl
+ *Description     : communication method to/from the user space
+ *
+ *Return type     : long
+ *-------------------------------------------------------------------------
+ */
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	long tmp;
+
+	PDEBUG("ioctl cmd 0x%08x\n", cmd);
+	/*
+	 * extract the type and number bitfields, and don't decode
+	 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+	 */
+	if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC)
+		return -ENOTTY;
+	if (_IOC_NR(cmd) > HANTRODEC_IOC_MAXNR)
+		return -ENOTTY;
+
+	/*
+	 * the direction is a bitmask, and VERIFY_WRITE catches R/W
+	 * transfers. `Type' is user-oriented, while
+	 * access_ok is kernel-oriented, so the concept of "read" and
+	 * "write" is reversed
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+
+	if (err)
+		return -EFAULT;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HANTRODEC_IOC_CLI): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= hantrodec_data.cores)
+			return -EFAULT;
+		disable_irq(hantrodec_data.irq[id]);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOC_STI): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= hantrodec_data.cores)
+			return -EFAULT;
+		enable_irq(hantrodec_data.irq[id]);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCGHWOFFSET): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		__put_user(multicorebase[id], (unsigned long *) arg);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCGHWIOSIZE): {
+		__u32 id;
+		__u32 io_size;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= hantrodec_data.cores)
+			return -EFAULT;
+		io_size = hantrodec_data.iosize[id];
+		__put_user(io_size, (u32 *) arg);
+
+		return 0;
+	}
+	case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS): {
+		tmp = copy_to_user((u64 *) arg, multicorebase, sizeof(multicorebase));
+		if (err) {
+			pr_err("copy_to_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+		__put_user(hantrodec_data.cores, (unsigned int *) arg);
+		PDEBUG("hantrodec_data.cores=%d\n", hantrodec_data.cores);
+		break;
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		DecFlushRegs(&hantrodec_data, &Core);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		PPFlushRegs(&hantrodec_data, &Core);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		return DecRefreshRegs(&hantrodec_data, &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		return PPRefreshRegs(&hantrodec_data, &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCH_DEC_RESERVE): {
+		PDEBUG("Reserve DEC Core, format = %li\n", arg);
+		return ReserveDecoder(&hantrodec_data, filp, arg);
+	}
+	case _IOC_NR(HANTRODEC_IOCT_DEC_RELEASE): {
+		if (arg >= hantrodec_data.cores || dec_owner[arg] != filp) {
+			pr_err("bogus DEC release, Core = %li\n", arg);
+			return -EFAULT;
+		}
+
+		PDEBUG("Release DEC, Core = %li\n", arg);
+
+		ReleaseDecoder(&hantrodec_data, arg);
+
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCQ_PP_RESERVE):
+		return ReservePostProcessor(&hantrodec_data, filp);
+	case _IOC_NR(HANTRODEC_IOCT_PP_RELEASE): {
+		if (arg != 0 || pp_owner[arg] != filp) {
+			pr_err("bogus PP release %li\n", arg);
+			return -EFAULT;
+		}
+
+		ReleasePostProcessor(&hantrodec_data, arg);
+
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT): {
+		struct core_desc Core;
+
+		/* get registers from user space */
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		return WaitDecReadyAndRefreshRegs(&hantrodec_data, &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCX_PP_WAIT): {
+		struct core_desc Core;
+
+		/* get registers from user space */
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= hantrodec_data.cores)
+			return -EFAULT;
+
+		return WaitPPReadyAndRefreshRegs(&hantrodec_data, &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT): {
+		int id;
+
+		tmp = WaitCoreReady(&hantrodec_data, filp, &id);
+		__put_user(id, (int *) arg);
+		return tmp;
+	}
+	case _IOC_NR(HANTRODEC_IOX_ASIC_ID): {
+		u32 id;
+
+		__get_user(id, (u32 *)arg);
+		if (id >= hantrodec_data.cores)
+			return -EFAULT;
+		id = ioread32(hantrodec_data.hwregs[id]);
+		__put_user(id, (u32 *) arg);
+		return 0;
+	}
+	case _IOC_NR(HANTRODEC_IOCG_CORE_ID): {
+		PDEBUG("Get DEC Core_id, format = %li\n", arg);
+		return GetDecCoreID(&hantrodec_data, filp, arg);
+	}
+	case _IOC_NR(HANTRODEC_DEBUG_STATUS): {
+		PDEBUG("hantrodec: dec_irq     = 0x%08x\n", dec_irq);
+		PDEBUG("hantrodec: pp_irq      = 0x%08x\n", pp_irq);
+
+		PDEBUG("hantrodec: IRQs received/sent2user = %d / %d\n",
+		atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+		for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+			PDEBUG("hantrodec: dec_core[%li] %s\n",
+					tmp, dec_owner[tmp] == NULL ? "FREE" : "RESERVED");
+			PDEBUG("hantrodec: pp_core[%li]  %s\n",
+					tmp, pp_owner[tmp] == NULL ? "FREE" : "RESERVED");
+		}
+		break;
+	}
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct core_desc_32 {
+	__u32 id; /* id of the Core */
+	compat_caddr_t regs; /* pointer to user registers */
+	__u32 size; /* size of register space */
+};
+
+static int get_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+	u32 tmp;
+
+	if (!access_ok(up, sizeof(struct core_desc_32)) ||
+				get_user(kp->id, &up->id) ||
+				get_user(kp->size, &up->size) ||
+				get_user(tmp, &up->regs)) {
+		return -EFAULT;
+	}
+	kp->regs = (__force u32 *)compat_ptr(tmp);
+	return 0;
+}
+
+static int put_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->regs);
+
+	if (!access_ok(up, sizeof(struct core_desc_32)) ||
+				put_user(kp->id, &up->id) ||
+				put_user(kp->size, &up->size) ||
+				put_user(tmp, &up->regs)) {
+		return -EFAULT;
+	}
+	return 0;
+}
+static long hantrodec_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+#define HANTRO_IOCTL32(err, filp, cmd, arg) { \
+		mm_segment_t old_fs = get_fs(); \
+		set_fs(KERNEL_DS); \
+		err = hantrodec_ioctl(filp, cmd, arg); \
+		if (err) \
+			return err; \
+		set_fs(old_fs); \
+	}
+
+	union {
+		struct core_desc kcore;
+		unsigned long kux;
+		unsigned int kui;
+	} karg;
+	void __user *up = compat_ptr(arg);
+	long err = 0;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HANTRODEC_IOCGHWOFFSET):
+	case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS):
+		err = get_user(karg.kux, (s32 __user *)up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kux), (s32 __user *)up);
+		break;
+	case _IOC_NR(HANTRODEC_IOCGHWIOSIZE):
+	case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+	case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT):
+	case _IOC_NR(HANTRODEC_IOX_ASIC_ID):
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG):
+	case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG):
+	case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT):
+	case _IOC_NR(HANTRODEC_IOCX_PP_WAIT):
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG):
+	case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG):
+		err = get_hantro_core_desc32(&karg.kcore, up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_hantro_core_desc32(&karg.kcore, up);
+		break;
+	default:
+		err = hantrodec_ioctl(filp, cmd, (unsigned long)up);
+		break;
+	}
+
+	return err;
+}
+
+#endif //ifdef CONFIG_COMPAT
+
+/*--------------------------------------------------------------------------
+ *Function name   : hantrodec_open
+ *Description     : open method
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_open(struct inode *inode, struct file *filp)
+{
+	PDEBUG("dev opened\n");
+	hantro_clk_enable(hantro_dev);
+	pm_runtime_get_sync(hantro_dev);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_release
+ *Description     : Release driver
+ *
+ *Return type     : int
+ *----------------------------------------------------------------------------
+ */
+static int hantrodec_release(struct inode *inode, struct file *filp)
+{
+	int n;
+	hantrodec_t *dev = &hantrodec_data;
+
+	PDEBUG("closing ...\n");
+
+	for (n = 0; n < dev->cores; n++) {
+		if (dec_owner[n] == filp) {
+			PDEBUG("releasing dec Core %i lock\n", n);
+			ReleaseDecoder(dev, n);
+		}
+	}
+
+	for (n = 0; n < 1; n++) {
+		if (pp_owner[n] == filp) {
+			PDEBUG("releasing pp Core %i lock\n", n);
+			ReleasePostProcessor(dev, n);
+		}
+	}
+
+	pm_runtime_put_sync(hantro_dev);
+	hantro_clk_disable(hantro_dev);
+	PDEBUG("closed\n");
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantro_mmap
+ *Description     : memory map interface for hantro file operation
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int hantro_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+	if (vm->vm_pgoff == (multicorebase[0] >> PAGE_SHIFT) || vm->vm_pgoff == (multicorebase[1] >> PAGE_SHIFT)) {
+		vm->vm_flags |= VM_IO;
+		vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+		PDEBUG("hantro mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+		return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+						vm->vm_page_prot) ? -EAGAIN : 0;
+	}	else {
+		pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+		return -EINVAL;
+	}
+}
+
+/* VFS methods */
+static const struct file_operations hantrodec_fops = {
+	.owner = THIS_MODULE,
+	.open = hantrodec_open,
+	.release = hantrodec_release,
+	.unlocked_ioctl = hantrodec_ioctl,
+	.fasync = NULL,
+	.mmap = hantro_mmap,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = hantrodec_ioctl32,
+#endif
+};
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_init
+ *Description     : Initialize the driver
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+int hantrodec_init(struct platform_device *pdev)
+{
+	int result;
+	int irq_0, irq_1;
+
+	dec_irq = 0;
+	pp_irq = 0;
+	pr_debug("hantrodec: Init multi Core[0] at 0x%16lx\n"
+			"                     Core[1] at 0x%16lx\n", multicorebase[0], multicorebase[1]);
+
+	hantrodec_data.cores = 0;
+	hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+	hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+
+	hantrodec_data.async_queue_dec = NULL;
+	hantrodec_data.async_queue_pp = NULL;
+
+	result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+	if (result < 0) {
+		pr_err("hantrodec: unable to get major %d\n", hantrodec_major);
+		goto err;
+	} else if (result != 0) { /* this is for dynamic major */
+		hantrodec_major = result;
+	}
+
+	result = ReserveIO();
+	if (result < 0)
+		goto err;
+
+	memset(dec_owner, 0, sizeof(dec_owner));
+	memset(pp_owner, 0, sizeof(pp_owner));
+
+	sema_init(&dec_core_sem, hantrodec_data.cores-1);
+	sema_init(&pp_core_sem, 1);
+
+	/* read configuration fo all cores */
+	ReadCoreConfig(&hantrodec_data);
+
+	/* reset hardware */
+	ResetAsic(&hantrodec_data);
+
+	/* register irq for each core*/
+	irq_0 = platform_get_irq_byname(pdev, "irq_hantro_g1");
+	if (irq_0 > 0) {
+		hantrodec_data.irq[0] = irq_0;
+		result = request_irq(irq_0, hantrodec_isr, IRQF_SHARED,
+				"hantrodec", (void *) &hantrodec_data);
+
+		if (result != 0) {
+			if (result == -EINVAL)
+				pr_err("hantrodec: Bad irq number or handler\n");
+			else if (result == -EBUSY) {
+				pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+				hantrodec_data.irq[0]);
+			}
+			ReleaseIO();
+			goto err;
+		}
+	}	else {
+		pr_err("hantrodec: IRQ0 not in use!\n");
+		goto err;
+	}
+
+	irq_1 = platform_get_irq_byname(pdev, "irq_hantro_g2");
+	if (irq_1 > 0) {
+		hantrodec_data.irq[1] = irq_1;
+		result = request_irq(irq_1, hantrodec_isr, IRQF_SHARED,
+				"hantrodec", (void *) &hantrodec_data);
+
+		if (result != 0) {
+			if (result == -EINVAL)
+				pr_err("hantrodec: Bad irq number or handler\n");
+			else if (result == -EBUSY) {
+				pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+					hantrodec_data.irq[1]);
+			}
+
+			ReleaseIO();
+			goto err;
+		}
+	}	else {
+		pr_err("hantrodec: IRQ1 not in use!\n");
+		goto err;
+	}
+	pr_info("hantrodec: module inserted. Major = %d\n", hantrodec_major);
+
+	return 0;
+
+err:
+	pr_err("hantrodec: module not inserted\n");
+	unregister_chrdev(hantrodec_major, "hantrodec");
+	return result;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_cleanup
+ *Description     : clean up
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+void hantrodec_cleanup(void)
+{
+	hantrodec_t *dev = &hantrodec_data;
+	int n = 0;
+	/* reset hardware */
+	ResetAsic(dev);
+
+	/* free the IRQ */
+	for (n = 0; n < dev->cores; n++) {
+		if (dev->irq[n] != -1)
+			free_irq(dev->irq[n], (void *) dev);
+	}
+
+	ReleaseIO();
+
+	unregister_chrdev(hantrodec_major, "hantrodec");
+
+	PDEBUG("hantrodec: module removed\n");
+
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : CheckHwId
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int CheckHwId(hantrodec_t *dev)
+{
+	long int hwid;
+	int i;
+	size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+	int found = 0;
+
+	for (i = 0; i < dev->cores; i++) {
+		if (dev->hwregs[i] != NULL) {
+			hwid = readl(dev->hwregs[i]);
+			pr_debug("hantrodec: Core %d HW ID=0x%16lx\n", i, hwid);
+			hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+			while (num_hw--) {
+				if (hwid == DecHwId[num_hw]) {
+					pr_debug("hantrodec: Supported HW found at 0x%16lx\n",
+							multicorebase[i]);
+					found++;
+					dev->hw_id[i] = hwid;
+					break;
+				}
+			}
+			if (!found) {
+				pr_err("hantrodec: Unknown HW found at 0x%16lx\n",	multicorebase[i]);
+				return 0;
+			}
+			found = 0;
+			num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+		}
+	}
+
+	return 1;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : ReserveIO
+ *Description     : IO reserve
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int ReserveIO(void)
+{
+	int i;
+
+	for (i = 0; i < HXDEC_MAX_CORES; i++) {
+		if (multicorebase[i] != -1) {
+			if (!request_mem_region(multicorebase[i], hantrodec_data.iosize[i], "hantrodec0")) {
+				pr_err("hantrodec: failed to reserve HW regs\n");
+				return -EBUSY;
+			}
+
+			hantrodec_data.hwregs[i] = (volatile u8 *) ioremap_nocache(multicorebase[i],
+			hantrodec_data.iosize[i]);
+
+			if (hantrodec_data.hwregs[i] == NULL) {
+				pr_err("hantrodec: failed to ioremap HW regs\n");
+				ReleaseIO();
+				return -EBUSY;
+			}
+			hantrodec_data.cores++;
+		}
+	}
+
+	/* check for correct HW */
+	if (!CheckHwId(&hantrodec_data)) {
+		ReleaseIO();
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : releaseIO
+ *Description     : release
+ *
+ *Return type     : void
+ *---------------------------------------------------------------------------
+ */
+static void ReleaseIO(void)
+{
+	int i;
+
+	for (i = 0; i < hantrodec_data.cores; i++) {
+		if (hantrodec_data.hwregs[i])
+			iounmap((void *) hantrodec_data.hwregs[i]);
+		release_mem_region(multicorebase[i], hantrodec_data.iosize[i]);
+	}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_isr
+ *Description     : interrupt handler
+ *
+ *Return type     : irqreturn_t
+ *---------------------------------------------------------------------------
+ */
+irqreturn_t hantrodec_isr(int irq, void *dev_id)
+{
+	unsigned long flags;
+	unsigned int handled = 0;
+	int i;
+	volatile u8 *hwregs;
+
+	hantrodec_t *dev = (hantrodec_t *) dev_id;
+	u32 irq_status_dec;
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	for (i = 0; i < dev->cores; i++) {
+		volatile u8 *hwregs = dev->hwregs[i];
+
+		/* interrupt status register read */
+		irq_status_dec = ioread32(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+		if (irq_status_dec & HANTRODEC_DEC_IRQ) {
+			/* clear dec IRQ */
+			irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+			iowrite32(irq_status_dec, hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+			PDEBUG("decoder IRQ received! Core %d\n", i);
+
+			atomic_inc(&irq_rx);
+
+			dec_irq |= (1 << i);
+
+			//wake_up_interruptible_all(&dec_wait_queue);
+			wake_up_all(&dec_wait_queue);
+			handled++;
+		}
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	if (!handled)
+		pr_info("IRQ received, but not hantrodec's!\n");
+
+	(void)hwregs;
+	return IRQ_RETVAL(handled);
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : ResetAsic
+ *Description     : reset asic
+ *
+ *Return type     :
+ *---------------------------------------------------------------------------
+ */
+void ResetAsic(hantrodec_t *dev)
+{
+	int i, j;
+	u32 status;
+
+	for (j = 0; j < dev->cores; j++) {
+		status = ioread32(dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+		if (status & HANTRODEC_DEC_E) {
+			/* abort with IRQ disabled */
+			status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+			iowrite32(status, dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+		}
+
+		if (IS_G1(dev->hw_id[j]))
+			/* reset PP */
+			iowrite32(0, dev->hwregs[j] + HANTRO_IRQ_STAT_PP_OFF);
+
+		for (i = 4; i < dev->iosize[j]; i += 4)
+			iowrite32(0, dev->hwregs[j] + i);
+	}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : dump_regs
+ *Description     : Dump registers
+ *
+ *Return type     :
+ *---------------------------------------------------------------------------
+ */
+#ifdef HANTRODEC_DEBUG
+void dump_regs(hantrodec_t *dev)
+{
+	int i, c;
+
+	PDEBUG("Reg Dump Start\n");
+	for (c = 0; c < dev->cores; c++) {
+		for (i = 0; i < dev->iosize[c]; i += 4*4) {
+			PDEBUG("\toffset %04X: %08X  %08X  %08X  %08X\n", i,
+			ioread32(dev->hwregs[c] + i),
+			ioread32(dev->hwregs[c] + i + 4),
+			ioread32(dev->hwregs[c] + i + 8),
+			ioread32(dev->hwregs[c] + i + 12));
+		}
+	}
+	PDEBUG("Reg Dump End\n");
+}
+#endif
+
+static int hantro_dev_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct device *temp_class;
+	struct resource *res;
+	unsigned long reg_base;
+
+	hantro_dev = &pdev->dev;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro");
+	if (!res) {
+		pr_err("hantro: unable to get vpu base addr\n");
+		return -ENODEV;
+	}
+	reg_base = res->start;
+	if ((ulong)reg_base != multicorebase[0]) {
+		pr_err("hantrodec: regbase(0x%lX) not equal to expected value(0x%lX)\n", reg_base, multicorebase[0]);
+		return -ENODEV;
+	}
+
+	hantro_clk_g1 = clk_get(&pdev->dev, "clk_hantro_g1");
+	hantro_clk_g2 = clk_get(&pdev->dev, "clk_hantro_g2");
+	hantro_clk_bus = clk_get(&pdev->dev, "clk_hantro_bus");
+	if (IS_ERR(hantro_clk_g1) || IS_ERR(hantro_clk_g2) || IS_ERR(hantro_clk_bus)) {
+		pr_err("hantro: get clock failed\n");
+		return -ENODEV;
+	}
+	pr_debug("hantro: g1, g2, bus clock: 0x%lX, 0x%lX, 0x%lX\n", clk_get_rate(hantro_clk_g1),
+				clk_get_rate(hantro_clk_g2), clk_get_rate(hantro_clk_bus));
+
+#if 0
+	hantro_regulator = regulator_get(&pdev->dev, "regulator");
+	if (IS_ERR(hantro_regulator)) {
+		pr_err("hantro: get regulator failed\n");
+		return -ENODEV;
+	}
+	hantro_update_voltage(&pdev->dev);
+#endif
+	hantro_clk_enable(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	pm_runtime_get_sync(&pdev->dev);
+
+	hantro_ctrlblk_reset(&pdev->dev);
+
+	err = hantrodec_init(pdev);
+	if (0 != err) {
+		pr_err("hantro: hantrodec_init failed\n");
+		goto error;
+	}
+
+	hantro_class = class_create(THIS_MODULE, "mxc_hantro");
+	if (IS_ERR(hantro_class)) {
+		err = PTR_ERR(hantro_class);
+		goto error;
+	}
+	temp_class = device_create(hantro_class, NULL, MKDEV(hantrodec_major, 0), NULL, DEVICE_NAME);
+	if (IS_ERR(temp_class)) {
+		err = PTR_ERR(temp_class);
+		goto err_out_class;
+	}
+
+#ifdef CONFIG_DEVICE_THERMAL
+	HANTRO_REG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+	thermal_event = 0;
+	thermal_cur = 0;
+	hantro_dynamic_clock = 0;
+#endif
+	timeout = 0;
+	goto out;
+
+err_out_class:
+	device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+	class_destroy(hantro_class);
+error:
+	pr_err("hantro probe failed\n");
+out:
+	pm_runtime_put_sync(&pdev->dev);
+	hantro_clk_disable(&pdev->dev);
+	return err;
+}
+
+static int hantro_dev_remove(struct platform_device *pdev)
+{
+	hantro_clk_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	if (hantrodec_major > 0) {
+		device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+		class_destroy(hantro_class);
+		hantrodec_cleanup();
+		hantrodec_major = 0;
+	}
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	hantro_clk_disable(&pdev->dev);
+
+	if (!IS_ERR(hantro_clk_g1))
+		clk_put(hantro_clk_g1);
+	if (!IS_ERR(hantro_clk_g2))
+		clk_put(hantro_clk_g2);
+	if (!IS_ERR(hantro_clk_bus))
+		clk_put(hantro_clk_bus);
+
+#ifdef CONFIG_DEVICE_THERMAL
+	HANTRO_UNREG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_suspend(struct device *dev)
+{
+	pm_runtime_put_sync_suspend(dev);   //power off
+	return 0;
+}
+static int hantro_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);     //power on
+	hantro_ctrlblk_reset(dev);
+	return 0;
+}
+static int hantro_runtime_suspend(struct device *dev)
+{
+//	release_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static int hantro_runtime_resume(struct device *dev)
+{
+//	request_bus_freq(BUS_FREQ_HIGH);
+	hantro_ctrlblk_reset(dev);
+	return 0;
+}
+
+static const struct dev_pm_ops hantro_pm_ops = {
+	SET_RUNTIME_PM_OPS(hantro_runtime_suspend, hantro_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(hantro_suspend, hantro_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_of_match[] = {
+	{ .compatible = "nxp,imx8mq-hantro", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, hantro_of_match);
+
+
+static struct platform_driver mxchantro_driver = {
+	.driver = {
+	.name = "mxc_hantro",
+	.of_match_table = hantro_of_match,
+#ifdef CONFIG_PM
+	.pm = &hantro_pm_ops,
+#endif
+	},
+	.probe = hantro_dev_probe,
+	.remove = hantro_dev_remove,
+};
+
+static int __init hantro_init(void)
+{
+	int ret = platform_driver_register(&mxchantro_driver);
+
+	return ret;
+}
+
+static void __exit hantro_exit(void)
+{
+
+#if 0
+	if (!IS_ERR(hantro_regulator))
+		regulator_put(hantro_regulator);
+#endif
+	platform_driver_unregister(&mxchantro_driver);
+}
+
+module_init(hantro_init);
+module_exit(hantro_exit);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Driver module for Hantro Decoder/Post-Processor");
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/hantro_845/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) 845 support"
+	depends on ARCH_MXC
+
+config MXC_HANTRO_845
+	tristate "Support for MXC HANTRO(Video Processing Unit) 845"
+	default y
+	---help---
+	  VPU codec device.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845/Makefile
+++ linux-ein-5.4.0/drivers/mxc/hantro_845/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+#ccflags-y += -I$(PWD)
+
+obj-$(CONFIG_MXC_HANTRO_845) += hantrodec_845s.o
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845/dwl_defs.h
+++ linux-ein-5.4.0/drivers/mxc/hantro_845/dwl_defs.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ *    The GPL License (GPL)
+ *
+ *    Copyright (c) 2015-2017, VeriSilicon Inc.
+ *    Copyright (c) 2011-2014, Google Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version 2
+ *    of the License, or (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You may obtain a copy of the GNU General Public License
+ *    Version 2 or later at the following locations:
+ *    http://www.opensource.org/licenses/gpl-license.html
+ *    http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E 31 /* 1 bit */
+#define DWL_VC1_E 29   /* 2 bits */
+#define DWL_JPEG_E 28  /* 1 bit */
+#define DWL_MPEG4_E 26 /* 2 bits */
+#define DWL_H264_E 24  /* 2 bits */
+#define DWL_VP6_E 23   /* 1 bit */
+#define DWL_RV_E 26    /* 2 bits */
+#define DWL_VP8_E 23   /* 1 bit */
+#define DWL_VP7_E 24   /* 1 bit */
+#define DWL_WEBP_E 19  /* 1 bit */
+#define DWL_AVS_E 22   /* 1 bit */
+#if 0
+#define DWL_PP_E       16  /* 1 bit */
+#endif
+#define DWL_PP_E 31    /* 1 bit */
+#define DWL_HEVC_E 5   /* 2 bits */
+#define DWL_VP9_E 3    /* 2 bits */
+
+#define DWL_HEVC_ENA 0  /* 1 bits */
+#define DWL_VP9_ENA 1   /* 1 bits */
+#define DWL_RFC_E 2     /* 1 bits */
+#define DWL_DS_E 3      /* 1 bits */
+#define DWL_HEVC_VER 8  /* 4 bits */
+#define DWL_VP9_PROFILE 12 /* 3 bits */
+#define DWL_RING_E 16   /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC 1
+#define HANTRODEC_IRQ_STAT_DEC_OFF (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG 60
+#define HANTRODECPP_SYNTH_CFG_OFF (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3 56
+#define HANTRODEC_SYNTH_CFG_3_OFF (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT 23
+#define HANTRODEC_CFG_STAT_OFF (HANTRODEC_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E 0x01
+#define HANTRODEC_PP_E 0x01
+#define HANTRODEC_DEC_ABORT 0x20
+#define HANTRODEC_DEC_IRQ_DISABLE 0x10
+#define HANTRODEC_DEC_IRQ 0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC          1
+#define HANTRO_IRQ_STAT_DEC_OFF      (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP           60
+#define HANTRO_IRQ_STAT_PP_OFF       (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG           100
+#define HANTROPP_SYNTH_CFG_OFF       (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG          50
+#define HANTRODEC_SYNTH_CFG_OFF      (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2        54
+#define HANTRODEC_SYNTH_CFG_2_OFF    (HANTRODEC_SYNTH_CFG_2 * 4)
+
+#define HANTRO_DEC_E                 0x01
+#define HANTRO_PP_E                  0x01
+#define HANTRO_DEC_ABORT             0x20
+#define HANTRO_DEC_IRQ_DISABLE       0x10
+#define HANTRO_PP_IRQ_DISABLE        0x10
+#define HANTRO_DEC_IRQ               0x100
+#define HANTRO_PP_IRQ                0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845/hantrodec_845s.c
+++ linux-ein-5.4.0/drivers/mxc/hantro_845/hantrodec_845s.c
@@ -0,0 +1,2108 @@
+/*****************************************************************************
+ *    The GPL License (GPL)
+ *
+ *    Copyright (c) 2015-2020, VeriSilicon Inc.
+ *    Copyright (c) 2011-2014, Google Inc.
+ *
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License
+ *    as published by the Free Software Foundation; either version 2
+ *    of the License, or (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You may obtain a copy of the GNU General Public License
+ *    Version 2 or later at the following locations:
+ *    http://www.opensource.org/licenses/gpl-license.html
+ *    http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+#include <linux/hantrodec.h>
+#include "dwl_defs.h"
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/busfreq-imx.h>
+
+#include <linux/delay.h>
+
+//#define CONFIG_DEVICE_THERMAL_HANTRO
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+#include <linux/device_cooling.h>
+#define HANTRO_REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a)
+#define HANTRO_UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a)
+static DEFINE_SPINLOCK(thermal_lock);
+/*1:hot, 0: not hot*/
+static int thermal_event;
+static int hantro_clock_ratio = 2;
+static int hantro_dynamic_clock;
+module_param(hantro_clock_ratio, int, 0644);
+module_param(hantro_dynamic_clock, int, 0644);
+MODULE_PARM_DESC(hantro_clock_ratio, "clock ratio 1/N");
+MODULE_PARM_DESC(hantro_dynamic_clock, "enable or disable dynamic clock rate");
+#endif
+
+/*hantro G1 regs config including dec and pp*/
+#define HANTRO_DEC_ORG_REGS             60
+#define HANTRO_PP_ORG_REGS              41
+
+#define HANTRO_DEC_EXT_REGS             27
+#define HANTRO_PP_EXT_REGS              9
+
+#define HANTRO_G1_DEC_TOTAL_REGS        (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS            (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_TOTAL_REGS             155 /*G1 total regs*/
+
+#define HANTRO_DEC_ORG_FIRST_REG        0
+#define HANTRO_DEC_ORG_LAST_REG         59
+#define HANTRO_DEC_EXT_FIRST_REG        119
+#define HANTRO_DEC_EXT_LAST_REG         145
+
+#define HANTRO_PP_ORG_FIRST_REG         60
+#define HANTRO_PP_ORG_LAST_REG          100
+#define HANTRO_PP_EXT_FIRST_REG         146
+#define HANTRO_PP_EXT_LAST_REG          154
+
+/*hantro G2 reg config*/
+#define HANTRO_G2_DEC_REGS                 265 /*G2 total regs*/
+
+#define HANTRO_G2_DEC_FIRST_REG            0
+#define HANTRO_G2_DEC_LAST_REG             (HANTRO_G2_DEC_REGS - 1)
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX             (MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_TOTAL_REGS) * 4)
+
+/********************************************************************
+ *                                              PORTING SEGMENT
+ * NOTES: customer should modify these configuration if do porting to own platform.
+ * Please guarantee the base_addr, io_size,dec_irq belong to same core.
+ ********************************************************************/
+
+#define HXDEC_MAX_CORES                 2
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE              0x38300000
+#define SOCLE_LOGIC_1_BASE              0x38310000
+#define BLK_CTL_BASE                          0x38330000 //0x38320000
+
+#define VEXPRESS_LOGIC_0_BASE           0xFC010000
+#define VEXPRESS_LOGIC_1_BASE           0xFC020000
+
+#define DEC_IO_SIZE_0             ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#define DEC_IO_SIZE_1             ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+
+#define HANTRO_DEC_DEF_CLK		(600000000)
+#define HANTRO_BUS_DEF_CLK	(800000000)
+/***********************************************************************/
+
+#define IS_G1(hw_id)    ((hw_id == 0x6731) ? 1:0)
+
+static const int DecHwId[] = {
+	0x8190, /* Legacy HW */
+	0x8170,
+	0x9170,
+	0x9190,
+	0x6731, /* G1 */
+	0x6732 /* G2 */
+};
+
+static ulong multicorebase[HXDEC_MAX_CORES] = {
+	SOCLE_LOGIC_0_BASE,
+	SOCLE_LOGIC_1_BASE
+};
+
+
+static struct class *hantro_class;
+#define DEVICE_NAME		"mxc_hantro"
+
+//static struct device *hantro_dev[HXDEC_MAX_CORES];
+
+typedef struct {
+	struct clk *dec;
+	struct clk *bus;
+} hantrodec_clk;
+
+static int hantro_dbg = -1;
+module_param(hantro_dbg, int, 0644);
+MODULE_PARM_DESC(hantro_dbg, "Debug level (0-1)");
+#undef PDEBUG
+#define PDEBUG(fmt, arg...)     \
+	do {                                      \
+		if (hantro_dbg > 0) { \
+			dev_info(hantrodec_data[0].dev, fmt, ## arg); \
+		} \
+	} while (0)
+
+
+static int hantrodec_major;
+static int cores = 2;
+/* here's all the must remember stuff */
+typedef struct {
+	//char *buffer;
+	unsigned int iosize;
+	volatile u8 *hwregs;
+	int irq;
+	int hw_id;
+	int hw_active;
+	int core_id;
+	//int cores;
+	//struct fasync_struct *async_queue_dec;
+	//struct fasync_struct *async_queue_pp;
+	hantrodec_clk clk;
+	u32 dec_regs[DEC_IO_SIZE_MAX/4];
+	struct semaphore dec_core_sem;
+	struct semaphore pp_core_sem;
+	struct file *dec_owner;
+	struct file *pp_owner;
+	u32 cfg;
+	u32 timeout;
+	atomic_t irq_rx;
+	atomic_t irq_tx;
+	struct device *dev;
+	struct mutex dev_mutex;
+	int thermal_cur;
+} hantrodec_t;
+
+static hantrodec_t hantrodec_data[HXDEC_MAX_CORES]; /* dynamic allocation? */
+
+typedef struct {
+	char inst_id;
+	char core_id;	//1:g1; 2:g2; 3:unknow
+} hantrodec_instance;
+static unsigned long instance_mask;
+#define MAX_HANTRODEC_INSTANCE 32
+static hantrodec_instance hantrodec_ctx[MAX_HANTRODEC_INSTANCE];
+
+static int ReserveIO(int);
+static void ReleaseIO(int);
+
+static void ResetAsic(hantrodec_t *dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+
+static int dec_irq;
+static int pp_irq;
+
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+static DEFINE_SPINLOCK(owner_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+
+static DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+#define DWL_CLIENT_TYPE_H264_DEC         1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC        2U
+#define DWL_CLIENT_TYPE_JPEG_DEC         3U
+#define DWL_CLIENT_TYPE_PP               4U
+#define DWL_CLIENT_TYPE_VC1_DEC          5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC        6U
+#define DWL_CLIENT_TYPE_VP6_DEC          7U
+#define DWL_CLIENT_TYPE_AVS_DEC          8U
+#define DWL_CLIENT_TYPE_RV_DEC           9U
+#define DWL_CLIENT_TYPE_VP8_DEC          10U
+#define DWL_CLIENT_TYPE_VP9_DEC          11U
+#define DWL_CLIENT_TYPE_HEVC_DEC         12U
+
+static int hantro_device_id(struct device *dev)
+{
+	int id;
+
+	if (strcmp("vpu_g1", dev->of_node->name) == 0) {
+		id = 0;
+	} else if (strcmp("vpu_g2", dev->of_node->name) == 0) {
+		id = 1;
+	} else {
+		return id = -1;
+	}
+	return id;
+}
+static int hantro_clk_enable(hantrodec_clk *clk)
+{
+	clk_prepare(clk->dec);
+	clk_enable(clk->dec);
+	clk_prepare(clk->bus);
+	clk_enable(clk->bus);
+	return 0;
+}
+
+static int hantro_clk_disable(hantrodec_clk *clk)
+{
+	clk_disable(clk->dec);
+	clk_unprepare(clk->dec);
+	clk_disable(clk->bus);
+	clk_unprepare(clk->bus);
+	return 0;
+}
+
+static int hantro_ctrlblk_reset(hantrodec_t *dev)
+{
+	volatile u8 *iobase;
+	u32 val;
+
+	//config G1/G2
+	hantro_clk_enable(&dev->clk);
+	iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+	if (dev->core_id == 0) {
+		val = ioread32(iobase);
+		val &= (~0x2);
+		iowrite32(val, iobase);  //assert G1 block soft reset  control
+		udelay(2);
+		val = ioread32(iobase);
+		val |= 0x2;
+		iowrite32(val, iobase);  //desert G1 block soft reset  control
+
+		val = ioread32(iobase+4);
+		val |= 0x2;
+		iowrite32(val, iobase+4); //VPUMIX G1 block clock enable control
+		iowrite32(0xFFFFFFFF, iobase + 0x8); // all G1 fuse dec enable
+		iowrite32(0xFFFFFFFF, iobase + 0xC); // all G1 fuse pp enable
+	} else {
+		val = ioread32(iobase);
+		val &= (~0x1);
+		iowrite32(val, iobase);  //assert G2 block soft reset  control
+		udelay(2);
+		val = ioread32(iobase);
+		val |= 0x1;
+		iowrite32(val, iobase);  //desert G2 block soft reset  control
+
+		val = ioread32(iobase+4);
+		val |= 0x1;
+		iowrite32(val, iobase+4); //VPUMIX G2 block clock enable control
+		iowrite32(0xFFFFFFFF, iobase + 0x10); // all G2 fuse dec enable
+	}
+	iounmap(iobase);
+	hantro_clk_disable(&dev->clk);
+	return 0;
+}
+
+static int hantro_power_on_disirq(hantrodec_t *hantrodev)
+{
+	//spin_lock_irq(&owner_lock);
+	mutex_lock(&hantrodev->dev_mutex);
+	disable_irq(hantrodev->irq);
+	pm_runtime_get_sync(hantrodev->dev);
+	enable_irq(hantrodev->irq);
+	mutex_unlock(&hantrodev->dev_mutex);
+	//spin_unlock_irq(&owner_lock);
+	return 0;
+}
+
+static int hantro_new_instance(void)
+{
+	int idx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (instance_mask  == ((1UL << MAX_HANTRODEC_INSTANCE) - 1)) {
+		spin_unlock_irqrestore(&owner_lock, flags);
+		return -1;
+	}
+	idx = ffz(instance_mask);
+	set_bit(idx, &instance_mask);
+	spin_unlock_irqrestore(&owner_lock, flags);
+	return idx;
+}
+
+static int hantro_free_instance(int idx)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	clear_bit(idx, &instance_mask);
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+static int hantro_thermal_check(struct device *dev)
+{
+	hantrodec_t *hantrodev = dev_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&thermal_lock, flags);
+	if (thermal_event == hantrodev->thermal_cur) {
+		/*nothing to do and return directly*/
+		spin_unlock_irqrestore(&thermal_lock, flags);
+		return 0;
+	}
+	hantrodev->thermal_cur = thermal_event;
+	spin_unlock_irqrestore(&thermal_lock, flags);
+
+	if (hantrodev->thermal_cur) {
+		int ratio = hantro_clock_ratio;
+
+		pr_debug("hantro[%d]: too hot, need to decrease clock, ratio: 1/%d\n", hantrodev->core_id, ratio);
+		/*clock disable/enable are not required for vpu clock rate operation*/
+		clk_set_rate(hantrodev->clk.dec, HANTRO_DEC_DEF_CLK/ratio);
+		clk_set_rate(hantrodev->clk.bus, HANTRO_BUS_DEF_CLK/ratio);
+	} else {
+		pr_debug("hantro[%d]: not hot again, will restore default clock\n", hantrodev->core_id);
+		clk_set_rate(hantrodev->clk.dec, HANTRO_DEC_DEF_CLK);
+		clk_set_rate(hantrodev->clk.bus, HANTRO_BUS_DEF_CLK);
+	}
+	pr_info("hantro[%d]: event(%d), dec, bus clock: %ld, %ld\n", hantrodev->core_id, hantrodev->thermal_cur,
+		clk_get_rate(hantrodev->clk.dec), clk_get_rate(hantrodev->clk.bus));
+	return 0;
+}
+
+static int hantro_thermal_hot_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&thermal_lock, flags);
+	thermal_event = event;		/*event: 1: hot, 0: cool*/
+	spin_unlock_irqrestore(&thermal_lock, flags);
+	pr_info("hantro receive hot notification event: %ld\n", event);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block hantro_thermal_hot_notifier = {
+	.notifier_call = hantro_thermal_hot_notify,
+};
+#endif  //CONFIG_DEVICE_THERMAL_HANTRO
+
+static void ReadCoreConfig(hantrodec_t *dev)
+{
+	int c = dev->core_id;
+	u32 reg, tmp, mask;
+
+	memset(&dev->cfg, 0, sizeof(dev->cfg));
+
+	//for (c = 0; c < dev->cores; c++) {
+		/* Decoder configuration */
+		if (IS_G1(dev->hw_id)) {
+			reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG * 4);
+
+			tmp = (reg >> DWL_H264_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has H264\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+			tmp = (reg >> DWL_JPEG_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has JPEG\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+			tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has MPEG4\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+			tmp = (reg >> DWL_VC1_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VC1\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC : 0;
+
+			tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has MPEG2\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+			tmp = (reg >> DWL_VP6_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VP6\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+			reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG_2 * 4);
+
+			/* VP7 and WEBP is part of VP8 */
+			mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+			tmp = (reg & mask);
+			if (tmp & (1 << DWL_VP8_E))
+				pr_debug("hantrodec: Core[%d] has VP8\n", c);
+			if (tmp & (1 << DWL_VP7_E))
+				pr_debug("hantrodec: Core[%d] has VP7\n", c);
+			if (tmp & (1 << DWL_WEBP_E))
+				pr_debug("hantrodec: Core[%d] has WebP\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+			tmp = (reg >> DWL_AVS_E) & 0x01U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has AVS\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC : 0;
+
+			tmp = (reg >> DWL_RV_E) & 0x03U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has RV\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+			/* Post-processor configuration */
+			//reg = ioread32(dev->hwregs + HANTROPP_SYNTH_CFG * 4);
+		} else {
+			reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG_2 * 4);
+
+			tmp = (reg >> DWL_HEVC_E) & 0x3U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has HEVC\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+			tmp = (reg >> DWL_VP9_E) & 0x03U;
+			if (tmp)
+				pr_debug("hantrodec: Core[%d] has VP9\n", c);
+			dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+		}
+
+		/* Post-processor configuration */
+		reg = ioread32(dev->hwregs + HANTRODECPP_SYNTH_CFG * 4);
+
+		tmp = (reg >> DWL_PP_E) & 0x01U;
+		if (tmp)
+			pr_debug("hantrodec: Core[%d] has PP\n", c);
+		dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+	//}
+}
+
+static int CoreHasFormat(const u32 cfg, u32 format)
+{
+	return (cfg & (1 << format)) ? 1 : 0;
+}
+
+static int GetDecCore(hantrodec_t *dev, struct file *filp)
+{
+	int success = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (dev->dec_owner == NULL) {
+		dev->dec_owner = filp;
+		success = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return success;
+}
+
+static int GetDecCoreAny(long *Core, hantrodec_t *dev, struct file *filp,
+			unsigned long format)
+{
+	int success = 0;
+	//long c;
+
+	*Core = -1;
+
+	//for (c = 0; c < dev->cores; c++) {
+		/* a free Core that has format */
+		if (CoreHasFormat(dev->cfg, format) && GetDecCore(dev, filp)) {
+			success = 1;
+			*Core = dev->core_id;
+			//break;
+		}
+	//}
+
+	return success;
+}
+
+static int GetDecCoreID(unsigned long format)
+{
+	long c;
+
+	int core_id = -1;
+
+	for (c = 0; c < cores; c++) {
+		/* a Core that has format */
+		if (CoreHasFormat(hantrodec_data[c].cfg, format)) {
+			core_id = c;
+			break;
+		}
+	}
+	PDEBUG("GetDecCoreID=%d\n", core_id);
+	return core_id;
+}
+#if 0
+static int hantrodec_choose_core(int is_g1)
+{
+	volatile unsigned char *reg = NULL;
+	unsigned int blk_base = BLK_CTL_BASE;
+
+	PDEBUG("hantrodec_choose_core\n");
+	if (!request_mem_region(blk_base, 0x1000, "blk_ctl"))	{
+		pr_err("blk_ctl: failed to reserve HW regs\n");
+		return -EBUSY;
+	}
+
+	reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+	if (reg == NULL) {
+		pr_err("blk_ctl: failed to ioremap HW regs\n");
+		if (reg)
+			iounmap((void *)reg);
+		release_mem_region(blk_base, 0x1000);
+		return -EBUSY;
+	}
+
+	// G1 use, set to 1; G2 use, set to 0, choose the one you are using
+	if (is_g1)
+		iowrite32(0x1, reg + 0x14);  // VPUMIX only use G1
+	else
+		iowrite32(0x0, reg + 0x14); // VPUMIX only use G2
+
+	if (reg)
+		iounmap((void *)reg);
+	release_mem_region(blk_base, 0x1000);
+	PDEBUG("hantrodec_choose_core OK!\n");
+	return 0;
+}
+#endif
+
+static long ReserveDecoder(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+	long Core = -1;
+
+	/* reserve a Core */
+	if (down_interruptible(&dev->dec_core_sem))
+		return -ERESTARTSYS;
+
+#if 1
+	if (GetDecCoreAny(&Core, dev, filp, format) == 0) {
+		pr_err("Core %d is already been reserved !\n", dev->core_id);
+		return -1;
+	}
+#else
+	/* lock a Core that has specific format*/
+	if (wait_event_interruptible(hw_queue, GetDecCoreAny(&Core, dev, filp, format) != 0))
+		return -ERESTARTSYS;
+#endif
+#if 0
+	if (IS_G1(dev->hw_id)) {
+		if (0 == hantrodec_choose_core(1))
+			PDEBUG("G1 is reserved\n");
+		else
+			return -1;
+	} else {
+		if (0 == hantrodec_choose_core(0))
+			PDEBUG("G2 is reserved\n");
+		else
+			return -1;
+	}
+#endif
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+	if (hantro_dynamic_clock)
+		hantro_thermal_check(dev->dev);
+#endif
+
+	return Core;
+}
+
+static void ReleaseDecoder(hantrodec_t *dev)
+{
+	u32 status;
+	unsigned long flags;
+
+	status = ioread32(dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+	/* make sure HW is disabled */
+	if (status & HANTRODEC_DEC_E) {
+		pr_info("hantrodec: DEC[%d] still enabled -> reset\n", dev->core_id);
+
+		/* abort decoder */
+		status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+		iowrite32(status, dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	dev->dec_owner = NULL;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	up(&dev->dec_core_sem);
+
+	//wake_up_interruptible_all(&hw_queue);
+
+}
+
+static long ReservePostProcessor(hantrodec_t *dev, struct file *filp)
+{
+	unsigned long flags;
+
+	long Core = 0;
+
+	/* single Core PP only */
+	if (down_interruptible(&dev->pp_core_sem))
+		return -ERESTARTSYS;
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	dev->pp_owner = filp;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return Core;
+}
+
+static void ReleasePostProcessor(hantrodec_t *dev)
+{
+	unsigned long flags;
+
+	u32 status = ioread32(dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+
+	/* make sure HW is disabled */
+	if (status & HANTRO_PP_E) {
+		pr_info("hantrodec: PP[%d] still enabled -> reset\n", dev->core_id);
+
+		/* disable IRQ */
+		status |= HANTRO_PP_IRQ_DISABLE;
+
+		/* disable postprocessor */
+		status &= (~HANTRO_PP_E);
+		iowrite32(0x10, dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	dev->pp_owner = NULL;
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	up(&dev->pp_core_sem);
+}
+
+#if 0
+static long ReserveDecPp(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+	/* reserve Core 0, DEC+PP for pipeline */
+	unsigned long flags;
+
+	long Core = 0;
+
+	/* check that Core has the requested dec format */
+	if (!CoreHasFormat(dev->cfg, format))
+		return -EFAULT;
+
+	/* check that Core has PP */
+	if (!CoreHasFormat(dev->cfg, DWL_CLIENT_TYPE_PP))
+		return -EFAULT;
+
+	/* reserve a Core */
+	if (down_interruptible(&dev->dec_core_sem))
+		return -ERESTARTSYS;
+
+	/* wait until the Core is available */
+	if (wait_event_interruptible(hw_queue,	GetDecCore(dev, filp) != 0)) {
+		up(&dev->dec_core_sem);
+		return -ERESTARTSYS;
+	}
+
+	if (down_interruptible(&dev->pp_core_sem)) {
+		ReleaseDecoder(dev);
+		return -ERESTARTSYS;
+	}
+
+	spin_lock_irqsave(&owner_lock, flags);
+	dev->pp_owner = filp;
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return Core;
+}
+#endif
+static long DecFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret = 0, i;
+
+	//u32 id = Core->id;
+
+	if (IS_G1(dev->hw_id)) {
+		/* copy original dec regs to kernal space*/
+		ret = copy_from_user(dev->dec_regs, Core->regs, HANTRO_DEC_ORG_REGS*4);
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+#ifdef USE_64BIT_ENV
+		/* copy extended dec regs to kernal space*/
+		ret = copy_from_user(dev->dec_regs + HANTRO_DEC_EXT_FIRST_REG,
+				Core->regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+
+		/* write dec regs but the status reg[1] to hardware */
+		/* both original and extended regs need to be written */
+		for (i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#endif
+	} else {
+		ret = copy_from_user(dev->dec_regs, Core->regs, HANTRO_G2_DEC_REGS*4);
+		if (ret) {
+			pr_err("copy_from_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+
+		/* write all regs but the status reg[1] to hardware */
+		for (i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+	}
+
+	if (dev->dec_regs[1] & 0x1)
+		dev->hw_active = 1;
+	/* write the status register, which may start the decoder */
+	iowrite32(dev->dec_regs[1], dev->hwregs + 4);
+
+	PDEBUG("flushed registers on Core %d\n", dev->core_id);
+
+	return 0;
+}
+
+static long DecRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret, i;
+	//u32 id = Core->id;
+
+	if (IS_G1(dev->hw_id)) {
+		/* user has to know exactly what they are asking for */
+		//if(Core->size != (HANTRO_DEC_ORG_REGS * 4))
+		//  return -EFAULT;
+
+		/* read all registers from hardware */
+		/* both original and extended regs need to be read */
+		for (i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#endif
+
+		if (dev->timeout) {
+			/* Enable TIMEOUT bits in Reg[1] */
+			dev->dec_regs[1] = 0x40100;
+			/* Reset HW */
+			ResetAsic(dev);
+			dev->timeout = 0;
+		}
+
+		/* put registers to user space*/
+		/* put original registers to user space*/
+		ret = copy_to_user(Core->regs, dev->dec_regs, HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+		/*put extended registers to user space*/
+		ret = copy_to_user(Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+				dev->dec_regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+		if (ret) {
+			pr_err("copy_to_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+	} else {
+	/* user has to know exactly what they are asking for */
+		if (Core->size != (HANTRO_G2_DEC_REGS * 4))
+			return -EFAULT;
+
+		/* read all registers from hardware */
+		for (i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+
+		if (dev->timeout) {
+			/* Enable TIMEOUT bits in Reg[1] */
+			dev->dec_regs[1] = 0x40100;
+			/* Reset HW */
+			ResetAsic(dev);
+			dev->timeout = 0;
+		}
+
+		/* put registers to user space*/
+		ret = copy_to_user(Core->regs, dev->dec_regs, HANTRO_G2_DEC_REGS*4);
+		if (ret) {
+			pr_err("copy_to_user failed, returned %li\n", ret);
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+static long DecRestoreRegs(hantrodec_t *dev)
+{
+	long i;
+
+	if (IS_G1(dev->hw_id)) {
+		/* write dec regs to hardware */
+		/* both original and extended regs need to be written */
+		for (i = 1; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#endif
+	} else {
+		/* write all regs to hardware */
+		for (i = 1; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+	}
+	return 0;
+}
+
+static long DecStoreRegs(hantrodec_t *dev)
+{
+	long i;
+
+	if (IS_G1(dev->hw_id)) {
+		/* read all registers from hardware */
+		/* both original and extended regs need to be read */
+		for (i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+		for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#endif
+	} else {
+		/* read all registers from hardware */
+		for (i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+			dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+	}
+	return 0;
+}
+
+
+static int CheckDecIrq(hantrodec_t *dev)
+{
+	unsigned long flags;
+	int rdy = 0;
+
+	const u32 irq_mask = (1 << dev->core_id);
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	if (dec_irq & irq_mask) {
+		/* reset the wait condition(s) */
+		dec_irq &= ~irq_mask;
+		rdy = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return rdy;
+}
+
+static long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	//u32 id = Core->id;
+	long ret;
+
+	PDEBUG("wait_event_interruptible DEC[%d]\n", dev->core_id);
+
+	//ret = wait_event_interruptible_timeout(dec_wait_queue, CheckDecIrq(dev), msecs_to_jiffies(200));
+	ret = wait_event_timeout(dec_wait_queue, CheckDecIrq(dev), msecs_to_jiffies(200));
+	if (ret == -ERESTARTSYS) {
+		pr_err("DEC[%d]  failed to wait_event_interruptible interrupted\n", dev->core_id);
+		return -ERESTARTSYS;
+	} else if (ret == 0) {
+		pr_err("DEC[%d]  wait_event_interruptible timeout\n", dev->core_id);
+		dev->timeout = 1;
+	}
+
+	atomic_inc(&dev->irq_tx);
+
+	/* refresh registers */
+	return DecRefreshRegs(dev, Core);
+}
+
+static long PPFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long ret = 0;
+	//u32 id = Core->id;
+	u32 i;
+
+	/* copy original dec regs to kernal space*/
+	ret = copy_from_user(dev->dec_regs + HANTRO_PP_ORG_FIRST_REG,
+			Core->regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+	/* copy extended dec regs to kernal space*/
+	ret = copy_from_user(dev->dec_regs + HANTRO_PP_EXT_FIRST_REG,
+			Core->regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS*4);
+#endif
+	if (ret) {
+		pr_err("copy_from_user failed, returned %li\n", ret);
+		return -EFAULT;
+	}
+
+	/* write all regs but the status reg[1] to hardware */
+	/* both original and extended regs need to be written */
+	for (i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+		iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+	for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+		iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#endif
+	/* write the stat reg, which may start the PP */
+	iowrite32(dev->dec_regs[HANTRO_PP_ORG_FIRST_REG],
+	dev->hwregs + HANTRO_PP_ORG_FIRST_REG * 4);
+
+	return 0;
+}
+
+static long PPRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	long i, ret;
+	//u32 id = Core->id;
+#ifdef USE_64BIT_ENV
+	/* user has to know exactly what they are asking for */
+	if (Core->size != (HANTRO_PP_TOTAL_REGS * 4))
+		return -EFAULT;
+#else
+	/* user has to know exactly what they are asking for */
+	if (Core->size != (HANTRO_PP_ORG_REGS * 4))
+		return -EFAULT;
+#endif
+
+	/* read all registers from hardware */
+	/* both original and extended regs need to be read */
+	for (i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+		dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+	for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+		dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#endif
+	/* put registers to user space*/
+	/* put original registers to user space*/
+	ret = copy_to_user(Core->regs + HANTRO_PP_ORG_FIRST_REG,
+			dev->dec_regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+	/* put extended registers to user space*/
+	ret = copy_to_user(Core->regs + HANTRO_PP_EXT_FIRST_REG,
+			dev->dec_regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS * 4);
+#endif
+	if (ret) {
+		pr_err("copy_to_user failed, returned %li\n", ret);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev)
+{
+	unsigned long flags;
+	int rdy = 0;
+
+	const u32 irq_mask = (1 << dev->core_id);
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	if (pp_irq & irq_mask) {
+		/* reset the wait condition(s) */
+		pp_irq &= ~irq_mask;
+		rdy = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return rdy;
+}
+
+static long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+	//u32 id = Core->id;
+
+	PDEBUG("wait_event_interruptible PP[%d]\n", dev->core_id);
+
+	if (wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev))) {
+		pr_err("PP[%d]  failed to wait_event_interruptible interrupted\n", dev->core_id);
+		return -ERESTARTSYS;
+	}
+
+	atomic_inc(&dev->irq_tx);
+
+	/* refresh registers */
+	return PPRefreshRegs(dev, Core);
+}
+
+static int CheckCoreIrq(const struct file *filp, int *id)
+{
+	unsigned long flags;
+	int rdy = 0, n = 0;
+	hantrodec_t *dev;
+
+	do {
+		u32 irq_mask;
+
+		dev = &hantrodec_data[n];
+		irq_mask = (1 << dev->core_id);
+
+		spin_lock_irqsave(&owner_lock, flags);
+
+		if (dec_irq & irq_mask) {
+			if (dev->dec_owner == filp) {
+				/* we have an IRQ for our client */
+
+				/* reset the wait condition(s) */
+				dec_irq &= ~irq_mask;
+
+				/* signal ready Core no. for our client */
+				*id = dev->core_id;
+
+				rdy = 1;
+
+				spin_unlock_irqrestore(&owner_lock, flags);
+				break;
+			} else if (dev->dec_owner == NULL) {
+				/* zombie IRQ */
+				pr_info("IRQ on Core[%d], but no owner!!!\n", n);
+
+				/* reset the wait condition(s) */
+				dec_irq &= ~irq_mask;
+			}
+		}
+
+		spin_unlock_irqrestore(&owner_lock, flags);
+
+		n++; /* next Core */
+	} while (n < cores);
+
+	return rdy;
+}
+
+static long WaitCoreReady(const struct file *filp, int *id)
+{
+	PDEBUG("wait_event_interruptible CORE\n");
+
+	if (wait_event_interruptible(dec_wait_queue, CheckCoreIrq(filp, id))) {
+		pr_err("CORE  failed to wait_event_interruptible interrupted\n");
+		return -ERESTARTSYS;
+	}
+
+	atomic_inc(&hantrodec_data[*id].irq_tx);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *Function name   : hantrodec_ioctl
+ *Description     : communication method to/from the user space
+ *
+ *Return type     : long
+ *-------------------------------------------------------------------------
+ */
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	long tmp;
+
+	PDEBUG("ioctl cmd 0x%08x\n", cmd);
+	/*
+	 * extract the type and number bitfields, and don't decode
+	 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+	 */
+	if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC)
+		return -ENOTTY;
+	if (_IOC_NR(cmd) > HANTRODEC_IOC_MAXNR)
+		return -ENOTTY;
+
+	/*
+	 * the direction is a bitmask, and VERIFY_WRITE catches R/W
+	 * transfers. `Type' is user-oriented, while
+	 * access_ok is kernel-oriented, so the concept of "read" and
+	 * "write" is reversed
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+
+	if (err)
+		return -EFAULT;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HANTRODEC_IOC_CLI): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= cores)
+			return -EFAULT;
+		disable_irq(hantrodec_data[id].irq);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOC_STI): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= cores)
+			return -EFAULT;
+		enable_irq(hantrodec_data[id].irq);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCGHWOFFSET): {
+		__u32 id;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= cores)
+			return -EFAULT;
+
+		__put_user(multicorebase[id], (unsigned long *) arg);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCGHWIOSIZE): {
+		__u32 id;
+		__u32 io_size;
+
+		__get_user(id, (__u32 *)arg);
+		if (id >= cores)
+			return -EFAULT;
+		io_size = hantrodec_data[id].iosize;
+		__put_user(io_size, (u32 *) arg);
+
+		return 0;
+	}
+	case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS): {
+		tmp = copy_to_user((u64 *) arg, multicorebase, sizeof(multicorebase));
+		if (err) {
+			pr_err("copy_to_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+		__put_user(cores, (unsigned int *) arg);
+		PDEBUG("hantrodec_data.cores=%d\n", cores);
+		break;
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		DecFlushRegs(&hantrodec_data[Core.id], &Core);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		PPFlushRegs(&hantrodec_data[Core.id], &Core);
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		return DecRefreshRegs(&hantrodec_data[Core.id], &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG): {
+		struct core_desc Core;
+
+		/* get registers from user space*/
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		return PPRefreshRegs(&hantrodec_data[Core.id], &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCH_DEC_RESERVE): {
+		int id;
+
+		PDEBUG("Reserve DEC Core, format = %li\n", arg);
+		id = GetDecCoreID(arg);
+		if (id < 0) {
+			pr_err("invalid format: %ld\n", arg);
+			return -EFAULT;
+		}
+		return ReserveDecoder(&hantrodec_data[id], filp, arg);
+	}
+	case _IOC_NR(HANTRODEC_IOCT_DEC_RELEASE): {
+		if (arg >= cores || hantrodec_data[arg].dec_owner != filp) {
+			pr_err("bogus DEC release, Core = %li\n", arg);
+			return -EFAULT;
+		}
+
+		PDEBUG("Release DEC, Core = %li\n", arg);
+
+		ReleaseDecoder(&hantrodec_data[arg]);
+
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCQ_PP_RESERVE):
+		return ReservePostProcessor(&hantrodec_data[0], filp);
+	case _IOC_NR(HANTRODEC_IOCT_PP_RELEASE): {
+		if (arg != 0 || hantrodec_data[arg].pp_owner != filp) {
+			pr_err("bogus PP release %li\n", arg);
+			return -EFAULT;
+		}
+
+		ReleasePostProcessor(&hantrodec_data[arg]);
+
+		break;
+	}
+	case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT): {
+		struct core_desc Core;
+
+		/* get registers from user space */
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		return WaitDecReadyAndRefreshRegs(&hantrodec_data[Core.id], &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCX_PP_WAIT): {
+		struct core_desc Core;
+
+		/* get registers from user space */
+		tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+		if (tmp) {
+			pr_err("copy_from_user failed, returned %li\n", tmp);
+			return -EFAULT;
+		}
+
+		if (Core.id >= cores)
+			return -EFAULT;
+
+		return WaitPPReadyAndRefreshRegs(&hantrodec_data[Core.id], &Core);
+	}
+	case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT): {
+		int id;
+
+		tmp = WaitCoreReady(filp, &id);
+		__put_user(id, (int *) arg);
+		return tmp;
+	}
+	case _IOC_NR(HANTRODEC_IOX_ASIC_ID): {
+		u32 id;
+
+		__get_user(id, (u32 *)arg);
+		if (id >= cores)
+			return -EFAULT;
+		id = ioread32(hantrodec_data[id].hwregs);
+		__put_user(id, (u32 *) arg);
+		return 0;
+	}
+	case _IOC_NR(HANTRODEC_IOCG_CORE_ID): {
+		int id;
+		hantrodec_instance *ctx = (hantrodec_instance *)filp->private_data;
+
+		PDEBUG("Get DEC Core_id, format = %li\n", arg);
+		id = GetDecCoreID(arg);
+		if ((ctx->core_id == 3) && (id >= 0)) {
+			if (id == 0) {
+				ctx->core_id = 1; //g1
+				/*power off g2*/
+				pm_runtime_put_sync(hantrodec_data[1].dev);
+				hantro_clk_disable(&hantrodec_data[1].clk);
+			} else if (id == 1) {
+				ctx->core_id = 2; //g2
+				/*power off g1*/
+				pm_runtime_put_sync(hantrodec_data[0].dev);
+				hantro_clk_disable(&hantrodec_data[0].clk);
+			}
+		}
+		return id;
+	}
+	case _IOC_NR(HANTRODEC_DEBUG_STATUS): {
+		PDEBUG("hantrodec: dec_irq     = 0x%08x\n", dec_irq);
+		PDEBUG("hantrodec: pp_irq      = 0x%08x\n", pp_irq);
+
+		//PDEBUG("hantrodec: IRQs received/sent2user = %d / %d\n",
+		//atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+		for (tmp = 0; tmp < cores; tmp++) {
+			PDEBUG("hantrodec: Core %ld IRQs received/sent2user = %d / %d\n", tmp,
+				atomic_read(&hantrodec_data[tmp].irq_rx), atomic_read(&hantrodec_data[tmp].irq_tx));
+
+			PDEBUG("hantrodec: dec_core[%li] %s\n",
+					tmp, hantrodec_data[tmp].dec_owner == NULL ? "FREE" : "RESERVED");
+			PDEBUG("hantrodec: pp_core[%li]  %s\n",
+					tmp, hantrodec_data[tmp].pp_owner == NULL ? "FREE" : "RESERVED");
+		}
+		break;
+	}
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct core_desc_32 {
+	__u32 id; /* id of the Core */
+	compat_caddr_t regs; /* pointer to user registers */
+	__u32 size; /* size of register space */
+};
+
+static int get_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+	u32 tmp;
+
+	if (!access_ok(up, sizeof(struct core_desc_32)) ||
+				get_user(kp->id, &up->id) ||
+				get_user(kp->size, &up->size) ||
+				get_user(tmp, &up->regs)) {
+		return -EFAULT;
+	}
+	kp->regs = (__force u32 *)compat_ptr(tmp);
+	return 0;
+}
+
+static int put_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->regs);
+
+	if (!access_ok(up, sizeof(struct core_desc_32)) ||
+				put_user(kp->id, &up->id) ||
+				put_user(kp->size, &up->size) ||
+				put_user(tmp, &up->regs)) {
+		return -EFAULT;
+	}
+	return 0;
+}
+static long hantrodec_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+#define HANTRO_IOCTL32(err, filp, cmd, arg) { \
+		mm_segment_t old_fs = get_fs(); \
+		set_fs(KERNEL_DS); \
+		err = hantrodec_ioctl(filp, cmd, arg); \
+		if (err) \
+			return err; \
+		set_fs(old_fs); \
+	}
+
+	union {
+		struct core_desc kcore;
+		unsigned long kux;
+		unsigned int kui;
+	} karg;
+	void __user *up = compat_ptr(arg);
+	long err = 0;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HANTRODEC_IOCGHWOFFSET):
+	case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS):
+		err = get_user(karg.kux, (s32 __user *)up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kux), (s32 __user *)up);
+		break;
+	case _IOC_NR(HANTRODEC_IOCGHWIOSIZE):
+	case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+	case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT):
+	case _IOC_NR(HANTRODEC_IOX_ASIC_ID):
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG):
+	case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG):
+	case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT):
+	case _IOC_NR(HANTRODEC_IOCX_PP_WAIT):
+	case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG):
+	case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG):
+		err = get_hantro_core_desc32(&karg.kcore, up);
+		if (err)
+			return err;
+		HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_hantro_core_desc32(&karg.kcore, up);
+		break;
+	default:
+		err = hantrodec_ioctl(filp, cmd, (unsigned long)up);
+		break;
+	}
+
+	return err;
+}
+
+#endif //ifdef CONFIG_COMPAT
+
+/*--------------------------------------------------------------------------
+ *Function name   : hantrodec_open
+ *Description     : open method
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_open(struct inode *inode, struct file *filp)
+{
+	int i;
+	int idx;
+
+	idx = hantro_new_instance();
+	if (idx < 0)
+		return -ENOMEM;
+
+	PDEBUG("dev opened: id: %d\n", idx);
+	hantrodec_ctx[idx].core_id = 3;  //unknow
+	hantrodec_ctx[idx].inst_id = idx;
+	filp->private_data = (void *)(&hantrodec_ctx[idx]);
+
+	/*not yet know which core id, so power on both g1 and g2 firstly*/
+	for (i = 0; i < 2; i++) {
+		hantro_clk_enable(&hantrodec_data[i].clk);
+		hantro_power_on_disirq(&hantrodec_data[i]);
+	}
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_release
+ *Description     : Release driver
+ *
+ *Return type     : int
+ *----------------------------------------------------------------------------
+ */
+static int hantrodec_release(struct inode *inode, struct file *filp)
+{
+	int n;
+	//hantrodec_t *dev = &hantrodec_data;
+	hantrodec_instance *ctx = (hantrodec_instance *)filp->private_data;
+
+	PDEBUG("closing ...\n");
+	for (n = 0; n < cores; n++) {
+		if (hantrodec_data[n].dec_owner == filp) {
+			PDEBUG("releasing dec Core %i lock\n", n);
+			ReleaseDecoder(&hantrodec_data[n]);
+		}
+	}
+
+	for (n = 0; n < 1; n++) {
+		if (hantrodec_data[n].pp_owner == filp) {
+			PDEBUG("releasing pp Core %i lock\n", n);
+			ReleasePostProcessor(&hantrodec_data[n]);
+		}
+	}
+
+	if (ctx->core_id & 0x1) {
+		pm_runtime_put_sync(hantrodec_data[0].dev);
+		hantro_clk_disable(&hantrodec_data[0].clk);
+	}
+	if (ctx->core_id & 0x2) {
+		pm_runtime_put_sync(hantrodec_data[1].dev);
+		hantro_clk_disable(&hantrodec_data[1].clk);
+	}
+	hantro_free_instance(ctx->inst_id);
+
+	PDEBUG("closed: id: %d\n", n);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantro_mmap
+ *Description     : memory map interface for hantro file operation
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int hantro_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+	if (vm->vm_pgoff == (multicorebase[0] >> PAGE_SHIFT) || vm->vm_pgoff == (multicorebase[1] >> PAGE_SHIFT)) {
+		vm->vm_flags |= VM_IO;
+		vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+		PDEBUG("hantro mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+		return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+						vm->vm_page_prot) ? -EAGAIN : 0;
+	}	else {
+		pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+		return -EINVAL;
+	}
+}
+
+/* VFS methods */
+static const struct file_operations hantrodec_fops = {
+	.owner = THIS_MODULE,
+	.open = hantrodec_open,
+	.release = hantrodec_release,
+	.unlocked_ioctl = hantrodec_ioctl,
+	.fasync = NULL,
+	.mmap = hantro_mmap,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = hantrodec_ioctl32,
+#endif
+};
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_init
+ *Description     : Initialize the driver
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_init(struct platform_device *pdev, int id)
+{
+	int result;
+	int irq;
+	struct device *temp_class;
+
+	//dec_irq = 0;
+	//pp_irq = 0;
+	pr_debug("hantrodec: Init multi Core[0] at 0x%16lx\n"
+			"                     Core[1] at 0x%16lx\n", multicorebase[0], multicorebase[1]);
+
+	//hantrodec_data.cores = 0;
+	//hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+	//hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+
+	//hantrodec_data.async_queue_dec = NULL;
+	//hantrodec_data.async_queue_pp = NULL;
+
+	hantrodec_data[id].iosize = (id == 0) ? DEC_IO_SIZE_0 : DEC_IO_SIZE_1;
+
+	if (!hantrodec_major) {
+		dec_irq = 0;
+		pp_irq = 0;
+
+		result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+		if (result < 0) {
+			pr_err("hantrodec: unable to get major %d\n", hantrodec_major);
+			goto err;
+		} else if (result != 0) { /* this is for dynamic major */
+			hantrodec_major = result;
+		}
+
+		hantro_class = class_create(THIS_MODULE, "mxc_hantro_845");
+		if (IS_ERR(hantro_class)) {
+			result = -1;
+			goto err;
+		}
+		temp_class = device_create(hantro_class, NULL, MKDEV(hantrodec_major, 0), NULL, DEVICE_NAME);
+		if (IS_ERR(temp_class)) {
+			result = -1;
+			goto err_out_class;
+		}
+	}
+
+	result = ReserveIO(id);
+	if (result < 0)
+		goto err;
+
+	hantrodec_data[id].dec_owner = 0;
+	hantrodec_data[id].pp_owner = 0;
+
+	sema_init(&hantrodec_data[id].dec_core_sem, 1);
+	sema_init(&hantrodec_data[id].pp_core_sem, 1);
+
+	/* read configuration fo all cores */
+	ReadCoreConfig(&hantrodec_data[id]);
+
+	/* reset hardware */
+	ResetAsic(&hantrodec_data[id]);
+
+	/* register irq for each core*/
+	irq = platform_get_irq_byname(pdev, "irq_hantro");
+	if (irq > 0) {
+		hantrodec_data[id].irq = irq;
+		result = request_irq(irq, hantrodec_isr, IRQF_SHARED,
+				"hantrodec", (void *) &hantrodec_data[id]);
+
+		if (result != 0) {
+			if (result == -EINVAL)
+				pr_err("hantrodec: Bad irq number or handler\n");
+			else if (result == -EBUSY) {
+				pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+				hantrodec_data[id].irq);
+			}
+			ReleaseIO(id);
+			goto err;
+		}
+	}	else {
+		pr_err("hantrodec: IRQ0 not in use!\n");
+		goto err;
+	}
+
+	hantrodec_data[id].irq_rx.counter = 0;
+	hantrodec_data[id].irq_tx.counter = 0;
+	irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+	pr_info("hantrodec %d : module inserted. Major = %d\n", id, hantrodec_major);
+
+	return 0;
+
+err_out_class:
+	device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+	class_destroy(hantro_class);
+err:
+	pr_err("hantrodec: module not inserted\n");
+	unregister_chrdev(hantrodec_major, "hantrodec");
+	return result;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_cleanup
+ *Description     : clean up
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static void hantrodec_cleanup(int id)
+{
+	hantrodec_t *dev = &hantrodec_data[id];
+	//int n = 0;
+	/* reset hardware */
+	ResetAsic(dev);
+
+	/* free the IRQ */
+	//for (n = 0; n < dev->cores; n++) {
+		if (dev->irq != -1)
+			free_irq(dev->irq, (void *) dev);
+	//}
+
+	ReleaseIO(id);
+
+	//unregister_chrdev(hantrodec_major, "hantrodec");
+
+	PDEBUG("hantrodec: module removed\n");
+
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : CheckHwId
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int CheckHwId(hantrodec_t *dev)
+{
+	long int hwid;
+	//int i;
+	size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+	int found = 0;
+
+	//for (i = 0; i < cores; i++) {
+		if (dev->hwregs != NULL) {
+			hwid = readl(dev->hwregs);
+			pr_debug("hantrodec: Core %d HW ID=0x%16lx\n", dev->core_id, hwid);
+			hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+			while (num_hw--) {
+				if (hwid == DecHwId[num_hw]) {
+					pr_debug("hantrodec: Supported HW found at 0x%16lx\n",
+							multicorebase[dev->core_id]);
+					found++;
+					dev->hw_id = hwid;
+					break;
+				}
+			}
+			if (!found) {
+				pr_err("hantrodec: Unknown HW found at 0x%16lx\n",	multicorebase[dev->core_id]);
+				return 0;
+			}
+			found = 0;
+			num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+		}
+	//}
+
+	return 1;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : ReserveIO
+ *Description     : IO reserve
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int ReserveIO(int i)
+{
+	//int i;
+
+	//for (i = 0; i < HXDEC_MAX_CORES; i++) {
+		if (multicorebase[i] != -1) {
+			if (!request_mem_region(multicorebase[i], hantrodec_data[i].iosize, "hantrodec0")) {
+				pr_err("hantrodec: failed to reserve HW regs, %d, base: 0x%lX, %d\n", i, multicorebase[i], hantrodec_data[i].iosize);
+				return -EBUSY;
+			}
+
+			hantrodec_data[i].hwregs = (volatile u8 *) ioremap_nocache(multicorebase[i],
+			hantrodec_data[i].iosize);
+
+			if (hantrodec_data[i].hwregs == NULL) {
+				pr_err("hantrodec: failed to ioremap HW regs\n");
+				ReleaseIO(i);
+				return -EBUSY;
+			}
+			//hantrodec_data.cores++;
+		}
+	//}
+
+	/* check for correct HW */
+	if (!CheckHwId(&hantrodec_data[i])) {
+		ReleaseIO(i);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : releaseIO
+ *Description     : release
+ *
+ *Return type     : void
+ *---------------------------------------------------------------------------
+ */
+static void ReleaseIO(int i)
+{
+	//int i;
+
+	//for (i = 0; i < hantrodec_data.cores; i++) {
+		if (hantrodec_data[i].hwregs)
+			iounmap((void *) hantrodec_data[i].hwregs);
+		release_mem_region(multicorebase[i], hantrodec_data[i].iosize);
+	//}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_isr
+ *Description     : interrupt handler
+ *
+ *Return type     : irqreturn_t
+ *---------------------------------------------------------------------------
+ */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id)
+{
+	unsigned long flags;
+	unsigned int handled = 0;
+	//int i;
+	volatile u8 *hwregs;
+
+	hantrodec_t *dev = (hantrodec_t *) dev_id;
+	u32 irq_status_dec;
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	//for (i = 0; i < cores; i++) {
+		hwregs = dev->hwregs;
+
+		/* interrupt status register read */
+		irq_status_dec = ioread32(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+		if (irq_status_dec & HANTRODEC_DEC_IRQ) {
+			/* clear dec IRQ */
+			irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+			iowrite32(irq_status_dec, hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+			PDEBUG("decoder IRQ received! Core %d\n", dev->core_id);
+			dev->hw_active = 0;
+
+			atomic_inc(&hantrodec_data[dev->core_id].irq_rx);
+
+			dec_irq |= (1 << dev->core_id);
+
+			//wake_up_interruptible_all(&dec_wait_queue);
+			wake_up_all(&dec_wait_queue);
+			handled++;
+		}
+	//}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	if (!handled)
+		pr_info("IRQ received, but not hantrodec's!\n");
+
+	(void)hwregs;
+	return IRQ_RETVAL(handled);
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : ResetAsic
+ *Description     : reset asic
+ *
+ *Return type     :
+ *---------------------------------------------------------------------------
+ */
+static void ResetAsic(hantrodec_t *dev)
+{
+	int i;
+	u32 status;
+
+	//for (j = 0; j < dev->cores; j++) {
+		status = ioread32(dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+		if (status & HANTRODEC_DEC_E) {
+			/* abort with IRQ disabled */
+			status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+			iowrite32(status, dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+		}
+
+		if (IS_G1(dev->hw_id))
+			/* reset PP */
+			iowrite32(0, dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+
+		for (i = 4; i < dev->iosize; i += 4)
+			iowrite32(0, dev->hwregs + i);
+	//}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : dump_regs
+ *Description     : Dump registers
+ *
+ *Return type     :
+ *---------------------------------------------------------------------------
+ */
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev)
+{
+	int i, c;
+
+	PDEBUG("Reg Dump Start\n");
+	for (c = 0; c < dev->cores; c++) {
+		for (i = 0; i < dev->iosize[c]; i += 4*4) {
+			PDEBUG("\toffset %04X: %08X  %08X  %08X  %08X\n", i,
+			ioread32(dev->hwregs[c] + i),
+			ioread32(dev->hwregs[c] + i + 4),
+			ioread32(dev->hwregs[c] + i + 8),
+			ioread32(dev->hwregs[c] + i + 12));
+		}
+	}
+	PDEBUG("Reg Dump End\n");
+}
+#endif
+
+static int hantro_dev_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct resource *res;
+	unsigned long reg_base;
+	int id;
+
+	id = hantro_device_id(&pdev->dev);
+	if (id < 0)
+		return -ENODEV;
+
+	hantrodec_data[id].dev = &pdev->dev;
+	hantrodec_data[id].core_id = id;
+	platform_set_drvdata(pdev, &hantrodec_data[id]);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro");
+	if (!res) {
+		pr_err("hantro: unable to get vpu base addr\n");
+		return -ENODEV;
+	}
+	reg_base = res->start;
+	if ((ulong)reg_base != multicorebase[id]) {
+		pr_err("hantrodec %d: regbase(0x%lX) not equal to expected value(0x%lX)\n", id, reg_base, multicorebase[id]);
+		return -ENODEV;
+	}
+
+	hantrodec_data[id].clk.dec = clk_get(&pdev->dev, "clk_hantro");
+	hantrodec_data[id].clk.bus = clk_get(&pdev->dev, "clk_hantro_bus");
+	if (IS_ERR(hantrodec_data[id].clk.dec) || IS_ERR(hantrodec_data[id].clk.bus)) {
+		pr_err("hantro: get clock failed\n");
+		return -ENODEV;
+	}
+	pr_debug("hantro: dec, bus clock: 0x%lX, 0x%lX\n", clk_get_rate(hantrodec_data[id].clk.dec),
+				clk_get_rate(hantrodec_data[id].clk.bus));
+
+	hantro_clk_enable(&hantrodec_data[id].clk);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	hantro_ctrlblk_reset(&hantrodec_data[id]);
+
+	err = hantrodec_init(pdev, id);
+	if (err != 0) {
+		pr_err("hantro: hantrodec_init failed\n");
+		goto error;
+	}
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+	HANTRO_REG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+	thermal_event = 0;
+	hantro_dynamic_clock = 0;
+	hantrodec_data[id].thermal_cur = 0;
+#endif
+	hantrodec_data[id].timeout = 0;
+	mutex_init(&hantrodec_data[id].dev_mutex);
+	instance_mask = 0;
+
+	goto out;
+
+error:
+	pr_err("hantro probe failed\n");
+out:
+	pm_runtime_put_sync(&pdev->dev);
+	hantro_clk_disable(&hantrodec_data[id].clk);
+	return err;
+}
+
+static int hantro_dev_remove(struct platform_device *pdev)
+{
+	hantrodec_t *dev = platform_get_drvdata(pdev);
+
+	hantro_clk_enable(&dev->clk);
+	pm_runtime_get_sync(&pdev->dev);
+	hantrodec_cleanup(dev->core_id);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	hantro_clk_disable(&dev->clk);
+	if (!IS_ERR(dev->clk.dec))
+		clk_put(dev->clk.dec);
+	if (!IS_ERR(dev->clk.bus))
+		clk_put(dev->clk.bus);
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+	HANTRO_UNREG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int __maybe_unused hantro_suspend(struct device *dev)
+{
+	hantrodec_t *hantrodev = dev_get_drvdata(dev);
+
+	if (hantrodev->dec_owner) {
+		/* polling until hw is idle */
+		while (hantrodev->hw_active) {
+			pr_info("DEC[%d] is still in active when suspend !\n", hantrodev->core_id);
+			usleep_range(5000, 10000);
+		}
+		/* let's backup all registers from H/W to shadow register to support suspend */
+		DecStoreRegs(hantrodev);
+	}
+
+	pm_runtime_put_sync_suspend(dev);   //power off
+	return 0;
+}
+static int __maybe_unused hantro_resume(struct device *dev)
+{
+	hantrodec_t *hantrodev = dev_get_drvdata(dev);
+
+	hantro_power_on_disirq(hantrodev);
+	hantro_ctrlblk_reset(hantrodev);
+
+	if (hantrodev->dec_owner) {
+		/* let's restore registers from shadow register to H/W to support resume */
+		DecRestoreRegs(hantrodev);
+	}
+
+	return 0;
+}
+static int hantro_runtime_suspend(struct device *dev)
+{
+	release_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static int hantro_runtime_resume(struct device *dev)
+{
+	hantrodec_t *hantrodev = dev_get_drvdata(dev);
+
+	request_bus_freq(BUS_FREQ_HIGH);
+	hantro_ctrlblk_reset(hantrodev);
+	return 0;
+}
+
+static const struct dev_pm_ops hantro_pm_ops = {
+	SET_RUNTIME_PM_OPS(hantro_runtime_suspend, hantro_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(hantro_suspend, hantro_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_of_match[] = {
+	{ .compatible = "nxp,imx8mm-hantro", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, hantro_of_match);
+
+
+static struct platform_driver mxchantro_driver = {
+	.driver = {
+	.name = "mxc_hantro_845",
+	.of_match_table = hantro_of_match,
+#ifdef CONFIG_PM
+	.pm = &hantro_pm_ops,
+#endif
+	},
+	.probe = hantro_dev_probe,
+	.remove = hantro_dev_remove,
+};
+
+static int __init hantro_init(void)
+{
+	int ret = platform_driver_register(&mxchantro_driver);
+
+	return ret;
+}
+
+static void __exit hantro_exit(void)
+{
+	platform_driver_unregister(&mxchantro_driver);
+	if (hantrodec_major > 0) {
+		device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+		class_destroy(hantro_class);
+		unregister_chrdev(hantrodec_major, "hantrodec");
+		hantrodec_major = 0;
+	}
+}
+
+module_init(hantro_init);
+module_exit(hantro_exit);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Driver module for Hantro Decoder/Post-Processor");
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845_h1/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/hantro_845_h1/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) encoder support"
+	depends on ARCH_MXC
+
+config MXC_HANTRO_845_H1
+	tristate "Support for MXC HANTRO(Video Processing Unit) encoder"
+	default y
+	---help---
+	  VPU codec device.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845_h1/Makefile
+++ linux-ein-5.4.0/drivers/mxc/hantro_845_h1/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+#ccflags-y += -I$(PWD)
+
+obj-$(CONFIG_MXC_HANTRO_845_H1) += hx280enc.o
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845_h1/hx280enc.c
+++ linux-ein-5.4.0/drivers/mxc/hantro_845_h1/hx280enc.c
@@ -0,0 +1,924 @@
+/*
+ * Encoder device driver (kernel module)
+ *
+ * Copyright (c) 2013-2019, VeriSilicon Inc.
+ * Copyright (C) 2012 Google Finland Oy.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+--------------------------------------------------------------------------------
+--
+--  Abstract : 6280/7280/8270/8290/H1 Encoder device driver (kernel module)
+--
+------------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* needed for __init,__exit directives */
+#include <linux/init.h>
+/* needed for remap_page_range
+	SetPageReserved
+	ClearPageReserved
+*/
+#include <linux/mm.h>
+/* obviously, for kmalloc */
+#include <linux/slab.h>
+/* for struct file_operations, register_chrdev() */
+#include <linux/fs.h>
+/* standard error codes */
+#include <linux/errno.h>
+
+#include <linux/moduleparam.h>
+/* request_irq(), free_irq() */
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+/* needed for virt_to_phys() */
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+#include <linux/of_irq.h>
+#include <linux/version.h>
+
+/* our own stuff */
+#include <linux/hx280enc.h>
+
+#ifndef VSI
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+//static int hantro_h1_major = -1; /* dynamic allocation */
+static struct class *hantro_h1_class;
+#define DEVICE_NAME		"mxc_hantro_h1"
+static struct device *hantro_h1_dev;
+static struct clk *hantro_clk_h1;
+static struct clk *hantro_clk_h1_bus;
+#define IRQF_DISABLED 0x0
+#endif
+
+#include <linux/delay.h>
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Hantro 6280/7280/8270/8290/H1 Encoder driver");
+
+/* this is ARM Integrator specific stuff */
+#ifndef VSI
+#define INTEGRATOR_LOGIC_MODULE0_BASE   0x38320000
+#else
+#define INTEGRATOR_LOGIC_MODULE0_BASE   0xC0000000
+#endif
+#define BLK_CTL_BASE        0x38330000 //0x38320000
+/*
+#define INTEGRATOR_LOGIC_MODULE1_BASE   0xD0000000
+#define INTEGRATOR_LOGIC_MODULE2_BASE   0xE0000000
+#define INTEGRATOR_LOGIC_MODULE3_BASE   0xF0000000
+*/
+
+#define VP_PB_INT_LT                    30
+/*
+#define INT_EXPINT1                     10
+#define INT_EXPINT2                     11
+#define INT_EXPINT3                     12
+*/
+/* these could be module params in the future */
+
+#define ENC_IO_BASE                 INTEGRATOR_LOGIC_MODULE0_BASE
+#define ENC_IO_SIZE                 (500 * 4)    /* bytes */
+
+#define ENC_HW_ID1                  0x62800000
+#define ENC_HW_ID2                  0x72800000
+#define ENC_HW_ID3                  0x82700000
+#define ENC_HW_ID4                  0x82900000
+#define ENC_HW_ID5                  0x48310000
+
+#define HX280ENC_BUF_SIZE           0
+
+static unsigned long base_port = INTEGRATOR_LOGIC_MODULE0_BASE;
+static int irq = VP_PB_INT_LT;
+
+/* for critical data access */
+static DEFINE_SPINLOCK(owner_lock);
+/* for irq wait */
+static DECLARE_WAIT_QUEUE_HEAD(enc_wait_queue);
+/* for reserve hw */
+static DECLARE_WAIT_QUEUE_HEAD(enc_hw_queue);
+
+/* module_param(name, type, perm) */
+module_param(base_port, ulong, 0644);
+module_param(irq, int, 0644);
+
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
+static int hx280enc_major;
+
+/* here's all the must remember stuff */
+typedef struct {
+	u32 hw_id; //hw id to indicate project
+	u32 is_valid; //indicate this core is hantro's core or not
+	u32 is_reserved; //indicate this core is occupied by user or not
+	int pid; //indicate which process is occupying the core
+	u32 irq_received; //indicate this core receives irq
+	u32 irq_status;
+	int irq;
+	unsigned long iobaseaddr;
+	unsigned int iosize;
+
+	volatile u8 *hwregs;
+	struct fasync_struct *async_queue;
+	unsigned int mirror_regs[512];
+	struct device *dev;
+	struct mutex dev_mutex;
+} hx280enc_t;
+
+/* dynamic allocation? */
+static hx280enc_t hx280enc_data;
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+static void ResetAsic(hx280enc_t *dev);
+
+#ifdef HX280ENC_DEBUG
+static void dump_regs(unsigned long data);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hx280enc_isr(int irq, void *dev_id);
+
+#ifndef VSI
+static int hantro_h1_clk_enable(struct device *dev)
+{
+	clk_prepare(hantro_clk_h1);
+	clk_enable(hantro_clk_h1);
+	clk_prepare(hantro_clk_h1_bus);
+	clk_enable(hantro_clk_h1_bus);
+	return 0;
+}
+
+static int hantro_h1_clk_disable(struct device *dev)
+{
+	if (hantro_clk_h1) {
+		clk_disable(hantro_clk_h1);
+		clk_unprepare(hantro_clk_h1);
+	}
+	if (hantro_clk_h1_bus) {
+		clk_disable(hantro_clk_h1_bus);
+		clk_unprepare(hantro_clk_h1_bus);
+	}
+	return 0;
+}
+
+static int hantro_h1_ctrlblk_reset(struct device *dev)
+{
+	volatile u8 *iobase;
+	u32 val;
+
+	//config H1
+	hantro_h1_clk_enable(dev);
+	iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+
+	val = ioread32(iobase);
+	val &= (~0x4);
+	iowrite32(val, iobase); // assert soft reset
+	udelay(2);
+
+	val = ioread32(iobase);
+	val |= 0x4;
+	iowrite32(val, iobase); // release soft reset
+
+	val = ioread32(iobase+0x4);
+	val |= 0x4;
+	iowrite32(val, iobase + 0x4); // enable clock
+
+	iowrite32(0xFFFFFFFF, iobase + 0x14); // H1 fuse encoder enable
+	iounmap(iobase);
+	hantro_h1_clk_disable(dev);
+	return 0;
+}
+
+static int hantro_h1_power_on_disirq(hx280enc_t *hx280enc)
+{
+	//spin_lock_irq(&owner_lock);
+	mutex_lock(&hx280enc->dev_mutex);
+	disable_irq(hx280enc->irq);
+	pm_runtime_get_sync(hx280enc->dev);
+	enable_irq(hx280enc->irq);
+	mutex_unlock(&hx280enc->dev_mutex);
+	//spin_unlock_irq(&owner_lock);
+	return 0;
+}
+
+#endif
+
+/* the device's mmap method. The VFS has kindly prepared the process's
+ * vm_area_struct for us, so we examine this to see what was requested.
+ */
+
+static int hx280enc_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+#ifdef VSI
+	int result = -EINVAL;
+
+	result = -EINVAL;
+	vma->vm_ops = &hx280enc_vm_ops;
+	return result;
+#else
+	if (vm->vm_pgoff == (hx280enc_data.iobaseaddr >> PAGE_SHIFT)) {
+		vm->vm_flags |= VM_IO;
+		vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+		PDEBUG("hx280enc mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+		return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+						vm->vm_page_prot) ? -EAGAIN : 0;
+	} else {
+		pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+		return -EINVAL;
+	}
+#endif
+}
+
+static int CheckEncIrq(hx280enc_t *dev)
+{
+	unsigned long flags;
+	int rdy = 0;
+
+	spin_lock_irqsave(&owner_lock, flags);
+
+	if (dev->irq_received) {
+		/* reset the wait condition(s) */
+		PDEBUG("check irq ready\n");
+		dev->irq_received = 0;
+		rdy = 1;
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+	//printk("rdy=%d\n",rdy);
+
+	return rdy;
+}
+
+unsigned int WaitEncReady(hx280enc_t *dev)
+{
+	u32 irq_status, is_write1_clr;
+	int i;
+	long ret;
+
+	PDEBUG("%s\n", __func__);
+	ret = wait_event_timeout(enc_wait_queue, CheckEncIrq(dev), msecs_to_jiffies(200));
+	if (ret == 0) {
+		u32 reg14 = readl(dev->hwregs + 14*4);
+
+		pr_err("%s: wait_event_timeout() timeout !\n", __func__);
+		writel(reg14 & (~1), dev->hwregs + 14*4);
+	}
+
+	/* read register to mirror */
+	for (i = 0; i < dev->iosize; i += 4)
+		dev->mirror_regs[i/4] = readl(dev->hwregs + i);
+
+	/* clear the status bits */
+	is_write1_clr = (dev->mirror_regs[0x4a0/4] & 0x00800000);
+	irq_status = dev->mirror_regs[1];
+	if (is_write1_clr)
+		writel(irq_status, dev->hwregs + 0x04);
+	else
+		writel(irq_status & (~0xf7d), dev->hwregs + 0x04);
+
+	return 0;
+}
+
+int CheckCoreOccupation(hx280enc_t *dev)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (!dev->is_reserved) {
+		dev->is_reserved = 1;
+		dev->pid = current->pid;
+		ret = 1;
+		PDEBUG("CheckCoreOccupation pid=%d\n", dev->pid);
+	}
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return ret;
+}
+
+int GetWorkableCore(hx280enc_t *dev)
+{
+	int ret = 0;
+
+	PDEBUG("GetWorkableCore\n");
+
+	if (dev->is_valid && CheckCoreOccupation(dev))
+		ret = 1;
+
+	return ret;
+}
+
+long ReserveEncoder(hx280enc_t *dev)
+{
+	/* lock a core that has specified core id*/
+	if (wait_event_interruptible(enc_hw_queue, GetWorkableCore(dev) != 0))
+		return -ERESTARTSYS;
+
+	return 0;
+}
+
+void ReleaseEncoder(hx280enc_t *dev)
+{
+	unsigned long flags;
+
+	PDEBUG("ReleaseEncoder\n");
+
+	spin_lock_irqsave(&owner_lock, flags);
+	PDEBUG("relase reseve by pid=%d with current->pid=%d\n", dev->pid, current->pid);
+	if (dev->is_reserved && dev->pid == current->pid) {
+		dev->pid = -1;
+		dev->is_reserved = 0;
+	}
+
+	dev->irq_received = 0;
+	dev->irq_status = 0;
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	wake_up_interruptible_all(&enc_hw_queue);
+}
+
+static long EncRefreshRegs(hx280enc_t *dev, unsigned int *regs)
+{
+	long ret;
+
+	ret = copy_to_user(regs, dev->mirror_regs, dev->iosize);
+	if (ret) {
+		PDEBUG("%s: copy_to_user failed, returned %li\n", __func__, ret);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+
+static long hx280enc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+
+	PDEBUG("ioctl cmd 0x%X\n", cmd);
+	/*
+	* extract the type and number bitfields, and don't encode
+	* wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+	*/
+	if (_IOC_TYPE(cmd) != HX280ENC_IOC_MAGIC)
+		return -ENOTTY;
+	if (_IOC_NR(cmd) > HX280ENC_IOC_MAXNR)
+		return -ENOTTY;
+
+	/*
+	* the direction is a bitmask, and VERIFY_WRITE catches R/W
+	* transfers. `Type' is user-oriented, while
+	* access_ok is kernel-oriented, so the concept of "read" and
+	* "write" is reversed
+	*/
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	switch (_IOC_NR(cmd))	{
+	case _IOC_NR(HX280ENC_IOCGHWOFFSET):
+		__put_user(hx280enc_data.iobaseaddr, (unsigned long *) arg);
+		break;
+	case _IOC_NR(HX280ENC_IOCGHWIOSIZE):
+		__put_user(hx280enc_data.iosize, (unsigned int *) arg);
+	break;
+	case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+		int ret;
+
+		PDEBUG("Reserve ENC Cores\n");
+		ret = ReserveEncoder(&hx280enc_data);
+		return ret;
+	}
+	case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE):
+		PDEBUG("Release ENC Core\n");
+		ReleaseEncoder(&hx280enc_data);
+		break;
+	case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+		unsigned int *regs = (unsigned int *)arg;
+		unsigned int ret1, ret2;
+
+		ret1 = WaitEncReady(&hx280enc_data);
+		ret2 = EncRefreshRegs(&hx280enc_data, regs);
+		if (ret2)
+			return ret2;
+		if (ret1)
+			return ret1;
+		break;
+	}
+	}
+	return 0;
+}
+
+static int hx280enc_open(struct inode *inode, struct file *filp)
+{
+	int result = 0;
+	hx280enc_t *dev = &hx280enc_data;
+
+	filp->private_data = (void *) dev;
+
+#ifndef VSI
+	hantro_h1_clk_enable(dev->dev);
+	hantro_h1_power_on_disirq(dev);
+#endif
+
+	PDEBUG("dev opened\n");
+	return result;
+}
+
+static int hx280enc_release(struct inode *inode, struct file *filp)
+{
+	hx280enc_t *dev = (hx280enc_t *) filp->private_data;
+	unsigned long flags;
+#ifdef HX280ENC_DEBUG
+	dump_regs((unsigned long) dev); /* dump the regs */
+#endif
+
+	PDEBUG("dev closed\n");
+	spin_lock_irqsave(&owner_lock, flags);
+	if (dev->is_reserved == 1 && dev->pid == current->pid) {
+		dev->pid = -1;
+		dev->is_reserved = 0;
+		dev->irq_received = 0;
+		dev->irq_status = 0;
+		PDEBUG("release reserved core\n");
+	}
+	spin_unlock_irqrestore(&owner_lock, flags);
+	wake_up_interruptible_all(&enc_hw_queue);
+
+#ifndef VSI
+	pm_runtime_put_sync(hantro_h1_dev);
+	hantro_h1_clk_disable(hantro_h1_dev);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long hx280enc_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+    long err = 0;
+#define HX280ENC_IOCTL32(err, filp, cmd, arg) { \
+	mm_segment_t old_fs = get_fs(); \
+	set_fs(KERNEL_DS); \
+	err = hx280enc_ioctl(filp, cmd, arg); \
+	if (err) \
+	return err; \
+	set_fs(old_fs); \
+}
+
+union {
+    unsigned long kux;
+    unsigned int kui;
+} karg;
+    void __user *up = compat_ptr(arg);
+
+    switch (_IOC_NR(cmd))    {
+    case _IOC_NR(HX280ENC_IOCGHWOFFSET):
+		err = get_user(karg.kux, (s32 __user *)up);
+		if (err)
+		    return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kux), (s32 __user *)up);
+		break;
+    case _IOC_NR(HX280ENC_IOCGHWIOSIZE):
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+		    return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+    case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+	    int ret;
+	    PDEBUG("Reserve ENC Cores\n");
+	    ret = ReserveEncoder(&hx280enc_data);
+	    return ret;
+	}
+    case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE): {
+	    PDEBUG("Release ENC Core\n");
+	    ReleaseEncoder(&hx280enc_data);
+	    break;
+	}
+	case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)up);
+		break;
+	}
+	}
+    return 0;
+}
+#endif
+
+/* VFS methods */
+static struct file_operations hx280enc_fops = {
+	.owner = THIS_MODULE,
+	.open = hx280enc_open,
+	.release = hx280enc_release,
+	.unlocked_ioctl = hx280enc_ioctl,
+	.fasync = NULL,
+	.mmap = hx280enc_mmap,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = hx280enc_ioctl32,
+#endif
+};
+
+#ifndef VSI
+static int hx280enc_init(void)
+#else
+static int __init hx280enc_init(void)
+#endif
+{
+	int result;
+
+	PDEBUG(KERN_INFO "hx280enc: module init - base_port=0x%08lx irq=%i\n",
+	base_port, irq);
+
+	hx280enc_data.iobaseaddr = base_port;
+	hx280enc_data.iosize = ENC_IO_SIZE;
+	hx280enc_data.irq = irq;
+	hx280enc_data.async_queue = NULL;
+	hx280enc_data.hwregs = NULL;
+
+	result = register_chrdev(hx280enc_major, "hx280enc", &hx280enc_fops);
+	if (result < 0) {
+		PDEBUG(KERN_INFO "hx280enc: unable to get major <%d>\n", hx280enc_major);
+		return result;
+	} else if (result != 0)    /* this is for dynamic major */
+		hx280enc_major = result;
+
+	result = ReserveIO();
+	if (result < 0)
+		goto err;
+
+	ResetAsic(&hx280enc_data);  /* reset hardware */
+
+	/* get the IRQ line */
+	if (irq != -1) {
+		result = request_irq(irq, hx280enc_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+					SA_INTERRUPT | SA_SHIRQ,
+#else
+				//IRQF_DISABLED | IRQF_SHARED,
+				IRQF_SHARED,
+#endif
+					"hx280enc", (void *) &hx280enc_data);
+		if (result == -EINVAL) {
+			PDEBUG(KERN_ERR "hx280enc: Bad irq number or handler\n");
+			ReleaseIO();
+			goto err;
+		} else if (result == -EBUSY) {
+			PDEBUG(KERN_ERR "hx280enc: IRQ <%d> busy, change your config\n",
+			hx280enc_data.irq);
+			ReleaseIO();
+			goto err;
+		}
+	} else
+	PDEBUG(KERN_INFO "hx280enc: IRQ not in use!\n");
+	irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+
+	pr_info("hx280enc: module inserted. Major <%d>\n", hx280enc_major);
+	return 0;
+
+err:
+	unregister_chrdev(hx280enc_major, "hx280enc");
+	PDEBUG(KERN_ERR "hx280enc: module not inserted\n");
+	return result;
+}
+
+#ifndef VSI
+static void hx280enc_cleanup(void)
+#else
+static void __exit hx280enc_cleanup(void)
+#endif
+{
+	writel(0, hx280enc_data.hwregs + 0x38); /* disable HW */
+	writel(0, hx280enc_data.hwregs + 0x04); /* clear enc IRQ */
+
+	/* free the encoder IRQ */
+	if (hx280enc_data.irq != -1)
+		free_irq(hx280enc_data.irq, (void *) &hx280enc_data);
+
+	ReleaseIO();
+	unregister_chrdev(hx280enc_major, "hx280enc");
+
+	PDEBUG(KERN_INFO "hx280enc: module removed\n");
+}
+
+#ifdef VSI
+module_init(hx280enc_init);
+module_exit(hx280enc_cleanup);
+#endif
+static int ReserveIO(void)
+{
+	long int hwid;
+
+	if (!request_mem_region(hx280enc_data.iobaseaddr, hx280enc_data.iosize, "hx280enc")) {
+		PDEBUG(KERN_INFO "hx280enc: failed to reserve HW regs\n");
+		return -EBUSY;
+	}
+	hx280enc_data.hwregs = (volatile u8 *) ioremap_nocache(hx280enc_data.iobaseaddr, hx280enc_data.iosize);
+	if (hx280enc_data.hwregs == NULL)	{
+		PDEBUG(KERN_INFO "hx280enc: failed to ioremap HW regs\n");
+		ReleaseIO();
+		return -EBUSY;
+	}
+
+	hwid = readl(hx280enc_data.hwregs);
+
+	/* check for encoder HW ID */
+	if ((((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID1 >> 16) & 0xFFFF)) &&
+		(((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID2 >> 16) & 0xFFFF)) &&
+		(((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID3 >> 16) & 0xFFFF)) &&
+		(((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID4 >> 16) & 0xFFFF)) &&
+		(((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID5 >> 16) & 0xFFFF))) {
+		PDEBUG(KERN_ERR "hx280enc: HW not found at 0x%08lx\n", hx280enc_data.iobaseaddr);
+#ifdef HX280ENC_DEBUG
+		dump_regs((unsigned long) &hx280enc_data);
+#endif
+		ReleaseIO();
+		return -EBUSY;
+	}
+
+	hx280enc_data.hw_id = hwid;
+	hx280enc_data.is_valid = 1;
+
+	PDEBUG(KERN_INFO "hx280enc: HW at base <0x%08lx> with ID <0x%08lx>\n", hx280enc_data.iobaseaddr, hwid);
+	return 0;
+}
+
+static void ReleaseIO(void)
+{
+	if (hx280enc_data.is_valid == 0)
+		return;
+	if (hx280enc_data.hwregs)
+		iounmap((void *) hx280enc_data.hwregs);
+	release_mem_region(hx280enc_data.iobaseaddr, hx280enc_data.iosize);
+}
+
+irqreturn_t hx280enc_isr(int irq, void *dev_id)
+{
+	hx280enc_t *dev = (hx280enc_t *) dev_id;
+	u32 irq_status;
+	unsigned long flags;
+	u32 is_write1_clr;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (!dev->is_reserved)	{
+		spin_unlock_irqrestore(&owner_lock, flags);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&owner_lock, flags);
+	irq_status = readl(dev->hwregs + 0x04);
+
+	/* BASE_HWFuse2 = 0x4a0; HWCFGIrqClearSupport = 0x00800000 */
+	is_write1_clr = (readl(dev->hwregs + 0x4a0) & 0x00800000);
+	if (irq_status & 0x01) {
+		/* clear enc IRQ and slice ready interrupt bit */
+		if (is_write1_clr)
+			writel(irq_status & (0x101), dev->hwregs + 0x04);
+		else
+			writel(irq_status & (~0x101), dev->hwregs + 0x04);
+
+		/* Handle slice ready interrupts. The reference implementation
+		* doesn't signal slice ready interrupts to EWL.
+		* The EWL will poll the slices ready register value. */
+		if ((irq_status & 0x1FE) == 0x100) {
+			PDEBUG("Slice ready IRQ handled!\n");
+			return IRQ_HANDLED;
+		}
+
+		spin_lock_irqsave(&owner_lock, flags);
+		dev->irq_received = 1;
+		dev->irq_status = irq_status & (~0x01);
+		spin_unlock_irqrestore(&owner_lock, flags);
+
+		wake_up_all(&enc_wait_queue);
+
+		PDEBUG("IRQ handled!\n");
+		return IRQ_HANDLED;
+	} else {
+		PDEBUG("IRQ received, but NOT handled!\n");
+		return IRQ_NONE;
+	}
+}
+
+static void ResetAsic(hx280enc_t *dev)
+{
+	int i;
+
+	if (dev->is_valid == 0)
+		return;
+
+	writel(0, dev->hwregs + 0x38);
+
+	for (i = 4; i < dev->iosize; i += 4)
+		writel(0, dev->hwregs + i);
+}
+
+#ifdef HX280ENC_DEBUG
+static void dump_regs(unsigned long data)
+{
+	hx280enc_t *dev = (hx280enc_t *) data;
+	int i;
+
+	PDEBUG("Reg Dump Start\n");
+	for (i = 0; i < dev->iosize; i += 4)
+		PDEBUG("\toffset %02X = %08X\n", i, readl(dev->hwregs + i));
+	PDEBUG("Reg Dump End\n");
+}
+#endif
+
+
+
+#ifndef VSI
+static int hantro_h1_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct device *temp_class;
+	struct resource *res;
+	unsigned long reg_base;
+
+	hantro_h1_dev = &pdev->dev;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro_h1");
+	if (!res) {
+		pr_err("hantro h1: unable to get vpu base addr\n");
+		return -ENODEV;
+	}
+	reg_base = res->start;
+	if ((ulong)reg_base != base_port) {
+		pr_err("hantro h1: regbase(0x%lX) not equal to expected value(0x%lX)\n", reg_base, base_port);
+		return -ENODEV;
+	}
+
+	irq = platform_get_irq_byname(pdev, "irq_hantro_h1");
+	if (irq < 0) {
+		pr_err("hantro h1: not find valid irq\n");
+		return -ENODEV;
+	}
+
+	hantro_clk_h1 = clk_get(&pdev->dev, "clk_hantro_h1");
+	if (IS_ERR(hantro_clk_h1)) {
+		pr_err("hantro h1: get clock failed, %p\n", hantro_clk_h1);
+		err = -ENXIO;
+		goto error;
+	}
+	hantro_clk_h1_bus = clk_get(&pdev->dev, "clk_hantro_h1_bus");
+	if (IS_ERR(hantro_clk_h1_bus)) {
+		pr_err("hantro h1: get bus clock failed, %p\n", hantro_clk_h1_bus);
+		err = -ENXIO;
+		goto error;
+	}
+
+	PDEBUG("hantro: h1 clock: 0x%lX, 0x%lX\n", clk_get_rate(hantro_clk_h1), clk_get_rate(hantro_clk_h1_bus));
+
+	hantro_h1_clk_enable(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	hantro_h1_ctrlblk_reset(&pdev->dev);
+
+	err = hx280enc_init();
+	if (0 != err) {
+		pr_err("hantro h1: init failed\n");
+		goto error;
+	}
+
+	hantro_h1_class = class_create(THIS_MODULE, "mxc_hantro_h1");
+	if (IS_ERR(hantro_h1_class)) {
+		err = PTR_ERR(hantro_h1_class);
+		goto error;
+	}
+	temp_class = device_create(hantro_h1_class, NULL, MKDEV(hx280enc_major, 0), NULL, DEVICE_NAME);
+	if (IS_ERR(temp_class)) {
+		err = PTR_ERR(temp_class);
+		goto err_out_class;
+	}
+	hx280enc_data.dev = &pdev->dev;
+	platform_set_drvdata(pdev, &hx280enc_data);
+	mutex_init(&hx280enc_data.dev_mutex);
+
+	goto out;
+
+err_out_class:
+	device_destroy(hantro_h1_class, MKDEV(hx280enc_major, 0));
+	class_destroy(hantro_h1_class);
+error:
+	pr_err("hantro probe failed\n");
+out:
+	pm_runtime_put_sync(&pdev->dev);
+	hantro_h1_clk_disable(&pdev->dev);
+	return err;
+}
+
+static int hantro_h1_dev_remove(struct platform_device *pdev)
+{
+	hantro_h1_clk_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	if (hx280enc_major > 0) {
+		device_destroy(hantro_h1_class, MKDEV(hx280enc_major, 0));
+		class_destroy(hantro_h1_class);
+		hx280enc_cleanup();
+		hx280enc_major = 0;
+	}
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	hantro_h1_clk_disable(&pdev->dev);
+
+	if (!IS_ERR(hantro_clk_h1))
+		clk_put(hantro_clk_h1);
+	if (!IS_ERR(hantro_clk_h1_bus))
+		clk_put(hantro_clk_h1_bus);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int __maybe_unused hantro_h1_suspend(struct device *dev)
+{
+	pm_runtime_put_sync_suspend(dev);   //power off
+	return 0;
+}
+static int __maybe_unused hantro_h1_resume(struct device *dev)
+{
+	hx280enc_t *hx280enc = dev_get_drvdata(dev);
+
+	hantro_h1_power_on_disirq(hx280enc);
+	hantro_h1_ctrlblk_reset(dev);
+	return 0;
+}
+static int hantro_h1_runtime_suspend(struct device *dev)
+{
+	//release_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static int hantro_h1_runtime_resume(struct device *dev)
+{
+	//request_bus_freq(BUS_FREQ_HIGH);
+	hantro_h1_ctrlblk_reset(dev);
+	return 0;
+}
+
+static const struct dev_pm_ops hantro_h1_pm_ops = {
+	SET_RUNTIME_PM_OPS(hantro_h1_runtime_suspend, hantro_h1_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(hantro_h1_suspend, hantro_h1_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_h1_of_match[] = {
+	{ .compatible = "nxp,imx8mm-hantro-h1", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, hantro_h1_of_match);
+
+
+static struct platform_driver mxchantro_h1_driver = {
+	.driver = {
+	.name = "mxc_hantro_h1",
+	.of_match_table = hantro_h1_of_match,
+#ifdef CONFIG_PM
+	.pm = &hantro_h1_pm_ops,
+#endif
+	},
+	.probe = hantro_h1_probe,
+	.remove = hantro_h1_dev_remove,
+};
+
+static int __init hantro_h1_init(void)
+{
+	int ret = platform_driver_register(&mxchantro_h1_driver);
+
+	return ret;
+}
+
+static void __exit hantro_h1_exit(void)
+{
+	platform_driver_unregister(&mxchantro_h1_driver);
+}
+
+module_init(hantro_h1_init);
+module_exit(hantro_h1_exit);
+
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_845_h1/hx280enc.h
+++ linux-ein-5.4.0/drivers/mxc/hantro_845_h1/hx280enc.h
@@ -0,0 +1,82 @@
+ /*****************************************************************************
+ * Encoder device driver (kernel module header)
+ *
+ * Copyright (C) 2012 Google Finland Oy.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+--------------------------------------------------------------------------------
+--
+--  Abstract : 6280/7280/8270/8290/H1 Encoder device driver (kernel module)
+--
+*****************************************************************************/
+#ifndef _UAPI_HX280ENC_H_
+#define _UAPI_HX280ENC_H_
+#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef HX280ENC_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk(KERN_INFO "hmp4e: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+
+/*
+ * Ioctl definitions
+ */
+struct mirror_regs {
+	unsigned int regs[512]; /* pointer to user registers */
+};
+
+/* Use 'k' as magic number */
+#define HX280ENC_IOC_MAGIC  'k'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+ /*
+  * #define HX280ENC_IOCGBUFBUSADDRESS _IOR(HX280ENC_IOC_MAGIC,  1, unsigned long *)
+  * #define HX280ENC_IOCGBUFSIZE       _IOR(HX280ENC_IOC_MAGIC,  2, unsigned int *)
+  */
+#define HX280ENC_IOCGHWOFFSET      _IOR(HX280ENC_IOC_MAGIC,  3, unsigned long *)
+#define HX280ENC_IOCGHWIOSIZE      _IOR(HX280ENC_IOC_MAGIC,  4, unsigned int *)
+#define HX280ENC_IOC_CLI           _IO(HX280ENC_IOC_MAGIC,  5)
+#define HX280ENC_IOC_STI           _IO(HX280ENC_IOC_MAGIC,  6)
+#define HX280ENC_IOCXVIRT2BUS      _IOWR(HX280ENC_IOC_MAGIC,  7, unsigned long *)
+
+#define HX280ENC_IOCHARDRESET      _IO(HX280ENC_IOC_MAGIC, 8)   /* debugging tool */
+#define HX280ENC_IOCGSRAMOFFSET    _IOR(HX280ENC_IOC_MAGIC,  9, unsigned long *)
+#define HX280ENC_IOCGSRAMEIOSIZE    _IOR(HX280ENC_IOC_MAGIC,  10, unsigned int *)
+
+#define HX280ENC_IOCH_ENC_RESERVE   _IOR(HX280ENC_IOC_MAGIC, 11, unsigned int *)
+#define HX280ENC_IOCH_ENC_RELEASE   _IOR(HX280ENC_IOC_MAGIC, 12, unsigned int *)
+#define HX280ENC_IOCG_CORE_WAIT     _IOR(HX280ENC_IOC_MAGIC, 13, unsigned int *)
+#define HX280ENC_IOC_MAXNR 30
+
+#endif /* !_UAPI_HX280ENC_H_ */
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_vc8000e/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/hantro_vc8000e/Kconfig
@@ -0,0 +1,15 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) VC8000E encoder support"
+#	depends on ARCH_FSL_IMX8MP
+	depends on ARCH_MXC
+
+config MXC_HANTRO_VC8000E
+	tristate "Support for MXC HANTRO(Video Processing Unit) VC8000E encoder"
+	default y
+	---help---
+	  VPU codec device.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_vc8000e/Makefile
+++ linux-ein-5.4.0/drivers/mxc/hantro_vc8000e/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+#ccflags-y += -I$(PWD)
+
+obj-$(CONFIG_MXC_HANTRO_VC8000E) += hx280enc_vc8000e.o
+
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_vc8000e/hx280enc.h
+++ linux-ein-5.4.0/drivers/mxc/hantro_vc8000e/hx280enc.h
@@ -0,0 +1,92 @@
+/*
+ *  H2 Encoder device driver (kernel module)
+ *
+ *  COPYRIGHT(C) 2014 VERISILICON
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#ifndef _HX280ENC_H_
+#define _HX280ENC_H_
+#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */
+#ifdef HANTROMMU_SUPPORT
+#include "hantrommu.h"
+#endif
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef HX280ENC_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk(KERN_INFO "hmp4e: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+
+/*
+ * Ioctl definitions
+ */
+
+#define ENC_HW_ID1                  0x48320100
+#define ENC_HW_ID2                  0x80006000
+#define CORE_INFO_MODE_OFFSET       31
+#define CORE_INFO_AMOUNT_OFFSET     28
+
+/* Use 'k' as magic number */
+#define HX280ENC_IOC_MAGIC  'k'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+ /*
+  * #define HX280ENC_IOCGBUFBUSADDRESS _IOR(HX280ENC_IOC_MAGIC,  1, unsigned long *)
+  * #define HX280ENC_IOCGBUFSIZE       _IOR(HX280ENC_IOC_MAGIC,  2, unsigned int *)
+  */
+#define HX280ENC_IOCGHWOFFSET      _IOR(HX280ENC_IOC_MAGIC,  3, unsigned long *)
+#define HX280ENC_IOCGHWIOSIZE      _IOR(HX280ENC_IOC_MAGIC,  4, unsigned int *)
+#define HX280ENC_IOC_CLI           _IO(HX280ENC_IOC_MAGIC,  5)
+#define HX280ENC_IOC_STI           _IO(HX280ENC_IOC_MAGIC,  6)
+#define HX280ENC_IOCXVIRT2BUS      _IOWR(HX280ENC_IOC_MAGIC,  7, unsigned long *)
+
+#define HX280ENC_IOCHARDRESET      _IO(HX280ENC_IOC_MAGIC, 8)   /* debugging tool */
+
+#define HX280ENC_IOCGSRAMOFFSET    _IOR(HX280ENC_IOC_MAGIC,  9, unsigned long *)
+#define HX280ENC_IOCGSRAMEIOSIZE    _IOR(HX280ENC_IOC_MAGIC,  10, unsigned int *)
+#define HX280ENC_IOCH_ENC_RESERVE   _IOR(HX280ENC_IOC_MAGIC, 11, unsigned int *)
+#define HX280ENC_IOCH_ENC_RELEASE   _IOR(HX280ENC_IOC_MAGIC, 12, unsigned int *)
+#define HX280ENC_IOCG_CORE_NUM      _IOR(HX280ENC_IOC_MAGIC, 13, unsigned int *)
+#define HX280ENC_IOCG_EN_CORE      _IOR(HX280ENC_IOC_MAGIC, 14, unsigned int *)
+
+#define HX280ENC_IOCG_CORE_WAIT     _IOR(HX280ENC_IOC_MAGIC, 19, unsigned int *)
+#define HX280ENC_IOC_MAXNR 30
+
+typedef struct {
+  unsigned long base_addr;
+  u32 iosize;
+  int irq;
+  u32 resouce_shared; //indicate the core share resources with other cores or not.If 1, means cores can not work at the same time.
+} CORE_CONFIG;
+#endif /* !_HX280ENC_H_ */
--- linux-ein-5.4.0.orig/drivers/mxc/hantro_vc8000e/hx280enc_vc8000e.c
+++ linux-ein-5.4.0/drivers/mxc/hantro_vc8000e/hx280enc_vc8000e.c
@@ -0,0 +1,1254 @@
+/*
+ *  H2 Encoder device driver (kernel module)
+ *
+ *  COPYRIGHT(C) 2014 VERISILICON
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* needed for __init,__exit directives */
+#include <linux/init.h>
+/* needed for remap_page_range
+    SetPageReserved
+    ClearPageReserved
+*/
+#include <linux/mm.h>
+/* obviously, for kmalloc */
+#include <linux/slab.h>
+/* for struct file_operations, register_chrdev() */
+#include <linux/fs.h>
+/* standard error codes */
+#include <linux/errno.h>
+
+#include <linux/moduleparam.h>
+/* request_irq(), free_irq() */
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+/* needed for virt_to_phys() */
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include <linux/compat.h>
+
+/* our own stuff */
+#include "hx280enc.h"
+
+#ifndef VSI
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#define DEVICE_NAME		"mxc_hantro_vc8000e"
+static struct device *hantro_vc8000e_dev;
+static struct clk *hantro_clk_vc8000e;
+static struct clk *hantro_clk_vc8000e_bus;
+#define BLK_CTL_BASE        0x38330000
+#endif
+
+
+/********variables declaration related with race condition**********/
+
+struct semaphore enc_core_sem;
+static DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+static DEFINE_SPINLOCK(owner_lock);
+static DECLARE_WAIT_QUEUE_HEAD(enc_wait_queue);
+
+/*------------------------------------------------------------------------
+*****************************PORTING LAYER********************************
+-------------------------------------------------------------------------*/
+#define RESOURCE_SHARED_INTER_CORES        0        /*0:no resource sharing inter cores 1: existing resource sharing*/
+#define CORE_0_IO_ADDR                 0xC0000000   /*customer specify according to own platform*/
+#define CORE_0_IO_SIZE                 (500 * 4)    /* bytes */
+
+#define CORE_1_IO_ADDR                 0xD0000000   /*customer specify according to own platform*/
+#define CORE_1_IO_SIZE                 (500 * 4)    /* bytes */
+
+#define INT_PIN_CORE_0                    -1        /*IRQ pin of core 0*/
+#define INT_PIN_CORE_1                    -1        /*IRQ pin of core 1*/
+
+/*for all cores, the core info should be listed here for subsequent use*/
+/*base_addr, iosize, irq, resource_shared*/
+CORE_CONFIG core_array[] = {
+	{CORE_0_IO_ADDR, CORE_0_IO_SIZE, INT_PIN_CORE_0, RESOURCE_SHARED_INTER_CORES}, //core_0 (VC8000E)
+	//{CORE_1_IO_ADDR, CORE_1_IO_SIZE, INT_PIN_CORE_1, RESOURCE_SHARED_INTER_CORES} //core_1 (VC8000EJ)
+};
+
+/*------------------------------END-------------------------------------*/
+
+/***************************TYPE AND FUNCTION DECLARATION****************/
+
+/* here's all the must remember stuff */
+typedef struct {
+	CORE_CONFIG  core_cfg; //config of each core,such as base addr, irq,etc
+	u32 hw_id; //hw id to indicate project
+	u32 core_id; //core id for driver and sw internal use
+	u32 is_valid; //indicate this core is hantro's core or not
+	u32 is_reserved; //indicate this core is occupied by user or not
+	int pid; //indicate which process is occupying the core
+	u32 irq_received; //indicate this core receives irq
+	u32 irq_status;
+	char *buffer;
+	unsigned int buffsize;
+	volatile u8 *hwregs;
+	u32 reg_buf[CORE_0_IO_SIZE/4];
+	struct semaphore core_suspend_sem;
+	u32 reg_corrupt;
+	struct fasync_struct *async_queue;
+#ifndef VSI
+	struct device *dev;
+	struct mutex dev_mutex;
+#endif
+} hantroenc_t;
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+static void ResetAsic(hantroenc_t *dev);
+static int CheckCoreOccupation(hantroenc_t *dev);
+
+#ifdef hantroenc_DEBUG
+static void dump_regs(unsigned long data);
+#endif
+
+/* IRQ handler */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+static irqreturn_t hantroenc_isr(int irq, void *dev_id, struct pt_regs *regs);
+#else
+static irqreturn_t hantroenc_isr(int irq, void *dev_id);
+#endif
+
+/*********************local variable declaration*****************/
+static unsigned long sram_base;
+static unsigned int sram_size;
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
+static int hantroenc_major;
+static int total_core_num;
+static volatile unsigned int asic_status;
+/* dynamic allocation*/
+static hantroenc_t *hantroenc_data;
+//static unsigned int pcie = 0;          /* used in hantro_mmu.c*/
+static struct class *hantro_enc_class;
+static struct device *hantro_enc_dev;
+
+/******************************************************************************/
+#ifndef VSI
+static int hantro_vc8000e_clk_enable(struct device *dev)
+{
+	clk_prepare(hantro_clk_vc8000e);
+	clk_enable(hantro_clk_vc8000e);
+	clk_prepare(hantro_clk_vc8000e_bus);
+	clk_enable(hantro_clk_vc8000e_bus);
+	return 0;
+}
+
+static int hantro_vc8000e_clk_disable(struct device *dev)
+{
+	if (hantro_clk_vc8000e) {
+		clk_disable(hantro_clk_vc8000e);
+		clk_unprepare(hantro_clk_vc8000e);
+	}
+	if (hantro_clk_vc8000e_bus) {
+		clk_disable(hantro_clk_vc8000e_bus);
+		clk_unprepare(hantro_clk_vc8000e_bus);
+	}
+	return 0;
+}
+
+static int hantro_vc8000e_ctrlblk_reset(struct device *dev)
+{
+	volatile u8 *iobase;
+	u32 val;
+
+	//config vc8000e
+	hantro_vc8000e_clk_enable(dev);
+	iobase = (volatile u8 *)ioremap(BLK_CTL_BASE, 0x10000);
+
+	val = ioread32(iobase);
+	val &= (~0x4);
+	iowrite32(val, iobase); // assert soft reset
+	udelay(2);
+
+	val = ioread32(iobase);
+	val |= 0x4;
+	iowrite32(val, iobase); // release soft reset
+
+	val = ioread32(iobase+0x4);
+	val |= 0x4;
+	iowrite32(val, iobase + 0x4); // enable clock
+
+	iowrite32(0xFFFFFFFF, iobase + 0x14); // fuse encoder enable
+	iounmap(iobase);
+	hantro_vc8000e_clk_disable(dev);
+	return 0;
+}
+
+static int hantro_vc8000e_power_on_disirq(hantroenc_t *hx280enc)
+{
+	//spin_lock_irq(&owner_lock);
+	mutex_lock(&hx280enc->dev_mutex);
+	//disable_irq(hx280enc->irq);
+	pm_runtime_get_sync(hx280enc->dev);
+	//enable_irq(hx280enc->irq);
+	mutex_unlock(&hx280enc->dev_mutex);
+	//spin_unlock_irq(&owner_lock);
+	return 0;
+}
+
+static int hantroenc_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+	if (vm->vm_pgoff == (hantroenc_data[0].core_cfg.base_addr >> PAGE_SHIFT)) {
+		vm->vm_flags |= VM_IO;
+		vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+		PDEBUG("hx280enc mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+		return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+						vm->vm_page_prot) ? -EAGAIN : 0;
+	} else {
+		pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+		return -EINVAL;
+	}
+}
+
+#endif  //VSI
+
+static int CheckEncIrq(hantroenc_t *dev, u32 *core_info, u32 *irq_status)
+{
+	unsigned long flags;
+	int rdy = 0;
+	u32 i = 0;
+	u8 core_mapping = 0;
+
+	core_mapping = (u8)(*core_info&0xFF);
+
+	while (core_mapping)	{
+		if (core_mapping & 0x1)	{
+			if (i > total_core_num-1)
+				break;
+
+			spin_lock_irqsave(&owner_lock, flags);
+
+			if (dev[i].irq_received)	{
+				/* reset the wait condition(s) */
+				PDEBUG("check %d irq ready\n", i);
+				dev[i].irq_received = 0;
+				rdy = 1;
+				*core_info = i;
+				*irq_status = dev[i].irq_status;
+			}
+
+			spin_unlock_irqrestore(&owner_lock, flags);
+			break;
+		}
+		core_mapping = core_mapping>>1;
+		i++;
+	}
+
+	return rdy;
+}
+
+static int WaitEncReady(hantroenc_t *dev, u32 *core_info, u32 *irq_status)
+{
+	PDEBUG("%s\n", __func__);
+
+	if (wait_event_timeout(enc_wait_queue,
+		CheckEncIrq(dev, core_info, irq_status), msecs_to_jiffies(200)) == 0)	{
+		pr_err("%s: wait interrupt timeout !\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int CheckCoreOccupation(hantroenc_t *dev)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&owner_lock, flags);
+	if (!dev->is_reserved) {
+		dev->is_reserved = 1;
+		dev->pid = current->pid;
+		ret = 1;
+		PDEBUG("%s pid=%d\n", __func__, dev->pid);
+	}
+
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	return ret;
+}
+
+static int GetWorkableCore(hantroenc_t *dev, u32 *core_info, u32 *core_info_tmp)
+{
+	int ret = 0;
+	u32 i = 0;
+	u32 cores;
+	u32 core_id = 0;
+	u8 core_mapping = 0;
+	u32 required_num = 0;
+
+	cores = *core_info;
+	required_num = ((cores >> CORE_INFO_AMOUNT_OFFSET) & 0x7)+1;
+	core_mapping = (u8)(cores & 0xFF);
+
+	if (*core_info_tmp == 0)
+		*core_info_tmp = required_num << 8;
+	else
+		required_num = ((*core_info_tmp & 0xF00) >> 8);
+
+	PDEBUG("%s:required_num=%d,core_info=%x\n", __func__, required_num, *core_info);
+
+	if (required_num) {
+		/* a valid free Core that has specified core id */
+		while (core_mapping)	{
+			if (core_mapping & 0x1)	{
+				if (i > total_core_num-1)
+					break;
+				core_id = i;
+				if (dev[core_id].is_valid && CheckCoreOccupation(&dev[core_id])) {
+					*core_info_tmp = ((((*core_info_tmp & 0xF00) >> 8)-1)<<8)|(*core_info_tmp & 0x0FF);
+					*core_info_tmp = *core_info_tmp | (1<<core_id);
+					if (((*core_info_tmp & 0xF00) >> 8) == 0) {
+						ret = 1;
+						*core_info = (*core_info&0xFFFFFF00)|(*core_info_tmp & 0xFF);
+						*core_info_tmp = 0;
+						required_num = 0;
+						break;
+					}
+				}
+			}
+			core_mapping = core_mapping >> 1;
+			i++;
+		}
+	} else
+		ret = 1;
+
+	PDEBUG("*core_info = %x\n", *core_info);
+	return ret;
+}
+
+static long ReserveEncoder(hantroenc_t *dev, u32 *core_info)
+{
+	u32 core_info_tmp = 0;
+
+	/*If HW resources are shared inter cores, just make sure only one is using the HW*/
+	if (dev[0].core_cfg.resouce_shared)	{
+		if (down_interruptible(&enc_core_sem))
+			return -ERESTARTSYS;
+	}
+
+	/* lock a core that has specified core id*/
+	if (wait_event_interruptible(hw_queue, GetWorkableCore(dev, core_info, &core_info_tmp) != 0))
+		return -ERESTARTSYS;
+
+	return 0;
+}
+
+static void ReleaseEncoder(hantroenc_t *dev, u32 *core_info)
+{
+	unsigned long flags;
+	u32 core_num = 0;
+	u32 i = 0, core_id;
+	u8 core_mapping = 0;
+
+	core_num = ((*core_info >> CORE_INFO_AMOUNT_OFFSET) & 0x7)+1;
+
+	core_mapping = (u8)(*core_info&0xFF);
+
+	PDEBUG("%s:core_num=%d,core_mapping=%x\n", __func__, core_num, core_mapping);
+	/* release specified core id */
+	while (core_mapping) {
+		if (core_mapping & 0x1)	{
+			core_id = i;
+			spin_lock_irqsave(&owner_lock, flags);
+			PDEBUG("dev[core_id].pid=%d,current->pid=%d\n", dev[core_id].pid, current->pid);
+			if (dev[core_id].is_reserved && dev[core_id].pid == current->pid) {
+				dev[core_id].pid = -1;
+				dev[core_id].is_reserved = 0;
+				dev[core_id].irq_received = 0;
+				dev[core_id].irq_status = 0;
+				dev[core_id].reg_corrupt = 0;
+			} else if (dev[core_id].pid != current->pid)
+				pr_err("WARNING:pid(%d) is trying to release core reserved by pid(%d)\n",
+					current->pid, dev[core_id].pid);
+
+			spin_unlock_irqrestore(&owner_lock, flags);
+
+			//wake_up_interruptible_all(&hw_queue);
+		}
+		core_mapping = core_mapping >> 1;
+		i++;
+	}
+
+	wake_up_interruptible_all(&hw_queue);
+
+	if (dev->core_cfg.resouce_shared)
+		up(&enc_core_sem);
+
+}
+
+static long hantroenc_ioctl(struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+
+	PDEBUG("ioctl cmd 0x%08x\n", cmd);
+	/*
+	* extract the type and number bitfields, and don't encode
+	* wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+	*/
+	if (_IOC_TYPE(cmd) != HX280ENC_IOC_MAGIC
+#ifdef HANTROMMU_SUPPORT
+		&& _IOC_TYPE(cmd) != HANTRO_IOC_MMU
+#endif
+	)
+		return -ENOTTY;
+	if ((_IOC_TYPE(cmd) == HX280ENC_IOC_MAGIC &&
+		_IOC_NR(cmd) > HX280ENC_IOC_MAXNR)
+#ifdef HANTROMMU_SUPPORT
+		|| (_IOC_TYPE(cmd) == HANTRO_IOC_MMU &&
+		_IOC_NR(cmd) > HANTRO_IOC_MMU_MAXNR)
+#endif
+	)
+		return -ENOTTY;
+
+	/*
+	* the direction is a bitmask, and VERIFY_WRITE catches R/W
+	* transfers. `Type' is user-oriented, while
+	* access_ok is kernel-oriented, so the concept of "read" and
+	* "write" is reversed
+	*/
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HX280ENC_IOCGHWOFFSET): {
+		u32 id;
+
+		__get_user(id, (u32 *)arg);
+
+		if (id >= total_core_num)
+			return -EFAULT;
+
+		__put_user(hantroenc_data[id].core_cfg.base_addr, (unsigned long *) arg);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCGHWIOSIZE):	{
+		u32 id;
+		u32 io_size;
+
+		__get_user(id, (u32 *)arg);
+
+		if (id >= total_core_num)
+			return -EFAULT;
+
+		io_size = hantroenc_data[id].core_cfg.iosize;
+		__put_user(io_size, (u32 *) arg);
+
+		return 0;
+	}
+	case _IOC_NR(HX280ENC_IOCGSRAMOFFSET):
+		__put_user(sram_base, (unsigned long *) arg);
+		break;
+	case _IOC_NR(HX280ENC_IOCGSRAMEIOSIZE):
+		__put_user(sram_size, (unsigned int *) arg);
+		break;
+	case _IOC_NR(HX280ENC_IOCG_CORE_NUM):
+		__put_user(total_core_num, (unsigned int *) arg);
+		break;
+	case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+		u32 core_info;
+		int ret;
+
+		PDEBUG("Reserve ENC Cores\n");
+		__get_user(core_info, (u32 *)arg);
+		ret = ReserveEncoder(hantroenc_data, &core_info);
+		if (ret == 0)
+			__put_user(core_info, (u32 *) arg);
+		return ret;
+	}
+	case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE): {
+		u32 core_info;
+
+		__get_user(core_info, (u32 *)arg);
+
+		PDEBUG("Release ENC Core\n");
+
+		ReleaseEncoder(hantroenc_data, &core_info);
+
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCG_EN_CORE): {
+		u32 core_id;
+		u32 reg_value;
+
+		__get_user(core_id, (u32 *)arg);
+		PDEBUG("Enable ENC Core\n");
+
+		if (hantroenc_data[core_id].is_reserved == 0)
+			return -EPERM;
+
+		if (hantroenc_data[core_id].reg_corrupt)	{
+			/*need to re-config HW if exception happen between reserve and enable*/
+			hantroenc_data[core_id].reg_corrupt = 0;
+			return -EAGAIN;
+		}
+
+		if (down_interruptible(&hantroenc_data[core_id].core_suspend_sem))
+			return -ERESTARTSYS;
+
+		reg_value = (u32)ioread32((void *)(hantroenc_data[core_id].hwregs + 0x14));
+		reg_value |= 0x01;
+		iowrite32(reg_value, (void *)(hantroenc_data[core_id].hwregs + 0x14));
+
+		break;
+	}
+
+	case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+		u32 core_info;
+		u32 irq_status;
+		u32 i;
+		u8 core_mapping;
+
+		__get_user(core_info, (u32 *)arg);
+
+		i = 0;
+		core_mapping = (u8)(core_info&0xFF);
+		while (core_mapping) {
+			if (core_mapping & 0x1)	{
+				if (i > total_core_num-1)
+					return -1;
+
+				if (hantroenc_data[i].is_reserved == 0)
+					return -1;
+				break;
+			}
+			core_mapping = core_mapping>>1;
+			i++;
+		}
+		err = WaitEncReady(hantroenc_data, &core_info, &irq_status);
+		if (err == 0) {
+			__put_user(irq_status, (unsigned int *)arg);
+			return core_info;//return core_id
+		} else {
+			__put_user(0, (unsigned int *)arg);
+			return -1;
+		}
+
+		break;
+	}
+	default: {
+#ifdef HANTROMMU_SUPPORT
+	if (_IOC_TYPE(cmd) == HANTRO_IOC_MMU)
+		return (MMUIoctl(cmd, filp, arg, hantroenc_data[0].hwregs));
+#endif
+	}
+	}
+	return 0;
+}
+
+static int hantroenc_open(struct inode *inode, struct file *filp)
+{
+	int result = 0;
+	hantroenc_t *dev = hantroenc_data;
+
+	filp->private_data = (void *) dev;
+
+#ifndef VSI
+	hantro_vc8000e_clk_enable(dev->dev);
+	hantro_vc8000e_power_on_disirq(dev);
+#endif
+
+	PDEBUG("dev opened\n");
+	return result;
+}
+static int hantroenc_release(struct inode *inode, struct file *filp)
+{
+	hantroenc_t *dev = (hantroenc_t *) filp->private_data;
+	u32 core_id = 0;
+
+#ifdef hantroenc_DEBUG
+	dump_regs((unsigned long) dev); /* dump the regs */
+#endif
+	unsigned long flags;
+
+	PDEBUG("dev closed\n");
+
+	for (core_id = 0; core_id < total_core_num; core_id++) {
+		spin_lock_irqsave(&owner_lock, flags);
+		if (dev[core_id].is_reserved == 1 && dev[core_id].pid == current->pid) {
+			dev[core_id].pid = -1;
+			dev[core_id].is_reserved = 0;
+			dev[core_id].irq_received = 0;
+			dev[core_id].irq_status = 0;
+			PDEBUG("release reserved core\n");
+		}
+		spin_unlock_irqrestore(&owner_lock, flags);
+	}
+
+#ifdef HANTROMMU_SUPPORT
+	MMURelease(filp, hantroenc_data[0].hwregs);
+#endif
+
+	wake_up_interruptible_all(&hw_queue);
+
+	if (dev->core_cfg.resouce_shared)
+		up(&enc_core_sem);
+
+#ifndef VSI
+	pm_runtime_put_sync(hantro_vc8000e_dev);
+	hantro_vc8000e_clk_disable(hantro_vc8000e_dev);
+#endif
+	return 0;
+}
+
+static long hantroenc_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	long err = 0;
+
+#define HX280ENC_IOCTL32(err, filp, cmd, arg) { \
+	mm_segment_t old_fs = get_fs(); \
+	set_fs(KERNEL_DS); \
+	err = hantroenc_ioctl(filp, cmd, arg); \
+	if (err) \
+		return err; \
+	set_fs(old_fs); \
+}
+
+union {
+	unsigned long kux;
+	unsigned int kui;
+} karg;
+	void __user *up = compat_ptr(arg);
+
+	switch (_IOC_NR(cmd)) {
+	case _IOC_NR(HX280ENC_IOCGHWOFFSET): {
+		err = get_user(karg.kux, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kux), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCGHWIOSIZE): {
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCGSRAMOFFSET): {
+		err = get_user(karg.kux, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kux), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCGSRAMEIOSIZE):{
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCG_CORE_NUM): {
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		err = put_user(((s32)karg.kui), (s32 __user *)up);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE): {
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		break;
+	}
+	case _IOC_NR(HX280ENC_IOCG_EN_CORE): {
+		err = get_user(karg.kui, (s32 __user *)up);
+		if (err)
+			return err;
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+		break;
+	}
+
+	case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+		HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)up);
+		break;
+	}
+	}
+	return 0;
+}
+
+/* VFS methods */
+static struct file_operations hantroenc_fops = {
+	.owner = THIS_MODULE,
+	.open = hantroenc_open,
+	.release = hantroenc_release,
+	.unlocked_ioctl = hantroenc_ioctl,
+	.fasync = NULL,
+#ifndef VSI
+	.mmap = hantroenc_mmap,
+#endif
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = hantroenc_ioctl32,
+#endif
+};
+
+static int hantro_enc_suspend(struct device *dev, pm_message_t state)
+{
+	int i, j;
+	u32 *reg_buf;
+
+	PDEBUG("%s start..\n", __func__);
+
+	for (i = 0; i < total_core_num; i++) {
+		/*if HW is active, need to wait until frame ready interrupt*/
+		if ((hantroenc_data[i].is_reserved == 0) || (down_interruptible(&hantroenc_data[i].core_suspend_sem)))
+			continue;
+
+		hantroenc_data[i].reg_corrupt = 1;
+		if (hantroenc_data[i].irq_status & 0x04) {
+			reg_buf = hantroenc_data[i].reg_buf;
+			for (j = 0; j < hantroenc_data[i].core_cfg.iosize; j += 4)
+				reg_buf[j/4] = ioread32((void *)(hantroenc_data[i].hwregs + j));
+		}
+
+		up(&hantroenc_data[i].core_suspend_sem);
+	}
+
+	PDEBUG("%s succeed!\n", __func__);
+	return 0;
+}
+
+static int hantro_enc_resume(struct device *dev)
+{
+	int i, j;
+	u32 *reg_buf;
+
+	PDEBUG("%s start..\n", __func__);
+
+	for (i = 0; i < total_core_num; i++)	{
+		if (hantroenc_data[i].is_reserved == 0)
+			continue;
+		reg_buf = hantroenc_data[i].reg_buf;
+
+		if (hantroenc_data[i].irq_status & 0x04) {
+			for (j = 0; j < hantroenc_data[i].core_cfg.iosize; j += 4)
+				iowrite32(reg_buf[j/4], (void *)(hantroenc_data[i].hwregs + j));
+			hantroenc_data[i].reg_corrupt = 0;
+		}
+	}
+
+	PDEBUG("%s succeed!\n", __func__);
+	return 0;
+
+}
+
+#ifndef VSI
+static int hantroenc_init(void)
+#else
+static int __init hantroenc_init(void)
+#endif
+{
+	int result = 0;
+	int i;
+
+	total_core_num = sizeof(core_array)/sizeof(CORE_CONFIG);
+	for (i = 0; i < total_core_num; i++)	{
+		PDEBUG("hantroenc: module init - core[%d] addr =%px\n", i,
+			(char *)core_array[i].base_addr);
+	}
+
+	hantroenc_data = (hantroenc_t *)vmalloc(sizeof(hantroenc_t)*total_core_num);
+	if (hantroenc_data == NULL)
+		goto err1;
+	memset(hantroenc_data, 0, sizeof(hantroenc_t)*total_core_num);
+
+	for (i = 0; i < total_core_num; i++) {
+		hantroenc_data[i].core_cfg = core_array[i];
+		hantroenc_data[i].async_queue = NULL;
+		hantroenc_data[i].hwregs = NULL;
+		hantroenc_data[i].core_id = i;
+		sema_init(&hantroenc_data[i].core_suspend_sem, 1);
+	}
+
+	result = register_chrdev(hantroenc_major, "hx280enc", &hantroenc_fops);
+	if (result < 0) {
+		pr_err("hx280enc: unable to get major <%d>\n",
+		hantroenc_major);
+		goto err1;
+	} else if (result != 0) /* this is for dynamic major */
+		hantroenc_major = result;
+
+
+	hantro_enc_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(hantro_enc_class)) {
+		pr_err("can't register device hx280 class\n");
+		goto err2;
+	}
+
+	hantro_enc_dev = device_create(hantro_enc_class, NULL, MKDEV(hantroenc_major, 0), NULL, DEVICE_NAME);
+
+	result = ReserveIO();
+	if (result < 0)
+		goto err;
+
+	ResetAsic(hantroenc_data);  /* reset hardware */
+
+	sema_init(&enc_core_sem, 1);
+
+#ifdef HANTROMMU_SUPPORT
+	result = MMUInit(hantroenc_data[0].hwregs);
+	if (result == MMU_STATUS_NOT_FOUND)
+		pr_err("MMU does not exist!\n");
+	else if (result != MMU_STATUS_OK) {
+		ReleaseIO();
+		goto err;
+	}
+#endif
+
+	/* get the IRQ line */
+	for (i = 0; i < total_core_num; i++) {
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+		if (hantroenc_data[i].core_cfg.irq != -1) {
+			result = request_irq(hantroenc_data[i].core_cfg.irq, hantroenc_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+				SA_INTERRUPT | SA_SHIRQ,
+#else
+				IRQF_SHARED,
+#endif
+				"hx280enc", (void *) &hantroenc_data[i]);
+			if (result == -EINVAL) {
+				pr_err("hx280enc: Bad irq number or handler\n");
+				ReleaseIO();
+				goto err;
+			} else if (result == -EBUSY) {
+				pr_err("hx280enc: IRQ <%d> busy, change your config\n",
+				hantroenc_data[i].core_cfg.irq);
+				ReleaseIO();
+				goto err;
+			}
+		} else
+			pr_err("hx280enc: IRQ not in use!\n");
+	}
+	pr_info("hx280enc: module inserted. Major <%d>\n", hantroenc_major);
+
+	return 0;
+
+err:
+	device_destroy(hantro_enc_class, MKDEV(hantroenc_major, 0));
+	class_destroy(hantro_enc_class);
+err2:
+	unregister_chrdev(hantroenc_major, "hx280enc");
+err1:
+	if (hantroenc_data != NULL)
+		vfree(hantroenc_data);
+	pr_err("hx280enc: module not inserted\n");
+	return result;
+}
+
+#ifndef VSI
+static void hantroenc_cleanup(void)
+#else
+static void __exit hantroenc_cleanup(void)
+#endif
+{
+	int i = 0;
+
+	for (i = 0; i < total_core_num; i++) {
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+		writel(0, hantroenc_data[i].hwregs + 0x14); /* disable HW */
+		writel(0, hantroenc_data[i].hwregs + 0x04); /* clear enc IRQ */
+
+		/* free the encoder IRQ */
+		if (hantroenc_data[i].core_cfg.irq != -1)
+			free_irq(hantroenc_data[i].core_cfg.irq, (void *)&hantroenc_data[i]);
+	}
+
+#ifdef HANTROMMU_SUPPORT
+	MMUCleanup(hantroenc_data[0].hwregs);
+#endif
+
+	ReleaseIO();
+	vfree(hantroenc_data);
+
+	device_destroy(hantro_enc_class, MKDEV(hantroenc_major, 0));
+
+	class_destroy(hantro_enc_class);
+
+	unregister_chrdev(hantroenc_major, "hantroenc");
+
+	pr_info("hantroenc: module removed\n");
+
+}
+
+static int ReserveIO(void)
+{
+	u32 hwid;
+	int i;
+	u32 found_hw = 0;
+
+	for (i = 0; i < total_core_num; i++) {
+		if (!request_mem_region
+			(hantroenc_data[i].core_cfg.base_addr, hantroenc_data[i].core_cfg.iosize, "hx280enc")) {
+			pr_err("hantroenc: failed to reserve HW regs\n");
+			continue;
+		}
+
+		hantroenc_data[i].hwregs =
+			(volatile u8 *) ioremap(hantroenc_data[i].core_cfg.base_addr,
+		hantroenc_data[i].core_cfg.iosize);
+
+		if (hantroenc_data[i].hwregs == NULL) {
+			pr_err("hantroenc: failed to ioremap HW regs\n");
+			ReleaseIO();
+			continue;
+		}
+
+		/*read hwid and check validness and store it*/
+		hwid = (u32)ioread32((void *)hantroenc_data[i].hwregs);
+		PDEBUG("hwid=0x%08x\n", hwid);
+
+		/* check for encoder HW ID */
+		if (((((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID1 >> 16) & 0xFFFF))) &&
+			((((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID2 >> 16) & 0xFFFF)))) {
+			pr_err("hantroenc: HW not found at %p\n",
+			(void *)hantroenc_data[i].core_cfg.base_addr);
+#ifdef hantroenc_DEBUG
+			dump_regs((unsigned long) &hantroenc_data);
+#endif
+			//ReleaseIO();
+			hantroenc_data[i].is_valid = 0;
+			continue;
+		}
+		hantroenc_data[i].hw_id = hwid;
+		hantroenc_data[i].is_valid = 1;
+		found_hw = 1;
+
+		pr_info("hantroenc: HW at base <%px> with ID <0x%08x>\n",
+			(char *)hantroenc_data[i].core_cfg.base_addr, hwid);
+
+	}
+
+	if (found_hw == 0) {
+		pr_err("hantroenc: NO ANY HW found!!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void ReleaseIO(void)
+{
+	u32 i;
+
+	for (i = 0; i < total_core_num; i++)	{
+		//if (hantroenc_data[i].is_valid == 0)
+		//   continue;
+		if (hantroenc_data[i].hwregs)
+			iounmap((void *) hantroenc_data[i].hwregs);
+		release_mem_region(hantroenc_data[i].core_cfg.base_addr, hantroenc_data[i].core_cfg.iosize);
+	}
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+static irqreturn_t hantroenc_isr(int irq, void *dev_id, struct pt_regs *regs)
+#else
+static irqreturn_t hantroenc_isr(int irq, void *dev_id)
+#endif
+{
+	unsigned int handled = 0;
+	hantroenc_t *dev = (hantroenc_t *) dev_id;
+	u32 irq_status;
+	unsigned long flags;
+
+	/*If core is not reserved by any user, but irq is received, just clean it*/
+	spin_lock_irqsave(&owner_lock, flags);
+	if (!dev->is_reserved) {
+		u32 hwId;
+		u32 majorId;
+		u32 wClr;
+
+		pr_err("hantroenc_isr:received IRQ but core is not reserved!\n");
+		irq_status = (u32)ioread32((void *)(dev->hwregs + 0x04));
+		if (irq_status & 0x01) {
+			/*  Disable HW when buffer over-flow happen
+			*  HW behavior changed in over-flow
+			*    in-pass, HW cleanup HWIF_ENC_E auto
+			*    new version:  ask SW cleanup HWIF_ENC_E when buffer over-flow
+			*/
+			if (irq_status & 0x20)
+				iowrite32(0, (void *)(dev->hwregs + 0x14));
+
+			/* clear all IRQ bits. (hwId >= 0x80006100) means IRQ is cleared by writting 1 */
+			hwId = ioread32((void *)dev->hwregs);
+			majorId = (hwId & 0x0000FF00) >> 8;
+			wClr = (majorId >= 0x61) ? irq_status : (irq_status & (~0x1FD));
+			iowrite32(wClr, (void *)(dev->hwregs + 0x04));
+		}
+		spin_unlock_irqrestore(&owner_lock, flags);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&owner_lock, flags);
+
+	irq_status = (u32)ioread32((void *)(dev->hwregs + 0x04));
+	if (irq_status & 0x01) {
+		u32 hwId;
+		u32 majorId;
+		u32 wClr;
+		/*  Disable HW when buffer over-flow happen
+		*  HW behavior changed in over-flow
+		*    in-pass, HW cleanup HWIF_ENC_E auto
+		*    new version:  ask SW cleanup HWIF_ENC_E when buffer over-flow
+		*/
+		if (irq_status & 0x20)
+			iowrite32(0, (void *)(dev->hwregs + 0x14));
+
+		/* clear all IRQ bits. (hwId >= 0x80006100) means IRQ is cleared by writting 1 */
+		hwId = ioread32((void *)dev->hwregs);
+		majorId = (hwId & 0x0000FF00) >> 8;
+		wClr = (majorId >= 0x61) ? irq_status : (irq_status & (~0x1FD));
+		iowrite32(wClr, (void *)(dev->hwregs + 0x04));
+
+		spin_lock_irqsave(&owner_lock, flags);
+		dev->irq_received = 1;
+		dev->irq_status = irq_status & (~0x01);
+		spin_unlock_irqrestore(&owner_lock, flags);
+		if (irq_status & 0x04)  // if frame_rdy IRQ is received, then HW will not be used any more.
+			up(&hantroenc_data[dev->core_id].core_suspend_sem);
+
+		wake_up_all(&enc_wait_queue);
+		handled++;
+	}
+
+	if (!handled) {
+		PDEBUG("IRQ received, but not hantro's!\n");
+	}
+	return IRQ_HANDLED;
+}
+
+static void ResetAsic(hantroenc_t *dev)
+{
+	int i, n;
+
+	for (n = 0; n < total_core_num; n++) {
+		if (dev[n].is_valid == 0)
+			continue;
+		iowrite32(0, (void *)(dev[n].hwregs + 0x14));
+		for (i = 4; i < dev[n].core_cfg.iosize; i += 4)
+			iowrite32(0, (void *)(dev[n].hwregs + i));
+	}
+}
+
+#ifdef hantroenc_DEBUG
+static void dump_regs(unsigned long data)
+{
+	hantroenc_t *dev = (hantroenc_t *) data;
+	int i;
+
+	PDEBUG("Reg Dump Start\n");
+	for (i = 0; i < dev->iosize; i += 4) {
+		PDEBUG("\toffset %02X = %08X\n", i, ioread32(dev->hwregs + i));
+	}
+	PDEBUG("Reg Dump End\n");
+}
+#endif
+
+#ifndef VSI
+static int hantro_vc8000e_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct resource *res;
+
+	hantro_vc8000e_dev = &pdev->dev;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro_vc8000e");
+	if (!res) {
+		pr_err("hantro vc8000e: unable to get vpu base addr\n");
+		return -ENODEV;
+	}
+
+	core_array[0].base_addr = res->start;
+	core_array[0].irq = platform_get_irq_byname(pdev, "irq_hantro_vc8000e");
+	hantro_clk_vc8000e = clk_get(&pdev->dev, "clk_hantro_vc8000e");
+	if (IS_ERR(hantro_clk_vc8000e)) {
+		pr_err("hantro vc8000e: get clock failed, %p\n", hantro_clk_vc8000e);
+		err = -ENXIO;
+		goto error;
+	}
+	hantro_clk_vc8000e_bus = clk_get(&pdev->dev, "clk_hantro_vc8000e_bus");
+	if (IS_ERR(hantro_clk_vc8000e_bus)) {
+		pr_err("hantro vc8000e: get bus clock failed, %p\n", hantro_clk_vc8000e_bus);
+		err = -ENXIO;
+		goto error;
+	}
+
+	PDEBUG("hantro: vc8000e clock: 0x%lX, 0x%lX\n", clk_get_rate(hantro_clk_vc8000e), clk_get_rate(hantro_clk_vc8000e_bus));
+
+	hantro_vc8000e_clk_enable(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	hantro_vc8000e_ctrlblk_reset(&pdev->dev);
+
+	err = hantroenc_init();
+	if (0 != err) {
+		pr_err("hantro vc8000e: init failed\n");
+		goto error;
+	}
+
+	hantroenc_data->dev = &pdev->dev;
+	platform_set_drvdata(pdev, hantroenc_data);
+	mutex_init(&hantroenc_data->dev_mutex);
+
+	goto out;
+
+error:
+	pr_err("hantro vc8000e probe failed\n");
+out:
+	pm_runtime_put_sync(&pdev->dev);
+	hantro_vc8000e_clk_disable(&pdev->dev);
+	return err;
+}
+
+static int hantro_vc8000e_dev_remove(struct platform_device *pdev)
+{
+	hantro_vc8000e_clk_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	if (hantroenc_major > 0) {
+		hantroenc_cleanup();
+		hantroenc_major = 0;
+	}
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	hantro_vc8000e_clk_disable(&pdev->dev);
+	if (!IS_ERR(hantro_clk_vc8000e))
+		clk_put(hantro_clk_vc8000e);
+	if (!IS_ERR(hantro_clk_vc8000e_bus))
+		clk_put(hantro_clk_vc8000e_bus);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int __maybe_unused hantro_vc8000e_suspend(struct device *dev)
+{
+	pm_message_t state = {0};
+
+	hantro_enc_suspend(dev, state);
+	pm_runtime_put_sync_suspend(dev);   //power off
+	return 0;
+}
+static int __maybe_unused hantro_vc8000e_resume(struct device *dev)
+{
+	hantroenc_t *hx280enc = dev_get_drvdata(dev);
+
+	hantro_vc8000e_power_on_disirq(hx280enc);
+	hantro_vc8000e_ctrlblk_reset(dev);
+
+	hantro_enc_resume(dev);
+
+	return 0;
+}
+static int hantro_vc8000e_runtime_suspend(struct device *dev)
+{
+	//release_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static int hantro_vc8000e_runtime_resume(struct device *dev)
+{
+	//request_bus_freq(BUS_FREQ_HIGH);
+	hantro_vc8000e_ctrlblk_reset(dev);
+	return 0;
+}
+
+static const struct dev_pm_ops hantro_vc8000e_pm_ops = {
+	SET_RUNTIME_PM_OPS(hantro_vc8000e_runtime_suspend, hantro_vc8000e_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(hantro_vc8000e_suspend, hantro_vc8000e_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_vc8000e_of_match[] = {
+	{ .compatible = "nxp,imx8mp-hantro-vc8000e", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, hantro_vc8000e_of_match);
+
+
+static struct platform_driver mxchantro_vc8000e_driver = {
+	.driver = {
+	.name = "mxc_hantro_vc8000e",
+	.of_match_table = hantro_vc8000e_of_match,
+#ifdef CONFIG_PM
+	.pm = &hantro_vc8000e_pm_ops,
+#endif
+	},
+	.probe = hantro_vc8000e_probe,
+	.remove = hantro_vc8000e_dev_remove,
+};
+
+static int __init hantro_vc8000e_init(void)
+{
+	int ret = platform_driver_register(&mxchantro_vc8000e_driver);
+
+	return ret;
+}
+
+static void __exit hantro_vc8000e_exit(void)
+{
+	platform_driver_unregister(&mxchantro_vc8000e_driver);
+}
+
+module_init(hantro_vc8000e_init);
+module_exit(hantro_vc8000e_exit);
+
+#else  //VSI
+module_init(hantroenc_init);
+module_exit(hantroenc_cleanup);
+
+#endif  //VSI
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Verisilicon");
+MODULE_DESCRIPTION("Hantro Encoder driver");
+
--- linux-ein-5.4.0.orig/drivers/mxc/hdmi-cec/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/hdmi-cec/Kconfig
@@ -0,0 +1,11 @@
+
+menu "MXC HDMI CEC (Consumer Electronics Control) support"
+
+config MXC_HDMI_CEC
+	tristate "Support for MXC HDMI CEC (Consumer Electronics Control)"
+	depends on MFD_MXC_HDMI
+	depends on FB_MXC_HDMI
+	help
+	  The HDMI CEC device implement low level protocol on i.MX6x platforms.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/hdmi-cec/Makefile
+++ linux-ein-5.4.0/drivers/mxc/hdmi-cec/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MXC_HDMI_CEC)                  += mxc_hdmi-cec.o
--- linux-ein-5.4.0.orig/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
+++ linux-ein-5.4.0/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_hdmi-cec.c
+ *
+ * @brief HDMI CEC system initialization and file operation implementation
+ *
+ * @ingroup HDMI
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/sizes.h>
+
+#include <linux/console.h>
+#include <linux/types.h>
+#include <linux/mfd/mxc-hdmi-core.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <video/mxc_hdmi.h>
+
+#include "mxc_hdmi-cec.h"
+
+
+#define MAX_MESSAGE_LEN		17
+
+#define MESSAGE_TYPE_RECEIVE_SUCCESS		1
+#define MESSAGE_TYPE_NOACK		2
+#define MESSAGE_TYPE_DISCONNECTED		3
+#define MESSAGE_TYPE_CONNECTED		4
+#define MESSAGE_TYPE_SEND_SUCCESS		5
+
+
+struct hdmi_cec_priv {
+	int  receive_error;
+	int  send_error;
+	u8 Logical_address;
+	bool cec_state;
+	u8 last_msg[MAX_MESSAGE_LEN];
+	u8 msg_len;
+	u8 latest_cec_stat;
+	spinlock_t irq_lock;
+	struct delayed_work hdmi_cec_work;
+	struct mutex lock;
+};
+
+struct hdmi_cec_event {
+	int event_type;
+	int msg_len;
+	u8 msg[MAX_MESSAGE_LEN];
+	struct list_head list;
+};
+
+static LIST_HEAD(head);
+
+static int hdmi_cec_major;
+static struct class *hdmi_cec_class;
+static struct hdmi_cec_priv hdmi_cec_data;
+static u8 open_count;
+
+static wait_queue_head_t hdmi_cec_queue;
+static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
+{
+	struct hdmi_cec_priv *hdmi_cec = data;
+	u8 cec_stat = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hdmi_cec->irq_lock, flags);
+
+	hdmi_writeb(0x7f, HDMI_IH_MUTE_CEC_STAT0);
+
+	cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0);
+	hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0);
+
+	if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
+		HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
+		HDMI_IH_CEC_STAT0_DONE)) == 0) {
+		spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	pr_debug("HDMI CEC interrupt received\n");
+	hdmi_cec->latest_cec_stat = cec_stat;
+
+	schedule_delayed_work(&(hdmi_cec->hdmi_cec_work), msecs_to_jiffies(20));
+
+	spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void mxc_hdmi_cec_handle(u16 cec_stat)
+{
+	u8 val = 0, i = 0;
+	struct hdmi_cec_event *event = NULL;
+
+	/* The current transmission is successful (for initiator only). */
+	if (!open_count)
+		return;
+
+	if (cec_stat & HDMI_IH_CEC_STAT0_DONE) {
+
+		event = vmalloc(sizeof(struct hdmi_cec_event));
+		if (NULL == event) {
+			pr_err("%s: Not enough memory!\n", __func__);
+			return;
+		}
+
+		memset(event, 0, sizeof(struct hdmi_cec_event));
+		event->event_type = MESSAGE_TYPE_SEND_SUCCESS;
+
+		mutex_lock(&hdmi_cec_data.lock);
+		list_add_tail(&event->list, &head);
+		mutex_unlock(&hdmi_cec_data.lock);
+
+		wake_up(&hdmi_cec_queue);
+	}
+
+	/* EOM is detected so that the received data is ready
+	 * in the receiver data buffer
+	 */
+	if (cec_stat & HDMI_IH_CEC_STAT0_EOM) {
+
+		hdmi_writeb(0x02, HDMI_IH_CEC_STAT0);
+
+		event = vmalloc(sizeof(struct hdmi_cec_event));
+		if (NULL == event) {
+			pr_err("%s: Not enough memory!\n", __func__);
+			return;
+		}
+		memset(event, 0, sizeof(struct hdmi_cec_event));
+
+		event->msg_len = hdmi_readb(HDMI_CEC_RX_CNT);
+		if (!event->msg_len) {
+			pr_err("%s: Invalid CEC message length!\n", __func__);
+			vfree(event);
+			return;
+		}
+		event->event_type = MESSAGE_TYPE_RECEIVE_SUCCESS;
+
+		for (i = 0; i < event->msg_len; i++)
+			event->msg[i] = hdmi_readb(HDMI_CEC_RX_DATA0+i);
+		hdmi_writeb(0x0, HDMI_CEC_LOCK);
+
+		mutex_lock(&hdmi_cec_data.lock);
+		list_add_tail(&event->list, &head);
+		mutex_unlock(&hdmi_cec_data.lock);
+
+		wake_up(&hdmi_cec_queue);
+	}
+
+	/* An error is detected on cec line (for initiator only). */
+	if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_INIT) {
+
+		mutex_lock(&hdmi_cec_data.lock);
+		hdmi_cec_data.send_error++;
+		if (hdmi_cec_data.send_error > 5) {
+			pr_err("%s:Re-transmission is attempted more than 5 times!\n",
+					__func__);
+			hdmi_cec_data.send_error = 0;
+			mutex_unlock(&hdmi_cec_data.lock);
+			return;
+		}
+
+		for (i = 0; i < hdmi_cec_data.msg_len; i++) {
+			hdmi_writeb(hdmi_cec_data.last_msg[i],
+						HDMI_CEC_TX_DATA0 + i);
+		}
+		hdmi_writeb(hdmi_cec_data.msg_len, HDMI_CEC_TX_CNT);
+
+		val = hdmi_readb(HDMI_CEC_CTRL);
+		val |= 0x01;
+		hdmi_writeb(val, HDMI_CEC_CTRL);
+		mutex_unlock(&hdmi_cec_data.lock);
+	}
+
+	/* A frame is not acknowledged in a directly addressed message.
+	 * Or a frame is negatively acknowledged in
+	 * a broadcast message (for initiator only).
+	 */
+	if (cec_stat & HDMI_IH_CEC_STAT0_NACK) {
+		event = vmalloc(sizeof(struct hdmi_cec_event));
+		if (NULL == event) {
+			pr_err("%s: Not enough memory\n", __func__);
+			return;
+		}
+		memset(event, 0, sizeof(struct hdmi_cec_event));
+		event->event_type = MESSAGE_TYPE_NOACK;
+
+		mutex_lock(&hdmi_cec_data.lock);
+		list_add_tail(&event->list, &head);
+		mutex_unlock(&hdmi_cec_data.lock);
+
+		wake_up(&hdmi_cec_queue);
+	}
+
+	/* An error is notified by a follower.
+	 * Abnormal logic data bit error (for follower).
+	 */
+	if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_FOLL) {
+		hdmi_cec_data.receive_error++;
+	}
+
+	/* HDMI cable connected */
+	if (cec_stat & 0x80) {
+		event = vmalloc(sizeof(struct hdmi_cec_event));
+		if (NULL == event) {
+			pr_err("%s: Not enough memory\n", __func__);
+			return;
+		}
+		memset(event, 0, sizeof(struct hdmi_cec_event));
+		event->event_type = MESSAGE_TYPE_CONNECTED;
+
+		mutex_lock(&hdmi_cec_data.lock);
+		list_add_tail(&event->list, &head);
+		mutex_unlock(&hdmi_cec_data.lock);
+
+		wake_up(&hdmi_cec_queue);
+	}
+
+	/* HDMI cable disconnected */
+	if (cec_stat & 0x100) {
+		event = vmalloc(sizeof(struct hdmi_cec_event));
+		if (NULL == event) {
+			pr_err("%s: Not enough memory!\n", __func__);
+			return;
+		}
+		memset(event, 0, sizeof(struct hdmi_cec_event));
+		event->event_type = MESSAGE_TYPE_DISCONNECTED;
+
+		mutex_lock(&hdmi_cec_data.lock);
+		list_add_tail(&event->list, &head);
+		mutex_unlock(&hdmi_cec_data.lock);
+
+		wake_up(&hdmi_cec_queue);
+	}
+
+    return;
+}
+EXPORT_SYMBOL(mxc_hdmi_cec_handle);
+
+static void mxc_hdmi_cec_worker(struct work_struct *work)
+{
+	u8 val;
+
+	mxc_hdmi_cec_handle(hdmi_cec_data.latest_cec_stat);
+	val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+			HDMI_IH_CEC_STAT0_ARB_LOST;
+	hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+}
+
+/*!
+ * @brief open function for vpu file operation
+ *
+ * @return  0 on success or negative error code on error
+ */
+static int hdmi_cec_open(struct inode *inode, struct file *filp)
+{
+	mutex_lock(&hdmi_cec_data.lock);
+	if (open_count) {
+		mutex_unlock(&hdmi_cec_data.lock);
+		return -EBUSY;
+	}
+
+	open_count = 1;
+	filp->private_data = (void *)(&hdmi_cec_data);
+	hdmi_cec_data.Logical_address = 15;
+	hdmi_cec_data.cec_state = false;
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	return 0;
+}
+
+static ssize_t hdmi_cec_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct hdmi_cec_event *event = NULL;
+
+	pr_debug("function : %s\n", __func__);
+	if (!open_count)
+		return -ENODEV;
+
+	mutex_lock(&hdmi_cec_data.lock);
+	if (false == hdmi_cec_data.cec_state) {
+		mutex_unlock(&hdmi_cec_data.lock);
+		return -EACCES;
+	}
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	/* delete from list */
+	mutex_lock(&hdmi_cec_data.lock);
+	if (list_empty(&head)) {
+		mutex_unlock(&hdmi_cec_data.lock);
+		return -EACCES;
+	}
+	event = list_first_entry(&head, struct hdmi_cec_event, list);
+	list_del(&event->list);
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	if (copy_to_user(buf, event,
+			sizeof(struct hdmi_cec_event) - sizeof(struct list_head))) {
+		vfree(event);
+		return -EFAULT;
+	}
+	vfree(event);
+
+	return sizeof(struct hdmi_cec_event);
+}
+
+static ssize_t hdmi_cec_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	int ret = 0 , i = 0;
+	u8 msg[MAX_MESSAGE_LEN];
+	u8 msg_len = 0, val = 0;
+
+	pr_debug("function : %s\n", __func__);
+	if (!open_count)
+		return -ENODEV;
+
+	mutex_lock(&hdmi_cec_data.lock);
+	if (false == hdmi_cec_data.cec_state) {
+		mutex_unlock(&hdmi_cec_data.lock);
+		return -EACCES;
+	}
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	if (count > MAX_MESSAGE_LEN)
+		return -EINVAL;
+
+	mutex_lock(&hdmi_cec_data.lock);
+	hdmi_cec_data.send_error = 0;
+	memset(&msg, 0, MAX_MESSAGE_LEN);
+	ret = copy_from_user(&msg, buf, count);
+	if (ret) {
+		ret = -EACCES;
+		goto end;
+	}
+
+	msg_len = count;
+	hdmi_writeb(msg_len, HDMI_CEC_TX_CNT);
+	for (i = 0; i < msg_len; i++) {
+		hdmi_writeb(msg[i], HDMI_CEC_TX_DATA0+i);
+	}
+
+	val = hdmi_readb(HDMI_CEC_CTRL);
+	val |= 0x01;
+	hdmi_writeb(val, HDMI_CEC_CTRL);
+	memcpy(hdmi_cec_data.last_msg, msg, msg_len);
+	hdmi_cec_data.msg_len = msg_len;
+
+	i = 0;
+	val = hdmi_readb(HDMI_CEC_CTRL);
+	while ((val & 0x01) == 0x1) {
+		msleep(50);
+		i++;
+		if (i > 3) {
+			ret = -EIO;
+			goto end;
+		}
+		val = hdmi_readb(HDMI_CEC_CTRL);
+	}
+
+end:
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	return ret;
+}
+
+/*!
+ * @brief IO ctrl function for vpu file operation
+ * @param cmd IO ctrl command
+ * @return  0 on success or negative error code on error
+ */
+static long hdmi_cec_ioctl(struct file *filp, u_int cmd,
+		     u_long arg)
+{
+	int ret = 0, status = 0;
+	u8 val = 0, msg = 0;
+	struct mxc_edid_cfg hdmi_edid_cfg;
+
+	pr_debug("function : %s\n", __func__);
+	if (!open_count)
+		return -ENODEV;
+
+	switch (cmd) {
+	case HDMICEC_IOC_SETLOGICALADDRESS:
+		mutex_lock(&hdmi_cec_data.lock);
+		if (false == hdmi_cec_data.cec_state) {
+			mutex_unlock(&hdmi_cec_data.lock);
+			return -EACCES;
+		}
+
+		hdmi_cec_data.Logical_address = (u8)arg;
+
+		if (hdmi_cec_data.Logical_address <= 7) {
+			val = 1 << hdmi_cec_data.Logical_address;
+			hdmi_writeb(val, HDMI_CEC_ADDR_L);
+			hdmi_writeb(0, HDMI_CEC_ADDR_H);
+		} else if (hdmi_cec_data.Logical_address > 7 &&
+					hdmi_cec_data.Logical_address <= 15) {
+			val = 1 << (hdmi_cec_data.Logical_address - 8);
+			hdmi_writeb(val, HDMI_CEC_ADDR_H);
+			hdmi_writeb(0, HDMI_CEC_ADDR_L);
+		} else {
+			ret = -EINVAL;
+		}
+
+		/* Send Polling message with same source
+		 * and destination address
+		 */
+		if (0 == ret && 15 != hdmi_cec_data.Logical_address) {
+			msg = (hdmi_cec_data.Logical_address << 4) |
+					hdmi_cec_data.Logical_address;
+			hdmi_writeb(1, HDMI_CEC_TX_CNT);
+			hdmi_writeb(msg, HDMI_CEC_TX_DATA0);
+
+			val = hdmi_readb(HDMI_CEC_CTRL);
+			val |= 0x01;
+			hdmi_writeb(val, HDMI_CEC_CTRL);
+		}
+
+		mutex_unlock(&hdmi_cec_data.lock);
+		break;
+
+	case HDMICEC_IOC_STARTDEVICE:
+		val = hdmi_readb(HDMI_MC_CLKDIS);
+		val &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+		hdmi_writeb(val, HDMI_MC_CLKDIS);
+
+		hdmi_writeb(0x02, HDMI_CEC_CTRL);
+
+		val = HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_NACK |
+			HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
+		hdmi_writeb(val, HDMI_CEC_POLARITY);
+
+		val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+			HDMI_IH_CEC_STAT0_ARB_LOST;
+		hdmi_writeb(val, HDMI_CEC_MASK);
+		hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+
+		mutex_lock(&hdmi_cec_data.lock);
+		hdmi_cec_data.cec_state = true;
+		mutex_unlock(&hdmi_cec_data.lock);
+		break;
+
+	case HDMICEC_IOC_STOPDEVICE:
+		hdmi_writeb(0x10, HDMI_CEC_CTRL);
+
+		val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+			HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST |
+			HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM |
+			HDMI_IH_CEC_STAT0_DONE;
+		hdmi_writeb(val, HDMI_CEC_MASK);
+		hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+
+		hdmi_writeb(0x0, HDMI_CEC_POLARITY);
+
+		val = hdmi_readb(HDMI_MC_CLKDIS);
+		val |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+		hdmi_writeb(val, HDMI_MC_CLKDIS);
+
+		mutex_lock(&hdmi_cec_data.lock);
+		hdmi_cec_data.cec_state = false;
+		mutex_unlock(&hdmi_cec_data.lock);
+		break;
+
+	case HDMICEC_IOC_GETPHYADDRESS:
+		hdmi_get_edid_cfg(&hdmi_edid_cfg);
+		status = copy_to_user((void __user *)arg,
+					 &hdmi_edid_cfg.physical_address,
+					 4*sizeof(u8));
+		if (status)
+			ret = -EFAULT;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*!
+* @brief Release function for vpu file operation
+* @return  0 on success or negative error code on error
+*/
+static int hdmi_cec_release(struct inode *inode, struct file *filp)
+{
+	mutex_lock(&hdmi_cec_data.lock);
+
+	if (open_count) {
+		open_count = 0;
+		hdmi_cec_data.cec_state = false;
+		hdmi_cec_data.Logical_address = 15;
+	}
+
+	mutex_unlock(&hdmi_cec_data.lock);
+
+	return 0;
+}
+
+static unsigned int hdmi_cec_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+
+	pr_debug("function : %s\n", __func__);
+
+	if (!open_count)
+		return -ENODEV;
+
+	if (false == hdmi_cec_data.cec_state)
+		return -EACCES;
+
+	poll_wait(file, &hdmi_cec_queue, wait);
+
+	if (!list_empty(&head))
+		mask |= (POLLIN | POLLRDNORM);
+
+	return mask;
+}
+
+const struct file_operations hdmi_cec_fops = {
+	.owner = THIS_MODULE,
+	.read = hdmi_cec_read,
+	.write = hdmi_cec_write,
+	.open = hdmi_cec_open,
+	.unlocked_ioctl = hdmi_cec_ioctl,
+	.release = hdmi_cec_release,
+	.poll = hdmi_cec_poll,
+};
+
+static int hdmi_cec_dev_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct device *temp_class;
+	struct resource *res;
+	struct pinctrl *pinctrl;
+	int irq = platform_get_irq(pdev, 0);
+
+	hdmi_cec_major = register_chrdev(hdmi_cec_major,
+				"mxc_hdmi_cec", &hdmi_cec_fops);
+	if (hdmi_cec_major < 0) {
+		dev_err(&pdev->dev, "hdmi_cec: unable to get a major for HDMI CEC\n");
+		err = -EBUSY;
+		goto out;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(res == NULL)) {
+		dev_err(&pdev->dev, "hdmi_cec:No HDMI irq line provided\n");
+		goto err_out_chrdev;
+	}
+
+	spin_lock_init(&hdmi_cec_data.irq_lock);
+
+	err = devm_request_irq(&pdev->dev, irq, mxc_hdmi_cec_isr, IRQF_SHARED,
+			dev_name(&pdev->dev), &hdmi_cec_data);
+	if (err < 0) {
+		dev_err(&pdev->dev, "hdmi_cec:Unable to request irq: %d\n", err);
+		goto err_out_chrdev;
+	}
+
+	hdmi_cec_class = class_create(THIS_MODULE, "mxc_hdmi_cec");
+	if (IS_ERR(hdmi_cec_class)) {
+		err = PTR_ERR(hdmi_cec_class);
+		goto err_out_chrdev;
+	}
+
+	temp_class = device_create(hdmi_cec_class, NULL,
+			MKDEV(hdmi_cec_major, 0), NULL, "mxc_hdmi_cec");
+	if (IS_ERR(temp_class)) {
+		err = PTR_ERR(temp_class);
+		goto err_out_class;
+	}
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		dev_err(&pdev->dev, "can't get/select CEC pinctrl\n");
+		goto err_out_class;
+	}
+
+	init_waitqueue_head(&hdmi_cec_queue);
+
+	INIT_LIST_HEAD(&head);
+
+	mutex_init(&hdmi_cec_data.lock);
+
+	hdmi_cec_data.Logical_address = 15;
+
+	platform_set_drvdata(pdev, &hdmi_cec_data);
+
+	INIT_DELAYED_WORK(&hdmi_cec_data.hdmi_cec_work, mxc_hdmi_cec_worker);
+
+	dev_info(&pdev->dev, "HDMI CEC initialized\n");
+	goto out;
+
+err_out_class:
+	device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
+	class_destroy(hdmi_cec_class);
+err_out_chrdev:
+	unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
+out:
+	return err;
+}
+
+static int hdmi_cec_dev_remove(struct platform_device *pdev)
+{
+	if (hdmi_cec_major > 0) {
+		device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
+		class_destroy(hdmi_cec_class);
+		unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
+		hdmi_cec_major = 0;
+	}
+	return 0;
+}
+
+static const struct of_device_id imx_hdmi_cec_match[] = {
+	{ .compatible = "fsl,imx6q-hdmi-cec", },
+	{ .compatible = "fsl,imx6dl-hdmi-cec", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver mxc_hdmi_cec_driver = {
+	.probe = hdmi_cec_dev_probe,
+	.remove = hdmi_cec_dev_remove,
+	.driver = {
+		.name = "mxc_hdmi_cec",
+		.of_match_table	= imx_hdmi_cec_match,
+	},
+};
+
+module_platform_driver(mxc_hdmi_cec_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux HDMI CEC driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxc_hdmi_cec");
+
--- linux-ein-5.4.0.orig/drivers/mxc/hdmi-cec/mxc_hdmi-cec.h
+++ linux-ein-5.4.0/drivers/mxc/hdmi-cec/mxc_hdmi-cec.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef _HDMICEC_H_
+#define _HDMICEC_H_
+#include <linux/ioctl.h>
+
+/*
+ * Ioctl definitions
+ */
+
+/* Use 'k' as magic number */
+#define HDMICEC_IOC_MAGIC  'H'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+#define HDMICEC_IOC_SETLOGICALADDRESS  \
+				_IOW(HDMICEC_IOC_MAGIC, 1, unsigned char)
+#define HDMICEC_IOC_STARTDEVICE	_IO(HDMICEC_IOC_MAGIC,  2)
+#define HDMICEC_IOC_STOPDEVICE	_IO(HDMICEC_IOC_MAGIC,  3)
+#define HDMICEC_IOC_GETPHYADDRESS	\
+				_IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4])
+
+#endif				/* !_HDMICEC_H_ */
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/ipu3/Kconfig
@@ -0,0 +1,21 @@
+config MXC_IPU_V3
+	bool
+
+config MXC_IPU_V3_PRG
+	tristate "i.MX IPUv3 prefetch gasket engine"
+	depends on MXC_IPU_V3 && MXC_IPU_V3_PRE
+	help
+	  This enables support for the IPUv3 prefetch gasket engine to
+	  support double buffer handshake control bewteen IPUv3 and
+	  prefetch engine(PRE), snoop the AXI interface for display
+	  refresh requests to memory and modify the request address to
+	  fetch the double buffered row of blocks in OCRAM.
+
+config MXC_IPU_V3_PRE
+	tristate "i.MX IPUv3 prefetch engine"
+	depends on MXC_IPU_V3
+	select MXC_IPU_V3_PRG
+	help
+	  This enables support for the IPUv3 prefetch engine to improve
+	  the system memory performance.  The engine has the capability
+	  to resolve framebuffers in tile pixel format to linear.
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/Makefile
+++ linux-ein-5.4.0/drivers/mxc/ipu3/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
+
+obj-$(CONFIG_MXC_IPU_V3_PRG) += prg.o
+obj-$(CONFIG_MXC_IPU_V3_PRE) += pre.o
+
+mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o \
+		ipu_calc_stripes_sizes.o vdoa.o ipu_pixel_clk.o
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_calc_stripes_sizes.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/math64.h>
+
+#define BPP_32 0
+#define BPP_16 3
+#define BPP_8 5
+#define BPP_24 1
+#define BPP_12 4
+#define BPP_18 2
+
+static u32 truncate(u32 up, /* 0: down; else: up */
+					u64 a, /* must be non-negative */
+					u32 b)
+{
+	u32 d;
+	u64 div;
+	div = div_u64(a, b);
+	d = b * (div >> 32);
+	if (up && (a > (((u64)d) << 32)))
+		return d+b;
+	else
+		return d;
+}
+
+static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
+{/* return input_f */
+	unsigned int f_calculated = 0;
+	switch (pfs) {
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV444P:
+		f_calculated = 16;
+		break;
+
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		f_calculated = 8;
+		break;
+
+	case IPU_PIX_FMT_NV12:
+		f_calculated = 8;
+		break;
+
+	default:
+		f_calculated = 0;
+		break;
+
+	}
+	if (!f_calculated) {
+		switch (bpp) {
+		case BPP_32:
+			f_calculated = 2;
+			break;
+
+		case BPP_16:
+			f_calculated = 4;
+			break;
+
+		case BPP_8:
+		case BPP_24:
+			f_calculated = 8;
+			break;
+
+		case BPP_12:
+			f_calculated = 16;
+			break;
+
+		case BPP_18:
+			f_calculated = 32;
+			break;
+
+		default:
+			f_calculated = 0;
+			break;
+			}
+		}
+	return f_calculated;
+}
+
+
+static unsigned int m_calc(unsigned int pfs)
+{
+	unsigned int m_calculated = 0;
+	switch (pfs) {
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV444P:
+		m_calculated = 16;
+		break;
+
+	case IPU_PIX_FMT_NV12:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		m_calculated = 8;
+		break;
+
+	default:
+		m_calculated = 8;
+		break;
+
+	}
+	return m_calculated;
+}
+
+static int calc_split_resize_coeffs(unsigned int inSize, unsigned int outSize,
+				    unsigned int *resizeCoeff,
+				    unsigned int *downsizeCoeff)
+{
+	uint32_t tempSize;
+	uint32_t tempDownsize;
+
+	if (inSize > 4096) {
+		pr_debug("IC input size(%d) cannot exceed 4096\n",
+			inSize);
+		return -EINVAL;
+	}
+
+	if (outSize > 1024) {
+		pr_debug("IC output size(%d) cannot exceed 1024\n",
+			outSize);
+		return -EINVAL;
+	}
+
+	if ((outSize << 3) < inSize) {
+		pr_debug("IC cannot downsize more than 8:1\n");
+		return -EINVAL;
+	}
+
+	/* Compute downsizing coefficient */
+	/* Output of downsizing unit cannot be more than 1024 */
+	tempDownsize = 0;
+	tempSize = inSize;
+	while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+	       (tempDownsize < 2)) {
+		tempSize >>= 1;
+		tempDownsize++;
+	}
+	*downsizeCoeff = tempDownsize;
+
+	/* compute resizing coefficient using the following equation:
+	   resizeCoeff = M*(SI -1)/(SO - 1)
+	   where M = 2^13, SI - input size, SO - output size    */
+	*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+	if (*resizeCoeff >= 16384L) {
+		pr_debug("Overflow on IC resize coefficient.\n");
+		return -EINVAL;
+	}
+
+	pr_debug("resizing from %u -> %u pixels, "
+		"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+		*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+		((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+	return 0;
+}
+
+/* Stripe parameters calculator */
+/**************************************************************************
+Notes:
+MSW = the maximal width allowed for a stripe
+	i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
+cirr = the maximal inverse resizing ratio for which overlap in the input
+	is requested; typically cirr~2
+flags
+	bit 0 - equal_stripes
+		0  each stripe is allowed to have independent parameters
+		for maximal image quality
+		1  the stripes are requested to have identical parameters
+	(except the base address), for maximal performance
+	bit 1 - vertical/horizontal
+		0 horizontal
+		1 vertical
+
+If performance is the top priority (above image quality)
+	Avoid overlap, by setting CIRR = 0
+		This will also force effectively identical_stripes = 1
+	Choose IF & OF that corresponds to the same IOX/SX for both stripes
+	Choose IFW & OFW such that
+	IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
+	The function returns an error status:
+	0: no error
+	1: invalid input parameters -> aborted without result
+		Valid parameters should satisfy the following conditions
+		IFW <= OFW, otherwise downsizing is required
+					 - which is not supported yet
+		4 <= IFW,OFW, so some interpolation may be needed even without overlap
+		IM, OM, IF, OF should not vanish
+		2*IF <= IFW
+		so the frame can be split to two equal stripes, even without overlap
+		2*(OF+IF/irr_opt) <= OFW
+		so a valid positive INW exists even for equal stripes
+		OF <= MSW, otherwise, the left stripe cannot be sufficiently large
+		MSW < OFW, so splitting to stripes is required
+		OFW <= 2*MSW, so two stripes are sufficient
+		(this also implies that 2<=MSW)
+	2: OF is not a multiple of OM - not fully-supported yet
+	Output is produced but OW is not guaranited to be a multiple of OM
+	4: OFW reduced to be a multiple of OM
+	8: CIRR > 1: truncated to 1
+	Overlap is not supported (and not needed) y for upsizing)
+**************************************************************************/
+int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
+			   /* input frame width;>1 */
+			   unsigned int output_frame_width, /* output frame width; >1 */
+			   const unsigned int maximal_stripe_width,
+			   /* the maximal width allowed for a stripe */
+			   const unsigned long long cirr, /* see above */
+			   const unsigned int flags, /* see above */
+			   u32 input_pixelformat,/* pixel format after of read channel*/
+			   u32 output_pixelformat,/* pixel format after of write channel*/
+			   struct stripe_param *left,
+			   struct stripe_param *right)
+{
+	const unsigned int irr_frac_bits = 13;
+	const unsigned long irr_steps = 1 << irr_frac_bits;
+	const u64 dirr = ((u64)1) << (32 - 2);
+	/* The maximum relative difference allowed between the irrs */
+	const u64 cr = ((u64)4) << 32;
+	/* The importance ratio between the two terms in the cost function below */
+
+	unsigned int status;
+	unsigned int temp;
+	unsigned int onw_min;
+	unsigned int inw = 0, onw = 0, inw_best = 0;
+	/* number of pixels in the left stripe NOT hidden by the right stripe */
+	u64 irr_opt; /* the optimal inverse resizing ratio */
+	u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
+	u64 dinw; /* the misalignment between the stripes */
+	/* (measured in units of input columns) */
+	u64 difwl, difwr = 0;
+	/* The number of input columns not reflected in the output */
+	/* the resizing ratio used for the right stripe is */
+	/*   left->irr and right->irr respectively */
+	u64 cost, cost_min;
+	u64 div; /* result of division */
+	bool equal_stripes = (flags & 0x1) != 0;
+	bool vertical =      (flags & 0x2) != 0;
+
+	unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
+	unsigned int resize_coeff;
+	unsigned int downsize_coeff;
+
+	status = 0;
+
+	if (vertical) {
+		input_f = 2;
+		input_m = 8;
+		output_f = 8;
+		output_m = 2;
+	} else {
+		input_f = f_calc(input_pixelformat, 0, NULL);
+		input_m = m_calc(input_pixelformat);
+		output_f = input_m;
+		output_m = m_calc(output_pixelformat);
+	}
+	if ((input_frame_width < 4) || (output_frame_width < 4))
+		return 1;
+
+	irr_opt = div_u64((((u64)(input_frame_width - 1)) << 32),
+			  (output_frame_width - 1));
+	rr_opt = div_u64((((u64)(output_frame_width - 1)) << 32),
+			 (input_frame_width - 1));
+
+	if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
+	    || (input_frame_width < (2 * input_f))
+	    || ((((u64)output_frame_width) << 32) <
+		(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
+	    || (maximal_stripe_width < output_f)
+	    || ((output_frame_width <= maximal_stripe_width)
+		&& (equal_stripes == 0))
+	    || ((2 * maximal_stripe_width) < output_frame_width))
+		return 1;
+
+	if (output_f % output_m)
+		status += 2;
+
+	temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
+	if (temp < output_frame_width) {
+		output_frame_width = temp;
+		status += 4;
+	}
+
+	pr_debug("---------------->\n"
+		   "if  = %d\n"
+		   "im  = %d\n"
+		   "of = %d\n"
+		   "om = %d\n"
+		   "irr_opt  = %llu\n"
+		   "rr_opt   = %llu\n"
+		   "cirr     = %llu\n"
+		   "pixel in  = %08x\n"
+		   "pixel out = %08x\n"
+		   "ifw = %d\n"
+		   "ofwidth = %d\n",
+		   input_f,
+		   input_m,
+		   output_f,
+		   output_m,
+		   irr_opt,
+		   rr_opt,
+		   cirr,
+		   input_pixelformat,
+		   output_pixelformat,
+		   input_frame_width,
+		   output_frame_width
+		   );
+
+	if (equal_stripes) {
+		if ((irr_opt > cirr) /* overlap in the input is not requested */
+		    && ((input_frame_width % (input_m << 1)) == 0)
+		    && ((input_frame_width % (input_f << 1)) == 0)
+		    && ((output_frame_width % (output_m << 1)) == 0)
+		    && ((output_frame_width % (output_f << 1)) == 0)) {
+			/* without overlap */
+			left->input_width = right->input_width = right->input_column =
+				input_frame_width >> 1;
+			left->output_width = right->output_width = right->output_column =
+				output_frame_width >> 1;
+			left->input_column = 0;
+			left->output_column = 0;
+			div = div_u64(((((u64)irr_steps) << 32) *
+				       (right->input_width - 1)), (right->output_width - 1));
+			left->irr = right->irr = truncate(0, div, 1);
+		} else { /* with overlap */
+			onw = truncate(0, (((u64)output_frame_width - 1) << 32) >> 1,
+				       output_f);
+			inw = truncate(0, onw * irr_opt, input_f);
+			/* this is the maximal inw which allows the same resizing ratio */
+			/* in both stripes */
+			onw = truncate(1, (inw * rr_opt), output_f);
+			div = div_u64((((u64)(irr_steps * inw)) <<
+				       32), onw);
+			left->irr = right->irr = truncate(0, div, 1);
+			left->output_width = right->output_width =
+				output_frame_width - onw;
+			/* These are valid assignments for output_width, */
+			/* assuming output_f is a multiple of output_m */
+			div = (((u64)(left->output_width-1) * (left->irr)) << 32);
+			div = (((u64)1) << 32) + div_u64(div, irr_steps);
+
+			left->input_width = right->input_width = truncate(1, div, input_m);
+
+			div = div_u64((((u64)((right->output_width - 1) * right->irr)) <<
+				       32), irr_steps);
+			difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+			div = div_u64((difwr + (((u64)input_f) << 32)), 2);
+			left->input_column = truncate(0, div, input_f);
+
+
+			/* This splits the truncated input columns evenly */
+			/*    between the left and right margins */
+			right->input_column = left->input_column + inw;
+			left->output_column = 0;
+			right->output_column = onw;
+		}
+		if (left->input_width > left->output_width) {
+			if (calc_split_resize_coeffs(left->input_width,
+						     left->output_width,
+						     &resize_coeff,
+						     &downsize_coeff) < 0)
+				return -EINVAL;
+
+			if (downsize_coeff > 0) {
+				left->irr = right->irr =
+					(downsize_coeff << 14) | resize_coeff;
+			}
+		}
+		pr_debug("inw %d, onw %d, ilw %d, ilc %d, olw %d,"
+			 " irw %d, irc %d, orw %d, orc %d, "
+			 "difwr  %llu, lirr %u\n",
+			 inw, onw, left->input_width,
+			 left->input_column, left->output_width,
+			 right->input_width, right->input_column,
+			 right->output_width,
+			 right->output_column, difwr, left->irr);
+		} else { /* independent stripes */
+		onw_min = output_frame_width - maximal_stripe_width;
+		/* onw is a multiple of output_f, in the range */
+		/* [max(output_f,output_frame_width-maximal_stripe_width),*/
+		/*min(output_frame_width-2,maximal_stripe_width)] */
+		/* definitely beyond the cost of any valid setting */
+		cost_min = (((u64)input_frame_width) << 32) + cr;
+		onw = truncate(0, ((u64)maximal_stripe_width), output_f);
+		if (output_frame_width - onw == 1)
+			onw -= output_f; /*  => onw and output_frame_width-1-onw are positive */
+		inw = truncate(0, onw * irr_opt, input_f);
+		/* this is the maximal inw which allows the same resizing ratio */
+		/* in both stripes */
+		onw = truncate(1, inw * rr_opt, output_f);
+		do {
+			div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
+			left->irr = truncate(0, div, 1);
+			div = div_u64((((u64)(onw * left->irr)) << 32),
+				      irr_steps);
+			dinw = (((u64)inw) << 32) - div;
+
+			div = div_u64((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
+				       32), irr_steps);
+
+			difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+
+			cost = difwl + (((u64)(cr * dinw)) >> 32);
+
+			if (cost < cost_min) {
+				inw_best = inw;
+				cost_min = cost;
+			}
+
+			inw -= input_f;
+			onw = truncate(1, inw * rr_opt, output_f);
+			/* This is the minimal onw which allows the same resizing ratio */
+			/*     in both stripes */
+		} while (onw >= onw_min);
+
+		inw = inw_best;
+		onw = truncate(1, inw * rr_opt, output_f);
+		div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
+		left->irr = truncate(0, div, 1);
+
+		left->output_width = onw;
+		right->output_width = output_frame_width - onw;
+		/* These are valid assignments for output_width, */
+		/* assuming output_f is a multiple of output_m */
+		left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
+		right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
+					      32, input_m);
+
+		div = div_u64((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
+			       32), (right->output_width - 1));
+		right->irr = truncate(0, div, 1);
+		temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
+		if (temp < right->irr)
+			right->irr = temp;
+		div = div_u64(((u64)((right->output_width - 1) * right->irr) <<
+			       32), irr_steps);
+		difwr = (u64)(input_frame_width - 1 - inw) - div;
+
+
+		div = div_u64((difwr + (((u64)input_f) << 32)), 2);
+		left->input_column = truncate(0, div, input_f);
+
+		/* This splits the truncated input columns evenly */
+		/*    between the left and right margins */
+		right->input_column = left->input_column + inw;
+		left->output_column = 0;
+		right->output_column = onw;
+		if (left->input_width > left->output_width) {
+			if (calc_split_resize_coeffs(left->input_width,
+						     left->output_width,
+						     &resize_coeff,
+						     &downsize_coeff) < 0)
+				return -EINVAL;
+			left->irr = (downsize_coeff << 14) | resize_coeff;
+		}
+		if (right->input_width > right->output_width) {
+			if (calc_split_resize_coeffs(right->input_width,
+						     right->output_width,
+						     &resize_coeff,
+						     &downsize_coeff) < 0)
+				return -EINVAL;
+			right->irr = (downsize_coeff << 14) | resize_coeff;
+		}
+	}
+	return status;
+}
+EXPORT_SYMBOL(ipu_calc_stripes_sizes);
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_capture.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_capture.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_capture.c
+ *
+ * @brief IPU capture dase functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+/*!
+ * _ipu_csi_mclk_set
+ *
+ * @param	ipu		ipu handler
+ * @param	pixel_clk   desired pixel clock frequency in Hz
+ * @param	csi         csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_mclk_set(struct ipu_soc *ipu, uint32_t pixel_clk, uint32_t csi)
+{
+	uint32_t temp;
+	int32_t div_ratio;
+
+	div_ratio = (clk_get_rate(ipu->ipu_clk) / pixel_clk) - 1;
+
+	if (div_ratio > 0xFF || div_ratio < 0) {
+		dev_dbg(ipu->dev, "value of pixel_clk extends normal range\n");
+		return -EINVAL;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+	temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+	ipu_csi_write(ipu, csi, temp |
+			(div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+			CSI_SENS_CONF);
+
+	return 0;
+}
+
+/*!
+ * ipu_csi_init_interface
+ *	Sets initial values for the CSI registers.
+ *	The width and height of the sensor and the actual frame size will be
+ *	set to the same values.
+ * @param	ipu		ipu handler
+ * @param	width		Sensor width
+ * @param       height		Sensor height
+ * @param       pixel_fmt	pixel format
+ * @param       cfg_param	ipu_csi_signal_cfg_t structure
+ * @param       csi             csi 0 or csi 1
+ *
+ * @return      0 for success, -EINVAL for error
+ */
+int32_t
+ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
+	uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param)
+{
+	uint32_t data = 0;
+	uint32_t csi = cfg_param.csi;
+
+	/* Set SENS_DATA_FORMAT bits (8, 9 and 10)
+	   RGB or YUV444 is 0 which is current value in data so not set
+	   explicitly
+	   This is also the default value if attempts are made to set it to
+	   something invalid. */
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_YUYV:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+		break;
+	case IPU_PIX_FMT_UYVY:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR24:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+		break;
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_GENERIC_16:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		break;
+	case IPU_PIX_FMT_RGB565:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+		break;
+	case IPU_PIX_FMT_RGB555:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set the CSI_SENS_CONF register remaining fields */
+	data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+		cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+		cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+		cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+		cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+		cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+		cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+		cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+		cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+		cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+		cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
+
+	/* Setup sensor frame size */
+	ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
+
+	/* Set CCIR registers */
+	if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
+		ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+	} else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+		if (width == 720 && height == 625) {
+			/* PAL case */
+			/*
+			 * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+			 * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+			 */
+			ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
+			/*
+			 * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+			 * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+			 */
+			ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_2);
+
+			ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+		} else if (width == 720 && height == 525) {
+			/* NTSC case */
+			/*
+			 * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+			 * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+			 */
+			ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_1);
+			/*
+			 * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+			 * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+			 */
+			ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_2);
+			ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+		} else {
+			dev_err(ipu->dev, "Unsupported CCIR656 interlaced "
+					"video mode\n");
+			mutex_unlock(&ipu->mutex_lock);
+			_ipu_put(ipu);
+			return -EINVAL;
+		}
+		_ipu_csi_ccir_err_detection_enable(ipu, csi);
+	} else if ((cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
+		ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+		_ipu_csi_ccir_err_detection_enable(ipu, csi);
+	} else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
+		   (cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
+		_ipu_csi_ccir_err_detection_disable(ipu, csi);
+	}
+
+	dev_dbg(ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+		ipu_csi_read(ipu, csi, CSI_SENS_CONF));
+	dev_dbg(ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+		ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE));
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_csi_init_interface);
+
+/*!
+ * ipu_csi_get_sensor_protocol
+ *
+ * @param	ipu		ipu handler
+ * @param	csi         csi 0 or csi 1
+ *
+ * @return	Returns sensor protocol
+ */
+int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi)
+{
+	int ret;
+	_ipu_get(ipu);
+	ret = (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
+		CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+		CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+	_ipu_put(ipu);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
+
+/*!
+ * ipu_csi_enable_mclk
+ *
+ * @param	ipu		ipu handler
+ * @param	csi         csi 0 or csi 1
+ * @param       flag        true to enable mclk, false to disable mclk
+ * @param       wait        true to wait 100ms make clock stable, false not wait
+ *
+ * @return      Returns 0 on success
+ */
+int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait)
+{
+	/* Return immediately if there is no csi_clk to manage */
+	if (ipu->csi_clk[csi] == NULL)
+		return 0;
+
+	if (flag) {
+		clk_enable(ipu->csi_clk[csi]);
+		if (wait == true)
+			msleep(10);
+	} else {
+		clk_disable(ipu->csi_clk[csi]);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_csi_enable_mclk);
+
+/*!
+ * ipu_csi_get_window_size
+ *
+ * @param	ipu		ipu handler
+ * @param	width	pointer to window width
+ * @param	height	pointer to window height
+ * @param	csi	csi 0 or csi 1
+ */
+void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi)
+{
+	uint32_t reg;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
+	*width = (reg & 0xFFFF) + 1;
+	*height = (reg >> 16 & 0xFFFF) + 1;
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_get_window_size);
+
+/*!
+ * ipu_csi_set_window_size
+ *
+ * @param	ipu		ipu handler
+ * @param	width	window width
+ * @param       height	window height
+ * @param       csi	csi 0 or csi 1
+ */
+void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi)
+{
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_size);
+
+/*!
+ * ipu_csi_set_window_pos
+ *
+ * @param	ipu		ipu handler
+ * @param       left	uint32 window x start
+ * @param       top	uint32 window y start
+ * @param       csi	csi 0 or csi 1
+ */
+void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi)
+{
+	uint32_t temp;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+	temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_pos);
+
+/*!
+ * _ipu_csi_horizontal_downsize_enable
+ *	Enable horizontal downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_horizontal_downsize_disable
+ *	Disable horizontal downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_enable
+ *	Enable vertical downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_disable
+ *	Disable vertical downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_set_test_generator
+ *
+ * @param	ipu		ipu handler
+ * @param	active       1 for active and 0 for inactive
+ * @param       r_value	     red value for the generated pattern of even pixel
+ * @param       g_value      green value for the generated pattern of even
+ *			     pixel
+ * @param       b_value      blue value for the generated pattern of even pixel
+ * @param	pixel_clk   desired pixel clock frequency in Hz
+ * @param       csi          csi 0 or csi 1
+ */
+void _ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+	uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_TST_CTRL);
+
+	if (active == false) {
+		temp &= ~CSI_TEST_GEN_MODE_EN;
+		ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+	} else {
+		/* Set sensb_mclk div_ratio*/
+		_ipu_csi_mclk_set(ipu, pix_clk, csi);
+
+		temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+			CSI_TEST_GEN_B_MASK);
+		temp |= CSI_TEST_GEN_MODE_EN;
+		temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+			(g_value << CSI_TEST_GEN_G_SHIFT) |
+			(b_value << CSI_TEST_GEN_B_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+	}
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_en
+ *	Enable error detection and correction for
+ *	CCIR interlaced mode with protection bit.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+	temp |= CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_disable
+ *	Disable error detection and correction for
+ *	CCIR interlaced mode with protection bit.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+	temp &= ~CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_set_mipi_di
+ *
+ * @param	ipu		ipu handler
+ * @param	num	MIPI data identifier 0-3 handled by CSI
+ * @param	di_val	data identifier value
+ * @param	csi	csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (di_val > 0xFFL) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_MIPI_DI);
+
+	switch (num) {
+	case IPU_CSI_MIPI_DI0:
+		temp &= ~CSI_MIPI_DI0_MASK;
+		temp |= (di_val << CSI_MIPI_DI0_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI1:
+		temp &= ~CSI_MIPI_DI1_MASK;
+		temp |= (di_val << CSI_MIPI_DI1_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI2:
+		temp &= ~CSI_MIPI_DI2_MASK;
+		temp |= (di_val << CSI_MIPI_DI2_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI3:
+		temp &= ~CSI_MIPI_DI3_MASK;
+		temp |= (di_val << CSI_MIPI_DI3_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_isp
+ *
+ * @param	ipu		ipu handler
+ * @param	skip		select frames to be skipped and set the
+ *				correspond bits to 1
+ * @param	max_ratio	number of frames in a skipping set and the
+ * 				maximum value of max_ratio is 5
+ * @param	csi		csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_isp(struct ipu_soc *ipu, uint32_t skip, uint32_t max_ratio, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (max_ratio > 5) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
+		(skip << CSI_SKIP_ISP_SHIFT);
+	ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_smfc
+ *
+ * @param	ipu		ipu handler
+ * @param	skip		select frames to be skipped and set the
+ *				correspond bits to 1
+ * @param	max_ratio	number of frames in a skipping set and the
+ *				maximum value of max_ratio is 5
+ * @param	id		csi to smfc skipping id
+ * @param	csi		csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_smfc(struct ipu_soc *ipu, uint32_t skip,
+	uint32_t max_ratio, uint32_t id, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (max_ratio > 5 || id > 3) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+			CSI_SKIP_SMFC_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+			(id << CSI_ID_2_SKIP_SHIFT) |
+			(skip << CSI_SKIP_SMFC_SHIFT);
+	ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_smfc_init
+ *	Map CSI frames to IDMAC channels.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	mipi_id		mipi id number 0-3
+ * @param	csi		csi0 or csi1
+ */
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_MAP);
+
+	switch (channel) {
+	case CSI_MEM0:
+		temp &= ~SMFC_MAP_CH0_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT;
+		break;
+	case CSI_MEM1:
+		temp &= ~SMFC_MAP_CH1_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT;
+		break;
+	case CSI_MEM2:
+		temp &= ~SMFC_MAP_CH2_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT;
+		break;
+	case CSI_MEM3:
+		temp &= ~SMFC_MAP_CH3_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT;
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_MAP);
+}
+
+/*!
+ * _ipu_smfc_set_wmc
+ *	Caution: The number of required channels,  the enabled channels
+ *	and the FIFO size per channel are configured restrictedly.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	set		set 1 or clear 0
+ * @param	level		water mark level when FIFO is on the
+ *				relative size
+ */
+void _ipu_smfc_set_wmc(struct ipu_soc *ipu, ipu_channel_t channel, bool set, uint32_t level)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_WMC);
+
+	switch (channel) {
+	case CSI_MEM0:
+		if (set == true) {
+			temp &= ~SMFC_WM0_SET_MASK;
+			temp |= level << SMFC_WM0_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM0_CLR_MASK;
+			temp |= level << SMFC_WM0_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM1:
+		if (set == true) {
+			temp &= ~SMFC_WM1_SET_MASK;
+			temp |= level << SMFC_WM1_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM1_CLR_MASK;
+			temp |= level << SMFC_WM1_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM2:
+		if (set == true) {
+			temp &= ~SMFC_WM2_SET_MASK;
+			temp |= level << SMFC_WM2_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM2_CLR_MASK;
+			temp |= level << SMFC_WM2_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM3:
+		if (set == true) {
+			temp &= ~SMFC_WM3_SET_MASK;
+			temp |= level << SMFC_WM3_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM3_CLR_MASK;
+			temp |= level << SMFC_WM3_CLR_SHIFT;
+		}
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_WMC);
+}
+
+/*!
+ * _ipu_smfc_set_burst_size
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	bs		burst size of IDMAC channel,
+ *				the value programmed here shoud be BURST_SIZE-1
+ */
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_BS);
+
+	switch (channel) {
+	case CSI_MEM0:
+		temp &= ~SMFC_BS0_MASK;
+		temp |= bs << SMFC_BS0_SHIFT;
+		break;
+	case CSI_MEM1:
+		temp &= ~SMFC_BS1_MASK;
+		temp |= bs << SMFC_BS1_SHIFT;
+		break;
+	case CSI_MEM2:
+		temp &= ~SMFC_BS2_MASK;
+		temp |= bs << SMFC_BS2_SHIFT;
+		break;
+	case CSI_MEM3:
+		temp &= ~SMFC_BS3_MASK;
+		temp |= bs << SMFC_BS3_SHIFT;
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_BS);
+}
+
+/*!
+ * _ipu_csi_init
+ *
+ * @param	ipu		ipu handler
+ * @param	channel      IDMAC channel
+ * @param	csi	     csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
+{
+	uint32_t csi_sens_conf, csi_dest;
+	int retval = 0;
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		csi_dest = CSI_DATA_DEST_IDMAC;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case CSI_PRP_VF_MEM:
+		csi_dest = CSI_DATA_DEST_IC;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	csi_sens_conf = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+	csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+	ipu_csi_write(ipu, csi, csi_sens_conf | (csi_dest <<
+		CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF);
+err:
+	return retval;
+}
+
+/*!
+ * csi_irq_handler
+ *
+ * @param	irq		interrupt id
+ * @param	dev_id		pointer to ipu handler
+ *
+ * @return	Returns if irq is handled
+ */
+static irqreturn_t csi_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_soc *ipu = dev_id;
+	struct completion *comp = &ipu->csi_comp;
+
+	complete(comp);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * _ipu_csi_wait4eof
+ *
+ * @param	ipu		ipu handler
+ * @param	channel      IDMAC channel
+ *
+ */
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	int ret;
+	int irq = 0;
+
+	if (channel == CSI_MEM0)
+		irq = IPU_IRQ_CSI0_OUT_EOF;
+	else if (channel == CSI_MEM1)
+		irq = IPU_IRQ_CSI1_OUT_EOF;
+	else if (channel == CSI_MEM2)
+		irq = IPU_IRQ_CSI2_OUT_EOF;
+	else if (channel == CSI_MEM3)
+		irq = IPU_IRQ_CSI3_OUT_EOF;
+	else if (channel == CSI_PRP_ENC_MEM)
+		irq = IPU_IRQ_PRP_ENC_OUT_EOF;
+	else if (channel == CSI_PRP_VF_MEM)
+		irq = IPU_IRQ_PRP_VF_OUT_EOF;
+	else{
+		dev_err(ipu->dev, "Not a CSI channel\n");
+		return;
+	}
+
+	init_completion(&ipu->csi_comp);
+	ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
+	if (ret < 0) {
+		dev_err(ipu->dev, "CSI irq %d in use\n", irq);
+		return;
+	}
+	ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500));
+	ipu_free_irq(ipu, irq, ipu);
+	dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_common.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_common.c
@@ -0,0 +1,3494 @@
+/*
+ * Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_common.c
+ *
+ * @brief This file contains the IPU driver common API functions.
+ *
+ * @ingroup IPU
+ */
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+static struct ipu_soc ipu_array[MXC_IPU_MAX_NUM];
+
+/* Static functions */
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc);
+static irqreturn_t ipu_err_irq_handler(int irq, void *desc);
+
+static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
+{
+	return ((uint32_t) ch >> (6 * type)) & 0x3F;
+};
+
+static inline int _ipu_is_ic_chan(uint32_t dma_chan)
+{
+	return (((dma_chan >= 11) && (dma_chan <= 22) && (dma_chan != 17) &&
+		(dma_chan != 18)));
+}
+
+static inline int _ipu_is_vdi_out_chan(uint32_t dma_chan)
+{
+	return (dma_chan == 5);
+}
+
+static inline int _ipu_is_ic_graphic_chan(uint32_t dma_chan)
+{
+	return (dma_chan == 14 || dma_chan == 15);
+}
+
+/* Either DP BG or DP FG can be graphic window */
+static inline int _ipu_is_dp_graphic_chan(uint32_t dma_chan)
+{
+	return (dma_chan == 23 || dma_chan == 27);
+}
+
+static inline int _ipu_is_irt_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 45) && (dma_chan <= 50));
+}
+
+static inline int _ipu_is_dmfc_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 23) && (dma_chan <= 29));
+}
+
+static inline int _ipu_is_trb_chan(struct ipu_soc *ipu, uint32_t dma_chan)
+{
+	return (((dma_chan == 8) || (dma_chan == 9) ||
+		 (dma_chan == 10) || (dma_chan == 13) ||
+		 (dma_chan == 21) || (dma_chan == 23) ||
+		 (dma_chan == 27) || (dma_chan == 28)) &&
+		(ipu->devtype >= IPUv3EX));
+}
+
+/*
+ * We usually use IDMAC 23 as full plane and IDMAC 27 as partial
+ * plane.
+ * IDMAC 23/24/28/41 can drive a display respectively - primary
+ * IDMAC 27 depends on IDMAC 23 - nonprimary
+ */
+static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan)
+{
+	return ((dma_chan == 23) || (dma_chan == 24) ||
+		(dma_chan == 28) || (dma_chan == 41));
+}
+
+static inline int _ipu_is_sync_irq(uint32_t irq)
+{
+	/* sync interrupt register number */
+	int reg_num = irq / 32 + 1;
+
+	return ((reg_num == 1)  || (reg_num == 2)  || (reg_num == 3)  ||
+		(reg_num == 4)  || (reg_num == 7)  || (reg_num == 8)  ||
+		(reg_num == 11) || (reg_num == 12) || (reg_num == 13) ||
+		(reg_num == 14) || (reg_num == 15));
+}
+
+static inline uint32_t tri_cur_buf_mask(uint32_t dma_chan)
+{
+	uint32_t mask = 1UL << ((dma_chan * 2) & 0x1F);
+
+	return mask * 3;
+}
+
+static inline uint32_t tri_cur_buf_shift(uint32_t dma_chan)
+{
+	uint32_t mask = 1UL << ((dma_chan * 2) & 0x1F);
+
+	return ffs(mask) - 1;
+}
+
+#define idma_is_valid(ch)	((ch) != NO_DMA)
+#define idma_mask(ch)		(idma_is_valid(ch) ? (1UL << ((ch) & 0x1F)) : 0)
+
+static inline bool idma_is_set(struct ipu_soc *ipu, uint32_t reg, uint32_t dma)
+{
+	return !!(ipu_idmac_read(ipu, reg) & idma_mask(dma));
+}
+
+static int ipu_clk_setup_enable(struct ipu_soc *ipu)
+{
+	char pixel_clk[11];
+	char pixel_clk_sel[15];
+	char pixel_clk_div[15];
+	char pixel_clk_parent0[5];
+	char pixel_clk_parent1[9];
+	char *pixel_clk_parents[2];
+	char di_clk[4];
+	char di_clk_sel[8];
+	struct clk *clk;
+	unsigned int di;
+	unsigned int ipu_id;	/* for clk naming */
+	int ret;
+
+	dev_dbg(ipu->dev, "ipu_clk = %lu\n", clk_get_rate(ipu->ipu_clk));
+
+	ipu_id = ipu->id + 1;
+
+	pixel_clk_parents[0] = pixel_clk_parent0;
+	pixel_clk_parents[1] = pixel_clk_parent1;
+
+	for (di = 0; di < 2; di++) {
+		snprintf(pixel_clk_sel, sizeof(pixel_clk_sel),
+				"ipu%u_pclk%u_sel", ipu_id, di);
+		snprintf(pixel_clk_parent0, sizeof(pixel_clk_parent0),
+				"ipu%u", ipu_id);
+		snprintf(pixel_clk_parent1, sizeof(pixel_clk_parent1),
+				"ipu%u_di%u", ipu_id, di);
+		clk = clk_register_mux_pix_clk(ipu->dev, pixel_clk_sel,
+				(const char **)pixel_clk_parents,
+				ARRAY_SIZE(pixel_clk_parents),
+				0, ipu->id, di, 0);
+		if (IS_ERR(clk)) {
+			dev_err(ipu->dev, "di%u mux clk register failed\n", di);
+			return PTR_ERR(clk);
+		}
+		ipu->pixel_clk_sel[di] = clk;
+
+		snprintf(pixel_clk_div, sizeof(pixel_clk_div),
+				"ipu%u_pclk%u_div", ipu_id, di);
+		clk = clk_register_div_pix_clk(ipu->dev, pixel_clk_div,
+					pixel_clk_sel, 0, ipu->id, di, 0);
+		if (IS_ERR(clk)) {
+			dev_err(ipu->dev, "di%u div clk register failed\n", di);
+			return PTR_ERR(clk);
+		}
+
+		snprintf(pixel_clk, sizeof(pixel_clk),
+				"ipu%u_pclk%u", ipu_id, di);
+		ipu->pixel_clk[di] = clk_register_gate_pix_clk(ipu->dev,
+					pixel_clk, pixel_clk_div,
+					CLK_SET_RATE_PARENT, ipu->id, di, 0);
+		if (IS_ERR(ipu->pixel_clk[di])) {
+			dev_err(ipu->dev,
+					"di%u gate clk register failed\n", di);
+			return PTR_ERR(ipu->pixel_clk[di]);
+		}
+
+		ret = clk_set_parent(ipu->pixel_clk_sel[di], ipu->ipu_clk);
+		if (ret) {
+			dev_err(ipu->dev, "pixel clk set parent failed\n");
+			return ret;
+		}
+
+		snprintf(di_clk, sizeof(di_clk), "di%u", di);
+		ipu->di_clk[di] = devm_clk_get(ipu->dev, di_clk);
+		if (IS_ERR(ipu->di_clk[di])) {
+			dev_err(ipu->dev, "di%u clk get failed\n", di);
+			return PTR_ERR(ipu->di_clk[di]);
+		}
+
+		snprintf(di_clk_sel, sizeof(di_clk_sel), "di%u_sel", di);
+		ipu->di_clk_sel[di] = devm_clk_get(ipu->dev, di_clk_sel);
+		if (IS_ERR(ipu->di_clk_sel[di])) {
+			dev_err(ipu->dev, "di%u sel clk get failed\n", di);
+			return PTR_ERR(ipu->di_clk_sel[di]);
+		}
+	}
+
+	return 0;
+}
+
+static int ipu_mem_reset(struct ipu_soc *ipu)
+{
+	int timeout = 1000;
+
+	ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+	while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+		if (!timeout--)
+			return -ETIME;
+		msleep(1);
+	}
+
+	return 0;
+}
+
+struct ipu_soc *ipu_get_soc(int id)
+{
+	if (id >= MXC_IPU_MAX_NUM)
+		return ERR_PTR(-ENODEV);
+	else if (!ipu_array[id].online)
+		return ERR_PTR(-ENODEV);
+	else
+		return &(ipu_array[id]);
+}
+EXPORT_SYMBOL_GPL(ipu_get_soc);
+
+void _ipu_get(struct ipu_soc *ipu)
+{
+	int ret;
+
+	ret = clk_enable(ipu->ipu_clk);
+	if (ret < 0)
+		BUG();
+}
+
+void _ipu_put(struct ipu_soc *ipu)
+{
+	clk_disable(ipu->ipu_clk);
+}
+
+void ipu_disable_hsp_clk(struct ipu_soc *ipu)
+{
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_hsp_clk);
+
+struct ipu_devtype {
+	const char *name;
+	unsigned long cm_ofs;
+	unsigned long idmac_ofs;
+	unsigned long ic_ofs;
+	unsigned long csi0_ofs;
+	unsigned long csi1_ofs;
+	unsigned long di0_ofs;
+	unsigned long di1_ofs;
+	unsigned long smfc_ofs;
+	unsigned long dc_ofs;
+	unsigned long dmfc_ofs;
+	unsigned long vdi_ofs;
+	unsigned long cpmem_ofs;
+	unsigned long srm_ofs;
+	unsigned long tpm_ofs;
+	unsigned long dc_tmpl_ofs;
+	enum ipuv3_type type;
+	bool idmac_used_bufs_present;
+};
+
+struct ipu_platform_type {
+	struct ipu_devtype devtype;
+	unsigned int ch0123_axi;
+	unsigned int ch23_axi;
+	unsigned int ch27_axi;
+	unsigned int ch28_axi;
+	unsigned int normal_axi;
+	bool smfc_idmac_12bit_3planar_bs_fixup;	/* workaround little stripes */
+	bool idmac_used_bufs_en_r;
+	bool idmac_used_bufs_en_w;
+	unsigned int idmac_used_bufs_max_r;
+	unsigned int idmac_used_bufs_max_w;
+};
+
+static struct ipu_platform_type ipu_type_imx51 = {
+	.devtype = {
+		.name =		"IPUv3EX",
+		.cm_ofs =	0x1E000000,
+		.idmac_ofs =	0x1E008000,
+		.ic_ofs =	0x1E020000,
+		.csi0_ofs =	0x1E030000,
+		.csi1_ofs =	0x1E038000,
+		.di0_ofs =	0x1E040000,
+		.di1_ofs =	0x1E048000,
+		.smfc_ofs =	0x1E050000,
+		.dc_ofs =	0x1E058000,
+		.dmfc_ofs =	0x1E060000,
+		.vdi_ofs =	0x1E068000,
+		.cpmem_ofs =	0x1F000000,
+		.srm_ofs =	0x1F040000,
+		.tpm_ofs =	0x1F060000,
+		.dc_tmpl_ofs =	0x1F080000,
+		.type =		IPUv3EX,
+		.idmac_used_bufs_present = false,
+	},
+	.ch0123_axi = 1,
+	.ch23_axi = 1,
+	.ch23_axi = 1,
+	.ch27_axi = 1,
+	.ch28_axi = 1,
+	.normal_axi = 0,
+	.smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx53 = {
+	.devtype = {
+		.name =		"IPUv3M",
+		.cm_ofs =	0x06000000,
+		.idmac_ofs =	0x06008000,
+		.ic_ofs =	0x06020000,
+		.csi0_ofs =	0x06030000,
+		.csi1_ofs =	0x06038000,
+		.di0_ofs =	0x06040000,
+		.di1_ofs =	0x06048000,
+		.smfc_ofs =	0x06050000,
+		.dc_ofs =	0x06058000,
+		.dmfc_ofs =	0x06060000,
+		.vdi_ofs =	0x06068000,
+		.cpmem_ofs =	0x07000000,
+		.srm_ofs =	0x07040000,
+		.tpm_ofs =	0x07060000,
+		.dc_tmpl_ofs =	0x07080000,
+		.type =		IPUv3M,
+		.idmac_used_bufs_present = true,
+	},
+	.ch0123_axi = 1,
+	.ch23_axi = 1,
+	.ch27_axi = 1,
+	.ch28_axi = 1,
+	.normal_axi = 0,
+	.idmac_used_bufs_en_r = false,
+	.idmac_used_bufs_en_w = false,
+	.smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx6q = {
+	.devtype = {
+		.name = "IPUv3H",
+		.cm_ofs =	0x00200000,
+		.idmac_ofs =	0x00208000,
+		.ic_ofs =	0x00220000,
+		.csi0_ofs =	0x00230000,
+		.csi1_ofs =	0x00238000,
+		.di0_ofs =	0x00240000,
+		.di1_ofs =	0x00248000,
+		.smfc_ofs =	0x00250000,
+		.dc_ofs =	0x00258000,
+		.dmfc_ofs =	0x00260000,
+		.vdi_ofs =	0x00268000,
+		.cpmem_ofs =	0x00300000,
+		.srm_ofs =	0x00340000,
+		.tpm_ofs =	0x00360000,
+		.dc_tmpl_ofs =	0x00380000,
+		.type =		IPUv3H,
+		.idmac_used_bufs_present = true,
+	},
+	.ch0123_axi = 0,
+	.ch23_axi = 0,
+	.ch27_axi = 0,
+	.ch28_axi = 0,
+	.normal_axi = 1,
+	.idmac_used_bufs_en_r = false,
+	.idmac_used_bufs_en_w = false,
+	.smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx6qp = {
+	.devtype = {
+		.name = "IPUv3H",
+		.cm_ofs =	0x00200000,
+		.idmac_ofs =	0x00208000,
+		.ic_ofs =	0x00220000,
+		.csi0_ofs =	0x00230000,
+		.csi1_ofs =	0x00238000,
+		.di0_ofs =	0x00240000,
+		.di1_ofs =	0x00248000,
+		.smfc_ofs =	0x00250000,
+		.dc_ofs =	0x00258000,
+		.dmfc_ofs =	0x00260000,
+		.vdi_ofs =	0x00268000,
+		.cpmem_ofs =	0x00300000,
+		.srm_ofs =	0x00340000,
+		.tpm_ofs =	0x00360000,
+		.dc_tmpl_ofs =	0x00380000,
+		.type =		IPUv3H,
+		.idmac_used_bufs_present = true,
+	},
+	.ch0123_axi = 0,
+	.ch23_axi = 0,
+	.ch27_axi = 2,
+	.ch28_axi = 3,
+	.normal_axi = 1,
+	.idmac_used_bufs_en_r = true,
+	.idmac_used_bufs_en_w = true,
+	.idmac_used_bufs_max_r = 0x3,
+	.idmac_used_bufs_max_w = 0x3,
+	.smfc_idmac_12bit_3planar_bs_fixup = true,
+ };
+
+static const struct of_device_id imx_ipuv3_dt_ids[] = {
+	{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+	{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+	{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+	{ .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6qp, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipuv3_dt_ids);
+
+/*!
+ * This function is called by the driver framework to initialize the IPU
+ * hardware.
+ *
+ * @param	dev	The device structure for the IPU passed in by the
+ *			driver framework.
+ *
+ * @return      Returns 0 on success or negative error code on error
+ */
+static int ipu_probe(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu;
+	struct resource *res;
+	unsigned long ipu_base;
+	const struct of_device_id *of_id =
+			of_match_device(imx_ipuv3_dt_ids, &pdev->dev);
+	const struct ipu_platform_type *iputype = of_id->data;
+	const struct ipu_devtype *devtype = &iputype->devtype;
+	int ret = 0, id;
+	u32 bypass_reset, reg;
+
+	dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+					"bypass_reset", &bypass_reset);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "can not get bypass_reset\n");
+		return ret;
+	}
+
+	id = of_alias_get_id(pdev->dev.of_node, "ipu");
+	if (id < 0) {
+		dev_dbg(&pdev->dev, "can not get alias id\n");
+		return id;
+	}
+
+	ipu = &ipu_array[id];
+	memset(ipu, 0, sizeof(struct ipu_soc));
+	ipu->bypass_reset = (bool)bypass_reset;
+	ipu->dev = &pdev->dev;
+	ipu->id = id;
+	ipu->devtype = devtype->type;
+	ipu->ch0123_axi = iputype->ch0123_axi;
+	ipu->ch23_axi = iputype->ch23_axi;
+	ipu->ch27_axi = iputype->ch27_axi;
+	ipu->ch28_axi = iputype->ch28_axi;
+	ipu->normal_axi = iputype->normal_axi;
+	ipu->smfc_idmac_12bit_3planar_bs_fixup =
+			iputype->smfc_idmac_12bit_3planar_bs_fixup;
+	spin_lock_init(&ipu->int_reg_spin_lock);
+	spin_lock_init(&ipu->rdy_reg_spin_lock);
+	mutex_init(&ipu->mutex_lock);
+
+	dev_dbg(&pdev->dev, "revision is %s\n", devtype->name);
+
+	ipu->irq_sync = platform_get_irq(pdev, 0);
+	ipu->irq_err = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || ipu->irq_sync < 0 || ipu->irq_err < 0) {
+		dev_err(&pdev->dev, "can't get device resources\n");
+		return -ENODEV;
+	}
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				     resource_size(res), pdev->name))
+		return -EBUSY;
+
+	ret = devm_request_irq(&pdev->dev, ipu->irq_sync,
+			ipu_sync_irq_handler, 0, pdev->name, ipu);
+	if (ret) {
+		dev_err(ipu->dev, "request SYNC interrupt failed\n");
+		return ret;
+	}
+	ret = devm_request_irq(&pdev->dev, ipu->irq_err,
+			ipu_err_irq_handler, 0, pdev->name, ipu);
+	if (ret) {
+		dev_err(ipu->dev, "request ERR interrupt failed\n");
+		return ret;
+	}
+
+	ipu_base = res->start;
+
+	ipu->cm_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->cm_ofs, PAGE_SIZE);
+	ipu->ic_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->ic_ofs, PAGE_SIZE);
+	ipu->idmac_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->idmac_ofs, PAGE_SIZE);
+	/* DP Registers are accessed thru the SRM */
+	ipu->dp_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->srm_ofs, PAGE_SIZE);
+	ipu->dc_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->dc_ofs, PAGE_SIZE);
+	ipu->dmfc_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->dmfc_ofs, PAGE_SIZE);
+	ipu->di_reg[0] = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->di0_ofs, PAGE_SIZE);
+	ipu->di_reg[1] = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->di1_ofs, PAGE_SIZE);
+	ipu->smfc_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->smfc_ofs, PAGE_SIZE);
+	ipu->csi_reg[0] = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->csi0_ofs, PAGE_SIZE);
+	ipu->csi_reg[1] = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->csi1_ofs, PAGE_SIZE);
+	ipu->cpmem_base = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->cpmem_ofs, SZ_128K);
+	ipu->tpmem_base = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->tpm_ofs, SZ_64K);
+	ipu->dc_tmpl_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->dc_tmpl_ofs, SZ_128K);
+	ipu->vdi_reg = devm_ioremap(&pdev->dev,
+				ipu_base + devtype->vdi_ofs, PAGE_SIZE);
+	if (!ipu->cm_reg || !ipu->ic_reg || !ipu->idmac_reg ||
+		!ipu->dp_reg || !ipu->dc_reg || !ipu->dmfc_reg ||
+		!ipu->di_reg[0] || !ipu->di_reg[1] || !ipu->smfc_reg ||
+		!ipu->csi_reg[0] || !ipu->csi_reg[1] || !ipu->cpmem_base ||
+		!ipu->tpmem_base || !ipu->dc_tmpl_reg || !ipu->vdi_reg)
+		return -ENOMEM;
+
+	dev_dbg(ipu->dev, "IPU CM Regs = %p\n", ipu->cm_reg);
+	dev_dbg(ipu->dev, "IPU IC Regs = %p\n", ipu->ic_reg);
+	dev_dbg(ipu->dev, "IPU IDMAC Regs = %p\n", ipu->idmac_reg);
+	dev_dbg(ipu->dev, "IPU DP Regs = %p\n", ipu->dp_reg);
+	dev_dbg(ipu->dev, "IPU DC Regs = %p\n", ipu->dc_reg);
+	dev_dbg(ipu->dev, "IPU DMFC Regs = %p\n", ipu->dmfc_reg);
+	dev_dbg(ipu->dev, "IPU DI0 Regs = %p\n", ipu->di_reg[0]);
+	dev_dbg(ipu->dev, "IPU DI1 Regs = %p\n", ipu->di_reg[1]);
+	dev_dbg(ipu->dev, "IPU SMFC Regs = %p\n", ipu->smfc_reg);
+	dev_dbg(ipu->dev, "IPU CSI0 Regs = %p\n", ipu->csi_reg[0]);
+	dev_dbg(ipu->dev, "IPU CSI1 Regs = %p\n", ipu->csi_reg[1]);
+	dev_dbg(ipu->dev, "IPU CPMem = %p\n", ipu->cpmem_base);
+	dev_dbg(ipu->dev, "IPU TPMem = %p\n", ipu->tpmem_base);
+	dev_dbg(ipu->dev, "IPU DC Template Mem = %p\n", ipu->dc_tmpl_reg);
+	dev_dbg(ipu->dev, "IPU VDI Regs = %p\n", ipu->vdi_reg);
+
+	ipu->ipu_clk = devm_clk_get(ipu->dev, "bus");
+	if (IS_ERR(ipu->ipu_clk)) {
+		dev_err(ipu->dev, "clk_get ipu failed");
+		return PTR_ERR(ipu->ipu_clk);
+	}
+
+	/* ipu_clk is always prepared */
+	ret = clk_prepare_enable(ipu->ipu_clk);
+	if (ret < 0) {
+		dev_err(ipu->dev, "ipu clk enable failed\n");
+		return ret;
+	}
+
+	ipu->prg_clk = devm_clk_get(ipu->dev, "prg");
+	if (IS_ERR(ipu->prg_clk))
+		ipu->prg_clk = NULL;
+
+	ipu->online = true;
+
+	platform_set_drvdata(pdev, ipu);
+
+	if (!bypass_reset) {
+		ret = device_reset(&pdev->dev);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+			return ret;
+		}
+
+		ipu_mem_reset(ipu);
+
+		ipu_disp_init(ipu);
+
+		/* Set MCU_T to divide MCU access window into 2 */
+		ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+			     IPU_DISP_GEN);
+	}
+
+	/* setup ipu clk tree after ipu reset  */
+	ret = ipu_clk_setup_enable(ipu);
+	if (ret < 0) {
+		dev_err(ipu->dev, "ipu clk setup failed\n");
+		ipu->online = false;
+		return ret;
+	}
+
+	if (devtype->idmac_used_bufs_present) {
+		reg = ipu_idmac_read(ipu, IDMAC_CONF);
+		if (iputype->idmac_used_bufs_en_r)
+			reg |= IDMAC_CONF_USED_BUFS_EN_R;
+		else
+			reg &= ~IDMAC_CONF_USED_BUFS_EN_R;
+		if (iputype->idmac_used_bufs_en_w)
+			reg |= IDMAC_CONF_USED_BUFS_EN_W;
+		else
+			reg &= ~IDMAC_CONF_USED_BUFS_EN_W;
+
+		reg &= ~IDMAC_CONF_USED_BUFS_MAX_R_MASK;
+		reg |= (iputype->idmac_used_bufs_max_r <<
+			IDMAC_CONF_USED_BUFS_MAX_R_OFFSET);
+		reg &= ~IDMAC_CONF_USED_BUFS_MAX_W_MASK;
+		reg |= (iputype->idmac_used_bufs_max_w <<
+			IDMAC_CONF_USED_BUFS_MAX_W_OFFSET);
+		ipu_idmac_write(ipu, reg, IDMAC_CONF);
+	}
+
+	/* Set sync refresh channels and CSI->mem channel as high priority */
+	ipu_idmac_write(ipu, 0x18800003L, IDMAC_CHA_PRI(0));
+
+	/* Enable error interrupts by default */
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+	if (!bypass_reset)
+		clk_disable(ipu->ipu_clk);
+
+	register_ipu_device(ipu, id);
+
+	pm_runtime_enable(&pdev->dev);
+
+	return ret;
+}
+
+int ipu_remove(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	unregister_ipu_device(ipu, ipu->id);
+
+	clk_put(ipu->ipu_clk);
+
+	return 0;
+}
+
+void ipu_dump_registers(struct ipu_soc *ipu)
+{
+	dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n", ipu_cm_read(ipu, IPU_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n", ipu_idmac_read(ipu, IDMAC_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, 0)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, 32)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+	if (ipu->devtype >= IPUv3EX) {
+		dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL0 = \t0x%08X\n",
+		       ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, 0)));
+		dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL1 = \t0x%08X\n",
+		       ipu_cm_read(ipu,
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, 32)));
+	}
+	dev_dbg(ipu->dev, "DMFC_WR_CHAN = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_WR_CHAN));
+	dev_dbg(ipu->dev, "DMFC_WR_CHAN_DEF = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_WR_CHAN_DEF));
+	dev_dbg(ipu->dev, "DMFC_DP_CHAN = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_DP_CHAN));
+	dev_dbg(ipu->dev, "DMFC_DP_CHAN_DEF = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_DP_CHAN_DEF));
+	dev_dbg(ipu->dev, "DMFC_IC_CTRL = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_IC_CTRL));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+	dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+	dev_dbg(ipu->dev, "IPU_VDIC_VDI_FSIZE = \t0x%08X\n",
+	       ipu_vdi_read(ipu, VDI_FSIZE));
+	dev_dbg(ipu->dev, "IPU_VDIC_VDI_C = \t0x%08X\n",
+	       ipu_vdi_read(ipu, VDI_C));
+	dev_dbg(ipu->dev, "IPU_IC_CONF = \t0x%08X\n",
+	       ipu_ic_read(ipu, IC_CONF));
+}
+
+/*!
+ * This function is called to initialize a logical IPU channel.
+ *
+ * @param	ipu	ipu handler
+ * @param       channel Input parameter for the logical channel ID to init.
+ *
+ * @param       params  Input parameter containing union of channel
+ *                      initialization parameters.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+	int ret = 0;
+	bool bad_pixfmt;
+	uint32_t ipu_conf, reg, in_g_pixel_fmt, sec_dma;
+
+	dev_dbg(ipu->dev, "init channel = %d\n", IPU_CHAN_ID(channel));
+
+	ret = pm_runtime_get_sync(ipu->dev);
+	if (ret < 0) {
+		dev_err(ipu->dev, "ch = %d, pm_runtime_get failed:%d!\n",
+				IPU_CHAN_ID(channel), ret);
+		dump_stack();
+		return ret;
+	}
+	/*
+	 * Here, ret could be 1 if the device's runtime PM status was
+	 * already 'active', so clear it to be 0.
+	 */
+	ret = 0;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	/* Re-enable error interrupts every time a channel is initialized */
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+	ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+	if (ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
+		dev_warn(ipu->dev, "Warning: channel already initialized %d\n",
+			IPU_CHAN_ID(channel));
+	}
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		if (params->csi_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (params->csi_mem.interlaced)
+			ipu->chan_is_interlaced[channel_2_dma(channel,
+				IPU_OUTPUT_BUFFER)] = true;
+		else
+			ipu->chan_is_interlaced[channel_2_dma(channel,
+				IPU_OUTPUT_BUFFER)] = false;
+
+		ipu->smfc_use_count++;
+		ipu->csi_channel[params->csi_mem.csi] = channel;
+
+		/*SMFC setting*/
+		if (params->csi_mem.mipi_en) {
+			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_mem.csi));
+			_ipu_smfc_init(ipu, channel, params->csi_mem.mipi_vc,
+				params->csi_mem.csi);
+			_ipu_csi_set_mipi_di(ipu, params->csi_mem.mipi_vc,
+				params->csi_mem.mipi_id, params->csi_mem.csi);
+		} else {
+			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_mem.csi));
+			_ipu_smfc_init(ipu, channel, 0, params->csi_mem.csi);
+		}
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_mem.csi);
+		break;
+	case CSI_PRP_ENC_MEM:
+		if (params->csi_prp_enc_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+		if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+			(ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = CSI_PRP_ENC_MEM;
+
+		ipu->ic_use_count++;
+		ipu->csi_channel[params->csi_prp_enc_mem.csi] = channel;
+
+		if (params->csi_prp_enc_mem.mipi_en) {
+			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_prp_enc_mem.csi));
+			_ipu_csi_set_mipi_di(ipu,
+				params->csi_prp_enc_mem.mipi_vc,
+				params->csi_prp_enc_mem.mipi_id,
+				params->csi_prp_enc_mem.csi);
+		} else
+			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_prp_enc_mem.csi));
+
+		/*CSI0/1 feed into IC*/
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+		if (params->csi_prp_enc_mem.csi)
+			ipu_conf |= IPU_CONF_CSI_SEL;
+		else
+			ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+		/*PRP skip buffer in memory, only valid when RWS_EN is true*/
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_prp_enc_mem.csi);
+		_ipu_ic_init_prpenc(ipu, params, true);
+		break;
+	case CSI_PRP_VF_MEM:
+		if (params->csi_prp_vf_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+		if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+			(ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = CSI_PRP_VF_MEM;
+
+		ipu->ic_use_count++;
+		ipu->csi_channel[params->csi_prp_vf_mem.csi] = channel;
+
+		if (params->csi_prp_vf_mem.mipi_en) {
+			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_prp_vf_mem.csi));
+			_ipu_csi_set_mipi_di(ipu,
+				params->csi_prp_vf_mem.mipi_vc,
+				params->csi_prp_vf_mem.mipi_id,
+				params->csi_prp_vf_mem.csi);
+		} else
+			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_prp_vf_mem.csi));
+
+		/*CSI0/1 feed into IC*/
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+		if (params->csi_prp_vf_mem.csi)
+			ipu_conf |= IPU_CONF_CSI_SEL;
+		else
+			ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+		/*PRP skip buffer in memory, only valid when RWS_EN is true*/
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_prp_vf_mem.csi);
+		_ipu_ic_init_prpvf(ipu, params, true);
+		break;
+	case MEM_PRP_VF_MEM:
+		if (params->mem_prp_vf_mem.graphics_combine_en) {
+			sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+			in_g_pixel_fmt = params->mem_prp_vf_mem.in_g_pixel_fmt;
+			bad_pixfmt =
+				_ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+			if (params->mem_prp_vf_mem.alpha_chan_en) {
+				if (bad_pixfmt) {
+					dev_err(ipu->dev, "bad pixel format "
+						"for graphics plane from "
+						"ch%d\n", sec_dma);
+					ret = -EINVAL;
+					goto err;
+				}
+				ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+			}
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		}
+
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg | FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		_ipu_ic_init_prpvf(ipu, params, false);
+		ipu->ic_use_count++;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+			(ipu->using_ic_dirct_ch == MEM_VDI_MEM) ||
+		     (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = MEM_VDI_PRP_VF_MEM;
+		ipu->ic_use_count++;
+		ipu->vdi_use_count++;
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		reg &= ~FS_VDI_SRC_SEL_MASK;
+		ipu_cm_write(ipu, reg , IPU_FS_PROC_FLOW1);
+
+		if (params->mem_prp_vf_mem.graphics_combine_en)
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		_ipu_ic_init_prpvf(ipu, params, false);
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+	case MEM_VDI_PRP_VF_MEM_N:
+	case MEM_VDI_MEM_P:
+	case MEM_VDI_MEM_N:
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_VDI_MEM:
+		if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+			(ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+		     (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = MEM_VDI_MEM;
+		ipu->ic_use_count++;
+		ipu->vdi_use_count++;
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_ROT_VF_MEM:
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		_ipu_ic_init_rotate_vf(ipu, params);
+		break;
+	case MEM_PRP_ENC_MEM:
+		ipu->ic_use_count++;
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg | FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+		_ipu_ic_init_prpenc(ipu, params, false);
+		break;
+	case MEM_ROT_ENC_MEM:
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		_ipu_ic_init_rotate_enc(ipu, params);
+		break;
+	case MEM_PP_MEM:
+		if (params->mem_pp_mem.graphics_combine_en) {
+			sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+			in_g_pixel_fmt = params->mem_pp_mem.in_g_pixel_fmt;
+			bad_pixfmt =
+				_ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+			if (params->mem_pp_mem.alpha_chan_en) {
+				if (bad_pixfmt) {
+					dev_err(ipu->dev, "bad pixel format "
+						"for graphics plane from "
+						"ch%d\n", sec_dma);
+					ret = -EINVAL;
+					goto err;
+				}
+				ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+			}
+
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		}
+
+		_ipu_ic_init_pp(ipu, params);
+		ipu->ic_use_count++;
+		break;
+	case MEM_ROT_PP_MEM:
+		_ipu_ic_init_rotate_pp(ipu, params);
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		break;
+	case MEM_DC_SYNC:
+		if (params->mem_dc_sync.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[1] = params->mem_dc_sync.di;
+		_ipu_dc_init(ipu, 1, params->mem_dc_sync.di,
+			     params->mem_dc_sync.interlaced,
+			     params->mem_dc_sync.out_pixel_fmt);
+		ipu->di_use_count[params->mem_dc_sync.di]++;
+		ipu->dc_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case MEM_BG_SYNC:
+		if (params->mem_dp_bg_sync.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (params->mem_dp_bg_sync.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+		ipu->dc_di_assignment[5] = params->mem_dp_bg_sync.di;
+		_ipu_dp_init(ipu, channel, params->mem_dp_bg_sync.in_pixel_fmt,
+			     params->mem_dp_bg_sync.out_pixel_fmt);
+		_ipu_dc_init(ipu, 5, params->mem_dp_bg_sync.di,
+			     params->mem_dp_bg_sync.interlaced,
+			     params->mem_dp_bg_sync.out_pixel_fmt);
+		ipu->di_use_count[params->mem_dp_bg_sync.di]++;
+		ipu->dc_use_count++;
+		ipu->dp_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case MEM_FG_SYNC:
+		_ipu_dp_init(ipu, channel, params->mem_dp_fg_sync.in_pixel_fmt,
+			     params->mem_dp_fg_sync.out_pixel_fmt);
+
+		if (params->mem_dp_fg_sync.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+		ipu->dc_use_count++;
+		ipu->dp_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case DIRECT_ASYNC0:
+		if (params->direct_async.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[8] = params->direct_async.di;
+		_ipu_dc_init(ipu, 8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+		ipu->di_use_count[params->direct_async.di]++;
+		ipu->dc_use_count++;
+		break;
+	case DIRECT_ASYNC1:
+		if (params->direct_async.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[9] = params->direct_async.di;
+		_ipu_dc_init(ipu, 9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+		ipu->di_use_count[params->direct_async.di]++;
+		ipu->dc_use_count++;
+		break;
+	default:
+		dev_err(ipu->dev, "Missing channel initialization\n");
+		break;
+	}
+
+	ipu->channel_init_mask |= 1L << IPU_CHAN_ID(channel);
+
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+err:
+	mutex_unlock(&ipu->mutex_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_init_channel);
+
+/*!
+ * This function is called to uninitialize a logical IPU channel.
+ *
+ * @param	ipu	ipu handler
+ * @param       channel Input parameter for the logical channel ID to uninit.
+ */
+void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t in_dma, out_dma = 0;
+	uint32_t ipu_conf;
+	uint32_t dc_chan = 0;
+	int ret;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	if ((ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+		dev_dbg(ipu->dev, "Channel already uninitialized %d\n",
+			IPU_CHAN_ID(channel));
+		mutex_unlock(&ipu->mutex_lock);
+		return;
+	}
+
+	/* Make sure channel is disabled */
+	/* Get input and output dma channels */
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+
+	if (idma_is_set(ipu, IDMAC_CHA_EN(in_dma), in_dma) ||
+	    idma_is_set(ipu, IDMAC_CHA_EN(out_dma), out_dma)) {
+		dev_err(ipu->dev,
+			"Channel %d is not disabled, disable first\n",
+			IPU_CHAN_ID(channel));
+		mutex_unlock(&ipu->mutex_lock);
+		return;
+	}
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+	/* Reset the double buffer */
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(in_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(out_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
+
+	/* Reset the triple buffer */
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, in_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(in_dma),
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, in_dma));
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, out_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(out_dma),
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, out_dma));
+
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) {
+		ipu->sec_chan_en[IPU_CHAN_ID(channel)] = false;
+		ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = false;
+	}
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		ipu->smfc_use_count--;
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case CSI_PRP_ENC_MEM:
+		ipu->ic_use_count--;
+		if (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpenc(ipu);
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case CSI_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		if (ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpvf(ipu);
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case MEM_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_prpvf(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		ipu->vdi_use_count--;
+		if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpvf(ipu);
+		_ipu_vdi_uninit(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_VDI_MEM:
+		ipu->ic_use_count--;
+		ipu->vdi_use_count--;
+		if (ipu->using_ic_dirct_ch == MEM_VDI_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_vdi_uninit(ipu);
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+	case MEM_VDI_PRP_VF_MEM_N:
+	case MEM_VDI_MEM_P:
+	case MEM_VDI_MEM_N:
+		break;
+	case MEM_ROT_VF_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_vf(ipu);
+		break;
+	case MEM_PRP_ENC_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_prpenc(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_ROT_ENC_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_enc(ipu);
+		break;
+	case MEM_PP_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_pp(ipu);
+		break;
+	case MEM_ROT_PP_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_pp(ipu);
+		break;
+	case MEM_DC_SYNC:
+		dc_chan = 1;
+		_ipu_dc_uninit(ipu, 1);
+		ipu->di_use_count[ipu->dc_di_assignment[1]]--;
+		ipu->dc_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case MEM_BG_SYNC:
+		dc_chan = 5;
+		_ipu_dp_uninit(ipu, channel);
+		_ipu_dc_uninit(ipu, 5);
+		ipu->di_use_count[ipu->dc_di_assignment[5]]--;
+		ipu->dc_use_count--;
+		ipu->dp_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case MEM_FG_SYNC:
+		_ipu_dp_uninit(ipu, channel);
+		ipu->dc_use_count--;
+		ipu->dp_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case DIRECT_ASYNC0:
+		dc_chan = 8;
+		_ipu_dc_uninit(ipu, 8);
+		ipu->di_use_count[ipu->dc_di_assignment[8]]--;
+		ipu->dc_use_count--;
+		break;
+	case DIRECT_ASYNC1:
+		dc_chan = 9;
+		_ipu_dc_uninit(ipu, 9);
+		ipu->di_use_count[ipu->dc_di_assignment[9]]--;
+		ipu->dc_use_count--;
+		break;
+	default:
+		break;
+	}
+
+	if (ipu->ic_use_count == 0)
+		ipu_conf &= ~IPU_CONF_IC_EN;
+	if (ipu->vdi_use_count == 0) {
+		ipu_conf &= ~IPU_CONF_ISP_EN;
+		ipu_conf &= ~IPU_CONF_VDI_EN;
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+	}
+	if (ipu->rot_use_count == 0)
+		ipu_conf &= ~IPU_CONF_ROT_EN;
+	if (ipu->dc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DC_EN;
+	if (ipu->dp_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DP_EN;
+	if (ipu->dmfc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DMFC_EN;
+	if (ipu->di_use_count[0] == 0) {
+		ipu_conf &= ~IPU_CONF_DI0_EN;
+	}
+	if (ipu->di_use_count[1] == 0) {
+		ipu_conf &= ~IPU_CONF_DI1_EN;
+	}
+	if (ipu->smfc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_SMFC_EN;
+
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	ipu->channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+	/*
+	 * Disable pixel clk and its parent clock(if the parent clock
+	 * usecount is 1) after clearing DC/DP/DI bits in IPU_CONF
+	 * register to prevent LVDS display channel starvation.
+	 */
+	if (_ipu_is_primary_disp_chan(in_dma) &&
+	    ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]]) {
+		clk_disable_unprepare(ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]);
+		ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]] = false;
+	}
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+
+	ret = pm_runtime_put_sync_suspend(ipu->dev);
+	if (ret < 0) {
+		dev_err(ipu->dev, "ch = %d, pm_runtime_put failed:%d!\n",
+				IPU_CHAN_ID(channel), ret);
+		dump_stack();
+	}
+
+	WARN_ON(ipu->ic_use_count < 0);
+	WARN_ON(ipu->vdi_use_count < 0);
+	WARN_ON(ipu->rot_use_count < 0);
+	WARN_ON(ipu->dc_use_count < 0);
+	WARN_ON(ipu->dp_use_count < 0);
+	WARN_ON(ipu->dmfc_use_count < 0);
+	WARN_ON(ipu->smfc_use_count < 0);
+}
+EXPORT_SYMBOL(ipu_uninit_channel);
+
+/*!
+ * This function is called to initialize buffer(s) for logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ *
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       rot_mode        Input parameter for rotation setting of buffer.
+ *                              A rotation setting other than
+ *                              IPU_ROTATE_VERT_FLIP
+ *                              should only be used for input buffers of
+ *                              rotation channels.
+ *
+ * @param       phyaddr_0       Input parameter buffer 0 physical address.
+ *
+ * @param       phyaddr_1       Input parameter buffer 1 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              double buffering mode.
+ *
+ * @param       phyaddr_2       Input parameter buffer 2 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              triple buffering mode, phyaddr_1 should not be
+ *                              NULL then.
+ *
+ * @param       u		private u offset for additional cropping,
+ *				zero if not used.
+ *
+ * @param       v		private v offset for additional cropping,
+ *				zero if not used.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+				ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				dma_addr_t phyaddr_2,
+				uint32_t u, uint32_t v)
+{
+	uint32_t reg;
+	uint32_t dma_chan;
+	uint32_t burst_size;
+
+	dma_chan = channel_2_dma(channel, type);
+	if (!idma_is_valid(dma_chan))
+		return -EINVAL;
+
+	if (stride < width * bytes_per_pixel(pixel_fmt))
+		stride = width * bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu->dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+	/* IC & IRT channels' width must be multiple of 8 pixels */
+	if ((_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan))
+		&& (width % 8)) {
+		dev_err(ipu->dev, "Width must be 8 pixel multiple\n");
+		return -EINVAL;
+	}
+
+	if (_ipu_is_vdi_out_chan(dma_chan) &&
+		((width < 16) || (height < 16) || (width % 2) || (height % 4))) {
+		dev_err(ipu->dev, "vdi width/height limited err\n");
+		return -EINVAL;
+	}
+
+	/* IPUv3EX and IPUv3M support triple buffer */
+	if ((!_ipu_is_trb_chan(ipu, dma_chan)) && phyaddr_2) {
+		dev_err(ipu->dev, "Chan%d doesn't support triple buffer "
+				   "mode\n", dma_chan);
+		return -EINVAL;
+	}
+	if (!phyaddr_1 && phyaddr_2) {
+		dev_err(ipu->dev, "Chan%d's buf1 physical addr is NULL for "
+				   "triple buffer mode\n", dma_chan);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ipu->mutex_lock);
+
+	/* Build parameter memory data for DMA channel */
+	_ipu_ch_param_init(ipu, dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1, phyaddr_2);
+
+	/* Set correlative channel parameter of local alpha channel */
+	if ((_ipu_is_ic_graphic_chan(dma_chan) ||
+	     _ipu_is_dp_graphic_chan(dma_chan)) &&
+	    (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] == true)) {
+		_ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, true);
+		_ipu_ch_param_set_alpha_buffer_memory(ipu, dma_chan);
+		_ipu_ch_param_set_alpha_condition_read(ipu, dma_chan);
+		/* fix alpha width as 8 and burst size as 16*/
+		_ipu_ch_params_set_alpha_width(ipu, dma_chan, 8);
+		_ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+	} else if (_ipu_is_ic_graphic_chan(dma_chan) &&
+		   ipu_pixel_format_has_alpha(pixel_fmt))
+		_ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, false);
+
+	if (rot_mode)
+		_ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
+
+	/* IC and ROT channels have restriction of 8 or 16 pix burst length */
+	if (_ipu_is_ic_chan(dma_chan) || _ipu_is_vdi_out_chan(dma_chan)) {
+		if ((width % 16) == 0)
+			_ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+		else
+			_ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+	} else if (_ipu_is_irt_chan(dma_chan)) {
+		_ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+		_ipu_ch_param_set_block_mode(ipu, dma_chan);
+	} else if (_ipu_is_dmfc_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		_ipu_dmfc_set_wait4eot(ipu, dma_chan, width);
+		_ipu_dmfc_set_burst_size(ipu, dma_chan, burst_size);
+	}
+
+	if (_ipu_disp_chan_is_interlaced(ipu, channel) ||
+		ipu->chan_is_interlaced[dma_chan])
+		_ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
+
+	if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan) ||
+		_ipu_is_vdi_out_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		_ipu_ic_idma_init(ipu, dma_chan, width, height, burst_size,
+			rot_mode);
+	} else if (_ipu_is_smfc_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		/*
+		 * This is different from IPUv3 spec, but it is confirmed
+		 * in IPUforum that SMFC burst size should be NPB[6:3]
+		 * when IDMAC works in 16-bit generic data mode.
+		 */
+		if (pixel_fmt == IPU_PIX_FMT_GENERIC)
+			/* 8 bits per pixel */
+			burst_size = burst_size >> 4;
+		else if (pixel_fmt == IPU_PIX_FMT_GENERIC_16)
+			/* 16 bits per pixel */
+			burst_size = burst_size >> 3;
+		else
+			burst_size = burst_size >> 2;
+		_ipu_smfc_set_burst_size(ipu, channel, burst_size-1);
+	}
+
+	switch (dma_chan) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		_ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch0123_axi);
+		break;
+	case 23:
+		_ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch23_axi);
+		break;
+	case 27:
+		_ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch27_axi);
+		break;
+	case 28:
+		_ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch28_axi);
+		break;
+	default:
+		_ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->normal_axi);
+		break;
+	}
+
+	if (idma_is_set(ipu, IDMAC_CHA_PRI(dma_chan), dma_chan) &&
+	    ipu->devtype == IPUv3H) {
+		uint32_t reg = IDMAC_CH_LOCK_EN_1(ipu->devtype);
+		uint32_t value = 0;
+
+		switch (dma_chan) {
+		case 5:
+			value = 0x3;
+			break;
+		case 11:
+			value = 0x3 << 2;
+			break;
+		case 12:
+			value = 0x3 << 4;
+			break;
+		case 14:
+			value = 0x3 << 6;
+			break;
+		case 15:
+			value = 0x3 << 8;
+			break;
+		case 20:
+			value = 0x3 << 10;
+			break;
+		case 21:
+			value = 0x3 << 12;
+			break;
+		case 22:
+			value = 0x3 << 14;
+			break;
+		case 23:
+			value = 0x3 << 16;
+			break;
+		case 27:
+			value = 0x3 << 18;
+			break;
+		case 28:
+			value = 0x3 << 20;
+			break;
+		case 45:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 0;
+			break;
+		case 46:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 2;
+			break;
+		case 47:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 4;
+			break;
+		case 48:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 6;
+			break;
+		case 49:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 8;
+			break;
+		case 50:
+			reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+			value = 0x3 << 10;
+			break;
+		default:
+			break;
+		}
+		value |= ipu_idmac_read(ipu, reg);
+		ipu_idmac_write(ipu, value, reg);
+	}
+
+	_ipu_ch_param_dump(ipu, dma_chan);
+
+	if (phyaddr_2 && ipu->devtype >= IPUv3EX) {
+		reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+		reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+		reg |= idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg,
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+
+		/* Set IDMAC third buffer's cpmem number */
+		/* See __ipu_ch_get_third_buf_cpmem_num() for mapping */
+		ipu_idmac_write(ipu, 0x00444047L,
+				IDMAC_SUB_ADDR_4(ipu->devtype));
+		ipu_idmac_write(ipu, 0x46004241L,
+				IDMAC_SUB_ADDR_3(ipu->devtype));
+		ipu_idmac_write(ipu, 0x00000045L,
+				IDMAC_SUB_ADDR_1(ipu->devtype));
+
+		/* Reset to buffer 0 */
+		ipu_cm_write(ipu, tri_cur_buf_mask(dma_chan),
+				IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, dma_chan));
+	} else {
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+		reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg,
+				IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+
+		reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+		if (phyaddr_1)
+			reg |= idma_mask(dma_chan);
+		else
+			reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+		/* Reset to buffer 0 */
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+				IPU_CHA_CUR_BUF(ipu->devtype, dma_chan));
+
+	}
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_channel_buffer);
+
+/*!
+ * This function is called to update the physical address of a buffer for
+ * a logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       bufNum          Input parameter for buffer number to update.
+ *                              0 or 1 are the only valid values.
+ *
+ * @param       phyaddr         Input parameter buffer physical address.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail. This function will fail if the buffer is set to ready.
+ */
+int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+				ipu_buffer_t type, uint32_t bufNum, dma_addr_t phyaddr)
+{
+	uint32_t reg;
+	int ret = 0;
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	if (bufNum == 0)
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+	else if (bufNum == 1)
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+	else
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+
+	if ((reg & idma_mask(dma_chan)) == 0)
+		_ipu_ch_param_set_buffer(ipu, dma_chan, bufNum, phyaddr);
+	else
+		ret = -EACCES;
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_buffer);
+
+/*!
+ * This function is called to update the band mode setting for
+ * a logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ *
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       band_height     Input parameter for band lines:
+ *				shoule be log2(4/8/16/32/64/128/256).
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
+				 ipu_buffer_t type, uint32_t band_height)
+{
+	uint32_t reg;
+	int ret = 0;
+	uint32_t dma_chan = channel_2_dma(channel, type);
+
+	if ((2 > band_height) || (8 < band_height))
+		return -EINVAL;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	reg = ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, dma_chan));
+	reg |= 1 << (dma_chan % 32);
+	ipu_idmac_write(ipu, reg, IDMAC_BAND_EN(ipu->devtype, dma_chan));
+
+	_ipu_ch_param_set_bandmode(ipu, dma_chan, band_height);
+	dev_dbg(ipu->dev, "dma_chan:%d, band_height:%d.\n\n",
+				dma_chan, 1 << band_height);
+	mutex_unlock(&ipu->mutex_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_set_channel_bandmode);
+
+/*!
+ * This function is called to initialize a buffer for logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       u		predefined private u offset for additional cropping,
+ *								zero if not used.
+ *
+ * @param       v		predefined private v offset for additional cropping,
+ *								zero if not used.
+ *
+ * @param			vertical_offset vertical offset for Y coordinate
+ * 								in the existed frame
+ *
+ *
+ * @param			horizontal_offset horizontal offset for X coordinate
+ * 								in the existed frame
+ *
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ *              This function will fail if any buffer is set to ready.
+ */
+
+int32_t ipu_update_channel_offset(struct ipu_soc *ipu,
+				ipu_channel_t channel, ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				uint32_t u, uint32_t v,
+				uint32_t vertical_offset, uint32_t horizontal_offset)
+{
+	int ret = 0;
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	if ((ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan)) &
+	     idma_mask(dma_chan)) ||
+	    (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan)) &
+	     idma_mask(dma_chan)) ||
+	    ((ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan)) &
+	     idma_mask(dma_chan)) &&
+	     (ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan)) &
+	      idma_mask(dma_chan)) && _ipu_is_trb_chan(ipu, dma_chan)))
+		ret = -EACCES;
+	else
+		_ipu_ch_offset_update(ipu, dma_chan, pixel_fmt, width, height, stride,
+				      u, v, 0, vertical_offset, horizontal_offset);
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_offset);
+
+int32_t ipu_get_channel_offset(uint32_t pixel_fmt,
+			       uint16_t width, uint16_t height,
+			       uint32_t stride,
+			       uint32_t u, uint32_t v,
+			       uint32_t vertical_offset, uint32_t horizontal_offset,
+			       uint32_t *u_offset, uint32_t *v_offset)
+{
+	return __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
+				    u, v, 0,
+				    vertical_offset, horizontal_offset,
+				    u_offset, v_offset);
+}
+EXPORT_SYMBOL(ipu_get_channel_offset);
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       bufNum          Input parameter for which buffer number set to
+ *                              ready state.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+			ipu_buffer_t type, uint32_t bufNum)
+{
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	/* Mark buffer to be ready. */
+	if (bufNum == 0)
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+	else if (bufNum == 1)
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+	else
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_select_buffer);
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param	ipu		ipu handler
+ * @param       bufNum          Input parameter for which buffer number set to
+ *                              ready state.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum)
+{
+
+	uint32_t dma_chan = channel_2_dma(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER);
+	uint32_t mask_bit =
+		idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_P, IPU_INPUT_BUFFER))|
+		idma_mask(dma_chan)|
+		idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_N, IPU_INPUT_BUFFER));
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	/* Mark buffers to be ready. */
+	if (bufNum == 0)
+		ipu_cm_write(ipu, mask_bit,
+				IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+	else
+		ipu_cm_write(ipu, mask_bit,
+				IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_select_multi_vdi_buffer);
+
+#define NA	-1
+static int proc_dest_sel[] = {
+	0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
+	0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 };
+static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA,
+  NA, NA, NA, NA, NA,  1,  2,  3,  4,  7,  8, NA, 8, NA };
+static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA,
+  NA, NA, NA, NA, NA,  1, NA,  2, NA,  3,  4,  4,  4,  4 };
+
+
+/*!
+ * This function links 2 channels together for automatic frame
+ * synchronization. The output of the source channel is linked to the input of
+ * the destination channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       src_ch          Input parameter for the logical channel ID of
+ *                              the source channel.
+ *
+ * @param       dest_ch         Input parameter for the logical channel ID of
+ *                              the destination channel.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+	int retval = 0;
+	uint32_t fs_proc_flow1;
+	uint32_t fs_proc_flow2;
+	uint32_t fs_proc_flow3;
+	uint32_t fs_disp_flow1;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+	fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+	fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+	switch (src_ch) {
+	case CSI_MEM0:
+		fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC0_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM1:
+		fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC1_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM2:
+		fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC2_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM3:
+		fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC3_DEST_SEL_OFFSET;
+		break;
+	case CSI_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_PRPENC_DEST_SEL_OFFSET;
+		break;
+	case CSI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PP_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PP_ROT_DEST_SEL_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPENC_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPENC_ROT_DEST_SEL_OFFSET;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_ROT_DEST_SEL_OFFSET;
+		break;
+	case MEM_VDOA_MEM:
+		fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+		if (MEM_VDI_MEM == dest_ch)
+			fs_proc_flow3 |= FS_VDOA_DEST_SEL_VDI;
+		else if (MEM_PP_MEM == dest_ch)
+			fs_proc_flow3 |= FS_VDOA_DEST_SEL_IC;
+		else {
+			retval = -EINVAL;
+			goto err;
+		}
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	switch (dest_ch) {
+	case MEM_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+		if (MEM_VDOA_MEM == src_ch)
+			fs_proc_flow1 |= FS_PP_SRC_SEL_VDOA;
+		else
+			fs_proc_flow1 |= proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+						FS_PP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PP_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PRPENC_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PRPVF_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_DC_SYNC:
+		fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC1_SRC_SEL_OFFSET;
+		break;
+	case MEM_BG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_SYNC0_SRC_SEL_OFFSET;
+		break;
+	case MEM_FG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_SYNC1_SRC_SEL_OFFSET;
+		break;
+	case MEM_DC_ASYNC:
+		fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC2_SRC_SEL_OFFSET;
+		break;
+	case MEM_BG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_ASYNC0_SRC_SEL_OFFSET;
+		break;
+	case MEM_FG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_ASYNC1_SRC_SEL_OFFSET;
+		break;
+	case MEM_VDI_MEM:
+		fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+		if (MEM_VDOA_MEM == src_ch)
+			fs_proc_flow1 |= FS_VDI_SRC_SEL_VDOA;
+		else {
+			retval = -EINVAL;
+			goto err;
+		}
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+	ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+	ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+	mutex_unlock(&ipu->mutex_lock);
+	return retval;
+}
+EXPORT_SYMBOL(ipu_link_channels);
+
+/*!
+ * This function unlinks 2 channels and disables automatic frame
+ * synchronization.
+ *
+ * @param	ipu		ipu handler
+ * @param       src_ch          Input parameter for the logical channel ID of
+ *                              the source channel.
+ *
+ * @param       dest_ch         Input parameter for the logical channel ID of
+ *                              the destination channel.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+	int retval = 0;
+	uint32_t fs_proc_flow1;
+	uint32_t fs_proc_flow2;
+	uint32_t fs_proc_flow3;
+	uint32_t fs_disp_flow1;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+	fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+	fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+	switch (src_ch) {
+	case CSI_MEM0:
+		fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+		break;
+	case CSI_MEM1:
+		fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+		break;
+	case CSI_MEM2:
+		fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+		break;
+	case CSI_MEM3:
+		fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+		break;
+	case CSI_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		break;
+	case CSI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+		break;
+	case MEM_VDOA_MEM:
+		fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	switch (dest_ch) {
+	case MEM_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_DC_SYNC:
+		fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+		break;
+	case MEM_BG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+		break;
+	case MEM_FG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+		break;
+	case MEM_DC_ASYNC:
+		fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+		break;
+	case MEM_BG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+		break;
+	case MEM_FG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+		break;
+	case MEM_VDI_MEM:
+		fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+	ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+	ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+	mutex_unlock(&ipu->mutex_lock);
+	return retval;
+}
+EXPORT_SYMBOL(ipu_unlink_channels);
+
+/*!
+ * This function check whether a logical channel was enabled.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 1 while request channel is enabled or
+ *              0 for not enabled.
+ */
+int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t in_dma;
+	uint32_t out_dma;
+
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+	if (reg & idma_mask(in_dma))
+		return 1;
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+	if (reg & idma_mask(out_dma))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(ipu_is_channel_busy);
+
+/*!
+ * This function enables a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t ipu_conf;
+	uint32_t in_dma;
+	uint32_t out_dma;
+	uint32_t sec_dma;
+	uint32_t thrd_dma;
+	uint32_t di = 0;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	if (ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
+		dev_err(ipu->dev, "Warning: channel already enabled %d\n",
+			IPU_CHAN_ID(channel));
+		mutex_unlock(&ipu->mutex_lock);
+		return -EACCES;
+	}
+
+	/* Get input and output dma channels */
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	switch (channel) {
+	case MEM_BG_SYNC:
+		di = ipu->dc_di_assignment[5];
+		if (ipu->di_use_count[di] > 0)
+			ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+		if (ipu->dp_use_count > 0)
+			ipu_conf |= IPU_CONF_DP_EN;
+		if (ipu->dc_use_count > 0)
+			ipu_conf |= IPU_CONF_DC_EN;
+		if (ipu->dmfc_use_count > 0)
+			ipu_conf |= IPU_CONF_DMFC_EN;
+		break;
+	case MEM_DC_SYNC:
+		di = ipu->dc_di_assignment[1];
+		if (ipu->di_use_count[di] > 0)
+			ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+		if (ipu->dc_use_count > 0)
+			ipu_conf |= IPU_CONF_DC_EN;
+		if (ipu->dmfc_use_count > 0)
+			ipu_conf |= IPU_CONF_DMFC_EN;
+		break;
+	case MEM_FG_SYNC:
+		if (ipu->dp_use_count > 0)
+			ipu_conf |= IPU_CONF_DP_EN;
+		if (ipu->dc_use_count > 0)
+			ipu_conf |= IPU_CONF_DC_EN;
+		if (ipu->dmfc_use_count > 0)
+			ipu_conf |= IPU_CONF_DMFC_EN;
+		break;
+	case DIRECT_ASYNC0:
+		di = ipu->dc_di_assignment[8];
+		/* fall through */
+	case DIRECT_ASYNC1:
+		di = ipu->dc_di_assignment[9];
+		if (ipu->di_use_count[di] > 0)
+			ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+		if (ipu->dc_use_count > 0)
+			ipu_conf |= IPU_CONF_DC_EN;
+		break;
+	case MEM_ROT_PP_MEM:
+	case MEM_ROT_ENC_MEM:
+	case MEM_ROT_VF_MEM:
+		if (ipu->rot_use_count > 0)
+			ipu_conf |= IPU_CONF_ROT_EN;
+		/* fall through */
+	case MEM_PP_MEM:
+	case MEM_PRP_ENC_MEM:
+	case MEM_PRP_VF_MEM:
+	case CSI_PRP_ENC_MEM:
+	case CSI_PRP_VF_MEM:
+		if (ipu->ic_use_count > 0)
+			ipu_conf |= IPU_CONF_IC_EN;
+		break;
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		if (ipu->smfc_use_count > 0)
+			ipu_conf |= IPU_CONF_SMFC_EN;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+	case MEM_VDI_MEM:
+		if (ipu->vdi_use_count > 0) {
+			ipu_conf |= IPU_CONF_ISP_EN;
+			ipu_conf |= IPU_CONF_VDI_EN;
+			ipu_conf |= IPU_CONF_IC_INPUT;
+		}
+		if (ipu->ic_use_count > 0)
+			ipu_conf |= IPU_CONF_IC_EN;
+		break;
+	default:
+		break;
+	}
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	if (idma_is_valid(in_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+	}
+	if (idma_is_valid(out_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+	}
+
+	if ((ipu->sec_chan_en[IPU_CHAN_ID(channel)]) &&
+		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM) ||
+		 (channel == MEM_VDI_PRP_VF_MEM))) {
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+	}
+	if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM))) {
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+		ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+	} else if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+		   ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))) {
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_SEP_ALPHA);
+	}
+
+	if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
+	    (channel == MEM_FG_SYNC)) {
+		reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+
+		_ipu_dp_dc_enable(ipu, channel);
+	}
+
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+		_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+		_ipu_is_vdi_out_chan(out_dma))
+		_ipu_ic_enable_task(ipu, channel);
+
+	ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
+
+	if (ipu->prg_clk)
+		clk_prepare_enable(ipu->prg_clk);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_enable_channel);
+
+/*!
+ * This function check buffer ready for a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to clear.
+ *
+ * @param       bufNum          Input parameter for which buffer number clear
+ * 				ready state.
+ *
+ */
+int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	if (bufNum == 0)
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+	else if (bufNum == 1)
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+	else
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	if (reg & idma_mask(dma_chan))
+		return 1;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(ipu_check_buffer_ready);
+
+/*!
+ * This function clear buffer ready for a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to clear.
+ *
+ * @param       bufNum          Input parameter for which buffer number clear
+ * 				ready state.
+ *
+ */
+void _ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	uint32_t dma_ch = channel_2_dma(channel, type);
+
+	if (!idma_is_valid(dma_ch))
+		return;
+
+	ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+	if (bufNum == 0)
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF0_RDY(ipu->devtype, dma_ch));
+	else if (bufNum == 1)
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF1_RDY(ipu->devtype, dma_ch));
+	else
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF2_RDY(ipu->devtype, dma_ch));
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+}
+
+void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	_ipu_clear_buffer_ready(ipu, channel, type, bufNum);
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+}
+EXPORT_SYMBOL(ipu_clear_buffer_ready);
+
+/*!
+ * This function disables a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       wait_for_stop   Flag to set whether to wait for channel end
+ *                              of frame or return immediately.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop)
+{
+	uint32_t reg;
+	uint32_t in_dma;
+	uint32_t out_dma;
+	uint32_t sec_dma = NO_DMA;
+	uint32_t thrd_dma = NO_DMA;
+	uint16_t fg_pos_x, fg_pos_y;
+	unsigned long lock_flags;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	if ((ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+		dev_dbg(ipu->dev, "Channel already disabled %d\n",
+			IPU_CHAN_ID(channel));
+		mutex_unlock(&ipu->mutex_lock);
+		return -EACCES;
+	}
+
+	/* Get input and output dma channels */
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	if ((idma_is_valid(in_dma) &&
+		!idma_is_set(ipu, IDMAC_CHA_EN(in_dma), in_dma))
+		&& (idma_is_valid(out_dma) &&
+		!idma_is_set(ipu, IDMAC_CHA_EN(out_dma), out_dma))) {
+		mutex_unlock(&ipu->mutex_lock);
+		return -EINVAL;
+	}
+
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)])
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) {
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+	}
+
+	if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+	    (channel == MEM_DC_SYNC)) {
+		if (channel == MEM_FG_SYNC) {
+			_ipu_disp_get_window_pos(ipu, channel, &fg_pos_x, &fg_pos_y);
+			_ipu_disp_set_window_pos(ipu, channel, 0, 0);
+		}
+
+		_ipu_dp_dc_disable(ipu, channel, false);
+
+		/*
+		 * wait for BG channel EOF then disable FG-IDMAC,
+		 * it avoid FG NFB4EOF error.
+		 */
+		if ((channel == MEM_FG_SYNC) && (ipu_is_channel_busy(ipu, MEM_BG_SYNC))) {
+			int timeout = 50;
+
+			ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF),
+					IPUIRQ_2_STATREG(ipu->devtype,
+							IPU_IRQ_BG_SYNC_EOF));
+			while ((ipu_cm_read(ipu,
+				IPUIRQ_2_STATREG(ipu->devtype,
+				IPU_IRQ_BG_SYNC_EOF)) &
+				IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) {
+				msleep(10);
+				timeout -= 10;
+				if (timeout <= 0) {
+					dev_err(ipu->dev, "warning: wait for bg sync eof timeout\n");
+					break;
+				}
+			}
+		}
+	} else if (wait_for_stop && !_ipu_is_smfc_chan(out_dma) &&
+		   channel != CSI_PRP_VF_MEM && channel != CSI_PRP_ENC_MEM) {
+		while (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, in_dma),
+					in_dma) ||
+		       idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, out_dma),
+					out_dma) ||
+			(ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+			idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, sec_dma),
+					sec_dma)) ||
+			(ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+			idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, thrd_dma),
+					thrd_dma))) {
+			uint32_t irq = 0xffffffff;
+			int timeout = 50000;
+
+			if (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+					out_dma), out_dma))
+				irq = out_dma;
+			if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+				idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+						sec_dma), sec_dma))
+				irq = sec_dma;
+			if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+				idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+						thrd_dma), thrd_dma))
+				irq = thrd_dma;
+			if (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+						in_dma), in_dma))
+				irq = in_dma;
+
+			if (irq == 0xffffffff) {
+				dev_dbg(ipu->dev, "warning: no channel busy, break\n");
+				break;
+			}
+
+			ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+					IPUIRQ_2_STATREG(ipu->devtype, irq));
+
+			dev_dbg(ipu->dev, "warning: channel %d busy, need wait\n", irq);
+
+			while (((ipu_cm_read(ipu,
+					IPUIRQ_2_STATREG(ipu->devtype, irq))
+				& IPUIRQ_2_MASK(irq)) == 0) &&
+				(idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+							irq), irq))) {
+				udelay(10);
+				timeout -= 10;
+				if (timeout <= 0) {
+					ipu_dump_registers(ipu);
+					dev_err(ipu->dev, "warning: disable ipu dma channel %d during its busy state\n", irq);
+					break;
+				}
+			}
+			dev_dbg(ipu->dev, "wait_time:%d\n", 50000 - timeout);
+
+		}
+	}
+
+	if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+	    (channel == MEM_DC_SYNC)) {
+		reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+	}
+
+	/* Disable IC task */
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+		_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+		_ipu_is_vdi_out_chan(out_dma))
+		_ipu_ic_disable_task(ipu, channel);
+
+	/* Disable DMA channel(s) */
+	if (idma_is_valid(in_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+		ipu_cm_write(ipu, idma_mask(in_dma),
+				IPU_CHA_CUR_BUF(ipu->devtype, in_dma));
+		ipu_cm_write(ipu, tri_cur_buf_mask(in_dma),
+				IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, in_dma));
+	}
+	if (idma_is_valid(out_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+		ipu_cm_write(ipu, idma_mask(out_dma),
+				IPU_CHA_CUR_BUF(ipu->devtype, out_dma));
+		ipu_cm_write(ipu, tri_cur_buf_mask(out_dma),
+				IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, out_dma));
+	}
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+		ipu_cm_write(ipu, idma_mask(sec_dma),
+				IPU_CHA_CUR_BUF(ipu->devtype, sec_dma));
+	}
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+		if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) {
+			reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+			ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_SEP_ALPHA);
+		} else {
+			reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+			ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+		}
+		ipu_cm_write(ipu, idma_mask(thrd_dma),
+				IPU_CHA_CUR_BUF(ipu->devtype, thrd_dma));
+	}
+
+	if (channel == MEM_FG_SYNC)
+		_ipu_disp_set_window_pos(ipu, channel, fg_pos_x, fg_pos_y);
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	/* Set channel buffers NOT to be ready */
+	if (idma_is_valid(in_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 1);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 2);
+	}
+	if (idma_is_valid(out_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 1);
+	}
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 1);
+	}
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 1);
+	}
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+	if (ipu->prg_clk)
+		clk_disable_unprepare(ipu->prg_clk);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disable_channel);
+
+/*!
+ * This function enables CSI.
+ *
+ * @param	ipu		ipu handler
+ * @param       csi	csi num 0 or 1
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t reg;
+
+	if (csi > 1) {
+		dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+		return -EINVAL;
+	}
+
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	ipu->csi_use_count[csi]++;
+
+	if (ipu->csi_use_count[csi] == 1) {
+		reg = ipu_cm_read(ipu, IPU_CONF);
+		if (csi == 0)
+			ipu_cm_write(ipu, reg | IPU_CONF_CSI0_EN, IPU_CONF);
+		else
+			ipu_cm_write(ipu, reg | IPU_CONF_CSI1_EN, IPU_CONF);
+	}
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_enable_csi);
+
+/*!
+ * This function disables CSI.
+ *
+ * @param	ipu		ipu handler
+ * @param       csi	csi num 0 or 1
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t reg;
+
+	if (csi > 1) {
+		dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+		return -EINVAL;
+	}
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	ipu->csi_use_count[csi]--;
+	if (ipu->csi_use_count[csi] == 0) {
+		_ipu_csi_wait4eof(ipu, ipu->csi_channel[csi]);
+		reg = ipu_cm_read(ipu, IPU_CONF);
+		if (csi == 0)
+			ipu_cm_write(ipu, reg & ~IPU_CONF_CSI0_EN, IPU_CONF);
+		else
+			ipu_cm_write(ipu, reg & ~IPU_CONF_CSI1_EN, IPU_CONF);
+	}
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disable_csi);
+
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc)
+{
+	struct ipu_soc *ipu = desc;
+	int i;
+	uint32_t line, bit, int_stat, int_ctrl;
+	irqreturn_t result = IRQ_NONE;
+	const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 };
+
+	spin_lock(&ipu->int_reg_spin_lock);
+
+	for (i = 0; int_reg[i] != 0; i++) {
+		int_stat = ipu_cm_read(ipu,
+				IPU_INT_STAT(ipu->devtype, int_reg[i]));
+		int_ctrl = ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i]));
+		int_stat &= int_ctrl;
+		ipu_cm_write(ipu, int_stat,
+				IPU_INT_STAT(ipu->devtype, int_reg[i]));
+		while ((line = ffs(int_stat)) != 0) {
+			bit = --line;
+			int_stat &= ~(1UL << line);
+			line += (int_reg[i] - 1) * 32;
+			result |=
+			    ipu->irq_list[line].handler(line,
+						       ipu->irq_list[line].
+						       dev_id);
+			if (ipu->irq_list[line].flags & IPU_IRQF_ONESHOT) {
+				int_ctrl &= ~(1UL << bit);
+				ipu_cm_write(ipu, int_ctrl,
+						IPU_INT_CTRL(int_reg[i]));
+			}
+		}
+	}
+
+	spin_unlock(&ipu->int_reg_spin_lock);
+
+	return result;
+}
+
+static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
+{
+	struct ipu_soc *ipu = desc;
+	int i;
+	uint32_t int_stat;
+	const int err_reg[] = { 5, 6, 9, 10, 0 };
+
+	spin_lock(&ipu->int_reg_spin_lock);
+
+	for (i = 0; err_reg[i] != 0; i++) {
+		int_stat = ipu_cm_read(ipu,
+				IPU_INT_STAT(ipu->devtype, err_reg[i]));
+		int_stat &= ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i]));
+		if (int_stat) {
+			ipu_cm_write(ipu, int_stat,
+				IPU_INT_STAT(ipu->devtype, err_reg[i]));
+			dev_warn(ipu->dev,
+				"IPU Warning - IPU_INT_STAT_%d = 0x%08X\n",
+				err_reg[i], int_stat);
+			/* Disable interrupts so we only get error once */
+			int_stat = ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i])) &
+					~int_stat;
+			ipu_cm_write(ipu, int_stat, IPU_INT_CTRL(err_reg[i]));
+		}
+	}
+
+	spin_unlock(&ipu->int_reg_spin_lock);
+
+	return IRQ_HANDLED;
+}
+
+/*!
+ * This function enables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to enable interrupt for.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+	int ret = 0;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+	/*
+	 * Check sync interrupt handler only, since we do nothing for
+	 * error interrupts but than print out register values in the
+	 * error interrupt source handler.
+	 */
+	if (_ipu_is_sync_irq(irq) && (ipu->irq_list[irq].handler == NULL)) {
+		dev_err(ipu->dev, "handler hasn't been registered on sync "
+				  "irq %d\n", irq);
+		ret = -EACCES;
+		goto out;
+	}
+
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg |= IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_enable_irq);
+
+/*!
+ * This function disables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to disable interrupt for.
+ *
+ */
+void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg &= ~IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_irq);
+
+/*!
+ * This function clears the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to clear interrupt for.
+ *
+ */
+void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+	ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+			IPUIRQ_2_STATREG(ipu->devtype, irq));
+
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_clear_irq);
+
+/*!
+ * This function returns the current interrupt status for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @return      Returns true if the interrupt is pending/asserted or false if
+ *              the interrupt is not pending.
+ */
+bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+	reg = ipu_cm_read(ipu, IPUIRQ_2_STATREG(ipu->devtype, irq));
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+
+	if (reg & IPUIRQ_2_MASK(irq))
+		return true;
+	else
+		return false;
+}
+EXPORT_SYMBOL(ipu_get_irq_status);
+
+/*!
+ * This function registers an interrupt handler function for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @param       handler         Input parameter for address of the handler
+ *                              function.
+ *
+ * @param       irq_flags       Flags for interrupt mode. Currently not used.
+ *
+ * @param       devname         Input parameter for string name of driver
+ *                              registering the handler.
+ *
+ * @param       dev_id          Input parameter for pointer of data to be
+ *                              passed to the handler.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
+		    irqreturn_t(*handler) (int, void *),
+		    uint32_t irq_flags, const char *devname, void *dev_id)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+	int ret = 0;
+
+	BUG_ON(irq >= IPU_IRQ_COUNT);
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+	if (ipu->irq_list[irq].handler != NULL) {
+		dev_err(ipu->dev,
+			"handler already installed on irq %d\n", irq);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Check sync interrupt handler only, since we do nothing for
+	 * error interrupts but than print out register values in the
+	 * error interrupt source handler.
+	 */
+	if (_ipu_is_sync_irq(irq) && (handler == NULL)) {
+		dev_err(ipu->dev, "handler is NULL for sync irq %d\n", irq);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ipu->irq_list[irq].handler = handler;
+	ipu->irq_list[irq].flags = irq_flags;
+	ipu->irq_list[irq].dev_id = dev_id;
+	ipu->irq_list[irq].name = devname;
+
+	/* clear irq stat for previous use */
+	ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+			IPUIRQ_2_STATREG(ipu->devtype, irq));
+	/* enable the interrupt */
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg |= IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_request_irq);
+
+/*!
+ * This function unregisters an interrupt handler for the specified interrupt
+ * line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @param       dev_id          Input parameter for pointer of data to be passed
+ *                              to the handler. This must match value passed to
+ *                              ipu_request_irq().
+ *
+ */
+void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+	/* disable the interrupt */
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg &= ~IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+	if (ipu->irq_list[irq].dev_id == dev_id)
+		memset(&ipu->irq_list[irq], 0, sizeof(ipu->irq_list[irq]));
+
+	spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_free_irq);
+
+uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type)
+{
+	uint32_t reg, dma_chan;
+
+	dma_chan = channel_2_dma(channel, type);
+	if (!idma_is_valid(dma_chan))
+		return -EINVAL;
+
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+	if ((reg & idma_mask(dma_chan)) && _ipu_is_trb_chan(ipu, dma_chan)) {
+		reg = ipu_cm_read(ipu,
+				IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, dma_chan));
+		return (reg & tri_cur_buf_mask(dma_chan)) >>
+				tri_cur_buf_shift(dma_chan);
+	} else {
+		reg = ipu_cm_read(ipu, IPU_CHA_CUR_BUF(ipu->devtype, dma_chan));
+		if (reg & idma_mask(dma_chan))
+			return 1;
+		else
+			return 0;
+	}
+}
+EXPORT_SYMBOL(ipu_get_cur_buffer_idx);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t stat = 0;
+	uint32_t task_stat_reg = ipu_cm_read(ipu,
+					IPU_PROC_TASK_STAT(ipu->devtype));
+
+	switch (channel) {
+	case MEM_PRP_VF_MEM:
+		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_VF_ROT_MASK) >> TSTAT_VF_ROT_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		stat = (task_stat_reg & TSTAT_ENC_MASK) >> TSTAT_ENC_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_ENC_ROT_MASK) >>
+		    TSTAT_ENC_ROT_OFFSET;
+		break;
+	case MEM_PP_MEM:
+		stat = (task_stat_reg & TSTAT_PP_MASK) >> TSTAT_PP_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_PP_ROT_MASK) >> TSTAT_PP_ROT_OFFSET;
+		break;
+
+	default:
+		stat = TASK_STAT_IDLE;
+		break;
+	}
+	return stat;
+}
+
+/*!
+ * This function check for  a logical channel status
+ *
+ * @param	ipu		ipu handler
+ * @param	channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 0 on idle and 1 on busy.
+ *
+ */
+uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t dma_status;
+
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	dma_status = ipu_is_channel_busy(ipu, channel);
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+
+	dev_dbg(ipu->dev, "%s, dma_status:%d.\n", __func__, dma_status);
+
+	return dma_status;
+}
+EXPORT_SYMBOL(ipu_channel_status);
+
+int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+	int from_dma = channel_2_dma(from_ch, IPU_INPUT_BUFFER);
+	int to_dma = channel_2_dma(to_ch, IPU_INPUT_BUFFER);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	/* enable target channel */
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(to_dma));
+	ipu_idmac_write(ipu, reg | idma_mask(to_dma), IDMAC_CHA_EN(to_dma));
+
+	ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(to_ch);
+
+	/* switch dp dc */
+	_ipu_dp_dc_disable(ipu, from_ch, true);
+
+	/* disable source channel */
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(from_dma));
+	ipu_idmac_write(ipu, reg & ~idma_mask(from_dma), IDMAC_CHA_EN(from_dma));
+	ipu_cm_write(ipu, idma_mask(from_dma),
+				IPU_CHA_CUR_BUF(ipu->devtype, from_dma));
+	ipu_cm_write(ipu, tri_cur_buf_mask(from_dma),
+				IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, from_dma));
+
+	ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(from_ch));
+
+	spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 0);
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 1);
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 2);
+	spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_swap_channel);
+
+uint32_t bytes_per_pixel(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/*generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YUV444P:
+	case IPU_PIX_FMT_NV12:
+	case PRE_PIX_FMT_NV21:
+	case IPU_PIX_FMT_NV16:
+	case PRE_PIX_FMT_NV61:
+		return 1;
+		break;
+	case IPU_PIX_FMT_GENERIC_16:	/* generic data */
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGRA4444:
+	case IPU_PIX_FMT_BGRA5551:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_GPU16_SB_ST:
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+	case IPU_PIX_FMT_GPU16_ST:
+	case IPU_PIX_FMT_GPU16_SRT:
+		return 2;
+		break;
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		return 3;
+		break;
+	case IPU_PIX_FMT_GENERIC_32:	/*generic data */
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_GPU32_SB_ST:
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+	case IPU_PIX_FMT_GPU32_ST:
+	case IPU_PIX_FMT_GPU32_SRT:
+	case IPU_PIX_FMT_AYUV:
+		return 4;
+		break;
+	default:
+		return 1;
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(bytes_per_pixel);
+
+ipu_color_space_t format_to_colorspace(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGRA4444:
+	case IPU_PIX_FMT_BGRA5551:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_GBR24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_LVDS666:
+	case IPU_PIX_FMT_LVDS888:
+	case IPU_PIX_FMT_GPU32_SB_ST:
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+	case IPU_PIX_FMT_GPU32_ST:
+	case IPU_PIX_FMT_GPU32_SRT:
+	case IPU_PIX_FMT_GPU16_SB_ST:
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+	case IPU_PIX_FMT_GPU16_ST:
+	case IPU_PIX_FMT_GPU16_SRT:
+		return RGB;
+		break;
+
+	default:
+		return YCbCr;
+		break;
+	}
+	return RGB;
+}
+EXPORT_SYMBOL(format_to_colorspace);
+
+bool ipu_pixel_format_has_alpha(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+		break;
+	default:
+		return false;
+		break;
+	}
+	return false;
+}
+
+bool ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+	return _ipu_ch_param_bad_alpha_pos(pixel_fmt);
+}
+EXPORT_SYMBOL(ipu_ch_param_bad_alpha_pos);
+
+bool ipu_pixel_format_is_gpu_tile(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GPU32_SB_ST:
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+	case IPU_PIX_FMT_GPU32_ST:
+	case IPU_PIX_FMT_GPU32_SRT:
+	case IPU_PIX_FMT_GPU16_SB_ST:
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+	case IPU_PIX_FMT_GPU16_ST:
+	case IPU_PIX_FMT_GPU16_SRT:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_gpu_tile);
+
+bool ipu_pixel_format_is_split_gpu_tile(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GPU32_SB_ST:
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+	case IPU_PIX_FMT_GPU16_SB_ST:
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_split_gpu_tile);
+
+bool ipu_pixel_format_is_pre_yuv(uint32_t fmt)
+{
+	switch (fmt) {
+	case PRE_PIX_FMT_NV21:
+	case PRE_PIX_FMT_NV61:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_pre_yuv);
+
+bool ipu_pixel_format_is_multiplanar_yuv(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_YVU410P:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV444P:
+	case IPU_PIX_FMT_NV12:
+	case PRE_PIX_FMT_NV21:
+	case IPU_PIX_FMT_NV16:
+	case PRE_PIX_FMT_NV61:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_multiplanar_yuv);
+
+int ipu_ch_param_get_axi_id(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type)
+{
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	int axi_id;
+
+	if (!idma_is_valid(dma_chan))
+		return -EINVAL;
+
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	axi_id = _ipu_ch_param_get_axi_id(ipu, dma_chan);
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+
+	return axi_id;
+}
+EXPORT_SYMBOL(ipu_ch_param_get_axi_id);
+
+#ifdef CONFIG_PM
+int ipu_runtime_suspend(struct device *dev)
+{
+	release_bus_freq(BUS_FREQ_HIGH);
+	dev_dbg(dev, "ipu busfreq high release.\n");
+
+	return 0;
+}
+
+int ipu_runtime_resume(struct device *dev)
+{
+	request_bus_freq(BUS_FREQ_HIGH);
+	dev_dbg(dev, "ipu busfreq high requst.\n");
+
+	return 0;
+}
+
+static const struct dev_pm_ops ipu_pm_ops = {
+	SET_RUNTIME_PM_OPS(ipu_runtime_suspend, ipu_runtime_resume, NULL)
+};
+#endif
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+			.name		= "imx-ipuv3",
+			.of_match_table	= imx_ipuv3_dt_ids,
+		#ifdef CONFIG_PM
+			.pm	= &ipu_pm_ops,
+		#endif
+	},
+	.probe		= ipu_probe,
+	.remove		= ipu_remove,
+};
+
+int32_t __init ipu_gen_init(void)
+{
+	int32_t ret;
+
+	ret = platform_driver_register(&mxcipu_driver);
+	return 0;
+}
+
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+	platform_driver_unregister(&mxcipu_driver);
+}
+
+module_exit(ipu_gen_uninit);
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_device.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_device.c
@@ -0,0 +1,3766 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019,2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_device.c
+ *
+ * @brief This file contains the IPUv3 driver device interface and fops functions.
+ *
+ * @ingroup IPU
+ */
+#include <linux/clk.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <uapi/linux/sched/types.h>
+#include <linux/sched/types.h>
+#include <linux/sched/rt.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+#include "vdoa.h"
+
+#define CHECK_RETCODE(cont, str, err, label, ret)			\
+do {									\
+	if (cont) {							\
+		dev_err(t->dev, "ERR:[0x%p]-no:0x%x "#str" ret:%d,"	\
+				"line:%d\n", t, t->task_no, ret, __LINE__);\
+		if (ret != -EACCES) {					\
+			t->state = err;					\
+			goto label;					\
+		}							\
+	}								\
+} while (0)
+
+#define CHECK_RETCODE_CONT(cont, str, err, ret)				\
+do {									\
+	if (cont) {							\
+		dev_err(t->dev, "ERR:[0x%p]-no:0x%x"#str" ret:%d,"	\
+				"line:%d\n", t, t->task_no, ret, __LINE__);\
+		if (ret != -EACCES) {					\
+			if (t->state == STATE_OK)			\
+				t->state = err;				\
+		}							\
+	}								\
+} while (0)
+
+#undef DBG_IPU_PERF
+#ifdef DBG_IPU_PERF
+#define CHECK_PERF(ts)							\
+do {									\
+	getnstimeofday(ts);						\
+} while (0)
+
+#define DECLARE_PERF_VAR						\
+	struct timespec ts_queue;					\
+	struct timespec ts_dotask;					\
+	struct timespec ts_waitirq;					\
+	struct timespec ts_sche;					\
+	struct timespec ts_rel;						\
+	struct timespec ts_frame
+
+#define PRINT_TASK_STATISTICS						\
+do {									\
+	ts_queue = timespec_sub(tsk->ts_dotask, tsk->ts_queue);		\
+	ts_dotask = timespec_sub(tsk->ts_waitirq, tsk->ts_dotask);	\
+	ts_waitirq = timespec_sub(tsk->ts_inirq, tsk->ts_waitirq);	\
+	ts_sche = timespec_sub(tsk->ts_wakeup, tsk->ts_inirq);		\
+	ts_rel = timespec_sub(tsk->ts_rel, tsk->ts_wakeup);		\
+	ts_frame = timespec_sub(tsk->ts_rel, tsk->ts_queue);		\
+	dev_dbg(tsk->dev, "[0x%p] no-0x%x, ts_q:%ldus, ts_do:%ldus,"	\
+		"ts_waitirq:%ldus,ts_sche:%ldus, ts_rel:%ldus,"		\
+		"ts_frame: %ldus\n", tsk, tsk->task_no,			\
+	ts_queue.tv_nsec / NSEC_PER_USEC + ts_queue.tv_sec * USEC_PER_SEC,\
+	ts_dotask.tv_nsec / NSEC_PER_USEC + ts_dotask.tv_sec * USEC_PER_SEC,\
+	ts_waitirq.tv_nsec / NSEC_PER_USEC + ts_waitirq.tv_sec * USEC_PER_SEC,\
+	ts_sche.tv_nsec / NSEC_PER_USEC + ts_sche.tv_sec * USEC_PER_SEC,\
+	ts_rel.tv_nsec / NSEC_PER_USEC + ts_rel.tv_sec * USEC_PER_SEC,\
+	ts_frame.tv_nsec / NSEC_PER_USEC + ts_frame.tv_sec * USEC_PER_SEC); \
+	if ((ts_frame.tv_nsec/NSEC_PER_USEC + ts_frame.tv_sec*USEC_PER_SEC) > \
+		80000)	\
+		dev_dbg(tsk->dev, "ts_frame larger than 80ms [0x%p] no-0x%x.\n"\
+				, tsk, tsk->task_no);	\
+} while (0)
+#else
+#define CHECK_PERF(ts)
+#define DECLARE_PERF_VAR
+#define PRINT_TASK_STATISTICS
+#endif
+
+#define	IPU_PP_CH_VF	(IPU_TASK_ID_VF - 1)
+#define	IPU_PP_CH_PP	(IPU_TASK_ID_PP - 1)
+#define MAX_PP_CH	(IPU_TASK_ID_MAX - 1)
+#define VDOA_DEF_TIMEOUT_MS	(HZ/2)
+
+/* Strucutures and variables for exporting MXC IPU as device*/
+typedef enum {
+	STATE_OK = 0,
+	STATE_QUEUE,
+	STATE_IN_PROGRESS,
+	STATE_ERR,
+	STATE_TIMEOUT,
+	STATE_RES_TIMEOUT,
+	STATE_NO_IPU,
+	STATE_NO_IRQ,
+	STATE_IPU_BUSY,
+	STATE_IRQ_FAIL,
+	STATE_IRQ_TIMEOUT,
+	STATE_ENABLE_CHAN_FAIL,
+	STATE_DISABLE_CHAN_FAIL,
+	STATE_SEL_BUF_FAIL,
+	STATE_INIT_CHAN_FAIL,
+	STATE_LINK_CHAN_FAIL,
+	STATE_UNLINK_CHAN_FAIL,
+	STATE_INIT_CHAN_BUF_FAIL,
+	STATE_INIT_CHAN_BAND_FAIL,
+	STATE_SYS_NO_MEM,
+	STATE_VDOA_IRQ_TIMEOUT,
+	STATE_VDOA_IRQ_FAIL,
+	STATE_VDOA_TASK_FAIL,
+} ipu_state_t;
+
+enum {
+	INPUT_CHAN_VDI_P = 1,
+	INPUT_CHAN,
+	INPUT_CHAN_VDI_N,
+};
+
+struct ipu_state_msg {
+	int state;
+	char *msg;
+} state_msg[] = {
+	{STATE_OK, "ok"},
+	{STATE_QUEUE, "split queue"},
+	{STATE_IN_PROGRESS, "split in progress"},
+	{STATE_ERR, "error"},
+	{STATE_TIMEOUT, "split task timeout"},
+	{STATE_RES_TIMEOUT, "wait resource timeout"},
+	{STATE_NO_IPU, "no ipu found"},
+	{STATE_NO_IRQ, "no irq found for task"},
+	{STATE_IPU_BUSY, "ipu busy"},
+	{STATE_IRQ_FAIL, "request irq failed"},
+	{STATE_IRQ_TIMEOUT, "wait for irq timeout"},
+	{STATE_ENABLE_CHAN_FAIL, "ipu enable channel fail"},
+	{STATE_DISABLE_CHAN_FAIL, "ipu disable channel fail"},
+	{STATE_SEL_BUF_FAIL, "ipu select buf fail"},
+	{STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
+	{STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
+	{STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
+	{STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+	{STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
+	{STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
+	{STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
+	{STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
+	{STATE_VDOA_TASK_FAIL, "vdoa task fail"},
+};
+
+struct stripe_setting {
+	u32 iw;
+	u32 ih;
+	u32 ow;
+	u32 oh;
+	u32 outh_resize_ratio;
+	u32 outv_resize_ratio;
+	u32 i_left_pos;
+	u32 i_right_pos;
+	u32 i_top_pos;
+	u32 i_bottom_pos;
+	u32 o_left_pos;
+	u32 o_right_pos;
+	u32 o_top_pos;
+	u32 o_bottom_pos;
+	u32 rl_split_line;
+	u32 ud_split_line;
+};
+
+struct task_set {
+#define	NULL_MODE	0x0
+#define	IC_MODE		0x1
+#define	ROT_MODE	0x2
+#define	VDI_MODE	0x4
+#define IPU_PREPROCESS_MODE_MASK	(IC_MODE | ROT_MODE | VDI_MODE)
+/* VDOA_MODE means this task use vdoa, and VDOA has two modes:
+ * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
+ * to memory. BAND mode needs hareware sync with IPU, it is used default
+ * if connected to VDIC.
+ */
+#define	VDOA_MODE	0x8
+#define	VDOA_BAND_MODE	0x10
+	u8	mode;
+#define IC_VF	0x1
+#define IC_PP	0x2
+#define ROT_VF	0x4
+#define ROT_PP	0x8
+#define VDI_VF	0x10
+#define	VDOA_ONLY	0x20
+	u8	task;
+#define NO_SPLIT	0x0
+#define RL_SPLIT	0x1
+#define UD_SPLIT	0x2
+#define LEFT_STRIPE	0x1
+#define RIGHT_STRIPE	0x2
+#define UP_STRIPE	0x4
+#define DOWN_STRIPE	0x8
+#define SPLIT_MASK	0xF
+	u8	split_mode;
+	u8	band_lines;
+	ipu_channel_t ic_chan;
+	ipu_channel_t rot_chan;
+	ipu_channel_t vdi_ic_p_chan;
+	ipu_channel_t vdi_ic_n_chan;
+
+	u32 i_off;
+	u32 i_uoff;
+	u32 i_voff;
+	u32 istride;
+
+	u32 ov_off;
+	u32 ov_uoff;
+	u32 ov_voff;
+	u32 ovstride;
+
+	u32 ov_alpha_off;
+	u32 ov_alpha_stride;
+
+	u32 o_off;
+	u32 o_uoff;
+	u32 o_voff;
+	u32 ostride;
+
+	u32 r_fmt;
+	u32 r_width;
+	u32 r_height;
+	u32 r_stride;
+	dma_addr_t r_paddr;
+
+	struct stripe_setting sp_setting;
+};
+
+struct ipu_split_task {
+	struct ipu_task task;
+	struct ipu_task_entry *parent_task;
+	struct ipu_task_entry *child_task;
+	u32 task_no;
+};
+
+struct ipu_task_entry {
+	struct ipu_input input;
+	struct ipu_output output;
+
+	bool overlay_en;
+	struct ipu_overlay overlay;
+#define DEF_TIMEOUT_MS	1000
+#define DEF_DELAY_MS 20
+	int	timeout;
+	int	irq;
+
+	u8	task_id;
+	u8	ipu_id;
+	u8	task_in_list;
+	u8	split_done;
+	struct mutex split_lock;
+	struct mutex vdic_lock;
+	wait_queue_head_t split_waitq;
+
+	struct list_head node;
+	struct list_head split_list;
+	struct ipu_soc *ipu;
+	struct device *dev;
+	struct task_set set;
+	wait_queue_head_t task_waitq;
+	struct completion irq_comp;
+	struct kref refcount;
+	ipu_state_t state;
+	u32 task_no;
+	atomic_t done;
+	atomic_t res_free;
+	atomic_t res_get;
+
+	struct ipu_task_entry *parent;
+	char *vditmpbuf[2];
+	u32 old_save_lines;
+	u32 old_size;
+	bool buf1filled;
+	bool buf0filled;
+
+	vdoa_handle_t vdoa_handle;
+	struct vdoa_output_mem {
+		void *vaddr;
+		dma_addr_t paddr;
+		int size;
+	} vdoa_dma;
+
+#ifdef DBG_IPU_PERF
+	struct timespec ts_queue;
+	struct timespec ts_dotask;
+	struct timespec ts_waitirq;
+	struct timespec ts_inirq;
+	struct timespec ts_wakeup;
+	struct timespec ts_rel;
+#endif
+};
+
+struct ipu_channel_tabel {
+	struct mutex	lock;
+	u8		used[MXC_IPU_MAX_NUM][MAX_PP_CH];
+	u8		vdoa_used;
+};
+
+struct ipu_thread_data {
+	struct ipu_soc *ipu;
+	u32	id;
+	u32	is_vdoa;
+};
+
+struct ipu_alloc_list {
+	struct list_head list;
+	dma_addr_t phy_addr;
+	void *cpu_addr;
+	u32 size;
+	void *file_index;
+};
+
+static LIST_HEAD(ipu_alloc_list);
+static DEFINE_MUTEX(ipu_alloc_lock);
+static struct ipu_channel_tabel	ipu_ch_tbl;
+static LIST_HEAD(ipu_task_list);
+static DEFINE_SPINLOCK(ipu_task_list_lock);
+static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
+static atomic_t req_cnt;
+static atomic_t file_index = ATOMIC_INIT(1);
+static int major;
+static int max_ipu_no;
+static int thread_id;
+static atomic_t frame_no;
+static struct class *ipu_class;
+static struct device *ipu_dev;
+static int debug;
+module_param(debug, int, 0600);
+#ifdef DBG_IPU_PERF
+static struct timespec ts_frame_max;
+static u32 ts_frame_avg;
+static atomic_t frame_cnt;
+#endif
+
+static bool deinterlace_3_field(struct ipu_task_entry *t)
+{
+	return ((t->set.mode & VDI_MODE) &&
+		(t->input.deinterlace.motion != HIGH_MOTION));
+}
+
+static u32 tiled_filed_size(struct ipu_task_entry *t)
+{
+	u32 field_size;
+
+	/* note: page_align is required by VPU hw ouput buffer */
+	field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
+	return field_size;
+}
+
+static bool only_ic(u8 mode)
+{
+	mode = mode & IPU_PREPROCESS_MODE_MASK;
+	return ((mode == IC_MODE) || (mode == VDI_MODE));
+}
+
+static bool only_rot(u8 mode)
+{
+	mode = mode & IPU_PREPROCESS_MODE_MASK;
+	return (mode == ROT_MODE);
+}
+
+static bool ic_and_rot(u8 mode)
+{
+	mode = mode & IPU_PREPROCESS_MODE_MASK;
+	return ((mode == (IC_MODE | ROT_MODE)) ||
+		 (mode == (VDI_MODE | ROT_MODE)));
+}
+
+static bool need_split(struct ipu_task_entry *t)
+{
+	return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
+}
+
+unsigned int fmt_to_bpp(unsigned int pixelformat)
+{
+	u32 bpp;
+
+	switch (pixelformat) {
+	case IPU_PIX_FMT_RGB565:
+	/*interleaved 422*/
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+	/*non-interleaved 422*/
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU422P:
+		bpp = 16;
+		break;
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_YUV444P:
+		bpp = 24;
+		break;
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+		bpp = 32;
+		break;
+	/*non-interleaved 420*/
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_NV12:
+		bpp = 12;
+		break;
+	default:
+		bpp = 8;
+		break;
+	}
+	return bpp;
+}
+EXPORT_SYMBOL_GPL(fmt_to_bpp);
+
+cs_t colorspaceofpixel(int fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_ABGR32:
+		return RGB_CS;
+		break;
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_YUV444P:
+	case IPU_PIX_FMT_NV12:
+	case IPU_PIX_FMT_TILED_NV12:
+	case IPU_PIX_FMT_TILED_NV12F:
+		return YUV_CS;
+		break;
+	default:
+		return NULL_CS;
+	}
+}
+EXPORT_SYMBOL_GPL(colorspaceofpixel);
+
+int need_csc(int ifmt, int ofmt)
+{
+	cs_t ics, ocs;
+
+	ics = colorspaceofpixel(ifmt);
+	ocs = colorspaceofpixel(ofmt);
+
+	if ((ics == NULL_CS) || (ocs == NULL_CS))
+		return -1;
+	else if (ics != ocs)
+		return 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(need_csc);
+
+static int soc_max_in_width(u32 is_vdoa)
+{
+	return is_vdoa ? 8192 : 4096;
+}
+
+static int soc_max_vdi_in_width(struct ipu_soc *ipu)
+{
+	int i;
+
+	if (!ipu) {
+		for (i = 0; i < max_ipu_no; i++) {
+			ipu = ipu_get_soc(i);
+			if (!IS_ERR_OR_NULL(ipu))
+				break;
+		}
+
+		if (i == max_ipu_no)
+			return 720;
+	}
+	return IPU_MAX_VDI_IN_WIDTH(ipu->devtype);
+}
+static int soc_max_in_height(void)
+{
+	return 4096;
+}
+
+static int soc_max_out_width(void)
+{
+	/* mx51/mx53/mx6q is 1024*/
+	return 1024;
+}
+
+static int soc_max_out_height(void)
+{
+	/* mx51/mx53/mx6q is 1024*/
+	return 1024;
+}
+
+static void dump_task_info(struct ipu_task_entry *t)
+{
+	if (!debug)
+		return;
+	dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
+	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
+	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
+	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
+	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+			(void *)t, t->input.crop.pos.x);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+			(void *)t, t->input.crop.pos.y);
+	dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
+	dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
+	dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
+	dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
+	dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
+	if (t->input.deinterlace.enable) {
+		dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
+		if (t->input.deinterlace.motion != HIGH_MOTION) {
+			dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
+			dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
+				(void *)t, t->input.paddr_n);
+		} else
+			dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
+	}
+
+	dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
+	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
+	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
+	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
+	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+			(void *)t, t->output.crop.pos.x);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+			(void *)t, t->output.crop.pos.y);
+	dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
+	dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
+	dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
+	dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
+	dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
+	dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
+
+	if (t->overlay_en) {
+		dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
+				(void *)t, t->overlay.format);
+		dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
+				(void *)t, t->overlay.width);
+		dev_dbg(t->dev, "[0x%p]\theight = %d\n",
+				(void *)t, t->overlay.height);
+		dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
+				(void *)t, t->overlay.crop.w);
+		dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
+				(void *)t, t->overlay.crop.h);
+		dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+				(void *)t, t->overlay.crop.pos.x);
+		dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+				(void *)t, t->overlay.crop.pos.y);
+		dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+				(void *)t, t->overlay.paddr);
+		dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
+				(void *)t, t->set.ov_off);
+		dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
+				(void *)t, t->set.ov_uoff);
+		dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
+				(void *)t, t->set.ov_voff);
+		dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
+				(void *)t, t->set.ovstride);
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+			dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
+					(void *)t);
+			dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+					(void *)t, t->overlay.alpha.loc_alp_paddr);
+			dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
+					(void *)t, t->set.ov_alpha_off);
+			dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
+					(void *)t, t->set.ov_alpha_stride);
+		} else
+			dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
+					(void *)t, t->overlay.alpha.gvalue);
+		if (t->overlay.colorkey.enable)
+			dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
+					(void *)t, t->overlay.colorkey.value);
+	}
+
+	dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
+	dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
+				(void *)t, t->set.mode);
+	dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
+	dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
+	dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
+	dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
+}
+
+static void dump_check_err(struct device *dev, int err)
+{
+	switch (err) {
+	case IPU_CHECK_ERR_INPUT_CROP:
+		dev_err(dev, "input crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_OUTPUT_CROP:
+		dev_err(dev, "output crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_OVERLAY_CROP:
+		dev_err(dev, "overlay crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
+		dev_err(dev, "input over limitation\n");
+		break;
+	case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
+		dev_err(dev, "do not support overlay with deinterlace\n");
+		break;
+	case IPU_CHECK_ERR_OV_OUT_NO_FIT:
+		dev_err(dev,
+			"width/height of overlay and ic output should be same\n");
+		break;
+	case IPU_CHECK_ERR_PROC_NO_NEED:
+		dev_err(dev, "no ipu processing need\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
+		dev_err(dev, "split mode input width overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
+		dev_err(dev, "split mode input height overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
+		dev_err(dev, "split mode output width overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
+		dev_err(dev, "split mode output height overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_WITH_ROT:
+		dev_err(dev, "not support split mode with rotation\n");
+		break;
+	case IPU_CHECK_ERR_W_DOWNSIZE_OVER:
+		dev_err(dev, "horizontal downsizing ratio overflow\n");
+		break;
+	case IPU_CHECK_ERR_H_DOWNSIZE_OVER:
+		dev_err(dev, "vertical downsizing ratio overflow\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static void dump_check_warn(struct device *dev, int warn)
+{
+	if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
+		dev_warn(dev, "input u/v offset not 8 align\n");
+	if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
+		dev_warn(dev, "output u/v offset not 8 align\n");
+	if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
+		dev_warn(dev, "overlay u/v offset not 8 align\n");
+}
+
+static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
+{
+	if ((width == 0) || (height == 0)) {
+		pr_err("Invalid param: width=%d, height=%d\n", width, height);
+		return -EINVAL;
+	}
+
+	if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
+		(IPU_PIX_FMT_TILED_NV12F == fmt)) {
+		if (crop->w || crop->h) {
+			if (((crop->w + crop->pos.x) > width)
+			|| ((crop->h + crop->pos.y) > height)
+			|| (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			|| (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			|| (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			) {
+				pr_err("set_crop error MB align.\n");
+				return -EINVAL;
+			}
+		} else {
+			crop->pos.x = 0;
+			crop->pos.y = 0;
+			crop->w = width;
+			crop->h = height;
+			if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+			|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
+				pr_err("set_crop error w/h MB align.\n");
+				return -EINVAL;
+			}
+		}
+	} else {
+		if (crop->w || crop->h) {
+			if (((crop->w + crop->pos.x) > (width + 16))
+			|| ((crop->h + crop->pos.y) > height + 16)) {
+				pr_err("set_crop error exceeds width/height.\n");
+				return -EINVAL;
+			}
+		} else {
+			crop->pos.x = 0;
+			crop->pos.y = 0;
+			crop->w = width;
+			crop->h = height;
+		}
+		crop->w -= crop->w%8;
+		crop->h -= crop->h%8;
+	}
+
+	if ((crop->w == 0) || (crop->h == 0)) {
+		pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
+			crop->w, crop->h);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void update_offset(unsigned int fmt,
+				unsigned int width, unsigned int height,
+				unsigned int pos_x, unsigned int pos_y,
+				int *off, int *uoff, int *voff, int *stride)
+{
+	/* NOTE: u v offset should based on start point of off*/
+	switch (fmt) {
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ (width/2) * (pos_y/2) + pos_x/2;
+		/* In case height is odd, round up to even */
+		*voff = *uoff + (width/2) * ((height+1)/2);
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		*off = pos_y * width + pos_x;
+		*voff = (width * (height - pos_y) - pos_x)
+			+ (width/2) * (pos_y/2) + pos_x/2;
+		/* In case height is odd, round up to even */
+		*uoff = *voff + (width/2) * ((height+1)/2);
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		*off = pos_y * width + pos_x;
+		*voff = (width * (height - pos_y) - pos_x)
+			+ (width/2) * pos_y + pos_x/2;
+		*uoff = *voff + (width/2) * height;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ (width/2) * pos_y + pos_x/2;
+		*voff = *uoff + (width/2) * height;
+		break;
+	case IPU_PIX_FMT_YUV444P:
+		*off = pos_y * width + pos_x;
+		*uoff = width * height;
+		*voff = width * height * 2;
+		break;
+	case IPU_PIX_FMT_NV12:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ width * (pos_y/2) + pos_x;
+		break;
+	case IPU_PIX_FMT_TILED_NV12:
+		/*
+		 * tiled format, progressive:
+		 * assuming that line is aligned with MB height (aligned to 16)
+		 * offset = line * stride + (pixel / MB_width) * pixels_in_MB
+		 * = line * stride + (pixel / 16) * 256
+		 * = line * stride + pixel * 16
+		 */
+		*off = pos_y * width + (pos_x << 4);
+		*uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
+		break;
+	case IPU_PIX_FMT_TILED_NV12F:
+		/*
+		 * tiled format, interlaced:
+		 * same as above, only number of pixels in MB is 128,
+		 * instead of 256
+		 */
+		*off = (pos_y >> 1) * width + (pos_x << 3);
+		*uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
+		break;
+	default:
+		*off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
+		break;
+	}
+	*stride = width * bytes_per_pixel(fmt);
+}
+
+static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
+{
+	struct stripe_param left_stripe;
+	struct stripe_param right_stripe;
+	struct stripe_param up_stripe;
+	struct stripe_param down_stripe;
+	u32 iw, ih, ow, oh;
+	u32 max_width;
+	int ret;
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+		return IPU_CHECK_ERR_SPLIT_WITH_ROT;
+
+	iw = t->input.crop.w;
+	ih = t->input.crop.h;
+
+	ow = t->output.crop.w;
+	oh = t->output.crop.h;
+
+	memset(&left_stripe, 0, sizeof(left_stripe));
+	memset(&right_stripe, 0, sizeof(right_stripe));
+	memset(&up_stripe, 0, sizeof(up_stripe));
+	memset(&down_stripe, 0, sizeof(down_stripe));
+
+	if (t->set.split_mode & RL_SPLIT) {
+		/*
+		 * We do want equal strips: initialize stripes in case
+		 * calc_stripes returns before actually doing the calculation
+		 */
+		left_stripe.input_width = iw / 2;
+		left_stripe.output_width = ow / 2;
+		right_stripe.input_column = iw / 2;
+		right_stripe.output_column = ow / 2;
+
+		if (vdi_split)
+			max_width = soc_max_vdi_in_width(t->ipu);
+		else
+			max_width = soc_max_out_width();
+		ret = ipu_calc_stripes_sizes(iw,
+				ow,
+				max_width,
+				(((unsigned long long)1) << 32), /* 32bit for fractional*/
+				1, /* equal stripes */
+				t->input.format,
+				t->output.format,
+				&left_stripe,
+				&right_stripe);
+		if (ret < 0)
+			return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+		else if (ret)
+			dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+				 t->task_no, ret);
+		t->set.sp_setting.iw = left_stripe.input_width;
+		t->set.sp_setting.ow = left_stripe.output_width;
+		t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
+		t->set.sp_setting.i_left_pos = left_stripe.input_column;
+		t->set.sp_setting.o_left_pos = left_stripe.output_column;
+		t->set.sp_setting.i_right_pos = right_stripe.input_column;
+		t->set.sp_setting.o_right_pos = right_stripe.output_column;
+	} else {
+		t->set.sp_setting.iw = iw;
+		t->set.sp_setting.ow = ow;
+		t->set.sp_setting.outh_resize_ratio = 0;
+		t->set.sp_setting.i_left_pos = 0;
+		t->set.sp_setting.o_left_pos = 0;
+		t->set.sp_setting.i_right_pos = 0;
+		t->set.sp_setting.o_right_pos = 0;
+	}
+	if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > (iw+16))
+		return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
+	if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
+		|| (t->set.sp_setting.ow > soc_max_out_width()))
+		return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
+	if (rounddown(t->set.sp_setting.ow, 8) * 8 <=
+	    rounddown(t->set.sp_setting.iw, 8))
+		return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+
+	if (t->set.split_mode & UD_SPLIT) {
+		/*
+		 * We do want equal strips: initialize stripes in case
+		 * calc_stripes returns before actually doing the calculation
+		 */
+		up_stripe.input_width = ih / 2;
+		up_stripe.output_width = oh / 2;
+		down_stripe.input_column = ih / 2;
+		down_stripe.output_column = oh / 2;
+		ret = ipu_calc_stripes_sizes(ih,
+				oh,
+				soc_max_out_height(),
+				(((unsigned long long)1) << 32), /* 32bit for fractional*/
+				0x1 | 0x2, /* equal stripes and vertical */
+				t->input.format,
+				t->output.format,
+				&up_stripe,
+				&down_stripe);
+		if (ret < 0)
+			return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+		else if (ret)
+			dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+				 t->task_no, ret);
+		t->set.sp_setting.ih = up_stripe.input_width;
+		t->set.sp_setting.oh = up_stripe.output_width;
+		t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
+		t->set.sp_setting.i_top_pos = up_stripe.input_column;
+		t->set.sp_setting.o_top_pos = up_stripe.output_column;
+		t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
+		t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
+	} else {
+		t->set.sp_setting.ih = ih;
+		t->set.sp_setting.oh = oh;
+		t->set.sp_setting.outv_resize_ratio = 0;
+		t->set.sp_setting.i_top_pos = 0;
+		t->set.sp_setting.o_top_pos = 0;
+		t->set.sp_setting.i_bottom_pos = 0;
+		t->set.sp_setting.o_bottom_pos = 0;
+	}
+
+	/* downscale case: enforce limits */
+	if (((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > (ih))
+	     && (t->set.sp_setting.ih >= t->set.sp_setting.oh))
+		return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+	/* upscale case: relax limits because ipu_calc_stripes_sizes() may
+	   create input stripe that falls just outside of the input window */
+	else if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos)
+		 > (ih+16))
+		return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+	if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
+		|| (t->set.sp_setting.oh > soc_max_out_height()))
+		return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
+	if (rounddown(t->set.sp_setting.oh, 8) * 8 <=
+	    rounddown(t->set.sp_setting.ih, 8))
+		return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+
+	return IPU_CHECK_OK;
+}
+
+static int check_task(struct ipu_task_entry *t)
+{
+	int tmp;
+	int ret = IPU_CHECK_OK;
+	int timeout;
+	bool vdi_split = false;
+	int ocw, och;
+
+	if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
+		(IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
+		((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+			!t->input.deinterlace.enable)) {
+		ret = IPU_CHECK_ERR_NOT_SUPPORT;
+		goto done;
+	}
+
+	/* check input */
+	ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+		t->input.format);
+	if (ret < 0) {
+		ret = IPU_CHECK_ERR_INPUT_CROP;
+		goto done;
+	} else
+		update_offset(t->input.format, t->input.width, t->input.height,
+				t->input.crop.pos.x, t->input.crop.pos.y,
+				&t->set.i_off, &t->set.i_uoff,
+				&t->set.i_voff, &t->set.istride);
+
+	/* check output */
+	ret = set_crop(&t->output.crop, t->output.width, t->output.height,
+		t->output.format);
+	if (ret < 0) {
+		ret = IPU_CHECK_ERR_OUTPUT_CROP;
+		goto done;
+	} else
+		update_offset(t->output.format,
+				t->output.width, t->output.height,
+				t->output.crop.pos.x, t->output.crop.pos.y,
+				&t->set.o_off, &t->set.o_uoff,
+				&t->set.o_voff, &t->set.ostride);
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		/*
+		 * Cache output width and height and
+		 * swap them so that we may check
+		 * downsize overflow correctly.
+		 */
+		ocw = t->output.crop.h;
+		och = t->output.crop.w;
+	} else {
+		ocw = t->output.crop.w;
+		och = t->output.crop.h;
+	}
+
+	if (ocw * 8 <= t->input.crop.w) {
+		ret = IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+		goto done;
+	}
+
+	if (och * 8 <= t->input.crop.h) {
+		ret = IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+		goto done;
+	}
+
+	if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+		if ((t->input.crop.w > soc_max_in_width(1)) ||
+			(t->input.crop.h > soc_max_in_height())) {
+			ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+			goto done;
+		}
+		/* output fmt: NV12 and YUYV, now don't support resize */
+		if (((IPU_PIX_FMT_NV12 != t->output.format) &&
+				(IPU_PIX_FMT_YUYV != t->output.format)) ||
+			(t->input.crop.w != t->output.crop.w) ||
+			(t->input.crop.h != t->output.crop.h)) {
+			ret = IPU_CHECK_ERR_NOT_SUPPORT;
+			goto done;
+		}
+	}
+
+	/* check overlay if there is */
+	if (t->overlay_en) {
+		if (t->input.deinterlace.enable) {
+			ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
+			goto done;
+		}
+
+		ret = set_crop(&t->overlay.crop, t->overlay.width,
+			t->overlay.height, t->overlay.format);
+		if (ret < 0) {
+			ret = IPU_CHECK_ERR_OVERLAY_CROP;
+			goto done;
+		} else {
+			ocw = t->output.crop.w;
+			och = t->output.crop.h;
+
+			if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+				ocw = t->output.crop.h;
+				och = t->output.crop.w;
+			}
+			if ((t->overlay.crop.w != ocw) ||
+			    (t->overlay.crop.h != och)) {
+				ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
+				goto done;
+			}
+
+			update_offset(t->overlay.format,
+					t->overlay.width, t->overlay.height,
+					t->overlay.crop.pos.x, t->overlay.crop.pos.y,
+					&t->set.ov_off, &t->set.ov_uoff,
+					&t->set.ov_voff, &t->set.ovstride);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+				t->set.ov_alpha_stride = t->overlay.width;
+				t->set.ov_alpha_off = t->overlay.crop.pos.y *
+					t->overlay.width + t->overlay.crop.pos.x;
+			}
+		}
+	}
+
+	/* input overflow? */
+	if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
+		if ((t->input.crop.w > soc_max_in_width(0)) ||
+			(t->input.crop.h > soc_max_in_height())) {
+				ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+				goto done;
+		}
+	}
+
+	/* check task mode */
+	t->set.mode = NULL_MODE;
+	t->set.split_mode = NO_SPLIT;
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		/*output swap*/
+		tmp = t->output.crop.w;
+		t->output.crop.w = t->output.crop.h;
+		t->output.crop.h = tmp;
+	}
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+		t->set.mode |= ROT_MODE;
+
+	/*need resize or CSC?*/
+	if ((t->input.crop.w != t->output.crop.w) ||
+			(t->input.crop.h != t->output.crop.h) ||
+			need_csc(t->input.format, t->output.format))
+		t->set.mode |= IC_MODE;
+
+	/*need cropping?*/
+	if ((t->input.crop.w != t->input.width)       ||
+		(t->input.crop.h != t->input.height)  ||
+		(t->output.crop.w != t->output.width) ||
+		(t->output.crop.h != t->output.height))
+		t->set.mode |= IC_MODE;
+
+	/*need flip?*/
+	if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
+		t->set.mode |= IC_MODE;
+
+	/*need IDMAC do format(same color space)?*/
+	if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
+		t->set.mode |= IC_MODE;
+
+	/*overlay support*/
+	if (t->overlay_en)
+		t->set.mode |= IC_MODE;
+
+	/*deinterlace*/
+	if (t->input.deinterlace.enable) {
+		t->set.mode &= ~IC_MODE;
+		t->set.mode |= VDI_MODE;
+	}
+	if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+		if (t->set.mode & ROT_MODE) {
+			ret = IPU_CHECK_ERR_NOT_SUPPORT;
+			goto done;
+		}
+		t->set.mode |= VDOA_MODE;
+		if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
+			t->set.mode |= VDOA_BAND_MODE;
+		t->set.mode &= ~IC_MODE;
+	}
+
+	if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
+		(IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+		if (t->output.crop.w > soc_max_out_width())
+			t->set.split_mode |= RL_SPLIT;
+		if (t->output.crop.h > soc_max_out_height())
+			t->set.split_mode |= UD_SPLIT;
+		if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
+				(t->input.crop.w >
+				 soc_max_vdi_in_width(t->ipu))) {
+			t->set.split_mode |= RL_SPLIT;
+			vdi_split = true;
+		}
+		if (t->set.split_mode) {
+			if ((t->set.split_mode == RL_SPLIT) ||
+				 (t->set.split_mode == UD_SPLIT))
+				timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
+			else
+				timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
+			if (t->timeout < timeout)
+				t->timeout = timeout;
+
+			ret = update_split_setting(t, vdi_split);
+			if (ret > IPU_CHECK_ERR_MIN)
+				goto done;
+		}
+	}
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		/*output swap*/
+		tmp = t->output.crop.w;
+		t->output.crop.w = t->output.crop.h;
+		t->output.crop.h = tmp;
+	}
+
+	if (t->set.mode == NULL_MODE) {
+		ret = IPU_CHECK_ERR_PROC_NO_NEED;
+		goto done;
+	}
+
+	if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
+		ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
+	if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
+		ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
+	if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
+		ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
+
+done:
+	/* dump msg */
+	if (debug) {
+		if (ret > IPU_CHECK_ERR_MIN)
+			dump_check_err(t->dev, ret);
+		else if (ret != IPU_CHECK_OK)
+			dump_check_warn(t->dev, ret);
+	}
+
+	return ret;
+}
+
+static int prepare_task(struct ipu_task_entry *t)
+{
+	int ret = 0;
+
+	ret = check_task(t);
+	if (ret > IPU_CHECK_ERR_MIN)
+		return -EINVAL;
+
+	if (t->set.mode & VDI_MODE) {
+		t->task_id = IPU_TASK_ID_VF;
+		t->set.task = VDI_VF;
+		if (t->set.mode & ROT_MODE)
+			t->set.task |= ROT_VF;
+	}
+
+	if (VDOA_MODE == t->set.mode) {
+		if (t->set.task != 0) {
+			dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
+					t->set.task, t);
+			return -EINVAL;
+		}
+		t->set.task |= VDOA_ONLY;
+	}
+
+	if (VDOA_BAND_MODE & t->set.mode) {
+		/* to save band size: 1<<3 = 8 lines */
+		t->set.band_lines = 3;
+	}
+
+	dump_task_info(t);
+
+	return ret;
+}
+
+static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
+{
+	uint32_t	status;
+	uint32_t	status_vf;
+	uint32_t	status_rot;
+
+	if (is_vf) {
+		status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
+		status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
+		status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
+		return status || status_vf || status_rot;
+	} else {
+		status = ipu_channel_status(ipu, MEM_PP_MEM);
+		status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
+		return status || status_rot;
+	}
+}
+
+static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+	int		i;
+	struct ipu_soc	*ipu;
+	u8		*used;
+	uint32_t	found_ipu = 0;
+	uint32_t	found_vdoa = 0;
+	struct ipu_channel_tabel	*tbl = &ipu_ch_tbl;
+
+	if (t->set.mode & VDOA_MODE) {
+		if (NULL != t->vdoa_handle)
+			found_vdoa = 1;
+		else {
+			found_vdoa = tbl->vdoa_used ? 0 : 1;
+			if (found_vdoa) {
+				tbl->vdoa_used = 1;
+				vdoa_get_handle(&t->vdoa_handle);
+			} else
+				/* first get vdoa->ipu resource sequence */
+				goto out;
+			if (t->set.task & VDOA_ONLY)
+				goto out;
+		}
+	}
+
+	for (i = 0; i < max_ipu_no; i++) {
+		ipu = ipu_get_soc(i);
+		if (IS_ERR(ipu))
+			dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+				 t->task_no, found_vdoa, i);
+
+		used = &tbl->used[i][IPU_PP_CH_VF];
+		if (t->set.mode & VDI_MODE) {
+			if (0 == *used) {
+				*used = 1;
+				found_ipu = 1;
+				break;
+			}
+		} else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+			if (0 == *used) {
+				t->task_id = IPU_TASK_ID_VF;
+				if (t->set.mode & IC_MODE)
+					t->set.task |= IC_VF;
+				if (t->set.mode & ROT_MODE)
+					t->set.task |= ROT_VF;
+				*used = 1;
+				found_ipu = 1;
+				break;
+			}
+		} else
+			dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
+				 t->task_no, found_vdoa, t->set.mode);
+	}
+	if (found_ipu)
+		goto next;
+
+	for (i = 0; i < max_ipu_no; i++) {
+		ipu = ipu_get_soc(i);
+		if (IS_ERR(ipu))
+			dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+				 t->task_no, found_vdoa, i);
+
+		if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+			used = &tbl->used[i][IPU_PP_CH_PP];
+			if (0 == *used) {
+				t->task_id = IPU_TASK_ID_PP;
+				if (t->set.mode & IC_MODE)
+					t->set.task |= IC_PP;
+				if (t->set.mode & ROT_MODE)
+					t->set.task |= ROT_PP;
+				*used = 1;
+				found_ipu = 1;
+				break;
+			}
+		}
+	}
+
+next:
+	if (found_ipu) {
+		t->ipu = ipu;
+		t->ipu_id = i;
+		t->dev = ipu->dev;
+		if (atomic_inc_return(&t->res_get) == 2)
+			dev_err(t->dev,
+				"ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
+				 t->task_no, found_vdoa);
+	}
+out:
+	dev_dbg(t->dev,
+		"%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
+		 __func__, t->task_no, found_vdoa, found_ipu);
+
+	if (t->set.task & VDOA_ONLY)
+		return found_vdoa;
+	else if (t->set.mode & VDOA_MODE)
+		return found_vdoa && found_ipu;
+	else
+		return found_ipu;
+}
+
+static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
+{
+	int ret;
+	int rel_vdoa = 0, rel_ipu = 0;
+	struct ipu_channel_tabel	*tbl = &ipu_ch_tbl;
+
+	if (tsk->set.mode & VDOA_MODE) {
+		if (!tbl->vdoa_used && tsk->vdoa_handle)
+			dev_err(tsk->dev,
+				"ERR no:0x%x,vdoa not used,mode:0x%x\n",
+				 tsk->task_no, tsk->set.mode);
+		if (tbl->vdoa_used && tsk->vdoa_handle) {
+			tbl->vdoa_used = 0;
+			vdoa_put_handle(&tsk->vdoa_handle);
+			if (tsk->ipu)
+				tsk->ipu->vdoa_en = 0;
+			rel_vdoa = 1;
+			if (vdoa_only || (tsk->set.task & VDOA_ONLY))
+				goto out;
+		}
+	}
+
+	if (tsk->ipu_id != 0 && tsk->ipu_id != 1) {
+		dev_err(tsk->dev,
+			"%s:invalid ipu id, no:0x%x, rel_vdoa:%d, rel_ipu:%d\n",
+			 __func__, tsk->task_no, rel_vdoa, rel_ipu);
+		goto out;
+	}
+
+	tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
+	rel_ipu = 1;
+	ret = atomic_inc_return(&tsk->res_free);
+	if (ret == 2)
+		dev_err(tsk->dev,
+			"ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
+			 tsk->task_no, rel_vdoa);
+out:
+	dev_dbg(tsk->dev,
+		"%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
+		 __func__, tsk->task_no, rel_vdoa, rel_ipu);
+}
+
+static int get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+	int		ret;
+	uint32_t	found = 0;
+
+	found = _get_vdoa_ipu_res(t);
+	if (!found) {
+		t->ipu_id = -1;
+		t->ipu = NULL;
+		/* blocking to get resource */
+		ret = atomic_inc_return(&req_cnt);
+		dev_dbg(t->dev,
+			"wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
+		ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
+				 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+		if (ret == 0) {
+			dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
+					 t, t->task_no, t->timeout - DEF_DELAY_MS);
+			ret = -ETIMEDOUT;
+			t->state = STATE_RES_TIMEOUT;
+			goto out;
+		} else {
+			if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
+				dev_err(t->dev,
+					"ERR[no-0x%x] can not get ipu!\n",
+					t->task_no);
+			ret = atomic_read(&req_cnt);
+			if (ret > 0)
+				ret = atomic_dec_return(&req_cnt);
+			else
+				dev_err(t->dev,
+					"ERR[no-0x%x] req_cnt:%d mismatch!\n",
+					t->task_no, ret);
+			dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
+						t->task_no, t, ret);
+			found = 1;
+		}
+	}
+
+out:
+	return found;
+}
+
+static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+
+	tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
+	if (!tsk)
+		return ERR_PTR(-ENOMEM);
+	kref_init(&tsk->refcount);
+	tsk->state = -EINVAL;
+	tsk->ipu_id = -1;
+	tsk->dev = ipu_dev;
+	tsk->input = task->input;
+	tsk->output = task->output;
+	tsk->overlay_en = task->overlay_en;
+	if (tsk->overlay_en)
+		tsk->overlay = task->overlay;
+	if (task->timeout > DEF_TIMEOUT_MS)
+		tsk->timeout = task->timeout;
+	else
+		tsk->timeout = DEF_TIMEOUT_MS;
+
+	return tsk;
+}
+
+static void task_mem_free(struct kref *ref)
+{
+	struct ipu_task_entry *tsk =
+			container_of(ref, struct ipu_task_entry, refcount);
+	kfree(tsk);
+}
+
+int create_split_child_task(struct ipu_split_task *sp_task)
+{
+	int ret = 0;
+	struct ipu_task_entry *tsk;
+
+	tsk = create_task_entry(&sp_task->task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	sp_task->child_task = tsk;
+	tsk->task_no = sp_task->task_no;
+
+	ret = prepare_task(tsk);
+	if (ret < 0)
+		goto err;
+
+	tsk->parent = sp_task->parent_task;
+	tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+
+	list_add(&tsk->node, &tsk->parent->split_list);
+	dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
+	tsk->state = STATE_QUEUE;
+	CHECK_PERF(&tsk->ts_queue);
+err:
+	return ret;
+}
+
+static inline int sp_task_check_done(struct ipu_split_task *sp_task,
+			struct ipu_task_entry *parent, int num, int *idx)
+{
+	int i;
+	int ret = 0;
+	struct ipu_task_entry *tsk;
+	struct mutex *lock = &parent->split_lock;
+
+	*idx = -EINVAL;
+	mutex_lock(lock);
+	for (i = 0; i < num; i++) {
+		tsk = sp_task[i].child_task;
+		if (tsk && tsk->split_done) {
+			*idx = i;
+			ret = 1;
+			goto out;
+		}
+	}
+
+out:
+	mutex_unlock(lock);
+	return ret;
+}
+
+static int create_split_task(
+		int stripe,
+		struct ipu_split_task *sp_task)
+{
+	struct ipu_task *task = &(sp_task->task);
+	struct ipu_task_entry *t = sp_task->parent_task;
+	int ret;
+
+	sp_task->task_no |= stripe;
+
+	task->input = t->input;
+	task->output = t->output;
+	task->overlay_en = t->overlay_en;
+	if (task->overlay_en)
+		task->overlay = t->overlay;
+	task->task_id = t->task_id;
+	if ((t->set.split_mode == RL_SPLIT) ||
+		 (t->set.split_mode == UD_SPLIT))
+		task->timeout = t->timeout / 2;
+	else
+		task->timeout = t->timeout / 4;
+
+	task->input.crop.w = t->set.sp_setting.iw;
+	task->input.crop.h = t->set.sp_setting.ih;
+	if (task->overlay_en) {
+		task->overlay.crop.w = t->set.sp_setting.ow;
+		task->overlay.crop.h = t->set.sp_setting.oh;
+	}
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		task->output.crop.w = t->set.sp_setting.oh;
+		task->output.crop.h = t->set.sp_setting.ow;
+		t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
+		t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
+
+	} else {
+		task->output.crop.w = t->set.sp_setting.ow;
+		task->output.crop.h = t->set.sp_setting.oh;
+		t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
+		t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
+	}
+
+	if (stripe & LEFT_STRIPE)
+		task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
+	else if (stripe & RIGHT_STRIPE)
+		task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
+	if (stripe & UP_STRIPE)
+		task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
+	else if (stripe & DOWN_STRIPE)
+		task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
+
+	if (task->overlay_en) {
+		if (stripe & LEFT_STRIPE)
+			task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+	}
+
+	switch (t->output.rotate) {
+	case IPU_ROTATE_NONE:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+		break;
+	case IPU_ROTATE_VERT_FLIP:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		break;
+	case IPU_ROTATE_HORIZ_FLIP:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+		break;
+	case IPU_ROTATE_180:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		break;
+	case IPU_ROTATE_90_RIGHT:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+		break;
+	case IPU_ROTATE_90_RIGHT_HFLIP:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+		break;
+	case IPU_ROTATE_90_RIGHT_VFLIP:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		break;
+	case IPU_ROTATE_90_LEFT:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		break;
+	default:
+		dev_err(t->dev, "ERR:should not be here\n");
+		break;
+	}
+
+	ret = create_split_child_task(sp_task);
+	if (ret < 0)
+		dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
+	return ret;
+}
+
+static int queue_split_task(struct ipu_task_entry *t,
+				struct ipu_split_task *sp_task, uint32_t size)
+{
+	int err[4];
+	int ret = 0;
+	int i, j;
+	struct ipu_task_entry *tsk = NULL;
+	struct mutex *lock = &t->split_lock;
+	struct mutex *vdic_lock = &t->vdic_lock;
+
+	dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
+			 t, t->task_no, size);
+	mutex_init(lock);
+	mutex_init(vdic_lock);
+	init_waitqueue_head(&t->split_waitq);
+	INIT_LIST_HEAD(&t->split_list);
+	for (j = 0; j < size; j++) {
+		memset(&sp_task[j], 0, sizeof(*sp_task));
+		sp_task[j].parent_task = t;
+		sp_task[j].task_no = t->task_no;
+	}
+
+	if (t->set.split_mode == RL_SPLIT) {
+		i = 0;
+		err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
+		if (err[i] < 0)
+			goto err_start;
+		i = 1;
+		err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
+	} else if (t->set.split_mode == UD_SPLIT) {
+		i = 0;
+		err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
+		if (err[i] < 0)
+			goto err_start;
+		i = 1;
+		err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
+	} else {
+		i = 0;
+		err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+		if (err[i] < 0)
+			goto err_start;
+		i = 1;
+		err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+		if (err[i] < 0)
+			goto err_start;
+		i = 2;
+		err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
+		if (err[i] < 0)
+			goto err_start;
+		i = 3;
+		err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
+	}
+
+err_start:
+	for (j = 0; j < (i + 1); j++) {
+		if (err[j] < 0) {
+			if (sp_task[j].child_task)
+				dev_err(t->dev,
+				 "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
+				j, sp_task[j].child_task->task_no,
+				sp_task[j].child_task->state, err[j]);
+			goto err_exit;
+		}
+		dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
+			sp_task[j].child_task, j, sp_task[j].child_task->task_no,
+			state_msg[sp_task[j].child_task->state].msg, err[j]);
+	}
+
+	return ret;
+
+err_exit:
+	for (j = 0; j < (i + 1); j++) {
+		if (err[j] < 0 && !ret)
+			ret = err[j];
+		tsk = sp_task[j].child_task;
+		if (!tsk)
+			continue;
+		kfree(tsk);
+	}
+	t->state = STATE_ERR;
+	return ret;
+
+}
+
+static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
+				ipu_channel_t channel, uint32_t ch_type)
+{
+	int ret = 0;
+	int i;
+	uint32_t ipu_fmt;
+	dma_addr_t inbuf_base = 0;
+	u32 field_size;
+	struct vdoa_params param;
+	struct vdoa_ipu_buf buf;
+	struct ipu_soc *ipu_idx;
+	u32 ipu_stride, obuf_size;
+	u32 height, width;
+	ipu_buffer_t type;
+
+	if ((IPU_PIX_FMT_YUYV != t->output.format) &&
+		(IPU_PIX_FMT_NV12 != t->output.format)) {
+		dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
+		return -EINVAL;
+	}
+
+	memset(&param, 0, sizeof(param));
+	/* init channel tiled bufs */
+	if (deinterlace_3_field(t) &&
+		(IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+		field_size = tiled_filed_size(t);
+		if (INPUT_CHAN_VDI_P == ch_type) {
+			inbuf_base = t->input.paddr + field_size;
+			param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
+		} else if (INPUT_CHAN == ch_type) {
+			inbuf_base = t->input.paddr_n;
+			param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
+		} else if (INPUT_CHAN_VDI_N == ch_type) {
+			inbuf_base = t->input.paddr_n + field_size;
+			param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
+		} else
+			return -EINVAL;
+		height = t->input.crop.h >> 1; /* field format for vdoa */
+		width = t->input.crop.w;
+		param.vfield_buf.vubo = t->set.i_uoff;
+		param.interlaced = 1;
+		param.scan_order = 1;
+		type = IPU_INPUT_BUFFER;
+	} else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
+			(INPUT_CHAN == ch_type)) {
+		height = t->input.crop.h;
+		width = t->input.crop.w;
+		param.vframe_buf.veba = t->input.paddr + t->set.i_off;
+		param.vframe_buf.vubo = t->set.i_uoff;
+		type = IPU_INPUT_BUFFER;
+	} else
+		return -EINVAL;
+
+	param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
+	if (param.band_mode && (t->set.band_lines != 3) &&
+		 (t->set.band_lines != 4) && (t->set.band_lines != 5))
+		return -EINVAL;
+	else if (param.band_mode)
+		param.band_lines = (1 << t->set.band_lines);
+	for (i = 0; i < max_ipu_no; i++) {
+		ipu_idx = ipu_get_soc(i);
+		if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
+			break;
+	}
+	if (t->set.task & VDOA_ONLY)
+		/* dummy, didn't need ipu res */
+		i = 0;
+	if (max_ipu_no == i) {
+		dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
+		return -EINVAL;
+	}
+
+	param.ipu_num = i;
+	param.vpu_stride = t->input.width;
+	param.height = height;
+	param.width = width;
+	if (IPU_PIX_FMT_NV12 == t->output.format)
+		param.pfs = VDOA_PFS_NV12;
+	else
+		param.pfs = VDOA_PFS_YUYV;
+	ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
+				IPU_PIX_FMT_NV12;
+	ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
+	obuf_size = PAGE_ALIGN(param.width * param.height *
+				fmt_to_bpp(ipu_fmt)/8);
+	dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
+			param.band_mode, param.band_lines);
+	if (!param.band_mode) {
+		/* note: if only for tiled -> raster convert and
+		   no other post-processing, we don't need alloc buf
+		   and use output buffer directly.
+		*/
+		if (t->set.task & VDOA_ONLY)
+			param.ieba0 = t->output.paddr;
+		else {
+			dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
+			return -EINVAL;
+		}
+	} else {
+		if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
+			dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
+			return -EINVAL;
+		}
+	}
+	ret = vdoa_setup(t->vdoa_handle, &param);
+	if (ret)
+		goto done;
+	vdoa_get_output_buf(t->vdoa_handle, &buf);
+	if (t->set.task & VDOA_ONLY)
+		goto done;
+
+	ret = ipu_init_channel_buffer(ipu,
+			channel,
+			type,
+			ipu_fmt,
+			width,
+			height,
+			ipu_stride,
+			IPU_ROTATE_NONE,
+			buf.ieba0,
+			buf.ieba1,
+			0,
+			buf.iubo,
+			0);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+	if (param.band_mode) {
+		ret = ipu_set_channel_bandmode(ipu, channel,
+				type, t->set.band_lines);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BAND_FAIL;
+			goto done;
+		}
+	}
+done:
+	return ret;
+}
+
+static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret = 0;
+
+	if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
+		ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+		CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
+	} else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
+		ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+		CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
+		ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
+					INPUT_CHAN_VDI_P);
+		CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
+		ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
+					INPUT_CHAN_VDI_N);
+		CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
+	} else {
+		ret = -EINVAL;
+		dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
+			t->task_no, t->input.format);
+	}
+
+done:
+	return ret;
+}
+
+static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret = 0;
+	ipu_channel_params_t params;
+	dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
+	dma_addr_t inbuf_p = 0, inbuf_n = 0;
+	dma_addr_t outbuf = 0;
+	int out_uoff = 0, out_voff = 0, out_rot;
+	int out_w = 0, out_h = 0, out_stride;
+	int out_fmt;
+	u32 vdi_frame_idx = 0;
+
+	memset(&params, 0, sizeof(params));
+
+	/* is it need link a rot channel */
+	if (ic_and_rot(t->set.mode)) {
+		outbuf = t->set.r_paddr;
+		out_w = t->set.r_width;
+		out_h = t->set.r_height;
+		out_stride = t->set.r_stride;
+		out_fmt = t->set.r_fmt;
+		out_uoff = 0;
+		out_voff = 0;
+		out_rot = IPU_ROTATE_NONE;
+	} else {
+		outbuf = t->output.paddr + t->set.o_off;
+		out_w = t->output.crop.w;
+		out_h = t->output.crop.h;
+		out_stride = t->set.ostride;
+		out_fmt = t->output.format;
+		out_uoff = t->set.o_uoff;
+		out_voff = t->set.o_voff;
+		out_rot = t->output.rotate;
+	}
+
+	/* settings */
+	params.mem_prp_vf_mem.in_width = t->input.crop.w;
+	params.mem_prp_vf_mem.out_width = out_w;
+	params.mem_prp_vf_mem.in_height = t->input.crop.h;
+	params.mem_prp_vf_mem.out_height = out_h;
+	params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
+	params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
+	params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
+
+	params.mem_prp_vf_mem.outh_resize_ratio =
+			t->set.sp_setting.outh_resize_ratio;
+	params.mem_prp_vf_mem.outv_resize_ratio =
+			t->set.sp_setting.outv_resize_ratio;
+
+	if (t->overlay_en) {
+		params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
+		params.mem_prp_vf_mem.graphics_combine_en = 1;
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
+			params.mem_prp_vf_mem.global_alpha_en = 1;
+		else if (t->overlay.alpha.loc_alp_paddr)
+			params.mem_prp_vf_mem.alpha_chan_en = 1;
+		/* otherwise, alpha bending per pixel is used. */
+		params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
+		if (t->overlay.colorkey.enable) {
+			params.mem_prp_vf_mem.key_color_en = 1;
+			params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
+		}
+	}
+
+	if (t->input.deinterlace.enable) {
+		if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
+			params.mem_prp_vf_mem.field_fmt =
+				IPU_DEINTERLACE_FIELD_BOTTOM;
+		else
+			params.mem_prp_vf_mem.field_fmt =
+				IPU_DEINTERLACE_FIELD_TOP;
+
+		if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
+			vdi_frame_idx = t->input.deinterlace.field_fmt &
+						IPU_DEINTERLACE_RATE_FRAME1;
+	}
+
+	if (t->set.mode & VDOA_MODE)
+		ipu->vdoa_en = 1;
+
+	/* init channels */
+	if (!(t->set.task & VDOA_ONLY)) {
+		ret = ipu_init_channel(ipu, t->set.ic_chan, &params);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_FAIL;
+			goto done;
+		}
+	}
+
+	if (deinterlace_3_field(t)) {
+		ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, &params);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_FAIL;
+			goto done;
+		}
+		ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, &params);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_FAIL;
+			goto done;
+		}
+	}
+
+	/* init channel bufs */
+	if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+		(IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+		ret = init_tiled_ch_bufs(ipu, t);
+		if (ret < 0)
+			goto done;
+	} else {
+		if ((deinterlace_3_field(t)) &&
+			(IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+			if (params.mem_prp_vf_mem.field_fmt ==
+				IPU_DEINTERLACE_FIELD_TOP) {
+				if (vdi_frame_idx) {
+					inbuf_p = t->input.paddr + t->set.istride +
+							t->set.i_off;
+					inbuf = t->input.paddr_n + t->set.i_off;
+					inbuf_n = t->input.paddr_n + t->set.istride +
+							t->set.i_off;
+					params.mem_prp_vf_mem.field_fmt =
+						IPU_DEINTERLACE_FIELD_BOTTOM;
+				} else {
+					inbuf_p = t->input.paddr + t->set.i_off;
+					inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+					inbuf_n = t->input.paddr_n + t->set.i_off;
+				}
+			} else {
+				if (vdi_frame_idx) {
+					inbuf_p = t->input.paddr + t->set.i_off;
+					inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
+					inbuf_n = t->input.paddr_n + t->set.i_off;
+					params.mem_prp_vf_mem.field_fmt =
+						IPU_DEINTERLACE_FIELD_TOP;
+				} else {
+					inbuf_p = t->input.paddr + t->set.istride +
+							t->set.i_off;
+					inbuf = t->input.paddr + t->set.i_off;
+					inbuf_n = t->input.paddr_n + t->set.istride +
+							t->set.i_off;
+				}
+			}
+		} else {
+			if (t->input.deinterlace.enable) {
+				if (params.mem_prp_vf_mem.field_fmt ==
+					IPU_DEINTERLACE_FIELD_TOP) {
+					if (vdi_frame_idx) {
+						inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+						params.mem_prp_vf_mem.field_fmt =
+							IPU_DEINTERLACE_FIELD_BOTTOM;
+					} else
+						inbuf = t->input.paddr + t->set.i_off;
+				} else {
+					if (vdi_frame_idx) {
+						inbuf = t->input.paddr + t->set.i_off;
+						params.mem_prp_vf_mem.field_fmt =
+							IPU_DEINTERLACE_FIELD_TOP;
+					} else
+						inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+				}
+			} else
+				inbuf = t->input.paddr + t->set.i_off;
+		}
+
+		if (t->overlay_en)
+			ovbuf = t->overlay.paddr + t->set.ov_off;
+	}
+	if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
+		ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+			+ t->set.ov_alpha_off;
+
+	if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
+		(IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.ic_chan,
+				IPU_INPUT_BUFFER,
+				t->input.format,
+				t->input.crop.w,
+				t->input.crop.h,
+				t->set.istride,
+				IPU_ROTATE_NONE,
+				inbuf,
+				0,
+				0,
+				t->set.i_uoff,
+				t->set.i_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+	if (deinterlace_3_field(t) &&
+		(IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.vdi_ic_p_chan,
+				IPU_INPUT_BUFFER,
+				t->input.format,
+				t->input.crop.w,
+				t->input.crop.h,
+				t->set.istride,
+				IPU_ROTATE_NONE,
+				inbuf_p,
+				0,
+				0,
+				t->set.i_uoff,
+				t->set.i_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.vdi_ic_n_chan,
+				IPU_INPUT_BUFFER,
+				t->input.format,
+				t->input.crop.w,
+				t->input.crop.h,
+				t->set.istride,
+				IPU_ROTATE_NONE,
+				inbuf_n,
+				0,
+				0,
+				t->set.i_uoff,
+				t->set.i_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+
+	if (t->overlay_en) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.ic_chan,
+				IPU_GRAPH_IN_BUFFER,
+				t->overlay.format,
+				t->overlay.crop.w,
+				t->overlay.crop.h,
+				t->set.ovstride,
+				IPU_ROTATE_NONE,
+				ovbuf,
+				0,
+				0,
+				t->set.ov_uoff,
+				t->set.ov_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+
+	if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.ic_chan,
+				IPU_ALPHA_IN_BUFFER,
+				IPU_PIX_FMT_GENERIC,
+				t->overlay.crop.w,
+				t->overlay.crop.h,
+				t->set.ov_alpha_stride,
+				IPU_ROTATE_NONE,
+				ov_alp_buf,
+				0,
+				0,
+				0, 0);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+
+	if (!(t->set.task & VDOA_ONLY)) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.ic_chan,
+				IPU_OUTPUT_BUFFER,
+				out_fmt,
+				out_w,
+				out_h,
+				out_stride,
+				out_rot,
+				outbuf,
+				0,
+				0,
+				out_uoff,
+				out_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+
+	if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+		ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+		CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
+				STATE_LINK_CHAN_FAIL, done, ret);
+	}
+
+done:
+	return ret;
+}
+
+static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret;
+
+	if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+		ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
+				STATE_UNLINK_CHAN_FAIL, ret);
+	}
+	ipu_uninit_channel(ipu, t->set.ic_chan);
+	if (deinterlace_3_field(t)) {
+		ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
+		ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
+	}
+}
+
+static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret = 0;
+	dma_addr_t inbuf = 0, outbuf = 0;
+	int in_uoff = 0, in_voff = 0;
+	int in_fmt, in_width, in_height, in_stride;
+
+	/* init channel */
+	ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_FAIL;
+		goto done;
+	}
+
+	/* init channel buf */
+	/* is it need link to a ic channel */
+	if (ic_and_rot(t->set.mode)) {
+		in_fmt = t->set.r_fmt;
+		in_width = t->set.r_width;
+		in_height = t->set.r_height;
+		in_stride = t->set.r_stride;
+		inbuf = t->set.r_paddr;
+		in_uoff = 0;
+		in_voff = 0;
+	} else {
+		in_fmt = t->input.format;
+		in_width = t->input.crop.w;
+		in_height = t->input.crop.h;
+		in_stride = t->set.istride;
+		inbuf = t->input.paddr + t->set.i_off;
+		in_uoff = t->set.i_uoff;
+		in_voff = t->set.i_voff;
+	}
+	outbuf = t->output.paddr + t->set.o_off;
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.rot_chan,
+			IPU_INPUT_BUFFER,
+			in_fmt,
+			in_width,
+			in_height,
+			in_stride,
+			t->output.rotate,
+			inbuf,
+			0,
+			0,
+			in_uoff,
+			in_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.rot_chan,
+			IPU_OUTPUT_BUFFER,
+			t->output.format,
+			t->output.crop.w,
+			t->output.crop.h,
+			t->set.ostride,
+			IPU_ROTATE_NONE,
+			outbuf,
+			0,
+			0,
+			t->set.o_uoff,
+			t->set.o_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
+static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	ipu_uninit_channel(ipu, t->set.rot_chan);
+}
+
+static int get_irq(struct ipu_task_entry *t)
+{
+	int irq;
+	ipu_channel_t chan;
+
+	if (only_ic(t->set.mode))
+		chan = t->set.ic_chan;
+	else
+		chan = t->set.rot_chan;
+
+	switch (chan) {
+	case MEM_ROT_VF_MEM:
+		irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
+		break;
+	case MEM_ROT_PP_MEM:
+		irq = IPU_IRQ_PP_ROT_OUT_EOF;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		irq = IPU_IRQ_PRP_VF_OUT_EOF;
+		break;
+	case MEM_PP_MEM:
+		irq = IPU_IRQ_PP_OUT_EOF;
+		break;
+	case MEM_VDI_MEM:
+		irq = IPU_IRQ_VDIC_OUT_EOF;
+		break;
+	default:
+		irq = -EINVAL;
+	}
+
+	return irq;
+}
+
+static irqreturn_t task_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_task_entry *prev_tsk = dev_id;
+
+	CHECK_PERF(&prev_tsk->ts_inirq);
+	complete(&prev_tsk->irq_comp);
+	dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
+				 prev_tsk, prev_tsk->task_no);
+
+	return IRQ_HANDLED;
+}
+
+/* Fix deinterlace up&down split mode medium line */
+static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	u32 vdi_size;
+	u32 vdi_save_lines;
+	u32 stripe_mode;
+	u32 task_no;
+	u32 i, offset_addr;
+	u32 line_size;
+	unsigned char  *base_off;
+	struct ipu_task_entry *parent = t->parent;
+	struct mutex *lock = &parent->vdic_lock;
+
+	if (!parent) {
+		dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
+		return;
+	}
+	mutex_lock(lock);
+	stripe_mode = t->task_no & 0xf;
+	task_no = t->task_no >> 4;
+
+	/* Save both luma and chroma part for interleaved YUV(e.g. YUYV).
+	 * Save luma part for non-interleaved and partial-interleaved
+	 * YUV format (e.g NV12 and YV12). */
+	if (t->output.format == IPU_PIX_FMT_YUYV ||
+			t->output.format == IPU_PIX_FMT_UYVY)
+		line_size = t->output.crop.w * fmt_to_bpp(t->output.format)/8;
+	else
+		line_size = t->output.crop.w;
+
+	vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
+	vdi_size = vdi_save_lines * line_size;
+	if (vdi_save_lines <= 0) {
+		dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
+		mutex_unlock(lock);
+		return;
+	}
+
+	/*check vditmpbuf buffer have alloced or buffer size is changed */
+	if ((vdi_save_lines != parent->old_save_lines) ||
+		(vdi_size != parent->old_size)) {
+		if (parent->vditmpbuf[0] != NULL)
+			kfree(parent->vditmpbuf[0]);
+		if (parent->vditmpbuf[1] != NULL)
+			kfree(parent->vditmpbuf[1]);
+
+		parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
+		if (parent->vditmpbuf[0] == NULL) {
+			dev_err(t->dev,
+				"[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
+			mutex_unlock(lock);
+			return;
+		}
+		memset(parent->vditmpbuf[0], 0, vdi_size);
+
+		parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
+		if (parent->vditmpbuf[1] == NULL) {
+			dev_err(t->dev,
+				"[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
+			mutex_unlock(lock);
+			return;
+		}
+		memset(parent->vditmpbuf[1], 0, vdi_size);
+
+		parent->old_save_lines = vdi_save_lines;
+		parent->old_size = vdi_size;
+	}
+
+	if (pfn_valid(t->output.paddr >> PAGE_SHIFT)) {
+		base_off = page_address(pfn_to_page(t->output.paddr >> PAGE_SHIFT));
+		base_off += t->output.paddr & ((1 << PAGE_SHIFT) - 1);
+	} else {
+		base_off = (char *)ioremap_nocache(t->output.paddr,
+				t->output.width * t->output.height *
+				fmt_to_bpp(t->output.format)/8);
+	}
+	if (base_off == NULL) {
+		dev_err(t->dev, "ERR[0x%p]Failed get virtual address\n", t);
+		mutex_unlock(lock);
+		return;
+	}
+
+	/* UP stripe or UP&LEFT stripe */
+	if ((stripe_mode == UP_STRIPE) ||
+			(stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
+		if (!parent->buf0filled) {
+			offset_addr = t->set.o_off +
+				t->set.sp_setting.ud_split_line*t->set.ostride;
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + vdi_size);
+			outer_flush_range(t->output.paddr + offset_addr,
+				t->output.paddr + offset_addr + vdi_size);
+
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(parent->vditmpbuf[0] + i*line_size,
+					base_off + offset_addr +
+					i*t->set.ostride, line_size);
+			parent->buf0filled = true;
+		} else {
+			offset_addr = t->set.o_off + (t->output.crop.h -
+					vdi_save_lines) * t->set.ostride;
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(base_off + offset_addr + i*t->set.ostride,
+						parent->vditmpbuf[0] + i*line_size, line_size);
+
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + i*t->set.ostride);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + i*t->set.ostride);
+			parent->buf0filled = false;
+		}
+	}
+	/*Down stripe or Down&Left stripe*/
+	else if ((stripe_mode == DOWN_STRIPE) ||
+			(stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
+		if (!parent->buf0filled) {
+			offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + vdi_size);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + vdi_size);
+
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(parent->vditmpbuf[0] + i*line_size,
+						base_off + offset_addr + i*t->set.ostride,
+						line_size);
+			parent->buf0filled = true;
+		} else {
+			offset_addr = t->set.o_off;
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(base_off + offset_addr + i*t->set.ostride,
+						parent->vditmpbuf[0] + i*line_size,
+						line_size);
+
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + i*t->set.ostride);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + i*t->set.ostride);
+			parent->buf0filled = false;
+		}
+	}
+	/*Up&Right stripe*/
+	else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
+		if (!parent->buf1filled) {
+			offset_addr = t->set.o_off +
+				t->set.sp_setting.ud_split_line*t->set.ostride;
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + vdi_size);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + vdi_size);
+
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(parent->vditmpbuf[1] + i*line_size,
+						base_off + offset_addr + i*t->set.ostride,
+						line_size);
+			parent->buf1filled = true;
+		} else {
+			offset_addr = t->set.o_off +
+				(t->output.crop.h - vdi_save_lines)*t->set.ostride;
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(base_off + offset_addr + i*t->set.ostride,
+						parent->vditmpbuf[1] + i*line_size,
+						line_size);
+
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + i*t->set.ostride);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + i*t->set.ostride);
+			parent->buf1filled = false;
+		}
+	}
+	/*Down stripe or Down&Right stript*/
+	else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
+		if (!parent->buf1filled) {
+			offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + vdi_save_lines*t->set.ostride);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(parent->vditmpbuf[1] + i*line_size,
+						base_off + offset_addr + i*t->set.ostride,
+						line_size);
+			parent->buf1filled = true;
+		} else {
+			offset_addr = t->set.o_off;
+			for (i = 0; i < vdi_save_lines; i++)
+				memcpy(base_off + offset_addr + i*t->set.ostride,
+						parent->vditmpbuf[1] + i*line_size,
+						line_size);
+
+			dmac_flush_range(base_off + offset_addr,
+					base_off + offset_addr + vdi_save_lines*t->set.ostride);
+			outer_flush_range(t->output.paddr + offset_addr,
+					t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+			parent->buf1filled = false;
+		}
+	}
+	if (!pfn_valid(t->output.paddr >> PAGE_SHIFT))
+		iounmap(base_off);
+	mutex_unlock(lock);
+}
+
+static void do_task_release(struct ipu_task_entry *t, int fail)
+{
+	int ret;
+	struct ipu_soc *ipu = t->ipu;
+
+	if (t->input.deinterlace.enable && !fail &&
+			(t->task_no & (UP_STRIPE | DOWN_STRIPE)))
+		vdi_split_process(ipu, t);
+
+	ipu_free_irq(ipu, t->irq, t);
+
+	if (t->vdoa_dma.vaddr)
+		dma_free_coherent(t->dev,
+			t->vdoa_dma.size,
+			t->vdoa_dma.vaddr,
+			t->vdoa_dma.paddr);
+
+	if (only_ic(t->set.mode)) {
+		ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
+				STATE_DISABLE_CHAN_FAIL, ret);
+		if (deinterlace_3_field(t)) {
+			ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+							true);
+			CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
+					STATE_DISABLE_CHAN_FAIL, ret);
+			ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+							true);
+			CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
+					STATE_DISABLE_CHAN_FAIL, ret);
+		}
+	} else if (only_rot(t->set.mode)) {
+		ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
+				STATE_DISABLE_CHAN_FAIL, ret);
+	} else if (ic_and_rot(t->set.mode)) {
+		ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
+				STATE_UNLINK_CHAN_FAIL, ret);
+		ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
+				STATE_DISABLE_CHAN_FAIL, ret);
+		ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+		CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
+				STATE_DISABLE_CHAN_FAIL, ret);
+		if (deinterlace_3_field(t)) {
+			ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+							true);
+			CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
+					STATE_DISABLE_CHAN_FAIL, ret);
+			ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+							true);
+			CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
+					STATE_DISABLE_CHAN_FAIL, ret);
+		}
+	}
+
+	if (only_ic(t->set.mode))
+		uninit_ic(ipu, t);
+	else if (only_rot(t->set.mode))
+		uninit_rot(ipu, t);
+	else if (ic_and_rot(t->set.mode)) {
+		uninit_ic(ipu, t);
+		uninit_rot(ipu, t);
+	}
+
+	t->state = STATE_OK;
+	CHECK_PERF(&t->ts_rel);
+	return;
+}
+
+static void do_task_vdoa_only(struct ipu_task_entry *t)
+{
+	int ret;
+
+	ret = init_tiled_ch_bufs(NULL, t);
+	CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
+	ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+	vdoa_stop(t->vdoa_handle);
+	CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
+			STATE_VDOA_IRQ_TIMEOUT, out, ret);
+
+	t->state = STATE_OK;
+out:
+	return;
+}
+
+static void do_task(struct ipu_task_entry *t)
+{
+	int r_size;
+	int irq;
+	int ret;
+	uint32_t busy;
+	struct ipu_soc *ipu = t->ipu;
+
+	CHECK_PERF(&t->ts_dotask);
+
+	if (!ipu) {
+		t->state = STATE_NO_IPU;
+		return;
+	}
+
+	init_completion(&t->irq_comp);
+	dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
+		 t->task_no, t->task_id);
+	dump_task_info(t);
+
+	if (t->set.task & IC_PP) {
+		t->set.ic_chan = MEM_PP_MEM;
+		dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
+	} else if (t->set.task & IC_VF) {
+		t->set.ic_chan = MEM_PRP_VF_MEM;
+		dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
+	} else if (t->set.task & VDI_VF) {
+		if (t->set.mode & VDOA_BAND_MODE) {
+			t->set.ic_chan = MEM_VDI_MEM;
+			if (deinterlace_3_field(t)) {
+				t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
+				t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
+			}
+			dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
+					 (void *)t);
+		} else {
+			t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
+			if (deinterlace_3_field(t)) {
+				t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
+				t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
+			}
+			dev_dbg(ipu->dev,
+				"[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
+		}
+	}
+
+	if (t->set.task & ROT_PP) {
+		t->set.rot_chan = MEM_ROT_PP_MEM;
+		dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
+	} else if (t->set.task & ROT_VF) {
+		t->set.rot_chan = MEM_ROT_VF_MEM;
+		dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
+	}
+
+	if (t->task_id == IPU_TASK_ID_VF)
+		busy = ic_vf_pp_is_busy(ipu, true);
+	else if (t->task_id == IPU_TASK_ID_PP)
+		busy = ic_vf_pp_is_busy(ipu, false);
+	else {
+		dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
+				t->task_no, t->task_id);
+		return;
+	}
+	if (busy) {
+		dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
+				(void *)t, t->task_no, t->task_id);
+		t->state = STATE_IPU_BUSY;
+		return;
+	}
+
+	irq = get_irq(t);
+	if (irq < 0) {
+		t->state = STATE_NO_IRQ;
+		return;
+	}
+	t->irq = irq;
+
+	/* channel setup */
+	if (only_ic(t->set.mode)) {
+		dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
+		ret = init_ic(ipu, t);
+		CHECK_RETCODE(ret < 0, "init_ic only_ic",
+				t->state, chan_setup, ret);
+	} else if (only_rot(t->set.mode)) {
+		dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
+		ret = init_rot(ipu, t);
+		CHECK_RETCODE(ret < 0, "init_rot only_rot",
+				t->state, chan_setup, ret);
+	} else if (ic_and_rot(t->set.mode)) {
+		int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
+
+		dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
+		t->set.r_fmt = t->output.format;
+		if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+			t->set.r_width = t->output.crop.h;
+			t->set.r_height = t->output.crop.w;
+		} else {
+			t->set.r_width = t->output.crop.w;
+			t->set.r_height = t->output.crop.h;
+		}
+		t->set.r_stride = t->set.r_width *
+			bytes_per_pixel(t->set.r_fmt);
+		r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
+			* fmt_to_bpp(t->set.r_fmt)/8);
+
+		if (r_size > ipu->rot_dma[rot_idx].size) {
+			dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
+
+			if (ipu->rot_dma[rot_idx].vaddr)
+				dma_free_coherent(t->dev,
+					ipu->rot_dma[rot_idx].size,
+					ipu->rot_dma[rot_idx].vaddr,
+					ipu->rot_dma[rot_idx].paddr);
+
+			ipu->rot_dma[rot_idx].size = r_size;
+			ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
+						r_size,
+						&ipu->rot_dma[rot_idx].paddr,
+						GFP_DMA | GFP_KERNEL);
+			CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
+					"ic_and_rot", STATE_SYS_NO_MEM,
+					chan_setup, -ENOMEM);
+		}
+		t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
+
+		dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
+		dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
+		dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
+		dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
+		dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
+
+		ret = init_ic(ipu, t);
+		CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
+				t->state, chan_setup, ret);
+		ret = init_rot(ipu, t);
+		CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
+				t->state, chan_setup, ret);
+		ret = ipu_link_channels(ipu, t->set.ic_chan,
+				t->set.rot_chan);
+		CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
+				STATE_LINK_CHAN_FAIL, chan_setup, ret);
+	} else {
+		dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
+		t->state = STATE_ERR;
+		return;
+	}
+
+	ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
+	CHECK_RETCODE(ret < 0, "ipu_req_irq",
+			STATE_IRQ_FAIL, chan_setup, ret);
+
+	/* enable/start channel */
+	if (only_ic(t->set.mode)) {
+		ret = ipu_enable_channel(ipu, t->set.ic_chan);
+		CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
+				STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		if (deinterlace_3_field(t)) {
+			ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+			CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
+					STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+			ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+			CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
+					STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		}
+
+		ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
+					0);
+		CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
+				STATE_SEL_BUF_FAIL, chan_buf, ret);
+		if (t->overlay_en) {
+			ret = ipu_select_buffer(ipu, t->set.ic_chan,
+						IPU_GRAPH_IN_BUFFER, 0);
+			CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
+					STATE_SEL_BUF_FAIL, chan_buf, ret);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+				ret = ipu_select_buffer(ipu, t->set.ic_chan,
+							IPU_ALPHA_IN_BUFFER, 0);
+				CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
+						STATE_SEL_BUF_FAIL, chan_buf,
+						ret);
+			}
+		}
+		if (!(t->set.mode & VDOA_BAND_MODE)) {
+			if (deinterlace_3_field(t))
+				ipu_select_multi_vdi_buffer(ipu, 0);
+			else {
+				ret = ipu_select_buffer(ipu, t->set.ic_chan,
+							IPU_INPUT_BUFFER, 0);
+				CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
+					STATE_SEL_BUF_FAIL, chan_buf, ret);
+			}
+		}
+	} else if (only_rot(t->set.mode)) {
+		ret = ipu_enable_channel(ipu, t->set.rot_chan);
+		CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
+				STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		ret = ipu_select_buffer(ipu, t->set.rot_chan,
+						IPU_OUTPUT_BUFFER, 0);
+		CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
+				STATE_SEL_BUF_FAIL, chan_buf, ret);
+		ret = ipu_select_buffer(ipu, t->set.rot_chan,
+						IPU_INPUT_BUFFER, 0);
+		CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
+				STATE_SEL_BUF_FAIL, chan_buf, ret);
+	} else if (ic_and_rot(t->set.mode)) {
+		ret = ipu_enable_channel(ipu, t->set.rot_chan);
+		CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
+				STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		ret = ipu_enable_channel(ipu, t->set.ic_chan);
+		CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
+				STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		if (deinterlace_3_field(t)) {
+			ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+			CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
+					STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+			ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+			CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
+					STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+		}
+
+		ret = ipu_select_buffer(ipu, t->set.rot_chan,
+						IPU_OUTPUT_BUFFER, 0);
+		CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
+				STATE_SEL_BUF_FAIL, chan_buf, ret);
+		if (t->overlay_en) {
+			ret = ipu_select_buffer(ipu, t->set.ic_chan,
+							IPU_GRAPH_IN_BUFFER, 0);
+			CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
+					STATE_SEL_BUF_FAIL, chan_buf, ret);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+				ret = ipu_select_buffer(ipu, t->set.ic_chan,
+							IPU_ALPHA_IN_BUFFER, 0);
+				CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
+						STATE_SEL_BUF_FAIL,
+						chan_buf, ret);
+			}
+		}
+		ret = ipu_select_buffer(ipu, t->set.ic_chan,
+						IPU_OUTPUT_BUFFER, 0);
+		CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
+				STATE_SEL_BUF_FAIL, chan_buf, ret);
+		if (deinterlace_3_field(t))
+			ipu_select_multi_vdi_buffer(ipu, 0);
+		else {
+			ret = ipu_select_buffer(ipu, t->set.ic_chan,
+							IPU_INPUT_BUFFER, 0);
+			CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
+					STATE_SEL_BUF_FAIL, chan_buf, ret);
+		}
+	}
+
+	if (need_split(t))
+		t->state = STATE_IN_PROGRESS;
+
+	if (t->set.mode & VDOA_BAND_MODE) {
+		ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+		CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
+				STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
+	}
+
+	CHECK_PERF(&t->ts_waitirq);
+	ret = wait_for_completion_timeout(&t->irq_comp,
+				 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+	CHECK_PERF(&t->ts_wakeup);
+	CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
+			STATE_IRQ_TIMEOUT, chan_rel, ret);
+	dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
+
+chan_rel:
+chan_buf:
+chan_en:
+chan_setup:
+	if (t->set.mode & VDOA_BAND_MODE)
+		vdoa_stop(t->vdoa_handle);
+	do_task_release(t, t->state >= STATE_ERR);
+	return;
+}
+
+static void do_task_vdoa_vdi(struct ipu_task_entry *t)
+{
+	int i;
+	int ret;
+	u32 stripe_width;
+
+	/* FIXME: crop mode not support now */
+	stripe_width = t->input.width >> 1;
+	t->input.crop.pos.x = 0;
+	t->input.crop.pos.y = 0;
+	t->input.crop.w = stripe_width;
+	t->input.crop.h = t->input.height;
+	t->output.crop.w = stripe_width;
+	t->output.crop.h = t->input.height;
+
+	for (i = 0; i < 2; i++) {
+		t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
+		t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
+		/* check input */
+		ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+			t->input.format);
+		if (ret < 0) {
+			ret = STATE_ERR;
+			goto done;
+		} else
+			update_offset(t->input.format,
+					t->input.width, t->input.height,
+					t->input.crop.pos.x,
+					t->input.crop.pos.y,
+					&t->set.i_off, &t->set.i_uoff,
+					&t->set.i_voff, &t->set.istride);
+		dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
+			t->set.i_off, t->set.i_uoff, t->set.istride);
+		/* check output */
+		ret = set_crop(&t->output.crop, t->input.width,
+					t->output.height, t->output.format);
+		if (ret < 0) {
+			ret = STATE_ERR;
+			goto done;
+		} else
+			update_offset(t->output.format,
+					t->output.width, t->output.height,
+					t->output.crop.pos.x,
+					t->output.crop.pos.y,
+					&t->set.o_off, &t->set.o_uoff,
+					&t->set.o_voff, &t->set.ostride);
+
+		dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
+				t->set.o_off, t->set.o_uoff, t->set.ostride);
+
+		do_task(t);
+	}
+
+	return;
+done:
+	dev_err(t->dev, "ERR %s set_crop.\n", __func__);
+	t->state = ret;
+	return;
+}
+
+static void get_res_do_task(struct ipu_task_entry *t)
+{
+	uint32_t	found;
+	uint32_t	split_child;
+	struct mutex	*lock;
+	struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
+
+	mutex_lock(&tbl->lock);
+
+	found = get_vdoa_ipu_res(t);
+	if (!found) {
+		dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
+			t, t->task_no);
+
+		if ((t->set.mode & VDOA_MODE) &&
+		    tbl->vdoa_used && t->vdoa_handle) {
+			tbl->vdoa_used = 0;
+			vdoa_put_handle(&t->vdoa_handle);
+		}
+
+		mutex_unlock(&tbl->lock);
+		return;
+	} else {
+		if (t->set.task & VDOA_ONLY)
+			do_task_vdoa_only(t);
+		else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+				(t->set.mode & VDOA_BAND_MODE) &&
+				(t->input.crop.w >
+				 soc_max_vdi_in_width(t->ipu)))
+			do_task_vdoa_vdi(t);
+		else
+			do_task(t);
+		put_vdoa_ipu_res(t, 0);
+	}
+	if (t->state != STATE_OK) {
+		dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
+			t, t->task_no, state_msg[t->state].msg);
+	}
+
+	mutex_unlock(&tbl->lock);
+
+	split_child = need_split(t) && t->parent;
+	if (split_child) {
+		lock = &t->parent->split_lock;
+		mutex_lock(lock);
+		t->split_done = 1;
+		mutex_unlock(lock);
+		wake_up(&t->parent->split_waitq);
+	}
+
+	return;
+}
+
+static void wait_split_task_complete(struct ipu_task_entry *parent,
+				struct ipu_split_task *sp_task, uint32_t size)
+{
+	struct ipu_task_entry *tsk = NULL;
+	int ret = 0, rc;
+	int j, idx = -1;
+	unsigned long flags;
+	struct mutex *lock = &parent->split_lock;
+	int k, busy_vf, busy_pp;
+	struct ipu_soc *ipu;
+	DECLARE_PERF_VAR;
+
+	for (j = 0; j < size; j++) {
+		rc = wait_event_timeout(
+			parent->split_waitq,
+			sp_task_check_done(sp_task, parent, size, &idx),
+			msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
+		if (!rc) {
+			dev_err(parent->dev,
+				"ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
+				"size:%d.\n",
+				 parent, parent->task_no, j, size);
+			ret = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (idx < 0) {
+				dev_err(parent->dev,
+				"ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
+				 parent, parent->task_no, idx);
+				continue;
+			}
+			tsk = sp_task[idx].child_task;
+			mutex_lock(lock);
+			if (!tsk->split_done || !tsk->ipu)
+				dev_err(tsk->dev,
+				"ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
+				 tsk->task_no, tsk->split_done, tsk->ipu);
+			tsk->split_done = 0;
+			mutex_unlock(lock);
+
+			dev_dbg(tsk->dev,
+				"[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
+				 tsk, tsk->task_no, idx, tsk->state);
+			#ifdef DBG_IPU_PERF
+				CHECK_PERF(&tsk->ts_rel);
+				PRINT_TASK_STATISTICS;
+			#endif
+		}
+	}
+
+out:
+	if (ret == -ETIMEDOUT) {
+		/* debug */
+		for (k = 0; k < max_ipu_no; k++) {
+			ipu = ipu_get_soc(k);
+			if (IS_ERR(ipu)) {
+				dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
+				 parent->task_no, k);
+			} else {
+				busy_vf = ic_vf_pp_is_busy(ipu, true);
+				busy_pp = ic_vf_pp_is_busy(ipu, false);
+				dev_err(parent->dev,
+					"ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
+					k, busy_vf, busy_pp);
+			}
+		}
+		for (k = 0; k < size; k++) {
+			tsk = sp_task[k].child_task;
+			if (!tsk)
+				continue;
+			dev_err(parent->dev,
+				"ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
+				 "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
+				 k, tsk, tsk->task_no, tsk->split_done,
+				 state_msg[tsk->state].msg, tsk->task_in_list,
+				 tsk->ipu);
+		}
+	}
+
+	for (j = 0; j < size; j++) {
+		tsk = sp_task[j].child_task;
+		if (!tsk)
+			continue;
+		spin_lock_irqsave(&ipu_task_list_lock, flags);
+		if (tsk->task_in_list) {
+			list_del(&tsk->node);
+			tsk->task_in_list = 0;
+			dev_dbg(tsk->dev,
+				"[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
+				 tsk, tsk->task_no, tsk->task_id);
+		}
+		spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+		if (!tsk->ipu)
+			continue;
+		if (tsk->state != STATE_OK) {
+			dev_err(tsk->dev,
+				"ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
+					tsk, tsk->task_no, tsk->task_id,
+					state_msg[tsk->state].msg);
+		}
+		kref_put(&tsk->refcount, task_mem_free);
+	}
+
+	kfree(parent->vditmpbuf[0]);
+	kfree(parent->vditmpbuf[1]);
+
+	if (ret < 0)
+		parent->state = STATE_TIMEOUT;
+	else
+		parent->state = STATE_OK;
+	return;
+}
+
+static inline int find_task(struct ipu_task_entry **t, int thread_id)
+{
+	int found;
+	unsigned long flags;
+	struct ipu_task_entry *tsk;
+	struct list_head *task_list = &ipu_task_list;
+
+	*t = NULL;
+	spin_lock_irqsave(&ipu_task_list_lock, flags);
+	found = !list_empty(task_list);
+	if (found) {
+		tsk = list_first_entry(task_list, struct ipu_task_entry, node);
+		if (tsk->task_in_list) {
+			list_del(&tsk->node);
+			tsk->task_in_list = 0;
+			*t = tsk;
+			kref_get(&tsk->refcount);
+			dev_dbg(tsk->dev,
+			"thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
+			thread_id, tsk, tsk->task_no, tsk->set.mode);
+		} else
+			dev_err(tsk->dev,
+			"thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
+			thread_id, tsk->task_no, tsk->set.mode);
+	}
+	spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+	return found;
+}
+
+static int ipu_task_thread(void *argv)
+{
+	struct ipu_task_entry *tsk;
+	struct ipu_task_entry *sp_tsk0;
+	struct ipu_split_task sp_task[4];
+	/* priority lower than irq_thread */
+	const struct sched_param param = {
+		.sched_priority = MAX_USER_RT_PRIO/2 - 1,
+	};
+	int ret;
+	int curr_thread_id;
+	uint32_t size;
+	unsigned long flags;
+	unsigned int cpu;
+	struct cpumask cpu_mask;
+	struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
+
+	thread_id++;
+	curr_thread_id = thread_id;
+	sched_setscheduler(current, SCHED_FIFO, &param);
+
+	if (!data->is_vdoa) {
+		cpu = cpumask_first(cpu_online_mask);
+		cpumask_set_cpu(cpu, &cpu_mask);
+		ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
+			&cpu_mask);
+		if (ret < 0) {
+			pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
+		}
+		pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
+	}
+
+	while (!kthread_should_stop()) {
+		int split_fail = 0;
+		int split_parent;
+		int split_child;
+
+		wait_event_interruptible(thread_waitq, find_task(&tsk, curr_thread_id));
+
+		if (!tsk) {
+			pr_err("thread:%d can not find task.\n",
+				curr_thread_id);
+			continue;
+		}
+
+		/* note: other threads run split child task */
+		split_parent = need_split(tsk) && !tsk->parent;
+		split_child = need_split(tsk) && tsk->parent;
+		if (split_parent) {
+			if ((tsk->set.split_mode == RL_SPLIT) ||
+				 (tsk->set.split_mode == UD_SPLIT))
+				size = 2;
+			else
+				size = 4;
+			ret = queue_split_task(tsk, sp_task, size);
+			if (ret < 0) {
+				split_fail = 1;
+			} else {
+				struct list_head *pos;
+
+				spin_lock_irqsave(&ipu_task_list_lock, flags);
+
+				sp_tsk0 = list_first_entry(&tsk->split_list,
+						struct ipu_task_entry, node);
+				list_del(&sp_tsk0->node);
+
+				list_for_each(pos, &tsk->split_list) {
+					struct ipu_task_entry *tmp;
+
+					tmp = list_entry(pos,
+						struct ipu_task_entry, node);
+					tmp->task_in_list = 1;
+					dev_dbg(tmp->dev,
+						"[0x%p] no-0x%x,id:%d sp_tsk "
+						"add_to_list.\n", tmp,
+						tmp->task_no, tmp->task_id);
+				}
+				/* add to global list */
+				list_splice(&tsk->split_list, &ipu_task_list);
+
+				spin_unlock_irqrestore(&ipu_task_list_lock,
+									flags);
+				/* let the parent thread do the first sp_task */
+				/* FIXME: ensure the correct sequence for split
+					4size: 5/6->9/a*/
+				wake_up_interruptible(&thread_waitq);
+				get_res_do_task(sp_tsk0);
+				dev_dbg(sp_tsk0->dev,
+					"thread:%d complete tsk no:0x%x.\n",
+					curr_thread_id, sp_tsk0->task_no);
+				ret = atomic_read(&req_cnt);
+				if (ret > 0) {
+					wake_up(&res_waitq);
+					dev_dbg(sp_tsk0->dev,
+					"sp_tsk0 sche thread:%d no:0x%x,"
+					"req_cnt:%d\n", curr_thread_id,
+					sp_tsk0->task_no, ret);
+					/* For other threads to get_res */
+					schedule();
+				}
+			}
+		} else
+			get_res_do_task(tsk);
+
+		/* wait for all 4 sp_task finished here or timeout
+			and then release all resources */
+		if (split_parent && !split_fail)
+			wait_split_task_complete(tsk, sp_task, size);
+
+		if (!split_child) {
+			atomic_inc(&tsk->done);
+			wake_up(&tsk->task_waitq);
+		}
+
+		dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
+				curr_thread_id, tsk->task_no, tsk);
+		ret = atomic_read(&req_cnt);
+		if (ret > 0) {
+			wake_up(&res_waitq);
+			dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
+				curr_thread_id, tsk->task_no, ret);
+			/* note: give cpu to other threads to get_res */
+			schedule();
+		}
+
+		kref_put(&tsk->refcount, task_mem_free);
+	}
+
+	pr_info("ERR %s exit.\n", __func__);
+	return 0;
+}
+
+int ipu_check_task(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+	int ret = 0;
+
+	tsk = create_task_entry(task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	ret = check_task(tsk);
+
+	task->input = tsk->input;
+	task->output = tsk->output;
+	task->overlay = tsk->overlay;
+	dump_task_info(tsk);
+
+	kref_put(&tsk->refcount, task_mem_free);
+	if (ret != 0)
+		pr_debug("%s ret:%d.\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_check_task);
+
+int ipu_queue_task(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+	unsigned long flags;
+	int ret;
+	u32 tmp_task_no;
+	DECLARE_PERF_VAR;
+
+	tsk = create_task_entry(task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	CHECK_PERF(&tsk->ts_queue);
+	ret = prepare_task(tsk);
+	if (ret < 0)
+		goto done;
+
+	if (need_split(tsk)) {
+		CHECK_PERF(&tsk->ts_dotask);
+		CHECK_PERF(&tsk->ts_waitirq);
+		CHECK_PERF(&tsk->ts_inirq);
+		CHECK_PERF(&tsk->ts_wakeup);
+	}
+
+	/* task_no last four bits for split task type*/
+	tmp_task_no = atomic_inc_return(&frame_no);
+	tsk->task_no = tmp_task_no << 4;
+	init_waitqueue_head(&tsk->task_waitq);
+
+	spin_lock_irqsave(&ipu_task_list_lock, flags);
+	list_add_tail(&tsk->node, &ipu_task_list);
+	tsk->task_in_list = 1;
+	dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
+	spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+	wake_up_interruptible(&thread_waitq);
+
+	ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
+						msecs_to_jiffies(tsk->timeout));
+	if (0 == ret) {
+		/* note: the timeout should larger than the internal timeout!*/
+		ret = -ETIMEDOUT;
+		dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
+				tsk, tsk->task_no, tsk->timeout);
+	} else {
+		if (STATE_OK != tsk->state) {
+			dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
+				tsk, tsk->task_no, tsk->state,
+				state_msg[tsk->state].msg);
+			ret = -ECANCELED;
+		} else
+			ret = 0;
+	}
+
+	spin_lock_irqsave(&ipu_task_list_lock, flags);
+	if (tsk->task_in_list) {
+		list_del(&tsk->node);
+		tsk->task_in_list = 0;
+		dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
+				tsk, tsk->task_no);
+	}
+	spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+#ifdef DBG_IPU_PERF
+	CHECK_PERF(&tsk->ts_rel);
+	PRINT_TASK_STATISTICS;
+	if (ts_frame_avg == 0)
+		ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
+				ts_frame.tv_sec * USEC_PER_SEC;
+	else
+		ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
+				+ ts_frame.tv_sec * USEC_PER_SEC)/2;
+	if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
+		ts_frame_max = ts_frame;
+
+	atomic_inc(&frame_cnt);
+
+	if ((atomic_read(&frame_cnt) %  1000) == 0)
+		pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
+			"frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
+			+ ts_frame_max.tv_sec * USEC_PER_SEC,
+			ts_frame_avg, atomic_read(&frame_cnt));
+#endif
+done:
+	if (ret < 0)
+		dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
+				tsk->task_no, ret);
+
+	kref_put(&tsk->refcount, task_mem_free);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_queue_task);
+
+static int mxc_ipu_open(struct inode *inode, struct file *file)
+{
+	file->private_data = (void *)atomic_inc_return(&file_index);
+	return 0;
+}
+
+static long mxc_ipu_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	switch (cmd) {
+	case IPU_CHECK_TASK:
+		{
+			struct ipu_task task;
+
+			if (copy_from_user
+					(&task, (struct ipu_task *) arg,
+					 sizeof(struct ipu_task)))
+				return -EFAULT;
+			ret = ipu_check_task(&task);
+			if (copy_to_user((struct ipu_task *) arg,
+				&task, sizeof(struct ipu_task)))
+				return -EFAULT;
+			break;
+		}
+	case IPU_QUEUE_TASK:
+		{
+			struct ipu_task task;
+
+			if (copy_from_user
+					(&task, (struct ipu_task *) arg,
+					 sizeof(struct ipu_task)))
+				return -EFAULT;
+			ret = ipu_queue_task(&task);
+			break;
+		}
+	case IPU_ALLOC:
+		{
+			int size;
+			struct ipu_alloc_list *mem;
+
+			mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+			if (mem == NULL)
+				return -ENOMEM;
+
+			if (get_user(size, argp)) {
+				kfree(mem);
+				return -EFAULT;
+			}
+
+			mem->size = PAGE_ALIGN(size);
+
+			mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
+							   &mem->phy_addr,
+							   GFP_DMA | GFP_KERNEL);
+			if (mem->cpu_addr == NULL) {
+				kfree(mem);
+				return -ENOMEM;
+			}
+			mem->file_index = file->private_data;
+			mutex_lock(&ipu_alloc_lock);
+			list_add(&mem->list, &ipu_alloc_list);
+			mutex_unlock(&ipu_alloc_lock);
+
+			if (put_user(mem->phy_addr, argp)) {
+				mutex_lock(&ipu_alloc_lock);
+				list_del(&mem->list);
+				mutex_unlock(&ipu_alloc_lock);
+				dma_free_coherent(ipu_dev,
+						  mem->size,
+						  mem->cpu_addr,
+						  mem->phy_addr);
+				kfree(mem);
+				return -EFAULT;
+			}
+
+			dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
+				mem->size, mem->phy_addr);
+
+			break;
+		}
+	case IPU_FREE:
+		{
+			unsigned long offset;
+			struct ipu_alloc_list *mem;
+
+			if (get_user(offset, argp))
+				return -EFAULT;
+
+			ret = -EINVAL;
+			mutex_lock(&ipu_alloc_lock);
+			list_for_each_entry(mem, &ipu_alloc_list, list) {
+				if (mem->phy_addr == offset) {
+					list_del(&mem->list);
+					dma_free_coherent(ipu_dev,
+							  mem->size,
+							  mem->cpu_addr,
+							  mem->phy_addr);
+					kfree(mem);
+					ret = 0;
+					break;
+				}
+			}
+			mutex_unlock(&ipu_alloc_lock);
+			if (0 == ret)
+				dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
+					mem->size, mem->phy_addr);
+
+			break;
+		}
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	bool found = false;
+	u32 len;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct ipu_alloc_list *mem;
+
+	mutex_lock(&ipu_alloc_lock);
+	list_for_each_entry(mem, &ipu_alloc_list, list) {
+		if (offset == mem->phy_addr) {
+			found = true;
+			len = mem->size;
+			break;
+		}
+	}
+	mutex_unlock(&ipu_alloc_lock);
+	if (!found)
+		return -EINVAL;
+
+	if (vma->vm_end - vma->vm_start > len)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot)) {
+		printk(KERN_ERR
+				"mmap failed!\n");
+		return -ENOBUFS;
+	}
+	return 0;
+}
+
+static int mxc_ipu_release(struct inode *inode, struct file *file)
+{
+	struct ipu_alloc_list *mem;
+	struct ipu_alloc_list *n;
+
+	mutex_lock(&ipu_alloc_lock);
+	list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
+		if ((mem->cpu_addr != 0) &&
+			(file->private_data == mem->file_index)) {
+			list_del(&mem->list);
+			dma_free_coherent(ipu_dev,
+					  mem->size,
+					  mem->cpu_addr,
+					  mem->phy_addr);
+			dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
+				mem->size, mem->phy_addr);
+			kfree(mem);
+		}
+	}
+	mutex_unlock(&ipu_alloc_lock);
+	atomic_dec(&file_index);
+
+	return 0;
+}
+
+static struct file_operations mxc_ipu_fops = {
+	.owner = THIS_MODULE,
+	.open = mxc_ipu_open,
+	.mmap = mxc_ipu_mmap,
+	.release = mxc_ipu_release,
+	.unlocked_ioctl = mxc_ipu_ioctl,
+};
+
+int register_ipu_device(struct ipu_soc *ipu, int id)
+{
+	int ret = 0;
+	static int idx;
+	static struct ipu_thread_data thread_data[5];
+
+	if (!major) {
+		major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
+		if (major < 0) {
+			printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
+			ret = major;
+			goto register_cdev_fail;
+		}
+
+		ipu_class = class_create(THIS_MODULE, "mxc_ipu");
+		if (IS_ERR(ipu_class)) {
+			ret = PTR_ERR(ipu_class);
+			goto ipu_class_fail;
+		}
+
+		ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
+				NULL, "mxc_ipu");
+		if (IS_ERR(ipu_dev)) {
+			ret = PTR_ERR(ipu_dev);
+			goto dev_create_fail;
+		}
+		ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
+		*ipu_dev->dma_mask = DMA_BIT_MASK(32);
+		ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+		mutex_init(&ipu_ch_tbl.lock);
+	}
+	max_ipu_no = ++id;
+	ipu->rot_dma[0].size = 0;
+	ipu->rot_dma[1].size = 0;
+
+	thread_data[idx].ipu = ipu;
+	thread_data[idx].id = 0;
+	thread_data[idx].is_vdoa = 0;
+	ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
+					"ipu%d_task", id);
+	if (IS_ERR(ipu->thread[0])) {
+		ret = PTR_ERR(ipu->thread[0]);
+		goto kthread0_fail;
+	}
+
+	thread_data[idx].ipu = ipu;
+	thread_data[idx].id = 1;
+	thread_data[idx].is_vdoa = 0;
+	ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
+				"ipu%d_task", id);
+	if (IS_ERR(ipu->thread[1])) {
+		ret = PTR_ERR(ipu->thread[1]);
+		goto kthread1_fail;
+	}
+
+
+	return ret;
+
+kthread1_fail:
+	kthread_stop(ipu->thread[0]);
+kthread0_fail:
+	if (id == 0)
+		device_destroy(ipu_class, MKDEV(major, 0));
+dev_create_fail:
+	if (id == 0) {
+		class_destroy(ipu_class);
+	}
+ipu_class_fail:
+	if (id == 0)
+		unregister_chrdev(major, "mxc_ipu");
+register_cdev_fail:
+	return ret;
+}
+
+void unregister_ipu_device(struct ipu_soc *ipu, int id)
+{
+	int i;
+
+	kthread_stop(ipu->thread[0]);
+	kthread_stop(ipu->thread[1]);
+	for (i = 0; i < 2; i++) {
+		if (ipu->rot_dma[i].vaddr)
+			dma_free_coherent(ipu_dev,
+				ipu->rot_dma[i].size,
+				ipu->rot_dma[i].vaddr,
+				ipu->rot_dma[i].paddr);
+	}
+
+	if (major) {
+		device_destroy(ipu_class, MKDEV(major, 0));
+		class_destroy(ipu_class);
+		unregister_chrdev(major, "mxc_ipu");
+		major = 0;
+	}
+}
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_disp.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_disp.c
@@ -0,0 +1,1993 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_disp.c
+ *
+ * @brief IPU display submodule API functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+#define SYNC_WAVE 0
+#define NULL_WAVE (-1)
+#define ASYNC_SER_WAVE 6
+
+/* DC display ID assignments */
+#define DC_DISP_ID_SYNC(di)	(di)
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+int dmfc_type_setup;
+
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first)
+{
+	u32 dmfc_wr_chan, dmfc_dp_chan;
+
+	if (first) {
+		if (dmfc_type_setup > dmfc_type)
+			dmfc_type = dmfc_type_setup;
+		else
+			dmfc_type_setup = dmfc_type;
+
+		/* disable DMFC-IC channel*/
+		ipu_dmfc_write(ipu, 0x2, DMFC_IC_CTRL);
+	} else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
+		dev_dbg(ipu->dev, "DMFC high resolution has set, will not change\n");
+		return;
+	} else
+		dmfc_type_setup = dmfc_type;
+
+	if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
+		/* 1 - segment 0~3;
+		 * 5B - segement 4, 5;
+		 * 5F - segement 6, 7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC DC HIGH RESOLUTION: 1(0~3), 5B(4,5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000088;
+		dmfc_dp_chan = 0x00009694;
+		ipu->dmfc_size_28 = 256*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 128*4;
+	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
+		/* 1 - segment 0, 1;
+		 * 5B - segement 2~5;
+		 * 5F - segement 6,7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC DP HIGH RESOLUTION: 1(0,1), 5B(2~5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000090;
+		dmfc_dp_chan = 0x0000968a;
+		ipu->dmfc_size_28 = 128*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 256*4;
+	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
+		/* 5B - segement 0~3;
+		 * 5F - segement 4~7;
+		 * 1, 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC ONLY-DP HIGH RESOLUTION: 5B(0~3), 5F(4~7)\n");
+		dmfc_wr_chan = 0x00000000;
+		dmfc_dp_chan = 0x00008c88;
+		ipu->dmfc_size_28 = 0;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 256*4;
+		ipu->dmfc_size_23 = 256*4;
+	} else {
+		/* 1 - segment 0, 1;
+		 * 5B - segement 4, 5;
+		 * 5F - segement 6, 7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000090;
+		dmfc_dp_chan = 0x00009694;
+		ipu->dmfc_size_28 = 128*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 128*4;
+	}
+	ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+	ipu_dmfc_write(ipu, 0x202020F6, DMFC_WR_CHAN_DEF);
+	ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+	/* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
+	ipu_dmfc_write(ipu, 0x2020F6F6, DMFC_DP_CHAN_DEF);
+}
+
+static int __init dmfc_setup(char *options)
+{
+	get_option(&options, &dmfc_type_setup);
+	if (dmfc_type_setup > DMFC_HIGH_RESOLUTION_ONLY_DP)
+		dmfc_type_setup = DMFC_HIGH_RESOLUTION_ONLY_DP;
+	return 1;
+}
+__setup("dmfc=", dmfc_setup);
+
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width)
+{
+	u32 dmfc_gen1 = ipu_dmfc_read(ipu, DMFC_GENERAL1);
+
+	if (width >= HIGH_RESOLUTION_WIDTH) {
+		if (dma_chan == 23)
+			_ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DP, 0);
+		else if (dma_chan == 28)
+			_ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DC, 0);
+	}
+
+	if (dma_chan == 23) { /*5B*/
+		if (ipu->dmfc_size_23/width > 3)
+			dmfc_gen1 |= 1UL << 20;
+		else
+			dmfc_gen1 &= ~(1UL << 20);
+	} else if (dma_chan == 24) { /*6B*/
+		if (ipu->dmfc_size_24/width > 1)
+			dmfc_gen1 |= 1UL << 22;
+		else
+			dmfc_gen1 &= ~(1UL << 22);
+	} else if (dma_chan == 27) { /*5F*/
+		if (ipu->dmfc_size_27/width > 2)
+			dmfc_gen1 |= 1UL << 21;
+		else
+			dmfc_gen1 &= ~(1UL << 21);
+	} else if (dma_chan == 28) { /*1*/
+		if (ipu->dmfc_size_28/width > 2)
+			dmfc_gen1 |= 1UL << 16;
+		else
+			dmfc_gen1 &= ~(1UL << 16);
+	} else if (dma_chan == 29) { /*6F*/
+		if (ipu->dmfc_size_29/width > 1)
+			dmfc_gen1 |= 1UL << 23;
+		else
+			dmfc_gen1 &= ~(1UL << 23);
+	}
+
+	ipu_dmfc_write(ipu, dmfc_gen1, DMFC_GENERAL1);
+}
+
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size)
+{
+	u32 dmfc_wr_chan = ipu_dmfc_read(ipu, DMFC_WR_CHAN);
+	u32 dmfc_dp_chan = ipu_dmfc_read(ipu, DMFC_DP_CHAN);
+	int dmfc_bs = 0;
+
+	switch (burst_size) {
+	case 64:
+		dmfc_bs = 0x40;
+		break;
+	case 32:
+	case 20:
+		dmfc_bs = 0x80;
+		break;
+	case 16:
+		dmfc_bs = 0xc0;
+		break;
+	default:
+		dev_err(ipu->dev, "Unsupported burst size %d\n",
+			burst_size);
+		return;
+	}
+
+	if (dma_chan == 23) { /*5B*/
+		dmfc_dp_chan &= ~(0xc0);
+		dmfc_dp_chan |= dmfc_bs;
+	} else if (dma_chan == 27) { /*5F*/
+		dmfc_dp_chan &= ~(0xc000);
+		dmfc_dp_chan |= (dmfc_bs << 8);
+	} else if (dma_chan == 28) { /*1*/
+		dmfc_wr_chan &= ~(0xc0);
+		dmfc_wr_chan |= dmfc_bs;
+	}
+
+	ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+	ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+}
+
+static void _ipu_di_data_wave_config(struct ipu_soc *ipu,
+				int di, int wave_gen,
+				int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void _ipu_di_data_pin_config(struct ipu_soc *ipu,
+			int di, int wave_gen, int di_pin, int set,
+			int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(ipu, di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(ipu, di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void _ipu_di_sync_config(struct ipu_soc *ipu,
+				int di, int wave_gen,
+				int run_count, int run_src,
+				int offset_count, int offset_src,
+				int repeat_count, int cnt_clr_src,
+				int cnt_polarity_gen_en,
+				int cnt_polarity_clr_src,
+				int cnt_polarity_trigger_src,
+				int cnt_up, int cnt_down)
+{
+	u32 reg;
+
+	if ((run_count >= 0x1000) || (offset_count >= 0x1000) || (repeat_count >= 0x1000) ||
+		(cnt_up >= 0x400) || (cnt_down >= 0x400)) {
+		dev_err(ipu->dev, "DI%d counters out of range.\n", di);
+		return;
+	}
+
+	reg = (run_count << 19) | (++run_src << 16) |
+	    (offset_count << 3) | ++offset_src;
+	ipu_di_write(ipu, di, reg, DI_SW_GEN0(wave_gen));
+	reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
+	    (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
+	reg |= (cnt_down << 16) | cnt_up;
+	if (repeat_count == 0) {
+		/* Enable auto reload */
+		reg |= 0x10000000;
+	}
+	ipu_di_write(ipu, di, reg, DI_SW_GEN1(wave_gen));
+	reg = ipu_di_read(ipu, di, DI_STP_REP(wave_gen));
+	reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
+	reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
+	ipu_di_write(ipu, di, reg, DI_STP_REP(wave_gen));
+}
+
+static void _ipu_dc_map_link(struct ipu_soc *ipu,
+		int current_map,
+		int base_map_0, int buf_num_0,
+		int base_map_1, int buf_num_1,
+		int base_map_2, int buf_num_2)
+{
+	int ptr_0 = base_map_0 * 3 + buf_num_0;
+	int ptr_1 = base_map_1 * 3 + buf_num_1;
+	int ptr_2 = base_map_2 * 3 + buf_num_2;
+	int ptr;
+	u32 reg;
+	ptr = (ptr_2 << 10) +  (ptr_1 << 5) + ptr_0;
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(current_map));
+	reg &= ~(0x1F << ((16 * (current_map & 0x1))));
+	reg |= ptr << ((16 * (current_map & 0x1)));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(current_map));
+}
+
+static void _ipu_dc_map_config(struct ipu_soc *ipu,
+		int map, int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_map_clear(struct ipu_soc *ipu, int map)
+{
+	u32 reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+	ipu_dc_write(ipu, reg & ~(0xFFFF << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_write_tmpl(struct ipu_soc *ipu,
+			int word, u32 opcode, u32 operand, int map,
+			int wave, int glue, int sync, int stop)
+{
+	u32 reg;
+
+	if (opcode == WRG) {
+		reg = sync;
+		reg |= (glue << 4);
+		reg |= (++wave << 11);
+		reg |= ((operand & 0x1FFFF) << 15);
+		ipu_dc_tmpl_write(ipu, reg, word * 8);
+
+		reg = (operand >> 17);
+		reg |= opcode << 7;
+		reg |= (stop << 9);
+		ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
+	} else {
+		reg = sync;
+		reg |= (glue << 4);
+		reg |= (++wave << 11);
+		reg |= (++map << 15);
+		reg |= (operand << 20) & 0xFFF00000;
+		ipu_dc_tmpl_write(ipu, reg, word * 8);
+
+		reg = (operand >> 12);
+		reg |= opcode << 4;
+		reg |= (stop << 9);
+		ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
+	}
+}
+
+static void _ipu_dc_link_event(struct ipu_soc *ipu,
+		int chan, int event, int addr, int priority)
+{
+	u32 reg;
+	u32 address_shift;
+	if (event < DC_EVEN_UGDE0) {
+		reg = ipu_dc_read(ipu, DC_RL_CH(chan, event));
+		reg &= ~(0xFFFF << (16 * (event & 0x1)));
+		reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+		ipu_dc_write(ipu, reg, DC_RL_CH(chan, event));
+	} else {
+		reg = ipu_dc_read(ipu, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+		if ((event - DC_EVEN_UGDE0) & 0x1) {
+			reg &= ~(0x2FF << 16);
+			reg |= (addr << 16);
+			reg |= priority ? (2 << 24) : 0x0;
+		} else {
+			reg &= ~0xFC00FFFF;
+			if (priority)
+				chan = (chan >> 1) +
+					((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3));
+			else
+				chan = 0x7;
+			address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8;
+			reg |= (addr << address_shift) | (priority << 3) | chan;
+		}
+		ipu_dc_write(ipu, reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+	}
+}
+
+/*     Y = R *  1.200 + G *  2.343 + B *  .453 + 0.250;
+       U = R * -.672 + G * -1.328 + B *  2.000 + 512.250.;
+       V = R *  2.000 + G * -1.672 + B * -.328 + 512.250.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{0x4D, 0x96, 0x1D},
+	{-0x2B, -0x55, 0x80},
+	{0x80, -0x6B, -0x15},
+	{0x0000, 0x0200, 0x0200},	/* B0, B1, B2 */
+	{0x2, 0x2, 0x2},	/* S0, S1, S2 */
+};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+	{0x095, 0x000, 0x0CC},
+	{0x095, 0x3CE, 0x398},
+	{0x095, 0x0FF, 0x000},
+	{0x3E42, 0x010A, 0x3DD6},	/*B0,B1,B2 */
+	{0x1, 0x1, 0x1},	/*S0,S1,S2 */
+};
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+/* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+	int c;
+	c = red * rgb2ycbcr_coeff[n][0];
+	c += green * rgb2ycbcr_coeff[n][1];
+	c += blue * rgb2ycbcr_coeff[n][2];
+	c /= 16;
+	c += rgb2ycbcr_coeff[3][n] * 4;
+	c += 8;
+	c /= 16;
+	if (c < 0)
+		c = 0;
+	if (c > 255)
+		c = 255;
+	return c;
+}
+
+/*
+ * Row is for BG: 	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+{
+	{DP_COM_CONF_CSC_DEF_BOTH, (void *)&rgb2ycbcr_coeff},
+	{0, 0}, {0, 0},
+	{DP_COM_CONF_CSC_DEF_BG, (void *)&rgb2ycbcr_coeff},
+	{DP_COM_CONF_CSC_DEF_BG, (void *)&rgb2ycbcr_coeff}
+},
+{
+	{0, 0},
+	{DP_COM_CONF_CSC_DEF_BOTH, (void *)&ycbcr2rgb_coeff},
+	{DP_COM_CONF_CSC_DEF_BG, (void *)&ycbcr2rgb_coeff},
+	{0, 0},
+	{DP_COM_CONF_CSC_DEF_BG, (void *)&ycbcr2rgb_coeff}
+},
+{
+	{0, 0},
+	{DP_COM_CONF_CSC_DEF_FG, (void *)&ycbcr2rgb_coeff},
+	{0, 0}, {0, 0}, {0, 0}
+},
+{
+	{DP_COM_CONF_CSC_DEF_FG, (void *)&rgb2ycbcr_coeff},
+	{0, 0}, {0, 0}, {0, 0}, {0, 0}
+},
+{
+	{DP_COM_CONF_CSC_DEF_FG, (void *)&rgb2ycbcr_coeff},
+	{DP_COM_CONF_CSC_DEF_FG, (void *)&ycbcr2rgb_coeff},
+	{0, 0}, {0, 0}, {0, 0}
+}
+};
+
+void __ipu_dp_csc_setup(struct ipu_soc *ipu,
+		int dp, struct dp_csc_param_t dp_csc_param,
+		bool srm_mode_update)
+{
+	u32 reg;
+	const int (*coeff)[5][3];
+
+	if (dp_csc_param.mode >= 0) {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(dp));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		ipu_dp_write(ipu, reg, DP_COM_CONF(dp));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		ipu_dp_write(ipu, mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(dp));
+		ipu_dp_write(ipu, mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+				(mask_b((*coeff)[3][2]) << 16) |
+				((*coeff)[4][2] << 30), DP_CSC_1(dp));
+	}
+
+	if (srm_mode_update) {
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+}
+
+int _ipu_dp_init(struct ipu_soc *ipu,
+		ipu_channel_t channel, uint32_t in_pixel_fmt,
+		uint32_t out_pixel_fmt)
+{
+	int in_fmt, out_fmt;
+	int dp;
+	int partial = false;
+	uint32_t reg;
+
+	if (channel == MEM_FG_SYNC) {
+		dp = DP_SYNC;
+		partial = true;
+	} else if (channel == MEM_BG_SYNC) {
+		dp = DP_SYNC;
+		partial = false;
+	} else if (channel == MEM_BG_ASYNC0) {
+		dp = DP_ASYNC0;
+		partial = false;
+	} else {
+		return -EINVAL;
+	}
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (partial) {
+		if (in_fmt == RGB) {
+			if (out_fmt == RGB)
+				ipu->fg_csc_type = RGB2RGB;
+			else
+				ipu->fg_csc_type = RGB2YUV;
+		} else {
+			if (out_fmt == RGB)
+				ipu->fg_csc_type = YUV2RGB;
+			else
+				ipu->fg_csc_type = YUV2YUV;
+		}
+	} else {
+		if (in_fmt == RGB) {
+			if (out_fmt == RGB)
+				ipu->bg_csc_type = RGB2RGB;
+			else
+				ipu->bg_csc_type = RGB2YUV;
+		} else {
+			if (out_fmt == RGB)
+				ipu->bg_csc_type = YUV2RGB;
+			else
+				ipu->bg_csc_type = YUV2YUV;
+		}
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = ipu_dp_read(ipu, DP_COM_CONF(dp));
+	if (ipu->color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2RGB) && (ipu->bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		uint32_t color_key = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 0xFFFFFFL;
+
+		dev_dbg(ipu->dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 0xFF000000L;
+		ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(dp));
+		ipu->color_key_4rgb = false;
+
+		dev_dbg(ipu->dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(ipu, dp,
+			   dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type],
+			   false);
+
+	return 0;
+}
+
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	int dp;
+	int partial = false;
+
+	if (channel == MEM_FG_SYNC) {
+		dp = DP_SYNC;
+		partial = true;
+	} else if (channel == MEM_BG_SYNC) {
+		dp = DP_SYNC;
+		partial = false;
+	} else if (channel == MEM_BG_ASYNC0) {
+		dp = DP_ASYNC0;
+		partial = false;
+	} else {
+		return;
+	}
+
+	if (partial)
+		ipu->fg_csc_type = CSC_NONE;
+	else
+		ipu->bg_csc_type = CSC_NONE;
+
+	__ipu_dp_csc_setup(ipu, dp, dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type], false);
+}
+
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt)
+{
+	u32 reg = 0;
+
+	if ((dc_chan == 1) || (dc_chan == 5)) {
+		if (interlaced) {
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 3);
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 2);
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 1);
+		} else {
+			if (di) {
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 2, 3);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 3, 2);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 1, 1);
+				if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+					_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 9, 5);
+					_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 8, 5);
+				}
+			} else {
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 5, 3);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 6, 2);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 12, 1);
+				if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+					_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 10, 5);
+					_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 11, 5);
+				}
+			}
+		}
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+		reg = 0x2;
+		reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+		reg |= di << 2;
+		if (interlaced)
+			reg |= DC_WR_CH_CONF_FIELD_MODE;
+	} else if ((dc_chan == 8) || (dc_chan == 9)) {
+		/* async channels */
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+		reg = 0x3;
+		reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	}
+	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+	ipu_dc_write(ipu, 0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	ipu_dc_write(ipu, 0x00000084, DC_GEN);
+}
+
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan)
+{
+	if ((dc_chan == 1) || (dc_chan == 5)) {
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 0, 0);
+	} else if ((dc_chan == 8) || (dc_chan == 9)) {
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
+	}
+}
+
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	if (channel == MEM_DC_SYNC)
+		return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_1) &
+			  DC_WR_CH_CONF_FIELD_MODE);
+	else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
+		return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_5) &
+			  DC_WR_CH_CONF_FIELD_MODE);
+	return 0;
+}
+
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	int di;
+	uint32_t reg;
+	uint32_t dc_chan;
+	int irq = 0;
+
+	if (channel == MEM_FG_SYNC)
+		irq = IPU_IRQ_DP_SF_END;
+	else if (channel == MEM_DC_SYNC)
+		dc_chan = 1;
+	else if (channel == MEM_BG_SYNC)
+		dc_chan = 5;
+	else
+		return;
+
+	if (channel == MEM_FG_SYNC) {
+		/* Enable FG channel */
+		reg = ipu_dp_read(ipu, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+		return;
+	} else if (channel == MEM_BG_SYNC) {
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+
+	di = ipu->dc_di_assignment[dc_chan];
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = ipu_dc_read(ipu, DC_WR_CH_CONF(6 - dc_chan));
+	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+	}
+
+	reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+	clk_prepare_enable(ipu->pixel_clk[di]);
+	ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]] = true;
+}
+
+static irqreturn_t dc_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_soc *ipu = dev_id;
+	struct completion *comp = &ipu->dc_comp;
+	uint32_t reg;
+	uint32_t dc_chan;
+
+	if (irq == IPU_IRQ_DC_FC_1)
+		dc_chan = 1;
+	else
+		dc_chan = 5;
+
+	if (!ipu->dc_swap) {
+		reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+		reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+		if (ipu->dc_di_assignment[dc_chan])
+			reg &= ~DI1_COUNTER_RELEASE;
+		else
+			reg &= ~DI0_COUNTER_RELEASE;
+		ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+	}
+
+	complete(comp);
+	return IRQ_HANDLED;
+}
+
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap)
+{
+	int ret;
+	uint32_t reg;
+	uint32_t csc;
+	uint32_t dc_chan;
+	int irq = 0;
+	int timeout = 50;
+
+	ipu->dc_swap = swap;
+
+	if (channel == MEM_DC_SYNC) {
+		dc_chan = 1;
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (channel == MEM_BG_SYNC) {
+		dc_chan = 5;
+		irq = IPU_IRQ_DP_SF_END;
+	} else if (channel == MEM_FG_SYNC) {
+		/* Disable FG channel */
+		dc_chan = 5;
+
+		reg = ipu_dp_read(ipu, DP_COM_CONF(DP_SYNC));
+		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_FG_EN;
+		ipu_dp_write(ipu, reg, DP_COM_CONF(DP_SYNC));
+
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+		if (ipu_is_channel_busy(ipu, MEM_BG_SYNC)) {
+			ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END),
+				IPUIRQ_2_STATREG(ipu->devtype,
+							IPU_IRQ_DP_SF_END));
+			while ((ipu_cm_read(ipu,
+				IPUIRQ_2_STATREG(ipu->devtype,
+							IPU_IRQ_DP_SF_END)) &
+				IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END)) == 0) {
+				msleep(2);
+				timeout -= 2;
+				if (timeout <= 0)
+					break;
+			}
+		}
+		return;
+	} else {
+		return;
+	}
+
+	init_completion(&ipu->dc_comp);
+	ret = ipu_request_irq(ipu, irq, dc_irq_handler, 0, NULL, ipu);
+	if (ret < 0) {
+		dev_err(ipu->dev, "DC irq %d in use\n", irq);
+		return;
+	}
+	ret = wait_for_completion_timeout(&ipu->dc_comp, msecs_to_jiffies(50));
+	ipu_free_irq(ipu, irq, ipu);
+	dev_dbg(ipu->dev, "DC stop timeout - %d * 10ms\n", 5 - ret);
+
+	if (ipu->dc_swap) {
+		/* Swap DC channel 1 and 5 settings, and disable old dc chan */
+		reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+		reg ^= DC_WR_CH_CONF_PROG_DI_ID;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+	}
+}
+
+void _ipu_init_dc_mappings(struct ipu_soc *ipu)
+{
+	/* IPU_PIX_FMT_RGB24 */
+	_ipu_dc_map_clear(ipu, 0);
+	_ipu_dc_map_config(ipu, 0, 0, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 0, 1, 15, 0xFF);
+	_ipu_dc_map_config(ipu, 0, 2, 23, 0xFF);
+
+	/* IPU_PIX_FMT_RGB666 */
+	_ipu_dc_map_clear(ipu, 1);
+	_ipu_dc_map_config(ipu, 1, 0, 5, 0xFC);
+	_ipu_dc_map_config(ipu, 1, 1, 11, 0xFC);
+	_ipu_dc_map_config(ipu, 1, 2, 17, 0xFC);
+
+	/* IPU_PIX_FMT_YUV444 */
+	_ipu_dc_map_clear(ipu, 2);
+	_ipu_dc_map_config(ipu, 2, 0, 15, 0xFF);
+	_ipu_dc_map_config(ipu, 2, 1, 23, 0xFF);
+	_ipu_dc_map_config(ipu, 2, 2, 7, 0xFF);
+
+	/* IPU_PIX_FMT_RGB565 */
+	_ipu_dc_map_clear(ipu, 3);
+	_ipu_dc_map_config(ipu, 3, 0, 4, 0xF8);
+	_ipu_dc_map_config(ipu, 3, 1, 10, 0xFC);
+	_ipu_dc_map_config(ipu, 3, 2, 15, 0xF8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	_ipu_dc_map_clear(ipu, 4);
+	_ipu_dc_map_config(ipu, 4, 0, 5, 0xFC);
+	_ipu_dc_map_config(ipu, 4, 1, 13, 0xFC);
+	_ipu_dc_map_config(ipu, 4, 2, 21, 0xFC);
+
+	/* IPU_PIX_FMT_VYUY 16bit width */
+	_ipu_dc_map_clear(ipu, 5);
+	_ipu_dc_map_config(ipu, 5, 0, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 5, 1, 0, 0x0);
+	_ipu_dc_map_config(ipu, 5, 2, 15, 0xFF);
+	_ipu_dc_map_clear(ipu, 6);
+	_ipu_dc_map_config(ipu, 6, 0, 0, 0x0);
+	_ipu_dc_map_config(ipu, 6, 1, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 6, 2, 15, 0xFF);
+
+	/* IPU_PIX_FMT_UYUV 16bit width */
+	_ipu_dc_map_clear(ipu, 7);
+	_ipu_dc_map_link(ipu, 7, 6, 0, 6, 1, 6, 2);
+	_ipu_dc_map_clear(ipu, 8);
+	_ipu_dc_map_link(ipu, 8, 5, 0, 5, 1, 5, 2);
+
+	/* IPU_PIX_FMT_YUYV 16bit width */
+	_ipu_dc_map_clear(ipu, 9);
+	_ipu_dc_map_link(ipu, 9, 5, 2, 5, 1, 5, 0);
+	_ipu_dc_map_clear(ipu, 10);
+	_ipu_dc_map_link(ipu, 10, 5, 1, 5, 2, 5, 0);
+
+	/* IPU_PIX_FMT_YVYU 16bit width */
+	_ipu_dc_map_clear(ipu, 11);
+	_ipu_dc_map_link(ipu, 11, 5, 1, 5, 2, 5, 0);
+	_ipu_dc_map_clear(ipu, 12);
+	_ipu_dc_map_link(ipu, 12, 5, 2, 5, 1, 5, 0);
+
+	/* IPU_PIX_FMT_GBR24 */
+	/* IPU_PIX_FMT_VYU444 */
+	_ipu_dc_map_clear(ipu, 13);
+	_ipu_dc_map_link(ipu, 13, 0, 2, 0, 0, 0, 1);
+
+	/* IPU_PIX_FMT_BGR24 */
+	_ipu_dc_map_clear(ipu, 14);
+	_ipu_dc_map_link(ipu, 14, 0, 2, 0, 1, 0, 0);
+}
+
+int _ipu_pixfmt_to_map(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_RGB24:
+		return 0;
+	case IPU_PIX_FMT_RGB666:
+		return 1;
+	case IPU_PIX_FMT_YUV444:
+		return 2;
+	case IPU_PIX_FMT_RGB565:
+		return 3;
+	case IPU_PIX_FMT_LVDS666:
+		return 4;
+	case IPU_PIX_FMT_VYUY:
+		return 6;
+	case IPU_PIX_FMT_UYVY:
+		return 8;
+	case IPU_PIX_FMT_YUYV:
+		return 10;
+	case IPU_PIX_FMT_YVYU:
+		return 12;
+	case IPU_PIX_FMT_GBR24:
+	case IPU_PIX_FMT_VYU444:
+		return 13;
+	case IPU_PIX_FMT_BGR24:
+		return 14;
+	}
+
+	return -1;
+}
+
+/*!
+ * This function sets the colorspace for of dp.
+ * modes.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       param         	If it's not NULL, update the csc table
+ *                              with this parameter.
+ *
+ * @return      N/A
+ */
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+	int dp;
+	struct dp_csc_param_t dp_csc_param;
+
+	if (channel == MEM_FG_SYNC)
+		dp = DP_SYNC;
+	else if (channel == MEM_BG_SYNC)
+		dp = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0)
+		dp = DP_ASYNC0;
+	else
+		return;
+
+	dp_csc_param.mode = -1;
+	dp_csc_param.coeff = param;
+	__ipu_dp_csc_setup(ipu, dp, dp_csc_param, true);
+}
+
+void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+	_ipu_dp_set_csc_coefficients(ipu, channel, param);
+}
+EXPORT_SYMBOL(ipu_set_csc_coefficients);
+
+/*!
+ * This function is called to adapt synchronous LCD panel to IPU restriction.
+ *
+ */
+void adapt_panel_to_ipu_restricitions(struct ipu_soc *ipu, uint16_t *v_start_width,
+					uint16_t *v_sync_width,
+					uint16_t *v_end_width)
+{
+	if (*v_end_width < 2) {
+		uint16_t diff = 2 - *v_end_width;
+		if (*v_start_width >= diff) {
+			*v_end_width = 2;
+			*v_start_width = *v_start_width - diff;
+		} else if (*v_sync_width > diff) {
+			*v_end_width = 2;
+			*v_sync_width = *v_sync_width - diff;
+		} else
+			dev_err(ipu->dev, "WARNING: try to adapt timming, but failed\n");
+		dev_err(ipu->dev, "WARNING: adapt panel end blank lines\n");
+	}
+}
+
+/*!
+ * This function is called to initialize a synchronous LCD panel.
+ *
+ * @param	ipu		ipu handler
+ * @param       disp            The DI the panel is attached to.
+ *
+ * @param       pixel_clk       Desired pixel clock frequency in Hz.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           The width of panel in pixels.
+ *
+ * @param       height          The height of panel in pixels.
+ *
+ * @param       hStartWidth     The number of pixel clocks between the HSYNC
+ *                              signal pulse and the start of valid data.
+ *
+ * @param       hSyncWidth      The width of the HSYNC signal in units of pixel
+ *                              clocks.
+ *
+ * @param       hEndWidth       The number of pixel clocks between the end of
+ *                              valid data and the HSYNC signal for next line.
+ *
+ * @param       vStartWidth     The number of lines between the VSYNC
+ *                              signal pulse and the start of valid data.
+ *
+ * @param       vSyncWidth      The width of the VSYNC signal in units of lines
+ *
+ * @param       vEndWidth       The number of lines between the end of valid
+ *                              data and the VSYNC signal for next frame.
+ *
+ * @param       sig             Bitfield of signal polarities for LCD interface.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
+			    uint16_t width, uint16_t height,
+			    uint32_t pixel_fmt,
+			    uint16_t h_start_width, uint16_t h_sync_width,
+			    uint16_t h_end_width, uint16_t v_start_width,
+			    uint16_t v_sync_width, uint16_t v_end_width,
+			    uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
+{
+	uint32_t field0_offset = 0;
+	uint32_t field1_offset;
+	uint32_t reg;
+	uint32_t di_gen, vsync_cnt;
+	uint32_t div, rounded_pixel_clk;
+	uint32_t h_total, v_total;
+	int map;
+	int ret;
+	struct clk *ldb_di0_clk, *ldb_di1_clk;
+	struct clk *di_parent;
+
+	dev_dbg(ipu->dev, "panel size = %d x %d\n", width, height);
+
+	if ((v_sync_width == 0) || (h_sync_width == 0))
+		return -EINVAL;
+
+	adapt_panel_to_ipu_restricitions(ipu, &v_start_width, &v_sync_width, &v_end_width);
+	h_total = width + h_sync_width + h_start_width + h_end_width;
+	v_total = height + v_sync_width + v_start_width + v_end_width;
+
+	/* Init clocking */
+	dev_dbg(ipu->dev, "pixel clk = %d\n", pixel_clk);
+
+	di_parent = clk_get_parent(ipu->di_clk_sel[disp]);
+	if (!di_parent) {
+		dev_err(ipu->dev, "get di clk parent fail\n");
+		return -EINVAL;
+	}
+	ldb_di0_clk = clk_get(ipu->dev, "ldb_di0");
+	if (IS_ERR(ldb_di0_clk)) {
+		dev_err(ipu->dev, "clk_get di0 failed");
+		return PTR_ERR(ldb_di0_clk);
+	}
+	ldb_di1_clk = clk_get(ipu->dev, "ldb_di1");
+	if (IS_ERR(ldb_di1_clk)) {
+		dev_err(ipu->dev, "clk_get di1 failed");
+		return PTR_ERR(ldb_di1_clk);
+	}
+	if (!strcmp(__clk_get_name(di_parent), __clk_get_name(ldb_di0_clk)) ||
+		!strcmp(__clk_get_name(di_parent), __clk_get_name(ldb_di1_clk))) {
+		/* if di clk parent is tve/ldb, then keep it;*/
+		dev_dbg(ipu->dev, "use special clk parent\n");
+		ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->di_clk[disp]);
+		if (ret) {
+			dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+			return ret;
+		}
+		clk_put(ldb_di0_clk);
+		clk_put(ldb_di1_clk);
+	} else {
+		/* try ipu clk first*/
+		dev_dbg(ipu->dev, "try ipu internal clk\n");
+		ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->ipu_clk);
+		if (ret) {
+			dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+			return ret;
+		}
+		rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+		dev_dbg(ipu->dev, "rounded pix clk:%d\n", rounded_pixel_clk);
+		/*
+		 * we will only use 1/2 fraction for ipu clk,
+		 * so if the clk rate is not fit, try ext clk.
+		 */
+		if (!sig.int_clk &&
+			((rounded_pixel_clk >= pixel_clk + pixel_clk/200) ||
+			(rounded_pixel_clk <= pixel_clk - pixel_clk/200))) {
+			dev_dbg(ipu->dev, "try ipu ext di clk\n");
+
+			rounded_pixel_clk =
+				clk_round_rate(ipu->di_clk[disp], pixel_clk);
+			ret = clk_set_rate(ipu->di_clk[disp],
+						rounded_pixel_clk);
+			if (ret) {
+				dev_err(ipu->dev,
+					"set di clk rate error:%d\n", ret);
+				return ret;
+			}
+			dev_dbg(ipu->dev, "di clk:%d\n", rounded_pixel_clk);
+			ret = clk_set_parent(ipu->pixel_clk_sel[disp],
+						ipu->di_clk[disp]);
+			if (ret) {
+				dev_err(ipu->dev,
+					"set pixel clk parent error:%d\n", ret);
+				return ret;
+			}
+		}
+	}
+	rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+	if (rounded_pixel_clk == 0) {
+		dev_err(ipu->dev, "rounded pixel clock should not be zero\n");
+		return -EINVAL;
+	}
+	dev_dbg(ipu->dev, "round pixel clk:%d\n", rounded_pixel_clk);
+	ret = clk_set_rate(ipu->pixel_clk[disp], rounded_pixel_clk);
+	if (ret) {
+		dev_err(ipu->dev, "set pixel clk rate error:%d\n", ret);
+		return ret;
+	}
+	msleep(5);
+	/* Get integer portion of divider */
+	div = clk_get_rate(clk_get_parent(ipu->pixel_clk_sel[disp])) / rounded_pixel_clk;
+	dev_dbg(ipu->dev, "div:%d\n", div);
+	if (!div) {
+		dev_err(ipu->dev, "invalid pixel clk div = 0\n");
+		return -EINVAL;
+	}
+
+
+	mutex_lock(&ipu->mutex_lock);
+
+	_ipu_di_data_wave_config(ipu, disp, SYNC_WAVE, div - 1, div - 1);
+	_ipu_di_data_pin_config(ipu, disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+	map = _ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu->dev, "IPU_DISP: No MAP\n");
+		mutex_unlock(&ipu->mutex_lock);
+		return -EINVAL;
+	}
+
+	/*clear DI*/
+	di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+	di_gen &= (0x3 << 20);
+	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+	if (sig.interlaced) {
+		if (ipu->devtype >= IPUv3EX) {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					1, 		/* counter */
+					h_total/2 - 1, 	/* run count */
+					DI_SYNC_CLK,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					2, 		/* counter */
+					h_total - 1, 	/* run count */
+					DI_SYNC_CLK,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					3, 		/* counter */
+					v_total*2 - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					1, 			/* offset */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					4, 		/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					v_start_width, 	/*  offset */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 		/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Active Line */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					5, 		/* counter */
+					0, 		/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 		/*  offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					height/2, 	/* repeat count */
+					4, 		/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					6, 		/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL  */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					7, 		/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution  */
+					9, 		/* offset  */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 		/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					8, 		/* counter */
+					0, 		/* run count  */
+					DI_SYNC_CLK,	/* run_resolution */
+					h_start_width, 	/* offset  */
+					DI_SYNC_CLK, 	/* offset resolution */
+					width, 		/* repeat count  */
+					5, 		/* CNT_CLR_SEL  */
+					0, 		/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL  */
+					0, 		/* COUNT UP  */
+					0		/* COUNT DOWN */
+					);
+
+			/* Second VSYNC */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					9, 		/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					v_total/2, 		/* offset  */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution  */
+					0, 		/* repeat count */
+					DI_SYNC_HSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* set gentime select and tag sel */
+			reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+			reg &= 0x1FFFFFFF;
+			reg |= (3-1)<<29 | 0x00008000;
+			ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+			ipu_di_write(ipu, disp, v_total / 2 - 1, DI_SCR_CONF);
+
+			/* set y_sel = 1 */
+			di_gen |= 0x10000000;
+			di_gen |= DI_GEN_POLARITY_5;
+			di_gen |= DI_GEN_POLARITY_8;
+		} else {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			field1_offset = v_sync_width + v_start_width + height / 2 +
+				v_end_width;
+			if (sig.odd_field_first) {
+				field0_offset = field1_offset - 1;
+				field1_offset = 0;
+			}
+			v_total += v_start_width + v_end_width;
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 2, v_total - 1, 1,
+					field0_offset,
+					field0_offset ? 1 : DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 3, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(ipu, disp, 4,
+					field0_offset ?
+					field0_offset : field1_offset - 2,
+					1, v_start_width + v_sync_width, 1, 2, 2,
+					0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* Active Line */
+			_ipu_di_sync_config(ipu, disp, 5, 0, 1,
+					0, DI_SYNC_NONE,
+					height / 2, 4, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 6, v_total - 1, 1,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(ipu, disp, 7, 0, 1,
+					field1_offset,
+					field1_offset ? 1 : DI_SYNC_NONE,
+					1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(ipu, disp, 8, 0, DI_SYNC_CLK,
+					h_sync_width + h_start_width, DI_SYNC_CLK,
+					width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
+					0, 0);
+
+			/* ??? */
+			_ipu_di_sync_config(ipu, disp, 9, v_total - 1, 2,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+			reg |= 0x8000;
+			ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+			ipu_di_write(ipu, disp, v_sync_width + v_start_width +
+					v_end_width + height / 2 - 1, DI_SCR_CONF);
+		}
+
+		/* Init template microcode */
+		_ipu_dc_write_tmpl(ipu, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
+
+		if (sig.Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig.Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		/* Setup internal HSYNC waveform */
+		_ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+		/* Setup external (delayed) HSYNC waveform */
+		_ipu_di_sync_config(ipu, disp, DI_SYNC_HSYNC, h_total - 1,
+				    DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
+				    0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
+				    DI_SYNC_CLK, 0, h_sync_width * 2);
+		/* Setup VSYNC waveform */
+		vsync_cnt = DI_SYNC_VSYNC;
+		_ipu_di_sync_config(ipu, disp, DI_SYNC_VSYNC, v_total - 1,
+				    DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
+				    DI_SYNC_NONE, 1, DI_SYNC_NONE,
+				    DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
+		ipu_di_write(ipu, disp, v_total - 1, DI_SCR_CONF);
+
+		/* Setup active data waveform to sync with DC */
+		_ipu_di_sync_config(ipu, disp, 4, 0, DI_SYNC_HSYNC,
+				    v_sync_width + v_start_width, DI_SYNC_HSYNC, height,
+				    DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
+				    DI_SYNC_NONE, 0, 0);
+		_ipu_di_sync_config(ipu, disp, 5, 0, DI_SYNC_CLK,
+				    h_sync_width + h_start_width, DI_SYNC_CLK,
+				    width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
+				    0);
+
+		/* set VGA delayed hsync/vsync no matter VGA enabled */
+		if (disp) {
+			/* couter 7 for VGA delay HSYNC */
+			_ipu_di_sync_config(ipu, disp, 7,
+					h_total - 1, DI_SYNC_CLK,
+					18, DI_SYNC_CLK,
+					0, DI_SYNC_NONE,
+					1, DI_SYNC_NONE, DI_SYNC_CLK,
+					0, h_sync_width * 2);
+
+			/* couter 8 for VGA delay VSYNC */
+			_ipu_di_sync_config(ipu, disp, 8,
+					v_total - 1, DI_SYNC_INT_HSYNC,
+					1, DI_SYNC_INT_HSYNC,
+					0, DI_SYNC_NONE,
+					1, DI_SYNC_NONE, DI_SYNC_INT_HSYNC,
+					0, v_sync_width * 2);
+		}
+
+		/* reset all unused counters */
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN0(6));
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN1(6));
+		if (!disp) {
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN0(7));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN1(7));
+			ipu_di_write(ipu, disp, 0, DI_STP_REP(7));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN0(8));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN1(8));
+			ipu_di_write(ipu, disp, 0, DI_STP_REP(8));
+		}
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN0(9));
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN1(9));
+		ipu_di_write(ipu, disp, 0, DI_STP_REP(9));
+
+		reg = ipu_di_read(ipu, disp, DI_STP_REP(6));
+		reg &= 0x0000FFFF;
+		ipu_di_write(ipu, disp, reg, DI_STP_REP(6));
+
+		/* Init template microcode */
+		if (disp) {
+			if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+				_ipu_dc_write_tmpl(ipu, 8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+				_ipu_dc_write_tmpl(ipu, 9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+				/* configure user events according to DISP NUM */
+				ipu_dc_write(ipu, (width - 1), DC_UGDE_3(disp));
+			}
+			_ipu_dc_write_tmpl(ipu, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+			_ipu_dc_write_tmpl(ipu, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+			_ipu_dc_write_tmpl(ipu, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+			_ipu_dc_write_tmpl(ipu, 1, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+
+		} else {
+			if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+				_ipu_dc_write_tmpl(ipu, 10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+				_ipu_dc_write_tmpl(ipu, 11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+				/* configure user events according to DISP NUM */
+				ipu_dc_write(ipu, width - 1, DC_UGDE_3(disp));
+			}
+		   _ipu_dc_write_tmpl(ipu, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+		   _ipu_dc_write_tmpl(ipu, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+		   _ipu_dc_write_tmpl(ipu, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+		   _ipu_dc_write_tmpl(ipu, 12, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+		}
+
+		if (sig.Hsync_pol) {
+			di_gen |= DI_GEN_POLARITY_2;
+			if (disp)
+				di_gen |= DI_GEN_POLARITY_7;
+		}
+		if (sig.Vsync_pol) {
+			di_gen |= DI_GEN_POLARITY_3;
+			if (disp)
+				di_gen |= DI_GEN_POLARITY_8;
+		}
+	}
+	/* changinc DISP_CLK polarity: it can be wrong for some applications */
+	if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+		(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+		(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+		(pixel_fmt == IPU_PIX_FMT_VYUY))
+			di_gen |= 0x00020000;
+
+	if (!sig.clk_pol)
+		di_gen |= DI_GEN_POLARITY_DISP_CLK;
+	else
+		di_gen &= ~DI_GEN_POLARITY_DISP_CLK;
+
+	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+	ipu_di_write(ipu, disp, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
+			0x00000002, DI_SYNC_AS_GEN);
+	reg = ipu_di_read(ipu, disp, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+	if (sig.enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig.data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+	ipu_di_write(ipu, disp, reg, DI_POL);
+
+	ipu_dc_write(ipu, width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_sync_panel);
+
+void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp)
+{
+	uint32_t reg;
+	uint32_t di_gen;
+
+	if (disp != 0 && disp != 1)
+		return;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+	di_gen |= 0x3ff | DI_GEN_POLARITY_DISP_CLK;
+	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+	reg = ipu_di_read(ipu, disp, DI_POL);
+	reg |= 0x3ffffff;
+	ipu_di_write(ipu, disp, reg, DI_POL);
+
+	mutex_unlock(&ipu->mutex_lock);
+}
+EXPORT_SYMBOL(ipu_uninit_sync_panel);
+
+int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
+			 uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig)
+{
+	int map;
+	u32 ser_conf = 0;
+	u32 div;
+	u32 di_clk = clk_get_rate(ipu->ipu_clk);
+
+	if (di_clk == 0) {
+		dev_err(ipu->dev, "di clock rate should not be zero\n");
+		return -EINVAL;
+	}
+
+	/* round up cycle_time, then calcalate the divider using scaled math */
+	cycle_time += (1000000000UL / di_clk) - 1;
+	div = (cycle_time * (di_clk / 256UL)) / (1000000000UL / 256UL);
+
+	map = _ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0)
+		return -EINVAL;
+
+	mutex_lock(&ipu->mutex_lock);
+
+	if (type == IPU_PANEL_SERIAL) {
+		ipu_di_write(ipu, disp, (div << 24) | ((sig.ifc_width - 1) << 4),
+			     DI_DW_GEN(ASYNC_SER_WAVE));
+
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_CS,
+					0, 0, (div * 2) + 1);
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_CLK,
+					1, div, div * 2);
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_RS,
+					2, 0, 0);
+
+		_ipu_dc_write_tmpl(ipu, 0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1);
+
+		/* Configure DC for serial panel */
+		ipu_dc_write(ipu, 0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL));
+
+		if (sig.clk_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_CLK_POL;
+		if (sig.data_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_DATA_POL;
+		if (sig.rs_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_RS_POL;
+		if (sig.cs_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_CS_POL;
+		ipu_di_write(ipu, disp, ser_conf, DI_SER_CONF);
+	}
+
+	mutex_unlock(&ipu->mutex_lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_async_panel);
+
+/*!
+ * This function sets the foreground and background plane global alpha blending
+ * modes. This function also sets the DP graphic plane according to the
+ * parameter of IPUv3 DP channel.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IPUv3 DP channel
+ *
+ * @param       enable          Boolean to enable or disable global alpha
+ *                              blending. If disabled, local blending is used.
+ *
+ * @param       alpha           Global alpha value.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel,
+				bool enable, uint8_t alpha)
+{
+	uint32_t reg;
+	uint32_t flow;
+	bool bg_chan;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
+	    channel == MEM_BG_ASYNC1)
+		bg_chan = true;
+	else
+		bg_chan = false;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	if (bg_chan) {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL;
+		ipu_dp_write(ipu, reg | ((uint32_t) alpha << 24),
+			     DP_GRAPH_WIND_CTRL(flow));
+
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_global_alpha);
+
+/*!
+ * This function sets the transparent color key for SDC graphic plane.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       enable          Boolean to enable or disable color key
+ *
+ * @param       colorKey        24-bit RGB color for transparent color key.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel,
+				bool enable, uint32_t color_key)
+{
+	uint32_t reg, flow;
+	int y, u, v;
+	int red, green, blue;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	ipu->color_key_4rgb = true;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+			((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			((ipu->fg_csc_type == YUV2RGB) && (ipu->bg_csc_type == YUV2RGB))) {
+
+		dev_dbg(ipu->dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		ipu->color_key_4rgb = false;
+
+		dev_dbg(ipu->dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0xFF000000L;
+		ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(flow));
+
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_color_key);
+
+/*!
+ * This function sets the gamma correction for DP output.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       enable          Boolean to enable or disable gamma correction.
+ *
+ * @param       constk        	Gamma piecewise linear approximation constk coeff.
+ *
+ * @param       slopek        	Gamma piecewise linear approximation slopek coeff.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable, int constk[], int slopek[])
+{
+	uint32_t reg, flow, i;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	_ipu_get(ipu);
+
+	mutex_lock(&ipu->mutex_lock);
+
+	for (i = 0; i < 8; i++)
+		ipu_dp_write(ipu, (constk[2*i] & 0x1ff) | ((constk[2*i+1] & 0x1ff) << 16), DP_GAMMA_C(flow, i));
+	for (i = 0; i < 4; i++)
+		ipu_dp_write(ipu, (slopek[4*i] & 0xff) | ((slopek[4*i+1] & 0xff) << 8) |
+			((slopek[4*i+2] & 0xff) << 16) | ((slopek[4*i+3] & 0xff) << 24), DP_GAMMA_S(flow, i));
+
+	reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+	if (enable) {
+		if ((ipu->bg_csc_type == RGB2YUV) || (ipu->bg_csc_type == YUV2YUV))
+			reg |= DP_COM_CONF_GAMMA_YUV_EN;
+		else
+			reg &= ~DP_COM_CONF_GAMMA_YUV_EN;
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+	} else
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&ipu->mutex_lock);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_gamma_correction);
+
+/*!
+ * This function sets the window position of the foreground or background plane.
+ * modes.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       x_pos           The X coordinate position to place window at.
+ *                              The position is relative to the top left corner.
+ *
+ * @param       y_pos           The Y coordinate position to place window at.
+ *                              The position is relative to the top left corner.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t x_pos, int16_t y_pos)
+{
+	u32 reg;
+	uint32_t flow = 0;
+	uint32_t dp_srm_shift;
+
+	if ((channel == MEM_FG_SYNC) || (channel == MEM_BG_SYNC)) {
+		flow = DP_SYNC;
+		dp_srm_shift = 3;
+	} else if (channel == MEM_FG_ASYNC0) {
+		flow = DP_ASYNC0;
+		dp_srm_shift = 5;
+	} else if (channel == MEM_FG_ASYNC1) {
+		flow = DP_ASYNC1;
+		dp_srm_shift = 7;
+	} else
+		return -EINVAL;
+
+	ipu_dp_write(ipu, (x_pos << 16) | y_pos, DP_FG_POS(flow));
+
+	if (ipu_is_channel_busy(ipu, channel)) {
+		/* controled by FSU if channel enabled */
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+		reg |= (0x1 << dp_srm_shift);
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	} else {
+		/* disable auto swap, controled by MCU if channel disabled */
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+
+	return 0;
+}
+
+int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t x_pos, int16_t y_pos)
+{
+	int ret;
+
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	ret = _ipu_disp_set_window_pos(ipu, channel, x_pos, y_pos);
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_disp_set_window_pos);
+
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t *x_pos, int16_t *y_pos)
+{
+	u32 reg;
+	uint32_t flow = 0;
+
+	if (channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	reg = ipu_dp_read(ipu, DP_FG_POS(flow));
+
+	*x_pos = (reg >> 16) & 0x7FF;
+	*y_pos = reg & 0x7FF;
+
+	return 0;
+}
+int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t *x_pos, int16_t *y_pos)
+{
+	int ret;
+
+	_ipu_get(ipu);
+	mutex_lock(&ipu->mutex_lock);
+	ret = _ipu_disp_get_window_pos(ipu, channel, x_pos, y_pos);
+	mutex_unlock(&ipu->mutex_lock);
+	_ipu_put(ipu);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_disp_get_window_pos);
+
+void ipu_reset_disp_panel(struct ipu_soc *ipu)
+{
+	uint32_t tmp;
+
+	tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+	ipu_di_write(ipu, 1, tmp | 0x08, DI_GENERAL);
+	msleep(10); /* tRES >= 100us */
+	tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+	ipu_di_write(ipu, 1, tmp & ~0x08, DI_GENERAL);
+	msleep(60);
+
+	return;
+}
+EXPORT_SYMBOL(ipu_reset_disp_panel);
+
+void ipu_disp_init(struct ipu_soc *ipu)
+{
+	ipu->fg_csc_type = ipu->bg_csc_type = CSC_NONE;
+	ipu->color_key_4rgb = true;
+	_ipu_init_dc_mappings(ipu);
+	_ipu_dmfc_init(ipu, DMFC_NORMAL, 1);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_ic.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_ic.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_ic.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+enum {
+	IC_TASK_VIEWFINDER,
+	IC_TASK_ENCODER,
+	IC_TASK_POST_PROCESSOR
+};
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+		      ipu_color_space_t out_format, int csc_index);
+
+static int _calc_resize_coeffs(struct ipu_soc *ipu,
+				uint32_t inSize, uint32_t outSize,
+				uint32_t *resizeCoeff,
+				uint32_t *downsizeCoeff);
+
+void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
+{
+	uint32_t reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	if (top_field_0)
+		reg &= ~VDI_C_TOP_FIELD_MAN_1;
+	else
+		reg |= VDI_C_TOP_FIELD_MAN_1;
+	ipu_vdi_write(ipu, reg, VDI_C);
+}
+
+void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
+{
+	uint32_t reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
+	if (motion_sel == HIGH_MOTION)
+		reg |= VDI_C_MOT_SEL_FULL;
+	else if (motion_sel == MED_MOTION)
+		reg |= VDI_C_MOT_SEL_MED;
+	else
+		reg |= VDI_C_MOT_SEL_LOW;
+
+	ipu_vdi_write(ipu, reg, VDI_C);
+	dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
+}
+
+void ic_dump_register(struct ipu_soc *ipu)
+{
+	printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
+	printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
+	       ipu_ic_read(ipu, IC_PRP_ENC_RSC));
+	printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
+	       ipu_ic_read(ipu, IC_PRP_VF_RSC));
+	printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
+	printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
+	printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
+	printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
+}
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t ic_conf;
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+	switch (channel) {
+	case CSI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
+		break;
+	case MEM_ROT_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_ROT_EN;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case MEM_PRP_ENC_MEM:
+		ic_conf |= IC_CONF_PRPENC_EN;
+		break;
+	case MEM_ROT_ENC_MEM:
+		ic_conf |= IC_CONF_PRPENC_ROT_EN;
+		break;
+	case MEM_PP_MEM:
+		ic_conf |= IC_CONF_PP_EN;
+		break;
+	case MEM_ROT_PP_MEM:
+		ic_conf |= IC_CONF_PP_ROT_EN;
+		break;
+	default:
+		break;
+	}
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t ic_conf;
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+	switch (channel) {
+	case CSI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_MEM:
+		ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
+		break;
+	case MEM_ROT_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case MEM_PRP_ENC_MEM:
+		ic_conf &= ~IC_CONF_PRPENC_EN;
+		break;
+	case MEM_ROT_ENC_MEM:
+		ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
+		break;
+	case MEM_PP_MEM:
+		ic_conf &= ~IC_CONF_PP_EN;
+		break;
+	case MEM_ROT_PP_MEM:
+		ic_conf &= ~IC_CONF_PP_ROT_EN;
+		break;
+	default:
+		break;
+	}
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+	uint32_t reg;
+	uint32_t pixel_fmt;
+	uint32_t pix_per_burst;
+
+	reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
+	  (params->mem_prp_vf_mem.in_width-1);
+	ipu_vdi_write(ipu, reg, VDI_FSIZE);
+
+	/* Full motion, only vertical filter is used
+	   Burst size is 4 accesses */
+	if (params->mem_prp_vf_mem.in_pixel_fmt ==
+	     IPU_PIX_FMT_UYVY ||
+	     params->mem_prp_vf_mem.in_pixel_fmt ==
+	     IPU_PIX_FMT_YUYV) {
+		pixel_fmt = VDI_C_CH_422;
+		pix_per_burst = 32;
+	 } else {
+		pixel_fmt = VDI_C_CH_420;
+		pix_per_burst = 64;
+	}
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	reg |= pixel_fmt;
+	switch (channel) {
+	case MEM_VDI_PRP_VF_MEM:
+		reg |= VDI_C_BURST_SIZE2_4;
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+		reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
+		break;
+	case MEM_VDI_PRP_VF_MEM_N:
+		reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
+		break;
+
+	case MEM_VDI_MEM:
+		reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+				<< VDI_C_BURST_SIZE2_OFFSET;
+		break;
+	case MEM_VDI_MEM_P:
+		reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+				<< VDI_C_BURST_SIZE1_OFFSET;
+		reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
+		break;
+	case MEM_VDI_MEM_N:
+		reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+				<< VDI_C_BURST_SIZE3_OFFSET;
+		reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
+		break;
+	default:
+		break;
+	}
+	ipu_vdi_write(ipu, reg, VDI_C);
+
+	if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
+		_ipu_vdi_set_top_field_man(ipu, true);
+	else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
+		_ipu_vdi_set_top_field_man(ipu, false);
+
+	_ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_RWS_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_vdi_uninit(struct ipu_soc *ipu)
+{
+	ipu_vdi_write(ipu, 0, VDI_FSIZE);
+	ipu_vdi_write(ipu, 0, VDI_C);
+}
+
+int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
+		       bool src_is_csi)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+	int ret = 0;
+
+	/* Setup vertical resizing */
+	if (!params->mem_prp_vf_mem.outv_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
+					params->mem_prp_vf_mem.out_height,
+					&resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate prpvf height "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else
+		reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
+
+	/* Setup horizontal resizing */
+	if (!params->mem_prp_vf_mem.outh_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
+					params->mem_prp_vf_mem.out_width,
+					&resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate prpvf width "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else
+		reg |= params->mem_prp_vf_mem.outh_resize_ratio;
+
+	ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (params->mem_prp_vf_mem.graphics_combine_en) {
+		ic_conf |= IC_CONF_PRPVF_CMB;
+
+		if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
+			/* need transparent CSC1 conversion */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;  /* Enable RGB->RGB CSC */
+		}
+		in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
+		out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+		if (in_fmt == RGB) {
+			if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+				/* Enable RGB->YCBCR CSC2 */
+				_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
+				ic_conf |= IC_CONF_PRPVF_CSC2;
+			}
+		}
+		if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+			if (out_fmt == RGB) {
+				/* Enable YCBCR->RGB CSC2 */
+				_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
+				ic_conf |= IC_CONF_PRPVF_CSC2;
+			} else {
+				/* TODO: Support YUV<->YCbCr conversion? */
+			}
+		}
+
+		if (params->mem_prp_vf_mem.global_alpha_en) {
+			ic_conf |= IC_CONF_IC_GLB_LOC_A;
+			reg = ipu_ic_read(ipu, IC_CMBP_1);
+			reg &= ~(0xff);
+			reg |= params->mem_prp_vf_mem.alpha;
+			ipu_ic_write(ipu, reg, IC_CMBP_1);
+		} else
+			ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+		if (params->mem_prp_vf_mem.key_color_en) {
+			ic_conf |= IC_CONF_KEY_COLOR_EN;
+			ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
+					IC_CMBP_2);
+		} else
+			ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+	} else {
+		ic_conf &= ~IC_CONF_PRPVF_CMB;
+	}
+
+	if (src_is_csi)
+		ic_conf &= ~IC_CONF_RWS_EN;
+	else
+		ic_conf |= IC_CONF_RWS_EN;
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+	return ret;
+}
+
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
+		 IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_PRPVF_ROT_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
+			bool src_is_csi)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+	int ret = 0;
+
+	/* Setup vertical resizing */
+	if (!params->mem_prp_enc_mem.outv_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu,
+					params->mem_prp_enc_mem.in_height,
+					params->mem_prp_enc_mem.out_height,
+					&resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate prpenc height "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else
+		reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
+
+	/* Setup horizontal resizing */
+	if (!params->mem_prp_enc_mem.outh_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
+					params->mem_prp_enc_mem.out_width,
+					&resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate prpenc width "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else
+		reg |= params->mem_prp_enc_mem.outh_resize_ratio;
+
+	ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PRPENC_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PRPENC_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (src_is_csi)
+		ic_conf &= ~IC_CONF_RWS_EN;
+	else
+		ic_conf |= IC_CONF_RWS_EN;
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+	return ret;
+}
+
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPENC_ROT_EN);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+	int ret = 0;
+
+	/* Setup vertical resizing */
+	if (!params->mem_pp_mem.outv_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
+				    params->mem_pp_mem.out_height,
+				    &resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate pp height "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else {
+		reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
+	}
+
+	/* Setup horizontal resizing */
+	if (!params->mem_pp_mem.outh_resize_ratio) {
+		ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
+					params->mem_pp_mem.out_width,
+					&resizeCoeff, &downsizeCoeff);
+		if (ret < 0) {
+			dev_err(ipu->dev, "failed to calculate pp width "
+				"scaling coefficients\n");
+			return ret;
+		}
+
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else {
+		reg |= params->mem_pp_mem.outh_resize_ratio;
+	}
+
+	ipu_ic_write(ipu, reg, IC_PP_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PP_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PP_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (params->mem_pp_mem.graphics_combine_en) {
+		ic_conf |= IC_CONF_PP_CMB;
+
+		if (!(ic_conf & IC_CONF_PP_CSC1)) {
+			/* need transparent CSC1 conversion */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
+			ic_conf |= IC_CONF_PP_CSC1;  /* Enable RGB->RGB CSC */
+		}
+
+		in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
+		out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+		if (in_fmt == RGB) {
+			if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+				/* Enable RGB->YCBCR CSC2 */
+				_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
+				ic_conf |= IC_CONF_PP_CSC2;
+			}
+		}
+		if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+			if (out_fmt == RGB) {
+				/* Enable YCBCR->RGB CSC2 */
+				_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
+				ic_conf |= IC_CONF_PP_CSC2;
+			} else {
+				/* TODO: Support YUV<->YCbCr conversion? */
+			}
+		}
+
+		if (params->mem_pp_mem.global_alpha_en) {
+			ic_conf |= IC_CONF_IC_GLB_LOC_A;
+			reg = ipu_ic_read(ipu, IC_CMBP_1);
+			reg &= ~(0xff00);
+			reg |= (params->mem_pp_mem.alpha << 8);
+			ipu_ic_write(ipu, reg, IC_CMBP_1);
+		} else
+			ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+		if (params->mem_pp_mem.key_color_en) {
+			ic_conf |= IC_CONF_KEY_COLOR_EN;
+			ipu_ic_write(ipu, params->mem_pp_mem.key_color,
+					IC_CMBP_2);
+		} else
+			ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+	} else {
+		ic_conf &= ~IC_CONF_PP_CMB;
+	}
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+	return ret;
+}
+
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
+		 IC_CONF_PP_CMB);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_PP_ROT_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
+		uint16_t width, uint16_t height,
+		int burst_size, ipu_rotate_mode_t rot)
+{
+	u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+	u32 temp_rot = bitrev8(rot) >> 5;
+	bool need_hor_flip = false;
+
+	if ((burst_size != 8) && (burst_size != 16)) {
+		dev_dbg(ipu->dev, "Illegal burst length for IC\n");
+		return -EINVAL;
+	}
+
+	width--;
+	height--;
+
+	if (temp_rot & 0x2)	/* Need horizontal flip */
+		need_hor_flip = true;
+
+	ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
+	ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
+	ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
+	if (dma_chan == 22) {	/* PP output - CB2 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+	} else if (dma_chan == 11) {	/* PP Input - CB5 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+	} else if (dma_chan == 47) {	/* PP Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+	}
+
+	if (dma_chan == 12) {	/* PRP Input - CB6 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+	}
+
+	if (dma_chan == 20) {	/* PRP ENC output - CB0 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+
+	} else if (dma_chan == 45) {	/* PRP ENC Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+	}
+
+	if (dma_chan == 21) {	/* PRP VF output - CB1 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+
+	} else if (dma_chan == 46) {	/* PRP VF Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+	}
+
+	if (dma_chan == 14) {	/* PRP VF graphics combining input - CB3 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+	} else if (dma_chan == 15) {	/* PP graphics combining input - CB4 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+	} else if (dma_chan == 5) {	/* VDIC OUTPUT - CB7 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+	}
+
+	ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
+	ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
+	ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
+	return 0;
+}
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+		      ipu_color_space_t out_format, int csc_index)
+{
+	/*
+	 * Y =  0.257 * R + 0.504 * G + 0.098 * B +  16;
+	 * U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
+	 * V =  0.439 * R - 0.368 * G - 0.071 * B + 128;
+	 */
+	static const uint32_t rgb2ycbcr_coeff[4][3] = {
+		{0x0042, 0x0081, 0x0019},
+		{0x01DA, 0x01B6, 0x0070},
+		{0x0070, 0x01A2, 0x01EE},
+		{0x0040, 0x0200, 0x0200},	/* A0, A1, A2 */
+	};
+
+	/* transparent RGB->RGB matrix for combining
+	 */
+	static const uint32_t rgb2rgb_coeff[4][3] = {
+		{0x0080, 0x0000, 0x0000},
+		{0x0000, 0x0080, 0x0000},
+		{0x0000, 0x0000, 0x0080},
+		{0x0000, 0x0000, 0x0000},	/* A0, A1, A2 */
+	};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+	static const uint32_t ycbcr2rgb_coeff[4][3] = {
+		{149, 0, 204},
+		{149, 462, 408},
+		{149, 255, 0},
+		{8192 - 446, 266, 8192 - 554},	/* A0, A1, A2 */
+	};
+
+	uint32_t param;
+	uint32_t *base = NULL;
+
+	if (ic_task == IC_TASK_ENCODER) {
+		base = (uint32_t *)ipu->tpmem_base + 0x2008 / 4;
+	} else if (ic_task == IC_TASK_VIEWFINDER) {
+		if (csc_index == 1)
+			base = (uint32_t *)ipu->tpmem_base + 0x4028 / 4;
+		else
+			base = (uint32_t *)ipu->tpmem_base + 0x4040 / 4;
+	} else if (ic_task == IC_TASK_POST_PROCESSOR) {
+		if (csc_index == 1)
+			base = (uint32_t *)ipu->tpmem_base + 0x6060 / 4;
+		else
+			base = (uint32_t *)ipu->tpmem_base + 0x6078 / 4;
+	} else {
+		BUG();
+	}
+
+	if ((in_format == YCbCr) && (out_format == RGB)) {
+		/* Init CSC (YCbCr->RGB) */
+		param = (ycbcr2rgb_coeff[3][0] << 27) |
+			(ycbcr2rgb_coeff[0][0] << 18) |
+			(ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
+		writel(param, base++);
+		/* scale = 2, sat = 0 */
+		param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][1] << 27) |
+			(ycbcr2rgb_coeff[0][1] << 18) |
+			(ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
+		writel(param, base++);
+		param = (ycbcr2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][2] << 27) |
+			(ycbcr2rgb_coeff[0][2] << 18) |
+			(ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
+		writel(param, base++);
+		param = (ycbcr2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if ((in_format == RGB) && (out_format == YCbCr)) {
+		/* Init CSC (RGB->YCbCr) */
+		param = (rgb2ycbcr_coeff[3][0] << 27) |
+			(rgb2ycbcr_coeff[0][0] << 18) |
+			(rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
+		writel(param, base++);
+		/* scale = 1, sat = 0 */
+		param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][1] << 27) |
+			(rgb2ycbcr_coeff[0][1] << 18) |
+			(rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
+		writel(param, base++);
+		param = (rgb2ycbcr_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][2] << 27) |
+			(rgb2ycbcr_coeff[0][2] << 18) |
+			(rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
+		writel(param, base++);
+		param = (rgb2ycbcr_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if ((in_format == RGB) && (out_format == RGB)) {
+		/* Init CSC */
+		param =
+		    (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
+		    (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
+		writel(param, base++);
+		/* scale = 2, sat = 0 */
+		param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
+		writel(param, base++);
+
+		param =
+		    (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
+		    (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
+		writel(param, base++);
+		param = (rgb2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param =
+		    (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
+		    (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
+		writel(param, base++);
+		param = (rgb2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else {
+		dev_err(ipu->dev, "Unsupported color space conversion\n");
+	}
+}
+
+static int _calc_resize_coeffs(struct ipu_soc *ipu,
+				uint32_t inSize, uint32_t outSize,
+				uint32_t *resizeCoeff,
+				uint32_t *downsizeCoeff)
+{
+	uint32_t tempSize;
+	uint32_t tempDownsize;
+
+	if (inSize > 4096) {
+		dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
+			inSize);
+		return -EINVAL;
+	}
+
+	if (outSize > 1024) {
+		dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
+			outSize);
+		return -EINVAL;
+	}
+
+	if ((outSize << 3) < inSize) {
+		dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
+		return -EINVAL;
+	}
+
+	/* Compute downsizing coefficient */
+	/* Output of downsizing unit cannot be more than 1024 */
+	tempDownsize = 0;
+	tempSize = inSize;
+	while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+	       (tempDownsize < 2)) {
+		tempSize >>= 1;
+		tempDownsize++;
+	}
+	*downsizeCoeff = tempDownsize;
+
+	/* compute resizing coefficient using the following equation:
+	   resizeCoeff = M*(SI -1)/(SO - 1)
+	   where M = 2^13, SI - input size, SO - output size    */
+	*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+	if (*resizeCoeff >= 16384L) {
+		dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
+		"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+		*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+		((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+	return 0;
+}
+
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	uint32_t mask_reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
+	if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
+		reg &= ~VDI_C_TOP_FIELD_MAN_1;
+	else
+		reg |= VDI_C_TOP_FIELD_MAN_1;
+
+	ipu_vdi_write(ipu, reg, VDI_C);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_param_mem.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_param_mem.h
@@ -0,0 +1,1002 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __INCLUDE_IPU_PARAM_MEM_H__
+#define __INCLUDE_IPU_PARAM_MEM_H__
+
+#include <linux/bitrev.h>
+#include <linux/types.h>
+
+#include "ipu_prv.h"
+
+extern u32 *ipu_cpmem_base;
+
+struct ipu_ch_param_word {
+	uint32_t data[5];
+	uint32_t res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+#define ipu_ch_param_addr(ipu, ch) \
+	(((struct ipu_ch_param *)(ipu)->cpmem_base) + (ch))
+
+#define _param_word(base, w) \
+	(((struct ipu_ch_param *)(base))->word[(w)].data)
+
+#define ipu_ch_param_set_field(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	_param_word((base), (w))[i] |= (v) << off; \
+	if (((bit)+(size)-1)/32 > i) { \
+		_param_word((base), (w))[i + 1] |= \
+			(v) >> (off ? (32 - off) : 0); \
+	} \
+}
+
+#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	unsigned reg_offset; \
+	u32 temp; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+	reg_offset += i; \
+	temp = readl((u32 *)(base) + reg_offset); \
+	temp |= (v) << off; \
+	writel(temp, (u32 *)(base) + reg_offset); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp = readl((u32 *)(base) + reg_offset); \
+		temp |= (v) >> (off ? (32 - off) : 0); \
+		writel(temp, (u32 *)(base) + reg_offset); \
+	} \
+}
+
+#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << (size)) - 1; \
+	u32 temp = _param_word((base), (w))[i]; \
+	temp &= ~(mask << off); \
+	_param_word((base), (w))[i] = temp | (v) << off; \
+	if (((bit)+(size)-1)/32 > i) { \
+		temp = _param_word((base), (w))[i + 1]; \
+		temp &= ~(mask >> (32 - off)); \
+		_param_word((base), (w))[i + 1] = \
+			temp | ((v) >> (off ? (32 - off) : 0)); \
+	} \
+}
+
+#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << (size)) - 1; \
+	unsigned reg_offset; \
+	u32 temp; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+	reg_offset += i; \
+	temp = readl((u32 *)(base) + reg_offset); \
+	temp &= ~(mask << off); \
+	temp |= (v) << off; \
+	writel(temp, (u32 *)(base) + reg_offset); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp = readl((u32 *)(base) + reg_offset); \
+		temp &= ~(mask >> (32 - off)); \
+		temp |= ((v) >> (off ? (32 - off) : 0)); \
+		writel(temp, (u32 *)(base) + reg_offset); \
+	} \
+}
+
+#define ipu_ch_param_read_field(base, w, bit, size) ({ \
+	u32 temp2; \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << (size)) - 1; \
+	u32 temp1 = _param_word((base), (w))[i]; \
+	temp1 = mask & (temp1 >> off); \
+	if (((bit)+(size)-1)/32 > i) { \
+		temp2 = _param_word((base), (w))[i + 1]; \
+		temp2 &= mask >> (off ? (32 - off) : 0); \
+		temp1 |= temp2 << (off ? (32 - off) : 0); \
+	} \
+	temp1; \
+})
+
+#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \
+	u32 temp1, temp2; \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << (size)) - 1; \
+	unsigned reg_offset; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+	reg_offset += i; \
+	temp1 = readl((u32 *)(base) + reg_offset); \
+	temp1 = mask & (temp1 >> off); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp2 = readl((u32 *)(base) + reg_offset); \
+		temp2 &= mask >> (off ? (32 - off) : 0); \
+		temp1 |= temp2 << (off ? (32 - off) : 0); \
+	} \
+	temp1; \
+})
+
+static inline int __ipu_ch_get_third_buf_cpmem_num(int ch)
+{
+	switch (ch) {
+	case 8:
+		return 64;
+	case 9:
+		return 65;
+	case 10:
+		return 66;
+	case 13:
+		return 67;
+	case 21:
+		return 68;
+	case 23:
+		return 69;
+	case 27:
+		return 70;
+	case 28:
+		return 71;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p,
+					      int red_width, int red_offset,
+					      int green_width, int green_offset,
+					      int blue_width, int blue_offset,
+					      int alpha_width, int alpha_offset)
+{
+	/* Setup red width and offset */
+	ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
+	ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
+	ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
+	ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
+	ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
+}
+
+static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
+{
+	struct ipu_ch_param *p = ipu_ch_param_addr(ipu, ch);
+	dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+		 p->word[0].data[3], p->word[0].data[4]);
+	dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+		 p->word[1].data[3], p->word[1].data[4]);
+	dev_dbg(ipu->dev, "PFS 0x%x, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4));
+	dev_dbg(ipu->dev, "BPP 0x%x, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3));
+	dev_dbg(ipu->dev, "NPB 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7));
+
+	dev_dbg(ipu->dev, "FW %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
+	dev_dbg(ipu->dev, "FH %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
+	dev_dbg(ipu->dev, "EBA0 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
+	dev_dbg(ipu->dev, "EBA1 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
+	dev_dbg(ipu->dev, "Stride %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
+	dev_dbg(ipu->dev, "scan_order %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
+	dev_dbg(ipu->dev, "uv_stride %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
+	dev_dbg(ipu->dev, "u_offset 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
+	dev_dbg(ipu->dev, "v_offset 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
+
+	dev_dbg(ipu->dev, "Width0 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
+	dev_dbg(ipu->dev, "Width1 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3));
+	dev_dbg(ipu->dev, "Width2 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3));
+	dev_dbg(ipu->dev, "Width3 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3));
+	dev_dbg(ipu->dev, "Offset0 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5));
+	dev_dbg(ipu->dev, "Offset1 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5));
+	dev_dbg(ipu->dev, "Offset2 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5));
+	dev_dbg(ipu->dev, "Offset3 %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5));
+}
+
+static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params)
+{
+	int i, w;
+	void *addr = ipu_ch_param_addr(ipu, ch);
+
+	/* 2 words, 5 valid data */
+	for (w = 0; w < 2; w++) {
+		for (i = 0; i < 5; i++) {
+			writel(params->word[w].data[i], addr);
+			addr += 4;
+		}
+		addr += 12;
+	}
+}
+
+static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
+				      uint32_t pixel_fmt, uint32_t width,
+				      uint32_t height, uint32_t stride,
+				      uint32_t u, uint32_t v,
+				      uint32_t uv_stride, dma_addr_t addr0,
+				      dma_addr_t addr1, dma_addr_t addr2)
+{
+	uint32_t u_offset = 0;
+	uint32_t v_offset = 0;
+	uint32_t bs = 0;
+	int32_t sub_ch = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
+
+	if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) {
+		ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+	} else {
+		/* note: for vdoa+vdi- ch8/9/10, always use band mode */
+		ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+	}
+
+	/* EBA is 8-byte aligned */
+	ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
+	ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+	if (addr0%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
+	if (addr1%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/*Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, 0, 107, 3, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 63);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_16:
+		/* Represents 16-bit generic data */
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_32:
+		/*Represents 32-bit Generic data */
+		break;
+	case IPU_PIX_FMT_RGB565:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+		break;
+	case IPU_PIX_FMT_BGRA4444:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 4, 4, 4, 8, 4, 12, 4, 0);
+		break;
+	case IPU_PIX_FMT_BGRA5551:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 5, 1, 5, 6, 5, 11, 1, 0);
+		break;
+	case IPU_PIX_FMT_BGR24:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 19);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 19);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_VYU444:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 19);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 8, 8, 0, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_AYUV:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+		break;
+	case IPU_PIX_FMT_ABGR32:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_UYVY:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 0xA);	/* pix format */
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 0x8);	/* pix format */
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			if (ipu->vdoa_en) {
+				ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+			} else {
+				ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+			}
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, 1, 85, 4, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			if (_ipu_is_smfc_chan(ch) &&
+				ipu->smfc_idmac_12bit_3planar_bs_fixup)
+				bs = 15;
+			else
+				bs = 31;
+			ipu_ch_param_set_field(&params, 1, 78, 7, bs);  /* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		ipu_ch_param_set_field(&params, 1, 85, 4, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = stride * height;
+		u_offset = v_offset + (uv_stride * height / 2);
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			if (_ipu_is_smfc_chan(ch) &&
+				ipu->smfc_idmac_12bit_3planar_bs_fixup)
+				bs = 15;
+			else
+				bs = 31;
+			ipu_ch_param_set_field(&params, 1, 78, 7, bs);  /* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = (v == 0) ? stride * height : v;
+		u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+		break;
+	case IPU_PIX_FMT_YUV444P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 0);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset * 2 : v;
+		break;
+	case IPU_PIX_FMT_NV16:
+		ipu_ch_param_set_field(&params, 1, 85, 4, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		break;
+	case IPU_PIX_FMT_NV12:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 4);	/* pix format */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			if (ipu->vdoa_en) {
+				 /* one field buffer, memory width 64bits */
+				ipu_ch_param_set_field(&params, 1, 78, 7, 63);
+			} else {
+				ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+				 /* top/bottom field in one buffer*/
+				uv_stride = uv_stride*2;
+			}
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	default:
+		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+		break;
+	}
+	/*set burst size to 16*/
+
+
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
+
+	/* Get the uv offset from user when need cropping */
+	if (u || v) {
+		u_offset = u;
+		v_offset = v;
+	}
+
+	/* UBO and VBO are 22-bit and 8-byte aligned */
+	if (u_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's U offset exceeds IPU limitation\n", ch);
+	if (v_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+	if (u_offset%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+	if (v_offset%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+	ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
+	ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
+
+	dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch));
+	fill_cpmem(ipu, ch, &params);
+	if (addr2) {
+		sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+		if (sub_ch <= 0)
+			return;
+
+		ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
+		ipu_ch_param_set_field(&params, 1, 29, 29, 0);
+		if (addr2%8)
+			dev_warn(ipu->dev,
+				 "IDMAC%d's sub-CPMEM entry%d EBA0 is not "
+				 "8-byte aligned\n", ch, sub_ch);
+
+		dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
+					ipu_ch_param_addr(ipu, sub_ch));
+		fill_cpmem(ipu, sub_ch, &params);
+	}
+};
+
+static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
+						uint32_t ch,
+						uint16_t burst_pixels)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7,
+			       burst_pixels - 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7,
+			       burst_pixels - 1);
+};
+
+static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch)
+{
+	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1;
+};
+
+static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch)
+{
+	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3);
+};
+
+static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch,
+					int bufNum, dma_addr_t phyaddr)
+{
+	if (bufNum == 2) {
+		ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+		if (ch <= 0)
+			return;
+		bufNum = 0;
+	}
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29,
+			       phyaddr / 8);
+};
+
+static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch,
+					      ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot);
+};
+
+static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
+								uint32_t ch,
+								bool option)
+{
+	int32_t sub_ch = 0;
+
+	if (option) {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1);
+	} else {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0);
+	}
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+
+	if (option) {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1);
+	} else {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0);
+	}
+};
+
+static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch)
+{
+	int alp_mem_idx;
+	int32_t sub_ch = 0;
+
+	switch (ch) {
+	case 14: /* PRP graphic */
+		alp_mem_idx = 0;
+		break;
+	case 15: /* PP graphic */
+		alp_mem_idx = 1;
+		break;
+	case 23: /* DP BG SYNC graphic */
+		alp_mem_idx = 4;
+		break;
+	case 27: /* DP FG SYNC graphic */
+		alp_mem_idx = 2;
+		break;
+	default:
+		dev_err(ipu->dev, "unsupported correlative channel of local "
+			"alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx);
+};
+
+static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch)
+{
+	u32 stride;
+	int32_t sub_ch = 0;
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);
+	if (sub_ch > 0)
+		ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1);
+	stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1;
+	/* ILO is 20-bit and 8-byte aligned */
+	if (stride/8 > 0xfffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's ILO exceeds IPU limitation\n", ch);
+	if (stride%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's ILO is not 8-byte aligned\n", ch);
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8);
+	if (sub_ch > 0)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20,
+				       stride / 8);
+	stride *= 2;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1);
+	if (sub_ch > 0)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14,
+				       stride - 1);
+};
+
+static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id)
+{
+	int32_t sub_ch = 0;
+
+	id %= 4;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id);
+};
+
+static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch)
+{
+	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2);
+}
+
+static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt,
+				       uint32_t width,
+				       uint32_t height,
+				       uint32_t stride,
+				       uint32_t u,
+				       uint32_t v,
+				       uint32_t uv_stride,
+				       uint32_t vertical_offset,
+				       uint32_t horizontal_offset,
+				       uint32_t *u_offset,
+				       uint32_t *v_offset)
+{
+	uint32_t u_fix = 0;
+	uint32_t v_fix = 0;
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_GENERIC_16:
+	case IPU_PIX_FMT_GENERIC_32:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGRA4444:
+	case IPU_PIX_FMT_BGRA5551:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_AYUV:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_GPU32_SB_ST:
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+	case IPU_PIX_FMT_GPU32_ST:
+	case IPU_PIX_FMT_GPU32_SRT:
+	case IPU_PIX_FMT_GPU16_SB_ST:
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+	case IPU_PIX_FMT_GPU16_ST:
+	case IPU_PIX_FMT_GPU16_SRT:
+		*u_offset = 0;
+		*v_offset = 0;
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		*u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset / 2;
+		*v_offset = *u_offset + (uv_stride * height / 2);
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*v_offset;
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		*v_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset / 2;
+		*u_offset = *v_offset + (uv_stride * height / 2);
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*v_offset;
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		*v_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset) +
+					horizontal_offset / 2;
+		*u_offset = *v_offset + uv_stride * height;
+		u_fix = u ? (u + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*v_offset;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		*u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset) +
+					horizontal_offset / 2;
+		*v_offset = *u_offset + uv_stride * height;
+		u_fix = u ? (u + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*v_offset;
+		break;
+	case IPU_PIX_FMT_YUV444P:
+		uv_stride = stride;
+		*u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset) +
+					horizontal_offset;
+		*v_offset = *u_offset + uv_stride * height;
+		u_fix = u ? (u + (uv_stride * vertical_offset) +
+					horizontal_offset -
+					(stride * vertical_offset) -
+					(horizontal_offset)) :
+					*u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset) +
+					horizontal_offset -
+					(stride * vertical_offset) -
+					(horizontal_offset)) :
+					*v_offset;
+		break;
+	case IPU_PIX_FMT_NV12:
+	case IPU_PIX_FMT_NV16:
+	case PRE_PIX_FMT_NV21:
+	case PRE_PIX_FMT_NV61:
+		uv_stride = stride;
+		*u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset;
+		*v_offset = 0;
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					horizontal_offset -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					*u_offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (u_fix > *u_offset)
+		*u_offset = u_fix;
+
+	if (v_fix > *v_offset)
+		*v_offset = v_fix;
+
+	return 0;
+}
+
+/* IDMAC U/V offset changing support */
+/* U and V input is not affected, */
+/* the update is done by new calculation according to */
+/* vertical_offset and horizontal_offset */
+static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
+					 int ch,
+					 uint32_t pixel_fmt,
+					 uint32_t width,
+					 uint32_t height,
+					 uint32_t stride,
+					 uint32_t u,
+					 uint32_t v,
+					 uint32_t uv_stride,
+					 uint32_t vertical_offset,
+					 uint32_t horizontal_offset)
+{
+	uint32_t u_offset = 0;
+	uint32_t v_offset = 0;
+	uint32_t old_offset = 0;
+	int32_t sub_ch = 0;
+	int ret;
+
+	ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
+				   u, v, uv_stride,
+				   vertical_offset, horizontal_offset,
+				   &u_offset, &v_offset);
+	if (ret) {
+		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+		return;
+	}
+
+	/* UBO and VBO are 22-bit and 8-byte aligned */
+	if (u_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			"IDMAC%d's U offset exceeds IPU limitation\n", ch);
+	if (v_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			"IDMAC%d's V offset exceeds IPU limitation\n", ch);
+	if (u_offset%8)
+		dev_warn(ipu->dev,
+			"IDMAC%d's U offset is not 8-byte aligned\n", ch);
+	if (v_offset%8)
+		dev_warn(ipu->dev,
+			"IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22);
+	if (old_offset != u_offset / 8)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
+	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22);
+	if (old_offset != v_offset / 8)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22);
+	if (old_offset != u_offset / 8)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
+	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22);
+	if (old_offset != v_offset / 8)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8);
+};
+
+static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
+};
+
+static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
+			uint32_t ch, uint32_t band_height)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
+					0, 114, 3, band_height - 1);
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch),
+					0, 114, 3, band_height - 1);
+
+	dev_dbg(ipu->dev, "BNDM 0x%x, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
+}
+
+/*
+ * The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane
+ * whose alpha component is at the most significant 8 bits. The bug only
+ * impacts on cases in which the relevant separate alpha channel is enabled.
+ *
+ * Return true on bad alpha component position, otherwise, return false.
+ */
+static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		return true;
+	}
+
+	return false;
+}
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_pixel_clk.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_pixel_clk.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_pixel_clk.c
+ *
+ * @brief IPU pixel clock implementation
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+ /*
+ * muxd clock implementation
+ */
+struct clk_di_mux {
+	struct clk_hw hw;
+	u8		ipu_id;
+	u8		di_id;
+	u8		flags;
+	u8		index;
+};
+#define to_clk_di_mux(_hw) container_of(_hw, struct clk_di_mux, hw)
+
+static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_di_mux *mux = to_clk_di_mux(hw);
+	struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id);
+	u32 di_gen;
+
+	di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL);
+	if (index == 0)
+		/* ipu1_clk or ipu2_clk internal clk */
+		di_gen &= ~DI_GEN_DI_CLK_EXT;
+	else
+		di_gen |= DI_GEN_DI_CLK_EXT;
+
+	ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL);
+	mux->index = index;
+	pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n",
+			!(di_gen & DI_GEN_DI_CLK_EXT), di_gen);
+	return 0;
+}
+
+static u8 _ipu_pixel_clk_get_parent(struct clk_hw *hw)
+{
+	struct clk_di_mux *mux = to_clk_di_mux(hw);
+
+	return mux->index;
+}
+
+const struct clk_ops clk_mux_di_ops = {
+	.get_parent = _ipu_pixel_clk_get_parent,
+	.set_parent = _ipu_pixel_clk_set_parent,
+};
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+		const char **parent_names, u8 num_parents, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_mux_flags)
+{
+	struct clk_di_mux *mux;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	mux = kzalloc(sizeof(struct clk_di_mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_mux_di_ops;
+	init.flags = flags;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	mux->ipu_id = ipu_id;
+	mux->di_id = di_id;
+	mux->flags = clk_mux_flags | CLK_SET_RATE_PARENT;
+	mux->hw.init = &init;
+
+	clk = clk_register(dev, &mux->hw);
+	if (IS_ERR(clk))
+		kfree(mux);
+
+	return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_div {
+	struct clk_hw hw;
+	u8		ipu_id;
+	u8		di_id;
+	u8		flags;
+};
+#define to_clk_di_div(_hw) container_of(_hw, struct clk_di_div, hw)
+
+static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct clk_di_div *di_div = to_clk_di_div(hw);
+	struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+	u32 div;
+	u64 final_rate = (unsigned long long)parent_rate * 16;
+
+	_ipu_get(ipu);
+	div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0);
+	_ipu_put(ipu);
+	pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
+			di_div->di_id, div, final_rate, parent_rate);
+
+	if (div == 0)
+		return 0;
+	do_div(final_rate, div);
+
+	return (unsigned long)final_rate;
+}
+
+static long _ipu_pixel_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *parent_clk_rate)
+{
+	u64 div, final_rate;
+	u32 remainder;
+	u64 parent_rate = (unsigned long long)(*parent_clk_rate) * 16;
+
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = parent_rate;
+	remainder = do_div(div, rate);
+	/* Round the divider value */
+	if (remainder > (rate/2))
+		div++;
+	if (div < 0x10)            /* Min DI disp clock divider is 1 */
+		div = 0x10;
+	if (div & ~0xFEF)
+		div &= 0xFF8;
+	else {
+		/* Round up divider if it gets us closer to desired pix clk */
+		if ((div & 0xC) == 0xC) {
+			div += 0x10;
+			div &= ~0xF;
+		}
+	}
+	final_rate = parent_rate;
+	do_div(final_rate, div);
+
+	return final_rate;
+}
+
+static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_clk_rate)
+{
+	struct clk_di_div *di_div = to_clk_di_div(hw);
+	struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+	u64 div, parent_rate;
+	u32 remainder;
+
+	parent_rate = (unsigned long long)parent_clk_rate * 16;
+	div = parent_rate;
+	remainder = do_div(div, rate);
+	/* Round the divider value */
+	if (remainder > (rate/2))
+		div++;
+
+	/* Round up divider if it gets us closer to desired pix clk */
+	if ((div & 0xC) == 0xC) {
+		div += 0x10;
+		div &= ~0xF;
+	}
+	if (div > 0x1000)
+		pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n",
+				di_div->di_id, (u32)div);
+	_ipu_get(ipu);
+	ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* FIXME: needs to be more flexible */
+	/* Down time is half of period */
+	ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1);
+	_ipu_put(ipu);
+
+	return 0;
+}
+
+static struct clk_ops clk_div_ops = {
+	.recalc_rate = _ipu_pixel_clk_div_recalc_rate,
+	.round_rate = _ipu_pixel_clk_div_round_rate,
+	.set_rate = _ipu_pixel_clk_div_set_rate,
+};
+
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_div_flags)
+{
+	struct clk_di_div *di_div;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	di_div = kzalloc(sizeof(struct clk_di_div), GFP_KERNEL);
+	if (!di_div)
+		return ERR_PTR(-ENOMEM);
+
+	/* struct clk_di_div assignments */
+	di_div->ipu_id = ipu_id;
+	di_div->di_id = di_id;
+	di_div->flags = clk_div_flags;
+
+	init.name = name;
+	init.ops = &clk_div_ops;
+	init.flags = flags | CLK_SET_RATE_PARENT;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	di_div->hw.init = &init;
+
+	clk = clk_register(dev, &di_div->hw);
+	if (IS_ERR(clk))
+		kfree(di_div);
+
+	return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_gate {
+	struct clk_hw hw;
+	u8		ipu_id;
+	u8		di_id;
+	u8		flags;
+};
+#define to_clk_di_gate(_hw) container_of(_hw, struct clk_di_gate, hw)
+
+static int _ipu_pixel_clk_enable(struct clk_hw *hw)
+{
+	struct clk_di_gate *gate = to_clk_di_gate(hw);
+	struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+	u32 disp_gen;
+
+	disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen |= gate->di_id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+	return 0;
+}
+
+static void _ipu_pixel_clk_disable(struct clk_hw *hw)
+{
+	struct clk_di_gate *gate = to_clk_di_gate(hw);
+	struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+	u32 disp_gen;
+
+	disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen &= gate->di_id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+}
+
+
+static struct clk_ops clk_gate_di_ops = {
+	.enable = _ipu_pixel_clk_enable,
+	.disable = _ipu_pixel_clk_disable,
+};
+
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_gate_flags)
+{
+	struct clk_di_gate *gate;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	gate = kzalloc(sizeof(struct clk_di_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->ipu_id = ipu_id;
+	gate->di_id = di_id;
+	gate->flags = clk_gate_flags;
+
+	init.name = name;
+	init.ops = &clk_gate_di_ops;
+	init.flags = flags | CLK_SET_RATE_PARENT;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	gate->hw.init = &init;
+
+	clk = clk_register(dev, &gate->hw);
+	if (IS_ERR(clk))
+		kfree(gate);
+
+	return clk;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_prv.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_prv.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __INCLUDE_IPU_PRV_H__
+#define __INCLUDE_IPU_PRV_H__
+
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/ipu-v3.h>
+#include <linux/types.h>
+
+#define MXC_IPU_MAX_NUM		2
+#define MXC_DI_NUM_PER_IPU	2
+
+/* Globals */
+extern int dmfc_type_setup;
+
+#define IDMA_CHAN_INVALID	0xFF
+#define HIGH_RESOLUTION_WIDTH	1024
+
+enum ipuv3_type {
+	IPUv3D,		/* i.MX37 */
+	IPUv3EX,	/* i.MX51 */
+	IPUv3M,		/* i.MX53 */
+	IPUv3H,		/* i.MX6Q/SDL */
+};
+
+#define IPU_MAX_VDI_IN_WIDTH(type)	({ (type) >= IPUv3M ? 968 : 720; })
+
+struct ipu_irq_node {
+	irqreturn_t(*handler) (int, void *);	/*!< the ISR */
+	const char *name;	/*!< device associated with the interrupt */
+	void *dev_id;		/*!< some unique information for the ISR */
+	__u32 flags;		/*!< not used */
+};
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+struct ipu_soc {
+	unsigned int id;
+	unsigned int devtype;
+	bool online;
+
+	/*clk*/
+	struct clk *ipu_clk;
+	struct clk *di_clk[2];
+	struct clk *di_clk_sel[2];
+	struct clk *pixel_clk[2];
+	bool pixel_clk_en[2];
+	struct clk *pixel_clk_sel[2];
+	struct clk *csi_clk[2];
+	struct clk *prg_clk;
+
+	/*irq*/
+	int irq_sync;
+	int irq_err;
+	struct ipu_irq_node irq_list[IPU_IRQ_COUNT];
+
+	/*reg*/
+	void __iomem *cm_reg;
+	void __iomem *idmac_reg;
+	void __iomem *dp_reg;
+	void __iomem *ic_reg;
+	void __iomem *dc_reg;
+	void __iomem *dc_tmpl_reg;
+	void __iomem *dmfc_reg;
+	void __iomem *di_reg[2];
+	void __iomem *smfc_reg;
+	void __iomem *csi_reg[2];
+	void __iomem *cpmem_base;
+	void __iomem *tpmem_base;
+	void __iomem *vdi_reg;
+
+	struct device *dev;
+
+	ipu_channel_t csi_channel[2];
+	ipu_channel_t using_ic_dirct_ch;
+	unsigned char dc_di_assignment[10];
+	bool sec_chan_en[IPU_MAX_CH];
+	bool thrd_chan_en[IPU_MAX_CH];
+	bool chan_is_interlaced[52];
+	uint32_t channel_init_mask;
+	uint32_t channel_enable_mask;
+
+	/*use count*/
+	int dc_use_count;
+	int dp_use_count;
+	int dmfc_use_count;
+	int smfc_use_count;
+	int ic_use_count;
+	int rot_use_count;
+	int vdi_use_count;
+	int di_use_count[2];
+	int csi_use_count[2];
+
+	struct mutex mutex_lock;
+	spinlock_t int_reg_spin_lock;
+	spinlock_t rdy_reg_spin_lock;
+
+	int dmfc_size_28;
+	int dmfc_size_29;
+	int dmfc_size_24;
+	int dmfc_size_27;
+	int dmfc_size_23;
+
+	enum csc_type_t fg_csc_type;
+	enum csc_type_t bg_csc_type;
+	bool color_key_4rgb;
+	bool dc_swap;
+	struct completion dc_comp;
+	struct completion csi_comp;
+
+	struct rot_mem {
+		void *vaddr;
+		dma_addr_t paddr;
+		int size;
+	} rot_dma[2];
+
+	int	vdoa_en;
+	struct task_struct *thread[2];
+
+	/*
+	 * Bypass reset to avoid display channel being
+	 * stopped by probe since it may starts to work
+	 * in bootloader.
+	 */
+	bool bypass_reset;
+
+	unsigned int ch0123_axi;
+	unsigned int ch23_axi;
+	unsigned int ch27_axi;
+	unsigned int ch28_axi;
+	unsigned int normal_axi;
+
+	bool smfc_idmac_12bit_3planar_bs_fixup;	/* workaround little stripes */
+};
+
+struct ipu_channel {
+	u8 video_in_dma;
+	u8 alpha_in_dma;
+	u8 graph_in_dma;
+	u8 out_dma;
+};
+
+enum ipu_dmfc_type {
+	DMFC_NORMAL = 0,
+	DMFC_HIGH_RESOLUTION_DC,
+	DMFC_HIGH_RESOLUTION_DP,
+	DMFC_HIGH_RESOLUTION_ONLY_DP,
+};
+
+static inline int _ipu_is_smfc_chan(uint32_t dma_chan)
+{
+	return dma_chan <= 3;
+}
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->idmac_reg + offset);
+}
+
+static inline u32 ipu_dc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dc_reg + offset);
+}
+
+static inline void ipu_dc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dc_reg + offset);
+}
+
+static inline u32 ipu_dc_tmpl_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dc_tmpl_reg + offset);
+}
+
+static inline void ipu_dc_tmpl_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dc_tmpl_reg + offset);
+}
+
+static inline u32 ipu_dmfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dmfc_reg + offset);
+}
+
+static inline void ipu_dmfc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dmfc_reg + offset);
+}
+
+static inline u32 ipu_dp_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dp_reg + offset);
+}
+
+static inline void ipu_dp_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dp_reg + offset);
+}
+
+static inline u32 ipu_di_read(struct ipu_soc *ipu, int di, unsigned offset)
+{
+	return readl(ipu->di_reg[di] + offset);
+}
+
+static inline void ipu_di_write(struct ipu_soc *ipu, int di,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->di_reg[di] + offset);
+}
+
+static inline u32 ipu_csi_read(struct ipu_soc *ipu, int csi, unsigned offset)
+{
+	return readl(ipu->csi_reg[csi] + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_soc *ipu, int csi,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->csi_reg[csi] + offset);
+}
+
+static inline u32 ipu_smfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->smfc_reg + offset);
+}
+
+static inline void ipu_smfc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->smfc_reg + offset);
+}
+
+static inline u32 ipu_vdi_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->vdi_reg + offset);
+}
+
+static inline void ipu_vdi_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->vdi_reg + offset);
+}
+
+static inline u32 ipu_ic_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ic_reg + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ic_reg + offset);
+}
+
+int register_ipu_device(struct ipu_soc *ipu, int id);
+void unregister_ipu_device(struct ipu_soc *ipu, int id);
+ipu_color_space_t format_to_colorspace(uint32_t fmt);
+bool ipu_pixel_format_has_alpha(uint32_t fmt);
+
+void ipu_dump_registers(struct ipu_soc *ipu);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void ipu_disp_init(struct ipu_soc *ipu);
+void _ipu_init_dc_mappings(struct ipu_soc *ipu);
+int _ipu_dp_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t in_pixel_fmt,
+		 uint32_t out_pixel_fmt);
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan);
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap);
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first);
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width);
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size);
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+int  _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
+			bool src_is_csi);
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
+void _ipu_vdi_uninit(struct ipu_soc *ipu);
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu);
+void _ipu_ic_init_csi(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_csi(struct ipu_soc *ipu);
+int  _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
+			 bool src_is_csi);
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu);
+int  _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu);
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_t height,
+		      int burst_size, ipu_rotate_mode_t rot);
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu);
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi);
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi);
+void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+		uint32_t g_value, uint32_t b_value,
+		uint32_t pix_clk, uint32_t csi);
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+		int16_t x_pos, int16_t y_pos);
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+		int16_t *x_pos, int16_t *y_pos);
+void _ipu_get(struct ipu_soc *ipu);
+void _ipu_put(struct ipu_soc *ipu);
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+		const char **parent_names, u8 num_parents, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_mux_flags);
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_div_flags);
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		u8 ipu_id, u8 di_id, u8 clk_gate_flags);
+#endif				/* __INCLUDE_IPU_PRV_H__ */
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/ipu_regs.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/ipu_regs.h
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_regs.h
+ *
+ * @brief IPU Register definitions
+ *
+ * @ingroup IPU
+ */
+#ifndef __IPU_REGS_INCLUDED__
+#define __IPU_REGS_INCLUDED__
+
+#include "ipu_prv.h"
+
+#define IPU_MCU_T_DEFAULT	8
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)		(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00A0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00A4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00A8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00AC)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00B0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00B4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00B8)
+#define IPU_SKIP			IPU_CM_REG(0x00BC)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00C0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00C4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00C8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00CC)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00D0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00D4)
+#define IPU_SNOOP			IPU_CM_REG(0x00D8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00DC)
+#define IPU_PM				IPU_CM_REG(0x00E0)
+#define IPU_GPR				IPU_CM_REG(0x00E4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+/*
+ * IPUv3D doesn't support triple buffer, so point
+ * IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and
+ * IPU_CHA_BUF2_RDY to readonly
+ * IPU_ALT_CUR_BUF0 for IPUv3D.
+ */
+#define IPU_CHA_TRB_MODE_SEL(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0178 + 4 * ((ch) / 32)) : \
+					    (0x012C); })
+#define IPU_CHA_TRIPLE_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+					      (0x0258 + \
+					       4 * (((ch) * 2) / 32)) : \
+					      (0x012C); })
+#define IPU_CHA_BUF2_RDY(type, ch)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0288 + 4 * ((ch) / 32)) : \
+					    (0x012C); })
+#define IPU_CHA_CUR_BUF(type, ch)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x023C + 4 * ((ch) / 32)) : \
+					    (0x0124 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CUR_BUF0(type)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0244) : \
+					    (0x012C); })
+#define IPU_ALT_CUR_BUF1(type)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0248) : \
+					    (0x0130); })
+#define IPU_SRM_STAT(type)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x024C) : \
+					    (0x0134); })
+#define IPU_PROC_TASK_STAT(type)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0250) : \
+					    (0x0138); })
+#define IPU_DISP_TASK_STAT(type)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0254) : \
+					    (0x013C); })
+#define IPU_CHA_BUF0_RDY(type, ch)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0268 + 4 * ((ch) / 32)) : \
+					    (0x0140 + 4 * ((ch) / 32)); })
+#define IPU_CHA_BUF1_RDY(type, ch)	IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0270 + 4 * ((ch) / 32)) : \
+					    (0x0148 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+					     (0x0278 + 4 * ((ch) / 32)) : \
+					     (0x0158 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+					     (0x0280 + 4 * ((ch) / 32)) : \
+					     (0x0160 + 4 * ((ch) / 32)); })
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_STAT(type, n)		IPU_CM_REG({(type) >= IPUv3EX ? \
+					    (0x0200 + 4 * ((n) - 1)) : \
+					    (0x00E8 + 4 * ((n) - 1)); })
+
+#define IPUIRQ_2_STATREG(type, irq)	IPU_CM_REG(IPU_INT_STAT((type), 1) + 4 \
+							* ((irq) / 32))
+#define IPUIRQ_2_CTRLREG(irq)	IPU_CM_REG(IPU_INT_CTRL(1) + 4 * ((irq) / 32))
+#define IPUIRQ_2_MASK(irq)	(1UL << ((irq) & 0x1F))
+
+/* IPU VDI registers */
+#define IPU_VDI_REG(offset)	(offset)
+
+#define VDI_FSIZE		IPU_VDI_REG(0)
+#define VDI_C			IPU_VDI_REG(0x0004)
+
+/* IPU CSI Registers */
+#define IPU_CSI_REG(offset)	(offset)
+
+#define CSI_SENS_CONF		IPU_CSI_REG(0)
+#define CSI_SENS_FRM_SIZE	IPU_CSI_REG(0x0004)
+#define CSI_ACT_FRM_SIZE	IPU_CSI_REG(0x0008)
+#define CSI_OUT_FRM_CTRL	IPU_CSI_REG(0x000C)
+#define CSI_TST_CTRL		IPU_CSI_REG(0x0010)
+#define CSI_CCIR_CODE_1		IPU_CSI_REG(0x0014)
+#define CSI_CCIR_CODE_2		IPU_CSI_REG(0x0018)
+#define CSI_CCIR_CODE_3		IPU_CSI_REG(0x001C)
+#define CSI_MIPI_DI		IPU_CSI_REG(0x0020)
+#define CSI_SKIP		IPU_CSI_REG(0x0024)
+#define CSI_CPD_CTRL		IPU_CSI_REG(0x0028)
+#define CSI_CPD_RC(n)		IPU_CSI_REG(0x002C + 4 * (n))
+#define CSI_CPD_RS(n)		IPU_CSI_REG(0x004C + 4 * (n))
+#define CSI_CPD_GRC(n)		IPU_CSI_REG(0x005C + 4 * (n))
+#define CSI_CPD_GRS(n)		IPU_CSI_REG(0x007C + 4 * (n))
+#define CSI_CPD_GBC(n)		IPU_CSI_REG(0x008C + 4 * (n))
+#define CSI_CPD_GBS(n)		IPU_CSI_REG(0x00AC + 4 * (n))
+#define CSI_CPD_BC(n)		IPU_CSI_REG(0x00BC + 4 * (n))
+#define CSI_CPD_BS(n)		IPU_CSI_REG(0x00DC + 4 * (n))
+#define CSI_CPD_OFFSET1		IPU_CSI_REG(0x00EC)
+#define CSI_CPD_OFFSET2		IPU_CSI_REG(0x00F0)
+
+/* IPU SMFC Registers */
+#define IPU_SMFC_REG(offset)	(offset)
+
+#define SMFC_MAP		IPU_SMFC_REG(0)
+#define SMFC_WMC		IPU_SMFC_REG(0x0004)
+#define SMFC_BS			IPU_SMFC_REG(0x0008)
+
+/* IPU IC Registers */
+#define IPU_IC_REG(offset)	(offset)
+
+#define IC_CONF			IPU_IC_REG(0)
+#define IC_PRP_ENC_RSC		IPU_IC_REG(0x0004)
+#define IC_PRP_VF_RSC		IPU_IC_REG(0x0008)
+#define IC_PP_RSC		IPU_IC_REG(0x000C)
+#define IC_CMBP_1		IPU_IC_REG(0x0010)
+#define IC_CMBP_2		IPU_IC_REG(0x0014)
+#define IC_IDMAC_1		IPU_IC_REG(0x0018)
+#define IC_IDMAC_2		IPU_IC_REG(0x001C)
+#define IC_IDMAC_3		IPU_IC_REG(0x0020)
+#define IC_IDMAC_4		IPU_IC_REG(0x0024)
+
+/* IPU IDMAC Registers */
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF		IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)	IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA		IPU_IDMAC_REG(0x000C)
+#define IDMAC_ALT_SEP_ALPHA	IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)	IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)		IPU_IDMAC_REG(0x001C + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0024) : 0; })
+#define IDMAC_CH_LOCK_EN_2(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0028) : \
+					       (0x0024); })
+#define IDMAC_SUB_ADDR_0(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x002C) : \
+					       (0x0028); })
+#define IDMAC_SUB_ADDR_1(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0030) : \
+					       (0x002C); })
+#define IDMAC_SUB_ADDR_2(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0034) : \
+					       (0x0030); })
+/*
+ * IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4,
+ * so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D.
+ */
+#define IDMAC_SUB_ADDR_3(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0038) : \
+					       (0x0040); })
+#define IDMAC_SUB_ADDR_4(type)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x003C) : \
+					       (0x0040); })
+#define IDMAC_BAND_EN(type, ch)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0040 + 4 * ((ch) / 32)) : \
+					       (0x0034 + 4 * ((ch) / 32)); })
+#define IDMAC_CHA_BUSY(type, ch)	IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+					       (0x0100 + 4 * ((ch) / 32)) : \
+					       (0x0040 + 4 * ((ch) / 32)); })
+
+/* IPU DI Registers */
+#define IPU_DI_REG(offset)	(offset)
+
+#define DI_GENERAL		IPU_DI_REG(0)
+#define DI_BS_CLKGEN0		IPU_DI_REG(0x0004)
+#define DI_BS_CLKGEN1		IPU_DI_REG(0x0008)
+#define DI_SW_GEN0(gen)		IPU_DI_REG(0x000C + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		IPU_DI_REG(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		IPU_DI_REG(0x0148 + 4 * (((gen) - 1) / 2))
+#define DI_SYNC_AS_GEN		IPU_DI_REG(0x0054)
+#define DI_DW_GEN(gen)		IPU_DI_REG(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	IPU_DI_REG(0x0088 + 4 * ((gen) + 0xC * (set)))
+#define DI_SER_CONF		IPU_DI_REG(0x015C)
+#define DI_SSC			IPU_DI_REG(0x0160)
+#define DI_POL			IPU_DI_REG(0x0164)
+#define DI_AW0			IPU_DI_REG(0x0168)
+#define DI_AW1			IPU_DI_REG(0x016C)
+#define DI_SCR_CONF		IPU_DI_REG(0x0170)
+#define DI_STAT			IPU_DI_REG(0x0174)
+
+/* IPU DMFC Registers */
+#define IPU_DMFC_REG(offset)	(offset)
+
+#define DMFC_RD_CHAN		IPU_DMFC_REG(0)
+#define DMFC_WR_CHAN		IPU_DMFC_REG(0x0004)
+#define DMFC_WR_CHAN_DEF	IPU_DMFC_REG(0x0008)
+#define DMFC_DP_CHAN		IPU_DMFC_REG(0x000C)
+#define DMFC_DP_CHAN_DEF	IPU_DMFC_REG(0x0010)
+#define DMFC_GENERAL1		IPU_DMFC_REG(0x0014)
+#define DMFC_GENERAL2		IPU_DMFC_REG(0x0018)
+#define DMFC_IC_CTRL		IPU_DMFC_REG(0x001C)
+#define DMFC_STAT		IPU_DMFC_REG(0x0020)
+
+/* IPU DC Registers */
+#define IPU_DC_REG(offset)	(offset)
+
+#define DC_MAP_CONF_PTR(n)	IPU_DC_REG(0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	IPU_DC_REG(0x0144 + ((n) & ~0x1) * 2)
+
+#define _RL_CH_2_OFFSET(ch)	(((ch) == 0) ? 8 : ( \
+				 ((ch) == 1) ? 0x24 : ( \
+				 ((ch) == 2) ? 0x40 : ( \
+				 ((ch) == 5) ? 0x64 : ( \
+				 ((ch) == 6) ? 0x80 : ( \
+				 ((ch) == 8) ? 0x9C : ( \
+				 ((ch) == 9) ? 0xBC : (-1))))))))
+#define DC_RL_CH(ch, evt)	IPU_DC_REG(_RL_CH_2_OFFSET(ch) + \
+					   ((evt) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+#define DC_EVEN_UGDE0 		12
+#define DC_ODD_UGDE0 		13
+#define DC_EVEN_UGDE1 		14
+#define DC_ODD_UGDE1 		15
+#define DC_EVEN_UGDE2 		16
+#define DC_ODD_UGDE2 		17
+#define DC_EVEN_UGDE3 		18
+#define DC_ODD_UGDE3 		19
+
+#define dc_ch_offset(ch) \
+({ \
+	const u8 _offset[] = { \
+		0, 0x1C, 0x38, 0x54, 0x58, 0x5C, 0x78, 0, 0x94, 0xB4}; \
+	_offset[ch]; \
+})
+#define DC_WR_CH_CONF(ch)	IPU_DC_REG(dc_ch_offset(ch))
+#define DC_WR_CH_ADDR(ch)	IPU_DC_REG(dc_ch_offset(ch) + 4)
+
+#define DC_WR_CH_CONF_1		IPU_DC_REG(0x001C)
+#define DC_WR_CH_ADDR_1		IPU_DC_REG(0x0020)
+#define DC_WR_CH_CONF_5		IPU_DC_REG(0x005C)
+#define DC_WR_CH_ADDR_5		IPU_DC_REG(0x0060)
+#define DC_GEN			IPU_DC_REG(0x00D4)
+#define DC_DISP_CONF1(disp)	IPU_DC_REG(0x00D8 + 4 * (disp))
+#define DC_DISP_CONF2(disp)	IPU_DC_REG(0x00E8 + 4 * (disp))
+#define DC_STAT			IPU_DC_REG(0x01C8)
+#define DC_UGDE_0(evt)		IPU_DC_REG(0x0174 + 16 * (evt))
+#define DC_UGDE_1(evt)		IPU_DC_REG(0x0178 + 16 * (evt))
+#define DC_UGDE_2(evt)		IPU_DC_REG(0x017C + 16 * (evt))
+#define DC_UGDE_3(evt)		IPU_DC_REG(0x0180 + 16 * (evt))
+
+/* IPU DP Registers */
+#define IPU_DP_REG(offset)		(offset)
+
+#define DP_SYNC				0
+#define DP_ASYNC0			0x60
+#define DP_ASYNC1			0xBC
+#define DP_COM_CONF(flow)		IPU_DP_REG(flow)
+#define DP_GRAPH_WIND_CTRL(flow)	IPU_DP_REG(0x0004 + (flow))
+#define DP_FG_POS(flow)			IPU_DP_REG(0x0008 + (flow))
+#define DP_GAMMA_C(flow, i)		IPU_DP_REG(0x0014 + (flow) + 4 * (i))
+#define DP_GAMMA_S(flow, i)		IPU_DP_REG(0x0034 + (flow) + 4 * (i))
+#define DP_CSC_A_0(flow)		IPU_DP_REG(0x0044 + (flow))
+#define DP_CSC_A_1(flow)		IPU_DP_REG(0x0048 + (flow))
+#define DP_CSC_A_2(flow)		IPU_DP_REG(0x004C + (flow))
+#define DP_CSC_A_3(flow)		IPU_DP_REG(0x0050 + (flow))
+#define DP_CSC_0(flow)			IPU_DP_REG(0x0054 + (flow))
+#define DP_CSC_1(flow)			IPU_DP_REG(0x0058 + (flow))
+
+enum {
+	IPU_CONF_CSI0_EN = 0x00000001,
+	IPU_CONF_CSI1_EN = 0x00000002,
+	IPU_CONF_IC_EN = 0x00000004,
+	IPU_CONF_ROT_EN = 0x00000008,
+	IPU_CONF_ISP_EN = 0x00000010,
+	IPU_CONF_DP_EN = 0x00000020,
+	IPU_CONF_DI0_EN = 0x00000040,
+	IPU_CONF_DI1_EN = 0x00000080,
+	IPU_CONF_DMFC_EN = 0x00000400,
+	IPU_CONF_SMFC_EN = 0x00000100,
+	IPU_CONF_DC_EN = 0x00000200,
+	IPU_CONF_VDI_EN = 0x00001000,
+	IPU_CONF_IDMAC_DIS = 0x00400000,
+	IPU_CONF_IC_DMFC_SEL = 0x02000000,
+	IPU_CONF_IC_DMFC_SYNC = 0x04000000,
+	IPU_CONF_VDI_DMFC_SYNC = 0x08000000,
+	IPU_CONF_CSI0_DATA_SOURCE = 0x10000000,
+	IPU_CONF_CSI0_DATA_SOURCE_OFFSET = 28,
+	IPU_CONF_CSI1_DATA_SOURCE = 0x20000000,
+	IPU_CONF_IC_INPUT = 0x40000000,
+	IPU_CONF_CSI_SEL = 0x80000000,
+
+	DI0_COUNTER_RELEASE = 0x01000000,
+	DI1_COUNTER_RELEASE = 0x02000000,
+
+	FS_PRPVF_ROT_SRC_SEL_MASK = 0x00000F00,
+	FS_PRPVF_ROT_SRC_SEL_OFFSET = 8,
+	FS_PRPENC_ROT_SRC_SEL_MASK = 0x0000000F,
+	FS_PRPENC_ROT_SRC_SEL_OFFSET = 0,
+	FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
+	FS_PP_ROT_SRC_SEL_OFFSET = 16,
+	FS_PP_SRC_SEL_MASK = 0x0000F000,
+	FS_PP_SRC_SEL_VDOA = 0x00008000,
+	FS_PP_SRC_SEL_OFFSET = 12,
+	FS_PRP_SRC_SEL_MASK = 0x0F000000,
+	FS_PRP_SRC_SEL_OFFSET = 24,
+	FS_VF_IN_VALID = 0x80000000,
+	FS_ENC_IN_VALID = 0x40000000,
+	FS_VDI_SRC_SEL_MASK = 0x30000000,
+	FS_VDI_SRC_SEL_VDOA = 0x20000000,
+	FS_VDOA_DEST_SEL_MASK = 0x00030000,
+	FS_VDOA_DEST_SEL_VDI = 0x00020000,
+	FS_VDOA_DEST_SEL_IC = 0x00010000,
+	FS_VDI_SRC_SEL_OFFSET = 28,
+
+
+	FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
+	FS_PRPENC_DEST_SEL_OFFSET = 0,
+	FS_PRPVF_DEST_SEL_MASK = 0x000000F0,
+	FS_PRPVF_DEST_SEL_OFFSET = 4,
+	FS_PRPVF_ROT_DEST_SEL_MASK = 0x00000F00,
+	FS_PRPVF_ROT_DEST_SEL_OFFSET = 8,
+	FS_PP_DEST_SEL_MASK = 0x0000F000,
+	FS_PP_DEST_SEL_OFFSET = 12,
+	FS_PP_ROT_DEST_SEL_MASK = 0x000F0000,
+	FS_PP_ROT_DEST_SEL_OFFSET = 16,
+	FS_PRPENC_ROT_DEST_SEL_MASK = 0x00F00000,
+	FS_PRPENC_ROT_DEST_SEL_OFFSET = 20,
+
+	FS_SMFC0_DEST_SEL_MASK = 0x0000000F,
+	FS_SMFC0_DEST_SEL_OFFSET = 0,
+	FS_SMFC1_DEST_SEL_MASK = 0x00000070,
+	FS_SMFC1_DEST_SEL_OFFSET = 4,
+	FS_SMFC2_DEST_SEL_MASK = 0x00000780,
+	FS_SMFC2_DEST_SEL_OFFSET = 7,
+	FS_SMFC3_DEST_SEL_MASK = 0x00003800,
+	FS_SMFC3_DEST_SEL_OFFSET = 11,
+
+	FS_DC1_SRC_SEL_MASK = 0x00F00000,
+	FS_DC1_SRC_SEL_OFFSET = 20,
+	FS_DC2_SRC_SEL_MASK = 0x000F0000,
+	FS_DC2_SRC_SEL_OFFSET = 16,
+	FS_DP_SYNC0_SRC_SEL_MASK = 0x0000000F,
+	FS_DP_SYNC0_SRC_SEL_OFFSET = 0,
+	FS_DP_SYNC1_SRC_SEL_MASK = 0x000000F0,
+	FS_DP_SYNC1_SRC_SEL_OFFSET = 4,
+	FS_DP_ASYNC0_SRC_SEL_MASK = 0x00000F00,
+	FS_DP_ASYNC0_SRC_SEL_OFFSET = 8,
+	FS_DP_ASYNC1_SRC_SEL_MASK = 0x0000F000,
+	FS_DP_ASYNC1_SRC_SEL_OFFSET = 12,
+
+	FS_AUTO_REF_PER_MASK = 0,
+	FS_AUTO_REF_PER_OFFSET = 16,
+
+	TSTAT_VF_MASK = 0x0000000C,
+	TSTAT_VF_OFFSET = 2,
+	TSTAT_VF_ROT_MASK = 0x00000300,
+	TSTAT_VF_ROT_OFFSET = 8,
+	TSTAT_ENC_MASK = 0x00000003,
+	TSTAT_ENC_OFFSET = 0,
+	TSTAT_ENC_ROT_MASK = 0x000000C0,
+	TSTAT_ENC_ROT_OFFSET = 6,
+	TSTAT_PP_MASK = 0x00000030,
+	TSTAT_PP_OFFSET = 4,
+	TSTAT_PP_ROT_MASK = 0x00000C00,
+	TSTAT_PP_ROT_OFFSET = 10,
+
+	TASK_STAT_IDLE = 0,
+	TASK_STAT_ACTIVE = 1,
+	TASK_STAT_WAIT4READY = 2,
+
+	/* IDMAC register bits */
+	IDMAC_CONF_USED_BUFS_EN_R = 0x02000000,
+	IDMAC_CONF_USED_BUFS_MAX_R_MASK = 0x01E00000,
+	IDMAC_CONF_USED_BUFS_MAX_R_OFFSET = 21,
+	IDMAC_CONF_USED_BUFS_EN_W = 0x00100000,
+	IDMAC_CONF_USED_BUFS_MAX_W_MASK = 0x000E0000,
+	IDMAC_CONF_USED_BUFS_MAX_W_OFFSET = 17,
+
+	/* Image Converter Register bits */
+	IC_CONF_PRPENC_EN = 0x00000001,
+	IC_CONF_PRPENC_CSC1 = 0x00000002,
+	IC_CONF_PRPENC_ROT_EN = 0x00000004,
+	IC_CONF_PRPVF_EN = 0x00000100,
+	IC_CONF_PRPVF_CSC1 = 0x00000200,
+	IC_CONF_PRPVF_CSC2 = 0x00000400,
+	IC_CONF_PRPVF_CMB = 0x00000800,
+	IC_CONF_PRPVF_ROT_EN = 0x00001000,
+	IC_CONF_PP_EN = 0x00010000,
+	IC_CONF_PP_CSC1 = 0x00020000,
+	IC_CONF_PP_CSC2 = 0x00040000,
+	IC_CONF_PP_CMB = 0x00080000,
+	IC_CONF_PP_ROT_EN = 0x00100000,
+	IC_CONF_IC_GLB_LOC_A = 0x10000000,
+	IC_CONF_KEY_COLOR_EN = 0x20000000,
+	IC_CONF_RWS_EN = 0x40000000,
+	IC_CONF_CSI_MEM_WR_EN = 0x80000000,
+
+	IC_RSZ_MAX_RESIZE_RATIO = 0x00004000,
+
+	IC_IDMAC_1_CB0_BURST_16 = 0x00000001,
+	IC_IDMAC_1_CB1_BURST_16 = 0x00000002,
+	IC_IDMAC_1_CB2_BURST_16 = 0x00000004,
+	IC_IDMAC_1_CB3_BURST_16 = 0x00000008,
+	IC_IDMAC_1_CB4_BURST_16 = 0x00000010,
+	IC_IDMAC_1_CB5_BURST_16 = 0x00000020,
+	IC_IDMAC_1_CB6_BURST_16 = 0x00000040,
+	IC_IDMAC_1_CB7_BURST_16 = 0x00000080,
+	IC_IDMAC_1_PRPENC_ROT_MASK = 0x00003800,
+	IC_IDMAC_1_PRPENC_ROT_OFFSET = 11,
+	IC_IDMAC_1_PRPVF_ROT_MASK = 0x0001C000,
+	IC_IDMAC_1_PRPVF_ROT_OFFSET = 14,
+	IC_IDMAC_1_PP_ROT_MASK = 0x000E0000,
+	IC_IDMAC_1_PP_ROT_OFFSET = 17,
+	IC_IDMAC_1_PP_FLIP_RS = 0x00400000,
+	IC_IDMAC_1_PRPVF_FLIP_RS = 0x00200000,
+	IC_IDMAC_1_PRPENC_FLIP_RS = 0x00100000,
+
+	IC_IDMAC_2_PRPENC_HEIGHT_MASK = 0x000003FF,
+	IC_IDMAC_2_PRPENC_HEIGHT_OFFSET = 0,
+	IC_IDMAC_2_PRPVF_HEIGHT_MASK = 0x000FFC00,
+	IC_IDMAC_2_PRPVF_HEIGHT_OFFSET = 10,
+	IC_IDMAC_2_PP_HEIGHT_MASK = 0x3FF00000,
+	IC_IDMAC_2_PP_HEIGHT_OFFSET = 20,
+
+	IC_IDMAC_3_PRPENC_WIDTH_MASK = 0x000003FF,
+	IC_IDMAC_3_PRPENC_WIDTH_OFFSET = 0,
+	IC_IDMAC_3_PRPVF_WIDTH_MASK = 0x000FFC00,
+	IC_IDMAC_3_PRPVF_WIDTH_OFFSET = 10,
+	IC_IDMAC_3_PP_WIDTH_MASK = 0x3FF00000,
+	IC_IDMAC_3_PP_WIDTH_OFFSET = 20,
+
+	CSI_SENS_CONF_DATA_FMT_SHIFT = 8,
+	CSI_SENS_CONF_DATA_FMT_MASK = 0x00000700,
+	CSI_SENS_CONF_DATA_FMT_RGB_YUV444 = 0L,
+	CSI_SENS_CONF_DATA_FMT_YUV422_YUYV = 1L,
+	CSI_SENS_CONF_DATA_FMT_YUV422_UYVY = 2L,
+	CSI_SENS_CONF_DATA_FMT_BAYER = 3L,
+	CSI_SENS_CONF_DATA_FMT_RGB565 = 4L,
+	CSI_SENS_CONF_DATA_FMT_RGB555 = 5L,
+	CSI_SENS_CONF_DATA_FMT_RGB444 = 6L,
+	CSI_SENS_CONF_DATA_FMT_JPEG = 7L,
+
+	CSI_SENS_CONF_VSYNC_POL_SHIFT = 0,
+	CSI_SENS_CONF_HSYNC_POL_SHIFT = 1,
+	CSI_SENS_CONF_DATA_POL_SHIFT = 2,
+	CSI_SENS_CONF_PIX_CLK_POL_SHIFT = 3,
+	CSI_SENS_CONF_SENS_PRTCL_MASK = 0x00000070L,
+	CSI_SENS_CONF_SENS_PRTCL_SHIFT = 4,
+	CSI_SENS_CONF_PACK_TIGHT_SHIFT = 7,
+	CSI_SENS_CONF_DATA_WIDTH_SHIFT = 11,
+	CSI_SENS_CONF_EXT_VSYNC_SHIFT = 15,
+	CSI_SENS_CONF_DIVRATIO_SHIFT = 16,
+
+	CSI_SENS_CONF_DIVRATIO_MASK = 0x00FF0000L,
+	CSI_SENS_CONF_DATA_DEST_SHIFT = 24,
+	CSI_SENS_CONF_DATA_DEST_MASK = 0x07000000L,
+	CSI_SENS_CONF_JPEG8_EN_SHIFT = 27,
+	CSI_SENS_CONF_JPEG_EN_SHIFT = 28,
+	CSI_SENS_CONF_FORCE_EOF_SHIFT = 29,
+	CSI_SENS_CONF_DATA_EN_POL_SHIFT = 31,
+
+	CSI_DATA_DEST_ISP = 1L,
+	CSI_DATA_DEST_IC = 2L,
+	CSI_DATA_DEST_IDMAC = 4L,
+
+	CSI_CCIR_ERR_DET_EN = 0x01000000L,
+	CSI_HORI_DOWNSIZE_EN = 0x80000000L,
+	CSI_VERT_DOWNSIZE_EN = 0x40000000L,
+	CSI_TEST_GEN_MODE_EN = 0x01000000L,
+
+	CSI_HSC_MASK = 0x1FFF0000,
+	CSI_HSC_SHIFT = 16,
+	CSI_VSC_MASK = 0x00000FFF,
+	CSI_VSC_SHIFT = 0,
+
+	CSI_TEST_GEN_R_MASK = 0x000000FFL,
+	CSI_TEST_GEN_R_SHIFT = 0,
+	CSI_TEST_GEN_G_MASK = 0x0000FF00L,
+	CSI_TEST_GEN_G_SHIFT = 8,
+	CSI_TEST_GEN_B_MASK = 0x00FF0000L,
+	CSI_TEST_GEN_B_SHIFT = 16,
+
+	CSI_MIPI_DI0_MASK = 0x000000FFL,
+	CSI_MIPI_DI0_SHIFT = 0,
+	CSI_MIPI_DI1_MASK = 0x0000FF00L,
+	CSI_MIPI_DI1_SHIFT = 8,
+	CSI_MIPI_DI2_MASK = 0x00FF0000L,
+	CSI_MIPI_DI2_SHIFT = 16,
+	CSI_MIPI_DI3_MASK = 0xFF000000L,
+	CSI_MIPI_DI3_SHIFT = 24,
+
+	CSI_MAX_RATIO_SKIP_ISP_MASK = 0x00070000L,
+	CSI_MAX_RATIO_SKIP_ISP_SHIFT = 16,
+	CSI_SKIP_ISP_MASK = 0x00F80000L,
+	CSI_SKIP_ISP_SHIFT = 19,
+	CSI_MAX_RATIO_SKIP_SMFC_MASK = 0x00000007L,
+	CSI_MAX_RATIO_SKIP_SMFC_SHIFT = 0,
+	CSI_SKIP_SMFC_MASK = 0x000000F8L,
+	CSI_SKIP_SMFC_SHIFT = 3,
+	CSI_ID_2_SKIP_MASK = 0x00000300L,
+	CSI_ID_2_SKIP_SHIFT = 8,
+
+	CSI_COLOR_FIRST_ROW_MASK = 0x00000002L,
+	CSI_COLOR_FIRST_COMP_MASK = 0x00000001L,
+
+	SMFC_MAP_CH0_MASK = 0x00000007L,
+	SMFC_MAP_CH0_SHIFT = 0,
+	SMFC_MAP_CH1_MASK = 0x00000038L,
+	SMFC_MAP_CH1_SHIFT = 3,
+	SMFC_MAP_CH2_MASK = 0x000001C0L,
+	SMFC_MAP_CH2_SHIFT = 6,
+	SMFC_MAP_CH3_MASK = 0x00000E00L,
+	SMFC_MAP_CH3_SHIFT = 9,
+
+	SMFC_WM0_SET_MASK = 0x00000007L,
+	SMFC_WM0_SET_SHIFT = 0,
+	SMFC_WM1_SET_MASK = 0x000001C0L,
+	SMFC_WM1_SET_SHIFT = 6,
+	SMFC_WM2_SET_MASK = 0x00070000L,
+	SMFC_WM2_SET_SHIFT = 16,
+	SMFC_WM3_SET_MASK = 0x01C00000L,
+	SMFC_WM3_SET_SHIFT = 22,
+
+	SMFC_WM0_CLR_MASK = 0x00000038L,
+	SMFC_WM0_CLR_SHIFT = 3,
+	SMFC_WM1_CLR_MASK = 0x00000E00L,
+	SMFC_WM1_CLR_SHIFT = 9,
+	SMFC_WM2_CLR_MASK = 0x00380000L,
+	SMFC_WM2_CLR_SHIFT = 19,
+	SMFC_WM3_CLR_MASK = 0x0E000000L,
+	SMFC_WM3_CLR_SHIFT = 25,
+
+	SMFC_BS0_MASK = 0x0000000FL,
+	SMFC_BS0_SHIFT = 0,
+	SMFC_BS1_MASK = 0x000000F0L,
+	SMFC_BS1_SHIFT = 4,
+	SMFC_BS2_MASK = 0x00000F00L,
+	SMFC_BS2_SHIFT = 8,
+	SMFC_BS3_MASK = 0x0000F000L,
+	SMFC_BS3_SHIFT = 12,
+
+	PF_CONF_TYPE_MASK = 0x00000007,
+	PF_CONF_TYPE_SHIFT = 0,
+	PF_CONF_PAUSE_EN = 0x00000010,
+	PF_CONF_RESET = 0x00008000,
+	PF_CONF_PAUSE_ROW_MASK = 0x00FF0000,
+	PF_CONF_PAUSE_ROW_SHIFT = 16,
+
+	DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
+	DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
+
+	DI_GEN_DI_CLK_EXT = 0x100000,
+	DI_GEN_POLARITY_DISP_CLK = 0x00020000,
+	DI_GEN_POLARITY_1 = 0x00000001,
+	DI_GEN_POLARITY_2 = 0x00000002,
+	DI_GEN_POLARITY_3 = 0x00000004,
+	DI_GEN_POLARITY_4 = 0x00000008,
+	DI_GEN_POLARITY_5 = 0x00000010,
+	DI_GEN_POLARITY_6 = 0x00000020,
+	DI_GEN_POLARITY_7 = 0x00000040,
+	DI_GEN_POLARITY_8 = 0x00000080,
+
+	DI_POL_DRDY_DATA_POLARITY = 0x00000080,
+	DI_POL_DRDY_POLARITY_15 = 0x00000010,
+
+	DI_VSYNC_SEL_OFFSET = 13,
+
+	DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
+	DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
+	DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
+	DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
+	DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
+	DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
+
+	DC_UGDE_0_ODD_EN = 0x02000000,
+	DC_UGDE_0_ID_CODED_MASK = 0x00000007,
+	DC_UGDE_0_ID_CODED_OFFSET = 0,
+	DC_UGDE_0_EV_PRIORITY_MASK = 0x00000078,
+	DC_UGDE_0_EV_PRIORITY_OFFSET = 3,
+
+	DP_COM_CONF_FG_EN = 0x00000001,
+	DP_COM_CONF_GWSEL = 0x00000002,
+	DP_COM_CONF_GWAM = 0x00000004,
+	DP_COM_CONF_GWCKE = 0x00000008,
+	DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
+	DP_COM_CONF_CSC_DEF_OFFSET = 8,
+	DP_COM_CONF_CSC_DEF_FG = 0x00000300,
+	DP_COM_CONF_CSC_DEF_BG = 0x00000200,
+	DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
+	DP_COM_CONF_GAMMA_EN = 0x00001000,
+	DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
+
+	DI_SER_CONF_LLA_SER_ACCESS = 0x00000020,
+	DI_SER_CONF_SERIAL_CLK_POL = 0x00000010,
+	DI_SER_CONF_SERIAL_DATA_POL = 0x00000008,
+	DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
+	DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
+	DI_SER_CONF_WAIT4SERIAL = 0x00000001,
+
+	VDI_C_CH_420 = 0x00000000,
+	VDI_C_CH_422 = 0x00000002,
+	VDI_C_MOT_SEL_FULL = 0x00000008,
+	VDI_C_MOT_SEL_LOW = 0x00000004,
+	VDI_C_MOT_SEL_MED = 0x00000000,
+	VDI_C_BURST_SIZE1_4 = 0x00000030,
+	VDI_C_BURST_SIZE2_4 = 0x00000300,
+	VDI_C_BURST_SIZE3_4 = 0x00003000,
+	VDI_C_BURST_SIZE_MASK = 0xF,
+	VDI_C_BURST_SIZE1_OFFSET = 4,
+	VDI_C_BURST_SIZE2_OFFSET = 8,
+	VDI_C_BURST_SIZE3_OFFSET = 12,
+	VDI_C_VWM1_SET_1 = 0x00000000,
+	VDI_C_VWM1_SET_2 = 0x00010000,
+	VDI_C_VWM1_CLR_2 = 0x00080000,
+	VDI_C_VWM3_SET_1 = 0x00000000,
+	VDI_C_VWM3_SET_2 = 0x00400000,
+	VDI_C_VWM3_CLR_2 = 0x02000000,
+	VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
+	VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = -1,
+	DI_SYNC_CLK = 0,
+	DI_SYNC_INT_HSYNC = 1,
+	DI_SYNC_HSYNC = 2,
+	DI_SYNC_VSYNC = 3,
+	DI_SYNC_DE = 5,
+};
+
+/* DC template opcodes */
+#define WROD(lf)		(0x18 | ((lf) << 1))
+#define WRG	        	(0x01)
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/pre-regs.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/pre-regs.h
@@ -0,0 +1,480 @@
+/*
+ * Freescale PRE Register Definitions
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ARCH_ARM___PRE_H
+#define __ARCH_ARM___PRE_H
+
+
+#define HW_PRE_CTRL	(0x00000000)
+#define HW_PRE_CTRL_SET	(0x00000004)
+#define HW_PRE_CTRL_CLR	(0x00000008)
+#define HW_PRE_CTRL_TOG	(0x0000000c)
+
+#define BM_PRE_CTRL_SFTRST 0x80000000
+#define BF_PRE_CTRL_SFTRST(v) \
+	(((v) << 31) & BM_PRE_CTRL_SFTRST)
+#define BM_PRE_CTRL_CLKGATE 0x40000000
+#define BF_PRE_CTRL_CLKGATE(v)  \
+	(((v) << 30) & BM_PRE_CTRL_CLKGATE)
+#define BM_PRE_CTRL_TPR_RESET_SEL 0x20000000
+#define BF_PRE_CTRL_TPR_RESET_SEL(v)  \
+	(((v) << 29) & BM_PRE_CTRL_TPR_RESET_SEL)
+#define BM_PRE_CTRL_EN_REPEAT 0x10000000
+#define BF_PRE_CTRL_EN_REPEAT(v)  \
+	(((v) << 28) & BM_PRE_CTRL_EN_REPEAT)
+#define BP_PRE_CTRL_RSVD2      16
+#define BM_PRE_CTRL_RSVD2 0x0FFF0000
+#define BF_PRE_CTRL_RSVD2(v)  \
+	(((v) << 16) & BM_PRE_CTRL_RSVD2)
+#define BP_PRE_CTRL_RSVD1      12
+#define BM_PRE_CTRL_RSVD1 0x0000F000
+#define BF_PRE_CTRL_RSVD1(v)  \
+	(((v) << 12) & BM_PRE_CTRL_RSVD1)
+#define BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN 0x00000800
+#define BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(v)  \
+	(((v) << 11) & BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN)
+#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__1 0x1
+#define BP_PRE_CTRL_HANDSHAKE_LINE_NUM      9
+#define BM_PRE_CTRL_HANDSHAKE_LINE_NUM 0x00000600
+#define BF_PRE_CTRL_HANDSHAKE_LINE_NUM(v)  \
+	(((v) << 9) & BM_PRE_CTRL_HANDSHAKE_LINE_NUM)
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__1 0x1
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__2 0x2
+#define BM_PRE_CTRL_HANDSHAKE_EN 0x00000100
+#define BF_PRE_CTRL_HANDSHAKE_EN(v)  \
+	(((v) << 8) & BM_PRE_CTRL_HANDSHAKE_EN)
+#define BV_PRE_CTRL_HANDSHAKE_EN__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_EN__1 0x1
+#define BM_PRE_CTRL_INTERLACED_FIELD 0x00000080
+#define BF_PRE_CTRL_INTERLACED_FIELD(v)  \
+	(((v) << 7) & BM_PRE_CTRL_INTERLACED_FIELD)
+#define BM_PRE_CTRL_SO 0x00000040
+#define BF_PRE_CTRL_SO(v)  \
+	(((v) << 6) & BM_PRE_CTRL_SO)
+#define BM_PRE_CTRL_VFLIP 0x00000020
+#define BF_PRE_CTRL_VFLIP(v)  \
+	(((v) << 5) & BM_PRE_CTRL_VFLIP)
+#define BM_PRE_CTRL_SDW_UPDATE 0x00000010
+#define BF_PRE_CTRL_SDW_UPDATE(v)  \
+	(((v) << 4) & BM_PRE_CTRL_SDW_UPDATE)
+#define BM_PRE_CTRL_RSVD0 0x00000008
+#define BF_PRE_CTRL_RSVD0(v)  \
+	(((v) << 3) & BM_PRE_CTRL_RSVD0)
+#define BM_PRE_CTRL_BLOCK_16 0x00000004
+#define BF_PRE_CTRL_BLOCK_16(v)  \
+	(((v) << 2) & BM_PRE_CTRL_BLOCK_16)
+#define BV_PRE_CTRL_BLOCK_16__32x4 0x0
+#define BV_PRE_CTRL_BLOCK_16__16x4 0x1
+#define BM_PRE_CTRL_BLOCK_EN 0x00000002
+#define BF_PRE_CTRL_BLOCK_EN(v)  \
+	(((v) << 1) & BM_PRE_CTRL_BLOCK_EN)
+#define BV_PRE_CTRL_BLOCK_EN__0 0x0
+#define BV_PRE_CTRL_BLOCK_EN__1 0x1
+#define BM_PRE_CTRL_ENABLE 0x00000001
+#define BF_PRE_CTRL_ENABLE(v)  \
+	(((v) << 0) & BM_PRE_CTRL_ENABLE)
+
+#define HW_PRE_IRQ_MASK	(0x00000010)
+#define HW_PRE_IRQ_MASK_SET	(0x00000014)
+#define HW_PRE_IRQ_MASK_CLR	(0x00000018)
+#define HW_PRE_IRQ_MASK_TOG	(0x0000001c)
+
+#define BP_PRE_IRQ_MASK_RSVD1      4
+#define BM_PRE_IRQ_MASK_RSVD1 0xFFFFFFF0
+#define BF_PRE_IRQ_MASK_RSVD1(v) \
+	(((v) << 4) & BM_PRE_IRQ_MASK_RSVD1)
+#define BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN 0x00000008
+#define BF_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN(v)  \
+	(((v) << 3) & BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN)
+#define BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN 0x00000004
+#define BF_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN(v)  \
+	(((v) << 2) & BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN)
+#define BM_PRE_IRQ_MASK_STORE_IRQ_EN 0x00000002
+#define BF_PRE_IRQ_MASK_STORE_IRQ_EN(v)  \
+	(((v) << 1) & BM_PRE_IRQ_MASK_STORE_IRQ_EN)
+#define BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN 0x00000001
+#define BF_PRE_IRQ_MASK_PREFETCH_IRQ_EN(v)  \
+	(((v) << 0) & BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN)
+
+#define HW_PRE_IRQ	(0x00000020)
+#define HW_PRE_IRQ_SET	(0x00000024)
+#define HW_PRE_IRQ_CLR	(0x00000028)
+#define HW_PRE_IRQ_TOG	(0x0000002c)
+
+#define BP_PRE_IRQ_RSVD1      14
+#define BM_PRE_IRQ_RSVD1 0xFFFFC000
+#define BF_PRE_IRQ_RSVD1(v) \
+	(((v) << 14) & BM_PRE_IRQ_RSVD1)
+#define BP_PRE_IRQ_AXI_ERROR_ID      10
+#define BM_PRE_IRQ_AXI_ERROR_ID 0x00003C00
+#define BF_PRE_IRQ_AXI_ERROR_ID(v)  \
+	(((v) << 10) & BM_PRE_IRQ_AXI_ERROR_ID)
+#define BM_PRE_IRQ_AXI_READ_ERROR 0x00000200
+#define BF_PRE_IRQ_AXI_READ_ERROR(v)  \
+	(((v) << 9) & BM_PRE_IRQ_AXI_READ_ERROR)
+#define BM_PRE_IRQ_AXI_WRITE_ERROR 0x00000100
+#define BF_PRE_IRQ_AXI_WRITE_ERROR(v)  \
+	(((v) << 8) & BM_PRE_IRQ_AXI_WRITE_ERROR)
+#define BP_PRE_IRQ_RSVD0      5
+#define BM_PRE_IRQ_RSVD0 0x000000E0
+#define BF_PRE_IRQ_RSVD0(v)  \
+	(((v) << 5) & BM_PRE_IRQ_RSVD0)
+#define BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ 0x00000010
+#define BF_PRE_IRQ_HANDSHAKE_ERROR_IRQ(v)  \
+	(((v) << 4) & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ)
+#define BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ 0x00000008
+#define BF_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ(v)  \
+	(((v) << 3) & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ)
+#define BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ 0x00000004
+#define BF_PRE_IRQ_HANDSHAKE_ABORT_IRQ(v)  \
+	(((v) << 2) & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ)
+#define BM_PRE_IRQ_STORE_IRQ 0x00000002
+#define BF_PRE_IRQ_STORE_IRQ(v)  \
+	(((v) << 1) & BM_PRE_IRQ_STORE_IRQ)
+#define BM_PRE_IRQ_PREFETCH_IRQ 0x00000001
+#define BF_PRE_IRQ_PREFETCH_IRQ(v)  \
+	(((v) << 0) & BM_PRE_IRQ_PREFETCH_IRQ)
+
+#define HW_PRE_CUR_BUF	(0x00000030)
+
+#define BP_PRE_CUR_BUF_ADDR      0
+#define BM_PRE_CUR_BUF_ADDR 0xFFFFFFFF
+#define BF_PRE_CUR_BUF_ADDR(v)   (v)
+
+#define HW_PRE_NEXT_BUF	(0x00000040)
+
+#define BP_PRE_NEXT_BUF_ADDR      0
+#define BM_PRE_NEXT_BUF_ADDR 0xFFFFFFFF
+#define BF_PRE_NEXT_BUF_ADDR(v)   (v)
+
+#define HW_PRE_U_BUF_OFFSET	(0x00000050)
+
+#define BP_PRE_U_BUF_OFFSET_RSVD0      25
+#define BM_PRE_U_BUF_OFFSET_RSVD0 0xFE000000
+#define BF_PRE_U_BUF_OFFSET_RSVD0(v) \
+	(((v) << 25) & BM_PRE_U_BUF_OFFSET_RSVD0)
+#define BP_PRE_U_BUF_OFFSET_UBO      0
+#define BM_PRE_U_BUF_OFFSET_UBO 0x01FFFFFF
+#define BF_PRE_U_BUF_OFFSET_UBO(v)  \
+	(((v) << 0) & BM_PRE_U_BUF_OFFSET_UBO)
+
+#define HW_PRE_V_BUF_OFFSET	(0x00000060)
+
+#define BP_PRE_V_BUF_OFFSET_RSVD0      25
+#define BM_PRE_V_BUF_OFFSET_RSVD0 0xFE000000
+#define BF_PRE_V_BUF_OFFSET_RSVD0(v) \
+	(((v) << 25) & BM_PRE_V_BUF_OFFSET_RSVD0)
+#define BP_PRE_V_BUF_OFFSET_VBO      0
+#define BM_PRE_V_BUF_OFFSET_VBO 0x01FFFFFF
+#define BF_PRE_V_BUF_OFFSET_VBO(v)  \
+	(((v) << 0) & BM_PRE_V_BUF_OFFSET_VBO)
+
+#define HW_PRE_TPR_CTRL	(0x00000070)
+#define HW_PRE_TPR_CTRL_SET	(0x00000074)
+#define HW_PRE_TPR_CTRL_CLR	(0x00000078)
+#define HW_PRE_TPR_CTRL_TOG	(0x0000007c)
+
+#define BP_PRE_TPR_CTRL_RSVD      8
+#define BM_PRE_TPR_CTRL_RSVD 0xFFFFFF00
+#define BF_PRE_TPR_CTRL_RSVD(v) \
+	(((v) << 8) & BM_PRE_TPR_CTRL_RSVD)
+#define BP_PRE_TPR_CTRL_TILE_FORMAT      0
+#define BM_PRE_TPR_CTRL_TILE_FORMAT 0x000000FF
+#define BF_PRE_TPR_CTRL_TILE_FORMAT(v)  \
+	(((v) << 0) & BM_PRE_TPR_CTRL_TILE_FORMAT)
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__BYPASS       0x00
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_ST  0x10
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_SRT 0x50
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_ST     0x20
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SRT    0x60
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MST    0xA0
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MSRT   0xE0
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_ST  0x11
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_SRT 0x51
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_ST     0x21
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SRT    0x61
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MST    0xA1
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MSRT   0xE1
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_PRO     0x22
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_SB_INT  0x13
+
+#define HW_PRE_PREFETCH_ENGINE_CTRL	(0x00000080)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_SET	(0x00000084)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_CLR	(0x00000088)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_TOG	(0x0000008c)
+
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD1      16
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD1(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN 0x00008000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(v)  \
+	(((v) << 15) & BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP 0x00004000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP(v)  \
+	(((v) << 14) & BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN 0x00002000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_CROP_EN(v)  \
+	(((v) << 13) & BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__1 0x1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE 0x00001000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(v)  \
+	(((v) << 12) & BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__1 0x1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS 0x00000800
+#define BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(v)  \
+	(((v) << 11) & BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__1 0x1
+#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT      8
+#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 0x00000700
+#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(v)  \
+	(((v) << 8) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__1 0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__2 0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__3 0x3
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__4 0x4
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__5 0x5
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD0      6
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0 0x000000C0
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD0(v)  \
+	(((v) << 6) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP      4
+#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 0x00000030
+#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(v)  \
+	(((v) << 4) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__3 0x3
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES      1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 0x0000000E
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(v)  \
+	(((v) << 1) & BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__8_bytes   0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__16_bytes  0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__32_bytes  0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__64_bytes  0x3
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__128_bytes 0x4
+#define BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN 0x00000001
+#define BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__1 0x1
+
+#define HW_PRE_PREFETCH_ENGINE_STATUS	(0x00000090)
+
+#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y      16
+#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 0x3FFF0000
+#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y)
+#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X      0
+#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X)
+
+#define HW_PRE_PREFETCH_ENGINE_INPUT_SIZE	(0x000000a0)
+
+#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT      16
+#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT)
+#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH      0
+#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH)
+
+#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC	(0x000000b0)
+
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y      16
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y)
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X      0
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X)
+
+#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC	(0x000000c0)
+
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y      16
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y)
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X      0
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X)
+
+#define HW_PRE_PREFETCH_ENGINE_PITCH	(0x000000d0)
+
+#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH      16
+#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH)
+#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH      0
+#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH)
+
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET	(0x000000e0)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_SET	(0x000000e4)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_CLR	(0x000000e8)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_TOG	(0x000000ec)
+
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0      29
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 0xE0000000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0(v) \
+	(((v) << 29) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3      24
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 0x1F000000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3(v)  \
+	(((v) << 24) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1      21
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 0x00E00000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1(v)  \
+	(((v) << 21) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2      16
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 0x001F0000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2(v)  \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2      13
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 0x0000E000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2(v)  \
+	(((v) << 13) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1      8
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 0x00001F00
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1(v)  \
+	(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3      5
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 0x000000E0
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3(v)  \
+	(((v) << 5) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0      0
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0x0000001F
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0)
+
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH	(0x000000f0)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_SET	(0x000000f4)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_CLR	(0x000000f8)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_TOG	(0x000000fc)
+
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0      16
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0(v) \
+	(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3      12
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 0x0000F000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3(v)  \
+	(((v) << 12) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2      8
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 0x00000F00
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2(v)  \
+	(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1      4
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 0x000000F0
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1(v)  \
+	(((v) << 4) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0      0
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0x0000000F
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0)
+
+#define HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET	(0x00000100)
+
+#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0      23
+#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 0xFF800000
+#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0(v) \
+	(((v) << 23) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET      0
+#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0xFFFFFFFF
+#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(v)  \
+	(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET)
+
+#define HW_PRE_STORE_ENGINE_CTRL	(0x00000110)
+#define HW_PRE_STORE_ENGINE_CTRL_SET	(0x00000114)
+#define HW_PRE_STORE_ENGINE_CTRL_CLR	(0x00000118)
+#define HW_PRE_STORE_ENGINE_CTRL_TOG	(0x0000011c)
+
+#define BP_PRE_STORE_ENGINE_CTRL_RSVD0      6
+#define BM_PRE_STORE_ENGINE_CTRL_RSVD0 0xFFFFFFC0
+#define BF_PRE_STORE_ENGINE_CTRL_RSVD0(v) \
+	(((v) << 6) & BM_PRE_STORE_ENGINE_CTRL_RSVD0)
+#define BP_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP      4
+#define BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 0x00000030
+#define BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(v)  \
+	(((v) << 4) & BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP)
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__8_bits  0x0
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__16_bits 0x1
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__32_bits 0x2
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__64_bits 0x3
+#define BP_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES      1
+#define BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 0x0000000E
+#define BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(v)  \
+	(((v) << 1) & BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES)
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__8_bytes   0x0
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__16_bytes  0x1
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__32_bytes  0x2
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__64_bytes  0x3
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__128_bytes 0x4
+#define BM_PRE_STORE_ENGINE_CTRL_STORE_EN 0x00000001
+#define BF_PRE_STORE_ENGINE_CTRL_STORE_EN(v)  \
+	(((v) << 0) & BM_PRE_STORE_ENGINE_CTRL_STORE_EN)
+#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__0 0x0
+#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__1 0x1
+
+#define HW_PRE_STORE_ENGINE_STATUS	(0x00000120)
+
+#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y      16
+#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 0x3FFF0000
+#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y(v) \
+	(((v) << 16) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y)
+#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X      0
+#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X(v)  \
+	(((v) << 0) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X)
+
+#define HW_PRE_STORE_ENGINE_SIZE	(0x00000130)
+
+#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT      16
+#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(v) \
+	(((v) << 16) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT)
+#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH      0
+#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(v)  \
+	(((v) << 0) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH)
+
+#define HW_PRE_STORE_ENGINE_PITCH	(0x00000140)
+
+#define BP_PRE_STORE_ENGINE_PITCH_RSVD0      16
+#define BM_PRE_STORE_ENGINE_PITCH_RSVD0 0xFFFF0000
+#define BF_PRE_STORE_ENGINE_PITCH_RSVD0(v) \
+	(((v) << 16) & BM_PRE_STORE_ENGINE_PITCH_RSVD0)
+#define BP_PRE_STORE_ENGINE_PITCH_OUT_PITCH      0
+#define BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(v)  \
+	(((v) << 0) & BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH)
+
+#define HW_PRE_STORE_ENGINE_ADDR	(0x00000150)
+
+#define BP_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR      0
+#define BM_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0xFFFFFFFF
+#define BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(v)   (v)
+#endif /* __ARCH_ARM___PRE_H */
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/pre.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/pre.c
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/ipu-v3-pre.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pre-regs.h"
+
+struct ipu_pre_data {
+	unsigned int id;
+	struct device *dev;
+	void __iomem *base;
+	struct clk *clk;
+
+	struct mutex mutex;	/* for in_use */
+	spinlock_t lock;	/* for register access */
+
+	struct list_head list;
+
+	struct gen_pool *iram_pool;
+	unsigned long double_buffer_size;
+	unsigned long double_buffer_base;
+	unsigned long double_buffer_paddr;
+
+	bool in_use;
+	bool enabled;
+};
+
+static LIST_HEAD(pre_list);
+static DEFINE_SPINLOCK(pre_list_lock);
+
+static inline void pre_write(struct ipu_pre_data *pre,
+			u32 value, unsigned int offset)
+{
+	writel(value, pre->base + offset);
+}
+
+static inline u32 pre_read(struct ipu_pre_data *pre, unsigned offset)
+{
+	return readl(pre->base + offset);
+}
+
+static struct ipu_pre_data *get_pre(unsigned int id)
+{
+	struct ipu_pre_data *pre;
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&pre_list_lock, lock_flags);
+	list_for_each_entry(pre, &pre_list, list) {
+		if (pre->id == id) {
+			spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+			return pre;
+		}
+	}
+	spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+	return NULL;
+}
+
+int ipu_pre_alloc(int ipu_id, ipu_channel_t channel)
+{
+	struct ipu_pre_data *pre;
+	int i, fixed;
+
+	if (channel == MEM_BG_SYNC) {
+		fixed = ipu_id ? 3 : 0;
+		pre = get_pre(fixed);
+		if (pre) {
+			mutex_lock(&pre->mutex);
+			if (!pre->in_use) {
+				pre->in_use = true;
+				mutex_unlock(&pre->mutex);
+				return pre->id;
+			}
+			mutex_unlock(&pre->mutex);
+		}
+		return pre ? -EBUSY : -ENOENT;
+	}
+
+	for (i = 1; i < 3; i++) {
+		pre = get_pre(i);
+		if (!pre)
+			continue;
+		mutex_lock(&pre->mutex);
+		if (!pre->in_use) {
+			pre->in_use = true;
+			mutex_unlock(&pre->mutex);
+			return pre->id;
+		}
+		mutex_unlock(&pre->mutex);
+	}
+
+	return pre ? -EBUSY : -ENOENT;
+}
+EXPORT_SYMBOL(ipu_pre_alloc);
+
+void ipu_pre_free(unsigned int *id)
+{
+	struct ipu_pre_data *pre;
+
+	pre = get_pre(*id);
+	if (!pre)
+		return;
+
+	mutex_lock(&pre->mutex);
+	pre->in_use = false;
+	mutex_unlock(&pre->mutex);
+
+	*id = -1;
+}
+EXPORT_SYMBOL(ipu_pre_free);
+
+unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+
+	if (!pre)
+		return -ENOENT;
+
+	if (!size)
+		return -EINVAL;
+
+	pre->double_buffer_base = gen_pool_alloc(pre->iram_pool, size);
+	if (!pre->double_buffer_base) {
+		dev_err(pre->dev, "double buffer allocate failed\n");
+		return -ENOMEM;
+	}
+	pre->double_buffer_size = size;
+
+	pre->double_buffer_paddr = gen_pool_virt_to_phys(pre->iram_pool,
+							 pre->double_buffer_base);
+
+	return pre->double_buffer_paddr;
+}
+EXPORT_SYMBOL(ipu_pre_alloc_double_buffer);
+
+void ipu_pre_free_double_buffer(unsigned int id)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+
+	if (!pre)
+		return;
+
+	if (pre->double_buffer_base) {
+		gen_pool_free(pre->iram_pool,
+			      pre->double_buffer_base,
+			      pre->double_buffer_size);
+		pre->double_buffer_base  = 0;
+		pre->double_buffer_size  = 0;
+		pre->double_buffer_paddr = 0;
+	}
+}
+EXPORT_SYMBOL(ipu_pre_free_double_buffer);
+
+/* PRE register configurations */
+int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+	int ret = 0;
+
+	if (!pre)
+		return -EINVAL;
+
+	if (!pre->enabled)
+		clk_prepare_enable(pre->clk);
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, BF_PRE_CTRL_TPR_RESET_SEL(1), HW_PRE_CTRL_SET);
+
+	if (config->repeat)
+		pre_write(pre, BF_PRE_CTRL_EN_REPEAT(1), HW_PRE_CTRL_SET);
+	else
+		pre_write(pre, BM_PRE_CTRL_EN_REPEAT, HW_PRE_CTRL_CLR);
+
+	if (config->vflip)
+		pre_write(pre, BF_PRE_CTRL_VFLIP(1), HW_PRE_CTRL_SET);
+	else
+		pre_write(pre, BM_PRE_CTRL_VFLIP, HW_PRE_CTRL_CLR);
+
+	if (config->handshake_en) {
+		pre_write(pre, BF_PRE_CTRL_HANDSHAKE_EN(1), HW_PRE_CTRL_SET);
+		if (config->hsk_abort_en)
+			pre_write(pre, BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(1),
+				  HW_PRE_CTRL_SET);
+		else
+			pre_write(pre, BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN,
+				  HW_PRE_CTRL_CLR);
+
+		switch (config->hsk_line_num) {
+		case 0 /* 4 lines */:
+			pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+				  HW_PRE_CTRL_CLR);
+			break;
+		case 1 /* 8 lines */:
+			pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+				  HW_PRE_CTRL_CLR);
+			pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(1),
+				  HW_PRE_CTRL_SET);
+			break;
+		case 2 /* 16 lines */:
+			pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+				  HW_PRE_CTRL_CLR);
+			pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(2),
+				  HW_PRE_CTRL_SET);
+			break;
+		default:
+			dev_err(pre->dev, "invalid hanshake line number\n");
+			ret = -EINVAL;
+			goto err;
+		}
+	} else
+		pre_write(pre, BM_PRE_CTRL_HANDSHAKE_EN, HW_PRE_CTRL_CLR);
+
+
+	switch (config->prefetch_mode) {
+	case 0:
+		pre_write(pre, BM_PRE_CTRL_BLOCK_EN, HW_PRE_CTRL_CLR);
+		break;
+	case 1:
+		pre_write(pre, BF_PRE_CTRL_BLOCK_EN(1), HW_PRE_CTRL_SET);
+		switch (config->block_size) {
+		case 0:
+			pre_write(pre, BM_PRE_CTRL_BLOCK_16, HW_PRE_CTRL_CLR);
+			break;
+		case 1:
+			pre_write(pre, BF_PRE_CTRL_BLOCK_16(1), HW_PRE_CTRL_SET);
+			break;
+		default:
+			dev_err(pre->dev, "invalid block size for pre\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		break;
+	default:
+		dev_err(pre->dev, "invalid prefech mode for pre\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	switch (config->interlaced) {
+	case 0: /* progressive mode */
+		pre_write(pre, BM_PRE_CTRL_SO, HW_PRE_CTRL_CLR);
+		break;
+	case 2: /* interlaced mode: Pal */
+		pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
+		pre_write(pre, BM_PRE_CTRL_INTERLACED_FIELD, HW_PRE_CTRL_CLR);
+		break;
+	case 3: /* interlaced mode: NTSC */
+		pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
+		pre_write(pre, BF_PRE_CTRL_INTERLACED_FIELD(1), HW_PRE_CTRL_SET);
+		break;
+	default:
+		dev_err(pre->dev, "invalid interlaced or progressive mode\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (config->sdw_update)
+		pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+	else
+		pre_write(pre, BM_PRE_CTRL_SDW_UPDATE, HW_PRE_CTRL_CLR);
+
+err:
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	if (!pre->enabled)
+		clk_disable_unprepare(pre->clk);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_pre_set_ctrl);
+
+static void ipu_pre_irq_mask(struct ipu_pre_data *pre,
+			     unsigned long mask, bool clear)
+{
+	if (clear) {
+		pre_write(pre, mask & 0x1f, HW_PRE_IRQ_MASK_CLR);
+		return;
+	}
+	pre_write(pre, mask & 0x1f, HW_PRE_IRQ_MASK_SET);
+}
+
+static int ipu_pre_buf_set(unsigned int id, unsigned long cur_buf,
+			   unsigned long next_buf)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, cur_buf, HW_PRE_CUR_BUF);
+	pre_write(pre, next_buf, HW_PRE_NEXT_BUF);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+
+static int ipu_pre_plane_buf_off_set(unsigned int id,
+				     unsigned long sec_buf_off,
+				     unsigned long trd_buf_off)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre || sec_buf_off & BM_PRE_U_BUF_OFFSET_RSVD0 ||
+	    trd_buf_off & BM_PRE_V_BUF_OFFSET_RSVD0)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
+	pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+
+static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+	unsigned int tpr_ctrl, fmt;
+
+	if (!pre)
+		return -EINVAL;
+
+	switch (tile_fmt) {
+	case 0x0: /* Bypass */
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x0);
+		break;
+	case IPU_PIX_FMT_GPU32_SB_ST:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x10);
+		break;
+	case IPU_PIX_FMT_GPU16_SB_ST:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x11);
+		break;
+	case IPU_PIX_FMT_GPU32_ST:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x20);
+		break;
+	case IPU_PIX_FMT_GPU16_ST:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x21);
+		break;
+	case IPU_PIX_FMT_GPU32_SB_SRT:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x50);
+		break;
+	case IPU_PIX_FMT_GPU16_SB_SRT:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x51);
+		break;
+	case IPU_PIX_FMT_GPU32_SRT:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x60);
+		break;
+	case IPU_PIX_FMT_GPU16_SRT:
+		fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x61);
+		break;
+	default:
+		dev_err(pre->dev, "invalid tile fmt for pre\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	tpr_ctrl = pre_read(pre, HW_PRE_TPR_CTRL);
+	tpr_ctrl &= ~BM_PRE_TPR_CTRL_TILE_FORMAT;
+	tpr_ctrl |= fmt;
+	pre_write(pre, tpr_ctrl, HW_PRE_TPR_CTRL);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+
+static int ipu_pre_set_shift(int id, unsigned int offset, unsigned int width)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, offset, HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET);
+	pre_write(pre, width,  HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+
+static int ipu_pre_prefetch(unsigned int id,
+			    unsigned int read_burst,
+			    unsigned int input_bpp,
+			    unsigned int input_pixel_fmt,
+			    bool shift_bypass,
+			    bool field_inverse,
+			    bool tpr_coor_offset_en,
+			    struct ipu_rect output_size,
+			    unsigned int input_width,
+			    unsigned int input_height,
+			    unsigned int input_active_width,
+			    unsigned int interlaced,
+			    int interlace_offset)
+{
+	unsigned int prefetch_ctrl = 0;
+	unsigned int input_y_pitch = 0, input_uv_pitch = 0;
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(1);
+	switch (read_burst) {
+	case 0x0:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x0);
+		break;
+	case 0x1:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x1);
+		break;
+	case 0x2:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x2);
+		break;
+	case 0x3:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x3);
+		break;
+	case 0x4:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x4);
+		break;
+	default:
+		spin_unlock_irqrestore(&pre->lock, lock_flags);
+		dev_err(pre->dev, "invalid read burst for prefetch engine\n");
+		return -EINVAL;
+	}
+
+	switch (input_bpp) {
+	case 8:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x0);
+		break;
+	case 16:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x1);
+		break;
+	case 32:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x2);
+		break;
+	case 64:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x3);
+		break;
+	default:
+		spin_unlock_irqrestore(&pre->lock, lock_flags);
+		dev_err(pre->dev, "invalid input bpp for prefetch engine\n");
+		return -EINVAL;
+	}
+
+	switch (input_pixel_fmt) {
+	case 0x1: /* tile */
+	case 0x0: /* generic data */
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGRA4444:
+	case IPU_PIX_FMT_BGRA5551:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_GBR24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_AYUV:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x0);
+		input_y_pitch = input_width * (input_bpp >> 3);
+		if (interlaced && input_pixel_fmt != 0x1)
+			input_y_pitch *= 2;
+		break;
+	case IPU_PIX_FMT_YUV444P:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x1);
+		input_y_pitch  = input_width;
+		input_uv_pitch = input_width;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU422P:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x2);
+		input_y_pitch  = input_width;
+		input_uv_pitch = input_width >> 1;
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x3);
+		input_y_pitch  = input_width;
+		input_uv_pitch = input_width >> 1;
+		break;
+	case PRE_PIX_FMT_NV61:
+		prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
+		/* fall-through */
+	case IPU_PIX_FMT_NV16:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x4);
+		input_y_pitch  = input_width;
+		input_uv_pitch = input_width;
+		break;
+	case PRE_PIX_FMT_NV21:
+		prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
+		/* fall-through */
+	case IPU_PIX_FMT_NV12:
+		prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x5);
+		input_y_pitch  = input_width;
+		input_uv_pitch = input_width;
+		break;
+	default:
+		spin_unlock_irqrestore(&pre->lock, lock_flags);
+		dev_err(pre->dev, "invalid input pixel format for prefetch engine\n");
+		return -EINVAL;
+	}
+
+	prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(shift_bypass ? 1 : 0);
+	prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(field_inverse ? 1 : 0);
+	prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(tpr_coor_offset_en ? 1 : 0);
+
+	pre_write(pre, BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(input_active_width) |
+		  BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(input_height),
+		  HW_PRE_PREFETCH_ENGINE_INPUT_SIZE);
+
+	if (tpr_coor_offset_en)
+		pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(output_size.left) |
+			     BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(output_size.top),
+			     HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
+
+	pre_write(pre, BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(input_y_pitch) |
+		     BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(input_uv_pitch),
+		     HW_PRE_PREFETCH_ENGINE_PITCH);
+
+	pre_write(pre, BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(interlace_offset), HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET);
+
+	pre_write(pre, prefetch_ctrl, HW_PRE_PREFETCH_ENGINE_CTRL);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+
+static int ipu_pre_store(unsigned int id,
+			 bool store_en,
+			 unsigned int write_burst,
+			 unsigned int output_bpp,
+			 /* this means the output
+			  * width by prefetch
+			  */
+			 unsigned int input_width,
+			 unsigned int input_height,
+			 unsigned int out_pitch,
+			 unsigned int output_addr)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned int store_ctrl = 0;
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_STORE_EN(store_en ? 1 : 0);
+
+	if (store_en) {
+		switch (write_burst) {
+		case 0x0:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x0);
+			break;
+		case 0x1:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x1);
+			break;
+		case 0x2:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x2);
+			break;
+		case 0x3:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x3);
+			break;
+		case 0x4:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x4);
+			break;
+		default:
+			spin_unlock_irqrestore(&pre->lock, lock_flags);
+			dev_err(pre->dev, "invalid write burst value for store engine\n");
+			return -EINVAL;
+		}
+
+		switch (output_bpp) {
+		case 8:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x0);
+			break;
+		case 16:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x1);
+			break;
+		case 32:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x2);
+			break;
+		case 64:
+			store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x3);
+			break;
+		default:
+			spin_unlock_irqrestore(&pre->lock, lock_flags);
+			dev_err(pre->dev, "invalid ouput bpp for store engine\n");
+			return -EINVAL;
+		}
+
+		pre_write(pre, BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(input_width) |
+			     BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(input_height),
+			     HW_PRE_STORE_ENGINE_SIZE);
+
+		pre_write(pre, BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(out_pitch),
+			     HW_PRE_STORE_ENGINE_PITCH);
+
+		pre_write(pre, BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(output_addr),
+			     HW_PRE_STORE_ENGINE_ADDR);
+	}
+
+	pre_write(pre, store_ctrl, HW_PRE_STORE_ENGINE_CTRL);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+/* End */
+
+static irqreturn_t ipu_pre_irq_handle(int irq, void *dev_id)
+{
+	struct ipu_pre_data *pre = dev_id;
+	unsigned int irq_stat, axi_id = 0;
+
+	spin_lock(&pre->lock);
+	irq_stat = pre_read(pre, HW_PRE_IRQ);
+
+	if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ) {
+		dev_warn(pre->dev, "handshake abort\n");
+		pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ, HW_PRE_IRQ_CLR);
+	}
+
+	if (irq_stat & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ) {
+		dev_warn(pre->dev, "tpr read num bytes overflow\n");
+		pre_write(pre, BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ,
+				HW_PRE_IRQ_CLR);
+	}
+
+	if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ) {
+		dev_warn(pre->dev, "handshake error\n");
+		pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, HW_PRE_IRQ_CLR);
+	}
+
+	axi_id = (irq_stat & BM_PRE_IRQ_AXI_ERROR_ID) >>
+					BP_PRE_IRQ_AXI_ERROR_ID;
+	if (irq_stat & BM_PRE_IRQ_AXI_WRITE_ERROR) {
+		dev_warn(pre->dev, "AXI%d write error\n", axi_id);
+		pre_write(pre, BM_PRE_IRQ_AXI_WRITE_ERROR, HW_PRE_IRQ_CLR);
+	}
+
+	if (irq_stat & BM_PRE_IRQ_AXI_READ_ERROR) {
+		dev_warn(pre->dev, "AXI%d read error\n", axi_id);
+		pre_write(pre, BM_PRE_IRQ_AXI_READ_ERROR, HW_PRE_IRQ_CLR);
+	}
+	spin_unlock(&pre->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void ipu_pre_out_of_reset(unsigned int id)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
+		  HW_PRE_CTRL_CLR);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+}
+
+int ipu_pre_config(int id, struct ipu_pre_context *config)
+{
+	int ret = 0;
+	struct ipu_pre_data *pre = get_pre(id);
+
+	if (!config || !pre)
+		return -EINVAL;
+
+	config->store_addr = pre->double_buffer_paddr;
+
+	if (!pre->enabled)
+		clk_prepare_enable(pre->clk);
+
+	ipu_pre_out_of_reset(id);
+
+	ret = ipu_pre_plane_buf_off_set(id, config->sec_buf_off,
+					config->trd_buf_off);
+	if (ret < 0)
+		goto out;
+
+	ret = ipu_pre_tpr_set(id, config->tile_fmt);
+	if (ret < 0)
+		goto out;
+
+	ret = ipu_pre_buf_set(id, config->cur_buf, config->next_buf);
+	if (ret < 0)
+		goto out;
+
+	ret = ipu_pre_set_shift(id, config->prefetch_shift_offset,
+				config->prefetch_shift_width);
+	if (ret < 0)
+		goto out;
+
+	ret = ipu_pre_prefetch(id, config->read_burst, config->prefetch_input_bpp,
+			config->prefetch_input_pixel_fmt, config->shift_bypass,
+			config->field_inverse, config->tpr_coor_offset_en,
+			config->prefetch_output_size, config->prefetch_input_width,
+			config->prefetch_input_height,
+			config->prefetch_input_active_width,
+			config->interlaced,
+			config->interlace_offset);
+	if (ret < 0)
+		goto out;
+
+	ret = ipu_pre_store(id, config->store_en,
+			config->write_burst, config->store_output_bpp,
+			config->prefetch_output_size.width, config->prefetch_output_size.height,
+			config->store_pitch,
+			config->store_addr);
+	if (ret < 0)
+		goto out;
+
+	ipu_pre_irq_mask(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ |
+			      BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ |
+			      BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, false);
+out:
+	if (!pre->enabled)
+		clk_disable_unprepare(pre->clk);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_pre_config);
+
+int ipu_pre_enable(int id)
+{
+	int ret = 0;
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	if (pre->enabled)
+		return 0;
+
+	clk_prepare_enable(pre->clk);
+
+	/* start the pre engine */
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_SET);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	pre->enabled = true;
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_pre_enable);
+
+int ipu_pre_sdw_update(int id)
+{
+	int ret = 0;
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return -EINVAL;
+
+	if (!pre->enabled)
+		clk_prepare_enable(pre->clk);
+
+	/* start the pre engine */
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	if (!pre->enabled)
+		clk_disable_unprepare(pre->clk);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_pre_sdw_update);
+
+void ipu_pre_disable(int id)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned long lock_flags;
+
+	if (!pre)
+		return;
+
+	if (!pre->enabled)
+		return;
+
+	/* stop the pre engine */
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_CLR);
+	pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+	pre_write(pre, BF_PRE_CTRL_SFTRST(1), HW_PRE_CTRL_SET);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	clk_disable_unprepare(pre->clk);
+
+	pre->enabled = false;
+}
+EXPORT_SYMBOL(ipu_pre_disable);
+
+int ipu_pre_set_fb_buffer(int id, bool resolve,
+			  unsigned long fb_paddr,
+			  unsigned int y_res,
+			  unsigned int x_crop,
+			  unsigned int y_crop,
+			  unsigned int sec_buf_off,
+			  unsigned int trd_buf_off)
+{
+	struct ipu_pre_data *pre = get_pre(id);
+	unsigned int store_stat, store_block_y;
+	unsigned long lock_flags;
+	bool update = true;
+
+	if (!pre)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pre->lock, lock_flags);
+	pre_write(pre, fb_paddr, HW_PRE_NEXT_BUF);
+	pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
+	pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
+	pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(x_crop) |
+		       BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(y_crop),
+		  HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
+
+	/*
+	 * Update shadow only when store engine runs out of the problematic
+	 * window to workaround the SoC design bug recorded by errata ERR009624.
+	 */
+	if (y_res > IPU_PRE_SMALL_LINE) {
+		unsigned long timeout = jiffies + msecs_to_jiffies(20);
+
+		do {
+			if (time_after(jiffies, timeout)) {
+				update = false;
+				dev_warn(pre->dev, "timeout waiting for PRE "
+					"to run out of problematic window for "
+					"shadow update\n");
+				break;
+			}
+
+			store_stat = pre_read(pre, HW_PRE_STORE_ENGINE_STATUS);
+			store_block_y = (store_stat &
+				BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y) >>
+				BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y;
+		} while (store_block_y >=
+			 (resolve ? DIV_ROUND_UP(y_res, 4) - 1 : y_res - 2) ||
+			  store_block_y == 0);
+	}
+
+	if (update)
+		pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+	spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_pre_set_fb_buffer);
+
+static int ipu_pre_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct ipu_pre_data *pre;
+	struct resource *res;
+	unsigned long lock_flags;
+	int id, irq, err;
+
+	pre = devm_kzalloc(&pdev->dev, sizeof(*pre), GFP_KERNEL);
+	if (!pre)
+		return -ENOMEM;
+	pre->dev = &pdev->dev;
+
+	id = of_alias_get_id(np, "pre");
+	if (id < 0) {
+		dev_err(&pdev->dev, "failed to get PRE id\n");
+		return id;
+	}
+	pre->id = id;
+
+	mutex_init(&pre->mutex);
+	spin_lock_init(&pre->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pre->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pre->base))
+		return PTR_ERR(pre->base);
+
+	pre->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pre->clk)) {
+		dev_err(&pdev->dev, "failed to get the pre clk\n");
+		return PTR_ERR(pre->clk);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	err = devm_request_irq(&pdev->dev, irq, ipu_pre_irq_handle,
+			       IRQF_TRIGGER_RISING, pdev->name, pre);
+	if (err) {
+		dev_err(&pdev->dev, "failed to request pre irq\n");
+		return err;
+	}
+
+	pre->iram_pool = of_gen_pool_get(pdev->dev.of_node, "ocram", 0);
+	if (!pre->iram_pool) {
+		dev_err(&pdev->dev, "no iram exist for pre\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&pre_list_lock, lock_flags);
+	list_add_tail(&pre->list, &pre_list);
+	spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+	ipu_pre_alloc_double_buffer(pre->id, IPU_PRE_MAX_WIDTH * 8 * IPU_PRE_MAX_BPP);
+
+	/* PRE GATE ON */
+	clk_prepare_enable(pre->clk);
+	pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
+		  HW_PRE_CTRL_CLR);
+	pre_write(pre, 0xf, HW_PRE_IRQ_MASK);
+	clk_disable_unprepare(pre->clk);
+
+	platform_set_drvdata(pdev, pre);
+
+	dev_info(&pdev->dev, "driver probed\n");
+
+	return 0;
+}
+
+static int ipu_pre_remove(struct platform_device *pdev)
+{
+	struct ipu_pre_data *pre = platform_get_drvdata(pdev);
+	unsigned long lock_flags;
+
+	if (pre->iram_pool && pre->double_buffer_base) {
+		gen_pool_free(pre->iram_pool,
+			      pre->double_buffer_base,
+			      pre->double_buffer_size);
+	}
+
+	spin_lock_irqsave(&pre_list_lock, lock_flags);
+	list_del(&pre->list);
+	spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+	return 0;
+}
+
+static const struct of_device_id imx_ipu_pre_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-pre", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_pre_dt_ids);
+
+static struct platform_driver ipu_pre_driver = {
+	.driver = {
+			.name = "imx-pre",
+			.of_match_table = of_match_ptr(imx_ipu_pre_dt_ids),
+		  },
+	.probe  = ipu_pre_probe,
+	.remove = ipu_pre_remove,
+};
+
+static int __init ipu_pre_init(void)
+{
+	return platform_driver_register(&ipu_pre_driver);
+}
+subsys_initcall(ipu_pre_init);
+
+static void __exit ipu_pre_exit(void)
+{
+	platform_driver_unregister(&ipu_pre_driver);
+}
+module_exit(ipu_pre_exit);
+
+MODULE_DESCRIPTION("i.MX PRE driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/prg-regs.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/prg-regs.h
@@ -0,0 +1,70 @@
+/*
+ * Freescale IPU PRG Register Definitions
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/bitops.h>
+
+#ifndef __IPU_PRG_H__
+#define __IPU_PRG_H__
+
+#define IPU_PR_CTRL		 0x00
+#define IPU_PR_STATUS		 0x04
+#define IPU_PR_QOS		 0x08
+#define IPU_PR_REG_UPDATE	 0x0c
+#define IPU_PR_STRIDE(ch)	(0x10 + (ch) * 4)
+#define IPU_PR_CROP_LINE	 0x1c
+#define IPU_PR_ADDR_THD		 0x20
+#define IPU_PR_CH_BADDR(ch)	(0x24 + (ch) * 4)
+#define IPU_PR_CH_OFFSET(ch)	(0x30 + (ch) * 4)
+#define IPU_PR_CH_ILO(ch)	(0x3c + (ch) * 4)
+#define IPU_PR_CH_HEIGHT(ch)	(0x48 + (ch) * 4)
+
+#define IPU_PR_CTRL_CH_BYPASS(ch)		(0x1 << (ch))
+#define IPU_PR_CTRL_SOFT_CH_ARID(ch, n)		((n) << ((ch) * 2 + 8))
+#define IPU_PR_CTRL_SOFT_CH_ARID_MASK(ch)	(0x3 << ((ch) * 2 + 8))
+#define IPU_PR_CTRL_CH_SO(ch, interlace)	((interlace) << ((ch) + 16))
+#define IPU_PR_CTRL_CH_SO_MASK(ch)		(0x1 << ((ch) + 16))
+#define IPU_PR_CTRL_CH_VFLIP(ch, vflip)		((vflip) << ((ch) + 19))
+#define IPU_PR_CTRL_CH_VFLIP_MASK(ch)		(0x1 << ((ch) + 19))
+#define IPU_PR_CTRL_CH_BLOCK_MODE(ch, mode)	((mode) << ((ch) + 22))
+#define IPU_PR_CTRL_CH_BLOCK_MODE_MASK(ch)	(0x1 << ((ch) + 22))
+#define IPU_PR_CTRL_CH_CNT_LOAD_EN(ch)		(0x1 << ((ch) + 25))
+#define IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK		(0x7 << 25)
+#define IPU_PR_CTRL_SOFTRST			BIT(30)
+#define IPU_PR_CTRL_SHADOW_EN			BIT(31)
+
+#define IPU_PR_STATUS_BUF_RDY(ch, buf)		(1 << ((ch) * 2 + (buf)))
+
+#define IPU_PR_QOS_PRI(id, qos)			((qos) << ((id) * 4))
+#define IPU_PR_QOS_MASK(id)			(0xf << ((id) * 4))
+
+#define IPU_PR_REG_UPDATE_EN			BIT(0)
+
+#define IPU_PR_STRIDE_MASK			0x3fff
+
+#define IPU_PR_CROP_LINE_NUM(ch, n)		((n) << ((ch) * 4))
+#define IPU_PR_CROP_LINE_MASK(ch)		(0xf << ((ch) * 4))
+
+#define IPU_PR_ADDR_THD_MASK			0xffffffff
+
+#define IPU_PR_CH_BADDR_MASK			0xffffffff
+
+#define IPU_PR_CH_OFFSET_MASK			0xffffffff
+
+#define IPU_PR_CH_ILO_MASK			0x007fffff
+#define IPU_PR_CH_ILO_NUM(ilo)			((ilo) & IPU_PR_CH_ILO_MASK)
+
+#define IPU_PR_CH_HEIGHT_MASK			0x00000fff
+#define IPU_PR_CH_HEIGHT_NUM(fh)		(((fh) - 1) & IPU_PR_CH_HEIGHT_MASK)
+#define IPU_PR_CH_IPU_HEIGHT_MASK		0x0fff0000
+#define IPU_PR_CH_IPU_HEIGHT_NUM(fh)		((((fh) - 1) << 16) & IPU_PR_CH_IPU_HEIGHT_MASK)
+
+#endif /* __IPU_PRG_H__ */
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/prg.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/prg.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3-prg.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "prg-regs.h"
+
+#define PRG_CHAN_NUM	3
+
+struct prg_chan {
+	unsigned int pre_num;
+	struct mutex mutex;	/* for in_use */
+	bool in_use;
+};
+
+struct ipu_prg_data {
+	unsigned int id;
+	void __iomem *base;
+	unsigned long memory;
+	struct clk *axi_clk;
+	struct clk *apb_clk;
+	struct list_head list;
+	struct device *dev;
+	struct prg_chan chan[PRG_CHAN_NUM];
+	struct regmap *regmap;
+	struct regmap_field *pre_prg_sel[2];
+	spinlock_t lock;
+};
+
+static LIST_HEAD(prg_list);
+static DEFINE_MUTEX(prg_lock);
+
+static inline void prg_write(struct ipu_prg_data *prg,
+			u32 value, unsigned int offset)
+{
+	writel(value, prg->base + offset);
+}
+
+static inline u32 prg_read(struct ipu_prg_data *prg, unsigned offset)
+{
+	return readl(prg->base + offset);
+}
+
+static struct ipu_prg_data *get_prg(unsigned int ipu_id)
+{
+	struct ipu_prg_data *prg;
+
+	mutex_lock(&prg_lock);
+	list_for_each_entry(prg, &prg_list, list) {
+		if (prg->id == ipu_id) {
+			mutex_unlock(&prg_lock);
+			return prg;
+		}
+	}
+	mutex_unlock(&prg_lock);
+
+	return NULL;
+}
+
+static int assign_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num,
+			   ipu_channel_t ipu_ch)
+{
+	int prg_ch;
+
+	if (!prg)
+		return -EINVAL;
+
+	switch (ipu_ch) {
+	case MEM_BG_SYNC:
+		prg_ch = 0;
+		break;
+	case MEM_FG_SYNC:
+		prg_ch = 1;
+		break;
+	case MEM_DC_SYNC:
+		prg_ch = 2;
+		break;
+	default:
+		dev_err(prg->dev, "wrong ipu channel type\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&prg->chan[prg_ch].mutex);
+	if (!prg->chan[prg_ch].in_use) {
+		prg->chan[prg_ch].in_use = true;
+		prg->chan[prg_ch].pre_num = pre_num;
+
+		if (prg_ch != 0) {
+			unsigned int pmux, psel;	/* primary */
+			unsigned int smux, ssel;	/* secondary */
+			struct regmap_field *pfield, *sfield;
+
+			psel = pre_num - 1;
+			ssel = psel ? 0 : 1;
+
+			pfield = prg->pre_prg_sel[psel];
+			sfield = prg->pre_prg_sel[ssel];
+			pmux = (prg_ch - 1) + (prg->id << 1);
+
+			mutex_lock(&prg_lock);
+			regmap_field_write(pfield, pmux);
+
+			/*
+			 * PRE1 and PRE2 cannot bind with a same channel of
+			 * one PRG even if one of the two PREs is disabled.
+			 */
+			regmap_field_read(sfield, &smux);
+			if (smux == pmux) {
+				smux = pmux ^ 0x1;
+				regmap_field_write(sfield, smux);
+			}
+			mutex_unlock(&prg_lock);
+		}
+		mutex_unlock(&prg->chan[prg_ch].mutex);
+		dev_dbg(prg->dev, "bind prg%u ch%d with pre%u\n",
+				prg->id, prg_ch, pre_num);
+		return prg_ch;
+	}
+	mutex_unlock(&prg->chan[prg_ch].mutex);
+	return -EBUSY;
+}
+
+static inline int get_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num)
+{
+	int i;
+
+	if (!prg)
+		return -EINVAL;
+
+	for (i = 0; i < PRG_CHAN_NUM; i++) {
+		mutex_lock(&prg->chan[i].mutex);
+		if (prg->chan[i].in_use &&
+		    prg->chan[i].pre_num == pre_num) {
+			mutex_unlock(&prg->chan[i].mutex);
+			return i;
+		}
+		mutex_unlock(&prg->chan[i].mutex);
+	}
+	return -ENOENT;
+}
+
+int ipu_prg_config(struct ipu_prg_config *config)
+{
+	struct ipu_prg_data *prg = get_prg(config->id);
+	struct ipu_soc *ipu = ipu_get_soc(config->id);
+	int prg_ch, axi_id;
+	u32 reg;
+
+	if (!prg || config->crop_line > 3 || !ipu)
+		return -EINVAL;
+
+	if (config->height & ~IPU_PR_CH_HEIGHT_MASK)
+		return -EINVAL;
+
+	prg_ch = assign_prg_chan(prg, config->pre_num, config->ipu_ch);
+	if (prg_ch < 0)
+		return prg_ch;
+
+	axi_id = ipu_ch_param_get_axi_id(ipu, config->ipu_ch, IPU_INPUT_BUFFER);
+
+	clk_prepare_enable(prg->axi_clk);
+	clk_prepare_enable(prg->apb_clk);
+
+	spin_lock(&prg->lock);
+	/* clear all load enable to impact other channels */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* counter load enable */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* AXI ID */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_SOFT_CH_ARID_MASK(prg_ch);
+	reg |= IPU_PR_CTRL_SOFT_CH_ARID(prg_ch, axi_id);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* so */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_SO_MASK(prg_ch);
+	reg |= IPU_PR_CTRL_CH_SO(prg_ch, config->so);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* vflip */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_VFLIP_MASK(prg_ch);
+	reg |= IPU_PR_CTRL_CH_VFLIP(prg_ch, config->vflip);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* block mode */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_BLOCK_MODE_MASK(prg_ch);
+	reg |= IPU_PR_CTRL_CH_BLOCK_MODE(prg_ch, config->block_mode);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* disable bypass */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_BYPASS(prg_ch);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* stride */
+	reg = prg_read(prg, IPU_PR_STRIDE(prg_ch));
+	reg &= ~IPU_PR_STRIDE_MASK;
+	reg |= config->stride - 1;
+	prg_write(prg, reg, IPU_PR_STRIDE(prg_ch));
+
+	/* ilo */
+	reg = prg_read(prg, IPU_PR_CH_ILO(prg_ch));
+	reg &= ~IPU_PR_CH_ILO_MASK;
+	reg |= IPU_PR_CH_ILO_NUM(config->ilo);
+	prg_write(prg, reg, IPU_PR_CH_ILO(prg_ch));
+
+	/* height */
+	reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
+	reg &= ~IPU_PR_CH_HEIGHT_MASK;
+	reg |= IPU_PR_CH_HEIGHT_NUM(config->height);
+	prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
+
+	/* ipu height */
+	reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
+	reg &= ~IPU_PR_CH_IPU_HEIGHT_MASK;
+	reg |= IPU_PR_CH_IPU_HEIGHT_NUM(config->ipu_height);
+	prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
+
+	/* crop */
+	reg = prg_read(prg, IPU_PR_CROP_LINE);
+	reg &= ~IPU_PR_CROP_LINE_MASK(prg_ch);
+	reg |= IPU_PR_CROP_LINE_NUM(prg_ch, config->crop_line);
+	prg_write(prg, reg, IPU_PR_CROP_LINE);
+
+	/* buffer address */
+	reg = prg_read(prg, IPU_PR_CH_BADDR(prg_ch));
+	reg &= ~IPU_PR_CH_BADDR_MASK;
+	reg |= config->baddr;
+	prg_write(prg, reg, IPU_PR_CH_BADDR(prg_ch));
+
+	/* offset */
+	reg = prg_read(prg, IPU_PR_CH_OFFSET(prg_ch));
+	reg &= ~IPU_PR_CH_OFFSET_MASK;
+	reg |= config->offset;
+	prg_write(prg, reg, IPU_PR_CH_OFFSET(prg_ch));
+
+	/* threshold */
+	reg = prg_read(prg, IPU_PR_ADDR_THD);
+	reg &= ~IPU_PR_ADDR_THD_MASK;
+	reg |= prg->memory;
+	prg_write(prg, reg, IPU_PR_ADDR_THD);
+
+	/* shadow enable */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg |= IPU_PR_CTRL_SHADOW_EN;
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* register update */
+	reg = prg_read(prg, IPU_PR_REG_UPDATE);
+	reg |= IPU_PR_REG_UPDATE_EN;
+	prg_write(prg, reg, IPU_PR_REG_UPDATE);
+	spin_unlock(&prg->lock);
+
+	clk_disable_unprepare(prg->apb_clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_prg_config);
+
+int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
+{
+	struct ipu_prg_data *prg = get_prg(ipu_id);
+	int prg_ch;
+	u32 reg;
+
+	if (!prg)
+		return -EINVAL;
+
+	prg_ch = get_prg_chan(prg, pre_num);
+	if (prg_ch < 0)
+		return prg_ch;
+
+	clk_prepare_enable(prg->apb_clk);
+
+	spin_lock(&prg->lock);
+	/* clear all load enable to impact other channels */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* counter load enable */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* enable bypass */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg |= IPU_PR_CTRL_CH_BYPASS(prg_ch);
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* shadow enable */
+	reg = prg_read(prg, IPU_PR_CTRL);
+	reg |= IPU_PR_CTRL_SHADOW_EN;
+	prg_write(prg, reg, IPU_PR_CTRL);
+
+	/* register update */
+	reg = prg_read(prg, IPU_PR_REG_UPDATE);
+	reg |= IPU_PR_REG_UPDATE_EN;
+	prg_write(prg, reg, IPU_PR_REG_UPDATE);
+	spin_unlock(&prg->lock);
+
+	clk_disable_unprepare(prg->apb_clk);
+	clk_disable_unprepare(prg->axi_clk);
+
+	mutex_lock(&prg->chan[prg_ch].mutex);
+	prg->chan[prg_ch].in_use = false;
+	mutex_unlock(&prg->chan[prg_ch].mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_prg_disable);
+
+int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
+			   unsigned int hsk_line_num,
+			   int pre_store_out_height)
+{
+	struct ipu_prg_data *prg = get_prg(ipu_id);
+	int prg_ch, timeout = 1000;
+	u32 reg;
+
+	if (!prg)
+		return -EINVAL;
+
+	prg_ch = get_prg_chan(prg, pre_num);
+	if (prg_ch < 0)
+		return prg_ch;
+
+	clk_prepare_enable(prg->apb_clk);
+
+	spin_lock(&prg->lock);
+	if (pre_store_out_height <= (4 << hsk_line_num)) {
+		do {
+			reg = prg_read(prg, IPU_PR_STATUS);
+			udelay(1000);
+			timeout--;
+		} while (!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) && timeout);
+	} else {
+		do {
+			reg = prg_read(prg, IPU_PR_STATUS);
+			udelay(1000);
+			timeout--;
+		} while ((!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) ||
+			  !(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 1))) && timeout);
+	}
+	spin_unlock(&prg->lock);
+
+	clk_disable_unprepare(prg->apb_clk);
+
+	if (!timeout)
+		dev_err(prg->dev, "wait for buffer ready timeout\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_prg_wait_buf_ready);
+
+static int ipu_prg_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node, *memory;
+	struct ipu_prg_data *prg;
+	struct resource *res;
+	struct reg_field reg_field0 = REG_FIELD(IOMUXC_GPR5,
+						IMX6Q_GPR5_PRE_PRG_SEL0_LSB,
+						IMX6Q_GPR5_PRE_PRG_SEL0_MSB);
+	struct reg_field reg_field1 = REG_FIELD(IOMUXC_GPR5,
+						IMX6Q_GPR5_PRE_PRG_SEL1_LSB,
+						IMX6Q_GPR5_PRE_PRG_SEL1_MSB);
+	int id, i;
+
+	prg = devm_kzalloc(&pdev->dev, sizeof(*prg), GFP_KERNEL);
+	if (!prg)
+		return -ENOMEM;
+	prg->dev = &pdev->dev;
+
+	for (i = 0; i < PRG_CHAN_NUM; i++)
+		mutex_init(&prg->chan[i].mutex);
+
+	spin_lock_init(&prg->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	prg->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(prg->base))
+		return PTR_ERR(prg->base);
+
+	prg->axi_clk = devm_clk_get(&pdev->dev, "axi");
+	if (IS_ERR(prg->axi_clk)) {
+		dev_err(&pdev->dev, "failed to get the axi clk\n");
+		return PTR_ERR(prg->axi_clk);
+	}
+
+	prg->apb_clk = devm_clk_get(&pdev->dev, "apb");
+	if (IS_ERR(prg->apb_clk)) {
+		dev_err(&pdev->dev, "failed to get the apb clk\n");
+		return PTR_ERR(prg->apb_clk);
+	}
+
+	prg->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+	if (IS_ERR(prg->regmap)) {
+		dev_err(&pdev->dev, "failed to get regmap\n");
+		return PTR_ERR(prg->regmap);
+	}
+
+	prg->pre_prg_sel[0] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
+							reg_field0);
+	if (IS_ERR(prg->pre_prg_sel[0]))
+		return PTR_ERR(prg->pre_prg_sel[0]);
+
+	prg->pre_prg_sel[1] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
+							reg_field1);
+	if (IS_ERR(prg->pre_prg_sel[1]))
+		return PTR_ERR(prg->pre_prg_sel[1]);
+
+	memory = of_parse_phandle(np, "memory-region", 0);
+	if (!memory)
+		return -ENODEV;
+
+	prg->memory = of_translate_address(memory,
+				of_get_address(memory, 0, NULL, NULL));
+
+	id = of_alias_get_id(np, "prg");
+	if (id < 0) {
+		dev_err(&pdev->dev, "failed to get PRG id\n");
+		return id;
+	}
+	prg->id = id;
+
+	mutex_lock(&prg_lock);
+	list_add_tail(&prg->list, &prg_list);
+	mutex_unlock(&prg_lock);
+
+	platform_set_drvdata(pdev, prg);
+
+	dev_info(&pdev->dev, "driver probed\n");
+
+	return 0;
+}
+
+static int ipu_prg_remove(struct platform_device *pdev)
+{
+	struct ipu_prg_data *prg = platform_get_drvdata(pdev);
+
+	mutex_lock(&prg_lock);
+	list_del(&prg->list);
+	mutex_unlock(&prg_lock);
+
+	return 0;
+}
+
+static const struct of_device_id imx_ipu_prg_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-prg", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_prg_dt_ids);
+
+static struct platform_driver ipu_prg_driver = {
+	.driver = {
+			.name = "imx-prg",
+			.of_match_table = of_match_ptr(imx_ipu_prg_dt_ids),
+		  },
+	.probe  = ipu_prg_probe,
+	.remove = ipu_prg_remove,
+};
+
+static int __init ipu_prg_init(void)
+{
+	return platform_driver_register(&ipu_prg_driver);
+}
+subsys_initcall(ipu_prg_init);
+
+static void __exit ipu_prg_exit(void)
+{
+	platform_driver_unregister(&ipu_prg_driver);
+}
+module_exit(ipu_prg_exit);
+
+MODULE_DESCRIPTION("i.MX PRG driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/vdoa.c
+++ linux-ein-5.4.0/drivers/mxc/ipu3/vdoa.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2018 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/genalloc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "vdoa.h"
+/* 6band(3field* double buffer) * (width*2) * bandline(8)
+	= 6x1024x2x8 = 96k or 72k(1.5byte) */
+#define MAX_VDOA_IRAM_SIZE	(1024*96)
+#define VDOA_IRAM_SIZE		(1024*72)
+
+#define VDOAC_BAND_HEIGHT_32LINES	(32)
+#define VDOAC_BAND_HEIGHT_16LINES	(16)
+#define VDOAC_BAND_HEIGHT_8LINES	(8)
+#define VDOAC_THREE_FRAMES		(0x1 << 2)
+#define VDOAC_SYNC_BAND_MODE		(0x1 << 3)
+#define VDOAC_SCAN_ORDER_INTERLACED	(0x1 << 4)
+#define VDOAC_PFS_YUYV			(0x1 << 5)
+#define VDOAC_IPU_SEL_1			(0x1 << 6)
+#define VDOAFP_FH_MASK			(0x1FFF)
+#define VDOAFP_FH_SHIFT			(16)
+#define VDOAFP_FW_MASK			(0x3FFF)
+#define VDOAFP_FW_SHIFT			(0)
+#define VDOASL_VSLY_MASK		(0x3FFF)
+#define VDOASL_VSLY_SHIFT		(16)
+#define VDOASL_ISLY_MASK		(0x7FFF)
+#define VDOASL_ISLY_SHIFT		(0)
+#define VDOASRR_START_XFER		(0x2)
+#define VDOASRR_SWRST			(0x1)
+#define VDOAIEIST_TRANSFER_ERR		(0x2)
+#define VDOAIEIST_TRANSFER_END		(0x1)
+
+#define	VDOAC		(0x0)	/* Control Register */
+#define	VDOASRR		(0x4)	/* Start and Reset Register */
+#define	VDOAIE		(0x8)	/* Interrupt Enable Register */
+#define	VDOAIST		(0xc)	/* Interrupt Status Register */
+#define	VDOAFP		(0x10)	/* Frame Parameters Register */
+#define	VDOAIEBA00	(0x14)	/* External Buffer n Frame m Address Register */
+#define	VDOAIEBA01	(0x18)	/* External Buffer n Frame m Address Register */
+#define	VDOAIEBA02	(0x1c)	/* External Buffer n Frame m Address Register */
+#define	VDOAIEBA10	(0x20)	/* External Buffer n Frame m Address Register */
+#define	VDOAIEBA11	(0x24)	/* External Buffer n Frame m Address Register */
+#define	VDOAIEBA12	(0x28)	/* External Buffer n Frame m Address Register */
+#define	VDOASL		(0x2c)	/* IPU Stride Line Register */
+#define	VDOAIUBO	(0x30)	/* IPU Chroma Buffer Offset Register */
+#define	VDOAVEBA0	(0x34)	/* External Buffer m Address Register */
+#define	VDOAVEBA1	(0x38)	/* External Buffer m Address Register */
+#define	VDOAVEBA2	(0x3c)	/* External Buffer m Address Register */
+#define	VDOAVUBO	(0x40)	/* VPU Chroma Buffer Offset */
+#define	VDOASR		(0x44)	/* Status Register */
+#define	VDOATD		(0x48)	/* Test Debug Register */
+
+
+enum {
+	VDOA_INIT	= 0x1,
+	VDOA_GET	= 0x2,
+	VDOA_SETUP	= 0x4,
+	VDOA_GET_OBUF	= 0x8,
+	VDOA_START	= 0x10,
+	VDOA_INIRQ	= 0x20,
+	VDOA_STOP	= 0x40,
+	VDOA_PUT	= VDOA_INIT,
+};
+
+enum {
+	VDOA_NULL	= 0,
+	VDOA_FRAME	= 1,
+	VDOA_PREV_FIELD	= 2,
+	VDOA_CURR_FIELD	= 3,
+	VDOA_NEXT_FIELD	= 4,
+};
+
+#define CHECK_STATE(expect, retcode)					\
+do {									\
+	if (!((expect) & vdoa->state)) {				\
+		dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
+				__func__, vdoa->state, (expect));	\
+		retcode;						\
+	}								\
+} while (0)
+
+#define CHECK_NULL_PTR(ptr)						\
+do {									\
+	pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n",			\
+			vdoa, __func__, vdoa->state);			\
+	if (NULL == (ptr)) {						\
+		pr_err("ERR vdoa: %s state:0x%x null ptr.\n",		\
+				__func__, vdoa->state);			\
+	}								\
+} while (0)
+
+struct vdoa_info {
+	int		state;
+	struct device	*dev;
+	struct clk	*vdoa_clk;
+	void __iomem	*reg_base;
+	struct gen_pool	*iram_pool;
+	unsigned long	iram_base;
+	unsigned long	iram_paddr;
+	int		irq;
+	int		field;
+	struct completion comp;
+};
+
+static struct vdoa_info *g_vdoa;
+static unsigned long iram_size;
+static DEFINE_MUTEX(vdoa_lock);
+
+static inline void vdoa_read_register(struct vdoa_info *vdoa,
+				u32 reg, u32 *val)
+{
+	*val = ioread32(vdoa->reg_base + reg);
+	dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
+}
+
+static inline void vdoa_write_register(struct vdoa_info *vdoa,
+				u32 reg, u32 val)
+{
+	iowrite32(val, vdoa->reg_base + reg);
+	dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
+}
+
+static void dump_registers(struct vdoa_info *vdoa)
+{
+	int i;
+	u32 data;
+
+	for (i = VDOAC; i < VDOATD; i += 4)
+		vdoa_read_register(vdoa, i, &data);
+}
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
+{
+	int	band_size;
+	int	total_band_size = 0;
+	int	ipu_stride;
+	u32	data;
+	struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return -EINVAL);
+	if (VDOA_GET == vdoa->state) {
+		dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
+			 params->width, params->height);
+		data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
+			((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
+				 1 : 0);
+		data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
+		data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
+		data |= params->pfs ? VDOAC_PFS_YUYV : 0;
+		data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
+		vdoa_write_register(vdoa, VDOAC, data);
+
+		data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
+			((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
+		vdoa_write_register(vdoa, VDOAFP, data);
+
+		ipu_stride = params->pfs ? params->width << 1 : params->width;
+		data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
+							VDOASL_VSLY_SHIFT) |
+			((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
+		vdoa_write_register(vdoa, VDOASL, data);
+
+		dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
+		params->band_mode, params->band_lines, vdoa->iram_paddr);
+	}
+	/*
+	 * band size	= (luma_per_line + chroma_per_line) * bandLines
+	 *		= width * (3/2 or 2) * bandLines
+	 * double buffer mode used.
+	 */
+	if (params->pfs)
+		band_size = (params->width << 1) * params->band_lines;
+	else
+		band_size = ((params->width * 3) >> 1) *
+						params->band_lines;
+	if (params->interlaced) {
+		total_band_size = 6 * band_size; /* 3 frames*double buffer */
+		if (iram_size < total_band_size) {
+			dev_err(vdoa->dev, "iram_size:0x%lx is smaller than "
+				"request:0x%x!\n", iram_size, total_band_size);
+			return -EINVAL;
+		}
+		if (params->vfield_buf.prev_veba) {
+			if (params->band_mode) {
+				vdoa_write_register(vdoa, VDOAIEBA00,
+							vdoa->iram_paddr);
+				vdoa_write_register(vdoa, VDOAIEBA10,
+						 vdoa->iram_paddr + band_size);
+			} else
+				vdoa_write_register(vdoa, VDOAIEBA00,
+							params->ieba0);
+			vdoa_write_register(vdoa, VDOAVEBA0,
+					params->vfield_buf.prev_veba);
+			vdoa->field = VDOA_PREV_FIELD;
+		}
+		if (params->vfield_buf.cur_veba) {
+			if (params->band_mode) {
+				vdoa_write_register(vdoa, VDOAIEBA01,
+					 vdoa->iram_paddr + band_size * 2);
+				vdoa_write_register(vdoa, VDOAIEBA11,
+					 vdoa->iram_paddr + band_size * 3);
+			} else
+				vdoa_write_register(vdoa, VDOAIEBA01,
+							params->ieba1);
+			vdoa_write_register(vdoa, VDOAVEBA1,
+					params->vfield_buf.cur_veba);
+			vdoa->field = VDOA_CURR_FIELD;
+		}
+		if (params->vfield_buf.next_veba) {
+			if (params->band_mode) {
+				vdoa_write_register(vdoa, VDOAIEBA02,
+					 vdoa->iram_paddr + band_size * 4);
+				vdoa_write_register(vdoa, VDOAIEBA12,
+					 vdoa->iram_paddr + band_size * 5);
+			} else
+				vdoa_write_register(vdoa, VDOAIEBA02,
+							params->ieba2);
+			vdoa_write_register(vdoa, VDOAVEBA2,
+					params->vfield_buf.next_veba);
+			vdoa->field = VDOA_NEXT_FIELD;
+			vdoa_read_register(vdoa, VDOAC, &data);
+			data |= VDOAC_THREE_FRAMES;
+			vdoa_write_register(vdoa, VDOAC, data);
+		}
+
+		if (!params->pfs)
+			vdoa_write_register(vdoa, VDOAIUBO,
+				 params->width * params->band_lines);
+		vdoa_write_register(vdoa, VDOAVUBO,
+				 params->vfield_buf.vubo);
+		dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
+	} else if (params->band_mode) {
+		/* used for progressive frame resize on PrP channel */
+		BUG(); /* currently not support */
+		/* progressvie frame: band mode */
+		vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
+		vdoa_write_register(vdoa, VDOAIEBA10,
+					 vdoa->iram_paddr + band_size);
+		if (!params->pfs)
+			vdoa_write_register(vdoa, VDOAIUBO,
+					params->width * params->band_lines);
+		dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
+	} else {
+		/* progressive frame: mem->mem, non-band mode */
+		vdoa->field = VDOA_FRAME;
+		vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
+		vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
+		vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
+		if (!params->pfs)
+			/* note: iubo is relative value, based on ieba0 */
+			vdoa_write_register(vdoa, VDOAIUBO,
+					params->width * params->height);
+	}
+	vdoa->state = VDOA_SETUP;
+	return 0;
+}
+
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
+{
+	u32	data;
+	struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_SETUP, return);
+	vdoa->state = VDOA_GET_OBUF;
+	memset(buf, 0, sizeof(*buf));
+
+	vdoa_read_register(vdoa, VDOAC, &data);
+	switch (vdoa->field) {
+	case VDOA_FRAME:
+	case VDOA_PREV_FIELD:
+		vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
+		if (data & VDOAC_SYNC_BAND_MODE)
+			vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
+		break;
+	case VDOA_CURR_FIELD:
+		vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
+		vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
+		break;
+	case VDOA_NEXT_FIELD:
+		vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
+		vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
+		break;
+	default:
+		BUG();
+		break;
+	}
+	if (!(data & VDOAC_PFS_YUYV))
+		vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
+}
+
+int vdoa_start(vdoa_handle_t handle, int timeout_ms)
+{
+	int ret;
+	struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
+	vdoa->state = VDOA_START;
+	init_completion(&vdoa->comp);
+	vdoa_write_register(vdoa, VDOAIST,
+			VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+	vdoa_write_register(vdoa, VDOAIE,
+			VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+
+	enable_irq(vdoa->irq);
+	vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
+	dump_registers(vdoa);
+
+	ret = wait_for_completion_timeout(&vdoa->comp,
+			msecs_to_jiffies(timeout_ms));
+
+	return ret > 0 ? 0 : -ETIMEDOUT;
+}
+
+void vdoa_stop(vdoa_handle_t handle)
+{
+	struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_GET | VDOA_START | VDOA_INIRQ, return);
+	vdoa->state = VDOA_STOP;
+
+	disable_irq(vdoa->irq);
+
+	vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+}
+
+void vdoa_get_handle(vdoa_handle_t *handle)
+{
+	struct vdoa_info *vdoa = g_vdoa;
+
+	CHECK_NULL_PTR(handle);
+	*handle = (vdoa_handle_t *)NULL;
+	CHECK_STATE(VDOA_INIT, return);
+	mutex_lock(&vdoa_lock);
+	clk_prepare_enable(vdoa->vdoa_clk);
+	vdoa->state = VDOA_GET;
+	vdoa->field = VDOA_NULL;
+	vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+
+	*handle = (vdoa_handle_t *)vdoa;
+}
+
+void vdoa_put_handle(vdoa_handle_t *handle)
+{
+	struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_STOP, return);
+	if (vdoa != g_vdoa)
+		BUG();
+
+	clk_disable_unprepare(vdoa->vdoa_clk);
+	vdoa->state = VDOA_PUT;
+	*handle = (vdoa_handle_t *)NULL;
+	mutex_unlock(&vdoa_lock);
+}
+
+static irqreturn_t vdoa_irq_handler(int irq, void *data)
+{
+	u32 status, mask, val;
+	struct vdoa_info *vdoa = data;
+
+	CHECK_NULL_PTR(vdoa);
+	CHECK_STATE(VDOA_START, return IRQ_HANDLED);
+	vdoa->state = VDOA_INIRQ;
+	vdoa_read_register(vdoa, VDOAIST, &status);
+	vdoa_read_register(vdoa, VDOAIE, &mask);
+	val = status & mask;
+	vdoa_write_register(vdoa, VDOAIST, val);
+	if (VDOAIEIST_TRANSFER_ERR & val)
+		dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
+	if (VDOAIEIST_TRANSFER_END & val)
+		dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
+	if (0 == val) {
+		dev_err(vdoa->dev, "vdoa unknown irq!\n");
+		BUG();
+	}
+
+	complete(&vdoa->comp);
+	return IRQ_HANDLED;
+}
+
+/* IRAM Size in Kbytes, example:vdoa_iram_size=64, 64KBytes */
+static int __init vdoa_iram_size_setup(char *options)
+{
+	int ret;
+
+	ret = kstrtoul(options, 0, &iram_size);
+	if (ret)
+		iram_size = 0;
+	else
+		iram_size *= SZ_1K;
+
+	return 1;
+}
+__setup("vdoa_iram_size=", vdoa_iram_size_setup);
+
+static const struct of_device_id imx_vdoa_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-vdoa", },
+	{ /* sentinel */ }
+};
+
+static int vdoa_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct vdoa_info *vdoa;
+	struct resource *res;
+	struct resource *res_irq;
+	struct device	*dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "can't get device resources\n");
+		return -ENOENT;
+	}
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq) {
+		dev_err(dev, "failed to get irq resource\n");
+		return -ENOENT;
+	}
+
+	vdoa = devm_kzalloc(dev, sizeof(struct vdoa_info), GFP_KERNEL);
+	if (!vdoa)
+		return -ENOMEM;
+	vdoa->dev = dev;
+
+	vdoa->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (!vdoa->reg_base)
+		return -EBUSY;
+
+	vdoa->irq = res_irq->start;
+	ret = devm_request_irq(dev, vdoa->irq, vdoa_irq_handler, 0,
+				"vdoa", vdoa);
+	if (ret) {
+		dev_err(dev, "can't claim irq %d\n", vdoa->irq);
+		return ret;
+	}
+	disable_irq(vdoa->irq);
+
+	vdoa->vdoa_clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(vdoa->vdoa_clk)) {
+		dev_err(dev, "failed to get vdoa_clk\n");
+		return PTR_ERR(vdoa->vdoa_clk);
+	}
+
+	vdoa->iram_pool = of_gen_pool_get(np, "iram", 0);
+	if (!vdoa->iram_pool) {
+		dev_err(&pdev->dev, "iram pool not available\n");
+		return -ENOMEM;
+	}
+
+	if ((iram_size == 0) || (iram_size > MAX_VDOA_IRAM_SIZE))
+		iram_size = VDOA_IRAM_SIZE;
+
+	vdoa->iram_base = gen_pool_alloc(vdoa->iram_pool, iram_size);
+	if (!vdoa->iram_base) {
+		dev_err(&pdev->dev, "unable to alloc iram\n");
+		return -ENOMEM;
+	}
+
+	vdoa->iram_paddr = gen_pool_virt_to_phys(vdoa->iram_pool,
+						 vdoa->iram_base);
+
+	dev_dbg(dev, "iram_base:0x%lx,iram_paddr:0x%lx,size:0x%lx\n",
+		 vdoa->iram_base, vdoa->iram_paddr, iram_size);
+
+	vdoa->state = VDOA_INIT;
+	dev_set_drvdata(dev, vdoa);
+	g_vdoa = vdoa;
+	dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
+	return 0;
+}
+
+static int vdoa_remove(struct platform_device *pdev)
+{
+	struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
+
+	gen_pool_free(vdoa->iram_pool, vdoa->iram_base, iram_size);
+	kfree(vdoa);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver vdoa_driver = {
+	.driver = {
+		.name = "mxc_vdoa",
+		.of_match_table = imx_vdoa_dt_ids,
+	},
+	.probe = vdoa_probe,
+	.remove = vdoa_remove,
+};
+
+static int __init vdoa_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&vdoa_driver);
+	if (err) {
+		pr_err("vdoa_driver register failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit vdoa_cleanup(void)
+{
+	platform_driver_unregister(&vdoa_driver);
+}
+
+subsys_initcall(vdoa_init);
+module_exit(vdoa_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/ipu3/vdoa.h
+++ linux-ein-5.4.0/drivers/mxc/ipu3/vdoa.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __VDOA_H__
+#define __VDOA_H__
+
+#define VDOA_PFS_YUYV (1)
+#define VDOA_PFS_NV12 (0)
+
+
+struct vfield_buf {
+	u32	prev_veba;
+	u32	cur_veba;
+	u32	next_veba;
+	u32	vubo;
+};
+
+struct vframe_buf {
+	u32	veba;
+	u32	vubo;
+};
+
+struct vdoa_params {
+	u32	width;
+	u32	height;
+	int	vpu_stride;
+	int	interlaced;
+	int	scan_order;
+	int	ipu_num;
+	int	band_lines;
+	int	band_mode;
+	int	pfs;
+	u32	ieba0;
+	u32	ieba1;
+	u32	ieba2;
+	struct	vframe_buf vframe_buf;
+	struct	vfield_buf vfield_buf;
+};
+struct vdoa_ipu_buf {
+	u32	ieba0;
+	u32	ieba1;
+	u32	iubo;
+};
+
+struct vdoa_info;
+typedef void *vdoa_handle_t;
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
+int  vdoa_start(vdoa_handle_t handle, int timeout_ms);
+void vdoa_stop(vdoa_handle_t handle);
+void vdoa_get_handle(vdoa_handle_t *handle);
+void vdoa_put_handle(vdoa_handle_t *handle);
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/mipi/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/mipi/Kconfig
@@ -0,0 +1,14 @@
+#
+# MIPI configuration
+#
+
+menu "MXC MIPI Support"
+
+config MXC_MIPI_CSI2
+	tristate "MIPI CSI2 support"
+	depends on (SOC_IMX6 || SOC_IMX7D)
+	default n
+	---help---
+	Say Y to get the MIPI CSI2 support.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/mipi/Makefile
+++ linux-ein-5.4.0/drivers/mxc/mipi/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the mipi interface driver
+#
+obj-$(CONFIG_MXC_MIPI_CSI2) += mxc_mipi_csi2.o
--- linux-ein-5.4.0.orig/drivers/mxc/mipi/mxc_mipi_csi2.c
+++ linux-ein-5.4.0/drivers/mxc/mipi/mxc_mipi_csi2.c
@@ -0,0 +1,528 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <linux/mipi_csi2.h>
+
+#include "mxc_mipi_csi2.h"
+
+static struct mipi_csi2_info *gmipi_csi2;
+
+void _mipi_csi2_lock(struct mipi_csi2_info *info)
+{
+	if (!in_irq() && !in_softirq())
+		mutex_lock(&info->mutex_lock);
+}
+
+void _mipi_csi2_unlock(struct mipi_csi2_info *info)
+{
+	if (!in_irq() && !in_softirq())
+		mutex_unlock(&info->mutex_lock);
+}
+
+static inline void mipi_csi2_write(struct mipi_csi2_info *info,
+		unsigned value, unsigned offset)
+{
+	writel(value, info->mipi_csi2_base + offset);
+}
+
+static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info,
+		unsigned offset)
+{
+	return readl(info->mipi_csi2_base + offset);
+}
+
+/*!
+ * This function is called to enable the mipi csi2 interface.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns setted value
+ */
+bool mipi_csi2_enable(struct mipi_csi2_info *info)
+{
+	bool status;
+
+	_mipi_csi2_lock(info);
+
+	if (!info->mipi_en) {
+		info->mipi_en = true;
+		clk_prepare_enable(info->cfg_clk);
+		clk_prepare_enable(info->dphy_clk);
+	} else
+		mipi_dbg("mipi csi2 already enabled!\n");
+
+	status = info->mipi_en;
+
+	_mipi_csi2_unlock(info);
+
+	return status;
+}
+EXPORT_SYMBOL(mipi_csi2_enable);
+
+/*!
+ * This function is called to disable the mipi csi2 interface.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns setted value
+ */
+bool mipi_csi2_disable(struct mipi_csi2_info *info)
+{
+	bool status;
+
+	_mipi_csi2_lock(info);
+
+	if (info->mipi_en) {
+		info->mipi_en = false;
+		clk_disable_unprepare(info->dphy_clk);
+		clk_disable_unprepare(info->cfg_clk);
+	} else
+		mipi_dbg("mipi csi2 already disabled!\n");
+
+	status = info->mipi_en;
+
+	_mipi_csi2_unlock(info);
+
+	return status;
+}
+EXPORT_SYMBOL(mipi_csi2_disable);
+
+/*!
+ * This function is called to get mipi csi2 disable/enable status.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns mipi csi2 status
+ */
+bool mipi_csi2_get_status(struct mipi_csi2_info *info)
+{
+	bool status;
+
+	_mipi_csi2_lock(info);
+	status = info->mipi_en;
+	_mipi_csi2_unlock(info);
+
+	return status;
+}
+EXPORT_SYMBOL(mipi_csi2_get_status);
+
+/*!
+ * This function is called to set mipi lanes.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns setted value
+ */
+unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info)
+{
+	unsigned int lanes;
+
+	_mipi_csi2_lock(info);
+	mipi_csi2_write(info, info->lanes - 1, MIPI_CSI2_N_LANES);
+	lanes = mipi_csi2_read(info, MIPI_CSI2_N_LANES);
+	_mipi_csi2_unlock(info);
+
+	return lanes;
+}
+EXPORT_SYMBOL(mipi_csi2_set_lanes);
+
+/*!
+ * This function is called to set mipi data type.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns setted value
+ */
+unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info,
+					unsigned int datatype)
+{
+	unsigned int dtype;
+
+	_mipi_csi2_lock(info);
+	info->datatype = datatype;
+	dtype = info->datatype;
+	_mipi_csi2_unlock(info);
+
+	return dtype;
+}
+EXPORT_SYMBOL(mipi_csi2_set_datatype);
+
+/*!
+ * This function is called to get mipi data type.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns mipi data type
+ */
+unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info)
+{
+	unsigned int dtype;
+
+	_mipi_csi2_lock(info);
+	dtype = info->datatype;
+	_mipi_csi2_unlock(info);
+
+	return dtype;
+}
+EXPORT_SYMBOL(mipi_csi2_get_datatype);
+
+/*!
+ * This function is called to get mipi csi2 dphy status.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns dphy status
+ */
+unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info)
+{
+	unsigned int status;
+
+	_mipi_csi2_lock(info);
+	status = mipi_csi2_read(info, MIPI_CSI2_PHY_STATE);
+	_mipi_csi2_unlock(info);
+
+	return status;
+}
+EXPORT_SYMBOL(mipi_csi2_dphy_status);
+
+/*!
+ * This function is called to get mipi csi2 error1 status.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns error1 value
+ */
+unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info)
+{
+	unsigned int err1;
+
+	_mipi_csi2_lock(info);
+	err1 = mipi_csi2_read(info, MIPI_CSI2_ERR1);
+	_mipi_csi2_unlock(info);
+
+	return err1;
+}
+EXPORT_SYMBOL(mipi_csi2_get_error1);
+
+/*!
+ * This function is called to get mipi csi2 error1 status.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns error1 value
+ */
+unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info)
+{
+	unsigned int err2;
+
+	_mipi_csi2_lock(info);
+	err2 = mipi_csi2_read(info, MIPI_CSI2_ERR2);
+	_mipi_csi2_unlock(info);
+
+	return err2;
+}
+EXPORT_SYMBOL(mipi_csi2_get_error2);
+
+/*!
+ * This function is called to enable mipi to ipu pixel clock.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info)
+{
+	return clk_prepare_enable(info->pixel_clk);
+}
+EXPORT_SYMBOL(mipi_csi2_pixelclk_enable);
+
+/*!
+ * This function is called to disable mipi to ipu pixel clock.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns 0 on success or negative error code on fail
+ */
+void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info)
+{
+	clk_disable_unprepare(info->pixel_clk);
+}
+EXPORT_SYMBOL(mipi_csi2_pixelclk_disable);
+
+/*!
+ * This function is called to power on mipi csi2.
+ *
+ * @param	info		mipi csi2 hander
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int mipi_csi2_reset(struct mipi_csi2_info *info)
+{
+	_mipi_csi2_lock(info);
+
+	mipi_csi2_write(info, 0x0, MIPI_CSI2_PHY_SHUTDOWNZ);
+	mipi_csi2_write(info, 0x0, MIPI_CSI2_DPHY_RSTZ);
+	mipi_csi2_write(info, 0x0, MIPI_CSI2_CSI2_RESETN);
+
+	mipi_csi2_write(info, 0x00000001, MIPI_CSI2_PHY_TST_CTRL0);
+	mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL1);
+	mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+	mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
+	mipi_csi2_write(info, 0x00010044, MIPI_CSI2_PHY_TST_CTRL1);
+	mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+	mipi_csi2_write(info, 0x00000014, MIPI_CSI2_PHY_TST_CTRL1);
+	mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
+	mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+
+	mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_PHY_SHUTDOWNZ);
+	mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_DPHY_RSTZ);
+	mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_CSI2_RESETN);
+
+	_mipi_csi2_unlock(info);
+
+	return 0;
+}
+EXPORT_SYMBOL(mipi_csi2_reset);
+
+/*!
+ * This function is called to get mipi csi2 info.
+ *
+ * @return      Returns mipi csi2 info struct pointor
+ */
+struct mipi_csi2_info *mipi_csi2_get_info(void)
+{
+	return gmipi_csi2;
+}
+EXPORT_SYMBOL(mipi_csi2_get_info);
+
+/*!
+ * This function is called to get mipi csi2 bind ipu num.
+ *
+ * @return      Returns mipi csi2 bind ipu num
+ */
+int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info)
+{
+	int ipu_id;
+
+	_mipi_csi2_lock(info);
+	ipu_id = info->ipu_id;
+	_mipi_csi2_unlock(info);
+
+	return ipu_id;
+}
+EXPORT_SYMBOL(mipi_csi2_get_bind_ipu);
+
+/*!
+ * This function is called to get mipi csi2 bind csi num.
+ *
+ * @return      Returns mipi csi2 bind csi num
+ */
+unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info)
+{
+	unsigned int csi_id;
+
+	_mipi_csi2_lock(info);
+	csi_id = info->csi_id;
+	_mipi_csi2_unlock(info);
+
+	return csi_id;
+}
+EXPORT_SYMBOL(mipi_csi2_get_bind_csi);
+
+/*!
+ * This function is called to get mipi csi2 virtual channel.
+ *
+ * @return      Returns mipi csi2 virtual channel num
+ */
+unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info)
+{
+	unsigned int v_channel;
+
+	_mipi_csi2_lock(info);
+	v_channel = info->v_channel;
+	_mipi_csi2_unlock(info);
+
+	return v_channel;
+}
+EXPORT_SYMBOL(mipi_csi2_get_virtual_channel);
+
+/**
+ * This function is called by the driver framework to initialize the MIPI CSI2
+ * device.
+ *
+ * @param	pdev	The device structure for the MIPI CSI2 passed in by the
+ *			driver framework.
+ *
+ * @return      Returns 0 on success or negative error code on error
+ */
+static int mipi_csi2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	u32 mipi_csi2_dphy_ver;
+	int ret;
+
+	gmipi_csi2 = kmalloc(sizeof(struct mipi_csi2_info), GFP_KERNEL);
+	if (!gmipi_csi2) {
+		ret = -ENOMEM;
+		goto alloc_failed;
+	}
+
+	ret = of_property_read_u32(np, "ipu_id", &(gmipi_csi2->ipu_id));
+	if (ret) {
+		dev_err(&pdev->dev, "ipu_id missing or invalid\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(np, "csi_id", &(gmipi_csi2->csi_id));
+	if (ret) {
+		dev_err(&pdev->dev, "csi_id missing or invalid\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(np, "v_channel", &(gmipi_csi2->v_channel));
+	if (ret) {
+		dev_err(&pdev->dev, "v_channel missing or invalid\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(np, "lanes", &(gmipi_csi2->lanes));
+	if (ret) {
+		dev_err(&pdev->dev, "lanes missing or invalid\n");
+		goto err;
+	}
+
+	if ((gmipi_csi2->ipu_id < 0) || (gmipi_csi2->ipu_id > 1) ||
+		(gmipi_csi2->csi_id > 1) || (gmipi_csi2->v_channel > 3) ||
+		(gmipi_csi2->lanes > 4)) {
+		dev_err(&pdev->dev, "invalid param for mipi csi2!\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* initialize mutex */
+	mutex_init(&gmipi_csi2->mutex_lock);
+
+	/* get mipi csi2 informaiton */
+	gmipi_csi2->pdev = pdev;
+	gmipi_csi2->mipi_en = false;
+
+	gmipi_csi2->cfg_clk = devm_clk_get(dev, "cfg_clk");
+	if (IS_ERR(gmipi_csi2->cfg_clk)) {
+		dev_err(&pdev->dev, "failed to get cfg_clk\n");
+		ret = PTR_ERR(gmipi_csi2->cfg_clk);
+		goto err;
+	}
+
+	/* get mipi dphy clk */
+	gmipi_csi2->dphy_clk = devm_clk_get(dev, "dphy_clk");
+	if (IS_ERR(gmipi_csi2->dphy_clk)) {
+		dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n");
+		ret = PTR_ERR(gmipi_csi2->dphy_clk);
+		goto err;
+	}
+
+	/* get mipi to ipu pixel clk */
+	gmipi_csi2->pixel_clk = devm_clk_get(dev, "pixel_clk");
+	if (IS_ERR(gmipi_csi2->pixel_clk)) {
+		dev_err(&pdev->dev, "failed to get mipi pixel clk\n");
+		ret = PTR_ERR(gmipi_csi2->pixel_clk);
+		goto err;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* mipi register mapping */
+	gmipi_csi2->mipi_csi2_base = ioremap(res->start, PAGE_SIZE);
+	if (!gmipi_csi2->mipi_csi2_base) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* mipi dphy clk enable for register access */
+	clk_prepare_enable(gmipi_csi2->dphy_clk);
+	/* get mipi csi2 dphy version */
+	mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, MIPI_CSI2_VERSION);
+
+	clk_disable_unprepare(gmipi_csi2->dphy_clk);
+
+	platform_set_drvdata(pdev, gmipi_csi2);
+
+	dev_info(&pdev->dev, "i.MX MIPI CSI2 driver probed\n");
+	dev_info(&pdev->dev, "i.MX MIPI CSI2 dphy version is 0x%x\n",
+						mipi_csi2_dphy_ver);
+
+	return 0;
+
+err:
+	kfree(gmipi_csi2);
+alloc_failed:
+	dev_err(&pdev->dev, "i.MX MIPI CSI2 driver probed -  error\n");
+	return ret;
+}
+
+static int mipi_csi2_remove(struct platform_device *pdev)
+{
+	/* unmapping mipi register */
+	iounmap(gmipi_csi2->mipi_csi2_base);
+
+	kfree(gmipi_csi2);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id imx_mipi_csi2_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-mipi-csi2", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver mipi_csi2_driver = {
+	.driver = {
+		   .name = "mxc_mipi_csi2",
+		   .of_match_table = imx_mipi_csi2_dt_ids,
+	},
+	.probe = mipi_csi2_probe,
+	.remove = mipi_csi2_remove,
+};
+
+static int __init mipi_csi2_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&mipi_csi2_driver);
+	if (err) {
+		pr_err("mipi_csi2_driver register failed\n");
+		return -ENODEV;
+	}
+
+	pr_info("MIPI CSI2 driver module loaded\n");
+
+	return 0;
+}
+
+static void __exit mipi_csi2_cleanup(void)
+{
+	platform_driver_unregister(&mipi_csi2_driver);
+}
+
+subsys_initcall(mipi_csi2_init);
+module_exit(mipi_csi2_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX MIPI CSI2 driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/mipi/mxc_mipi_csi2.h
+++ linux-ein-5.4.0/drivers/mxc/mipi/mxc_mipi_csi2.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2019 NXP
+ */
+
+#ifndef __MXC_MIPI_CSI2_H__
+#define __MXC_MIPI_CSI2_H__
+
+#ifdef DEBUG
+#define mipi_dbg(fmt, ...)	\
+	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define mipi_dbg(fmt, ...)
+#endif
+
+/* driver private data */
+struct mipi_csi2_info {
+	bool		mipi_en;
+	int		ipu_id;
+	unsigned int	csi_id;
+	unsigned int	v_channel;
+	unsigned int	lanes;
+	unsigned int	datatype;
+	struct clk	*cfg_clk;
+	struct clk	*dphy_clk;
+	struct clk	*pixel_clk;
+	void __iomem	*mipi_csi2_base;
+	struct platform_device	*pdev;
+
+	struct mutex mutex_lock;
+};
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/mlb/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/mlb/Kconfig
@@ -0,0 +1,17 @@
+#
+# MLB150 configuration
+#
+
+menu "MXC Media Local Bus Driver"
+
+config MXC_MLB
+	bool
+
+config MXC_MLB150
+	tristate "MLB150 support"
+	depends on ARCH_MXC || COMPILE_TEST
+	select MXC_MLB
+	help
+	Say Y to get the MLB150 support.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/mlb/Makefile
+++ linux-ein-5.4.0/drivers/mxc/mlb/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the i.MX6Q/DL MLB150 driver
+#
+
+obj-$(CONFIG_MXC_MLB150) += mxc_mlb.o
--- linux-ein-5.4.0.orig/drivers/mxc/mlb/mxc_mlb.c
+++ linux-ein-5.4.0/drivers/mxc/mlb/mxc_mlb.c
@@ -0,0 +1,2828 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdev.h>
+#include <linux/circ_buf.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mxc_mlb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched/signal.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#define DRIVER_NAME "mxc_mlb150"
+
+/*
+ * MLB module memory map registers define
+ */
+#define REG_MLBC0		0x0
+#define MLBC0_MLBEN		(0x1)
+#define MLBC0_MLBCLK_MASK	(0x7 << 2)
+#define MLBC0_MLBCLK_SHIFT	(2)
+#define MLBC0_MLBPEN		(0x1 << 5)
+#define MLBC0_MLBLK		(0x1 << 7)
+#define MLBC0_ASYRETRY		(0x1 << 12)
+#define MLBC0_CTLRETRY		(0x1 << 12)
+#define MLBC0_FCNT_MASK		(0x7 << 15)
+#define MLBC0_FCNT_SHIFT	(15)
+
+#define REG_MLBPC0		0x8
+#define MLBPC0_MCLKHYS		(0x1 << 11)
+
+#define REG_MS0			0xC
+#define REG_MS1			0x14
+
+#define REG_MSS			0x20
+#define MSS_RSTSYSCMD		(0x1)
+#define MSS_LKSYSCMD		(0x1 << 1)
+#define MSS_ULKSYSCMD		(0x1 << 2)
+#define MSS_CSSYSCMD		(0x1 << 3)
+#define MSS_SWSYSCMD		(0x1 << 4)
+#define MSS_SERVREQ		(0x1 << 5)
+
+#define REG_MSD			0x24
+
+#define REG_MIEN		0x2C
+#define MIEN_ISOC_PE		(0x1)
+#define MIEN_ISOC_BUFO		(0x1 << 1)
+#define MIEN_SYNC_PE		(0x1 << 16)
+#define MIEN_ARX_DONE		(0x1 << 17)
+#define MIEN_ARX_PE		(0x1 << 18)
+#define MIEN_ARX_BREAK		(0x1 << 19)
+#define MIEN_ATX_DONE		(0x1 << 20)
+#define MIEN_ATX_PE		(0x1 << 21)
+#define MIEN_ATX_BREAK		(0x1 << 22)
+#define MIEN_CRX_DONE		(0x1 << 24)
+#define MIEN_CRX_PE		(0x1 << 25)
+#define MIEN_CRX_BREAK		(0x1 << 26)
+#define MIEN_CTX_DONE		(0x1 << 27)
+#define MIEN_CTX_PE		(0x1 << 28)
+#define MIEN_CTX_BREAK		(0x1 << 29)
+
+#define REG_MLBPC2		0x34
+#define REG_MLBPC1		0x38
+#define MLBPC1_VAL		(0x00000888)
+
+#define REG_MLBC1		0x3C
+#define MLBC1_LOCK		(0x1 << 6)
+#define MLBC1_CLKM		(0x1 << 7)
+#define MLBC1_NDA_MASK		(0xFF << 8)
+#define MLBC1_NDA_SHIFT		(8)
+
+#define REG_HCTL		0x80
+#define HCTL_RST0		(0x1)
+#define HCTL_RST1		(0x1 << 1)
+#define HCTL_EN			(0x1 << 15)
+
+#define REG_HCMR0		0x88
+#define REG_HCMR1		0x8C
+#define REG_HCER0		0x90
+#define REG_HCER1		0x94
+#define REG_HCBR0		0x98
+#define REG_HCBR1		0x9C
+
+#define REG_MDAT0		0xC0
+#define REG_MDAT1		0xC4
+#define REG_MDAT2		0xC8
+#define REG_MDAT3		0xCC
+
+#define REG_MDWE0		0xD0
+#define REG_MDWE1		0xD4
+#define REG_MDWE2		0xD8
+#define REG_MDWE3		0xDC
+
+#define REG_MCTL		0xE0
+#define MCTL_XCMP		(0x1)
+
+#define REG_MADR		0xE4
+#define MADR_WNR		(0x1 << 31)
+#define MADR_TB			(0x1 << 30)
+#define MADR_ADDR_MASK		(0x7f << 8)
+#define MADR_ADDR_SHIFT		(0)
+
+#define REG_ACTL		0x3C0
+#define ACTL_MPB		(0x1 << 4)
+#define ACTL_DMAMODE		(0x1 << 2)
+#define ACTL_SMX		(0x1 << 1)
+#define ACTL_SCE		(0x1)
+
+#define REG_ACSR0		0x3D0
+#define REG_ACSR1		0x3D4
+#define REG_ACMR0		0x3D8
+#define REG_ACMR1		0x3DC
+
+#define REG_CAT_MDATn(ch) (REG_MDAT0 + ((ch % 8) >> 1) * 4)
+#define REG_CAT_MDWEn(ch) (REG_MDWE0 + ((ch % 8) >> 1) * 4)
+
+#define INT_AHB0_CH_START	(0)
+#define INT_AHB1_CH_START	(32)
+
+#define LOGIC_CH_NUM		(64)
+#define BUF_CDT_OFFSET		(0x0)
+#define BUF_ADT_OFFSET		(0x40)
+#define BUF_CAT_MLB_OFFSET	(0x80)
+#define BUF_CAT_HBI_OFFSET	(0x88)
+#define BUF_CTR_END_OFFSET	(0x8F)
+
+#define CAT_MODE_RX		(0x1 << 0)
+#define CAT_MODE_TX		(0x1 << 1)
+#define CAT_MODE_INBOUND_DMA	(0x1 << 8)
+#define CAT_MODE_OUTBOUND_DMA	(0x1 << 9)
+
+#define CH_SYNC_DEFAULT_QUAD	(1)
+#define CH_SYNC_MAX_QUAD	(15)
+#define CH_SYNC_CDT_BUF_DEP	(CH_SYNC_DEFAULT_QUAD * 4 * 4)
+#define CH_SYNC_ADT_BUF_MULTI	(4)
+#define CH_SYNC_ADT_BUF_DEP	(CH_SYNC_CDT_BUF_DEP * CH_SYNC_ADT_BUF_MULTI)
+#define CH_SYNC_BUF_SZ		(CH_SYNC_MAX_QUAD * 4 * 4 * \
+				CH_SYNC_ADT_BUF_MULTI)
+#define CH_CTRL_CDT_BUF_DEP	(64)
+#define CH_CTRL_ADT_BUF_DEP	(CH_CTRL_CDT_BUF_DEP)
+#define CH_CTRL_BUF_SZ		(CH_CTRL_ADT_BUF_DEP)
+#define CH_ASYNC_MDP_PACKET_LEN	(1024)
+#define CH_ASYNC_MEP_PACKET_LEN	(1536)
+#define CH_ASYNC_CDT_BUF_DEP	(CH_ASYNC_MEP_PACKET_LEN)
+#define CH_ASYNC_ADT_BUF_DEP	(CH_ASYNC_CDT_BUF_DEP)
+#define CH_ASYNC_BUF_SZ		(CH_ASYNC_ADT_BUF_DEP)
+#define CH_ISOC_BLK_SIZE_188	(188)
+#define CH_ISOC_BLK_SIZE_196	(196)
+#define CH_ISOC_BLK_SIZE	(CH_ISOC_BLK_SIZE_188)
+#define CH_ISOC_BLK_NUM		(1)
+#define CH_ISOC_CDT_BUF_DEP	(CH_ISOC_BLK_SIZE * CH_ISOC_BLK_NUM)
+#define CH_ISOC_ADT_BUF_DEP	(CH_ISOC_CDT_BUF_DEP)
+#define CH_ISOC_BUF_SZ		(1024)
+
+#define CH_SYNC_DBR_BUF_OFFSET	(0x0)
+#define CH_CTRL_DBR_BUF_OFFSET	(CH_SYNC_DBR_BUF_OFFSET + \
+				2 * (CH_SYNC_MAX_QUAD * 4 * 4))
+#define CH_ASYNC_DBR_BUF_OFFSET	(CH_CTRL_DBR_BUF_OFFSET + \
+				2 * CH_CTRL_CDT_BUF_DEP)
+#define CH_ISOC_DBR_BUF_OFFSET	(CH_ASYNC_DBR_BUF_OFFSET + \
+				2 * CH_ASYNC_CDT_BUF_DEP)
+
+#define DBR_BUF_START 0x00000
+
+#define CDT_LEN			(16)
+#define ADT_LEN			(16)
+#define CAT_LEN			(2)
+
+#define CDT_SZ			(CDT_LEN * LOGIC_CH_NUM)
+#define ADT_SZ			(ADT_LEN * LOGIC_CH_NUM)
+#define CAT_SZ			(CAT_LEN * LOGIC_CH_NUM * 2)
+
+#define CDT_BASE(base)		(base + BUF_CDT_OFFSET)
+#define ADT_BASE(base)		(base + BUF_ADT_OFFSET)
+#define CAT_MLB_BASE(base)	(base + BUF_CAT_MLB_OFFSET)
+#define CAT_HBI_BASE(base)	(base + BUF_CAT_HBI_OFFSET)
+
+#define CDTn_ADDR(base, n)	(base + BUF_CDT_OFFSET + n * CDT_LEN)
+#define ADTn_ADDR(base, n)	(base + BUF_ADT_OFFSET + n * ADT_LEN)
+#define CATn_MLB_ADDR(base, n)	(base + BUF_CAT_MLB_OFFSET + n * CAT_LEN)
+#define CATn_HBI_ADDR(base, n)	(base + BUF_CAT_HBI_OFFSET + n * CAT_LEN)
+
+#define CAT_CL_SHIFT		(0x0)
+#define CAT_CT_SHIFT		(8)
+#define CAT_CE			(0x1 << 11)
+#define CAT_RNW			(0x1 << 12)
+#define CAT_MT			(0x1 << 13)
+#define CAT_FCE			(0x1 << 14)
+#define CAT_MFE			(0x1 << 14)
+
+#define CDT_WSBC_SHIFT		(14)
+#define CDT_WPC_SHIFT		(11)
+#define CDT_RSBC_SHIFT		(30)
+#define CDT_RPC_SHIFT		(27)
+#define CDT_WPC_1_SHIFT		(12)
+#define CDT_RPC_1_SHIFT		(28)
+#define CDT_WPTR_SHIFT		(0)
+#define CDT_SYNC_WSTS_MASK	(0x0000f000)
+#define CDT_SYNC_WSTS_SHIFT	(12)
+#define CDT_CTRL_ASYNC_WSTS_MASK	(0x0000f000)
+#define CDT_CTRL_ASYNC_WSTS_SHIFT	(12)
+#define CDT_ISOC_WSTS_MASK	(0x0000e000)
+#define CDT_ISOC_WSTS_SHIFT	(13)
+#define CDT_RPTR_SHIFT		(16)
+#define CDT_SYNC_RSTS_MASK	(0xf0000000)
+#define CDT_SYNC_RSTS_SHIFT	(28)
+#define CDT_CTRL_ASYNC_RSTS_MASK	(0xf0000000)
+#define CDT_CTRL_ASYNC_RSTS_SHIFT	(28)
+#define CDT_ISOC_RSTS_MASK	(0xe0000000)
+#define CDT_ISOC_RSTS_SHIFT	(29)
+#define CDT_CTRL_ASYNC_WSTS_1	(0x1 << 14)
+#define CDT_CTRL_ASYNC_RSTS_1	(0x1 << 15)
+#define CDT_BD_SHIFT		(0)
+#define CDT_BA_SHIFT		(16)
+#define CDT_BS_SHIFT		(0)
+#define CDT_BF_SHIFT		(31)
+
+#define ADT_PG			(0x1 << 13)
+#define ADT_LE			(0x1 << 14)
+#define ADT_CE			(0x1 << 15)
+#define ADT_BD1_SHIFT		(0)
+#define ADT_ERR1		(0x1 << 13)
+#define ADT_DNE1		(0x1 << 14)
+#define ADT_RDY1		(0x1 << 15)
+#define ADT_BD2_SHIFT		(16)
+#define ADT_ERR2		(0x1 << 29)
+#define ADT_DNE2		(0x1 << 30)
+#define ADT_RDY2		(0x1 << 31)
+#define ADT_BA1_SHIFT		(0x0)
+#define ADT_BA2_SHIFT		(0x0)
+#define ADT_PS1			(0x1 << 12)
+#define ADT_PS2			(0x1 << 28)
+#define ADT_MEP1		(0x1 << 11)
+#define ADT_MEP2		(0x1 << 27)
+
+#define MLB_MINOR_DEVICES	4
+#define MLB_CONTROL_DEV_NAME	"ctrl"
+#define MLB_ASYNC_DEV_NAME	"async"
+#define MLB_SYNC_DEV_NAME	"sync"
+#define MLB_ISOC_DEV_NAME	"isoc"
+
+#define TX_CHANNEL		0
+#define RX_CHANNEL		1
+
+#define TRANS_RING_NODES	(1 << 3)
+#define MLB_QUIRK_MLB150	(1 << 0)
+
+enum MLB_CTYPE {
+	MLB_CTYPE_SYNC,
+	MLB_CTYPE_CTRL,
+	MLB_CTYPE_ASYNC,
+	MLB_CTYPE_ISOC,
+};
+
+enum CLK_SPEED {
+	CLK_256FS,
+	CLK_512FS,
+	CLK_1024FS,
+	CLK_2048FS,
+	CLK_3072FS,
+	CLK_4096FS,
+	CLK_6144FS,
+	CLK_8192FS,
+};
+
+enum MLB_INDEX {
+	IMX6Q_MLB = 0,
+	IMX6SX_MLB,
+	IMX8QXP_MLB,
+};
+
+struct imx_mlb_hwdata {
+	enum MLB_INDEX	devtype;
+	u32		quirk_flag;
+};
+
+struct mlb_ringbuf {
+	s8 *virt_bufs[TRANS_RING_NODES];
+	u32 phy_addrs[TRANS_RING_NODES];
+	s32 head;
+	s32 tail;
+	s32 unit_size;
+	s32 total_size;
+	rwlock_t rb_lock ____cacheline_aligned; /* ring index lock */
+};
+
+struct mlb_channel_info {
+	/* Input MLB channel address */
+	u32 address;
+	/* Internal AHB channel label */
+	u32 cl;
+	/* DBR buf head */
+	u32 dbr_buf_head;
+};
+
+struct mlb_dev_info {
+	/* device node name */
+	const char dev_name[20];
+	/* channel type */
+	const unsigned int channel_type;
+	/* ch fps */
+	enum CLK_SPEED fps;
+	/* channel info for tx/rx */
+	struct mlb_channel_info channels[2];
+	/* ring buffer */
+	u8 *rbuf_base_virt;
+	u32 rbuf_base_phy;
+	struct mlb_ringbuf rx_rbuf;
+	struct mlb_ringbuf tx_rbuf;
+	/* exception event */
+	unsigned long ex_event;
+	/* tx busy indicator */
+	unsigned long tx_busy;
+	/* channel started up or not */
+	atomic_t on;
+	/* device open count */
+	atomic_t opencnt;
+	/* wait queue head for channel */
+	wait_queue_head_t rx_wq;
+	wait_queue_head_t tx_wq;
+	/* TX OK */
+	s32 tx_ok;
+	/* spinlock for event access */
+	spinlock_t event_lock;
+	/*
+	 * Block size for isoc mode
+	 * This variable can be configured in ioctl
+	 */
+	u32 isoc_blksz;
+	/*
+	 * Quads number for sync mode
+	 * This variable can be confifured in ioctl
+	 */
+	u32 sync_quad;
+	/* Buffer depth in cdt */
+	u32 cdt_buf_dep;
+	/* Buffer depth in adt */
+	u32 adt_buf_dep;
+	/* Buffer size to hold data */
+	u32 buf_size;
+};
+
+struct mlb_data {
+	struct device *dev;
+	struct mlb_dev_info *devinfo;
+	const struct imx_mlb_hwdata *hwdata;
+	struct clk *ipg;
+	struct clk *hclk;
+	struct clk *mlb;
+	struct cdev cdev;
+	struct class *class;	/* device class */
+	dev_t firstdev;
+#ifdef CONFIG_REGULATOR
+	struct regulator *nvcc;
+#endif
+	void __iomem *membase;	/* mlb module base address */
+	struct gen_pool *iram_pool;
+	u32 iram_size;
+	int irq_ahb0;
+	int irq_ahb1;
+	int irq_mlb;
+	bool use_iram;
+};
+
+/*
+ * For optimization, we use fixed channel label for
+ * input channels of each mode
+ * SYNC: CL = 0 for RX, CL = 64 for TX
+ * CTRL: CL = 1 for RX, CL = 65 for TX
+ * ASYNC: CL = 2 for RX, CL = 66 for TX
+ * ISOC: CL = 3 for RX, CL = 67 for TX
+ */
+#define SYNC_RX_CL_AHB0		0
+#define CTRL_RX_CL_AHB0		1
+#define ASYNC_RX_CL_AHB0	2
+#define ISOC_RX_CL_AHB0		3
+#define SYNC_TX_CL_AHB0		4
+#define CTRL_TX_CL_AHB0		5
+#define ASYNC_TX_CL_AHB0	6
+#define ISOC_TX_CL_AHB0		7
+
+#define SYNC_RX_CL_AHB1		32
+#define CTRL_RX_CL_AHB1		33
+#define ASYNC_RX_CL_AHB1	34
+#define ISOC_RX_CL_AHB1		35
+#define SYNC_TX_CL_AHB1		36
+#define CTRL_TX_CL_AHB1		37
+#define ASYNC_TX_CL_AHB1	38
+#define ISOC_TX_CL_AHB1		39
+
+#define SYNC_RX_CL	SYNC_RX_CL_AHB0
+#define CTRL_RX_CL	CTRL_RX_CL_AHB0
+#define ASYNC_RX_CL	ASYNC_RX_CL_AHB0
+#define ISOC_RX_CL	ISOC_RX_CL_AHB0
+
+#define SYNC_TX_CL	SYNC_TX_CL_AHB0
+#define CTRL_TX_CL	CTRL_TX_CL_AHB0
+#define ASYNC_TX_CL	ASYNC_TX_CL_AHB0
+#define ISOC_TX_CL	ISOC_TX_CL_AHB0
+
+static struct mlb_dev_info mlb_devinfo[MLB_MINOR_DEVICES] = {
+	{
+	.dev_name = MLB_SYNC_DEV_NAME,
+	.channel_type = MLB_CTYPE_SYNC,
+	.channels = {
+		[0] = {
+			.cl = SYNC_TX_CL,
+			.dbr_buf_head = CH_SYNC_DBR_BUF_OFFSET,
+		},
+		[1] = {
+			.cl = SYNC_RX_CL,
+			.dbr_buf_head = CH_SYNC_DBR_BUF_OFFSET
+					+ CH_SYNC_BUF_SZ,
+		},
+	},
+	.rx_rbuf = {
+		.unit_size = CH_SYNC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[0].rx_rbuf.rb_lock),
+	},
+	.tx_rbuf = {
+		.unit_size = CH_SYNC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[0].tx_rbuf.rb_lock),
+	},
+	.cdt_buf_dep = CH_SYNC_CDT_BUF_DEP,
+	.adt_buf_dep = CH_SYNC_ADT_BUF_DEP,
+	.buf_size = CH_SYNC_BUF_SZ,
+	.on = ATOMIC_INIT(0),
+	.opencnt = ATOMIC_INIT(0),
+	.event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[0].event_lock),
+	},
+	{
+	.dev_name = MLB_CONTROL_DEV_NAME,
+	.channel_type = MLB_CTYPE_CTRL,
+	.channels = {
+		[0] = {
+			.cl = CTRL_TX_CL,
+			.dbr_buf_head = CH_CTRL_DBR_BUF_OFFSET,
+		},
+		[1] = {
+			.cl = CTRL_RX_CL,
+			.dbr_buf_head = CH_CTRL_DBR_BUF_OFFSET
+					+ CH_CTRL_BUF_SZ,
+		},
+	},
+	.rx_rbuf = {
+		.unit_size = CH_CTRL_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[1].rx_rbuf.rb_lock),
+	},
+	.tx_rbuf = {
+		.unit_size = CH_CTRL_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[1].tx_rbuf.rb_lock),
+	},
+	.cdt_buf_dep = CH_CTRL_CDT_BUF_DEP,
+	.adt_buf_dep = CH_CTRL_ADT_BUF_DEP,
+	.buf_size = CH_CTRL_BUF_SZ,
+	.on = ATOMIC_INIT(0),
+	.opencnt = ATOMIC_INIT(0),
+	.event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[1].event_lock),
+	},
+	{
+	.dev_name = MLB_ASYNC_DEV_NAME,
+	.channel_type = MLB_CTYPE_ASYNC,
+	.channels = {
+		[0] = {
+			.cl = ASYNC_TX_CL,
+			.dbr_buf_head = CH_ASYNC_DBR_BUF_OFFSET,
+		},
+		[1] = {
+			.cl = ASYNC_RX_CL,
+			.dbr_buf_head = CH_ASYNC_DBR_BUF_OFFSET
+					+ CH_ASYNC_BUF_SZ,
+		},
+	},
+	.rx_rbuf = {
+		.unit_size = CH_ASYNC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[2].rx_rbuf.rb_lock),
+	},
+	.tx_rbuf = {
+		.unit_size = CH_ASYNC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[2].tx_rbuf.rb_lock),
+	},
+	.cdt_buf_dep = CH_ASYNC_CDT_BUF_DEP,
+	.adt_buf_dep = CH_ASYNC_ADT_BUF_DEP,
+	.buf_size = CH_ASYNC_BUF_SZ,
+	.on = ATOMIC_INIT(0),
+	.opencnt = ATOMIC_INIT(0),
+	.event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[2].event_lock),
+	},
+	{
+	.dev_name = MLB_ISOC_DEV_NAME,
+	.channel_type = MLB_CTYPE_ISOC,
+	.channels = {
+		[0] = {
+			.cl = ISOC_TX_CL,
+			.dbr_buf_head = CH_ISOC_DBR_BUF_OFFSET,
+		},
+		[1] = {
+			.cl = ISOC_RX_CL,
+			.dbr_buf_head = CH_ISOC_DBR_BUF_OFFSET
+					+ CH_ISOC_BUF_SZ,
+		},
+	},
+	.rx_rbuf = {
+		.unit_size = CH_ISOC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[3].rx_rbuf.rb_lock),
+	},
+	.tx_rbuf = {
+		.unit_size = CH_ISOC_BUF_SZ,
+		.rb_lock =
+			__RW_LOCK_UNLOCKED(mlb_devinfo[3].tx_rbuf.rb_lock),
+	},
+	.cdt_buf_dep = CH_ISOC_CDT_BUF_DEP,
+	.adt_buf_dep = CH_ISOC_ADT_BUF_DEP,
+	.buf_size = CH_ISOC_BUF_SZ,
+	.on = ATOMIC_INIT(0),
+	.opencnt = ATOMIC_INIT(0),
+	.event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[3].event_lock),
+	.isoc_blksz = CH_ISOC_BLK_SIZE_188,
+	},
+};
+
+static void __iomem *mlb_base;
+
+DEFINE_SPINLOCK(ctr_lock);
+
+#ifdef DEBUG
+#define DUMP_REG(reg) pr_debug(#reg": 0x%08x\n", __raw_readl(mlb_base + reg))
+
+static void mlb150_dev_dump_reg(void)
+{
+	pr_debug("mxc_mlb150: Dump registers:\n");
+	DUMP_REG(REG_MLBC0);
+	DUMP_REG(REG_MLBPC0);
+	DUMP_REG(REG_MS0);
+	DUMP_REG(REG_MS1);
+	DUMP_REG(REG_MSS);
+	DUMP_REG(REG_MSD);
+	DUMP_REG(REG_MIEN);
+	DUMP_REG(REG_MLBPC2);
+	DUMP_REG(REG_MLBPC1);
+	DUMP_REG(REG_MLBC1);
+	DUMP_REG(REG_HCTL);
+	DUMP_REG(REG_HCMR0);
+	DUMP_REG(REG_HCMR1);
+	DUMP_REG(REG_HCER0);
+	DUMP_REG(REG_HCER1);
+	DUMP_REG(REG_HCBR0);
+	DUMP_REG(REG_HCBR1);
+	DUMP_REG(REG_MDAT0);
+	DUMP_REG(REG_MDAT1);
+	DUMP_REG(REG_MDAT2);
+	DUMP_REG(REG_MDAT3);
+	DUMP_REG(REG_MDWE0);
+	DUMP_REG(REG_MDWE1);
+	DUMP_REG(REG_MDWE2);
+	DUMP_REG(REG_MDWE3);
+	DUMP_REG(REG_MCTL);
+	DUMP_REG(REG_MADR);
+	DUMP_REG(REG_ACTL);
+	DUMP_REG(REG_ACSR0);
+	DUMP_REG(REG_ACSR1);
+	DUMP_REG(REG_ACMR0);
+	DUMP_REG(REG_ACMR1);
+}
+
+static void mlb150_dev_dump_hex(const u8 *buf, u32 len)
+{
+	print_hex_dump(KERN_DEBUG, "CTR DUMP:",
+			DUMP_PREFIX_OFFSET, 8, 1, buf, len, 0);
+}
+#endif
+
+static inline int mlb150_is_imx8qxp_mlb(struct mlb_data *drvdata)
+{
+	return drvdata->hwdata->devtype == IMX8QXP_MLB;
+}
+
+static inline void mlb150_dev_enable_ctr_write(u32 mdat0_bits_en,
+		u32 mdat1_bits_en, u32 mdat2_bits_en, u32 mdat3_bits_en)
+{
+	__raw_writel(mdat0_bits_en, mlb_base + REG_MDWE0);
+	__raw_writel(mdat1_bits_en, mlb_base + REG_MDWE1);
+	__raw_writel(mdat2_bits_en, mlb_base + REG_MDWE2);
+	__raw_writel(mdat3_bits_en, mlb_base + REG_MDWE3);
+}
+
+#ifdef DEBUG
+static inline u8 mlb150_dev_dbr_read(u32 dbr_addr)
+{
+	s32 timeout = 1000;
+	u8  dbr_val = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctr_lock, flags);
+	__raw_writel(MADR_TB | dbr_addr,
+		mlb_base + REG_MADR);
+
+	while ((!(__raw_readl(mlb_base + REG_MCTL)
+			& MCTL_XCMP)) &&
+			timeout--)
+		;
+
+	if (0 == timeout) {
+		spin_unlock_irqrestore(&ctr_lock, flags);
+		return -ETIME;
+	}
+
+	dbr_val = __raw_readl(mlb_base + REG_MDAT0) & 0x000000ff;
+
+	__raw_writel(0, mlb_base + REG_MCTL);
+	spin_unlock_irqrestore(&ctr_lock, flags);
+
+	return dbr_val;
+}
+
+static inline s32 mlb150_dev_dbr_write(u32 dbr_addr, u8 dbr_val)
+{
+	s32 timeout = 1000;
+	u32 mdat0 = dbr_val & 0x000000ff;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctr_lock, flags);
+	__raw_writel(mdat0, mlb_base + REG_MDAT0);
+
+	__raw_writel(MADR_WNR | MADR_TB | dbr_addr,
+			mlb_base + REG_MADR);
+
+	while ((!(__raw_readl(mlb_base + REG_MCTL)
+			& MCTL_XCMP)) &&
+			timeout--)
+		;
+
+	if (timeout <= 0) {
+		spin_unlock_irqrestore(&ctr_lock, flags);
+		return -ETIME;
+	}
+
+	__raw_writel(0, mlb_base + REG_MCTL);
+	spin_unlock_irqrestore(&ctr_lock, flags);
+
+	return 0;
+}
+
+static inline s32 mlb150_dev_dbr_dump(u32 addr, u32 size)
+{
+	u8 *dump_buf = NULL;
+	u8 *buf_ptr = NULL;
+	s32 i;
+
+	dump_buf = kzalloc(size, GFP_KERNEL);
+	if (!dump_buf) {
+		pr_err("can't allocate enough memory\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, buf_ptr = dump_buf;
+			i < size; ++i, ++buf_ptr)
+		*buf_ptr = mlb150_dev_dbr_read(addr + i);
+
+	mlb150_dev_dump_hex(dump_buf, size);
+
+	kfree(dump_buf);
+
+	return 0;
+}
+#endif
+
+static s32 mlb150_dev_ctr_read(u32 ctr_offset, u32 *ctr_val)
+{
+	s32 timeout = 1000;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctr_lock, flags);
+	__raw_writel(ctr_offset, mlb_base + REG_MADR);
+
+	while ((!(__raw_readl(mlb_base + REG_MCTL)
+			& MCTL_XCMP)) &&
+			timeout--)
+		;
+
+	if (timeout <= 0) {
+		spin_unlock_irqrestore(&ctr_lock, flags);
+		pr_debug("mxc_mlb150: Read CTR timeout\n");
+		return -ETIME;
+	}
+
+	ctr_val[0] = __raw_readl(mlb_base + REG_MDAT0);
+	ctr_val[1] = __raw_readl(mlb_base + REG_MDAT1);
+	ctr_val[2] = __raw_readl(mlb_base + REG_MDAT2);
+	ctr_val[3] = __raw_readl(mlb_base + REG_MDAT3);
+
+	__raw_writel(0, mlb_base + REG_MCTL);
+
+	spin_unlock_irqrestore(&ctr_lock, flags);
+
+	return 0;
+}
+
+static s32 mlb150_dev_ctr_write(u32 ctr_offset, const u32 *ctr_val)
+{
+	s32 timeout = 1000;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctr_lock, flags);
+
+	__raw_writel(ctr_val[0], mlb_base + REG_MDAT0);
+	__raw_writel(ctr_val[1], mlb_base + REG_MDAT1);
+	__raw_writel(ctr_val[2], mlb_base + REG_MDAT2);
+	__raw_writel(ctr_val[3], mlb_base + REG_MDAT3);
+
+	__raw_writel(MADR_WNR | ctr_offset,
+			mlb_base + REG_MADR);
+
+	while ((!(__raw_readl(mlb_base + REG_MCTL)
+			& MCTL_XCMP)) &&
+			timeout--)
+		;
+
+	if (timeout <= 0) {
+		spin_unlock_irqrestore(&ctr_lock, flags);
+		pr_debug("mxc_mlb150: Write CTR timeout\n");
+		return -ETIME;
+	}
+
+	__raw_writel(0, mlb_base + REG_MCTL);
+
+	spin_unlock_irqrestore(&ctr_lock, flags);
+
+#ifdef DEBUG_CTR
+	{
+		u32 ctr_rd[4] = { 0 };
+
+		if (!mlb150_dev_ctr_read(ctr_offset, ctr_rd)) {
+			if (ctr_val[0] == ctr_rd[0] &&
+				ctr_val[1] == ctr_rd[1] &&
+				ctr_val[2] == ctr_rd[2] &&
+				ctr_val[3] == ctr_rd[3])
+				return 0;
+			else {
+				pr_debug("mxc_mlb150: ctr write failed\n");
+				pr_debug("offset: 0x%x\n", ctr_offset);
+				pr_debug("Write: 0x%x 0x%x 0x%x 0x%x\n",
+						ctr_val[3], ctr_val[2],
+						ctr_val[1], ctr_val[0]);
+				pr_debug("Read: 0x%x 0x%x 0x%x 0x%x\n",
+						ctr_rd[3], ctr_rd[2],
+						ctr_rd[1], ctr_rd[0]);
+				return -EBADE;
+			}
+		} else {
+			pr_debug("mxc_mlb150: ctr read failed\n");
+			return -EBADE;
+		}
+	}
+#endif
+
+	return 0;
+}
+
+#ifdef DEBUG
+static s32 mlb150_dev_cat_read(u32 ctr_offset, u32 ch, u16 *cat_val)
+{
+	u16 ctr_val[8] = { 0 };
+
+	if (mlb150_dev_ctr_read(ctr_offset, (u32 *)ctr_val))
+		return -ETIME;
+
+	/*
+	 * Use u16 array to get u32 array value,
+	 * need to convert
+	 */
+	cat_val = ctr_val[ch % 8];
+
+	 return 0;
+}
+#endif
+
+static s32 mlb150_dev_cat_write(u32 ctr_offset, u32 ch, const u16 cat_val)
+{
+	u16 ctr_val[8] = { 0 };
+
+	if (mlb150_dev_ctr_read(ctr_offset, (u32 *)ctr_val))
+		return -ETIME;
+
+	ctr_val[ch % 8] = cat_val;
+	if (mlb150_dev_ctr_write(ctr_offset, (u32 *)ctr_val))
+		return -ETIME;
+
+	return 0;
+}
+
+#define mlb150_dev_cat_mlb_read(ch, cat_val)	\
+	mlb150_dev_cat_read(BUF_CAT_MLB_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_mlb_write(ch, cat_val)	\
+	mlb150_dev_cat_write(BUF_CAT_MLB_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_hbi_read(ch, cat_val)	\
+	mlb150_dev_cat_read(BUF_CAT_HBI_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_hbi_write(ch, cat_val)	\
+	mlb150_dev_cat_write(BUF_CAT_HBI_OFFSET + (ch >> 3), ch, cat_val)
+
+#define mlb150_dev_cdt_read(ch, cdt_val)	\
+	mlb150_dev_ctr_read(BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_cdt_write(ch, cdt_val)	\
+	mlb150_dev_ctr_write(BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_adt_read(ch, adt_val)	\
+	mlb150_dev_ctr_read(BUF_ADT_OFFSET + ch, adt_val)
+#define mlb150_dev_adt_write(ch, adt_val)	\
+	mlb150_dev_ctr_write(BUF_ADT_OFFSET + ch, adt_val)
+
+static s32 mlb150_dev_get_adt_sts(u32 ch)
+{
+	s32 timeout = 1000;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ctr_lock, flags);
+	__raw_writel(BUF_ADT_OFFSET + ch,
+			mlb_base + REG_MADR);
+
+	while ((!(__raw_readl(mlb_base + REG_MCTL)
+			& MCTL_XCMP)) &&
+			timeout--)
+		;
+
+	if (timeout <= 0) {
+		spin_unlock_irqrestore(&ctr_lock, flags);
+		pr_debug("mxc_mlb150: Read CTR timeout\n");
+		return -ETIME;
+	}
+
+	reg = __raw_readl(mlb_base + REG_MDAT1);
+
+	__raw_writel(0, mlb_base + REG_MCTL);
+	spin_unlock_irqrestore(&ctr_lock, flags);
+
+#ifdef DEBUG_ADT
+	pr_debug("mxc_mlb150: Get ch %d adt sts: 0x%08x\n", ch, reg);
+#endif
+
+	return reg;
+}
+
+#ifdef DEBUG
+static void mlb150_dev_dump_ctr_tbl(u32 ch_start, u32 ch_end)
+{
+	u32 i = 0;
+	u32 ctr_val[4] = { 0 };
+
+	pr_debug("mxc_mlb150: CDT Table");
+	for (i = BUF_CDT_OFFSET + ch_start;
+			i < BUF_CDT_OFFSET + ch_end;
+			++i) {
+		mlb150_dev_ctr_read(i, ctr_val);
+		pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+	}
+
+	pr_debug("mxc_mlb150: ADT Table");
+	for (i = BUF_ADT_OFFSET + ch_start;
+			i < BUF_ADT_OFFSET + ch_end;
+			++i) {
+		mlb150_dev_ctr_read(i, ctr_val);
+		pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+	}
+
+	pr_debug("mxc_mlb150: CAT MLB Table");
+	for (i = BUF_CAT_MLB_OFFSET + (ch_start >> 3);
+			i <= BUF_CAT_MLB_OFFSET + ((ch_end + 8) >> 3);
+			++i) {
+		mlb150_dev_ctr_read(i, ctr_val);
+		pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+	}
+
+	pr_debug("mxc_mlb150: CAT HBI Table");
+	for (i = BUF_CAT_HBI_OFFSET + (ch_start >> 3);
+			i <= BUF_CAT_HBI_OFFSET + ((ch_end + 8) >> 3);
+			++i) {
+		mlb150_dev_ctr_read(i, ctr_val);
+		pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+			i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+	}
+}
+#endif
+
+/*
+ * Initial the MLB module device
+ */
+static inline void  mlb150_dev_enable_dma_irq(u32 enable)
+{
+	u32 ch_rx_mask = (1 << SYNC_RX_CL_AHB0) | (1 << CTRL_RX_CL_AHB0)
+			| (1 << ASYNC_RX_CL_AHB0) | (1 << ISOC_RX_CL_AHB0)
+			| (1 << SYNC_TX_CL_AHB0) | (1 << CTRL_TX_CL_AHB0)
+			| (1 << ASYNC_TX_CL_AHB0) | (1 << ISOC_TX_CL_AHB0);
+	u32 ch_tx_mask = (1 << (SYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (CTRL_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ASYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ISOC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (SYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (CTRL_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ASYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ISOC_TX_CL_AHB1 - INT_AHB1_CH_START));
+
+	if (enable) {
+		__raw_writel(ch_rx_mask, mlb_base + REG_ACMR0);
+		__raw_writel(ch_tx_mask, mlb_base + REG_ACMR1);
+	} else {
+		__raw_writel(0x0, mlb_base + REG_ACMR0);
+		__raw_writel(0x0, mlb_base + REG_ACMR1);
+	}
+}
+
+
+static void mlb150_dev_init_ir_amba_ahb(void)
+{
+	u32 reg = 0;
+
+	/*
+	 * Step 1. Program the ACMRn registers to enable interrupts from all
+	 * active DMA channels
+	 */
+	mlb150_dev_enable_dma_irq(1);
+
+	/*
+	 * Step 2. Select the status clear method:
+	 * ACTL.SCE = 0, hardware clears on read
+	 * ACTL.SCE = 1, software writes a '1' to clear
+	 * We only support DMA MODE 1
+	 */
+	reg = __raw_readl(mlb_base + REG_ACTL);
+	reg |= ACTL_DMAMODE;
+#ifdef MULTIPLE_PACKAGE_MODE
+	reg |= REG_ACTL_MPB;
+#endif
+
+	/*
+	 *  Step 3. Select 1 or 2 interrupt signals:
+	 * ACTL.SMX = 0: one interrupt for channels 0 - 31 on ahb_init[0]
+	 *	and another interrupt for channels 32 - 63 on ahb_init[1]
+	 * ACTL.SMX = 1: singel interrupt all channels on ahb_init[0]
+	 */
+	reg &= ~ACTL_SMX;
+
+	__raw_writel(reg, mlb_base + REG_ACTL);
+}
+
+static inline void mlb150_dev_enable_ir_mlb(u32 enable)
+{
+	/*
+	 * Step 1, Select the MSn to be cleared by software,
+	 * writing a '0' to the appropriate bits
+	 */
+	__raw_writel(0, mlb_base + REG_MS0);
+	__raw_writel(0, mlb_base + REG_MS1);
+
+	/*
+	 * Step 1, Program MIEN to enable protocol error
+	 * interrupts for all active MLB channels
+	 */
+	if (enable)
+		__raw_writel(MIEN_CTX_PE |
+			MIEN_CRX_PE | MIEN_ATX_PE |
+			MIEN_ARX_PE | MIEN_SYNC_PE |
+			MIEN_ISOC_PE,
+			mlb_base + REG_MIEN);
+	else
+		__raw_writel(0, mlb_base + REG_MIEN);
+}
+
+static inline void mlb150_enable_pll(struct mlb_data *drvdata)
+{
+	u32 c0_val;
+
+	__raw_writel(MLBPC1_VAL,
+			drvdata->membase + REG_MLBPC1);
+
+	c0_val = __raw_readl(drvdata->membase + REG_MLBC0);
+	if (c0_val & MLBC0_MLBPEN) {
+		c0_val &= ~MLBC0_MLBPEN;
+		__raw_writel(c0_val,
+				drvdata->membase + REG_MLBC0);
+	}
+
+	c0_val |= (MLBC0_MLBPEN);
+	__raw_writel(c0_val, drvdata->membase + REG_MLBC0);
+}
+
+static inline void mlb150_disable_pll(struct mlb_data *drvdata)
+{
+	u32 c0_val;
+
+	c0_val = __raw_readl(drvdata->membase + REG_MLBC0);
+
+	__raw_writel(0x0, drvdata->membase + REG_MLBPC1);
+
+	c0_val &= ~MLBC0_MLBPEN;
+	__raw_writel(c0_val, drvdata->membase + REG_MLBC0);
+}
+
+static void mlb150_dev_reset_cdt(void)
+{
+	int i = 0;
+	u32 ctr_val[4] = { 0 };
+
+	mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+			0xffffffff, 0xffffffff);
+
+	for (i = 0; i < (LOGIC_CH_NUM); ++i)
+		mlb150_dev_ctr_write(BUF_CDT_OFFSET + i, ctr_val);
+}
+
+static s32 mlb150_dev_init_ch_cdt(struct mlb_dev_info *pdevinfo, u32 ch,
+		enum MLB_CTYPE ctype, u32 ch_func)
+{
+	u32 cdt_val[4] = { 0 };
+
+	/* a. Set the 14-bit base address (BA) */
+	pr_debug("mxc_mlb150: ctype: %d, ch: %d, dbr_buf_head: 0x%08x",
+		ctype, ch, pdevinfo->channels[ch_func].dbr_buf_head);
+	cdt_val[3] = (pdevinfo->channels[ch_func].dbr_buf_head)
+			<< CDT_BA_SHIFT;
+	/*
+	 * b. Set the 12-bit or 13-bit buffer depth (BD)
+	 * BD = buffer depth in bytes - 1
+	 * For synchronous channels: (BD + 1) = 4 * m * bpf
+	 * For control channels: (BD + 1) >= max packet length (64)
+	 * For asynchronous channels: (BD + 1) >= max packet length
+	 * 1024 for a MOST Data packet (MDP);
+	 * 1536 for a MOST Ethernet Packet (MEP)
+	 * For isochronous channels: (BD + 1) mod (BS + 1) = 0
+	 * BS
+	 */
+	if (MLB_CTYPE_ISOC == ctype)
+		cdt_val[1] |= (pdevinfo->isoc_blksz - 1);
+	/* BD */
+	cdt_val[3] |= (pdevinfo->cdt_buf_dep - 1) << CDT_BD_SHIFT;
+
+	pr_debug("mxc_mlb150: Set CDT val of channel %d, type: %d: "
+		"0x%08x 0x%08x 0x%08x 0x%08x\n",
+		ch, ctype, cdt_val[3], cdt_val[2], cdt_val[1], cdt_val[0]);
+
+	if (mlb150_dev_cdt_write(ch, cdt_val))
+		return -ETIME;
+
+#ifdef DEBUG_CTR
+	{
+		u32 cdt_rd[4] = { 0 };
+		if (!mlb150_dev_cdt_read(ch, cdt_rd)) {
+			pr_debug("mxc_mlb150: CDT val of channel %d: "
+				"0x%08x 0x%08x 0x%08x 0x%08x\n",
+				ch, cdt_rd[3], cdt_rd[2], cdt_rd[1], cdt_rd[0]);
+			if (cdt_rd[3] == cdt_val[3] &&
+				cdt_rd[2] == cdt_val[2] &&
+				cdt_rd[1] == cdt_val[1] &&
+				cdt_rd[0] == cdt_val[0]) {
+				pr_debug("mxc_mlb150: set cdt succeed!\n");
+				return 0;
+			} else {
+				pr_debug("mxc_mlb150: set cdt failed!\n");
+				return -EBADE;
+			}
+		} else {
+			pr_debug("mxc_mlb150: Read CDT val of channel %d failed\n",
+					ch);
+			return -EBADE;
+		}
+	}
+#endif
+
+	return 0;
+}
+
+static s32 mlb150_dev_init_ch_cat(u32 ch, u32 cl,
+		u32 cat_mode, enum MLB_CTYPE ctype)
+{
+	u16 cat_val = 0;
+#ifdef DEBUG_CTR
+	u16 cat_rd = 0;
+#endif
+
+	cat_val = CAT_CE | (ctype << CAT_CT_SHIFT) | cl;
+
+	if (cat_mode & CAT_MODE_OUTBOUND_DMA)
+		cat_val |= CAT_RNW;
+
+	if (MLB_CTYPE_SYNC == ctype)
+		cat_val |= CAT_MT;
+
+	switch (cat_mode) {
+	case CAT_MODE_RX | CAT_MODE_INBOUND_DMA:
+	case CAT_MODE_TX | CAT_MODE_OUTBOUND_DMA:
+		pr_debug("mxc_mlb150: set CAT val of channel %d, type: %d: 0x%04x\n",
+			ch, ctype, cat_val);
+
+		if (mlb150_dev_cat_mlb_write(ch, cat_val))
+			return -ETIME;
+#ifdef DEBUG_CTR
+		if (!mlb150_dev_cat_mlb_read(ch, &cat_rd))
+			pr_debug("mxc_mlb150: CAT val of mlb channel %d: 0x%04x",
+					ch, cat_rd);
+		else {
+			pr_debug("mxc_mlb150: Read CAT of mlb channel %d failed\n",
+					ch);
+				return -EBADE;
+		}
+#endif
+		break;
+	case CAT_MODE_TX | CAT_MODE_INBOUND_DMA:
+	case CAT_MODE_RX | CAT_MODE_OUTBOUND_DMA:
+		pr_debug("mxc_mlb150: set CAT val of channel %d, type: %d: 0x%04x\n",
+			cl, ctype, cat_val);
+
+		if (mlb150_dev_cat_hbi_write(cl, cat_val))
+			return -ETIME;
+#ifdef DEBUG_CTR
+		if (!mlb150_dev_cat_hbi_read(cl, &cat_rd))
+			pr_debug("mxc_mlb150: CAT val of hbi channel %d: 0x%04x",
+					cl, cat_rd);
+		else {
+			pr_debug("mxc_mlb150: Read CAT of hbi channel %d failed\n",
+					cl);
+				return -EBADE;
+		}
+#endif
+		break;
+	default:
+		return EBADRQC;
+	}
+
+#ifdef DEBUG_CTR
+	{
+		if (cat_val == cat_rd) {
+			pr_debug("mxc_mlb150: set cat succeed!\n");
+			return 0;
+		} else {
+			pr_debug("mxc_mlb150: set cat failed!\n");
+			return -EBADE;
+		}
+	}
+#endif
+	return 0;
+}
+
+static void mlb150_dev_reset_cat(void)
+{
+	int i = 0;
+	u32 ctr_val[4] = { 0 };
+
+	mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+			0xffffffff, 0xffffffff);
+
+	for (i = 0; i < (LOGIC_CH_NUM >> 3); ++i) {
+		mlb150_dev_ctr_write(BUF_CAT_MLB_OFFSET + i, ctr_val);
+		mlb150_dev_ctr_write(BUF_CAT_HBI_OFFSET + i, ctr_val);
+	}
+}
+
+static void mlb150_dev_init_rfb(struct mlb_dev_info *pdevinfo, u32 rx_ch,
+		u32 tx_ch, enum MLB_CTYPE ctype)
+{
+	u32 rx_cl = pdevinfo->channels[RX_CHANNEL].cl;
+	u32 tx_cl = pdevinfo->channels[TX_CHANNEL].cl;
+	/* Step 1, Initialize all bits of CAT to '0' */
+	mlb150_dev_reset_cat();
+	mlb150_dev_reset_cdt();
+	/*
+	 * Step 2, Initialize logical channel
+	 * Step 3, Program the CDT for channel N
+	 */
+	mlb150_dev_init_ch_cdt(pdevinfo, rx_cl, ctype, RX_CHANNEL);
+	mlb150_dev_init_ch_cdt(pdevinfo, tx_cl, ctype, TX_CHANNEL);
+
+	/* Step 4&5, Program the CAT for the inbound and outbound DMA */
+	mlb150_dev_init_ch_cat(rx_ch, rx_cl,
+			CAT_MODE_RX | CAT_MODE_INBOUND_DMA,
+			ctype);
+	mlb150_dev_init_ch_cat(rx_ch, rx_cl,
+			CAT_MODE_RX | CAT_MODE_OUTBOUND_DMA,
+			ctype);
+	mlb150_dev_init_ch_cat(tx_ch, tx_cl,
+			CAT_MODE_TX | CAT_MODE_INBOUND_DMA,
+			ctype);
+	mlb150_dev_init_ch_cat(tx_ch, tx_cl,
+			CAT_MODE_TX | CAT_MODE_OUTBOUND_DMA,
+			ctype);
+}
+
+static void mlb150_dev_reset_adt(void)
+{
+	int i = 0;
+	u32 ctr_val[4] = { 0 };
+
+	mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+			0xffffffff, 0xffffffff);
+
+	for (i = 0; i < (LOGIC_CH_NUM); ++i)
+		mlb150_dev_ctr_write(BUF_ADT_OFFSET + i, ctr_val);
+}
+
+static void mlb150_dev_reset_whole_ctr(void)
+{
+	mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+			0xffffffff, 0xffffffff);
+	mlb150_dev_reset_cdt();
+	mlb150_dev_reset_adt();
+	mlb150_dev_reset_cat();
+}
+
+#define CLR_REG(reg)  __raw_writel(0x0, mlb_base + reg)
+
+static void mlb150_dev_reset_all_regs(void)
+{
+	CLR_REG(REG_MLBC0);
+	CLR_REG(REG_MLBPC0);
+	CLR_REG(REG_MS0);
+	CLR_REG(REG_MS1);
+	CLR_REG(REG_MSS);
+	CLR_REG(REG_MSD);
+	CLR_REG(REG_MIEN);
+	CLR_REG(REG_MLBPC2);
+	CLR_REG(REG_MLBPC1);
+	CLR_REG(REG_MLBC1);
+	CLR_REG(REG_HCTL);
+	CLR_REG(REG_HCMR0);
+	CLR_REG(REG_HCMR1);
+	CLR_REG(REG_HCER0);
+	CLR_REG(REG_HCER1);
+	CLR_REG(REG_HCBR0);
+	CLR_REG(REG_HCBR1);
+	CLR_REG(REG_MDAT0);
+	CLR_REG(REG_MDAT1);
+	CLR_REG(REG_MDAT2);
+	CLR_REG(REG_MDAT3);
+	CLR_REG(REG_MDWE0);
+	CLR_REG(REG_MDWE1);
+	CLR_REG(REG_MDWE2);
+	CLR_REG(REG_MDWE3);
+	CLR_REG(REG_MCTL);
+	CLR_REG(REG_MADR);
+	CLR_REG(REG_ACTL);
+	CLR_REG(REG_ACSR0);
+	CLR_REG(REG_ACSR1);
+	CLR_REG(REG_ACMR0);
+	CLR_REG(REG_ACMR1);
+}
+
+static inline s32 mlb150_dev_pipo_start(struct mlb_ringbuf *rbuf,
+						u32 ahb_ch, u32 buf_addr)
+{
+	u32 ctr_val[4] = { 0 };
+
+	ctr_val[1] |= ADT_RDY1;
+	ctr_val[2] = buf_addr;
+
+	if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+		return -ETIME;
+
+	return 0;
+}
+
+static inline s32 mlb150_dev_pipo_next(u32 ahb_ch, enum MLB_CTYPE ctype,
+				u32 dne_sts, u32 buf_addr)
+{
+	u32 ctr_val[4] = { 0 };
+
+	if (MLB_CTYPE_ASYNC == ctype ||
+		MLB_CTYPE_CTRL == ctype) {
+		ctr_val[1] |= ADT_PS1;
+		ctr_val[1] |= ADT_PS2;
+	}
+
+	/*
+	 * Clear DNE1 and ERR1
+	 * Set the page ready bit (RDY1)
+	 */
+	if (dne_sts & ADT_DNE1) {
+		ctr_val[1] |= ADT_RDY2;
+		ctr_val[3] = buf_addr;
+	} else {
+		ctr_val[1] |= ADT_RDY1;
+		ctr_val[2] = buf_addr;
+	}
+
+	if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+		return -ETIME;
+
+	return 0;
+}
+
+static inline s32 mlb150_dev_pipo_stop(struct mlb_ringbuf *rbuf, u32 ahb_ch)
+{
+	u32 ctr_val[4] = { 0 };
+	unsigned long flags;
+
+	write_lock_irqsave(&rbuf->rb_lock, flags);
+	rbuf->head = rbuf->tail = 0;
+	write_unlock_irqrestore(&rbuf->rb_lock, flags);
+
+	if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+		return -ETIME;
+
+	return 0;
+}
+
+static s32 mlb150_dev_init_ch_amba_ahb(struct mlb_dev_info *pdevinfo,
+					struct mlb_channel_info *chinfo,
+					enum MLB_CTYPE ctype)
+{
+	u32 ctr_val[4] = { 0 };
+
+	/* a. Set the 32-bit base address (BA1) */
+	ctr_val[3] = 0;
+	ctr_val[2] = 0;
+	ctr_val[1] = (pdevinfo->adt_buf_dep - 1) << ADT_BD1_SHIFT;
+	ctr_val[1] |= (pdevinfo->adt_buf_dep - 1) << ADT_BD2_SHIFT;
+	if (MLB_CTYPE_ASYNC == ctype ||
+		MLB_CTYPE_CTRL == ctype) {
+		ctr_val[1] |= ADT_PS1;
+		ctr_val[1] |= ADT_PS2;
+	}
+
+	ctr_val[0] |= (ADT_LE | ADT_CE);
+
+	pr_debug("mxc_mlb150: Set ADT val of channel %d, ctype: %d: "
+		"0x%08x 0x%08x 0x%08x 0x%08x\n",
+		chinfo->cl, ctype, ctr_val[3], ctr_val[2],
+		ctr_val[1], ctr_val[0]);
+
+	if (mlb150_dev_adt_write(chinfo->cl, ctr_val))
+		return -ETIME;
+
+#ifdef DEBUG_CTR
+	{
+		u32 ctr_rd[4] = { 0 };
+		if (!mlb150_dev_adt_read(chinfo->cl, ctr_rd)) {
+			pr_debug("mxc_mlb150: ADT val of channel %d: "
+				"0x%08x 0x%08x 0x%08x 0x%08x\n",
+				chinfo->cl, ctr_rd[3], ctr_rd[2],
+				ctr_rd[1], ctr_rd[0]);
+			if (ctr_rd[3] == ctr_val[3] &&
+				ctr_rd[2] == ctr_val[2] &&
+				ctr_rd[1] == ctr_val[1] &&
+				ctr_rd[0] == ctr_val[0]) {
+				pr_debug("mxc_mlb150: set adt succeed!\n");
+				return 0;
+			} else {
+				pr_debug("mxc_mlb150: set adt failed!\n");
+				return -EBADE;
+			}
+		} else {
+			pr_debug("mxc_mlb150: Read ADT val of channel %d failed\n",
+					chinfo->cl);
+			return -EBADE;
+		}
+	}
+#endif
+
+	return 0;
+}
+
+static void mlb150_dev_init_amba_ahb(struct mlb_dev_info *pdevinfo,
+					enum MLB_CTYPE ctype)
+{
+	struct mlb_channel_info *tx_chinfo = &pdevinfo->channels[TX_CHANNEL];
+	struct mlb_channel_info *rx_chinfo = &pdevinfo->channels[RX_CHANNEL];
+
+	/* Step 1, Initialize all bits of the ADT to '0' */
+	mlb150_dev_reset_adt();
+
+	/*
+	 * Step 2, Select a logic channel
+	 * Step 3, Program the AMBA AHB block ping page for channel N
+	 * Step 4, Program the AMBA AHB block pong page for channel N
+	 */
+	mlb150_dev_init_ch_amba_ahb(pdevinfo, rx_chinfo, ctype);
+	mlb150_dev_init_ch_amba_ahb(pdevinfo, tx_chinfo, ctype);
+}
+
+static void mlb150_dev_exit(void)
+{
+	u32 c0_val, hctl_val;
+
+	/* Disable EN bits */
+	c0_val = __raw_readl(mlb_base + REG_MLBC0);
+	c0_val &= ~(MLBC0_MLBEN | MLBC0_MLBPEN);
+	__raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+	hctl_val = __raw_readl(mlb_base + REG_HCTL);
+	hctl_val &= ~HCTL_EN;
+	__raw_writel(hctl_val, mlb_base + REG_HCTL);
+
+	__raw_writel(0x0, mlb_base + REG_HCMR0);
+	__raw_writel(0x0, mlb_base + REG_HCMR1);
+
+	mlb150_dev_enable_dma_irq(0);
+	mlb150_dev_enable_ir_mlb(0);
+}
+
+static void mlb150_dev_init(void)
+{
+	u32 c0_val;
+	u32 ch_rx_mask = (1 << SYNC_RX_CL_AHB0) | (1 << CTRL_RX_CL_AHB0)
+			| (1 << ASYNC_RX_CL_AHB0) | (1 << ISOC_RX_CL_AHB0)
+			| (1 << SYNC_TX_CL_AHB0) | (1 << CTRL_TX_CL_AHB0)
+			| (1 << ASYNC_TX_CL_AHB0) | (1 << ISOC_TX_CL_AHB0);
+	u32 ch_tx_mask = (1 << (SYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (CTRL_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ASYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ISOC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (SYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (CTRL_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ASYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+			(1 << (ISOC_TX_CL_AHB1 - INT_AHB1_CH_START));
+
+	/* Disable EN bits */
+	mlb150_dev_exit();
+
+	/*
+	 * Step 1. Initialize CTR and registers
+	 * a. Set all bit of the CTR (CAT, CDT, and ADT) to 0.
+	 */
+	mlb150_dev_reset_whole_ctr();
+
+	/* a. Set all bit of the CTR (CAT, CDT, and ADT) to 0. */
+	mlb150_dev_reset_all_regs();
+
+	/*
+	 * Step 2, Configure the MediaLB interface
+	 * Select pin mode and clock, 3-pin and 256fs
+	 */
+	c0_val = __raw_readl(mlb_base + REG_MLBC0);
+	c0_val &= ~(MLBC0_MLBPEN | MLBC0_MLBCLK_MASK);
+	__raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+	c0_val |= MLBC0_MLBEN;
+	__raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+	/* Step 3, Configure the HBI interface */
+	__raw_writel(ch_rx_mask, mlb_base + REG_HCMR0);
+	__raw_writel(ch_tx_mask, mlb_base + REG_HCMR1);
+	__raw_writel(HCTL_EN, mlb_base + REG_HCTL);
+
+	mlb150_dev_init_ir_amba_ahb();
+
+	mlb150_dev_enable_ir_mlb(1);
+}
+
+static s32 mlb150_dev_unmute_syn_ch(u32 rx_ch, u32 rx_cl, u32 tx_ch, u32 tx_cl)
+{
+	u32 timeout = 10000;
+
+	/*
+	 * Check that MediaLB clock is running (MLBC1.CLKM = 0)
+	 * If MLBC1.CLKM = 1, clear the register bit, wait one
+	 * APB or I/O clock cycle and repeat the check
+	 */
+	while ((__raw_readl(mlb_base + REG_MLBC1) & MLBC1_CLKM)
+			&& --timeout)
+		__raw_writel(~MLBC1_CLKM, mlb_base + REG_MLBC1);
+
+	if (0 == timeout)
+		return -ETIME;
+
+	timeout = 10000;
+	/* Poll for MLB lock (MLBC0.MLBLK = 1) */
+	while (!(__raw_readl(mlb_base + REG_MLBC0) & MLBC0_MLBLK)
+			&& --timeout)
+		;
+
+	if (0 == timeout)
+		return -ETIME;
+
+	/* Unmute synchronous channel(s) */
+	mlb150_dev_cat_mlb_write(rx_ch, CAT_CE | rx_cl);
+	mlb150_dev_cat_mlb_write(tx_ch,
+			CAT_CE | tx_cl | CAT_RNW);
+	mlb150_dev_cat_hbi_write(rx_cl,
+			CAT_CE | rx_cl | CAT_RNW);
+	mlb150_dev_cat_hbi_write(tx_cl, CAT_CE | tx_cl);
+
+	return 0;
+}
+
+/* In case the user calls channel shutdown, but rx or tx is not completed yet */
+static s32 mlb150_trans_complete_check(struct mlb_dev_info *pdevinfo)
+{
+	struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+	struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+	s32 timeout = 1024;
+	unsigned long flags;
+
+	while (timeout--) {
+		read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+		if (!CIRC_CNT(tx_rbuf->head, tx_rbuf->tail, TRANS_RING_NODES)) {
+			read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+			break;
+		} else
+			read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+	}
+
+	if (timeout <= 0) {
+		pr_debug("TX complete check timeout!\n");
+		return -ETIME;
+	}
+
+	timeout = 1024;
+	while (timeout--) {
+		read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+		if (!CIRC_CNT(rx_rbuf->head, rx_rbuf->tail, TRANS_RING_NODES)) {
+			read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+			break;
+		} else
+			read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+	}
+
+	if (timeout <= 0) {
+		pr_debug("RX complete check timeout!\n");
+		return -ETIME;
+	}
+
+	/*
+	 * Interrupt from TX can only inform that the data is sent
+	 * to AHB bus, not mean that it is sent to MITB. Thus we add
+	 * a delay here for data to be completed sent.
+	 */
+	udelay(1000);
+
+	return 0;
+}
+
+/*
+ * Enable/Disable the MLB IRQ
+ */
+static void mxc_mlb150_irq_enable(struct mlb_data *drvdata, u8 enable)
+{
+	if (enable) {
+		enable_irq(drvdata->irq_ahb0);
+		enable_irq(drvdata->irq_mlb);
+		if (drvdata->irq_ahb1 > 0)
+			enable_irq(drvdata->irq_ahb1);
+	} else {
+		disable_irq(drvdata->irq_ahb0);
+		disable_irq(drvdata->irq_mlb);
+		if (drvdata->irq_ahb1 > 0)
+			disable_irq(drvdata->irq_ahb1);
+	}
+}
+
+/*
+ * Enable the MLB channel
+ */
+static s32 mlb_channel_enable(struct mlb_data *drvdata,
+				int chan_dev_id, int on)
+{
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+	struct mlb_channel_info *tx_chinfo = &pdevinfo->channels[TX_CHANNEL];
+	struct mlb_channel_info *rx_chinfo = &pdevinfo->channels[RX_CHANNEL];
+	u32 tx_ch = tx_chinfo->address;
+	u32 rx_ch = rx_chinfo->address;
+	u32 tx_cl = tx_chinfo->cl;
+	u32 rx_cl = rx_chinfo->cl;
+	s32 ret = 0;
+
+	/*
+	 * setup the direction, enable, channel type,
+	 * mode select, channel address and mask buf start
+	 */
+	if (on) {
+		u32 ctype = pdevinfo->channel_type;
+
+		mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+				0xffffffff, 0xffffffff);
+		mlb150_dev_init_rfb(pdevinfo, rx_ch, tx_ch, ctype);
+
+		mlb150_dev_init_amba_ahb(pdevinfo, ctype);
+
+#ifdef DEBUG
+		mlb150_dev_dump_ctr_tbl(0, tx_chinfo->cl + 1);
+#endif
+		/* Synchronize and unmute synchrouous channel */
+		if (MLB_CTYPE_SYNC == ctype) {
+			ret = mlb150_dev_unmute_syn_ch(rx_ch, rx_cl,
+							tx_ch, tx_cl);
+			if (ret)
+				return ret;
+		}
+
+		mlb150_dev_enable_ctr_write(0x0, ADT_RDY1 | ADT_DNE1 |
+				ADT_ERR1 | ADT_PS1 |
+				ADT_RDY2 | ADT_DNE2 | ADT_ERR2 | ADT_PS2,
+				0xffffffff, 0xffffffff);
+
+		if (pdevinfo->fps >= CLK_2048FS)
+			mlb150_enable_pll(drvdata);
+
+		atomic_set(&pdevinfo->on, 1);
+
+#ifdef DEBUG
+		mlb150_dev_dump_reg();
+		mlb150_dev_dump_ctr_tbl(0, tx_chinfo->cl + 1);
+#endif
+		/* Init RX ADT */
+		mlb150_dev_pipo_start(&pdevinfo->rx_rbuf, rx_cl,
+					pdevinfo->rx_rbuf.phy_addrs[0]);
+	} else {
+		mlb150_dev_pipo_stop(&pdevinfo->rx_rbuf, rx_cl);
+
+		mlb150_dev_enable_dma_irq(0);
+		mlb150_dev_enable_ir_mlb(0);
+
+		mlb150_dev_reset_cat();
+
+		atomic_set(&pdevinfo->on, 0);
+
+		if (pdevinfo->fps >= CLK_2048FS)
+			mlb150_disable_pll(drvdata);
+	}
+
+	return 0;
+}
+
+/*
+ * MLB interrupt handler
+ */
+static void mlb_rx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
+{
+	struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+	s32 head, tail, adt_sts;
+	u32 rx_buf_ptr;
+
+#ifdef DEBUG_RX
+	pr_debug("mxc_mlb150: mlb_rx_isr\n");
+#endif
+
+	read_lock(&rx_rbuf->rb_lock);
+
+	head = (rx_rbuf->head + 1) & (TRANS_RING_NODES - 1);
+	tail = READ_ONCE(rx_rbuf->tail);
+	read_unlock(&rx_rbuf->rb_lock);
+
+	if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1) {
+		rx_buf_ptr = rx_rbuf->phy_addrs[head];
+
+		/* commit the item before incrementing the head */
+		smp_wmb();
+
+		write_lock(&rx_rbuf->rb_lock);
+		rx_rbuf->head = head;
+		write_unlock(&rx_rbuf->rb_lock);
+
+		/* wake up the reader */
+		wake_up_interruptible(&pdevinfo->rx_wq);
+	} else {
+		rx_buf_ptr = rx_rbuf->phy_addrs[head];
+		pr_debug("drop RX package, due to no space, (%d,%d)\n",
+				head, tail);
+	}
+
+	adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+	/*  Set ADT for RX */
+	mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, rx_buf_ptr);
+}
+
+static void mlb_tx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
+{
+	struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+	s32 head, tail, adt_sts;
+	u32 tx_buf_ptr;
+
+	read_lock(&tx_rbuf->rb_lock);
+
+	head = READ_ONCE(tx_rbuf->head);
+	tail = (tx_rbuf->tail + 1) & (TRANS_RING_NODES - 1);
+	read_unlock(&tx_rbuf->rb_lock);
+
+	smp_mb();
+	write_lock(&tx_rbuf->rb_lock);
+	tx_rbuf->tail = tail;
+	write_unlock(&tx_rbuf->rb_lock);
+
+	/* check the current tx buffer is available or not */
+	if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1) {
+		/* read index before reading contents at that index */
+		smp_read_barrier_depends();
+
+		tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+
+		wake_up_interruptible(&pdevinfo->tx_wq);
+
+		adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+		/*  Set ADT for TX */
+		mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+	}
+}
+
+static irqreturn_t mlb_ahb_isr(int irq, void *dev_id)
+{
+	u32 acsr0, hcer0;
+	u32 ch_mask = (1 << SYNC_RX_CL) | (1 << CTRL_RX_CL)
+			| (1 << ASYNC_RX_CL) | (1 << ISOC_RX_CL)
+			| (1 << SYNC_TX_CL) | (1 << CTRL_TX_CL)
+			| (1 << ASYNC_TX_CL) | (1 << ISOC_TX_CL);
+
+	/*
+	 * Step 5, Read the ACSRn registers to determine which channel or
+	 * channels are causing the interrupt
+	 */
+	acsr0 = __raw_readl(mlb_base + REG_ACSR0);
+
+	hcer0 = __raw_readl(mlb_base + REG_HCER0);
+
+	/*
+	 * Step 6, If ACTL.SCE = 1, write the result of step 5 back to ACSR0
+	 * and ACSR1 to clear the interrupt
+	 * We'll not set ACTL_SCE
+	 */
+
+	if (ch_mask & hcer0)
+		pr_err("CH encounters an AHB error: 0x%x\n", hcer0);
+
+	if ((1 << SYNC_RX_CL) & acsr0)
+		mlb_rx_isr(MLB_CTYPE_SYNC, SYNC_RX_CL,
+				&mlb_devinfo[MLB_CTYPE_SYNC]);
+
+	if ((1 << CTRL_RX_CL) & acsr0)
+		mlb_rx_isr(MLB_CTYPE_CTRL, CTRL_RX_CL,
+				&mlb_devinfo[MLB_CTYPE_CTRL]);
+
+	if ((1 << ASYNC_RX_CL) & acsr0)
+		mlb_rx_isr(MLB_CTYPE_ASYNC, ASYNC_RX_CL,
+				&mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+	if ((1 << ISOC_RX_CL) & acsr0)
+		mlb_rx_isr(MLB_CTYPE_ISOC, ISOC_RX_CL,
+				&mlb_devinfo[MLB_CTYPE_ISOC]);
+
+	if ((1 << SYNC_TX_CL) & acsr0)
+		mlb_tx_isr(MLB_CTYPE_SYNC, SYNC_TX_CL,
+				&mlb_devinfo[MLB_CTYPE_SYNC]);
+
+	if ((1 << CTRL_TX_CL) & acsr0)
+		mlb_tx_isr(MLB_CTYPE_CTRL, CTRL_TX_CL,
+				&mlb_devinfo[MLB_CTYPE_CTRL]);
+
+	if ((1 << ASYNC_TX_CL) & acsr0)
+		mlb_tx_isr(MLB_CTYPE_ASYNC, ASYNC_TX_CL,
+				&mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+	if ((1 << ISOC_TX_CL) & acsr0)
+		mlb_tx_isr(MLB_CTYPE_ASYNC, ISOC_TX_CL,
+				&mlb_devinfo[MLB_CTYPE_ISOC]);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mlb_isr(int irq, void *dev_id)
+{
+	u32 rx_int_sts, tx_int_sts, ms0,
+		ms1, tx_cis, rx_cis, ctype;
+	int minor;
+	u32 cdt_val[4] = { 0 };
+
+	/*
+	 * Step 4, Read the MSn register to determine which channel(s)
+	 * are causing the interrupt
+	 */
+	ms0 = __raw_readl(mlb_base + REG_MS0);
+	ms1 = __raw_readl(mlb_base + REG_MS1);
+
+	/*
+	 * The MLB150_MS0, MLB150_MS1 registers need to be cleared. In
+	 * the spec description, the registers should  be cleared when
+	 * enabling interrupt. In fact, we also should clear it in ISR.
+	 */
+	__raw_writel(0, mlb_base + REG_MS0);
+	__raw_writel(0, mlb_base + REG_MS1);
+
+	pr_debug("mxc_mlb150: mlb interrupt:0x%08x 0x%08x\n",
+			(u32)ms0, (u32)ms1);
+
+	for (minor = 0; minor < MLB_MINOR_DEVICES; minor++) {
+		struct mlb_dev_info *pdevinfo = &mlb_devinfo[minor];
+		u32 rx_mlb_ch = pdevinfo->channels[RX_CHANNEL].address;
+		u32 tx_mlb_ch = pdevinfo->channels[TX_CHANNEL].address;
+		u32 rx_mlb_cl = pdevinfo->channels[RX_CHANNEL].cl;
+		u32 tx_mlb_cl = pdevinfo->channels[TX_CHANNEL].cl;
+
+		tx_cis = rx_cis = 0;
+
+		ctype = pdevinfo->channel_type;
+		rx_int_sts = (rx_mlb_ch < 31) ? ms0 : ms1;
+		tx_int_sts = (tx_mlb_ch < 31) ? ms0 : ms1;
+
+		pr_debug("mxc_mlb150: channel interrupt: "
+				"tx %d: 0x%08x, rx %d: 0x%08x\n",
+			tx_mlb_ch, (u32)tx_int_sts, rx_mlb_ch, (u32)rx_int_sts);
+
+		/* Get tx channel interrupt status */
+		if (tx_int_sts & (1 << (tx_mlb_ch % 32))) {
+			mlb150_dev_cdt_read(tx_mlb_cl, cdt_val);
+			pr_debug("mxc_mlb150: TX_CH: %d, cdt_val[3]: 0x%08x, "
+					"cdt_val[2]: 0x%08x, "
+					"cdt_val[1]: 0x%08x, "
+					"cdt_val[0]: 0x%08x\n",
+					tx_mlb_ch, cdt_val[3], cdt_val[2],
+					cdt_val[1], cdt_val[0]);
+			switch (ctype) {
+			case MLB_CTYPE_SYNC:
+				tx_cis = (cdt_val[2] & CDT_SYNC_WSTS_MASK)
+					>> CDT_SYNC_WSTS_SHIFT;
+				/*
+				 * Clear RSTS/WSTS errors to resume
+				 * channel operation
+				 * a. For synchronous channels: WSTS[3] = 0
+				 */
+				cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+				break;
+			case MLB_CTYPE_CTRL:
+			case MLB_CTYPE_ASYNC:
+				tx_cis = (cdt_val[2] &
+					CDT_CTRL_ASYNC_WSTS_MASK)
+					>> CDT_CTRL_ASYNC_WSTS_SHIFT;
+				tx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_WSTS_1) ?
+					(tx_cis | (0x1 << 4)) : tx_cis;
+				/*
+				 * b. For async and ctrl channels:
+				 * RSTS[4]/WSTS[4] = 0
+				 * and RSTS[2]/WSTS[2] = 0
+				 */
+				cdt_val[3] &= ~CDT_CTRL_ASYNC_WSTS_1;
+				cdt_val[2] &=
+					~(0x4 << CDT_CTRL_ASYNC_WSTS_SHIFT);
+				break;
+			case MLB_CTYPE_ISOC:
+				tx_cis = (cdt_val[2] & CDT_ISOC_WSTS_MASK)
+					>> CDT_ISOC_WSTS_SHIFT;
+				/* c. For isoc channels: WSTS[2:1] = 0x00 */
+				cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+				break;
+			default:
+				break;
+			}
+			mlb150_dev_cdt_write(tx_mlb_ch, cdt_val);
+		}
+
+		/* Get rx channel interrupt status */
+		if (rx_int_sts & (1 << (rx_mlb_ch % 32))) {
+			mlb150_dev_cdt_read(rx_mlb_cl, cdt_val);
+			pr_debug("mxc_mlb150: RX_CH: %d, cdt_val[3]: 0x%08x, "
+					"cdt_val[2]: 0x%08x, "
+					"cdt_val[1]: 0x%08x, "
+					"cdt_val[0]: 0x%08x\n",
+					rx_mlb_ch, cdt_val[3], cdt_val[2],
+					cdt_val[1], cdt_val[0]);
+			switch (ctype) {
+			case MLB_CTYPE_SYNC:
+				rx_cis = (cdt_val[2] & CDT_SYNC_RSTS_MASK)
+					>> CDT_SYNC_RSTS_SHIFT;
+				cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+				break;
+			case MLB_CTYPE_CTRL:
+			case MLB_CTYPE_ASYNC:
+				rx_cis =
+					(cdt_val[2] & CDT_CTRL_ASYNC_RSTS_MASK)
+					>> CDT_CTRL_ASYNC_RSTS_SHIFT;
+				rx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_RSTS_1) ?
+					(rx_cis | (0x1 << 4)) : rx_cis;
+				cdt_val[3] &= ~CDT_CTRL_ASYNC_RSTS_1;
+				cdt_val[2] &=
+					~(0x4 << CDT_CTRL_ASYNC_RSTS_SHIFT);
+				break;
+			case MLB_CTYPE_ISOC:
+				rx_cis = (cdt_val[2] & CDT_ISOC_RSTS_MASK)
+					>> CDT_ISOC_RSTS_SHIFT;
+				cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+				break;
+			default:
+				break;
+			}
+			mlb150_dev_cdt_write(rx_mlb_ch, cdt_val);
+		}
+
+		if (!tx_cis && !rx_cis)
+			continue;
+
+		/* fill exception event */
+		spin_lock(&pdevinfo->event_lock);
+		pdevinfo->ex_event |= (rx_cis << 16) | tx_cis;
+		spin_unlock(&pdevinfo->event_lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mxc_mlb150_open(struct inode *inode, struct file *filp)
+{
+	int minor, ring_buf_size, buf_size, j, ret;
+	void  *buf_addr;
+	dma_addr_t phy_addr;
+	struct mlb_dev_info *pdevinfo = NULL;
+	struct mlb_channel_info *pchinfo = NULL;
+	struct mlb_data *drvdata;
+
+	minor = MINOR(inode->i_rdev);
+	drvdata = container_of(inode->i_cdev, struct mlb_data, cdev);
+	drvdata->use_iram = true;
+
+	if (minor < 0 || minor >= MLB_MINOR_DEVICES) {
+		pr_err("no device\n");
+		return -ENODEV;
+	}
+
+	/* open for each channel device */
+	if (atomic_cmpxchg(&mlb_devinfo[minor].opencnt, 0, 1) != 0) {
+		pr_err("busy\n");
+		return -EBUSY;
+	}
+
+	if (mlb150_is_imx8qxp_mlb(drvdata)) {
+		clk_prepare_enable(drvdata->ipg);
+		clk_prepare_enable(drvdata->hclk);
+	}
+	clk_prepare_enable(drvdata->mlb);
+
+	/* initial MLB module */
+	mlb150_dev_init();
+
+	pdevinfo = &mlb_devinfo[minor];
+	pchinfo = &pdevinfo->channels[TX_CHANNEL];
+
+	ring_buf_size = pdevinfo->buf_size;
+	buf_size = ring_buf_size * (TRANS_RING_NODES * 2);
+
+	if (drvdata->iram_pool)
+		buf_addr = gen_pool_dma_alloc(drvdata->iram_pool, buf_size, &phy_addr);
+	else
+		buf_addr = NULL;
+	if (!buf_addr) {
+		drvdata->use_iram = false;
+		buf_addr = dma_alloc_coherent(drvdata->dev, buf_size, &phy_addr, GFP_KERNEL);
+		if (!buf_addr) {
+			ret = -ENOMEM;
+			pr_err("can not alloc rx/tx buffers: %d\n", buf_size);
+			return ret;
+		}
+	}
+
+	pr_debug("IRAM Range: Virt 0x%p - 0x%p, Phys 0x%x - 0x%x, size: 0x%x\n",
+			buf_addr, (buf_addr + buf_size - 1), (u32)phy_addr,
+			(u32)(phy_addr + buf_size - 1), buf_size);
+	pdevinfo->rbuf_base_virt = buf_addr;
+	pdevinfo->rbuf_base_phy = phy_addr;
+	drvdata->iram_size = drvdata->use_iram ? buf_size : 0;
+
+	memset(buf_addr, 0, buf_size);
+
+	for (j = 0; j < (TRANS_RING_NODES);
+		++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
+		pdevinfo->rx_rbuf.virt_bufs[j] = buf_addr;
+		pdevinfo->rx_rbuf.phy_addrs[j] = phy_addr;
+		pr_debug("RX Ringbuf[%d]: 0x%p 0x%x\n",
+			j, buf_addr, (u32)phy_addr);
+	}
+	pdevinfo->rx_rbuf.unit_size = ring_buf_size;
+	pdevinfo->rx_rbuf.total_size = buf_size;
+	for (j = 0; j < (TRANS_RING_NODES);
+		++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
+		pdevinfo->tx_rbuf.virt_bufs[j] = buf_addr;
+		pdevinfo->tx_rbuf.phy_addrs[j] = phy_addr;
+		pr_debug("TX Ringbuf[%d]: 0x%p 0x%x\n",
+			j, buf_addr, (u32)phy_addr);
+	}
+
+	pdevinfo->tx_rbuf.unit_size = ring_buf_size;
+	pdevinfo->tx_rbuf.total_size = buf_size;
+
+	/* reset the buffer read/write ptr */
+	pdevinfo->rx_rbuf.head = pdevinfo->rx_rbuf.tail = 0;
+	pdevinfo->tx_rbuf.head = pdevinfo->tx_rbuf.tail = 0;
+	pdevinfo->ex_event = 0;
+	pdevinfo->tx_ok = 0;
+
+	init_waitqueue_head(&pdevinfo->rx_wq);
+	init_waitqueue_head(&pdevinfo->tx_wq);
+
+	drvdata = container_of(inode->i_cdev, struct mlb_data, cdev);
+	drvdata->devinfo = pdevinfo;
+	mxc_mlb150_irq_enable(drvdata, 1);
+	filp->private_data = drvdata;
+
+	return 0;
+}
+
+static int mxc_mlb150_release(struct inode *inode, struct file *filp)
+{
+	int minor;
+	struct mlb_data *drvdata = filp->private_data;
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+	minor = MINOR(inode->i_rdev);
+	mxc_mlb150_irq_enable(drvdata, 0);
+
+#ifdef DEBUG
+	mlb150_dev_dump_reg();
+	mlb150_dev_dump_ctr_tbl(0, pdevinfo->channels[TX_CHANNEL].cl + 1);
+#endif
+
+	if (drvdata->use_iram)
+		gen_pool_free(drvdata->iram_pool,
+			(ulong)pdevinfo->rbuf_base_virt, drvdata->iram_size);
+
+	mlb150_dev_exit();
+
+	atomic_set(&pdevinfo->on, 0);
+
+	clk_disable_unprepare(drvdata->mlb);
+	if (mlb150_is_imx8qxp_mlb(drvdata)) {
+		clk_disable_unprepare(drvdata->hclk);
+		clk_disable_unprepare(drvdata->ipg);
+	}
+	/* decrease the open count */
+	atomic_set(&pdevinfo->opencnt, 0);
+
+	drvdata->devinfo = NULL;
+
+	return 0;
+}
+
+static long mxc_mlb150_ioctl(struct file *filp,
+			 unsigned int cmd, unsigned long arg)
+{
+	//struct inode *inode = filp->f_dentry->d_inode;
+	struct inode *inode = file_inode(filp);
+	struct mlb_data *drvdata = filp->private_data;
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+	void __user *argp = (void __user *)arg;
+	unsigned long flags, event;
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+
+	switch (cmd) {
+	case MLB_CHAN_SETADDR:
+		{
+			unsigned int caddr;
+			/* get channel address from user space */
+			if (copy_from_user(&caddr, argp, sizeof(caddr))) {
+				pr_err("mxc_mlb150: copy from user failed\n");
+				return -EFAULT;
+			}
+			pdevinfo->channels[TX_CHANNEL].address =
+							(caddr >> 16) & 0xFFFF;
+			pdevinfo->channels[RX_CHANNEL].address = caddr & 0xFFFF;
+			pr_debug("mxc_mlb150: set ch addr, tx: %d, rx: %d\n",
+					pdevinfo->channels[TX_CHANNEL].address,
+					pdevinfo->channels[RX_CHANNEL].address);
+			break;
+		}
+
+	case MLB_CHAN_STARTUP:
+		if (atomic_read(&pdevinfo->on)) {
+			pr_debug("mxc_mlb150: channel alreadly startup\n");
+			break;
+		}
+		if (mlb_channel_enable(drvdata, minor, 1))
+			return -EFAULT;
+		break;
+	case MLB_CHAN_SHUTDOWN:
+		if (atomic_read(&pdevinfo->on) == 0) {
+			pr_debug("mxc_mlb150: channel areadly shutdown\n");
+			break;
+		}
+		mlb150_trans_complete_check(pdevinfo);
+		mlb_channel_enable(drvdata, minor, 0);
+		break;
+	case MLB_CHAN_GETEVENT:
+		/* get and clear the ex_event */
+		spin_lock_irqsave(&pdevinfo->event_lock, flags);
+		event = pdevinfo->ex_event;
+		pdevinfo->ex_event = 0;
+		spin_unlock_irqrestore(&pdevinfo->event_lock, flags);
+
+		if (event) {
+			if (copy_to_user(argp, &event, sizeof(event))) {
+				pr_err("mxc_mlb150: copy to user failed\n");
+				return -EFAULT;
+			}
+		} else
+			return -EAGAIN;
+		break;
+	case MLB_SET_ISOC_BLKSIZE_188:
+		pdevinfo->isoc_blksz = 188;
+		pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+					pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+		break;
+	case MLB_SET_ISOC_BLKSIZE_196:
+		pdevinfo->isoc_blksz = 196;
+		pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+					pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+		break;
+	case MLB_SET_SYNC_QUAD:
+		{
+			u32 quad;
+
+			if (copy_from_user(&quad, argp, sizeof(quad))) {
+				pr_err("mxc_mlb150: get quad number "
+						"from user failed\n");
+				return -EFAULT;
+			}
+			if (quad <= 0 || quad > 3) {
+				pr_err("mxc_mlb150: Invalid Quadlets!"
+					"Quadlets in Sync mode can "
+					"only be 1, 2, 3\n");
+				return -EINVAL;
+			}
+			pdevinfo->sync_quad = quad;
+			/* Each quadlets is 4 bytes */
+			pdevinfo->cdt_buf_dep = quad * 4 * 4;
+			pdevinfo->adt_buf_dep =
+				pdevinfo->cdt_buf_dep * CH_SYNC_ADT_BUF_MULTI;
+		}
+		break;
+	case MLB_SET_FPS:
+		{
+			u32 fps, c0_val;
+
+			/* get fps from user space */
+			if (copy_from_user(&fps, argp, sizeof(fps))) {
+				pr_err("mxc_mlb150: copy from user failed\n");
+				return -EFAULT;
+			}
+
+			if ((fps > 1024) &&
+				!(drvdata->hwdata->quirk_flag &
+				MLB_QUIRK_MLB150)) {
+				pr_err("mxc_mlb150: not support fps %d\n", fps);
+				return -EINVAL;
+			}
+
+			c0_val = __raw_readl(mlb_base + REG_MLBC0);
+			c0_val &= ~MLBC0_MLBCLK_MASK;
+
+			/* check fps value */
+			switch (fps) {
+			case 256:
+			case 512:
+			case 1024:
+				pdevinfo->fps = fps >> 9;
+				c0_val &= ~MLBC0_MLBPEN;
+				c0_val |= (fps >> 9)
+					<< MLBC0_MLBCLK_SHIFT;
+
+				if (1024 == fps) {
+					/*
+					 * Invert output clock phase
+					 * in 1024 fps
+					 */
+					__raw_writel(0x1,
+						mlb_base + REG_MLBPC2);
+				}
+				break;
+			case 2048:
+			case 3072:
+			case 4096:
+				pdevinfo->fps = (fps >> 10) + 1;
+				c0_val |= ((fps >> 10) + 1)
+					<< MLBC0_MLBCLK_SHIFT;
+				break;
+			case 6144:
+				pdevinfo->fps = fps >> 10;
+				c0_val |= ((fps >> 10) + 1)
+					<< MLBC0_MLBCLK_SHIFT;
+				break;
+			case 8192:
+				pdevinfo->fps = (fps >> 10) - 1;
+				c0_val |= ((fps >> 10) - 1)
+						<< MLBC0_MLBCLK_SHIFT;
+				break;
+			default:
+				pr_debug("mxc_mlb150: invalid fps argument: %d\n",
+						fps);
+				return -EINVAL;
+			}
+
+			__raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+			pr_debug("mxc_mlb150: set fps to %d, MLBC0: 0x%08x\n",
+				fps,
+				(u32)__raw_readl(mlb_base + REG_MLBC0));
+
+			break;
+		}
+
+	case MLB_GET_VER:
+		{
+			u32 version;
+
+			/* get MLB device module version */
+			version = 0x03030003;
+
+			pr_debug("mxc_mlb150: get version: 0x%08x\n",
+					version);
+
+			if (copy_to_user(argp, &version, sizeof(version))) {
+				pr_err("mxc_mlb150: copy to user failed\n");
+				return -EFAULT;
+			}
+			break;
+		}
+
+	case MLB_SET_DEVADDR:
+		{
+			u32 c1_val;
+			u8 devaddr;
+
+			/* get MLB device address from user space */
+			if (copy_from_user
+				(&devaddr, argp, sizeof(unsigned char))) {
+				pr_err("mxc_mlb150: copy from user failed\n");
+				return -EFAULT;
+			}
+
+			c1_val = __raw_readl(mlb_base + REG_MLBC1);
+			c1_val &= ~MLBC1_NDA_MASK;
+			c1_val |= devaddr << MLBC1_NDA_SHIFT;
+			__raw_writel(c1_val, mlb_base + REG_MLBC1);
+			pr_debug("mxc_mlb150: set dev addr, dev addr: %d, "
+				"MLBC1: 0x%08x\n", devaddr,
+				(u32)__raw_readl(mlb_base + REG_MLBC1));
+
+			break;
+		}
+
+	case MLB_IRQ_DISABLE:
+		{
+			disable_irq(drvdata->irq_mlb);
+			break;
+		}
+
+	case MLB_IRQ_ENABLE:
+		{
+			enable_irq(drvdata->irq_mlb);
+			break;
+		}
+	default:
+		pr_info("mxc_mlb150: Invalid ioctl command\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * MLB read routine
+ * Read the current received data from queued buffer,
+ * and free this buffer for hw to fill ingress data.
+ */
+static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
+			    size_t count, loff_t *f_pos)
+{
+	int size;
+	struct mlb_data *drvdata = filp->private_data;
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+	struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+	int head, tail;
+	unsigned long flags;
+
+	read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+
+	head = READ_ONCE(rx_rbuf->head);
+	tail = rx_rbuf->tail;
+
+	read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+	/* check the current rx buffer is available or not */
+	if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		do {
+			DEFINE_WAIT(__wait);
+
+			for (;;) {
+				prepare_to_wait(&pdevinfo->rx_wq,
+						&__wait, TASK_INTERRUPTIBLE);
+
+				read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+				if (CIRC_CNT(rx_rbuf->head, rx_rbuf->tail,
+						TRANS_RING_NODES) > 0) {
+					read_unlock_irqrestore(&rx_rbuf->rb_lock,
+								flags);
+					break;
+				}
+				read_unlock_irqrestore(&rx_rbuf->rb_lock,
+							flags);
+
+				if (!signal_pending(current)) {
+					schedule();
+					continue;
+				}
+				return -ERESTARTSYS;
+			}
+			finish_wait(&pdevinfo->rx_wq, &__wait);
+		} while (0);
+	}
+
+	/* read index before reading contents at that index */
+	smp_read_barrier_depends();
+
+	size = pdevinfo->adt_buf_dep;
+	if (size > count) {
+		/* the user buffer is too small */
+		pr_warn("mxc_mlb150: received data size is biggerthan size:"
+			"%d, count: %d\n", size, (int)count);
+		return -EINVAL;
+	}
+
+	/* extract one item from the buffer */
+	if (copy_to_user(buf, rx_rbuf->virt_bufs[tail], size)) {
+		pr_err("mxc_mlb150: copy from user failed\n");
+		return -EFAULT;
+	}
+
+	/* finish reading descriptor before incrementing tail */
+	smp_mb();
+
+	write_lock_irqsave(&rx_rbuf->rb_lock, flags);
+	rx_rbuf->tail = (tail + 1) & (TRANS_RING_NODES - 1);
+	write_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+	*f_pos = 0;
+
+	return size;
+}
+
+/*
+ * MLB write routine
+ * Copy the user data to tx channel buffer,
+ * and prepare the channel current/next buffer ptr.
+ */
+static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
+			     size_t count, loff_t *f_pos)
+{
+	s32 ret = 0;
+	struct mlb_channel_info *pchinfo = NULL;
+	struct mlb_data *drvdata = filp->private_data;
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+	struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+	int head, tail;
+	unsigned long flags;
+
+	/*
+	 * minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	 */
+	pchinfo = &pdevinfo->channels[TX_CHANNEL];
+
+	if (count > pdevinfo->buf_size) {
+		/* too many data to write */
+		pr_warning("mxc_mlb150: overflow write data\n");
+		return -EFBIG;
+	}
+
+	*f_pos = 0;
+
+	read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+
+	head = tx_rbuf->head;
+	tail = READ_ONCE(tx_rbuf->tail);
+	read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+	if (0 == CIRC_SPACE(head, tail, TRANS_RING_NODES)) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		do {
+			DEFINE_WAIT(__wait);
+
+			for (;;) {
+				prepare_to_wait(&pdevinfo->tx_wq,
+						&__wait, TASK_INTERRUPTIBLE);
+
+				read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+				if (CIRC_SPACE(tx_rbuf->head, tx_rbuf->tail,
+							TRANS_RING_NODES) > 0) {
+					read_unlock_irqrestore(&tx_rbuf->rb_lock,
+							flags);
+					break;
+				}
+				read_unlock_irqrestore(&tx_rbuf->rb_lock,
+								flags);
+
+				if (!signal_pending(current)) {
+					schedule();
+					continue;
+				}
+				return -ERESTARTSYS;
+			}
+			finish_wait(&pdevinfo->tx_wq, &__wait);
+		} while (0);
+	}
+
+	if (copy_from_user((void *)tx_rbuf->virt_bufs[head], buf, count)) {
+		read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+		pr_err("mxc_mlb: copy from user failed\n");
+		ret = -EFAULT;
+		goto out;
+	}
+
+	write_lock_irqsave(&tx_rbuf->rb_lock, flags);
+	smp_wmb();
+	tx_rbuf->head = (head + 1) & (TRANS_RING_NODES - 1);
+	write_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+	if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+		u32 tx_buf_ptr, ahb_ch;
+		s32 adt_sts;
+		u32 ctype = pdevinfo->channel_type;
+
+		/* read index before reading contents at that index */
+		smp_read_barrier_depends();
+
+		tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+
+		ahb_ch = pdevinfo->channels[TX_CHANNEL].cl;
+		adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+
+		/*  Set ADT for TX */
+		mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+	}
+
+	ret = count;
+out:
+	return ret;
+}
+
+static unsigned int mxc_mlb150_poll(struct file *filp,
+				 struct poll_table_struct *wait)
+{
+	int minor;
+	unsigned int ret = 0;
+	struct mlb_data *drvdata = filp->private_data;
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+	struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+	struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+	int head, tail;
+	unsigned long flags;
+
+
+	minor = MINOR(file_inode(filp)->i_rdev);
+
+	poll_wait(filp, &pdevinfo->rx_wq, wait);
+	poll_wait(filp, &pdevinfo->tx_wq, wait);
+
+	read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+	head = tx_rbuf->head;
+	tail = tx_rbuf->tail;
+	read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+	/* check the tx buffer is avaiable or not */
+	if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1)
+		ret |= POLLOUT | POLLWRNORM;
+
+	read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+	head = rx_rbuf->head;
+	tail = rx_rbuf->tail;
+	read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+	/* check the rx buffer filled or not */
+	if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1)
+		ret |= POLLIN | POLLRDNORM;
+
+
+	/* check the exception event */
+	if (pdevinfo->ex_event)
+		ret |= POLLIN | POLLRDNORM;
+
+	return ret;
+}
+
+/*
+ * char dev file operations structure
+ */
+static const struct file_operations mxc_mlb150_fops = {
+
+	.owner = THIS_MODULE,
+	.open = mxc_mlb150_open,
+	.release = mxc_mlb150_release,
+	.unlocked_ioctl = mxc_mlb150_ioctl,
+	.poll = mxc_mlb150_poll,
+	.read = mxc_mlb150_read,
+	.write = mxc_mlb150_write,
+};
+
+static const struct imx_mlb_hwdata imx6q_mlb_hwdata = {
+	.devtype		= IMX6Q_MLB,
+	.quirk_flag		= MLB_QUIRK_MLB150,
+};
+
+static const struct imx_mlb_hwdata imx6sx_mlb_hwdata = {
+	.devtype		= IMX6SX_MLB,
+	.quirk_flag		= 0,
+};
+
+static const struct imx_mlb_hwdata imx8qxp_mlb_hwdata = {
+	.devtype		= IMX8QXP_MLB,
+	.quirk_flag		= MLB_QUIRK_MLB150,
+};
+
+static const struct of_device_id mlb150_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-mlb150",
+		.data = &imx6q_mlb_hwdata, },
+	{ .compatible = "fsl,imx6sx-mlb50",
+		.data = &imx6sx_mlb_hwdata, },
+	{ .compatible = "fsl,imx8qxp-mlb150",
+		.data = &imx8qxp_mlb_hwdata, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mlb150_imx_dt_ids);
+
+/*
+ * This function is called whenever the MLB device is detected.
+ */
+static int mxc_mlb150_probe(struct platform_device *pdev)
+{
+	int ret, mlb_major, i;
+	struct mlb_data *drvdata;
+	struct resource *res;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct mlb_data),
+				GFP_KERNEL);
+	if (!drvdata) {
+		dev_err(&pdev->dev, "can't allocate enough memory\n");
+		return -ENOMEM;
+	}
+
+	drvdata->dev = &pdev->dev;
+	of_id = of_match_device(mlb150_imx_dt_ids, &pdev->dev);
+	if (of_id)
+		drvdata->hwdata = of_id->data;
+	else
+		return -EINVAL;
+	/*
+	 * Register MLB lld as four character devices
+	 */
+	ret = alloc_chrdev_region(&drvdata->firstdev, 0,
+			MLB_MINOR_DEVICES, "mxc_mlb150");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "alloc region error\n");
+		goto err_reg;
+	}
+	mlb_major = MAJOR(drvdata->firstdev);
+	dev_dbg(&pdev->dev, "MLB device major: %d\n", mlb_major);
+
+	cdev_init(&drvdata->cdev, &mxc_mlb150_fops);
+	drvdata->cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&drvdata->cdev, drvdata->firstdev, MLB_MINOR_DEVICES);
+	if (ret) {
+		dev_err(&pdev->dev, "can't add cdev\n");
+		goto err_reg;
+	}
+
+	/* create class and device for udev information */
+	drvdata->class = class_create(THIS_MODULE, "mlb150");
+	if (IS_ERR(drvdata->class)) {
+		dev_err(&pdev->dev, "failed to create device class\n");
+		ret = -ENOMEM;
+		goto err_class;
+	}
+
+	for (i = 0; i < MLB_MINOR_DEVICES; i++) {
+		struct device *class_dev;
+
+		class_dev = device_create(drvdata->class, NULL,
+				MKDEV(mlb_major, i),
+				NULL, mlb_devinfo[i].dev_name);
+		if (IS_ERR(class_dev)) {
+			dev_err(&pdev->dev, "failed to create mlb150 %s"
+				" class device\n", mlb_devinfo[i].dev_name);
+			ret = -ENOMEM;
+			goto err_dev;
+		}
+	}
+
+	/* ahb0 irq */
+	drvdata->irq_ahb0 = platform_get_irq(pdev,  1);
+	if (drvdata->irq_ahb0 < 0) {
+		dev_err(&pdev->dev, "No ahb0 irq line provided\n");
+		goto err_dev;
+	}
+	dev_dbg(&pdev->dev, "ahb0_irq: %d\n", drvdata->irq_ahb0);
+	if (devm_request_irq(&pdev->dev, drvdata->irq_ahb0, mlb_ahb_isr,
+				0, "mlb_ahb0", NULL)) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_ahb0);
+		goto err_dev;
+	}
+
+	/* ahb1 irq */
+	drvdata->irq_ahb1 = platform_get_irq(pdev,  2);
+	dev_dbg(&pdev->dev, "ahb1_irq: %d\n", drvdata->irq_ahb1);
+	if (drvdata->irq_ahb1 > 0) {
+		if (devm_request_irq(&pdev->dev, drvdata->irq_ahb1, mlb_ahb_isr,
+				0, "mlb_ahb1", NULL)) {
+			dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_ahb1);
+			goto err_dev;
+		}
+	}
+
+	/* mlb irq */
+	drvdata->irq_mlb  = platform_get_irq(pdev,  0);
+	if (drvdata->irq_mlb < 0) {
+		dev_err(&pdev->dev, "No mlb irq line provided\n");
+		goto err_dev;
+	}
+	dev_dbg(&pdev->dev, "mlb_irq: %d\n", drvdata->irq_mlb);
+	if (devm_request_irq(&pdev->dev, drvdata->irq_mlb, mlb_isr,
+				0, "mlb", NULL)) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_mlb);
+		goto err_dev;
+	}
+
+	/* ioremap from phy mlb to kernel space */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "can't get device resources\n");
+		ret = -ENOENT;
+		goto err_dev;
+	}
+	mlb_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mlb_base)) {
+		dev_err(&pdev->dev,
+			"failed to get ioremap base\n");
+		ret = PTR_ERR(mlb_base);
+		goto err_dev;
+	}
+	drvdata->membase = mlb_base;
+
+#ifdef CONFIG_REGULATOR
+	drvdata->nvcc = devm_regulator_get(&pdev->dev, "reg_nvcc");
+	if (!IS_ERR(drvdata->nvcc)) {
+		regulator_set_voltage(drvdata->nvcc, 2500000, 2500000);
+		dev_err(&pdev->dev, "enalbe regulator\n");
+		ret = regulator_enable(drvdata->nvcc);
+		if (ret) {
+			dev_err(&pdev->dev, "vdd set voltage error\n");
+			goto err_dev;
+		}
+	}
+#endif
+
+	if (mlb150_is_imx8qxp_mlb(drvdata)) {
+		drvdata->ipg = devm_clk_get(&pdev->dev, "ipg");
+		if (IS_ERR(drvdata->ipg)) {
+			dev_err(&pdev->dev, "unable to get mlb ipg clock\n");
+			ret = PTR_ERR(drvdata->ipg);
+			goto err_dev;
+		}
+
+		drvdata->hclk = devm_clk_get(&pdev->dev, "hclk");
+		if (IS_ERR(drvdata->hclk)) {
+			dev_err(&pdev->dev, "unable to get mlb hclk clock\n");
+			ret = PTR_ERR(drvdata->hclk);
+			goto err_dev;
+		}
+	}
+
+	drvdata->mlb = devm_clk_get(&pdev->dev, "mlb");
+	if (IS_ERR(drvdata->mlb)) {
+		dev_err(&pdev->dev, "unable to get mlb clock\n");
+		ret = PTR_ERR(drvdata->mlb);
+		goto err_dev;
+	}
+
+	drvdata->iram_pool = of_gen_pool_get(np, "iram", 0);
+	if (!drvdata->iram_pool)
+		dev_warn(&pdev->dev, "no iram assigned, using external mem\n");
+
+	drvdata->devinfo = NULL;
+	mxc_mlb150_irq_enable(drvdata, 0);
+	platform_set_drvdata(pdev, drvdata);
+	return 0;
+
+err_dev:
+	for (--i; i >= 0; i--)
+		device_destroy(drvdata->class, MKDEV(mlb_major, i));
+
+	class_destroy(drvdata->class);
+err_class:
+	cdev_del(&drvdata->cdev);
+err_reg:
+	unregister_chrdev_region(drvdata->firstdev, MLB_MINOR_DEVICES);
+
+	return ret;
+}
+
+static int mxc_mlb150_remove(struct platform_device *pdev)
+{
+	int i;
+	struct mlb_data *drvdata = platform_get_drvdata(pdev);
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+	if (pdevinfo && atomic_read(&pdevinfo->opencnt))
+		clk_disable_unprepare(drvdata->mlb);
+
+	/* disable mlb power */
+#ifdef CONFIG_REGULATOR
+	if (!IS_ERR(drvdata->nvcc))
+		regulator_disable(drvdata->nvcc);
+#endif
+
+	/* destroy mlb device class */
+	for (i = MLB_MINOR_DEVICES - 1; i >= 0; i--)
+		device_destroy(drvdata->class,
+				MKDEV(MAJOR(drvdata->firstdev), i));
+	class_destroy(drvdata->class);
+
+	cdev_del(&drvdata->cdev);
+
+	/* Unregister the two MLB devices */
+	unregister_chrdev_region(drvdata->firstdev, MLB_MINOR_DEVICES);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxc_mlb150_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mlb_data *drvdata = platform_get_drvdata(pdev);
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+	if (pdevinfo && atomic_read(&pdevinfo->opencnt)) {
+		mlb150_dev_exit();
+		clk_disable_unprepare(drvdata->mlb);
+	}
+
+	return 0;
+}
+
+static int mxc_mlb150_resume(struct platform_device *pdev)
+{
+	struct mlb_data *drvdata = platform_get_drvdata(pdev);
+	struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+	if (pdevinfo && atomic_read(&pdevinfo->opencnt)) {
+		clk_prepare_enable(drvdata->mlb);
+		mlb150_dev_init();
+	}
+
+	return 0;
+}
+#else
+#define mxc_mlb150_suspend NULL
+#define mxc_mlb150_resume NULL
+#endif
+
+/*
+ * platform driver structure for MLB
+ */
+static struct platform_driver mxc_mlb150_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = mlb150_imx_dt_ids,
+	},
+	.probe = mxc_mlb150_probe,
+	.remove = mxc_mlb150_remove,
+	.suspend = mxc_mlb150_suspend,
+	.resume = mxc_mlb150_resume,
+};
+
+static int __init mxc_mlb150_init(void)
+{
+	return platform_driver_register(&mxc_mlb150_driver);
+}
+
+static void __exit mxc_mlb150_exit(void)
+{
+	platform_driver_unregister(&mxc_mlb150_driver);
+}
+
+module_init(mxc_mlb150_init);
+module_exit(mxc_mlb150_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MLB150 low level driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/sim/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/sim/Kconfig
@@ -0,0 +1,27 @@
+#
+# SIM configuration
+#
+
+menu "MXC SIM Support"
+
+config MXC_SIMv2
+	tristate "MXC SIMv2 support"
+	depends on ARCH_MXC && MXC_SIM
+	default n
+	---help---
+	Say Y if you want to use the SIMv2 on NXP i.MX6/7 processors.
+
+	This driver can also be built as a module. If so, the module
+	will be called imx_sim.
+
+config MXC_EMVSIM
+	tristate "MXC EMVSIM support"
+	depends on ARCH_MXC && MXC_SIM
+	default n
+	---help---
+	Say Y here if you want to use the EMVSIM on NXP i.MX8 processors.
+
+	This driver can also be built as a module. If so, the module
+	will be called imx_emvsim.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/sim/Makefile
+++ linux-ein-5.4.0/drivers/mxc/sim/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the i.MX SIM driver
+#
+
+obj-$(CONFIG_MXC_SIMv2) += imx_sim.o
+obj-$(CONFIG_MXC_EMVSIM) += imx_emvsim.o
--- linux-ein-5.4.0.orig/drivers/mxc/sim/imx_emvsim.c
+++ linux-ein-5.4.0/drivers/mxc/sim/imx_emvsim.c
@@ -0,0 +1,1767 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mxc_sim_interface.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#define	DRIVER_NAME	"mxc_emvsim"
+
+/* Definitions of the offset of the SIM hardware registers */
+#define	EMV_SIM_VER_ID		0X00
+#define	EMV_SIM_PARAM		0X04
+#define	EMV_SIM_CLKCFG		0X08
+#define	EMV_SIM_DIVISOR		0X0C
+#define	EMV_SIM_CTRL		0X10
+#define	EMV_SIM_INT_MASK	0X14
+#define	EMV_SIM_RX_THD		0X18
+#define	EMV_SIM_TX_THD		0X1C
+#define	EMV_SIM_RX_STATUS	0X20
+#define	EMV_SIM_TX_STATUS	0X24
+#define	EMV_SIM_PCSR		0X28
+#define	EMV_SIM_RX_BUF		0X2C
+#define	EMV_SIM_TX_BUF		0X30
+#define	EMV_SIM_TX_GETU		0X34
+#define	EMV_SIM_CWT_VAL		0X38
+#define	EMV_SIM_BWT_VAL		0X3C
+#define	EMV_SIM_BGT_VAL		0X40
+#define	EMV_SIM_GPCNT0_VAL	0X44
+#define	EMV_SIM_GPCNT1_VAL	0X48
+
+#define	SIM_XMT_BUFFER_SIZE	300
+#define	SIM_RCV_BUFFER_SIZE	400
+
+#define	SIM_TX_FIFO_DEPTH	16
+#define	SIM_RX_FIFO_DEPTH	16
+#define	TX_FIFO_THRESHOLD	4
+
+#define	SIM_STATE_REMOVED		0
+#define	SIM_STATE_DETECTED		1
+#define	SIM_STATE_ATR_RECEIVING		2
+#define	SIM_STATE_ATR_RECEIVED		3
+#define	SIM_STATE_XMTING		4
+#define	SIM_STATE_XMT_DONE		5
+#define	SIM_STATE_XMT_ERROR		6
+#define	SIM_STATE_RECEIVING		7
+#define	SIM_STATE_RECEIVE_DONE		8
+#define	SIM_STATE_RECEIVE_ERROR		9
+#define	SIM_STATE_RESET_SEQUENCY	10
+
+#define	SIM_CNTL_GPCNT_RESET		0
+#define	SIM_CNTL_GPCNT_CARD_CLK		1
+#define	SIM_CNTL_GPCNT_RCV_CLK		2
+#define	SIM_CNTL_GPCNT_ETU_CLK		3
+#define	SIM_EMV_NACK_THRESHOLD		5
+#define	EMV_T0_BGT			16
+#define	EMV_T1_BGT			22
+#define	ATR_THRESHOLD_MAX		100
+#define	ATR_MAX_CWT			10080
+#define	ATR_MAX_DURATION		20160
+#define	FCLK_FREQ			4000000
+
+#define	ATR_TIMEOUT			5
+#define	TX_TIMEOUT			10
+#define	RX_TIMEOUT			100
+#define	RESET_RETRY_TIMES		5
+#define	EMV_RESET_LOW_CYCLES		40000
+#define	ATR_MAX_DELAY_CLK		46400
+#define	DIVISOR_VALUE			372
+#define	CWT_ADJUSTMENT			2
+#define	BGT_BWT_ADJUSTMENT		2
+
+#define	SIM_CNTL_GPCNT0_CLK_SEL_MASK	(3 << 10)
+#define	SIM_CNTL_GPCNT0_CLK_SEL(x)	((x & 3) << 10)
+#define	SIM_CNTL_GPCNT1_CLK_SEL_MASK	(3 << 8)
+#define	SIM_CNTL_GPCNT1_CLK_SEL(x)	((x & 3) << 8)
+
+/* EMV_SIM_CTRL */
+#define	IC		(1 << 0)
+#define	ICM		(1 << 1)
+#define	ANACK		(1 << 2)
+#define	ONACK		(1 << 3)
+#define	FLSH_RX		(1 << 8)
+#define	FLSH_TX		(1 << 9)
+#define	SW_RST		(1 << 10)
+#define	KILL_CLOCKS	(1 << 11)
+#define	RCV_EN		(1 << 16)
+#define	XMT_EN		(1 << 17)
+#define	RCVR_11		(1 << 18)
+#define	CWT_EN		(1 << 27)
+#define	BWT_EN		(1 << 31)
+
+/* EMV_SIM_INT_MASK */
+#define	RDT_IM		(1 << 0)
+#define	TC_IM		(1 << 1)
+#define	ETC_IM		(1 << 3)
+#define	TNACK_IM	(1 << 5)
+#define	TDT_IM		(1 << 7)
+#define	GPCNT0_IM	(1 << 8)
+#define	CWT_ERR_IM	(1 << 9)
+#define	RNACK_IM	(1 << 10)
+#define	BWT_ERR_IM	(1 << 11)
+#define	GPCNT1_IM	(1 << 13)
+#define	RX_DATA_IM	(1 << 14)
+
+/* EMV_SIM_RX_THD */
+#define	SIM_RCV_THRESHOLD_RDT_MASK	(0x0f << 0)
+#define	SIM_RCV_THRESHOLD_RDT(x)	((x & 0x0f) << 0)
+#define	SIM_RCV_THRESHOLD_RTH_MASK	(0x0f << 8)
+#define	SIM_RCV_THRESHOLD_RTH(x)	((x & 0x0f) << 8)
+
+/* EMV_SIM_TX_THD */
+#define	SIM_XMT_THRESHOLD_TDT_MASK	(0x0f << 0)
+#define	SIM_XMT_THRESHOLD_TDT(x)	((x & 0x0f) << 0)
+#define	SIM_XMT_THRESHOLD_XTH_MASK	(0x0f << 8)
+#define	SIM_XMT_THRESHOLD_XTH(x)	((x & 0x0f) << 8)
+
+/* EMV_SIM_RX_STATUS */
+#define	RX_DATA		(1 << 4)
+#define	RDTF		(1 << 5)
+#define	CWT_ERR		(1 << 8)
+#define	RTE		(1 << 9)
+#define	BWT_ERR		(1 << 10)
+#define	BGT_ERR		(1 << 11)
+#define	PEF		(1 << 12)
+#define	FEF		(1 << 13)
+
+/* EMV_SIM_TX_STATUS */
+#define	TNTE		(1 << 0)
+#define	ETCF		(1 << 4)
+#define	TCF		(1 << 5)
+#define	TDTF		(1 << 7)
+#define	GPCNT0_TO	(1 << 8)
+#define	GPCNT1_TO	(1 << 9)
+
+/* EMV_SIM_PCSR */
+#define	SAPD		(1 << 0)
+#define	SVCC_EN		(1 << 1)
+#define	VCCENP		(1 << 2)
+#define	SRST		(1 << 3)
+#define	SCEN		(1 << 4)
+#define	SPD		(1 << 7)
+#define	SPDIM		(1 << 24)
+#define	SPDIF		(1 << 25)
+#define	SPDP		(1 << 26)
+#define	SPDES		(1 << 27)
+
+struct emvsim_t {
+	s32 present;
+	u8 open_cnt;
+	int state;
+	struct clk *clk;
+	struct clk *ipg;
+	struct resource *res;
+	void __iomem *ioaddr;
+	int irq;
+
+	int errval;
+	int protocol_type;
+	sim_timing_t timing_data;
+	sim_baud_t baud_rate;
+	int timeout;
+	u8 nack_threshold;
+	u8 nack_enable;
+	u32 expected_rcv_cnt;
+	u8 is_fixed_len_rec;
+	u32 xmt_remaining;
+	u32 xmt_pos;
+	u32 rcv_count;
+	u8 rcv_buffer[SIM_RCV_BUFFER_SIZE];
+	u8 xmt_buffer[SIM_XMT_BUFFER_SIZE];
+	struct completion xfer_done;
+	u16 rcv_head;
+	spinlock_t lock;
+	u32 clk_rate;
+	u8 checking_ts_timing;
+	u8 tx_last_character;
+
+	/* multiple power domain for emvsim */
+        struct device *sim_pd;
+        struct device *sim_aux_pd;
+};
+
+static struct miscdevice emvsim_dev;
+
+static void emvsim_data_reset(struct emvsim_t *emvsim)
+{
+	emvsim->errval = SIM_OK;
+	emvsim->protocol_type = 0;
+	emvsim->timeout = 0;
+	emvsim->nack_threshold = SIM_EMV_NACK_THRESHOLD;
+	emvsim->nack_enable = 0;
+	memset(&emvsim->timing_data, 0, sizeof(emvsim->timing_data));
+	memset(&emvsim->baud_rate, 0, sizeof(emvsim->baud_rate));
+
+	emvsim->xmt_remaining = 0;
+	emvsim->xmt_pos = 0;
+	emvsim->rcv_count = 0;
+	emvsim->rcv_head = 0;
+	memset(emvsim->rcv_buffer, 0, SIM_RCV_BUFFER_SIZE);
+	memset(emvsim->xmt_buffer, 0, SIM_XMT_BUFFER_SIZE);
+
+	reinit_completion(&emvsim->xfer_done);
+};
+
+static void emvsim_set_nack(struct emvsim_t *emvsim, u8 enable)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	/*Disable overrun NACK setting for now*/
+	reg_val &= ~ONACK;
+
+	if (enable) {
+		reg_val |= ANACK;
+		__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+
+		reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_THD);
+		reg_val &= ~(SIM_XMT_THRESHOLD_XTH_MASK);
+		reg_val |= SIM_XMT_THRESHOLD_XTH(emvsim->nack_threshold);
+		__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_THD);
+	} else {
+		reg_val &= ~ANACK;
+		__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+	}
+
+	emvsim->nack_enable = enable;
+}
+
+static void emvsim_set_tx(struct emvsim_t *emvsim, u8 enable)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	if (enable) {
+		reg_data |= XMT_EN;
+		reg_data &= ~RCV_EN;
+	} else {
+		reg_data &= ~XMT_EN;
+	}
+
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_set_rx(struct emvsim_t *emvsim, u8 enable)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	if (enable) {
+		reg_data |= RCV_EN;
+		reg_data &= ~XMT_EN;
+	} else {
+		reg_data &= ~RCV_EN;
+	}
+
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_mask_timer0_int(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data |= GPCNT0_IM;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	reg_data |= GPCNT0_TO;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+}
+
+static void emvsim_mask_timer1_int(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data |= GPCNT1_IM;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	reg_data |= GPCNT1_TO;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+}
+
+static void emvsim_set_gpctimer0_clk(struct emvsim_t *emvsim, u8 clk_source)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CLKCFG);
+	reg_data &= ~SIM_CNTL_GPCNT0_CLK_SEL_MASK;
+	reg_data |= SIM_CNTL_GPCNT0_CLK_SEL(clk_source);
+	writel(reg_data, emvsim->ioaddr + EMV_SIM_CLKCFG);
+}
+
+static void emvsim_set_gpctimer1_clk(struct emvsim_t *emvsim, u8 clk_source)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CLKCFG);
+	reg_data &= ~SIM_CNTL_GPCNT1_CLK_SEL_MASK;
+	reg_data |= SIM_CNTL_GPCNT1_CLK_SEL(clk_source);
+	writel(reg_data, emvsim->ioaddr + EMV_SIM_CLKCFG);
+}
+
+static void emvsim_reset_gpctimer(struct emvsim_t *emvsim)
+{
+	emvsim_set_gpctimer0_clk(emvsim, SIM_CNTL_GPCNT_RESET);
+	emvsim_set_gpctimer1_clk(emvsim, SIM_CNTL_GPCNT_RESET);
+
+	/* need a tx_en posedge to update gpctimer0 clk */
+	emvsim_set_tx(emvsim, 0);
+	emvsim_set_tx(emvsim, 1);
+	emvsim_set_tx(emvsim, 0);
+}
+
+static int emvsim_reset_low_timing(struct emvsim_t *emvsim, u32 clock_cycle)
+{
+	int errval = 0;
+	int timeout = 0;
+	u32 fclk_in_khz, delay_in_us, reg_data;
+
+	fclk_in_khz = emvsim->clk_rate / MSEC_PER_SEC;
+	delay_in_us = EMV_RESET_LOW_CYCLES * USEC_PER_MSEC / fclk_in_khz;
+
+	emvsim_mask_timer0_int(emvsim);
+	__raw_writel(clock_cycle, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+	emvsim_set_gpctimer0_clk(emvsim, SIM_CNTL_GPCNT_CARD_CLK);
+	emvsim_set_tx(emvsim, 1);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data &= ~GPCNT0_IM;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+	timeout  = wait_for_completion_timeout(
+			&emvsim->xfer_done,
+			msecs_to_jiffies(delay_in_us / 1000 * 2));
+	if (timeout == 0) {
+		dev_err(emvsim_dev.parent, "Reset low GPC timout\n");
+		errval =  -SIM_E_TIMEOUT;
+	}
+
+	return errval;
+}
+
+static void emvsim_set_cwt(struct emvsim_t *emvsim, u8 enable)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	if (enable && emvsim->timing_data.cwt)
+		reg_val |= CWT_EN;
+	else
+		reg_val &= ~CWT_EN;
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_set_bwt(struct emvsim_t *emvsim, u8 enable)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	if (enable && (emvsim->timing_data.bwt || emvsim->timing_data.bgt))
+		reg_val |= BWT_EN;
+	else
+		reg_val &= ~BWT_EN;
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static int emvsim_reset_module(struct emvsim_t *emvsim)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	reg_val |= SW_RST;
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+
+	/* Software should allow a minimum of 4 Protocol clock cycles(4MHz)*/
+	usleep_range(1, 3);
+
+	return 0;
+}
+
+static void emvsim_receive_atr_set(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	/* GPCNT0 with Card clock is for ATR maximum delay
+	 * GPCNT1 with ETU clock is for ART maximum duration
+	 */
+	emvsim_mask_timer1_int(emvsim);
+	__raw_writel(0x0, emvsim->ioaddr + EMV_SIM_GPCNT1_VAL);
+	emvsim_set_gpctimer1_clk(emvsim, SIM_CNTL_GPCNT_ETU_CLK);
+	emvsim_set_rx(emvsim, 1);
+
+	/*Set the cwt timer.Refer the setting of ATR on EMV4.3 book*/
+	__raw_writel(ATR_MAX_CWT + CWT_ADJUSTMENT, emvsim->ioaddr + EMV_SIM_CWT_VAL);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+	reg_data |= ICM;
+	reg_data |= CWT_EN;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+	emvsim_set_nack(emvsim, 0);
+	emvsim->errval = 0;
+	emvsim->rcv_count = 0;
+	emvsim->checking_ts_timing = 1;
+	emvsim->state = SIM_STATE_ATR_RECEIVING;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data |= CWT_ERR_IM;
+	reg_data &= ~(RX_DATA_IM | GPCNT0_IM);
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static int32_t emvsim_check_rec_data(u32 *reg_data)
+{
+	s32 err = 0;
+
+	if (*reg_data & FEF)
+		err |= SIM_ERROR_FRAME;
+
+	if (*reg_data & PEF)
+		err |= SIM_ERROR_PARITY;
+
+	return err;
+}
+
+static void emvsim_enable_guardtime(struct emvsim_t *emvsim, int enable)
+{
+	/* transmitter: set Guard Time Value in ETU */
+	if (enable) {
+		if (emvsim->protocol_type == SIM_PROTOCOL_T0) {
+			/*
+			 * From EMV4.3, TotalETU = 12 + CGT.
+			 * If cgt equals 0xFF, TotalETU = 12.
+			 */
+			if (emvsim->timing_data.cgt == 0xFF)
+				__raw_writel(0, emvsim->ioaddr + EMV_SIM_TX_GETU);
+			else
+				__raw_writel(emvsim->timing_data.cgt,
+					     emvsim->ioaddr + EMV_SIM_TX_GETU);
+		} else if (emvsim->protocol_type == SIM_PROTOCOL_T1) {
+			/*
+			 * From EMV4.3, TotalETU = 12 + CGT.
+			 * If cgt equals 0xFF, TotalETU = 11.
+			 */
+			__raw_writel(emvsim->timing_data.cgt,
+				     emvsim->ioaddr + EMV_SIM_TX_GETU);
+		}
+	} else {
+		__raw_writel(0, emvsim->ioaddr + EMV_SIM_TX_GETU);
+	}
+}
+
+static void emvsim_xmt_fill_fifo(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+	u32 bytesleft, i;
+
+	if (!emvsim->tx_last_character) {
+		reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+		bytesleft = SIM_TX_FIFO_DEPTH - ((reg_data >> 24) & 0x1F);
+
+		if (bytesleft > emvsim->xmt_remaining)
+			bytesleft = emvsim->xmt_remaining;
+
+		for (i = 0; i < bytesleft; i++) {
+			__raw_writel(emvsim->xmt_buffer[emvsim->xmt_pos],
+				     emvsim->ioaddr + EMV_SIM_TX_BUF);
+			emvsim->xmt_pos++;
+		};
+		emvsim->xmt_remaining -= bytesleft;
+	} else {
+		/* clear guard time before sending last character */
+		emvsim_enable_guardtime(emvsim, 0);
+
+		__raw_writel(emvsim->xmt_buffer[emvsim->xmt_pos],
+			     emvsim->ioaddr + EMV_SIM_TX_BUF);
+	}
+};
+
+static void emvsim_rcv_read_fifo(struct emvsim_t *emvsim)
+{
+	u16 i, count;
+	u32 reg_data;
+	u8 data;
+
+	count  = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS)  >> 24;
+
+	spin_lock(&emvsim->lock);
+	for (i = 0; i < count; i++) {
+		reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+		emvsim->errval |= emvsim_check_rec_data(&reg_data);
+
+		/* T1 mode and t0 mode no parity error, T1 mode SIM module
+		 * will not produce NACK be NACK is disabled. T0 mode to
+		 * ensure there is no parity error for the current byte
+		 */
+		if (!(emvsim->nack_enable && (reg_data & PEF))) {
+			data = __raw_readb(emvsim->ioaddr + EMV_SIM_RX_BUF);
+			emvsim->rcv_buffer[emvsim->rcv_head + emvsim->rcv_count] = data;
+			emvsim->rcv_count++;
+		}
+
+		if (emvsim->rcv_head + emvsim->rcv_count >=
+		    SIM_RCV_BUFFER_SIZE) {
+			dev_err(emvsim_dev.parent,
+				"The software fifo is full,head %d, cnt%d\n",
+				emvsim->rcv_head, emvsim->rcv_count);
+			break;
+		}
+	}
+	spin_unlock(&emvsim->lock);
+}
+
+static void emvsim_tx_irq_enable(struct emvsim_t *emvsim)
+{
+	u32 reg_val;
+
+	/*Clear the TX&RX status, W1C */
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_RX_STATUS);
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_val |= CWT_ERR_IM | BWT_ERR_IM | RX_DATA_IM | RNACK_IM;
+
+	if (emvsim->xmt_remaining != 0) {
+		reg_val &= ~TDT_IM;
+	} else {
+		reg_val &= ~TC_IM;
+		reg_val &= ~ETC_IM;
+	}
+
+	/* NACK interrupt is enabled only when T0 mode*/
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0 ||
+	    emvsim->nack_enable != 0)
+		reg_val &= ~TNACK_IM;
+	else
+		reg_val |= TNACK_IM;
+
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_tx_irq_disable(struct emvsim_t *emvsim)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_val |= (TDT_IM | TC_IM | TNACK_IM | ETC_IM);
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_rx_irq_enable(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	/*Clear the TX&RX status, W1C */
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_RX_STATUS);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data |= (TC_IM | TDT_IM | TNACK_IM | ETC_IM);
+	reg_data &= ~(RX_DATA_IM | CWT_ERR_IM | BWT_ERR_IM);
+
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0 ||
+	    emvsim->nack_enable != 0)
+		reg_data &= ~RNACK_IM;
+	else
+		reg_data |= RNACK_IM;
+
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_rx_irq_disable(struct emvsim_t *emvsim)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_val |= (RX_DATA_IM | CWT_ERR_IM | BWT_ERR_IM | RNACK_IM);
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static irqreturn_t emvsim_irq_handler(int irq, void *dev_id)
+{
+	u32 reg_data, tx_status, rx_status;
+	struct emvsim_t *emvsim = (struct emvsim_t *)dev_id;
+
+	/* clear TX/RX interrupt status, W1C*/
+	tx_status  = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	rx_status  = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS) & ~(PEF | FEF);
+	__raw_writel(tx_status, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+	__raw_writel(rx_status, emvsim->ioaddr + EMV_SIM_RX_STATUS);
+
+	if (emvsim->state == SIM_STATE_ATR_RECEIVING &&
+	    emvsim->checking_ts_timing == 1) {
+		if ((tx_status & GPCNT0_TO) && !(rx_status & RX_DATA)) {
+			reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+			reg_data &= ~CWT_EN;
+			__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+			reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+			reg_data |= (GPCNT0_IM | CWT_ERR_IM | RX_DATA_IM);
+			__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+			emvsim->errval = SIM_ERROR_ATR_DELAY;
+			complete(&emvsim->xfer_done);
+			emvsim->checking_ts_timing = 0;
+		} else if (rx_status & RX_DATA) {
+			u8 rdt = 1;
+
+			emvsim_mask_timer0_int(emvsim);
+
+			emvsim_rcv_read_fifo(emvsim);
+
+			/* ATR each received byte will cost 12 ETU */
+			reg_data = ATR_MAX_DURATION - emvsim->rcv_count * 12;
+			__raw_writel(reg_data,  emvsim->ioaddr + EMV_SIM_GPCNT1_VAL);
+
+			reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+			reg_data &= ~(GPCNT1_IM | CWT_ERR_IM | RX_DATA_IM);
+			__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+			reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(rdt);
+			__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_RX_THD);
+
+			/* ATR has arrived as EMV demands */
+			emvsim->checking_ts_timing = 0;
+		} else {
+			dev_err(emvsim_dev.parent,
+				"Unexpected irq when delay checking\n");
+		}
+	}
+
+	else if (emvsim->state == SIM_STATE_ATR_RECEIVING) {
+		/*CWT ERROR OR ATR_MAX_DURATION TIMEOUT */
+		if ((rx_status & CWT_ERR) ||
+		    ((tx_status & GPCNT1_TO) && (emvsim->rcv_count != 0))) {
+			reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+			reg_data &= ~CWT_EN;
+			__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+			reg_data = __raw_readl(emvsim->ioaddr +
+					       EMV_SIM_INT_MASK);
+			reg_data |= (GPCNT1_IM | CWT_ERR_IM | RX_DATA_IM | GPCNT0_IM);
+			__raw_writel(reg_data, emvsim->ioaddr +
+				     EMV_SIM_INT_MASK);
+
+			if (tx_status & GPCNT1_TO)
+				emvsim->errval |= SIM_ERROR_ATR_TIMEROUT;
+
+			if (rx_status & CWT_ERR)
+				emvsim->errval |= SIM_ERROR_CWT;
+
+			emvsim_rcv_read_fifo(emvsim);
+			emvsim->state = SIM_STATE_ATR_RECEIVED;
+
+			complete(&emvsim->xfer_done);
+		} else if (rx_status & RX_DATA) {
+			emvsim_rcv_read_fifo(emvsim);
+		}
+	}
+
+	else if (emvsim->state == SIM_STATE_XMTING) {
+		/* need to enable CWT timer */
+		if (tx_status & ETCF)
+			emvsim_set_cwt(emvsim, 1);
+
+		if (tx_status & TNTE) {
+			emvsim_set_tx(emvsim, 0);
+
+			/*Disalbe the timers*/
+			emvsim_set_cwt(emvsim, 0);
+			emvsim_set_bwt(emvsim, 0);
+
+			/*Disable the NACK interruptand TX related interrupt*/
+			emvsim_tx_irq_disable(emvsim);
+
+			/*Update the state and status*/
+			emvsim->errval |= SIM_ERROR_NACK_THRESHOLD;
+			emvsim->state = SIM_STATE_XMT_ERROR;
+
+			complete(&emvsim->xfer_done);
+		} else if (tx_status & TDTF && emvsim->xmt_remaining != 0) {
+			emvsim_xmt_fill_fifo(emvsim);
+			if (emvsim->xmt_remaining == 0) {
+				reg_data = __raw_readl(emvsim->ioaddr +
+						       EMV_SIM_INT_MASK);
+				reg_data |= TDT_IM;
+				reg_data &= ~(TC_IM | ETC_IM);
+				__raw_writel(reg_data, emvsim->ioaddr +
+					     EMV_SIM_INT_MASK);
+			}
+		} else if ((tx_status & TCF) && !emvsim->xmt_remaining &&
+			   !emvsim->tx_last_character) {
+			emvsim->tx_last_character = 1;
+			emvsim_xmt_fill_fifo(emvsim);
+		} else if ((tx_status & TCF) && !emvsim->xmt_remaining &&
+			   emvsim->tx_last_character) {
+			emvsim_tx_irq_disable(emvsim);
+			emvsim_set_rx(emvsim, 1);
+			emvsim->state = SIM_STATE_XMT_DONE;
+			complete(&emvsim->xfer_done);
+		}
+	}
+
+	/*
+	 * It takes some time to change from SIM_STATE_XMT_DONE to
+	 * SIM_STATE_RECEIVING RX would only be enabled after state
+	 * becomes SIM_STATE_RECEIVING
+	 */
+	else if (emvsim->state == SIM_STATE_RECEIVING) {
+		if (rx_status & RTE) {
+			emvsim_set_rx(emvsim, 0);
+
+			/* Disable the BWT timer and CWT timer right now */
+			emvsim_set_cwt(emvsim, 0);
+			emvsim_set_bwt(emvsim, 0);
+
+			/* Disable the interrupt right now */
+			emvsim_rx_irq_disable(emvsim);
+
+			/* Should we read the fifo or just flush the fifo? */
+			emvsim_rcv_read_fifo(emvsim);
+			emvsim->errval = SIM_ERROR_NACK_THRESHOLD;
+			emvsim->state = SIM_STATE_RECEIVE_ERROR;
+			complete(&emvsim->xfer_done);
+		}
+
+		if (rx_status & RX_DATA) {
+			emvsim_rcv_read_fifo(emvsim);
+			if (emvsim->is_fixed_len_rec &&
+			    emvsim->rcv_count >= emvsim->expected_rcv_cnt) {
+				emvsim_rx_irq_disable(emvsim);
+
+				if (emvsim->state == SIM_STATE_RECEIVING) {
+					emvsim->state = SIM_STATE_RECEIVE_DONE;
+					complete(&emvsim->xfer_done);
+				}
+			}
+		}
+
+		if (rx_status & (CWT_ERR | BWT_ERR | BGT_ERR)) {
+			emvsim_set_cwt(emvsim, 0);
+			emvsim_set_bwt(emvsim, 0);
+			emvsim_rx_irq_disable(emvsim);
+
+			if (rx_status & BWT_ERR)
+				emvsim->errval |= SIM_ERROR_BWT;
+			if (rx_status & CWT_ERR)
+				emvsim->errval |= SIM_ERROR_CWT;
+			if (rx_status & BGT_ERR)
+				emvsim->errval |= SIM_ERROR_BGT;
+
+			emvsim_rcv_read_fifo(emvsim);
+
+			if (emvsim->state == SIM_STATE_RECEIVING) {
+				emvsim->state = SIM_STATE_RECEIVE_DONE;
+				complete(&emvsim->xfer_done);
+			}
+		}
+	}
+
+	else if ((emvsim->state == SIM_STATE_RESET_SEQUENCY) &&
+		 (tx_status & GPCNT0_TO)) {
+		complete(&emvsim->xfer_done);
+		emvsim_mask_timer0_int(emvsim);
+	} else if (rx_status & RX_DATA) {
+		dev_err(emvsim_dev.parent,
+			"unexpected  status %d\n", emvsim->state);
+		emvsim_rcv_read_fifo(emvsim);
+	}
+
+	return IRQ_HANDLED;
+};
+
+static void emvsim_start(struct emvsim_t *emvsim)
+{
+	u32 reg_data, clk_rate, clk_div = 0;
+
+	clk_rate = clk_get_rate(emvsim->clk);
+	clk_div = (clk_rate + emvsim->clk_rate - 1) / emvsim->clk_rate;
+	__raw_writel(clk_div, emvsim->ioaddr + EMV_SIM_CLKCFG);
+
+	usleep_range(90, 100);
+	/* SPDP=0: SIM Presence Detect pin is low, default PRESENT status */
+	if (__raw_readl(emvsim->ioaddr + EMV_SIM_PCSR) & SPDP) {
+		emvsim->present = SIM_PRESENT_REMOVED;
+		emvsim->state = SIM_STATE_REMOVED;
+	} else {
+		emvsim->present = SIM_PRESENT_DETECTED;
+		emvsim->state = SIM_STATE_DETECTED;
+	};
+
+	/* disabled card interrupt. clear interrupt status*/
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data |= SPDIM | SPDIF;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+};
+
+static void emvsim_cold_reset_sequency(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	emvsim->state = SIM_STATE_RESET_SEQUENCY;
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data &= ~VCCENP;
+	reg_data |= SVCC_EN;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	msleep(20);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data |= SCEN;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	emvsim_reset_low_timing(emvsim, EMV_RESET_LOW_CYCLES);
+
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data |= SRST;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	emvsim_mask_timer0_int(emvsim);
+	__raw_writel(ATR_MAX_DELAY_CLK, emvsim->ioaddr +
+		     EMV_SIM_GPCNT0_VAL);
+};
+
+static void emvsim_deactivate(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	/* Auto powdown to implement the deactivate sequence */
+	if (emvsim->present != SIM_PRESENT_REMOVED) {
+		reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+		reg_data |= SAPD | SPD;
+		writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+	} else {
+		dev_err(emvsim_dev.parent, ">>>No card%s\n", __func__);
+	}
+};
+
+static void emvsim_cold_reset(struct emvsim_t *emvsim)
+{
+	if (emvsim->present != SIM_PRESENT_REMOVED) {
+		emvsim->state = SIM_STATE_DETECTED;
+		emvsim->present = SIM_PRESENT_DETECTED;
+		emvsim_cold_reset_sequency(emvsim);
+		emvsim_receive_atr_set(emvsim);
+	} else {
+		dev_err(emvsim_dev.parent, "No card%s\n", __func__);
+	}
+};
+
+static void emvsim_warm_reset_sequency(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	/*enable power/clk, deassert rst*/
+	emvsim->state = SIM_STATE_RESET_SEQUENCY;
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data |= (SRST | SCEN);
+	reg_data &= ~VCCENP;
+	reg_data |= SVCC_EN;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	usleep_range(20, 25);
+
+	/* assert rst */
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data &= ~SRST;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	/* rst keep low */
+	emvsim_reset_low_timing(emvsim, EMV_RESET_LOW_CYCLES);
+
+	/* deassert rst */
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	reg_data |= SRST;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	emvsim_mask_timer0_int(emvsim);
+	__raw_writel(ATR_MAX_DELAY_CLK, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+}
+
+static void emvsim_warm_reset(struct emvsim_t *emvsim)
+{
+	if (emvsim->present != SIM_PRESENT_REMOVED) {
+		emvsim_data_reset(emvsim);
+		emvsim_reset_gpctimer(emvsim);
+		emvsim_warm_reset_sequency(emvsim);
+		emvsim_receive_atr_set(emvsim);
+	} else {
+		dev_err(emvsim_dev.parent, "No card%s\n", __func__);
+	}
+};
+
+static int emvsim_card_lock(struct emvsim_t *emvsim)
+{
+	int errval;
+
+	/* place holder for true physcial locking */
+	if (emvsim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+
+	return errval;
+};
+
+static int emvsim_card_eject(struct emvsim_t *emvsim)
+{
+	int errval;
+
+	/* place holder for true physcial locking */
+	if (emvsim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+
+	return errval;
+};
+
+static int emvsim_check_baud_rate(sim_baud_t *baud_rate)
+{
+	/* The valid value is decribed in the 8.3.3.1 in EMV 4.3 */
+	if (baud_rate->fi == 1 && (baud_rate->di == 1 ||
+	    baud_rate->di == 2 || baud_rate->di == 3))
+		return 0;
+
+	return -EINVAL;
+}
+
+static int emvsim_set_baud_rate(struct emvsim_t *emvsim)
+{
+	u32 reg_data;
+
+	switch (emvsim->baud_rate.di) {
+	case 1:
+		reg_data = 372;
+		break;
+	case 2:
+		reg_data = 372 >> 1;
+		break;
+	case 3:
+		reg_data = 372 >> 2;
+		break;
+	default:
+		dev_err(emvsim_dev.parent,
+			"Invalid baud Di, Using default 372 / 1\n");
+		reg_data = 372;
+		break;
+	}
+
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_DIVISOR);
+
+	return 0;
+}
+
+static int emvsim_check_timing_data(sim_timing_t *timing_data)
+{
+	if (timing_data->wwt > 0xFFFF || timing_data->cwt > 0xFFFF ||
+	    timing_data->bgt > 0xFFFF || timing_data->cgt > 0xFF) {
+		dev_err(emvsim_dev.parent,
+			"The timing value is out of scope of IP\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void emvsim_set_timer_counter(struct emvsim_t *emvsim)
+{
+	u32 reg;
+
+	if (emvsim->timing_data.wwt != 0 &&
+	    emvsim->protocol_type == SIM_PROTOCOL_T0) {
+		emvsim->timing_data.cwt = emvsim->timing_data.wwt;
+		emvsim->timing_data.bwt = emvsim->timing_data.wwt;
+	}
+
+	if (emvsim->timing_data.bgt != 0)
+		__raw_writel(emvsim->timing_data.bgt - BGT_BWT_ADJUSTMENT,
+			     emvsim->ioaddr + EMV_SIM_BGT_VAL);
+
+	if (emvsim->timing_data.cwt != 0)
+		__raw_writel(emvsim->timing_data.cwt + CWT_ADJUSTMENT,
+			     emvsim->ioaddr + EMV_SIM_CWT_VAL);
+
+	if (emvsim->timing_data.bwt != 0)
+		__raw_writel(emvsim->timing_data.bwt + BGT_BWT_ADJUSTMENT,
+			     emvsim->ioaddr + EMV_SIM_BWT_VAL);
+
+	/* receiver: 12 etu and 11 etu, T0: 12ETU; T1: 11ETU */
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0) {
+		reg = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+		reg &= ~RCVR_11;
+		 __raw_writel(reg, emvsim->ioaddr + EMV_SIM_CTRL);
+	} else if (emvsim->protocol_type == SIM_PROTOCOL_T1) {
+		reg = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+		reg |= RCVR_11;
+		__raw_writel(reg, emvsim->ioaddr + EMV_SIM_CTRL);
+	}
+}
+
+static int emvsim_xmt_start(struct emvsim_t *emvsim)
+{
+	u32 reg_val;
+
+	emvsim_set_baud_rate(emvsim);
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0) {
+		emvsim_set_nack(emvsim, 1);
+	} else if (emvsim->protocol_type == SIM_PROTOCOL_T1) {
+		emvsim_set_nack(emvsim, 0);
+	} else {
+		dev_err(emvsim_dev.parent, "Invalid protocol not T0 or T1\n");
+		return -EINVAL;
+	}
+
+	emvsim_set_timer_counter(emvsim);
+	emvsim_enable_guardtime(emvsim, 1);
+
+	if (emvsim->xmt_remaining != 0) {
+		reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_THD);
+		reg_val &= ~SIM_XMT_THRESHOLD_TDT_MASK;
+		reg_val |= SIM_XMT_THRESHOLD_TDT(TX_FIFO_THRESHOLD);
+		__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_THD);
+	}
+
+	emvsim_set_bwt(emvsim, 1);
+	emvsim_set_cwt(emvsim, 0);
+
+	emvsim_set_tx(emvsim, 1);
+	emvsim_xmt_fill_fifo(emvsim);
+	emvsim_tx_irq_enable(emvsim);
+	emvsim->state = SIM_STATE_XMTING;
+
+	return 0;
+}
+
+static void emvsim_flush_fifo(struct emvsim_t *emvsim, u8 flush_tx, u8 flush_rx)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+
+	if (flush_tx)
+		reg_val |= FLSH_TX;
+	if (flush_rx)
+		reg_val |= FLSH_RX;
+	__raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_start_rcv(struct emvsim_t *emvsim)
+{
+	int rdt = 1;
+
+	emvsim->state = SIM_STATE_RECEIVING;
+
+	emvsim_set_rx(emvsim, 1);
+	emvsim_set_baud_rate(emvsim);
+	emvsim_set_timer_counter(emvsim);
+	emvsim_enable_guardtime(emvsim, 0);
+	emvsim_set_cwt(emvsim, 1);
+	emvsim_set_bwt(emvsim, 1);
+
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0)
+		emvsim_set_nack(emvsim, 1);
+	else if (emvsim->protocol_type == SIM_PROTOCOL_T1)
+		emvsim_set_nack(emvsim, 0);
+
+	/*Set RX threshold*/
+	if (emvsim->protocol_type == SIM_PROTOCOL_T0)
+		__raw_writel(SIM_RCV_THRESHOLD_RTH(emvsim->nack_threshold) |
+			     SIM_RCV_THRESHOLD_RDT(rdt),
+			     emvsim->ioaddr + EMV_SIM_RX_THD);
+	else
+		__raw_writel(SIM_RCV_THRESHOLD_RDT(rdt),
+			     emvsim->ioaddr + EMV_SIM_RX_THD);
+
+	/*Clear status and enable interrupt*/
+	emvsim_rx_irq_enable(emvsim);
+}
+
+static void emvsim_polling_delay(struct emvsim_t *emvsim, u32 delay)
+{
+	u32 reg_data;
+	unsigned long orig_jiffies = jiffies;
+
+	emvsim_mask_timer1_int(emvsim);
+
+	__raw_writel(delay, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+	reg_data &= ~GPCNT1_IM;
+	__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+	/* Loop for timeout, add timeout mechanism to avoid dead loop */
+	while (!(__raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS) & GPCNT0_TO)) {
+		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+			dev_err(emvsim_dev.parent, "polling delay timeout\n");
+			break;
+		}
+
+		usleep_range(10, 20);
+	}
+
+	emvsim_mask_timer1_int(emvsim);
+}
+
+void emvsim_clear_rx_buf(struct emvsim_t *emvsim)
+{
+	unsigned int i;
+
+	for (i = 0; i < SIM_RCV_BUFFER_SIZE; i++)
+		emvsim->rcv_buffer[i] = 0;
+	emvsim->rcv_count = 0;
+	emvsim->rcv_head = 0;
+}
+
+static long emvsim_ioctl(struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	int ret, errval = SIM_OK;
+	unsigned long timeout;
+	u32 reg_data;
+	u32 delay;
+	u32 copy_cnt, val;
+	unsigned long flags;
+	unsigned char __user *atr_buffer;
+	unsigned char __user *xmt_buffer;
+	unsigned char __user *rcv_buffer;
+
+	struct emvsim_t *emvsim = (struct emvsim_t *)file->private_data;
+
+	switch (cmd) {
+	case SIM_IOCTL_GET_ATR:
+		if (emvsim->present != SIM_PRESENT_DETECTED) {
+			dev_err(emvsim_dev.parent, "NO card ...\n");
+			errval = -SIM_E_NOCARD;
+			break;
+		}
+
+		emvsim->timeout = ATR_TIMEOUT * HZ;
+		val = 0;
+		ret = copy_to_user(&(((sim_atr_t *)arg)->size), &val,
+				   sizeof((((sim_atr_t *)arg)->size)));
+
+		timeout = wait_for_completion_interruptible_timeout(
+				&emvsim->xfer_done, emvsim->timeout);
+
+		emvsim_set_rx(emvsim, 0);
+		emvsim_set_tx(emvsim, 0);
+
+		reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+		reg_data &= ~CWT_EN;
+		__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+		reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+		reg_data |= (GPCNT0_IM | GPCNT1_IM | CWT_ERR_IM | RX_DATA_IM);
+		__raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+		if (timeout == 0) {
+			dev_err(emvsim_dev.parent, "ATR timeout\n");
+			errval = -SIM_E_TIMEOUT;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_atr_t *)arg)->size),
+				   &emvsim->rcv_count,
+				   sizeof(emvsim->rcv_count));
+		if (ret) {
+			dev_err(emvsim_dev.parent,
+				"ATR ACCESS rcv_count Error, %d\n", ret);
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		__get_user(atr_buffer, &((sim_atr_t __user *)arg)->atr_buffer);
+		ret = copy_to_user(atr_buffer,
+				   emvsim->rcv_buffer, emvsim->rcv_count);
+		if (ret) {
+			dev_err(emvsim_dev.parent,
+				"ATR ACCESS buffer Error %d %d\n",
+				emvsim->rcv_count, ret);
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+				   &emvsim->errval, sizeof(emvsim->errval));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+		emvsim->rcv_count = 0;
+		emvsim->rcv_head = 0;
+		emvsim->errval = 0;
+
+		break;
+
+	case SIM_IOCTL_DEACTIVATE:
+		emvsim_deactivate(emvsim);
+		break;
+
+	case SIM_IOCTL_COLD_RESET:
+		emvsim->present = SIM_PRESENT_REMOVED;
+		emvsim->state = SIM_STATE_REMOVED;
+		emvsim_reset_module(emvsim);
+		emvsim_data_reset(emvsim);
+		emvsim_start(emvsim);
+		emvsim_cold_reset(emvsim);
+		break;
+
+	case SIM_IOCTL_WARM_RESET:
+		emvsim_warm_reset(emvsim);
+		break;
+
+	case SIM_IOCTL_XMT:
+		ret = copy_from_user(&emvsim->xmt_remaining,
+				     &(((sim_xmt_t *)arg)->xmt_length),
+				     sizeof(uint32_t));
+		if (ret || emvsim->xmt_remaining > SIM_XMT_BUFFER_SIZE) {
+			dev_err(emvsim_dev.parent,
+				"copy error or to big buffer\n");
+			errval = -EINVAL;
+			break;
+		}
+
+		__get_user(xmt_buffer, &((sim_xmt_t *)arg)->xmt_buffer);
+		ret = copy_from_user(emvsim->xmt_buffer, xmt_buffer,
+				     emvsim->xmt_remaining);
+		if (ret) {
+			dev_err(emvsim_dev.parent, "Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		/* last character must be transmitted separately due to it
+		 * can't has guard time.
+		 */
+		emvsim->xmt_remaining -= 1;
+		if (!emvsim->xmt_remaining)
+			emvsim->tx_last_character = 1;
+		else
+			emvsim->tx_last_character = 0;
+
+		emvsim_clear_rx_buf(emvsim);
+		emvsim_set_cwt(emvsim, 0);
+		emvsim_set_bwt(emvsim, 0);
+		/*Flush the tx rx fifo*/
+		emvsim_flush_fifo(emvsim, 1, 1);
+		emvsim->xmt_pos = 0;
+		emvsim->errval = 0;
+
+		errval = emvsim_xmt_start(emvsim);
+		if (errval)
+			break;
+
+		emvsim->timeout = TX_TIMEOUT * HZ;
+		timeout = wait_for_completion_interruptible_timeout(
+				&emvsim->xfer_done, emvsim->timeout);
+		if (timeout == 0) {
+			/*Disable the NACK interruptand TX related interrupt*/
+			emvsim_tx_irq_disable(emvsim);
+			dev_err(emvsim_dev.parent, "tx timeout\n");
+		}
+
+		if (timeout == 0 || emvsim->state == SIM_STATE_XMT_ERROR) {
+			dev_err(emvsim_dev.parent, "TX error\n");
+			/*Disable timers*/
+			emvsim_set_cwt(emvsim, 0);
+			emvsim_set_bwt(emvsim, 0);
+			/*Disable TX*/
+			emvsim_set_tx(emvsim, 0);
+			/*Flush the tx fifos*/
+			emvsim_flush_fifo(emvsim, 1, 0);
+			if (timeout == 0)
+				errval = -SIM_E_TIMEOUT;
+			else
+				errval = -SIM_E_NACK;
+
+			ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+					   &emvsim->errval,
+					   sizeof(emvsim->errval));
+			emvsim->errval = 0;
+			break;
+		}
+
+		/*Copy the error status to user space*/
+		ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+				   &emvsim->errval, sizeof(emvsim->errval));
+		emvsim->errval = 0;
+
+		emvsim_start_rcv(emvsim);
+
+		break;
+
+	case SIM_IOCTL_RCV:
+		if (emvsim->present != SIM_PRESENT_DETECTED) {
+			errval = -SIM_E_NOCARD;
+			break;
+		}
+
+		val = 0;
+		emvsim->is_fixed_len_rec = 0;
+		ret = copy_from_user(&emvsim->expected_rcv_cnt,
+				     &(((sim_rcv_t *)arg)->rcv_length),
+				     sizeof(emvsim->expected_rcv_cnt));
+
+		/*Set the length to be 0 at first*/
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &val,
+				   sizeof(val));
+
+		/*Set error value to be 0 at first*/
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &val,
+				   sizeof(val));
+
+		if (emvsim->expected_rcv_cnt != 0)
+			emvsim->is_fixed_len_rec = 1;
+
+		if (emvsim->is_fixed_len_rec &&
+		    emvsim->rcv_count >= emvsim->expected_rcv_cnt)
+			goto copy_data;
+
+		if (emvsim->state != SIM_STATE_RECEIVING)
+			emvsim_start_rcv(emvsim);
+
+		emvsim->timeout = RX_TIMEOUT * HZ;
+		timeout = wait_for_completion_interruptible_timeout(
+				&emvsim->xfer_done, emvsim->timeout);
+		if (timeout == 0) {
+			dev_err(emvsim_dev.parent, "Receiving timeout\n");
+			emvsim_set_cwt(emvsim, 0);
+			emvsim_set_bwt(emvsim, 0);
+			emvsim_rx_irq_disable(emvsim);
+			errval = -SIM_E_TIMEOUT;
+			break;
+		}
+copy_data:
+		if (emvsim->is_fixed_len_rec)
+			copy_cnt = emvsim->rcv_count > emvsim->expected_rcv_cnt
+				 ? emvsim->expected_rcv_cnt
+				 : emvsim->rcv_count;
+		else
+			copy_cnt = emvsim->rcv_count;
+
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length),
+				   &copy_cnt, sizeof(copy_cnt));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		__get_user(rcv_buffer, &((sim_rcv_t *)arg)->rcv_buffer);
+		ret = copy_to_user(rcv_buffer,
+				   &emvsim->rcv_buffer[emvsim->rcv_head],
+				   copy_cnt);
+		if (ret) {
+			dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->errval),
+				   &emvsim->errval, sizeof(emvsim->errval));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+		/*Reset the receiving count and errval*/
+		spin_lock_irqsave(&emvsim->lock, flags);
+		emvsim->rcv_head += copy_cnt;
+		emvsim->rcv_count -= copy_cnt;
+		emvsim->errval = 0;
+		spin_unlock_irqrestore(&emvsim->lock, flags);
+
+		break;
+
+	case SIM_IOCTL_SET_PROTOCOL:
+		ret = copy_from_user(&emvsim->protocol_type, (int *)arg,
+				     sizeof(int));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_SET_TIMING:
+		ret = copy_from_user(&emvsim->timing_data, (sim_timing_t *)arg,
+				     sizeof(sim_timing_t));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		ret = emvsim_check_timing_data(&emvsim->timing_data);
+		if (ret)
+			errval = ret;
+
+		break;
+
+	case SIM_IOCTL_SET_BAUD:
+		ret = copy_from_user(&emvsim->baud_rate, (sim_baud_t *)arg,
+				     sizeof(sim_baud_t));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		ret = emvsim_check_baud_rate(&emvsim->baud_rate);
+		if (ret) {
+			dev_err(emvsim_dev.parent, "Invalid baud rate value\n");
+			errval = ret;
+		}
+
+		break;
+	case SIM_IOCTL_WAIT:
+		ret = copy_from_user(&delay, (unsigned int *)arg,
+				     sizeof(unsigned int));
+		if (ret) {
+			dev_err(emvsim_dev.parent, "\nWait Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		emvsim_polling_delay(emvsim, delay);
+		break;
+
+	case SIM_IOCTL_GET_PRESENSE:
+		if (put_user(emvsim->present, (int *)arg))
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_CARD_LOCK:
+		errval = emvsim_card_lock(emvsim);
+		break;
+
+	case SIM_IOCTL_CARD_EJECT:
+		errval = emvsim_card_eject(emvsim);
+		break;
+	};
+
+	return errval;
+};
+
+static int emvsim_open(struct inode *inode, struct file *file)
+{
+	int errval = SIM_OK;
+	struct emvsim_t *emvsim = dev_get_drvdata(emvsim_dev.parent);
+
+	file->private_data = emvsim;
+	spin_lock_init(&emvsim->lock);
+
+	if (!emvsim->ioaddr) {
+		errval = -ENOMEM;
+		return errval;
+	}
+
+	emvsim->open_cnt = 1;
+	errval = pm_runtime_get_sync(emvsim_dev.parent);
+	if (errval < 0)
+		return errval;
+
+	init_completion(&emvsim->xfer_done);
+	errval = emvsim_reset_module(emvsim);
+	emvsim_data_reset(emvsim);
+
+	return errval;
+};
+
+static int emvsim_release(struct inode *inode, struct file *file)
+{
+	u32 reg_data;
+	struct emvsim_t *emvsim = (struct emvsim_t *)file->private_data;
+
+	/* disable presense detection interrupt */
+	reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+	__raw_writel(reg_data | SPDIM, emvsim->ioaddr + EMV_SIM_PCSR);
+
+	if (emvsim->present != SIM_PRESENT_REMOVED)
+		emvsim_deactivate(emvsim);
+
+	pm_runtime_put(emvsim_dev.parent);
+	emvsim->open_cnt = 0;
+
+	return 0;
+};
+
+static const struct file_operations emvsim_fops = {
+	.owner = THIS_MODULE,
+	.open = emvsim_open,
+	.release = emvsim_release,
+	.unlocked_ioctl = emvsim_ioctl,
+};
+
+static struct miscdevice emvsim_dev = {
+	MISC_DYNAMIC_MINOR,
+	"mxc_sim",
+	&emvsim_fops
+};
+
+static const struct of_device_id emvsim_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx8-emvsim" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, emvsim_imx_dt_ids);
+
+static int emvsim_attach_multi_pd(struct device *dev, struct emvsim_t *emvsim)
+{
+        struct device_link *link;
+
+        /* Do nothing when in a signal power domain */
+        if (dev->pm_domain)
+                return 0;
+
+        emvsim->sim_pd = dev_pm_domain_attach_by_name(dev, "sim_pd");
+        if (IS_ERR(emvsim->sim_pd))
+                return PTR_ERR(emvsim->sim_pd);
+        link = device_link_add(dev, emvsim->sim_pd,
+                               DL_FLAG_STATELESS |
+                               DL_FLAG_PM_RUNTIME |
+                               DL_FLAG_RPM_ACTIVE);
+        if (IS_ERR(link)) {
+                dev_err(dev, "Failed to add device_link to EMVSIM pd: %ld\n", PTR_ERR(link));
+                return PTR_ERR(link);
+        }
+
+        emvsim->sim_aux_pd = dev_pm_domain_attach_by_name(dev, "sim_aux_pd");
+        if (IS_ERR(emvsim->sim_aux_pd))
+                return PTR_ERR(emvsim->sim_aux_pd);
+        link = device_link_add(dev, emvsim->sim_aux_pd,
+                               DL_FLAG_STATELESS |
+                               DL_FLAG_PM_RUNTIME |
+                               DL_FLAG_RPM_ACTIVE);
+        if (IS_ERR(link)) {
+                dev_err(dev, "Failed to add device_link to EMVSIM pd: %ld\n", PTR_ERR(link));
+                return PTR_ERR(link);
+        }
+
+        return 0;
+}
+
+static int emvsim_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	const struct of_device_id *of_id;
+	struct emvsim_t *emvsim = NULL;
+
+	emvsim = devm_kzalloc(&pdev->dev, sizeof(struct emvsim_t),
+			      GFP_KERNEL);
+	if (!emvsim)
+		return -ENOMEM;
+
+	of_id = of_match_device(emvsim_imx_dt_ids, &pdev->dev);
+	if (of_id)
+		pdev->id_entry = of_id->data;
+	else
+		return -EINVAL;
+
+	emvsim->clk_rate = FCLK_FREQ;
+
+	emvsim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!emvsim->res) {
+		dev_err(&pdev->dev, "Can't get the MEMORY\n");
+		return -ENOMEM;
+	}
+	emvsim->ioaddr = devm_ioremap_resource(&pdev->dev, emvsim->res);
+	if (IS_ERR(emvsim->ioaddr)) {
+		dev_err(&pdev->dev,
+			"failed to get ioremap base\n");
+		ret = PTR_ERR(emvsim->ioaddr);
+		return ret;
+	}
+
+	/* request the emvsim per clk and ipg clk */
+	emvsim->clk = devm_clk_get(&pdev->dev, "sim");
+	if (IS_ERR(emvsim->clk)) {
+		ret = PTR_ERR(emvsim->clk);
+		dev_err(&pdev->dev, "Get PER CLK ERROR !\n");
+		return ret;
+	}
+
+	emvsim->ipg = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(emvsim->ipg)) {
+		ret = PTR_ERR(emvsim->ipg);
+		dev_err(&pdev->dev, "Get IPG CLK ERROR !\n");
+		return ret;
+	}
+
+	emvsim->irq = platform_get_irq(pdev, 0);
+	if (emvsim->irq < 0) {
+		dev_err(&pdev->dev, "No irq line provided\n");
+		return -ENOENT;
+	}
+
+	if (devm_request_irq(&pdev->dev, emvsim->irq, emvsim_irq_handler,
+			     0, "mxc_emvsim_irq", emvsim)) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", emvsim->irq);
+		return -ENOENT;
+	}
+
+	platform_set_drvdata(pdev, emvsim);
+	emvsim_dev.parent = &pdev->dev;
+
+        ret = emvsim_attach_multi_pd(&pdev->dev, emvsim);
+        if (ret)
+                return ret;
+
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	emvsim->open_cnt = 1;
+	ret = clk_prepare_enable(emvsim->ipg);
+	if (ret)
+		return ret;
+	ret = clk_prepare_enable(emvsim->clk);
+	if (ret) {
+		clk_disable_unprepare(emvsim->ipg);
+		return ret;
+	}
+	/* Let pm_runtime_put() disable the clocks.
+	 * If CONFIG_PM is not enabled, the clocks will stay powered.
+	 */
+	pm_runtime_put(&pdev->dev);
+	emvsim->open_cnt = 0;
+
+	ret = misc_register(&emvsim_dev);
+
+	dev_info(&pdev->dev, "emvsim register %s\n", ret ? "fail" : "success");
+
+	return ret;
+}
+
+static int emvsim_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	misc_deregister(&emvsim_dev);
+
+	return 0;
+}
+
+static int __maybe_unused emvsim_suspend(struct device *dev)
+{
+	int err;
+
+	err = pm_runtime_force_suspend(dev);
+	if (err)
+		return err;
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int __maybe_unused emvsim_runtime_suspend(struct device *dev)
+{
+	struct emvsim_t *emvsim = dev_get_drvdata(dev);
+
+	if (emvsim->open_cnt) {
+		clk_disable_unprepare(emvsim->clk);
+		clk_disable_unprepare(emvsim->ipg);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused emvsim_resume(struct device *dev)
+{
+	int err;
+
+	err = pm_runtime_force_resume(dev);
+	if (err)
+		return err;
+
+	pinctrl_pm_select_default_state(dev);
+
+	return 0;
+}
+
+static int __maybe_unused emvsim_runtime_resume(struct device *dev)
+{
+	int err;
+	struct emvsim_t *emvsim = dev_get_drvdata(dev);
+
+	if (emvsim->open_cnt) {
+		err = clk_prepare_enable(emvsim->ipg);
+		if (err)
+			return err;
+		err = clk_prepare_enable(emvsim->clk);
+		if (err) {
+			clk_disable_unprepare(emvsim->ipg);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops emvsim_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(emvsim_suspend, emvsim_resume)
+	SET_RUNTIME_PM_OPS(emvsim_runtime_suspend, emvsim_runtime_resume, NULL)
+};
+
+static struct platform_driver emvsim_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.pm = &emvsim_pm_ops,
+		.of_match_table = emvsim_imx_dt_ids,
+	},
+	.probe = emvsim_probe,
+	.remove = emvsim_remove,
+};
+
+static int __init emvsim_drv_init(void)
+{
+	return platform_driver_register(&emvsim_driver);
+}
+
+static void __exit emvsim_drv_exit(void)
+{
+	platform_driver_unregister(&emvsim_driver);
+}
+
+module_init(emvsim_drv_init);
+module_exit(emvsim_drv_exit);
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("NXP EMVSIM Driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/sim/imx_sim.c
+++ linux-ein-5.4.0/drivers/mxc/sim/imx_sim.c
@@ -0,0 +1,1908 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mxc_sim_interface.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "mxc_sim"
+#define SIM_INTERNAL_CLK	(0)
+#define SIM_RFU			(-1)
+
+/* Transmit and receive buffer sizes */
+#define SIM_XMT_BUFFER_SIZE	(300)
+#define SIM_RCV_BUFFER_SIZE	(400)
+
+#define SIM_TX_FIFO_DEPTH	(16)
+#define SIM_RX_FIFO_DEPTH	(285)
+
+#define TX_FIFO_THRESHOLD	(0x04)
+#define RX_FIFO_THRESHOLD	(250)
+
+/* Interface character references */
+#define SIM_IFC_TXI(letter, number) (letter + number * 4)
+#define SIM_IFC_TA1   SIM_IFC_TXI(0, 0)
+#define SIM_IFC_TB1   SIM_IFC_TXI(0, 1)
+#define SIM_IFC_TC1   SIM_IFC_TXI(0, 2)
+#define SIM_IFC_TD1   SIM_IFC_TXI(0, 3)
+#define SIM_IFC_TA2   SIM_IFC_TXI(1, 0)
+#define SIM_IFC_TB2   SIM_IFC_TXI(1, 1)
+#define SIM_IFC_TC2   SIM_IFC_TXI(1, 2)
+#define SIM_IFC_TD2   SIM_IFC_TXI(1, 3)
+#define SIM_IFC_TA3   SIM_IFC_TXI(2, 0)
+#define SIM_IFC_TB3   SIM_IFC_TXI(2, 1)
+#define SIM_IFC_TC3   SIM_IFC_TXI(2, 2)
+#define SIM_IFC_TD3   SIM_IFC_TXI(2, 3)
+#define SIM_IFC_TA4   SIM_IFC_TXI(3, 0)
+#define SIM_IFC_TB4   SIM_IFC_TXI(3, 1)
+#define SIM_IFC_TC4   SIM_IFC_TXI(3, 2)
+#define SIM_IFC_TD4   SIM_IFC_TXI(3, 3)
+
+/* ATR and OPS states */
+#define SIM_STATE_REMOVED		(0)
+#define SIM_STATE_DETECTED		(1)
+#define SIM_STATE_ATR_RECEIVING		(2)
+#define SIM_STATE_ATR_RECEIVED		(3)
+#define SIM_STATE_XMTING		(4)
+#define SIM_STATE_XMT_DONE		(5)
+#define SIM_STATE_XMT_ERROR		(6)
+#define SIM_STATE_RECEIVING		(7)
+#define SIM_STATE_RECEIVE_DONE		(8)
+#define SIM_STATE_RECEIVE_ERROR		(9)
+#define SIM_STATE_RESET_SEQUENCY	(10)
+
+/* Definitions of the offset of the SIM hardware registers */
+#define PORT1_CNTL			(0x00)
+#define SETUP				(0x04)
+#define PORT1_DETECT			(0x08)
+#define PORT1_XMT_BUF			(0x0C)
+#define PORT1_RCV_BUF			(0x10)
+#define PORT0_CNTL			(0x14)
+#define CNTL				(0x18)
+#define CLK_PRESCALER			(0x1C)
+#define RCV_THRESHOLD			(0x20)
+#define ENABLE				(0x24)
+#define XMT_STATUS			(0x28)
+#define RCV_STATUS			(0x2C)
+#define INT_MASK			(0x30)
+#define PORTO_XMT_BUF			(0x34)
+#define PORT0_RCV_BUF			(0x38)
+#define PORT0_DETECT			(0x3C)
+#define DATA_FORMAT			(0x40)
+#define XMT_THRESHOLD			(0x44)
+#define GUARD_CNTL			(0x48)
+#define OD_CONFIG			(0x4C)
+#define RESET_CNTL			(0x50)
+#define CHAR_WAIT			(0x54)
+#define GPCNT				(0x58)
+#define DIVISOR				(0x5C)
+#define BWT				(0x60)
+#define BGT				(0x64)
+#define BWT_H				(0x68)
+#define XMT_FIFO_STAT			(0x6C)
+#define RCV_FIFO_CNT			(0x70)
+#define RCV_FIFO_WPTR			(0x74)
+#define RCV_FIFO_RPTR			(0x78)
+
+/* SIM SETUP register bits */
+#define SIM_SETUP_SPS_PORT0		(0 << 1)
+#define SIM_SETUP_SPS_PORT1		(1 << 1)
+
+/* SIM port[0|1]_cntl register bits */
+#define SIM_PORT_CNTL_SFPD		(1 << 7)
+#define SIM_PORT_CNTL_3VOLT		(1 << 6)
+#define SIM_PORT_CNTL_SCSP		(1 << 5)
+#define SIM_PORT_CNTL_SCEN		(1 << 4)
+#define SIM_PORT_CNTL_SRST		(1 << 3)
+#define SIM_PORT_CNTL_STEN		(1 << 2)
+#define SIM_PORT_CNTL_SVEN		(1 << 1)
+#define SIM_PORT_CNTL_SAPD		(1 << 0)
+
+/* SIM od_config register bits */
+#define SIM_OD_CONFIG_OD_P1		(1 << 1)
+#define SIM_OD_CONFIG_OD_P0		(1 << 0)
+
+/* SIM enable register bits */
+#define SIM_ENABLE_XMTEN		(1 << 1)
+#define SIM_ENABLE_RCVEN		(1 << 0)
+#define SIM_ESTOP_EN			(1 << 5)
+#define SIM_ESTOP_EXE			(1 << 6)
+
+/* SIM int_mask register bits */
+#define SIM_INT_MASK_RFEM		(1 << 13)
+#define SIM_INT_MASK_BGTM		(1 << 12)
+#define SIM_INT_MASK_BWTM		(1 << 11)
+#define SIM_INT_MASK_RTM		(1 << 10)
+#define SIM_INT_MASK_CWTM		(1 << 9)
+#define SIM_INT_MASK_GPCM		(1 << 8)
+#define SIM_INT_MASK_TDTFM		(1 << 7)
+#define SIM_INT_MASK_TFOM		(1 << 6)
+#define SIM_INT_MASK_XTM		(1 << 5)
+#define SIM_INT_MASK_TFEIM		(1 << 4)
+#define SIM_INT_MASK_ETCIM		(1 << 3)
+#define SIM_INT_MASK_OIM		(1 << 2)
+#define SIM_INT_MASK_TCIM		(1 << 1)
+#define SIM_INT_MASK_RIM		(1 << 0)
+
+/* SIM xmt_status register bits */
+#define SIM_XMT_STATUS_GPCNT		(1 << 8)
+#define SIM_XMT_STATUS_TDTF		(1 << 7)
+#define SIM_XMT_STATUS_TFO		(1 << 6)
+#define SIM_XMT_STATUS_TC		(1 << 5)
+#define SIM_XMT_STATUS_ETC		(1 << 4)
+#define SIM_XMT_STATUS_TFE		(1 << 3)
+#define SIM_XMT_STATUS_XTE		(1 << 0)
+
+/* SIM rcv_status register bits */
+#define SIM_RCV_STATUS_BGT		(1 << 11)
+#define SIM_RCV_STATUS_BWT		(1 << 10)
+#define SIM_RCV_STATUS_RTE		(1 << 9)
+#define SIM_RCV_STATUS_CWT		(1 << 8)
+#define SIM_RCV_STATUS_CRCOK		(1 << 7)
+#define SIM_RCV_STATUS_LRCOK		(1 << 6)
+#define SIM_RCV_STATUS_RDRF		(1 << 5)
+#define SIM_RCV_STATUS_RFD		(1 << 4)
+#define SIM_RCV_STATUS_RFE		(1 << 1)
+#define SIM_RCV_STATUS_OEF		(1 << 0)
+
+/* SIM cntl register bits */
+#define SIM_CNTL_BWTEN			(1 << 15)
+#define SIM_CNTL_XMT_CRC_LRC		(1 << 14)
+#define SIM_CNTL_CRCEN			(1 << 13)
+#define SIM_CNTL_LRCEN			(1 << 12)
+#define SIM_CNTL_CWTEN			(1 << 11)
+#define SIM_CNTL_SAMPLE12		(1 << 4)
+#define SIM_CNTL_ONACK			(1 << 3)
+#define SIM_CNTL_ANACK			(1 << 2)
+#define SIM_CNTL_ICM			(1 << 1)
+#define SIM_CNTL_GPCNT_CLK_SEL(x)	((x&0x03) << 9)
+#define SIM_CNTL_GPCNT_CLK_SEL_MASK	(0x03 << 9)
+#define SIM_CNTL_BAUD_SEL(x)		((x&0x07) << 6)
+#define SIM_CNTL_BAUD_SEL_MASK		(0x07 << 6)
+#define SIM_CNTL_GPCNT_CARD_CLK		1
+#define SIM_CNTL_GPCNT_RCV_CLK		2
+#define SIM_CNTL_GPCNT_ETU_CLK		3
+
+/* SIM rcv_threshold register bits */
+#define SIM_RCV_THRESHOLD_RTH(x)	((x&0x0f) << 9)
+#define SIM_RCV_THRESHOLD_RTH_MASK	(0x0f << 9)
+#define SIM_RCV_THRESHOLD_RDT(x)	((x&0x1ff) << 0)
+#define SIM_RCV_THRESHOLD_RDT_MASK	(0x1ff << 0)
+
+/* SIM xmt_threshold register bits */
+#define SIM_XMT_THRESHOLD_XTH(x)	((x&0x0f) << 4)
+#define SIM_XMT_THRESHOLD_XTH_MASK	(0x0f << 4)
+#define SIM_XMT_THRESHOLD_TDT(x)	((x&0x0f) << 0)
+#define SIM_XMT_THRESHOLD_TDT_MASK	(0x0f << 0)
+
+/* SIM guard_cntl register bits */
+#define SIM_GUARD_CNTL_RCVR11		(1 << 8)
+#define SIM_GIARD_CNTL_GETU(x)		(x&0xff)
+#define SIM_GIARD_CNTL_GETU_MASK	(0xff)
+
+/* SIM port[0|]_detect register bits */
+#define SIM_PORT_DETECT_SPDS		(1 << 3)
+#define SIM_PORT_DETECT_SPDP		(1 << 2)
+#define SIM_PORT_DETECT_SDI		(1 << 1)
+#define SIM_PORT_DETECT_SDIM		(1 << 0)
+
+/* SIM RESET_CNTL register bits*/
+#define SIM_RESET_CNTL_FLUSH_RCV	(1 << 0)
+#define SIM_RESET_CNTL_FLUSH_XMT	(1 << 1)
+#define SIM_RESET_CNTL_SOFT_RESET	(1 << 2)
+#define SIM_RESET_CNTL_KILL_CLOCK	(1 << 3)
+#define SIM_RESET_CNTL_DOZE		(1 << 4)
+#define SIM_RESET_CNTL_STOP		(1 << 5)
+#define SIM_RESET_CNTL_DEBUG		(1 << 6)
+
+
+/*SIM receive buffer register error status*/
+#define SIM_REC_CWT_ERROR		(1 << 10)
+#define SIM_REC_FRAME_ERROR		(1 << 9)
+#define SIM_REC_PARITY_ERROR		(1 << 8)
+
+#define SIM_EMV_NACK_THRESHOLD		(5)
+#define EMV_T0_BGT			(16)
+#define EMV_T1_BGT			(22)
+#define ATR_THRESHOLD_MAX		(100)
+#define ATR_MAX_CWT			(10080)
+#define ATR_MAX_DURATION		(20160)
+#define FCLK_FREQ			(4000000)
+
+#define ATR_TIMEOUT			(5)
+#define TX_TIMEOUT			(10)
+#define RX_TIMEOUT			(100)
+#define RESET_RETRY_TIMES		(5)
+#define SIM_QUIRK_TKT259347		(1 << 0)
+#define EMV_RESET_LOW_CYCLES		40000
+#define ATR_MAX_DELAY_CLK		46400
+
+/* Main SIM driver structure */
+struct sim_t{
+	s32 present;
+	u8 open_cnt;
+	int state;
+	struct clk *clk;
+	struct resource *res;
+	void __iomem *ioaddr;
+	int ipb_irq;
+	int dat_irq;
+
+	/* error code occured during transfer */
+	int errval;
+	int protocol_type;
+	sim_timing_t timing_data;
+	sim_baud_t baud_rate;
+	int timeout;
+	u8 nack_threshold;
+	u8 nack_enable;
+	u32 expected_rcv_cnt;
+	u8 is_fixed_len_rec;
+
+	/* remaining bytes to transmit for the current transfer */
+	u32 xmt_remaining;
+	/* transmit position */
+	u32 xmt_pos;
+	/* receive position / number of bytes received */
+	u32 rcv_count;
+	u8 rcv_buffer[SIM_RCV_BUFFER_SIZE];
+	u8 xmt_buffer[SIM_XMT_BUFFER_SIZE];
+	/* transfer completion notifier */
+	struct completion xfer_done;
+	/* async notifier for card and ATR detection */
+	struct fasync_struct *fasync;
+	/* Platform specific data */
+	struct mxc_sim_platform_data *plat_data;
+	bool last_is_tx;
+	u16 rcv_head;
+	spinlock_t lock;
+	bool sven_low_active;
+	u32 port_index;
+	u32 port_detect_reg;
+	u32 port_ctrl_reg;
+	u32 clk_rate;
+	u32 quirks;
+	u8 checking_ts_timing;
+};
+
+static struct miscdevice sim_dev;
+
+static void sim_data_reset(struct sim_t *sim)
+{
+	sim->errval = SIM_OK;
+	sim->protocol_type = 0;
+	sim->timeout = 0;
+	sim->nack_threshold = SIM_EMV_NACK_THRESHOLD;
+	sim->nack_enable = 0;
+	memset(&sim->timing_data, 0, sizeof(sim->timing_data));
+	memset(&sim->baud_rate, 0, sizeof(sim->baud_rate));
+
+	sim->xmt_remaining = 0;
+	sim->xmt_pos = 0;
+	sim->rcv_count = 0;
+	sim->rcv_head = 0;
+	sim->last_is_tx = false;
+	memset(sim->rcv_buffer, 0, SIM_RCV_BUFFER_SIZE);
+	memset(sim->xmt_buffer, 0, SIM_XMT_BUFFER_SIZE);
+
+	init_completion(&sim->xfer_done);
+};
+
+static void sim_set_nack(struct sim_t *sim, u8 enable)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(sim->ioaddr + CNTL);
+	/*Disable overrun NACK setting for now*/
+	reg_val &= ~(SIM_CNTL_ONACK);
+
+	if (enable) {
+		reg_val |= SIM_CNTL_ANACK;
+		__raw_writel(reg_val, sim->ioaddr + CNTL);
+		reg_val = __raw_readl(sim->ioaddr + XMT_THRESHOLD);
+		reg_val &= ~(SIM_XMT_THRESHOLD_XTH_MASK);
+		reg_val |= SIM_XMT_THRESHOLD_XTH(sim->nack_threshold);
+		__raw_writel(reg_val, sim->ioaddr + XMT_THRESHOLD);
+	} else {
+		reg_val &= ~SIM_CNTL_ANACK;
+		__raw_writel(reg_val, sim->ioaddr + CNTL);
+	}
+
+	sim->nack_enable = enable;
+}
+
+static void sim_set_tx(struct sim_t *sim, u8 enable)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(sim->ioaddr + ENABLE);
+	if (enable) {
+		reg_data |= SIM_ENABLE_XMTEN | SIM_ENABLE_RCVEN;
+		if (sim->quirks & SIM_QUIRK_TKT259347)
+			reg_data &= ~(SIM_ESTOP_EN | SIM_ESTOP_EXE);
+	} else
+		reg_data &= ~SIM_ENABLE_XMTEN;
+
+	__raw_writel(reg_data, sim->ioaddr + ENABLE);
+}
+
+static void sim_set_rx(struct sim_t *sim, u8 enable)
+{
+	u32 reg_data;
+	reg_data = __raw_readl(sim->ioaddr + ENABLE);
+	if (enable) {
+		reg_data |= SIM_ENABLE_RCVEN;
+		reg_data &= ~SIM_ENABLE_XMTEN;
+		if (sim->quirks & SIM_QUIRK_TKT259347)
+			reg_data |= (SIM_ESTOP_EN | SIM_ESTOP_EXE);
+	} else {
+		reg_data &= ~SIM_ENABLE_RCVEN;
+		if (sim->quirks & SIM_QUIRK_TKT259347)
+			reg_data &= ~(SIM_ESTOP_EN | SIM_ESTOP_EXE);
+	}
+
+	__raw_writel(reg_data, sim->ioaddr + ENABLE);
+}
+
+static void sim_reset_timer(struct sim_t *sim)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+}
+
+static void sim_start_timer(struct sim_t *sim, u8 clk_source)
+{
+	u32 reg_data;
+
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+	reg_data |= SIM_CNTL_GPCNT_CLK_SEL(clk_source);
+	writel(reg_data, sim->ioaddr + CNTL);
+}
+
+static void sim_set_gpc_timer(struct sim_t *sim, u32 val)
+{
+	uint32_t reg_data;
+
+	/*Clear the interrupt status*/
+	reg_data = __raw_readl(sim->ioaddr + XMT_STATUS);
+	reg_data |= SIM_XMT_STATUS_GPCNT;
+	__raw_writel(reg_data, sim->ioaddr + XMT_STATUS);
+
+	/*Set the timer counter*/
+	__raw_writel(val, sim->ioaddr + GPCNT);
+
+	/*First reset the counter*/
+	sim_reset_timer(sim);
+
+	/*Enable GPC timer interrupt*/
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data &= ~SIM_INT_MASK_GPCM;
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+	/*Set the GPCNT clock source to be Fclk*/
+	sim_start_timer(sim, SIM_CNTL_GPCNT_CARD_CLK);
+}
+
+static int sim_reset_low_timing(struct sim_t *sim, u32 clock_cycle)
+{
+	int errval = 0;
+	int timeout = 0;
+	u32 fclk_in_khz, delay_in_us, reg_data;
+
+	fclk_in_khz = sim->clk_rate / MSEC_PER_SEC;
+	delay_in_us = EMV_RESET_LOW_CYCLES * USEC_PER_MSEC / fclk_in_khz;
+
+	sim_set_gpc_timer(sim, clock_cycle);
+
+	timeout  = wait_for_completion_timeout(&sim->xfer_done,
+					msecs_to_jiffies(delay_in_us / 1000 * 2));
+	if (timeout == 0) {
+		pr_err("Reset low GPC timout\n");
+		errval =  -SIM_E_TIMEOUT;
+	}
+
+	sim_reset_timer(sim);
+	/*Disable GPC timer interrupt*/
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data |= SIM_INT_MASK_GPCM;
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+	return errval;
+}
+
+static void sim_set_cwt(struct sim_t *sim, u8 enable)
+{
+	u32 reg_val;
+	reg_val = __raw_readl(sim->ioaddr + CNTL);
+	if (enable && sim->timing_data.cwt)
+		reg_val |= SIM_CNTL_CWTEN;
+	else
+		reg_val &= ~SIM_CNTL_CWTEN;
+	__raw_writel(reg_val, sim->ioaddr + CNTL);
+}
+
+static void sim_set_bwt(struct sim_t *sim, u8 enable)
+{
+	u32 reg_val;
+	reg_val = __raw_readl(sim->ioaddr + CNTL);
+	if (enable && (sim->timing_data.bwt || sim->timing_data.bgt))
+		reg_val |= SIM_CNTL_BWTEN;
+	else
+		reg_val &= ~SIM_CNTL_BWTEN;
+	__raw_writel(reg_val, sim->ioaddr + CNTL);
+}
+
+static int sim_reset_module(struct sim_t *sim)
+{
+	u32 reg_val;
+	s8 timeout = RESET_RETRY_TIMES;
+
+	reg_val = __raw_readl(sim->ioaddr + RESET_CNTL);
+	reg_val |= (SIM_RESET_CNTL_SOFT_RESET);
+	__raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+
+	while (__raw_readl(sim->ioaddr + RESET_CNTL) & SIM_RESET_CNTL_SOFT_RESET) {
+		usleep_range(1, 3);
+		if (timeout-- <= 0) {
+			pr_err("SIM module reset timeout\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static void sim_receive_atr_set(struct sim_t *sim)
+{
+	u32 reg_data;
+
+	/*Enable RX*/
+	sim_set_rx(sim, 1);
+
+	/*Receive fifo threshold = 1*/
+	reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(1);
+	__raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
+
+	/* Clear the interrupt status*/
+	reg_data = __raw_readl(sim->ioaddr + RCV_STATUS);
+	reg_data |= (SIM_RCV_STATUS_CWT | SIM_RCV_STATUS_RDRF);
+	__raw_writel(reg_data, sim->ioaddr + RCV_STATUS);
+
+	/*Set the cwt timer.Refer the setting of ATR on EMV4.3 book*/
+	__raw_writel(ATR_MAX_CWT, sim->ioaddr + CHAR_WAIT);
+
+	/*Set the baud rate to be 1/372. Refer the setting of ATR on EMV4.3 book
+	 *Enable the CWT timer during receiving ATR process.
+	 */
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~SIM_CNTL_BAUD_SEL_MASK;
+	reg_data |= SIM_CNTL_BAUD_SEL(0) | SIM_CNTL_CWTEN;
+
+	/*Enable ICM mode*/
+	reg_data |= SIM_CNTL_ICM;
+
+	/*Enable Sample12*/
+	reg_data |= SIM_CNTL_SAMPLE12;
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+	/*Disable NACK*/
+	sim_set_nack(sim, 0);
+
+	/*Set 12 ETUS*/
+	__raw_writel(0, sim->ioaddr + GUARD_CNTL);
+
+	sim->errval = 0;
+	sim->rcv_count = 0;
+	sim->checking_ts_timing = 1;
+	sim->state = SIM_STATE_ATR_RECEIVING;
+
+	/*Enable the RIM and GPC interrupt, disalbe the CWT interrupt*/
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data |= SIM_INT_MASK_CWTM;
+	reg_data &= ~(SIM_INT_MASK_RIM | SIM_INT_MASK_GPCM);
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+}
+
+static int32_t sim_check_rec_data(u32 *reg_data)
+{
+	s32 err = 0;
+
+	if (*reg_data & SIM_REC_CWT_ERROR)
+		err |= SIM_ERROR_CWT;
+
+	if (*reg_data & SIM_REC_FRAME_ERROR)
+		err |= SIM_ERROR_FRAME;
+
+	if (*reg_data & SIM_REC_PARITY_ERROR)
+		err |= SIM_ERROR_PARITY;
+
+	return err;
+}
+
+static void sim_xmt_fill_fifo(struct sim_t *sim)
+{
+	u32 reg_data;
+	u32 bytesleft, i;
+
+	reg_data = __raw_readl(sim->ioaddr + XMT_FIFO_STAT);
+	bytesleft = SIM_TX_FIFO_DEPTH - ((reg_data >> 8) & 0x0F);
+
+	if (bytesleft > sim->xmt_remaining)
+		bytesleft = sim->xmt_remaining;
+
+	for (i = 0; i < bytesleft; i++) {
+		__raw_writel(sim->xmt_buffer[sim->xmt_pos],
+			     sim->ioaddr + PORT1_XMT_BUF);
+		sim->xmt_pos++;
+	};
+	sim->xmt_remaining -= bytesleft;
+};
+
+static void sim_rcv_read_fifo(struct sim_t *sim)
+{
+	u16 i, count;
+	u32 reg_data;
+
+	count  = __raw_readl(sim->ioaddr + RCV_FIFO_CNT);
+
+	spin_lock(&sim->lock);
+	for (i = 0; i < count; i++) {
+		reg_data = __raw_readl(sim->ioaddr + PORT1_RCV_BUF);
+		sim->errval |= sim_check_rec_data(&reg_data);
+
+		/* T1 mode and t0 mode no parity error, T1 mode SIM module will not produce NACK be
+		 * NACK is disabled. T0 mode to ensure there is no parity error for the current byte
+		 */
+		if (!(sim->nack_enable && (reg_data & SIM_REC_PARITY_ERROR))) {
+			sim->rcv_buffer[sim->rcv_head + sim->rcv_count] = (u8)reg_data;
+			sim->rcv_count++;
+		}
+		if (sim->rcv_head + sim->rcv_count >= SIM_RCV_BUFFER_SIZE) {
+			pr_err("The software fifo is full,head %d, cnt%d\n", sim->rcv_head, sim->rcv_count);
+			break;
+		}
+	}
+	spin_unlock(&sim->lock);
+}
+
+static void sim_tx_irq_enable(struct sim_t *sim)
+{
+	u32 reg_val;
+	/*Clear the status and enable the related interrupt*/
+	reg_val = __raw_readl(sim->ioaddr + XMT_STATUS);
+	__raw_writel(reg_val, sim->ioaddr + XMT_STATUS);
+	reg_val = __raw_readl(sim->ioaddr + RCV_STATUS);
+	__raw_writel(reg_val, sim->ioaddr + RCV_STATUS);
+
+	reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+	/*
+	 *Disable CWT , BWT interrupt when transmitting, it would
+	 *be enabled when rx is enabled just after tx completes
+	 *The timer will be enabled.
+	 */
+	reg_val |= SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM;
+	reg_val |= SIM_INT_MASK_RIM | SIM_INT_MASK_RTM;
+
+	if (sim->xmt_remaining != 0)
+		reg_val &= ~SIM_INT_MASK_TDTFM;
+	else{
+		reg_val &= ~SIM_INT_MASK_TCIM;
+		/*Enable transmit early complete interrupt.*/
+		reg_val &= ~SIM_INT_MASK_ETCIM;
+	}
+
+	/*NACK interrupt is enabled only when T0 mode*/
+	if (sim->protocol_type == SIM_PROTOCOL_T0 || sim->nack_enable != 0)
+		reg_val &= ~SIM_INT_MASK_XTM;
+	else
+		reg_val |= SIM_INT_MASK_XTM;
+	__raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static void sim_tx_irq_disable(struct sim_t *sim)
+{
+	u32 reg_val;
+	/*Disable the NACK interruptand TX related interrupt*/
+	reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_val |= (SIM_INT_MASK_TDTFM | SIM_INT_MASK_TCIM | SIM_INT_MASK_XTM | SIM_INT_MASK_ETCIM);
+	__raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static void sim_rx_irq_enable(struct sim_t *sim)
+{
+	u32 reg_data;
+	/*
+	 * Ensure the CWT timer is enabled.
+	 */
+	sim_set_cwt(sim, 1);
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data |= (SIM_INT_MASK_TCIM | SIM_INT_MASK_TDTFM | SIM_INT_MASK_XTM);
+	reg_data &= ~(SIM_INT_MASK_RIM | SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM);
+
+	if (sim->protocol_type == SIM_PROTOCOL_T0 || sim->nack_enable != 0)
+		reg_data &= ~SIM_INT_MASK_RTM;
+	else
+		reg_data |= SIM_INT_MASK_RTM;
+
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+}
+
+static void sim_rx_irq_disable(struct sim_t *sim)
+{
+	u32 reg_val;
+	reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_val |= (SIM_INT_MASK_RIM | SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM | SIM_INT_MASK_RTM);
+	__raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static irqreturn_t sim_irq_handler(int irq, void *dev_id)
+{
+	u32 reg_data, tx_status, rx_status;
+
+	struct sim_t *sim = (struct sim_t *) dev_id;
+
+	tx_status  = __raw_readl(sim->ioaddr + XMT_STATUS);
+	rx_status  = __raw_readl(sim->ioaddr + RCV_STATUS);
+	__raw_writel(tx_status, sim->ioaddr + XMT_STATUS);
+	__raw_writel(rx_status, sim->ioaddr + RCV_STATUS);
+
+	if (sim->state == SIM_STATE_ATR_RECEIVING &&
+		sim->checking_ts_timing == 1) {
+
+		if ((tx_status & SIM_XMT_STATUS_GPCNT) &&
+			!(rx_status & SIM_RCV_STATUS_RDRF)) {
+			/*Disable the GPCNT timer and CWT timer right now*/
+			reg_data = __raw_readl(sim->ioaddr + CNTL);
+			reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK |
+					SIM_CNTL_CWTEN);
+			__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+			reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+			reg_data |= (SIM_INT_MASK_GPCM |
+					SIM_INT_MASK_CWTM | SIM_INT_MASK_RIM);
+			__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+			sim->errval = SIM_ERROR_ATR_DELAY;
+			complete(&sim->xfer_done);
+			sim->checking_ts_timing = 0;
+		} else if (rx_status & SIM_RCV_STATUS_RDRF) {
+			/*
+			 * Reset/stop the GPCNT timer first.
+			 */
+			sim_reset_timer(sim);
+
+			/*Enable GPC, CWT interrupt and
+			 *disable the rx full interrupt
+			 */
+			reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+			reg_data &= ~(SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+			reg_data |= SIM_INT_MASK_RIM;
+			__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+			sim_rcv_read_fifo(sim);
+
+			/*Clear the GPCNT expiring status*/
+			__raw_writel(SIM_XMT_STATUS_GPCNT,
+					sim->ioaddr + XMT_STATUS);
+
+			/*ATR each recieved byte will cost 12 ETU, so get the remaining etus*/
+			reg_data = ATR_MAX_DURATION - sim->rcv_count * 12;
+			__raw_writel(reg_data, sim->ioaddr + GPCNT);
+
+			sim_start_timer(sim, SIM_CNTL_GPCNT_ETU_CLK);
+
+			/*Receive fifo threshold set to max value*/
+			reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(ATR_THRESHOLD_MAX);
+			__raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
+			sim->checking_ts_timing = 0;
+		} else {
+			pr_err("Unexpected irq when delay checking\n");
+		}
+	}
+
+	else if (sim->state == SIM_STATE_ATR_RECEIVING) {
+		if ((rx_status & SIM_RCV_STATUS_CWT) ||
+			((tx_status & SIM_XMT_STATUS_GPCNT) &&
+				(sim->rcv_count != 0))) {
+
+			/*Disable the GPCNT timer and CWT timer right now*/
+			reg_data = __raw_readl(sim->ioaddr + CNTL);
+			reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK | SIM_CNTL_CWTEN);
+			__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+			reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+			reg_data |= (SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+			__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+			if (tx_status & SIM_XMT_STATUS_GPCNT)
+				sim->errval |= SIM_ERROR_ATR_TIMEROUT;
+
+			if (rx_status & SIM_RCV_STATUS_CWT)
+				sim->errval |= SIM_ERROR_CWT;
+
+			sim_rcv_read_fifo(sim);
+			sim->state = SIM_STATE_ATR_RECEIVED;
+
+			complete(&sim->xfer_done);
+		}
+	}
+
+	else if (sim->state == SIM_STATE_XMTING) {
+		/*The CWT BWT expire should not happen when in the transmitting state*/
+		if (tx_status & SIM_XMT_STATUS_ETC) {
+			/*Once the transmit frame is completed, need to enable CWT timer*/
+			sim_set_cwt(sim, 1);
+		}
+		if (tx_status & SIM_XMT_STATUS_XTE) {
+			/*Disable TX*/
+			sim_set_tx(sim, 0);
+			/*Disalbe the timers*/
+			sim_set_cwt(sim, 0);
+			sim_set_bwt(sim, 0);
+			/*Disable the NACK interruptand TX related interrupt*/
+			sim_tx_irq_disable(sim);
+
+			/*Update the state and status*/
+			sim->errval |= SIM_ERROR_NACK_THRESHOLD;
+			sim->state = SIM_STATE_XMT_ERROR;
+
+			complete(&sim->xfer_done);
+		} else if (tx_status & SIM_XMT_STATUS_TDTF && sim->xmt_remaining != 0) {
+			sim_xmt_fill_fifo(sim);
+			if (sim->xmt_remaining == 0) {
+				/*Disable TX threshold interrupt and enable tx complete interrupt*/
+				reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+				reg_data |= SIM_INT_MASK_TDTFM;
+				/*Enable transmit complete and early transmit complete interrupt*/
+				reg_data &= ~(SIM_INT_MASK_TCIM | SIM_INT_MASK_ETCIM);
+				__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+			}
+		} else if (tx_status & SIM_XMT_STATUS_TC && sim->xmt_remaining == 0) {
+			/*Disable the NACK interruptand TX related interrupt*/
+			sim_tx_irq_disable(sim);
+			sim_set_rx(sim, 1);
+			/*Update the state and status*/
+			sim->state = SIM_STATE_XMT_DONE;
+			complete(&sim->xfer_done);
+		}
+	}
+
+	/*
+	 * It takes some time to change from SIM_STATE_XMT_DONE to SIM_STATE_RECEIVING
+	 * RX would only be enabled after state becomes SIM_STATE_RECEIVING
+	 */
+	else if (sim->state == SIM_STATE_RECEIVING) {
+		if (rx_status & SIM_RCV_STATUS_RTE) {
+			/*Disable RX*/
+			sim_set_rx(sim, 0);
+			/*Disable the BWT timer and CWT timer right now*/
+			sim_set_cwt(sim, 0);
+			sim_set_bwt(sim, 0);
+			/*Disable the interrupt right now*/
+			sim_rx_irq_disable(sim);
+			/*Should we read the fifo or just flush the fifo?*/
+			sim_rcv_read_fifo(sim);
+			sim->errval = SIM_ERROR_NACK_THRESHOLD;
+			sim->state = SIM_STATE_RECEIVE_ERROR;
+			complete(&sim->xfer_done);
+		}
+
+		if (rx_status & SIM_RCV_STATUS_RDRF) {
+			sim_rcv_read_fifo(sim);
+			if (sim->is_fixed_len_rec &&
+				sim->rcv_count >= sim->expected_rcv_cnt) {
+
+				/*Disable the BWT timer and CWT timer right now*/
+				sim_rx_irq_disable(sim);
+				/*Add the state judgement to ensure the maybe complete has been impletment in the above "if" case*/
+				if (sim->state == SIM_STATE_RECEIVING) {
+					sim->state = SIM_STATE_RECEIVE_DONE;
+					complete(&sim->xfer_done);
+				}
+			}
+		}
+
+		if ((rx_status & SIM_RCV_STATUS_CWT) ||
+			(rx_status & SIM_RCV_STATUS_BWT) ||
+			(rx_status & SIM_RCV_STATUS_BGT)) {
+
+			/*Disable the BWT timer and CWT timer right now*/
+			sim_set_cwt(sim, 0);
+			sim_set_bwt(sim, 0);
+			sim_rx_irq_disable(sim);
+
+			if (rx_status & SIM_RCV_STATUS_BWT) {
+				sim->errval |= SIM_ERROR_BWT;
+			}
+			if (rx_status & SIM_RCV_STATUS_CWT)
+				sim->errval |= SIM_ERROR_CWT;
+			if (rx_status & SIM_RCV_STATUS_BGT)
+				sim->errval |= SIM_ERROR_BGT;
+
+			sim_rcv_read_fifo(sim);
+			/*Add the state judgement to ensure the maybe complete has been impletment in the above "if" case*/
+			if (sim->state == SIM_STATE_RECEIVING) {
+				sim->state = SIM_STATE_RECEIVE_DONE;
+				complete(&sim->xfer_done);
+			}
+		}
+	}
+
+	else if ((sim->state == SIM_STATE_RESET_SEQUENCY) &&
+			(tx_status & SIM_XMT_STATUS_GPCNT))
+		complete(&sim->xfer_done);
+	else if (rx_status & SIM_RCV_STATUS_RDRF) {
+		pr_err("unexpected  status %d\n", sim->state);
+		sim_rcv_read_fifo(sim);
+	}
+
+	return IRQ_HANDLED;
+};
+
+static void sim_start(struct sim_t *sim)
+{
+	u32 reg_data, clk_rate, clk_div = 0;
+	pr_debug("%s entering.\n", __func__);
+
+	if (sim->port_index == 1)
+		__raw_writel(SIM_SETUP_SPS_PORT1, sim->ioaddr + SETUP);
+	else
+		__raw_writel(SIM_SETUP_SPS_PORT0, sim->ioaddr + SETUP);
+
+	/*1 ~ 5 MHz */
+	clk_rate = clk_get_rate(sim->clk);
+	clk_div = (clk_rate + sim->clk_rate - 1) / sim->clk_rate;
+	__raw_writel(clk_div, sim->ioaddr + CLK_PRESCALER);
+
+	/*Set the port pin to be open drained*/
+	reg_data = __raw_readl(sim->ioaddr + OD_CONFIG);
+	if (sim->port_index == 1)
+		reg_data |= SIM_OD_CONFIG_OD_P1;
+	else
+		reg_data |= SIM_OD_CONFIG_OD_P0;
+
+	__raw_writel(reg_data, sim->ioaddr + OD_CONFIG);
+
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+
+	/*One pin mode*/
+	reg_data |= SIM_PORT_CNTL_3VOLT | SIM_PORT_CNTL_STEN;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	/* presense detect */
+	pr_debug("%s p0_det is 0x%x \n", __func__,
+		 __raw_readl(sim->ioaddr + sim->port_detect_reg));
+	if (__raw_readl(sim->ioaddr +  sim->port_detect_reg)
+			& SIM_PORT_DETECT_SPDP) {
+		reg_data = __raw_readl(sim->ioaddr +  sim->port_detect_reg);
+		reg_data &= ~SIM_PORT_DETECT_SPDS;
+		__raw_writel(reg_data, sim->ioaddr +  sim->port_detect_reg);
+		sim->present = SIM_PRESENT_REMOVED;
+		sim->state = SIM_STATE_REMOVED;
+	} else {
+		reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+		reg_data |= SIM_PORT_DETECT_SPDS;
+		__raw_writel(reg_data, sim->ioaddr + sim->port_detect_reg);
+		sim->present = SIM_PRESENT_DETECTED;
+		sim->state = SIM_STATE_DETECTED;
+	};
+
+	/*enable card interrupt. clear interrupt status*/
+	reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+	reg_data |= SIM_PORT_DETECT_SDI;
+	reg_data |= SIM_PORT_DETECT_SDIM;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_detect_reg);
+};
+
+static void sim_cold_reset_sequency(struct sim_t *sim)
+{
+	u32 reg_data;
+
+	sim->state = SIM_STATE_RESET_SEQUENCY;
+
+	/*set VCC*/
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	if (sim->sven_low_active)
+		reg_data &= ~SIM_PORT_CNTL_SVEN;
+	else
+		reg_data |= SIM_PORT_CNTL_SVEN;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	msleep(9);
+
+	/*enable CLK*/
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	reg_data |= SIM_PORT_CNTL_SCEN;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	/*RST low time*/
+	sim_reset_low_timing(sim, EMV_RESET_LOW_CYCLES);
+
+	/*RST high*/
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	reg_data |= SIM_PORT_CNTL_SRST;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	/*wait for ATR*/
+	sim_set_gpc_timer(sim, ATR_MAX_DELAY_CLK);
+};
+
+static void sim_deactivate(struct sim_t *sim)
+{
+	u32 reg_data;
+
+	pr_debug("%s entering.\n", __func__);
+	/* Auto powdown to implement the deactivate sequence */
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		if (sim->sven_low_active) {
+			/*Set the RESET to be low*/
+			reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+			reg_data &= ~SIM_PORT_CNTL_SRST;
+			writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+			usleep_range(2, 5);
+
+			/*Set the clock to be low*/
+			reg_data &= ~SIM_PORT_CNTL_SCEN;
+			writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+			usleep_range(2, 5);
+
+			/*Set the sven to be high*/
+			reg_data |= SIM_PORT_CNTL_SVEN;
+			writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+		} else {
+			reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+			reg_data |= SIM_PORT_CNTL_SAPD;
+			__raw_writel(reg_data,
+				sim->ioaddr + sim->port_ctrl_reg);
+			reg_data |= SIM_PORT_CNTL_SFPD;
+			__raw_writel(reg_data,
+				sim->ioaddr + sim->port_ctrl_reg);
+		}
+	} else
+		pr_err(">>>No card%s\n", __func__);
+};
+
+static void sim_cold_reset(struct sim_t *sim)
+{
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		sim->state = SIM_STATE_DETECTED;
+		sim->present = SIM_PRESENT_DETECTED;
+		sim_cold_reset_sequency(sim);
+		sim_receive_atr_set(sim);
+	} else {
+		pr_err("No card%s\n", __func__);
+	}
+};
+
+static void sim_warm_reset_sequency(struct sim_t *sim)
+{
+	u32 reg_data;
+
+	sim->state = SIM_STATE_RESET_SEQUENCY;
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	reg_data |= (SIM_PORT_CNTL_SRST | SIM_PORT_CNTL_SCEN);
+	if (sim->sven_low_active)
+		reg_data &= ~SIM_PORT_CNTL_SVEN;
+	else
+		reg_data |= SIM_PORT_CNTL_SVEN;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	usleep_range(20, 25);
+
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	reg_data &= ~SIM_PORT_CNTL_SRST;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+	sim_reset_low_timing(sim, EMV_RESET_LOW_CYCLES);
+
+	reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+	reg_data |= SIM_PORT_CNTL_SRST;
+	__raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+	sim_set_gpc_timer(sim, ATR_MAX_DELAY_CLK);
+}
+
+static void sim_warm_reset(struct sim_t *sim)
+{
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		sim_data_reset(sim);
+		sim_warm_reset_sequency(sim);
+		sim_receive_atr_set(sim);
+	} else {
+		pr_err("No card%s\n", __func__);
+	}
+};
+
+
+static int sim_card_lock(struct sim_t *sim)
+{
+	int errval;
+
+	/* place holder for true physcial locking */
+	if (sim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+	return errval;
+};
+
+static int sim_card_eject(struct sim_t *sim)
+{
+	int errval;
+
+	pr_debug("%s entering.\n", __func__);
+	/* place holder for true physcial locking */
+	if (sim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+	return errval;
+};
+
+static int sim_check_baud_rate(sim_baud_t *baud_rate)
+{
+	/*
+	 * The valid value is decribed in the 8.3.3.1 in EMV 4.3
+	 */
+	if (baud_rate->fi == 1 && (baud_rate->di == 1 ||
+					baud_rate->di == 2 || baud_rate->di == 3))
+		return 0;
+
+	return -EINVAL;
+}
+
+static int sim_set_baud_rate(struct sim_t *sim)
+{
+	u32 reg_data;
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~(SIM_CNTL_BAUD_SEL_MASK);
+
+	switch (sim->baud_rate.di) {
+	case 1:
+		reg_data |= SIM_CNTL_BAUD_SEL(0);
+		break;
+	case 2:
+		reg_data |= SIM_CNTL_BAUD_SEL(1);
+		break;
+	case 3:
+		reg_data |= SIM_CNTL_BAUD_SEL(2);
+		break;
+	default:
+		pr_err("Invalid baud Di, Using default 372 / 1\n");
+		reg_data |= SIM_CNTL_BAUD_SEL(0);
+		break;
+	}
+
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+	return 0;
+}
+
+static int sim_check_timing_data(sim_timing_t *timing_data)
+{
+	if (timing_data->wwt > 0xFFFF ||
+		timing_data->cwt > 0xFFFF ||
+		timing_data->bgt > 0xFFFF ||
+		timing_data->cgt > 0xFF) {
+		/*Check whether the counter is out of the scope of SIM IP*/
+		pr_err("The timing value is out of scope of IP\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void sim_set_timer_counter(struct sim_t *sim)
+{
+	if (sim->timing_data.wwt != 0 &&
+		sim->protocol_type == SIM_PROTOCOL_T0) {
+		sim->timing_data.cwt = sim->timing_data.wwt;
+		sim->timing_data.bwt = sim->timing_data.wwt;
+	}
+
+
+	if (sim->timing_data.bgt != 0) {
+		__raw_writel(sim->timing_data.bgt, sim->ioaddr + BGT);
+	}
+
+	if (sim->timing_data.cwt != 0)
+		__raw_writel(sim->timing_data.cwt, sim->ioaddr + CHAR_WAIT);
+
+	if (sim->timing_data.bwt != 0) {
+
+		__raw_writel(sim->timing_data.bwt & 0x0000FFFF, sim->ioaddr + BWT);
+		__raw_writel((sim->timing_data.bwt >> 16) & 0x0000FFFF,
+				sim->ioaddr + BWT_H);
+	}
+
+	if (sim->timing_data.cgt == 0xFF && sim->protocol_type == SIM_PROTOCOL_T0)
+		/* From EMV4.3 , CGT =0xFF in T0 mode means 12 ETU.
+		 * Set register to be 12 ETU for transmitting and receiving.
+		 */
+		__raw_writel(0 , sim->ioaddr + GUARD_CNTL);
+	else if (sim->timing_data.cgt == 0xFF && sim->protocol_type == SIM_PROTOCOL_T1)
+		/* From EMV4.3 , CGT =0xFF in T1 mode means 11 ETU.
+		 * Set register to be 12 ETU for transmitting and receiving.
+		 */
+		__raw_writel(0x1FF , sim->ioaddr + GUARD_CNTL);
+
+	/*For the T1 mode, use 11ETU to receive.*/
+	else if (sim->protocol_type == SIM_PROTOCOL_T1)
+		__raw_writel((sim->timing_data.cgt | SIM_GUARD_CNTL_RCVR11), sim->ioaddr + GUARD_CNTL);
+
+	else
+		/*sim->protocol_type == SIM_PROTOCOL_T0*/
+		__raw_writel(sim->timing_data.cgt, sim->ioaddr + GUARD_CNTL);
+}
+
+static void sim_xmt_start(struct sim_t *sim)
+{
+	u32 reg_val;
+
+	/*Set TX threshold if there are remaing data*/
+	if (sim->xmt_remaining != 0) {
+		reg_val = __raw_readl(sim->ioaddr + XMT_THRESHOLD);
+		reg_val &= ~SIM_XMT_THRESHOLD_TDT_MASK;
+		reg_val |= SIM_XMT_THRESHOLD_TDT(TX_FIFO_THRESHOLD);
+		__raw_writel(reg_val, sim->ioaddr + XMT_THRESHOLD);
+	}
+	sim_tx_irq_enable(sim);
+
+	/*Enable  BWT and disalbe CWT timers when tx*/
+	sim_set_bwt(sim, 1);
+	sim_set_cwt(sim, 0);
+
+	/*Disalbe RX*/
+	sim_set_rx(sim, 0);
+
+	/*Enable TX*/
+	sim_set_tx(sim, 1);
+}
+
+static void sim_flush_fifo(struct sim_t *sim, u8 flush_tx, u8 flush_rx)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(sim->ioaddr + RESET_CNTL);
+
+	if (flush_tx)
+		reg_val |= SIM_RESET_CNTL_FLUSH_XMT;
+	if (flush_rx)
+		reg_val |= SIM_RESET_CNTL_FLUSH_RCV;
+	__raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+
+	usleep_range(2, 3);
+
+	if (flush_tx)
+		reg_val &= ~(SIM_RESET_CNTL_FLUSH_XMT);
+	if (flush_rx)
+		reg_val &= ~(SIM_RESET_CNTL_FLUSH_RCV);
+	__raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+}
+
+static void sim_change_rcv_threshold(struct sim_t *sim)
+{
+	u32 rx_threshold = 0;
+	u32 reg_val = 0;
+
+	if (sim->is_fixed_len_rec) {
+		rx_threshold = sim->expected_rcv_cnt - sim->rcv_count;
+		reg_val = __raw_readl(sim->ioaddr + RCV_THRESHOLD);
+		reg_val &= ~(SIM_RCV_THRESHOLD_RDT_MASK);
+		reg_val |= SIM_RCV_THRESHOLD_RDT(rx_threshold);
+		__raw_writel(reg_val, sim->ioaddr + RCV_THRESHOLD);
+	}
+}
+
+static void sim_start_rcv(struct sim_t *sim)
+{
+	sim_set_baud_rate(sim);
+	if (sim->protocol_type == SIM_PROTOCOL_T0)
+		sim_set_nack(sim, 1);
+	else if (sim->protocol_type == SIM_PROTOCOL_T1)
+		sim_set_nack(sim, 0);
+
+	/*Set RX threshold*/
+	if (sim->protocol_type == SIM_PROTOCOL_T0)
+		__raw_writel(SIM_RCV_THRESHOLD_RTH(sim->nack_threshold) |
+				SIM_RCV_THRESHOLD_RDT(RX_FIFO_THRESHOLD), sim->ioaddr + RCV_THRESHOLD);
+	 else
+		__raw_writel(SIM_RCV_THRESHOLD_RDT(RX_FIFO_THRESHOLD), sim->ioaddr + RCV_THRESHOLD);
+
+	/*Clear status and enable interrupt*/
+	sim_rx_irq_enable(sim);
+
+	/*Disalbe TX and Enable Rx*/
+	sim_set_rx(sim, 1);
+	sim_set_tx(sim, 0);
+}
+
+static void sim_polling_delay(struct sim_t *sim, u32 delay)
+{
+	u32 reg_data;
+
+	/*Reset the timer*/
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+	reg_data |= SIM_CNTL_GPCNT_CLK_SEL(0);
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+	/*Clear the interrupt status*/
+	__raw_writel(SIM_XMT_STATUS_GPCNT, sim->ioaddr + XMT_STATUS);
+
+	/*Disable timer interrupt*/
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data |= SIM_INT_MASK_GPCM;
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+	__raw_writel(delay, sim->ioaddr + GPCNT);
+
+	/*Set the ETU as clock source and start timer*/
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+	reg_data |= SIM_CNTL_GPCNT_CLK_SEL(3);
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+	/*Loop for timeout*/
+	while (!(__raw_readl(sim->ioaddr + XMT_STATUS) & SIM_XMT_STATUS_GPCNT))
+		usleep_range(10, 20);
+	__raw_writel(SIM_XMT_STATUS_GPCNT, sim->ioaddr + XMT_STATUS);
+}
+
+void sim_clear_rx_buf(struct sim_t *sim)
+{
+	unsigned int i;
+	for (i = 0; i < SIM_RCV_BUFFER_SIZE; i++)
+		sim->rcv_buffer[i] = 0;
+	sim->rcv_count = 0;
+	sim->rcv_head = 0;
+}
+
+static long sim_ioctl(struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret, errval = SIM_OK;
+	unsigned long timeout;
+	u32 reg_data;
+	u32 delay;
+	u32 copy_cnt, val;
+	unsigned long flags;
+	unsigned char __user *atr_buffer;
+	unsigned char __user *xmt_buffer;
+	unsigned char __user *rcv_buffer;
+
+	struct sim_t *sim = (struct sim_t *) file->private_data;
+
+	pr_debug("%s entering.\n", __func__);
+	switch (cmd) {
+
+	case SIM_IOCTL_GET_ATR:
+		if (sim->present != SIM_PRESENT_DETECTED) {
+			pr_err("NO card ...\n");
+			errval = -SIM_E_NOCARD;
+			break;
+		};
+		sim->timeout = ATR_TIMEOUT * HZ;
+		val = 0;
+		ret = copy_to_user(&(((sim_atr_t *)arg)->size), &val,
+					sizeof((((sim_atr_t *)arg)->size)));
+
+		timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+									sim->timeout);
+		/*Disalbe the GPCNT timer and CWT timer right now*/
+		reg_data = __raw_readl(sim->ioaddr + CNTL);
+		reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK | SIM_CNTL_CWTEN);
+		__raw_writel(reg_data, sim->ioaddr + CNTL);
+
+		reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+		reg_data |= (SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+		__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+		if (timeout == 0) {
+			pr_err("ATR timeout\n");
+			errval = -SIM_E_TIMEOUT;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_atr_t *)arg)->size), &sim->rcv_count,
+					sizeof(sim->rcv_count));
+		if (ret) {
+			pr_err("ATR ACCESS rcv_count Error, %d\n", ret);
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		__get_user(atr_buffer, &((sim_atr_t __user *)arg)->atr_buffer);
+		ret = copy_to_user(atr_buffer, sim->rcv_buffer, sim->rcv_count);
+		if (ret) {
+			pr_err("ATR ACCESS buffer Error %d %d\n", sim->rcv_count, ret);
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+					sizeof(sim->errval));
+		if (ret) {
+			pr_err("ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+		sim->rcv_count = 0;
+		sim->rcv_head = 0;
+		sim->errval = 0;
+
+		break;
+
+	case SIM_IOCTL_DEACTIVATE:
+
+		sim_deactivate(sim);
+		break;
+
+	case SIM_IOCTL_COLD_RESET:
+		sim->present = SIM_PRESENT_REMOVED;
+		sim->state = SIM_STATE_REMOVED;
+		sim_reset_module(sim);
+		sim_data_reset(sim);
+		sim_start(sim);
+		sim_cold_reset(sim);
+
+		break;
+
+	case SIM_IOCTL_WARM_RESET:
+		sim_warm_reset(sim);
+		break;
+
+	case SIM_IOCTL_XMT:
+		ret = copy_from_user(&sim->xmt_remaining, &(((sim_xmt_t *)arg)->xmt_length),
+				     sizeof(uint32_t));
+		if (ret || sim->xmt_remaining > SIM_XMT_BUFFER_SIZE) {
+			pr_err("copy error or to big buffer\n");
+			errval = -EINVAL;
+			break;
+		}
+
+		__get_user(xmt_buffer, &((sim_xmt_t *)arg)->xmt_buffer);
+		ret = copy_from_user(sim->xmt_buffer, xmt_buffer, sim->xmt_remaining);
+
+		if (ret) {
+			pr_err("Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		sim_clear_rx_buf(sim);
+		sim_set_cwt(sim, 0);
+		sim_set_bwt(sim, 0);
+		/*Flush the tx rx fifo*/
+		sim_flush_fifo(sim, 1, 1);
+		sim->xmt_pos = 0;
+		sim->errval = 0;
+
+		sim_xmt_fill_fifo(sim);
+		sim_set_baud_rate(sim);
+		if (sim->protocol_type == SIM_PROTOCOL_T0)
+			sim_set_nack(sim, 1);
+		else if (sim->protocol_type == SIM_PROTOCOL_T1)
+			sim_set_nack(sim, 0);
+		else {
+			pr_err("Invalid protocol not T0 or T1\n");
+			errval = -EINVAL;
+			break;
+		}
+
+		sim_set_timer_counter(sim);
+		sim_xmt_start(sim);
+		sim->state = SIM_STATE_XMTING;
+
+		sim->timeout = TX_TIMEOUT * HZ;
+		timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+									sim->timeout);
+		if (timeout == 0) {
+			/*Disable the NACK interruptand TX related interrupt*/
+			sim_tx_irq_disable(sim);
+			pr_err("tx timeout\n");
+		}
+
+		if (timeout == 0 || sim->state == SIM_STATE_XMT_ERROR) {
+			pr_err("TX error\n");
+			/*Disable timers*/
+			sim_set_cwt(sim, 0);
+			sim_set_bwt(sim, 0);
+			/*Disable TX*/
+			sim_set_tx(sim, 0);
+			/*Flush the tx fifos*/
+			sim_flush_fifo(sim, 1, 0);
+			if (timeout == 0)
+				errval = -SIM_E_TIMEOUT;
+			else
+				errval = -SIM_E_NACK;
+
+			ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+						sizeof(sim->errval));
+			sim->errval = 0;
+			break;
+		}
+
+		/*Copy the error status to user space*/
+		ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+						sizeof(sim->errval));
+		sim->last_is_tx = true;
+		/*Start RX*/
+		sim->errval = 0;
+		sim->state = SIM_STATE_RECEIVING;
+		sim_start_rcv(sim);
+
+		break;
+
+	case SIM_IOCTL_RCV:
+		if (sim->present != SIM_PRESENT_DETECTED) {
+			errval = -SIM_E_NOCARD;
+			break;
+		}
+		sim->is_fixed_len_rec = 0;
+		val = 0;
+		ret = copy_from_user(&sim->expected_rcv_cnt, &(((sim_rcv_t *)arg)->rcv_length),
+					sizeof(sim->expected_rcv_cnt));
+
+		/*Set the length to be 0 at first*/
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &val,
+					sizeof(val));
+
+		/*Set error value to be 0 at first*/
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &val,
+					sizeof(val));
+
+		if (sim->expected_rcv_cnt != 0)
+			sim->is_fixed_len_rec = 1;
+
+		if (sim->is_fixed_len_rec && sim->rcv_count >= sim->expected_rcv_cnt)
+			goto copy_data;
+
+		if (sim->state != SIM_STATE_RECEIVING) {
+			sim_set_timer_counter(sim);
+			/*Enable CWT BWT*/
+			sim_set_cwt(sim, 1);
+			sim_set_bwt(sim, 1);
+			sim->state = SIM_STATE_RECEIVING;
+			sim_start_rcv(sim);
+		}
+
+		spin_lock_irqsave(&sim->lock, flags);
+		if (sim->is_fixed_len_rec && sim->rcv_count < sim->expected_rcv_cnt)
+			sim_change_rcv_threshold(sim);
+		spin_unlock_irqrestore(&sim->lock, flags);
+		sim->timeout = RX_TIMEOUT * HZ;
+		timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+									sim->timeout);
+
+		if (timeout == 0) {
+			pr_err("Receiving timeout\n");
+			sim_set_cwt(sim, 0);
+			sim_set_bwt(sim, 0);
+			sim_rx_irq_disable(sim);
+			errval = -SIM_E_TIMEOUT;
+			break;
+		}
+
+copy_data:
+		if (sim->is_fixed_len_rec)
+			copy_cnt = sim->rcv_count >= sim->expected_rcv_cnt ? sim->expected_rcv_cnt : sim->rcv_count;
+		else
+			copy_cnt = sim->rcv_count;
+
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &copy_cnt,
+					sizeof(copy_cnt));
+		if (ret) {
+			pr_err("ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		__get_user(rcv_buffer, &((sim_rcv_t *)arg)->rcv_buffer);
+		ret = copy_to_user(rcv_buffer, &sim->rcv_buffer[sim->rcv_head], copy_cnt);
+		if (ret) {
+			pr_err("ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+
+		ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &sim->errval,
+						sizeof(sim->errval));
+		if (ret) {
+			pr_err("ATR ACCESS Error\n");
+			errval = -SIM_E_ACCESS;
+			break;
+		}
+		/*Reset the receiving count and errval*/
+		spin_lock_irqsave(&sim->lock, flags);
+		sim->rcv_head += copy_cnt;
+		sim->rcv_count -= copy_cnt;
+		sim->errval = 0;
+		spin_unlock_irqrestore(&sim->lock, flags);
+
+		sim->last_is_tx = false;
+
+		break;
+
+	case SIM_IOCTL_SET_PROTOCOL:
+		ret = copy_from_user(&sim->protocol_type, (int *)arg,
+				     sizeof(int));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_SET_TIMING:
+		ret = copy_from_user(&sim->timing_data, (sim_timing_t *)arg,
+				     sizeof(sim_timing_t));
+		if (ret) {
+			pr_err("Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		ret = sim_check_timing_data(&sim->timing_data);
+
+		if (ret)
+			errval = ret;
+
+		break;
+
+	case SIM_IOCTL_SET_BAUD:
+		ret = copy_from_user(&sim->baud_rate, (sim_baud_t *)arg,
+					sizeof(sim_baud_t));
+
+		if (ret) {
+			pr_err("Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		ret = sim_check_baud_rate(&sim->baud_rate);
+		if (ret) {
+			pr_err("Invalid baud rate value\n");
+			errval = ret;
+		}
+
+		break;
+	case SIM_IOCTL_WAIT:
+		ret = copy_from_user(&delay, (unsigned int *)arg,
+					sizeof(unsigned int));
+
+		if (ret) {
+			pr_err("\nWait Copy Error\n");
+			errval = ret;
+			break;
+		}
+
+		sim_polling_delay(sim, delay);
+		break;
+
+	case SIM_IOCTL_GET_PRESENSE:
+		if (put_user(sim->present, (int *)arg))
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_CARD_LOCK:
+		errval = sim_card_lock(sim);
+		break;
+
+	case SIM_IOCTL_CARD_EJECT:
+		errval = sim_card_eject(sim);
+		break;
+
+	};
+
+	return errval;
+};
+
+static int sim_open(struct inode *inode, struct file *file)
+{
+	int errval;
+	struct sim_t *sim = dev_get_drvdata(sim_dev.parent);
+
+	file->private_data = sim;
+	spin_lock_init(&sim->lock);
+
+	pr_debug("%s entering.\n", __func__);
+	if (!sim->ioaddr) {
+		errval = -ENOMEM;
+		return errval;
+	}
+
+	sim->open_cnt = 1;
+	errval = pm_runtime_get_sync(sim_dev.parent);
+	if (errval < 0)
+		return errval;
+
+	errval = sim_reset_module(sim);
+	if (errval < 0)
+		goto out_runtime_put;
+
+	sim_data_reset(sim);
+
+	return 0;
+
+out_runtime_put:
+	pm_runtime_put(sim_dev.parent);
+	return errval;
+};
+
+static int sim_release(struct inode *inode, struct file *file)
+{
+	u32 reg_data;
+	struct sim_t *sim = (struct sim_t *) file->private_data;
+
+	/* disable presense detection */
+	reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+	__raw_writel(reg_data | SIM_PORT_DETECT_SDIM,
+		     sim->ioaddr + sim->port_detect_reg);
+
+	if (sim->present != SIM_PRESENT_REMOVED)
+		sim_deactivate(sim);
+
+	pm_runtime_put(sim_dev.parent);
+	sim->open_cnt = 0;
+
+	return 0;
+};
+
+static const struct file_operations sim_fops = {
+	.owner = THIS_MODULE,
+	.open = sim_open,
+	.release = sim_release,
+	.unlocked_ioctl = sim_ioctl,
+};
+
+static struct miscdevice sim_dev = {
+	MISC_DYNAMIC_MINOR,
+	"mxc_sim",
+	&sim_fops
+};
+
+static struct platform_device_id imx_sim_devtype[] = {
+	{
+		.name = "imx7d-sim",
+		.driver_data = 0,
+	}, {
+		.name = "imx6ul-sim",
+		.driver_data = SIM_QUIRK_TKT259347,
+	}, {
+		/* sentinel */
+	}
+};
+
+enum imx_sim_type {
+	IMX7D_SIM = 0,
+	IMX6UL_SIM,
+};
+
+static const struct of_device_id sim_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx7d-sim",
+		.data = &imx_sim_devtype[IMX7D_SIM], },
+	{ .compatible = "fsl,imx6ul-sim",
+		.data = &imx_sim_devtype[IMX6UL_SIM], },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sim_imx_dt_ids);
+
+static int sim_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	const struct of_device_id *of_id;
+	struct sim_t *sim = NULL;
+	struct device_node *of_node = pdev->dev.of_node;
+
+	sim = devm_kzalloc(&pdev->dev, sizeof(struct sim_t),
+				GFP_KERNEL);
+	if (!sim) {
+		dev_err(&pdev->dev, "can't allocate enough memory\n");
+		return -ENOMEM;
+	}
+
+	of_id = of_match_device(sim_imx_dt_ids, &pdev->dev);
+	if (of_id)
+		pdev->id_entry = of_id->data;
+	else
+		return -EINVAL;
+
+	sim->clk_rate = FCLK_FREQ;
+
+	sim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!sim->res) {
+		pr_err("Can't get the MEMORY\n");
+		return -ENOMEM;
+	}
+	sim->ioaddr = devm_ioremap_resource(&pdev->dev, sim->res);
+	dev_dbg(&pdev->dev, "mapped base address: 0x%08x\n", (u32)sim->ioaddr);
+	if (IS_ERR(sim->ioaddr)) {
+		dev_err(&pdev->dev,
+			"failed to get ioremap base\n");
+		ret = PTR_ERR(sim->ioaddr);
+		return ret;
+	}
+
+	/* request the sim clk and sim_serial_clk */
+	sim->clk = devm_clk_get(&pdev->dev, "sim");
+	if (IS_ERR(sim->clk)) {
+		ret = PTR_ERR(sim->clk);
+		pr_err("Get CLK ERROR !\n");
+		return ret;
+	}
+	pr_debug("sim clock:%lu\n", clk_get_rate(sim->clk));
+
+	sim->ipb_irq = platform_get_irq(pdev, 0);
+	if (sim->ipb_irq < 0) {
+		dev_err(&pdev->dev, "No ipb irq line provided\n");
+		return -ENOENT;
+	}
+	if (devm_request_irq(&pdev->dev, sim->ipb_irq, sim_irq_handler,
+				0, "mxc_sim_ipb", sim)) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", sim->ipb_irq);
+		return -ENOENT;
+	}
+
+	sim->sven_low_active = of_property_read_bool(of_node,
+						"sven_low_active");
+
+	ret = of_property_read_u32(of_node, "port", &sim->port_index);
+	if (ret)
+		sim->port_index = 0;
+	sim->port_ctrl_reg = (sim->port_index == 0) ?
+				PORT0_CNTL : PORT1_CNTL;
+	sim->port_detect_reg = (sim->port_index == 0) ?
+				PORT0_DETECT : PORT1_DETECT;
+	sim->quirks = pdev->id_entry->driver_data;
+
+	platform_set_drvdata(pdev, sim);
+
+	/*
+	 *@todo: Need to figure a better way if possible.
+	 */
+	sim_dev.parent = &(pdev->dev);
+
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	sim->open_cnt = 1;
+	ret = clk_prepare_enable(sim->clk);
+	if (ret)
+		return ret;
+	/* Let pm_runtime_put() disable the clock.
+	 * If CONFIG_PM is not enabled, the clock will stay powered.
+	 */
+	pm_runtime_put(&pdev->dev);
+	sim->open_cnt = 0;
+
+	misc_register(&sim_dev);
+
+	return 0;
+}
+
+static int sim_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	misc_deregister(&sim_dev);
+
+	return 0;
+}
+
+static int __maybe_unused sim_suspend(struct device *dev)
+{
+	int err;
+
+	err = pm_runtime_force_suspend(dev);
+	if (err)
+		return err;
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int __maybe_unused sim_resume(struct device *dev)
+{
+	int err;
+
+	err = pm_runtime_force_resume(dev);
+	if (err)
+		return err;
+
+	pinctrl_pm_select_default_state(dev);
+
+	return 0;
+}
+
+static int __maybe_unused sim_runtime_suspend(struct device *dev)
+{
+	struct sim_t *sim = dev_get_drvdata(dev);
+
+	if (sim->open_cnt)
+		clk_disable_unprepare(sim->clk);
+
+	return 0;
+}
+
+static int __maybe_unused sim_runtime_resume(struct device *dev)
+{
+	int err;
+	struct sim_t *sim = dev_get_drvdata(dev);
+
+	if (sim->open_cnt) {
+		err = clk_prepare_enable(sim->clk);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops sim_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sim_suspend, sim_resume)
+	SET_RUNTIME_PM_OPS(sim_runtime_suspend, sim_runtime_resume, NULL)
+};
+
+static struct platform_driver sim_driver = {
+	.driver = {
+			.name = DRIVER_NAME,
+			.owner = THIS_MODULE,
+			.pm = &sim_pm_ops,
+			.of_match_table = sim_imx_dt_ids,
+			},
+	.probe = sim_probe,
+	.remove = sim_remove,
+	.id_table = imx_sim_devtype,
+};
+
+static int __init sim_drv_init(void)
+{
+	return platform_driver_register(&sim_driver);
+}
+
+static void __exit sim_drv_exit(void)
+{
+	platform_driver_unregister(&sim_driver);
+}
+
+module_init(sim_drv_init);
+module_exit(sim_drv_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC SIM Driver");
+MODULE_LICENSE("GPL");
+
--- linux-ein-5.4.0.orig/drivers/mxc/vpu/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/vpu/Kconfig
@@ -0,0 +1,31 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) support"
+
+config MXC_VPU
+	  tristate "Support for MXC VPU(Video Processing Unit)"
+	  depends on (SOC_IMX27 || SOC_IMX5 || SOC_IMX6Q)
+	  default y
+	---help---
+	  The VPU codec device provides codec function for H.264/MPEG4/H.263,
+	  as well as MPEG2/VC-1/DivX on some platforms.
+
+config MXC_VPU_DEBUG
+	bool "MXC VPU debugging"
+	depends on MXC_VPU != n
+	help
+	  This is an option for the developers; most people should
+	  say N here.  This enables MXC VPU driver debugging.
+
+config MX6_VPU_352M
+	bool "MX6 VPU 352M"
+	depends on MXC_VPU
+	default n
+	help
+	 Increase VPU frequncy to 352M, the config will disable bus frequency
+	 adjust dynamic, and CPU lowest setpoint will be 352Mhz.
+	 This config is used for special VPU use case.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/vpu/Makefile
+++ linux-ein-5.4.0/drivers/mxc/vpu/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the VPU drivers.
+#
+
+obj-$(CONFIG_MXC_VPU)                  += mxc_vpu.o
+
+ifeq ($(CONFIG_MXC_VPU_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu/mxc_vpu.c
+++ linux-ein-5.4.0/drivers/mxc/vpu/mxc_vpu.c
@@ -0,0 +1,1349 @@
+/*
+ * Copyright 2006-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_vpu.c
+ *
+ * @brief VPU system initialization and file operation implementation
+ *
+ * @ingroup VPU
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sched/signal.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/page-flags.h>
+#include <linux/mm_types.h>
+#include <linux/types.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/version.h>
+#include <asm/page.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+#include <linux/iram_alloc.h>
+#include <mach/clock.h>
+#include <mach/hardware.h>
+#include <mach/mxc_vpu.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/mxc_vpu.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+#include <mach/busfreq.h>
+#include <mach/common.h>
+#else
+#include <asm/sizes.h>
+#endif
+
+/* Define one new pgprot which combined uncached and XN(never executable) */
+#define pgprot_noncachedxn(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
+
+struct vpu_priv {
+	struct fasync_struct *async_queue;
+	struct work_struct work;
+	struct workqueue_struct *workqueue;
+	struct mutex lock;
+};
+
+/* To track the allocated memory buffer */
+struct memalloc_record {
+	struct list_head list;
+	struct vpu_mem_desc mem;
+};
+
+struct iram_setting {
+	u32 start;
+	u32 end;
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static struct gen_pool *iram_pool;
+static u32 iram_base;
+#endif
+
+static LIST_HEAD(head);
+
+static int vpu_major;
+static int vpu_clk_usercount;
+static struct class *vpu_class;
+static struct vpu_priv vpu_data;
+static u8 open_count;
+static struct clk *vpu_clk;
+static struct vpu_mem_desc bitwork_mem = { 0 };
+static struct vpu_mem_desc pic_para_mem = { 0 };
+static struct vpu_mem_desc user_data_mem = { 0 };
+static struct vpu_mem_desc share_mem = { 0 };
+static struct vpu_mem_desc vshare_mem = { 0 };
+
+static void __iomem *vpu_base;
+static int vpu_ipi_irq;
+static u32 phy_vpu_base_addr;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+static phys_addr_t top_address_DRAM;
+static struct mxc_vpu_platform_data *vpu_plat;
+#endif
+
+static struct device *vpu_dev;
+
+/* IRAM setting */
+static struct iram_setting iram;
+
+/* implement the blocking ioctl */
+static int irq_status;
+static int codec_done;
+static wait_queue_head_t vpu_queue;
+
+#ifdef CONFIG_SOC_IMX6Q
+#define MXC_VPU_HAS_JPU
+#endif
+
+#ifdef MXC_VPU_HAS_JPU
+static int vpu_jpu_irq;
+#endif
+
+#ifdef CONFIG_PM
+static unsigned int regBk[64];
+static unsigned int pc_before_suspend;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static struct regulator *vpu_regulator;
+#endif
+#endif
+static atomic_t clk_cnt_from_ioc = ATOMIC_INIT(0);
+
+#define	READ_REG(x)		readl_relaxed(vpu_base + x)
+#define	WRITE_REG(val, x)	writel_relaxed(val, vpu_base + x)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+/* redirect to static functions */
+static int cpu_is_mx6dl(void)
+{
+	int ret;
+	ret = of_machine_is_compatible("fsl,imx6dl");
+	return ret;
+}
+
+static int cpu_is_mx6q(void)
+{
+	int ret;
+	ret = of_machine_is_compatible("fsl,imx6q");
+	return ret;
+}
+#endif
+
+static void vpu_reset(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+	int ret;
+
+	ret = device_reset(vpu_dev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	imx_src_reset_vpu();
+#else
+	if (vpu_plat->reset)
+		vpu_plat->reset();
+#endif
+}
+
+static long vpu_power_get(bool on)
+{
+	long ret = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+	if (on) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+		vpu_regulator = regulator_get(NULL, "cpu_vddvpu");
+		ret = IS_ERR(vpu_regulator);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+		vpu_regulator = devm_regulator_get(vpu_dev, "pu");
+		ret = IS_ERR(vpu_regulator);
+#endif
+	} else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+		if (!IS_ERR(vpu_regulator))
+			regulator_put(vpu_regulator);
+#endif
+	}
+#endif
+	return ret;
+}
+
+static void vpu_power_up(bool on)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	if (on)
+		pm_runtime_get_sync(vpu_dev);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+	if (on) {
+		if (!IS_ERR(vpu_regulator)) {
+			if (regulator_enable(vpu_regulator))
+				dev_err(vpu_dev, "failed to power up vpu\n");
+		}
+	} else {
+		if (!IS_ERR(vpu_regulator)) {
+			if (regulator_disable(vpu_regulator))
+				dev_err(vpu_dev, "failed to power down vpu\n");
+		}
+	}
+#else
+	imx_gpc_power_up_pu(on);
+#endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	if (!on)
+		pm_runtime_put_sync_suspend(vpu_dev);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static int cpu_is_mx53(void)
+{
+	return 0;
+}
+
+static int cpu_is_mx51(void)
+{
+	return 0;
+}
+
+#define VM_RESERVED 0
+#endif
+
+/*!
+ * Private function to alloc dma buffer
+ * @return status  0 success.
+ */
+static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
+{
+	mem->cpu_addr = (unsigned long)
+	    dma_alloc_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+			       (dma_addr_t *) (&mem->phy_addr),
+			       GFP_DMA | GFP_KERNEL);
+	dev_dbg(vpu_dev, "[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr);
+	if ((void *)(mem->cpu_addr) == NULL) {
+		dev_err(vpu_dev, "Physical memory allocation error!\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*!
+ * Private function to free dma buffer
+ */
+static void vpu_free_dma_buffer(struct vpu_mem_desc *mem)
+{
+	if (mem->cpu_addr != 0) {
+		dma_free_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+				  (void *)mem->cpu_addr, mem->phy_addr);
+	}
+}
+
+/*!
+ * Private function to free buffers
+ * @return status  0 success.
+ */
+static int vpu_free_buffers(void)
+{
+	struct memalloc_record *rec, *n;
+	struct vpu_mem_desc mem;
+
+	list_for_each_entry_safe(rec, n, &head, list) {
+		mem = rec->mem;
+		if (mem.cpu_addr != 0) {
+			vpu_free_dma_buffer(&mem);
+			dev_dbg(vpu_dev, "[FREE] freed paddr=0x%08X\n", mem.phy_addr);
+			/* delete from list */
+			list_del(&rec->list);
+			kfree(rec);
+		}
+	}
+
+	return 0;
+}
+
+static inline void vpu_worker_callback(struct work_struct *w)
+{
+	struct vpu_priv *dev = container_of(w, struct vpu_priv,
+				work);
+
+	if (dev->async_queue)
+		kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+
+	irq_status = 1;
+	/*
+	 * Clock is gated on when dec/enc started, gate it off when
+	 * codec is done.
+	 */
+	if (codec_done)
+		codec_done = 0;
+
+	wake_up_interruptible(&vpu_queue);
+}
+
+/*!
+ * @brief vpu interrupt handler
+ */
+static irqreturn_t vpu_ipi_irq_handler(int irq, void *dev_id)
+{
+	struct vpu_priv *dev = dev_id;
+	unsigned long reg;
+
+	reg = READ_REG(BIT_INT_REASON);
+	if (reg & 0x8)
+		codec_done = 1;
+	WRITE_REG(0x1, BIT_INT_CLEAR);
+
+	queue_work(dev->workqueue, &dev->work);
+
+	return IRQ_HANDLED;
+}
+
+/*!
+ * @brief vpu jpu interrupt handler
+ */
+#ifdef MXC_VPU_HAS_JPU
+static irqreturn_t vpu_jpu_irq_handler(int irq, void *dev_id)
+{
+	struct vpu_priv *dev = dev_id;
+	unsigned long reg;
+
+	reg = READ_REG(MJPEG_PIC_STATUS_REG);
+	if (reg & 0x3)
+		codec_done = 1;
+
+	queue_work(dev->workqueue, &dev->work);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * @brief check phy memory prepare to pass to vpu is valid or not, we
+ * already address some issue that if pass a wrong address to vpu
+ * (like virtual address), system will hang.
+ *
+ * @return true return is a valid phy memory address, false return not.
+ */
+bool vpu_is_valid_phy_memory(u32 paddr)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+	if (paddr > top_address_DRAM)
+		return false;
+#endif
+
+	return true;
+}
+
+/*!
+ * @brief open function for vpu file operation
+ *
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_open(struct inode *inode, struct file *filp)
+{
+
+	mutex_lock(&vpu_data.lock);
+
+	if (open_count++ == 0) {
+		vpu_power_up(true);
+
+#ifdef CONFIG_SOC_IMX6Q
+		clk_prepare(vpu_clk);
+		clk_enable(vpu_clk);
+		if (READ_REG(BIT_CUR_PC))
+			dev_dbg(vpu_dev, "Not power off before vpu open!\n");
+		clk_disable(vpu_clk);
+		clk_unprepare(vpu_clk);
+#endif
+	}
+
+	filp->private_data = (void *)(&vpu_data);
+	mutex_unlock(&vpu_data.lock);
+	return 0;
+}
+
+/*!
+ * @brief IO ctrl function for vpu file operation
+ * @param cmd IO ctrl command
+ * @return  0 on success or negative error code on error
+ */
+static long vpu_ioctl(struct file *filp, u_int cmd,
+		     u_long arg)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case VPU_IOC_PHYMEM_ALLOC:
+		{
+			struct memalloc_record *rec;
+
+			rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+			if (!rec)
+				return -ENOMEM;
+
+			ret = copy_from_user(&(rec->mem),
+					     (struct vpu_mem_desc *)arg,
+					     sizeof(struct vpu_mem_desc));
+			if (ret) {
+				kfree(rec);
+				return -EFAULT;
+			}
+
+			dev_dbg(vpu_dev, "[ALLOC] mem alloc size = 0x%x\n",
+				 rec->mem.size);
+
+			ret = vpu_alloc_dma_buffer(&(rec->mem));
+			if (ret == -1) {
+				kfree(rec);
+				dev_err(vpu_dev,
+					"Physical memory allocation error!\n");
+				break;
+			}
+			ret = copy_to_user((void __user *)arg, &(rec->mem),
+					   sizeof(struct vpu_mem_desc));
+			if (ret) {
+				kfree(rec);
+				ret = -EFAULT;
+				break;
+			}
+
+			mutex_lock(&vpu_data.lock);
+			list_add(&rec->list, &head);
+			mutex_unlock(&vpu_data.lock);
+
+			break;
+		}
+	case VPU_IOC_PHYMEM_FREE:
+		{
+			struct memalloc_record *rec, *n;
+			struct vpu_mem_desc vpu_mem;
+
+			ret = copy_from_user(&vpu_mem,
+					     (struct vpu_mem_desc *)arg,
+					     sizeof(struct vpu_mem_desc));
+			if (ret)
+				return -EACCES;
+
+			dev_dbg(vpu_dev, "[FREE] mem freed cpu_addr = 0x%x\n",
+				 vpu_mem.cpu_addr);
+			if ((void *)vpu_mem.cpu_addr != NULL)
+				vpu_free_dma_buffer(&vpu_mem);
+
+			mutex_lock(&vpu_data.lock);
+			list_for_each_entry_safe(rec, n, &head, list) {
+				if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
+					/* delete from list */
+					list_del(&rec->list);
+					kfree(rec);
+					break;
+				}
+			}
+			mutex_unlock(&vpu_data.lock);
+
+			break;
+		}
+	case VPU_IOC_WAIT4INT:
+		{
+			u_long timeout = (u_long) arg;
+			if (!wait_event_interruptible_timeout
+			    (vpu_queue, irq_status != 0,
+			     msecs_to_jiffies(timeout))) {
+				dev_warn(vpu_dev, "VPU blocking: timeout.\n");
+				ret = -ETIME;
+			} else if (signal_pending(current)) {
+				dev_warn(vpu_dev, "VPU interrupt received.\n");
+				ret = -ERESTARTSYS;
+			} else
+				irq_status = 0;
+			break;
+		}
+	case VPU_IOC_IRAM_SETTING:
+		{
+			ret = copy_to_user((void __user *)arg, &iram,
+					   sizeof(struct iram_setting));
+			if (ret)
+				ret = -EFAULT;
+
+			break;
+		}
+	case VPU_IOC_CLKGATE_SETTING:
+		{
+			u32 clkgate_en;
+
+			if (get_user(clkgate_en, (u32 __user *) arg))
+				return -EFAULT;
+
+			if (clkgate_en) {
+				clk_prepare(vpu_clk);
+				clk_enable(vpu_clk);
+				atomic_inc(&clk_cnt_from_ioc);
+			} else {
+				clk_disable(vpu_clk);
+				clk_unprepare(vpu_clk);
+				atomic_dec(&clk_cnt_from_ioc);
+			}
+
+			break;
+		}
+	case VPU_IOC_GET_SHARE_MEM:
+		{
+			mutex_lock(&vpu_data.lock);
+			if (share_mem.cpu_addr != 0) {
+				ret = copy_to_user((void __user *)arg,
+						   &share_mem,
+						   sizeof(struct vpu_mem_desc));
+				mutex_unlock(&vpu_data.lock);
+				break;
+			} else {
+				if (copy_from_user(&share_mem,
+						   (struct vpu_mem_desc *)arg,
+						 sizeof(struct vpu_mem_desc))) {
+					mutex_unlock(&vpu_data.lock);
+					return -EFAULT;
+				}
+				if (vpu_alloc_dma_buffer(&share_mem) == -1)
+					ret = -EFAULT;
+				else {
+					if (copy_to_user((void __user *)arg,
+							 &share_mem,
+							 sizeof(struct
+								vpu_mem_desc)))
+						ret = -EFAULT;
+				}
+			}
+			mutex_unlock(&vpu_data.lock);
+			break;
+		}
+	case VPU_IOC_REQ_VSHARE_MEM:
+		{
+			mutex_lock(&vpu_data.lock);
+			if (vshare_mem.cpu_addr != 0) {
+				ret = copy_to_user((void __user *)arg,
+						   &vshare_mem,
+						   sizeof(struct vpu_mem_desc));
+				mutex_unlock(&vpu_data.lock);
+				break;
+			} else {
+				if (copy_from_user(&vshare_mem,
+						   (struct vpu_mem_desc *)arg,
+						   sizeof(struct
+							  vpu_mem_desc))) {
+					mutex_unlock(&vpu_data.lock);
+					return -EFAULT;
+				}
+				/* vmalloc shared memory if not allocated */
+				if (!vshare_mem.cpu_addr)
+					vshare_mem.cpu_addr =
+					    (unsigned long)
+					    vmalloc_user(vshare_mem.size);
+				if (copy_to_user
+				     ((void __user *)arg, &vshare_mem,
+				     sizeof(struct vpu_mem_desc)))
+					ret = -EFAULT;
+			}
+			mutex_unlock(&vpu_data.lock);
+			break;
+		}
+	case VPU_IOC_GET_WORK_ADDR:
+		{
+			if (bitwork_mem.cpu_addr != 0) {
+				ret =
+				    copy_to_user((void __user *)arg,
+						 &bitwork_mem,
+						 sizeof(struct vpu_mem_desc));
+				break;
+			} else {
+				if (copy_from_user(&bitwork_mem,
+						   (struct vpu_mem_desc *)arg,
+						   sizeof(struct vpu_mem_desc)))
+					return -EFAULT;
+
+				if (vpu_alloc_dma_buffer(&bitwork_mem) == -1)
+					ret = -EFAULT;
+				else if (copy_to_user((void __user *)arg,
+						      &bitwork_mem,
+						      sizeof(struct
+							     vpu_mem_desc)))
+					ret = -EFAULT;
+			}
+			break;
+		}
+	/*
+	 * The following two ioctl is used when user allocates working buffer
+	 * and register it to vpu driver.
+	 */
+	case VPU_IOC_QUERY_BITWORK_MEM:
+		{
+			if (copy_to_user((void __user *)arg,
+					 &bitwork_mem,
+					 sizeof(struct vpu_mem_desc)))
+				ret = -EFAULT;
+			break;
+		}
+	case VPU_IOC_SET_BITWORK_MEM:
+		{
+			if (copy_from_user(&bitwork_mem,
+					   (struct vpu_mem_desc *)arg,
+					   sizeof(struct vpu_mem_desc)))
+				ret = -EFAULT;
+			break;
+		}
+	case VPU_IOC_SYS_SW_RESET:
+		{
+			vpu_reset();
+			break;
+		}
+	case VPU_IOC_REG_DUMP:
+		break;
+	case VPU_IOC_PHYMEM_DUMP:
+		break;
+	case VPU_IOC_PHYMEM_CHECK:
+	{
+		struct vpu_mem_desc check_memory;
+		ret = copy_from_user(&check_memory,
+				     (void __user *)arg,
+				     sizeof(struct vpu_mem_desc));
+		if (ret != 0) {
+			dev_err(vpu_dev, "copy from user failure:%d\n", ret);
+			ret = -EFAULT;
+			break;
+		}
+		ret = vpu_is_valid_phy_memory((u32)check_memory.phy_addr);
+
+		dev_dbg(vpu_dev, "vpu: memory phy:0x%x %s phy memory\n",
+		       check_memory.phy_addr, (ret ? "is" : "isn't"));
+		/* borrow .size to pass back the result. */
+		check_memory.size = ret;
+		ret = copy_to_user((void __user *)arg, &check_memory,
+				   sizeof(struct vpu_mem_desc));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case VPU_IOC_LOCK_DEV:
+		{
+			u32 lock_en;
+
+			if (get_user(lock_en, (u32 __user *) arg))
+				return -EFAULT;
+
+			if (lock_en)
+				mutex_lock(&vpu_data.lock);
+			else
+				mutex_unlock(&vpu_data.lock);
+
+			break;
+		}
+	default:
+		{
+			dev_err(vpu_dev, "No such IOCTL, cmd is %d\n", cmd);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+
+/*!
+ * @brief Release function for vpu file operation
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_release(struct inode *inode, struct file *filp)
+{
+	int i;
+	unsigned long timeout;
+
+	mutex_lock(&vpu_data.lock);
+
+	if (open_count > 0 && !(--open_count)) {
+
+		/* Wait for vpu go to idle state */
+		clk_prepare(vpu_clk);
+		clk_enable(vpu_clk);
+		if (READ_REG(BIT_CUR_PC)) {
+
+			timeout = jiffies + HZ;
+			while (READ_REG(BIT_BUSY_FLAG)) {
+				msleep(1);
+				if (time_after(jiffies, timeout)) {
+					dev_warn(vpu_dev, "VPU timeout during release\n");
+					break;
+				}
+			}
+			clk_disable(vpu_clk);
+			clk_unprepare(vpu_clk);
+
+			/* Clean up interrupt */
+			cancel_work_sync(&vpu_data.work);
+			flush_workqueue(vpu_data.workqueue);
+			irq_status = 0;
+
+			clk_prepare(vpu_clk);
+			clk_enable(vpu_clk);
+			if (READ_REG(BIT_BUSY_FLAG)) {
+
+				if (cpu_is_mx51() || cpu_is_mx53()) {
+					dev_err(vpu_dev,
+						"fatal error: can't gate/power off when VPU is busy\n");
+					clk_disable(vpu_clk);
+					clk_unprepare(vpu_clk);
+					mutex_unlock(&vpu_data.lock);
+					return -EFAULT;
+				}
+
+#ifdef CONFIG_SOC_IMX6Q
+				if (cpu_is_mx6dl() || cpu_is_mx6q()) {
+					WRITE_REG(0x11, 0x10F0);
+					timeout = jiffies + HZ;
+					while (READ_REG(0x10F4) != 0x77) {
+						msleep(1);
+						if (time_after(jiffies, timeout))
+							break;
+					}
+
+					if (READ_REG(0x10F4) != 0x77) {
+						dev_err(vpu_dev,
+							"fatal error: can't gate/power off when VPU is busy\n");
+						WRITE_REG(0x0, 0x10F0);
+						clk_disable(vpu_clk);
+						clk_unprepare(vpu_clk);
+						mutex_unlock(&vpu_data.lock);
+						return -EFAULT;
+					} else
+						vpu_reset();
+				}
+#endif
+			}
+		}
+		clk_disable(vpu_clk);
+		clk_unprepare(vpu_clk);
+
+		vpu_free_buffers();
+
+		/* Free shared memory when vpu device is idle */
+		vpu_free_dma_buffer(&share_mem);
+		share_mem.cpu_addr = 0;
+		vfree((void *)vshare_mem.cpu_addr);
+		vshare_mem.cpu_addr = 0;
+
+		vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+		for (i = 0; i < vpu_clk_usercount; i++) {
+			clk_disable(vpu_clk);
+			clk_unprepare(vpu_clk);
+			atomic_dec(&clk_cnt_from_ioc);
+		}
+
+		vpu_power_up(false);
+	}
+	mutex_unlock(&vpu_data.lock);
+
+	return 0;
+}
+
+/*!
+ * @brief fasync function for vpu file operation
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_fasync(int fd, struct file *filp, int mode)
+{
+	struct vpu_priv *dev = (struct vpu_priv *)filp->private_data;
+	return fasync_helper(fd, filp, mode, &dev->async_queue);
+}
+
+/*!
+ * @brief memory map function of harware registers for vpu file operation
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_map_hwregs(struct file *fp, struct vm_area_struct *vm)
+{
+	unsigned long pfn;
+
+	vm->vm_flags |= VM_IO | VM_RESERVED;
+	/*
+	 * Since vpu registers have been mapped with ioremap() at probe
+	 * which L_PTE_XN is 1, and the same physical address must be
+	 * mapped multiple times with same type, so set L_PTE_XN to 1 here.
+	 * Otherwise, there may be unexpected result in video codec.
+	 */
+	vm->vm_page_prot = pgprot_noncachedxn(vm->vm_page_prot);
+	pfn = phy_vpu_base_addr >> PAGE_SHIFT;
+	dev_dbg(vpu_dev, "size=0x%x, page no.=0x%x\n",
+		 (int)(vm->vm_end - vm->vm_start), (int)pfn);
+	return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
+			       vm->vm_page_prot) ? -EAGAIN : 0;
+}
+
+/*!
+ * @brief memory map function of memory for vpu file operation
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_map_dma_mem(struct file *fp, struct vm_area_struct *vm)
+{
+	int request_size;
+	request_size = vm->vm_end - vm->vm_start;
+
+	dev_dbg(vpu_dev, "start=0x%x, pgoff=0x%x, size=0x%x\n",
+		 (unsigned int)(vm->vm_start), (unsigned int)(vm->vm_pgoff),
+		 request_size);
+
+	vm->vm_flags |= VM_IO | VM_RESERVED;
+	vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);
+
+	return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
+			       request_size, vm->vm_page_prot) ? -EAGAIN : 0;
+
+}
+
+/* !
+ * @brief memory map function of vmalloced share memory
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_map_vshare_mem(struct file *fp, struct vm_area_struct *vm)
+{
+	int ret = -EINVAL;
+
+	ret = remap_vmalloc_range(vm, (void *)(vm->vm_pgoff << PAGE_SHIFT), 0);
+	vm->vm_flags |= VM_IO;
+
+	return ret;
+}
+/*!
+ * @brief memory map interface for vpu file operation
+ * @return  0 on success or negative error code on error
+ */
+static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+	unsigned long offset;
+
+	offset = vshare_mem.cpu_addr >> PAGE_SHIFT;
+
+	if (vm->vm_pgoff && (vm->vm_pgoff == offset))
+		return vpu_map_vshare_mem(fp, vm);
+	else if (vm->vm_pgoff)
+		return vpu_map_dma_mem(fp, vm);
+	else
+		return vpu_map_hwregs(fp, vm);
+}
+
+const struct file_operations vpu_fops = {
+	.owner = THIS_MODULE,
+	.open = vpu_open,
+	.unlocked_ioctl = vpu_ioctl,
+	.release = vpu_release,
+	.fasync = vpu_fasync,
+	.mmap = vpu_mmap,
+};
+
+/*!
+ * This function is called by the driver framework to initialize the vpu device.
+ * @param   dev The device structure for the vpu passed in by the framework.
+ * @return   0 on success or negative error code on error
+ */
+static int vpu_dev_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct device *temp_class;
+	struct resource *res;
+	unsigned long addr = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	struct device_node *np = pdev->dev.of_node;
+	u32 iramsize;
+
+	err = of_property_read_u32(np, "iramsize", (u32 *)&iramsize);
+	if (!err && iramsize)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+	{
+		iram_pool = of_gen_pool_get(np, "iram", 0);
+		if (!iram_pool) {
+			dev_err(&pdev->dev, "iram pool not available\n");
+			return -ENOMEM;
+		}
+
+		iram_base = gen_pool_alloc(iram_pool, iramsize);
+		if (!iram_base) {
+			dev_err(&pdev->dev, "unable to alloc iram\n");
+			return -ENOMEM;
+		}
+
+		addr = gen_pool_virt_to_phys(iram_pool, iram_base);
+	}
+#else
+		iram_alloc(iramsize, &addr);
+#endif
+	if (addr == 0)
+		iram.start = iram.end = 0;
+	else {
+		iram.start = addr;
+		iram.end = addr + iramsize - 1;
+	}
+#else
+
+	vpu_plat = pdev->dev.platform_data;
+
+	if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
+		iram_alloc(vpu_plat->iram_size, &addr);
+	if (addr == 0)
+		iram.start = iram.end = 0;
+	else {
+		iram.start = addr;
+		iram.end = addr +  vpu_plat->iram_size - 1;
+	}
+#endif
+
+	vpu_dev = &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu_regs");
+	if (!res) {
+		dev_err(vpu_dev, "vpu: unable to get vpu base addr\n");
+		return -ENODEV;
+	}
+	phy_vpu_base_addr = res->start;
+	vpu_base = ioremap(res->start, res->end - res->start);
+
+	vpu_major = register_chrdev(vpu_major, "mxc_vpu", &vpu_fops);
+	if (vpu_major < 0) {
+		dev_err(vpu_dev, "vpu: unable to get a major for VPU\n");
+		err = -EBUSY;
+		goto error;
+	}
+
+	vpu_class = class_create(THIS_MODULE, "mxc_vpu");
+	if (IS_ERR(vpu_class)) {
+		err = PTR_ERR(vpu_class);
+		goto err_out_chrdev;
+	}
+
+	temp_class = device_create(vpu_class, NULL, MKDEV(vpu_major, 0),
+				   NULL, "mxc_vpu");
+	if (IS_ERR(temp_class)) {
+		err = PTR_ERR(temp_class);
+		goto err_out_class;
+	}
+
+	vpu_clk = clk_get(&pdev->dev, "vpu_clk");
+	if (IS_ERR(vpu_clk)) {
+		err = -ENOENT;
+		goto err_out_class;
+	}
+
+	vpu_ipi_irq = platform_get_irq_byname(pdev, "vpu_ipi_irq");
+	if (vpu_ipi_irq < 0) {
+		dev_err(vpu_dev, "vpu: unable to get vpu interrupt\n");
+		err = -ENXIO;
+		goto err_out_class;
+	}
+	err = request_irq(vpu_ipi_irq, vpu_ipi_irq_handler, 0, "VPU_CODEC_IRQ",
+			  (void *)(&vpu_data));
+	if (err)
+		goto err_out_class;
+	if (vpu_power_get(true)) {
+		if (!(cpu_is_mx51() || cpu_is_mx53())) {
+			dev_err(vpu_dev, "failed to get vpu power\n");
+			goto err_out_class;
+		} else {
+			/* regulator_get will return error on MX5x,
+			 * just igore it everywhere*/
+			dev_warn(vpu_dev, "failed to get vpu power\n");
+		}
+	}
+
+#ifdef MXC_VPU_HAS_JPU
+	vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq");
+	if (vpu_jpu_irq < 0) {
+		dev_err(vpu_dev, "vpu: unable to get vpu jpu interrupt\n");
+		err = -ENXIO;
+		free_irq(vpu_ipi_irq, &vpu_data);
+		goto err_out_class;
+	}
+	err = request_irq(vpu_jpu_irq, vpu_jpu_irq_handler, IRQF_TRIGGER_RISING,
+			  "VPU_JPG_IRQ", (void *)(&vpu_data));
+	if (err) {
+		free_irq(vpu_ipi_irq, &vpu_data);
+		goto err_out_class;
+	}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	pm_runtime_enable(&pdev->dev);
+#endif
+
+	vpu_data.workqueue = create_workqueue("vpu_wq");
+	INIT_WORK(&vpu_data.work, vpu_worker_callback);
+	mutex_init(&vpu_data.lock);
+	dev_info(vpu_dev, "VPU initialized\n");
+	goto out;
+
+err_out_class:
+	device_destroy(vpu_class, MKDEV(vpu_major, 0));
+	class_destroy(vpu_class);
+err_out_chrdev:
+	unregister_chrdev(vpu_major, "mxc_vpu");
+error:
+	iounmap(vpu_base);
+out:
+	return err;
+}
+
+static int vpu_dev_remove(struct platform_device *pdev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	pm_runtime_disable(&pdev->dev);
+#endif
+	free_irq(vpu_ipi_irq, &vpu_data);
+#ifdef MXC_VPU_HAS_JPU
+	free_irq(vpu_jpu_irq, &vpu_data);
+#endif
+	cancel_work_sync(&vpu_data.work);
+	flush_workqueue(vpu_data.workqueue);
+	destroy_workqueue(vpu_data.workqueue);
+
+	iounmap(vpu_base);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+	if (iram.start)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+		gen_pool_free(iram_pool, iram_base, iram.end-iram.start+1);
+#else
+		iram_free(iram.start, iram.end-iram.start+1);
+#endif
+#else
+	if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
+		iram_free(iram.start,  vpu_plat->iram_size);
+#endif
+
+	vpu_power_get(false);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int __maybe_unused vpu_suspend(struct device *dev)
+#else
+static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
+#endif
+{
+	int i;
+	unsigned long timeout;
+
+	mutex_lock(&vpu_data.lock);
+	if (open_count == 0) {
+		/* VPU is released (all instances are freed),
+		 * clock is already off, context is no longer needed,
+		 * power is already off on MX6,
+		 * gate power on MX51 */
+		if (cpu_is_mx51()) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+			if (vpu_plat->pg)
+				vpu_plat->pg(1);
+#endif
+		}
+	} else {
+		/* Wait for vpu go to idle state, suspect vpu cannot be changed
+		   to idle state after about 1 sec */
+		timeout = jiffies + HZ;
+		clk_prepare(vpu_clk);
+		clk_enable(vpu_clk);
+		while (READ_REG(BIT_BUSY_FLAG)) {
+			msleep(1);
+			if (time_after(jiffies, timeout)) {
+				clk_disable(vpu_clk);
+				clk_unprepare(vpu_clk);
+				mutex_unlock(&vpu_data.lock);
+				return -EAGAIN;
+			}
+		}
+		clk_disable(vpu_clk);
+		clk_unprepare(vpu_clk);
+
+		/* Make sure clock is disabled before suspend */
+		vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+		for (i = 0; i < vpu_clk_usercount; i++) {
+			clk_disable(vpu_clk);
+			clk_unprepare(vpu_clk);
+		}
+
+		if (cpu_is_mx53()) {
+			mutex_unlock(&vpu_data.lock);
+			return 0;
+		}
+
+		if (bitwork_mem.cpu_addr != 0) {
+			clk_prepare(vpu_clk);
+			clk_enable(vpu_clk);
+			/* Save 64 registers from BIT_CODE_BUF_ADDR */
+			for (i = 0; i < 64; i++)
+				regBk[i] = READ_REG(BIT_CODE_BUF_ADDR + (i * 4));
+			pc_before_suspend = READ_REG(BIT_CUR_PC);
+			clk_disable(vpu_clk);
+			clk_unprepare(vpu_clk);
+		}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+		if (vpu_plat->pg)
+			vpu_plat->pg(1);
+#endif
+
+		/* If VPU is working before suspend, disable
+		 * regulator to make usecount right. */
+		vpu_power_up(false);
+	}
+
+	mutex_unlock(&vpu_data.lock);
+	return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int __maybe_unused vpu_resume(struct device *dev)
+#else
+static int vpu_resume(struct platform_device *pdev)
+#endif
+{
+	int i;
+
+	mutex_lock(&vpu_data.lock);
+	if (open_count == 0) {
+		/* VPU is released (all instances are freed),
+		 * clock should be kept off, context is no longer needed,
+		 * power should be kept off on MX6,
+		 * disable power gating on MX51 */
+		if (cpu_is_mx51()) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+			if (vpu_plat->pg)
+				vpu_plat->pg(0);
+#endif
+		}
+	} else {
+		if (cpu_is_mx53())
+			goto recover_clk;
+
+		/* If VPU is working before suspend, enable
+		 * regulator to make usecount right. */
+		vpu_power_up(true);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+		if (vpu_plat->pg)
+			vpu_plat->pg(0);
+#endif
+
+		if (bitwork_mem.cpu_addr != 0) {
+			u32 *p = (u32 *) bitwork_mem.cpu_addr;
+			u32 data, pc;
+			u16 data_hi;
+			u16 data_lo;
+
+			clk_prepare(vpu_clk);
+			clk_enable(vpu_clk);
+
+			pc = READ_REG(BIT_CUR_PC);
+			if (pc) {
+				dev_warn(vpu_dev, "Not power off after suspend (PC=0x%x)\n", pc);
+				clk_disable(vpu_clk);
+				clk_unprepare(vpu_clk);
+				goto recover_clk;
+			}
+
+			/* Restore registers */
+			for (i = 0; i < 64; i++)
+				WRITE_REG(regBk[i], BIT_CODE_BUF_ADDR + (i * 4));
+
+			WRITE_REG(0x0, BIT_RESET_CTRL);
+			WRITE_REG(0x0, BIT_CODE_RUN);
+			/* MX6 RTL has a bug not to init MBC_SET_SUBBLK_EN on reset */
+#ifdef CONFIG_SOC_IMX6Q
+			WRITE_REG(0x0, MBC_SET_SUBBLK_EN);
+#endif
+
+			/*
+			 * Re-load boot code, from the codebuffer in external RAM.
+			 * Thankfully, we only need 4096 bytes, same for all platforms.
+			 */
+			for (i = 0; i < 2048; i += 4) {
+				data = p[(i / 2) + 1];
+				data_hi = (data >> 16) & 0xFFFF;
+				data_lo = data & 0xFFFF;
+				WRITE_REG((i << 16) | data_hi, BIT_CODE_DOWN);
+				WRITE_REG(((i + 1) << 16) | data_lo,
+						BIT_CODE_DOWN);
+
+				data = p[i / 2];
+				data_hi = (data >> 16) & 0xFFFF;
+				data_lo = data & 0xFFFF;
+				WRITE_REG(((i + 2) << 16) | data_hi,
+						BIT_CODE_DOWN);
+				WRITE_REG(((i + 3) << 16) | data_lo,
+						BIT_CODE_DOWN);
+			}
+
+			if (pc_before_suspend) {
+				WRITE_REG(0x1, BIT_BUSY_FLAG);
+				WRITE_REG(0x1, BIT_CODE_RUN);
+				while (READ_REG(BIT_BUSY_FLAG))
+					;
+			} else {
+				dev_warn(vpu_dev, "PC=0 before suspend\n");
+			}
+			clk_disable(vpu_clk);
+			clk_unprepare(vpu_clk);
+		}
+
+recover_clk:
+		/* Recover vpu clock */
+		for (i = 0; i < vpu_clk_usercount; i++) {
+			clk_prepare(vpu_clk);
+			clk_enable(vpu_clk);
+		}
+	}
+
+	mutex_unlock(&vpu_data.lock);
+	return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int vpu_runtime_suspend(struct device *dev)
+{
+	release_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+	request_bus_freq(BUS_FREQ_HIGH);
+	return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+	SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+#endif
+
+#else
+#define	vpu_suspend	NULL
+#define	vpu_resume	NULL
+#endif				/* !CONFIG_PM */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static const struct of_device_id vpu_of_match[] = {
+	{ .compatible = "fsl,imx6-vpu", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+#endif
+
+/*! Driver definition
+ *
+ */
+static struct platform_driver mxcvpu_driver = {
+	.driver = {
+		   .name = "mxc_vpu",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+		   .of_match_table = vpu_of_match,
+#ifdef CONFIG_PM
+		   .pm = &vpu_pm_ops,
+#endif
+#endif
+		   },
+	.probe = vpu_dev_probe,
+	.remove = vpu_dev_remove,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+	.suspend = vpu_suspend,
+	.resume = vpu_resume,
+#endif
+};
+
+static int __init vpu_init(void)
+{
+	int ret = platform_driver_register(&mxcvpu_driver);
+
+	init_waitqueue_head(&vpu_queue);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+	memblock_analyze();
+	top_address_DRAM = memblock_end_of_DRAM_with_reserved();
+#endif
+
+	return ret;
+}
+
+static void __exit vpu_exit(void)
+{
+	if (vpu_major > 0) {
+		device_destroy(vpu_class, MKDEV(vpu_major, 0));
+		class_destroy(vpu_class);
+		unregister_chrdev(vpu_major, "mxc_vpu");
+		vpu_major = 0;
+	}
+
+	vpu_free_dma_buffer(&bitwork_mem);
+	vpu_free_dma_buffer(&pic_para_mem);
+	vpu_free_dma_buffer(&user_data_mem);
+
+	/* reset VPU state */
+	vpu_power_up(true);
+	clk_prepare(vpu_clk);
+	clk_enable(vpu_clk);
+	vpu_reset();
+	clk_disable(vpu_clk);
+	clk_unprepare(vpu_clk);
+	vpu_power_up(false);
+
+	clk_put(vpu_clk);
+
+	platform_driver_unregister(&mxcvpu_driver);
+	return;
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_init(vpu_init);
+module_exit(vpu_exit);
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/Kconfig
@@ -0,0 +1,21 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) MALONE DECODER support"
+
+config MXC_VPU_MALONE
+	  tristate "Support for MXC VPU(Video Processing Unit) MALONE B0 DECODER"
+	  depends on VIDEO_V4L2
+	  default y
+	---help---
+	  The VPU codec device provides codec function for H.265 H.264 MPEG2 MPEG4 etc.
+
+config MXC_VPU_MALONE_DEBUG
+	bool "MXC VPU MALONE debugging"
+	depends on MXC_VPU_MALONE != n
+	help
+	  This is an option for the developers; most people should
+	  say N here.  This enables MXC VPU driver debugging.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/Makefile
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/Makefile
@@ -0,0 +1,18 @@
+##
+## Makefile for the VPU and M0 driver
+##
+DEFINES += -D REBOOT=1 \
+		   -D BOOT_ARCH=1
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-$(CONFIG_MXC_VPU_MALONE) = vpu-malone.o
+vpu-malone-objs = vpu_b0.o \
+	vpu_rpc.o \
+	insert_startcode.o \
+	vpu_debug_log.o \
+	vpu_mu.o \
+	vpu_pm.o
+
+clean:
+	rm -rf $(vpu-malone-objs)
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/insert_startcode.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/insert_startcode.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file insert_startcode.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include "insert_startcode.h"
+
+static void set_payload_hdr(unsigned char *dst, unsigned int scd_type, unsigned int codec_id,
+			unsigned int buffer_size, unsigned int width, unsigned int height)
+{
+	unsigned int payload_size;
+	/* payload_size = buffer_size + itself_size(16) - start_code(4) */
+	payload_size = buffer_size + 12;
+
+	dst[0] = 0x00;
+	dst[1] = 0x00;
+	dst[2] = 0x01;
+	dst[3] = scd_type;
+
+	/* length */
+	dst[4] = ((payload_size>>16)&0xff);
+	dst[5] = ((payload_size>>8)&0xff);
+	dst[6] = 0x4e;
+	dst[7] = ((payload_size>>0)&0xff);
+
+	/* Codec ID and Version */
+	dst[8] = codec_id;
+	dst[9] = IMX_CODEC_VERSION_ID;
+
+	/* width */
+	dst[10] = ((width>>8)&0xff);
+	dst[11] = ((width>>0)&0xff);
+	dst[12] = 0x58;
+
+	/* height */
+	dst[13] = ((height>>8)&0xff);
+	dst[14] = ((height>>0)&0xff);
+	dst[15] = 0x50;
+}
+
+static void set_vc1_rcv_seqhdr(unsigned char *dst, unsigned char *src,
+				unsigned int width, unsigned int height)
+{
+	unsigned int frames = IMX_VC1_RCV_NUM_FRAMES;
+	unsigned int ext_data_size = IMX_VC1_RCV_SEQ_EXT_DATA_SIZE;
+
+	/* 0-2 Number of frames, used default value 0xFF */
+	dst[0] = (unsigned char)frames;
+	dst[1] = (unsigned char)(frames >> 8);
+	dst[2] = (unsigned char)(frames >> 16);
+
+	/* 3 RCV version, used V1 */
+	dst[3] = (unsigned char)(IMX_VC1_RCV_CODEC_V1_VERSION);
+
+	/* 4-7 extension data size */
+	dst[4] = (unsigned char)ext_data_size;
+	dst[5] = (unsigned char)(ext_data_size >> 8);
+	dst[6] = (unsigned char)(ext_data_size >> 16);
+	dst[7] = (unsigned char)(ext_data_size >> 24);
+	/* 8-11 extension data */
+	dst[8] = src[0];
+	dst[9] = src[1];
+	dst[10] = src[2];
+	dst[11] = src[3];
+
+	/* height */
+	dst[12] = (unsigned char)height;
+	dst[13] = (unsigned char)(((height >> 8) & 0xff));
+	dst[14] = (unsigned char)(((height >> 16) & 0xff));
+	dst[15] = (unsigned char)(((height >> 24) & 0xff));
+	/* width */
+	dst[16] = (unsigned char)width;
+	dst[17] = (unsigned char)(((width >> 8) & 0xff));
+	dst[18] = (unsigned char)(((width >> 16) & 0xff));
+	dst[19] = (unsigned char)(((width >> 24) & 0xff));
+}
+
+static void set_vc1_rcv_pichdr(unsigned char *dst, unsigned int buffer_size)
+{
+	dst[0] = (unsigned char)buffer_size;
+	dst[1] = (unsigned char)(buffer_size >> 8);
+	dst[2] = (unsigned char)(buffer_size >> 16);
+	dst[3] = (unsigned char)(buffer_size >> 24);
+}
+
+static int create_vc1_nal_pichdr(unsigned char *dst, void *data)
+{
+	int len = 0;
+
+	if (IMX_VC1_IS_NOT_NAL(*((unsigned int *)data))) {
+		/* need insert nal header: special ID */
+		dst[0] = 0x0;
+		dst[1] = 0x0;
+		dst[2] = 0x01;
+		dst[3] = 0x0D;
+
+		len = 4;
+	}
+
+	return len;
+}
+
+static unsigned int insert_scd_pic_vc1(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+
+	if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+		unsigned int rcv_pichdr_size = IMX_VC1_RCV_PIC_HEADER_LEN;
+		unsigned char rcv_pichdr[IMX_VC1_RCV_PIC_HEADER_LEN] = { 0 };
+		unsigned char scd_pichdr[16] = { 0 };
+
+		set_payload_hdr(scd_pichdr, SCODE_NEW_PICTURE, IMX_CODEC_ID_VC1_SIMPLE,
+				rcv_pichdr_size + buffer_size, q_data->width, q_data->height);
+		length += copy_buffer_to_stream(ctx, scd_pichdr, 16);
+		set_vc1_rcv_pichdr(rcv_pichdr, buffer_size);
+		length += copy_buffer_to_stream(ctx, rcv_pichdr, rcv_pichdr_size);
+	} else {
+		unsigned char nal_hdr[IMX_VC1_NAL_HEADER_LEN] = { 0 };
+		unsigned int len;
+
+		len = create_vc1_nal_pichdr(nal_hdr, data);
+		length += copy_buffer_to_stream(ctx, nal_hdr, len);
+	}
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_vc1(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned int rvc_seqhdr_size = IMX_VC1_RCV_SEQ_HEADER_LEN;
+	unsigned char rcv_seqhdr[IMX_VC1_RCV_SEQ_HEADER_LEN] = { 0 };
+	unsigned char scd_seqhdr[16] = { 0 };
+
+	if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+		set_payload_hdr(scd_seqhdr, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VC1_SIMPLE,
+					rvc_seqhdr_size, q_data->width, q_data->height);
+		length += copy_buffer_to_stream(ctx, scd_seqhdr, 16);
+
+		set_vc1_rcv_seqhdr(rcv_seqhdr, data, q_data->width, q_data->height);
+		length += copy_buffer_to_stream(ctx, rcv_seqhdr, rvc_seqhdr_size);
+	} else {
+		length += copy_buffer_to_stream(ctx, data, buffer_size);
+	}
+
+	return length;
+}
+
+static unsigned int insert_scd_pic_vp6(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char pic_header[16] = { 0 };
+
+	set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_VC1_SIMPLE,
+			buffer_size, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_vp6(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char seq_header[16] = {0};
+	unsigned char *src = (unsigned char *)data;
+
+	set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VP6,
+			0, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+	/* first data include frame data, need to handle them too */
+	length += insert_scd_pic_vp6(ctx, buffer_size, data);
+	length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+	return length;
+}
+
+static void set_vp8_ivf_seqhdr(unsigned char *dst, int width, int height)
+{
+	/* 0-3byte signature "DKIF" */
+	dst[0] = 0x44;
+	dst[1] = 0x4b;
+	dst[2] = 0x49;
+	dst[3] = 0x46;
+	/* 4-5byte version: should be 0*/
+	dst[4] = 0x00;
+	dst[5] = 0x00;
+	/* 6-7 length of Header */
+	dst[6] = IMX_VP8_IVF_SEQ_HEADER_LEN;
+	dst[7] = IMX_VP8_IVF_SEQ_HEADER_LEN >> 8;
+	/* 8-11 VP8 fourcc */
+	dst[8] = 0x56;
+	dst[9] = 0x50;
+	dst[10] = 0x38;
+	dst[11] = 0x30;
+	/* 12-13 width in pixels */
+	dst[12] = width;
+	dst[13] = width >> 8;
+	/* 14-15 height in pixels */
+	dst[14] = height;
+	dst[15] = height >> 8;
+	/* 16-19 frame rate */
+	dst[16] = 0xe8;
+	dst[17] = 0x03;
+	dst[18] = 0x00;
+	dst[19] = 0x00;
+	/* 20-23 time scale */
+	dst[20] = 0x01;
+	dst[21] = 0x00;
+	dst[22] = 0x00;
+	dst[23] = 0x00;
+	/* 24-27 number frames */
+	dst[24] = 0xdf;
+	dst[25] = 0xf9;
+	dst[26] = 0x09;
+	dst[27] = 0x00;
+	/* 28-31 reserved */
+}
+
+static void set_vp8_ivf_pichdr(unsigned char *dst, unsigned int frame_size)
+{
+	/*
+	 * firmware just parse 64-bit timestamp(8 bytes).
+	 * As not transfer timestamp to firmware, use default value(ZERO).
+	 * No need to do anything here
+	 */
+}
+
+static unsigned int insert_scd_pic_vp8(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned int ivf_pichdr_size = IMX_VP8_IVF_FRAME_HEADER_LEN;
+	unsigned char pic_header[16] = { 0 };
+	unsigned char ivf_frame_header[IMX_VP8_IVF_FRAME_HEADER_LEN] = { 0 };
+
+	set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_VP8,
+			ivf_pichdr_size + buffer_size, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, pic_header, 16);
+	set_vp8_ivf_pichdr(ivf_frame_header, buffer_size);
+	length += copy_buffer_to_stream(ctx, ivf_frame_header, ivf_pichdr_size);
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_vp8(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned int ivf_seqhdr_size = IMX_VP8_IVF_SEQ_HEADER_LEN;
+	unsigned char scd_seqhdr[16] = { 0 };
+	unsigned char ivf_seqhdr[IMX_VP8_IVF_SEQ_HEADER_LEN] = { 0 };
+	unsigned char *src = (unsigned char *)data;
+
+	set_payload_hdr(scd_seqhdr, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VP8,
+				ivf_seqhdr_size, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, scd_seqhdr, 16);
+	set_vp8_ivf_seqhdr(ivf_seqhdr, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, ivf_seqhdr, ivf_seqhdr_size);
+
+	/* first data include frame data, need to handle them too */
+	length += insert_scd_pic_vp8(ctx, buffer_size, data);
+	length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+	return length;
+}
+
+static unsigned int insert_scd_pic_asp(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char pic_header[16] = { 0 };
+
+	if (q_data->fourcc == VPU_PIX_FMT_DIV3) {
+		set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_DIVX3,
+					buffer_size, q_data->width, q_data->height);
+		length += copy_buffer_to_stream(ctx, pic_header, 16);
+	}
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_asp(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char seq_header[16] = {0};
+	unsigned char *src = (unsigned char *)data;
+
+	if (q_data->fourcc == VPU_PIX_FMT_DIV3) {
+		set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_DIVX3,
+				0, q_data->width, q_data->height);
+		length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+		/* first data include frame data, need to handle them too */
+		length += insert_scd_pic_asp(ctx, buffer_size, data);
+		length += copy_buffer_to_stream(ctx, src, buffer_size);
+	} else {
+		/*
+		 * other format no sequence or picture header
+		 * directly copy frame data to ring buffer
+		 */
+		length += copy_buffer_to_stream(ctx, src, buffer_size);
+	}
+
+	return length;
+}
+
+static unsigned int insert_scd_pic_spk(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char pic_header[16] = { 0 };
+
+	set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_SPK,
+				buffer_size, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_spk(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char seq_header[16] = {0};
+	unsigned char *src = (unsigned char *)data;
+
+	set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_SPK,
+			0, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+	/* first data include frame data, need to handle them too */
+	length += insert_scd_pic_spk(ctx, buffer_size, data);
+	length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+	return length;
+}
+
+static unsigned int insert_slice_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char slice_header[16] = { 0 };
+	unsigned int codec_id;
+
+	if (ctx->arv_type == ARV_8)
+		codec_id = IMX_CODEC_ID_ARV8;
+	else
+		codec_id = IMX_CODEC_ID_ARV9;
+
+	set_payload_hdr(slice_header, SCODE_NEW_SLICE, codec_id, buffer_size,
+			q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, slice_header, 16);
+
+	return length;
+}
+
+static unsigned int insert_scd_pic_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned int slice_num = 0;
+	unsigned int packlen = 0;
+	unsigned char pic_header[16] = { 0 };
+	unsigned char *src = (unsigned char *)data;
+	unsigned int codec_id;
+
+	slice_num = ((src[16] << 24) | (src[17] << 16) | (src[18] << 8) | (src[19]));
+	packlen = 20 + 8 * slice_num;
+	if (ctx->arv_type == ARV_8)
+		codec_id = IMX_CODEC_ID_ARV8;
+	else
+		codec_id = IMX_CODEC_ID_ARV9;
+
+	set_payload_hdr(pic_header, SCODE_NEW_PICTURE, codec_id, packlen,
+			q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+	return length;
+}
+
+static unsigned int insert_scd_seq_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+	unsigned char seq_header[16] = {0};
+	unsigned int codec_id;
+
+	if (strncmp((const char *)(data + 8), "RV30", 4) == 0) {
+		ctx->arv_type = ARV_8;
+		codec_id = IMX_CODEC_ID_ARV8;
+	} else {
+		ctx->arv_type = ARV_9;
+		codec_id = IMX_CODEC_ID_ARV9;
+	}
+
+	set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, codec_id,
+			buffer_size, q_data->width, q_data->height);
+	length += copy_buffer_to_stream(ctx, seq_header, 16);
+	length += copy_buffer_to_stream(ctx, data, buffer_size);
+
+	return length;
+}
+
+u_int32 single_seq_info_format(struct queue_data *q_data)
+{
+	u_int32 ret = 0;
+
+	switch (q_data->fourcc) {
+	case V4L2_PIX_FMT_VC1_ANNEX_G:
+	case V4L2_PIX_FMT_VC1_ANNEX_L:
+	case VPU_PIX_FMT_RV:
+	case V4L2_PIX_FMT_MPEG4:
+	case V4L2_PIX_FMT_MPEG2:
+	case V4L2_PIX_FMT_XVID:
+		ret = 1;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+bool check_free_size_4_seq(struct vpu_ctx *ctx, u_int32 uPayloadSize)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	u_int32 nfreespace = 0;
+	u_int32 length = 0;
+
+	switch (q_data->vdec_std) {
+	case VPU_VIDEO_VC1:
+		length = IMX_VC1_RCV_SEQ_HEADER_LEN + 16;
+		break;
+	case  VPU_VIDEO_VP6:
+		length = uPayloadSize + 32;
+		break;
+	case VPU_VIDEO_VP8:
+		length = uPayloadSize + 72;
+		break;
+	case VPU_VIDEO_ASP:
+		length = uPayloadSize + 16;
+		break;
+	case VPU_VIDEO_SPK:
+		length = uPayloadSize + 32;
+		break;
+	case VPU_VIDEO_RV:
+		length = uPayloadSize + 16;
+		break;
+	case VPU_VIDEO_AVC:
+	case VPU_VIDEO_MPEG2:
+	case VPU_VIDEO_AVS:
+	case VPU_VIDEO_JPEG:
+	case VPU_VIDEO_AVC_MVC:
+	case VPU_VIDEO_HEVC:
+	case VPU_VIDEO_UNDEFINED:
+		length = uPayloadSize;
+		break;
+	default:
+		break;
+	}
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	nfreespace = got_free_space(pStrBufDesc->wptr, pStrBufDesc->rptr,
+				    pStrBufDesc->start, pStrBufDesc->end);
+	if (nfreespace < (length + MIN_SPACE)) {
+		vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size\n");
+		return false;
+	}
+
+	return true;
+}
+
+bool check_free_size_pic(struct vpu_ctx *ctx, unsigned int buffer_size)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	unsigned int nfreespace = 0;
+	unsigned int length = 0;
+
+	switch (q_data->vdec_std) {
+	case VPU_VIDEO_VC1:
+		length = buffer_size + IMX_VC1_RCV_PIC_HEADER_LEN
+			+ IMX_PAYLOAD_HEADER_SIZE;
+		break;
+	case VPU_VIDEO_VP8:
+		length = buffer_size + IMX_VP8_IVF_FRAME_HEADER_LEN + IMX_PAYLOAD_HEADER_SIZE;
+		break;
+	case  VPU_VIDEO_VP6:
+	case VPU_VIDEO_ASP:
+	case VPU_VIDEO_SPK:
+		length = buffer_size + IMX_PAYLOAD_HEADER_SIZE;
+		break;
+	case VPU_VIDEO_RV:
+		/* speciall: buffer_size need to include all slice header size*/
+		length = buffer_size + IMX_PAYLOAD_HEADER_SIZE;
+		break;
+	case VPU_VIDEO_AVC:
+	case VPU_VIDEO_MPEG2:
+	case VPU_VIDEO_AVS:
+	case VPU_VIDEO_JPEG:
+	case VPU_VIDEO_AVC_MVC:
+	case VPU_VIDEO_HEVC:
+	case VPU_VIDEO_UNDEFINED:
+		length = buffer_size;
+		break;
+	default:
+		break;
+	}
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	nfreespace = got_free_space(pStrBufDesc->wptr, pStrBufDesc->rptr,
+				    pStrBufDesc->start, pStrBufDesc->end);
+	if (nfreespace < (length + MIN_SPACE)) {
+		vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size\n");
+		return false;
+	}
+
+	return true;
+}
+
+struct VPU_FMT_INFO_ARV *get_arv_info(struct vpu_ctx *ctx, u_int8 *src, u_int32 size)
+{
+	u_int32 i;
+	struct VPU_FMT_INFO_ARV *arv_frame;
+
+	if (!ctx || !src)
+		return NULL;
+
+	if (size < 28)
+		return NULL;
+
+	arv_frame = kzalloc(sizeof(struct VPU_FMT_INFO_ARV), GFP_KERNEL);
+	if (IS_ERR_OR_NULL(arv_frame)) {
+		vpu_err("%s() error: arv_frame alloc failed\n", __func__);
+		goto err;
+	}
+
+	arv_frame->type = ctx->arv_type;
+
+	arv_frame->data_len = ((src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]));
+	arv_frame->slice_num = ((src[16] << 24) | (src[17] << 16) | (src[18] << 8) | (src[19]));
+	if (arv_frame->data_len > size || arv_frame->slice_num > size) {
+		vpu_dbg(LVL_WARN, "arv frame info incorrect, data_len=%d  slice_num=%d  buffer_size=%d\n",
+			arv_frame->data_len, arv_frame->slice_num, size);
+		goto err;
+	}
+
+	arv_frame->slice_offset = kcalloc(arv_frame->slice_num, sizeof(u_int32), GFP_KERNEL);
+	if (IS_ERR_OR_NULL(arv_frame->slice_offset)) {
+		vpu_err("%s() error: slice_offset alloc failed\n", __func__);
+		goto err;
+	}
+
+	for (i = 0; i < arv_frame->slice_num; i++)
+		arv_frame->slice_offset[i] = ((src[20+8*i+4] << 24) | (src[20+8*i+5] << 16) | (src[20+8*i+6] << 8) | (src[20+8*i+7]));
+
+	return arv_frame;
+
+err:
+	kfree(arv_frame->slice_offset);
+	kfree(arv_frame);
+	return NULL;
+}
+
+void put_arv_info(struct VPU_FMT_INFO_ARV *arv_frame)
+{
+	kfree(arv_frame->slice_offset);
+	kfree(arv_frame);
+}
+
+static const struct imx_scd_handler handlers[] = {
+	{.vdec_std = VPU_VIDEO_VC1,
+	 .insert_scd_seq = insert_scd_seq_vc1,
+	 .insert_scd_pic = insert_scd_pic_vc1,
+	},
+	{.vdec_std = VPU_VIDEO_VP6,
+	 .insert_scd_seq = insert_scd_seq_vp6,
+	 .insert_scd_pic = insert_scd_pic_vp6,
+	},
+	{.vdec_std = VPU_VIDEO_VP8,
+	 .insert_scd_seq = insert_scd_seq_vp8,
+	 .insert_scd_pic = insert_scd_pic_vp8,
+	},
+	{.vdec_std = VPU_VIDEO_ASP,
+	 .insert_scd_seq = insert_scd_seq_asp,
+	 .insert_scd_pic = insert_scd_pic_asp,
+	},
+	{.vdec_std = VPU_VIDEO_SPK,
+	 .insert_scd_seq = insert_scd_seq_spk,
+	 .insert_scd_pic = insert_scd_pic_spk,
+	},
+	{.vdec_std = VPU_VIDEO_RV,
+	 .insert_scd_seq = insert_scd_seq_arv,
+	 .insert_scd_pic = insert_scd_pic_arv,
+	 .insert_scd_slice = insert_slice_arv,
+	},
+};
+
+unsigned int insert_scode(struct vpu_ctx *ctx, unsigned int scd_type, unsigned int buffer_size, void *data)
+{
+	const struct imx_scd_handler *handler;
+	int i = 0;
+	bool found = false;
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	unsigned int length = 0;
+
+	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+		handler = &handlers[i];
+		if (handler->vdec_std != q_data->vdec_std)
+			continue;
+		found = true;
+		break;
+	}
+
+	if (scd_type ==  SCODE_NEW_SEQUENCE) {
+		if (!check_free_size_4_seq(ctx, buffer_size))
+			return length;
+
+		/* some format first data is frame data, and no need to add
+		 * any header, directly copy it to ring buffer.
+		 */
+		if (found && handler->insert_scd_seq)
+			length = handler->insert_scd_seq(ctx, buffer_size, data);
+		else
+			length = copy_buffer_to_stream(ctx, data, buffer_size);
+	} else if (scd_type ==  SCODE_NEW_PICTURE) {
+		if (found && handler->insert_scd_pic)
+			length = handler->insert_scd_pic(ctx, buffer_size, data);
+	} else if (scd_type ==  SCODE_NEW_SLICE) {
+		if (found && handler->insert_scd_slice)
+			length = handler->insert_scd_slice(ctx, buffer_size, data);
+	} else {
+		vpu_dbg(LVL_WARN, "ctx[%d] scd_type invalid\n", ctx->str_index);
+	}
+
+	return length;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/insert_startcode.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/insert_startcode.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file insert_startcode.h
+ *
+ */
+#ifndef __INSERT_STARTCODE_H__
+#define __INSERT_STARTCODE_H__
+
+#include "vpu_b0.h"
+#include "mediasys_types.h"
+#define SCODE_NEW_SEQUENCE 0x31
+#define SCODE_NEW_PICTURE 0x32
+#define SCODE_NEW_SLICE 0x33
+
+#define IMX_PAYLOAD_HEADER_SIZE		16
+
+#define IMX_CODEC_VERSION_ID		0x1
+
+#define IMX_CODEC_ID_VC1_SIMPLE		0x10
+#define IMX_CODEC_ID_VC1_MAIN		0x11
+#define IMX_CODEC_ID_ARV8		0x28
+#define IMX_CODEC_ID_ARV9		0x29
+#define IMX_CODEC_ID_VP6		0x36
+#define IMX_CODEC_ID_VP8		0x36
+#define IMX_CODEC_ID_DIVX3		0x38
+#define IMX_CODEC_ID_SPK		0x39
+
+#define IMX_VC1_RCV_CODEC_V1_VERSION	0x85
+#define IMX_VC1_RCV_CODEC_V2_VERSION	0xC5
+#define IMX_VC1_RCV_NUM_FRAMES          0xFF
+#define IMX_VC1_RCV_SEQ_EXT_DATA_SIZE	4
+#define IMX_VC1_RCV_SEQ_HEADER_LEN	20
+#define IMX_VC1_RCV_PIC_HEADER_LEN	4
+#define IMX_VC1_NAL_HEADER_LEN		4
+#define IMX_VC1_IS_NOT_NAL(id)      ((id & 0x00FFFFFF) != 0x00010000)
+
+#define IMX_VP8_IVF_SEQ_HEADER_LEN	32
+#define IMX_VP8_IVF_FRAME_HEADER_LEN	8
+
+
+struct imx_scd_handler {
+	unsigned int vdec_std;
+
+	unsigned int (*insert_scd_seq)(struct vpu_ctx *ctx, unsigned int buffer_size, void *data);
+	unsigned int (*insert_scd_pic)(struct vpu_ctx *ctx, unsigned int buffer_size, void *data);
+	unsigned int (*insert_scd_slice)(struct vpu_ctx *ctx, unsigned int buffer_size, void *data);
+};
+
+
+struct VPU_FMT_INFO_ARV *get_arv_info(struct vpu_ctx *ctx, u_int8 *src, u_int32 size);
+void put_arv_info(struct VPU_FMT_INFO_ARV *arv_frame);
+u_int32 single_seq_info_format(struct queue_data *q_data);
+unsigned int insert_scode(struct vpu_ctx *ctx, unsigned int scd_type,
+			  unsigned int buffer_size, void *data);
+bool check_free_size_pic(struct vpu_ctx *ctx, unsigned int buffer_size);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/mediasys_types.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/mediasys_types.h
@@ -0,0 +1,805 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#define VPU_MAX_NUM_STREAMS 8
+#define VID_API_NUM_STREAMS 8
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT    64
+#define VID_API_MESSAGE_LIMIT    256
+#define MSG_WORD_LENGTH 3
+#define MEDIA_PLAYER_SKIPPED_FRAME_ID 0x555
+
+#define API_CMD_AVAILABLE            0x0
+#define API_CMD_INCOMPLETE           0x1
+#define API_CMD_BUFFER_ERROR         0x2
+#define API_CMD_UNAVAILABLE          0x3
+#define API_MSG_AVAILABLE            0x0
+#define API_MSG_INCOMPLETE           0x1
+#define API_MSG_BUFFER_ERROR         0x2
+#define API_MSG_UNAVAILABLE          0x3
+
+typedef enum {
+	FRAME_ALLOC = 0,
+	FRAME_FREE,
+	FRAME_DECODED,
+	FRAME_READY,
+	FRAME_RELEASE,
+	FRAME_SKIP,
+} FRAME_BUFFER_STAT;
+
+typedef enum {
+	VPU_APP,
+	VPU_DRIVER,
+	VPU_DECODER,
+} FRAME_BUFFER_OWNER;
+
+typedef enum {
+	INVALID_MODE = 0,
+	FRAME_LVL,
+	NON_FRAME_LVL,
+} STREAM_INPUT_MODE;
+
+typedef enum {
+	MEDIAIP_FRAME_REQ = 0,
+	MEDIAIP_MBI_REQ,
+	MEDIAIP_DCP_REQ,
+	MEDIAIP_REQ_LAST = MEDIAIP_DCP_REQ
+
+} MEDIAIP_MEM_REQ;
+
+typedef struct {
+	u_int32          uNum;
+	MEDIAIP_MEM_REQ  eType;
+} MEDIA_PLAYER_FSREQ;
+
+typedef struct {
+	u_int32          uFSIdx;
+	MEDIAIP_MEM_REQ  eType;
+	BOOL             bNotDisplayed;
+} MEDIA_PLAYER_FSREL;
+
+typedef enum {
+	/* Non-Stream Specific messages   */
+	MEDIA_PLAYER_API_MODE_INVALID     = 0x00,
+	MEDIA_PLAYER_API_MODE_PARSE_STEP  = 0x01,
+	MEDIA_PLAYER_API_MODE_DECODE_STEP = 0x02,
+	MEDIA_PLAYER_API_MODE_CONTINUOUS  = 0x03
+} MEDIA_PLAYER_API_MODE;
+
+typedef enum {
+	/* Non-Stream Specific messages   */
+	MEDIA_PLAYER_FS_CTRL_MODE_INTERNAL    = 0x00,
+	MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL    = 0x01
+} MEDIA_PLAYER_FS_CTRL_MODE;
+
+typedef enum {
+	/* Non-Stream Specific messages   */
+	VID_API_CMD_NULL              = 0x00,
+	VID_API_CMD_PARSE_NEXT_SEQ    = 0x01,
+	VID_API_CMD_PARSE_NEXT_I      = 0x02,
+	VID_API_CMD_PARSE_NEXT_IP     = 0x03,
+	VID_API_CMD_PARSE_NEXT_ANY    = 0x04,
+	VID_API_CMD_DEC_PIC           = 0x05,
+	VID_API_CMD_UPDATE_ES_WR_PTR  = 0x06,
+	VID_API_CMD_UPDATE_ES_RD_PTR  = 0x07,
+	VID_API_CMD_UPDATE_UDATA      = 0x08,
+	VID_API_CMD_GET_FSINFO        = 0x09,
+	VID_API_CMD_SKIP_PIC          = 0x0a,
+	VID_API_CMD_DEC_CHUNK         = 0x0b,
+	VID_API_CMD_START             = 0x10,
+	VID_API_CMD_STOP              = 0x11,
+	VID_API_CMD_ABORT             = 0x12,
+	VID_API_CMD_RST_BUF           = 0x13,
+	VID_API_CMD_FS_RELEASE        = 0x15,
+	VID_API_CMD_MEM_REGION_ATTACH = 0x16,
+	VID_API_CMD_MEM_REGION_DETACH = 0x17,
+	VID_API_CMD_MVC_VIEW_SELECT   = 0x18,
+	VID_API_CMD_FS_ALLOC          = 0x19,
+	VID_API_CMD_DBG_GET_STATUS    = 0x1C,
+	VID_API_CMD_DBG_START_LOG     = 0x1D,
+	VID_API_CMD_DBG_STOP_LOG      = 0x1E,
+	VID_API_CMD_DBG_DUMP_LOG      = 0x1F,
+	/* Begin Encode CMDs */
+	VID_API_CMD_YUV_READY         = 0x20,
+	VID_API_CMD_TS                = 0x21,
+
+	VID_API_CMD_FIRM_RESET        = 0x40,
+
+#if BOOT_ARCH == REBOOT
+	VID_API_CMD_SNAPSHOT          = 0xAA,
+	VID_API_CMD_ROLL_SNAPSHOT     = 0xAB,
+	VID_API_CMD_LOCK_SCHEDULER    = 0xAC,
+	VID_API_CMD_UNLOCK_SCHEDULER  = 0xAD,
+#endif
+	VID_API_CMD_CQ_FIFO_DUMP      = 0xAE,
+	VID_API_CMD_DBG_FIFO_DUMP     = 0xAF,
+	VID_API_CMD_SVC_ILP           = 0xBB,
+	VID_API_CMD_INVALID           = 0xFF
+
+} TB_API_DEC_CMD;
+
+typedef enum {
+	/* Non-Stream Specific messages    */
+	VID_API_EVENT_NULL			= 0x00,
+	VID_API_EVENT_RESET_DONE		= 0x01,
+	VID_API_EVENT_SEQ_HDR_FOUND		= 0x02,
+	VID_API_EVENT_PIC_HDR_FOUND		= 0x03,
+	VID_API_EVENT_PIC_DECODED		= 0x04,
+	VID_API_EVENT_FIFO_LOW			= 0x05,
+	VID_API_EVENT_FIFO_HIGH			= 0x06,
+	VID_API_EVENT_FIFO_EMPTY		= 0x07,
+	VID_API_EVENT_FIFO_FULL			= 0x08,
+	VID_API_EVENT_BS_ERROR			= 0x09,
+	VID_API_EVENT_UDATA_FIFO_UPTD		= 0x0A,
+	VID_API_EVENT_RES_CHANGE		= 0x0B,
+	VID_API_EVENT_FIFO_OVF			= 0x0C,
+	VID_API_EVENT_CHUNK_DECODED		= 0x0D,
+	VID_API_EVENT_REQ_FRAME_BUFF		= 0x10,
+	VID_API_EVENT_FRAME_BUFF_RDY		= 0x11,
+	VID_API_EVENT_REL_FRAME_BUFF		= 0x12,
+	VID_API_EVENT_STR_BUF_RST		= 0x13,
+	VID_API_EVENT_RET_PING			= 0x14,
+	VID_API_EVENT_QMETER			= 0x15,
+	VID_API_EVENT_STR_FMT_CHANGE		= 0x16,
+	VID_API_EVENT_FIRMWARE_XCPT		= 0x17,
+	VID_API_EVENT_START_DONE		= 0x18,
+	VID_API_EVENT_STOPPED			= 0x19,
+	VID_API_EVENT_ABORT_DONE		= 0x1A,
+	VID_API_EVENT_FINISHED			= 0x1B,
+	VID_API_EVENT_DBG_STAT_UPDATE		= 0x1C,
+	VID_API_EVENT_DBG_LOG_STARTED		= 0x1D,
+	VID_API_EVENT_DBG_LOG_STOPPED		= 0x1E,
+	VID_API_EVENT_DBG_LOG_UPDATED		= 0x1F,
+	VID_API_EVENT_DBG_MSG_DEC		= 0x20,
+	VID_API_EVENT_DEC_SC_ERR		= 0x21,
+	VID_API_EVENT_CQ_FIFO_DUMP		= 0x22,
+	VID_API_EVENT_DBG_FIFO_DUMP		= 0x23,
+	VID_API_EVENT_DEC_CHECK_RES		= 0x24,
+	VID_API_EVENT_DEC_CFG_INFO		= 0x25,
+	VID_API_EVENT_UNSUPPORTED_STREAM	= 0x26,
+	VID_API_EVENT_STR_SUSPENDED		= 0x30,
+	VID_API_EVENT_SNAPSHOT_DONE		= 0x40,
+	VID_API_EVENT_INVALID			= 0xFF
+
+} TB_API_DEC_EVENT;
+
+typedef enum {
+	MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+	MEDIAIP_PLAYMODE_BROADCAST,
+	MEDIAIP_PLAYMODE_BROADCAST_DSS,
+	MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef enum {
+	MEDIA_IP_FMT_NULL        = 0x0,
+	MEDIA_IP_FMT_AVC         = 0x1,
+	MEDIA_IP_FMT_VC1         = 0x2,
+	MEDIA_IP_FMT_MP2         = 0x3,
+	MEDIA_IP_FMT_AVS         = 0x4,
+	MEDIA_IP_FMT_ASP         = 0x5,
+	MEDIA_IP_FMT_JPG         = 0x6,
+	MEDIA_IP_FMT_RV          = 0x7,
+	MEDIA_IP_FMT_VP6         = 0x8,
+	MEDIA_IP_FMT_SPK         = 0x9,
+	MEDIA_IP_FMT_VP8         = 0xA,
+	MEDIA_IP_FMT_MVC         = 0xB,
+	MEDIA_IP_FMT_VP3         = 0xC,
+	MEDIA_IP_FMT_HEVC        = 0xD,
+	MEDIA_IP_FMT_AUTO_DETECT = 0xAD00,
+	MEDIA_IP_FMT_ALL         = (int)0xAAAAAAAA,
+	MEDIA_IP_FMT_UNSUPPORTED = (int)0xFFFFFFFF,
+	MEDIA_IP_FMT_LAST = MEDIA_IP_FMT_UNSUPPORTED
+
+} MEDIA_IP_FORMAT;
+
+typedef enum {
+	VSys_FrmtNull = 0x0,
+	VSys_AvcFrmt  = 0x1,
+	VSys_Mp2Frmt  = 0x2,
+	VSys_Vc1Frmt  = 0x3,
+	VSys_AvsFrmt  = 0x4,
+	VSys_AspFrmt  = 0x5,
+	VSys_JpgFrmt  = 0x6,
+	VSys_RvFrmt   = 0x7,
+	VSys_Vp6Frmt  = 0x8,
+	VSys_SpkFrmt  = 0x9,
+	VSys_Vp8Frmt  = 0xA,
+	VSys_HevcFrmt = 0xB,
+	VSys_LastFrmt = VSys_HevcFrmt
+} TB_API_DEC_FMT;
+
+typedef struct {
+	u_int32 bTopFldFirst;
+	u_int32 bRptFstField;
+	u_int32 uDispVerRes;
+	u_int32	uDispHorRes;
+	u_int32	uCentreVerOffset;
+	u_int32	uCentreHorOffset;
+	u_int32 uCropLeftRightOffset;
+	u_int32 uCropTopBotOffset;
+
+} MediaIPFW_Video_PicDispInfo;
+
+typedef struct MediaIPFW_PicPerfInfo {
+	u_int32 uMemCRC;
+	u_int32 uBSCRC;
+	u_int32 uSlcActiveCnt;
+	u_int32 uIBEmptyCnt;
+	u_int32 uBaseMemCRC;
+
+	u_int32 uBaseCRCSkip;
+	u_int32 uBaseCRCDrop;
+	BOOL    bBaseCRCValid;
+
+	u_int32 uCRC0;
+	u_int32 uCRC1;
+	u_int32 uCRC2;
+	u_int32 uCRC3;
+	u_int32 uCRC4;
+	u_int32 uCRC5;
+
+	u_int32 uFrameActCount;
+	u_int32 uRbspBytesCount;
+	u_int32 uDpbReadCount;
+	u_int32 uMprWaitCount;
+	u_int32 uAccQP;
+	u_int32 uCacheStat;
+	u_int32 mbq_full;
+	u_int32 mbq_empty;
+	u_int32 slice_cnt;
+	u_int32 mb_count;
+
+	u_int32 uTotalTime_us;
+	u_int32 uTotalFwTime_us;
+
+	u_int32 uProcIaccTotRdCnt;
+	u_int32 uProcDaccTotRdCnt;
+	u_int32 uProcDaccTotWrCnt;
+	u_int32 uProcDaccRegRdCnt;
+	u_int32 uProcDaccRegWrCnt;
+	u_int32 uProcDaccRngRdCnt;
+	u_int32 uProcDaccRngWrCnt;
+
+} MediaIPFW_Video_PicPerfInfo;
+
+typedef struct {
+	u_int32 mb_count;
+	u_int32 slice_cnt;
+
+	/* Front End Metrics */
+	u_int32 uDFEBinsUsed;
+	u_int32 uDFECycleCount;
+	u_int32 uDFESliceCycleCount;
+	u_int32 uDFEIBWaitCount;
+	u_int32 uDFENumBytes;
+
+	u_int32 uProcIaccTotRdCnt;
+	u_int32 uProcDaccTotRdCnt;
+	u_int32 uProcDaccTotWrCnt;
+	u_int32 uProcDaccRegRdCnt;
+	u_int32 uProcDaccRegWrCnt;
+	u_int32 uProcDaccRngRdCnt;
+	u_int32 uProcDaccRngWrCnt;
+
+	/* Back End metrics */
+	u_int32 uNumBEUsed;
+	u_int32 uTotalTime_us;
+	u_int32 uTotalFwTime_us;
+	u_int32 uDBECycleCount[0x2];
+	u_int32 uDBESliceCycleCount[0x2];
+	u_int32 uDBEMprWaitCount[0x2];
+	u_int32 uDBEWaitCount[0x2];
+	u_int32 uDBECRC[0x2];
+	u_int32 uDBETotalTime_us[0x2];
+
+	u_int32 uDBEMPRPRXWaitCount[0x2];
+	u_int32 uDBEPXDPRXWaitCount[0x2];
+	u_int32 uDBEFCHPLQWaitCount[0x2];
+	u_int32 uDBEPXDPLQWaitCount[0x2];
+
+	u_int32 uDBEFchWordsCount[0x2];
+	u_int32 uDBEDpbCRC[0x2];
+	u_int32 uDBEDpbReadCount[0x2];
+	u_int32 uDBECacheStats[0x2];
+
+} MediaIPFW_Video_PicPerfDcpInfo, *pMediaIPFW_Video_PicPerfDcpInfo;
+
+typedef struct {
+	u_int32 uPicType;
+	u_int32 uPicStruct;
+	u_int32 bLastPicNPF;
+	u_int32 uPicStAddr;
+	u_int32 uFrameStoreID;
+	MediaIPFW_Video_PicDispInfo    DispInfo;
+	MediaIPFW_Video_PicPerfInfo    PerfInfo;
+	MediaIPFW_Video_PicPerfDcpInfo PerfDcpInfo;
+	u_int32 bUserDataAvail;
+	u_int32 uPercentInErr;
+
+	u_int32 uReservedBbd[3];
+	/* Luma top/bottom and Chroma top/bottom */
+	u_int32 uFSBaseAddr[4];
+
+	/* Only for RealVideo RPR */
+	u_int32 uRprPicWidth;
+	u_int32 uRprPicHeight;
+
+	/*only for divx3*/
+	u_int32 uFrameRate;
+
+} MediaIPFW_Video_PicInfo;
+
+
+typedef struct {
+	u_int32 bClosedGop;
+	u_int32 bBrokenLink;
+} MediaIPFW_Video_GopInfo;
+
+typedef struct {
+	u_int32 uIQuant;
+	u_int32 uIQuantAvail;
+	u_int32 uGopBitRate;
+	u_int32 uGopBitRateAvail;
+
+} MediaIPFW_Video_QMeterInfo;
+
+typedef struct {
+	u_int32                  pPicInfoArrayBase;
+	u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_PicInfoBuffTabDesc;
+
+typedef struct {
+	u_int32                  pGopInfoArrayBase;
+	u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_GopInfoBuffTabDesc;
+
+typedef struct {
+	u_int32                     pQMeterInfoArrayBase;
+	u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_QMeterInfoTabDesc;
+
+typedef struct {
+	u_int32	uMemChunkBase;
+	u_int32	uMemChunkSize;
+
+} MediaIPFW_Video_FrameBuffer;
+
+typedef struct {
+	u_int32	uUDataBase;
+	u_int32	uUDataTotalSize;
+	u_int32 uUDataSlotSize;
+
+} MediaIPFW_Video_UData;
+
+typedef struct {
+	u_int32	uDecStatusLogBase;
+	u_int32	uDecStatusLogSize;
+	u_int32 uDecStatusLogLevel;
+	u_int32   uReserved;
+
+} MediaIPFW_Video_DbgLogDesc;
+
+typedef struct {
+	u_int32 uDTVLogBase[VID_API_NUM_STREAMS];
+	u_int32 uDTVLogSize[VID_API_NUM_STREAMS];
+
+} MediaIPFW_Video_EngAccessLogDesc;
+
+typedef struct MediaIPFW_FrameStore {
+	u_int32 uFrameStoreLumaBase;
+	u_int32 uFrameStoreChromaBase;
+
+} MediaIPFW_Video_FrameStore;
+
+typedef struct {
+	u_int32 uAddrFirstDescriptor;
+	u_int32 uNumSizeDescriptors;
+
+} MediaIPFW_Video_StreamBuffTabDesc;
+
+typedef struct {
+	u_int32 uAddrFirstDescriptor;
+	u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_UserDataBuffTabDesc;
+
+typedef struct {
+	u_int32 uNumRefFrms;
+	u_int32 uNumDPBFrms;
+	u_int32 uNumDFEAreas;
+	u_int32 uColorDesc;
+	u_int32 uTransferChars;
+	u_int32 uMatrixCoeffs;
+	u_int32 uVideoFullRangeFlag;
+	u_int32 uVUIPresent;
+	u_int32 uProgressive;
+	u_int32 uVerRes;
+	u_int32 uHorRes;
+	u_int32 uParWidth;
+	u_int32 uParHeight;
+	u_int32 FrameRate;
+	u_int32 UDispAspRatio;
+	u_int32 uLevelIDC;
+	u_int32 uVerDecodeRes;
+	u_int32 uHorDecodeRes;
+	u_int32 uOverScan;
+	u_int32 uChromaFmt;
+	u_int32 uPAFF;
+	u_int32 uMBAFF;
+	u_int32 uBitDepthLuma;
+	u_int32 uBitDepthChroma;
+	u_int32 uMVCNumViews;
+	u_int32 uMVCViewList[VID_API_MAX_NUM_MVC_VIEWS];
+	u_int32 uActiveSeqTag;
+	u_int32 uFrameCropValid;
+	u_int32 uFrameCropLeftOffset;
+	u_int32 uFrameCropRightOffset;
+	u_int32 uFrameCropTopOffset;
+	u_int32 uFrameCropBottomOffset;
+
+} MediaIPFW_Video_SeqInfo;
+
+typedef struct {
+	u_int32                  pSeqInfoArrayBase;
+	u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_SeqInfoBuffTabDesc;
+
+typedef struct {
+	u_int32 wptr;
+	u_int32 rptr;
+	u_int32 start;
+	u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+	u_int32 stream_input_mode;
+	u_int32 stream_pic_input_count;
+	u_int32 stream_pic_parsed_count;
+	u_int32 stream_buffer_threshold;
+	u_int32 stream_pic_end_flag;
+} BUFFER_INFO_TYPE, *pBUFFER_INFO_TYPE;
+
+typedef struct {
+	volatile u_int32 wptr;
+	volatile u_int32 rptr;
+	volatile u_int32 start;
+	volatile u_int32 end;
+	volatile u_int32 LWM;
+
+} STREAM_BUFFER_DESCRIPTOR_TYPE, *pSTREAM_BUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+	u_int32 uRotationAngle;
+	u_int32 uHorizScaleFactor;
+	u_int32 uVertScaleFactor;
+	u_int32 uRotationMode;
+	u_int32 uRGBMode;
+	u_int32 uChunkMode; /* 0 ~ 1 */
+	u_int32 uLastChunk; /* 0 ~ 1 */
+	u_int32 uChunkRows; /* 0 ~ 255 */
+	u_int32 uNumBytes;
+	u_int32 uJpgCropXStart;
+	u_int32 uJpgCropYStart;
+	u_int32 uJpgCropWidth;
+	u_int32 uJpgCropHeight;
+	u_int32 uJpgMjpegMode;
+	u_int32 uJpgMjpegInterlaced;
+
+} MediaIPFW_Video_JpegParams;
+
+typedef struct {
+	u_int32                     pJpegParamArrayBase;
+	u_int32                    uNumSizeDescriptors;
+
+} MediaIPFW_Video_JpegParamTabDesc;
+
+typedef struct {
+	u_int32 uDispImm;
+	u_int32 uFourCC;
+	u_int32 uCodecVersion;
+	u_int32 uFrameRate;
+	u_int32 uEnableDbgLog;
+	u_int32 uBSDMALWM;
+	u_int32 bbd_coring;
+	u_int32 bbd_s_thr_row;
+	u_int32 bbd_p_thr_row;
+	u_int32 bbd_s_thr_logo_row;
+	u_int32 bbd_p_thr_logo_row;
+	u_int32 bbd_s_thr_col;
+	u_int32 bbd_p_thr_col;
+	u_int32 bbd_chr_thr_row;
+	u_int32 bbd_chr_thr_col;
+	u_int32 bbd_uv_mid_level;
+	u_int32 bbd_excl_win_mb_left;
+	u_int32 bbd_excl_win_mb_right;
+
+} MediaIPFW_Video_CodecParams;
+
+typedef struct {
+	u_int32 uFramePitch;
+
+} MediaIPFW_Video_PitchInfo;
+
+typedef struct {
+	u_int32	uWrPtr;
+	u_int32	uRdPtr;
+	u_int32	uStart;
+	u_int32	uEnd;
+	u_int32	uLo;
+	u_int32	uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+	u_int32                      pCodecParamArrayBase;
+	u_int32                      uNumSizeDescriptors;
+
+} MediaIPFW_Video_CodecParamTabDesc;
+
+typedef struct {
+	u_int32 uRC4Key[0x8];
+	u_int32 uMemObfuscVal;
+
+} MediaIPFW_Video_Encrypt_Info, *pMediaIPFW_Video_Encrypt_Info;
+
+typedef struct {
+	u_int32 uCfgCookie;
+
+	u_int32 uNumMalones;
+	u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+	u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+	u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+	u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+	u_int32 uNumWindsors;
+	u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+	u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+	u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+	u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+	u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+	u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+	u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+	u_int32 uSysClkFreq;
+	u_int32 uNumTimers;
+	u_int32 uTimerBaseAddr;
+	u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+	u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+	u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+	u_int32 uGICBaseAddr;
+	u_int32 uUartBaseAddr;
+
+	u_int32 uDPVBaseAddr;
+	u_int32 uDPVIrqPin;
+	u_int32 uDPVIrqTarget;
+
+	u_int32 uPixIfBaseAddr;
+
+	u_int32 pal_trace_level;
+	u_int32 pal_trace_destination;
+
+	u_int32 pal_trace_level1;
+	u_int32 pal_trace_destination1;
+
+	u_int32 uHeapBase;
+	u_int32 uHeapSize;
+
+	u_int32 uFSLCacheBaseAddr[2];
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+	u_int32                                FwExecBaseAddr;
+	u_int32                                FwExecAreaSize;
+	MediaIPFW_Video_BufDesc                StreamCmdBufferDesc;
+	MediaIPFW_Video_BufDesc                StreamMsgBufferDesc;
+	u_int32                                StreamCmdIntEnable[VID_API_NUM_STREAMS];
+	MediaIPFW_Video_PitchInfo              StreamPitchInfo[VID_API_NUM_STREAMS];
+	u_int32                                StreamConfig[VID_API_NUM_STREAMS];
+	MediaIPFW_Video_CodecParamTabDesc	   CodecParamTabDesc;                       /* TODO-KMC  should we just go ahead and remove the concept of tabdesc? It is basicaly a bad coding style used for pinkys anyway */
+	MediaIPFW_Video_JpegParamTabDesc       JpegParamTabDesc;
+	u_int32                                pStreamBuffDesc[VID_API_NUM_STREAMS][VID_API_MAX_BUF_PER_STR];
+	MediaIPFW_Video_SeqInfoBuffTabDesc     SeqInfoTabDesc;
+	MediaIPFW_Video_PicInfoBuffTabDesc     PicInfoTabDesc;
+	MediaIPFW_Video_GopInfoBuffTabDesc     GopInfoTabDesc;
+	MediaIPFW_Video_QMeterInfoTabDesc      QMeterInfoTabDesc;
+	u_int32                                StreamError[VID_API_NUM_STREAMS];
+	u_int32                                FWVersion;
+	u_int32                                uFWOffset;
+	u_int32                                uMaxDecoderStreams;
+	MediaIPFW_Video_DbgLogDesc             DbgLogDesc;
+	union {
+		struct {
+			MediaIPFW_Video_FrameBuffer StreamFrameBuffer[VID_API_NUM_STREAMS];
+			MediaIPFW_Video_FrameBuffer StreamDCPBuffer[VID_API_NUM_STREAMS];
+		};
+		BUFFER_DESCRIPTOR_TYPE         StreamApiCmdBufferDesc[VID_API_NUM_STREAMS];
+	};
+	MediaIPFW_Video_UData                  UDataBuffer[VID_API_NUM_STREAMS];
+	MediaIPFW_Video_BufDesc                DebugBufferDesc;
+	MediaIPFW_Video_BufDesc                EngAccessBufferDesc[VID_API_NUM_STREAMS];
+	u_int32                                ptEncryptInfo[VID_API_NUM_STREAMS];
+	MEDIAIP_FW_SYSTEM_CONFIG               sSystemCfg;
+	u_int32                                uApiVersion;
+	BUFFER_INFO_TYPE                       StreamBuffInfo[VID_API_NUM_STREAMS];
+} DEC_RPC_HOST_IFACE, *pDEC_RPC_HOST_IFACE;
+
+//x means source data , y means destination data
+#define VID_STREAM_CONFIG_FORMAT_MASK            0x0000000F
+#define VID_STREAM_CONFIG_FORMAT_POS             0
+#define VID_STREAM_CONFIG_FORMAT_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_FORMAT_POS)&VID_STREAM_CONFIG_FORMAT_MASK)))
+
+#define VID_STREAM_CONFIG_STRBUFIDX_MASK         0x00000300
+#define VID_STREAM_CONFIG_STRBUFIDX_POS          8
+#define VID_STREAM_CONFIG_STRBUFIDX_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_STRBUFIDX_POS)&VID_STREAM_CONFIG_STRBUFIDX_MASK)))
+
+#define VID_STREAM_CONFIG_NOSEQ_MASK             0x00000400
+#define VID_STREAM_CONFIG_NOSEQ_POS              10
+#define VID_STREAM_CONFIG_NOSEQ_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_NOSEQ_POS)&VID_STREAM_CONFIG_NOSEQ_MASK)))
+
+#define VID_STREAM_CONFIG_DEBLOCK_MASK           0x00000800
+#define VID_STREAM_CONFIG_DEBLOCK_POS            11
+#define VID_STREAM_CONFIG_DEBLOCK_SET(x, y)         (*y = (*y | ((x << VID_STREAM_CONFIG_DEBLOCK_POS)&VID_STREAM_CONFIG_DEBLOCK_MASK)))
+
+#define VID_STREAM_CONFIG_DERING_MASK            0x00001000
+#define VID_STREAM_CONFIG_DERING_POS             12
+#define VID_STREAM_CONFIG_DERING_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_DERING_POS)&VID_STREAM_CONFIG_DERING_MASK)))
+
+#define VID_STREAM_CONFIG_IBWAIT_MASK            0x00002000
+#define VID_STREAM_CONFIG_IBWAIT_POS             13
+#define VID_STREAM_CONFIG_IBWAIT_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_IBWAIT_POS)&VID_STREAM_CONFIG_IBWAIT_MASK)))
+
+#define VID_STREAM_CONFIG_FBC_MASK               0x00004000
+#define VID_STREAM_CONFIG_FBC_POS                14
+#define VID_STREAM_CONFIG_FBC_SET(x, y)             (*y = (*y | ((x << VID_STREAM_CONFIG_FBC_POS)&VID_STREAM_CONFIG_FBC_MASK)))
+
+#define VID_STREAM_CONFIG_PLAY_MODE_MASK         0x00030000
+#define VID_STREAM_CONFIG_PLAY_MODE_POS          16
+#define VID_STREAM_CONFIG_PLAY_MODE_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_PLAY_MODE_POS)&VID_STREAM_CONFIG_PLAY_MODE_MASK)))
+
+#define VID_STREAM_CONFIG_ENABLE_DCP_MASK      0x00100000
+#define VID_STREAM_CONFIG_ENABLE_DCP_POS       20
+#define VID_STREAM_CONFIG_ENABLE_DCP_SET(x, y)    (*y = (*y | ((x << VID_STREAM_CONFIG_ENABLE_DCP_POS)&VID_STREAM_CONFIG_ENABLE_DCP_MASK)))
+
+#define VID_STREAM_CONFIG_NUM_STR_BUF_MASK       0x00600000
+#define VID_STREAM_CONFIG_NUM_STR_BUF_POS        21
+#define VID_STREAM_CONFIG_NUM_STR_BUF_SET(x, y)     (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_STR_BUF_POS)&VID_STREAM_CONFIG_NUM_STR_BUF_MASK)))
+
+#define VID_STREAM_CONFIG_MALONE_USAGE_MASK      0x01800000
+#define VID_STREAM_CONFIG_MALONE_USAGE_POS       23
+#define VID_STREAM_CONFIG_MALONE_USAGE_SET(x, y)    (*y = (*y | ((x << VID_STREAM_CONFIG_MALONE_USAGE_POS)&VID_STREAM_CONFIG_MALONE_USAGE_MASK)))
+
+#define VID_STREAM_CONFIG_MULTI_VID_MASK         0x02000000
+#define VID_STREAM_CONFIG_MULTI_VID_POS          25
+#define VID_STREAM_CONFIG_MULTI_VID_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_MULTI_VID_POS)&VID_STREAM_CONFIG_MULTI_VID_MASK)))
+
+#define VID_STREAM_CONFIG_OBFUSC_EN_MASK         0x04000000
+#define VID_STREAM_CONFIG_OBFUSC_EN_POS          26
+#define VID_STREAM_CONFIG_OBFUSC_EN_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_OBFUSC_EN_POS)&VID_STREAM_CONFIG_OBFUSC_EN_MASK)))
+
+#define VID_STREAM_CONFIG_RC4_EN_MASK            0x08000000
+#define VID_STREAM_CONFIG_RC4_EN_POS             27
+#define VID_STREAM_CONFIG_RC4_EN_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_RC4_EN_POS)&VID_STREAM_CONFIG_RC4_EN_MASK)))
+
+#define VID_STREAM_CONFIG_MCX_MASK               0x10000000
+#define VID_STREAM_CONFIG_MCX_POS                28
+#define VID_STREAM_CONFIG_MCX_SET(x, y)             (*y = (*y | ((x << VID_STREAM_CONFIG_MCX_POS)&VID_STREAM_CONFIG_MCX_MASK)))
+
+#define VID_STREAM_CONFIG_PES_MASK               0x20000000
+#define VID_STREAM_CONFIG_PES_POS                29
+#define VID_STREAM_CONFIG_PES_SET(x, y)             ((*y = (*y | ((x << VID_STREAM_CONFIG_PES_POS)&VID_STREAM_CONFIG_PES_MASK))))
+
+#define VID_STREAM_CONFIG_NUM_DBE_MASK           0x40000000
+#define VID_STREAM_CONFIG_NUM_DBE_POS            30
+#define VID_STREAM_CONFIG_NUM_DBE_SET(x, y)         (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_DBE_POS)&VID_STREAM_CONFIG_NUM_DBE_MASK)))
+
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_MASK   0x80000000
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_POS    31
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_FS_CTRL_MODE_POS)&VID_STREAM_CONFIG_FS_CTRL_MODE_MASK)))
+
+#define SCB_XREG_SLV_BASE                               0x00000000
+#define SCB_SCB_BLK_CTRL                                0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET                     0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET                    0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR                    0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET                 0x00000100
+
+#define XMEM_CONTROL                                    0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE                           0x00180000
+
+#define MFD_HIF                                         0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS                0x00000018
+#define MFD_SIF                                         0x0001D000
+#define MFD_SIF_CTRL_STATUS                             0x000000F0
+#define MFD_SIF_INTR_STATUS                             0x000000F4
+#define MFD_MCX                                         0x00020800
+#define MFD_MCX_OFF                                     0x00000020
+
+#define MFD_BLK_CTRL                                    0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET                  0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR                  0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET           0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR           0x00000104
+
+#define CSR_CM0Px_ADDR_OFFSET				0x00000000
+#define CSR_CM0Px_CPUWAIT				0x00000004
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_b0.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_b0.c
@@ -0,0 +1,6849 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu-b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "vpu_b0.h"
+#include "insert_startcode.h"
+#include "vpu_debug_log.h"
+#include "vpu_pm.h"
+#include "vpu_mu.h"
+
+#ifndef TSM_TIMESTAMP_NONE
+#define TSM_TIMESTAMP_NONE	-1L
+#endif
+#ifndef TSM_TS_IS_VALID
+#define TSM_TS_IS_VALID(ts)	((ts) >= 0)
+#endif
+
+unsigned int vpu_dbg_level_decoder = LVL_WARN;
+static int vpu_frm_depth = VPU_FRAME_DEPTH_DEFAULT;
+static int vpu_log_depth = DEFAULT_LOG_DEPTH;
+static int vpu_max_bufsize = MAX_BUFFER_SIZE;
+static int vpu_frmdbg_ena = DEFAULT_FRMDBG_ENABLE;
+static int vpu_frmdbg_level = DEFAULT_FRMDBG_LEVEL;
+static int vpu_frmdbg_raw = 1;
+static int vpu_dbe_num = 1;
+static int vpu_frmcrcdump_ena;
+static int stream_buffer_threshold = 0x10000;
+static int precheck_show_bytes;
+static int vpu_show_perf_ena;
+static int vpu_show_perf_idx = (1 << VPU_MAX_NUM_STREAMS) - 1;
+static int vpu_show_perf_ent;
+static int vpu_datadump_ena;
+static unsigned short frame_threshold[VPU_MAX_NUM_STREAMS];
+module_param_array(frame_threshold, ushort, NULL, 0644);
+
+/* Generic End of content startcodes to differentiate from those naturally in the stream/file */
+#define EOS_GENERIC_HEVC 0x7c010000
+#define EOS_GENERIC_JPEG 0xefff0000
+#define EOS_GENERIC_MPEG 0xCC010000
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data);
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata);
+static int add_scode(struct vpu_ctx *ctx, u_int32 uStrBufIdx, VPU_PADDING_SCODE_TYPE eScodeType, bool bUpdateWr);
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx);
+static int swreset_vpu_firmware(struct vpu_dev *dev, u_int32 idx);
+static int find_first_available_instance(struct vpu_dev *dev);
+static int remove_instance_file(struct vpu_ctx *ctx);
+static void fill_stream_buffer_info(struct vpu_ctx *ctx);
+static void set_pic_end_flag(struct vpu_ctx *ctx);
+static void send_skip_event(struct vpu_ctx* ctx);
+static void reset_mbi_dcp_count(struct vpu_ctx *ctx);
+static bool verify_frame_buffer_size(struct queue_data *q_data,
+							struct vb2_data_req *p_data_req);
+static void add_buffer_to_queue(struct queue_data *q_data, struct vb2_data_req *data_req);
+static int send_abort_cmd(struct vpu_ctx *ctx);
+static int send_stop_cmd(struct vpu_ctx *ctx);
+static int vpu_dec_cmd_reset(struct vpu_ctx *ctx);
+static void vpu_dec_event_decode_error(struct vpu_ctx *ctx);
+static void vpu_calculate_performance(struct vpu_ctx *ctx, u_int32 uEvent, const char *str);
+static void vpu_dec_cancel_work(struct vpu_dev *vpudev);
+static void vpu_dec_alloc_mbi_dcp(struct vpu_ctx *ctx);
+static bool is_vpu_poweroff(struct vpu_dev *vpudev);
+
+#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
+
+static char *cmd2str[] = {
+	"VID_API_CMD_NULL",   /*0x0*/
+	"VID_API_CMD_PARSE_NEXT_SEQ", /*0x1*/
+	"VID_API_CMD_PARSE_NEXT_I",
+	"VID_API_CMD_PARSE_NEXT_IP",
+	"VID_API_CMD_PARSE_NEXT_ANY",
+	"VID_API_CMD_DEC_PIC",
+	"VID_API_CMD_UPDATE_ES_WR_PTR",
+	"VID_API_CMD_UPDATE_ES_RD_PTR",
+	"VID_API_CMD_UPDATE_UDATA",
+	"VID_API_CMD_GET_FSINFO",
+	"VID_API_CMD_SKIP_PIC",
+	"VID_API_CMD_DEC_CHUNK",  /*0x0b*/
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_START",         /*0x10*/
+	"VID_API_CMD_STOP",
+	"VID_API_CMD_ABORT",
+	"VID_API_CMD_RST_BUF",
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_FS_RELEASE",
+	"VID_API_CMD_MEM_REGION_ATTACH",
+	"VID_API_CMD_MEM_REGION_DETACH",
+	"VID_API_CMD_MVC_VIEW_SELECT",
+	"VID_API_CMD_FS_ALLOC",   /*0x19*/
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_UNDEFINED",
+	"VID_API_CMD_DBG_GET_STATUS", /*0x1C*/
+	"VID_API_CMD_DBG_START_LOG",
+	"VID_API_CMD_DBG_STOP_LOG",
+	"VID_API_CMD_DBG_DUMP_LOG",
+	"VID_API_CMD_YUV_READY",   /*0x20*/
+	"VID_API_CMD_TS",
+};
+
+static char *event2str[] = {
+	"VID_API_EVENT_NULL",  /*0x0*/
+	"VID_API_EVENT_RESET_DONE",  /*0x1*/
+	"VID_API_EVENT_SEQ_HDR_FOUND",
+	"VID_API_EVENT_PIC_HDR_FOUND",
+	"VID_API_EVENT_PIC_DECODED",
+	"VID_API_EVENT_FIFO_LOW",
+	"VID_API_EVENT_FIFO_HIGH",
+	"VID_API_EVENT_FIFO_EMPTY",
+	"VID_API_EVENT_FIFO_FULL",
+	"VID_API_EVENT_BS_ERROR",
+	"VID_API_EVENT_UDATA_FIFO_UPTD",
+	"VID_API_EVENT_RES_CHANGE",
+	"VID_API_EVENT_FIFO_OVF",
+	"VID_API_EVENT_CHUNK_DECODED",  /*0x0D*/
+	"VID_API_EVENT_UNDEFINED",
+	"VID_API_EVENT_UNDEFINED",
+	"VID_API_EVENT_REQ_FRAME_BUFF",  /*0x10*/
+	"VID_API_EVENT_FRAME_BUFF_RDY",
+	"VID_API_EVENT_REL_FRAME_BUFF",
+	"VID_API_EVENT_STR_BUF_RST",
+	"VID_API_EVENT_RET_PING",
+	"VID_API_EVENT_QMETER",
+	"VID_API_EVENT_STR_FMT_CHANGED",
+	"VID_API_EVENT_FIRMWARE_XCPT",
+	"VID_API_EVENT_START_DONE",
+	"VID_API_EVENT_STOPPED",
+	"VID_API_EVENT_ABORT_DONE",
+	"VID_API_EVENT_FINISHED",
+	"VID_API_EVENT_DBG_STAT_UPDATE",
+	"VID_API_EVENT_DBG_LOG_STARTED",
+	"VID_API_EVENT_DBG_LOG_STOPPED",
+	"VID_API_EVENT_DBG_LOG_UPFATED",
+	"VID_API_EVENT_DBG_MSG_DEC",  /*0x20*/
+	"VID_API_EVENT_DEC_SC_ERR",
+	"VID_API_EVENT_CQ_FIFO_DUMP",
+	"VID_API_EVENT_DBG_FIFO_DUMP",
+	"VID_API_EVENT_DEC_CHECK_RES",
+	"VID_API_EVENT_DEC_CFG_INFO",  /*0x25*/
+};
+
+static char *bufstat[] = {
+	"FRAME_ALLOC",
+	"FRAME_FREE",
+	"FRAME_DECODED",
+	"FRAME_READY",
+	"FRAME_RELEASE",
+	"FRAME_SKIP",
+};
+
+static int alloc_vpu_buffer(struct vpu_ctx *ctx);
+static bool vpu_dec_is_active(struct vpu_ctx *ctx);
+static void respond_req_frame(struct vpu_ctx *ctx,
+				struct queue_data *queue,
+				bool abnormal);
+static void release_frame_buffer(struct vpu_ctx *ctx,
+				u32 uStrIdx,
+				struct vb2_data_req *p_data_req);
+static void send_eos_event(struct vpu_ctx *ctx);
+static void release_queue_data(struct vpu_ctx *ctx);
+
+static char *get_event_str(u32 event)
+{
+	if (event == VID_API_EVENT_SNAPSHOT_DONE)
+		return "VID_API_EVENT_SNAPSHOT_DONE";
+	else if (event >= ARRAY_SIZE(event2str))
+		return "UNKNOWN EVENT";
+	return event2str[event];
+}
+
+static char *get_cmd_str(u32 cmdid)
+{
+	if (cmdid == VID_API_CMD_FIRM_RESET)
+		return "VID_API_CMD_FIRM_RESET";
+	else if (cmdid == VID_API_CMD_SNAPSHOT)
+		return "VID_API_CMD_SNAPSHOT";
+	else if (cmdid >= ARRAY_SIZE(cmd2str))
+		return "UNKNOWN CMD";
+	return cmd2str[cmdid];
+}
+
+static void vpu_log_event(u_int32 uEvent, u_int32 ctxid)
+{
+	if (uEvent > ARRAY_SIZE(event2str)-1)
+		vpu_dbg(LVL_BIT_EVT, "reveive event: 0x%X, ctx id:%d\n",
+				uEvent, ctxid);
+	else
+		vpu_dbg(LVL_BIT_EVT, "recevie event: %s, ctx id:%d\n",
+				event2str[uEvent], ctxid);
+}
+
+static void vpu_log_cmd(u_int32 cmdid, u_int32 ctxid)
+{
+	if (cmdid > ARRAY_SIZE(cmd2str)-1)
+		vpu_dbg(LVL_BIT_CMD, "send cmd: 0x%X, ctx id:%d\n",
+				cmdid, ctxid);
+	else
+		vpu_dbg(LVL_BIT_CMD, "send cmd: %s ctx id:%d\n",
+				cmd2str[cmdid], ctxid);
+}
+
+static void vpu_log_buffer_state(struct vpu_ctx *ctx)
+{
+	struct vb2_data_req *p_data_req;
+	struct queue_data *This;
+	int i;
+
+	if (!ctx)
+		return;
+
+	This = &ctx->q_data[V4L2_DST];
+	down(&This->drv_q_lock);
+	for (i = 0; i < VPU_MAX_BUFFER; i++) {
+		p_data_req = &This->vb2_reqs[i];
+		if (p_data_req->vb2_buf != NULL)
+			vpu_dbg(LVL_BIT_BUFFER_STAT,
+				"ctx: %d, buffer[%d] status: %s\n",
+				ctx->str_index, i, bufstat[p_data_req->status]);
+	}
+	up(&This->drv_q_lock);
+}
+
+static void count_event(struct vpu_statistic *statistic, u32 event)
+{
+	if (!statistic)
+		return;
+
+	if (event < ARRAY_SIZE(event2str))
+		statistic->event[event]++;
+	else
+		statistic->event[VID_API_EVENT_DEC_CFG_INFO + 1]++;
+
+	statistic->current_event = event;
+	ktime_get_raw_ts64(&statistic->ts_event);
+}
+
+static void count_cmd(struct vpu_statistic *statistic, u32 cmdid)
+{
+	if (!statistic)
+		return;
+
+	if (cmdid < ARRAY_SIZE(cmd2str))
+		statistic->cmd[cmdid]++;
+	else
+		statistic->cmd[VID_API_CMD_TS + 1]++;
+	statistic->current_cmd = cmdid;
+	ktime_get_raw_ts64(&statistic->ts_cmd);
+}
+
+static u32 get_greatest_common_divisor(u32 a, u32 b)
+{
+	u32 tmp;
+
+	if (!a)
+		return b;
+
+	while (b) {
+		tmp = a % b;
+		a = b;
+		b = tmp;
+	}
+
+	return a;
+}
+
+static void get_kmp_next(const u8 *p, int *next, int size)
+{
+	int k = -1;
+	int j = 0;
+
+	next[0] = -1;
+	while (j < size - 1) {
+		if (k == -1 || p[j] == p[k]) {
+			++k;
+			++j;
+			next[j] = k;
+		} else {
+			k = next[k];
+		}
+	}
+}
+
+static int kmp_search(u8 *s, int s_len, const u8 *p, int p_len, int *next)
+{
+	int i = 0;
+	int j = 0;
+
+	while (i < s_len && j < p_len) {
+		if (j == -1 || s[i] == p[j]) {
+			i++;
+			j++;
+		} else {
+			j = next[j];
+		}
+	}
+	if (j == p_len)
+		return i - j;
+	else
+		return -1;
+}
+
+static void find_pattern_from_vb(struct vpu_dev *dev, unsigned long index,
+				struct vb2_buffer *vb, unsigned int plane_no)
+{
+	u8 *ptr = NULL;
+	int ret;
+
+	if (!dev || !dev->precheck_num)
+		return;
+
+	if (!vb || plane_no >= vb->num_planes)
+		return;
+
+	ptr = vb2_plane_vaddr(vb, plane_no);
+	if (!ptr)
+		return;
+
+	ret = kmp_search(ptr,
+			vb->planes[plane_no].bytesused,
+			dev->precheck_pattern,
+			dev->precheck_num,
+			dev->precheck_next);
+	if (ret < 0)
+		return;
+	vpu_dbg(LVL_WARN, "[%12ld]pattern(%s) found : %d\n",
+			index,
+			dev->precheck_content,
+			ret);
+}
+
+static void show_beginning_of_data(unsigned long index,
+				struct vb2_buffer *vb, unsigned int plane_no)
+{
+	u8 *pdata;
+	u32 length;
+	u32 bytes = 0;
+	u32 show_count;
+	char temp[1028];
+	int i;
+	int ret;
+
+	if (!precheck_show_bytes)
+		return;
+
+	if (!vb || plane_no >= vb->num_planes)
+		return;
+
+	pdata = vb2_plane_vaddr(vb, plane_no);
+	length = vb->planes[plane_no].bytesused;
+	if (!pdata || !length)
+		return;
+	show_count = min_t(u32, precheck_show_bytes, length);
+	for (i = 0; i < show_count; i++) {
+		ret = scnprintf(temp + bytes,
+				sizeof(temp) - bytes,
+				"%s0x%02x",
+				i ? " " : "",
+				pdata[i]);
+		if (ret == 0)
+			break;
+		bytes += ret;
+		if (bytes >= sizeof(temp))
+			break;
+	}
+	vpu_dbg(LVL_WARN, "[%12ld][%12d/%12d]%s\n", index, i, length, temp);
+}
+
+static void precheck_vb_data(struct vpu_ctx *ctx, struct vb2_buffer *vb)
+{
+	unsigned long index;
+
+	if (!ctx || !vb)
+		return;
+
+	index = ctx->q_data[V4L2_SRC].qbuf_count;
+	show_beginning_of_data(index, vb, 0);
+	find_pattern_from_vb(ctx->dev, index, vb, 0);
+}
+
+static bool check_vb_is_changed(struct vb2_data_req *p_data_req, u32 pattern)
+{
+	u32 luma_addr;
+	u32 *pphy_address;
+
+	pphy_address = vb2_plane_cookie(p_data_req->vb2_buf, 0);
+	luma_addr = *pphy_address + p_data_req->data_offset[0];
+	if (luma_addr != pattern)
+		return true;
+
+	return false;
+}
+
+static int find_buffer_id(struct vpu_ctx *ctx, u_int32 addr)
+{
+	struct queue_data *This;
+	struct vb2_data_req *p_data_req;
+	u_int32 LumaAddr;
+	u_int32 i;
+
+	if (!ctx)
+		return -1;
+
+	This = &ctx->q_data[V4L2_DST];
+	down(&This->drv_q_lock);
+	for (i = 0; i < VPU_MAX_BUFFER; i++) {
+		p_data_req = &This->vb2_reqs[i];
+
+		if (!p_data_req->vb2_buf)
+			continue;
+
+		LumaAddr = p_data_req->phy_addr[0] + p_data_req->data_offset[0];
+		if (LumaAddr == addr) {
+			if (check_vb_is_changed(p_data_req, LumaAddr))
+				vpu_err("ctx[%d] frame buffer[%d] is changed\n",
+					ctx->str_index, i);
+			break;
+		}
+	}
+	up(&This->drv_q_lock);
+	if (i == VPU_MAX_BUFFER) {
+		vpu_err("error: ctx[%d] can't find id based on address(0x%x)\n",
+			ctx->str_index, addr);
+		return -1;
+	}
+	return i;
+}
+
+static u32 get_str_buffer_desc_offset(struct vpu_ctx *ctx)
+{
+	return DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+}
+
+pSTREAM_BUFFER_DESCRIPTOR_TYPE get_str_buffer_desc(struct vpu_ctx *ctx)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+
+	WARN_ON(!ctx || !ctx->dev);
+	pStrBufDesc = ctx->dev->regs_base + get_str_buffer_desc_offset(ctx);
+	return pStrBufDesc;
+}
+
+static void set_data_req_status(struct vb2_data_req *p_data_req,
+				FRAME_BUFFER_STAT status)
+{
+	vpu_dbg(LVL_BIT_BUFFER_STAT, "Buffer Status [%2d] : %s -> %s\n",
+			p_data_req->id,
+			bufstat[p_data_req->status],
+			bufstat[status]);
+	p_data_req->status = status;
+}
+
+static u32 vpu_dec_cpu_phy_to_mu(struct vpu_dev *dev, u32 addr)
+{
+	return addr - dev->m0_p_fw_space_phy;
+}
+
+#ifdef DEBUG
+static void vpu_log_shared_mem(struct vpu_ctx *ctx)
+{
+	struct vpu_dev *dev = ctx->dev;
+	struct shared_addr *This = &dev->shared_mem;
+	pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+	MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	u_int32 index = ctx->str_index;
+
+	vpu_dbg(LVL_INFO, "msg: wr: 0x%x, rd: 0x%x, cmd: wr : 0x%x, rd: 0x%x\n",
+			pMsgDesc->uWrPtr, pMsgDesc->uRdPtr, pCmdDesc->uWrPtr, pCmdDesc->uRdPtr);
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	vpu_dbg(LVL_INFO, "data: wptr(0x%x) rptr(0x%x) start(0x%x) end(0x%x) uStrIdx(%d)\n",
+			pStrBufDesc->wptr, pStrBufDesc->rptr, pStrBufDesc->start, pStrBufDesc->end, index);
+}
+#endif
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt  formats_compressed_dec[] = {
+	{
+		.name       = "H264 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_AVC,
+		.disable    = 0,
+	},
+	{
+		.name       = "VC1 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_VC1_ANNEX_G,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_VC1,
+		.disable    = 0,
+	},
+	{
+		.name       = "VC1 RCV Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_VC1_ANNEX_L,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_VC1,
+		.disable    = 0,
+	},
+	{
+		.name       = "MPEG2 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_MPEG2,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_MPEG2,
+		.disable    = 0,
+	},
+
+	{
+		.name       = "AVS Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_AVS,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_AVS,
+		.disable    = 0,
+	},
+	{
+		.name       = "MPEG4 ASP Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_ASP,
+		.disable    = 0,
+	},
+	{
+		.name       = "DIVX Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_DIV3,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_ASP,
+		.disable    = 0,
+	},
+	{
+		.name       = "DIVX Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_DIVX,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_ASP,
+		.disable    = 0,
+	},
+	{
+		.name       = "JPEG stills",
+		.fourcc     = V4L2_PIX_FMT_JPEG,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_JPEG,
+		.disable    = 0,
+	},
+	{
+		.name       = "RV Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_RV,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_RV,
+		.disable    = 0,
+	},
+	{
+		.name       = "VP6 Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_VP6,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_VP6,
+		.disable    = 0,
+	},
+	{
+		.name       = "SPK Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_SPK,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_SPK,
+		.disable    = 0,
+	},
+	{
+		.name       = "H263 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_ASP,
+		.disable    = 0,
+	},
+	{
+		.name       = "VP8 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_VP8,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_VP8,
+		.disable    = 0,
+	},
+	{
+		.name       = "H264/MVC Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_H264_MVC,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_AVC_MVC,
+		.disable    = 0,
+	},
+	{
+		.name       = "H265 HEVC Encoded Stream",
+		.fourcc     = VPU_PIX_FMT_HEVC,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_HEVC,
+		.disable    = 0,
+	},
+	{
+		.name       = "Xvid Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_XVID,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_ASP,
+		.disable    = 0,
+	},
+	{
+		.name       = "Logo",
+		.fourcc     = VPU_PIX_FMT_LOGO,
+		.num_planes = 1,
+		.vdec_std   = VPU_VIDEO_UNDEFINED,
+		.disable    = 0,
+	},
+};
+
+static struct vpu_v4l2_fmt  formats_yuv_dec[] = {
+	{
+		.name       = "4:2:0 2 Planes Y/CbCr",
+		.fourcc     = V4L2_PIX_FMT_NV12,
+		.num_planes	= 2,
+		.vdec_std   = VPU_PF_YUV420_SEMIPLANAR,
+		.disable    = 0,
+	},
+	{
+		.name       = "4:2:0 2 Planes Y/CbCr",
+		.fourcc     = V4L2_PIX_FMT_NV12_10BIT,
+		.num_planes = 2,
+		.vdec_std   = VPU_PF_YUV420_SEMIPLANAR,
+		.disable    = 0,
+	},
+};
+
+static int v4l2_ioctl_querycap(struct file *file,
+		void *fh,
+		struct v4l2_capability *cap
+		)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+	strlcpy(cap->driver, "vpu B0", sizeof(cap->driver));
+	strlcpy(cap->card, "vpu B0", sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_cap(struct file *file,
+		void *fh,
+		struct v4l2_fmtdesc *f
+		)
+{
+	struct vpu_v4l2_fmt *fmt;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	if (f->index >= ARRAY_SIZE(formats_yuv_dec))
+		return -EINVAL;
+
+	fmt = &formats_yuv_dec[f->index];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	vpu_dbg(LVL_INFO, "CAPTURE fmt[%d] %c%c%c%c\n",
+			f->index,
+			f->pixelformat & 0xff,
+			(f->pixelformat >> 8) & 0xff,
+			(f->pixelformat >> 16) & 0xff,
+			(f->pixelformat >> 24) & 0xff);
+	return 0;
+}
+
+static bool check_fmt_is_support(struct vpu_ctx *ctx, struct vpu_v4l2_fmt *fmt)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	bool support;
+
+	if (!ctx || !ctx->dev || !fmt)
+		return false;
+
+	if (fmt->disable)
+		return false;
+
+	pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	support = true;
+
+	switch (fmt->fourcc) {
+	case VPU_PIX_FMT_DIV3:
+	case VPU_PIX_FMT_DIVX:
+		if (!(pSharedInterface->FWVersion & VPU_DEC_FMT_DIVX_MASK))
+			support = false;
+		break;
+	case VPU_PIX_FMT_RV:
+		if (!(pSharedInterface->FWVersion & VPU_DEC_FMT_RV_MASK))
+			support = false;
+		break;
+	default:
+		break;
+	}
+
+	return support;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_out(struct file *file,
+		void *fh,
+		struct v4l2_fmtdesc *f
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_v4l2_fmt *fmt;
+	u_int32 index = 0, i;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	if (f->index >= ARRAY_SIZE(formats_compressed_dec))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(formats_compressed_dec); i++) {
+		fmt = &formats_compressed_dec[i];
+		if (!check_fmt_is_support(ctx, fmt))
+			continue;
+		if (f->index == index)
+			break;
+		index++;
+	}
+
+	if (i == ARRAY_SIZE(formats_compressed_dec))
+		return -EINVAL;
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+	vpu_dbg(LVL_INFO, "OUTPUT fmt[%d] %c%c%c%c\n",
+			f->index,
+			f->pixelformat & 0xff,
+			(f->pixelformat >> 8) & 0xff,
+			(f->pixelformat >> 16) & 0xff,
+			(f->pixelformat >> 24) & 0xff);
+
+	return 0;
+}
+
+static bool is_10bit_format(struct vpu_ctx *ctx)
+{
+	WARN_ON(!ctx);
+	if (ctx->seqinfo.uBitDepthLuma > 8)
+		return true;
+	if (ctx->seqinfo.uBitDepthChroma > 8)
+		return true;
+	return false;
+}
+
+static void calculate_frame_size(struct vpu_ctx *ctx)
+{
+	u_int32 width = ctx->seqinfo.uHorDecodeRes;
+	u_int32 height = ctx->seqinfo.uVerDecodeRes;
+	u_int32 luma_size;
+	u_int32 chroma_size;
+	u_int32 chroma_height;
+	bool b10BitFormat = is_10bit_format(ctx);
+	struct queue_data *q_data;
+
+	q_data = &ctx->q_data[V4L2_DST];
+
+	width = b10BitFormat?(width + ((width + 3) >> 2)):width;
+	width = ALIGN(width, V4L2_NXP_FRAME_HORIZONTAL_ALIGN);
+	q_data->stride = width;
+
+	height = ALIGN(height, V4L2_NXP_FRAME_VERTICAL_ALIGN);
+	chroma_height = height >> 1;
+
+	luma_size = width * height;
+	chroma_size = width * chroma_height;
+
+	q_data->width = ctx->seqinfo.uHorRes;
+	q_data->height = ctx->seqinfo.uVerRes;
+	q_data->sizeimage[0] = luma_size;
+	q_data->sizeimage[1] = chroma_size;
+	if (ctx->seqinfo.uProgressive == 1)
+		q_data->field = V4L2_FIELD_NONE;
+	else
+		q_data->field = V4L2_FIELD_INTERLACED;
+}
+
+static const u8 colorprimaries[] = {
+	0,
+	V4L2_COLORSPACE_REC709,        /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_COLORSPACE_470_SYSTEM_M, /*Rec. ITU-R BT.470-6 System M*/
+	V4L2_COLORSPACE_470_SYSTEM_BG,/*Rec. ITU-R BT.470-6 System B, G*/
+	V4L2_COLORSPACE_SMPTE170M,    /*SMPTE170M*/
+	V4L2_COLORSPACE_SMPTE240M,    /*SMPTE240M*/
+	V4L2_COLORSPACE_GENERIC_FILM, /*Generic film*/
+	V4L2_COLORSPACE_BT2020,       /*Rec. ITU-R BT.2020-2*/
+	V4L2_COLORSPACE_ST428         /*SMPTE ST 428-1*/
+};
+
+static const u8 colortransfers[] = {
+	0,
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_XFER_FUNC_GAMMA22,  /*Rec. ITU-R BT.470-6 System M*/
+	V4L2_XFER_FUNC_GAMMA28,  /*Rec. ITU-R BT.470-6 System B, G*/
+	V4L2_XFER_FUNC_709,      /*SMPTE170M*/
+	V4L2_XFER_FUNC_SMPTE240M,/*SMPTE240M*/
+	V4L2_XFER_FUNC_LINEAR,   /*Linear transfer characteristics*/
+	0,
+	0,
+	V4L2_XFER_FUNC_XVYCC,    /*IEC 61966-2-4*/
+	V4L2_XFER_FUNC_BT1361,   /*Rec. ITU-R BT.1361-0 extended colour gamut*/
+	V4L2_XFER_FUNC_SRGB,     /*IEC 61966-2-1 sRGB or sYCC*/
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.2020-2 (10 bit system)*/
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.2020-2 (12 bit system)*/
+	V4L2_XFER_FUNC_SMPTE2084,/*SMPTE ST 2084*/
+	V4L2_XFER_FUNC_ST428,    /*SMPTE ST 428-1*/
+	V4L2_XFER_FUNC_HLG       /*Rec. ITU-R BT.2100-0 hybrid log-gamma (HLG)*/
+};
+
+static const u8 colormatrixcoefs[] = {
+	0,
+	V4L2_YCBCR_ENC_709,             /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_YCBCR_ENC_BT470_6M,        /*Title 47 Code of Federal Regulations*/
+	V4L2_YCBCR_ENC_601,             /*Rec. ITU-R BT.601-7 625*/
+	V4L2_YCBCR_ENC_601,             /*Rec. ITU-R BT.601-7 525*/
+	V4L2_YCBCR_ENC_SMPTE240M,       /*SMPTE240M*/
+	0,
+	V4L2_YCBCR_ENC_BT2020,          /*Rec. ITU-R BT.2020-2*/
+	V4L2_YCBCR_ENC_BT2020_CONST_LUM /*Rec. ITU-R BT.2020-2 constant*/
+};
+
+static int vpu_dec_convert_color_iso_aspect_to_v4l2_aspect(struct vpu_ctx *ctx,
+		u32 primaries, u32 transfer, u32 coeffs, u32 fullrange)
+{
+	if (primaries < ARRAY_SIZE(colorprimaries))
+		ctx->colorspace = colorprimaries[primaries];
+
+	if (transfer < ARRAY_SIZE(colortransfers))
+		ctx->xfer_func = colortransfers[transfer];
+
+	if (coeffs < ARRAY_SIZE(colormatrixcoefs))
+		ctx->ycbcr_enc = colormatrixcoefs[coeffs];
+
+	if (fullrange)
+		ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+	else
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+
+	return 0;
+}
+
+static int v4l2_ioctl_g_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f
+		)
+{
+	struct vpu_ctx *ctx =           v4l2_fh_to_ctx(fh);
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+	unsigned int i;
+	struct queue_data               *q_data;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q_data = &ctx->q_data[V4L2_DST];
+		down(&q_data->drv_q_lock);
+		if (is_10bit_format(ctx))
+			pix_mp->pixelformat = V4L2_PIX_FMT_NV12_10BIT;
+		else
+			pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+
+		pix_mp->width = q_data->width;
+		pix_mp->height = q_data->height;
+		pix_mp->field = q_data->field;
+		pix_mp->num_planes = 2;
+		for (i = 0; i < pix_mp->num_planes; i++) {
+			pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+			pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+		}
+		up(&q_data->drv_q_lock);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		q_data = &ctx->q_data[V4L2_SRC];
+
+		down(&q_data->drv_q_lock);
+		pix_mp->width = q_data->width;
+		pix_mp->height = q_data->height;
+		pix_mp->field = V4L2_FIELD_NONE;
+		pix_mp->num_planes = q_data->num_planes;
+		for (i = 0; i < pix_mp->num_planes; i++) {
+			pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+			pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+
+		}
+		pix_mp->pixelformat = q_data->fourcc;
+		up(&q_data->drv_q_lock);
+	} else
+		return -EINVAL;
+
+	pix_mp->colorspace = ctx->colorspace;
+	pix_mp->xfer_func = ctx->xfer_func;
+	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+	pix_mp->quantization = ctx->quantization;
+
+	vpu_dbg(LVL_BIT_FLOW, "%s g_fmt : %c%c%c%c %d x %d\n",
+		V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
+		pix_mp->pixelformat & 0xff,
+		(pix_mp->pixelformat >> 8) & 0xff,
+		(pix_mp->pixelformat >> 16) & 0xff,
+		(pix_mp->pixelformat >> 24) & 0xff,
+		pix_mp->width,
+		pix_mp->height);
+	return 0;
+}
+
+static bool set_video_standard(struct vpu_ctx *ctx,
+		struct queue_data *q_data,
+		struct v4l2_format *f,
+		struct vpu_v4l2_fmt *pformat_table,
+		uint32_t table_size)
+{
+	unsigned int i;
+
+	for (i = 0; i < table_size; i++) {
+		if (pformat_table[i].fourcc == f->fmt.pix_mp.pixelformat) {
+			if (!check_fmt_is_support(ctx, &pformat_table[i]))
+				return false;
+			q_data->vdec_std = pformat_table[i].vdec_std;
+			q_data->num_planes = pformat_table[i].num_planes;
+			q_data->fourcc = f->fmt.pix_mp.pixelformat;
+		}
+	}
+	return true;
+}
+
+static void set_output_default_sizeimage(struct queue_data *q_data)
+{
+	u32 i;
+
+	for (i = 0; i < q_data->num_planes; i++) {
+		if (q_data->sizeimage[i])
+			continue;
+		q_data->sizeimage[i] = q_data->width * q_data->height;
+	}
+}
+
+static int v4l2_ioctl_s_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f
+		)
+{
+	struct vpu_ctx                  *ctx = v4l2_fh_to_ctx(fh);
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+	struct queue_data               *q_data;
+	u_int32                         i;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	vpu_dbg(LVL_BIT_FLOW, "%s s_fmt : %c%c%c%c %d x %d\n",
+		V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
+		pix_mp->pixelformat & 0xff,
+		(pix_mp->pixelformat >> 8) & 0xff,
+		(pix_mp->pixelformat >> 16) & 0xff,
+		(pix_mp->pixelformat >> 24) & 0xff,
+		pix_mp->width,
+		pix_mp->height);
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q_data = &ctx->q_data[V4L2_DST];
+		if (!set_video_standard(ctx, q_data, f, formats_yuv_dec, ARRAY_SIZE(formats_yuv_dec)))
+			return -EINVAL;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		q_data = &ctx->q_data[V4L2_SRC];
+		if (!set_video_standard(ctx, q_data, f, formats_compressed_dec, ARRAY_SIZE(formats_compressed_dec)))
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	pix_mp->colorspace = ctx->colorspace;
+	pix_mp->xfer_func = ctx->xfer_func;
+	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+	pix_mp->quantization = ctx->quantization;
+	pix_mp->num_planes = q_data->num_planes;
+
+	down(&q_data->drv_q_lock);
+	if (V4L2_TYPE_IS_OUTPUT(f->type) || ctx->b_firstseq) {
+		for (i = 0; i < q_data->num_planes; i++) {
+			q_data->stride = pix_mp->plane_fmt[i].bytesperline;
+			q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+		}
+		q_data->width = pix_mp->width;
+		q_data->height = pix_mp->height;
+	} else {
+		for (i = 0; i < q_data->num_planes; i++) {
+			pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+			pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+		}
+		pix_mp->width = q_data->width;
+		pix_mp->height = q_data->height;
+	}
+	if (V4L2_TYPE_IS_OUTPUT(f->type))
+		set_output_default_sizeimage(q_data);
+	up(&q_data->drv_q_lock);
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		vpu_calculate_performance(ctx, 0xff, "capture set fmt");
+	else
+		vpu_calculate_performance(ctx, 0xff, "output set fmt");
+
+	return 0;
+}
+
+static int vpu_dec_queue_expbuf(struct queue_data *queue,
+				struct v4l2_exportbuffer *buf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_expbuf(&queue->vb2_q, buf);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_reqbufs(struct queue_data *queue,
+				struct v4l2_requestbuffers *reqbuf)
+{
+	struct vpu_ctx *ctx;
+	int ret = -EINVAL;
+
+	ctx = container_of(queue, struct vpu_ctx, q_data[queue->type]);
+
+	down(&queue->drv_q_lock);
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] %s %s buffers\n",
+			ctx->str_index,
+			queue->type ? "CAPTURE" : "OUTPUT",
+			reqbuf->count ? "request" : "free");
+
+	if (queue->type == V4L2_SRC)
+		vpu_calculate_performance(ctx, 0xff, reqbuf->count ? "output request buffer begin" : "output free buffer begin");
+	else
+		vpu_calculate_performance(ctx, 0xff, reqbuf->count ? "capture request buffer begin" : "capture free buffer begin");
+
+	if (queue->vb2_q_inited)
+		ret = vb2_reqbufs(&queue->vb2_q, reqbuf);
+
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] %s %s buffers done\n",
+			ctx->str_index,
+			queue->type ? "CAPTURE" : "OUTPUT",
+			reqbuf->count ? "request" : "free");
+	if (queue->type == V4L2_SRC)
+		vpu_calculate_performance(ctx, 0xff, reqbuf->count ? "output request buffer finish" : "output free buffer finish");
+	else
+		vpu_calculate_performance(ctx, 0xff, reqbuf->count ? "capture request buffer finish" : "capture free buffer finish");
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_querybuf(struct queue_data *queue,
+				struct v4l2_buffer *buf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_querybuf(&queue->vb2_q, buf);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_qbuf(struct queue_data *queue,
+				struct v4l2_buffer *buf)
+{
+	int ret = -EINVAL;
+	struct vb2_buffer *vb;
+
+	if (buf->index >= queue->vb2_q.num_buffers) {
+		vpu_err("[%s] buffer index(%d) out of range\n",
+				queue->type ? "CAPTURE" : "OUTPUT", buf->index);
+		return -EINVAL;
+	}
+	vb = queue->vb2_q.bufs[buf->index];
+	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+		vpu_err("[%s] buffer[%d] has been queued before\n",
+				queue->type ? "CAPTURE" : "OUTPUT", buf->index);
+		return -EINVAL;
+	}
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+		ret = vb2_qbuf(&queue->vb2_q, queue->ctx->dev->v4l2_dev.mdev, buf);
+#else
+		ret = vb2_qbuf(&queue->vb2_q, buf);
+#endif
+	}
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_dqbuf(struct queue_data *queue,
+				struct v4l2_buffer *buf, bool nonblocking)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_dqbuf(&queue->vb2_q, buf, nonblocking);
+	if (!ret)
+		queue->dqbuf_count++;
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_enable(struct queue_data *queue,
+				enum v4l2_buf_type type)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_streamon(&queue->vb2_q, type);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static void check_queue_is_releasd(struct queue_data *queue, char *desc)
+{
+	struct vb2_data_req *p_data_req = NULL;
+	int i;
+
+	for (i = 0; i < queue->vb2_q.num_buffers; i++) {
+		p_data_req = &queue->vb2_reqs[i];
+		if (!p_data_req->vb2_buf)
+			continue;
+
+		if (p_data_req->status != FRAME_ALLOC)
+			vpu_dbg(LVL_WARN,
+				"%s:buffer(%d) status is %s when %s\n",
+				queue->type ? "CAPTURE" : "OUTPUT",
+				i, bufstat[p_data_req->status],
+				desc);
+	}
+}
+
+static void clear_queue(struct queue_data *queue)
+{
+	struct vb2_data_req *p_data_req = NULL;
+	struct vb2_data_req *p_temp;
+	struct vb2_buffer *vb;
+	struct vpu_ctx *ctx;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+	ctx = container_of(queue, struct vpu_ctx, q_data[queue->type]);
+	check_queue_is_releasd(queue, "clear queue");
+
+	list_for_each_entry_safe(p_data_req, p_temp, &queue->drv_q, list) {
+		list_del(&p_data_req->list);
+		p_data_req->queued = false;
+	}
+
+	list_for_each_entry(vb, &queue->vb2_q.queued_list, queued_entry) {
+		if (vb->state == VB2_BUF_STATE_ACTIVE)
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+	}
+	INIT_LIST_HEAD(&queue->drv_q);
+	if (queue->type == V4L2_SRC)
+		ctx->eos_stop_received = false;
+	vpu_dbg(LVL_BIT_FRAME_COUNT,
+		"%s qbuf_count : %ld, dqbuf_count : %ld\n",
+		queue->type == V4L2_DST ? "CAPTURE" : "OUTPUT",
+		queue->qbuf_count,
+		queue->dqbuf_count);
+	queue->qbuf_count = 0;
+	queue->dqbuf_count = 0;
+	queue->process_count = 0;
+}
+
+static int vpu_dec_queue_disable(struct queue_data *queue,
+				enum v4l2_buf_type type)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_streamoff(&queue->vb2_q, type);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_release(struct queue_data *queue)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited) {
+		clear_queue(queue);
+		vb2_queue_release(&queue->vb2_q);
+	}
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_dec_queue_mmap(struct queue_data *queue,
+				struct vm_area_struct *vma)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_mmap(&queue->vb2_q, vma);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int v4l2_ioctl_expbuf(struct file *file,
+		void *fh,
+		struct v4l2_exportbuffer *buf
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	return vpu_dec_queue_expbuf(q_data, buf);
+}
+
+static int v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub
+		)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s(), type: 0x%x\n", __func__, sub->type);
+
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SKIP:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	case V4L2_EVENT_DECODE_ERROR:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void vpu_dec_cleanup_event(struct vpu_ctx *ctx)
+{
+	struct v4l2_event ev;
+	int ret;
+
+	while (v4l2_event_pending(&ctx->fh)) {
+		ret = v4l2_event_dequeue(&ctx->fh, &ev, 1);
+		if (ret)
+			break;
+	};
+}
+
+static void init_dma_buffer(struct dma_buffer *buffer)
+{
+	if (!buffer)
+		return;
+
+	buffer->dma_phy = 0;
+	buffer->dma_virt = NULL;
+	buffer->dma_size = 0;
+}
+
+static int alloc_dma_buffer(struct vpu_ctx *ctx, struct dma_buffer *buffer)
+{
+	if (!ctx || !ctx->dev || !buffer) {
+		vpu_dec_event_decode_error(ctx);
+		return -EINVAL;
+	}
+
+	buffer->dma_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+			buffer->dma_size,
+			(dma_addr_t *)&buffer->dma_phy,
+			GFP_KERNEL | GFP_DMA32 | __GFP_NOWARN);
+
+	if (!buffer->dma_virt) {
+		vpu_err("error: %s() dma buffer alloc size(%x) fail!\n",
+				__func__,  buffer->dma_size);
+		vpu_dec_event_decode_error(ctx);
+		return -ENOMEM;
+	}
+
+	memset_io(buffer->dma_virt, 0, buffer->dma_size);
+	atomic64_add(buffer->dma_size, &ctx->statistic.total_dma_size);
+	return 0;
+}
+
+static int free_dma_buffer(struct vpu_ctx *ctx, struct dma_buffer *buffer)
+{
+	if (!ctx || !ctx->dev || !buffer)
+		return -EINVAL;
+
+	if (!buffer->dma_virt)
+		return -1;
+
+	dma_free_coherent(&ctx->dev->plat_dev->dev,
+			buffer->dma_size,
+			buffer->dma_virt,
+			buffer->dma_phy);
+
+	atomic64_sub(buffer->dma_size, &ctx->statistic.total_dma_size);
+	init_dma_buffer(buffer);
+	return 0;
+}
+
+static u_int32 get_mbi_size(struct queue_data *queue)
+{
+	u_int32 uAlign = 0x800;
+	u_int32 mbi_size;
+
+	mbi_size = (queue->sizeimage[0] + queue->sizeimage[1])/4;
+	return ALIGN(mbi_size, uAlign);
+}
+
+#define DCP_FIXED_MB_ALLOC_TYPICAL	250
+#define DCP_FIXED_MB_ALLOC_WORSTCASE	400
+#define DCP_FIXED_MB_ALLOC		DCP_FIXED_MB_ALLOC_TYPICAL
+static u32 get_dcp_size(struct vpu_ctx *ctx)
+{
+	u32 uNumDcpChunks = ((ctx->seqinfo.uNumDFEAreas >> 16) & 0xff);
+	u32 uNumMbs;
+	u32 width;
+	u32 height;
+	u32 uTotalBinSize;
+
+	if (!uNumDcpChunks)
+		return DCP_SIZE;
+
+	width = ctx->seqinfo.uHorDecodeRes;
+	height = ctx->seqinfo.uVerDecodeRes;
+	uNumMbs = DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height, 16);
+	uTotalBinSize = uNumMbs * DCP_FIXED_MB_ALLOC * uNumDcpChunks;
+	uTotalBinSize = min_t(u32, uTotalBinSize, DCP_SIZE);
+	uTotalBinSize = max_t(u32, uTotalBinSize, DCP_SIZE_MINIMUM);
+
+	return uTotalBinSize;
+}
+
+static int free_mbi_buffers(struct vpu_ctx *ctx)
+{
+	u_int32 i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->mbi_buffer); i++)
+		free_dma_buffer(ctx, &ctx->mbi_buffer[i]);
+
+	return 0;
+}
+
+static int free_dcp_buffers(struct vpu_ctx *ctx)
+{
+	u_int32 i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->dcp_buffer); i++)
+		free_dma_buffer(ctx, &ctx->dcp_buffer[i]);
+
+	return 0;
+}
+
+static int free_decoder_buffer(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue;
+
+	queue = &ctx->q_data[V4L2_DST];
+	down(&queue->drv_q_lock);
+	reset_mbi_dcp_count(ctx);
+	up(&queue->drv_q_lock);
+
+	queue = &ctx->q_data[V4L2_SRC];
+	down(&queue->drv_q_lock);
+	free_dma_buffer(ctx, &ctx->stream_buffer);
+	free_dma_buffer(ctx, &ctx->udata_buffer);
+	up(&queue->drv_q_lock);
+
+	return 0;
+}
+
+static int v4l2_ioctl_reqbufs(struct file *file,
+		void *fh,
+		struct v4l2_requestbuffers *reqbuf
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s(), buffer_type: %d, buffer_count: %d\n",
+			__func__, reqbuf->type, reqbuf->count);
+
+	if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	if (vb2_is_streaming(&q_data->vb2_q)) {
+		vpu_err("%s reqbufs (%d) during streaming\n",
+			q_data->type ? "CAPTURE" : "OUTPUT",
+			reqbuf->count);
+		return -EBUSY;
+	}
+
+	if (reqbuf->count > 0 && !q_data->sizeimage[0]) {
+		vpu_err("sizeimage isn't initialized, %s reqbufs fail\n",
+			q_data->type ? "CAPTURE" : "OUTPUT");
+		return -EINVAL;
+	}
+
+	ret = vpu_dec_queue_reqbufs(q_data, reqbuf);
+	if (ret) {
+		vpu_dbg(LVL_WARN, "warning: %s() can't request (%d) buffer : %d\n",
+				__func__, reqbuf->count, ret);
+		return ret;
+	}
+	if (V4L2_TYPE_IS_OUTPUT(reqbuf->type))
+		return ret;
+
+	return ret;
+}
+
+static int v4l2_ioctl_querybuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	unsigned int i;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	ret = vpu_dec_queue_querybuf(q_data, buf);
+	if (!ret) {
+		if (buf->memory == V4L2_MEMORY_MMAP) {
+			if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+				for (i = 0; i < buf->length; i++)
+					buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+			} else
+				buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+		}
+	} else
+		vpu_err("error: %s() return ret=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static bool is_codec_config_data(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (!vb)
+		return false;
+
+	vbuf = to_vb2_v4l2_buffer(vb);
+	if (vbuf->flags & V4L2_NXP_BUF_FLAG_CODECCONFIG)
+		return true;
+	return false;
+}
+
+static void vpu_dec_receive_ts(struct vpu_ctx *ctx,
+				struct vb2_buffer *vb,
+				int size)
+{
+	struct vb2_v4l2_buffer *vbuf;
+	s64 input_ts;
+	u32 data[3];
+
+	if (!ctx || !vb)
+		return;
+
+	vbuf = to_vb2_v4l2_buffer(vb);
+	if (vbuf->flags & V4L2_NXP_BUF_FLAG_TIMESTAMP_INVALID) {
+		vpu_dbg(LVL_BIT_TS, "[INPUT  TS]Invalid timestamp\n");
+		vb->timestamp = TSM_TIMESTAMP_NONE;
+	}
+
+	input_ts = vb->timestamp;
+	if (input_ts < 0)
+		input_ts = TSM_TIMESTAMP_NONE;
+
+	if (TSM_TS_IS_VALID(input_ts) && input_ts == ctx->output_ts)
+		vpu_dbg(LVL_BIT_TS, "repetitive timestamp\n");
+	if (TSM_TS_IS_VALID(input_ts) && input_ts > ctx->output_ts)
+		ctx->output_ts = input_ts;
+
+	if (is_codec_config_data(vb) && !TSM_TS_IS_VALID(input_ts)) {
+		vpu_dbg(LVL_BIT_TS, "[INPUT  TS]codec data\n");
+		ctx->extra_size += size;
+		return;
+	}
+
+	size += ctx->extra_size;
+	ctx->extra_size = 0;
+	vpu_dbg(LVL_BIT_TS, "[INPUT  TS]%32lld\n", input_ts);
+
+	if (input_ts < 0) {
+		data[0] = (u32)-1;
+		data[1] = 0;
+	} else {
+		data[0] = input_ts / NSEC_PER_SEC;
+		data[1] = input_ts % NSEC_PER_SEC;
+	}
+	data[2] = size;
+	v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_TS, 3, data);
+}
+
+static int v4l2_ioctl_qbuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	struct vb2_data_req *p_data_req;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		ctx->total_qbuf_bytes += buf->m.planes[0].bytesused;
+		vpu_dbg(LVL_BIT_FRAME_BYTES, "[%d]input bytes : %8d / %16ld\n",
+				ctx->str_index,
+				buf->m.planes[0].bytesused,
+				ctx->total_qbuf_bytes);
+		q_data = &ctx->q_data[V4L2_SRC];
+
+		v4l2_update_stream_addr(ctx, 0);
+	} else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q_data = &ctx->q_data[V4L2_DST];
+		down(&q_data->drv_q_lock);
+		p_data_req = &q_data->vb2_reqs[buf->index];
+		p_data_req->data_offset[0] = buf->m.planes[0].data_offset;
+		p_data_req->data_offset[1] = buf->m.planes[1].data_offset;
+		up(&q_data->drv_q_lock);
+	} else {
+		vpu_err("qbuf invalid buf type : %d\n", buf->type);
+		return -EINVAL;
+	}
+
+	ret = vpu_dec_queue_qbuf(q_data, buf);
+	if (ret) {
+		vpu_err("error: %s() return ret=%d\n", __func__, ret);
+		return ret;
+	}
+	v4l2_update_stream_addr(ctx, 0);
+
+	return ret;
+}
+
+static int v4l2_ioctl_dqbuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	ret = vpu_dec_queue_dqbuf(q_data, buf, file->f_flags & O_NONBLOCK);
+
+	if (ret) {
+		vpu_err("error: %s() return ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	if (q_data->vb2_reqs[buf->index].bfield)
+		buf->field = V4L2_FIELD_INTERLACED;
+	else
+		buf->field = V4L2_FIELD_NONE;
+	v4l2_update_stream_addr(ctx, 0);
+	if (!V4L2_TYPE_IS_OUTPUT(buf->type) && is_10bit_format(ctx))
+		buf->reserved = 1;
+
+	if (V4L2_TYPE_IS_OUTPUT(buf->type))
+		buf->flags &= ~V4L2_NXP_BUF_MASK_FLAGS;
+
+	return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+		unsigned int table_size,
+		struct v4l2_format *f)
+{
+	unsigned int i;
+
+	for (i = 0; i < table_size; i++) {
+		if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+			return true;
+	}
+	return false;
+}
+
+static int v4l2_ioctl_try_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	unsigned int table_size;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		table_size = ARRAY_SIZE(formats_compressed_dec);
+		if (!format_is_support(formats_compressed_dec, table_size, f))
+			return -EINVAL;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		table_size = ARRAY_SIZE(formats_yuv_dec);
+		if (!format_is_support(formats_yuv_dec, table_size, f))
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	f->fmt.pix_mp.colorspace = ctx->colorspace;
+	f->fmt.pix_mp.xfer_func = ctx->xfer_func;
+	f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
+	f->fmt.pix_mp.quantization = ctx->quantization;
+
+	return 0;
+}
+
+static int vpu_dec_v4l2_ioctl_g_selection(struct file *file, void *fh,
+					struct v4l2_selection *s)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (s->target != V4L2_SEL_TGT_CROP && s->target != V4L2_SEL_TGT_COMPOSE)
+		return -EINVAL;
+
+	s->r.left = ctx->seqinfo.uFrameCropLeftOffset;
+	s->r.top = ctx->seqinfo.uFrameCropTopOffset;
+	s->r.width = ctx->seqinfo.uHorRes;
+	s->r.height = ctx->seqinfo.uVerRes;
+
+	return 0;
+}
+
+static int v4l2_ioctl_decoder_cmd(struct file *file,
+		void *fh,
+		struct v4l2_decoder_cmd *cmd
+		)
+{
+	int ret = 0;
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	switch (cmd->cmd) {
+	case V4L2_DEC_CMD_START:
+		break;
+	case V4L2_DEC_CMD_STOP: {
+		vpu_dbg(LVL_EVENT, "ctx[%d]: receive V4L2_DEC_CMD_STOP\n", ctx->str_index);
+		ctx->eos_stop_received = true;
+		v4l2_update_stream_addr(ctx, 0);
+		}
+		break;
+	case V4L2_DEC_CMD_PAUSE:
+		break;
+	case V4L2_DEC_CMD_RESUME:
+		break;
+	case IMX_V4L2_DEC_CMD_RESET:
+		v4l2_update_stream_addr(ctx, 0);
+		mutex_lock(&ctx->fw_flow_mutex);
+		ret = vpu_dec_cmd_reset(ctx);
+		mutex_unlock(&ctx->fw_flow_mutex);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static int v4l2_ioctl_streamon(struct file *file,
+		void *fh,
+		enum v4l2_buf_type i
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s(), buffer_type: %d\n", __func__, i);
+
+	if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] %s on\n", ctx->str_index,
+		V4L2_TYPE_IS_OUTPUT(i) ? "OUTPUT" : "CAPTURE");
+
+	if (V4L2_TYPE_IS_OUTPUT(i)) {
+		ctx->firmware_finished = false;
+		ctx->eos_stop_added = false;
+	}
+
+	ret = vpu_dec_queue_enable(q_data, i);
+	if (!ret)
+		v4l2_update_stream_addr(ctx, 0);
+	else
+		vpu_err("error: %s %s() return ret=%d\n", V4L2_TYPE_IS_OUTPUT(i) ? "OUTPUT" : "CAPTURE", __func__, ret);
+
+	if (ctx->hang_status) {
+		vpu_err("%s(): not succeed and some instance are blocked\n", __func__);
+		return -EINVAL;
+	}
+	if (ret)
+		return ret;
+
+	down(&q_data->drv_q_lock);
+	q_data->enable = true;
+	if (!V4L2_TYPE_IS_OUTPUT(i))
+		respond_req_frame(ctx, q_data, false);
+	up(&q_data->drv_q_lock);
+
+	return ret;
+}
+
+static bool is_need_abort(struct vpu_ctx *ctx, enum v4l2_buf_type type)
+{
+	bool src_status = vb2_is_streaming(&ctx->q_data[V4L2_SRC].vb2_q);
+
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		return false;
+	if (!vpu_dec_is_active(ctx))
+		return false;
+
+	if (src_status)
+		ctx->seek_flag = false;
+	else
+		ctx->seek_flag = true;
+	if (ctx->wait_res_change_done) {
+		if (src_status)
+			return false;
+		vpu_dbg(LVL_INFO,
+			"ctx[%d] seek in res change\n", ctx->str_index);
+	}
+	return true;
+}
+
+static int v4l2_ioctl_streamoff(struct file *file,
+		void *fh,
+		enum v4l2_buf_type i
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s(): ctx[%d] buf_type: %d\n",
+			__func__, ctx->str_index, i);
+
+	if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		q_data = &ctx->q_data[V4L2_SRC];
+	else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		q_data = &ctx->q_data[V4L2_DST];
+	else
+		return -EINVAL;
+
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] %s off\n", ctx->str_index,
+		V4L2_TYPE_IS_OUTPUT(i) ? "OUTPUT" : "CAPTURE");
+
+	down(&q_data->drv_q_lock);
+	q_data->enable = false;
+	up(&q_data->drv_q_lock);
+
+	if (is_need_abort(ctx, i)) {
+		mutex_lock(&ctx->fw_flow_mutex);
+		send_abort_cmd(ctx);
+		mutex_unlock(&ctx->fw_flow_mutex);
+	}
+
+	if (V4L2_TYPE_IS_OUTPUT(i))
+		ctx->output_ts = TSM_TIMESTAMP_NONE;
+	else
+		ctx->capture_ts = TSM_TIMESTAMP_NONE;
+
+	ret = vpu_dec_queue_disable(q_data, i);
+	if (ctx->hang_status) {
+		vpu_err("%s(): not succeed and some instance are blocked\n", __func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int vpu_dec_v4l2_ioctl_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	u32 numerator;
+	u32 denominator;
+
+	mutex_lock(&ctx->instance_mutex);
+
+	numerator = ctx->fixed_frame_interval.numerator;
+	denominator = ctx->fixed_frame_interval.denominator;
+	if (!numerator || !denominator) {
+		numerator = ctx->frame_interval.numerator;
+		denominator = ctx->frame_interval.denominator;
+	}
+	if (!numerator || !denominator) {
+		numerator = 0;
+		denominator = 0;
+	}
+	parm->parm.capture.timeperframe.numerator = numerator;
+	parm->parm.capture.timeperframe.denominator = denominator;
+
+	mutex_unlock(&ctx->instance_mutex);
+	vpu_dbg(LVL_BIT_FLOW, "%s g_parm : %d / %d\n",
+			V4L2_TYPE_IS_OUTPUT(parm->type) ? "OUTPUT" : "CAPTURE",
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator);
+
+	return 0;
+}
+
+static int vpu_dec_v4l2_ioctl_s_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	u32 gcd;
+
+	if (!parm->parm.capture.timeperframe.numerator ||
+			!parm->parm.capture.timeperframe.denominator)
+		return -EINVAL;
+
+	gcd = get_greatest_common_divisor(
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator);
+
+	mutex_lock(&ctx->instance_mutex);
+	ctx->fixed_frame_interval.numerator =
+		parm->parm.capture.timeperframe.numerator / gcd;
+	ctx->fixed_frame_interval.denominator =
+		parm->parm.capture.timeperframe.denominator / gcd;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops v4l2_decoder_ioctl_ops = {
+	.vidioc_querycap                = v4l2_ioctl_querycap,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	.vidioc_enum_fmt_vid_cap	= v4l2_ioctl_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out	= v4l2_ioctl_enum_fmt_vid_out,
+#else
+	.vidioc_enum_fmt_vid_cap_mplane = v4l2_ioctl_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out_mplane = v4l2_ioctl_enum_fmt_vid_out,
+#endif
+	.vidioc_g_fmt_vid_cap_mplane    = v4l2_ioctl_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane    = v4l2_ioctl_g_fmt,
+	.vidioc_try_fmt_vid_cap_mplane  = v4l2_ioctl_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane  = v4l2_ioctl_try_fmt,
+	.vidioc_s_fmt_vid_cap_mplane    = v4l2_ioctl_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane    = v4l2_ioctl_s_fmt,
+	.vidioc_g_parm			= vpu_dec_v4l2_ioctl_g_parm,
+	.vidioc_s_parm			= vpu_dec_v4l2_ioctl_s_parm,
+	.vidioc_expbuf                  = v4l2_ioctl_expbuf,
+	.vidioc_g_selection		= vpu_dec_v4l2_ioctl_g_selection,
+	.vidioc_decoder_cmd             = v4l2_ioctl_decoder_cmd,
+	.vidioc_subscribe_event         = v4l2_ioctl_subscribe_event,
+	.vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+	.vidioc_reqbufs                 = v4l2_ioctl_reqbufs,
+	.vidioc_querybuf                = v4l2_ioctl_querybuf,
+	.vidioc_qbuf                    = v4l2_ioctl_qbuf,
+	.vidioc_dqbuf                   = v4l2_ioctl_dqbuf,
+	.vidioc_streamon                = v4l2_ioctl_streamon,
+	.vidioc_streamoff               = v4l2_ioctl_streamoff,
+};
+
+// Set/Get controls - v4l2 control framework
+
+static struct vpu_v4l2_control vpu_controls_dec[] = {
+	{
+		.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+		.minimum = 1,
+		.maximum = 32,
+		.step = 1,
+		.default_value = 4,
+		.is_volatile = true,
+	},
+};
+
+static	struct v4l2_ctrl_config vpu_custom_g_cfg[] = {
+	{
+		.id = V4L2_CID_USER_FRAME_COLORDESC,
+		.name = "color description",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 10,
+		.step = 1,
+		.def = 1,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_TRANSFERCHARS,
+		.name = "transfer characteristics",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 18,
+		.step = 1,
+		.def = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_MATRIXCOEFFS,
+		.name = "matrix coefficients",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 10,
+		.step = 1,
+		.def = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_FULLRANGE,
+		.name = "vido full range flg",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_VUIPRESENT,
+		.name = "VUI present",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+	}
+};
+
+static	struct v4l2_ctrl_config vpu_custom_s_cfg[] = {
+	{
+		.id = V4L2_CID_USER_RAW_BASE,
+		.name = "Raw Ctrl",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_DEPTH,
+		.name = "frame depth ctrl",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 1,
+		.max = VPU_FRAME_DEPTH_MAX,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_USER_FRAME_DIS_REORDER,
+		.name = "frame disable reoder ctrl",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.min = 0,
+		.max = 1,
+		.step = 1,
+		.def = 0,
+	},
+	{
+		.id = V4L2_CID_USER_TS_THRESHOLD,
+		.name = "frame timestamp threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = INT_MAX,
+		.step = 1,
+		.def = 0,
+	},
+	{
+		.id = V4L2_CID_USER_BS_L_THRESHOLD,
+		.name = "frame bitstream low threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.step = 1,
+		.def = 0,
+	},
+	{
+		.id = V4L2_CID_USER_BS_H_THRESHOLD,
+		.name = "frame bitstream high threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.step = 1,
+		.def = 0,
+	},
+	{
+		.id = V4L2_CID_USER_STREAM_INPUT_MODE,
+		.name = "stream input mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = NON_FRAME_LVL,
+		.step = 1,
+		.def = 1,
+	}
+};
+
+#define CNT_STAND_G_CTRLS	ARRAY_SIZE(vpu_controls_dec)
+#define CNT_CUSTOM_G_CFG	ARRAY_SIZE(vpu_custom_g_cfg)
+#define CNT_CUSTOM_S_CFG	ARRAY_SIZE(vpu_custom_s_cfg)
+#define CNT_CTRLS_DEC		(CNT_STAND_G_CTRLS + CNT_CUSTOM_G_CFG + CNT_CUSTOM_S_CFG)
+
+static int v4l2_custom_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() control(%d)\n",
+			__func__, ctrl->id);
+
+	switch (ctrl->id) {
+	case V4L2_CID_USER_RAW_BASE:
+		ctx->start_code_bypass = ctrl->val;
+		break;
+	case V4L2_CID_USER_FRAME_DEPTH:
+		vpu_frm_depth = ctrl->val;
+		break;
+	case V4L2_CID_USER_FRAME_DIS_REORDER:
+		ctx->b_dis_reorder = ctrl->val;
+		break;
+	case V4L2_CID_USER_TS_THRESHOLD:
+		ctx->ts_threshold = ctrl->val;
+		break;
+	case V4L2_CID_USER_BS_L_THRESHOLD:
+		ctx->bs_l_threshold = ctrl->val;
+		break;
+	case V4L2_CID_USER_BS_H_THRESHOLD:
+		ctx->bs_h_threshold = ctrl->val;
+		break;
+	case V4L2_CID_USER_STREAM_INPUT_MODE:
+		ctx->stream_input_mode = ctrl->val;
+		break;
+	default:
+		vpu_err("%s() Invalid costomer control(%d)\n",
+				__func__, ctrl->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int v4l2_custom_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct v4l2_ctrl_config *ctrl_cfg = NULL;
+	int i;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() control(%d)\n",
+			__func__, ctrl->id);
+
+	for (i = 0; i < CNT_CUSTOM_G_CFG; i++) {
+		if (vpu_custom_g_cfg[i].id == ctrl->id) {
+			ctrl_cfg = &vpu_custom_g_cfg[i];
+			break;
+		}
+	}
+	if (!ctrl_cfg) {
+		vpu_err("%s() Invalid costomer control(%d)\n",
+				__func__, ctrl->id);
+		return -EINVAL;
+	}
+
+	switch (ctrl->id) {
+	case V4L2_CID_USER_FRAME_COLORDESC:
+		ctrl->val = ctx->seqinfo.uColorDesc;
+		break;
+	case V4L2_CID_USER_FRAME_TRANSFERCHARS:
+		ctrl->val = ctx->seqinfo.uTransferChars;
+		break;
+	case V4L2_CID_USER_FRAME_MATRIXCOEFFS:
+		ctrl->val = ctx->seqinfo.uMatrixCoeffs;
+		break;
+	case V4L2_CID_USER_FRAME_FULLRANGE:
+		ctrl->val = ctx->seqinfo.uVideoFullRangeFlag;
+		break;
+	case V4L2_CID_USER_FRAME_VUIPRESENT:
+		ctrl->val = ctx->seqinfo.uVUIPresent;
+		break;
+	default:
+		vpu_err("%s() Invalid costomer control(%d)\n",
+				__func__, ctrl->id);
+		return -EINVAL;
+	}
+	ctrl->val = max_t(s32, ctrl->val, ctrl_cfg->min);
+	ctrl->val = min_t(s32, ctrl->val, ctrl_cfg->max);
+	vpu_dbg(LVL_BIT_FLOW, "%s = %d\n", ctrl->name, ctrl->val);
+	return 0;
+}
+
+static int v4l2_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() control(%d)\n",
+			__func__, ctrl->id);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+		ctrl->val = ctx->seqinfo.uNumDPBFrms + ctx->seqinfo.uNumRefFrms;
+		break;
+	default:
+		vpu_err("%s() Invalid control(%d)\n",
+				__func__, ctrl->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int add_stand_g_ctrl(struct vpu_ctx *This)
+{
+	static const struct v4l2_ctrl_ops vpu_dec_ctrl_ops = {
+		.g_volatile_ctrl  = v4l2_dec_g_v_ctrl,
+	};
+	u_int32 i;
+	struct v4l2_ctrl *ctrl;
+
+	if (!This)
+		return -EINVAL;
+
+	for (i = 0; i < CNT_STAND_G_CTRLS; i++) {
+		ctrl = v4l2_ctrl_new_std(&This->ctrl_handler,
+					 &vpu_dec_ctrl_ops,
+					 vpu_controls_dec[i].id,
+					 vpu_controls_dec[i].minimum,
+					 vpu_controls_dec[i].maximum,
+					 vpu_controls_dec[i].step,
+					 vpu_controls_dec[i].default_value);
+		if (This->ctrl_handler.error || !ctrl) {
+			vpu_err("%s() v4l2_ctrl_new_std[%d] failed: %d\n",
+				__func__, i, This->ctrl_handler.error);
+			return This->ctrl_handler.error;
+		}
+
+		if (vpu_controls_dec[i].is_volatile)
+			ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	}
+
+	ctrl = NULL;
+	return 0;
+}
+
+static int add_custom_s_ctrl(struct vpu_ctx *This)
+{
+	static const struct v4l2_ctrl_ops vpu_custom_ctrl_ops = {
+		.s_ctrl = v4l2_custom_s_ctrl,
+	};
+	uint32_t i;
+	struct v4l2_ctrl *ctrl;
+
+	if (!This)
+		return -EINVAL;
+
+	for (i = 0; i < CNT_CUSTOM_S_CFG; i++) {
+		vpu_custom_s_cfg[i].ops = &vpu_custom_ctrl_ops;
+
+		if (vpu_custom_s_cfg[i].id == V4L2_CID_USER_FRAME_DEPTH)
+			vpu_custom_s_cfg[i].def = vpu_frm_depth;
+		if (vpu_custom_s_cfg[i].id == V4L2_CID_USER_BS_L_THRESHOLD ||
+		    vpu_custom_s_cfg[i].id == V4L2_CID_USER_BS_H_THRESHOLD)
+			vpu_custom_s_cfg[i].max = vpu_max_bufsize;
+
+		ctrl = v4l2_ctrl_new_custom(&This->ctrl_handler,
+					    &vpu_custom_s_cfg[i], NULL);
+
+		if (This->ctrl_handler.error || !ctrl) {
+			vpu_err("%s() v4l2_ctrl_new_std[%d] failed: %d\n",
+				__func__, i, This->ctrl_handler.error);
+			return This->ctrl_handler.error;
+		}
+	}
+
+	ctrl = NULL;
+	return 0;
+}
+
+static int add_custom_g_ctrl(struct vpu_ctx *This)
+{
+	static const struct v4l2_ctrl_ops vpu_custom_g_ctrl_ops = {
+		.g_volatile_ctrl = v4l2_custom_g_ctrl,
+	};
+
+	uint32_t i;
+	struct v4l2_ctrl *ctrl;
+
+	if (!This)
+		return -EINVAL;
+
+	for (i = 0; i < CNT_CUSTOM_G_CFG; i++) {
+		vpu_custom_g_cfg[i].ops = &vpu_custom_g_ctrl_ops;
+		ctrl = v4l2_ctrl_new_custom(&This->ctrl_handler,
+					    &vpu_custom_g_cfg[i], NULL);
+
+		if (This->ctrl_handler.error || !ctrl) {
+			vpu_err("%s() v4l2_ctrl_new_std[%d] failed: %d\n",
+				__func__, i, This->ctrl_handler.error);
+			return This->ctrl_handler.error;
+		}
+	}
+
+	ctrl = NULL;
+	return 0;
+}
+
+static int set_frame_threshold(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	ctrl->val = max_t(s32, ctrl->val, ctrl->minimum);
+	ctrl->val = min_t(s32, ctrl->val, ctrl->maximum);
+	frame_threshold[ctx->str_index] = ctrl->val;
+	return 0;
+}
+
+static int get_frame_threshold(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	ctrl->val = frame_threshold[ctx->str_index];
+	ctrl->val = max_t(s32, ctrl->val, ctrl->minimum);
+	ctrl->val = min_t(s32, ctrl->val, ctrl->maximum);
+	return 0;
+}
+
+static int add_ctrl_frame_threshold(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_frame_threshold_ops = {
+		.s_ctrl = set_frame_threshold,
+		.g_volatile_ctrl = get_frame_threshold,
+	};
+	struct v4l2_ctrl_config ctrl_config = {
+		.id = V4L2_CID_USER_FRAME_THRESHOLD,
+		.name = "stream frame threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.min = 0,
+		.max = USHRT_MAX,
+		.step = 1,
+		.ops = &ctrl_frame_threshold_ops,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	if (!ctx)
+		return -EINVAL;
+
+	ctrl_config.def = frame_threshold[ctx->str_index];
+	ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+					&ctrl_config,
+					NULL);
+	if (ctx->ctrl_handler.error || !ctrl) {
+		vpu_err("add frame threshold ctrl fail : %d\n",
+				ctx->ctrl_handler.error);
+		return ctx->ctrl_handler.error;
+	}
+
+	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	return 0;
+}
+
+static int add_dec_ctrl(struct vpu_ctx *This)
+{
+	if (!This)
+		return -EINVAL;
+
+	add_stand_g_ctrl(This);
+	add_custom_s_ctrl(This);
+	add_custom_g_ctrl(This);
+	add_ctrl_frame_threshold(This);
+
+	return 0;
+}
+
+
+static int ctrls_setup_decoder(struct vpu_ctx *This)
+{
+	if (!This)
+		return -EINVAL;
+
+	v4l2_ctrl_handler_init(&This->ctrl_handler, CNT_CTRLS_DEC);
+	if (This->ctrl_handler.error) {
+		vpu_err("%s() v4l2_ctrl_handler_init failed(%d)\n",
+				__func__, This->ctrl_handler.error);
+
+		return This->ctrl_handler.error;
+	} else {
+		vpu_dbg(LVL_INFO, "%s() v4l2_ctrl_handler_init ctrls(%ld)\n",
+				__func__, CNT_CTRLS_DEC);
+		This->ctrl_inited = true;
+	}
+
+	add_dec_ctrl(This);
+
+	v4l2_ctrl_handler_setup(&This->ctrl_handler);
+
+	return 0;
+}
+
+static void ctrls_delete_decoder(struct vpu_ctx *This)
+{
+	if (!This)
+		return;
+
+	if (This->ctrl_inited) {
+		v4l2_ctrl_handler_free(&This->ctrl_handler);
+		This->ctrl_inited = false;
+	}
+}
+
+static void update_wptr(struct vpu_ctx *ctx,
+			pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc,
+			u32 wptr)
+{
+	u32 size;
+	u32 length;
+
+	size = pStrBufDesc->end - pStrBufDesc->start;
+	length = (wptr + size - pStrBufDesc->wptr) % size;
+	ctx->total_write_bytes += length;
+
+	vpu_dbg(LVL_BIT_FRAME_BYTES, "[%d]receive bytes : %8d / %16ld\n",
+			ctx->str_index, length, ctx->total_write_bytes);
+	vpu_dbg(LVL_BIT_WPTR, "ctx[%d] wptr : 0x%08x -> 0x%08x\n",
+			ctx->str_index, pStrBufDesc->wptr, wptr);
+	pStrBufDesc->wptr = wptr;
+}
+
+/* Insert either the codec specific EOS type or a special scode to mark that this frame should be flushed/pushed directly for decode */
+static int add_scode_vpu(struct vpu_ctx *ctx, u_int32 uStrBufIdx, VPU_PADDING_SCODE_TYPE eScodeType, bool bUpdateWr)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	uint32_t start;
+	uint32_t end;
+	uint32_t wptr;
+	uint32_t rptr;
+	uint8_t *pbbuffer;
+	uint32_t *plbuffer;
+	uint32_t last;
+	uint32_t last2 = 0x0;
+	uint32_t pad_bytes = 0;
+	uint8_t *buffer;
+
+	vpu_dbg(LVL_BIT_FUNC, "enter %s()\n", __func__);
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	start = pStrBufDesc->start;
+	end = pStrBufDesc->end;
+	wptr = pStrBufDesc->wptr;
+	rptr = pStrBufDesc->rptr;
+
+	if (start != ctx->stream_buffer.dma_phy ||
+			end != ctx->stream_buffer.dma_phy + ctx->stream_buffer.dma_size) {
+		vpu_err("error: %s(), start or end pointer cross-border\n", __func__);
+		return 0;
+	}
+	if (wptr < start || wptr > end) {
+		vpu_err("error: %s(), wptr pointer cross-border\n", __func__);
+		return 0;
+	}
+	if (rptr < start || rptr > end) {
+		vpu_err("error: %s(), rptr pointer cross-border\n", __func__);
+		return 0;
+	}
+
+	buffer = kzalloc(SCODE_SIZE, GFP_KERNEL);
+	if (!buffer)
+		return 0;
+
+	atomic64_add(SCODE_SIZE, &ctx->statistic.total_alloc_size);
+	plbuffer = (uint32_t *)buffer;
+	if (wptr - start < ctx->stream_buffer.dma_size)
+		pbbuffer = (uint8_t *)(ctx->stream_buffer.dma_virt + wptr - start);
+	else {
+		vpu_err("error: return wptr(0x%x), start(0x%x) is not valid\n", wptr, start);
+		goto error;
+	}
+
+	if (((u_int64)pbbuffer)%4 != 0) {
+		int i;
+		if (end%4 != 0) {
+			vpu_err("end address of stream not aligned by 4 bytes !\n");
+			goto error;
+		}
+		pad_bytes = 4 - (((u_int64)pbbuffer)%4);
+		for (i = 0; i < pad_bytes; i++)
+			pbbuffer[i] = 0;
+		pbbuffer += pad_bytes;
+		wptr += pad_bytes;
+		if (wptr == end) {
+			wptr = start;
+			pbbuffer = (uint8_t *)ctx->stream_buffer.dma_virt;
+		}
+	}
+
+	if (eScodeType == BUFABORT_PADDING_TYPE) {
+		switch (q_data->vdec_std) {
+		case VPU_VIDEO_AVC:
+			last = 0x0B010000;
+			break;
+		case VPU_VIDEO_VC1:
+			last = 0x0a010000;
+			break;
+		case VPU_VIDEO_MPEG2:
+			last = 0xb7010000;
+			break;
+		case VPU_VIDEO_ASP:
+		case VPU_VIDEO_AVS:
+			last = 0xb1010000;
+			break;
+		case VPU_VIDEO_SPK:
+		case VPU_VIDEO_VP6:
+		case VPU_VIDEO_VP8:
+		case VPU_VIDEO_RV:
+			last = 0x34010000;
+			break;
+		case VPU_VIDEO_HEVC:
+			last = 0x4A010000;
+			last2 = 0x20;
+			break;
+		case VPU_VIDEO_JPEG:
+		default:
+			last = 0x0;
+			break;
+		}
+	} else if (eScodeType == EOS_PADDING_TYPE) {
+		switch (q_data->vdec_std) {
+		case VPU_VIDEO_AVC:
+			last = 0x0B010000;
+			break;
+		case VPU_VIDEO_VC1:
+			last = 0x0a010000;
+			break;
+		case VPU_VIDEO_MPEG2:
+		case VPU_VIDEO_AVS:
+			last = EOS_GENERIC_MPEG;
+			break;
+		case VPU_VIDEO_ASP:
+			last = 0xb1010000;
+			break;
+		case VPU_VIDEO_SPK:
+		case VPU_VIDEO_VP6:
+		case VPU_VIDEO_VP8:
+		case VPU_VIDEO_RV:
+			last = 0x34010000;
+			break;
+		case VPU_VIDEO_JPEG:
+			last = EOS_GENERIC_JPEG;
+			break;
+		case VPU_VIDEO_HEVC:
+			last = 0x4A010000;
+			last2 = 0x20;
+			break;
+		default:
+			last = 0x0;
+			break;
+		}
+	} else {
+		if (q_data->vdec_std == VPU_VIDEO_AVC) {
+			last = 0x15010000;
+			last2 = 0x0;
+		} else {
+			/* all other standards do not support the frame flush mechanism so just return */
+			vpu_dbg(LVL_WARN, "warning: format(%d) not support frame flush mechanism !\n", q_data->vdec_std);
+			goto error;
+		}
+	}
+	plbuffer[0] = last;
+	plbuffer[1] = last2;
+
+	if ((wptr == rptr) || (wptr > rptr)) {
+		if (end - wptr >= SCODE_SIZE) {
+			memcpy(pbbuffer, buffer, SCODE_SIZE);
+			wptr += SCODE_SIZE;
+			if (wptr == end)
+				wptr = start;
+			pad_bytes += SCODE_SIZE;
+		} else {
+			if (rptr - start > SCODE_SIZE - (end - wptr)) {
+				memcpy(pbbuffer, buffer, end - wptr);
+				memcpy(ctx->stream_buffer.dma_virt, buffer + (end - wptr), SCODE_SIZE - (end - wptr));
+				wptr = start + SCODE_SIZE - (end - wptr);
+				pad_bytes += SCODE_SIZE;
+			} else {
+				vpu_err("No enough space to insert padding data, size=%d, rptr(%x), wptr(%x)\n",
+					(end - wptr) + (rptr - start), rptr, wptr);
+			}
+		}
+	} else {
+		if (rptr - wptr >= SCODE_SIZE) {
+			memcpy(pbbuffer, buffer, SCODE_SIZE);
+			wptr += SCODE_SIZE;
+			pad_bytes += SCODE_SIZE;
+		} else	{
+			vpu_err("No enough space to insert padding data, size=%d, rptr(%x), wptr(%x)\n",
+				rptr - wptr, rptr, wptr);
+		}
+	}
+	mb();
+
+	if (bUpdateWr)
+		update_wptr(ctx, pStrBufDesc, wptr);
+	kfree(buffer);
+	atomic64_sub(SCODE_SIZE, &ctx->statistic.total_alloc_size);
+
+	return pad_bytes;
+error:
+	kfree(buffer);
+	atomic64_sub(SCODE_SIZE, &ctx->statistic.total_alloc_size);
+	return 0;
+}
+
+static int add_scode(struct vpu_ctx *ctx, u_int32 uStrBufIdx, VPU_PADDING_SCODE_TYPE eScodeType, bool bUpdateWr)
+{
+	int size = 0;
+
+	if (!ctx)
+		return 0;
+
+	if (eScodeType == EOS_PADDING_TYPE)
+		vpu_dbg(LVL_BIT_FLOW, "ctx[%d] add eos\n", ctx->str_index);
+
+	mutex_lock(&ctx->instance_mutex);
+	size = add_scode_vpu(ctx, uStrBufIdx, eScodeType, bUpdateWr);
+	if (size > 0) {
+		if (!(eScodeType == BUFFLUSH_PADDING_TYPE && ctx->b_dis_reorder))
+			set_pic_end_flag(ctx);
+	} else {
+		size = 0;
+	}
+	mutex_unlock(&ctx->instance_mutex);
+	return size;
+}
+
+TB_API_DEC_FMT vpu_format_remap(uint32_t vdec_std)
+{
+	TB_API_DEC_FMT malone_format = VSys_FrmtNull;
+
+	switch (vdec_std) {
+	case VPU_VIDEO_AVC:
+		malone_format = VSys_AvcFrmt;
+		vpu_dbg(LVL_INFO, "format translated to AVC");
+		break;
+	case VPU_VIDEO_VC1:
+		malone_format = VSys_Vc1Frmt;
+		vpu_dbg(LVL_INFO, "format translated to VC1");
+		break;
+	case VPU_VIDEO_MPEG2:
+		malone_format = VSys_Mp2Frmt;
+		vpu_dbg(LVL_INFO, "format translated to MP2");
+		break;
+	case VPU_VIDEO_AVS:
+		malone_format = VSys_AvsFrmt;
+		vpu_dbg(LVL_INFO, "format translated to AVS");
+		break;
+	case VPU_VIDEO_ASP:
+		malone_format = VSys_AspFrmt;
+		vpu_dbg(LVL_INFO, "format translated to ASP");
+		break;
+	case VPU_VIDEO_JPEG:
+		malone_format = VSys_JpgFrmt;
+		vpu_dbg(LVL_INFO, "format translated to JPG");
+		break;
+	case VPU_VIDEO_VP6:
+		malone_format = VSys_Vp6Frmt;
+		vpu_dbg(LVL_INFO, "format translated to VP6");
+		break;
+	case VPU_VIDEO_SPK:
+		malone_format = VSys_SpkFrmt;
+		vpu_dbg(LVL_INFO, "format translated to SPK");
+		break;
+	case VPU_VIDEO_VP8:
+		malone_format = VSys_Vp8Frmt;
+		vpu_dbg(LVL_INFO, "format translated to VP8");
+		break;
+	case VPU_VIDEO_HEVC:
+		malone_format = VSys_HevcFrmt;
+		vpu_dbg(LVL_INFO, "format translated to HEVC");
+		break;
+	case VPU_VIDEO_RV:
+		malone_format = VSys_RvFrmt;
+		vpu_dbg(LVL_INFO, "format translated to RV");
+		break;
+	case VPU_VIDEO_AVC_MVC:
+		malone_format = VSys_AvcFrmt;
+		vpu_dbg(LVL_INFO, "format translated to AVC");
+		break;
+	default:
+		malone_format = VSys_FrmtNull;
+		vpu_dbg(LVL_INFO, "unspport format");
+		break;
+	}
+	vpu_dbg(LVL_INFO, "\n");
+
+	return malone_format;
+}
+
+static void vpu_dec_send_cmd(struct vpu_dev *dev, u32 idx, u32 cmdid,
+				u32 cmdnum, u32 *local_cmddata)
+{
+	WARN_ON(!dev || idx >= VPU_MAX_NUM_STREAMS);
+
+	if (!rpc_check_is_ready(&dev->shared_mem, idx))
+		vpu_err("[%d] is not ready\n", idx);
+	mutex_lock(&dev->cmd_mutex);
+	rpc_send_cmd_buf(&dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
+	mb();
+	vpu_mu_send_msg(dev, COMMAND, 0xffff);
+	mutex_unlock(&dev->cmd_mutex);
+}
+
+static void do_send_cmd_to_firmware(struct vpu_ctx *ctx,
+				uint32_t idx, uint32_t cmdid,
+				uint32_t cmdnum, uint32_t *local_cmddata)
+{
+	vpu_log_cmd(cmdid, idx);
+	count_cmd(&ctx->statistic, cmdid);
+	record_log_info(ctx, LOG_COMMAND, cmdid, 0);
+
+	vpu_dec_send_cmd(ctx->dev, idx, cmdid, cmdnum, local_cmddata);
+}
+
+static struct vpu_dec_cmd_request vpu_dec_cmds[] = {
+	{
+		.request = VID_API_CMD_START,
+		.response = VID_API_EVENT_START_DONE,
+		.block = true,
+	},
+	{
+		.request = VID_API_CMD_STOP,
+		.response = VID_API_EVENT_STOPPED,
+		.block = true,
+	},
+	{
+		.request = VID_API_CMD_ABORT,
+		.response = VID_API_EVENT_ABORT_DONE,
+		.block = true,
+	},
+	{
+		.request = VID_API_CMD_RST_BUF,
+		.response = VID_API_EVENT_STR_BUF_RST,
+		.block = true,
+	}
+};
+
+static struct vpu_dec_cmd_request *get_cmd_request(struct vpu_ctx *ctx,
+							u32 cmdid)
+{
+	struct vpu_dec_cmd_request *request;
+	int i;
+
+	request = vzalloc(sizeof(*request));
+	if (!request)
+		return NULL;
+
+	atomic64_add(sizeof(*request), &ctx->statistic.total_alloc_size);
+	request->request = cmdid;
+	request->response = VID_API_EVENT_INVALID;
+	request->block = false;
+	for (i = 0; i < ARRAY_SIZE(vpu_dec_cmds); i++) {
+		if (vpu_dec_cmds[i].request == cmdid) {
+			memcpy(request, &vpu_dec_cmds[i], sizeof(*request));
+			break;
+		}
+	}
+
+	return request;
+}
+
+static void put_cmd_request(struct vpu_ctx *ctx,
+				struct vpu_dec_cmd_request *request)
+{
+	if (!request)
+		return;
+
+	atomic64_sub(sizeof(*request), &ctx->statistic.total_alloc_size);
+	vfree(request);
+}
+
+static void vpu_dec_cleanup_cmd(struct vpu_ctx *ctx)
+{
+	struct vpu_dec_cmd_request *request;
+	struct vpu_dec_cmd_request *tmp;
+
+	mutex_lock(&ctx->cmd_lock);
+	if (ctx->pending) {
+		vpu_err("ctx[%d]'s cmd(%s) is not finished yet\n",
+			ctx->str_index, get_cmd_str(ctx->pending->request));
+		put_cmd_request(ctx, ctx->pending);
+		ctx->pending = NULL;
+	}
+	list_for_each_entry_safe(request, tmp, &ctx->cmd_q, list) {
+		list_del_init(&request->list);
+		vpu_err("cmd(%s) of ctx[%d] is missed\n",
+				get_cmd_str(request->request), ctx->str_index);
+		put_cmd_request(ctx, request);
+	}
+	mutex_unlock(&ctx->cmd_lock);
+}
+
+static void process_cmd_request(struct vpu_ctx *ctx)
+{
+	struct vpu_dec_cmd_request *request;
+	struct vpu_dec_cmd_request *tmp;
+
+	if (ctx->pending)
+		return;
+
+	list_for_each_entry_safe(request, tmp, &ctx->cmd_q, list) {
+		list_del_init(&request->list);
+		do_send_cmd_to_firmware(ctx,
+					request->idx,
+					request->request,
+					request->num,
+					request->data);
+		if (request->block &&
+				request->response != VID_API_EVENT_INVALID) {
+			ctx->pending = request;
+			break;
+		}
+		put_cmd_request(ctx, request);
+	}
+}
+
+static void vpu_dec_request_cmd(struct vpu_ctx *ctx,
+				uint32_t idx, uint32_t cmdid,
+				uint32_t cmdnum, uint32_t *local_cmddata)
+{
+	struct vpu_dec_cmd_request *request;
+	u32 i;
+
+	if (cmdnum > VPU_DEC_CMD_DATA_MAX_NUM) {
+		vpu_err("cmd(%s)'s data number(%d) > %d, drop it\n",
+			get_cmd_str(cmdid), cmdnum, VPU_DEC_CMD_DATA_MAX_NUM);
+		return;
+	}
+
+	request = get_cmd_request(ctx, cmdid);
+	if (!request) {
+		vpu_err("cmd(%s) of ctx[%d] is missed\n",
+				get_cmd_str(cmdid), idx);
+		return;
+	}
+
+	request->idx = idx;
+	request->num = cmdnum;
+	for (i = 0; i < cmdnum && i < ARRAY_SIZE(request->data); i++)
+		request->data[i] = local_cmddata[i];
+
+	mutex_lock(&ctx->cmd_lock);
+	list_add_tail(&request->list, &ctx->cmd_q);
+	process_cmd_request(ctx);
+	mutex_unlock(&ctx->cmd_lock);
+}
+
+static void vpu_dec_response_cmd(struct vpu_ctx *ctx, u32 event)
+{
+	mutex_lock(&ctx->cmd_lock);
+	if (ctx->pending && event == ctx->pending->response) {
+		put_cmd_request(ctx, ctx->pending);
+		ctx->pending = NULL;
+	}
+
+	process_cmd_request(ctx);
+	mutex_unlock(&ctx->cmd_lock);
+}
+
+static void vpu_dec_clear_pending_cmd(struct vpu_ctx *ctx)
+{
+	mutex_lock(&ctx->cmd_lock);
+	if (ctx->pending) {
+		put_cmd_request(ctx, ctx->pending);
+		ctx->pending = NULL;
+	}
+	mutex_unlock(&ctx->cmd_lock);
+}
+
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx,
+				uint32_t idx, uint32_t cmdid,
+				uint32_t cmdnum, uint32_t *local_cmddata)
+{
+	vpu_dec_request_cmd(ctx, idx, cmdid, cmdnum, local_cmddata);
+}
+
+static void dump_input_data_to_local(struct vpu_ctx *ctx, void *src, u_int32 len)
+{
+	struct file *fp;
+	char input_file[64];
+
+	if (!vpu_datadump_ena)
+		return;
+
+	scnprintf(input_file, sizeof(input_file) - 1,
+			"/data/vpu_input_data_%d.bin", ctx->str_index);
+
+	if (ctx->first_dump_data_flag) {
+		fp = filp_open(input_file, O_RDWR | O_TRUNC | O_CREAT, 0644);
+		ctx->first_dump_data_flag = false;
+	} else {
+		fp = filp_open(input_file, O_RDWR | O_APPEND | O_CREAT, 0644);
+	}
+	if (IS_ERR(fp)) {
+		vpu_dbg(LVL_WARN, "warning: open file(%s) fail\n", input_file);
+		return;
+	}
+
+	kernel_write(fp, src, len, &(fp->f_pos));
+	filp_close(fp, NULL);
+}
+
+static int send_start_cmd(struct vpu_ctx *ctx)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	u_int32 uStrBufIdx = 0; //set to be default 0, FIX_ME later
+	MediaIPFW_Video_UData *pUdataBuf;
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	MediaIPFW_Video_CodecParams *pCodecPara;
+	unsigned int *CurrStrfg;
+	u32 vdec_std;
+
+	if (!ctx)
+		return -EINVAL;
+	if (vpu_dec_is_active(ctx))
+		return -EINVAL;
+
+	pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	pUdataBuf = &pSharedInterface->UDataBuffer[ctx->str_index];
+	pCodecPara = ctx->dev->shared_mem.codec_mem_vir;
+	CurrStrfg = &pSharedInterface->StreamConfig[ctx->str_index];
+	vdec_std = ctx->q_data[V4L2_SRC].vdec_std;
+
+	vpu_dbg(LVL_WARN, "firmware version is %d.%d.%d\n",
+			(pSharedInterface->FWVersion & 0x00ff0000) >> 16,
+			(pSharedInterface->FWVersion & 0x0000ff00) >> 8,
+			pSharedInterface->FWVersion & 0x000000ff);
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	pStrBufDesc->wptr = ctx->stream_buffer.dma_phy;
+	pStrBufDesc->rptr = ctx->stream_buffer.dma_phy;
+	pStrBufDesc->start = ctx->stream_buffer.dma_phy;
+	pStrBufDesc->end = ctx->stream_buffer.dma_phy + ctx->stream_buffer.dma_size;
+	pStrBufDesc->LWM = 0x01;
+	ctx->beginning = pStrBufDesc->start;
+
+	pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
+		(VPU_REG_BASE + get_str_buffer_desc_offset(ctx));
+	pUdataBuf->uUDataBase = ctx->udata_buffer.dma_phy;
+	pUdataBuf->uUDataSlotSize = ctx->udata_buffer.dma_size;
+	VID_STREAM_CONFIG_FORMAT_SET(vpu_format_remap(vdec_std), CurrStrfg);
+
+	if (vdec_std == VPU_VIDEO_JPEG) {
+		MediaIPFW_Video_JpegParams *pJpgPara;
+
+		pJpgPara = (MediaIPFW_Video_JpegParams *)ctx->dev->shared_mem.jpeg_mem_vir;
+		pJpgPara[ctx->str_index].uJpgMjpegMode = 1; //1:JPGD_MJPEG_MODE_A; 2:JPGD_MJPEG_MODE_B
+		pJpgPara[ctx->str_index].uJpgMjpegInterlaced = 0; //0: JPGD_MJPEG_PROGRESSIVE
+	}
+
+	if (ctx->b_dis_reorder)
+		pCodecPara[ctx->str_index].uDispImm = 1;
+	else
+		pCodecPara[ctx->str_index].uDispImm = 0;
+
+	pCodecPara[ctx->str_index].uEnableDbgLog = CHECK_BIT(vpu_frmdbg_ena, ctx->str_index) ? 1 : 0;
+	pSharedInterface->DbgLogDesc.uDecStatusLogLevel = vpu_frmdbg_level;
+
+	ctx->frm_dis_delay = 0;
+	ctx->frm_dec_delay = 0;
+	ctx->frm_total_num = 0;
+	fill_stream_buffer_info(ctx);
+
+	v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_START, 0, NULL);
+	ctx->firmware_stopped = false;
+	ctx->first_data_flag = true;
+
+	vpu_calculate_performance(ctx, 0xff, "send start cmd");
+
+	return 0;
+}
+
+static void activate_vpu_dec(struct vpu_ctx *ctx)
+{
+	int ret;
+
+	vpu_calculate_performance(ctx, 0xff, "alloc stream buffer begin");
+	ret = alloc_vpu_buffer(ctx);
+	if (ret) {
+		vpu_err("alloc vpu buffer fail\n");
+		return;
+	}
+	vpu_calculate_performance(ctx, 0xff, "alloc stream buffer finish");
+
+	send_start_cmd(ctx);
+}
+
+u_int32 got_free_space(u_int32 wptr, u_int32 rptr, u_int32 start, u_int32 end)
+{
+	u_int32 freespace = 0;
+
+	if (wptr == rptr)
+		freespace = end - start;
+	if (wptr < rptr)
+		freespace = rptr - wptr;
+	if (wptr > rptr)
+		freespace = (end - wptr) + (rptr - start);
+	return freespace;
+}
+
+static u32 got_used_space(u32 wptr, u32 rptr, u32 start, u32 end)
+{
+	u32 stream_size = 0;
+
+	if (wptr == rptr)
+		stream_size = 0;
+	else if (rptr < wptr)
+		stream_size = wptr - rptr;
+	else
+		stream_size = (end - rptr) + (wptr - start);
+
+	return stream_size;
+}
+
+int copy_buffer_to_stream(struct vpu_ctx *ctx, void *buffer, uint32_t length)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	void *wptr_virt;
+	uint32_t wptr;
+	uint32_t rptr;
+	uint32_t start;
+	uint32_t end;
+
+	if (!ctx || !buffer || !length)
+		return 0;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	wptr = pStrBufDesc->wptr;
+	rptr = pStrBufDesc->rptr;
+	start = pStrBufDesc->start;
+	end = pStrBufDesc->end;
+
+	if (start != ctx->stream_buffer.dma_phy ||
+			end != ctx->stream_buffer.dma_phy + ctx->stream_buffer.dma_size) {
+		vpu_err("error: %s(), start or end pointer cross-border\n", __func__);
+		return 0;
+	}
+	if (wptr < start || wptr > end) {
+		vpu_err("error: %s(), wptr pointer cross-border\n", __func__);
+		return 0;
+	}
+	if (rptr < start || rptr > end) {
+		vpu_err("error: %s(), rptr pointer cross-border\n", __func__);
+		return 0;
+	}
+
+
+	wptr_virt = (void *)ctx->stream_buffer.dma_virt + wptr - start;
+	if ((wptr == rptr) || (wptr > rptr)) {
+		if (end - wptr >= length) {
+			memcpy(wptr_virt, buffer, length);
+			wptr += length;
+			if (wptr == end)
+				wptr = start;
+		} else {
+			memcpy(wptr_virt, buffer, end-wptr);
+			memcpy(ctx->stream_buffer.dma_virt, buffer + (end-wptr), length - (end-wptr));
+			wptr = start + length - (end - wptr);
+		}
+	} else {
+		memcpy(wptr_virt, buffer, length);
+		wptr += length;
+	}
+	dump_input_data_to_local(ctx, buffer, length);
+	mb();
+	update_wptr(ctx, pStrBufDesc, wptr);
+	return length;
+}
+
+static int send_abort_cmd(struct vpu_ctx *ctx)
+{
+	int size;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (!vpu_dec_is_active(ctx))
+		return 0;
+
+	ctx->wait_rst_done = true;
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] send ABORT CMD\n", ctx->str_index);
+	size = add_scode(ctx, 0, BUFABORT_PADDING_TYPE, false);
+	record_log_info(ctx, LOG_PADDING, 0, 0);
+	if (size <= 0)
+		vpu_err("%s(): failed to fill abort padding data\n", __func__);
+	reinit_completion(&ctx->completion);
+	v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_ABORT, 1, &size);
+	if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
+		ctx->hang_status = true;
+		vpu_err("the path id: %d firmware timeout after send %s\n",
+			ctx->str_index, get_cmd_str(VID_API_CMD_ABORT));
+		vpu_dec_clear_pending_cmd(ctx);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int send_stop_cmd(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	if (!vpu_dec_is_active(ctx))
+		return 0;
+
+	ctx->wait_rst_done = true;
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] send STOP CMD\n", ctx->str_index);
+	reinit_completion(&ctx->stop_cmp);
+	v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_STOP, 0, NULL);
+	if (!wait_for_completion_timeout(&ctx->stop_cmp, msecs_to_jiffies(1000))) {
+
+		vpu_dec_clear_pending_cmd(ctx);
+		ctx->hang_status = true;
+		vpu_err("the path id: %d firmware timeout after send %s\n",
+			ctx->str_index, get_cmd_str(VID_API_CMD_STOP));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int vpu_dec_cmd_reset(struct vpu_ctx *ctx)
+{
+	int ret = 0;
+
+	if (!ctx)
+		return -EPERM;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] reset decoder\n", ctx->str_index);
+
+	if (ctx->hang_status) {
+		vpu_dbg(LVL_WARN, "warning: %s() failed. hang_status: %d\n",
+			__func__, ctx->hang_status);
+		return -EPERM;
+	}
+
+	ret = send_abort_cmd(ctx);
+	if (ret)
+		return ret;
+	ret = send_stop_cmd(ctx);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void vpu_dec_event_decode_error(struct vpu_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_DECODE_ERROR
+	};
+
+	if (!ctx)
+		return;
+
+	vpu_dbg(LVL_BIT_FLOW, "send decode error event\n");
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static int update_stream_addr(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t uStrBufIdx)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+	uint32_t copy_length = 0;
+	uint32_t input_offset = 0;
+	struct VPU_FMT_INFO_ARV *arv_frame;
+	uint32_t i;
+
+	if (q_data->vdec_std != VPU_VIDEO_RV) {
+		if (!check_free_size_pic(ctx, buffer_size))
+			return 0;
+
+		copy_length += insert_scode(ctx, SCODE_NEW_PICTURE, buffer_size, input_buffer);
+		copy_length += copy_buffer_to_stream(ctx, input_buffer, buffer_size);
+	} else {
+		arv_frame = get_arv_info(ctx, input_buffer, buffer_size);
+		if (!arv_frame) {
+			vpu_dbg(LVL_WARN, "warning: %s() get arv frame info failed\n", __func__);
+			return -1;
+		}
+		if (!check_free_size_pic(ctx, buffer_size + arv_frame->slice_num * 16)) {
+			put_arv_info(arv_frame);
+			arv_frame = NULL;
+			return 0;
+		}
+
+		arv_frame->packlen = 20 + 8 * arv_frame->slice_num;
+
+		if (arv_frame->packlen >  buffer_size - input_offset) {
+			put_arv_info(arv_frame);
+			arv_frame = NULL;
+			return -1;
+		}
+
+		copy_length += insert_scode(ctx, SCODE_NEW_PICTURE, buffer_size, input_buffer);
+		copy_length += copy_buffer_to_stream(ctx, input_buffer + input_offset, arv_frame->packlen);
+		input_offset += arv_frame->packlen;
+		for (i = 0; i < arv_frame->slice_num; i++) {
+			if (i == arv_frame->slice_num - 1)
+				arv_frame->packlen = arv_frame->data_len - arv_frame->slice_offset[i];
+			else
+				arv_frame->packlen = arv_frame->slice_offset[i+1] - arv_frame->slice_offset[i];
+			copy_length += insert_scode(ctx, SCODE_NEW_SLICE, arv_frame->packlen, input_buffer + input_offset);
+			copy_length += copy_buffer_to_stream(ctx, input_buffer + input_offset, arv_frame->packlen);
+			input_offset += arv_frame->packlen;
+		}
+
+		put_arv_info(arv_frame);
+		arv_frame = NULL;
+	}
+
+	return copy_length;
+}
+
+static int update_stream_addr_vpu(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t uStrBufIdx)
+{
+	int size = 0;
+
+	if (ctx->wait_rst_done == true)
+		return size;
+
+	mutex_lock(&ctx->instance_mutex);
+	size = update_stream_addr(ctx, input_buffer, buffer_size, uStrBufIdx);
+	mutex_unlock(&ctx->instance_mutex);
+
+	return size;
+}
+
+static int update_stream_addr_bypass(struct vpu_ctx *ctx,
+					void *input_buffer,
+					uint32_t buffer_size)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	uint32_t nfreespace = 0;
+	uint32_t wptr;
+	uint32_t rptr;
+	uint32_t start;
+	uint32_t end;
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	wptr = pStrBufDesc->wptr;
+	rptr = pStrBufDesc->rptr;
+	start = pStrBufDesc->start;
+	end = pStrBufDesc->end;
+	nfreespace = got_free_space(wptr, rptr, start, end);
+
+	if (nfreespace < (buffer_size + MIN_SPACE)) {
+		vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size\n");
+		return 0;
+	}
+	return copy_buffer_to_stream(ctx, input_buffer, buffer_size);
+}
+
+static void fill_stream_buffer_info(struct vpu_ctx *ctx)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	pBUFFER_INFO_TYPE buffer_info;
+	int idx;
+
+	if (!ctx || ctx->str_index < 0 || ctx->str_index >= VPU_MAX_NUM_STREAMS)
+		return;
+
+	idx = ctx->str_index;
+	pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	buffer_info = &pSharedInterface->StreamBuffInfo[idx];
+
+	buffer_info->stream_input_mode = ctx->stream_input_mode;
+	if (ctx->stream_input_mode == NON_FRAME_LVL)
+		buffer_info->stream_buffer_threshold = stream_buffer_threshold;
+	else if (frame_threshold[idx] > 0)
+		buffer_info->stream_buffer_threshold = frame_threshold[idx];
+	else
+		buffer_info->stream_buffer_threshold = 0;
+}
+
+static void set_pic_end_flag(struct vpu_ctx *ctx)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	pBUFFER_INFO_TYPE buffer_info;
+
+	if (!ctx)
+		return;
+
+	pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	buffer_info = &pSharedInterface->StreamBuffInfo[ctx->str_index];
+
+	buffer_info->stream_pic_end_flag = 0x1;
+}
+
+static bool vpu_dec_stream_is_ready(struct vpu_ctx *ctx)
+{
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	u32 stream_size = 0;
+
+	WARN_ON(!ctx);
+
+	if (ctx->fifo_low)
+		return true;
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	stream_size = got_used_space(pStrBufDesc->wptr,
+					pStrBufDesc->rptr,
+					pStrBufDesc->start,
+					pStrBufDesc->end);
+	if (ctx->bs_l_threshold > 0) {
+		if (stream_size < ctx->bs_l_threshold)
+			return true;
+	}
+
+	/*
+	 *frame depth need to be set by user and then the condition works
+	 */
+	if (vpu_frm_depth > 0 && ctx->stream_input_mode == FRAME_LVL) {
+		if (ctx->frm_dec_delay >= vpu_frm_depth)
+			return false;
+	}
+
+	if (ctx->ts_threshold > 0 &&
+		TSM_TS_IS_VALID(ctx->output_ts) &&
+		TSM_TS_IS_VALID(ctx->capture_ts)) {
+		s64 threshold = ctx->ts_threshold * NSEC_PER_MSEC;
+
+		if (ctx->output_ts > ctx->capture_ts + threshold)
+			return false;
+	}
+
+	if (ctx->bs_h_threshold > 0) {
+		if (stream_size > ctx->bs_h_threshold)
+			return false;
+	}
+
+	return true;
+}
+
+static bool verify_decoded_frames(struct vpu_ctx *ctx)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	pBUFFER_INFO_TYPE buffer_info = &pSharedInterface->StreamBuffInfo[ctx->str_index];
+
+	if (ctx->stream_input_mode != FRAME_LVL)
+		return true;
+
+	if (buffer_info->stream_pic_input_count != buffer_info->stream_pic_parsed_count) {
+		vpu_dbg(LVL_WARN,
+			"ctx[%d] amount inconsistent between input(%d) and output(%d)\n",
+			ctx->str_index, buffer_info->stream_pic_input_count,
+			buffer_info->stream_pic_parsed_count);
+		return false;
+	}
+
+	return true;
+}
+
+static bool is_valid_frame(struct vpu_ctx *ctx, struct vb2_buffer *vb)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+
+	if (!ctx || !vb)
+		return false;
+	if (ctx->first_data_flag && single_seq_info_format(q_data))
+		return false;
+	if (is_codec_config_data(vb))
+		return false;
+
+	return true;
+}
+
+static int increase_frame_num(struct vpu_ctx *ctx, struct vb2_buffer *vb)
+{
+	if (!ctx || !vb)
+		return -EINVAL;
+
+	if (is_valid_frame(ctx, vb)) {
+		ctx->frm_dec_delay++;
+		ctx->frm_dis_delay++;
+		ctx->frm_total_num++;
+		fill_stream_buffer_info(ctx);
+	}
+	ctx->first_data_flag = false;
+
+	return 0;
+}
+
+static void enqueue_stream_data(struct vpu_ctx *ctx, uint32_t uStrBufIdx)
+{
+	struct vb2_data_req *p_data_req;
+	struct queue_data *This = &ctx->q_data[V4L2_SRC];
+	void *input_buffer;
+	uint32_t buffer_size;
+	int frame_bytes;
+
+	while (!list_empty(&This->drv_q)) {
+		struct vb2_buffer *vb;
+
+		if (!vpu_dec_stream_is_ready(ctx)) {
+			vpu_dbg(LVL_INFO,
+				"[%d] stream is not ready\n", ctx->str_index);
+			break;
+		}
+		p_data_req = list_first_entry(&This->drv_q,
+				typeof(*p_data_req), list);
+
+		if (!p_data_req->vb2_buf)
+			break;
+
+		vb = p_data_req->vb2_buf;
+		buffer_size = vb->planes[0].bytesused;
+		input_buffer = (void *)vb2_plane_vaddr(vb, 0);
+
+		if (ctx->start_code_bypass)
+			frame_bytes = update_stream_addr_bypass(ctx, input_buffer, buffer_size);
+		else if (ctx->first_data_flag || is_codec_config_data(vb))
+			frame_bytes = insert_scode(ctx, SCODE_NEW_SEQUENCE, buffer_size, input_buffer);
+		else
+			frame_bytes = update_stream_addr_vpu(ctx, input_buffer, buffer_size, uStrBufIdx);
+
+		if (frame_bytes == 0) {
+			vpu_dbg(LVL_INFO, " %s no space to write\n", __func__);
+			return;
+		} else if (frame_bytes < 0) {
+			vpu_dbg(LVL_WARN, "warning: incorrect input buffer data\n");
+		} else {
+			if (ctx->b_dis_reorder && !is_codec_config_data(vb)) {
+				/* frame successfully written into the stream buffer if in special low latency mode
+					mark that this frame should be flushed for decode immediately */
+				frame_bytes += add_scode(ctx,
+							 0,
+							 BUFFLUSH_PADDING_TYPE,
+							 true);
+				record_log_info(ctx, LOG_PADDING, 0, 0);
+			}
+
+			increase_frame_num(ctx, vb);
+
+			record_log_info(ctx, LOG_UPDATE_STREAM, 0, buffer_size);
+			vpu_dec_receive_ts(ctx, vb, frame_bytes);
+			This->process_count++;
+		}
+
+		list_del(&p_data_req->list);
+		p_data_req->queued = false;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+	if (list_empty(&This->drv_q) && ctx->eos_stop_received) {
+		if (vpu_dec_is_active(ctx)) {
+			vpu_dbg(LVL_EVENT, "ctx[%d]: insert eos directly\n", ctx->str_index);
+			if (add_scode(ctx, 0, EOS_PADDING_TYPE, true) > 0) {
+				record_log_info(ctx, LOG_EOS, 0, 0);
+				ctx->eos_stop_received = false;
+				ctx->eos_stop_added = true;
+			}
+		} else	{
+			ctx->eos_stop_received = false;
+			send_eos_event(ctx);
+		}
+	}
+}
+
+//warn uStrIdx need to refine how to handle it
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx)
+{
+	struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+	down(&This->drv_q_lock);
+	enqueue_stream_data(ctx, uStrBufIdx);
+	up(&This->drv_q_lock);
+}
+
+static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
+{
+	struct vb2_data_req *p_data_req;
+	struct queue_data *This = &ctx->q_data[V4L2_DST];
+	u_int32 *FrameInfo = (u_int32 *)frame_info;
+	u_int32 fs_id = FrameInfo[0x0];
+	uint32_t stride = FrameInfo[3];
+	s64 timestamp = ((s32)FrameInfo[9] * NSEC_PER_SEC) + FrameInfo[10];
+	bool b10BitFormat = is_10bit_format(ctx);
+	int buffer_id;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() fs_id=%d, ulFsLumaBase[0]=%x, stride=%d, b10BitFormat=%d, ctx->seqinfo.uBitDepthLuma=%d\n",
+			__func__, fs_id, FrameInfo[1], stride, b10BitFormat, ctx->seqinfo.uBitDepthLuma);
+	vpu_dbg(LVL_BIT_TS, "[OUTPUT TS]%32lld\n", timestamp);
+	ctx->capture_ts = timestamp;
+	v4l2_update_stream_addr(ctx, 0);
+
+	buffer_id = find_buffer_id(ctx, FrameInfo[1]);
+	if (buffer_id == -1) {
+		vpu_err("%s() ctx[%d] not find buffer id: %d, addr: 0x%x\n",
+				__func__, ctx->str_index, fs_id, FrameInfo[1]);
+		return;
+	}
+
+	if (buffer_id != fs_id) {
+		if (fs_id == MEDIA_PLAYER_SKIPPED_FRAME_ID) {
+			down(&This->drv_q_lock);
+			p_data_req = &This->vb2_reqs[buffer_id];
+			set_data_req_status(p_data_req, FRAME_SKIP);
+			up(&This->drv_q_lock);
+
+			send_skip_event(ctx);
+			ctx->frm_dis_delay--;
+			return;
+		}
+		vpu_err("error: find buffer_id(%d) and firmware return id(%d) doesn't match\n",
+				buffer_id, fs_id);
+	}
+
+	ctx->frm_dis_delay--;
+	vpu_dbg(LVL_INFO, "frame total: %d; depth: %d; delay: [dec, dis] = [%d, %d]\n", ctx->frm_total_num,
+		vpu_frm_depth, ctx->frm_dec_delay, ctx->frm_dis_delay);
+
+	down(&This->drv_q_lock);
+	p_data_req = &This->vb2_reqs[buffer_id];
+
+	if (p_data_req->status != FRAME_DECODED)
+		vpu_err("error: buffer(%d) need to set FRAME_READY, but previous state %s is not FRAME_DECODED\n",
+				buffer_id, bufstat[p_data_req->status]);
+	set_data_req_status(p_data_req, FRAME_READY);
+	if (p_data_req->vb2_buf) {
+		p_data_req->vb2_buf->planes[0].bytesused = This->sizeimage[0];
+		p_data_req->vb2_buf->planes[1].bytesused = This->sizeimage[1];
+		p_data_req->vb2_buf->timestamp = timestamp;
+		if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+			vb2_buffer_done(p_data_req->vb2_buf,
+					VB2_BUF_STATE_DONE);
+		else
+			vpu_err("warning: wait_rst_done(%d) check buffer(%d) state(%d)\n",
+					ctx->wait_rst_done, buffer_id, p_data_req->vb2_buf->state);
+	}
+	up(&This->drv_q_lock);
+	vpu_dbg(LVL_INFO, "leave %s\n", __func__);
+}
+
+static void send_skip_event(struct vpu_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_SKIP
+	};
+
+	if (!ctx)
+		return;
+
+	ctx->statistic.skipped_frame_count++;
+	vpu_dbg(LVL_INFO, "send skip event\n");
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static void send_eos_event(struct vpu_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_EOS
+	};
+
+	if (!ctx)
+		return;
+
+	vpu_dbg(LVL_BIT_FLOW, "send eos event\n");
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static void send_source_change_event(struct vpu_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
+	};
+
+	if (!ctx)
+		return;
+
+	ctx->res_change_send_count++;
+	vpu_dbg(LVL_BIT_FLOW, "ctx[%d] send source change event : %dx%d\n",
+		ctx->str_index, ctx->seqinfo.uHorRes, ctx->seqinfo.uVerRes);
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+}
+
+static void reset_mbi_dcp_count(struct vpu_ctx *ctx)
+{
+	free_mbi_buffers(ctx);
+	ctx->mbi_index = 0;
+	ctx->mbi_count = 0;
+	ctx->req_mbi_count = 0;
+	free_dcp_buffers(ctx);
+	ctx->dcp_index = 0;
+	ctx->dcp_count = 0;
+	ctx->req_dcp_count = 0;
+}
+
+static void reset_frame_buffer(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue;
+	struct vb2_data_req *p_data_req = NULL;
+	int i;
+
+	queue = &ctx->q_data[V4L2_DST];
+	for (i = 0; i < queue->vb2_q.num_buffers; i++) {
+		p_data_req = &queue->vb2_reqs[i];
+
+		if (p_data_req->status == FRAME_ALLOC ||
+		    p_data_req->status == FRAME_RELEASE)
+			continue;
+		set_data_req_status(p_data_req, FRAME_RELEASE);
+		release_frame_buffer(ctx, ctx->str_index, p_data_req);
+	}
+}
+
+static bool verify_frame_buffer_size(struct queue_data *q_data,
+							struct vb2_data_req *p_data_req)
+{
+	uint32_t size_0 = 0;
+	uint32_t size_1 = 0;
+	struct vpu_ctx *ctx = container_of(q_data, struct vpu_ctx,
+							q_data[V4L2_DST]);
+
+	if (!q_data || !p_data_req)
+		return false;
+
+	size_0 = p_data_req->vb2_buf->planes[0].length
+				- p_data_req->vb2_buf->planes[0].data_offset;
+	size_1 = p_data_req->vb2_buf->planes[1].length
+		- p_data_req->vb2_buf->planes[1].data_offset;
+	if (size_0 >= q_data->sizeimage[0] && size_1 >= q_data->sizeimage[1])
+		return true;
+
+	vpu_dbg(LVL_WARN, "warning: %s() ctx[%d] frame buffer size is smaller than need\n",
+			__func__, ctx->str_index);
+	return false;
+}
+
+static void add_buffer_to_queue(struct queue_data *q_data, struct vb2_data_req *data_req)
+{
+	if (!q_data || !data_req)
+		return;
+	if (data_req->queued == true)
+		return;
+	if (data_req->vb2_buf->state != VB2_BUF_STATE_ACTIVE)
+		return;
+
+	list_add_tail(&data_req->list, &q_data->drv_q);
+	data_req->queued = true;
+}
+
+static int parse_frame_interval_from_seqinfo(struct vpu_ctx *ctx,
+					MediaIPFW_Video_SeqInfo *seq_info)
+{
+	u32 gcd;
+
+	ctx->frame_interval.numerator = 1000;
+	ctx->frame_interval.denominator = seq_info->FrameRate;
+	if (!seq_info->FrameRate) {
+		vpu_dbg(LVL_INFO, "unknown FrameRate(%d)\n",
+				seq_info->FrameRate);
+		return -EINVAL;
+	}
+
+	gcd = get_greatest_common_divisor(ctx->frame_interval.numerator,
+					ctx->frame_interval.denominator);
+	ctx->frame_interval.numerator /= gcd;
+	ctx->frame_interval.denominator /= gcd;
+
+	return 0;
+}
+
+static struct vb2_data_req *get_frame_buffer(struct queue_data *queue)
+{
+	struct vb2_data_req *p_data_req;
+	struct vb2_data_req *p_temp;
+	bool found = false;
+
+	list_for_each_entry_safe(p_data_req, p_temp, &queue->drv_q, list) {
+		if (!p_data_req->vb2_buf)
+			continue;
+		if (p_data_req->status != FRAME_ALLOC)
+			continue;
+		if (verify_frame_buffer_size(queue, p_data_req)) {
+			list_del(&p_data_req->list);
+			p_data_req->queued = false;
+			found = true;
+			break;
+		}
+	}
+
+	if (!found)
+		return NULL;
+
+	return p_data_req;
+}
+
+static void respond_req_frame_abnormal(struct vpu_ctx *ctx)
+{
+	u32 local_cmddata[10];
+
+	ctx->req_frame_count--;
+	if (ctx->firmware_stopped)
+		return;
+
+	memset(local_cmddata, 0, sizeof(local_cmddata));
+	local_cmddata[0] = (ctx->seqinfo.uActiveSeqTag + 0xf0)<<24;
+	local_cmddata[6] = MEDIAIP_FRAME_REQ;
+	v4l2_vpu_send_cmd(ctx, ctx->str_index,
+			VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+}
+
+static bool alloc_frame_buffer(struct vpu_ctx *ctx,
+				struct queue_data *queue)
+{
+	struct vb2_data_req *p_data_req;
+	u32 local_cmddata[10];
+	dma_addr_t LumaAddr = 0;
+	dma_addr_t ChromaAddr = 0;
+
+	if (!ctx || !queue->enable || ctx->b_firstseq || ctx->firmware_stopped)
+		return false;
+
+	p_data_req = get_frame_buffer(queue);
+	if (!p_data_req)
+		return false;
+
+	LumaAddr = p_data_req->phy_addr[0] + p_data_req->data_offset[0];
+	ChromaAddr = p_data_req->phy_addr[1] + p_data_req->data_offset[1];
+	vpu_dbg(LVL_INFO, "%s() :LumaAddr(%llx) ChromaAddr(%llx) buf_id (%d)\n",
+			__func__, LumaAddr, ChromaAddr, p_data_req->id);
+
+	p_data_req->seq_tag = ctx->seqinfo.uActiveSeqTag;
+	memset(local_cmddata, 0, sizeof(local_cmddata));
+	local_cmddata[0] = p_data_req->id | (p_data_req->seq_tag << 24);
+	local_cmddata[1] = LumaAddr;
+	local_cmddata[2] = local_cmddata[1] + queue->sizeimage[0]/2;
+	local_cmddata[3] = ChromaAddr;
+	local_cmddata[4] = local_cmddata[3] + queue->sizeimage[1]/2;
+	local_cmddata[5] = queue->stride;
+	local_cmddata[6] = MEDIAIP_FRAME_REQ;
+
+	ctx->req_frame_count--;
+	v4l2_vpu_send_cmd(ctx, ctx->str_index,
+			VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+	set_data_req_status(p_data_req, FRAME_FREE);
+	vpu_dbg(LVL_INFO,
+		"VID_API_CMD_FS_ALLOC, ctx[%d] vb2_buf=%p, id=%d\n",
+		ctx->str_index, p_data_req->vb2_buf, p_data_req->id);
+
+	return true;
+}
+
+static bool alloc_mbi_to_firmware(struct vpu_ctx *ctx,
+				struct queue_data *queue)
+{
+	struct dma_buffer *buffer;
+	u_int32 local_cmddata[10];
+	u32 index;
+
+	if (!ctx || !queue || !ctx->mbi_size)
+		return false;
+
+	buffer = &ctx->mbi_buffer[ctx->mbi_index];
+	if (!buffer->dma_virt || buffer->dma_size < ctx->mbi_size)
+		return false;
+
+	index = ctx->str_index;
+	local_cmddata[0] = ctx->mbi_index | (ctx->seqinfo.uActiveSeqTag<<24);
+	local_cmddata[1] = ctx->mbi_buffer[ctx->mbi_index].dma_phy;
+	local_cmddata[2] = ctx->mbi_buffer[ctx->mbi_index].dma_size;
+	local_cmddata[3] = 0;
+	local_cmddata[4] = 0;
+	local_cmddata[5] = 0;
+	local_cmddata[6] = MEDIAIP_MBI_REQ;
+	v4l2_vpu_send_cmd(ctx, index, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+	vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, ctx[%d] eType=%d, index=%d\n",
+		ctx->str_index, MEDIAIP_MBI_REQ, ctx->mbi_index);
+	ctx->mbi_index++;
+
+	return true;
+}
+
+static bool alloc_dcp_to_firmware(struct vpu_ctx *ctx,
+				struct queue_data *queue)
+{
+	struct dma_buffer *buffer;
+	u_int32 local_cmddata[10];
+	u32 index;
+
+	if (!ctx || !queue || !ctx->dcp_size)
+		return false;
+
+	buffer = &ctx->dcp_buffer[ctx->dcp_index];
+	if (!buffer->dma_virt || buffer->dma_size < ctx->dcp_size)
+		return false;
+
+	index = ctx->str_index;
+	local_cmddata[0] = ctx->dcp_index | (ctx->seqinfo.uActiveSeqTag<<24);
+	local_cmddata[1] = ctx->dcp_buffer[ctx->dcp_index].dma_phy;
+	local_cmddata[2] = ctx->dcp_size;
+	local_cmddata[3] = 0;
+	local_cmddata[4] = 0;
+	local_cmddata[5] = 0;
+	local_cmddata[6] = MEDIAIP_DCP_REQ;
+	v4l2_vpu_send_cmd(ctx, index, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+	vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, ctx[%d] eType=%d, index=%d\n",
+		ctx->str_index, MEDIAIP_DCP_REQ, ctx->dcp_index);
+	ctx->dcp_index++;
+	return true;
+}
+
+static void check_wait_res_changed(struct vpu_ctx *ctx)
+{
+	struct queue_data *q_data = &ctx->q_data[V4L2_DST];
+	struct vb2_data_req *p_data_req;
+	struct vb2_data_req *p_temp;
+
+	if (!q_data->enable)
+		return;
+
+	list_for_each_entry_safe(p_data_req, p_temp, &q_data->drv_q, list) {
+		if (!p_data_req->vb2_buf)
+			continue;
+		if (verify_frame_buffer_size(q_data, p_data_req)) {
+			ctx->res_change_done_count++;
+			ctx->wait_res_change_done = false;
+			vpu_dbg(LVL_BIT_FLOW,
+				"ctx[%d] res change done, %d, %d, %d\n",
+				ctx->str_index,
+				ctx->res_change_occu_count,
+				ctx->res_change_send_count,
+				ctx->res_change_done_count);
+				vpu_calculate_performance(ctx, 0xff, "first provide buffer");
+			break;
+		}
+	}
+}
+
+static void respond_req_frame(struct vpu_ctx *ctx,
+				struct queue_data *queue,
+				bool abnormal)
+{
+	if (ctx->wait_res_change_done) {
+		if (ctx->seek_flag)
+			return;
+		check_wait_res_changed(ctx);
+	}
+
+	if (ctx->wait_res_change_done)
+		return;
+
+	while (ctx->req_frame_count > 0) {
+		if (abnormal) {
+			respond_req_frame_abnormal(ctx);
+			continue;
+		}
+		if (!queue->enable)
+			break;
+		if (!alloc_frame_buffer(ctx, queue))
+			break;
+	}
+	while (ctx->mbi_index < ctx->mbi_count) {
+		if (!queue->enable)
+			break;
+		if (!alloc_mbi_to_firmware(ctx, queue))
+			break;
+	}
+	while (ctx->dcp_index < ctx->dcp_count) {
+		if (!queue->enable)
+			break;
+		if (!alloc_dcp_to_firmware(ctx, queue))
+			break;
+	}
+}
+
+static void release_frame_buffer(struct vpu_ctx *ctx,
+				u32 uStrIdx,
+				struct vb2_data_req *p_data_req)
+{
+	u32 local_cmddata[1];
+
+	local_cmddata[0] = p_data_req->id | (p_data_req->seq_tag << 24);
+	v4l2_vpu_send_cmd(ctx, uStrIdx,
+			VID_API_CMD_FS_RELEASE, 1, local_cmddata);
+	set_data_req_status(p_data_req, FRAME_ALLOC);
+}
+
+static void get_seq_info(MediaIPFW_Video_SeqInfo *pSeqInfo,
+			u32 *event_data,
+			MediaIPFW_Video_SeqInfo *pRpcSeqInfo)
+{
+	memset(pSeqInfo, 0, sizeof(*pSeqInfo));
+
+	if (event_data && event_data[0]) {
+		pSeqInfo->uNumRefFrms = event_data[0];
+		pSeqInfo->uNumDPBFrms = event_data[1];
+		pSeqInfo->uNumDFEAreas = event_data[2];
+		pSeqInfo->uProgressive = event_data[3];
+		pSeqInfo->uVerRes = event_data[4];
+		pSeqInfo->uHorRes = event_data[5];
+		pSeqInfo->uParWidth = event_data[6];
+		pSeqInfo->uParHeight = event_data[7];
+		pSeqInfo->FrameRate = event_data[8];
+		pSeqInfo->UDispAspRatio = event_data[9];
+		pSeqInfo->uLevelIDC = event_data[10];
+		pSeqInfo->uVerDecodeRes = event_data[11];
+		pSeqInfo->uHorDecodeRes = event_data[12];
+		pSeqInfo->uBitDepthLuma = event_data[13];
+		pSeqInfo->uBitDepthChroma = event_data[14];
+		pSeqInfo->uChromaFmt = event_data[15];
+		pSeqInfo->uColorDesc = event_data[16];
+		pSeqInfo->uTransferChars = event_data[17];
+		pSeqInfo->uMatrixCoeffs = event_data[18];
+		pSeqInfo->uVideoFullRangeFlag = event_data[19];
+		pSeqInfo->uVUIPresent = event_data[20];
+		pSeqInfo->uMVCNumViews = event_data[21];
+		pSeqInfo->uFrameCropValid = event_data[22];
+		pSeqInfo->uFrameCropLeftOffset = event_data[23];
+		pSeqInfo->uFrameCropRightOffset = event_data[24];
+		pSeqInfo->uFrameCropTopOffset = event_data[25];
+		pSeqInfo->uFrameCropBottomOffset = event_data[25];
+		pSeqInfo->uActiveSeqTag = event_data[27];
+		return;
+	}
+
+	memcpy(pSeqInfo, pRpcSeqInfo, sizeof(*pSeqInfo));
+}
+
+static bool check_seq_info_is_valid(u32 ctx_id, MediaIPFW_Video_SeqInfo *info)
+{
+	if (!info)
+		return false;
+
+	if (!info->uHorRes || !info->uVerRes) {
+		vpu_err("ctx[%d] invalid seq info : %d x %d\n",
+			ctx_id, info->uHorRes, info->uVerRes);
+		return false;
+	}
+	if (info->uHorRes > VPU_DEC_MAX_WIDTH ||
+			info->uVerRes > VPU_DEC_MAX_HEIGTH) {
+		vpu_err("ctx[%d] invalid seq info : %d x %d\n",
+			ctx_id, info->uHorRes, info->uVerRes);
+		return false;
+	}
+
+	return true;
+}
+
+static bool check_res_is_changed(struct vpu_ctx *ctx,
+				MediaIPFW_Video_SeqInfo *pSeqInfo)
+{
+	if (ctx->seqinfo.uHorDecodeRes != pSeqInfo->uHorDecodeRes)
+		return true;
+	if (ctx->seqinfo.uVerDecodeRes != pSeqInfo->uVerDecodeRes)
+		return true;
+	if (ctx->seqinfo.uNumRefFrms != pSeqInfo->uNumRefFrms)
+		return true;
+	if (ctx->seqinfo.uNumDPBFrms != pSeqInfo->uNumDPBFrms)
+		return true;
+	if (ctx->seqinfo.uBitDepthLuma != pSeqInfo->uBitDepthLuma)
+		return true;
+	if (ctx->seqinfo.uBitDepthChroma != pSeqInfo->uBitDepthChroma)
+		return true;
+
+	return false;
+}
+
+static bool check_is_need_reset_after_abort(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return false;
+	if (ctx->b_firstseq)
+		return true;
+	if (!ctx->frame_decoded)
+		return true;
+
+	return false;
+}
+
+static struct vpu_dec_perf_queue *get_dec_perf_queue(struct vpu_ctx *ctx)
+{
+	struct vpu_dec_perf_queue *perf;
+
+	perf = vzalloc(sizeof(*perf));
+	if (!perf)
+		return NULL;
+
+	atomic64_add(sizeof(*perf), &ctx->statistic.total_alloc_size);
+
+	return perf;
+}
+
+static void put_dec_perf_queue(struct vpu_ctx *ctx, struct vpu_dec_perf_queue *perf)
+{
+	if (!perf)
+		return;
+
+	vfree(perf);
+	atomic64_sub(sizeof(*perf), &ctx->statistic.total_alloc_size);
+}
+
+static void cleanup_perf_queue(struct vpu_ctx *ctx)
+{
+	struct vpu_dec_perf_queue *perf;
+	struct vpu_dec_perf_queue *tmp;
+
+	mutex_lock(&ctx->perf_lock);
+	list_for_each_entry_safe(perf, tmp, &ctx->perf_q, list) {
+		list_del_init(&perf->list);
+		put_dec_perf_queue(ctx, perf);
+	}
+	mutex_unlock(&ctx->perf_lock);
+}
+
+static void vpu_calculate_performance(struct vpu_ctx *ctx,  u_int32 uEvent, const char *str)
+{
+	u_int64 Time;
+	u_int64 total_Time;
+	struct timespec64 ts;
+	struct vpu_dec_perf_queue *perf;
+
+	if (!vpu_show_perf_ena)
+		return;
+	if (!(vpu_show_perf_idx & (1<<ctx->str_index)))
+		return;
+
+	ktime_get_real_ts64(&ts);
+	Time = ((ts.tv_sec * 1000000000ULL) + ts.tv_nsec) / 1000000ULL;
+
+	switch (uEvent) {
+	case VID_API_EVENT_PIC_DECODED:
+		if (ctx->statistic.event[VID_API_EVENT_PIC_DECODED] == 1) {
+			ctx->perf_time.first_decoded_time = Time - 1;
+			ctx->perf_time.last_decoded_time = Time - 1;
+		}
+
+		ctx->perf_time.cur_decoded_interv = Time - ctx->perf_time.last_decoded_time;
+		total_Time = Time - ctx->perf_time.first_decoded_time;
+		ctx->perf_time.decoded_fps = ctx->statistic.event[VID_API_EVENT_PIC_DECODED] * 1000ULL / total_Time;
+		ctx->perf_time.last_decoded_time = Time;
+		if (vpu_show_perf_ent & VPU_DECODED_EVENT_PERF_MASK)
+			vpu_dbg(LVL_WARN, "[%2d] dec[%8ld]  interv: %8ld ms  fps: %ld\n",
+				ctx->str_index,
+				ctx->statistic.event[VID_API_EVENT_PIC_DECODED],
+				ctx->perf_time.cur_decoded_interv,
+				ctx->perf_time.decoded_fps);
+
+		break;
+	case VID_API_EVENT_FRAME_BUFF_RDY:
+		if (ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY] == 1) {
+			ctx->perf_time.first_ready_time = Time - 1;
+			ctx->perf_time.last_ready_time = Time - 1;
+		}
+
+		ctx->perf_time.cur_ready_interv = Time - ctx->perf_time.last_ready_time;
+		total_Time = Time - ctx->perf_time.first_ready_time;
+		ctx->perf_time.ready_fps = ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY] * 1000ULL / total_Time;
+		ctx->perf_time.last_ready_time = Time;
+		if (vpu_show_perf_ent & VPU_READY_EVENT_PERF_MASK)
+			vpu_dbg(LVL_WARN, "[%2d] rdy[%8ld]  interv: %8ld ms  fps: %ld\n",
+				ctx->str_index,
+				ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY],
+				ctx->perf_time.cur_ready_interv,
+				ctx->perf_time.ready_fps);
+
+		break;
+	default:
+		break;
+	}
+
+	if (ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY] > 1)
+		return;
+
+	if (str != NULL) {
+		perf = get_dec_perf_queue(ctx);
+		if (!perf) {
+			vpu_err("get_dec_perf_queue fail\n");
+			return;
+		}
+
+		scnprintf(perf->str, (VPU_MAX_STEP_STRING_LENGTH - 1), str);
+		perf->time = Time;
+
+		mutex_lock(&ctx->perf_lock);
+		list_add_tail(&perf->list, &ctx->perf_q);
+		mutex_unlock(&ctx->perf_lock);
+	}
+}
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data)
+{
+	struct vpu_dev *dev;
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+
+	vpu_log_event(uEvent, uStrIdx);
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+	record_log_info(ctx, LOG_EVENT, uEvent, pStrBufDesc->rptr);
+
+	if (ctx == NULL) {
+		vpu_err("receive event: 0x%X after instance released, ignore it\n", uEvent);
+		return;
+	}
+
+	if (ctx->firmware_stopped) {
+		switch (uEvent) {
+		case VID_API_EVENT_START_DONE:
+		case VID_API_EVENT_FIRMWARE_XCPT:
+			break;
+		case VID_API_EVENT_FIFO_LOW:
+			return;
+		default:
+			vpu_err("receive event: 0x%X after stopped, ignore it\n", uEvent);
+			return;
+		}
+	}
+
+	dev = ctx->dev;
+	pSharedInterface = (pDEC_RPC_HOST_IFACE)dev->shared_mem.shared_mem_vir;
+
+	vpu_dec_response_cmd(ctx, uEvent);
+	switch (uEvent) {
+	case VID_API_EVENT_START_DONE:
+		vpu_dbg(LVL_BIT_FLOW, "ctx[%d] START DONE\n", ctx->str_index);
+		ctx->firmware_stopped = false;
+		ctx->firmware_finished = false;
+		ctx->req_frame_count = 0;
+		reset_mbi_dcp_count(ctx);
+		vpu_calculate_performance(ctx, uEvent, "start done");
+		break;
+	case VID_API_EVENT_STOPPED: {
+		vpu_dbg(LVL_INFO, "receive VID_API_EVENT_STOPPED\n");
+		vpu_dbg(LVL_BIT_FLOW,
+			"ctx[%d] STOPPED, output qbuf(%ld), dqbuf(%ld)\n",
+			ctx->str_index,
+			ctx->q_data[V4L2_SRC].qbuf_count,
+			ctx->q_data[V4L2_SRC].dqbuf_count);
+		ctx->firmware_stopped = true;
+		ctx->frame_decoded = false;
+		ctx->wait_rst_done = false;
+		/* This also can fix an Andorid case indirectly:
+		 * seek in the beginning, but has not do capture port
+		 * streamoff/on when receive res changed event, then will cause
+		 * seek_flag status incorrect.
+		 * If abort before receive seq_hdr_found evnt will call stop cmd
+		 * to fw, then will reset seek_flag and wait_res_change_done.
+		 */
+		ctx->wait_res_change_done = false;
+		ctx->seek_flag = false;
+		ctx->res_change_occu_count = 0;
+		ctx->res_change_send_count = 0;
+		ctx->res_change_done_count = 0;
+		ctx->fifo_low = false;
+		down(&ctx->q_data[V4L2_DST].drv_q_lock);
+		ctx->b_firstseq = true;
+		respond_req_frame(ctx, &ctx->q_data[V4L2_DST], true);
+		reset_mbi_dcp_count(ctx);
+		memset(&ctx->seqinfo, 0, sizeof(MediaIPFW_Video_SeqInfo));
+		up(&ctx->q_data[V4L2_DST].drv_q_lock);
+		vpu_dec_cleanup_event(ctx);
+		complete(&ctx->completion);//reduce possibility of abort hang if decoder enter stop automatically
+		complete(&ctx->stop_cmp);
+		}
+		break;
+	case VID_API_EVENT_RESET_DONE:
+		break;
+	case VID_API_EVENT_PIC_DECODED: {
+		MediaIPFW_Video_QMeterInfo *pQMeterInfo = (MediaIPFW_Video_QMeterInfo *)dev->shared_mem.qmeter_mem_vir;
+		MediaIPFW_Video_PicInfo *pPicInfo = (MediaIPFW_Video_PicInfo *)dev->shared_mem.pic_mem_vir;
+		MediaIPFW_Video_PicDispInfo *pDispInfo = &pPicInfo[uStrIdx].DispInfo;
+		MediaIPFW_Video_PicPerfInfo *pPerfInfo = &pPicInfo[uStrIdx].PerfInfo;
+		MediaIPFW_Video_PicPerfDcpInfo *pPerfDcpInfo = &pPicInfo[uStrIdx].PerfDcpInfo;
+		int buffer_id;
+		u_int32 uDecFrmId = event_data[7];
+		u_int32 uPicStartAddr = event_data[10];
+		struct queue_data *This = &ctx->q_data[V4L2_DST];
+		u_int32 uDpbmcCrc;
+		size_t wr_size;
+		struct vb2_data_req *p_data_req = NULL;
+		u32 consumed_count = event_data[13];
+
+		if (This->vdec_std == VPU_VIDEO_HEVC)
+			uDpbmcCrc = pPerfDcpInfo->uDBEDpbCRC[0];
+		else
+			uDpbmcCrc = pPerfInfo->uMemCRC;
+		if (vpu_frmcrcdump_ena) {
+			wr_size = kernel_write(ctx->crc_fp, &uDpbmcCrc, sizeof(uDpbmcCrc), &ctx->pos);
+			ctx->pos += wr_size;
+		}
+
+		vpu_dbg(LVL_BIT_FRAME_BYTES, "PICINFO GET: uPicType:%d uPicStruct:%d uPicStAddr:0x%x uFrameStoreID:%d uPercentInErr:%d, uRbspBytesCount=%d, uDpbmcCrc:%x\n",
+			pPicInfo[uStrIdx].uPicType, pPicInfo[uStrIdx].uPicStruct,
+			pPicInfo[uStrIdx].uPicStAddr, pPicInfo[uStrIdx].uFrameStoreID,
+			pPicInfo[uStrIdx].uPercentInErr, pPerfInfo->uRbspBytesCount,
+			uDpbmcCrc);
+		vpu_dbg(LVL_BIT_FRAME_BYTES, "PICINFO GET: ulLumBaseAddr[0]=%x, uPicStartAddr=0x%x, pQMeterInfo:%p, pPicInfo:%p, pDispInfo:%p, pPerfInfo:%p, pPerfDcpInfo:%p\n",
+			event_data[0], uPicStartAddr, pQMeterInfo, pPicInfo,
+			pDispInfo, pPerfInfo, pPerfDcpInfo);
+
+		buffer_id = find_buffer_id(ctx, event_data[0]);
+		if (buffer_id == -1) {
+			vpu_err("error: %s() ctx[%d] not find buffer id: %d, addr: 0x%x\n",
+					__func__, ctx->str_index, uDecFrmId, event_data[0]);
+			break;
+		}
+
+		p_data_req = &This->vb2_reqs[buffer_id];
+		set_data_req_status(p_data_req, FRAME_DECODED);
+		if (ctx->seqinfo.uProgressive == 1)
+			p_data_req->bfield = false;
+		else
+			p_data_req->bfield = true;
+
+		This->process_count++;
+		if (ctx->statistic.event[VID_API_EVENT_PIC_DECODED] == 1)
+			vpu_calculate_performance(ctx, uEvent, "first decoded");
+		else
+			vpu_calculate_performance(ctx, uEvent, NULL);
+
+		if (ctx->frm_dec_delay >= consumed_count)
+			ctx->frm_dec_delay -= consumed_count;
+		else
+			ctx->frm_dec_delay = 0;
+		ctx->fifo_low = false;
+		ctx->frame_decoded = true;
+		v4l2_update_stream_addr(ctx, 0);
+		}
+		break;
+	case VID_API_EVENT_SEQ_HDR_FOUND: {
+		MediaIPFW_Video_SeqInfo *pSeqInfo = (MediaIPFW_Video_SeqInfo *)dev->shared_mem.seq_mem_vir;
+		MediaIPFW_Video_SeqInfo info;
+//		MediaIPFW_Video_FrameBuffer *pStreamFrameBuffer = &pSharedInterface->StreamFrameBuffer[uStrIdx];
+//		MediaIPFW_Video_FrameBuffer *pStreamDCPBuffer = &pSharedInterface->StreamDCPBuffer[uStrIdx];
+		MediaIPFW_Video_PitchInfo   *pStreamPitchInfo = &pSharedInterface->StreamPitchInfo[uStrIdx];
+		unsigned int num = pSharedInterface->SeqInfoTabDesc.uNumSizeDescriptors;
+		int wait_times = 0;
+
+		get_seq_info(&info, event_data, &pSeqInfo[ctx->str_index]);
+		if (!check_seq_info_is_valid(ctx->str_index, &info)) {
+			vpu_dec_event_decode_error(ctx);
+			break;
+		}
+
+		while (ctx->wait_res_change_done && wait_times++ < 100) {
+			if (!vpu_dec_is_active(ctx))
+				break;
+			if (ctx->wait_rst_done)
+				break;
+			mdelay(10);
+		}
+		if (!vpu_dec_is_active(ctx))
+			break;
+		if (ctx->wait_res_change_done)
+			vpu_dbg(LVL_WARN, "warning: ctx[%d] update seq info when waiting res change\n",
+				ctx->str_index);
+
+		down(&ctx->q_data[V4L2_DST].drv_q_lock);
+		respond_req_frame(ctx, &ctx->q_data[V4L2_DST], true);
+		if (check_res_is_changed(ctx, &info))
+			ctx->res_change_occu_count++;
+		memcpy(&ctx->seqinfo, &info, sizeof(MediaIPFW_Video_SeqInfo));
+		up(&ctx->q_data[V4L2_DST].drv_q_lock);
+
+		parse_frame_interval_from_seqinfo(ctx, &ctx->seqinfo);
+		vpu_dbg(LVL_BIT_FLOW,
+			"ctx[%d] SEQINFO GET: uHorRes:%d uVerRes:%d uHorDecodeRes:%d uVerDecodeRes:%d\n",
+			ctx->str_index,
+			ctx->seqinfo.uHorRes,
+			ctx->seqinfo.uVerRes,
+			ctx->seqinfo.uHorDecodeRes,
+			ctx->seqinfo.uVerDecodeRes);
+		vpu_dbg(LVL_BIT_FLOW,
+			"ctx[%d] SEQINFO GET: uNumDPBFrms:%d, num:%d, uNumRefFrms:%d, uNumDFEAreas:%d, scan lines: %s\n",
+			ctx->str_index,
+			ctx->seqinfo.uNumDPBFrms,
+			num,
+			ctx->seqinfo.uNumRefFrms,
+			ctx->seqinfo.uNumDFEAreas & 0xff,
+			ctx->seqinfo.uProgressive ? "progressive" : "interlaced");
+		vpu_dbg(LVL_BIT_FLOW,
+			"uColorDesc = %d, uTransferChars = %d, uMatrixCoeffs = %d, uVideoFullRangeFlag = %d, uVUIPresent = %d\n",
+			ctx->seqinfo.uColorDesc,
+			ctx->seqinfo.uTransferChars,
+			ctx->seqinfo.uMatrixCoeffs,
+			ctx->seqinfo.uVideoFullRangeFlag,
+			ctx->seqinfo.uVUIPresent);
+		vpu_dec_convert_color_iso_aspect_to_v4l2_aspect(ctx,
+				ctx->seqinfo.uColorDesc,
+				ctx->seqinfo.uTransferChars,
+				ctx->seqinfo.uMatrixCoeffs,
+				ctx->seqinfo.uVideoFullRangeFlag);
+
+		down(&ctx->q_data[V4L2_DST].drv_q_lock);
+		calculate_frame_size(ctx);
+		ctx->dcp_size = get_dcp_size(ctx);
+		if (ctx->b_firstseq) {
+			ctx->b_firstseq = false;
+			ctx->mbi_size = get_mbi_size(&ctx->q_data[V4L2_DST]);
+			reset_frame_buffer(ctx);
+			ctx->q_data[V4L2_DST].enable = false;
+			ctx->wait_res_change_done = true;
+			send_source_change_event(ctx);
+			pStreamPitchInfo->uFramePitch = 0x4000;
+			vpu_calculate_performance(ctx, uEvent, "seq_hdr_found");
+		}
+		up(&ctx->q_data[V4L2_DST].drv_q_lock);
+		}
+		break;
+	case VID_API_EVENT_PIC_HDR_FOUND:
+		break;
+	case VID_API_EVENT_REQ_FRAME_BUFF: {
+		MEDIA_PLAYER_FSREQ *pFSREQ = (MEDIA_PLAYER_FSREQ *)event_data;
+		struct queue_data *This = &ctx->q_data[V4L2_DST];
+
+		vpu_dbg(LVL_INFO, "VID_API_EVENT_REQ_FRAME_BUFF, type=%d, size=%ld\n", pFSREQ->eType, sizeof(MEDIA_PLAYER_FSREQ));
+		down(&This->drv_q_lock);
+		switch (pFSREQ->eType) {
+		case MEDIAIP_DCP_REQ:
+			ctx->req_dcp_count++;
+			if (ctx->req_dcp_count > MAX_DCP_NUM) {
+				vpu_err("error: request dcp count over %d\n",
+						MAX_DCP_NUM);
+				ctx->req_dcp_count = MAX_DCP_NUM;
+			}
+			break;
+		case MEDIAIP_MBI_REQ:
+			ctx->req_mbi_count++;
+			if (ctx->req_mbi_count > MAX_MBI_NUM) {
+				vpu_err("error: request mbi count over %d\n",
+						MAX_MBI_NUM);
+				ctx->req_mbi_count = MAX_MBI_NUM;
+			}
+			break;
+		default:
+			ctx->req_frame_count++;
+			break;
+		}
+		vpu_dec_alloc_mbi_dcp(ctx);
+		respond_req_frame(ctx, This, false);
+		up(&This->drv_q_lock);
+		}
+		break;
+	case VID_API_EVENT_REL_FRAME_BUFF: {
+		MEDIA_PLAYER_FSREL *fsrel = (MEDIA_PLAYER_FSREL *)event_data;
+		struct queue_data *This = &ctx->q_data[V4L2_DST];
+		struct vb2_data_req *p_data_req;
+
+		down(&This->drv_q_lock);
+		if (fsrel->eType == MEDIAIP_FRAME_REQ) {
+			p_data_req = &This->vb2_reqs[fsrel->uFSIdx];
+			if (!p_data_req->vb2_buf) {
+				vpu_dbg(LVL_INFO,
+					"frame[%d] buffer already freed!\n",
+					p_data_req->id);
+				up(&This->drv_q_lock);
+				break;
+			}
+
+			if (ctx->wait_rst_done != true && p_data_req->status != FRAME_READY) {
+				vpu_dbg(LVL_INFO, "warning: normal release and previous status %s, frame not for display, queue the buffer to list again\n",
+						bufstat[p_data_req->status]);
+
+				if (p_data_req->status == FRAME_DECODED)
+					send_skip_event(ctx);
+			}
+			if (p_data_req->status != FRAME_ALLOC) {
+				set_data_req_status(p_data_req, FRAME_RELEASE);
+				release_frame_buffer(ctx, uStrIdx, p_data_req);
+			} else {
+				vpu_dbg(LVL_INFO,
+					"frame[%d] already released\n",
+					p_data_req->id);
+			}
+			add_buffer_to_queue(This, p_data_req);
+			respond_req_frame(ctx, This, false);
+		} else if (fsrel->eType == MEDIAIP_MBI_REQ) {
+			vpu_dbg(LVL_INFO, "ctx[%d] relase MEDIAIP_MBI_REQ frame[%d]\n",
+					ctx->str_index, fsrel->uFSIdx);
+		} else if (fsrel->eType == MEDIAIP_DCP_REQ) {
+			vpu_dbg(LVL_INFO, "ctx[%d] relase MEDIAIP_DCP_REQ frame[%d]\n",
+					ctx->str_index, fsrel->uFSIdx);
+		} else {
+			vpu_dbg(LVL_WARN, "warning: ctx[%d] release unknown type frame!\n",
+					ctx->str_index);
+		}
+		up(&This->drv_q_lock);
+		vpu_dbg(LVL_INFO, "VID_API_EVENT_REL_FRAME_BUFF uFSIdx=%d, eType=%d, size=%ld\n",
+				fsrel->uFSIdx, fsrel->eType, sizeof(MEDIA_PLAYER_FSREL));
+	} break;
+	case VID_API_EVENT_FRAME_BUFF_RDY: {
+		u_int32 *FrameInfo = (u_int32 *)event_data;
+
+		report_buffer_done(ctx, FrameInfo);
+		if (ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY] == 1)
+			vpu_calculate_performance(ctx, uEvent, "first ready");
+		else
+			vpu_calculate_performance(ctx, uEvent, NULL);
+	}
+		break;
+	case VID_API_EVENT_CHUNK_DECODED:
+		break;
+	case VID_API_EVENT_FIFO_LOW: {
+		u_int32 uStrBufIdx = 0; //use buffer 0 for the stream
+
+		ctx->fifo_low = true;
+		v4l2_update_stream_addr(ctx, uStrBufIdx);
+	} break;
+	case VID_API_EVENT_FIFO_HIGH:
+		break;
+	case  VID_API_EVENT_FIFO_EMPTY:
+		break;
+	case  VID_API_EVENT_FIFO_FULL:
+		break;
+	case  VID_API_EVENT_FIFO_OVF:
+		break;
+	case  VID_API_EVENT_BS_ERROR:
+		break;
+	case  VID_API_EVENT_UDATA_FIFO_UPTD:
+		break;
+	case VID_API_EVENT_DBG_STAT_UPDATE:
+		break;
+	case VID_API_EVENT_DBG_LOG_STARTED:
+		break;
+	case VID_API_EVENT_DBG_LOG_STOPPED:
+		break;
+	case VID_API_EVENT_ABORT_DONE: {
+		pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+		struct queue_data *queue = &ctx->q_data[V4L2_SRC];
+
+		pStrBufDesc = get_str_buffer_desc(ctx);
+		vpu_dbg(LVL_INFO, "%s AbrtDone StrBuf Curr, wptr(%x) rptr(%x) start(%x) end(%x)\n",
+				__func__,
+				pStrBufDesc->wptr,
+				pStrBufDesc->rptr,
+				pStrBufDesc->start,
+				pStrBufDesc->end);
+
+		down(&queue->drv_q_lock);
+		vpu_dbg(LVL_BIT_FLOW,
+			"ctx[%d] ABORT DONE, output qbuf(%ld/%ld),dqbuf(%ld)\n",
+			ctx->str_index,
+			queue->process_count,
+			queue->qbuf_count,
+			queue->dqbuf_count);
+		vpu_dbg(LVL_BIT_FRAME_BYTES,
+				"[%d]total bytes: %ld, %ld\n",
+				ctx->str_index,
+				ctx->total_qbuf_bytes,
+				ctx->total_write_bytes);
+		update_wptr(ctx, pStrBufDesc, pStrBufDesc->rptr);
+		ctx->beginning = pStrBufDesc->rptr;
+		ctx->total_qbuf_bytes = 0;
+		ctx->total_write_bytes = 0;
+		up(&queue->drv_q_lock);
+
+		ctx->frm_dis_delay = 0;
+		ctx->frm_dec_delay = 0;
+		ctx->frm_total_num = 0;
+		v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_RST_BUF, 0, NULL);
+		}
+		break;
+	case VID_API_EVENT_RES_CHANGE: {
+		struct queue_data *This;
+
+		vpu_dbg(LVL_BIT_FLOW, "ctx[%d] RES CHANGE\n", ctx->str_index);
+		This = &ctx->q_data[V4L2_DST];
+		down(&This->drv_q_lock);
+		reset_mbi_dcp_count(ctx);
+		ctx->mbi_size = get_mbi_size(This);
+		ctx->dcp_size = get_dcp_size(ctx);
+		reset_frame_buffer(ctx);
+		up(&This->drv_q_lock);
+		vpu_dbg(LVL_BIT_FLOW,
+			"warning: ctx[%d] RES_CHANGE event, seq id: %d\n",
+			ctx->str_index, ctx->seqinfo.uActiveSeqTag);
+		vpu_log_buffer_state(ctx);
+		down(&This->drv_q_lock);
+		This->enable = false;
+		up(&This->drv_q_lock);
+		ctx->wait_res_change_done = true;
+		send_source_change_event(ctx);
+		}
+		break;
+	case VID_API_EVENT_STR_BUF_RST: {
+		pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+		struct queue_data *This;
+
+		pStrBufDesc = get_str_buffer_desc(ctx);
+		vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x)\n",
+				__func__,
+				pStrBufDesc->wptr,
+				pStrBufDesc->rptr,
+				pStrBufDesc->start,
+				pStrBufDesc->end
+			  );
+		This = &ctx->q_data[V4L2_DST];
+		down(&This->drv_q_lock);
+		check_queue_is_releasd(This, "EVENT_STR_BUF_RST is received");
+		up(&This->drv_q_lock);
+		if (check_is_need_reset_after_abort(ctx)) {
+			vpu_dbg(LVL_BIT_FLOW,
+				"Force reset ctx[%d]\n", ctx->str_index);
+			v4l2_vpu_send_cmd(ctx, ctx->str_index,
+					VID_API_CMD_STOP, 0, NULL);
+		} else {
+			ctx->wait_rst_done = false;
+			complete(&ctx->completion);
+		}
+		vpu_dbg(LVL_BIT_FLOW, "ctx[%d] STR_BUF_RST\n", ctx->str_index);
+		}
+		break;
+	case VID_API_EVENT_RET_PING:
+		break;
+	case VID_API_EVENT_STR_FMT_CHANGE:
+		break;
+	case VID_API_EVENT_FINISHED: {
+		if (ctx->firmware_finished == true)
+			vpu_err("warning: receive VID_API_EVENT_FINISHED when firmware_finished == true\n");
+		ctx->firmware_finished = true;
+		verify_decoded_frames(ctx);
+		vpu_dbg(LVL_BIT_FLOW, "ctx[%d] FINISHED\n", ctx->str_index);
+		vpu_dbg(LVL_INFO, "receive VID_API_EVENT_FINISHED and notfiy app eos\n");
+		vpu_log_buffer_state(ctx);
+		send_eos_event(ctx); //notfiy app stream eos reached
+	}	break;
+	case VID_API_EVENT_FIRMWARE_XCPT: {
+		char *xcpt_info = (char*)event_data;
+
+		vpu_err("ctx[%d] warning: VID_API_EVENT_FIRMWARE_XCPT,exception info: %s\n",
+				ctx->str_index, xcpt_info);
+		ctx->hang_status = true;
+		vpu_dec_event_decode_error(ctx);
+		}
+		break;
+	case VID_API_EVENT_DEC_CFG_INFO:
+		break;
+	case VID_API_EVENT_UNSUPPORTED_STREAM:
+		vpu_dbg(LVL_WARN, "warning: HW unsupprot the format or stream\n");
+		vpu_dec_event_decode_error(ctx);
+		break;
+	default:
+		vpu_err("warning: uEvent %d is not handled\n", uEvent);
+		break;
+	}
+	vpu_dbg(LVL_INFO, "leave %s, uEvent %d\n", __func__, uEvent);
+}
+
+static void release_vpu_ctx(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	remove_instance_file(ctx);
+	vpu_dec_cleanup_cmd(ctx);
+	release_queue_data(ctx);
+	free_decoder_buffer(ctx);
+	destroy_log_info_queue(ctx);
+	cleanup_perf_queue(ctx);
+
+	if (atomic64_read(&ctx->statistic.total_alloc_size) != 0)
+		vpu_err("error: memory leak for vpu kalloc buffer\n");
+	if (atomic64_read(&ctx->statistic.total_dma_size) != 0)
+		vpu_err("error: memory leak for vpu dma buffer\n");
+
+	mutex_destroy(&ctx->instance_mutex);
+	mutex_destroy(&ctx->cmd_lock);
+	mutex_destroy(&ctx->perf_lock);
+	mutex_destroy(&ctx->fw_flow_mutex);
+	clear_bit(ctx->str_index, &ctx->dev->instance_mask);
+	ctx->dev->ctx[ctx->str_index] = NULL;
+	pm_runtime_put_sync(ctx->dev->generic_dev);
+	kfree(ctx);
+}
+
+static int release_hang_instance(struct vpu_dev *dev)
+{
+	u_int32 i;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++)
+		if (dev->ctx[i]) {
+			release_vpu_ctx(dev->ctx[i]);
+			dev->ctx[i] = NULL;
+		}
+
+	return 0;
+}
+
+static int get_reset_index(struct vpu_dev *dev)
+{
+	int idx;
+
+	for (idx = 0; idx < VPU_MAX_NUM_STREAMS; idx++)
+		if (CHECK_BIT(dev->instance_mask, idx))
+			break;
+
+	return idx;
+}
+
+/*
+ * Add judge to find if it has available path to decode, if all
+ * path hang, reset vpu and then get one index
+ */
+static int vpu_next_free_instance(struct vpu_dev *dev)
+{
+	int idx;
+
+	if (dev->hang_mask == dev->instance_mask && dev->instance_mask != 0) {
+		idx = get_reset_index(dev);
+		if (idx < 0 || idx >= VPU_MAX_NUM_STREAMS)
+			return -EBUSY;
+		else {
+			if (swreset_vpu_firmware(dev, idx))
+				return -EINVAL;
+			release_hang_instance(dev);
+		}
+		dev->hang_mask = 0;
+		dev->instance_mask = 0;
+	}
+
+	idx = ffz(dev->instance_mask);
+	if (idx < 0 || idx >= VPU_MAX_NUM_STREAMS)
+		return -EBUSY;
+
+	release_vpu_ctx(dev->ctx[idx]);
+
+	return idx;
+}
+
+static void send_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+	u_int32 ret;
+
+	ret = kfifo_in(&ctx->msg_fifo, msg, sizeof(u_int32) * (MSG_WORD_LENGTH + msg->msgnum));
+	if (ret != sizeof(u_int32) * (MSG_WORD_LENGTH + msg->msgnum))
+		vpu_err("There is no memory for msg fifo, ret=%d\n", ret);
+}
+
+static bool receive_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+	u_int32 ret;
+
+	if (kfifo_len(&ctx->msg_fifo) >= sizeof(u_int32) * MSG_WORD_LENGTH) {
+		ret = kfifo_out(&ctx->msg_fifo, msg, sizeof(u_int32) * MSG_WORD_LENGTH);
+		if (ret != sizeof(u_int32) * MSG_WORD_LENGTH) {
+			vpu_err("kfifo_out msg word has error, ret=%d\n", ret);
+			return false;
+		} else {
+			if (msg->msgnum > 0) {
+				if (kfifo_len(&ctx->msg_fifo) >= sizeof(u_int32) * msg->msgnum) {
+					ret = kfifo_out(&ctx->msg_fifo, msg->msgdata, sizeof(u_int32) * msg->msgnum);
+					if (ret != sizeof(u_int32) * msg->msgnum) {
+						vpu_err("kfifo_out msg data has error, ret=%d\n", ret);
+						return false;
+					} else
+						return true;
+				} else
+					return false;
+			} else
+				return true;
+		}
+	} else
+		return false;
+}
+
+static void vpu_receive_msg_event(struct vpu_dev *dev)
+{
+	struct event_msg msg;
+	struct shared_addr *This;
+	struct vpu_ctx *ctx;
+
+	This = &dev->shared_mem;
+	if (!This)
+		return;
+
+	memset(&msg, 0, sizeof(struct event_msg));
+	while (rpc_MediaIPFW_Video_message_check(This) == API_MSG_AVAILABLE) {
+		rpc_receive_msg_buf(This, &msg);
+
+		mutex_lock(&dev->dev_mutex);
+		ctx = dev->ctx[msg.idx];
+		if (ctx)
+			count_event(&ctx->statistic, msg.msgid);
+		if (ctx != NULL && !ctx->ctx_released) {
+			send_msg_queue(ctx, &msg);
+			queue_work(ctx->instance_wq, ctx->instance_work);
+			queue_delayed_work(ctx->instance_wq,
+					ctx->delayed_instance_work,
+					msecs_to_jiffies(10));
+		} else {
+			vpu_err("msg [%d] %d is missed!%s\n",
+				msg.idx, msg.msgid,
+				ctx == NULL ? " ctx is NULL" : " ctx released");
+		}
+		mutex_unlock(&dev->dev_mutex);
+	}
+	if (rpc_MediaIPFW_Video_message_check(This) == API_MSG_BUFFER_ERROR)
+		vpu_err("error: message size is too big to handle\n");
+}
+
+static void vpu_handle_msg_data(struct vpu_dev *dev, u32 data)
+{
+	if (data == 0xaa) {
+		mutex_lock(&dev->cmd_mutex);
+		vpu_mu_send_msg(dev, RPC_BUF_OFFSET,
+				vpu_dec_cpu_phy_to_mu(dev, dev->m0_rpc_phy));
+		vpu_mu_send_msg(dev, BOOT_ADDRESS, dev->m0_p_fw_space_phy);
+		vpu_mu_send_msg(dev, INIT_DONE, 2);
+		mutex_unlock(&dev->cmd_mutex);
+	} else if (data == 0x55) {
+		dev->firmware_started = true;
+		complete(&dev->start_cmp);
+	}  else if (data == 0xA5) {
+		/*receive snapshot done msg and wakeup complete to suspend*/
+		complete(&dev->snap_done_cmp);
+	} else {
+		vpu_receive_msg_event(dev);
+	}
+}
+
+static void vpu_msg_run_work(struct work_struct *work)
+{
+	struct vpu_dev *dev = container_of(work, struct vpu_dev, msg_work);
+	u32 data;
+
+	while (vpu_mu_receive_msg(dev, &data) >= sizeof(u_int32))
+		vpu_handle_msg_data(dev, data);
+}
+
+static void vpu_msg_run_delayed_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct vpu_dev *dev;
+
+	dwork = to_delayed_work(work);
+	dev = container_of(dwork, struct vpu_dev, delayed_msg_work);
+	if (!kfifo_len(&dev->mu_msg_fifo))
+		return;
+
+	queue_work(dev->workqueue, &dev->msg_work);
+}
+
+static void vpu_msg_instance_work(struct work_struct *work)
+{
+	struct vpu_ctx_work *ctx_work;
+	struct vpu_ctx *ctx;
+	struct event_msg msg;
+
+	ctx_work = container_of(work, struct vpu_ctx_work, instance_work);
+	ctx = ctx_work->dev->ctx[ctx_work->str_index];
+	if (!ctx || ctx->ctx_released)
+		return;
+
+	memset(&msg, 0, sizeof(struct event_msg));
+
+	while (receive_msg_queue(ctx, &msg)) {
+		vpu_api_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+		memset(&msg, 0, sizeof(struct event_msg));
+	}
+}
+
+static void vpu_msg_delayed_instance_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct vpu_ctx_work *ctx_work;
+	struct vpu_ctx *ctx;
+
+	dwork = to_delayed_work(work);
+	ctx_work = container_of(dwork, struct vpu_ctx_work,
+				delayed_instance_work);
+	ctx = ctx_work->dev->ctx[ctx_work->str_index];
+	if (!ctx || ctx->ctx_released || !kfifo_len(&ctx->msg_fifo))
+		return;
+
+	queue_work(ctx->instance_wq, ctx->instance_work);
+}
+
+static bool vpu_dec_alloc_buffer_item(struct vpu_ctx *ctx,
+					u32 index, u32 count, u32 size,
+					struct dma_buffer *buffers,
+					const char *desc)
+{
+	struct dma_buffer buffer;
+	int ret;
+
+	if (index >= count)
+		return false;
+
+	if (buffers[index].dma_virt && buffers[index].dma_size >= size)
+		return true;
+
+	free_dma_buffer(ctx, &buffers[index]);
+
+	vpu_dbg(LVL_BIT_FLOW, "alloc %s[%d], size = %d\n", desc, index, size);
+	buffer.dma_size = size;
+
+	ret = alloc_dma_buffer(ctx, &buffer);
+	if (ret) {
+		vpu_err("error: alloc %s buffer[%d] fail\n", desc, index);
+		return false;
+	}
+	memcpy(&buffers[index], &buffer, sizeof(buffer));
+	return true;
+}
+
+static void vpu_dec_alloc_mbi_dcp(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue = &ctx->q_data[V4L2_DST];
+	int ret;
+
+	if (ctx->b_firstseq)
+		return;
+
+	while (ctx->mbi_count < ctx->req_mbi_count) {
+		ret = vpu_dec_alloc_buffer_item(ctx,
+						ctx->mbi_count,
+						ctx->req_mbi_count,
+						ctx->mbi_size,
+						ctx->mbi_buffer,
+						"mbi");
+		if (!ret)
+			break;
+		ctx->mbi_count++;
+	}
+	while (ctx->dcp_count < ctx->req_dcp_count) {
+		ret = vpu_dec_alloc_buffer_item(ctx,
+						ctx->dcp_count,
+						ctx->req_dcp_count,
+						ctx->dcp_size,
+						ctx->dcp_buffer,
+						"dcp");
+		if (!ret)
+			break;
+		ctx->dcp_count++;
+	}
+	respond_req_frame(ctx, queue, false);
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+		unsigned int *buf_count,
+		unsigned int *plane_count,
+		unsigned int psize[],
+		struct device *allocators[])
+{
+	struct queue_data  *This = (struct queue_data *)vq->drv_priv;
+	struct vpu_ctx *ctx = NULL;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+
+	ctx = container_of(This, struct vpu_ctx, q_data[This->type]);
+	if ((vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ||
+		(vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		) {
+		if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			*plane_count = 2;
+			psize[0] = This->sizeimage[0];//check alignment
+			psize[1] = This->sizeimage[1];//check colocated_size
+		} else {
+			psize[0] = This->sizeimage[0] + This->sizeimage[1];
+			*plane_count = 1;
+		}
+	} else {
+		*plane_count = 1;
+		psize[0] = This->sizeimage[0];
+	}
+
+	if (!V4L2_TYPE_IS_OUTPUT(vq->type))
+		ctx->seek_flag = false;
+
+	return 0;
+}
+
+static int vpu_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue    *vq = vb->vb2_queue;
+	struct queue_data   *queue = (struct queue_data *)vq->drv_priv;
+	struct vb2_data_req *p_data_req;
+
+	p_data_req = &queue->vb2_reqs[vb->index];
+	p_data_req->vb2_buf = vb;
+	p_data_req->id = vb->index;
+	set_data_req_status(p_data_req, FRAME_ALLOC);
+
+	return 0;
+}
+
+static void vpu_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vb2_queue    *vq = vb->vb2_queue;
+	struct queue_data   *queue = (struct queue_data *)vq->drv_priv;
+	struct vb2_data_req *p_data_req;
+
+	p_data_req = &queue->vb2_reqs[vb->index];
+	p_data_req->vb2_buf = NULL;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+
+	return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q,
+		unsigned int count
+		)
+{
+	int ret = 0;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+
+	return ret;
+}
+
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+	struct queue_data *queue = (struct queue_data *)q->drv_priv;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+	clear_queue(queue);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue    *vq = vb->vb2_queue;
+	struct queue_data   *This = (struct queue_data *)vq->drv_priv;
+	struct vb2_data_req *data_req;
+	u_int32 *pphy_address_0, *pphy_address_1;
+	struct vpu_ctx *ctx = NULL;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s(), vq->type=%d, vb->index=%d\n",
+			__func__, vq->type, vb->index);
+
+	ctx = container_of(This, struct vpu_ctx, q_data[This->type]);
+	data_req = &This->vb2_reqs[vb->index];
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		pphy_address_0 = (u_int32 *)vb2_plane_cookie(vb, 0);
+		pphy_address_1 = (u_int32 *)vb2_plane_cookie(vb, 1);
+		if (pphy_address_0 == NULL || pphy_address_1 == NULL) {
+			vpu_dbg(LVL_WARN, "%s() warning: pphy_address == NULL\n",
+					__func__);
+			return;
+		}
+		data_req->phy_addr[0] = *pphy_address_0;
+		data_req->phy_addr[1] = *pphy_address_1;
+	}
+
+	add_buffer_to_queue(This, data_req);
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		if (!vpu_dec_is_active(ctx))
+			activate_vpu_dec(ctx);
+		precheck_vb_data(ctx, vb);
+		enqueue_stream_data(ctx, 0);
+	} else {
+		respond_req_frame(ctx, This, false);
+	}
+
+	This->qbuf_count++;
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s() is called\n", __func__);
+}
+
+struct vb2_ops v4l2_qops = {
+	.queue_setup        = vpu_queue_setup,
+	.wait_prepare       = vpu_prepare,
+	.wait_finish        = vpu_finish,
+	.buf_init           = vpu_buf_init,
+	.buf_cleanup        = vpu_buf_cleanup,
+	.buf_prepare        = vpu_buf_prepare,
+	.start_streaming    = vpu_start_streaming,
+	.stop_streaming     = vpu_stop_streaming,
+	.buf_queue          = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type, struct vpu_ctx *ctx)
+{
+	struct vb2_queue  *vb2_q = &This->vb2_q;
+	int ret;
+	u_int32 i;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	for (i = 0; i < VPU_MAX_BUFFER; i++)
+		This->vb2_reqs[i].status = 0;
+	// initialze driver queue
+	INIT_LIST_HEAD(&This->drv_q);
+	// initialize vb2 queue
+	vb2_q->type = type;
+	vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	vb2_q->ops = &v4l2_qops;
+	vb2_q->drv_priv = This;
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		vb2_q->mem_ops = &vb2_vmalloc_memops;
+		vb2_q->gfp_flags = GFP_KERNEL;
+	} else {
+		vb2_q->mem_ops = &vb2_dma_contig_memops;
+		vb2_q->gfp_flags = GFP_KERNEL | GFP_DMA32 | __GFP_NOWARN;
+	}
+	vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	vb2_q->dev = &ctx->dev->plat_dev->dev;
+	ret = vb2_queue_init(vb2_q);
+	if (ret)
+		vpu_err("error: %s vb2_queue_init() failed (%d)!\n",
+				__func__, ret);
+	else
+		This->vb2_q_inited = true;
+}
+
+static void init_queue_data(struct vpu_ctx *ctx)
+{
+	init_vb2_queue(&ctx->q_data[V4L2_SRC], V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ctx);
+	ctx->q_data[V4L2_SRC].type = V4L2_SRC;
+	ctx->q_data[V4L2_SRC].ctx = ctx;
+	sema_init(&ctx->q_data[V4L2_SRC].drv_q_lock, 1);
+	init_vb2_queue(&ctx->q_data[V4L2_DST], V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ctx);
+	ctx->q_data[V4L2_DST].type = V4L2_DST;
+	ctx->q_data[V4L2_DST].ctx = ctx;
+	sema_init(&ctx->q_data[V4L2_DST].drv_q_lock, 1);
+}
+
+static void release_queue_data(struct vpu_ctx *ctx)
+{
+	vpu_dec_queue_release(&ctx->q_data[V4L2_SRC]);
+	vpu_dec_queue_release(&ctx->q_data[V4L2_DST]);
+}
+
+static void enable_csr_reg(struct vpu_dev *This)
+{
+	writel(This->m0_p_fw_space_phy, This->csr_base + CSR_CM0Px_ADDR_OFFSET);
+	writel(0x0, This->csr_base + CSR_CM0Px_CPUWAIT);
+}
+
+static void cleanup_firmware_memory(struct vpu_dev *vpudev)
+{
+	if (!vpudev->need_cleanup_firmware)
+		return;
+	memset_io(vpudev->m0_p_fw_space_vir, 0, vpudev->m0_boot_size);
+	vpudev->need_cleanup_firmware = false;
+}
+
+static int vpu_firmware_download(struct vpu_dev *This)
+{
+	unsigned char *image;
+	unsigned int FW_Size = 0;
+	int ret = 0;
+	char *p = This->m0_p_fw_space_vir;
+
+	This->firmware_started = false;
+	ret = request_firmware((const struct firmware **)&This->m0_pfw,
+			M0FW_FILENAME,
+			This->generic_dev
+			);
+
+	if (ret || !This->m0_pfw) {
+		vpu_err("error: %s() request fw %s failed(%d)\n",
+			__func__, M0FW_FILENAME, ret);
+
+		if (This->m0_pfw) {
+			release_firmware(This->m0_pfw);
+			This->m0_pfw = NULL;
+		}
+
+		return ret;
+	}
+
+	vpu_dbg(LVL_INFO, "%s() request fw %s got size(%d)\n",
+		__func__, M0FW_FILENAME, (int)This->m0_pfw->size);
+	image = (uint8_t *)This->m0_pfw->data;
+	FW_Size = This->m0_pfw->size;
+
+	cleanup_firmware_memory(This);
+	memcpy(This->m0_p_fw_space_vir, image, FW_Size);
+
+	p[16] = This->plat_type;
+	p[18] = 1;
+	enable_csr_reg(This);
+	This->need_cleanup_firmware = true;
+
+	release_firmware(This->m0_pfw);
+	This->m0_pfw = NULL;
+
+	return ret;
+}
+
+static int dbglog_show(struct seq_file *s, void *data)
+{
+#define DBG_UNIT_SIZE		(7)
+	struct vpu_dev *dev = s->private;
+	u_int32 *pbuf;
+	u_int32 line;
+	int length;
+
+	pbuf = (u_int32 *)dev->shared_mem.dbglog_mem_vir;
+	line = (DBGLOG_SIZE) / (DBG_UNIT_SIZE * sizeof(u_int32));
+	if (!line)
+		return 0;
+
+	if (!vpu_frmdbg_raw) {
+		u_int32 i;
+
+		length = 9 * DBG_UNIT_SIZE * line + 1;
+		if (s->count + length >= s->size) {
+			s->count = s->size;
+			return 0;
+		}
+		for (i = 0; i < line; i++) {
+			seq_printf(s, "%08x %08x %08x %08x %08x %08x %08x\n",
+				pbuf[0], pbuf[1], pbuf[2], pbuf[3],
+				pbuf[4], pbuf[5], pbuf[6]);
+			pbuf += DBG_UNIT_SIZE;
+		}
+
+		return 0;
+	}
+
+	length = DBG_UNIT_SIZE * sizeof(u_int32) * line;
+	if (s->count + length >= s->size) {
+		s->count = s->size;
+		return 0;
+	}
+
+	return seq_write(s, (void *)pbuf, length);
+}
+
+static int dbglog_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, dbglog_show, inode->i_private);
+}
+
+static struct file_operations dbglog_fops = {
+	.owner = THIS_MODULE,
+	.open = dbglog_open,
+	.release = single_release,
+	.read = seq_read,
+};
+
+static int create_dbglog_file(struct vpu_dev *dev)
+{
+	if (dev->debugfs_root == NULL) {
+		dev->debugfs_root = debugfs_create_dir("vpu", NULL);
+		if (!dev->debugfs_root) {
+			vpu_err("error: create debugfs_root fail\n");
+			return -EINVAL;
+		}
+	}
+
+	if (dev->debugfs_dbglog)
+		return 0;
+
+	dev->debugfs_dbglog = debugfs_create_file("dbglog",
+			VERIFY_OCTAL_PERMISSIONS(0444),
+			dev->debugfs_root,
+			dev,
+			&dbglog_fops);
+	if (!dev->debugfs_dbglog) {
+		vpu_err("error: create debugfs_dbglog fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fwlog_show(struct seq_file *s, void *data)
+{
+	struct vpu_dev *dev = s->private;
+	int length;
+	u32 rptr;
+	u32 wptr;
+	int ret = 0;
+
+	if (!dev->print_buf)
+		return 0;
+
+	rptr = dev->print_buf->read;
+	wptr = dev->print_buf->write;
+
+	if (rptr == wptr)
+		return 0;
+	else if (rptr < wptr)
+		length = wptr - rptr;
+	else
+		length = dev->print_buf->bytes + wptr - rptr;
+
+	if (s->count + length >= s->size) {
+		s->count = s->size;
+		return 0;
+	}
+
+	if (rptr + length > dev->print_buf->bytes) {
+		int num = dev->print_buf->bytes - rptr;
+
+		if (seq_write(s, dev->print_buf->buffer + rptr, num))
+			ret = -1;
+		length -= num;
+		rptr = 0;
+	}
+	if (seq_write(s, dev->print_buf->buffer + rptr, length))
+		ret = -1;
+	rptr += length;
+	rptr %= dev->print_buf->bytes;
+	if (!ret)
+		dev->print_buf->read = rptr;
+
+	return 0;
+}
+
+static int fwlog_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, fwlog_show, inode->i_private);
+}
+
+static const struct file_operations fwlog_fops = {
+	.owner = THIS_MODULE,
+	.open = fwlog_open,
+	.release = single_release,
+	.read = seq_read,
+};
+
+static int create_fwlog_file(struct vpu_dev *dev)
+{
+	if (dev->debugfs_root == NULL) {
+		dev->debugfs_root = debugfs_create_dir("vpu", NULL);
+		if (!dev->debugfs_root) {
+			vpu_err("error: create debugfs_root fail\n");
+			return -EINVAL;
+		}
+	}
+
+	if (dev->debugfs_fwlog)
+		return 0;
+	dev->debugfs_fwlog = debugfs_create_file("vpu_malone_log",
+						VERIFY_OCTAL_PERMISSIONS(0444),
+						dev->debugfs_root,
+						dev,
+						&fwlog_fops);
+	if (!dev->debugfs_fwlog) {
+		vpu_err("error: create debugfs_fwlog fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static ssize_t show_instance_command_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_ctx *ctx;
+	struct vpu_statistic *statistic;
+	int i, size, num = 0;
+
+	ctx = container_of(attr, struct vpu_ctx, dev_attr_instance_command);
+	statistic = &ctx->statistic;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "command number:\n");
+	for (i = VID_API_CMD_NULL; i < VID_API_CMD_TS + 1; i++) {
+		size = scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%40s(%2d):%16ld\n",
+				cmd2str[i], i, statistic->cmd[i]);
+		num += size;
+	}
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\t%40s    :%16ld\n",
+			"UNKNOWN COMMAND", statistic->cmd[VID_API_CMD_TS + 1]);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "current command:\n");
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"%10s:%40s;%10lld.%06ld\n", "command",
+			get_cmd_str(statistic->current_cmd),
+			statistic->ts_cmd.tv_sec,
+			statistic->ts_cmd.tv_nsec / 1000);
+
+	if (ctx->pending)
+		num += scnprintf(buf + num, PAGE_SIZE - num, "pending\n");
+
+	return num;
+}
+
+static ssize_t show_instance_event_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_ctx *ctx;
+	struct vpu_statistic *statistic;
+	int i, size, num = 0;
+
+	ctx = container_of(attr, struct vpu_ctx, dev_attr_instance_event);
+	statistic = &ctx->statistic;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "event number:\n");
+	for (i = VID_API_EVENT_NULL; i < VID_API_EVENT_DEC_CFG_INFO + 1; i++) {
+		size = scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%40s(%2d):%16ld\n",
+				event2str[i], i, statistic->event[i]);
+		num += size;
+	}
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\t%40s    :%16ld\n",
+			"UNKNOWN EVENT",
+			statistic->event[VID_API_EVENT_DEC_CFG_INFO + 1]);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "current event:\n");
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"%10s:%40s;%10lld.%06ld\n", "event",
+			get_event_str(statistic->current_event),
+			statistic->ts_event.tv_sec,
+			statistic->ts_event.tv_nsec / 1000);
+
+	return num;
+}
+
+static ssize_t show_instance_buffer_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_ctx *ctx;
+	struct vpu_statistic *statistic;
+	struct vb2_data_req *p_data_req;
+	struct queue_data *This;
+	pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+	u_int32 stream_length = 0;
+	int i, size, num = 0;
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	pBUFFER_INFO_TYPE buffer_info;
+
+	ctx = container_of(attr, struct vpu_ctx, dev_attr_instance_buffer);
+	statistic = &ctx->statistic;
+	pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+	buffer_info = &pSharedInterface->StreamBuffInfo[ctx->str_index];
+
+	This = &ctx->q_data[V4L2_SRC];
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"output buffer status(%d):\n", This->vb2_q.num_buffers);
+	for (i = 0; i < This->vb2_q.num_buffers; i++) {
+		p_data_req = &This->vb2_reqs[i];
+		if (!p_data_req->vb2_buf)
+			continue;
+		if (!p_data_req->queued)
+			continue;
+		num += scnprintf(buf + num, PAGE_SIZE - num,
+					"\t%40s(%2d):queued\n",
+					"buffer", i);
+	}
+
+	This = &ctx->q_data[V4L2_DST];
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"frame buffer status(%d):\n", This->vb2_q.num_buffers);
+	for (i = 0; i < VPU_MAX_BUFFER; i++) {
+		p_data_req = &This->vb2_reqs[i];
+		if (p_data_req->vb2_buf != NULL) {
+			size = scnprintf(buf + num, PAGE_SIZE - num,
+					"\t%40s(%2d):%16s:%d\n",
+					"buffer",
+					i,
+					bufstat[p_data_req->status],
+					p_data_req->vb2_buf->state);
+			num += size;
+		}
+	}
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "stream buffer status:\n");
+
+	pStrBufDesc = get_str_buffer_desc(ctx);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16x\n", "wptr", pStrBufDesc->wptr);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16x\n", "rptr", pStrBufDesc->rptr);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16x\n", "start", pStrBufDesc->start);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16x\n", "end", pStrBufDesc->end);
+	if (ctx->stream_buffer.dma_size)
+		stream_length = got_used_space(pStrBufDesc->wptr,
+						pStrBufDesc->rptr,
+						pStrBufDesc->start,
+						pStrBufDesc->end);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d / %16d\n", "stream length",
+			stream_length,
+			ctx->stream_buffer.dma_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "decode delay frame",
+			ctx->frm_dec_delay);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "display delay frame",
+			ctx->frm_dis_delay);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "total frame number",
+			ctx->frm_total_num);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16lld\n", "timestamp threshold(ms)",
+			ctx->ts_threshold);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%6lld,%09lld\n", "output timestamp(ns)",
+			ctx->output_ts / NSEC_PER_SEC,
+			ctx->output_ts % NSEC_PER_SEC);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%6lld,%09lld\n", "capture timestamp(ns)",
+			ctx->capture_ts / NSEC_PER_SEC,
+			ctx->capture_ts % NSEC_PER_SEC);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "bitstream low threshold",
+			ctx->bs_l_threshold);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "bitstream high threshold",
+			ctx->bs_h_threshold);
+
+	This = &ctx->q_data[V4L2_SRC];
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "output qbuf count",
+			This->qbuf_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "output dqbuf count",
+			This->dqbuf_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "output write count",
+			This->process_count);
+
+	This = &ctx->q_data[V4L2_DST];
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "capture qbuf count",
+			This->qbuf_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "capture dqbuf count",
+			This->dqbuf_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16ld\n", "skipped frame count",
+			ctx->statistic.skipped_frame_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16x\n", "beginning",
+			ctx->beginning);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "request frame count",
+			ctx->req_frame_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%12s%c%c%c%c\n",
+			"output pixel format", "",
+			ctx->q_data[V4L2_SRC].fourcc & 0xff,
+			(ctx->q_data[V4L2_SRC].fourcc >> 8) & 0xff,
+			(ctx->q_data[V4L2_SRC].fourcc >> 16) & 0xff,
+			(ctx->q_data[V4L2_SRC].fourcc >> 24) & 0xff);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%12s%c%c%c%c\n",
+			"capture pixel format", "",
+			ctx->q_data[V4L2_DST].fourcc & 0xff,
+			(ctx->q_data[V4L2_DST].fourcc >> 8) & 0xff,
+			(ctx->q_data[V4L2_DST].fourcc >> 16) & 0xff,
+			(ctx->q_data[V4L2_DST].fourcc >> 24) & 0xff);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%13d(%d)\n", "output status",
+			ctx->q_data[V4L2_SRC].enable,
+			vb2_is_streaming(&ctx->q_data[V4L2_SRC].vb2_q));
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%13d(%d)\n", "capture status",
+			ctx->q_data[V4L2_DST].enable,
+			vb2_is_streaming(&ctx->q_data[V4L2_DST].vb2_q));
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s: %dx%d(%dx%d), %d(DPB), %d(Ref), %d(DFE)\n",
+			"seqinfo",
+			ctx->seqinfo.uHorRes,
+			ctx->seqinfo.uVerRes,
+			ctx->seqinfo.uHorDecodeRes,
+			ctx->seqinfo.uVerDecodeRes,
+			ctx->seqinfo.uNumDPBFrms,
+			ctx->seqinfo.uNumRefFrms,
+			ctx->seqinfo.uNumDFEAreas & 0xff);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d/%16d/%16d(0x%x)\n", "mbi_count",
+			ctx->mbi_index, ctx->mbi_count, ctx->req_mbi_count,
+			ctx->mbi_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d/%16d/%16d(0x%x, %d, %d)\n", "dcp_count",
+			ctx->dcp_index, ctx->dcp_count, ctx->req_dcp_count,
+			ctx->dcp_size,
+			ctx->seqinfo.uNumDFEAreas >> 16,
+			DCP_FIXED_MB_ALLOC);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "stream_pic_input_count",
+			buffer_info->stream_pic_input_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "stream_pic_parsed_count",
+			buffer_info->stream_pic_parsed_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "stream_pic_end_flag",
+			buffer_info->stream_pic_end_flag);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "stream_input_mode",
+			buffer_info->stream_input_mode);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "stream_buffer_threshold",
+			buffer_info->stream_buffer_threshold);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "start_code_bypass",
+			ctx->start_code_bypass);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "ctx released",
+			ctx->ctx_released);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "msg kfifo length",
+			kfifo_len(&ctx->msg_fifo));
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16d\n", "mu kfifo length",
+			kfifo_len(&ctx->dev->mu_msg_fifo));
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%16lld,%16lld\n", "memory used",
+			atomic64_read(&ctx->statistic.total_alloc_size),
+			atomic64_read(&ctx->statistic.total_dma_size));
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"\t%40s:%12d.%d.%d\n", "firmware version",
+			(pSharedInterface->FWVersion & 0x00ff0000) >> 16,
+			(pSharedInterface->FWVersion & 0x0000ff00) >> 8,
+			pSharedInterface->FWVersion & 0x000000ff);
+
+	return num;
+}
+
+static ssize_t show_instance_log_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_ctx *ctx;
+	struct vpu_statistic *statistic;
+	struct vpu_log_info *vpu_info;
+	struct vpu_log_info *tem_info;
+	int num = 0;
+
+	ctx = container_of(attr, struct vpu_ctx, dev_attr_instance_flow);
+	statistic = &ctx->statistic;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "log info under depth: %d\n",
+			vpu_log_depth);
+
+	mutex_lock(&ctx->instance_mutex);
+	if (list_empty(&ctx->log_q))
+		goto exit;
+
+	list_for_each_entry_safe(vpu_info, tem_info, &ctx->log_q, list) {
+		switch (vpu_info->type) {
+		case LOG_EVENT:
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%20s:%40s %20s:%20x\n", "event", get_event_str(vpu_info->log_info[vpu_info->type]),
+				"rptr", vpu_info->data);
+			break;
+		case LOG_COMMAND:
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%20s:%40s\n", "command", get_cmd_str(vpu_info->log_info[vpu_info->type]));
+			break;
+		case LOG_EOS:
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%20s:%40s\n", "add eos", "done");
+			break;
+		case LOG_PADDING:
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%20s:%40s\n", "add padding", "done");
+			break;
+		case LOG_UPDATE_STREAM:
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"\t%20s:%40s %16d\n", "update stream data", "stream size", vpu_info->data);
+			break;
+		default:
+			break;
+		}
+	}
+
+exit:
+	mutex_unlock(&ctx->instance_mutex);
+	return num;
+}
+
+static ssize_t show_instance_perf_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_ctx *ctx;
+	struct vpu_statistic *statistic;
+	int num = 0;
+	u_int64 start_time = 0;
+	u_int64 prev_time = 0;
+	u_int64 interv = 0;
+	u_int64 total = 0;
+	struct vpu_dec_perf_queue *perf;
+	struct vpu_dec_perf_queue *tmp;
+	int i = 0;
+
+	ctx = container_of(attr, struct vpu_ctx, dev_attr_instance_perf);
+	statistic = &ctx->statistic;
+
+	if (!vpu_show_perf_ena)
+		return num;
+	if (!(vpu_show_perf_idx & (1<<ctx->str_index)))
+		return num;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "beginning:\n");
+	num += scnprintf(
+		buf + num, PAGE_SIZE - num,
+		"unit: ms \t\t time-point \t   interval    total\n");
+
+	mutex_lock(&ctx->perf_lock);
+	list_for_each_entry_safe(perf, tmp, &ctx->perf_q, list) {
+		if (i == 0) {
+			start_time = perf->time;
+			prev_time = perf->time;
+		}
+
+		interv = perf->time - prev_time;
+		total = perf->time - start_time;
+		num += scnprintf(buf + num, PAGE_SIZE - num,
+				 "%40s: %8ld %8ld\n", perf->str, interv, total);
+		prev_time = perf->time;
+
+		if (++i > 50) {
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+				"Too many initialization steps, omitting the following\n");
+			break;
+		}
+	}
+	mutex_unlock(&ctx->perf_lock);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "decoded:\n");
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\t count: %8ld \t fps: %8ld\n",
+			ctx->statistic.event[VID_API_EVENT_PIC_DECODED],
+			ctx->perf_time.decoded_fps);
+	num += scnprintf(buf + num, PAGE_SIZE - num, "ready:\n");
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\t count: %8ld \t fps: %8ld\n",
+			ctx->statistic.event[VID_API_EVENT_FRAME_BUFF_RDY],
+			ctx->perf_time.ready_fps);
+
+	return num;
+}
+
+static ssize_t precheck_pattern_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	int num = 0;
+
+	if (vdev->precheck_num)
+		num = scnprintf(buf, PAGE_SIZE, "%s\n", vdev->precheck_content);
+
+	return num;
+}
+
+static ssize_t precheck_pattern_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	long val;
+	int num = 0;
+	int bytes = 0;
+	const char *delim = " ,;";
+	char strbuf[1024];
+	char *token;
+	char *cur;
+
+	strncpy(strbuf, buf, sizeof(strbuf) - 1);
+	cur = strbuf;
+	while ((token = strsep(&cur, delim))) {
+		if (!strlen(token))
+			continue;
+		if (kstrtol((const char *)token, 0, &val))
+			continue;
+		vdev->precheck_pattern[num] = val;
+		bytes += scnprintf(vdev->precheck_content + bytes,
+					sizeof(vdev->precheck_content) - bytes,
+					"%s0x%02x",
+					num ? " " : "",
+					vdev->precheck_pattern[num]);
+		num++;
+		if (num >= ARRAY_SIZE(vdev->precheck_pattern))
+			break;
+	}
+	get_kmp_next(vdev->precheck_pattern, vdev->precheck_next, num);
+	if (num >= 3)
+		vdev->precheck_num = num;
+	else
+		vdev->precheck_num = 0;
+
+	return count;
+}
+DEVICE_ATTR_RW(precheck_pattern);
+
+static int create_instance_command_file(struct vpu_ctx *ctx)
+{
+	scnprintf(ctx->command_name, sizeof(ctx->command_name) - 1,
+			"instance%d_command",
+			ctx->str_index);
+	sysfs_attr_init(&ctx->dev_attr_instance_command.attr);
+	ctx->dev_attr_instance_command.attr.name = ctx->command_name;
+	ctx->dev_attr_instance_command.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	ctx->dev_attr_instance_command.show = show_instance_command_info;
+
+	device_create_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_command);
+
+	return 0;
+}
+
+static int create_instance_event_file(struct vpu_ctx *ctx)
+{
+	scnprintf(ctx->event_name, sizeof(ctx->event_name) - 1,
+			"instance%d_event",
+			ctx->str_index);
+	sysfs_attr_init(&ctx->dev_attr_instance_event.attr);
+	ctx->dev_attr_instance_event.attr.name = ctx->event_name;
+	ctx->dev_attr_instance_event.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	ctx->dev_attr_instance_event.show = show_instance_event_info;
+
+	device_create_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_event);
+
+	return 0;
+}
+
+static int create_instance_buffer_file(struct vpu_ctx *ctx)
+{
+	scnprintf(ctx->buffer_name, sizeof(ctx->buffer_name) - 1,
+			"instance%d_buffer",
+			ctx->str_index);
+	sysfs_attr_init(&ctx->dev_attr_instance_buffer.attr);
+	ctx->dev_attr_instance_buffer.attr.name = ctx->buffer_name;
+	ctx->dev_attr_instance_buffer.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	ctx->dev_attr_instance_buffer.show = show_instance_buffer_info;
+
+	device_create_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_buffer);
+
+	return 0;
+}
+
+static int create_instance_flow_file(struct vpu_ctx *ctx)
+{
+	scnprintf(ctx->flow_name, sizeof(ctx->flow_name) - 1,
+			"instance%d_flow",
+			ctx->str_index);
+	sysfs_attr_init(&ctx->dev_attr_instance_flow.attr);
+	ctx->dev_attr_instance_flow.attr.name = ctx->flow_name;
+	ctx->dev_attr_instance_flow.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	ctx->dev_attr_instance_flow.show = show_instance_log_info;
+
+	device_create_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_flow);
+
+	return 0;
+}
+
+static int create_instance_perf_file(struct vpu_ctx *ctx)
+{
+	scnprintf(ctx->perf_name, sizeof(ctx->perf_name) - 1,
+			"instance%d_perf",
+			ctx->str_index);
+	sysfs_attr_init(&ctx->dev_attr_instance_perf.attr);
+	ctx->dev_attr_instance_perf.attr.name = ctx->perf_name;
+	ctx->dev_attr_instance_perf.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	ctx->dev_attr_instance_perf.show = show_instance_perf_info;
+
+	device_create_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_perf);
+
+	return 0;
+}
+
+static int create_instance_file(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->dev || !ctx->dev->generic_dev)
+		return -EINVAL;
+
+	create_instance_command_file(ctx);
+	create_instance_event_file(ctx);
+	create_instance_buffer_file(ctx);
+	create_instance_flow_file(ctx);
+	create_instance_perf_file(ctx);
+
+
+	return 0;
+}
+
+static int remove_instance_file(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->dev || !ctx->dev->generic_dev)
+		return -EINVAL;
+
+	device_remove_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_command);
+	device_remove_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_event);
+	device_remove_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_buffer);
+	device_remove_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_flow);
+	device_remove_file(ctx->dev->generic_dev, &ctx->dev_attr_instance_perf);
+
+	return 0;
+}
+
+static int init_vpu_buffer(struct vpu_ctx *ctx)
+{
+	u_int32 i;
+
+	if (!ctx)
+		return -EINVAL;
+
+	for (i = 0; i < MAX_DCP_NUM; i++)
+		init_dma_buffer(&ctx->dcp_buffer[i]);
+	ctx->dcp_count = 0;
+	for (i = 0; i < MAX_MBI_NUM; i++)
+		init_dma_buffer(&ctx->mbi_buffer[i]);
+	ctx->mbi_count = 0;
+	ctx->mbi_size = 0;
+	init_dma_buffer(&ctx->stream_buffer);
+	init_dma_buffer(&ctx->udata_buffer);
+
+	return 0;
+}
+
+static int alloc_vpu_buffer(struct vpu_ctx *ctx)
+{
+	u_int32 ret = 0;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (!ctx->stream_buffer.dma_phy) {
+		ctx->stream_buffer.dma_size = vpu_max_bufsize;
+		ret = alloc_dma_buffer(ctx, &ctx->stream_buffer);
+		if (ret) {
+			vpu_err("error: alloc stream buffer fail!\n");
+			return ret;
+		}
+	}
+
+	if (!ctx->udata_buffer.dma_phy) {
+		ctx->udata_buffer.dma_size = UDATA_BUFFER_SIZE;
+		ret = alloc_dma_buffer(ctx, &ctx->udata_buffer);
+		if (ret) {
+			vpu_err("error: alloc udata buffer fail!\n");
+			free_dma_buffer(ctx, &ctx->stream_buffer);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int open_crc_file(struct vpu_ctx *ctx)
+{
+	char crc_file[64];
+	int ret = 0;
+
+	if (!ctx)
+		return -EINVAL;
+
+	scnprintf(crc_file, sizeof(crc_file) - 1,
+			"/data/instance%d_crc.txt",
+			ctx->str_index);
+	ctx->crc_fp = filp_open(crc_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
+	if (IS_ERR(ctx->crc_fp)) {
+		vpu_err("error: open crc file fail\n");
+		ret = -1;
+	}
+	ctx->pos = 0;
+
+	return ret;
+}
+
+static int close_crc_file(struct vpu_ctx *ctx)
+{
+	int ret = 0;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (!IS_ERR(ctx->crc_fp))
+		ret = filp_close(ctx->crc_fp, NULL);
+	ctx->pos = 0;
+
+	return ret;
+}
+
+static bool vpu_dec_is_active(struct vpu_ctx *ctx)
+{
+	bool status = true;
+
+	if (!ctx)
+		return false;
+	if (ctx->firmware_stopped)
+		return false;
+	mutex_lock(&ctx->cmd_lock);
+	if (ctx->pending && ctx->pending->request == VID_API_CMD_STOP)
+		status = false;
+	mutex_unlock(&ctx->cmd_lock);
+
+	return status;
+}
+
+static int v4l2_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct vpu_dev *dev = video_get_drvdata(vdev);
+	struct vpu_ctx *ctx = NULL;
+	int idx;
+	int ret = 0;
+
+	pm_runtime_get_sync(dev->generic_dev);
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		pm_runtime_put_sync(dev->generic_dev);
+		return -ENOMEM;
+	}
+	mutex_lock(&dev->dev_mutex);
+	idx = vpu_next_free_instance(dev);
+	if (idx < 0) {
+		ret = idx;
+		mutex_unlock(&dev->dev_mutex);
+		goto err_find_index;
+	}
+	set_bit(idx, &dev->instance_mask);
+	mutex_unlock(&dev->dev_mutex);
+	init_completion(&ctx->completion);
+	init_completion(&ctx->stop_cmp);
+	init_completion(&ctx->eos_cmp);
+
+	v4l2_fh_init(&ctx->fh, video_devdata(filp));
+	filp->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	ctx->ctrl_inited = false;
+	ctrls_setup_decoder(ctx);
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+	ctx->instance_wq = alloc_workqueue("vpu_instance", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!ctx->instance_wq) {
+		vpu_err("error: %s unable to alloc workqueue for ctx\n", __func__);
+		ret = -ENOMEM;
+		goto err_alloc_wq;
+	}
+	ctx->instance_work = &dev->ctx_work[idx].instance_work;
+	ctx->delayed_instance_work = &dev->ctx_work[idx].delayed_instance_work;
+
+	mutex_init(&ctx->instance_mutex);
+	mutex_init(&ctx->cmd_lock);
+	mutex_init(&ctx->perf_lock);
+	mutex_init(&ctx->fw_flow_mutex);
+	atomic64_set(&ctx->statistic.total_dma_size, 0);
+	atomic64_set(&ctx->statistic.total_alloc_size, 0);
+
+	ctx->msg_buffer_size = sizeof(struct event_msg) * VID_API_MESSAGE_LIMIT;
+	if (!is_power_of_2(ctx->msg_buffer_size))
+		ctx->msg_buffer_size = roundup_pow_of_two(ctx->msg_buffer_size);
+	ctx->msg_buffer = vzalloc(ctx->msg_buffer_size);
+	if (!ctx->msg_buffer) {
+		vpu_err("fail to alloc fifo when open\n");
+		ret = -ENOMEM;
+		goto err_alloc_fifo;
+	}
+	atomic64_add(ctx->msg_buffer_size, &ctx->statistic.total_alloc_size);
+	if (kfifo_init(&ctx->msg_fifo, ctx->msg_buffer, ctx->msg_buffer_size)) {
+		vpu_err("fail to init fifo when open\n");
+		ret = -EINVAL;
+		goto err_init_kfifo;
+	}
+	ctx->dev = dev;
+	ctx->str_index = idx;
+	dev->ctx[idx] = ctx;
+	ctx->b_firstseq = true;
+	ctx->wait_rst_done = false;
+	ctx->wait_res_change_done = false;
+	ctx->firmware_stopped = true;
+	ctx->firmware_finished = false;
+	ctx->frame_decoded = false;
+	ctx->eos_stop_received = false;
+	ctx->eos_stop_added = false;
+	ctx->ctx_released = false;
+	ctx->b_dis_reorder = false;
+	ctx->start_code_bypass = false;
+	ctx->stream_input_mode = FRAME_LVL;
+	ctx->hang_status = false;
+	ctx->first_dump_data_flag = true;
+	ctx->colorspace = V4L2_COLORSPACE_REC709;
+	ctx->xfer_func = V4L2_XFER_FUNC_709;
+	ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
+	ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+	INIT_LIST_HEAD(&ctx->cmd_q);
+	INIT_LIST_HEAD(&ctx->perf_q);
+	ctx->output_ts = TSM_TIMESTAMP_NONE;
+	ctx->capture_ts = TSM_TIMESTAMP_NONE;
+	create_instance_file(ctx);
+	if (vpu_frmcrcdump_ena) {
+		ret = open_crc_file(ctx);
+		if (ret)
+			goto err_open_crc;
+	}
+	ctx->seqinfo.uProgressive = 1;
+
+	init_queue_data(ctx);
+	init_log_info_queue(ctx);
+	create_log_info_queue(ctx, vpu_log_depth);
+	mutex_lock(&dev->dev_mutex);
+	if (!dev->fw_is_ready) {
+		ret = vpu_firmware_download(dev);
+		if (ret) {
+			vpu_err("error: vpu_firmware_download fail\n");
+			mutex_unlock(&dev->dev_mutex);
+			goto err_firmware_load;
+		}
+		vpu_dbg(LVL_INFO, "done: vpu_firmware_download\n");
+		if (!ctx->dev->firmware_started) {
+			reinit_completion(&ctx->dev->start_cmp);
+			if (!wait_for_completion_timeout(&ctx->dev->start_cmp, msecs_to_jiffies(1000))) {
+				vpu_err("error: don't get start interrupt\n");
+				ret = -1;
+				mutex_unlock(&dev->dev_mutex);
+				goto err_firmware_load;
+			}
+		}
+		dev->fw_is_ready = true;
+	}
+	create_fwlog_file(ctx->dev);
+	create_dbglog_file(ctx->dev);
+	mutex_unlock(&dev->dev_mutex);
+	rpc_init_instance(&dev->shared_mem, ctx->str_index);
+	rpc_set_stream_cfg_value(dev->shared_mem.pSharedInterface, ctx->str_index, vpu_dbe_num);
+	init_vpu_buffer(ctx);
+
+	vpu_dbg(LVL_BIT_FLOW, "<%d> ctx[%d] open\n",
+			current->pid, ctx->str_index);
+	vpu_calculate_performance(ctx, 0xff, "open device");
+
+	return 0;
+
+err_firmware_load:
+	destroy_log_info_queue(ctx);
+	cleanup_perf_queue(ctx);
+	release_queue_data(ctx);
+
+	if (vpu_frmcrcdump_ena)
+		close_crc_file(ctx);
+err_open_crc:
+	remove_instance_file(ctx);
+	dev->ctx[idx] = NULL;
+err_init_kfifo:
+	vfree(ctx->msg_buffer);
+	atomic64_sub(ctx->msg_buffer_size, &ctx->statistic.total_alloc_size);
+	ctx->msg_buffer = NULL;
+	ctx->msg_buffer_size = 0;
+err_alloc_fifo:
+	mutex_destroy(&ctx->instance_mutex);
+	mutex_destroy(&ctx->cmd_lock);
+	mutex_destroy(&ctx->perf_lock);
+	mutex_destroy(&ctx->fw_flow_mutex);
+	destroy_workqueue(ctx->instance_wq);
+err_alloc_wq:
+	ctrls_delete_decoder(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	clear_bit(ctx->str_index, &dev->instance_mask);
+err_find_index:
+	if (atomic64_read(&ctx->statistic.total_alloc_size) != 0)
+		vpu_err("error: memory leak for vpu kalloc buffer\n");
+	kfree(ctx);
+	pm_runtime_put_sync(dev->generic_dev);
+
+	return ret;
+}
+
+static void vpu_dec_disable(struct vpu_ctx *ctx, struct queue_data *queue)
+{
+	bool enable = false;
+
+	down(&queue->drv_q_lock);
+	if (queue->enable) {
+		enable = true;
+		queue->enable = false;
+	}
+	up(&queue->drv_q_lock);
+
+	if (!enable)
+		return;
+
+	vpu_dbg(LVL_BIT_FLOW, "Pls stream off %s of ctx[%d] before release\n",
+		V4L2_TYPE_IS_OUTPUT(queue->vb2_q.type) ? "Output" : "Capture",
+		ctx->str_index);
+	if (!V4L2_TYPE_IS_OUTPUT(queue->vb2_q.type)) {
+		mutex_lock(&ctx->fw_flow_mutex);
+		send_abort_cmd(ctx);
+		mutex_unlock(&ctx->fw_flow_mutex);
+		ctx->capture_ts = TSM_TIMESTAMP_NONE;
+	} else {
+		ctx->output_ts = TSM_TIMESTAMP_NONE;
+	}
+
+	vpu_dec_queue_disable(queue, queue->vb2_q.type);
+}
+
+static int v4l2_release(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct vpu_dev *dev = video_get_drvdata(vdev);
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+	vpu_dbg(LVL_BIT_FLOW, "<%d> ctx[%d] close\n",
+			current->pid, ctx->str_index);
+	vpu_dbg(LVL_BIT_FUNC,
+		"ctx[%d]: %s() - %s, %s, %s, total frame: %d\n",
+		ctx->str_index,
+		__func__,
+		ctx->firmware_stopped ? "stopped" : "not stopped",
+		ctx->firmware_finished ? "finished" : "not finished",
+		ctx->eos_stop_added ? "eos_added" : "not eos_added",
+		ctx->frm_total_num);
+
+	vpu_dec_disable(ctx, &ctx->q_data[V4L2_SRC]);
+	vpu_dec_disable(ctx, &ctx->q_data[V4L2_DST]);
+
+	mutex_lock(&ctx->fw_flow_mutex);
+	send_stop_cmd(ctx);
+	mutex_unlock(&ctx->fw_flow_mutex);
+
+	mutex_lock(&ctx->dev->dev_mutex);
+	ctx->ctx_released = true;
+	mutex_unlock(&ctx->dev->dev_mutex);
+
+	cancel_delayed_work_sync(ctx->delayed_instance_work);
+	cancel_work_sync(ctx->instance_work);
+	vfree(ctx->msg_buffer);
+	atomic64_sub(ctx->msg_buffer_size, &ctx->statistic.total_alloc_size);
+	ctx->msg_buffer = NULL;
+	ctx->msg_buffer_size = 0;
+	if (ctx->instance_wq)
+		destroy_workqueue(ctx->instance_wq);
+
+	if (vpu_frmcrcdump_ena)
+		close_crc_file(ctx);
+	ctrls_delete_decoder(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	mutex_lock(&dev->dev_mutex);
+	if (!ctx->hang_status)
+		release_vpu_ctx(ctx);
+	else
+		set_bit(ctx->str_index, &dev->hang_mask);
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+}
+
+static unsigned int v4l2_poll(struct file *filp, poll_table *wait)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+	struct vb2_queue *src_q, *dst_q;
+	unsigned int rc = 0;
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	poll_wait(filp, &ctx->fh.wait, wait);
+
+	if (v4l2_event_pending(&ctx->fh)) {
+		vpu_dbg(LVL_INFO, "%s() v4l2_event_pending\n", __func__);
+		rc |= POLLPRI;
+	}
+
+	src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+	dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+	if (ctx->firmware_finished && !src_q->streaming && !dst_q->streaming)
+		return POLLERR;
+
+	if ((ctx->firmware_finished || ctx->wait_res_change_done) &&
+	     !list_empty(&dst_q->done_list))
+		rc = 0;
+
+	poll_wait(filp, &src_q->done_wq, wait);
+	if (!list_empty(&src_q->done_list))
+		rc |= POLLOUT | POLLWRNORM;
+	poll_wait(filp, &dst_q->done_wq, wait);
+	if (!list_empty(&dst_q->done_list))
+		rc |= POLLIN | POLLRDNORM;
+
+	return rc;
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	long ret = -EPERM;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct queue_data *q_data;
+	enum QUEUE_TYPE type;
+
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+
+	if (ctx) {
+		type = offset >> MMAP_BUF_TYPE_SHIFT;
+		q_data = &ctx->q_data[type];
+
+		offset &= ~MMAP_BUF_TYPE_MASK;
+		offset = offset >> PAGE_SHIFT;
+		vma->vm_pgoff = offset;
+		ret = vpu_dec_queue_mmap(q_data, vma);
+	}
+
+	return ret;
+}
+
+static const struct v4l2_file_operations v4l2_decoder_fops = {
+	.owner = THIS_MODULE,
+	.open  = v4l2_open,
+	.unlocked_ioctl = video_ioctl2,
+	.release = v4l2_release,
+	.poll = v4l2_poll,
+	.mmap = v4l2_mmap,
+};
+
+static struct video_device v4l2_videodevice_decoder = {
+	.name   = "vpu decoder",
+	.fops   = &v4l2_decoder_fops,
+	.ioctl_ops = &v4l2_decoder_ioctl_ops,
+	.vfl_dir = VFL_DIR_M2M,
+};
+
+static void vpu_setup(struct vpu_dev *This)
+{
+	uint32_t read_data = 0;
+
+	vpu_dbg(LVL_BIT_FUNC, "enter %s\n", __func__);
+	writel(0x1, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+	writel(0xffffffff, This->regs_base + 0x70190);
+	writel(0xffffffff, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+	writel(0xE, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+	writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+	writel(0x1f, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET);
+	writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_SET);
+
+	writel(0x102, This->regs_base + XMEM_CONTROL);
+
+	read_data = readl(This->regs_base+0x70108);
+	vpu_dbg(LVL_INFO, "%s read_data=%x\n", __func__, read_data);
+}
+
+static int vpu_enable_hw(struct vpu_dev *This)
+{
+	vpu_dbg(LVL_BIT_FUNC, "%s()\n", __func__);
+	vpu_setup(This);
+	return 0;
+}
+static void vpu_disable_hw(struct vpu_dev *This)
+{
+}
+
+static int swreset_vpu_firmware(struct vpu_dev *dev, u_int32 idx)
+{
+	int ret = 0;
+
+	if (!dev)
+		return 0;
+
+	vpu_dbg(LVL_WARN, "SWRESET: swreset_vpu_firmware\n");
+	dev->firmware_started = false;
+	kfifo_reset(&dev->mu_msg_fifo);
+
+	reinit_completion(&dev->start_cmp);
+	vpu_dec_send_cmd(dev, 0, VID_API_CMD_FIRM_RESET, 0, NULL);
+	if (!wait_for_completion_timeout(&dev->start_cmp, msecs_to_jiffies(10000))) {
+		vpu_err("error: %s() fail\n", __func__);
+		return -1;
+	}
+	dev->firmware_started = true;
+
+	return ret;
+}
+
+static int parse_dt_info(struct vpu_dev *dev, struct device_node *np)
+{
+	u_int32 core_type;
+	struct resource reserved_res;
+	struct device_node *reserved_node;
+	u_int32 csr_base;
+	int ret;
+
+	if (!dev || !np)
+		return -EINVAL;
+
+	ret = of_property_read_u32(np, "core_type", &core_type);
+	if (ret) {
+		vpu_err("error: Cannot get core num %d\n", ret);
+		return -EINVAL;
+	}
+	if (core_type == 2)
+		dev->plat_type = IMX8QM;
+	else
+		dev->plat_type = IMX8QXP;
+	reserved_node = of_parse_phandle(np, "boot-region", 0);
+	if (!reserved_node) {
+		vpu_err("error: boot-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+		vpu_err("error: boot-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+	dev->m0_p_fw_space_phy = reserved_res.start;
+	dev->m0_boot_size = reserved_res.end - reserved_res.start;
+	reserved_node = of_parse_phandle(np, "rpc-region", 0);
+	if (!reserved_node) {
+		vpu_err("error: rpc-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+		vpu_err("error: rpc-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+	dev->m0_rpc_phy = reserved_res.start;
+	dev->m0_rpc_size = reserved_res.end - reserved_res.start;
+
+	ret = of_property_read_u32(np, "reg-csr", &csr_base);
+	if (ret) {
+		vpu_err("error: Cannot get csr offset %d\n", ret);
+		return -EINVAL;
+	}
+	dev->csr_base = ioremap(csr_base, 8); //for csr0 offset and cpuwait
+
+	return 0;
+}
+
+static int create_vpu_video_device(struct vpu_dev *dev)
+{
+	int ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	dev->pvpu_decoder_dev = video_device_alloc();
+	if (!dev->pvpu_decoder_dev) {
+		vpu_err("video device alloc for decoder fail\n");
+		return -ENOMEM;
+	}
+	strlcpy(dev->pvpu_decoder_dev->name,
+			v4l2_videodevice_decoder.name,
+			sizeof(dev->pvpu_decoder_dev->name));
+	dev->pvpu_decoder_dev->fops = v4l2_videodevice_decoder.fops;
+	dev->pvpu_decoder_dev->ioctl_ops = v4l2_videodevice_decoder.ioctl_ops;
+	dev->pvpu_decoder_dev->release = video_device_release;
+	dev->pvpu_decoder_dev->vfl_dir = v4l2_videodevice_decoder.vfl_dir;
+	dev->pvpu_decoder_dev->v4l2_dev = &dev->v4l2_dev;
+	dev->pvpu_decoder_dev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
+					     V4L2_CAP_STREAMING;
+
+	video_set_drvdata(dev->pvpu_decoder_dev, dev);
+
+	ret = video_register_device(dev->pvpu_decoder_dev,
+			VFL_TYPE_GRABBER,
+			DECODER_NODE_NUMBER);
+	if (ret) {
+		vpu_err("error: %s unable to register video decoder device\n",
+				__func__
+				);
+		video_device_release(dev->pvpu_decoder_dev);
+		dev->pvpu_decoder_dev = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static int init_vpudev_parameters(struct vpu_dev *dev)
+{
+	mutex_init(&dev->dev_mutex);
+	mutex_init(&dev->cmd_mutex);
+	init_completion(&dev->start_cmp);
+	init_completion(&dev->snap_done_cmp);
+	dev->firmware_started = false;
+	dev->need_cleanup_firmware = true;
+	dev->hang_mask = 0;
+	dev->instance_mask = 0;
+
+	//firmware space for M0
+	dev->m0_p_fw_space_vir = ioremap_wc(dev->m0_p_fw_space_phy,
+			dev->m0_boot_size
+			);
+	if (!dev->m0_p_fw_space_vir) {
+		vpu_err("error: failed to remap space for M0 firmware\n");
+		return -ENOMEM;
+	}
+
+	dev->m0_rpc_virt = ioremap_wc(dev->m0_rpc_phy,
+			dev->m0_rpc_size
+			);
+	if (!dev->m0_rpc_virt) {
+		vpu_err("error: failed to remap space for rpc shared memory\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void vpu_dec_init_rpc(struct vpu_dev *dev)
+{
+	cleanup_firmware_memory(dev);
+	memset_io(dev->m0_rpc_virt, 0, dev->m0_rpc_size);
+	rpc_init_shared_memory(&dev->shared_mem,
+				vpu_dec_cpu_phy_to_mu(dev, dev->m0_rpc_phy),
+				dev->m0_rpc_virt,
+				dev->m0_rpc_size);
+	dev->print_buf = dev->m0_rpc_virt + M0_PRINT_OFFSET;
+	rpc_set_system_cfg_value(dev->shared_mem.pSharedInterface,
+					VPU_REG_BASE);
+	dev->fw_is_ready = false;
+}
+
+static void vpu_dec_restore_rpc(struct vpu_dev *dev)
+{
+	vpu_dbg(LVL_WARN, "restore vpu decoder\n");
+	rpc_restore_shared_memory(&dev->shared_mem,
+				vpu_dec_cpu_phy_to_mu(dev, dev->m0_rpc_phy),
+				dev->m0_rpc_virt);
+	dev->print_buf = dev->m0_rpc_virt + M0_PRINT_OFFSET;
+	swreset_vpu_firmware(dev, 0);
+	dev->fw_is_ready = true;
+}
+
+static void vpu_dec_init_ctx_work(struct vpu_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		struct vpu_ctx_work *ctx_work = &dev->ctx_work[i];
+
+		ctx_work->str_index = i;
+		ctx_work->dev = dev;
+		INIT_WORK(&ctx_work->instance_work, vpu_msg_instance_work);
+		INIT_DELAYED_WORK(&ctx_work->delayed_instance_work,
+				vpu_msg_delayed_instance_work);
+	}
+}
+
+static int vpu_probe(struct platform_device *pdev)
+{
+	struct vpu_dev *dev;
+	struct resource *res;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->generic_dev = get_device(&pdev->dev);
+	dev->plat_dev = pdev;
+	ret = vpu_attach_pm_domains(dev);
+	if (ret)
+		goto err_put_dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dev->regs_base)) {
+		vpu_err("error: %s could not map regs_base\n", __func__);
+		ret = PTR_ERR(dev->regs_base);
+		goto err_det_pm;
+	}
+
+	ret = parse_dt_info(dev, np);
+	if (ret) {
+		vpu_err("error: %s parse device tree fail\n", __func__);
+		goto err_dev_iounmap;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	ret = vpu_sc_check_fuse(dev, formats_compressed_dec, ARRAY_SIZE(formats_compressed_dec));
+	if (ret)
+		goto err_dev_iounmap;
+
+	dev->mu_msg_buffer_size =
+		sizeof(u_int32) * VPU_MAX_NUM_STREAMS * VID_API_MESSAGE_LIMIT;
+	if (!is_power_of_2(dev->mu_msg_buffer_size))
+		dev->mu_msg_buffer_size = roundup_pow_of_two(dev->mu_msg_buffer_size);
+	dev->mu_msg_buffer = vzalloc(dev->mu_msg_buffer_size);
+	if (!dev->mu_msg_buffer) {
+		vpu_err("error: fail to alloc mu msg fifo\n");
+		goto err_dev_iounmap;
+	}
+	ret = kfifo_init(&dev->mu_msg_fifo,
+			dev->mu_msg_buffer, dev->mu_msg_buffer_size);
+	if (ret) {
+		vpu_err("error: fail to init mu msg fifo\n");
+		goto err_free_fifo;
+	}
+
+	dev->workqueue = alloc_workqueue("vpu", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!dev->workqueue) {
+		vpu_err("error: %s unable to alloc workqueue\n", __func__);
+		ret = -ENOMEM;
+		goto err_free_fifo;
+	}
+
+	INIT_WORK(&dev->msg_work, vpu_msg_run_work);
+	INIT_DELAYED_WORK(&dev->delayed_msg_work, vpu_msg_run_delayed_work);
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		vpu_err("failed to request mailbox, ret = %d\n", ret);
+		pm_runtime_put_noidle(&pdev->dev);
+		pm_runtime_set_suspended(&pdev->dev);
+		goto err_pm_runtime_get_sync;
+	}
+
+	ret = init_vpudev_parameters(dev);
+	if (ret) {
+		vpu_err("error: failed to init parameters for vpudev\n");
+		goto err_poweroff;
+	}
+
+	vpu_enable_hw(dev);
+	if (is_vpu_poweroff(dev))
+		vpu_dec_init_rpc(dev);
+	else
+		vpu_dec_restore_rpc(dev);
+
+	pm_runtime_put_sync(&pdev->dev);
+	device_create_file(&pdev->dev, &dev_attr_precheck_pattern);
+	vpu_dec_init_ctx_work(dev);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		vpu_err("error: %s unable to register v4l2 dev\n", __func__);
+		goto err_poweroff;
+	}
+	ret = create_vpu_video_device(dev);
+	if (ret) {
+		vpu_err("error: %s create vpu video device fail\n", __func__);
+		goto err_unreg_v4l2;
+	}
+
+	return 0;
+
+err_unreg_v4l2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+err_poweroff:
+	destroy_workqueue(dev->workqueue);
+	vpu_disable_hw(dev);
+	pm_runtime_put_sync(&pdev->dev);
+err_pm_runtime_get_sync:
+	pm_runtime_disable(&pdev->dev);
+err_free_fifo:
+	vfree(dev->mu_msg_buffer);
+	dev->mu_msg_buffer = NULL;
+	dev->mu_msg_buffer_size = 0;
+err_dev_iounmap:
+err_det_pm:
+	vpu_detach_pm_domains(dev);
+err_put_dev:
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+
+	return ret;
+}
+
+static int vpu_remove(struct platform_device *pdev)
+{
+	struct vpu_dev *dev = platform_get_drvdata(pdev);
+
+	device_remove_file(&pdev->dev, &dev_attr_precheck_pattern);
+	debugfs_remove_recursive(dev->debugfs_root);
+	dev->debugfs_root = NULL;
+	dev->debugfs_dbglog = NULL;
+	dev->debugfs_fwlog = NULL;
+	vfree(dev->mu_msg_buffer);
+	dev->mu_msg_buffer = NULL;
+	dev->mu_msg_buffer_size = 0;
+	vpu_dec_cancel_work(dev);
+	destroy_workqueue(dev->workqueue);
+	if (dev->m0_p_fw_space_vir)
+		iounmap(dev->m0_p_fw_space_vir);
+	if (dev->m0_pfw) {
+		release_firmware(dev->m0_pfw);
+		dev->m0_pfw = NULL;
+	}
+	dev->m0_p_fw_space_vir = NULL;
+	dev->m0_p_fw_space_phy = 0;
+	dev->m0_rpc_virt = NULL;
+	dev->m0_rpc_phy = 0;
+	if (dev->shared_mem.shared_mem_vir)
+		iounmap(dev->shared_mem.shared_mem_vir);
+	dev->shared_mem.shared_mem_vir = NULL;
+	dev->shared_mem.shared_mem_phy = 0;
+
+	vpu_disable_hw(dev);
+	pm_runtime_disable(&pdev->dev);
+
+	if (video_get_drvdata(dev->pvpu_decoder_dev))
+		video_unregister_device(dev->pvpu_decoder_dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	vpu_detach_pm_domains(dev);
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+
+	return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+
+	if (vpudev->generic_dev)
+		vpu_mu_free(vpudev);
+
+	return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+
+	if (vpudev->generic_dev)
+		ret = vpu_mu_request(vpudev);
+
+	return ret;
+}
+
+static int find_first_available_instance(struct vpu_dev *dev)
+{
+	int strIdx, i;
+
+	if (!dev)
+		return -EINVAL;
+
+	strIdx = (~dev->hang_mask) & (dev->instance_mask);
+
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		if (CHECK_BIT(strIdx, i)) {
+			strIdx = i;
+			break;
+		}
+	}
+
+	return strIdx;
+}
+
+static void v4l2_vpu_send_snapshot(struct vpu_dev *dev)
+{
+	int strIdx;
+
+	strIdx = find_first_available_instance(dev);
+	if (strIdx >= 0 && strIdx < VPU_MAX_NUM_STREAMS)
+		v4l2_vpu_send_cmd(dev->ctx[strIdx], strIdx, VID_API_CMD_SNAPSHOT, 0, NULL);
+	else
+		vpu_dbg(LVL_WARN, "warning: all path hang, need to reset\n");
+}
+
+static void vpu_dec_cancel_work(struct vpu_dev *vpudev)
+{
+	int i;
+
+	mutex_lock(&vpudev->dev_mutex);
+	vpudev->suspend = true;
+	mutex_unlock(&vpudev->dev_mutex);
+
+	cancel_delayed_work_sync(&vpudev->delayed_msg_work);
+	cancel_work_sync(&vpudev->msg_work);
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		struct vpu_ctx_work *ctx_work = &vpudev->ctx_work[i];
+
+		cancel_delayed_work_sync(&ctx_work->delayed_instance_work);
+		cancel_work_sync(&ctx_work->instance_work);
+	}
+}
+
+static void vpu_dec_resume_work(struct vpu_dev *vpudev)
+{
+	int i;
+
+	mutex_lock(&vpudev->dev_mutex);
+	vpudev->suspend = false;
+	queue_work(vpudev->workqueue, &vpudev->msg_work);
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		struct vpu_ctx *ctx = vpudev->ctx[i];
+
+		if (!ctx || ctx->ctx_released)
+			continue;
+		queue_work(ctx->instance_wq, ctx->instance_work);
+	}
+	mutex_unlock(&vpudev->dev_mutex);
+}
+
+static int __maybe_unused vpu_suspend(struct device *dev)
+{
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+	int ret = 0;
+
+	vpu_dbg(LVL_INFO, "suspend\n");
+
+	if (vpudev->hang_mask != vpudev->instance_mask) {
+
+		/*if there is an available device, send snapshot command to firmware*/
+		reinit_completion(&vpudev->snap_done_cmp);
+		v4l2_vpu_send_snapshot(vpudev);
+		if (!wait_for_completion_timeout(&vpudev->snap_done_cmp, msecs_to_jiffies(1000))) {
+			vpu_err("error: wait for vpu decoder snapdone event timeout!\n");
+			ret = -1;
+		}
+	}
+
+	vpu_dec_cancel_work(vpudev);
+	vpu_dbg(LVL_INFO, "suspend done\n");
+
+	return ret;
+}
+
+static bool is_vpu_poweroff(struct vpu_dev *vpudev)
+{
+	/* the csr register 'CM0Px_CPUWAIT' will be cleared to '1' after
+	 * reset(poweoff then poweron)
+	 */
+	if (readl_relaxed(vpudev->csr_base + CSR_CM0Px_CPUWAIT) == 1)
+		return true;
+	else
+		return false;
+}
+
+static int resume_vpu_register(struct vpu_dev *vpudev)
+{
+	if (!vpudev)
+		return -EINVAL;
+
+	vpu_enable_hw(vpudev);
+	vpu_mu_enable_rx(vpudev);
+
+	return 0;
+}
+
+static int resume_from_snapshot(struct vpu_dev *vpudev)
+{
+	int ret = 0;
+
+	reinit_completion(&vpudev->start_cmp);
+	enable_csr_reg(vpudev);
+	/*wait for firmware resotre done*/
+	if (!wait_for_completion_timeout(&vpudev->start_cmp, msecs_to_jiffies(1000))) {
+		vpu_err("error: wait for vpu decoder resume done timeout!\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int resume_from_vpu_poweroff(struct vpu_dev *vpudev)
+{
+	int ret = 0;
+
+	if (vpudev->hang_mask != vpudev->instance_mask)
+		ret = resume_from_snapshot(vpudev);
+	else
+		vpudev->fw_is_ready = false;
+
+	return ret;
+}
+
+static int __maybe_unused vpu_resume(struct device *dev)
+{
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+	int ret = 0;
+	u_int32 idx;
+
+	vpu_dbg(LVL_INFO, "resume\n");
+	pm_runtime_get_sync(vpudev->generic_dev);
+
+	resume_vpu_register(vpudev);
+
+	if (vpudev->fw_is_ready == false)
+		goto exit;
+
+	if (is_vpu_poweroff(vpudev))
+		ret = resume_from_vpu_poweroff(vpudev);
+	else if (vpudev->hang_mask != vpudev->instance_mask) {
+		idx = get_reset_index(vpudev);
+		if (idx < VPU_MAX_NUM_STREAMS)
+			swreset_vpu_firmware(vpudev, idx);
+		else
+			ret = -EINVAL;
+	}
+
+	vpu_dec_resume_work(vpudev);
+
+exit:
+	pm_runtime_put_sync(vpudev->generic_dev);
+	vpu_dbg(LVL_INFO, "resume done\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+	SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+static const struct of_device_id vpu_of_match[] = {
+	{ .compatible = "nxp,imx8qm-b0-vpudec", },
+	{ .compatible = "nxp,imx8qxp-b0-vpudec", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+static struct platform_driver vpu_driver = {
+	.probe = vpu_probe,
+	.remove = vpu_remove,
+	.driver = {
+		.name = "vpu-b0",
+		.of_match_table = vpu_of_match,
+		.pm = &vpu_pm_ops,
+	},
+};
+module_platform_driver(vpu_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_param(vpu_dbg_level_decoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_decoder, "Debug level (0-3)");
+module_param(vpu_frm_depth, int, 0644);
+MODULE_PARM_DESC(vpu_frm_depth, "maximum frame number in data pool");
+module_param(vpu_log_depth, int, 0644);
+MODULE_PARM_DESC(vpu_log_depth, "maximum log number in queue(0-60)");
+module_param(vpu_frmdbg_ena, int, 0644);
+MODULE_PARM_DESC(vpu_frmdbg_ena, "enable firmware mask instance dbg log (bit N to mask instance N)");
+module_param(vpu_frmdbg_level, int, 0644);
+MODULE_PARM_DESC(vpu_frmdbg_level, "firmware debug level (0-2)");
+module_param(vpu_frmdbg_raw, int, 0644);
+MODULE_PARM_DESC(vpu_frmdbg_raw, "dump dbglog with raw data or not");
+module_param(vpu_max_bufsize, int, 0644);
+MODULE_PARM_DESC(vpu_max_bufsize, "maximun stream buffer size");
+module_param(vpu_dbe_num, int, 0644);
+MODULE_PARM_DESC(vpu_dbe_num, "vpu dbe number(1-2)");
+module_param(vpu_frmcrcdump_ena, int, 0644);
+MODULE_PARM_DESC(vpu_frmcrcdump_ena, "enable frame crc dump(0-1)");
+module_param(stream_buffer_threshold, int, 0644);
+MODULE_PARM_DESC(stream_buffer_threshold, "stream buffer threshold");
+module_param(precheck_show_bytes, int, 0644);
+MODULE_PARM_DESC(precheck_show_bytes, "show the beginning of content");
+module_param(vpu_show_perf_ena, int, 0644);
+MODULE_PARM_DESC(vpu_show_perf_ena, "enable show vpu decode performance(0-1)");
+module_param(vpu_show_perf_idx, int, 0644);
+MODULE_PARM_DESC(vpu_show_perf_idx, "show performance of which instance(bit N to mask instance N)");
+module_param(vpu_show_perf_ent, int, 0644);
+MODULE_PARM_DESC(vpu_show_perf_ent, "show performance of which event(1: decoded, 2: ready)");
+module_param(vpu_datadump_ena, int, 0644);
+MODULE_PARM_DESC(vpu_datadump_ena, "enable dump input frame data (0-1)");
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_b0.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_b0.h
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_b0.h
+ *
+ * @brief VPU B0 definition
+ *
+ */
+#ifndef __VPU_B0_H
+#define __VPU_B0_H
+
+#include <linux/version.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#ifdef CONFIG_IMX_SCU
+#include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/svc/misc.h>
+#else
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#endif
+#include <linux/mx8_mu.h>
+#include <linux/mailbox_client.h>
+#include <media/v4l2-event.h>
+#include <linux/kfifo.h>
+#include "vpu_rpc.h"
+
+extern unsigned int vpu_dbg_level_decoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+	container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+	container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define MIN_SPACE (SCODE_SIZE + 64)
+#define SCODE_SIZE (4096)
+
+#define VPU_MAX_BUFFER 32
+#define M0FW_FILENAME "vpu/vpu_fw_imx8_dec.bin"
+#define MMAP_BUF_TYPE_SHIFT 28
+#define MMAP_BUF_TYPE_MASK 0xF0000000
+#define DCP_SIZE 0x3000000
+#define DCP_SIZE_MINIMUM	0x100000
+#define MAX_BUFFER_SIZE 0xc00000
+#define UDATA_BUFFER_SIZE 0x1000
+#define MAX_DCP_NUM 2
+#define MAX_MBI_NUM 18 // same with MEDIA_PLAYER_MAX_MBI_UNIT defined in firmware
+#define MAX_TIMEOUT_COUNT 10
+#define VPU_REG_BASE 0x40000000
+#define VPU_MAX_STEP_STRING_LENGTH 40
+#define VPU_DISABLE_BITS (0x7)
+
+#define V4L2_PIX_FMT_NV12_10BIT    v4l2_fourcc('N', 'T', '1', '2') /*  Y/CbCr 4:2:0 for 10bit  */
+#define	VPU_FRAME_DEPTH_MAX     512
+#define VPU_FRAME_DEPTH_DEFAULT 256
+#define DECODER_NODE_NUMBER 12 // use /dev/video12 as vpu decoder
+#define DEFAULT_LOG_DEPTH 20
+#define DEFAULT_FRMDBG_ENABLE 0
+#define DEFAULT_FRMDBG_LEVEL 0
+#define VPU_DEC_CMD_DATA_MAX_NUM	16
+#define VPU_DEC_MAX_WIDTH		8188
+#define VPU_DEC_MAX_HEIGTH		8188
+#define VPU_DEC_FMT_DIVX_MASK		(1 << 20)
+#define VPU_DEC_FMT_RV_MASK		(1 << 21)
+
+#define V4L2_EVENT_DECODE_ERROR		(V4L2_EVENT_PRIVATE_START + 1)
+#define V4L2_EVENT_SKIP			(V4L2_EVENT_PRIVATE_START + 2)
+
+struct vpu_v4l2_control {
+	uint32_t id;
+	enum v4l2_ctrl_type type;
+	uint32_t minimum;
+	uint32_t maximum;
+	uint32_t step;
+	uint32_t default_value;
+	uint32_t menu_skip_mask;
+	bool is_volatile;
+};
+
+typedef enum{
+	INIT_DONE = 1,
+	RPC_BUF_OFFSET,
+	BOOT_ADDRESS,
+	COMMAND,
+	EVENT
+} MSG_Type;
+
+enum PLAT_TYPE {
+	IMX8QXP = 0,
+	IMX8QM  = 1,
+};
+
+enum QUEUE_TYPE {
+	V4L2_SRC = 0,
+	V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+	VPU_VIDEO_UNDEFINED = 0,
+	VPU_VIDEO_AVC = 1,
+	VPU_VIDEO_VC1 = 2,
+	VPU_VIDEO_MPEG2 = 3,
+	VPU_VIDEO_AVS = 4,
+	VPU_VIDEO_ASP = 5,
+	VPU_VIDEO_JPEG = 6,
+	VPU_VIDEO_RV = 7,
+	VPU_VIDEO_VP6 = 8,
+	VPU_VIDEO_SPK = 9,
+	VPU_VIDEO_VP8 = 10,
+	VPU_VIDEO_AVC_MVC = 11,
+	VPU_VIDEO_HEVC = 12,
+};
+
+typedef enum{
+	EOS_PADDING_TYPE = 1,
+	BUFFLUSH_PADDING_TYPE = 2,
+	BUFABORT_PADDING_TYPE = 3,
+} VPU_PADDING_SCODE_TYPE;
+
+#define VPU_PIX_FMT_AVS         v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP         v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV          v4l2_fourcc('R', 'V', '0', '0')
+#define VPU_PIX_FMT_VP6         v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK         v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_DIV3        v4l2_fourcc('D', 'I', 'V', '3')
+#define VPU_PIX_FMT_DIVX        v4l2_fourcc('D', 'I', 'V', 'X')
+#define VPU_PIX_FMT_HEVC        v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_LOGO        v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8     v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10    v4l2_fourcc('Z', 'T', '1', '0')
+
+#define V4L2_CID_USER_RAW_BASE  (V4L2_CID_USER_BASE + 0x1100)
+#define V4L2_CID_USER_FRAME_DEPTH (V4L2_CID_USER_BASE + 0x1200)
+#define V4L2_CID_USER_FRAME_DIS_REORDER (V4L2_CID_USER_BASE + 0x1300)
+#define V4L2_CID_USER_TS_THRESHOLD	(V4L2_CID_USER_BASE + 0x1101)
+#define V4L2_CID_USER_BS_L_THRESHOLD	(V4L2_CID_USER_BASE + 0x1102)
+#define V4L2_CID_USER_BS_H_THRESHOLD	(V4L2_CID_USER_BASE + 0x1103)
+
+#define V4L2_CID_USER_FRAME_COLORDESC		(V4L2_CID_USER_BASE + 0x1104)
+#define V4L2_CID_USER_FRAME_TRANSFERCHARS	(V4L2_CID_USER_BASE + 0x1105)
+#define V4L2_CID_USER_FRAME_MATRIXCOEFFS	(V4L2_CID_USER_BASE + 0x1106)
+#define V4L2_CID_USER_FRAME_FULLRANGE		(V4L2_CID_USER_BASE + 0x1107)
+#define V4L2_CID_USER_FRAME_VUIPRESENT		(V4L2_CID_USER_BASE + 0x1108)
+
+#define V4L2_CID_USER_STREAM_INPUT_MODE		(V4L2_CID_USER_BASE + 0x1109)
+#define V4L2_CID_USER_FRAME_THRESHOLD		(V4L2_CID_USER_BASE + 0x110A)
+
+#define IMX_V4L2_DEC_CMD_START		(0x09000000)
+#define IMX_V4L2_DEC_CMD_RESET		(IMX_V4L2_DEC_CMD_START + 1)
+
+enum vpu_pixel_format {
+	VPU_HAS_COLOCATED = 0x00000001,
+	VPU_HAS_SPLIT_FLD = 0x00000002,
+	VPU_PF_MASK       = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+	VPU_IS_TILED      = 0x000000100,
+	VPU_HAS_10BPP     = 0x00000200,
+
+	VPU_IS_PLANAR     = 0x00001000,
+	VPU_IS_SEMIPLANAR = 0x00002000,
+	VPU_IS_PACKED     = 0x00004000,
+
+	// Merged definitions using above flags:
+	VPU_PF_UNDEFINED  = 0,
+	VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+	VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+	VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+	VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+	VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+enum ARV_FRAME_TYPE {
+	ARV_8 = 0,
+	ARV_9,
+	ARV_10,
+};
+
+struct VPU_FMT_INFO_ARV {
+	u_int32				data_len;
+	u_int32				slice_num;
+	u_int32				*slice_offset;
+	u_int32				packlen;
+	enum ARV_FRAME_TYPE	type;
+};
+
+struct vpu_v4l2_fmt {
+	char *name;
+	unsigned int fourcc;
+	unsigned int num_planes;
+	unsigned int vdec_std;
+	unsigned int disable;
+};
+
+struct vb2_data_req {
+	struct list_head  list;
+	struct vb2_buffer *vb2_buf;
+	int id;
+	u_int32 status;
+	bool bfield;
+	bool queued;
+	u_int32 phy_addr[2]; //0 for luma, 1 for chroma
+	u_int32 data_offset[2]; //0 for luma, 1 for chroma
+	u32 seq_tag;
+};
+
+struct queue_data {
+	unsigned int width;
+	unsigned int height;
+	unsigned int stride;
+	unsigned int field;
+	unsigned int num_planes;
+	unsigned int sizeimage[2];
+	unsigned int fourcc;
+	unsigned int vdec_std;
+	int buf_type; // v4l2_buf_type
+	bool vb2_q_inited;
+	struct vb2_queue vb2_q;    // vb2 queue
+	struct list_head drv_q;    // driver queue
+	struct semaphore drv_q_lock;
+	struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+	enum QUEUE_TYPE type;
+	unsigned long qbuf_count;
+	unsigned long dqbuf_count;
+	unsigned long process_count;
+	bool enable;
+	struct vpu_ctx *ctx;
+};
+
+struct print_buf_desc {
+	u32 start_h_phy;
+	u32 start_h_vir;
+	u32 start_m;
+	u32 bytes;
+	u32 read;
+	u32 write;
+	char buffer[0];
+};
+
+#ifdef CONFIG_IMX_SCU
+struct vpu_imx_sc_msg_misc {
+	struct imx_sc_rpc_msg hdr;
+	u32 word;
+} __packed;
+#endif
+
+struct vpu_sc_chan {
+	struct vpu_dev *dev;
+	char name[20];
+	struct mbox_client cl;
+	struct mbox_chan *ch;
+};
+
+struct vpu_ctx_work {
+	struct work_struct instance_work;
+	struct delayed_work delayed_instance_work;
+	int str_index;
+	struct vpu_dev *dev;
+};
+
+struct vpu_ctx;
+struct vpu_dev {
+	struct device *generic_dev;
+	struct v4l2_device v4l2_dev;
+	struct video_device *pvpu_decoder_dev;
+	struct platform_device *plat_dev;
+	struct firmware *m0_pfw;
+	void *m0_p_fw_space_vir;
+	u_int32 m0_p_fw_space_phy;
+	u_int32 m0_boot_size;
+	void *m0_rpc_virt;
+	u_int32 m0_rpc_phy;
+	u_int32 m0_rpc_size;
+	struct mutex dev_mutex;
+	struct mutex cmd_mutex;
+	bool fw_is_ready;
+	bool firmware_started;
+	bool need_cleanup_firmware;
+	bool suspend;
+	struct completion start_cmp;
+	struct completion snap_done_cmp;
+	struct workqueue_struct *workqueue;
+	struct work_struct msg_work;
+	struct delayed_work delayed_msg_work;
+	unsigned long instance_mask;
+	unsigned long hang_mask; //this is used to deal with hang issue to reset firmware
+	struct clk *vpu_clk;
+	void __iomem *mu_base_virtaddr;
+	unsigned int vpu_mu_id;
+	int vpu_mu_init;
+	u_int32 plat_type;
+
+	struct clk *clk_m0;
+	void __iomem *regs_base;
+	void __iomem *csr_base;
+	u_int32 cm_offset;
+
+	struct shared_addr shared_mem;
+	struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+	struct vpu_ctx_work ctx_work[VPU_MAX_NUM_STREAMS];
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_dbglog;
+	struct dentry *debugfs_fwlog;
+
+	struct print_buf_desc *print_buf;
+	u8 precheck_pattern[64];
+	int precheck_next[64];
+	int precheck_num;
+	char precheck_content[1024];
+
+	struct kfifo mu_msg_fifo;
+	void *mu_msg_buffer;
+	unsigned int mu_msg_buffer_size;
+	u_int32 vpu_irq;
+
+	/* reserve for kernel version 5.4 or later */
+	struct vpu_sc_chan sc_chan_tx0;
+	struct vpu_sc_chan sc_chan_tx1;
+	struct vpu_sc_chan sc_chan_rx;
+	struct device *pd_vpu;
+	struct device *pd_dec;
+	struct device *pd_mu;
+	struct device_link *pd_vpu_link;
+	struct device_link *pd_dec_link;
+	struct device_link *pd_mu_link;
+};
+
+struct vpu_statistic {
+	unsigned long cmd[VID_API_CMD_TS + 2];
+	unsigned long event[VID_API_EVENT_DEC_CFG_INFO + 2];
+	unsigned long current_cmd;
+	unsigned long current_event;
+	unsigned long skipped_frame_count;
+	struct timespec64 ts_cmd;
+	struct timespec64 ts_event;
+	atomic64_t total_dma_size;
+	atomic64_t total_alloc_size;
+};
+
+struct dma_buffer {
+	dma_addr_t dma_phy;
+	void *dma_virt;
+	u_int32 dma_size;
+};
+
+struct vpu_dec_cmd_request {
+	struct list_head list;
+	u32 request;
+	u32 response;
+	bool block;
+	u32 idx;
+	u32 num;
+	u32 data[VPU_DEC_CMD_DATA_MAX_NUM];
+};
+
+struct vpu_dec_perf_time {
+	u_int64 open_time;
+
+	u_int64 first_decoded_time;
+	u_int64 last_decoded_time;
+	u_int64 cur_decoded_interv;
+	u_int64 decoded_fps;
+
+	u_int64 first_ready_time;
+	u_int64 last_ready_time;
+	u_int64 cur_ready_interv;
+	u_int64 ready_fps;
+};
+
+struct vpu_dec_perf_queue {
+	struct list_head list;
+	char str[VPU_MAX_STEP_STRING_LENGTH];
+	u_int64 time;
+};
+
+struct vpu_ctx {
+	struct vpu_dev *dev;
+	struct v4l2_fh fh;
+
+	struct vpu_statistic statistic;
+	struct device_attribute dev_attr_instance_command;
+	char command_name[64];
+	struct device_attribute dev_attr_instance_event;
+	char event_name[64];
+	struct device_attribute dev_attr_instance_buffer;
+	char buffer_name[64];
+	struct device_attribute dev_attr_instance_flow;
+	char flow_name[64];
+	struct device_attribute dev_attr_instance_perf;
+	char perf_name[64];
+	struct v4l2_ctrl_handler ctrl_handler;
+	bool ctrl_inited;
+	struct list_head log_q;
+
+	int str_index;
+	struct queue_data q_data[2];
+	struct kfifo msg_fifo;
+	void *msg_buffer;
+	unsigned int msg_buffer_size;
+	struct mutex instance_mutex;
+	struct work_struct *instance_work;
+	struct delayed_work *delayed_instance_work;
+	struct workqueue_struct *instance_wq;
+	struct completion completion;
+	struct completion stop_cmp;
+	struct completion eos_cmp;
+	MediaIPFW_Video_SeqInfo seqinfo;
+	bool b_dis_reorder;
+	bool b_firstseq;
+	bool wait_rst_done;
+	bool wait_res_change_done;
+	bool seek_flag;
+	bool firmware_stopped;
+	bool firmware_finished;
+	bool eos_stop_received;
+	bool eos_stop_added;
+	bool ctx_released;
+	bool start_code_bypass;
+	STREAM_INPUT_MODE stream_input_mode;
+	bool hang_status;
+	bool fifo_low;
+	bool frame_decoded;
+	bool first_dump_data_flag;
+	bool first_data_flag;
+	u32 req_frame_count;
+	u32 req_mbi_count;
+	u32 req_dcp_count;
+	u32 mbi_count;
+	u32 mbi_size;
+	u32 dcp_count;
+	u32 dcp_size;
+	u32 mbi_index;
+	u32 dcp_index;
+	struct dma_buffer dpb_buffer;
+	struct dma_buffer dcp_buffer[MAX_DCP_NUM];
+	struct dma_buffer mbi_buffer[MAX_MBI_NUM];
+	struct dma_buffer stream_buffer;
+	struct dma_buffer udata_buffer;
+	enum ARV_FRAME_TYPE arv_type;
+	u32 beginning;
+
+	struct file *crc_fp;
+	loff_t pos;
+
+	int frm_dis_delay;
+	int frm_dec_delay;
+	int frm_total_num;
+
+	long total_qbuf_bytes;
+	long total_write_bytes;
+	u32 extra_size;
+	s64 output_ts;
+	s64 capture_ts;
+	s64 ts_threshold;
+	u32 bs_l_threshold;
+	u32 bs_h_threshold;
+
+	struct v4l2_fract fixed_frame_interval;
+	struct v4l2_fract frame_interval;
+
+	struct list_head cmd_q;
+	struct vpu_dec_cmd_request *pending;
+	struct mutex cmd_lock;
+
+	struct vpu_dec_perf_time perf_time;
+	int res_change_occu_count;
+	int res_change_send_count;
+	int res_change_done_count;
+
+	struct list_head perf_q;
+	struct mutex perf_lock;
+
+	struct mutex fw_flow_mutex;
+
+	u8 colorspace;
+	u8 xfer_func;
+	u8 ycbcr_enc;
+	u8 quantization;
+};
+
+#define LVL_WARN		(1 << 0)
+#define LVL_EVENT		(1 << 1)
+#define LVL_INFO		(1 << 2)
+#define LVL_BIT_CMD		(1 << 4)
+#define LVL_BIT_EVT		(1 << 5)
+#define LVL_BIT_TS		(1 << 6)
+#define LVL_BIT_FRAME_BYTES	(1 << 7)
+#define LVL_BIT_WPTR		(1 << 8)
+#define LVL_BIT_PIC_ADDR	(1 << 9)
+#define LVL_BIT_BUFFER_STAT	(1 << 10)
+#define LVL_BIT_BUFFER_DESC	(1 << 11)
+#define LVL_BIT_FUNC		(1 << 12)
+#define LVL_BIT_FLOW		(1 << 13)
+#define LVL_BIT_FRAME_COUNT	(1 << 14)
+
+#define vpu_err(fmt, arg...) pr_info("[VPU Decoder] " fmt, ## arg)
+
+#define vpu_dbg(level, fmt, arg...) \
+	do { \
+		if (vpu_dbg_level_decoder & (level)) \
+			pr_info("[VPU Decoder] " fmt, ## arg); \
+	} while (0)
+
+#define V4L2_NXP_BUF_FLAG_CODECCONFIG		0x00200000
+#define V4L2_NXP_BUF_FLAG_TIMESTAMP_INVALID	0x00400000
+
+#define V4L2_NXP_BUF_MASK_FLAGS		(V4L2_NXP_BUF_FLAG_CODECCONFIG | \
+					 V4L2_NXP_BUF_FLAG_TIMESTAMP_INVALID)
+
+#define VPU_DECODED_EVENT_PERF_MASK		(1 << 0)
+#define VPU_READY_EVENT_PERF_MASK		(1 << 1)
+
+#define V4L2_NXP_FRAME_VERTICAL_ALIGN		512
+#define V4L2_NXP_FRAME_HORIZONTAL_ALIGN		512
+
+#define VPU_IMX_DECODER_FUSE_OFFSET		14
+
+pSTREAM_BUFFER_DESCRIPTOR_TYPE get_str_buffer_desc(struct vpu_ctx *ctx);
+u_int32 got_free_space(u_int32 wptr, u_int32 rptr, u_int32 start, u_int32 end);
+int copy_buffer_to_stream(struct vpu_ctx *ctx, void *buffer, uint32_t length);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_debug_log.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_debug_log.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu-debug_log.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include "vpu_debug_log.h"
+
+int init_log_info_queue(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	mutex_lock(&ctx->instance_mutex);
+	INIT_LIST_HEAD(&ctx->log_q);
+	mutex_unlock(&ctx->instance_mutex);
+	return 0;
+}
+
+int create_log_info_queue(struct vpu_ctx *ctx, u_int32 vpu_log_depth)
+{
+	struct vpu_log_info *vpu_info = NULL;
+	u_int32 i;
+
+	if (!ctx)
+		return -EINVAL;
+
+	for (i = 0; i < vpu_log_depth; i++) {
+		vpu_info = kzalloc(sizeof(*vpu_info), GFP_KERNEL);
+		if (!vpu_info)
+			continue;
+
+		atomic64_add(sizeof(*vpu_info), &ctx->statistic.total_alloc_size);
+		list_add_tail(&vpu_info->list, &ctx->log_q);
+	}
+
+	return 0;
+}
+
+int destroy_log_info_queue(struct vpu_ctx *ctx)
+{
+	struct vpu_log_info *vpu_info, *temp_info;
+	u_int32 ret = 0;
+
+	if (!ctx)
+		return -EINVAL;
+
+	mutex_lock(&ctx->instance_mutex);
+	if (list_empty(&ctx->log_q)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	list_for_each_entry_safe(vpu_info, temp_info, &ctx->log_q, list)
+		if (vpu_info) {
+			list_del_init(&vpu_info->list);
+			kfree(vpu_info);
+			atomic64_sub(sizeof(*vpu_info), &ctx->statistic.total_alloc_size);
+		}
+
+exit:
+	mutex_unlock(&ctx->instance_mutex);
+
+	return ret;
+}
+
+int put_log_info(struct vpu_ctx *ctx, struct vpu_log_info *vpu_info)
+{
+	if (!ctx || !vpu_info)
+		return -EINVAL;
+
+	mutex_lock(&ctx->instance_mutex);
+	list_add_tail(&vpu_info->list, &ctx->log_q);
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+struct vpu_log_info *pop_log_info(struct vpu_ctx *ctx)
+{
+	struct vpu_log_info *vpu_info = NULL;
+
+	if (!ctx)
+		return NULL;
+
+	mutex_lock(&ctx->instance_mutex);
+	if (list_empty(&ctx->log_q))
+		vpu_info = NULL;
+	vpu_info = list_first_entry(&ctx->log_q, struct vpu_log_info, list);
+	if (vpu_info)
+		list_del_init(&vpu_info->list);
+	mutex_unlock(&ctx->instance_mutex);
+	return vpu_info;
+}
+
+int set_log_info(struct vpu_log_info *vpu_info, enum ACTION_TYPE type, u_int32 info, u_int32 info_data)
+{
+	if (!vpu_info)
+		return -EINVAL;
+	if (type >= LOG_RESERVED)
+		return -EINVAL;
+
+	vpu_info->type = type;
+	vpu_info->log_info[type] = info;
+	vpu_info->data = info_data;
+	return 0;
+}
+
+int record_log_info(struct vpu_ctx *ctx, enum ACTION_TYPE type, u_int32 info, u_int32 info_data)
+{
+	struct vpu_log_info *vpu_info = NULL;
+
+	if (!ctx)
+		return -EINVAL;
+
+	vpu_info = pop_log_info(ctx);
+	if (!vpu_info)
+		return -EINVAL;
+	set_log_info(vpu_info, type, info, info_data);
+	put_log_info(ctx, vpu_info);
+
+	return 0;
+}
+
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_debug_log.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_debug_log.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_debug_log.h
+ *
+ * @brief VPU debug definition
+ *
+ */
+#ifndef _VPU_DEBUG_LOG_H_
+#define _VPU_DEBUG_LOG_H_
+#include "vpu_b0.h"
+enum ACTION_TYPE {
+	LOG_NULL = 0,
+	LOG_EVENT,
+	LOG_COMMAND,
+	LOG_PADDING,
+	LOG_EOS,
+	LOG_UPDATE_STREAM,
+	LOG_RESERVED,
+};
+
+struct vpu_log_info {
+	struct list_head list;
+	enum ACTION_TYPE type;
+	u_int32 log_info[LOG_RESERVED];
+	u_int32 data;
+};
+int init_log_info_queue(struct vpu_ctx *ctx);
+int create_log_info_queue(struct vpu_ctx *ctx, u_int32 vpu_log_depth);
+int destroy_log_info_queue(struct vpu_ctx *ctx);
+int put_log_info(struct vpu_ctx *ctx, struct vpu_log_info *vpu_info);
+struct vpu_log_info *pop_log_info(struct vpu_ctx *ctx);
+int set_log_info(struct vpu_log_info *vpu_info, enum ACTION_TYPE type, u_int32 info, u_int32 info_data);
+int record_log_info(struct vpu_ctx *ctx, enum ACTION_TYPE type, u_int32 info, u_int32 info_data);
+
+#endif
+
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_mu.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_mu.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_mu.c
+ *
+ */
+
+#include "vpu_mu.h"
+
+static void vpu_mu_inq_msg(struct vpu_dev *dev, void *msg)
+{
+	if (&dev->mu_msg_fifo == NULL) {
+		vpu_err("&dev->mu_msg_fifo == NULL\n");
+		return;
+	}
+
+	if (kfifo_in(&dev->mu_msg_fifo, msg, sizeof(u_int32)) != sizeof(u_int32)) {
+		vpu_err("No memory for mu msg fifo\n");
+		return;
+	}
+
+	queue_work(dev->workqueue, &dev->msg_work);
+	queue_delayed_work(dev->workqueue,
+			&dev->delayed_msg_work, msecs_to_jiffies(10));
+}
+
+static void vpu_mbox_free(struct vpu_dev *dev)
+{
+	if (dev->sc_chan_tx0.ch && !IS_ERR(dev->sc_chan_tx0.ch))
+		mbox_free_channel(dev->sc_chan_tx0.ch);
+	if (dev->sc_chan_tx1.ch && !IS_ERR(dev->sc_chan_tx1.ch))
+		mbox_free_channel(dev->sc_chan_tx1.ch);
+	if (dev->sc_chan_rx.ch && !IS_ERR(dev->sc_chan_rx.ch))
+		mbox_free_channel(dev->sc_chan_rx.ch);
+
+	dev->sc_chan_tx0.ch = NULL;
+	dev->sc_chan_tx1.ch = NULL;
+	dev->sc_chan_rx.ch = NULL;
+}
+
+static void vpu_rx_callback(struct mbox_client *c, void *msg)
+{
+	struct vpu_sc_chan *sc_chan = container_of(c, struct vpu_sc_chan, cl);
+	struct vpu_dev *dev =
+		container_of(sc_chan, struct vpu_dev, sc_chan_rx);
+
+	if (&dev->mu_msg_fifo == NULL) {
+		vpu_err("&dev->mu_msg_fifo == NULL\n");
+		return;
+	}
+
+	vpu_mu_inq_msg(dev, msg);
+}
+
+static int vpu_rtx_channel_request(struct vpu_sc_chan *sc_chan, bool block, struct vpu_dev *vdev)
+{
+	struct device *dev = &vdev->plat_dev->dev;
+	struct mbox_client *cl;
+	int ret = 0;
+
+	if (sc_chan->ch && !IS_ERR(sc_chan->ch)) {
+		vpu_dbg(LVL_WARN, "vpu_sc_chan(%s) has been requested\n",
+			sc_chan->name);
+		return 0;
+	}
+
+	/* Normally, use block mode to ensure msg be writed correctly.
+	 * Firmware do not separate read tx1 channel until receive tx0.
+	 * Hence, when use tx1 must combine with tx0, and flow is tx1 -> tx0 to
+	 * ensure firmware read tx1 correctly. Due to tx1 write first, tx1 shall
+	 * use non-block mode, otherwise always wait timeout.
+	 * In addition, tx0 use block mode then also can ensure tx1 msg be
+	 * writed correctly as tx0 and tx1 are considered as a whole in this
+	 * case.
+	 */
+
+	/* core device id count from 0, mu count from 1 */
+
+	cl = &sc_chan->cl;
+	cl->dev = dev;
+	if (block) {
+		cl->tx_block = true;
+		cl->tx_tout = 1000;
+	} else {
+		cl->tx_block = false;
+	}
+	cl->knows_txdone = false;
+	cl->rx_callback = vpu_rx_callback;
+
+	sc_chan->ch = mbox_request_channel_byname(cl, sc_chan->name);
+	if (IS_ERR(sc_chan->ch)) {
+		ret = PTR_ERR(sc_chan->ch);
+		if (ret != -EPROBE_DEFER)
+			vpu_err("Failed to request mbox chan %s ret %d\n",
+				sc_chan->name, ret);
+	}
+
+	return ret;
+}
+
+static int vpu_rtx_channel_init(struct vpu_dev *vdev)
+{
+	int ret = 0;
+
+	vdev->sc_chan_tx0.dev = vdev;
+	scnprintf(vdev->sc_chan_tx0.name, sizeof(vdev->sc_chan_tx0.name) - 1,
+		  "tx0");
+	ret = vpu_rtx_channel_request(&vdev->sc_chan_tx0, true, vdev);
+	if (ret)
+		goto err;
+
+	vdev->sc_chan_tx1.dev = vdev;
+	scnprintf(vdev->sc_chan_tx1.name, sizeof(vdev->sc_chan_tx1.name) - 1,
+		  "tx1");
+	ret = vpu_rtx_channel_request(&vdev->sc_chan_tx1, false, vdev);
+	if (ret)
+		goto err;
+
+	vdev->sc_chan_rx.dev = vdev;
+	scnprintf(vdev->sc_chan_rx.name, sizeof(vdev->sc_chan_rx.name) - 1,
+		  "rx");
+	ret = vpu_rtx_channel_request(&vdev->sc_chan_rx, true, vdev);
+	if (ret)
+		goto err;
+
+	return ret;
+
+err:
+	vpu_mbox_free(vdev);
+
+	return ret;
+}
+
+int vpu_mu_request(struct vpu_dev *dev)
+{
+	int ret = 0;
+
+	if (!dev->vpu_mu_init) {
+		ret = vpu_rtx_channel_init(dev);
+		if (!ret)
+			dev->vpu_mu_init = TRUE;
+		else
+			vpu_dbg(LVL_WARN, "warning: init rtx channel failed, ret: %d\n",
+				ret);
+	}
+
+	return ret;
+}
+
+void vpu_mu_free(struct vpu_dev *dev)
+{
+	if (dev->vpu_mu_init) {
+		vpu_mbox_free(dev);
+		dev->vpu_mu_init = FALSE;
+	}
+}
+
+void vpu_mu_send_msg(struct vpu_dev *dev, MSG_Type type, u32 value)
+{
+	/* Ensure firmware read tx1 correctly when receive tx0,
+	 * need to write tx1 first.
+	 */
+
+	if (value != 0xffff)
+		mbox_send_message(dev->sc_chan_tx1.ch, &value);
+	if (type != 0xffff)
+		mbox_send_message(dev->sc_chan_tx0.ch, &type);
+}
+
+u_int32 vpu_mu_receive_msg(struct vpu_dev *dev, void *msg)
+{
+	int ret = 0;
+
+	if (kfifo_len(&dev->mu_msg_fifo) >= sizeof(u_int32)) {
+		ret = kfifo_out(&dev->mu_msg_fifo, msg, sizeof(u_int32));
+		if (ret != sizeof(u_int32))
+			vpu_err("error: kfifo_out mu msg failed\n, ret=%d\n",
+				ret);
+	} else {
+		ret = kfifo_len(&dev->mu_msg_fifo);
+		if (ret)
+			vpu_err("error: broken msg\n");
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int vpu_sc_get_fuse(struct imx_sc_ipc *ipc, u_int32 word, u_int32 *fuse)
+{
+	struct vpu_imx_sc_msg_misc msg;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = IMX_SC_RPC_SVC_MISC;
+	hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ;
+	hdr->size = 2;
+
+	msg.word = word;
+
+	ret = imx_scu_call_rpc(ipc, &msg, true);
+	if (ret)
+		return ret;
+
+	*fuse = msg.word;
+
+	return ret;
+}
+
+int vpu_sc_check_fuse(struct vpu_dev *dev, struct vpu_v4l2_fmt *pformat_table,
+		      u_int32 table_size)
+{
+	u_int32 fuse = 0xff;
+	u_int32 val;
+	u_int32 i;
+	int ret = 0;
+	struct imx_sc_ipc *ipcHandle;
+
+	ret = imx_scu_get_handle(&ipcHandle);
+	if (ret) {
+		vpu_err("error: scu get handle fail: %d\n", ret);
+		return ret;
+	}
+
+	vpu_sc_get_fuse(ipcHandle, VPU_DISABLE_BITS, &fuse);
+	if (ret) {
+		vpu_dbg(LVL_WARN, "warning: read value fail: %d\n", ret);
+		return ret;
+	}
+
+	val = (fuse >> VPU_IMX_DECODER_FUSE_OFFSET) & 0x3UL;
+	if (val == 0x1UL) {
+		for (i = 0; i < table_size; i++)
+			if (pformat_table[i].fourcc == VPU_PIX_FMT_HEVC)
+				pformat_table[i].disable = 1;
+		vpu_dbg(LVL_WARN, "H265 is disabled\n");
+	} else if (val == 0x2UL) {
+		for (i = 0; i < table_size; i++)
+			if (pformat_table[i].fourcc == V4L2_PIX_FMT_H264)
+				pformat_table[i].disable = 1;
+		vpu_dbg(LVL_WARN, "H264 is disabled\n");
+	} else if (val == 0x3UL) {
+		for (i = 0; i < table_size; i++)
+			pformat_table[i].disable = 1;
+		vpu_dbg(LVL_WARN, "All decoder disabled\n");
+	}
+
+	return ret;
+}
+
+void vpu_mu_enable_rx(struct vpu_dev *dev)
+{
+
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_mu.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_mu.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_mu.h
+ *
+ */
+
+#ifndef _VPU_MU_H_
+#define _VPU_MU_H_
+
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/mx8_mu.h>
+#include <linux/workqueue.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_client.h>
+#include <linux/pm_domain.h>
+#include <linux/kfifo.h>
+
+#include "vpu_b0.h"
+#include "mediasys_types.h"
+#include "vpu_debug_log.h"
+#include "vpu_rpc.h"
+
+int vpu_mu_request(struct vpu_dev *dev);
+void vpu_mu_free(struct vpu_dev *dev);
+void vpu_mu_send_msg(struct vpu_dev *dev, MSG_Type type, u_int32 value);
+u_int32 vpu_mu_receive_msg(struct vpu_dev *dev, void *msg);
+int vpu_sc_check_fuse(struct vpu_dev *dev, struct vpu_v4l2_fmt *pformat_table,
+		     u_int32 table_size);
+void vpu_mu_enable_rx(struct vpu_dev *dev);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_pm.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_pm.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_pm.c
+ *
+ */
+
+#include "vpu_pm.h"
+
+int vpu_attach_pm_domains(struct vpu_dev *dev)
+{
+	int ret = 0;
+
+	dev->pd_vpu = dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpu");
+	if (IS_ERR(dev->pd_vpu)) {
+		vpu_err("error: %s unable to get vpu power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_vpu);
+		goto err;
+	}
+	dev->pd_vpu_link = device_link_add(&dev->plat_dev->dev, dev->pd_vpu,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_vpu_link)) {
+		vpu_err("error: %s unable to link vpu power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_vpu_link);
+		goto err;
+	}
+
+	dev->pd_dec = dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpudec");
+	if (IS_ERR(dev->pd_dec)) {
+		vpu_err("error: %s unable to get vpu dec power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_dec);
+		goto err;
+	}
+	dev->pd_dec_link = device_link_add(&dev->plat_dev->dev, dev->pd_dec,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_dec_link)) {
+		vpu_err("error: %s unable to link vpu dec power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_dec_link);
+		goto err;
+	}
+
+	dev->pd_mu = dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpumu0");
+	if (IS_ERR(dev->pd_mu)) {
+		vpu_err("error: %s unable to get vpu mu0 power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_mu);
+		goto err;
+	}
+	dev->pd_mu_link = device_link_add(&dev->plat_dev->dev, dev->pd_mu,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_mu_link)) {
+		vpu_err("error: %s unable to link vpu mu0 power domain\n", __func__);
+		ret = PTR_ERR(dev->pd_mu_link);
+		goto err;
+	}
+
+	return ret;
+err:
+	vpu_detach_pm_domains(dev);
+	return ret;
+}
+
+void vpu_detach_pm_domains(struct vpu_dev *dev)
+{
+	if (dev->pd_vpu_link && !IS_ERR(dev->pd_vpu_link))
+		device_link_del(dev->pd_vpu_link);
+	if (dev->pd_vpu && !IS_ERR(dev->pd_vpu))
+		dev_pm_domain_detach(dev->pd_vpu, true);
+
+	if (dev->pd_dec_link && !IS_ERR(dev->pd_dec_link))
+		device_link_del(dev->pd_dec_link);
+	if (dev->pd_dec && !IS_ERR(dev->pd_dec))
+		dev_pm_domain_detach(dev->pd_dec, true);
+
+	if (dev->pd_mu_link && !IS_ERR(dev->pd_mu_link))
+		device_link_del(dev->pd_mu_link);
+	if (dev->pd_mu && !IS_ERR(dev->pd_mu))
+		dev_pm_domain_detach(dev->pd_mu, true);
+
+	dev->pd_vpu = NULL;
+	dev->pd_vpu_link = NULL;
+	dev->pd_dec = NULL;
+	dev->pd_dec_link = NULL;
+	dev->pd_mu = NULL;
+	dev->pd_mu_link = NULL;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_pm.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_pm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_pm.h
+ *
+ */
+
+#ifndef _VPU_PM_H_
+#define _VPU_PM_H_
+
+#include <linux/version.h>
+#include <linux/pm_domain.h>
+#include <linux/platform_device.h>
+
+#include "vpu_b0.h"
+
+int vpu_attach_pm_domains(struct vpu_dev *dev);
+void vpu_detach_pm_domains(struct vpu_dev *dev);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_rpc.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_rpc.c
@@ -0,0 +1,487 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include "vpu_rpc.h"
+
+void rpc_init_shared_memory(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr,
+		u_int32 total_size)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	unsigned int phy_addr;
+	unsigned int i;
+	MediaIPFW_Video_BufDesc *pSharedCmdBufDescPtr;
+	MediaIPFW_Video_BufDesc *pSharedMsgBufDescPtr;
+	MediaIPFW_Video_BufDesc *pDebugBufferDesc;
+	MediaIPFW_Video_BufDesc *pEngAccessBufferDesc;
+
+	This->shared_mem_phy = base_phy_addr;
+	This->shared_mem_vir = base_virt_addr;
+
+	pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	This->pSharedInterface = pSharedInterface;
+
+	pSharedInterface->FwExecBaseAddr = base_phy_addr;
+	pSharedInterface->FwExecAreaSize = total_size;
+
+	pSharedCmdBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamCmdBufferDesc;
+	pSharedMsgBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamMsgBufferDesc;
+
+	phy_addr = base_phy_addr + sizeof(DEC_RPC_HOST_IFACE);
+	This->cmd_mem_phy = phy_addr;
+	This->cmd_mem_vir = This->shared_mem_vir + sizeof(DEC_RPC_HOST_IFACE);
+
+	pSharedCmdBufDescPtr->uWrPtr = phy_addr;
+	pSharedCmdBufDescPtr->uRdPtr = pSharedCmdBufDescPtr->uWrPtr;
+	pSharedCmdBufDescPtr->uStart = pSharedCmdBufDescPtr->uWrPtr;
+	pSharedCmdBufDescPtr->uEnd = pSharedCmdBufDescPtr->uStart + CMD_SIZE;
+
+	phy_addr += CMD_SIZE;
+	This->msg_mem_phy = phy_addr;
+	This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+	pSharedMsgBufDescPtr->uWrPtr = phy_addr;
+	pSharedMsgBufDescPtr->uRdPtr = pSharedMsgBufDescPtr->uWrPtr;
+	pSharedMsgBufDescPtr->uStart = pSharedMsgBufDescPtr->uWrPtr;
+	pSharedMsgBufDescPtr->uEnd = pSharedMsgBufDescPtr->uStart + MSG_SIZE;
+
+	phy_addr += MSG_SIZE;
+	This->codec_mem_phy = phy_addr;
+	This->codec_mem_vir = This->msg_mem_vir + MSG_SIZE;
+	pSharedInterface->CodecParamTabDesc.pCodecParamArrayBase = This->codec_mem_phy;
+
+	phy_addr += CODEC_SIZE;
+	This->jpeg_mem_phy = phy_addr;
+	This->jpeg_mem_vir = This->codec_mem_vir + CODEC_SIZE;
+	pSharedInterface->JpegParamTabDesc.pJpegParamArrayBase = This->jpeg_mem_phy;
+
+	phy_addr += JPEG_SIZE;
+	This->seq_mem_phy = phy_addr;
+	This->seq_mem_vir = This->jpeg_mem_vir + JPEG_SIZE;
+
+	pSharedInterface->SeqInfoTabDesc.pSeqInfoArrayBase = This->seq_mem_phy;
+
+	phy_addr += SEQ_SIZE;
+	This->pic_mem_phy = phy_addr;
+	This->pic_mem_vir = This->seq_mem_vir + SEQ_SIZE;
+
+	pSharedInterface->PicInfoTabDesc.pPicInfoArrayBase = This->pic_mem_phy;
+
+	phy_addr += PIC_SIZE;
+	This->gop_mem_phy = phy_addr;
+	This->gop_mem_vir = This->pic_mem_vir + PIC_SIZE;
+
+	pSharedInterface->GopInfoTabDesc.pGopInfoArrayBase = This->gop_mem_phy;
+
+	phy_addr += GOP_SIZE;
+	This->qmeter_mem_phy = phy_addr;
+	This->qmeter_mem_vir = This->gop_mem_vir + GOP_SIZE;
+
+	pSharedInterface->QMeterInfoTabDesc.pQMeterInfoArrayBase = This->qmeter_mem_phy;
+
+	phy_addr += QMETER_SIZE;
+	pDebugBufferDesc = &pSharedInterface->DebugBufferDesc;
+	pDebugBufferDesc->uWrPtr = base_phy_addr + M0_PRINT_OFFSET;
+	pDebugBufferDesc->uRdPtr = pDebugBufferDesc->uWrPtr;
+	pDebugBufferDesc->uStart = pDebugBufferDesc->uWrPtr;
+	pDebugBufferDesc->uEnd = pDebugBufferDesc->uStart + DEBUG_SIZE;
+
+	This->dbglog_mem_phy = phy_addr;
+	This->dbglog_mem_vir = This->qmeter_mem_vir + QMETER_SIZE;
+
+	pSharedInterface->DbgLogDesc.uDecStatusLogBase = This->dbglog_mem_phy;
+	pSharedInterface->DbgLogDesc.uDecStatusLogSize = DBGLOG_SIZE;
+	phy_addr += DBGLOG_SIZE;
+
+//	phy_addr += sizeof(MediaIPFW_Video_BufDesc);
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		pEngAccessBufferDesc = &pSharedInterface->EngAccessBufferDesc[i];
+		pEngAccessBufferDesc->uWrPtr = phy_addr;
+		pEngAccessBufferDesc->uRdPtr = pEngAccessBufferDesc->uWrPtr;
+		pEngAccessBufferDesc->uStart = pEngAccessBufferDesc->uWrPtr;
+		pEngAccessBufferDesc->uEnd = pEngAccessBufferDesc->uStart + ENG_SIZE;
+		phy_addr += ENG_SIZE;
+	}
+
+	for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+		pSharedInterface->ptEncryptInfo[i] = phy_addr;
+		phy_addr += sizeof(MediaIPFW_Video_Encrypt_Info);
+	}
+}
+
+void rpc_restore_shared_memory(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	unsigned int phy_addr;
+
+	This->shared_mem_phy = base_phy_addr;
+	This->shared_mem_vir = base_virt_addr;
+
+	pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	This->pSharedInterface = pSharedInterface;
+
+	phy_addr = base_phy_addr + sizeof(DEC_RPC_HOST_IFACE);
+	This->cmd_mem_phy = phy_addr;
+	This->cmd_mem_vir = This->shared_mem_vir + sizeof(DEC_RPC_HOST_IFACE);
+
+	phy_addr += CMD_SIZE;
+	This->msg_mem_phy = phy_addr;
+	This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+	phy_addr += MSG_SIZE;
+	This->codec_mem_phy = phy_addr;
+	This->codec_mem_vir = This->msg_mem_vir + MSG_SIZE;
+
+	phy_addr += CODEC_SIZE;
+	This->jpeg_mem_phy = phy_addr;
+	This->jpeg_mem_vir = This->codec_mem_vir + CODEC_SIZE;
+
+	phy_addr += JPEG_SIZE;
+	This->seq_mem_phy = phy_addr;
+	This->seq_mem_vir = This->jpeg_mem_vir + JPEG_SIZE;
+
+	phy_addr += SEQ_SIZE;
+	This->pic_mem_phy = phy_addr;
+	This->pic_mem_vir = This->seq_mem_vir + SEQ_SIZE;
+
+	phy_addr += PIC_SIZE;
+	This->gop_mem_phy = phy_addr;
+	This->gop_mem_vir = This->pic_mem_vir + PIC_SIZE;
+
+	phy_addr += GOP_SIZE;
+	This->qmeter_mem_phy = phy_addr;
+	This->qmeter_mem_vir = This->gop_mem_vir + GOP_SIZE;
+
+	phy_addr += QMETER_SIZE;
+	This->dbglog_mem_phy = phy_addr;
+	This->dbglog_mem_vir = This->qmeter_mem_vir + QMETER_SIZE;
+}
+
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx, u_int32 vpu_dbe_num)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	u_int32 *CurrStrfg;
+
+	pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+	CurrStrfg = &pSharedInterface->StreamConfig[str_idx];
+	*CurrStrfg = 0;
+	//the value should be passed from application
+	VID_STREAM_CONFIG_STRBUFIDX_SET(0, CurrStrfg);
+	VID_STREAM_CONFIG_NOSEQ_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_DEBLOCK_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_DERING_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_PLAY_MODE_SET(MEDIA_PLAYER_API_MODE_CONTINUOUS, CurrStrfg);
+	VID_STREAM_CONFIG_FS_CTRL_MODE_SET(MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL, CurrStrfg);
+	VID_STREAM_CONFIG_ENABLE_DCP_SET(TRUE, CurrStrfg);
+	VID_STREAM_CONFIG_NUM_STR_BUF_SET(1, CurrStrfg);
+	VID_STREAM_CONFIG_MALONE_USAGE_SET(1, CurrStrfg);
+	VID_STREAM_CONFIG_MULTI_VID_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_OBFUSC_EN_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_RC4_EN_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_MCX_SET(TRUE, CurrStrfg);
+	VID_STREAM_CONFIG_PES_SET(FALSE, CurrStrfg);
+	VID_STREAM_CONFIG_NUM_DBE_SET(vpu_dbe_num, CurrStrfg);
+}
+
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+	pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+	pSystemCfg = &pSharedInterface->sSystemCfg;
+	pSystemCfg->uNumMalones = 1;
+	pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+
+	pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+	pSystemCfg->uHifOffset[0x0] = 0x1C000;
+	pSystemCfg->uHifOffset[0x1] = 0x0;
+
+	pSystemCfg->uDPVBaseAddr = 0x0;
+	pSystemCfg->uDPVIrqPin = 0x0;
+	pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+	pSystemCfg->uFSLCacheBaseAddr[0] = (unsigned int)(regs_base + 0x60000);
+	pSystemCfg->uFSLCacheBaseAddr[1] = (unsigned int)(regs_base + 0x68000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check(MediaIPFW_Video_BufDesc *pBufDesc,
+	BOOL bFull,
+	u_int32 uSize,
+	u_int32 *puUpdateAddress)
+{
+	u_int32 uPtr1;
+	u_int32 uPtr2;
+	u_int32 uStart;
+	u_int32 uEnd;
+	u_int32 uTemp;
+
+	/* bFull is FALSE when send message, write data   */
+	/* bFull is TRUE when process commands, read data */
+	uPtr1 = (bFull) ? pBufDesc->uRdPtr : pBufDesc->uWrPtr;
+	uPtr2 = (bFull) ? pBufDesc->uWrPtr : pBufDesc->uRdPtr;
+
+	if (uPtr1 == uPtr2) {
+		if (bFull)
+			/* No data at all to read */
+			return 0;
+		else {
+			/* wrt pointer equal to read pointer thus the     */
+			/* buffer is completely empty for further writes  */
+			uStart = pBufDesc->uStart;
+			uEnd   = pBufDesc->uEnd;
+			/* The address to be returned in this case is for */
+			/* the updated write pointer.                     */
+			uTemp = uPtr1 + uSize;
+			if (uTemp >= uEnd)
+				uTemp -= (uEnd - uStart);
+			*puUpdateAddress = uTemp;
+			return (uEnd - uStart);
+		}
+	} else if (uPtr1 < uPtr2) {
+		/* return updated rd pointer address                */
+		/* In this case if size was too big - we expect the */
+		/* external ftn to compare the size against the     */
+		/* space returned.
+		 */
+		*puUpdateAddress = uPtr1 + uSize;
+		return (uPtr2 - uPtr1);
+	}
+	/* We know the system has looped!! */
+	uStart = pBufDesc->uStart;
+	uEnd   = pBufDesc->uEnd;
+	uTemp  = uPtr1 + uSize;
+	if (uTemp >= uEnd)
+		uTemp -= (uEnd - uStart);
+	*puUpdateAddress = uTemp;
+	return ((uEnd - uPtr1) + (uPtr2 - uStart));
+}
+
+static void rpc_update_cmd_buffer_ptr(MediaIPFW_Video_BufDesc *pCmdDesc)
+{
+	u_int32 uWritePtr;
+
+	mb();
+	uWritePtr = pCmdDesc->uWrPtr + 4;
+	if (uWritePtr >= pCmdDesc->uEnd)
+		uWritePtr = pCmdDesc->uStart;
+	pCmdDesc->uWrPtr = uWritePtr;
+}
+
+void rpc_send_cmd_buf(struct shared_addr *This,
+		u_int32 idx,
+		u_int32 cmdid,
+		u_int32 cmdnum,
+		u_int32 *local_cmddata)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+	BUFFER_DESCRIPTOR_TYPE *desc = NULL;
+	u_int32 *cmddata;
+	u_int32 i;
+	u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+	u_int32 uIgnore;
+	u_int32 uSpace;
+
+	uSpace = rpc_MediaIPFW_Video_buffer_space_check(pCmdDesc,
+							FALSE,
+							0,
+							&uIgnore);
+	if (uSpace < ((cmdnum + 1) << 2) + 16) {
+		pr_err("[VPU MALONE] CmdBuf is no space for [%d] %d\n",
+				idx, cmdid);
+		return;
+	}
+
+	*cmdword = 0;
+	*cmdword |= ((idx & 0x000000ff) << 24);
+	*cmdword |= ((cmdnum & 0x000000ff) << 16);
+	*cmdword |= ((cmdid & 0x00003fff) << 0);
+	rpc_update_cmd_buffer_ptr(pCmdDesc);
+
+	for (i = 0; i < cmdnum; i++) {
+		cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+		*cmddata = local_cmddata[i];
+		rpc_update_cmd_buffer_ptr(pCmdDesc);
+	}
+	if (cmdid != VID_API_CMD_FIRM_RESET) {
+		desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
+		desc->wptr++;
+		if (desc->wptr >= desc->end)
+			desc->wptr = desc->start;
+	}
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This)
+{
+	u_int32 uSpace;
+	u_int32 uIgnore;
+	pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+	u_int32 msgword;
+	u_int32 msgnum;
+
+	uSpace = rpc_MediaIPFW_Video_buffer_space_check(pMsgDesc, TRUE, 0, &uIgnore);
+	uSpace = (uSpace >> 2);
+	if (uSpace) {
+		/* get current msgword word */
+		msgword      = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+		/* Find the number of additional words */
+		msgnum  = ((msgword & 0x00ff0000) >> 16);
+
+		/*
+		 * * Check the number of message words against
+		 * * 1) a limit - some sort of maximum or at least
+		 * * the size of the SW buffer the message is read into
+		 * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+		 * * It must be less than space (as opposed to <=) because
+		 * * the message itself is not included in msgword
+		 */
+		if (msgnum < VID_API_MESSAGE_LIMIT) {
+			if (msgnum < uSpace)
+				return API_MSG_AVAILABLE;
+			else
+				return API_MSG_INCOMPLETE;
+		} else
+			return API_MSG_BUFFER_ERROR;
+	}
+	return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr(MediaIPFW_Video_BufDesc *pMsgDesc)
+{
+	u_int32 uReadPtr;
+
+	mb();
+	uReadPtr = pMsgDesc->uRdPtr + 4;
+	if (uReadPtr >= pMsgDesc->uEnd)
+		uReadPtr = pMsgDesc->uStart;
+	pMsgDesc->uRdPtr = uReadPtr;
+}
+
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg)
+{
+	unsigned int i;
+	pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+	MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+	u_int32 msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+
+	msg->idx = ((msgword & 0xff000000) >> 24);
+	msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+	msg->msgid = ((msgword & 0x00003fff) >> 0);
+	rpc_update_msg_buffer_ptr(pMsgDesc);
+
+	for (i = 0; i < msg->msgnum; i++) {
+		msg->msgdata[i] = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+		rpc_update_msg_buffer_ptr(pMsgDesc);
+	}
+}
+
+static bool check_is_ready(struct shared_addr *This, u32 idx)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface = NULL;
+	BUFFER_DESCRIPTOR_TYPE *desc = NULL;
+	u32 size;
+	u32 rptr;
+	u32 wptr;
+	u32 used;
+
+	if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
+		return false;
+	pSharedInterface = This->shared_mem_vir;
+	desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
+	size = desc->end - desc->start;
+	rptr = desc->rptr;
+	wptr = desc->wptr;
+	used = (wptr + size - rptr) % size;
+	if (!size || used < size / 2)
+		return true;
+
+	return false;
+}
+
+bool rpc_check_is_ready(struct shared_addr *This, u32 idx)
+{
+	u32 cnt = 0;
+
+	if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
+		return false;
+	while (!check_is_ready(This, idx)) {
+		if (cnt > 30)
+			return false;
+		mdelay(1);
+		cnt++;
+	}
+
+	return true;
+}
+
+void rpc_init_instance(struct shared_addr *This, u32 idx)
+{
+	pDEC_RPC_HOST_IFACE pSharedInterface = NULL;
+	BUFFER_DESCRIPTOR_TYPE *desc = NULL;
+
+	if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
+		return;
+	pSharedInterface = This->shared_mem_vir;
+	desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
+	desc->wptr = desc->rptr;
+	if (desc->wptr >= desc->end)
+		desc->wptr = desc->start;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_malone/vpu_rpc.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_malone/vpu_rpc.h
@@ -0,0 +1,124 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_IPC_H
+#define __VPU_IPC_H
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 25600
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DBGLOG_SIZE 0x10000
+#define DEBUG_SIZE 0x80000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+#define M0_PRINT_OFFSET 0x180000
+
+struct shared_addr {
+	pDEC_RPC_HOST_IFACE pSharedInterface;
+	unsigned long long shared_mem_phy;
+	void *shared_mem_vir;
+	unsigned long long cmd_mem_phy;
+	void *cmd_mem_vir;
+	unsigned long long msg_mem_phy;
+	void *msg_mem_vir;
+	unsigned long long codec_mem_phy;
+	void *codec_mem_vir;
+	unsigned long long jpeg_mem_phy;
+	void *jpeg_mem_vir;
+	unsigned long long seq_mem_phy;
+	void *seq_mem_vir;
+	unsigned long long pic_mem_phy;
+	void *pic_mem_vir;
+	unsigned long long gop_mem_phy;
+	void *gop_mem_vir;
+	unsigned long long qmeter_mem_phy;
+	void *qmeter_mem_vir;
+	unsigned long long dbglog_mem_phy;
+	void *dbglog_mem_vir;
+};
+
+struct event_msg {
+	u_int32 idx;
+	u_int32 msgnum;
+	u_int32 msgid;
+	u_int32 msgdata[LOCAL_MSG_NUM];
+};
+
+void rpc_init_shared_memory(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr,
+		u_int32 total_size);
+void rpc_restore_shared_memory(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr);
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base);
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx, u_int32 vpu_dbe_num);
+void rpc_send_cmd_buf(struct shared_addr *This,
+		u_int32 idx,
+		u_int32 cmdid,
+		u_int32 cmdnum,
+		u_int32 *local_cmddata);
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg);
+u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This);
+bool rpc_check_is_ready(struct shared_addr *This, u32 idx);
+void rpc_init_instance(struct shared_addr *This, u32 idx);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/Kconfig
@@ -0,0 +1,25 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) WINDSOR ENCODER support"
+
+config MXC_VPU_WINDSOR
+	  tristate "Support for MXC VPU(Video Processing Unit) WINDSOR ENCODER"
+	  depends on MEDIA_SUPPORT
+	  depends on VIDEO_DEV
+	  depends on VIDEO_V4L2
+	  select VIDEOBUF2_DMA_CONTIG
+	  select VIDEOBUF2_VMALLOC
+	  default y
+	---help---
+	  The VPU codec device provides codec function for H.264 etc.
+
+config MXC_VPU_WINDSOR_DEBUG
+	bool "MXC VPU WINDSOR ENCODER debugging"
+	depends on MXC_VPU_WINDSOR != n
+	help
+	  This is an option for the developers; most people should
+	  say N here.  This enables MXC VPU WINDSOR Encoder driver debugging.
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/Makefile
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/Makefile
@@ -0,0 +1,17 @@
+##
+## Makefile for the VPU and M0 driver
+##
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-$(CONFIG_MXC_VPU_WINDSOR) = vpu-windsor.o
+vpu-windsor-objs = vpu_encoder_b0.o \
+	vpu_encoder_ctrl.o \
+	vpu_event_msg.o \
+	vpu_encoder_mem.o \
+	vpu_encoder_rpc.o \
+	vpu_encoder_mu.o \
+	vpu_encoder_pm.o
+
+clean:
+	rm -rf $(vpu-windsor-objs)
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/mediasys_types.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/mediasys_types.h
@@ -0,0 +1,714 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+typedef int int32;
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#define VID_API_NUM_STREAMS 8
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT    64
+#define VID_API_MESSAGE_LIMIT    256
+
+#define API_CMD_AVAILABLE            0x0
+#define API_CMD_INCOMPLETE           0x1
+#define API_CMD_BUFFER_ERROR         0x2
+#define API_CMD_UNAVAILABLE          0x3
+#define API_MSG_AVAILABLE            0x0
+#define API_MSG_INCOMPLETE           0x1
+#define API_MSG_BUFFER_ERROR         0x2
+#define API_MSG_UNAVAILABLE          0x3
+#define MEDIAIP_ENC_USER_DATA_WORDS  16
+#define MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES 0x6
+#define MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES 0x3
+
+typedef enum {
+	GTB_ENC_CMD_NOOP        = 0x0,
+	GTB_ENC_CMD_STREAM_START,
+	GTB_ENC_CMD_FRAME_ENCODE,
+	GTB_ENC_CMD_FRAME_SKIP,
+	GTB_ENC_CMD_STREAM_STOP,
+	GTB_ENC_CMD_PARAMETER_UPD,
+	GTB_ENC_CMD_TERMINATE,
+	GTB_ENC_CMD_SNAPSHOT,
+	GTB_ENC_CMD_ROLL_SNAPSHOT,
+	GTB_ENC_CMD_LOCK_SCHEDULER,
+	GTB_ENC_CMD_UNLOCK_SCHEDULER,
+	GTB_ENC_CMD_CONFIGURE_CODEC,
+	GTB_ENC_CMD_DEAD_MARK,
+	GTB_ENC_CMD_FIRM_RESET,
+	GTB_ENC_CMD_RESERVED
+} GTB_ENC_CMD;
+
+typedef enum {
+	VID_API_EVENT_UNDEFINED = 0x0,
+	VID_API_ENC_EVENT_RESET_DONE = 0x1,
+	VID_API_ENC_EVENT_START_DONE,
+	VID_API_ENC_EVENT_STOP_DONE,
+	VID_API_ENC_EVENT_TERMINATE_DONE,
+	VID_API_ENC_EVENT_FRAME_INPUT_DONE,
+	VID_API_ENC_EVENT_FRAME_DONE,
+	VID_API_ENC_EVENT_FRAME_RELEASE,
+	VID_API_ENC_EVENT_PARA_UPD_DONE,
+	VID_API_ENC_EVENT_MEM_REQUEST,
+	VID_API_ENC_EVENT_FIRMWARE_XCPT,
+	VID_API_ENC_EVENT_RESERVED
+} ENC_TB_API_ENC_EVENT;
+
+typedef enum {
+	MEDIAIP_ENC_PIC_TYPE_B_FRAME = 0,
+	MEDIAIP_ENC_PIC_TYPE_P_FRAME,
+	MEDIAIP_ENC_PIC_TYPE_I_FRAME,
+	MEDIAIP_ENC_PIC_TYPE_IDR_FRAME,
+	MEDIAIP_ENC_PIC_TYPE_BI_FRAME
+
+} MEDIAIP_ENC_PIC_TYPE, *pMEDIAIP_ENC_PIC_TYPE;
+
+typedef struct {
+	u_int32                   uMemPhysAddr;
+	u_int32                   uMemVirtAddr;
+	u_int32                   uMemSize;
+} MEDIAIP_ENC_MEM_RESOURCE, *pMEDIAIP_ENC_MEM_RESOURCE;
+
+typedef struct {
+	u_int32                    uEncFrmSize;
+	u_int32                    uEncFrmNum;
+	u_int32                    uRefFrmSize;
+	u_int32                    uRefFrmNum;
+	u_int32                    uActBufSize;
+} MEDIAIP_ENC_MEM_REQ_DATA, *pMEDIAIP_ENC_MEM_REQ_DATA;
+
+typedef struct {
+	MEDIAIP_ENC_MEM_RESOURCE  tEncFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+	MEDIAIP_ENC_MEM_RESOURCE  tRefFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+	MEDIAIP_ENC_MEM_RESOURCE  tActFrameBufferArea;
+} MEDIAIP_ENC_MEM_POOL, *pMEDIAIP_ENC_MEM_POOL;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIC_TYPE
+
+typedef struct {
+	u_int32              uFrameID;
+	u_int32              uPicEncodDone;
+	MEDIAIP_ENC_PIC_TYPE ePicType;
+	u_int32              uSkippedFrame;
+	u_int32              uErrorFlag;
+	u_int32              uPSNR;
+	u_int32              uFlushDone;
+	u_int32              uMBy;
+	u_int32              uMBx;
+	u_int32              uFrameSize;
+	u_int32              uFrameEncTtlCycles;
+	u_int32              uFrameEncTtlFrmCycles;
+	u_int32              uFrameEncTtlSlcCycles;
+	u_int32              uFrameEncTtlEncCycles;
+	u_int32              uFrameEncTtlHmeCycles;
+	u_int32              uFrameEncTtlDsaCycles;
+	u_int32              uFrameEncFwCycles;
+	u_int32              uFrameCrc;
+	u_int32              uNumInterrupts_1;
+	u_int32              uNumInterrupts_2;
+	u_int32              uH264POC;
+	u_int32              uRefInfo;
+	u_int32              uPicNum;
+	u_int32              uPicActivity;
+	u_int32              uSceneChange;
+	u_int32              uMBStats;
+	u_int32              uEncCacheCount0;
+	u_int32              uEncCacheCount1;
+	u_int32              uMtlWrStrbCnt;
+	u_int32              uMtlRdStrbCnt;
+	u_int32              uStrBuffWrPtr;
+	u_int32              uDiagnosticEvents;
+
+	u_int32              uProcIaccTotRdCnt;
+	u_int32              uProcDaccTotRdCnt;
+	u_int32              uProcDaccTotWrCnt;
+	u_int32              uProcDaccRegRdCnt;
+	u_int32              uProcDaccRegWrCnt;
+	u_int32              uProcDaccRngRdCnt;
+	u_int32              uProcDaccRngWrCnt;
+
+	int32                tv_s;
+	u_int32              tv_ns;
+} MEDIAIP_ENC_PIC_INFO, *pMEDIAIP_ENC_PIC_INFO;
+
+typedef enum {
+	MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+	MEDIAIP_PLAYMODE_BROADCAST,
+	MEDIAIP_PLAYMODE_BROADCAST_DSS,
+	MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef struct {
+	u_int32 wptr;
+	u_int32 rptr;
+	u_int32 start;
+	u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+	u_int32	uWrPtr;
+	u_int32	uRdPtr;
+	u_int32	uStart;
+	u_int32	uEnd;
+	u_int32	uLo;
+	u_int32	uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+	u_int32 uCfgCookie;
+
+	u_int32 uNumMalones;
+	u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+	u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+	u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+	u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+	u_int32 uNumWindsors;
+	u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+	u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+	u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+	u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+	u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+	u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+	u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+	u_int32 uSysClkFreq;
+	u_int32 uNumTimers;
+	u_int32 uTimerBaseAddr;
+	u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+	u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+	u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+	u_int32 uGICBaseAddr;
+	u_int32 uUartBaseAddr;
+
+	u_int32 uDPVBaseAddr;
+	u_int32 uDPVIrqPin;
+	u_int32 uDPVIrqTarget;
+
+	u_int32 uPixIfBaseAddr;
+
+	u_int32 pal_trace_level;
+	u_int32 pal_trace_destination;
+
+	u_int32 pal_trace_level1;
+	u_int32 pal_trace_destination1;
+
+	u_int32 uHeapBase;
+	u_int32 uHeapSize;
+
+	u_int32 uFSLCacheBaseAddr[2];
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+	u_int32   uFrameID;
+	u_int32   uLumaBase;
+	u_int32   uChromaBase;
+	u_int32   uParamIdx;
+	u_int32   uKeyFrame;
+} MEDIAIP_ENC_YUV_BUFFER_DESC, *pMEDIAIP_ENC_YUV_BUFFER_DESC;
+
+typedef struct {
+	u_int32 use_ame;
+
+	u_int32 cme_mvx_max;
+	u_int32 cme_mvy_max;
+	u_int32 ame_prefresh_y0;
+	u_int32 ame_prefresh_y1;
+	u_int32 fme_min_sad;
+	u_int32 cme_min_sad;
+
+	u_int32 fme_pred_int_weight;
+	u_int32 fme_pred_hp_weight;
+	u_int32 fme_pred_qp_weight;
+	u_int32 fme_cost_weight;
+	u_int32 fme_act_thold;
+	u_int32 fme_sad_thold;
+	u_int32 fme_zero_sad_thold;
+
+	u_int32 fme_lrg_mvx_lmt;
+	u_int32 fme_lrg_mvy_lmt;
+	u_int32 fme_force_mode;
+	u_int32 fme_force4mvcost;
+	u_int32 fme_force2mvcost;
+
+	u_int32 h264_inter_thrd;
+
+	u_int32 i16x16_mode_cost;
+	u_int32 i4x4_mode_lambda;
+	u_int32 i8x8_mode_lambda;
+
+	u_int32 inter_mod_mult;
+	u_int32 inter_sel_mult;
+	u_int32 inter_bid_cost;
+	u_int32 inter_bwd_cost;
+	u_int32 inter_4mv_cost;
+	int32   one_mv_i16_cost;
+	int32   one_mv_i4x4_cost;
+	int32   one_mv_i8x8_cost;
+	int32   two_mv_i16_cost;
+	int32   two_mv_i4x4_cost;
+	int32   two_mv_i8x8_cost;
+	int32   four_mv_i16_cost;
+	int32   four_mv_i4x4_cost;
+	int32   four_mv_i8x8_cost;
+
+	u_int32 intra_pred_enab;
+	u_int32 intra_chr_pred;
+	u_int32 intra16_pred;
+	u_int32 intra4x4_pred;
+	u_int32 intra8x8_pred;
+
+	u_int32 cb_base;
+	u_int32 cb_size;
+	u_int32 cb_head_room;
+
+	u_int32 mem_page_width;
+	u_int32 mem_page_height;
+	u_int32 mem_total_size;
+	u_int32 mem_chunk_phys_addr;
+	u_int32 mem_chunk_virt_addr;
+	u_int32 mem_chunk_size;
+	u_int32 mem_y_stride;
+	u_int32 mem_uv_stride;
+
+	u_int32 split_wr_enab;
+	u_int32 split_wr_req_size;
+	u_int32 split_rd_enab;
+	u_int32 split_rd_req_size;
+
+} MEDIAIP_ENC_CALIB_PARAMS, *pMEDIAIP_ENC_CALIB_PARAMS;
+
+typedef struct {
+	u_int32 ParamChange;
+
+	u_int32 start_frame;                // These variables are for debugging purposes only
+	u_int32 end_frame;
+
+	u_int32 userdata_enable;
+	u_int32 userdata_id[4];
+	u_int32 userdata_message[MEDIAIP_ENC_USER_DATA_WORDS];
+	u_int32 userdata_length;
+
+	u_int32 h264_profile_idc;
+	u_int32 h264_level_idc;
+	u_int32 h264_au_delimiter;          // Enable the use of Access Unit Delimiters
+	u_int32 h264_seq_end_code;          // Enable the use of Sequence End Codes
+	u_int32 h264_recovery_points;       // Enable the use of Recovery Points (must be with a fixed GOP structure)
+	u_int32 h264_vui_parameters;        // Enable the use of VUI parameters (for rate control purposes)
+	u_int32 h264_aspect_ratio_present;
+	u_int32 h264_aspect_ratio_sar_width;
+	u_int32 h264_aspect_ratio_sar_height;
+	u_int32 h264_overscan_present;
+	u_int32 h264_video_type_present;
+	u_int32 h264_video_format;
+	u_int32 h264_video_full_range;
+	u_int32 h264_video_colour_descriptor;
+	u_int32 h264_video_colour_primaries;
+	u_int32 h264_video_transfer_char;
+	u_int32 h264_video_matrix_coeff;
+	u_int32 h264_chroma_loc_info_present;
+	u_int32 h264_chroma_loc_type_top;
+	u_int32 h264_chroma_loc_type_bot;
+	u_int32 h264_timing_info_present;
+	u_int32 h264_buffering_period_present;
+	u_int32 h264_low_delay_hrd_flag;
+
+	u_int32 aspect_ratio;
+	u_int32 test_mode;                  // Automated firmware test mode
+	u_int32 dsa_test_mode;              // Automated test mode for the DSA.
+	u_int32 fme_test_mode;              // Automated test mode for the fme
+
+	u_int32 cbr_row_mode;               //0: FW mode; 1: HW mode
+	u_int32 windsor_mode;               //0: normal mode; 1: intra only mode; 2: intra+0MV mode
+	u_int32 encode_mode;                // H264, VC1, MPEG2, DIVX
+	u_int32 frame_width;                // display width
+	u_int32 frame_height;               // display height
+	u_int32 enc_frame_width;            // encoding width, should be 16-pix align
+	u_int32 enc_frame_height;           // encoding height, should be 16-pix aligned for progressive and 32-pix aligned for interlace
+	u_int32 frame_rate_num;
+	u_int32 frame_rate_den;
+
+	u_int32 vi_field_source;              // vi input source is frame or field
+	u_int32 vi_frame_width;
+	u_int32 vi_frame_height;
+	u_int32 crop_frame_width;
+	u_int32 crop_frame_height;
+	u_int32 crop_x_start_posn;
+	u_int32 crop_y_start_posn;
+	u_int32 mode422;
+	u_int32 mode_yuy2;
+	u_int32 dsa_luma_en;
+	u_int32 dsa_chroma_en;
+	u_int32 dsa_ext_hfilt_en;
+	u_int32 dsa_di_en;
+	u_int32 dsa_di_top_ref;
+	u_int32 dsa_vertf_disable;   // disable the vertical filter.
+	u_int32 dsa_disable_pwb;
+	u_int32 dsa_hor_phase;
+	u_int32 dsa_ver_phase;
+
+	u_int32 dsa_iac_enable;      // IAC / DSA cannot operate independently in FW so this variable controls
+	u_int32 iac_sc_threshold;
+	u_int32 iac_vm_threshold;
+	u_int32 iac_skip_mode;
+	u_int32 iac_grp_width;
+	u_int32 iac_grp_height;
+
+	u_int32 rate_control_mode;
+	u_int32 rate_control_resolution;
+	u_int32 buffer_size;
+	u_int32 buffer_level_init;
+	u_int32 buffer_I_bit_budget;
+
+	u_int32 top_field_first;
+
+	u_int32 intra_lum_qoffset;
+	u_int32 intra_chr_qoffset;
+	u_int32 inter_lum_qoffset;
+	u_int32 inter_chr_qoffset;
+	u_int32 use_def_scaling_mtx;
+
+	u_int32 inter_8x8_enab;
+	u_int32 inter_4x4_enab;
+
+	u_int32 fme_enable_qpel;
+	u_int32 fme_enable_hpel;
+	u_int32 fme_nozeromv;               // can force the FME not to do the (0,0) search.
+	u_int32 fme_predmv_en;
+	u_int32 fme_pred_2mv4mv;
+	u_int32 fme_smallsadthresh;
+
+	u_int32 ame_en_lmvc;
+	u_int32 ame_x_mult;
+	u_int32 cme_enable_4mv;             // Enable the use of 4MV partitioning
+	u_int32 cme_enable_1mv;
+	u_int32 hme_enable_16x8mv;
+	u_int32 hme_enable_8x16mv;
+	u_int32 cme_mv_weight;              // CME motion vector decisions are made by combining these
+	u_int32 cme_mv_cost;                // cost and weight variables
+	u_int32 ame_mult_mv;
+	u_int32 ame_shift_mv;
+
+	u_int32 hme_forceto1mv_en;
+	u_int32 hme_2mv_cost;               // the cost of choosing a 2MV mode over 1MV.
+	u_int32 hme_pred_mode;
+	u_int32 hme_sc_rnge;
+	u_int32 hme_sw_rnge;
+
+	// for windsor pes , add by fulin
+	u_int32 output_format;     // 0: output ES; 1: output PES
+	u_int32 timestamp_enab;    // 0: have timestamps in all frame; 1: have timestamps in I and P frame; 2: have timestamps only in I frame
+	u_int32 initial_PTS_enab;  // if enabled , use following value,else compute by fw
+	u_int32 initial_PTS;       // the initial value of PTS in the first frame (ms)
+
+} MEDIAIP_ENC_CONFIG_PARAMS, *pMEDIAIP_ENC_CONFIG_PARAMS;
+
+typedef struct {
+	u_int32 ParamChange;
+
+	u_int32 gop_length;
+
+	u_int32 rate_control_bitrate;
+	u_int32 rate_control_bitrate_min;
+	u_int32 rate_control_bitrate_max;
+	u_int32 rate_control_content_models;
+	u_int32 rate_control_iframe_maxsize; // Maximum size of I frame generated by BPM in comparison to ideal (/4)
+	u_int32 rate_control_qp_init;
+	u_int32 rate_control_islice_qp;
+	u_int32 rate_control_pslice_qp;
+	u_int32 rate_control_bslice_qp;
+
+	u_int32 adaptive_quantization;      // Enable the use of activity measures from VIPP in QP assignment
+	u_int32 aq_variance;
+	u_int32 cost_optimization;          // Enable picture/frame level adjustments of the cost parameters by FW.
+	u_int32 fdlp_mode;                  // Frequency-domain low-pass filter control, 0: off, 1-4: specific, 5: adaptive
+	u_int32 enable_isegbframes;         // Enable the use of B frames in the first segment of a GOP
+	u_int32 enable_adaptive_keyratio;   // Enable the use of an adaptive I to P/B ratio (aims to reduce distortion)
+	u_int32 keyratio_imin;              // Clamps applied to picture size ratios
+	u_int32 keyratio_imax;
+	u_int32 keyratio_pmin;
+	u_int32 keyratio_pmax;
+	u_int32 keyratio_bmin;
+	u_int32 keyratio_bmax;
+	int32   keyratio_istep;
+	int32   keyratio_pstep;
+	int32   keyratio_bstep;
+
+	u_int32 enable_paff;                // Enable Picture Adaptive Frame/Field
+	u_int32 enable_b_frame_ref;         // Enable B frame as references
+	u_int32 enable_adaptive_gop;        // Enable an adaptive GOP structure
+	u_int32 enable_closed_gop;          // Enable a closed GOP structure
+									  // i.e. if enabled, the first consecutive B frames following
+									  // an I frame in each GOP will be intra or backwards only coded
+									  // and do not rely on previous reference pictures.
+	u_int32 open_gop_refresh_freq;      // Controls the insertion of closed GOP's (or IDR GOP's in H.264)
+	u_int32 enable_adaptive_sc;         // Enable adaptive scene change GOP structure (0:off, 1:adaptive, 2:IDR)
+	u_int32 enable_fade_detection;      // Enable fade detection and associated motion estimation restrictions
+	int32   fade_detection_threshold;   // Threshold at which the activity slope indicates a possible fading event
+	u_int32 enable_repeat_b;            // Enalbe the repeated B frame mode at CBR
+	u_int32 enable_low_delay_b;         // Use low delay-b frames with an IPPPP style GOP
+
+} MEDIAIP_ENC_STATIC_PARAMS, *pMEDIAIP_ENC_STATIC_PARAMS;
+
+typedef struct {
+	u_int32 ParamChange;
+
+	u_int32 rows_per_slice;
+
+	u_int32 mbaff_enable;                // Macroblock adaptive frame/field enable
+	u_int32 dbf_enable;                  // Enable the deblocking filter
+
+	u_int32 field_source;                // progressive/interlaced control
+	u_int32 gop_b_length;                // Number of B frames between anchor frames
+									  //  (only to be changed at a GOP segment boundary)
+	u_int32 mb_group_size;               // Number of macroblocks normally assigned to a group
+									  // (implications for performance, interrupts and rate control)
+
+	u_int32 cbr_rows_per_group;
+
+	u_int32 skip_enable;                 // Enable the use of skipped macroblocks
+
+	u_int32 pts_bits_0_to_31;            // TO BE REMOVED...
+	u_int32 pts_bit_32;
+
+	u_int32 rm_expsv_cff;
+	u_int32 const_ipred;
+	int32 chr_qp_offset;
+	u_int32 intra_mb_qp_offset;
+
+	u_int32 h264_cabac_init_method;
+	u_int32 h264_cabac_init_idc;
+	u_int32 h264_cabac_enable;                 // Main and stream
+
+	int32 alpha_c0_offset_div2;
+	int32 beta_offset_div2;
+
+	u_int32 intra_prefresh_y0; // for setting intra limits for prog refresh.
+	u_int32 intra_prefresh_y1;
+
+	u_int32 dbg_dump_rec_src;
+
+} MEDIAIP_ENC_DYN_PARAMS, *pMEDIAIP_ENC_DYN_PARAMS;
+
+typedef struct {
+	MEDIAIP_ENC_CALIB_PARAMS   Calib;
+	MEDIAIP_ENC_CONFIG_PARAMS  Config;
+	MEDIAIP_ENC_STATIC_PARAMS  Static;
+	MEDIAIP_ENC_DYN_PARAMS     Dynamic;
+} MEDIAIP_ENC_EXPERT_MODE_PARAM, *pMEDIAIP_ENC_EXPERT_MODE_PARAM;
+
+typedef enum {
+	MEDIAIP_ENC_FMT_H264 = 0,
+	MEDIAIP_ENC_FMT_VC1,
+	MEDIAIP_ENC_FMT_MPEG2,
+	MEDIAIP_ENC_FMT_MPEG4SP,
+	MEDIAIP_ENC_FMT_H263,
+	MEDIAIP_ENC_FMT_MPEG1,
+	MEDIAIP_ENC_FMT_SHORT_HEADER,
+	MEDIAIP_ENC_FMT_NULL
+
+} MEDIAIP_ENC_FMT;
+
+typedef enum {
+	MEDIAIP_ENC_PROF_MPEG2_SP = 0,
+	MEDIAIP_ENC_PROF_MPEG2_MP,
+	MEDIAIP_ENC_PROF_MPEG2_HP,
+	MEDIAIP_ENC_PROF_H264_BP,
+	MEDIAIP_ENC_PROF_H264_MP,
+	MEDIAIP_ENC_PROF_H264_HP,
+	MEDIAIP_ENC_PROF_MPEG4_SP,
+	MEDIAIP_ENC_PROF_MPEG4_ASP,
+	MEDIAIP_ENC_PROF_VC1_SP,
+	MEDIAIP_ENC_PROF_VC1_MP,
+	MEDIAIP_ENC_PROF_VC1_AP
+
+} MEDIAIP_ENC_PROFILE;
+
+typedef enum {
+	MEDIAIP_ENC_BITRATECONTROLMODE_VBR          = 0x00000001,
+	MEDIAIP_ENC_BITRATECONTROLMODE_CBR          = 0x00000002,
+	MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP  = 0x00000004   /* Only in debug mode */
+
+} MEDIAIP_ENC_BITRATE_MODE, *pMEDIAIP_ENC_BITRATE_MODE;
+
+typedef struct {
+	MEDIAIP_ENC_FMT           eCodecMode;
+	MEDIAIP_ENC_PROFILE       eProfile;
+	u_int32                   uLevel;
+
+	MEDIAIP_ENC_MEM_RESOURCE  tEncMemDesc;
+
+	u_int32                   uFrameRate;
+	u_int32                   uSrcStride;
+	u_int32                   uSrcWidth;
+	u_int32                   uSrcHeight;
+	u_int32                   uSrcOffset_x;
+	u_int32                   uSrcOffset_y;
+	u_int32                   uSrcCropWidth;
+	u_int32                   uSrcCropHeight;
+	u_int32                   uOutWidth;
+	u_int32                   uOutHeight;
+	u_int32                   uIFrameInterval;
+	u_int32                   uGopBLength;
+	u_int32                   uLowLatencyMode;
+
+	MEDIAIP_ENC_BITRATE_MODE  eBitRateMode;
+	u_int32                   uTargetBitrate;
+	u_int32                   uMaxBitRate;
+	u_int32                   uMinBitRate;
+	u_int32                   uInitSliceQP;
+
+} MEDIAIP_ENC_PARAM, *pMEDIAIP_ENC_PARAM;
+
+typedef struct {
+	u_int32   uFrameID;
+	u_int32   uErrorFlag;   //Error type
+	u_int32   uMBy;
+	u_int32   uMBx;
+	u_int32   uReserved[12];
+
+} ENC_ENCODING_STATUS, *pENC_ENCODING_STATUS;
+
+typedef struct {
+	u_int32   uFrameID;
+	u_int32   uDsaCyle;
+	u_int32   uMBy;
+	u_int32   uMBx;
+	u_int32   uReserved[4];
+
+} ENC_DSA_STATUS_t, *pENC_DSA_STATUS_t;
+
+typedef struct {
+	u_int32                                  pEncYUVBufferDesc;
+	u_int32                                  pEncStreamBufferDesc;
+	u_int32                                  pEncExpertModeParam;
+	u_int32                                  pEncParam;
+	u_int32                                  pEncMemPool;
+	/* Status information for master to read */
+	u_int32                                  pEncEncodingStatus;
+	u_int32                                  pEncDSAStatus;
+} MEDIA_ENC_API_CONTROL_INTERFACE, *pMEDIA_ENC_API_CONTROL_INTERFACE;
+
+typedef struct {
+	u_int32					FwExecBaseAddr;
+	u_int32					FwExecAreaSize;
+	BUFFER_DESCRIPTOR_TYPE			StreamCmdBufferDesc;
+	BUFFER_DESCRIPTOR_TYPE			StreamMsgBufferDesc;
+	u_int32					StreamCmdIntEnable[VID_API_NUM_STREAMS];
+	u_int32					FWVersion;
+	u_int32					uMVDFWOffset;
+	u_int32					uMaxEncoderStreams;
+	u_int32					pEncCtrlInterface[VID_API_NUM_STREAMS];
+	MEDIAIP_FW_SYSTEM_CONFIG		sSystemCfg;
+	u_int32					uApiVersion;
+	BUFFER_DESCRIPTOR_TYPE			DebugBufferDesc;
+} ENC_RPC_HOST_IFACE, *pENC_RPC_HOST_IFACE;
+
+#define SCB_XREG_SLV_BASE                               0x00000000
+#define SCB_SCB_BLK_CTRL                                0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET                     0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET                    0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR                    0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET                 0x00000100
+
+#define XMEM_CONTROL                                    0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE                           0x00180000
+
+#define MFD_HIF                                         0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS                0x00000018
+#define MFD_SIF                                         0x0001D000
+#define MFD_SIF_CTRL_STATUS                             0x000000F0
+#define MFD_SIF_INTR_STATUS                             0x000000F4
+#define MFD_MCX                                         0x00020800
+#define MFD_MCX_OFF                                     0x00000020
+
+#define MFD_BLK_CTRL                                    0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET                  0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR                  0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET           0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR           0x00000104
+
+#define CSR_CM0Px_ADDR_OFFSET				0x00000000
+#define CSR_CM0Px_CPUWAIT				0x00000004
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_b0.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_b0.c
@@ -0,0 +1,6447 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/debugfs.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "vpu_encoder_b0.h"
+#include "vpu_encoder_ctrl.h"
+#include "vpu_encoder_config.h"
+#include "vpu_event_msg.h"
+#include "vpu_encoder_mem.h"
+#include "vpu_encoder_mu.h"
+#include "vpu_encoder_pm.h"
+
+#define VPU_ENC_DRIVER_VERSION		"1.0.3"
+
+struct vpu_frame_info {
+	struct list_head list;
+	MEDIAIP_ENC_PIC_INFO info;
+	u32 bytesleft;
+	u32 wptr;
+	u32 rptr;
+	u32 start;
+	u32 end;
+	bool eos;
+	bool is_start;
+	unsigned long index;
+	struct queue_data *queue;
+	s64 timestamp;
+};
+
+unsigned int vpu_dbg_level_encoder = LVL_ERR | LVL_WARN | LVL_ALL;
+static unsigned int reset_on_hang;
+static unsigned int show_detail_index = VPU_DETAIL_INDEX_DFT;
+static unsigned long debug_firmware_bitmap;
+
+#define ITEM_NAME(name)		\
+				[name] = #name
+
+static char *cmd2str[] = {
+	ITEM_NAME(GTB_ENC_CMD_NOOP),
+	ITEM_NAME(GTB_ENC_CMD_STREAM_START),
+	ITEM_NAME(GTB_ENC_CMD_FRAME_ENCODE),
+	ITEM_NAME(GTB_ENC_CMD_FRAME_SKIP),
+	ITEM_NAME(GTB_ENC_CMD_STREAM_STOP),
+	ITEM_NAME(GTB_ENC_CMD_PARAMETER_UPD),
+	ITEM_NAME(GTB_ENC_CMD_TERMINATE),
+	ITEM_NAME(GTB_ENC_CMD_SNAPSHOT),
+	ITEM_NAME(GTB_ENC_CMD_ROLL_SNAPSHOT),
+	ITEM_NAME(GTB_ENC_CMD_LOCK_SCHEDULER),
+	ITEM_NAME(GTB_ENC_CMD_UNLOCK_SCHEDULER),
+	ITEM_NAME(GTB_ENC_CMD_CONFIGURE_CODEC),
+	ITEM_NAME(GTB_ENC_CMD_DEAD_MARK),
+	ITEM_NAME(GTB_ENC_CMD_FIRM_RESET),
+	ITEM_NAME(GTB_ENC_CMD_RESERVED)
+};
+
+static char *event2str[] = {
+	ITEM_NAME(VID_API_EVENT_UNDEFINED),
+	ITEM_NAME(VID_API_ENC_EVENT_RESET_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_START_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_STOP_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_TERMINATE_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_FRAME_INPUT_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_FRAME_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_FRAME_RELEASE),
+	ITEM_NAME(VID_API_ENC_EVENT_PARA_UPD_DONE),
+	ITEM_NAME(VID_API_ENC_EVENT_MEM_REQUEST),
+	ITEM_NAME(VID_API_ENC_EVENT_FIRMWARE_XCPT),
+	ITEM_NAME(VID_API_ENC_EVENT_RESERVED)
+};
+
+static int wait_for_boot_done(struct core_device *core, int resume);
+static void wait_for_start_done(struct vpu_ctx *ctx);
+static void wait_for_stop_done(struct vpu_ctx *ctx);
+static int sw_reset_firmware(struct core_device *core, int resume);
+static int enable_fps_sts(struct vpu_attr *attr);
+static int disable_fps_sts(struct vpu_attr *attr);
+static int configure_codec(struct vpu_ctx *ctx);
+static struct vpu_frame_info *get_idle_frame(struct queue_data *queue);
+static void put_frame_idle(struct vpu_frame_info *frame);
+static int inc_frame(struct queue_data *queue);
+static void dec_frame(struct vpu_frame_info *frame);
+static int submit_input_and_encode(struct vpu_ctx *ctx);
+static int process_stream_output(struct vpu_ctx *ctx);
+static u32 get_ptr(u32 ptr);
+static int is_vpu_enc_poweroff(struct core_device *core);
+
+static char *get_event_str(u32 event)
+{
+	if (event >= VID_API_ENC_EVENT_RESERVED)
+		return "UNKNOWN EVENT";
+	return event2str[event];
+}
+
+static char *get_cmd_str(u32 cmdid)
+{
+	if (cmdid >= GTB_ENC_CMD_RESERVED)
+		return "UNKNOWN CMD";
+	return cmd2str[cmdid];
+}
+
+static void vpu_log_event(u_int32 uEvent, u_int32 ctxid)
+{
+	if (uEvent >= VID_API_ENC_EVENT_RESERVED)
+		vpu_err("receive event: 0x%X, ctx id:%d\n",
+				uEvent, ctxid);
+	else
+		vpu_dbg(LVL_EVT, "recevie event: %s, ctx id:%d\n",
+				event2str[uEvent], ctxid);
+}
+
+static void vpu_log_cmd(u_int32 cmdid, u_int32 ctxid)
+{
+	if (cmdid >= GTB_ENC_CMD_RESERVED)
+		vpu_err("send cmd: 0x%X, ctx id:%d\n",
+				cmdid, ctxid);
+	else
+		vpu_dbg(LVL_CMD, "send cmd: %s ctx id:%d\n",
+				cmd2str[cmdid], ctxid);
+}
+
+static void count_event(struct vpu_ctx *ctx, u32 event)
+{
+	struct vpu_attr *attr;
+
+	WARN_ON(!ctx);
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	if (event < VID_API_ENC_EVENT_RESERVED)
+		attr->statistic.event[event]++;
+	else
+		attr->statistic.event[VID_API_ENC_EVENT_RESERVED]++;
+
+	attr->statistic.current_event = event;
+	ktime_get_raw_ts64(&attr->statistic.ts_event);
+}
+
+static void count_cmd(struct vpu_attr *attr, u32 cmdid)
+{
+	WARN_ON(!attr);
+
+	if (cmdid < GTB_ENC_CMD_RESERVED)
+		attr->statistic.cmd[cmdid]++;
+	else
+		attr->statistic.cmd[GTB_ENC_CMD_RESERVED]++;
+	attr->statistic.current_cmd = cmdid;
+	ktime_get_raw_ts64(&attr->statistic.ts_cmd);
+}
+
+static void count_yuv_input(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = NULL;
+
+	WARN_ON(!ctx);
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	attr->statistic.yuv_count++;
+}
+
+static void count_h264_output(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = NULL;
+
+	WARN_ON(!ctx);
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	attr->statistic.h264_count++;
+}
+
+static void count_encoded_frame(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = NULL;
+
+	WARN_ON(!ctx);
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	attr->statistic.encoded_count++;
+}
+
+static void write_vpu_reg(struct vpu_dev *dev, u32 val, off_t reg)
+{
+	writel(val, dev->regs_base + reg);
+}
+
+static u32 read_vpu_reg(struct vpu_dev *dev, off_t reg)
+{
+	return readl(dev->regs_base + reg);
+}
+
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt  formats_compressed_enc[] = {
+	{
+		.name       = "H264 Encoded Stream",
+		.fourcc     = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.venc_std   = VPU_VIDEO_AVC,
+		.is_yuv     = 0,
+	},
+};
+
+static struct vpu_v4l2_fmt  formats_yuv_enc[] = {
+	{
+		.name       = "4:2:0 2 Planes Y/CbCr",
+		.fourcc     = V4L2_PIX_FMT_NV12,
+		.num_planes	= 2,
+		.venc_std   = VPU_PF_YUV420_SEMIPLANAR,
+		.is_yuv     = 1,
+	},
+};
+
+static void vpu_ctx_send_cmd(struct vpu_ctx *ctx, uint32_t cmdid,
+				uint32_t cmdnum, uint32_t *local_cmddata);
+
+#define GET_CTX_RPC(ctx, func)	\
+		func(&ctx->core_dev->shared_mem, ctx->str_index)
+
+pMEDIAIP_ENC_YUV_BUFFER_DESC get_rpc_yuv_buffer_desc(struct vpu_ctx *ctx)
+{
+	return GET_CTX_RPC(ctx, rpc_get_yuv_buffer_desc);
+}
+
+pBUFFER_DESCRIPTOR_TYPE get_rpc_stream_buffer_desc(struct vpu_ctx *ctx)
+{
+	return GET_CTX_RPC(ctx, rpc_get_stream_buffer_desc);
+}
+
+pMEDIAIP_ENC_EXPERT_MODE_PARAM get_rpc_expert_mode_param(struct vpu_ctx *ctx)
+{
+	return GET_CTX_RPC(ctx, rpc_get_expert_mode_param);
+}
+
+pMEDIAIP_ENC_PARAM get_rpc_enc_param(struct vpu_ctx *ctx)
+{
+	return GET_CTX_RPC(ctx, rpc_get_enc_param);
+}
+
+pMEDIAIP_ENC_MEM_POOL get_rpc_mem_pool(struct vpu_ctx *ctx)
+{
+	return GET_CTX_RPC(ctx, rpc_get_mem_pool);
+}
+
+pENC_ENCODING_STATUS get_rpc_encoding_status(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->core_dev)
+		return NULL;
+	return GET_CTX_RPC(ctx, rpc_get_encoding_status);
+}
+
+pENC_DSA_STATUS_t get_rpc_dsa_status(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->core_dev)
+		return NULL;
+	return GET_CTX_RPC(ctx, rpc_get_dsa_status);
+}
+
+static int vpu_enc_v4l2_ioctl_querycap(struct file *file,
+		void *fh,
+		struct v4l2_capability *cap)
+{
+	vpu_log_func();
+	strlcpy(cap->driver, "vpu encoder", sizeof(cap->driver));
+	strlcpy(cap->card, "vpu encoder", sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_enum_fmt_vid_cap(struct file *file,
+		void *fh,
+		struct v4l2_fmtdesc *f)
+{
+	struct vpu_v4l2_fmt *fmt;
+
+	vpu_log_func();
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	if (f->index >= ARRAY_SIZE(formats_compressed_enc))
+		return -EINVAL;
+
+	fmt = &formats_compressed_enc[f->index];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+	return 0;
+}
+static int vpu_enc_v4l2_ioctl_enum_fmt_vid_out(struct file *file,
+		void *fh,
+		struct v4l2_fmtdesc *f)
+{
+	struct vpu_v4l2_fmt *fmt;
+
+	vpu_log_func();
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	if (f->index >= ARRAY_SIZE(formats_yuv_enc))
+		return -EINVAL;
+
+	fmt = &formats_yuv_enc[f->index];
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_enum_framesizes(struct file *file, void *fh,
+					struct v4l2_frmsizeenum *fsize)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_dev *vdev = ctx->dev;
+
+	if (!fsize)
+		return -EINVAL;
+
+	if (fsize->index)
+		return -EINVAL;
+
+	if (!vdev)
+		return -EINVAL;
+
+	vpu_log_func();
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.max_width = vdev->supported_size.max_width;
+	fsize->stepwise.max_height = vdev->supported_size.max_height;
+	fsize->stepwise.min_width = vdev->supported_size.min_width;
+	fsize->stepwise.min_height = vdev->supported_size.min_height;
+	fsize->stepwise.step_width = vdev->supported_size.step_width;
+	fsize->stepwise.step_height = vdev->supported_size.step_height;
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_enum_frameintervals(struct file *file, void *fh,
+						struct v4l2_frmivalenum *fival)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_dev *vdev = ctx->dev;
+
+
+	if (!fival || fival->index)
+		return -EINVAL;
+	if (!vdev)
+		return -EINVAL;
+
+	vpu_log_func();
+
+	fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+	fival->stepwise.min.numerator = 1;
+	fival->stepwise.min.denominator = 65535;
+	fival->stepwise.max.numerator = 65535;
+	fival->stepwise.max.denominator = 1;
+	fival->stepwise.step.numerator = 1;
+	fival->stepwise.step.denominator = 1;
+
+	return 0;
+}
+
+static struct queue_data *get_queue_by_v4l2_type(struct vpu_ctx *ctx, u32 type)
+{
+	struct queue_data *queue = NULL;
+
+	if (!ctx)
+		return NULL;
+
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		queue = &ctx->q_data[V4L2_SRC];
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		queue = &ctx->q_data[V4L2_DST];
+		break;
+	default:
+		vpu_err("unsupport v4l2 buf type : %d\n", type);
+		break;
+	}
+
+	return queue;
+}
+
+static int vpu_enc_v4l2_ioctl_g_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f)
+{
+	struct vpu_ctx *ctx =           v4l2_fh_to_ctx(fh);
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+	struct queue_data *q_data;
+	unsigned int i;
+
+	q_data = get_queue_by_v4l2_type(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s\n", __func__, q_data->desc);
+
+	if (!q_data->current_fmt) {
+		vpu_err("%s's current fmt is NULL\n", q_data->desc);
+		return -EINVAL;
+	}
+
+	pix_mp->pixelformat = q_data->current_fmt->fourcc;
+	pix_mp->num_planes = q_data->current_fmt->num_planes;
+	pix_mp->width = q_data->width;
+	pix_mp->height = q_data->height;
+	pix_mp->field = V4L2_FIELD_ANY;
+	for (i = 0; i < pix_mp->num_planes; i++)
+		pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+
+	if (!V4L2_TYPE_IS_OUTPUT(f->type))
+		pix_mp->plane_fmt[0].bytesperline = q_data->width;
+
+	pix_mp->colorspace = ctx->colorspace;
+	pix_mp->xfer_func = ctx->xfer_func;
+	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+	pix_mp->quantization = ctx->quantization;
+
+	return 0;
+}
+
+u32 cpu_phy_to_mu(struct core_device *dev, u32 addr)
+{
+	return addr - dev->m0_p_fw_space_phy;
+}
+
+static int initialize_enc_param(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM param = &attr->param;
+
+	mutex_lock(&ctx->instance_mutex);
+	param->eCodecMode = MEDIAIP_ENC_FMT_H264;
+	param->tEncMemDesc.uMemPhysAddr = 0;
+	param->tEncMemDesc.uMemVirtAddr = 0;
+	param->tEncMemDesc.uMemSize     = 0;
+	param->uSrcStride = VPU_ENC_WIDTH_DEFAULT;
+	param->uSrcWidth = VPU_ENC_WIDTH_DEFAULT;
+	param->uSrcHeight = VPU_ENC_HEIGHT_DEFAULT;
+	param->uSrcOffset_x = 0;
+	param->uSrcOffset_y = 0;
+	param->uSrcCropWidth = VPU_ENC_WIDTH_DEFAULT;
+	param->uSrcCropHeight = VPU_ENC_HEIGHT_DEFAULT;
+	param->uOutWidth = VPU_ENC_WIDTH_DEFAULT;
+	param->uOutHeight = VPU_ENC_HEIGHT_DEFAULT;
+	param->uMinBitRate = BITRATE_LOW_THRESHOLD;
+
+	attr->fival.numerator = 1;
+	attr->fival.denominator = VPU_ENC_FRAMERATE_DEFAULT;
+	param->uFrameRate = VPU_ENC_FRAMERATE_DEFAULT;
+
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int check_stepwise(u32 val, u32 min, u32 max, u32 step)
+{
+	if (val < min)
+		return -EINVAL;
+	if (val > max)
+		return -EINVAL;
+	if ((val - min) % step)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int check_size(struct vpu_dev *vdev, u32 width, u32 height)
+{
+	int ret;
+
+	if (!vdev)
+		return -EINVAL;
+
+	ret = check_stepwise(width,
+			vdev->supported_size.min_width,
+			vdev->supported_size.max_width,
+			vdev->supported_size.step_width);
+	if (ret) {
+		vpu_err("Unsupported frame size : %dx%d\n", width, height);
+		return -EINVAL;
+	}
+	ret = check_stepwise(height,
+			vdev->supported_size.min_height,
+			vdev->supported_size.max_height,
+			vdev->supported_size.step_height);
+	if (ret) {
+		vpu_err("Unsupported frame size : %dx%d\n", width, height);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int valid_crop_info(struct queue_data *queue, struct v4l2_rect *rect)
+{
+	struct vpu_ctx *ctx;
+	u32 MIN_WIDTH;
+	u32 MIN_HEIGHT;
+
+	if (!queue || !rect || !queue->ctx)
+		return -EINVAL;
+
+	ctx = queue->ctx;
+	MIN_WIDTH = ctx->dev->supported_size.min_width;
+	MIN_HEIGHT = ctx->dev->supported_size.min_height;
+
+	if (rect->left > queue->width - MIN_WIDTH ||
+		rect->top > queue->height - MIN_HEIGHT) {
+		rect->left = 0;
+		rect->top = 0;
+		rect->width = queue->width;
+		rect->height = queue->height;
+		return 0;
+	}
+
+	rect->width = min(rect->width, queue->width - rect->left);
+	if (rect->width)
+		rect->width = max_t(u32, rect->width, MIN_WIDTH);
+	else
+		rect->width = queue->width;
+	rect->height = min(rect->height, queue->height - rect->top);
+	if (rect->height)
+		rect->height = max_t(u32, rect->height, MIN_HEIGHT);
+	else
+		rect->height = queue->height;
+
+	return 0;
+}
+
+static int check_v4l2_fmt(struct vpu_dev *dev, struct v4l2_format *f)
+{
+	int ret = -EINVAL;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		ret = check_size(dev, f->fmt.pix.width, f->fmt.pix.height);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		ret = check_size(dev, f->fmt.pix_mp.width,
+					f->fmt.pix_mp.height);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct vpu_v4l2_fmt *find_fmt_by_fourcc(struct vpu_v4l2_fmt *fmts,
+						unsigned int size,
+						u32 fourcc)
+{
+	unsigned int i;
+
+	if (!fmts || !size)
+		return NULL;
+
+	for (i = 0; i < size; i++) {
+		if (fmts[i].fourcc == fourcc)
+			return &fmts[i];
+	}
+
+	return NULL;
+}
+
+static char *cvrt_fourcc_to_str(u32 pixelformat)
+{
+	static char str[5];
+
+	str[0] = pixelformat & 0xff;
+	str[1] = (pixelformat >> 8) & 0xff;
+	str[2] = (pixelformat >> 16) & 0xff;
+	str[3] = (pixelformat >> 24) & 0xff;
+	str[4] = '\0';
+
+	return str;
+}
+
+static const u8 colorprimaries[] = {
+	0,
+	V4L2_COLORSPACE_REC709,        /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_COLORSPACE_470_SYSTEM_M, /*Rec. ITU-R BT.470-6 System M*/
+	V4L2_COLORSPACE_470_SYSTEM_BG,/*Rec. ITU-R BT.470-6 System B, G*/
+	V4L2_COLORSPACE_SMPTE170M,    /*SMPTE170M*/
+	V4L2_COLORSPACE_SMPTE240M,    /*SMPTE240M*/
+	V4L2_COLORSPACE_GENERIC_FILM, /*Generic film*/
+	V4L2_COLORSPACE_BT2020,       /*Rec. ITU-R BT.2020-2*/
+	V4L2_COLORSPACE_ST428         /*SMPTE ST 428-1*/
+};
+
+static const u8 colortransfers[] = {
+	0,
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_XFER_FUNC_GAMMA22,  /*Rec. ITU-R BT.470-6 System M*/
+	V4L2_XFER_FUNC_GAMMA28,  /*Rec. ITU-R BT.470-6 System B, G*/
+	V4L2_XFER_FUNC_709,      /*SMPTE170M*/
+	V4L2_XFER_FUNC_SMPTE240M,/*SMPTE240M*/
+	V4L2_XFER_FUNC_LINEAR,   /*Linear transfer characteristics*/
+	0,
+	0,
+	V4L2_XFER_FUNC_XVYCC,    /*IEC 61966-2-4*/
+	V4L2_XFER_FUNC_BT1361,   /*Rec. ITU-R BT.1361-0 extended colour gamut*/
+	V4L2_XFER_FUNC_SRGB,     /*IEC 61966-2-1 sRGB or sYCC*/
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.2020-2 (10 bit system)*/
+	V4L2_XFER_FUNC_709,      /*Rec. ITU-R BT.2020-2 (12 bit system)*/
+	V4L2_XFER_FUNC_SMPTE2084,/*SMPTE ST 2084*/
+	V4L2_XFER_FUNC_ST428,    /*SMPTE ST 428-1*/
+	V4L2_XFER_FUNC_HLG       /*Rec. ITU-R BT.2100-0 hybrid log-gamma (HLG)*/
+};
+
+static const u8 colormatrixcoefs[] = {
+	0,
+	V4L2_YCBCR_ENC_709,             /*Rec. ITU-R BT.709-6*/
+	0,
+	0,
+	V4L2_YCBCR_ENC_BT470_6M,        /*Title 47 Code of Federal Regulations*/
+	V4L2_YCBCR_ENC_601,             /*Rec. ITU-R BT.601-7 625*/
+	V4L2_YCBCR_ENC_601,             /*Rec. ITU-R BT.601-7 525*/
+	V4L2_YCBCR_ENC_SMPTE240M,       /*SMPTE240M*/
+	0,
+	V4L2_YCBCR_ENC_BT2020,          /*Rec. ITU-R BT.2020-2*/
+	V4L2_YCBCR_ENC_BT2020_CONST_LUM /*Rec. ITU-R BT.2020-2 constant*/
+};
+
+static int vpu_enc_convert_color_v4l2_aspect_to_iso_aspect(struct vpu_ctx *ctx,
+		u32 *primaries, u32 *transfer, u32 *coeffs, u32 *fullrange)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(colorprimaries); i++) {
+		if (colorprimaries[i] == ctx->colorspace) {
+			if (primaries)
+				*primaries = i;
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(colortransfers); i++) {
+		if (colortransfers[i] == ctx->xfer_func) {
+			if (transfer)
+				*transfer = i;
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(colormatrixcoefs); i++) {
+		if (colormatrixcoefs[i] == ctx->ycbcr_enc) {
+			if (coeffs)
+				*coeffs = i;
+			break;
+		}
+	}
+
+	if (fullrange)
+		*fullrange = ctx->quantization == V4L2_QUANTIZATION_FULL_RANGE;
+
+	return 0;
+}
+
+static bool vpu_enc_check_colorspace(u8 colorspace)
+{
+	int i;
+
+	if (colorspace == V4L2_COLORSPACE_DEFAULT)
+		return FALSE;
+
+	for (i = 0; i < ARRAY_SIZE(colorprimaries); i++) {
+		if (colorprimaries[i] == colorspace)
+			return true;
+	}
+
+	return false;
+}
+
+static bool vpu_enc_check_xfer_func(u8 xfer_func)
+{
+	int i;
+
+	if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(colortransfers); i++) {
+		if (colortransfers[i] == xfer_func)
+			return true;
+	}
+
+	return false;
+}
+
+static bool vpu_enc_check_ycbcr_enc(u8 ycbcr_enc)
+{
+	int i;
+
+	if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(colormatrixcoefs); i++) {
+		if (ycbcr_enc == colormatrixcoefs[i])
+			return true;
+	}
+
+	return false;
+}
+
+static bool vpu_enc_check_quantization(u8 quantization)
+{
+	bool support = false;
+
+	switch (quantization) {
+	case V4L2_QUANTIZATION_FULL_RANGE:
+	case V4L2_QUANTIZATION_LIM_RANGE:
+		support = true;
+		break;
+	default:
+		break;
+	}
+
+	return support;
+}
+
+static int vpu_enc_set_default_color(struct vpu_ctx *ctx, u8 colorspace)
+{
+	ctx->colorspace = colorspace;
+
+	switch (colorspace) {
+	case V4L2_COLORSPACE_REC709:
+		ctx->xfer_func = V4L2_XFER_FUNC_709;
+		ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+		break;
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+	case V4L2_COLORSPACE_SMPTE170M:
+		ctx->xfer_func = V4L2_XFER_FUNC_709;
+		ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+		break;
+	case V4L2_COLORSPACE_SMPTE240M:
+		ctx->xfer_func = V4L2_XFER_FUNC_SMPTE240M;
+		ctx->ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+		break;
+	case V4L2_COLORSPACE_BT2020:
+		ctx->xfer_func = V4L2_XFER_FUNC_709;
+		ctx->ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+		break;
+	default:
+		ctx->xfer_func = V4L2_XFER_FUNC_709;
+		ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
+		ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+		break;
+	}
+
+	return 0;
+}
+
+static int vpu_enc_set_color(struct vpu_ctx *ctx, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pix_mp;
+
+	if (!ctx || !f)
+		return -EINVAL;
+
+	pix_mp = &f->fmt.pix_mp;
+	if (vpu_enc_check_colorspace(pix_mp->colorspace))
+		vpu_enc_set_default_color(ctx, pix_mp->colorspace);
+	if (vpu_enc_check_xfer_func(pix_mp->xfer_func))
+		ctx->xfer_func = pix_mp->xfer_func;
+	if (vpu_enc_check_ycbcr_enc(pix_mp->ycbcr_enc))
+		ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+	if (vpu_enc_check_quantization(pix_mp->quantization))
+		ctx->quantization = pix_mp->quantization;
+
+	return 0;
+}
+
+static int set_yuv_queue_fmt(struct queue_data *q_data, struct v4l2_format *f)
+{
+	struct vpu_v4l2_fmt *fmt = NULL;
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	int i;
+
+	if (!q_data || !f)
+		return -EINVAL;
+
+	fmt = find_fmt_by_fourcc(q_data->supported_fmts, q_data->fmt_count,
+				pix_mp->pixelformat);
+	if (!fmt) {
+		vpu_err("unsupport yuv fmt : %s\n",
+				cvrt_fourcc_to_str(pix_mp->pixelformat));
+		return -EINVAL;
+	}
+
+	q_data->width = pix_mp->width;
+	q_data->height = pix_mp->height;
+	q_data->rect.left = 0;
+	q_data->rect.top = 0;
+	q_data->rect.width = pix_mp->width;
+	q_data->rect.height = pix_mp->height;
+	q_data->sizeimage[0] = pix_mp->width * pix_mp->height;
+	q_data->sizeimage[1] = pix_mp->width * pix_mp->height / 2;
+	pix_mp->num_planes = fmt->num_planes;
+	for (i = 0; i < pix_mp->num_planes; i++)
+		pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+
+	q_data->current_fmt = fmt;
+
+	vpu_enc_set_color(q_data->ctx, f);
+
+	return 0;
+}
+
+static u32 get_enc_minimum_sizeimage(u32 width, u32 height)
+{
+	const u32 THRESHOLD = 256 * 1024;
+	u32 sizeimage;
+
+	sizeimage = width * height / 2;
+	if (sizeimage < THRESHOLD)
+		sizeimage = THRESHOLD;
+
+	return sizeimage;
+}
+
+static int set_enc_queue_fmt(struct queue_data *q_data, struct v4l2_format *f)
+{
+	struct vpu_v4l2_fmt *fmt = NULL;
+	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+	u32 sizeimage;
+
+	if (!q_data || !f)
+		return -EINVAL;
+
+	fmt = find_fmt_by_fourcc(q_data->supported_fmts, q_data->fmt_count,
+				pix_mp->pixelformat);
+	if (!fmt) {
+		vpu_err("unsupport encode fmt : %s\n",
+				cvrt_fourcc_to_str(pix_mp->pixelformat));
+		return -EINVAL;
+	}
+
+	q_data->width = pix_mp->width;
+	q_data->height = pix_mp->height;
+	sizeimage = get_enc_minimum_sizeimage(pix_mp->width, pix_mp->height);
+	q_data->sizeimage[0] = max(sizeimage, pix_mp->plane_fmt[0].sizeimage);
+	pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+
+	q_data->current_fmt = fmt;
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_s_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f)
+{
+	struct vpu_ctx                  *ctx = v4l2_fh_to_ctx(fh);
+	int                             ret = 0;
+	struct queue_data               *q_data;
+	pMEDIAIP_ENC_PARAM  pEncParam;
+	struct vpu_attr *attr;
+
+	attr = get_vpu_ctx_attr(ctx);
+	pEncParam = &attr->param;
+	q_data = get_queue_by_v4l2_type(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+
+	ret = check_v4l2_fmt(ctx->dev, f);
+	if (ret)
+		return ret;
+
+	mutex_lock(&ctx->instance_mutex);
+	if (V4L2_TYPE_IS_OUTPUT(f->type))
+		ret = set_yuv_queue_fmt(q_data, f);
+	else
+		ret = set_enc_queue_fmt(q_data, f);
+	mutex_unlock(&ctx->instance_mutex);
+
+	f->fmt.pix_mp.colorspace = ctx->colorspace;
+	f->fmt.pix_mp.xfer_func = ctx->xfer_func;
+	f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
+	f->fmt.pix_mp.quantization = ctx->quantization;
+
+	vpu_dbg(LVL_FLOW, "[%d:%d] %s set fmt, %c%c%c%c %dx%d\n",
+			ctx->core_dev->id,
+			ctx->str_index,
+			V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
+			f->fmt.pix_mp.pixelformat,
+			f->fmt.pix_mp.pixelformat >> 8,
+			f->fmt.pix_mp.pixelformat >> 16,
+			f->fmt.pix_mp.pixelformat >> 24,
+			f->fmt.pix_mp.width,
+			f->fmt.pix_mp.height);
+	return ret;
+}
+
+static int vpu_enc_v4l2_ioctl_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_attr *attr = NULL;
+	pMEDIAIP_ENC_PARAM param = NULL;
+
+	if (!parm || !ctx)
+		return -EINVAL;
+
+	attr = get_vpu_ctx_attr(ctx);
+	param = &attr->param;
+
+	vpu_log_func();
+	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.capture.capturemode = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.capture.timeperframe.numerator = attr->fival.numerator;
+	parm->parm.capture.timeperframe.denominator = attr->fival.denominator;
+	parm->parm.capture.readbuffers = 0;
+
+	return 0;
+}
+
+static u32 __calc_coprime(u32 *a, u32 *b)
+{
+	int m = *a;
+	int n = *b;
+
+	if (m == 0)
+		return n;
+	if (n == 0)
+		return m;
+
+	while (n != 0) {
+		int tmp = m % n;
+
+		m = n;
+		n = tmp;
+	}
+	*a = (*a) / m;
+	*b = (*b) / m;
+
+	return m;
+}
+
+
+static int vpu_enc_v4l2_ioctl_s_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_attr *attr = NULL;
+	struct v4l2_fract fival;
+
+	if (!parm || !ctx)
+		return -EINVAL;
+
+	vpu_log_func();
+	attr = get_vpu_ctx_attr(ctx);
+
+	fival.numerator = parm->parm.capture.timeperframe.numerator;
+	fival.denominator = parm->parm.capture.timeperframe.denominator;
+	if (!fival.numerator || !fival.denominator)
+		return -EINVAL;
+
+	__calc_coprime(&fival.numerator, &fival.denominator);
+	mutex_lock(&ctx->instance_mutex);
+	attr->fival.numerator = fival.numerator;
+	attr->fival.denominator = fival.denominator;
+	attr->param.uFrameRate =
+		DIV_ROUND_CLOSEST(fival.denominator, fival.numerator);
+	mutex_unlock(&ctx->instance_mutex);
+	vpu_dbg(LVL_FLOW, "[%d:%d] %s set frame interval : %d / %d\n",
+			ctx->core_dev->id,
+			ctx->str_index,
+			V4L2_TYPE_IS_OUTPUT(parm->type) ? "OUTPUT" : "CAPTURE",
+			fival.numerator,
+			fival.denominator);
+
+	return 0;
+}
+
+static int vpu_enc_queue_expbuf(struct queue_data *queue,
+				struct v4l2_exportbuffer *buf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_expbuf(&queue->vb2_q, buf);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_reqbufs(struct queue_data *queue,
+				struct v4l2_requestbuffers *reqbuf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_reqbufs(&queue->vb2_q, reqbuf);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_querybuf(struct queue_data *queue,
+				struct v4l2_buffer *buf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_querybuf(&queue->vb2_q, buf);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_qbuf(struct queue_data *queue,
+				struct v4l2_buffer *buf)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+		ret = vb2_qbuf(&queue->vb2_q, queue->ctx->dev->v4l2_dev.mdev, buf);
+#else
+		ret = vb2_qbuf(&queue->vb2_q, buf);
+#endif
+	}
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_dqbuf(struct queue_data *queue,
+				struct v4l2_buffer *buf, bool nonblocking)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_dqbuf(&queue->vb2_q, buf, nonblocking);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_enable(struct queue_data *queue,
+				enum v4l2_buf_type type)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_streamon(&queue->vb2_q, type);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static void clear_queue(struct queue_data *queue)
+{
+	struct vpu_frame_info *frame;
+	struct vpu_frame_info *tmp;
+	struct vb2_data_req *p_data_req;
+	struct vb2_data_req *p_temp;
+	struct vb2_buffer *vb;
+
+	if (!queue)
+		return;
+
+	list_for_each_entry_safe(frame, tmp, &queue->frame_q, list) {
+		vpu_dbg(LVL_INFO, "drop frame\n");
+		put_frame_idle(frame);
+	}
+
+	list_for_each_entry_safe(frame, tmp, &queue->frame_idle, list)
+		dec_frame(frame);
+
+	list_for_each_entry_safe(p_data_req, p_temp, &queue->drv_q, list) {
+		vpu_dbg(LVL_DEBUG, "%s(%d) - list_del(%p)\n", __func__,
+				p_data_req->sequence, p_data_req);
+		list_del(&p_data_req->list);
+	}
+	list_for_each_entry(vb, &queue->vb2_q.queued_list, queued_entry) {
+		if (vb->state == VB2_BUF_STATE_ACTIVE)
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+	}
+
+	INIT_LIST_HEAD(&queue->drv_q);
+	INIT_LIST_HEAD(&queue->frame_q);
+	INIT_LIST_HEAD(&queue->frame_idle);
+}
+
+static int vpu_enc_queue_disable(struct queue_data *queue,
+				enum v4l2_buf_type type)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_streamoff(&queue->vb2_q, type);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_release(struct queue_data *queue)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited) {
+		clear_queue(queue);
+		vb2_queue_release(&queue->vb2_q);
+	}
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_queue_mmap(struct queue_data *queue,
+				struct vm_area_struct *vma)
+{
+	int ret = -EINVAL;
+
+	down(&queue->drv_q_lock);
+	if (queue->vb2_q_inited)
+		ret = vb2_mmap(&queue->vb2_q, vma);
+	up(&queue->drv_q_lock);
+
+	return ret;
+}
+
+static int vpu_enc_v4l2_ioctl_expbuf(struct file *file,
+		void *fh,
+		struct v4l2_exportbuffer *buf)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+
+	q_data = get_queue_by_v4l2_type(ctx, buf->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s\n", __func__, q_data->desc);
+
+	return vpu_enc_queue_expbuf(q_data, buf);
+}
+
+static int vpu_enc_v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub
+		)
+{
+	vpu_log_func();
+
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int vpu_enc_v4l2_ioctl_reqbufs(struct file *file,
+		void *fh,
+		struct v4l2_requestbuffers *reqbuf)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, reqbuf->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+	vpu_dbg(LVL_FLOW, "[%d:%d] %s reqbufs : %d\n",
+		ctx->core_dev->id,
+		ctx->str_index,
+		V4L2_TYPE_IS_OUTPUT(reqbuf->type) ? "OUTPUT" : "CATPURE",
+		reqbuf->count);
+
+	ret = vpu_enc_queue_reqbufs(q_data, reqbuf);
+
+	return ret;
+}
+
+static int vpu_enc_v4l2_ioctl_querybuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	unsigned int i;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, buf->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+
+	ret = vpu_enc_queue_querybuf(q_data, buf);
+	if (ret)
+		return ret;
+
+	if (buf->memory == V4L2_MEMORY_MMAP) {
+		if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+			for (i = 0; i < buf->length; i++)
+				buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+		} else
+			buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+	}
+
+	return ret;
+}
+
+static struct vb2_buffer *cvrt_v4l2_to_vb2_buffer(struct vb2_queue *vq,
+						struct v4l2_buffer *buf)
+{
+	if (!vq || !buf)
+		return NULL;
+
+	if (buf->index >= vq->num_buffers)
+		return NULL;
+
+	return vq->bufs[buf->index];
+}
+
+static u32 get_v4l2_plane_payload(struct v4l2_plane *plane)
+{
+	return plane->bytesused - plane->data_offset;
+}
+
+static void set_v4l2_plane_payload(struct v4l2_plane *plane, u32 size)
+{
+	plane->bytesused = plane->data_offset + size;
+}
+
+static int is_valid_output_mplane_buf(struct queue_data *q_data,
+					struct vpu_v4l2_fmt *fmt,
+					struct v4l2_buffer *buf)
+{
+	int i;
+
+	for (i = 0; i < fmt->num_planes; i++) {
+		u32 bytesused = get_v4l2_plane_payload(&buf->m.planes[i]);
+
+		if (!bytesused) {
+			set_v4l2_plane_payload(&buf->m.planes[i],
+						q_data->sizeimage[i]);
+			continue;
+		}
+		if (fmt->is_yuv && bytesused != q_data->sizeimage[i])
+			return 0;
+	}
+
+	return 1;
+}
+
+static int is_valid_output_buf(struct queue_data *q_data,
+				struct vpu_v4l2_fmt *fmt,
+				struct v4l2_buffer *buf)
+{
+	if (!buf->bytesused) {
+		buf->bytesused = q_data->sizeimage[0];
+		return 1;
+	}
+	if (fmt->is_yuv && buf->bytesused != q_data->sizeimage[0])
+		return 0;
+
+	return 1;
+}
+
+static int precheck_qbuf(struct queue_data *q_data, struct v4l2_buffer *buf)
+{
+	struct vb2_buffer *vb = NULL;
+	struct vpu_v4l2_fmt *fmt;
+	int ret;
+
+	if (!q_data || !buf)
+		return -EINVAL;
+
+	if (!q_data->current_fmt)
+		return -EINVAL;
+
+	vb = cvrt_v4l2_to_vb2_buffer(&q_data->vb2_q, buf);
+	if (!vb) {
+		vpu_err("invalid v4l2 buffer index:%d\n", buf->index);
+		return -EINVAL;
+	}
+	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+		vpu_err("invalid buffer state:%d\n", vb->state);
+		return -EINVAL;
+	}
+
+	if (!V4L2_TYPE_IS_OUTPUT(buf->type))
+		return 0;
+
+	fmt = q_data->current_fmt;
+	if (V4L2_TYPE_IS_MULTIPLANAR(buf->type))
+		ret = is_valid_output_mplane_buf(q_data, fmt, buf);
+	else
+		ret = is_valid_output_buf(q_data, fmt, buf);
+	if (!ret)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_qbuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, buf->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+
+	ret = precheck_qbuf(q_data, buf);
+	if (ret < 0)
+		return ret;
+
+	ret = vpu_enc_queue_qbuf(q_data, buf);
+	if (ret)
+		return ret;
+
+	if (V4L2_TYPE_IS_OUTPUT(buf->type)) {
+		mutex_lock(&ctx->dev->dev_mutex);
+		mutex_lock(&ctx->instance_mutex);
+		if (!test_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status))
+			set_bit(VPU_ENC_STATUS_DATA_READY, &ctx->status);
+		configure_codec(ctx);
+		mutex_unlock(&ctx->instance_mutex);
+		mutex_unlock(&ctx->dev->dev_mutex);
+		wait_for_start_done(ctx);
+
+		submit_input_and_encode(ctx);
+		count_yuv_input(ctx);
+	} else {
+		process_stream_output(ctx);
+	}
+
+	return ret;
+}
+
+static void notify_eos(struct vpu_ctx *ctx)
+{
+	const struct v4l2_event ev = {
+		.type = V4L2_EVENT_EOS
+	};
+
+	mutex_lock(&ctx->instance_mutex);
+	if (!test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status) &&
+		!test_and_set_bit(VPU_ENC_STATUS_EOS_SEND, &ctx->status)) {
+		v4l2_event_queue_fh(&ctx->fh, &ev);
+		vpu_dbg(LVL_FLOW, "[%d:%d] send eos event\n",
+				ctx->core_dev->id, ctx->str_index);
+	}
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+static int send_eos(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	if (!test_bit(VPU_ENC_STATUS_START_SEND, &ctx->status)) {
+		notify_eos(ctx);
+		return 0;
+	}
+
+	if (!test_and_set_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status)) {
+		reinit_completion(&ctx->stop_cmp);
+		vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_STREAM_STOP, 0, NULL);
+		vpu_dbg(LVL_FLOW, "[%d:%d] stop stream\n",
+				ctx->core_dev->id, ctx->str_index);
+	}
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_dqbuf(struct file *file,
+		void *fh,
+		struct v4l2_buffer *buf)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, buf->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+
+	ret = vpu_enc_queue_dqbuf(q_data, buf, file->f_flags & O_NONBLOCK);
+
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (!ret)
+			count_h264_output(ctx);
+	}
+
+	return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+		unsigned int table_size,
+		struct v4l2_format *f)
+{
+	unsigned int i;
+
+	for (i = 0; i < table_size; i++) {
+		if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+			return true;
+	}
+	return false;
+}
+
+static int vpu_enc_v4l2_ioctl_try_fmt(struct file *file,
+		void *fh,
+		struct v4l2_format *f)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+	struct queue_data *q_data;
+
+	q_data = get_queue_by_v4l2_type(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s\n", __func__, q_data->desc);
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		pix_mp->field = V4L2_FIELD_ANY;
+		pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+		if (!vpu_enc_check_colorspace(pix_mp->colorspace)) {
+			pix_mp->colorspace = ctx->colorspace;
+			pix_mp->xfer_func = ctx->xfer_func;
+			pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+			pix_mp->quantization = ctx->quantization;
+		} else {
+			if (!vpu_enc_check_xfer_func(pix_mp->xfer_func))
+				pix_mp->xfer_func = ctx->xfer_func;
+			if (!vpu_enc_check_ycbcr_enc(pix_mp->ycbcr_enc))
+				pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+			if (!vpu_enc_check_quantization(pix_mp->quantization))
+				pix_mp->quantization = ctx->quantization;
+		}
+	} else {
+		pix_mp->colorspace = ctx->colorspace;
+		pix_mp->xfer_func = ctx->xfer_func;
+		pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+		pix_mp->quantization = ctx->quantization;
+	}
+
+	if (!format_is_support(q_data->supported_fmts, q_data->fmt_count, f))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_g_selection(struct file *file, void *fh,
+					struct v4l2_selection *s)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *src = &ctx->q_data[V4L2_SRC];
+
+	if (s->target != V4L2_SEL_TGT_CROP && s->target != V4L2_SEL_TGT_COMPOSE)
+		return -EINVAL;
+
+	vpu_log_func();
+	s->r = src->rect;
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_s_selection(struct file *file, void *fh,
+					struct v4l2_selection *s)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *src = &ctx->q_data[V4L2_SRC];
+	struct vpu_dev *dev = ctx->dev;
+
+	if (s->target != V4L2_SEL_TGT_CROP && s->target != V4L2_SEL_TGT_COMPOSE)
+		return -EINVAL;
+
+	vpu_log_func();
+	src->rect.left = ALIGN(s->r.left, dev->supported_size.step_width);
+	src->rect.top = ALIGN(s->r.top, dev->supported_size.step_height);
+	src->rect.width = ALIGN(s->r.width, dev->supported_size.step_width);
+	src->rect.height = ALIGN(s->r.height, dev->supported_size.step_height);
+	valid_crop_info(src, &src->rect);
+
+	return 0;
+}
+
+static int response_stop_stream(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue;
+
+	if (!ctx)
+		return -EINVAL;
+
+	queue = &ctx->q_data[V4L2_SRC];
+
+	down(&queue->drv_q_lock);
+	if (!list_empty(&queue->drv_q))
+		goto exit;
+
+	if (!test_bit(VPU_ENC_FLAG_WRITEABLE, &queue->rw_flag))
+		goto exit;
+	if (test_and_clear_bit(VPU_ENC_STATUS_STOP_REQ, &ctx->status))
+		send_eos(ctx);
+exit:
+	up(&queue->drv_q_lock);
+
+	return 0;
+}
+
+static int request_eos(struct vpu_ctx *ctx)
+{
+	WARN_ON(!ctx);
+
+	vpu_dbg(LVL_FLOW, "[%d:%d] request eos\n",
+			ctx->core_dev->id, ctx->str_index);
+	set_bit(VPU_ENC_STATUS_STOP_REQ, &ctx->status);
+	response_stop_stream(ctx);
+
+	return 0;
+}
+
+static int set_core_force_release(struct core_device *core)
+{
+	int i;
+
+	if (!core)
+		return -EINVAL;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (!core->ctx[i])
+			continue;
+		set_bit(VPU_ENC_STATUS_FORCE_RELEASE, &core->ctx[i]->status);
+	}
+
+	return 0;
+}
+
+static void clear_start_status(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	clear_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status);
+	clear_bit(VPU_ENC_STATUS_START_SEND, &ctx->status);
+	clear_bit(VPU_ENC_STATUS_START_DONE, &ctx->status);
+}
+
+static void clear_stop_status(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	clear_bit(VPU_ENC_STATUS_STOP_REQ, &ctx->status);
+	clear_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status);
+	clear_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status);
+	clear_bit(VPU_ENC_STATUS_EOS_SEND, &ctx->status);
+}
+
+static void reset_core_on_hang(struct core_device *core)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < core->supported_instance_count; i++)
+		clear_start_status(core->ctx[i]);
+
+	ret = sw_reset_firmware(core, 1);
+	if (ret)
+		vpu_err("reset core[%d] on hang fail\n", core->id);
+}
+
+static int set_core_hang(struct core_device *core)
+{
+	core->hang = true;
+
+	if (reset_on_hang)
+		reset_core_on_hang(core);
+
+	return 0;
+}
+
+static void clear_core_hang(struct core_device *core)
+{
+	if (!core)
+		return;
+
+	core->hang = false;
+}
+
+static void wait_for_start_done(struct vpu_ctx *ctx)
+{
+	int ret;
+
+	WARN_ON(!ctx);
+
+	if (!test_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status))
+		return;
+	if (test_bit(VPU_ENC_STATUS_START_DONE, &ctx->status))
+		return;
+	ret = wait_for_completion_timeout(&ctx->start_cmp,
+					msecs_to_jiffies(300));
+	if (!ret && !test_bit(VPU_ENC_STATUS_START_DONE, &ctx->status))
+		vpu_err("wait for start done timeout\n");
+}
+
+static void wait_for_stop_done(struct vpu_ctx *ctx)
+{
+	int ret;
+
+	WARN_ON(!ctx);
+
+	if (!test_bit(VPU_ENC_STATUS_START_SEND, &ctx->status))
+		return;
+	if (test_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status))
+		return;
+
+	ret = wait_for_completion_timeout(&ctx->stop_cmp,
+						msecs_to_jiffies(500));
+	if (!ret && !test_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status))
+		vpu_err("wait for stop done timeout\n");
+}
+
+static int vpu_enc_v4l2_ioctl_encoder_cmd(struct file *file,
+		void *fh,
+		struct v4l2_encoder_cmd *cmd
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+	vpu_dbg(LVL_FUNC, "%s(), cmd = %d, (%d, %d)\n", __func__, cmd->cmd,
+			ctx->core_dev->id, ctx->str_index);
+	switch (cmd->cmd) {
+	case V4L2_ENC_CMD_START:
+		vpu_dbg(LVL_FLOW, "[%d:%d] start encoder\n",
+				ctx->core_dev->id, ctx->str_index);
+		vb2_clear_last_buffer_dequeued(&ctx->q_data[V4L2_DST].vb2_q);
+		break;
+	case V4L2_ENC_CMD_STOP:
+		vpu_dbg(LVL_FLOW, "[%d:%d] stop encoder\n",
+				ctx->core_dev->id, ctx->str_index);
+		request_eos(ctx);
+		break;
+	case V4L2_ENC_CMD_PAUSE:
+		vpu_dbg(LVL_FLOW, "[%d:%d] pause encoder\n",
+				ctx->core_dev->id, ctx->str_index);
+		break;
+	case V4L2_ENC_CMD_RESUME:
+		vpu_dbg(LVL_FLOW, "[%d:%d] resume encoder\n",
+				ctx->core_dev->id, ctx->str_index);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_streamon(struct file *file,
+		void *fh,
+		enum v4l2_buf_type i
+		)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct vpu_attr *attr;
+	struct queue_data *q_data;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, i);
+	if (!q_data)
+		return -EINVAL;
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+	vpu_dbg(LVL_FLOW, "[%d:%d] %s streamon\n",
+			ctx->core_dev->id, ctx->str_index,
+			V4L2_TYPE_IS_OUTPUT(i) ? "OUTPUT" : "CAPTURE");
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (attr) {
+		attr->ts_start[V4L2_SRC] = 0;
+		attr->ts_start[V4L2_DST] = 0;
+	}
+
+	ret = vpu_enc_queue_enable(q_data, i);
+	if (ret)
+		return ret;
+
+	if (V4L2_TYPE_IS_OUTPUT(i)) {
+		mutex_lock(&ctx->dev->dev_mutex);
+		mutex_lock(&ctx->instance_mutex);
+		set_bit(VPU_ENC_STATUS_OUTPUT_READY, &ctx->status);
+		configure_codec(ctx);
+		mutex_unlock(&ctx->instance_mutex);
+		mutex_unlock(&ctx->dev->dev_mutex);
+		wait_for_start_done(ctx);
+	}
+
+	return 0;
+}
+
+static int vpu_enc_v4l2_ioctl_streamoff(struct file *file,
+		void *fh,
+		enum v4l2_buf_type i)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+	struct queue_data *q_data;
+	int ret;
+
+	q_data = get_queue_by_v4l2_type(ctx, i);
+	if (!q_data)
+		return -EINVAL;
+
+	vpu_dbg(LVL_FUNC, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			ctx->core_dev->id, ctx->str_index);
+	vpu_dbg(LVL_FLOW, "[%d:%d] %s streamoff\n",
+			ctx->core_dev->id, ctx->str_index,
+			V4L2_TYPE_IS_OUTPUT(i) ? "OUTPUT" : "CAPTURE");
+
+	request_eos(ctx);
+	wait_for_stop_done(ctx);
+
+	ret = vpu_enc_queue_disable(q_data, i);
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops vpu_enc_v4l2_ioctl_ops = {
+	.vidioc_querycap                = vpu_enc_v4l2_ioctl_querycap,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	.vidioc_enum_fmt_vid_cap	= vpu_enc_v4l2_ioctl_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out	= vpu_enc_v4l2_ioctl_enum_fmt_vid_out,
+#else
+	.vidioc_enum_fmt_vid_cap_mplane	= vpu_enc_v4l2_ioctl_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out_mplane	= vpu_enc_v4l2_ioctl_enum_fmt_vid_out,
+#endif
+	.vidioc_enum_framesizes		= vpu_enc_v4l2_ioctl_enum_framesizes,
+	.vidioc_enum_frameintervals	= vpu_enc_v4l2_ioctl_enum_frameintervals,
+	.vidioc_g_fmt_vid_cap_mplane    = vpu_enc_v4l2_ioctl_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane    = vpu_enc_v4l2_ioctl_g_fmt,
+	.vidioc_try_fmt_vid_cap_mplane  = vpu_enc_v4l2_ioctl_try_fmt,
+	.vidioc_try_fmt_vid_out_mplane  = vpu_enc_v4l2_ioctl_try_fmt,
+	.vidioc_s_fmt_vid_cap_mplane    = vpu_enc_v4l2_ioctl_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane    = vpu_enc_v4l2_ioctl_s_fmt,
+	.vidioc_g_parm			= vpu_enc_v4l2_ioctl_g_parm,
+	.vidioc_s_parm			= vpu_enc_v4l2_ioctl_s_parm,
+	.vidioc_expbuf                  = vpu_enc_v4l2_ioctl_expbuf,
+	.vidioc_g_selection		= vpu_enc_v4l2_ioctl_g_selection,
+	.vidioc_s_selection		= vpu_enc_v4l2_ioctl_s_selection,
+	.vidioc_encoder_cmd             = vpu_enc_v4l2_ioctl_encoder_cmd,
+	.vidioc_subscribe_event         = vpu_enc_v4l2_ioctl_subscribe_event,
+	.vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+	.vidioc_reqbufs                 = vpu_enc_v4l2_ioctl_reqbufs,
+	.vidioc_querybuf                = vpu_enc_v4l2_ioctl_querybuf,
+	.vidioc_qbuf                    = vpu_enc_v4l2_ioctl_qbuf,
+	.vidioc_dqbuf                   = vpu_enc_v4l2_ioctl_dqbuf,
+	.vidioc_streamon                = vpu_enc_v4l2_ioctl_streamon,
+	.vidioc_streamoff               = vpu_enc_v4l2_ioctl_streamoff,
+};
+
+static void vpu_core_send_cmd(struct core_device *core, u32 idx,
+				u32 cmdid, u32 cmdnum, u32 *local_cmddata)
+{
+	WARN_ON(!core || idx >= VID_API_NUM_STREAMS);
+
+	vpu_log_cmd(cmdid, idx);
+	count_cmd(&core->attr[idx], cmdid);
+
+	mutex_lock(&core->cmd_mutex);
+	rpc_send_cmd_buf_encoder(&core->shared_mem, idx, cmdid, cmdnum,
+				 local_cmddata);
+	mb();
+	vpu_enc_mu_send_msg(core, COMMAND, 0xffff);
+	mutex_unlock(&core->cmd_mutex);
+}
+
+static void vpu_ctx_send_cmd(struct vpu_ctx *ctx, uint32_t cmdid,
+				uint32_t cmdnum, uint32_t *local_cmddata)
+{
+	vpu_core_send_cmd(ctx->core_dev, ctx->str_index,
+				cmdid, cmdnum, local_cmddata);
+}
+
+static void set_core_fw_status(struct core_device *core, bool status)
+{
+	core->fw_is_ready = status;
+}
+
+static int reset_vpu_core_dev(struct core_device *core_dev)
+{
+	if (!core_dev)
+		return -EINVAL;
+
+	set_core_fw_status(core_dev, false);
+	core_dev->firmware_started = false;
+
+	return 0;
+}
+
+static int sw_reset_firmware(struct core_device *core, int resume)
+{
+	int ret = 0;
+
+	WARN_ON(!core);
+
+	vpu_dbg(LVL_INFO, "core[%d] sw reset firmware\n", core->id);
+
+	kfifo_reset(&core->mu_msg_fifo);
+
+	reinit_completion(&core->boot_cmp);
+	vpu_core_send_cmd(core, 0, GTB_ENC_CMD_FIRM_RESET, 0, NULL);
+	ret = wait_for_boot_done(core, resume);
+	if (ret) {
+		set_core_hang(core);
+		return -EINVAL;
+	}
+	core->reset_times++;
+
+	return 0;
+}
+
+static int process_core_hang(struct core_device *core)
+{
+	int ret;
+	int i;
+	int instance_count = 0;
+
+	if (!core->hang)
+		return 0;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (core->ctx[i])
+			instance_count++;
+	}
+
+	if (instance_count)
+		return -EBUSY;
+
+	ret = sw_reset_firmware(core, 0);
+	if (ret)
+		return ret;
+
+	clear_core_hang(core);
+	return 0;
+}
+
+static void show_codec_configure(pMEDIAIP_ENC_PARAM param,
+		pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam)
+{
+	if (!param)
+		return;
+
+	vpu_dbg(LVL_INFO, "Encoder Parameter:\n");
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Codec Mode", param->eCodecMode);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Profile", param->eProfile);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Level", param->uLevel);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Mem Phys Addr", param->tEncMemDesc.uMemPhysAddr);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Mem Virt Addr", param->tEncMemDesc.uMemVirtAddr);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Mem Size", param->tEncMemDesc.uMemSize);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d(%d / %d)\n",
+			"Frame Rate", param->uFrameRate,
+			pEncExpertModeParam->Config.frame_rate_num,
+			pEncExpertModeParam->Config.frame_rate_den);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Stride", param->uSrcStride);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Width", param->uSrcWidth);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Height", param->uSrcHeight);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Offset x", param->uSrcOffset_x);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Offset y", param->uSrcOffset_y);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Crop Width", param->uSrcCropWidth);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Source Crop Height", param->uSrcCropHeight);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Out Width", param->uOutWidth);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Out Height", param->uOutHeight);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"I Frame Interval", param->uIFrameInterval);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"GOP Length", param->uGopBLength);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Low Latency Mode", param->uLowLatencyMode);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Bitrate Mode", param->eBitRateMode);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Target Bitrate", param->uTargetBitrate);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Min Bitrate", param->uMinBitRate);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"Max Bitrate", param->uMaxBitRate);
+	vpu_dbg(LVL_INFO, "\t%20s:%16d\n",
+			"QP", param->uInitSliceQP);
+}
+
+static void show_firmware_version(struct core_device *core_dev,
+				unsigned int level)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface;
+
+	if (!core_dev)
+		return;
+
+	pSharedInterface = core_dev->shared_mem.pSharedInterface;
+
+	vpu_dbg(level, "vpu encoder core[%d] firmware version is %d.%d.%d\n",
+			core_dev->id,
+			(pSharedInterface->FWVersion & 0x00ff0000) >> 16,
+			(pSharedInterface->FWVersion & 0x0000ff00) >> 8,
+			pSharedInterface->FWVersion & 0x000000ff);
+}
+
+static void update_encode_size(struct vpu_ctx *ctx)
+{
+	struct queue_data *src = NULL;
+	struct queue_data *dst = NULL;
+	struct vpu_attr *attr;
+	pMEDIAIP_ENC_PARAM  pEncParam;
+
+	if (!ctx)
+		return;
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	src = &ctx->q_data[V4L2_SRC];
+	dst = &ctx->q_data[V4L2_DST];
+	pEncParam = &attr->param;
+
+	pEncParam->uSrcStride           = src->width;
+	pEncParam->uSrcWidth            = src->width;
+	pEncParam->uSrcHeight           = src->height;
+	pEncParam->uSrcOffset_x         = src->rect.left;
+	pEncParam->uSrcOffset_y         = src->rect.top;
+	pEncParam->uSrcCropWidth        = src->rect.width;
+	pEncParam->uSrcCropHeight       = src->rect.height;
+	pEncParam->uOutWidth            = min(dst->width, src->rect.width);
+	pEncParam->uOutHeight           = min(dst->height, src->rect.height);
+}
+
+static void init_ctx_seq_info(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	ctx->sequence = 0;
+	ctx->timestamp = VPU_ENC_INVALID_TIMESTAMP;
+}
+
+static void fill_ctx_seq(struct vpu_ctx *ctx, struct vb2_data_req *p_data_req)
+{
+	WARN_ON(!ctx || !p_data_req);
+
+	p_data_req->sequence = ctx->sequence++;
+	if (ctx->timestamp < (s64)p_data_req->vb2_buf->timestamp)
+		ctx->timestamp = p_data_req->vb2_buf->timestamp;
+}
+
+static void fill_vb_sequence(struct vb2_buffer *vb, u32 sequence)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	vbuf->sequence = sequence;
+}
+
+static void set_vb_flags(struct vb2_buffer *vb, u32 buffer_flags)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	vbuf->flags |= buffer_flags;
+}
+
+static struct vb2_data_req *find_vb2_data_by_sequence(struct queue_data *queue,
+							u32 sequence)
+{
+	int i;
+
+	for (i = 0; i < queue->vb2_q.num_buffers; i++) {
+		if (!queue->vb2_reqs[i].vb2_buf)
+			continue;
+		if (queue->vb2_reqs[i].sequence == sequence)
+			return &queue->vb2_reqs[i];
+	}
+
+	return NULL;
+}
+
+static void update_stream_desc_rptr(struct vpu_ctx *ctx, u32 rptr)
+{
+	pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc;
+
+	stream_buffer_desc = get_rpc_stream_buffer_desc(ctx);
+	stream_buffer_desc->rptr = rptr;
+}
+
+static int do_configure_codec(struct vpu_ctx *ctx)
+{
+	pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc = NULL;
+	pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam = NULL;
+	pMEDIAIP_ENC_PARAM enc_param;
+	struct vpu_attr *attr;
+
+	if (!ctx || !ctx->core_dev)
+		return -EINVAL;
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return -EINVAL;
+
+	if (vpu_enc_alloc_stream(ctx))
+		return -ENOMEM;
+
+	update_encode_size(ctx);
+
+	enc_param = get_rpc_enc_param(ctx);
+	pEncStrBuffDesc = get_rpc_stream_buffer_desc(ctx);
+
+	pEncStrBuffDesc->start = ctx->encoder_stream.phy_addr;
+	pEncStrBuffDesc->wptr = pEncStrBuffDesc->start;
+	pEncStrBuffDesc->rptr = pEncStrBuffDesc->start;
+	pEncStrBuffDesc->end = ctx->encoder_stream.phy_addr +
+				ctx->encoder_stream.size;
+
+	vpu_dbg(LVL_DEBUG,
+		"pEncStrBuffDesc:start=%x, wptr=0x%x, rptr=%x, end=%x\n",
+		pEncStrBuffDesc->start,
+		pEncStrBuffDesc->wptr,
+		pEncStrBuffDesc->rptr,
+		pEncStrBuffDesc->end);
+
+	pEncExpertModeParam = get_rpc_expert_mode_param(ctx);
+	pEncExpertModeParam->Calib.mem_chunk_phys_addr = 0;
+	pEncExpertModeParam->Calib.mem_chunk_virt_addr = 0;
+	pEncExpertModeParam->Calib.mem_chunk_size = 0;
+	pEncExpertModeParam->Calib.cb_base = ctx->encoder_stream.phy_addr;
+	pEncExpertModeParam->Calib.cb_size = ctx->encoder_stream.size;
+
+	reinit_completion(&ctx->start_cmp);
+	show_firmware_version(ctx->core_dev, LVL_INFO);
+	clear_stop_status(ctx);
+	memcpy(enc_param, &attr->param, sizeof(attr->param));
+	if (!enc_param->uGopBLength)
+		enc_param->uLowLatencyMode = 1;
+	vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_CONFIGURE_CODEC, 0, NULL);
+
+	show_codec_configure(enc_param, pEncExpertModeParam);
+	vpu_dbg(LVL_FLOW, "[%d:%d] configure codec\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	return 0;
+}
+
+static int check_vpu_ctx_is_ready(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return false;
+
+	if (!test_bit(VPU_ENC_STATUS_OUTPUT_READY, &ctx->status))
+		return false;
+	if (!test_bit(VPU_ENC_STATUS_DATA_READY, &ctx->status))
+		return false;
+
+	return true;
+}
+
+static bool vpu_enc_check_ctx_is_alive(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return false;
+	if (test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		return false;
+	if (ctx->ctx_released)
+		return false;
+	if (!ctx->core_dev)
+		return false;
+	if (ctx->str_index >= ctx->core_dev->supported_instance_count)
+		return false;
+	if (ctx != ctx->core_dev->ctx[ctx->str_index])
+		return false;
+	return true;
+}
+
+static int configure_codec(struct vpu_ctx *ctx)
+{
+	if (!vpu_enc_check_ctx_is_alive(ctx))
+		return -EINVAL;
+
+	if (!check_vpu_ctx_is_ready(ctx))
+		return 0;
+
+	if (ctx->core_dev->snapshot)
+		return 0;
+
+	if (test_bit(VPU_ENC_STATUS_SNAPSHOT, &ctx->status))
+		return 0;
+
+	if (!test_and_set_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status)) {
+		do_configure_codec(ctx);
+		clear_bit(VPU_ENC_STATUS_OUTPUT_READY, &ctx->status);
+		clear_bit(VPU_ENC_STATUS_DATA_READY, &ctx->status);
+	}
+
+	return 0;
+}
+
+static void dump_vb2_data(struct vb2_buffer *vb)
+{
+#ifdef DUMP_DATA
+	const int DATA_NUM = 10;
+	char *read_data;
+	u_int32 read_idx;
+	char data_str[1024];
+	int num = 0;
+
+	if (!vb)
+		return;
+
+	read_data = vb2_plane_vaddr(vb, 0);
+	num = scnprintf(data_str, sizeof(data_str),
+			"transfer data from virt 0x%p: ", read_data);
+	for (read_idx = 0; read_idx < DATA_NUM; read_idx++)
+		num += scnprintf(data_str + num, sizeof(data_str) - num,
+				" 0x%x", read_data[read_idx]);
+
+	vpu_dbg(LVL_DEBUG, "%s\n", data_str);
+#endif
+}
+
+static u32 get_vb2_plane_phy_addr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+	dma_addr_t *dma_addr;
+
+	dma_addr = vb2_plane_cookie(vb, plane_no);
+	return *dma_addr + vb->planes[plane_no].data_offset;
+}
+
+static void record_start_time(struct vpu_ctx *ctx, enum QUEUE_TYPE type)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	struct timespec64 ts;
+
+	if (!attr)
+		return;
+
+	if (attr->ts_start[type])
+		return;
+
+	ktime_get_raw_ts64(&ts);
+	attr->ts_start[type] = ts.tv_sec * MSEC_PER_SEC +
+				ts.tv_nsec / NSEC_PER_MSEC;
+}
+
+static int update_encode_param(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr;
+	pMEDIAIP_ENC_PARAM enc_param;
+	pMEDIAIP_ENC_EXPERT_MODE_PARAM expert;
+	bool change = false;
+
+	attr = get_vpu_ctx_attr(ctx);
+	enc_param = get_rpc_enc_param(ctx);
+	expert = get_rpc_expert_mode_param(ctx);
+
+	if (enc_param->eBitRateMode == MEDIAIP_ENC_BITRATECONTROLMODE_CBR &&
+	    attr->param.eBitRateMode == enc_param->eBitRateMode &&
+	    attr->param.uTargetBitrate != enc_param->uTargetBitrate) {
+		vpu_dbg(LVL_CTRL, "[%d] bitrate %d -> %d (kbps)\n",
+				ctx->str_index,
+				enc_param->uTargetBitrate,
+				attr->param.uTargetBitrate);
+		expert->Static.rate_control_bitrate =
+			enc_param->uTargetBitrate = attr->param.uTargetBitrate;
+		change = true;
+	}
+
+	if (!change)
+		return 0;
+
+	vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_PARAMETER_UPD, 0, NULL);
+	return 0;
+}
+
+static bool update_yuv_addr(struct vpu_ctx *ctx, s64 *timestamp)
+{
+	bool bGotAFrame = FALSE;
+
+	struct vb2_data_req *p_data_req;
+	struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+	pMEDIAIP_ENC_YUV_BUFFER_DESC desc;
+
+	desc = get_rpc_yuv_buffer_desc(ctx);
+
+	if (list_empty(&This->drv_q))
+		return bGotAFrame;
+
+	p_data_req = list_first_entry(&This->drv_q, typeof(*p_data_req), list);
+
+	dump_vb2_data(p_data_req->vb2_buf);
+
+	desc->uLumaBase = get_vb2_plane_phy_addr(p_data_req->vb2_buf, 0);
+	desc->uChromaBase = get_vb2_plane_phy_addr(p_data_req->vb2_buf, 1);
+
+	if (desc->uLumaBase != 0)
+		bGotAFrame = TRUE;
+
+	update_encode_param(ctx);
+	/*
+	 * keeps increasing,
+	 * so just a frame input count rather than a Frame buffer ID
+	 */
+	desc->uFrameID = p_data_req->sequence;
+	if (test_and_clear_bit(VPU_ENC_STATUS_KEY_FRAME, &ctx->status))
+		desc->uKeyFrame = 1;
+	else
+		desc->uKeyFrame = 0;
+	list_del(&p_data_req->list);
+	if (timestamp)
+		*timestamp = p_data_req->vb2_buf->timestamp;
+
+	return bGotAFrame;
+}
+
+static void get_kmp_next(const u8 *p, int *next, int size)
+{
+	int k = -1;
+	int j = 0;
+
+	next[0] = -1;
+	while (j < size - 1) {
+		if (k == -1 || p[j] == p[k]) {
+			++k;
+			++j;
+			next[j] = k;
+		} else {
+			k = next[k];
+		}
+	}
+}
+
+static int kmp_search(u8 *s, int s_len, const u8 *p, int p_len, int *next)
+{
+	int i = 0;
+	int j = 0;
+
+	while (i < s_len && j < p_len) {
+		if (j == -1 || s[i] == p[j]) {
+			i++;
+			j++;
+		} else {
+			j = next[j];
+		}
+	}
+	if (j == p_len)
+		return i - j;
+	else
+		return -1;
+}
+
+static int get_stuff_data_size(u8 *data, int size)
+{
+	const u8 pattern[] = VPU_STRM_END_PATTERN;
+	int next[] = VPU_STRM_END_PATTERN;
+	int index;
+
+	if (size < ARRAY_SIZE(pattern))
+		return 0;
+
+	get_kmp_next(pattern, next, ARRAY_SIZE(pattern));
+	index =  kmp_search(data, size, pattern, ARRAY_SIZE(pattern), next);
+	if (index < 0)
+		return 0;
+	vpu_dbg(LVL_DEBUG, "find end_of_stream nal\n");
+	return size - index;
+}
+
+static void count_strip_info(struct vpu_strip_info *info, u32 bytes)
+{
+	if (!info)
+		return;
+
+	info->count++;
+	info->total += bytes;
+	if (info->max < bytes)
+		info->max = bytes;
+}
+
+static void strip_stuff_data_on_tail(struct vpu_ctx *ctx, struct vb2_buffer *vb)
+{
+	u8 *ptr = vb2_plane_vaddr(vb, 0);
+	unsigned long bytesused = vb2_get_plane_payload(vb, 0);
+	int count = VPU_TAIL_SERACH_SIZE;
+	int stuff_size;
+
+	if (count > bytesused)
+		count = bytesused;
+
+	if (!count)
+		return;
+
+	stuff_size = get_stuff_data_size(ptr + bytesused - count, count);
+	if (stuff_size) {
+		struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+		if (attr)
+			count_strip_info(&attr->statistic.strip_sts.eos,
+					stuff_size);
+
+		vpu_dbg(LVL_DEBUG, "strip %d bytes stuff data\n", stuff_size);
+		vb2_set_plane_payload(vb, 0, bytesused - stuff_size);
+	}
+}
+
+static int check_enc_rw_flag(int flag)
+{
+	int ret = -EINVAL;
+
+	switch (flag) {
+	case VPU_ENC_FLAG_WRITEABLE:
+	case VPU_ENC_FLAG_READABLE:
+		ret = 0;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static void set_queue_rw_flag(struct queue_data *queue, int flag)
+{
+	if (!queue)
+		return;
+
+	if (check_enc_rw_flag(flag))
+		return;
+
+	set_bit(flag, &queue->rw_flag);
+}
+
+static void clear_queue_rw_flag(struct queue_data *queue, int flag)
+{
+	if (!queue)
+		return;
+
+	if (check_enc_rw_flag(flag))
+		return;
+
+	clear_bit(flag, &queue->rw_flag);
+}
+
+u32 get_free_space(struct vpu_ctx *ctx)
+{
+	pBUFFER_DESCRIPTOR_TYPE desc = get_rpc_stream_buffer_desc(ctx);
+	u32 start = get_ptr(desc->start);
+	u32 end = get_ptr(desc->end);
+	u32 wptr = get_ptr(desc->wptr);
+	u32 rptr = get_ptr(desc->rptr);
+
+	if (rptr > wptr)
+		return (rptr - wptr);
+	else if (rptr < wptr)
+		return (end - start + rptr - wptr);
+	else
+		return (end - start);
+
+}
+
+bool check_stream_buffer_for_coded_picture(struct vpu_ctx *ctx)
+{
+	if (get_free_space(ctx) < ctx->cpb_size)
+		return false;
+
+	return true;
+}
+
+static int submit_input_and_encode(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue;
+	s64 timestamp = -1;
+
+	if (!ctx)
+		return -EINVAL;
+
+	queue = &ctx->q_data[V4L2_SRC];
+
+	down(&queue->drv_q_lock);
+
+	if (!test_bit(VPU_ENC_FLAG_WRITEABLE, &queue->rw_flag))
+		goto exit;
+
+	if (list_empty(&queue->drv_q))
+		goto exit;
+
+	if (!check_stream_buffer_for_coded_picture(ctx))
+		goto exit;
+
+	if (test_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status))
+		goto exit;
+	if (!test_bit(VPU_ENC_STATUS_START_DONE, &ctx->status))
+		goto exit;
+
+	if (update_yuv_addr(ctx, &timestamp)) {
+		u32 data[2];
+
+		if (timestamp < 0) {
+			data[0] = -1;
+			data[1] = 0;
+		} else {
+			data[0] = timestamp / NSEC_PER_SEC;
+			data[1] = timestamp % NSEC_PER_SEC;
+		}
+		vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_FRAME_ENCODE, 2, data);
+		clear_queue_rw_flag(queue, VPU_ENC_FLAG_WRITEABLE);
+		record_start_time(ctx, V4L2_SRC);
+	}
+exit:
+	up(&queue->drv_q_lock);
+
+	return 0;
+}
+
+static void add_rptr(struct vpu_frame_info *frame, u32 length)
+{
+	WARN_ON(!frame);
+
+	frame->rptr += length;
+	if (frame->rptr >= frame->end)
+		frame->rptr -= (frame->end - frame->start);
+}
+
+static void report_frame_type(struct vb2_data_req *p_data_req,
+				struct vpu_frame_info *frame)
+{
+	WARN_ON(!p_data_req || !frame);
+
+	switch (frame->info.ePicType) {
+	case MEDIAIP_ENC_PIC_TYPE_IDR_FRAME:
+	case MEDIAIP_ENC_PIC_TYPE_I_FRAME:
+		p_data_req->buffer_flags = V4L2_BUF_FLAG_KEYFRAME;
+		break;
+	case MEDIAIP_ENC_PIC_TYPE_P_FRAME:
+		p_data_req->buffer_flags = V4L2_BUF_FLAG_PFRAME;
+		break;
+	case MEDIAIP_ENC_PIC_TYPE_B_FRAME:
+		p_data_req->buffer_flags = V4L2_BUF_FLAG_BFRAME;
+		break;
+	default:
+		break;
+	}
+}
+
+static u32 calc_frame_length(struct vpu_frame_info *frame)
+{
+	u32 length;
+	u32 buffer_size;
+
+	WARN_ON(!frame);
+
+	if (frame->eos)
+		return 0;
+
+	buffer_size = frame->end - frame->start;
+	if (!buffer_size)
+		return 0;
+
+	length = (buffer_size + frame->wptr - frame->rptr) % buffer_size;
+
+	return length;
+}
+
+static u32 get_ptr(u32 ptr)
+{
+	return (ptr | 0x80000000);
+}
+
+static void *get_rptr_virt(struct vpu_ctx *ctx, struct vpu_frame_info *frame)
+{
+	WARN_ON(!ctx || !frame);
+
+	return ctx->encoder_stream.virt_addr + frame->rptr - frame->start;
+}
+
+static int find_nal_begin(u8 *data, u32 size)
+{
+	const u8 pattern[] = VPU_STRM_BEGIN_PATTERN;
+	int next[] = VPU_STRM_BEGIN_PATTERN;
+	u32 len;
+	int index;
+
+	len = ARRAY_SIZE(pattern);
+	get_kmp_next(pattern, next, len);
+	index = kmp_search(data, size, pattern, len, next);
+	if (index > 0 && data[index - 1] == 0)
+		index--;
+
+	return index;
+}
+
+static int find_frame_start_and_skip(struct vpu_ctx *ctx,
+			struct vpu_frame_info *frame, int skip)
+{
+	u32 length;
+	u32 bytesskiped = 0;
+	u8 *data = get_rptr_virt(ctx, frame);
+	int index;
+
+	length = frame->bytesleft;
+	if (frame->rptr + length <= frame->end) {
+		index = find_nal_begin(data, length);
+		if (index >= 0)
+			bytesskiped += index;
+		else
+			bytesskiped += length;
+	} else {
+		u32 size = frame->end - frame->rptr;
+
+		index = find_nal_begin(data, size);
+		if (index >= 0) {
+			bytesskiped += index;
+		} else {
+			bytesskiped += size;
+
+			data = ctx->encoder_stream.virt_addr;
+			size = length - size;
+			index = find_nal_begin(data, size);
+			if (index >= 0)
+				bytesskiped += index;
+			else
+				bytesskiped += size;
+		}
+	}
+
+	if (skip && bytesskiped) {
+		add_rptr(frame, bytesskiped);
+		frame->bytesleft -= bytesskiped;
+	}
+
+	return bytesskiped;
+}
+
+static int transfer_stream_output(struct vpu_ctx *ctx,
+					struct vpu_frame_info *frame,
+					struct vb2_data_req *p_data_req)
+{
+	struct vb2_buffer *vb = NULL;
+	u32 length;
+	void *pdst;
+
+	WARN_ON(!ctx || !frame || !p_data_req);
+
+	length = frame->bytesleft;
+
+	vb = p_data_req->vb2_buf;
+	if (length > vb->planes[0].length)
+		length = vb->planes[0].length;
+	vb2_set_plane_payload(vb, 0, length);
+
+	pdst = vb2_plane_vaddr(vb, 0);
+	if (frame->rptr + length <= frame->end) {
+		memcpy(pdst, get_rptr_virt(ctx, frame), length);
+		frame->bytesleft -= length;
+		add_rptr(frame, length);
+	} else {
+		u32 offset = frame->end - frame->rptr;
+
+		memcpy(pdst, get_rptr_virt(ctx, frame), offset);
+		frame->bytesleft -= offset;
+		add_rptr(frame, offset);
+		length -= offset;
+		memcpy(pdst + offset, get_rptr_virt(ctx, frame), length);
+		frame->bytesleft -= length;
+		add_rptr(frame, length);
+	}
+	report_frame_type(p_data_req, frame);
+	if (frame->bytesleft)
+		return 0;
+
+	strip_stuff_data_on_tail(ctx, p_data_req->vb2_buf);
+
+	return 0;
+}
+
+static int append_empty_end_frame(struct vb2_data_req *p_data_req)
+{
+	struct vb2_buffer *vb = NULL;
+	const u8 pattern[] = VPU_STRM_END_PATTERN;
+	void *pdst;
+
+	WARN_ON(!p_data_req);
+
+	vb = p_data_req->vb2_buf;
+	pdst = vb2_plane_vaddr(vb, 0);
+	memcpy(pdst, pattern, ARRAY_SIZE(pattern));
+
+	vb2_set_plane_payload(vb, 0, ARRAY_SIZE(pattern));
+	p_data_req->buffer_flags = V4L2_BUF_FLAG_LAST;
+
+	vpu_dbg(LVL_INFO, "append the last frame\n");
+
+	return 0;
+}
+
+static s64 calculate_timestamp_for_eos(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = NULL;
+	struct v4l2_fract *fival;
+	s64 timestamp;
+	u64 delta = 0;
+
+	timestamp = ctx->timestamp;
+	attr = get_vpu_ctx_attr(ctx);
+	fival = &attr->fival;
+	if (ctx->timestamp != VPU_ENC_INVALID_TIMESTAMP && fival->denominator) {
+		delta = NSEC_PER_SEC * fival->numerator / fival->denominator;
+		timestamp += delta;
+	}
+
+	vpu_dbg(LVL_INFO, "[%d]eos ts : %lld, delta = %lld, %lld, %d / %d\n",
+			ctx->str_index,
+			timestamp, delta, ctx->timestamp,
+			fival->numerator, fival->denominator);
+	return timestamp;
+}
+
+static bool is_valid_frame_read_pos(u32 ptr, struct vpu_frame_info *frame)
+{
+	if (ptr < frame->start || ptr >= frame->end)
+		return false;
+	if (ptr >= frame->rptr && ptr < frame->wptr)
+		return true;
+	if (frame->rptr > frame->wptr) {
+		if (ptr >= frame->rptr || ptr < frame->wptr)
+			return true;
+	}
+
+	return false;
+}
+static int precheck_frame(struct vpu_ctx *ctx, struct vpu_frame_info *frame)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	u32 length;
+	int bytesskiped;
+	u32 rptr;
+
+	if (frame->eos)
+		return 0;
+	if (!frame->is_start)
+		return 0;
+
+	add_rptr(frame, 0);
+	frame->is_start = false;
+	rptr = get_ptr(frame->info.uStrBuffWrPtr);
+	if (rptr == frame->end)
+		rptr = frame->start;
+
+	if (is_valid_frame_read_pos(rptr, frame)) {
+		if (rptr != frame->rptr) {
+			vpu_dbg(LVL_DEBUG, "frame skip %d bytes\n",
+					rptr - frame->rptr);
+			count_strip_info(&attr->statistic.strip_sts.fw,
+					rptr - frame->rptr);
+		}
+		frame->rptr = rptr;
+	} else {
+		vpu_err("[%ld]wrong uStrBuffWrPtr:0x%x\n", frame->index, rptr);
+	}
+
+	length = calc_frame_length(frame);
+	if (!length || length < frame->bytesleft) {
+		vpu_err("[%d][%d]'s frame[%ld] invalid, want %d but %d, drop\n",
+				ctx->core_dev->id, ctx->str_index,
+				frame->index, frame->bytesleft, length);
+		vpu_err("uStrBuffWrPtr = 0x%x, uFrameSize = 0x%x\n",
+			frame->info.uStrBuffWrPtr, frame->info.uFrameSize);
+		add_rptr(frame, length);
+		return -EINVAL;
+	}
+
+	bytesskiped = find_frame_start_and_skip(ctx, frame, 1);
+	if (!bytesskiped)
+		return 0;
+
+	if (attr)
+		count_strip_info(&attr->statistic.strip_sts.begin, bytesskiped);
+
+	return 0;
+}
+
+static int inc_frame(struct queue_data *queue)
+{
+	struct vpu_frame_info *frame = NULL;
+
+	if (!queue)
+		return -EINVAL;
+
+	frame = vzalloc(sizeof(*frame));
+	if (!frame)
+		return -EINVAL;
+
+	frame->queue = queue;
+	list_add_tail(&frame->list, &queue->frame_idle);
+	atomic64_inc(&queue->frame_count);
+
+	vpu_dbg(LVL_DEBUG, "++ frame : %lld\n",
+			atomic64_read(&queue->frame_count));
+
+	return 0;
+}
+
+static void dec_frame(struct vpu_frame_info *frame)
+{
+	if (!frame)
+		return;
+	list_del_init(&frame->list);
+	if (frame->queue) {
+		atomic64_dec(&frame->queue->frame_count);
+
+		vpu_dbg(LVL_DEBUG, "-- frame : %lld\n",
+				atomic64_read(&frame->queue->frame_count));
+	}
+	VPU_SAFE_RELEASE(frame, vfree);
+}
+
+static struct vpu_frame_info *get_idle_frame(struct queue_data *queue)
+{
+	struct vpu_frame_info *frame = NULL;
+
+	if (!queue)
+		return NULL;
+
+	if (list_empty(&queue->frame_idle))
+		inc_frame(queue);
+	frame = list_first_entry(&queue->frame_idle,
+				struct vpu_frame_info, list);
+	if (frame)
+		list_del_init(&frame->list);
+
+	return frame;
+}
+
+static void put_frame_idle(struct vpu_frame_info *frame)
+{
+	struct queue_data *queue;
+
+	if (!frame)
+		return;
+
+	list_del_init(&frame->list);
+	memset(&frame->info, 0, sizeof(frame->info));
+	frame->bytesleft = 0;
+	frame->wptr = 0;
+	frame->rptr = 0;
+	frame->start = 0;
+	frame->end = 0;
+	frame->eos = false;
+	frame->is_start = false;
+	frame->index = 0;
+	frame->timestamp = VPU_ENC_INVALID_TIMESTAMP;
+	queue = frame->queue;
+	if (queue && atomic64_read(&queue->frame_count) <= FRAME_COUNT_THD)
+		list_add_tail(&frame->list, &queue->frame_idle);
+	else
+		dec_frame(frame);
+}
+
+static bool process_frame_done(struct queue_data *queue)
+{
+	struct vpu_ctx *ctx;
+	struct vb2_data_req *p_data_req = NULL;
+	struct vpu_frame_info *frame = NULL;
+	pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc;
+
+	WARN_ON(!queue || !queue->ctx);
+
+	ctx = queue->ctx;
+
+	stream_buffer_desc = get_rpc_stream_buffer_desc(ctx);
+
+	if (list_empty(&queue->frame_q))
+		return false;
+
+	frame = list_first_entry(&queue->frame_q, typeof(*frame), list);
+	if (!frame)
+		return false;
+
+	frame->rptr = get_ptr(stream_buffer_desc->rptr);
+
+	if (precheck_frame(ctx, frame)) {
+		update_stream_desc_rptr(ctx, frame->rptr);
+		put_frame_idle(frame);
+		frame = NULL;
+		return true;
+	}
+
+	if (list_empty(&queue->drv_q))
+		return false;
+
+	p_data_req = list_first_entry(&queue->drv_q, typeof(*p_data_req), list);
+
+	if (frame->eos)
+		append_empty_end_frame(p_data_req);
+	else
+		transfer_stream_output(ctx, frame, p_data_req);
+
+	update_stream_desc_rptr(ctx, frame->rptr);
+	fill_vb_sequence(p_data_req->vb2_buf, frame->info.uFrameID);
+	set_vb_flags(p_data_req->vb2_buf, p_data_req->buffer_flags);
+	p_data_req->vb2_buf->timestamp = frame->timestamp;
+	vpu_dbg(LVL_FRAME, "[%d:%d][%8d], length : %8ld, ts : %32lld%s\n",
+			ctx->core_dev->id, ctx->str_index,
+			frame->info.uFrameID,
+			vb2_get_plane_payload(p_data_req->vb2_buf, 0),
+			p_data_req->vb2_buf->timestamp,
+			frame->eos ? " (EOS)" : "");
+	if (!frame->bytesleft) {
+		put_frame_idle(frame);
+		frame = NULL;
+	}
+	list_del(&p_data_req->list);
+
+	if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+		vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_DONE);
+	else
+		vpu_err("vb2_buf's state is invalid(%d\n)",
+				p_data_req->vb2_buf->state);
+
+	return true;
+}
+
+static int process_stream_output(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue = NULL;
+
+	if (!ctx)
+		return -EINVAL;
+
+	queue = &ctx->q_data[V4L2_DST];
+
+	down(&queue->drv_q_lock);
+	while (1) {
+		if (!process_frame_done(queue))
+			break;
+	}
+	up(&queue->drv_q_lock);
+
+	submit_input_and_encode(ctx);
+
+	return 0;
+}
+
+static void show_enc_pic_info(MEDIAIP_ENC_PIC_INFO *pEncPicInfo)
+{
+#ifdef TB_REC_DBG
+	vpu_dbg(LVL_DEBUG, "       - Frame ID      : 0x%x\n",
+			pEncPicInfo->uFrameID);
+
+	switch (pEncPicInfo->ePicType) {
+	case MEDIAIP_ENC_PIC_TYPE_IDR_FRAME:
+		vpu_dbg(LVL_DEBUG, "       - Picture Type  : IDR picture\n");
+		break;
+	case MEDIAIP_ENC_PIC_TYPE_I_FRAME:
+		vpu_dbg(LVL_DEBUG, "       - Picture Type  : I picture\n");
+		break;
+	case MEDIAIP_ENC_PIC_TYPE_P_FRAME:
+		vpu_dbg(LVL_DEBUG, "       - Picture Type  : P picture\n");
+		break;
+	case MEDIAIP_ENC_PIC_TYPE_B_FRAME:
+		vpu_dbg(LVL_DEBUG, "       - Picture Type  : B picture\n");
+		break;
+	default:
+		vpu_dbg(LVL_DEBUG, "       - Picture Type  : BI picture\n");
+		break;
+	}
+	vpu_dbg(LVL_DEBUG, "       - Skipped frame : 0x%x\n",
+			pEncPicInfo->uSkippedFrame);
+	vpu_dbg(LVL_DEBUG, "       - Frame size    : 0x%x\n",
+			pEncPicInfo->uFrameSize);
+	vpu_dbg(LVL_DEBUG, "       - Frame CRC     : 0x%x\n",
+			pEncPicInfo->uFrameCrc);
+#endif
+}
+
+static int handle_event_start_done(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	down(&ctx->q_data[V4L2_SRC].drv_q_lock);
+	set_bit(VPU_ENC_STATUS_START_DONE, &ctx->status);
+	set_queue_rw_flag(&ctx->q_data[V4L2_SRC], VPU_ENC_FLAG_WRITEABLE);
+	up(&ctx->q_data[V4L2_SRC].drv_q_lock);
+	submit_input_and_encode(ctx);
+
+	enable_fps_sts(get_vpu_ctx_attr(ctx));
+	complete(&ctx->start_cmp);
+	vpu_dbg(LVL_FLOW, "[%d:%d] start done\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	return 0;
+}
+
+static void vpu_enc_config_expert_mode_parm(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = NULL;
+	pMEDIAIP_ENC_EXPERT_MODE_PARAM param = NULL;
+
+	if (!ctx)
+		return;
+
+	attr = get_vpu_ctx_attr(ctx);
+	if (!attr)
+		return;
+
+	param = get_rpc_expert_mode_param(ctx);
+	if (!param)
+		return;
+
+	param->Config.frame_rate_num = attr->fival.numerator;
+	param->Config.frame_rate_den = attr->fival.denominator;
+	vpu_dbg(LVL_FLOW, "[%d:%d] h264 frame rate: %d/%d\n",
+		ctx->core_dev->id, ctx->str_index,
+		param->Config.frame_rate_num, param->Config.frame_rate_den);
+
+	param->Config.h264_aspect_ratio_present = attr->h264_vui_sar_enable;
+	param->Config.aspect_ratio = attr->h264_vui_sar_idc;
+	param->Config.h264_aspect_ratio_sar_width = attr->h264_vui_sar_width;
+	param->Config.h264_aspect_ratio_sar_height = attr->h264_vui_sar_height;
+	vpu_dbg(LVL_FLOW,
+		"[%d:%d] h264 vui sar:enable=%d, idc=%d, width=%d, height=%d\n",
+		ctx->core_dev->id, ctx->str_index,
+		attr->h264_vui_sar_enable,
+		attr->h264_vui_sar_idc,
+		attr->h264_vui_sar_width,
+		attr->h264_vui_sar_height);
+
+	param->Config.h264_video_type_present = 1;
+	param->Config.h264_video_format = 5;
+	param->Config.h264_video_colour_descriptor = 1;
+	vpu_enc_convert_color_v4l2_aspect_to_iso_aspect(ctx,
+			&param->Config.h264_video_colour_primaries,
+			&param->Config.h264_video_transfer_char,
+			&param->Config.h264_video_matrix_coeff,
+			&param->Config.h264_video_full_range);
+
+	vpu_dbg(LVL_FLOW,
+		"[%d:%d] primaries=%d, transfer=%d, matrix=%d, fullrange =%d\n",
+		ctx->core_dev->id, ctx->str_index,
+		param->Config.h264_video_colour_primaries,
+		param->Config.h264_video_transfer_char,
+		param->Config.h264_video_matrix_coeff,
+		param->Config.h264_video_full_range);
+}
+
+static int handle_event_mem_request(struct vpu_ctx *ctx,
+				MEDIAIP_ENC_MEM_REQ_DATA *req_data)
+{
+	int ret;
+
+	if (!ctx || !req_data)
+		return -EINVAL;
+
+	ret = vpu_enc_alloc_mem(ctx, req_data, get_rpc_mem_pool(ctx));
+	if (ret) {
+		vpu_err("fail to alloc encoder memory\n");
+		return ret;
+	}
+
+	vpu_enc_config_expert_mode_parm(ctx);
+
+	vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_STREAM_START, 0, NULL);
+	set_bit(VPU_ENC_STATUS_START_SEND, &ctx->status);
+	vpu_dbg(LVL_FLOW, "[%d:%d] start stream\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	return 0;
+}
+
+static bool check_stream_buffer_desc(struct vpu_ctx *ctx,
+				pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc)
+{
+	u32 start;
+	u32 end;
+	u32 rptr;
+	u32 wptr;
+
+	if (!stream_buffer_desc)
+		return false;
+	start = get_ptr(stream_buffer_desc->start);
+	end = get_ptr(stream_buffer_desc->end);
+	rptr = get_ptr(stream_buffer_desc->rptr);
+	wptr = get_ptr(stream_buffer_desc->wptr);
+
+	if (rptr < start || rptr > end ||
+		wptr < start || wptr > end ||
+		end <= start ||
+		end - start != ctx->encoder_stream.size) {
+		vpu_err("stream buffer desc is invalid, s:%x,e:%x,r:%x,w:%x\n",
+				start, end, rptr, wptr);
+		return false;
+	}
+
+	return true;
+}
+
+static int handle_event_frame_done(struct vpu_ctx *ctx,
+				MEDIAIP_ENC_PIC_INFO *pEncPicInfo)
+{
+	struct queue_data *queue;
+	struct vpu_frame_info *frame;
+	pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc;
+	s64 timestamp;
+
+	if (!ctx || !pEncPicInfo)
+		return -EINVAL;
+
+	vpu_dbg(LVL_DEBUG, "Frame done(%d) - uFrameID = %d\n",
+			pEncPicInfo->uPicEncodDone, pEncPicInfo->uFrameID);
+
+	queue = &ctx->q_data[V4L2_DST];
+	if (!pEncPicInfo->uPicEncodDone) {
+		vpu_err("Pic Encoder Not Done\n");
+		return -EINVAL;
+	}
+
+	stream_buffer_desc = get_rpc_stream_buffer_desc(ctx);
+	if (!check_stream_buffer_desc(ctx, stream_buffer_desc))
+		return -EINVAL;
+
+	show_enc_pic_info(pEncPicInfo);
+	record_start_time(ctx, V4L2_DST);
+
+	timestamp = (pEncPicInfo->tv_s * NSEC_PER_SEC + pEncPicInfo->tv_ns);
+
+	down(&queue->drv_q_lock);
+	frame = get_idle_frame(queue);
+	if (frame) {
+		struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+		memcpy(&frame->info, pEncPicInfo, sizeof(frame->info));
+		frame->bytesleft = frame->info.uFrameSize;
+		frame->wptr = get_ptr(stream_buffer_desc->wptr);
+		frame->rptr = get_ptr(stream_buffer_desc->rptr);
+		frame->start = get_ptr(stream_buffer_desc->start);
+		frame->end = get_ptr(stream_buffer_desc->end);
+		frame->eos = false;
+		frame->is_start = true;
+		frame->timestamp = timestamp;
+		if (attr)
+			frame->index = attr->statistic.encoded_count;
+
+		list_add_tail(&frame->list, &queue->frame_q);
+	} else {
+		vpu_err("fail to alloc memory for frame info\n");
+	}
+	up(&queue->drv_q_lock);
+	count_encoded_frame(ctx);
+
+	/* Sync the write pointer to the local view of it */
+	process_stream_output(ctx);
+
+	return 0;
+}
+
+static int handle_event_frame_release(struct vpu_ctx *ctx, u_int32 *uFrameID)
+{
+	struct queue_data *This = &ctx->q_data[V4L2_SRC];
+	struct vb2_data_req *p_data_req = NULL;
+
+	if (!ctx || !uFrameID)
+		return -EINVAL;
+
+	This = &ctx->q_data[V4L2_SRC];
+	vpu_dbg(LVL_DEBUG, "Frame release - uFrameID = %d\n", *uFrameID);
+	p_data_req = find_vb2_data_by_sequence(This, *uFrameID);
+	if (!p_data_req) {
+		vpu_err("uFrameID[%d] is invalid\n", *uFrameID);
+		return -EINVAL;
+	}
+	if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+		vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_DONE);
+
+	return 0;
+}
+
+static int handle_event_stop_done(struct vpu_ctx *ctx)
+{
+	struct queue_data *queue;
+	struct vpu_frame_info *frame;
+
+	WARN_ON(!ctx);
+	queue = &ctx->q_data[V4L2_DST];
+
+	disable_fps_sts(get_vpu_ctx_attr(ctx));
+
+	set_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status);
+	vpu_dbg(LVL_FLOW, "[%d:%d] stop done\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	down(&queue->drv_q_lock);
+	frame = get_idle_frame(queue);
+	if (frame) {
+		frame->eos = true;
+		frame->timestamp = calculate_timestamp_for_eos(ctx);
+		frame->info.uFrameID = ctx->sequence;
+		list_add_tail(&frame->list, &queue->frame_q);
+	} else {
+		vpu_err("fail to alloc memory for last frame\n");
+	}
+	up(&queue->drv_q_lock);
+
+	process_stream_output(ctx);
+
+	notify_eos(ctx);
+	clear_start_status(ctx);
+	init_ctx_seq_info(ctx);
+	complete(&ctx->stop_cmp);
+
+	return 0;
+}
+
+static void vpu_stop_ctx_asynchronous(struct vpu_ctx *ctx)
+{
+	if (!ctx || ctx->ctx_released)
+		return;
+	if (!test_bit(VPU_ENC_STATUS_START_DONE, &ctx->status))
+		return;
+	if (!test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		return;
+	if (test_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status))
+		return;
+	if (test_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status))
+		return;
+	request_eos(ctx);
+}
+
+static void vpu_enc_event_handler(struct vpu_ctx *ctx,
+				u_int32 uEvent, u_int32 *event_data)
+{
+	vpu_log_event(uEvent, ctx->str_index);
+	vpu_enc_check_mem_overstep(ctx);
+
+	switch (uEvent) {
+	case VID_API_ENC_EVENT_START_DONE:
+		handle_event_start_done(ctx);
+		break;
+	case VID_API_ENC_EVENT_MEM_REQUEST:
+		handle_event_mem_request(ctx,
+				(MEDIAIP_ENC_MEM_REQ_DATA *)event_data);
+		break;
+	case VID_API_ENC_EVENT_PARA_UPD_DONE:
+		break;
+	case VID_API_ENC_EVENT_FRAME_DONE:
+		handle_event_frame_done(ctx,
+					(MEDIAIP_ENC_PIC_INFO *)event_data);
+		break;
+	case VID_API_ENC_EVENT_FRAME_RELEASE:
+		handle_event_frame_release(ctx, (u_int32 *)event_data);
+		break;
+	case VID_API_ENC_EVENT_STOP_DONE:
+		handle_event_stop_done(ctx);
+		break;
+	case VID_API_ENC_EVENT_FRAME_INPUT_DONE:
+		down(&ctx->q_data[V4L2_SRC].drv_q_lock);
+		set_queue_rw_flag(&ctx->q_data[V4L2_SRC],
+				VPU_ENC_FLAG_WRITEABLE);
+		up(&ctx->q_data[V4L2_SRC].drv_q_lock);
+		response_stop_stream(ctx);
+		submit_input_and_encode(ctx);
+		break;
+	case VID_API_ENC_EVENT_TERMINATE_DONE:
+		break;
+	case VID_API_ENC_EVENT_RESET_DONE:
+		break;
+	case VID_API_ENC_EVENT_FIRMWARE_XCPT:
+		vpu_err("firmware exception:%s\n", (char *)event_data);
+		break;
+	default:
+		vpu_err("........unknown event : 0x%x\n", uEvent);
+		break;
+	}
+	if (test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		vpu_stop_ctx_asynchronous(ctx);
+}
+
+static void get_core_supported_instance_count(struct core_device *core)
+{
+	pENC_RPC_HOST_IFACE iface;
+
+	iface = core->shared_mem.pSharedInterface;
+	core->supported_instance_count =
+		min_t(u32, iface->uMaxEncoderStreams, VID_API_NUM_STREAMS);
+}
+
+static int re_configure_codecs(struct core_device *core)
+{
+	int i;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		struct vpu_ctx *ctx = core->ctx[i];
+		struct queue_data *queue;
+
+		if (!ctx || !test_bit(VPU_ENC_STATUS_INITIALIZED, &ctx->status))
+			continue;
+
+		mutex_lock(&ctx->instance_mutex);
+		queue = &ctx->q_data[V4L2_SRC];
+		if (!list_empty(&queue->drv_q)) {
+			vpu_dbg(LVL_INFO,
+				"re configure codec for core[%d]\n", core->id);
+			configure_codec(ctx);
+			submit_input_and_encode(ctx);
+		}
+		mutex_unlock(&ctx->instance_mutex);
+	}
+
+	return 0;
+}
+
+static int wait_for_boot_done(struct core_device *core, int resume)
+{
+	int ret;
+
+	if (!core)
+		return -EINVAL;
+
+	ret = wait_for_completion_timeout(&core->boot_cmp,
+						msecs_to_jiffies(1000));
+	if (!ret) {
+		vpu_err("error: wait for core[%d] %s done timeout!\n",
+				core->id, resume ? "resume" : "start");
+		return -EINVAL;
+	}
+
+	if (resume)
+		re_configure_codecs(core);
+
+	return 0;
+}
+
+static void vpu_core_start_done(struct core_device *core)
+{
+	if (!core)
+		return;
+
+	get_core_supported_instance_count(core);
+	core->firmware_started = true;
+	complete(&core->boot_cmp);
+
+	show_firmware_version(core, LVL_ALL);
+}
+
+static struct vpu_ctx *get_ctx_by_index(struct core_device *core, int index)
+{
+	struct vpu_ctx *ctx = NULL;
+
+	if (!core)
+		return NULL;
+
+	if (index < 0 || index >= core->supported_instance_count)
+		return NULL;
+
+	ctx = core->ctx[index];
+	if (!ctx)
+		return NULL;
+
+	if (!test_bit(VPU_ENC_STATUS_INITIALIZED, &ctx->status)) {
+		vpu_err("core[%d]'s ctx[%d] is not initialized\n",
+				core->id, index);
+		return NULL;
+	}
+
+	if (test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		vpu_err("core[%d]'s ctx[%d] is closed\n", core->id, index);
+
+	return ctx;
+}
+
+static int process_ctx_msg(struct vpu_ctx *ctx, struct msg_header *header)
+{
+	int ret = 0;
+	struct vpu_event_msg *msg = NULL;
+	u32 *pdata = NULL;
+
+	if (!ctx || !header)
+		return -EINVAL;
+
+	msg = get_idle_msg(ctx);
+	if (!msg) {
+		vpu_err("get idle msg fail\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	msg->idx = header->idx;
+	msg->msgid = header->msgid;
+	msg->number = header->msgnum;
+	pdata = msg->data;
+	ret = 0;
+	if (msg->number > ARRAY_SIZE(msg->data)) {
+		ret = alloc_msg_ext_buffer(msg, header->msgnum);
+		pdata = msg->ext_data;
+	}
+	rpc_read_msg_array(&ctx->core_dev->shared_mem, pdata, msg->number);
+	if (ret) {
+		put_idle_msg(ctx, msg);
+		return ret;
+	}
+
+	push_back_event_msg(ctx, msg);
+
+	return ret;
+error:
+	rpc_read_msg_array(&ctx->core_dev->shared_mem, NULL, header->msgnum);
+	return ret;
+}
+
+static void vpu_enc_notify_msg_event(struct core_device *core)
+{
+	int i;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		struct vpu_ctx *ctx = core->ctx[i];
+
+		if (!ctx || is_event_msg_empty(ctx))
+			continue;
+		queue_work(ctx->instance_wq, &ctx->instance_work);
+	}
+}
+
+static int process_msg(struct core_device *core)
+{
+	struct msg_header header;
+	struct vpu_ctx *ctx = NULL;
+	int ret;
+
+	ret = rpc_get_msg_header(&core->shared_mem, &header);
+	if (ret)
+		return ret;
+
+	if (header.idx >= ARRAY_SIZE(core->ctx)) {
+		vpu_err("msg idx(%d) is out of range, msgid = 0x%x\n",
+				header.idx, header.msgid);
+		rpc_read_msg_array(&core->shared_mem, NULL, header.msgnum);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->vdev->dev_mutex);
+	ctx = get_ctx_by_index(core, header.idx);
+	if (ctx != NULL && !ctx->ctx_released) {
+		count_event(ctx, header.msgid);
+		process_ctx_msg(ctx, &header);
+		queue_work(ctx->instance_wq, &ctx->instance_work);
+	} else {
+		vpu_err("msg[%d] of ctx[%d] is missed\n",
+				header.msgid, header.idx);
+		rpc_read_msg_array(&core->shared_mem, NULL, header.msgnum);
+	}
+	mutex_unlock(&core->vdev->dev_mutex);
+
+	return 0;
+}
+
+static void vpu_enc_fw_init(struct core_device *core_dev)
+{
+	u32 mu_addr;
+
+	vpu_dbg(LVL_ALL, "enable mu for core[%d]\n", core_dev->id);
+
+	mu_addr = cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy);
+	vpu_enc_mu_send_msg(core_dev, RPC_BUF_OFFSET, mu_addr);
+	vpu_enc_mu_send_msg(core_dev, BOOT_ADDRESS, core_dev->m0_p_fw_space_phy);
+	vpu_enc_mu_send_msg(core_dev, INIT_DONE, 2);
+}
+
+extern u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This);
+
+static void vpu_enc_receive_msg_event(struct core_device *core_dev)
+{
+	struct shared_addr *This = &core_dev->shared_mem;
+
+	while (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_AVAILABLE)
+		process_msg(core_dev);
+
+	if (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_BUFFER_ERROR)
+		vpu_err("MSG num is too big to handle\n");
+
+	mutex_lock(&core_dev->vdev->dev_mutex);
+	vpu_enc_notify_msg_event(core_dev);
+	mutex_unlock(&core_dev->vdev->dev_mutex);
+}
+
+static void vpu_enc_handle_msg_data(struct core_device *core_dev, u_int32 data)
+{
+	if (data == 0xaa)
+		vpu_enc_fw_init(core_dev);
+	else if (data == 0x55)
+		vpu_core_start_done(core_dev);
+	else if (data == 0xA5)
+		complete(&core_dev->snap_done_cmp);
+	else
+		vpu_enc_receive_msg_event(core_dev);
+}
+
+static void vpu_enc_msg_run_work(struct work_struct *work)
+{
+	struct core_device *dev = container_of(work, struct core_device, msg_work);
+	u_int32 data;
+
+	while (vpu_enc_mu_receive_msg(dev, &data) >= sizeof(u_int32))
+		vpu_enc_handle_msg_data(dev, data);
+}
+
+static void vpu_enc_msg_instance_work(struct work_struct *work)
+{
+	struct vpu_ctx *ctx = container_of(work, struct vpu_ctx, instance_work);
+	struct vpu_event_msg *msg;
+
+	while (1) {
+		msg = pop_event_msg(ctx);
+		if (!msg)
+			break;
+		if (msg->ext_data)
+			vpu_enc_event_handler(ctx, msg->msgid, msg->ext_data);
+		else
+			vpu_enc_event_handler(ctx, msg->msgid, msg->data);
+
+		put_idle_msg(ctx, msg);
+	}
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+		unsigned int *buf_count,
+		unsigned int *plane_count,
+		unsigned int psize[],
+		struct device *allocators[])
+{
+	struct queue_data  *This = (struct queue_data *)vq->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, This->desc,
+			This->ctx->core_dev->id, This->ctx->str_index);
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			*plane_count = 2;
+			psize[0] = This->sizeimage[0];//check alignment
+			psize[1] = This->sizeimage[1];//check colocated_size
+		} else {
+			psize[0] = This->sizeimage[0] + This->sizeimage[1];
+			*plane_count = 1;
+		}
+		if (*buf_count < MIN_BUFFER_COUNT)
+			*buf_count = MIN_BUFFER_COUNT;
+	} else {
+		*plane_count = 1;
+		psize[0] = This->sizeimage[0];//check alignment
+	}
+
+	if (*buf_count > VPU_MAX_BUFFER)
+		*buf_count = VPU_MAX_BUFFER;
+	if (*buf_count < 1)
+		*buf_count = 1;
+
+	return 0;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct queue_data *q_data = (struct queue_data *)vq->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			q_data->ctx->core_dev->id, q_data->ctx->str_index);
+
+	return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct queue_data *q_data = (struct queue_data *)q->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			q_data->ctx->core_dev->id, q_data->ctx->str_index);
+	vb2_clear_last_buffer_dequeued(q);
+
+	return 0;
+}
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+	struct queue_data *q_data = (struct queue_data *)q->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			q_data->ctx->core_dev->id, q_data->ctx->str_index);
+	clear_queue(q_data);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue    *vq = vb->vb2_queue;
+	struct queue_data   *This = (struct queue_data *)vq->drv_priv;
+	struct vb2_data_req *data_req;
+	struct vpu_ctx *ctx = This->ctx;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, This->desc,
+			This->ctx->core_dev->id, This->ctx->str_index);
+
+	data_req = &This->vb2_reqs[vb->index];
+	data_req->vb2_buf = vb;
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		fill_ctx_seq(ctx, data_req);
+		fill_vb_sequence(vb, data_req->sequence);
+	}
+	list_add_tail(&data_req->list, &This->drv_q);
+}
+
+static bool is_enc_dma_buf(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+
+	if (vb->memory != V4L2_MEMORY_MMAP)
+		return false;
+
+	if (vq->mem_ops != &vb2_dma_contig_memops)
+		return false;
+
+	return true;
+}
+
+static int vpu_enc_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct queue_data *queue = vq->drv_priv;
+	struct vpu_ctx *ctx = queue->ctx;
+	int i;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, queue->desc,
+			ctx->core_dev->id, ctx->str_index);
+	if (!is_enc_dma_buf(vb))
+		return 0;
+
+	for (i = 0; i < vb->num_planes; i++)
+		vpu_enc_add_dma_size(get_vpu_ctx_attr(ctx),
+					vb->planes[i].length);
+
+	return 0;
+}
+
+static void vpu_enc_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct queue_data *queue = vq->drv_priv;
+	struct vpu_ctx *ctx = queue->ctx;
+	int i;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, queue->desc,
+			ctx->core_dev->id, ctx->str_index);
+
+	if (!is_enc_dma_buf(vb))
+		return;
+
+	for (i = 0; i < vb->num_planes; i++)
+		vpu_enc_sub_dma_size(get_vpu_ctx_attr(ctx),
+					vb->planes[i].length);
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+	struct queue_data *q_data = (struct queue_data *)q->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			q_data->ctx->core_dev->id, q_data->ctx->str_index);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+	struct queue_data *q_data = (struct queue_data *)q->drv_priv;
+
+	vpu_dbg(LVL_BUF, "%s(), %s, (%d, %d)\n", __func__, q_data->desc,
+			q_data->ctx->core_dev->id, q_data->ctx->str_index);
+}
+
+static struct vb2_ops vpu_enc_v4l2_qops = {
+	.queue_setup        = vpu_queue_setup,
+	.buf_init           = vpu_enc_buf_init,
+	.buf_cleanup        = vpu_enc_buf_cleanup,
+	.wait_prepare       = vpu_prepare,
+	.wait_finish        = vpu_finish,
+	.buf_prepare        = vpu_buf_prepare,
+	.start_streaming    = vpu_start_streaming,
+	.stop_streaming     = vpu_stop_streaming,
+	.buf_queue          = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type,
+				struct vpu_ctx *ctx,
+				const struct vb2_mem_ops *mem_ops,
+				gfp_t gfp_flags)
+{
+	struct vb2_queue  *vb2_q = &This->vb2_q;
+	int ret;
+
+	vpu_log_func();
+
+	// initialze driver queue
+	INIT_LIST_HEAD(&This->drv_q);
+	INIT_LIST_HEAD(&This->frame_q);
+	INIT_LIST_HEAD(&This->frame_idle);
+	atomic64_set(&This->frame_count, 0);
+	// initialize vb2 queue
+	vb2_q->type = type;
+	vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	vb2_q->gfp_flags = gfp_flags;
+	vb2_q->ops = &vpu_enc_v4l2_qops;
+	vb2_q->drv_priv = This;
+	if (mem_ops)
+		vb2_q->mem_ops = mem_ops;
+	else
+		vb2_q->mem_ops = &vb2_dma_contig_memops;
+	vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	vb2_q->dev = &ctx->dev->plat_dev->dev;
+	ret = vb2_queue_init(vb2_q);
+	if (ret)
+		vpu_err("%s vb2_queue_init() failed (%d)!\n",
+				__func__,
+				ret
+				);
+	else
+		This->vb2_q_inited = true;
+}
+
+static void vpu_enc_init_output_queue(struct vpu_ctx *ctx,
+					struct queue_data *q)
+{
+	WARN_ON(!ctx);
+	WARN_ON(!q);
+
+	vpu_log_func();
+
+	init_vb2_queue(q,
+			V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+			ctx,
+			&vb2_dma_contig_memops,
+			GFP_DMA32);
+	q->type = V4L2_SRC;
+	sema_init(&q->drv_q_lock, 1);
+	q->ctx = ctx;
+
+	q->supported_fmts = formats_yuv_enc;
+	q->fmt_count = ARRAY_SIZE(formats_yuv_enc);
+	q->current_fmt = &formats_yuv_enc[0];
+
+	q->width = VPU_ENC_WIDTH_DEFAULT;
+	q->height = VPU_ENC_HEIGHT_DEFAULT;
+	q->rect.left = 0;
+	q->rect.top = 0;
+	q->rect.width = VPU_ENC_WIDTH_DEFAULT;
+	q->rect.height = VPU_ENC_HEIGHT_DEFAULT;
+	scnprintf(q->desc, sizeof(q->desc), "OUTPUT");
+}
+
+static void vpu_enc_init_capture_queue(struct vpu_ctx *ctx,
+					struct queue_data *q)
+{
+	WARN_ON(!ctx);
+	WARN_ON(!q);
+
+	vpu_log_func();
+
+	init_vb2_queue(q,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+			ctx,
+			&vb2_vmalloc_memops, 0);
+	q->type = V4L2_DST;
+	sema_init(&q->drv_q_lock, 1);
+	q->ctx = ctx;
+
+	q->supported_fmts = formats_compressed_enc;
+	q->fmt_count = ARRAY_SIZE(formats_compressed_enc);
+	q->current_fmt = &formats_compressed_enc[0];
+
+	q->width = VPU_ENC_WIDTH_DEFAULT;
+	q->height = VPU_ENC_HEIGHT_DEFAULT;
+	scnprintf(q->desc, sizeof(q->desc), "CAPTURE");
+}
+
+static void vpu_enc_init_queue_data(struct vpu_ctx *ctx)
+{
+	vpu_enc_init_output_queue(ctx, &ctx->q_data[V4L2_SRC]);
+	vpu_enc_init_capture_queue(ctx, &ctx->q_data[V4L2_DST]);
+}
+
+static void vpu_enc_release_queue_data(struct vpu_ctx *ctx)
+{
+	vpu_enc_queue_release(&ctx->q_data[V4L2_SRC]);
+	vpu_enc_queue_release(&ctx->q_data[V4L2_DST]);
+}
+
+static void vpu_ctx_power_on(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->core_dev)
+		return;
+
+	if (ctx->power_status)
+		return;
+	pm_runtime_get_sync(ctx->core_dev->generic_dev);
+	ctx->power_status = true;
+}
+
+static void vpu_ctx_power_off(struct vpu_ctx *ctx)
+{
+	if (!ctx || !ctx->core_dev)
+		return;
+
+	if (!ctx->power_status)
+		return;
+	pm_runtime_put_sync(ctx->core_dev->generic_dev);
+	ctx->power_status = false;
+}
+
+static int set_vpu_fw_addr(struct vpu_dev *dev, struct core_device *core_dev)
+{
+	off_t reg_fw_base;
+
+	if (!dev || !core_dev)
+		return -EINVAL;
+
+	vpu_enc_mu_enable_rx(core_dev);
+	reg_fw_base = core_dev->reg_csr_base;
+	write_vpu_reg(dev, core_dev->m0_p_fw_space_phy, reg_fw_base + CSR_CM0Px_ADDR_OFFSET);
+	write_vpu_reg(dev, 0x0, reg_fw_base + CSR_CM0Px_CPUWAIT);
+
+	return 0;
+}
+
+static void cleanup_firmware_memory(struct core_device *core_dev)
+{
+	memset_io(core_dev->m0_p_fw_space_vir, 0, core_dev->fw_buf_size);
+}
+
+static int vpu_firmware_download(struct vpu_dev *This, u_int32 core_id)
+{
+	const struct firmware *m0_pfw = NULL;
+	const u8 *image;
+	unsigned int FW_Size = 0;
+	int ret = 0;
+	struct core_device *core_dev = &This->core_dev[core_id];
+	char *p = This->core_dev[core_id].m0_p_fw_space_vir;
+
+	vpu_log_func();
+
+	ret = request_firmware(&m0_pfw, M0FW_FILENAME, This->generic_dev);
+	if (ret) {
+		vpu_err("%s() request fw %s failed(%d)\n",
+			__func__, M0FW_FILENAME, ret);
+
+		return ret;
+	}
+	vpu_dbg(LVL_DEBUG, "%s() request fw %s got size(%ld)\n",
+			__func__, M0FW_FILENAME, m0_pfw->size);
+
+	image = m0_pfw->data;
+	FW_Size = min_t(u32, m0_pfw->size, This->core_dev[core_id].fw_buf_size);
+	This->core_dev[core_id].fw_actual_size = FW_Size;
+
+	cleanup_firmware_memory(core_dev);
+	memcpy(core_dev->m0_p_fw_space_vir, image, FW_Size);
+	p[16] = This->plat_type;
+	p[17] = core_id + 1;
+	p[18] = 1;
+	set_vpu_fw_addr(This, &This->core_dev[core_id]);
+
+	release_firmware(m0_pfw);
+	m0_pfw = NULL;
+
+	return ret;
+}
+
+static int download_vpu_firmware(struct vpu_dev *dev,
+				struct core_device *core_dev)
+{
+	int ret = 0;
+
+	if (!dev || !core_dev)
+		return -EINVAL;
+
+	if (core_dev->fw_is_ready)
+		return 0;
+
+	vpu_dbg(LVL_INFO, "download firmware for core[%d]\n", core_dev->id);
+	reinit_completion(&core_dev->boot_cmp);
+	ret = vpu_firmware_download(dev, core_dev->id);
+	if (ret) {
+		vpu_err("error: vpu_firmware_download fail\n");
+		goto exit;
+	}
+	wait_for_boot_done(core_dev, 0);
+	if (!core_dev->firmware_started) {
+		vpu_err("core[%d] start firmware failed\n", core_dev->id);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	set_core_fw_status(core_dev, true);
+	clear_core_hang(core_dev);
+exit:
+	return ret;
+}
+
+static bool is_valid_ctx(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return false;
+	if (!ctx->dev || !ctx->core_dev)
+		return false;
+	if (ctx->str_index >= ARRAY_SIZE(ctx->core_dev->ctx))
+		return false;
+
+	return true;
+}
+
+static void free_instance(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	if (is_valid_ctx(ctx))
+		ctx->core_dev->ctx[ctx->str_index] = NULL;
+	VPU_SAFE_RELEASE(ctx, kfree);
+}
+
+static u32 count_free_core_slot(struct core_device *core)
+{
+	u32 count = 0;
+	int i;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (!core->ctx[i])
+			count++;
+	}
+
+	return count;
+}
+
+static struct core_device *find_proper_core(struct vpu_dev *dev)
+{
+	struct core_device *core = NULL;
+	u32 maximum = 0;
+	u32 count;
+	int i;
+	int ret;
+
+	for (i = 0; i < dev->core_num; i++) {
+		struct core_device *core_dev = &dev->core_dev[i];
+
+		ret = process_core_hang(core_dev);
+		if (ret)
+			continue;
+
+		ret = download_vpu_firmware(dev, core_dev);
+		if (ret)
+			continue;
+
+		if (core_dev->supported_instance_count == 0)
+			continue;
+
+		count = count_free_core_slot(core_dev);
+		if (count == core_dev->supported_instance_count)
+			return core_dev;
+
+		if (maximum < count) {
+			core = core_dev;
+			maximum = count;
+		}
+	}
+
+	return core;
+}
+
+static int request_instance(struct core_device *core, struct vpu_ctx *ctx)
+{
+	int found = 0;
+	int idx;
+
+	if (!core || !ctx)
+		return -EINVAL;
+
+	for (idx = 0; idx < core->supported_instance_count; idx++) {
+		if (!core->ctx[idx]) {
+			found = 1;
+			ctx->core_dev = core;
+			ctx->str_index = idx;
+			ctx->dev = core->vdev;
+			break;
+		}
+	}
+
+	if (!found) {
+		vpu_err("cann't request any instance\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int construct_vpu_ctx(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+
+	ctx->ctrl_inited = false;
+	mutex_init(&ctx->instance_mutex);
+	ctx->ctx_released = false;
+
+	return 0;
+}
+
+static struct vpu_ctx *create_and_request_instance(struct vpu_dev *dev)
+{
+	struct core_device *core = NULL;
+	struct vpu_ctx *ctx = NULL;
+	int ret;
+
+	if (!dev)
+		return NULL;
+
+	core = find_proper_core(dev);
+	if (!core)
+		return NULL;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return NULL;
+
+	ret = request_instance(core, ctx);
+	if (ret < 0) {
+		VPU_SAFE_RELEASE(ctx, kfree);
+		return NULL;
+	}
+
+	construct_vpu_ctx(ctx);
+	vpu_ctx_power_on(ctx);
+	vpu_dbg(LVL_INFO, "request encoder instance : %d.%d\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	return ctx;
+}
+
+static int init_vpu_ctx_fh(struct vpu_ctx *ctx, struct vpu_dev *dev)
+{
+	if (!ctx || !dev)
+		return -EINVAL;
+
+	mutex_lock(&ctx->instance_mutex);
+
+	v4l2_fh_init(&ctx->fh, dev->pvpu_encoder_dev);
+	v4l2_fh_add(&ctx->fh);
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	clear_bit(VPU_ENC_STATUS_CLOSED, &ctx->status);
+
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static void uninit_vpu_ctx_fh(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	mutex_lock(&ctx->instance_mutex);
+
+	set_bit(VPU_ENC_STATUS_CLOSED, &ctx->status);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+static void cancel_vpu_ctx(struct vpu_ctx *ctx)
+{
+	cancel_work_sync(&ctx->instance_work);
+	cleanup_ctx_msg_queue(ctx);
+}
+
+static void uninit_vpu_ctx(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return;
+
+	clear_bit(VPU_ENC_STATUS_INITIALIZED, &ctx->status);
+	cancel_vpu_ctx(ctx);
+	if (ctx->instance_wq) {
+		destroy_workqueue(ctx->instance_wq);
+		ctx->instance_wq = NULL;
+	}
+	mutex_lock(&ctx->instance_mutex);
+	vpu_enc_free_stream(ctx);
+
+	ctx->ctx_released = true;
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+static int init_vpu_ctx(struct vpu_ctx *ctx)
+{
+	INIT_WORK(&ctx->instance_work, vpu_enc_msg_instance_work);
+	ctx->instance_wq = alloc_workqueue("vpu_instance",
+				WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!ctx->instance_wq) {
+		vpu_err("error: unable to alloc workqueue for ctx\n");
+		return -ENOMEM;
+	}
+
+	init_ctx_msg_queue(ctx);
+
+	vpu_enc_init_queue_data(ctx);
+	vpu_enc_set_default_color(ctx, V4L2_COLORSPACE_REC709);
+	init_completion(&ctx->start_cmp);
+	init_completion(&ctx->stop_cmp);
+
+	set_bit(VPU_ENC_STATUS_INITIALIZED, &ctx->status);
+	ctx->core_dev->ctx[ctx->str_index] = ctx;
+
+	return 0;
+}
+
+static int show_encoder_param(struct vpu_attr *attr,
+		pMEDIAIP_ENC_PARAM param, char *buf, u32 size)
+{
+	pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam = NULL;
+	int num = 0;
+
+	pEncExpertModeParam = rpc_get_expert_mode_param(&attr->core->shared_mem,
+							attr->index);
+	num += scnprintf(buf + num, size - num,
+			"encoder param:[setting/take effect]\n");
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Codec Mode",
+			attr->param.eCodecMode, param->eCodecMode);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Profile",
+			attr->param.eProfile, param->eProfile);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Level",
+			attr->param.uLevel, param->uLevel);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%2d(%d / %d);%2d(%d / %d)\n",
+			"Frame Rate",
+			attr->param.uFrameRate,
+			attr->fival.numerator,
+			attr->fival.denominator,
+			param->uFrameRate,
+			pEncExpertModeParam->Config.frame_rate_num,
+			pEncExpertModeParam->Config.frame_rate_den);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Stride",
+			attr->param.uSrcStride, param->uSrcStride);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Width",
+			attr->param.uSrcWidth, param->uSrcWidth);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Height",
+			attr->param.uSrcHeight, param->uSrcHeight);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Offset x",
+			attr->param.uSrcOffset_x, param->uSrcOffset_x);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Offset y",
+			attr->param.uSrcOffset_y, param->uSrcOffset_y);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Crop Width",
+			attr->param.uSrcCropWidth, param->uSrcCropWidth);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Source Crop Height",
+			attr->param.uSrcCropHeight,
+			param->uSrcCropHeight);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Out Width",
+			attr->param.uOutWidth, param->uOutWidth);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Out Height",
+			attr->param.uOutHeight, param->uOutHeight);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "I Frame Interval",
+			attr->param.uIFrameInterval,
+			param->uIFrameInterval);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Bframes",
+			attr->param.uGopBLength, param->uGopBLength);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Low Latency Mode",
+			attr->param.uLowLatencyMode,
+			param->uLowLatencyMode);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Bitrate Mode",
+			attr->param.eBitRateMode, param->eBitRateMode);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Target Bitrate",
+			attr->param.uTargetBitrate,
+			param->uTargetBitrate);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Min Bitrate",
+			attr->param.uMinBitRate, param->uMinBitRate);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "Max Bitrate",
+			attr->param.uMaxBitRate, param->uMaxBitRate);
+	num += scnprintf(buf + num, size - num,
+			"\t%-18s:%10d;%10d\n", "QP",
+			attr->param.uInitSliceQP,
+			param->uInitSliceQP);
+
+	return num;
+}
+
+static int show_queue_buffer_info(struct queue_data *queue, char *buf, u32 size)
+{
+	int i;
+	int num = 0;
+
+	for (i = 0; i < queue->vb2_q.num_buffers; i++) {
+		struct vb2_buffer *vb = queue->vb2_q.bufs[i];
+
+		num += scnprintf(buf + num, size - num, " %d", vb->state);
+	}
+
+	return num;
+}
+
+static int show_cmd_event(struct vpu_statistic *statistic, int i,
+				char *buf, u32 size)
+{
+	int num = 0;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\t(%2d) ", i);
+
+	if (i <= GTB_ENC_CMD_RESERVED)
+		num += scnprintf(buf + num, PAGE_SIZE - num, "%-28s:%12ld;",
+				get_cmd_str(i), statistic->cmd[i]);
+	else
+		num += scnprintf(buf + num, PAGE_SIZE - num, "%-28s:%12s;",
+				"", "");
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "    ");
+	if (i <= VID_API_ENC_EVENT_RESERVED)
+		num += scnprintf(buf + num, PAGE_SIZE - num, "%-34s:%12ld;",
+				get_event_str(i), statistic->event[i]);
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "\n");
+
+	return num;
+}
+
+static int show_cmd_event_infos(struct vpu_statistic *statistic,
+		char *buf, u32 size)
+{
+	int num = 0;
+	int i;
+	int count;
+
+	num += scnprintf(buf + num, size - num, "command/event:\n");
+
+	count = max((int)GTB_ENC_CMD_RESERVED, (int)VID_API_ENC_EVENT_RESERVED);
+	for (i = 0; i <= count; i++)
+		num += show_cmd_event(statistic, i, buf + num, size - num);
+
+	num += scnprintf(buf + num, size - num, "current status:\n");
+	num += scnprintf(buf + num, size - num,
+			"\t%-10s:%36s;%10lld.%06ld\n", "commond",
+			get_cmd_str(statistic->current_cmd),
+			statistic->ts_cmd.tv_sec,
+			statistic->ts_cmd.tv_nsec / 1000);
+	num += scnprintf(buf + num, size - num,
+			"\t%-10s:%36s;%10lld.%06ld\n", "event",
+			get_event_str(statistic->current_event),
+			statistic->ts_event.tv_sec,
+			statistic->ts_event.tv_nsec / 1000);
+
+	return num;
+}
+
+static int show_single_fps_info(struct vpu_fps_sts *fps, char *buf, u32 size)
+{
+	const u32 COEF = VPU_FPS_COEF;
+	int num = 0;
+
+	num += scnprintf(buf + num, size - num, "%3ld.", fps->fps / COEF);
+	num += scnprintf(buf + num, size - num, "%02ld", fps->fps % COEF);
+	if (fps->thd)
+		num += scnprintf(buf + num, size - num, "(%ds)", fps->thd);
+	else
+		num += scnprintf(buf + num, size - num, "(avg)");
+
+	return num;
+}
+
+static int show_fps_info(struct vpu_fps_sts *fps, int count,
+			char *buf, u32 size)
+{
+	int i;
+	int num = 0;
+
+	for (i = 0; i < count; i++) {
+		if (i > 0)
+			num += scnprintf(buf + num, size - num, "  ");
+		num += show_single_fps_info(&fps[i], buf + num, size - num);
+	}
+
+	return num;
+}
+
+static int show_frame_sts(struct vpu_statistic *statistic, char *buf, u32 size)
+{
+	int num = 0;
+
+	num += scnprintf(buf + num, size - num,
+			"frame count:\n");
+	num += scnprintf(buf + num, size - num, "\t%-24s:%ld\n",
+			"dbuf input yuv count", statistic->yuv_count);
+	num += scnprintf(buf + num, size - num, "\t%-24s:%ld\n",
+			"encode frame count", statistic->encoded_count);
+	num += scnprintf(buf + num, size - num, "\t%-24s:%ld\n",
+			"dqbuf output h264 count", statistic->h264_count);
+
+	num += scnprintf(buf + num, size - num, "\t%-24s:", "actual fps:");
+	num += show_fps_info(statistic->fps, ARRAY_SIZE(statistic->fps),
+				buf + num, PAGE_SIZE - num);
+	num += scnprintf(buf + num, size - num, "\n");
+
+	return num;
+}
+
+static int show_strip_info(struct vpu_statistic *statistic, char *buf, u32 size)
+{
+	int num = 0;
+
+	num += scnprintf(buf + num, size - num,
+			"strip data frame count:\n");
+	num += scnprintf(buf + num, size - num,
+			"\t fw      :%16ld (max : %ld; total : %ld)\n",
+			statistic->strip_sts.fw.count,
+			statistic->strip_sts.fw.max,
+			statistic->strip_sts.fw.total);
+	num += scnprintf(buf + num, size - num,
+			"\t begin   :%16ld (max : %ld; total : %ld)\n",
+			statistic->strip_sts.begin.count,
+			statistic->strip_sts.begin.max,
+			statistic->strip_sts.begin.total);
+	num += scnprintf(buf + num, size - num,
+			"\t eos     :%16ld (max : %ld; total : %ld)\n",
+			statistic->strip_sts.eos.count,
+			statistic->strip_sts.eos.max,
+			statistic->strip_sts.eos.total);
+
+	return num;
+}
+
+static int show_v4l2_buf_status(struct vpu_ctx *ctx, char *buf, u32 size)
+{
+	int num = 0;
+
+	num += scnprintf(buf + num, size - num, "V4L2 Buffer Status: ");
+	num += scnprintf(buf + num, size - num, "(");
+	num += scnprintf(buf + num, size - num,
+			" %d:dequeued,", VB2_BUF_STATE_DEQUEUED);
+	num += scnprintf(buf + num, size - num,
+			" %d:active,", VB2_BUF_STATE_ACTIVE);
+	num += scnprintf(buf + num, size - num,
+			" %d:done,", VB2_BUF_STATE_DONE);
+	num += scnprintf(buf + num, size - num,
+			" %d:error", VB2_BUF_STATE_ERROR);
+	num += scnprintf(buf + num, size - num, ")\n");
+	num += scnprintf(buf + num, size - num, "\tOUTPUT(0x%lx):",
+			ctx->q_data[V4L2_SRC].rw_flag);
+	num += show_queue_buffer_info(&ctx->q_data[V4L2_SRC],
+					buf + num,
+					size - num);
+	num += scnprintf(buf + num, size - num, "    CAPTURE(0x%lx):",
+			ctx->q_data[V4L2_DST].rw_flag);
+	num += show_queue_buffer_info(&ctx->q_data[V4L2_DST],
+					buf + num,
+					size - num);
+	num += scnprintf(buf + num, size - num, "\n");
+
+	return num;
+}
+
+static int show_instance_status(struct vpu_ctx *ctx, char *buf, u32 size)
+{
+	int num = 0;
+
+	num += scnprintf(buf + num, size - num, "instance status:\n");
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%lx\n", "status", ctx->status);
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:%d\n", "frozen count", ctx->frozen_count);
+
+	return num;
+}
+
+static int show_instance_stream_buffer_desc(struct vpu_ctx *ctx,
+						char *buf, u32 size)
+{
+	pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc;
+	int num = 0;
+
+	stream_buffer_desc = get_rpc_stream_buffer_desc(ctx);
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%x\n", "start",
+			get_ptr(stream_buffer_desc->start));
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%x\n", "end",
+			get_ptr(stream_buffer_desc->end));
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%x\n", "rptr",
+			get_ptr(stream_buffer_desc->rptr));
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%x\n", "wptr",
+			get_ptr(stream_buffer_desc->wptr));
+	num += scnprintf(buf + num, size - num,
+			"\t%-13s:0x%x\n", "free space",
+			get_free_space(ctx));
+	return num;
+}
+
+static int show_instance_others(struct vpu_attr *attr, char *buf, u32 size)
+{
+	int num = 0;
+	struct vpu_ctx *ctx = NULL;
+	struct vpu_dev *vpudev = attr->core->vdev;
+
+	num += scnprintf(buf + num, size - num, "others:\n");
+	if (attr->ts_start[V4L2_SRC] && attr->ts_start[V4L2_DST]) {
+		unsigned long latency;
+
+		latency = attr->ts_start[V4L2_DST] - attr->ts_start[V4L2_SRC];
+		num += scnprintf(buf + num, size - num,
+				"\tlatency(ms)               :%ld\n", latency);
+	}
+
+	num += scnprintf(buf + num, size - num,
+			"\ttotal dma size            :%lld\n",
+			atomic64_read(&attr->total_dma_size));
+	num += scnprintf(buf + num, size - num,
+			"\ttotal event msg obj count :%ld\n",
+			attr->msg_count);
+	num += scnprintf(buf + num, size - num,
+			"\ttotal msg ext data count  :%lld\n",
+			get_total_ext_data_number());
+
+	mutex_lock(&vpudev->dev_mutex);
+	ctx = get_vpu_attr_ctx(attr);
+	if (ctx) {
+		num += scnprintf(buf + num, size - num,
+			"\tis the msg queue empty    :%d\n",
+			is_event_msg_empty(ctx));
+		num += scnprintf(buf + num, size - num,
+			"\ttotal frame obj count     :%lld\n",
+			atomic64_read(&ctx->q_data[V4L2_DST].frame_count));
+
+		if (test_bit(VPU_ENC_STATUS_HANG, &ctx->status))
+			num += scnprintf(buf + num, size - num, "<hang>\n");
+	} else {
+		num += scnprintf(buf + num, size - num,
+			"<instance has been released>\n");
+	}
+	mutex_unlock(&vpudev->dev_mutex);
+
+	return num;
+}
+
+static ssize_t show_instance_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_attr *vpu_attr;
+	struct vpu_dev *vpudev;
+	struct vpu_statistic *statistic;
+	struct vpu_ctx *ctx;
+	pMEDIAIP_ENC_PARAM param;
+	int num = 0;
+
+	vpu_attr = container_of(attr, struct vpu_attr,  dev_attr);
+	vpudev = vpu_attr->core->vdev;
+
+	num += scnprintf(buf + num, PAGE_SIZE,
+			"pid: %d; tgid: %d\n", vpu_attr->pid, vpu_attr->tgid);
+
+	param = rpc_get_enc_param(&vpu_attr->core->shared_mem, vpu_attr->index);
+	num += show_encoder_param(vpu_attr, param, buf + num, PAGE_SIZE - num);
+
+	statistic = &vpu_attr->statistic;
+	num += show_cmd_event_infos(statistic, buf + num, PAGE_SIZE - num);
+	num += show_frame_sts(statistic, buf + num, PAGE_SIZE - num);
+	num += show_strip_info(statistic, buf + num, PAGE_SIZE - num);
+
+	mutex_lock(&vpudev->dev_mutex);
+	ctx = get_vpu_attr_ctx(vpu_attr);
+	if (ctx) {
+		num += show_v4l2_buf_status(ctx, buf + num, PAGE_SIZE - num);
+		num += show_instance_status(ctx, buf + num, PAGE_SIZE - num);
+		num += show_instance_stream_buffer_desc(ctx,
+							buf + num,
+							PAGE_SIZE - num);
+	}
+	mutex_unlock(&vpudev->dev_mutex);
+
+	num += show_instance_others(vpu_attr, buf + num, PAGE_SIZE - num);
+
+	return num;
+}
+
+static ssize_t show_core_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct core_device *core = NULL;
+	char *fw = NULL;
+	int num = 0;
+
+	core = container_of(attr, struct core_device, core_attr);
+	fw = core->m0_p_fw_space_vir;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"core[%d] info:\n", core->id);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"vpu mu id       : %d\n", core->vpu_mu_id);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"irq             : %d\n", core->irq);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reg mu mcu      : 0x%08x 0x%08x\n",
+			core->reg_base, core->reg_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reg csr         : 0x%08x 0x%08x\n",
+			core->reg_csr_base, core->reg_csr_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"fw space phy    : 0x%08x\n", core->m0_p_fw_space_phy);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"fw space size   : 0x%08x\n", core->fw_buf_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"fw actual size  : 0x%08x\n", core->fw_actual_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"rpc phy         : 0x%08x\n", core->m0_rpc_phy);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"rpc buf size    : 0x%08x\n", core->rpc_buf_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"rpc actual size : 0x%08x\n", core->rpc_actual_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"print buf phy   : 0x%08x\n",
+			core->m0_rpc_phy + core->rpc_buf_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"print buf size  : 0x%08x\n", core->print_buf_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"max instance num: %d\n",
+			core->supported_instance_count);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"fw_is_ready     : %d\n", core->fw_is_ready);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"firmware_started: %d\n", core->firmware_started);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"hang            : %d\n", core->hang);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reset times     : %ld\n", core->reset_times);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"heartbeat       : %02x\n", core->vdev->heartbeat);
+	if (core->fw_is_ready) {
+		pENC_RPC_HOST_IFACE iface = core->shared_mem.pSharedInterface;
+
+		num += scnprintf(buf + num, PAGE_SIZE - num,
+			"firmware version: %d.%d.%d\n",
+			(iface->FWVersion & 0x00ff0000) >> 16,
+			(iface->FWVersion & 0x0000ff00) >> 8,
+			iface->FWVersion & 0x000000ff);
+		num += scnprintf(buf + num, PAGE_SIZE - num,
+			"fw info         : 0x%02x 0x%02x\n", fw[16], fw[17]);
+	}
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"driver version  : %s\n", VPU_ENC_DRIVER_VERSION);
+
+	return num;
+}
+
+static int show_vb2_memory(struct vb2_buffer *vb, char *buf, u32 size)
+{
+	int num = 0;
+	int i;
+
+	for (i = 0; i < vb->num_planes; i++) {
+		num += scnprintf(buf + num, size - num, "0x%8x 0x%x",
+				get_vb2_plane_phy_addr(vb, i),
+				vb->planes[i].length);
+		if (i == vb->num_planes - 1)
+			num += scnprintf(buf + num, size - num, "\n");
+		else
+			num += scnprintf(buf + num, size - num, "; ");
+	}
+
+	return num;
+}
+
+static int show_queue_memory(struct queue_data *queue, char *buf, u32 size,
+				char *prefix)
+{
+	int num = 0;
+	int i;
+
+	num += scnprintf(buf + num, size - num, "%s%4s v4l2buf  :\n", prefix,
+			queue->type == V4L2_SRC ? "YUV" : "H264");
+
+	for (i = 0; i < queue->vb2_q.num_buffers; i++) {
+		struct vb2_buffer *vb = queue->vb2_q.bufs[i];
+
+		num += scnprintf(buf + num, size - num, "%s%18s", prefix, "");
+		num += show_vb2_memory(vb, buf + num, size - num);
+	}
+
+	return num;
+}
+
+static int show_ctx_memory_details(struct vpu_ctx *ctx, char *buf, u32 size,
+				char *prefix)
+{
+	int num = 0;
+	int i;
+
+	if (!ctx)
+		return 0;
+
+	num += scnprintf(buf + num, size - num, "%smemory details:\n", prefix);
+	num += scnprintf(buf + num, size - num, "%sencFrames    :\n", prefix);
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++) {
+		num += scnprintf(buf + num, size - num, "%s%14s", prefix, "");
+		num += scnprintf(buf + num, size - num, "[%d] 0x%8llx 0x%x\n",
+				i,
+				ctx->encFrame[i].phy_addr,
+				ctx->encFrame[i].size);
+	}
+
+	num += scnprintf(buf + num, size - num, "%srefFrames    :\n", prefix);
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++) {
+		num += scnprintf(buf + num, size - num, "%s%14s", prefix, "");
+		num += scnprintf(buf + num, size - num, "[%d] 0x%8llx 0x%x\n",
+				i,
+				ctx->refFrame[i].phy_addr,
+				ctx->refFrame[i].size);
+	}
+
+	num += scnprintf(buf + num, size - num, "%sactFrames    :\n", prefix);
+	num += scnprintf(buf + num, size - num, "%s%18s", prefix, "");
+	num += scnprintf(buf + num, size - num, "0x%8llx 0x%x\n",
+			ctx->actFrame.phy_addr, ctx->actFrame.size);
+
+	num += scnprintf(buf + num, size - num, "%sencoderStream:\n", prefix);
+	num += scnprintf(buf + num, size - num, "%s%18s", prefix, "");
+	num += scnprintf(buf + num, size - num, "0x%8llx 0x%x\n",
+			ctx->encoder_stream.phy_addr, ctx->encoder_stream.size);
+
+	for (i = 0; i < ARRAY_SIZE(ctx->q_data); i++) {
+		struct queue_data *queue = &ctx->q_data[i];
+
+		if (queue->vb2_q.memory != V4L2_MEMORY_MMAP)
+			continue;
+		if (queue->vb2_q.mem_ops != &vb2_dma_contig_memops)
+			continue;
+
+		num += show_queue_memory(queue, buf + num, size - num, prefix);
+	}
+
+	return num;
+}
+
+static ssize_t show_memory_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	unsigned long total_dma_size = 0;
+	int num = 0;
+	int i;
+	int j;
+	int core_id = (show_detail_index >> 8) & 0xff;
+	int ctx_id = show_detail_index & 0xff;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num, "dma memory usage:\n");
+	for (i = 0; i < vdev->core_num; i++) {
+		struct core_device *core = &vdev->core_dev[i];
+
+		num += scnprintf(buf + num, PAGE_SIZE - num, "core[%d]\n", i);
+
+		for (j = 0; j < ARRAY_SIZE(core->attr); j++) {
+			struct vpu_attr *attr_loc = &core->attr[j];
+			unsigned long size;
+
+			size = atomic64_read(&attr_loc->total_dma_size);
+			total_dma_size += size;
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+					"\t[%d] : %ld\n", j, size);
+			if (core_id != i || ctx_id != j)
+				continue;
+			mutex_lock(&vdev->dev_mutex);
+			num += show_ctx_memory_details(core->ctx[j],
+							buf + num,
+							PAGE_SIZE - num,
+							"\t\t");
+			mutex_unlock(&vdev->dev_mutex);
+		}
+	}
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"total dma             : %ld\n", total_dma_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"total reserved memory : %ld\n",
+			vdev->reserved_mem.bytesused);
+	show_detail_index = VPU_DETAIL_INDEX_DFT;
+
+	return num;
+}
+
+static ssize_t store_memory_info_index(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	long val = VPU_DETAIL_INDEX_DFT;
+
+	if (!kstrtol(buf, 0, &val))
+		show_detail_index = val;
+
+	return count;
+}
+DEVICE_ATTR(meminfo, 0664, show_memory_info, store_memory_info_index);
+
+static ssize_t show_buffer_info(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	int num = 0;
+	int i;
+	int j;
+
+	mutex_lock(&vdev->dev_mutex);
+	num += scnprintf(buf + num, PAGE_SIZE - num, "vpu encoder buffers:\t");
+	num += scnprintf(buf + num, PAGE_SIZE - num, "(");
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			" %d:dequeued,", VB2_BUF_STATE_DEQUEUED);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			" %d:active,", VB2_BUF_STATE_ACTIVE);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			" %d:done,", VB2_BUF_STATE_DONE);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			" %d:error", VB2_BUF_STATE_ERROR);
+	num += scnprintf(buf + num, PAGE_SIZE - num, ")\n");
+
+	for (i = 0; i < vdev->core_num; i++) {
+		struct core_device *core = &vdev->core_dev[i];
+
+		if (!core->supported_instance_count)
+			continue;
+
+		num += scnprintf(buf + num, PAGE_SIZE - num, "core[%d]\n", i);
+		for (j = 0; j < core->supported_instance_count; j++) {
+			struct vpu_ctx *ctx = core->ctx[j];
+
+			if (!ctx)
+				continue;
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+					"\t[%d]: ", j);
+			num += scnprintf(buf + num,
+					PAGE_SIZE - num, "OUTPUT:");
+			num += show_queue_buffer_info(&ctx->q_data[V4L2_SRC],
+							buf + num,
+							PAGE_SIZE - num);
+			num += scnprintf(buf + num,
+					PAGE_SIZE - num, "    CAPTURE:");
+			num += show_queue_buffer_info(&ctx->q_data[V4L2_DST],
+							buf + num,
+							PAGE_SIZE - num);
+			num += scnprintf(buf + num, PAGE_SIZE - num, "\n");
+		}
+	}
+	mutex_unlock(&vdev->dev_mutex);
+
+	return num;
+}
+DEVICE_ATTR(buffer, 0444, show_buffer_info, NULL);
+
+static ssize_t show_fpsinfo(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	int num = 0;
+	int i;
+	int j;
+
+	for (i = 0; i < vdev->core_num; i++) {
+		struct core_device *core = &vdev->core_dev[i];
+
+		if (!core->supported_instance_count)
+			continue;
+
+		num += scnprintf(buf + num, PAGE_SIZE - num, "core[%d]\n", i);
+		for (j = 0; j < core->supported_instance_count; j++) {
+			struct vpu_attr *attr = &core->attr[j];
+
+			if (!attr->created)
+				continue;
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+					"\t[%d]", j);
+			num += scnprintf(buf + num, PAGE_SIZE - num,
+					"  %3d(%d / %d)(setting)  ",
+					attr->param.uFrameRate,
+					attr->fival.numerator,
+					attr->fival.denominator);
+			num += show_fps_info(attr->statistic.fps,
+					ARRAY_SIZE(attr->statistic.fps),
+					buf + num, PAGE_SIZE - num);
+			num += scnprintf(buf + num, PAGE_SIZE - num, "\n");
+		}
+	}
+
+	return num;
+}
+DEVICE_ATTR(fpsinfo, 0444, show_fpsinfo, NULL);
+
+static ssize_t show_vpuinfo(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct vpu_dev *vdev = dev_get_drvdata(dev);
+	int num = 0;
+
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"core number          : %d\n", vdev->core_num);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"platform type        : %d\n", vdev->plat_type);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reg-vpu              : 0x%8x 0x%08x\n",
+			vdev->reg_vpu_base, vdev->reg_vpu_size);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reg-rpc-system       : 0x%08x\n",
+			vdev->reg_rpc_system);
+	num += scnprintf(buf + num, PAGE_SIZE - num,
+			"reserved-memory      : 0x%08lx 0x%08lx\n",
+			vdev->reserved_mem.phy_addr, vdev->reserved_mem.size);
+	num += scnprintf(buf + num, PAGE_SIZE - num, "supported resolution :");
+	num += scnprintf(buf + num, PAGE_SIZE - num, " %dx%d(min);",
+			vdev->supported_size.min_width,
+			vdev->supported_size.min_height);
+	num += scnprintf(buf + num, PAGE_SIZE - num, " %dx%d(step);",
+			vdev->supported_size.step_width,
+			vdev->supported_size.step_height);
+	num += scnprintf(buf + num, PAGE_SIZE - num, " %dx%d(max)\n",
+			vdev->supported_size.max_width,
+			vdev->supported_size.max_height);
+
+	return num;
+}
+DEVICE_ATTR(vpuinfo, 0444, show_vpuinfo, NULL);
+
+static void reset_statistic(struct vpu_attr *attr)
+{
+	if (!attr)
+		return;
+
+	memset(&attr->statistic, 0, sizeof(attr->statistic));
+	attr->statistic.current_cmd = GTB_ENC_CMD_NOOP;
+	attr->statistic.current_event = VID_API_EVENT_UNDEFINED;
+}
+
+static int init_vpu_attr_fps_sts(struct vpu_attr *attr)
+{
+	const unsigned int THDS[] = VPU_FPS_STS_THDS;
+	int i;
+
+	for (i = 0; i < VPU_FPS_STS_CNT; i++) {
+		if (i < ARRAY_SIZE(THDS))
+			attr->statistic.fps[i].thd = THDS[i];
+		else
+			attr->statistic.fps[i].thd = 0;
+	}
+
+	return 0;
+}
+
+static int enable_fps_sts(struct vpu_attr *attr)
+{
+	int i;
+	struct vpu_statistic *sts = &attr->statistic;
+
+	sts->fps_sts_enable = true;
+
+	for (i = 0; i < VPU_FPS_STS_CNT; i++) {
+		ktime_get_raw_ts64(&sts->fps[i].ts);
+		sts->fps[i].frame_number = sts->encoded_count;
+	}
+
+	return 0;
+}
+
+static int disable_fps_sts(struct vpu_attr *attr)
+{
+	attr->statistic.fps_sts_enable = false;
+
+	return 0;
+}
+
+static int init_vpu_attr(struct vpu_attr *attr)
+{
+	if (!attr || !attr->core)
+		return -EINVAL;
+
+	reset_statistic(attr);
+	memset(&attr->param, 0, sizeof(attr->param));
+	attr->pid = current->pid;
+	attr->tgid = current->tgid;
+	if (!attr->created) {
+		device_create_file(attr->core->generic_dev, &attr->dev_attr);
+		attr->created = true;
+	}
+
+	init_vpu_attr_fps_sts(attr);
+
+	return 0;
+}
+
+static int release_instance(struct vpu_ctx *ctx)
+{
+	struct vpu_dev *dev;
+
+	if (!ctx || !ctx->dev)
+		return -EINVAL;
+
+	if (!test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		return 0;
+	if (!test_bit(VPU_ENC_STATUS_FORCE_RELEASE, &ctx->status)) {
+		if (test_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status) &&
+			!test_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status))
+			return -EINVAL;
+	}
+
+	dev = ctx->dev;
+
+	uninit_vpu_ctx(ctx);
+	vpu_enc_free_ctrls(ctx);
+	vpu_enc_release_queue_data(ctx);
+	vpu_enc_free_mem(ctx, get_rpc_mem_pool(ctx));
+
+	vpu_ctx_power_off(ctx);
+	free_instance(ctx);
+
+	return 0;
+}
+
+static int try_to_release_idle_instance(struct vpu_dev *dev)
+{
+	int i;
+	int j;
+
+	if (!dev)
+		return -EINVAL;
+
+	for (i = 0; i < dev->core_num; i++) {
+		if (dev->core_dev[i].hang)
+			set_core_force_release(&dev->core_dev[i]);
+		for (j = 0; j < dev->core_dev[i].supported_instance_count; j++)
+			release_instance(dev->core_dev[i].ctx[j]);
+	}
+
+	return 0;
+}
+
+struct vpu_attr *get_vpu_ctx_attr(struct vpu_ctx *ctx)
+{
+	WARN_ON(!ctx || !ctx->core_dev);
+
+	if (ctx->str_index >= ctx->core_dev->supported_instance_count)
+		return NULL;
+
+	return &ctx->core_dev->attr[ctx->str_index];
+}
+
+struct vpu_ctx *get_vpu_attr_ctx(struct vpu_attr *attr)
+{
+	WARN_ON(!attr || !attr->core);
+
+	if (attr->index >= attr->core->supported_instance_count)
+		return NULL;
+
+	return attr->core->ctx[attr->index];
+}
+
+static int vpu_enc_v4l2_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct vpu_dev *dev = video_get_drvdata(vdev);
+	struct vpu_ctx *ctx = NULL;
+	int ret;
+
+	vpu_log_func();
+
+	mutex_lock(&dev->dev_mutex);
+	try_to_release_idle_instance(dev);
+
+	pm_runtime_get_sync(dev->generic_dev);
+	ctx = create_and_request_instance(dev);
+	pm_runtime_put_sync(dev->generic_dev);
+	if (!ctx) {
+		mutex_unlock(&dev->dev_mutex);
+		vpu_err("failed to create encoder ctx\n");
+		return -ENOMEM;
+	}
+	vpu_dbg(LVL_FLOW, "[%d:%d] open\n",
+			ctx->core_dev->id, ctx->str_index);
+
+	init_vpu_attr(get_vpu_ctx_attr(ctx));
+	ret = init_vpu_ctx(ctx);
+	if (ret) {
+		mutex_unlock(&dev->dev_mutex);
+		vpu_err("init vpu ctx fail\n");
+		goto error;
+	}
+
+	initialize_enc_param(ctx);
+	vpu_enc_setup_ctrls(ctx);
+
+	init_vpu_ctx_fh(ctx, dev);
+	init_ctx_seq_info(ctx);
+	filp->private_data = &ctx->fh;
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+error:
+	mutex_lock(&dev->dev_mutex);
+	set_bit(VPU_ENC_STATUS_FORCE_RELEASE, &ctx->status);
+	VPU_SAFE_RELEASE(ctx, release_instance);
+	mutex_unlock(&dev->dev_mutex);
+	return ret;
+}
+
+static int vpu_enc_v4l2_release(struct file *filp)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+	struct vpu_dev *dev = ctx->dev;
+
+	vpu_log_func();
+
+	vpu_dbg(LVL_FLOW, "[%d:%d] close\n",
+			ctx->core_dev->id, ctx->str_index);
+	wait_for_start_done(ctx);
+	request_eos(ctx);
+	wait_for_stop_done(ctx);
+
+	mutex_lock(&dev->dev_mutex);
+
+	uninit_vpu_ctx_fh(ctx);
+	filp->private_data = NULL;
+
+	VPU_SAFE_RELEASE(ctx, release_instance);
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+}
+
+static unsigned int vpu_enc_v4l2_poll(struct file *filp, poll_table *wait)
+{
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+	struct vb2_queue *src_q, *dst_q;
+	unsigned int rc = 0;
+
+	vpu_dbg(LVL_FUNC, "%s(), event: 0x%lx\n", __func__,
+			(unsigned long)poll_requested_events(wait));
+
+	poll_wait(filp, &ctx->fh.wait, wait);
+
+	if (v4l2_event_pending(&ctx->fh)) {
+		vpu_dbg(LVL_DEBUG, "%s() v4l2_event_pending\n", __func__);
+		rc |= POLLPRI;
+	}
+
+	src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+	dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+	if ((!src_q->streaming || list_empty(&src_q->queued_list))
+		&& (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+		rc |= POLLERR;
+		return rc;
+	}
+	if (test_bit(VPU_ENC_STATUS_EOS_SEND, &ctx->status) &&
+			!list_empty(&dst_q->done_list))
+		rc &= ~POLLPRI;
+
+	poll_wait(filp, &src_q->done_wq, wait);
+	if (!list_empty(&src_q->done_list))
+		rc |= POLLOUT | POLLWRNORM;
+	poll_wait(filp, &dst_q->done_wq, wait);
+	if (!list_empty(&dst_q->done_list))
+		rc |= POLLIN | POLLRDNORM;
+	if (dst_q->last_buffer_dequeued)
+		rc |= POLLIN | POLLRDNORM;
+
+	return rc;
+}
+
+static int vpu_enc_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	long ret = -EPERM;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct queue_data *q_data;
+	enum QUEUE_TYPE type;
+
+	struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+	vpu_log_func();
+
+	if (ctx) {
+		type = offset >> MMAP_BUF_TYPE_SHIFT;
+		q_data = &ctx->q_data[type];
+
+		offset &= ~MMAP_BUF_TYPE_MASK;
+		offset = offset >> PAGE_SHIFT;
+		vma->vm_pgoff = offset;
+		ret = vpu_enc_queue_mmap(q_data, vma);
+	}
+
+	return ret;
+}
+
+static const struct v4l2_file_operations vpu_enc_v4l2_fops = {
+	.owner = THIS_MODULE,
+	.open  = vpu_enc_v4l2_open,
+	.unlocked_ioctl = video_ioctl2,
+	.release = vpu_enc_v4l2_release,
+	.poll = vpu_enc_v4l2_poll,
+	.mmap = vpu_enc_v4l2_mmap,
+};
+
+static struct video_device vpu_enc_v4l2_videodevice = {
+	.name   = "vpu encoder",
+	.fops   = &vpu_enc_v4l2_fops,
+	.ioctl_ops = &vpu_enc_v4l2_ioctl_ops,
+	.vfl_dir = VFL_DIR_M2M,
+};
+
+static void vpu_enc_setup(struct vpu_dev *This)
+{
+	const off_t offset = SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL;
+	uint32_t read_data = 0;
+
+	vpu_log_func();
+
+	write_vpu_reg(This, 0x1, offset + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+	write_vpu_reg(This, 0xffffffff, 0x70190);
+	write_vpu_reg(This, 0xffffffff, offset + SCB_BLK_CTRL_XMEM_RESET_SET);
+	write_vpu_reg(This, 0xE, offset + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+	write_vpu_reg(This, 0x7, offset + SCB_BLK_CTRL_CACHE_RESET_SET);
+	write_vpu_reg(This, 0x102, XMEM_CONTROL);
+
+	read_data = read_vpu_reg(This, 0x70108);
+	vpu_dbg(LVL_IRQ, "%s read_data=%x\n", __func__, read_data);
+}
+
+static int vpu_enc_enable_hw(struct vpu_dev *This)
+{
+	vpu_log_func();
+	if (This->hw_enable)
+		return 0;
+	vpu_enc_setup(This);
+
+	This->hw_enable = true;
+
+	return 0;
+}
+
+static void vpu_enc_disable_hw(struct vpu_dev *This)
+{
+	This->hw_enable = false;
+	if (This->regs_base) {
+		iounmap(This->regs_base);
+		This->regs_base = NULL;
+	}
+}
+
+static int parse_core_info(struct core_device *core, struct device_node *np)
+{
+	int ret;
+	u32 val;
+
+	WARN_ON(!core || !np);
+
+	ret = of_property_read_u32_index(np, "reg", 0, &val);
+	if (ret) {
+		vpu_err("find reg for core[%d] fail\n", core->id);
+		return ret;
+	}
+	core->reg_base = val;
+
+	ret = of_property_read_u32_index(np, "reg", 1, &val);
+	if (ret) {
+		vpu_err("find reg for core[%d] fail\n", core->id);
+		return ret;
+	}
+	core->reg_size = val;
+
+	ret = of_property_read_u32_index(np, "reg-csr", 0, &val);
+	if (ret) {
+		vpu_err("find reg-csr for core[%d] fail\n", core->id);
+		return ret;
+	}
+	core->reg_csr_base = val;
+
+	ret = of_property_read_u32_index(np, "reg-csr", 1, &val);
+	if (ret) {
+		vpu_err("find reg-csr for core[%d] fail\n", core->id);
+		return ret;
+	}
+	core->reg_csr_size = val;
+
+	ret = of_irq_get(np, 0);
+	if (ret < 0) {
+		vpu_err("get irq for core[%d] fail\n", core->id);
+		return -EINVAL;
+	}
+	core->irq = ret;
+
+	ret = of_property_read_u32(np, "fsl,vpu_ap_mu_id", &val);
+	if (!ret)
+		core->vpu_mu_id = val;
+
+	ret = of_property_read_u32(np, "fw-buf-size", &val);
+	if (ret) {
+		vpu_err("find fw-buf-size for core[%d] fail\n", core->id);
+		core->fw_buf_size = M0_BOOT_SIZE_DEFAULT;
+	} else {
+		core->fw_buf_size = val;
+	}
+	core->fw_buf_size = max_t(u32, core->fw_buf_size, M0_BOOT_SIZE_MIN);
+
+	ret = of_property_read_u32(np, "rpc-buf-size", &val);
+	if (ret) {
+		vpu_err("find rpc-buf-size for core[%d] fail\n", core->id);
+		core->rpc_buf_size = RPC_SIZE_DEFAULT;
+	} else {
+		core->rpc_buf_size = val;
+	}
+	core->rpc_buf_size = max_t(u32, core->rpc_buf_size, RPC_SIZE_MIN);
+
+	ret = of_property_read_u32(np, "print-buf-size", &val);
+	if (ret) {
+		vpu_err("find print-buf-size for core[%d] fail\n", core->id);
+		core->print_buf_size = PRINT_SIZE_DEFAULT;
+	} else {
+		core->print_buf_size = val;
+	}
+	core->print_buf_size = max_t(u32, core->print_buf_size, PRINT_SIZE_MIN);
+
+	return 0;
+}
+
+static int parse_dt_cores(struct vpu_dev *dev, struct device_node *np)
+{
+	char core_name[64];
+	struct device_node *node = NULL;
+	struct core_device *core = NULL;
+	int i;
+	int ret;
+
+	dev->core_num = 0;
+	for (i = 0; i < VPU_ENC_MAX_CORE_NUM; i++) {
+		scnprintf(core_name, sizeof(core_name), "core%d", i);
+		node = of_find_node_by_name(of_node_get(np), core_name);
+		if (!node) {
+			vpu_dbg(LVL_INFO, "can't find %s\n", core_name);
+			break;
+		}
+
+		core = &dev->core_dev[i];
+		core->id = i;
+		ret = parse_core_info(core, node);
+		of_node_put(node);
+		node = NULL;
+		if (ret) {
+			vpu_err("parse core[%d] fail\n", i);
+			break;
+		}
+	}
+	if (i == 0)
+		return -EINVAL;
+
+	dev->core_num = i;
+
+	return 0;
+}
+
+static int parse_dt_info(struct vpu_dev *dev, struct device_node *np)
+{
+	int ret;
+	struct device_node *reserved_node = NULL;
+	struct resource reserved_fw;
+	struct resource reserved_rpc;
+	struct resource reserved_mem;
+	u32 fw_total_size = 0;
+	u32 rpc_total_size = 0;
+	u32 val;
+	u32 i;
+
+	if (!dev || !np)
+		return -EINVAL;
+
+	ret = of_property_read_u32_index(np, "reg-rpc-system", 0, &val);
+	if (ret) {
+		vpu_err("get reg-rpc-system fail\n");
+		return -EINVAL;
+	}
+	dev->reg_rpc_system = val;
+
+	reserved_node = of_parse_phandle(np, "boot-region", 0);
+	if (!reserved_node) {
+		vpu_err("error: boot-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+	if (of_address_to_resource(reserved_node, 0, &reserved_fw)) {
+		vpu_err("error: boot-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+
+	reserved_node = of_parse_phandle(np, "rpc-region", 0);
+	if (!reserved_node) {
+		vpu_err("error: rpc-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+	if (of_address_to_resource(reserved_node, 0, &reserved_rpc)) {
+		vpu_err("error: rpc-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+
+	reserved_node = of_parse_phandle(np, "reserved-region", 0);
+	if (!reserved_node) {
+		vpu_err("error: rpc-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+	if (of_address_to_resource(reserved_node, 0, &reserved_mem)) {
+		vpu_err("error: rpc-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+	dev->reserved_mem.phy_addr = reserved_mem.start;
+	dev->reserved_mem.size = resource_size(&reserved_mem);
+
+	ret = parse_dt_cores(dev, np);
+	if (ret) {
+		vpu_err("parse cores from dt fail\n");
+		return ret;
+	}
+
+	fw_total_size = 0;
+	rpc_total_size = 0;
+	for (i = 0; i < dev->core_num; i++) {
+		struct core_device *core = &dev->core_dev[i];
+
+		core->m0_p_fw_space_phy = reserved_fw.start + fw_total_size;
+		core->m0_rpc_phy = reserved_rpc.start + rpc_total_size;
+		fw_total_size += core->fw_buf_size;
+		rpc_total_size += core->rpc_buf_size;
+		rpc_total_size += core->print_buf_size;
+	}
+
+	if (fw_total_size > resource_size(&reserved_fw)) {
+		vpu_err("boot-region's size(0x%llx) is less than wanted:0x%x\n",
+				resource_size(&reserved_fw), fw_total_size);
+		return -EINVAL;
+	}
+	if (rpc_total_size > resource_size(&reserved_rpc)) {
+		vpu_err("rpc-region's size(0x%llx) is less than wanted:0x%x\n",
+				resource_size(&reserved_rpc), rpc_total_size);
+		return -EINVAL;
+	}
+
+	dev->supported_size.min_width = VPU_ENC_WIDTH_MIN;
+	dev->supported_size.max_width = VPU_ENC_WIDTH_MAX;
+	dev->supported_size.step_width = VPU_ENC_WIDTH_STEP;
+	dev->supported_size.min_height = VPU_ENC_HEIGHT_MIN;
+	dev->supported_size.max_height = VPU_ENC_HEIGHT_MAX;
+	dev->supported_size.step_height = VPU_ENC_HEIGHT_STEP;
+
+	ret = of_property_read_u32_index(np, "resolution-max", 0, &val);
+	if (!ret)
+		dev->supported_size.max_width = val;
+
+	ret = of_property_read_u32_index(np, "resolution-max", 1, &val);
+	if (!ret)
+		dev->supported_size.max_height = val;
+
+	return 0;
+}
+
+static int create_vpu_video_device(struct vpu_dev *dev)
+{
+	int ret;
+
+	dev->pvpu_encoder_dev = video_device_alloc();
+	if (!dev->pvpu_encoder_dev) {
+		vpu_err("alloc vpu encoder video device fail\n");
+		return -ENOMEM;
+	}
+
+	strlcpy(dev->pvpu_encoder_dev->name,
+		vpu_enc_v4l2_videodevice.name,
+		sizeof(dev->pvpu_encoder_dev->name));
+	dev->pvpu_encoder_dev->fops = vpu_enc_v4l2_videodevice.fops;
+	dev->pvpu_encoder_dev->ioctl_ops = vpu_enc_v4l2_videodevice.ioctl_ops;
+	dev->pvpu_encoder_dev->release = video_device_release;
+	dev->pvpu_encoder_dev->vfl_dir = vpu_enc_v4l2_videodevice.vfl_dir;
+	dev->pvpu_encoder_dev->v4l2_dev = &dev->v4l2_dev;
+	dev->pvpu_encoder_dev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
+					     V4L2_CAP_STREAMING;
+
+	video_set_drvdata(dev->pvpu_encoder_dev, dev);
+
+	ret = video_register_device(dev->pvpu_encoder_dev,
+					VFL_TYPE_GRABBER,
+					ENCODER_NODE_NUMBER);
+	if (ret) {
+		vpu_err("unable to register video encoder device\n");
+		video_device_release(dev->pvpu_encoder_dev);
+		dev->pvpu_encoder_dev = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static int init_vpu_attrs(struct core_device *core)
+{
+	int i;
+
+	WARN_ON(!core);
+
+	for (i = 0; i < ARRAY_SIZE(core->attr); i++) {
+		struct vpu_attr *attr = &core->attr[i];
+
+		attr->core = core;
+		attr->index = i;
+		scnprintf(attr->name, sizeof(attr->name) - 1, "instance.%d.%d",
+				core->id, attr->index);
+		sysfs_attr_init(&attr->dev_attr.attr);
+		attr->dev_attr.attr.name = attr->name;
+		attr->dev_attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+		attr->dev_attr.show = show_instance_info;
+
+		atomic64_set(&attr->total_dma_size, 0);
+
+		attr->created = false;
+	}
+
+	return 0;
+}
+
+static int release_vpu_attrs(struct core_device *core)
+{
+	int i;
+
+	WARN_ON(!core);
+
+	for (i = 0; i < ARRAY_SIZE(core->attr); i++) {
+		struct vpu_attr *attr = &core->attr[i];
+
+		if (!attr->created)
+			continue;
+		device_remove_file(attr->core->generic_dev, &attr->dev_attr);
+	}
+
+	return 0;
+}
+
+static int is_ctx_frozen(struct vpu_ctx *ctx)
+{
+	int is_frozen = 1;
+	int i;
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	for (i = 0; i < GTB_ENC_CMD_RESERVED; i++) {
+		if (attr->statistic.cmd[i] != ctx->sts.cmd[i])
+			is_frozen = 0;
+		ctx->sts.cmd[i] = attr->statistic.cmd[i];
+	}
+
+	for (i = 0; i < VID_API_ENC_EVENT_RESERVED; i++) {
+		if (attr->statistic.event[i] != ctx->sts.event[i])
+			is_frozen = 0;
+		ctx->sts.event[i] = attr->statistic.event[i];
+	}
+
+	if (ctx->sts.cmd[GTB_ENC_CMD_FRAME_ENCODE] ==
+			ctx->sts.event[VID_API_ENC_EVENT_FRAME_DONE])
+		is_frozen = 0;
+
+	if (ctx->sts.cmd[GTB_ENC_CMD_CONFIGURE_CODEC] >
+			ctx->sts.event[VID_API_ENC_EVENT_MEM_REQUEST])
+		is_frozen = 1;
+	if (ctx->sts.cmd[GTB_ENC_CMD_STREAM_START] >
+			ctx->sts.event[VID_API_ENC_EVENT_START_DONE])
+		is_frozen = 1;
+	if (ctx->sts.cmd[GTB_ENC_CMD_STREAM_STOP] >
+			ctx->sts.event[VID_API_ENC_EVENT_STOP_DONE])
+		is_frozen = 1;
+
+	return is_frozen;
+}
+
+static bool check_vpu_ctx_is_hang(struct vpu_ctx *ctx)
+{
+	if (is_ctx_frozen(ctx))
+		ctx->frozen_count++;
+	else
+		ctx->frozen_count = 0;
+
+	if (ctx->frozen_count > VPU_ENC_HANG_THD) {
+		set_bit(VPU_ENC_STATUS_HANG, &ctx->status);
+		ctx->frozen_count = VPU_ENC_HANG_THD;
+	} else if (ctx->frozen_count == 0) {
+		clear_bit(VPU_ENC_STATUS_HANG, &ctx->status);
+	}
+
+	if (test_bit(VPU_ENC_STATUS_HANG, &ctx->status))
+		return true;
+
+	return false;
+}
+
+static void check_vpu_core_is_hang(struct core_device *core)
+{
+	int i;
+	unsigned int instance_count = 0;
+	unsigned int hang_count = 0;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (!core->ctx[i])
+			continue;
+
+		if (check_vpu_ctx_is_hang(core->ctx[i]))
+			hang_count++;
+		instance_count++;
+	}
+
+	if (!instance_count)
+		return;
+	if (hang_count == instance_count)
+		set_core_hang(core);
+	else
+		clear_core_hang(core);
+}
+
+static void handle_vpu_core_watchdog(struct core_device *core)
+{
+	if (!core->fw_is_ready)
+		return;
+	if (core->suspend)
+		return;
+	if (core->snapshot)
+		return;
+
+	queue_work(core->workqueue, &core->msg_work);
+	vpu_enc_notify_msg_event(core);
+	check_vpu_core_is_hang(core);
+}
+
+static unsigned long get_timestamp_ns(struct timespec64 *ts)
+{
+	if (!ts)
+		return 0;
+
+	return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
+}
+
+static void calc_rt_fps(struct vpu_fps_sts *fps,
+			unsigned long number, struct timespec64 *ts)
+{
+	unsigned long delta_num;
+	unsigned long delta_ts;
+
+	if (!fps || !ts)
+		return;
+
+	fps->times++;
+	if (fps->times < fps->thd)
+		return;
+
+	if (number >= fps->frame_number) {
+		delta_num = number - fps->frame_number;
+		delta_ts = get_timestamp_ns(ts) - get_timestamp_ns(&fps->ts);
+		if (!delta_ts)
+			return;
+		fps->fps = delta_num * NSEC_PER_SEC * VPU_FPS_COEF / delta_ts;
+	}
+	fps->times = 0;
+	if (fps->thd) {
+		fps->frame_number = number;
+		memcpy(&fps->ts, ts, sizeof(fps->ts));
+	}
+}
+
+static void statistic_fps_info(struct vpu_statistic *sts)
+{
+	unsigned long encoded_count = sts->encoded_count;
+	struct timespec64 ts;
+	int i;
+
+	if (!sts->fps_sts_enable)
+		return;
+	ktime_get_raw_ts64(&ts);
+	for (i = 0; i < VPU_FPS_STS_CNT; i++)
+		calc_rt_fps(&sts->fps[i], encoded_count, &ts);
+}
+
+static void handle_core_minors(struct core_device *core)
+{
+	int i;
+
+	for (i = 0; i < core->supported_instance_count; i++)
+		statistic_fps_info(&core->attr[i].statistic);
+}
+
+static void vpu_enc_watchdog_handler(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct vpu_dev *vdev;
+	int i;
+
+	if (!work)
+		return;
+
+	dwork = to_delayed_work(work);
+	vdev = container_of(dwork, struct vpu_dev, watchdog);
+
+	mutex_lock(&vdev->dev_mutex);
+	for (i = 0; i < vdev->core_num; i++)
+		handle_vpu_core_watchdog(&vdev->core_dev[i]);
+	mutex_unlock(&vdev->dev_mutex);
+
+	for (i = 0; i < vdev->core_num; i++)
+		handle_core_minors(&vdev->core_dev[i]);
+
+	vdev->heartbeat++;
+	schedule_delayed_work(&vdev->watchdog,
+			msecs_to_jiffies(VPU_WATCHDOG_INTERVAL_MS));
+}
+
+static int fwlog_show(struct seq_file *s, void *data)
+{
+	struct core_device *core = s->private;
+	int length;
+	u32 rptr;
+	u32 wptr;
+	int ret = 0;
+
+	if (!core->print_buf)
+		return 0;
+
+	rptr = core->print_buf->read;
+	wptr = core->print_buf->write;
+
+	if (rptr == wptr)
+		return 0;
+	else if (rptr < wptr)
+		length = wptr - rptr;
+	else
+		length = core->print_buf->bytes + wptr - rptr;
+
+	if (s->count + length >= s->size) {
+		s->count = s->size;
+		return 0;
+	}
+
+	if (rptr + length > core->print_buf->bytes) {
+		int num = core->print_buf->bytes - rptr;
+
+		if (seq_write(s, core->print_buf->buffer + rptr, num))
+			ret = -1;
+		length -= num;
+		rptr = 0;
+	}
+
+	if (seq_write(s, core->print_buf->buffer + rptr, length))
+		ret = -1;
+	rptr += length;
+	rptr %= core->print_buf->bytes;
+	if (!ret)
+		core->print_buf->read = rptr;
+
+	return 0;
+}
+
+static int fwlog_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, fwlog_show, inode->i_private);
+}
+
+static const struct file_operations fwlog_fops = {
+	.owner = THIS_MODULE,
+	.open = fwlog_open,
+	.release = single_release,
+	.read = seq_read,
+};
+
+static void vpu_enc_create_debugfs_file(struct vpu_dev *dev)
+{
+	struct core_device *core;
+	char name[64];
+	int i;
+
+	if (dev->debugfs_root == NULL) {
+		dev->debugfs_root = debugfs_create_dir("vpu_windsor", NULL);
+		if (!dev->debugfs_root) {
+			vpu_err("error: create debugfs_root fail\n");
+			return;
+		}
+	}
+
+	for (i = 0; i < dev->core_num; i++) {
+		core = &dev->core_dev[i];
+
+		if (core->debugfs_fwlog)
+			continue;
+
+		scnprintf(name, sizeof(name), "vpu_windsor_log%d", i);
+		core->debugfs_fwlog = debugfs_create_file((const char *)name,
+						VERIFY_OCTAL_PERMISSIONS(0444),
+						dev->debugfs_root,
+						core,
+						&fwlog_fops);
+		if (!core->debugfs_fwlog) {
+			vpu_err("error: create debugfs_fwlog fail\n");
+			continue;
+		}
+	}
+}
+
+static void vpu_enc_remove_debugfs_file(struct vpu_dev *dev)
+{
+	struct core_device *core;
+	int i;
+
+	if (!dev)
+		return;
+
+	for (i = 0; i < dev->core_num; i++) {
+		core = &dev->core_dev[i];
+
+		debugfs_remove(core->debugfs_fwlog);
+		core->debugfs_fwlog = NULL;
+	}
+	debugfs_remove_recursive(dev->debugfs_root);
+	dev->debugfs_root = NULL;
+}
+
+static void vpu_enc_init_core_rpc(struct core_device *core_dev)
+{
+	u32 mu_addr;
+
+	cleanup_firmware_memory(core_dev);
+	memset_io(core_dev->m0_rpc_virt, 0, core_dev->rpc_buf_size);
+
+	rpc_init_shared_memory_encoder(&core_dev->shared_mem,
+				cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy),
+				core_dev->m0_rpc_virt, core_dev->rpc_buf_size,
+				&core_dev->rpc_actual_size);
+	rpc_set_system_cfg_value_encoder(core_dev->shared_mem.pSharedInterface,
+				core_dev->vdev->reg_rpc_system, core_dev->id);
+
+	if (core_dev->rpc_actual_size > core_dev->rpc_buf_size)
+		vpu_err("rpc actual size(0x%x) > (0x%x), may occur overlay\n",
+			core_dev->rpc_actual_size, core_dev->rpc_buf_size);
+
+	mu_addr = cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy + core_dev->rpc_buf_size);
+	rpc_set_print_buffer(&core_dev->shared_mem, mu_addr, core_dev->print_buf_size);
+	core_dev->print_buf = core_dev->m0_rpc_virt + core_dev->rpc_buf_size;
+
+	reset_vpu_core_dev(core_dev);
+}
+
+static void vpu_enc_restore_core_rpc(struct core_device *core_dev)
+{
+	rpc_restore_shared_memory_encoder(&core_dev->shared_mem,
+				cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy),
+				core_dev->m0_rpc_virt);
+	core_dev->print_buf = core_dev->m0_rpc_virt + core_dev->rpc_buf_size;
+	sw_reset_firmware(core_dev, 0);
+	set_core_fw_status(core_dev, true);
+}
+
+static int init_vpu_core_dev(struct core_device *core_dev)
+{
+	int ret = 0;
+
+	if (!core_dev)
+		return -EINVAL;
+
+	mutex_init(&core_dev->cmd_mutex);
+	init_completion(&core_dev->boot_cmp);
+	init_completion(&core_dev->snap_done_cmp);
+
+	core_dev->workqueue = alloc_workqueue("vpu",
+					WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!core_dev->workqueue) {
+		vpu_err("%s unable to alloc workqueue\n", __func__);
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	INIT_WORK(&core_dev->msg_work, vpu_enc_msg_run_work);
+
+	ret = kfifo_alloc(&core_dev->mu_msg_fifo,
+			  sizeof(u32) * VID_API_NUM_STREAMS * VID_API_MESSAGE_LIMIT,
+			  GFP_KERNEL);
+	if (ret) {
+		vpu_err("error: fail to alloc mu msg fifo\n");
+		goto err_des_work;
+	}
+
+	//firmware space for M0
+	core_dev->m0_p_fw_space_vir =
+		ioremap_wc(core_dev->m0_p_fw_space_phy, core_dev->fw_buf_size);
+	if (!core_dev->m0_p_fw_space_vir) {
+		vpu_err("failed to remap space for M0 firmware\n");
+		ret = -EINVAL;
+		goto err_free_fifo;
+	}
+
+	core_dev->m0_rpc_virt =
+		ioremap_wc(core_dev->m0_rpc_phy,
+			core_dev->rpc_buf_size + core_dev->print_buf_size);
+	if (!core_dev->m0_rpc_virt) {
+		vpu_err("failed to remap space for shared memory\n");
+		ret = -EINVAL;
+		goto err_free_fifo;
+	}
+
+	if (is_vpu_enc_poweroff(core_dev))
+		vpu_enc_init_core_rpc(core_dev);
+	else
+		vpu_enc_restore_core_rpc(core_dev);
+
+	init_vpu_attrs(core_dev);
+
+	scnprintf(core_dev->name, sizeof(core_dev->name) - 1,
+			"core.%d", core_dev->id);
+	sysfs_attr_init(&core_dev->core_attr.attr);
+	core_dev->core_attr.attr.name = core_dev->name;
+	core_dev->core_attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
+	core_dev->core_attr.show = show_core_info;
+	device_create_file(core_dev->generic_dev, &core_dev->core_attr);
+
+	return ret;
+
+err_free_fifo:
+	kfifo_free(&core_dev->mu_msg_fifo);
+err_des_work:
+	if (core_dev->workqueue) {
+		destroy_workqueue(core_dev->workqueue);
+		core_dev->workqueue = NULL;
+	}
+	return ret;
+}
+
+static int uninit_vpu_core_dev(struct core_device *core_dev)
+{
+	if (!core_dev)
+		return -EINVAL;
+
+	vpu_enc_mu_free(core_dev);
+	kfifo_free(&core_dev->mu_msg_fifo);
+
+	if (core_dev->core_attr.attr.name)
+		device_remove_file(core_dev->generic_dev, &core_dev->core_attr);
+	release_vpu_attrs(core_dev);
+	if (core_dev->workqueue) {
+		cancel_work_sync(&core_dev->msg_work);
+		destroy_workqueue(core_dev->workqueue);
+		core_dev->workqueue = NULL;
+	}
+
+	if (core_dev->m0_p_fw_space_vir) {
+		iounmap(core_dev->m0_p_fw_space_vir);
+		core_dev->m0_p_fw_space_vir = NULL;
+	}
+	core_dev->m0_p_fw_space_phy = 0;
+
+	if (core_dev->m0_rpc_virt) {
+		iounmap(core_dev->m0_rpc_virt);
+		core_dev->m0_rpc_virt = NULL;
+	}
+	core_dev->m0_rpc_phy = 0;
+
+	if (core_dev->mu_base_virtaddr)
+		core_dev->mu_base_virtaddr = NULL;
+
+	if (core_dev->generic_dev) {
+		put_device(core_dev->generic_dev);
+		core_dev->generic_dev = NULL;
+	}
+
+	return 0;
+}
+
+static void init_vpu_enc_watchdog(struct vpu_dev *vdev)
+{
+	if (!vdev)
+		return;
+
+	INIT_DELAYED_WORK(&vdev->watchdog, vpu_enc_watchdog_handler);
+	schedule_delayed_work(&vdev->watchdog,
+			msecs_to_jiffies(VPU_WATCHDOG_INTERVAL_MS));
+}
+
+static const struct of_device_id vpu_enc_of_match[];
+static int vpu_enc_probe(struct platform_device *pdev)
+{
+	struct vpu_dev *dev;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *dev_id = NULL;
+	struct resource *res = NULL;
+	u_int32 i;
+	int ret;
+
+	if (!np) {
+		vpu_err("error: %s of_node is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_id = of_match_device(vpu_enc_of_match, &pdev->dev);
+	if (!dev_id) {
+		vpu_err("unmatch vpu encoder device\n");
+		return -EINVAL;
+	}
+	vpu_dbg(LVL_INFO, "probe %s\n", dev_id->compatible);
+
+	if (vpu_enc_sc_check_fuse())
+		return -EINVAL;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	dev->plat_type = *(enum PLAT_TYPE *)dev_id->data;
+	dev->plat_dev = pdev;
+	dev->generic_dev = get_device(&pdev->dev);
+
+	ret = vpu_enc_attach_pm_domains(dev);
+	if (ret)
+		goto error_put_dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		ret = -EINVAL;
+		goto error_det_pm;
+	}
+
+	dev->reg_vpu_base = res->start;
+	dev->reg_vpu_size = resource_size(res);
+
+	ret = parse_dt_info(dev, np);
+	if (ret) {
+		vpu_err("parse device tree fail\n");
+		goto error_det_pm;
+	}
+
+	dev->regs_base = ioremap(dev->reg_vpu_base, dev->reg_vpu_size);
+	if (!dev->regs_base) {
+		vpu_err("%s could not map regs_base\n", __func__);
+		ret = PTR_ERR(dev->regs_base);
+		goto error_det_pm;
+	}
+
+	ret = vpu_enc_init_reserved_memory(&dev->reserved_mem);
+	if (ret) {
+		vpu_err("%s couldn't init reserved memory\n", __func__);
+		goto error_iounmap;
+	}
+
+	platform_set_drvdata(pdev, dev);
+	mutex_init(&dev->dev_mutex);
+	for (i = 0; i < dev->core_num; i++) {
+		dev->core_dev[i].id = i;
+		dev->core_dev[i].generic_dev = get_device(dev->generic_dev);
+		dev->core_dev[i].vdev = dev;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		vpu_err("fail to request mailbox, ret = %d\n", ret);
+		pm_runtime_put_noidle(&pdev->dev);
+		pm_runtime_set_suspended(&pdev->dev);
+		goto error_pm_runtime_get_sync;
+	}
+
+	mutex_init(&dev->dev_mutex);
+	for (i = 0; i < dev->core_num; i++) {
+		ret = init_vpu_core_dev(&dev->core_dev[i]);
+		if (ret)
+			break;
+	}
+
+	if (i < dev->core_num) {
+		if (i == 0)
+			goto error_init_core;
+		else
+			vpu_err("error: core[%d] init failed\n", i);
+	}
+
+	dev->core_num = i;
+	vpu_enc_enable_hw(dev);
+
+	pm_runtime_put_sync(&pdev->dev);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		vpu_err("%s unable to register v4l2 dev\n", __func__);
+		goto error_init_core;
+	}
+
+	ret = create_vpu_video_device(dev);
+	if (ret) {
+		vpu_err("create vpu video device fail\n");
+		goto error_unreg_v4l2;
+	}
+
+
+	device_create_file(&pdev->dev, &dev_attr_meminfo);
+	device_create_file(&pdev->dev, &dev_attr_buffer);
+	device_create_file(&pdev->dev, &dev_attr_fpsinfo);
+	device_create_file(&pdev->dev, &dev_attr_vpuinfo);
+	vpu_enc_create_debugfs_file(dev);
+	init_vpu_enc_watchdog(dev);
+	vpu_dbg(LVL_INFO, "VPU Encoder registered\n");
+
+	return 0;
+
+error_unreg_v4l2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+error_init_core:
+	for (i = 0; i < dev->core_num; i++)
+		uninit_vpu_core_dev(&dev->core_dev[i]);
+
+	vpu_enc_disable_hw(dev);
+	pm_runtime_put_sync(&pdev->dev);
+error_pm_runtime_get_sync:
+	pm_runtime_disable(&pdev->dev);
+
+	if (dev->pvpu_encoder_dev) {
+		video_unregister_device(dev->pvpu_encoder_dev);
+		dev->pvpu_encoder_dev = NULL;
+	}
+	vpu_enc_release_reserved_memory(&dev->reserved_mem);
+error_iounmap:
+	if (dev->regs_base) {
+		iounmap(dev->regs_base);
+		dev->regs_base = NULL;
+	}
+error_det_pm:
+	vpu_enc_detach_pm_domains(dev);
+error_put_dev:
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+
+	return ret;
+}
+
+static int vpu_enc_remove(struct platform_device *pdev)
+{
+	struct vpu_dev *dev = platform_get_drvdata(pdev);
+	u_int32 i;
+
+	cancel_delayed_work_sync(&dev->watchdog);
+	vpu_enc_remove_debugfs_file(dev);
+	device_remove_file(&pdev->dev, &dev_attr_vpuinfo);
+	device_remove_file(&pdev->dev, &dev_attr_fpsinfo);
+	device_remove_file(&pdev->dev, &dev_attr_buffer);
+	device_remove_file(&pdev->dev, &dev_attr_meminfo);
+
+	pm_runtime_get_sync(&pdev->dev);
+	for (i = 0; i < dev->core_num; i++)
+		uninit_vpu_core_dev(&dev->core_dev[i]);
+
+	vpu_enc_disable_hw(dev);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	if (video_get_drvdata(dev->pvpu_encoder_dev))
+		video_unregister_device(dev->pvpu_encoder_dev);
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+	vpu_enc_detach_pm_domains(dev);
+	vpu_enc_release_reserved_memory(&dev->reserved_mem);
+	if (dev->regs_base) {
+		iounmap(dev->regs_base);
+		dev->regs_base = NULL;
+	}
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+
+	return 0;
+}
+
+static int vpu_enc_runtime_suspend(struct device *dev)
+{
+	int i;
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+
+	for (i = 0; i < vpudev->core_num; i++) {
+		if (!vpudev->core_dev[i].generic_dev)
+			continue;
+		vpu_enc_mu_free(&vpudev->core_dev[i]);
+	}
+
+	return 0;
+}
+
+static int vpu_enc_runtime_resume(struct device *dev)
+{
+	int i;
+	int ret = 0;
+
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+
+	for (i = 0; i < vpudev->core_num; i++) {
+		if (!vpudev->core_dev[i].generic_dev)
+			continue;
+		ret |= vpu_enc_mu_request(&vpudev->core_dev[i]);
+	}
+
+	return ret;
+}
+
+static int is_vpu_enc_poweroff(struct core_device *core)
+{
+	/* the csr register 'CM0Px_CPUWAIT' will be cleared to '1' after
+	 * reset(poweoff then poweron)
+	 */
+	if (read_vpu_reg(core->vdev, core->reg_csr_base + CSR_CM0Px_CPUWAIT) == 1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_need_shapshot(struct vpu_ctx *ctx)
+{
+	if (!test_bit(VPU_ENC_STATUS_INITIALIZED, &ctx->status))
+		return 0;
+	if (!test_bit(VPU_ENC_STATUS_CONFIGURED, &ctx->status))
+		return 0;
+	if (test_bit(VPU_ENC_STATUS_CLOSED, &ctx->status))
+		return 0;
+	if (test_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status))
+		return 0;
+	if (test_bit(VPU_ENC_STATUS_STOP_DONE, &ctx->status))
+		return 0;
+
+	return 1;
+}
+
+static int vpu_enc_snapshot(struct vpu_ctx *ctx)
+{
+	int ret;
+
+	if (!ctx)
+		return -EINVAL;
+
+	vpu_dbg(LVL_INFO, "core[%d] snapshot\n", ctx->core_dev->id);
+	vpu_ctx_send_cmd(ctx, GTB_ENC_CMD_SNAPSHOT, 0, NULL);
+	ret = wait_for_completion_timeout(&ctx->core_dev->snap_done_cmp,
+						msecs_to_jiffies(1000));
+	if (!ret)
+		vpu_err("error:wait for snapdone event timeout!\n");
+	else
+		ctx->core_dev->snapshot = true;
+
+	return 0;
+}
+
+static int resume_from_snapshot(struct core_device *core)
+{
+	int ret = 0;
+
+	if (!core)
+		return -EINVAL;
+	if (!core->snapshot)
+		return 0;
+
+	vpu_dbg(LVL_INFO, "core[%d] resume from snapshot\n", core->id);
+
+	reinit_completion(&core->boot_cmp);
+	set_vpu_fw_addr(core->vdev, core);
+	ret = wait_for_boot_done(core, 1);
+	if (ret) {
+		set_core_force_release(core);
+		reset_vpu_core_dev(core);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int re_download_firmware(struct core_device *core)
+{
+	if (!core)
+		return -EINVAL;
+
+	vpu_dbg(LVL_INFO, "re download firmware for core[%d]\n", core->id);
+
+	reset_vpu_core_dev(core);
+	return download_vpu_firmware(core->vdev, core);
+}
+
+static int suspend_instance(struct vpu_ctx *ctx)
+{
+	int ret = 0;
+
+	if (!ctx)
+		return 0;
+
+	if (test_bit(VPU_ENC_STATUS_STOP_REQ, &ctx->status) ||
+		test_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status))
+		wait_for_stop_done(ctx);
+
+	mutex_lock(&ctx->instance_mutex);
+	if (!ctx->core_dev->snapshot && is_need_shapshot(ctx))
+		ret = vpu_enc_snapshot(ctx);
+	set_bit(VPU_ENC_STATUS_SNAPSHOT, &ctx->status);
+	mutex_unlock(&ctx->instance_mutex);
+
+	return ret;
+}
+
+static int resume_instance(struct vpu_ctx *ctx)
+{
+	if (!ctx)
+		return 0;
+
+	clear_bit(VPU_ENC_STATUS_SNAPSHOT, &ctx->status);
+
+	return 0;
+}
+
+static int suspend_core(struct core_device *core)
+{
+	int i;
+	int ret = 0;
+
+	WARN_ON(!core);
+
+	core->snapshot = false;
+
+	if (!core->fw_is_ready)
+		return 0;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (!core->ctx[i])
+			continue;
+		ret = suspend_instance(core->ctx[i]);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < core->supported_instance_count; i++)
+		vpu_ctx_power_off(core->ctx[i]);
+
+	core->suspend = true;
+
+	return 0;
+}
+
+static int resume_core(struct core_device *core)
+{
+	int ret = 0;
+	u32 instance_count = 0;
+	int i;
+
+	WARN_ON(!core);
+
+	if (!core->suspend)
+		return 0;
+
+	for (i = 0; i < core->supported_instance_count; i++) {
+		if (!core->ctx[i])
+			continue;
+		instance_count++;
+		vpu_ctx_power_on(core->ctx[i]);
+		resume_instance(core->ctx[i]);
+	}
+
+	if (is_vpu_enc_poweroff(core)) {
+		if (!core->vdev->hw_enable)
+			vpu_enc_enable_hw(core->vdev);
+		if (core->snapshot)
+			ret = resume_from_snapshot(core);
+		else if (instance_count)
+			ret = re_download_firmware(core);
+		else
+			reset_vpu_core_dev(core);
+	} else {
+		if (core->snapshot || instance_count)
+			ret = sw_reset_firmware(core, 1);
+	}
+
+	core->snapshot = false;
+	core->suspend = false;
+
+	return ret;
+}
+
+static void vpu_enc_cancel_work(struct vpu_dev *vpudev)
+{
+	int i;
+	int j;
+
+	for (i = 0; i < vpudev->core_num; i++) {
+		struct core_device *core = &vpudev->core_dev[i];
+
+		if (!core->fw_is_ready)
+			continue;
+		cancel_work_sync(&core->msg_work);
+		for (j = 0; j < core->supported_instance_count; j++) {
+			struct vpu_ctx *ctx = core->ctx[j];
+
+			if (!ctx)
+				continue;
+			cancel_work_sync(&ctx->instance_work);
+		}
+	}
+	cancel_delayed_work_sync(&vpudev->watchdog);
+}
+
+static void vpu_enc_resume_work(struct vpu_dev *vpudev)
+{
+	int i;
+	int j;
+
+	for (i = 0; i < vpudev->core_num; i++) {
+		struct core_device *core = &vpudev->core_dev[i];
+
+		if (!core->fw_is_ready)
+			continue;
+		queue_work(core->workqueue, &core->msg_work);
+		for (j = 0; j < core->supported_instance_count; j++) {
+			struct vpu_ctx *ctx = core->ctx[j];
+
+			if (!ctx)
+				continue;
+			queue_work(ctx->instance_wq, &ctx->instance_work);
+		}
+	}
+	schedule_delayed_work(&vpudev->watchdog,
+			msecs_to_jiffies(VPU_WATCHDOG_INTERVAL_MS));
+}
+
+static int __maybe_unused vpu_enc_suspend(struct device *dev)
+{
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+	int i;
+	int ret = 0;
+
+	vpu_dbg(LVL_INFO, "suspend\n");
+
+	mutex_lock(&vpudev->dev_mutex);
+	pm_runtime_get_sync(dev);
+	for (i = 0; i < vpudev->core_num; i++) {
+		ret = suspend_core(&vpudev->core_dev[i]);
+		if (ret)
+			break;
+	}
+	vpu_enc_cancel_work(vpudev);
+	pm_runtime_put_sync(dev);
+	mutex_unlock(&vpudev->dev_mutex);
+
+	vpu_dbg(LVL_INFO, "suspend done\n");
+
+	return ret;
+}
+
+static int __maybe_unused vpu_enc_resume(struct device *dev)
+{
+	struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+	int i;
+	int ret = 0;
+
+	vpu_dbg(LVL_INFO, "resume\n");
+
+	mutex_lock(&vpudev->dev_mutex);
+	pm_runtime_get_sync(dev);
+	vpudev->hw_enable = false;
+	for (i = 0; i < vpudev->core_num; i++) {
+		ret = resume_core(&vpudev->core_dev[i]);
+		if (ret)
+			break;
+	}
+	vpudev->hw_enable = true;
+	vpu_enc_resume_work(vpudev);
+	pm_runtime_put_sync(dev);
+	mutex_unlock(&vpudev->dev_mutex);
+
+	vpu_dbg(LVL_INFO, "resume done\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops vpu_enc_pm_ops = {
+	SET_RUNTIME_PM_OPS(vpu_enc_runtime_suspend, vpu_enc_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(vpu_enc_suspend, vpu_enc_resume)
+};
+
+static enum PLAT_TYPE supported_plat_types[PLAT_TYPE_RESERVED] = {
+	[IMX8QXP] = IMX8QXP,
+	[IMX8QM] = IMX8QM,
+};
+
+static const struct of_device_id vpu_enc_of_match[] = {
+	{ .compatible = "nxp,imx8qm-b0-vpuenc",
+	  .data = (void *)&supported_plat_types[IMX8QM]
+	},
+	{ .compatible = "nxp,imx8qxp-b0-vpuenc",
+	  .data = (void *)&supported_plat_types[IMX8QXP]
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, vpu_enc_of_match);
+
+static struct platform_driver vpu_enc_driver = {
+	.probe = vpu_enc_probe,
+	.remove = vpu_enc_remove,
+	.driver = {
+		.name = "vpu-b0-encoder",
+		.of_match_table = vpu_enc_of_match,
+		.pm = &vpu_enc_pm_ops,
+	},
+};
+module_platform_driver(vpu_enc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPU_ENC_DRIVER_VERSION);
+
+module_param(vpu_dbg_level_encoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_encoder, "Debug level (0-4)");
+
+module_param(reset_on_hang, int, 0644);
+MODULE_PARM_DESC(reset_on_hang, "reset on hang (0-1)");
+
+module_param(show_detail_index, int, 0644);
+MODULE_PARM_DESC(show_detail_index, "show memory detail info index");
+
+module_param(debug_firmware_bitmap, long, 0644);
+MODULE_PARM_DESC(debug_firmware_bitmap, "firmware debug info switch");
+
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_b0.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_b0.h
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.h
+ *
+ * @brief VPU ENCODER B0 definition
+ *
+ */
+#ifndef __VPU_ENCODER_B0_H__
+#define __VPU_ENCODER_B0_H__
+
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#ifdef CONFIG_IMX_SCU
+#include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/svc/misc.h>
+#else
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#endif
+#include <linux/mx8_mu.h>
+#include <media/v4l2-event.h>
+#include <linux/mailbox_client.h>
+#include <linux/kfifo.h>
+
+#include "vpu_encoder_rpc.h"
+#include "vpu_encoder_config.h"
+
+extern unsigned int vpu_dbg_level_encoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+	container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+	container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define VPU_ENC_MAX_CORE_NUM		2
+#define VPU_MAX_BUFFER			32
+#define M0FW_FILENAME			"vpu/vpu_fw_imx8_enc.bin"
+#define MMAP_BUF_TYPE_SHIFT		28
+#define MMAP_BUF_TYPE_MASK		0xF0000000
+#define M0_BOOT_SIZE_DEFAULT		0x1000000
+#define M0_BOOT_SIZE_MIN		0x100000
+#define RPC_SIZE_DEFAULT		0x80000
+#define RPC_SIZE_MIN			0x20000
+#define PRINT_SIZE_DEFAULT		0x80000
+#define PRINT_SIZE_MIN			0x20000
+#define STREAM_SIZE			0x300000
+
+#define MIN_BUFFER_COUNT		3
+#define BITRATE_COEF			1024
+#define BITRATE_LOW_THRESHOLD		(16)
+#define BITRATE_HIGH_THRESHOLD		(240 * 1024)
+#define BITRATE_DEFAULT_TARGET		(2 * 1024)
+#define BITRATE_DEFAULT_PEAK		(8 * 1024)
+#define GOP_H_THRESHOLD			300
+#define GOP_L_THRESHOLD			1
+#define GOP_DEFAULT			30
+#define BFRAMES_H_THRESHOLD		4
+#define BFRAMES_L_THRESHOLD		0
+#define BFRAMES_DEFAULT			0
+#define QP_MAX				51
+#define QP_MIN				0
+#define QP_DEFAULT			25
+#define CPB_CTRL_UNIT			1024
+#define CPB_COUNT			3
+
+#define VPU_DISABLE_BITS		0x7
+#define VPU_ENCODER_MASK		0x1
+
+#define ENCODER_NODE_NUMBER 13 //use /dev/video13 as encoder node
+struct vpu_v4l2_control {
+	uint32_t id;
+	enum v4l2_ctrl_type type;
+	uint32_t minimum;
+	uint32_t maximum;
+	uint32_t step;
+	uint32_t default_value;
+	uint32_t menu_skip_mask;
+	bool is_volatile;
+};
+
+typedef enum{
+	INIT_DONE = 1,
+	RPC_BUF_OFFSET,
+	BOOT_ADDRESS,
+	COMMAND,
+	EVENT
+} MSG_Type;
+
+enum PLAT_TYPE {
+	IMX8QXP = 0,
+	IMX8QM  = 1,
+	IMX8DM,
+	IMX8DX,
+	PLAT_TYPE_RESERVED
+};
+
+enum QUEUE_TYPE {
+	V4L2_SRC = 0,
+	V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+	VPU_VIDEO_UNDEFINED = 0,
+	VPU_VIDEO_AVC = 1,
+	VPU_VIDEO_VC1 = 2,
+	VPU_VIDEO_MPEG2 = 3,
+	VPU_VIDEO_AVS = 4,
+	VPU_VIDEO_ASP = 5,
+	VPU_VIDEO_JPEG = 6,
+	VPU_VIDEO_RV8 = 7,
+	VPU_VIDEO_RV9 = 8,
+	VPU_VIDEO_VP6 = 9,
+	VPU_VIDEO_SPK = 10,
+	VPU_VIDEO_VP8 = 11,
+	VPU_VIDEO_AVC_MVC = 12,
+	VPU_VIDEO_HEVC = 13,
+	VPU_VIDEO_VP9 = 14,
+};
+
+#define VPU_PIX_FMT_AVS         v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP         v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV8         v4l2_fourcc('R', 'V', '8', '0')
+#define VPU_PIX_FMT_RV9         v4l2_fourcc('R', 'V', '9', '0')
+#define VPU_PIX_FMT_VP6         v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK         v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_HEVC        v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_VP9         v4l2_fourcc('V', 'P', '9', '0')
+#define VPU_PIX_FMT_LOGO        v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8     v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10    v4l2_fourcc('Z', 'T', '1', '0')
+
+enum vpu_pixel_format {
+	VPU_HAS_COLOCATED = 0x00000001,
+	VPU_HAS_SPLIT_FLD = 0x00000002,
+	VPU_PF_MASK       = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+	VPU_IS_TILED      = 0x000000100,
+	VPU_HAS_10BPP     = 0x00000200,
+
+	VPU_IS_PLANAR     = 0x00001000,
+	VPU_IS_SEMIPLANAR = 0x00002000,
+	VPU_IS_PACKED     = 0x00004000,
+
+	// Merged definitions using above flags:
+	VPU_PF_UNDEFINED  = 0,
+	VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+	VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+	VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+	VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+	VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+struct vpu_ctx;
+struct core_device;
+struct vpu_dev;
+struct vpu_v4l2_fmt {
+	char *name;
+	unsigned int fourcc;
+	unsigned int num_planes;
+	unsigned int venc_std;
+	unsigned int is_yuv;
+};
+
+struct vb2_data_req {
+	struct list_head  list;
+	struct vb2_buffer *vb2_buf;
+	u_int32 sequence;
+	u_int32 buffer_flags;
+};
+
+enum ENC_RW_FLAG {
+	VPU_ENC_FLAG_WRITEABLE,
+	VPU_ENC_FLAG_READABLE
+};
+
+struct queue_data {
+	unsigned int width;
+	unsigned int height;
+	unsigned int sizeimage[VB2_MAX_PLANES];
+	struct v4l2_rect rect;
+	int buf_type; // v4l2_buf_type
+	bool vb2_q_inited;
+	struct vb2_queue vb2_q;    // vb2 queue
+	struct list_head drv_q;    // driver queue
+	struct semaphore drv_q_lock;
+	struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+	enum QUEUE_TYPE type;
+	struct vpu_v4l2_fmt *supported_fmts;
+	unsigned int fmt_count;
+	struct vpu_v4l2_fmt *current_fmt;
+	unsigned long rw_flag;
+	struct list_head frame_q;
+	atomic64_t frame_count;
+	struct list_head frame_idle;
+	struct vpu_ctx *ctx;
+	char desc[64];
+};
+
+struct vpu_strip_info {
+	unsigned long count;
+	unsigned long max;
+	unsigned long total;
+};
+
+struct vpu_fps_sts {
+	unsigned int thd;
+	unsigned int times;
+	unsigned long frame_number;
+	struct timespec64 ts;
+	unsigned long fps;
+};
+
+struct vpu_statistic {
+	unsigned long cmd[GTB_ENC_CMD_RESERVED + 1];
+	unsigned long event[VID_API_ENC_EVENT_RESERVED + 1];
+	unsigned long current_cmd;
+	unsigned long current_event;
+	struct timespec64 ts_cmd;
+	struct timespec64 ts_event;
+	unsigned long yuv_count;
+	unsigned long encoded_count;
+	unsigned long h264_count;
+	struct {
+		struct vpu_strip_info fw;
+		struct vpu_strip_info begin;
+		struct vpu_strip_info eos;
+	} strip_sts;
+	bool fps_sts_enable;
+	struct vpu_fps_sts fps[VPU_FPS_STS_CNT];
+};
+
+struct vpu_attr {
+	struct device_attribute dev_attr;
+	char name[64];
+	u32 index;
+	struct core_device *core;
+
+	pid_t pid;
+	pid_t tgid;
+
+	struct vpu_statistic statistic;
+	MEDIAIP_ENC_PARAM param;
+	struct v4l2_fract fival;
+	u32 h264_vui_sar_enable;
+	u32 h264_vui_sar_idc;
+	u32 h264_vui_sar_width;
+	u32 h264_vui_sar_height;
+
+	unsigned long ts_start[2];
+	unsigned long msg_count;
+	atomic64_t total_dma_size;
+
+	bool created;
+};
+
+struct print_buf_desc {
+	u32 start_h_phy;
+	u32 start_h_vir;
+	u32 start_m;
+	u32 bytes;
+	u32 read;
+	u32 write;
+	char buffer[0];
+};
+
+#ifdef CONFIG_IMX_SCU
+struct vpu_sc_msg_misc {
+	struct imx_sc_rpc_msg hdr;
+	u32 word;
+} __packed;
+#endif
+
+struct vpu_sc_chan {
+	struct core_device *dev;
+	char name[20];
+	struct mbox_client cl;
+	struct mbox_chan *ch;
+};
+
+struct core_device {
+	void *m0_p_fw_space_vir;
+	u_int32 m0_p_fw_space_phy;
+	u32 fw_buf_size;
+	u32 fw_actual_size;
+	void *m0_rpc_virt;
+	u_int32 m0_rpc_phy;
+	u32 rpc_buf_size;
+	u32 print_buf_size;
+	u32 rpc_actual_size;
+	struct print_buf_desc *print_buf;
+
+	struct mutex cmd_mutex;
+	bool fw_is_ready;
+	bool firmware_started;
+	struct completion boot_cmp;
+	struct completion snap_done_cmp;
+	struct workqueue_struct *workqueue;
+	struct work_struct msg_work;
+	void __iomem *mu_base_virtaddr;
+	unsigned int vpu_mu_id;
+	int vpu_mu_init;
+
+	u32 supported_instance_count;
+	struct vpu_ctx *ctx[VID_API_NUM_STREAMS];
+	struct vpu_attr attr[VID_API_NUM_STREAMS];
+	struct shared_addr shared_mem;
+	u32 id;
+	u32 reg_base;
+	u32 reg_size;
+	u32 reg_csr_base;
+	u32 reg_csr_size;
+	int irq;
+	struct device *generic_dev;
+	struct vpu_dev *vdev;
+	bool snapshot;
+	bool suspend;
+	bool hang;
+	struct device_attribute core_attr;
+	char name[64];
+	unsigned long reset_times;
+
+	struct kfifo mu_msg_fifo;
+
+	/* reserve for kernel version 5.4 or later */
+	struct vpu_sc_chan sc_chan_tx0;
+	struct vpu_sc_chan sc_chan_tx1;
+	struct vpu_sc_chan sc_chan_rx;
+
+	struct dentry *debugfs_fwlog;
+};
+
+struct vpu_enc_mem_item {
+	struct list_head list;
+	void *virt_addr;
+	unsigned long phy_addr;
+	unsigned long size;
+	unsigned long offset;
+};
+
+struct vpu_enc_mem_info {
+	void *virt_addr;
+	unsigned long phy_addr;
+	unsigned long size;
+	unsigned long bytesused;
+	struct list_head memorys;
+	struct mutex lock;
+};
+
+struct vpu_dev {
+	struct device *generic_dev;
+	struct v4l2_device v4l2_dev;
+	struct video_device *pvpu_encoder_dev;
+	struct platform_device *plat_dev;
+	struct clk *clk_m0;
+	u32 reg_vpu_base;
+	u32 reg_vpu_size;
+	u32 reg_rpc_system;
+	void __iomem *regs_base;
+	struct mutex dev_mutex;
+	struct core_device core_dev[VPU_ENC_MAX_CORE_NUM];
+	u_int32 plat_type;
+	u_int32 core_num;
+	bool hw_enable;
+
+	struct delayed_work watchdog;
+	u8 heartbeat;
+
+	struct {
+		u32 min_width;
+		u32 max_width;
+		u32 step_width;
+		u32 min_height;
+		u32 max_height;
+		u32 step_height;
+	} supported_size;
+	struct {
+		u32 min;
+		u32 max;
+		u32 step;
+	} supported_fps;
+	struct vpu_enc_mem_info reserved_mem;
+
+	/* reserve for kernel version 5.4 or later */
+	struct device *pd_vpu;
+	struct device *pd_enc1;
+	struct device *pd_enc2;
+	struct device *pd_mu1;
+	struct device *pd_mu2;
+	struct device_link *pd_vpu_link;
+	struct device_link *pd_enc1_link;
+	struct device_link *pd_enc2_link;
+	struct device_link *pd_mu1_link;
+	struct device_link *pd_mu2_link;
+	struct dentry *debugfs_root;
+};
+
+struct buffer_addr {
+	void *virt_addr;
+	dma_addr_t phy_addr;
+	u_int32 size;
+};
+
+enum {
+	VPU_ENC_STATUS_INITIALIZED,
+	VPU_ENC_STATUS_OUTPUT_READY = 18,
+	VPU_ENC_STATUS_DATA_READY = 19,
+	VPU_ENC_STATUS_SNAPSHOT = 20,
+	VPU_ENC_STATUS_FORCE_RELEASE = 21,
+	VPU_ENC_STATUS_EOS_SEND = 22,
+	VPU_ENC_STATUS_START_SEND = 23,
+	VPU_ENC_STATUS_START_DONE = 24,
+	VPU_ENC_STATUS_STOP_REQ = 25,
+	VPU_ENC_STATUS_STOP_SEND = 26,
+	VPU_ENC_STATUS_STOP_DONE = 27,
+	VPU_ENC_STATUS_CLOSED = 28,
+	VPU_ENC_STATUS_CONFIGURED = 29,
+	VPU_ENC_STATUS_HANG = 30,
+	VPU_ENC_STATUS_KEY_FRAME = 31
+};
+
+struct vpu_ctx {
+	struct vpu_dev *dev;
+	struct v4l2_fh fh;
+
+	struct v4l2_ctrl_handler ctrl_handler;
+	bool ctrl_inited;
+
+	int str_index;
+	unsigned long status;
+	struct queue_data q_data[2];
+	struct mutex instance_mutex;
+	struct work_struct instance_work;
+	struct workqueue_struct *instance_wq;
+	bool ctx_released;
+	struct buffer_addr encoder_stream;
+	struct buffer_addr encFrame[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+	struct buffer_addr refFrame[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+	struct buffer_addr actFrame;
+	struct buffer_addr enc_buffer;
+	MEDIAIP_ENC_MEM_REQ_DATA mem_req;
+	struct core_device *core_dev;
+
+	struct completion start_cmp;
+	struct completion stop_cmp;
+	bool power_status;
+
+	struct list_head msg_q;
+	struct list_head idle_q;
+
+	struct vpu_statistic sts;
+	unsigned int frozen_count;
+	u_int32 sequence;
+	u32 cpb_size;
+	s64 timestamp;
+	u8 colorspace;
+	u8 xfer_func;
+	u8 ycbcr_enc;
+	u8 quantization;
+};
+
+#define LVL_ERR		(1 << 0)
+#define LVL_WARN	(1 << 1)
+#define LVL_ALL		(1 << 2)
+#define LVL_IRQ		(1 << 3)
+#define LVL_INFO	(1 << 4)
+#define LVL_CMD		(1 << 5)
+#define LVL_EVT		(1 << 6)
+#define LVL_DEBUG	(1 << 7)
+#define LVL_CTRL	(1 << 8)
+#define LVL_RPC		(1 << 9)
+#define LVL_MSG		(1 << 10)
+#define LVL_MEM		(1 << 11)
+#define LVL_BUF		(1 << 12)
+#define LVL_FLOW	(1 << 13)
+#define LVL_FRAME	(1 << 14)
+#define LVL_FUNC	(1 << 16)
+
+#ifndef TAG
+#define TAG	"[VPU Encoder] "
+#endif
+
+#define vpu_dbg(level, fmt, arg...) \
+	do { \
+		if ((vpu_dbg_level_encoder & (level)) || ((level) & LVL_ERR)) \
+			pr_info(TAG""fmt, ## arg); \
+	} while (0)
+
+#define vpu_err(fmt, arg...)	vpu_dbg(LVL_ERR, fmt, ##arg)
+#define vpu_log_func()		vpu_dbg(LVL_FUNC, "%s()\n", __func__)
+
+u32 cpu_phy_to_mu(struct core_device *dev, u32 addr);
+struct vpu_attr *get_vpu_ctx_attr(struct vpu_ctx *ctx);
+struct vpu_ctx *get_vpu_attr_ctx(struct vpu_attr *attr);
+
+#ifndef VPU_SAFE_RELEASE
+#define VPU_SAFE_RELEASE(p, func)	\
+	do {\
+		if (p) {\
+			func(p);\
+			p = NULL;\
+		} \
+	} while (0)
+#endif
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_config.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_config.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _VPU_ENCODER_CONFIG_H
+#define _VPU_ENCODER_CONFIG_H
+
+#define VPU_ENC_WIDTH_MAX		1920
+#define VPU_ENC_HEIGHT_MAX		1920
+#define VPU_ENC_WIDTH_MIN		64
+#define VPU_ENC_HEIGHT_MIN		48
+#define VPU_ENC_WIDTH_STEP		16
+#define VPU_ENC_HEIGHT_STEP		2
+
+#define VPU_ENC_WIDTH_DEFAULT		1920
+#define VPU_ENC_HEIGHT_DEFAULT		1080
+#define VPU_ENC_FRAMERATE_DEFAULT	30
+
+#define VPU_MEM_PATTERN			0x5a5a5a5a
+
+#define VPU_TAIL_SERACH_SIZE		16
+#define VPU_STRM_END_PATTERN		{0x0, 0x0, 0x1, 0xb}
+#define VPU_STRM_BEGIN_PATTERN		{0x0, 0x0, 0x1}
+
+#define MSG_DATA_DEFAULT_SIZE		256
+#define MSG_COUNT_THD			16
+#define FRAME_COUNT_THD			16
+
+#define VPU_WATCHDOG_INTERVAL_MS	1000
+#define VPU_ENC_HANG_THD		15
+
+#define VPU_FPS_STS_CNT			3
+#define VPU_FPS_STS_THDS		{1, 3, 0}
+#define VPU_FPS_COEF			100
+
+#define VPU_DETAIL_INDEX_DFT		0xffff
+
+#define VPU_MU_MAX_ADDRESS		0x40000000
+#define VPU_ENC_SEQ_CAPACITY		32
+#define VPU_ENC_INVALID_TIMESTAMP	-1
+
+#define VPU_ENC_H264_EXTENDED_SAR	255
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_ctrl.c
+ *
+ * copyright here may be changed later
+ *
+ */
+
+#define TAG	"[VPU Encoder Ctrl]\t "
+#include <media/v4l2-ctrls.h>
+
+#include "vpu_encoder_b0.h"
+#include "vpu_encoder_ctrl.h"
+
+// H264 level is maped like level 5.1 to uLevel 51, except level 1b to uLevel 14
+const u_int32 h264_level[] = {
+	[V4L2_MPEG_VIDEO_H264_LEVEL_1_0] = 10,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_1B]  = 14,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_1_1] = 11,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_1_2] = 12,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_1_3] = 13,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_2_0] = 20,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_2_1] = 21,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_2_2] = 22,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_3_0] = 30,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_3_1] = 31,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_3_2] = 32,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_4_0] = 40,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_4_1] = 41,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_4_2] = 42,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_5_0] = 50,
+	[V4L2_MPEG_VIDEO_H264_LEVEL_5_1] = 51
+};
+
+static int set_h264_profile(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	mutex_lock(&ctx->instance_mutex);
+	switch (ctrl->val) {
+	case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+		vpu_dbg(LVL_CTRL, "set h264 profile baseline\n");
+		param->eProfile = MEDIAIP_ENC_PROF_H264_BP;
+		break;
+	case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+		vpu_dbg(LVL_CTRL, "set h264 profile main\n");
+		param->eProfile = MEDIAIP_ENC_PROF_H264_MP;
+		break;
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+		vpu_dbg(LVL_CTRL, "set h264 profile high\n");
+		param->eProfile = MEDIAIP_ENC_PROF_H264_HP;
+		break;
+	default:
+		vpu_err("not support H264 profile %d, set to main\n",
+				ctrl->val);
+		param->eProfile = MEDIAIP_ENC_PROF_H264_MP;
+		break;
+	}
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_h264_level(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	mutex_lock(&ctx->instance_mutex);
+	param->uLevel = h264_level[ctrl->val];
+	mutex_unlock(&ctx->instance_mutex);
+
+	vpu_dbg(LVL_CTRL, "set h264 level to %d (%d)\n",
+			ctrl->val, h264_level[ctrl->val]);
+
+	return 0;
+}
+
+static int set_bitrate_mode(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	mutex_lock(&ctx->instance_mutex);
+	switch (ctrl->val) {
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+		vpu_dbg(LVL_CTRL, "set bitrate mode VBR\n");
+		param->eBitRateMode =
+				MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP;
+		break;
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+		vpu_dbg(LVL_CTRL, "set bitrate mode CBR\n");
+		param->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CBR;
+		break;
+	default:
+		vpu_err("not support bitrate mode %d, set to cbr\n",
+				ctrl->val);
+		param->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CBR;
+		break;
+	}
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_bitrate(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set bitrate %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uTargetBitrate = ctrl->val / BITRATE_COEF;
+	if (param->uMaxBitRate < param->uTargetBitrate)
+		param->uMaxBitRate = param->uTargetBitrate;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_bitrate_peak(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set peak bitrate %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uMaxBitRate = ctrl->val / BITRATE_COEF;
+	if (param->uTargetBitrate > param->uMaxBitRate)
+		param->uTargetBitrate = param->uMaxBitRate;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_gop_size(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set gop size %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uIFrameInterval = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_i_period(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set iframe interval %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uIFrameInterval = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int get_gop_size(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "get gop size\n");
+	ctrl->val = param->uIFrameInterval;
+
+	return 0;
+}
+
+static int set_b_frames(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set bframes %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uGopBLength = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_qp(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set qp %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	param->uInitSliceQP = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int get_min_buffers_for_output(struct v4l2_ctrl *ctrl)
+{
+	vpu_dbg(LVL_CTRL, "get min buffers for output\n");
+
+	ctrl->val = MIN_BUFFER_COUNT;
+
+	return 0;
+}
+
+static int set_display_re_ordering(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+	pMEDIAIP_ENC_PARAM  param = &attr->param;
+
+	vpu_dbg(LVL_CTRL, "set lowlatencymode %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	if (ctrl->val)
+		param->uLowLatencyMode = 1;
+	else
+		param->uLowLatencyMode = 0;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_force_key_frame(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	vpu_dbg(LVL_CTRL, "force key frame\n");
+	set_bit(VPU_ENC_STATUS_KEY_FRAME, &ctx->status);
+
+	return 0;
+}
+
+static int set_h264_cpb_size(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+	ctx->cpb_size = ctrl->val * CPB_CTRL_UNIT;
+
+	return 0;
+}
+
+static int set_h264_vui_sar_enable(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	vpu_dbg(LVL_CTRL, "set h264 vui sar enable %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	if (ctrl->val)
+		attr->h264_vui_sar_enable = 1;
+	else
+		attr->h264_vui_sar_enable = 0;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_h264_vui_sar_idc(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	vpu_dbg(LVL_CTRL, "set h264 vui sar idc %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	if (ctrl->val < V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED)
+		attr->h264_vui_sar_idc = ctrl->val;
+	else
+		attr->h264_vui_sar_idc = VPU_ENC_H264_EXTENDED_SAR;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_h264_vui_sar_width(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	vpu_dbg(LVL_CTRL, "set h264 vui sar width %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	attr->h264_vui_sar_width = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int set_h264_vui_sar_height(struct v4l2_ctrl *ctrl)
+{
+	struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	vpu_dbg(LVL_CTRL, "set h264 vui sar height %d\n", ctrl->val);
+	mutex_lock(&ctx->instance_mutex);
+	attr->h264_vui_sar_height = ctrl->val;
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+static int add_ctrl_h264_profile(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_h264_profile_ops = {
+		.s_ctrl = set_h264_profile,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler,
+				      &ctrl_h264_profile_ops,
+				      V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				      V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+				      0xa,
+				      V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 profile fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_level(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_h264_level_ops = {
+		.s_ctrl = set_h264_level,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler,
+				      &ctrl_h264_level_ops,
+				      V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				      V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+				      0x0,
+				      V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 level fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_bitrate_mode(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_bitrate_mode_ops = {
+		.s_ctrl = set_bitrate_mode,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler,
+				      &ctrl_bitrate_mode_ops,
+				      V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+				      V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+				      0x0,
+				      V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	if (!ctrl) {
+		vpu_err("add ctrl bitrate mode fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_bitrate(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_bitrate_ops = {
+		.s_ctrl = set_bitrate,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_bitrate_ops,
+				 V4L2_CID_MPEG_VIDEO_BITRATE,
+				 BITRATE_LOW_THRESHOLD * BITRATE_COEF,
+				 BITRATE_HIGH_THRESHOLD * BITRATE_COEF,
+				 BITRATE_COEF,
+				 BITRATE_DEFAULT_TARGET * BITRATE_COEF);
+	if (!ctrl) {
+		vpu_err("add ctrl bitrate fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_bitrate_peak(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_bitrate_ops = {
+		.s_ctrl = set_bitrate_peak,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_bitrate_ops,
+				 V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+				 BITRATE_LOW_THRESHOLD * BITRATE_COEF,
+				 BITRATE_HIGH_THRESHOLD * BITRATE_COEF,
+				 BITRATE_COEF,
+				 BITRATE_DEFAULT_PEAK * BITRATE_COEF);
+	if (!ctrl) {
+		vpu_err("add ctrl bitrate peak fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_gop_size(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_gop_ops = {
+		.s_ctrl = set_gop_size,
+		.g_volatile_ctrl = get_gop_size,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_gop_ops,
+				 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+				 GOP_L_THRESHOLD,
+				 GOP_H_THRESHOLD,
+				 1,
+				 GOP_DEFAULT);
+	if (!ctrl) {
+		vpu_err("add ctrl gop size fail\n");
+		return -EINVAL;
+	}
+
+	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	return 0;
+}
+
+static int add_ctrl_i_period(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_i_period_ops = {
+		.s_ctrl = set_i_period,
+		.g_volatile_ctrl = get_gop_size,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&ctrl_i_period_ops,
+			V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+			GOP_L_THRESHOLD,
+			GOP_H_THRESHOLD,
+			1,
+			GOP_DEFAULT);
+
+	if (!ctrl) {
+		vpu_err("add ctrl i period fail\n");
+		return -EINVAL;
+	}
+
+	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	return 0;
+}
+
+static int add_ctrl_b_frames(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_b_frames = {
+		.s_ctrl = set_b_frames,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&ctrl_b_frames,
+			V4L2_CID_MPEG_VIDEO_B_FRAMES,
+			BFRAMES_L_THRESHOLD,
+			BFRAMES_H_THRESHOLD,
+			1,
+			BFRAMES_DEFAULT);
+
+	if (!ctrl) {
+		vpu_err("add ctrl b frames fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_i_frame_qp(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_iframe_qp_ops = {
+		.s_ctrl = set_qp,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_iframe_qp_ops,
+				 V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+				 QP_MIN,
+				 QP_MAX,
+				 1,
+				 QP_DEFAULT);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 I frame qp fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_p_frame_qp(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_pframe_qp_ops = {
+		.s_ctrl = set_qp,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_pframe_qp_ops,
+				 V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+				 QP_MIN,
+				 QP_MAX,
+				 1,
+				 QP_DEFAULT);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 P frame qp fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_b_frame_qp(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_bframe_qp_ops = {
+		.s_ctrl = set_qp,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_bframe_qp_ops,
+				 V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+				 QP_MIN,
+				 QP_MAX,
+				 1,
+				 QP_DEFAULT);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 B frame qp fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_min_buffers_for_output(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_min_buffers_ops = {
+		.g_volatile_ctrl = get_min_buffers_for_output,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				 &ctrl_min_buffers_ops,
+				 V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+				 1,
+				 32,
+				 1,
+				 MIN_BUFFER_COUNT);
+	if (!ctrl) {
+		vpu_err("add ctrl min buffers for output fail\n");
+		return -EINVAL;
+	}
+
+	ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	return 0;
+}
+
+static int add_ctrl_display_re_ordering(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops re_ordering_ops = {
+		.s_ctrl = set_display_re_ordering,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&re_ordering_ops,
+			V4L2_CID_MPEG_VIDEO_H264_ASO,
+			0, 1, 1, 0);
+	if (!ctrl) {
+		vpu_err("add ctrl display re ordering fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_force_key_frame(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops force_key_frame_ops = {
+		.s_ctrl = set_force_key_frame,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+			&force_key_frame_ops,
+			V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
+			0, 0, 0, 0);
+	if (!ctrl) {
+		vpu_err("add ctrl force key frame fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_cpb_size(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_cpb_size_ops = {
+		.s_ctrl = set_h264_cpb_size,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				&ctrl_cpb_size_ops,
+				V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+				64, 10240, 1, 1024);
+
+	if (!ctrl) {
+		vpu_err("add ctrl h264 cpb size fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_vui_sar_enable(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_vui_sar_enable_ops = {
+		.s_ctrl = set_h264_vui_sar_enable,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				&ctrl_vui_sar_enable_ops,
+				V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+				0, 1, 1, 1);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 vui sar enable fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_vui_sar_idc(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_vui_sar_idc_ops = {
+		.s_ctrl = set_h264_vui_sar_idc,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler,
+				&ctrl_vui_sar_idc_ops,
+				V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+				V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+				0x0,
+				V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1);
+
+
+	if (!ctrl) {
+		vpu_err("add ctrl h264 vui sar idc fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_vui_sar_width(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_vui_sar_width_ops = {
+		.s_ctrl = set_h264_vui_sar_width,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				&ctrl_vui_sar_width_ops,
+				V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+				0, USHRT_MAX, 1, 1);
+
+	if (!ctrl) {
+		vpu_err("add ctrl h264 vui sar width fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int add_ctrl_h264_vui_sar_height(struct vpu_ctx *ctx)
+{
+	static const struct v4l2_ctrl_ops ctrl_vui_sar_height_ops = {
+		.s_ctrl = set_h264_vui_sar_height,
+	};
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+				&ctrl_vui_sar_height_ops,
+				V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+				0, USHRT_MAX, 1, 1);
+	if (!ctrl) {
+		vpu_err("add ctrl h264 vui sar height fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vpu_enc_register_ctrls(struct vpu_ctx *ctx)
+{
+	add_ctrl_h264_profile(ctx);
+	add_ctrl_h264_level(ctx);
+	add_ctrl_bitrate_mode(ctx);
+	add_ctrl_bitrate(ctx);
+	add_ctrl_bitrate_peak(ctx);
+	add_ctrl_gop_size(ctx);
+	add_ctrl_i_period(ctx);
+	add_ctrl_b_frames(ctx);
+	add_ctrl_i_frame_qp(ctx);
+	add_ctrl_p_frame_qp(ctx);
+	add_ctrl_b_frame_qp(ctx);
+	add_ctrl_min_buffers_for_output(ctx);
+	add_ctrl_display_re_ordering(ctx);
+	add_ctrl_force_key_frame(ctx);
+	add_ctrl_h264_cpb_size(ctx);
+	add_ctrl_h264_vui_sar_enable(ctx);
+	add_ctrl_h264_vui_sar_idc(ctx);
+	add_ctrl_h264_vui_sar_width(ctx);
+	add_ctrl_h264_vui_sar_height(ctx);
+
+	return 0;
+}
+
+int vpu_enc_setup_ctrls(struct vpu_ctx *ctx)
+{
+	vpu_log_func();
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 11);
+	vpu_enc_register_ctrls(ctx);
+	if (ctx->ctrl_handler.error) {
+		vpu_err("control initialization error (%d)\n",
+			ctx->ctrl_handler.error);
+		return -EINVAL;
+	}
+	ctx->ctrl_inited = true;
+	return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+int vpu_enc_free_ctrls(struct vpu_ctx *ctx)
+{
+	vpu_log_func();
+
+	if (ctx->ctrl_inited) {
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		ctx->ctrl_inited = false;
+	}
+
+	return 0;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _VPU_ENCODER_CTRL_H
+#define _VPU_ENCODER_CTRL_H
+
+#include "mediasys_types.h"
+
+int vpu_enc_setup_ctrls(struct vpu_ctx *ctx);
+int vpu_enc_free_ctrls(struct vpu_ctx *ctx);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_mem.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_mem.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define TAG	"[VPU Encoder Mem]\t "
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include "vpu_encoder_config.h"
+#include "vpu_encoder_b0.h"
+#include "vpu_encoder_mem.h"
+
+int vpu_enc_init_reserved_memory(struct vpu_enc_mem_info *info)
+{
+	if (!info || !info->phy_addr || !info->size)
+		return -EINVAL;
+
+	info->virt_addr = ioremap_wc(info->phy_addr, info->size);
+	if (!info->virt_addr)
+		return -EINVAL;
+	memset_io(info->virt_addr, 0, info->size);
+	info->bytesused = 0;
+	INIT_LIST_HEAD(&info->memorys);
+	mutex_init(&info->lock);
+
+	return 0;
+}
+
+void vpu_enc_release_reserved_memory(struct vpu_enc_mem_info *info)
+{
+	struct vpu_enc_mem_item *item = NULL;
+	struct vpu_enc_mem_item *tmp = NULL;
+
+	if (!info)
+		return;
+
+	mutex_lock(&info->lock);
+	list_for_each_entry_safe(item, tmp, &info->memorys, list) {
+		list_del_init(&item->list);
+		info->bytesused -= item->size;
+		vpu_dbg(LVL_MEM, "free reserved memory %ld\n", item->size);
+		VPU_SAFE_RELEASE(item, vfree);
+	}
+	mutex_unlock(&info->lock);
+
+	mutex_destroy(&info->lock);
+	if (info->virt_addr) {
+		iounmap(info->virt_addr);
+		info->virt_addr = NULL;
+	}
+}
+
+int vpu_enc_alloc_reserved_mem(struct vpu_enc_mem_info *info,
+				struct buffer_addr *buffer)
+{
+	struct vpu_enc_mem_item *item = NULL;
+	struct list_head *pos = NULL;
+	unsigned long offset = 0;
+	int ret;
+
+	if (!info || !buffer)
+		return -EINVAL;
+
+	mutex_lock(&info->lock);
+	if (buffer->size + info->bytesused > info->size) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	list_for_each_entry(item, &info->memorys, list) {
+		if (item->offset - offset >= buffer->size) {
+			pos = &item->list;
+			break;
+		}
+		offset = item->offset + item->size;
+	}
+	if (!pos && info->size - offset >= buffer->size)
+		pos = &info->memorys;
+	if (!pos) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+	item = vzalloc(sizeof(*item));
+	if (!item) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	item->offset = offset;
+	item->virt_addr = info->virt_addr + offset;
+	item->phy_addr = info->phy_addr + offset;
+	item->size = buffer->size;
+	list_add_tail(&item->list, pos);
+	info->bytesused += buffer->size;
+	vpu_dbg(LVL_MEM, "alloc reserved memory <0x%lx 0x%lx(%ld)>\n",
+			item->phy_addr, item->size, item->size);
+	buffer->virt_addr = item->virt_addr;
+	buffer->phy_addr = item->phy_addr;
+	ret = 0;
+exit:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+int vpu_enc_free_reserved_mem(struct vpu_enc_mem_info *info,
+				struct buffer_addr *buffer)
+{
+	struct vpu_enc_mem_item *item = NULL;
+	struct vpu_enc_mem_item *tmp = NULL;
+	unsigned long offset;
+	int ret = -EINVAL;
+
+	if (!info || !buffer)
+		return -EINVAL;
+	if (!buffer->virt_addr)
+		return 0;
+
+	if (buffer->phy_addr < info->phy_addr) {
+		vpu_err("invalid reserved memory addr : 0x%llx %d\n",
+				buffer->phy_addr, buffer->size);
+		return -EINVAL;
+	}
+
+	offset = buffer->phy_addr - info->phy_addr;
+	if (offset + buffer->size > info->size) {
+		vpu_err("invalid reserved memory addr : 0x%llx %d\n",
+				buffer->phy_addr, buffer->size);
+		return -EINVAL;
+	}
+
+	mutex_lock(&info->lock);
+	list_for_each_entry_safe(item, tmp, &info->memorys, list) {
+		if (offset < item->offset)
+			continue;
+		if (offset + buffer->size > item->offset + item->size)
+			continue;
+		list_del_init(&item->list);
+		info->bytesused -= item->size;
+		vpu_dbg(LVL_MEM, "free reserved memory <0x%lx 0x%lx(%ld)>\n",
+			item->phy_addr, item->size, item->size);
+		VPU_SAFE_RELEASE(item, vfree);
+		ret = 0;
+		break;
+	}
+	mutex_unlock(&info->lock);
+
+	return ret;
+}
+
+void vpu_enc_add_dma_size(struct vpu_attr *attr, unsigned long size)
+{
+	if (!attr)
+		return;
+
+	atomic64_add(size, &attr->total_dma_size);
+}
+
+void vpu_enc_sub_dma_size(struct vpu_attr *attr, unsigned long size)
+{
+	if (!attr)
+		return;
+
+	atomic64_sub(size, &attr->total_dma_size);
+}
+
+int vpu_enc_alloc_dma_buffer(struct vpu_ctx *ctx, struct buffer_addr *buffer)
+{
+	if (!ctx || !ctx->dev || !buffer || !buffer->size)
+		return -EINVAL;
+
+	vpu_dbg(LVL_MEM, "alloc coherent dma %d\n", buffer->size);
+	buffer->virt_addr = dma_alloc_coherent(ctx->dev->generic_dev,
+						buffer->size,
+						(dma_addr_t *)&buffer->phy_addr,
+						GFP_KERNEL | GFP_DMA32);
+	if (!buffer->virt_addr) {
+		vpu_err("encoder alloc coherent dma(%d) fail\n",
+				buffer->size);
+		return -ENOMEM;
+	}
+	memset_io(buffer->virt_addr, 0, buffer->size);
+	vpu_enc_add_dma_size(get_vpu_ctx_attr(ctx), buffer->size);
+
+	return 0;
+}
+
+void vpu_enc_init_dma_buffer(struct buffer_addr *buffer)
+{
+	if (!buffer)
+		return;
+
+	buffer->virt_addr = NULL;
+	buffer->phy_addr = 0;
+	buffer->size = 0;
+}
+
+int vpu_enc_free_dma_buffer(struct vpu_ctx *ctx, struct buffer_addr *buffer)
+{
+	if (!ctx || !ctx->dev || !buffer)
+		return -EINVAL;
+
+	if (!buffer->virt_addr)
+		return 0;
+
+	vpu_dbg(LVL_MEM, "free coherent dma %d\n", buffer->size);
+	vpu_enc_sub_dma_size(get_vpu_ctx_attr(ctx), buffer->size);
+	dma_free_coherent(ctx->dev->generic_dev, buffer->size,
+				buffer->virt_addr, buffer->phy_addr);
+
+	vpu_enc_init_dma_buffer(buffer);
+
+	return 0;
+}
+
+static bool check_mem_resource_is_valid(MEDIAIP_ENC_MEM_RESOURCE *resource)
+{
+	if (!resource)
+		return false;
+	if (resource->uMemVirtAddr >= VPU_MU_MAX_ADDRESS)
+		return false;
+	if (resource->uMemVirtAddr + resource->uMemSize > VPU_MU_MAX_ADDRESS)
+		return false;
+	return true;
+}
+
+static u32 get_enc_alloc_size(u32 size)
+{
+	u32 esize = ALIGN(size, PAGE_SIZE);
+
+	if (esize < size + sizeof(u32))
+		esize += PAGE_SIZE;
+
+	return esize;
+}
+
+static int alloc_mem_res(struct vpu_ctx *ctx, struct buffer_addr *buffer,
+			MEDIAIP_ENC_MEM_RESOURCE *resource, u32 size)
+{
+	int ret;
+
+	if (!ctx || !buffer || !resource)
+		return -EINVAL;
+
+	if (!size) {
+		vpu_err("invalid memory resource size : %d\n", size);
+		return -EINVAL;
+	}
+
+	buffer->size = get_enc_alloc_size(size);
+	ret = vpu_enc_alloc_dma_buffer(ctx, buffer);
+	if (ret)
+		return ret;
+
+	resource->uMemPhysAddr = buffer->phy_addr;
+	resource->uMemVirtAddr = cpu_phy_to_mu(ctx->core_dev, buffer->phy_addr);
+	resource->uMemSize = size;
+
+	return 0;
+}
+
+static int free_mem_res(struct vpu_ctx *ctx, struct buffer_addr *buffer,
+			MEDIAIP_ENC_MEM_RESOURCE *resource)
+{
+	if (!ctx || !buffer || !resource)
+		return -EINVAL;
+
+	vpu_enc_free_dma_buffer(ctx, buffer);
+
+	resource->uMemPhysAddr = 0;
+	resource->uMemVirtAddr = 0;
+	resource->uMemSize = 0;
+
+	return 0;
+}
+
+static int alloc_reserved_mem_res(struct vpu_ctx *ctx,
+				struct buffer_addr *buffer,
+				MEDIAIP_ENC_MEM_RESOURCE *resource,
+				u32 size)
+{
+	int ret;
+
+	if (!ctx || !ctx->dev || !buffer || !resource)
+		return -EINVAL;
+
+	if (!size) {
+		vpu_err("invalid memory resource size : %d\n", size);
+		return -EINVAL;
+	}
+
+	buffer->size = get_enc_alloc_size(size);
+	ret = vpu_enc_alloc_reserved_mem(&ctx->dev->reserved_mem, buffer);
+	if (ret)
+		return ret;
+
+	resource->uMemPhysAddr = buffer->phy_addr;
+	resource->uMemVirtAddr = cpu_phy_to_mu(ctx->core_dev, buffer->phy_addr);
+	resource->uMemSize = size;
+
+	return 0;
+}
+
+static int free_reserved_mem_res(struct vpu_ctx *ctx,
+				struct buffer_addr *buffer,
+				MEDIAIP_ENC_MEM_RESOURCE *resource)
+{
+	if (!ctx || !ctx->dev || !buffer || !resource)
+		return -EINVAL;
+
+	vpu_enc_free_reserved_mem(&ctx->dev->reserved_mem, buffer);
+
+	resource->uMemPhysAddr = 0;
+	resource->uMemVirtAddr = 0;
+	resource->uMemSize = 0;
+
+	return 0;
+}
+
+static int free_enc_frames(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int i;
+
+	vpu_log_func();
+	for (i = 0; i < ctx->mem_req.uEncFrmNum; i++)
+		free_mem_res(ctx, &ctx->encFrame[i],
+				&pool->tEncFrameBuffers[i]);
+
+	return 0;
+}
+
+static int alloc_enc_frames(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int i;
+	int ret;
+
+	vpu_log_func();
+	for (i = 0; i < ctx->mem_req.uEncFrmNum; i++) {
+		ret = alloc_mem_res(ctx,
+				&ctx->encFrame[i],
+				&pool->tEncFrameBuffers[i],
+				ctx->mem_req.uEncFrmSize);
+		if (ret) {
+			vpu_err("alloc enc frame[%d] fail\n", i);
+			goto error;
+		}
+		vpu_dbg(LVL_MEM, "encFrame[%d]: 0x%llx,%d(%d)\n", i,
+				ctx->encFrame[i].phy_addr,
+				ctx->mem_req.uEncFrmSize,
+				ctx->encFrame[i].size);
+	}
+
+	return 0;
+error:
+	free_enc_frames(ctx, pool);
+	return ret;
+}
+
+static int free_ref_frames(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int i;
+
+	vpu_log_func();
+	for (i = 0; i < ctx->mem_req.uRefFrmNum; i++)
+		free_mem_res(ctx, &ctx->refFrame[i],
+				&pool->tRefFrameBuffers[i]);
+
+	return 0;
+}
+
+static int alloc_ref_frames(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int i;
+	int ret;
+
+	vpu_log_func();
+	for (i = 0; i < ctx->mem_req.uRefFrmNum; i++) {
+		ret = alloc_mem_res(ctx,
+				&ctx->refFrame[i],
+				&pool->tRefFrameBuffers[i],
+				ctx->mem_req.uRefFrmSize);
+		if (ret) {
+			vpu_err("alloc ref frame[%d] fail\n", i);
+			goto error;
+		}
+		vpu_dbg(LVL_MEM, "refFrame[%d]: 0x%llx,%d(%d)\n", i,
+				ctx->refFrame[i].phy_addr,
+				ctx->mem_req.uRefFrmSize,
+				ctx->refFrame[i].size);
+	}
+
+	return 0;
+error:
+	free_ref_frames(ctx, pool);
+	return ret;
+}
+
+static int free_act_frame(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	if (!ctx || !pool)
+		return -EINVAL;
+
+	vpu_log_func();
+	free_reserved_mem_res(ctx, &ctx->actFrame, &pool->tActFrameBufferArea);
+
+	return 0;
+}
+
+static int alloc_act_frame(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int ret = 0;
+
+	vpu_log_func();
+	ret = alloc_reserved_mem_res(ctx,
+			&ctx->actFrame,
+			&pool->tActFrameBufferArea,
+			ctx->mem_req.uActBufSize);
+	if (ret) {
+		vpu_err("alloc act frame fail\n");
+		return ret;
+	}
+
+	if (!check_mem_resource_is_valid(&pool->tActFrameBufferArea)) {
+		vpu_err("invalid actFrames address, 0x%x, 0x%x, 0x%x\n",
+				pool->tActFrameBufferArea.uMemPhysAddr,
+				pool->tActFrameBufferArea.uMemVirtAddr,
+				pool->tActFrameBufferArea.uMemSize);
+		free_act_frame(ctx, pool);
+		return -EINVAL;
+	}
+
+	vpu_dbg(LVL_MEM, "actFrame: 0x%llx, %d(%d)\n",
+			ctx->actFrame.phy_addr,
+			ctx->mem_req.uActBufSize,
+			ctx->actFrame.size);
+	return 0;
+}
+
+static void set_mem_pattern(u32 *ptr)
+{
+	if (!ptr)
+		return;
+	*ptr = VPU_MEM_PATTERN;
+}
+
+static int check_mem_pattern(u32 *ptr)
+{
+	if (!ptr)
+		return -EINVAL;
+
+	if (*ptr != VPU_MEM_PATTERN)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void vpu_enc_set_mem_pattern(struct vpu_ctx *ctx)
+{
+	int i;
+
+	if (!ctx)
+		return;
+
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++) {
+		if (!ctx->encFrame[i].virt_addr)
+			continue;
+		set_mem_pattern(ctx->encFrame[i].virt_addr +
+				ctx->mem_req.uEncFrmSize);
+	}
+
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++) {
+		if (!ctx->refFrame[i].virt_addr)
+			continue;
+		set_mem_pattern(ctx->refFrame[i].virt_addr +
+				ctx->mem_req.uRefFrmSize);
+	}
+
+	if (ctx->actFrame.virt_addr)
+		set_mem_pattern(ctx->actFrame.virt_addr +
+				ctx->mem_req.uActBufSize);
+}
+
+int vpu_enc_check_mem_overstep(struct vpu_ctx *ctx)
+{
+	int i;
+	int ret;
+	int flag = 0;
+
+	if (!ctx)
+		return -EINVAL;
+
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++) {
+		if (!ctx->encFrame[i].virt_addr)
+			continue;
+		ret = check_mem_pattern(ctx->encFrame[i].virt_addr +
+					ctx->mem_req.uEncFrmSize);
+		if (ret) {
+			vpu_err("***error:[%d][%d]encFrame[%d] out of bounds\n",
+					ctx->core_dev->id, ctx->str_index, i);
+			flag = 1;
+		}
+	}
+
+	for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++) {
+		if (!ctx->refFrame[i].virt_addr)
+			continue;
+		ret = check_mem_pattern(ctx->refFrame[i].virt_addr +
+					ctx->mem_req.uRefFrmSize);
+		if (ret) {
+			vpu_err("***error:[%d][%d]refFrame[%d] out of bounds\n",
+					ctx->core_dev->id, ctx->str_index, i);
+			flag = 1;
+		}
+	}
+
+	if (ctx->actFrame.virt_addr) {
+		ret = check_mem_pattern(ctx->actFrame.virt_addr +
+					ctx->mem_req.uActBufSize);
+		if (ret) {
+			vpu_err("***error:[%d][%d]actFrame out of bounds\n",
+					ctx->core_dev->id, ctx->str_index);
+			flag = 1;
+		}
+	}
+
+	if (flag) {
+		vpu_err("Error:Memory out of bounds in [%d][%d]\n",
+			ctx->core_dev->id, ctx->str_index);
+		vpu_enc_set_mem_pattern(ctx);
+	}
+
+	return 0;
+}
+
+int vpu_enc_alloc_mem(struct vpu_ctx *ctx,
+			MEDIAIP_ENC_MEM_REQ_DATA *req_data,
+			pMEDIAIP_ENC_MEM_POOL pool)
+{
+	int ret;
+
+	if (!ctx || !req_data || !pool)
+		return -EINVAL;
+
+	if (ctx->mem_req.uEncFrmSize < req_data->uEncFrmSize ||
+			ctx->mem_req.uEncFrmNum < req_data->uEncFrmNum) {
+		free_enc_frames(ctx, pool);
+		ctx->mem_req.uEncFrmSize = req_data->uEncFrmSize;
+		ctx->mem_req.uEncFrmNum = req_data->uEncFrmNum;
+		ret = alloc_enc_frames(ctx, pool);
+		if (ret)
+			return ret;
+	}
+
+	if (ctx->mem_req.uRefFrmSize < req_data->uRefFrmSize ||
+			ctx->mem_req.uRefFrmNum < req_data->uRefFrmNum) {
+		free_ref_frames(ctx, pool);
+		ctx->mem_req.uRefFrmSize = req_data->uRefFrmSize;
+		ctx->mem_req.uRefFrmNum = req_data->uRefFrmNum;
+		ret = alloc_ref_frames(ctx, pool);
+		if (ret)
+			goto error_alloc_refs;
+	}
+
+	if (ctx->mem_req.uActBufSize < req_data->uActBufSize) {
+		free_act_frame(ctx, pool);
+		ctx->mem_req.uActBufSize = req_data->uActBufSize;
+		ret = alloc_act_frame(ctx, pool);
+		if (ret)
+			goto error_alloc_act;
+	}
+
+	vpu_enc_set_mem_pattern(ctx);
+
+	return 0;
+error_alloc_act:
+	free_ref_frames(ctx, pool);
+error_alloc_refs:
+	free_enc_frames(ctx, pool);
+	return ret;
+}
+
+int vpu_enc_free_mem(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool)
+{
+	if (!ctx || !pool)
+		return -EINVAL;
+
+	free_act_frame(ctx, pool);
+	free_ref_frames(ctx, pool);
+	free_enc_frames(ctx, pool);
+
+	return 0;
+}
+
+int vpu_enc_alloc_stream(struct vpu_ctx *ctx)
+{
+	int ret;
+
+	if (ctx->encoder_stream.virt_addr)
+		return 0;
+
+	ctx->encoder_stream.size =
+		max_t(u32, ctx->cpb_size * CPB_COUNT, STREAM_SIZE);
+	ret = vpu_enc_alloc_dma_buffer(ctx, &ctx->encoder_stream);
+	if (ret) {
+		vpu_err("alloc encoder stream buffer fail\n");
+		return -ENOMEM;
+	}
+	vpu_dbg(LVL_MEM, "encoder_stream: 0x%llx, %d\n",
+			ctx->encoder_stream.phy_addr, ctx->encoder_stream.size);
+
+	return 0;
+}
+
+void vpu_enc_free_stream(struct vpu_ctx *ctx)
+{
+	vpu_enc_free_dma_buffer(ctx, &ctx->encoder_stream);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_mem.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_mem.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _VPU_ENCODER_MEM_H
+#define _VPU_ENCODER_MEM_H
+
+#include "vpu_encoder_b0.h"
+
+int vpu_enc_init_reserved_memory(struct vpu_enc_mem_info *info);
+void vpu_enc_release_reserved_memory(struct vpu_enc_mem_info *info);
+void vpu_enc_add_dma_size(struct vpu_attr *attr, unsigned long size);
+void vpu_enc_sub_dma_size(struct vpu_attr *attr, unsigned long size);
+int vpu_enc_alloc_dma_buffer(struct vpu_ctx *ctx, struct buffer_addr *buffer);
+int vpu_enc_free_dma_buffer(struct vpu_ctx *ctx, struct buffer_addr *buffer);
+void vpu_enc_init_dma_buffer(struct buffer_addr *buffer);
+int vpu_enc_check_mem_overstep(struct vpu_ctx *ctx);
+int vpu_enc_alloc_mem(struct vpu_ctx *ctx,
+			MEDIAIP_ENC_MEM_REQ_DATA *req_data,
+			pMEDIAIP_ENC_MEM_POOL pool);
+int vpu_enc_free_mem(struct vpu_ctx *ctx, pMEDIAIP_ENC_MEM_POOL pool);
+int vpu_enc_alloc_stream(struct vpu_ctx *ctx);
+void vpu_enc_free_stream(struct vpu_ctx *ctx);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_mu.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_mu.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_mu.h
+ *
+ */
+
+#include "vpu_encoder_mu.h"
+
+static void vpu_enc_mbox_free(struct core_device *core_dev)
+{
+	if (core_dev->sc_chan_tx0.ch && !IS_ERR(core_dev->sc_chan_tx0.ch))
+		mbox_free_channel(core_dev->sc_chan_tx0.ch);
+	if (core_dev->sc_chan_tx1.ch && !IS_ERR(core_dev->sc_chan_tx1.ch))
+		mbox_free_channel(core_dev->sc_chan_tx1.ch);
+	if (core_dev->sc_chan_rx.ch && !IS_ERR(core_dev->sc_chan_rx.ch))
+		mbox_free_channel(core_dev->sc_chan_rx.ch);
+
+	core_dev->sc_chan_tx0.ch = NULL;
+	core_dev->sc_chan_tx1.ch = NULL;
+	core_dev->sc_chan_rx.ch = NULL;
+}
+
+static void vpu_enc_mu_inq_msg(struct core_device *core_dev, void *msg)
+{
+	if (&core_dev->mu_msg_fifo == NULL) {
+		vpu_err("mu_msg_fifo is NULL\n");
+		return;
+	}
+
+	if (kfifo_in(&core_dev->mu_msg_fifo, msg, sizeof(u_int32)) != sizeof(u_int32)) {
+		vpu_err("No memory for mu msg fifo\n");
+		return;
+	}
+
+	queue_work(core_dev->workqueue, &core_dev->msg_work);
+}
+
+static void vpu_enc_rx_callback(struct mbox_client *c, void *msg)
+{
+	struct vpu_sc_chan *sc_chan = container_of(c, struct vpu_sc_chan, cl);
+	struct core_device *dev =
+		container_of(sc_chan, struct core_device, sc_chan_rx);
+
+	vpu_enc_mu_inq_msg(dev, msg);
+}
+
+static int vpu_enc_rtx_channel_request(struct vpu_sc_chan *sc_chan, bool block)
+{
+	struct device *dev = sc_chan->dev->generic_dev;
+	struct mbox_client *cl;
+	int ret = 0;
+
+	if (sc_chan->ch && !IS_ERR(sc_chan->ch)) {
+		vpu_dbg(LVL_WARN, "vpu_sc_chan(%s) has been requested\n",
+			sc_chan->name);
+		return 0;
+	}
+
+	cl = &sc_chan->cl;
+	cl->dev = dev;
+	if (block) {
+		cl->tx_block = true;
+		cl->tx_tout = 1000;
+	} else {
+		cl->tx_block = false;
+	}
+	cl->knows_txdone = false;
+	cl->rx_callback = vpu_enc_rx_callback;
+
+	sc_chan->ch = mbox_request_channel_byname(cl, sc_chan->name);
+	if (IS_ERR(sc_chan->ch)) {
+		ret = PTR_ERR(sc_chan->ch);
+		if (ret != -EPROBE_DEFER)
+			vpu_err("Failed to request mbox chan %s, ret: %d\n",
+				sc_chan->name, ret);
+	}
+
+	return ret;
+}
+
+static int vpu_enc_rtx_channel_init(struct core_device *core_dev)
+{
+	int ret = 0;
+
+	/* Normally, use block mode to ensure msg be writed correctly.
+	 * Firmware do not separate read tx1 channel until receive tx0.
+	 * Hence, when use tx1 must combine with tx0, and flow is tx1 -> tx0 to
+	 * ensure firmware read tx1 correctly. Due to tx1 write first, tx1 shall
+	 * use non-block mode, otherwise always wait timeout.
+	 * In addition, tx0 use block mode then also can ensure tx1 msg be
+	 * writed correctly as tx0 and tx1 are considered as a whole in this
+	 * case.
+	 */
+
+	/* core device id count from 0, mu count from 1 */
+
+	core_dev->sc_chan_tx0.dev = core_dev;
+	scnprintf(core_dev->sc_chan_tx0.name, sizeof(core_dev->sc_chan_tx0.name) - 1,
+		  "enc%d_tx0", core_dev->id + 1);
+	ret = vpu_enc_rtx_channel_request(&core_dev->sc_chan_tx0, true);
+	if (ret)
+		goto err;
+
+	core_dev->sc_chan_tx1.dev = core_dev;
+	scnprintf(core_dev->sc_chan_tx1.name, sizeof(core_dev->sc_chan_tx1.name) - 1,
+		  "enc%d_tx1", core_dev->id + 1);
+	ret = vpu_enc_rtx_channel_request(&core_dev->sc_chan_tx1, false);
+	if (ret)
+		goto err;
+
+	core_dev->sc_chan_rx.dev = core_dev;
+	scnprintf(core_dev->sc_chan_rx.name, sizeof(core_dev->sc_chan_rx.name) - 1,
+		  "enc%d_rx", core_dev->id + 1);
+	ret = vpu_enc_rtx_channel_request(&core_dev->sc_chan_rx, true);
+	if (ret)
+		goto err;
+
+	return ret;
+
+err:
+	vpu_enc_mbox_free(core_dev);
+
+	return ret;
+}
+
+int vpu_enc_mu_request(struct core_device *core_dev)
+{
+	int ret = 0;
+
+	if (!core_dev->vpu_mu_init) {
+		ret = vpu_enc_rtx_channel_init(core_dev);
+		if (!ret)
+			core_dev->vpu_mu_init = TRUE;
+		else
+			vpu_dbg(LVL_WARN, "warning: %s init rtx channel failed, ret: %d\n",
+				core_dev->name, ret);
+	}
+
+	return ret;
+}
+
+void vpu_enc_mu_free(struct core_device *core_dev)
+{
+	if (core_dev->vpu_mu_init) {
+		vpu_enc_mbox_free(core_dev);
+		core_dev->vpu_mu_init = FALSE;
+	}
+}
+
+void vpu_enc_mu_send_msg(struct core_device *core_dev, MSG_Type type, u_int32 value)
+{
+	/* Ensure firmware read tx1 correctly when receive tx0,
+	 * need to write tx1 first.
+	 */
+
+	if (value != 0xffff)
+		mbox_send_message(core_dev->sc_chan_tx1.ch, &value);
+	if (type != 0xffff)
+		mbox_send_message(core_dev->sc_chan_tx0.ch, &type);
+}
+
+u_int32 vpu_enc_mu_receive_msg(struct core_device *core_dev, void *msg)
+{
+	int ret = 0;
+
+	if (kfifo_len(&core_dev->mu_msg_fifo) >= sizeof(u_int32)) {
+		ret = kfifo_out(&core_dev->mu_msg_fifo, msg, sizeof(u_int32));
+		if (ret != sizeof(u_int32))
+			vpu_err("error: kfifo_out mu msg failed\n, ret=%d\n",
+				ret);
+	} else {
+		ret = kfifo_len(&core_dev->mu_msg_fifo);
+	}
+
+	return ret;
+}
+
+static int vpu_enc_sc_get_fuse(struct imx_sc_ipc *ipc, u32 word, u32 *fuse)
+{
+	struct vpu_sc_msg_misc msg;
+	struct imx_sc_rpc_msg *hdr = &msg.hdr;
+	int ret;
+
+	hdr->ver = IMX_SC_RPC_VERSION;
+	hdr->svc = IMX_SC_RPC_SVC_MISC;
+	hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ;
+	hdr->size = 2;
+
+	msg.word = word;
+
+	ret = imx_scu_call_rpc(ipc, &msg, true);
+	if (ret)
+		return ret;
+
+	*fuse = msg.word;
+
+	return ret;
+}
+
+int vpu_enc_sc_check_fuse(void)
+{
+	u_int32 fuse = 0xffff;
+	int ret = 0;
+	struct imx_sc_ipc *ipcHandle;
+
+	ret = imx_scu_get_handle(&ipcHandle);
+	if (ret) {
+		vpu_err("error: scu get handle fail: %d\n", ret);
+		return -EINVAL;
+	}
+
+	ret = vpu_enc_sc_get_fuse(ipcHandle, VPU_DISABLE_BITS, &fuse);
+	if (ret) {
+		vpu_dbg(LVL_WARN, "warning: read value fail: %d\n", ret);
+		return ret;
+	}
+
+	if (fuse & VPU_ENCODER_MASK) {
+		vpu_err("warning: VPU Encoder is disabled\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+void vpu_enc_mu_enable_rx(struct core_device *core_dev)
+{
+
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_mu.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_mu.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_mu.h
+ *
+ */
+
+#ifndef _VPU_ENCODER_MU_H_
+#define _VPU_ENCODER_MU_H_
+
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/mx8_mu.h>
+#include <linux/workqueue.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_client.h>
+#include <linux/pm_domain.h>
+#include <linux/kfifo.h>
+
+#include "vpu_encoder_b0.h"
+
+int vpu_enc_mu_request(struct core_device *core_dev);
+void vpu_enc_mu_free(struct core_device *core_dev);
+void vpu_enc_mu_send_msg(struct core_device *core_dev, MSG_Type type, u_int32 value);
+u_int32 vpu_enc_mu_receive_msg(struct core_device *core_dev, void *msg);
+int vpu_enc_sc_check_fuse(void);
+void vpu_enc_mu_enable_rx(struct core_device *core_dev);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_pm.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_pm.c
+ *
+ */
+
+#include "vpu_encoder_pm.h"
+
+int vpu_enc_attach_pm_domains(struct vpu_dev *dev)
+{
+	int ret = 0;
+
+	dev->pd_vpu = dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpu");
+	if (IS_ERR(dev->pd_vpu)) {
+		vpu_err("error: unable to get vpu power domain\n");
+		ret = PTR_ERR(dev->pd_vpu);
+		goto err;
+	}
+	dev->pd_vpu_link = device_link_add(&dev->plat_dev->dev, dev->pd_vpu,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_vpu_link)) {
+		vpu_err("error: unable to link vpu power domain\n");
+		ret = PTR_ERR(dev->pd_vpu_link);
+		goto err;
+	}
+
+	dev->pd_enc1 = dev_pm_domain_attach_by_name(&dev->plat_dev->dev,
+						    "vpuenc1");
+	if (IS_ERR(dev->pd_enc1)) {
+		vpu_err("error: unable to get vpu enc1 power domain\n");
+		ret = PTR_ERR(dev->pd_enc1);
+		goto err;
+	}
+	dev->pd_enc1_link = device_link_add(&dev->plat_dev->dev, dev->pd_enc1,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_enc1_link)) {
+		vpu_err("error: unable to link vpu enc1 power domain\n");
+		ret = PTR_ERR(dev->pd_enc1_link);
+		goto err;
+	}
+
+	dev->pd_mu1 = dev_pm_domain_attach_by_name(&dev->plat_dev->dev,
+						   "vpumu1");
+	if (IS_ERR(dev->pd_mu1)) {
+		vpu_err("error: unable to get vpu mu1 power domain\n");
+		ret = PTR_ERR(dev->pd_mu1);
+		goto err;
+	}
+	dev->pd_mu1_link = device_link_add(&dev->plat_dev->dev, dev->pd_mu1,
+		DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_mu1_link)) {
+		vpu_err("error: unable to link vpu mu1 power domain\n");
+		ret = PTR_ERR(dev->pd_mu1_link);
+		goto err;
+	}
+
+	if (dev->plat_type == IMX8QM) {
+		dev->pd_enc2 = dev_pm_domain_attach_by_name(&dev->plat_dev->dev,
+							    "vpuenc2");
+		if (IS_ERR(dev->pd_enc2)) {
+			vpu_err("error: unable to get vpu enc2 power domain\n");
+			ret = PTR_ERR(dev->pd_enc2);
+			goto err;
+		}
+		dev->pd_enc2_link = device_link_add(&dev->plat_dev->dev, dev->pd_enc2,
+			DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+		if (IS_ERR(dev->pd_enc2_link)) {
+			vpu_err("error: unable to link vpu enc2 power domain\n");
+			ret = PTR_ERR(dev->pd_enc2_link);
+			goto err;
+		}
+
+		dev->pd_mu2 = dev_pm_domain_attach_by_name(&dev->plat_dev->dev,
+							   "vpumu2");
+		if (IS_ERR(dev->pd_mu2)) {
+			vpu_err("error: unable to get vpu mu2 power domain\n");
+			ret = PTR_ERR(dev->pd_mu2);
+			goto err;
+		}
+
+		dev->pd_mu2_link = device_link_add(&dev->plat_dev->dev, dev->pd_mu2,
+			DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+		if (IS_ERR(dev->pd_mu2_link)) {
+			vpu_err("error: unable to link vpu mu2 power domain\n");
+			ret = PTR_ERR(dev->pd_mu2_link);
+			goto err;
+		}
+	}
+
+	return ret;
+err:
+	vpu_enc_detach_pm_domains(dev);
+	return ret;
+}
+
+void vpu_enc_detach_pm_domains(struct vpu_dev *dev)
+{
+	if (dev->pd_vpu_link && !IS_ERR(dev->pd_vpu_link))
+		device_link_del(dev->pd_vpu_link);
+	if (dev->pd_vpu && !IS_ERR(dev->pd_vpu))
+		dev_pm_domain_detach(dev->pd_vpu, true);
+
+	if (dev->pd_enc1_link && !IS_ERR(dev->pd_enc1_link))
+		device_link_del(dev->pd_enc1_link);
+	if (dev->pd_enc1 && !IS_ERR(dev->pd_enc1))
+		dev_pm_domain_detach(dev->pd_enc1, true);
+
+	if (dev->pd_mu1_link && !IS_ERR(dev->pd_mu1_link))
+		device_link_del(dev->pd_mu1_link);
+	if (dev->pd_mu1 && !IS_ERR(dev->pd_mu1))
+		dev_pm_domain_detach(dev->pd_mu1, true);
+
+	if (dev->plat_type == IMX8QM) {
+		if (dev->pd_enc2_link && !IS_ERR(dev->pd_enc2_link))
+			device_link_del(dev->pd_enc2_link);
+		if (dev->pd_enc2 && !IS_ERR(dev->pd_enc2))
+			dev_pm_domain_detach(dev->pd_enc2, true);
+		if (dev->pd_mu2_link && !IS_ERR(dev->pd_mu2_link))
+			device_link_del(dev->pd_mu2_link);
+		if (dev->pd_mu2 && !IS_ERR(dev->pd_mu2))
+			dev_pm_domain_detach(dev->pd_mu2, true);
+	}
+
+	dev->pd_vpu = NULL;
+	dev->pd_vpu_link = NULL;
+	dev->pd_enc1 = NULL;
+	dev->pd_enc1_link = NULL;
+	dev->pd_mu1 = NULL;
+	dev->pd_mu1_link = NULL;
+	if (dev->plat_type == IMX8QM) {
+		dev->pd_enc2 = NULL;
+		dev->pd_enc2_link = NULL;
+		dev->pd_mu2 = NULL;
+		dev->pd_mu2_link = NULL;
+	}
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_pm.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_pm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_pm.h
+ *
+ */
+
+#ifndef _VPU_ENCODER_PM_H_
+#define _VPU_ENCODER_PM_H_
+
+#include <linux/version.h>
+#include <linux/pm_domain.h>
+#include <linux/platform_device.h>
+
+#include "vpu_encoder_b0.h"
+
+int vpu_enc_attach_pm_domains(struct vpu_dev *dev);
+void vpu_enc_detach_pm_domains(struct vpu_dev *dev);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_rpc.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_rpc.c
@@ -0,0 +1,483 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include "vpu_encoder_rpc.h"
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr,
+		u_int32 total_size,
+		u32 *actual_size)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface;
+	unsigned int phy_addr;
+	unsigned int i;
+	unsigned int temp_addr;
+	BUFFER_DESCRIPTOR_TYPE *pSharedCmdBufDescPtr;
+	BUFFER_DESCRIPTOR_TYPE *pSharedMsgBufDescPtr;
+	pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+
+	This->shared_mem_phy = base_phy_addr;
+	This->shared_mem_vir = base_virt_addr;
+	This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr);
+
+	pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+	This->pSharedInterface = pSharedInterface;
+
+	pSharedInterface->FwExecBaseAddr = base_phy_addr;
+	pSharedInterface->FwExecAreaSize = total_size;
+
+	pSharedCmdBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamCmdBufferDesc;
+	pSharedMsgBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamMsgBufferDesc;
+
+	phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE);
+	This->cmd_mem_phy = phy_addr;
+	This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE);
+
+	pSharedCmdBufDescPtr->wptr = phy_addr;
+	pSharedCmdBufDescPtr->rptr = pSharedCmdBufDescPtr->wptr;
+	pSharedCmdBufDescPtr->start = pSharedCmdBufDescPtr->wptr;
+	pSharedCmdBufDescPtr->end = pSharedCmdBufDescPtr->start + CMD_SIZE;
+
+	phy_addr += CMD_SIZE;
+	This->msg_mem_phy = phy_addr;
+	This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+	pSharedMsgBufDescPtr->wptr = phy_addr;
+	pSharedMsgBufDescPtr->rptr = pSharedMsgBufDescPtr->wptr;
+	pSharedMsgBufDescPtr->start = pSharedMsgBufDescPtr->wptr;
+	pSharedMsgBufDescPtr->end = pSharedMsgBufDescPtr->start + MSG_SIZE;
+
+	phy_addr += MSG_SIZE;
+
+	for (i = 0; i < VID_API_NUM_STREAMS; i++) {
+		pSharedInterface->pEncCtrlInterface[i] = phy_addr;
+		phy_addr += sizeof(MEDIA_ENC_API_CONTROL_INTERFACE);
+	}
+
+	for (i = 0; i < VID_API_NUM_STREAMS; i++) {
+		temp_addr = pSharedInterface->pEncCtrlInterface[i];
+		pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)(temp_addr + This->base_offset);
+		pEncCtrlInterface->pEncYUVBufferDesc = phy_addr;
+		phy_addr += sizeof(MEDIAIP_ENC_YUV_BUFFER_DESC);
+		pEncCtrlInterface->pEncStreamBufferDesc = phy_addr;
+		phy_addr += sizeof(BUFFER_DESCRIPTOR_TYPE);
+		pEncCtrlInterface->pEncExpertModeParam = phy_addr;
+		phy_addr += sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM);
+		pEncCtrlInterface->pEncParam = phy_addr;
+		phy_addr += sizeof(MEDIAIP_ENC_PARAM);
+		pEncCtrlInterface->pEncMemPool = phy_addr;
+		phy_addr += sizeof(MEDIAIP_ENC_MEM_POOL);
+		pEncCtrlInterface->pEncEncodingStatus = phy_addr;
+		phy_addr += sizeof(ENC_ENCODING_STATUS);
+		pEncCtrlInterface->pEncDSAStatus = phy_addr;
+		phy_addr += sizeof(ENC_DSA_STATUS_t);
+	}
+	if (actual_size)
+		*actual_size = phy_addr - base_phy_addr;
+}
+
+void rpc_restore_shared_memory_encoder(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface;
+	unsigned int phy_addr;
+
+	This->shared_mem_phy = base_phy_addr;
+	This->shared_mem_vir = base_virt_addr;
+	This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr);
+
+	pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+	This->pSharedInterface = pSharedInterface;
+
+	phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE);
+	This->cmd_mem_phy = phy_addr;
+	This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE);
+
+	phy_addr += CMD_SIZE;
+	This->msg_mem_phy = phy_addr;
+	This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+}
+
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface;
+	MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+	pSharedInterface = (pENC_RPC_HOST_IFACE)Interface;
+	pSystemCfg = &pSharedInterface->sSystemCfg;
+	pSystemCfg->uNumWindsors = 1;
+	pSystemCfg->uWindsorIrqPin[0x0][0x0] = 0x4; // PAL_IRQ_WINDSOR_LOW
+	pSystemCfg->uWindsorIrqPin[0x0][0x1] = 0x5; // PAL_IRQ_WINDSOR_HI
+	pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+	if (core_id == 0)
+		pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0x800000);
+	else
+		pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0xa00000);
+	pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+	pSystemCfg->uHifOffset[0x0] = 0x1C000;
+	pSystemCfg->uHifOffset[0x1] = 0x0;
+
+	pSystemCfg->uDPVBaseAddr = 0x0;
+	pSystemCfg->uDPVIrqPin = 0x0;
+	pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+	pSystemCfg->uFSLCacheBaseAddr[0] = (unsigned int)(regs_base + 0x60000);
+	pSystemCfg->uFSLCacheBaseAddr[1] = (unsigned int)(regs_base + 0x68000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check_encoder(BUFFER_DESCRIPTOR_TYPE *pBufDesc,
+	BOOL bFull,
+	u_int32 uSize,
+	u_int32 *puUpdateAddress)
+{
+	u_int32 uPtr1;
+	u_int32 uPtr2;
+	u_int32 start;
+	u_int32 end;
+	u_int32 uTemp;
+
+	/* bFull is FALSE when send message, write data   */
+	/* bFull is TRUE when process commands, read data */
+	uPtr1 = (bFull) ? pBufDesc->rptr : pBufDesc->wptr;
+	uPtr2 = (bFull) ? pBufDesc->wptr : pBufDesc->rptr;
+
+	if (uPtr1 == uPtr2) {
+		if (bFull)
+			/* No data at all to read */
+			return 0;
+		else {
+			/* wrt pointer equal to read pointer thus the     */
+			/* buffer is completely empty for further writes  */
+			start = pBufDesc->start;
+			end   = pBufDesc->end;
+			/* The address to be returned in this case is for */
+			/* the updated write pointer.                     */
+			uTemp = uPtr1 + uSize;
+			if (uTemp >= end)
+				uTemp -= (end - start);
+			*puUpdateAddress = uTemp;
+			return (end - start);
+		}
+	} else if (uPtr1 < uPtr2) {
+		/* return updated rd pointer address                */
+		/* In this case if size was too big - we expect the */
+		/* external ftn to compare the size against the     */
+		/* space returned.
+		 */
+		*puUpdateAddress = uPtr1 + uSize;
+		return (uPtr2 - uPtr1);
+	}
+	/* We know the system has looped!! */
+	start = pBufDesc->start;
+	end   = pBufDesc->end;
+	uTemp  = uPtr1 + uSize;
+	if (uTemp >= end)
+		uTemp -= (end - start);
+	*puUpdateAddress = uTemp;
+	return ((end - uPtr1) + (uPtr2 - start));
+}
+
+static void rpc_update_cmd_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pCmdDesc)
+{
+	u_int32 uWritePtr;
+
+	/*avoid sw reset fail*/
+	mb();
+	uWritePtr = pCmdDesc->wptr + 4;
+	if (uWritePtr >= pCmdDesc->end)
+		uWritePtr = pCmdDesc->start;
+	pCmdDesc->wptr = uWritePtr;
+}
+
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+		u_int32 idx,
+		u_int32 cmdid,
+		u_int32 cmdnum,
+		u_int32 *local_cmddata)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+	BUFFER_DESCRIPTOR_TYPE *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+	u_int32 *cmddata;
+	u_int32 i;
+	u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+	u_int32 uIgnore;
+	u_int32 uSpace;
+
+	uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pCmdDesc,
+								FALSE,
+								0,
+								&uIgnore);
+	if (uSpace < ((cmdnum + 1) << 2) + 16) {
+		pr_err("[VPU WINDSOR] CmdBuf is no space for [%d] %d\n",
+				idx, cmdid);
+		return;
+	}
+
+	*cmdword = 0;
+	*cmdword |= ((idx & 0x000000ff) << 24);
+	*cmdword |= ((cmdnum & 0x000000ff) << 16);
+	*cmdword |= ((cmdid & 0x00003fff) << 0);
+	rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+
+	for (i = 0; i < cmdnum; i++) {
+		cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+		*cmddata = local_cmddata[i];
+		rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+	}
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This)
+{
+	u_int32 uSpace;
+	u_int32 uIgnore;
+	pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+	BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+	u_int32 msgword;
+	u_int32 msgnum;
+
+	uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pMsgDesc, TRUE, 0, &uIgnore);
+	uSpace = (uSpace >> 2);
+	if (uSpace) {
+		/* get current msgword word */
+		msgword      = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+		/* Find the number of additional words */
+		msgnum  = ((msgword & 0x00ff0000) >> 16);
+
+		/*
+		 * * Check the number of message words against
+		 * * 1) a limit - some sort of maximum or at least
+		 * * the size of the SW buffer the message is read into
+		 * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+		 * * It must be less than space (as opposed to <=) because
+		 * * the message itself is not included in msgword
+		 */
+		if (msgnum < VID_API_MESSAGE_LIMIT) {
+			if (msgnum < uSpace)
+				return API_MSG_AVAILABLE;
+			else
+				return API_MSG_INCOMPLETE;
+		} else
+			return API_MSG_BUFFER_ERROR;
+	}
+	return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pMsgDesc)
+{
+	u_int32 uReadPtr;
+
+	uReadPtr = pMsgDesc->rptr + 4;
+	if (uReadPtr >= pMsgDesc->end)
+		uReadPtr = pMsgDesc->start;
+	pMsgDesc->rptr = uReadPtr;
+}
+
+u32 rpc_read_msg_u32(struct shared_addr *shared_mem)
+{
+	u32 msgword;
+	u32 *ptr = NULL;
+	pENC_RPC_HOST_IFACE iface = NULL;
+	BUFFER_DESCRIPTOR_TYPE *msg_buf = NULL;
+
+	if (!shared_mem)
+		return 0;
+
+	iface = shared_mem->pSharedInterface;
+	msg_buf = &iface->StreamMsgBufferDesc;
+	ptr = shared_mem->msg_mem_vir + msg_buf->rptr - msg_buf->start;
+	rpc_update_msg_buffer_ptr_encoder(msg_buf);
+	msgword = *ptr;
+
+	return msgword;
+}
+
+int rpc_read_msg_array(struct shared_addr *shared_mem, u32 *buf, u32 number)
+{
+	int i;
+	u32 val;
+
+	if (!shared_mem)
+		return -EINVAL;
+
+	for (i = 0; i < number; i++) {
+		val = rpc_read_msg_u32(shared_mem);
+		if (buf)
+			buf[i] = val;
+	}
+
+	return 0;
+}
+
+int rpc_get_msg_header(struct shared_addr *shared_mem, struct msg_header *msg)
+{
+	u32 msgword;
+
+	if (!shared_mem || !msg)
+		return -EINVAL;
+
+	msgword = rpc_read_msg_u32(shared_mem);
+	msg->idx = ((msgword & 0xff000000) >> 24);
+	msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+	msg->msgid = ((msgword & 0x00003fff) >> 0);
+
+	return 0;
+}
+
+static void *phy_to_virt(u_int32 src, unsigned long long offset)
+{
+	void *result;
+
+	result = (void *)(src + offset);
+	return result;
+}
+
+#define GET_CTRL_INTERFACE_MEMBER(shared_mem, index, name, member) \
+	do {\
+		pENC_RPC_HOST_IFACE iface = shared_mem->pSharedInterface; \
+		pMEDIA_ENC_API_CONTROL_INTERFACE ctrl_interface =\
+			phy_to_virt(iface->pEncCtrlInterface[index],\
+					shared_mem->base_offset);\
+		name = phy_to_virt(ctrl_interface->member,\
+				shared_mem->base_offset);\
+	} while (0)
+
+pMEDIAIP_ENC_YUV_BUFFER_DESC rpc_get_yuv_buffer_desc(
+		struct shared_addr *shared_mem, int index)
+{
+	pMEDIAIP_ENC_YUV_BUFFER_DESC desc = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index, desc, pEncYUVBufferDesc);
+
+	return desc;
+}
+
+pBUFFER_DESCRIPTOR_TYPE rpc_get_stream_buffer_desc(
+		struct shared_addr *shared_mem, int index)
+{
+	pBUFFER_DESCRIPTOR_TYPE desc = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index,
+				desc, pEncStreamBufferDesc);
+
+	return desc;
+}
+
+pMEDIAIP_ENC_EXPERT_MODE_PARAM rpc_get_expert_mode_param(
+		struct shared_addr *shared_mem, int index)
+{
+	pMEDIAIP_ENC_EXPERT_MODE_PARAM param = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index,
+				param, pEncExpertModeParam);
+
+	return param;
+}
+
+pMEDIAIP_ENC_PARAM rpc_get_enc_param(
+		struct shared_addr *shared_mem, int index)
+{
+	pMEDIAIP_ENC_PARAM param = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index, param, pEncParam);
+
+	return param;
+}
+
+pMEDIAIP_ENC_MEM_POOL rpc_get_mem_pool(
+		struct shared_addr *shared_mem, int index)
+{
+	pMEDIAIP_ENC_MEM_POOL pool = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index, pool, pEncMemPool);
+
+	return pool;
+}
+
+pENC_ENCODING_STATUS rpc_get_encoding_status(
+		struct shared_addr *shared_mem, int index)
+{
+	pENC_ENCODING_STATUS encoding_status = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index,
+				encoding_status, pEncEncodingStatus);
+
+	return encoding_status;
+}
+
+pENC_DSA_STATUS_t rpc_get_dsa_status(struct shared_addr *shared_mem, int index)
+{
+	pENC_DSA_STATUS_t dsa_status = NULL;
+
+	GET_CTRL_INTERFACE_MEMBER(shared_mem, index, dsa_status, pEncDSAStatus);
+
+	return dsa_status;
+}
+
+void rpc_set_print_buffer(struct shared_addr *shared_mem,
+				unsigned long print_phy_addr, u32 size)
+{
+	pENC_RPC_HOST_IFACE pSharedInterface;
+	pBUFFER_DESCRIPTOR_TYPE debugBufDesc;
+
+
+	pSharedInterface = shared_mem->pSharedInterface;
+	debugBufDesc = &pSharedInterface->DebugBufferDesc;
+
+	debugBufDesc->start = print_phy_addr;
+	debugBufDesc->end = debugBufDesc->start + size;
+	debugBufDesc->wptr = debugBufDesc->rptr = debugBufDesc->start;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_encoder_rpc.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_encoder_rpc.h
@@ -0,0 +1,135 @@
+/*
+ * 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) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_ENCODER_RPC_H__
+#define __VPU_ENCODER_RPC_H__
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 2560
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DEBUG_SIZE 0x1000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+
+struct shared_addr {
+	pENC_RPC_HOST_IFACE pSharedInterface;
+	unsigned long long shared_mem_phy;
+	void *shared_mem_vir;
+	unsigned long long cmd_mem_phy;
+	void *cmd_mem_vir;
+	unsigned long long msg_mem_phy;
+	void *msg_mem_vir;
+	unsigned long long codec_mem_phy;
+	void *codec_mem_vir;
+	unsigned long long jpeg_mem_phy;
+	void *jpeg_mem_vir;
+	unsigned long long seq_mem_phy;
+	void *seq_mem_vir;
+	unsigned long long pic_mem_phy;
+	void *pic_mem_vir;
+	unsigned long long gop_mem_phy;
+	void *gop_mem_vir;
+	unsigned long long qmeter_mem_phy;
+	void *qmeter_mem_vir;
+	unsigned long long base_offset;
+};
+
+struct msg_header {
+	u32 idx;
+	u32 msgnum;
+	u32 msgid;
+};
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr,
+		u_int32 total_size,
+		u32 *actual_size);
+void rpc_restore_shared_memory_encoder(struct shared_addr *This,
+		unsigned long long base_phy_addr,
+		void *base_virt_addr);
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id);
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+		u_int32 idx,
+		u_int32 cmdid,
+		u_int32 cmdnum,
+		u_int32 *local_cmddata);
+u32 rpc_read_msg_u32(struct shared_addr *shared_mem);
+int rpc_read_msg_array(struct shared_addr *shared_mem, u32 *buf, u32 number);
+int rpc_get_msg_header(struct shared_addr *shared_mem, struct msg_header *msg);
+
+pMEDIAIP_ENC_YUV_BUFFER_DESC rpc_get_yuv_buffer_desc(
+		struct shared_addr *shared_mem, int index);
+pBUFFER_DESCRIPTOR_TYPE rpc_get_stream_buffer_desc(
+		struct shared_addr *shared_mem, int index);
+pMEDIAIP_ENC_EXPERT_MODE_PARAM rpc_get_expert_mode_param(
+		struct shared_addr *shared_mem, int index);
+pMEDIAIP_ENC_PARAM rpc_get_enc_param(
+		struct shared_addr *shared_mem, int index);
+pMEDIAIP_ENC_MEM_POOL rpc_get_mem_pool(
+		struct shared_addr *shared_mem, int index);
+pENC_ENCODING_STATUS rpc_get_encoding_status(
+		struct shared_addr *shared_mem, int index);
+pENC_DSA_STATUS_t rpc_get_dsa_status(struct shared_addr *shared_mem, int index);
+void rpc_set_print_buffer(struct shared_addr *shared_mem,
+				unsigned long print_phy_addr, u32 size);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_event_msg.c
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_event_msg.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define TAG	"[VPU Encoder Msg]\t "
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+
+#include "vpu_encoder_b0.h"
+#include "vpu_event_msg.h"
+
+static atomic64_t total_ext_data = ATOMIC64_INIT(0);
+
+static struct vpu_event_msg *alloc_event_msg(void)
+{
+	struct vpu_event_msg *msg = NULL;
+
+	msg = vzalloc(sizeof(*msg));
+
+	return msg;
+}
+
+static void free_event_msg(struct vpu_event_msg *msg)
+{
+	if (!msg)
+		return;
+
+	free_msg_ext_buffer(msg);
+	VPU_SAFE_RELEASE(msg, vfree);
+}
+
+static void set_msg_count(struct vpu_ctx *ctx, unsigned long count)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	if (attr)
+		attr->msg_count = count;
+}
+
+static void inc_msg_count(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	if (attr)
+		attr->msg_count++;
+}
+
+static void dec_msg_count(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	if (attr)
+		attr->msg_count--;
+}
+
+static bool is_msg_count_full(struct vpu_ctx *ctx)
+{
+	struct vpu_attr *attr = get_vpu_ctx_attr(ctx);
+
+	if (!attr)
+		return false;
+	if (attr->msg_count > MSG_COUNT_THD)
+		return true;
+	return false;
+}
+
+void cleanup_ctx_msg_queue(struct vpu_ctx *ctx)
+{
+	struct vpu_event_msg *msg;
+	struct vpu_event_msg *tmp;
+
+	WARN_ON(!ctx);
+
+	vpu_log_func();
+	mutex_lock(&ctx->instance_mutex);
+	list_for_each_entry_safe(msg, tmp, &ctx->msg_q, list) {
+		list_del_init(&msg->list);
+		vpu_dbg(LVL_MSG, "drop core[%d] ctx[%d] msg:[%d]\n",
+				ctx->core_dev->id, ctx->str_index, msg->msgid);
+		VPU_SAFE_RELEASE(msg, free_event_msg);
+		dec_msg_count(ctx);
+	}
+
+	list_for_each_entry_safe(msg, tmp, &ctx->idle_q, list) {
+		list_del_init(&msg->list);
+		VPU_SAFE_RELEASE(msg, free_event_msg);
+		dec_msg_count(ctx);
+	}
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+static int increase_idle_msg(struct vpu_ctx *ctx, u32 count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct vpu_event_msg *msg = alloc_event_msg();
+
+		if (!msg)
+			continue;
+		list_add_tail(&msg->list, &ctx->idle_q);
+		inc_msg_count(ctx);
+	}
+
+	return 0;
+}
+
+int init_ctx_msg_queue(struct vpu_ctx *ctx)
+{
+	WARN_ON(!ctx);
+	if (!ctx)
+		return -EINVAL;
+
+	vpu_log_func();
+	mutex_lock(&ctx->instance_mutex);
+
+	set_msg_count(ctx, 0);
+	INIT_LIST_HEAD(&ctx->msg_q);
+	INIT_LIST_HEAD(&ctx->idle_q);
+
+	mutex_unlock(&ctx->instance_mutex);
+
+	return 0;
+}
+
+struct vpu_event_msg *get_idle_msg(struct vpu_ctx *ctx)
+{
+	struct vpu_event_msg *msg = NULL;
+
+	WARN_ON(!ctx);
+
+	mutex_lock(&ctx->instance_mutex);
+	if (list_empty(&ctx->idle_q))
+		increase_idle_msg(ctx, 1);
+
+	msg = list_first_entry(&ctx->idle_q, struct vpu_event_msg, list);
+	if (msg)
+		list_del_init(&msg->list);
+
+	mutex_unlock(&ctx->instance_mutex);
+
+	return msg;
+}
+
+void put_idle_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg)
+{
+	WARN_ON(!ctx);
+
+	if (!ctx || !msg)
+		return;
+
+	free_msg_ext_buffer(msg);
+
+	mutex_lock(&ctx->instance_mutex);
+	if (is_msg_count_full(ctx)) {
+		VPU_SAFE_RELEASE(msg, free_event_msg);
+		dec_msg_count(ctx);
+	} else {
+		list_add_tail(&msg->list, &ctx->idle_q);
+	}
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+struct vpu_event_msg *pop_event_msg(struct vpu_ctx *ctx)
+{
+	struct vpu_event_msg *msg = NULL;
+
+	WARN_ON(!ctx);
+
+	mutex_lock(&ctx->instance_mutex);
+	if (list_empty(&ctx->msg_q))
+		goto exit;
+
+	msg = list_first_entry(&ctx->msg_q, struct vpu_event_msg, list);
+	if (msg)
+		list_del_init(&msg->list);
+
+exit:
+	mutex_unlock(&ctx->instance_mutex);
+	return msg;
+}
+
+void push_back_event_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg)
+{
+	WARN_ON(!ctx);
+
+	if (!ctx || !msg)
+		return;
+
+	mutex_lock(&ctx->instance_mutex);
+	list_add_tail(&msg->list, &ctx->msg_q);
+	mutex_unlock(&ctx->instance_mutex);
+}
+
+bool is_event_msg_empty(struct vpu_ctx *ctx)
+{
+	bool is_empty = false;
+
+	mutex_lock(&ctx->instance_mutex);
+	is_empty = list_empty(&ctx->msg_q);
+	mutex_unlock(&ctx->instance_mutex);
+
+	return is_empty;
+}
+
+int alloc_msg_ext_buffer(struct vpu_event_msg *msg, u32 number)
+{
+	WARN_ON(!msg);
+
+	if (!msg || !number)
+		return -EINVAL;
+
+	msg->ext_data = vzalloc(number * sizeof(u32));
+	if (!msg->ext_data)
+		return -ENOMEM;
+	msg->number = number;
+
+	atomic64_add(number, &total_ext_data);
+	vpu_dbg(LVL_MSG, "++++alloc %d msg ext data: %lld\n",
+			number, get_total_ext_data_number());
+
+	return 0;
+}
+
+void free_msg_ext_buffer(struct vpu_event_msg *msg)
+{
+	WARN_ON(!msg);
+
+	if (!msg || !msg->ext_data)
+		return;
+
+	atomic64_sub(msg->number, &total_ext_data);
+	VPU_SAFE_RELEASE(msg->ext_data, vfree);
+	vpu_dbg(LVL_MSG, "----free %d msg ext data: %lld\n",
+			msg->number, get_total_ext_data_number());
+}
+
+long long get_total_ext_data_number(void)
+{
+	return atomic64_read(&total_ext_data);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/vpu_windsor/vpu_event_msg.h
+++ linux-ein-5.4.0/drivers/mxc/vpu_windsor/vpu_event_msg.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _VPU_EVENT_MSG_H
+#define _VPU_EVENT_MSG_H
+
+#include "vpu_encoder_config.h"
+
+struct vpu_event_msg {
+	struct list_head list;
+	u32 idx;
+	u32 msgid;
+	u32 number;
+	u32 data[MSG_DATA_DEFAULT_SIZE];
+	u32 *ext_data;
+};
+
+int init_ctx_msg_queue(struct vpu_ctx *ctx);
+void cleanup_ctx_msg_queue(struct vpu_ctx *ctx);
+struct vpu_event_msg *get_idle_msg(struct vpu_ctx *ctx);
+void put_idle_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg);
+struct vpu_event_msg *pop_event_msg(struct vpu_ctx *ctx);
+void push_back_event_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg);
+bool is_event_msg_empty(struct vpu_ctx *ctx);
+int alloc_msg_ext_buffer(struct vpu_event_msg *msg, u32 number);
+void free_msg_ext_buffer(struct vpu_event_msg *msg);
+long long get_total_ext_data_number(void);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/Kconfig
+++ linux-ein-5.4.0/drivers/mxc/xuvi/Kconfig
@@ -0,0 +1,14 @@
+#
+# DVB device configuration
+#
+
+menu "XUVI/PPM HW TS filter and demux"
+	depends on ARCH_MXC
+
+config MXC_IMX_DMX_HW
+	tristate "Enable HW Implementation based on XUVI/PPM"
+	default y
+	help
+	  Hardware demux driver implementation using PPM
+
+endmenu
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/Makefile
+++ linux-ein-5.4.0/drivers/mxc/xuvi/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MXC_IMX_DMX_HW)	+= xuvi_pm.o
+obj-$(CONFIG_MXC_IMX_DMX_HW)	+= xuvi_mu.o
+obj-$(CONFIG_MXC_IMX_DMX_HW)	+= ppm.o
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/ppm.c
+++ linux-ein-5.4.0/drivers/mxc/xuvi/ppm.c
@@ -0,0 +1,1269 @@
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ppm.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include "ppm.h"
+#include "xuvi_pm.h"
+#include "xuvi_mu.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define CSR_CM0Px_ADDR_OFFSET  0x00000000
+#define CSR_CM0Px_CPUWAIT      0x00000004
+
+#define LVL_DEBUG 3
+#define LVL_INFO 2
+#define LVL_WARN  1
+#define LVL_ERR  0
+
+static int ppm_debug_level = 1;
+static int debug_firmware;
+
+module_param(ppm_debug_level, int, 0644);
+MODULE_PARM_DESC(ppm_debug_level, "ppm debug level (0-3)");
+module_param(debug_firmware, int, 0644);
+MODULE_PARM_DESC(debug_firmware, "open FW debug log");
+
+#define dprintk(level, fmt, arg...) do { \
+	if (ppm_debug_level >= (level)) \
+	printk(KERN_ERR pr_fmt("level: %d %s line: %d: " fmt), \
+	level, __func__, __LINE__, ##arg); \
+} while (0)
+
+static void dvb_dmx_filter(struct dvb_demux *demux, const u8 *buf,
+			   uint32_t len, u16 pid)
+{
+	struct dvb_demux_feed *feed;
+	struct ppm_ctx *ctx = demux->priv;
+	struct ppm_dev *ppm = ctx->dev;
+
+	list_for_each_entry(feed, &demux->feed_list, list_head) {
+
+		if (ctx->stop_start || !feed)
+			break;
+
+		if ((feed->pid != pid) && (feed->pid != 0x2000))
+			continue;
+
+		while (feed->cb.ts(buf, len, NULL, 0, &feed->feed.ts,
+				   &feed->buffer_flags) < 0) {
+			dprintk(LVL_DEBUG, "ringbuffer overflow, retry");
+			if (ctx->stop_start || ppm->suspend) {
+				dprintk(LVL_WARN, "suspend or stop drop");
+				break;
+			}
+			msleep(1000);
+		}
+	}
+}
+
+static void send_msg(struct ppm_dev *dev, uint32_t value0, uint32_t value1,
+		     uint32_t value2, uint32_t value3)
+{
+	xuvi_mu_send_msg(dev, value0, value1, value2, value3);
+}
+
+static void ppm_send_cmd(struct ppm_dev *dev, uint32_t idx, uint32_t cmdid,
+			 uint32_t value1, uint32_t value2, uint32_t value3)
+{
+	uint32_t cmdword;
+
+	cmdword = 0;
+	cmdword |= ((idx & 0x000000ff) << 16);
+	cmdword |= ((cmdid & 0x00003fff) << 0);
+
+	dprintk(LVL_DEBUG, "send idx: %d msg: %x 0x%x %d %d\n", idx,
+		cmdword, value1, value2, value3);
+	send_msg(dev, cmdword, value1, value2, value3);
+}
+
+static struct ppm_buf_list *find_buf(struct ppm_dev *ppm, uint32_t phy,
+				     bool is_input)
+{
+	int i;
+	struct ppm_buf_list *buf;
+
+	for (i = 0; i < BUF_NUM; i++) {
+		if (is_input)
+			buf = &ppm->bufs[i];
+		else
+			buf = &ppm->out_bufs[i];
+
+		if (buf->phy == phy)
+			return buf;
+	}
+	dprintk(LVL_ERR, "can't find buffer: 0x%x is_input %d\n", phy,
+		is_input);
+
+	return NULL;
+}
+
+static void ppm_event_handler(struct ppm_ctx *ctx, uint32_t idx,
+			      uint32_t evt, uint32_t *event_data)
+{
+	struct ppm_dev *dev;
+	struct ppm_buf_list *buf;
+	uint32_t phy = event_data[1];
+	uint32_t len = event_data[2];
+	uint32_t pid = event_data[3];
+
+	if (ctx == NULL) {
+		dprintk(LVL_ERR,
+			"receive event: 0x%X after instance released, ignore it\n",
+			evt);
+		return;
+	}
+
+	dev = ctx->dev;
+
+	switch (evt) {
+	case STOP:
+		dprintk(LVL_ERR, "receive PPM_EVENT_STOPPED\n");
+		ctx->fw_stopped = true;
+		complete(&ctx->stop_comp);
+		break;
+	case BUF_FROM:
+		if (len) {
+			buf = find_buf(dev, phy, false);
+			dvb_dmx_filter(&ctx->demux, buf->vir, len, pid);
+			mutex_lock(&dev->buf_list_lock);
+			ppm_send_cmd(dev, 0, BUF_TO, buf->phy, 0,
+				     buf->size);
+			mutex_unlock(&dev->buf_list_lock);
+		} else {
+			buf = find_buf(dev, phy, true);
+			mutex_lock(&dev->buf_list_lock);
+			list_add_tail(&buf->list, &dev->buf_list);
+			mutex_unlock(&dev->buf_list_lock);
+		}
+		break;
+	default:
+		dprintk(LVL_ERR, "warning: evt %d is not handled\n", evt);
+		break;
+	}
+	dprintk(LVL_DEBUG, "leave, evt %d\n", evt);
+}
+
+static void send_msg_queue(struct ppm_ctx *ctx, struct event_msg *msg)
+{
+	uint32_t ret;
+
+	ret =
+	    kfifo_in(&ctx->msg_fifo, msg,
+		     sizeof(uint32_t) * (MSG_WORD_LENGTH + msg->msgnum));
+	if (ret != sizeof(uint32_t) * (MSG_WORD_LENGTH + msg->msgnum))
+		dprintk(LVL_ERR,
+			"There is no memory for msg fifo, ret=%d\n", ret);
+}
+
+static bool receive_msg_queue(struct ppm_ctx *ctx, struct event_msg *msg)
+{
+	uint32_t ret;
+	struct ppm_dev *ppm = ctx->dev;
+
+	if (ppm->suspend)
+		return false;
+
+	if (kfifo_len(&ctx->msg_fifo) >=
+	    sizeof(uint32_t) * MSG_WORD_LENGTH) {
+		ret =
+		    kfifo_out(&ctx->msg_fifo, msg,
+			      sizeof(uint32_t) * MSG_WORD_LENGTH);
+		if (ret != sizeof(uint32_t) * MSG_WORD_LENGTH) {
+			dprintk(LVL_ERR,
+				"kfifo_out msg word has error, ret=%d\n",
+				ret);
+			return false;
+		} else {
+			if (msg->msgnum > 0) {
+				if (kfifo_len(&ctx->msg_fifo) >=
+				    sizeof(uint32_t) * msg->msgnum) {
+					ret =
+					    kfifo_out(&ctx->msg_fifo,
+						      msg->msgdata,
+						      sizeof(uint32_t) *
+						      msg->msgnum);
+					if (ret !=
+					    sizeof(uint32_t) *
+					    msg->msgnum) {
+						dprintk(LVL_ERR,
+							"kfifo_out msg data has error, ret=%d\n",
+							ret);
+						return false;
+					} else
+						return true;
+				} else
+					return false;
+			} else
+				return true;
+		}
+	} else
+		return false;
+}
+
+static void read_msg(struct ppm_dev *dev, struct event_msg *msg)
+{
+	uint32_t msg_mu[4];
+	uint32_t msgword;
+	uint32_t ret;
+
+	ret = kfifo_out(&dev->msg_fifo, msg_mu, sizeof(uint32_t) * 4);
+	if (ret != sizeof(uint32_t) * 4) {
+		dprintk(LVL_ERR, "kfifo_out msg word has error, ret=%d\n",
+			ret);
+	}
+
+	msgword = msg_mu[0];
+	msg->idx = ((msgword & 0x00ff0000) >> 16);
+	msg->msgid = ((msgword & 0x00003fff) >> 0);
+
+	msg->msgnum = 4;
+	msg->msgdata[0] = msg_mu[0];
+	msg->msgdata[1] = msg_mu[1];
+	msg->msgdata[2] = msg_mu[2];
+	msg->msgdata[3] = msg_mu[3];
+}
+
+static void ppm_msg_instance_work(struct work_struct *work)
+{
+	struct ppm_ctx *ctx =
+	    container_of(work, struct ppm_ctx, instance_work);
+	struct event_msg msg;
+
+	memset(&msg, 0, sizeof(struct event_msg));
+
+	while (receive_msg_queue(ctx, &msg))
+		ppm_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+}
+
+static int ensure_buf(struct ppm_dev *ppm, bool is_input)
+{
+	uint32_t i;
+	struct ppm_buf_list *buf;
+
+	if (is_input)
+		buf = &ppm->bufs[0];
+	else
+		buf = &ppm->out_bufs[0];
+
+	if (buf->vir)
+		return 0;
+
+	for (i = 0; i < BUF_NUM; i++) {
+		if (is_input)
+			buf = &ppm->bufs[i];
+		else
+			buf = &ppm->out_bufs[i];
+
+		buf->vir = dma_alloc_coherent(&ppm->plat_dev->dev,
+					      BUF_SIZE,
+					      (dma_addr_t *) &buf->phy,
+					      GFP_KERNEL | GFP_DMA32);
+
+		if (!buf->vir) {
+			dprintk(LVL_ERR, "dma buf alloc size(%d) fail!\n",
+				BUF_SIZE);
+			return -ENOMEM;
+		}
+		buf->size = BUF_SIZE;
+		if (is_input)
+			list_add_tail(&buf->list, &ppm->buf_list);
+		else
+			ppm_send_cmd(ppm, 0, BUF_TO, buf->phy, 0,
+				     buf->size);
+
+		dprintk(LVL_DEBUG, "Allocate buffer: 0x%x 0x%p\n",
+			buf->phy, buf->vir);
+	}
+
+	return 0;
+}
+
+static int ppm_dvbdmx_write(struct dmx_demux *demux,
+			    const char __user *buf_in, size_t count)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *) demux;
+	struct ppm_ctx *ctx = dvbdemux->priv;
+	struct ppm_dev *dev = ctx->dev;
+	struct ppm_buf_list *buf;
+	int ret;
+	void *p;
+
+	if ((!demux->frontend)
+	    || (demux->frontend->source != DMX_MEMORY_FE))
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	p = memdup_user(buf_in, count);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+
+	ret = ensure_buf(dev, true);
+	if (ret) {
+		dprintk(LVL_ERR, "alloc ppm buffer fail\n");
+		return ret;
+	}
+
+	mutex_lock(&dev->dev_ins_mutex);
+	while (list_empty(&dev->buf_list)) {
+		if (signal_pending(current)) {
+			dprintk(LVL_WARN, "fatal_signal_pending");
+			mutex_unlock(&dev->dev_ins_mutex);
+			return 0;
+		}
+		msleep(20);
+	}
+
+	mutex_lock(&dev->buf_list_lock);
+	buf = list_first_entry(&dev->buf_list, struct ppm_buf_list, list);
+	list_del(&buf->list);
+	mutex_unlock(&dev->buf_list_lock);
+	mutex_unlock(&dev->dev_ins_mutex);
+	memcpy(buf->vir, p, count);
+	mutex_lock(&dev->buf_list_lock);
+
+	ppm_send_cmd(dev, ctx->idx, BUF_TO, buf->phy, count, buf->size);
+	mutex_unlock(&dev->buf_list_lock);
+
+	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+		kfree(p);
+		return -ERESTARTSYS;
+	}
+
+	kfree(p);
+	mutex_unlock(&dvbdemux->mutex);
+
+	return count;
+}
+
+static void ppm_run_fw(struct ppm_dev *dev)
+{
+	writel(dev->fw_space_phy, dev->csr_base);
+	writel(0x0, dev->csr_base + CSR_CM0Px_CPUWAIT);
+}
+
+static int ppm_fw_download(struct ppm_dev *dev)
+{
+	unsigned char *image;
+	unsigned int fw_size = 0;
+	int ret = 0;
+	char *p = dev->fw_space_vir;
+
+	ret = request_firmware((const struct firmware **) &dev->pfw,
+			       M0FW_FILENAME, dev->generic_dev);
+	if (ret) {
+		dprintk(LVL_ERR, "request fw %s failed(%d)\n",
+			M0FW_FILENAME, ret);
+		return ret;
+	} else {
+		dprintk(LVL_INFO, "request fw %s got size(%d)\n",
+			M0FW_FILENAME, (int) dev->pfw->size);
+		image = (uint8_t *) dev->pfw->data;
+		fw_size = dev->pfw->size;
+	}
+	memcpy(dev->fw_space_vir, image, fw_size);
+
+	release_firmware(dev->pfw);
+	dev->pfw = NULL;
+
+	p[18] = 1;
+	ppm_run_fw(dev);
+
+	return ret;
+}
+
+static int ppm_dev_event_handler(struct ppm_dev *dev,
+				 struct event_msg *msg)
+{
+	int cmd;
+
+	cmd = msg->msgdata[0];
+	cmd &= 0x00003fff;
+	if (cmd == 0xaa) {
+		ppm_send_cmd(dev, 0, BOOT_ADDRESS, dev->fw_space_phy, 0,
+			     0);
+		ppm_send_cmd(dev, 0, INIT_DONE, LOG_OFFSET,
+			     dev->boot_size - LOG_OFFSET, 0);
+		dev->print_buf = dev->fw_space_vir + LOG_OFFSET;
+	} else if (cmd == 0x55) {
+		dev->fw_started = true;
+		complete(&dev->fw_start_comp);
+	} else if (cmd == 0xA5) {
+		complete(&dev->snap_done_comp);
+	} else if (cmd == HARD_FAULT) {
+		dprintk(LVL_ERR, "FW exception. lr: %x addr: %x\n",
+			msg->msgdata[1], msg->msgdata[2]);
+	} else {
+		return 1;
+	}
+
+	return 0;
+}
+
+static void ppm_msg_run_work(struct work_struct *work)
+{
+	struct ppm_dev *dev = container_of(work, struct ppm_dev, msg_work);
+	struct ppm_ctx *ctx;
+	struct event_msg msg;
+
+	memset(&msg, 0, sizeof(struct event_msg));
+
+	while (kfifo_len(&dev->msg_fifo) >= sizeof(uint32_t) * 4) {
+		read_msg(dev, &msg);
+		if (ppm_dev_event_handler(dev, &msg) == 0)
+			continue;
+		mutex_lock(&dev->dev_mutex);
+		ctx = dev->ctx[msg.idx];
+		if (ctx != NULL) {
+			mutex_lock(&ctx->instance_mutex);
+			if (!ctx->ctx_released) {
+				send_msg_queue(ctx, &msg);
+				queue_work(ctx->instance_wq,
+					   &ctx->instance_work);
+			}
+			mutex_unlock(&ctx->instance_mutex);
+		}
+		mutex_unlock(&dev->dev_mutex);
+	}
+}
+
+static void print_firmware_debug(char *ptr, u32 size)
+{
+	u32 total = 0;
+	u32 len;
+
+	while (total < size) {
+		len = min_t(u32, size - total, 256);
+		dprintk(LVL_ERR, "%.*s", len, ptr + total);
+		total += len;
+	}
+}
+
+static void firmware_debug(struct ppm_dev *dev)
+{
+	char *ptr;
+	u32 rptr;
+	u32 wptr;
+
+	if (!dev || !dev->print_buf)
+		return;
+
+	if (!debug_firmware)
+		return;
+
+	rptr = dev->print_buf->read;
+	wptr = dev->print_buf->write;
+	if (rptr == wptr)
+		return;
+
+	ptr = dev->print_buf->buffer;
+	if (rptr > wptr) {
+		print_firmware_debug(ptr + rptr,
+				     dev->print_buf->bytes - rptr);
+		rptr = 0;
+	}
+	if (rptr < wptr) {
+		print_firmware_debug(ptr + rptr, wptr - rptr);
+		rptr = wptr;
+	}
+	if (rptr >= dev->print_buf->bytes)
+		rptr = 0;
+	dev->print_buf->read = rptr;
+}
+
+static void ppm_watchdog_handler(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct ppm_dev *dev;
+
+	if (!work)
+		return;
+
+	dwork = to_delayed_work(work);
+	dev = container_of(dwork, struct ppm_dev, watchdog);
+
+	firmware_debug(dev);
+
+	schedule_delayed_work(&dev->watchdog,
+			      msecs_to_jiffies(PPM_WATCHDOG_INTERVAL_MS));
+}
+
+static void init_ppm_watchdog(struct ppm_dev *dev)
+{
+	if (!dev)
+		return;
+
+	INIT_DELAYED_WORK(&dev->watchdog, ppm_watchdog_handler);
+	schedule_delayed_work(&dev->watchdog,
+			      msecs_to_jiffies(PPM_WATCHDOG_INTERVAL_MS));
+}
+
+static int ppm_start(struct ppm_ctx *ctx)
+{
+	int ret = 0;
+	struct ppm_dev *dev = ctx->dev;
+
+	pm_runtime_get_sync(&dev->plat_dev->dev);
+
+	ctx->ctx_released = false;
+	ctx->fw_stopped = false;
+	ctx->stop_start = false;
+	if (!ctx->instance_activated) {
+		init_completion(&ctx->stop_comp);
+		init_completion(&ctx->eos_comp);
+		INIT_WORK(&ctx->instance_work, ppm_msg_instance_work);
+		mutex_init(&ctx->instance_mutex);
+
+		if (kfifo_alloc(&ctx->msg_fifo,
+				sizeof(struct event_msg) *
+				PPM_MESSAGE_LIMIT, GFP_KERNEL)) {
+			dprintk(LVL_ERR, "fail to alloc fifo when open\n");
+			ret = -ENOMEM;
+			goto err_alloc_fifo;
+		}
+
+		ctx->instance_wq =
+		    alloc_workqueue("ppm_instance",
+				    WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+		if (!ctx->instance_wq) {
+			dprintk(LVL_ERR,
+				"unable to alloc workqueue for ctx\n");
+			ret = -ENOMEM;
+			goto err_alloc_wq;
+		}
+		ctx->instance_activated = true;
+	}
+
+	mutex_lock(&dev->dev_mutex);
+	if (!dev->fw_is_ready) {
+		dev->fw_space_vir =
+		    ioremap_wc(dev->fw_space_phy, dev->boot_size);
+		if (!dev->fw_space_vir) {
+			dprintk(LVL_ERR, "can't map firmware space\n");
+			ret = -1;
+			mutex_unlock(&dev->dev_mutex);
+			goto err_fw_load;
+		}
+		memset_io(dev->fw_space_vir, 0, dev->boot_size);
+
+		ret = ppm_fw_download(dev);
+		if (ret) {
+			dprintk(LVL_ERR, "ppm_fw_download fail\n");
+			mutex_unlock(&dev->dev_mutex);
+			goto err_fw_load;
+		}
+		dprintk(LVL_INFO, "done: ppm_fw_download\n");
+		if (!ctx->dev->fw_started)
+			if (!wait_for_completion_timeout
+			    (&ctx->dev->fw_start_comp,
+			     msecs_to_jiffies(10000))) {
+				dprintk(LVL_ERR,
+					"don't get start interrupt\n");
+				ret = -1;
+				mutex_unlock(&dev->dev_mutex);
+				goto err_fw_load;
+			}
+		dev->fw_is_ready = true;
+	}
+
+	ret = ensure_buf(dev, false);
+	if (ret) {
+		dprintk(LVL_ERR, "alloc ppm buffer fail\n");
+		mutex_unlock(&dev->dev_mutex);
+		goto err_fw_load;
+	}
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+
+err_fw_load:
+	destroy_workqueue(ctx->instance_wq);
+err_alloc_wq:
+	if (&ctx->msg_fifo)
+		kfifo_free(&ctx->msg_fifo);
+err_alloc_fifo:
+	pm_runtime_put_sync(dev->generic_dev);
+
+	return ret;
+}
+
+static int ppm_stop(struct ppm_ctx *ctx)
+{
+	struct ppm_dev *dev = ctx->dev;
+
+	dprintk(LVL_ERR, "ppm stop");
+	if (!ctx->fw_stopped && ctx->start_flag == false) {
+		dprintk(LVL_INFO, "send STOP\n");
+		ppm_send_cmd(dev, ctx->idx, STOP, 0, 0, 0);
+		if (!wait_for_completion_timeout
+		    (&ctx->stop_comp, msecs_to_jiffies(1000))) {
+			dprintk(LVL_ERR,
+				"the path id:%d fw hang after send PPM_CMD_STOP\n",
+				ctx->idx);
+		}
+	} else
+		dprintk(LVL_INFO, "stopped(%d): skip PPM_CMD_STOP\n",
+			ctx->fw_stopped);
+
+	pm_runtime_put_sync(dev->generic_dev);
+
+	return 0;
+}
+
+static int ppm_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ppm_ctx *ppm = dvbdmx->priv;
+	struct dvb_demux_feed *feed;
+
+	dprintk(LVL_DEBUG, "PPM DVB Start feed");
+	if (!dvbdmx->dmx.frontend) {
+		dprintk(LVL_DEBUG, "no frontend ?");
+		return -EINVAL;
+	}
+
+	ppm->feeds++;
+	dprintk(LVL_DEBUG, "ppm start feed, feeds=%d", ppm->feeds);
+
+	if (ppm->feeds == 1) {
+		dprintk(LVL_DEBUG, "ppm start feed & dma");
+		ppm_start(ppm);
+	}
+
+	list_for_each_entry(feed, &dvbdmx->feed_list, list_head) {
+		dprintk(LVL_DEBUG, "feed pid: 0x%X\n", feed->pid);
+		ppm_send_cmd(ppm->dev, 0, ADD_PID, feed->pid, 0, 0);
+	}
+
+	return ppm->feeds;
+}
+
+static int ppm_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ppm_ctx *ctx = dvbdmx->priv;
+	struct dvb_demux_feed *feed;
+
+	dprintk(LVL_DEBUG, "PPM DVB Stop feed");
+	if (!dvbdmx->dmx.frontend) {
+		dprintk(LVL_DEBUG, "no frontend ?");
+		return -EINVAL;
+	}
+
+	ctx->feeds--;
+	ctx->stop_start = true;
+	if (ctx->feeds == 0) {
+		dprintk(LVL_DEBUG, "ppm stop feed and dma");
+		ppm_stop(ctx);
+	}
+
+	list_for_each_entry(feed, &dvbdmx->feed_list, list_head) {
+		dprintk(LVL_DEBUG, "feed pid: 0x%X\n", feed->pid);
+		ppm_send_cmd(ctx->dev, 0, RM_PID, feed->pid, 0, 0);
+	}
+
+	return 0;
+}
+
+int ppm_dvb_init(struct ppm_ctx *ppm)
+{
+	int result = -1;
+
+	dprintk(LVL_DEBUG, "dvb_register_adapter");
+
+	result = dvb_register_adapter(&ppm->dvb_adapter,
+				      "PPM DVB adapter",
+				      THIS_MODULE,
+				      &ppm->dev->plat_dev->dev,
+				      adapter_nr);
+
+	if (result < 0) {
+		dprintk(LVL_ERR, "Error registering adapter");
+		return -ENODEV;
+	}
+
+	ppm->dvb_adapter.priv = ppm;
+	ppm->demux.dmx.capabilities = DMX_TS_FILTERING |
+	    DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
+
+	ppm->demux.priv = ppm;
+	ppm->demux.filternum = 256;
+	ppm->demux.feednum = 256;
+	ppm->demux.start_feed = ppm_dvb_start_feed;
+	ppm->demux.stop_feed = ppm_dvb_stop_feed;
+	ppm->demux.write_to_decoder = NULL;
+
+	dprintk(LVL_DEBUG, "dvb_dmx_init");
+	result = dvb_dmx_init(&ppm->demux);
+	if (result < 0) {
+		dprintk(LVL_ERR, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err0;
+	}
+
+	ppm->dmxdev.filternum = 256;
+	ppm->dmxdev.demux = &ppm->demux.dmx;
+	ppm->dmxdev.demux->write = ppm_dvbdmx_write;
+	ppm->dmxdev.capabilities = 0;
+	dprintk(LVL_DEBUG, "dvb_dmxdev_init");
+
+	result = dvb_dmxdev_init(&ppm->dmxdev, &ppm->dvb_adapter);
+	if (result < 0) {
+		dprintk(LVL_ERR, "dvb_dmxdev_init failed, ERROR=%d",
+			result);
+		goto err1;
+	}
+
+	ppm->fe_hw.source = DMX_FRONTEND_0;
+	result = ppm->demux.dmx.add_frontend(&ppm->demux.dmx, &ppm->fe_hw);
+	if (result < 0) {
+		dprintk(LVL_ERR, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err2;
+	}
+
+	ppm->fe_mem.source = DMX_MEMORY_FE;
+	result =
+	    ppm->demux.dmx.add_frontend(&ppm->demux.dmx, &ppm->fe_mem);
+	if (result < 0) {
+		dprintk(LVL_ERR, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err3;
+	}
+
+	result =
+	    ppm->demux.dmx.connect_frontend(&ppm->demux.dmx, &ppm->fe_hw);
+	if (result < 0) {
+		dprintk(LVL_ERR, "dvb_dmx_init failed, ERROR=%d", result);
+		goto err4;
+	}
+
+	dvb_net_init(&ppm->dvb_adapter, &ppm->dvbnet, &ppm->demux.dmx);
+
+	return 0;
+
+	/* Error conditions ..        */
+err4:
+	ppm->demux.dmx.remove_frontend(&ppm->demux.dmx, &ppm->fe_mem);
+
+err3:
+	ppm->demux.dmx.remove_frontend(&ppm->demux.dmx, &ppm->fe_hw);
+
+err2:
+	dvb_dmxdev_release(&ppm->dmxdev);
+
+err1:
+	dvb_dmx_release(&ppm->demux);
+
+err0:
+	dvb_unregister_adapter(&ppm->dvb_adapter);
+
+	return result;
+}
+
+static int ppm_dvb_exit(struct ppm_ctx *ppm)
+{
+	dvb_net_release(&ppm->dvbnet);
+
+	ppm->demux.dmx.remove_frontend(&ppm->demux.dmx, &ppm->fe_mem);
+	ppm->demux.dmx.remove_frontend(&ppm->demux.dmx, &ppm->fe_hw);
+
+	dvb_dmxdev_release(&ppm->dmxdev);
+	dvb_dmx_release(&ppm->demux);
+
+	dprintk(LVL_DEBUG, "dvb_unregister_adapter");
+	dvb_unregister_adapter(&ppm->dvb_adapter);
+
+	return 0;
+}
+
+static int parse_dt_info(struct ppm_dev *dev, struct device_node *np)
+{
+	struct resource reserved_res;
+	struct device_node *reserved_node;
+	uint32_t csr_base;
+	int ret;
+
+	if (!dev || !np)
+		return -EINVAL;
+
+	reserved_node = of_parse_phandle(np, "boot-region", 0);
+	if (!reserved_node) {
+		dprintk(LVL_ERR, "boot-region of_parse_phandle error\n");
+		return -ENODEV;
+	}
+
+	if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+		dprintk(LVL_ERR,
+			"boot-region of_address_to_resource error\n");
+		return -EINVAL;
+	}
+	dev->fw_space_phy = reserved_res.start;
+	dev->boot_size = resource_size(&reserved_res);
+	dprintk(LVL_DEBUG, "boot-region: %x size: %d\n", dev->fw_space_phy,
+		dev->boot_size);
+
+	ret = of_property_read_u32(np, "reg-csr", &csr_base);
+	if (ret) {
+		dprintk(LVL_ERR, "Cannot get csr offset %d\n", ret);
+		return -EINVAL;
+	}
+	dev->csr_base = ioremap(csr_base, 8);
+
+	return 0;
+}
+
+static int ppm_probe(struct platform_device *pdev)
+{
+	struct ppm_dev *dev;
+	struct ppm_ctx *ctx;
+	struct device_node *np = pdev->dev.of_node;
+	int ret, i;
+
+	dprintk(LVL_DEBUG, "enter probe\n");
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->plat_dev = pdev;
+
+	ret = xuvi_attach_pm_domains(dev);
+	if (ret)
+		goto err_pm;
+
+	ret = parse_dt_info(dev, np);
+	if (ret) {
+		dprintk(LVL_ERR, "parse device tree fail\n");
+		goto err_put_dev;
+	}
+
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+		if (!ctx) {
+			ret = -ENOMEM;
+			goto err_put_dev;
+		}
+
+		ctx->dev = dev;
+		ctx->idx = i;
+		dev->ctx[i] = ctx;
+
+		ret = ppm_dvb_init(ctx);
+		if (ret) {
+			dprintk(LVL_ERR, "ppm dvb init fail\n");
+			goto err_put_dev;
+		}
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	init_ppm_watchdog(dev);
+	mutex_init(&dev->dev_mutex);
+	mutex_init(&dev->dev_ins_mutex);
+	INIT_WORK(&dev->msg_work, ppm_msg_run_work);
+	INIT_LIST_HEAD(&dev->buf_list);
+	mutex_init(&dev->buf_list_lock);
+	init_waitqueue_head(&dev->buffer_wq);
+	init_completion(&dev->fw_start_comp);
+	init_completion(&dev->snap_done_comp);
+	if (kfifo_alloc(&dev->msg_fifo,
+			4 * 4 * PPM_MESSAGE_LIMIT, GFP_KERNEL)) {
+		dprintk(LVL_ERR, "fail to alloc fifo when open\n");
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	dev->workqueue =
+	    alloc_workqueue("ppm", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!dev->workqueue) {
+		dprintk(LVL_ERR, "unable to alloc workqueue for dev\n");
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	dev->fw_started = false;
+	dev->fw_is_ready = false;
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	dev->generic_dev = get_device(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
+
+	return 0;
+
+err_put_dev:
+	xuvi_detach_pm_domains(dev);
+err_pm:
+	if (&dev->msg_fifo)
+		kfifo_free(&dev->msg_fifo);
+
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+
+	devm_kfree(&pdev->dev, dev);
+	dprintk(LVL_ERR, "probe failed\n");
+
+	return ret;
+}
+
+static void free_dma_buf(struct ppm_dev *dev)
+{
+	struct ppm_buf_list *buf;
+	uint32_t i;
+
+	for (i = 0; i < BUF_NUM; i++) {
+		buf = &dev->out_bufs[i];
+		if (!buf->vir)
+			break;
+		dma_free_coherent(&dev->plat_dev->dev, buf->size, buf->vir,
+				  buf->phy);
+		buf->vir = NULL;
+	}
+
+	for (i = 0; i < BUF_NUM; i++) {
+		buf = &dev->bufs[i];
+		if (!buf->vir)
+			break;
+		dma_free_coherent(&dev->plat_dev->dev, buf->size, buf->vir,
+				  buf->phy);
+		buf->vir = NULL;
+	}
+}
+
+static int ppm_remove(struct platform_device *pdev)
+{
+	struct ppm_dev *dev = platform_get_drvdata(pdev);
+	struct ppm_ctx *ctx;
+	int i;
+
+	dev->fw_started = false;
+	dev->fw_is_ready = false;
+
+	cancel_delayed_work_sync(&dev->watchdog);
+
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		ctx = dev->ctx[i];
+		if (!ctx->instance_activated)
+			continue;
+		mutex_lock(&ctx->instance_mutex);
+		ctx->ctx_released = true;
+		kfifo_free(&ctx->msg_fifo);
+		destroy_workqueue(ctx->instance_wq);
+		mutex_unlock(&ctx->instance_mutex);
+	}
+
+	free_dma_buf(dev);
+
+	if (dev->fw_space_vir)
+		iounmap(dev->fw_space_vir);
+	dev->fw_space_vir = NULL;
+	dev->fw_space_phy = 0;
+
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		ppm_dvb_exit(dev->ctx[i]);
+		kfree(dev->ctx[i]);
+		dev->ctx[i] = NULL;
+	}
+
+	if (&dev->msg_fifo)
+		kfifo_free(&dev->msg_fifo);
+
+	destroy_workqueue(dev->workqueue);
+
+	pm_runtime_disable(&pdev->dev);
+
+	xuvi_detach_pm_domains(dev);
+	if (dev->generic_dev) {
+		put_device(dev->generic_dev);
+		dev->generic_dev = NULL;
+	}
+	devm_kfree(&pdev->dev, dev);
+
+	return 0;
+}
+
+static int ppm_runtime_suspend(struct device *dev)
+{
+	struct ppm_dev *ppmdev = (struct ppm_dev *)dev_get_drvdata(dev);
+
+	dprintk(LVL_DEBUG, "ppm_runtime_suspend\n");
+	if (ppmdev->generic_dev)
+		xuvi_mu_free(ppmdev);
+
+	return 0;
+}
+
+static int ppm_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct ppm_dev *ppmdev = (struct ppm_dev *)dev_get_drvdata(dev);
+
+	dprintk(LVL_DEBUG, "ppm_runtime_resume\n");
+	if (ppmdev->generic_dev)
+		ret = xuvi_mu_request(ppmdev);
+
+	return ret;
+}
+
+static int find_first_available_instance(struct ppm_dev *dev)
+{
+	int strIdx = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	return strIdx;
+}
+
+static void ppm_send_snapshot(struct ppm_dev *dev)
+{
+	int strIdx;
+
+	strIdx = find_first_available_instance(dev);
+	if (strIdx >= 0 && strIdx < PPM_MAX_INSTANCE) {
+		dprintk(LVL_INFO, "send SNAP_SHOT\n");
+		ppm_send_cmd(dev, strIdx, SNAP_SHOT, 0, 0, 0);
+	} else
+		dprintk(LVL_WARN,
+			"warning: all path hang, need to reset\n");
+}
+
+static void ppm_dec_cancel_work(struct ppm_dev *ppmdev)
+{
+	int i;
+
+	mutex_lock(&ppmdev->dev_mutex);
+	cancel_work_sync(&ppmdev->msg_work);
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		struct ppm_ctx *ctx = ppmdev->ctx[i];
+
+		if (!ctx->instance_activated)
+			continue;
+		cancel_work_sync(&ppmdev->ctx[i]->instance_work);
+	}
+	cancel_delayed_work_sync(&ppmdev->watchdog);
+	mutex_unlock(&ppmdev->dev_mutex);
+}
+
+static bool ppm_has_instance(struct ppm_dev *ppmdev)
+{
+	int i;
+
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		struct ppm_ctx *ctx = ppmdev->ctx[i];
+
+		if (ctx)
+			return true;
+	}
+	return false;
+}
+
+static void ppm_dec_resume_work(struct ppm_dev *ppmdev)
+{
+	int i;
+
+	mutex_lock(&ppmdev->dev_mutex);
+	queue_work(ppmdev->workqueue, &ppmdev->msg_work);
+	for (i = 0; i < PPM_MAX_INSTANCE; i++) {
+		struct ppm_ctx *ctx = ppmdev->ctx[i];
+
+		if (!ctx->instance_activated)
+			continue;
+		if (!ctx->ctx_released)
+			queue_work(ctx->instance_wq, &ctx->instance_work);
+	}
+	schedule_delayed_work(&ppmdev->watchdog,
+			      msecs_to_jiffies(PPM_WATCHDOG_INTERVAL_MS));
+	mutex_unlock(&ppmdev->dev_mutex);
+}
+
+static int __maybe_unused ppm_suspend(struct device *dev)
+{
+	struct ppm_dev *ppmdev = (struct ppm_dev *) dev_get_drvdata(dev);
+	int ret = 0;
+
+	dprintk(LVL_INFO, "suspend\n");
+	pm_runtime_get_sync(ppmdev->generic_dev);
+	if (ppmdev->fw_is_ready) {
+		ppm_send_snapshot(ppmdev);
+		reinit_completion(&ppmdev->snap_done_comp);
+		if (!wait_for_completion_timeout
+		    (&ppmdev->snap_done_comp, msecs_to_jiffies(1000))) {
+			dprintk(LVL_ERR,
+				"error: wait for ppm decoder snapdone event timeout!\n");
+			ret = -1;
+		}
+	}
+
+	ppmdev->suspend = true;
+	ppm_dec_cancel_work(ppmdev);
+	ppmdev->suspend = false;
+	dprintk(LVL_INFO, "suspend done\n");
+	pm_runtime_put_sync(ppmdev->generic_dev);
+
+	return ret;
+}
+
+static bool is_ppm_poweroff(struct ppm_dev *ppmdev)
+{
+	if (!ppmdev)
+		return false;
+
+	if (readl_relaxed(ppmdev->csr_base + CSR_CM0Px_CPUWAIT) == 1)
+		return true;
+	else
+		return false;
+
+}
+
+static int resume_from_snapshot(struct ppm_dev *ppmdev)
+{
+	int ret = 0;
+
+	ppm_run_fw(ppmdev);
+	/*wait for firmware resotre done */
+	reinit_completion(&ppmdev->fw_start_comp);
+	if (!wait_for_completion_timeout
+	    (&ppmdev->fw_start_comp, msecs_to_jiffies(1000))) {
+		dprintk(LVL_ERR,
+			"error: wait for ppm decoder resume done timeout!\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int resume_from_ppm_poweroff(struct ppm_dev *ppmdev)
+{
+	int ret = 0;
+
+	dprintk(LVL_INFO, "resume from poweroff\n");
+	ret = resume_from_snapshot(ppmdev);
+
+	return ret;
+}
+
+static int __maybe_unused ppm_resume(struct device *dev)
+{
+	struct ppm_dev *ppmdev = (struct ppm_dev *) dev_get_drvdata(dev);
+	int ret = 0;
+
+	dprintk(LVL_INFO, "resume\n");
+	pm_runtime_get_sync(ppmdev->generic_dev);
+
+	if (ppmdev->fw_is_ready == false)
+		goto exit;
+
+	if (is_ppm_poweroff(ppmdev))
+		ret = resume_from_ppm_poweroff(ppmdev);
+	else if (ppm_has_instance(ppmdev))
+		dprintk(LVL_INFO, "resume from instance\n");
+
+	ppm_dec_resume_work(ppmdev);
+
+exit:
+	pm_runtime_put_sync(ppmdev->generic_dev);
+	dprintk(LVL_INFO, "resume done\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops ppm_pm_ops = {
+	SET_RUNTIME_PM_OPS(ppm_runtime_suspend, ppm_runtime_resume, NULL)
+	    SET_SYSTEM_SLEEP_PM_OPS(ppm_suspend, ppm_resume)
+};
+
+static const struct of_device_id demux_device_match[] = {
+	{.compatible = "nxp,imx8qm-b0-vpu-ts",},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, demux_device_match);
+
+static struct platform_driver demux_platform_driver = {
+	.probe = ppm_probe,
+	.remove = ppm_remove,
+	.driver = {
+		   .pm = &ppm_pm_ops,
+		   .name = "ppm",
+		   .of_match_table = demux_device_match,
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int ppm_device_init(void)
+{
+	return platform_driver_register(&demux_platform_driver);
+}
+
+static void ppm_device_exit(void)
+{
+	platform_driver_unregister(&demux_platform_driver);
+}
+
+module_init(ppm_device_init)
+module_exit(ppm_device_exit)
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("i.MX8QM PPM driver");
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/ppm.h
+++ linux-ein-5.4.0/drivers/mxc/xuvi/ppm.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2019-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ppm.h
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#ifndef __PPM_H__
+#define __PPM_H__
+
+#include <linux/slab.h>
+#include "media/demux.h"
+
+#define CONFIG_PROC_FS               1
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/wait.h>
+#include <linux/mailbox_client.h>
+
+#include "media/dvbdev.h"
+#include "media/dmxdev.h"
+#include "media/demux.h"
+#include "media/dvb_demux.h"
+#include "media/dvb_frontend.h"
+#include "media/dvb_net.h"
+
+#define VID_API_COMMAND_LIMIT    64
+#define PPM_MESSAGE_LIMIT    256
+#define MSG_WORD_LENGTH 3
+#define PPM_MAX_INSTANCE 2
+#define PPM_TS_188		0
+#define PPM_TS_204		1
+#define BUF_NUM 36
+#define BUF_SIZE (1*1024*1024)
+#define LOG_OFFSET (2*1024*1024)
+#define MSG_SIZE 4
+#define MU_CHANNEL 8
+#define PPM_WATCHDOG_INTERVAL_MS 1000
+
+#define M0FW_FILENAME "imx/xuvi/vpu_fw_imx8_xuvi.bin"
+
+enum {
+	INIT_DONE = 1,
+	RPC_BUF_OFFSET,
+	/*PRINT_BUF_OFFSET, */
+	BOOT_ADDRESS,
+	COMMAND,
+	EVENT,
+	BUF_TO = 16,
+	BUF_FROM,
+	ADD_PID,
+	RM_PID,
+	STOP,
+	HARD_FAULT,
+	DRAIN_DONE,
+	FLUSH_DONE,
+	SNAP_SHOT
+};
+
+struct event_msg {
+	u32 idx;
+	u32 msgnum;
+	u32 msgid;
+	u32 msgdata[MSG_SIZE];
+};
+
+struct ppm_buf_list {
+	struct list_head list;
+	void *vir;
+	u32 phy;
+	u32 size;
+};
+
+struct print_buf_desc {
+	u32 start_h_phy;
+	u32 start_h_vir;
+	u32 start_m;
+	u32 bytes;
+	u32 read;
+	u32 write;
+	char buffer[0];
+};
+
+struct xuvi_mu_chan {
+	struct ppm_dev *dev;
+	int idx;
+	struct mbox_client cl;
+	struct mbox_chan *ch;
+};
+
+struct ppm_ctx;
+struct ppm_dev {
+	struct device *generic_dev;
+	struct video_device *pppm_decoder_dev;
+	struct platform_device *plat_dev;
+	struct firmware *pfw;
+	void *fw_space_vir;
+	u32 fw_space_phy;
+	u32 boot_size;
+	struct mutex dev_mutex;
+	struct mutex dev_ins_mutex;
+	struct mutex cmd_mutex;
+	bool fw_is_ready;
+	bool fw_started;
+	struct completion fw_start_comp;
+	struct completion snap_done_comp;
+	struct delayed_work watchdog;
+	struct workqueue_struct *workqueue;
+	struct work_struct msg_work;
+	struct clk *ppm_clk;
+	struct ppm_buf_list bufs[BUF_NUM];
+	struct list_head buf_list;
+	struct mutex buf_list_lock;
+	struct ppm_buf_list out_bufs[BUF_NUM];
+	struct kfifo msg_fifo;
+
+	struct print_buf_desc *print_buf;
+
+	void __iomem *regs_base;
+	void __iomem *csr_base;
+	struct wait_queue_head buffer_wq;
+	struct ppm_ctx *ctx[PPM_MAX_INSTANCE];
+
+	bool suspend;
+
+	struct xuvi_mu_chan mu_chans[MU_CHANNEL];
+	struct device *pd_vpu;
+	struct device *pd_ts;
+	struct device *pd_mu;
+	struct device_link *pd_vpu_link;
+	struct device_link *pd_ts_link;
+	struct device_link *pd_mu_link;
+};
+
+struct ppm_ctx {
+	struct ppm_dev *dev;
+
+	/*    DVB stuff               */
+	struct dvb_adapter dvb_adapter;
+	struct dvb_frontend *fe;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net dvbnet;
+
+	int idx;
+	struct kfifo msg_fifo;
+	struct mutex instance_mutex;
+	struct work_struct instance_work;
+	struct workqueue_struct *instance_wq;
+	struct completion stop_comp;
+	struct completion eos_comp;
+	bool start_flag;
+	bool wait_abort_done;
+	bool wait_rst_done;
+	bool fw_stopped;
+	bool stop_start;
+	bool fw_finished;
+	bool eos_stop_received;
+	bool eos_stop_added;
+	bool ctx_released;
+	bool hang_status;
+	bool instance_activated;
+	u8 feeds;
+};
+
+#endif				// __PPM_H__ //
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/xuvi_mu.c
+++ linux-ein-5.4.0/drivers/mxc/xuvi/xuvi_mu.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file xuvi_mu.c
+ *
+ */
+
+#include "xuvi_mu.h"
+
+static void xuvi_rx_callback(struct mbox_client *c, void *msg)
+{
+	struct xuvi_mu_chan *mu_chan =
+	    container_of(c, struct xuvi_mu_chan, cl);
+	struct ppm_dev *dev = mu_chan->dev;
+	static uint32_t msg_mu[4], msg_mask;
+	u32 *data = msg;
+
+	msg_mu[mu_chan->idx] = *data;
+	msg_mask |= 1 << mu_chan->idx;
+
+	if (msg_mask == 0xF) {
+		msg_mask = 0;
+		if (kfifo_in(&dev->msg_fifo, msg_mu, sizeof(uint32_t) * 4)
+		    != sizeof(uint32_t) * 4) {
+			return;
+		}
+
+		queue_work(dev->workqueue, &dev->msg_work);
+	}
+}
+
+int xuvi_mu_request(struct ppm_dev *dev)
+{
+	struct xuvi_mu_chan *mu_chan;
+	struct mbox_client *cl;
+	char *chan_name;
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < MU_CHANNEL; i++) {
+		if (i < 4)
+			chan_name = kasprintf(GFP_KERNEL, "ts_tx%d", i);
+		else
+			chan_name =
+			    kasprintf(GFP_KERNEL, "ts_rx%d", i - 4);
+
+		if (!chan_name)
+			return -ENOMEM;
+
+		mu_chan = &dev->mu_chans[i];
+		cl = &mu_chan->cl;
+		cl->dev = &dev->plat_dev->dev;
+		if (i == 1 || i == 2 || i == 3) {
+			cl->tx_block = false;
+		} else {
+			cl->tx_block = true;
+			cl->tx_tout = 1000;
+		}
+		cl->knows_txdone = false;
+		cl->rx_callback = xuvi_rx_callback;
+
+		mu_chan->dev = dev;
+		mu_chan->idx = i % 4;
+		mu_chan->ch = mbox_request_channel_byname(cl, chan_name);
+		if (IS_ERR(mu_chan->ch)) {
+			ret = PTR_ERR(mu_chan->ch);
+			if (ret != -EPROBE_DEFER)
+				printk
+				    ("Failed to request mbox chan %s ret %d\n",
+				     chan_name, ret);
+			kfree(chan_name);
+			return ret;
+		}
+
+		kfree(chan_name);
+	}
+
+	return ret;
+}
+
+void xuvi_mu_free(struct ppm_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < MU_CHANNEL; i++) {
+		if (dev->mu_chans[i].ch && !IS_ERR(dev->mu_chans[i].ch))
+			mbox_free_channel(dev->mu_chans[i].ch);
+		dev->mu_chans[i].ch = NULL;
+	}
+}
+
+void xuvi_mu_send_msg(struct ppm_dev *dev, uint32_t value0,
+		      uint32_t value1, uint32_t value2, uint32_t value3)
+{
+	mbox_send_message(dev->mu_chans[3].ch, &value3);
+	mbox_send_message(dev->mu_chans[2].ch, &value2);
+	mbox_send_message(dev->mu_chans[1].ch, &value1);
+	mbox_send_message(dev->mu_chans[0].ch, &value0);
+}
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/xuvi_mu.h
+++ linux-ein-5.4.0/drivers/mxc/xuvi/xuvi_mu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file xuvi_mu.h
+ *
+ */
+
+#ifndef _XUVI_MU_H_
+#define _XUVI_MU_H_
+
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/mx8_mu.h>
+#include <linux/workqueue.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_client.h>
+#include <linux/pm_domain.h>
+#include <linux/kfifo.h>
+
+#include "ppm.h"
+
+int xuvi_mu_request(struct ppm_dev *dev);
+void xuvi_mu_free(struct ppm_dev *dev);
+void xuvi_mu_send_msg(struct ppm_dev *dev, uint32_t value0,
+		      uint32_t value1, uint32_t value2, uint32_t value3);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/xuvi_pm.c
+++ linux-ein-5.4.0/drivers/mxc/xuvi/xuvi_pm.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file xuvi_pm.c
+ *
+ */
+
+#include "xuvi_pm.h"
+#define vpu_err printk
+int xuvi_attach_pm_domains(struct ppm_dev *dev)
+{
+	int ret = 0;
+
+	dev->pd_vpu =
+	    dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpu");
+	if (IS_ERR(dev->pd_vpu)) {
+		vpu_err("error: %s unable to get vpu power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_vpu);
+		goto err;
+	}
+	dev->pd_vpu_link =
+	    device_link_add(&dev->plat_dev->dev, dev->pd_vpu,
+			    DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+			    DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_vpu_link)) {
+		vpu_err("error: %s unable to link vpu power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_vpu_link);
+		goto err;
+	}
+
+	dev->pd_ts =
+	    dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vputs");
+	if (IS_ERR(dev->pd_ts)) {
+		vpu_err("error: %s unable to get vpu ts power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_ts);
+		goto err;
+	}
+	dev->pd_ts_link = device_link_add(&dev->plat_dev->dev, dev->pd_ts,
+					  DL_FLAG_STATELESS |
+					  DL_FLAG_PM_RUNTIME |
+					  DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_ts_link)) {
+		vpu_err("error: %s unable to link vpu ts power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_ts_link);
+		goto err;
+	}
+
+	dev->pd_mu =
+	    dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpumu3");
+	if (IS_ERR(dev->pd_mu)) {
+		vpu_err("error: %s unable to get vpu mu0 power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_mu);
+		goto err;
+	}
+	dev->pd_mu_link = device_link_add(&dev->plat_dev->dev, dev->pd_mu,
+					  DL_FLAG_STATELESS |
+					  DL_FLAG_PM_RUNTIME |
+					  DL_FLAG_RPM_ACTIVE);
+	if (IS_ERR(dev->pd_mu_link)) {
+		vpu_err("error: %s unable to link vpu mu0 power domain\n",
+			__func__);
+		ret = PTR_ERR(dev->pd_mu_link);
+		goto err;
+	}
+
+	return ret;
+err:
+	xuvi_detach_pm_domains(dev);
+	return ret;
+}
+
+void xuvi_detach_pm_domains(struct ppm_dev *dev)
+{
+	if (dev->pd_vpu_link && !IS_ERR(dev->pd_vpu_link))
+		device_link_del(dev->pd_vpu_link);
+	if (dev->pd_vpu && !IS_ERR(dev->pd_vpu))
+		dev_pm_domain_detach(dev->pd_vpu, true);
+
+	if (dev->pd_ts_link && !IS_ERR(dev->pd_ts_link))
+		device_link_del(dev->pd_ts_link);
+	if (dev->pd_ts && !IS_ERR(dev->pd_ts))
+		dev_pm_domain_detach(dev->pd_ts, true);
+
+	if (dev->pd_mu_link && !IS_ERR(dev->pd_mu_link))
+		device_link_del(dev->pd_mu_link);
+	if (dev->pd_mu && !IS_ERR(dev->pd_mu))
+		dev_pm_domain_detach(dev->pd_mu, true);
+
+	dev->pd_vpu = NULL;
+	dev->pd_vpu_link = NULL;
+	dev->pd_ts = NULL;
+	dev->pd_ts_link = NULL;
+	dev->pd_mu = NULL;
+	dev->pd_mu_link = NULL;
+}
--- linux-ein-5.4.0.orig/drivers/mxc/xuvi/xuvi_pm.h
+++ linux-ein-5.4.0/drivers/mxc/xuvi/xuvi_pm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file xuvi_pm.h
+ *
+ */
+
+#ifndef _XUVI_PM_H_
+#define _XUVI_PM_H_
+
+#include <linux/version.h>
+#include <linux/pm_domain.h>
+#include <linux/platform_device.h>
+
+#include "ppm.h"
+
+int xuvi_attach_pm_domains(struct ppm_dev *dev);
+void xuvi_detach_pm_domains(struct ppm_dev *dev);
+
+#endif
--- linux-ein-5.4.0.orig/drivers/net/Kconfig
+++ linux-ein-5.4.0/drivers/net/Kconfig
@@ -106,6 +106,7 @@
 config IFB
 	tristate "Intermediate Functional Block support"
 	depends on NET_CLS_ACT
+	select NET_REDIRECT
 	---help---
 	  This is an intermediate driver that allows sharing of
 	  resources.
--- linux-ein-5.4.0.orig/drivers/net/appletalk/cops.c
+++ linux-ein-5.4.0/drivers/net/appletalk/cops.c
@@ -325,6 +325,8 @@
 			break;
 	}
 
+	dev->base_addr = ioaddr;
+
 	/* Reserve any actual interrupt. */
 	if (dev->irq) {
 		retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev);
@@ -332,8 +334,6 @@
 			goto err_out;
 	}
 
-	dev->base_addr = ioaddr;
-
         lp = netdev_priv(dev);
         spin_lock_init(&lp->lock);
 
--- linux-ein-5.4.0.orig/drivers/net/arcnet/arc-rimi.c
+++ linux-ein-5.4.0/drivers/net/arcnet/arc-rimi.c
@@ -332,7 +332,7 @@
 		dev->irq = 9;
 
 	if (arcrimi_probe(dev)) {
-		free_netdev(dev);
+		free_arcdev(dev);
 		return -EIO;
 	}
 
@@ -349,7 +349,7 @@
 	iounmap(lp->mem_start);
 	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
 	free_irq(dev->irq, dev);
-	free_netdev(dev);
+	free_arcdev(dev);
 }
 
 #ifndef MODULE
--- linux-ein-5.4.0.orig/drivers/net/arcnet/arcdevice.h
+++ linux-ein-5.4.0/drivers/net/arcnet/arcdevice.h
@@ -186,6 +186,8 @@
 #define ARC_IS_5MBIT    1   /* card default speed is 5MBit */
 #define ARC_CAN_10MBIT  2   /* card uses COM20022, supporting 10MBit,
 				 but default is 2.5MBit. */
+#define ARC_HAS_LED     4   /* card has software controlled LEDs */
+#define ARC_HAS_ROTARY  8   /* card has rotary encoder */
 
 /* information needed to define an encapsulation driver */
 struct ArcProto {
@@ -298,6 +300,10 @@
 
 	int excnak_pending;    /* We just got an excesive nak interrupt */
 
+	/* RESET flag handling */
+	int reset_in_progress;
+	struct work_struct reset_work;
+
 	struct {
 		uint16_t sequence;	/* sequence number (incs with each packet) */
 		__be16 aborted_seq;
@@ -350,7 +356,9 @@
 
 void arcnet_unregister_proto(struct ArcProto *proto);
 irqreturn_t arcnet_interrupt(int irq, void *dev_id);
+
 struct net_device *alloc_arcdev(const char *name);
+void free_arcdev(struct net_device *dev);
 
 int arcnet_open(struct net_device *dev);
 int arcnet_close(struct net_device *dev);
--- linux-ein-5.4.0.orig/drivers/net/arcnet/arcnet.c
+++ linux-ein-5.4.0/drivers/net/arcnet/arcnet.c
@@ -387,10 +387,44 @@
 	struct arcnet_local *lp = from_timer(lp, t, timer);
 	struct net_device *dev = lp->dev;
 
-	if (!netif_carrier_ok(dev)) {
+	spin_lock_irq(&lp->lock);
+
+	if (!lp->reset_in_progress && !netif_carrier_ok(dev)) {
 		netif_carrier_on(dev);
 		netdev_info(dev, "link up\n");
 	}
+
+	spin_unlock_irq(&lp->lock);
+}
+
+static void reset_device_work(struct work_struct *work)
+{
+	struct arcnet_local *lp;
+	struct net_device *dev;
+
+	lp = container_of(work, struct arcnet_local, reset_work);
+	dev = lp->dev;
+
+	/* Do not bring the network interface back up if an ifdown
+	 * was already done.
+	 */
+	if (!netif_running(dev) || !lp->reset_in_progress)
+		return;
+
+	rtnl_lock();
+
+	/* Do another check, in case of an ifdown that was triggered in
+	 * the small race window between the exit condition above and
+	 * acquiring RTNL.
+	 */
+	if (!netif_running(dev) || !lp->reset_in_progress)
+		goto out;
+
+	dev_close(dev);
+	dev_open(dev, NULL);
+
+out:
+	rtnl_unlock();
 }
 
 static void arcnet_reply_tasklet(unsigned long data)
@@ -434,7 +468,7 @@
 
 	ret = sock_queue_err_skb(sk, ackskb);
 	if (ret)
-		kfree_skb(ackskb);
+		dev_kfree_skb_irq(ackskb);
 
 	local_irq_enable();
 };
@@ -452,12 +486,25 @@
 		lp->dev = dev;
 		spin_lock_init(&lp->lock);
 		timer_setup(&lp->timer, arcnet_timer, 0);
+		INIT_WORK(&lp->reset_work, reset_device_work);
 	}
 
 	return dev;
 }
 EXPORT_SYMBOL(alloc_arcdev);
 
+void free_arcdev(struct net_device *dev)
+{
+	struct arcnet_local *lp = netdev_priv(dev);
+
+	/* Do not cancel this at ->ndo_close(), as the workqueue itself
+	 * indirectly calls the ifdown path through dev_close().
+	 */
+	cancel_work_sync(&lp->reset_work);
+	free_netdev(dev);
+}
+EXPORT_SYMBOL(free_arcdev);
+
 /* Open/initialize the board.  This is called sometime after booting when
  * the 'ifconfig' program is run.
  *
@@ -587,6 +634,10 @@
 
 	/* shut down the card */
 	lp->hw.close(dev);
+
+	/* reset counters */
+	lp->reset_in_progress = 0;
+
 	module_put(lp->hw.owner);
 	return 0;
 }
@@ -820,6 +871,9 @@
 
 	spin_lock_irqsave(&lp->lock, flags);
 
+	if (lp->reset_in_progress)
+		goto out;
+
 	/* RESET flag was enabled - if device is not running, we must
 	 * clear it right away (but nothing else).
 	 */
@@ -852,11 +906,14 @@
 		if (status & RESETflag) {
 			arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n",
 				   status);
-			arcnet_close(dev);
-			arcnet_open(dev);
+
+			lp->reset_in_progress = 1;
+			netif_stop_queue(dev);
+			netif_carrier_off(dev);
+			schedule_work(&lp->reset_work);
 
 			/* get out of the interrupt handler! */
-			break;
+			goto out;
 		}
 		/* RX is inhibited - we must have received something.
 		 * Prepare to receive into the next buffer.
@@ -1052,6 +1109,7 @@
 	udelay(1);
 	lp->hw.intmask(dev, lp->intmask);
 
+out:
 	spin_unlock_irqrestore(&lp->lock, flags);
 	return retval;
 }
--- linux-ein-5.4.0.orig/drivers/net/arcnet/com20020-isa.c
+++ linux-ein-5.4.0/drivers/net/arcnet/com20020-isa.c
@@ -169,7 +169,7 @@
 		dev->irq = 9;
 
 	if (com20020isa_probe(dev)) {
-		free_netdev(dev);
+		free_arcdev(dev);
 		return -EIO;
 	}
 
@@ -182,7 +182,7 @@
 	unregister_netdev(my_dev);
 	free_irq(my_dev->irq, my_dev);
 	release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE);
-	free_netdev(my_dev);
+	free_arcdev(my_dev);
 }
 
 #ifndef MODULE
--- linux-ein-5.4.0.orig/drivers/net/arcnet/com20020-pci.c
+++ linux-ein-5.4.0/drivers/net/arcnet/com20020-pci.c
@@ -127,6 +127,8 @@
 	int i, ioaddr, ret;
 	struct resource *r;
 
+	ret = 0;
+
 	if (pci_enable_device(pdev))
 		return -EIO;
 
@@ -136,9 +138,14 @@
 		return -ENOMEM;
 
 	ci = (struct com20020_pci_card_info *)id->driver_data;
+	if (!ci)
+		return -EINVAL;
+
 	priv->ci = ci;
 	mm = &ci->misc_map;
 
+	pci_set_drvdata(pdev, priv);
+
 	INIT_LIST_HEAD(&priv->list_dev);
 
 	if (mm->size) {
@@ -161,7 +168,7 @@
 		dev = alloc_arcdev(device);
 		if (!dev) {
 			ret = -ENOMEM;
-			goto out_port;
+			break;
 		}
 		dev->dev_port = i;
 
@@ -178,7 +185,7 @@
 			pr_err("IO region %xh-%xh already allocated\n",
 			       ioaddr, ioaddr + cm->size - 1);
 			ret = -EBUSY;
-			goto out_port;
+			goto err_free_arcdev;
 		}
 
 		/* Dummy access after Reset
@@ -206,76 +213,79 @@
 		if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
 			lp->backplane = 1;
 
-		/* Get the dev_id from the PLX rotary coder */
-		if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
-			dev_id_mask = 0x3;
-		dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
-
-		snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
+		if (ci->flags & ARC_HAS_ROTARY) {
+			/* Get the dev_id from the PLX rotary coder */
+			if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
+				dev_id_mask = 0x3;
+			dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
+			snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
+		}
 
 		if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
 			pr_err("IO address %Xh is empty!\n", ioaddr);
 			ret = -EIO;
-			goto out_port;
+			goto err_free_arcdev;
 		}
 		if (com20020_check(dev)) {
 			ret = -EIO;
-			goto out_port;
+			goto err_free_arcdev;
 		}
 
+		ret = com20020_found(dev, IRQF_SHARED);
+		if (ret)
+			goto err_free_arcdev;
+
 		card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
 				    GFP_KERNEL);
 		if (!card) {
 			ret = -ENOMEM;
-			goto out_port;
+			goto err_free_arcdev;
 		}
 
 		card->index = i;
 		card->pci_priv = priv;
-		card->tx_led.brightness_set = led_tx_set;
-		card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
-						GFP_KERNEL, "arc%d-%d-tx",
-						dev->dev_id, i);
-		card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-						"pci:green:tx:%d-%d",
-						dev->dev_id, i);
-
-		card->tx_led.dev = &dev->dev;
-		card->recon_led.brightness_set = led_recon_set;
-		card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
-						GFP_KERNEL, "arc%d-%d-recon",
-						dev->dev_id, i);
-		card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-						"pci:red:recon:%d-%d",
-						dev->dev_id, i);
-		card->recon_led.dev = &dev->dev;
-		card->dev = dev;
-
-		ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
-		if (ret)
-			goto out_port;
-
-		ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
-		if (ret)
-			goto out_port;
 
-		dev_set_drvdata(&dev->dev, card);
+		if (ci->flags & ARC_HAS_LED) {
+			card->tx_led.brightness_set = led_tx_set;
+			card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
+							GFP_KERNEL, "arc%d-%d-tx",
+							dev->dev_id, i);
+			card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+							"pci:green:tx:%d-%d",
+							dev->dev_id, i);
+
+			card->tx_led.dev = &dev->dev;
+			card->recon_led.brightness_set = led_recon_set;
+			card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
+							GFP_KERNEL, "arc%d-%d-recon",
+							dev->dev_id, i);
+			card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+							"pci:red:recon:%d-%d",
+							dev->dev_id, i);
+			card->recon_led.dev = &dev->dev;
+
+			ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
+			if (ret)
+				goto err_free_arcdev;
+
+			ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
+			if (ret)
+				goto err_free_arcdev;
 
-		ret = com20020_found(dev, IRQF_SHARED);
-		if (ret)
-			goto out_port;
-
-		devm_arcnet_led_init(dev, dev->dev_id, i);
+			dev_set_drvdata(&dev->dev, card);
+			devm_arcnet_led_init(dev, dev->dev_id, i);
+		}
 
+		card->dev = dev;
 		list_add(&card->list, &priv->list_dev);
-	}
+		continue;
 
-	pci_set_drvdata(pdev, priv);
-
-	return 0;
-
-out_port:
-	com20020pci_remove(pdev);
+err_free_arcdev:
+		free_arcdev(dev);
+		break;
+	}
+	if (ret)
+		com20020pci_remove(pdev);
 	return ret;
 }
 
@@ -291,7 +301,7 @@
 
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
-		free_netdev(dev);
+		free_arcdev(dev);
 	}
 }
 
@@ -322,7 +332,7 @@
 };
 
 static struct com20020_pci_card_info card_info_sohard = {
-	.name = "PLX-PCI",
+	.name = "SOHARD SH ARC-PCI",
 	.devcount = 1,
 	/* SOHARD needs PCI base addr 4 */
 	.chan_map_tbl = {
@@ -357,7 +367,7 @@
 		},
 	},
 	.rotary = 0x0,
-	.flags = ARC_CAN_10MBIT,
+	.flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
 };
 
 static struct com20020_pci_card_info card_info_eae_ma1 = {
@@ -389,7 +399,7 @@
 		},
 	},
 	.rotary = 0x0,
-	.flags = ARC_CAN_10MBIT,
+	.flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
 };
 
 static struct com20020_pci_card_info card_info_eae_fb2 = {
@@ -414,7 +424,7 @@
 		},
 	},
 	.rotary = 0x0,
-	.flags = ARC_CAN_10MBIT,
+	.flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
 };
 
 static const struct pci_device_id com20020pci_id_table[] = {
--- linux-ein-5.4.0.orig/drivers/net/arcnet/com20020_cs.c
+++ linux-ein-5.4.0/drivers/net/arcnet/com20020_cs.c
@@ -177,7 +177,7 @@
 		dev = info->dev;
 		if (dev) {
 			dev_dbg(&link->dev, "kfree...\n");
-			free_netdev(dev);
+			free_arcdev(dev);
 		}
 		dev_dbg(&link->dev, "kfree2...\n");
 		kfree(info);
--- linux-ein-5.4.0.orig/drivers/net/arcnet/com90io.c
+++ linux-ein-5.4.0/drivers/net/arcnet/com90io.c
@@ -396,7 +396,7 @@
 	err = com90io_probe(dev);
 
 	if (err) {
-		free_netdev(dev);
+		free_arcdev(dev);
 		return err;
 	}
 
@@ -419,7 +419,7 @@
 
 	free_irq(dev->irq, dev);
 	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-	free_netdev(dev);
+	free_arcdev(dev);
 }
 
 module_init(com90io_init)
--- linux-ein-5.4.0.orig/drivers/net/arcnet/com90xx.c
+++ linux-ein-5.4.0/drivers/net/arcnet/com90xx.c
@@ -554,7 +554,7 @@
 err_release_mem:
 	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
 err_free_dev:
-	free_netdev(dev);
+	free_arcdev(dev);
 	return -EIO;
 }
 
@@ -672,7 +672,7 @@
 		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
 		release_mem_region(dev->mem_start,
 				   dev->mem_end - dev->mem_start + 1);
-		free_netdev(dev);
+		free_arcdev(dev);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_3ad.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_3ad.c
@@ -233,7 +233,7 @@
 	if (bond == NULL)
 		return 0;
 
-	return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;
+	return atomic_read(&BOND_AD_INFO(bond).agg_select_timer) ? 1 : 0;
 }
 
 /**
@@ -1013,8 +1013,8 @@
 				if (port->aggregator &&
 				    port->aggregator->is_active &&
 				    !__port_is_enabled(port)) {
-
 					__enable_port(port);
+					*update_slave_arr = true;
 				}
 			}
 			break;
@@ -1529,6 +1529,7 @@
 			slave_err(bond->dev, port->slave->dev,
 				  "Port %d did not find a suitable aggregator\n",
 				  port->actor_port_number);
+			return;
 		}
 	}
 	/* if all aggregator's ports are READY_N == TRUE, set ready=TRUE
@@ -1770,6 +1771,7 @@
 			     port = port->next_port_in_aggregator) {
 				__enable_port(port);
 			}
+			*update_slave_arr = true;
 		}
 	}
 
@@ -1984,7 +1986,7 @@
  */
 void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
 {
-	BOND_AD_INFO(bond).agg_select_timer = timeout;
+	atomic_set(&BOND_AD_INFO(bond).agg_select_timer, timeout);
 }
 
 /**
@@ -1996,30 +1998,24 @@
  */
 void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
 {
-	/* check that the bond is not initialized yet */
-	if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr),
-				bond->dev->dev_addr)) {
-
-		BOND_AD_INFO(bond).aggregator_identifier = 0;
-
-		BOND_AD_INFO(bond).system.sys_priority =
-			bond->params.ad_actor_sys_prio;
-		if (is_zero_ether_addr(bond->params.ad_actor_system))
-			BOND_AD_INFO(bond).system.sys_mac_addr =
-			    *((struct mac_addr *)bond->dev->dev_addr);
-		else
-			BOND_AD_INFO(bond).system.sys_mac_addr =
-			    *((struct mac_addr *)bond->params.ad_actor_system);
+	BOND_AD_INFO(bond).aggregator_identifier = 0;
+	BOND_AD_INFO(bond).system.sys_priority =
+		bond->params.ad_actor_sys_prio;
+	if (is_zero_ether_addr(bond->params.ad_actor_system))
+		BOND_AD_INFO(bond).system.sys_mac_addr =
+		    *((struct mac_addr *)bond->dev->dev_addr);
+	else
+		BOND_AD_INFO(bond).system.sys_mac_addr =
+		    *((struct mac_addr *)bond->params.ad_actor_system);
 
-		/* initialize how many times this module is called in one
-		 * second (should be about every 100ms)
-		 */
-		ad_ticks_per_sec = tick_resolution;
+	/* initialize how many times this module is called in one
+	 * second (should be about every 100ms)
+	 */
+	ad_ticks_per_sec = tick_resolution;
 
-		bond_3ad_initiate_agg_selection(bond,
-						AD_AGGREGATOR_SELECTION_TIMER *
-						ad_ticks_per_sec);
-	}
+	bond_3ad_initiate_agg_selection(bond,
+					AD_AGGREGATOR_SELECTION_TIMER *
+					ad_ticks_per_sec);
 }
 
 /**
@@ -2217,7 +2213,8 @@
 				temp_aggregator->num_of_ports--;
 				if (__agg_active_ports(temp_aggregator) == 0) {
 					select_new_active_agg = temp_aggregator->is_active;
-					ad_clear_agg(temp_aggregator);
+					if (temp_aggregator->num_of_ports == 0)
+						ad_clear_agg(temp_aggregator);
 					if (select_new_active_agg) {
 						slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
 						/* select new active aggregator */
@@ -2268,6 +2265,28 @@
 }
 
 /**
+ * bond_agg_timer_advance - advance agg_select_timer
+ * @bond:  bonding structure
+ *
+ * Return true when agg_select_timer reaches 0.
+ */
+static bool bond_agg_timer_advance(struct bonding *bond)
+{
+	int val, nval;
+
+	while (1) {
+		val = atomic_read(&BOND_AD_INFO(bond).agg_select_timer);
+		if (!val)
+			return false;
+		nval = val - 1;
+		if (atomic_cmpxchg(&BOND_AD_INFO(bond).agg_select_timer,
+				   val, nval) == val)
+			break;
+	}
+	return nval == 0;
+}
+
+/**
  * bond_3ad_state_machine_handler - handle state machines timeout
  * @bond: bonding struct to work on
  *
@@ -2302,9 +2321,7 @@
 	if (!bond_has_slaves(bond))
 		goto re_arm;
 
-	/* check if agg_select_timer timer after initialize is timed out */
-	if (BOND_AD_INFO(bond).agg_select_timer &&
-	    !(--BOND_AD_INFO(bond).agg_select_timer)) {
+	if (bond_agg_timer_advance(bond)) {
 		slave = bond_first_slave_rcu(bond);
 		port = slave ? &(SLAVE_AD_INFO(slave)->port) : NULL;
 
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_alb.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_alb.c
@@ -50,11 +50,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);
@@ -553,10 +548,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;
@@ -653,18 +649,22 @@
  */
 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;
 
-	/* Don't modify or load balance ARPs that do not originate locally
-	 * (e.g.,arrive via a bridge).
+	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
+	 * from the bond itself or a VLAN directly above the bond.
 	 */
-	if (!bond_slave_has_mac_rx(bond, arp->mac_src))
+	if (!bond_slave_has_mac_rcu(bond, arp->mac_src))
 		return NULL;
 
 	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)
 			bond_hw_addr_copy(arp->mac_src, tx_slave->dev->dev_addr,
 					  tx_slave->dev->addr_len);
@@ -676,7 +676,7 @@
 		 * When the arp reply is received the entry will be updated
 		 * with the correct unicast address of the client.
 		 */
-		tx_slave = rlb_choose_channel(skb, bond);
+		tx_slave = 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.
@@ -970,7 +970,8 @@
 	if (netif_is_macvlan(upper) && !strict_match) {
 		tags = bond_verify_device_path(bond->dev, upper, 0);
 		if (IS_ERR_OR_NULL(tags))
-			BUG();
+			return -ENOMEM;
+
 		alb_send_lp_vid(slave, upper->dev_addr,
 				tags[0].vlan_proto, tags[0].vlan_id);
 		kfree(tags);
@@ -1276,12 +1277,12 @@
 		return res;
 
 	if (rlb_enabled) {
-		bond->alb_info.rlb_enabled = 1;
 		res = rlb_initialize(bond);
 		if (res) {
 			tlb_deinitialize(bond);
 			return res;
 		}
+		bond->alb_info.rlb_enabled = 1;
 	} else {
 		bond->alb_info.rlb_enabled = 0;
 	}
@@ -1360,7 +1361,7 @@
 				struct bond_up_slave *slaves;
 				unsigned int count;
 
-				slaves = rcu_dereference(bond->slave_arr);
+				slaves = rcu_dereference(bond->usable_slaves);
 				count = slaves ? READ_ONCE(slaves->count) : 0;
 				if (likely(count))
 					tx_slave = slaves->arr[hash_index %
@@ -1383,26 +1384,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 (is_broadcast_ether_addr(eth_data->h_dest) ||
-		    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.
 		 */
@@ -1419,7 +1425,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.
 		 */
@@ -1429,17 +1439,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
@@ -1448,9 +1467,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)
@@ -1474,7 +1495,7 @@
 			struct bond_up_slave *slaves;
 			unsigned int count;
 
-			slaves = rcu_dereference(bond->slave_arr);
+			slaves = rcu_dereference(bond->usable_slaves);
 			count = slaves ? READ_ONCE(slaves->count) : 0;
 			if (likely(count))
 				tx_slave = slaves->arr[bond_xmit_hash(bond, skb) %
@@ -1494,14 +1515,14 @@
 	struct slave *slave;
 
 	if (!bond_has_slaves(bond)) {
-		bond_info->tx_rebalance_counter = 0;
+		atomic_set(&bond_info->tx_rebalance_counter, 0);
 		bond_info->lp_counter = 0;
 		goto re_arm;
 	}
 
 	rcu_read_lock();
 
-	bond_info->tx_rebalance_counter++;
+	atomic_inc(&bond_info->tx_rebalance_counter);
 	bond_info->lp_counter++;
 
 	/* send learning packets */
@@ -1523,7 +1544,7 @@
 	}
 
 	/* rebalance tx traffic */
-	if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) {
+	if (atomic_read(&bond_info->tx_rebalance_counter) >= BOND_TLB_REBALANCE_TICKS) {
 		bond_for_each_slave_rcu(bond, slave, iter) {
 			tlb_clear_slave(bond, slave, 1);
 			if (slave == rcu_access_pointer(bond->curr_active_slave)) {
@@ -1533,7 +1554,7 @@
 				bond_info->unbalanced_load = 0;
 			}
 		}
-		bond_info->tx_rebalance_counter = 0;
+		atomic_set(&bond_info->tx_rebalance_counter, 0);
 	}
 
 	if (bond_info->rlb_enabled) {
@@ -1603,7 +1624,8 @@
 	tlb_init_slave(slave);
 
 	/* order a rebalance ASAP */
-	bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
+	atomic_set(&bond->alb_info.tx_rebalance_counter,
+		   BOND_TLB_REBALANCE_TICKS);
 
 	if (bond->alb_info.rlb_enabled)
 		bond->alb_info.rlb_rebalance = 1;
@@ -1640,7 +1662,8 @@
 			rlb_clear_slave(bond, slave);
 	} else if (link == BOND_LINK_UP) {
 		/* order a rebalance ASAP */
-		bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
+		atomic_set(&bond_info->tx_rebalance_counter,
+			   BOND_TLB_REBALANCE_TICKS);
 		if (bond->alb_info.rlb_enabled) {
 			bond->alb_info.rlb_rebalance = 1;
 			/* If the updelay module parameter is smaller than the
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_debugfs.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_debugfs.c
@@ -76,7 +76,7 @@
 
 	d = debugfs_rename(bonding_debug_root, bond->debug_dir,
 			   bonding_debug_root, bond->dev->name);
-	if (d) {
+	if (!IS_ERR(d)) {
 		bond->debug_dir = d;
 	} else {
 		netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n");
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_main.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_main.c
@@ -792,9 +792,6 @@
 	slave = rcu_dereference(bond->curr_active_slave);
 	rcu_read_unlock();
 
-	netdev_dbg(bond->dev, "bond_should_notify_peers: slave %s\n",
-		   slave ? slave->dev->name : "NULL");
-
 	if (!slave || !bond->send_peer_notif ||
 	    bond->send_peer_notif %
 	    max(1, bond->params.peer_notif_delay) != 0 ||
@@ -802,6 +799,9 @@
 	    test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
 		return false;
 
+	netdev_dbg(bond->dev, "bond_should_notify_peers: slave %s\n",
+		   slave ? slave->dev->name : "NULL");
+
 	return true;
 }
 
@@ -1144,14 +1144,26 @@
 static void bond_setup_by_slave(struct net_device *bond_dev,
 				struct net_device *slave_dev)
 {
+	bool was_up = !!(bond_dev->flags & IFF_UP);
+
+	dev_close(bond_dev);
+
 	bond_dev->header_ops	    = slave_dev->header_ops;
 
 	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,
 		slave_dev->addr_len);
+
+	if (slave_dev->flags & IFF_POINTOPOINT) {
+		bond_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+		bond_dev->flags |= (IFF_POINTOPOINT | IFF_NOARP);
+	}
+	if (was_up)
+		dev_open(bond_dev, NULL);
 }
 
 /* On bonding slaves other than the currently active slave, suppress
@@ -1218,7 +1230,7 @@
 	skb->dev = bond->dev;
 
 	if (BOND_MODE(bond) == BOND_MODE_ALB &&
-	    bond->dev->priv_flags & IFF_BRIDGE_PORT &&
+	    netif_is_bridge_port(bond->dev) &&
 	    skb->pkt_type == PACKET_HOST) {
 
 		if (unlikely(skb_cow_head(skb,
@@ -1292,7 +1304,39 @@
 	slave->dev->flags &= ~IFF_SLAVE;
 }
 
-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;
 
@@ -1300,30 +1344,25 @@
 	if (!slave)
 		return NULL;
 
+	slave->bond = bond;
+	slave->dev = slave_dev;
+	INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work);
+
+	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;
 		}
 	}
-	INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work);
 
 	return slave;
 }
 
-static void bond_free_slave(struct slave *slave)
-{
-	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 void bond_fill_ifbond(struct bonding *bond, struct ifbond *info)
 {
 	info->bond_mode = BOND_MODE(bond);
@@ -1507,14 +1546,12 @@
 			goto err_undo_flags;
 	}
 
-	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.
 	 */
@@ -1836,7 +1873,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 */
@@ -1900,7 +1937,6 @@
 	/* recompute stats just before removing the slave */
 	bond_get_stats(bond->dev, &bond->bond_stats);
 
-	bond_upper_dev_unlink(bond, slave);
 	/* unregister rx_handler early so bond_handle_frame wouldn't be called
 	 * for this slave anymore.
 	 */
@@ -1909,6 +1945,8 @@
 	if (BOND_MODE(bond) == BOND_MODE_8023AD)
 		bond_3ad_unbind_slave(slave);
 
+	bond_upper_dev_unlink(bond, slave);
+
 	if (bond_mode_can_use_xmit_hash(bond))
 		bond_update_slave_arr(bond, slave);
 
@@ -1952,10 +1990,9 @@
 		bond_select_active_slave(bond);
 	}
 
-	if (!bond_has_slaves(bond)) {
-		bond_set_carrier(bond);
+	bond_set_carrier(bond);
+	if (!bond_has_slaves(bond))
 		eth_hw_addr_random(bond_dev);
-	}
 
 	unblock_netpoll_tx();
 	synchronize_rcu();
@@ -2016,7 +2053,7 @@
 	if (!netif_is_bond_master(slave_dev))
 		slave_dev->priv_flags &= ~IFF_BONDING;
 
-	bond_free_slave(slave);
+	kobject_put(&slave->kobj);
 
 	return 0;
 }
@@ -2037,7 +2074,8 @@
 	int ret;
 
 	ret = __bond_release_one(bond_dev, slave_dev, false, true);
-	if (ret == 0 && !bond_has_slaves(bond)) {
+	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\n");
 		bond_remove_proc_entry(bond);
@@ -2075,12 +2113,21 @@
 /* called with rcu_read_lock() */
 static int bond_miimon_inspect(struct bonding *bond)
 {
+	bool ignore_updelay = false;
 	int link_state, commit = 0;
 	struct list_head *iter;
 	struct slave *slave;
-	bool ignore_updelay;
 
-	ignore_updelay = !rcu_dereference(bond->curr_active_slave);
+	if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) {
+		ignore_updelay = !rcu_dereference(bond->curr_active_slave);
+	} else {
+		struct bond_up_slave *usable_slaves;
+
+		usable_slaves = rcu_dereference(bond->usable_slaves);
+
+		if (usable_slaves && usable_slaves->count == 0)
+			ignore_updelay = true;
+	}
 
 	bond_for_each_slave_rcu(bond, slave, iter) {
 		bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
@@ -2225,9 +2272,6 @@
 			} else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
 				/* make it immediately active */
 				bond_set_active_slave(slave);
-			} else if (slave != primary) {
-				/* prevent it from being the active one */
-				bond_set_backup_slave(slave);
 			}
 
 			slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n",
@@ -2780,6 +2824,9 @@
 			if (bond_time_in_interval(bond, last_rx, 1)) {
 				bond_propose_link_state(slave, BOND_LINK_UP);
 				commit++;
+			} else if (slave->link == BOND_LINK_BACK) {
+				bond_propose_link_state(slave, BOND_LINK_FAIL);
+				commit++;
 			}
 			continue;
 		}
@@ -2888,6 +2935,19 @@
 
 			continue;
 
+		case BOND_LINK_FAIL:
+			bond_set_slave_link_state(slave, BOND_LINK_FAIL,
+						  BOND_SLAVE_NOTIFY_NOW);
+			bond_set_slave_inactive_flags(slave,
+						      BOND_SLAVE_NOTIFY_NOW);
+
+			/* A slave has just been enslaved and has become
+			 * the current active slave.
+			 */
+			if (rtnl_dereference(bond->curr_active_slave))
+				RCU_INIT_POINTER(bond->current_arp_slave, NULL);
+			continue;
+
 		default:
 			slave_err(bond->dev, slave->dev,
 				  "impossible: link_new_state %d on slave\n",
@@ -2938,8 +2998,6 @@
 			return should_notify_rtnl;
 	}
 
-	bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
-
 	bond_for_each_slave_rcu(bond, slave, iter) {
 		if (!found && !before && bond_slave_is_up(slave))
 			before = slave;
@@ -3033,9 +3091,11 @@
 		if (!rtnl_trylock())
 			return;
 
-		if (should_notify_peers)
+		if (should_notify_peers) {
+			bond->send_peer_notif--;
 			call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
 						 bond->dev);
+		}
 		if (should_notify_rtnl) {
 			bond_slave_state_notify(bond);
 			bond_slave_link_notify(bond);
@@ -3190,7 +3250,11 @@
 		unblock_netpoll_tx();
 		break;
 	case NETDEV_FEAT_CHANGE:
-		bond_compute_features(bond);
+		if (!bond->notifier_ctx) {
+			bond->notifier_ctx = true;
+			bond_compute_features(bond);
+			bond->notifier_ctx = false;
+		}
 		break;
 	case NETDEV_RESEND_IGMP:
 		/* Propagate to master device */
@@ -3439,6 +3503,47 @@
 	}
 }
 
+#ifdef CONFIG_LOCKDEP
+static int bond_get_lowest_level_rcu(struct net_device *dev)
+{
+	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
+	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
+	int cur = 0, max = 0;
+
+	now = dev;
+	iter = &dev->adj_list.lower;
+
+	while (1) {
+		next = NULL;
+		while (1) {
+			ldev = netdev_next_lower_dev_rcu(now, &iter);
+			if (!ldev)
+				break;
+
+			next = ldev;
+			niter = &ldev->adj_list.lower;
+			dev_stack[cur] = now;
+			iter_stack[cur++] = iter;
+			if (max <= cur)
+				max = cur;
+			break;
+		}
+
+		if (!next) {
+			if (!cur)
+				return max;
+			next = dev_stack[--cur];
+			niter = iter_stack[cur];
+		}
+
+		now = next;
+		iter = niter;
+	}
+
+	return max;
+}
+#endif
+
 static void bond_get_stats(struct net_device *bond_dev,
 			   struct rtnl_link_stats64 *stats)
 {
@@ -3446,11 +3551,17 @@
 	struct rtnl_link_stats64 temp;
 	struct list_head *iter;
 	struct slave *slave;
+	int nest_level = 0;
 
-	spin_lock(&bond->stats_lock);
-	memcpy(stats, &bond->bond_stats, sizeof(*stats));
 
 	rcu_read_lock();
+#ifdef CONFIG_LOCKDEP
+	nest_level = bond_get_lowest_level_rcu(bond_dev);
+#endif
+
+	spin_lock_nested(&bond->stats_lock, nest_level);
+	memcpy(stats, &bond->bond_stats, sizeof(*stats));
+
 	bond_for_each_slave_rcu(bond, slave, iter) {
 		const struct rtnl_link_stats64 *new =
 			dev_get_stats(slave->dev, &temp);
@@ -3460,10 +3571,10 @@
 		/* save off the slave stats for the next run */
 		memcpy(&slave->slave_stats, new, sizeof(*new));
 	}
-	rcu_read_unlock();
 
 	memcpy(&bond->bond_stats, stats, sizeof(*stats));
 	spin_unlock(&bond->stats_lock);
+	rcu_read_unlock();
 }
 
 static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)
@@ -3553,6 +3664,8 @@
 	case BOND_RELEASE_OLD:
 	case SIOCBONDRELEASE:
 		res = bond_release(bond_dev, slave_dev);
+		if (!res)
+			netdev_update_lockdep_key(slave_dev);
 		break;
 	case BOND_SETHWADDR_OLD:
 	case SIOCBONDSETHWADDR:
@@ -3612,32 +3725,35 @@
 	const struct net_device_ops *slave_ops;
 	struct neigh_parms parms;
 	struct slave *slave;
-	int ret;
+	int ret = 0;
 
-	slave = bond_first_slave(bond);
+	rcu_read_lock();
+	slave = bond_first_slave_rcu(bond);
 	if (!slave)
-		return 0;
+		goto out;
 	slave_ops = slave->dev->netdev_ops;
 	if (!slave_ops->ndo_neigh_setup)
-		return 0;
-
-	parms.neigh_setup = NULL;
-	parms.neigh_cleanup = NULL;
-	ret = slave_ops->ndo_neigh_setup(slave->dev, &parms);
-	if (ret)
-		return ret;
+		goto out;
 
-	/* Assign slave's neigh_cleanup to neighbour in case cleanup is called
-	 * after the last slave has been detached.  Assumes that all slaves
-	 * utilize the same neigh_cleanup (true at this writing as only user
-	 * is ipoib).
+	/* TODO: find another way [1] to implement this.
+	 * Passing a zeroed structure is fragile,
+	 * but at least we do not pass garbage.
+	 *
+	 * [1] One way would be that ndo_neigh_setup() never touch
+	 *     struct neigh_parms, but propagate the new neigh_setup()
+	 *     back to ___neigh_create() / neigh_parms_alloc()
 	 */
-	n->parms->neigh_cleanup = parms.neigh_cleanup;
+	memset(&parms, 0, sizeof(parms));
+	ret = slave_ops->ndo_neigh_setup(slave->dev, &parms);
 
-	if (!parms.neigh_setup)
-		return 0;
+	if (ret)
+		goto out;
 
-	return parms.neigh_setup(n);
+	if (parms.neigh_setup)
+		ret = parms.neigh_setup(n);
+out:
+	rcu_read_unlock();
+	return ret;
 }
 
 /* The bonding ndo_neigh_setup is called at init time beofre any
@@ -3948,6 +4064,29 @@
 	bond_slave_arr_work_rearm(bond, 1);
 }
 
+static void bond_skip_slave(struct bond_up_slave *slaves,
+			    struct slave *skipslave)
+{
+	int idx;
+
+	/* Rare situation where caller has asked to skip a specific
+	 * slave but allocation failed (most likely!). BTW this is
+	 * only possible when the call is initiated from
+	 * __bond_release_one(). In this situation; overwrite the
+	 * skipslave entry in the array with the last entry from the
+	 * array to avoid a situation where the xmit path may choose
+	 * this to-be-skipped slave to send a packet out.
+	 */
+	for (idx = 0; slaves && idx < slaves->count; idx++) {
+		if (skipslave == slaves->arr[idx]) {
+			slaves->arr[idx] =
+				slaves->arr[slaves->count - 1];
+			slaves->count--;
+			break;
+		}
+	}
+}
+
 /* Build the usable slaves array in control path for modes that use xmit-hash
  * to determine the slave interface -
  * (a) BOND_MODE_8023AD
@@ -3958,9 +4097,9 @@
  */
 int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 {
+	struct bond_up_slave *usable_slaves, *old_usable_slaves;
 	struct slave *slave;
 	struct list_head *iter;
-	struct bond_up_slave *new_arr, *old_arr;
 	int agg_id = 0;
 	int ret = 0;
 
@@ -3968,11 +4107,10 @@
 	WARN_ON(lockdep_is_held(&bond->mode_lock));
 #endif
 
-	new_arr = kzalloc(offsetof(struct bond_up_slave, arr[bond->slave_cnt]),
-			  GFP_KERNEL);
-	if (!new_arr) {
+	usable_slaves = kzalloc(struct_size(usable_slaves, arr,
+					    bond->slave_cnt), GFP_KERNEL);
+	if (!usable_slaves) {
 		ret = -ENOMEM;
-		pr_err("Failed to build slave-array.\n");
 		goto out;
 	}
 	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
@@ -3980,14 +4118,14 @@
 
 		if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
 			pr_debug("bond_3ad_get_active_agg_info failed\n");
-			kfree_rcu(new_arr, rcu);
+			kfree_rcu(usable_slaves, rcu);
 			/* No active aggragator means it's not safe to use
 			 * the previous array.
 			 */
-			old_arr = rtnl_dereference(bond->slave_arr);
-			if (old_arr) {
-				RCU_INIT_POINTER(bond->slave_arr, NULL);
-				kfree_rcu(old_arr, rcu);
+			old_usable_slaves = rtnl_dereference(bond->usable_slaves);
+			if (old_usable_slaves) {
+				RCU_INIT_POINTER(bond->usable_slaves, NULL);
+				kfree_rcu(old_usable_slaves, rcu);
 			}
 			goto out;
 		}
@@ -4007,37 +4145,20 @@
 			continue;
 
 		slave_dbg(bond->dev, slave->dev, "Adding slave to tx hash array[%d]\n",
-			  new_arr->count);
+			  usable_slaves->count);
 
-		new_arr->arr[new_arr->count++] = slave;
+		usable_slaves->arr[usable_slaves->count++] = slave;
 	}
 
-	old_arr = rtnl_dereference(bond->slave_arr);
-	rcu_assign_pointer(bond->slave_arr, new_arr);
-	if (old_arr)
-		kfree_rcu(old_arr, rcu);
+	old_usable_slaves = rtnl_dereference(bond->usable_slaves);
+	rcu_assign_pointer(bond->usable_slaves, usable_slaves);
+	if (old_usable_slaves)
+		kfree_rcu(old_usable_slaves, rcu);
 out:
-	if (ret != 0 && skipslave) {
-		int idx;
+	if (ret != 0 && skipslave)
+		bond_skip_slave(rtnl_dereference(bond->usable_slaves),
+				skipslave);
 
-		/* Rare situation where caller has asked to skip a specific
-		 * slave but allocation failed (most likely!). BTW this is
-		 * only possible when the call is initiated from
-		 * __bond_release_one(). In this situation; overwrite the
-		 * skipslave entry in the array with the last entry from the
-		 * array to avoid a situation where the xmit path may choose
-		 * this to-be-skipped slave to send a packet out.
-		 */
-		old_arr = rtnl_dereference(bond->slave_arr);
-		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];
-				old_arr->count--;
-				break;
-			}
-		}
-	}
 	return ret;
 }
 
@@ -4053,7 +4174,7 @@
 	struct bond_up_slave *slaves;
 	unsigned int count;
 
-	slaves = rcu_dereference(bond->slave_arr);
+	slaves = rcu_dereference(bond->usable_slaves);
 	count = slaves ? READ_ONCE(slaves->count) : 0;
 	if (likely(count)) {
 		slave = slaves->arr[bond_xmit_hash(bond, skb) % count];
@@ -4197,13 +4318,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_link_ksettings(struct net_device *bond_dev,
 					   struct ethtool_link_ksettings *cmd)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	unsigned long speed = 0;
 	struct list_head *iter;
 	struct slave *slave;
+	u32 speed = 0;
 
 	cmd->base.duplex = DUPLEX_UNKNOWN;
 	cmd->base.port = PORT_OTHER;
@@ -4215,8 +4346,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 (cmd->base.duplex == DUPLEX_UNKNOWN &&
 			    slave->duplex != DUPLEX_UNKNOWN)
 				cmd->base.duplex = slave->duplex;
@@ -4321,7 +4457,9 @@
 
 	bond_dev->hw_features = BOND_VLAN_FEATURES |
 				NETIF_F_HW_VLAN_CTAG_RX |
-				NETIF_F_HW_VLAN_CTAG_FILTER;
+				NETIF_F_HW_VLAN_CTAG_FILTER |
+				NETIF_F_HW_VLAN_STAG_RX |
+				NETIF_F_HW_VLAN_STAG_FILTER;
 
 	bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
 	bond_dev->features |= bond_dev->hw_features;
@@ -4345,9 +4483,9 @@
 		__bond_release_one(bond_dev, slave->dev, true, true);
 	netdev_info(bond_dev, "Released all slaves\n");
 
-	arr = rtnl_dereference(bond->slave_arr);
+	arr = rtnl_dereference(bond->usable_slaves);
 	if (arr) {
-		RCU_INIT_POINTER(bond->slave_arr, NULL);
+		RCU_INIT_POINTER(bond->usable_slaves, NULL);
 		kfree_rcu(arr, rcu);
 	}
 
@@ -4757,6 +4895,8 @@
 	if (!bond->wq)
 		return -ENOMEM;
 
+	bond->notifier_ctx = false;
+
 	spin_lock_init(&bond->stats_lock);
 	lockdep_register_key(&bond->stats_lock_key);
 	lockdep_set_class(&bond->stats_lock, &bond->stats_lock_key);
@@ -4815,15 +4955,19 @@
 	bond_dev->rtnl_link_ops = &bond_link_ops;
 
 	res = register_netdevice(bond_dev);
+	if (res < 0) {
+		free_netdev(bond_dev);
+		rtnl_unlock();
+
+		return res;
+	}
 
 	netif_carrier_off(bond_dev);
 
 	bond_work_init_all(bond);
 
 	rtnl_unlock();
-	if (res < 0)
-		free_netdev(bond_dev);
-	return res;
+	return 0;
 }
 
 static int __net_init bond_net_init(struct net *net)
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_netlink.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_netlink.c
@@ -456,11 +456,10 @@
 		return err;
 
 	err = register_netdevice(bond_dev);
-
-	netif_carrier_off(bond_dev);
 	if (!err) {
 		struct bonding *bond = netdev_priv(bond_dev);
 
+		netif_carrier_off(bond_dev);
 		bond_work_init_all(bond);
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_options.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_options.c
@@ -1398,6 +1398,8 @@
 	case '-':
 		slave_dbg(bond->dev, dev, "Releasing interface\n");
 		ret = bond_release(bond->dev, dev);
+		if (!ret)
+			netdev_update_lockdep_key(dev);
 		break;
 
 	default:
@@ -1450,7 +1452,7 @@
 		mac = (u8 *)&newval->value;
 	}
 
-	if (!is_valid_ether_addr(mac))
+	if (is_multicast_ether_addr(mac))
 		goto err;
 
 	netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
--- linux-ein-5.4.0.orig/drivers/net/bonding/bond_sysfs_slave.c
+++ linux-ein-5.4.0/drivers/net/bonding/bond_sysfs_slave.c
@@ -108,20 +108,19 @@
 }
 static SLAVE_ATTR_RO(ad_partner_oper_port_state);
 
-static const struct slave_attribute *slave_attrs[] = {
-	&slave_attr_state,
-	&slave_attr_mii_status,
-	&slave_attr_link_failure_count,
-	&slave_attr_perm_hwaddr,
-	&slave_attr_queue_id,
-	&slave_attr_ad_aggregator_id,
-	&slave_attr_ad_actor_oper_port_state,
-	&slave_attr_ad_partner_oper_port_state,
+static const struct attribute *slave_attrs[] = {
+	&slave_attr_state.attr,
+	&slave_attr_mii_status.attr,
+	&slave_attr_link_failure_count.attr,
+	&slave_attr_perm_hwaddr.attr,
+	&slave_attr_queue_id.attr,
+	&slave_attr_ad_aggregator_id.attr,
+	&slave_attr_ad_actor_oper_port_state.attr,
+	&slave_attr_ad_partner_oper_port_state.attr,
 	NULL
 };
 
 #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)
@@ -132,43 +131,16 @@
 	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) {
-			kobject_put(&slave->kobj);
-			return err;
-		}
-	}
-
-	return 0;
+	return sysfs_create_files(&slave->kobj, slave_attrs);
 }
 
 void bond_sysfs_slave_del(struct slave *slave)
 {
-	const struct slave_attribute **a;
-
-	for (a = slave_attrs; *a; ++a)
-		sysfs_remove_file(&slave->kobj, &((*a)->attr));
-
-	kobject_put(&slave->kobj);
+	sysfs_remove_files(&slave->kobj, slave_attrs);
 }
--- linux-ein-5.4.0.orig/drivers/net/caif/caif_serial.c
+++ linux-ein-5.4.0/drivers/net/caif/caif_serial.c
@@ -270,7 +270,6 @@
 {
 	struct ser_device *ser;
 
-	BUG_ON(dev == NULL);
 	ser = netdev_priv(dev);
 
 	/* Send flow off once, on high water mark */
@@ -352,6 +351,7 @@
 	rtnl_lock();
 	result = register_netdevice(dev);
 	if (result) {
+		tty_kref_put(tty);
 		rtnl_unlock();
 		free_netdev(dev);
 		return -ENODEV;
--- linux-ein-5.4.0.orig/drivers/net/caif/caif_virtio.c
+++ linux-ein-5.4.0/drivers/net/caif/caif_virtio.c
@@ -723,13 +723,21 @@
 	/* Carrier is off until netdevice is opened */
 	netif_carrier_off(netdev);
 
+	/* serialize netdev register + virtio_device_ready() with ndo_open() */
+	rtnl_lock();
+
 	/* register Netdev */
-	err = register_netdev(netdev);
+	err = register_netdevice(netdev);
 	if (err) {
+		rtnl_unlock();
 		dev_err(&vdev->dev, "Unable to register netdev (%d)\n", err);
 		goto err;
 	}
 
+	virtio_device_ready(vdev);
+
+	rtnl_unlock();
+
 	debugfs_init(cfv);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/can/Kconfig
+++ linux-ein-5.4.0/drivers/net/can/Kconfig
@@ -123,6 +123,7 @@
 config CAN_KVASER_PCIEFD
 	depends on PCI
 	tristate "Kvaser PCIe FD cards"
+	select CRC32
 	  help
 	  This is a driver for the Kvaser PCI Express CAN FD family.
 
--- linux-ein-5.4.0.orig/drivers/net/can/Makefile
+++ linux-ein-5.4.0/drivers/net/can/Makefile
@@ -7,12 +7,7 @@
 obj-$(CONFIG_CAN_VXCAN)		+= vxcan.o
 obj-$(CONFIG_CAN_SLCAN)		+= slcan.o
 
-obj-$(CONFIG_CAN_DEV)		+= can-dev.o
-can-dev-y			+= dev.o
-can-dev-y			+= rx-offload.o
-
-can-dev-$(CONFIG_CAN_LEDS)	+= led.o
-
+obj-y				+= dev/
 obj-y				+= rcar/
 obj-y				+= spi/
 obj-y				+= usb/
--- linux-ein-5.4.0.orig/drivers/net/can/c_can/c_can.c
+++ linux-ein-5.4.0/drivers/net/can/c_can/c_can.c
@@ -212,18 +212,6 @@
 	.brp_inc = 1,
 };
 
-static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
-{
-	if (priv->device)
-		pm_runtime_enable(priv->device);
-}
-
-static inline void c_can_pm_runtime_disable(const struct c_can_priv *priv)
-{
-	if (priv->device)
-		pm_runtime_disable(priv->device);
-}
-
 static inline void c_can_pm_runtime_get_sync(const struct c_can_priv *priv)
 {
 	if (priv->device)
@@ -1334,7 +1322,6 @@
 
 int register_c_can_dev(struct net_device *dev)
 {
-	struct c_can_priv *priv = netdev_priv(dev);
 	int err;
 
 	/* Deactivate pins to prevent DRA7 DCAN IP from being
@@ -1344,28 +1331,19 @@
 	 */
 	pinctrl_pm_select_sleep_state(dev->dev.parent);
 
-	c_can_pm_runtime_enable(priv);
-
 	dev->flags |= IFF_ECHO;	/* we support local echo */
 	dev->netdev_ops = &c_can_netdev_ops;
 
 	err = register_candev(dev);
-	if (err)
-		c_can_pm_runtime_disable(priv);
-	else
+	if (!err)
 		devm_can_led_init(dev);
-
 	return err;
 }
 EXPORT_SYMBOL_GPL(register_c_can_dev);
 
 void unregister_c_can_dev(struct net_device *dev)
 {
-	struct c_can_priv *priv = netdev_priv(dev);
-
 	unregister_candev(dev);
-
-	c_can_pm_runtime_disable(priv);
 }
 EXPORT_SYMBOL_GPL(unregister_c_can_dev);
 
--- linux-ein-5.4.0.orig/drivers/net/can/c_can/c_can_pci.c
+++ linux-ein-5.4.0/drivers/net/can/c_can/c_can_pci.c
@@ -239,12 +239,13 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct c_can_priv *priv = netdev_priv(dev);
+	void __iomem *addr = priv->base;
 
 	unregister_c_can_dev(dev);
 
 	free_c_can_dev(dev);
 
-	pci_iounmap(pdev, priv->base);
+	pci_iounmap(pdev, addr);
 	pci_disable_msi(pdev);
 	pci_clear_master(pdev);
 	pci_release_regions(pdev);
--- linux-ein-5.4.0.orig/drivers/net/can/c_can/c_can_platform.c
+++ linux-ein-5.4.0/drivers/net/can/c_can/c_can_platform.c
@@ -29,6 +29,7 @@
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -385,6 +386,7 @@
 	platform_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
+	pm_runtime_enable(priv->device);
 	ret = register_c_can_dev(dev);
 	if (ret) {
 		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
@@ -397,6 +399,7 @@
 	return 0;
 
 exit_free_device:
+	pm_runtime_disable(priv->device);
 	free_c_can_dev(dev);
 exit:
 	dev_err(&pdev->dev, "probe failed\n");
@@ -407,9 +410,10 @@
 static int c_can_plat_remove(struct platform_device *pdev)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
+	struct c_can_priv *priv = netdev_priv(dev);
 
 	unregister_c_can_dev(dev);
-
+	pm_runtime_disable(priv->device);
 	free_c_can_dev(dev);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/can/cc770/cc770_isa.c
+++ linux-ein-5.4.0/drivers/net/can/cc770/cc770_isa.c
@@ -264,22 +264,24 @@
 	if (err) {
 		dev_err(&pdev->dev,
 			"couldn't register device (err=%d)\n", err);
-		goto exit_unmap;
+		goto exit_free;
 	}
 
 	dev_info(&pdev->dev, "device registered (reg_base=0x%p, irq=%d)\n",
 		 priv->reg_base, dev->irq);
 	return 0;
 
- exit_unmap:
+exit_free:
+	free_cc770dev(dev);
+exit_unmap:
 	if (mem[idx])
 		iounmap(base);
- exit_release:
+exit_release:
 	if (mem[idx])
 		release_mem_region(mem[idx], iosize);
 	else
 		release_region(port[idx], iosize);
- exit:
+exit:
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/dev/Makefile
+++ linux-ein-5.4.0/drivers/net/can/dev/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_CAN_DEV)		+= can-dev.o
+can-dev-y			+= dev.o
+can-dev-y			+= rx-offload.o
+
+can-dev-$(CONFIG_CAN_LEDS)	+= led.o
--- linux-ein-5.4.0.orig/drivers/net/can/dev/dev.c
+++ linux-ein-5.4.0/drivers/net/can/dev/dev.c
@@ -0,0 +1,1313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
+ * Copyright (C) 2006 Andrey Volkov, Varma Electronics
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/workqueue.h>
+#include <linux/can.h>
+#include <linux/can/can-ml.h>
+#include <linux/can/dev.h>
+#include <linux/can/skb.h>
+#include <linux/can/netlink.h>
+#include <linux/can/led.h>
+#include <linux/of.h>
+#include <net/rtnetlink.h>
+
+#define MOD_DESC "CAN device driver interface"
+
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+
+/* CAN DLC to real data length conversion helpers */
+
+static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+			     8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from can_dlc with sanitized can_dlc */
+u8 can_dlc2len(u8 can_dlc)
+{
+	return dlc2len[can_dlc & 0x0F];
+}
+EXPORT_SYMBOL_GPL(can_dlc2len);
+
+static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,		/* 0 - 8 */
+			     9, 9, 9, 9,			/* 9 - 12 */
+			     10, 10, 10, 10,			/* 13 - 16 */
+			     11, 11, 11, 11,			/* 17 - 20 */
+			     12, 12, 12, 12,			/* 21 - 24 */
+			     13, 13, 13, 13, 13, 13, 13, 13,	/* 25 - 32 */
+			     14, 14, 14, 14, 14, 14, 14, 14,	/* 33 - 40 */
+			     14, 14, 14, 14, 14, 14, 14, 14,	/* 41 - 48 */
+			     15, 15, 15, 15, 15, 15, 15, 15,	/* 49 - 56 */
+			     15, 15, 15, 15, 15, 15, 15, 15};	/* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+u8 can_len2dlc(u8 len)
+{
+	if (unlikely(len > 64))
+		return 0xF;
+
+	return len2dlc[len];
+}
+EXPORT_SYMBOL_GPL(can_len2dlc);
+
+#ifdef CONFIG_CAN_CALC_BITTIMING
+#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
+#define CAN_CALC_SYNC_SEG 1
+
+/* Bit-timing calculation derived from:
+ *
+ * Code based on LinCAN sources and H8S2638 project
+ * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ * Copyright 2005      Stanislav Marek
+ * email: pisa@cmp.felk.cvut.cz
+ *
+ * Calculates proper bit-timing parameters for a specified bit-rate
+ * and sample-point, which can then be used to set the bit-timing
+ * registers of the CAN controller. You can find more information
+ * in the header file linux/can/netlink.h.
+ */
+static int
+can_update_sample_point(const struct can_bittiming_const *btc,
+			unsigned int sample_point_nominal, unsigned int tseg,
+			unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
+			unsigned int *sample_point_error_ptr)
+{
+	unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
+	unsigned int sample_point, best_sample_point = 0;
+	unsigned int tseg1, tseg2;
+	int i;
+
+	for (i = 0; i <= 1; i++) {
+		tseg2 = tseg + CAN_CALC_SYNC_SEG -
+			(sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) /
+			1000 - i;
+		tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
+		tseg1 = tseg - tseg2;
+		if (tseg1 > btc->tseg1_max) {
+			tseg1 = btc->tseg1_max;
+			tseg2 = tseg - tseg1;
+		}
+
+		sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) /
+			(tseg + CAN_CALC_SYNC_SEG);
+		sample_point_error = abs(sample_point_nominal - sample_point);
+
+		if (sample_point <= sample_point_nominal &&
+		    sample_point_error < best_sample_point_error) {
+			best_sample_point = sample_point;
+			best_sample_point_error = sample_point_error;
+			*tseg1_ptr = tseg1;
+			*tseg2_ptr = tseg2;
+		}
+	}
+
+	if (sample_point_error_ptr)
+		*sample_point_error_ptr = best_sample_point_error;
+
+	return best_sample_point;
+}
+
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+			      const struct can_bittiming_const *btc)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	unsigned int bitrate;			/* current bitrate */
+	unsigned int bitrate_error;		/* difference between current and nominal value */
+	unsigned int best_bitrate_error = UINT_MAX;
+	unsigned int sample_point_error;	/* difference between current and nominal value */
+	unsigned int best_sample_point_error = UINT_MAX;
+	unsigned int sample_point_nominal;	/* nominal sample point */
+	unsigned int best_tseg = 0;		/* current best value for tseg */
+	unsigned int best_brp = 0;		/* current best value for brp */
+	unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
+	u64 v64;
+
+	/* Use CiA recommended sample points */
+	if (bt->sample_point) {
+		sample_point_nominal = bt->sample_point;
+	} else {
+		if (bt->bitrate > 800000)
+			sample_point_nominal = 750;
+		else if (bt->bitrate > 500000)
+			sample_point_nominal = 800;
+		else
+			sample_point_nominal = 875;
+	}
+
+	/* tseg even = round down, odd = round up */
+	for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
+	     tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
+		tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
+
+		/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
+		brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
+
+		/* choose brp step which is possible in system */
+		brp = (brp / btc->brp_inc) * btc->brp_inc;
+		if (brp < btc->brp_min || brp > btc->brp_max)
+			continue;
+
+		bitrate = priv->clock.freq / (brp * tsegall);
+		bitrate_error = abs(bt->bitrate - bitrate);
+
+		/* tseg brp biterror */
+		if (bitrate_error > best_bitrate_error)
+			continue;
+
+		/* reset sample point error if we have a better bitrate */
+		if (bitrate_error < best_bitrate_error)
+			best_sample_point_error = UINT_MAX;
+
+		can_update_sample_point(btc, sample_point_nominal, tseg / 2,
+					&tseg1, &tseg2, &sample_point_error);
+		if (sample_point_error > best_sample_point_error)
+			continue;
+
+		best_sample_point_error = sample_point_error;
+		best_bitrate_error = bitrate_error;
+		best_tseg = tseg / 2;
+		best_brp = brp;
+
+		if (bitrate_error == 0 && sample_point_error == 0)
+			break;
+	}
+
+	if (best_bitrate_error) {
+		/* Error in one-tenth of a percent */
+		v64 = (u64)best_bitrate_error * 1000;
+		do_div(v64, bt->bitrate);
+		bitrate_error = (u32)v64;
+		if (bitrate_error > CAN_CALC_MAX_ERROR) {
+			netdev_err(dev,
+				   "bitrate error %d.%d%% too high\n",
+				   bitrate_error / 10, bitrate_error % 10);
+			return -EDOM;
+		}
+		netdev_warn(dev, "bitrate error %d.%d%%\n",
+			    bitrate_error / 10, bitrate_error % 10);
+	}
+
+	/* real sample point */
+	bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
+						   best_tseg, &tseg1, &tseg2,
+						   NULL);
+
+	v64 = (u64)best_brp * 1000 * 1000 * 1000;
+	do_div(v64, priv->clock.freq);
+	bt->tq = (u32)v64;
+	bt->prop_seg = tseg1 / 2;
+	bt->phase_seg1 = tseg1 - bt->prop_seg;
+	bt->phase_seg2 = tseg2;
+
+	/* check for sjw user settings */
+	if (!bt->sjw || !btc->sjw_max) {
+		bt->sjw = 1;
+	} else {
+		/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
+		if (bt->sjw > btc->sjw_max)
+			bt->sjw = btc->sjw_max;
+		/* bt->sjw must not be higher than tseg2 */
+		if (tseg2 < bt->sjw)
+			bt->sjw = tseg2;
+	}
+
+	bt->brp = best_brp;
+
+	/* real bitrate */
+	bt->bitrate = priv->clock.freq /
+		(bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
+
+	return 0;
+}
+#else /* !CONFIG_CAN_CALC_BITTIMING */
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+			      const struct can_bittiming_const *btc)
+{
+	netdev_err(dev, "bit-timing calculation not available\n");
+	return -EINVAL;
+}
+#endif /* CONFIG_CAN_CALC_BITTIMING */
+
+/* Checks the validity of the specified bit-timing parameters prop_seg,
+ * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
+ * prescaler value brp. You can find more information in the header
+ * file linux/can/netlink.h.
+ */
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
+			       const struct can_bittiming_const *btc)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	int tseg1, alltseg;
+	u64 brp64;
+
+	tseg1 = bt->prop_seg + bt->phase_seg1;
+	if (!bt->sjw)
+		bt->sjw = 1;
+	if (bt->sjw > btc->sjw_max ||
+	    tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
+	    bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
+		return -ERANGE;
+
+	brp64 = (u64)priv->clock.freq * (u64)bt->tq;
+	if (btc->brp_inc > 1)
+		do_div(brp64, btc->brp_inc);
+	brp64 += 500000000UL - 1;
+	do_div(brp64, 1000000000UL); /* the practicable BRP */
+	if (btc->brp_inc > 1)
+		brp64 *= btc->brp_inc;
+	bt->brp = (u32)brp64;
+
+	if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
+		return -EINVAL;
+
+	alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
+	bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
+	bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
+
+	return 0;
+}
+
+/* Checks the validity of predefined bitrate settings */
+static int
+can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt,
+		     const u32 *bitrate_const,
+		     const unsigned int bitrate_const_cnt)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	unsigned int i;
+
+	for (i = 0; i < bitrate_const_cnt; i++) {
+		if (bt->bitrate == bitrate_const[i])
+			break;
+	}
+
+	if (i >= priv->bitrate_const_cnt)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
+			     const struct can_bittiming_const *btc,
+			     const u32 *bitrate_const,
+			     const unsigned int bitrate_const_cnt)
+{
+	int err;
+
+	/* Depending on the given can_bittiming parameter structure the CAN
+	 * timing parameters are calculated based on the provided bitrate OR
+	 * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
+	 * provided directly which are then checked and fixed up.
+	 */
+	if (!bt->tq && bt->bitrate && btc)
+		err = can_calc_bittiming(dev, bt, btc);
+	else if (bt->tq && !bt->bitrate && btc)
+		err = can_fixup_bittiming(dev, bt, btc);
+	else if (!bt->tq && bt->bitrate && bitrate_const)
+		err = can_validate_bitrate(dev, bt, bitrate_const,
+					   bitrate_const_cnt);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+
+static void can_update_state_error_stats(struct net_device *dev,
+					 enum can_state new_state)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	if (new_state <= priv->state)
+		return;
+
+	switch (new_state) {
+	case CAN_STATE_ERROR_WARNING:
+		priv->can_stats.error_warning++;
+		break;
+	case CAN_STATE_ERROR_PASSIVE:
+		priv->can_stats.error_passive++;
+		break;
+	case CAN_STATE_BUS_OFF:
+		priv->can_stats.bus_off++;
+		break;
+	default:
+		break;
+	}
+}
+
+static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
+{
+	switch (state) {
+	case CAN_STATE_ERROR_ACTIVE:
+		return CAN_ERR_CRTL_ACTIVE;
+	case CAN_STATE_ERROR_WARNING:
+		return CAN_ERR_CRTL_TX_WARNING;
+	case CAN_STATE_ERROR_PASSIVE:
+		return CAN_ERR_CRTL_TX_PASSIVE;
+	default:
+		return 0;
+	}
+}
+
+static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
+{
+	switch (state) {
+	case CAN_STATE_ERROR_ACTIVE:
+		return CAN_ERR_CRTL_ACTIVE;
+	case CAN_STATE_ERROR_WARNING:
+		return CAN_ERR_CRTL_RX_WARNING;
+	case CAN_STATE_ERROR_PASSIVE:
+		return CAN_ERR_CRTL_RX_PASSIVE;
+	default:
+		return 0;
+	}
+}
+
+void can_change_state(struct net_device *dev, struct can_frame *cf,
+		      enum can_state tx_state, enum can_state rx_state)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	enum can_state new_state = max(tx_state, rx_state);
+
+	if (unlikely(new_state == priv->state)) {
+		netdev_warn(dev, "%s: oops, state did not change", __func__);
+		return;
+	}
+
+	netdev_dbg(dev, "New error state: %d\n", new_state);
+
+	can_update_state_error_stats(dev, new_state);
+	priv->state = new_state;
+
+	if (!cf)
+		return;
+
+	if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
+		cf->can_id |= CAN_ERR_BUSOFF;
+		return;
+	}
+
+	cf->can_id |= CAN_ERR_CRTL;
+	cf->data[1] |= tx_state >= rx_state ?
+		       can_tx_state_to_frame(dev, tx_state) : 0;
+	cf->data[1] |= tx_state <= rx_state ?
+		       can_rx_state_to_frame(dev, rx_state) : 0;
+}
+EXPORT_SYMBOL_GPL(can_change_state);
+
+/* Local echo of CAN messages
+ *
+ * CAN network devices *should* support a local echo functionality
+ * (see Documentation/networking/can.rst). To test the handling of CAN
+ * interfaces that do not support the local echo both driver types are
+ * implemented. In the case that the driver does not support the echo
+ * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
+ * to perform the echo as a fallback solution.
+ */
+static void can_flush_echo_skb(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	int i;
+
+	for (i = 0; i < priv->echo_skb_max; i++) {
+		if (priv->echo_skb[i]) {
+			kfree_skb(priv->echo_skb[i]);
+			priv->echo_skb[i] = NULL;
+			stats->tx_dropped++;
+			stats->tx_aborted_errors++;
+		}
+	}
+}
+
+/* Put the skb on the stack to be looped backed locally lateron
+ *
+ * The function is typically called in the start_xmit function
+ * of the device driver. The driver must protect access to
+ * priv->echo_skb, if necessary.
+ */
+void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
+		      unsigned int idx)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	BUG_ON(idx >= priv->echo_skb_max);
+
+	/* check flag whether this packet has to be looped back */
+	if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
+	    (skb->protocol != htons(ETH_P_CAN) &&
+	     skb->protocol != htons(ETH_P_CANFD))) {
+		kfree_skb(skb);
+		return;
+	}
+
+	if (!priv->echo_skb[idx]) {
+		skb = can_create_echo_skb(skb);
+		if (!skb)
+			return;
+
+		/* make settings for echo to reduce code in irq context */
+		skb->pkt_type = PACKET_BROADCAST;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->dev = dev;
+
+		/* save this skb for tx interrupt echo handling */
+		priv->echo_skb[idx] = skb;
+	} else {
+		/* locking problem with netif_stop_queue() ?? */
+		netdev_err(dev, "%s: BUG! echo_skb is occupied!\n", __func__);
+		kfree_skb(skb);
+	}
+}
+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
+ *
+ * The function is typically called when the TX done interrupt
+ * is handled in the device driver. The driver must protect
+ * access to priv->echo_skb, if necessary.
+ */
+unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
+{
+	struct sk_buff *skb;
+	u8 len;
+
+	skb = __can_get_echo_skb(dev, idx, &len);
+	if (!skb)
+		return 0;
+
+	skb_get(skb);
+	if (netif_rx(skb) == NET_RX_SUCCESS)
+		dev_consume_skb_any(skb);
+	else
+		dev_kfree_skb_any(skb);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(can_get_echo_skb);
+
+/* Remove the skb from the stack and free it.
+ *
+ * The function is typically called when TX failed.
+ */
+void can_free_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]) {
+		dev_kfree_skb_any(priv->echo_skb[idx]);
+		priv->echo_skb[idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(can_free_echo_skb);
+
+/* CAN device restart for bus-off recovery */
+static void can_restart(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	struct can_frame *cf;
+	int err;
+
+	if (netif_carrier_ok(dev))
+		netdev_err(dev, "Attempt to restart for bus-off recovery, but carrier is OK?\n");
+
+	/* No synchronization needed because the device is bus-off and
+	 * no messages can come in or go out.
+	 */
+	can_flush_echo_skb(dev);
+
+	/* send restart message upstream */
+	skb = alloc_can_err_skb(dev, &cf);
+	if (!skb)
+		goto restart;
+
+	cf->can_id |= CAN_ERR_RESTARTED;
+
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+	netif_rx_ni(skb);
+
+restart:
+	netdev_dbg(dev, "restarted\n");
+	priv->can_stats.restarts++;
+
+	/* Now restart the device */
+	netif_carrier_on(dev);
+	err = priv->do_set_mode(dev, CAN_MODE_START);
+	if (err) {
+		netdev_err(dev, "Error %d during restart", err);
+		netif_carrier_off(dev);
+	}
+}
+
+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);
+
+	/* A manual restart is only permitted if automatic restart is
+	 * disabled and the device is in the bus-off state
+	 */
+	if (priv->restart_ms)
+		return -EINVAL;
+	if (priv->state != CAN_STATE_BUS_OFF)
+		return -EBUSY;
+
+	cancel_delayed_work_sync(&priv->restart_work);
+	can_restart(dev);
+
+	return 0;
+}
+
+/* CAN bus-off
+ *
+ * This functions should be called when the device goes bus-off to
+ * tell the netif layer that no more packets can be sent or received.
+ * If enabled, a timer is started to trigger bus-off recovery.
+ */
+void can_bus_off(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	netdev_info(dev, "bus-off\n");
+
+	netif_carrier_off(dev);
+
+	if (priv->restart_ms)
+		schedule_delayed_work(&priv->restart_work,
+				      msecs_to_jiffies(priv->restart_ms));
+}
+EXPORT_SYMBOL_GPL(can_bus_off);
+
+static void can_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_CAN;
+	dev->mtu = CAN_MTU;
+	dev->hard_header_len = 0;
+	dev->addr_len = 0;
+	dev->tx_queue_len = 10;
+
+	/* New-style flags. */
+	dev->flags = IFF_NOARP;
+	dev->features = NETIF_F_HW_CSUM;
+}
+
+struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
+{
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+			       sizeof(struct can_frame));
+	if (unlikely(!skb))
+		return NULL;
+
+	skb->protocol = htons(ETH_P_CAN);
+	skb->pkt_type = PACKET_BROADCAST;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+
+	can_skb_reserve(skb);
+	can_skb_prv(skb)->ifindex = dev->ifindex;
+	can_skb_prv(skb)->skbcnt = 0;
+
+	*cf = skb_put_zero(skb, sizeof(struct can_frame));
+
+	return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_can_skb);
+
+struct sk_buff *alloc_canfd_skb(struct net_device *dev,
+				struct canfd_frame **cfd)
+{
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+			       sizeof(struct canfd_frame));
+	if (unlikely(!skb))
+		return NULL;
+
+	skb->protocol = htons(ETH_P_CANFD);
+	skb->pkt_type = PACKET_BROADCAST;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+
+	can_skb_reserve(skb);
+	can_skb_prv(skb)->ifindex = dev->ifindex;
+	can_skb_prv(skb)->skbcnt = 0;
+
+	*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
+
+	return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_canfd_skb);
+
+struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_can_skb(dev, cf);
+	if (unlikely(!skb))
+		return NULL;
+
+	(*cf)->can_id = CAN_ERR_FLAG;
+	(*cf)->can_dlc = CAN_ERR_DLC;
+
+	return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_can_err_skb);
+
+/* Allocate and setup space for the CAN network device */
+struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
+				    unsigned int txqs, unsigned int rxqs)
+{
+	struct can_ml_priv *can_ml;
+	struct net_device *dev;
+	struct can_priv *priv;
+	int size;
+
+	/* We put the driver's priv, the CAN mid layer priv and the
+	 * echo skb into the netdevice's priv. The memory layout for
+	 * the netdev_priv is like this:
+	 *
+	 * +-------------------------+
+	 * | driver's priv           |
+	 * +-------------------------+
+	 * | struct can_ml_priv      |
+	 * +-------------------------+
+	 * | array of struct sk_buff |
+	 * +-------------------------+
+	 */
+
+	size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv);
+
+	if (echo_skb_max)
+		size = ALIGN(size, sizeof(struct sk_buff *)) +
+			echo_skb_max * sizeof(struct sk_buff *);
+
+	dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,
+			       txqs, rxqs);
+	if (!dev)
+		return NULL;
+
+	priv = netdev_priv(dev);
+	priv->dev = dev;
+
+	can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
+	can_set_ml_priv(dev, can_ml);
+
+	if (echo_skb_max) {
+		priv->echo_skb_max = echo_skb_max;
+		priv->echo_skb = (void *)priv +
+			(size - echo_skb_max * sizeof(struct sk_buff *));
+	}
+
+	priv->state = CAN_STATE_STOPPED;
+
+	INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_candev_mqs);
+
+/* Free space of the CAN network device */
+void free_candev(struct net_device *dev)
+{
+	free_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(free_candev);
+
+/* changing MTU and control mode for CAN/CANFD devices */
+int can_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	/* Do not allow changing the MTU while running */
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	/* 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:
+		/* 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;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(can_change_mtu);
+
+/* Common open function when the device gets opened.
+ *
+ * This function should be called in the open function of the device
+ * driver.
+ */
+int open_candev(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	if (!priv->bittiming.bitrate) {
+		netdev_err(dev, "bit-timing not yet defined\n");
+		return -EINVAL;
+	}
+
+	/* For CAN FD the data bitrate has to be >= the arbitration bitrate */
+	if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
+	    (!priv->data_bittiming.bitrate ||
+	     priv->data_bittiming.bitrate < priv->bittiming.bitrate)) {
+		netdev_err(dev, "incorrect/missing data bit-timing\n");
+		return -EINVAL;
+	}
+
+	/* Switch carrier on if device was stopped while in bus-off state */
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(open_candev);
+
+#ifdef CONFIG_OF
+/* Common function that can be used to understand the limitation of
+ * a transceiver when it provides no means to determine these limitations
+ * at runtime.
+ */
+void of_can_transceiver(struct net_device *dev)
+{
+	struct device_node *dn;
+	struct can_priv *priv = netdev_priv(dev);
+	struct device_node *np = dev->dev.parent->of_node;
+	int ret;
+
+	dn = of_get_child_by_name(np, "can-transceiver");
+	if (!dn)
+		return;
+
+	ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
+	of_node_put(dn);
+	if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
+		netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
+}
+EXPORT_SYMBOL_GPL(of_can_transceiver);
+#endif
+
+/* Common close function for cleanup before the device gets closed.
+ *
+ * This function should be called in the close function of the device
+ * driver.
+ */
+void close_candev(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	cancel_delayed_work_sync(&priv->restart_work);
+	can_flush_echo_skb(dev);
+}
+EXPORT_SYMBOL_GPL(close_candev);
+
+/* CAN netlink interface */
+static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
+	[IFLA_CAN_STATE]	= { .type = NLA_U32 },
+	[IFLA_CAN_CTRLMODE]	= { .len = sizeof(struct can_ctrlmode) },
+	[IFLA_CAN_RESTART_MS]	= { .type = NLA_U32 },
+	[IFLA_CAN_RESTART]	= { .type = NLA_U32 },
+	[IFLA_CAN_BITTIMING]	= { .len = sizeof(struct can_bittiming) },
+	[IFLA_CAN_BITTIMING_CONST]
+				= { .len = sizeof(struct can_bittiming_const) },
+	[IFLA_CAN_CLOCK]	= { .len = sizeof(struct can_clock) },
+	[IFLA_CAN_BERR_COUNTER]	= { .len = sizeof(struct can_berr_counter) },
+	[IFLA_CAN_DATA_BITTIMING]
+				= { .len = sizeof(struct can_bittiming) },
+	[IFLA_CAN_DATA_BITTIMING_CONST]
+				= { .len = sizeof(struct can_bittiming_const) },
+	[IFLA_CAN_TERMINATION]	= { .type = NLA_U16 },
+};
+
+static int can_validate(struct nlattr *tb[], struct nlattr *data[],
+			struct netlink_ext_ack *extack)
+{
+	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[],
+			  struct netlink_ext_ack *extack)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	int err;
+
+	/* We need synchronization with dev->stop() */
+	ASSERT_RTNL();
+
+	if (data[IFLA_CAN_BITTIMING]) {
+		struct can_bittiming bt;
+
+		/* Do not allow changing bittiming while running */
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+
+		/* Calculate bittiming parameters based on
+		 * bittiming_const if set, otherwise pass bitrate
+		 * directly via do_set_bitrate(). Bail out if neither
+		 * is given.
+		 */
+		if (!priv->bittiming_const && !priv->do_set_bittiming)
+			return -EOPNOTSUPP;
+
+		memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+		err = can_get_bittiming(dev, &bt,
+					priv->bittiming_const,
+					priv->bitrate_const,
+					priv->bitrate_const_cnt);
+		if (err)
+			return err;
+
+		if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
+			netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
+				   priv->bitrate_max);
+			return -EINVAL;
+		}
+
+		memcpy(&priv->bittiming, &bt, sizeof(bt));
+
+		if (priv->do_set_bittiming) {
+			/* Finally, set the bit-timing registers */
+			err = priv->do_set_bittiming(dev);
+			if (err)
+				return err;
+		}
+	}
+
+	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 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 |= maskedflags;
+
+		/* CAN_CTRLMODE_FD can only be set when driver supports FD */
+		if (priv->ctrlmode & CAN_CTRLMODE_FD)
+			dev->mtu = CANFD_MTU;
+		else
+			dev->mtu = CAN_MTU;
+	}
+
+	if (data[IFLA_CAN_RESTART_MS]) {
+		/* Do not allow changing restart delay while running */
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+		priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
+	}
+
+	if (data[IFLA_CAN_RESTART]) {
+		/* Do not allow a restart while not running */
+		if (!(dev->flags & IFF_UP))
+			return -EINVAL;
+		err = can_restart_now(dev);
+		if (err)
+			return err;
+	}
+
+	if (data[IFLA_CAN_DATA_BITTIMING]) {
+		struct can_bittiming dbt;
+
+		/* Do not allow changing bittiming while running */
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+
+		/* Calculate bittiming parameters based on
+		 * data_bittiming_const if set, otherwise pass bitrate
+		 * directly via do_set_bitrate(). Bail out if neither
+		 * is given.
+		 */
+		if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
+			return -EOPNOTSUPP;
+
+		memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
+		       sizeof(dbt));
+		err = can_get_bittiming(dev, &dbt,
+					priv->data_bittiming_const,
+					priv->data_bitrate_const,
+					priv->data_bitrate_const_cnt);
+		if (err)
+			return err;
+
+		if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
+			netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
+				   priv->bitrate_max);
+			return -EINVAL;
+		}
+
+		memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
+
+		if (priv->do_set_data_bittiming) {
+			/* Finally, set the bit-timing registers */
+			err = priv->do_set_data_bittiming(dev);
+			if (err)
+				return err;
+		}
+	}
+
+	if (data[IFLA_CAN_TERMINATION]) {
+		const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
+		const unsigned int num_term = priv->termination_const_cnt;
+		unsigned int i;
+
+		if (!priv->do_set_termination)
+			return -EOPNOTSUPP;
+
+		/* check whether given value is supported by the interface */
+		for (i = 0; i < num_term; i++) {
+			if (termval == priv->termination_const[i])
+				break;
+		}
+		if (i >= num_term)
+			return -EINVAL;
+
+		/* Finally, set the termination value */
+		err = priv->do_set_termination(dev, termval);
+		if (err)
+			return err;
+
+		priv->termination = termval;
+	}
+
+	return 0;
+}
+
+static size_t can_get_size(const struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	size_t size = 0;
+
+	if (priv->bittiming.bitrate)				/* IFLA_CAN_BITTIMING */
+		size += nla_total_size(sizeof(struct can_bittiming));
+	if (priv->bittiming_const)				/* IFLA_CAN_BITTIMING_CONST */
+		size += nla_total_size(sizeof(struct can_bittiming_const));
+	size += nla_total_size(sizeof(struct can_clock));	/* IFLA_CAN_CLOCK */
+	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_STATE */
+	size += nla_total_size(sizeof(struct can_ctrlmode));	/* IFLA_CAN_CTRLMODE */
+	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_RESTART_MS */
+	if (priv->do_get_berr_counter)				/* IFLA_CAN_BERR_COUNTER */
+		size += nla_total_size(sizeof(struct can_berr_counter));
+	if (priv->data_bittiming.bitrate)			/* IFLA_CAN_DATA_BITTIMING */
+		size += nla_total_size(sizeof(struct can_bittiming));
+	if (priv->data_bittiming_const)				/* IFLA_CAN_DATA_BITTIMING_CONST */
+		size += nla_total_size(sizeof(struct can_bittiming_const));
+	if (priv->termination_const) {
+		size += nla_total_size(sizeof(priv->termination));		/* IFLA_CAN_TERMINATION */
+		size += nla_total_size(sizeof(*priv->termination_const) *	/* IFLA_CAN_TERMINATION_CONST */
+				       priv->termination_const_cnt);
+	}
+	if (priv->bitrate_const)				/* IFLA_CAN_BITRATE_CONST */
+		size += nla_total_size(sizeof(*priv->bitrate_const) *
+				       priv->bitrate_const_cnt);
+	if (priv->data_bitrate_const)				/* IFLA_CAN_DATA_BITRATE_CONST */
+		size += nla_total_size(sizeof(*priv->data_bitrate_const) *
+				       priv->data_bitrate_const_cnt);
+	size += sizeof(priv->bitrate_max);			/* IFLA_CAN_BITRATE_MAX */
+
+	return size;
+}
+
+static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+	struct can_ctrlmode cm = {.flags = priv->ctrlmode};
+	struct can_berr_counter bec = { };
+	enum can_state state = priv->state;
+
+	if (priv->do_get_state)
+		priv->do_get_state(dev, &state);
+
+	if ((priv->bittiming.bitrate &&
+	     nla_put(skb, IFLA_CAN_BITTIMING,
+		     sizeof(priv->bittiming), &priv->bittiming)) ||
+
+	    (priv->bittiming_const &&
+	     nla_put(skb, IFLA_CAN_BITTIMING_CONST,
+		     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
+
+	    nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
+	    nla_put_u32(skb, IFLA_CAN_STATE, state) ||
+	    nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
+	    nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
+
+	    (priv->do_get_berr_counter &&
+	     !priv->do_get_berr_counter(dev, &bec) &&
+	     nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
+
+	    (priv->data_bittiming.bitrate &&
+	     nla_put(skb, IFLA_CAN_DATA_BITTIMING,
+		     sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
+
+	    (priv->data_bittiming_const &&
+	     nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
+		     sizeof(*priv->data_bittiming_const),
+		     priv->data_bittiming_const)) ||
+
+	    (priv->termination_const &&
+	     (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
+	      nla_put(skb, IFLA_CAN_TERMINATION_CONST,
+		      sizeof(*priv->termination_const) *
+		      priv->termination_const_cnt,
+		      priv->termination_const))) ||
+
+	    (priv->bitrate_const &&
+	     nla_put(skb, IFLA_CAN_BITRATE_CONST,
+		     sizeof(*priv->bitrate_const) *
+		     priv->bitrate_const_cnt,
+		     priv->bitrate_const)) ||
+
+	    (priv->data_bitrate_const &&
+	     nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
+		     sizeof(*priv->data_bitrate_const) *
+		     priv->data_bitrate_const_cnt,
+		     priv->data_bitrate_const)) ||
+
+	    (nla_put(skb, IFLA_CAN_BITRATE_MAX,
+		     sizeof(priv->bitrate_max),
+		     &priv->bitrate_max))
+	    )
+
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static size_t can_get_xstats_size(const struct net_device *dev)
+{
+	return sizeof(struct can_device_stats);
+}
+
+static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	if (nla_put(skb, IFLA_INFO_XSTATS,
+		    sizeof(priv->can_stats), &priv->can_stats))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int can_newlink(struct net *src_net, struct net_device *dev,
+		       struct nlattr *tb[], struct nlattr *data[],
+		       struct netlink_ext_ack *extack)
+{
+	return -EOPNOTSUPP;
+}
+
+static void can_dellink(struct net_device *dev, struct list_head *head)
+{
+}
+
+static struct rtnl_link_ops can_link_ops __read_mostly = {
+	.kind		= "can",
+	.netns_refund	= true,
+	.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,
+	.fill_xstats	= can_fill_xstats,
+};
+
+/* Register the CAN network device */
+int register_candev(struct net_device *dev)
+{
+	struct can_priv *priv = netdev_priv(dev);
+
+	/* Ensure termination_const, termination_const_cnt and
+	 * do_set_termination consistency. All must be either set or
+	 * unset.
+	 */
+	if ((!priv->termination_const != !priv->termination_const_cnt) ||
+	    (!priv->termination_const != !priv->do_set_termination))
+		return -EINVAL;
+
+	if (!priv->bitrate_const != !priv->bitrate_const_cnt)
+		return -EINVAL;
+
+	if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
+		return -EINVAL;
+
+	dev->rtnl_link_ops = &can_link_ops;
+	netif_carrier_off(dev);
+
+	return register_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(register_candev);
+
+/* Unregister the CAN network device */
+void unregister_candev(struct net_device *dev)
+{
+	unregister_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_candev);
+
+/* Test if a network device is a candev based device
+ * and return the can_priv* if so.
+ */
+struct can_priv *safe_candev_priv(struct net_device *dev)
+{
+	if (dev->type != ARPHRD_CAN || dev->rtnl_link_ops != &can_link_ops)
+		return NULL;
+
+	return netdev_priv(dev);
+}
+EXPORT_SYMBOL_GPL(safe_candev_priv);
+
+static __init int can_dev_init(void)
+{
+	int err;
+
+	can_led_notifier_init();
+
+	err = rtnl_link_register(&can_link_ops);
+	if (!err)
+		pr_info(MOD_DESC "\n");
+
+	return err;
+}
+module_init(can_dev_init);
+
+static __exit void can_dev_exit(void)
+{
+	rtnl_link_unregister(&can_link_ops);
+
+	can_led_notifier_exit();
+}
+module_exit(can_dev_exit);
+
+MODULE_ALIAS_RTNL_LINK("can");
--- linux-ein-5.4.0.orig/drivers/net/can/dev/rx-offload.c
+++ linux-ein-5.4.0/drivers/net/can/dev/rx-offload.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2014      Protonic Holland,
+ *                         David Jander
+ * Copyright (C) 2014-2017 Pengutronix,
+ *                         Marc Kleine-Budde <kernel@pengutronix.de>
+ */
+
+#include <linux/can/dev.h>
+#include <linux/can/rx-offload.h>
+
+struct can_rx_offload_cb {
+	u32 timestamp;
+};
+
+static inline struct can_rx_offload_cb *
+can_rx_offload_get_cb(struct sk_buff *skb)
+{
+	BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
+
+	return (struct can_rx_offload_cb *)skb->cb;
+}
+
+static inline bool
+can_rx_offload_le(struct can_rx_offload *offload,
+		  unsigned int a, unsigned int b)
+{
+	if (offload->inc)
+		return a <= b;
+	else
+		return a >= b;
+}
+
+static inline unsigned int
+can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
+{
+	if (offload->inc)
+		return (*val)++;
+	else
+		return (*val)--;
+}
+
+static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
+{
+	struct can_rx_offload *offload = container_of(napi,
+						      struct can_rx_offload,
+						      napi);
+	struct net_device *dev = offload->dev;
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	int work_done = 0;
+
+	while ((work_done < quota) &&
+	       (skb = skb_dequeue(&offload->skb_queue))) {
+		struct can_frame *cf = (struct can_frame *)skb->data;
+
+		work_done++;
+		stats->rx_packets++;
+		stats->rx_bytes += cf->can_dlc;
+		netif_receive_skb(skb);
+	}
+
+	if (work_done < quota) {
+		napi_complete_done(napi, work_done);
+
+		/* Check if there was another interrupt */
+		if (!skb_queue_empty(&offload->skb_queue))
+			napi_reschedule(&offload->napi);
+	}
+
+	can_led_event(offload->dev, CAN_LED_EVENT_RX);
+
+	return work_done;
+}
+
+static inline void
+__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
+		     int (*compare)(struct sk_buff *a, struct sk_buff *b))
+{
+	struct sk_buff *pos, *insert = NULL;
+
+	skb_queue_reverse_walk(head, pos) {
+		const struct can_rx_offload_cb *cb_pos, *cb_new;
+
+		cb_pos = can_rx_offload_get_cb(pos);
+		cb_new = can_rx_offload_get_cb(new);
+
+		netdev_dbg(new->dev,
+			   "%s: pos=0x%08x, new=0x%08x, diff=%10d, queue_len=%d\n",
+			   __func__,
+			   cb_pos->timestamp, cb_new->timestamp,
+			   cb_new->timestamp - cb_pos->timestamp,
+			   skb_queue_len(head));
+
+		if (compare(pos, new) < 0)
+			continue;
+		insert = pos;
+		break;
+	}
+	if (!insert)
+		__skb_queue_head(head, new);
+	else
+		__skb_queue_after(head, insert, new);
+}
+
+static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
+{
+	const struct can_rx_offload_cb *cb_a, *cb_b;
+
+	cb_a = can_rx_offload_get_cb(a);
+	cb_b = can_rx_offload_get_cb(b);
+
+	/* Subtract two u32 and return result as int, to keep
+	 * difference steady around the u32 overflow.
+	 */
+	return cb_b->timestamp - cb_a->timestamp;
+}
+
+/**
+ * can_rx_offload_offload_one() - Read one CAN frame from HW
+ * @offload: pointer to rx_offload context
+ * @n: number of mailbox to read
+ *
+ * The task of this function is to read a CAN frame from mailbox @n
+ * from the device and return the mailbox's content as a struct
+ * sk_buff.
+ *
+ * If the struct can_rx_offload::skb_queue exceeds the maximal queue
+ * length (struct can_rx_offload::skb_queue_len_max) or no skb can be
+ * allocated, the mailbox contents is discarded by reading it into an
+ * overflow buffer. This way the mailbox is marked as free by the
+ * driver.
+ *
+ * Return: A pointer to skb containing the CAN frame on success.
+ *
+ *         NULL if the mailbox @n is empty.
+ *
+ *         ERR_PTR() in case of an error
+ */
+static struct sk_buff *
+can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
+{
+	struct sk_buff *skb;
+	struct can_rx_offload_cb *cb;
+	bool drop = false;
+	u32 timestamp;
+
+	/* If queue is full drop frame */
+	if (unlikely(skb_queue_len(&offload->skb_queue) >
+		     offload->skb_queue_len_max))
+		drop = true;
+
+	skb = offload->mailbox_read(offload, n, &timestamp, drop);
+	/* Mailbox was empty. */
+	if (unlikely(!skb))
+		return NULL;
+
+	/* There was a problem reading the mailbox, propagate
+	 * error value.
+	 */
+	if (unlikely(IS_ERR(skb))) {
+		offload->dev->stats.rx_dropped++;
+		offload->dev->stats.rx_fifo_errors++;
+
+		return skb;
+	}
+
+	/* Mailbox was read. */
+	cb = can_rx_offload_get_cb(skb);
+	cb->timestamp = timestamp;
+
+	return skb;
+}
+
+int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
+					 u64 pending)
+{
+	struct sk_buff_head skb_queue;
+	unsigned int i;
+
+	__skb_queue_head_init(&skb_queue);
+
+	for (i = offload->mb_first;
+	     can_rx_offload_le(offload, i, offload->mb_last);
+	     can_rx_offload_inc(offload, &i)) {
+		struct sk_buff *skb;
+
+		if (!(pending & BIT_ULL(i)))
+			continue;
+
+		skb = can_rx_offload_offload_one(offload, i);
+		if (IS_ERR_OR_NULL(skb))
+			continue;
+
+		__skb_queue_add_sort(&skb_queue, skb, can_rx_offload_compare);
+	}
+
+	if (!skb_queue_empty(&skb_queue)) {
+		unsigned long flags;
+		u32 queue_len;
+
+		spin_lock_irqsave(&offload->skb_queue.lock, flags);
+		skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
+		spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
+
+		queue_len = skb_queue_len(&offload->skb_queue);
+		if (queue_len > offload->skb_queue_len_max / 8)
+			netdev_dbg(offload->dev, "%s: queue_len=%d\n",
+				   __func__, queue_len);
+
+		can_rx_offload_schedule(offload);
+	}
+
+	return skb_queue_len(&skb_queue);
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
+
+int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
+{
+	struct sk_buff *skb;
+	int received = 0;
+
+	while (1) {
+		skb = can_rx_offload_offload_one(offload, 0);
+		if (IS_ERR(skb))
+			continue;
+		if (!skb)
+			break;
+
+		skb_queue_tail(&offload->skb_queue, skb);
+		received++;
+	}
+
+	if (received)
+		can_rx_offload_schedule(offload);
+
+	return received;
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
+
+int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
+				struct sk_buff *skb, u32 timestamp)
+{
+	struct can_rx_offload_cb *cb;
+	unsigned long flags;
+
+	if (skb_queue_len(&offload->skb_queue) >
+	    offload->skb_queue_len_max) {
+		dev_kfree_skb_any(skb);
+		return -ENOBUFS;
+	}
+
+	cb = can_rx_offload_get_cb(skb);
+	cb->timestamp = timestamp;
+
+	spin_lock_irqsave(&offload->skb_queue.lock, flags);
+	__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
+	spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
+
+	can_rx_offload_schedule(offload);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
+
+unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
+					 unsigned int idx, u32 timestamp)
+{
+	struct net_device *dev = offload->dev;
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	u8 len;
+	int err;
+
+	skb = __can_get_echo_skb(dev, idx, &len);
+	if (!skb)
+		return 0;
+
+	err = can_rx_offload_queue_sorted(offload, skb, timestamp);
+	if (err) {
+		stats->rx_errors++;
+		stats->tx_fifo_errors++;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);
+
+int can_rx_offload_queue_tail(struct can_rx_offload *offload,
+			      struct sk_buff *skb)
+{
+	if (skb_queue_len(&offload->skb_queue) >
+	    offload->skb_queue_len_max) {
+		dev_kfree_skb_any(skb);
+		return -ENOBUFS;
+	}
+
+	skb_queue_tail(&offload->skb_queue, skb);
+	can_rx_offload_schedule(offload);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
+
+static int can_rx_offload_init_queue(struct net_device *dev,
+				     struct can_rx_offload *offload,
+				     unsigned int weight)
+{
+	offload->dev = dev;
+
+	/* Limit queue len to 4x the weight (rounted to next power of two) */
+	offload->skb_queue_len_max = 2 << fls(weight);
+	offload->skb_queue_len_max *= 4;
+	skb_queue_head_init(&offload->skb_queue);
+
+	netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
+
+	dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
+		__func__, offload->skb_queue_len_max);
+
+	return 0;
+}
+
+int can_rx_offload_add_timestamp(struct net_device *dev,
+				 struct can_rx_offload *offload)
+{
+	unsigned int weight;
+
+	if (offload->mb_first > BITS_PER_LONG_LONG ||
+	    offload->mb_last > BITS_PER_LONG_LONG || !offload->mailbox_read)
+		return -EINVAL;
+
+	if (offload->mb_first < offload->mb_last) {
+		offload->inc = true;
+		weight = offload->mb_last - offload->mb_first;
+	} else {
+		offload->inc = false;
+		weight = offload->mb_first - offload->mb_last;
+	}
+
+	return can_rx_offload_init_queue(dev, offload, weight);
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
+
+int can_rx_offload_add_fifo(struct net_device *dev,
+			    struct can_rx_offload *offload, unsigned int weight)
+{
+	if (!offload->mailbox_read)
+		return -EINVAL;
+
+	return can_rx_offload_init_queue(dev, offload, weight);
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
+
+void can_rx_offload_enable(struct can_rx_offload *offload)
+{
+	napi_enable(&offload->napi);
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_enable);
+
+void can_rx_offload_del(struct can_rx_offload *offload)
+{
+	netif_napi_del(&offload->napi);
+	skb_queue_purge(&offload->skb_queue);
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_del);
--- linux-ein-5.4.0.orig/drivers/net/can/flexcan.c
+++ linux-ein-5.4.0/drivers/net/can/flexcan.c
@@ -9,7 +9,7 @@
 //
 // Based on code originally by Andrey Volkov <avolkov@varma-el.com>
 
-#include <linux/netdevice.h>
+#include <linux/bitfield.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
@@ -21,12 +21,14 @@
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
+#include <linux/netdevice.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #define DRV_NAME			"flexcan"
 
@@ -52,6 +54,7 @@
 #define FLEXCAN_MCR_IRMQ		BIT(16)
 #define FLEXCAN_MCR_LPRIO_EN		BIT(13)
 #define FLEXCAN_MCR_AEN			BIT(12)
+#define FLEXCAN_MCR_FDEN		BIT(11)
 /* MCR_MAXMB: maximum used MBs is MAXMB + 1 */
 #define FLEXCAN_MCR_MAXMB(x)		((x) & 0x7f)
 #define FLEXCAN_MCR_IDAM_A		(0x0 << 8)
@@ -91,6 +94,7 @@
 #define FLEXCAN_CTRL2_MRP		BIT(18)
 #define FLEXCAN_CTRL2_RRS		BIT(17)
 #define FLEXCAN_CTRL2_EACEN		BIT(16)
+#define FLEXCAN_CTRL2_ISOCANFDEN	BIT(12)
 
 /* FLEXCAN memory error control register (MECR) bits */
 #define FLEXCAN_MECR_ECRWRDIS		BIT(31)
@@ -134,15 +138,42 @@
 	(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
 #define FLEXCAN_ESR_ALL_INT \
 	(FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
-	 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
-	 FLEXCAN_ESR_WAK_INT)
+	 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
+
+/* FLEXCAN Bit Timing register (CBT) bits */
+#define FLEXCAN_CBT_BTF			BIT(31)
+#define FLEXCAN_CBT_EPRESDIV_MASK	GENMASK(30, 21)
+#define FLEXCAN_CBT_ERJW_MASK		GENMASK(20, 16)
+#define FLEXCAN_CBT_EPROPSEG_MASK	GENMASK(15, 10)
+#define FLEXCAN_CBT_EPSEG1_MASK		GENMASK(9, 5)
+#define FLEXCAN_CBT_EPSEG2_MASK		GENMASK(4, 0)
+
+/* FLEXCAN FD control register (FDCTRL) bits */
+#define FLEXCAN_FDCTRL_FDRATE		BIT(31)
+#define FLEXCAN_FDCTRL_MBDSR1		GENMASK(20, 19)
+#define FLEXCAN_FDCTRL_MBDSR0		GENMASK(17, 16)
+#define FLEXCAN_FDCTRL_MBDSR_8		0x0
+#define FLEXCAN_FDCTRL_MBDSR_12		0x1
+#define FLEXCAN_FDCTRL_MBDSR_32		0x2
+#define FLEXCAN_FDCTRL_MBDSR_64		0x3
+#define FLEXCAN_FDCTRL_TDCEN		BIT(15)
+#define FLEXCAN_FDCTRL_TDCFAIL		BIT(14)
+#define FLEXCAN_FDCTRL_TDCOFF		GENMASK(12, 8)
+#define FLEXCAN_FDCTRL_TDCVAL		GENMASK(5, 0)
+
+/* FLEXCAN FD Bit Timing register (FDCBT) bits */
+#define FLEXCAN_FDCBT_FPRESDIV_MASK	GENMASK(29, 20)
+#define FLEXCAN_FDCBT_FRJW_MASK		GENMASK(18, 16)
+#define FLEXCAN_FDCBT_FPROPSEG_MASK	GENMASK(14, 10)
+#define FLEXCAN_FDCBT_FPSEG1_MASK	GENMASK(7, 5)
+#define FLEXCAN_FDCBT_FPSEG2_MASK	GENMASK(2, 0)
 
 /* FLEXCAN interrupt flag register (IFLAG) bits */
 /* Errata ERR005829 step7: Reserve first valid MB */
 #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO		8
 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP	0
 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST	(FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
-#define FLEXCAN_IFLAG_MB(x)		BIT((x) & 0x1f)
+#define FLEXCAN_IFLAG_MB(x)		BIT_ULL(x)
 #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7)
 #define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6)
 #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE	BIT(5)
@@ -161,6 +192,9 @@
 #define FLEXCAN_MB_CODE_TX_DATA		(0xc << 24)
 #define FLEXCAN_MB_CODE_TX_TANSWER	(0xe << 24)
 
+#define FLEXCAN_MB_CNT_EDL		BIT(31)
+#define FLEXCAN_MB_CNT_BRS		BIT(30)
+#define FLEXCAN_MB_CNT_ESI		BIT(29)
 #define FLEXCAN_MB_CNT_SRR		BIT(22)
 #define FLEXCAN_MB_CNT_IDE		BIT(21)
 #define FLEXCAN_MB_CNT_RTR		BIT(20)
@@ -172,26 +206,42 @@
 /* FLEXCAN hardware feature flags
  *
  * Below is some version info we got:
- *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR re-
- *                                Filter? connected?  Passive detection  ception in MB
- *   MX25  FlexCAN2  03.00.00.00     no        no        no       no        no
- *   MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no
- *   MX35  FlexCAN2  03.00.00.00     no        no        no       no        no
- *   MX53  FlexCAN2  03.00.00.00    yes        no        no       no        no
- *   MX6s  FlexCAN3  10.00.12.00    yes       yes        no       no       yes
- *   VF610 FlexCAN3  ?               no       yes        no      yes       yes?
- * LS1021A FlexCAN2  03.00.04.00     no       yes        no       no       yes
+ *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece-   FD Mode
+ *                                Filter? connected?  Passive detection  ption in MB Supported?
+ *   MX25  FlexCAN2  03.00.00.00     no        no        no       no        no           no
+ *   MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no           no
+ *   MX35  FlexCAN2  03.00.00.00     no        no        no       no        no           no
+ *   MX53  FlexCAN2  03.00.00.00    yes        no        no       no        no           no
+ *   MX6s  FlexCAN3  10.00.12.00    yes       yes        no       no       yes           no
+ *   MX8QM FlexCAN3  03.00.23.00    yes       yes        no       no       yes          yes
+ *   MX8MP FlexCAN3  03.00.17.01    yes       yes        no      yes       yes          yes
+ *   VF610 FlexCAN3  ?               no       yes        no      yes       yes?          no
+ * LS1021A FlexCAN2  03.00.04.00     no       yes        no       no       yes           no
+ * LX2160A FlexCAN3  03.00.23.00     no       yes        no       no       yes          yes
  *
  * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
  */
-#define FLEXCAN_QUIRK_BROKEN_WERR_STATE	BIT(1) /* [TR]WRN_INT not connected */
-#define FLEXCAN_QUIRK_DISABLE_RXFG	BIT(2) /* Disable RX FIFO Global mask */
-#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS	BIT(3) /* Enable EACEN and RRS bit in ctrl2 */
-#define FLEXCAN_QUIRK_DISABLE_MECR	BIT(4) /* Disable Memory error detection */
-#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP	BIT(5) /* Use timestamp based offloading */
-#define FLEXCAN_QUIRK_BROKEN_PERR_STATE	BIT(6) /* No interrupt for error passive */
-#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN	BIT(7) /* default to BE register access */
-#define FLEXCAN_QUIRK_SETUP_STOP_MODE		BIT(8) /* Setup stop mode to support wakeup */
+
+/* [TR]WRN_INT not connected */
+#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1)
+ /* Disable RX FIFO Global mask */
+#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2)
+/* Enable EACEN and RRS bit in ctrl2 */
+#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS  BIT(3)
+/* Disable non-correctable errors interrupt and freeze mode */
+#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4)
+/* Use timestamp based offloading */
+#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5)
+/* No interrupt for error passive */
+#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6)
+/* default to BE register access */
+#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7)
+/* Setup stop mode to support wakeup */
+#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8)
+/* Support CAN-FD mode */
+#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9)
+/* support memory detection and correction */
+#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10)
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -203,12 +253,12 @@
 /* Structure of the hardware registers */
 struct flexcan_regs {
 	u32 mcr;		/* 0x00 */
-	u32 ctrl;		/* 0x04 */
+	u32 ctrl;		/* 0x04 - Not affected by Soft Reset */
 	u32 timer;		/* 0x08 */
-	u32 _reserved1;		/* 0x0c */
-	u32 rxgmask;		/* 0x10 */
-	u32 rx14mask;		/* 0x14 */
-	u32 rx15mask;		/* 0x18 */
+	u32 tcr;		/* 0x0c */
+	u32 rxgmask;		/* 0x10 - Not affected by Soft Reset */
+	u32 rx14mask;		/* 0x14 - Not affected by Soft Reset */
+	u32 rx15mask;		/* 0x18 - Not affected by Soft Reset */
 	u32 ecr;		/* 0x1c */
 	u32 esr;		/* 0x20 */
 	u32 imask2;		/* 0x24 */
@@ -217,20 +267,24 @@
 	u32 iflag1;		/* 0x30 */
 	union {			/* 0x34 */
 		u32 gfwr_mx28;	/* MX28, MX53 */
-		u32 ctrl2;	/* MX6, VF610 */
+		u32 ctrl2;	/* MX6, VF610 - Not affected by Soft Reset */
 	};
 	u32 esr2;		/* 0x38 */
 	u32 imeur;		/* 0x3c */
 	u32 lrfr;		/* 0x40 */
 	u32 crcr;		/* 0x44 */
 	u32 rxfgmask;		/* 0x48 */
-	u32 rxfir;		/* 0x4c */
-	u32 _reserved3[12];	/* 0x50 */
-	u8 mb[2][512];		/* 0x80 */
+	u32 rxfir;		/* 0x4c - Not affected by Soft Reset */
+	u32 cbt;		/* 0x50 - Not affected by Soft Reset */
+	u32 _reserved2;		/* 0x54 */
+	u32 dbg1;		/* 0x58 */
+	u32 dbg2;		/* 0x5c */
+	u32 _reserved3[8];	/* 0x60 */
+	u8 mb[2][512];		/* 0x80 - Not affected by Soft Reset */
 	/* FIFO-mode:
 	 *			MB
 	 * 0x080...0x08f	0	RX message buffer
-	 * 0x090...0x0df	1-5	reserverd
+	 * 0x090...0x0df	1-5	reserved
 	 * 0x0e0...0x0ff	6-7	8 entry ID table
 	 *				(mx25, mx28, mx35, mx53)
 	 * 0x0e0...0x2df	6-7..37	8..128 entry ID table
@@ -238,10 +292,19 @@
 	 *				(mx6, vf610)
 	 */
 	u32 _reserved4[256];	/* 0x480 */
-	u32 rximr[64];		/* 0x880 */
+	u32 rximr[64];		/* 0x880 - Not affected by Soft Reset */
 	u32 _reserved5[24];	/* 0x980 */
 	u32 gfwr_mx6;		/* 0x9e0 - MX6 */
-	u32 _reserved6[63];	/* 0x9e4 */
+	u32 _reserved6[39];	/* 0x9e4 */
+	u32 _rxfir[6];		/* 0xa80 */
+	u32 _reserved8[2];	/* 0xa98 */
+	u32 _rxmgmask;		/* 0xaa0 */
+	u32 _rxfgmask;		/* 0xaa4 */
+	u32 _rx14mask;		/* 0xaa8 */
+	u32 _rx15mask;		/* 0xaac */
+	u32 tx_smb[4];		/* 0xab0 */
+	u32 rx_smb0[4];		/* 0xac0 */
+	u32 rx_smb1[4];		/* 0xad0 */
 	u32 mecr;		/* 0xae0 */
 	u32 erriar;		/* 0xae4 */
 	u32 erridpr;		/* 0xae8 */
@@ -250,8 +313,18 @@
 	u32 rerrdr;		/* 0xaf4 */
 	u32 rerrsynr;		/* 0xaf8 */
 	u32 errsr;		/* 0xafc */
+	u32 _reserved7[64];	/* 0xb00 */
+	u32 fdctrl;		/* 0xc00 - Not affected by Soft Reset */
+	u32 fdcbt;		/* 0xc04 - Not affected by Soft Reset */
+	u32 fdcrc;		/* 0xc08 */
+	u32 _reserved9[199];	/* 0xc0c */
+	u32 tx_smb_fd[18];	/* 0xf28 */
+	u32 rx_smb0_fd[18];	/* 0xf70 */
+	u32 rx_smb1_fd[18];	/* 0xfb8 */
 };
 
+static_assert(sizeof(struct flexcan_regs) ==  0x4 * 18 + 0xfb8);
+
 struct flexcan_devtype_data {
 	u32 quirks;		/* quirks needed for different IP cores */
 };
@@ -260,8 +333,6 @@
 	struct regmap *gpr;
 	u8 req_gpr;
 	u8 req_bit;
-	u8 ack_gpr;
-	u8 ack_bit;
 };
 
 struct flexcan_priv {
@@ -277,9 +348,9 @@
 	u8 mb_size;
 	u8 clk_src;	/* clock source of CAN Protocol Engine */
 
+	u64 rx_mask;
+	u64 tx_mask;
 	u32 reg_ctrl_default;
-	u32 reg_imask1_default;
-	u32 reg_imask2_default;
 
 	struct clk *clk_ipg;
 	struct clk *clk_per;
@@ -313,6 +384,19 @@
 		FLEXCAN_QUIRK_SETUP_STOP_MODE,
 };
 
+static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
+	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+		FLEXCAN_QUIRK_SUPPORT_FD,
+};
+
+static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
+	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+		FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
+		FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE |
+		FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC,
+};
+
 static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 		FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
@@ -321,8 +405,13 @@
 
 static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+		FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
+};
+
+static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
+	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 		FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
-		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
+		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_SUPPORT_FD,
 };
 
 static const struct can_bittiming_const flexcan_bittiming_const = {
@@ -337,6 +426,30 @@
 	.brp_inc = 1,
 };
 
+static const struct can_bittiming_const flexcan_fd_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 2,
+	.tseg1_max = 96,
+	.tseg2_min = 2,
+	.tseg2_max = 32,
+	.sjw_max = 16,
+	.brp_min = 1,
+	.brp_max = 1024,
+	.brp_inc = 1,
+};
+
+static const struct can_bittiming_const flexcan_fd_data_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 2,
+	.tseg1_max = 39,
+	.tseg2_min = 2,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 1024,
+	.brp_inc = 1,
+};
+
 /* FlexCAN module is essentially modelled as a little-endian IP in most
  * SoCs, i.e the registers as well as the message buffer areas are
  * implemented in a little-endian fashion.
@@ -389,6 +502,34 @@
 		(&priv->regs->mb[bank][priv->mb_size * mb_index]);
 }
 
+static int flexcan_low_power_enter_ack(struct flexcan_priv *priv)
+{
+	struct flexcan_regs __iomem *regs = priv->regs;
+	unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+	while (timeout-- && !(priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+		udelay(10);
+
+	if (!(priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int flexcan_low_power_exit_ack(struct flexcan_priv *priv)
+{
+	struct flexcan_regs __iomem *regs = priv->regs;
+	unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+	while (timeout-- && (priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+		udelay(10);
+
+	if (priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
 static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
@@ -407,7 +548,6 @@
 static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	unsigned int ackval;
 	u32 reg_mcr;
 
 	reg_mcr = priv->read(&regs->mcr);
@@ -418,36 +558,23 @@
 	regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 			   1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
 
-	/* get stop acknowledgment */
-	if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
-				     ackval, ackval & (1 << priv->stm.ack_bit),
-				     0, FLEXCAN_TIMEOUT_US))
-		return -ETIMEDOUT;
-
-	return 0;
+	return flexcan_low_power_enter_ack(priv);
 }
 
 static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	unsigned int ackval;
 	u32 reg_mcr;
 
 	/* remove stop request */
 	regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 			   1 << priv->stm.req_bit, 0);
 
-	/* get stop acknowledgment */
-	if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
-				     ackval, !(ackval & (1 << priv->stm.ack_bit)),
-				     0, FLEXCAN_TIMEOUT_US))
-		return -ETIMEDOUT;
-
 	reg_mcr = priv->read(&regs->mcr);
 	reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
 	priv->write(reg_mcr, &regs->mcr);
 
-	return 0;
+	return flexcan_low_power_exit_ack(priv);
 }
 
 static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
@@ -506,49 +633,41 @@
 static int flexcan_chip_enable(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
 	u32 reg;
 
 	reg = priv->read(&regs->mcr);
 	reg &= ~FLEXCAN_MCR_MDIS;
 	priv->write(reg, &regs->mcr);
 
-	while (timeout-- && (priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
-		udelay(10);
-
-	if (priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
-		return -ETIMEDOUT;
-
-	return 0;
+	return flexcan_low_power_exit_ack(priv);
 }
 
 static int flexcan_chip_disable(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
 	u32 reg;
 
 	reg = priv->read(&regs->mcr);
 	reg |= FLEXCAN_MCR_MDIS;
 	priv->write(reg, &regs->mcr);
 
-	while (timeout-- && !(priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
-		udelay(10);
-
-	if (!(priv->read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
-		return -ETIMEDOUT;
-
-	return 0;
+	return flexcan_low_power_enter_ack(priv);
 }
 
 static int flexcan_chip_freeze(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+	unsigned int timeout;
+	u32 bitrate = priv->can.bittiming.bitrate;
 	u32 reg;
 
+	if (bitrate)
+		timeout = 1000 * 1000 * 10 / bitrate;
+	else
+		timeout = FLEXCAN_TIMEOUT_US / 10;
+
 	reg = priv->read(&regs->mcr);
-	reg |= FLEXCAN_MCR_HALT;
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT;
 	priv->write(reg, &regs->mcr);
 
 	while (timeout-- && !(priv->read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
@@ -614,8 +733,10 @@
 	int err;
 
 	err = pm_runtime_get_sync(priv->dev);
-	if (err < 0)
+	if (err < 0) {
+		pm_runtime_put_noidle(priv->dev);
 		return err;
+	}
 
 	err = __flexcan_get_berr_counter(dev, bec);
 
@@ -627,10 +748,10 @@
 static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	const struct flexcan_priv *priv = netdev_priv(dev);
-	struct can_frame *cf = (struct can_frame *)skb->data;
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
 	u32 can_id;
 	u32 data;
-	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
+	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16);
 	int i;
 
 	if (can_dropped_invalid_skb(dev, skb))
@@ -638,18 +759,25 @@
 
 	netif_stop_queue(dev);
 
-	if (cf->can_id & CAN_EFF_FLAG) {
-		can_id = cf->can_id & CAN_EFF_MASK;
+	if (cfd->can_id & CAN_EFF_FLAG) {
+		can_id = cfd->can_id & CAN_EFF_MASK;
 		ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
 	} else {
-		can_id = (cf->can_id & CAN_SFF_MASK) << 18;
+		can_id = (cfd->can_id & CAN_SFF_MASK) << 18;
 	}
 
-	if (cf->can_id & CAN_RTR_FLAG)
+	if (cfd->can_id & CAN_RTR_FLAG)
 		ctrl |= FLEXCAN_MB_CNT_RTR;
 
-	for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
-		data = be32_to_cpup((__be32 *)&cf->data[i]);
+	if (can_is_canfd_skb(skb)) {
+		ctrl |= FLEXCAN_MB_CNT_EDL;
+
+		if (cfd->flags & CANFD_BRS)
+			ctrl |= FLEXCAN_MB_CNT_BRS;
+	}
+
+	for (i = 0; i < cfd->len; i += sizeof(u32)) {
+		data = be32_to_cpup((__be32 *)&cfd->data[i]);
 		priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
 	}
 
@@ -743,8 +871,6 @@
 	u32 timestamp;
 	int err;
 
-	timestamp = priv->read(&regs->timer) << 16;
-
 	flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
 	if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
 		tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
@@ -764,6 +890,8 @@
 	if (likely(new_state == priv->can.state))
 		return;
 
+	timestamp = priv->read(&regs->timer) << 16;
+
 	skb = alloc_can_err_skb(dev, &cf);
 	if (unlikely(!skb))
 		return;
@@ -778,21 +906,58 @@
 		dev->stats.rx_fifo_errors++;
 }
 
+static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask)
+{
+	u64 reg = 0;
+
+	if (upper_32_bits(mask))
+		reg = (u64)priv->read(addr - 4) << 32;
+	if (lower_32_bits(mask))
+		reg |= priv->read(addr);
+
+	return reg & mask;
+}
+
+static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr)
+{
+	if (upper_32_bits(val))
+		priv->write(upper_32_bits(val), addr - 4);
+	if (lower_32_bits(val))
+		priv->write(lower_32_bits(val), addr);
+}
+
+static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+{
+	return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
+}
+
+static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
+{
+	return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
+}
+
 static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
 {
 	return container_of(offload, struct flexcan_priv, offload);
 }
 
-static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
-					 struct can_frame *cf,
-					 u32 *timestamp, unsigned int n)
+static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
+					    unsigned int n, u32 *timestamp,
+					    bool drop)
 {
 	struct flexcan_priv *priv = rx_offload_to_priv(offload);
 	struct flexcan_regs __iomem *regs = priv->regs;
 	struct flexcan_mb __iomem *mb;
+	struct sk_buff *skb;
+	struct canfd_frame *cfd;
 	u32 reg_ctrl, reg_id, reg_iflag1;
 	int i;
 
+	if (unlikely(drop)) {
+		skb = ERR_PTR(-ENOBUFS);
+		goto mark_as_read;
+	}
+
 	mb = flexcan_get_mb(priv, n);
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
@@ -806,7 +971,7 @@
 		code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
 		if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
 		    (code != FLEXCAN_MB_CODE_RX_OVERRUN))
-			return 0;
+			return NULL;
 
 		if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
 			/* This MB was overrun, we lost data */
@@ -816,39 +981,54 @@
 	} else {
 		reg_iflag1 = priv->read(&regs->iflag1);
 		if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE))
-			return 0;
+			return NULL;
 
 		reg_ctrl = priv->read(&mb->can_ctrl);
 	}
 
+	if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
+		skb = alloc_canfd_skb(offload->dev, &cfd);
+	else
+		skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd);
+	if (unlikely(!skb)) {
+		skb = ERR_PTR(-ENOMEM);
+		goto mark_as_read;
+	}
+
 	/* increase timstamp to full 32 bit */
 	*timestamp = reg_ctrl << 16;
 
 	reg_id = priv->read(&mb->can_id);
 	if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
-		cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+		cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
 	else
-		cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+		cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+	if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
+		cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
 
-	if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
-		cf->can_id |= CAN_RTR_FLAG;
-	cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+		if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+			cfd->flags |= CANFD_BRS;
+	} else {
+		cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
 
-	for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
+		if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+			cfd->can_id |= CAN_RTR_FLAG;
+	}
+
+	if (reg_ctrl & FLEXCAN_MB_CNT_ESI)
+		cfd->flags |= CANFD_ESI;
+
+	for (i = 0; i < cfd->len; i += sizeof(u32)) {
 		__be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
-		*(__be32 *)(cf->data + i) = data;
+		*(__be32 *)(cfd->data + i) = data;
 	}
 
-	/* mark as read */
-	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
-		/* Clear IRQ */
-		if (n < 32)
-			priv->write(BIT(n), &regs->iflag1);
-		else
-			priv->write(BIT(n - 32), &regs->iflag2);
-	} else {
+ mark_as_read:
+	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
+		flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), &regs->iflag1);
+	else
 		priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
-	}
 
 	/* Read the Free Running Timer. It is optional but recommended
 	 * to unlock Mailbox as soon as possible and make it available
@@ -856,20 +1036,7 @@
 	 */
 	priv->read(&regs->timer);
 
-	return 1;
-}
-
-
-static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
-{
-	struct flexcan_regs __iomem *regs = priv->regs;
-	u32 iflag1, iflag2;
-
-	iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
-		~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
-	iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
-
-	return (u64)iflag2 << 32 | iflag1;
+	return skb;
 }
 
 static irqreturn_t flexcan_irq(int irq, void *dev_id)
@@ -879,18 +1046,19 @@
 	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->regs;
 	irqreturn_t handled = IRQ_NONE;
-	u32 reg_iflag2, reg_esr;
+	u64 reg_iflag_tx;
+	u32 reg_esr;
 	enum can_state last_state = priv->can.state;
 
 	/* reception interrupt */
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
-		u64 reg_iflag;
+		u64 reg_iflag_rx;
 		int ret;
 
-		while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) {
+		while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
 			handled = IRQ_HANDLED;
 			ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
-								   reg_iflag);
+								   reg_iflag_rx);
 			if (!ret)
 				break;
 		}
@@ -913,10 +1081,10 @@
 		}
 	}
 
-	reg_iflag2 = priv->read(&regs->iflag2);
+	reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
 
 	/* transmission complete interrupt */
-	if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
+	if (reg_iflag_tx & priv->tx_mask) {
 		u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
 
 		handled = IRQ_HANDLED;
@@ -928,16 +1096,16 @@
 		/* after sending a RTR frame MB is in RX mode */
 		priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
 			    &priv->tx_mb->can_ctrl);
-		priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2);
+		flexcan_write64(priv, priv->tx_mask, &regs->iflag1);
 		netif_wake_queue(dev);
 	}
 
 	reg_esr = priv->read(&regs->esr);
 
-	/* ACK all bus error and state change IRQ sources */
-	if (reg_esr & FLEXCAN_ESR_ALL_INT) {
+	/* ACK all bus error, state change and wake IRQ sources */
+	if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) {
 		handled = IRQ_HANDLED;
-		priv->write(reg_esr & FLEXCAN_ESR_ALL_INT, &regs->esr);
+		priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), &regs->esr);
 	}
 
 	/* state change interrupt or broken error state quirk fix is enabled */
@@ -992,7 +1160,7 @@
 	return handled;
 }
 
-static void flexcan_set_bittiming(struct net_device *dev)
+static void flexcan_set_bittiming_ctrl(const struct net_device *dev)
 {
 	const struct flexcan_priv *priv = netdev_priv(dev);
 	const struct can_bittiming *bt = &priv->can.bittiming;
@@ -1004,10 +1172,7 @@
 		 FLEXCAN_CTRL_RJW(0x3) |
 		 FLEXCAN_CTRL_PSEG1(0x7) |
 		 FLEXCAN_CTRL_PSEG2(0x7) |
-		 FLEXCAN_CTRL_PROPSEG(0x7) |
-		 FLEXCAN_CTRL_LPB |
-		 FLEXCAN_CTRL_SMP |
-		 FLEXCAN_CTRL_LOM);
+		 FLEXCAN_CTRL_PROPSEG(0x7));
 
 	reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
 		FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
@@ -1015,6 +1180,130 @@
 		FLEXCAN_CTRL_RJW(bt->sjw - 1) |
 		FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
 
+	netdev_dbg(dev, "writing ctrl=0x%08x\n", reg);
+	priv->write(reg, &regs->ctrl);
+
+	/* print chip status */
+	netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+		   priv->read(&regs->mcr), priv->read(&regs->ctrl));
+}
+
+static void flexcan_set_bittiming_cbt(const struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct can_bittiming *dbt = &priv->can.data_bittiming;
+	struct flexcan_regs __iomem *regs = priv->regs;
+	u32 reg_cbt, reg_fdctrl;
+
+	/* CBT */
+	/* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit
+	 * long. The can_calc_bittiming() tries to divide the tseg1
+	 * equally between phase_seg1 and prop_seg, which may not fit
+	 * in CBT register. Therefore, if phase_seg1 is more than
+	 * possible value, increase prop_seg and decrease phase_seg1.
+	 */
+	if (bt->phase_seg1 > 0x20) {
+		bt->prop_seg += (bt->phase_seg1 - 0x20);
+		bt->phase_seg1 = 0x20;
+	}
+
+	reg_cbt = FLEXCAN_CBT_BTF |
+		FIELD_PREP(FLEXCAN_CBT_EPRESDIV_MASK, bt->brp - 1) |
+		FIELD_PREP(FLEXCAN_CBT_ERJW_MASK, bt->sjw - 1) |
+		FIELD_PREP(FLEXCAN_CBT_EPROPSEG_MASK, bt->prop_seg - 1) |
+		FIELD_PREP(FLEXCAN_CBT_EPSEG1_MASK, bt->phase_seg1 - 1) |
+		FIELD_PREP(FLEXCAN_CBT_EPSEG2_MASK, bt->phase_seg2 - 1);
+
+	netdev_dbg(dev, "writing cbt=0x%08x\n", reg_cbt);
+	priv->write(reg_cbt, &regs->cbt);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+		u32 reg_fdcbt, reg_ctrl2;
+
+		if (bt->brp != dbt->brp)
+			netdev_warn(dev, "Data brp=%d and brp=%d don't match, this may result in a phase error. Consider using different bitrate and/or data bitrate.\n",
+				    dbt->brp, bt->brp);
+
+		/* FDCBT */
+		/* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is
+		 * 5 bit long. The can_calc_bittiming tries to divide
+		 * the tseg1 equally between phase_seg1 and prop_seg,
+		 * which may not fit in FDCBT register. Therefore, if
+		 * phase_seg1 is more than possible value, increase
+		 * prop_seg and decrease phase_seg1
+		 */
+		if (dbt->phase_seg1 > 0x8) {
+			dbt->prop_seg += (dbt->phase_seg1 - 0x8);
+			dbt->phase_seg1 = 0x8;
+		}
+
+		reg_fdcbt = priv->read(&regs->fdcbt);
+		reg_fdcbt &= ~(FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, 0x3ff) |
+			       FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, 0x7) |
+			       FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, 0x1f) |
+			       FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, 0x7) |
+			       FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, 0x7));
+
+		reg_fdcbt |= FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, dbt->brp - 1) |
+			FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, dbt->sjw - 1) |
+			FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, dbt->prop_seg) |
+			FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, dbt->phase_seg1 - 1) |
+			FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, dbt->phase_seg2 - 1);
+
+		netdev_dbg(dev, "writing fdcbt=0x%08x\n", reg_fdcbt);
+		priv->write(reg_fdcbt, &regs->fdcbt);
+
+		/* CTRL2 */
+		reg_ctrl2 = priv->read(&regs->ctrl2);
+		reg_ctrl2 &= ~FLEXCAN_CTRL2_ISOCANFDEN;
+		if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
+			reg_ctrl2 |= FLEXCAN_CTRL2_ISOCANFDEN;
+
+		netdev_dbg(dev, "writing ctrl2=0x%08x\n", reg_ctrl2);
+		priv->write(reg_ctrl2, &regs->ctrl2);
+	}
+
+	/* FDCTRL */
+	reg_fdctrl = priv->read(&regs->fdctrl);
+	reg_fdctrl &= ~(FLEXCAN_FDCTRL_FDRATE |
+			FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, 0x1f));
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+		reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
+
+		if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+			/* TDC must be disabled for Loop Back mode */
+			reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN;
+		} else {
+			reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN |
+				FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF,
+					   ((dbt->phase_seg1 - 1) +
+					    dbt->prop_seg + 2) *
+					   ((dbt->brp - 1 ) + 1));
+		}
+	}
+
+	netdev_dbg(dev, "writing fdctrl=0x%08x\n", reg_fdctrl);
+	priv->write(reg_fdctrl, &regs->fdctrl);
+
+	netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x ctrl2=0x%08x fdctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n",
+		   __func__,
+		   priv->read(&regs->mcr), priv->read(&regs->ctrl),
+		   priv->read(&regs->ctrl2), priv->read(&regs->fdctrl),
+		   priv->read(&regs->cbt), priv->read(&regs->fdcbt));
+}
+
+static void flexcan_set_bittiming(struct net_device *dev)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->regs;
+	u32 reg;
+
+	reg = priv->read(&regs->ctrl);
+	reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP |
+		 FLEXCAN_CTRL_LOM);
+
 	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
 		reg |= FLEXCAN_CTRL_LPB;
 	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
@@ -1025,9 +1314,41 @@
 	netdev_dbg(dev, "writing ctrl=0x%08x\n", reg);
 	priv->write(reg, &regs->ctrl);
 
-	/* print chip status */
-	netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
-		   priv->read(&regs->mcr), priv->read(&regs->ctrl));
+	if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD)
+		return flexcan_set_bittiming_cbt(dev);
+	else
+		return flexcan_set_bittiming_ctrl(dev);
+}
+
+static void flexcan_ram_init(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->regs;
+	u32 reg_ctrl2;
+
+	/* 11.8.3.13 Detection and correction of memory errors:
+	 * CTRL2[WRMFRZ] grants write access to all memory positions
+	 * that require initialization, ranging from 0x080 to 0xADF
+	 * and from 0xF28 to 0xFFF when the CAN FD feature is enabled.
+	 * The RXMGMASK, RX14MASK, RX15MASK, and RXFGMASK registers
+	 * need to be initialized as well. MCR[RFEN] must not be set
+	 * during memory initialization.
+	 */
+	reg_ctrl2 = priv->read(&regs->ctrl2);
+	reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ;
+	priv->write(reg_ctrl2, &regs->ctrl2);
+
+	memset_io(&regs->mb[0][0], 0,
+		  offsetof(struct flexcan_regs, rx_smb1[3]) -
+		  offsetof(struct flexcan_regs, mb[0][0]) + 0x4);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+		memset_io(&regs->tx_smb_fd[0], 0,
+			  offsetof(struct flexcan_regs, rx_smb1_fd[17]) -
+			  offsetof(struct flexcan_regs, tx_smb_fd[0]) + 0x4);
+
+	reg_ctrl2 &= ~FLEXCAN_CTRL2_WRMFRZ;
+	priv->write(reg_ctrl2, &regs->ctrl2);
 }
 
 /* flexcan_chip_start
@@ -1040,6 +1361,7 @@
 	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->regs;
 	u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
+	u64 reg_imask;
 	int err, i;
 	struct flexcan_mb __iomem *mb;
 
@@ -1053,12 +1375,18 @@
 	if (err)
 		goto out_chip_disable;
 
+	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_ECC)
+		flexcan_ram_init(dev);
+
 	flexcan_set_bittiming(dev);
 
+	/* set freeze, halt */
+	err = flexcan_chip_freeze(priv);
+	if (err)
+		goto out_chip_disable;
+
 	/* MCR
 	 *
-	 * enable freeze
-	 * halt now
 	 * only supervisor access
 	 * enable warning int
 	 * enable individual RX masking
@@ -1067,9 +1395,8 @@
 	 */
 	reg_mcr = priv->read(&regs->mcr);
 	reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
-	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
-		FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | FLEXCAN_MCR_IDAM_C |
-		FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
+	reg_mcr |= FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ |
+		FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
 
 	/* MCR
 	 *
@@ -1099,6 +1426,12 @@
 	else
 		reg_mcr |= FLEXCAN_MCR_SRX_DIS;
 
+	/* MCR - CAN-FD */
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+		reg_mcr |= FLEXCAN_MCR_FDEN;
+	else
+		reg_mcr &= ~FLEXCAN_MCR_FDEN;
+
 	netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
 	priv->write(reg_mcr, &regs->mcr);
 
@@ -1141,6 +1474,32 @@
 		priv->write(reg_ctrl2, &regs->ctrl2);
 	}
 
+	if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+		u32 reg_fdctrl;
+
+		reg_fdctrl = priv->read(&regs->fdctrl);
+		reg_fdctrl &= ~(FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, 0x3) |
+				FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, 0x3));
+
+		if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+			reg_fdctrl |=
+				FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1,
+					   FLEXCAN_FDCTRL_MBDSR_64) |
+				FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0,
+					   FLEXCAN_FDCTRL_MBDSR_64);
+		} else {
+			reg_fdctrl |=
+				FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1,
+					   FLEXCAN_FDCTRL_MBDSR_8) |
+				FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0,
+					   FLEXCAN_FDCTRL_MBDSR_8);
+		}
+
+		netdev_dbg(dev, "%s: writing fdctrl=0x%08x",
+			   __func__, reg_fdctrl);
+		priv->write(reg_fdctrl, &regs->fdctrl);
+	}
+
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
 		for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) {
 			mb = flexcan_get_mb(priv, i);
@@ -1176,46 +1535,58 @@
 	for (i = 0; i < priv->mb_count; i++)
 		priv->write(0, &regs->rximr[i]);
 
-	/* On Vybrid, disable memory error detection interrupts
-	 * and freeze mode.
-	 * This also works around errata e5295 which generates
-	 * false positive memory errors and put the device in
-	 * freeze mode.
+	/* On Vybrid, disable non-correctable errors interrupt and
+	 * freeze mode. It still can correct the correctable errors
+	 * when HW supports ECC.
+	 *
+	 * This also works around errata e5295 which generates false
+	 * positive memory errors and put the device in freeze mode.
 	 */
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) {
 		/* Follow the protocol as described in "Detection
 		 * and Correction of Memory Errors" to write to
-		 * MECR register
+		 * MECR register (step 1 - 5)
+		 *
+		 * 1. By default, CTRL2[ECRWRE] = 0, MECR[ECRWRDIS] = 1
+		 * 2. set CTRL2[ECRWRE]
 		 */
 		reg_ctrl2 = priv->read(&regs->ctrl2);
 		reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE;
 		priv->write(reg_ctrl2, &regs->ctrl2);
 
+		/* 3. clear MECR[ECRWRDIS] */
 		reg_mecr = priv->read(&regs->mecr);
 		reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
 		priv->write(reg_mecr, &regs->mecr);
-		reg_mecr |= FLEXCAN_MECR_ECCDIS;
+
+		/* 4. all writes to MECR must keep MECR[ECRWRDIS] cleared */
 		reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
 			      FLEXCAN_MECR_FANCEI_MSK);
 		priv->write(reg_mecr, &regs->mecr);
-	}
 
-	err = flexcan_transceiver_enable(priv);
-	if (err)
-		goto out_chip_disable;
+		/* 5. after configuration done, lock MECR by either
+		 * setting MECR[ECRWRDIS] or clearing CTRL2[ECRWRE]
+		 */
+		reg_mecr |= FLEXCAN_MECR_ECRWRDIS;
+		priv->write(reg_mecr, &regs->mecr);
+
+		reg_ctrl2 &= ~FLEXCAN_CTRL2_ECRWRE;
+		priv->write(reg_ctrl2, &regs->ctrl2);
+	}
 
 	/* synchronize with the can bus */
 	err = flexcan_chip_unfreeze(priv);
 	if (err)
-		goto out_transceiver_disable;
+		goto out_chip_disable;
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
 	/* enable interrupts atomically */
 	disable_irq(dev->irq);
 	priv->write(priv->reg_ctrl_default, &regs->ctrl);
-	priv->write(priv->reg_imask1_default, &regs->imask1);
-	priv->write(priv->reg_imask2_default, &regs->imask2);
+	reg_imask = priv->rx_mask | priv->tx_mask;
+	priv->write(upper_32_bits(reg_imask), &regs->imask2);
+	priv->write(lower_32_bits(reg_imask), &regs->imask1);
 	enable_irq(dev->irq);
 
 	/* print chip status */
@@ -1224,25 +1595,28 @@
 
 	return 0;
 
- out_transceiver_disable:
-	flexcan_transceiver_disable(priv);
  out_chip_disable:
 	flexcan_chip_disable(priv);
 	return err;
 }
 
-/* flexcan_chip_stop
+/* __flexcan_chip_stop
  *
- * this functions is entered with clocks enabled
+ * this function is entered with clocks enabled
  */
-static void flexcan_chip_stop(struct net_device *dev)
+static int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error)
 {
 	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->regs;
+	int err;
 
 	/* freeze + disable module */
-	flexcan_chip_freeze(priv);
-	flexcan_chip_disable(priv);
+	err = flexcan_chip_freeze(priv);
+	if (err && !disable_on_error)
+		return err;
+	err = flexcan_chip_disable(priv);
+	if (err && !disable_on_error)
+		goto out_chip_unfreeze;
 
 	/* Disable all interrupts */
 	priv->write(0, &regs->imask2);
@@ -1250,8 +1624,24 @@
 	priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
 		    &regs->ctrl);
 
-	flexcan_transceiver_disable(priv);
 	priv->can.state = CAN_STATE_STOPPED;
+
+	return 0;
+
+ out_chip_unfreeze:
+	flexcan_chip_unfreeze(priv);
+
+	return err;
+}
+
+static inline int flexcan_chip_stop_disable_on_error(struct net_device *dev)
+{
+	return __flexcan_chip_stop(dev, true);
+}
+
+static inline int flexcan_chip_stop(struct net_device *dev)
+{
+	return __flexcan_chip_stop(dev, false);
 }
 
 static int flexcan_open(struct net_device *dev)
@@ -1259,19 +1649,34 @@
 	struct flexcan_priv *priv = netdev_priv(dev);
 	int err;
 
+	if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) &&
+	    (priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
+		netdev_err(dev, "Three Samples mode and CAN-FD mode can't be used together\n");
+		return -EINVAL;
+	}
+
 	err = pm_runtime_get_sync(priv->dev);
-	if (err < 0)
+	if (err < 0) {
+		pm_runtime_put_noidle(priv->dev);
 		return err;
+	}
 
 	err = open_candev(dev);
 	if (err)
 		goto out_runtime_put;
 
-	err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+	err = flexcan_transceiver_enable(priv);
 	if (err)
 		goto out_close;
 
-	priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
+	err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+	if (err)
+		goto out_transceiver_disable;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+		priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
+	else
+		priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
 	priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
 			 (sizeof(priv->regs->mb[1]) / priv->mb_size);
 
@@ -1283,26 +1688,19 @@
 			flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
 	priv->tx_mb_idx = priv->mb_count - 1;
 	priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
-
-	priv->reg_imask1_default = 0;
-	priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+	priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
 
 	priv->offload.mailbox_read = flexcan_mailbox_read;
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
-		u64 imask;
-
 		priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
 		priv->offload.mb_last = priv->mb_count - 2;
 
-		imask = GENMASK_ULL(priv->offload.mb_last,
-				    priv->offload.mb_first);
-		priv->reg_imask1_default |= imask;
-		priv->reg_imask2_default |= imask >> 32;
-
+		priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
+					    priv->offload.mb_first);
 		err = can_rx_offload_add_timestamp(dev, &priv->offload);
 	} else {
-		priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+		priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
 			FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
 		err = can_rx_offload_add_fifo(dev, &priv->offload,
 					      FLEXCAN_NAPI_WEIGHT);
@@ -1326,6 +1724,8 @@
 	can_rx_offload_del(&priv->offload);
  out_free_irq:
 	free_irq(dev->irq, dev);
+ out_transceiver_disable:
+	flexcan_transceiver_disable(priv);
  out_close:
 	close_candev(dev);
  out_runtime_put:
@@ -1340,10 +1740,11 @@
 
 	netif_stop_queue(dev);
 	can_rx_offload_disable(&priv->offload);
-	flexcan_chip_stop(dev);
+	flexcan_chip_stop_disable_on_error(dev);
 
 	can_rx_offload_del(&priv->offload);
 	free_irq(dev->irq, dev);
+	flexcan_transceiver_disable(priv);
 
 	close_candev(dev);
 	pm_runtime_put(priv->dev);
@@ -1406,10 +1807,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 = priv->read(&regs->mcr);
-	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	reg |=  FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
 	priv->write(reg, &regs->mcr);
 
 	/* Currently we only support newer versions of this core
@@ -1455,14 +1860,14 @@
 	struct device_node *gpr_np;
 	struct flexcan_priv *priv;
 	phandle phandle;
-	u32 out_val[5];
+	u32 out_val[3];
 	int ret;
 
 	if (!np)
 		return -EINVAL;
 
 	/* stop mode property format is:
-	 * <&gpr req_gpr req_bit ack_gpr ack_bit>.
+	 * <&gpr req_gpr req_bit>.
 	 */
 	ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
 					 ARRAY_SIZE(out_val));
@@ -1488,13 +1893,10 @@
 
 	priv->stm.req_gpr = out_val[1];
 	priv->stm.req_bit = out_val[2];
-	priv->stm.ack_gpr = out_val[3];
-	priv->stm.ack_bit = out_val[4];
 
 	dev_dbg(&pdev->dev,
-		"gpr %s req_gpr=0x02%x req_bit=%u ack_gpr=0x02%x ack_bit=%u\n",
-		gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit,
-		priv->stm.ack_gpr, priv->stm.ack_bit);
+		"gpr %s req_gpr=0x02%x req_bit=%u\n",
+		gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit);
 
 	device_set_wakeup_capable(&pdev->dev, true);
 
@@ -1509,6 +1911,8 @@
 }
 
 static const struct of_device_id flexcan_of_match[] = {
+	{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
+	{ .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
 	{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
 	{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
 	{ .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
@@ -1517,6 +1921,7 @@
 	{ .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
 	{ .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
 	{ .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
+	{ .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, flexcan_of_match);
@@ -1534,18 +1939,19 @@
 	struct net_device *dev;
 	struct flexcan_priv *priv;
 	struct regulator *reg_xceiver;
-	struct resource *mem;
 	struct clk *clk_ipg = NULL, *clk_per = NULL;
 	struct flexcan_regs __iomem *regs;
 	int err, irq;
 	u8 clk_src = 1;
 	u32 clock_freq = 0;
 
-	reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+	reg_xceiver = devm_regulator_get_optional(&pdev->dev, "xceiver");
 	if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
-	else if (IS_ERR(reg_xceiver))
+	else if (PTR_ERR(reg_xceiver) == -ENODEV)
 		reg_xceiver = NULL;
+	else if (IS_ERR(reg_xceiver))
+		return PTR_ERR(reg_xceiver);
 
 	if (pdev->dev.of_node) {
 		of_property_read_u32(pdev->dev.of_node,
@@ -1569,12 +1975,11 @@
 		clock_freq = clk_get_rate(clk_per);
 	}
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0)
 		return -ENODEV;
 
-	regs = devm_ioremap_resource(&pdev->dev, mem);
+	regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
 
@@ -1588,6 +1993,12 @@
 		return -ENODEV;
 	}
 
+	if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) &&
+	    !(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) {
+		dev_err(&pdev->dev, "CAN-FD mode doesn't work with FIFO mode!\n");
+		return -EINVAL;
+	}
+
 	dev = alloc_candev(sizeof(struct flexcan_priv), 1);
 	if (!dev)
 		return -ENOMEM;
@@ -1612,7 +2023,6 @@
 
 	priv->dev = &pdev->dev;
 	priv->can.clock.freq = clock_freq;
-	priv->can.bittiming_const = &flexcan_bittiming_const;
 	priv->can.do_set_mode = flexcan_set_mode;
 	priv->can.do_get_berr_counter = flexcan_get_berr_counter;
 	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
@@ -1625,6 +2035,16 @@
 	priv->devtype_data = devtype_data;
 	priv->reg_xceiver = reg_xceiver;
 
+	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) {
+		priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD |
+			CAN_CTRLMODE_FD_NON_ISO;
+		priv->can.bittiming_const = &flexcan_fd_bittiming_const;
+		priv->can.data_bittiming_const =
+			&flexcan_fd_data_bittiming_const;
+	} else {
+		priv->can.bittiming_const = &flexcan_bittiming_const;
+	}
+
 	pm_runtime_get_noresume(&pdev->dev);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
@@ -1635,6 +2055,7 @@
 		goto failed_register;
 	}
 
+	of_can_transceiver(dev);
 	devm_can_led_init(dev);
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
@@ -1646,6 +2067,8 @@
 	return 0;
 
  failed_register:
+	pm_runtime_put_noidle(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	free_candev(dev);
 	return err;
 }
@@ -1654,6 +2077,8 @@
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 
+	device_set_wakeup_enable(&pdev->dev, false);
+	device_set_wakeup_capable(&pdev->dev, false);
 	unregister_flexcandev(dev);
 	pm_runtime_disable(&pdev->dev);
 	free_candev(dev);
@@ -1665,7 +2090,7 @@
 {
 	struct net_device *dev = dev_get_drvdata(device);
 	struct flexcan_priv *priv = netdev_priv(dev);
-	int err = 0;
+	int err;
 
 	if (netif_running(dev)) {
 		/* if wakeup is enabled, enter stop mode
@@ -1677,25 +2102,27 @@
 			if (err)
 				return err;
 		} else {
-			err = flexcan_chip_disable(priv);
+			err = flexcan_chip_stop(dev);
 			if (err)
 				return err;
 
-			err = pm_runtime_force_suspend(device);
+			err = pinctrl_pm_select_sleep_state(device);
+			if (err)
+				return err;
 		}
 		netif_stop_queue(dev);
 		netif_device_detach(dev);
 	}
 	priv->can.state = CAN_STATE_SLEEPING;
 
-	return err;
+	return 0;
 }
 
 static int __maybe_unused flexcan_resume(struct device *device)
 {
 	struct net_device *dev = dev_get_drvdata(device);
 	struct flexcan_priv *priv = netdev_priv(dev);
-	int err = 0;
+	int err;
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 	if (netif_running(dev)) {
@@ -1703,16 +2130,21 @@
 		netif_start_queue(dev);
 		if (device_may_wakeup(device)) {
 			disable_irq_wake(dev->irq);
+			err = flexcan_exit_stop_mode(priv);
+			if (err)
+				return err;
 		} else {
-			err = pm_runtime_force_resume(device);
+			err = pinctrl_pm_select_default_state(device);
 			if (err)
 				return err;
 
-			err = flexcan_chip_enable(priv);
+			err = flexcan_chip_start(dev);
+			if (err)
+				return err;
 		}
 	}
 
-	return err;
+	return 0;
 }
 
 static int __maybe_unused flexcan_runtime_suspend(struct device *device)
@@ -1738,8 +2170,16 @@
 	struct net_device *dev = dev_get_drvdata(device);
 	struct flexcan_priv *priv = netdev_priv(dev);
 
-	if (netif_running(dev) && device_may_wakeup(device))
-		flexcan_enable_wakeup_irq(priv, true);
+	if (netif_running(dev)) {
+		int err;
+
+		if (device_may_wakeup(device))
+			flexcan_enable_wakeup_irq(priv, true);
+
+		err = pm_runtime_force_suspend(device);
+		if (err)
+			return err;
+	}
 
 	return 0;
 }
@@ -1748,13 +2188,16 @@
 {
 	struct net_device *dev = dev_get_drvdata(device);
 	struct flexcan_priv *priv = netdev_priv(dev);
-	int err;
 
-	if (netif_running(dev) && device_may_wakeup(device)) {
-		flexcan_enable_wakeup_irq(priv, false);
-		err = flexcan_exit_stop_mode(priv);
+	if (netif_running(dev)) {
+		int err;
+
+		err = pm_runtime_force_resume(device);
 		if (err)
 			return err;
+
+		if (device_may_wakeup(device))
+			flexcan_enable_wakeup_irq(priv, false);
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/can/grcan.c
+++ linux-ein-5.4.0/drivers/net/can/grcan.c
@@ -241,13 +241,14 @@
 		.rxsize		= GRCAN_DEFAULT_BUFFER_SIZE,	\
 		}
 
-#define GRCAN_TXBUG_SAFE_GRLIB_VERSION	0x4100
+#define GRCAN_TXBUG_SAFE_GRLIB_VERSION	4100
 #define GRLIB_VERSION_MASK		0xffff
 
 /* GRCAN private data structure */
 struct grcan_priv {
 	struct can_priv can;	/* must be the first member */
 	struct net_device *dev;
+	struct device *ofdev_dev;
 	struct napi_struct napi;
 
 	struct grcan_registers __iomem *regs;	/* ioremap'ed registers */
@@ -924,7 +925,7 @@
 	struct grcan_priv *priv = netdev_priv(dev);
 	struct grcan_dma *dma = &priv->dma;
 
-	dma_free_coherent(&dev->dev, dma->base_size, dma->base_buf,
+	dma_free_coherent(priv->ofdev_dev, dma->base_size, dma->base_buf,
 			  dma->base_handle);
 	memset(dma, 0, sizeof(*dma));
 }
@@ -949,7 +950,7 @@
 
 	/* Extra GRCAN_BUFFER_ALIGNMENT to allow for alignment */
 	dma->base_size = lsize + ssize + GRCAN_BUFFER_ALIGNMENT;
-	dma->base_buf = dma_alloc_coherent(&dev->dev,
+	dma->base_buf = dma_alloc_coherent(priv->ofdev_dev,
 					   dma->base_size,
 					   &dma->base_handle,
 					   GFP_KERNEL);
@@ -1113,8 +1114,10 @@
 
 	priv->closing = true;
 	if (priv->need_txbug_workaround) {
+		spin_unlock_irqrestore(&priv->lock, flags);
 		del_timer_sync(&priv->hang_timer);
 		del_timer_sync(&priv->rr_timer);
+		spin_lock_irqsave(&priv->lock, flags);
 	}
 	netif_stop_queue(dev);
 	grcan_stop_hardware(dev);
@@ -1134,7 +1137,7 @@
 	return 0;
 }
 
-static int grcan_transmit_catch_up(struct net_device *dev, int budget)
+static void grcan_transmit_catch_up(struct net_device *dev)
 {
 	struct grcan_priv *priv = netdev_priv(dev);
 	unsigned long flags;
@@ -1142,7 +1145,7 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	work_done = catch_up_echo_skb(dev, budget, true);
+	work_done = catch_up_echo_skb(dev, -1, true);
 	if (work_done) {
 		if (!priv->resetting && !priv->closing &&
 		    !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
@@ -1156,8 +1159,6 @@
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return work_done;
 }
 
 static int grcan_receive(struct net_device *dev, int budget)
@@ -1239,19 +1240,13 @@
 	struct net_device *dev = priv->dev;
 	struct grcan_registers __iomem *regs = priv->regs;
 	unsigned long flags;
-	int tx_work_done, rx_work_done;
-	int rx_budget = budget / 2;
-	int tx_budget = budget - rx_budget;
+	int work_done;
 
-	/* Half of the budget for receiveing messages */
-	rx_work_done = grcan_receive(dev, rx_budget);
+	work_done = grcan_receive(dev, budget);
 
-	/* Half of the budget for transmitting messages as that can trigger echo
-	 * frames being received
-	 */
-	tx_work_done = grcan_transmit_catch_up(dev, tx_budget);
+	grcan_transmit_catch_up(dev);
 
-	if (rx_work_done < rx_budget && tx_work_done < tx_budget) {
+	if (work_done < budget) {
 		napi_complete(napi);
 
 		/* Guarantee no interference with a running reset that otherwise
@@ -1268,7 +1263,7 @@
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	return rx_work_done + tx_work_done;
+	return work_done;
 }
 
 /* Work tx bug by waiting while for the risky situation to clear. If that fails,
@@ -1600,6 +1595,7 @@
 	memcpy(&priv->config, &grcan_module_config,
 	       sizeof(struct grcan_device_config));
 	priv->dev = dev;
+	priv->ofdev_dev = &ofdev->dev;
 	priv->regs = base;
 	priv->can.bittiming_const = &grcan_bittiming_const;
 	priv->can.do_set_bittiming = grcan_set_bittiming;
@@ -1652,6 +1648,7 @@
 static int grcan_probe(struct platform_device *ofdev)
 {
 	struct device_node *np = ofdev->dev.of_node;
+	struct device_node *sysid_parent;
 	struct resource *res;
 	u32 sysid, ambafreq;
 	int irq, err;
@@ -1661,10 +1658,14 @@
 	/* Compare GRLIB version number with the first that does not
 	 * have the tx bug (see start_xmit)
 	 */
-	err = of_property_read_u32(np, "systemid", &sysid);
-	if (!err && ((sysid & GRLIB_VERSION_MASK)
-		     >= GRCAN_TXBUG_SAFE_GRLIB_VERSION))
-		txbug = false;
+	sysid_parent = of_find_node_by_path("/ambapp0");
+	if (sysid_parent) {
+		err = of_property_read_u32(sysid_parent, "systemid", &sysid);
+		if (!err && ((sysid & GRLIB_VERSION_MASK) >=
+			     GRCAN_TXBUG_SAFE_GRLIB_VERSION))
+			txbug = false;
+		of_node_put(sysid_parent);
+	}
 
 	err = of_property_read_u32(np, "freq", &ambafreq);
 	if (err) {
--- linux-ein-5.4.0.orig/drivers/net/can/janz-ican3.c
+++ linux-ein-5.4.0/drivers/net/can/janz-ican3.c
@@ -1451,7 +1451,7 @@
 
 	/* process all communication messages */
 	while (true) {
-		struct ican3_msg uninitialized_var(msg);
+		struct ican3_msg msg;
 		ret = ican3_recv_msg(mod, &msg);
 		if (ret)
 			break;
--- linux-ein-5.4.0.orig/drivers/net/can/kvaser_pciefd.c
+++ linux-ein-5.4.0/drivers/net/can/kvaser_pciefd.c
@@ -57,6 +57,7 @@
 #define KVASER_PCIEFD_KCAN_STAT_REG 0x418
 #define KVASER_PCIEFD_KCAN_MODE_REG 0x41c
 #define KVASER_PCIEFD_KCAN_BTRN_REG 0x420
+#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424
 #define KVASER_PCIEFD_KCAN_BTRD_REG 0x428
 #define KVASER_PCIEFD_KCAN_PWM_REG 0x430
 /* Loopback control register */
@@ -69,10 +70,12 @@
 #define KVASER_PCIEFD_SYSID_BUILD_REG (KVASER_PCIEFD_SYSID_BASE + 0x14)
 /* Shared receive buffer registers */
 #define KVASER_PCIEFD_SRB_BASE 0x1f200
+#define KVASER_PCIEFD_SRB_FIFO_LAST_REG (KVASER_PCIEFD_SRB_BASE + 0x1f4)
 #define KVASER_PCIEFD_SRB_CMD_REG (KVASER_PCIEFD_SRB_BASE + 0x200)
 #define KVASER_PCIEFD_SRB_IEN_REG (KVASER_PCIEFD_SRB_BASE + 0x204)
 #define KVASER_PCIEFD_SRB_IRQ_REG (KVASER_PCIEFD_SRB_BASE + 0x20c)
 #define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210)
+#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214)
 #define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218)
 /* EPCS flash controller registers */
 #define KVASER_PCIEFD_SPI_BASE 0x1fc00
@@ -109,6 +112,9 @@
 /* DMA support */
 #define KVASER_PCIEFD_SRB_STAT_DMA BIT(24)
 
+/* SRB current packet level */
+#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK 0xff
+
 /* DMA Enable */
 #define KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE BIT(0)
 
@@ -247,6 +253,9 @@
 #define KVASER_PCIEFD_SPACK_EWLR BIT(23)
 #define KVASER_PCIEFD_SPACK_EPLR BIT(24)
 
+/* Kvaser KCAN_EPACK second word */
+#define KVASER_PCIEFD_EPACK_DIR_TX BIT(0)
+
 struct kvaser_pciefd;
 
 struct kvaser_pciefd_can {
@@ -287,12 +296,12 @@
 static const struct can_bittiming_const kvaser_pciefd_bittiming_const = {
 	.name = KVASER_PCIEFD_DRV_NAME,
 	.tseg1_min = 1,
-	.tseg1_max = 255,
+	.tseg1_max = 512,
 	.tseg2_min = 1,
 	.tseg2_max = 32,
 	.sjw_max = 16,
 	.brp_min = 1,
-	.brp_max = 4096,
+	.brp_max = 8192,
 	.brp_inc = 1,
 };
 
@@ -524,7 +533,7 @@
 	      KVASER_PCIEFD_KCAN_IRQ_TOF | KVASER_PCIEFD_KCAN_IRQ_ABD |
 	      KVASER_PCIEFD_KCAN_IRQ_TAE | KVASER_PCIEFD_KCAN_IRQ_TAL |
 	      KVASER_PCIEFD_KCAN_IRQ_FDIC | KVASER_PCIEFD_KCAN_IRQ_BPP |
-	      KVASER_PCIEFD_KCAN_IRQ_TAR | KVASER_PCIEFD_KCAN_IRQ_TFD;
+	      KVASER_PCIEFD_KCAN_IRQ_TAR;
 
 	iowrite32(msk, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 
@@ -552,6 +561,8 @@
 
 	if (can->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
 		mode |= KVASER_PCIEFD_KCAN_MODE_LOM;
+	else
+		mode &= ~KVASER_PCIEFD_KCAN_MODE_LOM;
 
 	mode |= KVASER_PCIEFD_KCAN_MODE_EEN;
 	mode |= KVASER_PCIEFD_KCAN_MODE_EPEN;
@@ -570,7 +581,7 @@
 
 	spin_lock_irqsave(&can->lock, irq);
 	iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG);
-	iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD | KVASER_PCIEFD_KCAN_IRQ_TFD,
+	iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD,
 		  can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 
 	status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG);
@@ -613,7 +624,7 @@
 	iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 	iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG);
 
-	iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD | KVASER_PCIEFD_KCAN_IRQ_TFD,
+	iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD,
 		  can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 
 	mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG);
@@ -715,6 +726,7 @@
 		iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 		del_timer(&can->bec_poll_timer);
 	}
+	can->can.state = CAN_STATE_STOPPED;
 	close_candev(netdev);
 
 	return ret;
@@ -947,6 +959,9 @@
 		timer_setup(&can->bec_poll_timer, kvaser_pciefd_bec_poll_timer,
 			    0);
 
+		/* Disable Bus load reporting */
+		iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_BUS_LOAD_REG);
+
 		tx_npackets = ioread32(can->reg_base +
 				       KVASER_PCIEFD_KCAN_TX_NPACKETS_REG);
 		if (((tx_npackets >> KVASER_PCIEFD_KCAN_TX_NPACKETS_MAX_SHIFT) &
@@ -994,8 +1009,7 @@
 		SET_NETDEV_DEV(netdev, &pcie->pci->dev);
 
 		iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG);
-		iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD |
-			  KVASER_PCIEFD_KCAN_IRQ_TFD,
+		iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD,
 			  can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 
 		pcie->can[i] = can;
@@ -1045,6 +1059,7 @@
 {
 	int i;
 	u32 srb_status;
+	u32 srb_packet_count;
 	dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT];
 
 	/* Disable the DMA */
@@ -1072,6 +1087,15 @@
 		  KVASER_PCIEFD_SRB_CMD_RDB1,
 		  pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
 
+	/* Empty Rx FIFO */
+	srb_packet_count = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG) &
+			   KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK;
+	while (srb_packet_count) {
+		/* Drop current packet in FIFO */
+		ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
+		srb_packet_count--;
+	}
+
 	srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG);
 	if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) {
 		dev_err(&pcie->pci->dev, "DMA not idle before enabling\n");
@@ -1279,7 +1303,10 @@
 
 	can->err_rep_cnt++;
 	can->can.can_stats.bus_error++;
-	stats->rx_errors++;
+	if (p->header[1] & KVASER_PCIEFD_EPACK_DIR_TX)
+		stats->tx_errors++;
+	else
+		stats->rx_errors++;
 
 	can->bec.txerr = bec.txerr;
 	can->bec.rxerr = bec.rxerr;
@@ -1411,9 +1438,6 @@
 		cmd = KVASER_PCIEFD_KCAN_CMD_AT;
 		cmd |= ++can->cmd_seq << KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT;
 		iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG);
-
-		iowrite32(KVASER_PCIEFD_KCAN_IRQ_TFD,
-			  can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
 	} else if (p->header[0] & KVASER_PCIEFD_SPACK_IDET &&
 		   p->header[0] & KVASER_PCIEFD_SPACK_IRM &&
 		   cmdseq == (p->header[1] & KVASER_PCIEFD_PACKET_SEQ_MSK) &&
@@ -1702,15 +1726,6 @@
 	if (irq & KVASER_PCIEFD_KCAN_IRQ_TOF)
 		netdev_err(can->can.dev, "Tx FIFO overflow\n");
 
-	if (irq & KVASER_PCIEFD_KCAN_IRQ_TFD) {
-		u8 count = ioread32(can->reg_base +
-				    KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff;
-
-		if (count == 0)
-			iowrite32(KVASER_PCIEFD_KCAN_CTRL_EFLUSH,
-				  can->reg_base + KVASER_PCIEFD_KCAN_CTRL_REG);
-	}
-
 	if (irq & KVASER_PCIEFD_KCAN_IRQ_BPP)
 		netdev_err(can->can.dev,
 			   "Fail to change bittiming, when not in reset mode\n");
@@ -1812,6 +1827,11 @@
 	if (err)
 		goto err_teardown_can_ctrls;
 
+	err = request_irq(pcie->pci->irq, kvaser_pciefd_irq_handler,
+			  IRQF_SHARED, KVASER_PCIEFD_DRV_NAME, pcie);
+	if (err)
+		goto err_teardown_can_ctrls;
+
 	iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1,
 		  pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
 
@@ -1832,11 +1852,6 @@
 	iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
 		  pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
 
-	err = request_irq(pcie->pci->irq, kvaser_pciefd_irq_handler,
-			  IRQF_SHARED, KVASER_PCIEFD_DRV_NAME, pcie);
-	if (err)
-		goto err_teardown_can_ctrls;
-
 	err = kvaser_pciefd_reg_candev(pcie);
 	if (err)
 		goto err_free_irq;
@@ -1844,6 +1859,8 @@
 	return 0;
 
 err_free_irq:
+	/* Disable PCI interrupts */
+	iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG);
 	free_irq(pcie->pci->irq, pcie);
 
 err_teardown_can_ctrls:
--- linux-ein-5.4.0.orig/drivers/net/can/m_can/Kconfig
+++ linux-ein-5.4.0/drivers/net/can/m_can/Kconfig
@@ -16,7 +16,8 @@
 
 config CAN_M_CAN_TCAN4X5X
 	depends on CAN_M_CAN
-	depends on REGMAP_SPI
+	depends on SPI
+	select REGMAP_SPI
 	tristate "TCAN4X5X M_CAN device"
 	---help---
 	  Say Y here if you want support for Texas Instruments TCAN4x5x
--- linux-ein-5.4.0.orig/drivers/net/can/m_can/m_can.c
+++ linux-ein-5.4.0/drivers/net/can/m_can/m_can.c
@@ -206,15 +206,15 @@
 
 /* Interrupts for version 3.0.x */
 #define IR_ERR_LEC_30X	(IR_STE	| IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
-#define IR_ERR_BUS_30X	(IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \
-			 IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
-			 IR_RF1L | IR_RF0L)
+#define IR_ERR_BUS_30X	(IR_ERR_LEC_30X | IR_WDI | IR_BEU | IR_BEC | \
+			 IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
+			 IR_RF0L)
 #define IR_ERR_ALL_30X	(IR_ERR_STATE | IR_ERR_BUS_30X)
 /* Interrupts for version >= 3.1.x */
 #define IR_ERR_LEC_31X	(IR_PED | IR_PEA)
-#define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
-			 IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
-			 IR_RF1L | IR_RF0L)
+#define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \
+			 IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
+			 IR_RF0L)
 #define IR_ERR_ALL_31X	(IR_ERR_STATE | IR_ERR_BUS_31X)
 
 /* Interrupt Line Select (ILS) */
@@ -379,10 +379,6 @@
 		cccr &= ~CCCR_CSR;
 
 	if (enable) {
-		/* Clear the Clock stop request if it was set */
-		if (cccr & CCCR_CSR)
-			cccr &= ~CCCR_CSR;
-
 		/* enable m_can configuration */
 		m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT);
 		udelay(5);
@@ -505,9 +501,6 @@
 	}
 
 	while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) {
-		if (rxfs & RXFS_RFL)
-			netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
-
 		m_can_read_fifo(dev, rxfs);
 
 		quota--;
@@ -664,7 +657,7 @@
 	unsigned int ecr;
 
 	switch (new_state) {
-	case CAN_STATE_ERROR_ACTIVE:
+	case CAN_STATE_ERROR_WARNING:
 		/* error warning state */
 		cdev->can.can_stats.error_warning++;
 		cdev->can.state = CAN_STATE_ERROR_WARNING;
@@ -693,7 +686,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) ?
@@ -758,8 +751,6 @@
 {
 	if (irqstatus & IR_WDI)
 		netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
-	if (irqstatus & IR_ELO)
-		netdev_err(dev, "Error Logging Overflow\n");
 	if (irqstatus & IR_BEU)
 		netdev_err(dev, "Bit Error Uncorrected\n");
 	if (irqstatus & IR_BEC)
@@ -846,7 +837,7 @@
 {
 	struct m_can_classdev *cdev = netdev_priv(dev);
 
-	m_can_rx_handler(dev, 1);
+	m_can_rx_handler(dev, M_CAN_NAPI_WEIGHT);
 
 	m_can_enable_all_interrupts(cdev);
 
@@ -913,6 +904,8 @@
 	struct net_device_stats *stats = &dev->stats;
 	u32 ir;
 
+	if (pm_runtime_suspended(cdev->dev))
+		return IRQ_NONE;
 	ir = m_can_read(cdev, M_CAN_IR);
 	if (!ir)
 		return IRQ_NONE;
@@ -988,7 +981,7 @@
 	.name = KBUILD_MODNAME,
 	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
 	.tseg1_max = 256,
-	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
+	.tseg2_min = 2,		/* Time segment 2 = phase_seg2 */
 	.tseg2_max = 128,
 	.sjw_max = 128,
 	.brp_min = 1,
@@ -1335,6 +1328,8 @@
 						&m_can_data_bittiming_const_31X;
 		break;
 	case 32:
+	case 33:
+		/* Support both MCAN version v3.2.x and v3.3.0 */
 		m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
 			m_can_dev->bit_timing : &m_can_bittiming_const_31X;
 
@@ -1366,6 +1361,9 @@
 	/* disable all interrupts */
 	m_can_disable_all_interrupts(cdev);
 
+	/* Set init mode to disengage from the network */
+	m_can_config_endisable(cdev, true);
+
 	/* set the state as STOPPED */
 	cdev->can.state = CAN_STATE_STOPPED;
 }
@@ -1418,6 +1416,8 @@
 	int i;
 	int putidx;
 
+	cdev->tx_skb = NULL;
+
 	/* Generate ID field for TX buffer Element */
 	/* Common to all supported M_CAN versions */
 	if (cf->can_id & CAN_EFF_FLAG) {
@@ -1443,8 +1443,6 @@
 					 M_CAN_FIFO_DATA(i / 4),
 					 *(u32 *)(cf->data + i));
 
-		can_put_echo_skb(skb, dev, 0);
-
 		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
 			cccr = m_can_read(cdev, M_CAN_CCCR);
 			cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
@@ -1461,6 +1459,9 @@
 			m_can_write(cdev, M_CAN_CCCR, cccr);
 		}
 		m_can_write(cdev, M_CAN_TXBTIE, 0x1);
+
+		can_put_echo_skb(skb, dev, 0);
+
 		m_can_write(cdev, M_CAN_TXBAR, 0x1);
 		/* End of xmit function for version 3.0.x */
 	} else {
@@ -1534,7 +1535,6 @@
 						tx_work);
 
 	m_can_tx_handler(cdev);
-	cdev->tx_skb = NULL;
 }
 
 static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
@@ -1600,7 +1600,7 @@
 		INIT_WORK(&cdev->tx_work, m_can_tx_work_queue);
 
 		err = request_threaded_irq(dev->irq, NULL, m_can_isr,
-					   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+					   IRQF_ONESHOT,
 					   dev->name, dev);
 	} else {
 		err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
@@ -1764,6 +1764,12 @@
 }
 EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
 
+void m_can_class_free_dev(struct net_device *net)
+{
+	free_candev(net);
+}
+EXPORT_SYMBOL_GPL(m_can_class_free_dev);
+
 int m_can_class_register(struct m_can_classdev *m_can_dev)
 {
 	int ret;
@@ -1859,8 +1865,6 @@
 {
 	unregister_candev(m_can_dev->net);
 
-	m_can_clk_stop(m_can_dev);
-
 	free_candev(m_can_dev->net);
 }
 EXPORT_SYMBOL_GPL(m_can_class_unregister);
--- linux-ein-5.4.0.orig/drivers/net/can/m_can/m_can.h
+++ linux-ein-5.4.0/drivers/net/can/m_can/m_can.h
@@ -99,6 +99,7 @@
 };
 
 struct m_can_classdev *m_can_class_allocate_dev(struct device *dev);
+void m_can_class_free_dev(struct net_device *net);
 int m_can_class_register(struct m_can_classdev *cdev);
 void m_can_class_unregister(struct m_can_classdev *cdev);
 int m_can_class_get_clocks(struct m_can_classdev *cdev);
--- linux-ein-5.4.0.orig/drivers/net/can/m_can/m_can_platform.c
+++ linux-ein-5.4.0/drivers/net/can/m_can/m_can_platform.c
@@ -144,8 +144,6 @@
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct m_can_classdev *mcan_class = netdev_priv(ndev);
 
-	m_can_class_suspend(dev);
-
 	clk_disable_unprepare(mcan_class->cclk);
 	clk_disable_unprepare(mcan_class->hclk);
 
--- linux-ein-5.4.0.orig/drivers/net/can/m_can/tcan4x5x.c
+++ linux-ein-5.4.0/drivers/net/can/m_can/tcan4x5x.c
@@ -88,7 +88,7 @@
 
 #define TCAN4X5X_MRAM_START 0x8000
 #define TCAN4X5X_MCAN_OFFSET 0x1000
-#define TCAN4X5X_MAX_REGISTER 0x8fff
+#define TCAN4X5X_MAX_REGISTER 0x8ffc
 
 #define TCAN4X5X_CLEAR_ALL_INT 0xffffffff
 #define TCAN4X5X_SET_ALL_INT 0xffffffff
@@ -126,30 +126,6 @@
 	int reg_offset;
 };
 
-static struct can_bittiming_const tcan4x5x_bittiming_const = {
-	.name = DEVICE_NAME,
-	.tseg1_min = 2,
-	.tseg1_max = 31,
-	.tseg2_min = 2,
-	.tseg2_max = 16,
-	.sjw_max = 16,
-	.brp_min = 1,
-	.brp_max = 32,
-	.brp_inc = 1,
-};
-
-static struct can_bittiming_const tcan4x5x_data_bittiming_const = {
-	.name = DEVICE_NAME,
-	.tseg1_min = 1,
-	.tseg1_max = 32,
-	.tseg2_min = 1,
-	.tseg2_max = 16,
-	.sjw_max = 16,
-	.brp_min = 1,
-	.brp_max = 32,
-	.brp_inc = 1,
-};
-
 static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
 {
 	int wake_state = 0;
@@ -164,6 +140,28 @@
 	}
 }
 
+static int tcan4x5x_reset(struct tcan4x5x_priv *priv)
+{
+	int ret = 0;
+
+	if (priv->reset_gpio) {
+		gpiod_set_value(priv->reset_gpio, 1);
+
+		/* tpulse_width minimum 30us */
+		usleep_range(30, 100);
+		gpiod_set_value(priv->reset_gpio, 0);
+	} else {
+		ret = regmap_write(priv->regmap, TCAN4X5X_CONFIG,
+				   TCAN4X5X_SW_RESET);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(700, 1000);
+
+	return ret;
+}
+
 static int regmap_spi_gather_write(void *context, const void *reg,
 				   size_t reg_len, const void *val,
 				   size_t val_len)
@@ -293,11 +291,6 @@
 	if (ret)
 		return ret;
 
-	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_MCAN_INT_REG,
-				      TCAN4X5X_ENABLE_MCAN_INT);
-	if (ret)
-		return ret;
-
 	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS,
 				      TCAN4X5X_CLEAR_ALL_INT);
 	if (ret)
@@ -327,20 +320,21 @@
 	if (ret)
 		return ret;
 
+	/* Zero out the MCAN buffers */
+	m_can_init_ram(cdev);
+
 	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
 				 TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
 	if (ret)
 		return ret;
 
-	/* Zero out the MCAN buffers */
-	m_can_init_ram(cdev);
-
 	return ret;
 }
 
 static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
 {
 	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
+	int ret;
 
 	tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
 						    GPIOD_OUT_HIGH);
@@ -354,6 +348,10 @@
 	if (IS_ERR(tcan4x5x->reset_gpio))
 		tcan4x5x->reset_gpio = NULL;
 
+	ret = tcan4x5x_reset(tcan4x5x);
+	if (ret)
+		return ret;
+
 	tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
 							      "device-state",
 							      GPIOD_IN);
@@ -422,8 +420,6 @@
 	mcan_class->dev = &spi->dev;
 	mcan_class->ops = &tcan4x5x_ops;
 	mcan_class->is_peripheral = true;
-	mcan_class->bit_timing = &tcan4x5x_bittiming_const;
-	mcan_class->data_timing = &tcan4x5x_data_bittiming_const;
 	mcan_class->net->irq = spi->irq;
 
 	spi_set_drvdata(spi, priv);
@@ -440,9 +436,17 @@
 
 	priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
 					&spi->dev, &tcan4x5x_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		goto out_clk;
+	}
 
 	tcan4x5x_power_enable(priv->power, 1);
 
+	ret = tcan4x5x_init(mcan_class);
+	if (ret)
+		goto out_power;
+
 	ret = m_can_class_register(mcan_class);
 	if (ret)
 		goto out_power;
@@ -466,10 +470,10 @@
 {
 	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
 
-	tcan4x5x_power_enable(priv->power, 0);
-
 	m_can_class_unregister(priv->mcan_dev);
 
+	tcan4x5x_power_enable(priv->power, 0);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/mscan/mpc5xxx_can.c
+++ linux-ein-5.4.0/drivers/net/can/mscan/mpc5xxx_can.c
@@ -325,14 +325,14 @@
 					       &mscan_clksrc);
 	if (!priv->can.clock.freq) {
 		dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
-		goto exit_free_mscan;
+		goto exit_put_clock;
 	}
 
 	err = register_mscandev(dev, mscan_clksrc);
 	if (err) {
 		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
 			DRV_NAME, err);
-		goto exit_free_mscan;
+		goto exit_put_clock;
 	}
 
 	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
@@ -340,7 +340,9 @@
 
 	return 0;
 
-exit_free_mscan:
+exit_put_clock:
+	if (data->put_clock)
+		data->put_clock(ofdev);
 	free_candev(dev);
 exit_dispose_irq:
 	irq_dispose_mapping(irq);
--- linux-ein-5.4.0.orig/drivers/net/can/mscan/mscan.c
+++ linux-ein-5.4.0/drivers/net/can/mscan/mscan.c
@@ -381,13 +381,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;
@@ -408,18 +407,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-ein-5.4.0.orig/drivers/net/can/pch_can.c
+++ linux-ein-5.4.0/drivers/net/can/pch_can.c
@@ -489,6 +489,7 @@
 	if (!skb)
 		return;
 
+	errc = ioread32(&priv->regs->errc);
 	if (status & PCH_BUS_OFF) {
 		pch_can_set_tx_all(priv, 0);
 		pch_can_set_rx_all(priv, 0);
@@ -496,9 +497,11 @@
 		cf->can_id |= CAN_ERR_BUSOFF;
 		priv->can.can_stats.bus_off++;
 		can_bus_off(ndev);
+	} else {
+		cf->data[6] = errc & PCH_TEC;
+		cf->data[7] = (errc & PCH_REC) >> 8;
 	}
 
-	errc = ioread32(&priv->regs->errc);
 	/* Warning interrupt. */
 	if (status & PCH_EWARN) {
 		state = CAN_STATE_ERROR_WARNING;
@@ -556,9 +559,6 @@
 		break;
 	}
 
-	cf->data[6] = errc & PCH_TEC;
-	cf->data[7] = (errc & PCH_REC) >> 8;
-
 	priv->can.state = state;
 	netif_receive_skb(skb);
 
@@ -692,11 +692,11 @@
 			cf->data[i + 1] = data_reg >> 8;
 		}
 
-		netif_receive_skb(skb);
 		rcv_pkts++;
 		stats->rx_packets++;
 		quota--;
 		stats->rx_bytes += cf->can_dlc;
+		netif_receive_skb(skb);
 
 		pch_fifo_thresh(priv, obj_num);
 		obj_num++;
--- linux-ein-5.4.0.orig/drivers/net/can/peak_canfd/peak_canfd.c
+++ linux-ein-5.4.0/drivers/net/can/peak_canfd/peak_canfd.c
@@ -232,6 +232,20 @@
 	return pucan_write_cmd(priv);
 }
 
+static int pucan_netif_rx(struct sk_buff *skb, __le32 ts_low, __le32 ts_high)
+{
+	struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
+	u64 ts_us;
+
+	ts_us = (u64)le32_to_cpu(ts_high) << 32;
+	ts_us |= le32_to_cpu(ts_low);
+
+	/* IP core timestamps are µs. */
+	hwts->hwtstamp = ns_to_ktime(ts_us * NSEC_PER_USEC);
+
+	return netif_rx(skb);
+}
+
 /* handle the reception of one CAN frame */
 static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
 			       struct pucan_rx_msg *msg)
@@ -248,8 +262,7 @@
 		cf_len = get_can_dlc(pucan_msg_get_dlc(msg));
 
 	/* if this frame is an echo, */
-	if ((rx_msg_flags & PUCAN_MSG_LOOPED_BACK) &&
-	    !(rx_msg_flags & PUCAN_MSG_SELF_RECEIVE)) {
+	if (rx_msg_flags & PUCAN_MSG_LOOPED_BACK) {
 		unsigned long flags;
 
 		spin_lock_irqsave(&priv->echo_lock, flags);
@@ -263,7 +276,13 @@
 		netif_wake_queue(priv->ndev);
 
 		spin_unlock_irqrestore(&priv->echo_lock, flags);
-		return 0;
+
+		/* if this frame is only an echo, stop here. Otherwise,
+		 * continue to push this application self-received frame into
+		 * its own rx queue.
+		 */
+		if (!(rx_msg_flags & PUCAN_MSG_SELF_RECEIVE))
+			return 0;
 	}
 
 	/* otherwise, it should be pushed into rx fifo */
@@ -299,7 +318,7 @@
 	stats->rx_bytes += cf->len;
 	stats->rx_packets++;
 
-	netif_rx(skb);
+	pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
 
 	return 0;
 }
@@ -333,8 +352,8 @@
 				return err;
 		}
 
-		/* start network queue (echo_skb array is empty) */
-		netif_start_queue(ndev);
+		/* wake network queue up (echo_skb array is empty) */
+		netif_wake_queue(ndev);
 
 		return 0;
 	}
@@ -393,7 +412,7 @@
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
-	netif_rx(skb);
+	pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/can/rcar/rcar_can.c
+++ linux-ein-5.4.0/drivers/net/can/rcar/rcar_can.c
@@ -235,11 +235,8 @@
 	if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) {
 		txerr = readb(&priv->regs->tecr);
 		rxerr = readb(&priv->regs->recr);
-		if (skb) {
+		if (skb)
 			cf->can_id |= CAN_ERR_CRTL;
-			cf->data[6] = txerr;
-			cf->data[7] = rxerr;
-		}
 	}
 	if (eifr & RCAR_CAN_EIFR_BEIF) {
 		int rx_errors = 0, tx_errors = 0;
@@ -339,6 +336,9 @@
 		can_bus_off(ndev);
 		if (skb)
 			cf->can_id |= CAN_ERR_BUSOFF;
+	} else if (skb) {
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
 	}
 	if (eifr & RCAR_CAN_EIFR_ORIF) {
 		netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
@@ -848,10 +848,12 @@
 	struct rcar_can_priv *priv = netdev_priv(ndev);
 	u16 ctlr;
 
-	if (netif_running(ndev)) {
-		netif_stop_queue(ndev);
-		netif_device_detach(ndev);
-	}
+	if (!netif_running(ndev))
+		return 0;
+
+	netif_stop_queue(ndev);
+	netif_device_detach(ndev);
+
 	ctlr = readw(&priv->regs->ctlr);
 	ctlr |= RCAR_CAN_CTLR_CANM_HALT;
 	writew(ctlr, &priv->regs->ctlr);
@@ -870,6 +872,9 @@
 	u16 ctlr;
 	int err;
 
+	if (!netif_running(ndev))
+		return 0;
+
 	err = clk_enable(priv->clk);
 	if (err) {
 		netdev_err(ndev, "clk_enable() failed, error %d\n", err);
@@ -883,10 +888,9 @@
 	writew(ctlr, &priv->regs->ctlr);
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
-	if (netif_running(ndev)) {
-		netif_device_attach(ndev);
-		netif_start_queue(ndev);
-	}
+	netif_device_attach(ndev);
+	netif_start_queue(ndev);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/rcar/rcar_canfd.c
+++ linux-ein-5.4.0/drivers/net/can/rcar/rcar_canfd.c
@@ -1075,7 +1075,7 @@
 	struct rcar_canfd_global *gpriv = dev_id;
 	struct net_device *ndev;
 	struct rcar_canfd_channel *priv;
-	u32 sts, gerfl;
+	u32 sts, cc, gerfl;
 	u32 ch, ridx;
 
 	/* Global error interrupts still indicate a condition specific
@@ -1093,7 +1093,9 @@
 
 		/* Handle Rx interrupts */
 		sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx));
-		if (likely(sts & RCANFD_RFSTS_RFIF)) {
+		cc = rcar_canfd_read(priv->base, RCANFD_RFCC(ridx));
+		if (likely(sts & RCANFD_RFSTS_RFIF &&
+			   cc & RCANFD_RFCC_RFIE)) {
 			if (napi_schedule_prep(&priv->napi)) {
 				/* Disable Rx FIFO interrupts */
 				rcar_canfd_clear_bit(priv->base,
@@ -1598,15 +1600,15 @@
 
 	netif_napi_add(ndev, &priv->napi, rcar_canfd_rx_poll,
 		       RCANFD_NAPI_WEIGHT);
+	spin_lock_init(&priv->tx_lock);
+	devm_can_led_init(ndev);
+	gpriv->ch[priv->channel] = priv;
 	err = register_candev(ndev);
 	if (err) {
 		dev_err(&pdev->dev,
 			"register_candev() failed, error %d\n", err);
 		goto fail_candev;
 	}
-	spin_lock_init(&priv->tx_lock);
-	devm_can_led_init(ndev);
-	gpriv->ch[priv->channel] = priv;
 	dev_info(&pdev->dev, "device registered (channel %u)\n", priv->channel);
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/net/can/sja1000/ems_pcmcia.c
+++ linux-ein-5.4.0/drivers/net/can/sja1000/ems_pcmcia.c
@@ -235,7 +235,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-ein-5.4.0.orig/drivers/net/can/sja1000/peak_pci.c
+++ linux-ein-5.4.0/drivers/net/can/sja1000/peak_pci.c
@@ -731,16 +731,15 @@
 		struct net_device *prev_dev = chan->prev_dev;
 
 		dev_info(&pdev->dev, "removing device %s\n", dev->name);
+		/* do that only for first channel */
+		if (!prev_dev && chan->pciec_card)
+			peak_pciec_remove(chan->pciec_card);
 		unregister_sja1000dev(dev);
 		free_sja1000dev(dev);
 		dev = prev_dev;
 
-		if (!dev) {
-			/* do that only for first channel */
-			if (chan->pciec_card)
-				peak_pciec_remove(chan->pciec_card);
+		if (!dev)
 			break;
-		}
 		priv = netdev_priv(dev);
 		chan = priv->priv;
 	}
--- linux-ein-5.4.0.orig/drivers/net/can/sja1000/sja1000.c
+++ linux-ein-5.4.0/drivers/net/can/sja1000/sja1000.c
@@ -405,9 +405,6 @@
 	txerr = priv->read_reg(priv, SJA1000_TXERR);
 	rxerr = priv->read_reg(priv, SJA1000_RXERR);
 
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
-
 	if (isrc & IRQ_DOI) {
 		/* data overrun interrupt */
 		netdev_dbg(dev, "data overrun interrupt\n");
@@ -429,6 +426,10 @@
 		else
 			state = CAN_STATE_ERROR_ACTIVE;
 	}
+	if (state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
+	}
 	if (isrc & IRQ_BEI) {
 		/* bus error interrupt */
 		priv->can.can_stats.bus_error++;
--- linux-ein-5.4.0.orig/drivers/net/can/sja1000/sja1000_isa.c
+++ linux-ein-5.4.0/drivers/net/can/sja1000/sja1000_isa.c
@@ -202,22 +202,24 @@
 	if (err) {
 		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
 			DRV_NAME, err);
-		goto exit_unmap;
+		goto exit_free;
 	}
 
 	dev_info(&pdev->dev, "%s device registered (reg_base=0x%p, irq=%d)\n",
 		 DRV_NAME, priv->reg_base, dev->irq);
 	return 0;
 
- exit_unmap:
+exit_free:
+	free_sja1000dev(dev);
+exit_unmap:
 	if (mem[idx])
 		iounmap(base);
- exit_release:
+exit_release:
 	if (mem[idx])
 		release_mem_region(mem[idx], iosize);
 	else
 		release_region(port[idx], iosize);
- exit:
+exit:
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/slcan.c
+++ linux-ein-5.4.0/drivers/net/can/slcan.c
@@ -148,7 +148,7 @@
 	u32 tmpid;
 	char *cmd = sl->rbuff;
 
-	cf.can_id = 0;
+	memset(&cf, 0, sizeof(cf));
 
 	switch (*cmd) {
 	case 'r':
@@ -187,8 +187,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. */
@@ -514,6 +519,7 @@
 	int i;
 	char name[IFNAMSIZ];
 	struct net_device *dev = NULL;
+	struct can_ml_priv *can_ml;
 	struct slcan       *sl;
 	int size;
 
@@ -536,7 +542,8 @@
 
 	dev->base_addr  = i;
 	sl = netdev_priv(dev);
-	dev->ml_priv = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
+	can_ml = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
+	can_set_ml_priv(dev, can_ml);
 
 	/* Initialize channel control data */
 	sl->magic = SLCAN_MAGIC;
@@ -617,7 +624,11 @@
 	sl->tty = NULL;
 	tty->disc_data = NULL;
 	clear_bit(SLF_INUSE, &sl->flags);
+	slc_free_netdev(sl->dev);
+	/* do not call free_netdev before rtnl_unlock */
+	rtnl_unlock();
 	free_netdev(sl->dev);
+	return err;
 
 err_exit:
 	rtnl_unlock();
@@ -643,10 +654,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-ein-5.4.0.orig/drivers/net/can/softing/softing_cs.c
+++ linux-ein-5.4.0/drivers/net/can/softing/softing_cs.c
@@ -293,7 +293,7 @@
 	return 0;
 
 platform_failed:
-	kfree(dev);
+	platform_device_put(pdev);
 mem_failed:
 pcmcia_bad:
 pcmcia_failed:
--- linux-ein-5.4.0.orig/drivers/net/can/softing/softing_fw.c
+++ linux-ein-5.4.0/drivers/net/can/softing/softing_fw.c
@@ -565,18 +565,19 @@
 		if (ret < 0)
 			goto failed;
 	}
-	/* enable_error_frame */
-	/*
+
+	/* enable_error_frame
+	 *
 	 * Error reporting is switched off at the moment since
 	 * the receiving of them is not yet 100% verified
 	 * This should be enabled sooner or later
-	 *
-	if (error_reporting) {
+	 */
+	if (0 && error_reporting) {
 		ret = softing_fct_cmd(card, 51, "enable_error_frame");
 		if (ret < 0)
 			goto failed;
 	}
-	*/
+
 	/* initialize interface */
 	iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
 	iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
--- linux-ein-5.4.0.orig/drivers/net/can/softing/softing_main.c
+++ linux-ein-5.4.0/drivers/net/can/softing/softing_main.c
@@ -382,8 +382,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-ein-5.4.0.orig/drivers/net/can/spi/hi311x.c
+++ linux-ein-5.4.0/drivers/net/can/spi/hi311x.c
@@ -218,7 +218,7 @@
 	return ret;
 }
 
-static u8 hi3110_cmd(struct spi_device *spi, u8 command)
+static int hi3110_cmd(struct spi_device *spi, u8 command)
 {
 	struct hi3110_priv *priv = spi_get_drvdata(spi);
 
@@ -670,8 +670,6 @@
 
 			txerr = hi3110_read(spi, HI3110_READ_TEC);
 			rxerr = hi3110_read(spi, HI3110_READ_REC);
-			cf->data[6] = txerr;
-			cf->data[7] = rxerr;
 			tx_state = txerr >= rxerr ? new_state : 0;
 			rx_state = txerr <= rxerr ? new_state : 0;
 			can_change_state(net, cf, tx_state, rx_state);
@@ -684,6 +682,9 @@
 					hi3110_hw_sleep(spi);
 					break;
 				}
+			} else {
+				cf->data[6] = txerr;
+				cf->data[7] = rxerr;
 			}
 		}
 
--- linux-ein-5.4.0.orig/drivers/net/can/spi/mcp251x.c
+++ linux-ein-5.4.0/drivers/net/can/spi/mcp251x.c
@@ -39,6 +39,7 @@
 #include <linux/spi/spi.h>
 #include <linux/uaccess.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
 
 /* SPI interface instruction set */
 #define INSTRUCTION_WRITE	0x02
@@ -597,6 +598,7 @@
 			return -EBUSY;
 		}
 	}
+
 	return 0;
 }
 
@@ -756,9 +758,6 @@
 
 		mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
 
-		/* mask out flags we don't care about */
-		intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR;
-
 		/* receive buffer 0 */
 		if (intf & CANINTF_RX0IF) {
 			mcp251x_hw_rx(spi, 0);
@@ -768,6 +767,18 @@
 			if (mcp251x_is_2510(spi))
 				mcp251x_write_bits(spi, CANINTF,
 						   CANINTF_RX0IF, 0x00);
+
+			/* check if buffer 1 is already known to be full, no need to re-read */
+			if (!(intf & CANINTF_RX1IF)) {
+				u8 intf1, eflag1;
+
+				/* intf needs to be read again to avoid a race condition */
+				mcp251x_read_2regs(spi, CANINTF, &intf1, &eflag1);
+
+				/* combine flags from both operations for error handling */
+				intf |= intf1;
+				eflag |= eflag1;
+			}
 		}
 
 		/* receive buffer 1 */
@@ -778,6 +789,9 @@
 				clear_intf |= CANINTF_RX1IF;
 		}
 
+		/* mask out flags we don't care about */
+		intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR;
+
 		/* any error or tx interrupt we need to clear? */
 		if (intf & (CANINTF_ERR | CANINTF_TX))
 			clear_intf |= intf & (CANINTF_ERR | CANINTF_TX);
@@ -991,6 +1005,8 @@
 	struct mcp251x_priv *priv;
 	struct clk *clk;
 	int freq, ret;
+	struct device_node *np = spi->dev.of_node;
+	int standby_gpio;
 
 	clk = devm_clk_get_optional(&spi->dev, NULL);
 	if (IS_ERR(clk))
@@ -1013,6 +1029,15 @@
 	if (ret)
 		goto out_free;
 
+	standby_gpio = of_get_named_gpio(np, "standby-gpios", 0);
+	dev_dbg(&spi->dev, "can bus standby gpio=%d, freq=%d\n", standby_gpio, freq);
+	if (standby_gpio > 0) {
+		ret = devm_gpio_request_one(&spi->dev, standby_gpio, GPIOF_OUT_INIT_LOW, "CAN standby");
+		if (ret) {
+			dev_err(&spi->dev, "unable to get can standby gpio\n");
+		}
+	}
+
 	net->netdev_ops = &mcp251x_netdev_ops;
 	net->flags |= IFF_ECHO;
 
--- linux-ein-5.4.0.orig/drivers/net/can/sun4i_can.c
+++ linux-ein-5.4.0/drivers/net/can/sun4i_can.c
@@ -525,11 +525,6 @@
 	rxerr = (errc >> 16) & 0xFF;
 	txerr = errc & 0xFF;
 
-	if (skb) {
-		cf->data[6] = txerr;
-		cf->data[7] = rxerr;
-	}
-
 	if (isrc & SUN4I_INT_DATA_OR) {
 		/* data overrun interrupt */
 		netdev_dbg(dev, "data overrun interrupt\n");
@@ -560,6 +555,10 @@
 		else
 			state = CAN_STATE_ERROR_ACTIVE;
 	}
+	if (skb && state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
+	}
 	if (isrc & SUN4I_INT_BUS_ERR) {
 		/* bus error interrupt */
 		netdev_dbg(dev, "bus error interrupt\n");
--- linux-ein-5.4.0.orig/drivers/net/can/ti_hecc.c
+++ linux-ein-5.4.0/drivers/net/can/ti_hecc.c
@@ -535,15 +535,28 @@
 	return container_of(offload, struct ti_hecc_priv, offload);
 }
 
-static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
-					 struct can_frame *cf,
-					 u32 *timestamp, unsigned int mbxno)
+static struct sk_buff *ti_hecc_mailbox_read(struct can_rx_offload *offload,
+					    unsigned int mbxno, u32 *timestamp,
+					    bool drop)
 {
 	struct ti_hecc_priv *priv = rx_offload_to_priv(offload);
+	struct sk_buff *skb;
+	struct can_frame *cf;
 	u32 data, mbx_mask;
-	int ret = 1;
 
 	mbx_mask = BIT(mbxno);
+
+	if (unlikely(drop)) {
+		skb = ERR_PTR(-ENOBUFS);
+		goto mark_as_read;
+	}
+
+	skb = alloc_can_skb(offload->dev, &cf);
+	if (unlikely(!skb)) {
+		skb = ERR_PTR(-ENOMEM);
+		goto mark_as_read;
+	}
+
 	data = hecc_read_mbx(priv, mbxno, HECC_CANMID);
 	if (data & HECC_CANMID_IDE)
 		cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
@@ -578,11 +591,12 @@
 	 */
 	if (unlikely(mbxno == HECC_RX_LAST_MBOX &&
 		     hecc_read(priv, HECC_CANRML) & mbx_mask))
-		ret = -ENOBUFS;
+		skb = ERR_PTR(-ENOBUFS);
 
+ mark_as_read:
 	hecc_write(priv, HECC_CANRMP, mbx_mask);
 
-	return ret;
+	return skb;
 }
 
 static int ti_hecc_error(struct net_device *ndev, int int_status,
@@ -873,7 +887,8 @@
 	priv->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(priv->base)) {
 		dev_err(&pdev->dev, "hecc ioremap failed\n");
-		return PTR_ERR(priv->base);
+		err = PTR_ERR(priv->base);
+		goto probe_exit_candev;
 	}
 
 	/* handle hecc-ram memory */
@@ -886,7 +901,8 @@
 	priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(priv->hecc_ram)) {
 		dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
-		return PTR_ERR(priv->hecc_ram);
+		err = PTR_ERR(priv->hecc_ram);
+		goto probe_exit_candev;
 	}
 
 	/* handle mbx memory */
@@ -899,13 +915,14 @@
 	priv->mbx = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(priv->mbx)) {
 		dev_err(&pdev->dev, "mbx ioremap failed\n");
-		return PTR_ERR(priv->mbx);
+		err = PTR_ERR(priv->mbx);
+		goto probe_exit_candev;
 	}
 
 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!irq) {
 		dev_err(&pdev->dev, "No irq resource\n");
-		goto probe_exit;
+		goto probe_exit_candev;
 	}
 
 	priv->ndev = ndev;
@@ -936,7 +953,7 @@
 	err = clk_prepare_enable(priv->clk);
 	if (err) {
 		dev_err(&pdev->dev, "clk_prepare_enable() failed\n");
-		goto probe_exit_clk;
+		goto probe_exit_release_clk;
 	}
 
 	priv->offload.mailbox_read = ti_hecc_mailbox_read;
@@ -945,7 +962,7 @@
 	err = can_rx_offload_add_timestamp(ndev, &priv->offload);
 	if (err) {
 		dev_err(&pdev->dev, "can_rx_offload_add_timestamp() failed\n");
-		goto probe_exit_clk;
+		goto probe_exit_disable_clk;
 	}
 
 	err = register_candev(ndev);
@@ -963,11 +980,13 @@
 
 probe_exit_offload:
 	can_rx_offload_del(&priv->offload);
-probe_exit_clk:
+probe_exit_disable_clk:
+	clk_disable_unprepare(priv->clk);
+probe_exit_release_clk:
 	clk_put(priv->clk);
 probe_exit_candev:
 	free_candev(ndev);
-probe_exit:
+
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/usb/ems_usb.c
+++ linux-ein-5.4.0/drivers/net/can/usb/ems_usb.c
@@ -194,7 +194,7 @@
 	__le32 ts_sec;	/* timestamp in seconds */
 	__le32 ts_nsec;	/* timestamp in nano seconds */
 
-	union {
+	union __packed {
 		u8 generic[64];
 		struct cpc_can_msg can_msg;
 		struct cpc_can_params can_params;
@@ -255,6 +255,8 @@
 	unsigned int free_slots; /* remember number of available slots */
 
 	struct ems_cpc_msg active_params; /* active controller parameters */
+	void *rxbuf[MAX_RX_URBS];
+	dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 static void ems_usb_read_interrupt_callback(struct urb *urb)
@@ -587,6 +589,7 @@
 	for (i = 0; i < MAX_RX_URBS; i++) {
 		struct urb *urb = NULL;
 		u8 *buf = NULL;
+		dma_addr_t buf_dma;
 
 		/* create a URB, and a buffer for it */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -596,7 +599,7 @@
 		}
 
 		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-					 &urb->transfer_dma);
+					 &buf_dma);
 		if (!buf) {
 			netdev_err(netdev, "No memory left for USB buffer\n");
 			usb_free_urb(urb);
@@ -604,6 +607,8 @@
 			break;
 		}
 
+		urb->transfer_dma = buf_dma;
+
 		usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
 				  buf, RX_BUFFER_SIZE,
 				  ems_usb_read_bulk_callback, dev);
@@ -619,6 +624,9 @@
 			break;
 		}
 
+		dev->rxbuf[i] = buf;
+		dev->rxbuf_dma[i] = buf_dma;
+
 		/* Drop reference, USB core will take care of freeing it */
 		usb_free_urb(urb);
 	}
@@ -684,6 +692,10 @@
 
 	usb_kill_anchored_urbs(&dev->rx_submitted);
 
+	for (i = 0; i < MAX_RX_URBS; ++i)
+		usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
+				  dev->rxbuf[i], dev->rxbuf_dma[i]);
+
 	usb_kill_anchored_urbs(&dev->tx_submitted);
 	atomic_set(&dev->active_tx_urbs, 0);
 
@@ -811,7 +823,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);
 
@@ -1053,7 +1064,6 @@
 
 	if (dev) {
 		unregister_netdev(dev->netdev);
-		free_candev(dev->netdev);
 
 		unlink_all_urbs(dev);
 
@@ -1061,6 +1071,8 @@
 
 		kfree(dev->intr_in_buffer);
 		kfree(dev->tx_msg_buffer);
+
+		free_candev(dev->netdev);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/can/usb/esd_usb2.c
+++ linux-ein-5.4.0/drivers/net/can/usb/esd_usb2.c
@@ -195,6 +195,8 @@
 	int net_count;
 	u32 version;
 	int rxinitdone;
+	void *rxbuf[MAX_RX_URBS];
+	dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 struct esd_usb2_net_priv {
@@ -222,8 +224,12 @@
 	if (id == ESD_EV_CAN_ERROR_EXT) {
 		u8 state = msg->msg.rx.data[0];
 		u8 ecc = msg->msg.rx.data[1];
-		u8 txerr = msg->msg.rx.data[2];
-		u8 rxerr = msg->msg.rx.data[3];
+		u8 rxerr = msg->msg.rx.data[2];
+		u8 txerr = msg->msg.rx.data[3];
+
+		netdev_dbg(priv->netdev,
+			   "CAN_ERR_EV_EXT: dlc=%#02x state=%02x ecc=%02x rec=%02x tec=%02x\n",
+			   msg->msg.rx.dlc, state, ecc, rxerr, txerr);
 
 		skb = alloc_can_err_skb(priv->netdev, &cf);
 		if (skb == NULL) {
@@ -251,6 +257,8 @@
 				break;
 			default:
 				priv->can.state = CAN_STATE_ERROR_ACTIVE;
+				txerr = 0;
+				rxerr = 0;
 				break;
 			}
 		} else {
@@ -270,7 +278,6 @@
 				cf->data[2] |= CAN_ERR_PROT_STUFF;
 				break;
 			default:
-				cf->data[3] = ecc & SJA1000_ECC_SEG;
 				break;
 			}
 
@@ -278,6 +285,9 @@
 			if (!(ecc & SJA1000_ECC_DIR))
 				cf->data[2] |= CAN_ERR_PROT_TX;
 
+			/* Bit stream position in CAN frame as the error was detected */
+			cf->data[3] = ecc & SJA1000_ECC_SEG;
+
 			if (priv->can.state == CAN_STATE_ERROR_WARNING ||
 			    priv->can.state == CAN_STATE_ERROR_PASSIVE) {
 				cf->data[1] = (txerr > rxerr) ?
@@ -544,6 +554,7 @@
 	for (i = 0; i < MAX_RX_URBS; i++) {
 		struct urb *urb = NULL;
 		u8 *buf = NULL;
+		dma_addr_t buf_dma;
 
 		/* create a URB, and a buffer for it */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -553,7 +564,7 @@
 		}
 
 		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-					 &urb->transfer_dma);
+					 &buf_dma);
 		if (!buf) {
 			dev_warn(dev->udev->dev.parent,
 				 "No memory left for USB buffer\n");
@@ -561,6 +572,8 @@
 			goto freeurb;
 		}
 
+		urb->transfer_dma = buf_dma;
+
 		usb_fill_bulk_urb(urb, dev->udev,
 				  usb_rcvbulkpipe(dev->udev, 1),
 				  buf, RX_BUFFER_SIZE,
@@ -573,8 +586,12 @@
 			usb_unanchor_urb(urb);
 			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
 					  urb->transfer_dma);
+			goto freeurb;
 		}
 
+		dev->rxbuf[i] = buf;
+		dev->rxbuf_dma[i] = buf_dma;
+
 freeurb:
 		/* Drop reference, USB core will take care of freeing it */
 		usb_free_urb(urb);
@@ -662,6 +679,11 @@
 	int i, j;
 
 	usb_kill_anchored_urbs(&dev->rx_submitted);
+
+	for (i = 0; i < MAX_RX_URBS; ++i)
+		usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
+				  dev->rxbuf[i], dev->rxbuf_dma[i]);
+
 	for (i = 0; i < dev->net_count; i++) {
 		priv = dev->nets[i];
 		if (priv) {
--- linux-ein-5.4.0.orig/drivers/net/can/usb/gs_usb.c
+++ linux-ein-5.4.0/drivers/net/can/usb/gs_usb.c
@@ -63,21 +63,27 @@
 };
 
 /* data types passed between host and device */
+
+/* The firmware on the original USB2CAN by Geschwister Schneider
+ * Technologie Entwicklungs- und Vertriebs UG exchanges all data
+ * between the host and the device in host byte order. This is done
+ * with the struct gs_host_config::byte_order member, which is sent
+ * first to indicate the desired byte order.
+ *
+ * The widely used open source firmware candleLight doesn't support
+ * this feature and exchanges the data in little endian byte order.
+ */
 struct gs_host_config {
-	u32 byte_order;
+	__le32 byte_order;
 } __packed;
-/* All data exchanged between host and device is exchanged in host byte order,
- * thanks to the struct gs_host_config byte_order member, which is sent first
- * to indicate the desired byte order.
- */
 
 struct gs_device_config {
 	u8 reserved1;
 	u8 reserved2;
 	u8 reserved3;
 	u8 icount;
-	u32 sw_version;
-	u32 hw_version;
+	__le32 sw_version;
+	__le32 hw_version;
 } __packed;
 
 #define GS_CAN_MODE_NORMAL               0
@@ -87,26 +93,26 @@
 #define GS_CAN_MODE_ONE_SHOT             BIT(3)
 
 struct gs_device_mode {
-	u32 mode;
-	u32 flags;
+	__le32 mode;
+	__le32 flags;
 } __packed;
 
 struct gs_device_state {
-	u32 state;
-	u32 rxerr;
-	u32 txerr;
+	__le32 state;
+	__le32 rxerr;
+	__le32 txerr;
 } __packed;
 
 struct gs_device_bittiming {
-	u32 prop_seg;
-	u32 phase_seg1;
-	u32 phase_seg2;
-	u32 sjw;
-	u32 brp;
+	__le32 prop_seg;
+	__le32 phase_seg1;
+	__le32 phase_seg2;
+	__le32 sjw;
+	__le32 brp;
 } __packed;
 
 struct gs_identify_mode {
-	u32 mode;
+	__le32 mode;
 } __packed;
 
 #define GS_CAN_FEATURE_LISTEN_ONLY      BIT(0)
@@ -117,23 +123,23 @@
 #define GS_CAN_FEATURE_IDENTIFY         BIT(5)
 
 struct gs_device_bt_const {
-	u32 feature;
-	u32 fclk_can;
-	u32 tseg1_min;
-	u32 tseg1_max;
-	u32 tseg2_min;
-	u32 tseg2_max;
-	u32 sjw_max;
-	u32 brp_min;
-	u32 brp_max;
-	u32 brp_inc;
+	__le32 feature;
+	__le32 fclk_can;
+	__le32 tseg1_min;
+	__le32 tseg1_max;
+	__le32 tseg2_min;
+	__le32 tseg2_max;
+	__le32 sjw_max;
+	__le32 brp_min;
+	__le32 brp_max;
+	__le32 brp_inc;
 } __packed;
 
 #define GS_CAN_FLAG_OVERFLOW 1
 
 struct gs_host_frame {
 	u32 echo_id;
-	u32 can_id;
+	__le32 can_id;
 
 	u8 can_dlc;
 	u8 channel;
@@ -178,14 +184,16 @@
 
 	struct usb_anchor tx_submitted;
 	atomic_t active_tx_urbs;
+	void *rxbuf[GS_MAX_RX_URBS];
+	dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
 };
 
 /* usb interface struct */
 struct gs_usb {
 	struct gs_can *canch[GS_MAX_INTF];
 	struct usb_anchor rx_submitted;
-	atomic_t active_channels;
 	struct usb_device *udev;
+	u8 active_channels;
 };
 
 /* 'allocate' a tx context.
@@ -314,7 +322,7 @@
 
 	/* device reports out of range channel id */
 	if (hf->channel >= GS_MAX_INTF)
-		goto resubmit_urb;
+		goto device_detach;
 
 	dev = usbcan->canch[hf->channel];
 
@@ -329,13 +337,13 @@
 		if (!skb)
 			return;
 
-		cf->can_id = hf->can_id;
+		cf->can_id = le32_to_cpu(hf->can_id);
 
 		cf->can_dlc = get_can_dlc(hf->can_dlc);
 		memcpy(cf->data, hf->data, 8);
 
 		/* ERROR frames tell us information about the controller */
-		if (hf->can_id & CAN_ERR_FLAG)
+		if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
 			gs_update_state(dev, cf);
 
 		netdev->stats.rx_packets++;
@@ -373,6 +381,9 @@
 	}
 
 	if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
+		stats->rx_over_errors++;
+		stats->rx_errors++;
+
 		skb = alloc_can_err_skb(netdev, &cf);
 		if (!skb)
 			goto resubmit_urb;
@@ -380,8 +391,6 @@
 		cf->can_id |= CAN_ERR_CRTL;
 		cf->can_dlc = CAN_ERR_DLC;
 		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-		stats->rx_over_errors++;
-		stats->rx_errors++;
 		netif_rx(skb);
 	}
 
@@ -399,6 +408,7 @@
 
 	/* USB failure take down all interfaces */
 	if (rc == -ENODEV) {
+ device_detach:
 		for (rc = 0; rc < GS_MAX_INTF; rc++) {
 			if (usbcan->canch[rc])
 				netif_device_detach(usbcan->canch[rc]->netdev);
@@ -418,11 +428,11 @@
 	if (!dbt)
 		return -ENOMEM;
 
-	dbt->prop_seg = bt->prop_seg;
-	dbt->phase_seg1 = bt->phase_seg1;
-	dbt->phase_seg2 = bt->phase_seg2;
-	dbt->sjw = bt->sjw;
-	dbt->brp = bt->brp;
+	dbt->prop_seg = cpu_to_le32(bt->prop_seg);
+	dbt->phase_seg1 = cpu_to_le32(bt->phase_seg1);
+	dbt->phase_seg2 = cpu_to_le32(bt->phase_seg2);
+	dbt->sjw = cpu_to_le32(bt->sjw);
+	dbt->brp = cpu_to_le32(bt->brp);
 
 	/* request bit timings */
 	rc = usb_control_msg(interface_to_usbdev(intf),
@@ -500,10 +510,12 @@
 
 	hf->echo_id = idx;
 	hf->channel = dev->channel;
+	hf->flags = 0;
+	hf->reserved = 0;
 
 	cf = (struct can_frame *)skb->data;
 
-	hf->can_id = cf->can_id;
+	hf->can_id = cpu_to_le32(cf->can_id);
 	hf->can_dlc = cf->can_dlc;
 	memcpy(hf->data, cf->data, cf->can_dlc);
 
@@ -573,15 +585,17 @@
 	int rc, i;
 	struct gs_device_mode *dm;
 	u32 ctrlmode;
+	u32 flags = 0;
 
 	rc = open_candev(netdev);
 	if (rc)
 		return rc;
 
-	if (atomic_add_return(1, &parent->active_channels) == 1) {
+	if (!parent->active_channels) {
 		for (i = 0; i < GS_MAX_RX_URBS; i++) {
 			struct urb *urb;
 			u8 *buf;
+			dma_addr_t buf_dma;
 
 			/* alloc rx urb */
 			urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -592,7 +606,7 @@
 			buf = usb_alloc_coherent(dev->udev,
 						 sizeof(struct gs_host_frame),
 						 GFP_KERNEL,
-						 &urb->transfer_dma);
+						 &buf_dma);
 			if (!buf) {
 				netdev_err(netdev,
 					   "No memory left for USB buffer\n");
@@ -600,6 +614,8 @@
 				return -ENOMEM;
 			}
 
+			urb->transfer_dma = buf_dma;
+
 			/* fill, anchor, and submit rx urb */
 			usb_fill_bulk_urb(urb,
 					  dev->udev,
@@ -623,10 +639,17 @@
 					   rc);
 
 				usb_unanchor_urb(urb);
+				usb_free_coherent(dev->udev,
+						  sizeof(struct gs_host_frame),
+						  buf,
+						  buf_dma);
 				usb_free_urb(urb);
 				break;
 			}
 
+			dev->rxbuf[i] = buf;
+			dev->rxbuf_dma[i] = buf_dma;
+
 			/* Drop reference,
 			 * USB core will take care of freeing it
 			 */
@@ -640,24 +663,25 @@
 
 	/* flags */
 	ctrlmode = dev->can.ctrlmode;
-	dm->flags = 0;
 
 	if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
-		dm->flags |= GS_CAN_MODE_LOOP_BACK;
+		flags |= GS_CAN_MODE_LOOP_BACK;
 	else if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
-		dm->flags |= GS_CAN_MODE_LISTEN_ONLY;
+		flags |= GS_CAN_MODE_LISTEN_ONLY;
 
 	/* Controller is not allowed to retry TX
 	 * this mode is unavailable on atmels uc3c hardware
 	 */
 	if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
-		dm->flags |= GS_CAN_MODE_ONE_SHOT;
+		flags |= GS_CAN_MODE_ONE_SHOT;
 
 	if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
-		dm->flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
+		flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
 
 	/* finally start device */
-	dm->mode = GS_CAN_MODE_START;
+	dev->can.state = CAN_STATE_ERROR_ACTIVE;
+	dm->mode = cpu_to_le32(GS_CAN_MODE_START);
+	dm->flags = cpu_to_le32(flags);
 	rc = usb_control_msg(interface_to_usbdev(dev->iface),
 			     usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0),
 			     GS_USB_BREQ_MODE,
@@ -672,13 +696,13 @@
 	if (rc < 0) {
 		netdev_err(netdev, "Couldn't start device (err=%d)\n", rc);
 		kfree(dm);
+		dev->can.state = CAN_STATE_STOPPED;
 		return rc;
 	}
 
 	kfree(dm);
 
-	dev->can.state = CAN_STATE_ERROR_ACTIVE;
-
+	parent->active_channels++;
 	if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
 		netif_start_queue(netdev);
 
@@ -690,17 +714,27 @@
 	int rc;
 	struct gs_can *dev = netdev_priv(netdev);
 	struct gs_usb *parent = dev->parent;
+	unsigned int i;
 
 	netif_stop_queue(netdev);
 
 	/* Stop polling */
-	if (atomic_dec_and_test(&parent->active_channels))
+	parent->active_channels--;
+	if (!parent->active_channels) {
 		usb_kill_anchored_urbs(&parent->rx_submitted);
+		for (i = 0; i < GS_MAX_RX_URBS; i++)
+			usb_free_coherent(dev->udev,
+					  sizeof(struct gs_host_frame),
+					  dev->rxbuf[i],
+					  dev->rxbuf_dma[i]);
+	}
 
 	/* Stop sending URBs */
 	usb_kill_anchored_urbs(&dev->tx_submitted);
 	atomic_set(&dev->active_tx_urbs, 0);
 
+	dev->can.state = CAN_STATE_STOPPED;
+
 	/* reset the device */
 	rc = gs_cmd_reset(dev);
 	if (rc < 0)
@@ -737,9 +771,9 @@
 		return -ENOMEM;
 
 	if (do_identify)
-		imode->mode = GS_CAN_IDENTIFY_ON;
+		imode->mode = cpu_to_le32(GS_CAN_IDENTIFY_ON);
 	else
-		imode->mode = GS_CAN_IDENTIFY_OFF;
+		imode->mode = cpu_to_le32(GS_CAN_IDENTIFY_OFF);
 
 	rc = usb_control_msg(interface_to_usbdev(dev->iface),
 			     usb_sndctrlpipe(interface_to_usbdev(dev->iface),
@@ -790,6 +824,7 @@
 	struct net_device *netdev;
 	int rc;
 	struct gs_device_bt_const *bt_const;
+	u32 feature;
 
 	bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL);
 	if (!bt_const)
@@ -830,14 +865,14 @@
 
 	/* dev settup */
 	strcpy(dev->bt_const.name, "gs_usb");
-	dev->bt_const.tseg1_min = bt_const->tseg1_min;
-	dev->bt_const.tseg1_max = bt_const->tseg1_max;
-	dev->bt_const.tseg2_min = bt_const->tseg2_min;
-	dev->bt_const.tseg2_max = bt_const->tseg2_max;
-	dev->bt_const.sjw_max = bt_const->sjw_max;
-	dev->bt_const.brp_min = bt_const->brp_min;
-	dev->bt_const.brp_max = bt_const->brp_max;
-	dev->bt_const.brp_inc = bt_const->brp_inc;
+	dev->bt_const.tseg1_min = le32_to_cpu(bt_const->tseg1_min);
+	dev->bt_const.tseg1_max = le32_to_cpu(bt_const->tseg1_max);
+	dev->bt_const.tseg2_min = le32_to_cpu(bt_const->tseg2_min);
+	dev->bt_const.tseg2_max = le32_to_cpu(bt_const->tseg2_max);
+	dev->bt_const.sjw_max = le32_to_cpu(bt_const->sjw_max);
+	dev->bt_const.brp_min = le32_to_cpu(bt_const->brp_min);
+	dev->bt_const.brp_max = le32_to_cpu(bt_const->brp_max);
+	dev->bt_const.brp_inc = le32_to_cpu(bt_const->brp_inc);
 
 	dev->udev = interface_to_usbdev(intf);
 	dev->iface = intf;
@@ -854,28 +889,29 @@
 
 	/* can settup */
 	dev->can.state = CAN_STATE_STOPPED;
-	dev->can.clock.freq = bt_const->fclk_can;
+	dev->can.clock.freq = le32_to_cpu(bt_const->fclk_can);
 	dev->can.bittiming_const = &dev->bt_const;
 	dev->can.do_set_bittiming = gs_usb_set_bittiming;
 
 	dev->can.ctrlmode_supported = 0;
 
-	if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY)
+	feature = le32_to_cpu(bt_const->feature);
+	if (feature & GS_CAN_FEATURE_LISTEN_ONLY)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
-	if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK)
+	if (feature & GS_CAN_FEATURE_LOOP_BACK)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK;
 
-	if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE)
+	if (feature & GS_CAN_FEATURE_TRIPLE_SAMPLE)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 
-	if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT)
+	if (feature & GS_CAN_FEATURE_ONE_SHOT)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
 
 	SET_NETDEV_DEV(netdev, &intf->dev);
 
-	if (dconf->sw_version > 1)
-		if (bt_const->feature & GS_CAN_FEATURE_IDENTIFY)
+	if (le32_to_cpu(dconf->sw_version) > 1)
+		if (feature & GS_CAN_FEATURE_IDENTIFY)
 			netdev->ethtool_ops = &gs_usb_ethtool_ops;
 
 	kfree(bt_const);
@@ -910,7 +946,7 @@
 	if (!hconf)
 		return -ENOMEM;
 
-	hconf->byte_order = 0x0000beef;
+	hconf->byte_order = cpu_to_le32(0x0000beef);
 
 	/* send host config */
 	rc = usb_control_msg(interface_to_usbdev(intf),
@@ -918,7 +954,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);
@@ -941,7 +977,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);
@@ -971,8 +1007,6 @@
 
 	init_usb_anchor(&dev->rx_submitted);
 
-	atomic_set(&dev->active_channels, 0);
-
 	usb_set_intfdata(intf, dev);
 	dev->udev = interface_to_usbdev(intf);
 
--- linux-ein-5.4.0.orig/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+++ linux-ein-5.4.0/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
@@ -35,9 +35,10 @@
 #define KVASER_USB_RX_BUFFER_SIZE		3072
 #define KVASER_USB_MAX_NET_DEVICES		5
 
-/* USB devices features */
-#define KVASER_USB_HAS_SILENT_MODE		BIT(0)
-#define KVASER_USB_HAS_TXRX_ERRORS		BIT(1)
+/* Kvaser USB device quirks */
+#define KVASER_USB_QUIRK_HAS_SILENT_MODE	BIT(0)
+#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS	BIT(1)
+#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ	BIT(2)
 
 /* Device capabilities */
 #define KVASER_USB_CAP_BERR_CAP			0x01
@@ -65,12 +66,7 @@
 struct kvaser_usb_dev_card_data {
 	u32 ctrlmode_supported;
 	u32 capabilities;
-	union {
-		struct {
-			enum kvaser_usb_leaf_family family;
-		} leaf;
-		struct kvaser_usb_dev_card_data_hydra hydra;
-	};
+	struct kvaser_usb_dev_card_data_hydra hydra;
 };
 
 /* Context for an outstanding, not yet ACKed, transmission */
@@ -80,11 +76,19 @@
 	int dlc;
 };
 
+struct kvaser_usb_busparams {
+	__le32 bitrate;
+	u8 tseg1;
+	u8 tseg2;
+	u8 sjw;
+	u8 nsamples;
+} __packed;
+
 struct kvaser_usb {
 	struct usb_device *udev;
 	struct usb_interface *intf;
 	struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
-	const struct kvaser_usb_dev_ops *ops;
+	const struct kvaser_usb_driver_info *driver_info;
 	const struct kvaser_usb_dev_cfg *cfg;
 
 	struct usb_endpoint_descriptor *bulk_in, *bulk_out;
@@ -108,13 +112,19 @@
 	struct can_priv can;
 	struct can_berr_counter bec;
 
+	/* subdriver-specific data */
+	void *sub_priv;
+
 	struct kvaser_usb *dev;
 	struct net_device *netdev;
 	int channel;
 
-	struct completion start_comp, stop_comp, flush_comp;
+	struct completion start_comp, stop_comp, flush_comp,
+			  get_busparams_comp;
 	struct usb_anchor tx_submitted;
 
+	struct kvaser_usb_busparams busparams_nominal, busparams_data;
+
 	spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */
 	int active_tx_contexts;
 	struct kvaser_usb_tx_urb_context tx_contexts[];
@@ -124,11 +134,15 @@
  * struct kvaser_usb_dev_ops - Device specific functions
  * @dev_set_mode:		used for can.do_set_mode
  * @dev_set_bittiming:		used for can.do_set_bittiming
+ * @dev_get_busparams:		readback arbitration busparams
  * @dev_set_data_bittiming:	used for can.do_set_data_bittiming
+ * @dev_get_data_busparams:	readback data busparams
  * @dev_get_berr_counter:	used for can.do_get_berr_counter
  *
  * @dev_setup_endpoints:	setup USB in and out endpoints
  * @dev_init_card:		initialize card
+ * @dev_init_channel:		initialize channel
+ * @dev_remove_channel:		uninitialize channel
  * @dev_get_software_info:	get software info
  * @dev_get_software_details:	get software details
  * @dev_get_card_info:		get card info
@@ -144,12 +158,18 @@
  */
 struct kvaser_usb_dev_ops {
 	int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode);
-	int (*dev_set_bittiming)(struct net_device *netdev);
-	int (*dev_set_data_bittiming)(struct net_device *netdev);
+	int (*dev_set_bittiming)(const struct net_device *netdev,
+				 const struct kvaser_usb_busparams *busparams);
+	int (*dev_get_busparams)(struct kvaser_usb_net_priv *priv);
+	int (*dev_set_data_bittiming)(const struct net_device *netdev,
+				      const struct kvaser_usb_busparams *busparams);
+	int (*dev_get_data_busparams)(struct kvaser_usb_net_priv *priv);
 	int (*dev_get_berr_counter)(const struct net_device *netdev,
 				    struct can_berr_counter *bec);
 	int (*dev_setup_endpoints)(struct kvaser_usb *dev);
 	int (*dev_init_card)(struct kvaser_usb *dev);
+	int (*dev_init_channel)(struct kvaser_usb_net_priv *priv);
+	void (*dev_remove_channel)(struct kvaser_usb_net_priv *priv);
 	int (*dev_get_software_info)(struct kvaser_usb *dev);
 	int (*dev_get_software_details)(struct kvaser_usb *dev);
 	int (*dev_get_card_info)(struct kvaser_usb *dev);
@@ -166,6 +186,12 @@
 				  int *cmd_len, u16 transid);
 };
 
+struct kvaser_usb_driver_info {
+	u32 quirks;
+	enum kvaser_usb_leaf_family family;
+	const struct kvaser_usb_dev_ops *ops;
+};
+
 struct kvaser_usb_dev_cfg {
 	const struct can_clock clock;
 	const unsigned int timestamp_freq;
@@ -176,6 +202,8 @@
 extern const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops;
 extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops;
 
+void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv);
+
 int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len,
 			int *actual_len);
 
@@ -185,4 +213,7 @@
 			      int len);
 
 int kvaser_usb_can_rx_over_error(struct net_device *netdev);
+
+extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
+
 #endif /* KVASER_USB_H */
--- linux-ein-5.4.0.orig/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ linux-ein-5.4.0/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -79,104 +79,134 @@
 #define USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID	269
 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID	270
 
-static inline bool kvaser_is_leaf(const struct usb_device_id *id)
-{
-	return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
-		id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
-		(id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
-		 id->idProduct <= USB_MINI_PCIE_2HS_PRODUCT_ID);
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
+	.quirks = 0,
+	.ops = &kvaser_usb_hydra_dev_ops,
+};
 
-static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
-{
-	return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
-	       id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
+	.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+		  KVASER_USB_QUIRK_HAS_SILENT_MODE,
+	.family = KVASER_USBCAN,
+	.ops = &kvaser_usb_leaf_dev_ops,
+};
 
-static inline bool kvaser_is_hydra(const struct usb_device_id *id)
-{
-	return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
-	       id->idProduct <= USB_HYBRID_PRO_CANLIN_PRODUCT_ID;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
+	.quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+	.family = KVASER_LEAF,
+	.ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
+	.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+		  KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+	.family = KVASER_LEAF,
+	.ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
+	.quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+		  KVASER_USB_QUIRK_HAS_SILENT_MODE |
+		  KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+	.family = KVASER_LEAF,
+	.ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
+	.quirks = 0,
+	.ops = &kvaser_usb_leaf_dev_ops,
+};
 
 static const struct usb_device_id kvaser_usb_table[] = {
-	/* Leaf USB product IDs */
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+	/* Leaf M32C USB product IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-			       KVASER_USB_HAS_SILENT_MODE },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+
+	/* Leaf i.MX28 USB product IDs */
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
 
 	/* USBCANII USB product IDs */
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 	{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
-		.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 
 	/* Minihydra USB product IDs */
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-	{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+	{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
+		.driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -267,6 +297,7 @@
 static void kvaser_usb_read_bulk_callback(struct urb *urb)
 {
 	struct kvaser_usb *dev = urb->context;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
 	int err;
 	unsigned int i;
 
@@ -283,8 +314,8 @@
 		goto resubmit_urb;
 	}
 
-	dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
-					 urb->actual_length);
+	ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
+				    urb->actual_length);
 
 resubmit_urb:
 	usb_fill_bulk_urb(urb, dev->udev,
@@ -378,21 +409,18 @@
 {
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
 	struct kvaser_usb *dev = priv->dev;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
 	int err;
 
 	err = open_candev(netdev);
 	if (err)
 		return err;
 
-	err = kvaser_usb_setup_rx_urbs(dev);
-	if (err)
-		goto error;
-
-	err = dev->ops->dev_set_opt_mode(priv);
+	err = ops->dev_set_opt_mode(priv);
 	if (err)
 		goto error;
 
-	err = dev->ops->dev_start_chip(priv);
+	err = ops->dev_start_chip(priv);
 	if (err) {
 		netdev_warn(netdev, "Cannot start device, error %d\n", err);
 		goto error;
@@ -421,7 +449,7 @@
 /* This method might sleep. Do not call it in the atomic context
  * of URB completions.
  */
-static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
 {
 	usb_kill_anchored_urbs(&priv->tx_submitted);
 	kvaser_usb_reset_tx_urb_contexts(priv);
@@ -449,22 +477,23 @@
 {
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
 	struct kvaser_usb *dev = priv->dev;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
 	int err;
 
 	netif_stop_queue(netdev);
 
-	err = dev->ops->dev_flush_queue(priv);
+	err = ops->dev_flush_queue(priv);
 	if (err)
 		netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
 
-	if (dev->ops->dev_reset_chip) {
-		err = dev->ops->dev_reset_chip(dev, priv->channel);
+	if (ops->dev_reset_chip) {
+		err = ops->dev_reset_chip(dev, priv->channel);
 		if (err)
 			netdev_warn(netdev, "Cannot reset card, error %d\n",
 				    err);
 	}
 
-	err = dev->ops->dev_stop_chip(priv);
+	err = ops->dev_stop_chip(priv);
 	if (err)
 		netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
@@ -477,6 +506,93 @@
 	return 0;
 }
 
+static int kvaser_usb_set_bittiming(struct net_device *netdev)
+{
+	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+	struct kvaser_usb *dev = priv->dev;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+	struct can_bittiming *bt = &priv->can.bittiming;
+
+	struct kvaser_usb_busparams busparams;
+	int tseg1 = bt->prop_seg + bt->phase_seg1;
+	int tseg2 = bt->phase_seg2;
+	int sjw = bt->sjw;
+	int err = -EOPNOTSUPP;
+
+	busparams.bitrate = cpu_to_le32(bt->bitrate);
+	busparams.sjw = (u8)sjw;
+	busparams.tseg1 = (u8)tseg1;
+	busparams.tseg2 = (u8)tseg2;
+	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+		busparams.nsamples = 3;
+	else
+		busparams.nsamples = 1;
+
+	err = ops->dev_set_bittiming(netdev, &busparams);
+	if (err)
+		return err;
+
+	err = kvaser_usb_setup_rx_urbs(priv->dev);
+	if (err)
+		return err;
+
+	err = ops->dev_get_busparams(priv);
+	if (err) {
+		/* Treat EOPNOTSUPP as success */
+		if (err == -EOPNOTSUPP)
+			err = 0;
+		return err;
+	}
+
+	if (memcmp(&busparams, &priv->busparams_nominal,
+		   sizeof(priv->busparams_nominal)) != 0)
+		err = -EINVAL;
+
+	return err;
+}
+
+static int kvaser_usb_set_data_bittiming(struct net_device *netdev)
+{
+	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+	struct kvaser_usb *dev = priv->dev;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+	struct can_bittiming *dbt = &priv->can.data_bittiming;
+
+	struct kvaser_usb_busparams busparams;
+	int tseg1 = dbt->prop_seg + dbt->phase_seg1;
+	int tseg2 = dbt->phase_seg2;
+	int sjw = dbt->sjw;
+	int err;
+
+	if (!ops->dev_set_data_bittiming ||
+	    !ops->dev_get_data_busparams)
+		return -EOPNOTSUPP;
+
+	busparams.bitrate = cpu_to_le32(dbt->bitrate);
+	busparams.sjw = (u8)sjw;
+	busparams.tseg1 = (u8)tseg1;
+	busparams.tseg2 = (u8)tseg2;
+	busparams.nsamples = 1;
+
+	err = ops->dev_set_data_bittiming(netdev, &busparams);
+	if (err)
+		return err;
+
+	err = kvaser_usb_setup_rx_urbs(priv->dev);
+	if (err)
+		return err;
+
+	err = ops->dev_get_data_busparams(priv);
+	if (err)
+		return err;
+
+	if (memcmp(&busparams, &priv->busparams_data,
+		   sizeof(priv->busparams_data)) != 0)
+		err = -EINVAL;
+
+	return err;
+}
+
 static void kvaser_usb_write_bulk_callback(struct urb *urb)
 {
 	struct kvaser_usb_tx_urb_context *context = urb->context;
@@ -503,6 +619,7 @@
 {
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
 	struct kvaser_usb *dev = priv->dev;
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
 	struct net_device_stats *stats = &netdev->stats;
 	struct kvaser_usb_tx_urb_context *context = NULL;
 	struct urb *urb;
@@ -545,8 +662,8 @@
 		goto freeurb;
 	}
 
-	buf = dev->ops->dev_frame_to_cmd(priv, skb, &context->dlc, &cmd_len,
-					 context->echo_index);
+	buf = ops->dev_frame_to_cmd(priv, skb, &context->dlc, &cmd_len,
+				    context->echo_index);
 	if (!buf) {
 		stats->tx_dropped++;
 		dev_kfree_skb(skb);
@@ -611,6 +728,7 @@
 
 static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
 {
+	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
 	int i;
 
 	for (i = 0; i < dev->nchannels; i++) {
@@ -626,19 +744,23 @@
 		if (!dev->nets[i])
 			continue;
 
+		if (ops->dev_remove_channel)
+			ops->dev_remove_channel(dev->nets[i]);
+
 		free_candev(dev->nets[i]->netdev);
 	}
 }
 
-static int kvaser_usb_init_one(struct kvaser_usb *dev,
-			       const struct usb_device_id *id, int channel)
+static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
 {
 	struct net_device *netdev;
 	struct kvaser_usb_net_priv *priv;
+	const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
+	const struct kvaser_usb_dev_ops *ops = driver_info->ops;
 	int err;
 
-	if (dev->ops->dev_reset_chip) {
-		err = dev->ops->dev_reset_chip(dev, channel);
+	if (ops->dev_reset_chip) {
+		err = ops->dev_reset_chip(dev, channel);
 		if (err)
 			return err;
 	}
@@ -655,6 +777,8 @@
 	init_usb_anchor(&priv->tx_submitted);
 	init_completion(&priv->start_comp);
 	init_completion(&priv->stop_comp);
+	init_completion(&priv->flush_comp);
+	init_completion(&priv->get_busparams_comp);
 	priv->can.ctrlmode_supported = 0;
 
 	priv->dev = dev;
@@ -667,20 +791,19 @@
 	priv->can.state = CAN_STATE_STOPPED;
 	priv->can.clock.freq = dev->cfg->clock.freq;
 	priv->can.bittiming_const = dev->cfg->bittiming_const;
-	priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
-	priv->can.do_set_mode = dev->ops->dev_set_mode;
-	if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
+	priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
+	priv->can.do_set_mode = ops->dev_set_mode;
+	if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
 	    (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
-		priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
-	if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
+		priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
+	if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
 		priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
 	priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
 
 	if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
 		priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
-		priv->can.do_set_data_bittiming =
-					dev->ops->dev_set_data_bittiming;
+		priv->can.do_set_data_bittiming = kvaser_usb_set_data_bittiming;
 	}
 
 	netdev->flags |= IFF_ECHO;
@@ -692,17 +815,26 @@
 
 	dev->nets[channel] = priv;
 
+	if (ops->dev_init_channel) {
+		err = ops->dev_init_channel(priv);
+		if (err)
+			goto err;
+	}
+
 	err = register_candev(netdev);
 	if (err) {
 		dev_err(&dev->intf->dev, "Failed to register CAN device\n");
-		free_candev(netdev);
-		dev->nets[channel] = NULL;
-		return err;
+		goto err;
 	}
 
 	netdev_dbg(netdev, "device registered\n");
 
 	return 0;
+
+err:
+	free_candev(netdev);
+	dev->nets[channel] = NULL;
+	return err;
 }
 
 static int kvaser_usb_probe(struct usb_interface *intf,
@@ -711,29 +843,22 @@
 	struct kvaser_usb *dev;
 	int err;
 	int i;
+	const struct kvaser_usb_driver_info *driver_info;
+	const struct kvaser_usb_dev_ops *ops;
+
+	driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
+	if (!driver_info)
+		return -ENODEV;
 
 	dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return -ENOMEM;
 
-	if (kvaser_is_leaf(id)) {
-		dev->card_data.leaf.family = KVASER_LEAF;
-		dev->ops = &kvaser_usb_leaf_dev_ops;
-	} else if (kvaser_is_usbcan(id)) {
-		dev->card_data.leaf.family = KVASER_USBCAN;
-		dev->ops = &kvaser_usb_leaf_dev_ops;
-	} else if (kvaser_is_hydra(id)) {
-		dev->ops = &kvaser_usb_hydra_dev_ops;
-	} else {
-		dev_err(&intf->dev,
-			"Product ID (%d) is not a supported Kvaser USB device\n",
-			id->idProduct);
-		return -ENODEV;
-	}
-
 	dev->intf = intf;
+	dev->driver_info = driver_info;
+	ops = driver_info->ops;
 
-	err = dev->ops->dev_setup_endpoints(dev);
+	err = ops->dev_setup_endpoints(dev);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get usb endpoint(s)");
 		return err;
@@ -747,22 +872,22 @@
 
 	dev->card_data.ctrlmode_supported = 0;
 	dev->card_data.capabilities = 0;
-	err = dev->ops->dev_init_card(dev);
+	err = ops->dev_init_card(dev);
 	if (err) {
 		dev_err(&intf->dev,
 			"Failed to initialize card, error %d\n", err);
 		return err;
 	}
 
-	err = dev->ops->dev_get_software_info(dev);
+	err = ops->dev_get_software_info(dev);
 	if (err) {
 		dev_err(&intf->dev,
 			"Cannot get software info, error %d\n", err);
 		return err;
 	}
 
-	if (dev->ops->dev_get_software_details) {
-		err = dev->ops->dev_get_software_details(dev);
+	if (ops->dev_get_software_details) {
+		err = ops->dev_get_software_details(dev);
 		if (err) {
 			dev_err(&intf->dev,
 				"Cannot get software details, error %d\n", err);
@@ -780,14 +905,14 @@
 
 	dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
 
-	err = dev->ops->dev_get_card_info(dev);
+	err = ops->dev_get_card_info(dev);
 	if (err) {
 		dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
 		return err;
 	}
 
-	if (dev->ops->dev_get_capabilities) {
-		err = dev->ops->dev_get_capabilities(dev);
+	if (ops->dev_get_capabilities) {
+		err = ops->dev_get_capabilities(dev);
 		if (err) {
 			dev_err(&intf->dev,
 				"Cannot get capabilities, error %d\n", err);
@@ -797,7 +922,7 @@
 	}
 
 	for (i = 0; i < dev->nchannels; i++) {
-		err = kvaser_usb_init_one(dev, id, i);
+		err = kvaser_usb_init_one(dev, i);
 		if (err) {
 			kvaser_usb_remove_interfaces(dev);
 			return err;
--- linux-ein-5.4.0.orig/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+++ linux-ein-5.4.0/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
@@ -43,6 +43,8 @@
 
 /* Minihydra command IDs */
 #define CMD_SET_BUSPARAMS_REQ			16
+#define CMD_GET_BUSPARAMS_REQ			17
+#define CMD_GET_BUSPARAMS_RESP			18
 #define CMD_GET_CHIP_STATE_REQ			19
 #define CMD_CHIP_STATE_EVENT			20
 #define CMD_SET_DRIVERMODE_REQ			21
@@ -193,21 +195,26 @@
 #define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO	0x01
 #define KVASER_USB_HYDRA_BUS_MODE_NONISO	0x02
 struct kvaser_cmd_set_busparams {
-	__le32 bitrate;
-	u8 tseg1;
-	u8 tseg2;
-	u8 sjw;
-	u8 nsamples;
+	struct kvaser_usb_busparams busparams_nominal;
 	u8 reserved0[4];
-	__le32 bitrate_d;
-	u8 tseg1_d;
-	u8 tseg2_d;
-	u8 sjw_d;
-	u8 nsamples_d;
+	struct kvaser_usb_busparams busparams_data;
 	u8 canfd_mode;
 	u8 reserved1[7];
 } __packed;
 
+/* Busparam type */
+#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN	0x00
+#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD	0x01
+struct kvaser_cmd_get_busparams_req {
+	u8 type;
+	u8 reserved[27];
+} __packed;
+
+struct kvaser_cmd_get_busparams_res {
+	struct kvaser_usb_busparams busparams;
+	u8 reserved[20];
+} __packed;
+
 /* Ctrl modes */
 #define KVASER_USB_HYDRA_CTRLMODE_NORMAL	0x01
 #define KVASER_USB_HYDRA_CTRLMODE_LISTEN	0x02
@@ -278,6 +285,8 @@
 		struct kvaser_cmd_error_event error_event;
 
 		struct kvaser_cmd_set_busparams set_busparams_req;
+		struct kvaser_cmd_get_busparams_req get_busparams_req;
+		struct kvaser_cmd_get_busparams_res get_busparams_res;
 
 		struct kvaser_cmd_chip_state_event chip_state_event;
 
@@ -293,6 +302,7 @@
 #define KVASER_USB_HYDRA_CF_FLAG_OVERRUN	BIT(1)
 #define KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME	BIT(4)
 #define KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID	BIT(5)
+#define KVASER_USB_HYDRA_CF_FLAG_TX_ACK		BIT(6)
 /* CAN frame flags. Used in ext_rx_can and ext_tx_can */
 #define KVASER_USB_HYDRA_CF_FLAG_OSM_NACK	BIT(12)
 #define KVASER_USB_HYDRA_CF_FLAG_ABL		BIT(13)
@@ -359,6 +369,10 @@
 	} __packed;
 } __packed;
 
+struct kvaser_usb_net_hydra_priv {
+	int pending_get_busparams_type;
+};
+
 static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
 	.name = "kvaser_usb_kcan",
 	.tseg1_min = 1,
@@ -367,11 +381,11 @@
 	.tseg2_max = 32,
 	.sjw_max = 16,
 	.brp_min = 1,
-	.brp_max = 4096,
+	.brp_max = 8192,
 	.brp_inc = 1,
 };
 
-static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
+const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
 	.name = "kvaser_usb_flex",
 	.tseg1_min = 4,
 	.tseg1_max = 16,
@@ -504,6 +518,7 @@
 					    u8 cmd_no, int channel)
 {
 	struct kvaser_cmd *cmd;
+	size_t cmd_len;
 	int err;
 
 	cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
@@ -511,6 +526,7 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = cmd_no;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
 	if (channel < 0) {
 		kvaser_usb_hydra_set_cmd_dest_he
 				(cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL);
@@ -527,7 +543,7 @@
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 	if (err)
 		goto end;
 
@@ -543,6 +559,7 @@
 {
 	struct kvaser_cmd *cmd;
 	struct kvaser_usb *dev = priv->dev;
+	size_t cmd_len;
 	int err;
 
 	cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC);
@@ -550,14 +567,14 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = cmd_no;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
 
 	kvaser_usb_hydra_set_cmd_dest_he
 		(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd_async(priv, cmd,
-					kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd_async(priv, cmd, cmd_len);
 	if (err)
 		kfree(cmd);
 
@@ -701,6 +718,7 @@
 {
 	struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
 	struct kvaser_cmd *cmd;
+	size_t cmd_len;
 	u32 value = 0;
 	u32 mask = 0;
 	u16 cap_cmd_res;
@@ -712,13 +730,14 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = CMD_GET_CAPABILITIES_REQ;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
 	cmd->cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
 
 	kvaser_usb_hydra_set_cmd_dest_he(cmd, card_data->hydra.sysdbg_he);
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 	if (err)
 		goto end;
 
@@ -812,6 +831,39 @@
 	complete(&priv->flush_comp);
 }
 
+static void kvaser_usb_hydra_get_busparams_reply(const struct kvaser_usb *dev,
+						 const struct kvaser_cmd *cmd)
+{
+	struct kvaser_usb_net_priv *priv;
+	struct kvaser_usb_net_hydra_priv *hydra;
+
+	priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
+	if (!priv)
+		return;
+
+	hydra = priv->sub_priv;
+	if (!hydra)
+		return;
+
+	switch (hydra->pending_get_busparams_type) {
+	case KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN:
+		memcpy(&priv->busparams_nominal, &cmd->get_busparams_res.busparams,
+		       sizeof(priv->busparams_nominal));
+		break;
+	case KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD:
+		memcpy(&priv->busparams_data, &cmd->get_busparams_res.busparams,
+		       sizeof(priv->busparams_nominal));
+		break;
+	default:
+		dev_warn(&dev->intf->dev, "Unknown get_busparams_type %d\n",
+			 hydra->pending_get_busparams_type);
+		break;
+	}
+	hydra->pending_get_busparams_type = -1;
+
+	complete(&priv->get_busparams_comp);
+}
+
 static void
 kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv,
 					 u8 bus_status,
@@ -890,8 +942,10 @@
 	    new_state < CAN_STATE_BUS_OFF)
 		priv->can.can_stats.restarts++;
 
-	cf->data[6] = bec->txerr;
-	cf->data[7] = bec->rxerr;
+	if (new_state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = bec->txerr;
+		cf->data[7] = bec->rxerr;
+	}
 
 	stats = &netdev->stats;
 	stats->rx_packets++;
@@ -1045,8 +1099,10 @@
 	shhwtstamps->hwtstamp = hwtstamp;
 
 	cf->can_id |= CAN_ERR_BUSERROR;
-	cf->data[6] = bec.txerr;
-	cf->data[7] = bec.rxerr;
+	if (new_state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = bec.txerr;
+		cf->data[7] = bec.rxerr;
+	}
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
@@ -1095,6 +1151,7 @@
 	struct kvaser_usb_net_priv *priv;
 	unsigned long irq_flags;
 	bool one_shot_fail = false;
+	bool is_err_frame = false;
 	u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd);
 
 	priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
@@ -1113,10 +1170,13 @@
 			kvaser_usb_hydra_one_shot_fail(priv, cmd_ext);
 			one_shot_fail = true;
 		}
+
+		is_err_frame = flags & KVASER_USB_HYDRA_CF_FLAG_TX_ACK &&
+			       flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME;
 	}
 
 	context = &priv->tx_contexts[transid % dev->max_tx_urbs];
-	if (!one_shot_fail) {
+	if (!one_shot_fail && !is_err_frame) {
 		struct net_device_stats *stats = &priv->netdev->stats;
 
 		stats->tx_packets++;
@@ -1290,6 +1350,10 @@
 		kvaser_usb_hydra_state_event(dev, cmd);
 		break;
 
+	case CMD_GET_BUSPARAMS_RESP:
+		kvaser_usb_hydra_get_busparams_reply(dev, cmd);
+		break;
+
 	case CMD_ERROR_EVENT:
 		kvaser_usb_hydra_error_event(dev, cmd);
 		break;
@@ -1490,15 +1554,61 @@
 	return err;
 }
 
-static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
+static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
+					  int busparams_type)
+{
+	struct kvaser_usb *dev = priv->dev;
+	struct kvaser_usb_net_hydra_priv *hydra = priv->sub_priv;
+	struct kvaser_cmd *cmd;
+	size_t cmd_len;
+	int err;
+
+	if (!hydra)
+		return -EINVAL;
+
+	cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->header.cmd_no = CMD_GET_BUSPARAMS_REQ;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+	kvaser_usb_hydra_set_cmd_dest_he
+		(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
+	kvaser_usb_hydra_set_cmd_transid
+				(cmd, kvaser_usb_hydra_get_next_transid(dev));
+	cmd->get_busparams_req.type = busparams_type;
+	hydra->pending_get_busparams_type = busparams_type;
+
+	reinit_completion(&priv->get_busparams_comp);
+
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
+	if (err)
+		return err;
+
+	if (!wait_for_completion_timeout(&priv->get_busparams_comp,
+					 msecs_to_jiffies(KVASER_USB_TIMEOUT)))
+		return -ETIMEDOUT;
+
+	return err;
+}
+
+static int kvaser_usb_hydra_get_nominal_busparams(struct kvaser_usb_net_priv *priv)
+{
+	return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN);
+}
+
+static int kvaser_usb_hydra_get_data_busparams(struct kvaser_usb_net_priv *priv)
+{
+	return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD);
+}
+
+static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev,
+					  const struct kvaser_usb_busparams *busparams)
 {
 	struct kvaser_cmd *cmd;
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
-	struct can_bittiming *bt = &priv->can.bittiming;
 	struct kvaser_usb *dev = priv->dev;
-	int tseg1 = bt->prop_seg + bt->phase_seg1;
-	int tseg2 = bt->phase_seg2;
-	int sjw = bt->sjw;
+	size_t cmd_len;
 	int err;
 
 	cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
@@ -1506,33 +1616,29 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ;
-	cmd->set_busparams_req.bitrate = cpu_to_le32(bt->bitrate);
-	cmd->set_busparams_req.sjw = (u8)sjw;
-	cmd->set_busparams_req.tseg1 = (u8)tseg1;
-	cmd->set_busparams_req.tseg2 = (u8)tseg2;
-	cmd->set_busparams_req.nsamples = 1;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+	memcpy(&cmd->set_busparams_req.busparams_nominal, busparams,
+	       sizeof(cmd->set_busparams_req.busparams_nominal));
 
 	kvaser_usb_hydra_set_cmd_dest_he
 		(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 
 	kfree(cmd);
 
 	return err;
 }
 
-static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev)
+static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev,
+					       const struct kvaser_usb_busparams *busparams)
 {
 	struct kvaser_cmd *cmd;
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
-	struct can_bittiming *dbt = &priv->can.data_bittiming;
 	struct kvaser_usb *dev = priv->dev;
-	int tseg1 = dbt->prop_seg + dbt->phase_seg1;
-	int tseg2 = dbt->phase_seg2;
-	int sjw = dbt->sjw;
+	size_t cmd_len;
 	int err;
 
 	cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
@@ -1540,11 +1646,9 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ;
-	cmd->set_busparams_req.bitrate_d = cpu_to_le32(dbt->bitrate);
-	cmd->set_busparams_req.sjw_d = (u8)sjw;
-	cmd->set_busparams_req.tseg1_d = (u8)tseg1;
-	cmd->set_busparams_req.tseg2_d = (u8)tseg2;
-	cmd->set_busparams_req.nsamples_d = 1;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+	memcpy(&cmd->set_busparams_req.busparams_data, busparams,
+	       sizeof(cmd->set_busparams_req.busparams_data));
 
 	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
 		if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
@@ -1560,7 +1664,7 @@
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 
 	kfree(cmd);
 
@@ -1590,7 +1694,7 @@
 	struct usb_endpoint_descriptor *ep;
 	int i;
 
-	iface_desc = &dev->intf->altsetting[0];
+	iface_desc = dev->intf->cur_altsetting;
 
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		ep = &iface_desc->endpoint[i].desc;
@@ -1651,6 +1755,19 @@
 	return 0;
 }
 
+static int kvaser_usb_hydra_init_channel(struct kvaser_usb_net_priv *priv)
+{
+	struct kvaser_usb_net_hydra_priv *hydra;
+
+	hydra = devm_kzalloc(&priv->dev->intf->dev, sizeof(*hydra), GFP_KERNEL);
+	if (!hydra)
+		return -ENOMEM;
+
+	priv->sub_priv = hydra;
+
+	return 0;
+}
+
 static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev)
 {
 	struct kvaser_cmd cmd;
@@ -1675,6 +1792,7 @@
 static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev)
 {
 	struct kvaser_cmd *cmd;
+	size_t cmd_len;
 	int err;
 	u32 flags;
 	struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
@@ -1684,6 +1802,7 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = CMD_GET_SOFTWARE_DETAILS_REQ;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
 	cmd->sw_detail_req.use_ext_cmd = 1;
 	kvaser_usb_hydra_set_cmd_dest_he
 				(cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL);
@@ -1691,7 +1810,7 @@
 	kvaser_usb_hydra_set_cmd_transid
 				(cmd, kvaser_usb_hydra_get_next_transid(dev));
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 	if (err)
 		goto end;
 
@@ -1807,6 +1926,7 @@
 {
 	struct kvaser_usb *dev = priv->dev;
 	struct kvaser_cmd *cmd;
+	size_t cmd_len;
 	int err;
 
 	if ((priv->can.ctrlmode &
@@ -1822,6 +1942,7 @@
 		return -ENOMEM;
 
 	cmd->header.cmd_no = CMD_SET_DRIVERMODE_REQ;
+	cmd_len = kvaser_usb_hydra_cmd_size(cmd);
 	kvaser_usb_hydra_set_cmd_dest_he
 		(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
 	kvaser_usb_hydra_set_cmd_transid
@@ -1831,7 +1952,7 @@
 	else
 		cmd->set_ctrlmode.mode = KVASER_USB_HYDRA_CTRLMODE_NORMAL;
 
-	err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
+	err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
 	kfree(cmd);
 
 	return err;
@@ -1841,7 +1962,7 @@
 {
 	int err;
 
-	init_completion(&priv->start_comp);
+	reinit_completion(&priv->start_comp);
 
 	err = kvaser_usb_hydra_send_simple_cmd(priv->dev, CMD_START_CHIP_REQ,
 					       priv->channel);
@@ -1859,7 +1980,7 @@
 {
 	int err;
 
-	init_completion(&priv->stop_comp);
+	reinit_completion(&priv->stop_comp);
 
 	/* Make sure we do not report invalid BUS_OFF from CMD_CHIP_STATE_EVENT
 	 * see comment in kvaser_usb_hydra_update_state()
@@ -1882,7 +2003,7 @@
 {
 	int err;
 
-	init_completion(&priv->flush_comp);
+	reinit_completion(&priv->flush_comp);
 
 	err = kvaser_usb_hydra_send_simple_cmd(priv->dev, CMD_FLUSH_QUEUE,
 					       priv->channel);
@@ -1993,10 +2114,13 @@
 const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = {
 	.dev_set_mode = kvaser_usb_hydra_set_mode,
 	.dev_set_bittiming = kvaser_usb_hydra_set_bittiming,
+	.dev_get_busparams = kvaser_usb_hydra_get_nominal_busparams,
 	.dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming,
+	.dev_get_data_busparams = kvaser_usb_hydra_get_data_busparams,
 	.dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter,
 	.dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints,
 	.dev_init_card = kvaser_usb_hydra_init_card,
+	.dev_init_channel = kvaser_usb_hydra_init_channel,
 	.dev_get_software_info = kvaser_usb_hydra_get_software_info,
 	.dev_get_software_details = kvaser_usb_hydra_get_software_details,
 	.dev_get_card_info = kvaser_usb_hydra_get_card_info,
@@ -2024,5 +2148,5 @@
 		.freq = 24000000,
 	},
 	.timestamp_freq = 1,
-	.bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
+	.bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
--- linux-ein-5.4.0.orig/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ linux-ein-5.4.0/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/usb.h>
+#include <linux/workqueue.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -28,10 +29,6 @@
 
 #include "kvaser_usb.h"
 
-/* Forward declaration */
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg;
-
-#define CAN_USB_CLOCK			8000000
 #define MAX_USBCAN_NET_DEVICES		2
 
 /* Command header size */
@@ -59,6 +56,9 @@
 #define CMD_RX_EXT_MESSAGE		14
 #define CMD_TX_EXT_MESSAGE		15
 #define CMD_SET_BUS_PARAMS		16
+#define CMD_GET_BUS_PARAMS		17
+#define CMD_GET_BUS_PARAMS_REPLY	18
+#define CMD_GET_CHIP_STATE		19
 #define CMD_CHIP_STATE_EVENT		20
 #define CMD_SET_CTRL_MODE		21
 #define CMD_RESET_CHIP			24
@@ -73,13 +73,24 @@
 #define CMD_GET_CARD_INFO_REPLY		35
 #define CMD_GET_SOFTWARE_INFO		38
 #define CMD_GET_SOFTWARE_INFO_REPLY	39
+#define CMD_ERROR_EVENT			45
 #define CMD_FLUSH_QUEUE			48
 #define CMD_TX_ACKNOWLEDGE		50
 #define CMD_CAN_ERROR_EVENT		51
 #define CMD_FLUSH_QUEUE_REPLY		68
+#define CMD_GET_CAPABILITIES_REQ	95
+#define CMD_GET_CAPABILITIES_RESP	96
 
 #define CMD_LEAF_LOG_MESSAGE		106
 
+/* Leaf frequency options */
+#define KVASER_USB_LEAF_SWOPTION_FREQ_MASK 0x60
+#define KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK 0
+#define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
+#define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)
+
+#define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12)
+
 /* error factors */
 #define M16C_EF_ACKE			BIT(0)
 #define M16C_EF_CRCE			BIT(1)
@@ -98,16 +109,6 @@
 #define USBCAN_ERROR_STATE_RX_ERROR	BIT(1)
 #define USBCAN_ERROR_STATE_BUSERROR	BIT(2)
 
-/* bittiming parameters */
-#define KVASER_USB_TSEG1_MIN		1
-#define KVASER_USB_TSEG1_MAX		16
-#define KVASER_USB_TSEG2_MIN		1
-#define KVASER_USB_TSEG2_MAX		8
-#define KVASER_USB_SJW_MAX		4
-#define KVASER_USB_BRP_MIN		1
-#define KVASER_USB_BRP_MAX		64
-#define KVASER_USB_BRP_INC		1
-
 /* ctrl modes */
 #define KVASER_CTRL_MODE_NORMAL		1
 #define KVASER_CTRL_MODE_SILENT		2
@@ -164,11 +165,7 @@
 struct kvaser_cmd_busparams {
 	u8 tid;
 	u8 channel;
-	__le32 bitrate;
-	u8 tseg1;
-	u8 tseg2;
-	u8 sjw;
-	u8 no_samp;
+	struct kvaser_usb_busparams busparams;
 } __packed;
 
 struct kvaser_cmd_tx_can {
@@ -237,7 +234,7 @@
 	u8 tid;
 } __packed;
 
-struct leaf_cmd_error_event {
+struct leaf_cmd_can_error_event {
 	u8 tid;
 	u8 flags;
 	__le16 time[3];
@@ -249,7 +246,7 @@
 	u8 error_factor;
 } __packed;
 
-struct usbcan_cmd_error_event {
+struct usbcan_cmd_can_error_event {
 	u8 tid;
 	u8 padding;
 	u8 tx_errors_count_ch0;
@@ -261,6 +258,28 @@
 	__le16 time;
 } __packed;
 
+/* CMD_ERROR_EVENT error codes */
+#define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8
+#define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9
+
+struct leaf_cmd_error_event {
+	u8 tid;
+	u8 error_code;
+	__le16 timestamp[3];
+	__le16 padding;
+	__le16 info1;
+	__le16 info2;
+} __packed;
+
+struct usbcan_cmd_error_event {
+	u8 tid;
+	u8 error_code;
+	__le16 info1;
+	__le16 info2;
+	__le16 timestamp;
+	__le16 padding;
+} __packed;
+
 struct kvaser_cmd_ctrl_mode {
 	u8 tid;
 	u8 channel;
@@ -285,6 +304,28 @@
 	u8 data[8];
 } __packed;
 
+/* Sub commands for cap_req and cap_res */
+#define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02
+#define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05
+struct kvaser_cmd_cap_req {
+	__le16 padding0;
+	__le16 cap_cmd;
+	__le16 padding1;
+	__le16 channel;
+} __packed;
+
+/* Status codes for cap_res */
+#define KVASER_USB_LEAF_CAP_STAT_OK 0x00
+#define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01
+#define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02
+struct kvaser_cmd_cap_res {
+	__le16 padding;
+	__le16 cap_cmd;
+	__le16 status;
+	__le32 mask;
+	__le32 value;
+} __packed;
+
 struct kvaser_cmd {
 	u8 len;
 	u8 id;
@@ -300,14 +341,18 @@
 			struct leaf_cmd_softinfo softinfo;
 			struct leaf_cmd_rx_can rx_can;
 			struct leaf_cmd_chip_state_event chip_state_event;
-			struct leaf_cmd_error_event error_event;
+			struct leaf_cmd_can_error_event can_error_event;
 			struct leaf_cmd_log_message log_message;
+			struct leaf_cmd_error_event error_event;
+			struct kvaser_cmd_cap_req cap_req;
+			struct kvaser_cmd_cap_res cap_res;
 		} __packed leaf;
 
 		union {
 			struct usbcan_cmd_softinfo softinfo;
 			struct usbcan_cmd_rx_can rx_can;
 			struct usbcan_cmd_chip_state_event chip_state_event;
+			struct usbcan_cmd_can_error_event can_error_event;
 			struct usbcan_cmd_error_event error_event;
 		} __packed usbcan;
 
@@ -317,6 +362,42 @@
 	} u;
 } __packed;
 
+#define CMD_SIZE_ANY 0xff
+#define kvaser_fsize(field) sizeof_field(struct kvaser_cmd, field)
+
+static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
+	[CMD_START_CHIP_REPLY]		= kvaser_fsize(u.simple),
+	[CMD_STOP_CHIP_REPLY]		= kvaser_fsize(u.simple),
+	[CMD_GET_CARD_INFO_REPLY]	= kvaser_fsize(u.cardinfo),
+	[CMD_TX_ACKNOWLEDGE]		= kvaser_fsize(u.tx_acknowledge_header),
+	[CMD_GET_SOFTWARE_INFO_REPLY]	= kvaser_fsize(u.leaf.softinfo),
+	[CMD_RX_STD_MESSAGE]		= kvaser_fsize(u.leaf.rx_can),
+	[CMD_RX_EXT_MESSAGE]		= kvaser_fsize(u.leaf.rx_can),
+	[CMD_LEAF_LOG_MESSAGE]		= kvaser_fsize(u.leaf.log_message),
+	[CMD_CHIP_STATE_EVENT]		= kvaser_fsize(u.leaf.chip_state_event),
+	[CMD_CAN_ERROR_EVENT]		= kvaser_fsize(u.leaf.can_error_event),
+	[CMD_GET_CAPABILITIES_RESP]	= kvaser_fsize(u.leaf.cap_res),
+	[CMD_GET_BUS_PARAMS_REPLY]	= kvaser_fsize(u.busparams),
+	[CMD_ERROR_EVENT]		= kvaser_fsize(u.leaf.error_event),
+	/* ignored events: */
+	[CMD_FLUSH_QUEUE_REPLY]		= CMD_SIZE_ANY,
+};
+
+static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
+	[CMD_START_CHIP_REPLY]		= kvaser_fsize(u.simple),
+	[CMD_STOP_CHIP_REPLY]		= kvaser_fsize(u.simple),
+	[CMD_GET_CARD_INFO_REPLY]	= kvaser_fsize(u.cardinfo),
+	[CMD_TX_ACKNOWLEDGE]		= kvaser_fsize(u.tx_acknowledge_header),
+	[CMD_GET_SOFTWARE_INFO_REPLY]	= kvaser_fsize(u.usbcan.softinfo),
+	[CMD_RX_STD_MESSAGE]		= kvaser_fsize(u.usbcan.rx_can),
+	[CMD_RX_EXT_MESSAGE]		= kvaser_fsize(u.usbcan.rx_can),
+	[CMD_CHIP_STATE_EVENT]		= kvaser_fsize(u.usbcan.chip_state_event),
+	[CMD_CAN_ERROR_EVENT]		= kvaser_fsize(u.usbcan.can_error_event),
+	[CMD_ERROR_EVENT]		= kvaser_fsize(u.usbcan.error_event),
+	/* ignored events: */
+	[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
+};
+
 /* Summary of a kvaser error event, for a unified Leaf/Usbcan error
  * handling. Some discrepancies between the two families exist:
  *
@@ -340,6 +421,113 @@
 	};
 };
 
+struct kvaser_usb_net_leaf_priv {
+	struct kvaser_usb_net_priv *net;
+
+	struct delayed_work chip_state_req_work;
+};
+
+static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
+	.name = "kvaser_usb_ucii",
+	.tseg1_min = 4,
+	.tseg1_max = 16,
+	.tseg2_min = 2,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 16,
+	.brp_inc = 1,
+};
+
+static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
+	.name = "kvaser_usb_leaf",
+	.tseg1_min = 3,
+	.tseg1_max = 16,
+	.tseg2_min = 2,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 2,
+	.brp_max = 128,
+	.brp_inc = 2,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
+	.clock = {
+		.freq = 8000000,
+	},
+	.timestamp_freq = 1,
+	.bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
+	.clock = {
+		.freq = 16000000,
+	},
+	.timestamp_freq = 1,
+	.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
+	.clock = {
+		.freq = 16000000,
+	},
+	.timestamp_freq = 1,
+	.bittiming_const = &kvaser_usb_flexc_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
+	.clock = {
+		.freq = 24000000,
+	},
+	.timestamp_freq = 1,
+	.bittiming_const = &kvaser_usb_flexc_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
+	.clock = {
+		.freq = 32000000,
+	},
+	.timestamp_freq = 1,
+	.bittiming_const = &kvaser_usb_flexc_bittiming_const,
+};
+
+static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
+				       const struct kvaser_cmd *cmd)
+{
+	/* buffer size >= cmd->len ensured by caller */
+	u8 min_size = 0;
+
+	switch (dev->driver_info->family) {
+	case KVASER_LEAF:
+		if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_leaf))
+			min_size = kvaser_usb_leaf_cmd_sizes_leaf[cmd->id];
+		break;
+	case KVASER_USBCAN:
+		if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_usbcan))
+			min_size = kvaser_usb_leaf_cmd_sizes_usbcan[cmd->id];
+		break;
+	}
+
+	if (min_size == CMD_SIZE_ANY)
+		return 0;
+
+	if (min_size) {
+		min_size += CMD_HEADER_LEN;
+		if (cmd->len >= min_size)
+			return 0;
+
+		dev_err_ratelimited(&dev->intf->dev,
+				    "Received command %u too short (size %u, needed %u)",
+				    cmd->id, cmd->len, min_size);
+		return -EIO;
+	}
+
+	dev_warn_ratelimited(&dev->intf->dev,
+			     "Unhandled command (%d, size %d)\n",
+			     cmd->id, cmd->len);
+	return -EINVAL;
+}
+
 static void *
 kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
 			     const struct sk_buff *skb, int *frame_len,
@@ -359,7 +547,7 @@
 				      sizeof(struct kvaser_cmd_tx_can);
 		cmd->u.tx_can.channel = priv->channel;
 
-		switch (dev->card_data.leaf.family) {
+		switch (dev->driver_info->family) {
 		case KVASER_LEAF:
 			cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
 			break;
@@ -447,6 +635,9 @@
 end:
 	kfree(buf);
 
+	if (err == 0)
+		err = kvaser_usb_leaf_verify_size(dev, cmd);
+
 	return err;
 }
 
@@ -471,6 +662,37 @@
 	return rc;
 }
 
+static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
+						   const struct leaf_cmd_softinfo *softinfo)
+{
+	u32 sw_options = le32_to_cpu(softinfo->sw_options);
+
+	dev->fw_version = le32_to_cpu(softinfo->fw_version);
+	dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
+
+	if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP)
+		dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP;
+
+	if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
+		/* Firmware expects bittiming parameters calculated for 16MHz
+		 * clock, regardless of the actual clock
+		 */
+		dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
+	} else {
+		switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+		case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+			dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
+			break;
+		case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+			dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
+			break;
+		case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+			dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
+			break;
+		}
+	}
+}
+
 static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
 {
 	struct kvaser_cmd cmd;
@@ -484,16 +706,15 @@
 	if (err)
 		return err;
 
-	switch (dev->card_data.leaf.family) {
+	switch (dev->driver_info->family) {
 	case KVASER_LEAF:
-		dev->fw_version = le32_to_cpu(cmd.u.leaf.softinfo.fw_version);
-		dev->max_tx_urbs =
-			le16_to_cpu(cmd.u.leaf.softinfo.max_outstanding_tx);
+		kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
 		break;
 	case KVASER_USBCAN:
 		dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
 		dev->max_tx_urbs =
 			le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
+		dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
 		break;
 	}
 
@@ -532,13 +753,123 @@
 
 	dev->nchannels = cmd.u.cardinfo.nchannels;
 	if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
-	    (dev->card_data.leaf.family == KVASER_USBCAN &&
+	    (dev->driver_info->family == KVASER_USBCAN &&
 	     dev->nchannels > MAX_USBCAN_NET_DEVICES))
 		return -EINVAL;
 
 	return 0;
 }
 
+static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
+						 u16 cap_cmd_req, u16 *status)
+{
+	struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
+	struct kvaser_cmd *cmd;
+	u32 value = 0;
+	u32 mask = 0;
+	u16 cap_cmd_res;
+	int err;
+	int i;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->id = CMD_GET_CAPABILITIES_REQ;
+	cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
+	cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req);
+
+	err = kvaser_usb_send_cmd(dev, cmd, cmd->len);
+	if (err)
+		goto end;
+
+	err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd);
+	if (err)
+		goto end;
+
+	*status = le16_to_cpu(cmd->u.leaf.cap_res.status);
+
+	if (*status != KVASER_USB_LEAF_CAP_STAT_OK)
+		goto end;
+
+	cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd);
+	switch (cap_cmd_res) {
+	case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+	case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+		value = le32_to_cpu(cmd->u.leaf.cap_res.value);
+		mask = le32_to_cpu(cmd->u.leaf.cap_res.mask);
+		break;
+	default:
+		dev_warn(&dev->intf->dev, "Unknown capability command %u\n",
+			 cap_cmd_res);
+		break;
+	}
+
+	for (i = 0; i < dev->nchannels; i++) {
+		if (BIT(i) & (value & mask)) {
+			switch (cap_cmd_res) {
+			case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+				card_data->ctrlmode_supported |=
+						CAN_CTRLMODE_LISTENONLY;
+				break;
+			case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+				card_data->capabilities |=
+						KVASER_USB_CAP_BERR_CAP;
+				break;
+			}
+		}
+	}
+
+end:
+	kfree(cmd);
+
+	return err;
+}
+
+static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
+{
+	int err;
+	u16 status;
+
+	if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
+		dev_info(&dev->intf->dev,
+			 "No extended capability support. Upgrade device firmware.\n");
+		return 0;
+	}
+
+	err = kvaser_usb_leaf_get_single_capability(dev,
+						    KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
+						    &status);
+	if (err)
+		return err;
+	if (status)
+		dev_info(&dev->intf->dev,
+			 "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
+			 status);
+
+	err = kvaser_usb_leaf_get_single_capability(dev,
+						    KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
+						    &status);
+	if (err)
+		return err;
+	if (status)
+		dev_info(&dev->intf->dev,
+			 "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n",
+			 status);
+
+	return 0;
+}
+
+static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
+{
+	int err = 0;
+
+	if (dev->driver_info->family == KVASER_LEAF)
+		err = kvaser_usb_leaf_get_capabilities_leaf(dev);
+
+	return err;
+}
+
 static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
 					   const struct kvaser_cmd *cmd)
 {
@@ -567,7 +898,7 @@
 	context = &priv->tx_contexts[tid % dev->max_tx_urbs];
 
 	/* Sometimes the state change doesn't come after a bus-off event */
-	if (priv->can.restart_ms && priv->can.state >= CAN_STATE_BUS_OFF) {
+	if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) {
 		struct sk_buff *skb;
 		struct can_frame *cf;
 
@@ -608,7 +939,7 @@
 	struct kvaser_cmd *cmd;
 	int err;
 
-	cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
 	if (!cmd)
 		return -ENOMEM;
 
@@ -623,6 +954,16 @@
 	return err;
 }
 
+static void kvaser_usb_leaf_chip_state_req_work(struct work_struct *work)
+{
+	struct kvaser_usb_net_leaf_priv *leaf =
+		container_of(work, struct kvaser_usb_net_leaf_priv,
+			     chip_state_req_work.work);
+	struct kvaser_usb_net_priv *priv = leaf->net;
+
+	kvaser_usb_leaf_simple_cmd_async(priv, CMD_GET_CHIP_STATE);
+}
+
 static void
 kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
 					const struct kvaser_usb_err_summary *es,
@@ -641,20 +982,16 @@
 		new_state = CAN_STATE_BUS_OFF;
 	} else if (es->status & M16C_STATE_BUS_PASSIVE) {
 		new_state = CAN_STATE_ERROR_PASSIVE;
-	} else if (es->status & M16C_STATE_BUS_ERROR) {
+	} else if ((es->status & M16C_STATE_BUS_ERROR) &&
+		   cur_state >= CAN_STATE_BUS_OFF) {
 		/* Guard against spurious error events after a busoff */
-		if (cur_state < CAN_STATE_BUS_OFF) {
-			if (es->txerr >= 128 || es->rxerr >= 128)
-				new_state = CAN_STATE_ERROR_PASSIVE;
-			else if (es->txerr >= 96 || es->rxerr >= 96)
-				new_state = CAN_STATE_ERROR_WARNING;
-			else if (cur_state > CAN_STATE_ERROR_ACTIVE)
-				new_state = CAN_STATE_ERROR_ACTIVE;
-		}
-	}
-
-	if (!es->status)
+	} else if (es->txerr >= 128 || es->rxerr >= 128) {
+		new_state = CAN_STATE_ERROR_PASSIVE;
+	} else if (es->txerr >= 96 || es->rxerr >= 96) {
+		new_state = CAN_STATE_ERROR_WARNING;
+	} else {
 		new_state = CAN_STATE_ERROR_ACTIVE;
+	}
 
 	if (new_state != cur_state) {
 		tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
@@ -664,11 +1001,11 @@
 	}
 
 	if (priv->can.restart_ms &&
-	    cur_state >= CAN_STATE_BUS_OFF &&
+	    cur_state == CAN_STATE_BUS_OFF &&
 	    new_state < CAN_STATE_BUS_OFF)
 		priv->can.can_stats.restarts++;
 
-	switch (dev->card_data.leaf.family) {
+	switch (dev->driver_info->family) {
 	case KVASER_LEAF:
 		if (es->leaf.error_factor) {
 			priv->can.can_stats.bus_error++;
@@ -698,6 +1035,7 @@
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
 	struct kvaser_usb_net_priv *priv;
+	struct kvaser_usb_net_leaf_priv *leaf;
 	enum can_state old_state, new_state;
 
 	if (es->channel >= dev->nchannels) {
@@ -707,8 +1045,13 @@
 	}
 
 	priv = dev->nets[es->channel];
+	leaf = priv->sub_priv;
 	stats = &priv->netdev->stats;
 
+	/* Ignore e.g. state change to bus-off reported just after stopping */
+	if (!netif_running(priv->netdev))
+		return;
+
 	/* Update all of the CAN interface's state and error counters before
 	 * trying any memory allocation that can actually fail with -ENOMEM.
 	 *
@@ -723,6 +1066,14 @@
 	kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf);
 	new_state = priv->can.state;
 
+	/* If there are errors, request status updates periodically as we do
+	 * not get automatic notifications of improved state.
+	 */
+	if (new_state < CAN_STATE_BUS_OFF &&
+	    (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE))
+		schedule_delayed_work(&leaf->chip_state_req_work,
+				      msecs_to_jiffies(500));
+
 	skb = alloc_can_err_skb(priv->netdev, &cf);
 	if (!skb) {
 		stats->rx_dropped++;
@@ -740,14 +1091,14 @@
 		}
 
 		if (priv->can.restart_ms &&
-		    old_state >= CAN_STATE_BUS_OFF &&
+		    old_state == CAN_STATE_BUS_OFF &&
 		    new_state < CAN_STATE_BUS_OFF) {
 			cf->can_id |= CAN_ERR_RESTARTED;
 			netif_carrier_on(priv->netdev);
 		}
 	}
 
-	switch (dev->card_data.leaf.family) {
+	switch (dev->driver_info->family) {
 	case KVASER_LEAF:
 		if (es->leaf.error_factor) {
 			cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
@@ -774,8 +1125,10 @@
 		break;
 	}
 
-	cf->data[6] = es->txerr;
-	cf->data[7] = es->rxerr;
+	if (new_state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = es->txerr;
+		cf->data[7] = es->rxerr;
+	}
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
@@ -838,11 +1191,11 @@
 
 	case CMD_CAN_ERROR_EVENT:
 		es.channel = 0;
-		es.status = cmd->u.usbcan.error_event.status_ch0;
-		es.txerr = cmd->u.usbcan.error_event.tx_errors_count_ch0;
-		es.rxerr = cmd->u.usbcan.error_event.rx_errors_count_ch0;
+		es.status = cmd->u.usbcan.can_error_event.status_ch0;
+		es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0;
+		es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0;
 		es.usbcan.other_ch_status =
-			cmd->u.usbcan.error_event.status_ch1;
+			cmd->u.usbcan.can_error_event.status_ch1;
 		kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
 
 		/* The USBCAN firmware supports up to 2 channels.
@@ -850,13 +1203,13 @@
 		 */
 		if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
 			es.channel = 1;
-			es.status = cmd->u.usbcan.error_event.status_ch1;
+			es.status = cmd->u.usbcan.can_error_event.status_ch1;
 			es.txerr =
-				cmd->u.usbcan.error_event.tx_errors_count_ch1;
+				cmd->u.usbcan.can_error_event.tx_errors_count_ch1;
 			es.rxerr =
-				cmd->u.usbcan.error_event.rx_errors_count_ch1;
+				cmd->u.usbcan.can_error_event.rx_errors_count_ch1;
 			es.usbcan.other_ch_status =
-				cmd->u.usbcan.error_event.status_ch0;
+				cmd->u.usbcan.can_error_event.status_ch0;
 			kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
 		}
 		break;
@@ -873,11 +1226,11 @@
 
 	switch (cmd->id) {
 	case CMD_CAN_ERROR_EVENT:
-		es.channel = cmd->u.leaf.error_event.channel;
-		es.status = cmd->u.leaf.error_event.status;
-		es.txerr = cmd->u.leaf.error_event.tx_errors_count;
-		es.rxerr = cmd->u.leaf.error_event.rx_errors_count;
-		es.leaf.error_factor = cmd->u.leaf.error_event.error_factor;
+		es.channel = cmd->u.leaf.can_error_event.channel;
+		es.status = cmd->u.leaf.can_error_event.status;
+		es.txerr = cmd->u.leaf.can_error_event.tx_errors_count;
+		es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count;
+		es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor;
 		break;
 	case CMD_LEAF_LOG_MESSAGE:
 		es.channel = cmd->u.leaf.log_message.channel;
@@ -939,7 +1292,7 @@
 	stats = &priv->netdev->stats;
 
 	if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
-	    (dev->card_data.leaf.family == KVASER_LEAF &&
+	    (dev->driver_info->family == KVASER_LEAF &&
 	     cmd->id == CMD_LEAF_LOG_MESSAGE)) {
 		kvaser_usb_leaf_leaf_rx_error(dev, cmd);
 		return;
@@ -955,7 +1308,7 @@
 		return;
 	}
 
-	switch (dev->card_data.leaf.family) {
+	switch (dev->driver_info->family) {
 	case KVASER_LEAF:
 		rx_data = cmd->u.leaf.rx_can.data;
 		break;
@@ -970,7 +1323,7 @@
 		return;
 	}
 
-	if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
+	if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
 	    CMD_LEAF_LOG_MESSAGE) {
 		cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
 		if (cf->can_id & KVASER_EXTENDED_FRAME)
@@ -1009,6 +1362,74 @@
 	netif_rx(skb);
 }
 
+static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev,
+						  const struct kvaser_cmd *cmd)
+{
+	u16 info1 = 0;
+
+	switch (dev->driver_info->family) {
+	case KVASER_LEAF:
+		info1 = le16_to_cpu(cmd->u.leaf.error_event.info1);
+		break;
+	case KVASER_USBCAN:
+		info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1);
+		break;
+	}
+
+	/* info1 will contain the offending cmd_no */
+	switch (info1) {
+	case CMD_SET_CTRL_MODE:
+		dev_warn(&dev->intf->dev,
+			 "CMD_SET_CTRL_MODE error in parameter\n");
+		break;
+
+	case CMD_SET_BUS_PARAMS:
+		dev_warn(&dev->intf->dev,
+			 "CMD_SET_BUS_PARAMS error in parameter\n");
+		break;
+
+	default:
+		dev_warn(&dev->intf->dev,
+			 "Unhandled parameter error event cmd_no (%u)\n",
+			 info1);
+		break;
+	}
+}
+
+static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev,
+					const struct kvaser_cmd *cmd)
+{
+	u8 error_code = 0;
+
+	switch (dev->driver_info->family) {
+	case KVASER_LEAF:
+		error_code = cmd->u.leaf.error_event.error_code;
+		break;
+	case KVASER_USBCAN:
+		error_code = cmd->u.usbcan.error_event.error_code;
+		break;
+	}
+
+	switch (error_code) {
+	case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL:
+		/* Received additional CAN message, when firmware TX queue is
+		 * already full. Something is wrong with the driver.
+		 * This should never happen!
+		 */
+		dev_err(&dev->intf->dev,
+			"Received error event TX_QUEUE_FULL\n");
+		break;
+	case KVASER_USB_LEAF_ERROR_EVENT_PARAM:
+		kvaser_usb_leaf_error_event_parameter(dev, cmd);
+		break;
+
+	default:
+		dev_warn(&dev->intf->dev,
+			 "Unhandled error event (%d)\n", error_code);
+		break;
+	}
+}
+
 static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev,
 					     const struct kvaser_cmd *cmd)
 {
@@ -1049,9 +1470,31 @@
 	complete(&priv->stop_comp);
 }
 
+static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
+						const struct kvaser_cmd *cmd)
+{
+	struct kvaser_usb_net_priv *priv;
+	u8 channel = cmd->u.busparams.channel;
+
+	if (channel >= dev->nchannels) {
+		dev_err(&dev->intf->dev,
+			"Invalid channel number (%d)\n", channel);
+		return;
+	}
+
+	priv = dev->nets[channel];
+	memcpy(&priv->busparams_nominal, &cmd->u.busparams.busparams,
+	       sizeof(priv->busparams_nominal));
+
+	complete(&priv->get_busparams_comp);
+}
+
 static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
 					   const struct kvaser_cmd *cmd)
 {
+	if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
+		return;
+
 	switch (cmd->id) {
 	case CMD_START_CHIP_REPLY:
 		kvaser_usb_leaf_start_chip_reply(dev, cmd);
@@ -1067,14 +1510,14 @@
 		break;
 
 	case CMD_LEAF_LOG_MESSAGE:
-		if (dev->card_data.leaf.family != KVASER_LEAF)
+		if (dev->driver_info->family != KVASER_LEAF)
 			goto warn;
 		kvaser_usb_leaf_rx_can_msg(dev, cmd);
 		break;
 
 	case CMD_CHIP_STATE_EVENT:
 	case CMD_CAN_ERROR_EVENT:
-		if (dev->card_data.leaf.family == KVASER_LEAF)
+		if (dev->driver_info->family == KVASER_LEAF)
 			kvaser_usb_leaf_leaf_rx_error(dev, cmd);
 		else
 			kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
@@ -1084,14 +1527,22 @@
 		kvaser_usb_leaf_tx_acknowledge(dev, cmd);
 		break;
 
+	case CMD_ERROR_EVENT:
+		kvaser_usb_leaf_error_event(dev, cmd);
+		break;
+
+	case CMD_GET_BUS_PARAMS_REPLY:
+		kvaser_usb_leaf_get_busparams_reply(dev, cmd);
+		break;
+
 	/* Ignored commands */
 	case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
-		if (dev->card_data.leaf.family != KVASER_USBCAN)
+		if (dev->driver_info->family != KVASER_USBCAN)
 			goto warn;
 		break;
 
 	case CMD_FLUSH_QUEUE_REPLY:
-		if (dev->card_data.leaf.family != KVASER_LEAF)
+		if (dev->driver_info->family != KVASER_LEAF)
 			goto warn;
 		break;
 
@@ -1140,7 +1591,7 @@
 	struct kvaser_cmd *cmd;
 	int rc;
 
-	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (!cmd)
 		return -ENOMEM;
 
@@ -1164,7 +1615,7 @@
 {
 	int err;
 
-	init_completion(&priv->start_comp);
+	reinit_completion(&priv->start_comp);
 
 	err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP,
 					      priv->channel);
@@ -1180,9 +1631,12 @@
 
 static int kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv *priv)
 {
+	struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
 	int err;
 
-	init_completion(&priv->stop_comp);
+	reinit_completion(&priv->stop_comp);
+
+	cancel_delayed_work(&leaf->chip_state_req_work);
 
 	err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP,
 					      priv->channel);
@@ -1206,7 +1660,7 @@
 	struct kvaser_cmd *cmd;
 	int rc;
 
-	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (!cmd)
 		return -ENOMEM;
 
@@ -1225,28 +1679,40 @@
 {
 	struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
 
-	dev->cfg = &kvaser_usb_leaf_dev_cfg;
 	card_data->ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 
 	return 0;
 }
 
-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
-	.name = "kvaser_usb",
-	.tseg1_min = KVASER_USB_TSEG1_MIN,
-	.tseg1_max = KVASER_USB_TSEG1_MAX,
-	.tseg2_min = KVASER_USB_TSEG2_MIN,
-	.tseg2_max = KVASER_USB_TSEG2_MAX,
-	.sjw_max = KVASER_USB_SJW_MAX,
-	.brp_min = KVASER_USB_BRP_MIN,
-	.brp_max = KVASER_USB_BRP_MAX,
-	.brp_inc = KVASER_USB_BRP_INC,
-};
+static int kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv *priv)
+{
+	struct kvaser_usb_net_leaf_priv *leaf;
+
+	leaf = devm_kzalloc(&priv->dev->intf->dev, sizeof(*leaf), GFP_KERNEL);
+	if (!leaf)
+		return -ENOMEM;
 
-static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
+	leaf->net = priv;
+	INIT_DELAYED_WORK(&leaf->chip_state_req_work,
+			  kvaser_usb_leaf_chip_state_req_work);
+
+	priv->sub_priv = leaf;
+
+	return 0;
+}
+
+static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv)
+{
+	struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
+
+	if (leaf)
+		cancel_delayed_work_sync(&leaf->chip_state_req_work);
+}
+
+static int kvaser_usb_leaf_set_bittiming(const struct net_device *netdev,
+					 const struct kvaser_usb_busparams *busparams)
 {
 	struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
-	struct can_bittiming *bt = &priv->can.bittiming;
 	struct kvaser_usb *dev = priv->dev;
 	struct kvaser_cmd *cmd;
 	int rc;
@@ -1259,15 +1725,8 @@
 	cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams);
 	cmd->u.busparams.channel = priv->channel;
 	cmd->u.busparams.tid = 0xff;
-	cmd->u.busparams.bitrate = cpu_to_le32(bt->bitrate);
-	cmd->u.busparams.sjw = bt->sjw;
-	cmd->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
-	cmd->u.busparams.tseg2 = bt->phase_seg2;
-
-	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
-		cmd->u.busparams.no_samp = 3;
-	else
-		cmd->u.busparams.no_samp = 1;
+	memcpy(&cmd->u.busparams.busparams, busparams,
+	       sizeof(cmd->u.busparams.busparams));
 
 	rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
 
@@ -1275,6 +1734,27 @@
 	return rc;
 }
 
+static int kvaser_usb_leaf_get_busparams(struct kvaser_usb_net_priv *priv)
+{
+	int err;
+
+	if (priv->dev->driver_info->family == KVASER_USBCAN)
+		return -EOPNOTSUPP;
+
+	reinit_completion(&priv->get_busparams_comp);
+
+	err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_GET_BUS_PARAMS,
+					      priv->channel);
+	if (err)
+		return err;
+
+	if (!wait_for_completion_timeout(&priv->get_busparams_comp,
+					 msecs_to_jiffies(KVASER_USB_TIMEOUT)))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
 static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
 				    enum can_mode mode)
 {
@@ -1283,9 +1763,13 @@
 
 	switch (mode) {
 	case CAN_MODE_START:
+		kvaser_usb_unlink_tx_urbs(priv);
+
 		err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
 		if (err)
 			return err;
+
+		priv->can.state = CAN_STATE_ERROR_ACTIVE;
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -1310,7 +1794,7 @@
 	struct usb_endpoint_descriptor *endpoint;
 	int i;
 
-	iface_desc = &dev->intf->altsetting[0];
+	iface_desc = dev->intf->cur_altsetting;
 
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
@@ -1332,14 +1816,18 @@
 const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
 	.dev_set_mode = kvaser_usb_leaf_set_mode,
 	.dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
+	.dev_get_busparams = kvaser_usb_leaf_get_busparams,
 	.dev_set_data_bittiming = NULL,
+	.dev_get_data_busparams = NULL,
 	.dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
 	.dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
 	.dev_init_card = kvaser_usb_leaf_init_card,
+	.dev_init_channel = kvaser_usb_leaf_init_channel,
+	.dev_remove_channel = kvaser_usb_leaf_remove_channel,
 	.dev_get_software_info = kvaser_usb_leaf_get_software_info,
 	.dev_get_software_details = NULL,
 	.dev_get_card_info = kvaser_usb_leaf_get_card_info,
-	.dev_get_capabilities = NULL,
+	.dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
 	.dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
 	.dev_start_chip = kvaser_usb_leaf_start_chip,
 	.dev_stop_chip = kvaser_usb_leaf_stop_chip,
@@ -1348,11 +1836,3 @@
 	.dev_read_bulk_callback = kvaser_usb_leaf_read_bulk_callback,
 	.dev_frame_to_cmd = kvaser_usb_leaf_frame_to_cmd,
 };
-
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg = {
-	.clock = {
-		.freq = CAN_USB_CLOCK,
-	},
-	.timestamp_freq = 1,
-	.bittiming_const = &kvaser_usb_leaf_bittiming_const,
-};
--- linux-ein-5.4.0.orig/drivers/net/can/usb/mcba_usb.c
+++ linux-ein-5.4.0/drivers/net/can/usb/mcba_usb.c
@@ -33,10 +33,6 @@
 #define MCBA_USB_RX_BUFF_SIZE 64
 #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg))
 
-/* MCBA endpoint numbers */
-#define MCBA_USB_EP_IN 1
-#define MCBA_USB_EP_OUT 1
-
 /* Microchip command id */
 #define MBCA_CMD_RECEIVE_MESSAGE 0xE3
 #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5
@@ -51,6 +47,10 @@
 #define MCBA_VER_REQ_USB 1
 #define MCBA_VER_REQ_CAN 2
 
+/* Drive the CAN_RES signal LOW "0" to activate R24 and R25 */
+#define MCBA_VER_TERMINATION_ON 0
+#define MCBA_VER_TERMINATION_OFF 1
+
 #define MCBA_SIDL_EXID_MASK 0x8
 #define MCBA_DLC_MASK 0xf
 #define MCBA_DLC_RTR_MASK 0x40
@@ -82,6 +82,10 @@
 	bool can_ka_first_pass;
 	bool can_speed_check;
 	atomic_t free_ctx_cnt;
+	void *rxbuf[MCBA_MAX_RX_URBS];
+	dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
+	int rx_pipe;
+	int tx_pipe;
 };
 
 /* CAN frame */
@@ -270,10 +274,8 @@
 
 	memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE);
 
-	usb_fill_bulk_urb(urb, priv->udev,
-			  usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf,
-			  MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback,
-			  ctx);
+	usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE,
+			  mcba_usb_write_bulk_callback, ctx);
 
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	usb_anchor_urb(urb, &priv->tx_submitted);
@@ -326,8 +328,6 @@
 	if (!ctx)
 		return NETDEV_TX_BUSY;
 
-	can_put_echo_skb(skb, priv->netdev, ctx->ndx);
-
 	if (cf->can_id & CAN_EFF_FLAG) {
 		/* SIDH    | SIDL                 | EIDH   | EIDL
 		 * 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
@@ -357,6 +357,8 @@
 	if (cf->can_id & CAN_RTR_FLAG)
 		usb_msg.dlc |= MCBA_DLC_RTR_MASK;
 
+	can_put_echo_skb(skb, priv->netdev, ctx->ndx);
+
 	err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
 	if (err)
 		goto xmit_failed;
@@ -366,7 +368,6 @@
 xmit_failed:
 	can_free_echo_skb(priv->netdev, ctx->ndx);
 	mcba_usb_free_ctx(ctx);
-	dev_kfree_skb(skb);
 	stats->tx_dropped++;
 
 	return NETDEV_TX_OK;
@@ -472,7 +473,7 @@
 		priv->usb_ka_first_pass = false;
 	}
 
-	if (msg->termination_state)
+	if (msg->termination_state == MCBA_VER_TERMINATION_ON)
 		priv->can.termination = MCBA_TERMINATION_ENABLED;
 	else
 		priv->can.termination = MCBA_TERMINATION_DISABLED;
@@ -609,7 +610,7 @@
 resubmit_urb:
 
 	usb_fill_bulk_urb(urb, priv->udev,
-			  usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_OUT),
+			  priv->rx_pipe,
 			  urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE,
 			  mcba_usb_read_bulk_callback, priv);
 
@@ -633,6 +634,7 @@
 	for (i = 0; i < MCBA_MAX_RX_URBS; i++) {
 		struct urb *urb = NULL;
 		u8 *buf;
+		dma_addr_t buf_dma;
 
 		/* create a URB, and a buffer for it */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -642,7 +644,7 @@
 		}
 
 		buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
-					 GFP_KERNEL, &urb->transfer_dma);
+					 GFP_KERNEL, &buf_dma);
 		if (!buf) {
 			netdev_err(netdev, "No memory left for USB buffer\n");
 			usb_free_urb(urb);
@@ -650,8 +652,10 @@
 			break;
 		}
 
+		urb->transfer_dma = buf_dma;
+
 		usb_fill_bulk_urb(urb, priv->udev,
-				  usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN),
+				  priv->rx_pipe,
 				  buf, MCBA_USB_RX_BUFF_SIZE,
 				  mcba_usb_read_bulk_callback, priv);
 		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -661,11 +665,14 @@
 		if (err) {
 			usb_unanchor_urb(urb);
 			usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
-					  buf, urb->transfer_dma);
+					  buf, buf_dma);
 			usb_free_urb(urb);
 			break;
 		}
 
+		priv->rxbuf[i] = buf;
+		priv->rxbuf_dma[i] = buf_dma;
+
 		/* Drop reference, USB core will take care of freeing it */
 		usb_free_urb(urb);
 	}
@@ -708,7 +715,14 @@
 
 static void mcba_urb_unlink(struct mcba_priv *priv)
 {
+	int i;
+
 	usb_kill_anchored_urbs(&priv->rx_submitted);
+
+	for (i = 0; i < MCBA_MAX_RX_URBS; ++i)
+		usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
+				  priv->rxbuf[i], priv->rxbuf_dma[i]);
+
 	usb_kill_anchored_urbs(&priv->tx_submitted);
 }
 
@@ -779,9 +793,9 @@
 	};
 
 	if (term == MCBA_TERMINATION_ENABLED)
-		usb_msg.termination = 1;
+		usb_msg.termination = MCBA_VER_TERMINATION_ON;
 	else
-		usb_msg.termination = 0;
+		usb_msg.termination = MCBA_VER_TERMINATION_OFF;
 
 	mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);
 
@@ -795,6 +809,13 @@
 	struct mcba_priv *priv;
 	int err = -ENOMEM;
 	struct usb_device *usbdev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *in, *out;
+
+	err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL);
+	if (err) {
+		dev_err(&intf->dev, "Can't find endpoints\n");
+		return err;
+	}
 
 	netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS);
 	if (!netdev) {
@@ -840,6 +861,9 @@
 		goto cleanup_free_candev;
 	}
 
+	priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress);
+	priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress);
+
 	devm_can_led_init(netdev);
 
 	/* Start USB dev only if we have successfully registered CAN device */
--- linux-ein-5.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ linux-ein-5.4.0/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -130,14 +130,55 @@
 	/* protect from getting time before setting now */
 	if (ktime_to_ns(time_ref->tv_host)) {
 		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;
 
 		*time = ktime_add_us(time_ref->tv_host_0, delta_us);
@@ -815,7 +856,7 @@
 	if (dev->adapter->dev_set_bus) {
 		err = dev->adapter->dev_set_bus(dev, 0);
 		if (err)
-			goto lbl_unregister_candev;
+			goto adap_dev_free;
 	}
 
 	/* get device number early */
@@ -827,6 +868,10 @@
 
 	return 0;
 
+adap_dev_free:
+	if (dev->adapter->dev_free)
+		dev->adapter->dev_free(dev);
+
 lbl_unregister_candev:
 	unregister_candev(netdev);
 
--- linux-ein-5.4.0.orig/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ linux-ein-5.4.0/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -468,12 +468,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);
@@ -506,11 +512,11 @@
 	else
 		memcpy(cfd->data, rm->d, cfd->len);
 
-	peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(rm->ts_low));
-
 	netdev->stats.rx_packets++;
 	netdev->stats.rx_bytes += cfd->len;
 
+	peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(rm->ts_low));
+
 	return 0;
 }
 
@@ -519,15 +525,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;
@@ -539,11 +551,10 @@
 	} else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) {
 		new_state = CAN_STATE_ERROR_WARNING;
 	} else {
-		/* no error bit (so, no error skb, back to active state) */
-		dev->can.state = CAN_STATE_ERROR_ACTIVE;
+		/* back to (or still in) ERROR_ACTIVE state */
+		new_state = CAN_STATE_ERROR_ACTIVE;
 		pdev->bec.txerr = 0;
 		pdev->bec.rxerr = 0;
-		return 0;
 	}
 
 	/* state hasn't changed */
@@ -566,11 +577,11 @@
 	if (!skb)
 		return -ENOMEM;
 
-	peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(sm->ts_low));
-
 	netdev->stats.rx_packets++;
 	netdev->stats.rx_bytes += cf->can_dlc;
 
+	peak_usb_netif_rx(skb, &usb_if->time_ref, le32_to_cpu(sm->ts_low));
+
 	return 0;
 }
 
@@ -579,9 +590,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;
@@ -595,11 +611,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)
@@ -716,6 +738,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);
--- linux-ein-5.4.0.orig/drivers/net/can/usb/ucan.c
+++ linux-ein-5.4.0/drivers/net/can/usb/ucan.c
@@ -792,7 +792,7 @@
 			  up);
 
 	usb_anchor_urb(urb, &up->rx_urbs);
-	ret = usb_submit_urb(urb, GFP_KERNEL);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
 
 	if (ret < 0) {
 		netdev_err(up->netdev,
--- linux-ein-5.4.0.orig/drivers/net/can/usb/usb_8dev.c
+++ linux-ein-5.4.0/drivers/net/can/usb/usb_8dev.c
@@ -137,7 +137,8 @@
 	u8 *cmd_msg_buffer;
 
 	struct mutex usb_8dev_cmd_lock;
-
+	void *rxbuf[MAX_RX_URBS];
+	dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 /* tx frame */
@@ -441,9 +442,10 @@
 
 	if (rx_errors)
 		stats->rx_errors++;
-
-	cf->data[6] = txerr;
-	cf->data[7] = rxerr;
+	if (priv->can.state != CAN_STATE_BUS_OFF) {
+		cf->data[6] = txerr;
+		cf->data[7] = rxerr;
+	}
 
 	priv->bec.txerr = txerr;
 	priv->bec.rxerr = rxerr;
@@ -669,9 +671,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);
 
@@ -690,19 +703,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);
 
@@ -733,6 +733,7 @@
 	for (i = 0; i < MAX_RX_URBS; i++) {
 		struct urb *urb = NULL;
 		u8 *buf;
+		dma_addr_t buf_dma;
 
 		/* create a URB, and a buffer for it */
 		urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -742,7 +743,7 @@
 		}
 
 		buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-					 &urb->transfer_dma);
+					 &buf_dma);
 		if (!buf) {
 			netdev_err(netdev, "No memory left for USB buffer\n");
 			usb_free_urb(urb);
@@ -750,6 +751,8 @@
 			break;
 		}
 
+		urb->transfer_dma = buf_dma;
+
 		usb_fill_bulk_urb(urb, priv->udev,
 				  usb_rcvbulkpipe(priv->udev,
 						  USB_8DEV_ENDP_DATA_RX),
@@ -767,6 +770,9 @@
 			break;
 		}
 
+		priv->rxbuf[i] = buf;
+		priv->rxbuf_dma[i] = buf_dma;
+
 		/* Drop reference, USB core will take care of freeing it */
 		usb_free_urb(urb);
 	}
@@ -836,6 +842,10 @@
 
 	usb_kill_anchored_urbs(&priv->rx_submitted);
 
+	for (i = 0; i < MAX_RX_URBS; ++i)
+		usb_free_coherent(priv->udev, RX_BUFFER_SIZE,
+				  priv->rxbuf[i], priv->rxbuf_dma[i]);
+
 	usb_kill_anchored_urbs(&priv->tx_submitted);
 	atomic_set(&priv->active_tx_urbs, 0);
 
--- linux-ein-5.4.0.orig/drivers/net/can/vcan.c
+++ linux-ein-5.4.0/drivers/net/can/vcan.c
@@ -153,7 +153,7 @@
 	dev->addr_len		= 0;
 	dev->tx_queue_len	= 0;
 	dev->flags		= IFF_NOARP;
-	dev->ml_priv		= netdev_priv(dev);
+	can_set_ml_priv(dev, netdev_priv(dev));
 
 	/* set flags according to driver capabilities */
 	if (echo)
--- linux-ein-5.4.0.orig/drivers/net/can/vxcan.c
+++ linux-ein-5.4.0/drivers/net/can/vxcan.c
@@ -39,6 +39,7 @@
 	struct net_device *peer;
 	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
 	struct net_device_stats *peerstats, *srcstats = &dev->stats;
+	u8 len;
 
 	if (can_dropped_invalid_skb(dev, skb))
 		return NETDEV_TX_OK;
@@ -61,12 +62,13 @@
 	skb->dev        = peer;
 	skb->ip_summed  = CHECKSUM_UNNECESSARY;
 
+	len = cfd->len;
 	if (netif_rx_ni(skb) == NET_RX_SUCCESS) {
 		srcstats->tx_packets++;
-		srcstats->tx_bytes += cfd->len;
+		srcstats->tx_bytes += len;
 		peerstats = &peer->stats;
 		peerstats->rx_packets++;
-		peerstats->rx_bytes += cfd->len;
+		peerstats->rx_bytes += len;
 	}
 
 out_unlock:
@@ -139,15 +141,19 @@
 
 static void vxcan_setup(struct net_device *dev)
 {
+	struct can_ml_priv *can_ml;
+
 	dev->type		= ARPHRD_CAN;
 	dev->mtu		= CANFD_MTU;
 	dev->hard_header_len	= 0;
 	dev->addr_len		= 0;
 	dev->tx_queue_len	= 0;
-	dev->flags		= (IFF_NOARP|IFF_ECHO);
+	dev->flags		= IFF_NOARP;
 	dev->netdev_ops		= &vxcan_netdev_ops;
 	dev->needs_free_netdev	= true;
-	dev->ml_priv		= netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
+
+	can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
+	can_set_ml_priv(dev, can_ml);
 }
 
 /* forward declaration for rtnl_create_link() */
@@ -173,12 +179,7 @@
 
 		nla_peer = data[VXCAN_INFO_PEER];
 		ifmp = nla_data(nla_peer);
-		err = rtnl_nla_parse_ifla(peer_tb,
-					  nla_data(nla_peer) +
-					  sizeof(struct ifinfomsg),
-					  nla_len(nla_peer) -
-					  sizeof(struct ifinfomsg),
-					  NULL);
+		err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
 		if (err < 0)
 			return err;
 
--- linux-ein-5.4.0.orig/drivers/net/can/xilinx_can.c
+++ linux-ein-5.4.0/drivers/net/can/xilinx_can.c
@@ -60,6 +60,8 @@
 	XCAN_TXMSG_BASE_OFFSET	= 0x0100, /* TX Message Space */
 	XCAN_RXMSG_BASE_OFFSET	= 0x1100, /* RX Message Space */
 	XCAN_RXMSG_2_BASE_OFFSET	= 0x2100, /* RX Message Space */
+	XCAN_AFR_2_MASK_OFFSET	= 0x0A00, /* Acceptance Filter MASK */
+	XCAN_AFR_2_ID_OFFSET	= 0x0A04, /* Acceptance Filter ID */
 };
 
 #define XCAN_FRAME_ID_OFFSET(frame_base)	((frame_base) + 0x00)
@@ -237,7 +239,7 @@
 };
 
 /* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */
-static struct can_bittiming_const xcan_data_bittiming_const_canfd = {
+static const struct can_bittiming_const xcan_data_bittiming_const_canfd = {
 	.name = DRIVER_NAME,
 	.tseg1_min = 1,
 	.tseg1_max = 16,
@@ -263,7 +265,7 @@
 };
 
 /* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */
-static struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
+static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
 	.name = DRIVER_NAME,
 	.tseg1_min = 1,
 	.tseg1_max = 32,
@@ -1382,7 +1384,7 @@
 	if (ret < 0) {
 		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
 			   __func__, ret);
-		return ret;
+		goto err;
 	}
 
 	ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags,
@@ -1466,6 +1468,7 @@
 	if (ret < 0) {
 		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
 			   __func__, ret);
+		pm_runtime_put(priv->dev);
 		return ret;
 	}
 
@@ -1750,7 +1753,12 @@
 	spin_lock_init(&priv->tx_lock);
 
 	/* Get IRQ for the device */
-	ndev->irq = platform_get_irq(pdev, 0);
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto err_free;
+
+	ndev->irq = ret;
+
 	ndev->flags |= IFF_ECHO;	/* We support local echo */
 
 	platform_set_drvdata(pdev, ndev);
@@ -1781,7 +1789,7 @@
 	if (ret < 0) {
 		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
 			   __func__, ret);
-		goto err_pmdisable;
+		goto err_disableclks;
 	}
 
 	if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) {
@@ -1803,6 +1811,11 @@
 
 	pm_runtime_put(&pdev->dev);
 
+	if (priv->devtype.flags & XCAN_FLAG_CANFD_2) {
+		priv->write_reg(priv, XCAN_AFR_2_ID_OFFSET, 0x00000000);
+		priv->write_reg(priv, XCAN_AFR_2_MASK_OFFSET, 0x00000000);
+	}
+
 	netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx buffers: actual %d, using %d\n",
 		   priv->reg_base, ndev->irq, priv->can.clock.freq,
 		   hw_tx_max, priv->tx_max);
@@ -1811,7 +1824,6 @@
 
 err_disableclks:
 	pm_runtime_put(priv->dev);
-err_pmdisable:
 	pm_runtime_disable(&pdev->dev);
 err_free:
 	free_candev(ndev);
--- linux-ein-5.4.0.orig/drivers/net/dsa/Kconfig
+++ linux-ein-5.4.0/drivers/net/dsa/Kconfig
@@ -77,6 +77,7 @@
 config NET_DSA_SMSC_LAN9303
 	tristate
 	select NET_DSA_TAG_LAN9303
+	select REGMAP
 	---help---
 	  This enables support for the SMSC/Microchip LAN9303 3 port ethernet
 	  switch chips.
--- linux-ein-5.4.0.orig/drivers/net/dsa/b53/b53_common.c
+++ linux-ein-5.4.0/drivers/net/dsa/b53/b53_common.c
@@ -347,7 +347,7 @@
 	 * frames should be flooded or not.
 	 */
 	b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
-	mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN;
+	mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
 	b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
 }
 
@@ -514,6 +514,19 @@
 }
 EXPORT_SYMBOL(b53_imp_vlan_setup);
 
+static void b53_port_set_learning(struct b53_device *dev, int port,
+				  bool learning)
+{
+	u16 reg;
+
+	b53_read16(dev, B53_CTRL_PAGE, B53_DIS_LEARNING, &reg);
+	if (learning)
+		reg &= ~BIT(port);
+	else
+		reg |= BIT(port);
+	b53_write16(dev, B53_CTRL_PAGE, B53_DIS_LEARNING, reg);
+}
+
 int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
 {
 	struct b53_device *dev = ds->priv;
@@ -526,6 +539,9 @@
 
 	cpu_port = ds->ports[port].cpu_dp->index;
 
+	b53_br_egress_floods(ds, port, true, true);
+	b53_port_set_learning(dev, port, false);
+
 	if (dev->ops->irq_enable)
 		ret = dev->ops->irq_enable(dev, port);
 	if (ret)
@@ -641,6 +657,9 @@
 	b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), port_ctrl);
 
 	b53_brcm_hdr_setup(dev->ds, port);
+
+	b53_br_egress_floods(dev->ds, port, true, true);
+	b53_port_set_learning(dev, port, false);
 }
 
 static void b53_enable_mib(struct b53_device *dev)
@@ -676,7 +695,7 @@
 		b53_do_vlan_op(dev, VTA_CMD_CLEAR);
 	}
 
-	b53_enable_vlan(dev, false, ds->vlan_filtering);
+	b53_enable_vlan(dev, dev->vlan_enabled, ds->vlan_filtering);
 
 	b53_for_each_port(dev, i)
 		b53_write16(dev, B53_VLAN_PAGE,
@@ -977,13 +996,6 @@
 			b53_disable_port(ds, port);
 	}
 
-	/* Let DSA handle the case were multiple bridges span the same switch
-	 * device and different VLAN awareness settings are requested, which
-	 * would be breaking filtering semantics for any of the other bridge
-	 * devices. (not hardware supported)
-	 */
-	ds->vlan_filtering_is_global = true;
-
 	return ret;
 }
 
@@ -1326,7 +1338,7 @@
 	if ((is5325(dev) || is5365(dev)) && vlan->vid_begin == 0)
 		return -EOPNOTSUPP;
 
-	if (vlan->vid_end > dev->num_vlans)
+	if (vlan->vid_end >= dev->num_vlans)
 		return -ERANGE;
 
 	b53_enable_vlan(dev, true, ds->vlan_filtering);
@@ -1349,6 +1361,9 @@
 
 		b53_get_vlan_entry(dev, vid, vl);
 
+		if (vid == 0 && vid == b53_default_pvid(dev))
+			untagged = true;
+
 		vl->members |= BIT(port);
 		if (untagged && !dsa_is_cpu_port(ds, port))
 			vl->untag |= BIT(port);
@@ -1434,6 +1449,10 @@
 		reg |= ARLTBL_RW;
 	else
 		reg &= ~ARLTBL_RW;
+	if (dev->vlan_enabled)
+		reg &= ~ARLTBL_IVL_SVL_SELECT;
+	else
+		reg |= ARLTBL_IVL_SVL_SELECT;
 	b53_write8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, reg);
 
 	return b53_arl_op_wait(dev);
@@ -1443,6 +1462,7 @@
 			u16 vid, struct b53_arl_entry *ent, u8 *idx,
 			bool is_valid)
 {
+	DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
 	unsigned int i;
 	int ret;
 
@@ -1450,6 +1470,8 @@
 	if (ret)
 		return ret;
 
+	bitmap_zero(free_bins, dev->num_arl_entries);
+
 	/* Read the bins */
 	for (i = 0; i < dev->num_arl_entries; i++) {
 		u64 mac_vid;
@@ -1461,13 +1483,24 @@
 			   B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
 		b53_arl_to_entry(ent, mac_vid, fwd_entry);
 
-		if (!(fwd_entry & ARLTBL_VALID))
+		if (!(fwd_entry & ARLTBL_VALID)) {
+			set_bit(i, free_bins);
 			continue;
+		}
 		if ((mac_vid & ARLTBL_MAC_MASK) != mac)
 			continue;
+		if (dev->vlan_enabled &&
+		    ((mac_vid >> ARLTBL_VID_S) & ARLTBL_VID_MASK) != vid)
+			continue;
 		*idx = i;
+		return 0;
 	}
 
+	if (bitmap_weight(free_bins, dev->num_arl_entries) == 0)
+		return -ENOSPC;
+
+	*idx = find_first_bit(free_bins, dev->num_arl_entries);
+
 	return -ENOENT;
 }
 
@@ -1497,10 +1530,23 @@
 	if (op)
 		return ret;
 
-	/* We could not find a matching MAC, so reset to a new entry */
-	if (ret) {
+	switch (ret) {
+	case -ETIMEDOUT:
+		return ret;
+	case -ENOSPC:
+		dev_dbg(dev->dev, "{%pM,%.4d} no space left in ARL\n",
+			addr, vid);
+		return is_valid ? ret : 0;
+	case -ENOENT:
+		/* We could not find a matching MAC, so reset to a new entry */
+		dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n",
+			addr, vid, idx);
 		fwd_entry = 0;
-		idx = 1;
+		break;
+	default:
+		dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n",
+			addr, vid, idx);
+		break;
 	}
 
 	memset(&ent, 0, sizeof(ent));
@@ -1667,6 +1713,8 @@
 	b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
 	dev->ports[port].vlan_ctl_mask = pvlan;
 
+	b53_port_set_learning(dev, port, true);
+
 	return 0;
 }
 EXPORT_SYMBOL(b53_br_join);
@@ -1714,6 +1762,7 @@
 		vl->untag |= BIT(port) | BIT(cpu_port);
 		b53_set_vlan_entry(dev, pvid, vl);
 	}
+	b53_port_set_learning(dev, port, false);
 }
 EXPORT_SYMBOL(b53_br_leave);
 
@@ -1766,19 +1815,26 @@
 	struct b53_device *dev = ds->priv;
 	u16 uc, mc;
 
-	b53_read16(dev, B53_CTRL_PAGE, B53_UC_FWD_EN, &uc);
+	b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc);
 	if (unicast)
 		uc |= BIT(port);
 	else
 		uc &= ~BIT(port);
-	b53_write16(dev, B53_CTRL_PAGE, B53_UC_FWD_EN, uc);
+	b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc);
 
-	b53_read16(dev, B53_CTRL_PAGE, B53_MC_FWD_EN, &mc);
+	b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc);
 	if (multicast)
 		mc |= BIT(port);
 	else
 		mc &= ~BIT(port);
-	b53_write16(dev, B53_CTRL_PAGE, B53_MC_FWD_EN, mc);
+	b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc);
+
+	b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc);
+	if (multicast)
+		mc |= BIT(port);
+	else
+		mc &= ~BIT(port);
+	b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc);
 
 	return 0;
 
@@ -2298,9 +2354,8 @@
 			dev->cpu_port = 5;
 	}
 
-	/* cpu port is always last */
-	dev->num_ports = dev->cpu_port + 1;
 	dev->enabled_ports |= BIT(dev->cpu_port);
+	dev->num_ports = fls(dev->enabled_ports);
 
 	/* Include non standard CPU port built-in PHYs to be probed */
 	if (is539x(dev) || is531x5(dev)) {
@@ -2356,6 +2411,13 @@
 	dev->priv = priv;
 	dev->ops = ops;
 	ds->ops = &b53_switch_ops;
+	/* Let DSA handle the case were multiple bridges span the same switch
+	 * device and different VLAN awareness settings are requested, which
+	 * would be breaking filtering semantics for any of the other bridge
+	 * devices. (not hardware supported)
+	 */
+	ds->vlan_filtering_is_global = true;
+
 	mutex_init(&dev->reg_mutex);
 	mutex_init(&dev->stats_mutex);
 
--- linux-ein-5.4.0.orig/drivers/net/dsa/b53/b53_mmap.c
+++ linux-ein-5.4.0/drivers/net/dsa/b53/b53_mmap.c
@@ -215,6 +215,18 @@
 	return 0;
 }
 
+static int b53_mmap_phy_read16(struct b53_device *dev, int addr, int reg,
+			       u16 *value)
+{
+	return -EIO;
+}
+
+static int b53_mmap_phy_write16(struct b53_device *dev, int addr, int reg,
+				u16 value)
+{
+	return -EIO;
+}
+
 static const struct b53_io_ops b53_mmap_ops = {
 	.read8 = b53_mmap_read8,
 	.read16 = b53_mmap_read16,
@@ -226,6 +238,8 @@
 	.write32 = b53_mmap_write32,
 	.write48 = b53_mmap_write48,
 	.write64 = b53_mmap_write64,
+	.phy_read16 = b53_mmap_phy_read16,
+	.phy_write16 = b53_mmap_phy_write16,
 };
 
 static int b53_mmap_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/net/dsa/b53/b53_regs.h
+++ linux-ein-5.4.0/drivers/net/dsa/b53/b53_regs.h
@@ -115,6 +115,7 @@
 #define B53_UC_FLOOD_MASK		0x32
 #define B53_MC_FLOOD_MASK		0x34
 #define B53_IPMC_FLOOD_MASK		0x36
+#define B53_DIS_LEARNING		0x3c
 
 /*
  * Override Ports 0-7 State on devices with xMII interfaces (8 bit)
@@ -292,6 +293,7 @@
 /* ARL Table Read/Write Register (8 bit) */
 #define B53_ARLTBL_RW_CTRL		0x00
 #define    ARLTBL_RW			BIT(0)
+#define    ARLTBL_IVL_SVL_SELECT	BIT(6)
 #define    ARLTBL_START_DONE		BIT(7)
 
 /* MAC Address Index Register (48 bit) */
@@ -304,7 +306,7 @@
  *
  * BCM5325 and BCM5365 share most definitions below
  */
-#define B53_ARLTBL_MAC_VID_ENTRY(n)	(0x10 * (n))
+#define B53_ARLTBL_MAC_VID_ENTRY(n)	((0x10 * (n)) + 0x10)
 #define   ARLTBL_MAC_MASK		0xffffffffffffULL
 #define   ARLTBL_VID_S			48
 #define   ARLTBL_VID_MASK_25		0xff
@@ -316,13 +318,16 @@
 #define   ARLTBL_VALID_25		BIT(63)
 
 /* ARL Table Data Entry N Registers (32 bit) */
-#define B53_ARLTBL_DATA_ENTRY(n)	((0x10 * (n)) + 0x08)
+#define B53_ARLTBL_DATA_ENTRY(n)	((0x10 * (n)) + 0x18)
 #define   ARLTBL_DATA_PORT_ID_MASK	0x1ff
 #define   ARLTBL_TC(tc)			((3 & tc) << 11)
 #define   ARLTBL_AGE			BIT(14)
 #define   ARLTBL_STATIC			BIT(15)
 #define   ARLTBL_VALID			BIT(16)
 
+/* Maximum number of bin entries in the ARL for all switches */
+#define B53_ARLTBL_MAX_BIN_ENTRIES	4
+
 /* ARL Search Control Register (8 bit) */
 #define B53_ARL_SRCH_CTL		0x50
 #define B53_ARL_SRCH_CTL_25		0x20
--- linux-ein-5.4.0.orig/drivers/net/dsa/bcm_sf2.c
+++ linux-ein-5.4.0/drivers/net/dsa/bcm_sf2.c
@@ -69,6 +69,7 @@
 		/* Force link status for IMP port */
 		reg = core_readl(priv, offset);
 		reg |= (MII_SW_OR | LINK_STS);
+		reg &= ~GMII_SPEED_UP_2G;
 		core_writel(priv, reg, offset);
 
 		/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
@@ -171,11 +172,6 @@
 	reg &= ~P_TXQ_PSM_VDD(port);
 	core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
 
-	/* Enable learning */
-	reg = core_readl(priv, CORE_DIS_LEARN);
-	reg &= ~BIT(port);
-	core_writel(priv, reg, CORE_DIS_LEARN);
-
 	/* Enable Broadcom tags for that port if requested */
 	if (priv->brcm_tag_mask & BIT(port))
 		b53_brcm_hdr_setup(ds, port);
@@ -420,15 +416,19 @@
 	/* Find our integrated MDIO bus node */
 	dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
 	priv->master_mii_bus = of_mdio_find_bus(dn);
-	if (!priv->master_mii_bus)
+	if (!priv->master_mii_bus) {
+		of_node_put(dn);
 		return -EPROBE_DEFER;
+	}
 
 	get_device(&priv->master_mii_bus->dev);
 	priv->master_mii_dn = dn;
 
 	priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
-	if (!priv->slave_mii_bus)
+	if (!priv->slave_mii_bus) {
+		of_node_put(dn);
 		return -ENOMEM;
+	}
 
 	priv->slave_mii_bus->priv = priv;
 	priv->slave_mii_bus->name = "sf2 slave mii";
@@ -458,7 +458,7 @@
 	priv->slave_mii_bus->parent = ds->dev->parent;
 	priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
 
-	err = of_mdiobus_register(priv->slave_mii_bus, dn);
+	err = mdiobus_register(priv->slave_mii_bus);
 	if (err && dn)
 		of_node_put(dn);
 
@@ -479,8 +479,10 @@
 	 * in bits 15:8 and the patch level in bits 7:0 which is exactly what
 	 * the REG_PHY_REVISION register layout is.
 	 */
-
-	return priv->hw_params.gphy_rev;
+	if (priv->int_phy_mask & BIT(port))
+		return priv->hw_params.gphy_rev;
+	else
+		return 0;
 }
 
 static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port,
@@ -600,6 +602,11 @@
 		reg |= LINK_STS;
 	if (state->duplex == DUPLEX_FULL)
 		reg |= DUPLX_MODE;
+	if (state->pause & MLO_PAUSE_TXRX_MASK) {
+		if (state->pause & MLO_PAUSE_TX)
+			reg |= TXFLOW_CNTL;
+		reg |= RXFLOW_CNTL;
+	}
 
 	core_writel(priv, reg, offset);
 }
@@ -1052,6 +1059,7 @@
 	const struct bcm_sf2_of_data *data;
 	struct b53_platform_data *pdata;
 	struct dsa_switch_ops *ops;
+	struct device_node *ports;
 	struct bcm_sf2_priv *priv;
 	struct b53_device *dev;
 	struct dsa_switch *ds;
@@ -1114,7 +1122,13 @@
 	set_bit(0, priv->cfp.used);
 	set_bit(0, priv->cfp.unique);
 
-	bcm_sf2_identify_ports(priv, dn->child);
+	/* Balance of_node_put() done by of_find_node_by_name() */
+	of_node_get(dn);
+	ports = of_find_node_by_name(dn, "ports");
+	if (ports) {
+		bcm_sf2_identify_ports(priv, ports);
+		of_node_put(ports);
+	}
 
 	priv->irq0 = irq_of_parse_and_map(dn, 0);
 	priv->irq1 = irq_of_parse_and_map(dn, 1);
--- linux-ein-5.4.0.orig/drivers/net/dsa/bcm_sf2_cfp.c
+++ linux-ein-5.4.0/drivers/net/dsa/bcm_sf2_cfp.c
@@ -358,7 +358,7 @@
 		return -EINVAL;
 	}
 
-	ip_frag = be32_to_cpu(fs->m_ext.data[0]);
+	ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1);
 
 	/* Locate the first rule available */
 	if (fs->location == RX_CLS_LOC_ANY)
@@ -542,14 +542,14 @@
 static struct cfp_rule *bcm_sf2_cfp_rule_find(struct bcm_sf2_priv *priv,
 					      int port, u32 location)
 {
-	struct cfp_rule *rule = NULL;
+	struct cfp_rule *rule;
 
 	list_for_each_entry(rule, &priv->cfp.rules_list, next) {
 		if (rule->port == port && rule->fs.location == location)
-			break;
+			return rule;
 	}
 
-	return rule;
+	return NULL;
 }
 
 static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port,
@@ -569,7 +569,7 @@
 
 		if (rule->fs.flow_type != fs->flow_type ||
 		    rule->fs.ring_cookie != fs->ring_cookie ||
-		    rule->fs.m_ext.data[0] != fs->m_ext.data[0])
+		    rule->fs.h_ext.data[0] != fs->h_ext.data[0])
 			continue;
 
 		switch (fs->flow_type & ~FLOW_EXT) {
@@ -621,7 +621,7 @@
 		return -EINVAL;
 	}
 
-	ip_frag = be32_to_cpu(fs->m_ext.data[0]);
+	ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1);
 
 	layout = &udf_tcpip6_layout;
 	slice_num = bcm_sf2_get_slice_number(layout, 0);
@@ -882,17 +882,14 @@
 	     fs->m_ext.data[1]))
 		return -EINVAL;
 
-	if (fs->location != RX_CLS_LOC_ANY && fs->location >= CFP_NUM_RULES)
+	if (fs->location != RX_CLS_LOC_ANY &&
+	    fs->location > bcm_sf2_cfp_rule_size(priv))
 		return -EINVAL;
 
 	if (fs->location != RX_CLS_LOC_ANY &&
 	    test_bit(fs->location, priv->cfp.used))
 		return -EBUSY;
 
-	if (fs->location != RX_CLS_LOC_ANY &&
-	    fs->location > bcm_sf2_cfp_rule_size(priv))
-		return -EINVAL;
-
 	ret = bcm_sf2_cfp_rule_cmp(priv, port, fs);
 	if (ret == 0)
 		return -EEXIST;
@@ -973,7 +970,7 @@
 	struct cfp_rule *rule;
 	int ret;
 
-	if (loc >= CFP_NUM_RULES)
+	if (loc > bcm_sf2_cfp_rule_size(priv))
 		return -EINVAL;
 
 	/* Refuse deleting unused rules, and those that are not unique since
--- linux-ein-5.4.0.orig/drivers/net/dsa/dsa_loop.c
+++ linux-ein-5.4.0/drivers/net/dsa/dsa_loop.c
@@ -329,6 +329,17 @@
 
 #define NUM_FIXED_PHYS	(DSA_LOOP_NUM_PORTS - 2)
 
+static void dsa_loop_phydevs_unregister(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FIXED_PHYS; i++)
+		if (!IS_ERR(phydevs[i])) {
+			fixed_phy_unregister(phydevs[i]);
+			phy_device_free(phydevs[i]);
+		}
+}
+
 static int __init dsa_loop_init(void)
 {
 	struct fixed_phy_status status = {
@@ -336,26 +347,27 @@
 		.speed = SPEED_100,
 		.duplex = DUPLEX_FULL,
 	};
-	unsigned int i;
+	unsigned int i, ret;
 
 	for (i = 0; i < NUM_FIXED_PHYS; i++)
 		phydevs[i] = fixed_phy_register(PHY_POLL, &status, NULL);
 
-	return mdio_driver_register(&dsa_loop_drv);
+	ret = mdio_driver_register(&dsa_loop_drv);
+	if (ret)
+		dsa_loop_phydevs_unregister();
+
+	return ret;
 }
 module_init(dsa_loop_init);
 
 static void __exit dsa_loop_exit(void)
 {
-	unsigned int i;
-
 	mdio_driver_unregister(&dsa_loop_drv);
-	for (i = 0; i < NUM_FIXED_PHYS; i++)
-		if (!IS_ERR(phydevs[i]))
-			fixed_phy_unregister(phydevs[i]);
+	dsa_loop_phydevs_unregister();
 }
 module_exit(dsa_loop_exit);
 
+MODULE_SOFTDEP("pre: dsa_loop_bdinfo");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Florian Fainelli");
 MODULE_DESCRIPTION("DSA loopback driver");
--- linux-ein-5.4.0.orig/drivers/net/dsa/lan9303-core.c
+++ linux-ein-5.4.0/drivers/net/dsa/lan9303-core.c
@@ -557,12 +557,12 @@
 	return 0;
 }
 
-typedef void alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
-			   int portmap, void *ctx);
+typedef int alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
+			  int portmap, void *ctx);
 
-static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
+static int lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
 {
-	int i;
+	int ret = 0, i;
 
 	mutex_lock(&chip->alr_mutex);
 	lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
@@ -582,13 +582,17 @@
 						LAN9303_ALR_DAT1_PORT_BITOFFS;
 		portmap = alrport_2_portmap[alrport];
 
-		cb(chip, dat0, dat1, portmap, ctx);
+		ret = cb(chip, dat0, dat1, portmap, ctx);
+		if (ret)
+			break;
 
 		lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
 					 LAN9303_ALR_CMD_GET_NEXT);
 		lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
 	}
 	mutex_unlock(&chip->alr_mutex);
+
+	return ret;
 }
 
 static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
@@ -606,18 +610,20 @@
 };
 
 /* Clear learned (non-static) entry on given port */
-static void alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
-					 u32 dat1, int portmap, void *ctx)
+static int alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
+					u32 dat1, int portmap, void *ctx)
 {
 	struct del_port_learned_ctx *del_ctx = ctx;
 	int port = del_ctx->port;
 
 	if (((BIT(port) & portmap) == 0) || (dat1 & LAN9303_ALR_DAT1_STATIC))
-		return;
+		return 0;
 
 	/* learned entries has only one port, we can just delete */
 	dat1 &= ~LAN9303_ALR_DAT1_VALID; /* delete entry */
 	lan9303_alr_make_entry_raw(chip, dat0, dat1);
+
+	return 0;
 }
 
 struct port_fdb_dump_ctx {
@@ -626,19 +632,19 @@
 	dsa_fdb_dump_cb_t *cb;
 };
 
-static void alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
-				      u32 dat1, int portmap, void *ctx)
+static int alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
+				     u32 dat1, int portmap, void *ctx)
 {
 	struct port_fdb_dump_ctx *dump_ctx = ctx;
 	u8 mac[ETH_ALEN];
 	bool is_static;
 
 	if ((BIT(dump_ctx->port) & portmap) == 0)
-		return;
+		return 0;
 
 	alr_reg_to_mac(dat0, dat1, mac);
 	is_static = !!(dat1 & LAN9303_ALR_DAT1_STATIC);
-	dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
+	return dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
 }
 
 /* Set a static ALR entry. Delete entry if port_map is zero */
@@ -951,7 +957,7 @@
 	{ .offset = LAN9303_MAC_TX_BRDCST_CNT_0, .name = "TxBroad", },
 	{ .offset = LAN9303_MAC_TX_PAUSE_CNT_0, .name = "TxPause", },
 	{ .offset = LAN9303_MAC_TX_MULCST_CNT_0, .name = "TxMulti", },
-	{ .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "TxUnderRun", },
+	{ .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "RxShort", },
 	{ .offset = LAN9303_MAC_TX_64_CNT_0, .name = "Tx64Byte", },
 	{ .offset = LAN9303_MAC_TX_127_CNT_0, .name = "Tx128Byte", },
 	{ .offset = LAN9303_MAC_TX_255_CNT_0, .name = "Tx256Byte", },
@@ -995,9 +1001,11 @@
 		ret = lan9303_read_switch_port(
 			chip, port, lan9303_mib[u].offset, &reg);
 
-		if (ret)
+		if (ret) {
 			dev_warn(chip->dev, "Reading status port %d reg %u failed\n",
 				 port, lan9303_mib[u].offset);
+			reg = 0;
+		}
 		data[u] = reg;
 	}
 }
@@ -1179,8 +1187,6 @@
 	struct lan9303 *chip = ds->priv;
 
 	dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
-	if (vid)
-		return -EOPNOTSUPP;
 
 	return lan9303_alr_add_port(chip, addr, port, false);
 }
@@ -1192,8 +1198,6 @@
 	struct lan9303 *chip = ds->priv;
 
 	dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
-	if (vid)
-		return -EOPNOTSUPP;
 	lan9303_alr_del_port(chip, addr, port);
 
 	return 0;
@@ -1210,9 +1214,7 @@
 	};
 
 	dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
-	lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
-
-	return 0;
+	return lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
 }
 
 static int lan9303_port_mdb_prepare(struct dsa_switch *ds, int port,
@@ -1299,7 +1301,7 @@
 				     struct device_node *np)
 {
 	chip->reset_gpio = devm_gpiod_get_optional(chip->dev, "reset",
-						   GPIOD_OUT_LOW);
+						   GPIOD_OUT_HIGH);
 	if (IS_ERR(chip->reset_gpio))
 		return PTR_ERR(chip->reset_gpio);
 
--- linux-ein-5.4.0.orig/drivers/net/dsa/lan9303_mdio.c
+++ linux-ein-5.4.0/drivers/net/dsa/lan9303_mdio.c
@@ -32,7 +32,7 @@
 	struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
 
 	reg <<= 2; /* reg num to offset */
-	mutex_lock(&sw_dev->device->bus->mdio_lock);
+	mutex_lock_nested(&sw_dev->device->bus->mdio_lock, MDIO_MUTEX_NESTED);
 	lan9303_mdio_real_write(sw_dev->device, reg, val & 0xffff);
 	lan9303_mdio_real_write(sw_dev->device, reg + 2, (val >> 16) & 0xffff);
 	mutex_unlock(&sw_dev->device->bus->mdio_lock);
@@ -50,7 +50,7 @@
 	struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
 
 	reg <<= 2; /* reg num to offset */
-	mutex_lock(&sw_dev->device->bus->mdio_lock);
+	mutex_lock_nested(&sw_dev->device->bus->mdio_lock, MDIO_MUTEX_NESTED);
 	*val = lan9303_mdio_real_read(sw_dev->device, reg);
 	*val |= (lan9303_mdio_real_read(sw_dev->device, reg + 2) << 16);
 	mutex_unlock(&sw_dev->device->bus->mdio_lock);
--- linux-ein-5.4.0.orig/drivers/net/dsa/lantiq_gswip.c
+++ linux-ein-5.4.0/drivers/net/dsa/lantiq_gswip.c
@@ -26,6 +26,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
 #include <linux/if_bridge.h>
@@ -91,11 +92,13 @@
 					 GSWIP_MDIO_PHY_FDUP_MASK)
 
 /* GSWIP MII Registers */
-#define GSWIP_MII_CFG0			0x00
-#define GSWIP_MII_CFG1			0x02
-#define GSWIP_MII_CFG5			0x04
+#define GSWIP_MII_CFGp(p)		(0x2 * (p))
+#define  GSWIP_MII_CFG_RESET		BIT(15)
 #define  GSWIP_MII_CFG_EN		BIT(14)
+#define  GSWIP_MII_CFG_ISOLATE		BIT(13)
 #define  GSWIP_MII_CFG_LDCLKDIS		BIT(12)
+#define  GSWIP_MII_CFG_RGMII_IBS	BIT(8)
+#define  GSWIP_MII_CFG_RMII_CLK		BIT(7)
 #define  GSWIP_MII_CFG_MODE_MIIP	0x0
 #define  GSWIP_MII_CFG_MODE_MIIM	0x1
 #define  GSWIP_MII_CFG_MODE_RMIIP	0x2
@@ -191,6 +194,23 @@
 #define GSWIP_PCE_DEFPVID(p)		(0x486 + ((p) * 0xA))
 
 #define GSWIP_MAC_FLEN			0x8C5
+#define GSWIP_MAC_CTRL_0p(p)		(0x903 + ((p) * 0xC))
+#define  GSWIP_MAC_CTRL_0_PADEN		BIT(8)
+#define  GSWIP_MAC_CTRL_0_FCS_EN	BIT(7)
+#define  GSWIP_MAC_CTRL_0_FCON_MASK	0x0070
+#define  GSWIP_MAC_CTRL_0_FCON_AUTO	0x0000
+#define  GSWIP_MAC_CTRL_0_FCON_RX	0x0010
+#define  GSWIP_MAC_CTRL_0_FCON_TX	0x0020
+#define  GSWIP_MAC_CTRL_0_FCON_RXTX	0x0030
+#define  GSWIP_MAC_CTRL_0_FCON_NONE	0x0040
+#define  GSWIP_MAC_CTRL_0_FDUP_MASK	0x000C
+#define  GSWIP_MAC_CTRL_0_FDUP_AUTO	0x0000
+#define  GSWIP_MAC_CTRL_0_FDUP_EN	0x0004
+#define  GSWIP_MAC_CTRL_0_FDUP_DIS	0x000C
+#define  GSWIP_MAC_CTRL_0_GMII_MASK	0x0003
+#define  GSWIP_MAC_CTRL_0_GMII_AUTO	0x0000
+#define  GSWIP_MAC_CTRL_0_GMII_MII	0x0001
+#define  GSWIP_MAC_CTRL_0_GMII_RGMII	0x0002
 #define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))
 #define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */
 
@@ -209,7 +229,7 @@
 #define GSWIP_SDMA_PCTRLp(p)		(0xBC0 + ((p) * 0x6))
 #define  GSWIP_SDMA_PCTRL_EN		BIT(0)	/* SDMA Port Enable */
 #define  GSWIP_SDMA_PCTRL_FCEN		BIT(1)	/* Flow Control Enable */
-#define  GSWIP_SDMA_PCTRL_PAUFWD	BIT(1)	/* Pause Frame Forwarding */
+#define  GSWIP_SDMA_PCTRL_PAUFWD	BIT(3)	/* Pause Frame Forwarding */
 
 #define GSWIP_TABLE_ACTIVE_VLAN		0x01
 #define GSWIP_TABLE_VLAN_MAPPING	0x02
@@ -391,17 +411,9 @@
 static void gswip_mii_mask_cfg(struct gswip_priv *priv, u32 clear, u32 set,
 			       int port)
 {
-	switch (port) {
-	case 0:
-		gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG0);
-		break;
-	case 1:
-		gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG1);
-		break;
-	case 5:
-		gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG5);
-		break;
-	}
+	/* There's no MII_CFG register for the CPU port */
+	if (!dsa_is_cpu_port(priv->ds, port))
+		gswip_mii_mask(priv, clear, set, GSWIP_MII_CFGp(port));
 }
 
 static void gswip_mii_mask_pcdu(struct gswip_priv *priv, u32 clear, u32 set,
@@ -662,16 +674,13 @@
 			  GSWIP_SDMA_PCTRLp(port));
 
 	if (!dsa_is_cpu_port(ds, port)) {
-		u32 macconf = GSWIP_MDIO_PHY_LINK_AUTO |
-			      GSWIP_MDIO_PHY_SPEED_AUTO |
-			      GSWIP_MDIO_PHY_FDUP_AUTO |
-			      GSWIP_MDIO_PHY_FCONTX_AUTO |
-			      GSWIP_MDIO_PHY_FCONRX_AUTO |
-			      (phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK);
-
-		gswip_mdio_w(priv, macconf, GSWIP_MDIO_PHYp(port));
-		/* Activate MDIO auto polling */
-		gswip_mdio_mask(priv, 0, BIT(port), GSWIP_MDIO_MDC_CFG0);
+		u32 mdio_phy = 0;
+
+		if (phydev)
+			mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
+
+		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_ADDR_MASK, mdio_phy,
+				GSWIP_MDIO_PHYp(port));
 	}
 
 	return 0;
@@ -684,14 +693,6 @@
 	if (!dsa_is_user_port(ds, port))
 		return;
 
-	if (!dsa_is_cpu_port(ds, port)) {
-		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN,
-				GSWIP_MDIO_PHY_LINK_MASK,
-				GSWIP_MDIO_PHYp(port));
-		/* Deactivate MDIO auto polling */
-		gswip_mdio_mask(priv, BIT(port), 0, GSWIP_MDIO_MDC_CFG0);
-	}
-
 	gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,
 			  GSWIP_FDMA_PCTRLp(port));
 	gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
@@ -799,15 +800,32 @@
 	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2);
 	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3);
 
-	/* disable PHY auto polling */
+	/* Deactivate MDIO PHY auto polling. Some PHYs as the AR8030 have an
+	 * interoperability problem with this auto polling mechanism because
+	 * their status registers think that the link is in a different state
+	 * than it actually is. For the AR8030 it has the BMSR_ESTATEN bit set
+	 * as well as ESTATUS_1000_TFULL and ESTATUS_1000_XFULL. This makes the
+	 * auto polling state machine consider the link being negotiated with
+	 * 1Gbit/s. Since the PHY itself is a Fast Ethernet RMII PHY this leads
+	 * to the switch port being completely dead (RX and TX are both not
+	 * working).
+	 * Also with various other PHY / port combinations (PHY11G GPHY, PHY22F
+	 * GPHY, external RGMII PEF7071/7072) any traffic would stop. Sometimes
+	 * it would work fine for a few minutes to hours and then stop, on
+	 * other device it would no traffic could be sent or received at all.
+	 * Testing shows that when PHY auto polling is disabled these problems
+	 * go away.
+	 */
 	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
+
 	/* Configure the MDIO Clock 2.5 MHz */
 	gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1);
 
-	/* Disable the xMII link */
-	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 0);
-	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 1);
-	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 5);
+	/* Disable the xMII interface and clear it's isolation bit */
+	for (i = 0; i < priv->hw_info->max_ports; i++)
+		gswip_mii_mask_cfg(priv,
+				   GSWIP_MII_CFG_EN | GSWIP_MII_CFG_ISOLATE,
+				   0, i);
 
 	/* enable special tag insertion on cpu port */
 	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
@@ -819,7 +837,8 @@
 
 	gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
 			  GSWIP_MAC_CTRL_2p(cpu_port));
-	gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
+	gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8 + ETH_FCS_LEN,
+		       GSWIP_MAC_FLEN);
 	gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
 			  GSWIP_BM_QUEUE_GCTRL);
 
@@ -1381,11 +1400,17 @@
 		addr[1] = mac_bridge.key[2] & 0xff;
 		addr[0] = (mac_bridge.key[2] >> 8) & 0xff;
 		if (mac_bridge.val[1] & GSWIP_TABLE_MAC_BRIDGE_STATIC) {
-			if (mac_bridge.val[0] & BIT(port))
-				cb(addr, 0, true, data);
+			if (mac_bridge.val[0] & BIT(port)) {
+				err = cb(addr, 0, true, data);
+				if (err)
+					return err;
+			}
 		} else {
-			if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) == port)
-				cb(addr, 0, false, data);
+			if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) == port) {
+				err = cb(addr, 0, false, data);
+				if (err)
+					return err;
+			}
 		}
 	}
 	return 0;
@@ -1429,11 +1454,12 @@
 	phylink_set(mask, Pause);
 	phylink_set(mask, Asym_Pause);
 
-	/* With the exclusion of MII and Reverse MII, we support Gigabit,
-	 * including Half duplex
+	/* With the exclusion of MII, Reverse MII and Reduced MII, we
+	 * support Gigabit, including Half duplex
 	 */
 	if (state->interface != PHY_INTERFACE_MODE_MII &&
-	    state->interface != PHY_INTERFACE_MODE_REVMII) {
+	    state->interface != PHY_INTERFACE_MODE_REVMII &&
+	    state->interface != PHY_INTERFACE_MODE_RMII) {
 		phylink_set(mask, 1000baseT_Full);
 		phylink_set(mask, 1000baseT_Half);
 	}
@@ -1451,10 +1477,117 @@
 
 unsupported:
 	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
-	dev_err(ds->dev, "Unsupported interface: %d\n", state->interface);
+	dev_err(ds->dev, "Unsupported interface '%s' for port %d\n",
+		phy_modes(state->interface), port);
 	return;
 }
 
+static void gswip_port_set_link(struct gswip_priv *priv, int port, bool link)
+{
+	u32 mdio_phy;
+
+	if (link)
+		mdio_phy = GSWIP_MDIO_PHY_LINK_UP;
+	else
+		mdio_phy = GSWIP_MDIO_PHY_LINK_DOWN;
+
+	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_MASK, mdio_phy,
+			GSWIP_MDIO_PHYp(port));
+}
+
+static void gswip_port_set_speed(struct gswip_priv *priv, int port, int speed,
+				 phy_interface_t interface)
+{
+	u32 mdio_phy = 0, mii_cfg = 0, mac_ctrl_0 = 0;
+
+	switch (speed) {
+	case SPEED_10:
+		mdio_phy = GSWIP_MDIO_PHY_SPEED_M10;
+
+		if (interface == PHY_INTERFACE_MODE_RMII)
+			mii_cfg = GSWIP_MII_CFG_RATE_M50;
+		else
+			mii_cfg = GSWIP_MII_CFG_RATE_M2P5;
+
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
+		break;
+
+	case SPEED_100:
+		mdio_phy = GSWIP_MDIO_PHY_SPEED_M100;
+
+		if (interface == PHY_INTERFACE_MODE_RMII)
+			mii_cfg = GSWIP_MII_CFG_RATE_M50;
+		else
+			mii_cfg = GSWIP_MII_CFG_RATE_M25;
+
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
+		break;
+
+	case SPEED_1000:
+		mdio_phy = GSWIP_MDIO_PHY_SPEED_G1;
+
+		mii_cfg = GSWIP_MII_CFG_RATE_M125;
+
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_RGMII;
+		break;
+	}
+
+	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_SPEED_MASK, mdio_phy,
+			GSWIP_MDIO_PHYp(port));
+	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_RATE_MASK, mii_cfg, port);
+	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_GMII_MASK, mac_ctrl_0,
+			  GSWIP_MAC_CTRL_0p(port));
+}
+
+static void gswip_port_set_duplex(struct gswip_priv *priv, int port, int duplex)
+{
+	u32 mac_ctrl_0, mdio_phy;
+
+	if (duplex == DUPLEX_FULL) {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_EN;
+		mdio_phy = GSWIP_MDIO_PHY_FDUP_EN;
+	} else {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_DIS;
+		mdio_phy = GSWIP_MDIO_PHY_FDUP_DIS;
+	}
+
+	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FDUP_MASK, mac_ctrl_0,
+			  GSWIP_MAC_CTRL_0p(port));
+	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_FDUP_MASK, mdio_phy,
+			GSWIP_MDIO_PHYp(port));
+}
+
+static void gswip_port_set_pause(struct gswip_priv *priv, int port,
+				 bool tx_pause, bool rx_pause)
+{
+	u32 mac_ctrl_0, mdio_phy;
+
+	if (tx_pause && rx_pause) {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RXTX;
+		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
+			   GSWIP_MDIO_PHY_FCONRX_EN;
+	} else if (tx_pause) {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_TX;
+		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
+			   GSWIP_MDIO_PHY_FCONRX_DIS;
+	} else if (rx_pause) {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RX;
+		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
+			   GSWIP_MDIO_PHY_FCONRX_EN;
+	} else {
+		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_NONE;
+		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
+			   GSWIP_MDIO_PHY_FCONRX_DIS;
+	}
+
+	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FCON_MASK,
+			  mac_ctrl_0, GSWIP_MAC_CTRL_0p(port));
+	gswip_mdio_mask(priv,
+			GSWIP_MDIO_PHY_FCONTX_MASK |
+			GSWIP_MDIO_PHY_FCONRX_MASK,
+			mdio_phy, GSWIP_MDIO_PHYp(port));
+}
+
 static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
 				     unsigned int mode,
 				     const struct phylink_link_state *state)
@@ -1486,7 +1619,16 @@
 			"Unsupported interface: %d\n", state->interface);
 		return;
 	}
-	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_MODE_MASK, miicfg, port);
+
+	gswip_mii_mask_cfg(priv,
+			   GSWIP_MII_CFG_MODE_MASK | GSWIP_MII_CFG_RMII_CLK |
+			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS,
+			   miicfg, port);
+
+	gswip_port_set_speed(priv, port, state->speed, state->interface);
+	gswip_port_set_duplex(priv, port, state->duplex);
+	gswip_port_set_pause(priv, port, !!(state->pause & MLO_PAUSE_TX),
+			     !!(state->pause & MLO_PAUSE_RX));
 
 	switch (state->interface) {
 	case PHY_INTERFACE_MODE_RGMII_ID:
@@ -1511,6 +1653,9 @@
 	struct gswip_priv *priv = ds->priv;
 
 	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port);
+
+	if (!dsa_is_cpu_port(ds, port))
+		gswip_port_set_link(priv, port, false);
 }
 
 static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
@@ -1520,9 +1665,10 @@
 {
 	struct gswip_priv *priv = ds->priv;
 
-	/* Enable the xMII interface only for the external PHY */
-	if (interface != PHY_INTERFACE_MODE_INTERNAL)
-		gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);
+	if (!dsa_is_cpu_port(ds, port))
+		gswip_port_set_link(priv, port, true);
+
+	gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);
 }
 
 static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset,
@@ -1812,11 +1958,23 @@
 	for_each_available_child_of_node(gphy_fw_list_np, gphy_fw_np) {
 		err = gswip_gphy_fw_probe(priv, &priv->gphy_fw[i],
 					  gphy_fw_np, i);
-		if (err)
+		if (err) {
+			of_node_put(gphy_fw_np);
 			goto remove_gphy;
+		}
 		i++;
 	}
 
+	/* The standalone PHY11G requires 300ms to be fully
+	 * initialized and ready for any MDIO communication after being
+	 * taken out of reset. For the SoC-internal GPHY variant there
+	 * is no (known) documentation for the minimum time after a
+	 * reset. Use the same value as for the standalone variant as
+	 * some users have reported internal PHYs not being detected
+	 * without any delay.
+	 */
+	msleep(300);
+
 	return 0;
 
 remove_gphy:
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz8795.c
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz8795.c
@@ -1267,6 +1267,9 @@
 			return -ENOMEM;
 	}
 
+	/* set the real number of ports */
+	dev->ds->num_ports = dev->port_cnt;
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz8795_spi.c
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz8795_spi.c
@@ -86,12 +86,23 @@
 };
 MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
 
+static const struct spi_device_id ksz8795_spi_ids[] = {
+	{ "ksz8765" },
+	{ "ksz8794" },
+	{ "ksz8795" },
+	{ "ksz8863" },
+	{ "ksz8873" },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids);
+
 static struct spi_driver ksz8795_spi_driver = {
 	.driver = {
 		.name	= "ksz8795-switch",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(ksz8795_dt_ids),
 	},
+	.id_table = ksz8795_spi_ids,
 	.probe	= ksz8795_spi_probe,
 	.remove	= ksz8795_spi_remove,
 	.shutdown = ksz8795_spi_shutdown,
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz9477.c
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz9477.c
@@ -682,10 +682,10 @@
 		ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]);
 
 		/* clear forwarding port */
-		alu_table[2] &= ~BIT(port);
+		alu_table[1] &= ~BIT(port);
 
 		/* if there is no port to forward, clear table */
-		if ((alu_table[2] & ALU_V_PORT_MAP) == 0) {
+		if ((alu_table[1] & ALU_V_PORT_MAP) == 0) {
 			alu_table[0] = 0;
 			alu_table[1] = 0;
 			alu_table[2] = 0;
@@ -766,6 +766,9 @@
 			goto exit;
 		}
 
+		if (!(ksz_data & ALU_VALID))
+			continue;
+
 		/* read ALU table */
 		ksz9477_read_table(dev, alu_table);
 
@@ -973,23 +976,6 @@
 			     PORT_MIRROR_SNIFFER, false);
 }
 
-static void ksz9477_phy_setup(struct ksz_device *dev, int port,
-			      struct phy_device *phy)
-{
-	/* Only apply to port with PHY. */
-	if (port >= dev->phy_port_cnt)
-		return;
-
-	/* The MAC actually cannot run in 1000 half-duplex mode. */
-	phy_remove_link_mode(phy,
-			     ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-
-	/* PHY does not support gigabit. */
-	if (!(dev->features & GBIT_SUPPORT))
-		phy_remove_link_mode(phy,
-				     ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
-}
-
 static bool ksz9477_get_gbit(struct ksz_device *dev, u8 data)
 {
 	bool gbit;
@@ -1537,6 +1523,7 @@
 		.num_statics = 16,
 		.cpu_ports = 0x7F,	/* can be configured as cpu port */
 		.port_cnt = 7,		/* total physical port count */
+		.phy_errata_9477 = true,
 	},
 };
 
@@ -1587,6 +1574,9 @@
 			return -ENOMEM;
 	}
 
+	/* set the real number of ports */
+	dev->ds->num_ports = dev->port_cnt;
+
 	return 0;
 }
 
@@ -1599,7 +1589,6 @@
 	.get_port_addr = ksz9477_get_port_addr,
 	.cfg_port_member = ksz9477_cfg_port_member,
 	.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
-	.phy_setup = ksz9477_phy_setup,
 	.port_setup = ksz9477_port_setup,
 	.r_mib_cnt = ksz9477_r_mib_cnt,
 	.r_mib_pkt = ksz9477_r_mib_pkt,
@@ -1613,7 +1602,29 @@
 
 int ksz9477_switch_register(struct ksz_device *dev)
 {
-	return ksz_switch_register(dev, &ksz9477_dev_ops);
+	int ret, i;
+	struct phy_device *phydev;
+
+	ret = ksz_switch_register(dev, &ksz9477_dev_ops);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < dev->phy_port_cnt; ++i) {
+		if (!dsa_is_user_port(dev->ds, i))
+			continue;
+
+		phydev = dsa_to_port(dev->ds, i)->slave->phydev;
+
+		/* The MAC actually cannot run in 1000 half-duplex mode. */
+		phy_remove_link_mode(phydev,
+				     ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+
+		/* PHY does not support gigabit. */
+		if (!(dev->features & GBIT_SUPPORT))
+			phy_remove_link_mode(phydev,
+					     ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
+	}
+	return ret;
 }
 EXPORT_SYMBOL(ksz9477_switch_register);
 
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz9477_spi.c
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz9477_spi.c
@@ -88,12 +88,24 @@
 };
 MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
 
+static const struct spi_device_id ksz9477_spi_ids[] = {
+	{ "ksz9477" },
+	{ "ksz9897" },
+	{ "ksz9893" },
+	{ "ksz9563" },
+	{ "ksz8563" },
+	{ "ksz9567" },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids);
+
 static struct spi_driver ksz9477_spi_driver = {
 	.driver = {
 		.name	= "ksz9477-switch",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(ksz9477_dt_ids),
 	},
+	.id_table = ksz9477_spi_ids,
 	.probe	= ksz9477_spi_probe,
 	.remove	= ksz9477_spi_remove,
 	.shutdown = ksz9477_spi_shutdown,
@@ -101,6 +113,12 @@
 
 module_spi_driver(ksz9477_spi_driver);
 
+MODULE_ALIAS("spi:ksz9477");
+MODULE_ALIAS("spi:ksz9897");
+MODULE_ALIAS("spi:ksz9893");
+MODULE_ALIAS("spi:ksz9563");
+MODULE_ALIAS("spi:ksz8563");
+MODULE_ALIAS("spi:ksz9567");
 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
 MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch SPI access Driver");
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz_common.c
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz_common.c
@@ -366,8 +366,6 @@
 
 	/* setup slave port */
 	dev->dev_ops->port_setup(dev, port, false);
-	if (dev->dev_ops->phy_setup)
-		dev->dev_ops->phy_setup(dev, port, phy);
 
 	/* port_stp_state_set() will be called after to enable the port so
 	 * there is no need to do anything.
--- linux-ein-5.4.0.orig/drivers/net/dsa/microchip/ksz_common.h
+++ linux-ein-5.4.0/drivers/net/dsa/microchip/ksz_common.h
@@ -120,8 +120,6 @@
 	u32 (*get_port_addr)(int port, int offset);
 	void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member);
 	void (*flush_dyn_mac_table)(struct ksz_device *dev, int port);
-	void (*phy_setup)(struct ksz_device *dev, int port,
-			  struct phy_device *phy);
 	void (*port_cleanup)(struct ksz_device *dev, int port);
 	void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port);
 	void (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
@@ -217,12 +215,8 @@
 	int ret;
 
 	ret = regmap_bulk_read(dev->regmap[2], reg, value, 2);
-	if (!ret) {
-		/* Ick! ToDo: Add 64bit R/W to regmap on 32bit systems */
-		value[0] = swab32(value[0]);
-		value[1] = swab32(value[1]);
-		*val = swab64((u64)*value);
-	}
+	if (!ret)
+		*val = (u64)value[0] << 32 | value[1];
 
 	return ret;
 }
--- linux-ein-5.4.0.orig/drivers/net/dsa/mt7530.c
+++ linux-ein-5.4.0/drivers/net/dsa/mt7530.c
@@ -45,6 +45,7 @@
 	MIB_DESC(2, 0x48, "TxBytes"),
 	MIB_DESC(1, 0x60, "RxDrop"),
 	MIB_DESC(1, 0x64, "RxFiltering"),
+	MIB_DESC(1, 0x68, "RxUnicast"),
 	MIB_DESC(1, 0x6c, "RxMulticast"),
 	MIB_DESC(1, 0x70, "RxBroadcast"),
 	MIB_DESC(1, 0x74, "RxAlignErr"),
@@ -67,58 +68,6 @@
 };
 
 static int
-mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
-{
-	int ret;
-
-	ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
-	if (ret < 0)
-		dev_err(priv->dev,
-			"failed to priv write register\n");
-	return ret;
-}
-
-static u32
-mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
-{
-	int ret;
-	u32 val;
-
-	ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
-	if (ret < 0) {
-		dev_err(priv->dev,
-			"failed to priv read register\n");
-		return ret;
-	}
-
-	return val;
-}
-
-static void
-mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
-		  u32 mask, u32 set)
-{
-	u32 val;
-
-	val = mt7623_trgmii_read(priv, reg);
-	val &= ~mask;
-	val |= set;
-	mt7623_trgmii_write(priv, reg, val);
-}
-
-static void
-mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-	mt7623_trgmii_rmw(priv, reg, 0, val);
-}
-
-static void
-mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-	mt7623_trgmii_rmw(priv, reg, val, 0);
-}
-
-static int
 core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
 {
 	struct mii_bus *bus = priv->bus;
@@ -448,9 +397,9 @@
 	case PHY_INTERFACE_MODE_TRGMII:
 		trgint = 1;
 		if (priv->id == ID_MT7621) {
-			/* PLL frequency: 150MHz: 1.2GBit */
+			/* PLL frequency: 125MHz: 1.0GBit */
 			if (xtal == HWTRAP_XTAL_40MHZ)
-				ncpo1 = 0x0780;
+				ncpo1 = 0x0640;
 			if (xtal == HWTRAP_XTAL_25MHZ)
 				ncpo1 = 0x0a00;
 		} else { /* PLL frequency: 250MHz: 2.0Gbit */
@@ -530,27 +479,6 @@
 		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
 			mt7530_rmw(priv, MT7530_TRGMII_RD(i),
 				   RD_TAP_MASK, RD_TAP(16));
-	else
-		if (priv->id != ID_MT7621)
-			mt7623_trgmii_set(priv, GSW_INTF_MODE,
-					  INTF_MODE_TRGMII);
-
-	return 0;
-}
-
-static int
-mt7623_pad_clk_setup(struct dsa_switch *ds)
-{
-	struct mt7530_priv *priv = ds->priv;
-	int i;
-
-	for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-		mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
-				    TD_DM_DRVP(8) | TD_DM_DRVN(8));
-
-	mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
-	mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
-
 	return 0;
 }
 
@@ -566,7 +494,7 @@
 static void
 mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
 {
-	u32 mask = PMCR_TX_EN | PMCR_RX_EN;
+	u32 mask = PMCR_TX_EN | PMCR_RX_EN | PMCR_FORCE_LNK;
 
 	if (enable)
 		mt7530_set(priv, MT7530_PMCR_P(port), mask);
@@ -712,14 +640,11 @@
 	mt7530_write(priv, MT7530_PVC_P(port),
 		     PORT_SPEC_TAG);
 
-	/* Disable auto learning on the cpu port */
-	mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
-
-	/* Unknown unicast frame fordwarding to the cpu port */
-	mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
+	/* Unknown multicast frame forwarding to the cpu port */
+	mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port)));
 
 	/* Set CPU port number */
-	if (priv->id == ID_MT7621)
+	if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
 		mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
 
 	/* CPU port gets connected to all user ports of
@@ -857,8 +782,9 @@
 	 */
 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
 		   MT7530_PORT_MATRIX_MODE);
-	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
-		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT));
+	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT) |
+		   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
 
 	for (i = 0; i < MT7530_NUM_PORTS; i++) {
 		if (dsa_is_user_port(ds, i) &&
@@ -874,8 +800,8 @@
 	if (all_user_ports_removed) {
 		mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT),
 			     PCR_MATRIX(dsa_user_ports(priv->ds)));
-		mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT),
-			     PORT_SPEC_TAG);
+		mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG
+			     | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
 	}
 }
 
@@ -884,25 +810,23 @@
 {
 	struct mt7530_priv *priv = ds->priv;
 
-	/* The real fabric path would be decided on the membership in the
-	 * entry of VLAN table. PCR_MATRIX set up here with ALL_MEMBERS
-	 * means potential VLAN can be consisting of certain subset of all
-	 * ports.
-	 */
-	mt7530_rmw(priv, MT7530_PCR_P(port),
-		   PCR_MATRIX_MASK, PCR_MATRIX(MT7530_ALL_MEMBERS));
-
 	/* Trapped into security mode allows packet forwarding through VLAN
-	 * table lookup.
+	 * table lookup. CPU port is set to fallback mode to let untagged
+	 * frames pass through.
 	 */
-	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
-		   MT7530_PORT_SECURITY_MODE);
+	if (dsa_is_cpu_port(ds, port))
+		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
+			   MT7530_PORT_FALLBACK_MODE);
+	else
+		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
+			   MT7530_PORT_SECURITY_MODE);
 
 	/* Set the port as a user port which is to be able to recognize VID
 	 * from incoming packets before fetching entry within the VLAN table.
 	 */
-	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
-		   VLAN_ATTR(MT7530_VLAN_USER));
+	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+		   VLAN_ATTR(MT7530_VLAN_USER) |
+		   PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
 }
 
 static void
@@ -918,11 +842,8 @@
 		/* Remove this port from the port matrix of the other ports
 		 * in the same bridge. If the port is disabled, port matrix
 		 * is kept and not being setup until the port becomes enabled.
-		 * And the other port's port matrix cannot be broken when the
-		 * other port is still a VLAN-aware port.
 		 */
-		if (dsa_is_user_port(ds, i) && i != port &&
-		   !dsa_port_is_vlan_filtering(&ds->ports[i])) {
+		if (dsa_is_user_port(ds, i) && i != port) {
 			if (dsa_to_port(ds, i)->bridge_dev != bridge)
 				continue;
 			if (priv->ports[i].enable)
@@ -1255,10 +1176,6 @@
 	dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent;
 
 	if (priv->id == ID_MT7530) {
-		priv->ethernet = syscon_node_to_regmap(dn);
-		if (IS_ERR(priv->ethernet))
-			return PTR_ERR(priv->ethernet);
-
 		regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
 		ret = regulator_enable(priv->core_pwr);
 		if (ret < 0) {
@@ -1321,8 +1238,6 @@
 	/* Enable and reset MIB counters */
 	mt7530_mib_reset(ds);
 
-	mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
-
 	for (i = 0; i < MT7530_NUM_PORTS; i++) {
 		/* Disable forwarding by default on all ports */
 		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
@@ -1332,6 +1247,10 @@
 			mt7530_cpu_port_enable(priv, i);
 		else
 			mt7530_port_disable(ds, i);
+
+		/* Enable consistent egress tag */
+		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
+			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
 	}
 
 	/* Setup port 5 */
@@ -1353,6 +1272,9 @@
 				continue;
 
 			phy_node = of_parse_phandle(mac_np, "phy-handle", 0);
+			if (!phy_node)
+				continue;
+
 			if (phy_node->parent == priv->dev->of_node->parent) {
 				interface = of_get_phy_mode(mac_np);
 				id = of_mdio_parse_addr(ds->dev, phy_node);
@@ -1413,14 +1335,6 @@
 		/* Setup TX circuit incluing relevant PAD and driving */
 		mt7530_pad_clk_setup(ds, state->interface);
 
-		if (priv->id == ID_MT7530) {
-			/* Setup RX circuit, relevant PAD and driving on the
-			 * host which must be placed after the setup on the
-			 * device side is all finished.
-			 */
-			mt7623_pad_clk_setup(ds);
-		}
-
 		priv->p6_interface = state->interface;
 		break;
 	default:
@@ -1439,7 +1353,7 @@
 	mcr_new &= ~(PMCR_FORCE_SPEED_1000 | PMCR_FORCE_SPEED_100 |
 		     PMCR_FORCE_FDX | PMCR_TX_FC_EN | PMCR_RX_FC_EN);
 	mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
-		   PMCR_BACKPR_EN | PMCR_FORCE_MODE | PMCR_FORCE_LNK;
+		   PMCR_BACKPR_EN | PMCR_FORCE_MODE;
 
 	/* Are we connected to external phy */
 	if (port == 5 && dsa_is_user_port(ds, 5))
@@ -1532,7 +1446,7 @@
 		phylink_set(mask, 100baseT_Full);
 
 		if (state->interface != PHY_INTERFACE_MODE_MII) {
-			phylink_set(mask, 1000baseT_Half);
+			/* This switch only supports 1G full-duplex. */
 			phylink_set(mask, 1000baseT_Full);
 			if (port == 5)
 				phylink_set(mask, 1000baseX_Full);
--- linux-ein-5.4.0.orig/drivers/net/dsa/mt7530.h
+++ linux-ein-5.4.0/drivers/net/dsa/mt7530.h
@@ -31,6 +31,7 @@
 #define MT7530_MFC			0x10
 #define  BC_FFP(x)			(((x) & 0xff) << 24)
 #define  UNM_FFP(x)			(((x) & 0xff) << 16)
+#define  UNM_FFP_MASK			UNM_FFP(~0)
 #define  UNU_FFP(x)			(((x) & 0xff) << 8)
 #define  UNU_FFP_MASK			UNU_FFP(~0)
 #define  CPU_EN				BIT(7)
@@ -147,6 +148,12 @@
 	/* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */
 	MT7530_PORT_MATRIX_MODE = PORT_VLAN(0),
 
+	/* Fallback Mode: Forward received frames with ingress ports that do
+	 * not belong to the VLAN member. Frames whose VID is not listed on
+	 * the VLAN table are forwarded by the PCR_MATRIX members.
+	 */
+	MT7530_PORT_FALLBACK_MODE = PORT_VLAN(1),
+
 	/* Security Mode: Discard any frame due to ingress membership
 	 * violation or VID missed on the VLAN table.
 	 */
@@ -167,9 +174,16 @@
 /* Register for port vlan control */
 #define MT7530_PVC_P(x)			(0x2010 + ((x) * 0x100))
 #define  PORT_SPEC_TAG			BIT(5)
+#define  PVC_EG_TAG(x)			(((x) & 0x7) << 8)
+#define  PVC_EG_TAG_MASK		PVC_EG_TAG(7)
 #define  VLAN_ATTR(x)			(((x) & 0x3) << 6)
 #define  VLAN_ATTR_MASK			VLAN_ATTR(3)
 
+enum mt7530_vlan_port_eg_tag {
+	MT7530_VLAN_EG_DISABLED = 0,
+	MT7530_VLAN_EG_CONSISTENT = 1,
+};
+
 enum mt7530_vlan_port_attr {
 	MT7530_VLAN_USER = 0,
 	MT7530_VLAN_TRANSPARENT = 3,
@@ -268,7 +282,6 @@
 
 /* Registers for TRGMII on the both side */
 #define MT7530_TRGMII_RCK_CTRL		0x7a00
-#define GSW_TRGMII_RCK_CTRL		0x300
 #define  RX_RST				BIT(31)
 #define  RXC_DQSISEL			BIT(30)
 #define  DQSI1_TAP_MASK			(0x7f << 8)
@@ -277,31 +290,24 @@
 #define  DQSI0_TAP(x)			((x) & 0x7f)
 
 #define MT7530_TRGMII_RCK_RTT		0x7a04
-#define GSW_TRGMII_RCK_RTT		0x304
 #define  DQS1_GATE			BIT(31)
 #define  DQS0_GATE			BIT(30)
 
 #define MT7530_TRGMII_RD(x)		(0x7a10 + (x) * 8)
-#define GSW_TRGMII_RD(x)		(0x310 + (x) * 8)
 #define  BSLIP_EN			BIT(31)
 #define  EDGE_CHK			BIT(30)
 #define  RD_TAP_MASK			0x7f
 #define  RD_TAP(x)			((x) & 0x7f)
 
-#define GSW_TRGMII_TXCTRL		0x340
 #define MT7530_TRGMII_TXCTRL		0x7a40
 #define  TRAIN_TXEN			BIT(31)
 #define  TXC_INV			BIT(30)
 #define  TX_RST				BIT(28)
 
 #define MT7530_TRGMII_TD_ODT(i)		(0x7a54 + 8 * (i))
-#define GSW_TRGMII_TD_ODT(i)		(0x354 + 8 * (i))
 #define  TD_DM_DRVP(x)			((x) & 0xf)
 #define  TD_DM_DRVN(x)			(((x) & 0xf) << 4)
 
-#define GSW_INTF_MODE			0x390
-#define  INTF_MODE_TRGMII		BIT(1)
-
 #define MT7530_TRGMII_TCK_CTRL		0x7a78
 #define  TCK_TAP(x)			(((x) & 0xf) << 8)
 
@@ -434,7 +440,6 @@
  * @ds:			The pointer to the dsa core structure
  * @bus:		The bus used for the device and built-in PHY
  * @rstc:		The pointer to reset control used by MCM
- * @ethernet:		The regmap used for access TRGMII-based registers
  * @core_pwr:		The power supplied into the core
  * @io_pwr:		The power supplied into the I/O
  * @reset:		The descriptor for GPIO line tied to its reset pin
@@ -451,7 +456,6 @@
 	struct dsa_switch	*ds;
 	struct mii_bus		*bus;
 	struct reset_control	*rstc;
-	struct regmap		*ethernet;
 	struct regulator	*core_pwr;
 	struct regulator	*io_pwr;
 	struct gpio_desc	*reset;
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6060.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6060.c
@@ -117,6 +117,9 @@
 	int addr = REG_PORT(p);
 	int ret;
 
+	if (dsa_is_unused_port(priv->ds, p))
+		return 0;
+
 	/* Do not force flow control, disable Ingress and Egress
 	 * Header tagging, disable VLAN tunneling, and set the port
 	 * state to Forwarding.  Additionally, if this is the CPU
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/chip.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1517,7 +1517,11 @@
 		if (!entry.portvec)
 			entry.state = 0;
 	} else {
-		entry.portvec |= BIT(port);
+		if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
+			entry.portvec = BIT(port);
+		else
+			entry.portvec |= BIT(port);
+
 		entry.state = state;
 	}
 
@@ -2139,10 +2143,22 @@
 
 	/* If there is a GPIO connected to the reset pin, toggle it */
 	if (gpiod) {
+		/* If the switch has just been reset and not yet completed
+		 * loading EEPROM, the reset may interrupt the I2C transaction
+		 * mid-byte, causing the first EEPROM read after the reset
+		 * from the wrong location resulting in the switch booting
+		 * to wrong mode and inoperable.
+		 */
+		if (chip->info->ops->get_eeprom)
+			mv88e6xxx_g2_eeprom_wait(chip);
+
 		gpiod_set_value_cansleep(gpiod, 1);
 		usleep_range(10000, 20000);
 		gpiod_set_value_cansleep(gpiod, 0);
 		usleep_range(10000, 20000);
+
+		if (chip->info->ops->get_eeprom)
+			mv88e6xxx_g2_eeprom_wait(chip);
 	}
 }
 
@@ -2427,9 +2443,14 @@
 	 * If this is the upstream port for this switch, enable
 	 * forwarding of unknown unicasts and multicasts.
 	 */
-	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
-		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
+	reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
 		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
+	/* Forward any IPv4 IGMP or IPv6 MLD frames received
+	 * by a USER port to the CPU port to allow snooping.
+	 */
+	if (dsa_is_user_port(ds, port))
+		reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP;
+
 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
 	if (err)
 		return err;
@@ -2760,10 +2781,17 @@
 	return err;
 }
 
+/* prod_id for switch families which do not have a PHY model number */
+static const u16 family_prod_id_table[] = {
+	[MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
+	[MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
+};
+
 static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
 {
 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
 	struct mv88e6xxx_chip *chip = mdio_bus->chip;
+	u16 prod_id;
 	u16 val;
 	int err;
 
@@ -2774,23 +2802,12 @@
 	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
 	mv88e6xxx_reg_unlock(chip);
 
-	if (reg == MII_PHYSID2) {
-		/* Some internal PHYs don't have a model number. */
-		if (chip->info->family != MV88E6XXX_FAMILY_6165)
-			/* Then there is the 6165 family. It gets is
-			 * PHYs correct. But it can also have two
-			 * SERDES interfaces in the PHY address
-			 * space. And these don't have a model
-			 * number. But they are not PHYs, so we don't
-			 * want to give them something a PHY driver
-			 * will recognise.
-			 *
-			 * Use the mv88e6390 family model number
-			 * instead, for anything which really could be
-			 * a PHY,
-			 */
-			if (!(val & 0x3f0))
-				val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
+	/* Some internal PHYs don't have a model number. */
+	if (reg == MII_PHYSID2 && !(val & 0x3f0) &&
+	    chip->info->family < ARRAY_SIZE(family_prod_id_table)) {
+		prod_id = family_prod_id_table[chip->info->family];
+		if (prod_id)
+			val |= prod_id >> 4;
 	}
 
 	return err ? err : val;
@@ -2908,6 +2925,7 @@
 	 */
 	child = of_get_child_by_name(np, "mdio");
 	err = mv88e6xxx_mdio_register(chip, child, false);
+	of_node_put(child);
 	if (err)
 		return err;
 
@@ -3060,10 +3078,10 @@
 	.port_set_duplex = mv88e6xxx_port_set_duplex,
 	.port_set_speed = mv88e6185_port_set_speed,
 	.port_tag_remap = mv88e6095_port_tag_remap,
+	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
 	.port_set_ether_type = mv88e6351_port_set_ether_type,
-	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
 	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
 	.port_pause_limit = mv88e6097_port_pause_limit,
 	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
@@ -3191,7 +3209,7 @@
 	.port_set_cmode = mv88e6341_port_set_cmode,
 	.port_setup_message_port = mv88e6xxx_setup_message_port,
 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
-	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
 	.stats_get_strings = mv88e6320_stats_get_strings,
 	.stats_get_stats = mv88e6390_stats_get_stats,
@@ -3714,6 +3732,7 @@
 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
 	.port_set_speed = mv88e6250_port_set_speed,
 	.port_tag_remap = mv88e6095_port_tag_remap,
+	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
 	.port_set_ether_type = mv88e6351_port_set_ether_type,
@@ -3867,6 +3886,7 @@
 	.set_cpu_port = mv88e6095_g1_set_cpu_port,
 	.set_egress_port = mv88e6095_g1_set_egress_port,
 	.watchdog_ops = &mv88e6390_watchdog_ops,
+	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
@@ -3905,7 +3925,7 @@
 	.port_set_cmode = mv88e6341_port_set_cmode,
 	.port_setup_message_port = mv88e6xxx_setup_message_port,
 	.stats_snapshot = mv88e6390_g1_stats_snapshot,
-	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
 	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
 	.stats_get_strings = mv88e6320_stats_get_strings,
 	.stats_get_stats = mv88e6390_stats_get_stats,
@@ -3915,6 +3935,7 @@
 	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
 	.pot_clear = mv88e6xxx_g2_pot_clear,
 	.reset = mv88e6352_g1_reset,
+	.rmu_disable = mv88e6390_g1_rmu_disable,
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
@@ -3981,6 +4002,7 @@
 	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
 	.port_set_speed = mv88e6185_port_set_speed,
 	.port_tag_remap = mv88e6095_port_tag_remap,
+	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
 	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
 	.port_set_ether_type = mv88e6351_port_set_ether_type,
@@ -4003,6 +4025,7 @@
 	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
 	.pot_clear = mv88e6xxx_g2_pot_clear,
 	.reset = mv88e6352_g1_reset,
+	.rmu_disable = mv88e6390_g1_rmu_disable,
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.avb_ops = &mv88e6352_avb_ops,
@@ -5083,7 +5106,7 @@
 		goto out;
 	}
 	if (chip->reset)
-		usleep_range(1000, 2000);
+		usleep_range(10000, 20000);
 
 	err = mv88e6xxx_detect(chip);
 	if (err)
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/global1.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/global1.c
@@ -332,6 +332,11 @@
 {
 	u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST;
 
+	/* Use the default high priority for management frames sent to
+	 * the CPU.
+	 */
+	port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI;
+
 	return mv88e6390_g1_monitor_write(chip, ptr, port);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/global1.h
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/global1.h
@@ -210,6 +210,7 @@
 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST		0x2000
 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST		0x2100
 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST		0x3000
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI	0x00e0
 #define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK			0x00ff
 
 /* Offset 0x1C: Global Control 2 */
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/global1_vtu.c
@@ -125,11 +125,9 @@
  * Offset 0x08: VTU/STU Data Register 2
  * Offset 0x09: VTU/STU Data Register 3
  */
-
-static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
-				      struct mv88e6xxx_vtu_entry *entry)
+static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
+					  u16 *regs)
 {
-	u16 regs[3];
 	int i;
 
 	/* Read all 3 VTU/STU Data registers */
@@ -142,12 +140,45 @@
 			return err;
 	}
 
-	/* Extract MemberTag and PortState data */
+	return 0;
+}
+
+static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
+				      struct mv88e6xxx_vtu_entry *entry)
+{
+	u16 regs[3];
+	int err;
+	int i;
+
+	err = mv88e6185_g1_vtu_stu_data_read(chip, regs);
+	if (err)
+		return err;
+
+	/* Extract MemberTag data */
 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
 		unsigned int member_offset = (i % 4) * 4;
-		unsigned int state_offset = member_offset + 2;
 
 		entry->member[i] = (regs[i / 4] >> member_offset) & 0x3;
+	}
+
+	return 0;
+}
+
+static int mv88e6185_g1_stu_data_read(struct mv88e6xxx_chip *chip,
+				      struct mv88e6xxx_vtu_entry *entry)
+{
+	u16 regs[3];
+	int err;
+	int i;
+
+	err = mv88e6185_g1_vtu_stu_data_read(chip, regs);
+	if (err)
+		return err;
+
+	/* Extract PortState data */
+	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
+		unsigned int state_offset = (i % 4) * 4 + 2;
+
 		entry->state[i] = (regs[i / 4] >> state_offset) & 0x3;
 	}
 
@@ -320,6 +351,10 @@
 		if (err)
 			return err;
 
+		err = mv88e6185_g1_stu_data_read(chip, entry);
+		if (err)
+			return err;
+
 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
 		 * VTU DBNum[5:4] are located in VTU Operation 9:8
 		 */
@@ -349,6 +384,10 @@
 		if (err)
 			return err;
 
+		err = mv88e6185_g1_stu_data_read(chip, entry);
+		if (err)
+			return err;
+
 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
 		 * VTU DBNum[7:4] are located in VTU Operation 11:8
 		 */
@@ -374,16 +413,20 @@
 		return err;
 
 	if (entry->valid) {
-		/* Fetch (and mask) VLAN PortState data from the STU */
-		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
+		err = mv88e6185_g1_vtu_data_read(chip, entry);
 		if (err)
 			return err;
 
-		err = mv88e6185_g1_vtu_data_read(chip, entry);
+		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
 		if (err)
 			return err;
 
-		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
+		/* Fetch VLAN PortState data from the STU */
+		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
+		if (err)
+			return err;
+
+		err = mv88e6185_g1_stu_data_read(chip, entry);
 		if (err)
 			return err;
 	}
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/global2.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/global2.c
@@ -310,7 +310,7 @@
  * Offset 0x15: EEPROM Addr (for 8-bit data access)
  */
 
-static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
+int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
 {
 	int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
 	int err;
@@ -1083,6 +1083,13 @@
 {
 	int err, irq, virq;
 
+	chip->g2_irq.masked = ~0;
+	mv88e6xxx_reg_lock(chip);
+	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
+	mv88e6xxx_reg_unlock(chip);
+	if (err)
+		return err;
+
 	chip->g2_irq.domain = irq_domain_add_simple(
 		chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
 	if (!chip->g2_irq.domain)
@@ -1092,7 +1099,6 @@
 		irq_create_mapping(chip->g2_irq.domain, irq);
 
 	chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
-	chip->g2_irq.masked = ~0;
 
 	chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
 					    MV88E6XXX_G1_STS_IRQ_DEVICE);
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/global2.h
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/global2.h
@@ -340,6 +340,7 @@
 
 int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
 				      int port);
+int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip);
 
 extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
 extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops;
--- linux-ein-5.4.0.orig/drivers/net/dsa/mv88e6xxx/port.c
+++ linux-ein-5.4.0/drivers/net/dsa/mv88e6xxx/port.c
@@ -393,7 +393,7 @@
 }
 
 static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
-				    phy_interface_t mode)
+				    phy_interface_t mode, bool force)
 {
 	u8 lane;
 	u16 cmode;
@@ -427,8 +427,8 @@
 		cmode = 0;
 	}
 
-	/* cmode doesn't change, nothing to do for us */
-	if (cmode == chip->ports[port].cmode)
+	/* cmode doesn't change, nothing to do for us unless forced */
+	if (cmode == chip->ports[port].cmode && !force)
 		return 0;
 
 	lane = mv88e6xxx_serdes_get_lane(chip, port);
@@ -484,7 +484,7 @@
 	if (port != 9 && port != 10)
 		return -EOPNOTSUPP;
 
-	return mv88e6xxx_port_set_cmode(chip, port, mode);
+	return mv88e6xxx_port_set_cmode(chip, port, mode, false);
 }
 
 int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
@@ -504,7 +504,7 @@
 		break;
 	}
 
-	return mv88e6xxx_port_set_cmode(chip, port, mode);
+	return mv88e6xxx_port_set_cmode(chip, port, mode, false);
 }
 
 static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
@@ -555,7 +555,7 @@
 	if (err)
 		return err;
 
-	return mv88e6xxx_port_set_cmode(chip, port, mode);
+	return mv88e6xxx_port_set_cmode(chip, port, mode, true);
 }
 
 int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
--- linux-ein-5.4.0.orig/drivers/net/dsa/realtek-smi-core.h
+++ linux-ein-5.4.0/drivers/net/dsa/realtek-smi-core.h
@@ -25,6 +25,9 @@
 	const char	*name;
 };
 
+/**
+ * struct rtl8366_vlan_mc - Virtual LAN member configuration
+ */
 struct rtl8366_vlan_mc {
 	u16	vid;
 	u16	untag;
@@ -119,7 +122,6 @@
 int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used);
 int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member,
 		     u32 untag, u32 fid);
-int rtl8366_get_pvid(struct realtek_smi *smi, int port, int *val);
 int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port,
 		     unsigned int vid);
 int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable);
--- linux-ein-5.4.0.orig/drivers/net/dsa/rtl8366.c
+++ linux-ein-5.4.0/drivers/net/dsa/rtl8366.c
@@ -36,113 +36,66 @@
 }
 EXPORT_SYMBOL_GPL(rtl8366_mc_is_used);
 
-int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member,
-		     u32 untag, u32 fid)
+/**
+ * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration
+ * @smi: the Realtek SMI device instance
+ * @vid: the VLAN ID to look up or allocate
+ * @vlanmc: the pointer will be assigned to a pointer to a valid member config
+ * if successful
+ * @return: index of a new member config or negative error number
+ */
+static int rtl8366_obtain_mc(struct realtek_smi *smi, int vid,
+			     struct rtl8366_vlan_mc *vlanmc)
 {
 	struct rtl8366_vlan_4k vlan4k;
 	int ret;
 	int i;
 
-	/* Update the 4K table */
-	ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
-	if (ret)
-		return ret;
-
-	vlan4k.member = member;
-	vlan4k.untag = untag;
-	vlan4k.fid = fid;
-	ret = smi->ops->set_vlan_4k(smi, &vlan4k);
-	if (ret)
-		return ret;
-
-	/* Try to find an existing MC entry for this VID */
+	/* Try to find an existing member config entry for this VID */
 	for (i = 0; i < smi->num_vlan_mc; i++) {
-		struct rtl8366_vlan_mc vlanmc;
-
-		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
-		if (ret)
+		ret = smi->ops->get_vlan_mc(smi, i, vlanmc);
+		if (ret) {
+			dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n",
+				i, vid);
 			return ret;
-
-		if (vid == vlanmc.vid) {
-			/* update the MC entry */
-			vlanmc.member = member;
-			vlanmc.untag = untag;
-			vlanmc.fid = fid;
-
-			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
-			break;
 		}
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
 
-int rtl8366_get_pvid(struct realtek_smi *smi, int port, int *val)
-{
-	struct rtl8366_vlan_mc vlanmc;
-	int ret;
-	int index;
-
-	ret = smi->ops->get_mc_index(smi, port, &index);
-	if (ret)
-		return ret;
-
-	ret = smi->ops->get_vlan_mc(smi, index, &vlanmc);
-	if (ret)
-		return ret;
-
-	*val = vlanmc.vid;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtl8366_get_pvid);
-
-int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port,
-		     unsigned int vid)
-{
-	struct rtl8366_vlan_mc vlanmc;
-	struct rtl8366_vlan_4k vlan4k;
-	int ret;
-	int i;
-
-	/* Try to find an existing MC entry for this VID */
-	for (i = 0; i < smi->num_vlan_mc; i++) {
-		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
-		if (ret)
-			return ret;
-
-		if (vid == vlanmc.vid) {
-			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
-			if (ret)
-				return ret;
-
-			ret = smi->ops->set_mc_index(smi, port, i);
-			return ret;
-		}
+		if (vid == vlanmc->vid)
+			return i;
 	}
 
 	/* We have no MC entry for this VID, try to find an empty one */
 	for (i = 0; i < smi->num_vlan_mc; i++) {
-		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
-		if (ret)
+		ret = smi->ops->get_vlan_mc(smi, i, vlanmc);
+		if (ret) {
+			dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n",
+				i, vid);
 			return ret;
+		}
 
-		if (vlanmc.vid == 0 && vlanmc.member == 0) {
+		if (vlanmc->vid == 0 && vlanmc->member == 0) {
 			/* Update the entry from the 4K table */
 			ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
-			if (ret)
+			if (ret) {
+				dev_err(smi->dev, "error looking for 4K VLAN MC %d for VID %d\n",
+					i, vid);
 				return ret;
+			}
 
-			vlanmc.vid = vid;
-			vlanmc.member = vlan4k.member;
-			vlanmc.untag = vlan4k.untag;
-			vlanmc.fid = vlan4k.fid;
-			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
-			if (ret)
+			vlanmc->vid = vid;
+			vlanmc->member = vlan4k.member;
+			vlanmc->untag = vlan4k.untag;
+			vlanmc->fid = vlan4k.fid;
+			ret = smi->ops->set_vlan_mc(smi, i, vlanmc);
+			if (ret) {
+				dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n",
+					i, vid);
 				return ret;
+			}
 
-			ret = smi->ops->set_mc_index(smi, port, i);
-			return ret;
+			dev_dbg(smi->dev, "created new MC at index %d for VID %d\n",
+				i, vid);
+			return i;
 		}
 	}
 
@@ -160,24 +113,110 @@
 			if (ret)
 				return ret;
 
-			vlanmc.vid = vid;
-			vlanmc.member = vlan4k.member;
-			vlanmc.untag = vlan4k.untag;
-			vlanmc.fid = vlan4k.fid;
-			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
-			if (ret)
+			vlanmc->vid = vid;
+			vlanmc->member = vlan4k.member;
+			vlanmc->untag = vlan4k.untag;
+			vlanmc->fid = vlan4k.fid;
+			ret = smi->ops->set_vlan_mc(smi, i, vlanmc);
+			if (ret) {
+				dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n",
+					i, vid);
 				return ret;
-
-			ret = smi->ops->set_mc_index(smi, port, i);
-			return ret;
+			}
+			dev_dbg(smi->dev, "recycled MC at index %i for VID %d\n",
+				i, vid);
+			return i;
 		}
 	}
 
-	dev_err(smi->dev,
-		"all VLAN member configurations are in use\n");
-
+	dev_err(smi->dev, "all VLAN member configurations are in use\n");
 	return -ENOSPC;
 }
+
+int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member,
+		     u32 untag, u32 fid)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	struct rtl8366_vlan_4k vlan4k;
+	int mc;
+	int ret;
+
+	if (!smi->ops->is_vlan_valid(smi, vid))
+		return -EINVAL;
+
+	dev_dbg(smi->dev,
+		"setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
+		vid, member, untag);
+
+	/* Update the 4K table */
+	ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+	if (ret)
+		return ret;
+
+	vlan4k.member |= member;
+	vlan4k.untag |= untag;
+	vlan4k.fid = fid;
+	ret = smi->ops->set_vlan_4k(smi, &vlan4k);
+	if (ret)
+		return ret;
+
+	dev_dbg(smi->dev,
+		"resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
+		vid, vlan4k.member, vlan4k.untag);
+
+	/* Find or allocate a member config for this VID */
+	ret = rtl8366_obtain_mc(smi, vid, &vlanmc);
+	if (ret < 0)
+		return ret;
+	mc = ret;
+
+	/* Update the MC entry */
+	vlanmc.member |= member;
+	vlanmc.untag |= untag;
+	vlanmc.fid = fid;
+
+	/* Commit updates to the MC entry */
+	ret = smi->ops->set_vlan_mc(smi, mc, &vlanmc);
+	if (ret)
+		dev_err(smi->dev, "failed to commit changes to VLAN MC index %d for VID %d\n",
+			mc, vid);
+	else
+		dev_dbg(smi->dev,
+			"resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n",
+			vid, vlanmc.member, vlanmc.untag);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
+
+int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port,
+		     unsigned int vid)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	int mc;
+	int ret;
+
+	if (!smi->ops->is_vlan_valid(smi, vid))
+		return -EINVAL;
+
+	/* Find or allocate a member config for this VID */
+	ret = rtl8366_obtain_mc(smi, vid, &vlanmc);
+	if (ret < 0)
+		return ret;
+	mc = ret;
+
+	ret = smi->ops->set_mc_index(smi, port, mc);
+	if (ret) {
+		dev_err(smi->dev, "set PVID: failed to set MC index %d for port %d\n",
+			mc, port);
+		return ret;
+	}
+
+	dev_dbg(smi->dev, "set PVID: the PVID for port %d set to %d using existing MC index %d\n",
+		port, vid, mc);
+
+	return 0;
+}
 EXPORT_SYMBOL_GPL(rtl8366_set_pvid);
 
 int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable)
@@ -376,7 +415,8 @@
 		if (!smi->ops->is_vlan_valid(smi, vid))
 			return;
 
-	dev_info(smi->dev, "add VLAN on port %d, %s, %s\n",
+	dev_info(smi->dev, "add VLAN %d on port %d, %s, %s\n",
+		 vlan->vid_begin,
 		 port,
 		 untagged ? "untagged" : "tagged",
 		 pvid ? " PVID" : "no PVID");
@@ -384,36 +424,31 @@
 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
 		dev_err(smi->dev, "port is DSA or CPU port\n");
 
-	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
-		int pvid_val = 0;
-
-		dev_info(smi->dev, "add VLAN %04x\n", vid);
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
 		member |= BIT(port);
 
 		if (untagged)
 			untag |= BIT(port);
 
-		/* To ensure that we have a valid MC entry for this VLAN,
-		 * initialize the port VLAN ID here.
-		 */
-		ret = rtl8366_get_pvid(smi, port, &pvid_val);
-		if (ret < 0) {
-			dev_err(smi->dev, "could not lookup PVID for port %d\n",
-				port);
-			return;
-		}
-		if (pvid_val == 0) {
-			ret = rtl8366_set_pvid(smi, port, vid);
-			if (ret < 0)
-				return;
-		}
-	}
+		ret = rtl8366_set_vlan(smi, vid, member, untag, 0);
+		if (ret)
+			dev_err(smi->dev,
+				"failed to set up VLAN %04x",
+				vid);
 
-	ret = rtl8366_set_vlan(smi, port, member, untag, 0);
-	if (ret)
-		dev_err(smi->dev,
-			"failed to set up VLAN %04x",
-			vid);
+		if (!pvid)
+			continue;
+
+		ret = rtl8366_set_pvid(smi, port, vid);
+		if (ret)
+			dev_err(smi->dev,
+				"failed to set PVID on port %d to VLAN %04x",
+				port, vid);
+
+		if (!ret)
+			dev_dbg(smi->dev, "VLAN add: added VLAN %d with PVID on port %d\n",
+				vid, port);
+	}
 }
 EXPORT_SYMBOL_GPL(rtl8366_vlan_add);
 
@@ -439,13 +474,19 @@
 				return ret;
 
 			if (vid == vlanmc.vid) {
-				/* clear VLAN member configurations */
-				vlanmc.vid = 0;
-				vlanmc.priority = 0;
-				vlanmc.member = 0;
-				vlanmc.untag = 0;
-				vlanmc.fid = 0;
-
+				/* Remove this port from the VLAN */
+				vlanmc.member &= ~BIT(port);
+				vlanmc.untag &= ~BIT(port);
+				/*
+				 * If no ports are members of this VLAN
+				 * anymore then clear the whole member
+				 * config so it can be reused.
+				 */
+				if (!vlanmc.member && vlanmc.untag) {
+					vlanmc.vid = 0;
+					vlanmc.priority = 0;
+					vlanmc.fid = 0;
+				}
 				ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
 				if (ret) {
 					dev_err(smi->dev,
--- linux-ein-5.4.0.orig/drivers/net/dsa/rtl8366rb.c
+++ linux-ein-5.4.0/drivers/net/dsa/rtl8366rb.c
@@ -1264,12 +1264,12 @@
 
 static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan)
 {
-	unsigned int max = RTL8366RB_NUM_VLANS;
+	unsigned int max = RTL8366RB_NUM_VLANS - 1;
 
 	if (smi->vlan4k_enabled)
 		max = RTL8366RB_NUM_VIDS - 1;
 
-	if (vlan == 0 || vlan >= max)
+	if (vlan == 0 || vlan > max)
 		return false;
 
 	return true;
--- linux-ein-5.4.0.orig/drivers/net/dsa/sja1105/sja1105_main.c
+++ linux-ein-5.4.0/drivers/net/dsa/sja1105/sja1105_main.c
@@ -178,6 +178,7 @@
 		default:
 			dev_err(dev, "Unsupported PHY mode %s!\n",
 				phy_modes(ports[i].phy_mode));
+			return -EINVAL;
 		}
 
 		mii->phy_mac[i] = ports[i].role;
@@ -594,15 +595,15 @@
 	int i;
 
 	for (i = 0; i < SJA1105_NUM_PORTS; i++) {
-		if (ports->role == XMII_MAC)
+		if (ports[i].role == XMII_MAC)
 			continue;
 
-		if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
-		    ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+		if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
+		    ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
 			priv->rgmii_rx_delay[i] = true;
 
-		if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
-		    ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+		if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
+		    ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
 			priv->rgmii_tx_delay[i] = true;
 
 		if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) &&
@@ -619,7 +620,7 @@
 	struct device *dev = &priv->spidev->dev;
 	struct device_node *child;
 
-	for_each_child_of_node(ports_node, child) {
+	for_each_available_child_of_node(ports_node, child) {
 		struct device_node *phy_node;
 		int phy_mode;
 		u32 index;
@@ -991,10 +992,11 @@
 int sja1105et_fdb_add(struct dsa_switch *ds, int port,
 		      const unsigned char *addr, u16 vid)
 {
-	struct sja1105_l2_lookup_entry l2_lookup = {0};
+	struct sja1105_l2_lookup_entry l2_lookup = {0}, tmp;
 	struct sja1105_private *priv = ds->priv;
 	struct device *dev = ds->dev;
 	int last_unused = -1;
+	int start, end, i;
 	int bin, way, rc;
 
 	bin = sja1105et_fdb_hash(priv, addr, vid);
@@ -1006,7 +1008,7 @@
 		 * mask? If yes, we need to do nothing. If not, we need
 		 * to rewrite the entry by adding this port to it.
 		 */
-		if (l2_lookup.destports & BIT(port))
+		if ((l2_lookup.destports & BIT(port)) && l2_lookup.lockeds)
 			return 0;
 		l2_lookup.destports |= BIT(port);
 	} else {
@@ -1037,6 +1039,7 @@
 						     index, NULL, false);
 		}
 	}
+	l2_lookup.lockeds = true;
 	l2_lookup.index = sja1105et_fdb_index(bin, way);
 
 	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
@@ -1045,6 +1048,29 @@
 	if (rc < 0)
 		return rc;
 
+	/* Invalidate a dynamically learned entry if that exists */
+	start = sja1105et_fdb_index(bin, 0);
+	end = sja1105et_fdb_index(bin, way);
+
+	for (i = start; i < end; i++) {
+		rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
+						 i, &tmp);
+		if (rc == -ENOENT)
+			continue;
+		if (rc)
+			return rc;
+
+		if (tmp.macaddr != ether_addr_to_u64(addr) || tmp.vlanid != vid)
+			continue;
+
+		rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+						  i, NULL, false);
+		if (rc)
+			return rc;
+
+		break;
+	}
+
 	return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
 }
 
@@ -1086,7 +1112,7 @@
 int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
 			const unsigned char *addr, u16 vid)
 {
-	struct sja1105_l2_lookup_entry l2_lookup = {0};
+	struct sja1105_l2_lookup_entry l2_lookup = {0}, tmp;
 	struct sja1105_private *priv = ds->priv;
 	int rc, i;
 
@@ -1107,10 +1133,10 @@
 	rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
 					 SJA1105_SEARCH, &l2_lookup);
 	if (rc == 0) {
-		/* Found and this port is already in the entry's
+		/* Found a static entry and this port is already in the entry's
 		 * port mask => job done
 		 */
-		if (l2_lookup.destports & BIT(port))
+		if ((l2_lookup.destports & BIT(port)) && l2_lookup.lockeds)
 			return 0;
 		/* l2_lookup.index is populated by the switch in case it
 		 * found something.
@@ -1133,16 +1159,46 @@
 		dev_err(ds->dev, "FDB is full, cannot add entry.\n");
 		return -EINVAL;
 	}
-	l2_lookup.lockeds = true;
 	l2_lookup.index = i;
 
 skip_finding_an_index:
+	l2_lookup.lockeds = true;
+
 	rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
 					  l2_lookup.index, &l2_lookup,
 					  true);
 	if (rc < 0)
 		return rc;
 
+	/* The switch learns dynamic entries and looks up the FDB left to
+	 * right. It is possible that our addition was concurrent with the
+	 * dynamic learning of the same address, so now that the static entry
+	 * has been installed, we are certain that address learning for this
+	 * particular address has been turned off, so the dynamic entry either
+	 * is in the FDB at an index smaller than the static one, or isn't (it
+	 * can also be at a larger index, but in that case it is inactive
+	 * because the static FDB entry will match first, and the dynamic one
+	 * will eventually age out). Search for a dynamically learned address
+	 * prior to our static one and invalidate it.
+	 */
+	tmp = l2_lookup;
+
+	rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
+					 SJA1105_SEARCH, &tmp);
+	if (rc < 0) {
+		dev_err(ds->dev,
+			"port %d failed to read back entry for %pM vid %d: %pe\n",
+			port, addr, vid, ERR_PTR(rc));
+		return rc;
+	}
+
+	if (tmp.index < l2_lookup.index) {
+		rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+						  tmp.index, NULL, false);
+		if (rc < 0)
+			return rc;
+	}
+
 	return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
 }
 
@@ -1256,7 +1312,9 @@
 		/* We need to hide the dsa_8021q VLANs from the user. */
 		if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
 			l2_lookup.vlanid = 0;
-		cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
+		rc = cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
+		if (rc)
+			return rc;
 	}
 	return 0;
 }
@@ -1389,6 +1447,8 @@
 	int speed_mbps[SJA1105_NUM_PORTS];
 	int rc, i;
 
+	mutex_lock(&priv->mgmt_lock);
+
 	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
 
 	/* Back up the dynamic link speed changed by sja1105_adjust_port_config
@@ -1420,6 +1480,8 @@
 			goto out;
 	}
 out:
+	mutex_unlock(&priv->mgmt_lock);
+
 	return rc;
 }
 
@@ -1556,8 +1618,8 @@
 
 	if (enabled) {
 		/* Enable VLAN filtering. */
-		tpid  = ETH_P_8021AD;
-		tpid2 = ETH_P_8021Q;
+		tpid  = ETH_P_8021Q;
+		tpid2 = ETH_P_8021AD;
 	} else {
 		/* Disable VLAN filtering. */
 		tpid  = ETH_P_SJA1105;
@@ -1566,9 +1628,9 @@
 
 	table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
 	general_params = table->entries;
-	/* EtherType used to identify outer tagged (S-tag) VLAN traffic */
-	general_params->tpid = tpid;
 	/* EtherType used to identify inner tagged (C-tag) VLAN traffic */
+	general_params->tpid = tpid;
+	/* EtherType used to identify outer tagged (S-tag) VLAN traffic */
 	general_params->tpid2 = tpid2;
 	/* When VLAN filtering is on, we need to at least be able to
 	 * decode management traffic through the "backup plan".
--- linux-ein-5.4.0.orig/drivers/net/dsa/sja1105/sja1105_static_config.c
+++ linux-ein-5.4.0/drivers/net/dsa/sja1105/sja1105_static_config.c
@@ -142,6 +142,9 @@
 	return size;
 }
 
+/* TPID and TPID2 are intentionally reversed so that semantic
+ * compatibility with E/T is kept.
+ */
 static size_t
 sja1105pqrs_general_params_entry_packing(void *buf, void *entry_ptr,
 					 enum packing_op op)
@@ -166,9 +169,9 @@
 	sja1105_packing(buf, &entry->mirr_port,   141, 139, size, op);
 	sja1105_packing(buf, &entry->vlmarker,    138, 107, size, op);
 	sja1105_packing(buf, &entry->vlmask,      106,  75, size, op);
-	sja1105_packing(buf, &entry->tpid,         74,  59, size, op);
+	sja1105_packing(buf, &entry->tpid2,        74,  59, size, op);
 	sja1105_packing(buf, &entry->ignore2stf,   58,  58, size, op);
-	sja1105_packing(buf, &entry->tpid2,        57,  42, size, op);
+	sja1105_packing(buf, &entry->tpid,         57,  42, size, op);
 	sja1105_packing(buf, &entry->queue_ts,     41,  41, size, op);
 	sja1105_packing(buf, &entry->egrmirrvid,   40,  29, size, op);
 	sja1105_packing(buf, &entry->egrmirrpcp,   28,  26, size, op);
--- linux-ein-5.4.0.orig/drivers/net/dsa/vitesse-vsc73xx-core.c
+++ linux-ein-5.4.0/drivers/net/dsa/vitesse-vsc73xx-core.c
@@ -1108,6 +1108,8 @@
 
 	vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
 				       vsc->chipid);
+	if (!vsc->gc.label)
+		return -ENOMEM;
 	vsc->gc.ngpio = 4;
 	vsc->gc.owner = THIS_MODULE;
 	vsc->gc.parent = vsc->dev;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/3com/3c589_cs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/3com/3c589_cs.c
@@ -196,6 +196,7 @@
 {
 	struct el3_private *lp;
 	struct net_device *dev;
+	int ret;
 
 	dev_dbg(&link->dev, "3c589_attach()\n");
 
@@ -219,7 +220,15 @@
 
 	dev->ethtool_ops = &netdev_ethtool_ops;
 
-	return tc589_config(link);
+	ret = tc589_config(link);
+	if (ret)
+		goto err_free_netdev;
+
+	return 0;
+
+err_free_netdev:
+	free_netdev(dev);
+	return ret;
 }
 
 static void tc589_detach(struct pcmcia_device *link)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/8390/mcf8390.c
+++ linux-ein-5.4.0/drivers/net/ethernet/8390/mcf8390.c
@@ -406,12 +406,12 @@
 static int mcf8390_probe(struct platform_device *pdev)
 {
 	struct net_device *dev;
-	struct resource *mem, *irq;
+	struct resource *mem;
 	resource_size_t msize;
-	int ret;
+	int ret, irq;
 
-	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (irq == NULL) {
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
 		dev_err(&pdev->dev, "no IRQ specified?\n");
 		return -ENXIO;
 	}
@@ -434,7 +434,7 @@
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	platform_set_drvdata(pdev, dev);
 
-	dev->irq = irq->start;
+	dev->irq = irq;
 	dev->base_addr = mem->start;
 
 	ret = mcf8390_init(dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/Kconfig
@@ -100,6 +100,7 @@
 config KORINA
 	tristate "Korina (IDT RC32434) Ethernet support"
 	depends on MIKROTIK_RB532
+	select CRC32
 	---help---
 	  If you have a Mikrotik RouterBoard 500 or IDT RC32434
 	  based system say Y. Otherwise say N.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aeroflex/greth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aeroflex/greth.c
@@ -258,6 +258,7 @@
 			if (dma_mapping_error(greth->dev, dma_addr)) {
 				if (netif_msg_ifup(greth))
 					dev_err(greth->dev, "Could not create initial DMA mapping\n");
+				dev_kfree_skb(skb);
 				goto cleanup;
 			}
 			greth->rx_skbuff[i] = skb;
@@ -1541,10 +1542,11 @@
 	mdiobus_unregister(greth->mdio);
 
 	unregister_netdev(ndev);
-	free_netdev(ndev);
 
 	of_iounmap(&of_dev->resource[0], greth->regs, resource_size(&of_dev->resource[0]));
 
+	free_netdev(ndev);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -432,7 +432,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;
@@ -440,7 +440,7 @@
 
 	channel = db->tx_fifo_stat & 3;
 	if (channel == 3)
-		return 1;
+		return NETDEV_TX_BUSY;
 
 	channel = (channel == 1 ? 1 : 0);
 
@@ -845,13 +845,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);
@@ -910,6 +910,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:
@@ -928,6 +930,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-ein-5.4.0.orig/drivers/net/ethernet/altera/altera_tse_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/altera/altera_tse_main.c
@@ -163,7 +163,8 @@
 	mdio = mdiobus_alloc();
 	if (mdio == NULL) {
 		netdev_err(dev, "Error allocating MDIO bus\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto put_node;
 	}
 
 	mdio->name = ALTERA_TSE_RESOURCE_NAME;
@@ -180,6 +181,7 @@
 			   mdio->id);
 		goto out_free_mdio;
 	}
+	of_node_put(mdio_node);
 
 	if (netif_msg_drv(priv))
 		netdev_info(dev, "MDIO bus %s: created\n", mdio->id);
@@ -189,6 +191,8 @@
 out_free_mdio:
 	mdiobus_free(mdio);
 	mdio = NULL;
+put_node:
+	of_node_put(mdio_node);
 	return ret;
 }
 
@@ -1431,16 +1435,19 @@
 		priv->rxdescmem_busaddr = dma_res->start;
 
 	} else {
+		ret = -ENODEV;
 		goto err_free_netdev;
 	}
 
-	if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
+	if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) {
 		dma_set_coherent_mask(priv->device,
 				      DMA_BIT_MASK(priv->dmaops->dmamask));
-	else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
+	} else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) {
 		dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
-	else
+	} else {
+		ret = -EIO;
 		goto err_free_netdev;
+	}
 
 	/* MAC address space */
 	ret = request_and_map(pdev, "control_port", &control_port,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -1,37 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 #ifndef _ENA_ADMIN_H_
 #define _ENA_ADMIN_H_
 
+#define ENA_ADMIN_RSS_KEY_PARTS              10
 
 enum ena_admin_aq_opcode {
 	ENA_ADMIN_CREATE_SQ                         = 1,
@@ -55,6 +29,7 @@
 	ENA_ADMIN_RESOURCE_BUSY                     = 7,
 };
 
+/* subcommands for the set/get feature admin commands */
 enum ena_admin_aq_feature_id {
 	ENA_ADMIN_DEVICE_ATTRIBUTES                 = 1,
 	ENA_ADMIN_MAX_QUEUES_NUM                    = 2,
@@ -63,7 +38,7 @@
 	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_RSS_INDIRECTION_TABLE_CONFIG      = 12,
 	ENA_ADMIN_MTU                               = 14,
 	ENA_ADMIN_RSS_HASH_INPUT                    = 18,
 	ENA_ADMIN_INTERRUPT_MODERATION              = 20,
@@ -117,6 +92,8 @@
 enum ena_admin_get_stats_type {
 	ENA_ADMIN_GET_STATS_TYPE_BASIC              = 0,
 	ENA_ADMIN_GET_STATS_TYPE_EXTENDED           = 1,
+	/* extra HW stats for specific network interface */
+	ENA_ADMIN_GET_STATS_TYPE_ENI                = 2,
 };
 
 enum ena_admin_get_stats_scope {
@@ -193,7 +170,7 @@
 	u16 extended_status;
 
 	/* indicates to the driver which AQ entry has been consumed by the
-	 *    device and could be reused
+	 * device and could be reused
 	 */
 	u16 sq_head_indx;
 };
@@ -238,8 +215,8 @@
 	 */
 	u8 sq_caps_3;
 
-	/* associated completion queue id. This CQ must be created prior to
-	 *    SQ creation
+	/* associated completion queue id. This CQ must be created prior to SQ
+	 * creation
 	 */
 	u16 cq_idx;
 
@@ -378,7 +355,7 @@
 	u16 queue_idx;
 
 	/* device id, value 0xFFFF means mine. only privileged device can get
-	 *    stats of other device
+	 * stats of other device
 	 */
 	u16 device_id;
 };
@@ -404,12 +381,49 @@
 	u32 rx_drops_low;
 
 	u32 rx_drops_high;
+
+	u32 tx_drops_low;
+
+	u32 tx_drops_high;
+};
+
+/* ENI Statistics Command. */
+struct ena_admin_eni_stats {
+	/* The number of packets shaped due to inbound aggregate BW
+	 * allowance being exceeded
+	 */
+	u64 bw_in_allowance_exceeded;
+
+	/* The number of packets shaped due to outbound aggregate BW
+	 * allowance being exceeded
+	 */
+	u64 bw_out_allowance_exceeded;
+
+	/* The number of packets shaped due to PPS allowance being exceeded */
+	u64 pps_allowance_exceeded;
+
+	/* The number of packets shaped due to connection tracking
+	 * allowance being exceeded and leading to failure in establishment
+	 * of new connections
+	 */
+	u64 conntrack_allowance_exceeded;
+
+	/* The number of packets shaped due to linklocal packet rate
+	 * allowance being exceeded
+	 */
+	u64 linklocal_allowance_exceeded;
 };
 
 struct ena_admin_acq_get_stats_resp {
 	struct ena_admin_acq_common_desc acq_common_desc;
 
-	struct ena_admin_basic_stats basic_stats;
+	union {
+		u64 raw[7];
+
+		struct ena_admin_basic_stats basic_stats;
+
+		struct ena_admin_eni_stats eni_stats;
+	} u;
 };
 
 struct ena_admin_get_set_feature_common_desc {
@@ -436,7 +450,9 @@
 
 	u32 device_version;
 
-	/* bitmap of ena_admin_aq_feature_id */
+	/* bitmap of ena_admin_aq_feature_id, which represents supported
+	 * subcommands for the set/get feature admin commands.
+	 */
 	u32 supported_features;
 
 	u32 reserved3;
@@ -487,37 +503,65 @@
 	ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY          = 2,
 };
 
+enum ena_admin_accel_mode_feat {
+	ENA_ADMIN_DISABLE_META_CACHING              = 0,
+	ENA_ADMIN_LIMIT_TX_BURST                    = 1,
+};
+
+struct ena_admin_accel_mode_get {
+	/* bit field of enum ena_admin_accel_mode_feat */
+	u16 supported_flags;
+
+	/* maximum burst size between two doorbells. The size is in bytes */
+	u16 max_tx_burst_size;
+};
+
+struct ena_admin_accel_mode_set {
+	/* bit field of enum ena_admin_accel_mode_feat */
+	u16 enabled_flags;
+
+	u16 reserved;
+};
+
+struct ena_admin_accel_mode_req {
+	union {
+		u32 raw[2];
+
+		struct ena_admin_accel_mode_get get;
+
+		struct ena_admin_accel_mode_set set;
+	} u;
+};
+
 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.
+	/* 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
+	/* 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
+	/* 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;
 
@@ -525,17 +569,20 @@
 	u16 desc_num_before_header_enabled;
 
 	/* valid only if inline was chosen. bitfield of enum
-	 *    ena_admin_llq_stride_ctrl
+	 * 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.
+	/* reserved */
+	u32 reserved1;
+
+	/* accelerated low latency queues requirement. driver needs to
+	 * support those requirements in order to use accelerated llq
 	 */
-	u32 max_tx_burst_size;
+	struct ena_admin_accel_mode_req accel_mode;
 };
 
 struct ena_admin_queue_ext_feature_fields {
@@ -557,8 +604,8 @@
 
 	u32 max_tx_header_size;
 
-	/* Maximum Descriptors number, including meta descriptor, allowed for
-	 * a single Tx packet
+	/* Maximum Descriptors number, including meta descriptor, allowed for a
+	 * single Tx packet
 	 */
 	u16 max_per_packet_tx_descs;
 
@@ -581,8 +628,8 @@
 
 	u32 max_header_size;
 
-	/* Maximum Descriptors number, including meta descriptor, allowed for
-	 *    a single Tx packet
+	/* Maximum Descriptors number, including meta descriptor, allowed for a
+	 * single Tx packet
 	 */
 	u16 max_packet_tx_descs;
 
@@ -670,11 +717,11 @@
 };
 
 struct ena_admin_feature_rss_flow_hash_control {
-	u32 keys_num;
+	u32 key_parts;
 
 	u32 reserved;
 
-	u32 key[10];
+	u32 key[ENA_ADMIN_RSS_KEY_PARTS];
 };
 
 struct ena_admin_feature_rss_flow_hash_function {
@@ -764,8 +811,8 @@
 	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,
+	ENA_ADMIN_OS_ESXI                           = 6,
+	ENA_ADMIN_OS_GROUPS_NUM                     = 6,
 };
 
 struct ena_admin_host_info {
@@ -809,9 +856,12 @@
 
 	u16 reserved;
 
-	/* 1 :0 : reserved
+	/* 0 : reserved
+	 * 1 : rx_offset
 	 * 2 : interrupt_moderation
-	 * 31:3 : reserved
+	 * 3 : rx_buf_mirroring
+	 * 4 : rss_configurable_function_key
+	 * 31:5 : reserved
 	 */
 	u32 driver_supported_features;
 };
@@ -967,7 +1017,7 @@
 struct ena_admin_aenq_common_desc {
 	u16 group;
 
-	u16 syndrom;
+	u16 syndrome;
 
 	/* 0 : phase
 	 * 7:1 : reserved - MBZ
@@ -991,7 +1041,7 @@
 	ENA_ADMIN_AENQ_GROUPS_NUM                   = 5,
 };
 
-enum ena_admin_aenq_notification_syndrom {
+enum ena_admin_aenq_notification_syndrome {
 	ENA_ADMIN_SUSPEND                           = 0,
 	ENA_ADMIN_RESUME                            = 1,
 	ENA_ADMIN_UPDATE_HINTS                      = 2,
@@ -1017,6 +1067,10 @@
 	u32 rx_drops_low;
 
 	u32 rx_drops_high;
+
+	u32 tx_drops_low;
+
+	u32 tx_drops_high;
 };
 
 struct ena_admin_ena_mmio_req_read_less_resp {
@@ -1116,8 +1170,14 @@
 #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_RX_OFFSET_SHIFT                 1
+#define ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK                  BIT(1)
 #define ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_SHIFT      2
 #define ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK       BIT(2)
+#define ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_SHIFT          3
+#define ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK           BIT(3)
+#define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_SHIFT 4
+#define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK BIT(4)
 
 /* aenq_common_desc */
 #define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK               BIT(0)
@@ -1125,4 +1185,4 @@
 /* aenq_link_change_desc */
 #define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK    BIT(0)
 
-#endif /*_ENA_ADMIN_H_ */
+#endif /* _ENA_ADMIN_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_com.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -1,33 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #include "ena_com.h"
@@ -62,7 +35,9 @@
 
 #define ENA_REGS_ADMIN_INTR_MASK 1
 
-#define ENA_POLL_MS	5
+#define ENA_MIN_ADMIN_POLL_US 100
+
+#define ENA_MAX_ADMIN_POLL_US 5000
 
 /*****************************************************************************/
 /*****************************************************************************/
@@ -96,7 +71,7 @@
 				       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");
+		pr_err("DMA address has more bits that the device supports\n");
 		return -EINVAL;
 	}
 
@@ -106,16 +81,16 @@
 	return 0;
 }
 
-static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue)
+static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue)
 {
-	struct ena_com_admin_sq *sq = &queue->sq;
-	u16 size = ADMIN_SQ_SIZE(queue->q_depth);
+	struct ena_com_admin_sq *sq = &admin_queue->sq;
+	u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth);
 
-	sq->entries = dma_alloc_coherent(queue->q_dmadev, size, &sq->dma_addr,
-					 GFP_KERNEL);
+	sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size,
+					 &sq->dma_addr, GFP_KERNEL);
 
 	if (!sq->entries) {
-		pr_err("memory allocation failed\n");
+		pr_err("Memory allocation failed\n");
 		return -ENOMEM;
 	}
 
@@ -128,16 +103,16 @@
 	return 0;
 }
 
-static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue)
+static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue)
 {
-	struct ena_com_admin_cq *cq = &queue->cq;
-	u16 size = ADMIN_CQ_SIZE(queue->q_depth);
+	struct ena_com_admin_cq *cq = &admin_queue->cq;
+	u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth);
 
-	cq->entries = dma_alloc_coherent(queue->q_dmadev, size, &cq->dma_addr,
-					 GFP_KERNEL);
+	cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size,
+					 &cq->dma_addr, GFP_KERNEL);
 
 	if (!cq->entries) {
-		pr_err("memory allocation failed\n");
+		pr_err("Memory allocation failed\n");
 		return -ENOMEM;
 	}
 
@@ -147,20 +122,20 @@
 	return 0;
 }
 
-static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
+static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev,
 				   struct ena_aenq_handlers *aenq_handlers)
 {
-	struct ena_com_aenq *aenq = &dev->aenq;
+	struct ena_com_aenq *aenq = &ena_dev->aenq;
 	u32 addr_low, addr_high, aenq_caps;
 	u16 size;
 
-	dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
+	ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH;
 	size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH);
-	aenq->entries = dma_alloc_coherent(dev->dmadev, size, &aenq->dma_addr,
-					   GFP_KERNEL);
+	aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size,
+					   &aenq->dma_addr, GFP_KERNEL);
 
 	if (!aenq->entries) {
-		pr_err("memory allocation failed\n");
+		pr_err("Memory allocation failed\n");
 		return -ENOMEM;
 	}
 
@@ -170,18 +145,18 @@
 	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);
+	writel(addr_low, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF);
+	writel(addr_high, ena_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 |= ena_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);
+	writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF);
 
 	if (unlikely(!aenq_handlers)) {
-		pr_err("aenq handlers pointer is NULL\n");
+		pr_err("AENQ handlers pointer is NULL\n");
 		return -EINVAL;
 	}
 
@@ -197,26 +172,31 @@
 	atomic_dec(&queue->outstanding_cmds);
 }
 
-static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue,
+static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_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);
+	if (unlikely(command_id >= admin_queue->q_depth)) {
+		pr_err("Command id is larger than the queue size. cmd_id: %u queue size %d\n",
+		       command_id, admin_queue->q_depth);
+		return NULL;
+	}
+
+	if (unlikely(!admin_queue->comp_ctx)) {
+		pr_err("Completion context is NULL\n");
 		return NULL;
 	}
 
-	if (unlikely(queue->comp_ctx[command_id].occupied && capture)) {
+	if (unlikely(admin_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;
+		atomic_inc(&admin_queue->outstanding_cmds);
+		admin_queue->comp_ctx[command_id].occupied = true;
 	}
 
-	return &queue->comp_ctx[command_id];
+	return &admin_queue->comp_ctx[command_id];
 }
 
 static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue,
@@ -237,7 +217,7 @@
 	/* 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");
+		pr_debug("Admin queue is full.\n");
 		admin_queue->stats.out_of_space++;
 		return ERR_PTR(-ENOSPC);
 	}
@@ -277,20 +257,21 @@
 	return comp_ctx;
 }
 
-static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
+static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue)
 {
-	size_t size = queue->q_depth * sizeof(struct ena_comp_ctx);
+	size_t size = admin_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");
+	admin_queue->comp_ctx =
+		devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL);
+	if (unlikely(!admin_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);
+	for (i = 0; i < admin_queue->q_depth; i++) {
+		comp_ctx = get_comp_ctxt(admin_queue, i, false);
 		if (comp_ctx)
 			init_completion(&comp_ctx->wait_event);
 	}
@@ -356,7 +337,7 @@
 		}
 
 		if (!io_sq->desc_addr.virt_addr) {
-			pr_err("memory allocation failed\n");
+			pr_err("Memory allocation failed\n");
 			return -ENOMEM;
 		}
 	}
@@ -370,7 +351,7 @@
 		io_sq->bounce_buf_ctrl.next_to_use = 0;
 
 		size = io_sq->bounce_buf_ctrl.buffer_size *
-			 io_sq->bounce_buf_ctrl.buffers_num;
+			io_sq->bounce_buf_ctrl.buffers_num;
 
 		dev_node = dev_to_node(ena_dev->dmadev);
 		set_dev_node(ena_dev->dmadev, ctx->numa_node);
@@ -382,7 +363,7 @@
 				devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
 
 		if (!io_sq->bounce_buf_ctrl.base_buffer) {
-			pr_err("bounce buffer memory allocation failed\n");
+			pr_err("Bounce buffer memory allocation failed\n");
 			return -ENOMEM;
 		}
 
@@ -396,6 +377,8 @@
 		       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;
+		io_sq->disable_meta_caching =
+			io_sq->llq_info.disable_meta_caching;
 
 		if (io_sq->llq_info.max_entries_in_tx_burst > 0)
 			io_sq->entries_in_tx_burst_left =
@@ -440,7 +423,7 @@
 	}
 
 	if (!io_cq->cdesc_addr.virt_addr) {
-		pr_err("memory allocation failed\n");
+		pr_err("Memory allocation failed\n");
 		return -ENOMEM;
 	}
 
@@ -516,10 +499,7 @@
 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;
+		pr_err("Admin command failed[%u]\n", comp_status);
 
 	switch (comp_status) {
 	case ENA_ADMIN_SUCCESS:
@@ -533,9 +513,18 @@
 	case ENA_ADMIN_ILLEGAL_PARAMETER:
 	case ENA_ADMIN_UNKNOWN_ERROR:
 		return -EINVAL;
+	case ENA_ADMIN_RESOURCE_BUSY:
+		return -EAGAIN;
 	}
 
-	return 0;
+	return -EINVAL;
+}
+
+static void ena_delay_exponential_backoff_us(u32 exp, u32 delay_us)
+{
+	delay_us = max_t(u32, ENA_MIN_ADMIN_POLL_US, delay_us);
+	delay_us = min_t(u32, delay_us * (1U << exp), ENA_MAX_ADMIN_POLL_US);
+	usleep_range(delay_us, 2 * delay_us);
 }
 
 static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
@@ -544,6 +533,7 @@
 	unsigned long flags = 0;
 	unsigned long timeout;
 	int ret;
+	u32 exp = 0;
 
 	timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout);
 
@@ -567,7 +557,8 @@
 			goto err;
 		}
 
-		msleep(ENA_POLL_MS);
+		ena_delay_exponential_backoff_us(exp++,
+						 admin_queue->ena_dev->ena_min_poll_delay_us);
 	}
 
 	if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) {
@@ -588,7 +579,7 @@
 	return ret;
 }
 
-/**
+/*
  * Set the LLQ configurations of the firmware
  *
  * The driver provides only the enabled feature values to the device,
@@ -613,6 +604,10 @@
 	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;
 
+	cmd.u.llq.accel_mode.u.set.enabled_flags =
+		BIT(ENA_ADMIN_DISABLE_META_CACHING) |
+		BIT(ENA_ADMIN_LIMIT_TX_BURST);
+
 	ret = ena_com_execute_admin_command(admin_queue,
 					    (struct ena_admin_aq_entry *)&cmd,
 					    sizeof(cmd),
@@ -630,6 +625,7 @@
 				   struct ena_llq_configurations *llq_default_cfg)
 {
 	struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+	struct ena_admin_accel_mode_get llq_accel_mode_get;
 	u16 supported_feat;
 	int rc;
 
@@ -697,8 +693,7 @@
 		/* 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);
+		pr_err("Illegal entry size %d\n", llq_info->desc_list_entry_size);
 		return -EINVAL;
 	}
 
@@ -730,9 +725,17 @@
 		       llq_default_cfg->llq_num_decs_before_header,
 		       supported_feat, llq_info->descs_num_before_header);
 	}
+	/* Check for accelerated queue supported */
+	llq_accel_mode_get = llq_features->accel_mode.u.get;
 
-	llq_info->max_entries_in_tx_burst =
-		(u16)(llq_features->max_tx_burst_size /	llq_default_cfg->llq_ring_entry_size_value);
+	llq_info->disable_meta_caching =
+		!!(llq_accel_mode_get.supported_flags &
+		   BIT(ENA_ADMIN_DISABLE_META_CACHING));
+
+	if (llq_accel_mode_get.supported_flags & BIT(ENA_ADMIN_LIMIT_TX_BURST))
+		llq_info->max_entries_in_tx_burst =
+			llq_accel_mode_get.max_tx_burst_size /
+			llq_default_cfg->llq_ring_entry_size_value;
 
 	rc = ena_com_set_llq(ena_dev);
 	if (rc)
@@ -770,7 +773,7 @@
 			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",
+			pr_err("The ena device didn'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.
@@ -831,7 +834,7 @@
 	}
 
 	if (unlikely(i == timeout)) {
-		pr_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n",
+		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;
@@ -898,7 +901,7 @@
 					    sizeof(destroy_resp));
 
 	if (unlikely(ret && (ret != -ENODEV)))
-		pr_err("failed to destroy io sq error: %d\n", ret);
+		pr_err("Failed to destroy io sq error: %d\n", ret);
 
 	return ret;
 }
@@ -938,12 +941,13 @@
 static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout,
 				u16 exp_state)
 {
-	u32 val, i;
+	u32 val, exp = 0;
+	unsigned long timeout_stamp;
 
-	/* Convert timeout from resolution of 100ms to ENA_POLL_MS */
-	timeout = (timeout * 100) / ENA_POLL_MS;
+	/* Convert timeout from resolution of 100ms to us resolution. */
+	timeout_stamp = jiffies + usecs_to_jiffies(100 * 1000 * timeout);
 
-	for (i = 0; i < timeout; i++) {
+	while (1) {
 		val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF);
 
 		if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) {
@@ -955,10 +959,11 @@
 			exp_state)
 			return 0;
 
-		msleep(ENA_POLL_MS);
-	}
+		if (time_is_before_jiffies(timeout_stamp))
+			return -ETIME;
 
-	return -ETIME;
+		ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us);
+	}
 }
 
 static bool ena_com_check_supported_feature_id(struct ena_com_dev *ena_dev,
@@ -1005,7 +1010,7 @@
 				   &get_cmd.control_buffer.address,
 				   control_buf_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -1041,10 +1046,31 @@
 				      feature_ver);
 }
 
+static void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev)
+{
+	struct ena_admin_feature_rss_flow_hash_control *hash_key =
+		(ena_dev->rss).hash_key;
+
+	netdev_rss_key_fill(&hash_key->key, sizeof(hash_key->key));
+	/* The key buffer is stored in the device in an array of
+	 * uint32 elements.
+	 */
+	hash_key->key_parts = ENA_ADMIN_RSS_KEY_PARTS;
+}
+
+int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev)
+{
+	return ena_dev->rss.hash_func;
+}
+
 static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
 {
 	struct ena_rss *rss = &ena_dev->rss;
 
+	if (!ena_com_check_supported_feature_id(ena_dev,
+						ENA_ADMIN_RSS_HASH_FUNCTION))
+		return -EOPNOTSUPP;
+
 	rss->hash_key =
 		dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
 				   &rss->hash_key_dma_addr, GFP_KERNEL);
@@ -1098,13 +1124,13 @@
 	int ret;
 
 	ret = ena_com_get_feature(ena_dev, &get_resp,
-				  ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG, 0);
+				  ENA_ADMIN_RSS_INDIRECTION_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",
+		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;
@@ -1197,7 +1223,7 @@
 					   &create_cmd.sq_ba,
 					   io_sq->desc_addr.phys_addr);
 		if (unlikely(ret)) {
-			pr_err("memory address set failed\n");
+			pr_err("Memory address set failed\n");
 			return ret;
 		}
 	}
@@ -1226,7 +1252,7 @@
 			cmd_completion.llq_descriptors_offset);
 	}
 
-	pr_debug("created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
+	pr_debug("Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth);
 
 	return ret;
 }
@@ -1254,40 +1280,12 @@
 	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;
+	u16 prev_intr_delay_resolution = ena_dev->intr_delay_resolution;
 
-	if (!intr_delay_resolution) {
+	if (unlikely(!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;
 	}
@@ -1367,7 +1365,7 @@
 				   &create_cmd.cq_ba,
 				   io_cq->cdesc_addr.phys_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -1396,7 +1394,7 @@
 			(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);
+	pr_debug("Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth);
 
 	return ret;
 }
@@ -1441,11 +1439,13 @@
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
 	unsigned long flags = 0;
+	u32 exp = 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);
+		ena_delay_exponential_backoff_us(exp++,
+						 ena_dev->ena_min_poll_delay_us);
 		spin_lock_irqsave(&admin_queue->q_lock, flags);
 	}
 	spin_unlock_irqrestore(&admin_queue->q_lock, flags);
@@ -1587,12 +1587,12 @@
 		return -ETIME;
 	}
 
-	pr_info("ena device version: %d.%d\n",
+	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",
+	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) >>
@@ -1615,6 +1615,19 @@
 	return 0;
 }
 
+static void
+ena_com_free_ena_admin_queue_comp_ctx(struct ena_com_dev *ena_dev,
+				      struct ena_com_admin_queue *admin_queue)
+
+{
+	if (!admin_queue->comp_ctx)
+		return;
+
+	devm_kfree(ena_dev->dmadev, admin_queue->comp_ctx);
+
+	admin_queue->comp_ctx = NULL;
+}
+
 void ena_com_admin_destroy(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
@@ -1623,9 +1636,8 @@
 	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;
+	ena_com_free_ena_admin_queue_comp_ctx(ena_dev, admin_queue);
+
 	size = ADMIN_SQ_SIZE(admin_queue->q_depth);
 	if (sq->entries)
 		dma_free_coherent(ena_dev->dmadev, size, sq->entries,
@@ -1793,6 +1805,7 @@
 	if (ret)
 		goto error;
 
+	admin_queue->ena_dev = ena_dev;
 	admin_queue->running_state = true;
 
 	return 0;
@@ -1902,6 +1915,7 @@
 
 	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)) {
@@ -1980,10 +1994,10 @@
 /* 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,
+static ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *ena_dev,
 						     u16 group)
 {
-	struct ena_aenq_handlers *aenq_handlers = dev->aenq.aenq_handlers;
+	struct ena_aenq_handlers *aenq_handlers = ena_dev->aenq.aenq_handlers;
 
 	if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group])
 		return aenq_handlers->handlers[group];
@@ -1995,12 +2009,12 @@
  * 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)
+void ena_com_aenq_intr_handler(struct ena_com_dev *ena_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;
+	struct ena_com_aenq *aenq  = &ena_dev->aenq;
+	u64 timestamp;
 	ena_aenq_handler handler_cb;
 	u16 masked_head, processed = 0;
 	u8 phase;
@@ -2018,14 +2032,14 @@
 		 */
 		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);
+		timestamp = (u64)aenq_common->timestamp_low |
+			((u64)aenq_common->timestamp_high << 32);
+
+		pr_debug("AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n",
+			 aenq_common->group, aenq_common->syndrome, timestamp);
 
 		/* Handle specific event*/
-		handler_cb = ena_com_get_specific_aenq_cb(dev,
+		handler_cb = ena_com_get_specific_aenq_cb(ena_dev,
 							  aenq_common->group);
 		handler_cb(data, aenq_e); /* call the actual event handler*/
 
@@ -2051,7 +2065,7 @@
 	/* 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);
+		       ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF);
 }
 
 int ena_com_dev_reset(struct ena_com_dev *ena_dev,
@@ -2143,6 +2157,21 @@
 	return ret;
 }
 
+int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
+			  struct ena_admin_eni_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_ENI);
+	if (likely(ret == 0))
+		memcpy(stats, &ctx.get_resp.u.eni_stats,
+		       sizeof(ctx.get_resp.u.eni_stats));
+
+	return ret;
+}
+
 int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
 				struct ena_admin_basic_stats *stats)
 {
@@ -2152,8 +2181,8 @@
 	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));
+		memcpy(stats, &ctx.get_resp.u.basic_stats,
+		       sizeof(ctx.get_resp.u.basic_stats));
 
 	return ret;
 }
@@ -2249,7 +2278,7 @@
 				   &cmd.control_buffer.address,
 				   rss->hash_key_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -2273,12 +2302,14 @@
 			       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_feature_rss_flow_hash_control *hash_key;
 	struct ena_admin_get_feat_resp get_resp;
-	struct ena_admin_feature_rss_flow_hash_control *hash_key =
-		rss->hash_key;
+	enum ena_admin_hash_functions old_func;
+	struct ena_rss *rss = &ena_dev->rss;
 	int rc;
 
+	hash_key = rss->hash_key;
+
 	/* Make sure size is a mult of DWs */
 	if (unlikely(key_len & 0x3))
 		return -EINVAL;
@@ -2290,22 +2321,23 @@
 	if (unlikely(rc))
 		return rc;
 
-	if (!((1 << func) & get_resp.u.flow_hash_func.supported_func)) {
+	if (!(BIT(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;
+		if (key) {
+			if (key_len != sizeof(hash_key->key)) {
+				pr_err("key len (%hu) doesn't equal the supported size (%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->key_parts = key_len / sizeof(hash_key->key[0]);
 		}
-
-		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;
@@ -2315,26 +2347,27 @@
 		return -EINVAL;
 	}
 
+	old_func = rss->hash_func;
 	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);
+		rss->hash_func = old_func;
 
 	return rc;
 }
 
 int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
-			      enum ena_admin_hash_functions *func,
-			      u8 *key)
+			      enum ena_admin_hash_functions *func)
 {
 	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;
 
+	if (unlikely(!func))
+		return -EINVAL;
+
 	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
 				    ENA_ADMIN_RSS_HASH_FUNCTION,
 				    rss->hash_key_dma_addr,
@@ -2342,12 +2375,24 @@
 	if (unlikely(rc))
 		return rc;
 
-	rss->hash_func = get_resp.u.flow_hash_func.selected_func;
-	if (func)
-		*func = rss->hash_func;
+	/* ffs() returns 1 in case the lsb is set */
+	rss->hash_func = ffs(get_resp.u.flow_hash_func.selected_func);
+	if (rss->hash_func)
+		rss->hash_func--;
+
+	*func = rss->hash_func;
+
+	return 0;
+}
+
+int ena_com_get_hash_key(struct ena_com_dev *ena_dev, u8 *key)
+{
+	struct ena_admin_feature_rss_flow_hash_control *hash_key =
+		ena_dev->rss.hash_key;
 
 	if (key)
-		memcpy(key, hash_key->key, (size_t)(hash_key->keys_num) << 2);
+		memcpy(key, hash_key->key,
+		       (size_t)(hash_key->key_parts) * sizeof(hash_key->key[0]));
 
 	return 0;
 }
@@ -2403,7 +2448,7 @@
 				   &cmd.control_buffer.address,
 				   rss->hash_ctrl_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 	cmd.control_buffer.length = sizeof(*hash_ctrl);
@@ -2464,7 +2509,7 @@
 		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",
+			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;
@@ -2502,7 +2547,7 @@
 	/* 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",
+		pr_err("Proto %d doesn't support the required fields %x. supports only: %x\n",
 		       proto, hash_fields, supported_fields);
 	}
 
@@ -2542,9 +2587,9 @@
 	int ret;
 
 	if (!ena_com_check_supported_feature_id(
-		    ena_dev, ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG)) {
+		    ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) {
 		pr_debug("Feature %d isn't supported\n",
-			 ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG);
+			 ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG);
 		return -EOPNOTSUPP;
 	}
 
@@ -2559,7 +2604,7 @@
 	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.feat_common.feature_id = ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG;
 	cmd.u.ind_table.size = rss->tbl_log_size;
 	cmd.u.ind_table.inline_index = 0xFFFFFFFF;
 
@@ -2567,7 +2612,7 @@
 				   &cmd.control_buffer.address,
 				   rss->rss_ind_tbl_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -2597,7 +2642,7 @@
 		sizeof(struct ena_admin_rss_ind_table_entry);
 
 	rc = ena_com_get_feature_ex(ena_dev, &get_resp,
-				    ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG,
+				    ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG,
 				    rss->rss_ind_tbl_dma_addr,
 				    tbl_size, 0);
 	if (unlikely(rc))
@@ -2606,10 +2651,6 @@
 	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];
 
@@ -2626,8 +2667,14 @@
 	if (unlikely(rc))
 		goto err_indr_tbl;
 
+	/* The following function might return unsupported in case the
+	 * device doesn't support setting the key / hash function. We can safely
+	 * ignore this error and have indirection table support only.
+	 */
 	rc = ena_com_hash_key_allocate(ena_dev);
-	if (unlikely(rc))
+	if (likely(!rc))
+		ena_com_hash_key_fill_default_key(ena_dev);
+	else if (rc != -EOPNOTSUPP)
 		goto err_hash_key;
 
 	rc = ena_com_hash_ctrl_init(ena_dev);
@@ -2678,8 +2725,7 @@
 
 	host_attr->debug_area_virt_addr =
 		dma_alloc_coherent(ena_dev->dmadev, debug_area_size,
-				   &host_attr->debug_area_dma_addr,
-				   GFP_KERNEL);
+				   &host_attr->debug_area_dma_addr, GFP_KERNEL);
 	if (unlikely(!host_attr->debug_area_virt_addr)) {
 		host_attr->debug_area_size = 0;
 		return -ENOMEM;
@@ -2736,7 +2782,7 @@
 				   &cmd.u.host_attr.debug_ba,
 				   host_attr->debug_area_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -2744,7 +2790,7 @@
 				   &cmd.u.host_attr.os_info_ba,
 				   host_attr->host_info_dma_addr);
 	if (unlikely(ret)) {
-		pr_err("memory address set failed\n");
+		pr_err("Memory address set failed\n");
 		return ret;
 	}
 
@@ -2863,7 +2909,7 @@
 		(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");
+		pr_err("The size of the LLQ entry is smaller than needed\n");
 		return -EINVAL;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_com.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #ifndef ENA_COM
@@ -44,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/wait.h>
+#include <linux/netdevice.h>
 
 #include "ena_common_defs.h"
 #include "ena_admin_defs.h"
@@ -53,9 +27,9 @@
 #undef pr_fmt
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define ENA_MAX_NUM_IO_QUEUES		128U
+#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_TOTAL_NUM_QUEUES (2 * (ENA_MAX_NUM_IO_QUEUES))
 
 #define ENA_MAX_HANDLERS 256
 
@@ -72,13 +46,15 @@
 /*****************************************************************************/
 /* ENA adaptive interrupt moderation settings */
 
-#define ENA_INTR_INITIAL_TX_INTERVAL_USECS		196
-#define ENA_INTR_INITIAL_RX_INTERVAL_USECS		0
-#define ENA_DEFAULT_INTR_DELAY_RESOLUTION		1
+#define ENA_INTR_INITIAL_TX_INTERVAL_USECS 64
+#define ENA_INTR_INITIAL_RX_INTERVAL_USECS 0
+#define ENA_DEFAULT_INTR_DELAY_RESOLUTION 1
+
+#define ENA_HASH_KEY_SIZE 40
 
-#define ENA_HW_HINTS_NO_TIMEOUT				0xFFFF
+#define ENA_HW_HINTS_NO_TIMEOUT	0xFFFF
 
-#define ENA_FEATURE_MAX_QUEUE_EXT_VER	1
+#define ENA_FEATURE_MAX_QUEUE_EXT_VER 1
 
 struct ena_llq_configurations {
 	enum ena_admin_llq_header_location llq_header_location;
@@ -124,6 +100,7 @@
 	u16 descs_num_before_header;
 	u16 descs_per_entry;
 	u16 max_entries_in_tx_burst;
+	bool disable_meta_caching;
 };
 
 struct ena_com_io_cq {
@@ -186,6 +163,8 @@
 	enum queue_direction direction;
 	enum ena_admin_placement_policy_type mem_queue_type;
 
+	bool disable_meta_caching;
+
 	u32 msix_vector;
 	struct ena_com_tx_meta cached_tx_meta;
 	struct ena_com_llq_info llq_info;
@@ -227,15 +206,16 @@
 };
 
 struct ena_com_stats_admin {
-	u32 aborted_cmd;
-	u32 submitted_cmd;
-	u32 completed_cmd;
-	u32 out_of_space;
-	u32 no_completion;
+	u64 aborted_cmd;
+	u64 submitted_cmd;
+	u64 completed_cmd;
+	u64 out_of_space;
+	u64 no_completion;
 };
 
 struct ena_com_admin_queue {
 	void *q_dmadev;
+	struct ena_com_dev *ena_dev;
 	spinlock_t q_lock; /* spinlock for the admin queue */
 
 	struct ena_comp_ctx *comp_ctx;
@@ -348,6 +328,8 @@
 	struct ena_intr_moder_entry *intr_moder_tbl;
 
 	struct ena_com_llq_info llq_info;
+
+	u32 ena_min_poll_delay_us;
 };
 
 struct ena_com_dev_get_features_ctx {
@@ -392,7 +374,7 @@
  */
 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_com_set_mmio_read_mode - Enable/disable the indirect mmio reg read mechanism
  * @ena_dev: ENA communication layer struct
  * @readless_supported: readless mode (enable/disable)
  */
@@ -500,18 +482,6 @@
  */
 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
@@ -526,7 +496,7 @@
 /* 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
+ * This method goes over the admin completion queue and wakes up all the pending
  * threads that wait on the commands wait event.
  *
  * @note: Should be called after MSI-X interrupt.
@@ -536,10 +506,10 @@
 /* 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
+ * This method goes over the async event notification queue and calls the proper
  * aenq handler.
  */
-void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data);
+void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data);
 
 /* ena_com_abort_admin_commands - Abort all the outstanding admin commands.
  * @ena_dev: ENA communication layer struct
@@ -553,14 +523,14 @@
 /* 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.
+ * This method waits until all the outstanding admin commands are 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
+ * This method verifies 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.
@@ -619,6 +589,15 @@
 int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
 				struct ena_admin_basic_stats *stats);
 
+/* ena_com_get_eni_stats - Get extended network interface statistics
+ * @ena_dev: ENA communication layer struct
+ * @stats: stats return value
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
+			  struct ena_admin_eni_stats *stats);
+
 /* ena_com_set_dev_mtu - Configure the device mtu.
  * @ena_dev: ENA communication layer struct
  * @mtu: mtu value
@@ -655,6 +634,14 @@
  */
 void ena_com_rss_destroy(struct ena_com_dev *ena_dev);
 
+/* ena_com_get_current_hash_function - Get RSS hash function
+ * @ena_dev: ENA communication layer struct
+ *
+ * Return the current hash function.
+ * @return: 0 or one of the ena_admin_hash_functions values.
+ */
+int ena_com_get_current_hash_function(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)
@@ -686,23 +673,32 @@
  */
 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_com_get_hash_function - Retrieve the hash function 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.
+ * Retrieve the hash function from the device.
  *
- * @note: If the caller called ena_com_fill_hash_function but didn't flash
+ * @note: If the caller called ena_com_fill_hash_function but didn't flush
  * 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);
+			      enum ena_admin_hash_functions *func);
 
+/* ena_com_get_hash_key - Retrieve the hash key
+ * @ena_dev: ENA communication layer struct
+ * @key: hash key
+ *
+ * Retrieve the hash key.
+ *
+ * @note: If the caller called ena_com_fill_hash_key but didn't flush
+ * it to the device, the new configuration will be lost.
+ *
+ * @return: 0 on Success and negative value otherwise.
+ */
+int ena_com_get_hash_key(struct ena_com_dev *ena_dev, u8 *key);
 /* ena_com_fill_hash_ctrl - Fill RSS hash control
  * @ena_dev: ENA communication layer struct.
  * @proto: The protocol to configure.
@@ -737,7 +733,7 @@
  *
  * Retrieve the hash control from the device.
  *
- * @note, If the caller called ena_com_fill_hash_ctrl but didn't flash
+ * @note: If the caller called ena_com_fill_hash_ctrl but didn't flush
  * it to the device, the new configuration will be lost.
  *
  * @return: 0 on Success and negative value otherwise.
@@ -789,7 +785,7 @@
  *
  * Retrieve the RSS indirection table from the device.
  *
- * @note: If the caller called ena_com_indirect_table_fill_entry but didn't flash
+ * @note: If the caller called ena_com_indirect_table_fill_entry but didn't flush
  * it to the device, the new configuration will be lost.
  *
  * @return: 0 on Success and negative value otherwise.
@@ -815,14 +811,14 @@
 /* ena_com_delete_debug_area - Free the debug area resources.
  * @ena_dev: ENA communication layer struct
  *
- * Free the allocate debug area.
+ * Free the allocated 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.
+ * Free the allocated host info.
  */
 void ena_com_delete_host_info(struct ena_com_dev *ena_dev);
 
@@ -863,9 +859,9 @@
  * @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
+ * Submit an admin command and then wait until the device returns a
  * completion.
- * The completion will be copyed into cmd_comp.
+ * The completion will be copied into cmd_comp.
  *
  * @return - 0 on success, negative value on failure.
  */
@@ -928,7 +924,7 @@
 /* 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_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,
@@ -954,7 +950,7 @@
  * @intr_reg: interrupt register to update.
  * @rx_delay_interval: Rx interval in usecs
  * @tx_delay_interval: Tx interval in usecs
- * @unmask: unask enable/disable
+ * @unmask: unmask enable/disable
  *
  * Prepare interrupt update register with the supplied parameters.
  */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_common_defs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_common_defs.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 #ifndef _ENA_COMMON_H_
 #define _ENA_COMMON_H_
@@ -45,4 +18,4 @@
 	u16 reserved16;
 };
 
-#endif /*_ENA_COMMON_H_ */
+#endif /* _ENA_COMMON_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_com.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_eth_com.c
@@ -1,33 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #include "ena_eth_com.h"
@@ -45,8 +18,9 @@
 	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;
+	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;
@@ -89,7 +63,7 @@
 		}
 
 		io_sq->entries_in_tx_burst_left--;
-		pr_debug("decreasing entries_in_tx_burst_left of queue %d to %d\n",
+		pr_debug("Decreasing entries_in_tx_burst_left of queue %d to %d\n",
 			 io_sq->qid, io_sq->entries_in_tx_burst_left);
 	}
 
@@ -128,12 +102,12 @@
 
 	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");
+		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");
+		pr_err("Bounce buffer is NULL\n");
 		return -EFAULT;
 	}
 
@@ -151,7 +125,7 @@
 	bounce_buffer = pkt_ctrl->curr_bounce_buf;
 
 	if (unlikely(!bounce_buffer)) {
-		pr_err("bounce buffer is NULL\n");
+		pr_err("Bounce buffer is NULL\n");
 		return NULL;
 	}
 
@@ -262,8 +236,9 @@
 
 		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;
+		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) {
@@ -275,7 +250,7 @@
 		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",
+		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;
@@ -285,13 +260,15 @@
 	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)
+static int ena_com_create_meta(struct ena_com_io_sq *io_sq,
+			       struct ena_com_tx_meta *ena_meta)
 {
 	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);
+	if (unlikely(!meta_desc))
+		return -EFAULT;
+
 	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;
@@ -299,7 +276,7 @@
 	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 <<
+	meta_desc->word2 |= ((u32)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 */
@@ -309,33 +286,57 @@
 
 	/* 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 <<
+	meta_desc->len_ctrl |= ((u32)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->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_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 <<
+	meta_desc->word2 |= ((u32)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;
+	return ena_com_sq_update_tail(io_sq);
+}
 
-	/* Cached the meta desc */
-	memcpy(&io_sq->cached_tx_meta, ena_meta,
-	       sizeof(struct ena_com_tx_meta));
+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,
+						 bool *have_meta)
+{
+	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
 
-	return ena_com_sq_update_tail(io_sq);
+	/* When disable meta caching is set, don't bother to save the meta and
+	 * compare it to the stored version, just create the meta
+	 */
+	if (io_sq->disable_meta_caching) {
+		if (unlikely(!ena_tx_ctx->meta_valid))
+			return -EINVAL;
+
+		*have_meta = true;
+		return ena_com_create_meta(io_sq, ena_meta);
+	}
+
+	if (ena_com_meta_desc_changed(io_sq, ena_tx_ctx)) {
+		*have_meta = true;
+		/* Cache the meta desc */
+		memcpy(&io_sq->cached_tx_meta, ena_meta,
+		       sizeof(struct ena_com_tx_meta));
+		return ena_com_create_meta(io_sq, ena_meta);
+	}
+
+	*have_meta = false;
+	return 0;
 }
 
 static void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
-					struct ena_eth_io_rx_cdesc_base *cdesc)
+				 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;
@@ -356,7 +357,7 @@
 		(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",
+	pr_debug("l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %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);
@@ -389,7 +390,7 @@
 	}
 
 	if (unlikely(header_len > io_sq->tx_max_header_size)) {
-		pr_err("header size is too large %d max header: %d\n",
+		pr_err("Header size is too large %d max header: %d\n",
 		       header_len, io_sq->tx_max_header_size);
 		return -EINVAL;
 	}
@@ -402,12 +403,10 @@
 	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;
+	rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx, &have_meta);
+	if (unlikely(rc)) {
+		pr_err("Failed to create and store tx meta desc\n");
+		return rc;
 	}
 
 	/* If the caller doesn't want to send packets */
@@ -426,16 +425,16 @@
 	if (!have_meta)
 		desc->len_ctrl |= ENA_ETH_IO_TX_DESC_FIRST_MASK;
 
-	desc->buff_addr_hi_hdr_sz |= (header_len <<
+	desc->buff_addr_hi_hdr_sz |= ((u32)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) &
+	desc->len_ctrl |= ((u32)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 <<
+	desc->meta_ctrl |= ((u32)ena_tx_ctx->req_id <<
 		ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT) &
 		ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK;
 
@@ -481,7 +480,7 @@
 
 			memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
 
-			desc->len_ctrl |= (io_sq->phase <<
+			desc->len_ctrl |= ((u32)io_sq->phase <<
 				ENA_ETH_IO_TX_DESC_PHASE_SHIFT) &
 				ENA_ETH_IO_TX_DESC_PHASE_MASK;
 		}
@@ -517,9 +516,10 @@
 {
 	struct ena_com_rx_buf_info *ena_buf = &ena_rx_ctx->ena_bufs[0];
 	struct ena_eth_io_rx_cdesc_base *cdesc = NULL;
+	u16 q_depth = io_cq->q_depth;
 	u16 cdesc_idx = 0;
 	u16 nb_hw_desc;
-	u16 i;
+	u16 i = 0;
 
 	WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
 
@@ -529,7 +529,7 @@
 		return 0;
 	}
 
-	pr_debug("fetch rx packet: queue %d completed desc: %d\n", io_cq->qid,
+	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)) {
@@ -538,13 +538,21 @@
 		return -ENOSPC;
 	}
 
-	for (i = 0; i < nb_hw_desc; i++) {
+	cdesc = ena_com_rx_cdesc_idx_to_ptr(io_cq, cdesc_idx);
+	ena_rx_ctx->pkt_offset = cdesc->offset;
+
+	do {
+		ena_buf[i].len = cdesc->length;
+		ena_buf[i].req_id = cdesc->req_id;
+		if (unlikely(ena_buf[i].req_id >= q_depth))
+			return -EIO;
+
+		if (++i >= nb_hw_desc)
+			break;
+
 		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++;
-	}
+	} while (1);
 
 	/* Update SQ head ptr */
 	io_sq->next_to_comp += nb_hw_desc;
@@ -578,10 +586,10 @@
 
 	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->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK |
+		     ENA_ETH_IO_RX_DESC_LAST_MASK |
+		     (io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK) |
+		     ENA_ETH_IO_RX_DESC_COMP_REQ_MASK;
 
 	desc->req_id = req_id;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_com.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_eth_com.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #ifndef ENA_ETH_COM_H_
@@ -73,6 +46,7 @@
 	u32 hash;
 	u16 descs;
 	int max_bufs;
+	u8 pkt_offset;
 };
 
 int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
@@ -95,7 +69,7 @@
 	writel(intr_reg->intr_control, io_cq->unmask_reg);
 }
 
-static inline int ena_com_free_desc(struct ena_com_io_sq *io_sq)
+static inline int ena_com_free_q_entries(struct ena_com_io_sq *io_sq)
 {
 	u16 tail, next_to_comp, cnt;
 
@@ -113,7 +87,7 @@
 	int temp;
 
 	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
-		return ena_com_free_desc(io_sq) >= required_buffers;
+		return ena_com_free_q_entries(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
@@ -122,7 +96,7 @@
 	 */
 	temp = required_buffers / io_sq->llq_info.descs_per_entry + 2;
 
-	return ena_com_free_desc(io_sq) > temp;
+	return ena_com_free_q_entries(io_sq) > temp;
 }
 
 static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
@@ -156,7 +130,8 @@
 	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)))
+	if (llq_info->disable_meta_caching ||
+	    unlikely(ena_com_meta_desc_changed(io_sq, ena_tx_ctx)))
 		++num_descs;
 
 	if (num_descs > llq_info->descs_num_before_header) {
@@ -165,7 +140,7 @@
 						   llq_info->descs_per_entry);
 	}
 
-	pr_debug("queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid,
+	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;
@@ -176,13 +151,13 @@
 	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",
+	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",
+		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;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 #ifndef _ENA_ETH_IO_H_
 #define _ENA_ETH_IO_H_
@@ -264,7 +237,9 @@
 
 	u16 sub_qid;
 
-	u16 reserved;
+	u8 offset;
+
+	u8 reserved;
 };
 
 /* 8-word format */
@@ -412,4 +387,4 @@
 #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_ */
+#endif /* _ENA_ETH_IO_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -1,33 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #include <linux/pci.h>
@@ -41,12 +14,17 @@
 
 #define ENA_STAT_ENA_COM_ENTRY(stat) { \
 	.name = #stat, \
-	.stat_offset = offsetof(struct ena_com_stats_admin, stat) \
+	.stat_offset = offsetof(struct ena_com_stats_admin, stat) / sizeof(u64) \
 }
 
 #define ENA_STAT_ENTRY(stat, stat_type) { \
 	.name = #stat, \
-	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) \
+	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) / sizeof(u64) \
+}
+
+#define ENA_STAT_HW_ENTRY(stat, stat_type) { \
+	.name = #stat, \
+	.stat_offset = offsetof(struct ena_admin_##stat_type, stat) / sizeof(u64) \
 }
 
 #define ENA_STAT_RX_ENTRY(stat) \
@@ -58,6 +36,9 @@
 #define ENA_STAT_GLOBAL_ENTRY(stat) \
 	ENA_STAT_ENTRY(stat, dev)
 
+#define ENA_STAT_ENI_ENTRY(stat) \
+	ENA_STAT_HW_ENTRY(stat, eni_stats)
+
 static const struct ena_stats ena_stats_global_strings[] = {
 	ENA_STAT_GLOBAL_ENTRY(tx_timeout),
 	ENA_STAT_GLOBAL_ENTRY(suspend),
@@ -68,6 +49,14 @@
 	ENA_STAT_GLOBAL_ENTRY(admin_q_pause),
 };
 
+static const struct ena_stats ena_stats_eni_strings[] = {
+	ENA_STAT_ENI_ENTRY(bw_in_allowance_exceeded),
+	ENA_STAT_ENI_ENTRY(bw_out_allowance_exceeded),
+	ENA_STAT_ENI_ENTRY(pps_allowance_exceeded),
+	ENA_STAT_ENI_ENTRY(conntrack_allowance_exceeded),
+	ENA_STAT_ENI_ENTRY(linklocal_allowance_exceeded),
+};
+
 static const struct ena_stats ena_stats_tx_strings[] = {
 	ENA_STAT_TX_ENTRY(cnt),
 	ENA_STAT_TX_ENTRY(bytes),
@@ -83,6 +72,7 @@
 	ENA_STAT_TX_ENTRY(bad_req_id),
 	ENA_STAT_TX_ENTRY(llq_buffer_copy),
 	ENA_STAT_TX_ENTRY(missed_tx),
+	ENA_STAT_TX_ENTRY(unmask_interrupt),
 };
 
 static const struct ena_stats ena_stats_rx_strings[] = {
@@ -99,6 +89,11 @@
 	ENA_STAT_RX_ENTRY(bad_req_id),
 	ENA_STAT_RX_ENTRY(empty_rx_ring),
 	ENA_STAT_RX_ENTRY(csum_unchecked),
+	ENA_STAT_RX_ENTRY(xdp_aborted),
+	ENA_STAT_RX_ENTRY(xdp_drop),
+	ENA_STAT_RX_ENTRY(xdp_pass),
+	ENA_STAT_RX_ENTRY(xdp_tx),
+	ENA_STAT_RX_ENTRY(xdp_invalid),
 };
 
 static const struct ena_stats ena_stats_ena_com_strings[] = {
@@ -109,10 +104,12 @@
 	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)
+#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)
+#define ENA_STATS_ARRAY_ENI(adapter)	\
+	(ARRAY_SIZE(ena_stats_eni_strings) * (adapter)->eni_stats_supported)
 
 static void ena_safe_update_stat(u64 *src, u64 *dst,
 				 struct u64_stats_sync *syncp)
@@ -133,29 +130,30 @@
 	u64 *ptr;
 	int i, j;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues + adapter->xdp_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);
+			ptr = (u64 *)&ring->tx_stats + ena_stats->stat_offset;
 
 			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
 		}
+		/* XDP TX queues don't have a RX queue counterpart */
+		if (!ENA_IS_XDP_INDEX(adapter, i)) {
+			/* Rx stats */
+			ring = &adapter->rx_ring[i];
 
-		/* Rx stats */
-		ring = &adapter->rx_ring[i];
-
-		for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
-			ena_stats = &ena_stats_rx_strings[j];
+			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);
+				ptr = (u64 *)&ring->rx_stats +
+					ena_stats->stat_offset;
 
-			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
+				ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
+			}
 		}
 	}
 }
@@ -163,24 +161,23 @@
 static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
 {
 	const struct ena_stats *ena_stats;
-	u32 *ptr;
+	u64 *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);
+		ptr = (u64 *)&adapter->ena_dev->admin_queue.stats +
+			ena_stats->stat_offset;
 
 		*(*data)++ = *ptr;
 	}
 }
 
-static void ena_get_ethtool_stats(struct net_device *netdev,
-				  struct ethtool_stats *stats,
-				  u64 *data)
+static void ena_get_stats(struct ena_adapter *adapter,
+			  u64 *data,
+			  bool eni_stats_needed)
 {
-	struct ena_adapter *adapter = netdev_priv(netdev);
 	const struct ena_stats *ena_stats;
 	u64 *ptr;
 	int i;
@@ -188,16 +185,48 @@
 	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);
+		ptr = (u64 *)&adapter->dev_stats + ena_stats->stat_offset;
 
 		ena_safe_update_stat(ptr, data++, &adapter->syncp);
 	}
 
+	if (eni_stats_needed) {
+		ena_update_hw_stats(adapter);
+		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
+			ena_stats = &ena_stats_eni_strings[i];
+
+			ptr = (u64 *)&adapter->eni_stats +
+				ena_stats->stat_offset;
+
+			ena_safe_update_stat(ptr, data++, &adapter->syncp);
+		}
+	}
+
 	ena_queue_stats(adapter, &data);
 	ena_dev_admin_queue_stats(adapter, &data);
 }
 
+static void ena_get_ethtool_stats(struct net_device *netdev,
+				  struct ethtool_stats *stats,
+				  u64 *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	ena_get_stats(adapter, data, adapter->eni_stats_supported);
+}
+
+static int ena_get_sw_stats_count(struct ena_adapter *adapter)
+{
+	return adapter->num_io_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
+		+ adapter->xdp_num_queues * ENA_STATS_ARRAY_TX
+		+ ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
+}
+
+static int ena_get_hw_stats_count(struct ena_adapter *adapter)
+{
+	return ENA_STATS_ARRAY_ENI(adapter);
+}
+
 int ena_get_sset_count(struct net_device *netdev, int sset)
 {
 	struct ena_adapter *adapter = netdev_priv(netdev);
@@ -205,31 +234,38 @@
 	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;
+	return ena_get_sw_stats_count(adapter) + ena_get_hw_stats_count(adapter);
 }
 
 static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
 {
 	const struct ena_stats *ena_stats;
+	bool is_xdp;
 	int i, j;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
+		is_xdp = ENA_IS_XDP_INDEX(adapter, 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;
+				 "queue_%u_%s_%s", i,
+				 is_xdp ? "xdp_tx" : "tx", 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;
+		if (!is_xdp) {
+			/* RX stats, in XDP there isn't a RX queue
+			 * counterpart
+			 */
+			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;
+			}
 		}
 	}
 }
@@ -248,26 +284,43 @@
 	}
 }
 
-static void ena_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+static void ena_get_strings(struct ena_adapter *adapter,
+			    u8 *data,
+			    bool eni_stats_needed)
 {
-	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;
 	}
 
+	if (eni_stats_needed) {
+		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
+			ena_stats = &ena_stats_eni_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 void ena_get_ethtool_strings(struct net_device *netdev,
+				    u32 sset,
+				    u8 *data)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	if (sset != ETH_SS_STATS)
+		return;
+
+	ena_get_strings(adapter, data, adapter->eni_stats_supported);
+}
+
 static int ena_get_link_ksettings(struct net_device *netdev,
 				  struct ethtool_link_ksettings *link_ksettings)
 {
@@ -306,19 +359,16 @@
 	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)) {
-		/* the devie doesn't support interrupt moderation */
+	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;
 
-	if (!ena_com_get_adaptive_moderation_enabled(ena_dev))
-		coalesce->rx_coalesce_usecs =
-			ena_com_get_nonadaptive_moderation_interval_rx(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);
@@ -326,25 +376,25 @@
 	return 0;
 }
 
-static void ena_update_tx_rings_intr_moderation(struct ena_adapter *adapter)
+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++)
+	for (i = 0; i < adapter->num_io_queues; i++)
 		adapter->tx_ring[i].smoothed_interval = val;
 }
 
-static void ena_update_rx_rings_intr_moderation(struct ena_adapter *adapter)
+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++)
+	for (i = 0; i < adapter->num_io_queues; i++)
 		adapter->rx_ring[i].smoothed_interval = val;
 }
 
@@ -355,35 +405,30 @@
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc;
 
-	if (!ena_com_interrupt_moderation_supported(ena_dev)) {
-		/* the devie doesn't support interrupt moderation */
+	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_intr_moderation(adapter);
-
-	if (coalesce->use_adaptive_rx_coalesce) {
-		if (!ena_com_get_adaptive_moderation_enabled(ena_dev))
-			ena_com_enable_adaptive_moderation(ena_dev);
-		return 0;
-	}
+	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_intr_moderation(adapter);
+	ena_update_rx_rings_nonadaptive_intr_moderation(adapter);
 
-	if (!coalesce->use_adaptive_rx_coalesce) {
-		if (ena_com_get_adaptive_moderation_enabled(ena_dev))
-			ena_com_disable_adaptive_moderation(ena_dev);
-	}
+	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;
 }
@@ -408,7 +453,6 @@
 	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));
 }
@@ -612,7 +656,7 @@
 
 	switch (info->cmd) {
 	case ETHTOOL_GRXRINGS:
-		info->data = adapter->num_queues;
+		info->data = adapter->num_io_queues;
 		rc = 0;
 		break;
 	case ETHTOOL_GRXFH:
@@ -640,6 +684,54 @@
 	return ENA_HASH_KEY_SIZE;
 }
 
+static int ena_indirection_table_set(struct ena_adapter *adapter,
+				     const u32 *indir)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int i, rc;
+
+	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, adapter->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, adapter->netdev,
+			  "Cannot set indirect table\n");
+		return rc == -EPERM ? -EOPNOTSUPP : rc;
+	}
+	return rc;
+}
+
+static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int i, rc;
+
+	if (!indir)
+		return 0;
+
+	rc = ena_com_indirect_table_get(ena_dev, indir);
+	if (rc)
+		return rc;
+
+	/* Our internal representation of the indices is: even indices
+	 * for Tx and uneven indices for Rx. We need to convert the Rx
+	 * indices to be consecutive
+	 */
+	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++)
+		indir[i] = ENA_IO_RXQ_IDX_TO_COMBINED_IDX(indir[i]);
+
+	return rc;
+}
+
 static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
 			u8 *hfunc)
 {
@@ -648,11 +740,22 @@
 	u8 func;
 	int rc;
 
-	rc = ena_com_indirect_table_get(adapter->ena_dev, indir);
+	rc = ena_indirection_table_get(adapter, indir);
 	if (rc)
 		return rc;
 
-	rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key);
+	/* We call this function in order to check if the device
+	 * supports getting/setting the hash function.
+	 */
+	rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func);
+	if (rc) {
+		if (rc == -EOPNOTSUPP)
+			rc = 0;
+
+		return rc;
+	}
+
+	rc = ena_com_get_hash_key(adapter->ena_dev, key);
 	if (rc)
 		return rc;
 
@@ -661,7 +764,7 @@
 		func = ETH_RSS_HASH_TOP;
 		break;
 	case ENA_ADMIN_CRC32:
-		func = ETH_RSS_HASH_XOR;
+		func = ETH_RSS_HASH_CRC32;
 		break;
 	default:
 		netif_err(adapter, drv, netdev,
@@ -672,7 +775,7 @@
 	if (hfunc)
 		*hfunc = func;
 
-	return rc;
+	return 0;
 }
 
 static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
@@ -680,34 +783,23 @@
 {
 	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;
+	enum ena_admin_hash_functions func = 0;
+	int rc;
 
 	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;
-		}
+		rc = ena_indirection_table_set(adapter, indir);
+		if (rc)
+			return rc;
 	}
 
 	switch (hfunc) {
+	case ETH_RSS_HASH_NO_CHANGE:
+		func = ena_com_get_current_hash_function(ena_dev);
+		break;
 	case ETH_RSS_HASH_TOP:
 		func = ENA_ADMIN_TOEPLITZ;
 		break;
-	case ETH_RSS_HASH_XOR:
+	case ETH_RSS_HASH_CRC32:
 		func = ENA_ADMIN_CRC32;
 		break;
 	default:
@@ -716,7 +808,7 @@
 		return -EOPNOTSUPP;
 	}
 
-	if (key) {
+	if (key || func) {
 		rc = ena_com_fill_hash_function(ena_dev, func, key,
 						ENA_HASH_KEY_SIZE,
 						0xFFFFFFFF);
@@ -734,14 +826,22 @@
 {
 	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;
+	channels->max_combined = adapter->max_num_io_queues;
+	channels->combined_count = adapter->num_io_queues;
+}
+
+static int ena_set_channels(struct net_device *netdev,
+			    struct ethtool_channels *channels)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	u32 count = channels->combined_count;
+	/* The check for max value is already done in ethtool */
+	if (count < ENA_MIN_NUM_IO_QUEUES ||
+	    (ena_xdp_present(adapter) &&
+	    !ena_xdp_legal_queue_count(adapter, channels->combined_count)))
+		return -EINVAL;
+
+	return ena_update_queue_count(adapter, count);
 }
 
 static int ena_get_tunable(struct net_device *netdev,
@@ -798,7 +898,7 @@
 	.get_ringparam		= ena_get_ringparam,
 	.set_ringparam		= ena_set_ringparam,
 	.get_sset_count         = ena_get_sset_count,
-	.get_strings		= ena_get_strings,
+	.get_strings		= ena_get_ethtool_strings,
 	.get_ethtool_stats      = ena_get_ethtool_stats,
 	.get_rxnfc		= ena_get_rxnfc,
 	.set_rxnfc		= ena_set_rxnfc,
@@ -807,8 +907,10 @@
 	.get_rxfh		= ena_get_rxfh,
 	.set_rxfh		= ena_set_rxfh,
 	.get_channels		= ena_get_channels,
+	.set_channels		= ena_set_channels,
 	.get_tunable		= ena_get_tunable,
 	.set_tunable		= ena_set_tunable,
+	.get_ts_info            = ethtool_op_get_ts_info,
 };
 
 void ena_set_ethtool_ops(struct net_device *netdev)
@@ -824,7 +926,7 @@
 	int strings_num;
 	int i, rc;
 
-	strings_num = ena_get_sset_count(netdev, ETH_SS_STATS);
+	strings_num = ena_get_sw_stats_count(adapter);
 	if (strings_num <= 0) {
 		netif_err(adapter, drv, netdev, "Can't get stats num\n");
 		return;
@@ -835,7 +937,7 @@
 				   GFP_ATOMIC);
 	if (!strings_buf) {
 		netif_err(adapter, drv, netdev,
-			  "failed to alloc strings_buf\n");
+			  "Failed to allocate strings_buf\n");
 		return;
 	}
 
@@ -844,13 +946,13 @@
 				GFP_ATOMIC);
 	if (!data_buf) {
 		netif_err(adapter, drv, netdev,
-			  "failed to allocate data buf\n");
+			  "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);
+	ena_get_strings(adapter, strings_buf, false);
+	ena_get_stats(adapter, data_buf, false);
 
 	/* If there is a buffer, dump stats, otherwise print them to dmesg */
 	if (buf)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -1,33 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -36,7 +9,6 @@
 #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/numa.h>
@@ -47,14 +19,12 @@
 #include <net/ip.h>
 
 #include "ena_netdev.h"
+#include <linux/bpf_trace.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)
@@ -78,6 +48,36 @@
 static void ena_destroy_device(struct ena_adapter *adapter, bool graceful);
 static int ena_restore_device(struct ena_adapter *adapter);
 
+static void ena_init_io_rings(struct ena_adapter *adapter,
+			      int first_index, int count);
+static void ena_init_napi_in_range(struct ena_adapter *adapter, int first_index,
+				   int count);
+static void ena_del_napi_in_range(struct ena_adapter *adapter, int first_index,
+				  int count);
+static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid);
+static int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
+					   int first_index,
+					   int count);
+static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid);
+static void ena_free_tx_resources(struct ena_adapter *adapter, int qid);
+static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget);
+static void ena_destroy_all_tx_queues(struct ena_adapter *adapter);
+static void ena_free_all_io_tx_resources(struct ena_adapter *adapter);
+static void ena_napi_disable_in_range(struct ena_adapter *adapter,
+				      int first_index, int count);
+static void ena_napi_enable_in_range(struct ena_adapter *adapter,
+				     int first_index, int count);
+static int ena_up(struct ena_adapter *adapter);
+static void ena_down(struct ena_adapter *adapter);
+static void ena_unmask_interrupt(struct ena_ring *tx_ring,
+				 struct ena_ring *rx_ring);
+static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
+				      struct ena_ring *rx_ring);
+static void ena_unmap_tx_buff(struct ena_ring *tx_ring,
+			      struct ena_tx_buffer *tx_info);
+static int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
+					    int first_index, int count);
+
 static void ena_tx_timeout(struct net_device *dev)
 {
 	struct ena_adapter *adapter = netdev_priv(dev);
@@ -101,7 +101,7 @@
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = 0; i < adapter->num_io_queues; i++)
 		adapter->rx_ring[i].mtu = mtu;
 }
 
@@ -112,7 +112,7 @@
 
 	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);
+		netif_dbg(adapter, drv, dev, "Set MTU to %d\n", new_mtu);
 		update_rx_ring_mtu(adapter, new_mtu);
 		dev->mtu = new_mtu;
 	} else {
@@ -123,16 +123,472 @@
 	return ret;
 }
 
+static int ena_xmit_common(struct net_device *dev,
+			   struct ena_ring *ring,
+			   struct ena_tx_buffer *tx_info,
+			   struct ena_com_tx_ctx *ena_tx_ctx,
+			   u16 next_to_use,
+			   u32 bytes)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+	int rc, nb_hw_desc;
+
+	if (unlikely(ena_com_is_doorbell_needed(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",
+			  ring->qid);
+		ena_com_write_sq_doorbell(ring->ena_com_io_sq);
+	}
+
+	/* prepare the packet's descriptors to dma engine */
+	rc = ena_com_prepare_tx(ring->ena_com_io_sq, ena_tx_ctx,
+				&nb_hw_desc);
+
+	/* In case there isn't enough space in the queue for the packet,
+	 * we simply drop it. 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(&ring->syncp);
+		ring->tx_stats.prepare_ctx_err++;
+		u64_stats_update_end(&ring->syncp);
+		if (rc != -ENOMEM) {
+			adapter->reset_reason =
+				ENA_REGS_RESET_DRIVER_INVALID_STATE;
+			set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
+		}
+		return rc;
+	}
+
+	u64_stats_update_begin(&ring->syncp);
+	ring->tx_stats.cnt++;
+	ring->tx_stats.bytes += bytes;
+	u64_stats_update_end(&ring->syncp);
+
+	tx_info->tx_descs = nb_hw_desc;
+	tx_info->last_jiffies = jiffies;
+	tx_info->print_once = 0;
+
+	ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
+						 ring->ring_size);
+	return 0;
+}
+
+/* This is the XDP napi callback. XDP queues use a separate napi callback
+ * than Rx/Tx queues.
+ */
+static int ena_xdp_io_poll(struct napi_struct *napi, int budget)
+{
+	struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
+	u32 xdp_work_done, xdp_budget;
+	struct ena_ring *xdp_ring;
+	int napi_comp_call = 0;
+	int ret;
+
+	xdp_ring = ena_napi->xdp_ring;
+	xdp_ring->first_interrupt = ena_napi->first_interrupt;
+
+	xdp_budget = budget;
+
+	if (!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags) ||
+	    test_bit(ENA_FLAG_TRIGGER_RESET, &xdp_ring->adapter->flags)) {
+		napi_complete_done(napi, 0);
+		return 0;
+	}
+
+	xdp_work_done = ena_clean_xdp_irq(xdp_ring, xdp_budget);
+
+	/* If the device is about to reset or down, avoid unmask
+	 * the interrupt and return 0 so NAPI won't reschedule
+	 */
+	if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags))) {
+		napi_complete_done(napi, 0);
+		ret = 0;
+	} else if (xdp_budget > xdp_work_done) {
+		napi_comp_call = 1;
+		if (napi_complete_done(napi, xdp_work_done))
+			ena_unmask_interrupt(xdp_ring, NULL);
+		ena_update_ring_numa_node(xdp_ring, NULL);
+		ret = xdp_work_done;
+	} else {
+		ret = xdp_budget;
+	}
+
+	u64_stats_update_begin(&xdp_ring->syncp);
+	xdp_ring->tx_stats.napi_comp += napi_comp_call;
+	xdp_ring->tx_stats.tx_poll++;
+	u64_stats_update_end(&xdp_ring->syncp);
+
+	return ret;
+}
+
+static int ena_xdp_tx_map_buff(struct ena_ring *xdp_ring,
+			       struct ena_tx_buffer *tx_info,
+			       struct xdp_buff *xdp,
+			       void **push_hdr,
+			       u32 *push_len)
+{
+	struct ena_adapter *adapter = xdp_ring->adapter;
+	struct ena_com_buf *ena_buf;
+	dma_addr_t dma = 0;
+	u32 size;
+
+	tx_info->xdpf = convert_to_xdp_frame(xdp);
+	size = tx_info->xdpf->len;
+	ena_buf = tx_info->bufs;
+
+	/* llq push buffer */
+	*push_len = min_t(u32, size, xdp_ring->tx_max_header_size);
+	*push_hdr = tx_info->xdpf->data;
+
+	if (size - *push_len > 0) {
+		dma = dma_map_single(xdp_ring->dev,
+				     *push_hdr + *push_len,
+				     size - *push_len,
+				     DMA_TO_DEVICE);
+		if (unlikely(dma_mapping_error(xdp_ring->dev, dma)))
+			goto error_report_dma_error;
+
+		tx_info->map_linear_data = 1;
+		tx_info->num_of_bufs = 1;
+	}
+
+	ena_buf->paddr = dma;
+	ena_buf->len = size;
+
+	return 0;
+
+error_report_dma_error:
+	u64_stats_update_begin(&xdp_ring->syncp);
+	xdp_ring->tx_stats.dma_mapping_err++;
+	u64_stats_update_end(&xdp_ring->syncp);
+	netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map xdp buff\n");
+
+	xdp_return_frame_rx_napi(tx_info->xdpf);
+	tx_info->xdpf = NULL;
+	tx_info->num_of_bufs = 0;
+
+	return -EINVAL;
+}
+
+static int ena_xdp_xmit_buff(struct net_device *dev,
+			     struct xdp_buff *xdp,
+			     int qid,
+			     struct ena_rx_buffer *rx_info)
+{
+	struct ena_adapter *adapter = netdev_priv(dev);
+	struct ena_com_tx_ctx ena_tx_ctx = {};
+	struct ena_tx_buffer *tx_info;
+	struct ena_ring *xdp_ring;
+	u16 next_to_use, req_id;
+	int rc;
+	void *push_hdr;
+	u32 push_len;
+
+	xdp_ring = &adapter->tx_ring[qid];
+	next_to_use = xdp_ring->next_to_use;
+	req_id = xdp_ring->free_ids[next_to_use];
+	tx_info = &xdp_ring->tx_buffer_info[req_id];
+	tx_info->num_of_bufs = 0;
+	page_ref_inc(rx_info->page);
+	tx_info->xdp_rx_page = rx_info->page;
+
+	rc = ena_xdp_tx_map_buff(xdp_ring, tx_info, xdp, &push_hdr, &push_len);
+	if (unlikely(rc))
+		goto error_drop_packet;
+
+	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 = push_len;
+
+	rc = ena_xmit_common(dev,
+			     xdp_ring,
+			     tx_info,
+			     &ena_tx_ctx,
+			     next_to_use,
+			     xdp->data_end - xdp->data);
+	if (rc)
+		goto error_unmap_dma;
+	/* trigger the dma engine. ena_com_write_sq_doorbell()
+	 * has a mb
+	 */
+	ena_com_write_sq_doorbell(xdp_ring->ena_com_io_sq);
+	u64_stats_update_begin(&xdp_ring->syncp);
+	xdp_ring->tx_stats.doorbells++;
+	u64_stats_update_end(&xdp_ring->syncp);
+
+	return NETDEV_TX_OK;
+
+error_unmap_dma:
+	ena_unmap_tx_buff(xdp_ring, tx_info);
+	tx_info->xdpf = NULL;
+error_drop_packet:
+	__free_page(tx_info->xdp_rx_page);
+	return NETDEV_TX_OK;
+}
+
+static int ena_xdp_execute(struct ena_ring *rx_ring,
+			   struct xdp_buff *xdp,
+			   struct ena_rx_buffer *rx_info)
+{
+	struct bpf_prog *xdp_prog;
+	u32 verdict = XDP_PASS;
+	u64 *xdp_stat;
+
+	rcu_read_lock();
+	xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
+
+	if (!xdp_prog)
+		goto out;
+
+	verdict = bpf_prog_run_xdp(xdp_prog, xdp);
+
+	if (verdict == XDP_TX) {
+		ena_xdp_xmit_buff(rx_ring->netdev,
+				  xdp,
+				  rx_ring->qid + rx_ring->adapter->num_io_queues,
+				  rx_info);
+
+		xdp_stat = &rx_ring->rx_stats.xdp_tx;
+	} else if (unlikely(verdict == XDP_ABORTED)) {
+		trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
+		xdp_stat = &rx_ring->rx_stats.xdp_aborted;
+	} else if (unlikely(verdict == XDP_DROP)) {
+		xdp_stat = &rx_ring->rx_stats.xdp_drop;
+	} else if (unlikely(verdict == XDP_PASS)) {
+		xdp_stat = &rx_ring->rx_stats.xdp_pass;
+	} else {
+		bpf_warn_invalid_xdp_action(verdict);
+		xdp_stat = &rx_ring->rx_stats.xdp_invalid;
+	}
+
+	u64_stats_update_begin(&rx_ring->syncp);
+	(*xdp_stat)++;
+	u64_stats_update_end(&rx_ring->syncp);
+out:
+	rcu_read_unlock();
+
+	return verdict;
+}
+
+static void ena_init_all_xdp_queues(struct ena_adapter *adapter)
+{
+	adapter->xdp_first_ring = adapter->num_io_queues;
+	adapter->xdp_num_queues = adapter->num_io_queues;
+
+	ena_init_io_rings(adapter,
+			  adapter->xdp_first_ring,
+			  adapter->xdp_num_queues);
+}
+
+static int ena_setup_and_create_all_xdp_queues(struct ena_adapter *adapter)
+{
+	int rc = 0;
+
+	rc = ena_setup_tx_resources_in_range(adapter, adapter->xdp_first_ring,
+					     adapter->xdp_num_queues);
+	if (rc)
+		goto setup_err;
+
+	rc = ena_create_io_tx_queues_in_range(adapter,
+					      adapter->xdp_first_ring,
+					      adapter->xdp_num_queues);
+	if (rc)
+		goto create_err;
+
+	return 0;
+
+create_err:
+	ena_free_all_io_tx_resources(adapter);
+setup_err:
+	return rc;
+}
+
+/* Provides a way for both kernel and bpf-prog to know
+ * more about the RX-queue a given XDP frame arrived on.
+ */
+static int ena_xdp_register_rxq_info(struct ena_ring *rx_ring)
+{
+	int rc;
+
+	rc = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, rx_ring->qid);
+
+	if (rc) {
+		netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
+			  "Failed to register xdp rx queue info. RX queue num %d rc: %d\n",
+			  rx_ring->qid, rc);
+		goto err;
+	}
+
+	rc = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq, MEM_TYPE_PAGE_SHARED,
+					NULL);
+
+	if (rc) {
+		netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
+			  "Failed to register xdp rx queue info memory model. RX queue num %d rc: %d\n",
+			  rx_ring->qid, rc);
+		xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+	}
+
+err:
+	return rc;
+}
+
+static void ena_xdp_unregister_rxq_info(struct ena_ring *rx_ring)
+{
+	xdp_rxq_info_unreg_mem_model(&rx_ring->xdp_rxq);
+	xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+}
+
+static void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
+						 struct bpf_prog *prog,
+						 int first, int count)
+{
+	struct ena_ring *rx_ring;
+	int i = 0;
+
+	for (i = first; i < count; i++) {
+		rx_ring = &adapter->rx_ring[i];
+		xchg(&rx_ring->xdp_bpf_prog, prog);
+		if (prog) {
+			ena_xdp_register_rxq_info(rx_ring);
+			rx_ring->rx_headroom = XDP_PACKET_HEADROOM;
+		} else {
+			ena_xdp_unregister_rxq_info(rx_ring);
+			rx_ring->rx_headroom = 0;
+		}
+	}
+}
+
+static void ena_xdp_exchange_program(struct ena_adapter *adapter,
+				     struct bpf_prog *prog)
+{
+	struct bpf_prog *old_bpf_prog = xchg(&adapter->xdp_bpf_prog, prog);
+
+	ena_xdp_exchange_program_rx_in_range(adapter,
+					     prog,
+					     0,
+					     adapter->num_io_queues);
+
+	if (old_bpf_prog)
+		bpf_prog_put(old_bpf_prog);
+}
+
+static int ena_destroy_and_free_all_xdp_queues(struct ena_adapter *adapter)
+{
+	bool was_up;
+	int rc;
+
+	was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+
+	if (was_up)
+		ena_down(adapter);
+
+	adapter->xdp_first_ring = 0;
+	adapter->xdp_num_queues = 0;
+	ena_xdp_exchange_program(adapter, NULL);
+	if (was_up) {
+		rc = ena_up(adapter);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
+static int ena_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+	struct bpf_prog *prog = bpf->prog;
+	struct bpf_prog *old_bpf_prog;
+	int rc, prev_mtu;
+	bool is_up;
+
+	is_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+	rc = ena_xdp_allowed(adapter);
+	if (rc == ENA_XDP_ALLOWED) {
+		old_bpf_prog = adapter->xdp_bpf_prog;
+		if (prog) {
+			if (!is_up) {
+				ena_init_all_xdp_queues(adapter);
+			} else if (!old_bpf_prog) {
+				ena_down(adapter);
+				ena_init_all_xdp_queues(adapter);
+			}
+			ena_xdp_exchange_program(adapter, prog);
+
+			if (is_up && !old_bpf_prog) {
+				rc = ena_up(adapter);
+				if (rc)
+					return rc;
+			}
+		} else if (old_bpf_prog) {
+			rc = ena_destroy_and_free_all_xdp_queues(adapter);
+			if (rc)
+				return rc;
+		}
+
+		prev_mtu = netdev->max_mtu;
+		netdev->max_mtu = prog ? ENA_XDP_MAX_MTU : adapter->max_mtu;
+
+		if (!old_bpf_prog)
+			netif_info(adapter, drv, adapter->netdev,
+				   "XDP program is set, changing the max_mtu from %d to %d",
+				   prev_mtu, netdev->max_mtu);
+
+	} else if (rc == ENA_XDP_CURRENT_MTU_TOO_LARGE) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Failed to set xdp program, the current MTU (%d) is larger than the maximum allowed MTU (%lu) while xdp is on",
+			  netdev->mtu, ENA_XDP_MAX_MTU);
+		NL_SET_ERR_MSG_MOD(bpf->extack,
+				   "Failed to set xdp program, the current MTU is larger than the maximum allowed MTU. Check the dmesg for more info");
+		return -EINVAL;
+	} else if (rc == ENA_XDP_NO_ENOUGH_QUEUES) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Failed to set xdp program, the Rx/Tx channel count should be at most half of the maximum allowed channel count. The current queue count (%d), the maximal queue count (%d)\n",
+			  adapter->num_io_queues, adapter->max_num_io_queues);
+		NL_SET_ERR_MSG_MOD(bpf->extack,
+				   "Failed to set xdp program, there is no enough space for allocating XDP queues, Check the dmesg for more info");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* This is the main xdp callback, it's used by the kernel to set/unset the xdp
+ * program as well as to query the current xdp program id.
+ */
+static int ena_xdp(struct net_device *netdev, struct netdev_bpf *bpf)
+{
+	struct ena_adapter *adapter = netdev_priv(netdev);
+
+	switch (bpf->command) {
+	case XDP_SETUP_PROG:
+		return ena_xdp_set(netdev, bpf);
+	case XDP_QUERY_PROG:
+		bpf->prog_id = adapter->xdp_bpf_prog ?
+			adapter->xdp_bpf_prog->aux->id : 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 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);
+	adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_io_queues);
 	if (!adapter->netdev->rx_cpu_rmap)
 		return -ENOMEM;
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		int irq_idx = ENA_IO_IRQ_IDX(i);
 
 		rc = irq_cpu_rmap_add(adapter->netdev->rx_cpu_rmap,
@@ -164,7 +620,8 @@
 	u64_stats_init(&ring->syncp);
 }
 
-static void ena_init_io_rings(struct ena_adapter *adapter)
+static void ena_init_io_rings(struct ena_adapter *adapter,
+			      int first_index, int count)
 {
 	struct ena_com_dev *ena_dev;
 	struct ena_ring *txr, *rxr;
@@ -172,13 +629,12 @@
 
 	ena_dev = adapter->ena_dev;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = first_index; i < first_index + count; i++) {
 		txr = &adapter->tx_ring[i];
 		rxr = &adapter->rx_ring[i];
 
-		/* TX/RX common ring state */
+		/* TX 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;
@@ -187,15 +643,22 @@
 		txr->sgl_size = adapter->max_tx_sgl_size;
 		txr->smoothed_interval =
 			ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
+		txr->disable_meta_caching = adapter->disable_meta_caching;
 
-		/* 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;
+		/* Don't init RX queues for xdp queues */
+		if (!ENA_IS_XDP_INDEX(adapter, i)) {
+			/* RX common ring state */
+			ena_init_io_rings_common(adapter, rxr, i);
+
+			/* 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;
+		}
 	}
 }
 
@@ -285,16 +748,13 @@
 	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)
+static int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
+					   int first_index,
+					   int count)
 {
 	int i, rc = 0;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = first_index; i < first_index + count; i++) {
 		rc = ena_setup_tx_resources(adapter, i);
 		if (rc)
 			goto err_setup_tx;
@@ -308,40 +768,31 @@
 		  "Tx queue %d: allocation failed\n", i);
 
 	/* rewind the index freeing the rings as we go */
-	while (i--)
+	while (first_index < 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)
+static void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
+						  int first_index, int count)
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = first_index; i < first_index + count; i++)
 		ena_free_tx_resources(adapter, i);
 }
 
-static int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id)
+/* 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)
 {
-	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_free_all_io_tx_resources_in_range(adapter,
+					      0,
+					      adapter->xdp_num_queues +
+					      adapter->num_io_queues);
 }
 
 /* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors)
@@ -428,7 +879,7 @@
 {
 	int i, rc = 0;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		rc = ena_setup_rx_resources(adapter, i);
 		if (rc)
 			goto err_setup_rx;
@@ -456,17 +907,21 @@
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = 0; i < adapter->num_io_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)
 {
+	int headroom = rx_ring->rx_headroom;
 	struct ena_com_buf *ena_buf;
 	struct page *page;
 	dma_addr_t dma;
 
+	/* restore page offset value in case it has been changed by device */
+	rx_info->page_offset = headroom;
+
 	/* if previous allocated page is not used */
 	if (unlikely(rx_info->page))
 		return 0;
@@ -479,8 +934,11 @@
 		return -ENOMEM;
 	}
 
+	/* To enable NIC-side port-mirroring, AKA SPAN port,
+	 * we make the buffer readable from the nic as well
+	 */
 	dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
-			   DMA_FROM_DEVICE);
+			   DMA_BIDIRECTIONAL);
 	if (unlikely(dma_mapping_error(rx_ring->dev, dma))) {
 		u64_stats_update_begin(&rx_ring->syncp);
 		rx_ring->rx_stats.dma_mapping_err++;
@@ -490,13 +948,12 @@
 		return -EIO;
 	}
 	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
-		  "alloc page %p, rx_info %p\n", page, rx_info);
+		  "Allocate 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;
+	ena_buf->paddr = dma + headroom;
+	ena_buf->len = ENA_PAGE_SIZE - headroom;
 
 	return 0;
 }
@@ -513,8 +970,9 @@
 		return;
 	}
 
-	dma_unmap_page(rx_ring->dev, ena_buf->paddr, ENA_PAGE_SIZE,
-		       DMA_FROM_DEVICE);
+	dma_unmap_page(rx_ring->dev, ena_buf->paddr - rx_ring->rx_headroom,
+		       ENA_PAGE_SIZE,
+		       DMA_BIDIRECTIONAL);
 
 	__free_page(page);
 	rx_info->page = NULL;
@@ -532,18 +990,14 @@
 		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_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",
+				   "Failed to allocate buffer for rx queue %d\n",
 				   rx_ring->qid);
 			break;
 		}
@@ -552,7 +1006,7 @@
 						req_id);
 		if (unlikely(rc)) {
 			netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
-				   "failed to add buffer for rx queue %d\n",
+				   "Failed to add buffer for rx queue %d\n",
 				   rx_ring->qid);
 			break;
 		}
@@ -564,9 +1018,9 @@
 		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);
+		netif_warn(rx_ring->adapter, rx_err, 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() */
@@ -600,14 +1054,14 @@
 	struct ena_ring *rx_ring;
 	int i, rc, bufs_num;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_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",
+				   "Refilling Queue %d failed. allocated %d buffers from: %d\n",
 				   i, rc, bufs_num);
 	}
 }
@@ -616,12 +1070,12 @@
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = 0; i < adapter->num_io_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)
+static void ena_unmap_tx_buff(struct ena_ring *tx_ring,
+			      struct ena_tx_buffer *tx_info)
 {
 	struct ena_com_buf *ena_buf;
 	u32 cnt;
@@ -665,17 +1119,17 @@
 			continue;
 
 		if (print_once) {
-			netdev_notice(tx_ring->netdev,
-				      "free uncompleted tx skb qid %d idx 0x%x\n",
-				      tx_ring->qid, i);
+			netif_notice(tx_ring->adapter, ifdown, 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);
+			netif_dbg(tx_ring->adapter, ifdown, 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);
+		ena_unmap_tx_buff(tx_ring, tx_info);
 
 		dev_kfree_skb_any(tx_info->skb);
 	}
@@ -688,7 +1142,7 @@
 	struct ena_ring *tx_ring;
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
 		tx_ring = &adapter->tx_ring[i];
 		ena_free_tx_bufs(tx_ring);
 	}
@@ -699,7 +1153,7 @@
 	u16 ena_qid;
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
 		ena_qid = ENA_IO_TXQ_IDX(i);
 		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
 	}
@@ -710,7 +1164,7 @@
 	u16 ena_qid;
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_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);
@@ -723,6 +1177,32 @@
 	ena_destroy_all_rx_queues(adapter);
 }
 
+static int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
+				 struct ena_tx_buffer *tx_info, bool is_xdp)
+{
+	if (tx_info)
+		netif_err(ring->adapter,
+			  tx_done,
+			  ring->netdev,
+			  "tx_info doesn't have valid %s",
+			   is_xdp ? "xdp frame" : "skb");
+	else
+		netif_err(ring->adapter,
+			  tx_done,
+			  ring->netdev,
+			  "Invalid req_id: %hu\n",
+			  req_id);
+
+	u64_stats_update_begin(&ring->syncp);
+	ring->tx_stats.bad_req_id++;
+	u64_stats_update_end(&ring->syncp);
+
+	/* Trigger device reset */
+	ring->adapter->reset_reason = ENA_REGS_RESET_INV_TX_REQ_ID;
+	set_bit(ENA_FLAG_TRIGGER_RESET, &ring->adapter->flags);
+	return -EFAULT;
+}
+
 static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
 {
 	struct ena_tx_buffer *tx_info = NULL;
@@ -733,21 +1213,20 @@
 			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);
+	return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
+}
 
-	u64_stats_update_begin(&tx_ring->syncp);
-	tx_ring->tx_stats.bad_req_id++;
-	u64_stats_update_end(&tx_ring->syncp);
+static int validate_xdp_req_id(struct ena_ring *xdp_ring, u16 req_id)
+{
+	struct ena_tx_buffer *tx_info = NULL;
 
-	/* 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;
+	if (likely(req_id < xdp_ring->ring_size)) {
+		tx_info = &xdp_ring->tx_buffer_info[req_id];
+		if (likely(tx_info->xdpf))
+			return 0;
+	}
+
+	return handle_invalid_req_id(xdp_ring, req_id, tx_info, true);
 }
 
 static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
@@ -786,7 +1265,7 @@
 		tx_info->skb = NULL;
 		tx_info->last_jiffies = 0;
 
-		ena_unmap_tx_skb(tx_ring, tx_info);
+		ena_unmap_tx_buff(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,
@@ -871,6 +1350,7 @@
 
 	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)) {
@@ -885,7 +1365,8 @@
 
 	/* save virt address of first buffer */
 	va = page_address(rx_info->page) + rx_info->page_offset;
-	prefetch(va + NET_IP_ALIGN);
+
+	prefetch(va);
 
 	if (len <= rx_ring->rx_copybreak) {
 		skb = ena_alloc_skb(rx_ring, false);
@@ -893,7 +1374,7 @@
 			return NULL;
 
 		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
-			  "rx allocated small packet. len %d. data_len %d\n",
+			  "RX allocated small packet. len %d. data_len %d\n",
 			  skb->len, skb->data_len);
 
 		/* sync this buffer for CPU use */
@@ -922,13 +1403,13 @@
 	do {
 		dma_unmap_page(rx_ring->dev,
 			       dma_unmap_addr(&rx_info->ena_buf, paddr),
-			       ENA_PAGE_SIZE, DMA_FROM_DEVICE);
+			       ENA_PAGE_SIZE, DMA_BIDIRECTIONAL);
 
 		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",
+			  "RX skb updated. len %d. data_len %d\n",
 			  skb->len, skb->data_len);
 
 		rx_info->page = NULL;
@@ -943,6 +1424,7 @@
 		buf++;
 		len = ena_bufs[buf].len;
 		req_id = ena_bufs[buf].req_id;
+
 		rx_info = &rx_ring->rx_buffer_info[req_id];
 	} while (1);
 
@@ -1037,6 +1519,32 @@
 	}
 }
 
+static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp)
+{
+	struct ena_rx_buffer *rx_info;
+	int ret;
+
+	rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
+	xdp->data = page_address(rx_info->page) + rx_info->page_offset;
+	xdp_set_data_meta_invalid(xdp);
+	xdp->data_hard_start = page_address(rx_info->page);
+	xdp->data_end = xdp->data + rx_ring->ena_bufs[0].len;
+	/* If for some reason we received a bigger packet than
+	 * we expect, then we simply drop it
+	 */
+	if (unlikely(rx_ring->ena_bufs[0].len > ENA_XDP_MAX_MTU))
+		return XDP_DROP;
+
+	ret = ena_xdp_execute(rx_ring, xdp, rx_info);
+
+	/* The xdp program might expand the headers */
+	if (ret == XDP_PASS) {
+		rx_info->page_offset = xdp->data - xdp->data_hard_start;
+		rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data;
+	}
+
+	return ret;
+}
 /* ena_clean_rx_irq - Cleanup RX irq
  * @rx_ring: RX ring to clean
  * @napi: napi handler
@@ -1048,26 +1556,32 @@
 			    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_rx_buffer *rx_info;
 	struct ena_adapter *adapter;
+	u32 res_budget, work_done;
+	int rx_copybreak_pkt = 0;
+	int refill_threshold;
 	struct sk_buff *skb;
 	int refill_required;
-	int refill_threshold;
-	int rc = 0;
+	struct xdp_buff xdp;
 	int total_len = 0;
-	int rx_copybreak_pkt = 0;
+	int xdp_verdict;
+	int rc = 0;
 	int i;
 
 	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
 		  "%s qid %d\n", __func__, rx_ring->qid);
 	res_budget = budget;
+	xdp.rxq = &rx_ring->xdp_rxq;
 
 	do {
+		xdp_verdict = XDP_PASS;
+		skb = NULL;
 		ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
 		ena_rx_ctx.max_bufs = rx_ring->sgl_size;
 		ena_rx_ctx.descs = 0;
+		ena_rx_ctx.pkt_offset = 0;
 		rc = ena_com_rx_pkt(rx_ring->ena_com_io_cq,
 				    rx_ring->ena_com_io_sq,
 				    &ena_rx_ctx);
@@ -1077,17 +1591,34 @@
 		if (unlikely(ena_rx_ctx.descs == 0))
 			break;
 
+		/* First descriptor might have an offset set by the device */
+		rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
+		rx_info->page_offset += ena_rx_ctx.pkt_offset;
+
 		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);
 
+		if (ena_xdp_present_ring(rx_ring))
+			xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp);
+
 		/* allocate skb and fill it */
-		skb = ena_rx_skb(rx_ring, rx_ring->ena_bufs, ena_rx_ctx.descs,
-				 &next_to_clean);
+		if (xdp_verdict == XDP_PASS)
+			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)) {
+			/* The page might not actually be freed here since the
+			 * page reference count is incremented in
+			 * ena_xdp_xmit_buff(), and it will be decreased only
+			 * when send completion was received from the device
+			 */
+			if (xdp_verdict == XDP_TX)
+				ena_free_rx_page(rx_ring,
+						 &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id]);
 			for (i = 0; i < ena_rx_ctx.descs; i++) {
 				rx_ring->free_ids[next_to_clean] =
 					rx_ring->ena_bufs[i].req_id;
@@ -1095,6 +1626,10 @@
 					ENA_RX_RING_IDX_NEXT(next_to_clean,
 							     rx_ring->ring_size);
 			}
+			if (xdp_verdict != XDP_PASS) {
+				res_budget--;
+				continue;
+			}
 			break;
 		}
 
@@ -1126,7 +1661,7 @@
 
 	rx_ring->next_to_clean = next_to_clean;
 
-	refill_required = ena_com_free_desc(rx_ring->ena_com_io_sq);
+	refill_required = ena_com_free_q_entries(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);
@@ -1142,12 +1677,18 @@
 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);
+	if (rc == -ENOSPC) {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.bad_desc_num++;
+		u64_stats_update_end(&rx_ring->syncp);
+		adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS;
+	} else {
+		u64_stats_update_begin(&rx_ring->syncp);
+		rx_ring->rx_stats.bad_req_id++;
+		u64_stats_update_end(&rx_ring->syncp);
+		adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID;
+	}
 
-	/* 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;
@@ -1188,9 +1729,14 @@
 					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);
+	u32 rx_interval = 0;
+	/* Rx ring can be NULL when for XDP tx queues which don't have an
+	 * accompanying rx_ring pair.
+	 */
+	if (rx_ring)
+		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
@@ -1200,11 +1746,16 @@
 				tx_ring->smoothed_interval,
 				true);
 
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->tx_stats.unmask_interrupt++;
+	u64_stats_update_end(&tx_ring->syncp);
+
 	/* 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
+	 * The Tx ring is used because the rx_ring is NULL for XDP queues
 	 */
-	ena_com_unmask_intr(rx_ring->ena_com_io_cq, &intr_reg);
+	ena_com_unmask_intr(tx_ring->ena_com_io_cq, &intr_reg);
 }
 
 static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
@@ -1222,24 +1773,84 @@
 
 	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);
+		if (rx_ring)
+			ena_com_update_numa_node(rx_ring->ena_com_io_cq,
+						 numa_node);
 	}
 
 	tx_ring->cpu = cpu;
-	rx_ring->cpu = cpu;
+	if (rx_ring)
+		rx_ring->cpu = cpu;
 
 	return;
 out:
 	put_cpu();
 }
 
+static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget)
+{
+	u32 total_done = 0;
+	u16 next_to_clean;
+	u32 tx_bytes = 0;
+	int tx_pkts = 0;
+	u16 req_id;
+	int rc;
+
+	if (unlikely(!xdp_ring))
+		return 0;
+	next_to_clean = xdp_ring->next_to_clean;
+
+	while (tx_pkts < budget) {
+		struct ena_tx_buffer *tx_info;
+		struct xdp_frame *xdpf;
+
+		rc = ena_com_tx_comp_req_id_get(xdp_ring->ena_com_io_cq,
+						&req_id);
+		if (rc)
+			break;
+
+		rc = validate_xdp_req_id(xdp_ring, req_id);
+		if (rc)
+			break;
+
+		tx_info = &xdp_ring->tx_buffer_info[req_id];
+		xdpf = tx_info->xdpf;
+
+		tx_info->xdpf = NULL;
+		tx_info->last_jiffies = 0;
+		ena_unmap_tx_buff(xdp_ring, tx_info);
+
+		netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
+			  "tx_poll: q %d skb %p completed\n", xdp_ring->qid,
+			  xdpf);
+
+		tx_bytes += xdpf->len;
+		tx_pkts++;
+		total_done += tx_info->tx_descs;
+
+		__free_page(tx_info->xdp_rx_page);
+		xdp_ring->free_ids[next_to_clean] = req_id;
+		next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
+						     xdp_ring->ring_size);
+	}
+
+	xdp_ring->next_to_clean = next_to_clean;
+	ena_com_comp_ack(xdp_ring->ena_com_io_sq, total_done);
+	ena_com_update_dev_comp_head(xdp_ring->ena_com_io_cq);
+
+	netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
+		  "tx_poll: q %d done. total pkts: %d\n",
+		  xdp_ring->qid, tx_pkts);
+
+	return tx_pkts;
+}
+
 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_work_done;
+	int rx_work_done = 0;
 	int tx_budget;
 	int napi_comp_call = 0;
 	int ret;
@@ -1247,6 +1858,9 @@
 	tx_ring = ena_napi->tx_ring;
 	rx_ring = ena_napi->rx_ring;
 
+	tx_ring->first_interrupt = ena_napi->first_interrupt;
+	rx_ring->first_interrupt = ena_napi->first_interrupt;
+
 	tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;
 
 	if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
@@ -1256,7 +1870,11 @@
 	}
 
 	tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
-	rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
+	/* On netpoll the budget is zero and the handler should only clean the
+	 * tx completions.
+	 */
+	if (likely(budget))
+		rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
 
 	/* If the device is about to reset or down, avoid unmask
 	 * the interrupt and return 0 so NAPI won't reschedule
@@ -1272,7 +1890,10 @@
 		/* Update numa and unmask the interrupt only when schedule
 		 * from the interrupt context (vs from sk_busy_loop)
 		 */
-		if (napi_complete_done(napi, rx_work_done)) {
+		if (napi_complete_done(napi, rx_work_done) &&
+		    READ_ONCE(ena_napi->interrupts_masked)) {
+			smp_rmb(); /* make sure interrupts_masked is read */
+			WRITE_ONCE(ena_napi->interrupts_masked, false);
 			/* We apply adaptive moderation on Rx path only.
 			 * Tx uses static interrupt moderation.
 			 */
@@ -1318,8 +1939,10 @@
 {
 	struct ena_napi *ena_napi = data;
 
-	ena_napi->tx_ring->first_interrupt = true;
-	ena_napi->rx_ring->first_interrupt = true;
+	ena_napi->first_interrupt = true;
+
+	WRITE_ONCE(ena_napi->interrupts_masked, true);
+	smp_wmb(); /* write interrupts_masked before calling napi */
 
 	napi_schedule_irqoff(&ena_napi->napi);
 
@@ -1331,7 +1954,7 @@
  * the number of potential io queues is the minimum of what the device
  * supports and the number of vCPUs.
  */
-static int ena_enable_msix(struct ena_adapter *adapter, int num_queues)
+static int ena_enable_msix(struct ena_adapter *adapter)
 {
 	int msix_vecs, irq_cnt;
 
@@ -1342,9 +1965,9 @@
 	}
 
 	/* Reserved the max msix vectors we might need */
-	msix_vecs = ENA_MAX_MSIX_VEC(num_queues);
+	msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
 	netif_dbg(adapter, probe, adapter->netdev,
-		  "trying to enable MSI-X, vectors %d\n", msix_vecs);
+		  "Trying to enable MSI-X, vectors %d\n", msix_vecs);
 
 	irq_cnt = pci_alloc_irq_vectors(adapter->pdev, ENA_MIN_MSIX_VEC,
 					msix_vecs, PCI_IRQ_MSIX);
@@ -1357,9 +1980,9 @@
 
 	if (irq_cnt != msix_vecs) {
 		netif_notice(adapter, probe, adapter->netdev,
-			     "enable only %d MSI-X (out of %d), reduce the number of queues\n",
+			     "Enable only %d MSI-X (out of %d), reduce the number of queues\n",
 			     irq_cnt, msix_vecs);
-		adapter->num_queues = irq_cnt - ENA_ADMIN_MSIX_VEC;
+		adapter->num_io_queues = irq_cnt - ENA_ADMIN_MSIX_VEC;
 	}
 
 	if (ena_init_rx_cpu_rmap(adapter))
@@ -1394,10 +2017,12 @@
 {
 	struct net_device *netdev;
 	int irq_idx, i, cpu;
+	int io_queue_count;
 
 	netdev = adapter->netdev;
+	io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < io_queue_count; i++) {
 		irq_idx = ENA_IO_IRQ_IDX(i);
 		cpu = i % num_online_cpus();
 
@@ -1425,12 +2050,12 @@
 			 irq->data);
 	if (rc) {
 		netif_err(adapter, probe, adapter->netdev,
-			  "failed to request admin irq\n");
+			  "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",
+		  "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);
@@ -1440,6 +2065,7 @@
 
 static int ena_request_io_irq(struct ena_adapter *adapter)
 {
+	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 	unsigned long flags = 0;
 	struct ena_irq *irq;
 	int rc = 0, i, k;
@@ -1450,7 +2076,7 @@
 		return -EINVAL;
 	}
 
-	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
 		irq = &adapter->irq_tbl[i];
 		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
 				 irq->data);
@@ -1462,7 +2088,7 @@
 		}
 
 		netif_dbg(adapter, ifup, adapter->netdev,
-			  "set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
+			  "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);
@@ -1491,6 +2117,7 @@
 
 static void ena_free_io_irq(struct ena_adapter *adapter)
 {
+	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 	struct ena_irq *irq;
 	int i;
 
@@ -1501,7 +2128,7 @@
 	}
 #endif /* CONFIG_RFS_ACCEL */
 
-	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
 		irq = &adapter->irq_tbl[i];
 		irq_set_affinity_hint(irq->vector, NULL);
 		free_irq(irq->vector, irq->data);
@@ -1516,54 +2143,70 @@
 
 static void ena_disable_io_intr_sync(struct ena_adapter *adapter)
 {
+	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 	int i;
 
 	if (!netif_running(adapter->netdev))
 		return;
 
-	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++)
+	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++)
 		synchronize_irq(adapter->irq_tbl[i].vector);
 }
 
-static void ena_del_napi(struct ena_adapter *adapter)
+static void ena_del_napi_in_range(struct ena_adapter *adapter,
+				  int first_index,
+				  int count)
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = first_index; i < first_index + count; i++) {
 		netif_napi_del(&adapter->ena_napi[i].napi);
+
+		WARN_ON(!ENA_IS_XDP_INDEX(adapter, i) &&
+			adapter->ena_napi[i].xdp_ring);
+	}
 }
 
-static void ena_init_napi(struct ena_adapter *adapter)
+static void ena_init_napi_in_range(struct ena_adapter *adapter,
+				   int first_index, int count)
 {
-	struct ena_napi *napi;
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
-		napi = &adapter->ena_napi[i];
+	for (i = first_index; i < first_index + count; i++) {
+		struct ena_napi *napi = &adapter->ena_napi[i];
 
 		netif_napi_add(adapter->netdev,
-			       &adapter->ena_napi[i].napi,
-			       ena_io_poll,
+			       &napi->napi,
+			       ENA_IS_XDP_INDEX(adapter, i) ? ena_xdp_io_poll : ena_io_poll,
 			       ENA_NAPI_BUDGET);
-		napi->rx_ring = &adapter->rx_ring[i];
-		napi->tx_ring = &adapter->tx_ring[i];
+
+		if (!ENA_IS_XDP_INDEX(adapter, i)) {
+			napi->rx_ring = &adapter->rx_ring[i];
+			napi->tx_ring = &adapter->tx_ring[i];
+		} else {
+			napi->xdp_ring = &adapter->tx_ring[i];
+		}
 		napi->qid = i;
 	}
 }
 
-static void ena_napi_disable_all(struct ena_adapter *adapter)
+static void ena_napi_disable_in_range(struct ena_adapter *adapter,
+				      int first_index,
+				      int count)
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = first_index; i < first_index + count; i++)
 		napi_disable(&adapter->ena_napi[i].napi);
 }
 
-static void ena_napi_enable_all(struct ena_adapter *adapter)
+static void ena_napi_enable_in_range(struct ena_adapter *adapter,
+				     int first_index,
+				     int count)
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = first_index; i < first_index + count; i++)
 		napi_enable(&adapter->ena_napi[i].napi);
 }
 
@@ -1616,7 +2259,9 @@
 	/* enable transmits */
 	netif_tx_start_all_queues(adapter->netdev);
 
-	ena_napi_enable_all(adapter);
+	ena_napi_enable_in_range(adapter,
+				 0,
+				 adapter->xdp_num_queues + adapter->num_io_queues);
 
 	return 0;
 }
@@ -1668,12 +2313,13 @@
 	return rc;
 }
 
-static int ena_create_all_io_tx_queues(struct ena_adapter *adapter)
+static int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
+					    int first_index, int count)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc, i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = first_index; i < first_index + count; i++) {
 		rc = ena_create_io_tx_queue(adapter, i);
 		if (rc)
 			goto create_err;
@@ -1682,7 +2328,7 @@
 	return 0;
 
 create_err:
-	while (i--)
+	while (i-- > first_index)
 		ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
 
 	return rc;
@@ -1727,13 +2373,15 @@
 		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;
+		goto err;
 	}
 
 	ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
 
 	return rc;
+err:
+	ena_com_destroy_io_queue(ena_dev, ena_qid);
+	return rc;
 }
 
 static int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
@@ -1741,7 +2389,7 @@
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc, i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		rc = ena_create_io_rx_queue(adapter, i);
 		if (rc)
 			goto create_err;
@@ -1760,11 +2408,12 @@
 }
 
 static void set_io_rings_size(struct ena_adapter *adapter,
-				     int new_tx_size, int new_rx_size)
+			      int new_tx_size,
+			      int new_rx_size)
 {
 	int i;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		adapter->tx_ring[i].ring_size = new_tx_size;
 		adapter->rx_ring[i].ring_size = new_rx_size;
 	}
@@ -1797,11 +2446,21 @@
 			  adapter->requested_rx_ring_size);
 
 	while (1) {
-		rc = ena_setup_all_tx_resources(adapter);
+		if (ena_xdp_present(adapter)) {
+			rc = ena_setup_and_create_all_xdp_queues(adapter);
+
+			if (rc)
+				goto err_setup_tx;
+		}
+		rc = ena_setup_tx_resources_in_range(adapter,
+						     0,
+						     adapter->num_io_queues);
 		if (rc)
 			goto err_setup_tx;
 
-		rc = ena_create_all_io_tx_queues(adapter);
+		rc = ena_create_io_tx_queues_in_range(adapter,
+						      0,
+						      adapter->num_io_queues);
 		if (rc)
 			goto err_create_tx_queues;
 
@@ -1867,10 +2526,11 @@
 
 static int ena_up(struct ena_adapter *adapter)
 {
-	int rc, i;
+	int io_queue_count, rc, i;
 
-	netdev_dbg(adapter->netdev, "%s\n", __func__);
+	netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);
 
+	io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 	ena_setup_io_intr(adapter);
 
 	/* napi poll functions should be initialized before running
@@ -1878,7 +2538,7 @@
 	 * interrupt, causing the ISR to fire immediately while the poll
 	 * function wasn't set yet, causing a null dereference
 	 */
-	ena_init_napi(adapter);
+	ena_init_napi_in_range(adapter, 0, io_queue_count);
 
 	rc = ena_request_io_irq(adapter);
 	if (rc)
@@ -1902,14 +2562,14 @@
 	set_bit(ENA_FLAG_DEV_UP, &adapter->flags);
 
 	/* Enable completion queues interrupt */
-	for (i = 0; i < adapter->num_queues; i++)
+	for (i = 0; i < adapter->num_io_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++)
+	for (i = 0; i < io_queue_count; i++)
 		napi_schedule(&adapter->ena_napi[i].napi);
 
 	return rc;
@@ -1922,13 +2582,15 @@
 err_create_queues_with_backoff:
 	ena_free_io_irq(adapter);
 err_req_irq:
-	ena_del_napi(adapter);
+	ena_del_napi_in_range(adapter, 0, io_queue_count);
 
 	return rc;
 }
 
 static void ena_down(struct ena_adapter *adapter)
 {
+	int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
+
 	netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__);
 
 	clear_bit(ENA_FLAG_DEV_UP, &adapter->flags);
@@ -1941,7 +2603,7 @@
 	netif_tx_disable(adapter->netdev);
 
 	/* After this point the napi handler won't enable the tx queue */
-	ena_napi_disable_all(adapter);
+	ena_napi_disable_in_range(adapter, 0, io_queue_count);
 
 	/* After destroy the queue there won't be any new interrupts */
 
@@ -1950,7 +2612,8 @@
 
 		rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
 		if (rc)
-			dev_err(&adapter->pdev->dev, "Device reset failed\n");
+			netif_err(adapter, ifdown, adapter->netdev,
+				  "Device reset failed\n");
 		/* stop submitting admin commands on a device that was reset */
 		ena_com_set_admin_running_state(adapter->ena_dev, false);
 	}
@@ -1959,7 +2622,7 @@
 
 	ena_disable_io_intr_sync(adapter);
 	ena_free_io_irq(adapter);
-	ena_del_napi(adapter);
+	ena_del_napi_in_range(adapter, 0, io_queue_count);
 
 	ena_free_all_tx_bufs(adapter);
 	ena_free_all_rx_bufs(adapter);
@@ -1984,13 +2647,13 @@
 	int rc;
 
 	/* Notify the stack of the actual queue counts. */
-	rc = netif_set_real_num_tx_queues(netdev, adapter->num_queues);
+	rc = netif_set_real_num_tx_queues(netdev, adapter->num_io_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);
+	rc = netif_set_real_num_rx_queues(netdev, adapter->num_io_queues);
 	if (rc) {
 		netif_err(adapter, ifup, netdev, "Can't set num rx queues\n");
 		return rc;
@@ -2043,17 +2706,59 @@
 			   u32 new_tx_size,
 			   u32 new_rx_size)
 {
-	bool dev_up;
+	bool dev_was_up;
 
-	dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+	dev_was_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;
+	ena_init_io_rings(adapter,
+			  0,
+			  adapter->xdp_num_queues +
+			  adapter->num_io_queues);
+	return dev_was_up ? ena_up(adapter) : 0;
 }
 
-static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct sk_buff *skb)
+int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count)
+{
+	struct ena_com_dev *ena_dev = adapter->ena_dev;
+	int prev_channel_count;
+	bool dev_was_up;
+
+	dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+	ena_close(adapter->netdev);
+	prev_channel_count = adapter->num_io_queues;
+	adapter->num_io_queues = new_channel_count;
+	if (ena_xdp_present(adapter) &&
+	    ena_xdp_allowed(adapter) == ENA_XDP_ALLOWED) {
+		adapter->xdp_first_ring = new_channel_count;
+		adapter->xdp_num_queues = new_channel_count;
+		if (prev_channel_count > new_channel_count)
+			ena_xdp_exchange_program_rx_in_range(adapter,
+							     NULL,
+							     new_channel_count,
+							     prev_channel_count);
+		else
+			ena_xdp_exchange_program_rx_in_range(adapter,
+							     adapter->xdp_bpf_prog,
+							     prev_channel_count,
+							     new_channel_count);
+	}
+
+	/* We need to destroy the rss table so that the indirection
+	 * table will be reinitialized by ena_up()
+	 */
+	ena_com_rss_destroy(ena_dev);
+	ena_init_io_rings(adapter,
+			  0,
+			  adapter->xdp_num_queues +
+			  adapter->num_io_queues);
+	return dev_was_up ? ena_open(adapter->netdev) : 0;
+}
+
+static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx,
+			struct sk_buff *skb,
+			bool disable_meta_caching)
 {
 	u32 mss = skb_shinfo(skb)->gso_size;
 	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
@@ -2097,7 +2802,9 @@
 		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 if (disable_meta_caching) {
+		memset(ena_meta, 0, sizeof(*ena_meta));
+		ena_tx_ctx->meta_valid = 1;
 	} else {
 		ena_tx_ctx->meta_valid = 0;
 	}
@@ -2228,12 +2935,12 @@
 	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");
+	netif_warn(adapter, tx_queued, 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);
+	ena_unmap_tx_buff(tx_ring, tx_info);
 
 	return -EINVAL;
 }
@@ -2248,7 +2955,7 @@
 	struct netdev_queue *txq;
 	void *push_hdr;
 	u16 next_to_use, req_id, header_len;
-	int qid, rc, nb_hw_desc;
+	int qid, rc;
 
 	netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
 	/*  Determine which tx ring we will be placed on */
@@ -2281,52 +2988,19 @@
 	ena_tx_ctx.header_len = header_len;
 
 	/* set flags and meta data */
-	ena_tx_csum(&ena_tx_ctx, skb);
+	ena_tx_csum(&ena_tx_ctx, skb, tx_ring->disable_meta_caching);
 
-	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);
+	rc = ena_xmit_common(dev,
+			     tx_ring,
+			     tx_info,
+			     &ena_tx_ctx,
+			     next_to_use,
+			     skb->len);
+	if (rc)
 		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).
@@ -2373,7 +3047,7 @@
 	return NETDEV_TX_OK;
 
 error_unmap_dma:
-	ena_unmap_tx_skb(tx_ring, tx_info);
+	ena_unmap_tx_buff(tx_ring, tx_info);
 	tx_info->skb = NULL;
 
 error_drop_packet:
@@ -2397,16 +3071,16 @@
 	return qid;
 }
 
-static void ena_config_host_info(struct ena_com_dev *ena_dev,
-				 struct pci_dev *pdev)
+static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
 {
+	struct device *dev = &pdev->dev;
 	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");
+		dev_err(dev, "Cannot allocate host info\n");
 		return;
 	}
 
@@ -2421,21 +3095,24 @@
 	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) |
+		(DRV_MODULE_GEN_MAJOR) |
+		(DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
+		(DRV_MODULE_GEN_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;
+		ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK |
+		ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK |
+		ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK |
+		ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK;
 
 	rc = ena_com_set_host_attributes(ena_dev);
 	if (rc) {
 		if (rc == -EOPNOTSUPP)
-			pr_warn("Cannot set host attributes\n");
+			dev_warn(dev, "Cannot set host attributes\n");
 		else
-			pr_err("Cannot set host attributes\n");
+			dev_err(dev, "Cannot set host attributes\n");
 
 		goto err;
 	}
@@ -2463,7 +3140,8 @@
 
 	rc = ena_com_allocate_debug_area(adapter->ena_dev, debug_area_size);
 	if (rc) {
-		pr_err("Cannot allocate debug area\n");
+		netif_err(adapter, drv, adapter->netdev,
+			  "Cannot allocate debug area\n");
 		return;
 	}
 
@@ -2483,6 +3161,19 @@
 	ena_com_delete_debug_area(adapter->ena_dev);
 }
 
+int ena_update_hw_stats(struct ena_adapter *adapter)
+{
+	int rc = 0;
+
+	rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_stats);
+	if (rc) {
+		dev_info_once(&adapter->pdev->dev, "Failed to get ENI stats\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static void ena_get_stats64(struct net_device *netdev,
 			    struct rtnl_link_stats64 *stats)
 {
@@ -2490,12 +3181,13 @@
 	struct ena_ring *rx_ring, *tx_ring;
 	unsigned int start;
 	u64 rx_drops;
+	u64 tx_drops;
 	int i;
 
 	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
 		return;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		u64 bytes, packets;
 
 		tx_ring = &adapter->tx_ring[i];
@@ -2524,9 +3216,11 @@
 	do {
 		start = u64_stats_fetch_begin_irq(&adapter->syncp);
 		rx_drops = adapter->dev_stats.rx_drops;
+		tx_drops = adapter->dev_stats.tx_drops;
 	} while (u64_stats_fetch_retry_irq(&adapter->syncp, start));
 
 	stats->rx_dropped = rx_drops;
+	stats->tx_dropped = tx_drops;
 
 	stats->multicast = 0;
 	stats->collisions = 0;
@@ -2552,6 +3246,7 @@
 	.ndo_change_mtu		= ena_change_mtu,
 	.ndo_set_mac_address	= NULL,
 	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_bpf		= ena_xdp,
 };
 
 static int ena_device_validate_params(struct ena_adapter *adapter,
@@ -2577,10 +3272,71 @@
 	return 0;
 }
 
+static void set_default_llq_configurations(struct ena_llq_configurations *llq_config)
+{
+	llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
+	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 = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+	llq_config->llq_ring_entry_size_value = 128;
+}
+
+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)
+{
+	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;
+	}
+
+	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;
+}
+
+static int ena_map_llq_mem_bar(struct pci_dev *pdev, struct ena_com_dev *ena_dev,
+			       int bars)
+{
+	bool has_mem_bar = !!(bars & BIT(ENA_MEM_BAR));
+
+	if (!has_mem_bar) {
+		if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+			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 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 ena_llq_configurations llq_config;
 	struct device *dev = &pdev->dev;
 	bool readless_supported;
 	u32 aenq_groups;
@@ -2589,7 +3345,7 @@
 
 	rc = ena_com_mmio_reg_read_request_init(ena_dev);
 	if (rc) {
-		dev_err(dev, "failed to init mmio read less\n");
+		dev_err(dev, "Failed to init mmio read less\n");
 		return rc;
 	}
 
@@ -2607,7 +3363,7 @@
 
 	rc = ena_com_validate_version(ena_dev);
 	if (rc) {
-		dev_err(dev, "device version is too low\n");
+		dev_err(dev, "Device version is too low\n");
 		goto err_mmio_read_less;
 	}
 
@@ -2618,16 +3374,9 @@
 		goto err_mmio_read_less;
 	}
 
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_width));
+	rc = dma_set_mask_and_coherent(dev, 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);
+		dev_err(dev, "dma_set_mask_and_coherent failed %d\n", rc);
 		goto err_mmio_read_less;
 	}
 
@@ -2671,6 +3420,15 @@
 
 	*wd_state = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
 
+	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(dev, "ENA device init failed\n");
+		goto err_admin_init;
+	}
+
 	return 0;
 
 err_admin_init:
@@ -2682,14 +3440,13 @@
 	return rc;
 }
 
-static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter,
-						    int io_vectors)
+static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	struct device *dev = &adapter->pdev->dev;
 	int rc;
 
-	rc = ena_enable_msix(adapter, io_vectors);
+	rc = ena_enable_msix(adapter);
 	if (rc) {
 		dev_err(dev, "Can not reserve msix vectors\n");
 		return rc;
@@ -2754,6 +3511,7 @@
 
 	ena_com_mmio_reg_read_request_destroy(ena_dev);
 
+	/* return reset reason to default value */
 	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
 
 	clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
@@ -2782,8 +3540,7 @@
 		goto err_device_destroy;
 	}
 
-	rc = ena_enable_msix_and_set_admin_interrupts(adapter,
-						      adapter->num_queues);
+	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
 	if (rc) {
 		dev_err(&pdev->dev, "Enable MSI-X failed\n");
 		goto err_device_destroy;
@@ -2804,9 +3561,10 @@
 		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);
+	adapter->last_keep_alive_jiffies = jiffies;
+	dev_err(&pdev->dev, "Device reset completed successfully\n");
+
+	dev_err(&pdev->dev, "Device reset completed successfully\n");
 
 	return rc;
 err_disable_msix:
@@ -2831,16 +3589,14 @@
 {
 	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);
+
+	if (likely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
+		ena_destroy_device(adapter, false);
+		ena_restore_device(adapter);
+	}
+
 	rtnl_unlock();
 }
 
@@ -2922,7 +3678,7 @@
 	}
 
 	u64_stats_update_begin(&tx_ring->syncp);
-	tx_ring->tx_stats.missed_tx = missed_tx;
+	tx_ring->tx_stats.missed_tx += missed_tx;
 	u64_stats_update_end(&tx_ring->syncp);
 
 	return rc;
@@ -2933,7 +3689,9 @@
 	struct ena_ring *tx_ring;
 	struct ena_ring *rx_ring;
 	int i, budget, rc;
+	int io_queue_count;
 
+	io_queue_count = adapter->xdp_num_queues + adapter->num_io_queues;
 	/* Make sure the driver doesn't turn the device in other process */
 	smp_rmb();
 
@@ -2948,7 +3706,7 @@
 
 	budget = ENA_MONITORED_TX_QUEUES;
 
-	for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) {
+	for (i = adapter->last_monitored_tx_qid; i < io_queue_count; i++) {
 		tx_ring = &adapter->tx_ring[i];
 		rx_ring = &adapter->rx_ring[i];
 
@@ -2956,7 +3714,8 @@
 		if (unlikely(rc))
 			return;
 
-		rc = check_for_rx_interrupt_queue(adapter, rx_ring);
+		rc =  !ENA_IS_XDP_INDEX(adapter, i) ?
+			check_for_rx_interrupt_queue(adapter, rx_ring) : 0;
 		if (unlikely(rc))
 			return;
 
@@ -2965,7 +3724,7 @@
 			break;
 	}
 
-	adapter->last_monitored_tx_qid = i % adapter->num_queues;
+	adapter->last_monitored_tx_qid = i % io_queue_count;
 }
 
 /* trigger napi schedule after 2 consecutive detections */
@@ -2995,11 +3754,10 @@
 	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
 		return;
 
-	for (i = 0; i < adapter->num_queues; i++) {
+	for (i = 0; i < adapter->num_io_queues; i++) {
 		rx_ring = &adapter->rx_ring[i];
 
-		refill_required =
-			ena_com_free_desc(rx_ring->ena_com_io_sq);
+		refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
 		if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
 			rx_ring->empty_rx_queue++;
 
@@ -3009,7 +3767,7 @@
 				u64_stats_update_end(&rx_ring->syncp);
 
 				netif_err(adapter, drv, adapter->netdev,
-					  "trigger refill for ring %d\n", i);
+					  "Trigger refill for ring %d\n", i);
 
 				napi_schedule(rx_ring->napi);
 				rx_ring->empty_rx_queue = 0;
@@ -3031,8 +3789,8 @@
 	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);
+	keep_alive_expired = 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");
@@ -3134,19 +3892,19 @@
 	}
 
 	/* Reset the timer */
-	mod_timer(&adapter->timer_service, jiffies + HZ);
+	mod_timer(&adapter->timer_service, round_jiffies(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)
+static u32 ena_calc_max_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;
+	u32 io_tx_sq_num, io_tx_cq_num, io_rx_num, max_num_io_queues;
 
 	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,
+		io_rx_num = min_t(u32, 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;
@@ -3156,73 +3914,25 @@
 			&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);
+		io_rx_num = min_t(u32, 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);
+	max_num_io_queues = min_t(u32, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
+	max_num_io_queues = min_t(u32, max_num_io_queues, io_rx_num);
+	max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_sq_num);
+	max_num_io_queues = min_t(u32, max_num_io_queues, 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)) {
+	max_num_io_queues = min_t(u32, max_num_io_queues, pci_msix_vec_count(pdev) - 1);
+	if (unlikely(!max_num_io_queues)) {
 		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;
+	return max_num_io_queues;
 }
 
 static void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat,
@@ -3302,7 +4012,7 @@
 	}
 
 	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
-		val = ethtool_rxfh_indir_default(i, adapter->num_queues);
+		val = ethtool_rxfh_indir_default(i, adapter->num_io_queues);
 		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
 						       ENA_IO_RXQ_IDX(val));
 		if (unlikely(rc && (rc != -EOPNOTSUPP))) {
@@ -3311,7 +4021,7 @@
 		}
 	}
 
-	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL,
+	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL,
 					ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
 	if (unlikely(rc && (rc != -EOPNOTSUPP))) {
 		dev_err(dev, "Cannot fill hash function\n");
@@ -3340,16 +4050,8 @@
 	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)
+static int ena_calc_io_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;
@@ -3358,7 +4060,7 @@
 	u32 max_tx_queue_size;
 	u32 max_rx_queue_size;
 
-	if (ctx->ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+	if (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,
@@ -3427,27 +4129,30 @@
  */
 static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+	struct ena_calc_queue_size_ctx calc_queue_ctx = {};
 	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;
+	u32 max_num_io_queues;
 	bool wd_state;
+	int bars, rc;
 
 	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;
 	}
 
+	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(ENA_MAX_PHYS_ADDR_SIZE_BITS));
+	if (rc) {
+		dev_err(&pdev->dev, "dma_set_mask_and_coherent failed %d\n", rc);
+		goto err_disable_device;
+	}
+
 	pci_set_master(pdev);
 
 	ena_dev = vzalloc(sizeof(*ena_dev));
@@ -3468,56 +4173,48 @@
 					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");
+		dev_err(&pdev->dev, "Failed to remap regs bar\n");
 		rc = -EFAULT;
 		goto err_free_region;
 	}
 
+	ena_dev->ena_min_poll_delay_us = ENA_ADMIN_POLL_DELAY_US;
+
 	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");
+		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);
+	rc = ena_map_llq_mem_bar(pdev, ena_dev, bars);
 	if (rc) {
-		dev_err(&pdev->dev, "ena device init failed\n");
-		goto err_device_destroy;
+		dev_err(&pdev->dev, "ENA llq bar mapping failed\n");
+		goto err_free_ena_dev;
 	}
 
 	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
-	*/
+	/* 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) {
+	max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev, &get_feat_ctx);
+	rc = ena_calc_io_queue_size(&calc_queue_ctx);
+	if (rc || !max_num_io_queues) {
 		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);
+	netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), max_num_io_queues);
 	if (!netdev) {
 		dev_err(&pdev->dev, "alloc_etherdev_mq failed\n");
 		rc = -ENOMEM;
@@ -3545,10 +4242,19 @@
 	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->num_io_queues = max_num_io_queues;
+	adapter->max_num_io_queues = max_num_io_queues;
 	adapter->last_monitored_tx_qid = 0;
 
+	adapter->xdp_first_ring = 0;
+	adapter->xdp_num_queues = 0;
+
 	adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK;
+	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+		adapter->disable_meta_caching =
+			!!(get_feat_ctx.llq.accel_mode.u.get.supported_flags &
+			   BIT(ENA_ADMIN_DISABLE_META_CACHING));
+
 	adapter->wd_state = wd_state;
 
 	snprintf(adapter->name, ENA_NAME_MAX_LEN, "ena_%d", adapters_found);
@@ -3559,7 +4265,10 @@
 			"Failed to query interrupt moderation feature\n");
 		goto err_netdev_destroy;
 	}
-	ena_init_io_rings(adapter);
+	ena_init_io_rings(adapter,
+			  0,
+			  adapter->xdp_num_queues +
+			  adapter->num_io_queues);
 
 	netdev->netdev_ops = &ena_netdev_ops;
 	netdev->watchdog_timeo = TX_TIMEOUT;
@@ -3569,7 +4278,7 @@
 
 	u64_stats_init(&adapter->syncp);
 
-	rc = ena_enable_msix_and_set_admin_interrupts(adapter, io_queue_num);
+	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"Failed to enable and set the admin interrupts\n");
@@ -3583,6 +4292,11 @@
 
 	ena_config_debug_area(adapter);
 
+	if (!ena_update_hw_stats(adapter))
+		adapter->eni_stats_supported = true;
+	else
+		adapter->eni_stats_supported = false;
+
 	memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
 
 	netif_carrier_off(netdev);
@@ -3605,15 +4319,10 @@
 	timer_setup(&adapter->timer_service, ena_timer_service, 0);
 	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",
+		 "%s found at mem %lx, mac addr %pM\n",
 		 DEVICE_NAME, (long)pci_resource_start(pdev, 0),
-		 netdev->dev_addr, io_queue_num, queue_type_str);
+		 netdev->dev_addr);
 
 	set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
 
@@ -3648,13 +4357,15 @@
 
 /*****************************************************************************/
 
-/* ena_remove - Device Removal Routine
+/* __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_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
+ * __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_remove(struct pci_dev *pdev)
+static void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
 {
 	struct ena_adapter *adapter = pci_get_drvdata(pdev);
 	struct ena_com_dev *ena_dev;
@@ -3669,17 +4380,25 @@
 		netdev->rx_cpu_rmap = NULL;
 	}
 #endif /* CONFIG_RFS_ACCEL */
-	del_timer_sync(&adapter->timer_service);
 
+	/* Make sure timer and reset routine won't be called after
+	 * freeing device resources.
+	 */
+	del_timer_sync(&adapter->timer_service);
 	cancel_work_sync(&adapter->reset_task);
 
-	rtnl_lock();
+	rtnl_lock(); /* lock released inside the below if-else block */
+	adapter->reset_reason = ENA_REGS_RESET_SHUTDOWN;
 	ena_destroy_device(adapter, true);
-	rtnl_unlock();
-
-	unregister_netdev(netdev);
-
-	free_netdev(netdev);
+	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);
 
@@ -3694,13 +4413,36 @@
 	vfree(ena_dev);
 }
 
-#ifdef CONFIG_PM
-/* ena_suspend - PM suspend callback
+/* ena_remove - Device Removal Routine
  * @pdev: PCI device information struct
- * @state:power state
+ *
+ * ena_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
  */
-static int ena_suspend(struct pci_dev *pdev,  pm_message_t state)
+
+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);
+}
+
+/* ena_suspend - PM suspend callback
+ * @dev_d: Device information struct
+ */
+static int __maybe_unused ena_suspend(struct device *dev_d)
+{
+	struct pci_dev *pdev = to_pci_dev(dev_d);
 	struct ena_adapter *adapter = pci_get_drvdata(pdev);
 
 	u64_stats_update_begin(&adapter->syncp);
@@ -3710,7 +4452,7 @@
 	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");
+			"Ignoring device reset request as the device is being suspended\n");
 		clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
 	}
 	ena_destroy_device(adapter, true);
@@ -3719,12 +4461,11 @@
 }
 
 /* ena_resume - PM resume callback
- * @pdev: PCI device information struct
- *
+ * @dev_d: Device information struct
  */
-static int ena_resume(struct pci_dev *pdev)
+static int __maybe_unused ena_resume(struct device *dev_d)
 {
-	struct ena_adapter *adapter = pci_get_drvdata(pdev);
+	struct ena_adapter *adapter = dev_get_drvdata(dev_d);
 	int rc;
 
 	u64_stats_update_begin(&adapter->syncp);
@@ -3736,24 +4477,21 @@
 	rtnl_unlock();
 	return rc;
 }
-#endif
+
+static SIMPLE_DEV_PM_OPS(ena_pm_ops, ena_suspend, ena_resume);
 
 static struct pci_driver ena_pci_driver = {
 	.name		= DRV_MODULE_NAME,
 	.id_table	= ena_pci_tbl,
 	.probe		= ena_probe,
 	.remove		= ena_remove,
-#ifdef CONFIG_PM
-	.suspend    = ena_suspend,
-	.resume     = ena_resume,
-#endif
+	.shutdown	= ena_shutdown,
+	.driver.pm	= &ena_pm_ops,
 	.sriov_configure = pci_sriov_configure_simple,
 };
 
 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");
@@ -3789,7 +4527,7 @@
 		ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
 
 	if (status) {
-		netdev_dbg(adapter->netdev, "%s\n", __func__);
+		netif_dbg(adapter, ifup, 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);
@@ -3805,14 +4543,20 @@
 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
 	struct ena_admin_aenq_keep_alive_desc *desc;
 	u64 rx_drops;
+	u64 tx_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;
+	tx_drops = ((u64)desc->tx_drops_high << 32) | desc->tx_drops_low;
 
 	u64_stats_update_begin(&adapter->syncp);
+	/* These stats are accumulated by the device, so the counters indicate
+	 * all drops since last reset.
+	 */
 	adapter->dev_stats.rx_drops = rx_drops;
+	adapter->dev_stats.tx_drops = tx_drops;
 	u64_stats_update_end(&adapter->syncp);
 }
 
@@ -3827,7 +4571,7 @@
 	     aenq_e->aenq_common_desc.group,
 	     ENA_ADMIN_NOTIFICATION);
 
-	switch (aenq_e->aenq_common_desc.syndrom) {
+	switch (aenq_e->aenq_common_desc.syndrome) {
 	case ENA_ADMIN_UPDATE_HINTS:
 		hints = (struct ena_admin_ena_hw_hints *)
 			(&aenq_e->inline_data_w4);
@@ -3836,7 +4580,7 @@
 	default:
 		netif_err(adapter, drv, adapter->netdev,
 			  "Invalid aenq notification link state %d\n",
-			  aenq_e->aenq_common_desc.syndrom);
+			  aenq_e->aenq_common_desc.syndrome);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #ifndef ENA_H
@@ -36,6 +9,7 @@
 #include <linux/bitops.h>
 #include <linux/dim.h>
 #include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 #include <linux/inetdevice.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
@@ -44,17 +18,11 @@
 #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_GEN_MAJOR	2
+#define DRV_MODULE_GEN_MINOR	1
+#define DRV_MODULE_GEN_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)"
 
@@ -68,7 +36,7 @@
  * 16kB.
  */
 #if PAGE_SIZE > SZ_16K
-#define ENA_PAGE_SIZE SZ_16K
+#define ENA_PAGE_SIZE (_AC(SZ_16K, UL))
 #else
 #define ENA_PAGE_SIZE PAGE_SIZE
 #endif
@@ -82,6 +50,8 @@
 #define ENA_DEFAULT_RING_SIZE	(1024)
 #define ENA_MIN_RING_SIZE	(256)
 
+#define ENA_MIN_NUM_IO_QUEUES	(1)
+
 #define ENA_TX_WAKEUP_THRESH		(MAX_SKB_FRAGS + 2)
 #define ENA_DEFAULT_RX_COPYBREAK	(256 - NET_IP_ALIGN)
 
@@ -101,8 +71,6 @@
 #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.
  */
@@ -127,11 +95,15 @@
 
 #define ENA_IO_TXQ_IDX(q)	(2 * (q))
 #define ENA_IO_RXQ_IDX(q)	(2 * (q) + 1)
+#define ENA_IO_TXQ_IDX_TO_COMBINED_IDX(q)	((q) / 2)
+#define ENA_IO_RXQ_IDX_TO_COMBINED_IDX(q)	(((q) - 1) / 2)
 
 #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))
 
+#define ENA_ADMIN_POLL_DELAY_US 100
+
 /* ENA device should send keep alive msg every 1 sec.
  * We wait for 6 sec just to be on the safe side.
  */
@@ -140,6 +112,18 @@
 
 #define ENA_MMIO_DISABLE_REG_READ	BIT(0)
 
+/* The max MTU size is configured to be the ethernet frame size without
+ * the overhead of the ethernet header, which can have a VLAN header, and
+ * a frame check sequence (FCS).
+ * The buffer size we share with the device is defined to be ENA_PAGE_SIZE
+ */
+
+#define ENA_XDP_MAX_MTU (ENA_PAGE_SIZE - ETH_HLEN - ETH_FCS_LEN - \
+				VLAN_HLEN - XDP_PACKET_HEADROOM)
+
+#define ENA_IS_XDP_INDEX(adapter, index) (((index) >= (adapter)->xdp_first_ring) && \
+	((index) < (adapter)->xdp_first_ring + (adapter)->xdp_num_queues))
+
 struct ena_irq {
 	irq_handler_t handler;
 	void *data;
@@ -153,6 +137,9 @@
 	struct napi_struct napi ____cacheline_aligned;
 	struct ena_ring *tx_ring;
 	struct ena_ring *rx_ring;
+	struct ena_ring *xdp_ring;
+	bool first_interrupt;
+	bool interrupts_masked;
 	u32 qid;
 	struct dim dim;
 };
@@ -161,10 +148,10 @@
 	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;
+	u32 tx_queue_size;
+	u32 rx_queue_size;
+	u32 max_tx_queue_size;
+	u32 max_rx_queue_size;
 	u16 max_tx_sgl_size;
 	u16 max_rx_sgl_size;
 };
@@ -178,6 +165,17 @@
 	/* num of buffers used by this skb */
 	u32 num_of_bufs;
 
+	/* XDP buffer structure which is used for sending packets in
+	 * the xdp queues
+	 */
+	struct xdp_frame *xdpf;
+	/* The rx page for the rx buffer that was received in rx and
+	 * re transmitted on xdp tx queues as a result of XDP_TX action.
+	 * We need to free the page once we finished cleaning the buffer in
+	 * clean_xdp_irq()
+	 */
+	struct page *xdp_rx_page;
+
 	/* Indicate if bufs[0] map the linear data of the skb. */
 	u8 map_linear_data;
 
@@ -218,6 +216,7 @@
 	u64 bad_req_id;
 	u64 llq_buffer_copy;
 	u64 missed_tx;
+	u64 unmask_interrupt;
 };
 
 struct ena_stats_rx {
@@ -234,6 +233,11 @@
 	u64 bad_req_id;
 	u64 empty_rx_ring;
 	u64 csum_unchecked;
+	u64 xdp_aborted;
+	u64 xdp_drop;
+	u64 xdp_pass;
+	u64 xdp_tx;
+	u64 xdp_invalid;
 };
 
 struct ena_ring {
@@ -256,10 +260,13 @@
 	struct ena_adapter *adapter;
 	struct ena_com_io_cq *ena_com_io_cq;
 	struct ena_com_io_sq *ena_com_io_sq;
+	struct bpf_prog *xdp_bpf_prog;
+	struct xdp_rxq_info xdp_rxq;
 
 	u16 next_to_use;
 	u16 next_to_clean;
 	u16 rx_copybreak;
+	u16 rx_headroom;
 	u16 qid;
 	u16 mtu;
 	u16 sgl_size;
@@ -268,6 +275,7 @@
 	u8 tx_max_header_size;
 
 	bool first_interrupt;
+	bool disable_meta_caching;
 	u16 no_interrupt_event_cnt;
 
 	/* cpu for TPH */
@@ -300,6 +308,7 @@
 	u64 interface_down;
 	u64 admin_q_pause;
 	u64 rx_drops;
+	u64 tx_drops;
 };
 
 enum ena_flags_t {
@@ -324,7 +333,8 @@
 	u32 rx_copybreak;
 	u32 max_mtu;
 
-	int num_queues;
+	u32 num_io_queues;
+	u32 max_num_io_queues;
 
 	int msix_vecs;
 
@@ -367,15 +377,22 @@
 
 	bool wd_state;
 	bool dev_up_before_reset;
+	bool disable_meta_caching;
 	unsigned long last_keep_alive_jiffies;
 
 	struct u64_stats_sync syncp;
 	struct ena_stats_dev dev_stats;
+	struct ena_admin_eni_stats eni_stats;
+	bool eni_stats_supported;
 
 	/* last queue index that was checked for uncompleted tx packets */
 	u32 last_monitored_tx_qid;
 
 	enum ena_regs_reset_reason_types reset_reason;
+
+	struct bpf_prog *xdp_bpf_prog;
+	u32 xdp_first_ring;
+	u32 xdp_num_queues;
 };
 
 void ena_set_ethtool_ops(struct net_device *netdev);
@@ -384,10 +401,53 @@
 
 void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf);
 
+int ena_update_hw_stats(struct ena_adapter *adapter);
+
 int ena_update_queue_sizes(struct ena_adapter *adapter,
 			   u32 new_tx_size,
 			   u32 new_rx_size);
 
+int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count);
+
 int ena_get_sset_count(struct net_device *netdev, int sset);
 
+enum ena_xdp_errors_t {
+	ENA_XDP_ALLOWED = 0,
+	ENA_XDP_CURRENT_MTU_TOO_LARGE,
+	ENA_XDP_NO_ENOUGH_QUEUES,
+};
+
+static inline bool ena_xdp_queues_present(struct ena_adapter *adapter)
+{
+	return adapter->xdp_first_ring != 0;
+}
+
+static inline bool ena_xdp_present(struct ena_adapter *adapter)
+{
+	return !!adapter->xdp_bpf_prog;
+}
+
+static inline bool ena_xdp_present_ring(struct ena_ring *ring)
+{
+	return !!ring->xdp_bpf_prog;
+}
+
+static inline int ena_xdp_legal_queue_count(struct ena_adapter *adapter,
+					    u32 queues)
+{
+	return 2 * queues <= adapter->max_num_io_queues;
+}
+
+static inline enum ena_xdp_errors_t ena_xdp_allowed(struct ena_adapter *adapter)
+{
+	enum ena_xdp_errors_t rc = ENA_XDP_ALLOWED;
+
+	if (adapter->netdev->mtu > ENA_XDP_MAX_MTU)
+		rc = ENA_XDP_CURRENT_MTU_TOO_LARGE;
+	else if (!ena_xdp_legal_queue_count(adapter, adapter->num_io_queues))
+		rc = ENA_XDP_NO_ENOUGH_QUEUES;
+
+	return rc;
+}
+
 #endif /* !(ENA_H) */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_pci_id_tbl.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_pci_id_tbl.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 
 #ifndef ENA_PCI_ID_TBL_H_
@@ -53,10 +26,15 @@
 #define PCI_DEV_ID_ENA_LLQ_VF	0xec21
 #endif
 
+#ifndef PCI_DEV_ID_ENA_RESRV0
+#define PCI_DEV_ID_ENA_RESRV0	0x0051
+#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_RESRV0)
 	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)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
@@ -1,33 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
 /*
- * 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.
+ * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
  */
 #ifndef _ENA_REGS_H_
 #define _ENA_REGS_H_
@@ -154,4 +127,4 @@
 #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_ */
+#endif /* _ENA_REGS_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/atarilance.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/atarilance.c
@@ -825,7 +825,7 @@
 	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
 	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
 	dev->stats.tx_bytes += skb->len;
-	dev_kfree_skb( skb );
+	dev_consume_skb_irq(skb);
 	lp->cur_tx++;
 	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
 		lp->cur_tx -= TX_RING_SIZE;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/lance.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/lance.c
@@ -997,7 +997,7 @@
 		skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len);
 		lp->tx_ring[entry].base =
 			((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
-		dev_kfree_skb(skb);
+		dev_consume_skb_irq(skb);
 	} else {
 		lp->tx_skbuff[entry] = skb;
 		lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/nmclan_cs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/nmclan_cs.c
@@ -652,7 +652,7 @@
     } else {
       pr_notice("mace id not found: %x %x should be 0x40 0x?9\n",
 		sig[0], sig[1]);
-      return -ENODEV;
+      goto failed;
     }
   }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/pcnet32.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/pcnet32.c
@@ -1548,8 +1548,7 @@
 	}
 	pci_set_master(pdev);
 
-	ioaddr = pci_resource_start(pdev, 0);
-	if (!ioaddr) {
+	if (!pci_resource_len(pdev, 0)) {
 		if (pcnet32_debug & NETIF_MSG_PROBE)
 			pr_err("card has no PCI IO resources, aborting\n");
 		err = -ENODEV;
@@ -1562,6 +1561,8 @@
 			pr_err("architecture does not support 32bit PCI busmaster DMA\n");
 		goto err_disable_dev;
 	}
+
+	ioaddr = pci_resource_start(pdev, 0);
 	if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) {
 		if (pcnet32_debug & NETIF_MSG_PROBE)
 			pr_err("io address range already allocated\n");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -1279,10 +1279,18 @@
 #define MDIO_PMA_10GBR_FECCTRL		0x00ab
 #endif
 
+#ifndef MDIO_PMA_RX_CTRL1
+#define MDIO_PMA_RX_CTRL1		0x8051
+#endif
+
 #ifndef MDIO_PCS_DIG_CTRL
 #define MDIO_PCS_DIG_CTRL		0x8000
 #endif
 
+#ifndef MDIO_PCS_DIGITAL_STAT
+#define MDIO_PCS_DIGITAL_STAT		0x8010
+#endif
+
 #ifndef MDIO_AN_XNP
 #define MDIO_AN_XNP			0x0016
 #endif
@@ -1323,6 +1331,10 @@
 #define MDIO_VEND2_PMA_CDR_CONTROL	0x8056
 #endif
 
+#ifndef MDIO_VEND2_PMA_MISC_CTRL0
+#define MDIO_VEND2_PMA_MISC_CTRL0	0x8090
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G		(MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
@@ -1358,6 +1370,8 @@
 #define XGBE_KR_TRAINING_ENABLE		BIT(1)
 
 #define XGBE_PCS_CL37_BP		BIT(12)
+#define XGBE_PCS_PSEQ_STATE_MASK	0x1c
+#define XGBE_PCS_PSEQ_STATE_POWER_GOOD	0x10
 
 #define XGBE_AN_CL37_INT_CMPLT		BIT(0)
 #define XGBE_AN_CL37_INT_MASK		0x01
@@ -1375,6 +1389,14 @@
 #define XGBE_PMA_CDR_TRACK_EN_OFF	0x00
 #define XGBE_PMA_CDR_TRACK_EN_ON	0x01
 
+#define XGBE_PMA_RX_RST_0_MASK		BIT(4)
+#define XGBE_PMA_RX_RST_0_RESET_ON	0x10
+#define XGBE_PMA_RX_RST_0_RESET_OFF	0x00
+
+#define XGBE_PMA_PLL_CTRL_MASK		BIT(15)
+#define XGBE_PMA_PLL_CTRL_ENABLE	BIT(15)
+#define XGBE_PMA_PLL_CTRL_DISABLE	0x0000
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -524,19 +524,28 @@
 	netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n");
 }
 
+static unsigned int xgbe_get_fc_queue_count(struct xgbe_prv_data *pdata)
+{
+	unsigned int max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
+
+	/* From MAC ver 30H the TFCR is per priority, instead of per queue */
+	if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) >= 0x30)
+		return max_q_count;
+	else
+		return min_t(unsigned int, pdata->tx_q_count, max_q_count);
+}
+
 static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
 {
-	unsigned int max_q_count, q_count;
 	unsigned int reg, reg_val;
-	unsigned int i;
+	unsigned int i, q_count;
 
 	/* Clear MTL flow control */
 	for (i = 0; i < pdata->rx_q_count; i++)
 		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0);
 
 	/* Clear MAC flow control */
-	max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-	q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
+	q_count = xgbe_get_fc_queue_count(pdata);
 	reg = MAC_Q0TFCR;
 	for (i = 0; i < q_count; i++) {
 		reg_val = XGMAC_IOREAD(pdata, reg);
@@ -553,9 +562,8 @@
 {
 	struct ieee_pfc *pfc = pdata->pfc;
 	struct ieee_ets *ets = pdata->ets;
-	unsigned int max_q_count, q_count;
 	unsigned int reg, reg_val;
-	unsigned int i;
+	unsigned int i, q_count;
 
 	/* Set MTL flow control */
 	for (i = 0; i < pdata->rx_q_count; i++) {
@@ -579,8 +587,7 @@
 	}
 
 	/* Set MAC flow control */
-	max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-	q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
+	q_count = xgbe_get_fc_queue_count(pdata);
 	reg = MAC_Q0TFCR;
 	for (i = 0; i < q_count; i++) {
 		reg_val = XGMAC_IOREAD(pdata, reg);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -514,7 +514,7 @@
 				xgbe_disable_rx_tx_ints(pdata);
 
 				/* Turn on polling */
-				__napi_schedule_irqoff(&pdata->napi);
+				__napi_schedule(&pdata->napi);
 			}
 		} else {
 			/* Don't clear Rx/Tx status if doing per channel DMA
@@ -682,10 +682,24 @@
 static void xgbe_service_timer(struct timer_list *t)
 {
 	struct xgbe_prv_data *pdata = from_timer(pdata, t, service_timer);
+	struct xgbe_channel *channel;
+	unsigned int i;
 
 	queue_work(pdata->dev_workqueue, &pdata->service_work);
 
 	mod_timer(&pdata->service_timer, jiffies + HZ);
+
+	if (!pdata->tx_usecs)
+		return;
+
+	for (i = 0; i < pdata->channel_count; i++) {
+		channel = pdata->channel[i];
+		if (!channel->tx_ring || channel->tx_timer_active)
+			break;
+		channel->tx_timer_active = 1;
+		mod_timer(&channel->tx_timer,
+			  jiffies + usecs_to_jiffies(pdata->tx_usecs));
+	}
 }
 
 static void xgbe_init_timers(struct xgbe_prv_data *pdata)
@@ -721,7 +735,9 @@
 		if (!channel->tx_ring)
 			break;
 
+		/* Deactivate the Tx timer */
 		del_timer_sync(&channel->tx_timer);
+		channel->tx_timer_active = 0;
 	}
 }
 
@@ -1137,6 +1153,9 @@
 
 	devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
 
+	tasklet_kill(&pdata->tasklet_dev);
+	tasklet_kill(&pdata->tasklet_ecc);
+
 	if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq))
 		devm_free_irq(pdata->dev, pdata->ecc_irq, pdata);
 
@@ -1443,6 +1462,7 @@
 		return;
 
 	netif_tx_stop_all_queues(netdev);
+	netif_carrier_off(pdata->netdev);
 
 	xgbe_stop_timers(pdata);
 	flush_workqueue(pdata->dev_workqueue);
@@ -2764,6 +2784,14 @@
 			buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
 			len += buf2_len;
 
+			if (buf2_len > rdata->rx.buf.dma_len) {
+				/* Hardware inconsistency within the descriptors
+				 * that has resulted in a length underflow.
+				 */
+				error = 1;
+				goto skip_data;
+			}
+
 			if (!skb) {
 				skb = xgbe_create_skb(pdata, napi, rdata,
 						      buf1_len);
@@ -2793,8 +2821,10 @@
 		if (!last || context_next)
 			goto read_again;
 
-		if (!skb)
+		if (!skb || error) {
+			dev_kfree_skb(skb);
 			goto next_packet;
+		}
 
 		/* Be sure we don't exceed the configured MTU */
 		max_len = netdev->mtu + ETH_HLEN;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -314,10 +314,15 @@
 
 	cmd->base.phy_address = pdata->phy.address;
 
-	cmd->base.autoneg = pdata->phy.autoneg;
-	cmd->base.speed = pdata->phy.speed;
-	cmd->base.duplex = pdata->phy.duplex;
+	if (netif_carrier_ok(netdev)) {
+		cmd->base.speed = pdata->phy.speed;
+		cmd->base.duplex = pdata->phy.duplex;
+	} else {
+		cmd->base.speed = SPEED_UNKNOWN;
+		cmd->base.duplex = DUPLEX_UNKNOWN;
+	}
 
+	cmd->base.autoneg = pdata->phy.autoneg;
 	cmd->base.port = PORT_NONE;
 
 	XGBE_LM_COPY(cmd, supported, lks, supported);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
@@ -447,8 +447,10 @@
 	xgbe_i2c_disable(pdata);
 	xgbe_i2c_clear_all_interrupts(pdata);
 
-	if (pdata->dev_irq != pdata->i2c_irq)
+	if (pdata->dev_irq != pdata->i2c_irq) {
 		devm_free_irq(pdata->dev, pdata->i2c_irq, pdata);
+		tasklet_kill(&pdata->tasklet_i2c);
+	}
 }
 
 static int xgbe_i2c_start(struct xgbe_prv_data *pdata)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -496,6 +496,7 @@
 	reg |= XGBE_KR_TRAINING_ENABLE;
 	reg |= XGBE_KR_TRAINING_START;
 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+	pdata->kr_start_time = jiffies;
 
 	netif_dbg(pdata, link, pdata->netdev,
 		  "KR training initiated\n");
@@ -632,6 +633,8 @@
 
 	xgbe_switch_mode(pdata);
 
+	pdata->an_result = XGBE_AN_READY;
+
 	xgbe_an_restart(pdata);
 
 	return XGBE_AN_INCOMPAT_LINK;
@@ -1175,7 +1178,19 @@
 	if (pdata->phy.duplex != DUPLEX_FULL)
 		return -EINVAL;
 
-	xgbe_set_mode(pdata, mode);
+	/* Force the mode change for SFI in Fixed PHY config.
+	 * Fixed PHY configs needs PLL to be enabled while doing mode set.
+	 * When the SFP module isn't connected during boot, driver assumes
+	 * AN is ON and attempts autonegotiation. However, if the connected
+	 * SFP comes up in Fixed PHY config, the link will not come up as
+	 * PLL isn't enabled while the initial mode set command is issued.
+	 * So, force the mode change for SFI in Fixed PHY configuration to
+	 * fix link issues.
+	 */
+	if (mode == XGBE_MODE_SFI)
+		xgbe_change_mode(pdata, mode);
+	else
+		xgbe_set_mode(pdata, mode);
 
 	return 0;
 }
@@ -1275,9 +1290,30 @@
 static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
 {
 	unsigned long link_timeout;
+	unsigned long kr_time;
+	int wait;
 
 	link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
 	if (time_after(jiffies, link_timeout)) {
+		if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) &&
+		    pdata->phy.autoneg == AUTONEG_ENABLE) {
+			/* AN restart should not happen while KR training is in progress.
+			 * The while loop ensures no AN restart during KR training,
+			 * waits up to 500ms and AN restart is triggered only if KR
+			 * training is failed.
+			 */
+			wait = XGBE_KR_TRAINING_WAIT_ITER;
+			while (wait--) {
+				kr_time = pdata->kr_start_time +
+					  msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
+				if (time_after(jiffies, kr_time))
+					break;
+				/* AN restart is not required, if AN result is COMPLETE */
+				if (pdata->an_result == XGBE_AN_COMPLETE)
+					return;
+				usleep_range(10000, 11000);
+			}
+		}
 		netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
 		xgbe_phy_config_aneg(pdata);
 	}
@@ -1288,7 +1324,7 @@
 	return pdata->phy_if.phy_impl.an_outcome(pdata);
 }
 
-static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
+static bool xgbe_phy_status_result(struct xgbe_prv_data *pdata)
 {
 	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
 	enum xgbe_mode mode;
@@ -1323,8 +1359,13 @@
 
 	pdata->phy.duplex = DUPLEX_FULL;
 
-	if (xgbe_set_mode(pdata, mode) && pdata->an_again)
+	if (!xgbe_set_mode(pdata, mode))
+		return false;
+
+	if (pdata->an_again)
 		xgbe_phy_reconfig_aneg(pdata);
+
+	return true;
 }
 
 static void xgbe_phy_status(struct xgbe_prv_data *pdata)
@@ -1345,7 +1386,7 @@
 							     &an_restart);
 	if (an_restart) {
 		xgbe_phy_config_aneg(pdata);
-		return;
+		goto adjust_link;
 	}
 
 	if (pdata->phy.link) {
@@ -1354,7 +1395,8 @@
 			return;
 		}
 
-		xgbe_phy_status_result(pdata);
+		if (xgbe_phy_status_result(pdata))
+			return;
 
 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
 			clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
@@ -1390,13 +1432,14 @@
 	/* Disable auto-negotiation */
 	xgbe_an_disable_all(pdata);
 
-	if (pdata->dev_irq != pdata->an_irq)
+	if (pdata->dev_irq != pdata->an_irq) {
 		devm_free_irq(pdata->dev, pdata->an_irq, pdata);
+		tasklet_kill(&pdata->tasklet_an);
+	}
 
 	pdata->phy_if.phy_impl.stop(pdata);
 
 	pdata->phy.link = 0;
-	netif_carrier_off(pdata->netdev);
 
 	xgbe_phy_adjust_link(pdata);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-pci.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-pci.c
@@ -418,6 +418,9 @@
 
 	pci_free_irq_vectors(pdata->pcidev);
 
+	/* Disable all interrupts in the hardware */
+	XP_IOWRITE(pdata, XP_INT_EN, 0x0);
+
 	xgbe_free_pdata(pdata);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -188,6 +188,7 @@
 	XGBE_SFP_CABLE_UNKNOWN = 0,
 	XGBE_SFP_CABLE_ACTIVE,
 	XGBE_SFP_CABLE_PASSIVE,
+	XGBE_SFP_CABLE_FIBER,
 };
 
 enum xgbe_sfp_base {
@@ -235,9 +236,7 @@
 
 #define XGBE_SFP_BASE_BR			12
 #define XGBE_SFP_BASE_BR_1GBE_MIN		0x0a
-#define XGBE_SFP_BASE_BR_1GBE_MAX		0x0d
 #define XGBE_SFP_BASE_BR_10GBE_MIN		0x64
-#define XGBE_SFP_BASE_BR_10GBE_MAX		0x68
 
 #define XGBE_SFP_BASE_CU_CABLE_LEN		18
 
@@ -283,6 +282,8 @@
 #define XGBE_BEL_FUSE_VENDOR	"BEL-FUSE        "
 #define XGBE_BEL_FUSE_PARTNO	"1GBT-SFP06      "
 
+#define XGBE_MOLEX_VENDOR	"Molex Inc.      "
+
 struct xgbe_sfp_ascii {
 	union {
 		char vendor[XGBE_SFP_BASE_VENDOR_NAME_LEN + 1];
@@ -822,25 +823,22 @@
 static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
 				  enum xgbe_sfp_speed sfp_speed)
 {
-	u8 *sfp_base, min, max;
+	u8 *sfp_base, min;
 
 	sfp_base = sfp_eeprom->base;
 
 	switch (sfp_speed) {
 	case XGBE_SFP_SPEED_1000:
 		min = XGBE_SFP_BASE_BR_1GBE_MIN;
-		max = XGBE_SFP_BASE_BR_1GBE_MAX;
 		break;
 	case XGBE_SFP_SPEED_10000:
 		min = XGBE_SFP_BASE_BR_10GBE_MIN;
-		max = XGBE_SFP_BASE_BR_10GBE_MAX;
 		break;
 	default:
 		return false;
 	}
 
-	return ((sfp_base[XGBE_SFP_BASE_BR] >= min) &&
-		(sfp_base[XGBE_SFP_BASE_BR] <= max));
+	return sfp_base[XGBE_SFP_BASE_BR] >= min;
 }
 
 static void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata)
@@ -921,6 +919,9 @@
 	if ((phy_id & 0xfffffff0) != 0x03625d10)
 		return false;
 
+	/* Reset PHY - wait for self-clearing reset bit to clear */
+	genphy_soft_reset(phy_data->phydev);
+
 	/* Disable RGMII mode */
 	phy_write(phy_data->phydev, 0x18, 0x7007);
 	reg = phy_read(phy_data->phydev, 0x18);
@@ -1138,16 +1139,21 @@
 	phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
 	phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
 
-	/* Assume ACTIVE cable unless told it is PASSIVE */
+	/* Assume FIBER cable unless told otherwise */
 	if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
 		phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
 		phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN];
-	} else {
+	} else if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_ACTIVE) {
 		phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
+	} else {
+		phy_data->sfp_cable = XGBE_SFP_CABLE_FIBER;
 	}
 
 	/* Determine the type of SFP */
-	if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR)
+	if (phy_data->sfp_cable != XGBE_SFP_CABLE_FIBER &&
+	    xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000))
+		phy_data->sfp_base = XGBE_SFP_BASE_10000_CR;
+	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR)
 		phy_data->sfp_base = XGBE_SFP_BASE_10000_SR;
 	else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR)
 		phy_data->sfp_base = XGBE_SFP_BASE_10000_LR;
@@ -1163,9 +1169,6 @@
 		phy_data->sfp_base = XGBE_SFP_BASE_1000_CX;
 	else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T)
 		phy_data->sfp_base = XGBE_SFP_BASE_1000_T;
-	else if ((phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE) &&
-		 xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000))
-		phy_data->sfp_base = XGBE_SFP_BASE_10000_CR;
 
 	switch (phy_data->sfp_base) {
 	case XGBE_SFP_BASE_1000_T:
@@ -1948,16 +1951,53 @@
 	xgbe_phy_put_comm_ownership(pdata);
 }
 
+static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
+{
+	int reg;
+
+	reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT,
+			      XGBE_PCS_PSEQ_STATE_MASK);
+	if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) {
+		/* Mailbox command timed out, reset of RX block is required.
+		 * This can be done by asseting the reset bit and wait for
+		 * its compeletion.
+		 */
+		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+				 XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON);
+		ndelay(20);
+		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+				 XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF);
+		usleep_range(40, 50);
+		netif_err(pdata, link, pdata->netdev, "firmware mailbox reset performed\n");
+	}
+}
+
+static void xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable)
+{
+	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0,
+			 XGBE_PMA_PLL_CTRL_MASK,
+			 enable ? XGBE_PMA_PLL_CTRL_ENABLE
+				: XGBE_PMA_PLL_CTRL_DISABLE);
+
+	/* Wait for command to complete */
+	usleep_range(100, 200);
+}
+
 static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
 					unsigned int cmd, unsigned int sub_cmd)
 {
 	unsigned int s0 = 0;
 	unsigned int wait;
 
+	/* Disable PLL re-initialization during FW command processing */
+	xgbe_phy_pll_ctrl(pdata, false);
+
 	/* Log if a previous command did not complete */
-	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
+	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
 		netif_dbg(pdata, link, pdata->netdev,
 			  "firmware mailbox not ready for command\n");
+		xgbe_phy_rx_reset(pdata);
+	}
 
 	/* Construct the command */
 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd);
@@ -1972,13 +2012,20 @@
 	wait = XGBE_RATECHANGE_COUNT;
 	while (wait--) {
 		if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
-			return;
+			goto reenable_pll;
 
 		usleep_range(1000, 2000);
 	}
 
 	netif_dbg(pdata, link, pdata->netdev,
 		  "firmware mailbox command did not complete\n");
+
+	/* Reset on error */
+	xgbe_phy_rx_reset(pdata);
+
+reenable_pll:
+	/* Enable PLL re-initialization */
+	xgbe_phy_pll_ctrl(pdata, true);
 }
 
 static void xgbe_phy_rrc(struct xgbe_prv_data *pdata)
@@ -2575,6 +2622,14 @@
 	if (reg & MDIO_STAT1_LSTATUS)
 		return 1;
 
+	if (pdata->phy.autoneg == AUTONEG_ENABLE &&
+	    phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) {
+		if (!test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
+			netif_carrier_off(pdata->netdev);
+			*an_restart = 1;
+		}
+	}
+
 	/* No link, attempt a receiver reset cycle */
 	if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
 		phy_data->rrc_count = 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ linux-ein-5.4.0/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -181,9 +181,9 @@
 #define XGBE_DMA_SYS_AWCR	0x30303030
 
 /* DMA cache settings - PCI device */
-#define XGBE_DMA_PCI_ARCR	0x00000003
-#define XGBE_DMA_PCI_AWCR	0x13131313
-#define XGBE_DMA_PCI_AWARCR	0x00000313
+#define XGBE_DMA_PCI_ARCR	0x000f0f0f
+#define XGBE_DMA_PCI_AWCR	0x0f0f0f0f
+#define XGBE_DMA_PCI_AWARCR	0x00000f0f
 
 /* DMA channel interrupt modes */
 #define XGBE_IRQ_MODE_EDGE	0
@@ -290,6 +290,7 @@
 /* Auto-negotiation */
 #define XGBE_AN_MS_TIMEOUT		500
 #define XGBE_LINK_TIMEOUT		5
+#define XGBE_KR_TRAINING_WAIT_ITER	50
 
 #define XGBE_SGMII_AN_LINK_STATUS	BIT(1)
 #define XGBE_SGMII_AN_LINK_SPEED	(BIT(2) | BIT(3))
@@ -1266,6 +1267,7 @@
 	unsigned int parallel_detect;
 	unsigned int fec_ability;
 	unsigned long an_start;
+	unsigned long kr_start_time;
 	enum xgbe_an_mode an_mode;
 
 	/* I2C support */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/apm/xgene-v2/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/apm/xgene-v2/main.c
@@ -677,11 +677,13 @@
 	ret = register_netdev(ndev);
 	if (ret) {
 		netdev_err(ndev, "Failed to register netdev\n");
-		goto err;
+		goto err_mdio_remove;
 	}
 
 	return 0;
 
+err_mdio_remove:
+	xge_mdio_remove(ndev);
 err:
 	free_netdev(ndev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -696,6 +696,12 @@
 	buf_pool->rx_skb[skb_index] = NULL;
 
 	datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1));
+
+	/* strip off CRC as HW isn't doing this */
+	nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0));
+	if (!nv)
+		datalen -= 4;
+
 	skb_put(skb, datalen);
 	prefetch(skb->data - NET_IP_ALIGN);
 	skb->protocol = eth_type_trans(skb, ndev);
@@ -717,12 +723,8 @@
 		}
 	}
 
-	nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0));
-	if (!nv) {
-		/* strip off CRC as HW isn't doing this */
-		datalen -= 4;
+	if (!nv)
 		goto skip_jumbo;
-	}
 
 	slots = page_pool->slots - 1;
 	head = page_pool->head;
@@ -1002,8 +1004,10 @@
 
 	xgene_enet_napi_enable(pdata);
 	ret = xgene_enet_register_irq(ndev);
-	if (ret)
+	if (ret) {
+		xgene_enet_napi_disable(pdata);
 		return ret;
+	}
 
 	if (ndev->phydev) {
 		phy_start(ndev->phydev);
@@ -2020,7 +2024,7 @@
 	int ret;
 
 	ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdata),
-				  XGENE_NUM_RX_RING, XGENE_NUM_TX_RING);
+				  XGENE_NUM_TX_RING, XGENE_NUM_RX_RING);
 	if (!ndev)
 		return -ENOMEM;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -18,6 +18,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_net.h>
 #include <linux/of_mdio.h>
+#include <linux/mdio/mdio-xgene.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <linux/prefetch.h>
@@ -26,7 +27,6 @@
 #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 ETHER_MIN_PACKET	64
--- linux-ein-5.4.0.orig/drivers/net/ethernet/apple/bmac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/apple/bmac.c
@@ -1182,7 +1182,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);
@@ -1511,7 +1511,7 @@
 	i = bp->tx_empty;
 	++dev->stats.tx_errors;
 	if (i != bp->tx_fill) {
-		dev_kfree_skb(bp->tx_bufs[i]);
+		dev_kfree_skb_irq(bp->tx_bufs[i]);
 		bp->tx_bufs[i] = NULL;
 		if (++i >= N_TX_RING) i = 0;
 		bp->tx_empty = i;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/apple/mace.c
+++ linux-ein-5.4.0/drivers/net/ethernet/apple/mace.c
@@ -841,7 +841,7 @@
     if (mp->tx_bad_runt) {
 	mp->tx_bad_runt = 0;
     } else if (i != mp->tx_fill) {
-	dev_kfree_skb(mp->tx_bufs[i]);
+	dev_kfree_skb_irq(mp->tx_bufs[i]);
 	if (++i >= N_TX_RING)
 	    i = 0;
 	mp->tx_empty = i;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -158,7 +158,7 @@
 	}
 
 	if ((aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
-	    (!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci),
+	    (!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK,
 		       aq_nic->active_vlans))) {
 		netdev_err(aq_nic->ndev,
 			   "ethtool: unknown vlan-id specified");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -230,7 +230,7 @@
 
 	struct aq_stats_s *(*hw_get_hw_stats)(struct aq_hw_s *self);
 
-	int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
+	u32 (*hw_get_fw_version)(struct aq_hw_s *self);
 
 	int (*hw_set_offload)(struct aq_hw_s *self,
 			      struct aq_nic_cfg_s *aq_nic_cfg);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -66,8 +66,10 @@
 		goto err_exit;
 
 	err = aq_nic_start(aq_nic);
-	if (err < 0)
+	if (err < 0) {
+		aq_nic_stop(aq_nic);
 		goto err_exit;
+	}
 
 err_exit:
 	if (err < 0)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -467,8 +467,10 @@
 				     dx_buff->len,
 				     DMA_TO_DEVICE);
 
-	if (unlikely(dma_mapping_error(aq_nic_get_dev(self), dx_buff->pa)))
+	if (unlikely(dma_mapping_error(aq_nic_get_dev(self), dx_buff->pa))) {
+		ret = 0;
 		goto exit;
+	}
 
 	first = dx_buff;
 	dx_buff->len_pkt = skb->len;
@@ -598,10 +600,6 @@
 	if (likely(frags)) {
 		err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw,
 						       ring, frags);
-		if (err >= 0) {
-			++ring->stats.tx.packets;
-			ring->stats.tx.bytes += skb->len;
-		}
 	} else {
 		err = NETDEV_TX_BUSY;
 	}
@@ -692,6 +690,9 @@
 	u32 *regs_buff = p;
 	int err = 0;
 
+	if (unlikely(!self->aq_hw_ops->hw_get_regs))
+		return -EOPNOTSUPP;
+
 	regs->version = 1;
 
 	err = self->aq_hw_ops->hw_get_regs(self->aq_hw,
@@ -706,6 +707,9 @@
 
 int aq_nic_get_regs_count(struct aq_nic_s *self)
 {
+	if (unlikely(!self->aq_hw_ops->hw_get_regs))
+		return 0;
+
 	return self->aq_nic_cfg.aq_hw_caps->mac_regs_count;
 }
 
@@ -899,7 +903,6 @@
 		default:
 			err = -1;
 			goto err_exit;
-		break;
 		}
 		if (!(self->aq_nic_cfg.aq_hw_caps->link_speed_msk & rate)) {
 			err = -1;
@@ -928,11 +931,7 @@
 
 u32 aq_nic_get_fw_version(struct aq_nic_s *self)
 {
-	u32 fw_version = 0U;
-
-	self->aq_hw_ops->hw_get_fw_version(self->aq_hw, &fw_version);
-
-	return fw_version;
+	return self->aq_hw_ops->hw_get_fw_version(self->aq_hw);
 }
 
 int aq_nic_stop(struct aq_nic_s *self)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -56,7 +56,7 @@
 	{ AQ_DEVICE_ID_D108,	AQ_HWREV_2,	&hw_atl_ops_b0, &hw_atl_b0_caps_aqc108, },
 	{ AQ_DEVICE_ID_D109,	AQ_HWREV_2,	&hw_atl_ops_b0, &hw_atl_b0_caps_aqc109, },
 
-	{ AQ_DEVICE_ID_AQC100,	AQ_HWREV_ANY,	&hw_atl_ops_b1, &hw_atl_b0_caps_aqc107, },
+	{ AQ_DEVICE_ID_AQC100,	AQ_HWREV_ANY,	&hw_atl_ops_b1, &hw_atl_b0_caps_aqc100, },
 	{ AQ_DEVICE_ID_AQC107,	AQ_HWREV_ANY,	&hw_atl_ops_b1, &hw_atl_b0_caps_aqc107, },
 	{ AQ_DEVICE_ID_AQC108,	AQ_HWREV_ANY,	&hw_atl_ops_b1, &hw_atl_b0_caps_aqc108, },
 	{ AQ_DEVICE_ID_AQC109,	AQ_HWREV_ANY,	&hw_atl_ops_b1, &hw_atl_b0_caps_aqc109, },
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -243,9 +243,12 @@
 			}
 		}
 
-		if (unlikely(buff->is_eop))
-			dev_kfree_skb_any(buff->skb);
+		if (unlikely(buff->is_eop)) {
+			++self->stats.rx.packets;
+			self->stats.tx.bytes += buff->skb->len;
 
+			dev_kfree_skb_any(buff->skb);
+		}
 		buff->pa = 0U;
 		buff->eop_index = 0xffffU;
 		self->sw_head = aq_ring_next_dx(self, self->sw_head);
@@ -302,6 +305,10 @@
 		if (!buff->is_eop) {
 			buff_ = buff;
 			do {
+				if (buff_->next >= self->size) {
+					err = -EIO;
+					goto err_exit;
+				}
 				next_ = buff_->next,
 				buff_ = &self->buff_ring[next_];
 				is_rsc_completed =
@@ -324,6 +331,10 @@
 			if (buff->is_error || buff->is_cso_err) {
 				buff_ = buff;
 				do {
+					if (buff_->next >= self->size) {
+						err = -EIO;
+						goto err_exit;
+					}
 					next_ = buff_->next,
 					buff_ = &self->buff_ring[next_];
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -776,7 +776,7 @@
 	int err = 0;
 
 	if (count > (HW_ATL_A0_MAC_MAX - HW_ATL_A0_MAC_MIN)) {
-		err = EBADRQC;
+		err = -EBADRQC;
 		goto err_exit;
 	}
 	for (self->aq_nic_cfg->mc_list_count = 0U;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -674,6 +674,13 @@
 		err = -ENXIO;
 		goto err_exit;
 	}
+
+	/* Validate that the new hw_head_ is reasonable. */
+	if (hw_head_ >= ring->size) {
+		err = -ENXIO;
+		goto err_exit;
+	}
+
 	ring->hw_head = hw_head_;
 	err = aq_hw_err_from_flags(self);
 
@@ -1097,7 +1104,7 @@
 	return aq_hw_err_from_flags(self);
 }
 
-/**
+/*
  * @brief Set VLAN filter table
  * @details Configure VLAN filter table to accept (and assign the queue) traffic
  *  for the particular vlan ids.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1597,7 +1597,7 @@
 	for (i = 0; i < 4; ++i)
 		aq_hw_write_reg(aq_hw,
 				HW_ATL_RPF_L3_SRCA_ADR(location + i),
-				ipv6_src[i]);
+				ipv6_src[3 - i]);
 }
 
 void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
@@ -1608,7 +1608,7 @@
 	for (i = 0; i < 4; ++i)
 		aq_hw_write_reg(aq_hw,
 				HW_ATL_RPF_L3_DSTA_ADR(location + i),
-				ipv6_dest[i]);
+				ipv6_dest[3 - i]);
 }
 
 u32 hw_atl_sem_ram_get(struct aq_hw_s *self)
@@ -1616,6 +1616,16 @@
 	return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
 }
 
+u32 hw_atl_sem_reset1_get(struct aq_hw_s *self)
+{
+	return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RESET1);
+}
+
+u32 hw_atl_sem_reset2_get(struct aq_hw_s *self)
+{
+	return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RESET2);
+}
+
 u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp)
 {
 	return aq_hw_read_reg(aq_hw,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -755,6 +755,9 @@
 /* get global microprocessor ram semaphore */
 u32 hw_atl_sem_ram_get(struct aq_hw_s *self);
 
+u32 hw_atl_sem_reset1_get(struct aq_hw_s *self);
+u32 hw_atl_sem_reset2_get(struct aq_hw_s *self);
+
 /* get global microprocessor scratch pad register */
 u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -2564,7 +2564,7 @@
  */
 
  /* Register address for bitfield pif_rpf_l3_da0_i[31:0] */
-#define HW_ATL_RPF_L3_DSTA_ADR(location) (0x000053B0 + (location) * 0x4)
+#define HW_ATL_RPF_L3_DSTA_ADR(filter) (0x000053D0 + (filter) * 0x4)
 /* Bitmask for bitfield l3_da0[1F:0] */
 #define HW_ATL_RPF_L3_DSTA_MSK 0xFFFFFFFFu
 /* Inverted bitmask for bitfield l3_da0[1F:0] */
@@ -2576,6 +2576,10 @@
 /* Default value of bitfield l3_da0[1F:0] */
 #define HW_ATL_RPF_L3_DSTA_DEFAULT 0x0
 
+#define HW_ATL_MIF_RESET_TIMEOUT_ADR 0x00000348
+
 #define HW_ATL_FW_SM_RAM        0x2U
+#define HW_ATL_FW_SM_RESET1     0x3U
+#define HW_ATL_FW_SM_RESET2     0x4U
 
 #endif /* HW_ATL_LLH_INTERNAL_H */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -22,6 +22,7 @@
 #define HW_ATL_MIF_ADDR         0x0208U
 #define HW_ATL_MIF_VAL          0x020CU
 
+#define HW_ATL_MPI_RPC_ADDR     0x0334U
 #define HW_ATL_RPC_CONTROL_ADR  0x0338U
 #define HW_ATL_RPC_STATE_ADR    0x033CU
 
@@ -44,19 +45,18 @@
 #define HW_ATL_FW_VER_1X 0x01050006U
 #define HW_ATL_FW_VER_2X 0x02000000U
 #define HW_ATL_FW_VER_3X 0x03000000U
+#define HW_ATL_FW_VER_4X 0x04000000U
 
 #define FORCE_FLASHLESS 0
 
-static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
-
 static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
-				      enum hal_atl_utils_fw_state_e state);
-
+		enum hal_atl_utils_fw_state_e state);
 static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self);
 static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self);
 static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self);
 static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self);
 static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self);
+static u32 aq_fw1x_rpc_get(struct aq_hw_s *self);
 
 int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
 {
@@ -67,22 +67,21 @@
 		return err;
 
 	hw_atl_utils_hw_chip_features_init(self,
-					   &self->chip_features);
+			&self->chip_features);
 
-	hw_atl_utils_get_fw_version(self, &self->fw_ver_actual);
+	self->fw_ver_actual = hw_atl_utils_get_fw_version(self);
 
-	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
-				   self->fw_ver_actual) == 0) {
+	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) {
 		*fw_ops = &aq_fw_1x_ops;
-	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
-					  self->fw_ver_actual) == 0) {
+	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) {
+		*fw_ops = &aq_fw_2x_ops;
+	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) {
 		*fw_ops = &aq_fw_2x_ops;
-	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
-					  self->fw_ver_actual) == 0) {
+	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, self->fw_ver_actual)) {
 		*fw_ops = &aq_fw_2x_ops;
 	} else {
 		aq_pr_err("Bad FW version detected: %x\n",
-			  self->fw_ver_actual);
+				self->fw_ver_actual);
 		return -EOPNOTSUPP;
 	}
 	self->aq_fw_ops = *fw_ops;
@@ -121,7 +120,7 @@
 
 	for (k = 0; k < 1000; k++) {
 		u32 flb_status = aq_hw_read_reg(self,
-						HW_ATL_MPI_DAISY_CHAIN_STATUS);
+				HW_ATL_MPI_DAISY_CHAIN_STATUS);
 
 		flb_status = flb_status & 0x10;
 		if (flb_status)
@@ -144,8 +143,8 @@
 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
-			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
-			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
+			BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
+			HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
 
@@ -186,8 +185,8 @@
 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
-			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
-			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
+			BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
+			HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
 			(gsr & 0xFFFFBFFF) | 0x8000);
@@ -238,14 +237,15 @@
 int hw_atl_utils_soft_reset(struct aq_hw_s *self)
 {
 	int k;
+	int ver = hw_atl_utils_get_fw_version(self);
 	u32 boot_exit_code = 0;
 	u32 val;
 
 	for (k = 0; k < 1000; ++k) {
 		u32 flb_status = aq_hw_read_reg(self,
-						HW_ATL_MPI_DAISY_CHAIN_STATUS);
+				HW_ATL_MPI_DAISY_CHAIN_STATUS);
 		boot_exit_code = aq_hw_read_reg(self,
-						HW_ATL_MPI_BOOT_EXIT_CODE);
+				HW_ATL_MPI_BOOT_EXIT_CODE);
 		if (flb_status != 0x06000000 || boot_exit_code != 0)
 			break;
 	}
@@ -257,22 +257,41 @@
 
 	self->rbl_enabled = (boot_exit_code != 0);
 
-	/* FW 1.x may bootup in an invalid POWER state (WOL feature).
-	 * We should work around this by forcing its state back to DEINIT
-	 */
-	if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
-				    aq_hw_read_reg(self,
-						   HW_ATL_MPI_FW_VERSION))) {
+	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, ver)) {
 		int err = 0;
 
+		/* FW 1.x may bootup in an invalid POWER state (WOL feature).
+		 * We should work around this by forcing its state back to DEINIT
+		 */
 		hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
 		err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state,
-						self, val,
-						(val & HW_ATL_MPI_STATE_MSK) ==
-						 MPI_DEINIT,
-						10, 10000U);
+				self, val,
+				(val & HW_ATL_MPI_STATE_MSK) ==
+				MPI_DEINIT,
+				10, 10000U);
 		if (err)
 			return err;
+	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, ver)) {
+		u64 sem_timeout = aq_hw_read_reg(self, HW_ATL_MIF_RESET_TIMEOUT_ADR);
+
+		/* Acquire 2 semaphores before issuing reset for FW 4.x */
+		if (sem_timeout > 3000)
+			sem_timeout = 3000;
+		sem_timeout = sem_timeout * 1000;
+
+		if (sem_timeout != 0) {
+			int err;
+
+			err = readx_poll_timeout_atomic(hw_atl_sem_reset1_get, self, val,
+							val == 1U, 1U, sem_timeout);
+			if (err)
+				aq_pr_err("reset sema1 timeout");
+
+			err = readx_poll_timeout_atomic(hw_atl_sem_reset2_get, self, val,
+							val == 1U, 1U, sem_timeout);
+			if (err)
+				aq_pr_err("reset sema2 timeout");
+		}
 	}
 
 	if (self->rbl_enabled)
@@ -282,14 +301,14 @@
 }
 
 int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
-				  u32 *p, u32 cnt)
+		u32 *p, u32 cnt)
 {
 	int err = 0;
 	u32 val;
 
 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get,
-					self, val, val == 1U,
-					1U, 10000U);
+			self, val, val == 1U,
+			1U, 10000U);
 
 	if (err < 0) {
 		bool is_locked;
@@ -309,13 +328,13 @@
 
 		if (IS_CHIP_FEATURE(REVISION_B1))
 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get,
-							self, val, val != a,
-							1U, 1000U);
+					self, val, val != a,
+					1U, 1000U);
 		else
 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
-							self, val,
-							!(val & 0x100),
-							1U, 1000U);
+					self, val,
+					!(val & 0x100),
+					1U, 1000U);
 
 		*(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
 		a += 4;
@@ -328,14 +347,14 @@
 }
 
 static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
-					 u32 cnt)
+		u32 cnt)
 {
 	u32 val;
 	int err = 0;
 
 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self,
-					val, val == 1U,
-					10U, 100000U);
+			val, val == 1U,
+			10U, 100000U);
 	if (err < 0)
 		goto err_exit;
 
@@ -349,10 +368,10 @@
 			hw_atl_mcp_up_force_intr_set(self, 1);
 			/* 1000 times by 10us = 10ms */
 			err = readx_poll_timeout_atomic(hw_atl_scrpad12_get,
-							self, val,
-							(val & 0xF0000000) !=
-							0x80000000,
-							10U, 10000U);
+					self, val,
+					(val & 0xF0000000) !=
+					0x80000000,
+					10U, 10000U);
 		}
 	} else {
 		u32 offset = 0;
@@ -364,9 +383,9 @@
 			aq_hw_write_reg(self, 0x200, 0xC000);
 
 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
-							self, val,
-							(val & 0x100) == 0,
-							1000U, 10000U);
+					self, val,
+					(val & 0x100) == 0,
+					1000U, 10000U);
 		}
 	}
 
@@ -376,19 +395,21 @@
 	return err;
 }
 
-static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
+bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
 {
-	int err = 0;
 	const u32 dw_major_mask = 0xff000000U;
 	const u32 dw_minor_mask = 0x00ffffffU;
+	bool ver_match;
 
-	err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
-	if (err < 0)
+	ver_match = (dw_major_mask & (ver_expected ^ ver_actual)) ? false : true;
+	if (!ver_match)
 		goto err_exit;
-	err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
-		-EOPNOTSUPP : 0;
+
+	ver_match = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
+		false : true;
+
 err_exit:
-	return err;
+	return ver_match;
 }
 
 static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
@@ -413,6 +434,10 @@
 					self, self->mbox_addr,
 					self->mbox_addr != 0U,
 					1000U, 10000U);
+	err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self,
+					self->rpc_addr,
+					self->rpc_addr != 0U,
+					1000U, 100000U);
 
 	return err;
 }
@@ -469,8 +494,19 @@
 						self, fw.val,
 						sw.tid == fw.tid,
 						1000U, 100000U);
+		if (err < 0)
+			goto err_exit;
+
+		err = aq_hw_err_from_flags(self);
+		if (err < 0)
+			goto err_exit;
 
 		if (fw.len == 0xFFFFU) {
+			if (sw.len > sizeof(self->rpc)) {
+				printk(KERN_INFO "Invalid sw len: %x\n", sw.len);
+				err = -EINVAL;
+				goto err_exit;
+			}
 			err = hw_atl_utils_fw_rpc_call(self, sw.len);
 			if (err < 0)
 				goto err_exit;
@@ -479,6 +515,11 @@
 
 	if (rpc) {
 		if (fw.len) {
+			if (fw.len > sizeof(self->rpc)) {
+				printk(KERN_INFO "Invalid fw len: %x\n", fw.len);
+				err = -EINVAL;
+				goto err_exit;
+			}
 			err =
 			hw_atl_utils_fw_downld_dwords(self,
 						      self->rpc_addr,
@@ -840,10 +881,9 @@
 	return 0;
 }
 
-int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
+u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self)
 {
-	*fw_version = aq_hw_read_reg(self, 0x18U);
-	return 0;
+	return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
 }
 
 static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac)
@@ -950,6 +990,11 @@
 	return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR);
 }
 
+static u32 aq_fw1x_rpc_get(struct aq_hw_s *self)
+{
+	return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR);
+}
+
 const struct aq_fw_ops aq_fw_1x_ops = {
 	.init = hw_atl_utils_mpi_create,
 	.deinit = hw_atl_fw1x_deinit,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ linux-ein-5.4.0/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -466,7 +466,7 @@
 
 int hw_atl_utils_hw_deinit(struct aq_hw_s *self);
 
-int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version);
+u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self);
 
 int hw_atl_utils_update_stats(struct aq_hw_s *self);
 
@@ -482,6 +482,8 @@
 int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
 			     struct hw_atl_utils_fw_rpc **rpc);
 
+bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
+
 extern const struct aq_fw_ops aq_fw_1x_ops;
 extern const struct aq_fw_ops aq_fw_2x_ops;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/arc/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/arc/Kconfig
@@ -21,6 +21,7 @@
 	depends on ARC || ARCH_ROCKCHIP || COMPILE_TEST
 	select MII
 	select PHYLIB
+	select CRC32
 
 config ARC_EMAC
 	tristate "ARC EMAC support"
--- linux-ein-5.4.0.orig/drivers/net/ethernet/arc/emac_mdio.c
+++ linux-ein-5.4.0/drivers/net/ethernet/arc/emac_mdio.c
@@ -153,6 +153,7 @@
 	if (IS_ERR(data->reset_gpio)) {
 		error = PTR_ERR(data->reset_gpio);
 		dev_err(priv->dev, "Failed to request gpio: %d\n", error);
+		mdiobus_free(bus);
 		return error;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/ag71xx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/ag71xx.c
@@ -222,8 +222,6 @@
 #define AG71XX_REG_RX_SM	0x01b0
 #define AG71XX_REG_TX_SM	0x01b4
 
-#define ETH_SWITCH_HEADER_LEN	2
-
 #define AG71XX_DEFAULT_MSG_ENABLE	\
 	(NETIF_MSG_DRV			\
 	| NETIF_MSG_PROBE		\
@@ -553,7 +551,8 @@
 	ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
 	if (IS_ERR(ag->mdio_reset)) {
 		netif_err(ag, probe, ndev, "Failed to get reset mdio.\n");
-		return PTR_ERR(ag->mdio_reset);
+		err = PTR_ERR(ag->mdio_reset);
+		goto mdio_err_put_clk;
 	}
 
 	mii_bus->name = "ag71xx_mdio";
@@ -783,7 +782,7 @@
 
 static unsigned int ag71xx_max_frame_len(unsigned int mtu)
 {
-	return ETH_SWITCH_HEADER_LEN + ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
+	return ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
 }
 
 static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/alx/ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/alx/ethtool.c
@@ -46,6 +46,8 @@
 #include "reg.h"
 #include "hw.h"
 
+extern const bool enable_wol;
+
 /* The order of these strings must match the order of the fields in
  * struct alx_hw_stats
  * See hw.h
@@ -281,9 +283,8 @@
 	spin_lock(&alx->stats_lock);
 
 	alx_update_hw_stats(hw);
-	BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) <
-		     ALX_NUM_STATS * sizeof(u64));
-	memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64));
+	BUILD_BUG_ON(sizeof(hw->stats) != ALX_NUM_STATS * sizeof(u64));
+	memcpy(data, &hw->stats, sizeof(hw->stats));
 
 	spin_unlock(&alx->stats_lock);
 }
@@ -310,11 +311,50 @@
 	}
 }
 
+static void alx_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct alx_priv *alx = netdev_priv(netdev);
+	struct alx_hw *hw = &alx->hw;
+
+	if (!enable_wol)
+		return;
+
+	wol->supported = WAKE_MAGIC | WAKE_PHY;
+	wol->wolopts = 0;
+
+	if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+		wol->wolopts |= WAKE_MAGIC;
+	if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY)
+		wol->wolopts |= WAKE_PHY;
+}
+
+static int alx_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct alx_priv *alx = netdev_priv(netdev);
+	struct alx_hw *hw = &alx->hw;
+
+	if (!enable_wol || (wol->wolopts & ~(WAKE_MAGIC | WAKE_PHY)))
+		return -EOPNOTSUPP;
+
+	hw->sleep_ctrl = 0;
+
+	if (wol->wolopts & WAKE_MAGIC)
+		hw->sleep_ctrl |= ALX_SLEEP_WOL_MAGIC;
+	if (wol->wolopts & WAKE_PHY)
+		hw->sleep_ctrl |= ALX_SLEEP_WOL_PHY;
+
+	device_set_wakeup_enable(&alx->hw.pdev->dev, hw->sleep_ctrl);
+
+	return 0;
+}
+
 const struct ethtool_ops alx_ethtool_ops = {
 	.get_pauseparam	= alx_get_pauseparam,
 	.set_pauseparam	= alx_set_pauseparam,
 	.get_msglevel	= alx_get_msglevel,
 	.set_msglevel	= alx_set_msglevel,
+	.get_wol	= alx_get_wol,
+	.set_wol	= alx_set_wol,
 	.get_link	= ethtool_op_get_link,
 	.get_strings	= alx_get_strings,
 	.get_sset_count	= alx_get_sset_count,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/alx/hw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/alx/hw.c
@@ -332,6 +332,16 @@
 	alx_write_mem32(hw, ALX_STAD1, val);
 }
 
+static void alx_enable_osc(struct alx_hw *hw)
+{
+	u32 val;
+
+	/* rising edge */
+	val = alx_read_mem32(hw, ALX_MISC);
+	alx_write_mem32(hw, ALX_MISC, val & ~ALX_MISC_INTNLOSC_OPEN);
+	alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+}
+
 static void alx_reset_osc(struct alx_hw *hw, u8 rev)
 {
 	u32 val, val2;
@@ -774,7 +784,6 @@
 	return err;
 }
 
-
 void alx_post_phy_link(struct alx_hw *hw)
 {
 	u16 phy_val, len, agc;
@@ -848,6 +857,65 @@
 	}
 }
 
+/* NOTE:
+ *    1. phy link must be established before calling this function
+ *    2. wol option (pattern,magic,link,etc.) is configed before call it.
+ */
+int alx_pre_suspend(struct alx_hw *hw, int speed, u8 duplex)
+{
+	u32 master, mac, phy, val;
+	int err = 0;
+
+	master = alx_read_mem32(hw, ALX_MASTER);
+	master &= ~ALX_MASTER_PCLKSEL_SRDS;
+	mac = hw->rx_ctrl;
+	/* 10/100 half */
+	ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,  ALX_MAC_CTRL_SPEED_10_100);
+	mac &= ~(ALX_MAC_CTRL_FULLD | ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
+
+	phy = alx_read_mem32(hw, ALX_PHY_CTRL);
+	phy &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_CLS);
+	phy |= ALX_PHY_CTRL_RST_ANALOG | ALX_PHY_CTRL_HIB_PULSE |
+	       ALX_PHY_CTRL_HIB_EN;
+
+	/* without any activity  */
+	if (!(hw->sleep_ctrl & ALX_SLEEP_ACTIVE)) {
+		err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+		if (err)
+			return err;
+		phy |= ALX_PHY_CTRL_IDDQ | ALX_PHY_CTRL_POWER_DOWN;
+	} else {
+		if (hw->sleep_ctrl & (ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_CIFS))
+			mac |= ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_BRD_EN;
+		if (hw->sleep_ctrl & ALX_SLEEP_CIFS)
+			mac |= ALX_MAC_CTRL_TX_EN;
+		if (duplex == DUPLEX_FULL)
+			mac |= ALX_MAC_CTRL_FULLD;
+		if (speed == SPEED_1000)
+			ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
+				      ALX_MAC_CTRL_SPEED_1000);
+		phy |= ALX_PHY_CTRL_DSPRST_OUT;
+		err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG,
+					ALX_MIIEXT_S3DIG10,
+					ALX_MIIEXT_S3DIG10_SL);
+		if (err)
+			return err;
+	}
+
+	alx_enable_osc(hw);
+	hw->rx_ctrl = mac;
+	alx_write_mem32(hw, ALX_MASTER, master);
+	alx_write_mem32(hw, ALX_MAC_CTRL, mac);
+	alx_write_mem32(hw, ALX_PHY_CTRL, phy);
+
+	/* set val of PDLL D3PLLOFF */
+	val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
+	val |= ALX_PDLL_TRNS1_D3PLLOFF_EN;
+	alx_write_mem32(hw, ALX_PDLL_TRNS1, val);
+
+	return 0;
+}
+
 bool alx_phy_configured(struct alx_hw *hw)
 {
 	u32 cfg, hw_cfg;
@@ -920,6 +988,26 @@
 	return alx_read_phy_reg(hw, ALX_MII_ISR, &isr);
 }
 
+int alx_config_wol(struct alx_hw *hw)
+{
+	u32 wol = 0;
+	int err = 0;
+
+	/* turn on magic packet event */
+	if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+		wol |= ALX_WOL0_MAGIC_EN | ALX_WOL0_PME_MAGIC_EN;
+
+	/* turn on link up event */
+	if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY) {
+		wol |=  ALX_WOL0_LINK_EN | ALX_WOL0_PME_LINK;
+		/* only link up can wake up */
+		err = alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP);
+	}
+	alx_write_mem32(hw, ALX_WOL0, wol);
+
+	return err;
+}
+
 void alx_disable_rss(struct alx_hw *hw)
 {
 	u32 ctrl = alx_read_mem32(hw, ALX_RXQ0);
@@ -1044,6 +1132,70 @@
 	alx_post_write(hw);
 }
 
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed, u8 *duplex)
+{
+	int i, err;
+	u16 lpa;
+
+	err = alx_read_phy_link(hw);
+	if (err)
+		return err;
+
+	if (hw->link_speed == SPEED_UNKNOWN) {
+		*speed = SPEED_UNKNOWN;
+		*duplex = DUPLEX_UNKNOWN;
+		return 0;
+	}
+
+	err = alx_read_phy_reg(hw, MII_LPA, &lpa);
+	if (err)
+		return err;
+
+	if (!(lpa & LPA_LPACK)) {
+		*speed = hw->link_speed;
+		return 0;
+	}
+
+	if (lpa & LPA_10FULL) {
+		*speed = SPEED_10;
+		*duplex = DUPLEX_FULL;
+	} else if (lpa & LPA_10HALF) {
+		*speed = SPEED_10;
+		*duplex = DUPLEX_HALF;
+	} else if (lpa & LPA_100FULL) {
+		*speed = SPEED_100;
+		*duplex = DUPLEX_FULL;
+	} else {
+		*speed = SPEED_100;
+		*duplex = DUPLEX_HALF;
+	}
+
+	if (*speed == hw->link_speed && *duplex == hw->duplex)
+		return 0;
+	err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+	if (err)
+		return err;
+	err = alx_setup_speed_duplex(hw, alx_speed_to_ethadv(*speed, *duplex) |
+					ADVERTISED_Autoneg, ALX_FC_ANEG |
+					ALX_FC_RX | ALX_FC_TX);
+	if (err)
+		return err;
+
+	/* wait for linkup */
+	for (i = 0; i < ALX_MAX_SETUP_LNK_CYCLE; i++) {
+		msleep(100);
+
+		err = alx_read_phy_link(hw);
+		if (err < 0)
+			return err;
+		if (hw->link_speed != SPEED_UNKNOWN)
+			break;
+	}
+	if (i == ALX_MAX_SETUP_LNK_CYCLE)
+		return -ETIMEDOUT;
+
+	return 0;
+}
 
 bool alx_get_phy_info(struct alx_hw *hw)
 {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/alx/hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/alx/hw.h
@@ -487,6 +487,8 @@
 	u8 flowctrl;
 	u32 adv_cfg;
 
+	u32 sleep_ctrl;
+
 	spinlock_t mdio_lock;
 	struct mdio_if_info mdio;
 	u16 phy_id[2];
@@ -549,12 +551,14 @@
 void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en);
 int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl);
 void alx_post_phy_link(struct alx_hw *hw);
+int alx_pre_suspend(struct alx_hw *hw, int speed, u8 duplex);
 int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data);
 int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data);
 int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata);
 int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data);
 int alx_read_phy_link(struct alx_hw *hw);
 int alx_clear_phy_intr(struct alx_hw *hw);
+int alx_config_wol(struct alx_hw *hw);
 void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc);
 void alx_start_mac(struct alx_hw *hw);
 int alx_reset_mac(struct alx_hw *hw);
@@ -563,6 +567,7 @@
 void alx_configure_basic(struct alx_hw *hw);
 void alx_mask_msix(struct alx_hw *hw, int index, bool mask);
 void alx_disable_rss(struct alx_hw *hw);
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed, u8 *duplex);
 bool alx_get_phy_info(struct alx_hw *hw);
 void alx_update_hw_stats(struct alx_hw *hw);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/alx/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/alx/main.c
@@ -51,6 +51,11 @@
 
 static const char alx_drv_name[] = "alx";
 
+/* disable WoL by default */
+bool enable_wol;
+module_param(enable_wol, bool, 0644);
+MODULE_PARM_DESC(enable_wol, "Enable Wake on Lan feature");
+
 static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
 {
 	struct alx_buffer *txb = &txq->bufs[entry];
@@ -1069,6 +1074,7 @@
 	alx->dev->max_mtu = ALX_MAX_FRAME_LEN(ALX_MAX_FRAME_SIZE);
 	alx->tx_ringsz = 256;
 	alx->rx_ringsz = 512;
+	hw->sleep_ctrl = ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_WOL_PHY;
 	hw->imt = 200;
 	alx->int_mask = ALX_ISR_MISC;
 	hw->dma_chnl = hw->max_dma_chnl;
@@ -1249,8 +1255,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);
 	alx_free_napis(alx);
 }
@@ -1343,6 +1353,66 @@
 	return 0;
 }
 
+static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en)
+{
+	struct alx_priv *alx = pci_get_drvdata(pdev);
+	struct net_device *netdev = alx->dev;
+	struct alx_hw *hw = &alx->hw;
+	int err, speed;
+	u8 duplex;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		__alx_stop(alx);
+
+#ifdef CONFIG_PM_SLEEP
+	err = pci_save_state(pdev);
+	if (err)
+		return err;
+#endif
+
+	err = alx_select_powersaving_speed(hw, &speed, &duplex);
+	if (err)
+		return err;
+	err = alx_clear_phy_intr(hw);
+	if (err)
+		return err;
+	err = alx_pre_suspend(hw, speed, duplex);
+	if (err)
+		return err;
+	err = alx_config_wol(hw);
+	if (err)
+		return err;
+
+	*wol_en = false;
+	if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) {
+		netif_info(alx, wol, netdev,
+			   "wol: ctrl=%X, speed=%X\n",
+			   hw->sleep_ctrl, speed);
+		device_set_wakeup_enable(&pdev->dev, true);
+		*wol_en = true;
+	}
+
+	pci_disable_device(pdev);
+
+	return 0;
+}
+
+static void alx_shutdown(struct pci_dev *pdev)
+{
+	int err;
+	bool wol_en;
+
+	err = __alx_shutdown(pdev, &wol_en);
+	if (!err) {
+		pci_wake_from_d3(pdev, wol_en);
+		pci_set_power_state(pdev, PCI_D3hot);
+	} else {
+		dev_err(&pdev->dev, "shutdown fail %d\n", err);
+	}
+}
+
 static void alx_link_check(struct work_struct *work)
 {
 	struct alx_priv *alx;
@@ -1836,6 +1906,8 @@
 		goto out_unmap;
 	}
 
+	device_set_wakeup_enable(&pdev->dev, hw->sleep_ctrl);
+
 	netdev_info(netdev,
 		    "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n",
 		    netdev->dev_addr);
@@ -1848,6 +1920,7 @@
 	free_netdev(netdev);
 out_pci_release:
 	pci_release_mem_regions(pdev);
+	pci_disable_pcie_error_reporting(pdev);
 out_pci_disable:
 	pci_disable_device(pdev);
 	return err;
@@ -1858,9 +1931,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);
 
@@ -1877,41 +1947,95 @@
 #ifdef CONFIG_PM_SLEEP
 static int alx_suspend(struct device *dev)
 {
-	struct alx_priv *alx = dev_get_drvdata(dev);
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int err;
+	bool wol_en;
+
+	err = __alx_shutdown(pdev, &wol_en);
+	if (err) {
+		dev_err(&pdev->dev, "shutdown fail in suspend %d\n", err);
+		return err;
+	}
+
+	if (wol_en) {
+		pci_prepare_to_sleep(pdev);
+	} else {
+		pci_wake_from_d3(pdev, false);
+		pci_set_power_state(pdev, PCI_D3hot);
+	}
 
-	if (!netif_running(alx->dev))
-		return 0;
-	netif_device_detach(alx->dev);
-	__alx_stop(alx);
 	return 0;
 }
 
 static int alx_resume(struct device *dev)
 {
-	struct alx_priv *alx = dev_get_drvdata(dev);
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct alx_priv *alx = pci_get_drvdata(pdev);
+	struct net_device *netdev = alx->dev;
 	struct alx_hw *hw = &alx->hw;
 	int err;
 
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_save_state(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	hw->link_speed = SPEED_UNKNOWN;
+	alx->int_mask = ALX_ISR_MISC;
+
+	alx_reset_pcie(hw);
 	alx_reset_phy(hw);
 
-	if (!netif_running(alx->dev))
-		return 0;
-	netif_device_attach(alx->dev);
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_save_state(pdev);
 
-	rtnl_lock();
-	err = __alx_open(alx, true);
-	rtnl_unlock();
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	hw->link_speed = SPEED_UNKNOWN;
+	alx->int_mask = ALX_ISR_MISC;
+
+	alx_reset_pcie(hw);
+	alx_reset_phy(hw);
+
+	err = alx_reset_mac(hw);
+	if (err) {
+		netif_err(alx, hw, alx->dev,
+			  "resume:reset_mac fail %d\n", err);
+		return -EIO;
+	}
+
+	err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
+	if (err) {
+		netif_err(alx, hw, alx->dev,
+			  "resume:setup_speed_duplex fail %d\n", err);
+		return -EIO;
+	}
+
+	if (netif_running(netdev)) {
+		rtnl_lock();
+		err = __alx_open(alx, true);
+		rtnl_unlock();
+		if (err)
+			return err;
+	}
+
+	netif_device_attach(netdev);
 
 	return err;
 }
+#endif
 
+#ifdef CONFIG_PM_SLEEP
 static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
 #define ALX_PM_OPS      (&alx_pm_ops)
 #else
 #define ALX_PM_OPS      NULL
 #endif
 
-
 static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
 					       pci_channel_state_t state)
 {
@@ -1954,6 +2078,8 @@
 	}
 
 	pci_set_master(pdev);
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
 
 	alx_reset_pcie(hw);
 	if (!alx_reset_mac(hw))
@@ -2008,6 +2134,7 @@
 	.id_table    = alx_pci_tbl,
 	.probe       = alx_probe,
 	.remove      = alx_remove,
+	.shutdown    = alx_shutdown,
 	.err_handler = &alx_err_handlers,
 	.driver.pm   = ALX_PM_OPS,
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -1989,8 +1989,11 @@
 			real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
 					+ ntohs(ip_hdr(skb)->tot_len));
 
-			if (real_len < skb->len)
-				pskb_trim(skb, real_len);
+			if (real_len < skb->len) {
+				err = pskb_trim(skb, real_len);
+				if (err)
+					return err;
+			}
 
 			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
 			if (unlikely(skb->len == hdr_len)) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -868,10 +868,13 @@
 		netdev_err(adapter->netdev, "offset(%d) > ring size(%d) !!\n",
 			   offset, adapter->ring_size);
 		err = -1;
-		goto failed;
+		goto free_buffer;
 	}
 
 	return 0;
+free_buffer:
+	kfree(tx_ring->tx_buffer);
+	tx_ring->tx_buffer = NULL;
 failed:
 	if (adapter->ring_vir_addr != NULL) {
 		pci_free_consistent(pdev, adapter->ring_size,
@@ -1638,8 +1641,11 @@
 			real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
 					+ ntohs(ip_hdr(skb)->tot_len));
 
-			if (real_len < skb->len)
-				pskb_trim(skb, real_len);
+			if (real_len < skb->len) {
+				err = pskb_trim(skb, real_len);
+				if (err)
+					return err;
+			}
 
 			hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
 			if (unlikely(skb->len == hdr_len)) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/Makefile
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/Makefile
@@ -16,3 +16,8 @@
 obj-$(CONFIG_BGMAC_PLATFORM) += bgmac-platform.o
 obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
 obj-$(CONFIG_BNXT) += bnxt/
+
+# FIXME: temporarily silence -Warray-bounds on non W=1+ builds
+ifndef KBUILD_EXTRA_WARN
+CFLAGS_tg3.o += -Wno-array-bounds
+endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/b44.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/b44.c
@@ -1519,8 +1519,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)
@@ -1532,7 +1534,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;
@@ -2388,7 +2391,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-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bcmsysport.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -666,7 +666,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");
@@ -1276,11 +1277,11 @@
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
 	struct device *kdev = &priv->pdev->dev;
 	struct bcm_sysport_tx_ring *ring;
+	unsigned long flags, desc_flags;
 	struct bcm_sysport_cb *cb;
 	struct netdev_queue *txq;
 	u32 len_status, addr_lo;
 	unsigned int skb_len;
-	unsigned long flags;
 	dma_addr_t mapping;
 	u16 queue;
 	int ret;
@@ -1338,8 +1339,10 @@
 	ring->desc_count--;
 
 	/* Ports are latched, so write upper address first */
+	spin_lock_irqsave(&priv->desc_lock, desc_flags);
 	tdma_writel(priv, len_status, TDMA_WRITE_PORT_HI(ring->index));
 	tdma_writel(priv, addr_lo, TDMA_WRITE_PORT_LO(ring->index));
+	spin_unlock_irqrestore(&priv->desc_lock, desc_flags);
 
 	/* Check ring space and update SW control flow */
 	if (ring->desc_count == 0)
@@ -1969,6 +1972,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) {
@@ -2135,7 +2139,7 @@
 		return -ENOSPC;
 
 	index = find_first_zero_bit(priv->filters, RXCHK_BRCM_TAG_MAX);
-	if (index > RXCHK_BRCM_TAG_MAX)
+	if (index >= RXCHK_BRCM_TAG_MAX)
 		return -ENOSPC;
 
 	/* Location is the classification ID, and index is the position
@@ -2323,7 +2327,7 @@
 		ring->switch_queue = qp;
 		ring->switch_port = port;
 		ring->inspect = true;
-		priv->ring_map[q + port * num_tx_queues] = ring;
+		priv->ring_map[qp + port * num_tx_queues] = ring;
 		qp++;
 	}
 
@@ -2338,7 +2342,7 @@
 	struct net_device *slave_dev;
 	unsigned int num_tx_queues;
 	struct net_device *dev;
-	unsigned int q, port;
+	unsigned int q, qp, port;
 
 	priv = container_of(nb, struct bcm_sysport_priv, dsa_notifier);
 	if (priv->netdev != info->master)
@@ -2364,7 +2368,8 @@
 			continue;
 
 		ring->inspect = false;
-		priv->ring_map[q + port * num_tx_queues] = NULL;
+		qp = ring->switch_queue;
+		priv->ring_map[qp + port * num_tx_queues] = NULL;
 	}
 
 	return 0;
@@ -2451,8 +2456,10 @@
 	priv->tx_rings = devm_kcalloc(&pdev->dev, txq,
 				      sizeof(struct bcm_sysport_tx_ring),
 				      GFP_KERNEL);
-	if (!priv->tx_rings)
-		return -ENOMEM;
+	if (!priv->tx_rings) {
+		ret = -ENOMEM;
+		goto err_free_netdev;
+	}
 
 	priv->is_lite = params->is_lite;
 	priv->num_rx_desc_words = params->num_rx_desc_words;
@@ -2516,6 +2523,7 @@
 			 NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 	dev->hw_features |= dev->features;
 	dev->vlan_features |= dev->features;
+	dev->max_mtu = UMAC_MAX_MTU_SIZE;
 
 	/* Request the WOL interrupt and advertise suspend if available */
 	priv->wol_irq_disabled = 1;
@@ -2727,6 +2735,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-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bcmsysport.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -742,6 +742,7 @@
 	int			wol_irq;
 
 	/* Transmit rings */
+	spinlock_t		desc_lock;
 	struct bcm_sysport_tx_ring *tx_rings;
 
 	/* Receive queue */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bgmac-bcma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bgmac-bcma.c
@@ -228,12 +228,12 @@
 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
 		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
 		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
-		if (ci->pkg == BCMA_PKG_ID_BCM47188 ||
-		    ci->pkg == BCMA_PKG_ID_BCM47186) {
+		if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) ||
+		    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) {
 			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
 			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
 		}
-		if (ci->pkg == BCMA_PKG_ID_BCM5358)
+		if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358)
 			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
 		break;
 	case BCMA_CHIP_ID_BCM53573:
@@ -323,7 +323,6 @@
 	bcma_mdio_mii_unregister(bgmac->mii_bus);
 	bgmac_enet_remove(bgmac);
 	bcma_set_drvdata(core, NULL);
-	kfree(bgmac);
 }
 
 static struct bcma_driver bgmac_bcma_driver = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bgmac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bgmac.c
@@ -189,8 +189,8 @@
 	}
 
 	slot->skb = skb;
-	ring->end += nr_frags + 1;
 	netdev_sent_queue(net_dev, skb->len);
+	ring->end += nr_frags + 1;
 
 	wmb();
 
@@ -890,13 +890,13 @@
 
 		if (iost & BGMAC_BCMA_IOST_ATTACHED) {
 			flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
-			if (!bgmac->has_robosw)
+			if (bgmac->in_init || !bgmac->has_robosw)
 				flags |= BGMAC_BCMA_IOCTL_SW_RESET;
 		}
 		bgmac_clk_enable(bgmac, flags);
 	}
 
-	if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+	if (iost & BGMAC_BCMA_IOST_ATTACHED && (bgmac->in_init || !bgmac->has_robosw))
 		bgmac_idm_write(bgmac, BCMA_IOCTL,
 				bgmac_idm_read(bgmac, BCMA_IOCTL) &
 				~BGMAC_BCMA_IOCTL_SW_RESET);
@@ -1447,7 +1447,7 @@
 	int err;
 
 	phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
-	if (!phy_dev || IS_ERR(phy_dev)) {
+	if (IS_ERR(phy_dev)) {
 		dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
 		return -ENODEV;
 	}
@@ -1489,6 +1489,8 @@
 	struct net_device *net_dev = bgmac->net_dev;
 	int err;
 
+	bgmac->in_init = true;
+
 	bgmac_chip_intrs_off(bgmac);
 
 	net_dev->irq = bgmac->irq;
@@ -1538,6 +1540,8 @@
 	net_dev->hw_features = net_dev->features;
 	net_dev->vlan_features = net_dev->features;
 
+	bgmac->in_init = false;
+
 	err = register_netdev(bgmac->net_dev);
 	if (err) {
 		dev_err(bgmac->dev, "Cannot register net device\n");
@@ -1564,7 +1568,6 @@
 	phy_disconnect(bgmac->net_dev->phydev);
 	netif_napi_del(&bgmac->napi);
 	bgmac_dma_free(bgmac);
-	free_netdev(bgmac->net_dev);
 }
 EXPORT_SYMBOL_GPL(bgmac_enet_remove);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bgmac.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bgmac.h
@@ -511,6 +511,8 @@
 	int irq;
 	u32 int_mask;
 
+	bool in_init;
+
 	/* Current MAC state */
 	int mac_speed;
 	int mac_duplex;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2.c
@@ -1461,7 +1461,7 @@
 static void
 bnx2_enable_forced_2g5(struct bnx2 *bp)
 {
-	u32 uninitialized_var(bmcr);
+	u32 bmcr;
 	int err;
 
 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
@@ -1505,7 +1505,7 @@
 static void
 bnx2_disable_forced_2g5(struct bnx2 *bp)
 {
-	u32 uninitialized_var(bmcr);
+	u32 bmcr;
 	int err;
 
 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
@@ -8249,9 +8249,9 @@
 		BNX2_WR(bp, PCI_COMMAND, reg);
 	} else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
 		!(bp->flags & BNX2_FLAG_PCIX)) {
-
 		dev_err(&pdev->dev,
 			"5706 A1 can only be used in a PCIX bus, aborting\n");
+		rc = -EPERM;
 		goto err_out_unmap;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -787,6 +787,7 @@
 			BNX2X_ERR("skb_put is about to fail...  pad %d  len %d  rx_buf_size %d\n",
 				  pad, len, fp->rx_buf_size);
 			bnx2x_panic();
+			bnx2x_frag_free(fp, new_data);
 			return;
 		}
 #endif
@@ -2666,7 +2667,8 @@
 	}
 
 	/* Allocated memory for FW statistics  */
-	if (bnx2x_alloc_fw_stats_mem(bp))
+	rc = bnx2x_alloc_fw_stats_mem(bp);
+	if (rc)
 		LOAD_ERROR_EXIT(bp, load_error0);
 
 	/* request pf to initialize status blocks */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1109,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-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
@@ -296,7 +296,6 @@
  *    possible, the driver should only write the valid vnics into the internal
  *    ram according to the appropriate port mode.
  */
-#define BITS_TO_BYTES(x) ((x)/8)
 
 /* CMNG constants, as derived from system spec calculations */
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
@@ -635,11 +635,13 @@
 {
 	int i, rc;
 	struct bnx2x_ilt *ilt = BP_ILT(bp);
-	struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+	struct ilt_client_info *ilt_cli;
 
 	if (!ilt || !ilt->lines)
 		return -1;
 
+	ilt_cli = &ilt->clients[cli_num];
+
 	if (ilt_cli->flags & (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM))
 		return 0;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9976,10 +9976,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) {
@@ -14259,10 +14267,6 @@
 
 	/* Stop Tx */
 	bnx2x_tx_disable(bp);
-	/* Delete all NAPI objects */
-	bnx2x_del_all_napi(bp);
-	if (CNIC_LOADED(bp))
-		bnx2x_del_all_napi_cnic(bp);
 	netdev_reset_tc(bp->dev);
 
 	del_timer_sync(&bp->timer);
@@ -14367,6 +14371,11 @@
 		bnx2x_drain_tx_queues(bp);
 		bnx2x_send_unload_req(bp, UNLOAD_RECOVERY);
 		bnx2x_netif_stop(bp, 1);
+		bnx2x_del_all_napi(bp);
+
+		if (CNIC_LOADED(bp))
+			bnx2x_del_all_napi_cnic(bp);
+
 		bnx2x_free_irq(bp);
 
 		/* Report UNLOAD_DONE to MCP */
@@ -14417,11 +14426,16 @@
 	bp->fw_seq = SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
 							DRV_MSG_SEQ_NUMBER_MASK;
 
-	if (netif_running(dev))
-		bnx2x_nic_load(bp, LOAD_NORMAL);
+	if (netif_running(dev)) {
+		if (bnx2x_nic_load(bp, LOAD_NORMAL)) {
+			netdev_err(bp->dev, "Error during driver initialization, try unloading/reloading the driver\n");
+			goto done;
+		}
+	}
 
 	netif_device_attach(dev);
 
+done:
 	rtnl_unlock();
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -807,16 +807,20 @@
 
 static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
 {
-	struct pci_dev *dev;
 	struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+	struct pci_dev *dev;
+	bool pending;
 
 	if (!vf)
 		return false;
 
 	dev = pci_get_domain_bus_and_slot(vf->domain, vf->bus, vf->devfn);
-	if (dev)
-		return bnx2x_is_pcie_pending(dev);
-	return false;
+	if (!dev)
+		return false;
+	pending = bnx2x_is_pcie_pending(dev);
+	pci_dev_put(dev);
+
+	return pending;
 }
 
 int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
@@ -1245,8 +1249,10 @@
 		goto failed;
 
 	/* SR-IOV capability was enabled but there are no VFs*/
-	if (iov->total == 0)
+	if (iov->total == 0) {
+		err = 0;
 		goto failed;
+	}
 
 	iov->nr_virtfn = min_t(u16, iov->total, num_vfs_param);
 
@@ -2397,15 +2403,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-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -139,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 */
 	bool malicious;		/* true if FW indicated so, until FLR */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -2107,6 +2107,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-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -125,7 +125,10 @@
 	NETXTREME_E_VF,
 	NETXTREME_C_VF,
 	NETXTREME_S_VF,
+	NETXTREME_C_VF_HV,
+	NETXTREME_E_VF_HV,
 	NETXTREME_E_P5_VF,
+	NETXTREME_E_P5_VF_HV,
 };
 
 /* indexed by enum above */
@@ -173,7 +176,10 @@
 	[NETXTREME_E_VF] = { "Broadcom NetXtreme-E Ethernet Virtual Function" },
 	[NETXTREME_C_VF] = { "Broadcom NetXtreme-C Ethernet Virtual Function" },
 	[NETXTREME_S_VF] = { "Broadcom NetXtreme-S Ethernet Virtual Function" },
+	[NETXTREME_C_VF_HV] = { "Broadcom NetXtreme-C Virtual Function for Hyper-V" },
+	[NETXTREME_E_VF_HV] = { "Broadcom NetXtreme-E Virtual Function for Hyper-V" },
 	[NETXTREME_E_P5_VF] = { "Broadcom BCM5750X NetXtreme-E Ethernet Virtual Function" },
+	[NETXTREME_E_P5_VF_HV] = { "Broadcom BCM5750X NetXtreme-E Virtual Function for Hyper-V" },
 };
 
 static const struct pci_device_id bnxt_pci_tbl[] = {
@@ -215,25 +221,35 @@
 	{ PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
 	{ PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
 	{ PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 },
-	{ PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57508_NPAR },
+	{ PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR },
 	{ PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR },
-	{ PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57502_NPAR },
-	{ PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57508_NPAR },
+	{ PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR },
+	{ PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57502_NPAR },
 	{ PCI_VDEVICE(BROADCOM, 0x1804), .driver_data = BCM57504_NPAR },
-	{ PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57502_NPAR },
+	{ PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57508_NPAR },
 	{ PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
 	{ PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
 #ifdef CONFIG_BNXT_SRIOV
 	{ PCI_VDEVICE(BROADCOM, 0x1606), .driver_data = NETXTREME_E_VF },
+	{ PCI_VDEVICE(BROADCOM, 0x1607), .driver_data = NETXTREME_E_VF_HV },
+	{ PCI_VDEVICE(BROADCOM, 0x1608), .driver_data = NETXTREME_E_VF_HV },
 	{ PCI_VDEVICE(BROADCOM, 0x1609), .driver_data = NETXTREME_E_VF },
+	{ PCI_VDEVICE(BROADCOM, 0x16bd), .driver_data = NETXTREME_E_VF_HV },
 	{ PCI_VDEVICE(BROADCOM, 0x16c1), .driver_data = NETXTREME_E_VF },
+	{ PCI_VDEVICE(BROADCOM, 0x16c2), .driver_data = NETXTREME_C_VF_HV },
+	{ PCI_VDEVICE(BROADCOM, 0x16c3), .driver_data = NETXTREME_C_VF_HV },
+	{ PCI_VDEVICE(BROADCOM, 0x16c4), .driver_data = NETXTREME_E_VF_HV },
+	{ PCI_VDEVICE(BROADCOM, 0x16c5), .driver_data = NETXTREME_E_VF_HV },
 	{ PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = NETXTREME_C_VF },
 	{ PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = NETXTREME_E_VF },
 	{ PCI_VDEVICE(BROADCOM, 0x16dc), .driver_data = NETXTREME_E_VF },
 	{ PCI_VDEVICE(BROADCOM, 0x16e1), .driver_data = NETXTREME_C_VF },
 	{ PCI_VDEVICE(BROADCOM, 0x16e5), .driver_data = NETXTREME_C_VF },
+	{ PCI_VDEVICE(BROADCOM, 0x16e6), .driver_data = NETXTREME_C_VF_HV },
 	{ PCI_VDEVICE(BROADCOM, 0x1806), .driver_data = NETXTREME_E_P5_VF },
 	{ PCI_VDEVICE(BROADCOM, 0x1807), .driver_data = NETXTREME_E_P5_VF },
+	{ PCI_VDEVICE(BROADCOM, 0x1808), .driver_data = NETXTREME_E_P5_VF_HV },
+	{ PCI_VDEVICE(BROADCOM, 0x1809), .driver_data = NETXTREME_E_P5_VF_HV },
 	{ PCI_VDEVICE(BROADCOM, 0xd800), .driver_data = NETXTREME_S_VF },
 #endif
 	{ 0 }
@@ -263,7 +279,9 @@
 static bool bnxt_vf_pciid(enum board_idx idx)
 {
 	return (idx == NETXTREME_C_VF || idx == NETXTREME_E_VF ||
-		idx == NETXTREME_S_VF || idx == NETXTREME_E_P5_VF);
+		idx == NETXTREME_S_VF || idx == NETXTREME_C_VF_HV ||
+		idx == NETXTREME_E_VF_HV || idx == NETXTREME_E_P5_VF ||
+		idx == NETXTREME_E_P5_VF_HV);
 }
 
 #define DB_CP_REARM_FLAGS	(DB_KEY_CP | DB_IDX_VALID)
@@ -342,6 +360,26 @@
 	return md_dst->u.port_info.port_id;
 }
 
+static bool bnxt_txr_netif_try_stop_queue(struct bnxt *bp,
+					  struct bnxt_tx_ring_info *txr,
+					  struct netdev_queue *txq)
+{
+	netif_tx_stop_queue(txq);
+
+	/* netif_tx_stop_queue() must be done before checking
+	 * tx index in bnxt_tx_avail() below, because in
+	 * bnxt_tx_int(), we update tx index before checking for
+	 * netif_tx_queue_stopped().
+	 */
+	smp_mb();
+	if (bnxt_tx_avail(bp, txr) >= bp->tx_wake_thresh) {
+		netif_tx_wake_queue(txq);
+		return false;
+	}
+
+	return true;
+}
+
 static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct bnxt *bp = netdev_priv(dev);
@@ -369,8 +407,8 @@
 
 	free_size = bnxt_tx_avail(bp, txr);
 	if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) {
-		netif_tx_stop_queue(txq);
-		return NETDEV_TX_BUSY;
+		if (bnxt_txr_netif_try_stop_queue(bp, txr, txq))
+			return NETDEV_TX_BUSY;
 	}
 
 	length = skb->len;
@@ -579,16 +617,7 @@
 		if (netdev_xmit_more() && !tx_buf->is_push)
 			bnxt_db_write(bp, &txr->tx_db, prod);
 
-		netif_tx_stop_queue(txq);
-
-		/* netif_tx_stop_queue() must be done before checking
-		 * tx index in bnxt_tx_avail() below, because in
-		 * bnxt_tx_int(), we update tx index before checking for
-		 * netif_tx_queue_stopped().
-		 */
-		smp_mb();
-		if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)
-			netif_tx_wake_queue(txq);
+		bnxt_txr_netif_try_stop_queue(bp, txr, txq);
 	}
 	return NETDEV_TX_OK;
 
@@ -672,14 +701,9 @@
 	smp_mb();
 
 	if (unlikely(netif_tx_queue_stopped(txq)) &&
-	    (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
-		__netif_tx_lock(txq, smp_processor_id());
-		if (netif_tx_queue_stopped(txq) &&
-		    bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh &&
-		    txr->dev_state != BNXT_DEV_STATE_CLOSING)
-			netif_tx_wake_queue(txq);
-		__netif_tx_unlock(txq);
-	}
+	    bnxt_tx_avail(bp, txr) >= bp->tx_wake_thresh &&
+	    READ_ONCE(txr->dev_state) != BNXT_DEV_STATE_CLOSING)
+		netif_tx_wake_queue(txq);
 }
 
 static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
@@ -942,6 +966,7 @@
 	dma_addr -= bp->rx_dma_offset;
 	dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir,
 			     DMA_ATTR_WEAK_ORDERING);
+	page_pool_release_page(rxr->page_pool, page);
 
 	if (unlikely(!payload))
 		payload = eth_get_headlen(bp->dev, data_ptr, len);
@@ -1142,6 +1167,9 @@
 
 static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
 {
+	if (!(test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)))
+		return;
+
 	if (BNXT_PF(bp))
 		queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
 	else
@@ -1156,14 +1184,6 @@
 		schedule_work(&bp->sp_task);
 }
 
-static void bnxt_cancel_sp_work(struct bnxt *bp)
-{
-	if (BNXT_PF(bp))
-		flush_workqueue(bnxt_pf_wq);
-	else
-		cancel_work_sync(&bp->sp_task);
-}
-
 static void bnxt_sched_reset(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
 {
 	if (!rxr->bnapi->in_reset) {
@@ -1704,6 +1724,10 @@
 	if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons))
 		return -EBUSY;
 
+	/* The valid test of the entry must be done first before
+	 * reading any further.
+	 */
+	dma_rmb();
 	prod = rxr->rx_prod;
 
 	if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) {
@@ -1732,12 +1756,14 @@
 
 	cons = rxcmp->rx_cmp_opaque;
 	if (unlikely(cons != rxr->rx_next_cons)) {
-		int rc1 = bnxt_discard_rx(bp, cpr, raw_cons, rxcmp);
+		int rc1 = bnxt_discard_rx(bp, cpr, &tmp_raw_cons, rxcmp);
 
 		netdev_warn(bp->dev, "RX cons %x != expected cons %x\n",
 			    cons, rxr->rx_next_cons);
 		bnxt_sched_reset(bp, rxr);
-		return rc1;
+		if (rc1)
+			return rc1;
+		goto next_rx_no_prod_no_len;
 	}
 	rx_buf = &rxr->rx_buf_ring[cons];
 	data = rx_buf->data;
@@ -1767,8 +1793,12 @@
 
 		rc = -EIO;
 		if (rx_err & RX_CMPL_ERRORS_BUFFER_ERROR_MASK) {
-			netdev_warn(bp->dev, "RX buffer error %x\n", rx_err);
-			bnxt_sched_reset(bp, rxr);
+			bnapi->cp_ring.rx_buf_errors++;
+			if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
+				netdev_warn(bp->dev, "RX buffer error %x\n",
+					    rx_err);
+				bnxt_sched_reset(bp, rxr);
+			}
 		}
 		goto next_rx_no_len;
 	}
@@ -1892,6 +1922,10 @@
 	if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons))
 		return -EBUSY;
 
+	/* The valid test of the entry must be done first before
+	 * reading any further.
+	 */
+	dma_rmb();
 	cmp_type = RX_CMP_TYPE(rxcmp);
 	if (cmp_type == CMP_TYPE_RX_L2_CMP) {
 		rxcmp1->rx_cmp_cfa_code_errors_v2 |=
@@ -1991,6 +2025,9 @@
 	case ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY: {
 		u32 data1 = le32_to_cpu(cmpl->event_data1);
 
+		if (!bp->fw_health)
+			goto async_event_process_exit;
+
 		bp->fw_reset_timestamp = jiffies;
 		bp->fw_reset_min_dsecs = cmpl->timestamp_lo;
 		if (!bp->fw_reset_min_dsecs)
@@ -2169,7 +2206,7 @@
 		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);
 				if (budget)
@@ -2285,6 +2322,10 @@
 		if (!TX_CMP_VALID(txcmp, raw_cons))
 			break;
 
+		/* The valid test of the entry must be done first before
+		 * reading any further.
+		 */
+		dma_rmb();
 		if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
 			tmp_raw_cons = NEXT_RAW_CMP(raw_cons);
 			cp_cons = RING_CMP(tmp_raw_cons);
@@ -2706,7 +2747,7 @@
 
 static void bnxt_free_tpa_info(struct bnxt *bp)
 {
-	int i;
+	int i, j;
 
 	for (i = 0; i < bp->rx_nr_rings; i++) {
 		struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
@@ -2714,8 +2755,10 @@
 		kfree(rxr->rx_tpa_idx_map);
 		rxr->rx_tpa_idx_map = NULL;
 		if (rxr->rx_tpa) {
-			kfree(rxr->rx_tpa[0].agg_arr);
-			rxr->rx_tpa[0].agg_arr = NULL;
+			for (j = 0; j < bp->max_tpa; j++) {
+				kfree(rxr->rx_tpa[j].agg_arr);
+				rxr->rx_tpa[j].agg_arr = NULL;
+			}
 		}
 		kfree(rxr->rx_tpa);
 		rxr->rx_tpa = NULL;
@@ -2724,14 +2767,13 @@
 
 static int bnxt_alloc_tpa_info(struct bnxt *bp)
 {
-	int i, j, total_aggs = 0;
+	int i, j;
 
 	bp->max_tpa = MAX_TPA;
 	if (bp->flags & BNXT_FLAG_CHIP_P5) {
 		if (!bp->max_tpa_v2)
 			return 0;
 		bp->max_tpa = max_t(u16, bp->max_tpa_v2, MAX_TPA_P5);
-		total_aggs = bp->max_tpa * MAX_SKB_FRAGS;
 	}
 
 	for (i = 0; i < bp->rx_nr_rings; i++) {
@@ -2745,12 +2787,12 @@
 
 		if (!(bp->flags & BNXT_FLAG_CHIP_P5))
 			continue;
-		agg = kcalloc(total_aggs, sizeof(*agg), GFP_KERNEL);
-		rxr->rx_tpa[0].agg_arr = agg;
-		if (!agg)
-			return -ENOMEM;
-		for (j = 1; j < bp->max_tpa; j++)
-			rxr->rx_tpa[j].agg_arr = agg + j * MAX_SKB_FRAGS;
+		for (j = 0; j < bp->max_tpa; j++) {
+			agg = kcalloc(MAX_SKB_FRAGS, sizeof(*agg), GFP_KERNEL);
+			if (!agg)
+				return -ENOMEM;
+			rxr->rx_tpa[j].agg_arr = agg;
+		}
 		rxr->rx_tpa_idx_map = kzalloc(sizeof(*rxr->rx_tpa_idx_map),
 					      GFP_KERNEL);
 		if (!rxr->rx_tpa_idx_map)
@@ -3288,7 +3330,7 @@
 	u16 i;
 
 	bp->tx_wake_thresh = max_t(int, bp->tx_ring_size / 2,
-				   MAX_SKB_FRAGS + 1);
+				   BNXT_MIN_TX_DESC_CNT);
 
 	for (i = 0; i < bp->tx_nr_rings; i++) {
 		struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
@@ -3415,7 +3457,7 @@
  */
 void bnxt_set_ring_params(struct bnxt *bp)
 {
-	u32 ring_size, rx_size, rx_space;
+	u32 ring_size, rx_size, rx_space, max_rx_cmpl;
 	u32 agg_factor = 0, agg_ring_size = 0;
 
 	/* 8 for CRC and VLAN */
@@ -3471,7 +3513,15 @@
 	bp->tx_nr_pages = bnxt_calc_nr_ring_pages(ring_size, TX_DESC_CNT);
 	bp->tx_ring_mask = (bp->tx_nr_pages * TX_DESC_CNT) - 1;
 
-	ring_size = bp->rx_ring_size * (2 + agg_factor) + bp->tx_ring_size;
+	max_rx_cmpl = bp->rx_ring_size;
+	/* MAX TPA needs to be added because TPA_START completions are
+	 * immediately recycled, so the TPA completions are not bound by
+	 * the RX ring size.
+	 */
+	if (bp->flags & BNXT_FLAG_TPA)
+		max_rx_cmpl += bp->max_tpa;
+	/* RX and TPA completions are 32-byte, all others are 16-byte */
+	ring_size = max_rx_cmpl * 2 + agg_ring_size + bp->tx_ring_size;
 	bp->cp_ring_size = ring_size;
 
 	bp->cp_nr_pages = bnxt_calc_nr_ring_pages(ring_size, CP_DESC_CNT);
@@ -4183,7 +4233,8 @@
 	u32 bar_offset = BNXT_GRCPF_REG_CHIMP_COMM;
 	u16 dst = BNXT_HWRM_CHNL_CHIMP;
 
-	if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+	if (BNXT_NO_FW_ACCESS(bp) &&
+	    le16_to_cpu(req->req_type) != HWRM_FUNC_RESET)
 		return -EBUSY;
 
 	if (msg_len > BNXT_HWRM_MAX_REQ_LEN) {
@@ -4434,8 +4485,9 @@
 			    FUNC_DRV_RGTR_REQ_ENABLES_VER);
 
 	req.os_type = cpu_to_le16(FUNC_DRV_RGTR_REQ_OS_TYPE_LINUX);
-	flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE |
-		FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT;
+	flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE;
+	if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET)
+		flags |= FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT;
 	if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
 		flags |= FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT;
 	req.flags = cpu_to_le32(flags);
@@ -5517,7 +5569,7 @@
 	struct hwrm_ring_free_output *resp = bp->hwrm_cmd_resp_addr;
 	u16 error_code;
 
-	if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+	if (BNXT_NO_FW_ACCESS(bp))
 		return 0;
 
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_FREE, cmpl_ring_id, -1);
@@ -6170,7 +6222,7 @@
 		tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks_irq);
 		val = clamp_t(u16, tmr, 1,
 			      coal_cap->cmpl_aggr_dma_tmr_during_int_max);
-		req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(tmr);
+		req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(val);
 		req->enables |=
 			cpu_to_le16(BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE);
 	}
@@ -6640,7 +6692,7 @@
 	int rc;
 
 	if (!mem_size)
-		return 0;
+		return -EINVAL;
 
 	ctx_pg->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE);
 	if (ctx_pg->nr_pages > MAX_CTX_TOTAL_PAGES) {
@@ -6854,12 +6906,12 @@
 	}
 	ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES;
 	rc = bnxt_hwrm_func_backing_store_cfg(bp, ena);
-	if (rc)
+	if (rc) {
 		netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n",
 			   rc);
-	else
-		ctx->flags |= BNXT_CTX_FLAG_INITED;
-
+		return rc;
+	}
+	ctx->flags |= BNXT_CTX_FLAG_INITED;
 	return 0;
 }
 
@@ -6970,7 +7022,6 @@
 
 		pf->fw_fid = le16_to_cpu(resp->fid);
 		pf->port_id = le16_to_cpu(resp->port_id);
-		bp->dev->dev_port = pf->port_id;
 		memcpy(pf->mac_addr, resp->mac_address, ETH_ALEN);
 		pf->first_vf_id = le16_to_cpu(resp->first_vf_id);
 		pf->max_vfs = le16_to_cpu(resp->max_vfs);
@@ -7092,14 +7143,6 @@
 	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 	if (rc)
 		goto err_recovery_out;
-	if (!fw_health) {
-		fw_health = kzalloc(sizeof(*fw_health), GFP_KERNEL);
-		bp->fw_health = fw_health;
-		if (!fw_health) {
-			rc = -ENOMEM;
-			goto err_recovery_out;
-		}
-	}
 	fw_health->flags = le32_to_cpu(resp->flags);
 	if ((fw_health->flags & ERROR_RECOVERY_QCFG_RESP_FLAGS_CO_CPU) &&
 	    !(bp->fw_cap & BNXT_FW_CAP_KONG_MB_CHNL)) {
@@ -7386,14 +7429,22 @@
 		pri2cos = &resp2->pri0_cos_queue_id;
 		for (i = 0; i < 8; i++) {
 			u8 queue_id = pri2cos[i];
+			u8 queue_idx;
 
+			/* Per port queue IDs start from 0, 10, 20, etc */
+			queue_idx = queue_id % 10;
+			if (queue_idx > BNXT_MAX_QUEUE) {
+				bp->pri2cos_valid = false;
+				goto qstats_done;
+			}
 			for (j = 0; j < bp->max_q; j++) {
 				if (bp->q_ids[j] == queue_id)
-					bp->pri2cos[i] = j;
+					bp->pri2cos_idx[i] = queue_idx;
 			}
 		}
 		bp->pri2cos_valid = 1;
 	}
+qstats_done:
 	mutex_unlock(&bp->hwrm_cmd_lock);
 	return rc;
 }
@@ -7432,7 +7483,7 @@
 
 	if (set_tpa)
 		tpa_flags = bp->flags & BNXT_FLAG_TPA;
-	else if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+	else if (BNXT_NO_FW_ACCESS(bp))
 		return 0;
 	for (i = 0; i < bp->nr_vnics; i++) {
 		rc = bnxt_hwrm_vnic_set_tpa(bp, i, tpa_flags);
@@ -7730,6 +7781,9 @@
 		goto err_out;
 	}
 
+	if (BNXT_VF(bp))
+		bnxt_hwrm_func_qcfg(bp);
+
 	rc = bnxt_setup_vnic(bp, 0);
 	if (rc)
 		goto err_out;
@@ -7873,7 +7927,7 @@
 	int tcs, i;
 
 	tcs = netdev_get_num_tc(dev);
-	if (tcs > 1) {
+	if (tcs) {
 		int i, off, count;
 
 		for (i = 0; i < tcs; i++) {
@@ -7912,10 +7966,18 @@
 	bp->irq_tbl[0].handler = bnxt_inta;
 }
 
+static int bnxt_init_int_mode(struct bnxt *bp);
+
 static int bnxt_setup_int_mode(struct bnxt *bp)
 {
 	int rc;
 
+	if (!bp->irq_tbl) {
+		rc = bnxt_init_int_mode(bp);
+		if (rc || !bp->irq_tbl)
+			return rc ?: -ENODEV;
+	}
+
 	if (bp->flags & BNXT_FLAG_USING_MSIX)
 		bnxt_setup_msix(bp);
 	else
@@ -8100,7 +8162,7 @@
 
 static int bnxt_init_int_mode(struct bnxt *bp)
 {
-	int rc = 0;
+	int rc = -ENODEV;
 
 	if (bp->flags & BNXT_FLAG_MSIX_CAP)
 		rc = bnxt_init_msix(bp);
@@ -8147,10 +8209,14 @@
 		netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc);
 		return rc;
 	}
-	if (tcs && (bp->tx_nr_rings_per_tc * tcs != bp->tx_nr_rings)) {
+	if (tcs && (bp->tx_nr_rings_per_tc * tcs !=
+		    bp->tx_nr_rings - bp->tx_nr_rings_xdp)) {
 		netdev_err(bp->dev, "tx ring reservation failure\n");
 		netdev_reset_tc(bp->dev);
-		bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
+		if (bp->tx_nr_rings_xdp)
+			bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp;
+		else
+			bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
 		return -ENOMEM;
 	}
 	return 0;
@@ -8300,10 +8366,9 @@
 	for (i = 0; i < bp->cp_nr_rings; i++) {
 		struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
 
+		napi_disable(&bp->bnapi[i]->napi);
 		if (bp->bnapi[i]->rx_ring)
 			cancel_work_sync(&cpr->dim.work);
-
-		napi_disable(&bp->bnapi[i]->napi);
 	}
 }
 
@@ -8331,12 +8396,15 @@
 	if (bp->tx_ring) {
 		for (i = 0; i < bp->tx_nr_rings; i++) {
 			txr = &bp->tx_ring[i];
-			txr->dev_state = BNXT_DEV_STATE_CLOSING;
+			WRITE_ONCE(txr->dev_state, BNXT_DEV_STATE_CLOSING);
 		}
 	}
+	/* Make sure napi polls see @dev_state change */
+	synchronize_net();
+	/* 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);
 }
 
 void bnxt_tx_enable(struct bnxt *bp)
@@ -8346,8 +8414,10 @@
 
 	for (i = 0; i < bp->tx_nr_rings; i++) {
 		txr = &bp->tx_ring[i];
-		txr->dev_state = 0;
+		WRITE_ONCE(txr->dev_state, 0);
 	}
+	/* Make sure napi polls see @dev_state change */
+	synchronize_net();
 	netif_tx_wake_all_queues(bp->dev);
 	if (bp->link_info.link_up)
 		netif_carrier_on(bp->dev);
@@ -8362,6 +8432,11 @@
 		u16 fec;
 
 		netif_carrier_on(bp->dev);
+		speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed);
+		if (speed == SPEED_UNKNOWN) {
+			netdev_info(bp->dev, "NIC Link is Up, speed unknown\n");
+			return;
+		}
 		if (bp->link_info.duplex == BNXT_LINK_DUPLEX_FULL)
 			duplex = "full";
 		else
@@ -8374,7 +8449,6 @@
 			flow_ctrl = "ON - receive";
 		else
 			flow_ctrl = "none";
-		speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed);
 		netdev_info(bp->dev, "NIC Link is Up, %u Mbps %s duplex, Flow control: %s\n",
 			    speed, duplex, flow_ctrl);
 		if (bp->flags & BNXT_FLAG_EEE_CAP)
@@ -8730,7 +8804,8 @@
 {
 	struct hwrm_func_drv_if_change_output *resp = bp->hwrm_cmd_resp_addr;
 	struct hwrm_func_drv_if_change_input req = {0};
-	bool resc_reinit = false, fw_reset = false;
+	bool fw_reset = !bp->irq_tbl;
+	bool resc_reinit = false;
 	u32 flags = 0;
 	int rc;
 
@@ -8758,10 +8833,14 @@
 
 	if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state) && !fw_reset) {
 		netdev_err(bp->dev, "RESET_DONE not set during FW reset.\n");
+		set_bit(BNXT_STATE_ABORT_ERR, &bp->state);
 		return -ENODEV;
 	}
 	if (resc_reinit || fw_reset) {
 		if (fw_reset) {
+			bnxt_free_ctx_mem(bp);
+			kfree(bp->ctx);
+			bp->ctx = NULL;
 			rc = bnxt_fw_init_one(bp);
 			if (rc) {
 				set_bit(BNXT_STATE_ABORT_ERR, &bp->state);
@@ -8913,16 +8992,19 @@
 	struct hwrm_temp_monitor_query_input req = {0};
 	struct hwrm_temp_monitor_query_output *resp;
 	struct bnxt *bp = dev_get_drvdata(dev);
-	u32 temp = 0;
+	u32 len = 0;
+	int rc;
 
 	resp = bp->hwrm_cmd_resp_addr;
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_TEMP_MONITOR_QUERY, -1, -1);
 	mutex_lock(&bp->hwrm_cmd_lock);
-	if (!_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
-		temp = resp->temp * 1000; /* display millidegree */
+	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+	if (!rc)
+		len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */
 	mutex_unlock(&bp->hwrm_cmd_lock);
-
-	return sprintf(buf, "%u\n", temp);
+	if (rc)
+		return rc;
+	return len;
 }
 static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0);
 
@@ -8942,7 +9024,16 @@
 
 static void bnxt_hwmon_open(struct bnxt *bp)
 {
+	struct hwrm_temp_monitor_query_input req = {0};
 	struct pci_dev *pdev = bp->pdev;
+	int rc;
+
+	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_TEMP_MONITOR_QUERY, -1, -1);
+	rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+	if (rc == -EACCES || rc == -EOPNOTSUPP) {
+		bnxt_hwmon_close(bp);
+		return;
+	}
 
 	if (bp->hwmon_dev)
 		return;
@@ -9104,15 +9195,15 @@
 		}
 	}
 
-	bnxt_enable_napi(bp);
-	bnxt_debug_dev_init(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);
+	bnxt_debug_dev_init(bp);
+
 	if (link_re_init) {
 		mutex_lock(&bp->link_lock);
 		rc = bnxt_update_phy_setting(bp);
@@ -9143,10 +9234,6 @@
 		bnxt_vf_reps_open(bp);
 	return 0;
 
-open_err:
-	bnxt_debug_dev_exit(bp);
-	bnxt_disable_napi(bp);
-
 open_err_irq:
 	bnxt_del_napi(bp);
 
@@ -9162,7 +9249,10 @@
 {
 	int rc = 0;
 
-	rc = __bnxt_open_nic(bp, irq_re_init, link_re_init);
+	if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state))
+		rc = -EIO;
+	if (!rc)
+		rc = __bnxt_open_nic(bp, irq_re_init, link_re_init);
 	if (rc) {
 		netdev_err(bp->dev, "nic open fail (rc: %x)\n", rc);
 		dev_close(bp->dev);
@@ -9178,6 +9268,12 @@
 {
 	int rc = 0;
 
+	if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
+		netdev_err(bp->dev, "A previous firmware reset has not completed, aborting half open\n");
+		rc = -ENODEV;
+		goto half_open_err;
+	}
+
 	rc = bnxt_alloc_mem(bp, false);
 	if (rc) {
 		netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
@@ -9270,14 +9366,10 @@
 	bnxt_debug_dev_exit(bp);
 	bnxt_disable_napi(bp);
 	del_timer_sync(&bp->timer);
-	if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state) &&
-	    pci_is_enabled(bp->pdev))
-		pci_disable_device(bp->pdev);
-
 	bnxt_free_skbs(bp);
 
 	/* Save ring stats before shutdown */
-	if (bp->bnapi)
+	if (bp->bnapi && irq_re_init)
 		bnxt_get_ring_stats(bp, &bp->net_stats_prev);
 	if (irq_re_init) {
 		bnxt_free_irq(bp);
@@ -9707,7 +9799,7 @@
 
 	if (bp->flags & BNXT_FLAG_CHIP_P5)
 		return bnxt_rfs_supported(bp);
-	if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp))
+	if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings)
 		return false;
 
 	vnics = 1 + bp->rx_nr_rings;
@@ -9747,6 +9839,7 @@
 					   netdev_features_t features)
 {
 	struct bnxt *bp = netdev_priv(dev);
+	netdev_features_t vlan_features;
 
 	if ((features & NETIF_F_NTUPLE) && !bnxt_rfs_capable(bp))
 		features &= ~NETIF_F_NTUPLE;
@@ -9763,12 +9856,14 @@
 	/* Both CTAG and STAG VLAN accelaration on the RX side have to be
 	 * turned on or off together.
 	 */
-	if ((features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX)) !=
-	    (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX)) {
+	vlan_features = features & (NETIF_F_HW_VLAN_CTAG_RX |
+				    NETIF_F_HW_VLAN_STAG_RX);
+	if (vlan_features != (NETIF_F_HW_VLAN_CTAG_RX |
+			      NETIF_F_HW_VLAN_STAG_RX)) {
 		if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
 			features &= ~(NETIF_F_HW_VLAN_CTAG_RX |
 				      NETIF_F_HW_VLAN_STAG_RX);
-		else
+		else if (vlan_features)
 			features |= NETIF_F_HW_VLAN_CTAG_RX |
 				    NETIF_F_HW_VLAN_STAG_RX;
 	}
@@ -9927,12 +10022,15 @@
 	if (netif_running(bp->dev)) {
 		int rc;
 
-		if (!silent)
+		if (silent) {
+			bnxt_close_nic(bp, false, false);
+			bnxt_open_nic(bp, false, false);
+		} else {
 			bnxt_ulp_stop(bp);
-		bnxt_close_nic(bp, false, false);
-		rc = bnxt_open_nic(bp, false, false);
-		if (!silent && !rc)
-			bnxt_ulp_start(bp);
+			bnxt_close_nic(bp, true, false);
+			rc = bnxt_open_nic(bp, true, false);
+			bnxt_ulp_start(bp, rc);
+		}
 	}
 }
 
@@ -9950,8 +10048,7 @@
 	struct bnxt_fw_health *fw_health = bp->fw_health;
 	u32 val;
 
-	if (!fw_health || !fw_health->enabled ||
-	    test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
+	if (!fw_health->enabled || test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
 		return;
 
 	if (fw_health->tmr_counter) {
@@ -9982,7 +10079,7 @@
 	struct bnxt *bp = from_timer(bp, t, timer);
 	struct net_device *dev = bp->dev;
 
-	if (!netif_running(dev))
+	if (!netif_running(dev) || !test_bit(BNXT_STATE_OPEN, &bp->state))
 		return;
 
 	if (atomic_read(&bp->intr_sem) != 0)
@@ -10050,8 +10147,15 @@
 {
 	__bnxt_close_nic(bp, true, false);
 	bnxt_ulp_irq_stop(bp);
+	/* When firmware is fatal state, disable PCI device to prevent
+	 * any potential bad DMAs before freeing kernel memory.
+	 */
+	if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+		pci_disable_device(bp->pdev);
 	bnxt_clear_int_mode(bp);
 	bnxt_hwrm_func_drv_unrgtr(bp);
+	if (pci_is_enabled(bp->pdev))
+		pci_disable_device(bp->pdev);
 	bnxt_free_ctx_mem(bp);
 	kfree(bp->ctx);
 	bp->ctx = NULL;
@@ -10236,6 +10340,8 @@
 		bnxt_cfg_ntp_filters(bp);
 	if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event))
 		bnxt_hwrm_exec_fwd_req(bp);
+	if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event))
+		netdev_info(bp->dev, "Receive PF driver unload event!\n");
 	if (test_and_clear_bit(BNXT_VXLAN_ADD_PORT_SP_EVENT, &bp->sp_event)) {
 		bnxt_hwrm_tunnel_dst_port_alloc(
 			bp, bp->vxlan_port,
@@ -10412,6 +10518,23 @@
 	bp->stats_coal_ticks = BNXT_DEF_STATS_COAL_TICKS;
 }
 
+static void bnxt_alloc_fw_health(struct bnxt *bp)
+{
+	if (bp->fw_health)
+		return;
+
+	if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) &&
+	    !(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
+		return;
+
+	bp->fw_health = kzalloc(sizeof(*bp->fw_health), GFP_KERNEL);
+	if (!bp->fw_health) {
+		netdev_warn(bp->dev, "Failed to allocate fw_health\n");
+		bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
+		bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
+	}
+}
+
 static int bnxt_fw_init_one_p1(struct bnxt *bp)
 {
 	int rc;
@@ -10458,6 +10581,7 @@
 		netdev_warn(bp->dev, "hwrm query adv flow mgnt failure rc: %d\n",
 			    rc);
 
+	bnxt_alloc_fw_health(bp);
 	rc = bnxt_hwrm_error_recovery_qcfg(bp);
 	if (rc)
 		netdev_warn(bp->dev, "hwrm query error recovery failure rc: %d\n",
@@ -10526,6 +10650,8 @@
 	bnxt_hwrm_coal_params_qcaps(bp);
 }
 
+static int bnxt_probe_phy(struct bnxt *bp, bool fw_dflt);
+
 static int bnxt_fw_init_one(struct bnxt *bp)
 {
 	int rc;
@@ -10540,9 +10666,18 @@
 		netdev_err(bp->dev, "Firmware init phase 2 failed\n");
 		return rc;
 	}
+	rc = bnxt_probe_phy(bp, false);
+	if (rc)
+		return rc;
 	rc = bnxt_approve_mac(bp, bp->dev->dev_addr, false);
 	if (rc)
 		return rc;
+
+	/* In case fw capabilities have changed, destroy the unneeded
+	 * reporters and create newly capable ones.
+	 */
+	bnxt_dl_fw_reporters_destroy(bp, false);
+	bnxt_dl_fw_reporters_create(bp);
 	bnxt_fw_init_one_p3(bp);
 	return 0;
 }
@@ -10637,6 +10772,10 @@
 		}
 		bp->fw_reset_timestamp = jiffies;
 		rtnl_lock();
+		if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
+			rtnl_unlock();
+			goto fw_reset_abort;
+		}
 		bnxt_fw_reset_close(bp);
 		if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) {
 			bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW_DOWN;
@@ -10676,8 +10815,7 @@
 		bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);
 		return;
 	case BNXT_FW_RESET_STATE_ENABLE_DEV:
-		if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state) &&
-		    bp->fw_health) {
+		if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
 			u32 val;
 
 			val = bnxt_fw_health_readl(bp,
@@ -10769,7 +10907,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);
@@ -10862,13 +11001,13 @@
 	struct bnxt *bp = netdev_priv(dev);
 
 	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;
 }
@@ -10966,11 +11105,23 @@
 	struct flow_keys *keys1 = &f1->fkeys;
 	struct flow_keys *keys2 = &f2->fkeys;
 
-	if (keys1->addrs.v4addrs.src == keys2->addrs.v4addrs.src &&
-	    keys1->addrs.v4addrs.dst == keys2->addrs.v4addrs.dst &&
-	    keys1->ports.ports == keys2->ports.ports &&
-	    keys1->basic.ip_proto == keys2->basic.ip_proto &&
-	    keys1->basic.n_proto == keys2->basic.n_proto &&
+	if (keys1->basic.n_proto != keys2->basic.n_proto ||
+	    keys1->basic.ip_proto != keys2->basic.ip_proto)
+		return false;
+
+	if (keys1->basic.n_proto == htons(ETH_P_IP)) {
+		if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src ||
+		    keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst)
+			return false;
+	} else {
+		if (memcmp(&keys1->addrs.v6addrs.src, &keys2->addrs.v6addrs.src,
+			   sizeof(keys1->addrs.v6addrs.src)) ||
+		    memcmp(&keys1->addrs.v6addrs.dst, &keys2->addrs.v6addrs.dst,
+			   sizeof(keys1->addrs.v6addrs.dst)))
+			return false;
+	}
+
+	if (keys1->ports.ports == keys2->ports.ports &&
 	    keys1->control.flags == keys2->control.flags &&
 	    ether_addr_equal(f1->src_mac_addr, f2->src_mac_addr) &&
 	    ether_addr_equal(f1->dst_mac_addr, f2->dst_mac_addr))
@@ -11041,8 +11192,8 @@
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(fltr, head, hash) {
 		if (bnxt_fltr_match(fltr, new_fltr)) {
+			rc = fltr->sw_id;
 			rcu_read_unlock();
-			rc = 0;
 			goto err_free;
 		}
 	}
@@ -11117,8 +11268,6 @@
 			}
 		}
 	}
-	if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event))
-		netdev_info(bp->dev, "Receive PF driver unload event!");
 }
 
 #else
@@ -11262,7 +11411,7 @@
 		return -EOPNOTSUPP;
 
 	/* The PF and it's VF-reps only support the switchdev framework */
-	if (!BNXT_PF(bp))
+	if (!BNXT_PF(bp) || !(bp->flags & BNXT_FLAG_DSN_VALID))
 		return -EOPNOTSUPP;
 
 	ppid->id_len = sizeof(bp->switch_id);
@@ -11318,17 +11467,21 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct bnxt *bp = netdev_priv(dev);
 
-	if (BNXT_PF(bp)) {
+	if (BNXT_PF(bp))
 		bnxt_sriov_disable(bp);
-		bnxt_dl_unregister(bp);
-	}
 
 	pci_disable_pcie_error_reporting(pdev);
 	unregister_netdev(dev);
-	bnxt_shutdown_tc(bp);
-	bnxt_cancel_sp_work(bp);
+	clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
+	/* Flush any pending tasks */
+	cancel_work_sync(&bp->sp_task);
+	cancel_delayed_work_sync(&bp->fw_reset_task);
 	bp->sp_event = 0;
 
+	bnxt_dl_fw_reporters_destroy(bp, true);
+	bnxt_dl_unregister(bp);
+	bnxt_shutdown_tc(bp);
+
 	bnxt_clear_int_mode(bp);
 	bnxt_hwrm_func_drv_unrgtr(bp);
 	bnxt_free_hwrm_resources(bp);
@@ -11337,6 +11490,8 @@
 	bnxt_dcb_free(bp);
 	kfree(bp->edev);
 	bp->edev = NULL;
+	kfree(bp->fw_health);
+	bp->fw_health = NULL;
 	bnxt_cleanup_pci(bp);
 	bnxt_free_ctx_mem(bp);
 	kfree(bp->ctx);
@@ -11552,6 +11707,10 @@
 		bp->rx_nr_rings++;
 		bp->cp_nr_rings++;
 	}
+	if (rc) {
+		bp->tx_nr_rings = 0;
+		bp->rx_nr_rings = 0;
+	}
 	return rc;
 }
 
@@ -11574,10 +11733,9 @@
 		goto init_dflt_ring_err;
 
 	bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
-	if (bnxt_rfs_supported(bp) && bnxt_rfs_capable(bp)) {
-		bp->flags |= BNXT_FLAG_RFS;
-		bp->dev->features |= NETIF_F_NTUPLE;
-	}
+
+	bnxt_set_dflt_rfs(bp);
+
 init_dflt_ring_err:
 	bnxt_ulp_irq_restart(bp, rc);
 	return rc;
@@ -11652,6 +11810,7 @@
 	put_unaligned_le32(dw, &dsn[0]);
 	pci_read_config_dword(pdev, pos + 4, &dw);
 	put_unaligned_le32(dw, &dsn[4]);
+	bp->flags |= BNXT_FLAG_DSN_VALID;
 	return 0;
 }
 
@@ -11668,6 +11827,14 @@
 	if (version_printed++ == 0)
 		pr_info("%s", version);
 
+	/* Clear any pending DMA transactions from crash kernel
+	 * while loading driver in capture kernel.
+	 */
+	if (is_kdump_kernel()) {
+		pci_clear_master(pdev);
+		pcie_flr(pdev);
+	}
+
 	max_irqs = bnxt_get_max_irq(pdev);
 	dev = alloc_etherdev_mq(sizeof(*bp), max_irqs);
 	if (!dev)
@@ -11763,9 +11930,7 @@
 
 	if (BNXT_PF(bp)) {
 		/* Read the adapter's DSN to use as the eswitch switch_id */
-		rc = bnxt_pcie_dsn_get(bp, bp->switch_id);
-		if (rc)
-			goto init_err_pci_clean;
+		bnxt_pcie_dsn_get(bp, bp->switch_id);
 	}
 
 	/* MTU range: 60 - FW defined max */
@@ -11806,39 +11971,46 @@
 				create_singlethread_workqueue("bnxt_pf_wq");
 			if (!bnxt_pf_wq) {
 				dev_err(&pdev->dev, "Unable to create workqueue.\n");
+				rc = -ENOMEM;
 				goto init_err_pci_clean;
 			}
 		}
 		bnxt_init_tc(bp);
 	}
 
+	bnxt_dl_register(bp);
+
 	rc = register_netdev(dev);
 	if (rc)
-		goto init_err_cleanup_tc;
+		goto init_err_cleanup;
 
 	if (BNXT_PF(bp))
-		bnxt_dl_register(bp);
+		devlink_port_type_eth_set(&bp->dl_port, bp->dev);
+	bnxt_dl_fw_reporters_create(bp);
 
 	netdev_info(dev, "%s found at mem %lx, node addr %pM\n",
 		    board_info[ent->driver_data].name,
 		    (long)pci_resource_start(pdev, 0), dev->dev_addr);
 	pcie_print_link_status(pdev);
 
+	pci_save_state(pdev);
 	return 0;
 
-init_err_cleanup_tc:
+init_err_cleanup:
+	bnxt_dl_unregister(bp);
 	bnxt_shutdown_tc(bp);
 	bnxt_clear_int_mode(bp);
 
 init_err_pci_clean:
 	bnxt_free_hwrm_short_cmd_req(bp);
 	bnxt_free_hwrm_resources(bp);
-	bnxt_free_ctx_mem(bp);
-	kfree(bp->ctx);
-	bp->ctx = NULL;
+	bnxt_ethtool_free(bp);
 	kfree(bp->fw_health);
 	bp->fw_health = NULL;
 	bnxt_cleanup_pci(bp);
+	bnxt_free_ctx_mem(bp);
+	kfree(bp->ctx);
+	bp->ctx = NULL;
 
 init_err_free:
 	free_netdev(dev);
@@ -11862,10 +12034,10 @@
 		dev_close(dev);
 
 	bnxt_ulp_shutdown(bp);
+	bnxt_clear_int_mode(bp);
+	pci_disable_device(pdev);
 
 	if (system_state == SYSTEM_POWER_OFF) {
-		bnxt_clear_int_mode(bp);
-		pci_disable_device(pdev);
 		pci_wake_from_d3(pdev, bp->wol);
 		pci_set_power_state(pdev, PCI_D3hot);
 	}
@@ -11954,6 +12126,9 @@
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
+	if (state == pci_channel_io_frozen)
+		set_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state);
+
 	if (netif_running(netdev))
 		bnxt_close(netdev);
 
@@ -11977,7 +12152,7 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct bnxt *bp = netdev_priv(netdev);
-	int err = 0;
+	int err = 0, off;
 	pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
 
 	netdev_info(bp->dev, "PCI Slot Reset\n");
@@ -11989,23 +12164,41 @@
 			"Cannot re-enable PCI device after reset.\n");
 	} else {
 		pci_set_master(pdev);
+		/* Upon fatal error, our device internal logic that latches to
+		 * BAR value is getting reset and will restore only upon
+		 * rewritting the BARs.
+		 *
+		 * As pci_restore_state() does not re-write the BARs if the
+		 * value is same as saved value earlier, driver needs to
+		 * write the BARs to 0 to force restore, in case of fatal error.
+		 */
+		if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN,
+				       &bp->state)) {
+			for (off = PCI_BASE_ADDRESS_0;
+			     off <= PCI_BASE_ADDRESS_5; off += 4)
+				pci_write_config_dword(bp->pdev, off, 0);
+		}
+		pci_restore_state(pdev);
+		pci_save_state(pdev);
 
 		err = bnxt_hwrm_func_reset(bp);
 		if (!err && netif_running(netdev))
 			err = bnxt_open(netdev);
 
-		if (!err) {
+		if (!err)
 			result = PCI_ERS_RESULT_RECOVERED;
-			bnxt_ulp_start(bp);
-		}
+		bnxt_ulp_start(bp, err);
 	}
 
-	if (result != PCI_ERS_RESULT_RECOVERED && netif_running(netdev))
-		dev_close(netdev);
+	if (result != PCI_ERS_RESULT_RECOVERED) {
+		if (netif_running(netdev))
+			dev_close(netdev);
+		pci_disable_device(pdev);
+	}
 
 	rtnl_unlock();
 
-	return PCI_ERS_RESULT_RECOVERED;
+	return result;
 }
 
 /**
@@ -12047,8 +12240,16 @@
 
 static int __init bnxt_init(void)
 {
+	int err;
+
 	bnxt_debug_init();
-	return pci_register_driver(&bnxt_pci_driver);
+	err = pci_register_driver(&bnxt_pci_driver);
+	if (err) {
+		bnxt_debug_exit();
+		return err;
+	}
+
+	return 0;
 }
 
 static void __exit bnxt_exit(void)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -559,7 +559,8 @@
 #define BNXT_MAX_MTU		9500
 #define BNXT_MAX_PAGE_MODE_MTU	\
 	((unsigned int)PAGE_SIZE - VLAN_ETH_HLEN - NET_IP_ALIGN -	\
-	 XDP_PACKET_HEADROOM)
+	 XDP_PACKET_HEADROOM - \
+	 SKB_DATA_ALIGN((unsigned int)sizeof(struct skb_shared_info)))
 
 #define BNXT_MIN_PKT_SIZE	52
 
@@ -601,6 +602,11 @@
 #define BNXT_MAX_RX_JUM_DESC_CNT	(RX_DESC_CNT * MAX_RX_AGG_PAGES - 1)
 #define BNXT_MAX_TX_DESC_CNT		(TX_DESC_CNT * MAX_TX_PAGES - 1)
 
+/* Minimum TX BDs for a TX packet with MAX_SKB_FRAGS + 1.  We need one extra
+ * BD because the first TX BD is always a long BD.
+ */
+#define BNXT_MIN_TX_DESC_CNT		(MAX_SKB_FRAGS + 2)
+
 #define RX_RING(x)	(((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
 #define RX_IDX(x)	((x) & (RX_DESC_CNT - 1))
 
@@ -927,6 +933,7 @@
 	dma_addr_t		hw_stats_map;
 	u32			hw_stats_ctx_id;
 	u64			rx_l4_csum_errors;
+	u64			rx_buf_errors;
 	u64			missed_irqs;
 
 	struct bnxt_ring_struct	cp_ring_struct;
@@ -1057,7 +1064,6 @@
 #define BNXT_VF_LINK_FORCED	0x4
 #define BNXT_VF_LINK_UP		0x8
 #define BNXT_VF_TRUST		0x10
-	u32	func_flags; /* func cfg flags */
 	u32	min_tx_rate;
 	u32	max_tx_rate;
 	void	*hwrm_cmd_req_addr;
@@ -1509,6 +1515,7 @@
 	#define BNXT_FLAG_NO_AGG_RINGS	0x20000
 	#define BNXT_FLAG_RX_PAGE_MODE	0x40000
 	#define BNXT_FLAG_MULTI_HOST	0x100000
+	#define BNXT_FLAG_DSN_VALID	0x200000
 	#define BNXT_FLAG_DOUBLE_DB	0x400000
 	#define BNXT_FLAG_CHIP_NITRO_A0	0x1000000
 	#define BNXT_FLAG_DIM		0x2000000
@@ -1626,6 +1633,11 @@
 #define BNXT_STATE_IN_FW_RESET	4
 #define BNXT_STATE_ABORT_ERR	5
 #define BNXT_STATE_FW_FATAL_COND	6
+#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN	8
+
+#define BNXT_NO_FW_ACCESS(bp)					\
+	(test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) ||	\
+	 pci_channel_offline((bp)->pdev))
 
 	struct bnxt_irq	*irq_tbl;
 	int			total_irqs;
@@ -1657,6 +1669,7 @@
 	#define BNXT_FW_CAP_PCIE_STATS_SUPPORTED	0x00020000
 	#define BNXT_FW_CAP_EXT_STATS_SUPPORTED		0x00040000
 	#define BNXT_FW_CAP_ERR_RECOVER_RELOAD		0x00100000
+	#define BNXT_FW_CAP_HOT_RESET			0x00200000
 
 #define BNXT_NEW_RM(bp)		((bp)->fw_cap & BNXT_FW_CAP_NEW_RM)
 	u32			hwrm_spec_code;
@@ -1685,7 +1698,7 @@
 	u16			fw_rx_stats_ext_size;
 	u16			fw_tx_stats_ext_size;
 	u16			hw_ring_stats_size;
-	u8			pri2cos[8];
+	u8			pri2cos_idx[8];
 	u8			pri2cos_valid;
 
 	u16			hwrm_max_req_len;
@@ -1902,9 +1915,6 @@
 	case HWRM_CFA_ENCAP_RECORD_FREE:
 	case HWRM_CFA_DECAP_FILTER_ALLOC:
 	case HWRM_CFA_DECAP_FILTER_FREE:
-	case HWRM_CFA_NTUPLE_FILTER_ALLOC:
-	case HWRM_CFA_NTUPLE_FILTER_FREE:
-	case HWRM_CFA_NTUPLE_FILTER_CFG:
 	case HWRM_CFA_EM_FLOW_ALLOC:
 	case HWRM_CFA_EM_FLOW_FREE:
 	case HWRM_CFA_EM_FLOW_CFG:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -479,24 +479,26 @@
 {
 	struct bnxt *bp = netdev_priv(dev);
 	struct ieee_ets *my_ets = bp->ieee_ets;
+	int rc;
 
 	ets->ets_cap = bp->max_tc;
 
 	if (!my_ets) {
-		int rc;
-
 		if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
 			return 0;
 
 		my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
 		if (!my_ets)
-			return 0;
+			return -ENOMEM;
 		rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets);
 		if (rc)
-			return 0;
+			goto error;
 		rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets);
 		if (rc)
-			return 0;
+			goto error;
+
+		/* cache result */
+		bp->ieee_ets = my_ets;
 	}
 
 	ets->cbs = my_ets->cbs;
@@ -505,6 +507,9 @@
 	memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
 	memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
 	return 0;
+error:
+	kfree(my_ets);
+	return rc;
 }
 
 static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -19,11 +19,10 @@
 				     struct devlink_fmsg *fmsg)
 {
 	struct bnxt *bp = devlink_health_reporter_priv(reporter);
-	struct bnxt_fw_health *health = bp->fw_health;
 	u32 val, health_status;
 	int rc;
 
-	if (!health || test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
+	if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
 		return 0;
 
 	val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
@@ -103,21 +102,15 @@
 	.recover = bnxt_fw_fatal_recover,
 };
 
-static void bnxt_dl_fw_reporters_create(struct bnxt *bp)
+void bnxt_dl_fw_reporters_create(struct bnxt *bp)
 {
 	struct bnxt_fw_health *health = bp->fw_health;
 
-	if (!health)
+	if (!bp->dl || !health)
 		return;
 
-	health->fw_reporter =
-		devlink_health_reporter_create(bp->dl, &bnxt_dl_fw_reporter_ops,
-					       0, false, bp);
-	if (IS_ERR(health->fw_reporter)) {
-		netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
-			    PTR_ERR(health->fw_reporter));
-		health->fw_reporter = NULL;
-	}
+	if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
+		goto err_recovery;
 
 	health->fw_reset_reporter =
 		devlink_health_reporter_create(bp->dl,
@@ -127,8 +120,30 @@
 		netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
 			    PTR_ERR(health->fw_reset_reporter));
 		health->fw_reset_reporter = NULL;
+		bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
+	}
+
+err_recovery:
+	if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
+		return;
+
+	if (!health->fw_reporter) {
+		health->fw_reporter =
+			devlink_health_reporter_create(bp->dl,
+						       &bnxt_dl_fw_reporter_ops,
+						       0, false, bp);
+		if (IS_ERR(health->fw_reporter)) {
+			netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
+				    PTR_ERR(health->fw_reporter));
+			health->fw_reporter = NULL;
+			bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
+			return;
+		}
 	}
 
+	if (health->fw_fatal_reporter)
+		return;
+
 	health->fw_fatal_reporter =
 		devlink_health_reporter_create(bp->dl,
 					       &bnxt_dl_fw_fatal_reporter_ops,
@@ -137,24 +152,35 @@
 		netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
 			    PTR_ERR(health->fw_fatal_reporter));
 		health->fw_fatal_reporter = NULL;
+		bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
 	}
 }
 
-static void bnxt_dl_fw_reporters_destroy(struct bnxt *bp)
+void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
 {
 	struct bnxt_fw_health *health = bp->fw_health;
 
-	if (!health)
+	if (!bp->dl || !health)
 		return;
 
-	if (health->fw_reporter)
-		devlink_health_reporter_destroy(health->fw_reporter);
-
-	if (health->fw_reset_reporter)
+	if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
+	    health->fw_reset_reporter) {
 		devlink_health_reporter_destroy(health->fw_reset_reporter);
+		health->fw_reset_reporter = NULL;
+	}
 
-	if (health->fw_fatal_reporter)
+	if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
+		return;
+
+	if (health->fw_reporter) {
+		devlink_health_reporter_destroy(health->fw_reporter);
+		health->fw_reporter = NULL;
+	}
+
+	if (health->fw_fatal_reporter) {
 		devlink_health_reporter_destroy(health->fw_fatal_reporter);
+		health->fw_fatal_reporter = NULL;
+	}
 }
 
 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
@@ -162,9 +188,6 @@
 	struct bnxt_fw_health *fw_health = bp->fw_health;
 	struct bnxt_fw_reporter_ctx fw_reporter_ctx;
 
-	if (!fw_health)
-		return;
-
 	fw_reporter_ctx.sp_event = event;
 	switch (event) {
 	case BNXT_FW_RESET_NOTIFY_SP_EVENT:
@@ -203,6 +226,8 @@
 #endif /* CONFIG_BNXT_SRIOV */
 };
 
+static const struct devlink_ops bnxt_vf_dl_ops;
+
 enum bnxt_dl_param_id {
 	BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
 	BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
@@ -311,10 +336,17 @@
 	} else {
 		rc = hwrm_send_message_silent(bp, msg, msg_len,
 					      HWRM_CMD_TIMEOUT);
-		if (!rc)
+		if (!rc) {
 			bnxt_copy_from_nvm_data(val, data,
 						nvm_param.nvm_num_bits,
 						nvm_param.dl_num_bytes);
+		} else {
+			struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
+
+			if (resp->cmd_err ==
+				NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
+				rc = -EOPNOTSUPP;
+		}
 	}
 	dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
 	if (rc == -EACCES)
@@ -409,7 +441,10 @@
 		return -ENOTSUPP;
 	}
 
-	dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
+	if (BNXT_PF(bp))
+		dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
+	else
+		dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
 	if (!dl) {
 		netdev_warn(bp->dev, "devlink_alloc failed");
 		return -ENOMEM;
@@ -428,6 +463,9 @@
 		goto err_dl_free;
 	}
 
+	if (!BNXT_PF(bp))
+		return 0;
+
 	rc = devlink_params_register(dl, bnxt_dl_params,
 				     ARRAY_SIZE(bnxt_dl_params));
 	if (rc) {
@@ -444,7 +482,6 @@
 		netdev_err(bp->dev, "devlink_port_register failed");
 		goto err_dl_param_unreg;
 	}
-	devlink_port_type_eth_set(&bp->dl_port, bp->dev);
 
 	rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
 					  ARRAY_SIZE(bnxt_dl_port_params));
@@ -455,8 +492,6 @@
 
 	devlink_params_publish(dl);
 
-	bnxt_dl_fw_reporters_create(bp);
-
 	return 0;
 
 err_dl_port_unreg:
@@ -479,12 +514,14 @@
 	if (!dl)
 		return;
 
-	bnxt_dl_fw_reporters_destroy(bp);
-	devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
-				       ARRAY_SIZE(bnxt_dl_port_params));
-	devlink_port_unregister(&bp->dl_port);
-	devlink_params_unregister(dl, bnxt_dl_params,
-				  ARRAY_SIZE(bnxt_dl_params));
+	if (BNXT_PF(bp)) {
+		devlink_port_params_unregister(&bp->dl_port,
+					       bnxt_dl_port_params,
+					       ARRAY_SIZE(bnxt_dl_port_params));
+		devlink_port_unregister(&bp->dl_port);
+		devlink_params_unregister(dl, bnxt_dl_params,
+					  ARRAY_SIZE(bnxt_dl_params));
+	}
 	devlink_unregister(dl);
 	devlink_free(dl);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
@@ -39,7 +39,7 @@
 #define NVM_OFF_DIS_GRE_VER_CHECK	171
 #define NVM_OFF_ENABLE_SRIOV		401
 
-#define BNXT_MSIX_VEC_MAX	1280
+#define BNXT_MSIX_VEC_MAX	512
 #define BNXT_MSIX_VEC_MIN_MAX	128
 
 enum bnxt_nvm_dir_type {
@@ -57,6 +57,8 @@
 };
 
 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event);
+void bnxt_dl_fw_reporters_create(struct bnxt *bp);
+void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all);
 int bnxt_dl_register(struct bnxt *bp);
 void bnxt_dl_unregister(struct bnxt *bp);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -124,7 +124,7 @@
 	}
 
 reset_coalesce:
-	if (netif_running(dev)) {
+	if (test_bit(BNXT_STATE_OPEN, &bp->state)) {
 		if (update_stats) {
 			rc = bnxt_close_nic(bp, true, false);
 			if (!rc)
@@ -173,6 +173,7 @@
 
 static const char * const bnxt_ring_sw_stats_str[] = {
 	"rx_l4_csum_errors",
+	"rx_buf_errors",
 	"missed_irqs",
 };
 
@@ -552,6 +553,7 @@
 		for (k = 0; k < stat_fields; j++, k++)
 			buf[j] = le64_to_cpu(hw_stats[k]);
 		buf[j++] = cpr->rx_l4_csum_errors;
+		buf[j++] = cpr->rx_buf_errors;
 		buf[j++] = cpr->missed_irqs;
 
 		bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter +=
@@ -587,25 +589,25 @@
 		if (bp->pri2cos_valid) {
 			for (i = 0; i < 8; i++, j++) {
 				long n = bnxt_rx_bytes_pri_arr[i].base_off +
-					 bp->pri2cos[i];
+					 bp->pri2cos_idx[i];
 
 				buf[j] = le64_to_cpu(*(rx_port_stats_ext + n));
 			}
 			for (i = 0; i < 8; i++, j++) {
 				long n = bnxt_rx_pkts_pri_arr[i].base_off +
-					 bp->pri2cos[i];
+					 bp->pri2cos_idx[i];
 
 				buf[j] = le64_to_cpu(*(rx_port_stats_ext + n));
 			}
 			for (i = 0; i < 8; i++, j++) {
 				long n = bnxt_tx_bytes_pri_arr[i].base_off +
-					 bp->pri2cos[i];
+					 bp->pri2cos_idx[i];
 
 				buf[j] = le64_to_cpu(*(tx_port_stats_ext + n));
 			}
 			for (i = 0; i < 8; i++, j++) {
 				long n = bnxt_tx_pkts_pri_arr[i].base_off +
-					 bp->pri2cos[i];
+					 bp->pri2cos_idx[i];
 
 				buf[j] = le64_to_cpu(*(tx_port_stats_ext + n));
 			}
@@ -742,7 +744,7 @@
 
 	if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
 	    (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
-	    (ering->tx_pending <= MAX_SKB_FRAGS))
+	    (ering->tx_pending < BNXT_MIN_TX_DESC_CNT))
 		return -EINVAL;
 
 	if (netif_running(dev))
@@ -767,7 +769,7 @@
 	int max_tx_sch_inputs;
 
 	/* Get the most up-to-date max_tx_sch_inputs. */
-	if (BNXT_NEW_RM(bp))
+	if (netif_running(dev) && BNXT_NEW_RM(bp))
 		bnxt_hwrm_func_resc_qcaps(bp, false);
 	max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;
 
@@ -1663,14 +1665,15 @@
 	if (!BNXT_SINGLE_PF(bp))
 		return -EOPNOTSUPP;
 
+	mutex_lock(&bp->link_lock);
 	if (epause->autoneg) {
-		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
-			return -EINVAL;
+		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
+			rc = -EINVAL;
+			goto pause_exit;
+		}
 
 		link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
-		if (bp->hwrm_spec_code >= 0x10201)
-			link_info->req_flow_ctrl =
-				PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE;
+		link_info->req_flow_ctrl = 0;
 	} else {
 		/* when transition from auto pause to force pause,
 		 * force a link change
@@ -1688,6 +1691,9 @@
 
 	if (netif_running(dev))
 		rc = bnxt_hwrm_set_pause(bp);
+
+pause_exit:
+	mutex_unlock(&bp->link_lock);
 	return rc;
 }
 
@@ -2003,8 +2009,8 @@
 	struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr;
 	struct hwrm_nvm_install_update_input install = {0};
 	const struct firmware *fw;
-	int rc, hwrm_err = 0;
 	u32 item_len;
+	int rc = 0;
 	u16 index;
 
 	bnxt_hwrm_fw_set_time(bp);
@@ -2048,15 +2054,14 @@
 			memcpy(kmem, fw->data, fw->size);
 			modify.host_src_addr = cpu_to_le64(dma_handle);
 
-			hwrm_err = hwrm_send_message(bp, &modify,
-						     sizeof(modify),
-						     FLASH_PACKAGE_TIMEOUT);
+			rc = hwrm_send_message(bp, &modify, sizeof(modify),
+					       FLASH_PACKAGE_TIMEOUT);
 			dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
 					  dma_handle);
 		}
 	}
 	release_firmware(fw);
-	if (rc || hwrm_err)
+	if (rc)
 		goto err_exit;
 
 	if ((install_type & 0xffff) == 0)
@@ -2065,20 +2070,19 @@
 	install.install_type = cpu_to_le32(install_type);
 
 	mutex_lock(&bp->hwrm_cmd_lock);
-	hwrm_err = _hwrm_send_message(bp, &install, sizeof(install),
-				      INSTALL_PACKAGE_TIMEOUT);
-	if (hwrm_err) {
+	rc = _hwrm_send_message(bp, &install, sizeof(install),
+				INSTALL_PACKAGE_TIMEOUT);
+	if (rc) {
 		u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
 
 		if (resp->error_code && error_code ==
 		    NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
 			install.flags |= cpu_to_le16(
 			       NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
-			hwrm_err = _hwrm_send_message(bp, &install,
-						      sizeof(install),
-						      INSTALL_PACKAGE_TIMEOUT);
+			rc = _hwrm_send_message(bp, &install, sizeof(install),
+						INSTALL_PACKAGE_TIMEOUT);
 		}
-		if (hwrm_err)
+		if (rc)
 			goto flash_pkg_exit;
 	}
 
@@ -2090,7 +2094,7 @@
 flash_pkg_exit:
 	mutex_unlock(&bp->hwrm_cmd_lock);
 err_exit:
-	if (hwrm_err == -EACCES)
+	if (rc == -EACCES)
 		bnxt_print_admin_err(bp);
 	return rc;
 }
@@ -2158,6 +2162,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;
@@ -2391,8 +2398,7 @@
 	struct bnxt *bp = netdev_priv(dev);
 	struct ethtool_eee *eee = &bp->eee;
 	struct bnxt_link_info *link_info = &bp->link_info;
-	u32 advertising =
-		 _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
+	u32 advertising;
 	int rc = 0;
 
 	if (!BNXT_SINGLE_PF(bp))
@@ -2401,19 +2407,23 @@
 	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
 		return -EOPNOTSUPP;
 
+	mutex_lock(&bp->link_lock);
+	advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
 	if (!edata->eee_enabled)
 		goto eee_ok;
 
 	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
 		netdev_warn(dev, "EEE requires autoneg\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto eee_exit;
 	}
 	if (edata->tx_lpi_enabled) {
 		if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
 				       edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
 			netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
 				    bp->lpi_tmr_lo, bp->lpi_tmr_hi);
-			return -EINVAL;
+			rc = -EINVAL;
+			goto eee_exit;
 		} else if (!bp->lpi_tmr_hi) {
 			edata->tx_lpi_timer = eee->tx_lpi_timer;
 		}
@@ -2423,7 +2433,8 @@
 	} else if (edata->advertised & ~advertising) {
 		netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
 			    edata->advertised, advertising);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto eee_exit;
 	}
 
 	eee->advertised = edata->advertised;
@@ -2435,6 +2446,8 @@
 	if (netif_running(dev))
 		rc = bnxt_hwrm_set_link_setting(bp, false, true);
 
+eee_exit:
+	mutex_unlock(&bp->link_lock);
 	return rc;
 }
 
@@ -2569,7 +2582,7 @@
 	/* Read A2 portion of the EEPROM */
 	if (length) {
 		start -= ETH_MODULE_SFF_8436_LEN;
-		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1,
+		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0,
 						      start, length, data);
 	}
 	return rc;
@@ -3062,8 +3075,15 @@
 			}
 		}
 
-		if (info->dest_buf)
-			memcpy(info->dest_buf + off, dma_buf, len);
+		if (info->dest_buf) {
+			if ((info->seg_start + off + len) <=
+			    BNXT_COREDUMP_BUF_LEN(info->buf_len)) {
+				memcpy(info->dest_buf + off, dma_buf, len);
+			} else {
+				rc = -ENOBUFS;
+				break;
+			}
+		}
 
 		if (cmn_req->req_type ==
 				cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
@@ -3117,7 +3137,7 @@
 
 static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
 					   u16 segment_id, u32 *seg_len,
-					   void *buf, u32 offset)
+					   void *buf, u32 buf_len, u32 offset)
 {
 	struct hwrm_dbg_coredump_retrieve_input req = {0};
 	struct bnxt_hwrm_dbg_dma_info info = {NULL};
@@ -3132,8 +3152,11 @@
 				seq_no);
 	info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output,
 				     data_len);
-	if (buf)
+	if (buf) {
 		info.dest_buf = buf + offset;
+		info.buf_len = buf_len;
+		info.seg_start = offset;
+	}
 
 	rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info);
 	if (!rc)
@@ -3223,14 +3246,17 @@
 static int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
 {
 	u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output);
+	u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0;
 	struct coredump_segment_record *seg_record = NULL;
-	u32 offset = 0, seg_hdr_len, seg_record_len;
 	struct bnxt_coredump_segment_hdr seg_hdr;
 	struct bnxt_coredump coredump = {NULL};
 	time64_t start_time;
 	u16 start_utc;
 	int rc = 0, i;
 
+	if (buf)
+		buf_len = *dump_len;
+
 	start_time = ktime_get_real_seconds();
 	start_utc = sys_tz.tz_minuteswest * 60;
 	seg_hdr_len = sizeof(seg_hdr);
@@ -3263,6 +3289,12 @@
 		u32 duration = 0, seg_len = 0;
 		unsigned long start, end;
 
+		if (buf && ((offset + seg_hdr_len) >
+			    BNXT_COREDUMP_BUF_LEN(buf_len))) {
+			rc = -ENOBUFS;
+			goto err;
+		}
+
 		start = jiffies;
 
 		rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id);
@@ -3275,9 +3307,11 @@
 
 		/* Write segment data into the buffer */
 		rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id,
-						     &seg_len, buf,
+						     &seg_len, buf, buf_len,
 						     offset + seg_hdr_len);
-		if (rc)
+		if (rc && rc == -ENOBUFS)
+			goto err;
+		else if (rc)
 			netdev_err(bp->dev,
 				   "Failed to retrieve coredump for seg = %d\n",
 				   seg_record->segment_id);
@@ -3307,7 +3341,8 @@
 					  rc);
 	kfree(coredump.data);
 	*dump_len += sizeof(struct bnxt_coredump_record);
-
+	if (rc == -ENOBUFS)
+		netdev_err(bp->dev, "Firmware returned large coredump buffer");
 	return rc;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
@@ -31,6 +31,8 @@
 	u16		total_segs;
 };
 
+#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record))
+
 struct bnxt_hwrm_dbg_dma_info {
 	void *dest_buf;
 	int dest_buf_size;
@@ -38,6 +40,8 @@
 	u16 seq_off;
 	u16 data_len_off;
 	u16 segs;
+	u32 seg_start;
+	u32 buf_len;
 };
 
 struct hwrm_dbg_cmn_input {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -85,11 +85,10 @@
 	if (old_setting == setting)
 		return 0;
 
-	func_flags = vf->func_flags;
 	if (setting)
-		func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE;
+		func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE;
 	else
-		func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE;
+		func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE;
 	/*TODO: if the driver supports VLAN filter on guest VLAN,
 	 * the spoof check should also include vlan anti-spoofing
 	 */
@@ -98,7 +97,6 @@
 	req.flags = cpu_to_le32(func_flags);
 	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 	if (!rc) {
-		vf->func_flags = func_flags;
 		if (setting)
 			vf->flags |= BNXT_VF_SPOOFCHK;
 		else
@@ -230,7 +228,6 @@
 	memcpy(vf->mac_addr, mac, ETH_ALEN);
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
 	req.fid = cpu_to_le16(vf->fw_fid);
-	req.flags = cpu_to_le32(vf->func_flags);
 	req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR);
 	memcpy(req.dflt_mac_addr, mac, ETH_ALEN);
 	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
@@ -268,7 +265,6 @@
 
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
 	req.fid = cpu_to_le16(vf->fw_fid);
-	req.flags = cpu_to_le32(vf->func_flags);
 	req.dflt_vlan = cpu_to_le16(vlan_tag);
 	req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN);
 	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
@@ -307,7 +303,6 @@
 		return 0;
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
 	req.fid = cpu_to_le16(vf->fw_fid);
-	req.flags = cpu_to_le32(vf->func_flags);
 	req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW);
 	req.max_bw = cpu_to_le32(max_tx_rate);
 	req.enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MIN_BW);
@@ -403,6 +398,7 @@
 		}
 	}
 
+	bp->pf.active_vfs = 0;
 	kfree(bp->pf.vf);
 	bp->pf.vf = NULL;
 }
@@ -479,7 +475,6 @@
 	vf = &bp->pf.vf[vf_id];
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
 	req.fid = cpu_to_le16(vf->fw_fid);
-	req.flags = cpu_to_le32(vf->func_flags);
 
 	if (is_valid_ether_addr(vf->mac_addr)) {
 		req.enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR);
@@ -602,7 +597,7 @@
 		hw_resc->max_stat_ctxs -= le16_to_cpu(req.min_stat_ctx) * n;
 		hw_resc->max_vnics -= le16_to_cpu(req.min_vnics) * n;
 		if (bp->flags & BNXT_FLAG_CHIP_P5)
-			hw_resc->max_irqs -= vf_msix * n;
+			hw_resc->max_nqs -= vf_msix;
 
 		rc = pf->active_vfs;
 	}
@@ -839,7 +834,6 @@
 
 	bnxt_free_vf_resources(bp);
 
-	bp->pf.active_vfs = 0;
 	/* Reclaim all resources for the PF. */
 	rtnl_lock();
 	bnxt_restore_pf_fw_resources(bp);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -113,8 +113,10 @@
 {
 	struct net_device *dev = edev->net;
 	struct bnxt *bp = netdev_priv(dev);
+	struct bnxt_hw_resc *hw_resc;
 	int max_idx, max_cp_rings;
 	int avail_msix, idx;
+	int total_vecs;
 	int rc = 0;
 
 	ASSERT_RTNL();
@@ -142,7 +144,10 @@
 	}
 	edev->ulp_tbl[ulp_id].msix_base = idx;
 	edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
-	if (bp->total_irqs < (idx + avail_msix)) {
+	hw_resc = &bp->hw_resc;
+	total_vecs = idx + avail_msix;
+	if (bp->total_irqs < total_vecs ||
+	    (BNXT_NEW_RM(bp) && hw_resc->resv_irqs < total_vecs)) {
 		if (netif_running(dev)) {
 			bnxt_close_nic(bp, true, false);
 			rc = bnxt_open_nic(bp, true, false);
@@ -156,7 +161,6 @@
 	}
 
 	if (BNXT_NEW_RM(bp)) {
-		struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
 		int resv_msix;
 
 		resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
@@ -182,7 +186,7 @@
 
 	edev->ulp_tbl[ulp_id].msix_requested = 0;
 	edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
-	if (netif_running(dev)) {
+	if (netif_running(dev) && !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
 		bnxt_close_nic(bp, true, false);
 		bnxt_open_nic(bp, true, false);
 	}
@@ -212,8 +216,12 @@
 
 int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
 {
-	if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP))
-		return BNXT_MIN_ROCE_STAT_CTXS;
+	if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
+		struct bnxt_en_dev *edev = bp->edev;
+
+		if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
+			return BNXT_MIN_ROCE_STAT_CTXS;
+	}
 
 	return 0;
 }
@@ -266,6 +274,7 @@
 	if (!edev)
 		return;
 
+	edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
 	for (i = 0; i < BNXT_MAX_ULP; i++) {
 		struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 
@@ -276,7 +285,7 @@
 	}
 }
 
-void bnxt_ulp_start(struct bnxt *bp)
+void bnxt_ulp_start(struct bnxt *bp, int err)
 {
 	struct bnxt_en_dev *edev = bp->edev;
 	struct bnxt_ulp_ops *ops;
@@ -285,6 +294,11 @@
 	if (!edev)
 		return;
 
+	edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
+
+	if (err)
+		return;
+
 	for (i = 0; i < BNXT_MAX_ULP; i++) {
 		struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
 
@@ -459,13 +473,14 @@
 		if (!edev)
 			return ERR_PTR(-ENOMEM);
 		edev->en_ops = &bnxt_en_ops_tbl;
-		if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
-			edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
-		if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
-			edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
 		edev->net = dev;
 		edev->pdev = bp->pdev;
 		bp->edev = edev;
 	}
+	edev->flags &= ~BNXT_EN_FLAG_ROCE_CAP;
+	if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
+		edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
+	if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
+		edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
 	return bp->edev;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
@@ -64,6 +64,7 @@
 	#define BNXT_EN_FLAG_ROCE_CAP		(BNXT_EN_FLAG_ROCEV1_CAP | \
 						 BNXT_EN_FLAG_ROCEV2_CAP)
 	#define BNXT_EN_FLAG_MSIX_REQUESTED	0x4
+	#define BNXT_EN_FLAG_ULP_STOPPED	0x8
 	const struct bnxt_en_ops	*en_ops;
 	struct bnxt_ulp			ulp_tbl[BNXT_MAX_ULP];
 };
@@ -92,7 +93,7 @@
 int bnxt_get_ulp_msix_base(struct bnxt *bp);
 int bnxt_get_ulp_stat_ctxs(struct bnxt *bp);
 void bnxt_ulp_stop(struct bnxt *bp);
-void bnxt_ulp_start(struct bnxt *bp);
+void bnxt_ulp_start(struct bnxt *bp, int err);
 void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs);
 void bnxt_ulp_shutdown(struct bnxt *bp);
 void bnxt_ulp_irq_stop(struct bnxt *bp);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -398,6 +398,9 @@
 	struct net_device *dev;
 	int rc, i;
 
+	if (!(bp->flags & BNXT_FLAG_DSN_VALID))
+		return -ENODEV;
+
 	bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL);
 	if (!bp->vf_reps)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -69,6 +69,9 @@
 #define GENET_RDMA_REG_OFF	(priv->hw_params->rdma_offset + \
 				TOTAL_DESC * DMA_DESC_SIZE)
 
+/* Forward declarations */
+static void bcmgenet_set_rx_mode(struct net_device *dev);
+
 static inline void bcmgenet_writel(u32 value, void __iomem *offset)
 {
 	/* MIPS chips strapped for BE will automagically configure the
@@ -995,6 +998,8 @@
 	if (netif_running(dev))
 		bcmgenet_update_mib_counters(priv);
 
+	dev->netdev_ops->ndo_get_stats(dev);
+
 	for (i = 0; i < BCMGENET_STATS_LEN; i++) {
 		const struct bcmgenet_stats *s;
 		char *p;
@@ -1013,7 +1018,8 @@
 	}
 }
 
-static void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
+			     bool tx_lpi_enabled)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	u32 off = priv->hw_params->tbuf_offset + TBUF_ENERGY_CTRL;
@@ -1033,7 +1039,7 @@
 
 	/* Enable EEE and switch to a 27Mhz clock automatically */
 	reg = bcmgenet_readl(priv->base + off);
-	if (enable)
+	if (tx_lpi_enabled)
 		reg |= TBUF_EEE_EN | TBUF_PM_EN;
 	else
 		reg &= ~(TBUF_EEE_EN | TBUF_PM_EN);
@@ -1054,6 +1060,7 @@
 
 	priv->eee.eee_enabled = enable;
 	priv->eee.eee_active = enable;
+	priv->eee.tx_lpi_enabled = tx_lpi_enabled;
 }
 
 static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e)
@@ -1069,6 +1076,7 @@
 
 	e->eee_enabled = p->eee_enabled;
 	e->eee_active = p->eee_active;
+	e->tx_lpi_enabled = p->tx_lpi_enabled;
 	e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER);
 
 	return phy_ethtool_get_eee(dev->phydev, e);
@@ -1078,7 +1086,6 @@
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	struct ethtool_eee *p = &priv->eee;
-	int ret = 0;
 
 	if (GENET_IS_V1(priv))
 		return -EOPNOTSUPP;
@@ -1089,16 +1096,11 @@
 	p->eee_enabled = e->eee_enabled;
 
 	if (!p->eee_enabled) {
-		bcmgenet_eee_enable_set(dev, false);
+		bcmgenet_eee_enable_set(dev, false, false);
 	} else {
-		ret = phy_init_eee(dev->phydev, 0);
-		if (ret) {
-			netif_err(priv, hw, dev, "EEE initialization failed\n");
-			return ret;
-		}
-
+		p->eee_active = phy_init_eee(dev->phydev, false) >= 0;
 		bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
-		bcmgenet_eee_enable_set(dev, true);
+		bcmgenet_eee_enable_set(dev, p->eee_active, e->tx_lpi_enabled);
 	}
 
 	return phy_ethtool_set_eee(dev->phydev, e);
@@ -1182,7 +1184,8 @@
 
 	switch (mode) {
 	case GENET_POWER_PASSIVE:
-		reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+		reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS |
+			 EXT_ENERGY_DET_MASK);
 		if (GENET_IS_V5(priv)) {
 			reg &= ~(EXT_PWR_DOWN_PHY_EN |
 				 EXT_PWR_DOWN_PHY_RD |
@@ -1541,6 +1544,11 @@
 	return skb;
 }
 
+static void bcmgenet_hide_tsb(struct sk_buff *skb)
+{
+	__skb_pull(skb, sizeof(struct status_64));
+}
+
 static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
@@ -1586,11 +1594,6 @@
 		goto out;
 	}
 
-	if (skb_padto(skb, ETH_ZLEN)) {
-		ret = NETDEV_TX_OK;
-		goto out;
-	}
-
 	/* Retain how many bytes will be sent on the wire, without TSB inserted
 	 * by transmit checksum offload
 	 */
@@ -1639,8 +1642,13 @@
 		len_stat = (size << DMA_BUFLENGTH_SHIFT) |
 			   (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT);
 
+		/* Note: if we ever change from DMA_TX_APPEND_CRC below we
+		 * will need to restore software padding of "runt" packets
+		 */
+		len_stat |= DMA_TX_APPEND_CRC;
+
 		if (!i) {
-			len_stat |= DMA_TX_APPEND_CRC | DMA_SOP;
+			len_stat |= DMA_SOP;
 			if (skb->ip_summed == CHECKSUM_PARTIAL)
 				len_stat |= DMA_TX_DO_CSUM;
 		}
@@ -1651,6 +1659,8 @@
 	}
 
 	GENET_CB(skb)->last_cb = tx_cb_ptr;
+
+	bcmgenet_hide_tsb(skb);
 	skb_tx_timestamp(skb);
 
 	/* Decrement total BD count and advance our write pointer */
@@ -1695,7 +1705,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,
@@ -1811,6 +1822,14 @@
 			  __func__, p_index, ring->c_index,
 			  ring->read_ptr, dma_length_status);
 
+		if (unlikely(len > RX_BUF_LENGTH)) {
+			netif_err(priv, rx_status, dev, "oversized packet\n");
+			dev->stats.rx_length_errors++;
+			dev->stats.rx_errors++;
+			dev_kfree_skb_any(skb);
+			goto next;
+		}
+
 		if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
 			netif_err(priv, rx_status, dev,
 				  "dropping fragmented packet!\n");
@@ -2164,8 +2183,8 @@
 				  DMA_END_ADDR);
 
 	/* Initialize Tx NAPI */
-	netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll,
-		       NAPI_POLL_WEIGHT);
+	netif_tx_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll,
+			  NAPI_POLL_WEIGHT);
 }
 
 /* Initialize a RDMA ring */
@@ -2779,15 +2798,21 @@
 /* Returns a reusable dma control register value */
 static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv)
 {
+	unsigned int i;
 	u32 reg;
 	u32 dma_ctrl;
 
 	/* disable DMA */
 	dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+	for (i = 0; i < priv->hw_params->tx_queues; i++)
+		dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT));
 	reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
 	reg &= ~dma_ctrl;
 	bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
 
+	dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+	for (i = 0; i < priv->hw_params->rx_queues; i++)
+		dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT));
 	reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
 	reg &= ~dma_ctrl;
 	bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
@@ -2849,6 +2874,7 @@
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 
 	/* Start the network engine */
+	bcmgenet_set_rx_mode(dev);
 	bcmgenet_enable_rx_napi(priv);
 
 	umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
@@ -2890,12 +2916,6 @@
 
 	bcmgenet_set_hw_addr(priv, dev->dev_addr);
 
-	if (priv->internal_phy) {
-		reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-		reg |= EXT_ENERGY_DET_MASK;
-		bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-	}
-
 	/* Disable RX/TX DMA and flush TX queues */
 	dma_ctrl = bcmgenet_dma_disable(priv);
 
@@ -2952,7 +2972,7 @@
 	return ret;
 }
 
-static void bcmgenet_netif_stop(struct net_device *dev)
+static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 
@@ -2967,7 +2987,8 @@
 	/* Disable MAC transmit. TX DMA disabled must be done before this */
 	umac_enable_set(priv, CMD_TX_EN, false);
 
-	phy_stop(dev->phydev);
+	if (stop_phy)
+		phy_stop(dev->phydev);
 	bcmgenet_disable_rx_napi(priv);
 	bcmgenet_intr_disable(priv);
 
@@ -2993,7 +3014,7 @@
 
 	netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
 
-	bcmgenet_netif_stop(dev);
+	bcmgenet_netif_stop(dev, false);
 
 	/* Really kill the PHY state machine and disconnect from it */
 	phy_disconnect(dev->phydev);
@@ -3204,6 +3225,7 @@
 	dev->stats.rx_packets = rx_packets;
 	dev->stats.rx_errors = rx_errors;
 	dev->stats.rx_missed_errors = rx_errors;
+	dev->stats.rx_dropped = rx_dropped;
 	return &dev->stats;
 }
 
@@ -3500,10 +3522,12 @@
 
 	/* Request the WOL interrupt and advertise suspend if available */
 	priv->wol_irq_disabled = true;
-	err = devm_request_irq(&pdev->dev, priv->wol_irq, bcmgenet_wol_isr, 0,
-			       dev->name, priv);
-	if (!err)
-		device_set_wakeup_capable(&pdev->dev, 1);
+	if (priv->wol_irq > 0) {
+		err = devm_request_irq(&pdev->dev, priv->wol_irq,
+				       bcmgenet_wol_isr, 0, dev->name, priv);
+		if (!err)
+			device_set_wakeup_capable(&pdev->dev, 1);
+	}
 
 	/* Set the needed headroom to account for any possible
 	 * features enabling/disabling at runtime
@@ -3578,8 +3602,10 @@
 	clk_disable_unprepare(priv->clk);
 
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		bcmgenet_mii_exit(dev);
 		goto err;
+	}
 
 	return err;
 
@@ -3609,7 +3635,6 @@
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	unsigned long dma_ctrl;
 	int ret;
-	u32 reg;
 
 	if (!netif_running(dev))
 		return 0;
@@ -3641,12 +3666,6 @@
 
 	bcmgenet_set_hw_addr(priv, dev->dev_addr);
 
-	if (priv->internal_phy) {
-		reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-		reg |= EXT_ENERGY_DET_MASK;
-		bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-	}
-
 	if (priv->wolopts)
 		bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
 
@@ -3666,9 +3685,6 @@
 	if (!device_may_wakeup(d))
 		phy_resume(dev->phydev);
 
-	if (priv->eee.eee_enabled)
-		bcmgenet_eee_enable_set(dev, true);
-
 	bcmgenet_netif_start(dev);
 
 	netif_device_attach(dev);
@@ -3693,7 +3709,7 @@
 
 	netif_device_detach(dev);
 
-	bcmgenet_netif_stop(dev);
+	bcmgenet_netif_stop(dev, true);
 
 	if (!device_may_wakeup(d))
 		phy_suspend(dev->phydev);
@@ -3733,3 +3749,4 @@
 MODULE_DESCRIPTION("Broadcom GENET Ethernet controller driver");
 MODULE_ALIAS("platform:bcmgenet");
 MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: mdio-bcm-unimac");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -14,6 +14,7 @@
 #include <linux/if_vlan.h>
 #include <linux/phy.h>
 #include <linux/dim.h>
+#include <linux/ethtool.h>
 
 /* total number of Buffer Descriptors, same for Rx/Tx */
 #define TOTAL_DESC				256
@@ -674,6 +675,7 @@
 	/* WOL */
 	struct clk *clk_wol;
 	u32 wolopts;
+	u8 sopass[SOPASS_MAX];
 
 	struct bcmgenet_mib_counters mib;
 
@@ -734,4 +736,7 @@
 void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
 			       enum bcmgenet_power_mode mode);
 
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
+			     bool tx_lpi_enabled);
+
 #endif /* __BCMGENET_H__ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -41,18 +41,20 @@
 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
-	u32 reg;
+	struct device *kdev = &priv->pdev->dev;
+
+	if (!device_can_wakeup(kdev)) {
+		wol->supported = 0;
+		wol->wolopts = 0;
+		return;
+	}
 
 	wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
 	wol->wolopts = priv->wolopts;
 	memset(wol->sopass, 0, sizeof(wol->sopass));
 
-	if (wol->wolopts & WAKE_MAGICSECURE) {
-		reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
-		put_unaligned_be16(reg, &wol->sopass[0]);
-		reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
-		put_unaligned_be32(reg, &wol->sopass[2]);
-	}
+	if (wol->wolopts & WAKE_MAGICSECURE)
+		memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 }
 
 /* ethtool function - set WOL (Wake on LAN) settings.
@@ -62,7 +64,6 @@
 {
 	struct bcmgenet_priv *priv = netdev_priv(dev);
 	struct device *kdev = &priv->pdev->dev;
-	u32 reg;
 
 	if (!device_can_wakeup(kdev))
 		return -ENOTSUPP;
@@ -70,17 +71,8 @@
 	if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
 		return -EINVAL;
 
-	reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-	if (wol->wolopts & WAKE_MAGICSECURE) {
-		bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
-				     UMAC_MPD_PW_MS);
-		bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
-				     UMAC_MPD_PW_LS);
-		reg |= MPD_PW_EN;
-	} else {
-		reg &= ~MPD_PW_EN;
-	}
-	bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+	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) {
@@ -120,6 +112,14 @@
 	return retries;
 }
 
+static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
+{
+	bcmgenet_umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
+			     UMAC_MPD_PW_MS);
+	bcmgenet_umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
+			     UMAC_MPD_PW_LS);
+}
+
 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
 				enum bcmgenet_power_mode mode)
 {
@@ -140,13 +140,17 @@
 
 	reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
 	reg |= MPD_EN;
+	if (priv->wolopts & WAKE_MAGICSECURE) {
+		bcmgenet_set_mpd_password(priv);
+		reg |= MPD_PW_EN;
+	}
 	bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
 	/* Do not leave UniMAC in MPD mode only */
 	retries = bcmgenet_poll_wol_status(priv);
 	if (retries < 0) {
 		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-		reg &= ~MPD_EN;
+		reg &= ~(MPD_EN | MPD_PW_EN);
 		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 		return retries;
 	}
@@ -163,12 +167,6 @@
 	reg |= CMD_RX_EN;
 	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 
-	if (priv->hw_params->flags & GENET_HAS_EXT) {
-		reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
-		reg &= ~EXT_ENERGY_DET_MASK;
-		bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
-	}
-
 	return 0;
 }
 
@@ -185,7 +183,7 @@
 	reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
 	if (!(reg & MPD_EN))
 		return;	/* already powered up so skip the rest */
-	reg &= ~MPD_EN;
+	reg &= ~(MPD_EN | MPD_PW_EN);
 	bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
 	/* Disable CRC Forward */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -25,6 +25,7 @@
 
 #include "bcmgenet.h"
 
+
 /* setup netdev link state when PHY link status change and
  * update UMAC and RGMII block when link up
  */
@@ -96,6 +97,11 @@
 			       CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
 		reg |= cmd_bits;
 		bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+		priv->eee.eee_active = phy_init_eee(phydev, 0) >= 0;
+		bcmgenet_eee_enable_set(dev,
+					priv->eee.eee_enabled && priv->eee.eee_active,
+					priv->eee.tx_lpi_enabled);
 	} else {
 		/* done if nothing has changed */
 		if (!status_changed)
@@ -426,6 +432,10 @@
 	int id, ret;
 
 	pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!pres) {
+		dev_err(&pdev->dev, "Invalid resource\n");
+		return -EINVAL;
+	}
 	memset(&res, 0, sizeof(res));
 	memset(&ppd, 0, sizeof(ppd));
 
@@ -561,7 +571,7 @@
 		};
 
 		phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
-		if (!phydev || IS_ERR(phydev)) {
+		if (IS_ERR(phydev)) {
 			dev_err(kdev, "failed to register fixed PHY device\n");
 			return -ENODEV;
 		}
@@ -614,5 +624,7 @@
 	if (of_phy_is_fixed_link(dn))
 		of_phy_deregister_fixed_link(dn);
 	of_node_put(priv->phy_dn);
+	clk_prepare_enable(priv->clk);
 	platform_device_unregister(priv->mii_pdev);
+	clk_disable_unprepare(priv->clk);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/tg3.c
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/tg3.c
@@ -230,6 +230,7 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 MODULE_FIRMWARE(FIRMWARE_TG3);
+MODULE_FIRMWARE(FIRMWARE_TG357766);
 MODULE_FIRMWARE(FIRMWARE_TG3TSO);
 MODULE_FIRMWARE(FIRMWARE_TG3TSO5);
 
@@ -6459,6 +6460,14 @@
 	int i;
 	u32 *regs;
 
+	/* If it is a PCI error, all registers will be 0xffff,
+	 * we don't dump them out, just report the error and return
+	 */
+	if (tp->pdev->error_state != pci_channel_io_normal) {
+		netdev_err(tp->dev, "PCI channel ERROR!\n");
+		return;
+	}
+
 	regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC);
 	if (!regs)
 		return;
@@ -6869,7 +6878,7 @@
 				       desc_idx, *post_ptr);
 		drop_it_no_recycle:
 			/* Other statistics kept track of by card. */
-			tp->rx_dropped++;
+			tnapi->rx_dropped++;
 			goto next_pkt;
 		}
 
@@ -7227,8 +7236,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);
 }
 
@@ -7895,8 +7904,10 @@
 
 	segs = skb_gso_segment(skb, tp->dev->features &
 				    ~(NETIF_F_TSO | NETIF_F_TSO6));
-	if (IS_ERR(segs) || !segs)
+	if (IS_ERR(segs) || !segs) {
+		tnapi->tx_dropped++;
 		goto tg3_tso_bug_end;
+	}
 
 	do {
 		nskb = segs;
@@ -8168,7 +8179,7 @@
 drop:
 	dev_kfree_skb_any(skb);
 drop_nofree:
-	tp->tx_dropped++;
+	tnapi->tx_dropped++;
 	return NETDEV_TX_OK;
 }
 
@@ -9347,7 +9358,7 @@
 /* tp->lock is held. */
 static int tg3_halt(struct tg3 *tp, int kind, bool silent)
 {
-	int err;
+	int err, i;
 
 	tg3_stop_fw(tp);
 
@@ -9368,6 +9379,13 @@
 
 		/* And make sure the next sample is new data */
 		memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
+
+		for (i = 0; i < TG3_IRQ_MAX_VECS; ++i) {
+			struct tg3_napi *tnapi = &tp->napi[i];
+
+			tnapi->rx_dropped = 0;
+			tnapi->tx_dropped = 0;
+		}
 	}
 
 	return err;
@@ -11195,7 +11213,8 @@
 	rtnl_lock();
 	tg3_full_lock(tp, 0);
 
-	if (!netif_running(tp->dev)) {
+	if (tp->pcierr_recovery || !netif_running(tp->dev) ||
+	    tp->pdev->error_state != pci_channel_io_normal) {
 		tg3_flag_clear(tp, RESET_TASK_PENDING);
 		tg3_full_unlock(tp);
 		rtnl_unlock();
@@ -11219,18 +11238,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();
 }
 
@@ -11915,6 +11943,9 @@
 {
 	struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
 	struct tg3_hw_stats *hw_stats = tp->hw_stats;
+	unsigned long rx_dropped;
+	unsigned long tx_dropped;
+	int i;
 
 	stats->rx_packets = old_stats->rx_packets +
 		get_stat64(&hw_stats->rx_ucast_packets) +
@@ -11961,8 +11992,26 @@
 	stats->rx_missed_errors = old_stats->rx_missed_errors +
 		get_stat64(&hw_stats->rx_discards);
 
-	stats->rx_dropped = tp->rx_dropped;
-	stats->tx_dropped = tp->tx_dropped;
+	/* Aggregate per-queue counters. The per-queue counters are updated
+	 * by a single writer, race-free. The result computed by this loop
+	 * might not be 100% accurate (counters can be updated in the middle of
+	 * the loop) but the next tg3_get_nstats() will recompute the current
+	 * value so it is acceptable.
+	 *
+	 * Note that these counters wrap around at 4G on 32bit machines.
+	 */
+	rx_dropped = (unsigned long)(old_stats->rx_dropped);
+	tx_dropped = (unsigned long)(old_stats->tx_dropped);
+
+	for (i = 0; i < tp->irq_cnt; i++) {
+		struct tg3_napi *tnapi = &tp->napi[i];
+
+		rx_dropped += tnapi->rx_dropped;
+		tx_dropped += tnapi->tx_dropped;
+	}
+
+	stats->rx_dropped = rx_dropped;
+	stats->tx_dropped = tx_dropped;
 }
 
 static int tg3_get_regs_len(struct net_device *dev)
@@ -18145,7 +18194,10 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct tg3 *tp = netdev_priv(dev);
 
+	tg3_reset_task_cancel(tp);
+
 	rtnl_lock();
+
 	netif_device_detach(dev);
 
 	if (netif_running(dev))
@@ -18155,6 +18207,8 @@
 		tg3_power_down(tp);
 
 	rtnl_unlock();
+
+	pci_disable_device(pdev);
 }
 
 /**
@@ -18174,10 +18228,13 @@
 
 	netdev_info(netdev, "PCI I/O error detected\n");
 
+	/* Want to make sure that the reset task doesn't run */
+	tg3_reset_task_cancel(tp);
+
 	rtnl_lock();
 
-	/* We probably don't have netdev yet */
-	if (!netdev || !netif_running(netdev))
+	/* 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 */
@@ -18190,9 +18247,6 @@
 
 	tg3_timer_stop(tp);
 
-	/* Want to make sure that the reset task doesn't run */
-	tg3_reset_task_cancel(tp);
-
 	netif_device_detach(netdev);
 
 	/* Clean up software state, even if MMIO is blocked */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/broadcom/tg3.h
+++ linux-ein-5.4.0/drivers/net/ethernet/broadcom/tg3.h
@@ -3018,6 +3018,7 @@
 	u16				*rx_rcb_prod_idx;
 	struct tg3_rx_prodring_set	prodring;
 	struct tg3_rx_buffer_desc	*rx_rcb;
+	unsigned long			rx_dropped;
 
 	u32				tx_prod	____cacheline_aligned;
 	u32				tx_cons;
@@ -3026,6 +3027,7 @@
 	u32				prodmbox;
 	struct tg3_tx_buffer_desc	*tx_ring;
 	struct tg3_tx_ring_info		*tx_buffers;
+	unsigned long			tx_dropped;
 
 	dma_addr_t			status_mapping;
 	dma_addr_t			rx_rcb_mapping;
@@ -3219,8 +3221,6 @@
 
 
 	/* begin "everything else" cacheline(s) section */
-	unsigned long			rx_dropped;
-	unsigned long			tx_dropped;
 	struct rtnl_link_stats64	net_stats_prev;
 	struct tg3_ethtool_stats	estats_prev;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/brocade/bna/bnad.c
+++ linux-ein-5.4.0/drivers/net/ethernet/brocade/bna/bnad.c
@@ -3282,7 +3282,7 @@
 {
 	int err, mtu;
 	struct bnad *bnad = netdev_priv(netdev);
-	u32 rx_count = 0, frame, new_frame;
+	u32 frame, new_frame;
 
 	mutex_lock(&bnad->conf_mutex);
 
@@ -3298,12 +3298,9 @@
 		/* only when transition is over 4K */
 		if ((frame <= 4096 && new_frame > 4096) ||
 		    (frame > 4096 && new_frame <= 4096))
-			rx_count = bnad_reinit_rx(bnad);
+			bnad_reinit_rx(bnad);
 	}
 
-	/* rx_count > 0 - new rx created
-	 *	- Linux set err = 0 and return
-	 */
 	err = bnad_mtu_set(bnad, new_frame);
 	if (err)
 		err = -EBUSY;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cadence/macb_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cadence/macb_main.c
@@ -73,7 +73,11 @@
 /* Max length of transmit frame must be a multiple of 8 bytes */
 #define MACB_TX_LEN_ALIGN	8
 #define MACB_MAX_TX_LEN		((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
-#define GEM_MAX_TX_LEN		((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
+/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a
+ * false amba_error in TX path from the DMA assuming there is not enough
+ * space in the SRAM (16KB) even when there is.
+ */
+#define GEM_MAX_TX_LEN		(unsigned int)(0x3FC0)
 
 #define GEM_MTU_MIN_SIZE	ETH_MIN_MTU
 #define MACB_NETIF_LSO		NETIF_F_TSO
@@ -330,8 +334,10 @@
 	int status;
 
 	status = pm_runtime_get_sync(&bp->pdev->dev);
-	if (status < 0)
+	if (status < 0) {
+		pm_runtime_put_noidle(&bp->pdev->dev);
 		goto mdio_pm_exit;
+	}
 
 	status = macb_mdio_wait_for_idle(bp);
 	if (status < 0)
@@ -363,8 +369,10 @@
 	int status;
 
 	status = pm_runtime_get_sync(&bp->pdev->dev);
-	if (status < 0)
+	if (status < 0) {
+		pm_runtime_put_noidle(&bp->pdev->dev);
 		goto mdio_pm_exit;
+	}
 
 	status = macb_mdio_wait_for_idle(bp);
 	if (status < 0)
@@ -711,6 +719,10 @@
 	}
 #endif
 	addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
+#ifdef CONFIG_MACB_USE_HWSTAMP
+	if (bp->hw_dma_cap & HW_DMA_CAP_PTP)
+		addr &= ~GEM_BIT(DMA_RXVALID);
+#endif
 	return addr;
 }
 
@@ -919,7 +931,6 @@
 		/* Make hw descriptor updates visible to CPU */
 		rmb();
 
-		queue->rx_prepared_head++;
 		desc = macb_rx_desc(queue, entry);
 
 		if (!queue->rx_skbuff[entry]) {
@@ -958,6 +969,7 @@
 			dma_wmb();
 			desc->addr &= ~MACB_BIT(RX_USED);
 		}
+		queue->rx_prepared_head++;
 	}
 
 	/* Make descriptor updates visible to hardware */
@@ -1275,7 +1287,14 @@
 	if (work_done < budget) {
 		napi_complete_done(napi, work_done);
 
-		/* Packets received while interrupts were disabled */
+		/* RSR bits only seem to propagate to raise interrupts when
+		 * interrupts are enabled at the time, so if bits are already
+		 * set due to packets received while interrupts were disabled,
+		 * they will not cause another interrupt to be generated when
+		 * interrupts are re-enabled.
+		 * Check for this case here. This has been seen to happen
+		 * around 30% of the time under heavy network load.
+		 */
 		status = macb_readl(bp, RSR);
 		if (status) {
 			if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
@@ -1283,6 +1302,22 @@
 			napi_reschedule(napi);
 		} else {
 			queue_writel(queue, IER, bp->rx_intr_mask);
+
+			/* In rare cases, packets could have been received in
+			 * the window between the check above and re-enabling
+			 * interrupts. Therefore, a double-check is required
+			 * to avoid losing a wakeup. This can potentially race
+			 * with the interrupt handler doing the same actions
+			 * if an interrupt is raised just after enabling them,
+			 * but this should be harmless.
+			 */
+			status = macb_readl(bp, RSR);
+			if (unlikely(status)) {
+				queue_writel(queue, IDR, bp->rx_intr_mask);
+				if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+					queue_writel(queue, ISR, MACB_BIT(RCOMP));
+				napi_schedule(napi);
+			}
 		}
 	}
 
@@ -1347,6 +1382,7 @@
 	unsigned int head = queue->tx_head;
 	unsigned int tail = queue->tx_tail;
 	struct macb *bp = queue->bp;
+	unsigned int head_idx, tbqp;
 
 	if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
 		queue_writel(queue, ISR, MACB_BIT(TXUBR));
@@ -1354,6 +1390,13 @@
 	if (head == tail)
 		return;
 
+	tbqp = queue_readl(queue, TBQP) / macb_dma_desc_get_size(bp);
+	tbqp = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, tbqp));
+	head_idx = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, head));
+
+	if (tbqp == head_idx)
+		return;
+
 	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
 }
 
@@ -1664,16 +1707,14 @@
 
 	/* Validate LSO compatibility */
 
-	/* there is only one buffer */
-	if (!skb_is_nonlinear(skb))
+	/* there is only one buffer or protocol is not UDP */
+	if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP))
 		return features;
 
 	/* length of header */
 	hdrlen = skb_transport_offset(skb);
-	if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-		hdrlen += tcp_hdrlen(skb);
 
-	/* For LSO:
+	/* For UFO only:
 	 * When software supplies two or more payload buffers all payload buffers
 	 * apart from the last must be a multiple of 8 bytes in size.
 	 */
@@ -1712,9 +1753,9 @@
 
 static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
 {
-	bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb);
+	bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
+		      skb_is_nonlinear(*skb);
 	int padlen = ETH_ZLEN - (*skb)->len;
-	int headroom = skb_headroom(*skb);
 	int tailroom = skb_tailroom(*skb);
 	struct sk_buff *nskb;
 	u32 fcs;
@@ -1728,9 +1769,6 @@
 		/* FCS could be appeded to tailroom. */
 		if (tailroom >= ETH_FCS_LEN)
 			goto add_fcs;
-		/* FCS could be appeded by moving data to headroom. */
-		else if (!cloned && headroom + tailroom >= ETH_FCS_LEN)
-			padlen = 0;
 		/* No room for FCS, need to reallocate skb. */
 		else
 			padlen = ETH_FCS_LEN;
@@ -1739,10 +1777,7 @@
 		padlen += ETH_FCS_LEN;
 	}
 
-	if (!cloned && headroom + tailroom >= padlen) {
-		(*skb)->data = memmove((*skb)->head, (*skb)->data, (*skb)->len);
-		skb_set_tail_pointer(*skb, (*skb)->len);
-	} else {
+	if (cloned || tailroom < padlen) {
 		nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
 		if (!nskb)
 			return -ENOMEM;
@@ -2529,6 +2564,9 @@
 	struct gem_stats *hwstat = &bp->hw_stats.gem;
 	struct net_device_stats *nstat = &bp->dev->stats;
 
+	if (!netif_running(bp->dev))
+		return nstat;
+
 	gem_update_stats(bp);
 
 	nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors +
@@ -2908,6 +2946,9 @@
 	bool cmp_b = false;
 	bool cmp_c = false;
 
+	if (!macb_is_gem(bp))
+		return;
+
 	tp4sp_v = &(fs->h_u.tcp_ip4_spec);
 	tp4sp_m = &(fs->m_u.tcp_ip4_spec);
 
@@ -3279,6 +3320,7 @@
 {
 	struct net_device *netdev = bp->dev;
 	netdev_features_t features = netdev->features;
+	struct ethtool_rx_fs_item *item;
 
 	/* TX checksum offload */
 	macb_set_txcsum_feature(bp, features);
@@ -3287,6 +3329,9 @@
 	macb_set_rxcsum_feature(bp, features);
 
 	/* RX Flow Filters */
+	list_for_each_entry(item, &bp->rx_fs_list.list, list)
+		gem_prog_cmp_regs(bp, &item->fs);
+
 	macb_set_rxflow_feature(bp, features);
 }
 
@@ -3576,6 +3621,7 @@
 	reg = gem_readl(bp, DCFG8);
 	bp->max_tuples = min((GEM_BFEXT(SCR2CMP, reg) / 3),
 			GEM_BFEXT(T2SCR, reg));
+	INIT_LIST_HEAD(&bp->rx_fs_list.list);
 	if (bp->max_tuples > 0) {
 		/* also needs one ethtype match to check IPv4 */
 		if (GEM_BFEXT(SCR2ETH, reg) > 0) {
@@ -3586,7 +3632,6 @@
 			/* Filtering is supported in hw but don't enable it in kernel now */
 			dev->hw_features |= NETIF_F_NTUPLE;
 			/* init Rx flow definitions */
-			INIT_LIST_HEAD(&bp->rx_fs_list.list);
 			bp->rx_fs_list.count = 0;
 			spin_lock_init(&bp->rx_fs_lock);
 		} else
@@ -3688,6 +3733,12 @@
 	u32 ctl;
 	int ret;
 
+	ret = pm_runtime_get_sync(&lp->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&lp->pdev->dev);
+		return ret;
+	}
+
 	/* Clear internal statistics */
 	ctl = macb_readl(lp, NCR);
 	macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT));
@@ -3696,7 +3747,7 @@
 
 	ret = at91ether_start(dev);
 	if (ret)
-		return ret;
+		goto pm_exit;
 
 	/* Enable MAC interrupts */
 	macb_writel(lp, IER, MACB_BIT(RCOMP)	|
@@ -3713,6 +3764,10 @@
 	netif_start_queue(dev);
 
 	return 0;
+
+pm_exit:
+	pm_runtime_put_sync(&lp->pdev->dev);
+	return ret;
 }
 
 /* Close the interface */
@@ -3748,7 +3803,7 @@
 			  q->rx_buffers, q->rx_buffers_dma);
 	q->rx_buffers = NULL;
 
-	return 0;
+	return pm_runtime_put(&lp->pdev->dev);
 }
 
 /* Transmit packet */
@@ -4027,7 +4082,7 @@
 	mgmt->rate = 0;
 	mgmt->hw.init = &init;
 
-	*tx_clk = clk_register(NULL, &mgmt->hw);
+	*tx_clk = devm_clk_register(&pdev->dev, &mgmt->hw);
 	if (IS_ERR(*tx_clk))
 		return PTR_ERR(*tx_clk);
 
@@ -4042,15 +4097,9 @@
 
 static int fu540_c000_init(struct platform_device *pdev)
 {
-	struct resource *res;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res)
-		return -ENODEV;
-
-	mgmt->reg = ioremap(res->start, resource_size(res));
-	if (!mgmt->reg)
-		return -ENOMEM;
+	mgmt->reg = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(mgmt->reg))
+		return PTR_ERR(mgmt->reg);
 
 	return macb_init(pdev);
 }
@@ -4254,7 +4303,7 @@
 	bp->wol = 0;
 	if (of_get_property(np, "magic-packet", NULL))
 		bp->wol |= MACB_WOL_HAS_MAGIC_PACKET;
-	device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
+	device_set_wakeup_capable(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
 
 	spin_lock_init(&bp->lock);
 
@@ -4263,7 +4312,7 @@
 
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 	if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
-		dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+		dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
 		bp->hw_dma_cap |= HW_DMA_CAP_64B;
 	}
 #endif
@@ -4361,7 +4410,6 @@
 
 err_disable_clocks:
 	clk_disable_unprepare(tx_clk);
-	clk_unregister(tx_clk);
 	clk_disable_unprepare(hclk);
 	clk_disable_unprepare(pclk);
 	clk_disable_unprepare(rx_clk);
@@ -4392,11 +4440,11 @@
 		mdiobus_free(bp->mii_bus);
 
 		unregister_netdev(dev);
+		tasklet_kill(&bp->hresp_err_tasklet);
 		pm_runtime_disable(&pdev->dev);
 		pm_runtime_dont_use_autosuspend(&pdev->dev);
 		if (!pm_runtime_suspended(&pdev->dev)) {
 			clk_disable_unprepare(bp->tx_clk);
-			clk_unregister(bp->tx_clk);
 			clk_disable_unprepare(bp->hclk);
 			clk_disable_unprepare(bp->pclk);
 			clk_disable_unprepare(bp->rx_clk);
@@ -4448,7 +4496,8 @@
 	netif_carrier_off(netdev);
 	if (bp->ptp_info)
 		bp->ptp_info->ptp_remove(netdev);
-	pm_runtime_force_suspend(dev);
+	if (!device_may_wakeup(dev))
+		pm_runtime_force_suspend(dev);
 
 	return 0;
 }
@@ -4463,7 +4512,8 @@
 	if (!netif_running(netdev))
 		return 0;
 
-	pm_runtime_force_resume(dev);
+	if (!device_may_wakeup(dev))
+		pm_runtime_force_resume(dev);
 
 	if (bp->wol & MACB_WOL_ENABLED) {
 		macb_writel(bp, IDR, MACB_BIT(WOL));
@@ -4502,7 +4552,7 @@
 	struct net_device *netdev = dev_get_drvdata(dev);
 	struct macb *bp = netdev_priv(netdev);
 
-	if (!(device_may_wakeup(&bp->dev->dev))) {
+	if (!(device_may_wakeup(dev))) {
 		clk_disable_unprepare(bp->tx_clk);
 		clk_disable_unprepare(bp->hclk);
 		clk_disable_unprepare(bp->pclk);
@@ -4518,7 +4568,7 @@
 	struct net_device *netdev = dev_get_drvdata(dev);
 	struct macb *bp = netdev_priv(netdev);
 
-	if (!(device_may_wakeup(&bp->dev->dev))) {
+	if (!(device_may_wakeup(dev))) {
 		clk_prepare_enable(bp->pclk);
 		clk_prepare_enable(bp->hclk);
 		clk_prepare_enable(bp->tx_clk);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cadence/macb_pci.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cadence/macb_pci.c
@@ -112,9 +112,9 @@
 	struct platform_device *plat_dev = pci_get_drvdata(pdev);
 	struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
 
-	platform_device_unregister(plat_dev);
 	clk_unregister(plat_data->pclk);
 	clk_unregister(plat_data->hclk);
+	platform_device_unregister(plat_dev);
 }
 
 static const struct pci_device_id dev_id_table[] = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cadence/macb_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cadence/macb_ptp.c
@@ -275,6 +275,12 @@
 
 	if (GEM_BFEXT(DMA_RXVALID, desc->addr)) {
 		desc_ptp = macb_ptp_desc(bp, desc);
+		/* Unlikely but check */
+		if (!desc_ptp) {
+			dev_warn_ratelimited(&bp->pdev->dev,
+					     "Timestamp not supported in BD\n");
+			return;
+		}
 		gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts);
 		memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
 		shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
@@ -307,8 +313,11 @@
 	if (CIRC_SPACE(head, tail, PTP_TS_BUFFER_SIZE) == 0)
 		return -ENOMEM;
 
-	skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 	desc_ptp = macb_ptp_desc(queue->bp, desc);
+	/* Unlikely but check */
+	if (!desc_ptp)
+		return -EINVAL;
+	skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 	tx_timestamp = &queue->tx_timestamps[head];
 	tx_timestamp->skb = skb;
 	/* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
@@ -420,7 +420,7 @@
 	 * bits 32:47 indicate the PVF num.
 	 */
 	for (q_no = 0; q_no < ern; q_no++) {
-		reg_val = oct->pcie_port << CN23XX_PKT_INPUT_CTL_MAC_NUM_POS;
+		reg_val = (u64)oct->pcie_port << CN23XX_PKT_INPUT_CTL_MAC_NUM_POS;
 
 		/* for VF assigned queues. */
 		if (q_no < oct->sriov_info.pf_srn) {
@@ -1167,7 +1167,7 @@
 		oct->pf_num = ((fdl_bit >> CN23XX_PCIE_SRIOV_FDL_BIT_POS) &
 			       CN23XX_PCIE_SRIOV_FDL_MASK);
 	} else {
-		ret = EINVAL;
+		ret = -EINVAL;
 
 		/* Under some virtual environments, extended PCI regs are
 		 * inaccessible, in which case the above read will have failed.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_regs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_regs.h
@@ -521,7 +521,7 @@
 #define    CN23XX_BAR1_INDEX_OFFSET                3
 
 #define    CN23XX_PEM_BAR1_INDEX_REG(port, idx)		\
-		(CN23XX_PEM_BAR1_INDEX_START + ((port) << CN23XX_PEM_OFFSET) + \
+		(CN23XX_PEM_BAR1_INDEX_START + (((u64)port) << CN23XX_PEM_OFFSET) + \
 		 ((idx) << CN23XX_BAR1_INDEX_OFFSET))
 
 /*############################ DPI #########################*/
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h
@@ -412,7 +412,7 @@
 	   | CN6XXX_INTR_M0UNWI_ERR             \
 	   | CN6XXX_INTR_M1UPB0_ERR             \
 	   | CN6XXX_INTR_M1UPWI_ERR             \
-	   | CN6XXX_INTR_M1UPB0_ERR             \
+	   | CN6XXX_INTR_M1UNB0_ERR             \
 	   | CN6XXX_INTR_M1UNWI_ERR             \
 	   | CN6XXX_INTR_INSTR_DB_OF_ERR        \
 	   | CN6XXX_INTR_SLIST_DB_OF_ERR        \
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -1179,7 +1179,7 @@
  * @param lio per-network private data
  * @param start_stop whether to start or stop
  */
-static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
+static int send_rx_ctrl_cmd(struct lio *lio, int start_stop)
 {
 	struct octeon_soft_command *sc;
 	union octnet_cmd *ncmd;
@@ -1187,15 +1187,15 @@
 	int retval;
 
 	if (oct->props[lio->ifidx].rx_on == start_stop)
-		return;
+		return 0;
 
 	sc = (struct octeon_soft_command *)
 		octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
 					  16, 0);
 	if (!sc) {
 		netif_info(lio, rx_err, lio->netdev,
-			   "Failed to allocate octeon_soft_command\n");
-		return;
+			   "Failed to allocate octeon_soft_command struct\n");
+		return -ENOMEM;
 	}
 
 	ncmd = (union octnet_cmd *)sc->virtdptr;
@@ -1218,18 +1218,19 @@
 	if (retval == IQ_SEND_FAILED) {
 		netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n");
 		octeon_free_soft_command(oct, sc);
-		return;
 	} else {
 		/* Sleep on a wait queue till the cond flag indicates that the
 		 * response arrived or timed-out.
 		 */
 		retval = wait_for_sc_completion_timeout(oct, sc, 0);
 		if (retval)
-			return;
+			return retval;
 
 		oct->props[lio->ifidx].rx_on = start_stop;
 		WRITE_ONCE(sc->caller_is_done, true);
 	}
+
+	return retval;
 }
 
 /**
@@ -1816,6 +1817,7 @@
 	struct octeon_device_priv *oct_priv =
 		(struct octeon_device_priv *)oct->priv;
 	struct napi_struct *napi, *n;
+	int ret = 0;
 
 	if (oct->props[lio->ifidx].napi_enabled == 0) {
 		tasklet_disable(&oct_priv->droq_tasklet);
@@ -1834,13 +1836,10 @@
 
 	ifstate_set(lio, LIO_IFSTATE_RUNNING);
 
-	if (OCTEON_CN23XX_PF(oct)) {
-		if (!oct->msix_on)
-			if (setup_tx_poll_fn(netdev))
-				return -1;
-	} else {
-		if (setup_tx_poll_fn(netdev))
-			return -1;
+	if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) {
+		ret = setup_tx_poll_fn(netdev);
+		if (ret)
+			goto err_poll;
 	}
 
 	netif_tx_start_all_queues(netdev);
@@ -1851,7 +1850,9 @@
 	netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n");
 
 	/* tell Octeon to start forwarding packets to host */
-	send_rx_ctrl_cmd(lio, 1);
+	ret = send_rx_ctrl_cmd(lio, 1);
+	if (ret)
+		goto err_rx_ctrl;
 
 	/* start periodical statistics fetch */
 	INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats);
@@ -1863,6 +1864,27 @@
 		 netdev->name);
 
 	return 0;
+
+err_rx_ctrl:
+	if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on)
+		cleanup_tx_poll_fn(netdev);
+err_poll:
+	if (lio->ptp_clock) {
+		ptp_clock_unregister(lio->ptp_clock);
+		lio->ptp_clock = NULL;
+	}
+
+	if (oct->props[lio->ifidx].napi_enabled == 1) {
+		list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
+			napi_disable(napi);
+
+		oct->props[lio->ifidx].napi_enabled = 0;
+
+		if (OCTEON_CN23XX_PF(oct))
+			oct->droq[0]->ops.poll_mode = 0;
+	}
+
+	return ret;
 }
 
 /**
@@ -1876,6 +1898,7 @@
 	struct octeon_device_priv *oct_priv =
 		(struct octeon_device_priv *)oct->priv;
 	struct napi_struct *napi, *n;
+	int ret = 0;
 
 	ifstate_reset(lio, LIO_IFSTATE_RUNNING);
 
@@ -1892,7 +1915,9 @@
 	lio->link_changes++;
 
 	/* Tell Octeon that nic interface is down. */
-	send_rx_ctrl_cmd(lio, 0);
+	ret = send_rx_ctrl_cmd(lio, 0);
+	if (ret)
+		return ret;
 
 	if (OCTEON_CN23XX_PF(oct)) {
 		if (!oct->msix_on)
@@ -1927,7 +1952,7 @@
 
 	dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
 
-	return 0;
+	return ret;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
@@ -598,7 +598,7 @@
  * @param lio per-network private data
  * @param start_stop whether to start or stop
  */
-static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
+static int send_rx_ctrl_cmd(struct lio *lio, int start_stop)
 {
 	struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
 	struct octeon_soft_command *sc;
@@ -606,11 +606,16 @@
 	int retval;
 
 	if (oct->props[lio->ifidx].rx_on == start_stop)
-		return;
+		return 0;
 
 	sc = (struct octeon_soft_command *)
 		octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
 					  16, 0);
+	if (!sc) {
+		netif_info(lio, rx_err, lio->netdev,
+			   "Failed to allocate octeon_soft_command struct\n");
+		return -ENOMEM;
+	}
 
 	ncmd = (union octnet_cmd *)sc->virtdptr;
 
@@ -638,11 +643,13 @@
 		 */
 		retval = wait_for_sc_completion_timeout(oct, sc, 0);
 		if (retval)
-			return;
+			return retval;
 
 		oct->props[lio->ifidx].rx_on = start_stop;
 		WRITE_ONCE(sc->caller_is_done, true);
 	}
+
+	return retval;
 }
 
 /**
@@ -909,6 +916,7 @@
 	struct octeon_device_priv *oct_priv =
 		(struct octeon_device_priv *)oct->priv;
 	struct napi_struct *napi, *n;
+	int ret = 0;
 
 	if (!oct->props[lio->ifidx].napi_enabled) {
 		tasklet_disable(&oct_priv->droq_tasklet);
@@ -935,11 +943,13 @@
 					(LIQUIDIO_NDEV_STATS_POLL_TIME_MS));
 
 	/* tell Octeon to start forwarding packets to host */
-	send_rx_ctrl_cmd(lio, 1);
+	ret = send_rx_ctrl_cmd(lio, 1);
+	if (ret)
+		return ret;
 
 	dev_info(&oct->pci_dev->dev, "%s interface is opened\n", netdev->name);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -953,9 +963,12 @@
 	struct octeon_device_priv *oct_priv =
 		(struct octeon_device_priv *)oct->priv;
 	struct napi_struct *napi, *n;
+	int ret = 0;
 
 	/* tell Octeon to stop forwarding packets to host */
-	send_rx_ctrl_cmd(lio, 0);
+	ret = send_rx_ctrl_cmd(lio, 0);
+	if (ret)
+		return ret;
 
 	netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n");
 	/* Inform that netif carrier is down */
@@ -989,7 +1002,7 @@
 
 	dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
 
-	return 0;
+	return ret;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
@@ -235,6 +235,11 @@
 
 		/* Put it in the ring.  */
 		p->rx_ring[p->rx_next_fill] = re.d64;
+		/* Make sure there is no reorder of filling the ring and ringing
+		 * the bell
+		 */
+		wmb();
+
 		dma_sync_single_for_device(p->dev, p->rx_ring_handle,
 					   ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
 					   DMA_BIDIRECTIONAL);
@@ -1217,7 +1222,7 @@
 	 */
 	if (netdev->phydev) {
 		netif_carrier_off(netdev);
-		phy_start_aneg(netdev->phydev);
+		phy_start(netdev->phydev);
 	}
 
 	netif_wake_queue(netdev);
@@ -1245,8 +1250,10 @@
 	napi_disable(&p->napi);
 	netif_stop_queue(netdev);
 
-	if (netdev->phydev)
+	if (netdev->phydev) {
+		phy_stop(netdev->phydev);
 		phy_disconnect(netdev->phydev);
+	}
 
 	netif_carrier_off(netdev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -1193,7 +1193,7 @@
 		dev_err(&nic->pdev->dev,
 			"Request for #%d msix vectors failed, returned %d\n",
 			   nic->num_vec, ret);
-		return 1;
+		return ret;
 	}
 
 	/* Register mailbox interrupt handler */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -1226,7 +1226,7 @@
 	if (ret < 0) {
 		netdev_err(nic->netdev,
 			   "Req for #%d msix vectors failed\n", nic->num_vec);
-		return 1;
+		return ret;
 	}
 
 	sprintf(nic->irq_name[irq], "%s Mbox", "NICVF");
@@ -1245,7 +1245,7 @@
 	if (!nicvf_check_pf_ready(nic)) {
 		nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
 		nicvf_unregister_interrupts(nic);
-		return 1;
+		return -EIO;
 	}
 
 	return 0;
@@ -2047,11 +2047,11 @@
 	/* Save message data locally to prevent them from
 	 * being overwritten by next ndo_set_rx_mode call().
 	 */
-	spin_lock(&nic->rx_mode_wq_lock);
+	spin_lock_bh(&nic->rx_mode_wq_lock);
 	mode = vf_work->mode;
 	mc = vf_work->mc;
 	vf_work->mc = NULL;
-	spin_unlock(&nic->rx_mode_wq_lock);
+	spin_unlock_bh(&nic->rx_mode_wq_lock);
 
 	__nicvf_set_rx_mode_task(mode, mc, nic);
 }
@@ -2185,6 +2185,9 @@
 		nic->max_queues *= 2;
 	nic->ptp_clock = ptp_clock;
 
+	/* Initialize mutex that serializes usage of VF's mailbox */
+	mutex_init(&nic->rx_mode_mtx);
+
 	/* MAP VF's configuration registers */
 	nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
 	if (!nic->reg_base) {
@@ -2261,12 +2264,11 @@
 
 	INIT_WORK(&nic->rx_mode_work.work, nicvf_set_rx_mode_task);
 	spin_lock_init(&nic->rx_mode_wq_lock);
-	mutex_init(&nic->rx_mode_mtx);
 
 	err = register_netdev(netdev);
 	if (err) {
 		dev_err(dev, "Failed to register netdevice\n");
-		goto err_unregister_interrupts;
+		goto err_destroy_workqueue;
 	}
 
 	nic->msg_enable = debug;
@@ -2275,6 +2277,8 @@
 
 	return 0;
 
+err_destroy_workqueue:
+	destroy_workqueue(nic->nicvf_rx_mode_wq);
 err_unregister_interrupts:
 	nicvf_unregister_interrupts(nic);
 err_free_netdev:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -776,7 +776,7 @@
 	mbx.rq.msg = NIC_MBOX_MSG_RQ_CFG;
 	mbx.rq.qs_num = qs->vnic_id;
 	mbx.rq.rq_num = qidx;
-	mbx.rq.cfg = (rq->caching << 26) | (rq->cq_qs << 19) |
+	mbx.rq.cfg = ((u64)rq->caching << 26) | (rq->cq_qs << 19) |
 			  (rq->cq_idx << 16) | (rq->cont_rbdr_qs << 9) |
 			  (rq->cont_qs_rbdr_idx << 8) |
 			  (rq->start_rbdr_qs << 1) | (rq->start_qs_rbdr_idx);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -410,10 +410,19 @@
 	lmac = &bgx->lmac[lmacid];
 
 	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
-	if (enable)
+	if (enable) {
 		cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN;
-	else
+
+		/* enable TX FIFO Underflow interrupt */
+		bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_INT_ENA_W1S,
+			       GMI_TXX_INT_UNDFLW);
+	} else {
 		cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+
+		/* Disable TX FIFO Underflow interrupt */
+		bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_INT_ENA_W1C,
+			       GMI_TXX_INT_UNDFLW);
+	}
 	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
 
 	if (bgx->is_rgx)
@@ -1115,7 +1124,7 @@
 				       phy_interface_mode(lmac->lmac_type)))
 			return -ENODEV;
 
-		phy_start_aneg(lmac->phydev);
+		phy_start(lmac->phydev);
 		return 0;
 	}
 
@@ -1429,8 +1438,10 @@
 		return AE_OK;
 	}
 
-	if (strncmp(string.pointer, bgx_sel, 4))
+	if (strncmp(string.pointer, bgx_sel, 4)) {
+		kfree(string.pointer);
 		return AE_OK;
+	}
 
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
 			    bgx_acpi_register_phy, NULL, bgx, NULL);
@@ -1535,6 +1546,48 @@
 	return bgx_init_of_phy(bgx);
 }
 
+static irqreturn_t bgx_intr_handler(int irq, void *data)
+{
+	struct bgx *bgx = (struct bgx *)data;
+	u64 status, val;
+	int lmac;
+
+	for (lmac = 0; lmac < bgx->lmac_count; lmac++) {
+		status = bgx_reg_read(bgx, lmac, BGX_GMP_GMI_TXX_INT);
+		if (status & GMI_TXX_INT_UNDFLW) {
+			pci_err(bgx->pdev, "BGX%d lmac%d UNDFLW\n",
+				bgx->bgx_id, lmac);
+			val = bgx_reg_read(bgx, lmac, BGX_CMRX_CFG);
+			val &= ~CMR_EN;
+			bgx_reg_write(bgx, lmac, BGX_CMRX_CFG, val);
+			val |= CMR_EN;
+			bgx_reg_write(bgx, lmac, BGX_CMRX_CFG, val);
+		}
+		/* clear interrupts */
+		bgx_reg_write(bgx, lmac, BGX_GMP_GMI_TXX_INT, status);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void bgx_register_intr(struct pci_dev *pdev)
+{
+	struct bgx *bgx = pci_get_drvdata(pdev);
+	int ret;
+
+	ret = pci_alloc_irq_vectors(pdev, BGX_LMAC_VEC_OFFSET,
+				    BGX_LMAC_VEC_OFFSET, PCI_IRQ_ALL_TYPES);
+	if (ret < 0) {
+		pci_err(pdev, "Req for #%d msix vectors failed\n",
+			BGX_LMAC_VEC_OFFSET);
+		return;
+	}
+	ret = pci_request_irq(pdev, GMPX_GMI_TX_INT, bgx_intr_handler, NULL,
+			      bgx, "BGX%d", bgx->bgx_id);
+	if (ret)
+		pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx);
+}
+
 static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err;
@@ -1550,7 +1603,7 @@
 
 	pci_set_drvdata(pdev, bgx);
 
-	err = pci_enable_device(pdev);
+	err = pcim_enable_device(pdev);
 	if (err) {
 		dev_err(dev, "Failed to enable PCI device\n");
 		pci_set_drvdata(pdev, NULL);
@@ -1604,6 +1657,8 @@
 
 	bgx_init_hw(bgx);
 
+	bgx_register_intr(pdev);
+
 	/* Enable all LMACs */
 	for (lmac = 0; lmac < bgx->lmac_count; lmac++) {
 		err = bgx_lmac_enable(bgx, lmac);
@@ -1620,6 +1675,7 @@
 
 err_enable:
 	bgx_vnic[bgx->bgx_id] = NULL;
+	pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx);
 err_release_regions:
 	pci_release_regions(pdev);
 err_disable_device:
@@ -1637,6 +1693,8 @@
 	for (lmac = 0; lmac < bgx->lmac_count; lmac++)
 		bgx_lmac_disable(bgx, lmac);
 
+	pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx);
+
 	bgx_vnic[bgx->bgx_id] = NULL;
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -180,6 +180,15 @@
 #define BGX_GMP_GMI_TXX_BURST		0x38228
 #define BGX_GMP_GMI_TXX_MIN_PKT		0x38240
 #define BGX_GMP_GMI_TXX_SGMII_CTL	0x38300
+#define BGX_GMP_GMI_TXX_INT		0x38500
+#define BGX_GMP_GMI_TXX_INT_W1S		0x38508
+#define BGX_GMP_GMI_TXX_INT_ENA_W1C	0x38510
+#define BGX_GMP_GMI_TXX_INT_ENA_W1S	0x38518
+#define  GMI_TXX_INT_PTP_LOST			BIT_ULL(4)
+#define  GMI_TXX_INT_LATE_COL			BIT_ULL(3)
+#define  GMI_TXX_INT_XSDEF			BIT_ULL(2)
+#define  GMI_TXX_INT_XSCOL			BIT_ULL(1)
+#define  GMI_TXX_INT_UNDFLW			BIT_ULL(0)
 
 #define BGX_MSIX_VEC_0_29_ADDR		0x400000 /* +(0..29) << 4 */
 #define BGX_MSIX_VEC_0_29_CTL		0x400008
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -1153,6 +1153,7 @@
 	if (!adapter->registered_device_map) {
 		pr_err("%s: could not register any net devices\n",
 		       pci_name(pdev));
+		err = -EINVAL;
 		goto out_release_adapter_res;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1303,6 +1303,7 @@
 		if (ret < 0) {
 			CH_ERR(adap, "failed to bind qsets, err %d\n", ret);
 			t3_intr_disable(adap);
+			quiesce_rx(adap);
 			free_irq_resources(adap);
 			err = ret;
 			goto out;
@@ -2448,6 +2449,8 @@
 
 		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)))
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -3176,6 +3176,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-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -3677,6 +3677,8 @@
 	    MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
 	adapter->params.pci.vpd_cap_addr =
 	    pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+	if (!adapter->params.pci.vpd_cap_addr)
+		return -ENODEV;
 	ret = get_vpd_params(adapter, &adapter->params.vpd);
 	if (ret < 0)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -1054,9 +1054,9 @@
 	}
 }
 
-static unsigned long cudbg_mem_region_size(struct cudbg_init *pdbg_init,
-					   struct cudbg_error *cudbg_err,
-					   u8 mem_type)
+static int cudbg_mem_region_size(struct cudbg_init *pdbg_init,
+				 struct cudbg_error *cudbg_err,
+				 u8 mem_type, unsigned long *region_size)
 {
 	struct adapter *padap = pdbg_init->adap;
 	struct cudbg_meminfo mem_info;
@@ -1065,15 +1065,23 @@
 
 	memset(&mem_info, 0, sizeof(struct cudbg_meminfo));
 	rc = cudbg_fill_meminfo(padap, &mem_info);
-	if (rc)
+	if (rc) {
+		cudbg_err->sys_err = rc;
 		return rc;
+	}
 
 	cudbg_t4_fwcache(pdbg_init, cudbg_err);
 	rc = cudbg_meminfo_get_mem_index(padap, &mem_info, mem_type, &mc_idx);
-	if (rc)
+	if (rc) {
+		cudbg_err->sys_err = rc;
 		return rc;
+	}
+
+	if (region_size)
+		*region_size = mem_info.avail[mc_idx].limit -
+			       mem_info.avail[mc_idx].base;
 
-	return mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+	return 0;
 }
 
 static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
@@ -1081,7 +1089,12 @@
 				    struct cudbg_error *cudbg_err,
 				    u8 mem_type)
 {
-	unsigned long size = cudbg_mem_region_size(pdbg_init, cudbg_err, mem_type);
+	unsigned long size = 0;
+	int rc;
+
+	rc = cudbg_mem_region_size(pdbg_init, cudbg_err, mem_type, &size);
+	if (rc)
+		return rc;
 
 	return cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type, size,
 				 cudbg_err);
@@ -1380,11 +1393,25 @@
 	struct cudbg_buffer temp_buff = { 0 };
 	struct sge_qbase_reg_field *sge_qbase;
 	struct ireg_buf *ch_sge_dbg;
+	u8 padap_running = 0;
 	int i, rc;
+	u32 size;
 
-	rc = cudbg_get_buff(pdbg_init, dbg_buff,
-			    sizeof(*ch_sge_dbg) * 2 + sizeof(*sge_qbase),
-			    &temp_buff);
+	/* Accessing SGE_QBASE_MAP[0-3] and SGE_QBASE_INDEX regs can
+	 * lead to SGE missing doorbells under heavy traffic. So, only
+	 * collect them when adapter is idle.
+	 */
+	for_each_port(padap, i) {
+		padap_running = netif_running(padap->port[i]);
+		if (padap_running)
+			break;
+	}
+
+	size = sizeof(*ch_sge_dbg) * 2;
+	if (!padap_running)
+		size += sizeof(*sge_qbase);
+
+	rc = cudbg_get_buff(pdbg_init, dbg_buff, size, &temp_buff);
 	if (rc)
 		return rc;
 
@@ -1406,7 +1433,8 @@
 		ch_sge_dbg++;
 	}
 
-	if (CHELSIO_CHIP_VERSION(padap->params.chip) > CHELSIO_T5) {
+	if (CHELSIO_CHIP_VERSION(padap->params.chip) > CHELSIO_T5 &&
+	    !padap_running) {
 		sge_qbase = (struct sge_qbase_reg_field *)ch_sge_dbg;
 		/* 1 addr reg SGE_QBASE_INDEX and 4 data reg
 		 * SGE_QBASE_MAP[0-3]
@@ -1967,7 +1995,6 @@
 	u8 mem_type[CTXT_INGRESS + 1] = { 0 };
 	struct cudbg_buffer temp_buff = { 0 };
 	struct cudbg_ch_cntxt *buff;
-	u64 *dst_off, *src_off;
 	u8 *ctx_buf;
 	u8 i, k;
 	int rc;
@@ -2036,8 +2063,11 @@
 		}
 
 		for (j = 0; j < max_ctx_qid; j++) {
+			__be64 *dst_off;
+			u64 *src_off;
+
 			src_off = (u64 *)(ctx_buf + j * SGE_CTXT_SIZE);
-			dst_off = (u64 *)buff->data;
+			dst_off = (__be64 *)buff->data;
 
 			/* The data is stored in 64-bit cpu order.  Convert it
 			 * to big endian before parsing.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -503,6 +503,7 @@
 
 	enum cc_pause  requested_fc;     /* flow control user has requested */
 	enum cc_pause  fc;               /* actual link flow control */
+	enum cc_pause  advertised_fc;    /* actual advertised flow control */
 
 	enum cc_fec    requested_fec;	 /* Forward Error Correction: */
 	enum cc_fec    fec;		 /* requested and actual in use */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -70,8 +70,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;
 }
 
@@ -2691,7 +2690,7 @@
 	seq_printf(seq, "%-12s", s); \
 	for (i = 0; i < n; ++i) \
 		seq_printf(seq, " %16" fmt_spec, v); \
-		seq_putc(seq, '\n'); \
+	seq_putc(seq, '\n'); \
 } while (0)
 #define S(s, v) S3("s", s, v)
 #define T3(fmt_spec, s, v) S3(fmt_spec, s, tx[i].v)
@@ -2996,6 +2995,9 @@
 	int tot_uld_entries = 0;
 	int i;
 
+	if (!is_uld(adap))
+		goto lld_only;
+
 	mutex_lock(&uld_mutex);
 	for (i = 0; i < CXGB4_TX_MAX; i++)
 		tot_uld_entries += sge_qinfo_uld_txq_entries(adap, i);
@@ -3006,6 +3008,7 @@
 	}
 	mutex_unlock(&uld_mutex);
 
+lld_only:
 	return DIV_ROUND_UP(adap->sge.ethqsets, 4) +
 	       tot_uld_entries +
 	       DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
@@ -793,8 +793,8 @@
 	struct port_info *p = netdev_priv(dev);
 
 	epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
-	epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0;
-	epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0;
+	epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0;
+	epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0;
 }
 
 static int set_pauseparam(struct net_device *dev,
@@ -1466,12 +1466,15 @@
 		if (ret)
 			return ret;
 
-		if (!sff8472_comp || (sff_diag_type & 4)) {
+		if (!sff8472_comp || (sff_diag_type & SFP_DIAG_ADDRMODE)) {
 			modinfo->type = ETH_MODULE_SFF_8079;
 			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
 		} else {
 			modinfo->type = ETH_MODULE_SFF_8472;
-			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+			if (sff_diag_type & SFP_DIAG_IMPLEMENTED)
+				modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+			else
+				modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
 		}
 		break;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
@@ -145,13 +145,13 @@
 	int err;
 
 	/* do a set-tcb for smac-sel and CWR bit.. */
-	err = set_tcb_tflag(adap, f, f->tid, TF_CCTRL_CWR_S, 1, 1);
-	if (err)
-		goto smac_err;
-
 	err = set_tcb_field(adap, f, f->tid, TCB_SMAC_SEL_W,
 			    TCB_SMAC_SEL_V(TCB_SMAC_SEL_M),
 			    TCB_SMAC_SEL_V(f->smt->idx), 1);
+	if (err)
+		goto smac_err;
+
+	err = set_tcb_tflag(adap, f, f->tid, TF_CCTRL_CWR_S, 1, 1);
 	if (!err)
 		return 0;
 
@@ -165,37 +165,40 @@
 			   unsigned int tid, bool dip, bool sip, bool dp,
 			   bool sp)
 {
+	u8 *nat_lp = (u8 *)&f->fs.nat_lport;
+	u8 *nat_fp = (u8 *)&f->fs.nat_fport;
+
 	if (dip) {
 		if (f->fs.type) {
 			set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W,
 				      WORD_MASK, f->fs.nat_lip[15] |
 				      f->fs.nat_lip[14] << 8 |
 				      f->fs.nat_lip[13] << 16 |
-				      f->fs.nat_lip[12] << 24, 1);
+				      (u64)f->fs.nat_lip[12] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 1,
 				      WORD_MASK, f->fs.nat_lip[11] |
 				      f->fs.nat_lip[10] << 8 |
 				      f->fs.nat_lip[9] << 16 |
-				      f->fs.nat_lip[8] << 24, 1);
+				      (u64)f->fs.nat_lip[8] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 2,
 				      WORD_MASK, f->fs.nat_lip[7] |
 				      f->fs.nat_lip[6] << 8 |
 				      f->fs.nat_lip[5] << 16 |
-				      f->fs.nat_lip[4] << 24, 1);
+				      (u64)f->fs.nat_lip[4] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_SND_UNA_RAW_W + 3,
 				      WORD_MASK, f->fs.nat_lip[3] |
 				      f->fs.nat_lip[2] << 8 |
 				      f->fs.nat_lip[1] << 16 |
-				      f->fs.nat_lip[0] << 24, 1);
+				      (u64)f->fs.nat_lip[0] << 24, 1);
 		} else {
 			set_tcb_field(adap, f, tid, TCB_RX_FRAG3_LEN_RAW_W,
 				      WORD_MASK, f->fs.nat_lip[3] |
 				      f->fs.nat_lip[2] << 8 |
 				      f->fs.nat_lip[1] << 16 |
-				      f->fs.nat_lip[0] << 24, 1);
+				      (u64)f->fs.nat_lip[0] << 24, 1);
 		}
 	}
 
@@ -205,25 +208,25 @@
 				      WORD_MASK, f->fs.nat_fip[15] |
 				      f->fs.nat_fip[14] << 8 |
 				      f->fs.nat_fip[13] << 16 |
-				      f->fs.nat_fip[12] << 24, 1);
+				      (u64)f->fs.nat_fip[12] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 1,
 				      WORD_MASK, f->fs.nat_fip[11] |
 				      f->fs.nat_fip[10] << 8 |
 				      f->fs.nat_fip[9] << 16 |
-				      f->fs.nat_fip[8] << 24, 1);
+				      (u64)f->fs.nat_fip[8] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 2,
 				      WORD_MASK, f->fs.nat_fip[7] |
 				      f->fs.nat_fip[6] << 8 |
 				      f->fs.nat_fip[5] << 16 |
-				      f->fs.nat_fip[4] << 24, 1);
+				      (u64)f->fs.nat_fip[4] << 24, 1);
 
 			set_tcb_field(adap, f, tid, TCB_RX_FRAG2_PTR_RAW_W + 3,
 				      WORD_MASK, f->fs.nat_fip[3] |
 				      f->fs.nat_fip[2] << 8 |
 				      f->fs.nat_fip[1] << 16 |
-				      f->fs.nat_fip[0] << 24, 1);
+				      (u64)f->fs.nat_fip[0] << 24, 1);
 
 		} else {
 			set_tcb_field(adap, f, tid,
@@ -231,13 +234,14 @@
 				      WORD_MASK, f->fs.nat_fip[3] |
 				      f->fs.nat_fip[2] << 8 |
 				      f->fs.nat_fip[1] << 16 |
-				      f->fs.nat_fip[0] << 24, 1);
+				      (u64)f->fs.nat_fip[0] << 24, 1);
 		}
 	}
 
 	set_tcb_field(adap, f, tid, TCB_PDU_HDR_LEN_W, WORD_MASK,
-		      (dp ? f->fs.nat_lport : 0) |
-		      (sp ? f->fs.nat_fport << 16 : 0), 1);
+		      (dp ? (nat_lp[1] | nat_lp[0] << 8) : 0) |
+		      (sp ? (nat_fp[1] << 16 | (u64)nat_fp[0] << 24) : 0),
+		      1);
 }
 
 /* Validate filter spec against configuration done on the card. */
@@ -608,6 +612,7 @@
 		      FW_FILTER_WR_DIRSTEERHASH_V(f->fs.dirsteerhash) |
 		      FW_FILTER_WR_LPBK_V(f->fs.action == FILTER_SWITCH) |
 		      FW_FILTER_WR_DMAC_V(f->fs.newdmac) |
+		      FW_FILTER_WR_SMAC_V(f->fs.newsmac) |
 		      FW_FILTER_WR_INSVLAN_V(f->fs.newvlan == VLAN_INSERT ||
 					     f->fs.newvlan == VLAN_REWRITE) |
 		      FW_FILTER_WR_RMVLAN_V(f->fs.newvlan == VLAN_REMOVE ||
@@ -625,7 +630,8 @@
 		 FW_FILTER_WR_OVLAN_VLD_V(f->fs.val.ovlan_vld) |
 		 FW_FILTER_WR_IVLAN_VLDM_V(f->fs.mask.ivlan_vld) |
 		 FW_FILTER_WR_OVLAN_VLDM_V(f->fs.mask.ovlan_vld));
-	fwr->smac_sel = 0;
+	if (f->fs.newsmac)
+		fwr->smac_sel = f->smt->idx;
 	fwr->rx_chan_rx_rpl_iq =
 		htons(FW_FILTER_WR_RX_CHAN_V(0) |
 		      FW_FILTER_WR_RX_RPL_IQ_V(adapter->sge.fw_evtq.abs_id));
@@ -656,6 +662,9 @@
 	fwr->fpm = htons(f->fs.mask.fport);
 
 	if (adapter->params.filter2_wr_support) {
+		u8 *nat_lp = (u8 *)&f->fs.nat_lport;
+		u8 *nat_fp = (u8 *)&f->fs.nat_fport;
+
 		fwr->natmode_to_ulp_type =
 			FW_FILTER2_WR_ULP_TYPE_V(f->fs.nat_mode ?
 						 ULP_MODE_TCPDDP :
@@ -663,8 +672,8 @@
 			FW_FILTER2_WR_NATMODE_V(f->fs.nat_mode);
 		memcpy(fwr->newlip, f->fs.nat_lip, sizeof(fwr->newlip));
 		memcpy(fwr->newfip, f->fs.nat_fip, sizeof(fwr->newfip));
-		fwr->newlport = htons(f->fs.nat_lport);
-		fwr->newfport = htons(f->fs.nat_fport);
+		fwr->newlport = htons(nat_lp[1] | nat_lp[0] << 8);
+		fwr->newfport = htons(nat_fp[1] | nat_fp[0] << 8);
 	}
 
 	/* Mark the filter as "pending" and ship off the Filter Work Request.
@@ -769,7 +778,7 @@
 				cxgb4_del_filter(dev, i, &f->fs);
 		}
 
-		sb = t4_read_reg(adapter, LE_DB_SRVR_START_INDEX_A);
+		sb = adapter->tids.stid_base;
 		for (i = 0; i < sb; i++) {
 			f = (struct filter_entry *)adapter->tids.tid_tab[i];
 
@@ -832,16 +841,16 @@
 		struct in_addr *addr;
 
 		addr = (struct in_addr *)ipmask;
-		if (addr->s_addr == 0xffffffff)
+		if (addr->s_addr == htonl(0xffffffff))
 			return true;
 	} else if (family == AF_INET6) {
 		struct in6_addr *addr6;
 
 		addr6 = (struct in6_addr *)ipmask;
-		if (addr6->s6_addr32[0] == 0xffffffff &&
-		    addr6->s6_addr32[1] == 0xffffffff &&
-		    addr6->s6_addr32[2] == 0xffffffff &&
-		    addr6->s6_addr32[3] == 0xffffffff)
+		if (addr6->s6_addr32[0] == htonl(0xffffffff) &&
+		    addr6->s6_addr32[1] == htonl(0xffffffff) &&
+		    addr6->s6_addr32[2] == htonl(0xffffffff) &&
+		    addr6->s6_addr32[3] == htonl(0xffffffff))
 			return true;
 	}
 	return false;
@@ -1041,11 +1050,8 @@
 			    TX_QUEUE_V(f->fs.nat_mode) |
 			    T5_OPT_2_VALID_F |
 			    RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) |
-			    CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
-					 (f->fs.dirsteer << 1)) |
 			    PACE_V((f->fs.maskhash) |
-				   ((f->fs.dirsteerhash) << 1)) |
-			    CCTRL_ECN_V(f->fs.action == FILTER_SWITCH));
+				   ((f->fs.dirsteerhash) << 1)));
 }
 
 static void mk_act_open_req(struct filter_entry *f, struct sk_buff *skb,
@@ -1081,11 +1087,8 @@
 			    TX_QUEUE_V(f->fs.nat_mode) |
 			    T5_OPT_2_VALID_F |
 			    RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) |
-			    CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
-					 (f->fs.dirsteer << 1)) |
 			    PACE_V((f->fs.maskhash) |
-				   ((f->fs.dirsteerhash) << 1)) |
-			    CCTRL_ECN_V(f->fs.action == FILTER_SWITCH));
+				   ((f->fs.dirsteerhash) << 1)));
 }
 
 static int cxgb4_set_hash_filter(struct net_device *dev,
@@ -1610,13 +1613,16 @@
 static int configure_filter_tcb(struct adapter *adap, unsigned int tid,
 				struct filter_entry *f)
 {
-	if (f->fs.hitcnts)
+	if (f->fs.hitcnts) {
 		set_tcb_field(adap, f, tid, TCB_TIMESTAMP_W,
-			      TCB_TIMESTAMP_V(TCB_TIMESTAMP_M) |
+			      TCB_TIMESTAMP_V(TCB_TIMESTAMP_M),
+			      TCB_TIMESTAMP_V(0ULL),
+			      1);
+		set_tcb_field(adap, f, tid, TCB_RTT_TS_RECENT_AGE_W,
 			      TCB_RTT_TS_RECENT_AGE_V(TCB_RTT_TS_RECENT_AGE_M),
-			      TCB_TIMESTAMP_V(0ULL) |
 			      TCB_RTT_TS_RECENT_AGE_V(0ULL),
 			      1);
+	}
 
 	if (f->fs.newdmac)
 		set_tcb_tflag(adap, f, tid, TF_CCTRL_ECE_S, 1,
@@ -1738,6 +1744,20 @@
 			}
 			return;
 		}
+		switch (f->fs.action) {
+		case FILTER_PASS:
+			if (f->fs.dirsteer)
+				set_tcb_tflag(adap, f, tid,
+					      TF_DIRECT_STEER_S, 1, 1);
+			break;
+		case FILTER_DROP:
+			set_tcb_tflag(adap, f, tid, TF_DROP_S, 1, 1);
+			break;
+		case FILTER_SWITCH:
+			set_tcb_tflag(adap, f, tid, TF_LPBK_S, 1, 1);
+			break;
+		}
+
 		break;
 
 	default:
@@ -1798,22 +1818,11 @@
 			if (ctx)
 				ctx->result = 0;
 		} else if (ret == FW_FILTER_WR_FLT_ADDED) {
-			int err = 0;
-
-			if (f->fs.newsmac)
-				err = configure_filter_smac(adap, f);
-
-			if (!err) {
-				f->pending = 0;  /* async setup completed */
-				f->valid = 1;
-				if (ctx) {
-					ctx->result = 0;
-					ctx->tid = idx;
-				}
-			} else {
-				clear_filter(adap, f);
-				if (ctx)
-					ctx->result = err;
+			f->pending = 0;  /* async setup completed */
+			f->valid = 1;
+			if (ctx) {
+				ctx->result = 0;
+				ctx->tid = idx;
 			}
 		} else {
 			/* Something went wrong.  Issue a warning about the
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2245,6 +2245,9 @@
 {
 	unsigned int i;
 
+	if (!is_uld(adap))
+		return;
+
 	mutex_lock(&uld_mutex);
 	list_del(&adap->list_node);
 
@@ -2504,7 +2507,7 @@
 
 	/* Clear out filter specifications */
 	memset(&f->fs, 0, sizeof(struct ch_filter_specification));
-	f->fs.val.lport = cpu_to_be16(sport);
+	f->fs.val.lport = be16_to_cpu(sport);
 	f->fs.mask.lport  = ~0;
 	val = (u8 *)&sip;
 	if ((val[0] | val[1] | val[2] | val[3]) != 0) {
@@ -3032,7 +3035,6 @@
 		return ret;
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	pi->xact_addr_filt = ret;
 	return 0;
 }
 
@@ -6153,10 +6155,13 @@
 		 */
 		destroy_workqueue(adapter->workq);
 
-		if (is_uld(adapter)) {
-			detach_ulds(adapter);
-			t4_uld_clean_up(adapter);
-		}
+		detach_ulds(adapter);
+
+		for_each_port(adapter, i)
+			if (adapter->port[i]->reg_state == NETREG_REGISTERED)
+				unregister_netdev(adapter->port[i]);
+
+		t4_uld_clean_up(adapter);
 
 		adap_free_hma_mem(adapter);
 
@@ -6164,10 +6169,6 @@
 
 		cxgb4_free_mps_ref_entries(adapter);
 
-		for_each_port(adapter, i)
-			if (adapter->port[i]->reg_state == NETREG_REGISTERED)
-				unregister_netdev(adapter->port[i]);
-
 		debugfs_remove_recursive(adapter->debugfs_root);
 
 		if (!is_t4(adapter->params.chip))
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
@@ -229,7 +229,7 @@
 {
 	struct mps_entries_ref *mps_entry, *tmp;
 
-	if (!list_empty(&adap->mps_ref))
+	if (list_empty(&adap->mps_ref))
 		return;
 
 	spin_lock(&adap->mps_ref_lock);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
@@ -246,6 +246,9 @@
 			     FW_PTP_CMD_PORTID_V(0));
 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
 	c.u.ts.sc = FW_PTP_SC_ADJ_FTIME;
+	c.u.ts.sign = (delta < 0) ? 1 : 0;
+	if (delta < 0)
+		delta = -delta;
 	c.u.ts.tm = cpu_to_be64(delta);
 
 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
@@ -308,32 +311,17 @@
  */
 static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
 {
-	struct adapter *adapter = (struct adapter *)container_of(ptp,
-				   struct adapter, ptp_clock_info);
-	struct fw_ptp_cmd c;
+	struct adapter *adapter = container_of(ptp, struct adapter,
+					       ptp_clock_info);
 	u64 ns;
-	int err;
 
-	memset(&c, 0, sizeof(c));
-	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
-				     FW_CMD_REQUEST_F |
-				     FW_CMD_READ_F |
-				     FW_PTP_CMD_PORTID_V(0));
-	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
-	c.u.ts.sc = FW_PTP_SC_GET_TIME;
-
-	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), &c);
-	if (err < 0) {
-		dev_err(adapter->pdev_dev,
-			"PTP: %s error %d\n", __func__, -err);
-		return err;
-	}
+	ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A));
+	ns |= (u64)t4_read_reg(adapter,
+			       T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32;
 
 	/* convert to timespec*/
-	ns = be64_to_cpu(c.u.ts.tm);
 	*ts = ns_to_timespec64(ns);
-
-	return err;
+	return 0;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
@@ -58,12 +58,91 @@
 	PEDIT_FIELDS(IP6_, DST_63_32, 4, nat_lip, 4),
 	PEDIT_FIELDS(IP6_, DST_95_64, 4, nat_lip, 8),
 	PEDIT_FIELDS(IP6_, DST_127_96, 4, nat_lip, 12),
-	PEDIT_FIELDS(TCP_, SPORT, 2, nat_fport, 0),
-	PEDIT_FIELDS(TCP_, DPORT, 2, nat_lport, 0),
-	PEDIT_FIELDS(UDP_, SPORT, 2, nat_fport, 0),
-	PEDIT_FIELDS(UDP_, DPORT, 2, nat_lport, 0),
 };
 
+static const struct cxgb4_natmode_config cxgb4_natmode_config_array[] = {
+	/* Default supported NAT modes */
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_NONE,
+		.natmode = NAT_MODE_NONE,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP,
+		.natmode = NAT_MODE_DIP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT,
+		.natmode = NAT_MODE_DIP_DP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT |
+			 CXGB4_ACTION_NATMODE_SIP,
+		.natmode = NAT_MODE_DIP_DP_SIP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT |
+			 CXGB4_ACTION_NATMODE_SPORT,
+		.natmode = NAT_MODE_DIP_DP_SP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_SIP | CXGB4_ACTION_NATMODE_SPORT,
+		.natmode = NAT_MODE_SIP_SP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP |
+			 CXGB4_ACTION_NATMODE_SPORT,
+		.natmode = NAT_MODE_DIP_SIP_SP,
+	},
+	{
+		.chip = CHELSIO_T5,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP |
+			 CXGB4_ACTION_NATMODE_DPORT |
+			 CXGB4_ACTION_NATMODE_SPORT,
+		.natmode = NAT_MODE_ALL,
+	},
+	/* T6+ can ignore L4 ports when they're disabled. */
+	{
+		.chip = CHELSIO_T6,
+		.flags = CXGB4_ACTION_NATMODE_SIP,
+		.natmode = NAT_MODE_SIP_SP,
+	},
+	{
+		.chip = CHELSIO_T6,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SPORT,
+		.natmode = NAT_MODE_DIP_DP_SP,
+	},
+	{
+		.chip = CHELSIO_T6,
+		.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP,
+		.natmode = NAT_MODE_ALL,
+	},
+};
+
+static void cxgb4_action_natmode_tweak(struct ch_filter_specification *fs,
+				       u8 natmode_flags)
+{
+	u8 i = 0;
+
+	/* Translate the enabled NAT 4-tuple fields to one of the
+	 * hardware supported NAT mode configurations. This ensures
+	 * that we pick a valid combination, where the disabled fields
+	 * do not get overwritten to 0.
+	 */
+	for (i = 0; i < ARRAY_SIZE(cxgb4_natmode_config_array); i++) {
+		if (cxgb4_natmode_config_array[i].flags == natmode_flags) {
+			fs->nat_mode = cxgb4_natmode_config_array[i].natmode;
+			return;
+		}
+	}
+}
+
 static struct ch_tc_flower_entry *allocate_flower_entry(void)
 {
 	struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
@@ -156,14 +235,14 @@
 		struct flow_match_ports match;
 
 		flow_rule_match_ports(rule, &match);
-		fs->val.lport = cpu_to_be16(match.key->dst);
-		fs->mask.lport = cpu_to_be16(match.mask->dst);
-		fs->val.fport = cpu_to_be16(match.key->src);
-		fs->mask.fport = cpu_to_be16(match.mask->src);
+		fs->val.lport = be16_to_cpu(match.key->dst);
+		fs->mask.lport = be16_to_cpu(match.mask->dst);
+		fs->val.fport = be16_to_cpu(match.key->src);
+		fs->mask.fport = be16_to_cpu(match.mask->src);
 
 		/* also initialize nat_lport/fport to same values */
-		fs->nat_lport = cpu_to_be16(match.key->dst);
-		fs->nat_fport = cpu_to_be16(match.key->src);
+		fs->nat_lport = fs->val.lport;
+		fs->nat_fport = fs->val.fport;
 	}
 
 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
@@ -291,7 +370,8 @@
 }
 
 static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
-				u32 mask, u32 offset, u8 htype)
+				u32 mask, u32 offset, u8 htype,
+				u8 *natmode_flags)
 {
 	switch (htype) {
 	case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
@@ -316,74 +396,104 @@
 		switch (offset) {
 		case PEDIT_IP4_SRC:
 			offload_pedit(fs, val, mask, IP4_SRC);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
 			break;
 		case PEDIT_IP4_DST:
 			offload_pedit(fs, val, mask, IP4_DST);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 		}
-		fs->nat_mode = NAT_MODE_ALL;
 		break;
 	case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
 		switch (offset) {
 		case PEDIT_IP6_SRC_31_0:
 			offload_pedit(fs, val, mask, IP6_SRC_31_0);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
 			break;
 		case PEDIT_IP6_SRC_63_32:
 			offload_pedit(fs, val, mask, IP6_SRC_63_32);
+			*natmode_flags |=  CXGB4_ACTION_NATMODE_SIP;
 			break;
 		case PEDIT_IP6_SRC_95_64:
 			offload_pedit(fs, val, mask, IP6_SRC_95_64);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
 			break;
 		case PEDIT_IP6_SRC_127_96:
 			offload_pedit(fs, val, mask, IP6_SRC_127_96);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
 			break;
 		case PEDIT_IP6_DST_31_0:
 			offload_pedit(fs, val, mask, IP6_DST_31_0);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 			break;
 		case PEDIT_IP6_DST_63_32:
 			offload_pedit(fs, val, mask, IP6_DST_63_32);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 			break;
 		case PEDIT_IP6_DST_95_64:
 			offload_pedit(fs, val, mask, IP6_DST_95_64);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 			break;
 		case PEDIT_IP6_DST_127_96:
 			offload_pedit(fs, val, mask, IP6_DST_127_96);
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 		}
-		fs->nat_mode = NAT_MODE_ALL;
 		break;
 	case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
 		switch (offset) {
 		case PEDIT_TCP_SPORT_DPORT:
-			if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
-				offload_pedit(fs, cpu_to_be32(val) >> 16,
-					      cpu_to_be32(mask) >> 16,
-					      TCP_SPORT);
-			else
-				offload_pedit(fs, cpu_to_be32(val),
-					      cpu_to_be32(mask), TCP_DPORT);
+			if (~mask & PEDIT_TCP_UDP_SPORT_MASK) {
+				fs->nat_fport = val;
+				*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
+			} else {
+				fs->nat_lport = val >> 16;
+				*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
+			}
 		}
-		fs->nat_mode = NAT_MODE_ALL;
 		break;
 	case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
 		switch (offset) {
 		case PEDIT_UDP_SPORT_DPORT:
-			if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
-				offload_pedit(fs, cpu_to_be32(val) >> 16,
-					      cpu_to_be32(mask) >> 16,
-					      UDP_SPORT);
-			else
-				offload_pedit(fs, cpu_to_be32(val),
-					      cpu_to_be32(mask), UDP_DPORT);
+			if (~mask & PEDIT_TCP_UDP_SPORT_MASK) {
+				fs->nat_fport = val;
+				*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
+			} else {
+				fs->nat_lport = val >> 16;
+				*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
+			}
 		}
-		fs->nat_mode = NAT_MODE_ALL;
+		break;
 	}
 }
 
+static int cxgb4_action_natmode_validate(struct net_device *dev,
+					 struct adapter *adap, u8 natmode_flags)
+{
+	u8 i = 0;
+
+	/* Extract the NAT mode to enable based on what 4-tuple fields
+	 * are enabled to be overwritten. This ensures that the
+	 * disabled fields don't get overwritten to 0.
+	 */
+	for (i = 0; i < ARRAY_SIZE(cxgb4_natmode_config_array); i++) {
+		const struct cxgb4_natmode_config *c;
+
+		c = &cxgb4_natmode_config_array[i];
+		if (CHELSIO_CHIP_VERSION(adap->params.chip) >= c->chip &&
+		    natmode_flags == c->flags)
+			return 0;
+	}
+	netdev_err(dev, "%s: Unsupported NAT mode 4-tuple combination\n",
+		   __func__);
+	return -EOPNOTSUPP;
+}
+
 static void cxgb4_process_flow_actions(struct net_device *in,
 				       struct flow_cls_offload *cls,
 				       struct ch_filter_specification *fs)
 {
 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
 	struct flow_action_entry *act;
+	u8 natmode_flags = 0;
 	int i;
 
 	flow_action_for_each(i, act, &rule->action) {
@@ -434,13 +544,17 @@
 			val = act->mangle.val;
 			offset = act->mangle.offset;
 
-			process_pedit_field(fs, val, mask, offset, htype);
+			process_pedit_field(fs, val, mask, offset, htype,
+					    &natmode_flags);
 			}
 			break;
 		default:
 			break;
 		}
 	}
+	if (natmode_flags)
+		cxgb4_action_natmode_tweak(fs, natmode_flags);
+
 }
 
 static bool valid_l4_mask(u32 mask)
@@ -457,7 +571,8 @@
 }
 
 static bool valid_pedit_action(struct net_device *dev,
-			       const struct flow_action_entry *act)
+			       const struct flow_action_entry *act,
+			       u8 *natmode_flags)
 {
 	u32 mask, offset;
 	u8 htype;
@@ -482,7 +597,10 @@
 	case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
 		switch (offset) {
 		case PEDIT_IP4_SRC:
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
+			break;
 		case PEDIT_IP4_DST:
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 			break;
 		default:
 			netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -496,10 +614,13 @@
 		case PEDIT_IP6_SRC_63_32:
 		case PEDIT_IP6_SRC_95_64:
 		case PEDIT_IP6_SRC_127_96:
+			*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
+			break;
 		case PEDIT_IP6_DST_31_0:
 		case PEDIT_IP6_DST_63_32:
 		case PEDIT_IP6_DST_95_64:
 		case PEDIT_IP6_DST_127_96:
+			*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
 			break;
 		default:
 			netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -515,6 +636,10 @@
 					   __func__);
 				return false;
 			}
+			if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
+				*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
+			else
+				*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
 			break;
 		default:
 			netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -530,6 +655,10 @@
 					   __func__);
 				return false;
 			}
+			if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
+				*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
+			else
+				*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
 			break;
 		default:
 			netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -548,10 +677,12 @@
 				       struct flow_cls_offload *cls)
 {
 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+	struct adapter *adap = netdev2adap(dev);
 	struct flow_action_entry *act;
 	bool act_redir = false;
 	bool act_pedit = false;
 	bool act_vlan = false;
+	u8 natmode_flags = 0;
 	int i;
 
 	flow_action_for_each(i, act, &rule->action) {
@@ -561,7 +692,6 @@
 			/* Do nothing */
 			break;
 		case FLOW_ACTION_REDIRECT: {
-			struct adapter *adap = netdev2adap(dev);
 			struct net_device *n_dev, *target_dev;
 			unsigned int i;
 			bool found = false;
@@ -611,7 +741,8 @@
 			}
 			break;
 		case FLOW_ACTION_MANGLE: {
-			bool pedit_valid = valid_pedit_action(dev, act);
+			bool pedit_valid = valid_pedit_action(dev, act,
+							      &natmode_flags);
 
 			if (!pedit_valid)
 				return -EOPNOTSUPP;
@@ -630,6 +761,14 @@
 		return -EINVAL;
 	}
 
+	if (act_pedit) {
+		int ret;
+
+		ret = cxgb4_action_natmode_validate(dev, adap, natmode_flags);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
@@ -108,6 +108,21 @@
 #define PEDIT_TCP_SPORT_DPORT		0x0
 #define PEDIT_UDP_SPORT_DPORT		0x0
 
+enum cxgb4_action_natmode_flags {
+	CXGB4_ACTION_NATMODE_NONE = 0,
+	CXGB4_ACTION_NATMODE_DIP = (1 << 0),
+	CXGB4_ACTION_NATMODE_SIP = (1 << 1),
+	CXGB4_ACTION_NATMODE_DPORT = (1 << 2),
+	CXGB4_ACTION_NATMODE_SPORT = (1 << 3),
+};
+
+/* TC PEDIT action to NATMODE translation entry */
+struct cxgb4_natmode_config {
+	enum chip_type chip;
+	u8 flags;
+	u8 natmode;
+};
+
 int cxgb4_tc_flower_replace(struct net_device *dev,
 			    struct flow_cls_offload *cls);
 int cxgb4_tc_flower_destroy(struct net_device *dev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c
@@ -47,7 +47,7 @@
 			     bool next_header)
 {
 	unsigned int i, j;
-	u32 val, mask;
+	__be32 val, mask;
 	int off, err;
 	bool found;
 
@@ -216,7 +216,7 @@
 		const struct cxgb4_next_header *next;
 		bool found = false;
 		unsigned int i, j;
-		u32 val, mask;
+		__be32 val, mask;
 		int off;
 
 		if (t->table[link_uhtid - 1].link_handle) {
@@ -230,10 +230,10 @@
 
 		/* Try to find matches that allow jumps to next header. */
 		for (i = 0; next[i].jump; i++) {
-			if (next[i].offoff != cls->knode.sel->offoff ||
-			    next[i].shift != cls->knode.sel->offshift ||
-			    next[i].mask != cls->knode.sel->offmask ||
-			    next[i].offset != cls->knode.sel->off)
+			if (next[i].sel.offoff != cls->knode.sel->offoff ||
+			    next[i].sel.offshift != cls->knode.sel->offshift ||
+			    next[i].sel.offmask != cls->knode.sel->offmask ||
+			    next[i].sel.off != cls->knode.sel->off)
 				continue;
 
 			/* Found a possible candidate.  Find a key that
@@ -245,9 +245,9 @@
 				val = cls->knode.sel->keys[j].val;
 				mask = cls->knode.sel->keys[j].mask;
 
-				if (next[i].match_off == off &&
-				    next[i].match_val == val &&
-				    next[i].match_mask == mask) {
+				if (next[i].key.off == off &&
+				    next[i].key.val == val &&
+				    next[i].key.mask == mask) {
 					found = true;
 					break;
 				}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h
@@ -38,12 +38,12 @@
 struct cxgb4_match_field {
 	int off; /* Offset from the beginning of the header to match */
 	/* Fill the value/mask pair in the spec if matched */
-	int (*val)(struct ch_filter_specification *f, u32 val, u32 mask);
+	int (*val)(struct ch_filter_specification *f, __be32 val, __be32 mask);
 };
 
 /* IPv4 match fields */
 static inline int cxgb4_fill_ipv4_tos(struct ch_filter_specification *f,
-				      u32 val, u32 mask)
+				      __be32 val, __be32 mask)
 {
 	f->val.tos  = (ntohl(val)  >> 16) & 0x000000FF;
 	f->mask.tos = (ntohl(mask) >> 16) & 0x000000FF;
@@ -52,7 +52,7 @@
 }
 
 static inline int cxgb4_fill_ipv4_frag(struct ch_filter_specification *f,
-				       u32 val, u32 mask)
+				       __be32 val, __be32 mask)
 {
 	u32 mask_val;
 	u8 frag_val;
@@ -74,7 +74,7 @@
 }
 
 static inline int cxgb4_fill_ipv4_proto(struct ch_filter_specification *f,
-					u32 val, u32 mask)
+					__be32 val, __be32 mask)
 {
 	f->val.proto  = (ntohl(val)  >> 16) & 0x000000FF;
 	f->mask.proto = (ntohl(mask) >> 16) & 0x000000FF;
@@ -83,7 +83,7 @@
 }
 
 static inline int cxgb4_fill_ipv4_src_ip(struct ch_filter_specification *f,
-					 u32 val, u32 mask)
+					 __be32 val, __be32 mask)
 {
 	memcpy(&f->val.fip[0],  &val,  sizeof(u32));
 	memcpy(&f->mask.fip[0], &mask, sizeof(u32));
@@ -92,7 +92,7 @@
 }
 
 static inline int cxgb4_fill_ipv4_dst_ip(struct ch_filter_specification *f,
-					 u32 val, u32 mask)
+					 __be32 val, __be32 mask)
 {
 	memcpy(&f->val.lip[0],  &val,  sizeof(u32));
 	memcpy(&f->mask.lip[0], &mask, sizeof(u32));
@@ -111,7 +111,7 @@
 
 /* IPv6 match fields */
 static inline int cxgb4_fill_ipv6_tos(struct ch_filter_specification *f,
-				      u32 val, u32 mask)
+				      __be32 val, __be32 mask)
 {
 	f->val.tos  = (ntohl(val)  >> 20) & 0x000000FF;
 	f->mask.tos = (ntohl(mask) >> 20) & 0x000000FF;
@@ -120,7 +120,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_proto(struct ch_filter_specification *f,
-					u32 val, u32 mask)
+					__be32 val, __be32 mask)
 {
 	f->val.proto  = (ntohl(val)  >> 8) & 0x000000FF;
 	f->mask.proto = (ntohl(mask) >> 8) & 0x000000FF;
@@ -129,7 +129,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_src_ip0(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.fip[0],  &val,  sizeof(u32));
 	memcpy(&f->mask.fip[0], &mask, sizeof(u32));
@@ -138,7 +138,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_src_ip1(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.fip[4],  &val,  sizeof(u32));
 	memcpy(&f->mask.fip[4], &mask, sizeof(u32));
@@ -147,7 +147,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_src_ip2(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.fip[8],  &val,  sizeof(u32));
 	memcpy(&f->mask.fip[8], &mask, sizeof(u32));
@@ -156,7 +156,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_src_ip3(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.fip[12],  &val,  sizeof(u32));
 	memcpy(&f->mask.fip[12], &mask, sizeof(u32));
@@ -165,7 +165,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_dst_ip0(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.lip[0],  &val,  sizeof(u32));
 	memcpy(&f->mask.lip[0], &mask, sizeof(u32));
@@ -174,7 +174,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_dst_ip1(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.lip[4],  &val,  sizeof(u32));
 	memcpy(&f->mask.lip[4], &mask, sizeof(u32));
@@ -183,7 +183,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_dst_ip2(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.lip[8],  &val,  sizeof(u32));
 	memcpy(&f->mask.lip[8], &mask, sizeof(u32));
@@ -192,7 +192,7 @@
 }
 
 static inline int cxgb4_fill_ipv6_dst_ip3(struct ch_filter_specification *f,
-					  u32 val, u32 mask)
+					  __be32 val, __be32 mask)
 {
 	memcpy(&f->val.lip[12],  &val,  sizeof(u32));
 	memcpy(&f->mask.lip[12], &mask, sizeof(u32));
@@ -216,7 +216,7 @@
 
 /* TCP/UDP match */
 static inline int cxgb4_fill_l4_ports(struct ch_filter_specification *f,
-				      u32 val, u32 mask)
+				      __be32 val, __be32 mask)
 {
 	f->val.fport  = ntohl(val)  >> 16;
 	f->mask.fport = ntohl(mask) >> 16;
@@ -237,19 +237,13 @@
 };
 
 struct cxgb4_next_header {
-	unsigned int offset; /* Offset to next header */
-	/* offset, shift, and mask added to offset above
+	/* Offset, shift, and mask added to beginning of the header
 	 * to get to next header.  Useful when using a header
 	 * field's value to jump to next header such as IHL field
 	 * in IPv4 header.
 	 */
-	unsigned int offoff;
-	u32 shift;
-	u32 mask;
-	/* match criteria to make this jump */
-	unsigned int match_off;
-	u32 match_val;
-	u32 match_mask;
+	struct tc_u32_sel sel;
+	struct tc_u32_key key;
 	/* location of jump to make */
 	const struct cxgb4_match_field *jump;
 };
@@ -258,26 +252,74 @@
  * IPv4 header.
  */
 static const struct cxgb4_next_header cxgb4_ipv4_jumps[] = {
-	{ .offset = 0, .offoff = 0, .shift = 6, .mask = 0xF,
-	  .match_off = 8, .match_val = 0x600, .match_mask = 0xFF00,
-	  .jump = cxgb4_tcp_fields },
-	{ .offset = 0, .offoff = 0, .shift = 6, .mask = 0xF,
-	  .match_off = 8, .match_val = 0x1100, .match_mask = 0xFF00,
-	  .jump = cxgb4_udp_fields },
-	{ .jump = NULL }
+	{
+		/* TCP Jump */
+		.sel = {
+			.off = 0,
+			.offoff = 0,
+			.offshift = 6,
+			.offmask = cpu_to_be16(0x0f00),
+		},
+		.key = {
+			.off = 8,
+			.val = cpu_to_be32(0x00060000),
+			.mask = cpu_to_be32(0x00ff0000),
+		},
+		.jump = cxgb4_tcp_fields,
+	},
+	{
+		/* UDP Jump */
+		.sel = {
+			.off = 0,
+			.offoff = 0,
+			.offshift = 6,
+			.offmask = cpu_to_be16(0x0f00),
+		},
+		.key = {
+			.off = 8,
+			.val = cpu_to_be32(0x00110000),
+			.mask = cpu_to_be32(0x00ff0000),
+		},
+		.jump = cxgb4_udp_fields,
+	},
+	{ .jump = NULL },
 };
 
 /* Accept a rule with a jump directly past the 40 Bytes of IPv6 fixed header
  * to get to transport layer header.
  */
 static const struct cxgb4_next_header cxgb4_ipv6_jumps[] = {
-	{ .offset = 0x28, .offoff = 0, .shift = 0, .mask = 0,
-	  .match_off = 4, .match_val = 0x60000, .match_mask = 0xFF0000,
-	  .jump = cxgb4_tcp_fields },
-	{ .offset = 0x28, .offoff = 0, .shift = 0, .mask = 0,
-	  .match_off = 4, .match_val = 0x110000, .match_mask = 0xFF0000,
-	  .jump = cxgb4_udp_fields },
-	{ .jump = NULL }
+	{
+		/* TCP Jump */
+		.sel = {
+			.off = 40,
+			.offoff = 0,
+			.offshift = 0,
+			.offmask = 0,
+		},
+		.key = {
+			.off = 4,
+			.val = cpu_to_be32(0x00000600),
+			.mask = cpu_to_be32(0x0000ff00),
+		},
+		.jump = cxgb4_tcp_fields,
+	},
+	{
+		/* UDP Jump */
+		.sel = {
+			.off = 40,
+			.offoff = 0,
+			.offshift = 0,
+			.offmask = 0,
+		},
+		.key = {
+			.off = 4,
+			.val = cpu_to_be32(0x00001100),
+			.mask = cpu_to_be32(0x0000ff00),
+		},
+		.jump = cxgb4_udp_fields,
+	},
+	{ .jump = NULL },
 };
 
 struct cxgb4_link {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c
@@ -62,6 +62,7 @@
 int cxgb4_thermal_init(struct adapter *adap)
 {
 	struct ch_thermal *ch_thermal = &adap->ch_thermal;
+	char ch_tz_name[THERMAL_NAME_LENGTH];
 	int num_trip = CXGB4_NUM_TRIPS;
 	u32 param, val;
 	int ret;
@@ -82,7 +83,8 @@
 		ch_thermal->trip_type = THERMAL_TRIP_CRITICAL;
 	}
 
-	ch_thermal->tzdev = thermal_zone_device_register("cxgb4", num_trip,
+	snprintf(ch_tz_name, sizeof(ch_tz_name), "cxgb4_%s", adap->name);
+	ch_thermal->tzdev = thermal_zone_device_register(ch_tz_name, num_trip,
 							 0, adap,
 							 &cxgb4_thermal_ops,
 							 NULL, 0, 0);
@@ -97,7 +99,9 @@
 
 int cxgb4_thermal_remove(struct adapter *adap)
 {
-	if (adap->ch_thermal.tzdev)
+	if (adap->ch_thermal.tzdev) {
 		thermal_zone_device_unregister(adap->ch_thermal.tzdev);
+		adap->ch_thermal.tzdev = NULL;
+	}
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -638,6 +638,9 @@
 {
 	unsigned int i;
 
+	if (!is_uld(adap))
+		return;
+
 	mutex_lock(&uld_mutex);
 	for (i = 0; i < CXGB4_ULD_MAX; i++) {
 		if (!adap->uld[i].handle)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -44,6 +44,9 @@
 
 #define MAX_ULD_QSETS 16
 
+/* ulp_mem_io + ulptx_idata + payload + padding */
+#define MAX_IMM_ULPTX_WR_LEN (32 + 8 + 256 + 8)
+
 /* CPL message priority levels */
 enum {
 	CPL_PRIORITY_DATA     = 0,  /* data messages */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -507,40 +507,19 @@
 EXPORT_SYMBOL(cxgb4_select_ntuple);
 
 /*
- * Called when address resolution fails for an L2T entry to handle packets
- * on the arpq head.  If a packet specifies a failure handler it is invoked,
- * otherwise the packet is sent to the device.
- */
-static void handle_failed_resolution(struct adapter *adap, struct l2t_entry *e)
-{
-	struct sk_buff *skb;
-
-	while ((skb = __skb_dequeue(&e->arpq)) != NULL) {
-		const struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
-
-		spin_unlock(&e->lock);
-		if (cb->arp_err_handler)
-			cb->arp_err_handler(cb->handle, skb);
-		else
-			t4_ofld_send(adap, skb);
-		spin_lock(&e->lock);
-	}
-}
-
-/*
  * Called when the host's neighbor layer makes a change to some entry that is
  * loaded into the HW L2 table.
  */
 void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
 {
-	struct l2t_entry *e;
-	struct sk_buff_head *arpq = NULL;
-	struct l2t_data *d = adap->l2t;
 	unsigned int addr_len = neigh->tbl->key_len;
 	u32 *addr = (u32 *) neigh->primary_key;
-	int ifidx = neigh->dev->ifindex;
-	int hash = addr_hash(d, addr, addr_len, ifidx);
+	int hash, ifidx = neigh->dev->ifindex;
+	struct sk_buff_head *arpq = NULL;
+	struct l2t_data *d = adap->l2t;
+	struct l2t_entry *e;
 
+	hash = addr_hash(d, addr, addr_len, ifidx);
 	read_lock_bh(&d->lock);
 	for (e = d->l2tab[hash].first; e; e = e->next)
 		if (!addreq(e, addr) && e->ifindex == ifidx) {
@@ -573,8 +552,25 @@
 			write_l2e(adap, e, 0);
 	}
 
-	if (arpq)
-		handle_failed_resolution(adap, e);
+	if (arpq) {
+		struct sk_buff *skb;
+
+		/* Called when address resolution fails for an L2T
+		 * entry to handle packets on the arpq head. If a
+		 * packet specifies a failure handler it is invoked,
+		 * otherwise the packet is sent to the device.
+		 */
+		while ((skb = __skb_dequeue(&e->arpq)) != NULL) {
+			const struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+			spin_unlock(&e->lock);
+			if (cb->arp_err_handler)
+				cb->arp_err_handler(cb->handle, skb);
+			else
+				t4_ofld_send(adap, skb);
+			spin_lock(&e->lock);
+		}
+	}
 	spin_unlock_bh(&e->lock);
 }
 
@@ -682,8 +678,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-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -1324,8 +1324,9 @@
 int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq,
 				 int maxreclaim)
 {
+	unsigned int reclaimed, hw_cidx;
 	struct sge_txq *q = &eq->q;
-	unsigned int reclaimed;
+	int hw_in_use;
 
 	if (!q->in_use || !__netif_tx_trylock(eq->txq))
 		return 0;
@@ -1333,12 +1334,17 @@
 	/* Reclaim pending completed TX Descriptors. */
 	reclaimed = reclaim_completed_tx(adap, &eq->q, maxreclaim, true);
 
+	hw_cidx = ntohs(READ_ONCE(q->stat->cidx));
+	hw_in_use = q->pidx - hw_cidx;
+	if (hw_in_use < 0)
+		hw_in_use += q->size;
+
 	/* If the TX Queue is currently stopped and there's now more than half
 	 * the queue available, restart it.  Otherwise bail out since the rest
 	 * of what we want do here is with the possibility of shipping any
 	 * currently buffered Coalesced TX Work Request.
 	 */
-	if (netif_tx_queue_stopped(eq->txq) && txq_avail(q) > (q->size / 2)) {
+	if (netif_tx_queue_stopped(eq->txq) && hw_in_use < (q->size / 2)) {
 		netif_tx_wake_queue(eq->txq);
 		eq->q.restarts++;
 	}
@@ -1469,16 +1475,7 @@
 		 * has opened up.
 		 */
 		eth_txq_stop(q);
-
-		/* If we're using the SGE Doorbell Queue Timer facility, we
-		 * don't need to ask the Firmware to send us Egress Queue CIDX
-		 * Updates: the Hardware will do this automatically.  And
-		 * since we send the Ingress Queue CIDX Updates to the
-		 * corresponding Ethernet Response Queue, we'll get them very
-		 * quickly.
-		 */
-		if (!q->dbqt)
-			wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
+		wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
 	}
 
 	wr = (void *)&q->q.desc[q->q.pidx];
@@ -1792,16 +1789,7 @@
 		 * has opened up.
 		 */
 		eth_txq_stop(txq);
-
-		/* If we're using the SGE Doorbell Queue Timer facility, we
-		 * don't need to ask the Firmware to send us Egress Queue CIDX
-		 * Updates: the Hardware will do this automatically.  And
-		 * since we send the Ingress Queue CIDX Updates to the
-		 * corresponding Ethernet Response Queue, we'll get them very
-		 * quickly.
-		 */
-		if (!txq->dbqt)
-			wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
+		wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
 	}
 
 	/* Start filling in our Work Request.  Note that we do _not_ handle
@@ -2170,17 +2158,22 @@
  *	@skb: the packet
  *
  *	Returns true if a packet can be sent as an offload WR with immediate
- *	data.  We currently use the same limit as for Ethernet packets.
+ *	data.
+ *	FW_OFLD_TX_DATA_WR limits the payload to 255 bytes due to 8-bit field.
+ *      However, FW_ULPTX_WR commands have a 256 byte immediate only
+ *      payload limit.
  */
 static inline int is_ofld_imm(const struct sk_buff *skb)
 {
 	struct work_request_hdr *req = (struct work_request_hdr *)skb->data;
 	unsigned long opcode = FW_WR_OP_G(ntohl(req->wr_hi));
 
-	if (opcode == FW_CRYPTO_LOOKASIDE_WR)
+	if (unlikely(opcode == FW_ULPTX_WR))
+		return skb->len <= MAX_IMM_ULPTX_WR_LEN;
+	else if (opcode == FW_CRYPTO_LOOKASIDE_WR)
 		return skb->len <= SGE_MAX_WR_LEN;
 	else
-		return skb->len <= MAX_IMM_TX_PKT_LEN;
+		return skb->len <= MAX_IMM_OFLD_TX_DATA_WR_LEN;
 }
 
 /**
@@ -2453,6 +2446,7 @@
 	txq_info = adap->sge.uld_txq_info[tx_uld_type];
 	if (unlikely(!txq_info)) {
 		WARN_ON(true);
+		kfree_skb(skb);
 		return NET_XMIT_DROP;
 	}
 
@@ -2828,7 +2822,7 @@
 
 	hwtstamps = skb_hwtstamps(skb);
 	memset(hwtstamps, 0, sizeof(*hwtstamps));
-	hwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*((u64 *)data)));
+	hwtstamps->hwtstamp = ns_to_ktime(get_unaligned_be64(data));
 
 	return RX_PTP_PKT_SUC;
 }
@@ -2924,26 +2918,6 @@
 	}
 
 	txq = &s->ethtxq[pi->first_qset + rspq->idx];
-
-	/* We've got the Hardware Consumer Index Update in the Egress Update
-	 * message.  If we're using the SGE Doorbell Queue Timer mechanism,
-	 * these Egress Update messages will be our sole CIDX Updates we get
-	 * since we don't want to chew up PCIe bandwidth for both Ingress
-	 * Messages and Status Page writes.  However, The code which manages
-	 * reclaiming successfully DMA'ed TX Work Requests uses the CIDX value
-	 * stored in the Status Page at the end of the TX Queue.  It's easiest
-	 * to simply copy the CIDX Update value from the Egress Update message
-	 * to the Status Page.  Also note that no Endian issues need to be
-	 * considered here since both are Big Endian and we're just copying
-	 * bytes consistently ...
-	 */
-	if (txq->dbqt) {
-		struct cpl_sge_egr_update *egr;
-
-		egr = (struct cpl_sge_egr_update *)rsp;
-		WRITE_ONCE(txq->q.stat->cidx, egr->cidx);
-	}
-
 	t4_sge_eth_txq_egress_update(adapter, txq, -1);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -2093,7 +2093,8 @@
 		0x1190, 0x1194,
 		0x11a0, 0x11a4,
 		0x11b0, 0x11b4,
-		0x11fc, 0x1274,
+		0x11fc, 0x123c,
+		0x1254, 0x1274,
 		0x1280, 0x133c,
 		0x1800, 0x18fc,
 		0x3000, 0x302c,
@@ -3499,7 +3500,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) {
@@ -3528,8 +3529,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);
@@ -3560,7 +3561,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;
 	}
 
@@ -3748,7 +3749,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;
@@ -3849,6 +3850,8 @@
 		 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
 	ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
 				    &param, &val, 30000);
+	if (ret)
+		return ret;
 
 	/* If we have version number support, then check to see that the new
 	 * firmware got loaded properly.
@@ -4089,7 +4092,8 @@
 		if (cc_pause & PAUSE_TX)
 			fw_pause |= FW_PORT_CAP32_802_3_PAUSE;
 		else
-			fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
+			fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR |
+				    FW_PORT_CAP32_802_3_PAUSE;
 	} else if (cc_pause & PAUSE_TX) {
 		fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
 	}
@@ -8563,17 +8567,17 @@
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
 {
 	const struct fw_port_cmd *cmd = (const void *)rpl;
-	int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
-	struct adapter *adapter = pi->adapter;
+	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
 	struct link_config *lc = &pi->link_cfg;
-	int link_ok, linkdnrc;
-	enum fw_port_type port_type;
+	struct adapter *adapter = pi->adapter;
+	unsigned int speed, fc, fec, adv_fc;
 	enum fw_port_module_type mod_type;
-	unsigned int speed, fc, fec;
-	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
+	int action, link_ok, linkdnrc;
+	enum fw_port_type port_type;
 
 	/* Extract the various fields from the Port Information message.
 	 */
+	action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
 	switch (action) {
 	case FW_PORT_ACTION_GET_PORT_INFO: {
 		u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
@@ -8611,6 +8615,7 @@
 	}
 
 	fec = fwcap_to_cc_fec(acaps);
+	adv_fc = fwcap_to_cc_pause(acaps);
 	fc = fwcap_to_cc_pause(linkattr);
 	speed = fwcap_to_speed(linkattr);
 
@@ -8667,7 +8672,9 @@
 	}
 
 	if (link_ok != lc->link_ok || speed != lc->speed ||
-	    fc != lc->fc || fec != lc->fec) {	/* something changed */
+	    fc != lc->fc || adv_fc != lc->advertised_fc ||
+	    fec != lc->fec) {
+		/* something changed */
 		if (!link_ok && lc->link_ok) {
 			lc->link_down_rc = linkdnrc;
 			dev_warn_ratelimited(adapter->pdev_dev,
@@ -8677,6 +8684,7 @@
 		}
 		lc->link_ok = link_ok;
 		lc->speed = speed;
+		lc->advertised_fc = adv_fc;
 		lc->fc = fc;
 		lc->fec = fec;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -293,6 +293,8 @@
 #define I2C_PAGE_SIZE		0x100
 #define SFP_DIAG_TYPE_ADDR	0x5c
 #define SFP_DIAG_TYPE_LEN	0x1
+#define SFP_DIAG_ADDRMODE	BIT(2)
+#define SFP_DIAG_IMPLEMENTED	BIT(6)
 #define SFF_8472_COMP_ADDR	0x5e
 #define SFF_8472_COMP_LEN	0x1
 #define SFF_REV_ADDR		0x1
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
@@ -219,6 +219,7 @@
 	CH_PCI_ID_TABLE_FENTRY(0x6089), /* Custom T62100-KR */
 	CH_PCI_ID_TABLE_FENTRY(0x608a), /* Custom T62100-CR */
 	CH_PCI_ID_TABLE_FENTRY(0x608b), /* Custom T6225-CR */
+	CH_PCI_ID_TABLE_FENTRY(0x6092), /* Custom T62100-CR-LOM */
 CH_PCI_DEVICE_ID_TABLE_DEFINE_END;
 
 #endif /* __T4_PCI_ID_TBL_H__ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -1900,6 +1900,9 @@
 
 #define MAC_PORT_CFG2_A 0x818
 
+#define MAC_PORT_PTP_SUM_LO_A 0x990
+#define MAC_PORT_PTP_SUM_HI_A 0x994
+
 #define MPS_CMN_CTL_A	0x9000
 
 #define COUNTPAUSEMCRX_S    5
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
@@ -50,6 +50,10 @@
 #define TCB_RQ_START_M		0x3ffffffULL
 #define TCB_RQ_START_V(x)	((x) << TCB_RQ_START_S)
 
+#define TF_DROP_S		22
+#define TF_DIRECT_STEER_S	23
+#define TF_LPBK_S		59
+
 #define TF_CCTRL_ECE_S		60
 #define TF_CCTRL_CWR_S		61
 #define TF_CCTRL_RFR_S		62
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -860,7 +860,7 @@
 	 */
 	err = t4vf_update_port_info(pi);
 	if (err < 0)
-		return err;
+		goto err_unwind;
 
 	/*
 	 * Note that this interface is up and start everything up ...
@@ -1690,8 +1690,8 @@
 	struct port_info *pi = netdev_priv(dev);
 
 	pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
-	pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0;
-	pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0;
+	pauseparam->rx_pause = (pi->link_cfg.advertised_fc & PAUSE_RX) != 0;
+	pauseparam->tx_pause = (pi->link_cfg.advertised_fc & PAUSE_TX) != 0;
 }
 
 /*
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
@@ -135,6 +135,7 @@
 
 	enum cc_pause	requested_fc;	/* flow control user has requested */
 	enum cc_pause	fc;		/* actual link flow control */
+	enum cc_pause   advertised_fc;  /* actual advertised flow control */
 
 	enum cc_fec	auto_fec;	/* Forward Error Correction: */
 	enum cc_fec	requested_fec;	/*   "automatic" (IEEE 802.3), */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
@@ -1913,16 +1913,16 @@
 static void t4vf_handle_get_port_info(struct port_info *pi,
 				      const struct fw_port_cmd *cmd)
 {
-	int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
-	struct adapter *adapter = pi->adapter;
+	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
 	struct link_config *lc = &pi->link_cfg;
-	int link_ok, linkdnrc;
-	enum fw_port_type port_type;
+	struct adapter *adapter = pi->adapter;
+	unsigned int speed, fc, fec, adv_fc;
 	enum fw_port_module_type mod_type;
-	unsigned int speed, fc, fec;
-	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
+	int action, link_ok, linkdnrc;
+	enum fw_port_type port_type;
 
 	/* Extract the various fields from the Port Information message. */
+	action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
 	switch (action) {
 	case FW_PORT_ACTION_GET_PORT_INFO: {
 		u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
@@ -1982,6 +1982,7 @@
 	}
 
 	fec = fwcap_to_cc_fec(acaps);
+	adv_fc = fwcap_to_cc_pause(acaps);
 	fc = fwcap_to_cc_pause(linkattr);
 	speed = fwcap_to_speed(linkattr);
 
@@ -2012,7 +2013,9 @@
 	}
 
 	if (link_ok != lc->link_ok || speed != lc->speed ||
-	    fc != lc->fc || fec != lc->fec) {	/* something changed */
+	    fc != lc->fc || adv_fc != lc->advertised_fc ||
+	    fec != lc->fec) {
+		/* something changed */
 		if (!link_ok && lc->link_ok) {
 			lc->link_down_rc = linkdnrc;
 			dev_warn_ratelimited(adapter->pdev_dev,
@@ -2022,6 +2025,7 @@
 		}
 		lc->link_ok = link_ok;
 		lc->speed = speed;
+		lc->advertised_fc = adv_fc;
 		lc->fc = fc;
 		lc->fec = fec;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c
+++ linux-ein-5.4.0/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c
@@ -32,6 +32,7 @@
 
 #include <linux/tcp.h>
 #include <linux/ipv6.h>
+#include <net/inet_ecn.h>
 #include <net/route.h>
 #include <net/ip6_route.h>
 
@@ -99,7 +100,7 @@
 
 	rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
 				   peer_port, local_port, IPPROTO_TCP,
-				   tos, 0);
+				   tos & ~INET_ECN_MASK, 0);
 	if (IS_ERR(rt))
 		return NULL;
 	n = dst_neigh_lookup(&rt->dst, &peer_ip);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cisco/enic/enic.h
+++ linux-ein-5.4.0/drivers/net/ethernet/cisco/enic/enic.h
@@ -171,6 +171,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-ein-5.4.0.orig/drivers/net/ethernet/cisco/enic/enic_api.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -454,7 +454,6 @@
 		break;
 	default:
 		return -EINVAL;
-		break;
 	}
 
 	fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cisco/enic/enic_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -803,7 +803,7 @@
 	return err;
 }
 
-static inline void enic_queue_wq_skb(struct enic *enic,
+static inline int enic_queue_wq_skb(struct enic *enic,
 	struct vnic_wq *wq, struct sk_buff *skb)
 {
 	unsigned int mss = skb_shinfo(skb)->gso_size;
@@ -849,6 +849,7 @@
 		wq->to_use = buf->next;
 		dev_kfree_skb(skb);
 	}
+	return err;
 }
 
 /* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -892,7 +893,8 @@
 		return NETDEV_TX_BUSY;
 	}
 
-	enic_queue_wq_skb(enic, wq, skb);
+	if (enic_queue_wq_skb(enic, wq, skb))
+		goto error;
 
 	if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)
 		netif_tx_stop_queue(txq);
@@ -900,6 +902,7 @@
 	if (!netdev_xmit_more() || netif_xmit_stopped(txq))
 		vnic_wq_doorbell(wq);
 
+error:
 	spin_unlock(&enic->wq_lock[txq_map]);
 
 	return NETDEV_TX_OK;
@@ -2013,10 +2016,10 @@
 		napi_disable(&enic->napi[i]);
 
 	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);
@@ -2142,8 +2145,6 @@
 	int done;
 	int err;
 
-	BUG_ON(in_interrupt());
-
 	err = start(vdev, arg);
 	if (err)
 		return err;
@@ -2331,6 +2332,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);
@@ -2340,7 +2348,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);
@@ -2348,7 +2358,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();
@@ -2360,7 +2373,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);
@@ -2369,7 +2384,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();
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cortina/gemini.c
+++ linux-ein-5.4.0/drivers/net/ethernet/cortina/gemini.c
@@ -304,21 +304,21 @@
 	switch (phydev->speed) {
 	case 1000:
 		status.bits.speed = GMAC_SPEED_1000;
-		if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
+		if (phy_interface_mode_is_rgmii(phydev->interface))
 			status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
 		netdev_dbg(netdev, "connect %s to RGMII @ 1Gbit\n",
 			   phydev_name(phydev));
 		break;
 	case 100:
 		status.bits.speed = GMAC_SPEED_100;
-		if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
+		if (phy_interface_mode_is_rgmii(phydev->interface))
 			status.bits.mii_rmii = GMAC_PHY_RGMII_100_10;
 		netdev_dbg(netdev, "connect %s to RGMII @ 100 Mbit\n",
 			   phydev_name(phydev));
 		break;
 	case 10:
 		status.bits.speed = GMAC_SPEED_10;
-		if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
+		if (phy_interface_mode_is_rgmii(phydev->interface))
 			status.bits.mii_rmii = GMAC_PHY_RGMII_100_10;
 		netdev_dbg(netdev, "connect %s to RGMII @ 10 Mbit\n",
 			   phydev_name(phydev));
@@ -388,6 +388,9 @@
 		status.bits.mii_rmii = GMAC_PHY_GMII;
 		break;
 	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
 		netdev_dbg(netdev,
 			   "RGMII: set GMAC0 and GMAC1 to MII/RGMII mode\n");
 		status.bits.mii_rmii = GMAC_PHY_RGMII_100_10;
@@ -429,8 +432,8 @@
 		.val = CONFIG0_MAXLEN_1536,
 	},
 	{
-		.max_l3_len = 1542,
-		.val = CONFIG0_MAXLEN_1542,
+		.max_l3_len = 1548,
+		.val = CONFIG0_MAXLEN_1548,
 	},
 	{
 		.max_l3_len = 9212,
@@ -576,6 +579,8 @@
 
 	if (port->txq_dma_base & ~DMA_Q_BASE_MASK) {
 		dev_warn(geth->dev, "TX queue base is not aligned\n");
+		dma_free_coherent(geth->dev, len * sizeof(*desc_ring),
+				  desc_ring, port->txq_dma_base);
 		kfree(skb_tab);
 		return -ENOMEM;
 	}
@@ -1147,6 +1152,7 @@
 	dma_addr_t mapping;
 	unsigned short mtu;
 	void *buffer;
+	int ret;
 
 	mtu  = ETH_HLEN;
 	mtu += netdev->mtu;
@@ -1161,9 +1167,30 @@
 		word3 |= mtu;
 	}
 
-	if (skb->ip_summed != CHECKSUM_NONE) {
+	if (skb->len >= ETH_FRAME_LEN) {
+		/* Hardware offloaded checksumming isn't working on frames
+		 * bigger than 1514 bytes. A hypothesis about this is that the
+		 * checksum buffer is only 1518 bytes, so when the frames get
+		 * bigger they get truncated, or the last few bytes get
+		 * overwritten by the FCS.
+		 *
+		 * Just use software checksumming and bypass on bigger frames.
+		 */
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			ret = skb_checksum_help(skb);
+			if (ret)
+				return ret;
+		}
+		word1 |= TSS_BYPASS_BIT;
+	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		int tcp = 0;
 
+		/* We do not switch off the checksumming on non TCP/UDP
+		 * frames: as is shown from tests, the checksumming engine
+		 * is smart enough to see that a frame is not actually TCP
+		 * or UDP and then just pass it through without any changes
+		 * to the frame.
+		 */
 		if (skb->protocol == htons(ETH_P_IP)) {
 			word1 |= TSS_IP_CHKSUM_BIT;
 			tcp = ip_hdr(skb)->protocol == IPPROTO_TCP;
@@ -1988,15 +2015,6 @@
 	return 0;
 }
 
-static netdev_features_t gmac_fix_features(struct net_device *netdev,
-					   netdev_features_t features)
-{
-	if (netdev->mtu + ETH_HLEN + VLAN_HLEN > MTU_SIZE_BIT_MASK)
-		features &= ~GMAC_OFFLOAD_FEATURES;
-
-	return features;
-}
-
 static int gmac_set_features(struct net_device *netdev,
 			     netdev_features_t features)
 {
@@ -2217,7 +2235,6 @@
 	.ndo_set_mac_address	= gmac_set_mac_address,
 	.ndo_get_stats64	= gmac_get_stats64,
 	.ndo_change_mtu		= gmac_change_mtu,
-	.ndo_fix_features	= gmac_fix_features,
 	.ndo_set_features	= gmac_set_features,
 };
 
@@ -2386,7 +2403,7 @@
 
 	dev_info(dev, "probe %s ID %d\n", dev_name(dev), id);
 
-	netdev = alloc_etherdev_mq(sizeof(*port), TX_QUEUE_NUM);
+	netdev = devm_alloc_etherdev_mqs(dev, sizeof(*port), TX_QUEUE_NUM, TX_QUEUE_NUM);
 	if (!netdev) {
 		dev_err(dev, "Can't allocate ethernet device #%d\n", id);
 		return -ENOMEM;
@@ -2443,7 +2460,8 @@
 	port->reset = devm_reset_control_get_exclusive(dev, NULL);
 	if (IS_ERR(port->reset)) {
 		dev_err(dev, "no reset\n");
-		return PTR_ERR(port->reset);
+		ret = PTR_ERR(port->reset);
+		goto unprepare;
 	}
 	reset_control_reset(port->reset);
 	usleep_range(100, 500);
@@ -2470,11 +2488,12 @@
 
 	netdev->hw_features = GMAC_OFFLOAD_FEATURES;
 	netdev->features |= GMAC_OFFLOAD_FEATURES | NETIF_F_GRO;
-	/* We can handle jumbo frames up to 10236 bytes so, let's accept
-	 * payloads of 10236 bytes minus VLAN and ethernet header
+	/* We can receive jumbo frames up to 10236 bytes but only
+	 * transmit 2047 bytes so, let's accept payloads of 2047
+	 * bytes minus VLAN and ethernet header
 	 */
 	netdev->min_mtu = ETH_MIN_MTU;
-	netdev->max_mtu = 10236 - VLAN_ETH_HLEN;
+	netdev->max_mtu = MTU_SIZE_BIT_MASK - VLAN_ETH_HLEN;
 
 	port->freeq_refill = 0;
 	netif_napi_add(netdev, &port->napi, gmac_napi_poll,
@@ -2499,23 +2518,24 @@
 					port_names[port->id],
 					port);
 	if (ret)
-		return ret;
+		goto unprepare;
 
 	ret = register_netdev(netdev);
-	if (!ret) {
+	if (ret)
+		goto unprepare;
+
+	netdev_info(netdev,
+		    "irq %d, DMA @ 0x%pap, GMAC @ 0x%pap\n",
+		    port->irq, &dmares->start,
+		    &gmacres->start);
+	ret = gmac_setup_phy(netdev);
+	if (ret)
 		netdev_info(netdev,
-			    "irq %d, DMA @ 0x%pap, GMAC @ 0x%pap\n",
-			    port->irq, &dmares->start,
-			    &gmacres->start);
-		ret = gmac_setup_phy(netdev);
-		if (ret)
-			netdev_info(netdev,
-				    "PHY init failed, deferring to ifup time\n");
-		return 0;
-	}
+			    "PHY init failed, deferring to ifup time\n");
+	return 0;
 
-	port->netdev = NULL;
-	free_netdev(netdev);
+unprepare:
+	clk_disable_unprepare(port->pclk);
 	return ret;
 }
 
@@ -2524,7 +2544,6 @@
 	struct gemini_ethernet_port *port = platform_get_drvdata(pdev);
 
 	gemini_port_remove(port);
-	free_netdev(port->netdev);
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/cortina/gemini.h
+++ linux-ein-5.4.0/drivers/net/ethernet/cortina/gemini.h
@@ -502,7 +502,7 @@
 #define SOF_BIT			0x80000000
 #define EOF_BIT			0x40000000
 #define EOFIE_BIT		BIT(29)
-#define MTU_SIZE_BIT_MASK	0x1fff
+#define MTU_SIZE_BIT_MASK	0x7ff /* Max MTU 2047 bytes */
 
 /* GMAC Tx Descriptor */
 struct gmac_txdesc {
@@ -787,7 +787,7 @@
 #define  CONFIG0_MAXLEN_1536	0
 #define  CONFIG0_MAXLEN_1518	1
 #define  CONFIG0_MAXLEN_1522	2
-#define  CONFIG0_MAXLEN_1542	3
+#define  CONFIG0_MAXLEN_1548	3
 #define  CONFIG0_MAXLEN_9k	4	/* 9212 */
 #define  CONFIG0_MAXLEN_10k	5	/* 10236 */
 #define  CONFIG0_MAXLEN_1518__6	6
--- linux-ein-5.4.0.orig/drivers/net/ethernet/davicom/dm9000.c
+++ linux-ein-5.4.0/drivers/net/ethernet/davicom/dm9000.c
@@ -134,6 +134,8 @@
 	u32		wake_state;
 
 	int		ip_summed;
+
+	struct regulator *power_supply;
 };
 
 /* debug code */
@@ -1405,6 +1407,8 @@
 	mac_addr = of_get_mac_address(np);
 	if (!IS_ERR(mac_addr))
 		ether_addr_copy(pdata->dev_addr, mac_addr);
+	else if (PTR_ERR(mac_addr) == -EPROBE_DEFER)
+		return ERR_CAST(mac_addr);
 
 	return pdata;
 }
@@ -1452,7 +1456,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 */
@@ -1464,14 +1468,18 @@
 
 	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 */
 	ndev = alloc_etherdev(sizeof(struct board_info));
-	if (!ndev)
-		return -ENOMEM;
+	if (!ndev) {
+		ret = -ENOMEM;
+		goto out_regulator_disable;
+	}
 
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
@@ -1482,6 +1490,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);
@@ -1504,7 +1514,7 @@
 		goto out;
 	}
 
-	db->irq_wake = platform_get_irq(pdev, 1);
+	db->irq_wake = platform_get_irq_optional(pdev, 1);
 	if (db->irq_wake >= 0) {
 		dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
 
@@ -1706,6 +1716,10 @@
 	dm9000_release_board(pdev, db);
 	free_netdev(ndev);
 
+out_regulator_disable:
+	if (!IS_ERR(power))
+		regulator_disable(power);
+
 	return ret;
 }
 
@@ -1763,10 +1777,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);
 	free_netdev(ndev);		/* free device structure */
+	if (dm->power_supply)
+		regulator_disable(dm->power_supply);
 
 	dev_dbg(&pdev->dev, "released and freed device\n");
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/de2104x.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/de4x5.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -4708,6 +4708,10 @@
         lp->ibn = 3;
         lp->active = *p++;
 	if (MOTO_SROM_BUG) lp->active = 0;
+	/* if (MOTO_SROM_BUG) statement indicates lp->active could
+	 * be 8 (i.e. the size of array lp->phy) */
+	if (WARN_ON(lp->active >= ARRAY_SIZE(lp->phy)))
+		return -EINVAL;
 	lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1);
 	lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1);
 	lp->phy[lp->active].mc  = get_unaligned_le16(p); p += 2;
@@ -4927,11 +4931,11 @@
 	u_char breg[2];
     } a;
     int i, r2, r3, ret=0;*/
-    int r2, r3;
+    int r2;
 
     /* Read r2 and r3 */
     r2 = mii_rd(MII_ID0, phyaddr, ioaddr);
-    r3 = mii_rd(MII_ID1, phyaddr, ioaddr);
+    mii_rd(MII_ID1, phyaddr, ioaddr);
                                                 /* SEEQ and Cypress way * /
     / * Shuffle r2 and r3 * /
     a.reg=0;
@@ -4999,19 +5003,23 @@
 	}
 	if ((j == limit) && (i < DE4X5_MAX_MII)) {
 	    for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++);
-	    lp->phy[k].addr = i;
-	    lp->phy[k].id = id;
-	    lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */
-	    lp->phy[k].spd.mask = GENERIC_MASK;    /* 100Mb/s technologies   */
-	    lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
-	    lp->mii_cnt++;
-	    lp->active++;
-	    printk("%s: Using generic MII device control. If the board doesn't operate,\nplease mail the following dump to the author:\n", dev->name);
-	    j = de4x5_debug;
-	    de4x5_debug |= DEBUG_MII;
-	    de4x5_dbg_mii(dev, k);
-	    de4x5_debug = j;
-	    printk("\n");
+	    if (k < DE4X5_MAX_PHY) {
+		lp->phy[k].addr = i;
+		lp->phy[k].id = id;
+		lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */
+		lp->phy[k].spd.mask = GENERIC_MASK;    /* 100Mb/s technologies   */
+		lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
+		lp->mii_cnt++;
+		lp->active++;
+		printk("%s: Using generic MII device control. If the board doesn't operate,\nplease mail the following dump to the author:\n", dev->name);
+		j = de4x5_debug;
+		de4x5_debug |= DEBUG_MII;
+		de4x5_dbg_mii(dev, k);
+		de4x5_debug = j;
+		printk("\n");
+	    } else {
+		goto purgatory;
+	    }
 	}
     }
   purgatory:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/dmfe.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -2214,15 +2214,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-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/media.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/media.c
@@ -319,13 +319,8 @@
 			break;
 		}
 		case 5: case 6: {
-			u16 setup[5];
-
 			new_csr6 = 0; /* FIXME */
 
-			for (i = 0; i < 5; i++)
-				setup[i] = get_u16(&p[i*2 + 1]);
-
 			if (startup && mtable->has_reset) {
 				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
 				unsigned char *rst = rleaf->leafdata;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/tulip_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -1410,8 +1410,10 @@
 
 	/* alloc_etherdev ensures aligned and zeroed private structures */
 	dev = alloc_etherdev (sizeof (*tp));
-	if (!dev)
+	if (!dev) {
+		pci_disable_device(pdev);
 		return -ENOMEM;
+	}
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
@@ -1788,6 +1790,7 @@
 
 err_out_free_netdev:
 	free_netdev (dev);
+	pci_disable_device(pdev);
 	return -ENODEV;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/uli526x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -1809,8 +1809,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-ein-5.4.0.orig/drivers/net/ethernet/dec/tulip/winbond-840.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -367,7 +367,7 @@
 	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	void __iomem *ioaddr;
 
-	i = pci_enable_device(pdev);
+	i = pcim_enable_device(pdev);
 	if (i) return i;
 
 	pci_set_master(pdev);
@@ -389,7 +389,7 @@
 
 	ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size);
 	if (!ioaddr)
-		goto err_out_free_res;
+		goto err_out_netdev;
 
 	for (i = 0; i < 3; i++)
 		((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i));
@@ -468,8 +468,6 @@
 
 err_out_cleardev:
 	pci_iounmap(pdev, ioaddr);
-err_out_free_res:
-	pci_release_regions(pdev);
 err_out_netdev:
 	free_netdev (dev);
 	return -ENODEV;
@@ -1535,7 +1533,6 @@
 	if (dev) {
 		struct netdev_private *np = netdev_priv(dev);
 		unregister_netdev(dev);
-		pci_release_regions(pdev);
 		pci_iounmap(pdev, np->base_addr);
 		free_netdev(dev);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/dnet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/dnet.c
@@ -553,11 +553,11 @@
 
 	skb_tx_timestamp(skb);
 
+	spin_unlock_irqrestore(&bp->lock, flags);
+
 	/* free the buffer */
 	dev_kfree_skb(skb);
 
-	spin_unlock_irqrestore(&bp->lock, flags);
-
 	return NETDEV_TX_OK;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ec_bhf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ec_bhf.c
@@ -576,10 +576,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-ein-5.4.0.orig/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ linux-ein-5.4.0/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -550,7 +550,7 @@
 	int num = 0, status = 0;
 	struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 
-	spin_lock_bh(&adapter->mcc_cq_lock);
+	spin_lock(&adapter->mcc_cq_lock);
 
 	while ((compl = be_mcc_compl_get(adapter))) {
 		if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
@@ -566,7 +566,7 @@
 	if (num)
 		be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
 
-	spin_unlock_bh(&adapter->mcc_cq_lock);
+	spin_unlock(&adapter->mcc_cq_lock);
 	return status;
 }
 
@@ -581,7 +581,9 @@
 		if (be_check_error(adapter, BE_ERROR_ANY))
 			return -EIO;
 
+		local_bh_disable();
 		status = be_process_mcc(adapter);
+		local_bh_enable();
 
 		if (atomic_read(&mcc_obj->q.used) == 0)
 			break;
@@ -2285,7 +2287,7 @@
 
 /* Uses sync mcc */
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-				      u8 page_num, u8 *data)
+				      u8 page_num, u32 off, u32 len, u8 *data)
 {
 	struct be_dma_mem cmd;
 	struct be_mcc_wrb *wrb;
@@ -2319,10 +2321,10 @@
 	req->port = cpu_to_le32(adapter->hba_port_num);
 	req->page_num = cpu_to_le32(page_num);
 	status = be_mcc_notify_wait(adapter);
-	if (!status) {
+	if (!status && len > 0) {
 		struct be_cmd_resp_port_type *resp = cmd.va;
 
-		memcpy(data, resp->page_data, PAGE_DATA_LEN);
+		memcpy(data, resp->page_data + off, len);
 	}
 err:
 	mutex_unlock(&adapter->mcc_lock);
@@ -2413,7 +2415,7 @@
 	int status;
 
 	status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-						   page_data);
+						   0, PAGE_DATA_LEN, page_data);
 	if (!status) {
 		switch (adapter->phy.interface_type) {
 		case PHY_TYPE_QSFP:
@@ -2438,7 +2440,7 @@
 	int status;
 
 	status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-						   page_data);
+						   0, PAGE_DATA_LEN, page_data);
 	if (!status) {
 		strlcpy(adapter->phy.vendor_name, page_data +
 			SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ linux-ein-5.4.0/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -2427,7 +2427,7 @@
 int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
 			    u32 *state);
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-				      u8 page_num, u8 *data);
+				      u8 page_num, u32 off, u32 len, u8 *data);
 int be_cmd_query_cable_type(struct be_adapter *adapter);
 int be_cmd_query_sfp_info(struct be_adapter *adapter);
 int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1339,7 +1339,7 @@
 		return -EOPNOTSUPP;
 
 	status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-						   page_data);
+						   0, PAGE_DATA_LEN, page_data);
 	if (!status) {
 		if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
 			modinfo->type = ETH_MODULE_SFF_8079;
@@ -1357,25 +1357,32 @@
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
 	int status;
+	u32 begin, end;
 
 	if (!check_privilege(adapter, MAX_PRIVILEGES))
 		return -EOPNOTSUPP;
 
-	status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-						   data);
-	if (status)
-		goto err;
-
-	if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
-		status = be_cmd_read_port_transceiver_data(adapter,
-							   TR_PAGE_A2,
-							   data +
-							   PAGE_DATA_LEN);
+	begin = eeprom->offset;
+	end = eeprom->offset + eeprom->len;
+
+	if (begin < PAGE_DATA_LEN) {
+		status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin,
+							   min_t(u32, end, PAGE_DATA_LEN) - begin,
+							   data);
+		if (status)
+			goto err;
+
+		data += PAGE_DATA_LEN - begin;
+		begin = PAGE_DATA_LEN;
+	}
+
+	if (end > PAGE_DATA_LEN) {
+		status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
+							   begin - PAGE_DATA_LEN,
+							   end - begin, data);
 		if (status)
 			goto err;
 	}
-	if (eeprom->offset)
-		memcpy(data, data + eeprom->offset, eeprom->len);
 err:
 	return be_cmd_status(status);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/emulex/benet/be_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1137,10 +1137,11 @@
 	eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
 						VLAN_ETH_HLEN : ETH_HLEN;
 	if (skb->len <= 60 &&
-	    (lancer_chip(adapter) || skb_vlan_tag_present(skb)) &&
-	    is_ipv4_pkt(skb)) {
+	    (lancer_chip(adapter) || BE3_chip(adapter) ||
+	     skb_vlan_tag_present(skb)) && is_ipv4_pkt(skb)) {
 		ip = (struct iphdr *)ip_hdr(skb);
-		pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
+		if (unlikely(pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len))))
+			goto tx_drop;
 	}
 
 	/* If vlan tag is already inlined in the packet, skip HW VLAN
@@ -5631,7 +5632,9 @@
 	 * mcc completions
 	 */
 	if (!netif_running(adapter->netdev)) {
+		local_bh_disable();
 		be_process_mcc(adapter);
+		local_bh_enable();
 		goto reschedule;
 	}
 
@@ -6030,6 +6033,7 @@
 unmap_bars:
 	be_unmap_pci_bars(adapter);
 free_netdev:
+	pci_disable_pcie_error_reporting(pdev);
 	free_netdev(netdev);
 rel_reg:
 	pci_release_regions(pdev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ethoc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ethoc.c
@@ -1207,7 +1207,7 @@
 	ret = mdiobus_register(priv->mdio);
 	if (ret) {
 		dev_err(&netdev->dev, "failed to register MDIO bus\n");
-		goto free2;
+		goto free3;
 	}
 
 	ret = ethoc_mdio_probe(netdev);
@@ -1239,6 +1239,7 @@
 	netif_napi_del(&priv->napi);
 error:
 	mdiobus_unregister(priv->mdio);
+free3:
 	mdiobus_free(priv->mdio);
 free2:
 	clk_disable_unprepare(priv->clk);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ezchip/nps_enet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ezchip/nps_enet.c
@@ -610,7 +610,7 @@
 
 	/* Get IRQ number */
 	priv->irq = platform_get_irq(pdev, 0);
-	if (!priv->irq) {
+	if (priv->irq < 0) {
 		dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n");
 		err = -ENODEV;
 		goto out_netdev;
@@ -645,8 +645,8 @@
 	struct nps_enet_priv *priv = netdev_priv(ndev);
 
 	unregister_netdev(ndev);
-	free_netdev(ndev);
 	netif_napi_del(&priv->napi);
+	free_netdev(ndev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/faraday/ftgmac100.c
+++ linux-ein-5.4.0/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1307,6 +1307,7 @@
 	 */
 	if (unlikely(priv->need_mac_restart)) {
 		ftgmac100_start_hw(priv);
+		priv->need_mac_restart = false;
 
 		/* Re-enable "bad" interrupts */
 		iowrite32(FTGMAC100_INT_BAD,
@@ -1733,6 +1734,19 @@
 			FTGMAC_100MHZ);
 }
 
+static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
+{
+	struct device_node *child_np = of_get_child_by_name(np, name);
+	bool ret = false;
+
+	if (child_np) {
+		ret = true;
+		of_node_put(child_np);
+	}
+
+	return ret;
+}
+
 static int ftgmac100_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1807,6 +1821,11 @@
 		priv->rxdes0_edorr_mask = BIT(30);
 		priv->txdes0_edotr_mask = BIT(30);
 		priv->is_aspeed = true;
+		/* Disable ast2600 problematic HW arbitration */
+		if (of_device_is_compatible(np, "aspeed,ast2600-mac")) {
+			iowrite32(FTGMAC100_TM_DEFAULT,
+				  priv->base + FTGMAC100_OFFSET_TM);
+		}
 	} else {
 		priv->rxdes0_edorr_mask = BIT(15);
 		priv->txdes0_edotr_mask = BIT(15);
@@ -1815,14 +1834,17 @@
 	if (np && of_get_property(np, "use-ncsi", NULL)) {
 		if (!IS_ENABLED(CONFIG_NET_NCSI)) {
 			dev_err(&pdev->dev, "NCSI stack not enabled\n");
+			err = -EINVAL;
 			goto err_ncsi_dev;
 		}
 
 		dev_info(&pdev->dev, "Using NCSI interface\n");
 		priv->use_ncsi = true;
 		priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
-		if (!priv->ndev)
+		if (!priv->ndev) {
+			err = -EINVAL;
 			goto err_ncsi_dev;
+		}
 	} else if (np && of_get_property(np, "phy-handle", NULL)) {
 		struct phy_device *phy;
 
@@ -1830,6 +1852,7 @@
 					     &ftgmac100_adjust_link);
 		if (!phy) {
 			dev_err(&pdev->dev, "Failed to connect to phy\n");
+			err = -EINVAL;
 			goto err_setup_mdio;
 		}
 
@@ -1840,7 +1863,7 @@
 
 		/* Display what we found */
 		phy_attached_info(phy);
-	} else if (np && !of_get_child_by_name(np, "mdio")) {
+	} else if (np && !ftgmac100_has_child_node(np, "mdio")) {
 		/* Support legacy ASPEED devicetree descriptions that decribe a
 		 * MAC with an embedded MDIO controller but have no "mdio"
 		 * child node. Automatically scan the MDIO bus for available
@@ -1870,6 +1893,11 @@
 	/* AST2400  doesn't have working HW checksum generation */
 	if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
 		netdev->hw_features &= ~NETIF_F_HW_CSUM;
+
+	/* AST2600 tx checksum with NCSI is broken */
+	if (priv->use_ncsi && of_device_is_compatible(np, "aspeed,ast2600-mac"))
+		netdev->hw_features &= ~NETIF_F_HW_CSUM;
+
 	if (np && of_get_property(np, "no-hw-checksum", NULL))
 		netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM);
 	netdev->features |= netdev->hw_features;
@@ -1886,6 +1914,8 @@
 	return 0;
 
 err_ncsi_dev:
+	if (priv->ndev)
+		ncsi_unregister_dev(priv->ndev);
 err_register_netdev:
 	ftgmac100_destroy_mdio(netdev);
 err_setup_mdio:
@@ -1906,6 +1936,8 @@
 	netdev = platform_get_drvdata(pdev);
 	priv = netdev_priv(netdev);
 
+	if (priv->ndev)
+		ncsi_unregister_dev(priv->ndev);
 	unregister_netdev(netdev);
 
 	clk_disable_unprepare(priv->clk);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/faraday/ftgmac100.h
+++ linux-ein-5.4.0/drivers/net/ethernet/faraday/ftgmac100.h
@@ -170,6 +170,14 @@
 #define FTGMAC100_MACCR_SW_RST		(1 << 31)
 
 /*
+ * test mode control register
+ */
+#define FTGMAC100_TM_RQ_TX_VALID_DIS (1 << 28)
+#define FTGMAC100_TM_RQ_RR_IDLE_PREV (1 << 27)
+#define FTGMAC100_TM_DEFAULT                                                   \
+	(FTGMAC100_TM_RQ_TX_VALID_DIS | FTGMAC100_TM_RQ_RR_IDLE_PREV)
+
+/*
  * PHY control register
  */
 #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0x3f
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/Kconfig
@@ -77,6 +77,7 @@
 	depends on QUICC_ENGINE
 	select FSL_PQ_MDIO
 	select PHYLIB
+	select FIXED_PHY
 	---help---
 	  This driver supports the Gigabit Ethernet mode of the QUICC Engine,
 	  which is available on some Freescale SOCs.
@@ -90,6 +91,7 @@
 	depends on HAS_DMA
 	select FSL_PQ_MDIO
 	select PHYLIB
+	select FIXED_PHY
 	select CRC32
 	---help---
 	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa/Kconfig
@@ -3,6 +3,7 @@
 	tristate "DPAA Ethernet"
 	depends on FSL_DPAA && FSL_FMAN
 	select PHYLIB
+	select FIXED_PHY
 	select FSL_FMAN_MAC
 	---help---
 	  Data Path Acceleration Architecture Ethernet driver,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1600,13 +1600,15 @@
  * Skb freeing is not handled here.
  *
  * This function may be called on error paths in the Tx function, so guard
- * against cases when not all fd relevant fields were filled in.
+ * against cases when not all fd relevant fields were filled in. To avoid
+ * reading the invalid transmission timestamp for the error paths set ts to
+ * false.
  *
  * Return the skb backpointer, since for S/G frames the buffer containing it
  * gets freed here.
  */
 static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
-					  const struct qm_fd *fd)
+					  const struct qm_fd *fd, bool ts)
 {
 	const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
 	struct device *dev = priv->net_dev->dev.parent;
@@ -1620,18 +1622,6 @@
 	skbh = (struct sk_buff **)phys_to_virt(addr);
 	skb = *skbh;
 
-	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
-		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-
-		if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh,
-					  &ns)) {
-			shhwtstamps.hwtstamp = ns_to_ktime(ns);
-			skb_tstamp_tx(skb, &shhwtstamps);
-		} else {
-			dev_warn(dev, "fman_port_get_tstamp failed!\n");
-		}
-	}
-
 	if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
 		nr_frags = skb_shinfo(skb)->nr_frags;
 		dma_unmap_single(dev, addr,
@@ -1654,14 +1644,29 @@
 			dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
 				       qm_sg_entry_get_len(&sgt[i]), dma_dir);
 		}
-
-		/* Free the page frag that we allocated on Tx */
-		skb_free_frag(phys_to_virt(addr));
 	} else {
 		dma_unmap_single(dev, addr,
 				 skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
 	}
 
+	/* DMA unmapping is required before accessing the HW provided info */
+	if (ts && priv->tx_tstamp &&
+	    skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+
+		if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh,
+					  &ns)) {
+			shhwtstamps.hwtstamp = ns_to_ktime(ns);
+			skb_tstamp_tx(skb, &shhwtstamps);
+		} else {
+			dev_warn(dev, "fman_port_get_tstamp failed!\n");
+		}
+	}
+
+	if (qm_fd_get_format(fd) == qm_fd_sg)
+		/* Free the page frag that we allocated on Tx */
+		skb_free_frag(phys_to_virt(addr));
+
 	return skb;
 }
 
@@ -2114,7 +2119,7 @@
 	if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
 		return NETDEV_TX_OK;
 
-	dpaa_cleanup_tx_fd(priv, &fd);
+	dpaa_cleanup_tx_fd(priv, &fd, false);
 skb_to_fd_failed:
 enomem:
 	percpu_stats->tx_errors++;
@@ -2160,7 +2165,7 @@
 
 	percpu_priv->stats.tx_errors++;
 
-	skb = dpaa_cleanup_tx_fd(priv, fd);
+	skb = dpaa_cleanup_tx_fd(priv, fd, false);
 	dev_kfree_skb(skb);
 }
 
@@ -2200,7 +2205,7 @@
 
 	percpu_priv->tx_confirm++;
 
-	skb = dpaa_cleanup_tx_fd(priv, fd);
+	skb = dpaa_cleanup_tx_fd(priv, fd, true);
 
 	consume_skb(skb);
 }
@@ -2430,7 +2435,7 @@
 	percpu_priv->stats.tx_fifo_errors++;
 	count_ern(percpu_priv, msg);
 
-	skb = dpaa_cleanup_tx_fd(priv, fd);
+	skb = dpaa_cleanup_tx_fd(priv, fd, false);
 	dev_kfree_skb_any(skb);
 }
 
@@ -2478,6 +2483,9 @@
 	mac_dev->adjust_link(mac_dev);
 }
 
+/* The Aquantia PHYs are capable of performing rate adaptation */
+#define PHY_VEND_AQUANTIA	0x03a1b400
+
 static int dpaa_phy_init(struct net_device *net_dev)
 {
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
@@ -2496,9 +2504,14 @@
 		return -ENODEV;
 	}
 
-	/* Remove any features not supported by the controller */
-	ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
-	linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+	/* Unless the PHY is capable of rate adaptation */
+	if (mac_dev->phy_if != PHY_INTERFACE_MODE_XGMII ||
+	    ((phy_dev->drv->phy_id & GENMASK(31, 10)) != PHY_VEND_AQUANTIA)) {
+		/* remove any features not supported by the controller */
+		ethtool_convert_legacy_u32_to_link_mode(mask,
+							mac_dev->if_support);
+		linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+	}
 
 	phy_support_asym_pause(phy_dev);
 
@@ -2757,9 +2770,7 @@
 	headroom = (u16)(bl->priv_data_size + DPAA_PARSE_RESULTS_SIZE +
 		DPAA_TIME_STAMP_SIZE + DPAA_HASH_RESULTS_SIZE);
 
-	return DPAA_FD_DATA_ALIGNMENT ? ALIGN(headroom,
-					      DPAA_FD_DATA_ALIGNMENT) :
-					headroom;
+	return ALIGN(headroom, DPAA_FD_DATA_ALIGNMENT);
 }
 
 static int dpaa_eth_probe(struct platform_device *pdev)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -506,11 +506,15 @@
 	info->phc_index = -1;
 
 	fman_node = of_get_parent(mac_node);
-	if (fman_node)
+	if (fman_node) {
 		ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
+		of_node_put(fman_node);
+	}
 
-	if (ptp_node)
+	if (ptp_node) {
 		ptp_dev = of_find_device_by_node(ptp_node);
+		of_node_put(ptp_node);
+	}
 
 	if (ptp_dev)
 		ptp = platform_get_drvdata(ptp_dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -86,7 +86,7 @@
 	for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
 		addr = dpaa2_sg_get_addr(&sgt[i]);
 		sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-		dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+		dma_unmap_page(dev, addr, priv->rx_buf_size,
 			       DMA_BIDIRECTIONAL);
 
 		free_pages((unsigned long)sg_vaddr, 0);
@@ -144,7 +144,7 @@
 		/* Get the address and length from the S/G entry */
 		sg_addr = dpaa2_sg_get_addr(sge);
 		sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr);
-		dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE,
+		dma_unmap_page(dev, sg_addr, priv->rx_buf_size,
 			       DMA_BIDIRECTIONAL);
 
 		sg_length = dpaa2_sg_get_len(sge);
@@ -185,7 +185,7 @@
 				(page_address(page) - page_address(head_page));
 
 			skb_add_rx_frag(skb, i - 1, head_page, page_offset,
-					sg_length, DPAA2_ETH_RX_BUF_SIZE);
+					sg_length, priv->rx_buf_size);
 		}
 
 		if (dpaa2_sg_is_final(sge))
@@ -211,7 +211,7 @@
 
 	for (i = 0; i < count; i++) {
 		vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]);
-		dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE,
+		dma_unmap_page(dev, buf_array[i], priv->rx_buf_size,
 			       DMA_BIDIRECTIONAL);
 		free_pages((unsigned long)vaddr, 0);
 	}
@@ -331,7 +331,7 @@
 		break;
 	case XDP_REDIRECT:
 		dma_unmap_page(priv->net_dev->dev.parent, addr,
-			       DPAA2_ETH_RX_BUF_SIZE, DMA_BIDIRECTIONAL);
+			       priv->rx_buf_size, DMA_BIDIRECTIONAL);
 		ch->buf_count--;
 		xdp.data_hard_start = vaddr;
 		err = xdp_do_redirect(priv->net_dev, &xdp, xdp_prog);
@@ -370,7 +370,7 @@
 	trace_dpaa2_rx_fd(priv->net_dev, fd);
 
 	vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-	dma_sync_single_for_cpu(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+	dma_sync_single_for_cpu(dev, addr, priv->rx_buf_size,
 				DMA_BIDIRECTIONAL);
 
 	fas = dpaa2_get_fas(vaddr, false);
@@ -389,13 +389,13 @@
 			return;
 		}
 
-		dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+		dma_unmap_page(dev, addr, priv->rx_buf_size,
 			       DMA_BIDIRECTIONAL);
 		skb = build_linear_skb(ch, fd, vaddr);
 	} else if (fd_format == dpaa2_fd_sg) {
 		WARN_ON(priv->xdp_prog);
 
-		dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+		dma_unmap_page(dev, addr, priv->rx_buf_size,
 			       DMA_BIDIRECTIONAL);
 		skb = build_frag_skb(priv, ch, buf_data);
 		free_pages((unsigned long)vaddr, 0);
@@ -963,7 +963,7 @@
 		if (!page)
 			goto err_alloc;
 
-		addr = dma_map_page(dev, page, 0, DPAA2_ETH_RX_BUF_SIZE,
+		addr = dma_map_page(dev, page, 0, priv->rx_buf_size,
 				    DMA_BIDIRECTIONAL);
 		if (unlikely(dma_mapping_error(dev, addr)))
 			goto err_map;
@@ -971,9 +971,9 @@
 		buf_array[i] = addr;
 
 		/* tracing point */
-		trace_dpaa2_eth_buf_seed(priv->net_dev,
-					 page, DPAA2_ETH_RX_BUF_RAW_SIZE,
-					 addr, DPAA2_ETH_RX_BUF_SIZE,
+		trace_dpaa2_eth_buf_seed(priv->net_dev, page_address(page),
+					 DPAA2_ETH_RX_BUF_RAW_SIZE,
+					 addr, priv->rx_buf_size,
 					 bpid);
 	}
 
@@ -1680,7 +1680,7 @@
 	int mfl, linear_mfl;
 
 	mfl = DPAA2_ETH_L2_MAX_FRM(mtu);
-	linear_mfl = DPAA2_ETH_RX_BUF_SIZE - DPAA2_ETH_RX_HWA_SIZE -
+	linear_mfl = priv->rx_buf_size - DPAA2_ETH_RX_HWA_SIZE -
 		     dpaa2_eth_rx_head_room(priv) - XDP_PACKET_HEADROOM;
 
 	if (mfl > linear_mfl) {
@@ -1981,7 +1981,7 @@
 	int i;
 
 	if (type != TC_SETUP_QDISC_MQPRIO)
-		return -EINVAL;
+		return -EOPNOTSUPP;
 
 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
 	num_queues = dpaa2_eth_queue_count(priv);
@@ -1993,7 +1993,7 @@
 	if (num_tc  > dpaa2_eth_tc_count(priv)) {
 		netdev_err(net_dev, "Max %d traffic classes supported\n",
 			   dpaa2_eth_tc_count(priv));
-		return -EINVAL;
+		return -EOPNOTSUPP;
 	}
 
 	if (!num_tc) {
@@ -2090,7 +2090,7 @@
 free:
 	fsl_mc_object_free(dpcon);
 
-	return NULL;
+	return ERR_PTR(err);
 }
 
 static void free_dpcon(struct dpaa2_eth_priv *priv,
@@ -2114,8 +2114,8 @@
 		return NULL;
 
 	channel->dpcon = setup_dpcon(priv);
-	if (IS_ERR_OR_NULL(channel->dpcon)) {
-		err = PTR_ERR_OR_ZERO(channel->dpcon);
+	if (IS_ERR(channel->dpcon)) {
+		err = PTR_ERR(channel->dpcon);
 		goto err_setup;
 	}
 
@@ -2432,6 +2432,11 @@
 	else
 		rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN;
 
+	/* We need to ensure that the buffer size seen by WRIOP is a multiple
+	 * of 64 or 256 bytes depending on the WRIOP version.
+	 */
+	priv->rx_buf_size = ALIGN_DOWN(DPAA2_ETH_RX_BUF_SIZE, rx_buf_align);
+
 	/* tx buffer */
 	buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE;
 	buf_layout.pass_timestamp = true;
@@ -2649,8 +2654,10 @@
 
 	priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) *
 				       dpaa2_eth_fs_count(priv), GFP_KERNEL);
-	if (!priv->cls_rules)
+	if (!priv->cls_rules) {
+		err = -ENOMEM;
 		goto close;
+	}
 
 	return 0;
 
@@ -3096,7 +3103,7 @@
 	pools_params.num_dpbp = 1;
 	pools_params.pools[0].dpbp_id = priv->dpbp_dev->obj_desc.id;
 	pools_params.pools[0].backup_pool = 0;
-	pools_params.pools[0].buffer_size = DPAA2_ETH_RX_BUF_SIZE;
+	pools_params.pools[0].buffer_size = priv->rx_buf_size;
 	err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params);
 	if (err) {
 		dev_err(dev, "dpni_set_pools() failed\n");
@@ -3609,10 +3616,10 @@
 
 	fsl_mc_portal_free(priv->mc_io);
 
-	free_netdev(net_dev);
-
 	dev_dbg(net_dev->dev.parent, "Removed interface %s\n", net_dev->name);
 
+	free_netdev(net_dev);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -373,6 +373,7 @@
 	u16 tx_data_offset;
 
 	struct fsl_mc_device *dpbp_dev;
+	u16 rx_buf_size;
 	u16 bpid;
 	struct iommu_domain *iommu_domain;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
@@ -216,7 +216,7 @@
 		if (err == -EINVAL)
 			/* Older firmware versions don't support all pages */
 			memset(&dpni_stats, 0, sizeof(dpni_stats));
-		else
+		else if (err)
 			netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j);
 
 		num_cnt = dpni_stats_page_size[j] / sizeof(u64);
@@ -590,7 +590,7 @@
 
 static int update_cls_rule(struct net_device *net_dev,
 			   struct ethtool_rx_flow_spec *new_fs,
-			   int location)
+			   unsigned int location)
 {
 	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
 	struct dpaa2_eth_cls_rule *rule;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
@@ -148,7 +148,7 @@
 	base = of_iomap(node, 0);
 	if (!base) {
 		err = -ENOMEM;
-		goto err_close;
+		goto err_put;
 	}
 
 	err = fsl_mc_allocate_irqs(mc_dev);
@@ -160,10 +160,10 @@
 	irq = mc_dev->irqs[0];
 	ptp_qoriq->irq = irq->msi_desc->irq;
 
-	err = devm_request_threaded_irq(dev, ptp_qoriq->irq, NULL,
-					dpaa2_ptp_irq_handler_thread,
-					IRQF_NO_SUSPEND | IRQF_ONESHOT,
-					dev_name(dev), ptp_qoriq);
+	err = request_threaded_irq(ptp_qoriq->irq, NULL,
+				   dpaa2_ptp_irq_handler_thread,
+				   IRQF_NO_SUSPEND | IRQF_ONESHOT,
+				   dev_name(dev), ptp_qoriq);
 	if (err < 0) {
 		dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
 		goto err_free_mc_irq;
@@ -173,22 +173,26 @@
 				   DPRTC_IRQ_INDEX, 1);
 	if (err < 0) {
 		dev_err(dev, "dprtc_set_irq_enable(): %d\n", err);
-		goto err_free_mc_irq;
+		goto err_free_threaded_irq;
 	}
 
 	err = ptp_qoriq_init(ptp_qoriq, base, &dpaa2_ptp_caps);
 	if (err)
-		goto err_free_mc_irq;
+		goto err_free_threaded_irq;
 
 	dpaa2_phc_index = ptp_qoriq->phc_index;
 	dev_set_drvdata(dev, ptp_qoriq);
 
 	return 0;
 
+err_free_threaded_irq:
+	free_irq(ptp_qoriq->irq, ptp_qoriq);
 err_free_mc_irq:
 	fsl_mc_free_irqs(mc_dev);
 err_unmap:
 	iounmap(base);
+err_put:
+	of_node_put(node);
 err_close:
 	dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
 err_free_mcp:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -254,7 +254,7 @@
 	/* disable interrupts */
 	enetc_wr_reg(v->rbier, 0);
 
-	for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+	for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
 		enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i), 0);
 
 	napi_schedule_irqoff(&v->napi);
@@ -290,7 +290,7 @@
 	/* enable interrupts */
 	enetc_wr_reg(v->rbier, ENETC_RBIER_RXTIE);
 
-	for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+	for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
 		enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i),
 			     ENETC_TBIER_TXTIE);
 
@@ -942,7 +942,7 @@
 		enetc_free_tx_ring(priv->tx_ring[i]);
 }
 
-static int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
 {
 	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
 
@@ -963,7 +963,7 @@
 	return 0;
 }
 
-static void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
 {
 	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
 
@@ -971,7 +971,7 @@
 	cbdr->bd_base = NULL;
 }
 
-static void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
+void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
 {
 	/* set CBDR cache attributes */
 	enetc_wr(hw, ENETC_SICAR2,
@@ -991,7 +991,7 @@
 	cbdr->cir = hw->reg + ENETC_SICBDRCIR;
 }
 
-static void enetc_clear_cbdr(struct enetc_hw *hw)
+void enetc_clear_cbdr(struct enetc_hw *hw)
 {
 	enetc_wr(hw, ENETC_SICBDRMR, 0);
 }
@@ -1016,13 +1016,12 @@
 	return 0;
 }
 
-static int enetc_configure_si(struct enetc_ndev_priv *priv)
+int enetc_configure_si(struct enetc_ndev_priv *priv)
 {
 	struct enetc_si *si = priv->si;
 	struct enetc_hw *hw = &si->hw;
 	int err;
 
-	enetc_setup_cbdr(hw, &si->cbd_ring);
 	/* set SI cache attributes */
 	enetc_wr(hw, ENETC_SICAR0,
 		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
@@ -1068,6 +1067,8 @@
 	if (err)
 		return err;
 
+	enetc_setup_cbdr(&si->hw, &si->cbd_ring);
+
 	priv->cls_rules = kcalloc(si->num_fs_entries, sizeof(*priv->cls_rules),
 				  GFP_KERNEL);
 	if (!priv->cls_rules) {
@@ -1075,14 +1076,8 @@
 		goto err_alloc_cls;
 	}
 
-	err = enetc_configure_si(priv);
-	if (err)
-		goto err_config_si;
-
 	return 0;
 
-err_config_si:
-	kfree(priv->cls_rules);
 err_alloc_cls:
 	enetc_clear_cbdr(&si->hw);
 	enetc_free_cbdr(priv->dev, &si->cbd_ring);
@@ -1151,7 +1146,12 @@
 
 	enetc_rxbdr_wr(hw, idx, ENETC_RBBSR, ENETC_RXB_DMA_SIZE);
 
+	/* Also prepare the consumer index in case page allocation never
+	 * succeeds. In that case, hardware will never advance producer index
+	 * to match consumer index, and will drop all frames.
+	 */
 	enetc_rxbdr_wr(hw, idx, ENETC_RBPIR, 0);
+	enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, 1);
 
 	/* enable Rx ints by setting pkt thr to 1 */
 	enetc_rxbdr_wr(hw, idx, ENETC_RBICIR0, ENETC_RBICIR0_ICEN | 0x1);
@@ -1227,7 +1227,6 @@
 static int enetc_setup_irqs(struct enetc_ndev_priv *priv)
 {
 	struct pci_dev *pdev = priv->si->pdev;
-	cpumask_t cpu_mask;
 	int i, j, err;
 
 	for (i = 0; i < priv->bdr_int_num; i++) {
@@ -1254,9 +1253,7 @@
 
 			enetc_wr(hw, ENETC_SIMSITRV(idx), entry);
 		}
-		cpumask_clear(&cpu_mask);
-		cpumask_set_cpu(i % num_online_cpus(), &cpu_mask);
-		irq_set_affinity_hint(irq, &cpu_mask);
+		irq_set_affinity_hint(irq, get_cpu_mask(i % num_online_cpus()));
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -221,6 +221,7 @@
 void enetc_init_si_rings_params(struct enetc_ndev_priv *priv);
 int enetc_alloc_si_resources(struct enetc_ndev_priv *priv);
 void enetc_free_si_resources(struct enetc_ndev_priv *priv);
+int enetc_configure_si(struct enetc_ndev_priv *priv);
 
 int enetc_open(struct net_device *ndev);
 int enetc_close(struct net_device *ndev);
@@ -236,6 +237,10 @@
 void enetc_set_ethtool_ops(struct net_device *ndev);
 
 /* control buffer descriptor ring (CBDR) */
+int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
+void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
+void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr);
+void enetc_clear_cbdr(struct enetc_hw *hw);
 int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
 			    char *mac_addr, int si_map);
 int enetc_clear_mac_flt_entry(struct enetc_si *si, int index);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -141,8 +141,8 @@
 	{ ENETC_PM0_R255,   "MAC rx 128-255 byte packets" },
 	{ ENETC_PM0_R511,   "MAC rx 256-511 byte packets" },
 	{ ENETC_PM0_R1023,  "MAC rx 512-1023 byte packets" },
-	{ ENETC_PM0_R1518,  "MAC rx 1024-1518 byte packets" },
-	{ ENETC_PM0_R1519X, "MAC rx 1519 to max-octet packets" },
+	{ ENETC_PM0_R1522,  "MAC rx 1024-1522 byte packets" },
+	{ ENETC_PM0_R1523X, "MAC rx 1523 to max-octet packets" },
 	{ ENETC_PM0_ROVR,   "MAC rx oversized packets" },
 	{ ENETC_PM0_RJBR,   "MAC rx jabber packets" },
 	{ ENETC_PM0_RFRG,   "MAC rx fragment packets" },
@@ -155,15 +155,19 @@
 	{ ENETC_PM0_TFRM,   "MAC tx frames" },
 	{ ENETC_PM0_TFCS,   "MAC tx fcs errors" },
 	{ ENETC_PM0_TVLAN,  "MAC tx VLAN frames" },
-	{ ENETC_PM0_TERR,   "MAC tx frames" },
+	{ ENETC_PM0_TERR,   "MAC tx frame errors" },
 	{ ENETC_PM0_TUCA,   "MAC tx unicast frames" },
 	{ ENETC_PM0_TMCA,   "MAC tx multicast frames" },
 	{ ENETC_PM0_TBCA,   "MAC tx broadcast frames" },
 	{ ENETC_PM0_TPKT,   "MAC tx packets" },
 	{ ENETC_PM0_TUND,   "MAC tx undersized packets" },
+	{ ENETC_PM0_T64,    "MAC tx 64 byte packets" },
 	{ ENETC_PM0_T127,   "MAC tx 65-127 byte packets" },
+	{ ENETC_PM0_T255,   "MAC tx 128-255 byte packets" },
+	{ ENETC_PM0_T511,   "MAC tx 256-511 byte packets" },
 	{ ENETC_PM0_T1023,  "MAC tx 512-1023 byte packets" },
-	{ ENETC_PM0_T1518,  "MAC tx 1024-1518 byte packets" },
+	{ ENETC_PM0_T1522,  "MAC tx 1024-1522 byte packets" },
+	{ ENETC_PM0_T1523X, "MAC tx 1523 to max-octet packets" },
 	{ ENETC_PM0_TCNP,   "MAC tx control packets" },
 	{ ENETC_PM0_TDFR,   "MAC tx deferred packets" },
 	{ ENETC_PM0_TMCOL,  "MAC tx multiple collisions" },
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -181,6 +181,8 @@
 #define ENETC_PTCCBSR0(n)	(0x1110 + (n) * 8) /* n = 0 to 7*/
 #define ENETC_PTCCBSR1(n)	(0x1114 + (n) * 8) /* n = 0 to 7*/
 #define ENETC_RSSHASH_KEY_SIZE	40
+#define ENETC_PRSSCAPR		0x1404
+#define ENETC_PRSSCAPR_GET_NUM_RSS(val)	(BIT((val) & 0xf) * 32)
 #define ENETC_PRSSK(n)		(0x1410 + (n) * 4) /* n = [0..9] */
 #define ENETC_PSIVLANFMR	0x1700
 #define ENETC_PSIVLANFMR_VS	BIT(0)
@@ -239,8 +241,8 @@
 #define ENETC_PM0_R255		0x8180
 #define ENETC_PM0_R511		0x8188
 #define ENETC_PM0_R1023		0x8190
-#define ENETC_PM0_R1518		0x8198
-#define ENETC_PM0_R1519X	0x81A0
+#define ENETC_PM0_R1522		0x8198
+#define ENETC_PM0_R1523X	0x81A0
 #define ENETC_PM0_ROVR		0x81A8
 #define ENETC_PM0_RJBR		0x81B0
 #define ENETC_PM0_RFRG		0x81B8
@@ -259,9 +261,13 @@
 #define ENETC_PM0_TBCA		0x8250
 #define ENETC_PM0_TPKT		0x8260
 #define ENETC_PM0_TUND		0x8268
+#define ENETC_PM0_T64		0x8270
 #define ENETC_PM0_T127		0x8278
+#define ENETC_PM0_T255		0x8280
+#define ENETC_PM0_T511		0x8288
 #define ENETC_PM0_T1023		0x8290
-#define ENETC_PM0_T1518		0x8298
+#define ENETC_PM0_T1522		0x8298
+#define ENETC_PM0_T1523X	0x82A0
 #define ENETC_PM0_TCNP		0x82C0
 #define ENETC_PM0_TDFR		0x82D0
 #define ENETC_PM0_TMCOL		0x82D8
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -809,6 +809,71 @@
 		of_node_put(priv->phy_node);
 }
 
+/* Initialize the entire shared memory for the flow steering entries
+ * of this port (PF + VFs)
+ */
+static int enetc_init_port_rfs_memory(struct enetc_si *si)
+{
+	struct enetc_cmd_rfse rfse = {0};
+	struct enetc_hw *hw = &si->hw;
+	int num_rfs, i, err = 0;
+	u32 val;
+
+	val = enetc_port_rd(hw, ENETC_PRFSCAPR);
+	num_rfs = ENETC_PRFSCAPR_GET_NUM_RFS(val);
+
+	for (i = 0; i < num_rfs; i++) {
+		err = enetc_set_fs_entry(si, &rfse, i);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int enetc_init_port_rss_memory(struct enetc_si *si)
+{
+	struct enetc_hw *hw = &si->hw;
+	int num_rss, err;
+	int *rss_table;
+	u32 val;
+
+	val = enetc_port_rd(hw, ENETC_PRSSCAPR);
+	num_rss = ENETC_PRSSCAPR_GET_NUM_RSS(val);
+	if (!num_rss)
+		return 0;
+
+	rss_table = kcalloc(num_rss, sizeof(*rss_table), GFP_KERNEL);
+	if (!rss_table)
+		return -ENOMEM;
+
+	err = enetc_set_rss_table(si, rss_table, num_rss);
+
+	kfree(rss_table);
+
+	return err;
+}
+
+static void enetc_init_unused_port(struct enetc_si *si)
+{
+	struct device *dev = &si->pdev->dev;
+	struct enetc_hw *hw = &si->hw;
+	int err;
+
+	si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
+	err = enetc_alloc_cbdr(dev, &si->cbd_ring);
+	if (err)
+		return;
+
+	enetc_setup_cbdr(hw, &si->cbd_ring);
+
+	enetc_init_port_rfs_memory(si);
+	enetc_init_port_rss_memory(si);
+
+	enetc_clear_cbdr(hw);
+	enetc_free_cbdr(dev, &si->cbd_ring);
+}
+
 static int enetc_pf_probe(struct pci_dev *pdev,
 			  const struct pci_device_id *ent)
 {
@@ -818,11 +883,6 @@
 	struct enetc_pf *pf;
 	int err;
 
-	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
-		dev_info(&pdev->dev, "device is disabled, skipping\n");
-		return -ENODEV;
-	}
-
 	err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
 	if (err) {
 		dev_err(&pdev->dev, "PCI probing failed\n");
@@ -836,6 +896,13 @@
 		goto err_map_pf_space;
 	}
 
+	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
+		enetc_init_unused_port(si);
+		dev_info(&pdev->dev, "device is disabled, skipping\n");
+		err = -ENODEV;
+		goto err_device_disabled;
+	}
+
 	pf = enetc_si_priv(si);
 	pf->si = si;
 	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
@@ -863,6 +930,24 @@
 		goto err_alloc_si_res;
 	}
 
+	err = enetc_init_port_rfs_memory(si);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to initialize RFS memory\n");
+		goto err_init_port_rfs;
+	}
+
+	err = enetc_init_port_rss_memory(si);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to initialize RSS memory\n");
+		goto err_init_port_rss;
+	}
+
+	err = enetc_configure_si(priv);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to configure SI\n");
+		goto err_config_si;
+	}
+
 	err = enetc_alloc_msix(priv);
 	if (err) {
 		dev_err(&pdev->dev, "MSIX alloc failed\n");
@@ -885,14 +970,19 @@
 	return 0;
 
 err_reg_netdev:
+	enetc_mdio_remove(pf);
 	enetc_of_put_phy(priv);
 	enetc_free_msix(priv);
+err_config_si:
+err_init_port_rss:
+err_init_port_rfs:
 err_alloc_msix:
 	enetc_free_si_resources(priv);
 err_alloc_si_res:
 	si->ndev = NULL;
 	free_netdev(ndev);
 err_alloc_netdev:
+err_device_disabled:
 err_map_pf_space:
 	enetc_pci_remove(pdev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
@@ -8,7 +8,7 @@
 #include "enetc.h"
 
 int enetc_phc_index = -1;
-EXPORT_SYMBOL(enetc_phc_index);
+EXPORT_SYMBOL_GPL(enetc_phc_index);
 
 static struct ptp_clock_info enetc_ptp_caps = {
 	.owner		= THIS_MODULE,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -189,6 +189,12 @@
 		goto err_alloc_si_res;
 	}
 
+	err = enetc_configure_si(priv);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to configure SI\n");
+		goto err_config_si;
+	}
+
 	err = enetc_alloc_msix(priv);
 	if (err) {
 		dev_err(&pdev->dev, "MSIX alloc failed\n");
@@ -208,6 +214,7 @@
 
 err_reg_netdev:
 	enetc_free_msix(priv);
+err_config_si:
 err_alloc_msix:
 	enetc_free_si_resources(priv);
 err_alloc_si_res:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fec.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fec.h
@@ -77,6 +77,8 @@
 #define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
 #define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
 #define FEC_QOS_SCHEME		0x1f0 /* Set multi queues Qos scheme */
+#define FEC_LPI_SLEEP		0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
+#define FEC_LPI_WAKE		0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -373,11 +375,13 @@
 #define FEC_ENET_WAKEUP	((uint)0x00020000)	/* Wakeup request */
 #define FEC_ENET_TXF	(FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
 #define FEC_ENET_RXF	(FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
+#define FEC_ENET_RXF_GET(X)	(((X) == 0) ? FEC_ENET_RXF_0 :	\
+				(((X) == 1) ? FEC_ENET_RXF_1 :	\
+				FEC_ENET_RXF_2))
 #define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
 #define FEC_ENET_TS_TIMER       ((uint)0x00008000)
 
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_NAPI_IMASK	FEC_ENET_MII
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
 #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* ENET interrupt coalescing macro define */
@@ -457,6 +461,38 @@
  */
 #define FEC_QUIRK_HAS_FRREG		(1 << 16)
 
+/* Some FEC hardware blocks need the MMFR cleared at setup time to avoid
+ * the generation of an MII event. This must be avoided in the older
+ * FEC blocks where it will stop MII events being generated.
+ */
+#define FEC_QUIRK_CLEAR_SETUP_MII	(1 << 17)
+
+/* Some link partners do not tolerate the momentary reset of the REF_CLK
+ * frequency when the RNCTL register is cleared by hardware reset.
+ */
+#define FEC_QUIRK_NO_HARD_RESET		(1 << 18)
+
+/* i.MX6SX ENET IP supports multiple queues (3 queues), use this quirk to
+ * represents this ENET IP.
+ */
+#define FEC_QUIRK_HAS_MULTI_QUEUES	(1 << 19)
+
+/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE
+ * standard. For the transmission, MAC supply two user registers to set
+ * Sleep (TS) and Wake (TW) time.
+ */
+#define FEC_QUIRK_HAS_EEE		(1 << 20)
+
+/* i.MX8QM ENET IP version add new feture to generate delayed TXC/RXC
+ * as an alternative option to make sure it works well with various PHYs.
+ * For the implementation of delayed clock, ENET takes synchronized 250MHz
+ * clocks to generate 2ns delay.
+ */
+#define FEC_QUIRK_DELAYED_CLKS_SUPPORT	(1 << 21)
+
+/* i.MX8MQ SoC integration mix wakeup interrupt signal into "int2" interrupt line. */
+#define FEC_QUIRK_WAKEUP_FROM_INT2	(1 << 22)
+
 struct bufdesc_prop {
 	int qid;
 	/* Address of Rx and Tx buffers */
@@ -488,6 +524,12 @@
 	struct  sk_buff *rx_skbuff[RX_RING_SIZE];
 };
 
+struct fec_stop_mode_gpr {
+	struct regmap *gpr;
+	u8 reg;
+	u8 bit;
+};
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -520,11 +562,6 @@
 	unsigned int total_tx_ring_size;
 	unsigned int total_rx_ring_size;
 
-	unsigned long work_tx;
-	unsigned long work_rx;
-	unsigned long work_ts;
-	unsigned long work_mdio;
-
 	struct	platform_device *pdev;
 
 	int	dev_id;
@@ -537,12 +574,13 @@
 	int	link;
 	int	full_duplex;
 	int	speed;
-	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
 	bool	bufdesc_ex;
 	int	pause_flag;
 	int	wol_flag;
+	int	wake_irq;
 	u32	quirks;
+	bool	customize_phy_led;
 
 	struct	napi_struct napi;
 	int	csum_flags;
@@ -562,6 +600,7 @@
 	int hwts_tx_en;
 	struct delayed_work time_keep;
 	struct regulator *reg_phy;
+	struct fec_stop_mode_gpr stop_gpr;
 
 	unsigned int tx_align;
 	unsigned int rx_align;
@@ -573,6 +612,10 @@
 	unsigned int tx_time_itr;
 	unsigned int itr_clk_rate;
 
+	/* tx lpi eee mode */
+	struct ethtool_eee eee;
+	unsigned int clk_ref_rate;
+
 	u32 rx_copybreak;
 
 	/* ptp clock period in ns*/
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fec_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fec_main.c
@@ -46,6 +46,7 @@
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <linux/crc32.h>
@@ -62,6 +63,8 @@
 #include <linux/if_vlan.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/prefetch.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <soc/imx/cpuidle.h>
 
 #include <asm/cacheflush.h>
@@ -73,7 +76,7 @@
 
 #define DRIVER_NAME	"fec"
 
-#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+static const u16 fec_enet_vlan_pri_to_queue[8] = {0, 0, 1, 1, 1, 2, 2, 2};
 
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE	(1 << 5)
@@ -84,6 +87,74 @@
 #define FEC_ENET_OPD_V	0xFFF0
 #define FEC_MDIO_PM_TIMEOUT  100 /* ms */
 
+struct fec_devinfo {
+	u32 quirks;
+};
+
+static const struct fec_devinfo fec_imx25_info = {
+	.quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
+		  FEC_QUIRK_HAS_FRREG,
+};
+
+static const struct fec_devinfo fec_imx27_info = {
+	.quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
+};
+
+static const struct fec_devinfo fec_imx28_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
+		  FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
+		  FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII |
+		  FEC_QUIRK_NO_HARD_RESET,
+};
+
+static const struct fec_devinfo fec_imx6q_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
+		  FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII,
+};
+
+static const struct fec_devinfo fec_mvf600_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
+};
+
+static const struct fec_devinfo fec_imx6x_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+		  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+		  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+		  FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES,
+};
+
+static const struct fec_devinfo fec_imx6ul_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
+		  FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
+		  FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII,
+};
+
+static const struct fec_devinfo fec_imx8mq_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+		  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+		  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+		  FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
+		  FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2,
+};
+
+static const struct fec_devinfo fec_imx8qm_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+		  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+		  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+		  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+		  FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
+		  FEC_QUIRK_DELAYED_CLKS_SUPPORT,
+};
+
 static struct platform_device_id fec_devtype[] = {
 	{
 		/* keep it for coldfire */
@@ -91,39 +162,31 @@
 		.driver_data = 0,
 	}, {
 		.name = "imx25-fec",
-		.driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
-			       FEC_QUIRK_HAS_FRREG,
+		.driver_data = (kernel_ulong_t)&fec_imx25_info,
 	}, {
 		.name = "imx27-fec",
-		.driver_data = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
+		.driver_data = (kernel_ulong_t)&fec_imx27_info,
 	}, {
 		.name = "imx28-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
-				FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
-				FEC_QUIRK_HAS_FRREG,
+		.driver_data = (kernel_ulong_t)&fec_imx28_info,
 	}, {
 		.name = "imx6q-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
-				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
-				FEC_QUIRK_HAS_RACC,
+		.driver_data = (kernel_ulong_t)&fec_imx6q_info,
 	}, {
 		.name = "mvf600-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
+		.driver_data = (kernel_ulong_t)&fec_mvf600_info,
 	}, {
 		.name = "imx6sx-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
-				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
-				FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
-				FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
+		.driver_data = (kernel_ulong_t)&fec_imx6x_info,
 	}, {
 		.name = "imx6ul-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
-				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
-				FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
-				FEC_QUIRK_HAS_COALESCE,
+		.driver_data = (kernel_ulong_t)&fec_imx6ul_info,
+	}, {
+		.name = "imx8mq-fec",
+		.driver_data = (kernel_ulong_t)&fec_imx8mq_info,
+	}, {
+		.name = "imx8qm-fec",
+		.driver_data = (kernel_ulong_t)&fec_imx8qm_info,
 	}, {
 		/* sentinel */
 	}
@@ -138,6 +201,8 @@
 	MVF600_FEC,
 	IMX6SX_FEC,
 	IMX6UL_FEC,
+	IMX8MQ_FEC,
+	IMX8QM_FEC,
 };
 
 static const struct of_device_id fec_dt_ids[] = {
@@ -148,6 +213,8 @@
 	{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
 	{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
 	{ .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
+	{ .compatible = "fsl,imx8mq-fec", .data = &fec_devtype[IMX8MQ_FEC], },
+	{ .compatible = "fsl,imx8qm-fec", .data = &fec_devtype[IMX8QM_FEC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -232,7 +299,15 @@
 #define FEC_WOL_FLAG_ENABLE		(0x1 << 1)
 #define FEC_WOL_FLAG_SLEEP_ON		(0x1 << 2)
 
-#define COPYBREAK_DEFAULT	256
+/* By default, set the copybreak to 1518,
+ * then the RX path always keep DMA memory unchanged, and
+ * allocate one new skb and copy DMA memory data to the new skb
+ * buffer, which can improve the performance when SMMU is enabled.
+ *
+ * The driver support .set_tunable() interface for ethtool, user
+ * can dynamicly change the copybreak value.
+ */
+#define COPYBREAK_DEFAULT	1518
 
 /* Max number of allowed TCP segments for software TSO */
 #define FEC_MAX_TSO_SEGS	100
@@ -386,6 +461,7 @@
 				estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
 			if (skb->ip_summed == CHECKSUM_PARTIAL)
 				estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
+
 			ebdp->cbd_bdu = 0;
 			ebdp->cbd_esc = cpu_to_fec32(estatus);
 		}
@@ -588,7 +664,7 @@
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
 			netdev_err(ndev, "Tx DMA memory map failed\n");
-		return NETDEV_TX_BUSY;
+		return NETDEV_TX_OK;
 	}
 
 	bdp->cbd_datlen = cpu_to_fec16(size);
@@ -650,7 +726,7 @@
 			dev_kfree_skb_any(skb);
 			if (net_ratelimit())
 				netdev_err(ndev, "Tx DMA memory map failed\n");
-			return NETDEV_TX_BUSY;
+			return NETDEV_TX_OK;
 		}
 	}
 
@@ -912,7 +988,6 @@
 fec_restart(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	u32 val;
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
@@ -921,7 +996,8 @@
 	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
 	 * instead of reset MAC itself.
 	 */
-	if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+	if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES ||
+	    ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
 		writel(0, fep->hwp + FEC_ECNTRL);
 	} else {
 		writel(1, fep->hwp + FEC_ECNTRL);
@@ -938,8 +1014,8 @@
 	writel((__force u32)cpu_to_be32(temp_mac[1]),
 	       fep->hwp + FEC_ADDR_HIGH);
 
-	/* Clear any outstanding interrupt. */
-	writel(0xffffffff, fep->hwp + FEC_IEVENT);
+	/* Clear any outstanding interrupt, except MDIO. */
+	writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT);
 
 	fec_enet_bd_init(ndev);
 
@@ -963,7 +1039,8 @@
 
 #if !defined(CONFIG_M5272)
 	if (fep->quirks & FEC_QUIRK_HAS_RACC) {
-		val = readl(fep->hwp + FEC_RACC);
+		u32 val = readl(fep->hwp + FEC_RACC);
+
 		/* align IP header */
 		val |= FEC_RACC_SHIFT16;
 		if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
@@ -1085,18 +1162,50 @@
 	if (fep->link)
 		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	else
-		writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+		writel(0, fep->hwp + FEC_IMASK);
 
 	/* Init the interrupt coalescing */
 	fec_enet_itr_coal_init(ndev);
 
 }
 
+static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
+{
+	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
+	struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr;
+
+	if (stop_gpr->gpr) {
+		if (enabled)
+			regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
+					   BIT(stop_gpr->bit),
+					   BIT(stop_gpr->bit));
+		else
+			regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
+					   BIT(stop_gpr->bit), 0);
+	} else if (pdata && pdata->sleep_mode_enable) {
+		pdata->sleep_mode_enable(enabled);
+	}
+}
+
+static void fec_irqs_disable(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	writel(0, fep->hwp + FEC_IMASK);
+}
+
+static void fec_irqs_disable_except_wakeup(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	writel(0, fep->hwp + FEC_IMASK);
+	writel(FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
+}
+
 static void
 fec_stop(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
 	u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
 	u32 val;
 
@@ -1113,23 +1222,19 @@
 	 * instead of reset MAC itself.
 	 */
 	if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
-		if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+		if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
 			writel(0, fep->hwp + FEC_ECNTRL);
 		} else {
 			writel(1, fep->hwp + FEC_ECNTRL);
 			udelay(10);
 		}
-		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	} else {
-		writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
 		val = readl(fep->hwp + FEC_ECNTRL);
 		val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
 		writel(val, fep->hwp + FEC_ECNTRL);
-
-		if (pdata && pdata->sleep_mode_enable)
-			pdata->sleep_mode_enable(true);
 	}
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
 	/* We have to keep ENET enabled to have MII interrupt stay working */
 	if (fep->quirks & FEC_QUIRK_ENET_MAC &&
@@ -1199,8 +1304,6 @@
 
 	fep = netdev_priv(ndev);
 
-	queue_id = FEC_ENET_GET_QUQUE(queue_id);
-
 	txq = fep->tx_queue[queue_id];
 	/* get next bdp of dirty_tx */
 	nq = netdev_get_tx_queue(ndev, queue_id);
@@ -1291,17 +1394,14 @@
 		writel(0, txq->bd.reg_desc_active);
 }
 
-static void
-fec_enet_tx(struct net_device *ndev)
+static void fec_enet_tx(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	u16 queue_id;
-	/* First process class A queue, then Class B and Best Effort queue */
-	for_each_set_bit(queue_id, &fep->work_tx, FEC_ENET_MAX_TX_QS) {
-		clear_bit(queue_id, &fep->work_tx);
-		fec_enet_tx_queue(ndev, queue_id);
-	}
-	return;
+	int i;
+
+	/* Make sure that AVB queues are processed first. */
+	for (i = fep->num_tx_queues - 1; i >= 0; i--)
+		fec_enet_tx_queue(ndev, i);
 }
 
 static int
@@ -1377,7 +1477,6 @@
 #ifdef CONFIG_M532x
 	flush_cache_all();
 #endif
-	queue_id = FEC_ENET_GET_QUQUE(queue_id);
 	rxq = fep->rx_queue[queue_id];
 
 	/* First, grab all of the stats for the incoming packet.
@@ -1391,7 +1490,7 @@
 			break;
 		pkt_received++;
 
-		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
+		writel(FEC_ENET_RXF_GET(queue_id), fep->hwp + FEC_IEVENT);
 
 		/* Check for errors. */
 		status ^= BD_ENET_RX_LAST;
@@ -1501,6 +1600,7 @@
 					       htons(ETH_P_8021Q),
 					       vlan_tag);
 
+		skb_record_rx_queue(skb, queue_id);
 		napi_gro_receive(&fep->napi, skb);
 
 		if (is_copybreak) {
@@ -1546,48 +1646,30 @@
 	return pkt_received;
 }
 
-static int
-fec_enet_rx(struct net_device *ndev, int budget)
+static int fec_enet_rx(struct net_device *ndev, int budget)
 {
-	int     pkt_received = 0;
-	u16	queue_id;
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i, done = 0;
 
-	for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
-		int ret;
-
-		ret = fec_enet_rx_queue(ndev,
-					budget - pkt_received, queue_id);
+	/* Make sure that AVB queues are processed first. */
+	for (i = fep->num_rx_queues - 1; i >= 0; i--)
+		done += fec_enet_rx_queue(ndev, budget - done, i);
 
-		if (ret < budget - pkt_received)
-			clear_bit(queue_id, &fep->work_rx);
-
-		pkt_received += ret;
-	}
-	return pkt_received;
+	return done;
 }
 
-static bool
-fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
+static bool fec_enet_collect_events(struct fec_enet_private *fep)
 {
-	if (int_events == 0)
-		return false;
+	uint int_events;
 
-	if (int_events & FEC_ENET_RXF_0)
-		fep->work_rx |= (1 << 2);
-	if (int_events & FEC_ENET_RXF_1)
-		fep->work_rx |= (1 << 0);
-	if (int_events & FEC_ENET_RXF_2)
-		fep->work_rx |= (1 << 1);
-
-	if (int_events & FEC_ENET_TXF_0)
-		fep->work_tx |= (1 << 2);
-	if (int_events & FEC_ENET_TXF_1)
-		fep->work_tx |= (1 << 0);
-	if (int_events & FEC_ENET_TXF_2)
-		fep->work_tx |= (1 << 1);
+	int_events = readl(fep->hwp + FEC_IEVENT);
 
-	return true;
+	/* Don't clear MDIO events, we poll for those */
+	int_events &= ~FEC_ENET_MII;
+
+	writel(int_events, fep->hwp + FEC_IEVENT);
+
+	return int_events != 0;
 }
 
 static irqreturn_t
@@ -1595,27 +1677,18 @@
 {
 	struct net_device *ndev = dev_id;
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	uint int_events;
 	irqreturn_t ret = IRQ_NONE;
 
-	int_events = readl(fep->hwp + FEC_IEVENT);
-	writel(int_events, fep->hwp + FEC_IEVENT);
-	fec_enet_collect_events(fep, int_events);
-
-	if ((fep->work_tx || fep->work_rx) && fep->link) {
+	if (fec_enet_collect_events(fep) && fep->link) {
 		ret = IRQ_HANDLED;
 
 		if (napi_schedule_prep(&fep->napi)) {
-			/* Disable the NAPI interrupts */
-			writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
+			/* Disable interrupts */
+			writel(0, fep->hwp + FEC_IMASK);
 			__napi_schedule(&fep->napi);
 		}
 	}
 
-	if (int_events & FEC_ENET_MII) {
-		ret = IRQ_HANDLED;
-		complete(&fep->mdio_done);
-	}
 	return ret;
 }
 
@@ -1623,24 +1696,25 @@
 {
 	struct net_device *ndev = napi->dev;
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	int pkts;
-
-	pkts = fec_enet_rx(ndev, budget);
+	int done = 0;
 
-	fec_enet_tx(ndev);
+	do {
+		done += fec_enet_rx(ndev, budget - done);
+		fec_enet_tx(ndev);
+	} while ((done < budget) && fec_enet_collect_events(fep));
 
-	if (pkts < budget) {
-		napi_complete_done(napi, pkts);
+	if (done < budget) {
+		napi_complete_done(napi, done);
 		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	}
-	return pkts;
+
+	return done;
 }
 
 /* ------------------------------------------------------------------------- */
-static void fec_get_mac(struct net_device *ndev)
+static int fec_get_mac(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
 	unsigned char *iap, tmpaddr[ETH_ALEN];
 
 	/*
@@ -1660,6 +1734,8 @@
 			const char *mac = of_get_mac_address(np);
 			if (!IS_ERR(mac))
 				iap = (unsigned char *) mac;
+			else if (PTR_ERR(mac) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
 		}
 	}
 
@@ -1671,6 +1747,8 @@
 		if (FEC_FLASHMAC)
 			iap = (unsigned char *)FEC_FLASHMAC;
 #else
+		struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
+
 		if (pdata)
 			iap = (unsigned char *)&pdata->mac;
 #endif
@@ -1696,7 +1774,7 @@
 		eth_hw_addr_random(ndev);
 		dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
 			 ndev->dev_addr);
-		return;
+		return 0;
 	}
 
 	memcpy(ndev->dev_addr, iap, ETH_ALEN);
@@ -1704,19 +1782,76 @@
 	/* Adjust MAC if using macaddr */
 	if (iap == macaddr)
 		 ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id;
+
+	return 0;
 }
 
 /* ------------------------------------------------------------------------- */
 
 /*
- * Phy section
+ * Set PHY LED configuration for RTL8211E
  */
+static void set_led_configuration_e(struct phy_device *phy_dev)
+{
+	/* Disable EEE LED mode */
+	phy_write(phy_dev, 31, 0x0005);
+	phy_write(phy_dev, 5, 0x8b82);
+	phy_write(phy_dev, 6, 0x052b);
+	phy_write(phy_dev, 31, 0x0000);
+
+	/* To switch to extension Page44 */
+	phy_write(phy_dev, 31, 0x0007);
+	phy_write(phy_dev, 30, 0x002c);
+
+	phy_write(phy_dev, 26, 0x0010);
+	phy_write(phy_dev, 28, 0x0247);
+
+	/* Switch to PHY`s Page0 */
+	phy_write(phy_dev, 31, 0);
+}
+
+/* Set PHY LED configuration for RTL8211F */
+static void set_led_configuration_f(struct phy_device *phy_dev)
+{
+	/* To switch Page0xd04 */
+	phy_write(phy_dev, 31, 0x0d04);
+	/* Disable EEELCR mode */
+	phy_write(phy_dev, 17, 0x0000);
+	phy_write(phy_dev, 16, 0x091b);
+
+	/* LED freq */
+	phy_write(phy_dev, 18, 0x03e2);
+
+	/* Switch to Page0 */
+	phy_write(phy_dev, 31, 0x0000);
+}
+
+/* Phy section */
+static inline void fec_set_phy_led_config(struct phy_device *phy_dev)
+{
+	int phy_id2_val = 0;
+
+	dev_dbg(&phy_dev->mdio.dev, "PHYID1 = 0x%x, PHYID2 = 0x%x\n",
+		phy_read(phy_dev, 2), phy_read(phy_dev, 3));
+	phy_id2_val = phy_read(phy_dev, 3);
+	if (phy_id2_val == 0xc915) {
+		dev_dbg(&phy_dev->mdio.dev, "PHY is RTL8211E\n");
+		set_led_configuration_e(phy_dev);
+	} else {
+		dev_dbg(&phy_dev->mdio.dev, "PHY is RTL8211F\n");
+		set_led_configuration_f(phy_dev);
+	}
+}
+
 static void fec_enet_adjust_link(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct phy_device *phy_dev = ndev->phydev;
 	int status_change = 0;
 
+	if (fep->customize_phy_led)
+		fec_set_phy_led_config(phy_dev);
+
 	/*
 	 * If the netdev is down, or is going down, we're not interested
 	 * in link state events, so just mark our idea of the link as down
@@ -1742,6 +1877,7 @@
 
 		/* if any of the above changed restart the FEC */
 		if (status_change) {
+			netif_stop_queue(ndev);
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
 			fec_restart(ndev);
@@ -1751,6 +1887,7 @@
 		}
 	} else {
 		if (fep->link) {
+			netif_stop_queue(ndev);
 			napi_disable(&fep->napi);
 			netif_tx_lock_bh(ndev);
 			fec_stop(ndev);
@@ -1765,20 +1902,31 @@
 		phy_print_status(phy_dev);
 }
 
+static int fec_enet_mdio_wait(struct fec_enet_private *fep)
+{
+	uint ievent;
+	int ret;
+
+	ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent,
+					ievent & FEC_ENET_MII, 2, 30000);
+
+	if (!ret)
+		writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+
+	return ret;
+}
+
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
 	struct fec_enet_private *fep = bus->priv;
 	struct device *dev = &fep->pdev->dev;
-	unsigned long time_left;
 	int ret = 0, frame_start, frame_addr, frame_op;
 	bool is_c45 = !!(regnum & MII_ADDR_C45);
 
-	ret = pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0)
 		return ret;
 
-	reinit_completion(&fep->mdio_done);
-
 	if (is_c45) {
 		frame_start = FEC_MMFR_ST_C45;
 
@@ -1790,11 +1938,9 @@
 		       fep->hwp + FEC_MII_DATA);
 
 		/* wait for end of transfer */
-		time_left = wait_for_completion_timeout(&fep->mdio_done,
-				usecs_to_jiffies(FEC_MII_TIMEOUT));
-		if (time_left == 0) {
+		ret = fec_enet_mdio_wait(fep);
+		if (ret) {
 			netdev_err(fep->netdev, "MDIO address write timeout\n");
-			ret = -ETIMEDOUT;
 			goto out;
 		}
 
@@ -1813,11 +1959,9 @@
 		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+	ret = fec_enet_mdio_wait(fep);
+	if (ret) {
 		netdev_err(fep->netdev, "MDIO read timeout\n");
-		ret = -ETIMEDOUT;
 		goto out;
 	}
 
@@ -1835,17 +1979,12 @@
 {
 	struct fec_enet_private *fep = bus->priv;
 	struct device *dev = &fep->pdev->dev;
-	unsigned long time_left;
 	int ret, frame_start, frame_addr;
 	bool is_c45 = !!(regnum & MII_ADDR_C45);
 
-	ret = pm_runtime_get_sync(dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0)
 		return ret;
-	else
-		ret = 0;
-
-	reinit_completion(&fep->mdio_done);
 
 	if (is_c45) {
 		frame_start = FEC_MMFR_ST_C45;
@@ -1858,11 +1997,9 @@
 		       fep->hwp + FEC_MII_DATA);
 
 		/* wait for end of transfer */
-		time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-		if (time_left == 0) {
+		ret = fec_enet_mdio_wait(fep);
+		if (ret) {
 			netdev_err(fep->netdev, "MDIO address write timeout\n");
-			ret = -ETIMEDOUT;
 			goto out;
 		}
 	} else {
@@ -1878,12 +2015,9 @@
 		fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+	ret = fec_enet_mdio_wait(fep);
+	if (ret)
 		netdev_err(fep->netdev, "MDIO write timeout\n");
-		ret  = -ETIMEDOUT;
-	}
 
 out:
 	pm_runtime_mark_last_busy(dev);
@@ -1892,6 +2026,27 @@
 	return ret;
 }
 
+static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct phy_device *phy_dev = ndev->phydev;
+
+	if (phy_dev) {
+		phy_reset_after_clk_enable(phy_dev);
+	} else if (fep->phy_node) {
+		/*
+		 * If the PHY still is not bound to the MAC, but there is
+		 * OF PHY node and a matching PHY device instance already,
+		 * use the OF PHY node to obtain the PHY device instance,
+		 * and then use that PHY device instance when triggering
+		 * the PHY reset.
+		 */
+		phy_dev = of_phy_find_device(fep->phy_node);
+		phy_reset_after_clk_enable(phy_dev);
+		put_device(&phy_dev->mdio.dev);
+	}
+}
+
 static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1918,7 +2073,7 @@
 		if (ret)
 			goto failed_clk_ref;
 
-		phy_reset_after_clk_enable(ndev->phydev);
+		fec_enet_phy_reset_after_clk_enable(ndev);
 	} else {
 		clk_disable_unprepare(fep->clk_enet_out);
 		if (fep->clk_ptp) {
@@ -1933,11 +2088,14 @@
 	return 0;
 
 failed_clk_ref:
-	if (fep->clk_ref)
-		clk_disable_unprepare(fep->clk_ref);
+	if (fep->clk_ptp) {
+		mutex_lock(&fep->ptp_clk_mutex);
+		clk_disable_unprepare(fep->clk_ptp);
+		fep->ptp_clk_on = false;
+		mutex_unlock(&fep->ptp_clk_mutex);
+	}
 failed_clk_ptp:
-	if (fep->clk_enet_out)
-		clk_disable_unprepare(fep->clk_enet_out);
+	clk_disable_unprepare(fep->clk_enet_out);
 
 	return ret;
 }
@@ -2012,9 +2170,11 @@
 	static struct mii_bus *fec0_mii_bus;
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	bool suppress_preamble = false;
 	struct device_node *node;
 	int err = -ENXIO;
 	u32 mii_speed, holdtime;
+	u32 bus_freq;
 
 	/*
 	 * The i.MX28 dual fec interfaces are not equal.
@@ -2042,15 +2202,23 @@
 		return -ENOENT;
 	}
 
+	bus_freq = 2500000; /* 2.5MHz by default */
+	node = of_get_child_by_name(pdev->dev.of_node, "mdio");
+	if (node) {
+		of_property_read_u32(node, "clock-frequency", &bus_freq);
+		suppress_preamble = of_property_read_bool(node,
+							  "suppress-preamble");
+	}
+
 	/*
-	 * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
+	 * Set MII speed (= clk_get_rate() / 2 * phy_speed)
 	 *
 	 * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
 	 * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'.  The i.MX28
 	 * Reference Manual has an error on this, and gets fixed on i.MX6Q
 	 * document.
 	 */
-	mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
+	mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), bus_freq * 2);
 	if (fep->quirks & FEC_QUIRK_ENET_MAC)
 		mii_speed--;
 	if (mii_speed > 63) {
@@ -2077,8 +2245,26 @@
 
 	fep->phy_speed = mii_speed << 1 | holdtime << 8;
 
+	if (suppress_preamble)
+		fep->phy_speed |= BIT(7);
+
+	if (fep->quirks & FEC_QUIRK_CLEAR_SETUP_MII) {
+		/* Clear MMFR to avoid to generate MII event by writing MSCR.
+		 * MII event generation condition:
+		 * - writing MSCR:
+		 *	- mmfr[31:0]_not_zero & mscr[7:0]_is_zero &
+		 *	  mscr_reg_data_in[7:0] != 0
+		 * - writing MMFR:
+		 *	- mscr[7:0]_not_zero
+		 */
+		writel(0, fep->hwp + FEC_MII_DATA);
+	}
+
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
+	/* Clear any pending transaction complete indication */
+	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+
 	fep->mii_bus = mdiobus_alloc();
 	if (fep->mii_bus == NULL) {
 		err = -ENOMEM;
@@ -2093,11 +2279,10 @@
 	fep->mii_bus->priv = fep;
 	fep->mii_bus->parent = &pdev->dev;
 
-	node = of_get_child_by_name(pdev->dev.of_node, "mdio");
 	err = of_mdiobus_register(fep->mii_bus, node);
-	of_node_put(node);
 	if (err)
 		goto err_out_free_mdiobus;
+	of_node_put(node);
 
 	mii_cnt++;
 
@@ -2110,6 +2295,7 @@
 err_out_free_mdiobus:
 	mdiobus_free(fep->mii_bus);
 err_out:
+	of_node_put(node);
 	return err;
 }
 
@@ -2199,8 +2385,14 @@
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	u32 __iomem *theregs = (u32 __iomem *)fep->hwp;
+	struct device *dev = &fep->pdev->dev;
 	u32 *buf = (u32 *)regbuf;
 	u32 i, off;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return;
 
 	regs->version = fec_enet_register_version;
 
@@ -2216,6 +2408,9 @@
 		off >>= 2;
 		buf[off] = readl(&theregs[off]);
 	}
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static int fec_enet_get_ts_info(struct net_device *ndev,
@@ -2475,7 +2670,7 @@
 
 	writel(tx_itr, fep->hwp + FEC_TXIC0);
 	writel(rx_itr, fep->hwp + FEC_RXIC0);
-	if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+	if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
 		writel(tx_itr, fep->hwp + FEC_TXIC1);
 		writel(rx_itr, fep->hwp + FEC_RXIC1);
 		writel(tx_itr, fep->hwp + FEC_TXIC2);
@@ -2520,15 +2715,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) {
 		dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
 		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) {
-		dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
+		dev_err(dev, "Tx coalesced usec exceed hardware limitation\n");
 		return -EINVAL;
 	}
 
@@ -2594,6 +2789,92 @@
 	return ret;
 }
 
+/* LPI Sleep Ts count base on tx clk (clk_ref).
+ * The lpi sleep cnt value = X us / (cycle_ns)
+ */
+static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	return us * (fep->clk_ref_rate / 1000) / 1000;
+}
+
+static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct ethtool_eee *p = &fep->eee;
+	unsigned int sleep_cycle, wake_cycle;
+	int ret = 0;
+
+	if (enable) {
+		ret = phy_init_eee(ndev->phydev, 0);
+		if (ret)
+			return ret;
+
+		sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
+		wake_cycle = sleep_cycle;
+	} else {
+		sleep_cycle = 0;
+		wake_cycle = 0;
+	}
+
+	p->tx_lpi_enabled = enable;
+	p->eee_enabled = enable;
+	p->eee_active = enable;
+
+	writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
+	writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
+
+	return 0;
+}
+
+static int
+fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct ethtool_eee *p = &fep->eee;
+
+	if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+		return -EOPNOTSUPP;
+
+	if (!netif_running(ndev))
+		return -ENETDOWN;
+
+	edata->eee_enabled = p->eee_enabled;
+	edata->eee_active = p->eee_active;
+	edata->tx_lpi_timer = p->tx_lpi_timer;
+	edata->tx_lpi_enabled = p->tx_lpi_enabled;
+
+	return phy_ethtool_get_eee(ndev->phydev, edata);
+}
+
+static int
+fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct ethtool_eee *p = &fep->eee;
+	int ret = 0;
+
+	if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+		return -EOPNOTSUPP;
+
+	if (!netif_running(ndev))
+		return -ENETDOWN;
+
+	p->tx_lpi_timer = edata->tx_lpi_timer;
+
+	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
+	    !edata->tx_lpi_timer)
+		ret = fec_enet_eee_mode_set(ndev, false);
+	else
+		ret = fec_enet_eee_mode_set(ndev, true);
+
+	if (ret)
+		return ret;
+
+	return phy_ethtool_set_eee(ndev->phydev, edata);
+}
+
 static void
 fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
 {
@@ -2619,15 +2900,10 @@
 		return -EINVAL;
 
 	device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
-	if (device_may_wakeup(&ndev->dev)) {
+	if (device_may_wakeup(&ndev->dev))
 		fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
-		if (fep->irq[0] > 0)
-			enable_irq_wake(fep->irq[0]);
-	} else {
+	else
 		fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
-		if (fep->irq[0] > 0)
-			disable_irq_wake(fep->irq[0]);
-	}
 
 	return 0;
 }
@@ -2652,6 +2928,8 @@
 	.set_tunable		= fec_enet_set_tunable,
 	.get_wol		= fec_enet_get_wol,
 	.set_wol		= fec_enet_set_wol,
+	.get_eee		= fec_enet_get_eee,
+	.set_eee		= fec_enet_set_eee,
 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
 };
@@ -2706,7 +2984,6 @@
 
 	for (q = 0; q < fep->num_tx_queues; q++) {
 		txq = fep->tx_queue[q];
-		bdp = txq->bd.base;
 		for (i = 0; i < txq->bd.ring_size; i++) {
 			kfree(txq->tx_bounce[i]);
 			txq->tx_bounce[i] = NULL;
@@ -2889,7 +3166,7 @@
 	int ret;
 	bool reset_again;
 
-	ret = pm_runtime_get_sync(&fep->pdev->dev);
+	ret = pm_runtime_resume_and_get(&fep->pdev->dev);
 	if (ret < 0)
 		return ret;
 
@@ -2920,16 +3197,16 @@
 	/* Init MAC prior to mii bus probe */
 	fec_restart(ndev);
 
-	/* Probe and connect to PHY when open the interface */
-	ret = fec_enet_mii_probe(ndev);
-	if (ret)
-		goto err_enet_mii_probe;
-
 	/* Call phy_reset_after_clk_enable() again if it failed during
 	 * phy_reset_after_clk_enable() before because the PHY wasn't probed.
 	 */
 	if (reset_again)
-		phy_reset_after_clk_enable(ndev->phydev);
+		fec_enet_phy_reset_after_clk_enable(ndev);
+
+	/* Probe and connect to PHY when open the interface */
+	ret = fec_enet_mii_probe(ndev);
+	if (ret)
+		goto err_enet_mii_probe;
 
 	if (fep->quirks & FEC_QUIRK_ERR006687)
 		imx6q_cpuidle_fec_irqs_used();
@@ -3136,10 +3413,40 @@
 	return 0;
 }
 
+static u16 fec_enet_get_raw_vlan_tci(struct sk_buff *skb)
+{
+	struct vlan_ethhdr *vhdr;
+	unsigned short vlan_TCI = 0;
+
+	if (skb->protocol == htons(ETH_P_ALL)) {
+		vhdr = (struct vlan_ethhdr *)(skb->data);
+		vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+	}
+
+	return vlan_TCI;
+}
+
+static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+				 struct net_device *sb_dev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	u16 vlan_tag;
+
+	if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
+		return netdev_pick_tx(ndev, skb, NULL);
+
+	vlan_tag = fec_enet_get_raw_vlan_tci(skb);
+	if (!vlan_tag)
+		return vlan_tag;
+
+	return fec_enet_vlan_pri_to_queue[vlan_tag >> 13];
+}
+
 static const struct net_device_ops fec_netdev_ops = {
 	.ndo_open		= fec_enet_open,
 	.ndo_stop		= fec_enet_close,
 	.ndo_start_xmit		= fec_enet_start_xmit,
+	.ndo_select_queue       = fec_enet_select_queue,
 	.ndo_set_rx_mode	= set_multicast_list,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_tx_timeout		= fec_timeout,
@@ -3191,7 +3498,9 @@
 		return ret;
 	}
 
-	fec_enet_alloc_queue(ndev);
+	ret = fec_enet_alloc_queue(ndev);
+	if (ret)
+		return ret;
 
 	bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) * dsize;
 
@@ -3199,11 +3508,15 @@
 	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;
 	}
 
 	/* Get the Ethernet address */
-	fec_get_mac(ndev);
+	ret = fec_get_mac(ndev);
+	if (ret)
+		goto free_queue_mem;
+
 	/* make sure MAC we just acquired is programmed into the hw */
 	fec_set_mac_address(ndev, NULL);
 
@@ -3262,7 +3575,7 @@
 		fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
 	}
 
-	if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+	if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
 		fep->tx_align = 0;
 		fep->rx_align = 0x3f;
 	}
@@ -3277,6 +3590,10 @@
 		fec_enet_update_ethtool_stats(ndev);
 
 	return 0;
+
+free_queue_mem:
+	fec_enet_free_queue(ndev);
+	return ret;
 }
 
 #ifdef CONFIG_OF
@@ -3389,6 +3706,52 @@
 	return irq_cnt;
 }
 
+static void fec_enet_get_wakeup_irq(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	if (fep->quirks & FEC_QUIRK_WAKEUP_FROM_INT2)
+		fep->wake_irq = fep->irq[2];
+	else
+		fep->wake_irq = fep->irq[0];
+}
+
+static int fec_enet_init_stop_mode(struct fec_enet_private *fep,
+				   struct device_node *np)
+{
+	struct device_node *gpr_np;
+	u32 out_val[3];
+	int ret = 0;
+
+	gpr_np = of_parse_phandle(np, "fsl,stop-mode", 0);
+	if (!gpr_np)
+		return 0;
+
+	ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
+					 ARRAY_SIZE(out_val));
+	if (ret) {
+		dev_dbg(&fep->pdev->dev, "no stop mode property\n");
+		return ret;
+	}
+
+	fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np);
+	if (IS_ERR(fep->stop_gpr.gpr)) {
+		dev_err(&fep->pdev->dev, "could not find gpr regmap\n");
+		ret = PTR_ERR(fep->stop_gpr.gpr);
+		fep->stop_gpr.gpr = NULL;
+		goto out;
+	}
+
+	fep->stop_gpr.reg = out_val[1];
+	fep->stop_gpr.bit = out_val[2];
+
+out:
+	of_node_put(gpr_np);
+
+	return ret;
+}
+
 static int
 fec_probe(struct platform_device *pdev)
 {
@@ -3403,6 +3766,7 @@
 	int num_rx_qs;
 	char irq_name[8];
 	int irq_cnt;
+	struct fec_devinfo *dev_info;
 
 	fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
@@ -3420,7 +3784,9 @@
 	of_id = of_match_device(fec_dt_ids, &pdev->dev);
 	if (of_id)
 		pdev->id_entry = of_id->data;
-	fep->quirks = pdev->id_entry->driver_data;
+	dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data;
+	if (dev_info)
+		fep->quirks = dev_info->quirks;
 
 	fep->netdev = ndev;
 	fep->num_rx_queues = num_rx_qs;
@@ -3454,6 +3820,10 @@
 	if (of_get_property(np, "fsl,magic-packet", NULL))
 		fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
 
+	ret = fec_enet_init_stop_mode(fep, np);
+	if (ret)
+		goto failed_stop_mode;
+
 	phy_node = of_parse_phandle(np, "phy-handle", 0);
 	if (!phy_node && of_phy_is_fixed_link(np)) {
 		ret = of_phy_register_fixed_link(np);
@@ -3503,6 +3873,7 @@
 	fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
 	if (IS_ERR(fep->clk_ref))
 		fep->clk_ref = NULL;
+	fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
 
 	fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
 	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
@@ -3573,16 +3944,23 @@
 		fep->irq[i] = irq;
 	}
 
-	init_completion(&fep->mdio_done);
+	/* Decide which interrupt line is wakeup capable */
+	fec_enet_get_wakeup_irq(pdev);
+
 	ret = fec_enet_mii_init(pdev);
 	if (ret)
 		goto failed_mii_init;
 
+	if (of_get_property(np, "customize-phy-led", NULL))
+		fep->customize_phy_led = true;
+
 	/* Carrier starts down, phylib will bring it up */
 	netif_carrier_off(ndev);
 	fec_enet_clk_enable(ndev, false);
 	pinctrl_pm_select_sleep_state(&pdev->dev);
 
+	ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN;
+
 	ret = register_netdev(ndev);
 	if (ret)
 		goto failed_register;
@@ -3607,11 +3985,11 @@
 failed_irq:
 failed_init:
 	fec_ptp_stop(pdev);
-	if (fep->reg_phy)
-		regulator_disable(fep->reg_phy);
 failed_reset:
 	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+	if (fep->reg_phy)
+		regulator_disable(fep->reg_phy);
 failed_regulator:
 	clk_disable_unprepare(fep->clk_ahb);
 failed_clk_ahb:
@@ -3622,6 +4000,7 @@
 	if (of_phy_is_fixed_link(np))
 		of_phy_deregister_fixed_link(np);
 	of_node_put(phy_node);
+failed_stop_mode:
 failed_phy:
 	dev_id--;
 failed_ioremap:
@@ -3638,9 +4017,11 @@
 	struct device_node *np = pdev->dev.of_node;
 	int ret;
 
-	ret = pm_runtime_get_sync(&pdev->dev);
+	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0)
-		return ret;
+		dev_err(&pdev->dev,
+			"Failed to resume device in remove callback (%pe)\n",
+			ERR_PTR(ret));
 
 	cancel_work_sync(&fep->tx_timeout_work);
 	fec_ptp_stop(pdev);
@@ -3652,13 +4033,18 @@
 	if (of_phy_is_fixed_link(np))
 		of_phy_deregister_fixed_link(np);
 	of_node_put(fep->phy_node);
-	free_netdev(ndev);
 
-	clk_disable_unprepare(fep->clk_ahb);
-	clk_disable_unprepare(fep->clk_ipg);
+	/* After pm_runtime_get_sync() failed, the clks are still off, so skip
+	 * disabling them again.
+	 */
+	if (ret >= 0) {
+		clk_disable_unprepare(fep->clk_ahb);
+		clk_disable_unprepare(fep->clk_ipg);
+	}
 	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
+	free_netdev(ndev);
 	return 0;
 }
 
@@ -3677,9 +4063,19 @@
 		netif_device_detach(ndev);
 		netif_tx_unlock_bh(ndev);
 		fec_stop(ndev);
-		fec_enet_clk_enable(ndev, false);
-		if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
+		if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
+			fec_irqs_disable(ndev);
 			pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+		} else {
+			fec_irqs_disable_except_wakeup(ndev);
+			if (fep->wake_irq > 0) {
+				disable_irq(fep->wake_irq);
+				enable_irq_wake(fep->wake_irq);
+			}
+			fec_enet_stop_mode(fep, true);
+		}
+		/* It's safe to disable clocks since interrupts are masked */
+		fec_enet_clk_enable(ndev, false);
 	}
 	rtnl_unlock();
 
@@ -3699,7 +4095,6 @@
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
 	int ret;
 	int val;
 
@@ -3717,8 +4112,12 @@
 			goto failed_clk;
 		}
 		if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
-			if (pdata && pdata->sleep_mode_enable)
-				pdata->sleep_mode_enable(false);
+			fec_enet_stop_mode(fep, false);
+			if (fep->wake_irq) {
+				disable_irq_wake(fep->wake_irq);
+				enable_irq(fep->wake_irq);
+			}
+
 			val = readl(fep->hwp + FEC_ECNTRL);
 			val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
 			writel(val, fep->hwp + FEC_ECNTRL);
@@ -3784,6 +4183,7 @@
 		.name	= DRIVER_NAME,
 		.pm	= &fec_pm_ops,
 		.of_match_table = fec_dt_ids,
+		.suppress_bind_attrs = true,
 	},
 	.id_table = fec_devtype,
 	.probe	= fec_probe,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -74,7 +74,7 @@
 static irqreturn_t mpc52xx_fec_interrupt(int, void *);
 static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
 static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
-static void mpc52xx_fec_stop(struct net_device *dev);
+static void mpc52xx_fec_stop(struct net_device *dev, bool may_sleep);
 static void mpc52xx_fec_start(struct net_device *dev);
 static void mpc52xx_fec_reset(struct net_device *dev);
 
@@ -283,7 +283,7 @@
 
 	netif_stop_queue(dev);
 
-	mpc52xx_fec_stop(dev);
+	mpc52xx_fec_stop(dev, true);
 
 	mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);
 
@@ -693,7 +693,7 @@
  *
  * stop all activity on fec and empty dma buffers
  */
-static void mpc52xx_fec_stop(struct net_device *dev)
+static void mpc52xx_fec_stop(struct net_device *dev, bool may_sleep)
 {
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 	struct mpc52xx_fec __iomem *fec = priv->fec;
@@ -706,7 +706,7 @@
 	bcom_disable(priv->rx_dmatsk);
 
 	/* Wait for tx queue to drain, but only if we're in process context */
-	if (!in_interrupt()) {
+	if (may_sleep) {
 		timeout = jiffies + msecs_to_jiffies(2000);
 		while (time_before(jiffies, timeout) &&
 				!bcom_queue_empty(priv->tx_dmatsk))
@@ -738,7 +738,7 @@
 	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
 	struct mpc52xx_fec __iomem *fec = priv->fec;
 
-	mpc52xx_fec_stop(dev);
+	mpc52xx_fec_stop(dev, false);
 
 	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
 	out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fec_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fec_ptp.c
@@ -103,11 +103,6 @@
 	u64 ns;
 	val = 0;
 
-	if (!(fep->hwts_tx_en || fep->hwts_rx_en)) {
-		dev_err(&fep->pdev->dev, "No ptp stack is running\n");
-		return -EINVAL;
-	}
-
 	if (fep->pps_enable == enable)
 		return 0;
 
@@ -141,11 +136,7 @@
 		 * NSEC_PER_SEC - ts.tv_nsec. Add the remaining nanoseconds
 		 * to current timer would be next second.
 		 */
-		tempval = readl(fep->hwp + FEC_ATIME_CTRL);
-		tempval |= FEC_T_CTRL_CAPTURE;
-		writel(tempval, fep->hwp + FEC_ATIME_CTRL);
-
-		tempval = readl(fep->hwp + FEC_ATIME);
+		tempval = fep->cc.read(&fep->cc);
 		/* Convert the ptp local counter to 1588 timestamp */
 		ns = timecounter_cyc2time(&fep->tc, tempval);
 		ts = ns_to_timespec64(ns);
@@ -220,15 +211,13 @@
 {
 	struct fec_enet_private *fep =
 		container_of(cc, struct fec_enet_private, cc);
-	const struct platform_device_id *id_entry =
-		platform_get_device_id(fep->pdev);
 	u32 tempval;
 
 	tempval = readl(fep->hwp + FEC_ATIME_CTRL);
 	tempval |= FEC_T_CTRL_CAPTURE;
 	writel(tempval, fep->hwp + FEC_ATIME_CTRL);
 
-	if (id_entry->driver_data & FEC_QUIRK_BUG_CAPTURE)
+	if (fep->quirks & FEC_QUIRK_BUG_CAPTURE)
 		udelay(1);
 
 	return readl(fep->hwp + FEC_ATIME);
@@ -269,7 +258,7 @@
 	fep->cc.mult = FEC_CC_MULT;
 
 	/* reset the ns time counter */
-	timecounter_init(&fep->tc, &fep->cc, ktime_to_ns(ktime_get_real()));
+	timecounter_init(&fep->tc, &fep->cc, 0);
 
 	spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 }
@@ -382,9 +371,16 @@
 	u64 ns;
 	unsigned long flags;
 
+	mutex_lock(&adapter->ptp_clk_mutex);
+	/* Check the ptp clock */
+	if (!adapter->ptp_clk_on) {
+		mutex_unlock(&adapter->ptp_clk_mutex);
+		return -EINVAL;
+	}
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
 	ns = timecounter_read(&adapter->tc);
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+	mutex_unlock(&adapter->ptp_clk_mutex);
 
 	*ts = ns_to_timespec64(ns);
 
@@ -478,9 +474,7 @@
 
 	switch (config.rx_filter) {
 	case HWTSTAMP_FILTER_NONE:
-		if (fep->hwts_rx_en)
-			fep->hwts_rx_en = 0;
-		config.rx_filter = HWTSTAMP_FILTER_NONE;
+		fep->hwts_rx_en = 0;
 		break;
 
 	default:
@@ -515,13 +509,12 @@
 {
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep);
-	u64 ns;
 	unsigned long flags;
 
 	mutex_lock(&fep->ptp_clk_mutex);
 	if (fep->ptp_clk_on) {
 		spin_lock_irqsave(&fep->tmreg_lock, flags);
-		ns = timecounter_read(&fep->tc);
+		timecounter_read(&fep->tc);
 		spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 	}
 	mutex_unlock(&fep->ptp_clk_mutex);
@@ -577,7 +570,7 @@
 	int ret;
 
 	fep->ptp_caps.owner = THIS_MODULE;
-	snprintf(fep->ptp_caps.name, 16, "fec ptp");
+	strlcpy(fep->ptp_caps.name, "fec ptp", sizeof(fep->ptp_caps.name));
 
 	fep->ptp_caps.max_adj = 250000000;
 	fep->ptp_caps.n_alarm = 0;
@@ -592,6 +585,10 @@
 	fep->ptp_caps.enable = fec_ptp_enable;
 
 	fep->cycle_speed = clk_get_rate(fep->clk_ptp);
+	if (!fep->cycle_speed) {
+		fep->cycle_speed = NSEC_PER_SEC;
+		dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n");
+	}
 	fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
 
 	spin_lock_init(&fep->tmreg_lock);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/Kconfig
@@ -8,3 +8,31 @@
 	help
 		Freescale Data-Path Acceleration Architecture Frame Manager
 		(FMan) support
+
+config DPAA_ERRATUM_A050385
+	bool
+	depends on ARM64 && FSL_DPAA
+	default y
+	help
+		DPAA FMan erratum A050385 software workaround implementation:
+		align buffers, data start, SG fragment length to avoid FMan DMA
+		splits.
+		FMAN DMA read or writes under heavy traffic load may cause FMAN
+		internal resource leak thus stopping further packet processing.
+		The FMAN internal queue can overflow when FMAN splits single
+		read or write transactions into multiple smaller transactions
+		such that more than 17 AXI transactions are in flight from FMAN
+		to interconnect. When the FMAN internal queue overflows, it can
+		stall further packet processing. The issue can occur with any
+		one of the following three conditions:
+		1. FMAN AXI transaction crosses 4K address boundary (Errata
+		A010022)
+		2. FMAN DMA address for an AXI transaction is not 16 byte
+		aligned, i.e. the last 4 bits of an address are non-zero
+		3. Scatter Gather (SG) frames have more than one SG buffer in
+		the SG list and any one of the buffers, except the last
+		buffer in the SG list has data size that is not a multiple
+		of 16 bytes, i.e., other than 16, 32, 48, 64, etc.
+		With any one of the above three conditions present, there is
+		likelihood of stalled FMAN packet processing, especially under
+		stress with multiple ports injecting line-rate traffic.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008-2015 Freescale Semiconductor Inc.
+ * Copyright 2020 NXP
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -566,6 +567,10 @@
 	u32 qmi_def_tnums_thresh;
 };
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+static bool fman_has_err_a050385;
+#endif
+
 static irqreturn_t fman_exceptions(struct fman *fman,
 				   enum fman_exceptions exception)
 {
@@ -1391,8 +1396,7 @@
 {
 	struct fman_fpm_regs __iomem *fpm_rg = fman->fpm_regs;
 	u16 fm_clk_freq = fman->state->fm_clk_freq;
-	u32 tmp, intgr, ts_freq;
-	u64 frac;
+	u32 tmp, intgr, ts_freq, frac;
 
 	ts_freq = (u32)(1 << fman->state->count1_micro_bit);
 	/* configure timestamp so that bit 8 will count 1 microsecond
@@ -2514,6 +2518,14 @@
 }
 EXPORT_SYMBOL(fman_bind);
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+bool fman_has_errata_a050385(void)
+{
+	return fman_has_err_a050385;
+}
+EXPORT_SYMBOL(fman_has_errata_a050385);
+#endif
+
 static irqreturn_t fman_err_irq(int irq, void *handle)
 {
 	struct fman *fman = (struct fman *)handle;
@@ -2841,6 +2853,11 @@
 		goto fman_free;
 	}
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+	fman_has_err_a050385 =
+		of_property_read_bool(fm_node, "fsl,erratum-a050385");
+#endif
+
 	return fman;
 
 fman_node_put:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman.h
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008-2015 Freescale Semiconductor Inc.
+ * Copyright 2020 NXP
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -398,6 +399,10 @@
 
 int fman_get_rx_extra_headroom(void);
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+bool fman_has_errata_a050385(void);
+#endif
+
 struct fman *fman_bind(struct device *dev);
 
 #endif /* __FM_H */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman_dtsec.c
@@ -1205,7 +1205,7 @@
 		list_for_each(pos,
 			      &dtsec->multicast_addr_hash->lsts[bucket]) {
 			hash_entry = ETH_HASH_ENTRY_OBJ(pos);
-			if (hash_entry->addr == addr) {
+			if (hash_entry && hash_entry->addr == addr) {
 				list_del_init(&hash_entry->node);
 				kfree(hash_entry);
 				break;
@@ -1218,7 +1218,7 @@
 		list_for_each(pos,
 			      &dtsec->unicast_addr_hash->lsts[bucket]) {
 			hash_entry = ETH_HASH_ENTRY_OBJ(pos);
-			if (hash_entry->addr == addr) {
+			if (hash_entry && hash_entry->addr == addr) {
 				list_del_init(&hash_entry->node);
 				kfree(hash_entry);
 				break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman_mac.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman_mac.h
@@ -252,7 +252,7 @@
 	struct eth_hash_t *hash;
 
 	/* Allocate address hash table */
-	hash = kmalloc_array(size, sizeof(struct eth_hash_t *), GFP_KERNEL);
+	hash = kmalloc(sizeof(*hash), GFP_KERNEL);
 	if (!hash)
 		return NULL;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman_memac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman_memac.c
@@ -110,7 +110,7 @@
 /* Interface Mode Register (IF_MODE) */
 
 #define IF_MODE_MASK		0x00000003 /* 30-31 Mask on i/f mode bits */
-#define IF_MODE_XGMII		0x00000000 /* 30-31 XGMII (10G) interface */
+#define IF_MODE_10G		0x00000000 /* 30-31 10G interface */
 #define IF_MODE_GMII		0x00000002 /* 30-31 GMII (1G) interface */
 #define IF_MODE_RGMII		0x00000004
 #define IF_MODE_RGMII_AUTO	0x00008000
@@ -440,7 +440,7 @@
 	tmp = 0;
 	switch (phy_if) {
 	case PHY_INTERFACE_MODE_XGMII:
-		tmp |= IF_MODE_XGMII;
+		tmp |= IF_MODE_10G;
 		break;
 	default:
 		tmp |= IF_MODE_GMII;
@@ -856,7 +856,6 @@
 
 	tmp = ioread32be(&regs->command_config);
 	tmp &= ~CMD_CFG_PFC_MODE;
-	priority = 0;
 
 	iowrite32be(tmp, &regs->command_config);
 
@@ -986,7 +985,7 @@
 
 	list_for_each(pos, &memac->multicast_addr_hash->lsts[hash]) {
 		hash_entry = ETH_HASH_ENTRY_OBJ(pos);
-		if (hash_entry->addr == addr) {
+		if (hash_entry && hash_entry->addr == addr) {
 			list_del_init(&hash_entry->node);
 			kfree(hash_entry);
 			break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman_port.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1756,6 +1756,7 @@
 	struct fman_port *port;
 	struct fman *fman;
 	struct device_node *fm_node, *port_node;
+	struct platform_device *fm_pdev;
 	struct resource res;
 	struct resource *dev_res;
 	u32 val;
@@ -1780,19 +1781,25 @@
 		goto return_err;
 	}
 
-	fman = dev_get_drvdata(&of_find_device_by_node(fm_node)->dev);
+	fm_pdev = of_find_device_by_node(fm_node);
 	of_node_put(fm_node);
-	if (!fman) {
+	if (!fm_pdev) {
 		err = -EINVAL;
 		goto return_err;
 	}
 
+	fman = dev_get_drvdata(&fm_pdev->dev);
+	if (!fman) {
+		err = -EINVAL;
+		goto put_device;
+	}
+
 	err = of_property_read_u32(port_node, "cell-index", &val);
 	if (err) {
 		dev_err(port->dev, "%s: reading cell-index for %pOF failed\n",
 			__func__, port_node);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 	port_id = (u8)val;
 	port->dts_params.id = port_id;
@@ -1826,7 +1833,7 @@
 	}  else {
 		dev_err(port->dev, "%s: Illegal port type\n", __func__);
 		err = -EINVAL;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.type = port_type;
@@ -1840,7 +1847,7 @@
 			dev_err(port->dev, "%s: incorrect qman-channel-id\n",
 				__func__);
 			err = -EINVAL;
-			goto return_err;
+			goto put_device;
 		}
 		port->dts_params.qman_channel_id = qman_channel_id;
 	}
@@ -1850,7 +1857,7 @@
 		dev_err(port->dev, "%s: of_address_to_resource() failed\n",
 			__func__);
 		err = -ENOMEM;
-		goto return_err;
+		goto put_device;
 	}
 
 	port->dts_params.fman = fman;
@@ -1875,6 +1882,8 @@
 
 	return 0;
 
+put_device:
+	put_device(&fm_pdev->dev);
 return_err:
 	of_node_put(port_node);
 free_port:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/fman_tgec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/fman_tgec.c
@@ -630,7 +630,7 @@
 
 	list_for_each(pos, &tgec->multicast_addr_hash->lsts[hash]) {
 		hash_entry = ETH_HASH_ENTRY_OBJ(pos);
-		if (hash_entry->addr == addr) {
+		if (hash_entry && hash_entry->addr == addr) {
 			list_del_init(&hash_entry->node);
 			kfree(hash_entry);
 			break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fman/mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fman/mac.c
@@ -94,14 +94,17 @@
 		__func__, ex);
 }
 
-static void set_fman_mac_params(struct mac_device *mac_dev,
-				struct fman_mac_params *params)
+static int set_fman_mac_params(struct mac_device *mac_dev,
+			       struct fman_mac_params *params)
 {
 	struct mac_priv_s *priv = mac_dev->priv;
 
 	params->base_addr = (typeof(params->base_addr))
 		devm_ioremap(priv->dev, mac_dev->res->start,
 			     resource_size(mac_dev->res));
+	if (!params->base_addr)
+		return -ENOMEM;
+
 	memcpy(&params->addr, mac_dev->addr, sizeof(mac_dev->addr));
 	params->max_speed	= priv->max_speed;
 	params->phy_if		= mac_dev->phy_if;
@@ -112,6 +115,8 @@
 	params->event_cb	= mac_exception;
 	params->dev_id		= mac_dev;
 	params->internal_phy_node = priv->internal_phy_node;
+
+	return 0;
 }
 
 static int tgec_initialization(struct mac_device *mac_dev)
@@ -123,7 +128,9 @@
 
 	priv = mac_dev->priv;
 
-	set_fman_mac_params(mac_dev, &params);
+	err = set_fman_mac_params(mac_dev, &params);
+	if (err)
+		goto _return;
 
 	mac_dev->fman_mac = tgec_config(&params);
 	if (!mac_dev->fman_mac) {
@@ -169,7 +176,9 @@
 
 	priv = mac_dev->priv;
 
-	set_fman_mac_params(mac_dev, &params);
+	err = set_fman_mac_params(mac_dev, &params);
+	if (err)
+		goto _return;
 
 	mac_dev->fman_mac = dtsec_config(&params);
 	if (!mac_dev->fman_mac) {
@@ -218,7 +227,9 @@
 
 	priv = mac_dev->priv;
 
-	set_fman_mac_params(mac_dev, &params);
+	err = set_fman_mac_params(mac_dev, &params);
+	if (err)
+		goto _return;
 
 	if (priv->max_speed == SPEED_10000)
 		params.phy_if = PHY_INTERFACE_MODE_XGMII;
@@ -874,12 +885,21 @@
 	return err;
 }
 
+static int mac_remove(struct platform_device *pdev)
+{
+	struct mac_device *mac_dev = platform_get_drvdata(pdev);
+
+	platform_device_unregister(mac_dev->priv->eth_dev);
+	return 0;
+}
+
 static struct platform_driver mac_driver = {
 	.driver = {
 		.name		= KBUILD_MODNAME,
 		.of_match_table	= mac_match,
 	},
 	.probe		= mac_probe,
+	.remove		= mac_remove,
 };
 
 builtin_platform_driver(mac_driver);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
@@ -98,7 +98,7 @@
 		return -EINVAL;
 
 	fep->fec.fecp = of_iomap(ofdev->dev.of_node, 0);
-	if (!fep->fcc.fccp)
+	if (!fep->fec.fecp)
 		return -EINVAL;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
@@ -223,3 +223,4 @@
 };
 
 module_platform_driver(fs_enet_bb_mdio_driver);
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
@@ -224,3 +224,4 @@
 };
 
 module_platform_driver(fs_enet_fec_mdio_driver);
+MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/gianfar.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/gianfar.c
@@ -366,7 +366,11 @@
 
 static int gfar_set_mac_addr(struct net_device *dev, void *p)
 {
-	eth_mac_addr(dev, p);
+	int ret;
+
+	ret = eth_mac_addr(dev, p);
+	if (ret)
+		return ret;
 
 	gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
 
@@ -751,8 +755,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);
@@ -1824,20 +1830,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 */
@@ -2204,13 +2202,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;
@@ -2224,7 +2226,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;
@@ -2234,7 +2236,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);
@@ -2390,6 +2392,10 @@
 		if (lstatus & BD_LFLAG(RXBD_LAST))
 			size -= skb->len;
 
+		WARN(size < 0, "gianfar: rx fragment size underflow");
+		if (size < 0)
+			return false;
+
 		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
 				rxb->page_offset + RXBUF_ALIGNMENT,
 				size, GFAR_RXB_TRUESIZE);
@@ -2552,6 +2558,17 @@
 		if (lstatus & BD_LFLAG(RXBD_EMPTY))
 			break;
 
+		/* lost RXBD_LAST descriptor due to overrun */
+		if (skb &&
+		    (lstatus & BD_LFLAG(RXBD_FIRST))) {
+			/* discard faulty buffer */
+			dev_kfree_skb(skb);
+			skb = NULL;
+			rx_queue->stats.rx_dropped++;
+
+			/* can continue normally */
+		}
+
 		/* order rx buffer descriptor reads */
 		rmb();
 
@@ -3371,7 +3388,7 @@
 
 	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++) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -1489,6 +1489,7 @@
 	ptp_node = of_find_compatible_node(NULL, NULL, "fsl,etsec-ptp");
 	if (ptp_node) {
 		ptp_dev = of_find_device_by_node(ptp_node);
+		of_node_put(ptp_node);
 		if (ptp_dev)
 			ptp = platform_get_drvdata(ptp_dev);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/ucc_geth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/ucc_geth.c
@@ -42,6 +42,7 @@
 #include <soc/fsl/qe/ucc.h>
 #include <soc/fsl/qe/ucc_fast.h>
 #include <asm/machdep.h>
+#include <net/sch_generic.h>
 
 #include "ucc_geth.h"
 
@@ -1548,11 +1549,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);
@@ -1565,7 +1563,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
@@ -3889,6 +3890,7 @@
 	INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work);
 	netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64);
 	dev->mtu = 1500;
+	dev->max_mtu = 1518;
 
 	ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
 	ugeth->phy_interface = phy_interface;
@@ -3934,12 +3936,12 @@
 	struct device_node *np = ofdev->dev.of_node;
 
 	unregister_netdev(dev);
-	free_netdev(dev);
 	ucc_geth_memclean(ugeth);
 	if (of_phy_is_fixed_link(np))
 		of_phy_deregister_fixed_link(np);
 	of_node_put(ugeth->ug_info->tbi_node);
 	of_node_put(ugeth->ug_info->phy_node);
+	free_netdev(dev);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/freescale/ucc_geth.h
+++ linux-ein-5.4.0/drivers/net/ethernet/freescale/ucc_geth.h
@@ -576,7 +576,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-ein-5.4.0.orig/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ linux-ein-5.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);
@@ -274,6 +276,9 @@
 	priv->is_little_endian = of_property_read_bool(pdev->dev.of_node,
 						       "little-endian");
 
+	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");
@@ -296,9 +301,10 @@
 static int xgmac_mdio_remove(struct platform_device *pdev)
 {
 	struct mii_bus *bus = platform_get_drvdata(pdev);
+	struct mdio_fsl_priv *priv = bus->priv;
 
 	mdiobus_unregister(bus);
-	iounmap(bus->priv);
+	iounmap(priv->mdio_base);
 	mdiobus_free(bus);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -548,8 +548,8 @@
 
     base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
     if (!base) {
-	    pcmcia_release_window(link, link->resource[2]);
-	    return -ENOMEM;
+	pcmcia_release_window(link, link->resource[2]);
+	return -1;
     }
 
     pcmcia_map_mem_page(link, link->resource[2], 0);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/google/gve/gve.h
+++ linux-ein-5.4.0/drivers/net/ethernet/google/gve/gve.h
@@ -391,7 +391,7 @@
 				    gve_num_tx_qpls(priv));
 
 	/* we are out of rx qpls */
-	if (id == priv->qpl_cfg.qpl_map_size)
+	if (id == gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv))
 		return NULL;
 
 	set_bit(id, priv->qpl_cfg.qpl_id_map);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/google/gve/gve_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/google/gve/gve_main.c
@@ -30,6 +30,7 @@
 {
 	struct gve_priv *priv = netdev_priv(dev);
 	unsigned int start;
+	u64 packets, bytes;
 	int ring;
 
 	if (priv->rx) {
@@ -37,10 +38,12 @@
 			do {
 				start =
 				  u64_stats_fetch_begin(&priv->rx[ring].statss);
-				s->rx_packets += priv->rx[ring].rpackets;
-				s->rx_bytes += priv->rx[ring].rbytes;
+				packets = priv->rx[ring].rpackets;
+				bytes = priv->rx[ring].rbytes;
 			} while (u64_stats_fetch_retry(&priv->rx[ring].statss,
 						       start));
+			s->rx_packets += packets;
+			s->rx_bytes += bytes;
 		}
 	}
 	if (priv->tx) {
@@ -48,10 +51,12 @@
 			do {
 				start =
 				  u64_stats_fetch_begin(&priv->tx[ring].statss);
-				s->tx_packets += priv->tx[ring].pkt_done;
-				s->tx_bytes += priv->tx[ring].bytes_done;
+				packets = priv->tx[ring].pkt_done;
+				bytes = priv->tx[ring].bytes_done;
 			} while (u64_stats_fetch_retry(&priv->tx[ring].statss,
 						       start));
+			s->tx_packets += packets;
+			s->tx_bytes += bytes;
 		}
 	}
 }
@@ -121,7 +126,7 @@
 	/* Double check we have no extra work.
 	 * Ensure unmask synchronizes with checking for work.
 	 */
-	dma_rmb();
+	mb();
 	if (block->tx)
 		reschedule |= gve_tx_poll(block, -1);
 	if (block->rx)
@@ -161,6 +166,7 @@
 		int vecs_left = new_num_ntfy_blks % 2;
 
 		priv->num_ntfy_blks = new_num_ntfy_blks;
+		priv->mgmt_msix_idx = priv->num_ntfy_blks;
 		priv->tx_cfg.max_queues = min_t(int, priv->tx_cfg.max_queues,
 						vecs_per_type);
 		priv->rx_cfg.max_queues = min_t(int, priv->rx_cfg.max_queues,
@@ -241,20 +247,22 @@
 {
 	int i;
 
-	/* Free the irqs */
-	for (i = 0; i < priv->num_ntfy_blks; i++) {
-		struct gve_notify_block *block = &priv->ntfy_blocks[i];
-		int msix_idx = i;
-
-		irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
-				      NULL);
-		free_irq(priv->msix_vectors[msix_idx].vector, block);
+	if (priv->msix_vectors) {
+		/* Free the irqs */
+		for (i = 0; i < priv->num_ntfy_blks; i++) {
+			struct gve_notify_block *block = &priv->ntfy_blocks[i];
+			int msix_idx = i;
+
+			irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
+					      NULL);
+			free_irq(priv->msix_vectors[msix_idx].vector, block);
+		}
+		free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
 	}
 	dma_free_coherent(&priv->pdev->dev,
 			  priv->num_ntfy_blks * sizeof(*priv->ntfy_blocks),
 			  priv->ntfy_blocks, priv->ntfy_block_bus);
 	priv->ntfy_blocks = NULL;
-	free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
 	pci_disable_msix(priv->pdev);
 	kvfree(priv->msix_vectors);
 	priv->msix_vectors = NULL;
@@ -544,7 +552,7 @@
 	}
 
 	qpl->id = id;
-	qpl->num_entries = pages;
+	qpl->num_entries = 0;
 	qpl->pages = kvzalloc(pages * sizeof(*qpl->pages), GFP_KERNEL);
 	/* caller handles clean up */
 	if (!qpl->pages)
@@ -562,6 +570,7 @@
 		/* caller handles clean up */
 		if (err)
 			return -ENOMEM;
+		qpl->num_entries++;
 	}
 	priv->num_registered_pages += pages;
 
@@ -1114,8 +1123,8 @@
 
 	gve_write_version(&reg_bar->driver_version);
 	/* Get max queues to alloc etherdev */
-	max_rx_queues = ioread32be(&reg_bar->max_tx_queues);
-	max_tx_queues = ioread32be(&reg_bar->max_rx_queues);
+	max_tx_queues = ioread32be(&reg_bar->max_tx_queues);
+	max_rx_queues = ioread32be(&reg_bar->max_rx_queues);
 	/* Alloc and setup the netdev and priv */
 	dev = alloc_etherdev_mqs(sizeof(*priv), max_tx_queues, max_rx_queues);
 	if (!dev) {
@@ -1166,13 +1175,16 @@
 
 	err = register_netdev(dev);
 	if (err)
-		goto abort_with_wq;
+		goto abort_with_gve_init;
 
 	dev_info(&pdev->dev, "GVE version %s\n", gve_version_str);
 	gve_clear_probe_in_progress(priv);
 	queue_work(priv->gve_wq, &priv->service_task);
 	return 0;
 
+abort_with_gve_init:
+	gve_teardown_priv_resources(priv);
+
 abort_with_wq:
 	destroy_workqueue(priv->gve_wq);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/google/gve/gve_rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/google/gve/gve_rx.c
@@ -418,8 +418,6 @@
 	rx->cnt = cnt;
 	rx->fill_cnt += work_done;
 
-	/* restock desc ring slots */
-	dma_wmb();	/* Ensure descs are visible before ringing doorbell */
 	gve_rx_write_doorbell(priv, rx);
 	return gve_rx_work_pending(rx);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/google/gve/gve_tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/google/gve/gve_tx.c
@@ -207,10 +207,12 @@
 		goto abort_with_info;
 
 	tx->tx_fifo.qpl = gve_assign_tx_qpl(priv);
+	if (!tx->tx_fifo.qpl)
+		goto abort_with_desc;
 
 	/* map Tx FIFO */
 	if (gve_tx_fifo_init(priv, &tx->tx_fifo))
-		goto abort_with_desc;
+		goto abort_with_qpl;
 
 	tx->q_resources =
 		dma_alloc_coherent(hdev,
@@ -229,6 +231,8 @@
 
 abort_with_fifo:
 	gve_tx_fifo_release(priv, &tx->tx_fifo);
+abort_with_qpl:
+	gve_unassign_qpl(priv, tx->tx_fifo.qpl->id);
 abort_with_desc:
 	dma_free_coherent(hdev, bytes, tx->desc, tx->bus);
 	tx->desc = NULL;
@@ -478,7 +482,7 @@
 	struct gve_tx_ring *tx;
 	int nsegs;
 
-	WARN(skb_get_queue_mapping(skb) > priv->tx_cfg.num_queues,
+	WARN(skb_get_queue_mapping(skb) >= priv->tx_cfg.num_queues,
 	     "skb queue index out of range");
 	tx = &priv->tx[skb_get_queue_mapping(skb)];
 	if (unlikely(gve_maybe_stop_tx(tx, skb))) {
@@ -487,10 +491,6 @@
 		 * may have added descriptors without ringing the doorbell.
 		 */
 
-		/* Ensure tx descs from a prior gve_tx are visible before
-		 * ringing doorbell.
-		 */
-		dma_wmb();
 		gve_tx_put_doorbell(priv, tx->q_resources, tx->req);
 		return NETDEV_TX_BUSY;
 	}
@@ -505,8 +505,6 @@
 	if (!netif_xmit_stopped(tx->netdev_txq) && netdev_xmit_more())
 		return NETDEV_TX_OK;
 
-	/* Ensure tx descs are visible before ringing doorbell */
-	dma_wmb();
 	gve_tx_put_doorbell(priv, tx->q_resources, tx->req);
 	return NETDEV_TX_OK;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -131,7 +131,7 @@
 /* buf unit size is cache_line_size, which is 64, so the shift is 6 */
 #define PPE_BUF_SIZE_SHIFT		6
 #define PPE_TX_BUF_HOLD			BIT(31)
-#define CACHE_LINE_MASK			0x3F
+#define SOC_CACHE_LINE_MASK		0x3F
 #else
 #define PPE_CFG_QOS_VMID_GRP_SHIFT	8
 #define PPE_CFG_RX_CTRL_ALIGN_SHIFT	11
@@ -531,8 +531,8 @@
 #if defined(CONFIG_HI13X1_GMAC)
 	desc->cfg = (__force u32)cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV
 		| TX_RELEASE_TO_PPE | priv->port << TX_POOL_SHIFT);
-	desc->data_offset = (__force u32)cpu_to_be32(phys & CACHE_LINE_MASK);
-	desc->send_addr =  (__force u32)cpu_to_be32(phys & ~CACHE_LINE_MASK);
+	desc->data_offset = (__force u32)cpu_to_be32(phys & SOC_CACHE_LINE_MASK);
+	desc->send_addr =  (__force u32)cpu_to_be32(phys & ~SOC_CACHE_LINE_MASK);
 #else
 	desc->cfg = (__force u32)cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV);
 	desc->send_addr = (__force u32)cpu_to_be32(phys);
@@ -543,9 +543,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++;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hisi_femac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hisi_femac.c
@@ -283,7 +283,7 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		napi_gro_receive(&priv->napi, skb);
 		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += skb->len;
+		dev->stats.rx_bytes += len;
 next:
 		pos = (pos + 1) % rxq->num;
 		if (rx_pkts_num >= limit)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -550,7 +550,7 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		napi_gro_receive(&priv->napi, skb);
 		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += skb->len;
+		dev->stats.rx_bytes += len;
 next:
 		pos = dma_ring_incr(pos, RX_DESC_NUM);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns/hnae.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns/hnae.c
@@ -419,8 +419,10 @@
 	hdev->cls_dev.release = hnae_release;
 	(void)dev_set_name(&hdev->cls_dev, "hnae%d", hdev->id);
 	ret = device_register(&hdev->cls_dev);
-	if (ret)
+	if (ret) {
+		put_device(&hdev->cls_dev);
 		return ret;
+	}
 
 	__module_get(THIS_MODULE);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -66,6 +66,27 @@
 	}
 }
 
+static u32 hns_mac_link_anti_shake(struct mac_driver *mac_ctrl_drv)
+{
+#define HNS_MAC_LINK_WAIT_TIME 5
+#define HNS_MAC_LINK_WAIT_CNT 40
+
+	u32 link_status = 0;
+	int i;
+
+	if (!mac_ctrl_drv->get_link_status)
+		return link_status;
+
+	for (i = 0; i < HNS_MAC_LINK_WAIT_CNT; i++) {
+		msleep(HNS_MAC_LINK_WAIT_TIME);
+		mac_ctrl_drv->get_link_status(mac_ctrl_drv, &link_status);
+		if (!link_status)
+			break;
+	}
+
+	return link_status;
+}
+
 void hns_mac_get_link_status(struct hns_mac_cb *mac_cb, u32 *link_status)
 {
 	struct mac_driver *mac_ctrl_drv;
@@ -83,6 +104,14 @@
 							       &sfp_prsnt);
 		if (!ret)
 			*link_status = *link_status && sfp_prsnt;
+
+		/* for FIBER port, it may have a fake link up.
+		 * when the link status changes from down to up, we need to do
+		 * anti-shake. the anti-shake time is base on tests.
+		 * only FIBER port need to do this.
+		 */
+		if (*link_status && !mac_cb->link)
+			*link_status = hns_mac_link_anti_shake(mac_ctrl_drv);
 	}
 
 	mac_cb->link = *link_status;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -398,6 +398,10 @@
 		return;
 
 	if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
+		/* DSAF_MAX_PORT_NUM is 6, but DSAF_GE_NUM is 8.
+		   We need check to prevent array overflow */
+		if (port >= DSAF_MAX_PORT_NUM)
+			return;
 		reg_val_1  = 0x1 << port;
 		port_rst_off = dsaf_dev->mac_cb[port]->port_rst_off;
 		/* there is difference between V1 and V2 in register.*/
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -565,7 +565,6 @@
 	skb = *out_skb = napi_alloc_skb(&ring_data->napi,
 					HNS_RX_HEAD_SIZE);
 	if (unlikely(!skb)) {
-		netdev_err(ndev, "alloc rx skb fail\n");
 		ring->stats.sw_err_cnt++;
 		return -ENOMEM;
 	}
@@ -1056,7 +1055,6 @@
 		container_of(napi, struct hns_nic_ring_data, napi);
 	struct hnae_ring *ring = ring_data->ring;
 
-try_again:
 	clean_complete += ring_data->poll_one(
 				ring_data, budget - clean_complete,
 				ring_data->ex_process);
@@ -1066,7 +1064,7 @@
 			napi_complete(napi);
 			ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
 		} else {
-			goto try_again;
+			return budget;
 		}
 	}
 
@@ -1679,8 +1677,10 @@
 			for (j = 0; j < fetch_num; j++) {
 				/* alloc one skb and init */
 				skb = hns_assemble_skb(ndev);
-				if (!skb)
+				if (!skb) {
+					ret = -ENOMEM;
 					goto out;
+				}
 				rd = &tx_ring_data(priv, skb->queue_mapping);
 				hns_nic_net_xmit_hw(ndev, skb, rd);
 
@@ -2298,8 +2298,10 @@
 			priv->enet_ver = AE_VERSION_1;
 		else if (acpi_dev_found(hns_enet_acpi_match[1].id))
 			priv->enet_ver = AE_VERSION_2;
-		else
-			return -ENXIO;
+		else {
+			ret = -ENXIO;
+			goto out_read_prop_fail;
+		}
 
 		/* try to find port-idx-in-ae first */
 		ret = acpi_node_get_property_reference(dev->fwnode,
@@ -2315,7 +2317,8 @@
 		priv->fwnode = args.fwnode;
 	} else {
 		dev_err(dev, "cannot read cfg data from OF or acpi\n");
-		return -ENXIO;
+		ret = -ENXIO;
+		goto out_read_prop_fail;
 	}
 
 	ret = device_property_read_u32(dev, "port-idx-in-ae", &port_id);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -415,6 +415,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;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/Makefile
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/Makefile
@@ -3,6 +3,8 @@
 # Makefile for the HISILICON network device drivers.
 #
 
+ccflags-y += -I$(srctree)/$(src)
+
 obj-$(CONFIG_HNS3) += hns3pf/
 obj-$(CONFIG_HNS3) += hns3vf/
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -45,8 +45,10 @@
 	HCLGE_MBX_GET_LINK_MODE,	/* (VF -> PF) get the link mode of pf */
 	HCLGE_MBX_PUSH_VLAN_INFO,	/* (PF -> VF) push port base vlan */
 	HCLGE_MBX_GET_MEDIA_TYPE,       /* (VF -> PF) get media type */
+	HCLGE_MBX_PUSH_PROMISC_INFO,	/* (PF -> VF) push vf promisc info */
+	HCLGE_MBX_VF_UNINIT,            /* (VF -> PF) vf is unintializing */
 
-	HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */
+	HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */
 	HCLGE_MBX_PUSH_LINK_STATUS,	/* (M7 -> PF) get port link status */
 	HCLGE_MBX_NCSI_ERROR,		/* (M7 -> PF) receive a NCSI error */
 };
@@ -71,7 +73,7 @@
 };
 
 #define HCLGE_MBX_MAX_MSG_SIZE	16
-#define HCLGE_MBX_MAX_RESP_DATA_SIZE	8
+#define HCLGE_MBX_MAX_RESP_DATA_SIZE	8U
 #define HCLGE_MBX_RING_MAP_BASIC_MSG_NUM	3
 #define HCLGE_MBX_RING_NODE_VARIABLE_NUM	3
 
@@ -123,7 +125,7 @@
 #define hclge_mbx_ring_ptr_move_crq(crq) \
 	(crq->next_to_use = (crq->next_to_use + 1) % crq->desc_num)
 #define hclge_mbx_tail_ptr_move_arq(arq) \
-	(arq.tail = (arq.tail + 1) % HCLGE_MBX_MAX_ARQ_MSG_SIZE)
+		(arq.tail = (arq.tail + 1) % HCLGE_MBX_MAX_ARQ_MSG_NUM)
 #define hclge_mbx_head_ptr_move_arq(arq) \
-		(arq.head = (arq.head + 1) % HCLGE_MBX_MAX_ARQ_MSG_SIZE)
+		(arq.head = (arq.head + 1) % HCLGE_MBX_MAX_ARQ_MSG_NUM)
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hnae3.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -10,6 +10,27 @@
 static LIST_HEAD(hnae3_client_list);
 static LIST_HEAD(hnae3_ae_dev_list);
 
+void hnae3_unregister_ae_algo_prepare(struct hnae3_ae_algo *ae_algo)
+{
+	const struct pci_device_id *pci_id;
+	struct hnae3_ae_dev *ae_dev;
+
+	if (!ae_algo)
+		return;
+
+	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
+		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
+			continue;
+
+		pci_id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
+		if (!pci_id)
+			continue;
+		if (IS_ENABLED(CONFIG_PCI_IOV))
+			pci_disable_sriov(ae_dev->pdev);
+	}
+}
+EXPORT_SYMBOL(hnae3_unregister_ae_algo_prepare);
+
 /* we are keeping things simple and using single lock for all the
  * list. This is a non-critical code so other updations, if happen
  * in parallel, can wait.
@@ -146,7 +167,7 @@
 		return;
 
 	mutex_lock(&hnae3_common_lock);
-
+	/* one system should only have one client for every type */
 	list_for_each_entry(client_tmp, &hnae3_client_list, node) {
 		if (client_tmp->type == client->type) {
 			existed = true;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -77,6 +77,7 @@
 	((ring)->p = ((ring)->p - 1 + (ring)->desc_num) % (ring)->desc_num)
 
 enum hns_desc_type {
+	DESC_TYPE_UNKNOWN,
 	DESC_TYPE_SKB,
 	DESC_TYPE_PAGE,
 };
@@ -130,7 +131,6 @@
 	HNAE3_MODULE_TYPE_CR		= 0x04,
 	HNAE3_MODULE_TYPE_KR		= 0x05,
 	HNAE3_MODULE_TYPE_TP		= 0x06,
-
 };
 
 enum hnae3_fec_mode {
@@ -165,11 +165,7 @@
 	HNAE3_IMP_RESET,
 	HNAE3_UNKNOWN_RESET,
 	HNAE3_NONE_RESET,
-};
-
-enum hnae3_flr_state {
-	HNAE3_FLR_DOWN,
-	HNAE3_FLR_DONE,
+	HNAE3_MAX_RESET,
 };
 
 enum hnae3_port_base_vlan_state {
@@ -366,6 +362,19 @@
  *   Enable/disable HW GRO
  * add_arfs_entry
  *   Check the 5-tuples of flow, and create flow director rule
+ * get_vf_config
+ *   Get the VF configuration setting by the host
+ * set_vf_link_state
+ *   Set VF link status
+ * set_vf_spoofchk
+ *   Enable/disable spoof check for specified vf
+ * set_vf_trust
+ *   Enable/disable trust for specified vf, if the vf being trusted, then
+ *   it can enable promisc mode
+ * set_vf_rate
+ *   Set the max tx rate of specified vf.
+ * set_vf_mac
+ *   Configure the default MAC for specified VF
  */
 struct hnae3_ae_ops {
 	int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -531,6 +540,16 @@
 	int (*mac_connect_phy)(struct hnae3_handle *handle);
 	void (*mac_disconnect_phy)(struct hnae3_handle *handle);
 	void (*restore_vlan_table)(struct hnae3_handle *handle);
+	int (*get_vf_config)(struct hnae3_handle *handle, int vf,
+			     struct ifla_vf_info *ivf);
+	int (*set_vf_link_state)(struct hnae3_handle *handle, int vf,
+				 int link_state);
+	int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf,
+			       bool enable);
+	int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable);
+	int (*set_vf_rate)(struct hnae3_handle *handle, int vf,
+			   int min_tx_rate, int max_tx_rate, bool force);
+	int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p);
 };
 
 struct hnae3_dcb_ops {
@@ -553,7 +572,7 @@
 	const struct pci_device_id *pdev_id_table;
 };
 
-#define HNAE3_INT_NAME_LEN        (IFNAMSIZ + 16)
+#define HNAE3_INT_NAME_LEN        32
 #define HNAE3_ITR_COUNTDOWN_START 100
 
 struct hnae3_tc_info {
@@ -665,6 +684,7 @@
 int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
 void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
 
+void hnae3_unregister_ae_algo_prepare(struct hnae3_ae_algo *ae_algo);
 void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo);
 void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
@@ -16,15 +16,14 @@
 			       const char *cmd_buf)
 {
 	struct hns3_nic_priv *priv = h->priv;
-	struct hns3_nic_ring_data *ring_data;
 	struct hns3_enet_ring *ring;
 	u32 base_add_l, base_add_h;
 	u32 queue_num, queue_max;
 	u32 value, i = 0;
 	int cnt;
 
-	if (!priv->ring_data) {
-		dev_err(&h->pdev->dev, "ring_data is NULL\n");
+	if (!priv->ring) {
+		dev_err(&h->pdev->dev, "priv->ring is NULL\n");
 		return -EFAULT;
 	}
 
@@ -44,7 +43,6 @@
 		return -EINVAL;
 	}
 
-	ring_data = priv->ring_data;
 	for (i = queue_num; i < queue_max; i++) {
 		/* Each cycle needs to determine whether the instance is reset,
 		 * to prevent reference to invalid memory. And need to ensure
@@ -54,73 +52,73 @@
 		    test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
 			return -EPERM;
 
-		ring = ring_data[(u32)(i + h->kinfo.num_tqps)].ring;
+		ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)];
 		base_add_h = readl_relaxed(ring->tqp->io_base +
 					   HNS3_RING_RX_RING_BASEADDR_H_REG);
 		base_add_l = readl_relaxed(ring->tqp->io_base +
 					   HNS3_RING_RX_RING_BASEADDR_L_REG);
-		dev_info(&h->pdev->dev, "RX(%d) BASE ADD: 0x%08x%08x\n", i,
+		dev_info(&h->pdev->dev, "RX(%u) BASE ADD: 0x%08x%08x\n", i,
 			 base_add_h, base_add_l);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_BD_NUM_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING BD NUM: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING BD NUM: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_BD_LEN_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING BD LEN: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING BD LEN: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_TAIL_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING TAIL: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING TAIL: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_HEAD_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING HEAD: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING HEAD: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_FBDNUM_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING FBDNUM: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING FBDNUM: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_RX_RING_PKTNUM_RECORD_REG);
-		dev_info(&h->pdev->dev, "RX(%d) RING PKTNUM: %u\n", i, value);
+		dev_info(&h->pdev->dev, "RX(%u) RING PKTNUM: %u\n", i, value);
 
-		ring = ring_data[i].ring;
+		ring = &priv->ring[i];
 		base_add_h = readl_relaxed(ring->tqp->io_base +
 					   HNS3_RING_TX_RING_BASEADDR_H_REG);
 		base_add_l = readl_relaxed(ring->tqp->io_base +
 					   HNS3_RING_TX_RING_BASEADDR_L_REG);
-		dev_info(&h->pdev->dev, "TX(%d) BASE ADD: 0x%08x%08x\n", i,
+		dev_info(&h->pdev->dev, "TX(%u) BASE ADD: 0x%08x%08x\n", i,
 			 base_add_h, base_add_l);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_BD_NUM_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING BD NUM: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING BD NUM: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_TC_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING TC: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING TC: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_TAIL_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING TAIL: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING TAIL: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_HEAD_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING HEAD: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING HEAD: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_FBDNUM_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING FBDNUM: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING FBDNUM: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_OFFSET_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING OFFSET: %u\n", i, value);
+		dev_info(&h->pdev->dev, "TX(%u) RING OFFSET: %u\n", i, value);
 
 		value = readl_relaxed(ring->tqp->io_base +
 				      HNS3_RING_TX_RING_PKTNUM_RECORD_REG);
-		dev_info(&h->pdev->dev, "TX(%d) RING PKTNUM: %u\n\n", i,
+		dev_info(&h->pdev->dev, "TX(%u) RING PKTNUM: %u\n\n", i,
 			 value);
 	}
 
@@ -130,7 +128,6 @@
 static int hns3_dbg_queue_map(struct hnae3_handle *h)
 {
 	struct hns3_nic_priv *priv = h->priv;
-	struct hns3_nic_ring_data *ring_data;
 	int i;
 
 	if (!h->ae_algo->ops->get_global_queue_id)
@@ -143,15 +140,12 @@
 		u16 global_qid;
 
 		global_qid = h->ae_algo->ops->get_global_queue_id(h, i);
-		ring_data = &priv->ring_data[i];
-		if (!ring_data || !ring_data->ring ||
-		    !ring_data->ring->tqp_vector)
+		if (!priv->ring || !priv->ring[i].tqp_vector)
 			continue;
 
 		dev_info(&h->pdev->dev,
 			 "      %4d            %4d            %4d\n",
-			 i, global_qid,
-			 ring_data->ring->tqp_vector->vector_irq);
+			 i, global_qid, priv->ring[i].tqp_vector->vector_irq);
 	}
 
 	return 0;
@@ -160,7 +154,6 @@
 static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf)
 {
 	struct hns3_nic_priv *priv = h->priv;
-	struct hns3_nic_ring_data *ring_data;
 	struct hns3_desc *rx_desc, *tx_desc;
 	struct device *dev = &h->pdev->dev;
 	struct hns3_enet_ring *ring;
@@ -183,8 +176,7 @@
 		return -EINVAL;
 	}
 
-	ring_data = priv->ring_data;
-	ring  = ring_data[q_num].ring;
+	ring = &priv->ring[q_num];
 	value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG);
 	tx_index = (cnt == 1) ? value : tx_index;
 
@@ -198,39 +190,46 @@
 	addr = le64_to_cpu(tx_desc->addr);
 	dev_info(dev, "TX Queue Num: %u, BD Index: %u\n", q_num, tx_index);
 	dev_info(dev, "(TX)addr: %pad\n", &addr);
-	dev_info(dev, "(TX)vlan_tag: %u\n", tx_desc->tx.vlan_tag);
-	dev_info(dev, "(TX)send_size: %u\n", tx_desc->tx.send_size);
+	dev_info(dev, "(TX)vlan_tag: %u\n", le16_to_cpu(tx_desc->tx.vlan_tag));
+	dev_info(dev, "(TX)send_size: %u\n",
+		 le16_to_cpu(tx_desc->tx.send_size));
 	dev_info(dev, "(TX)vlan_tso: %u\n", tx_desc->tx.type_cs_vlan_tso);
 	dev_info(dev, "(TX)l2_len: %u\n", tx_desc->tx.l2_len);
 	dev_info(dev, "(TX)l3_len: %u\n", tx_desc->tx.l3_len);
 	dev_info(dev, "(TX)l4_len: %u\n", tx_desc->tx.l4_len);
-	dev_info(dev, "(TX)vlan_tag: %u\n", tx_desc->tx.outer_vlan_tag);
-	dev_info(dev, "(TX)tv: %u\n", tx_desc->tx.tv);
+	dev_info(dev, "(TX)vlan_tag: %u\n",
+		 le16_to_cpu(tx_desc->tx.outer_vlan_tag));
+	dev_info(dev, "(TX)tv: %u\n", le16_to_cpu(tx_desc->tx.tv));
 	dev_info(dev, "(TX)vlan_msec: %u\n", tx_desc->tx.ol_type_vlan_msec);
 	dev_info(dev, "(TX)ol2_len: %u\n", tx_desc->tx.ol2_len);
 	dev_info(dev, "(TX)ol3_len: %u\n", tx_desc->tx.ol3_len);
 	dev_info(dev, "(TX)ol4_len: %u\n", tx_desc->tx.ol4_len);
-	dev_info(dev, "(TX)paylen: %u\n", tx_desc->tx.paylen);
-	dev_info(dev, "(TX)vld_ra_ri: %u\n", tx_desc->tx.bdtp_fe_sc_vld_ra_ri);
-	dev_info(dev, "(TX)mss: %u\n", tx_desc->tx.mss);
+	dev_info(dev, "(TX)paylen: %u\n", le32_to_cpu(tx_desc->tx.paylen));
+	dev_info(dev, "(TX)vld_ra_ri: %u\n",
+		 le16_to_cpu(tx_desc->tx.bdtp_fe_sc_vld_ra_ri));
+	dev_info(dev, "(TX)mss: %u\n", le16_to_cpu(tx_desc->tx.mss));
 
-	ring  = ring_data[q_num + h->kinfo.num_tqps].ring;
+	ring = &priv->ring[q_num + h->kinfo.num_tqps];
 	value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG);
 	rx_index = (cnt == 1) ? value : tx_index;
-	rx_desc	 = &ring->desc[rx_index];
+	rx_desc = &ring->desc[rx_index];
 
 	addr = le64_to_cpu(rx_desc->addr);
 	dev_info(dev, "RX Queue Num: %u, BD Index: %u\n", q_num, rx_index);
 	dev_info(dev, "(RX)addr: %pad\n", &addr);
-	dev_info(dev, "(RX)l234_info: %u\n", rx_desc->rx.l234_info);
-	dev_info(dev, "(RX)pkt_len: %u\n", rx_desc->rx.pkt_len);
-	dev_info(dev, "(RX)size: %u\n", rx_desc->rx.size);
-	dev_info(dev, "(RX)rss_hash: %u\n", rx_desc->rx.rss_hash);
-	dev_info(dev, "(RX)fd_id: %u\n", rx_desc->rx.fd_id);
-	dev_info(dev, "(RX)vlan_tag: %u\n", rx_desc->rx.vlan_tag);
-	dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n", rx_desc->rx.o_dm_vlan_id_fb);
-	dev_info(dev, "(RX)ot_vlan_tag: %u\n", rx_desc->rx.ot_vlan_tag);
-	dev_info(dev, "(RX)bd_base_info: %u\n", rx_desc->rx.bd_base_info);
+	dev_info(dev, "(RX)l234_info: %u\n",
+		 le32_to_cpu(rx_desc->rx.l234_info));
+	dev_info(dev, "(RX)pkt_len: %u\n", le16_to_cpu(rx_desc->rx.pkt_len));
+	dev_info(dev, "(RX)size: %u\n", le16_to_cpu(rx_desc->rx.size));
+	dev_info(dev, "(RX)rss_hash: %u\n", le32_to_cpu(rx_desc->rx.rss_hash));
+	dev_info(dev, "(RX)fd_id: %u\n", le16_to_cpu(rx_desc->rx.fd_id));
+	dev_info(dev, "(RX)vlan_tag: %u\n", le16_to_cpu(rx_desc->rx.vlan_tag));
+	dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n",
+		 le16_to_cpu(rx_desc->rx.o_dm_vlan_id_fb));
+	dev_info(dev, "(RX)ot_vlan_tag: %u\n",
+		 le16_to_cpu(rx_desc->rx.ot_vlan_tag));
+	dev_info(dev, "(RX)bd_base_info: %u\n",
+		 le32_to_cpu(rx_desc->rx.bd_base_info));
 
 	return 0;
 }
@@ -261,6 +260,8 @@
 	dev_info(&h->pdev->dev, "dump m7 info\n");
 	dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n");
 	dev_info(&h->pdev->dev, "dump mac tnl status\n");
+	dev_info(&h->pdev->dev, "dump loopback\n");
+	dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n");
 
 	memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
 	strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]",
@@ -298,8 +299,8 @@
 	if (!buf)
 		return -ENOMEM;
 
-	len = snprintf(buf, HNS3_DBG_READ_LEN, "%s\n",
-		       "Please echo help to cmd to get help information");
+	len = scnprintf(buf, HNS3_DBG_READ_LEN, "%s\n",
+			"Please echo help to cmd to get help information");
 	uncopy_bytes = copy_to_user(buffer, buf, len);
 
 	kfree(buf);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -21,9 +21,16 @@
 #include <net/pkt_cls.h>
 #include <net/tcp.h>
 #include <net/vxlan.h>
+#include <net/geneve.h>
 
 #include "hnae3.h"
 #include "hns3_enet.h"
+/* All hns3 tracepoints are defined by the include below, which
+ * must be included exactly once across the whole kernel with
+ * CREATE_TRACE_POINTS defined
+ */
+#define CREATE_TRACE_POINTS
+#include "hns3_trace.h"
 
 #define hns3_set_field(origin, shift, val)	((origin) |= ((val) << (shift)))
 #define hns3_tx_bd_count(S)	DIV_ROUND_UP(S, HNS3_MAX_BD_SIZE)
@@ -54,6 +61,9 @@
 #define HNS3_INNER_VLAN_TAG	1
 #define HNS3_OUTER_VLAN_TAG	2
 
+#define HNS3_MIN_TX_LEN		33U
+#define HNS3_MIN_TUN_PKT_LEN	65U
+
 /* hns3_pci_tbl - PCI Device ID Table
  *
  * Last entry must be all 0s
@@ -127,18 +137,21 @@
 			continue;
 
 		if (tqp_vectors->tx_group.ring && tqp_vectors->rx_group.ring) {
-			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN - 1,
-				 "%s-%s-%d", priv->netdev->name, "TxRx",
-				 txrx_int_idx++);
+			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN,
+				 "%s-%s-%s-%d", hns3_driver_name,
+				 pci_name(priv->ae_handle->pdev),
+				 "TxRx", txrx_int_idx++);
 			txrx_int_idx++;
 		} else if (tqp_vectors->rx_group.ring) {
-			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN - 1,
-				 "%s-%s-%d", priv->netdev->name, "Rx",
-				 rx_int_idx++);
+			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN,
+				 "%s-%s-%s-%d", hns3_driver_name,
+				 pci_name(priv->ae_handle->pdev),
+				 "Rx", rx_int_idx++);
 		} else if (tqp_vectors->tx_group.ring) {
-			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN - 1,
-				 "%s-%s-%d", priv->netdev->name, "Tx",
-				 tx_int_idx++);
+			snprintf(tqp_vectors->name, HNAE3_INT_NAME_LEN,
+				 "%s-%s-%s-%d", hns3_driver_name,
+				 pci_name(priv->ae_handle->pdev),
+				 "Tx", tx_int_idx++);
 		} else {
 			/* Skip this unused q_vector */
 			continue;
@@ -155,6 +168,8 @@
 			return ret;
 		}
 
+		disable_irq(tqp_vectors->vector_irq);
+
 		irq_set_affinity_hint(tqp_vectors->vector_irq,
 				      &tqp_vectors->affinity_mask);
 
@@ -173,6 +188,7 @@
 static void hns3_vector_enable(struct hns3_enet_tqp_vector *tqp_vector)
 {
 	napi_enable(&tqp_vector->napi);
+	enable_irq(tqp_vector->vector_irq);
 
 	/* enable vector */
 	hns3_mask_vector_irq(tqp_vector, 1);
@@ -372,18 +388,6 @@
 	if (ret)
 		return ret;
 
-	/* the device can work without cpu rmap, only aRFS needs it */
-	ret = hns3_set_rx_cpu_rmap(netdev);
-	if (ret)
-		netdev_warn(netdev, "set rx cpu rmap fail, ret=%d!\n", ret);
-
-	/* get irq resource for all vectors */
-	ret = hns3_nic_init_irq(priv);
-	if (ret) {
-		netdev_err(netdev, "init irq failed! ret=%d\n", ret);
-		goto free_rmap;
-	}
-
 	clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
 
 	/* enable the vectors */
@@ -396,22 +400,15 @@
 
 	/* start the ae_dev */
 	ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
-	if (ret)
-		goto out_start_err;
-
-	return 0;
-
-out_start_err:
-	set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
-	while (j--)
-		hns3_tqp_disable(h->kinfo.tqp[j]);
+	if (ret) {
+		set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
+		while (j--)
+			hns3_tqp_disable(h->kinfo.tqp[j]);
 
-	for (j = i - 1; j >= 0; j--)
-		hns3_vector_disable(&priv->tqp_vector[j]);
+		for (j = i - 1; j >= 0; j--)
+			hns3_vector_disable(&priv->tqp_vector[j]);
+	}
 
-	hns3_nic_uninit_irq(priv);
-free_rmap:
-	hns3_free_rx_cpu_rmap(netdev);
 	return ret;
 }
 
@@ -448,6 +445,11 @@
 	if (hns3_nic_resetting(netdev))
 		return -EBUSY;
 
+	if (!test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
+		netdev_warn(netdev, "net open repeatedly!\n");
+		return 0;
+	}
+
 	netif_carrier_off(netdev);
 
 	ret = hns3_nic_set_real_num_queue(netdev);
@@ -483,7 +485,7 @@
 
 	for (i = 0; i < h->kinfo.num_tqps; i++) {
 		dev_queue = netdev_get_tx_queue(ndev,
-						priv->ring_data[i].queue_index);
+						priv->ring[i].queue_index);
 		netdev_tx_reset_queue(dev_queue);
 	}
 }
@@ -508,11 +510,6 @@
 	if (ops->stop)
 		ops->stop(priv->ae_handle);
 
-	hns3_free_rx_cpu_rmap(netdev);
-
-	/* free irq resources */
-	hns3_nic_uninit_irq(priv);
-
 	/* delay ring buffer clearing to hns3_reset_notify_uninit_enet
 	 * during reset process, because driver may not be able
 	 * to disable the ring through firmware when downing the netdev.
@@ -536,8 +533,8 @@
 	if (h->ae_algo->ops->set_timer_task)
 		h->ae_algo->ops->set_timer_task(priv->ae_handle, false);
 
-	netif_tx_stop_all_queues(netdev);
 	netif_carrier_off(netdev);
+	netif_tx_disable(netdev);
 
 	hns3_nic_net_down(netdev);
 
@@ -681,7 +678,7 @@
 		return 0;
 
 	ret = skb_cow_head(skb, 0);
-	if (unlikely(ret))
+	if (unlikely(ret < 0))
 		return ret;
 
 	l3.hdr = skb_network_header(skb);
@@ -734,6 +731,8 @@
 	/* get MSS for TSO */
 	*mss = skb_shinfo(skb)->gso_size;
 
+	trace_hns3_tso(skb);
+
 	return 0;
 }
 
@@ -793,7 +792,7 @@
  * and it is udp packet, which has a dest port as the IANA assigned.
  * the hardware is expected to do the checksum offload, but the
  * hardware will not do the checksum offload when udp dest port is
- * 4789.
+ * 4789, 4790 or 6081.
  */
 static bool hns3_tunnel_csum_bug(struct sk_buff *skb)
 {
@@ -802,11 +801,11 @@
 	l4.hdr = skb_transport_header(skb);
 
 	if (!(!skb->encapsulation &&
-	      l4.udp->dest == htons(IANA_VXLAN_UDP_PORT)))
+	      (l4.udp->dest == htons(IANA_VXLAN_UDP_PORT) ||
+	      l4.udp->dest == htons(GENEVE_UDP_PORT) ||
+	      l4.udp->dest == htons(4790))))
 		return false;
 
-	skb_checksum_help(skb);
-
 	return true;
 }
 
@@ -884,8 +883,7 @@
 			/* the stack computes the IP header already,
 			 * driver calculate l4 checksum when not TSO.
 			 */
-			skb_checksum_help(skb);
-			return 0;
+			return skb_checksum_help(skb);
 		}
 
 		hns3_set_outer_l2l3l4(skb, ol4_proto, ol_type_vlan_len_msec);
@@ -929,8 +927,11 @@
 			       l4.tcp->doff);
 		break;
 	case IPPROTO_UDP:
-		if (hns3_tunnel_csum_bug(skb))
-			break;
+		if (hns3_tunnel_csum_bug(skb)) {
+			int ret = skb_put_padto(skb, HNS3_MIN_TUN_PKT_LEN);
+
+			return ret ? ret : skb_checksum_help(skb);
+		}
 
 		hns3_set_field(*type_cs_vlan_tso, HNS3_TXD_L4CS_B, 1);
 		hns3_set_field(*type_cs_vlan_tso, HNS3_TXD_L4T_S,
@@ -955,21 +956,12 @@
 		/* the stack computes the IP header already,
 		 * driver calculate l4 checksum when not TSO.
 		 */
-		skb_checksum_help(skb);
-		return 0;
+		return skb_checksum_help(skb);
 	}
 
 	return 0;
 }
 
-static void hns3_set_txbd_baseinfo(u16 *bdtp_fe_sc_vld_ra_ri, int frag_end)
-{
-	/* Config bd buffer end */
-	if (!!frag_end)
-		hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, 1U);
-	hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1U);
-}
-
 static int hns3_handle_vtags(struct hns3_enet_ring *tx_ring,
 			     struct sk_buff *skb)
 {
@@ -1062,7 +1054,7 @@
 		skb_reset_mac_len(skb);
 
 		ret = hns3_get_l4_protocol(skb, &ol4_proto, &il4_proto);
-		if (unlikely(ret)) {
+		if (unlikely(ret < 0)) {
 			u64_stats_update_begin(&ring->syncp);
 			ring->stats.tx_l4_proto_err++;
 			u64_stats_update_end(&ring->syncp);
@@ -1072,7 +1064,7 @@
 		ret = hns3_set_l2l3l4(skb, ol4_proto, il4_proto,
 				      &type_cs_vlan_tso,
 				      &ol_type_vlan_len_msec);
-		if (unlikely(ret)) {
+		if (unlikely(ret < 0)) {
 			u64_stats_update_begin(&ring->syncp);
 			ring->stats.tx_l2l3l4_err++;
 			u64_stats_update_end(&ring->syncp);
@@ -1081,7 +1073,7 @@
 
 		ret = hns3_set_tso(skb, &paylen, &mss,
 				   &type_cs_vlan_tso);
-		if (unlikely(ret)) {
+		if (unlikely(ret < 0)) {
 			u64_stats_update_begin(&ring->syncp);
 			ring->stats.tx_tso_err++;
 			u64_stats_update_end(&ring->syncp);
@@ -1102,9 +1094,10 @@
 }
 
 static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
-			  unsigned int size, int frag_end,
-			  enum hns_desc_type type)
+			  unsigned int size, enum hns_desc_type type)
 {
+#define HNS3_LIKELY_BD_NUM	1
+
 	struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
 	struct hns3_desc *desc = &ring->desc[ring->next_to_use];
 	struct device *dev = ring_to_dev(ring);
@@ -1118,7 +1111,7 @@
 		int ret;
 
 		ret = hns3_fill_skb_desc(ring, skb, desc);
-		if (unlikely(ret))
+		if (unlikely(ret < 0))
 			return ret;
 
 		dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
@@ -1137,19 +1130,17 @@
 	desc_cb->length = size;
 
 	if (likely(size <= HNS3_MAX_BD_SIZE)) {
-		u16 bdtp_fe_sc_vld_ra_ri = 0;
-
 		desc_cb->priv = priv;
 		desc_cb->dma = dma;
 		desc_cb->type = type;
 		desc->addr = cpu_to_le64(dma);
 		desc->tx.send_size = cpu_to_le16(size);
-		hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end);
 		desc->tx.bdtp_fe_sc_vld_ra_ri =
-			cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
+			cpu_to_le16(BIT(HNS3_TXD_VLD_B));
 
+		trace_hns3_tx_desc(ring, ring->next_to_use);
 		ring_ptr_move_fw(ring, next_to_use);
-		return 0;
+		return HNS3_LIKELY_BD_NUM;
 	}
 
 	frag_buf_num = hns3_tx_bd_count(size);
@@ -1158,8 +1149,6 @@
 
 	/* When frag size is bigger than hardware limit, split this frag */
 	for (k = 0; k < frag_buf_num; k++) {
-		u16 bdtp_fe_sc_vld_ra_ri = 0;
-
 		/* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
 		desc_cb->priv = priv;
 		desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k;
@@ -1170,12 +1159,10 @@
 		desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k);
 		desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ?
 				     (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE);
-		hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri,
-				       frag_end && (k == frag_buf_num - 1) ?
-						1 : 0);
 		desc->tx.bdtp_fe_sc_vld_ra_ri =
-				cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
+				cpu_to_le16(BIT(HNS3_TXD_VLD_B));
 
+		trace_hns3_tx_desc(ring, ring->next_to_use);
 		/* move ring pointer to next */
 		ring_ptr_move_fw(ring, next_to_use);
 
@@ -1183,23 +1170,78 @@
 		desc = &ring->desc[ring->next_to_use];
 	}
 
-	return 0;
+	return frag_buf_num;
 }
 
-static unsigned int hns3_nic_bd_num(struct sk_buff *skb)
+static unsigned int hns3_skb_bd_num(struct sk_buff *skb, unsigned int *bd_size,
+				    unsigned int bd_num)
 {
-	unsigned int bd_num;
+	unsigned int size;
 	int i;
 
-	/* if the total len is within the max bd limit */
-	if (likely(skb->len <= HNS3_MAX_BD_SIZE))
-		return skb_shinfo(skb)->nr_frags + 1;
+	size = skb_headlen(skb);
+	while (size > HNS3_MAX_BD_SIZE) {
+		bd_size[bd_num++] = HNS3_MAX_BD_SIZE;
+		size -= HNS3_MAX_BD_SIZE;
+
+		if (bd_num > HNS3_MAX_TSO_BD_NUM)
+			return bd_num;
+	}
 
-	bd_num = hns3_tx_bd_count(skb_headlen(skb));
+	if (size) {
+		bd_size[bd_num++] = size;
+		if (bd_num > HNS3_MAX_TSO_BD_NUM)
+			return bd_num;
+	}
 
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-		bd_num += hns3_tx_bd_count(skb_frag_size(frag));
+		size = skb_frag_size(frag);
+		if (!size)
+			continue;
+
+		while (size > HNS3_MAX_BD_SIZE) {
+			bd_size[bd_num++] = HNS3_MAX_BD_SIZE;
+			size -= HNS3_MAX_BD_SIZE;
+
+			if (bd_num > HNS3_MAX_TSO_BD_NUM)
+				return bd_num;
+		}
+
+		bd_size[bd_num++] = size;
+		if (bd_num > HNS3_MAX_TSO_BD_NUM)
+			return bd_num;
+	}
+
+	return bd_num;
+}
+
+static unsigned int hns3_tx_bd_num(struct sk_buff *skb, unsigned int *bd_size)
+{
+	struct sk_buff *frag_skb;
+	unsigned int bd_num = 0;
+
+	/* If the total len is within the max bd limit */
+	if (likely(skb->len <= HNS3_MAX_BD_SIZE && !skb_has_frag_list(skb) &&
+		   skb_shinfo(skb)->nr_frags < HNS3_MAX_NON_TSO_BD_NUM))
+		return skb_shinfo(skb)->nr_frags + 1U;
+
+	/* The below case will always be linearized, return
+	 * HNS3_MAX_BD_NUM_TSO + 1U to make sure it is linearized.
+	 */
+	if (unlikely(skb->len > HNS3_MAX_TSO_SIZE ||
+		     (!skb_is_gso(skb) && skb->len > HNS3_MAX_NON_TSO_SIZE)))
+		return HNS3_MAX_TSO_BD_NUM + 1U;
+
+	bd_num = hns3_skb_bd_num(skb, bd_size, bd_num);
+
+	if (!skb_has_frag_list(skb) || bd_num > HNS3_MAX_TSO_BD_NUM)
+		return bd_num;
+
+	skb_walk_frags(skb, frag_skb) {
+		bd_num = hns3_skb_bd_num(frag_skb, bd_size, bd_num);
+		if (bd_num > HNS3_MAX_TSO_BD_NUM)
+			return bd_num;
 	}
 
 	return bd_num;
@@ -1218,26 +1260,26 @@
  * 7 frags to to be larger than gso header len + mss, and the remaining
  * continuous 7 frags to be larger than MSS except the last 7 frags.
  */
-static bool hns3_skb_need_linearized(struct sk_buff *skb)
+static bool hns3_skb_need_linearized(struct sk_buff *skb, unsigned int *bd_size,
+				     unsigned int bd_num)
 {
-	int bd_limit = HNS3_MAX_BD_NUM_NORMAL - 1;
 	unsigned int tot_len = 0;
 	int i;
 
-	for (i = 0; i < bd_limit; i++)
-		tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
+	for (i = 0; i < HNS3_MAX_NON_TSO_BD_NUM - 1U; i++)
+		tot_len += bd_size[i];
 
-	/* ensure headlen + the first 7 frags is greater than mss + header
-	 * and the first 7 frags is greater than mss.
-	 */
-	if (((tot_len + skb_headlen(skb)) < (skb_shinfo(skb)->gso_size +
-	    hns3_gso_hdr_len(skb))) || (tot_len < skb_shinfo(skb)->gso_size))
+	/* ensure the first 8 frags is greater than mss + header */
+	if (tot_len + bd_size[HNS3_MAX_NON_TSO_BD_NUM - 1U] <
+	    skb_shinfo(skb)->gso_size + hns3_gso_hdr_len(skb))
 		return true;
 
-	/* ensure the remaining continuous 7 buffer is greater than mss */
-	for (i = 0; i < (skb_shinfo(skb)->nr_frags - bd_limit - 1); i++) {
-		tot_len -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
-		tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i + bd_limit]);
+	/* ensure every continuous 7 buffer is greater than mss
+	 * except the last one.
+	 */
+	for (i = 0; i < bd_num - HNS3_MAX_NON_TSO_BD_NUM; i++) {
+		tot_len -= bd_size[i];
+		tot_len += bd_size[i + HNS3_MAX_NON_TSO_BD_NUM - 1U];
 
 		if (tot_len < skb_shinfo(skb)->gso_size)
 			return true;
@@ -1246,31 +1288,40 @@
 	return false;
 }
 
+void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_SKB_FRAGS; i++)
+		size[i] = skb_frag_size(&shinfo->frags[i]);
+}
+
 static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
-				  struct sk_buff **out_skb)
+				  struct net_device *netdev,
+				  struct sk_buff *skb)
 {
-	struct sk_buff *skb = *out_skb;
+	struct hns3_nic_priv *priv = netdev_priv(netdev);
+	unsigned int bd_size[HNS3_MAX_TSO_BD_NUM + 1U];
 	unsigned int bd_num;
 
-	bd_num = hns3_nic_bd_num(skb);
-	if (unlikely(bd_num > HNS3_MAX_BD_NUM_NORMAL)) {
-		struct sk_buff *new_skb;
-
-		if (skb_is_gso(skb) && bd_num <= HNS3_MAX_BD_NUM_TSO &&
-		    !hns3_skb_need_linearized(skb))
+	bd_num = hns3_tx_bd_num(skb, bd_size);
+	if (unlikely(bd_num > HNS3_MAX_NON_TSO_BD_NUM)) {
+		if (bd_num <= HNS3_MAX_TSO_BD_NUM && skb_is_gso(skb) &&
+		    !hns3_skb_need_linearized(skb, bd_size, bd_num)) {
+			trace_hns3_over_8bd(skb);
 			goto out;
+		}
 
-		/* manual split the send packet */
-		new_skb = skb_copy(skb, GFP_ATOMIC);
-		if (!new_skb)
+		if (__skb_linearize(skb))
 			return -ENOMEM;
-		dev_kfree_skb_any(skb);
-		*out_skb = new_skb;
 
-		bd_num = hns3_nic_bd_num(new_skb);
-		if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_TSO) ||
-		    (!skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_NORMAL))
+		bd_num = hns3_tx_bd_count(skb->len);
+		if ((skb_is_gso(skb) && bd_num > HNS3_MAX_TSO_BD_NUM) ||
+		    (!skb_is_gso(skb) &&
+		     bd_num > HNS3_MAX_NON_TSO_BD_NUM)) {
+			trace_hns3_over_8bd(skb);
 			return -ENOMEM;
+		}
 
 		u64_stats_update_begin(&ring->syncp);
 		ring->stats.tx_copy++;
@@ -1278,10 +1329,23 @@
 	}
 
 out:
-	if (unlikely(ring_space(ring) < bd_num))
-		return -EBUSY;
+	if (likely(ring_space(ring) >= bd_num))
+		return bd_num;
 
-	return bd_num;
+	netif_stop_subqueue(netdev, ring->queue_index);
+	smp_mb(); /* Memory barrier before checking ring_space */
+
+	/* Start queue in case hns3_clean_tx_ring has just made room
+	 * available and has not seen the queue stopped state performed
+	 * by netif_stop_subqueue above.
+	 */
+	if (ring_space(ring) >= bd_num && netif_carrier_ok(netdev) &&
+	    !test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
+		netif_start_subqueue(netdev, ring->queue_index);
+		return bd_num;
+	}
+
+	return -EBUSY;
 }
 
 static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
@@ -1290,6 +1354,10 @@
 	unsigned int i;
 
 	for (i = 0; i < ring->desc_num; i++) {
+		struct hns3_desc *desc = &ring->desc[ring->next_to_use];
+
+		memset(desc, 0, sizeof(*desc));
+
 		/* check if this is where we started */
 		if (ring->next_to_use == next_to_use_orig)
 			break;
@@ -1297,6 +1365,9 @@
 		/* rollback one */
 		ring_ptr_move_bw(ring, next_to_use);
 
+		if (!ring->desc_cb[ring->next_to_use].dma)
+			continue;
+
 		/* unmap the descriptor dma address */
 		if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB)
 			dma_unmap_single(dev,
@@ -1311,76 +1382,107 @@
 
 		ring->desc_cb[ring->next_to_use].length = 0;
 		ring->desc_cb[ring->next_to_use].dma = 0;
+		ring->desc_cb[ring->next_to_use].type = DESC_TYPE_UNKNOWN;
 	}
 }
 
+static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring,
+				 struct sk_buff *skb, enum hns_desc_type type)
+{
+	unsigned int size = skb_headlen(skb);
+	int i, ret, bd_num = 0;
+
+	if (size) {
+		ret = hns3_fill_desc(ring, skb, size, type);
+		if (unlikely(ret < 0))
+			return ret;
+
+		bd_num += ret;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		size = skb_frag_size(frag);
+		if (!size)
+			continue;
+
+		ret = hns3_fill_desc(ring, frag, size, DESC_TYPE_PAGE);
+		if (unlikely(ret < 0))
+			return ret;
+
+		bd_num += ret;
+	}
+
+	return bd_num;
+}
+
 netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct hns3_nic_priv *priv = netdev_priv(netdev);
-	struct hns3_nic_ring_data *ring_data =
-		&tx_ring_data(priv, skb->queue_mapping);
-	struct hns3_enet_ring *ring = ring_data->ring;
+	struct hns3_enet_ring *ring = &priv->ring[skb->queue_mapping];
 	struct netdev_queue *dev_queue;
-	skb_frag_t *frag;
-	int next_to_use_head;
-	int buf_num;
-	int seg_num;
-	int size;
+	int pre_ntu, next_to_use_head;
+	struct sk_buff *frag_skb;
+	int bd_num = 0;
 	int ret;
-	int i;
+
+	/* Hardware can only handle short frames above 32 bytes */
+	if (skb_put_padto(skb, HNS3_MIN_TX_LEN))
+		return NETDEV_TX_OK;
 
 	/* Prefetch the data used later */
 	prefetch(skb->data);
 
-	buf_num = hns3_nic_maybe_stop_tx(ring, &skb);
-	if (unlikely(buf_num <= 0)) {
-		if (buf_num == -EBUSY) {
+	ret = hns3_nic_maybe_stop_tx(ring, netdev, skb);
+	if (unlikely(ret <= 0)) {
+		if (ret == -EBUSY) {
 			u64_stats_update_begin(&ring->syncp);
 			ring->stats.tx_busy++;
 			u64_stats_update_end(&ring->syncp);
-			goto out_net_tx_busy;
-		} else if (buf_num == -ENOMEM) {
+			return NETDEV_TX_BUSY;
+		} else if (ret == -ENOMEM) {
 			u64_stats_update_begin(&ring->syncp);
 			ring->stats.sw_err_cnt++;
 			u64_stats_update_end(&ring->syncp);
 		}
 
-		hns3_rl_err(netdev, "xmit error: %d!\n", buf_num);
+		hns3_rl_err(netdev, "xmit error: %d!\n", ret);
 		goto out_err_tx_ok;
 	}
 
-	/* No. of segments (plus a header) */
-	seg_num = skb_shinfo(skb)->nr_frags + 1;
-	/* Fill the first part */
-	size = skb_headlen(skb);
-
 	next_to_use_head = ring->next_to_use;
 
-	ret = hns3_fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0,
-			     DESC_TYPE_SKB);
-	if (unlikely(ret))
+	ret = hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB);
+	if (unlikely(ret < 0))
 		goto fill_err;
 
-	/* Fill the fragments */
-	for (i = 1; i < seg_num; i++) {
-		frag = &skb_shinfo(skb)->frags[i - 1];
-		size = skb_frag_size(frag);
+	bd_num += ret;
 
-		ret = hns3_fill_desc(ring, frag, size,
-				     seg_num - 1 == i ? 1 : 0,
-				     DESC_TYPE_PAGE);
+	if (!skb_has_frag_list(skb))
+		goto out;
 
-		if (unlikely(ret))
+	skb_walk_frags(skb, frag_skb) {
+		ret = hns3_fill_skb_to_desc(ring, frag_skb, DESC_TYPE_PAGE);
+		if (unlikely(ret < 0))
 			goto fill_err;
+
+		bd_num += ret;
 	}
+out:
+	pre_ntu = ring->next_to_use ? (ring->next_to_use - 1) :
+					(ring->desc_num - 1);
+	ring->desc[pre_ntu].tx.bdtp_fe_sc_vld_ra_ri |=
+				cpu_to_le16(BIT(HNS3_TXD_FE_B));
+	trace_hns3_tx_desc(ring, pre_ntu);
 
 	/* Complete translate all packets */
-	dev_queue = netdev_get_tx_queue(netdev, ring_data->queue_index);
+	dev_queue = netdev_get_tx_queue(netdev, ring->queue_index);
 	netdev_tx_sent_queue(dev_queue, skb->len);
 
 	wmb(); /* Commit all data before submit */
 
-	hnae3_queue_xmit(ring->tqp, buf_num);
+	hnae3_queue_xmit(ring->tqp, bd_num);
 
 	return NETDEV_TX_OK;
 
@@ -1390,12 +1492,6 @@
 out_err_tx_ok:
 	dev_kfree_skb_any(skb);
 	return NETDEV_TX_OK;
-
-out_net_tx_busy:
-	netif_stop_subqueue(netdev, ring_data->queue_index);
-	smp_mb(); /* Commit all data before submit */
-
-	return NETDEV_TX_BUSY;
 }
 
 static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p)
@@ -1413,6 +1509,16 @@
 		return 0;
 	}
 
+	/* For VF device, if there is a perm_addr, then the user will not
+	 * be allowed to change the address.
+	 */
+	if (!hns3_is_phys_func(h->pdev) &&
+	    !is_zero_ether_addr(netdev->perm_addr)) {
+		netdev_err(netdev, "has permanent MAC %pM, user MAC %pM not allow\n",
+			   netdev->perm_addr, mac_addr->sa_data);
+		return -EPERM;
+	}
+
 	ret = h->ae_algo->ops->set_mac_addr(h, mac_addr->sa_data, false);
 	if (ret) {
 		netdev_err(netdev, "set_mac_address fail, ret=%d!\n", ret);
@@ -1477,6 +1583,37 @@
 	return 0;
 }
 
+static netdev_features_t hns3_features_check(struct sk_buff *skb,
+					     struct net_device *dev,
+					     netdev_features_t features)
+{
+#define HNS3_MAX_HDR_LEN	480U
+#define HNS3_MAX_L4_HDR_LEN	60U
+
+	size_t len;
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return features;
+
+	if (skb->encapsulation)
+		len = skb_inner_transport_header(skb) - skb->data;
+	else
+		len = skb_transport_header(skb) - skb->data;
+
+	/* Assume L4 is 60 byte as TCP is the only protocol with a
+	 * a flexible value, and it's max len is 60 bytes.
+	 */
+	len += HNS3_MAX_L4_HDR_LEN;
+
+	/* Hardware only supports checksum on the skb with a max header
+	 * len of 480 bytes.
+	 */
+	if (len > HNS3_MAX_HDR_LEN)
+		features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+
+	return features;
+}
+
 static void hns3_nic_get_stats64(struct net_device *netdev,
 				 struct rtnl_link_stats64 *stats)
 {
@@ -1505,7 +1642,7 @@
 
 	for (idx = 0; idx < queue_num; idx++) {
 		/* fetch the tx stats */
-		ring = priv->ring_data[idx].ring;
+		ring = &priv->ring[idx];
 		do {
 			start = u64_stats_fetch_begin_irq(&ring->syncp);
 			tx_bytes += ring->stats.tx_bytes;
@@ -1523,7 +1660,7 @@
 		} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
 
 		/* fetch the rx stats */
-		ring = priv->ring_data[idx + queue_num].ring;
+		ring = &priv->ring[idx + queue_num];
 		do {
 			start = u64_stats_fetch_begin_irq(&ring->syncp);
 			rx_bytes += ring->stats.rx_bytes;
@@ -1590,7 +1727,7 @@
 	netif_dbg(h, drv, netdev, "setup tc: num_tc=%u\n", tc);
 
 	return (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
-		kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
+		kinfo->dcb_ops->setup_tc(h, tc ? tc : 1, prio_tc) : -EOPNOTSUPP;
 }
 
 static int hns3_nic_setup_tc(struct net_device *dev, enum tc_setup_type type,
@@ -1633,8 +1770,8 @@
 	int ret = -EIO;
 
 	netif_dbg(h, drv, netdev,
-		  "set vf vlan: vf=%d, vlan=%u, qos=%u, vlan_proto=%u\n",
-		  vf, vlan, qos, vlan_proto);
+		  "set vf vlan: vf=%d, vlan=%u, qos=%u, vlan_proto=0x%x\n",
+		  vf, vlan, qos, ntohs(vlan_proto));
 
 	if (h->ae_algo->ops->set_vf_vlan_filter)
 		ret = h->ae_algo->ops->set_vf_vlan_filter(h, vf, vlan,
@@ -1643,6 +1780,29 @@
 	return ret;
 }
 
+static int hns3_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
+{
+	struct hnae3_handle *handle = hns3_get_handle(netdev);
+
+	if (hns3_nic_resetting(netdev))
+		return -EBUSY;
+
+	if (!handle->ae_algo->ops->set_vf_spoofchk)
+		return -EOPNOTSUPP;
+
+	return handle->ae_algo->ops->set_vf_spoofchk(handle, vf, enable);
+}
+
+static int hns3_set_vf_trust(struct net_device *netdev, int vf, bool enable)
+{
+	struct hnae3_handle *handle = hns3_get_handle(netdev);
+
+	if (!handle->ae_algo->ops->set_vf_trust)
+		return -EOPNOTSUPP;
+
+	return handle->ae_algo->ops->set_vf_trust(handle, vf, enable);
+}
+
 static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
 {
 	struct hnae3_handle *h = hns3_get_handle(netdev);
@@ -1671,7 +1831,7 @@
 {
 	struct hns3_nic_priv *priv = netdev_priv(ndev);
 	struct hnae3_handle *h = hns3_get_handle(ndev);
-	struct hns3_enet_ring *tx_ring = NULL;
+	struct hns3_enet_ring *tx_ring;
 	struct napi_struct *napi;
 	int timeout_queue = 0;
 	int hw_head, hw_tail;
@@ -1692,6 +1852,9 @@
 		    time_after(jiffies,
 			       (trans_start + ndev->watchdog_timeo))) {
 			timeout_queue = i;
+			netdev_info(ndev, "queue state: 0x%lx, delta msecs: %u\n",
+				    q->state,
+				    jiffies_to_msecs(jiffies - trans_start));
 			break;
 		}
 	}
@@ -1705,7 +1868,7 @@
 
 	priv->tx_timeout_count++;
 
-	tx_ring = priv->ring_data[timeout_queue].ring;
+	tx_ring = &priv->ring[timeout_queue];
 	napi = &tx_ring->tqp_vector->napi;
 
 	netdev_info(ndev,
@@ -1805,6 +1968,57 @@
 }
 #endif
 
+static int hns3_nic_get_vf_config(struct net_device *ndev, int vf,
+				  struct ifla_vf_info *ivf)
+{
+	struct hnae3_handle *h = hns3_get_handle(ndev);
+
+	if (!h->ae_algo->ops->get_vf_config)
+		return -EOPNOTSUPP;
+
+	return h->ae_algo->ops->get_vf_config(h, vf, ivf);
+}
+
+static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf,
+				      int link_state)
+{
+	struct hnae3_handle *h = hns3_get_handle(ndev);
+
+	if (!h->ae_algo->ops->set_vf_link_state)
+		return -EOPNOTSUPP;
+
+	return h->ae_algo->ops->set_vf_link_state(h, vf, link_state);
+}
+
+static int hns3_nic_set_vf_rate(struct net_device *ndev, int vf,
+				int min_tx_rate, int max_tx_rate)
+{
+	struct hnae3_handle *h = hns3_get_handle(ndev);
+
+	if (!h->ae_algo->ops->set_vf_rate)
+		return -EOPNOTSUPP;
+
+	return h->ae_algo->ops->set_vf_rate(h, vf, min_tx_rate, max_tx_rate,
+					    false);
+}
+
+static int hns3_nic_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+{
+	struct hnae3_handle *h = hns3_get_handle(netdev);
+
+	if (!h->ae_algo->ops->set_vf_mac)
+		return -EOPNOTSUPP;
+
+	if (is_multicast_ether_addr(mac)) {
+		netdev_err(netdev,
+			   "Invalid MAC:%pM specified. Could not set MAC\n",
+			   mac);
+		return -EINVAL;
+	}
+
+	return h->ae_algo->ops->set_vf_mac(h, vf_id, mac);
+}
+
 static const struct net_device_ops hns3_nic_netdev_ops = {
 	.ndo_open		= hns3_nic_net_open,
 	.ndo_stop		= hns3_nic_net_stop,
@@ -1814,16 +2028,22 @@
 	.ndo_do_ioctl		= hns3_nic_do_ioctl,
 	.ndo_change_mtu		= hns3_nic_change_mtu,
 	.ndo_set_features	= hns3_nic_set_features,
+	.ndo_features_check	= hns3_features_check,
 	.ndo_get_stats64	= hns3_nic_get_stats64,
 	.ndo_setup_tc		= hns3_nic_setup_tc,
 	.ndo_set_rx_mode	= hns3_nic_set_rx_mode,
 	.ndo_vlan_rx_add_vid	= hns3_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= hns3_vlan_rx_kill_vid,
 	.ndo_set_vf_vlan	= hns3_ndo_set_vf_vlan,
+	.ndo_set_vf_spoofchk	= hns3_set_vf_spoofchk,
+	.ndo_set_vf_trust	= hns3_set_vf_trust,
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= hns3_rx_flow_steer,
 #endif
-
+	.ndo_get_vf_config	= hns3_nic_get_vf_config,
+	.ndo_set_vf_link_state	= hns3_nic_set_vf_link_state,
+	.ndo_set_vf_rate	= hns3_nic_set_vf_rate,
+	.ndo_set_vf_mac		= hns3_nic_set_vf_mac,
 };
 
 bool hns3_is_phys_func(struct pci_dev *pdev)
@@ -1843,7 +2063,7 @@
 	case HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF:
 		return false;
 	default:
-		dev_warn(&pdev->dev, "un-recognized pci device-id %d",
+		dev_warn(&pdev->dev, "un-recognized pci device-id %u",
 			 dev_id);
 	}
 
@@ -2026,7 +2246,7 @@
 {
 	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
 
-	dev_info(&pdev->dev, "hns3 flr prepare\n");
+	dev_info(&pdev->dev, "FLR prepare\n");
 	if (ae_dev && ae_dev->ops && ae_dev->ops->flr_prepare)
 		ae_dev->ops->flr_prepare(ae_dev);
 }
@@ -2035,7 +2255,7 @@
 {
 	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
 
-	dev_info(&pdev->dev, "hns3 flr done\n");
+	dev_info(&pdev->dev, "FLR done\n");
 	if (ae_dev && ae_dev->ops && ae_dev->ops->flr_done)
 		ae_dev->ops->flr_done(ae_dev);
 }
@@ -2069,9 +2289,8 @@
 		NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
 		NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
 		NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
-		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
-
-	netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
+		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
+		NETIF_F_TSO_MANGLEID | NETIF_F_FRAGLIST;
 
 	netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
 
@@ -2081,21 +2300,24 @@
 		NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
 		NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
 		NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
-		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
+		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
+		NETIF_F_FRAGLIST;
 
 	netdev->vlan_features |=
 		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
 		NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
 		NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
 		NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
-		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
+		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
+		NETIF_F_FRAGLIST;
 
 	netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
 		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
 		NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
 		NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
 		NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
-		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
+		NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
+		NETIF_F_FRAGLIST;
 
 	if (pdev->revision >= 0x21) {
 		netdev->hw_features |= NETIF_F_GRO_HW;
@@ -2320,21 +2542,22 @@
 
 void hns3_clean_tx_ring(struct hns3_enet_ring *ring)
 {
-	struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+	struct net_device *netdev = ring_to_netdev(ring);
 	struct hns3_nic_priv *priv = netdev_priv(netdev);
 	struct netdev_queue *dev_queue;
 	int bytes, pkts;
 	int head;
 
 	head = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_HEAD_REG);
-	rmb(); /* Make sure head is ready before touch any data */
 
 	if (is_ring_empty(ring) || head == ring->next_to_clean)
 		return; /* no data to poll */
 
+	rmb(); /* Make sure head is ready before touch any data */
+
 	if (unlikely(!is_valid_clean_head(ring, head))) {
-		netdev_err(netdev, "wrong head (%d, %d-%d)\n", head,
-			   ring->next_to_use, ring->next_to_clean);
+		hns3_rl_err(netdev, "wrong head (%d, %d-%d)\n", head,
+			    ring->next_to_use, ring->next_to_clean);
 
 		u64_stats_update_begin(&ring->syncp);
 		ring->stats.io_err_cnt++;
@@ -2357,8 +2580,8 @@
 	dev_queue = netdev_get_tx_queue(netdev, ring->tqp->tqp_index);
 	netdev_tx_completed_queue(dev_queue, pkts, bytes);
 
-	if (unlikely(pkts && netif_carrier_ok(netdev) &&
-		     (ring_space(ring) > HNS3_MAX_BD_PER_PKT))) {
+	if (unlikely(netif_carrier_ok(netdev) &&
+		     ring_space(ring) > HNS3_MAX_TSO_BD_NUM)) {
 		/* Make sure that anybody stopping the queue after this
 		 * sees the new next_to_clean.
 		 */
@@ -2401,7 +2624,7 @@
 				ring->stats.sw_err_cnt++;
 				u64_stats_update_end(&ring->syncp);
 
-				hns3_rl_err(ring->tqp_vector->napi.dev,
+				hns3_rl_err(ring_to_netdev(ring),
 					    "alloc rx buffer failed: %d\n",
 					    ret);
 				break;
@@ -2420,6 +2643,12 @@
 	writel_relaxed(i, ring->tqp->io_base + HNS3_RING_RX_RING_HEAD_REG);
 }
 
+static bool hns3_page_is_reusable(struct page *page)
+{
+	return page_to_nid(page) == numa_mem_id() &&
+		!page_is_pfmemalloc(page);
+}
+
 static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
 				struct hns3_enet_ring *ring, int pull_len,
 				struct hns3_desc_cb *desc_cb)
@@ -2434,7 +2663,7 @@
 	/* Avoid re-using remote pages, or the stack is still using the page
 	 * when page_offset rollback to zero, flag default unreuse
 	 */
-	if (unlikely(page_to_nid(desc_cb->priv) != numa_mem_id()) ||
+	if (unlikely(!hns3_page_is_reusable(desc_cb->priv)) ||
 	    (!desc_cb->page_offset && page_count(desc_cb->priv) > 1))
 		return;
 
@@ -2504,13 +2733,16 @@
 	skb->csum_start = (unsigned char *)th - skb->head;
 	skb->csum_offset = offsetof(struct tcphdr, check);
 	skb->ip_summed = CHECKSUM_PARTIAL;
+
+	trace_hns3_gro(skb);
+
 	return 0;
 }
 
 static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
 			     u32 l234info, u32 bd_base_info, u32 ol_info)
 {
-	struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+	struct net_device *netdev = ring_to_netdev(ring);
 	int l3_type, l4_type;
 	int ol4_type;
 
@@ -2624,9 +2856,8 @@
 static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length,
 			  unsigned char *va)
 {
-#define HNS3_NEED_ADD_FRAG	1
 	struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_clean];
-	struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+	struct net_device *netdev = ring_to_netdev(ring);
 	struct sk_buff *skb;
 
 	ring->skb = napi_alloc_skb(&ring->tqp_vector->napi, HNS3_RX_HEAD_SIZE);
@@ -2641,6 +2872,7 @@
 		return -ENOMEM;
 	}
 
+	trace_hns3_rx_desc(ring);
 	prefetchw(skb->data);
 
 	ring->pending_buf = 1;
@@ -2650,7 +2882,7 @@
 		memcpy(__skb_put(skb, length), va, ALIGN(length, sizeof(long)));
 
 		/* We can reuse buffer as-is, just make sure it is local */
-		if (likely(page_to_nid(desc_cb->priv) == numa_mem_id()))
+		if (likely(hns3_page_is_reusable(desc_cb->priv)))
 			desc_cb->reuse_flag = 1;
 		else /* This page cannot be reused so discard it */
 			put_page(desc_cb->priv);
@@ -2668,33 +2900,19 @@
 			    desc_cb);
 	ring_ptr_move_fw(ring, next_to_clean);
 
-	return HNS3_NEED_ADD_FRAG;
+	return 0;
 }
 
-static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc,
-			 struct sk_buff **out_skb, bool pending)
+static int hns3_add_frag(struct hns3_enet_ring *ring)
 {
-	struct sk_buff *skb = *out_skb;
-	struct sk_buff *head_skb = *out_skb;
+	struct sk_buff *skb = ring->skb;
+	struct sk_buff *head_skb = skb;
 	struct sk_buff *new_skb;
 	struct hns3_desc_cb *desc_cb;
-	struct hns3_desc *pre_desc;
+	struct hns3_desc *desc;
 	u32 bd_base_info;
-	int pre_bd;
-
-	/* if there is pending bd, the SW param next_to_clean has moved
-	 * to next and the next is NULL
-	 */
-	if (pending) {
-		pre_bd = (ring->next_to_clean - 1 + ring->desc_num) %
-			 ring->desc_num;
-		pre_desc = &ring->desc[pre_bd];
-		bd_base_info = le32_to_cpu(pre_desc->rx.bd_base_info);
-	} else {
-		bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
-	}
 
-	while (!(bd_base_info & BIT(HNS3_RXD_FE_B))) {
+	do {
 		desc = &ring->desc[ring->next_to_clean];
 		desc_cb = &ring->desc_cb[ring->next_to_clean];
 		bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
@@ -2704,10 +2922,9 @@
 			return -ENXIO;
 
 		if (unlikely(ring->frag_num >= MAX_SKB_FRAGS)) {
-			new_skb = napi_alloc_skb(&ring->tqp_vector->napi,
-						 HNS3_RX_HEAD_SIZE);
+			new_skb = napi_alloc_skb(&ring->tqp_vector->napi, 0);
 			if (unlikely(!new_skb)) {
-				hns3_rl_err(ring->tqp_vector->napi.dev,
+				hns3_rl_err(ring_to_netdev(ring),
 					    "alloc rx fraglist skb fail\n");
 				return -ENXIO;
 			}
@@ -2730,9 +2947,10 @@
 		}
 
 		hns3_nic_reuse_page(skb, ring->frag_num++, ring, 0, desc_cb);
+		trace_hns3_rx_desc(ring);
 		ring_ptr_move_fw(ring, next_to_clean);
 		ring->pending_buf++;
-	}
+	} while (!(bd_base_info & BIT(HNS3_RXD_FE_B)));
 
 	return 0;
 }
@@ -2783,7 +3001,7 @@
 
 static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
 {
-	struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+	struct net_device *netdev = ring_to_netdev(ring);
 	enum hns3_pkt_l2t_type l2_frame_type;
 	u32 bd_base_info, l234info, ol_info;
 	struct hns3_desc *desc;
@@ -2858,8 +3076,7 @@
 	return 0;
 }
 
-static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
-			     struct sk_buff **out_skb)
+static int hns3_handle_rx_bd(struct hns3_enet_ring *ring)
 {
 	struct sk_buff *skb = ring->skb;
 	struct hns3_desc_cb *desc_cb;
@@ -2897,32 +3114,27 @@
 
 	if (!skb) {
 		ret = hns3_alloc_skb(ring, length, ring->va);
-		*out_skb = skb = ring->skb;
+		skb = ring->skb;
 
 		if (ret < 0) /* alloc buffer fail */
 			return ret;
-		if (ret > 0) { /* need add frag */
-			ret = hns3_add_frag(ring, desc, &skb, false);
+		if (!(bd_base_info & BIT(HNS3_RXD_FE_B))) { /* need add frag */
+			ret = hns3_add_frag(ring);
 			if (ret)
 				return ret;
-
-			/* As the head data may be changed when GRO enable, copy
-			 * the head data in after other data rx completed
-			 */
-			memcpy(skb->data, ring->va,
-			       ALIGN(ring->pull_len, sizeof(long)));
 		}
 	} else {
-		ret = hns3_add_frag(ring, desc, &skb, true);
+		ret = hns3_add_frag(ring);
 		if (ret)
 			return ret;
+	}
 
-		/* As the head data may be changed when GRO enable, copy
-		 * the head data in after other data rx completed
-		 */
+	/* As the head data may be changed when GRO enable, copy
+	 * the head data in after other data rx completed
+	 */
+	if (skb->len > HNS3_RX_HEAD_SIZE)
 		memcpy(skb->data, ring->va,
 		       ALIGN(ring->pull_len, sizeof(long)));
-	}
 
 	ret = hns3_handle_bdinfo(ring, skb);
 	if (unlikely(ret)) {
@@ -2931,8 +3143,6 @@
 	}
 
 	skb_record_rx_queue(skb, ring->tqp->tqp_index);
-	*out_skb = skb;
-
 	return 0;
 }
 
@@ -2941,17 +3151,19 @@
 {
 #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16
 	int unused_count = hns3_desc_unused(ring);
-	struct sk_buff *skb = ring->skb;
 	int recv_pkts = 0;
 	int recv_bds = 0;
 	int err, num;
 
 	num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG);
-	rmb(); /* Make sure num taken effect before the other data is touched */
-
 	num -= unused_count;
 	unused_count -= ring->pending_buf;
 
+	if (num <= 0)
+		goto out;
+
+	rmb(); /* Make sure num taken effect before the other data is touched */
+
 	while (recv_pkts < budget && recv_bds < num) {
 		/* Reuse or realloc buffers */
 		if (unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) {
@@ -2961,27 +3173,19 @@
 		}
 
 		/* Poll one pkt */
-		err = hns3_handle_rx_bd(ring, &skb);
-		if (unlikely(!skb)) /* This fault cannot be repaired */
+		err = hns3_handle_rx_bd(ring);
+		/* Do not get FE for the packet or failed to alloc skb */
+		if (unlikely(!ring->skb || err == -ENXIO)) {
 			goto out;
-
-		if (err == -ENXIO) { /* Do not get FE for the packet */
-			goto out;
-		} else if (unlikely(err)) {  /* Do jump the err */
-			recv_bds += ring->pending_buf;
-			unused_count += ring->pending_buf;
-			ring->skb = NULL;
-			ring->pending_buf = 0;
-			continue;
+		} else if (likely(!err)) {
+			rx_fn(ring, ring->skb);
+			recv_pkts++;
 		}
 
-		rx_fn(ring, skb);
 		recv_bds += ring->pending_buf;
 		unused_count += ring->pending_buf;
 		ring->skb = NULL;
 		ring->pending_buf = 0;
-
-		recv_pkts++;
 	}
 
 out:
@@ -3303,7 +3507,6 @@
 
 static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
 {
-	struct hnae3_ring_chain_node vector_ring_chain;
 	struct hnae3_handle *h = priv->ae_handle;
 	struct hns3_enet_tqp_vector *tqp_vector;
 	int ret = 0;
@@ -3324,17 +3527,19 @@
 		tqp_vector = &priv->tqp_vector[vector_i];
 
 		hns3_add_ring_to_group(&tqp_vector->tx_group,
-				       priv->ring_data[i].ring);
+				       &priv->ring[i]);
 
 		hns3_add_ring_to_group(&tqp_vector->rx_group,
-				       priv->ring_data[i + tqp_num].ring);
+				       &priv->ring[i + tqp_num]);
 
-		priv->ring_data[i].ring->tqp_vector = tqp_vector;
-		priv->ring_data[i + tqp_num].ring->tqp_vector = tqp_vector;
+		priv->ring[i].tqp_vector = tqp_vector;
+		priv->ring[i + tqp_num].tqp_vector = tqp_vector;
 		tqp_vector->num_tqps++;
 	}
 
 	for (i = 0; i < priv->vector_num; i++) {
+		struct hnae3_ring_chain_node vector_ring_chain;
+
 		tqp_vector = &priv->tqp_vector[i];
 
 		tqp_vector->rx_group.total_bytes = 0;
@@ -3436,26 +3641,25 @@
 		if (!tqp_vector->rx_group.ring && !tqp_vector->tx_group.ring)
 			continue;
 
-		hns3_get_vector_ring_chain(tqp_vector, &vector_ring_chain);
+		/* Since the mapping can be overwritten, when fail to get the
+		 * chain between vector and ring, we should go on to deal with
+		 * the remaining options.
+		 */
+		if (hns3_get_vector_ring_chain(tqp_vector, &vector_ring_chain))
+			dev_warn(priv->dev, "failed to get ring chain\n");
 
 		h->ae_algo->ops->unmap_ring_from_vector(h,
 			tqp_vector->vector_irq, &vector_ring_chain);
 
 		hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
 
-		if (tqp_vector->irq_init_flag == HNS3_VECTOR_INITED) {
-			irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
-			free_irq(tqp_vector->vector_irq, tqp_vector);
-			tqp_vector->irq_init_flag = HNS3_VECTOR_NOT_INITED;
-		}
-
 		hns3_clear_ring_group(&tqp_vector->rx_group);
 		hns3_clear_ring_group(&tqp_vector->tx_group);
 		netif_napi_del(&priv->tqp_vector[i].napi);
 	}
 }
 
-static int hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv)
+static void hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv)
 {
 	struct hnae3_handle *h = priv->ae_handle;
 	struct pci_dev *pdev = h->pdev;
@@ -3467,35 +3671,28 @@
 		tqp_vector = &priv->tqp_vector[i];
 		ret = h->ae_algo->ops->put_vector(h, tqp_vector->vector_irq);
 		if (ret)
-			return ret;
+			return;
 	}
 
 	devm_kfree(&pdev->dev, priv->tqp_vector);
-	return 0;
 }
 
-static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
-			     unsigned int ring_type)
+static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
+			      unsigned int ring_type)
 {
-	struct hns3_nic_ring_data *ring_data = priv->ring_data;
 	int queue_num = priv->ae_handle->kinfo.num_tqps;
-	struct pci_dev *pdev = priv->ae_handle->pdev;
 	struct hns3_enet_ring *ring;
 	int desc_num;
 
-	ring = devm_kzalloc(&pdev->dev, sizeof(*ring), GFP_KERNEL);
-	if (!ring)
-		return -ENOMEM;
-
 	if (ring_type == HNAE3_RING_TYPE_TX) {
+		ring = &priv->ring[q->tqp_index];
 		desc_num = priv->ae_handle->kinfo.num_tx_desc;
-		ring_data[q->tqp_index].ring = ring;
-		ring_data[q->tqp_index].queue_index = q->tqp_index;
+		ring->queue_index = q->tqp_index;
 		ring->io_base = (u8 __iomem *)q->io_base + HNS3_TX_REG_OFFSET;
 	} else {
+		ring = &priv->ring[q->tqp_index + queue_num];
 		desc_num = priv->ae_handle->kinfo.num_rx_desc;
-		ring_data[q->tqp_index + queue_num].ring = ring;
-		ring_data[q->tqp_index + queue_num].queue_index = q->tqp_index;
+		ring->queue_index = q->tqp_index;
 		ring->io_base = q->io_base;
 	}
 
@@ -3510,76 +3707,41 @@
 	ring->desc_num = desc_num;
 	ring->next_to_use = 0;
 	ring->next_to_clean = 0;
-
-	return 0;
 }
 
-static int hns3_queue_to_ring(struct hnae3_queue *tqp,
-			      struct hns3_nic_priv *priv)
+static void hns3_queue_to_ring(struct hnae3_queue *tqp,
+			       struct hns3_nic_priv *priv)
 {
-	int ret;
-
-	ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX);
-	if (ret)
-		return ret;
-
-	ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX);
-	if (ret) {
-		devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring);
-		return ret;
-	}
-
-	return 0;
+	hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX);
+	hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX);
 }
 
 static int hns3_get_ring_config(struct hns3_nic_priv *priv)
 {
 	struct hnae3_handle *h = priv->ae_handle;
 	struct pci_dev *pdev = h->pdev;
-	int i, ret;
+	int i;
 
-	priv->ring_data =  devm_kzalloc(&pdev->dev,
-					array3_size(h->kinfo.num_tqps,
-						    sizeof(*priv->ring_data),
-						    2),
-					GFP_KERNEL);
-	if (!priv->ring_data)
+	priv->ring = devm_kzalloc(&pdev->dev,
+				  array3_size(h->kinfo.num_tqps,
+					      sizeof(*priv->ring), 2),
+				  GFP_KERNEL);
+	if (!priv->ring)
 		return -ENOMEM;
 
-	for (i = 0; i < h->kinfo.num_tqps; i++) {
-		ret = hns3_queue_to_ring(h->kinfo.tqp[i], priv);
-		if (ret)
-			goto err;
-	}
+	for (i = 0; i < h->kinfo.num_tqps; i++)
+		hns3_queue_to_ring(h->kinfo.tqp[i], priv);
 
 	return 0;
-err:
-	while (i--) {
-		devm_kfree(priv->dev, priv->ring_data[i].ring);
-		devm_kfree(priv->dev,
-			   priv->ring_data[i + h->kinfo.num_tqps].ring);
-	}
-
-	devm_kfree(&pdev->dev, priv->ring_data);
-	priv->ring_data = NULL;
-	return ret;
 }
 
 static void hns3_put_ring_config(struct hns3_nic_priv *priv)
 {
-	struct hnae3_handle *h = priv->ae_handle;
-	int i;
-
-	if (!priv->ring_data)
+	if (!priv->ring)
 		return;
 
-	for (i = 0; i < h->kinfo.num_tqps; i++) {
-		devm_kfree(priv->dev, priv->ring_data[i].ring);
-		devm_kfree(priv->dev,
-			   priv->ring_data[i + h->kinfo.num_tqps].ring);
-	}
-	devm_kfree(priv->dev, priv->ring_data);
-	priv->ring_data = NULL;
+	devm_kfree(priv->dev, priv->ring);
+	priv->ring = NULL;
 }
 
 static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring)
@@ -3696,7 +3858,7 @@
 		for (j = 0; j < tc_info->tqp_count; j++) {
 			struct hnae3_queue *q;
 
-			q = priv->ring_data[tc_info->tqp_offset + j].ring->tqp;
+			q = priv->ring[tc_info->tqp_offset + j].tqp;
 			hns3_write_dev(q, HNS3_RING_TX_RING_TC_REG,
 				       tc_info->tc);
 		}
@@ -3711,21 +3873,21 @@
 	int ret;
 
 	for (i = 0; i < ring_num; i++) {
-		ret = hns3_alloc_ring_memory(priv->ring_data[i].ring);
+		ret = hns3_alloc_ring_memory(&priv->ring[i]);
 		if (ret) {
 			dev_err(priv->dev,
 				"Alloc ring memory fail! ret=%d\n", ret);
 			goto out_when_alloc_ring_memory;
 		}
 
-		u64_stats_init(&priv->ring_data[i].ring->syncp);
+		u64_stats_init(&priv->ring[i].syncp);
 	}
 
 	return 0;
 
 out_when_alloc_ring_memory:
 	for (j = i - 1; j >= 0; j--)
-		hns3_fini_ring(priv->ring_data[j].ring);
+		hns3_fini_ring(&priv->ring[j]);
 
 	return -ENOMEM;
 }
@@ -3736,30 +3898,31 @@
 	int i;
 
 	for (i = 0; i < h->kinfo.num_tqps; i++) {
-		hns3_fini_ring(priv->ring_data[i].ring);
-		hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring);
+		hns3_fini_ring(&priv->ring[i]);
+		hns3_fini_ring(&priv->ring[i + h->kinfo.num_tqps]);
 	}
 	return 0;
 }
 
 /* Set mac addr if it is configured. or leave it to the AE driver */
-static int hns3_init_mac_addr(struct net_device *netdev, bool init)
+static int hns3_init_mac_addr(struct net_device *netdev)
 {
 	struct hns3_nic_priv *priv = netdev_priv(netdev);
 	struct hnae3_handle *h = priv->ae_handle;
-	u8 mac_addr_temp[ETH_ALEN];
+	u8 mac_addr_temp[ETH_ALEN] = {0};
 	int ret = 0;
 
-	if (h->ae_algo->ops->get_mac_addr && init) {
+	if (h->ae_algo->ops->get_mac_addr)
 		h->ae_algo->ops->get_mac_addr(h, mac_addr_temp);
-		ether_addr_copy(netdev->dev_addr, mac_addr_temp);
-	}
 
 	/* Check if the MAC address is valid, if not get a random one */
-	if (!is_valid_ether_addr(netdev->dev_addr)) {
+	if (!is_valid_ether_addr(mac_addr_temp)) {
 		eth_hw_addr_random(netdev);
 		dev_warn(priv->dev, "using random MAC address %pM\n",
 			 netdev->dev_addr);
+	} else {
+		ether_addr_copy(netdev->dev_addr, mac_addr_temp);
+		ether_addr_copy(netdev->perm_addr, mac_addr_temp);
 	}
 
 	if (h->ae_algo->ops->set_mac_addr)
@@ -3827,14 +3990,14 @@
 	struct hnae3_knic_private_info *kinfo = &priv->ae_handle->kinfo;
 
 	dev_info(priv->dev, "MAC address: %pM\n", priv->netdev->dev_addr);
-	dev_info(priv->dev, "Task queue pairs numbers: %d\n", kinfo->num_tqps);
-	dev_info(priv->dev, "RSS size: %d\n", kinfo->rss_size);
-	dev_info(priv->dev, "Allocated RSS size: %d\n", kinfo->req_rss_size);
-	dev_info(priv->dev, "RX buffer length: %d\n", kinfo->rx_buf_len);
-	dev_info(priv->dev, "Desc num per TX queue: %d\n", kinfo->num_tx_desc);
-	dev_info(priv->dev, "Desc num per RX queue: %d\n", kinfo->num_rx_desc);
-	dev_info(priv->dev, "Total number of enabled TCs: %d\n", kinfo->num_tc);
-	dev_info(priv->dev, "Max mtu size: %d\n", priv->netdev->max_mtu);
+	dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps);
+	dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size);
+	dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size);
+	dev_info(priv->dev, "RX buffer length: %u\n", kinfo->rx_buf_len);
+	dev_info(priv->dev, "Desc num per TX queue: %u\n", kinfo->num_tx_desc);
+	dev_info(priv->dev, "Desc num per RX queue: %u\n", kinfo->num_rx_desc);
+	dev_info(priv->dev, "Total number of enabled TCs: %u\n", kinfo->num_tc);
+	dev_info(priv->dev, "Max mtu size: %u\n", priv->netdev->max_mtu);
 }
 
 static int hns3_client_init(struct hnae3_handle *handle)
@@ -3863,7 +4026,7 @@
 	handle->kinfo.netdev = netdev;
 	handle->priv = (void *)priv;
 
-	hns3_init_mac_addr(netdev, true);
+	hns3_init_mac_addr(netdev);
 
 	hns3_set_default_feature(netdev);
 
@@ -3897,7 +4060,7 @@
 	ret = hns3_init_all_ring(priv);
 	if (ret) {
 		ret = -ENOMEM;
-		goto out_init_ring_data;
+		goto out_init_ring;
 	}
 
 	ret = hns3_init_phy(netdev);
@@ -3910,6 +4073,18 @@
 		goto out_reg_netdev_fail;
 	}
 
+	/* the device can work without cpu rmap, only aRFS needs it */
+	ret = hns3_set_rx_cpu_rmap(netdev);
+	if (ret)
+		dev_warn(priv->dev, "set rx cpu rmap fail, ret=%d\n", ret);
+
+	ret = hns3_nic_init_irq(priv);
+	if (ret) {
+		dev_err(priv->dev, "init irq failed! ret=%d\n", ret);
+		hns3_free_rx_cpu_rmap(netdev);
+		goto out_init_irq_fail;
+	}
+
 	ret = hns3_client_start(handle);
 	if (ret) {
 		dev_err(priv->dev, "hns3_client_start fail! ret=%d\n", ret);
@@ -3931,17 +4106,20 @@
 	return ret;
 
 out_client_start:
+	hns3_free_rx_cpu_rmap(netdev);
+	hns3_nic_uninit_irq(priv);
+out_init_irq_fail:
 	unregister_netdev(netdev);
 out_reg_netdev_fail:
 	hns3_uninit_phy(netdev);
 out_init_phy:
 	hns3_uninit_all_ring(priv);
-out_init_ring_data:
+out_init_ring:
 	hns3_nic_uninit_vector_data(priv);
 out_init_vector_data:
 	hns3_nic_dealloc_vector_data(priv);
 out_alloc_vector_data:
-	priv->ring_data = NULL;
+	priv->ring = NULL;
 out_get_ring_cfg:
 	priv->ae_handle = NULL;
 	free_netdev(netdev);
@@ -3968,15 +4146,17 @@
 		goto out_netdev_free;
 	}
 
+	hns3_free_rx_cpu_rmap(netdev);
+
+	hns3_nic_uninit_irq(priv);
+
 	hns3_del_all_fd_rules(netdev, true);
 
 	hns3_clear_all_ring(handle, true);
 
 	hns3_nic_uninit_vector_data(priv);
 
-	ret = hns3_nic_dealloc_vector_data(priv);
-	if (ret)
-		netdev_err(netdev, "dealloc vector error\n");
+	hns3_nic_dealloc_vector_data(priv);
 
 	ret = hns3_uninit_all_ring(priv);
 	if (ret)
@@ -3984,9 +4164,8 @@
 
 	hns3_put_ring_config(priv);
 
-	hns3_dbg_uninit(handle);
-
 out_netdev_free:
+	hns3_dbg_uninit(handle);
 	free_netdev(netdev);
 }
 
@@ -3998,8 +4177,8 @@
 		return;
 
 	if (linkup) {
-		netif_carrier_on(netdev);
 		netif_tx_wake_all_queues(netdev);
+		netif_carrier_on(netdev);
 		if (netif_msg_link(handle))
 			netdev_info(netdev, "link up\n");
 	} else {
@@ -4102,7 +4281,7 @@
 				/* if alloc new buffer fail, exit directly
 				 * and reclear in up flow.
 				 */
-				netdev_warn(ring->tqp->handle->kinfo.netdev,
+				netdev_warn(ring_to_netdev(ring),
 					    "reserve buffer map failed, ret = %d\n",
 					    ret);
 				return ret;
@@ -4148,10 +4327,10 @@
 	for (i = 0; i < h->kinfo.num_tqps; i++) {
 		struct hns3_enet_ring *ring;
 
-		ring = priv->ring_data[i].ring;
+		ring = &priv->ring[i];
 		hns3_clear_tx_ring(ring);
 
-		ring = priv->ring_data[i + h->kinfo.num_tqps].ring;
+		ring = &priv->ring[i + h->kinfo.num_tqps];
 		/* Continue to clear other rings even if clearing some
 		 * rings failed.
 		 */
@@ -4175,16 +4354,16 @@
 		if (ret)
 			return ret;
 
-		hns3_init_ring_hw(priv->ring_data[i].ring);
+		hns3_init_ring_hw(&priv->ring[i]);
 
 		/* We need to clear tx ring here because self test will
 		 * use the ring and will not run down before up
 		 */
-		hns3_clear_tx_ring(priv->ring_data[i].ring);
-		priv->ring_data[i].ring->next_to_clean = 0;
-		priv->ring_data[i].ring->next_to_use = 0;
+		hns3_clear_tx_ring(&priv->ring[i]);
+		priv->ring[i].next_to_clean = 0;
+		priv->ring[i].next_to_use = 0;
 
-		rx_ring = priv->ring_data[i + h->kinfo.num_tqps].ring;
+		rx_ring = &priv->ring[i + h->kinfo.num_tqps];
 		hns3_init_ring_hw(rx_ring);
 		ret = hns3_clear_rx_ring(rx_ring);
 		if (ret)
@@ -4261,6 +4440,11 @@
 	struct hns3_nic_priv *priv = netdev_priv(kinfo->netdev);
 	int ret = 0;
 
+	if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state)) {
+		netdev_err(kinfo->netdev, "device is not initialized yet\n");
+		return -EFAULT;
+	}
+
 	clear_bit(HNS3_NIC_STATE_RESETTING, &priv->state);
 
 	if (netif_running(kinfo->netdev)) {
@@ -4303,17 +4487,32 @@
 	if (ret)
 		goto err_uninit_vector;
 
+	/* the device can work without cpu rmap, only aRFS needs it */
+	ret = hns3_set_rx_cpu_rmap(netdev);
+	if (ret)
+		dev_warn(priv->dev, "set rx cpu rmap fail, ret=%d\n", ret);
+
+	ret = hns3_nic_init_irq(priv);
+	if (ret) {
+		dev_err(priv->dev, "init irq failed! ret=%d\n", ret);
+		hns3_free_rx_cpu_rmap(netdev);
+		goto err_init_irq_fail;
+	}
+
 	ret = hns3_client_start(handle);
 	if (ret) {
 		dev_err(priv->dev, "hns3_client_start fail! ret=%d\n", ret);
-		goto err_uninit_ring;
+		goto err_client_start_fail;
 	}
 
 	set_bit(HNS3_NIC_STATE_INITED, &priv->state);
 
 	return ret;
 
-err_uninit_ring:
+err_client_start_fail:
+	hns3_free_rx_cpu_rmap(netdev);
+	hns3_nic_uninit_irq(priv);
+err_init_irq_fail:
 	hns3_uninit_all_ring(priv);
 err_uninit_vector:
 	hns3_nic_uninit_vector_data(priv);
@@ -4331,7 +4530,7 @@
 	bool vlan_filter_enable;
 	int ret;
 
-	ret = hns3_init_mac_addr(netdev, false);
+	ret = hns3_init_mac_addr(netdev);
 	if (ret)
 		return ret;
 
@@ -4363,6 +4562,8 @@
 		return 0;
 	}
 
+	hns3_free_rx_cpu_rmap(netdev);
+	hns3_nic_uninit_irq(priv);
 	hns3_clear_all_ring(handle, true);
 	hns3_reset_tx_queue(priv->ae_handle);
 
@@ -4370,9 +4571,7 @@
 
 	hns3_store_coal(priv);
 
-	ret = hns3_nic_dealloc_vector_data(priv);
-	if (ret)
-		netdev_err(netdev, "dealloc vector error\n");
+	hns3_nic_dealloc_vector_data(priv);
 
 	ret = hns3_uninit_all_ring(priv);
 	if (ret)
@@ -4454,7 +4653,7 @@
 	if (new_tqp_num > hns3_get_max_available_channels(h) ||
 	    new_tqp_num < 1) {
 		dev_err(&netdev->dev,
-			"Change tqps fail, the tqp range is from 1 to %d",
+			"Change tqps fail, the tqp range is from 1 to %u",
 			hns3_get_max_available_channels(h));
 		return -EINVAL;
 	}
@@ -4538,7 +4737,7 @@
 	pr_info("%s: %s\n", hns3_driver_name, hns3_copyright);
 
 	client.type = HNAE3_CLIENT_KNIC;
-	snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s",
+	snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH, "%s",
 		 hns3_driver_name);
 
 	client.ops = &client_ops;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -76,7 +76,7 @@
 #define HNS3_RING_NAME_LEN			16
 #define HNS3_BUFFER_SIZE_2048			2048
 #define HNS3_RING_MAX_PENDING			32760
-#define HNS3_RING_MIN_PENDING			24
+#define HNS3_RING_MIN_PENDING			72
 #define HNS3_RING_BD_MULTIPLE			8
 /* max frame size of mac */
 #define HNS3_MAC_MAX_FRAME			9728
@@ -186,7 +186,7 @@
 #define HNS3_TXD_MSS_S				0
 #define HNS3_TXD_MSS_M				(0x3fff << HNS3_TXD_MSS_S)
 
-#define HNS3_TX_LAST_SIZE_M                    0xffff
+#define HNS3_TX_LAST_SIZE_M			0xffff
 
 #define HNS3_VECTOR_TX_IRQ			BIT_ULL(0)
 #define HNS3_VECTOR_RX_IRQ			BIT_ULL(1)
@@ -195,9 +195,13 @@
 #define HNS3_VECTOR_INITED			1
 
 #define HNS3_MAX_BD_SIZE			65535
-#define HNS3_MAX_BD_NUM_NORMAL			8
-#define HNS3_MAX_BD_NUM_TSO			63
-#define HNS3_MAX_BD_PER_PKT			MAX_SKB_FRAGS
+#define HNS3_MAX_NON_TSO_BD_NUM			8U
+#define HNS3_MAX_TSO_BD_NUM			63U
+#define HNS3_MAX_TSO_SIZE \
+	(HNS3_MAX_BD_SIZE * HNS3_MAX_TSO_BD_NUM)
+
+#define HNS3_MAX_NON_TSO_SIZE \
+	(HNS3_MAX_BD_SIZE * HNS3_MAX_NON_TSO_BD_NUM)
 
 #define HNS3_VECTOR_GL0_OFFSET			0x100
 #define HNS3_VECTOR_GL1_OFFSET			0x200
@@ -309,7 +313,7 @@
 
 	u16 reuse_flag;
 
-       /* desc type, used by the ring user to mark the type of the priv data */
+	/* desc type, used by the ring user to mark the type of the priv data */
 	u16 type;
 };
 
@@ -405,6 +409,7 @@
 	struct hns3_enet_ring *next;
 	struct hns3_enet_tqp_vector *tqp_vector;
 	struct hnae3_queue *tqp;
+	int queue_index;
 	struct device *dev; /* will be used for DMA mapping of descriptors */
 
 	/* statistic */
@@ -430,18 +435,7 @@
 	int pending_buf;
 	struct sk_buff *skb;
 	struct sk_buff *tail_skb;
-};
-
-struct hns_queue;
-
-struct hns3_nic_ring_data {
-	struct hns3_enet_ring *ring;
-	struct napi_struct napi;
-	int queue_index;
-	int (*poll_one)(struct hns3_nic_ring_data *, int, void *);
-	void (*ex_process)(struct hns3_nic_ring_data *, struct sk_buff *);
-	void (*fini_process)(struct hns3_nic_ring_data *);
-};
+} ____cacheline_internodealigned_in_smp;
 
 enum hns3_flow_level_range {
 	HNS3_FLOW_LOW = 0,
@@ -518,7 +512,7 @@
 	 * the cb for nic to manage the ring buffer, the first half of the
 	 * array is for tx_ring and vice versa for the second half
 	 */
-	struct hns3_nic_ring_data *ring_data;
+	struct hns3_enet_ring *ring;
 	struct hns3_enet_tqp_vector *tqp_vector;
 	u16 vector_num;
 
@@ -613,11 +607,11 @@
 
 #define ring_to_dev(ring) ((ring)->dev)
 
+#define ring_to_netdev(ring)	((ring)->tqp_vector->napi.dev)
+
 #define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \
 	DMA_TO_DEVICE : DMA_FROM_DEVICE)
 
-#define tx_ring_data(priv, idx) ((priv)->ring_data[idx])
-
 #define hns3_buf_size(_ring) ((_ring)->buf_size)
 
 static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring)
@@ -679,4 +673,5 @@
 void hns3_dbg_uninit(struct hnae3_handle *handle);
 void hns3_dbg_register_debugfs(const char *debugfs_dir_name);
 void hns3_dbg_unregister_debugfs(void);
+void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -174,18 +174,21 @@
 {
 	struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector;
 	unsigned char *packet = skb->data;
+	u32 len = skb_headlen(skb);
 	u32 i;
 
-	for (i = 0; i < skb->len; i++)
+	len = min_t(u32, len, HNS3_NIC_LB_TEST_PACKET_SIZE);
+
+	for (i = 0; i < len; i++)
 		if (packet[i] != (unsigned char)(i & 0xff))
 			break;
 
 	/* The packet is correctly received */
-	if (i == skb->len)
+	if (i == HNS3_NIC_LB_TEST_PACKET_SIZE)
 		tqp_vector->rx_group.total_packets++;
 	else
 		print_hex_dump(KERN_ERR, "selftest:", DUMP_PREFIX_OFFSET, 16, 1,
-			       skb->data, skb->len, true);
+			       skb->data, len, true);
 
 	dev_kfree_skb_any(skb);
 }
@@ -198,7 +201,7 @@
 
 	kinfo = &h->kinfo;
 	for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) {
-		struct hns3_enet_ring *ring = priv->ring_data[i].ring;
+		struct hns3_enet_ring *ring = &priv->ring[i];
 		struct hns3_enet_ring_group *rx_group;
 		u64 pre_rx_pkt;
 
@@ -221,7 +224,7 @@
 	u32 i;
 
 	for (i = start_ringid; i <= end_ringid; i++) {
-		struct hns3_enet_ring *ring = priv->ring_data[i].ring;
+		struct hns3_enet_ring *ring = &priv->ring[i];
 
 		hns3_clean_tx_ring(ring);
 	}
@@ -423,9 +426,8 @@
 			data[ETH_GSTRING_LEN - 1] = '\0';
 
 			/* first, prepend the prefix string */
-			n1 = snprintf(data, MAX_PREFIX_SIZE, "%s%d_",
-				      prefix, i);
-			n1 = min_t(uint, n1, MAX_PREFIX_SIZE - 1);
+			n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%d_",
+				       prefix, i);
 			size_left = (ETH_GSTRING_LEN - 1) - n1;
 
 			/* now, concatenate the stats string to it */
@@ -486,7 +488,7 @@
 
 	/* get stats for Tx */
 	for (i = 0; i < kinfo->num_tqps; i++) {
-		ring = nic_priv->ring_data[i].ring;
+		ring = &nic_priv->ring[i];
 		for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) {
 			stat = (u8 *)ring + hns3_txq_stats[j].stats_offset;
 			*data++ = *(u64 *)stat;
@@ -495,7 +497,7 @@
 
 	/* get stats for Rx */
 	for (i = 0; i < kinfo->num_tqps; i++) {
-		ring = nic_priv->ring_data[i + kinfo->num_tqps].ring;
+		ring = &nic_priv->ring[i + kinfo->num_tqps];
 		for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) {
 			stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset;
 			*data++ = *(u64 *)stat;
@@ -598,8 +600,8 @@
 	param->tx_max_pending = HNS3_RING_MAX_PENDING;
 	param->rx_max_pending = HNS3_RING_MAX_PENDING;
 
-	param->tx_pending = priv->ring_data[0].ring->desc_num;
-	param->rx_pending = priv->ring_data[queue_num].ring->desc_num;
+	param->tx_pending = priv->ring[0].desc_num;
+	param->rx_pending = priv->ring[queue_num].desc_num;
 }
 
 static void hns3_get_pauseparam(struct net_device *netdev,
@@ -673,7 +675,9 @@
 		hns3_get_ksettings(h, cmd);
 		break;
 	case HNAE3_MEDIA_TYPE_FIBER:
-		if (module_type == HNAE3_MODULE_TYPE_CR)
+		if (module_type == HNAE3_MODULE_TYPE_UNKNOWN)
+			cmd->base.port = PORT_OTHER;
+		else if (module_type == HNAE3_MODULE_TYPE_CR)
 			cmd->base.port = PORT_DA;
 		else
 			cmd->base.port = PORT_FIBRE;
@@ -737,7 +741,7 @@
 	if (ops->get_media_type)
 		ops->get_media_type(handle, &media_type, &module_type);
 
-	if (cmd->base.duplex != DUPLEX_FULL &&
+	if (cmd->base.duplex == DUPLEX_HALF &&
 	    media_type != HNAE3_MEDIA_TYPE_COPPER) {
 		netdev_err(netdev,
 			   "only copper port supports half duplex!");
@@ -901,9 +905,8 @@
 	h->kinfo.num_rx_desc = rx_desc_num;
 
 	for (i = 0; i < h->kinfo.num_tqps; i++) {
-		priv->ring_data[i].ring->desc_num = tx_desc_num;
-		priv->ring_data[i + h->kinfo.num_tqps].ring->desc_num =
-			rx_desc_num;
+		priv->ring[i].desc_num = tx_desc_num;
+		priv->ring[i + h->kinfo.num_tqps].desc_num = rx_desc_num;
 	}
 }
 
@@ -919,7 +922,7 @@
 		return NULL;
 
 	for (i = 0; i < handle->kinfo.num_tqps * 2; i++) {
-		memcpy(&tmp_rings[i], priv->ring_data[i].ring,
+		memcpy(&tmp_rings[i], &priv->ring[i],
 		       sizeof(struct hns3_enet_ring));
 		tmp_rings[i].skb = NULL;
 	}
@@ -967,8 +970,8 @@
 	/* Hardware requires that its descriptors must be multiple of eight */
 	new_tx_desc_num = ALIGN(param->tx_pending, HNS3_RING_BD_MULTIPLE);
 	new_rx_desc_num = ALIGN(param->rx_pending, HNS3_RING_BD_MULTIPLE);
-	old_tx_desc_num = priv->ring_data[0].ring->desc_num;
-	old_rx_desc_num = priv->ring_data[queue_num].ring->desc_num;
+	old_tx_desc_num = priv->ring[0].desc_num;
+	old_rx_desc_num = priv->ring[queue_num].desc_num;
 	if (old_tx_desc_num == new_tx_desc_num &&
 	    old_rx_desc_num == new_rx_desc_num)
 		return 0;
@@ -981,7 +984,7 @@
 	}
 
 	netdev_info(ndev,
-		    "Changing Tx/Rx ring depth from %d/%d to %d/%d\n",
+		    "Changing Tx/Rx ring depth from %u/%u to %u/%u\n",
 		    old_tx_desc_num, old_rx_desc_num,
 		    new_tx_desc_num, new_rx_desc_num);
 
@@ -997,7 +1000,7 @@
 		hns3_change_all_ring_bd_num(priv, old_tx_desc_num,
 					    old_rx_desc_num);
 		for (i = 0; i < h->kinfo.num_tqps * 2; i++)
-			memcpy(priv->ring_data[i].ring, &tmp_rings[i],
+			memcpy(&priv->ring[i], &tmp_rings[i],
 			       sizeof(struct hns3_enet_ring));
 	} else {
 		for (i = 0; i < h->kinfo.num_tqps * 2; i++)
@@ -1093,13 +1096,13 @@
 
 	if (queue >= queue_num) {
 		netdev_err(netdev,
-			   "Invalid queue value %d! Queue max id=%d\n",
+			   "Invalid queue value %u! Queue max id=%u\n",
 			   queue, queue_num - 1);
 		return -EINVAL;
 	}
 
-	tx_vector = priv->ring_data[queue].ring->tqp_vector;
-	rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector;
+	tx_vector = priv->ring[queue].tqp_vector;
+	rx_vector = priv->ring[queue_num + queue].tqp_vector;
 
 	cmd->use_adaptive_tx_coalesce =
 			tx_vector->tx_group.coal.gl_adapt_enable;
@@ -1143,14 +1146,14 @@
 	rx_gl = hns3_gl_round_down(cmd->rx_coalesce_usecs);
 	if (rx_gl != cmd->rx_coalesce_usecs) {
 		netdev_info(netdev,
-			    "rx_usecs(%d) rounded down to %d, because it must be multiple of 2.\n",
+			    "rx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n",
 			    cmd->rx_coalesce_usecs, rx_gl);
 	}
 
 	tx_gl = hns3_gl_round_down(cmd->tx_coalesce_usecs);
 	if (tx_gl != cmd->tx_coalesce_usecs) {
 		netdev_info(netdev,
-			    "tx_usecs(%d) rounded down to %d, because it must be multiple of 2.\n",
+			    "tx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n",
 			    cmd->tx_coalesce_usecs, tx_gl);
 	}
 
@@ -1178,7 +1181,7 @@
 	rl = hns3_rl_round_down(cmd->rx_coalesce_usecs_high);
 	if (rl != cmd->rx_coalesce_usecs_high) {
 		netdev_info(netdev,
-			    "usecs_high(%d) rounded down to %d, because it must be multiple of 4.\n",
+			    "usecs_high(%u) rounded down to %u, because it must be multiple of 4.\n",
 			    cmd->rx_coalesce_usecs_high, rl);
 	}
 
@@ -1207,7 +1210,7 @@
 	if (cmd->use_adaptive_tx_coalesce == 1 ||
 	    cmd->use_adaptive_rx_coalesce == 1) {
 		netdev_info(netdev,
-			    "adaptive-tx=%d and adaptive-rx=%d, tx_usecs or rx_usecs will changed dynamically.\n",
+			    "adaptive-tx=%u and adaptive-rx=%u, tx_usecs or rx_usecs will changed dynamically.\n",
 			    cmd->use_adaptive_tx_coalesce,
 			    cmd->use_adaptive_rx_coalesce);
 	}
@@ -1224,8 +1227,8 @@
 	struct hnae3_handle *h = priv->ae_handle;
 	int queue_num = h->kinfo.num_tqps;
 
-	tx_vector = priv->ring_data[queue].ring->tqp_vector;
-	rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector;
+	tx_vector = priv->ring[queue].tqp_vector;
+	rx_vector = priv->ring[queue_num + queue].tqp_vector;
 
 	tx_vector->tx_group.coal.gl_adapt_enable =
 				cmd->use_adaptive_tx_coalesce;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3_trace.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3_trace.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2018-2019 Hisilicon Limited. */
+
+/* This must be outside ifdef _HNS3_TRACE_H */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hns3
+
+#if !defined(_HNS3_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _HNS3_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+#define DESC_NR		(sizeof(struct hns3_desc) / sizeof(u32))
+
+DECLARE_EVENT_CLASS(hns3_skb_template,
+	TP_PROTO(struct sk_buff *skb),
+	TP_ARGS(skb),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, headlen)
+		__field(unsigned int, len)
+		__field(__u8, nr_frags)
+		__field(__u8, ip_summed)
+		__field(unsigned int, hdr_len)
+		__field(unsigned short, gso_size)
+		__field(unsigned short, gso_segs)
+		__field(unsigned int, gso_type)
+		__field(bool, fraglist)
+		__array(__u32, size, MAX_SKB_FRAGS)
+	),
+
+	TP_fast_assign(
+		__entry->headlen = skb_headlen(skb);
+		__entry->len = skb->len;
+		__entry->nr_frags = skb_shinfo(skb)->nr_frags;
+		__entry->gso_size = skb_shinfo(skb)->gso_size;
+		__entry->gso_segs = skb_shinfo(skb)->gso_segs;
+		__entry->gso_type = skb_shinfo(skb)->gso_type;
+		__entry->hdr_len = skb->encapsulation ?
+		skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb) :
+		skb_transport_offset(skb) + tcp_hdrlen(skb);
+		__entry->ip_summed = skb->ip_summed;
+		__entry->fraglist = skb_has_frag_list(skb);
+		hns3_shinfo_pack(skb_shinfo(skb), __entry->size);
+	),
+
+	TP_printk(
+		"len: %u, %u, %u, cs: %u, gso: %u, %u, %x, frag(%d %u): %s",
+		__entry->headlen, __entry->len, __entry->hdr_len,
+		__entry->ip_summed, __entry->gso_size, __entry->gso_segs,
+		__entry->gso_type, __entry->fraglist, __entry->nr_frags,
+		__print_array(__entry->size, MAX_SKB_FRAGS, sizeof(__u32))
+	)
+);
+
+DEFINE_EVENT(hns3_skb_template, hns3_over_8bd,
+	TP_PROTO(struct sk_buff *skb),
+	TP_ARGS(skb));
+
+DEFINE_EVENT(hns3_skb_template, hns3_gro,
+	TP_PROTO(struct sk_buff *skb),
+	TP_ARGS(skb));
+
+DEFINE_EVENT(hns3_skb_template, hns3_tso,
+	TP_PROTO(struct sk_buff *skb),
+	TP_ARGS(skb));
+
+TRACE_EVENT(hns3_tx_desc,
+	TP_PROTO(struct hns3_enet_ring *ring, int cur_ntu),
+	TP_ARGS(ring, cur_ntu),
+
+	TP_STRUCT__entry(
+		__field(int, index)
+		__field(int, ntu)
+		__field(int, ntc)
+		__field(dma_addr_t, desc_dma)
+		__array(u32, desc, DESC_NR)
+		__string(devname, ring->tqp->handle->kinfo.netdev->name)
+	),
+
+	TP_fast_assign(
+		__entry->index = ring->tqp->tqp_index;
+		__entry->ntu = ring->next_to_use;
+		__entry->ntc = ring->next_to_clean;
+		__entry->desc_dma = ring->desc_dma_addr,
+		memcpy(__entry->desc, &ring->desc[cur_ntu],
+		       sizeof(struct hns3_desc));
+		__assign_str(devname, ring->tqp->handle->kinfo.netdev->name);
+	),
+
+	TP_printk(
+		"%s-%d-%d/%d desc(%pad): %s",
+		__get_str(devname), __entry->index, __entry->ntu,
+		__entry->ntc, &__entry->desc_dma,
+		__print_array(__entry->desc, DESC_NR, sizeof(u32))
+	)
+);
+
+TRACE_EVENT(hns3_rx_desc,
+	TP_PROTO(struct hns3_enet_ring *ring),
+	TP_ARGS(ring),
+
+	TP_STRUCT__entry(
+		__field(int, index)
+		__field(int, ntu)
+		__field(int, ntc)
+		__field(dma_addr_t, desc_dma)
+		__field(dma_addr_t, buf_dma)
+		__array(u32, desc, DESC_NR)
+		__string(devname, ring->tqp->handle->kinfo.netdev->name)
+	),
+
+	TP_fast_assign(
+		__entry->index = ring->tqp->tqp_index;
+		__entry->ntu = ring->next_to_use;
+		__entry->ntc = ring->next_to_clean;
+		__entry->desc_dma = ring->desc_dma_addr;
+		__entry->buf_dma = ring->desc_cb[ring->next_to_clean].dma;
+		memcpy(__entry->desc, &ring->desc[ring->next_to_clean],
+		       sizeof(struct hns3_desc));
+		__assign_str(devname, ring->tqp->handle->kinfo.netdev->name);
+	),
+
+	TP_printk(
+		"%s-%d-%d/%d desc(%pad) buf(%pad): %s",
+		__get_str(devname), __entry->index, __entry->ntu,
+		__entry->ntc, &__entry->desc_dma, &__entry->buf_dma,
+		__print_array(__entry->desc, DESC_NR, sizeof(u32))
+	)
+);
+
+#endif /* _HNS3_TRACE_H_ */
+
+/* This must be outside ifdef _HNS3_TRACE_H */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE hns3_trace
+#include <trace/define_trace.h>
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -145,7 +145,7 @@
 	rmb(); /* Make sure head is ready before touch any data */
 
 	if (!is_valid_csq_clean_head(csq, head)) {
-		dev_warn(&hdev->pdev->dev, "wrong cmd head (%d, %d-%d)\n", head,
+		dev_warn(&hdev->pdev->dev, "wrong cmd head (%u, %d-%d)\n", head,
 			 csq->next_to_use, csq->next_to_clean);
 		dev_warn(&hdev->pdev->dev,
 			 "Disabling any further commands to IMP firmware\n");
@@ -314,11 +314,10 @@
 		} while (timeout < hw->cmq.tx_timeout);
 	}
 
-	if (!complete) {
+	if (!complete)
 		retval = -EBADE;
-	} else {
+	else
 		retval = hclge_cmd_check_retval(hw, desc, num, ntc);
-	}
 
 	/* Clean the command send queue */
 	handle = hclge_cmd_csq_clean(hw);
@@ -480,19 +479,6 @@
 	hclge_write_dev(hw, HCLGE_NIC_CRQ_TAIL_REG, 0);
 }
 
-static void hclge_destroy_queue(struct hclge_cmq_ring *ring)
-{
-	spin_lock(&ring->lock);
-	hclge_free_cmd_desc(ring);
-	spin_unlock(&ring->lock);
-}
-
-static void hclge_destroy_cmd_queue(struct hclge_hw *hw)
-{
-	hclge_destroy_queue(&hw->cmq.csq);
-	hclge_destroy_queue(&hw->cmq.crq);
-}
-
 void hclge_cmd_uninit(struct hclge_dev *hdev)
 {
 	spin_lock_bh(&hdev->hw.cmq.csq.lock);
@@ -502,5 +488,6 @@
 	spin_unlock(&hdev->hw.cmq.crq.lock);
 	spin_unlock_bh(&hdev->hw.cmq.csq.lock);
 
-	hclge_destroy_cmd_queue(&hdev->hw);
+	hclge_free_cmd_desc(&hdev->hw.cmq.csq);
+	hclge_free_cmd_desc(&hdev->hw.cmq.crq);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -5,8 +5,11 @@
 #define __HCLGE_CMD_H
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/etherdevice.h>
+#include "hnae3.h"
 
 #define HCLGE_CMDQ_TX_TIMEOUT		30000
+#define HCLGE_DESC_DATA_LEN		6
 
 struct hclge_dev;
 struct hclge_desc {
@@ -18,7 +21,7 @@
 	__le16 flag;
 	__le16 retval;
 	__le16 rsv;
-	__le32 data[6];
+	__le32 data[HCLGE_DESC_DATA_LEN];
 };
 
 struct hclge_cmq_ring {
@@ -61,6 +64,7 @@
 struct hclge_misc_vector {
 	u8 __iomem *addr;
 	int vector_irq;
+	char name[HNAE3_INT_NAME_LEN];
 };
 
 struct hclge_cmq {
@@ -244,7 +248,7 @@
 	/* QCN commands */
 	HCLGE_OPC_QCN_MOD_CFG		= 0x1A01,
 	HCLGE_OPC_QCN_GRP_TMPLT_CFG	= 0x1A02,
-	HCLGE_OPC_QCN_SHAPPING_IR_CFG	= 0x1A03,
+	HCLGE_OPC_QCN_SHAPPING_CFG	= 0x1A03,
 	HCLGE_OPC_QCN_SHAPPING_BS_CFG	= 0x1A04,
 	HCLGE_OPC_QCN_QSET_LINK_CFG	= 0x1A05,
 	HCLGE_OPC_QCN_RP_STATUS_GET	= 0x1A06,
@@ -257,8 +261,12 @@
 	/* Led command */
 	HCLGE_OPC_LED_STATUS_CFG	= 0xB000,
 
+	/* clear hardware resource command */
+	HCLGE_OPC_CLEAR_HW_RESOURCE	= 0x700B,
+
 	/* NCL config command */
 	HCLGE_OPC_QUERY_NCL_CONFIG	= 0x7011,
+
 	/* M7 stats command */
 	HCLGE_OPC_M7_STATS_BD		= 0x7012,
 	HCLGE_OPC_M7_STATS_INFO		= 0x7013,
@@ -428,8 +436,10 @@
 #define HCLGE_PF_MAC_NUM_MASK	0x3
 #define HCLGE_PF_STATE_MAIN	BIT(HCLGE_PF_STATE_MAIN_B)
 #define HCLGE_PF_STATE_DONE	BIT(HCLGE_PF_STATE_DONE_B)
+#define HCLGE_VF_RST_STATUS_CMD	4
+
 struct hclge_func_status_cmd {
-	__le32  vf_rst_state[4];
+	__le32  vf_rst_state[HCLGE_VF_RST_STATUS_CMD];
 	u8 pf_state;
 	u8 mac_id;
 	u8 rsv1;
@@ -485,10 +495,12 @@
 #define HCLGE_CFG_UMV_TBL_SPACE_S	16
 #define HCLGE_CFG_UMV_TBL_SPACE_M	GENMASK(31, 16)
 
+#define HCLGE_CFG_CMD_CNT		4
+
 struct hclge_cfg_param_cmd {
 	__le32 offset;
 	__le32 rsv;
-	__le32 param[4];
+	__le32 param[HCLGE_CFG_CMD_CNT];
 };
 
 #define HCLGE_MAC_MODE		0x0
@@ -712,8 +724,7 @@
 	u8      flags;
 	u8      resp_code;
 	__le16  vlan_tag;
-	__le32  mac_addr_hi32;
-	__le16  mac_addr_lo16;
+	u8      mac_addr[ETH_ALEN];
 	__le16  rsv1;
 	__le16  ethter_type;
 	__le16  egress_port;
@@ -758,20 +769,27 @@
 	u8 rsv2[19];
 };
 
+#define HCLGE_VLAN_ID_OFFSET_STEP	160
+#define HCLGE_VLAN_BYTE_SIZE		8
+#define	HCLGE_VLAN_OFFSET_BITMAP \
+	(HCLGE_VLAN_ID_OFFSET_STEP / HCLGE_VLAN_BYTE_SIZE)
+
 struct hclge_vlan_filter_pf_cfg_cmd {
 	u8 vlan_offset;
 	u8 vlan_cfg;
 	u8 rsv[2];
-	u8 vlan_offset_bitmap[20];
+	u8 vlan_offset_bitmap[HCLGE_VLAN_OFFSET_BITMAP];
 };
 
+#define HCLGE_MAX_VF_BYTES  16
+
 struct hclge_vlan_filter_vf_cfg_cmd {
 	__le16 vlan_id;
 	u8  resp_code;
 	u8  rsv;
 	u8  vlan_cfg;
 	u8  rsv1[3];
-	u8  vf_bitmap[16];
+	u8  vf_bitmap[HCLGE_MAX_VF_BYTES];
 };
 
 #define HCLGE_SWITCH_ANTI_SPOOF_B	0U
@@ -806,6 +824,7 @@
 #define HCLGE_CFG_NIC_ROCE_SEL_B	4
 #define HCLGE_ACCEPT_TAG2_B		5
 #define HCLGE_ACCEPT_UNTAG2_B		6
+#define HCLGE_VF_NUM_PER_BYTE		8
 
 struct hclge_vport_vtag_tx_cfg_cmd {
 	u8 vport_vlan_cfg;
@@ -813,7 +832,7 @@
 	u8 rsv1[2];
 	__le16 def_vlan_tag1;
 	__le16 def_vlan_tag2;
-	u8 vf_bitmap[8];
+	u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE];
 	u8 rsv2[8];
 };
 
@@ -825,7 +844,7 @@
 	u8 vport_vlan_cfg;
 	u8 vf_offset;
 	u8 rsv1[6];
-	u8 vf_bitmap[8];
+	u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE];
 	u8 rsv2[8];
 };
 
@@ -864,7 +883,7 @@
 	u8	flags;
 	u8	resp_code;
 	__le16  vlan_tag;
-	u8      mac_addr[6];
+	u8      mac_addr[ETH_ALEN];
 	__le16  index;
 	__le16	ethter_type;
 	__le16  egress_port;
@@ -1018,16 +1037,16 @@
 #define HCLGE_FD_AD_DROP_B		0
 #define HCLGE_FD_AD_DIRECT_QID_B	1
 #define HCLGE_FD_AD_QID_S		2
-#define HCLGE_FD_AD_QID_M		GENMASK(12, 2)
+#define HCLGE_FD_AD_QID_M		GENMASK(11, 2)
 #define HCLGE_FD_AD_USE_COUNTER_B	12
 #define HCLGE_FD_AD_COUNTER_NUM_S	13
 #define HCLGE_FD_AD_COUNTER_NUM_M	GENMASK(20, 13)
 #define HCLGE_FD_AD_NXT_STEP_B		20
 #define HCLGE_FD_AD_NXT_KEY_S		21
-#define HCLGE_FD_AD_NXT_KEY_M		GENMASK(26, 21)
+#define HCLGE_FD_AD_NXT_KEY_M		GENMASK(25, 21)
 #define HCLGE_FD_AD_WR_RULE_ID_B	0
 #define HCLGE_FD_AD_RULE_ID_S		1
-#define HCLGE_FD_AD_RULE_ID_M		GENMASK(13, 1)
+#define HCLGE_FD_AD_RULE_ID_M		GENMASK(12, 1)
 
 struct hclge_fd_ad_config_cmd {
 	u8 stage;
@@ -1090,9 +1109,6 @@
 				enum hclge_opcode_type opcode, bool is_read);
 void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
 
-int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
-			       struct hclge_promisc_param *param);
-
 enum hclge_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw,
 					   struct hclge_desc *desc);
 enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
@@ -87,7 +87,7 @@
 	for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
 		if (prio_tc[i] >= num_tc) {
 			dev_err(&hdev->pdev->dev,
-				"prio_tc[%u] checking failed, %u >= num_tc(%u)\n",
+				"prio_tc[%d] checking failed, %u >= num_tc(%u)\n",
 				i, prio_tc[i], num_tc);
 			return -EINVAL;
 		}
@@ -124,7 +124,7 @@
 	if (ret)
 		return ret;
 
-	for (i = 0; i < hdev->tc_max; i++) {
+	for (i = 0; i < HNAE3_MAX_TC; i++) {
 		switch (ets->tc_tsa[i]) {
 		case IEEE_8021QAZ_TSA_STRICT:
 			if (hdev->tm_info.tc_info[i].tc_sch_mode !=
@@ -132,6 +132,15 @@
 				*changed = true;
 			break;
 		case IEEE_8021QAZ_TSA_ETS:
+			/* The hardware will switch to sp mode if bandwidth is
+			 * 0, so limit ets bandwidth must be greater than 0.
+			 */
+			if (!ets->tc_tx_bw[i]) {
+				dev_err(&hdev->pdev->dev,
+					"tc%u ets bw cannot be 0\n", i);
+				return -EINVAL;
+			}
+
 			if (hdev->tm_info.tc_info[i].tc_sch_mode !=
 				HCLGE_SCH_MODE_DWRR)
 				*changed = true;
@@ -281,21 +290,12 @@
 	u64 requests[HNAE3_MAX_TC], indications[HNAE3_MAX_TC];
 	struct hclge_vport *vport = hclge_get_vport(h);
 	struct hclge_dev *hdev = vport->back;
-	u8 i, j, pfc_map, *prio_tc;
 	int ret;
+	u8 i;
 
 	memset(pfc, 0, sizeof(*pfc));
 	pfc->pfc_cap = hdev->pfc_max;
-	prio_tc = hdev->tm_info.prio_tc;
-	pfc_map = hdev->tm_info.hw_pfc_map;
-
-	/* Pfc setting is based on TC */
-	for (i = 0; i < hdev->tm_info.num_tc; i++) {
-		for (j = 0; j < HNAE3_MAX_USER_PRIO; j++) {
-			if ((prio_tc[j] == i) && (pfc_map & BIT(i)))
-				pfc->pfc_en |= BIT(j);
-		}
-	}
+	pfc->pfc_en = hdev->tm_info.pfc_en;
 
 	ret = hclge_pfc_tx_stats_get(hdev, requests);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -73,8 +73,6 @@
 
 static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset)
 {
-#define HCLGE_GET_DFX_REG_TYPE_CNT	4
-
 	struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
 	int entries_per_desc;
 	int index;
@@ -89,7 +87,7 @@
 
 	entries_per_desc = ARRAY_SIZE(desc[0].data);
 	index = offset % entries_per_desc;
-	return (int)desc[offset / entries_per_desc].data[index];
+	return le32_to_cpu(desc[offset / entries_per_desc].data[index]);
 }
 
 static int hclge_dbg_cmd_send(struct hclge_dev *hdev,
@@ -145,15 +143,13 @@
 		return;
 	}
 
-	buf_len	 = sizeof(struct hclge_desc) * bd_num;
+	buf_len	= sizeof(struct hclge_desc) * bd_num;
 	desc_src = kzalloc(buf_len, GFP_KERNEL);
-	if (!desc_src) {
-		dev_err(&hdev->pdev->dev, "call kzalloc failed\n");
+	if (!desc_src)
 		return;
-	}
 
 	desc = desc_src;
-	ret  = hclge_dbg_cmd_send(hdev, desc, index, bd_num, reg_msg->cmd);
+	ret = hclge_dbg_cmd_send(hdev, desc, index, bd_num, reg_msg->cmd);
 	if (ret) {
 		kfree(desc_src);
 		return;
@@ -169,7 +165,7 @@
 		if (dfx_message->flag)
 			dev_info(&hdev->pdev->dev, "%s: 0x%x\n",
 				 dfx_message->message,
-				 desc->data[i % entries_per_desc]);
+				 le32_to_cpu(desc->data[i % entries_per_desc]));
 
 		dfx_message++;
 	}
@@ -181,6 +177,7 @@
 {
 	struct device *dev = &hdev->pdev->dev;
 	struct hclge_dbg_bitmap_cmd *bitmap;
+	enum hclge_opcode_type cmd;
 	int rq_id, pri_id, qset_id;
 	int port_id, nq_id, pg_id;
 	struct hclge_desc desc[2];
@@ -195,10 +192,10 @@
 		return;
 	}
 
-	ret = hclge_dbg_cmd_send(hdev, desc, qset_id, 1,
-				 HCLGE_OPC_QSET_DFX_STS);
+	cmd = HCLGE_OPC_QSET_DFX_STS;
+	ret = hclge_dbg_cmd_send(hdev, desc, qset_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
 	bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
 	dev_info(dev, "roce_qset_mask: 0x%x\n", bitmap->bit0);
@@ -206,75 +203,90 @@
 	dev_info(dev, "qs_shaping_pass: 0x%x\n", bitmap->bit2);
 	dev_info(dev, "qs_bp_sts: 0x%x\n", bitmap->bit3);
 
-	ret = hclge_dbg_cmd_send(hdev, desc, pri_id, 1, HCLGE_OPC_PRI_DFX_STS);
+	cmd = HCLGE_OPC_PRI_DFX_STS;
+	ret = hclge_dbg_cmd_send(hdev, desc, pri_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
 	bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
 	dev_info(dev, "pri_mask: 0x%x\n", bitmap->bit0);
 	dev_info(dev, "pri_cshaping_pass: 0x%x\n", bitmap->bit1);
 	dev_info(dev, "pri_pshaping_pass: 0x%x\n", bitmap->bit2);
 
-	ret = hclge_dbg_cmd_send(hdev, desc, pg_id, 1, HCLGE_OPC_PG_DFX_STS);
+	cmd = HCLGE_OPC_PG_DFX_STS;
+	ret = hclge_dbg_cmd_send(hdev, desc, pg_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
 	bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
 	dev_info(dev, "pg_mask: 0x%x\n", bitmap->bit0);
 	dev_info(dev, "pg_cshaping_pass: 0x%x\n", bitmap->bit1);
 	dev_info(dev, "pg_pshaping_pass: 0x%x\n", bitmap->bit2);
 
-	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1,
-				 HCLGE_OPC_PORT_DFX_STS);
+	cmd = HCLGE_OPC_PORT_DFX_STS;
+	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
 	bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
 	dev_info(dev, "port_mask: 0x%x\n", bitmap->bit0);
 	dev_info(dev, "port_shaping_pass: 0x%x\n", bitmap->bit1);
 
-	ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, HCLGE_OPC_SCH_NQ_CNT);
+	cmd = HCLGE_OPC_SCH_NQ_CNT;
+	ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
-	dev_info(dev, "sch_nq_cnt: 0x%x\n", desc[0].data[1]);
+	dev_info(dev, "sch_nq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1]));
 
-	ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, HCLGE_OPC_SCH_RQ_CNT);
+	cmd = HCLGE_OPC_SCH_RQ_CNT;
+	ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
-	dev_info(dev, "sch_rq_cnt: 0x%x\n", desc[0].data[1]);
+	dev_info(dev, "sch_rq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1]));
 
-	ret = hclge_dbg_cmd_send(hdev, desc, 0, 2, HCLGE_OPC_TM_INTERNAL_STS);
+	cmd = HCLGE_OPC_TM_INTERNAL_STS;
+	ret = hclge_dbg_cmd_send(hdev, desc, 0, 2, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
-	dev_info(dev, "pri_bp: 0x%x\n", desc[0].data[1]);
-	dev_info(dev, "fifo_dfx_info: 0x%x\n", desc[0].data[2]);
-	dev_info(dev, "sch_roce_fifo_afull_gap: 0x%x\n", desc[0].data[3]);
-	dev_info(dev, "tx_private_waterline: 0x%x\n", desc[0].data[4]);
-	dev_info(dev, "tm_bypass_en: 0x%x\n", desc[0].data[5]);
-	dev_info(dev, "SSU_TM_BYPASS_EN: 0x%x\n", desc[1].data[0]);
-	dev_info(dev, "SSU_RESERVE_CFG: 0x%x\n", desc[1].data[1]);
+	dev_info(dev, "pri_bp: 0x%x\n", le32_to_cpu(desc[0].data[1]));
+	dev_info(dev, "fifo_dfx_info: 0x%x\n", le32_to_cpu(desc[0].data[2]));
+	dev_info(dev, "sch_roce_fifo_afull_gap: 0x%x\n",
+		 le32_to_cpu(desc[0].data[3]));
+	dev_info(dev, "tx_private_waterline: 0x%x\n",
+		 le32_to_cpu(desc[0].data[4]));
+	dev_info(dev, "tm_bypass_en: 0x%x\n", le32_to_cpu(desc[0].data[5]));
+	dev_info(dev, "SSU_TM_BYPASS_EN: 0x%x\n", le32_to_cpu(desc[1].data[0]));
+	dev_info(dev, "SSU_RESERVE_CFG: 0x%x\n", le32_to_cpu(desc[1].data[1]));
 
-	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1,
-				 HCLGE_OPC_TM_INTERNAL_CNT);
+	cmd = HCLGE_OPC_TM_INTERNAL_CNT;
+	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
 
-	dev_info(dev, "SCH_NIC_NUM: 0x%x\n", desc[0].data[1]);
-	dev_info(dev, "SCH_ROCE_NUM: 0x%x\n", desc[0].data[2]);
+	dev_info(dev, "SCH_NIC_NUM: 0x%x\n", le32_to_cpu(desc[0].data[1]));
+	dev_info(dev, "SCH_ROCE_NUM: 0x%x\n", le32_to_cpu(desc[0].data[2]));
 
-	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1,
-				 HCLGE_OPC_TM_INTERNAL_STS_1);
+	cmd = HCLGE_OPC_TM_INTERNAL_STS_1;
+	ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
 	if (ret)
-		return;
+		goto err_dcb_cmd_send;
+
+	dev_info(dev, "TC_MAP_SEL: 0x%x\n", le32_to_cpu(desc[0].data[1]));
+	dev_info(dev, "IGU_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[2]));
+	dev_info(dev, "MAC_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[3]));
+	dev_info(dev, "IGU_PRI_MAP_TC_CFG: 0x%x\n",
+		 le32_to_cpu(desc[0].data[4]));
+	dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n",
+		 le32_to_cpu(desc[0].data[5]));
+	return;
 
-	dev_info(dev, "TC_MAP_SEL: 0x%x\n", desc[0].data[1]);
-	dev_info(dev, "IGU_PFC_PRI_EN: 0x%x\n", desc[0].data[2]);
-	dev_info(dev, "MAC_PFC_PRI_EN: 0x%x\n", desc[0].data[3]);
-	dev_info(dev, "IGU_PRI_MAP_TC_CFG: 0x%x\n", desc[0].data[4]);
-	dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n", desc[0].data[5]);
+err_dcb_cmd_send:
+	dev_err(&hdev->pdev->dev,
+		"failed to dump dcb dfx, cmd = %#x, ret = %d\n",
+		cmd, ret);
 }
 
 static void hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev, const char *cmd_buf)
@@ -308,8 +320,9 @@
 				  char *false_buf)
 {
 	if (flag)
-		dev_info(&hdev->pdev->dev, "%s(%d): %s\n", title_buf, index,
-			 true_buf);
+		dev_info(&hdev->pdev->dev, "%s(%d): %s weight: %u\n",
+			 title_buf, index, true_buf,
+			 hdev->tm_info.pg_info[0].tc_dwrr[index]);
 	else
 		dev_info(&hdev->pdev->dev, "%s(%d): %s\n", title_buf, index,
 			 false_buf);
@@ -337,7 +350,8 @@
 
 	ets_weight = (struct hclge_ets_tc_weight_cmd *)desc.data;
 
-	dev_info(&hdev->pdev->dev, "dump tc\n");
+	dev_info(&hdev->pdev->dev, "dump tc: %u tc enabled\n",
+		 hdev->tm_info.num_tc);
 	dev_info(&hdev->pdev->dev, "weight_offset: %u\n",
 		 ets_weight->weight_offset);
 
@@ -364,7 +378,7 @@
 	pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "PG_C pg_id: %u\n", pg_shap_cfg_cmd->pg_id);
 	dev_info(&hdev->pdev->dev, "PG_C pg_shapping: 0x%x\n",
-		 pg_shap_cfg_cmd->pg_shapping_para);
+		 le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para));
 
 	cmd = HCLGE_OPC_TM_PG_P_SHAPPING;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -375,7 +389,7 @@
 	pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "PG_P pg_id: %u\n", pg_shap_cfg_cmd->pg_id);
 	dev_info(&hdev->pdev->dev, "PG_P pg_shapping: 0x%x\n",
-		 pg_shap_cfg_cmd->pg_shapping_para);
+		 le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para));
 
 	cmd = HCLGE_OPC_TM_PORT_SHAPPING;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -385,7 +399,7 @@
 
 	port_shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "PORT port_shapping: 0x%x\n",
-		 port_shap_cfg_cmd->port_shapping_para);
+		 le32_to_cpu(port_shap_cfg_cmd->port_shapping_para));
 
 	cmd = HCLGE_OPC_TM_PG_SCH_MODE_CFG;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -393,7 +407,8 @@
 	if (ret)
 		goto err_tm_pg_cmd_send;
 
-	dev_info(&hdev->pdev->dev, "PG_SCH pg_id: %u\n", desc.data[0]);
+	dev_info(&hdev->pdev->dev, "PG_SCH pg_id: %u\n",
+		 le32_to_cpu(desc.data[0]));
 
 	cmd = HCLGE_OPC_TM_PRI_SCH_MODE_CFG;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -401,7 +416,8 @@
 	if (ret)
 		goto err_tm_pg_cmd_send;
 
-	dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n", desc.data[0]);
+	dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n",
+		 le32_to_cpu(desc.data[0]));
 
 	cmd = HCLGE_OPC_TM_QS_SCH_MODE_CFG;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -409,7 +425,8 @@
 	if (ret)
 		goto err_tm_pg_cmd_send;
 
-	dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n", desc.data[0]);
+	dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n",
+		 le32_to_cpu(desc.data[0]));
 
 	if (!hnae3_dev_dcb_supported(hdev)) {
 		dev_info(&hdev->pdev->dev,
@@ -429,7 +446,7 @@
 	dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_group_id: 0x%x\n",
 		 bp_to_qs_map_cmd->qs_group_id);
 	dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_bit_map: 0x%x\n",
-		 bp_to_qs_map_cmd->qs_bit_map);
+		 le32_to_cpu(bp_to_qs_map_cmd->qs_bit_map));
 	return;
 
 err_tm_pg_cmd_send:
@@ -471,7 +488,7 @@
 
 	qs_to_pri_map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "QS_TO_PRI qs_id: %u\n",
-		 qs_to_pri_map->qs_id);
+		 le16_to_cpu(qs_to_pri_map->qs_id));
 	dev_info(&hdev->pdev->dev, "QS_TO_PRI priority: %u\n",
 		 qs_to_pri_map->priority);
 	dev_info(&hdev->pdev->dev, "QS_TO_PRI link_vld: %u\n",
@@ -484,9 +501,10 @@
 		goto err_tm_cmd_send;
 
 	nq_to_qs_map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
-	dev_info(&hdev->pdev->dev, "NQ_TO_QS nq_id: %u\n", nq_to_qs_map->nq_id);
+	dev_info(&hdev->pdev->dev, "NQ_TO_QS nq_id: %u\n",
+		 le16_to_cpu(nq_to_qs_map->nq_id));
 	dev_info(&hdev->pdev->dev, "NQ_TO_QS qset_id: 0x%x\n",
-		 nq_to_qs_map->qset_id);
+		 le16_to_cpu(nq_to_qs_map->qset_id));
 
 	cmd = HCLGE_OPC_TM_PG_WEIGHT;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -505,7 +523,8 @@
 		goto err_tm_cmd_send;
 
 	qs_weight = (struct hclge_qs_weight_cmd *)desc.data;
-	dev_info(&hdev->pdev->dev, "QS qs_id: %u\n", qs_weight->qs_id);
+	dev_info(&hdev->pdev->dev, "QS qs_id: %u\n",
+		 le16_to_cpu(qs_weight->qs_id));
 	dev_info(&hdev->pdev->dev, "QS dwrr: %u\n", qs_weight->dwrr);
 
 	cmd = HCLGE_OPC_TM_PRI_WEIGHT;
@@ -527,7 +546,7 @@
 	shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "PRI_C pri_id: %u\n", shap_cfg_cmd->pri_id);
 	dev_info(&hdev->pdev->dev, "PRI_C pri_shapping: 0x%x\n",
-		 shap_cfg_cmd->pri_shapping_para);
+		 le32_to_cpu(shap_cfg_cmd->pri_shapping_para));
 
 	cmd = HCLGE_OPC_TM_PRI_P_SHAPPING;
 	hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -538,7 +557,7 @@
 	shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
 	dev_info(&hdev->pdev->dev, "PRI_P pri_id: %u\n", shap_cfg_cmd->pri_id);
 	dev_info(&hdev->pdev->dev, "PRI_P pri_shapping: 0x%x\n",
-		 shap_cfg_cmd->pri_shapping_para);
+		 le32_to_cpu(shap_cfg_cmd->pri_shapping_para));
 
 	hclge_dbg_dump_tm_pg(hdev);
 
@@ -574,7 +593,7 @@
 	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
 	if (ret)
 		goto err_tm_map_cmd_send;
-	qset_id = nq_to_qs_map->qset_id & 0x3FF;
+	qset_id = le16_to_cpu(nq_to_qs_map->qset_id) & 0x3FF;
 
 	cmd = HCLGE_OPC_TM_QS_TO_PRI_LINK;
 	map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
@@ -614,7 +633,8 @@
 		if (ret)
 			goto err_tm_map_cmd_send;
 
-		qset_maping[group_id] = bp_to_qs_map_cmd->qs_bit_map;
+		qset_maping[group_id] =
+			le32_to_cpu(bp_to_qs_map_cmd->qs_bit_map);
 	}
 
 	dev_info(&hdev->pdev->dev, "index | tm bp qset maping:\n");
@@ -658,7 +678,7 @@
 	dev_info(&hdev->pdev->dev, "pause_trans_gap: 0x%x\n",
 		 pause_param->pause_trans_gap);
 	dev_info(&hdev->pdev->dev, "pause_trans_time: 0x%x\n",
-		 pause_param->pause_trans_time);
+		 le16_to_cpu(pause_param->pause_trans_time));
 }
 
 static void hclge_dbg_dump_qos_pri_map(struct hclge_dev *hdev)
@@ -712,7 +732,7 @@
 	tx_buf_cmd = (struct hclge_tx_buff_alloc_cmd *)desc[0].data;
 	for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
 		dev_info(&hdev->pdev->dev, "tx_packet_buf_tc_%d: 0x%x\n", i,
-			 tx_buf_cmd->tx_pkt_buff[i]);
+			 le16_to_cpu(tx_buf_cmd->tx_pkt_buff[i]));
 
 	cmd = HCLGE_OPC_RX_PRIV_BUFF_ALLOC;
 	hclge_cmd_setup_basic_desc(desc, cmd, true);
@@ -724,10 +744,10 @@
 	rx_buf_cmd = (struct hclge_rx_priv_buff_cmd *)desc[0].data;
 	for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
 		dev_info(&hdev->pdev->dev, "rx_packet_buf_tc_%d: 0x%x\n", i,
-			 rx_buf_cmd->buf_num[i]);
+			 le16_to_cpu(rx_buf_cmd->buf_num[i]));
 
 	dev_info(&hdev->pdev->dev, "rx_share_buf: 0x%x\n",
-		 rx_buf_cmd->shared_buf);
+		 le16_to_cpu(rx_buf_cmd->shared_buf));
 
 	cmd = HCLGE_OPC_RX_COM_WL_ALLOC;
 	hclge_cmd_setup_basic_desc(desc, cmd, true);
@@ -738,7 +758,8 @@
 	rx_com_wl = (struct hclge_rx_com_wl *)desc[0].data;
 	dev_info(&hdev->pdev->dev, "\n");
 	dev_info(&hdev->pdev->dev, "rx_com_wl: high: 0x%x, low: 0x%x\n",
-		 rx_com_wl->com_wl.high, rx_com_wl->com_wl.low);
+		 le16_to_cpu(rx_com_wl->com_wl.high),
+		 le16_to_cpu(rx_com_wl->com_wl.low));
 
 	cmd = HCLGE_OPC_RX_GBL_PKT_CNT;
 	hclge_cmd_setup_basic_desc(desc, cmd, true);
@@ -749,7 +770,8 @@
 	rx_packet_cnt = (struct hclge_rx_com_wl *)desc[0].data;
 	dev_info(&hdev->pdev->dev,
 		 "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n",
-		 rx_packet_cnt->com_wl.high, rx_packet_cnt->com_wl.low);
+		 le16_to_cpu(rx_packet_cnt->com_wl.high),
+		 le16_to_cpu(rx_packet_cnt->com_wl.low));
 	dev_info(&hdev->pdev->dev, "\n");
 
 	if (!hnae3_dev_dcb_supported(hdev)) {
@@ -769,14 +791,16 @@
 	for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
 		dev_info(&hdev->pdev->dev,
 			 "rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n", i,
-			 rx_priv_wl->tc_wl[i].high, rx_priv_wl->tc_wl[i].low);
+			 le16_to_cpu(rx_priv_wl->tc_wl[i].high),
+			 le16_to_cpu(rx_priv_wl->tc_wl[i].low));
 
 	rx_priv_wl = (struct hclge_rx_priv_wl_buf *)desc[1].data;
 	for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
 		dev_info(&hdev->pdev->dev,
 			 "rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n",
 			 i + HCLGE_TC_NUM_ONE_DESC,
-			 rx_priv_wl->tc_wl[i].high, rx_priv_wl->tc_wl[i].low);
+			 le16_to_cpu(rx_priv_wl->tc_wl[i].high),
+			 le16_to_cpu(rx_priv_wl->tc_wl[i].low));
 
 	cmd = HCLGE_OPC_RX_COM_THRD_ALLOC;
 	hclge_cmd_setup_basic_desc(&desc[0], cmd, true);
@@ -791,16 +815,16 @@
 	for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
 		dev_info(&hdev->pdev->dev,
 			 "rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n", i,
-			 rx_com_thrd->com_thrd[i].high,
-			 rx_com_thrd->com_thrd[i].low);
+			 le16_to_cpu(rx_com_thrd->com_thrd[i].high),
+			 le16_to_cpu(rx_com_thrd->com_thrd[i].low));
 
 	rx_com_thrd = (struct hclge_rx_com_thrd *)desc[1].data;
 	for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
 		dev_info(&hdev->pdev->dev,
 			 "rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n",
 			 i + HCLGE_TC_NUM_ONE_DESC,
-			 rx_com_thrd->com_thrd[i].high,
-			 rx_com_thrd->com_thrd[i].low);
+			 le16_to_cpu(rx_com_thrd->com_thrd[i].high),
+			 le16_to_cpu(rx_com_thrd->com_thrd[i].low));
 	return;
 
 err_qos_cmd_send:
@@ -813,6 +837,7 @@
 	struct hclge_mac_ethertype_idx_rd_cmd *req0;
 	char printf_buf[HCLGE_DBG_BUF_LEN];
 	struct hclge_desc desc;
+	u32 msg_egress_port;
 	int ret, i;
 
 	dev_info(&hdev->pdev->dev, "mng tab:\n");
@@ -845,7 +870,8 @@
 		memset(printf_buf, 0, HCLGE_DBG_BUF_LEN);
 		snprintf(printf_buf, HCLGE_DBG_BUF_LEN,
 			 "%02u   |%02x:%02x:%02x:%02x:%02x:%02x|",
-			 req0->index, req0->mac_addr[0], req0->mac_addr[1],
+			 le16_to_cpu(req0->index),
+			 req0->mac_addr[0], req0->mac_addr[1],
 			 req0->mac_addr[2], req0->mac_addr[3],
 			 req0->mac_addr[4], req0->mac_addr[5]);
 
@@ -853,27 +879,28 @@
 			 HCLGE_DBG_BUF_LEN - strlen(printf_buf),
 			 "%x   |%04x |%x   |%04x|%x   |%02x   |%02x   |",
 			 !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
-			 req0->ethter_type,
+			 le16_to_cpu(req0->ethter_type),
 			 !!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
-			 req0->vlan_tag & HCLGE_DBG_MNG_VLAN_TAG,
+			 le16_to_cpu(req0->vlan_tag) & HCLGE_DBG_MNG_VLAN_TAG,
 			 !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
 			 req0->i_port_bitmap, req0->i_port_direction);
 
+		msg_egress_port = le16_to_cpu(req0->egress_port);
 		snprintf(printf_buf + strlen(printf_buf),
 			 HCLGE_DBG_BUF_LEN - strlen(printf_buf),
-			 "%d     |%d    |%02d   |%04d|%x\n",
-			 !!(req0->egress_port & HCLGE_DBG_MNG_E_TYPE_B),
-			 req0->egress_port & HCLGE_DBG_MNG_PF_ID,
-			 (req0->egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
-			 req0->egress_queue,
-			 !!(req0->egress_port & HCLGE_DBG_MNG_DROP_B));
+			 "%x     |%x    |%02x   |%04x|%x\n",
+			 !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
+			 msg_egress_port & HCLGE_DBG_MNG_PF_ID,
+			 (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
+			 le16_to_cpu(req0->egress_queue),
+			 !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
 
 		dev_info(&hdev->pdev->dev, "%s", printf_buf);
 	}
 }
 
-static void hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
-				   bool sel_x, u32 loc)
+static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
+				  bool sel_x, u32 loc)
 {
 	struct hclge_fd_tcam_config_1_cmd *req1;
 	struct hclge_fd_tcam_config_2_cmd *req2;
@@ -898,7 +925,7 @@
 
 	ret = hclge_cmd_send(&hdev->hw, desc, 3);
 	if (ret)
-		return;
+		return ret;
 
 	dev_info(&hdev->pdev->dev, " read result tcam key %s(%u):\n",
 		 sel_x ? "x" : "y", loc);
@@ -917,19 +944,79 @@
 	req = (u32 *)req3->tcam_data;
 	for (i = 0; i < 5; i++)
 		dev_info(&hdev->pdev->dev, "%08x\n", *req++);
+
+	return ret;
+}
+
+static int hclge_dbg_get_rules_location(struct hclge_dev *hdev, u16 *rule_locs)
+{
+	struct hclge_fd_rule *rule;
+	struct hlist_node *node;
+	int cnt = 0;
+
+	spin_lock_bh(&hdev->fd_rule_lock);
+	hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
+		rule_locs[cnt] = rule->location;
+		cnt++;
+	}
+	spin_unlock_bh(&hdev->fd_rule_lock);
+
+	if (cnt != hdev->hclge_fd_rule_num)
+		return -EINVAL;
+
+	return cnt;
 }
 
 static void hclge_dbg_fd_tcam(struct hclge_dev *hdev)
 {
-	u32 i;
+	int i, ret, rule_cnt;
+	u16 *rule_locs;
+
+	if (!hnae3_dev_fd_supported(hdev)) {
+		dev_err(&hdev->pdev->dev,
+			"Only FD-supported dev supports dump fd tcam\n");
+		return;
+	}
+
+	if (!hdev->hclge_fd_rule_num ||
+	    !hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
+		return;
+
+	rule_locs = kcalloc(hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1],
+			    sizeof(u16), GFP_KERNEL);
+	if (!rule_locs)
+		return;
+
+	rule_cnt = hclge_dbg_get_rules_location(hdev, rule_locs);
+	if (rule_cnt <= 0) {
+		dev_err(&hdev->pdev->dev,
+			"failed to get rule number, ret = %d\n", rule_cnt);
+		kfree(rule_locs);
+		return;
+	}
+
+	for (i = 0; i < rule_cnt; i++) {
+		ret = hclge_dbg_fd_tcam_read(hdev, 0, true, rule_locs[i]);
+		if (ret) {
+			dev_err(&hdev->pdev->dev,
+				"failed to get fd tcam key x, ret = %d\n", ret);
+			kfree(rule_locs);
+			return;
+		}
 
-	for (i = 0; i < hdev->fd_cfg.rule_num[0]; i++) {
-		hclge_dbg_fd_tcam_read(hdev, 0, true, i);
-		hclge_dbg_fd_tcam_read(hdev, 0, false, i);
+		ret = hclge_dbg_fd_tcam_read(hdev, 0, false, rule_locs[i]);
+		if (ret) {
+			dev_err(&hdev->pdev->dev,
+				"failed to get fd tcam key y, ret = %d\n", ret);
+			kfree(rule_locs);
+			return;
+		}
 	}
+
+	kfree(rule_locs);
 }
 
-static void hclge_dbg_dump_rst_info(struct hclge_dev *hdev)
+void hclge_dbg_dump_rst_info(struct hclge_dev *hdev)
 {
 	dev_info(&hdev->pdev->dev, "PF reset count: %u\n",
 		 hdev->rst_stats.pf_rst_cnt);
@@ -945,8 +1032,6 @@
 		 hdev->rst_stats.hw_reset_done_cnt);
 	dev_info(&hdev->pdev->dev, "reset count: %u\n",
 		 hdev->rst_stats.reset_cnt);
-	dev_info(&hdev->pdev->dev, "reset count: %u\n",
-		 hdev->rst_stats.reset_cnt);
 	dev_info(&hdev->pdev->dev, "reset fail count: %u\n",
 		 hdev->rst_stats.reset_fail_cnt);
 	dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n",
@@ -961,6 +1046,15 @@
 		 hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
 	dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n",
 		 hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
+	dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state);
+}
+
+static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
+{
+	dev_info(&hdev->pdev->dev, "last_serv_processed: %lu\n",
+		 hdev->last_serv_processed);
+	dev_info(&hdev->pdev->dev, "last_serv_cnt: %lu\n",
+		 hdev->serv_processed_cnt);
 }
 
 static void hclge_dbg_get_m7_stats_info(struct hclge_dev *hdev)
@@ -986,11 +1080,8 @@
 
 	buf_len	 = sizeof(struct hclge_desc) * bd_num;
 	desc_src = kzalloc(buf_len, GFP_KERNEL);
-	if (!desc_src) {
-		dev_err(&hdev->pdev->dev,
-			"allocate desc for get_m7_stats failed\n");
+	if (!desc_src)
 		return;
-	}
 
 	desc_tmp = desc_src;
 	ret  = hclge_dbg_cmd_send(hdev, desc_tmp, 0, bd_num,
@@ -1053,7 +1144,7 @@
 				      const char *cmd_buf)
 {
 #define HCLGE_MAX_NCL_CONFIG_OFFSET	4096
-#define HCLGE_MAX_NCL_CONFIG_LENGTH	(20 + 24 * 4)
+#define HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD	(20 + 24 * 4)
 
 	struct hclge_desc desc[HCLGE_CMD_NCL_CONFIG_BD_NUM];
 	int bd_num = HCLGE_CMD_NCL_CONFIG_BD_NUM;
@@ -1077,8 +1168,8 @@
 
 	while (length > 0) {
 		data0 = offset;
-		if (length >= HCLGE_MAX_NCL_CONFIG_LENGTH)
-			data0 |= HCLGE_MAX_NCL_CONFIG_LENGTH << 16;
+		if (length >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
+			data0 |= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD << 16;
 		else
 			data0 |= length << 16;
 		ret = hclge_dbg_cmd_send(hdev, desc, data0, bd_num,
@@ -1090,6 +1181,57 @@
 	}
 }
 
+static void hclge_dbg_dump_loopback(struct hclge_dev *hdev,
+				    const char *cmd_buf)
+{
+	struct phy_device *phydev = hdev->hw.mac.phydev;
+	struct hclge_config_mac_mode_cmd *req_app;
+	struct hclge_serdes_lb_cmd *req_serdes;
+	struct hclge_desc desc;
+	u8 loopback_en;
+	int ret;
+
+	req_app = (struct hclge_config_mac_mode_cmd *)desc.data;
+	req_serdes = (struct hclge_serdes_lb_cmd *)desc.data;
+
+	dev_info(&hdev->pdev->dev, "mac id: %u\n", hdev->hw.mac.mac_id);
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to dump app loopback status, ret = %d\n", ret);
+		return;
+	}
+
+	loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en),
+				    HCLGE_MAC_APP_LP_B);
+	dev_info(&hdev->pdev->dev, "app loopback: %s\n",
+		 loopback_en ? "on" : "off");
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to dump serdes loopback status, ret = %d\n",
+			ret);
+		return;
+	}
+
+	loopback_en = req_serdes->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+	dev_info(&hdev->pdev->dev, "serdes serial loopback: %s\n",
+		 loopback_en ? "on" : "off");
+
+	loopback_en = req_serdes->enable &
+			HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B;
+	dev_info(&hdev->pdev->dev, "serdes parallel loopback: %s\n",
+		 loopback_en ? "on" : "off");
+
+	if (phydev)
+		dev_info(&hdev->pdev->dev, "phy loopback: %s\n",
+			 phydev->loopback_enabled ? "on" : "off");
+}
+
 /* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt
  * @hdev: pointer to struct hclge_dev
  */
@@ -1110,10 +1252,87 @@
 	}
 }
 
+static void hclge_dbg_dump_qs_shaper_single(struct hclge_dev *hdev, u16 qsid)
+{
+	struct hclge_qs_shapping_cmd *shap_cfg_cmd;
+	u8 ir_u, ir_b, ir_s, bs_b, bs_s;
+	struct hclge_desc desc;
+	u32 shapping_para;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true);
+
+	shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
+	shap_cfg_cmd->qs_id = cpu_to_le16(qsid);
+
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"qs%u failed to get tx_rate, ret=%d\n",
+			qsid, ret);
+		return;
+	}
+
+	shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para);
+	ir_b = hclge_tm_get_field(shapping_para, IR_B);
+	ir_u = hclge_tm_get_field(shapping_para, IR_U);
+	ir_s = hclge_tm_get_field(shapping_para, IR_S);
+	bs_b = hclge_tm_get_field(shapping_para, BS_B);
+	bs_s = hclge_tm_get_field(shapping_para, BS_S);
+
+	dev_info(&hdev->pdev->dev,
+		 "qs%u ir_b:%u, ir_u:%u, ir_s:%u, bs_b:%u, bs_s:%u\n",
+		 qsid, ir_b, ir_u, ir_s, bs_b, bs_s);
+}
+
+static void hclge_dbg_dump_qs_shaper_all(struct hclge_dev *hdev)
+{
+	struct hnae3_knic_private_info *kinfo;
+	struct hclge_vport *vport;
+	int vport_id, i;
+
+	for (vport_id = 0; vport_id <= pci_num_vf(hdev->pdev); vport_id++) {
+		vport = &hdev->vport[vport_id];
+		kinfo = &vport->nic.kinfo;
+
+		dev_info(&hdev->pdev->dev, "qs cfg of vport%d:\n", vport_id);
+
+		for (i = 0; i < kinfo->num_tc; i++) {
+			u16 qsid = vport->qs_offset + i;
+
+			hclge_dbg_dump_qs_shaper_single(hdev, qsid);
+		}
+	}
+}
+
+static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
+				     const char *cmd_buf)
+{
+#define HCLGE_MAX_QSET_NUM 1024
+
+	u16 qsid;
+	int ret;
+
+	ret = kstrtou16(cmd_buf, 0, &qsid);
+	if (ret) {
+		hclge_dbg_dump_qs_shaper_all(hdev);
+		return;
+	}
+
+	if (qsid >= HCLGE_MAX_QSET_NUM) {
+		dev_err(&hdev->pdev->dev, "qsid(%u) out of range[0-1023]\n",
+			qsid);
+		return;
+	}
+
+	hclge_dbg_dump_qs_shaper_single(hdev, qsid);
+}
+
 int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
 {
 #define DUMP_REG	"dump reg"
 #define DUMP_TM_MAP	"dump tm map"
+#define DUMP_LOOPBACK	"dump loopback"
 
 	struct hclge_vport *vport = hclge_get_vport(handle);
 	struct hclge_dev *hdev = vport->back;
@@ -1138,6 +1357,8 @@
 		hclge_dbg_dump_reg_cmd(hdev, &cmd_buf[sizeof(DUMP_REG)]);
 	} else if (strncmp(cmd_buf, "dump reset info", 15) == 0) {
 		hclge_dbg_dump_rst_info(hdev);
+	} else if (strncmp(cmd_buf, "dump serv info", 14) == 0) {
+		hclge_dbg_dump_serv_info(hdev);
 	} else if (strncmp(cmd_buf, "dump m7 info", 12) == 0) {
 		hclge_dbg_get_m7_stats_info(hdev);
 	} else if (strncmp(cmd_buf, "dump ncl_config", 15) == 0) {
@@ -1145,6 +1366,12 @@
 					  &cmd_buf[sizeof("dump ncl_config")]);
 	} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
 		hclge_dbg_dump_mac_tnl_status(hdev);
+	} else if (strncmp(cmd_buf, DUMP_LOOPBACK,
+		   strlen(DUMP_LOOPBACK)) == 0) {
+		hclge_dbg_dump_loopback(hdev, &cmd_buf[sizeof(DUMP_LOOPBACK)]);
+	} else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
+		hclge_dbg_dump_qs_shaper(hdev,
+					 &cmd_buf[sizeof("dump qs shaper")]);
 	} else {
 		dev_info(&hdev->pdev->dev, "unknown command\n");
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
@@ -35,8 +35,6 @@
 
 #define HCLGE_DBG_DFX_SSU_2_OFFSET 12
 
-#pragma pack(1)
-
 struct hclge_qos_pri_map_cmd {
 	u8 pri0_tc  : 4,
 	   pri1_tc  : 4;
@@ -85,8 +83,6 @@
 	struct hclge_dbg_reg_common_msg reg_msg;
 };
 
-#pragma pack()
-
 static struct hclge_dbg_dfx_message hclge_dbg_bios_common_reg[] = {
 	{false, "Reserved"},
 	{true,	"BP_CPU_STATE"},
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
@@ -505,7 +505,7 @@
 
 static const struct hclge_hw_error hclge_ssu_port_based_err_int[] = {
 	{ .int_msk = BIT(0), .msg = "roc_pkt_without_key_port",
-	  .reset_level = HNAE3_GLOBAL_RESET },
+	  .reset_level = HNAE3_FUNC_RESET },
 	{ .int_msk = BIT(1), .msg = "tpu_pkt_without_key_port",
 	  .reset_level = HNAE3_GLOBAL_RESET },
 	{ .int_msk = BIT(2), .msg = "igu_pkt_without_key_port",
@@ -599,7 +599,7 @@
 
 static const struct hclge_hw_error hclge_ssu_port_based_pf_int[] = {
 	{ .int_msk = BIT(0), .msg = "roc_pkt_without_key_port",
-	  .reset_level = HNAE3_GLOBAL_RESET },
+	  .reset_level = HNAE3_FUNC_RESET },
 	{ .int_msk = BIT(9), .msg = "low_water_line_err_port",
 	  .reset_level = HNAE3_NONE_RESET },
 	{ .int_msk = BIT(10), .msg = "hi_water_line_err_port",
@@ -753,8 +753,9 @@
 
 	/* configure IGU,EGU error interrupts */
 	hclge_cmd_setup_basic_desc(&desc, HCLGE_IGU_COMMON_INT_EN, false);
+	desc.data[0] = cpu_to_le32(HCLGE_IGU_ERR_INT_TYPE);
 	if (en)
-		desc.data[0] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN);
+		desc.data[0] |= cpu_to_le32(HCLGE_IGU_ERR_INT_EN);
 
 	desc.data[1] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN_MASK);
 
@@ -1667,9 +1668,6 @@
 		hclge_handle_rocee_ras_error(ae_dev);
 	}
 
-	if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
-		goto out;
-
 	if (ae_dev->hw_err_reset_req)
 		return PCI_ERS_RESULT_NEED_RESET;
 
@@ -1747,7 +1745,7 @@
 
 	if (vf_id) {
 		if (vf_id >= hdev->num_alloc_vport) {
-			dev_err(dev, "invalid vf id(%d)\n", vf_id);
+			dev_err(dev, "invalid vf id(%u)\n", vf_id);
 			return;
 		}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
@@ -33,7 +33,8 @@
 #define HCLGE_TQP_ECC_ERR_INT_EN_MASK	0x0FFF
 #define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN_MASK	0x0F000000
 #define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN	0x0F000000
-#define HCLGE_IGU_ERR_INT_EN	0x0000066F
+#define HCLGE_IGU_ERR_INT_EN	0x0000000F
+#define HCLGE_IGU_ERR_INT_TYPE	0x00000660
 #define HCLGE_IGU_ERR_INT_EN_MASK	0x000F
 #define HCLGE_IGU_TNL_ERR_INT_EN    0x0002AABF
 #define HCLGE_IGU_TNL_ERR_INT_EN_MASK  0x003F
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -55,6 +55,8 @@
 
 #define HCLGE_LINK_STATUS_MS	10
 
+#define HCLGE_VF_VPORT_START_NUM	1
+
 static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps);
 static int hclge_init_vlan_config(struct hclge_dev *hdev);
 static void hclge_sync_vlan_filter(struct hclge_dev *hdev);
@@ -70,6 +72,8 @@
 
 static struct hnae3_ae_algo ae_algo;
 
+static struct workqueue_struct *hclge_wq;
+
 static const struct pci_device_id ae_algo_pci_tbl[] = {
 	{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0},
 	{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0},
@@ -323,8 +327,7 @@
 	{
 		.flags = HCLGE_MAC_MGR_MASK_VLAN_B,
 		.ethter_type = cpu_to_le16(ETH_P_LLDP),
-		.mac_addr_hi32 = cpu_to_le32(htonl(0x0180C200)),
-		.mac_addr_lo16 = cpu_to_le16(htons(0x000E)),
+		.mac_addr = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e},
 		.i_port_bitmap = 0x1,
 	},
 };
@@ -415,7 +418,7 @@
 {
 #define HCLGE_MAC_CMD_NUM 21
 
-	u64 *data = (u64 *)(&hdev->hw_stats.mac_stats);
+	u64 *data = (u64 *)(&hdev->mac_stats);
 	struct hclge_desc desc[HCLGE_MAC_CMD_NUM];
 	__le64 *desc_data;
 	int i, k, n;
@@ -452,7 +455,7 @@
 
 static int hclge_mac_update_stats_complete(struct hclge_dev *hdev, u32 desc_num)
 {
-	u64 *data = (u64 *)(&hdev->hw_stats.mac_stats);
+	u64 *data = (u64 *)(&hdev->mac_stats);
 	struct hclge_desc *desc;
 	__le64 *desc_data;
 	u16 i, k, n;
@@ -746,7 +749,8 @@
 		handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK;
 		handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK;
 
-		if (hdev->hw.mac.phydev) {
+		if (hdev->hw.mac.phydev && hdev->hw.mac.phydev->drv &&
+		    hdev->hw.mac.phydev->drv->set_loopback) {
 			count += 1;
 			handle->flags |= HNAE3_SUPPORT_PHY_LOOPBACK;
 		}
@@ -801,7 +805,7 @@
 	struct hclge_dev *hdev = vport->back;
 	u64 *p;
 
-	p = hclge_comm_get_stats(&hdev->hw_stats.mac_stats, g_mac_stats_string,
+	p = hclge_comm_get_stats(&hdev->mac_stats, g_mac_stats_string,
 				 ARRAY_SIZE(g_mac_stats_string), data);
 	p = hclge_tqps_get_stats(handle, p);
 }
@@ -814,13 +818,15 @@
 
 	hclge_update_stats(handle, NULL);
 
-	mac_stats->tx_pause_cnt = hdev->hw_stats.mac_stats.mac_tx_mac_pause_num;
-	mac_stats->rx_pause_cnt = hdev->hw_stats.mac_stats.mac_rx_mac_pause_num;
+	mac_stats->tx_pause_cnt = hdev->mac_stats.mac_tx_mac_pause_num;
+	mac_stats->rx_pause_cnt = hdev->mac_stats.mac_rx_mac_pause_num;
 }
 
 static int hclge_parse_func_status(struct hclge_dev *hdev,
 				   struct hclge_func_status_cmd *status)
 {
+#define HCLGE_MAC_ID_MASK	0xF
+
 	if (!(status->pf_state & HCLGE_PF_STATE_DONE))
 		return -EINVAL;
 
@@ -830,6 +836,7 @@
 	else
 		hdev->flag &= ~HCLGE_FLAG_MAIN;
 
+	hdev->hw.mac.mac_id = status->mac_id & HCLGE_MAC_ID_MASK;
 	return 0;
 }
 
@@ -1194,6 +1201,35 @@
 		hclge_parse_backplane_link_mode(hdev, speed_ability);
 }
 
+static u32 hclge_get_max_speed(u8 speed_ability)
+{
+	if (speed_ability & HCLGE_SUPPORT_100G_BIT)
+		return HCLGE_MAC_SPEED_100G;
+
+	if (speed_ability & HCLGE_SUPPORT_50G_BIT)
+		return HCLGE_MAC_SPEED_50G;
+
+	if (speed_ability & HCLGE_SUPPORT_40G_BIT)
+		return HCLGE_MAC_SPEED_40G;
+
+	if (speed_ability & HCLGE_SUPPORT_25G_BIT)
+		return HCLGE_MAC_SPEED_25G;
+
+	if (speed_ability & HCLGE_SUPPORT_10G_BIT)
+		return HCLGE_MAC_SPEED_10G;
+
+	if (speed_ability & HCLGE_SUPPORT_1G_BIT)
+		return HCLGE_MAC_SPEED_1G;
+
+	if (speed_ability & HCLGE_SUPPORT_100M_BIT)
+		return HCLGE_MAC_SPEED_100M;
+
+	if (speed_ability & HCLGE_SUPPORT_10M_BIT)
+		return HCLGE_MAC_SPEED_10M;
+
+	return HCLGE_MAC_SPEED_1G;
+}
+
 static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
 {
 	struct hclge_cfg_param_cmd *req;
@@ -1327,9 +1363,10 @@
 
 static int hclge_configure(struct hclge_dev *hdev)
 {
+	const struct cpumask *cpumask = cpu_online_mask;
 	struct hclge_cfg cfg;
 	unsigned int i;
-	int ret;
+	int node, ret;
 
 	ret = hclge_get_cfg(hdev, &cfg);
 	if (ret) {
@@ -1364,9 +1401,11 @@
 
 	hclge_parse_link_mode(hdev, cfg.speed_ability);
 
+	hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability);
+
 	if ((hdev->tc_max > HNAE3_MAX_TC) ||
 	    (hdev->tc_max < 1)) {
-		dev_warn(&hdev->pdev->dev, "TC num = %d.\n",
+		dev_warn(&hdev->pdev->dev, "TC num = %u.\n",
 			 hdev->tc_max);
 		hdev->tc_max = 1;
 	}
@@ -1389,11 +1428,12 @@
 
 	hclge_init_kdump_kernel_config(hdev);
 
-	/* Set the init affinity based on pci func number */
-	i = cpumask_weight(cpumask_of_node(dev_to_node(&hdev->pdev->dev)));
-	i = i ? PCI_FUNC(hdev->pdev->devfn) % i : 0;
-	cpumask_set_cpu(cpumask_local_spread(i, dev_to_node(&hdev->pdev->dev)),
-			&hdev->affinity_mask);
+	/* Set the affinity based on numa node */
+	node = dev_to_node(&hdev->pdev->dev);
+	if (node != NUMA_NO_NODE)
+		cpumask = cpumask_of_node(node);
+
+	cpumask_copy(&hdev->affinity_mask, cpumask);
 
 	return ret;
 }
@@ -1626,7 +1666,7 @@
 	num_vport = hdev->num_vmdq_vport + hdev->num_req_vfs + 1;
 
 	if (hdev->num_tqps < num_vport) {
-		dev_err(&hdev->pdev->dev, "tqps(%d) is less than vports(%d)",
+		dev_err(&hdev->pdev->dev, "tqps(%u) is less than vports(%d)",
 			hdev->num_tqps, num_vport);
 		return -EINVAL;
 	}
@@ -1649,6 +1689,7 @@
 	for (i = 0; i < num_vport; i++) {
 		vport->back = hdev;
 		vport->vport_id = i;
+		vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO;
 		vport->mps = HCLGE_MAC_DEFAULT_FRAME;
 		vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE;
 		vport->rxvlan_cfg.rx_vlan_offload_en = true;
@@ -2312,7 +2353,7 @@
 	}
 	if (vectors < hdev->num_msi)
 		dev_warn(&hdev->pdev->dev,
-			 "requested %d MSI/MSI-X, but allocated %d MSI/MSI-X\n",
+			 "requested %u MSI/MSI-X, but allocated %d MSI/MSI-X\n",
 			 hdev->num_msi, vectors);
 
 	hdev->num_msi = vectors;
@@ -2417,10 +2458,12 @@
 
 int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex)
 {
+	struct hclge_mac *mac = &hdev->hw.mac;
 	int ret;
 
 	duplex = hclge_check_speed_dup(duplex, speed);
-	if (hdev->hw.mac.speed == speed && hdev->hw.mac.duplex == duplex)
+	if (!mac->support_autoneg && mac->speed == speed &&
+	    mac->duplex == duplex)
 		return 0;
 
 	ret = hclge_cfg_mac_speed_dup_hw(hdev, speed, duplex);
@@ -2632,31 +2675,27 @@
 
 static void hclge_mbx_task_schedule(struct hclge_dev *hdev)
 {
-	if (!test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state) &&
+	if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
 	    !test_and_set_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state))
-		queue_work_on(cpumask_first(&hdev->affinity_mask), system_wq,
-			      &hdev->mbx_service_task);
+		mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
+				    hclge_wq, &hdev->service_task, 0);
 }
 
 static void hclge_reset_task_schedule(struct hclge_dev *hdev)
 {
 	if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
 	    !test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
-		queue_work_on(cpumask_first(&hdev->affinity_mask), system_wq,
-			      &hdev->rst_service_task);
+		mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
+				    hclge_wq, &hdev->service_task, 0);
 }
 
 void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time)
 {
-	if (!test_bit(HCLGE_STATE_DOWN, &hdev->state) &&
-	    !test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
-	    !test_and_set_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state)) {
-		hdev->hw_stats.stats_timer++;
-		hdev->fd_arfs_expire_timer++;
+	if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
+	    !test_bit(HCLGE_STATE_RST_FAIL, &hdev->state))
 		mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
-				    system_wq, &hdev->service_task,
+				    hclge_wq, &hdev->service_task,
 				    delay_time);
-	}
 }
 
 static int hclge_get_mac_link_status(struct hclge_dev *hdev)
@@ -2715,6 +2754,10 @@
 
 	if (!client)
 		return;
+
+	if (test_and_set_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state))
+		return;
+
 	state = hclge_get_mac_phy_link(hdev);
 	if (state != hdev->hw.mac.link) {
 		for (i = 0; i < hdev->num_vmdq_vport + 1; i++) {
@@ -2728,6 +2771,8 @@
 		}
 		hdev->hw.mac.link = state;
 	}
+
+	clear_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state);
 }
 
 static void hclge_update_port_capability(struct hclge_mac *mac)
@@ -2744,7 +2789,7 @@
 	else if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER)
 		mac->module_type = HNAE3_MODULE_TYPE_TP;
 
-	if (mac->support_autoneg == true) {
+	if (mac->support_autoneg) {
 		linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported);
 		linkmode_copy(mac->advertising, mac->supported);
 	} else {
@@ -2798,6 +2843,12 @@
 		return ret;
 	}
 
+	/* In some case, mac speed get from IMP may be 0, it shouldn't be
+	 * set to mac->speed.
+	 */
+	if (!le32_to_cpu(resp->speed))
+		return 0;
+
 	mac->speed = le32_to_cpu(resp->speed);
 	/* if resp->speed_ability is 0, it means it's an old version
 	 * firmware, do not update these params
@@ -2871,6 +2922,65 @@
 	return hdev->hw.mac.link;
 }
 
+static struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf)
+{
+	if (pci_num_vf(hdev->pdev) == 0) {
+		dev_err(&hdev->pdev->dev,
+			"SRIOV is disabled, can not get vport(%d) info.\n", vf);
+		return NULL;
+	}
+
+	if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) {
+		dev_err(&hdev->pdev->dev,
+			"vf id(%d) is out of range(0 <= vfid < %d)\n",
+			vf, pci_num_vf(hdev->pdev));
+		return NULL;
+	}
+
+	/* VF start from 1 in vport */
+	vf += HCLGE_VF_VPORT_START_NUM;
+	return &hdev->vport[vf];
+}
+
+static int hclge_get_vf_config(struct hnae3_handle *handle, int vf,
+			       struct ifla_vf_info *ivf)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	ivf->vf = vf;
+	ivf->linkstate = vport->vf_info.link_state;
+	ivf->spoofchk = vport->vf_info.spoofchk;
+	ivf->trusted = vport->vf_info.trusted;
+	ivf->min_tx_rate = 0;
+	ivf->max_tx_rate = vport->vf_info.max_tx_rate;
+	ivf->vlan = vport->port_base_vlan_cfg.vlan_info.vlan_tag;
+	ivf->vlan_proto = htons(vport->port_base_vlan_cfg.vlan_info.vlan_proto);
+	ivf->qos = vport->port_base_vlan_cfg.vlan_info.qos;
+	ether_addr_copy(ivf->mac, vport->vf_info.mac);
+
+	return 0;
+}
+
+static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf,
+				   int link_state)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	vport->vf_info.link_state = link_state;
+
+	return 0;
+}
+
 static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
 {
 	u32 rst_src_reg, cmdq_src_reg, msix_src_reg;
@@ -2909,8 +3019,6 @@
 
 	/* check for vector0 msix event source */
 	if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK) {
-		dev_info(&hdev->pdev->dev, "received event 0x%x\n",
-			 msix_src_reg);
 		*clearval = msix_src_reg;
 		return HCLGE_VECTOR0_EVENT_ERR;
 	}
@@ -2934,8 +3042,13 @@
 static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type,
 				    u32 regclr)
 {
+#define HCLGE_IMP_RESET_DELAY		5
+
 	switch (event_type) {
 	case HCLGE_VECTOR0_EVENT_RST:
+		if (regclr == BIT(HCLGE_VECTOR0_IMPRESET_INT_B))
+			mdelay(HCLGE_IMP_RESET_DELAY);
+
 		hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, regclr);
 		break;
 	case HCLGE_VECTOR0_EVENT_MBX:
@@ -3083,8 +3196,10 @@
 	hclge_get_misc_vector(hdev);
 
 	/* this would be explicitly freed in the end */
+	snprintf(hdev->misc_vector.name, HNAE3_INT_NAME_LEN, "%s-misc-%s",
+		 HCLGE_NAME, pci_name(hdev->pdev));
 	ret = request_irq(hdev->misc_vector.vector_irq, hclge_misc_irq_handle,
-			  0, "hclge_misc", hdev);
+			  0, hdev->misc_vector.name, hdev);
 	if (ret) {
 		hclge_free_vector(hdev, 0);
 		dev_err(&hdev->pdev->dev, "request misc irq(%d) fail\n",
@@ -3158,7 +3273,8 @@
 static int hclge_reset_wait(struct hclge_dev *hdev)
 {
 #define HCLGE_RESET_WATI_MS	100
-#define HCLGE_RESET_WAIT_CNT	200
+#define HCLGE_RESET_WAIT_CNT	350
+
 	u32 val, reg, reg_bit;
 	u32 cnt = 0;
 
@@ -3175,8 +3291,6 @@
 		reg = HCLGE_FUN_RST_ING;
 		reg_bit = HCLGE_FUN_RST_ING_B;
 		break;
-	case HNAE3_FLR_RESET:
-		break;
 	default:
 		dev_err(&hdev->pdev->dev,
 			"Wait for unsupported reset type: %d\n",
@@ -3184,20 +3298,6 @@
 		return -EINVAL;
 	}
 
-	if (hdev->reset_type == HNAE3_FLR_RESET) {
-		while (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state) &&
-		       cnt++ < HCLGE_RESET_WAIT_CNT)
-			msleep(HCLGE_RESET_WATI_MS);
-
-		if (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state)) {
-			dev_err(&hdev->pdev->dev,
-				"flr wait timeout: %d\n", cnt);
-			return -EBUSY;
-		}
-
-		return 0;
-	}
-
 	val = hclge_read_dev(&hdev->hw, reg);
 	while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) {
 		msleep(HCLGE_RESET_WATI_MS);
@@ -3241,7 +3341,7 @@
 		ret = hclge_set_vf_rst(hdev, vport->vport_id, reset);
 		if (ret) {
 			dev_err(&hdev->pdev->dev,
-				"set vf(%d) rst failed %d!\n",
+				"set vf(%u) rst failed %d!\n",
 				vport->vport_id, ret);
 			return ret;
 		}
@@ -3256,14 +3356,26 @@
 		ret = hclge_inform_reset_assert_to_vf(vport);
 		if (ret)
 			dev_warn(&hdev->pdev->dev,
-				 "inform reset to vf(%d) failed %d!\n",
+				 "inform reset to vf(%u) failed %d!\n",
 				 vport->vport_id, ret);
 	}
 
 	return 0;
 }
 
-static int hclge_func_reset_sync_vf(struct hclge_dev *hdev)
+static void hclge_mailbox_service_task(struct hclge_dev *hdev)
+{
+	if (!test_and_clear_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state) ||
+	    test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state) ||
+	    test_and_set_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state))
+		return;
+
+	hclge_mbx_handler(hdev);
+
+	clear_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state);
+}
+
+static void hclge_func_reset_sync_vf(struct hclge_dev *hdev)
 {
 	struct hclge_pf_rst_sync_cmd *req;
 	struct hclge_desc desc;
@@ -3274,26 +3386,28 @@
 	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_VF_RST_RDY, true);
 
 	do {
+		/* vf need to down netdev by mbx during PF or FLR reset */
+		hclge_mailbox_service_task(hdev);
+
 		ret = hclge_cmd_send(&hdev->hw, &desc, 1);
 		/* for compatible with old firmware, wait
 		 * 100 ms for VF to stop IO
 		 */
 		if (ret == -EOPNOTSUPP) {
 			msleep(HCLGE_RESET_SYNC_TIME);
-			return 0;
+			return;
 		} else if (ret) {
-			dev_err(&hdev->pdev->dev, "sync with VF fail %d!\n",
-				ret);
-			return ret;
+			dev_warn(&hdev->pdev->dev, "sync with VF fail %d!\n",
+				 ret);
+			return;
 		} else if (req->all_vf_ready) {
-			return 0;
+			return;
 		}
 		msleep(HCLGE_PF_RESET_SYNC_TIME);
 		hclge_cmd_reuse_desc(&desc, true);
 	} while (cnt++ < HCLGE_PF_RESET_SYNC_CNT);
 
-	dev_err(&hdev->pdev->dev, "sync with VF timeout!\n");
-	return -ETIME;
+	dev_warn(&hdev->pdev->dev, "sync with VF timeout!\n");
 }
 
 void hclge_report_hw_error(struct hclge_dev *hdev,
@@ -3353,7 +3467,7 @@
 	u32 val;
 
 	if (hclge_get_hw_reset_stat(handle)) {
-		dev_info(&pdev->dev, "Hardware reset not finish\n");
+		dev_info(&pdev->dev, "hardware reset not finish\n");
 		dev_info(&pdev->dev, "func_rst_reg:0x%x, global_rst_reg:0x%x\n",
 			 hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING),
 			 hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
@@ -3362,26 +3476,20 @@
 
 	switch (hdev->reset_type) {
 	case HNAE3_GLOBAL_RESET:
+		dev_info(&pdev->dev, "global reset requested\n");
 		val = hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG);
 		hnae3_set_bit(val, HCLGE_GLOBAL_RESET_BIT, 1);
 		hclge_write_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG, val);
-		dev_info(&pdev->dev, "Global Reset requested\n");
 		break;
 	case HNAE3_FUNC_RESET:
-		dev_info(&pdev->dev, "PF Reset requested\n");
+		dev_info(&pdev->dev, "PF reset requested\n");
 		/* schedule again to check later */
 		set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending);
 		hclge_reset_task_schedule(hdev);
 		break;
-	case HNAE3_FLR_RESET:
-		dev_info(&pdev->dev, "FLR requested\n");
-		/* schedule again to check later */
-		set_bit(HNAE3_FLR_RESET, &hdev->reset_pending);
-		hclge_reset_task_schedule(hdev);
-		break;
 	default:
 		dev_warn(&pdev->dev,
-			 "Unsupported reset type: %d\n", hdev->reset_type);
+			 "unsupported reset type: %d\n", hdev->reset_type);
 		break;
 	}
 }
@@ -3394,10 +3502,15 @@
 
 	/* first, resolve any unknown reset type to the known type(s) */
 	if (test_bit(HNAE3_UNKNOWN_RESET, addr)) {
+		u32 msix_sts_reg = hclge_read_dev(&hdev->hw,
+					HCLGE_VECTOR0_PF_OTHER_INT_STS_REG);
 		/* we will intentionally ignore any errors from this function
 		 *  as we will end up in *some* reset request in any case
 		 */
-		hclge_handle_hw_msix_error(hdev, addr);
+		if (hclge_handle_hw_msix_error(hdev, addr))
+			dev_info(&hdev->pdev->dev, "received msix interrupt 0x%x\n",
+				 msix_sts_reg);
+
 		clear_bit(HNAE3_UNKNOWN_RESET, addr);
 		/* We defered the clearing of the error event which caused
 		 * interrupt since it was not posssible to do that in
@@ -3462,23 +3575,6 @@
 	hclge_enable_vector(&hdev->misc_vector, true);
 }
 
-static int hclge_reset_prepare_down(struct hclge_dev *hdev)
-{
-	int ret = 0;
-
-	switch (hdev->reset_type) {
-	case HNAE3_FUNC_RESET:
-		/* fall through */
-	case HNAE3_FLR_RESET:
-		ret = hclge_set_all_vf_rst(hdev, true);
-		break;
-	default:
-		break;
-	}
-
-	return ret;
-}
-
 static void hclge_reset_handshake(struct hclge_dev *hdev, bool enable)
 {
 	u32 reg_val;
@@ -3492,6 +3588,19 @@
 	hclge_write_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG, reg_val);
 }
 
+static int hclge_func_reset_notify_vf(struct hclge_dev *hdev)
+{
+	int ret;
+
+	ret = hclge_set_all_vf_rst(hdev, true);
+	if (ret)
+		return ret;
+
+	hclge_func_reset_sync_vf(hdev);
+
+	return 0;
+}
+
 static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
 {
 	u32 reg_val;
@@ -3499,10 +3608,7 @@
 
 	switch (hdev->reset_type) {
 	case HNAE3_FUNC_RESET:
-		/* to confirm whether all running VF is ready
-		 * before request PF reset
-		 */
-		ret = hclge_func_reset_sync_vf(hdev);
+		ret = hclge_func_reset_notify_vf(hdev);
 		if (ret)
 			return ret;
 
@@ -3522,16 +3628,9 @@
 		hdev->rst_stats.pf_rst_cnt++;
 		break;
 	case HNAE3_FLR_RESET:
-		/* to confirm whether all running VF is ready
-		 * before request PF reset
-		 */
-		ret = hclge_func_reset_sync_vf(hdev);
+		ret = hclge_func_reset_notify_vf(hdev);
 		if (ret)
 			return ret;
-
-		set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
-		set_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
-		hdev->rst_stats.flr_rst_cnt++;
 		break;
 	case HNAE3_IMP_RESET:
 		hclge_handle_imp_error(hdev);
@@ -3569,7 +3668,7 @@
 		hdev->rst_stats.reset_fail_cnt++;
 		set_bit(hdev->reset_type, &hdev->reset_pending);
 		dev_info(&hdev->pdev->dev,
-			 "re-schedule reset task(%d)\n",
+			 "re-schedule reset task(%u)\n",
 			 hdev->rst_stats.reset_fail_cnt);
 		return true;
 	}
@@ -3580,6 +3679,11 @@
 	hclge_reset_handshake(hdev, true);
 
 	dev_err(&hdev->pdev->dev, "Reset fail!\n");
+
+	hclge_dbg_dump_rst_info(hdev);
+
+	set_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
+
 	return false;
 }
 
@@ -3655,10 +3759,9 @@
 	return hclge_notify_client(hdev, HNAE3_RESTORE_CLIENT);
 }
 
-static void hclge_reset(struct hclge_dev *hdev)
+static int hclge_reset_prepare(struct hclge_dev *hdev)
 {
 	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
-	enum hnae3_reset_type reset_level;
 	int ret;
 
 	/* Initialize ae_dev reset status as well, in case enet layer wants to
@@ -3669,45 +3772,41 @@
 	/* perform reset of the stack & ae device for a client */
 	ret = hclge_notify_roce_client(hdev, HNAE3_DOWN_CLIENT);
 	if (ret)
-		goto err_reset;
-
-	ret = hclge_reset_prepare_down(hdev);
-	if (ret)
-		goto err_reset;
+		return ret;
 
 	rtnl_lock();
 	ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
-	if (ret)
-		goto err_reset_lock;
-
 	rtnl_unlock();
-
-	ret = hclge_reset_prepare_wait(hdev);
 	if (ret)
-		goto err_reset;
+		return ret;
 
-	if (hclge_reset_wait(hdev))
-		goto err_reset;
+	return hclge_reset_prepare_wait(hdev);
+}
+
+static int hclge_reset_rebuild(struct hclge_dev *hdev)
+{
+	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+	enum hnae3_reset_type reset_level;
+	int ret;
 
 	hdev->rst_stats.hw_reset_done_cnt++;
 
 	ret = hclge_notify_roce_client(hdev, HNAE3_UNINIT_CLIENT);
 	if (ret)
-		goto err_reset;
+		return ret;
 
 	rtnl_lock();
-
 	ret = hclge_reset_stack(hdev);
+	rtnl_unlock();
 	if (ret)
-		goto err_reset_lock;
+		return ret;
 
 	hclge_clear_reset_cause(hdev);
 
 	ret = hclge_reset_prepare_up(hdev);
 	if (ret)
-		goto err_reset_lock;
+		return ret;
 
-	rtnl_unlock();
 
 	ret = hclge_notify_roce_client(hdev, HNAE3_INIT_CLIENT);
 	/* ignore RoCE notify error if it fails HCLGE_RESET_MAX_FAIL_CNT - 1
@@ -3715,24 +3814,23 @@
 	 */
 	if (ret &&
 	    hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1)
-		goto err_reset;
+		return ret;
 
 	rtnl_lock();
-
 	ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT);
-	if (ret)
-		goto err_reset_lock;
-
 	rtnl_unlock();
+	if (ret)
+		return ret;
 
 	ret = hclge_notify_roce_client(hdev, HNAE3_UP_CLIENT);
 	if (ret)
-		goto err_reset;
+		return ret;
 
 	hdev->last_reset_time = jiffies;
 	hdev->rst_stats.reset_fail_cnt = 0;
 	hdev->rst_stats.reset_done_cnt++;
 	ae_dev->reset_type = HNAE3_NONE_RESET;
+	clear_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
 
 	/* if default_reset_request has a higher level reset request,
 	 * it should be handled as soon as possible. since some errors
@@ -3743,10 +3841,22 @@
 	if (reset_level != HNAE3_NONE_RESET)
 		set_bit(reset_level, &hdev->reset_request);
 
+	return 0;
+}
+
+static void hclge_reset(struct hclge_dev *hdev)
+{
+	if (hclge_reset_prepare(hdev))
+		goto err_reset;
+
+	if (hclge_reset_wait(hdev))
+		goto err_reset;
+
+	if (hclge_reset_rebuild(hdev))
+		goto err_reset;
+
 	return;
 
-err_reset_lock:
-	rtnl_unlock();
 err_reset:
 	if (hclge_reset_err_handle(hdev))
 		hclge_reset_task_schedule(hdev);
@@ -3779,12 +3889,13 @@
 				  HCLGE_RESET_INTERVAL))) {
 		mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL);
 		return;
-	} else if (hdev->default_reset_request)
+	} else if (hdev->default_reset_request) {
 		hdev->reset_level =
 			hclge_get_reset_level(ae_dev,
 					      &hdev->default_reset_request);
-	else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ)))
+	} else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ))) {
 		hdev->reset_level = HNAE3_FUNC_RESET;
+	}
 
 	dev_info(&hdev->pdev->dev, "received reset event, reset type is %d\n",
 		 hdev->reset_level);
@@ -3846,34 +3957,18 @@
 	hdev->reset_type = HNAE3_NONE_RESET;
 }
 
-static void hclge_reset_service_task(struct work_struct *work)
+static void hclge_reset_service_task(struct hclge_dev *hdev)
 {
-	struct hclge_dev *hdev =
-		container_of(work, struct hclge_dev, rst_service_task);
-
-	if (test_and_set_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+	if (!test_and_clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
 		return;
 
-	clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state);
+	down(&hdev->reset_sem);
+	set_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
 
 	hclge_reset_subtask(hdev);
 
 	clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
-}
-
-static void hclge_mailbox_service_task(struct work_struct *work)
-{
-	struct hclge_dev *hdev =
-		container_of(work, struct hclge_dev, mbx_service_task);
-
-	if (test_and_set_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state))
-		return;
-
-	clear_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state);
-
-	hclge_mbx_handler(hdev);
-
-	clear_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state);
+	up(&hdev->reset_sem);
 }
 
 static void hclge_update_vport_alive(struct hclge_dev *hdev)
@@ -3893,28 +3988,62 @@
 	}
 }
 
-static void hclge_service_task(struct work_struct *work)
+static void hclge_periodic_service_task(struct hclge_dev *hdev)
 {
-	struct hclge_dev *hdev =
-		container_of(work, struct hclge_dev, service_task.work);
+	unsigned long delta = round_jiffies_relative(HZ);
 
-	clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state);
+	/* Always handle the link updating to make sure link state is
+	 * updated when it is triggered by mbx.
+	 */
+	hclge_update_link_status(hdev);
 
-	if (hdev->hw_stats.stats_timer >= HCLGE_STATS_TIMER_INTERVAL) {
-		hclge_update_stats_for_all(hdev);
-		hdev->hw_stats.stats_timer = 0;
+	if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) {
+		delta = jiffies - hdev->last_serv_processed;
+
+		if (delta < round_jiffies_relative(HZ)) {
+			delta = round_jiffies_relative(HZ) - delta;
+			goto out;
+		}
 	}
 
-	hclge_update_port_info(hdev);
-	hclge_update_link_status(hdev);
+	hdev->serv_processed_cnt++;
 	hclge_update_vport_alive(hdev);
+
+	if (test_bit(HCLGE_STATE_DOWN, &hdev->state)) {
+		hdev->last_serv_processed = jiffies;
+		goto out;
+	}
+
+	if (!(hdev->serv_processed_cnt % HCLGE_STATS_TIMER_INTERVAL))
+		hclge_update_stats_for_all(hdev);
+
+	hclge_update_port_info(hdev);
 	hclge_sync_vlan_filter(hdev);
-	if (hdev->fd_arfs_expire_timer >= HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL) {
+
+	if (!(hdev->serv_processed_cnt % HCLGE_ARFS_EXPIRE_INTERVAL))
 		hclge_rfs_filter_expire(hdev);
-		hdev->fd_arfs_expire_timer = 0;
-	}
 
-	hclge_task_schedule(hdev, round_jiffies_relative(HZ));
+	hdev->last_serv_processed = jiffies;
+
+out:
+	hclge_task_schedule(hdev, delta);
+}
+
+static void hclge_service_task(struct work_struct *work)
+{
+	struct hclge_dev *hdev =
+		container_of(work, struct hclge_dev, service_task.work);
+
+	hclge_reset_service_task(hdev);
+	hclge_mailbox_service_task(hdev);
+	hclge_periodic_service_task(hdev);
+
+	/* Handle reset and mbx again in case periodical task delays the
+	 * handling by calling hclge_task_schedule() in
+	 * hclge_periodic_service_task().
+	 */
+	hclge_reset_service_task(hdev);
+	hclge_mailbox_service_task(hdev);
 }
 
 struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle)
@@ -3985,7 +4114,7 @@
 	vector_id = hclge_get_vector_index(hdev, vector);
 	if (vector_id < 0) {
 		dev_err(&hdev->pdev->dev,
-			"Get vector index fail. vector_id =%d\n", vector_id);
+			"Get vector index fail. vector = %d\n", vector);
 		return vector_id;
 	}
 
@@ -4415,7 +4544,7 @@
 	 */
 	if (rss_size > HCLGE_RSS_TC_SIZE_7 || rss_size == 0) {
 		dev_err(&hdev->pdev->dev,
-			"Configure rss tc size failed, invalid TC_SIZE = %d\n",
+			"Configure rss tc size failed, invalid TC_SIZE = %u\n",
 			rss_size);
 		return -EINVAL;
 	}
@@ -4560,7 +4689,7 @@
 	vector_id = hclge_get_vector_index(hdev, vector);
 	if (vector_id < 0) {
 		dev_err(&hdev->pdev->dev,
-			"Get vector index fail. vector_id =%d\n", vector_id);
+			"failed to get vector index. vector=%d\n", vector);
 		return vector_id;
 	}
 
@@ -4593,8 +4722,8 @@
 	return ret;
 }
 
-int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
-			       struct hclge_promisc_param *param)
+static int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
+				      struct hclge_promisc_param *param)
 {
 	struct hclge_promisc_cfg_cmd *req;
 	struct hclge_desc desc;
@@ -4621,8 +4750,9 @@
 	return ret;
 }
 
-void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
-			      bool en_mc, bool en_bc, int vport_id)
+static void hclge_promisc_param_init(struct hclge_promisc_param *param,
+				     bool en_uc, bool en_mc, bool en_bc,
+				     int vport_id)
 {
 	if (!param)
 		return;
@@ -4637,12 +4767,21 @@
 	param->vf_id = vport_id;
 }
 
+int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc,
+				 bool en_mc_pmc, bool en_bc_pmc)
+{
+	struct hclge_dev *hdev = vport->back;
+	struct hclge_promisc_param param;
+
+	hclge_promisc_param_init(&param, en_uc_pmc, en_mc_pmc, en_bc_pmc,
+				 vport->vport_id);
+	return hclge_cmd_set_promisc_mode(hdev, &param);
+}
+
 static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
 				  bool en_mc_pmc)
 {
 	struct hclge_vport *vport = hclge_get_vport(handle);
-	struct hclge_dev *hdev = vport->back;
-	struct hclge_promisc_param param;
 	bool en_bc_pmc = true;
 
 	/* For revision 0x20, if broadcast promisc enabled, vlan filter is
@@ -4652,9 +4791,8 @@
 	if (handle->pdev->revision == 0x20)
 		en_bc_pmc = handle->netdev_flags & HNAE3_BPE ? true : false;
 
-	hclge_promisc_param_init(&param, en_uc_pmc, en_mc_pmc, en_bc_pmc,
-				 vport->vport_id);
-	return hclge_cmd_set_promisc_mode(hdev, &param);
+	return hclge_set_vport_promisc_mode(vport, en_uc_pmc, en_mc_pmc,
+					    en_bc_pmc);
 }
 
 static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode)
@@ -4756,7 +4894,7 @@
 		break;
 	default:
 		dev_err(&hdev->pdev->dev,
-			"Unsupported flow director mode %d\n",
+			"Unsupported flow director mode %u\n",
 			hdev->fd_cfg.fd_mode);
 		return -EOPNOTSUPP;
 	}
@@ -4905,9 +5043,9 @@
 	case BIT(INNER_SRC_MAC):
 		for (i = 0; i < ETH_ALEN; i++) {
 			calc_x(key_x[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
-			       rule->tuples.src_mac[i]);
+			       rule->tuples_mask.src_mac[i]);
 			calc_y(key_y[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
-			       rule->tuples.src_mac[i]);
+			       rule->tuples_mask.src_mac[i]);
 		}
 
 		return true;
@@ -5086,7 +5224,7 @@
 				   true);
 	if (ret) {
 		dev_err(&hdev->pdev->dev,
-			"fd key_y config fail, loc=%d, ret=%d\n",
+			"fd key_y config fail, loc=%u, ret=%d\n",
 			rule->queue_id, ret);
 		return ret;
 	}
@@ -5095,7 +5233,7 @@
 				   true);
 	if (ret)
 		dev_err(&hdev->pdev->dev,
-			"fd key_x config fail, loc=%d, ret=%d\n",
+			"fd key_x config fail, loc=%u, ret=%d\n",
 			rule->queue_id, ret);
 	return ret;
 }
@@ -5344,7 +5482,7 @@
 		}
 	} else if (!is_add) {
 		dev_err(&hdev->pdev->dev,
-			"delete fail, rule %d is inexistent\n",
+			"delete fail, rule %u is inexistent\n",
 			location);
 		return -EINVAL;
 	}
@@ -5584,7 +5722,7 @@
 
 		if (vf > hdev->num_req_vfs) {
 			dev_err(&hdev->pdev->dev,
-				"Error: vf id (%d) > max vf num (%d)\n",
+				"Error: vf id (%u) > max vf num (%u)\n",
 				vf, hdev->num_req_vfs);
 			return -EINVAL;
 		}
@@ -5594,7 +5732,7 @@
 
 		if (ring >= tqps) {
 			dev_err(&hdev->pdev->dev,
-				"Error: queue id (%d) > max tqp num (%d)\n",
+				"Error: queue id (%u) > max tqp num (%u)\n",
 				ring, tqps - 1);
 			return -EINVAL;
 		}
@@ -5625,9 +5763,9 @@
 	/* to avoid rule conflict, when user configure rule by ethtool,
 	 * we need to clear all arfs rules
 	 */
+	spin_lock_bh(&hdev->fd_rule_lock);
 	hclge_clear_arfs_rules(handle);
 
-	spin_lock_bh(&hdev->fd_rule_lock);
 	ret = hclge_fd_config_rule(hdev, rule);
 
 	spin_unlock_bh(&hdev->fd_rule_lock);
@@ -5653,7 +5791,7 @@
 
 	if (!hclge_fd_rule_exist(hdev, fs->location)) {
 		dev_err(&hdev->pdev->dev,
-			"Delete fail, rule %d is inexistent\n", fs->location);
+			"Delete fail, rule %u is inexistent\n", fs->location);
 		return -ENOENT;
 	}
 
@@ -5670,6 +5808,7 @@
 	return ret;
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
 				     bool clear_list)
 {
@@ -5682,7 +5821,6 @@
 	if (!hnae3_dev_fd_supported(hdev))
 		return;
 
-	spin_lock_bh(&hdev->fd_rule_lock);
 	for_each_set_bit(location, hdev->fd_bmap,
 			 hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
 		hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
@@ -5699,8 +5837,6 @@
 		bitmap_zero(hdev->fd_bmap,
 			    hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
 	}
-
-	spin_unlock_bh(&hdev->fd_rule_lock);
 }
 
 static int hclge_restore_fd_entries(struct hnae3_handle *handle)
@@ -5730,7 +5866,7 @@
 
 		if (ret) {
 			dev_warn(&hdev->pdev->dev,
-				 "Restore rule %d failed, remove it\n",
+				 "Restore rule %u failed, remove it\n",
 				 rule->location);
 			clear_bit(rule->location, hdev->fd_bmap);
 			hlist_del(&rule->rule_node);
@@ -5938,8 +6074,7 @@
 		fs->h_ext.vlan_tci = cpu_to_be16(rule->tuples.vlan_tag1);
 		fs->m_ext.vlan_tci =
 				rule->unused_tuple & BIT(INNER_VLAN_TAG_FST) ?
-				cpu_to_be16(VLAN_VID_MASK) :
-				cpu_to_be16(rule->tuples_mask.vlan_tag1);
+				0 : cpu_to_be16(rule->tuples_mask.vlan_tag1);
 	}
 
 	if (fs->flow_type & FLOW_MAC_EXT) {
@@ -6003,6 +6138,9 @@
 static void hclge_fd_get_flow_tuples(const struct flow_keys *fkeys,
 				     struct hclge_fd_rule_tuples *tuples)
 {
+#define flow_ip6_src fkeys->addrs.v6addrs.src.in6_u.u6_addr32
+#define flow_ip6_dst fkeys->addrs.v6addrs.dst.in6_u.u6_addr32
+
 	tuples->ether_proto = be16_to_cpu(fkeys->basic.n_proto);
 	tuples->ip_proto = fkeys->basic.ip_proto;
 	tuples->dst_port = be16_to_cpu(fkeys->ports.dst);
@@ -6011,12 +6149,12 @@
 		tuples->src_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.src);
 		tuples->dst_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.dst);
 	} else {
-		memcpy(tuples->src_ip,
-		       fkeys->addrs.v6addrs.src.in6_u.u6_addr32,
-		       sizeof(tuples->src_ip));
-		memcpy(tuples->dst_ip,
-		       fkeys->addrs.v6addrs.dst.in6_u.u6_addr32,
-		       sizeof(tuples->dst_ip));
+		int i;
+
+		for (i = 0; i < IPV6_SIZE; i++) {
+			tuples->src_ip[i] = be32_to_cpu(flow_ip6_src[i]);
+			tuples->dst_ip[i] = be32_to_cpu(flow_ip6_dst[i]);
+		}
 	}
 }
 
@@ -6064,7 +6202,7 @@
 				      u16 flow_id, struct flow_keys *fkeys)
 {
 	struct hclge_vport *vport = hclge_get_vport(handle);
-	struct hclge_fd_rule_tuples new_tuples;
+	struct hclge_fd_rule_tuples new_tuples = {};
 	struct hclge_dev *hdev = vport->back;
 	struct hclge_fd_rule *rule;
 	u16 tmp_queue_id;
@@ -6074,20 +6212,18 @@
 	if (!hnae3_dev_fd_supported(hdev))
 		return -EOPNOTSUPP;
 
-	memset(&new_tuples, 0, sizeof(new_tuples));
-	hclge_fd_get_flow_tuples(fkeys, &new_tuples);
-
-	spin_lock_bh(&hdev->fd_rule_lock);
-
 	/* when there is already fd rule existed add by user,
 	 * arfs should not work
 	 */
+	spin_lock_bh(&hdev->fd_rule_lock);
 	if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE) {
 		spin_unlock_bh(&hdev->fd_rule_lock);
 
 		return -EOPNOTSUPP;
 	}
 
+	hclge_fd_get_flow_tuples(fkeys, &new_tuples);
+
 	/* check is there flow director filter existed for this flow,
 	 * if not, create a new filter for it;
 	 * if filter exist with different queue id, modify the filter;
@@ -6172,6 +6308,7 @@
 #endif
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_clear_arfs_rules(struct hnae3_handle *handle)
 {
 #ifdef CONFIG_RFS_ACCEL
@@ -6216,10 +6353,14 @@
 
 	hdev->fd_en = enable;
 	clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE;
-	if (!enable)
+
+	if (!enable) {
+		spin_lock_bh(&hdev->fd_rule_lock);
 		hclge_del_all_fd_entries(handle, clear);
-	else
+		spin_unlock_bh(&hdev->fd_rule_lock);
+	} else {
 		hclge_restore_fd_entries(handle);
+	}
 }
 
 static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
@@ -6631,6 +6772,19 @@
 	}
 }
 
+static void hclge_flush_link_update(struct hclge_dev *hdev)
+{
+#define HCLGE_FLUSH_LINK_TIMEOUT	100000
+
+	unsigned long last = hdev->serv_processed_cnt;
+	int i = 0;
+
+	while (test_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state) &&
+	       i++ < HCLGE_FLUSH_LINK_TIMEOUT &&
+	       last == hdev->serv_processed_cnt)
+		usleep_range(1, 1);
+}
+
 static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable)
 {
 	struct hclge_vport *vport = hclge_get_vport(handle);
@@ -6639,12 +6793,12 @@
 	if (enable) {
 		hclge_task_schedule(hdev, round_jiffies_relative(HZ));
 	} else {
-		/* Set the DOWN flag here to disable the service to be
-		 * scheduled again
-		 */
+		/* Set the DOWN flag here to disable link updating */
 		set_bit(HCLGE_STATE_DOWN, &hdev->state);
-		cancel_delayed_work_sync(&hdev->service_task);
-		clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state);
+
+		/* flush memory to make sure DOWN is seen by service task */
+		smp_mb__before_atomic();
+		hclge_flush_link_update(hdev);
 	}
 }
 
@@ -6673,17 +6827,22 @@
 	int i;
 
 	set_bit(HCLGE_STATE_DOWN, &hdev->state);
-
+	spin_lock_bh(&hdev->fd_rule_lock);
 	hclge_clear_arfs_rules(handle);
+	spin_unlock_bh(&hdev->fd_rule_lock);
 
-	/* If it is not PF reset, the firmware will disable the MAC,
+	/* If it is not PF reset or FLR, the firmware will disable the MAC,
 	 * so it only need to stop phy here.
 	 */
-	if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) &&
-	    hdev->reset_type != HNAE3_FUNC_RESET) {
-		hclge_mac_stop_phy(hdev);
-		hclge_update_link_status(hdev);
-		return;
+	if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) {
+		hclge_pfc_pause_en_cfg(hdev, HCLGE_PFC_TX_RX_DISABLE,
+				       HCLGE_PFC_DISABLE);
+		if (hdev->reset_type != HNAE3_FUNC_RESET &&
+		    hdev->reset_type != HNAE3_FLR_RESET) {
+			hclge_mac_stop_phy(hdev);
+			hclge_update_link_status(hdev);
+			return;
+		}
 	}
 
 	for (i = 0; i < handle->kinfo.num_tqps; i++)
@@ -6735,7 +6894,7 @@
 
 	if (cmdq_resp) {
 		dev_err(&hdev->pdev->dev,
-			"cmdq execute failed for get_mac_vlan_cmd_status,status=%d.\n",
+			"cmdq execute failed for get_mac_vlan_cmd_status,status=%u.\n",
 			cmdq_resp);
 		return -EIO;
 	}
@@ -6987,7 +7146,7 @@
 
 	if (allocated_size < hdev->wanted_umv_size)
 		dev_warn(&hdev->pdev->dev,
-			 "Alloc umv space failed, want %d, get %d\n",
+			 "Alloc umv space failed, want %u, get %u\n",
 			 hdev->wanted_umv_size, allocated_size);
 
 	mutex_init(&hdev->umv_mutex);
@@ -7155,7 +7314,7 @@
 
 	/* check if we just hit the duplicate */
 	if (!ret) {
-		dev_warn(&hdev->pdev->dev, "VF %d mac(%pM) exists\n",
+		dev_warn(&hdev->pdev->dev, "VF %u mac(%pM) exists\n",
 			 vport->vport_id, addr);
 		return 0;
 	}
@@ -7225,7 +7384,6 @@
 		return -EINVAL;
 	}
 	memset(&req, 0, sizeof(req));
-	hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
 	hclge_prepare_mac_addr(&req, addr, true);
 	status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
 	if (status) {
@@ -7270,7 +7428,6 @@
 	}
 
 	memset(&req, 0, sizeof(req));
-	hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
 	hclge_prepare_mac_addr(&req, addr, true);
 	status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
 	if (!status) {
@@ -7336,7 +7493,7 @@
 	mc_flag = is_write_tbl && mac_type == HCLGE_MAC_ADDR_MC;
 
 	list_for_each_entry_safe(mac_cfg, tmp, list, node) {
-		if (strncmp(mac_cfg->mac_addr, mac_addr, ETH_ALEN) == 0) {
+		if (ether_addr_equal(mac_cfg->mac_addr, mac_addr)) {
 			if (uc_flag && mac_cfg->hd_tbl_status)
 				hclge_rm_uc_addr_common(vport, mac_addr);
 
@@ -7380,7 +7537,6 @@
 	struct hclge_vport *vport;
 	int i;
 
-	mutex_lock(&hdev->vport_cfg_mutex);
 	for (i = 0; i < hdev->num_alloc_vport; i++) {
 		vport = &hdev->vport[i];
 		list_for_each_entry_safe(mac, tmp, &vport->uc_mac_list, node) {
@@ -7393,7 +7549,6 @@
 			kfree(mac);
 		}
 	}
-	mutex_unlock(&hdev->vport_cfg_mutex);
 }
 
 static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev,
@@ -7408,7 +7563,7 @@
 
 	if (cmdq_resp) {
 		dev_err(&hdev->pdev->dev,
-			"cmdq execute failed for get_mac_ethertype_cmd_status, status=%d.\n",
+			"cmdq execute failed for get_mac_ethertype_cmd_status, status=%u.\n",
 			cmdq_resp);
 		return -EIO;
 	}
@@ -7430,7 +7585,7 @@
 		break;
 	default:
 		dev_err(&hdev->pdev->dev,
-			"add mac ethertype failed for undefined, code=%d.\n",
+			"add mac ethertype failed for undefined, code=%u.\n",
 			resp_code);
 		return_status = -EIO;
 	}
@@ -7438,6 +7593,73 @@
 	return return_status;
 }
 
+static bool hclge_check_vf_mac_exist(struct hclge_vport *vport, int vf_idx,
+				     u8 *mac_addr)
+{
+	struct hclge_mac_vlan_tbl_entry_cmd req;
+	struct hclge_dev *hdev = vport->back;
+	struct hclge_desc desc;
+	u16 egress_port = 0;
+	int i;
+
+	if (is_zero_ether_addr(mac_addr))
+		return false;
+
+	memset(&req, 0, sizeof(req));
+	hnae3_set_field(egress_port, HCLGE_MAC_EPORT_VFID_M,
+			HCLGE_MAC_EPORT_VFID_S, vport->vport_id);
+	req.egress_port = cpu_to_le16(egress_port);
+	hclge_prepare_mac_addr(&req, mac_addr, false);
+
+	if (hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false) != -ENOENT)
+		return true;
+
+	vf_idx += HCLGE_VF_VPORT_START_NUM;
+	for (i = hdev->num_vmdq_vport + 1; i < hdev->num_alloc_vport; i++)
+		if (i != vf_idx &&
+		    ether_addr_equal(mac_addr, hdev->vport[i].vf_info.mac))
+			return true;
+
+	return false;
+}
+
+static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf,
+			    u8 *mac_addr)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	if (ether_addr_equal(mac_addr, vport->vf_info.mac)) {
+		dev_info(&hdev->pdev->dev,
+			 "Specified MAC(=%pM) is same as before, no change committed!\n",
+			 mac_addr);
+		return 0;
+	}
+
+	if (hclge_check_vf_mac_exist(vport, vf, mac_addr)) {
+		dev_err(&hdev->pdev->dev, "Specified MAC(=%pM) exists!\n",
+			mac_addr);
+		return -EEXIST;
+	}
+
+	ether_addr_copy(vport->vf_info.mac, mac_addr);
+
+	if (test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) {
+		dev_info(&hdev->pdev->dev,
+			 "MAC of VF %d has been set to %pM, and it will be reinitialized!\n",
+			 vf, mac_addr);
+		return hclge_inform_reset_assert_to_vf(vport);
+	}
+
+	dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %pM\n",
+		 vf, mac_addr);
+	return 0;
+}
+
 static int hclge_add_mgr_tbl(struct hclge_dev *hdev,
 			     const struct hclge_mac_mgr_tbl_entry_cmd *req)
 {
@@ -7558,16 +7780,27 @@
 	struct hclge_desc desc;
 	int ret;
 
-	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_CTRL, false);
-
+	/* read current vlan filter parameter */
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_CTRL, true);
 	req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data;
 	req->vlan_type = vlan_type;
-	req->vlan_fe = filter_en ? fe_type : 0;
 	req->vf_id = vf_id;
 
 	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to get vlan filter config, ret = %d.\n", ret);
+		return ret;
+	}
+
+	/* modify and write new config parameter */
+	hclge_cmd_reuse_desc(&desc, false);
+	req->vlan_fe = filter_en ?
+			(req->vlan_fe | fe_type) : (req->vlan_fe & ~fe_type);
+
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
 	if (ret)
-		dev_err(&hdev->pdev->dev, "set vlan filter fail, ret =%d.\n",
+		dev_err(&hdev->pdev->dev, "failed to set vlan filter, ret = %d.\n",
 			ret);
 
 	return ret;
@@ -7610,7 +7843,7 @@
 				    bool is_kill, u16 vlan,
 				    __be16 proto)
 {
-#define HCLGE_MAX_VF_BYTES  16
+	struct hclge_vport *vport = &hdev->vport[vfid];
 	struct hclge_vlan_filter_vf_cfg_cmd *req0;
 	struct hclge_vlan_filter_vf_cfg_cmd *req1;
 	struct hclge_desc desc[2];
@@ -7619,10 +7852,18 @@
 	int ret;
 
 	/* if vf vlan table is full, firmware will close vf vlan filter, it
-	 * is unable and unnecessary to add new vlan id to vf vlan filter
+	 * is unable and unnecessary to add new vlan id to vf vlan filter.
+	 * If spoof check is enable, and vf vlan is full, it shouldn't add
+	 * new vlan, because tx packets with these vlan id will be dropped.
 	 */
-	if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill)
+	if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) {
+		if (vport->vf_info.spoofchk && vlan) {
+			dev_err(&hdev->pdev->dev,
+				"Can't add vlan due to spoof check is on and vf vlan table is full\n");
+			return -EPERM;
+		}
 		return 0;
+	}
 
 	hclge_cmd_setup_basic_desc(&desc[0],
 				   HCLGE_OPC_VLAN_FILTER_VF_CFG, false);
@@ -7666,7 +7907,7 @@
 		}
 
 		dev_err(&hdev->pdev->dev,
-			"Add vf vlan filter fail, ret =%d.\n",
+			"Add vf vlan filter fail, ret =%u.\n",
 			req0->resp_code);
 	} else {
 #define HCLGE_VF_VLAN_DEL_NO_FOUND	1
@@ -7682,7 +7923,7 @@
 			return 0;
 
 		dev_err(&hdev->pdev->dev,
-			"Kill vf vlan filter fail, ret =%d.\n",
+			"Kill vf vlan filter fail, ret =%u.\n",
 			req0->resp_code);
 	}
 
@@ -7701,9 +7942,10 @@
 
 	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_PF_CFG, false);
 
-	vlan_offset_160 = vlan_id / 160;
-	vlan_offset_byte = (vlan_id % 160) / 8;
-	vlan_offset_byte_val = 1 << (vlan_id % 8);
+	vlan_offset_160 = vlan_id / HCLGE_VLAN_ID_OFFSET_STEP;
+	vlan_offset_byte = (vlan_id % HCLGE_VLAN_ID_OFFSET_STEP) /
+			   HCLGE_VLAN_BYTE_SIZE;
+	vlan_offset_byte_val = 1 << (vlan_id % HCLGE_VLAN_BYTE_SIZE);
 
 	req = (struct hclge_vlan_filter_pf_cfg_cmd *)desc.data;
 	req->vlan_offset = vlan_offset_160;
@@ -7731,7 +7973,7 @@
 				       proto);
 	if (ret) {
 		dev_err(&hdev->pdev->dev,
-			"Set %d vport vlan filter config fail, ret =%d.\n",
+			"Set %u vport vlan filter config fail, ret =%d.\n",
 			vport_id, ret);
 		return ret;
 	}
@@ -7743,7 +7985,7 @@
 
 	if (!is_kill && test_and_set_bit(vport_id, hdev->vlan_table[vlan_id])) {
 		dev_err(&hdev->pdev->dev,
-			"Add port vlan failed, vport %d is already in vlan %d\n",
+			"Add port vlan failed, vport %u is already in vlan %u\n",
 			vport_id, vlan_id);
 		return -EINVAL;
 	}
@@ -7751,7 +7993,7 @@
 	if (is_kill &&
 	    !test_and_clear_bit(vport_id, hdev->vlan_table[vlan_id])) {
 		dev_err(&hdev->pdev->dev,
-			"Delete port vlan failed, vport %d is not in vlan %d\n",
+			"Delete port vlan failed, vport %u is not in vlan %u\n",
 			vport_id, vlan_id);
 		return -EINVAL;
 	}
@@ -7999,7 +8241,11 @@
 static void hclge_add_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id,
 				       bool writen_to_tbl)
 {
-	struct hclge_vport_vlan_cfg *vlan;
+	struct hclge_vport_vlan_cfg *vlan, *tmp;
+
+	list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node)
+		if (vlan->vlan_id == vlan_id)
+			return;
 
 	vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
 	if (!vlan)
@@ -8076,6 +8322,7 @@
 			kfree(vlan);
 		}
 	}
+	clear_bit(vport->vport_id, hdev->vf_vlan_full);
 }
 
 void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev)
@@ -8084,7 +8331,6 @@
 	struct hclge_vport *vport;
 	int i;
 
-	mutex_lock(&hdev->vport_cfg_mutex);
 	for (i = 0; i < hdev->num_alloc_vport; i++) {
 		vport = &hdev->vport[i];
 		list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) {
@@ -8092,7 +8338,6 @@
 			kfree(vlan);
 		}
 	}
-	mutex_unlock(&hdev->vport_cfg_mutex);
 }
 
 static void hclge_restore_vlan_table(struct hnae3_handle *handle)
@@ -8104,7 +8349,6 @@
 	u16 state, vlan_id;
 	int i;
 
-	mutex_lock(&hdev->vport_cfg_mutex);
 	for (i = 0; i < hdev->num_alloc_vport; i++) {
 		vport = &hdev->vport[i];
 		vlan_proto = vport->port_base_vlan_cfg.vlan_info.vlan_proto;
@@ -8119,16 +8363,17 @@
 		}
 
 		list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) {
-			if (vlan->hd_tbl_status)
-				hclge_set_vlan_filter_hw(hdev,
-							 htons(ETH_P_8021Q),
-							 vport->vport_id,
-							 vlan->vlan_id,
-							 false);
+			int ret;
+
+			if (!vlan->hd_tbl_status)
+				continue;
+			ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q),
+						       vport->vport_id,
+						       vlan->vlan_id, false);
+			if (ret)
+				break;
 		}
 	}
-
-	mutex_unlock(&hdev->vport_cfg_mutex);
 }
 
 int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
@@ -8262,13 +8507,16 @@
 	if (hdev->pdev->revision == 0x20)
 		return -EOPNOTSUPP;
 
+	vport = hclge_get_vf_vport(hdev, vfid);
+	if (!vport)
+		return -EINVAL;
+
 	/* qos is a 3 bits value, so can not be bigger than 7 */
-	if (vfid >= hdev->num_alloc_vfs || vlan > VLAN_N_VID - 1 || qos > 7)
+	if (vlan > VLAN_N_VID - 1 || qos > 7)
 		return -EINVAL;
 	if (proto != htons(ETH_P_8021Q))
 		return -EPROTONOSUPPORT;
 
-	vport = &hdev->vport[vfid];
 	state = hclge_get_port_base_vlan_state(vport,
 					       vport->port_base_vlan_cfg.state,
 					       vlan);
@@ -8279,27 +8527,40 @@
 	vlan_info.qos = qos;
 	vlan_info.vlan_proto = ntohs(proto);
 
-	/* update port based VLAN for PF */
-	if (!vfid) {
-		hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
-		ret = hclge_update_port_base_vlan_cfg(vport, state, &vlan_info);
-		hclge_notify_client(hdev, HNAE3_UP_CLIENT);
-
-		return ret;
-	}
-
 	if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) {
 		return hclge_update_port_base_vlan_cfg(vport, state,
 						       &vlan_info);
 	} else {
 		ret = hclge_push_vf_port_base_vlan_info(&hdev->vport[0],
-							(u8)vfid, state,
+							vport->vport_id, state,
 							vlan, qos,
 							ntohs(proto));
 		return ret;
 	}
 }
 
+static void hclge_clear_vf_vlan(struct hclge_dev *hdev)
+{
+	struct hclge_vlan_info *vlan_info;
+	struct hclge_vport *vport;
+	int ret;
+	int vf;
+
+	/* clear port base vlan for all vf */
+	for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) {
+		vport = &hdev->vport[vf];
+		vlan_info = &vport->port_base_vlan_cfg.vlan_info;
+
+		ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q),
+					       vport->vport_id,
+					       vlan_info->vlan_tag, true);
+		if (ret)
+			dev_err(&hdev->pdev->dev,
+				"failed to clear vf vlan for vf%d, ret = %d\n",
+				vf - HCLGE_VF_VPORT_START_NUM, ret);
+	}
+}
+
 int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
 			  u16 vlan_id, bool is_kill)
 {
@@ -8330,11 +8591,11 @@
 	}
 
 	if (!ret) {
-		if (is_kill)
-			hclge_rm_vport_vlan_table(vport, vlan_id, false);
-		else
+		if (!is_kill)
 			hclge_add_vport_vlan_table(vport, vlan_id,
 						   writen_to_tbl);
+		else if (is_kill && vlan_id != 0)
+			hclge_rm_vport_vlan_table(vport, vlan_id, false);
 	} else if (is_kill) {
 		/* when remove hw vlan filter failed, record the vlan id,
 		 * and try to remove it from hw later, to be consistence
@@ -8404,6 +8665,7 @@
 	struct hclge_dev *hdev = vport->back;
 	int i, max_frm_size, ret;
 
+	/* HW supprt 2 layer vlan */
 	max_frm_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN;
 	if (max_frm_size < HCLGE_MAC_MIN_FRAME ||
 	    max_frm_size > HCLGE_MAC_MAX_FRAME)
@@ -8555,12 +8817,19 @@
 
 void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id)
 {
+	struct hnae3_handle *handle = &vport->nic;
 	struct hclge_dev *hdev = vport->back;
 	int reset_try_times = 0;
 	int reset_status;
 	u16 queue_gid;
 	int ret;
 
+	if (queue_id >= handle->kinfo.num_tqps) {
+		dev_warn(&hdev->pdev->dev, "Invalid vf queue id(%u)\n",
+			 queue_id);
+		return;
+	}
+
 	queue_gid = hclge_covert_handle_qid_global(&vport->nic, queue_id);
 
 	ret = hclge_send_reset_tqp_cmd(hdev, queue_gid, true);
@@ -8819,16 +9088,16 @@
 
 	dev_info(dev, "PF info begin:\n");
 
-	dev_info(dev, "Task queue pairs numbers: %d\n", hdev->num_tqps);
-	dev_info(dev, "Desc num per TX queue: %d\n", hdev->num_tx_desc);
-	dev_info(dev, "Desc num per RX queue: %d\n", hdev->num_rx_desc);
-	dev_info(dev, "Numbers of vports: %d\n", hdev->num_alloc_vport);
-	dev_info(dev, "Numbers of vmdp vports: %d\n", hdev->num_vmdq_vport);
-	dev_info(dev, "Numbers of VF for this PF: %d\n", hdev->num_req_vfs);
-	dev_info(dev, "HW tc map: %d\n", hdev->hw_tc_map);
-	dev_info(dev, "Total buffer size for TX/RX: %d\n", hdev->pkt_buf_size);
-	dev_info(dev, "TX buffer size for each TC: %d\n", hdev->tx_buf_size);
-	dev_info(dev, "DV buffer size for each TC: %d\n", hdev->dv_buf_size);
+	dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps);
+	dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc);
+	dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc);
+	dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport);
+	dev_info(dev, "Numbers of vmdp vports: %u\n", hdev->num_vmdq_vport);
+	dev_info(dev, "Numbers of VF for this PF: %u\n", hdev->num_req_vfs);
+	dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map);
+	dev_info(dev, "Total buffer size for TX/RX: %u\n", hdev->pkt_buf_size);
+	dev_info(dev, "TX buffer size for each TC: %u\n", hdev->tx_buf_size);
+	dev_info(dev, "DV buffer size for each TC: %u\n", hdev->dv_buf_size);
 	dev_info(dev, "This is %s PF\n",
 		 hdev->flag & HCLGE_FLAG_MAIN ? "main" : "not main");
 	dev_info(dev, "DCB %s\n",
@@ -8844,10 +9113,9 @@
 {
 	struct hnae3_client *client = vport->nic.client;
 	struct hclge_dev *hdev = ae_dev->priv;
-	int rst_cnt;
+	int rst_cnt = hdev->rst_stats.reset_cnt;
 	int ret;
 
-	rst_cnt = hdev->rst_stats.reset_cnt;
 	ret = client->ops->init_instance(&vport->nic);
 	if (ret)
 		return ret;
@@ -8947,7 +9215,6 @@
 
 		switch (client->type) {
 		case HNAE3_CLIENT_KNIC:
-
 			hdev->nic_client = client;
 			vport->nic.client = client;
 			ret = hclge_init_nic_client_instance(ae_dev, vport);
@@ -9087,6 +9354,7 @@
 	set_bit(HCLGE_STATE_DOWN, &hdev->state);
 	clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state);
 	clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
+	clear_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
 	clear_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state);
 	clear_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state);
 }
@@ -9100,38 +9368,57 @@
 		del_timer_sync(&hdev->reset_timer);
 	if (hdev->service_task.work.func)
 		cancel_delayed_work_sync(&hdev->service_task);
-	if (hdev->rst_service_task.func)
-		cancel_work_sync(&hdev->rst_service_task);
-	if (hdev->mbx_service_task.func)
-		cancel_work_sync(&hdev->mbx_service_task);
 }
 
 static void hclge_flr_prepare(struct hnae3_ae_dev *ae_dev)
 {
-#define HCLGE_FLR_WAIT_MS	100
-#define HCLGE_FLR_WAIT_CNT	50
-	struct hclge_dev *hdev = ae_dev->priv;
-	int cnt = 0;
+#define HCLGE_FLR_RETRY_WAIT_MS	500
+#define HCLGE_FLR_RETRY_CNT	5
 
-	clear_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
-	clear_bit(HNAE3_FLR_DONE, &hdev->flr_state);
-	set_bit(HNAE3_FLR_RESET, &hdev->default_reset_request);
-	hclge_reset_event(hdev->pdev, NULL);
+	struct hclge_dev *hdev = ae_dev->priv;
+	int retry_cnt = 0;
+	int ret;
 
-	while (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state) &&
-	       cnt++ < HCLGE_FLR_WAIT_CNT)
-		msleep(HCLGE_FLR_WAIT_MS);
+retry:
+	down(&hdev->reset_sem);
+	set_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
+	hdev->reset_type = HNAE3_FLR_RESET;
+	ret = hclge_reset_prepare(hdev);
+	if (ret) {
+		dev_err(&hdev->pdev->dev, "fail to prepare FLR, ret=%d\n",
+			ret);
+		if (hdev->reset_pending ||
+		    retry_cnt++ < HCLGE_FLR_RETRY_CNT) {
+			dev_err(&hdev->pdev->dev,
+				"reset_pending:0x%lx, retry_cnt:%d\n",
+				hdev->reset_pending, retry_cnt);
+			clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
+			up(&hdev->reset_sem);
+			msleep(HCLGE_FLR_RETRY_WAIT_MS);
+			goto retry;
+		}
+	}
 
-	if (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state))
-		dev_err(&hdev->pdev->dev,
-			"flr wait down timeout: %d\n", cnt);
+	/* disable misc vector before FLR done */
+	hclge_enable_vector(&hdev->misc_vector, false);
+	set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
+	hdev->rst_stats.flr_rst_cnt++;
 }
 
 static void hclge_flr_done(struct hnae3_ae_dev *ae_dev)
 {
 	struct hclge_dev *hdev = ae_dev->priv;
+	int ret;
+
+	hclge_enable_vector(&hdev->misc_vector, true);
+
+	ret = hclge_reset_rebuild(hdev);
+	if (ret)
+		dev_err(&hdev->pdev->dev, "fail to rebuild, ret=%d\n", ret);
 
-	set_bit(HNAE3_FLR_DONE, &hdev->flr_state);
+	hdev->reset_type = HNAE3_NONE_RESET;
+	clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state);
+	up(&hdev->reset_sem);
 }
 
 static void hclge_clear_resetting_state(struct hclge_dev *hdev)
@@ -9146,11 +9433,33 @@
 		ret = hclge_set_vf_rst(hdev, vport->vport_id, false);
 		if (ret)
 			dev_warn(&hdev->pdev->dev,
-				 "clear vf(%d) rst failed %d!\n",
+				 "clear vf(%u) rst failed %d!\n",
 				 vport->vport_id, ret);
 	}
 }
 
+static int hclge_clear_hw_resource(struct hclge_dev *hdev)
+{
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CLEAR_HW_RESOURCE, false);
+
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	/* This new command is only supported by new firmware, it will
+	 * fail with older firmware. Error value -EOPNOSUPP can only be
+	 * returned by older firmware running this command, to keep code
+	 * backward compatible we will override this value and return
+	 * success.
+	 */
+	if (ret && ret != -EOPNOTSUPP) {
+		dev_err(&hdev->pdev->dev,
+			"failed to clear hw resource, ret = %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
 static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 {
 	struct pci_dev *pdev = ae_dev->pdev;
@@ -9168,11 +9477,13 @@
 	hdev->reset_type = HNAE3_NONE_RESET;
 	hdev->reset_level = HNAE3_FUNC_RESET;
 	ae_dev->priv = hdev;
+
+	/* HW supprt 2 layer vlan */
 	hdev->mps = ETH_FRAME_LEN + ETH_FCS_LEN + 2 * VLAN_HLEN;
 
 	mutex_init(&hdev->vport_lock);
-	mutex_init(&hdev->vport_cfg_mutex);
 	spin_lock_init(&hdev->fd_rule_lock);
+	sema_init(&hdev->reset_sem, 1);
 
 	ret = hclge_pci_init(hdev);
 	if (ret) {
@@ -9192,6 +9503,10 @@
 	if (ret)
 		goto err_cmd_uninit;
 
+	ret  = hclge_clear_hw_resource(hdev);
+	if (ret)
+		goto err_cmd_uninit;
+
 	ret = hclge_get_cap(hdev);
 	if (ret) {
 		dev_err(&pdev->dev, "get hw capability error, ret = %d.\n",
@@ -9306,8 +9621,6 @@
 
 	timer_setup(&hdev->reset_timer, hclge_reset_timer, 0);
 	INIT_DELAYED_WORK(&hdev->service_task, hclge_service_task);
-	INIT_WORK(&hdev->rst_service_task, hclge_reset_service_task);
-	INIT_WORK(&hdev->mbx_service_task, hclge_mailbox_service_task);
 
 	/* Setup affinity after service timer setup because add_timer_on
 	 * is called in affinity notify.
@@ -9341,6 +9654,8 @@
 	dev_info(&hdev->pdev->dev, "%s driver initialization finished.\n",
 		 HCLGE_DRIVER_NAME);
 
+	hclge_task_schedule(hdev, round_jiffies_relative(HZ));
+
 	return 0;
 
 err_mdiobus_unreg:
@@ -9363,7 +9678,220 @@
 
 static void hclge_stats_clear(struct hclge_dev *hdev)
 {
-	memset(&hdev->hw_stats, 0, sizeof(hdev->hw_stats));
+	memset(&hdev->mac_stats, 0, sizeof(hdev->mac_stats));
+}
+
+static int hclge_set_mac_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
+{
+	return hclge_config_switch_param(hdev, vf, enable,
+					 HCLGE_SWITCH_ANTI_SPOOF_MASK);
+}
+
+static int hclge_set_vlan_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
+{
+	return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+					  HCLGE_FILTER_FE_NIC_INGRESS_B,
+					  enable, vf);
+}
+
+static int hclge_set_vf_spoofchk_hw(struct hclge_dev *hdev, int vf, bool enable)
+{
+	int ret;
+
+	ret = hclge_set_mac_spoofchk(hdev, vf, enable);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"Set vf %d mac spoof check %s failed, ret=%d\n",
+			vf, enable ? "on" : "off", ret);
+		return ret;
+	}
+
+	ret = hclge_set_vlan_spoofchk(hdev, vf, enable);
+	if (ret)
+		dev_err(&hdev->pdev->dev,
+			"Set vf %d vlan spoof check %s failed, ret=%d\n",
+			vf, enable ? "on" : "off", ret);
+
+	return ret;
+}
+
+static int hclge_set_vf_spoofchk(struct hnae3_handle *handle, int vf,
+				 bool enable)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+	u32 new_spoofchk = enable ? 1 : 0;
+	int ret;
+
+	if (hdev->pdev->revision == 0x20)
+		return -EOPNOTSUPP;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	if (vport->vf_info.spoofchk == new_spoofchk)
+		return 0;
+
+	if (enable && test_bit(vport->vport_id, hdev->vf_vlan_full))
+		dev_warn(&hdev->pdev->dev,
+			 "vf %d vlan table is full, enable spoof check may cause its packet send fail\n",
+			 vf);
+	else if (enable && hclge_is_umv_space_full(vport))
+		dev_warn(&hdev->pdev->dev,
+			 "vf %d mac table is full, enable spoof check may cause its packet send fail\n",
+			 vf);
+
+	ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, enable);
+	if (ret)
+		return ret;
+
+	vport->vf_info.spoofchk = new_spoofchk;
+	return 0;
+}
+
+static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev)
+{
+	struct hclge_vport *vport = hdev->vport;
+	int ret;
+	int i;
+
+	if (hdev->pdev->revision == 0x20)
+		return 0;
+
+	/* resume the vf spoof check state after reset */
+	for (i = 0; i < hdev->num_alloc_vport; i++) {
+		ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id,
+					       vport->vf_info.spoofchk);
+		if (ret)
+			return ret;
+
+		vport++;
+	}
+
+	return 0;
+}
+
+static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+	u32 new_trusted = enable ? 1 : 0;
+	bool en_bc_pmc;
+	int ret;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	if (vport->vf_info.trusted == new_trusted)
+		return 0;
+
+	/* Disable promisc mode for VF if it is not trusted any more. */
+	if (!enable && vport->vf_info.promisc_enable) {
+		en_bc_pmc = hdev->pdev->revision != 0x20;
+		ret = hclge_set_vport_promisc_mode(vport, false, false,
+						   en_bc_pmc);
+		if (ret)
+			return ret;
+		vport->vf_info.promisc_enable = 0;
+		hclge_inform_vf_promisc_info(vport);
+	}
+
+	vport->vf_info.trusted = new_trusted;
+
+	return 0;
+}
+
+static void hclge_reset_vf_rate(struct hclge_dev *hdev)
+{
+	int ret;
+	int vf;
+
+	/* reset vf rate to default value */
+	for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) {
+		struct hclge_vport *vport = &hdev->vport[vf];
+
+		vport->vf_info.max_tx_rate = 0;
+		ret = hclge_tm_qs_shaper_cfg(vport, vport->vf_info.max_tx_rate);
+		if (ret)
+			dev_err(&hdev->pdev->dev,
+				"vf%d failed to reset to default, ret=%d\n",
+				vf - HCLGE_VF_VPORT_START_NUM, ret);
+	}
+}
+
+static int hclge_vf_rate_param_check(struct hclge_dev *hdev, int vf,
+				     int min_tx_rate, int max_tx_rate)
+{
+	if (min_tx_rate != 0 ||
+	    max_tx_rate < 0 || max_tx_rate > hdev->hw.mac.max_speed) {
+		dev_err(&hdev->pdev->dev,
+			"min_tx_rate:%d [0], max_tx_rate:%d [0, %u]\n",
+			min_tx_rate, max_tx_rate, hdev->hw.mac.max_speed);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hclge_set_vf_rate(struct hnae3_handle *handle, int vf,
+			     int min_tx_rate, int max_tx_rate, bool force)
+{
+	struct hclge_vport *vport = hclge_get_vport(handle);
+	struct hclge_dev *hdev = vport->back;
+	int ret;
+
+	ret = hclge_vf_rate_param_check(hdev, vf, min_tx_rate, max_tx_rate);
+	if (ret)
+		return ret;
+
+	vport = hclge_get_vf_vport(hdev, vf);
+	if (!vport)
+		return -EINVAL;
+
+	if (!force && max_tx_rate == vport->vf_info.max_tx_rate)
+		return 0;
+
+	ret = hclge_tm_qs_shaper_cfg(vport, max_tx_rate);
+	if (ret)
+		return ret;
+
+	vport->vf_info.max_tx_rate = max_tx_rate;
+
+	return 0;
+}
+
+static int hclge_resume_vf_rate(struct hclge_dev *hdev)
+{
+	struct hnae3_handle *handle = &hdev->vport->nic;
+	struct hclge_vport *vport;
+	int ret;
+	int vf;
+
+	/* resume the vf max_tx_rate after reset */
+	for (vf = 0; vf < pci_num_vf(hdev->pdev); vf++) {
+		vport = hclge_get_vf_vport(hdev, vf);
+		if (!vport)
+			return -EINVAL;
+
+		/* zero means max rate, after reset, firmware already set it to
+		 * max rate, so just continue.
+		 */
+		if (!vport->vf_info.max_tx_rate)
+			continue;
+
+		ret = hclge_set_vf_rate(handle, vf, 0,
+					vport->vf_info.max_tx_rate, true);
+		if (ret) {
+			dev_err(&hdev->pdev->dev,
+				"vf%d failed to resume tx_rate:%u, ret=%d\n",
+				vf, vport->vf_info.max_tx_rate, ret);
+			return ret;
+		}
+	}
+
+	return 0;
 }
 
 static void hclge_reset_vport_state(struct hclge_dev *hdev)
@@ -9437,12 +9965,22 @@
 		return ret;
 	}
 
+	ret = init_mgr_tbl(hdev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to reinit manager table, ret = %d\n", ret);
+		return ret;
+	}
+
 	ret = hclge_init_fd_config(hdev);
 	if (ret) {
 		dev_err(&pdev->dev, "fd table init fail, ret=%d\n", ret);
 		return ret;
 	}
 
+	/* Log and clear the hw errors those already occurred */
+	hclge_handle_all_hns_hw_errors(ae_dev);
+
 	/* Re-enable the hw error interrupts because
 	 * the interrupts get disabled on global reset.
 	 */
@@ -9465,6 +10003,13 @@
 	}
 
 	hclge_reset_vport_state(hdev);
+	ret = hclge_reset_vport_spoofchk(hdev);
+	if (ret)
+		return ret;
+
+	ret = hclge_resume_vf_rate(hdev);
+	if (ret)
+		return ret;
 
 	dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
 		 HCLGE_DRIVER_NAME);
@@ -9477,6 +10022,8 @@
 	struct hclge_dev *hdev = ae_dev->priv;
 	struct hclge_mac *mac = &hdev->hw.mac;
 
+	hclge_reset_vf_rate(hdev);
+	hclge_clear_vf_vlan(hdev);
 	hclge_misc_affinity_teardown(hdev);
 	hclge_state_uninit(hdev);
 
@@ -9500,7 +10047,6 @@
 	mutex_destroy(&hdev->vport_lock);
 	hclge_uninit_vport_mac_table(hdev);
 	hclge_uninit_vport_vlan_table(hdev);
-	mutex_destroy(&hdev->vport_cfg_mutex);
 	ae_dev->priv = NULL;
 }
 
@@ -9541,8 +10087,8 @@
 	u16 tc_offset[HCLGE_MAX_TC_NUM] = {0};
 	struct hclge_dev *hdev = vport->back;
 	u16 tc_size[HCLGE_MAX_TC_NUM] = {0};
-	int cur_rss_size = kinfo->rss_size;
-	int cur_tqps = kinfo->num_tqps;
+	u16 cur_rss_size = kinfo->rss_size;
+	u16 cur_tqps = kinfo->num_tqps;
 	u16 tc_valid[HCLGE_MAX_TC_NUM];
 	u16 roundup_size;
 	u32 *rss_indir;
@@ -9596,7 +10142,7 @@
 out:
 	if (!ret)
 		dev_info(&hdev->pdev->dev,
-			 "Channels changed, rss_size from %d to %d, tqps from %d to %d",
+			 "Channels changed, rss_size from %u to %u, tqps from %u to %u",
 			 cur_rss_size, kinfo->rss_size,
 			 cur_tqps, kinfo->rss_size * kinfo->num_tc);
 
@@ -9762,10 +10308,8 @@
 				    int *bd_num_list,
 				    u32 type_num)
 {
-#define HCLGE_DFX_REG_BD_NUM	4
-
 	u32 entries_per_desc, desc_index, index, offset, i;
-	struct hclge_desc desc[HCLGE_DFX_REG_BD_NUM];
+	struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
 	int ret;
 
 	ret = hclge_query_bd_num_cmd_send(hdev, desc);
@@ -9834,8 +10378,9 @@
 static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len)
 {
 	u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
-	int data_len_per_desc, data_len, bd_num, i;
+	int data_len_per_desc, bd_num, i;
 	int bd_num_list[BD_LIST_MAX_NUM];
+	u32 data_len;
 	int ret;
 
 	ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
@@ -9878,10 +10423,8 @@
 
 	buf_len = sizeof(*desc_src) * bd_num_max;
 	desc_src = kzalloc(buf_len, GFP_KERNEL);
-	if (!desc_src) {
-		dev_err(&hdev->pdev->dev, "%s kzalloc failed\n", __func__);
+	if (!desc_src)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < dfx_reg_type_num; i++) {
 		bd_num = bd_num_list[i];
@@ -10199,6 +10742,12 @@
 	.mac_connect_phy = hclge_mac_connect_phy,
 	.mac_disconnect_phy = hclge_mac_disconnect_phy,
 	.restore_vlan_table = hclge_restore_vlan_table,
+	.get_vf_config = hclge_get_vf_config,
+	.set_vf_link_state = hclge_set_vf_link_state,
+	.set_vf_spoofchk = hclge_set_vf_spoofchk,
+	.set_vf_trust = hclge_set_vf_trust,
+	.set_vf_rate = hclge_set_vf_rate,
+	.set_vf_mac = hclge_set_vf_mac,
 };
 
 static struct hnae3_ae_algo ae_algo = {
@@ -10210,6 +10759,12 @@
 {
 	pr_info("%s is initializing\n", HCLGE_NAME);
 
+	hclge_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, HCLGE_NAME);
+	if (!hclge_wq) {
+		pr_err("%s: failed to create workqueue\n", HCLGE_NAME);
+		return -ENOMEM;
+	}
+
 	hnae3_register_ae_algo(&ae_algo);
 
 	return 0;
@@ -10217,7 +10772,9 @@
 
 static void hclge_exit(void)
 {
+	hnae3_unregister_ae_algo_prepare(&ae_algo);
 	hnae3_unregister_ae_algo(&ae_algo);
+	destroy_workqueue(hclge_wq);
 }
 module_init(hclge_init);
 module_exit(hclge_exit);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -139,9 +139,10 @@
 #define HCLGE_PHY_MDIX_STATUS_B		6
 #define HCLGE_PHY_SPEED_DUP_RESOLVE_B	11
 
+#define HCLGE_GET_DFX_REG_TYPE_CNT	4
+
 /* Factor used to calculate offset and bitmap of VF num */
 #define HCLGE_VF_NUM_PER_CMD           64
-#define HCLGE_VF_NUM_PER_BYTE          8
 
 enum HLCGE_PORT_TYPE {
 	HOST_PORT,
@@ -209,13 +210,14 @@
 	HCLGE_STATE_NIC_REGISTERED,
 	HCLGE_STATE_ROCE_REGISTERED,
 	HCLGE_STATE_SERVICE_INITED,
-	HCLGE_STATE_SERVICE_SCHED,
 	HCLGE_STATE_RST_SERVICE_SCHED,
 	HCLGE_STATE_RST_HANDLING,
 	HCLGE_STATE_MBX_SERVICE_SCHED,
 	HCLGE_STATE_MBX_HANDLING,
 	HCLGE_STATE_STATISTICS_UPDATING,
 	HCLGE_STATE_CMD_DISABLE,
+	HCLGE_STATE_LINK_UPDATING,
+	HCLGE_STATE_RST_FAIL,
 	HCLGE_STATE_MAX
 };
 
@@ -226,8 +228,6 @@
 	HCLGE_VECTOR0_EVENT_OTHER,
 };
 
-#define HCLGE_MPF_ENBALE 1
-
 enum HCLGE_MAC_SPEED {
 	HCLGE_MAC_SPEED_UNKNOWN = 0,		/* unknown */
 	HCLGE_MAC_SPEED_10M	= 10,		/* 10 Mbps */
@@ -249,6 +249,7 @@
 #define QUERY_ACTIVE_SPEED	1
 
 struct hclge_mac {
+	u8 mac_id;
 	u8 phy_addr;
 	u8 flag;
 	u8 media_type;	/* port media type, e.g. fibre/copper/backplane */
@@ -258,6 +259,7 @@
 	u8 support_autoneg;
 	u8 speed_type;	/* 0: sfp speed, 1: active speed */
 	u32 speed;
+	u32 max_speed;
 	u32 speed_ability; /* speed ability supported by current media */
 	u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */
 	u32 fec_mode; /* active fec mode */
@@ -456,11 +458,7 @@
 	u64 mac_rx_ctrl_pkt_num;
 };
 
-#define HCLGE_STATS_TIMER_INTERVAL	(60 * 5)
-struct hclge_hw_stats {
-	struct hclge_mac_stats      mac_stats;
-	u32 stats_timer;
-};
+#define HCLGE_STATS_TIMER_INTERVAL	300UL
 
 struct hclge_vlan_type_cfg {
 	u16 rx_ot_fst_vlan_type;
@@ -551,7 +549,7 @@
 
 /* assigned by firmware, the real filter number for each pf may be less */
 #define MAX_FD_FILTER_NUM	4096
-#define HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL	5
+#define HCLGE_ARFS_EXPIRE_INTERVAL	5UL
 
 enum HCLGE_FD_ACTIVE_RULE_TYPE {
 	HCLGE_FD_RULE_NONE,
@@ -655,7 +653,6 @@
 	u32 hw_reset_done_cnt;	/* the number of HW reset has completed */
 	u32 pf_rst_cnt;		/* the number of PF reset */
 	u32 flr_rst_cnt;	/* the number of FLR */
-	u32 core_rst_cnt;	/* the number of CORE reset */
 	u32 global_rst_cnt;	/* the number of GLOBAL */
 	u32 imp_rst_cnt;	/* the number of IMP reset */
 	u32 reset_cnt;		/* the number of reset */
@@ -715,7 +712,7 @@
 	struct hnae3_ae_dev *ae_dev;
 	struct hclge_hw hw;
 	struct hclge_misc_vector misc_vector;
-	struct hclge_hw_stats hw_stats;
+	struct hclge_mac_stats mac_stats;
 	unsigned long state;
 	unsigned long flr_state;
 	unsigned long last_reset_time;
@@ -726,6 +723,7 @@
 	unsigned long reset_request;	/* reset has been requested */
 	unsigned long reset_pending;	/* client rst is pending to be served */
 	struct hclge_rst_stats rst_stats;
+	struct semaphore reset_sem;	/* protect reset process */
 	u32 fw_version;
 	u16 num_vmdq_vport;		/* Num vmdq vport this PF has set up */
 	u16 num_tqps;			/* Num task queue pairs of this PF */
@@ -777,8 +775,6 @@
 	unsigned long service_timer_previous;
 	struct timer_list reset_timer;
 	struct delayed_work service_task;
-	struct work_struct rst_service_task;
-	struct work_struct mbx_service_task;
 
 	bool cur_promisc;
 	int num_alloc_vfs;	/* Actual number of VFs allocated */
@@ -814,7 +810,8 @@
 	struct hlist_head fd_rule_list;
 	spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */
 	u16 hclge_fd_rule_num;
-	u16 fd_arfs_expire_timer;
+	unsigned long serv_processed_cnt;
+	unsigned long last_serv_processed;
 	unsigned long fd_bmap[BITS_TO_LONGS(MAX_FD_FILTER_NUM)];
 	enum HCLGE_FD_ACTIVE_RULE_TYPE fd_active_type;
 	u8 fd_en;
@@ -828,8 +825,6 @@
 	u16 share_umv_size;
 	struct mutex umv_mutex; /* protect share_umv_size */
 
-	struct mutex vport_cfg_mutex;   /* Protect stored vf table */
-
 	DECLARE_KFIFO(mac_tnl_log, struct hclge_mac_tnl_stats,
 		      HCLGE_MAC_TNL_LOG_SIZE);
 
@@ -886,6 +881,15 @@
 	struct hclge_vlan_info vlan_info;
 };
 
+struct hclge_vf_info {
+	int link_state;
+	u8 mac[ETH_ALEN];
+	u32 spoofchk;
+	u32 max_tx_rate;
+	u32 trusted;
+	u16 promisc_enable;
+};
+
 struct hclge_vport {
 	u16 alloc_tqps;	/* Allocated Tx/Rx queues */
 
@@ -917,15 +921,15 @@
 	unsigned long state;
 	unsigned long last_active_jiffies;
 	u32 mps; /* Max packet size */
+	struct hclge_vf_info vf_info;
 
 	struct list_head uc_mac_list;   /* Store VF unicast table */
 	struct list_head mc_mac_list;   /* Store VF multicast table */
 	struct list_head vlan_list;     /* Store VF vlan table */
 };
 
-void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
-			      bool en_mc, bool en_bc, int vport_id);
-
+int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc,
+				 bool en_mc_pmc, bool en_bc_pmc);
 int hclge_add_uc_addr_common(struct hclge_vport *vport,
 			     const unsigned char *addr);
 int hclge_rm_uc_addr_common(struct hclge_vport *vport,
@@ -994,4 +998,6 @@
 				struct hclge_desc *desc);
 void hclge_report_hw_error(struct hclge_dev *hdev,
 			   enum hnae3_hw_error_type type);
+void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
+void hclge_dbg_dump_rst_info(struct hclge_dev *hdev);
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -26,7 +26,7 @@
 
 	if (resp_data_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) {
 		dev_err(&hdev->pdev->dev,
-			"PF fail to gen resp to VF len %d exceeds max len %d\n",
+			"PF fail to gen resp to VF len %u exceeds max len %u\n",
 			resp_data_len,
 			HCLGE_MBX_MAX_RESP_DATA_SIZE);
 		/* If resp_data_len is too long, set the value to max length
@@ -64,6 +64,13 @@
 	enum hclge_cmd_status status;
 	struct hclge_desc desc;
 
+	if (msg_len > HCLGE_MBX_MAX_MSG_SIZE) {
+		dev_err(&hdev->pdev->dev,
+			"msg data length(=%u) exceeds maximum(=%u)\n",
+			msg_len, HCLGE_MBX_MAX_MSG_SIZE);
+		return -EMSGSIZE;
+	}
+
 	resp_pf_to_vf = (struct hclge_mbx_pf_to_vf_cmd *)desc.data;
 
 	hclge_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_PF_TO_VF, false);
@@ -86,10 +93,12 @@
 int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
 {
 	struct hclge_dev *hdev = vport->back;
-	enum hnae3_reset_type reset_type;
+	u16 reset_type;
 	u8 msg_data[2];
 	u8 dest_vfid;
 
+	BUILD_BUG_ON(HNAE3_MAX_RESET > U16_MAX);
+
 	dest_vfid = (u8)vport->vport_id;
 
 	if (hdev->reset_type == HNAE3_FUNC_RESET)
@@ -205,12 +214,38 @@
 static int hclge_set_vf_promisc_mode(struct hclge_vport *vport,
 				     struct hclge_mbx_vf_to_pf_cmd *req)
 {
-	bool en_bc = req->msg[1] ? true : false;
-	struct hclge_promisc_param param;
+#define HCLGE_MBX_BC_INDEX	1
+#define HCLGE_MBX_UC_INDEX	2
+#define HCLGE_MBX_MC_INDEX	3
+
+	bool en_bc = req->msg[HCLGE_MBX_BC_INDEX] ? true : false;
+	bool en_uc = req->msg[HCLGE_MBX_UC_INDEX] ? true : false;
+	bool en_mc = req->msg[HCLGE_MBX_MC_INDEX] ? true : false;
+	int ret;
+
+	if (!vport->vf_info.trusted) {
+		en_uc = false;
+		en_mc = false;
+	}
+
+	ret = hclge_set_vport_promisc_mode(vport, en_uc, en_mc, en_bc);
+	if (req->mbx_need_resp)
+		hclge_gen_resp_to_vf(vport, req, ret, NULL, 0);
+
+	vport->vf_info.promisc_enable = (en_uc || en_mc) ? 1 : 0;
+
+	return ret;
+}
+
+void hclge_inform_vf_promisc_info(struct hclge_vport *vport)
+{
+	u8 dest_vfid = (u8)vport->vport_id;
+	u8 msg_data[2];
 
-	/* vf is not allowed to enable unicast/multicast broadcast */
-	hclge_promisc_param_init(&param, false, false, en_bc, vport->vport_id);
-	return hclge_cmd_set_promisc_mode(vport->back, &param);
+	memcpy(&msg_data[0], &vport->vf_info.promisc_enable, sizeof(u16));
+
+	hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
+			   HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid);
 }
 
 static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
@@ -223,6 +258,20 @@
 	if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_UC_MODIFY) {
 		const u8 *old_addr = (const u8 *)(&mbx_req->msg[8]);
 
+		/* If VF MAC has been configured by the host then it
+		 * cannot be overridden by the MAC specified by the VM.
+		 */
+		if (!is_zero_ether_addr(vport->vf_info.mac) &&
+		    !ether_addr_equal(mac_addr, vport->vf_info.mac)) {
+			status = -EPERM;
+			goto out;
+		}
+
+		if (!is_valid_ether_addr(mac_addr)) {
+			status = -EINVAL;
+			goto out;
+		}
+
 		hclge_rm_uc_addr_common(vport, old_addr);
 		status = hclge_add_uc_addr_common(vport, mac_addr);
 		if (status) {
@@ -245,11 +294,12 @@
 						 false, HCLGE_MAC_ADDR_UC);
 	} else {
 		dev_err(&hdev->pdev->dev,
-			"failed to set unicast mac addr, unknown subcode %d\n",
+			"failed to set unicast mac addr, unknown subcode %u\n",
 			mbx_req->msg[1]);
 		return -EIO;
 	}
 
+out:
 	if (mbx_req->mbx_need_resp & HCLGE_MBX_NEED_RESP_BIT)
 		hclge_gen_resp_to_vf(vport, mbx_req, status, NULL, 0);
 
@@ -278,7 +328,7 @@
 						 false, HCLGE_MAC_ADDR_MC);
 	} else {
 		dev_err(&hdev->pdev->dev,
-			"failed to set mcast mac addr, unknown subcode %d\n",
+			"failed to set mcast mac addr, unknown subcode %u\n",
 			mbx_req->msg[1]);
 		return -EIO;
 	}
@@ -324,6 +374,9 @@
 		proto =  msg_cmd->proto;
 		status = hclge_set_vlan_filter(handle, cpu_to_be16(proto),
 					       vlan, is_kill);
+		if (mbx_req->mbx_need_resp)
+			return hclge_gen_resp_to_vf(vport, mbx_req, status,
+						    NULL, 0);
 	} else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
 		struct hnae3_handle *handle = &vport->nic;
 		bool en = msg_cmd->is_kill ? true : false;
@@ -398,6 +451,13 @@
 				    HCLGE_TQPS_RSS_INFO_LEN);
 }
 
+static int hclge_get_vf_mac_addr(struct hclge_vport *vport,
+				 struct hclge_mbx_vf_to_pf_cmd *mbx_req)
+{
+	return hclge_gen_resp_to_vf(vport, mbx_req, 0, vport->vf_info.mac,
+				    ETH_ALEN);
+}
+
 static int hclge_get_vf_queue_depth(struct hclge_vport *vport,
 				    struct hclge_mbx_vf_to_pf_cmd *mbx_req,
 				    bool gen_resp)
@@ -428,6 +488,9 @@
 static int hclge_get_link_info(struct hclge_vport *vport,
 			       struct hclge_mbx_vf_to_pf_cmd *mbx_req)
 {
+#define HCLGE_VF_LINK_STATE_UP		1U
+#define HCLGE_VF_LINK_STATE_DOWN	0U
+
 	struct hclge_dev *hdev = vport->back;
 	u16 link_status;
 	u8 msg_data[8];
@@ -435,7 +498,19 @@
 	u16 duplex;
 
 	/* mac.link can only be 0 or 1 */
-	link_status = (u16)hdev->hw.mac.link;
+	switch (vport->vf_info.link_state) {
+	case IFLA_VF_LINK_STATE_ENABLE:
+		link_status = HCLGE_VF_LINK_STATE_UP;
+		break;
+	case IFLA_VF_LINK_STATE_DISABLE:
+		link_status = HCLGE_VF_LINK_STATE_DOWN;
+		break;
+	case IFLA_VF_LINK_STATE_AUTO:
+	default:
+		link_status = (u16)hdev->hw.mac.link;
+		break;
+	}
+
 	duplex = hdev->hw.mac.duplex;
 	memcpy(&msg_data[0], &link_status, sizeof(u16));
 	memcpy(&msg_data[2], &hdev->hw.mac.speed, sizeof(u32));
@@ -455,7 +530,7 @@
 	unsigned long advertising;
 	unsigned long supported;
 	unsigned long send_data;
-	u8 msg_data[10];
+	u8 msg_data[10] = {};
 	u8 dest_vfid;
 
 	advertising = hdev->hw.mac.advertising[0];
@@ -489,7 +564,7 @@
 	struct hclge_dev *hdev = vport->back;
 	int ret;
 
-	dev_warn(&hdev->pdev->dev, "PF received VF reset request from VF %d!",
+	dev_warn(&hdev->pdev->dev, "PF received VF reset request from VF %u!",
 		 vport->vport_id);
 
 	ret = hclge_func_reset_cmd(hdev, vport->vport_id);
@@ -524,7 +599,8 @@
 	qid_in_pf = hclge_covert_handle_qid_global(&vport->nic, queue_id);
 	memcpy(resp_data, &qid_in_pf, sizeof(qid_in_pf));
 
-	return hclge_gen_resp_to_vf(vport, mbx_req, 0, resp_data, 2);
+	return hclge_gen_resp_to_vf(vport, mbx_req, 0, resp_data,
+				    sizeof(resp_data));
 }
 
 static int hclge_get_rss_key(struct hclge_vport *vport,
@@ -568,7 +644,6 @@
 #define LINK_STATUS_OFFSET	1
 #define LINK_FAIL_CODE_OFFSET	2
 
-	clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state);
 	hclge_task_schedule(hdev, 0);
 
 	if (!req->msg[LINK_STATUS_OFFSET])
@@ -614,7 +689,7 @@
 		flag = le16_to_cpu(crq->desc[crq->next_to_use].flag);
 		if (unlikely(!hnae3_get_bit(flag, HCLGE_CMDQ_RX_OUTVLD_B))) {
 			dev_warn(&hdev->pdev->dev,
-				 "dropped invalid mailbox message, code = %d\n",
+				 "dropped invalid mailbox message, code = %u\n",
 				 req->msg[0]);
 
 			/* dropping/not processing this invalid message */
@@ -731,13 +806,12 @@
 			hclge_get_link_mode(vport, req);
 			break;
 		case HCLGE_MBX_GET_VF_FLR_STATUS:
-			mutex_lock(&hdev->vport_cfg_mutex);
+		case HCLGE_MBX_VF_UNINIT:
 			hclge_rm_vport_all_mac_table(vport, true,
 						     HCLGE_MAC_ADDR_UC);
 			hclge_rm_vport_all_mac_table(vport, true,
 						     HCLGE_MAC_ADDR_MC);
 			hclge_rm_vport_all_vlan_table(vport, true);
-			mutex_unlock(&hdev->vport_cfg_mutex);
 			break;
 		case HCLGE_MBX_GET_MEDIA_TYPE:
 			ret = hclge_get_vf_media_type(vport, req);
@@ -749,12 +823,19 @@
 		case HCLGE_MBX_PUSH_LINK_STATUS:
 			hclge_handle_link_change_event(hdev, req);
 			break;
+		case HCLGE_MBX_GET_MAC_ADDR:
+			ret = hclge_get_vf_mac_addr(vport, req);
+			if (ret)
+				dev_err(&hdev->pdev->dev,
+					"PF failed(%d) to get MAC for VF\n",
+					ret);
+			break;
 		case HCLGE_MBX_NCSI_ERROR:
 			hclge_handle_ncsi_error(hdev);
 			break;
 		default:
 			dev_err(&hdev->pdev->dev,
-				"un-supported mailbox message, code = %d\n",
+				"un-supported mailbox message, code = %u\n",
 				req->msg[0]);
 			break;
 		}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
@@ -134,7 +134,7 @@
 			 "no phy device is connected to mdio bus\n");
 		return 0;
 	} else if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR) {
-		dev_err(&hdev->pdev->dev, "phy_addr(%d) is too large.\n",
+		dev_err(&hdev->pdev->dev, "phy_addr(%u) is too large.\n",
 			hdev->hw.mac.phy_addr);
 		return -EINVAL;
 	}
@@ -255,6 +255,8 @@
 	if (!phydev)
 		return;
 
+	phy_loopback(phydev, false);
+
 	phy_start(phydev);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -46,7 +46,7 @@
 #define DIVISOR_CLK		(1000 * 8)
 #define DIVISOR_IR_B_126	(126 * DIVISOR_CLK)
 
-	const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = {
+	static const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = {
 		6 * 256,        /* Prioriy level */
 		6 * 32,         /* Prioriy group level */
 		6 * 8,          /* Port level */
@@ -170,8 +170,8 @@
 	return hclge_cmd_send(&hdev->hw, &desc, 1);
 }
 
-static int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
-				  u8 pfc_bitmap)
+int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
+			   u8 pfc_bitmap)
 {
 	struct hclge_desc desc;
 	struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)desc.data;
@@ -511,6 +511,49 @@
 	return hclge_cmd_send(&hdev->hw, &desc, 1);
 }
 
+int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate)
+{
+	struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+	struct hclge_qs_shapping_cmd *shap_cfg_cmd;
+	struct hclge_dev *hdev = vport->back;
+	struct hclge_desc desc;
+	u8 ir_b, ir_u, ir_s;
+	u32 shaper_para;
+	int ret, i;
+
+	if (!max_tx_rate)
+		max_tx_rate = HCLGE_ETHER_MAX_RATE;
+
+	ret = hclge_shaper_para_calc(max_tx_rate, HCLGE_SHAPER_LVL_QSET,
+				     &ir_b, &ir_u, &ir_s);
+	if (ret)
+		return ret;
+
+	shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
+						 HCLGE_SHAPER_BS_U_DEF,
+						 HCLGE_SHAPER_BS_S_DEF);
+
+	for (i = 0; i < kinfo->num_tc; i++) {
+		hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG,
+					   false);
+
+		shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
+		shap_cfg_cmd->qs_id = cpu_to_le16(vport->qs_offset + i);
+		shap_cfg_cmd->qs_shapping_para = cpu_to_le32(shaper_para);
+
+		ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+		if (ret) {
+			dev_err(&hdev->pdev->dev,
+				"vf%u, qs%u failed to set tx_rate:%d, ret=%d\n",
+				vport->vport_id, shap_cfg_cmd->qs_id,
+				max_tx_rate, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
 {
 	struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
@@ -523,7 +566,7 @@
 	 */
 	kinfo->num_tc = vport->vport_id ? 1 :
 			min_t(u16, vport->alloc_tqps, hdev->tm_info.num_tc);
-	vport->qs_offset = (vport->vport_id ? hdev->tm_info.num_tc : 0) +
+	vport->qs_offset = (vport->vport_id ? HNAE3_MAX_TC : 0) +
 				(vport->vport_id ? (vport->vport_id - 1) : 0);
 
 	max_rss_size = min_t(u16, hdev->rss_size_max,
@@ -532,7 +575,7 @@
 	/* Set to user value, no larger than max_rss_size. */
 	if (kinfo->req_rss_size != kinfo->rss_size && kinfo->req_rss_size &&
 	    kinfo->req_rss_size <= max_rss_size) {
-		dev_info(&hdev->pdev->dev, "rss changes from %d to %d\n",
+		dev_info(&hdev->pdev->dev, "rss changes from %u to %u\n",
 			 kinfo->rss_size, kinfo->req_rss_size);
 		kinfo->rss_size = kinfo->req_rss_size;
 	} else if (kinfo->rss_size > max_rss_size ||
@@ -633,6 +676,8 @@
 		hdev->tm_info.pg_info[i].tc_bit_map = hdev->hw_tc_map;
 		for (k = 0; k < hdev->tm_info.num_tc; k++)
 			hdev->tm_info.pg_info[i].tc_dwrr[k] = BW_PERCENT;
+		for (; k < HNAE3_MAX_TC; k++)
+			hdev->tm_info.pg_info[i].tc_dwrr[k] = 0;
 	}
 }
 
@@ -972,7 +1017,6 @@
 
 static int hclge_tm_ets_tc_dwrr_cfg(struct hclge_dev *hdev)
 {
-#define DEFAULT_TC_WEIGHT	1
 #define DEFAULT_TC_OFFSET	14
 
 	struct hclge_ets_tc_weight_cmd *ets_weight;
@@ -985,13 +1029,7 @@
 	for (i = 0; i < HNAE3_MAX_TC; i++) {
 		struct hclge_pg_info *pg_info;
 
-		ets_weight->tc_weight[i] = DEFAULT_TC_WEIGHT;
-
-		if (!(hdev->hw_tc_map & BIT(i)))
-			continue;
-
-		pg_info =
-			&hdev->tm_info.pg_info[hdev->tm_info.tc_info[i].pgid];
+		pg_info = &hdev->tm_info.pg_info[hdev->tm_info.tc_info[i].pgid];
 		ets_weight->tc_weight[i] = pg_info->tc_dwrr[i];
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -96,6 +96,12 @@
 	__le32 pg_shapping_para;
 };
 
+struct hclge_qs_shapping_cmd {
+	__le16 qs_id;
+	u8 rsvd[2];
+	__le32 qs_shapping_para;
+};
+
 #define HCLGE_BP_GRP_NUM		32
 #define HCLGE_BP_SUB_GRP_ID_S		0
 #define HCLGE_BP_SUB_GRP_ID_M		GENMASK(4, 0)
@@ -109,6 +115,9 @@
 	u32 rsvd1;
 };
 
+#define HCLGE_PFC_DISABLE	0
+#define HCLGE_PFC_TX_RX_DISABLE	0
+
 struct hclge_pfc_en_cmd {
 	u8 tx_rx_en_bitmap;
 	u8 pri_en_bitmap;
@@ -150,8 +159,12 @@
 void hclge_tm_pfc_info_update(struct hclge_dev *hdev);
 int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
 int hclge_tm_init_hw(struct hclge_dev *hdev, bool init);
+int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
+			   u8 pfc_bitmap);
 int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
 int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr);
 int hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats);
 int hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats);
+int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate);
+
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
@@ -50,7 +50,7 @@
 	rmb(); /* Make sure head is ready before touch any data */
 
 	if (!hclgevf_is_valid_csq_clean_head(csq, head)) {
-		dev_warn(&hdev->pdev->dev, "wrong cmd head (%d, %d-%d)\n", head,
+		dev_warn(&hdev->pdev->dev, "wrong cmd head (%u, %d-%d)\n", head,
 			 csq->next_to_use, csq->next_to_clean);
 		dev_warn(&hdev->pdev->dev,
 			 "Disabling any further commands to IMP firmware\n");
@@ -92,9 +92,9 @@
 	u32 reg_val;
 
 	if (ring->flag == HCLGEVF_TYPE_CSQ) {
-		reg_val = (u32)ring->desc_dma_addr;
+		reg_val = lower_32_bits(ring->desc_dma_addr);
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_L_REG, reg_val);
-		reg_val = (u32)((ring->desc_dma_addr >> 31) >> 1);
+		reg_val = upper_32_bits(ring->desc_dma_addr);
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_H_REG, reg_val);
 
 		reg_val = hclgevf_read_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG);
@@ -105,9 +105,9 @@
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0);
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0);
 	} else {
-		reg_val = (u32)ring->desc_dma_addr;
+		reg_val = lower_32_bits(ring->desc_dma_addr);
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_L_REG, reg_val);
-		reg_val = (u32)((ring->desc_dma_addr >> 31) >> 1);
+		reg_val = upper_32_bits(ring->desc_dma_addr);
 		hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_H_REG, reg_val);
 
 		reg_val = (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S);
@@ -443,7 +443,7 @@
 {
 	spin_lock_bh(&hdev->hw.cmq.csq.lock);
 	spin_lock(&hdev->hw.cmq.crq.lock);
-	clear_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state);
+	set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state);
 	hclgevf_cmd_uninit_regs(&hdev->hw);
 	spin_unlock(&hdev->hw.cmq.crq.lock);
 	spin_unlock_bh(&hdev->hw.cmq.csq.lock);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -16,6 +16,8 @@
 static int hclgevf_reset_hdev(struct hclgevf_dev *hdev);
 static struct hnae3_ae_algo ae_algovf;
 
+static struct workqueue_struct *hclgevf_wq;
+
 static const struct pci_device_id ae_algovf_pci_tbl[] = {
 	{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_VF), 0},
 	{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF), 0},
@@ -440,6 +442,9 @@
 	struct hnae3_client *rclient;
 	struct hnae3_client *client;
 
+	if (test_and_set_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state))
+		return;
+
 	client = handle->client;
 	rclient = hdev->roce_client;
 
@@ -452,6 +457,8 @@
 			rclient->ops->link_status_change(rhandle, !!link_state);
 		hdev->hw.mac.link = link_state;
 	}
+
+	clear_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state);
 }
 
 static void hclgevf_update_link_mode(struct hclgevf_dev *hdev)
@@ -644,9 +651,9 @@
 	roundup_size = ilog2(roundup_size);
 
 	for (i = 0; i < HCLGEVF_MAX_TC_NUM; i++) {
-		tc_valid[i] = !!(hdev->hw_tc_map & BIT(i));
+		tc_valid[i] = 1;
 		tc_size[i] = roundup_size;
-		tc_offset[i] = rss_size * i;
+		tc_offset[i] = (hdev->hw_tc_map & BIT(i)) ? rss_size * i : 0;
 	}
 
 	hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_RSS_TC_MODE, false);
@@ -1113,6 +1120,7 @@
 }
 
 static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
+					bool en_uc_pmc, bool en_mc_pmc,
 					bool en_bc_pmc)
 {
 	struct hclge_mbx_vf_to_pf_cmd *req;
@@ -1120,10 +1128,11 @@
 	int ret;
 
 	req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data;
-
 	hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_VF_TO_PF, false);
 	req->msg[0] = HCLGE_MBX_SET_PROMISC_MODE;
 	req->msg[1] = en_bc_pmc ? 1 : 0;
+	req->msg[2] = en_uc_pmc ? 1 : 0;
+	req->msg[3] = en_mc_pmc ? 1 : 0;
 
 	ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
 	if (ret)
@@ -1133,9 +1142,17 @@
 	return ret;
 }
 
-static int hclgevf_set_promisc_mode(struct hclgevf_dev *hdev, bool en_bc_pmc)
+static int hclgevf_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
+				    bool en_mc_pmc)
 {
-	return hclgevf_cmd_set_promisc_mode(hdev, en_bc_pmc);
+	struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+	struct pci_dev *pdev = hdev->pdev;
+	bool en_bc_pmc;
+
+	en_bc_pmc = pdev->revision != 0x20;
+
+	return hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc,
+					    en_bc_pmc);
 }
 
 static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, unsigned int tqp_id,
@@ -1174,11 +1191,37 @@
 	}
 }
 
+static int hclgevf_get_host_mac_addr(struct hclgevf_dev *hdev, u8 *p)
+{
+	u8 host_mac[ETH_ALEN];
+	int status;
+
+	status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_MAC_ADDR, 0, NULL, 0,
+				      true, host_mac, ETH_ALEN);
+	if (status) {
+		dev_err(&hdev->pdev->dev,
+			"fail to get VF MAC from host %d", status);
+		return status;
+	}
+
+	ether_addr_copy(p, host_mac);
+
+	return 0;
+}
+
 static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p)
 {
 	struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+	u8 host_mac_addr[ETH_ALEN];
+
+	if (hclgevf_get_host_mac_addr(hdev, host_mac_addr))
+		return;
 
-	ether_addr_copy(p, hdev->hw.mac.mac_addr);
+	hdev->has_pf_mac = !is_zero_ether_addr(host_mac_addr);
+	if (hdev->has_pf_mac)
+		ether_addr_copy(p, host_mac_addr);
+	else
+		ether_addr_copy(p, hdev->hw.mac.mac_addr);
 }
 
 static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p,
@@ -1273,14 +1316,13 @@
 	msg_data[0] = is_kill;
 	memcpy(&msg_data[1], &vlan_id, sizeof(vlan_id));
 	memcpy(&msg_data[3], &proto, sizeof(proto));
-	ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
-				   HCLGE_MBX_VLAN_FILTER, msg_data,
-				   HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0);
-
 	/* when remove hw vlan filter failed, record the vlan id,
 	 * and try to remove it from hw later, to be consistence
 	 * with stack.
 	 */
+	ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
+				   HCLGE_MBX_VLAN_FILTER, msg_data,
+				   HCLGEVF_VLAN_MBX_MSG_LEN, true, NULL, 0);
 	if (is_kill && ret)
 		set_bit(vlan_id, hdev->vlan_del_fail_bmap);
 
@@ -1368,32 +1410,6 @@
 	return ret;
 }
 
-static void hclgevf_flr_done(struct hnae3_ae_dev *ae_dev)
-{
-	struct hclgevf_dev *hdev = ae_dev->priv;
-
-	set_bit(HNAE3_FLR_DONE, &hdev->flr_state);
-}
-
-static int hclgevf_flr_poll_timeout(struct hclgevf_dev *hdev,
-				    unsigned long delay_us,
-				    unsigned long wait_cnt)
-{
-	unsigned long cnt = 0;
-
-	while (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state) &&
-	       cnt++ < wait_cnt)
-		usleep_range(delay_us, delay_us * 2);
-
-	if (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state)) {
-		dev_err(&hdev->pdev->dev,
-			"flr wait timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 static int hclgevf_reset_wait(struct hclgevf_dev *hdev)
 {
 #define HCLGEVF_RESET_WAIT_US	20000
@@ -1404,11 +1420,7 @@
 	u32 val;
 	int ret;
 
-	if (hdev->reset_type == HNAE3_FLR_RESET)
-		return hclgevf_flr_poll_timeout(hdev,
-						HCLGEVF_RESET_WAIT_US,
-						HCLGEVF_RESET_WAIT_CNT);
-	else if (hdev->reset_type == HNAE3_VF_RESET)
+	if (hdev->reset_type == HNAE3_VF_RESET)
 		ret = readl_poll_timeout(hdev->hw.io_base +
 					 HCLGEVF_VF_RST_ING, val,
 					 !(val & HCLGEVF_VF_RST_ING_BIT),
@@ -1432,7 +1444,10 @@
 	 * might happen in case reset assertion was made by PF. Yes, this also
 	 * means we might end up waiting bit more even for VF reset.
 	 */
-	msleep(5000);
+	if (hdev->reset_type == HNAE3_VF_FULL_RESET)
+		msleep(5000);
+	else
+		msleep(500);
 
 	return 0;
 }
@@ -1480,7 +1495,8 @@
 	/* clear handshake status with IMP */
 	hclgevf_reset_handshake(hdev, false);
 
-	return 0;
+	/* bring up the nic to enable TX/RX again */
+	return hclgevf_notify_client(hdev, HNAE3_UP_CLIENT);
 }
 
 static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev)
@@ -1489,18 +1505,10 @@
 
 	int ret = 0;
 
-	switch (hdev->reset_type) {
-	case HNAE3_VF_FUNC_RESET:
+	if (hdev->reset_type == HNAE3_VF_FUNC_RESET) {
 		ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_RESET, 0, NULL,
 					   0, true, NULL, sizeof(u8));
 		hdev->rst_stats.vf_func_rst_cnt++;
-		break;
-	case HNAE3_FLR_RESET:
-		set_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
-		hdev->rst_stats.flr_rst_cnt++;
-		break;
-	default:
-		break;
 	}
 
 	set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state);
@@ -1513,12 +1521,39 @@
 	return ret;
 }
 
+static void hclgevf_dump_rst_info(struct hclgevf_dev *hdev)
+{
+	dev_info(&hdev->pdev->dev, "VF function reset count: %u\n",
+		 hdev->rst_stats.vf_func_rst_cnt);
+	dev_info(&hdev->pdev->dev, "FLR reset count: %u\n",
+		 hdev->rst_stats.flr_rst_cnt);
+	dev_info(&hdev->pdev->dev, "VF reset count: %u\n",
+		 hdev->rst_stats.vf_rst_cnt);
+	dev_info(&hdev->pdev->dev, "reset done count: %u\n",
+		 hdev->rst_stats.rst_done_cnt);
+	dev_info(&hdev->pdev->dev, "HW reset done count: %u\n",
+		 hdev->rst_stats.hw_rst_done_cnt);
+	dev_info(&hdev->pdev->dev, "reset count: %u\n",
+		 hdev->rst_stats.rst_cnt);
+	dev_info(&hdev->pdev->dev, "reset fail count: %u\n",
+		 hdev->rst_stats.rst_fail_cnt);
+	dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n",
+		 hclgevf_read_dev(&hdev->hw, HCLGEVF_MISC_VECTOR_REG_BASE));
+	dev_info(&hdev->pdev->dev, "vector0 interrupt status: 0x%x\n",
+		 hclgevf_read_dev(&hdev->hw, HCLGEVF_VECTOR0_CMDQ_STAT_REG));
+	dev_info(&hdev->pdev->dev, "handshake status: 0x%x\n",
+		 hclgevf_read_dev(&hdev->hw, HCLGEVF_CMDQ_TX_DEPTH_REG));
+	dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n",
+		 hclgevf_read_dev(&hdev->hw, HCLGEVF_RST_ING));
+	dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state);
+}
+
 static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev)
 {
 	/* recover handshake status with IMP when reset fail */
 	hclgevf_reset_handshake(hdev, true);
 	hdev->rst_stats.rst_fail_cnt++;
-	dev_err(&hdev->pdev->dev, "failed to reset VF(%d)\n",
+	dev_err(&hdev->pdev->dev, "failed to reset VF(%u)\n",
 		hdev->rst_stats.rst_fail_cnt);
 
 	if (hdev->rst_stats.rst_fail_cnt < HCLGEVF_RESET_MAX_FAIL_CNT)
@@ -1527,10 +1562,13 @@
 	if (hclgevf_is_reset_pending(hdev)) {
 		set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
 		hclgevf_reset_task_schedule(hdev);
+	} else {
+		set_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state);
+		hclgevf_dump_rst_info(hdev);
 	}
 }
 
-static int hclgevf_reset(struct hclgevf_dev *hdev)
+static int hclgevf_reset_prepare(struct hclgevf_dev *hdev)
 {
 	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
 	int ret;
@@ -1540,61 +1578,64 @@
 	 */
 	ae_dev->reset_type = hdev->reset_type;
 	hdev->rst_stats.rst_cnt++;
-	rtnl_lock();
 
+	rtnl_lock();
 	/* bring down the nic to stop any ongoing TX/RX */
 	ret = hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT);
-	if (ret)
-		goto err_reset_lock;
-
 	rtnl_unlock();
-
-	ret = hclgevf_reset_prepare_wait(hdev);
 	if (ret)
-		goto err_reset;
+		return ret;
 
-	/* check if VF could successfully fetch the hardware reset completion
-	 * status from the hardware
-	 */
-	ret = hclgevf_reset_wait(hdev);
-	if (ret) {
-		/* can't do much in this situation, will disable VF */
-		dev_err(&hdev->pdev->dev,
-			"VF failed(=%d) to fetch H/W reset completion status\n",
-			ret);
-		goto err_reset;
-	}
+	return hclgevf_reset_prepare_wait(hdev);
+}
+
+static int hclgevf_reset_rebuild(struct hclgevf_dev *hdev)
+{
+	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+	int ret;
 
 	hdev->rst_stats.hw_rst_done_cnt++;
 
 	rtnl_lock();
-
 	/* now, re-initialize the nic client and ae device */
 	ret = hclgevf_reset_stack(hdev);
+	rtnl_unlock();
 	if (ret) {
 		dev_err(&hdev->pdev->dev, "failed to reset VF stack\n");
-		goto err_reset_lock;
+		return ret;
 	}
 
-	/* bring up the nic to enable TX/RX again */
-	ret = hclgevf_notify_client(hdev, HNAE3_UP_CLIENT);
-	if (ret)
-		goto err_reset_lock;
-
-	rtnl_unlock();
-
 	hdev->last_reset_time = jiffies;
 	ae_dev->reset_type = HNAE3_NONE_RESET;
 	hdev->rst_stats.rst_done_cnt++;
 	hdev->rst_stats.rst_fail_cnt = 0;
+	clear_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state);
+
+	return 0;
+}
+
+static void hclgevf_reset(struct hclgevf_dev *hdev)
+{
+	if (hclgevf_reset_prepare(hdev))
+		goto err_reset;
+
+	/* check if VF could successfully fetch the hardware reset completion
+	 * status from the hardware
+	 */
+	if (hclgevf_reset_wait(hdev)) {
+		/* can't do much in this situation, will disable VF */
+		dev_err(&hdev->pdev->dev,
+			"failed to fetch H/W reset completion status\n");
+		goto err_reset;
+	}
+
+	if (hclgevf_reset_rebuild(hdev))
+		goto err_reset;
+
+	return;
 
-	return ret;
-err_reset_lock:
-	rtnl_unlock();
 err_reset:
 	hclgevf_reset_err_handle(hdev);
-
-	return ret;
 }
 
 static enum hnae3_reset_type hclgevf_get_reset_level(struct hclgevf_dev *hdev,
@@ -1657,25 +1698,60 @@
 	set_bit(rst_type, &hdev->default_reset_request);
 }
 
+static void hclgevf_enable_vector(struct hclgevf_misc_vector *vector, bool en)
+{
+	writel(en ? 1 : 0, vector->addr);
+}
+
 static void hclgevf_flr_prepare(struct hnae3_ae_dev *ae_dev)
 {
-#define HCLGEVF_FLR_WAIT_MS	100
-#define HCLGEVF_FLR_WAIT_CNT	50
+#define HCLGEVF_FLR_RETRY_WAIT_MS	500
+#define HCLGEVF_FLR_RETRY_CNT		5
+
 	struct hclgevf_dev *hdev = ae_dev->priv;
-	int cnt = 0;
+	int retry_cnt = 0;
+	int ret;
 
-	clear_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
-	clear_bit(HNAE3_FLR_DONE, &hdev->flr_state);
-	set_bit(HNAE3_FLR_RESET, &hdev->default_reset_request);
-	hclgevf_reset_event(hdev->pdev, NULL);
+retry:
+	down(&hdev->reset_sem);
+	set_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state);
+	hdev->reset_type = HNAE3_FLR_RESET;
+	ret = hclgevf_reset_prepare(hdev);
+	if (ret) {
+		dev_err(&hdev->pdev->dev, "fail to prepare FLR, ret=%d\n",
+			ret);
+		if (hdev->reset_pending ||
+		    retry_cnt++ < HCLGEVF_FLR_RETRY_CNT) {
+			dev_err(&hdev->pdev->dev,
+				"reset_pending:0x%lx, retry_cnt:%d\n",
+				hdev->reset_pending, retry_cnt);
+			clear_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state);
+			up(&hdev->reset_sem);
+			msleep(HCLGEVF_FLR_RETRY_WAIT_MS);
+			goto retry;
+		}
+	}
 
-	while (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state) &&
-	       cnt++ < HCLGEVF_FLR_WAIT_CNT)
-		msleep(HCLGEVF_FLR_WAIT_MS);
+	/* disable misc vector before FLR done */
+	hclgevf_enable_vector(&hdev->misc_vector, false);
+	hdev->rst_stats.flr_rst_cnt++;
+}
 
-	if (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state))
-		dev_err(&hdev->pdev->dev,
-			"flr wait down timeout: %d\n", cnt);
+static void hclgevf_flr_done(struct hnae3_ae_dev *ae_dev)
+{
+	struct hclgevf_dev *hdev = ae_dev->priv;
+	int ret;
+
+	hclgevf_enable_vector(&hdev->misc_vector, true);
+
+	ret = hclgevf_reset_rebuild(hdev);
+	if (ret)
+		dev_warn(&hdev->pdev->dev, "fail to rebuild, ret=%d\n",
+			 ret);
+
+	hdev->reset_type = HNAE3_NONE_RESET;
+	clear_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state);
+	up(&hdev->reset_sem);
 }
 
 static u32 hclgevf_get_fw_version(struct hnae3_handle *handle)
@@ -1702,60 +1778,37 @@
 
 void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev)
 {
-	if (!test_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state) &&
-	    !test_bit(HCLGEVF_STATE_REMOVING, &hdev->state)) {
-		set_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state);
-		schedule_work(&hdev->rst_service_task);
-	}
+	if (!test_bit(HCLGEVF_STATE_REMOVING, &hdev->state) &&
+	    !test_and_set_bit(HCLGEVF_STATE_RST_SERVICE_SCHED,
+			      &hdev->state))
+		mod_delayed_work(hclgevf_wq, &hdev->service_task, 0);
 }
 
 void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev)
 {
-	if (!test_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED, &hdev->state) &&
-	    !test_bit(HCLGEVF_STATE_MBX_HANDLING, &hdev->state)) {
-		set_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED, &hdev->state);
-		schedule_work(&hdev->mbx_service_task);
-	}
-}
-
-static void hclgevf_task_schedule(struct hclgevf_dev *hdev)
-{
-	if (!test_bit(HCLGEVF_STATE_DOWN, &hdev->state)  &&
-	    !test_and_set_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state))
-		schedule_work(&hdev->service_task);
-}
-
-static void hclgevf_deferred_task_schedule(struct hclgevf_dev *hdev)
-{
-	/* if we have any pending mailbox event then schedule the mbx task */
-	if (hdev->mbx_event_pending)
-		hclgevf_mbx_task_schedule(hdev);
-
-	if (test_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state))
-		hclgevf_reset_task_schedule(hdev);
+	if (!test_bit(HCLGEVF_STATE_REMOVING, &hdev->state) &&
+	    !test_and_set_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED,
+			      &hdev->state))
+		mod_delayed_work(hclgevf_wq, &hdev->service_task, 0);
 }
 
-static void hclgevf_service_timer(struct timer_list *t)
+static void hclgevf_task_schedule(struct hclgevf_dev *hdev,
+				  unsigned long delay)
 {
-	struct hclgevf_dev *hdev = from_timer(hdev, t, service_timer);
-
-	mod_timer(&hdev->service_timer, jiffies +
-		  HCLGEVF_GENERAL_TASK_INTERVAL * HZ);
-
-	hdev->stats_timer++;
-	hclgevf_task_schedule(hdev);
+	if (!test_bit(HCLGEVF_STATE_REMOVING, &hdev->state) &&
+	    !test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state))
+		mod_delayed_work(hclgevf_wq, &hdev->service_task, delay);
 }
 
-static void hclgevf_reset_service_task(struct work_struct *work)
+static void hclgevf_reset_service_task(struct hclgevf_dev *hdev)
 {
-	struct hclgevf_dev *hdev =
-		container_of(work, struct hclgevf_dev, rst_service_task);
-	int ret;
+#define	HCLGEVF_MAX_RESET_ATTEMPTS_CNT	3
 
-	if (test_and_set_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state))
+	if (!test_and_clear_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state))
 		return;
 
-	clear_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state);
+	down(&hdev->reset_sem);
+	set_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state);
 
 	if (test_and_clear_bit(HCLGEVF_RESET_PENDING,
 			       &hdev->reset_state)) {
@@ -1769,12 +1822,8 @@
 		hdev->last_reset_time = jiffies;
 		while ((hdev->reset_type =
 			hclgevf_get_reset_level(hdev, &hdev->reset_pending))
-		       != HNAE3_NONE_RESET) {
-			ret = hclgevf_reset(hdev);
-			if (ret)
-				dev_err(&hdev->pdev->dev,
-					"VF stack reset failed %d.\n", ret);
-		}
+		       != HNAE3_NONE_RESET)
+			hclgevf_reset(hdev);
 	} else if (test_and_clear_bit(HCLGEVF_RESET_REQUESTED,
 				      &hdev->reset_state)) {
 		/* we could be here when either of below happens:
@@ -1800,7 +1849,7 @@
 		 * We cannot do much for 2. but to check first we can try reset
 		 * our PCIe + stack and see if it alleviates the problem.
 		 */
-		if (hdev->reset_attempts > 3) {
+		if (hdev->reset_attempts > HCLGEVF_MAX_RESET_ATTEMPTS_CNT) {
 			/* prepare for full reset of stack + pcie interface */
 			set_bit(HNAE3_VF_FULL_RESET, &hdev->reset_pending);
 
@@ -1815,42 +1864,29 @@
 		hclgevf_reset_task_schedule(hdev);
 	}
 
+	hdev->reset_type = HNAE3_NONE_RESET;
 	clear_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state);
+	up(&hdev->reset_sem);
 }
 
-static void hclgevf_mailbox_service_task(struct work_struct *work)
+static void hclgevf_mailbox_service_task(struct hclgevf_dev *hdev)
 {
-	struct hclgevf_dev *hdev;
-
-	hdev = container_of(work, struct hclgevf_dev, mbx_service_task);
+	if (!test_and_clear_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED, &hdev->state))
+		return;
 
 	if (test_and_set_bit(HCLGEVF_STATE_MBX_HANDLING, &hdev->state))
 		return;
 
-	clear_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED, &hdev->state);
-
 	hclgevf_mbx_async_handler(hdev);
 
 	clear_bit(HCLGEVF_STATE_MBX_HANDLING, &hdev->state);
 }
 
-static void hclgevf_keep_alive_timer(struct timer_list *t)
+static void hclgevf_keep_alive(struct hclgevf_dev *hdev)
 {
-	struct hclgevf_dev *hdev = from_timer(hdev, t, keep_alive_timer);
-
-	schedule_work(&hdev->keep_alive_task);
-	mod_timer(&hdev->keep_alive_timer, jiffies +
-		  HCLGEVF_KEEP_ALIVE_TASK_INTERVAL * HZ);
-}
-
-static void hclgevf_keep_alive_task(struct work_struct *work)
-{
-	struct hclgevf_dev *hdev;
 	u8 respmsg;
 	int ret;
 
-	hdev = container_of(work, struct hclgevf_dev, keep_alive_task);
-
 	if (test_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state))
 		return;
 
@@ -1861,19 +1897,32 @@
 			"VF sends keep alive cmd failed(=%d)\n", ret);
 }
 
-static void hclgevf_service_task(struct work_struct *work)
+static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev)
 {
-	struct hnae3_handle *handle;
-	struct hclgevf_dev *hdev;
+	unsigned long delta = round_jiffies_relative(HZ);
+	struct hnae3_handle *handle = &hdev->nic;
 
-	hdev = container_of(work, struct hclgevf_dev, service_task);
-	handle = &hdev->nic;
+	if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) {
+		delta = jiffies - hdev->last_serv_processed;
 
-	if (hdev->stats_timer >= HCLGEVF_STATS_TIMER_INTERVAL) {
-		hclgevf_tqps_update_stats(handle);
-		hdev->stats_timer = 0;
+		if (delta < round_jiffies_relative(HZ)) {
+			delta = round_jiffies_relative(HZ) - delta;
+			goto out;
+		}
+	}
+
+	hdev->serv_processed_cnt++;
+	if (!(hdev->serv_processed_cnt % HCLGEVF_KEEP_ALIVE_TASK_INTERVAL))
+		hclgevf_keep_alive(hdev);
+
+	if (test_bit(HCLGEVF_STATE_DOWN, &hdev->state)) {
+		hdev->last_serv_processed = jiffies;
+		goto out;
 	}
 
+	if (!(hdev->serv_processed_cnt % HCLGEVF_STATS_TIMER_INTERVAL))
+		hclgevf_tqps_update_stats(handle);
+
 	/* request the link status from the PF. PF would be able to tell VF
 	 * about such updates in future so we might remove this later
 	 */
@@ -1883,9 +1932,27 @@
 
 	hclgevf_sync_vlan_filter(hdev);
 
-	hclgevf_deferred_task_schedule(hdev);
+	hdev->last_serv_processed = jiffies;
 
-	clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state);
+out:
+	hclgevf_task_schedule(hdev, delta);
+}
+
+static void hclgevf_service_task(struct work_struct *work)
+{
+	struct hclgevf_dev *hdev = container_of(work, struct hclgevf_dev,
+						service_task.work);
+
+	hclgevf_reset_service_task(hdev);
+	hclgevf_mailbox_service_task(hdev);
+	hclgevf_periodic_service_task(hdev);
+
+	/* Handle reset and mbx again in case periodical task delays the
+	 * handling by calling hclgevf_task_schedule() in
+	 * hclgevf_periodic_service_task()
+	 */
+	hclgevf_reset_service_task(hdev);
+	hclgevf_mailbox_service_task(hdev);
 }
 
 static void hclgevf_clear_event_cause(struct hclgevf_dev *hdev, u32 regclr)
@@ -1938,16 +2005,14 @@
 		return HCLGEVF_VECTOR0_EVENT_MBX;
 	}
 
-	dev_dbg(&hdev->pdev->dev, "vector 0 interrupt from unknown source\n");
+	/* print other vector0 event source */
+	dev_info(&hdev->pdev->dev,
+		 "vector 0 interrupt from unknown source, cmdq_src = %#x\n",
+		 cmdq_stat_reg);
 
 	return HCLGEVF_VECTOR0_EVENT_OTHER;
 }
 
-static void hclgevf_enable_vector(struct hclgevf_misc_vector *vector, bool en)
-{
-	writel(en ? 1 : 0, vector->addr);
-}
-
 static irqreturn_t hclgevf_misc_irq_handle(int irq, void *data)
 {
 	enum hclgevf_evt_cause event_cause;
@@ -1956,6 +2021,8 @@
 
 	hclgevf_enable_vector(&hdev->misc_vector, false);
 	event_cause = hclgevf_check_evt_cause(hdev, &clearval);
+	if (event_cause != HCLGEVF_VECTOR0_EVENT_OTHER)
+		hclgevf_clear_event_cause(hdev, clearval);
 
 	switch (event_cause) {
 	case HCLGEVF_VECTOR0_EVENT_RST:
@@ -1968,10 +2035,7 @@
 		break;
 	}
 
-	if (event_cause != HCLGEVF_VECTOR0_EVENT_OTHER) {
-		hclgevf_clear_event_cause(hdev, clearval);
-		hclgevf_enable_vector(&hdev->misc_vector, true);
-	}
+	hclgevf_enable_vector(&hdev->misc_vector, true);
 
 	return IRQ_HANDLED;
 }
@@ -2103,7 +2167,6 @@
 		ret = hclgevf_set_rss_input_tuple(hdev, rss_cfg);
 		if (ret)
 			return ret;
-
 	}
 
 	/* Initialize RSS indirect table */
@@ -2119,20 +2182,45 @@
 
 static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev)
 {
+	struct hnae3_handle *nic = &hdev->nic;
+	int ret;
+
+	ret = hclgevf_en_hw_strip_rxvtag(nic, true);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to enable rx vlan offload, ret = %d\n", ret);
+		return ret;
+	}
+
 	return hclgevf_set_vlan_filter(&hdev->nic, htons(ETH_P_8021Q), 0,
 				       false);
 }
 
+static void hclgevf_flush_link_update(struct hclgevf_dev *hdev)
+{
+#define HCLGEVF_FLUSH_LINK_TIMEOUT	100000
+
+	unsigned long last = hdev->serv_processed_cnt;
+	int i = 0;
+
+	while (test_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state) &&
+	       i++ < HCLGEVF_FLUSH_LINK_TIMEOUT &&
+	       last == hdev->serv_processed_cnt)
+		usleep_range(1, 1);
+}
+
 static void hclgevf_set_timer_task(struct hnae3_handle *handle, bool enable)
 {
 	struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
 
 	if (enable) {
-		mod_timer(&hdev->service_timer, jiffies + HZ);
+		hclgevf_task_schedule(hdev, 0);
 	} else {
-		del_timer_sync(&hdev->service_timer);
-		cancel_work_sync(&hdev->service_task);
-		clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state);
+		set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
+
+		/* flush memory to make sure DOWN is seen by service task */
+		smp_mb__before_atomic();
+		hclgevf_flush_link_update(hdev);
 	}
 }
 
@@ -2140,14 +2228,14 @@
 {
 	struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
 
+	clear_bit(HCLGEVF_STATE_DOWN, &hdev->state);
+
 	hclgevf_reset_tqp_stats(handle);
 
 	hclgevf_request_link_info(hdev);
 
 	hclgevf_update_link_mode(hdev);
 
-	clear_bit(HCLGEVF_STATE_DOWN, &hdev->state);
-
 	return 0;
 }
 
@@ -2179,16 +2267,12 @@
 
 static int hclgevf_client_start(struct hnae3_handle *handle)
 {
-	struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
 	int ret;
 
 	ret = hclgevf_set_alive(handle, true);
 	if (ret)
 		return ret;
 
-	mod_timer(&hdev->keep_alive_timer, jiffies +
-		  HCLGEVF_KEEP_ALIVE_TASK_INTERVAL * HZ);
-
 	return 0;
 }
 
@@ -2201,27 +2285,18 @@
 	if (ret)
 		dev_warn(&hdev->pdev->dev,
 			 "%s failed %d\n", __func__, ret);
-
-	del_timer_sync(&hdev->keep_alive_timer);
-	cancel_work_sync(&hdev->keep_alive_task);
 }
 
 static void hclgevf_state_init(struct hclgevf_dev *hdev)
 {
-	/* setup tasks for the MBX */
-	INIT_WORK(&hdev->mbx_service_task, hclgevf_mailbox_service_task);
 	clear_bit(HCLGEVF_STATE_MBX_SERVICE_SCHED, &hdev->state);
 	clear_bit(HCLGEVF_STATE_MBX_HANDLING, &hdev->state);
+	clear_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state);
 
-	/* setup tasks for service timer */
-	timer_setup(&hdev->service_timer, hclgevf_service_timer, 0);
-
-	INIT_WORK(&hdev->service_task, hclgevf_service_task);
-	clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state);
-
-	INIT_WORK(&hdev->rst_service_task, hclgevf_reset_service_task);
+	INIT_DELAYED_WORK(&hdev->service_task, hclgevf_service_task);
 
 	mutex_init(&hdev->mbx_resp.mbx_mutex);
+	sema_init(&hdev->reset_sem, 1);
 
 	/* bring the device down */
 	set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
@@ -2232,18 +2307,8 @@
 	set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
 	set_bit(HCLGEVF_STATE_REMOVING, &hdev->state);
 
-	if (hdev->keep_alive_timer.function)
-		del_timer_sync(&hdev->keep_alive_timer);
-	if (hdev->keep_alive_task.func)
-		cancel_work_sync(&hdev->keep_alive_task);
-	if (hdev->service_timer.function)
-		del_timer_sync(&hdev->service_timer);
-	if (hdev->service_task.func)
-		cancel_work_sync(&hdev->service_task);
-	if (hdev->mbx_service_task.func)
-		cancel_work_sync(&hdev->mbx_service_task);
-	if (hdev->rst_service_task.func)
-		cancel_work_sync(&hdev->rst_service_task);
+	if (hdev->service_task.work.func)
+		cancel_delayed_work_sync(&hdev->service_task);
 
 	mutex_destroy(&hdev->mbx_resp.mbx_mutex);
 }
@@ -2272,7 +2337,7 @@
 	}
 	if (vectors < hdev->num_msi)
 		dev_warn(&hdev->pdev->dev,
-			 "requested %d MSI/MSI-X, but allocated %d MSI/MSI-X\n",
+			 "requested %u MSI/MSI-X, but allocated %d MSI/MSI-X\n",
 			 hdev->num_msi, vectors);
 
 	hdev->num_msi = vectors;
@@ -2317,8 +2382,10 @@
 
 	hclgevf_get_misc_vector(hdev);
 
+	snprintf(hdev->misc_vector.name, HNAE3_INT_NAME_LEN, "%s-misc-%s",
+		 HCLGEVF_NAME, pci_name(hdev->pdev));
 	ret = request_irq(hdev->misc_vector.vector_irq, hclgevf_misc_irq_handle,
-			  0, "hclgevf_cmd", hdev);
+			  0, hdev->misc_vector.name, hdev);
 	if (ret) {
 		dev_err(&hdev->pdev->dev, "VF failed to request misc irq(%d)\n",
 			hdev->misc_vector.vector_irq);
@@ -2348,12 +2415,12 @@
 
 	dev_info(dev, "VF info begin:\n");
 
-	dev_info(dev, "Task queue pairs numbers: %d\n", hdev->num_tqps);
-	dev_info(dev, "Desc num per TX queue: %d\n", hdev->num_tx_desc);
-	dev_info(dev, "Desc num per RX queue: %d\n", hdev->num_rx_desc);
-	dev_info(dev, "Numbers of vports: %d\n", hdev->num_alloc_vport);
-	dev_info(dev, "HW tc map: %d\n", hdev->hw_tc_map);
-	dev_info(dev, "PF media type of this VF: %d\n",
+	dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps);
+	dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc);
+	dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc);
+	dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport);
+	dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map);
+	dev_info(dev, "PF media type of this VF: %u\n",
 		 hdev->hw.mac.media_type);
 
 	dev_info(dev, "VF info end.\n");
@@ -2583,7 +2650,8 @@
 	struct pci_dev *pdev = hdev->pdev;
 	int ret = 0;
 
-	if (hdev->reset_type == HNAE3_VF_FULL_RESET &&
+	if ((hdev->reset_type == HNAE3_VF_FULL_RESET ||
+	     hdev->reset_type == HNAE3_FLR_RESET) &&
 	    test_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state)) {
 		hclgevf_misc_irq_uninit(hdev);
 		hclgevf_uninit_msi(hdev);
@@ -2648,12 +2716,6 @@
 		return ret;
 	}
 
-	if (pdev->revision >= 0x21) {
-		ret = hclgevf_set_promisc_mode(hdev, true);
-		if (ret)
-			return ret;
-	}
-
 	dev_info(&hdev->pdev->dev, "Reset done\n");
 
 	return 0;
@@ -2696,6 +2758,7 @@
 
 	hclgevf_state_init(hdev);
 	hdev->reset_level = HNAE3_VF_FUNC_RESET;
+	hdev->reset_type = HNAE3_NONE_RESET;
 
 	ret = hclgevf_misc_irq_init(hdev);
 	if (ret) {
@@ -2728,17 +2791,6 @@
 	if (ret)
 		goto err_config;
 
-	/* vf is not allowed to enable unicast/multicast promisc mode.
-	 * For revision 0x20, default to disable broadcast promisc mode,
-	 * firmware makes sure broadcast packets can be accepted.
-	 * For revision 0x21, default to enable broadcast promisc mode.
-	 */
-	if (pdev->revision >= 0x21) {
-		ret = hclgevf_set_promisc_mode(hdev, true);
-		if (ret)
-			goto err_config;
-	}
-
 	/* Initialize RSS for this VF */
 	ret = hclgevf_rss_init_hw(hdev);
 	if (ret) {
@@ -2758,6 +2810,8 @@
 	dev_info(&hdev->pdev->dev, "finished initializing %s driver\n",
 		 HCLGEVF_DRIVER_NAME);
 
+	hclgevf_task_schedule(hdev, round_jiffies_relative(HZ));
+
 	return 0;
 
 err_config:
@@ -2777,19 +2831,21 @@
 {
 	hclgevf_state_uninit(hdev);
 
+	hclgevf_send_mbx_msg(hdev, HCLGE_MBX_VF_UNINIT, 0, NULL, 0,
+			     false, NULL, 0);
+
 	if (test_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state)) {
 		hclgevf_misc_irq_uninit(hdev);
 		hclgevf_uninit_msi(hdev);
 	}
 
-	hclgevf_pci_uninit(hdev);
 	hclgevf_cmd_uninit(hdev);
+	hclgevf_pci_uninit(hdev);
 }
 
 static int hclgevf_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 {
 	struct pci_dev *pdev = ae_dev->pdev;
-	struct hclgevf_dev *hdev;
 	int ret;
 
 	ret = hclgevf_alloc_hdev(ae_dev);
@@ -2804,10 +2860,6 @@
 		return ret;
 	}
 
-	hdev = ae_dev->priv;
-	timer_setup(&hdev->keep_alive_timer, hclgevf_keep_alive_timer, 0);
-	INIT_WORK(&hdev->keep_alive_task, hclgevf_keep_alive_task);
-
 	return 0;
 }
 
@@ -3152,6 +3204,7 @@
 	.get_global_queue_id = hclgevf_get_qid_global,
 	.set_timer_task = hclgevf_set_timer_task,
 	.get_link_mode = hclgevf_get_link_mode,
+	.set_promisc_mode = hclgevf_set_promisc_mode,
 };
 
 static struct hnae3_ae_algo ae_algovf = {
@@ -3163,6 +3216,12 @@
 {
 	pr_info("%s is initializing\n", HCLGEVF_NAME);
 
+	hclgevf_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, HCLGEVF_NAME);
+	if (!hclgevf_wq) {
+		pr_err("%s: failed to create workqueue\n", HCLGEVF_NAME);
+		return -ENOMEM;
+	}
+
 	hnae3_register_ae_algo(&ae_algovf);
 
 	return 0;
@@ -3171,6 +3230,7 @@
 static void hclgevf_exit(void)
 {
 	hnae3_unregister_ae_algo(&ae_algovf);
+	destroy_workqueue(hclgevf_wq);
 }
 module_init(hclgevf_init);
 module_exit(hclgevf_exit);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -142,16 +142,15 @@
 	HCLGEVF_STATE_REMOVING,
 	HCLGEVF_STATE_NIC_REGISTERED,
 	/* task states */
-	HCLGEVF_STATE_SERVICE_SCHED,
 	HCLGEVF_STATE_RST_SERVICE_SCHED,
 	HCLGEVF_STATE_RST_HANDLING,
 	HCLGEVF_STATE_MBX_SERVICE_SCHED,
 	HCLGEVF_STATE_MBX_HANDLING,
 	HCLGEVF_STATE_CMD_DISABLE,
+	HCLGEVF_STATE_LINK_UPDATING,
+	HCLGEVF_STATE_RST_FAIL,
 };
 
-#define HCLGEVF_MPF_ENBALE 1
-
 struct hclgevf_mac {
 	u8 media_type;
 	u8 module_type;
@@ -222,6 +221,7 @@
 struct hclgevf_misc_vector {
 	u8 __iomem *addr;
 	int vector_irq;
+	char name[HNAE3_INT_NAME_LEN];
 };
 
 struct hclgevf_rst_stats {
@@ -253,6 +253,7 @@
 	unsigned long reset_state;	/* requested, pending */
 	struct hclgevf_rst_stats rst_stats;
 	u32 reset_attempts;
+	struct semaphore reset_sem;	/* protect reset process */
 
 	u32 fw_version;
 	u16 num_tqps;		/* num task queue pairs of this PF */
@@ -266,6 +267,7 @@
 	u16 num_tx_desc;	/* desc num of per tx queue */
 	u16 num_rx_desc;	/* desc num of per rx queue */
 	u8 hw_tc_map;
+	u8 has_pf_mac;
 
 	u16 num_msi;
 	u16 num_msi_left;
@@ -284,12 +286,7 @@
 	struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
 	struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
 
-	struct timer_list service_timer;
-	struct timer_list keep_alive_timer;
-	struct work_struct service_task;
-	struct work_struct keep_alive_task;
-	struct work_struct rst_service_task;
-	struct work_struct mbx_service_task;
+	struct delayed_work service_task;
 
 	struct hclgevf_tqp *htqp;
 
@@ -299,7 +296,8 @@
 	struct hnae3_client *nic_client;
 	struct hnae3_client *roce_client;
 	u32 flag;
-	u32 stats_timer;
+	unsigned long serv_processed_cnt;
+	unsigned long last_serv_processed;
 };
 
 static inline bool hclgevf_is_reset_pending(struct hclgevf_dev *hdev)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
@@ -33,7 +33,7 @@
 
 	if (resp_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) {
 		dev_err(&hdev->pdev->dev,
-			"VF mbx response len(=%d) exceeds maximum(=%d)\n",
+			"VF mbx response len(=%u) exceeds maximum(=%u)\n",
 			resp_len,
 			HCLGE_MBX_MAX_RESP_DATA_SIZE);
 		return -EINVAL;
@@ -49,7 +49,7 @@
 
 	if (i >= HCLGEVF_MAX_TRY_TIMES) {
 		dev_err(&hdev->pdev->dev,
-			"VF could not get mbx(%d,%d) resp(=%d) from PF in %d tries\n",
+			"VF could not get mbx(%u,%u) resp(=%d) from PF in %d tries\n",
 			code0, code1, hdev->mbx_resp.received_resp, i);
 		return -EIO;
 	}
@@ -68,10 +68,10 @@
 
 	if (!(r_code0 == code0 && r_code1 == code1 && !mbx_resp->resp_status)) {
 		dev_err(&hdev->pdev->dev,
-			"VF could not match resp code(code0=%d,code1=%d), %d\n",
+			"VF could not match resp code(code0=%u,code1=%u), %d\n",
 			code0, code1, mbx_resp->resp_status);
 		dev_err(&hdev->pdev->dev,
-			"VF could not match resp r_code(r_code0=%d,r_code1=%d)\n",
+			"VF could not match resp r_code(r_code0=%u,r_code1=%u)\n",
 			r_code0, r_code1);
 		return -EIO;
 	}
@@ -168,7 +168,7 @@
 		flag = le16_to_cpu(crq->desc[crq->next_to_use].flag);
 		if (unlikely(!hnae3_get_bit(flag, HCLGEVF_CMDQ_RX_OUTVLD_B))) {
 			dev_warn(&hdev->pdev->dev,
-				 "dropped invalid mailbox message, code = %d\n",
+				 "dropped invalid mailbox message, code = %u\n",
 				 req->msg[0]);
 
 			/* dropping/not processing this invalid message */
@@ -187,7 +187,7 @@
 		case HCLGE_MBX_PF_VF_RESP:
 			if (resp->received_resp)
 				dev_warn(&hdev->pdev->dev,
-					 "VF mbx resp flag not clear(%d)\n",
+					 "VF mbx resp flag not clear(%u)\n",
 					 req->msg[1]);
 			resp->received_resp = true;
 
@@ -205,6 +205,7 @@
 		case HCLGE_MBX_ASSERTING_RESET:
 		case HCLGE_MBX_LINK_STAT_MODE:
 		case HCLGE_MBX_PUSH_VLAN_INFO:
+		case HCLGE_MBX_PUSH_PROMISC_INFO:
 			/* set this mbx event as pending. This is required as we
 			 * might loose interrupt event when mbx task is busy
 			 * handling. This shall be cleared when mbx task just
@@ -218,7 +219,7 @@
 			if (atomic_read(&hdev->arq.count) >=
 			    HCLGE_MBX_MAX_ARQ_MSG_NUM) {
 				dev_warn(&hdev->pdev->dev,
-					 "Async Q full, dropping msg(%d)\n",
+					 "Async Q full, dropping msg(%u)\n",
 					 req->msg[1]);
 				break;
 			}
@@ -235,7 +236,7 @@
 			break;
 		default:
 			dev_err(&hdev->pdev->dev,
-				"VF received unsupported(%d) mbx msg from PF\n",
+				"VF received unsupported(%u) mbx msg from PF\n",
 				req->msg[0]);
 			break;
 		}
@@ -248,6 +249,14 @@
 			  crq->next_to_use);
 }
 
+static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev,
+				       u16 promisc_info)
+{
+	if (!promisc_info)
+		dev_info(&hdev->pdev->dev,
+			 "Promisc mode is closed by host for being untrusted.\n");
+}
+
 void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
 {
 	enum hnae3_reset_type reset_type;
@@ -313,9 +322,12 @@
 			hclgevf_update_port_base_vlan_info(hdev, state,
 							   (u8 *)vlan_info, 8);
 			break;
+		case HCLGE_MBX_PUSH_PROMISC_INFO:
+			hclgevf_parse_promisc_info(hdev, msg_q[1]);
+			break;
 		default:
 			dev_err(&hdev->pdev->dev,
-				"fetched unsupported(%d) message from arq\n",
+				"fetched unsupported(%u) message from arq\n",
 				msg_q[0]);
 			break;
 		}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
@@ -389,7 +389,8 @@
 
 	spin_unlock_bh(&cmdq->cmdq_lock);
 
-	if (!wait_for_completion_timeout(&done, CMDQ_TIMEOUT)) {
+	if (!wait_for_completion_timeout(&done,
+					 msecs_to_jiffies(CMDQ_TIMEOUT))) {
 		spin_lock_bh(&cmdq->cmdq_lock);
 
 		if (cmdq->errcode[curr_prod_idx] == &errcode)
@@ -623,6 +624,8 @@
 	if (!CMDQ_WQE_COMPLETED(be32_to_cpu(ctrl->ctrl_info)))
 		return -EBUSY;
 
+	dma_rmb();
+
 	errcode = CMDQ_WQE_ERRCODE_GET(be32_to_cpu(status->status_info), VAL);
 
 	cmdq_sync_cmd_handler(cmdq, ci, errcode);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
@@ -297,6 +297,7 @@
 	}
 
 	hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
+	hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);
 
 	hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT;
 	hw_ioctxt.cmdq_depth = 0;
@@ -359,50 +360,6 @@
 	return -EFAULT;
 }
 
-static int wait_for_io_stopped(struct hinic_hwdev *hwdev)
-{
-	struct hinic_cmd_io_status cmd_io_status;
-	struct hinic_hwif *hwif = hwdev->hwif;
-	struct pci_dev *pdev = hwif->pdev;
-	struct hinic_pfhwdev *pfhwdev;
-	unsigned long end;
-	u16 out_size;
-	int err;
-
-	if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
-		dev_err(&pdev->dev, "Unsupported PCI Function type\n");
-		return -EINVAL;
-	}
-
-	pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);
-
-	cmd_io_status.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
-
-	end = jiffies + msecs_to_jiffies(IO_STATUS_TIMEOUT);
-	do {
-		err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,
-					HINIC_COMM_CMD_IO_STATUS_GET,
-					&cmd_io_status, sizeof(cmd_io_status),
-					&cmd_io_status, &out_size,
-					HINIC_MGMT_MSG_SYNC);
-		if ((err) || (out_size != sizeof(cmd_io_status))) {
-			dev_err(&pdev->dev, "Failed to get IO status, ret = %d\n",
-				err);
-			return err;
-		}
-
-		if (cmd_io_status.status == IO_STOPPED) {
-			dev_info(&pdev->dev, "IO stopped\n");
-			return 0;
-		}
-
-		msleep(20);
-	} while (time_before(jiffies, end));
-
-	dev_err(&pdev->dev, "Wait for IO stopped - Timeout\n");
-	return -ETIMEDOUT;
-}
-
 /**
  * clear_io_resource - set the IO resources as not active in the NIC
  * @hwdev: the NIC HW device
@@ -422,11 +379,8 @@
 		return -EINVAL;
 	}
 
-	err = wait_for_io_stopped(hwdev);
-	if (err) {
-		dev_err(&pdev->dev, "IO has not stopped yet\n");
-		return err;
-	}
+	/* sleep 100ms to wait for firmware stopping I/O */
+	msleep(100);
 
 	cmd_clear_io_res.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
@@ -151,8 +151,8 @@
 
 	u8      lro_en;
 	u8      rsvd3;
+	u8      ppf_idx;
 	u8      rsvd4;
-	u8      rsvd5;
 
 	u16     rq_depth;
 	u16     rx_buf_sz_idx;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
@@ -188,7 +188,7 @@
  * eq_update_ci - update the HW cons idx of event queue
  * @eq: the event queue to update the cons idx for
  **/
-static void eq_update_ci(struct hinic_eq *eq)
+static void eq_update_ci(struct hinic_eq *eq, u32 arm_state)
 {
 	u32 val, addr = EQ_CONS_IDX_REG_ADDR(eq);
 
@@ -202,7 +202,7 @@
 
 	val |= HINIC_EQ_CI_SET(eq->cons_idx, IDX)    |
 	       HINIC_EQ_CI_SET(eq->wrapped, WRAPPED) |
-	       HINIC_EQ_CI_SET(EQ_ARMED, INT_ARMED);
+	       HINIC_EQ_CI_SET(arm_state, INT_ARMED);
 
 	val |= HINIC_EQ_CI_SET(eq_cons_idx_checksum_set(val), XOR_CHKSUM);
 
@@ -235,6 +235,8 @@
 		if (HINIC_EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED) == eq->wrapped)
 			break;
 
+		dma_rmb();
+
 		event = HINIC_EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
 		if (event >= HINIC_MAX_AEQ_EVENTS) {
 			dev_err(&pdev->dev, "Unknown AEQ Event %d\n", event);
@@ -347,7 +349,7 @@
 	else if (eq->type == HINIC_CEQ)
 		ceq_irq_handler(eq);
 
-	eq_update_ci(eq);
+	eq_update_ci(eq, EQ_ARMED);
 }
 
 /**
@@ -702,7 +704,7 @@
 	}
 
 	set_eq_ctrls(eq);
-	eq_update_ci(eq);
+	eq_update_ci(eq, EQ_ARMED);
 
 	err = alloc_eq_pages(eq);
 	if (err) {
@@ -752,18 +754,28 @@
  **/
 static void remove_eq(struct hinic_eq *eq)
 {
-	struct msix_entry *entry = &eq->msix_entry;
-
-	free_irq(entry->vector, eq);
+	hinic_set_msix_state(eq->hwif, eq->msix_entry.entry,
+			     HINIC_MSIX_DISABLE);
+	free_irq(eq->msix_entry.vector, eq);
 
 	if (eq->type == HINIC_AEQ) {
 		struct hinic_eq_work *aeq_work = &eq->aeq_work;
 
 		cancel_work_sync(&aeq_work->work);
+		/* clear aeq_len to avoid hw access host memory */
+		hinic_hwif_write_reg(eq->hwif,
+				     HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
 	} else if (eq->type == HINIC_CEQ) {
 		tasklet_kill(&eq->ceq_tasklet);
+		/* clear ceq_len to avoid hw access host memory */
+		hinic_hwif_write_reg(eq->hwif,
+				     HINIC_CSR_CEQ_CTRL_1_ADDR(eq->q_id), 0);
 	}
 
+	/* update cons_idx to avoid invalid interrupt */
+	eq->cons_idx = hinic_hwif_read_reg(eq->hwif, EQ_PROD_IDX_REG_ADDR(eq));
+	eq_update_ci(eq, EQ_NOT_ARMED);
+
 	free_eq_pages(eq);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
@@ -137,6 +137,7 @@
 #define HINIC_HWIF_FUNC_IDX(hwif)       ((hwif)->attr.func_idx)
 #define HINIC_HWIF_PCI_INTF(hwif)       ((hwif)->attr.pci_intf_idx)
 #define HINIC_HWIF_PF_IDX(hwif)         ((hwif)->attr.pf_idx)
+#define HINIC_HWIF_PPF_IDX(hwif)        ((hwif)->attr.ppf_idx)
 
 #define HINIC_FUNC_TYPE(hwif)           ((hwif)->attr.func_type)
 #define HINIC_IS_PF(hwif)               (HINIC_FUNC_TYPE(hwif) == HINIC_PF)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
@@ -43,7 +43,9 @@
 
 #define MSG_NOT_RESP                    0xFFFF
 
-#define MGMT_MSG_TIMEOUT                1000
+#define MGMT_MSG_TIMEOUT                5000
+
+#define SET_FUNC_PORT_MGMT_TIMEOUT	25000
 
 #define mgmt_to_pfhwdev(pf_mgmt)        \
 		container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
@@ -238,12 +240,13 @@
 			    u8 *buf_in, u16 in_size,
 			    u8 *buf_out, u16 *out_size,
 			    enum mgmt_direction_type direction,
-			    u16 resp_msg_id)
+			    u16 resp_msg_id, u32 timeout)
 {
 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
 	struct pci_dev *pdev = hwif->pdev;
 	struct hinic_recv_msg *recv_msg;
 	struct completion *recv_done;
+	unsigned long timeo;
 	u16 msg_id;
 	int err;
 
@@ -267,7 +270,9 @@
 		goto unlock_sync_msg;
 	}
 
-	if (!wait_for_completion_timeout(recv_done, MGMT_MSG_TIMEOUT)) {
+	timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
+
+	if (!wait_for_completion_timeout(recv_done, timeo)) {
 		dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
 		err = -ETIMEDOUT;
 		goto unlock_sync_msg;
@@ -341,6 +346,7 @@
 {
 	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
 	struct pci_dev *pdev = hwif->pdev;
+	u32 timeout = 0;
 
 	if (sync != HINIC_MGMT_MSG_SYNC) {
 		dev_err(&pdev->dev, "Invalid MGMT msg type\n");
@@ -352,9 +358,12 @@
 		return -EINVAL;
 	}
 
+	if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
+		timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
+
 	return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
 				buf_out, out_size, MGMT_DIRECT_SEND,
-				MSG_NOT_RESP);
+				MSG_NOT_RESP, timeout);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
@@ -94,6 +94,7 @@
 
 	struct hinic_wq         *wq;
 
+	struct cpumask		affinity_mask;
 	u32                     irq;
 	u16                     msix_entry;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -356,7 +356,8 @@
 	if (!num_cpus)
 		num_cpus = num_online_cpus();
 
-	nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
+	nic_dev->num_qps = hinic_hwdev_num_qps(hwdev);
+	nic_dev->num_qps = min_t(u16, nic_dev->num_qps, num_cpus);
 
 	nic_dev->rss_limit = nic_dev->num_qps;
 	nic_dev->num_rss = nic_dev->num_qps;
@@ -482,7 +483,6 @@
 {
 	struct hinic_dev *nic_dev = netdev_priv(netdev);
 	unsigned int flags;
-	int err;
 
 	down(&nic_dev->mgmt_lock);
 
@@ -496,20 +496,9 @@
 
 	up(&nic_dev->mgmt_lock);
 
-	err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
-	if (err) {
-		netif_err(nic_dev, drv, netdev,
-			  "Failed to set func port state\n");
-		nic_dev->flags |= (flags & HINIC_INTF_UP);
-		return err;
-	}
+	hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
 
-	err = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
-	if (err) {
-		netif_err(nic_dev, drv, netdev, "Failed to set port state\n");
-		nic_dev->flags |= (flags & HINIC_INTF_UP);
-		return err;
-	}
+	hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
 
 	if (nic_dev->flags & HINIC_RSS_ENABLE) {
 		hinic_rss_deinit(nic_dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_rx.c
@@ -350,6 +350,9 @@
 		if (!rq_wqe)
 			break;
 
+		/* make sure we read rx_done before packet length */
+		dma_rmb();
+
 		cqe = rq->cqe[ci];
 		status =  be32_to_cpu(cqe->status);
 		hinic_rq_get_sge(rxq->rq, rq_wqe, ci, &sge);
@@ -475,7 +478,6 @@
 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
 	struct hinic_rq *rq = rxq->rq;
 	struct hinic_qp *qp;
-	struct cpumask mask;
 	int err;
 
 	rx_add_napi(rxq);
@@ -492,8 +494,8 @@
 	}
 
 	qp = container_of(rq, struct hinic_qp, rq);
-	cpumask_set_cpu(qp->q_id % num_online_cpus(), &mask);
-	return irq_set_affinity_hint(rq->irq, &mask);
+	cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
+	return irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
 }
 
 static void rx_free_irq(struct hinic_rxq *rxq)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/huawei/hinic/hinic_tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/huawei/hinic/hinic_tx.c
@@ -45,7 +45,7 @@
 
 #define HW_CONS_IDX(sq)                 be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
 
-#define MIN_SKB_LEN                     17
+#define MIN_SKB_LEN			32
 
 #define	MAX_PAYLOAD_OFFSET	        221
 #define TRANSPORT_OFFSET(l4_hdr, skb)	((u32)((l4_hdr) - (skb)->data))
@@ -622,6 +622,8 @@
 	do {
 		hw_ci = HW_CONS_IDX(sq) & wq->mask;
 
+		dma_rmb();
+
 		/* Reading a WQEBB to get real WQE size and consumer index. */
 		sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &sw_ci);
 		if ((!sq_wqe) ||
--- linux-ein-5.4.0.orig/drivers/net/ethernet/i825xx/82596.c
+++ linux-ein-5.4.0/drivers/net/ethernet/i825xx/82596.c
@@ -1155,7 +1155,7 @@
 			err = -ENODEV;
 			goto out;
 		}
-		memcpy(eth_addr, (void *) 0xfffc1f2c, ETH_ALEN);	/* YUCK! Get addr from NOVRAM */
+		memcpy(eth_addr, absolute_pointer(0xfffc1f2c), ETH_ALEN); /* YUCK! Get addr from NOVRAM */
 		dev->base_addr = MVME_I596_BASE;
 		dev->irq = (unsigned) MVME16x_IRQ_I596;
 		goto found;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/i825xx/sni_82596.c
+++ linux-ein-5.4.0/drivers/net/ethernet/i825xx/sni_82596.c
@@ -123,9 +123,10 @@
 	netdevice->dev_addr[5] = readb(eth_addr + 0x06);
 	iounmap(eth_addr);
 
-	if (!netdevice->irq) {
+	if (netdevice->irq < 0) {
 		printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
 			__FILE__, netdevice->base_addr);
+		retval = netdevice->irq;
 		goto probe_failed;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -2617,10 +2617,8 @@
 	u16 dummy16 = 0;
 
 	cb0 = (void *)get_zeroed_page(GFP_KERNEL);
-	if (!cb0) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!cb0)
+		return -ENOMEM;
 
 	for (i = 0; i < (port->num_def_qps); i++) {
 		struct ehea_port_res *pr =  &port->port_res[i];
@@ -2640,6 +2638,7 @@
 					    cb0);
 		if (hret != H_SUCCESS) {
 			netdev_err(dev, "query_ehea_qp failed (1)\n");
+			ret = -EFAULT;
 			goto out;
 		}
 
@@ -2652,6 +2651,7 @@
 					     &dummy64, &dummy16, &dummy16);
 		if (hret != H_SUCCESS) {
 			netdev_err(dev, "modify_ehea_qp failed (1)\n");
+			ret = -EFAULT;
 			goto out;
 		}
 
@@ -2660,6 +2660,7 @@
 					    cb0);
 		if (hret != H_SUCCESS) {
 			netdev_err(dev, "query_ehea_qp failed (2)\n");
+			ret = -EFAULT;
 			goto out;
 		}
 
@@ -2896,6 +2897,7 @@
 	ret = of_device_register(&port->ofdev);
 	if (ret) {
 		pr_err("failed to register device. ret=%d\n", ret);
+		put_device(&port->ofdev.dev);
 		goto out;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ibm/ibmveth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ibm/ibmveth.c
@@ -196,7 +196,7 @@
 	unsigned long offset;
 
 	for (offset = 0; offset < length; offset += SMP_CACHE_BYTES)
-		asm("dcbfl %0,%1" :: "b" (addr), "r" (offset));
+		asm("dcbf %0,%1,1" :: "b" (addr), "r" (offset));
 }
 
 /* replenish the buffers for a pool.  note that we don't need to
@@ -1317,6 +1317,7 @@
 			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);
 
@@ -1353,16 +1354,26 @@
 			skb_put(skb, length);
 			skb->protocol = eth_type_trans(skb, netdev);
 
-			if (csum_good) {
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
-				ibmveth_rx_csum_helper(skb, adapter);
+			/* 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) {
+			if ((length > netdev->mtu + ETH_HLEN) ||
+			    lrg_pkt || iph_check == 0xffff) {
 				ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
 				adapter->rx_large_packets++;
 			}
 
+			if (csum_good) {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+				ibmveth_rx_csum_helper(skb, adapter);
+			}
+
 			napi_gro_receive(napi, skb);	/* send it up */
 
 			netdev->stats.rx_packets++;
@@ -1682,7 +1693,7 @@
 	}
 
 	netdev->min_mtu = IBMVETH_MIN_MTU;
-	netdev->max_mtu = ETH_MAX_MTU;
+	netdev->max_mtu = ETH_MAX_MTU - IBMVETH_BUFF_OH;
 
 	memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ibm/ibmvnic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ibm/ibmvnic.c
@@ -176,7 +176,7 @@
 	ltb->map_id = adapter->map_id;
 	adapter->map_id++;
 
-	init_completion(&adapter->fw_done);
+	reinit_completion(&adapter->fw_done);
 	rc = send_request_map(adapter, ltb->addr,
 			      ltb->size, ltb->map_id);
 	if (rc) {
@@ -202,8 +202,13 @@
 	if (!ltb->buff)
 		return;
 
+	/* VIOS automatically unmaps the long term buffer at remote
+	 * end for the following resets:
+	 * FAILOVER, MOBILITY, TIMEOUT.
+	 */
 	if (adapter->reset_reason != VNIC_RESET_FAILOVER &&
-	    adapter->reset_reason != VNIC_RESET_MOBILITY)
+	    adapter->reset_reason != VNIC_RESET_MOBILITY &&
+	    adapter->reset_reason != VNIC_RESET_TIMEOUT)
 		send_request_unmap(adapter, ltb->map_id);
 	dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
 }
@@ -215,7 +220,7 @@
 
 	memset(ltb->buff, 0, ltb->size);
 
-	init_completion(&adapter->fw_done);
+	reinit_completion(&adapter->fw_done);
 	rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
 	if (rc)
 		return rc;
@@ -416,6 +421,9 @@
 	int i, j, rc;
 	u64 *size_array;
 
+	if (!adapter->rx_pool)
+		return -1;
+
 	size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
 		be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size));
 
@@ -586,6 +594,9 @@
 	int tx_scrqs;
 	int i, rc;
 
+	if (!adapter->tx_pool)
+		return -1;
+
 	tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
 	for (i = 0; i < tx_scrqs; i++) {
 		rc = reset_one_tx_pool(adapter, &adapter->tso_pool[i]);
@@ -683,8 +694,11 @@
 
 	adapter->tso_pool = kcalloc(tx_subcrqs,
 				    sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
-	if (!adapter->tso_pool)
+	if (!adapter->tso_pool) {
+		kfree(adapter->tx_pool);
+		adapter->tx_pool = NULL;
 		return -1;
+	}
 
 	adapter->num_active_tx_pools = tx_subcrqs;
 
@@ -779,12 +793,13 @@
 	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
 	unsigned long timeout = msecs_to_jiffies(30000);
 	int retry_count = 0;
+	int retries = 10;
 	bool retry;
 	int rc;
 
 	do {
 		retry = false;
-		if (retry_count > IBMVNIC_MAX_QUEUES) {
+		if (retry_count > retries) {
 			netdev_warn(netdev, "Login attempts exceeded\n");
 			return -1;
 		}
@@ -799,11 +814,23 @@
 
 		if (!wait_for_completion_timeout(&adapter->init_done,
 						 timeout)) {
-			netdev_warn(netdev, "Login timed out\n");
-			return -1;
+			netdev_warn(netdev, "Login timed out, retrying...\n");
+			retry = true;
+			adapter->init_done_rc = 0;
+			retry_count++;
+			continue;
 		}
 
-		if (adapter->init_done_rc == PARTIALSUCCESS) {
+		if (adapter->init_done_rc == ABORTED) {
+			netdev_warn(netdev, "Login aborted, retrying...\n");
+			retry = true;
+			adapter->init_done_rc = 0;
+			retry_count++;
+			/* FW or device may be busy, so
+			 * wait a bit before retrying login
+			 */
+			msleep(500);
+		} else if (adapter->init_done_rc == PARTIALSUCCESS) {
 			retry_count++;
 			release_sub_crqs(adapter, 1);
 
@@ -846,12 +873,22 @@
 
 static void release_login_buffer(struct ibmvnic_adapter *adapter)
 {
+	if (!adapter->login_buf)
+		return;
+
+	dma_unmap_single(&adapter->vdev->dev, adapter->login_buf_token,
+			 adapter->login_buf_sz, DMA_TO_DEVICE);
 	kfree(adapter->login_buf);
 	adapter->login_buf = NULL;
 }
 
 static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
 {
+	if (!adapter->login_rsp_buf)
+		return;
+
+	dma_unmap_single(&adapter->vdev->dev, adapter->login_rsp_buf_token,
+			 adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
 	kfree(adapter->login_rsp_buf);
 	adapter->login_rsp_buf = NULL;
 }
@@ -943,7 +980,7 @@
 	if (adapter->vpd->buff)
 		len = adapter->vpd->len;
 
-	init_completion(&adapter->fw_done);
+	reinit_completion(&adapter->fw_done);
 	crq.get_vpd_size.first = IBMVNIC_CRQ_CMD;
 	crq.get_vpd_size.cmd = GET_VPD_SIZE;
 	rc = ibmvnic_send_crq(adapter, &crq);
@@ -1057,8 +1094,7 @@
 
 	rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
 	if (rc) {
-		for (i = 0; i < adapter->req_rx_queues; i++)
-			napi_disable(&adapter->napi[i]);
+		ibmvnic_napi_disable(adapter);
 		release_resources(adapter);
 		return rc;
 	}
@@ -1090,18 +1126,27 @@
 	if (adapter->state != VNIC_CLOSED) {
 		rc = ibmvnic_login(netdev);
 		if (rc)
-			return rc;
+			goto out;
 
 		rc = init_resources(adapter);
 		if (rc) {
 			netdev_err(netdev, "failed to initialize resources\n");
 			release_resources(adapter);
-			return rc;
+			goto out;
 		}
 	}
 
 	rc = __ibmvnic_open(netdev);
 
+out:
+	/*
+	 * If open fails due to a pending failover, set device state and
+	 * return. Device operation will be handled by reset routine.
+	 */
+	if (rc && adapter->failover_pending) {
+		adapter->state = VNIC_OPEN;
+		rc = 0;
+	}
 	return rc;
 }
 
@@ -1226,10 +1271,8 @@
 
 	adapter->state = VNIC_CLOSING;
 	rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
-	if (rc)
-		return rc;
 	adapter->state = VNIC_CLOSED;
-	return 0;
+	return rc;
 }
 
 static int ibmvnic_close(struct net_device *netdev)
@@ -1429,8 +1472,6 @@
 	netdev_tx_t ret = NETDEV_TX_OK;
 
 	if (test_bit(0, &adapter->resetting)) {
-		if (!netif_subqueue_stopped(netdev, skb))
-			netif_stop_subqueue(netdev, queue_num);
 		dev_kfree_skb_any(skb);
 
 		tx_send_failed++;
@@ -1492,6 +1533,9 @@
 		skb_copy_from_linear_data(skb, dst, skb->len);
 	}
 
+	/* post changes to long_term_buff *dst before VIOS accessing it */
+	dma_wmb();
+
 	tx_pool->consumer_index =
 	    (tx_pool->consumer_index + 1) % tx_pool->num_buffers;
 
@@ -1689,7 +1733,7 @@
 	crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
 	ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr);
 
-	init_completion(&adapter->fw_done);
+	reinit_completion(&adapter->fw_done);
 	rc = ibmvnic_send_crq(adapter, &crq);
 	if (rc) {
 		rc = -EIO;
@@ -1716,6 +1760,9 @@
 	int rc;
 
 	rc = 0;
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
 	ether_addr_copy(adapter->mac_addr, addr->sa_data);
 	if (adapter->state != VNIC_PROBED)
 		rc = __ibmvnic_set_mac(netdev, addr->sa_data);
@@ -1813,12 +1860,19 @@
 	u64 old_num_rx_queues, old_num_tx_queues;
 	u64 old_num_rx_slots, old_num_tx_slots;
 	struct net_device *netdev = adapter->netdev;
-	int i, rc;
+	int rc;
 
 	netdev_dbg(adapter->netdev, "Re-setting driver (%d)\n",
 		   rwi->reset_reason);
 
 	rtnl_lock();
+	/*
+	 * Now that we have the rtnl lock, clear any pending failover.
+	 * This will ensure ibmvnic_open() has either completed or will
+	 * block until failover is complete.
+	 */
+	if (rwi->reset_reason == VNIC_RESET_FAILOVER)
+		adapter->failover_pending = false;
 
 	netif_carrier_off(netdev);
 	adapter->reset_reason = rwi->reset_reason;
@@ -1865,13 +1919,18 @@
 			release_sub_crqs(adapter, 1);
 		} else {
 			rc = ibmvnic_reset_crq(adapter);
-			if (!rc)
+			if (rc == H_CLOSED || rc == H_SUCCESS) {
 				rc = vio_enable_interrupts(adapter->vdev);
+				if (rc)
+					netdev_err(adapter->netdev,
+						   "Reset failed to enable interrupts. rc=%d\n",
+						   rc);
+			}
 		}
 
 		if (rc) {
 			netdev_err(adapter->netdev,
-				   "Couldn't initialize crq. rc=%d\n", rc);
+				   "Reset couldn't initialize crq. rc=%d\n", rc);
 			goto out;
 		}
 
@@ -1900,7 +1959,10 @@
 		    adapter->req_rx_add_entries_per_subcrq !=
 		    old_num_rx_slots ||
 		    adapter->req_tx_entries_per_subcrq !=
-		    old_num_tx_slots) {
+		    old_num_tx_slots ||
+		    !adapter->rx_pool ||
+		    !adapter->tso_pool ||
+		    !adapter->tx_pool) {
 			release_rx_pools(adapter);
 			release_tx_pools(adapter);
 			release_napi(adapter);
@@ -1912,12 +1974,18 @@
 
 		} else {
 			rc = reset_tx_pools(adapter);
-			if (rc)
+			if (rc) {
+				netdev_dbg(adapter->netdev, "reset tx pools failed (%d)\n",
+						rc);
 				goto out;
+			}
 
 			rc = reset_rx_pools(adapter);
-			if (rc)
+			if (rc) {
+				netdev_dbg(adapter->netdev, "reset rx pools failed (%d)\n",
+						rc);
 				goto out;
+			}
 		}
 		ibmvnic_disable_irqs(adapter);
 	}
@@ -1937,12 +2005,11 @@
 	/* refresh device's multicast list */
 	ibmvnic_set_multi(netdev);
 
-	/* kick napi */
-	for (i = 0; i < adapter->req_rx_queues; i++)
-		napi_schedule(&adapter->napi[i]);
-
-	if (adapter->reset_reason != VNIC_RESET_FAILOVER)
+	if (adapter->reset_reason == VNIC_RESET_FAILOVER ||
+	    adapter->reset_reason == VNIC_RESET_MOBILITY) {
 		call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev);
+		call_netdevice_notifiers(NETDEV_RESEND_IGMP, netdev);
+	}
 
 	rc = 0;
 
@@ -2012,6 +2079,9 @@
 	if (rc)
 		return IBMVNIC_OPEN_FAILED;
 
+	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev);
+	call_netdevice_notifiers(NETDEV_RESEND_IGMP, netdev);
+
 	return 0;
 }
 
@@ -2075,6 +2145,13 @@
 			/* CHANGE_PARAM requestor holds rtnl_lock */
 			rc = do_change_param_reset(adapter, rwi, reset_state);
 		} else if (adapter->force_reset_recovery) {
+			/*
+			 * Since we are doing a hard reset now, clear the
+			 * failover_pending flag so we don't ignore any
+			 * future MOBILITY or other resets.
+			 */
+			adapter->failover_pending = false;
+
 			/* Transport event occurred during previous reset */
 			if (adapter->wait_for_reset) {
 				/* Previous was CHANGE_PARAM; caller locked */
@@ -2138,9 +2215,15 @@
 	unsigned long flags;
 	int ret;
 
+	/*
+	 * If failover is pending don't schedule any other reset.
+	 * Instead let the failover complete. If there is already a
+	 * a failover reset scheduled, we will detect and drop the
+	 * duplicate reset when walking the ->rwi_list below.
+	 */
 	if (adapter->state == VNIC_REMOVING ||
 	    adapter->state == VNIC_REMOVED ||
-	    adapter->failover_pending) {
+	    (adapter->failover_pending && reason != VNIC_RESET_FAILOVER)) {
 		ret = EBUSY;
 		netdev_dbg(netdev, "Adapter removing or pending failover, skipping reset\n");
 		goto err;
@@ -2175,8 +2258,10 @@
 	 * flush reset queue and process this reset
 	 */
 	if (adapter->force_reset_recovery && !list_empty(&adapter->rwi_list)) {
-		list_for_each_safe(entry, tmp_entry, &adapter->rwi_list)
+		list_for_each_safe(entry, tmp_entry, &adapter->rwi_list) {
 			list_del(entry);
+			kfree(list_entry(entry, struct ibmvnic_rwi, list));
+		}
 	}
 	rwi->reset_reason = reason;
 	list_add_tail(&rwi->list, &adapter->rwi_list);
@@ -2193,6 +2278,12 @@
 {
 	struct ibmvnic_adapter *adapter = netdev_priv(dev);
 
+	if (test_bit(0, &adapter->resetting)) {
+		netdev_err(adapter->netdev,
+			   "Adapter is resetting, skip timeout reset\n");
+		return;
+	}
+
 	ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT);
 }
 
@@ -2234,6 +2325,12 @@
 
 		if (!pending_scrq(adapter, adapter->rx_scrq[scrq_num]))
 			break;
+		/* The queue entry at the current index is peeked at above
+		 * to determine that there is a valid descriptor awaiting
+		 * processing. We want to be sure that the current slot
+		 * holds a valid descriptor before reading its contents.
+		 */
+		dma_rmb();
 		next = ibmvnic_next_scrq(adapter, adapter->rx_scrq[scrq_num]);
 		rx_buff =
 		    (struct ibmvnic_rx_buff *)be64_to_cpu(next->
@@ -2258,6 +2355,8 @@
 		offset = be16_to_cpu(next->rx_comp.off_frame_data);
 		flags = next->rx_comp.flags;
 		skb = rx_buff->skb;
+		/* load long_term_buff before copying to skb */
+		dma_rmb();
 		skb_copy_to_linear_data(skb, rx_buff->data + offset,
 					length);
 
@@ -2316,7 +2415,7 @@
 	adapter->fallback.rx_entries = adapter->req_rx_add_entries_per_subcrq;
 	adapter->fallback.tx_entries = adapter->req_tx_entries_per_subcrq;
 
-	init_completion(&adapter->reset_done);
+	reinit_completion(&adapter->reset_done);
 	adapter->wait_for_reset = true;
 	rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
 	if (rc)
@@ -2332,7 +2431,7 @@
 		adapter->desired.rx_entries = adapter->fallback.rx_entries;
 		adapter->desired.tx_entries = adapter->fallback.tx_entries;
 
-		init_completion(&adapter->reset_done);
+		reinit_completion(&adapter->reset_done);
 		adapter->wait_for_reset = true;
 		rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
 		if (rc)
@@ -2603,7 +2702,7 @@
 	    cpu_to_be32(sizeof(struct ibmvnic_statistics));
 
 	/* Wait for data to be written */
-	init_completion(&adapter->stats_done);
+	reinit_completion(&adapter->stats_done);
 	rc = ibmvnic_send_crq(adapter, &crq);
 	if (rc)
 		return;
@@ -2694,6 +2793,9 @@
 {
 	int i, rc;
 
+	if (!adapter->tx_scrq || !adapter->rx_scrq)
+		return -EINVAL;
+
 	for (i = 0; i < adapter->req_tx_queues; i++) {
 		netdev_dbg(adapter->netdev, "Re-setting tx_scrq[%d]\n", i);
 		rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]);
@@ -2912,13 +3014,18 @@
 		unsigned int pool = scrq->pool_index;
 		int num_entries = 0;
 
+		/* The queue entry at the current index is peeked at above
+		 * to determine that there is a valid descriptor awaiting
+		 * processing. We want to be sure that the current slot
+		 * holds a valid descriptor before reading its contents.
+		 */
+		dma_rmb();
+
 		next = ibmvnic_next_scrq(adapter, scrq);
 		for (i = 0; i < next->tx_comp.num_comps; i++) {
-			if (next->tx_comp.rcs[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]);
 			if (index & IBMVNIC_TSO_POOL_MASK) {
 				tx_pool = &adapter->tso_pool[pool];
@@ -3067,7 +3174,7 @@
 req_tx_irq_failed:
 	for (j = 0; j < i; j++) {
 		free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
-		irq_dispose_mapping(adapter->rx_scrq[j]->irq);
+		irq_dispose_mapping(adapter->tx_scrq[j]->irq);
 	}
 	release_sub_crqs(adapter, 1);
 	return rc;
@@ -3163,11 +3270,25 @@
 	struct device *dev = &adapter->vdev->dev;
 	union ibmvnic_crq crq;
 	int max_entries;
+	int cap_reqs;
+
+	/* We send out 6 or 7 REQUEST_CAPABILITY CRQs below (depending on
+	 * the PROMISC flag). Initialize this count upfront. When the tasklet
+	 * receives a response to all of these, it will send the next protocol
+	 * message (QUERY_IP_OFFLOAD).
+	 */
+	if (!(adapter->netdev->flags & IFF_PROMISC) ||
+	    adapter->promisc_supported)
+		cap_reqs = 7;
+	else
+		cap_reqs = 6;
 
 	if (!retry) {
 		/* Sub-CRQ entries are 32 byte long */
 		int entries_page = 4 * PAGE_SIZE / (sizeof(u64) * 4);
 
+		atomic_set(&adapter->running_cap_crqs, cap_reqs);
+
 		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");
@@ -3228,44 +3349,45 @@
 					adapter->opt_rx_comp_queues;
 
 		adapter->req_rx_add_queues = adapter->max_rx_add_queues;
+	} else {
+		atomic_add(cap_reqs, &adapter->running_cap_crqs);
 	}
-
 	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_be64(adapter->req_tx_queues);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
 	crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
 	crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	crq.request_capability.capability =
 	    cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
 	crq.request_capability.number =
 	    cpu_to_be64(adapter->req_tx_entries_per_subcrq);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	crq.request_capability.capability =
 	    cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
 	crq.request_capability.number =
 	    cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	crq.request_capability.capability = cpu_to_be16(REQ_MTU);
 	crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
-	atomic_inc(&adapter->running_cap_crqs);
+	cap_reqs--;
 	ibmvnic_send_crq(adapter, &crq);
 
 	if (adapter->netdev->flags & IFF_PROMISC) {
@@ -3273,16 +3395,21 @@
 			crq.request_capability.capability =
 			    cpu_to_be16(PROMISC_REQUESTED);
 			crq.request_capability.number = cpu_to_be64(1);
-			atomic_inc(&adapter->running_cap_crqs);
+			cap_reqs--;
 			ibmvnic_send_crq(adapter, &crq);
 		}
 	} else {
 		crq.request_capability.capability =
 		    cpu_to_be16(PROMISC_REQUESTED);
 		crq.request_capability.number = cpu_to_be64(0);
-		atomic_inc(&adapter->running_cap_crqs);
+		cap_reqs--;
 		ibmvnic_send_crq(adapter, &crq);
 	}
+
+	/* Keep at end to catch any discrepancy between expected and actual
+	 * CRQs sent.
+	 */
+	WARN_ON(cap_reqs != 0);
 }
 
 static int pending_scrq(struct ibmvnic_adapter *adapter,
@@ -3312,6 +3439,11 @@
 	}
 	spin_unlock_irqrestore(&scrq->lock, flags);
 
+	/* Ensure that the entire buffer descriptor has been
+	 * loaded before reading its contents
+	 */
+	dma_rmb();
+
 	return entry;
 }
 
@@ -3682,118 +3814,132 @@
 static void send_cap_queries(struct ibmvnic_adapter *adapter)
 {
 	union ibmvnic_crq crq;
+	int cap_reqs;
+
+	/* We send out 25 QUERY_CAPABILITY CRQs below.  Initialize this count
+	 * upfront. When the tasklet receives a response to all of these, it
+	 * can send out the next protocol messaage (REQUEST_CAPABILITY).
+	 */
+	cap_reqs = 25;
+
+	atomic_set(&adapter->running_cap_crqs, cap_reqs);
 
-	atomic_set(&adapter->running_cap_crqs, 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_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 	    cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 	    cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 	    cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 	    cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MIN_MTU);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_MTU);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(RX_VLAN_HEADER_INSERTION);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 			cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 			cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability =
 			cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
-	atomic_inc(&adapter->running_cap_crqs);
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
 
 	crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
-	atomic_inc(&adapter->running_cap_crqs);
+
 	ibmvnic_send_crq(adapter, &crq);
+	cap_reqs--;
+
+	/* Keep at end to catch any discrepancy between expected and actual
+	 * CRQs sent.
+	 */
+	WARN_ON(cap_reqs != 0);
 }
 
 static void handle_vpd_size_rsp(union ibmvnic_crq *crq,
@@ -4040,8 +4186,13 @@
 		dev_err(dev, "Error %ld in CHANGE_MAC_ADDR_RSP\n", rc);
 		goto out;
 	}
+	/* crq->change_mac_addr.mac_addr is the requested one
+	 * crq->change_mac_addr_rsp.mac_addr is the returned valid one.
+	 */
 	ether_addr_copy(netdev->dev_addr,
 			&crq->change_mac_addr_rsp.mac_addr[0]);
+	ether_addr_copy(adapter->mac_addr,
+			&crq->change_mac_addr_rsp.mac_addr[0]);
 out:
 	complete(&adapter->fw_done);
 	return rc;
@@ -4055,6 +4206,8 @@
 	char *name;
 
 	atomic_dec(&adapter->running_cap_crqs);
+	netdev_dbg(adapter->netdev, "Outstanding request-caps: %d\n",
+		   atomic_read(&adapter->running_cap_crqs));
 	switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
 	case REQ_TX_QUEUES:
 		req_value = &adapter->req_tx_queues;
@@ -4155,11 +4308,6 @@
 	struct ibmvnic_login_buffer *login = adapter->login_buf;
 	int i;
 
-	dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
-			 DMA_TO_DEVICE);
-	dma_unmap_single(dev, adapter->login_rsp_buf_token,
-			 adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
-
 	/* If the number of queues requested can't be allocated by the
 	 * server, the login response will return with code 1. We will need
 	 * to resend the login buffer with fewer queues requested.
@@ -4170,6 +4318,14 @@
 		return 0;
 	}
 
+	if (adapter->failover_pending) {
+		adapter->init_done_rc = -EAGAIN;
+		netdev_dbg(netdev, "Failover pending, ignoring login response\n");
+		complete(&adapter->init_done);
+		/* login response buffer will be released on reset */
+		return 0;
+	}
+
 	netdev->mtu = adapter->req_mtu - ETH_HLEN;
 
 	netdev_dbg(adapter->netdev, "Login Response Buffer:\n");
@@ -4408,7 +4564,7 @@
 	memset(&crq, 0, sizeof(crq));
 	crq.query_phys_parms.first = IBMVNIC_CRQ_CMD;
 	crq.query_phys_parms.cmd = QUERY_PHYS_PARMS;
-	init_completion(&adapter->fw_done);
+	reinit_completion(&adapter->fw_done);
 	rc = ibmvnic_send_crq(adapter, &crq);
 	if (rc)
 		return rc;
@@ -4438,7 +4594,7 @@
 	case IBMVNIC_1GBPS:
 		adapter->speed = SPEED_1000;
 		break;
-	case IBMVNIC_10GBP:
+	case IBMVNIC_10GBPS:
 		adapter->speed = SPEED_10000;
 		break;
 	case IBMVNIC_25GBPS:
@@ -4453,6 +4609,9 @@
 	case IBMVNIC_100GBPS:
 		adapter->speed = SPEED_100000;
 		break;
+	case IBMVNIC_200GBPS:
+		adapter->speed = SPEED_200000;
+		break;
 	default:
 		if (netif_carrier_ok(netdev))
 			netdev_warn(netdev, "Unknown speed 0x%08x\n", rspeed);
@@ -4486,12 +4645,26 @@
 		case IBMVNIC_CRQ_INIT:
 			dev_info(dev, "Partner initialized\n");
 			adapter->from_passive_init = true;
-			adapter->failover_pending = false;
 			if (!completion_done(&adapter->init_done)) {
 				complete(&adapter->init_done);
 				adapter->init_done_rc = -EIO;
 			}
-			ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
+			rc = ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
+			if (rc && rc != -EBUSY) {
+				/* We were unable to schedule the failover
+				 * reset either because the adapter was still
+				 * probing (eg: during kexec) or we could not
+				 * allocate memory. Clear the failover_pending
+				 * flag since no one else will. We ignore
+				 * EBUSY because it means either FAILOVER reset
+				 * is already scheduled or the adapter is
+				 * being removed.
+				 */
+				netdev_err(netdev,
+					   "Error %ld scheduling failover reset\n",
+					   rc);
+				adapter->failover_pending = false;
+			}
 			break;
 		case IBMVNIC_CRQ_INIT_COMPLETE:
 			dev_info(dev, "Partner initialization complete\n");
@@ -4535,12 +4708,10 @@
 			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 =
+		ibmvnic_version =
 			    be16_to_cpu(crq->version_exchange_rsp.version);
+		dev_info(dev, "Partner protocol version is %d\n",
+			 ibmvnic_version);
 		send_cap_queries(adapter);
 		break;
 	case QUERY_CAPABILITY_RSP:
@@ -4650,15 +4821,15 @@
 	while (!done) {
 		/* Pull all the valid messages off the CRQ */
 		while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
+			/* This barrier makes sure ibmvnic_next_crq()'s
+			 * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
+			 * before ibmvnic_handle_crq()'s
+			 * switch(gen_crq->first) and switch(gen_crq->cmd).
+			 */
+			dma_rmb();
 			ibmvnic_handle_crq(crq, adapter);
 			crq->generic.first = 0;
 		}
-
-		/* remain in tasklet until all
-		 * capabilities responses are received
-		 */
-		if (!adapter->wait_capability)
-			done = true;
 	}
 	/* if capabilities CRQ's were sent in this tasklet, the following
 	 * tasklet must wait until all responses are received
@@ -4696,6 +4867,9 @@
 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
 	/* Clean out the queue */
+	if (!crq->msgs)
+		return -EINVAL;
+
 	memset(crq->msgs, 0, PAGE_SIZE);
 	crq->cur = 0;
 	crq->active = false;
@@ -4797,6 +4971,9 @@
 	crq->cur = 0;
 	spin_lock_init(&crq->lock);
 
+	/* process any CRQs that were queued before we enabled interrupts */
+	tasklet_schedule(&adapter->tasklet);
+
 	return retrc;
 
 req_irq_failed:
@@ -4850,6 +5027,15 @@
 			release_sub_crqs(adapter, 0);
 			rc = init_sub_crqs(adapter);
 		} else {
+			/* no need to reinitialize completely, but we do
+			 * need to clean up transmits that were in flight
+			 * when we processed the reset.  Failure to do so
+			 * will confound the upper layer, usually TCP, by
+			 * creating the illusion of transmits that are
+			 * awaiting completion.
+			 */
+			clean_tx_pools(adapter);
+
 			rc = reset_sub_crq_queues(adapter);
 		}
 	} else {
@@ -4960,6 +5146,9 @@
 	INIT_LIST_HEAD(&adapter->rwi_list);
 	spin_lock_init(&adapter->rwi_lock);
 	init_completion(&adapter->init_done);
+	init_completion(&adapter->fw_done);
+	init_completion(&adapter->reset_done);
+	init_completion(&adapter->stats_done);
 	clear_bit(0, &adapter->resetting);
 
 	do {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ibm/ibmvnic.h
+++ linux-ein-5.4.0/drivers/net/ethernet/ibm/ibmvnic.h
@@ -373,7 +373,7 @@
 #define IBMVNIC_10MBPS		0x40000000
 #define IBMVNIC_100MBPS		0x20000000
 #define IBMVNIC_1GBPS		0x10000000
-#define IBMVNIC_10GBP		0x08000000
+#define IBMVNIC_10GBPS		0x08000000
 #define IBMVNIC_40GBPS		0x04000000
 #define IBMVNIC_100GBPS		0x02000000
 #define IBMVNIC_25GBPS		0x01000000
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e100.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e100.c
@@ -1398,7 +1398,7 @@
 	u8 phy_type;
 	int without_mii;
 
-	phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f;
+	phy_type = (le16_to_cpu(nic->eeprom[eeprom_phy_iface]) >> 8) & 0x0f;
 
 	switch (phy_type) {
 	case NoSuchPhy: /* Non-MII PHY; UNTESTED! */
@@ -1518,7 +1518,7 @@
 		mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
 	} else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
 	   (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
-		(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+	   (le16_to_cpu(nic->eeprom[eeprom_cnfg_mdix]) & eeprom_mdix_enabled))) {
 		/* enable/disable MDI/MDI-X auto-switching. */
 		mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
 				nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
@@ -2266,9 +2266,9 @@
 {
 	/* ASF can be enabled from eeprom */
 	return (nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
-	   (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
-	   !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
-	   ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE);
+	   (le16_to_cpu(nic->eeprom[eeprom_config_asf]) & eeprom_asf) &&
+	   !(le16_to_cpu(nic->eeprom[eeprom_config_asf]) & eeprom_gcl) &&
+	   ((le16_to_cpu(nic->eeprom[eeprom_smbus_addr]) & 0xFF) != 0xFE);
 }
 
 static int e100_up(struct nic *nic)
@@ -2435,11 +2435,15 @@
 		sizeof(info->bus_info));
 }
 
-#define E100_PHY_REGS 0x1C
+#define E100_PHY_REGS 0x1D
 static int e100_get_regs_len(struct net_device *netdev)
 {
 	struct nic *nic = netdev_priv(netdev);
-	return 1 + E100_PHY_REGS + sizeof(nic->mem->dump_buf);
+
+	/* We know the number of registers, and the size of the dump buffer.
+	 * Calculate the total size in bytes.
+	 */
+	return (1 + E100_PHY_REGS) * sizeof(u32) + sizeof(nic->mem->dump_buf);
 }
 
 static void e100_get_regs(struct net_device *netdev,
@@ -2453,14 +2457,18 @@
 	buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
 		ioread8(&nic->csr->scb.cmd_lo) << 16 |
 		ioread16(&nic->csr->scb.status);
-	for (i = E100_PHY_REGS; i >= 0; i--)
-		buff[1 + E100_PHY_REGS - i] =
-			mdio_read(netdev, nic->mii.phy_id, i);
+	for (i = 0; i < E100_PHY_REGS; i++)
+		/* Note that we read the registers in reverse order. This
+		 * ordering is the ABI apparently used by ethtool and other
+		 * applications.
+		 */
+		buff[1 + i] = mdio_read(netdev, nic->mii.phy_id,
+					E100_PHY_REGS - 1 - i);
 	memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
 	e100_exec_cb(nic, NULL, e100_dump);
 	msleep(10);
-	memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
-		sizeof(nic->mem->dump_buf));
+	memcpy(&buff[1 + E100_PHY_REGS], nic->mem->dump_buf,
+	       sizeof(nic->mem->dump_buf));
 }
 
 static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
@@ -2924,7 +2932,7 @@
 
 	/* Wol magic packet can be enabled from eeprom */
 	if ((nic->mac >= mac_82558_D101_A4) &&
-	   (nic->eeprom[eeprom_id] & eeprom_id_wol)) {
+	   (le16_to_cpu(nic->eeprom[eeprom_id]) & eeprom_id_wol)) {
 		nic->flags |= wol_magic;
 		device_set_wakeup_enable(&pdev->dev, true);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -542,8 +542,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);
 }
 
@@ -1433,10 +1438,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);
@@ -3140,8 +3150,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
@@ -3162,6 +3173,7 @@
 				}
 				len = skb_headlen(skb);
 				break;
+			}
 			default:
 				/* do nothing */
 				break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/82571.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/82571.c
@@ -899,6 +899,8 @@
 	} else {
 		data &= ~IGP02E1000_PM_D0_LPLU;
 		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+		if (ret_val)
+			return ret_val;
 		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
 		 * during Dx states where the power conservation is most
 		 * important.  During driver activity we should enable
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/e1000.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -185,13 +185,12 @@
 
 /* board specific private data structure */
 struct e1000_adapter {
+	struct timer_list watchdog_timer;
 	struct timer_list phy_info_timer;
 	struct timer_list blink_timer;
 
 	struct work_struct reset_task;
-	struct delayed_work watchdog_task;
-
-	struct workqueue_struct *e1000_workqueue;
+	struct work_struct watchdog_task;
 
 	const struct e1000_info *ei;
 
@@ -577,7 +576,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-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/hw.h
@@ -86,6 +86,12 @@
 #define E1000_DEV_ID_PCH_ICP_I219_V8		0x15E0
 #define E1000_DEV_ID_PCH_ICP_I219_LM9		0x15E1
 #define E1000_DEV_ID_PCH_ICP_I219_V9		0x15E2
+#define E1000_DEV_ID_PCH_CMP_I219_LM10		0x0D4E
+#define E1000_DEV_ID_PCH_CMP_I219_V10		0x0D4F
+#define E1000_DEV_ID_PCH_CMP_I219_LM11		0x0D4C
+#define E1000_DEV_ID_PCH_CMP_I219_V11		0x0D4D
+#define E1000_DEV_ID_PCH_CMP_I219_LM12		0x0D53
+#define E1000_DEV_ID_PCH_CMP_I219_V12		0x0D55
 
 #define E1000_REVISION_4	4
 
@@ -662,6 +668,7 @@
 	bool kmrn_lock_loss_workaround_enabled;
 	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
 	bool nvm_k1_enabled;
+	bool disable_k1_off;
 	bool eee_disable;
 	u16 eee_lp_ability;
 	enum e1000_ulp_state ulp_state;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -995,6 +995,8 @@
 {
 	u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
 	    link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
+	u32 max_ltr_enc_d = 0;	/* maximum LTR decoded by platform */
+	u32 lat_enc_d = 0;	/* latency decoded */
 	u16 lat_enc = 0;	/* latency encoded */
 
 	if (link) {
@@ -1048,7 +1050,17 @@
 				     E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
 		max_ltr_enc = max_t(u16, max_snoop, max_nosnoop);
 
-		if (lat_enc > max_ltr_enc)
+		lat_enc_d = (lat_enc & E1000_LTRV_VALUE_MASK) *
+			     (1U << (E1000_LTRV_SCALE_FACTOR *
+			     ((lat_enc & E1000_LTRV_SCALE_MASK)
+			     >> E1000_LTRV_SCALE_SHIFT)));
+
+		max_ltr_enc_d = (max_ltr_enc & E1000_LTRV_VALUE_MASK) *
+				 (1U << (E1000_LTRV_SCALE_FACTOR *
+				 ((max_ltr_enc & E1000_LTRV_SCALE_MASK)
+				 >> E1000_LTRV_SCALE_SHIFT)));
+
+		if (lat_enc_d > max_ltr_enc_d)
 			lat_enc = max_ltr_enc;
 	}
 
@@ -1237,9 +1249,9 @@
 			ew32(H2ME, mac_reg);
 		}
 
-		/* Poll up to 300msec for ME to clear ULP_CFG_DONE. */
+		/* Poll up to 2.5sec for ME to clear ULP_CFG_DONE. */
 		while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
-			if (i++ == 30) {
+			if (i++ == 250) {
 				ret_val = -E1000_ERR_PHY;
 				goto out;
 			}
@@ -1538,6 +1550,9 @@
 				fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
 		}
 
+		if (hw->dev_spec.ich8lan.disable_k1_off == true)
+			fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
+
 		ew32(FEXTNVM6, fextnvm6);
 	}
 
@@ -4084,13 +4099,17 @@
 		return ret_val;
 
 	if (!(data & valid_csum_mask)) {
-		data |= valid_csum_mask;
-		ret_val = e1000_write_nvm(hw, word, 1, &data);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1000e_update_nvm_checksum(hw);
-		if (ret_val)
-			return ret_val;
+		e_dbg("NVM Checksum Invalid\n");
+
+		if (hw->mac.type < e1000_pch_cnp) {
+			data |= valid_csum_mask;
+			ret_val = e1000_write_nvm(hw, word, 1, &data);
+			if (ret_val)
+				return ret_val;
+			ret_val = e1000e_update_nvm_checksum(hw);
+			if (ret_val)
+				return ret_val;
+		}
 	}
 
 	return e1000e_validate_nvm_checksum_generic(hw);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/ich8lan.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -274,8 +274,11 @@
 
 /* Latency Tolerance Reporting */
 #define E1000_LTRV			0x000F8
+#define E1000_LTRV_VALUE_MASK		0x000003FF
 #define E1000_LTRV_SCALE_MAX		5
 #define E1000_LTRV_SCALE_FACTOR		5
+#define E1000_LTRV_SCALE_SHIFT		10
+#define E1000_LTRV_SCALE_MASK		0x00001C00
 #define E1000_LTRV_REQ_SHIFT		15
 #define E1000_LTRV_NOSNOOP_SHIFT	16
 #define E1000_LTRV_SEND			(1 << 30)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/netdev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -119,14 +119,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)
@@ -607,11 +605,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);
@@ -624,11 +622,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);
@@ -1780,8 +1778,7 @@
 		}
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
-			mod_delayed_work(adapter->e1000_workqueue,
-					 &adapter->watchdog_task, HZ);
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
 	/* Reset on uncorrectable ECC error */
@@ -1861,8 +1858,7 @@
 		}
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
-			mod_delayed_work(adapter->e1000_workqueue,
-					 &adapter->watchdog_task, HZ);
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
 	/* Reset on uncorrectable ECC error */
@@ -1907,8 +1903,7 @@
 		hw->mac.get_link_status = true;
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
-			mod_delayed_work(adapter->e1000_workqueue,
-					 &adapter->watchdog_task, HZ);
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
 	if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -4281,6 +4276,7 @@
 
 	napi_synchronize(&adapter->napi);
 
+	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 
 	spin_lock(&adapter->stats64_lock);
@@ -4715,12 +4711,12 @@
 
 	pm_runtime_get_sync(&pdev->dev);
 
-	if (!test_bit(__E1000_DOWN, &adapter->state)) {
+	if (netif_device_present(netdev)) {
 		e1000e_down(adapter, true);
 		e1000_free_irq(adapter);
 
 		/* Link status message must follow this format */
-		pr_info("%s NIC Link is Down\n", adapter->netdev->name);
+		pr_info("%s NIC Link is Down\n", netdev->name);
 	}
 
 	napi_disable(&adapter->napi);
@@ -5152,11 +5148,25 @@
 	}
 }
 
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void e1000_watchdog(struct timer_list *t)
+{
+	struct e1000_adapter *adapter = from_timer(adapter, t, watchdog_timer);
+
+	/* Do the rest outside of interrupt context */
+	schedule_work(&adapter->watchdog_task);
+
+	/* TODO: make this use queue_delayed_work() */
+}
+
 static void e1000_watchdog_task(struct work_struct *work)
 {
 	struct e1000_adapter *adapter = container_of(work,
 						     struct e1000_adapter,
-						     watchdog_task.work);
+						     watchdog_task);
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_mac_info *mac = &adapter->hw.mac;
 	struct e1000_phy_info *phy = &adapter->hw.phy;
@@ -5189,18 +5199,20 @@
 			pm_runtime_resume(netdev->dev.parent);
 
 			/* Checking if MAC is in DMoff state*/
-			pcim_state = er32(STATUS);
-			while (pcim_state & E1000_STATUS_PCIM_STATE) {
-				if (tries++ == dmoff_exit_timeout) {
-					e_dbg("Error in exiting dmoff\n");
-					break;
-				}
-				usleep_range(10000, 20000);
+			if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
 				pcim_state = er32(STATUS);
-
-				/* Checking if MAC exited DMoff state */
-				if (!(pcim_state & E1000_STATUS_PCIM_STATE))
-					e1000_phy_hw_reset(&adapter->hw);
+				while (pcim_state & E1000_STATUS_PCIM_STATE) {
+					if (tries++ == dmoff_exit_timeout) {
+						e_dbg("Error in exiting dmoff\n");
+						break;
+					}
+					usleep_range(10000, 20000);
+					pcim_state = er32(STATUS);
+
+					/* Checking if MAC exited DMoff state */
+					if (!(pcim_state & E1000_STATUS_PCIM_STATE))
+						e1000_phy_hw_reset(&adapter->hw);
+				}
 			}
 
 			/* update snapshot of PHY registers on LSC */
@@ -5258,27 +5270,6 @@
 				ew32(TARC(0), tarc0);
 			}
 
-			/* disable TSO for pcie and 10/100 speeds, to avoid
-			 * some hardware issues
-			 */
-			if (!(adapter->flags & FLAG_TSO_FORCE)) {
-				switch (adapter->link_speed) {
-				case SPEED_10:
-				case SPEED_100:
-					e_info("10/100 speed: disabling TSO\n");
-					netdev->features &= ~NETIF_F_TSO;
-					netdev->features &= ~NETIF_F_TSO6;
-					break;
-				case SPEED_1000:
-					netdev->features |= NETIF_F_TSO;
-					netdev->features |= NETIF_F_TSO6;
-					break;
-				default:
-					/* oops */
-					break;
-				}
-			}
-
 			/* enable transmits in the hardware, need to do this
 			 * after setting TARC(0)
 			 */
@@ -5404,9 +5395,8 @@
 
 	/* Reset the timer */
 	if (!test_bit(__E1000_DOWN, &adapter->state))
-		queue_delayed_work(adapter->e1000_workqueue,
-				   &adapter->watchdog_task,
-				   round_jiffies(2 * HZ));
+		mod_timer(&adapter->watchdog_timer,
+			  round_jiffies(jiffies + 2 * HZ));
 }
 
 #define E1000_TX_FLAGS_CSUM		0x00000001
@@ -5901,9 +5891,9 @@
 		e1000_tx_queue(tx_ring, tx_flags, count);
 		/* Make sure there is space in the ring for the next send. */
 		e1000_maybe_stop_tx(tx_ring,
-				    (MAX_SKB_FRAGS *
+				    ((MAX_SKB_FRAGS + 1) *
 				     DIV_ROUND_UP(PAGE_SIZE,
-						  adapter->tx_fifo_limit) + 2));
+						  adapter->tx_fifo_limit) + 4));
 
 		if (!netdev_xmit_more() ||
 		    netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) {
@@ -5940,15 +5930,19 @@
 	struct e1000_adapter *adapter;
 	adapter = container_of(work, struct e1000_adapter, reset_task);
 
+	rtnl_lock();
 	/* don't run the task if already down */
-	if (test_bit(__E1000_DOWN, &adapter->state))
+	if (test_bit(__E1000_DOWN, &adapter->state)) {
+		rtnl_unlock();
 		return;
+	}
 
 	if (!(adapter->flags & FLAG_RESTART_NOW)) {
 		e1000e_dump(adapter);
 		e_err("Reset adapter unexpectedly\n");
 	}
 	e1000e_reinit_locked(adapter);
+	rtnl_unlock();
 }
 
 /**
@@ -6294,14 +6288,186 @@
 	pm_runtime_put_sync(netdev->dev.parent);
 }
 
+/* S0ix implementation */
+static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 mac_data;
+	u16 phy_data;
+
+	/* Disable the periodic inband message,
+	 * don't request PCIe clock in K1 page770_17[10:9] = 10b
+	 */
+	e1e_rphy(hw, HV_PM_CTRL, &phy_data);
+	phy_data &= ~HV_PM_CTRL_K1_CLK_REQ;
+	phy_data |= BIT(10);
+	e1e_wphy(hw, HV_PM_CTRL, phy_data);
+
+	/* Make sure we don't exit K1 every time a new packet arrives
+	 * 772_29[5] = 1 CS_Mode_Stay_In_K1
+	 */
+	e1e_rphy(hw, I217_CGFREG, &phy_data);
+	phy_data |= BIT(5);
+	e1e_wphy(hw, I217_CGFREG, phy_data);
+
+	/* Change the MAC/PHY interface to SMBus
+	 * Force the SMBus in PHY page769_23[0] = 1
+	 * Force the SMBus in MAC CTRL_EXT[11] = 1
+	 */
+	e1e_rphy(hw, CV_SMB_CTRL, &phy_data);
+	phy_data |= CV_SMB_CTRL_FORCE_SMBUS;
+	e1e_wphy(hw, CV_SMB_CTRL, phy_data);
+	mac_data = er32(CTRL_EXT);
+	mac_data |= E1000_CTRL_EXT_FORCE_SMBUS;
+	ew32(CTRL_EXT, mac_data);
+
+	/* DFT control: PHY bit: page769_20[0] = 1
+	 * Gate PPW via EXTCNF_CTRL - set 0x0F00[7] = 1
+	 */
+	e1e_rphy(hw, I82579_DFT_CTRL, &phy_data);
+	phy_data |= BIT(0);
+	e1e_wphy(hw, I82579_DFT_CTRL, phy_data);
+
+	mac_data = er32(EXTCNF_CTRL);
+	mac_data |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+	ew32(EXTCNF_CTRL, mac_data);
+
+	/* Check MAC Tx/Rx packet buffer pointers.
+	 * Reset MAC Tx/Rx packet buffer pointers to suppress any
+	 * pending traffic indication that would prevent power gating.
+	 */
+	mac_data = er32(TDFH);
+	if (mac_data)
+		ew32(TDFH, 0);
+	mac_data = er32(TDFT);
+	if (mac_data)
+		ew32(TDFT, 0);
+	mac_data = er32(TDFHS);
+	if (mac_data)
+		ew32(TDFHS, 0);
+	mac_data = er32(TDFTS);
+	if (mac_data)
+		ew32(TDFTS, 0);
+	mac_data = er32(TDFPC);
+	if (mac_data)
+		ew32(TDFPC, 0);
+	mac_data = er32(RDFH);
+	if (mac_data)
+		ew32(RDFH, 0);
+	mac_data = er32(RDFT);
+	if (mac_data)
+		ew32(RDFT, 0);
+	mac_data = er32(RDFHS);
+	if (mac_data)
+		ew32(RDFHS, 0);
+	mac_data = er32(RDFTS);
+	if (mac_data)
+		ew32(RDFTS, 0);
+	mac_data = er32(RDFPC);
+	if (mac_data)
+		ew32(RDFPC, 0);
+
+	/* Enable the Dynamic Power Gating in the MAC */
+	mac_data = er32(FEXTNVM7);
+	mac_data |= BIT(22);
+	ew32(FEXTNVM7, mac_data);
+
+	/* Disable the time synchronization clock */
+	mac_data = er32(FEXTNVM7);
+	mac_data |= BIT(31);
+	mac_data &= ~BIT(0);
+	ew32(FEXTNVM7, mac_data);
+
+	/* Dynamic Power Gating Enable */
+	mac_data = er32(CTRL_EXT);
+	mac_data |= BIT(3);
+	ew32(CTRL_EXT, mac_data);
+
+	/* Enable the Dynamic Clock Gating in the DMA and MAC */
+	mac_data = er32(CTRL_EXT);
+	mac_data |= E1000_CTRL_EXT_DMA_DYN_CLK_EN;
+	ew32(CTRL_EXT, mac_data);
+
+	/* No MAC DPG gating SLP_S0 in modern standby
+	 * Switch the logic of the lanphypc to use PMC counter
+	 */
+	mac_data = er32(FEXTNVM5);
+	mac_data |= BIT(7);
+	ew32(FEXTNVM5, mac_data);
+}
+
+static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 mac_data;
+	u16 phy_data;
+
+	/* Disable the Dynamic Power Gating in the MAC */
+	mac_data = er32(FEXTNVM7);
+	mac_data &= 0xFFBFFFFF;
+	ew32(FEXTNVM7, mac_data);
+
+	/* Enable the time synchronization clock */
+	mac_data = er32(FEXTNVM7);
+	mac_data |= BIT(0);
+	ew32(FEXTNVM7, mac_data);
+
+	/* Disable Dynamic Power Gating */
+	mac_data = er32(CTRL_EXT);
+	mac_data &= 0xFFFFFFF7;
+	ew32(CTRL_EXT, mac_data);
+
+	/* Disable the Dynamic Clock Gating in the DMA and MAC */
+	mac_data = er32(CTRL_EXT);
+	mac_data &= 0xFFF7FFFF;
+	ew32(CTRL_EXT, mac_data);
+
+	/* Revert the lanphypc logic to use the internal Gbe counter
+	 * and not the PMC counter
+	 */
+	mac_data = er32(FEXTNVM5);
+	mac_data &= 0xFFFFFF7F;
+	ew32(FEXTNVM5, mac_data);
+
+	/* Enable the periodic inband message,
+	 * Request PCIe clock in K1 page770_17[10:9] =01b
+	 */
+	e1e_rphy(hw, HV_PM_CTRL, &phy_data);
+	phy_data &= 0xFBFF;
+	phy_data |= HV_PM_CTRL_K1_CLK_REQ;
+	e1e_wphy(hw, HV_PM_CTRL, phy_data);
+
+	/* Return back configuration
+	 * 772_29[5] = 0 CS_Mode_Stay_In_K1
+	 */
+	e1e_rphy(hw, I217_CGFREG, &phy_data);
+	phy_data &= 0xFFDF;
+	e1e_wphy(hw, I217_CGFREG, phy_data);
+
+	/* Change the MAC/PHY interface to Kumeran
+	 * Unforce the SMBus in PHY page769_23[0] = 0
+	 * Unforce the SMBus in MAC CTRL_EXT[11] = 0
+	 */
+	e1e_rphy(hw, CV_SMB_CTRL, &phy_data);
+	phy_data &= ~CV_SMB_CTRL_FORCE_SMBUS;
+	e1e_wphy(hw, CV_SMB_CTRL, phy_data);
+	mac_data = er32(CTRL_EXT);
+	mac_data &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+	ew32(CTRL_EXT, mac_data);
+}
+
 static int e1000e_pm_freeze(struct device *dev)
 {
 	struct net_device *netdev = dev_get_drvdata(dev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	bool present;
+
+	rtnl_lock();
 
+	present = netif_device_present(netdev);
 	netif_device_detach(netdev);
 
-	if (netif_running(netdev)) {
+	if (present && netif_running(netdev)) {
 		int count = E1000_CHECK_RESET_COUNT;
 
 		while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
@@ -6313,6 +6479,8 @@
 		e1000e_down(adapter, false);
 		e1000_free_irq(adapter);
 	}
+	rtnl_unlock();
+
 	e1000e_reset_interrupt_capability(adapter);
 
 	/* Allow time for pending master requests to run */
@@ -6326,11 +6494,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;
@@ -6387,7 +6561,7 @@
 	if (adapter->hw.phy.type == e1000_phy_igp_3) {
 		e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
 	} else if (hw->mac.type >= e1000_pch_lpt) {
-		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.
 			 */
@@ -6560,6 +6734,30 @@
 	__e1000e_disable_aspm(pdev, state, 1);
 }
 
+static int e1000e_pm_thaw(struct device *dev)
+{
+	struct net_device *netdev = dev_get_drvdata(dev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int rc = 0;
+
+	e1000e_set_interrupt_capability(adapter);
+
+	rtnl_lock();
+	if (netif_running(netdev)) {
+		rc = e1000_request_irq(adapter);
+		if (rc)
+			goto err_irq;
+
+		e1000e_up(adapter);
+	}
+
+	netif_device_attach(netdev);
+err_irq:
+	rtnl_unlock();
+
+	return rc;
+}
+
 #ifdef CONFIG_PM
 static int __e1000_resume(struct pci_dev *pdev)
 {
@@ -6627,29 +6825,12 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int e1000e_pm_thaw(struct device *dev)
-{
-	struct net_device *netdev = dev_get_drvdata(dev);
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-
-	e1000e_set_interrupt_capability(adapter);
-	if (netif_running(netdev)) {
-		u32 err = e1000_request_irq(adapter);
-
-		if (err)
-			return err;
-
-		e1000e_up(adapter);
-	}
-
-	netif_device_attach(netdev);
-
-	return 0;
-}
-
 static int e1000e_pm_suspend(struct device *dev)
 {
+	struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct pci_dev *pdev = to_pci_dev(dev);
+	struct e1000_hw *hw = &adapter->hw;
 	int rc;
 
 	e1000e_flush_lpic(pdev);
@@ -6660,14 +6841,25 @@
 	if (rc)
 		e1000e_pm_thaw(dev);
 
+	/* Introduce S0ix implementation */
+	if (hw->mac.type >= e1000_pch_cnp)
+		e1000e_s0ix_entry_flow(adapter);
+
 	return rc;
 }
 
 static int e1000e_pm_resume(struct device *dev)
 {
+	struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct pci_dev *pdev = to_pci_dev(dev);
+	struct e1000_hw *hw = &adapter->hw;
 	int rc;
 
+	/* Introduce S0ix implementation */
+	if (hw->mac.type >= e1000_pch_cnp)
+		e1000e_s0ix_exit_flow(adapter);
+
 	rc = __e1000_resume(pdev);
 	if (rc)
 		return rc;
@@ -6818,16 +7010,11 @@
 static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
 						pci_channel_state_t state)
 {
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-
-	netif_device_detach(netdev);
+	e1000e_pm_freeze(&pdev->dev);
 
 	if (state == pci_channel_io_perm_failure)
 		return PCI_ERS_RESULT_DISCONNECT;
 
-	if (netif_running(netdev))
-		e1000e_down(adapter, true);
 	pci_disable_device(pdev);
 
 	/* Request a slot slot reset. */
@@ -6893,10 +7080,7 @@
 
 	e1000_init_manageability_pt(adapter);
 
-	if (netif_running(netdev))
-		e1000e_up(adapter);
-
-	netif_device_attach(netdev);
+	e1000e_pm_thaw(&pdev->dev);
 
 	/* If the controller has AMT, do not set DRV_LOAD until the interface
 	 * is up.  For all other cases, let the f/w know that the h/w is now
@@ -7196,6 +7380,32 @@
 			    NETIF_F_RXCSUM |
 			    NETIF_F_HW_CSUM);
 
+	/* disable TSO for pcie and 10/100 speeds to avoid
+	 * some hardware issues and for i219 to fix transfer
+	 * speed being capped at 60%
+	 */
+	if (!(adapter->flags & FLAG_TSO_FORCE)) {
+		switch (adapter->link_speed) {
+		case SPEED_10:
+		case SPEED_100:
+			e_info("10/100 speed: disabling TSO\n");
+			netdev->features &= ~NETIF_F_TSO;
+			netdev->features &= ~NETIF_F_TSO6;
+			break;
+		case SPEED_1000:
+			netdev->features |= NETIF_F_TSO;
+			netdev->features |= NETIF_F_TSO6;
+			break;
+		default:
+			/* oops */
+			break;
+		}
+		if (hw->mac.type == e1000_pch_spt) {
+			netdev->features &= ~NETIF_F_TSO;
+			netdev->features &= ~NETIF_F_TSO6;
+		}
+	}
+
 	/* Set user-changeable features (subset of all device features) */
 	netdev->hw_features = netdev->features;
 	netdev->hw_features |= NETIF_F_RXFCS;
@@ -7259,21 +7469,11 @@
 		goto err_eeprom;
 	}
 
-	adapter->e1000_workqueue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0,
-						   e1000e_driver_name);
-
-	if (!adapter->e1000_workqueue) {
-		err = -ENOMEM;
-		goto err_workqueue;
-	}
-
-	INIT_DELAYED_WORK(&adapter->watchdog_task, e1000_watchdog_task);
-	queue_delayed_work(adapter->e1000_workqueue, &adapter->watchdog_task,
-			   0);
-
+	timer_setup(&adapter->watchdog_timer, e1000_watchdog, 0);
 	timer_setup(&adapter->phy_info_timer, e1000_update_phy_info, 0);
 
 	INIT_WORK(&adapter->reset_task, e1000_reset_task);
+	INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
 	INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
 	INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
 	INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang);
@@ -7367,9 +7567,6 @@
 	return 0;
 
 err_register:
-	flush_workqueue(adapter->e1000_workqueue);
-	destroy_workqueue(adapter->e1000_workqueue);
-err_workqueue:
 	if (!(adapter->flags & FLAG_HAS_AMT))
 		e1000e_release_hw_control(adapter);
 err_eeprom:
@@ -7387,6 +7584,7 @@
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_etherdev:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
@@ -7407,26 +7605,22 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	bool down = test_bit(__E1000_DOWN, &adapter->state);
 
 	e1000e_ptp_remove(adapter);
 
 	/* The timers may be rescheduled, so explicitly disable them
 	 * from being rescheduled.
 	 */
-	if (!down)
-		set_bit(__E1000_DOWN, &adapter->state);
+	set_bit(__E1000_DOWN, &adapter->state);
+	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 
 	cancel_work_sync(&adapter->reset_task);
+	cancel_work_sync(&adapter->watchdog_task);
 	cancel_work_sync(&adapter->downshift_task);
 	cancel_work_sync(&adapter->update_phy_task);
 	cancel_work_sync(&adapter->print_hang_task);
 
-	cancel_delayed_work(&adapter->watchdog_task);
-	flush_workqueue(adapter->e1000_workqueue);
-	destroy_workqueue(adapter->e1000_workqueue);
-
 	if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
 		cancel_work_sync(&adapter->tx_hwtstamp_work);
 		if (adapter->tx_hwtstamp_skb) {
@@ -7435,9 +7629,6 @@
 		}
 	}
 
-	/* Don't lie to e1000_close() down the road. */
-	if (!down)
-		clear_bit(__E1000_DOWN, &adapter->state);
 	unregister_netdev(netdev);
 
 	if (pci_dev_run_wake(pdev))
@@ -7567,6 +7758,12 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V8), board_pch_cnp },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM9), board_pch_cnp },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V9), board_pch_cnp },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM10), board_pch_cnp },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V10), board_pch_cnp },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM11), board_pch_cnp },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V11), board_pch_cnp },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM12), board_pch_spt },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V12), board_pch_spt },
 
 	{ 0, 0, 0, 0, 0, 0, 0 }	/* terminate list */
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/phy.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/phy.c
@@ -203,7 +203,7 @@
 	 * Increasing the time out as testing showed failures with
 	 * the lower time out
 	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 10); i++) {
 		udelay(50);
 		mdic = er32(MDIC);
 		if (mdic & E1000_MDIC_READY)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/e1000e/regs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/e1000e/regs.h
@@ -18,6 +18,7 @@
 #define E1000_FEXTNVM	0x00028	/* Future Extended NVM - RW */
 #define E1000_FEXTNVM3	0x0003C	/* Future Extended NVM 3 - RW */
 #define E1000_FEXTNVM4	0x00024	/* Future Extended NVM 4 - RW */
+#define E1000_FEXTNVM5	0x00014	/* Future Extended NVM 5 - RW */
 #define E1000_FEXTNVM6	0x00010	/* Future Extended NVM 6 - RW */
 #define E1000_FEXTNVM7	0x000E4	/* Future Extended NVM 7 - RW */
 #define E1000_FEXTNVM9	0x5BB4	/* Future Extended NVM 9 - RW */
@@ -234,4 +235,7 @@
 #define E1000_RXMTRL	0x0B634	/* Time sync Rx EtherType and Msg Type - RW */
 #define E1000_RXUDP	0x0B638	/* Time Sync Rx UDP Port - RW */
 
+/* PHY registers */
+#define I82579_DFT_CTRL	PHY_REG(769, 20)
+
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -2230,6 +2230,7 @@
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_netdev:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e.h
@@ -129,6 +129,7 @@
 	__I40E_RESET_INTR_RECEIVED,
 	__I40E_REINIT_REQUESTED,
 	__I40E_PF_RESET_REQUESTED,
+	__I40E_PF_RESET_AND_REBUILD_REQUESTED,
 	__I40E_CORE_RESET_REQUESTED,
 	__I40E_GLOBAL_RESET_REQUESTED,
 	__I40E_EMP_RESET_INTR_RECEIVED,
@@ -150,11 +151,15 @@
 	__I40E_CLIENT_RESET,
 	__I40E_VIRTCHNL_OP_PENDING,
 	__I40E_RECOVERY_MODE,
+	__I40E_VF_RESETS_DISABLED,	/* disable resets during i40e_remove */
+	__I40E_VFS_RELEASING,
 	/* This must be last as it determines the size of the BITMAP */
 	__I40E_STATE_SIZE__,
 };
 
 #define I40E_PF_RESET_FLAG	BIT_ULL(__I40E_PF_RESET_REQUESTED)
+#define I40E_PF_RESET_AND_REBUILD_FLAG	\
+	BIT_ULL(__I40E_PF_RESET_AND_REBUILD_REQUESTED)
 
 /* VSI state flags */
 enum i40e_vsi_state_t {
@@ -164,6 +169,7 @@
 	__I40E_VSI_OVERFLOW_PROMISC,
 	__I40E_VSI_REINIT_REQUESTED,
 	__I40E_VSI_DOWN_REQUESTED,
+	__I40E_VSI_RELEASING,
 	/* This must be last as it determines the size of the BITMAP */
 	__I40E_VSI_STATE_SIZE__,
 };
@@ -176,7 +182,6 @@
 
 struct i40e_lump_tracking {
 	u16 num_entries;
-	u16 search_hint;
 	u16 list[0];
 #define I40E_PILE_VALID_BIT  0x8000
 #define I40E_IWARP_IRQ_PILE_ID  (I40E_PILE_VALID_BIT - 2)
@@ -751,12 +756,12 @@
 	struct rtnl_link_stats64 net_stats_offsets;
 	struct i40e_eth_stats eth_stats;
 	struct i40e_eth_stats eth_stats_offsets;
-	u32 tx_restart;
-	u32 tx_busy;
+	u64 tx_restart;
+	u64 tx_busy;
 	u64 tx_linearize;
 	u64 tx_force_wb;
-	u32 rx_buf_failed;
-	u32 rx_page_failed;
+	u64 rx_buf_failed;
+	u64 rx_page_failed;
 
 	/* These are containers of ring pointers, allocated at run-time */
 	struct i40e_ring **rx_rings;
@@ -1141,6 +1146,7 @@
 void i40e_ptp_restore_hw_time(struct i40e_pf *pf);
 void i40e_ptp_init(struct i40e_pf *pf);
 void i40e_ptp_stop(struct i40e_pf *pf);
+int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset);
 int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
 i40e_status i40e_get_partition_bw_setting(struct i40e_pf *pf);
 i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf);
@@ -1151,7 +1157,7 @@
 
 static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
 {
-	return !!vsi->xdp_prog;
+	return !!READ_ONCE(vsi->xdp_prog);
 }
 
 int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -1211,7 +1211,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
+#define I40E_AQC_SET_VSI_PROMISC_RX_ONLY	0x8000
 	__le16	seid;
 #define I40E_AQC_VSI_PROM_CMD_SEID_MASK		0x3FF
 	__le16	vlan_tag;
@@ -1893,8 +1893,10 @@
 	I40E_PHY_TYPE_25GBASE_LR		= 0x22,
 	I40E_PHY_TYPE_25GBASE_AOC		= 0x23,
 	I40E_PHY_TYPE_25GBASE_ACC		= 0x24,
-	I40E_PHY_TYPE_2_5GBASE_T		= 0x30,
-	I40E_PHY_TYPE_5GBASE_T			= 0x31,
+	I40E_PHY_TYPE_2_5GBASE_T		= 0x26,
+	I40E_PHY_TYPE_5GBASE_T			= 0x27,
+	I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS	= 0x30,
+	I40E_PHY_TYPE_5GBASE_T_LINK_STATUS	= 0x31,
 	I40E_PHY_TYPE_MAX,
 	I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP	= 0xFD,
 	I40E_PHY_TYPE_EMPTY			= 0xFE,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_alloc.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_alloc.h
@@ -20,16 +20,11 @@
 };
 
 /* prototype for functions used for dynamic memory allocation */
-i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw,
-					    struct i40e_dma_mem *mem,
-					    enum i40e_memory_type type,
-					    u64 size, u32 alignment);
-i40e_status i40e_free_dma_mem(struct i40e_hw *hw,
-					struct i40e_dma_mem *mem);
-i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw,
-					     struct i40e_virt_mem *mem,
-					     u32 size);
-i40e_status i40e_free_virt_mem(struct i40e_hw *hw,
-					 struct i40e_virt_mem *mem);
+int i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem,
+			  enum i40e_memory_type type, u64 size, u32 alignment);
+int i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem);
+int i40e_allocate_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem,
+			   u32 size);
+int i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem);
 
 #endif /* _I40E_ALLOC_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_client.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_client.c
@@ -178,6 +178,10 @@
 			"Cannot locate client instance close routine\n");
 		return;
 	}
+	if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
+		dev_dbg(&pf->pdev->dev, "Client is not open, abort close\n");
+		return;
+	}
 	cdev->client->ops->close(&cdev->lan_info, cdev->client, reset);
 	clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
 	i40e_client_release_qvlist(&cdev->lan_info);
@@ -376,7 +380,7 @@
 				/* Remove failed client instance */
 				clear_bit(__I40E_CLIENT_INSTANCE_OPENED,
 					  &cdev->state);
-				i40e_client_del_instance(pf);
+				return;
 			}
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -29,6 +29,7 @@
 		case I40E_DEV_ID_QSFP_C:
 		case I40E_DEV_ID_10G_BASE_T:
 		case I40E_DEV_ID_10G_BASE_T4:
+		case I40E_DEV_ID_10G_BASE_T_BC:
 		case I40E_DEV_ID_10G_B:
 		case I40E_DEV_ID_10G_SFP:
 		case I40E_DEV_ID_20G_KR2:
@@ -1156,8 +1157,8 @@
 		break;
 	case I40E_PHY_TYPE_100BASE_TX:
 	case I40E_PHY_TYPE_1000BASE_T:
-	case I40E_PHY_TYPE_2_5GBASE_T:
-	case I40E_PHY_TYPE_5GBASE_T:
+	case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS:
+	case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS:
 	case I40E_PHY_TYPE_10GBASE_T:
 		media = I40E_MEDIA_TYPE_BASET;
 		break;
@@ -1341,7 +1342,7 @@
 		     I40E_PFLAN_QALLOC_FIRSTQ_SHIFT;
 	j = (val & I40E_PFLAN_QALLOC_LASTQ_MASK) >>
 	    I40E_PFLAN_QALLOC_LASTQ_SHIFT;
-	if (val & I40E_PFLAN_QALLOC_VALID_MASK)
+	if (val & I40E_PFLAN_QALLOC_VALID_MASK && j >= base_queue)
 		num_queues = (j - base_queue) + 1;
 	else
 		num_queues = 0;
@@ -1351,7 +1352,7 @@
 	    I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT;
 	j = (val & I40E_PF_VT_PFALLOC_LASTVF_MASK) >>
 	    I40E_PF_VT_PFALLOC_LASTVF_SHIFT;
-	if (val & I40E_PF_VT_PFALLOC_VALID_MASK)
+	if (val & I40E_PF_VT_PFALLOC_VALID_MASK && j >= i)
 		num_vfs = (j - i) + 1;
 	else
 		num_vfs = 0;
@@ -1441,9 +1442,9 @@
 	u32 gpio_val = 0;
 	u32 port;
 
-	if (!hw->func_caps.led[idx])
+	if (!I40E_IS_X710TL_DEVICE(hw->device_id) &&
+	    !hw->func_caps.led[idx])
 		return 0;
-
 	gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(idx));
 	port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK) >>
 		I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT;
@@ -1462,8 +1463,15 @@
 #define I40E_FILTER_ACTIVITY 0xE
 #define I40E_LINK_ACTIVITY 0xC
 #define I40E_MAC_ACTIVITY 0xD
+#define I40E_FW_LED BIT(4)
+#define I40E_LED_MODE_VALID (I40E_GLGEN_GPIO_CTL_LED_MODE_MASK >> \
+			     I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT)
+
 #define I40E_LED0 22
 
+#define I40E_PIN_FUNC_SDP 0x0
+#define I40E_PIN_FUNC_LED 0x1
+
 /**
  * i40e_led_get - return current on/off mode
  * @hw: pointer to the hw struct
@@ -1508,8 +1516,10 @@
 {
 	int i;
 
-	if (mode & 0xfffffff0)
+	if (mode & ~I40E_LED_MODE_VALID) {
 		hw_dbg(hw, "invalid mode passed in %X\n", mode);
+		return;
+	}
 
 	/* as per the documentation GPIO 22-29 are the LED
 	 * GPIO pins named LED0..LED7
@@ -1519,6 +1529,20 @@
 
 		if (!gpio_val)
 			continue;
+
+		if (I40E_IS_X710TL_DEVICE(hw->device_id)) {
+			u32 pin_func = 0;
+
+			if (mode & I40E_FW_LED)
+				pin_func = I40E_PIN_FUNC_SDP;
+			else
+				pin_func = I40E_PIN_FUNC_LED;
+
+			gpio_val &= ~I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK;
+			gpio_val |= ((pin_func <<
+				     I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) &
+				     I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK);
+		}
 		gpio_val &= ~I40E_GLGEN_GPIO_CTL_LED_MODE_MASK;
 		/* this & is a bit of paranoia, but serves as a range check */
 		gpio_val |= ((mode << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) &
@@ -1950,6 +1974,21 @@
 }
 
 /**
+ * i40e_is_aq_api_ver_ge
+ * @aq: pointer to AdminQ info containing HW API version to compare
+ * @maj: API major value
+ * @min: API minor value
+ *
+ * Assert whether current HW API version is greater/equal than provided.
+ **/
+static bool i40e_is_aq_api_ver_ge(struct i40e_adminq_info *aq, u16 maj,
+				  u16 min)
+{
+	return (aq->api_maj_ver > maj ||
+		(aq->api_maj_ver == maj && aq->api_min_ver >= min));
+}
+
+/**
  * i40e_aq_add_vsi
  * @hw: pointer to the hw struct
  * @vsi_ctx: pointer to a vsi context struct
@@ -2074,18 +2113,16 @@
 
 	if (set) {
 		flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
-		if (rx_only_promisc &&
-		    (((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;
+		if (rx_only_promisc && i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+			flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY;
 	}
 
 	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);
+	if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+		cmd->valid_flags |=
+			cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY);
 
 	cmd->seid = cpu_to_le16(seid);
 	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
@@ -2182,11 +2219,17 @@
 	i40e_fill_default_direct_cmd_desc(&desc,
 					  i40e_aqc_opc_set_vsi_promiscuous_modes);
 
-	if (enable)
+	if (enable) {
 		flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
+		if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+			flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY;
+	}
 
 	cmd->promiscuous_flags = cpu_to_le16(flags);
 	cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
+	if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+		cmd->valid_flags |=
+			cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY);
 	cmd->seid = cpu_to_le16(seid);
 	cmd->vlan_tag = cpu_to_le16(vid | I40E_AQC_SET_VSI_VLAN_VALID);
 
@@ -2571,9 +2614,16 @@
 		if (status)
 			return status;
 
-		hw->phy.link_info.req_fec_info =
-			abilities.fec_cfg_curr_mod_ext_info &
-			(I40E_AQ_REQUEST_FEC_KR | I40E_AQ_REQUEST_FEC_RS);
+		if (abilities.fec_cfg_curr_mod_ext_info &
+		    I40E_AQ_ENABLE_FEC_AUTO)
+			hw->phy.link_info.req_fec_info =
+				(I40E_AQ_REQUEST_FEC_KR |
+				 I40E_AQ_REQUEST_FEC_RS);
+		else
+			hw->phy.link_info.req_fec_info =
+				abilities.fec_cfg_curr_mod_ext_info &
+				(I40E_AQ_REQUEST_FEC_KR |
+				 I40E_AQ_REQUEST_FEC_RS);
 
 		memcpy(hw->phy.link_info.module_type, &abilities.module_type,
 		       sizeof(hw->phy.link_info.module_type));
@@ -4885,6 +4935,7 @@
 		break;
 	case I40E_DEV_ID_10G_BASE_T:
 	case I40E_DEV_ID_10G_BASE_T4:
+	case I40E_DEV_ID_10G_BASE_T_BC:
 	case I40E_DEV_ID_10G_BASE_T_X722:
 	case I40E_DEV_ID_25G_B:
 	case I40E_DEV_ID_25G_SFP28:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_dcb.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_dcb.c
@@ -889,7 +889,9 @@
 
 		ret = i40e_read_nvm_module_data(hw,
 						I40E_SR_EMP_SR_SETTINGS_PTR,
-						offset, 1,
+						offset,
+						I40E_LLDP_CURRENT_STATUS_OFFSET,
+						I40E_LLDP_CURRENT_STATUS_SIZE,
 						&lldp_cfg.adminstatus);
 	} else {
 		ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_dcb.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_dcb.h
@@ -32,6 +32,9 @@
 #define I40E_CEE_MAX_FEAT_TYPE		3
 #define I40E_LLDP_CURRENT_STATUS_XL710_OFFSET	0x2B
 #define I40E_LLDP_CURRENT_STATUS_X722_OFFSET	0x31
+#define I40E_LLDP_CURRENT_STATUS_OFFSET		1
+#define I40E_LLDP_CURRENT_STATUS_SIZE		1
+
 /* Defines for LLDP TLV header */
 #define I40E_LLDP_TLV_LEN_SHIFT		0
 #define I40E_LLDP_TLV_LEN_MASK		(0x01FF << I40E_LLDP_TLV_LEN_SHIFT)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -234,7 +234,7 @@
 		 (unsigned long int)vsi->net_stats_offsets.rx_compressed,
 		 (unsigned long int)vsi->net_stats_offsets.tx_compressed);
 	dev_info(&pf->pdev->dev,
-		 "    tx_restart = %d, tx_busy = %d, rx_buf_failed = %d, rx_page_failed = %d\n",
+		 "    tx_restart = %llu, tx_busy = %llu, rx_buf_failed = %llu, rx_page_failed = %llu\n",
 		 vsi->tx_restart, vsi->tx_busy,
 		 vsi->rx_buf_failed, vsi->rx_page_failed);
 	rcu_read_lock();
@@ -1755,7 +1755,7 @@
 void i40e_dbg_init(void)
 {
 	i40e_dbg_root = debugfs_create_dir(i40e_driver_name, NULL);
-	if (!i40e_dbg_root)
+	if (IS_ERR(i40e_dbg_root))
 		pr_info("init of debugfs failed\n");
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_devids.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_devids.h
@@ -23,6 +23,8 @@
 #define I40E_DEV_ID_10G_BASE_T_BC	0x15FF
 #define I40E_DEV_ID_10G_B		0x104F
 #define I40E_DEV_ID_10G_SFP		0x104E
+#define I40E_IS_X710TL_DEVICE(d) \
+	((d) == I40E_DEV_ID_10G_BASE_T_BC)
 #define I40E_DEV_ID_KX_X722		0x37CE
 #define I40E_DEV_ID_QSFP_X722		0x37CF
 #define I40E_DEV_ID_SFP_X722		0x37D0
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_diag.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_diag.c
@@ -44,7 +44,7 @@
 	return 0;
 }
 
-struct i40e_diag_reg_test_info i40e_reg_list[] = {
+const struct i40e_diag_reg_test_info i40e_reg_list[] = {
 	/* offset               mask         elements   stride */
 	{I40E_QTX_CTL(0),       0x0000FFBF, 1,
 		I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
@@ -78,27 +78,28 @@
 {
 	i40e_status ret_code = 0;
 	u32 reg, mask;
+	u32 elements;
 	u32 i, j;
 
 	for (i = 0; i40e_reg_list[i].offset != 0 &&
 					     !ret_code; i++) {
 
+		elements = i40e_reg_list[i].elements;
 		/* set actual reg range for dynamically allocated resources */
 		if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) &&
 		    hw->func_caps.num_tx_qp != 0)
-			i40e_reg_list[i].elements = hw->func_caps.num_tx_qp;
+			elements = hw->func_caps.num_tx_qp;
 		if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) ||
 		     i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) ||
 		     i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) ||
 		     i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) ||
 		     i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) &&
 		    hw->func_caps.num_msix_vectors != 0)
-			i40e_reg_list[i].elements =
-				hw->func_caps.num_msix_vectors - 1;
+			elements = hw->func_caps.num_msix_vectors - 1;
 
 		/* test register access */
 		mask = i40e_reg_list[i].mask;
-		for (j = 0; j < i40e_reg_list[i].elements && !ret_code; j++) {
+		for (j = 0; j < elements && !ret_code; j++) {
 			reg = i40e_reg_list[i].offset +
 			      (j * i40e_reg_list[i].stride);
 			ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_diag.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_diag.h
@@ -20,7 +20,7 @@
 	u32 stride;	/* bytes between each element */
 };
 
-extern struct i40e_diag_reg_test_info i40e_reg_list[];
+extern const struct i40e_diag_reg_test_info i40e_reg_list[];
 
 i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
 i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -232,6 +232,8 @@
 	I40E_STAT(struct i40e_vsi, _name, _stat)
 #define I40E_VEB_STAT(_name, _stat) \
 	I40E_STAT(struct i40e_veb, _name, _stat)
+#define I40E_VEB_TC_STAT(_name, _stat) \
+	I40E_STAT(struct i40e_cp_veb_tc_stats, _name, _stat)
 #define I40E_PFC_STAT(_name, _stat) \
 	I40E_STAT(struct i40e_pfc_stats, _name, _stat)
 #define I40E_QUEUE_STAT(_name, _stat) \
@@ -266,11 +268,18 @@
 	I40E_VEB_STAT("veb.rx_unknown_protocol", stats.rx_unknown_protocol),
 };
 
+struct i40e_cp_veb_tc_stats {
+	u64 tc_rx_packets;
+	u64 tc_rx_bytes;
+	u64 tc_tx_packets;
+	u64 tc_tx_bytes;
+};
+
 static const struct i40e_stats i40e_gstrings_veb_tc_stats[] = {
-	I40E_VEB_STAT("veb.tc_%u_tx_packets", tc_stats.tc_tx_packets),
-	I40E_VEB_STAT("veb.tc_%u_tx_bytes", tc_stats.tc_tx_bytes),
-	I40E_VEB_STAT("veb.tc_%u_rx_packets", tc_stats.tc_rx_packets),
-	I40E_VEB_STAT("veb.tc_%u_rx_bytes", tc_stats.tc_rx_bytes),
+	I40E_VEB_TC_STAT("veb.tc_%u_tx_packets", tc_tx_packets),
+	I40E_VEB_TC_STAT("veb.tc_%u_tx_bytes", tc_tx_bytes),
+	I40E_VEB_TC_STAT("veb.tc_%u_rx_packets", tc_rx_packets),
+	I40E_VEB_TC_STAT("veb.tc_%u_rx_bytes", tc_rx_bytes),
 };
 
 static const struct i40e_stats i40e_gstrings_misc_stats[] = {
@@ -722,7 +731,14 @@
 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
 	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
 
-	if (I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) {
+	if ((I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) &&
+	    (I40E_AQ_SET_FEC_REQUEST_KR & req_fec_info)) {
+		ethtool_link_ksettings_add_link_mode(ks, advertising,
+						     FEC_NONE);
+		ethtool_link_ksettings_add_link_mode(ks, advertising,
+						     FEC_BASER);
+		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+	} else if (I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) {
 		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
 	} else if (I40E_AQ_SET_FEC_REQUEST_KR & req_fec_info) {
 		ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -730,12 +746,6 @@
 	} else {
 		ethtool_link_ksettings_add_link_mode(ks, advertising,
 						     FEC_NONE);
-		if (I40E_AQ_SET_FEC_AUTO & req_fec_info) {
-			ethtool_link_ksettings_add_link_mode(ks, advertising,
-							     FEC_RS);
-			ethtool_link_ksettings_add_link_mode(ks, advertising,
-							     FEC_BASER);
-		}
 	}
 }
 
@@ -829,8 +839,8 @@
 							     10000baseT_Full);
 		break;
 	case I40E_PHY_TYPE_10GBASE_T:
-	case I40E_PHY_TYPE_5GBASE_T:
-	case I40E_PHY_TYPE_2_5GBASE_T:
+	case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS:
+	case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS:
 	case I40E_PHY_TYPE_1000BASE_T:
 	case I40E_PHY_TYPE_100BASE_TX:
 		ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
@@ -967,7 +977,7 @@
 	default:
 		/* if we got here and link is up something bad is afoot */
 		netdev_info(netdev,
-			    "WARNING: Link is up but PHY type 0x%x is not recognized.\n",
+			    "WARNING: Link is up but PHY type 0x%x is not recognized, or incorrect cable is in use\n",
 			    hw_link_info->phy_type);
 	}
 
@@ -1097,6 +1107,7 @@
 
 	/* Set flow control settings */
 	ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
+	ethtool_link_ksettings_add_link_mode(ks, supported, Asym_Pause);
 
 	switch (hw->fc.requested_mode) {
 	case I40E_FC_FULL:
@@ -1248,8 +1259,7 @@
 			if (ethtool_link_ksettings_test_link_mode(&safe_ks,
 								  supported,
 								  Autoneg) &&
-			    hw->phy.link_info.phy_type !=
-			    I40E_PHY_TYPE_10GBASE_T) {
+			    hw->phy.media_type != I40E_MEDIA_TYPE_BASET) {
 				netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
 				err = -EINVAL;
 				goto done;
@@ -1395,7 +1405,8 @@
 
 		memset(&config, 0, sizeof(config));
 		config.phy_type = abilities.phy_type;
-		config.abilities = abilities.abilities;
+		config.abilities = abilities.abilities |
+				   I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
 		config.phy_type_ext = abilities.phy_type_ext;
 		config.link_speed = abilities.link_speed;
 		config.eee_capability = abilities.eee_capability;
@@ -1437,6 +1448,7 @@
 	struct i40e_hw *hw = &pf->hw;
 	i40e_status status = 0;
 	int err = 0;
+	u8 fec_cfg;
 
 	/* Get the current phy config */
 	memset(&abilities, 0, sizeof(abilities));
@@ -1448,18 +1460,16 @@
 	}
 
 	fecparam->fec = 0;
-	if (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_AUTO)
+	fec_cfg = abilities.fec_cfg_curr_mod_ext_info;
+	if (fec_cfg & I40E_AQ_SET_FEC_AUTO)
 		fecparam->fec |= ETHTOOL_FEC_AUTO;
-	if ((abilities.fec_cfg_curr_mod_ext_info &
-	     I40E_AQ_SET_FEC_REQUEST_RS) ||
-	    (abilities.fec_cfg_curr_mod_ext_info &
-	     I40E_AQ_SET_FEC_ABILITY_RS))
+	else if (fec_cfg & (I40E_AQ_SET_FEC_REQUEST_RS |
+		 I40E_AQ_SET_FEC_ABILITY_RS))
 		fecparam->fec |= ETHTOOL_FEC_RS;
-	if ((abilities.fec_cfg_curr_mod_ext_info &
-	     I40E_AQ_SET_FEC_REQUEST_KR) ||
-	    (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_ABILITY_KR))
+	else if (fec_cfg & (I40E_AQ_SET_FEC_REQUEST_KR |
+		 I40E_AQ_SET_FEC_ABILITY_KR))
 		fecparam->fec |= ETHTOOL_FEC_BASER;
-	if (abilities.fec_cfg_curr_mod_ext_info == 0)
+	if (fec_cfg == 0)
 		fecparam->fec |= ETHTOOL_FEC_OFF;
 
 	if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA)
@@ -2213,6 +2223,29 @@
 }
 
 /**
+ * i40e_get_veb_tc_stats - copy VEB TC statistics to formatted structure
+ * @tc: the TC statistics in VEB structure (veb->tc_stats)
+ * @i: the index of traffic class in (veb->tc_stats) structure to copy
+ *
+ * Copy VEB TC statistics from structure of arrays (veb->tc_stats) to
+ * one dimensional structure i40e_cp_veb_tc_stats.
+ * Produce formatted i40e_cp_veb_tc_stats structure of the VEB TC
+ * statistics for the given TC.
+ **/
+static struct i40e_cp_veb_tc_stats
+i40e_get_veb_tc_stats(struct i40e_veb_tc_stats *tc, unsigned int i)
+{
+	struct i40e_cp_veb_tc_stats veb_tc = {
+		.tc_rx_packets = tc->tc_rx_packets[i],
+		.tc_rx_bytes = tc->tc_rx_bytes[i],
+		.tc_tx_packets = tc->tc_tx_packets[i],
+		.tc_tx_bytes = tc->tc_tx_bytes[i],
+	};
+
+	return veb_tc;
+}
+
+/**
  * i40e_get_pfc_stats - copy HW PFC statistics to formatted structure
  * @pf: the PF device structure
  * @i: the priority value to copy
@@ -2296,8 +2329,16 @@
 			       i40e_gstrings_veb_stats);
 
 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
-		i40e_add_ethtool_stats(&data, veb_stats ? veb : NULL,
-				       i40e_gstrings_veb_tc_stats);
+		if (veb_stats) {
+			struct i40e_cp_veb_tc_stats veb_tc =
+				i40e_get_veb_tc_stats(&veb->tc_stats, i);
+
+			i40e_add_ethtool_stats(&data, &veb_tc,
+					       i40e_gstrings_veb_tc_stats);
+		} else {
+			i40e_add_ethtool_stats(&data, NULL,
+					       i40e_gstrings_veb_tc_stats);
+		}
 
 	i40e_add_ethtool_stats(&data, pf, i40e_gstrings_stats);
 
@@ -2537,15 +2578,16 @@
 
 		set_bit(__I40E_TESTING, pf->state);
 
+		if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
+		    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state)) {
+			dev_warn(&pf->pdev->dev,
+				 "Cannot start offline testing when PF is in reset state.\n");
+			goto skip_ol_tests;
+		}
+
 		if (i40e_active_vfs(pf) || i40e_active_vmdqs(pf)) {
 			dev_warn(&pf->pdev->dev,
 				 "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n");
-			data[I40E_ETH_TEST_REG]		= 1;
-			data[I40E_ETH_TEST_EEPROM]	= 1;
-			data[I40E_ETH_TEST_INTR]	= 1;
-			data[I40E_ETH_TEST_LINK]	= 1;
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-			clear_bit(__I40E_TESTING, pf->state);
 			goto skip_ol_tests;
 		}
 
@@ -2592,9 +2634,17 @@
 		data[I40E_ETH_TEST_INTR] = 0;
 	}
 
-skip_ol_tests:
-
 	netif_info(pf, drv, netdev, "testing finished\n");
+	return;
+
+skip_ol_tests:
+	data[I40E_ETH_TEST_REG]		= 1;
+	data[I40E_ETH_TEST_EEPROM]	= 1;
+	data[I40E_ETH_TEST_INTR]	= 1;
+	data[I40E_ETH_TEST_LINK]	= 1;
+	eth_test->flags |= ETH_TEST_FL_FAILED;
+	clear_bit(__I40E_TESTING, pf->state);
+	netif_info(pf, drv, netdev, "testing failed\n");
 }
 
 static void i40e_get_wol(struct net_device *netdev,
@@ -3032,10 +3082,17 @@
 
 		if (cmd->flow_type == TCP_V4_FLOW ||
 		    cmd->flow_type == UDP_V4_FLOW) {
-			if (i_set & I40E_L3_SRC_MASK)
-				cmd->data |= RXH_IP_SRC;
-			if (i_set & I40E_L3_DST_MASK)
-				cmd->data |= RXH_IP_DST;
+			if (hw->mac.type == I40E_MAC_X722) {
+				if (i_set & I40E_X722_L3_SRC_MASK)
+					cmd->data |= RXH_IP_SRC;
+				if (i_set & I40E_X722_L3_DST_MASK)
+					cmd->data |= RXH_IP_DST;
+			} else {
+				if (i_set & I40E_L3_SRC_MASK)
+					cmd->data |= RXH_IP_SRC;
+				if (i_set & I40E_L3_DST_MASK)
+					cmd->data |= RXH_IP_DST;
+			}
 		} else if (cmd->flow_type == TCP_V6_FLOW ||
 			  cmd->flow_type == UDP_V6_FLOW) {
 			if (i_set & I40E_L3_V6_SRC_MASK)
@@ -3342,12 +3399,15 @@
 
 /**
  * i40e_get_rss_hash_bits - Read RSS Hash bits from register
+ * @hw: hw structure
  * @nfc: pointer to user request
  * @i_setc: bits currently set
  *
  * Returns value of bits to be set per user request
  **/
-static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc)
+static u64 i40e_get_rss_hash_bits(struct i40e_hw *hw,
+				  struct ethtool_rxnfc *nfc,
+				  u64 i_setc)
 {
 	u64 i_set = i_setc;
 	u64 src_l3 = 0, dst_l3 = 0;
@@ -3366,8 +3426,13 @@
 		dst_l3 = I40E_L3_V6_DST_MASK;
 	} else if (nfc->flow_type == TCP_V4_FLOW ||
 		  nfc->flow_type == UDP_V4_FLOW) {
-		src_l3 = I40E_L3_SRC_MASK;
-		dst_l3 = I40E_L3_DST_MASK;
+		if (hw->mac.type == I40E_MAC_X722) {
+			src_l3 = I40E_X722_L3_SRC_MASK;
+			dst_l3 = I40E_X722_L3_DST_MASK;
+		} else {
+			src_l3 = I40E_L3_SRC_MASK;
+			dst_l3 = I40E_L3_DST_MASK;
+		}
 	} else {
 		/* Any other flow type are not supported here */
 		return i_set;
@@ -3385,6 +3450,7 @@
 	return i_set;
 }
 
+#define FLOW_PCTYPES_SIZE 64
 /**
  * i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash
  * @pf: pointer to the physical function struct
@@ -3397,9 +3463,11 @@
 	struct i40e_hw *hw = &pf->hw;
 	u64 hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
 		   ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
-	u8 flow_pctype = 0;
+	DECLARE_BITMAP(flow_pctypes, FLOW_PCTYPES_SIZE);
 	u64 i_set, i_setc;
 
+	bitmap_zero(flow_pctypes, FLOW_PCTYPES_SIZE);
+
 	if (pf->flags & I40E_FLAG_MFP_ENABLED) {
 		dev_err(&pf->pdev->dev,
 			"Change of RSS hash input set is not supported when MFP mode is enabled\n");
@@ -3415,36 +3483,35 @@
 
 	switch (nfc->flow_type) {
 	case TCP_V4_FLOW:
-		flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+		set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP, flow_pctypes);
 		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
-			hena |=
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
+			set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK,
+				flow_pctypes);
 		break;
 	case TCP_V6_FLOW:
-		flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
+		set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP, flow_pctypes);
 		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
-			hena |=
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
-		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
-			hena |=
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
+			set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK,
+				flow_pctypes);
 		break;
 	case UDP_V4_FLOW:
-		flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
-		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
-			hena |=
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
-
+		set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_UDP, flow_pctypes);
+		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+			set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP,
+				flow_pctypes);
+			set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP,
+				flow_pctypes);
+		}
 		hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4);
 		break;
 	case UDP_V6_FLOW:
-		flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
-		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
-			hena |=
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
-			  BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
-
+		set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_UDP, flow_pctypes);
+		if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+			set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP,
+				flow_pctypes);
+			set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP,
+				flow_pctypes);
+		}
 		hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6);
 		break;
 	case AH_ESP_V4_FLOW:
@@ -3477,17 +3544,20 @@
 		return -EINVAL;
 	}
 
-	if (flow_pctype) {
-		i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0,
-					       flow_pctype)) |
-			((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1,
-					       flow_pctype)) << 32);
-		i_set = i40e_get_rss_hash_bits(nfc, i_setc);
-		i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_pctype),
-				  (u32)i_set);
-		i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_pctype),
-				  (u32)(i_set >> 32));
-		hena |= BIT_ULL(flow_pctype);
+	if (bitmap_weight(flow_pctypes, FLOW_PCTYPES_SIZE)) {
+		u8 flow_id;
+
+		for_each_set_bit(flow_id, flow_pctypes, FLOW_PCTYPES_SIZE) {
+			i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id)) |
+				 ((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id)) << 32);
+			i_set = i40e_get_rss_hash_bits(&pf->hw, nfc, i_setc);
+
+			i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_id),
+					  (u32)i_set);
+			i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_id),
+					  (u32)(i_set >> 32));
+			hena |= BIT_ULL(flow_id);
+		}
 	}
 
 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
@@ -4163,11 +4233,7 @@
 			return -EOPNOTSUPP;
 
 		/* First 4 bytes of L4 header */
-		if (usr_ip4_spec->l4_4_bytes == htonl(0xFFFFFFFF))
-			new_mask |= I40E_L4_SRC_MASK | I40E_L4_DST_MASK;
-		else if (!usr_ip4_spec->l4_4_bytes)
-			new_mask &= ~(I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
-		else
+		if (usr_ip4_spec->l4_4_bytes)
 			return -EOPNOTSUPP;
 
 		/* Filtering on Type of Service is not supported. */
@@ -4874,7 +4940,7 @@
 	enum i40e_admin_queue_err adq_err;
 	struct i40e_vsi *vsi = np->vsi;
 	struct i40e_pf *pf = vsi->back;
-	bool is_reset_needed;
+	u32 reset_needed = 0;
 	i40e_status status;
 	u32 i, j;
 
@@ -4919,9 +4985,11 @@
 flags_complete:
 	changed_flags = orig_flags ^ new_flags;
 
-	is_reset_needed = !!(changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
-		I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED |
-		I40E_FLAG_DISABLE_FW_LLDP));
+	if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP)
+		reset_needed = I40E_PF_RESET_AND_REBUILD_FLAG;
+	if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
+	    I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED))
+		reset_needed = BIT(__I40E_PF_RESET_REQUESTED);
 
 	/* Before we finalize any flag changes, we need to perform some
 	 * checks to ensure that the changes are supported and safe.
@@ -5038,12 +5106,16 @@
 				case I40E_AQ_RC_EEXIST:
 					dev_warn(&pf->pdev->dev,
 						 "FW LLDP agent is already running\n");
-					is_reset_needed = false;
+					reset_needed = 0;
 					break;
 				case I40E_AQ_RC_EPERM:
 					dev_warn(&pf->pdev->dev,
 						 "Device configuration forbids SW from starting the LLDP agent.\n");
 					return -EINVAL;
+				case I40E_AQ_RC_EAGAIN:
+					dev_warn(&pf->pdev->dev,
+						 "Stop FW LLDP agent command is still being processed, please try again in a second.\n");
+					return -EBUSY;
 				default:
 					dev_warn(&pf->pdev->dev,
 						 "Starting FW LLDP agent failed: error: %s, %s\n",
@@ -5067,8 +5139,8 @@
 	/* Issue reset to cause things to take effect, as additional bits
 	 * are added we will need to create a mask of bits requiring reset
 	 */
-	if (is_reset_needed)
-		i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED), true);
+	if (reset_needed)
+		i40e_do_reset(pf, reset_needed, true);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -44,6 +44,8 @@
 static void i40e_determine_queue_usage(struct i40e_pf *pf);
 static int i40e_setup_pf_filter_control(struct i40e_pf *pf);
 static void i40e_prep_for_reset(struct i40e_pf *pf, bool lock_acquired);
+static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit,
+				   bool lock_acquired);
 static int i40e_reset(struct i40e_pf *pf);
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);
 static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf);
@@ -105,6 +107,30 @@
 
 static struct workqueue_struct *i40e_wq;
 
+static void netdev_hw_addr_refcnt(struct i40e_mac_filter *f,
+				  struct net_device *netdev, int delta)
+{
+	struct netdev_hw_addr_list *ha_list;
+	struct netdev_hw_addr *ha;
+
+	if (!f || !netdev)
+		return;
+
+	if (is_unicast_ether_addr(f->macaddr) || is_link_local_ether_addr(f->macaddr))
+		ha_list = &netdev->uc;
+	else
+		ha_list = &netdev->mc;
+
+	netdev_hw_addr_list_for_each(ha, ha_list) {
+		if (ether_addr_equal(ha->addr, f->macaddr)) {
+			ha->refcount += delta;
+			if (ha->refcount <= 0)
+				ha->refcount = 1;
+			break;
+		}
+	}
+}
+
 /**
  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
  * @hw:   pointer to the HW structure
@@ -184,10 +210,6 @@
  * @id: an owner id to stick on the items assigned
  *
  * Returns the base item index of the lump, or negative for error
- *
- * The search_hint trick and lack of advanced fit-finding only work
- * because we're highly likely to have all the same size lump requests.
- * Linear search time and any fragmentation should be minimal.
  **/
 static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
 			 u16 needed, u16 id)
@@ -202,8 +224,21 @@
 		return -EINVAL;
 	}
 
-	/* start the linear search with an imperfect hint */
-	i = pile->search_hint;
+	/* Allocate last queue in the pile for FDIR VSI queue
+	 * so it doesn't fragment the qp_pile
+	 */
+	if (pile == pf->qp_pile && pf->vsi[id]->type == I40E_VSI_FDIR) {
+		if (pile->list[pile->num_entries - 1] & I40E_PILE_VALID_BIT) {
+			dev_err(&pf->pdev->dev,
+				"Cannot allocate queue %d for I40E_VSI_FDIR\n",
+				pile->num_entries - 1);
+			return -ENOMEM;
+		}
+		pile->list[pile->num_entries - 1] = id | I40E_PILE_VALID_BIT;
+		return pile->num_entries - 1;
+	}
+
+	i = 0;
 	while (i < pile->num_entries) {
 		/* skip already allocated entries */
 		if (pile->list[i] & I40E_PILE_VALID_BIT) {
@@ -222,7 +257,6 @@
 			for (j = 0; j < needed; j++)
 				pile->list[i+j] = id | I40E_PILE_VALID_BIT;
 			ret = i;
-			pile->search_hint = i + j;
 			break;
 		}
 
@@ -245,7 +279,7 @@
 {
 	int valid_id = (id | I40E_PILE_VALID_BIT);
 	int count = 0;
-	int i;
+	u16 i;
 
 	if (!pile || index >= pile->num_entries)
 		return -EINVAL;
@@ -257,8 +291,6 @@
 		count++;
 	}
 
-	if (count && index < pile->search_hint)
-		pile->search_hint = index;
 
 	return count;
 }
@@ -383,7 +415,9 @@
 		set_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state);
 		break;
 	default:
-		netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
+		netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in non-recoverable state.\n");
+		set_bit(__I40E_DOWN_REQUESTED, pf->state);
+		set_bit(__I40E_VSI_DOWN_REQUESTED, vsi->state);
 		break;
 	}
 
@@ -458,11 +492,15 @@
 		i40e_get_netdev_stats_struct_tx(ring, stats);
 
 		if (i40e_enabled_xdp_vsi(vsi)) {
-			ring++;
+			ring = READ_ONCE(vsi->xdp_rings[i]);
+			if (!ring)
+				continue;
 			i40e_get_netdev_stats_struct_tx(ring, stats);
 		}
 
-		ring++;
+		ring = READ_ONCE(vsi->rx_rings[i]);
+		if (!ring)
+			continue;
 		do {
 			start   = u64_stats_fetch_begin_irq(&ring->syncp);
 			packets = ring->stats.packets;
@@ -774,9 +812,9 @@
 	struct rtnl_link_stats64 *ns;   /* netdev stats */
 	struct i40e_eth_stats *oes;
 	struct i40e_eth_stats *es;     /* device's eth stats */
-	u32 tx_restart, tx_busy;
+	u64 tx_restart, tx_busy;
 	struct i40e_ring *p;
-	u32 rx_page, rx_buf;
+	u64 rx_page, rx_buf;
 	u64 bytes, packets;
 	unsigned int start;
 	u64 tx_linearize;
@@ -806,6 +844,8 @@
 	for (q = 0; q < vsi->num_queue_pairs; q++) {
 		/* locate Tx ring */
 		p = READ_ONCE(vsi->tx_rings[q]);
+		if (!p)
+			continue;
 
 		do {
 			start = u64_stats_fetch_begin_irq(&p->syncp);
@@ -819,8 +859,11 @@
 		tx_linearize += p->tx_stats.tx_linearize;
 		tx_force_wb += p->tx_stats.tx_force_wb;
 
-		/* Rx queue is part of the same block as Tx queue */
-		p = &p[1];
+		/* locate Rx ring */
+		p = READ_ONCE(vsi->rx_rings[q]);
+		if (!p)
+			continue;
+
 		do {
 			start = u64_stats_fetch_begin_irq(&p->syncp);
 			packets = p->stats.packets;
@@ -1765,6 +1808,7 @@
 				     bool is_add)
 {
 	struct i40e_pf *pf = vsi->back;
+	u16 num_tc_qps = 0;
 	u16 sections = 0;
 	u8 netdev_tc = 0;
 	u16 numtc = 1;
@@ -1772,13 +1816,37 @@
 	u8 offset;
 	u16 qmap;
 	int i;
-	u16 num_tc_qps = 0;
 
 	sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
 	offset = 0;
+	/* zero out queue mapping, it will get updated on the end of the function */
+	memset(ctxt->info.queue_mapping, 0, sizeof(ctxt->info.queue_mapping));
+
+	if (vsi->type == I40E_VSI_MAIN) {
+		/* This code helps add more queue to the VSI if we have
+		 * more cores than RSS can support, the higher cores will
+		 * be served by ATR or other filters. Furthermore, the
+		 * non-zero req_queue_pairs says that user requested a new
+		 * queue count via ethtool's set_channels, so use this
+		 * value for queues distribution across traffic classes
+		 * We need at least one queue pair for the interface
+		 * to be usable as we see in else statement.
+		 */
+		if (vsi->req_queue_pairs > 0)
+			vsi->num_queue_pairs = vsi->req_queue_pairs;
+		else if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+			vsi->num_queue_pairs = pf->num_lan_msix;
+		else
+			vsi->num_queue_pairs = 1;
+	}
 
 	/* Number of queues per enabled TC */
-	num_tc_qps = vsi->alloc_queue_pairs;
+	if (vsi->type == I40E_VSI_MAIN ||
+	    (vsi->type == I40E_VSI_SRIOV && vsi->num_queue_pairs != 0))
+		num_tc_qps = vsi->num_queue_pairs;
+	else
+		num_tc_qps = vsi->alloc_queue_pairs;
+
 	if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
 		/* Find numtc from enabled TC bitmap */
 		for (i = 0, numtc = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
@@ -1856,15 +1924,11 @@
 		}
 		ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
 	}
-
-	/* Set actual Tx/Rx queue pairs */
-	vsi->num_queue_pairs = offset;
-	if ((vsi->type == I40E_VSI_MAIN) && (numtc == 1)) {
-		if (vsi->req_queue_pairs > 0)
-			vsi->num_queue_pairs = vsi->req_queue_pairs;
-		else if (pf->flags & I40E_FLAG_MSIX_ENABLED)
-			vsi->num_queue_pairs = pf->num_lan_msix;
-	}
+	/* Do not change previously set num_queue_pairs for PFs and VFs*/
+	if ((vsi->type == I40E_VSI_MAIN && numtc != 1) ||
+	    (vsi->type == I40E_VSI_SRIOV && vsi->num_queue_pairs == 0) ||
+	    (vsi->type != I40E_VSI_MAIN && vsi->type != I40E_VSI_SRIOV))
+		vsi->num_queue_pairs = offset;
 
 	/* Scheduler section valid can only be set for ADD VSI */
 	if (is_add) {
@@ -1994,6 +2058,7 @@
 	hlist_for_each_entry_safe(new, h, from, hlist) {
 		/* We can simply free the wrapper structure */
 		hlist_del(&new->hlist);
+		netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
 		kfree(new);
 	}
 }
@@ -2341,6 +2406,10 @@
 						       &tmp_add_list,
 						       &tmp_del_list,
 						       vlan_filters);
+
+		hlist_for_each_entry(new, &tmp_add_list, hlist)
+			netdev_hw_addr_refcnt(new->f, vsi->netdev, 1);
+
 		if (retval)
 			goto err_no_memory_locked;
 
@@ -2473,6 +2542,7 @@
 			if (new->f->state == I40E_FILTER_NEW)
 				new->f->state = new->state;
 			hlist_del(&new->hlist);
+			netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
 			kfree(new);
 		}
 		spin_unlock_bh(&vsi->mac_filter_hash_lock);
@@ -2536,8 +2606,7 @@
 				 i40e_stat_str(hw, aq_ret),
 				 i40e_aq_str(hw, hw->aq.asq_last_status));
 		} else {
-			dev_info(&pf->pdev->dev, "%s is %s allmulti mode.\n",
-				 vsi->netdev->name,
+			dev_info(&pf->pdev->dev, "%s allmulti mode.\n",
 				 cur_multipromisc ? "entering" : "leaving");
 		}
 	}
@@ -2592,14 +2661,15 @@
 		return;
 	if (!test_and_clear_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state))
 		return;
-	if (test_and_set_bit(__I40E_VF_DISABLE, pf->state)) {
+	if (test_bit(__I40E_VF_DISABLE, pf->state)) {
 		set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state);
 		return;
 	}
 
 	for (v = 0; v < pf->num_alloc_vsi; v++) {
 		if (pf->vsi[v] &&
-		    (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED)) {
+		    (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED) &&
+		    !test_bit(__I40E_VSI_RELEASING, pf->vsi[v]->state)) {
 			int ret = i40e_sync_vsi_filters(pf->vsi[v]);
 
 			if (ret) {
@@ -2610,7 +2680,6 @@
 			}
 		}
 	}
-	clear_bit(__I40E_VF_DISABLE, pf->state);
 }
 
 /**
@@ -2639,7 +2708,7 @@
 	struct i40e_pf *pf = vsi->back;
 
 	if (i40e_enabled_xdp_vsi(vsi)) {
-		int frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+		int frame_size = new_mtu + I40E_PACKET_HDR_PAD;
 
 		if (frame_size > i40e_max_xdp_frame_size(vsi))
 			return -EINVAL;
@@ -3534,14 +3603,14 @@
 		q_vector->rx.target_itr =
 			ITR_TO_REG(vsi->rx_rings[i]->itr_setting);
 		wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
-		     q_vector->rx.target_itr);
+		     q_vector->rx.target_itr >> 1);
 		q_vector->rx.current_itr = q_vector->rx.target_itr;
 
 		q_vector->tx.next_update = jiffies + 1;
 		q_vector->tx.target_itr =
 			ITR_TO_REG(vsi->tx_rings[i]->itr_setting);
 		wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
-		     q_vector->tx.target_itr);
+		     q_vector->tx.target_itr >> 1);
 		q_vector->tx.current_itr = q_vector->tx.target_itr;
 
 		wr32(hw, I40E_PFINT_RATEN(vector - 1),
@@ -3646,11 +3715,11 @@
 	/* set the ITR configuration */
 	q_vector->rx.next_update = jiffies + 1;
 	q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[0]->itr_setting);
-	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr);
+	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr >> 1);
 	q_vector->rx.current_itr = q_vector->rx.target_itr;
 	q_vector->tx.next_update = jiffies + 1;
 	q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[0]->itr_setting);
-	wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr);
+	wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr >> 1);
 	q_vector->tx.current_itr = q_vector->tx.target_itr;
 
 	i40e_enable_misc_int_causes(pf);
@@ -3979,8 +4048,16 @@
 	}
 
 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
-		ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
-		set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
+		/* disable any further VFLR event notifications */
+		if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) {
+			u32 reg = rd32(hw, I40E_PFINT_ICR0_ENA);
+
+			reg &= ~I40E_PFINT_ICR0_VFLR_MASK;
+			wr32(hw, I40E_PFINT_ICR0_ENA, reg);
+		} else {
+			ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
+			set_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
+		}
 	}
 
 	if (icr0 & I40E_PFINT_ICR0_GRST_MASK) {
@@ -4386,11 +4463,10 @@
 }
 
 /**
- * i40e_vsi_control_tx - Start or stop a VSI's rings
+ * i40e_vsi_enable_tx - Start a VSI's rings
  * @vsi: the VSI being configured
- * @enable: start or stop the rings
  **/
-static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
+static int i40e_vsi_enable_tx(struct i40e_vsi *vsi)
 {
 	struct i40e_pf *pf = vsi->back;
 	int i, pf_q, ret = 0;
@@ -4399,7 +4475,7 @@
 	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
 		ret = i40e_control_wait_tx_q(vsi->seid, pf,
 					     pf_q,
-					     false /*is xdp*/, enable);
+					     false /*is xdp*/, true);
 		if (ret)
 			break;
 
@@ -4408,7 +4484,7 @@
 
 		ret = i40e_control_wait_tx_q(vsi->seid, pf,
 					     pf_q + vsi->alloc_queue_pairs,
-					     true /*is xdp*/, enable);
+					     true /*is xdp*/, true);
 		if (ret)
 			break;
 	}
@@ -4506,32 +4582,25 @@
 }
 
 /**
- * i40e_vsi_control_rx - Start or stop a VSI's rings
+ * i40e_vsi_enable_rx - Start a VSI's rings
  * @vsi: the VSI being configured
- * @enable: start or stop the rings
  **/
-static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
+static int i40e_vsi_enable_rx(struct i40e_vsi *vsi)
 {
 	struct i40e_pf *pf = vsi->back;
 	int i, pf_q, ret = 0;
 
 	pf_q = vsi->base_queue;
 	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-		ret = i40e_control_wait_rx_q(pf, pf_q, enable);
+		ret = i40e_control_wait_rx_q(pf, pf_q, true);
 		if (ret) {
 			dev_info(&pf->pdev->dev,
-				 "VSI seid %d Rx ring %d %sable timeout\n",
-				 vsi->seid, pf_q, (enable ? "en" : "dis"));
+				 "VSI seid %d Rx ring %d enable timeout\n",
+				 vsi->seid, pf_q);
 			break;
 		}
 	}
 
-	/* Due to HW errata, on Rx disable only, the register can indicate done
-	 * before it really is. Needs 50ms to be sure
-	 */
-	if (!enable)
-		mdelay(50);
-
 	return ret;
 }
 
@@ -4544,29 +4613,47 @@
 	int ret = 0;
 
 	/* do rx first for enable and last for disable */
-	ret = i40e_vsi_control_rx(vsi, true);
+	ret = i40e_vsi_enable_rx(vsi);
 	if (ret)
 		return ret;
-	ret = i40e_vsi_control_tx(vsi, true);
+	ret = i40e_vsi_enable_tx(vsi);
 
 	return ret;
 }
 
+#define I40E_DISABLE_TX_GAP_MSEC	50
+
 /**
  * i40e_vsi_stop_rings - Stop a VSI's rings
  * @vsi: the VSI being configured
  **/
 void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
 {
+	struct i40e_pf *pf = vsi->back;
+	int pf_q, err, q_end;
+
 	/* When port TX is suspended, don't wait */
 	if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
 		return i40e_vsi_stop_rings_no_wait(vsi);
 
-	/* do rx first for enable and last for disable
-	 * Ignore return value, we need to shutdown whatever we can
-	 */
-	i40e_vsi_control_tx(vsi, false);
-	i40e_vsi_control_rx(vsi, false);
+	q_end = vsi->base_queue + vsi->num_queue_pairs;
+	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+		i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
+
+	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
+		err = i40e_control_wait_rx_q(pf, pf_q, false);
+		if (err)
+			dev_info(&pf->pdev->dev,
+				 "VSI seid %d Rx ring %d dissable timeout\n",
+				 vsi->seid, pf_q);
+	}
+
+	msleep(I40E_DISABLE_TX_GAP_MSEC);
+	pf_q = vsi->base_queue;
+	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+		wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);
+
+	i40e_vsi_wait_queues_disabled(vsi);
 }
 
 /**
@@ -4790,7 +4877,8 @@
 {
 	int i;
 
-	i40e_free_misc_vector(pf);
+	if (test_bit(__I40E_MISC_IRQ_REQUESTED, pf->state))
+		i40e_free_misc_vector(pf);
 
 	i40e_put_lump(pf->irq_pile, pf->iwarp_base_vector,
 		      I40E_IWARP_IRQ_PILE_ID);
@@ -4977,7 +5065,7 @@
 {
 	int v, ret = 0;
 
-	for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+	for (v = 0; v < pf->num_alloc_vsi; v++) {
 		if (pf->vsi[v]) {
 			ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
 			if (ret)
@@ -5344,6 +5432,58 @@
 }
 
 /**
+ * i40e_update_adq_vsi_queues - update queue mapping for ADq VSI
+ * @vsi: the VSI being reconfigured
+ * @vsi_offset: offset from main VF VSI
+ */
+int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset)
+{
+	struct i40e_vsi_context ctxt = {};
+	struct i40e_pf *pf;
+	struct i40e_hw *hw;
+	int ret;
+
+	if (!vsi)
+		return I40E_ERR_PARAM;
+	pf = vsi->back;
+	hw = &pf->hw;
+
+	ctxt.seid = vsi->seid;
+	ctxt.pf_num = hw->pf_id;
+	ctxt.vf_num = vsi->vf_id + hw->func_caps.vf_base_id + vsi_offset;
+	ctxt.uplink_seid = vsi->uplink_seid;
+	ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
+	ctxt.flags = I40E_AQ_VSI_TYPE_VF;
+	ctxt.info = vsi->info;
+
+	i40e_vsi_setup_queue_map(vsi, &ctxt, vsi->tc_config.enabled_tc,
+				 false);
+	if (vsi->reconfig_rss) {
+		vsi->rss_size = min_t(int, pf->alloc_rss_size,
+				      vsi->num_queue_pairs);
+		ret = i40e_vsi_config_rss(vsi);
+		if (ret) {
+			dev_info(&pf->pdev->dev, "Failed to reconfig rss for num_queues\n");
+			return ret;
+		}
+		vsi->reconfig_rss = false;
+	}
+
+	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+	if (ret) {
+		dev_info(&pf->pdev->dev, "Update vsi config failed, err %s aq_err %s\n",
+			 i40e_stat_str(hw, ret),
+			 i40e_aq_str(hw, hw->aq.asq_last_status));
+		return ret;
+	}
+	/* update the local VSI info with updated queue map */
+	i40e_vsi_update_queue_map(vsi, &ctxt);
+	vsi->info.valid_sections = 0;
+
+	return ret;
+}
+
+/**
  * i40e_vsi_config_tc - Configure VSI Tx Scheduler for given TC map
  * @vsi: VSI to be configured
  * @enabled_tc: TC bitmap
@@ -5505,6 +5645,26 @@
 }
 
 /**
+ * i40e_bw_bytes_to_mbits - Convert max_tx_rate from bytes to mbits
+ * @vsi: Pointer to vsi structure
+ * @max_tx_rate: max TX rate in bytes to be converted into Mbits
+ *
+ * Helper function to convert units before send to set BW limit
+ **/
+static u64 i40e_bw_bytes_to_mbits(struct i40e_vsi *vsi, u64 max_tx_rate)
+{
+	if (max_tx_rate < I40E_BW_MBPS_DIVISOR) {
+		dev_warn(&vsi->back->pdev->dev,
+			 "Setting max tx rate to minimum usable value of 50Mbps.\n");
+		max_tx_rate = I40E_BW_CREDIT_DIVISOR;
+	} else {
+		do_div(max_tx_rate, I40E_BW_MBPS_DIVISOR);
+	}
+
+	return max_tx_rate;
+}
+
+/**
  * i40e_set_bw_limit - setup BW limit for Tx traffic based on max_tx_rate
  * @vsi: VSI to be configured
  * @seid: seid of the channel/VSI
@@ -5526,10 +5686,10 @@
 			max_tx_rate, seid);
 		return -EINVAL;
 	}
-	if (max_tx_rate && max_tx_rate < 50) {
+	if (max_tx_rate && max_tx_rate < I40E_BW_CREDIT_DIVISOR) {
 		dev_warn(&pf->pdev->dev,
 			 "Setting max tx rate to minimum usable value of 50Mbps.\n");
-		max_tx_rate = 50;
+		max_tx_rate = I40E_BW_CREDIT_DIVISOR;
 	}
 
 	/* Tx rate credits are in values of 50Mbps, 0 is disabled */
@@ -5634,24 +5794,6 @@
 }
 
 /**
- * i40e_is_any_channel - channel exist or not
- * @vsi: ptr to VSI to which channels are associated with
- *
- * Returns true or false if channel(s) exist for associated VSI or not
- **/
-static bool i40e_is_any_channel(struct i40e_vsi *vsi)
-{
-	struct i40e_channel *ch, *ch_tmp;
-
-	list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
-		if (ch->initialized)
-			return true;
-	}
-
-	return false;
-}
-
-/**
  * i40e_get_max_queues_for_channel
  * @vsi: ptr to VSI to which channels are associated with
  *
@@ -6158,26 +6300,15 @@
 	/* By default we are in VEPA mode, if this is the first VF/VMDq
 	 * VSI to be added switch to VEB mode.
 	 */
-	if ((!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) ||
-	    (!i40e_is_any_channel(vsi))) {
-		if (!is_power_of_2(vsi->tc_config.tc_info[0].qcount)) {
-			dev_dbg(&pf->pdev->dev,
-				"Failed to create channel. Override queues (%u) not power of 2\n",
-				vsi->tc_config.tc_info[0].qcount);
-			return -EINVAL;
-		}
 
-		if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
-			pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+	if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+		pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
 
-			if (vsi->type == I40E_VSI_MAIN) {
-				if (pf->flags & I40E_FLAG_TC_MQPRIO)
-					i40e_do_reset(pf, I40E_PF_RESET_FLAG,
-						      true);
-				else
-					i40e_do_reset_safe(pf,
-							   I40E_PF_RESET_FLAG);
-			}
+		if (vsi->type == I40E_VSI_MAIN) {
+			if (pf->flags & I40E_FLAG_TC_MQPRIO)
+				i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
+			else
+				i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
 		}
 		/* now onwards for main VSI, number of queues will be value
 		 * of TC0's queue count
@@ -6804,8 +6935,8 @@
 	for (i = 0; i < vsi->num_queue_pairs; i++) {
 		i40e_clean_tx_ring(vsi->tx_rings[i]);
 		if (i40e_enabled_xdp_vsi(vsi)) {
-			/* Make sure that in-progress ndo_xdp_xmit
-			 * calls are completed.
+			/* Make sure that in-progress ndo_xdp_xmit and
+			 * ndo_xsk_wakeup calls are completed.
 			 */
 			synchronize_rcu();
 			i40e_clean_tx_ring(vsi->xdp_rings[i]);
@@ -6851,6 +6982,8 @@
 	}
 	if (vsi->num_queue_pairs <
 	    (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
+		dev_err(&vsi->back->pdev->dev,
+			"Failed to create traffic channel, insufficient number of queues.\n");
 		return -EINVAL;
 	}
 	if (sum_max_rate > i40e_get_link_speed(vsi)) {
@@ -7019,42 +7152,43 @@
 static int i40e_fwd_ring_up(struct i40e_vsi *vsi, struct net_device *vdev,
 			    struct i40e_fwd_adapter *fwd)
 {
+	struct i40e_channel *ch = NULL, *ch_tmp, *iter;
 	int ret = 0, num_tc = 1,  i, aq_err;
-	struct i40e_channel *ch, *ch_tmp;
 	struct i40e_pf *pf = vsi->back;
 	struct i40e_hw *hw = &pf->hw;
 
-	if (list_empty(&vsi->macvlan_list))
-		return -EINVAL;
-
 	/* Go through the list and find an available channel */
-	list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {
-		if (!i40e_is_channel_macvlan(ch)) {
-			ch->fwd = fwd;
+	list_for_each_entry_safe(iter, ch_tmp, &vsi->macvlan_list, list) {
+		if (!i40e_is_channel_macvlan(iter)) {
+			iter->fwd = fwd;
 			/* record configuration for macvlan interface in vdev */
 			for (i = 0; i < num_tc; i++)
 				netdev_bind_sb_channel_queue(vsi->netdev, vdev,
 							     i,
-							     ch->num_queue_pairs,
-							     ch->base_queue);
-			for (i = 0; i < ch->num_queue_pairs; i++) {
+							     iter->num_queue_pairs,
+							     iter->base_queue);
+			for (i = 0; i < iter->num_queue_pairs; i++) {
 				struct i40e_ring *tx_ring, *rx_ring;
 				u16 pf_q;
 
-				pf_q = ch->base_queue + i;
+				pf_q = iter->base_queue + i;
 
 				/* Get to TX ring ptr */
 				tx_ring = vsi->tx_rings[pf_q];
-				tx_ring->ch = ch;
+				tx_ring->ch = iter;
 
 				/* Get the RX ring ptr */
 				rx_ring = vsi->rx_rings[pf_q];
-				rx_ring->ch = ch;
+				rx_ring->ch = iter;
 			}
+			ch = iter;
 			break;
 		}
 	}
 
+	if (!ch)
+		return -EINVAL;
+
 	/* Guarantee all rings are updated before we update the
 	 * MAC address filter.
 	 */
@@ -7168,6 +7302,7 @@
 		ch->num_queue_pairs = qcnt;
 		if (!i40e_setup_channel(pf, vsi, ch)) {
 			ret = -EINVAL;
+			kfree(ch);
 			goto err_free;
 		}
 		ch->parent_vsi = vsi;
@@ -7466,17 +7601,25 @@
 			    vsi->seid);
 		need_reset = true;
 		goto exit;
-	} else {
-		dev_info(&vsi->back->pdev->dev,
-			 "Setup channel (id:%u) utilizing num_queues %d\n",
-			 vsi->seid, vsi->tc_config.tc_info[0].qcount);
+	} else if (enabled_tc &&
+		   (!is_power_of_2(vsi->tc_config.tc_info[0].qcount))) {
+		netdev_info(netdev,
+			    "Failed to create channel. Override queues (%u) not power of 2\n",
+			    vsi->tc_config.tc_info[0].qcount);
+		ret = -EINVAL;
+		need_reset = true;
+		goto exit;
 	}
 
+	dev_info(&vsi->back->pdev->dev,
+		 "Setup channel (id:%u) utilizing num_queues %d\n",
+		 vsi->seid, vsi->tc_config.tc_info[0].qcount);
+
 	if (pf->flags & I40E_FLAG_TC_MQPRIO) {
 		if (vsi->mqprio_qopt.max_rate[0]) {
-			u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0];
+			u64 max_tx_rate = i40e_bw_bytes_to_mbits(vsi,
+						  vsi->mqprio_qopt.max_rate[0]);
 
-			do_div(max_tx_rate, I40E_BW_MBPS_DIVISOR);
 			ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
 			if (!ret) {
 				u64 credits = max_tx_rate;
@@ -7592,6 +7735,8 @@
 	if (filter->flags >= ARRAY_SIZE(flag_table))
 		return I40E_ERR_CONFIG;
 
+	memset(&cld_filter, 0, sizeof(cld_filter));
+
 	/* copy element needed to add cloud filter from filter */
 	i40e_set_cld_element(filter, &cld_filter);
 
@@ -7655,10 +7800,13 @@
 		return -EOPNOTSUPP;
 
 	/* adding filter using src_port/src_ip is not supported at this stage */
-	if (filter->src_port || filter->src_ipv4 ||
+	if (filter->src_port ||
+	    (filter->src_ipv4 && filter->n_proto != ETH_P_IPV6) ||
 	    !ipv6_addr_any(&filter->ip.v6.src_ip6))
 		return -EOPNOTSUPP;
 
+	memset(&cld_filter, 0, sizeof(cld_filter));
+
 	/* copy element needed to add cloud filter from filter */
 	i40e_set_cld_element(filter, &cld_filter.element);
 
@@ -7682,7 +7830,7 @@
 			cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);
 		}
 
-	} else if (filter->dst_ipv4 ||
+	} else if ((filter->dst_ipv4 && filter->n_proto != ETH_P_IPV6) ||
 		   !ipv6_addr_any(&filter->ip.v6.dst_ip6)) {
 		cld_filter.element.flags =
 				cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);
@@ -7992,6 +8140,11 @@
 		return -EOPNOTSUPP;
 	}
 
+	if (!tc) {
+		dev_err(&pf->pdev->dev, "Unable to add filter because of invalid destination");
+		return -EINVAL;
+	}
+
 	if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
 	    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))
 		return -EBUSY;
@@ -8031,9 +8184,8 @@
 		err = i40e_add_del_cloud_filter(vsi, filter, true);
 
 	if (err) {
-		dev_err(&pf->pdev->dev,
-			"Failed to add cloud filter, err %s\n",
-			i40e_stat_str(&pf->hw, err));
+		dev_err(&pf->pdev->dev, "Failed to add cloud filter, err %d\n",
+			err);
 		goto err;
 	}
 
@@ -8219,6 +8371,27 @@
 }
 
 /**
+ * i40e_netif_set_realnum_tx_rx_queues - Update number of tx/rx queues
+ * @vsi: vsi structure
+ *
+ * This updates netdev's number of tx/rx queues
+ *
+ * Returns status of setting tx/rx queues
+ **/
+static int i40e_netif_set_realnum_tx_rx_queues(struct i40e_vsi *vsi)
+{
+	int ret;
+
+	ret = netif_set_real_num_rx_queues(vsi->netdev,
+					   vsi->num_queue_pairs);
+	if (ret)
+		return ret;
+
+	return netif_set_real_num_tx_queues(vsi->netdev,
+					    vsi->num_queue_pairs);
+}
+
+/**
  * i40e_vsi_open -
  * @vsi: the VSI to open
  *
@@ -8254,13 +8427,7 @@
 			goto err_setup_rx;
 
 		/* Notify the stack of the actual queue counts. */
-		err = netif_set_real_num_tx_queues(vsi->netdev,
-						   vsi->num_queue_pairs);
-		if (err)
-			goto err_set_queues;
-
-		err = netif_set_real_num_rx_queues(vsi->netdev,
-						   vsi->num_queue_pairs);
+		err = i40e_netif_set_realnum_tx_rx_queues(vsi);
 		if (err)
 			goto err_set_queues;
 
@@ -8269,6 +8436,8 @@
 			 dev_driver_string(&pf->pdev->dev),
 			 dev_name(&pf->pdev->dev));
 		err = i40e_vsi_request_irq(vsi, int_name);
+		if (err)
+			goto err_setup_rx;
 
 	} else {
 		err = -EINVAL;
@@ -8461,6 +8630,13 @@
 		dev_dbg(&pf->pdev->dev, "PFR requested\n");
 		i40e_handle_reset_warning(pf, lock_acquired);
 
+	} else if (reset_flags & I40E_PF_RESET_AND_REBUILD_FLAG) {
+		/* Request a PF Reset
+		 *
+		 * Resets PF and reinitializes PFs VSI.
+		 */
+		i40e_prep_for_reset(pf, lock_acquired);
+		i40e_reset_and_rebuild(pf, true, lock_acquired);
 		dev_info(&pf->pdev->dev,
 			 pf->flags & I40E_FLAG_DISABLE_FW_LLDP ?
 			 "FW LLDP is disabled\n" :
@@ -9572,7 +9748,7 @@
 		if (pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) {
 			/* retry with a larger buffer */
 			buf_len = data_size;
-		} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
+		} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK || err) {
 			dev_info(&pf->pdev->dev,
 				 "capability discovery failed, err %s aq_err %s\n",
 				 i40e_stat_str(&pf->hw, err),
@@ -9784,6 +9960,21 @@
 }
 
 /**
+ * i40e_clean_xps_state - clean xps state for every tx_ring
+ * @vsi: ptr to the VSI
+ **/
+static void i40e_clean_xps_state(struct i40e_vsi *vsi)
+{
+	int i;
+
+	if (vsi->tx_rings)
+		for (i = 0; i < vsi->num_queue_pairs; i++)
+			if (vsi->tx_rings[i])
+				clear_bit(__I40E_TX_XPS_INIT_DONE,
+					  vsi->tx_rings[i]->state);
+}
+
+/**
  * i40e_prep_for_reset - prep for the core to reset
  * @pf: board private structure
  * @lock_acquired: indicates whether or not the lock has been acquired
@@ -9814,8 +10005,10 @@
 		rtnl_unlock();
 
 	for (v = 0; v < pf->num_alloc_vsi; v++) {
-		if (pf->vsi[v])
+		if (pf->vsi[v]) {
+			i40e_clean_xps_state(pf->vsi[v]);
 			pf->vsi[v]->seid = 0;
+		}
 	}
 
 	i40e_shutdown_adminq(&pf->hw);
@@ -9924,22 +10117,19 @@
  **/
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
 {
-	int old_recovery_mode_bit = test_bit(__I40E_RECOVERY_MODE, pf->state);
+	const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf);
 	struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
 	struct i40e_hw *hw = &pf->hw;
-	u8 set_fc_aq_fail = 0;
 	i40e_status ret;
 	u32 val;
 	int v;
 
 	if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-	    i40e_check_recovery_mode(pf)) {
+	    is_recovery_mode_reported)
 		i40e_set_ethtool_ops(pf->vsi[pf->lan_vsi]->netdev);
-	}
 
 	if (test_bit(__I40E_DOWN, pf->state) &&
-	    !test_bit(__I40E_RECOVERY_MODE, pf->state) &&
-	    !old_recovery_mode_bit)
+	    !test_bit(__I40E_RECOVERY_MODE, pf->state))
 		goto clear_recovery;
 	dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
@@ -9953,15 +10143,9 @@
 	}
 	i40e_get_oem_version(&pf->hw);
 
-	if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-	    ((hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver <= 33) ||
-	     hw->aq.fw_maj_ver < 4) && hw->mac.type == I40E_MAC_XL710) {
-		/* The following delay is necessary for 4.33 firmware and older
-		 * to recover after EMP reset. 200 ms should suffice but we
-		 * put here 300 ms to be sure that FW is ready to operate
-		 * after reset.
-		 */
-		mdelay(300);
+	if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) {
+		/* The following delay is necessary for firmware update. */
+		mdelay(1000);
 	}
 
 	/* re-verify the eeprom if we just had an EMP reset */
@@ -9972,13 +10156,12 @@
 	 * accordingly with regard to resources initialization
 	 * and deinitialization
 	 */
-	if (test_bit(__I40E_RECOVERY_MODE, pf->state) ||
-	    old_recovery_mode_bit) {
+	if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
 		if (i40e_get_capabilities(pf,
 					  i40e_aqc_opc_list_func_capabilities))
 			goto end_unlock;
 
-		if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+		if (is_recovery_mode_reported) {
 			/* we're staying in recovery mode so we'll reinitialize
 			 * misc vector here
 			 */
@@ -10053,13 +10236,6 @@
 			 i40e_stat_str(&pf->hw, ret),
 			 i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 
-	/* make sure our flow control settings are restored */
-	ret = i40e_set_fc(&pf->hw, &set_fc_aq_fail, true);
-	if (ret)
-		dev_dbg(&pf->pdev->dev, "setting flow control: ret = %s last_status = %s\n",
-			i40e_stat_str(&pf->hw, ret),
-			i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
-
 	/* Rebuild the VSIs and VEBs that existed before reset.
 	 * They are still in our local switch element arrays, so only
 	 * need to rebuild the switch model in the HW.
@@ -10114,10 +10290,10 @@
 	}
 
 	if (vsi->mqprio_qopt.max_rate[0]) {
-		u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0];
+		u64 max_tx_rate = i40e_bw_bytes_to_mbits(vsi,
+						  vsi->mqprio_qopt.max_rate[0]);
 		u64 credits = 0;
 
-		do_div(max_tx_rate, I40E_BW_MBPS_DIVISOR);
 		ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
 		if (ret)
 			goto end_unlock;
@@ -10166,8 +10342,11 @@
 					     pf->hw.aq.asq_last_status));
 	}
 	/* reinit the misc interrupt */
-	if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+	if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
 		ret = i40e_setup_misc_vector(pf);
+		if (ret)
+			goto end_unlock;
+	}
 
 	/* Add a filter to drop all Flow control frames from any VSI from being
 	 * transmitted. By doing so we stop a malicious VF from sending out
@@ -10815,10 +10994,10 @@
 	if (vsi->tx_rings && vsi->tx_rings[0]) {
 		for (i = 0; i < vsi->alloc_queue_pairs; i++) {
 			kfree_rcu(vsi->tx_rings[i], rcu);
-			vsi->tx_rings[i] = NULL;
-			vsi->rx_rings[i] = NULL;
+			WRITE_ONCE(vsi->tx_rings[i], NULL);
+			WRITE_ONCE(vsi->rx_rings[i], NULL);
 			if (vsi->xdp_rings)
-				vsi->xdp_rings[i] = NULL;
+				WRITE_ONCE(vsi->xdp_rings[i], NULL);
 		}
 	}
 }
@@ -10852,7 +11031,7 @@
 		if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
 			ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
 		ring->itr_setting = pf->tx_itr_default;
-		vsi->tx_rings[i] = ring++;
+		WRITE_ONCE(vsi->tx_rings[i], ring++);
 
 		if (!i40e_enabled_xdp_vsi(vsi))
 			goto setup_rx;
@@ -10870,7 +11049,7 @@
 			ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
 		set_ring_xdp(ring);
 		ring->itr_setting = pf->tx_itr_default;
-		vsi->xdp_rings[i] = ring++;
+		WRITE_ONCE(vsi->xdp_rings[i], ring++);
 
 setup_rx:
 		ring->queue_index = i;
@@ -10883,7 +11062,7 @@
 		ring->size = 0;
 		ring->dcb_tc = 0;
 		ring->itr_setting = pf->rx_itr_default;
-		vsi->rx_rings[i] = ring;
+		WRITE_ONCE(vsi->rx_rings[i], ring);
 	}
 
 	return 0;
@@ -11264,7 +11443,6 @@
 		return -ENOMEM;
 
 	pf->irq_pile->num_entries = vectors;
-	pf->irq_pile->search_hint = 0;
 
 	/* track first vector for misc interrupts, ignore return */
 	(void)i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT - 1);
@@ -11396,7 +11574,7 @@
 
 	/* associate no queues to the misc vector */
 	wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST);
-	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K);
+	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K >> 1);
 
 	i40e_flush(hw);
 
@@ -11742,6 +11920,8 @@
 	struct i40e_aqc_configure_partition_bw_data bw_data;
 	i40e_status status;
 
+	memset(&bw_data, 0, sizeof(bw_data));
+
 	/* Set the valid bit for this PF */
 	bw_data.pf_valid_bits = cpu_to_le16(BIT(pf->hw.pf_id));
 	bw_data.max_bw[pf->hw.pf_id] = pf->max_bw & I40E_ALT_BW_VALUE_MASK;
@@ -11848,6 +12028,7 @@
 {
 	int err = 0;
 	int size;
+	u16 pow;
 
 	/* Set default capability flags */
 	pf->flags = I40E_FLAG_RX_CSUM_ENABLED |
@@ -11866,6 +12047,11 @@
 	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);
+
+	/* find the next higher power-of-2 of num cpus */
+	pow = roundup_pow_of_two(num_online_cpus());
+	pf->rss_size_max = min_t(int, pf->rss_size_max, pow);
+
 	if (pf->hw.func_caps.rss) {
 		pf->flags |= I40E_FLAG_RSS_ENABLED;
 		pf->alloc_rss_size = min_t(int, pf->rss_size_max,
@@ -12007,7 +12193,6 @@
 		goto sw_init_done;
 	}
 	pf->qp_pile->num_entries = pf->hw.func_caps.num_tx_qp;
-	pf->qp_pile->search_hint = 0;
 
 	pf->tx_timeout_recovery_level = 1;
 
@@ -12359,6 +12544,8 @@
 	}
 
 	br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+	if (!br_spec)
+		return -EINVAL;
 
 	nla_for_each_nested(attr, br_spec, rem) {
 		__u16 mode;
@@ -12526,8 +12713,12 @@
 
 	old_prog = xchg(&vsi->xdp_prog, prog);
 
-	if (need_reset)
+	if (need_reset) {
+		if (!prog)
+			/* Wait until ndo_xsk_wakeup completes. */
+			synchronize_rcu();
 		i40e_reset_and_rebuild(pf, true, true);
+	}
 
 	for (i = 0; i < vsi->num_queue_pairs; i++)
 		WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
@@ -12847,6 +13038,7 @@
 	.ndo_poll_controller	= i40e_netpoll,
 #endif
 	.ndo_setup_tc		= __i40e_setup_tc,
+	.ndo_select_queue	= i40e_lan_select_queue,
 	.ndo_set_features	= i40e_set_features,
 	.ndo_set_vf_mac		= i40e_ndo_set_vf_mac,
 	.ndo_set_vf_vlan	= i40e_ndo_set_vf_port_vlan,
@@ -13280,15 +13472,15 @@
 		vsi->id = ctxt.vsi_number;
 	}
 
-	vsi->active_filters = 0;
-	clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
 	spin_lock_bh(&vsi->mac_filter_hash_lock);
+	vsi->active_filters = 0;
 	/* If macvlan filters already exist, force them to get loaded */
 	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
 		f->state = I40E_FILTER_NEW;
 		f_count++;
 	}
 	spin_unlock_bh(&vsi->mac_filter_hash_lock);
+	clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
 
 	if (f_count) {
 		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
@@ -13338,7 +13530,7 @@
 		dev_info(&pf->pdev->dev, "Can't remove PF VSI\n");
 		return -ENODEV;
 	}
-
+	set_bit(__I40E_VSI_RELEASING, vsi->state);
 	uplink_seid = vsi->uplink_seid;
 	if (vsi->type != I40E_VSI_SRIOV) {
 		if (vsi->netdev_registered) {
@@ -13670,6 +13862,9 @@
 		ret = i40e_config_netdev(vsi);
 		if (ret)
 			goto err_netdev;
+		ret = i40e_netif_set_realnum_tx_rx_queues(vsi);
+		if (ret)
+			goto err_netdev;
 		ret = register_netdev(vsi->netdev);
 		if (ret)
 			goto err_netdev;
@@ -14637,6 +14832,7 @@
 	int err;
 	int v_idx;
 
+	pci_set_drvdata(pf->pdev, pf);
 	pci_save_state(pf->pdev);
 
 	/* set up periodic task facility */
@@ -14672,12 +14868,16 @@
 	 * in order to register the netdev
 	 */
 	v_idx = i40e_vsi_mem_alloc(pf, I40E_VSI_MAIN);
-	if (v_idx < 0)
+	if (v_idx < 0) {
+		err = v_idx;
 		goto err_switch_setup;
+	}
 	pf->lan_vsi = v_idx;
 	vsi = pf->vsi[v_idx];
-	if (!vsi)
+	if (!vsi) {
+		err = -EFAULT;
 		goto err_switch_setup;
+	}
 	vsi->alloc_queue_pairs = 1;
 	err = i40e_config_netdev(vsi);
 	if (err)
@@ -14736,7 +14936,6 @@
 	int err;
 	u32 val;
 	u32 i;
-	u8 set_fc_aq_fail;
 
 	err = pci_enable_device_mem(pdev);
 	if (err)
@@ -14911,8 +15110,8 @@
 
 	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
 	    hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw))
-		dev_info(&pdev->dev,
-			 "The driver for the device detected a newer version of the NVM image v%u.%u than expected v%u.%u. Please install the most recent version of the network driver.\n",
+		dev_dbg(&pdev->dev,
+			"The driver for the device detected a newer version of the NVM image v%u.%u than v%u.%u.\n",
 			 hw->aq.api_maj_ver,
 			 hw->aq.api_min_ver,
 			 I40E_FW_API_VERSION_MAJOR,
@@ -15058,24 +15257,6 @@
 	}
 	INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list);
 
-	/* Make sure flow control is set according to current settings */
-	err = i40e_set_fc(hw, &set_fc_aq_fail, true);
-	if (set_fc_aq_fail & I40E_SET_FC_AQ_FAIL_GET)
-		dev_dbg(&pf->pdev->dev,
-			"Set fc with err %s aq_err %s on get_phy_cap\n",
-			i40e_stat_str(hw, err),
-			i40e_aq_str(hw, hw->aq.asq_last_status));
-	if (set_fc_aq_fail & I40E_SET_FC_AQ_FAIL_SET)
-		dev_dbg(&pf->pdev->dev,
-			"Set fc with err %s aq_err %s on set_phy_config\n",
-			i40e_stat_str(hw, err),
-			i40e_aq_str(hw, hw->aq.asq_last_status));
-	if (set_fc_aq_fail & I40E_SET_FC_AQ_FAIL_UPDATE)
-		dev_dbg(&pf->pdev->dev,
-			"Set fc with err %s aq_err %s on get_link_info\n",
-			i40e_stat_str(hw, err),
-			i40e_aq_str(hw, hw->aq.asq_last_status));
-
 	/* if FDIR VSI was set up, start it now */
 	for (i = 0; i < pf->num_alloc_vsi; i++) {
 		if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
@@ -15132,6 +15313,8 @@
 		if (err) {
 			dev_info(&pdev->dev,
 				 "setup of misc vector failed: %d\n", err);
+			i40e_cloud_filter_exit(pf);
+			i40e_fdir_teardown(pf);
 			goto err_vsis;
 		}
 	}
@@ -15328,6 +15511,14 @@
 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
+	while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+		usleep_range(1000, 2000);
+
+	if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+		set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
+		i40e_free_vfs(pf);
+		pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
+	}
 	/* no more scheduling of any task */
 	set_bit(__I40E_SUSPENDED, pf->state);
 	set_bit(__I40E_DOWN, pf->state);
@@ -15354,11 +15545,6 @@
 	 */
 	i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
 
-	if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
-		i40e_free_vfs(pf);
-		pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
-	}
-
 	i40e_fdir_teardown(pf);
 
 	/* If there is a switch structure or any orphans, remove them.
@@ -15373,11 +15559,15 @@
 			i40e_switch_branch_release(pf->veb[i]);
 	}
 
-	/* Now we can shutdown the PF's VSI, just before we kill
+	/* Now we can shutdown the PF's VSIs, just before we kill
 	 * adminq and hmc.
 	 */
-	if (pf->vsi[pf->lan_vsi])
-		i40e_vsi_release(pf->vsi[pf->lan_vsi]);
+	for (i = pf->num_alloc_vsi; i--;)
+		if (pf->vsi[i]) {
+			i40e_vsi_close(pf->vsi[i]);
+			i40e_vsi_release(pf->vsi[i]);
+			pf->vsi[i] = NULL;
+		}
 
 	i40e_cloud_filter_exit(pf);
 
@@ -15526,6 +15716,9 @@
 	struct i40e_pf *pf = pci_get_drvdata(pdev);
 
 	i40e_reset_and_rebuild(pf, false, false);
+#ifdef CONFIG_PCI_IOV
+	i40e_restore_all_vfs_msi_state(pdev);
+#endif /* CONFIG_PCI_IOV */
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_nvm.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_nvm.c
@@ -210,11 +210,11 @@
  * @hw: pointer to the HW structure.
  * @module_pointer: module pointer location in words from the NVM beginning
  * @offset: offset in words from module start
- * @words: number of words to write
- * @data: buffer with words to write to the Shadow RAM
+ * @words: number of words to read
+ * @data: buffer with words to read to the Shadow RAM
  * @last_command: tells the AdminQ that this is the last command
  *
- * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
+ * Reads a 16 bit words buffer to the Shadow RAM using the admin command.
  **/
 static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw,
 				    u8 module_pointer, u32 offset,
@@ -234,18 +234,18 @@
 	 */
 	if ((offset + words) > hw->nvm.sr_size)
 		i40e_debug(hw, I40E_DEBUG_NVM,
-			   "NVM write error: offset %d beyond Shadow RAM limit %d\n",
+			   "NVM read error: offset %d beyond Shadow RAM limit %d\n",
 			   (offset + words), hw->nvm.sr_size);
 	else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
-		/* We can write only up to 4KB (one sector), in one AQ write */
+		/* We can read only up to 4KB (one sector), in one AQ write */
 		i40e_debug(hw, I40E_DEBUG_NVM,
-			   "NVM write fail error: tried to write %d words, limit is %d.\n",
+			   "NVM read fail error: tried to read %d words, limit is %d.\n",
 			   words, I40E_SR_SECTOR_SIZE_IN_WORDS);
 	else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
 		 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
-		/* A single write cannot spread over two sectors */
+		/* A single read cannot spread over two sectors */
 		i40e_debug(hw, I40E_DEBUG_NVM,
-			   "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
+			   "NVM read error: cannot spread over two sectors in a single read offset=%d words=%d\n",
 			   offset, words);
 	else
 		ret_code = i40e_aq_read_nvm(hw, module_pointer,
@@ -323,20 +323,24 @@
 
 /**
  * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location
- * @hw: pointer to the HW structure
+ * @hw: Pointer to the HW structure
  * @module_ptr: Pointer to module in words with respect to NVM beginning
- * @offset: offset in words from module start
+ * @module_offset: Offset in words from module start
+ * @data_offset: Offset in words from reading data area start
  * @words_data_size: Words to read from NVM
  * @data_ptr: Pointer to memory location where resulting buffer will be stored
  **/
-i40e_status i40e_read_nvm_module_data(struct i40e_hw *hw,
-				      u8 module_ptr, u16 offset,
-				      u16 words_data_size,
-				      u16 *data_ptr)
+enum i40e_status_code i40e_read_nvm_module_data(struct i40e_hw *hw,
+						u8 module_ptr,
+						u16 module_offset,
+						u16 data_offset,
+						u16 words_data_size,
+						u16 *data_ptr)
 {
 	i40e_status status;
+	u16 specific_ptr = 0;
 	u16 ptr_value = 0;
-	u32 flat_offset;
+	u32 offset = 0;
 
 	if (module_ptr != 0) {
 		status = i40e_read_nvm_word(hw, module_ptr, &ptr_value);
@@ -352,36 +356,35 @@
 
 	/* Pointer not initialized */
 	if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
-	    ptr_value == I40E_NVM_INVALID_VAL)
+	    ptr_value == I40E_NVM_INVALID_VAL) {
+		i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
 		return I40E_ERR_BAD_PTR;
+	}
 
 	/* Check whether the module is in SR mapped area or outside */
 	if (ptr_value & I40E_PTR_TYPE) {
 		/* Pointer points outside of the Shared RAM mapped area */
-		ptr_value &= ~I40E_PTR_TYPE;
+		i40e_debug(hw, I40E_DEBUG_ALL,
+			   "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
 
-		/* PtrValue in 4kB units, need to convert to words */
-		ptr_value /= 2;
-		flat_offset = ((u32)ptr_value * 0x1000) + (u32)offset;
-		status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
-		if (!status) {
-			status = i40e_aq_read_nvm(hw, 0, 2 * flat_offset,
-						  2 * words_data_size,
-						  data_ptr, true, NULL);
-			i40e_release_nvm(hw);
-			if (status) {
-				i40e_debug(hw, I40E_DEBUG_ALL,
-					   "Reading nvm aq failed.Error code: %d.\n",
-					   status);
-				return I40E_ERR_NVM;
-			}
-		} else {
-			return I40E_ERR_NVM;
-		}
+		return I40E_ERR_PARAM;
 	} else {
 		/* Read from the Shadow RAM */
-		status = i40e_read_nvm_buffer(hw, ptr_value + offset,
-					      &words_data_size, data_ptr);
+
+		status = i40e_read_nvm_word(hw, ptr_value + module_offset,
+					    &specific_ptr);
+		if (status) {
+			i40e_debug(hw, I40E_DEBUG_ALL,
+				   "Reading nvm word failed.Error code: %d.\n",
+				   status);
+			return I40E_ERR_NVM;
+		}
+
+		offset = ptr_value + module_offset + specific_ptr +
+			data_offset;
+
+		status = i40e_read_nvm_buffer(hw, offset, &words_data_size,
+					      data_ptr);
 		if (status) {
 			i40e_debug(hw, I40E_DEBUG_ALL,
 				   "Reading nvm buffer failed.Error code: %d.\n",
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -315,10 +315,12 @@
 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_module_data(struct i40e_hw *hw,
-				      u8 module_ptr, u16 offset,
-				      u16 words_data_size,
-				      u16 *data_ptr);
+enum i40e_status_code i40e_read_nvm_module_data(struct i40e_hw *hw,
+						u8 module_ptr,
+						u16 module_offset,
+						u16 data_offset,
+						u16 words_data_size,
+						u16 *data_ptr);
 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);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1195,6 +1195,11 @@
 	rc->total_packets = 0;
 }
 
+static struct i40e_rx_buffer *i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx)
+{
+	return &rx_ring->rx_bi[idx];
+}
+
 /**
  * i40e_reuse_rx_page - page flip buffer and store it back on the ring
  * @rx_ring: rx descriptor ring to store buffers on
@@ -1208,7 +1213,7 @@
 	struct i40e_rx_buffer *new_buff;
 	u16 nta = rx_ring->next_to_alloc;
 
-	new_buff = &rx_ring->rx_bi[nta];
+	new_buff = i40e_rx_bi(rx_ring, nta);
 
 	/* update, and store next to alloc */
 	nta++;
@@ -1272,7 +1277,7 @@
 	ntc = rx_ring->next_to_clean;
 
 	/* fetch, update, and store next to clean */
-	rx_buffer = &rx_ring->rx_bi[ntc++];
+	rx_buffer = i40e_rx_bi(rx_ring, ntc++);
 	ntc = (ntc < rx_ring->count) ? ntc : 0;
 	rx_ring->next_to_clean = ntc;
 
@@ -1361,7 +1366,7 @@
 
 	/* Free all the Rx ring sk_buffs */
 	for (i = 0; i < rx_ring->count; i++) {
-		struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
+		struct i40e_rx_buffer *rx_bi = i40e_rx_bi(rx_ring, i);
 
 		if (!rx_bi->page)
 			continue;
@@ -1576,7 +1581,7 @@
 		return false;
 
 	rx_desc = I40E_RX_DESC(rx_ring, ntu);
-	bi = &rx_ring->rx_bi[ntu];
+	bi = i40e_rx_bi(rx_ring, ntu);
 
 	do {
 		if (!i40e_alloc_mapped_page(rx_ring, bi))
@@ -1598,7 +1603,7 @@
 		ntu++;
 		if (unlikely(ntu == rx_ring->count)) {
 			rx_desc = I40E_RX_DESC(rx_ring, 0);
-			bi = rx_ring->rx_bi;
+			bi = i40e_rx_bi(rx_ring, 0);
 			ntu = 0;
 		}
 
@@ -1864,6 +1869,7 @@
  * the adapter for another receive
  *
  * @rx_buffer: buffer containing the page
+ * @rx_buffer_pgcnt: buffer page refcount pre xdp_do_redirect() call
  *
  * If page is reusable, rx_buffer->page_offset is adjusted to point to
  * an unused region in the page.
@@ -1886,7 +1892,8 @@
  *
  * In either case, if the page is reusable its refcount is increased.
  **/
-static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer)
+static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer,
+				   int rx_buffer_pgcnt)
 {
 	unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
 	struct page *page = rx_buffer->page;
@@ -1897,7 +1904,7 @@
 
 #if (PAGE_SIZE < 8192)
 	/* if we are only owner of page we can reuse it */
-	if (unlikely((page_count(page) - pagecnt_bias) > 1))
+	if (unlikely((rx_buffer_pgcnt - pagecnt_bias) > 1))
 		return false;
 #else
 #define I40E_LAST_OFFSET \
@@ -1956,17 +1963,25 @@
  * i40e_get_rx_buffer - Fetch Rx buffer and synchronize data for use
  * @rx_ring: rx descriptor ring to transact packets on
  * @size: size of buffer to add to skb
+ * @rx_buffer_pgcnt: buffer page refcount
  *
  * This function will pull an Rx buffer from the ring and synchronize it
  * for use by the CPU.
  */
 static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
-						 const unsigned int size)
+						 const unsigned int size,
+						 int *rx_buffer_pgcnt)
 {
 	struct i40e_rx_buffer *rx_buffer;
 
-	rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
-	prefetchw(rx_buffer->page);
+	rx_buffer = i40e_rx_bi(rx_ring, rx_ring->next_to_clean);
+	*rx_buffer_pgcnt =
+#if (PAGE_SIZE < 8192)
+		page_count(rx_buffer->page);
+#else
+		0;
+#endif
+	prefetch_page_address(rx_buffer->page);
 
 	/* we are reusing so sync this buffer for CPU use */
 	dma_sync_single_range_for_cpu(rx_ring->dev,
@@ -2120,14 +2135,16 @@
  * i40e_put_rx_buffer - Clean up used buffer and either recycle or free
  * @rx_ring: rx descriptor ring to transact packets on
  * @rx_buffer: rx buffer to pull data from
+ * @rx_buffer_pgcnt: rx buffer page refcount pre xdp_do_redirect() call
  *
  * This function will clean up the contents of the rx_buffer.  It will
  * either recycle the buffer or unmap it and free the associated resources.
  */
 static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
-			       struct i40e_rx_buffer *rx_buffer)
+			       struct i40e_rx_buffer *rx_buffer,
+			       int rx_buffer_pgcnt)
 {
-	if (i40e_can_reuse_rx_page(rx_buffer)) {
+	if (i40e_can_reuse_rx_page(rx_buffer, rx_buffer_pgcnt)) {
 		/* hand second half of page back to the ring */
 		i40e_reuse_rx_page(rx_ring, rx_buffer);
 	} else {
@@ -2216,15 +2233,20 @@
 	case XDP_TX:
 		xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
 		result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
+		if (result == I40E_XDP_CONSUMED)
+			goto out_failure;
 		break;
 	case XDP_REDIRECT:
 		err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
-		result = !err ? I40E_XDP_REDIR : I40E_XDP_CONSUMED;
+		if (err)
+			goto out_failure;
+		result = I40E_XDP_REDIR;
 		break;
 	default:
 		bpf_warn_invalid_xdp_action(act);
 		/* fall through */
 	case XDP_ABORTED:
+out_failure:
 		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
 		/* fall through -- handle aborts by dropping packet */
 	case XDP_DROP:
@@ -2340,6 +2362,7 @@
 	while (likely(total_rx_packets < (unsigned int)budget)) {
 		struct i40e_rx_buffer *rx_buffer;
 		union i40e_rx_desc *rx_desc;
+		int rx_buffer_pgcnt;
 		unsigned int size;
 		u64 qword;
 
@@ -2379,7 +2402,7 @@
 			break;
 
 		i40e_trace(clean_rx_irq, rx_ring, rx_desc, skb);
-		rx_buffer = i40e_get_rx_buffer(rx_ring, size);
+		rx_buffer = i40e_get_rx_buffer(rx_ring, size, &rx_buffer_pgcnt);
 
 		/* retrieve a buffer from the ring */
 		if (!skb) {
@@ -2419,7 +2442,7 @@
 			break;
 		}
 
-		i40e_put_rx_buffer(rx_ring, rx_buffer);
+		i40e_put_rx_buffer(rx_ring, rx_buffer, rx_buffer_pgcnt);
 		cleaned_count++;
 
 		if (i40e_is_non_eop(rx_ring, rx_desc, skb))
@@ -2646,7 +2669,7 @@
 		return budget;
 	}
 
-	if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR)
+	if (q_vector->tx.ring[0].flags & I40E_TXR_FLAGS_WB_ON_ITR)
 		q_vector->arm_wb_state = false;
 
 	/* Exit the polling mode, but don't re-enable interrupts if stack might
@@ -3075,13 +3098,16 @@
 
 			l4_proto = ip.v4->protocol;
 		} else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+			int ret;
+
 			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);
+			ret = ipv6_skip_exthdr(skb, exthdr - skb->data,
+					       &l4_proto, &frag_off);
+			if (ret < 0)
+				return -1;
 		}
 
 		/* define outer transport */
@@ -3495,6 +3521,55 @@
 	return -1;
 }
 
+static u16 i40e_swdcb_skb_tx_hash(struct net_device *dev,
+				  const struct sk_buff *skb,
+				  u16 num_tx_queues)
+{
+	u32 jhash_initval_salt = 0xd631614b;
+	u32 hash;
+
+	if (skb->sk && skb->sk->sk_hash)
+		hash = skb->sk->sk_hash;
+	else
+		hash = (__force u16)skb->protocol ^ skb->hash;
+
+	hash = jhash_1word(hash, jhash_initval_salt);
+
+	return (u16)(((u64)hash * num_tx_queues) >> 32);
+}
+
+u16 i40e_lan_select_queue(struct net_device *netdev,
+			  struct sk_buff *skb,
+			  struct net_device __always_unused *sb_dev)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_hw *hw;
+	u16 qoffset;
+	u16 qcount;
+	u8 tclass;
+	u16 hash;
+	u8 prio;
+
+	/* is DCB enabled at all? */
+	if (vsi->tc_config.numtc == 1)
+		return netdev_pick_tx(netdev, skb, sb_dev);
+
+	prio = skb->priority;
+	hw = &vsi->back->hw;
+	tclass = hw->local_dcbx_config.etscfg.prioritytable[prio];
+	/* sanity check */
+	if (unlikely(!(vsi->tc_config.enabled_tc & BIT(tclass))))
+		tclass = 0;
+
+	/* select a queue assigned for the given TC */
+	qcount = vsi->tc_config.tc_info[tclass].qcount;
+	hash = i40e_swdcb_skb_tx_hash(netdev, skb, qcount);
+
+	qoffset = vsi->tc_config.tc_info[tclass].qoffset;
+	return qoffset + hash;
+}
+
 /**
  * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring
  * @xdp: data to transmit
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -481,6 +481,8 @@
 
 bool i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
 netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+u16 i40e_lan_select_queue(struct net_device *netdev, struct sk_buff *skb,
+			  struct net_device *sb_dev);
 void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
 void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
 int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -253,11 +253,8 @@
 #define I40E_CAP_PHY_TYPE_25GBASE_ACC BIT_ULL(I40E_PHY_TYPE_25GBASE_ACC + \
 					     I40E_PHY_TYPE_OFFSET)
 /* Offset for 2.5G/5G PHY Types value to bit number conversion */
-#define I40E_PHY_TYPE_OFFSET2 (-10)
-#define I40E_CAP_PHY_TYPE_2_5GBASE_T BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T + \
-					     I40E_PHY_TYPE_OFFSET2)
-#define I40E_CAP_PHY_TYPE_5GBASE_T BIT_ULL(I40E_PHY_TYPE_5GBASE_T + \
-					     I40E_PHY_TYPE_OFFSET2)
+#define I40E_CAP_PHY_TYPE_2_5GBASE_T BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T)
+#define I40E_CAP_PHY_TYPE_5GBASE_T BIT_ULL(I40E_PHY_TYPE_5GBASE_T)
 #define I40E_HW_CAP_MAX_GPIO			30
 /* Capabilities of a PF or a VF or the whole device */
 struct i40e_hw_capabilities {
@@ -1473,6 +1470,10 @@
 #define I40E_PFQF_CTL_0_HASHLUTSIZE_512	0x00010000
 
 /* INPUT SET MASK for RSS, flow director, and flexible payload */
+#define I40E_X722_L3_SRC_SHIFT		49
+#define I40E_X722_L3_SRC_MASK		(0x3ULL << I40E_X722_L3_SRC_SHIFT)
+#define I40E_X722_L3_DST_SHIFT		41
+#define I40E_X722_L3_DST_MASK		(0x3ULL << I40E_X722_L3_DST_SHIFT)
 #define I40E_L3_SRC_SHIFT		47
 #define I40E_L3_SRC_MASK		(0x3ULL << I40E_L3_SRC_SHIFT)
 #define I40E_L3_V6_SRC_SHIFT		43
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -55,12 +55,7 @@
 
 	pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
 	pfe.severity = PF_EVENT_SEVERITY_INFO;
-
-	/* Always report link is down if the VF queues aren't enabled */
-	if (!vf->queues_enabled) {
-		pfe.event_data.link_event.link_status = false;
-		pfe.event_data.link_event.link_speed = 0;
-	} else if (vf->link_forced) {
+	if (vf->link_forced) {
 		pfe.event_data.link_event.link_status = vf->link_up;
 		pfe.event_data.link_event.link_speed =
 			(vf->link_up ? VIRTCHNL_LINK_SPEED_40GB : 0);
@@ -70,7 +65,6 @@
 		pfe.event_data.link_event.link_speed =
 			i40e_virtchnl_link_speed(ls->link_speed);
 	}
-
 	i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
 			       0, (u8 *)&pfe, sizeof(pfe), NULL);
 }
@@ -105,6 +99,32 @@
 			     (u8 *)&pfe, sizeof(struct virtchnl_pf_event));
 }
 
+#ifdef CONFIG_PCI_IOV
+void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev)
+{
+	u16 vf_id;
+	u16 pos;
+
+	/* Continue only if this is a PF */
+	if (!pdev->is_physfn)
+		return;
+
+	if (!pci_num_vf(pdev))
+		return;
+
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (pos) {
+		struct pci_dev *vf_dev = NULL;
+
+		pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id);
+		while ((vf_dev = pci_get_device(pdev->vendor, vf_id, vf_dev))) {
+			if (vf_dev->is_virtfn && vf_dev->physfn == pdev)
+				pci_restore_msi_state(vf_dev);
+		}
+	}
+}
+#endif /* CONFIG_PCI_IOV */
+
 /**
  * i40e_vc_notify_vf_reset
  * @vf: pointer to the VF structure
@@ -136,16 +156,18 @@
 /***********************misc routines*****************************/
 
 /**
- * i40e_vc_disable_vf
+ * i40e_vc_reset_vf
  * @vf: pointer to the VF info
- *
- * Disable the VF through a SW reset.
+ * @notify_vf: notify vf about reset or not
+ * Reset VF handler.
  **/
-static inline void i40e_vc_disable_vf(struct i40e_vf *vf)
+static void i40e_vc_reset_vf(struct i40e_vf *vf, bool notify_vf)
 {
+	struct i40e_pf *pf = vf->pf;
 	int i;
 
-	i40e_vc_notify_vf_reset(vf);
+	if (notify_vf)
+		i40e_vc_notify_vf_reset(vf);
 
 	/* We want to ensure that an actual reset occurs initiated after this
 	 * function was called. However, we do not want to wait forever, so
@@ -153,14 +175,24 @@
 	 * ensure a reset.
 	 */
 	for (i = 0; i < 20; i++) {
+		/* If PF is in VFs releasing state reset VF is impossible,
+		 * so leave it.
+		 */
+		if (test_bit(__I40E_VFS_RELEASING, pf->state))
+			return;
 		if (i40e_reset_vf(vf, false))
 			return;
 		usleep_range(10000, 20000);
 	}
 
-	dev_warn(&vf->pf->pdev->dev,
-		 "Failed to initiate reset for VF %d after 200 milliseconds\n",
-		 vf->vf_id);
+	if (notify_vf)
+		dev_warn(&vf->pf->pdev->dev,
+			 "Failed to initiate reset for VF %d after 200 milliseconds\n",
+			 vf->vf_id);
+	else
+		dev_dbg(&vf->pf->pdev->dev,
+			"Failed to initiate reset for VF %d after 200 milliseconds\n",
+			vf->vf_id);
 }
 
 /**
@@ -621,14 +653,13 @@
 				    u16 vsi_queue_id,
 				    struct virtchnl_rxq_info *info)
 {
+	u16 pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);
 	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx];
 	struct i40e_hw *hw = &pf->hw;
 	struct i40e_hmc_obj_rxq rx_ctx;
-	u16 pf_queue_id;
 	int ret = 0;
 
-	pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);
-
 	/* clear the context structure first */
 	memset(&rx_ctx, 0, sizeof(struct i40e_hmc_obj_rxq));
 
@@ -666,6 +697,10 @@
 	}
 	rx_ctx.rxmax = info->max_pkt_size;
 
+	/* if port VLAN is configured increase the max packet size */
+	if (vsi->info.pvid)
+		rx_ctx.rxmax += VLAN_HLEN;
+
 	/* enable 32bytes desc always */
 	rx_ctx.dsize = 1;
 
@@ -1107,39 +1142,98 @@
 	return -EIO;
 }
 
-static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi);
+/**
+ * __i40e_getnum_vf_vsi_vlan_filters
+ * @vsi: pointer to the vsi
+ *
+ * called to get the number of VLANs offloaded on this VF
+ **/
+static int __i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
+{
+	struct i40e_mac_filter *f;
+	u16 num_vlans = 0, bkt;
+
+	hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+		if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
+			num_vlans++;
+	}
+
+	return num_vlans;
+}
+
+/**
+ * i40e_getnum_vf_vsi_vlan_filters
+ * @vsi: pointer to the vsi
+ *
+ * wrapper for __i40e_getnum_vf_vsi_vlan_filters() with spinlock held
+ **/
+static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
+{
+	int num_vlans;
+
+	spin_lock_bh(&vsi->mac_filter_hash_lock);
+	num_vlans = __i40e_getnum_vf_vsi_vlan_filters(vsi);
+	spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+	return num_vlans;
+}
 
 /**
- * i40e_config_vf_promiscuous_mode
- * @vf: pointer to the VF info
- * @vsi_id: VSI id
- * @allmulti: set MAC L2 layer multicast promiscuous enable/disable
- * @alluni: set MAC L2 layer unicast promiscuous enable/disable
+ * i40e_get_vlan_list_sync
+ * @vsi: pointer to the VSI
+ * @num_vlans: number of VLANs in mac_filter_hash, returned to caller
+ * @vlan_list: list of VLANs present in mac_filter_hash, returned to caller.
+ *             This array is allocated here, but has to be freed in caller.
  *
- * Called from the VF to configure the promiscuous mode of
- * VF vsis and from the VF reset path to reset promiscuous mode.
+ * Called to get number of VLANs and VLAN list present in mac_filter_hash.
  **/
-static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
-						   u16 vsi_id,
-						   bool allmulti,
-						   bool alluni)
+static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, u16 *num_vlans,
+				    s16 **vlan_list)
 {
-	struct i40e_pf *pf = vf->pf;
-	struct i40e_hw *hw = &pf->hw;
 	struct i40e_mac_filter *f;
-	i40e_status aq_ret = 0;
-	struct i40e_vsi *vsi;
+	int i = 0;
 	int bkt;
 
-	vsi = i40e_find_vsi_from_id(pf, vsi_id);
-	if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
-		return I40E_ERR_PARAM;
+	spin_lock_bh(&vsi->mac_filter_hash_lock);
+	*num_vlans = __i40e_getnum_vf_vsi_vlan_filters(vsi);
+	*vlan_list = kcalloc(*num_vlans, sizeof(**vlan_list), GFP_ATOMIC);
+	if (!(*vlan_list))
+		goto err;
 
-	if (vf->port_vlan_id) {
-		aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
-							    allmulti,
-							    vf->port_vlan_id,
-							    NULL);
+	hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+		if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
+			continue;
+		(*vlan_list)[i++] = f->vlan;
+	}
+err:
+	spin_unlock_bh(&vsi->mac_filter_hash_lock);
+}
+
+/**
+ * i40e_set_vsi_promisc
+ * @vf: pointer to the VF struct
+ * @seid: VSI number
+ * @multi_enable: set MAC L2 layer multicast promiscuous enable/disable
+ *                for a given VLAN
+ * @unicast_enable: set MAC L2 layer unicast promiscuous enable/disable
+ *                  for a given VLAN
+ * @vl: List of VLANs - apply filter for given VLANs
+ * @num_vlans: Number of elements in @vl
+ **/
+static i40e_status
+i40e_set_vsi_promisc(struct i40e_vf *vf, u16 seid, bool multi_enable,
+		     bool unicast_enable, s16 *vl, u16 num_vlans)
+{
+	i40e_status aq_ret, aq_tmp = 0;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_hw *hw = &pf->hw;
+	int i;
+
+	/* No VLAN to set promisc on, set on VSI */
+	if (!num_vlans || !vl) {
+		aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, seid,
+							       multi_enable,
+							       NULL);
 		if (aq_ret) {
 			int aq_err = pf->hw.aq.asq_last_status;
 
@@ -1148,13 +1242,14 @@
 				vf->vf_id,
 				i40e_stat_str(&pf->hw, aq_ret),
 				i40e_aq_str(&pf->hw, aq_err));
+
 			return aq_ret;
 		}
 
-		aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
-							    alluni,
-							    vf->port_vlan_id,
-							    NULL);
+		aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, seid,
+							     unicast_enable,
+							     NULL, true);
+
 		if (aq_ret) {
 			int aq_err = pf->hw.aq.asq_last_status;
 
@@ -1164,68 +1259,94 @@
 				i40e_stat_str(&pf->hw, aq_ret),
 				i40e_aq_str(&pf->hw, aq_err));
 		}
+
 		return aq_ret;
-	} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
-		hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-			if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
-				continue;
-			aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
-								    vsi->seid,
-								    allmulti,
-								    f->vlan,
-								    NULL);
-			if (aq_ret) {
-				int aq_err = pf->hw.aq.asq_last_status;
+	}
 
-				dev_err(&pf->pdev->dev,
-					"Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
-					f->vlan,
-					i40e_stat_str(&pf->hw, aq_ret),
-					i40e_aq_str(&pf->hw, aq_err));
-			}
+	for (i = 0; i < num_vlans; i++) {
+		aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, seid,
+							    multi_enable,
+							    vl[i], NULL);
+		if (aq_ret) {
+			int aq_err = pf->hw.aq.asq_last_status;
+
+			dev_err(&pf->pdev->dev,
+				"VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
+				vf->vf_id,
+				i40e_stat_str(&pf->hw, aq_ret),
+				i40e_aq_str(&pf->hw, aq_err));
 
-			aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
-								    vsi->seid,
-								    alluni,
-								    f->vlan,
-								    NULL);
-			if (aq_ret) {
-				int aq_err = pf->hw.aq.asq_last_status;
+			if (!aq_tmp)
+				aq_tmp = aq_ret;
+		}
 
-				dev_err(&pf->pdev->dev,
-					"Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
-					f->vlan,
-					i40e_stat_str(&pf->hw, aq_ret),
-					i40e_aq_str(&pf->hw, aq_err));
-			}
+		aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, seid,
+							    unicast_enable,
+							    vl[i], NULL);
+		if (aq_ret) {
+			int aq_err = pf->hw.aq.asq_last_status;
+
+			dev_err(&pf->pdev->dev,
+				"VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
+				vf->vf_id,
+				i40e_stat_str(&pf->hw, aq_ret),
+				i40e_aq_str(&pf->hw, aq_err));
+
+			if (!aq_tmp)
+				aq_tmp = aq_ret;
 		}
-		return aq_ret;
 	}
-	aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti,
-						       NULL);
-	if (aq_ret) {
-		int aq_err = pf->hw.aq.asq_last_status;
 
-		dev_err(&pf->pdev->dev,
-			"VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
-			vf->vf_id,
-			i40e_stat_str(&pf->hw, aq_ret),
-			i40e_aq_str(&pf->hw, aq_err));
+	if (aq_tmp)
+		aq_ret = aq_tmp;
+
+	return aq_ret;
+}
+
+/**
+ * i40e_config_vf_promiscuous_mode
+ * @vf: pointer to the VF info
+ * @vsi_id: VSI id
+ * @allmulti: set MAC L2 layer multicast promiscuous enable/disable
+ * @alluni: set MAC L2 layer unicast promiscuous enable/disable
+ *
+ * Called from the VF to configure the promiscuous mode of
+ * VF vsis and from the VF reset path to reset promiscuous mode.
+ **/
+static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
+						   u16 vsi_id,
+						   bool allmulti,
+						   bool alluni)
+{
+	i40e_status aq_ret = I40E_SUCCESS;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi;
+	u16 num_vlans;
+	s16 *vl;
+
+	vsi = i40e_find_vsi_from_id(pf, vsi_id);
+	if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
+		return I40E_ERR_PARAM;
+
+	if (vf->port_vlan_id) {
+		aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti,
+					      alluni, &vf->port_vlan_id, 1);
 		return aq_ret;
-	}
+	} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
+		i40e_get_vlan_list_sync(vsi, &num_vlans, &vl);
 
-	aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, alluni,
-						     NULL, true);
-	if (aq_ret) {
-		int aq_err = pf->hw.aq.asq_last_status;
+		if (!vl)
+			return I40E_ERR_NO_MEMORY;
 
-		dev_err(&pf->pdev->dev,
-			"VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
-			vf->vf_id,
-			i40e_stat_str(&pf->hw, aq_ret),
-			i40e_aq_str(&pf->hw, aq_err));
+		aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti, alluni,
+					      vl, num_vlans);
+		kfree(vl);
+		return aq_ret;
 	}
 
+	/* no VLANs to set on, set on VSI */
+	aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti, alluni,
+				      NULL, 0);
 	return aq_ret;
 }
 
@@ -1335,7 +1456,8 @@
  * @vf: pointer to the VF structure
  * @flr: VFLR was issued or not
  *
- * Returns true if the VF is reset, false otherwise.
+ * Returns true if the VF is in reset, resets successfully, or resets
+ * are disabled and false otherwise.
  **/
 bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
 {
@@ -1345,11 +1467,16 @@
 	u32 reg;
 	int i;
 
-	/* If the VFs have been disabled, this means something else is
-	 * resetting the VF, so we shouldn't continue.
-	 */
-	if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-		return false;
+	if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state))
+		return true;
+
+	/* Bail out if VFs are disabled. */
+	if (test_bit(__I40E_VF_DISABLE, pf->state))
+		return true;
+
+	/* If VF is being reset already we don't need to continue. */
+	if (test_and_set_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
+		return true;
 
 	i40e_trigger_vf_reset(vf, flr);
 
@@ -1385,7 +1512,8 @@
 	i40e_cleanup_reset_vf(vf);
 
 	i40e_flush(hw);
-	clear_bit(__I40E_VF_DISABLE, pf->state);
+	usleep_range(20000, 40000);
+	clear_bit(I40E_VF_STATE_RESETTING, &vf->vf_states);
 
 	return true;
 }
@@ -1418,8 +1546,12 @@
 		return false;
 
 	/* Begin reset on all VFs at once */
-	for (v = 0; v < pf->num_alloc_vfs; v++)
-		i40e_trigger_vf_reset(&pf->vf[v], flr);
+	for (v = 0; v < pf->num_alloc_vfs; v++) {
+		vf = &pf->vf[v];
+		/* If VF is being reset no need to trigger reset again */
+		if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
+			i40e_trigger_vf_reset(&pf->vf[v], flr);
+	}
 
 	/* HW requires some time to make sure it can flush the FIFO for a VF
 	 * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
@@ -1435,9 +1567,11 @@
 		 */
 		while (v < pf->num_alloc_vfs) {
 			vf = &pf->vf[v];
-			reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
-			if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK))
-				break;
+			if (!test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states)) {
+				reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
+				if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK))
+					break;
+			}
 
 			/* If the current VF has finished resetting, move on
 			 * to the next VF in sequence.
@@ -1465,6 +1599,10 @@
 		if (pf->vf[v].lan_vsi_idx == 0)
 			continue;
 
+		/* If VF is reset in another thread just continue */
+		if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
+			continue;
+
 		i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[v].lan_vsi_idx]);
 	}
 
@@ -1476,6 +1614,10 @@
 		if (pf->vf[v].lan_vsi_idx == 0)
 			continue;
 
+		/* If VF is reset in another thread just continue */
+		if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
+			continue;
+
 		i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[v].lan_vsi_idx]);
 	}
 
@@ -1485,10 +1627,16 @@
 	mdelay(50);
 
 	/* Finish the reset on each VF */
-	for (v = 0; v < pf->num_alloc_vfs; v++)
+	for (v = 0; v < pf->num_alloc_vfs; v++) {
+		/* If VF is reset in another thread just continue */
+		if (test_bit(I40E_VF_STATE_RESETTING, &vf->vf_states))
+			continue;
+
 		i40e_cleanup_reset_vf(&pf->vf[v]);
+	}
 
 	i40e_flush(hw);
+	usleep_range(20000, 40000);
 	clear_bit(__I40E_VF_DISABLE, pf->state);
 
 	return true;
@@ -1508,11 +1656,22 @@
 
 	if (!pf->vf)
 		return;
+
+	set_bit(__I40E_VFS_RELEASING, pf->state);
 	while (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
 		usleep_range(1000, 2000);
 
 	i40e_notify_client_of_vf_enable(pf, 0);
 
+	/* Disable IOV before freeing resources. This lets any VF drivers
+	 * running in the host get themselves cleaned up before we yank
+	 * the carpet out from underneath their feet.
+	 */
+	if (!pci_vfs_assigned(pf->pdev))
+		pci_disable_sriov(pf->pdev);
+	else
+		dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
+
 	/* Amortize wait time by stopping all VFs at the same time */
 	for (i = 0; i < pf->num_alloc_vfs; i++) {
 		if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
@@ -1528,15 +1687,6 @@
 		i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
 	}
 
-	/* Disable IOV before freeing resources. This lets any VF drivers
-	 * running in the host get themselves cleaned up before we yank
-	 * the carpet out from underneath their feet.
-	 */
-	if (!pci_vfs_assigned(pf->pdev))
-		pci_disable_sriov(pf->pdev);
-	else
-		dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
-
 	/* free up VF resources */
 	tmp = pf->num_alloc_vfs;
 	pf->num_alloc_vfs = 0;
@@ -1565,6 +1715,7 @@
 		}
 	}
 	clear_bit(__I40E_VF_DISABLE, pf->state);
+	clear_bit(__I40E_VFS_RELEASING, pf->state);
 }
 
 #ifdef CONFIG_PCI_IOV
@@ -1700,7 +1851,7 @@
 	if (num_vfs) {
 		if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
 			pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
-			i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
+			i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG);
 		}
 		ret = i40e_pci_sriov_enable(pdev, num_vfs);
 		goto sriov_configure_out;
@@ -1709,7 +1860,7 @@
 	if (!pci_vfs_assigned(pf->pdev)) {
 		i40e_free_vfs(pf);
 		pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
-		i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
+		i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG);
 	} else {
 		dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
 		ret = -EINVAL;
@@ -1795,6 +1946,32 @@
 }
 
 /**
+ * i40e_sync_vf_state
+ * @vf: pointer to the VF info
+ * @state: VF state
+ *
+ * Called from a VF message to synchronize the service with a potential
+ * VF reset state
+ **/
+static bool i40e_sync_vf_state(struct i40e_vf *vf, enum i40e_vf_states state)
+{
+	int i;
+
+	/* When handling some messages, it needs VF state to be set.
+	 * It is possible that this flag is cleared during VF reset,
+	 * so there is a need to wait until the end of the reset to
+	 * handle the request message correctly.
+	 */
+	for (i = 0; i < I40E_VF_STATE_WAIT_COUNT; i++) {
+		if (test_bit(state, &vf->vf_states))
+			return true;
+		usleep_range(10000, 20000);
+	}
+
+	return test_bit(state, &vf->vf_states);
+}
+
+/**
  * i40e_vc_get_version_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -1838,6 +2015,25 @@
 }
 
 /**
+ * i40e_vc_get_max_frame_size
+ * @vf: pointer to the VF
+ *
+ * Max frame size is determined based on the current port's max frame size and
+ * whether a port VLAN is configured on this VF. The VF is not aware whether
+ * it's in a port VLAN so the PF needs to account for this in max frame size
+ * checks and sending the max frame size to the VF.
+ **/
+static u16 i40e_vc_get_max_frame_size(struct i40e_vf *vf)
+{
+	u16 max_frame_size = vf->pf->hw.phy.link_info.max_frame_size;
+
+	if (vf->port_vlan_id)
+		max_frame_size -= VLAN_HLEN;
+
+	return max_frame_size;
+}
+
+/**
  * i40e_vc_get_vf_resources_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -1854,7 +2050,7 @@
 	size_t len = 0;
 	int ret;
 
-	if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_INIT)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -1937,6 +2133,7 @@
 	vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
 	vfres->rss_key_size = I40E_HKEY_ARRAY_SIZE;
 	vfres->rss_lut_size = I40E_VF_HLUT_ARRAY_SIZE;
+	vfres->max_mtu = i40e_vc_get_max_frame_size(vf);
 
 	if (vf->lan_vsi_idx) {
 		vfres->vsi_res[0].vsi_id = vf->lan_vsi_id;
@@ -1960,39 +2157,6 @@
 }
 
 /**
- * i40e_vc_reset_vf_msg
- * @vf: pointer to the VF info
- *
- * called from the VF to reset itself,
- * unlike other virtchnl messages, PF driver
- * doesn't send the response back to the VF
- **/
-static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
-{
-	if (test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
-		i40e_reset_vf(vf, false);
-}
-
-/**
- * i40e_getnum_vf_vsi_vlan_filters
- * @vsi: pointer to the vsi
- *
- * called to get the number of VLANs offloaded on this VF
- **/
-static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
-{
-	struct i40e_mac_filter *f;
-	int num_vlans = 0, bkt;
-
-	hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-		if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
-			num_vlans++;
-	}
-
-	return num_vlans;
-}
-
-/**
  * i40e_vc_config_promiscuous_mode_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -2009,7 +2173,7 @@
 	bool allmulti = false;
 	bool alluni = false;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err_out;
 	}
@@ -2090,13 +2254,14 @@
 	struct virtchnl_vsi_queue_config_info *qci =
 	    (struct virtchnl_vsi_queue_config_info *)msg;
 	struct virtchnl_queue_pair_info *qpi;
-	struct i40e_pf *pf = vf->pf;
 	u16 vsi_id, vsi_queue_id = 0;
-	u16 num_qps_all = 0;
+	struct i40e_pf *pf = vf->pf;
 	i40e_status aq_ret = 0;
 	int i, j = 0, idx = 0;
+	struct i40e_vsi *vsi;
+	u16 num_qps_all = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2112,7 +2277,7 @@
 	}
 
 	if (vf->adq_enabled) {
-		for (i = 0; i < I40E_MAX_VF_VSI; i++)
+		for (i = 0; i < vf->num_tc; i++)
 			num_qps_all += vf->ch[i].num_qps;
 		if (num_qps_all != qci->num_queue_pairs) {
 			aq_ret = I40E_ERR_PARAM;
@@ -2183,9 +2348,15 @@
 		pf->vsi[vf->lan_vsi_idx]->num_queue_pairs =
 			qci->num_queue_pairs;
 	} else {
-		for (i = 0; i < vf->num_tc; i++)
-			pf->vsi[vf->ch[i].vsi_idx]->num_queue_pairs =
-			       vf->ch[i].num_qps;
+		for (i = 0; i < vf->num_tc; i++) {
+			vsi = pf->vsi[vf->ch[i].vsi_idx];
+			vsi->num_queue_pairs = vf->ch[i].num_qps;
+
+			if (i40e_update_adq_vsi_queues(vsi, i)) {
+				aq_ret = I40E_ERR_CONFIG;
+				goto error_param;
+			}
+		}
 	}
 
 error_param:
@@ -2238,7 +2409,7 @@
 	i40e_status aq_ret = 0;
 	int i;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2323,6 +2494,22 @@
 }
 
 /**
+ * i40e_vc_validate_vqs_bitmaps - validate Rx/Tx queue bitmaps from VIRTHCHNL
+ * @vqs: virtchnl_queue_select structure containing bitmaps to validate
+ *
+ * Returns true if validation was successful, else false.
+ */
+static bool i40e_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs)
+{
+	if ((!vqs->rx_queues && !vqs->tx_queues) ||
+	    vqs->rx_queues >= BIT(I40E_MAX_VF_QUEUES) ||
+	    vqs->tx_queues >= BIT(I40E_MAX_VF_QUEUES))
+		return false;
+
+	return true;
+}
+
+/**
  * i40e_vc_enable_queues_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -2347,7 +2534,7 @@
 		goto error_param;
 	}
 
-	if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
+	if (!i40e_vc_validate_vqs_bitmaps(vqs)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2373,8 +2560,6 @@
 		}
 	}
 
-	vf->queues_enabled = true;
-
 error_param:
 	/* send the response to the VF */
 	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
@@ -2396,10 +2581,7 @@
 	struct i40e_pf *pf = vf->pf;
 	i40e_status aq_ret = 0;
 
-	/* Immediately mark queues as disabled */
-	vf->queues_enabled = false;
-
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2409,9 +2591,7 @@
 		goto error_param;
 	}
 
-	if ((vqs->rx_queues == 0 && vqs->tx_queues == 0) ||
-	    vqs->rx_queues > I40E_MAX_VF_QUEUES ||
-	    vqs->tx_queues > I40E_MAX_VF_QUEUES) {
+	if (!i40e_vc_validate_vqs_bitmaps(vqs)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2434,6 +2614,59 @@
 }
 
 /**
+ * i40e_check_enough_queue - find big enough queue number
+ * @vf: pointer to the VF info
+ * @needed: the number of items needed
+ *
+ * Returns the base item index of the queue, or negative for error
+ **/
+static int i40e_check_enough_queue(struct i40e_vf *vf, u16 needed)
+{
+	unsigned int  i, cur_queues, more, pool_size;
+	struct i40e_lump_tracking *pile;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi;
+
+	vsi = pf->vsi[vf->lan_vsi_idx];
+	cur_queues = vsi->alloc_queue_pairs;
+
+	/* if current allocated queues are enough for need */
+	if (cur_queues >= needed)
+		return vsi->base_queue;
+
+	pile = pf->qp_pile;
+	if (cur_queues > 0) {
+		/* if the allocated queues are not zero
+		 * just check if there are enough queues for more
+		 * behind the allocated queues.
+		 */
+		more = needed - cur_queues;
+		for (i = vsi->base_queue + cur_queues;
+			i < pile->num_entries; i++) {
+			if (pile->list[i] & I40E_PILE_VALID_BIT)
+				break;
+
+			if (more-- == 1)
+				/* there is enough */
+				return vsi->base_queue;
+		}
+	}
+
+	pool_size = 0;
+	for (i = 0; i < pile->num_entries; i++) {
+		if (pile->list[i] & I40E_PILE_VALID_BIT) {
+			pool_size = 0;
+			continue;
+		}
+		if (needed <= ++pool_size)
+			/* there is enough */
+			return i;
+	}
+
+	return -ENOMEM;
+}
+
+/**
  * i40e_vc_request_queues_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -2451,7 +2684,7 @@
 	u8 cur_pairs = vf->num_queue_pairs;
 	struct i40e_pf *pf = vf->pf;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE))
 		return -EINVAL;
 
 	if (req_pairs > I40E_MAX_VF_QUEUES) {
@@ -2467,11 +2700,16 @@
 			 req_pairs - cur_pairs,
 			 pf->queues_left);
 		vfres->num_queue_pairs = pf->queues_left + cur_pairs;
+	} else if (i40e_check_enough_queue(vf, req_pairs) < 0) {
+		dev_warn(&pf->pdev->dev,
+			 "VF %d requested %d more queues, but there is not enough for it.\n",
+			 vf->vf_id,
+			 req_pairs - cur_pairs);
+		vfres->num_queue_pairs = cur_pairs;
 	} else {
 		/* successful request */
 		vf->num_req_queues = req_pairs;
-		i40e_vc_notify_vf_reset(vf);
-		i40e_reset_vf(vf, false);
+		i40e_vc_reset_vf(vf, true);
 		return 0;
 	}
 
@@ -2497,7 +2735,7 @@
 
 	memset(&stats, 0, sizeof(struct i40e_eth_stats));
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
@@ -2606,7 +2844,7 @@
 	i40e_status ret = 0;
 	int i;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
 	    !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
 		ret = I40E_ERR_PARAM;
 		goto error_param;
@@ -2675,7 +2913,7 @@
 	i40e_status ret = 0;
 	int i;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
 	    !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
 		ret = I40E_ERR_PARAM;
 		goto error_param;
@@ -2814,7 +3052,7 @@
 	i40e_status aq_ret = 0;
 	int i;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
 	    !i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
@@ -2934,9 +3172,9 @@
 	struct i40e_vsi *vsi = NULL;
 	i40e_status aq_ret = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
 	    !i40e_vc_isvalid_vsi_id(vf, vrk->vsi_id) ||
-	    (vrk->key_len != I40E_HKEY_ARRAY_SIZE)) {
+	    vrk->key_len != I40E_HKEY_ARRAY_SIZE) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -2965,9 +3203,9 @@
 	i40e_status aq_ret = 0;
 	u16 i;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
 	    !i40e_vc_isvalid_vsi_id(vf, vrl->vsi_id) ||
-	    (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)) {
+	    vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3000,7 +3238,7 @@
 	i40e_status aq_ret = 0;
 	int len = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3036,7 +3274,7 @@
 	struct i40e_hw *hw = &pf->hw;
 	i40e_status aq_ret = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3061,7 +3299,7 @@
 	i40e_status aq_ret = 0;
 	struct i40e_vsi *vsi;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3087,7 +3325,7 @@
 	i40e_status aq_ret = 0;
 	struct i40e_vsi *vsi;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3120,16 +3358,16 @@
 	bool found = false;
 	int bkt;
 
-	if (!tc_filter->action) {
+	if (tc_filter->action != VIRTCHNL_ACTION_TC_REDIRECT) {
 		dev_info(&pf->pdev->dev,
-			 "VF %d: Currently ADq doesn't support Drop Action\n",
-			 vf->vf_id);
+			 "VF %d: ADQ doesn't support this action (%d)\n",
+			 vf->vf_id, tc_filter->action);
 		goto err;
 	}
 
 	/* action_meta is TC number here to which the filter is applied */
 	if (!tc_filter->action_meta ||
-	    tc_filter->action_meta > I40E_MAX_VF_VSI) {
+	    tc_filter->action_meta > vf->num_tc) {
 		dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n",
 			 vf->vf_id, tc_filter->action_meta);
 		goto err;
@@ -3314,7 +3552,7 @@
 	i40e_status aq_ret = 0;
 	int i, ret;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3445,7 +3683,7 @@
 	i40e_status aq_ret = 0;
 	int i, ret;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err_out;
 	}
@@ -3554,7 +3792,7 @@
 	i40e_status aq_ret = 0;
 	u64 speed = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3661,15 +3899,9 @@
 
 	/* set this flag only after making sure all inputs are sane */
 	vf->adq_enabled = true;
-	/* num_req_queues is set when user changes number of queues via ethtool
-	 * and this causes issue for default VSI(which depends on this variable)
-	 * when ADq is enabled, hence reset it.
-	 */
-	vf->num_req_queues = 0;
 
 	/* reset the VF in order to allocate resources */
-	i40e_vc_notify_vf_reset(vf);
-	i40e_reset_vf(vf, false);
+	i40e_vc_reset_vf(vf, true);
 
 	return I40E_SUCCESS;
 
@@ -3689,7 +3921,7 @@
 	struct i40e_pf *pf = vf->pf;
 	i40e_status aq_ret = 0;
 
-	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+	if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto err;
 	}
@@ -3709,8 +3941,7 @@
 	}
 
 	/* reset the VF in order to allocate resources */
-	i40e_vc_notify_vf_reset(vf);
-	i40e_reset_vf(vf, false);
+	i40e_vc_reset_vf(vf, true);
 
 	return I40E_SUCCESS;
 
@@ -3772,7 +4003,7 @@
 		i40e_vc_notify_vf_link_state(vf);
 		break;
 	case VIRTCHNL_OP_RESET_VF:
-		i40e_vc_reset_vf_msg(vf);
+		i40e_vc_reset_vf(vf, false);
 		ret = 0;
 		break;
 	case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
@@ -3962,20 +4193,16 @@
 		goto error_param;
 
 	vf = &pf->vf[vf_id];
-	vsi = pf->vsi[vf->lan_vsi_idx];
 
 	/* When the VF is resetting wait until it is done.
 	 * It can take up to 200 milliseconds,
 	 * but wait for up to 300 milliseconds to be safe.
-	 * If the VF is indeed in reset, the vsi pointer has
-	 * to show on the newly loaded vsi under pf->vsi[id].
+	 * Acquire the VSI pointer only after the VF has been
+	 * properly initialized.
 	 */
 	for (i = 0; i < 15; i++) {
-		if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-			if (i > 0)
-				vsi = pf->vsi[vf->lan_vsi_idx];
+		if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
 			break;
-		}
 		msleep(20);
 	}
 	if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
@@ -3984,6 +4211,7 @@
 		ret = -EAGAIN;
 		goto error_param;
 	}
+	vsi = pf->vsi[vf->lan_vsi_idx];
 
 	if (is_multicast_ether_addr(mac)) {
 		dev_err(&pf->pdev->dev,
@@ -4029,7 +4257,7 @@
 	/* Force the VF interface down so it has to bring up with new MAC
 	 * address
 	 */
-	i40e_vc_disable_vf(vf);
+	i40e_vc_reset_vf(vf, true);
 	dev_info(&pf->pdev->dev, "Bring down and up the VF interface to make this change effective.\n");
 
 error_param:
@@ -4038,34 +4266,6 @@
 }
 
 /**
- * i40e_vsi_has_vlans - True if VSI has configured VLANs
- * @vsi: pointer to the vsi
- *
- * Check if a VSI has configured any VLANs. False if we have a port VLAN or if
- * we have no configured VLANs. Do not call while holding the
- * mac_filter_hash_lock.
- */
-static bool i40e_vsi_has_vlans(struct i40e_vsi *vsi)
-{
-	bool have_vlans;
-
-	/* If we have a port VLAN, then the VSI cannot have any VLANs
-	 * configured, as all MAC/VLAN filters will be assigned to the PVID.
-	 */
-	if (vsi->info.pvid)
-		return false;
-
-	/* Since we don't have a PVID, we know that if the device is in VLAN
-	 * mode it must be because of a VLAN filter configured on this VSI.
-	 */
-	spin_lock_bh(&vsi->mac_filter_hash_lock);
-	have_vlans = i40e_is_vsi_in_vlan(vsi);
-	spin_unlock_bh(&vsi->mac_filter_hash_lock);
-
-	return have_vlans;
-}
-
-/**
  * i40e_ndo_set_vf_port_vlan
  * @netdev: network interface device structure
  * @vf_id: VF identifier
@@ -4121,19 +4321,6 @@
 		/* duplicate request, so just return success */
 		goto error_pvid;
 
-	if (i40e_vsi_has_vlans(vsi)) {
-		dev_err(&pf->pdev->dev,
-			"VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
-			vf_id);
-		/* Administrator Error - knock the VF offline until he does
-		 * the right thing by reconfiguring his network correctly
-		 * and then reloading the VF driver.
-		 */
-		i40e_vc_disable_vf(vf);
-		/* During reset the VF got a new VSI, so refresh the pointer. */
-		vsi = pf->vsi[vf->lan_vsi_idx];
-	}
-
 	/* Locked once because multiple functions below iterate list */
 	spin_lock_bh(&vsi->mac_filter_hash_lock);
 
@@ -4219,6 +4406,10 @@
 	 */
 	vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
 
+	i40e_vc_reset_vf(vf, true);
+	/* During reset the VF got a new VSI, so refresh a pointer. */
+	vsi = pf->vsi[vf->lan_vsi_idx];
+
 	ret = i40e_config_vf_promiscuous_mode(vf, vsi->id, allmulti, alluni);
 	if (ret) {
 		dev_err(&pf->pdev->dev, "Unable to config vf promiscuous mode\n");
@@ -4514,7 +4705,7 @@
 		goto out;
 
 	vf->trusted = setting;
-	i40e_vc_disable_vf(vf);
+	i40e_vc_reset_vf(vf, true);
 	dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
 		 vf_id, setting ? "" : "un");
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -19,6 +19,8 @@
 
 #define I40E_MAX_VF_PROMISC_FLAGS	3
 
+#define I40E_VF_STATE_WAIT_COUNT	20
+
 /* Various queue ctrls */
 enum i40e_queue_ctrl {
 	I40E_QUEUE_CTRL_UNKNOWN = 0,
@@ -39,6 +41,7 @@
 	I40E_VF_STATE_MC_PROMISC,
 	I40E_VF_STATE_UC_PROMISC,
 	I40E_VF_STATE_PRE_ENABLE,
+	I40E_VF_STATE_RESETTING
 };
 
 /* VF capabilities */
@@ -99,7 +102,6 @@
 	unsigned int tx_rate;	/* Tx bandwidth limit in Mbps */
 	bool link_forced;
 	bool link_up;		/* only valid if VF link is forced */
-	bool queues_enabled;	/* true if the VF queues are enabled */
 	bool spoofchk;
 	u16 num_mac;
 	u16 num_vlan;
@@ -139,5 +141,8 @@
 
 void i40e_vc_notify_link_state(struct i40e_pf *pf);
 void i40e_vc_notify_reset(struct i40e_pf *pf);
+#ifdef CONFIG_PCI_IOV
+void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev);
+#endif /* CONFIG_PCI_IOV */
 
 #endif /* _I40E_VIRTCHNL_PF_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -9,6 +9,11 @@
 #include "i40e_txrx_common.h"
 #include "i40e_xsk.h"
 
+static struct i40e_rx_buffer *i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx)
+{
+	return &rx_ring->rx_bi[idx];
+}
+
 /**
  * i40e_xsk_umem_dma_map - DMA maps all UMEM memory for the netdev
  * @vsi: Current VSI
@@ -207,21 +212,28 @@
 
 	xdp->handle = xsk_umem_adjust_offset(umem, xdp->handle, offset);
 
+	if (likely(act == XDP_REDIRECT)) {
+		err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
+		if (err)
+			goto out_failure;
+		rcu_read_unlock();
+		return I40E_XDP_REDIR;
+	}
+
 	switch (act) {
 	case XDP_PASS:
 		break;
 	case XDP_TX:
 		xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
 		result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
-		break;
-	case XDP_REDIRECT:
-		err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
-		result = !err ? I40E_XDP_REDIR : I40E_XDP_CONSUMED;
+		if (result == I40E_XDP_CONSUMED)
+			goto out_failure;
 		break;
 	default:
 		bpf_warn_invalid_xdp_action(act);
 		/* fall through */
 	case XDP_ABORTED:
+out_failure:
 		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
 		/* fallthrough -- handle aborts by dropping packet */
 	case XDP_DROP:
@@ -321,7 +333,7 @@
 	bool ok = true;
 
 	rx_desc = I40E_RX_DESC(rx_ring, ntu);
-	bi = &rx_ring->rx_bi[ntu];
+	bi = i40e_rx_bi(rx_ring, ntu);
 	do {
 		if (!alloc(rx_ring, bi)) {
 			ok = false;
@@ -340,7 +352,7 @@
 
 		if (unlikely(ntu == rx_ring->count)) {
 			rx_desc = I40E_RX_DESC(rx_ring, 0);
-			bi = rx_ring->rx_bi;
+			bi = i40e_rx_bi(rx_ring, 0);
 			ntu = 0;
 		}
 
@@ -402,7 +414,7 @@
 {
 	struct i40e_rx_buffer *bi;
 
-	bi = &rx_ring->rx_bi[rx_ring->next_to_clean];
+	bi = i40e_rx_bi(rx_ring, rx_ring->next_to_clean);
 
 	/* we are reusing so sync this buffer for CPU use */
 	dma_sync_single_range_for_cpu(rx_ring->dev,
@@ -424,7 +436,8 @@
 static void i40e_reuse_rx_buffer_zc(struct i40e_ring *rx_ring,
 				    struct i40e_rx_buffer *old_bi)
 {
-	struct i40e_rx_buffer *new_bi = &rx_ring->rx_bi[rx_ring->next_to_alloc];
+	struct i40e_rx_buffer *new_bi = i40e_rx_bi(rx_ring,
+						   rx_ring->next_to_alloc);
 	u16 nta = rx_ring->next_to_alloc;
 
 	/* update, and store next to alloc */
@@ -456,7 +469,7 @@
 	mask = rx_ring->xsk_umem->chunk_mask;
 
 	nta = rx_ring->next_to_alloc;
-	bi = &rx_ring->rx_bi[nta];
+	bi = i40e_rx_bi(rx_ring, nta);
 
 	nta++;
 	rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
@@ -492,13 +505,11 @@
 	struct sk_buff *skb;
 
 	/* allocate a skb to store the frags */
-	skb = __napi_alloc_skb(&rx_ring->q_vector->napi,
-			       xdp->data_end - xdp->data_hard_start,
+	skb = __napi_alloc_skb(&rx_ring->q_vector->napi, datasize,
 			       GFP_ATOMIC | __GFP_NOWARN);
 	if (unlikely(!skb))
 		return NULL;
 
-	skb_reserve(skb, xdp->data - xdp->data_hard_start);
 	memcpy(__skb_put(skb, datasize), xdp->data, datasize);
 	if (metasize)
 		skb_metadata_set(skb, metasize);
@@ -787,8 +798,12 @@
 {
 	struct i40e_netdev_priv *np = netdev_priv(dev);
 	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
 	struct i40e_ring *ring;
 
+	if (test_bit(__I40E_CONFIG_BUSY, pf->state))
+		return -EAGAIN;
+
 	if (test_bit(__I40E_VSI_DOWN, vsi->state))
 		return -ENETDOWN;
 
@@ -820,7 +835,7 @@
 	u16 i;
 
 	for (i = 0; i < rx_ring->count; i++) {
-		struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
+		struct i40e_rx_buffer *rx_bi = i40e_rx_bi(rx_ring, i);
 
 		if (!rx_bi->addr)
 			continue;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf.h
@@ -86,6 +86,11 @@
 #define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
 #define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4)
 #define IAVF_MBPS_DIVISOR	125000 /* divisor to convert to Mbps */
+#define IAVF_MBPS_QUANTA	50
+
+#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE (sizeof(struct virtchnl_vf_resource) + \
+					(IAVF_MAX_VF_VSI * \
+					 sizeof(struct virtchnl_vsi_resource)))
 
 /* MAX_MSIX_Q_VECTORS of these are allocated,
  * but we only use one per queue-specific vector.
@@ -130,6 +135,7 @@
 struct iavf_mac_filter {
 	struct list_head list;
 	u8 macaddr[ETH_ALEN];
+	bool is_new_mac;	/* filter is new, wait for PF decision */
 	bool remove;		/* filter needs to be removed */
 	bool add;		/* filter needs to be added */
 };
@@ -306,6 +312,14 @@
 	bool netdev_registered;
 	bool link_up;
 	enum virtchnl_link_speed link_speed;
+	/* This is only populated if the VIRTCHNL_VF_CAP_ADV_LINK_SPEED is set
+	 * in vf_res->vf_cap_flags. Use ADV_LINK_SUPPORT macro to determine if
+	 * this field is valid. This field should be used going forward and the
+	 * enum virtchnl_link_speed above should be considered the legacy way of
+	 * storing/communicating link speeds.
+	 */
+	u32 link_speed_mbps;
+
 	enum virtchnl_ops current_op;
 #define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \
 			    (_a)->vf_res->vf_cap_flags & \
@@ -322,6 +336,8 @@
 			VIRTCHNL_VF_OFFLOAD_RSS_PF)))
 #define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
 			  VIRTCHNL_VF_OFFLOAD_VLAN)
+#define ADV_LINK_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
+			      VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
 	struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
 	struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
 	struct virtchnl_version_info pf_version;
@@ -369,7 +385,7 @@
 void iavf_update_stats(struct iavf_adapter *adapter);
 void iavf_reset_interrupt_capability(struct iavf_adapter *adapter);
 int iavf_init_interrupt_scheme(struct iavf_adapter *adapter);
-void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask);
+void iavf_irq_enable_queues(struct iavf_adapter *adapter);
 void iavf_free_all_tx_resources(struct iavf_adapter *adapter);
 void iavf_free_all_rx_resources(struct iavf_adapter *adapter);
 
@@ -415,4 +431,6 @@
 void iavf_disable_channels(struct iavf_adapter *adapter);
 void iavf_add_cloud_filter(struct iavf_adapter *adapter);
 void iavf_del_cloud_filter(struct iavf_adapter *adapter);
+struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+					const u8 *macaddr);
 #endif /* _IAVF_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_adminq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_adminq.c
@@ -324,6 +324,7 @@
 static enum iavf_status iavf_init_asq(struct iavf_hw *hw)
 {
 	enum iavf_status ret_code = 0;
+	int i;
 
 	if (hw->aq.asq.count > 0) {
 		/* queue already initialized */
@@ -354,12 +355,17 @@
 	/* initialize base registers */
 	ret_code = iavf_config_asq_regs(hw);
 	if (ret_code)
-		goto init_adminq_free_rings;
+		goto init_free_asq_bufs;
 
 	/* success! */
 	hw->aq.asq.count = hw->aq.num_asq_entries;
 	goto init_adminq_exit;
 
+init_free_asq_bufs:
+	for (i = 0; i < hw->aq.num_asq_entries; i++)
+		iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+	iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
+
 init_adminq_free_rings:
 	iavf_free_adminq_asq(hw);
 
@@ -383,6 +389,7 @@
 static enum iavf_status iavf_init_arq(struct iavf_hw *hw)
 {
 	enum iavf_status ret_code = 0;
+	int i;
 
 	if (hw->aq.arq.count > 0) {
 		/* queue already initialized */
@@ -413,12 +420,16 @@
 	/* initialize base registers */
 	ret_code = iavf_config_arq_regs(hw);
 	if (ret_code)
-		goto init_adminq_free_rings;
+		goto init_free_arq_bufs;
 
 	/* success! */
 	hw->aq.arq.count = hw->aq.num_arq_entries;
 	goto init_adminq_exit;
 
+init_free_arq_bufs:
+	for (i = 0; i < hw->aq.num_arq_entries; i++)
+		iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+	iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
 init_adminq_free_rings:
 	iavf_free_adminq_arq(hw);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -662,7 +662,7 @@
 	/* Non Tunneled IPv6 */
 	IAVF_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
 	IAVF_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
-	IAVF_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3),
+	IAVF_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY4),
 	IAVF_PTT_UNUSED_ENTRY(91),
 	IAVF_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4),
 	IAVF_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -278,7 +278,18 @@
 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
 	cmd->base.autoneg = AUTONEG_DISABLE;
 	cmd->base.port = PORT_NONE;
-	/* Set speed and duplex */
+	cmd->base.duplex = DUPLEX_FULL;
+
+	if (ADV_LINK_SUPPORT(adapter)) {
+		if (adapter->link_speed_mbps &&
+		    adapter->link_speed_mbps < U32_MAX)
+			cmd->base.speed = adapter->link_speed_mbps;
+		else
+			cmd->base.speed = SPEED_UNKNOWN;
+
+		return 0;
+	}
+
 	switch (adapter->link_speed) {
 	case IAVF_LINK_SPEED_40GB:
 		cmd->base.speed = SPEED_40000;
@@ -306,7 +317,6 @@
 	default:
 		break;
 	}
-	cmd->base.duplex = DUPLEX_FULL;
 
 	return 0;
 }
@@ -602,23 +612,44 @@
 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
 		return -EINVAL;
 
-	new_tx_count = clamp_t(u32, ring->tx_pending,
-			       IAVF_MIN_TXD,
-			       IAVF_MAX_TXD);
-	new_tx_count = ALIGN(new_tx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
-
-	new_rx_count = clamp_t(u32, ring->rx_pending,
-			       IAVF_MIN_RXD,
-			       IAVF_MAX_RXD);
-	new_rx_count = ALIGN(new_rx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+	if (ring->tx_pending > IAVF_MAX_TXD ||
+	    ring->tx_pending < IAVF_MIN_TXD ||
+	    ring->rx_pending > IAVF_MAX_RXD ||
+	    ring->rx_pending < IAVF_MIN_RXD) {
+		netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
+			   ring->tx_pending, ring->rx_pending, IAVF_MIN_TXD,
+			   IAVF_MAX_RXD, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+		return -EINVAL;
+	}
+
+	new_tx_count = ALIGN(ring->tx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+	if (new_tx_count != ring->tx_pending)
+		netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",
+			    new_tx_count);
+
+	new_rx_count = ALIGN(ring->rx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+	if (new_rx_count != ring->rx_pending)
+		netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",
+			    new_rx_count);
 
 	/* if nothing to do return success */
 	if ((new_tx_count == adapter->tx_desc_count) &&
-	    (new_rx_count == adapter->rx_desc_count))
+	    (new_rx_count == adapter->rx_desc_count)) {
+		netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n");
 		return 0;
+	}
+
+	if (new_tx_count != adapter->tx_desc_count) {
+		netdev_dbg(netdev, "Changing Tx descriptor count from %d to %d\n",
+			   adapter->tx_desc_count, new_tx_count);
+		adapter->tx_desc_count = new_tx_count;
+	}
 
-	adapter->tx_desc_count = new_tx_count;
-	adapter->rx_desc_count = new_rx_count;
+	if (new_rx_count != adapter->rx_desc_count) {
+		netdev_dbg(netdev, "Changing Rx descriptor count from %d to %d\n",
+			   adapter->rx_desc_count, new_rx_count);
+		adapter->rx_desc_count = new_rx_count;
+	}
 
 	if (netif_running(netdev)) {
 		adapter->flags |= IAVF_FLAG_RESET_NEEDED;
@@ -709,12 +740,31 @@
  *
  * Change the ITR settings for a specific queue.
  **/
-static void iavf_set_itr_per_queue(struct iavf_adapter *adapter,
-				   struct ethtool_coalesce *ec, int queue)
+static int iavf_set_itr_per_queue(struct iavf_adapter *adapter,
+				  struct ethtool_coalesce *ec, int queue)
 {
 	struct iavf_ring *rx_ring = &adapter->rx_rings[queue];
 	struct iavf_ring *tx_ring = &adapter->tx_rings[queue];
 	struct iavf_q_vector *q_vector;
+	u16 itr_setting;
+
+	itr_setting = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
+
+	if (ec->rx_coalesce_usecs != itr_setting &&
+	    ec->use_adaptive_rx_coalesce) {
+		netif_info(adapter, drv, adapter->netdev,
+			   "Rx interrupt throttling cannot be changed if adaptive-rx is enabled\n");
+		return -EINVAL;
+	}
+
+	itr_setting = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
+
+	if (ec->tx_coalesce_usecs != itr_setting &&
+	    ec->use_adaptive_tx_coalesce) {
+		netif_info(adapter, drv, adapter->netdev,
+			   "Tx interrupt throttling cannot be changed if adaptive-tx is enabled\n");
+		return -EINVAL;
+	}
 
 	rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
 	tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
@@ -737,6 +787,7 @@
 	 * the Tx and Rx ITR values based on the values we have entered
 	 * into the q_vector, no need to write the values now.
 	 */
+	return 0;
 }
 
 /**
@@ -778,9 +829,11 @@
 	 */
 	if (queue < 0) {
 		for (i = 0; i < adapter->num_active_queues; i++)
-			iavf_set_itr_per_queue(adapter, ec, i);
+			if (iavf_set_itr_per_queue(adapter, ec, i))
+				return -EINVAL;
 	} else if (queue < adapter->num_active_queues) {
-		iavf_set_itr_per_queue(adapter, ec, queue);
+		if (iavf_set_itr_per_queue(adapter, ec, queue))
+			return -EINVAL;
 	} else {
 		netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
 			   adapter->num_active_queues - 1);
@@ -952,14 +1005,13 @@
 
 	if (hfunc)
 		*hfunc = ETH_RSS_HASH_TOP;
-	if (!indir)
-		return 0;
-
-	memcpy(key, adapter->rss_key, adapter->rss_key_size);
+	if (key)
+		memcpy(key, adapter->rss_key, adapter->rss_key_size);
 
-	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
-	for (i = 0; i < adapter->rss_lut_size; i++)
-		indir[i] = (u32)adapter->rss_lut[i];
+	if (indir)
+		/* Each 32 bits pointed by 'indir' is stored with a lut entry */
+		for (i = 0; i < adapter->rss_lut_size; i++)
+			indir[i] = (u32)adapter->rss_lut[i];
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -143,6 +143,30 @@
 }
 
 /**
+ * iavf_lock_timeout - try to set bit but give up after timeout
+ * @adapter: board private structure
+ * @bit: bit to set
+ * @msecs: timeout in msecs
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int iavf_lock_timeout(struct iavf_adapter *adapter,
+			     enum iavf_critical_section_t bit,
+			     unsigned int msecs)
+{
+	unsigned int wait, delay = 10;
+
+	for (wait = 0; wait < msecs; wait += delay) {
+		if (!test_and_set_bit(bit, &adapter->crit_section))
+			return 0;
+
+		msleep(delay);
+	}
+
+	return -1;
+}
+
+/**
  * iavf_schedule_reset - Set the flags and schedule a reset event
  * @adapter: board private structure
  **/
@@ -220,21 +244,18 @@
 }
 
 /**
- * iavf_irq_enable_queues - Enable interrupt for specified queues
+ * iavf_irq_enable_queues - Enable interrupt for all queues
  * @adapter: board private structure
- * @mask: bitmap of queues to enable
  **/
-void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask)
+void iavf_irq_enable_queues(struct iavf_adapter *adapter)
 {
 	struct iavf_hw *hw = &adapter->hw;
 	int i;
 
 	for (i = 1; i < adapter->num_msix_vectors; i++) {
-		if (mask & BIT(i - 1)) {
-			wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
-			     IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
-			     IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
-		}
+		wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
+		     IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
+		     IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
 	}
 }
 
@@ -248,7 +269,7 @@
 	struct iavf_hw *hw = &adapter->hw;
 
 	iavf_misc_irq_enable(adapter);
-	iavf_irq_enable_queues(adapter, ~0);
+	iavf_irq_enable_queues(adapter);
 
 	if (flush)
 		iavf_flush(hw);
@@ -743,9 +764,8 @@
  *
  * Returns ptr to the filter object or NULL when no memory available.
  **/
-static struct
-iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
-				 const u8 *macaddr)
+struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+					const u8 *macaddr)
 {
 	struct iavf_mac_filter *f;
 
@@ -762,6 +782,7 @@
 
 		list_add_tail(&f->list, &adapter->mac_filter_list);
 		f->add = true;
+		f->is_new_mac = true;
 		adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
 	} else {
 		f->remove = false;
@@ -1368,19 +1389,16 @@
 static void iavf_free_q_vectors(struct iavf_adapter *adapter)
 {
 	int q_idx, num_q_vectors;
-	int napi_vectors;
 
 	if (!adapter->q_vectors)
 		return;
 
 	num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
-	napi_vectors = adapter->num_active_queues;
 
 	for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
 		struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx];
 
-		if (q_idx < napi_vectors)
-			netif_napi_del(&q_vector->napi);
+		netif_napi_del(&q_vector->napi);
 	}
 	kfree(adapter->q_vectors);
 	adapter->q_vectors = NULL;
@@ -1500,11 +1518,6 @@
 	set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
 
 	iavf_map_rings_to_vectors(adapter);
-
-	if (RSS_AQ(adapter))
-		adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
-	else
-		err = iavf_init_rss(adapter);
 err:
 	return err;
 }
@@ -1607,8 +1620,7 @@
 		iavf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC);
 		return 0;
 	}
-
-	if ((adapter->aq_required & IAVF_FLAG_AQ_RELEASE_PROMISC) &&
+	if ((adapter->aq_required & IAVF_FLAG_AQ_RELEASE_PROMISC) ||
 	    (adapter->aq_required & IAVF_FLAG_AQ_RELEASE_ALLMULTI)) {
 		iavf_set_promiscuous(adapter, 0);
 		return 0;
@@ -1757,17 +1769,17 @@
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 	struct iavf_hw *hw = &adapter->hw;
-	int err = 0, bufsz;
+	int err;
 
 	WARN_ON(adapter->state != __IAVF_INIT_GET_RESOURCES);
 	/* aq msg sent, awaiting reply */
 	if (!adapter->vf_res) {
-		bufsz = sizeof(struct virtchnl_vf_resource) +
-			(IAVF_MAX_VF_VSI *
-			sizeof(struct virtchnl_vsi_resource));
-		adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
-		if (!adapter->vf_res)
+		adapter->vf_res = kzalloc(IAVF_VIRTCHNL_VF_RESOURCE_SIZE,
+					  GFP_KERNEL);
+		if (!adapter->vf_res) {
+			err = -ENOMEM;
 			goto err;
+		}
 	}
 	err = iavf_get_vf_config(adapter);
 	if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
@@ -1787,7 +1799,8 @@
 		goto err_alloc;
 	}
 
-	if (iavf_process_config(adapter))
+	err = iavf_process_config(adapter);
+	if (err)
 		goto err_alloc;
 	adapter->current_op = VIRTCHNL_OP_UNKNOWN;
 
@@ -1845,11 +1858,9 @@
 	netif_tx_stop_all_queues(netdev);
 	if (CLIENT_ALLOWED(adapter)) {
 		err = iavf_lan_add_device(adapter);
-		if (err) {
-			rtnl_unlock();
+		if (err)
 			dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
 				 err);
-		}
 	}
 	dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
 	if (netdev->features & NETIF_F_GRO)
@@ -1864,8 +1875,10 @@
 
 	adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL);
 	adapter->rss_lut = kzalloc(adapter->rss_lut_size, GFP_KERNEL);
-	if (!adapter->rss_key || !adapter->rss_lut)
+	if (!adapter->rss_key || !adapter->rss_lut) {
+		err = -ENOMEM;
 		goto err_mem;
+	}
 	if (RSS_AQ(adapter))
 		adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
 	else
@@ -1947,7 +1960,10 @@
 				iavf_send_api_ver(adapter);
 			}
 		} else {
-			if (!iavf_process_aq_command(adapter) &&
+			/* An error will be returned if no commands were
+			 * processed; use this opportunity to update stats
+			 */
+			if (iavf_process_aq_command(adapter) &&
 			    adapter->state == __IAVF_RUNNING)
 				iavf_request_stats(adapter);
 		}
@@ -1962,7 +1978,6 @@
 		/* check for hw reset */
 	reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
 	if (!reg_val) {
-		adapter->state = __IAVF_RESETTING;
 		adapter->flags |= IAVF_FLAG_RESET_PENDING;
 		adapter->aq_required = 0;
 		adapter->current_op = VIRTCHNL_OP_UNKNOWN;
@@ -2035,9 +2050,9 @@
 
 	iavf_free_misc_irq(adapter);
 	iavf_reset_interrupt_capability(adapter);
-	iavf_free_queues(adapter);
 	iavf_free_q_vectors(adapter);
-	kfree(adapter->vf_res);
+	iavf_free_queues(adapter);
+	memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE);
 	iavf_shutdown_adminq(&adapter->hw);
 	adapter->netdev->flags &= ~IFF_UP;
 	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
@@ -2065,9 +2080,9 @@
 	struct virtchnl_vf_resource *vfres = adapter->vf_res;
 	struct net_device *netdev = adapter->netdev;
 	struct iavf_hw *hw = &adapter->hw;
+	struct iavf_mac_filter *f, *ftmp;
 	struct iavf_vlan_filter *vlf;
 	struct iavf_cloud_filter *cf;
-	struct iavf_mac_filter *f;
 	u32 reg_val;
 	int i = 0, err;
 	bool running;
@@ -2078,6 +2093,10 @@
 	if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
 		return;
 
+	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 200)) {
+		schedule_work(&adapter->reset_task);
+		return;
+	}
 	while (test_and_set_bit(__IAVF_IN_CLIENT_TASK,
 				&adapter->crit_section))
 		usleep_range(500, 1000);
@@ -2126,6 +2145,7 @@
 	}
 
 	pci_set_master(adapter->pdev);
+	pci_restore_msi_state(adapter->pdev);
 
 	if (i == IAVF_RESET_WAIT_COUNT) {
 		dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
@@ -2176,11 +2196,29 @@
 			goto reset_err;
 	}
 
+	if (RSS_AQ(adapter)) {
+		adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
+	} else {
+		err = iavf_init_rss(adapter);
+		if (err)
+			goto reset_err;
+	}
+
 	adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG;
 	adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS;
 
 	spin_lock_bh(&adapter->mac_vlan_list_lock);
 
+	/* Delete filter for the current MAC address, it could have
+	 * been changed by the PF via administratively set MAC.
+	 * Will be re-added via VIRTCHNL_OP_GET_VF_RESOURCES.
+	 */
+	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
+		if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) {
+			list_del(&f->list);
+			kfree(f);
+		}
+	}
 	/* re-add all MAC filters */
 	list_for_each_entry(f, &adapter->mac_filter_list, list) {
 		f->add = true;
@@ -2274,6 +2312,8 @@
 	if (!event.msg_buf)
 		goto out;
 
+	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 200))
+		goto freedom;
 	do {
 		ret = iavf_clean_arq_element(hw, &event, &pending);
 		v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
@@ -2287,6 +2327,7 @@
 		if (pending != 0)
 			memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);
 	} while (pending);
+	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
 
 	if ((adapter->flags &
 	     (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
@@ -2295,7 +2336,7 @@
 
 	/* check for error indications */
 	val = rd32(hw, hw->aq.arq.len);
-	if (val == 0xdeadbeef) /* indicates device in reset */
+	if (val == 0xdeadbeef || val == 0xffffffff) /* device in reset */
 		goto freedom;
 	oldval = val;
 	if (val & IAVF_VF_ARQLEN1_ARQVFE_MASK) {
@@ -2478,6 +2519,16 @@
 {
 	int speed = 0, ret = 0;
 
+	if (ADV_LINK_SUPPORT(adapter)) {
+		if (adapter->link_speed_mbps < U32_MAX) {
+			speed = adapter->link_speed_mbps;
+			goto validate_bw;
+		} else {
+			dev_err(&adapter->pdev->dev, "Unknown link speed\n");
+			return -EINVAL;
+		}
+	}
+
 	switch (adapter->link_speed) {
 	case IAVF_LINK_SPEED_40GB:
 		speed = 40000;
@@ -2501,6 +2552,7 @@
 		break;
 	}
 
+validate_bw:
 	if (max_tx_rate > speed) {
 		dev_err(&adapter->pdev->dev,
 			"Invalid tx rate specified\n");
@@ -2523,6 +2575,7 @@
 				   struct tc_mqprio_qopt_offload *mqprio_qopt)
 {
 	u64 total_max_rate = 0;
+	u32 tx_rate_rem = 0;
 	int i, num_qps = 0;
 	u64 tx_rate = 0;
 	int ret = 0;
@@ -2537,17 +2590,40 @@
 			return -EINVAL;
 		if (mqprio_qopt->min_rate[i]) {
 			dev_err(&adapter->pdev->dev,
-				"Invalid min tx rate (greater than 0) specified\n");
+				"Invalid min tx rate (greater than 0) specified for TC%d\n",
+				i);
 			return -EINVAL;
 		}
-		/*convert to Mbps */
+
+		/* convert to Mbps */
 		tx_rate = div_u64(mqprio_qopt->max_rate[i],
 				  IAVF_MBPS_DIVISOR);
+
+		if (mqprio_qopt->max_rate[i] &&
+		    tx_rate < IAVF_MBPS_QUANTA) {
+			dev_err(&adapter->pdev->dev,
+				"Invalid max tx rate for TC%d, minimum %dMbps\n",
+				i, IAVF_MBPS_QUANTA);
+			return -EINVAL;
+		}
+
+		(void)div_u64_rem(tx_rate, IAVF_MBPS_QUANTA, &tx_rate_rem);
+
+		if (tx_rate_rem != 0) {
+			dev_err(&adapter->pdev->dev,
+				"Invalid max tx rate for TC%d, not divisible by %d\n",
+				i, IAVF_MBPS_QUANTA);
+			return -EINVAL;
+		}
+
 		total_max_rate += tx_rate;
 		num_qps += mqprio_qopt->qopt.count[i];
 	}
-	if (num_qps > IAVF_MAX_REQ_QUEUES)
+	if (num_qps > adapter->num_active_queues) {
+		dev_err(&adapter->pdev->dev,
+			"Cannot support requested number of queues\n");
 		return -EINVAL;
+	}
 
 	ret = iavf_validate_tx_bandwidth(adapter, total_max_rate);
 	return ret;
@@ -2976,11 +3052,11 @@
 	/* start out with flow type and eth type IPv4 to begin with */
 	filter->f.flow_type = VIRTCHNL_TCP_V4_FLOW;
 	err = iavf_parse_cls_flower(adapter, cls_flower, filter);
-	if (err < 0)
+	if (err)
 		goto err;
 
 	err = iavf_handle_tclass(adapter, tc, filter);
-	if (err < 0)
+	if (err)
 		goto err;
 
 	/* add filter to the list */
@@ -3052,9 +3128,6 @@
 static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter,
 				    struct flow_cls_offload *cls_flower)
 {
-	if (cls_flower->common.chain_index)
-		return -EOPNOTSUPP;
-
 	switch (cls_flower->command) {
 	case FLOW_CLS_REPLACE:
 		return iavf_configure_clsflower(adapter, cls_flower);
@@ -3078,6 +3151,11 @@
 static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
 				  void *cb_priv)
 {
+	struct iavf_adapter *adapter = cb_priv;
+
+	if (!tc_cls_can_offload_and_chain0(adapter->netdev, type_data))
+		return -EOPNOTSUPP;
+
 	switch (type) {
 	case TC_SETUP_CLSFLOWER:
 		return iavf_setup_tc_cls_flower(cb_priv, type_data);
@@ -3260,8 +3338,11 @@
 		iavf_notify_client_l2_params(&adapter->vsi);
 		adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
 	}
-	adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-	queue_work(iavf_wq, &adapter->reset_task);
+
+	if (netif_running(netdev)) {
+		adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+		queue_work(iavf_wq, &adapter->reset_task);
+	}
 
 	return 0;
 }
@@ -3365,7 +3446,8 @@
 {
 	struct iavf_adapter *adapter = netdev_priv(netdev);
 
-	if (!(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
+	if (adapter->vf_res &&
+	    !(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
 		features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
 			      NETIF_F_HW_VLAN_CTAG_RX |
 			      NETIF_F_HW_VLAN_CTAG_FILTER);
@@ -3570,6 +3652,10 @@
 						    init_task.work);
 	struct iavf_hw *hw = &adapter->hw;
 
+	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000)) {
+		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);
+		return;
+	}
 	switch (adapter->state) {
 	case __IAVF_STARTUP:
 		if (iavf_startup(adapter) < 0)
@@ -3582,14 +3668,14 @@
 	case __IAVF_INIT_GET_RESOURCES:
 		if (iavf_init_get_resources(adapter) < 0)
 			goto init_failed;
-		return;
+		goto out;
 	default:
 		goto init_failed;
 	}
 
 	queue_delayed_work(iavf_wq, &adapter->init_task,
 			   msecs_to_jiffies(30));
-	return;
+	goto out;
 init_failed:
 	if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
 		dev_err(&adapter->pdev->dev,
@@ -3598,9 +3684,11 @@
 		iavf_shutdown_adminq(hw);
 		adapter->state = __IAVF_STARTUP;
 		queue_delayed_work(iavf_wq, &adapter->init_task, HZ * 5);
-		return;
+		goto out;
 	}
 	queue_delayed_work(iavf_wq, &adapter->init_task, HZ);
+out:
+	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
 }
 
 /**
@@ -3617,9 +3705,12 @@
 	if (netif_running(netdev))
 		iavf_close(netdev);
 
+	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000))
+		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);
 	/* Prevent the watchdog from running. */
 	adapter->state = __IAVF_REMOVE;
 	adapter->aq_required = 0;
+	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
 
 #ifdef CONFIG_PM
 	pci_save_state(pdev);
@@ -3739,6 +3830,7 @@
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_etherdev:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_regions(pdev);
 err_pci_reg:
 err_dma:
@@ -3746,7 +3838,6 @@
 	return err;
 }
 
-#ifdef CONFIG_PM
 /**
  * iavf_suspend - Power management suspend routine
  * @pdev: PCI device information struct
@@ -3754,11 +3845,10 @@
  *
  * Called when the system (VM) is entering sleep/suspend.
  **/
-static int iavf_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused iavf_suspend(struct device *dev_d)
 {
-	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct net_device *netdev = dev_get_drvdata(dev_d);
 	struct iavf_adapter *adapter = netdev_priv(netdev);
-	int retval = 0;
 
 	netif_device_detach(netdev);
 
@@ -3776,12 +3866,6 @@
 
 	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
 
-	retval = pci_save_state(pdev);
-	if (retval)
-		return retval;
-
-	pci_disable_device(pdev);
-
 	return 0;
 }
 
@@ -3791,24 +3875,13 @@
  *
  * Called when the system (VM) is resumed from sleep/suspend.
  **/
-static int iavf_resume(struct pci_dev *pdev)
+static int __maybe_unused iavf_resume(struct device *dev_d)
 {
-	struct iavf_adapter *adapter = pci_get_drvdata(pdev);
-	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = to_pci_dev(dev_d);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct iavf_adapter *adapter = netdev_priv(netdev);
 	u32 err;
 
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
-	/* pci_restore_state clears dev->state_saved so call
-	 * pci_save_state to restore it.
-	 */
-	pci_save_state(pdev);
-
-	err = pci_enable_device_mem(pdev);
-	if (err) {
-		dev_err(&pdev->dev, "Cannot enable PCI device from suspend.\n");
-		return err;
-	}
 	pci_set_master(pdev);
 
 	rtnl_lock();
@@ -3832,7 +3905,6 @@
 	return err;
 }
 
-#endif /* CONFIG_PM */
 /**
  * iavf_remove - Device Removal Routine
  * @pdev: PCI device information struct
@@ -3867,10 +3939,6 @@
 				 err);
 	}
 
-	/* Shut down all the garbage mashers on the detention level */
-	adapter->state = __IAVF_REMOVE;
-	adapter->aq_required = 0;
-	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
 	iavf_request_reset(adapter);
 	msleep(50);
 	/* If the FW isn't responding, kick it once, but only once. */
@@ -3878,6 +3946,13 @@
 		iavf_request_reset(adapter);
 		msleep(50);
 	}
+	if (iavf_lock_timeout(adapter, __IAVF_IN_CRITICAL_TASK, 5000))
+		dev_warn(&adapter->pdev->dev, "failed to set __IAVF_IN_CRITICAL_TASK in %s\n", __FUNCTION__);
+
+	/* Shut down all the garbage mashers on the detention level */
+	adapter->state = __IAVF_REMOVE;
+	adapter->aq_required = 0;
+	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
 	iavf_free_all_tx_resources(adapter);
 	iavf_free_all_rx_resources(adapter);
 	iavf_misc_irq_disable(adapter);
@@ -3900,8 +3975,6 @@
 
 	iounmap(hw->hw_addr);
 	pci_release_regions(pdev);
-	iavf_free_all_tx_resources(adapter);
-	iavf_free_all_rx_resources(adapter);
 	iavf_free_queues(adapter);
 	kfree(adapter->vf_res);
 	spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -3934,16 +4007,15 @@
 	pci_disable_device(pdev);
 }
 
+static SIMPLE_DEV_PM_OPS(iavf_pm_ops, iavf_suspend, iavf_resume);
+
 static struct pci_driver iavf_driver = {
-	.name     = iavf_driver_name,
-	.id_table = iavf_pci_tbl,
-	.probe    = iavf_probe,
-	.remove   = iavf_remove,
-#ifdef CONFIG_PM
-	.suspend  = iavf_suspend,
-	.resume   = iavf_resume,
-#endif
-	.shutdown = iavf_shutdown,
+	.name      = iavf_driver_name,
+	.id_table  = iavf_pci_tbl,
+	.probe     = iavf_probe,
+	.remove    = iavf_remove,
+	.driver.pm = &iavf_pm_ops,
+	.shutdown  = iavf_shutdown,
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_register.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_register.h
@@ -40,7 +40,7 @@
 #define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT)
 #define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
 #define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
-#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
+#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...63 */ /* Reset: VFR */
 #define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0
 #define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT)
 #define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -114,8 +114,11 @@
 {
 	u32 head, tail;
 
+	/* underlying hardware might not allow access and/or always return
+	 * 0 for the head/tail registers so just use the cached values
+	 */
 	head = ring->next_to_clean;
-	tail = readl(ring->tail);
+	tail = ring->next_to_use;
 
 	if (head != tail)
 		return (head < tail) ?
@@ -1058,7 +1061,7 @@
 		cpu_to_le64((u64)IAVF_RX_DESC_FLTSTAT_RSS_HASH <<
 			    IAVF_RX_DESC_STATUS_FLTSTAT_SHIFT);
 
-	if (ring->netdev->features & NETIF_F_RXHASH)
+	if (!(ring->netdev->features & NETIF_F_RXHASH))
 		return;
 
 	if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
@@ -1263,11 +1266,10 @@
 {
 	struct iavf_rx_buffer *rx_buffer;
 
-	if (!size)
-		return NULL;
-
 	rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
 	prefetchw(rx_buffer->page);
+	if (!size)
+		return rx_buffer;
 
 	/* we are reusing so sync this buffer for CPU use */
 	dma_sync_single_range_for_cpu(rx_ring->dev,
@@ -1372,7 +1374,7 @@
 #endif
 	struct sk_buff *skb;
 
-	if (!rx_buffer)
+	if (!rx_buffer || !size)
 		return NULL;
 	/* prefetch first cache line of first page */
 	va = page_address(rx_buffer->page) + rx_buffer->page_offset;
@@ -1532,7 +1534,7 @@
 		/* exit if we failed to retrieve a buffer */
 		if (!skb) {
 			rx_ring->rx_stats.alloc_buff_failed++;
-			if (rx_buffer)
+			if (rx_buffer && size)
 				rx_buffer->pagecnt_bias++;
 			break;
 		}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -139,7 +139,8 @@
 	       VIRTCHNL_VF_OFFLOAD_ENCAP |
 	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
 	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
-	       VIRTCHNL_VF_OFFLOAD_ADQ;
+	       VIRTCHNL_VF_OFFLOAD_ADQ |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
 
 	adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
 	adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG;
@@ -240,11 +241,14 @@
 void iavf_configure_queues(struct iavf_adapter *adapter)
 {
 	struct virtchnl_vsi_queue_config_info *vqci;
-	struct virtchnl_queue_pair_info *vqpi;
+	int i, max_frame = adapter->vf_res->max_mtu;
 	int pairs = adapter->num_active_queues;
-	int i, max_frame = IAVF_MAX_RXBUFFER;
+	struct virtchnl_queue_pair_info *vqpi;
 	size_t len;
 
+	if (max_frame > IAVF_MAX_RXBUFFER || !max_frame)
+		max_frame = IAVF_MAX_RXBUFFER;
+
 	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
 		/* bail because we already have a command pending */
 		dev_err(&adapter->pdev->dev, "Cannot configure queues, command %d pending\n",
@@ -564,6 +568,47 @@
 }
 
 /**
+ * iavf_mac_add_ok
+ * @adapter: adapter structure
+ *
+ * Submit list of filters based on PF response.
+ **/
+static void iavf_mac_add_ok(struct iavf_adapter *adapter)
+{
+	struct iavf_mac_filter *f, *ftmp;
+
+	spin_lock_bh(&adapter->mac_vlan_list_lock);
+	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
+		f->is_new_mac = false;
+	}
+	spin_unlock_bh(&adapter->mac_vlan_list_lock);
+}
+
+/**
+ * iavf_mac_add_reject
+ * @adapter: adapter structure
+ *
+ * Remove filters from list based on PF response.
+ **/
+static void iavf_mac_add_reject(struct iavf_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct iavf_mac_filter *f, *ftmp;
+
+	spin_lock_bh(&adapter->mac_vlan_list_lock);
+	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
+		if (f->remove && ether_addr_equal(f->macaddr, netdev->dev_addr))
+			f->remove = false;
+
+		if (f->is_new_mac) {
+			list_del(&f->list);
+			kfree(f);
+		}
+	}
+	spin_unlock_bh(&adapter->mac_vlan_list_lock);
+}
+
+/**
  * iavf_add_vlans
  * @adapter: adapter structure
  *
@@ -918,6 +963,8 @@
 	iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, NULL, 0);
 }
 
+#define IAVF_MAX_SPEED_STRLEN	13
+
 /**
  * iavf_print_link_message - print link up or down
  * @adapter: adapter structure
@@ -927,37 +974,99 @@
 static void iavf_print_link_message(struct iavf_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	char *speed = "Unknown ";
+	int link_speed_mbps;
+	char *speed;
 
 	if (!adapter->link_up) {
 		netdev_info(netdev, "NIC Link is Down\n");
 		return;
 	}
 
+	speed = kcalloc(1, IAVF_MAX_SPEED_STRLEN, GFP_KERNEL);
+	if (!speed)
+		return;
+
+	if (ADV_LINK_SUPPORT(adapter)) {
+		link_speed_mbps = adapter->link_speed_mbps;
+		goto print_link_msg;
+	}
+
 	switch (adapter->link_speed) {
 	case IAVF_LINK_SPEED_40GB:
-		speed = "40 G";
+		link_speed_mbps = SPEED_40000;
 		break;
 	case IAVF_LINK_SPEED_25GB:
-		speed = "25 G";
+		link_speed_mbps = SPEED_25000;
 		break;
 	case IAVF_LINK_SPEED_20GB:
-		speed = "20 G";
+		link_speed_mbps = SPEED_20000;
 		break;
 	case IAVF_LINK_SPEED_10GB:
-		speed = "10 G";
+		link_speed_mbps = SPEED_10000;
 		break;
 	case IAVF_LINK_SPEED_1GB:
-		speed = "1000 M";
+		link_speed_mbps = SPEED_1000;
 		break;
 	case IAVF_LINK_SPEED_100MB:
-		speed = "100 M";
+		link_speed_mbps = SPEED_100;
 		break;
 	default:
+		link_speed_mbps = SPEED_UNKNOWN;
 		break;
 	}
 
-	netdev_info(netdev, "NIC Link is Up %sbps Full Duplex\n", speed);
+print_link_msg:
+	if (link_speed_mbps > SPEED_1000) {
+		if (link_speed_mbps == SPEED_2500)
+			snprintf(speed, IAVF_MAX_SPEED_STRLEN, "2.5 Gbps");
+		else
+			/* convert to Gbps inline */
+			snprintf(speed, IAVF_MAX_SPEED_STRLEN, "%d %s",
+				 link_speed_mbps / 1000, "Gbps");
+	} else if (link_speed_mbps == SPEED_UNKNOWN) {
+		snprintf(speed, IAVF_MAX_SPEED_STRLEN, "%s", "Unknown Mbps");
+	} else {
+		snprintf(speed, IAVF_MAX_SPEED_STRLEN, "%u %s",
+			 link_speed_mbps, "Mbps");
+	}
+
+	netdev_info(netdev, "NIC Link is Up Speed is %s Full Duplex\n", speed);
+	kfree(speed);
+}
+
+/**
+ * iavf_get_vpe_link_status
+ * @adapter: adapter structure
+ * @vpe: virtchnl_pf_event structure
+ *
+ * Helper function for determining the link status
+ **/
+static bool
+iavf_get_vpe_link_status(struct iavf_adapter *adapter,
+			 struct virtchnl_pf_event *vpe)
+{
+	if (ADV_LINK_SUPPORT(adapter))
+		return vpe->event_data.link_event_adv.link_status;
+	else
+		return vpe->event_data.link_event.link_status;
+}
+
+/**
+ * iavf_set_adapter_link_speed_from_vpe
+ * @adapter: adapter structure for which we are setting the link speed
+ * @vpe: virtchnl_pf_event structure that contains the link speed we are setting
+ *
+ * Helper function for setting iavf_adapter link speed
+ **/
+static void
+iavf_set_adapter_link_speed_from_vpe(struct iavf_adapter *adapter,
+				     struct virtchnl_pf_event *vpe)
+{
+	if (ADV_LINK_SUPPORT(adapter))
+		adapter->link_speed_mbps =
+			vpe->event_data.link_event_adv.link_speed;
+	else
+		adapter->link_speed = vpe->event_data.link_event.link_speed;
 }
 
 /**
@@ -1187,12 +1296,11 @@
 	if (v_opcode == VIRTCHNL_OP_EVENT) {
 		struct virtchnl_pf_event *vpe =
 			(struct virtchnl_pf_event *)msg;
-		bool link_up = vpe->event_data.link_event.link_status;
+		bool link_up = iavf_get_vpe_link_status(adapter, vpe);
 
 		switch (vpe->event) {
 		case VIRTCHNL_EVENT_LINK_CHANGE:
-			adapter->link_speed =
-				vpe->event_data.link_event.link_speed;
+			iavf_set_adapter_link_speed_from_vpe(adapter, vpe);
 
 			/* we've already got the right link status, bail */
 			if (adapter->link_up == link_up)
@@ -1252,6 +1360,7 @@
 		case VIRTCHNL_OP_ADD_ETH_ADDR:
 			dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n",
 				iavf_stat_str(&adapter->hw, v_retval));
+			iavf_mac_add_reject(adapter);
 			/* restore administratively set MAC address */
 			ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
 			break;
@@ -1321,10 +1430,11 @@
 		}
 	}
 	switch (v_opcode) {
-	case VIRTCHNL_OP_ADD_ETH_ADDR: {
+	case VIRTCHNL_OP_ADD_ETH_ADDR:
+		if (!v_retval)
+			iavf_mac_add_ok(adapter);
 		if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr))
 			ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
-		}
 		break;
 	case VIRTCHNL_OP_GET_STATS: {
 		struct iavf_eth_stats *stats =
@@ -1359,6 +1469,9 @@
 			ether_addr_copy(netdev->perm_addr,
 					adapter->hw.mac.addr);
 		}
+		spin_lock_bh(&adapter->mac_vlan_list_lock);
+		iavf_add_filter(adapter, adapter->hw.mac.addr);
+		spin_unlock_bh(&adapter->mac_vlan_list_lock);
 		iavf_process_config(adapter);
 		}
 		break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_common.c
@@ -436,6 +436,7 @@
 static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
 {
 	struct ice_switch_info *sw;
+	enum ice_status status;
 
 	hw->switch_info = devm_kzalloc(ice_hw_to_dev(hw),
 				       sizeof(*hw->switch_info), GFP_KERNEL);
@@ -446,7 +447,12 @@
 
 	INIT_LIST_HEAD(&sw->vsi_list_map_head);
 
-	return ice_init_def_sw_recp(hw);
+	status = ice_init_def_sw_recp(hw);
+	if (status) {
+		devm_kfree(ice_hw_to_dev(hw), hw->switch_info);
+		return status;
+	}
+	return 0;
 }
 
 /**
@@ -934,7 +940,7 @@
  */
 enum ice_status ice_check_reset(struct ice_hw *hw)
 {
-	u32 cnt, reg = 0, grst_delay;
+	u32 cnt, reg = 0, grst_delay, uld_mask;
 
 	/* Poll for Device Active state in case a recent CORER, GLOBR,
 	 * or EMPR has occurred. The grst delay value is in 100ms units.
@@ -956,13 +962,20 @@
 		return ICE_ERR_RESET_FAILED;
 	}
 
-#define ICE_RESET_DONE_MASK	(GLNVM_ULD_CORER_DONE_M | \
-				 GLNVM_ULD_GLOBR_DONE_M)
+#define ICE_RESET_DONE_MASK	(GLNVM_ULD_PCIER_DONE_M |\
+				 GLNVM_ULD_PCIER_DONE_1_M |\
+				 GLNVM_ULD_CORER_DONE_M |\
+				 GLNVM_ULD_GLOBR_DONE_M |\
+				 GLNVM_ULD_POR_DONE_M |\
+				 GLNVM_ULD_POR_DONE_1_M |\
+				 GLNVM_ULD_PCIER_DONE_2_M)
+
+	uld_mask = ICE_RESET_DONE_MASK;
 
 	/* Device is Active; check Global Reset processes are done */
 	for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
-		reg = rd32(hw, GLNVM_ULD) & ICE_RESET_DONE_MASK;
-		if (reg == ICE_RESET_DONE_MASK) {
+		reg = rd32(hw, GLNVM_ULD) & uld_mask;
+		if (reg == uld_mask) {
 			ice_debug(hw, ICE_DBG_INIT,
 				  "Global reset processes done. %d\n", cnt);
 			break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -199,7 +199,9 @@
 		cq->rq.r.rq_bi[i].pa = 0;
 		cq->rq.r.rq_bi[i].size = 0;
 	}
+	cq->rq.r.rq_bi = NULL;
 	devm_kfree(ice_hw_to_dev(hw), cq->rq.dma_head);
+	cq->rq.dma_head = NULL;
 
 	return ICE_ERR_NO_MEMORY;
 }
@@ -245,7 +247,9 @@
 		cq->sq.r.sq_bi[i].pa = 0;
 		cq->sq.r.sq_bi[i].size = 0;
 	}
+	cq->sq.r.sq_bi = NULL;
 	devm_kfree(ice_hw_to_dev(hw), cq->sq.dma_head);
+	cq->sq.dma_head = NULL;
 
 	return ICE_ERR_NO_MEMORY;
 }
@@ -304,6 +308,28 @@
 	return 0;
 }
 
+#define ICE_FREE_CQ_BUFS(hw, qi, ring)					\
+do {									\
+	int i;								\
+	/* free descriptors */						\
+	if ((qi)->ring.r.ring##_bi)					\
+		for (i = 0; i < (qi)->num_##ring##_entries; i++)	\
+			if ((qi)->ring.r.ring##_bi[i].pa) {		\
+				dmam_free_coherent(ice_hw_to_dev(hw),	\
+					(qi)->ring.r.ring##_bi[i].size,	\
+					(qi)->ring.r.ring##_bi[i].va,	\
+					(qi)->ring.r.ring##_bi[i].pa);	\
+					(qi)->ring.r.ring##_bi[i].va = NULL;\
+					(qi)->ring.r.ring##_bi[i].pa = 0;\
+					(qi)->ring.r.ring##_bi[i].size = 0;\
+		}							\
+	/* free the buffer info list */					\
+	if ((qi)->ring.cmd_buf)						\
+		devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf);	\
+	/* free DMA head */						\
+	devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head);		\
+} while (0)
+
 /**
  * ice_init_sq - main initialization routine for Control ATQ
  * @hw: pointer to the hardware structure
@@ -357,6 +383,7 @@
 	goto init_ctrlq_exit;
 
 init_ctrlq_free_rings:
+	ICE_FREE_CQ_BUFS(hw, cq, sq);
 	ice_free_cq_ring(hw, &cq->sq);
 
 init_ctrlq_exit:
@@ -416,33 +443,13 @@
 	goto init_ctrlq_exit;
 
 init_ctrlq_free_rings:
+	ICE_FREE_CQ_BUFS(hw, cq, rq);
 	ice_free_cq_ring(hw, &cq->rq);
 
 init_ctrlq_exit:
 	return ret_code;
 }
 
-#define ICE_FREE_CQ_BUFS(hw, qi, ring)					\
-do {									\
-	int i;								\
-	/* free descriptors */						\
-	for (i = 0; i < (qi)->num_##ring##_entries; i++)		\
-		if ((qi)->ring.r.ring##_bi[i].pa) {			\
-			dmam_free_coherent(ice_hw_to_dev(hw),		\
-					   (qi)->ring.r.ring##_bi[i].size,\
-					   (qi)->ring.r.ring##_bi[i].va,\
-					   (qi)->ring.r.ring##_bi[i].pa);\
-			(qi)->ring.r.ring##_bi[i].va = NULL;		\
-			(qi)->ring.r.ring##_bi[i].pa = 0;		\
-			(qi)->ring.r.ring##_bi[i].size = 0;		\
-		}							\
-	/* free the buffer info list */					\
-	if ((qi)->ring.cmd_buf)						\
-		devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf);	\
-	/* free DMA head */						\
-	devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head);		\
-} while (0)
-
 /**
  * ice_shutdown_sq - shutdown the Control ATQ
  * @hw: pointer to the hardware structure
@@ -948,7 +955,7 @@
 		if (ice_sq_done(hw, cq))
 			break;
 
-		mdelay(1);
+		udelay(ICE_CTL_Q_SQ_CMD_USEC);
 		total_delay++;
 	} while (total_delay < cq->sq_cmd_timeout);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -31,8 +31,9 @@
 	ICE_CTL_Q_MAILBOX,
 };
 
-/* Control Queue default settings */
-#define ICE_CTL_Q_SQ_CMD_TIMEOUT	250  /* msecs */
+/* Control Queue timeout settings - max delay 1s */
+#define ICE_CTL_Q_SQ_CMD_TIMEOUT	10000 /* Count 10000 times */
+#define ICE_CTL_Q_SQ_CMD_USEC		100   /* Check every 100usec */
 
 struct ice_ctl_q_ring {
 	void *dma_head;			/* Virtual address to DMA head */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_devids.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_devids.h
@@ -5,11 +5,50 @@
 #define _ICE_DEVIDS_H_
 
 /* Device IDs */
+/* Intel(R) Ethernet Connection E823-L for backplane */
+#define ICE_DEV_ID_E823L_BACKPLANE	0x124C
+/* Intel(R) Ethernet Connection E823-L for SFP */
+#define ICE_DEV_ID_E823L_SFP		0x124D
+/* Intel(R) Ethernet Connection E823-L/X557-AT 10GBASE-T */
+#define ICE_DEV_ID_E823L_10G_BASE_T	0x124E
+/* Intel(R) Ethernet Connection E823-L 1GbE */
+#define ICE_DEV_ID_E823L_1GBE		0x124F
+/* Intel(R) Ethernet Connection E823-L for QSFP */
+#define ICE_DEV_ID_E823L_QSFP		0x151D
 /* Intel(R) Ethernet Controller E810-C for backplane */
 #define ICE_DEV_ID_E810C_BACKPLANE	0x1591
 /* Intel(R) Ethernet Controller E810-C for QSFP */
 #define ICE_DEV_ID_E810C_QSFP		0x1592
 /* Intel(R) Ethernet Controller E810-C for SFP */
 #define ICE_DEV_ID_E810C_SFP		0x1593
-
+/* Intel(R) Ethernet Controller E810-XXV for SFP */
+#define ICE_DEV_ID_E810_XXV_SFP		0x159B
+/* Intel(R) Ethernet Connection E823-C for backplane */
+#define ICE_DEV_ID_E823C_BACKPLANE	0x188A
+/* Intel(R) Ethernet Connection E823-C for QSFP */
+#define ICE_DEV_ID_E823C_QSFP		0x188B
+/* Intel(R) Ethernet Connection E823-C for SFP */
+#define ICE_DEV_ID_E823C_SFP		0x188C
+/* Intel(R) Ethernet Connection E823-C/X557-AT 10GBASE-T */
+#define ICE_DEV_ID_E823C_10G_BASE_T	0x188D
+/* Intel(R) Ethernet Connection E823-C 1GbE */
+#define ICE_DEV_ID_E823C_SGMII		0x188E
+/* Intel(R) Ethernet Connection E822-C for backplane */
+#define ICE_DEV_ID_E822C_BACKPLANE	0x1890
+/* Intel(R) Ethernet Connection E822-C for QSFP */
+#define ICE_DEV_ID_E822C_QSFP		0x1891
+/* Intel(R) Ethernet Connection E822-C for SFP */
+#define ICE_DEV_ID_E822C_SFP		0x1892
+/* Intel(R) Ethernet Connection E822-C/X557-AT 10GBASE-T */
+#define ICE_DEV_ID_E822C_10G_BASE_T	0x1893
+/* Intel(R) Ethernet Connection E822-C 1GbE */
+#define ICE_DEV_ID_E822C_SGMII		0x1894
+/* Intel(R) Ethernet Connection E822-X for backplane */
+#define ICE_DEV_ID_E822X_BACKPLANE	0x1897
+/* Intel(R) Ethernet Connection E822-L for SFP */
+#define ICE_DEV_ID_E822L_SFP		0x1898
+/* Intel(R) Ethernet Connection E822-L/X557-AT 10GBASE-T */
+#define ICE_DEV_ID_E822L_10G_BASE_T	0x1899
+/* Intel(R) Ethernet Connection E822-L 1GbE */
+#define ICE_DEV_ID_E822L_SGMII		0x189A
 #endif /* _ICE_DEVIDS_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -138,9 +138,6 @@
 	QINT_RQCTL(0),
 	PFINT_OICR_ENA,
 	QRX_ITR(0),
-	PF0INT_ITR_0(0),
-	PF0INT_ITR_1(0),
-	PF0INT_ITR_2(0),
 };
 
 struct ice_priv_flag {
@@ -619,7 +616,8 @@
 		rx_desc = ICE_RX_DESC(rx_ring, i);
 
 		if (!(rx_desc->wb.status_error0 &
-		    cpu_to_le16(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS)))
+		    (cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) |
+		     cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)))))
 			continue;
 
 		rx_buf = &rx_ring->rx_buf[i];
@@ -2338,6 +2336,42 @@
 }
 
 /**
+ * ice_set_phy_type_from_speed - set phy_types based on speeds
+ * and advertised modes
+ * @ks: ethtool link ksettings struct
+ * @phy_type_low: pointer to the lower part of phy_type
+ * @phy_type_high: pointer to the higher part of phy_type
+ * @adv_link_speed: targeted link speeds bitmap
+ */
+static void
+ice_set_phy_type_from_speed(const struct ethtool_link_ksettings *ks,
+			    u64 *phy_type_low, u64 *phy_type_high,
+			    u16 adv_link_speed)
+{
+	/* Handle 1000M speed in a special way because ice_update_phy_type
+	 * enables all link modes, but having mixed copper and optical
+	 * standards is not supported.
+	 */
+	adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB;
+
+	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+						  1000baseT_Full))
+		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T |
+				 ICE_PHY_TYPE_LOW_1G_SGMII;
+
+	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+						  1000baseKX_Full))
+		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX;
+
+	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+						  1000baseX_Full))
+		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX |
+				 ICE_PHY_TYPE_LOW_1000BASE_LX;
+
+	ice_update_phy_type(phy_type_low, phy_type_high, adv_link_speed);
+}
+
+/**
  * ice_set_link_ksettings - Set Speed and Duplex
  * @netdev: network interface device structure
  * @ks: ethtool ksettings
@@ -2472,7 +2506,8 @@
 		adv_link_speed = curr_link_speed;
 
 	/* Convert the advertise link speeds to their corresponded PHY_TYPE */
-	ice_update_phy_type(&phy_type_low, &phy_type_high, adv_link_speed);
+	ice_set_phy_type_from_speed(ks, &phy_type_low, &phy_type_high,
+				    adv_link_speed);
 
 	if (!autoneg_changed && adv_link_speed == curr_link_speed) {
 		netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
@@ -2635,14 +2670,14 @@
 	netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n",
 		    vsi->tx_rings[0]->count, new_tx_cnt);
 
-	tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq,
+	tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_txq,
 				sizeof(*tx_rings), GFP_KERNEL);
 	if (!tx_rings) {
 		err = -ENOMEM;
 		goto done;
 	}
 
-	for (i = 0; i < vsi->alloc_txq; i++) {
+	ice_for_each_txq(vsi, i) {
 		/* clone ring and setup updated count */
 		tx_rings[i] = *vsi->tx_rings[i];
 		tx_rings[i].count = new_tx_cnt;
@@ -2667,14 +2702,14 @@
 	netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n",
 		    vsi->rx_rings[0]->count, new_rx_cnt);
 
-	rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq,
+	rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_rxq,
 				sizeof(*rx_rings), GFP_KERNEL);
 	if (!rx_rings) {
 		err = -ENOMEM;
 		goto done;
 	}
 
-	for (i = 0; i < vsi->alloc_rxq; i++) {
+	ice_for_each_rxq(vsi, i) {
 		/* clone ring and setup updated count */
 		rx_rings[i] = *vsi->rx_rings[i];
 		rx_rings[i].count = new_rx_cnt;
@@ -2712,7 +2747,7 @@
 		ice_down(vsi);
 
 		if (tx_rings) {
-			for (i = 0; i < vsi->alloc_txq; i++) {
+			ice_for_each_txq(vsi, i) {
 				ice_free_tx_ring(vsi->tx_rings[i]);
 				*vsi->tx_rings[i] = tx_rings[i];
 			}
@@ -2720,7 +2755,7 @@
 		}
 
 		if (rx_rings) {
-			for (i = 0; i < vsi->alloc_rxq; i++) {
+			ice_for_each_rxq(vsi, i) {
 				ice_free_rx_ring(vsi->rx_rings[i]);
 				/* copy the real tail offset */
 				rx_rings[i].tail = vsi->rx_rings[i]->tail;
@@ -2744,7 +2779,7 @@
 free_tx:
 	/* error cleanup if the Rx allocations failed after getting Tx */
 	if (tx_rings) {
-		for (i = 0; i < vsi->alloc_txq; i++)
+		ice_for_each_txq(vsi, i)
 			ice_free_tx_ring(&tx_rings[i]);
 		devm_kfree(&pf->pdev->dev, tx_rings);
 	}
@@ -2916,13 +2951,6 @@
 	else
 		return -EINVAL;
 
-	/* Tell the OS link is going down, the link will go back up when fw
-	 * says it is ready asynchronously
-	 */
-	ice_print_link_msg(vsi, false);
-	netif_carrier_off(netdev);
-	netif_tx_stop_all_queues(netdev);
-
 	/* Set the FC mode and only restart AN if link is up */
 	status = ice_set_fc(pi, &aq_failures, link_up);
 
@@ -3368,10 +3396,17 @@
 	struct ice_vsi *vsi = np->vsi;
 
 	if (q_num < 0) {
-		int i;
+		int v_idx;
+
+		ice_for_each_q_vector(vsi, v_idx) {
+			/* In some cases if DCB is configured the num_[rx|tx]q
+			 * can be less than vsi->num_q_vectors. This check
+			 * accounts for that so we don't report a false failure
+			 */
+			if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq)
+				goto set_complete;
 
-		ice_for_each_q_vector(vsi, i) {
-			if (ice_set_q_coalesce(vsi, ec, i))
+			if (ice_set_q_coalesce(vsi, ec, v_idx))
 				return -EINVAL;
 		}
 		goto set_complete;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
@@ -1535,10 +1535,12 @@
 		es->ref_count = devm_kcalloc(ice_hw_to_dev(hw), es->count,
 					     sizeof(*es->ref_count),
 					     GFP_KERNEL);
+		if (!es->ref_count)
+			goto err;
 
 		es->written = devm_kcalloc(ice_hw_to_dev(hw), es->count,
 					   sizeof(*es->written), GFP_KERNEL);
-		if (!es->ref_count)
+		if (!es->written)
 			goto err;
 	}
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -6,9 +6,6 @@
 #ifndef _ICE_HW_AUTOGEN_H_
 #define _ICE_HW_AUTOGEN_H_
 
-#define PF0INT_ITR_0(_i)			(0x03000004 + ((_i) * 4096))
-#define PF0INT_ITR_1(_i)			(0x03000008 + ((_i) * 4096))
-#define PF0INT_ITR_2(_i)			(0x0300000C + ((_i) * 4096))
 #define QTX_COMM_DBELL(_DBQM)			(0x002C0000 + ((_DBQM) * 4))
 #define QTX_COMM_HEAD(_DBQM)			(0x000E0000 + ((_DBQM) * 4))
 #define QTX_COMM_HEAD_HEAD_S			0
@@ -34,6 +31,7 @@
 #define PF_FW_ATQLEN_ATQOVFL_M			BIT(29)
 #define PF_FW_ATQLEN_ATQCRIT_M			BIT(30)
 #define VF_MBX_ARQLEN(_VF)			(0x0022BC00 + ((_VF) * 4))
+#define VF_MBX_ATQLEN(_VF)			(0x0022A800 + ((_VF) * 4))
 #define PF_FW_ATQLEN_ATQENABLE_M		BIT(31)
 #define PF_FW_ATQT				0x00080400
 #define PF_MBX_ARQBAH				0x0022E400
@@ -273,8 +271,14 @@
 #define GLNVM_GENS_SR_SIZE_S			5
 #define GLNVM_GENS_SR_SIZE_M			ICE_M(0x7, 5)
 #define GLNVM_ULD				0x000B6008
+#define GLNVM_ULD_PCIER_DONE_M			BIT(0)
+#define GLNVM_ULD_PCIER_DONE_1_M		BIT(1)
 #define GLNVM_ULD_CORER_DONE_M			BIT(3)
 #define GLNVM_ULD_GLOBR_DONE_M			BIT(4)
+#define GLNVM_ULD_POR_DONE_M			BIT(5)
+#define GLNVM_ULD_POR_DONE_1_M			BIT(8)
+#define GLNVM_ULD_PCIER_DONE_2_M		BIT(9)
+#define GLNVM_ULD_PE_DONE_M			BIT(10)
 #define GLPCI_CNF2				0x000BE004
 #define GLPCI_CNF2_CACHELINE_SIZE_M		BIT(1)
 #define PF_FUNC_RID				0x0009E880
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_lib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1015,8 +1015,7 @@
 
 	ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
 				ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
-				((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &
-				 ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
+				(hash_type & ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_main.c
@@ -2900,7 +2900,7 @@
 	if (err) {
 		dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err);
 		err = -EIO;
-		goto err_init_interrupt_unroll;
+		goto err_init_vsi_unroll;
 	}
 
 	/* Driver is mostly up */
@@ -2986,6 +2986,7 @@
 	ice_free_irq_msix_misc(pf);
 err_init_interrupt_unroll:
 	ice_clear_interrupt_scheme(pf);
+err_init_vsi_unroll:
 	devm_kfree(dev, pf->vsi);
 err_init_pf_unroll:
 	ice_deinit_pf(pf);
@@ -3004,9 +3005,6 @@
 	struct ice_pf *pf = pci_get_drvdata(pdev);
 	int i;
 
-	if (!pf)
-		return;
-
 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
 		if (!ice_is_reset_in_progress(pf->state))
 			break;
@@ -3178,6 +3176,26 @@
 	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_BACKPLANE), 0 },
 	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_QSFP), 0 },
 	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_BACKPLANE), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_QSFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_10G_BASE_T), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SGMII), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_BACKPLANE), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_QSFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_10G_BASE_T), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SGMII), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822X_BACKPLANE), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_10G_BASE_T), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SGMII), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_BACKPLANE), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_SFP), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 },
+	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 },
 	/* required last entry */
 	{ 0, }
 };
@@ -3213,7 +3231,7 @@
 	pr_info("%s - version %s\n", ice_driver_string, ice_drv_ver);
 	pr_info("%s\n", ice_copyright);
 
-	ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME);
+	ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME);
 	if (!ice_wq) {
 		pr_err("Failed to create workqueue\n");
 		return -ENOMEM;
@@ -3494,11 +3512,10 @@
 {
 	int err;
 
-	if (vsi->netdev) {
+	if (vsi->netdev && vsi->type == ICE_VSI_PF) {
 		ice_set_rx_mode(vsi->netdev);
 
 		err = ice_vsi_vlan_setup(vsi);
-
 		if (err)
 			return err;
 	}
@@ -3557,13 +3574,19 @@
 
 	if (vsi->port_info &&
 	    (vsi->port_info->phy.link_info.link_info & ICE_AQ_LINK_UP) &&
-	    vsi->netdev) {
+	    vsi->netdev && vsi->type == ICE_VSI_PF) {
 		ice_print_link_msg(vsi, true);
 		netif_tx_start_all_queues(vsi->netdev);
 		netif_carrier_on(vsi->netdev);
 	}
 
-	ice_service_task_schedule(pf);
+	/* Perform an initial read of the statistics registers now to
+	 * set the baseline so counters are ready when interface is up
+	 */
+	ice_update_eth_stats(vsi);
+
+	if (vsi->type == ICE_VSI_PF)
+		ice_service_task_schedule(pf);
 
 	return 0;
 }
@@ -3970,8 +3993,13 @@
 	}
 
 	ice_for_each_txq(vsi, i) {
-		vsi->tx_rings[i]->netdev = vsi->netdev;
-		err = ice_setup_tx_ring(vsi->tx_rings[i]);
+		struct ice_ring *ring = vsi->tx_rings[i];
+
+		if (!ring)
+			return -EINVAL;
+
+		ring->netdev = vsi->netdev;
+		err = ice_setup_tx_ring(ring);
 		if (err)
 			break;
 	}
@@ -3996,8 +4024,13 @@
 	}
 
 	ice_for_each_rxq(vsi, i) {
-		vsi->rx_rings[i]->netdev = vsi->netdev;
-		err = ice_setup_rx_ring(vsi->rx_rings[i]);
+		struct ice_ring *ring = vsi->rx_rings[i];
+
+		if (!ring)
+			return -EINVAL;
+
+		ring->netdev = vsi->netdev;
+		err = ice_setup_rx_ring(ring);
 		if (err)
 			break;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -289,6 +289,32 @@
 
 	hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo;
 
+	switch (hw->device_id) {
+	/* the following devices do not have boot_cfg_tlv yet */
+	case ICE_DEV_ID_E823C_BACKPLANE:
+	case ICE_DEV_ID_E823C_QSFP:
+	case ICE_DEV_ID_E823C_SFP:
+	case ICE_DEV_ID_E823C_10G_BASE_T:
+	case ICE_DEV_ID_E823C_SGMII:
+	case ICE_DEV_ID_E822C_BACKPLANE:
+	case ICE_DEV_ID_E822C_QSFP:
+	case ICE_DEV_ID_E822C_10G_BASE_T:
+	case ICE_DEV_ID_E822C_SGMII:
+	case ICE_DEV_ID_E822C_SFP:
+	case ICE_DEV_ID_E822X_BACKPLANE:
+	case ICE_DEV_ID_E822L_SFP:
+	case ICE_DEV_ID_E822L_10G_BASE_T:
+	case ICE_DEV_ID_E822L_SGMII:
+	case ICE_DEV_ID_E823L_BACKPLANE:
+	case ICE_DEV_ID_E823L_SFP:
+	case ICE_DEV_ID_E823L_10G_BASE_T:
+	case ICE_DEV_ID_E823L_1GBE:
+	case ICE_DEV_ID_E823L_QSFP:
+		return status;
+	default:
+		break;
+	}
+
 	return status;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_switch.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -1279,6 +1279,9 @@
 			ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
 						vsi_list_id);
 
+		if (!m_entry->vsi_list_info)
+			return ICE_ERR_NO_MEMORY;
+
 		/* If this entry was large action then the large action needs
 		 * to be updated to point to FWD to VSI list
 		 */
@@ -2266,6 +2269,7 @@
 	return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
 		 fm_entry->fltr_info.vsi_handle == vsi_handle) ||
 		(fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
+		 fm_entry->vsi_list_info &&
 		 (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
 }
 
@@ -2338,14 +2342,12 @@
 		return ICE_ERR_PARAM;
 
 	list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
-		struct ice_fltr_info *fi;
-
-		fi = &fm_entry->fltr_info;
-		if (!fi || !ice_vsi_uses_fltr(fm_entry, vsi_handle))
+		if (!ice_vsi_uses_fltr(fm_entry, vsi_handle))
 			continue;
 
 		status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
-							vsi_list_head, fi);
+							vsi_list_head,
+							&fm_entry->fltr_info);
 		if (status)
 			return status;
 	}
@@ -2625,7 +2627,7 @@
 		else
 			status = ice_set_vsi_promisc(hw, vsi_handle,
 						     promisc_mask, vlan_id);
-		if (status)
+		if (status && status != -EEXIST)
 			break;
 	}
 
@@ -2663,7 +2665,7 @@
 					  &remove_list_head);
 	mutex_unlock(rule_lock);
 	if (status)
-		return;
+		goto free_fltr_list;
 
 	switch (lkup) {
 	case ICE_SW_LKUP_MAC:
@@ -2686,6 +2688,7 @@
 		break;
 	}
 
+free_fltr_list:
 	list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
 		list_del(&fm_entry->list_entry);
 		devm_kfree(ice_hw_to_dev(hw), fm_entry);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -2109,6 +2109,7 @@
 	struct ice_tx_offload_params offload = { 0 };
 	struct ice_vsi *vsi = tx_ring->vsi;
 	struct ice_tx_buf *first;
+	struct ethhdr *eth;
 	unsigned int count;
 	int tso, csum;
 
@@ -2156,7 +2157,9 @@
 		goto out_drop;
 
 	/* allow CONTROL frames egress from main VSI if FW LLDP disabled */
-	if (unlikely(skb->priority == TC_PRIO_CONTROL &&
+	eth = (struct ethhdr *)skb_mac_header(skb);
+	if (unlikely((skb->priority == TC_PRIO_CONTROL ||
+		      eth->h_proto == htons(ETH_P_LLDP)) &&
 		     vsi->type == ICE_VSI_PF &&
 		     vsi->port_info->is_sw_lldp))
 		offload.cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_type.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_type.h
@@ -48,7 +48,7 @@
 /* FW update timeout definitions are in milliseconds */
 #define ICE_NVM_TIMEOUT			180000
 #define ICE_CHANGE_LOCK_TIMEOUT		1000
-#define ICE_GLOBAL_CFG_LOCK_TIMEOUT	3000
+#define ICE_GLOBAL_CFG_LOCK_TIMEOUT	5000
 
 enum ice_aq_res_access_type {
 	ICE_RES_READ = 1,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
@@ -317,8 +317,9 @@
 	pf->num_alloc_vfs = 0;
 	for (i = 0; i < tmp; i++) {
 		if (test_bit(ICE_VF_STATE_INIT, pf->vf[i].vf_states)) {
-			/* disable VF qp mappings */
+			/* disable VF qp mappings and set VF disable state */
 			ice_dis_vf_mappings(&pf->vf[i]);
+			set_bit(ICE_VF_STATE_DIS, pf->vf[i].vf_states);
 			ice_free_vf_res(&pf->vf[i]);
 		}
 	}
@@ -383,13 +384,15 @@
 	 */
 	clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
 
-	/* VF_MBX_ARQLEN is cleared by PFR, so the driver needs to clear it
-	 * in the case of VFR. If this is done for PFR, it can mess up VF
-	 * resets because the VF driver may already have started cleanup
-	 * by the time we get here.
-	 */
-	if (!is_pfr)
-		wr32(hw, VF_MBX_ARQLEN(vf_abs_id), 0);
+	/* VF_MBX_ARQLEN and VF_MBX_ATQLEN are cleared by PFR, so the driver
+	 * needs to clear them in the case of VFR/VFLR. If this is done for
+	 * PFR, it can mess up VF resets because the VF driver may already
+	 * have started cleanup by the time we get here.
+	 */
+	if (!is_pfr) {
+		wr32(hw, VF_MBX_ARQLEN(vf->vf_id), 0);
+		wr32(hw, VF_MBX_ATQLEN(vf->vf_id), 0);
+	}
 
 	/* In the case of a VFLR, the HW has already reset the VF and we
 	 * just need to clean up, so don't hit the VFRTRIG register.
@@ -1287,9 +1290,12 @@
 	if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
 		return;
 
-	/* verify if the VF is in either init or active before proceeding */
-	if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
-	    !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+	/* Bail out if VF is in disabled state, neither initialized, nor active
+	 * state - otherwise proceed with notifications
+	 */
+	if ((!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
+	     !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) ||
+	    test_bit(ICE_VF_STATE_DIS, vf->vf_states))
 		return;
 
 	pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING;
@@ -1869,8 +1875,8 @@
 	enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 	struct virtchnl_queue_select *vqs =
 		(struct virtchnl_queue_select *)msg;
+	struct ice_eth_stats stats = { 0 };
 	struct ice_pf *pf = vf->pf;
-	struct ice_eth_stats stats;
 	struct ice_vsi *vsi;
 
 	if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
@@ -1889,7 +1895,6 @@
 		goto error_param;
 	}
 
-	memset(&stats, 0, sizeof(struct ice_eth_stats));
 	ice_update_eth_stats(vsi);
 
 	stats = vsi->eth_stats;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -530,7 +530,7 @@
 		dev_spec->module_plugged = true;
 		if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) {
 			hw->phy.media_type = e1000_media_type_internal_serdes;
-		} else if (eth_flags->e100_base_fx) {
+		} else if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) {
 			dev_spec->sgmii_active = true;
 			hw->phy.media_type = e1000_media_type_internal_serdes;
 		} else if (eth_flags->e1000_base_t) {
@@ -657,14 +657,10 @@
 			break;
 		}
 
-		/* do not change link mode for 100BaseFX */
-		if (dev_spec->eth_flags.e100_base_fx)
-			break;
-
 		/* change current link mode setting */
 		ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
 
-		if (hw->phy.media_type == e1000_media_type_copper)
+		if (dev_spec->sgmii_active)
 			ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII;
 		else
 			ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -425,7 +425,7 @@
 static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
 {
 	u32 hash_value, hash_mask;
-	u8 bit_shift = 0;
+	u8 bit_shift = 1;
 
 	/* Register count multiplied by bits per register */
 	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
@@ -433,7 +433,7 @@
 	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
 	 * where 0xFF would still fall within the hash mask.
 	 */
-	while (hash_mask >> bit_shift != 0xFF)
+	while (hash_mask >> bit_shift != 0xFF && bit_shift < 4)
 		bit_shift++;
 
 	/* The portion of the address that is used for the hash table
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/igb.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/igb.h
@@ -32,11 +32,11 @@
 /* TX/RX descriptor defines */
 #define IGB_DEFAULT_TXD		256
 #define IGB_DEFAULT_TX_WORK	128
-#define IGB_MIN_TXD		80
+#define IGB_MIN_TXD		64
 #define IGB_MAX_TXD		4096
 
 #define IGB_DEFAULT_RXD		256
-#define IGB_MIN_RXD		80
+#define IGB_MIN_RXD		64
 #define IGB_MAX_RXD		4096
 
 #define IGB_DEFAULT_ITR		3 /* dynamic */
@@ -594,6 +594,8 @@
 	struct igb_mac_addr *mac_table;
 	struct vf_mac_filter vf_macs;
 	struct vf_mac_filter *vf_mac_list;
+	/* lock for VF resources */
+	spinlock_t vfs_lock;
 };
 
 /* flags controlling PTP/1588 function */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -143,7 +143,8 @@
 	u32 speed;
 	u32 supported, advertising;
 
-	status = rd32(E1000_STATUS);
+	status = pm_runtime_suspended(&adapter->pdev->dev) ?
+		 0 : rd32(E1000_STATUS);
 	if (hw->phy.media_type == e1000_media_type_copper) {
 
 		supported = (SUPPORTED_10baseT_Half |
@@ -181,7 +182,7 @@
 				advertising &= ~ADVERTISED_1000baseKX_Full;
 			}
 		}
-		if (eth_flags->e100_base_fx) {
+		if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) {
 			supported |= SUPPORTED_100baseT_Full;
 			advertising |= ADVERTISED_100baseT_Full;
 		}
@@ -813,6 +814,8 @@
 		 */
 		ret_val = hw->nvm.ops.read(hw, last_word, 1,
 				   &eeprom_buff[last_word - first_word]);
+		if (ret_val)
+			goto out;
 	}
 
 	/* Device's eeprom is always little-endian, word addressable */
@@ -832,6 +835,7 @@
 		hw->nvm.ops.update(hw);
 
 	igb_set_fw_version(adapter);
+out:
 	kfree(eeprom_buff);
 	return ret_val;
 }
@@ -1401,6 +1405,8 @@
 			*data = 1;
 			return -1;
 		}
+		wr32(E1000_IVAR_MISC, E1000_IVAR_VALID << 8);
+		wr32(E1000_EIMS, BIT(0));
 	} else if (adapter->flags & IGB_FLAG_HAS_MSI) {
 		shared_int = false;
 		if (request_irq(irq,
@@ -2991,11 +2997,15 @@
 	if (err)
 		goto err_out_w_lock;
 
-	igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
+	err = igb_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
+	if (err)
+		goto err_out_input_filter;
 
 	spin_unlock(&adapter->nfc_lock);
 	return 0;
 
+err_out_input_filter:
+	igb_erase_filter(adapter, input);
 err_out_w_lock:
 	spin_unlock(&adapter->nfc_lock);
 err_out:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/igb_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/igb_main.c
@@ -940,6 +940,7 @@
  **/
 static int igb_request_msix(struct igb_adapter *adapter)
 {
+	unsigned int num_q_vectors = adapter->num_q_vectors;
 	struct net_device *netdev = adapter->netdev;
 	int i, err = 0, vector = 0, free_vector = 0;
 
@@ -948,7 +949,13 @@
 	if (err)
 		goto err_out;
 
-	for (i = 0; i < adapter->num_q_vectors; i++) {
+	if (num_q_vectors > MAX_Q_VECTORS) {
+		num_q_vectors = MAX_Q_VECTORS;
+		dev_warn(&adapter->pdev->dev,
+			 "The number of queue vectors (%d) is higher than max allowed (%d)\n",
+			 adapter->num_q_vectors, MAX_Q_VECTORS);
+	}
+	for (i = 0; i < num_q_vectors; i++) {
 		struct igb_q_vector *q_vector = adapter->q_vector[i];
 
 		vector++;
@@ -1206,8 +1213,12 @@
 	if (!q_vector) {
 		q_vector = kzalloc(size, GFP_KERNEL);
 	} else if (size > ksize(q_vector)) {
-		kfree_rcu(q_vector, rcu);
-		q_vector = kzalloc(size, GFP_KERNEL);
+		struct igb_q_vector *new_q_vector;
+
+		new_q_vector = kzalloc(size, GFP_KERNEL);
+		if (new_q_vector)
+			kfree_rcu(q_vector, rcu);
+		q_vector = new_q_vector;
 	} else {
 		memset(q_vector, 0, size);
 	}
@@ -1687,14 +1698,15 @@
  **/
 static void igb_config_tx_modes(struct igb_adapter *adapter, int queue)
 {
-	struct igb_ring *ring = adapter->tx_ring[queue];
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_hw *hw = &adapter->hw;
+	struct igb_ring *ring;
 	u32 tqavcc, tqavctrl;
 	u16 value;
 
 	WARN_ON(hw->mac.type != e1000_i210);
 	WARN_ON(queue < 0 || queue > 1);
+	ring = adapter->tx_ring[queue];
 
 	/* If any of the Qav features is enabled, configure queues as SR and
 	 * with HIGH PRIO. If none is, then configure them with LOW PRIO and
@@ -2651,7 +2663,8 @@
 			}
 
 			input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
-			input->filter.vlan_tci = match.key->vlan_priority;
+			input->filter.vlan_tci =
+				(__force __be16)match.key->vlan_priority;
 		}
 	}
 
@@ -3468,6 +3481,7 @@
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_etherdev:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
@@ -3481,6 +3495,7 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
+	unsigned long flags;
 
 	/* reclaim resources allocated to VFs */
 	if (adapter->vf_data) {
@@ -3493,12 +3508,13 @@
 			pci_disable_sriov(pdev);
 			msleep(500);
 		}
-
+		spin_lock_irqsave(&adapter->vfs_lock, flags);
 		kfree(adapter->vf_mac_list);
 		adapter->vf_mac_list = NULL;
 		kfree(adapter->vf_data);
 		adapter->vf_data = NULL;
 		adapter->vfs_allocated_count = 0;
+		spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 		wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
 		wrfl();
 		msleep(100);
@@ -3694,8 +3710,9 @@
 	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_hw *hw = &adapter->hw;
 
-	/* Virtualization features not supported on i210 family. */
-	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
+	/* Virtualization features not supported on i210 and 82580 family. */
+	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211) ||
+	    (hw->mac.type == e1000_82580))
 		return;
 
 	/* Of the below we really only want the effect of getting
@@ -3819,6 +3836,9 @@
 
 	spin_lock_init(&adapter->nfc_lock);
 	spin_lock_init(&adapter->stats64_lock);
+
+	/* init spinlock to avoid concurrency of VF resources */
+	spin_lock_init(&adapter->vfs_lock);
 #ifdef CONFIG_PCI_IOV
 	switch (hw->mac.type) {
 	case e1000_82576:
@@ -4326,8 +4346,7 @@
 		else
 			mrqc |= E1000_MRQC_ENABLE_VMDQ;
 	} else {
-		if (hw->mac.type != e1000_i211)
-			mrqc |= E1000_MRQC_ENABLE_RSS_MQ;
+		mrqc |= E1000_MRQC_ENABLE_RSS_MQ;
 	}
 	igb_vmm_control(adapter);
 
@@ -4534,6 +4553,10 @@
 static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
 				  struct igb_ring *rx_ring)
 {
+#if (PAGE_SIZE < 8192)
+	struct e1000_hw *hw = &adapter->hw;
+#endif
+
 	/* set build_skb and buffer size flags */
 	clear_ring_build_skb_enabled(rx_ring);
 	clear_ring_uses_large_buffer(rx_ring);
@@ -4544,10 +4567,9 @@
 	set_ring_build_skb_enabled(rx_ring);
 
 #if (PAGE_SIZE < 8192)
-	if (adapter->max_frame_size <= IGB_MAX_FRAME_BUILD_SKB)
-		return;
-
-	set_ring_uses_large_buffer(rx_ring);
+	if (adapter->max_frame_size > IGB_MAX_FRAME_BUILD_SKB ||
+	    rd32(E1000_RCTL) & E1000_RCTL_SBP)
+		set_ring_uses_large_buffer(rx_ring);
 #endif
 }
 
@@ -4657,6 +4679,8 @@
 					       DMA_TO_DEVICE);
 		}
 
+		tx_buffer->next_to_watch = NULL;
+
 		/* move us one more past the eop_desc for start of next pkt */
 		tx_buffer++;
 		i++;
@@ -5307,7 +5331,8 @@
 				break;
 			}
 
-			if (adapter->link_speed != SPEED_1000)
+			if (adapter->link_speed != SPEED_1000 ||
+			    !hw->phy.ops.read_reg)
 				goto no_wait;
 
 			/* wait for Remote receiver status OK */
@@ -6194,9 +6219,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();
 }
 
 /**
@@ -7105,7 +7139,7 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 	unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
-	u32 reg, msgbuf[3];
+	u32 reg, msgbuf[3] = {};
 	u8 *addr = (u8 *)(&msgbuf[1]);
 
 	/* process all the same items cleared in a function level reset */
@@ -7354,6 +7388,20 @@
 	struct vf_mac_filter *entry = NULL;
 	int ret = 0;
 
+	if ((vf_data->flags & IGB_VF_FLAG_PF_SET_MAC) &&
+	    !vf_data->trusted) {
+		dev_warn(&pdev->dev,
+			 "VF %d requested MAC filter but is administratively denied\n",
+			  vf);
+		return -EINVAL;
+	}
+	if (!is_valid_ether_addr(addr)) {
+		dev_warn(&pdev->dev,
+			 "VF %d attempted to set invalid MAC filter\n",
+			  vf);
+		return -EINVAL;
+	}
+
 	switch (info) {
 	case E1000_VF_MAC_FILTER_CLR:
 		/* remove all unicast MAC filters related to the current VF */
@@ -7367,20 +7415,6 @@
 		}
 		break;
 	case E1000_VF_MAC_FILTER_ADD:
-		if ((vf_data->flags & IGB_VF_FLAG_PF_SET_MAC) &&
-		    !vf_data->trusted) {
-			dev_warn(&pdev->dev,
-				 "VF %d requested MAC filter but is administratively denied\n",
-				 vf);
-			return -EINVAL;
-		}
-		if (!is_valid_ether_addr(addr)) {
-			dev_warn(&pdev->dev,
-				 "VF %d attempted to set invalid MAC filter\n",
-				 vf);
-			return -EINVAL;
-		}
-
 		/* try to find empty slot in the list */
 		list_for_each(pos, &adapter->vf_macs.l) {
 			entry = list_entry(pos, struct vf_mac_filter, l);
@@ -7548,8 +7582,10 @@
 static void igb_msg_task(struct igb_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
+	unsigned long flags;
 	u32 vf;
 
+	spin_lock_irqsave(&adapter->vfs_lock, flags);
 	for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
 		/* process any reset requests */
 		if (!igb_check_for_rst(hw, vf))
@@ -7563,6 +7599,7 @@
 		if (!igb_check_for_ack(hw, vf))
 			igb_rcv_ack_from_vf(adapter, vf);
 	}
+	spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 }
 
 /**
@@ -7732,7 +7769,7 @@
 	if (likely(napi_complete_done(napi, work_done)))
 		igb_ring_irq_enable(q_vector);
 
-	return min(work_done, budget - 1);
+	return work_done;
 }
 
 /**
@@ -8247,7 +8284,7 @@
 
 		if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
 		    test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
-			vid = be16_to_cpu(rx_desc->wb.upper.vlan);
+			vid = be16_to_cpu((__force __be16)rx_desc->wb.upper.vlan);
 		else
 			vid = le16_to_cpu(rx_desc->wb.upper.vlan);
 
@@ -8995,6 +9032,11 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct igb_adapter *adapter = netdev_priv(netdev);
 
+	if (state == pci_channel_io_normal) {
+		dev_warn(&pdev->dev, "Non-correctable non-fatal error reported.\n");
+		return PCI_ERS_RESULT_CAN_RECOVER;
+	}
+
 	netif_device_detach(netdev);
 
 	if (state == pci_channel_io_perm_failure)
@@ -9383,11 +9425,10 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 dmac_thr;
 	u16 hwm;
+	u32 reg;
 
 	if (hw->mac.type > e1000_82580) {
 		if (adapter->flags & IGB_FLAG_DMAC) {
-			u32 reg;
-
 			/* force threshold to 0. */
 			wr32(E1000_DMCTXTH, 0);
 
@@ -9420,7 +9461,6 @@
 			/* Disable BMC-to-OS Watchdog Enable */
 			if (hw->mac.type != e1000_i354)
 				reg &= ~E1000_DMACR_DC_BMC2OSW_EN;
-
 			wr32(E1000_DMACR, reg);
 
 			/* no lower threshold to disable
@@ -9437,12 +9477,12 @@
 			 */
 			wr32(E1000_DMCTXTH, (IGB_MIN_TXPBSIZE -
 			     (IGB_TX_BUF_4096 + adapter->max_frame_size)) >> 6);
+		}
 
-			/* make low power state decision controlled
-			 * by DMA coal
-			 */
+		if (hw->mac.type >= e1000_i210 ||
+		    (adapter->flags & IGB_FLAG_DMAC)) {
 			reg = rd32(E1000_PCIEMISC);
-			reg &= ~E1000_PCIEMISC_LX_DECISION;
+			reg |= E1000_PCIEMISC_LX_DECISION;
 			wr32(E1000_PCIEMISC, reg);
 		} /* endif adapter->dmac is not disabled */
 	} else if (hw->mac.type == e1000_82580) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -1245,18 +1245,6 @@
 		return;
 	}
 
-	spin_lock_init(&adapter->tmreg_lock);
-	INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
-
-	if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK)
-		INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
-				  igb_ptp_overflow_check);
-
-	adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
-	adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
-
-	igb_ptp_reset(adapter);
-
 	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
 						&adapter->pdev->dev);
 	if (IS_ERR(adapter->ptp_clock)) {
@@ -1266,6 +1254,18 @@
 		dev_info(&adapter->pdev->dev, "added PHC on %s\n",
 			 adapter->netdev->name);
 		adapter->ptp_flags |= IGB_PTP_ENABLED;
+
+		spin_lock_init(&adapter->tmreg_lock);
+		INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
+
+		if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK)
+			INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
+					  igb_ptp_overflow_check);
+
+		adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+		adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+
+		igb_ptp_reset(adapter);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igbvf/igbvf.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igbvf/igbvf.h
@@ -39,11 +39,11 @@
 /* Tx/Rx descriptor defines */
 #define IGBVF_DEFAULT_TXD	256
 #define IGBVF_MAX_TXD		4096
-#define IGBVF_MIN_TXD		80
+#define IGBVF_MIN_TXD		64
 
 #define IGBVF_DEFAULT_RXD	256
 #define IGBVF_MAX_RXD		4096
-#define IGBVF_MIN_RXD		80
+#define IGBVF_MIN_RXD		64
 
 #define IGBVF_MIN_ITR_USECS	10 /* 100000 irq/sec */
 #define IGBVF_MAX_ITR_USECS	10000 /* 100    irq/sec */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igbvf/netdev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -83,14 +83,14 @@
 static void igbvf_receive_skb(struct igbvf_adapter *adapter,
 			      struct net_device *netdev,
 			      struct sk_buff *skb,
-			      u32 status, u16 vlan)
+			      u32 status, __le16 vlan)
 {
 	u16 vid;
 
 	if (status & E1000_RXD_STAT_VP) {
 		if ((adapter->flags & IGBVF_FLAG_RX_LB_VLAN_BSWAP) &&
 		    (status & E1000_RXDEXT_STATERR_LB))
-			vid = be16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
+			vid = be16_to_cpu((__force __be16)vlan) & E1000_RXD_SPC_VLAN_MASK;
 		else
 			vid = le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
 		if (test_bit(vid, adapter->active_vlans))
@@ -1070,7 +1070,7 @@
 			  igbvf_intr_msix_rx, 0, adapter->rx_ring->name,
 			  netdev);
 	if (err)
-		goto out;
+		goto free_irq_tx;
 
 	adapter->rx_ring->itr_register = E1000_EITR(vector);
 	adapter->rx_ring->itr_val = adapter->current_itr;
@@ -1079,10 +1079,14 @@
 	err = request_irq(adapter->msix_entries[vector].vector,
 			  igbvf_msix_other, 0, netdev->name, netdev);
 	if (err)
-		goto out;
+		goto free_irq_rx;
 
 	igbvf_configure_msix(adapter);
 	return 0;
+free_irq_rx:
+	free_irq(adapter->msix_entries[--vector].vector, netdev);
+free_irq_tx:
+	free_irq(adapter->msix_entries[--vector].vector, netdev);
 out:
 	return err;
 }
@@ -2887,6 +2891,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-ein-5.4.0.orig/drivers/net/ethernet/intel/igbvf/vf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igbvf/vf.c
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2009 - 2018 Intel Corporation. */
 
+#include <linux/etherdevice.h>
+
 #include "vf.h"
 
 static s32 e1000_check_for_link_vf(struct e1000_hw *hw);
@@ -131,11 +133,16 @@
 		/* set our "perm_addr" based on info provided by PF */
 		ret_val = mbx->ops.read_posted(hw, msgbuf, 3);
 		if (!ret_val) {
-			if (msgbuf[0] == (E1000_VF_RESET |
-					  E1000_VT_MSGTYPE_ACK))
+			switch (msgbuf[0]) {
+			case E1000_VF_RESET | E1000_VT_MSGTYPE_ACK:
 				memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
-			else
+				break;
+			case E1000_VF_RESET | E1000_VT_MSGTYPE_NACK:
+				eth_zero_addr(hw->mac.perm_addr);
+				break;
+			default:
 				ret_val = -E1000_ERR_MAC_INIT;
+			}
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc.h
@@ -78,11 +78,11 @@
 /* TX/RX descriptor defines */
 #define IGC_DEFAULT_TXD		256
 #define IGC_DEFAULT_TX_WORK	128
-#define IGC_MIN_TXD		80
+#define IGC_MIN_TXD		64
 #define IGC_MAX_TXD		4096
 
 #define IGC_DEFAULT_RXD		256
-#define IGC_MIN_RXD		80
+#define IGC_MIN_RXD		64
 #define IGC_MAX_RXD		4096
 
 /* Transmit and receive queues */
@@ -504,7 +504,7 @@
 	if (hw->phy.ops.read_reg)
 		return hw->phy.ops.read_reg(hw, offset, data);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 /* forward declaration */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_base.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_base.c
@@ -187,15 +187,7 @@
 
 	igc_check_for_copper_link(hw);
 
-	/* Verify phy id and set remaining function pointers */
-	switch (phy->id) {
-	case I225_I_PHY_ID:
-		phy->type	= igc_phy_i225;
-		break;
-	default:
-		ret_val = -IGC_ERR_PHY;
-		goto out;
-	}
+	phy->type = igc_phy_i225;
 
 out:
 	return ret_val;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_defines.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -360,6 +360,7 @@
 /* PHY Status Register */
 #define MII_SR_LINK_STATUS	0x0004 /* Link Status 1 = link */
 #define MII_SR_AUTONEG_COMPLETE	0x0020 /* Auto Neg Complete */
+#define IGC_PHY_RST_COMP	0x0100 /* Internal PHY reset completion */
 
 /* PHY 1000 MII Register/Bit Definitions */
 /* PHY Registers defined by IEEE */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1668,14 +1668,22 @@
 	/* twisted pair */
 	cmd->base.port = PORT_TP;
 	cmd->base.phy_address = hw->phy.addr;
+	ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
+	ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
 
 	/* advertising link modes */
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
-	ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
+	if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
+	if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
+	if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
+	if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
+	if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
+	if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
 
 	/* set autoneg settings */
 	if (hw->mac.autoneg == 1) {
@@ -1684,6 +1692,9 @@
 						     Autoneg);
 	}
 
+	/* Set pause flow control settings */
+	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
+
 	switch (hw->fc.requested_mode) {
 	case igc_fc_full:
 		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
@@ -1698,12 +1709,11 @@
 						     Asym_Pause);
 		break;
 	default:
-		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
-		ethtool_link_ksettings_add_link_mode(cmd, advertising,
-						     Asym_Pause);
+		break;
 	}
 
-	status = rd32(IGC_STATUS);
+	status = pm_runtime_suspended(&adapter->pdev->dev) ?
+		 0 : rd32(IGC_STATUS);
 
 	if (status & IGC_STATUS_LU) {
 		if (status & IGC_STATUS_SPEED_1000) {
@@ -1758,7 +1768,7 @@
 {
 	struct igc_adapter *adapter = netdev_priv(netdev);
 	struct igc_hw *hw = &adapter->hw;
-	u32 advertising;
+	u16 advertised = 0;
 
 	/* When adapter in resetting mode, autoneg/speed/duplex
 	 * cannot be changed
@@ -1784,12 +1794,33 @@
 	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
 		usleep_range(1000, 2000);
 
-	ethtool_convert_link_mode_to_legacy_u32(&advertising,
-						cmd->link_modes.advertising);
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  2500baseT_Full))
+		advertised |= ADVERTISE_2500_FULL;
+
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  1000baseT_Full))
+		advertised |= ADVERTISE_1000_FULL;
+
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  100baseT_Full))
+		advertised |= ADVERTISE_100_FULL;
+
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  100baseT_Half))
+		advertised |= ADVERTISE_100_HALF;
+
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  10baseT_Full))
+		advertised |= ADVERTISE_10_FULL;
+
+	if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+						  10baseT_Half))
+		advertised |= ADVERTISE_10_HALF;
 
 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
 		hw->mac.autoneg = 1;
-		hw->phy.autoneg_advertised = advertising;
+		hw->phy.autoneg_advertised = advertised;
 		if (adapter->fc_autoneg)
 			hw->fc.requested_mode = igc_fc_default;
 	} else {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_i225.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_i225.c
@@ -156,8 +156,15 @@
 {
 	u32 swfw_sync;
 
-	while (igc_get_hw_semaphore_i225(hw))
-		; /* Empty */
+	/* Releasing the resource requires first getting the HW semaphore.
+	 * If we fail to get the semaphore, there is nothing we can do,
+	 * except log an error and quit. We are not allowed to hang here
+	 * indefinitely, as it may cause denial of service or system crash.
+	 */
+	if (igc_get_hw_semaphore_i225(hw)) {
+		hw_dbg("Failed to release SW_FW_SYNC.\n");
+		return;
+	}
 
 	swfw_sync = rd32(IGC_SW_FW_SYNC);
 	swfw_sync &= ~mask;
@@ -219,9 +226,9 @@
 			      u16 *data)
 {
 	struct igc_nvm_info *nvm = &hw->nvm;
+	s32 ret_val = -IGC_ERR_NVM;
 	u32 attempts = 100000;
 	u32 i, k, eewr = 0;
-	s32 ret_val = 0;
 
 	/* A check for invalid values:  offset too large, too many words,
 	 * too many words for the offset, and not enough words.
@@ -229,7 +236,6 @@
 	if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
 	    words == 0) {
 		hw_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -IGC_ERR_NVM;
 		goto out;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -647,7 +647,7 @@
 	}
 
 out:
-	return 0;
+	return ret_val;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_main.c
@@ -256,6 +256,8 @@
 					       DMA_TO_DEVICE);
 		}
 
+		tx_buffer->next_to_watch = NULL;
+
 		/* move us one more past the eop_desc for start of next pkt */
 		tx_buffer++;
 		i++;
@@ -608,7 +610,6 @@
 	/* disable the queue */
 	wr32(IGC_TXDCTL(reg_idx), 0);
 	wrfl();
-	mdelay(10);
 
 	wr32(IGC_TDLEN(reg_idx),
 	     ring->count * sizeof(union igc_adv_tx_desc));
@@ -2222,21 +2223,23 @@
 }
 
 /**
- * igc_get_stats - Get System Network Statistics
+ * igc_get_stats64 - Get System Network Statistics
  * @netdev: network interface device structure
+ * @stats: rtnl_link_stats64 pointer
  *
  * Returns the address of the device statistics structure.
  * The statistics are updated here and also from the timer callback.
  */
-static struct net_device_stats *igc_get_stats(struct net_device *netdev)
+static void igc_get_stats64(struct net_device *netdev,
+			    struct rtnl_link_stats64 *stats)
 {
 	struct igc_adapter *adapter = netdev_priv(netdev);
 
+	spin_lock(&adapter->stats64_lock);
 	if (!test_bit(__IGC_RESETTING, &adapter->state))
 		igc_update_stats(adapter);
-
-	/* only return the current stats */
-	return &netdev->stats;
+	memcpy(stats, &adapter->stats64, sizeof(*stats));
+	spin_unlock(&adapter->stats64_lock);
 }
 
 static netdev_features_t igc_fix_features(struct net_device *netdev,
@@ -2689,6 +2692,7 @@
  */
 static int igc_request_msix(struct igc_adapter *adapter)
 {
+	unsigned int num_q_vectors = adapter->num_q_vectors;
 	int i = 0, err = 0, vector = 0, free_vector = 0;
 	struct net_device *netdev = adapter->netdev;
 
@@ -2697,7 +2701,13 @@
 	if (err)
 		goto err_out;
 
-	for (i = 0; i < adapter->num_q_vectors; i++) {
+	if (num_q_vectors > MAX_Q_VECTORS) {
+		num_q_vectors = MAX_Q_VECTORS;
+		dev_warn(&adapter->pdev->dev,
+			 "The number of queue vectors (%d) is higher than max allowed (%d)\n",
+			 adapter->num_q_vectors, MAX_Q_VECTORS);
+	}
+	for (i = 0; i < num_q_vectors; i++) {
 		struct igc_q_vector *q_vector = adapter->q_vector[i];
 
 		vector++;
@@ -2873,8 +2883,7 @@
 		break;
 	}
 
-	if (hw->mac.type == igc_i225 &&
-	    hw->phy.id == I225_I_PHY_ID) {
+	if (hw->mac.type == igc_i225) {
 		if (!netif_carrier_ok(adapter->netdev)) {
 			adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
 		} else if (!(adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)) {
@@ -3984,7 +3993,7 @@
 	.ndo_start_xmit		= igc_xmit_frame,
 	.ndo_set_mac_address	= igc_set_mac,
 	.ndo_change_mtu		= igc_change_mtu,
-	.ndo_get_stats		= igc_get_stats,
+	.ndo_get_stats64	= igc_get_stats64,
 	.ndo_fix_features	= igc_fix_features,
 	.ndo_set_features	= igc_set_features,
 	.ndo_features_check	= igc_features_check,
@@ -4308,8 +4317,8 @@
 err_ioremap:
 	free_netdev(netdev);
 err_alloc_etherdev:
-	pci_release_selected_regions(pdev,
-				     pci_select_bars(pdev, IORESOURCE_MEM));
+	pci_disable_pcie_error_reporting(pdev);
+	pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
 	pci_disable_device(pdev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_phy.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -173,6 +173,7 @@
 s32 igc_phy_hw_reset(struct igc_hw *hw)
 {
 	struct igc_phy_info *phy = &hw->phy;
+	u32 phpm = 0, timeout = 10000;
 	s32  ret_val;
 	u32 ctrl;
 
@@ -186,6 +187,8 @@
 	if (ret_val)
 		goto out;
 
+	phpm = rd32(IGC_I225_PHPM);
+
 	ctrl = rd32(IGC_CTRL);
 	wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
 	wrfl();
@@ -195,7 +198,18 @@
 	wr32(IGC_CTRL, ctrl);
 	wrfl();
 
-	usleep_range(1500, 2000);
+	/* SW should guarantee 100us for the completion of the PHY reset */
+	usleep_range(100, 150);
+	do {
+		phpm = rd32(IGC_I225_PHPM);
+		timeout--;
+		udelay(1);
+	} while (!(phpm & IGC_PHY_RST_COMP) && timeout);
+
+	if (!timeout)
+		hw_dbg("Timeout is expired after a phy reset\n");
+
+	usleep_range(100, 150);
 
 	phy->ops.release(hw);
 
@@ -235,8 +249,7 @@
 			return ret_val;
 	}
 
-	if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
-	    hw->phy.id == I225_I_PHY_ID) {
+	if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
 		/* Read the MULTI GBT AN Control Register - reg 7.32 */
 		ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
 					    MMD_DEVADDR_SHIFT) |
@@ -376,8 +389,7 @@
 		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
 					     mii_1000t_ctrl_reg);
 
-	if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
-	    hw->phy.id == I225_I_PHY_ID)
+	if (phy->autoneg_mask & ADVERTISE_2500_FULL)
 		ret_val = phy->ops.write_reg(hw,
 					     (STANDARD_AN_REG_MASK <<
 					     MMD_DEVADDR_SHIFT) |
@@ -569,7 +581,7 @@
 	 * the lower time out
 	 */
 	for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
-		usleep_range(500, 1000);
+		udelay(50);
 		mdic = rd32(IGC_MDIC);
 		if (mdic & IGC_MDIC_READY)
 			break;
@@ -626,7 +638,7 @@
 	 * the lower time out
 	 */
 	for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
-		usleep_range(500, 1000);
+		udelay(50);
 		mdic = rd32(IGC_MDIC);
 		if (mdic & IGC_MDIC_READY)
 			break;
@@ -734,8 +746,6 @@
 		if (ret_val)
 			return ret_val;
 		ret_val = igc_write_phy_reg_mdic(hw, offset, data);
-		if (ret_val)
-			return ret_val;
 		hw->phy.ops.release(hw);
 	} else {
 		ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
@@ -767,8 +777,6 @@
 		if (ret_val)
 			return ret_val;
 		ret_val = igc_read_phy_reg_mdic(hw, offset, data);
-		if (ret_val)
-			return ret_val;
 		hw->phy.ops.release(hw);
 	} else {
 		ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/igc/igc_regs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -12,6 +12,7 @@
 #define IGC_MDIC		0x00020  /* MDI Control - RW */
 #define IGC_MDICNFG		0x00E04  /* MDC/MDIO Configuration - RW */
 #define IGC_CONNSW		0x00034  /* Copper/Fiber switch control - RW */
+#define IGC_I225_PHPM		0x00E14  /* I225 PHY Power Management */
 
 /* Internal Packet Buffer Size Registers */
 #define IGC_RXPBS		0x02404  /* Rx Packet Buffer Size - RW */
@@ -236,4 +237,6 @@
 
 #define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
 
+#define IGC_REMOVED(h) unlikely(!(h))
+
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -67,6 +67,8 @@
 #define IXGBE_RXBUFFER_4K    4096
 #define IXGBE_MAX_RXBUFFER  16384  /* largest size for a single descriptor */
 
+#define IXGBE_PKT_HDR_PAD   (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2))
+
 /* Attempt to maximize the headroom available for incoming frames.  We
  * use a 2K buffer for receives and need 1536/1534 to store the data for
  * the frame.  This leaves us with 512 bytes of room.  From that we need
@@ -177,11 +179,14 @@
 	u16 pf_vlan; /* When set, guest VLAN config not allowed. */
 	u16 pf_qos;
 	u16 tx_rate;
+	int link_enable;
+	int link_state;
 	u8 spoofchk_enabled;
 	bool rss_query_enabled;
 	u8 trusted;
 	int xcast_mode;
 	unsigned int vf_api;
+	u8 primary_abort_count;
 };
 
 enum ixgbevf_xcast_modes {
@@ -553,6 +558,8 @@
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
 #define IXGBE_SFP_POLL_JIFFIES (2 * HZ)	/* SFP poll every 2 seconds */
 
+#define IXGBE_PRIMARY_ABORT_LIMIT	5
+
 /* board specific private data structure */
 struct ixgbe_adapter {
 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -614,6 +621,7 @@
 #define IXGBE_FLAG2_RX_LEGACY			BIT(16)
 #define IXGBE_FLAG2_IPSEC_ENABLED		BIT(17)
 #define IXGBE_FLAG2_VF_IPSEC_ENABLED		BIT(18)
+#define IXGBE_FLAG2_AUTO_DISABLE_VF		BIT(19)
 
 	/* Tx fast path data */
 	int num_tx_queues;
@@ -773,6 +781,7 @@
 #ifdef CONFIG_IXGBE_IPSEC
 	struct ixgbe_ipsec *ipsec;
 #endif /* CONFIG_IXGBE_IPSEC */
+	spinlock_t vfs_lock;
 };
 
 static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -123,14 +123,14 @@
 		if (ret_val)
 			return ret_val;
 		if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
-			return IXGBE_ERR_SFP_NOT_SUPPORTED;
+			return -EOPNOTSUPP;
 
 		/* Check to see if SFP+ module is supported */
 		ret_val = ixgbe_get_sfp_init_sequence_offsets(hw,
 							    &list_offset,
 							    &data_offset);
 		if (ret_val)
-			return IXGBE_ERR_SFP_NOT_SUPPORTED;
+			return -EOPNOTSUPP;
 		break;
 	default:
 		break;
@@ -213,7 +213,7 @@
 		break;
 
 	default:
-		return IXGBE_ERR_LINK_SETUP;
+		return -EIO;
 	}
 
 	return 0;
@@ -283,7 +283,7 @@
 
 	/* Validate the water mark configuration */
 	if (!hw->fc.pause_time)
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 
 	/* Low water mark of zero causes XOFF floods */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
@@ -292,7 +292,7 @@
 			if (!hw->fc.low_water[i] ||
 			    hw->fc.low_water[i] >= hw->fc.high_water[i]) {
 				hw_dbg(hw, "Invalid water mark configuration\n");
-				return IXGBE_ERR_INVALID_LINK_SETTINGS;
+				return -EINVAL;
 			}
 		}
 	}
@@ -369,7 +369,7 @@
 		break;
 	default:
 		hw_dbg(hw, "Flow control param set incorrectly\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	/* Set 802.3x based flow control settings. */
@@ -438,7 +438,7 @@
 				msleep(100);
 			}
 			if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
-				status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+				status = -EIO;
 				hw_dbg(hw, "Autonegotiation did not complete.\n");
 			}
 		}
@@ -478,7 +478,7 @@
 
 	if (timeout == IXGBE_VALIDATE_LINK_READY_TIMEOUT) {
 		hw_dbg(hw, "Link was indicated but link is down\n");
-		return IXGBE_ERR_LINK_SETUP;
+		return -EIO;
 	}
 
 	return 0;
@@ -594,7 +594,7 @@
 	speed &= link_capabilities;
 
 	if (speed == IXGBE_LINK_SPEED_UNKNOWN)
-		return IXGBE_ERR_LINK_SETUP;
+		return -EINVAL;
 
 	/* Set KX4/KX support according to speed requested */
 	else if (link_mode == IXGBE_AUTOC_LMS_KX4_AN ||
@@ -701,9 +701,9 @@
 
 		/* Init PHY and function pointers, perform SFP setup */
 		phy_status = hw->phy.ops.init(hw);
-		if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+		if (phy_status == -EOPNOTSUPP)
 			return phy_status;
-		if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT)
+		if (phy_status == -ENOENT)
 			goto mac_reset_top;
 
 		hw->phy.ops.reset(hw);
@@ -727,7 +727,7 @@
 		udelay(1);
 	}
 	if (ctrl & IXGBE_CTRL_RST) {
-		status = IXGBE_ERR_RESET_FAILED;
+		status = -EIO;
 		hw_dbg(hw, "Reset polling failed to complete.\n");
 	}
 
@@ -789,7 +789,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (rar >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
@@ -814,7 +814,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (rar >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
@@ -845,7 +845,7 @@
 	u32 vftabyte;
 
 	if (vlan > 4095)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* Determine 32-bit word position in array */
 	regindex = (vlan >> 5) & 0x7F;   /* upper seven bits */
@@ -964,7 +964,7 @@
 		gssr = IXGBE_GSSR_PHY0_SM;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	if (hw->phy.type == ixgbe_phy_nl) {
 		/*
@@ -993,7 +993,7 @@
 
 		if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) {
 			hw_dbg(hw, "EEPROM read did not pass.\n");
-			status = IXGBE_ERR_SFP_NOT_PRESENT;
+			status = -ENOENT;
 			goto out;
 		}
 
@@ -1003,7 +1003,7 @@
 
 		*eeprom_data = (u8)(sfp_data >> 8);
 	} else {
-		status = IXGBE_ERR_PHY;
+		status = -EIO;
 	}
 
 out:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -117,7 +117,7 @@
 		ret_val = hw->mac.ops.acquire_swfw_sync(hw,
 							IXGBE_GSSR_MAC_CSR_SM);
 		if (ret_val)
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		if (hw->eeprom.ops.read(hw, ++data_offset, &data_value))
 			goto setup_sfp_err;
@@ -144,7 +144,7 @@
 
 		if (ret_val) {
 			hw_dbg(hw, " sfp module setup not complete\n");
-			return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+			return -EIO;
 		}
 	}
 
@@ -159,7 +159,7 @@
 	usleep_range(hw->eeprom.semaphore_delay * 1000,
 		     hw->eeprom.semaphore_delay * 2000);
 	hw_err(hw, "eeprom read at offset %d failed\n", data_offset);
-	return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+	return -EIO;
 }
 
 /**
@@ -184,7 +184,7 @@
 		ret_val = hw->mac.ops.acquire_swfw_sync(hw,
 					IXGBE_GSSR_MAC_CSR_SM);
 		if (ret_val)
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		*locked = true;
 	}
@@ -219,7 +219,7 @@
 		ret_val = hw->mac.ops.acquire_swfw_sync(hw,
 					IXGBE_GSSR_MAC_CSR_SM);
 		if (ret_val)
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		locked = true;
 	}
@@ -400,7 +400,7 @@
 		break;
 
 	default:
-		return IXGBE_ERR_LINK_SETUP;
+		return -EIO;
 	}
 
 	if (hw->phy.multispeed_fiber) {
@@ -541,7 +541,7 @@
 				msleep(100);
 			}
 			if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
-				status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+				status = -EIO;
 				hw_dbg(hw, "Autoneg did not complete.\n");
 			}
 		}
@@ -794,7 +794,7 @@
 	speed &= link_capabilities;
 
 	if (speed == IXGBE_LINK_SPEED_UNKNOWN)
-		return IXGBE_ERR_LINK_SETUP;
+		return -EINVAL;
 
 	/* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
 	if (hw->mac.orig_link_settings_stored)
@@ -861,8 +861,7 @@
 					msleep(100);
 				}
 				if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
-					status =
-						IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+					status = -EIO;
 					hw_dbg(hw, "Autoneg did not complete.\n");
 				}
 			}
@@ -927,7 +926,7 @@
 	/* Identify PHY and related function pointers */
 	status = hw->phy.ops.init(hw);
 
-	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (status == -EOPNOTSUPP)
 		return status;
 
 	/* Setup SFP module if there is one present. */
@@ -936,7 +935,7 @@
 		hw->phy.sfp_setup_needed = false;
 	}
 
-	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (status == -EOPNOTSUPP)
 		return status;
 
 	/* Reset PHY */
@@ -974,7 +973,7 @@
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
-		status = IXGBE_ERR_RESET_FAILED;
+		status = -EIO;
 		hw_dbg(hw, "Reset polling failed to complete.\n");
 	}
 
@@ -1093,7 +1092,7 @@
 		udelay(10);
 	}
 
-	return IXGBE_ERR_FDIR_CMD_INCOMPLETE;
+	return -EIO;
 }
 
 /**
@@ -1155,7 +1154,7 @@
 	}
 	if (i >= IXGBE_FDIR_INIT_DONE_POLL) {
 		hw_dbg(hw, "Flow Director Signature poll time exceeded!\n");
-		return IXGBE_ERR_FDIR_REINIT_FAILED;
+		return -EIO;
 	}
 
 	/* Clear FDIR statistics registers (read to clear) */
@@ -1387,7 +1386,7 @@
 		break;
 	default:
 		hw_dbg(hw, " Error on flow type input\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	/* configure FDIRCMD register */
@@ -1546,7 +1545,7 @@
 		break;
 	default:
 		hw_dbg(hw, " Error on vm pool mask\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	switch (input_mask->formatted.flow_type & IXGBE_ATR_L4TYPE_MASK) {
@@ -1555,13 +1554,13 @@
 		if (input_mask->formatted.dst_port ||
 		    input_mask->formatted.src_port) {
 			hw_dbg(hw, " Error on src/dst port mask\n");
-			return IXGBE_ERR_CONFIG;
+			return -EIO;
 		}
 	case IXGBE_ATR_L4TYPE_MASK:
 		break;
 	default:
 		hw_dbg(hw, " Error on flow type mask\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	switch (ntohs(input_mask->formatted.vlan_id) & 0xEFFF) {
@@ -1582,7 +1581,7 @@
 		break;
 	default:
 		hw_dbg(hw, " Error on VLAN mask\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	switch ((__force u16)input_mask->formatted.flex_bytes & 0xFFFF) {
@@ -1594,7 +1593,7 @@
 		break;
 	default:
 		hw_dbg(hw, " Error on flexible byte mask\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
@@ -1823,7 +1822,7 @@
 
 	/* Return error if SFP module has been detected but is not supported */
 	if (hw->phy.type == ixgbe_phy_sfp_unsupported)
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 
 	return status;
 }
@@ -1862,13 +1861,13 @@
  *  Verifies that installed the firmware version is 0.6 or higher
  *  for SFI devices. All 82599 SFI devices should have version 0.6 or higher.
  *
- *  Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or
- *  if the FW version is not supported.
+ *  Return: -EACCES if the FW is not present or if the FW version is
+ *  not supported.
  **/
 static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
 {
-	s32 status = IXGBE_ERR_EEPROM_VERSION;
 	u16 fw_offset, fw_ptp_cfg_offset;
+	s32 status = -EACCES;
 	u16 offset;
 	u16 fw_version = 0;
 
@@ -1882,7 +1881,7 @@
 		goto fw_version_err;
 
 	if (fw_offset == 0 || fw_offset == 0xFFFF)
-		return IXGBE_ERR_EEPROM_VERSION;
+		return -EACCES;
 
 	/* get the offset to the Pass Through Patch Configuration block */
 	offset = fw_offset + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR;
@@ -1890,7 +1889,7 @@
 		goto fw_version_err;
 
 	if (fw_ptp_cfg_offset == 0 || fw_ptp_cfg_offset == 0xFFFF)
-		return IXGBE_ERR_EEPROM_VERSION;
+		return -EACCES;
 
 	/* get the firmware version */
 	offset = fw_ptp_cfg_offset + IXGBE_FW_PATCH_VERSION_4;
@@ -1904,7 +1903,7 @@
 
 fw_version_err:
 	hw_err(hw, "eeprom read at offset %d failed\n", offset);
-	return IXGBE_ERR_EEPROM_VERSION;
+	return -EACCES;
 }
 
 /**
@@ -2037,7 +2036,7 @@
 
 	if (!(anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)) {
 		hw_dbg(hw, "auto negotiation not completed\n");
-		ret_val = IXGBE_ERR_RESET_FAILED;
+		ret_val = -EIO;
 		goto reset_pipeline_out;
 	}
 
@@ -2086,7 +2085,7 @@
 
 		if (!timeout) {
 			hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
-			status = IXGBE_ERR_I2C;
+			status = -EIO;
 			goto release_i2c_access;
 		}
 	}
@@ -2140,7 +2139,7 @@
 
 		if (!timeout) {
 			hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
-			status = IXGBE_ERR_I2C;
+			status = -EIO;
 			goto release_i2c_access;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -30,7 +30,7 @@
 					     u16 words, u16 *data);
 static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
 						 u16 offset);
-static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
+static s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw);
 
 /* Base table for registers values that change by MAC */
 const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT] = {
@@ -124,7 +124,7 @@
 	 */
 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
 		hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 	}
 
 	/*
@@ -215,7 +215,7 @@
 		break;
 	default:
 		hw_dbg(hw, "Flow control param set incorrectly\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	if (hw->mac.type != ixgbe_mac_X540) {
@@ -500,7 +500,7 @@
 
 	if (pba_num == NULL) {
 		hw_dbg(hw, "PBA string buffer was null\n");
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data);
@@ -526,7 +526,7 @@
 		/* we will need 11 characters to store the PBA */
 		if (pba_num_size < 11) {
 			hw_dbg(hw, "PBA string buffer too small\n");
-			return IXGBE_ERR_NO_SPACE;
+			return -ENOSPC;
 		}
 
 		/* extract hex string from data and pba_ptr */
@@ -563,13 +563,13 @@
 
 	if (length == 0xFFFF || length == 0) {
 		hw_dbg(hw, "NVM PBA number section invalid length\n");
-		return IXGBE_ERR_PBA_SECTION;
+		return -EIO;
 	}
 
 	/* check if pba_num buffer is big enough */
 	if (pba_num_size  < (((u32)length * 2) - 1)) {
 		hw_dbg(hw, "PBA string buffer too small\n");
-		return IXGBE_ERR_NO_SPACE;
+		return -ENOSPC;
 	}
 
 	/* trim pba length from start of string */
@@ -746,10 +746,10 @@
 	usleep_range(1000, 2000);
 
 	/*
-	 * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+	 * Prevent the PCI-E bus from hanging by disabling PCI-E primary
 	 * access and verify no pending requests
 	 */
-	return ixgbe_disable_pcie_master(hw);
+	return ixgbe_disable_pcie_primary(hw);
 }
 
 /**
@@ -805,7 +805,7 @@
 	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* To turn on the LED, set mode to ON. */
 	led_reg &= ~IXGBE_LED_MODE_MASK(index);
@@ -826,7 +826,7 @@
 	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* To turn off the LED, set mode to OFF. */
 	led_reg &= ~IXGBE_LED_MODE_MASK(index);
@@ -904,11 +904,8 @@
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (words == 0)
-		return IXGBE_ERR_INVALID_ARGUMENT;
-
-	if (offset + words > hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+	if (words == 0 || (offset + words > hw->eeprom.word_size))
+		return -EINVAL;
 
 	/*
 	 * The EEPROM page size cannot be queried from the chip. We do lazy
@@ -962,7 +959,7 @@
 
 	if (ixgbe_ready_eeprom(hw) != 0) {
 		ixgbe_release_eeprom(hw);
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	for (i = 0; i < words; i++) {
@@ -1028,7 +1025,7 @@
 	hw->eeprom.ops.init_params(hw);
 
 	if (offset >= hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+		return -EINVAL;
 
 	return ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data);
 }
@@ -1050,11 +1047,8 @@
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (words == 0)
-		return IXGBE_ERR_INVALID_ARGUMENT;
-
-	if (offset + words > hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+	if (words == 0 || (offset + words > hw->eeprom.word_size))
+		return -EINVAL;
 
 	/*
 	 * We cannot hold synchronization semaphores for too long
@@ -1099,7 +1093,7 @@
 
 	if (ixgbe_ready_eeprom(hw) != 0) {
 		ixgbe_release_eeprom(hw);
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	for (i = 0; i < words; i++) {
@@ -1142,7 +1136,7 @@
 	hw->eeprom.ops.init_params(hw);
 
 	if (offset >= hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+		return -EINVAL;
 
 	return ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
 }
@@ -1165,11 +1159,8 @@
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (words == 0)
-		return IXGBE_ERR_INVALID_ARGUMENT;
-
-	if (offset >= hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+	if (words == 0 || offset >= hw->eeprom.word_size)
+		return -EINVAL;
 
 	for (i = 0; i < words; i++) {
 		eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
@@ -1262,11 +1253,8 @@
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (words == 0)
-		return IXGBE_ERR_INVALID_ARGUMENT;
-
-	if (offset >= hw->eeprom.word_size)
-		return IXGBE_ERR_EEPROM;
+	if (words == 0 || offset >= hw->eeprom.word_size)
+		return -EINVAL;
 
 	for (i = 0; i < words; i++) {
 		eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
@@ -1328,7 +1316,7 @@
 		}
 		udelay(5);
 	}
-	return IXGBE_ERR_EEPROM;
+	return -EIO;
 }
 
 /**
@@ -1344,7 +1332,7 @@
 	u32 i;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0)
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
 
@@ -1366,7 +1354,7 @@
 		hw_dbg(hw, "Could not acquire EEPROM grant\n");
 
 		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	/* Setup EEPROM for Read/Write */
@@ -1419,7 +1407,7 @@
 		swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
 		if (swsm & IXGBE_SWSM_SMBI) {
 			hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n");
-			return IXGBE_ERR_EEPROM;
+			return -EIO;
 		}
 	}
 
@@ -1447,7 +1435,7 @@
 	if (i >= timeout) {
 		hw_dbg(hw, "SWESMBI Software EEPROM semaphore not granted.\n");
 		ixgbe_release_eeprom_semaphore(hw);
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	return 0;
@@ -1503,7 +1491,7 @@
 	 */
 	if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) {
 		hw_dbg(hw, "SPI EEPROM Status error\n");
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	return 0;
@@ -1715,7 +1703,7 @@
 	for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
 		if (hw->eeprom.ops.read(hw, i, &pointer)) {
 			hw_dbg(hw, "EEPROM read failed\n");
-			return IXGBE_ERR_EEPROM;
+			return -EIO;
 		}
 
 		/* If the pointer seems invalid */
@@ -1724,7 +1712,7 @@
 
 		if (hw->eeprom.ops.read(hw, pointer, &length)) {
 			hw_dbg(hw, "EEPROM read failed\n");
-			return IXGBE_ERR_EEPROM;
+			return -EIO;
 		}
 
 		if (length == 0xFFFF || length == 0)
@@ -1733,7 +1721,7 @@
 		for (j = pointer + 1; j <= pointer + length; j++) {
 			if (hw->eeprom.ops.read(hw, j, &word)) {
 				hw_dbg(hw, "EEPROM read failed\n");
-				return IXGBE_ERR_EEPROM;
+				return -EIO;
 			}
 			checksum += word;
 		}
@@ -1786,7 +1774,7 @@
 	 * calculated checksum
 	 */
 	if (read_checksum != checksum)
-		status = IXGBE_ERR_EEPROM_CHECKSUM;
+		status = -EIO;
 
 	/* If the user cares, return the calculated checksum */
 	if (checksum_val)
@@ -1845,7 +1833,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (index >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", index);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	/* setup VMDq pool selection before this RAR gets enabled */
@@ -1897,7 +1885,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (index >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", index);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	/*
@@ -2146,7 +2134,7 @@
 
 	/* Validate the water mark configuration. */
 	if (!hw->fc.pause_time)
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 
 	/* Low water mark of zero causes XOFF floods */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
@@ -2155,7 +2143,7 @@
 			if (!hw->fc.low_water[i] ||
 			    hw->fc.low_water[i] >= hw->fc.high_water[i]) {
 				hw_dbg(hw, "Invalid water mark configuration\n");
-				return IXGBE_ERR_INVALID_LINK_SETTINGS;
+				return -EINVAL;
 			}
 		}
 	}
@@ -2212,7 +2200,7 @@
 		break;
 	default:
 		hw_dbg(hw, "Flow control param set incorrectly\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	/* Set 802.3x based flow control settings. */
@@ -2243,7 +2231,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);
 
@@ -2269,7 +2257,7 @@
 		       u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm)
 {
 	if ((!(adv_reg)) ||  (!(lp_reg)))
-		return IXGBE_ERR_FC_NOT_NEGOTIATED;
+		return -EINVAL;
 
 	if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) {
 		/*
@@ -2321,7 +2309,7 @@
 	linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
 	if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) ||
 	    (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1))
-		return IXGBE_ERR_FC_NOT_NEGOTIATED;
+		return -EIO;
 
 	pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
 	pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
@@ -2353,12 +2341,12 @@
 	 */
 	links = IXGBE_READ_REG(hw, IXGBE_LINKS);
 	if ((links & IXGBE_LINKS_KX_AN_COMP) == 0)
-		return IXGBE_ERR_FC_NOT_NEGOTIATED;
+		return -EIO;
 
 	if (hw->mac.type == ixgbe_mac_82599EB) {
 		links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2);
 		if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0)
-			return IXGBE_ERR_FC_NOT_NEGOTIATED;
+			return -EIO;
 	}
 	/*
 	 * Read the 10g AN autoc and LP ability registers and resolve
@@ -2407,8 +2395,8 @@
  **/
 void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
 {
-	s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED;
 	ixgbe_link_speed speed;
+	s32 ret_val = -EIO;
 	bool link_up;
 
 	/*
@@ -2506,15 +2494,15 @@
 }
 
 /**
- *  ixgbe_disable_pcie_master - Disable PCI-express master access
+ *  ixgbe_disable_pcie_primary - Disable PCI-express primary access
  *  @hw: pointer to hardware structure
  *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
- *  bit hasn't caused the master requests to be disabled, else 0
- *  is returned signifying master requests disabled.
+ *  Disables PCI-Express primary access and verifies there are no pending
+ *  requests. -EALREADY is returned if primary disable
+ *  bit hasn't caused the primary requests to be disabled, else 0
+ *  is returned signifying primary requests disabled.
  **/
-static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
+static s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw)
 {
 	u32 i, poll;
 	u16 value;
@@ -2523,23 +2511,23 @@
 	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++) {
+	for (i = 0; i < IXGBE_PCI_PRIMARY_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) {
+	if (i >= IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT) {
 		hw_dbg(hw, "GIO disable did not set - requesting resets\n");
 		goto gio_disable_fail;
 	}
 
-	/* Exit if master requests are blocked */
+	/* Exit if primary requests are blocked */
 	if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) ||
 	    ixgbe_removed(hw->hw_addr))
 		return 0;
 
-	/* Poll for master request bit to clear */
-	for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+	/* Poll for primary request bit to clear */
+	for (i = 0; i < IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT; i++) {
 		udelay(100);
 		if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
 			return 0;
@@ -2547,13 +2535,13 @@
 
 	/*
 	 * Two consecutive resets are required via CTRL.RST per datasheet
-	 * 5.2.5.3.2 Master Disable.  We set a flag to inform the reset routine
-	 * of this need.  The first reset prevents new master requests from
+	 * 5.2.5.3.2 Primary Disable.  We set a flag to inform the reset routine
+	 * of this need.  The first reset prevents new primary requests from
 	 * being issued by our device.  We then must wait 1usec or more for any
 	 * remaining completions from the PCIe bus to trickle in, and then reset
 	 * 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");
+	hw_dbg(hw, "GIO Primary Disable bit didn't clear - requesting resets\n");
 gio_disable_fail:
 	hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
 
@@ -2575,7 +2563,7 @@
 	}
 
 	hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n");
-	return IXGBE_ERR_MASTER_REQUESTS_PENDING;
+	return -EALREADY;
 }
 
 /**
@@ -2600,7 +2588,7 @@
 		 * SW_FW_SYNC bits (not just NVM)
 		 */
 		if (ixgbe_get_eeprom_semaphore(hw))
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
 		if (!(gssr & (fwmask | swmask))) {
@@ -2620,7 +2608,7 @@
 		ixgbe_release_swfw_sync(hw, gssr & (fwmask | swmask));
 
 	usleep_range(5000, 10000);
-	return IXGBE_ERR_SWFW_SYNC;
+	return -EBUSY;
 }
 
 /**
@@ -2757,7 +2745,7 @@
 	s32 ret_val;
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/*
 	 * Link must be up to auto-blink the LEDs;
@@ -2803,7 +2791,7 @@
 	s32 ret_val;
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
 	if (ret_val)
@@ -2963,7 +2951,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (rar >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
@@ -3014,7 +3002,7 @@
 	/* Make sure we are using a valid rar index range */
 	if (rar >= rar_entries) {
 		hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	if (vmdq < 32) {
@@ -3091,7 +3079,7 @@
 	 * 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;
+	first_empty_slot = vlvf_bypass ? -ENOSPC : 0;
 
 	/* add VLAN enable bit for comparison */
 	vlan |= IXGBE_VLVF_VIEN;
@@ -3115,7 +3103,7 @@
 	if (!first_empty_slot)
 		hw_dbg(hw, "No space in VLVF.\n");
 
-	return first_empty_slot ? : IXGBE_ERR_NO_SPACE;
+	return first_empty_slot ? : -ENOSPC;
 }
 
 /**
@@ -3135,7 +3123,7 @@
 	s32 vlvf_index;
 
 	if ((vlan > 4095) || (vind > 63))
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/*
 	 * this is a 2 part operation - first the VFTA, then the
@@ -3596,7 +3584,8 @@
  *
  *  Communicates with the manageability block. On success return 0
  *  else returns semaphore error when encountering an error acquiring
- *  semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ *  semaphore, -EINVAL when incorrect parameters passed or -EIO when
+ *  command fails.
  *
  *  This function assumes that the IXGBE_GSSR_SW_MNG_SM semaphore is held
  *  by the caller.
@@ -3609,7 +3598,7 @@
 
 	if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) {
 		hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length);
-		return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+		return -EINVAL;
 	}
 
 	/* Set bit 9 of FWSTS clearing FW reset indication */
@@ -3620,13 +3609,13 @@
 	hicr = IXGBE_READ_REG(hw, IXGBE_HICR);
 	if (!(hicr & IXGBE_HICR_EN)) {
 		hw_dbg(hw, "IXGBE_HOST_EN bit disabled.\n");
-		return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+		return -EIO;
 	}
 
 	/* Calculate length in DWORDs. We must be DWORD aligned */
 	if (length % sizeof(u32)) {
 		hw_dbg(hw, "Buffer length failure, not aligned to dword");
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 	}
 
 	dword_len = length >> 2;
@@ -3651,7 +3640,7 @@
 	/* Check command successful completion. */
 	if ((timeout && i == timeout) ||
 	    !(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV))
-		return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+		return -EIO;
 
 	return 0;
 }
@@ -3671,7 +3660,7 @@
  *  in these cases.
  *
  *  Communicates with the manageability block.  On success return 0
- *  else return IXGBE_ERR_HOST_INTERFACE_COMMAND.
+ *  else return -EIO or -EINVAL.
  **/
 s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
 				 u32 length, u32 timeout,
@@ -3688,7 +3677,7 @@
 
 	if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) {
 		hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length);
-		return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+		return -EINVAL;
 	}
 	/* Take management host interface semaphore */
 	status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM);
@@ -3718,7 +3707,7 @@
 
 	if (length < round_up(buf_len, 4) + hdr_size) {
 		hw_dbg(hw, "Buffer not large enough for reply message.\n");
-		status = IXGBE_ERR_HOST_INTERFACE_COMMAND;
+		status = -EIO;
 		goto rel_out;
 	}
 
@@ -3749,8 +3738,8 @@
  *
  *  Sends driver version number to firmware through the manageability
  *  block.  On success return 0
- *  else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring
- *  semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ *  else returns -EBUSY when encountering an error acquiring
+ *  semaphore or -EIO when command fails.
  **/
 s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
 				 u8 build, u8 sub, __always_unused u16 len,
@@ -3786,7 +3775,7 @@
 		    FW_CEM_RESP_STATUS_SUCCESS)
 			ret_val = 0;
 		else
-			ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND;
+			ret_val = -EIO;
 
 		break;
 	}
@@ -3884,14 +3873,14 @@
 		return status;
 
 	if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF))
-		return IXGBE_NOT_IMPLEMENTED;
+		return -EOPNOTSUPP;
 
 	status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg);
 	if (status)
 		return status;
 
 	if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED)
-		return IXGBE_NOT_IMPLEMENTED;
+		return -EOPNOTSUPP;
 
 	return 0;
 }
@@ -3914,7 +3903,7 @@
 
 	/* Only support thermal sensors attached to physical port 0 */
 	if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1))
-		return IXGBE_NOT_IMPLEMENTED;
+		return -EOPNOTSUPP;
 
 	status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
 	if (status)
@@ -3974,7 +3963,7 @@
 
 	/* Only support thermal sensors attached to physical port 0 */
 	if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1))
-		return IXGBE_NOT_IMPLEMENTED;
+		return -EOPNOTSUPP;
 
 	status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
 	if (status)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -138,6 +138,8 @@
 	"legacy-rx",
 #define IXGBE_PRIV_FLAGS_VF_IPSEC_EN	BIT(1)
 	"vf-ipsec",
+#define IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF	BIT(2)
+	"mdd-disable-vf",
 };
 
 #define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings)
@@ -2542,6 +2544,14 @@
 	return 0;
 }
 
+static int ixgbe_rss_indir_tbl_max(struct ixgbe_adapter *adapter)
+{
+	if (adapter->hw.mac.type < ixgbe_mac_X550)
+		return 16;
+	else
+		return 64;
+}
+
 static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
 			   u32 *rule_locs)
 {
@@ -2550,7 +2560,8 @@
 
 	switch (cmd->cmd) {
 	case ETHTOOL_GRXRINGS:
-		cmd->data = adapter->num_rx_queues;
+		cmd->data = min_t(int, adapter->num_rx_queues,
+				  ixgbe_rss_indir_tbl_max(adapter));
 		ret = 0;
 		break;
 	case ETHTOOL_GRXCLSRLCNT:
@@ -2952,14 +2963,6 @@
 	return ret;
 }
 
-static int ixgbe_rss_indir_tbl_max(struct ixgbe_adapter *adapter)
-{
-	if (adapter->hw.mac.type < ixgbe_mac_X550)
-		return 16;
-	else
-		return 64;
-}
-
 static u32 ixgbe_get_rxfh_key_size(struct net_device *netdev)
 {
 	return IXGBE_RSS_KEY_SIZE;
@@ -3008,8 +3011,8 @@
 	int i;
 	u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
 
-	if (hfunc)
-		return -EINVAL;
+	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
 
 	/* Fill out the redirection table */
 	if (indir) {
@@ -3246,7 +3249,7 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(dev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+	s32 status = -EFAULT;
 	u8 databyte = 0xFF;
 	int i = 0;
 
@@ -3416,6 +3419,9 @@
 	if (adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED)
 		priv_flags |= IXGBE_PRIV_FLAGS_VF_IPSEC_EN;
 
+	if (adapter->flags2 & IXGBE_FLAG2_AUTO_DISABLE_VF)
+		priv_flags |= IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF;
+
 	return priv_flags;
 }
 
@@ -3423,6 +3429,7 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	unsigned int flags2 = adapter->flags2;
+	unsigned int i;
 
 	flags2 &= ~IXGBE_FLAG2_RX_LEGACY;
 	if (priv_flags & IXGBE_PRIV_FLAGS_LEGACY_RX)
@@ -3432,6 +3439,21 @@
 	if (priv_flags & IXGBE_PRIV_FLAGS_VF_IPSEC_EN)
 		flags2 |= IXGBE_FLAG2_VF_IPSEC_ENABLED;
 
+	flags2 &= ~IXGBE_FLAG2_AUTO_DISABLE_VF;
+	if (priv_flags & IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF) {
+		if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+			/* Reset primary abort counter */
+			for (i = 0; i < adapter->num_vfs; i++)
+				adapter->vfinfo[i].primary_abort_count = 0;
+
+			flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
+		} else {
+			e_info(probe,
+			       "Cannot set private flags: Operation not supported\n");
+			return -EOPNOTSUPP;
+		}
+	}
+
 	if (flags2 != adapter->flags2) {
 		adapter->flags2 = flags2;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -192,7 +192,7 @@
 	}
 
 	/* alloc the udl from per cpu ddp pool */
-	ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_KERNEL, &ddp->udp);
+	ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp);
 	if (!ddp->udl) {
 		e_err(drv, "failed allocated ddp context\n");
 		goto out_noddp_unmap;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -575,6 +575,11 @@
 		return -EINVAL;
 	}
 
+	if (xs->props.mode != XFRM_MODE_TRANSPORT) {
+		netdev_err(dev, "Unsupported mode for ipsec offload\n");
+		return -EINVAL;
+	}
+
 	if (ixgbe_ipsec_check_mgmt_ip(xs)) {
 		netdev_err(dev, "IPsec IP addr clash with mgmt filters\n");
 		return -EINVAL;
@@ -898,7 +903,8 @@
 	/* Tx IPsec offload doesn't seem to work on this
 	 * device, so block these requests for now.
 	 */
-	if (!(sam->flags & XFRM_OFFLOAD_INBOUND)) {
+	sam->flags = sam->flags & ~XFRM_OFFLOAD_IPV6;
+	if (sam->flags != XFRM_OFFLOAD_INBOUND) {
 		err = -EOPNOTSUPP;
 		goto err_out;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -923,7 +923,7 @@
 		ring->queue_index = txr_idx;
 
 		/* assign ring to adapter */
-		adapter->tx_ring[txr_idx] = ring;
+		WRITE_ONCE(adapter->tx_ring[txr_idx], ring);
 
 		/* update count and index */
 		txr_count--;
@@ -950,7 +950,7 @@
 		set_ring_xdp(ring);
 
 		/* assign ring to adapter */
-		adapter->xdp_ring[xdp_idx] = ring;
+		WRITE_ONCE(adapter->xdp_ring[xdp_idx], ring);
 
 		/* update count and index */
 		xdp_count--;
@@ -993,7 +993,7 @@
 		ring->queue_index = rxr_idx;
 
 		/* assign ring to adapter */
-		adapter->rx_ring[rxr_idx] = ring;
+		WRITE_ONCE(adapter->rx_ring[rxr_idx], ring);
 
 		/* update count and index */
 		rxr_count--;
@@ -1022,13 +1022,13 @@
 
 	ixgbe_for_each_ring(ring, q_vector->tx) {
 		if (ring_is_xdp(ring))
-			adapter->xdp_ring[ring->queue_index] = NULL;
+			WRITE_ONCE(adapter->xdp_ring[ring->queue_index], NULL);
 		else
-			adapter->tx_ring[ring->queue_index] = NULL;
+			WRITE_ONCE(adapter->tx_ring[ring->queue_index], NULL);
 	}
 
 	ixgbe_for_each_ring(ring, q_vector->rx)
-		adapter->rx_ring[ring->queue_index] = NULL;
+		WRITE_ONCE(adapter->rx_ring[ring->queue_index], NULL);
 
 	adapter->q_vector[v_idx] = NULL;
 	napi_hash_del(&q_vector->napi);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1827,7 +1827,8 @@
 				struct sk_buff *skb)
 {
 	if (ring_uses_build_skb(rx_ring)) {
-		unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK;
+		unsigned long mask = (unsigned long)ixgbe_rx_pg_size(rx_ring) - 1;
+		unsigned long offset = (unsigned long)(skb->data) & mask;
 
 		dma_sync_single_range_for_cpu(rx_ring->dev,
 					      IXGBE_CB(skb)->dma,
@@ -1947,7 +1948,8 @@
 	return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
 }
 
-static bool ixgbe_can_reuse_rx_page(struct ixgbe_rx_buffer *rx_buffer)
+static bool ixgbe_can_reuse_rx_page(struct ixgbe_rx_buffer *rx_buffer,
+				    int rx_buffer_pgcnt)
 {
 	unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
 	struct page *page = rx_buffer->page;
@@ -1958,7 +1960,7 @@
 
 #if (PAGE_SIZE < 8192)
 	/* if we are only owner of page we can reuse it */
-	if (unlikely((page_ref_count(page) - pagecnt_bias) > 1))
+	if (unlikely((rx_buffer_pgcnt - pagecnt_bias) > 1))
 		return false;
 #else
 	/* The last offset is a bit aggressive in that we assume the
@@ -2023,11 +2025,18 @@
 static struct ixgbe_rx_buffer *ixgbe_get_rx_buffer(struct ixgbe_ring *rx_ring,
 						   union ixgbe_adv_rx_desc *rx_desc,
 						   struct sk_buff **skb,
-						   const unsigned int size)
+						   const unsigned int size,
+						   int *rx_buffer_pgcnt)
 {
 	struct ixgbe_rx_buffer *rx_buffer;
 
 	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+	*rx_buffer_pgcnt =
+#if (PAGE_SIZE < 8192)
+		page_count(rx_buffer->page);
+#else
+		0;
+#endif
 	prefetchw(rx_buffer->page);
 	*skb = rx_buffer->skb;
 
@@ -2057,9 +2066,10 @@
 
 static void ixgbe_put_rx_buffer(struct ixgbe_ring *rx_ring,
 				struct ixgbe_rx_buffer *rx_buffer,
-				struct sk_buff *skb)
+				struct sk_buff *skb,
+				int rx_buffer_pgcnt)
 {
-	if (ixgbe_can_reuse_rx_page(rx_buffer)) {
+	if (ixgbe_can_reuse_rx_page(rx_buffer, rx_buffer_pgcnt)) {
 		/* hand second half of page back to the ring */
 		ixgbe_reuse_rx_page(rx_ring, rx_buffer);
 	} else {
@@ -2254,7 +2264,8 @@
 	rx_buffer->page_offset ^= truesize;
 #else
 	unsigned int truesize = ring_uses_build_skb(rx_ring) ?
-				SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) :
+				SKB_DATA_ALIGN(IXGBE_SKB_PAD + size) +
+				SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
 				SKB_DATA_ALIGN(size);
 
 	rx_buffer->page_offset += truesize;
@@ -2294,6 +2305,7 @@
 		union ixgbe_adv_rx_desc *rx_desc;
 		struct ixgbe_rx_buffer *rx_buffer;
 		struct sk_buff *skb;
+		int rx_buffer_pgcnt;
 		unsigned int size;
 
 		/* return some buffers to hardware, one at a time is too slow */
@@ -2313,7 +2325,7 @@
 		 */
 		dma_rmb();
 
-		rx_buffer = ixgbe_get_rx_buffer(rx_ring, rx_desc, &skb, size);
+		rx_buffer = ixgbe_get_rx_buffer(rx_ring, rx_desc, &skb, size, &rx_buffer_pgcnt);
 
 		/* retrieve a buffer from the ring */
 		if (!skb) {
@@ -2355,7 +2367,7 @@
 			break;
 		}
 
-		ixgbe_put_rx_buffer(rx_ring, rx_buffer, skb);
+		ixgbe_put_rx_buffer(rx_ring, rx_buffer, skb, rx_buffer_pgcnt);
 		cleaned_count++;
 
 		/* place incomplete frames back on ring for completion */
@@ -2743,7 +2755,6 @@
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 eicr = adapter->interrupt_event;
-	s32 rc;
 
 	if (test_bit(__IXGBE_DOWN, &adapter->state))
 		return;
@@ -2777,14 +2788,13 @@
 		}
 
 		/* Check if this is not due to overtemp */
-		if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP)
+		if (!hw->phy.ops.check_overtemp(hw))
 			return;
 
 		break;
 	case IXGBE_DEV_ID_X550EM_A_1G_T:
 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
-		rc = hw->phy.ops.check_overtemp(hw);
-		if (rc != IXGBE_ERR_OVERTEMP)
+		if (!hw->phy.ops.check_overtemp(hw))
 			return;
 		break;
 	default:
@@ -5239,7 +5249,7 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct hlist_node *node2;
 	struct ixgbe_fdir_filter *filter;
-	u64 action;
+	u8 queue;
 
 	spin_lock(&adapter->fdir_perfect_lock);
 
@@ -5248,17 +5258,34 @@
 
 	hlist_for_each_entry_safe(filter, node2,
 				  &adapter->fdir_filter_list, fdir_node) {
-		action = filter->action;
-		if (action != IXGBE_FDIR_DROP_QUEUE && action != 0)
-			action =
-			(action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1;
+		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,
-				(action == IXGBE_FDIR_DROP_QUEUE) ?
-				IXGBE_FDIR_DROP_QUEUE :
-				adapter->rx_ring[action]->reg_idx);
+				&filter->filter, filter->sw_idx, queue);
 	}
 
 	spin_unlock(&adapter->fdir_perfect_lock);
@@ -5490,7 +5517,7 @@
 {
 	u32 speed;
 	bool autoneg, link_up = false;
-	int ret = IXGBE_ERR_LINK_SETUP;
+	int ret = -EIO;
 
 	if (hw->mac.ops.check_link)
 		ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
@@ -5650,6 +5677,9 @@
 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
 	ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+	/* update setting rx tx for all active vfs */
+	ixgbe_set_all_vfs(adapter);
 }
 
 void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
@@ -5909,13 +5939,13 @@
 	err = hw->mac.ops.init_hw(hw);
 	switch (err) {
 	case 0:
-	case IXGBE_ERR_SFP_NOT_PRESENT:
-	case IXGBE_ERR_SFP_NOT_SUPPORTED:
+	case -ENOENT:
+	case -EOPNOTSUPP:
 		break;
-	case IXGBE_ERR_MASTER_REQUESTS_PENDING:
-		e_dev_err("master disable timed out\n");
+	case -EALREADY:
+		e_dev_err("primary disable timed out\n");
 		break;
-	case IXGBE_ERR_EEPROM_VERSION:
+	case -EACCES:
 		/* We are running on a pre-production device, log a warning */
 		e_dev_warn("This device is a pre-production adapter/LOM. "
 			   "Please be aware there may be issues associated with "
@@ -6108,11 +6138,8 @@
 		for (i = 0 ; i < adapter->num_vfs; i++)
 			adapter->vfinfo[i].clear_to_send = false;
 
-		/* ping all the active vfs to let them know we are going down */
-		ixgbe_ping_all_vfs(adapter);
-
-		/* Disable all VFTE/VFRE TX/RX */
-		ixgbe_disable_tx_rx(adapter);
+		/* update setting rx tx for all active vfs */
+		ixgbe_set_all_vfs(adapter);
 	}
 
 	/* disable transmits in the hardware now that interrupts are off */
@@ -6367,6 +6394,9 @@
 	/* n-tuple support exists, always init our spinlock */
 	spin_lock_init(&adapter->fdir_perfect_lock);
 
+	/* init spinlock to avoid concurrency of VF resources */
+	spin_lock_init(&adapter->vfs_lock);
+
 #ifdef CONFIG_IXGBE_DCB
 	ixgbe_init_dcb(adapter);
 #endif
@@ -6690,6 +6720,18 @@
 }
 
 /**
+ * ixgbe_max_xdp_frame_size - returns the maximum allowed frame size for XDP
+ * @adapter: device handle, pointer to adapter
+ */
+static int ixgbe_max_xdp_frame_size(struct ixgbe_adapter *adapter)
+{
+	if (PAGE_SIZE >= 8192 || adapter->flags2 & IXGBE_FLAG2_RX_LEGACY)
+		return IXGBE_RXBUFFER_2K;
+	else
+		return IXGBE_RXBUFFER_3K;
+}
+
+/**
  * ixgbe_change_mtu - Change the Maximum Transfer Unit
  * @netdev: network interface device structure
  * @new_mtu: new value for maximum frame size
@@ -6700,18 +6742,12 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-	if (adapter->xdp_prog) {
-		int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN +
-				     VLAN_HLEN;
-		int i;
-
-		for (i = 0; i < adapter->num_rx_queues; i++) {
-			struct ixgbe_ring *ring = adapter->rx_ring[i];
+	if (ixgbe_enabled_xdp_adapter(adapter)) {
+		int new_frame_size = new_mtu + IXGBE_PKT_HDR_PAD;
 
-			if (new_frame_size > ixgbe_rx_bufsz(ring)) {
-				e_warn(probe, "Requested MTU size is not supported with XDP\n");
-				return -EINVAL;
-			}
+		if (new_frame_size > ixgbe_max_xdp_frame_size(adapter)) {
+			e_warn(probe, "Requested MTU size is not supported with XDP\n");
+			return -EINVAL;
 		}
 	}
 
@@ -7046,7 +7082,10 @@
 	}
 
 	for (i = 0; i < adapter->num_rx_queues; i++) {
-		struct ixgbe_ring *rx_ring = adapter->rx_ring[i];
+		struct ixgbe_ring *rx_ring = READ_ONCE(adapter->rx_ring[i]);
+
+		if (!rx_ring)
+			continue;
 		non_eop_descs += rx_ring->rx_stats.non_eop_descs;
 		alloc_rx_page += rx_ring->rx_stats.alloc_rx_page;
 		alloc_rx_page_failed += rx_ring->rx_stats.alloc_rx_page_failed;
@@ -7067,15 +7106,20 @@
 	packets = 0;
 	/* gather some stats to the adapter struct that are per queue */
 	for (i = 0; i < adapter->num_tx_queues; i++) {
-		struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+		struct ixgbe_ring *tx_ring = READ_ONCE(adapter->tx_ring[i]);
+
+		if (!tx_ring)
+			continue;
 		restart_queue += tx_ring->tx_stats.restart_queue;
 		tx_busy += tx_ring->tx_stats.tx_busy;
 		bytes += tx_ring->stats.bytes;
 		packets += tx_ring->stats.packets;
 	}
 	for (i = 0; i < adapter->num_xdp_queues; i++) {
-		struct ixgbe_ring *xdp_ring = adapter->xdp_ring[i];
+		struct ixgbe_ring *xdp_ring = READ_ONCE(adapter->xdp_ring[i]);
 
+		if (!xdp_ring)
+			continue;
 		restart_queue += xdp_ring->tx_stats.restart_queue;
 		tx_busy += xdp_ring->tx_stats.tx_busy;
 		bytes += xdp_ring->stats.bytes;
@@ -7588,6 +7632,27 @@
 }
 
 #ifdef CONFIG_PCI_IOV
+static void ixgbe_bad_vf_abort(struct ixgbe_adapter *adapter, u32 vf)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	if (adapter->hw.mac.type == ixgbe_mac_82599EB &&
+	    adapter->flags2 & IXGBE_FLAG2_AUTO_DISABLE_VF) {
+		adapter->vfinfo[vf].primary_abort_count++;
+		if (adapter->vfinfo[vf].primary_abort_count ==
+		    IXGBE_PRIMARY_ABORT_LIMIT) {
+			ixgbe_set_vf_link_state(adapter, vf,
+						IFLA_VF_LINK_STATE_DISABLE);
+			adapter->vfinfo[vf].primary_abort_count = 0;
+
+			e_info(drv,
+			       "Malicious Driver Detection event detected on PF %d VF %d MAC: %pM mdd-disable-vf=on",
+			       hw->bus.func, vf,
+			       adapter->vfinfo[vf].vf_mac_addresses);
+		}
+	}
+}
+
 static void ixgbe_check_for_bad_vf(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -7619,8 +7684,10 @@
 			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)
+		    status_reg & PCI_STATUS_REC_MASTER_ABORT) {
+			ixgbe_bad_vf_abort(adapter, vf);
 			pcie_flr(vfdev);
+		}
 	}
 }
 
@@ -7707,10 +7774,10 @@
 	adapter->sfp_poll_time = jiffies + IXGBE_SFP_POLL_JIFFIES - 1;
 
 	err = hw->phy.ops.identify_sfp(hw);
-	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (err == -EOPNOTSUPP)
 		goto sfp_out;
 
-	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+	if (err == -ENOENT) {
 		/* If no cable is present, then we need to reset
 		 * the next time we find a good cable. */
 		adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
@@ -7736,7 +7803,7 @@
 	else
 		err = hw->mac.ops.setup_sfp(hw);
 
-	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (err == -EOPNOTSUPP)
 		goto sfp_out;
 
 	adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
@@ -7745,8 +7812,8 @@
 sfp_out:
 	clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
 
-	if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
-	    (adapter->netdev->reg_state == NETREG_REGISTERED)) {
+	if (err == -EOPNOTSUPP &&
+	    adapter->netdev->reg_state == NETREG_REGISTERED) {
 		e_dev_err("failed to initialize because an unsupported "
 			  "SFP+ module type was detected.\n");
 		e_dev_err("Reload the driver after installing a "
@@ -7816,7 +7883,7 @@
 static void ixgbe_phy_interrupt_subtask(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	u32 status;
+	bool overtemp;
 
 	if (!(adapter->flags2 & IXGBE_FLAG2_PHY_INTERRUPT))
 		return;
@@ -7826,11 +7893,9 @@
 	if (!hw->phy.ops.handle_lasi)
 		return;
 
-	status = hw->phy.ops.handle_lasi(&adapter->hw);
-	if (status != IXGBE_ERR_OVERTEMP)
-		return;
-
-	e_crit(drv, "%s\n", ixgbe_overheat_msg);
+	hw->phy.ops.handle_lasi(&adapter->hw, &overtemp);
+	if (overtemp)
+		e_crit(drv, "%s\n", ixgbe_overheat_msg);
 }
 
 static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
@@ -8377,7 +8442,7 @@
 		struct ixgbe_adapter *adapter = q_vector->adapter;
 
 		if (unlikely(skb_tail_pointer(skb) < hdr.network +
-			     VXLAN_HEADROOM))
+			     vxlan_headroom(0)))
 			return;
 
 		/* verify the port is recognized as VXLAN */
@@ -8639,7 +8704,8 @@
 
 	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
 	    adapter->ptp_clock) {
-		if (!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
+		if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
+		    !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
 					   &adapter->state)) {
 			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 			tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
@@ -9558,8 +9624,10 @@
 	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);
+	if (err)
+		goto err_out_w_lock;
+
+	ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
 	spin_unlock(&adapter->fdir_perfect_lock);
 
 	if ((uhtid != 0x800) && (adapter->jump_tables[uhtid]))
@@ -10247,7 +10315,12 @@
 
 	/* If transitioning XDP modes reconfigure rings */
 	if (need_reset) {
-		int err = ixgbe_setup_tc(dev, adapter->hw_tcs);
+		int err;
+
+		if (!prog)
+			/* Wait until ndo_xsk_wakeup completes. */
+			synchronize_rcu();
+		err = ixgbe_setup_tc(dev, adapter->hw_tcs);
 
 		if (err) {
 			rcu_assign_pointer(adapter->xdp_prog, old_prog);
@@ -10361,6 +10434,7 @@
 	.ndo_set_vf_vlan	= ixgbe_ndo_set_vf_vlan,
 	.ndo_set_vf_rate	= ixgbe_ndo_set_vf_bw,
 	.ndo_set_vf_spoofchk	= ixgbe_ndo_set_vf_spoofchk,
+	.ndo_set_vf_link_state	= ixgbe_ndo_set_vf_link_state,
 	.ndo_set_vf_rss_query_en = ixgbe_ndo_set_vf_rss_query_en,
 	.ndo_set_vf_trust	= ixgbe_ndo_set_vf_trust,
 	.ndo_get_vf_config	= ixgbe_ndo_get_vf_config,
@@ -10829,6 +10903,9 @@
 	if (err)
 		goto err_sw_init;
 
+	if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+		adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;
+
 	/* Make sure the SWFW semaphore is in a valid state */
 	if (hw->mac.ops.init_swfw_sync)
 		hw->mac.ops.init_swfw_sync(hw);
@@ -10864,9 +10941,9 @@
 	err = hw->mac.ops.reset_hw(hw);
 	hw->phy.reset_if_overtemp = false;
 	ixgbe_set_eee_capable(adapter);
-	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+	if (err == -ENOENT) {
 		err = 0;
-	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+	} else if (err == -EOPNOTSUPP) {
 		e_dev_err("failed to load because an unsupported SFP+ or QSFP module type was detected.\n");
 		e_dev_err("Reload the driver after installing a supported module.\n");
 		goto err_sw_init;
@@ -11083,7 +11160,7 @@
 
 	/* reset the hardware with the new settings */
 	err = hw->mac.ops.start_hw(hw);
-	if (err == IXGBE_ERR_EEPROM_VERSION) {
+	if (err == -EACCES) {
 		/* We are running on a pre-production device, log a warning */
 		e_dev_warn("This device is a pre-production adapter/LOM. "
 			   "Please be aware there may be issues associated "
@@ -11163,6 +11240,7 @@
 	disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
 	free_netdev(netdev);
 err_alloc_etherdev:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -24,7 +24,7 @@
 		size = mbx->size;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	return mbx->ops->read(hw, msg, size, mbx_id);
 }
@@ -43,10 +43,10 @@
 	struct ixgbe_mbx_info *mbx = &hw->mbx;
 
 	if (size > mbx->size)
-		return IXGBE_ERR_MBX;
+		return -EINVAL;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	return mbx->ops->write(hw, msg, size, mbx_id);
 }
@@ -63,7 +63,7 @@
 	struct ixgbe_mbx_info *mbx = &hw->mbx;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	return mbx->ops->check_for_msg(hw, mbx_id);
 }
@@ -80,7 +80,7 @@
 	struct ixgbe_mbx_info *mbx = &hw->mbx;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	return mbx->ops->check_for_ack(hw, mbx_id);
 }
@@ -97,7 +97,7 @@
 	struct ixgbe_mbx_info *mbx = &hw->mbx;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	return mbx->ops->check_for_rst(hw, mbx_id);
 }
@@ -115,12 +115,12 @@
 	int countdown = mbx->timeout;
 
 	if (!countdown || !mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	while (mbx->ops->check_for_msg(hw, mbx_id)) {
 		countdown--;
 		if (!countdown)
-			return IXGBE_ERR_MBX;
+			return -EIO;
 		udelay(mbx->usec_delay);
 	}
 
@@ -140,12 +140,12 @@
 	int countdown = mbx->timeout;
 
 	if (!countdown || !mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	while (mbx->ops->check_for_ack(hw, mbx_id)) {
 		countdown--;
 		if (!countdown)
-			return IXGBE_ERR_MBX;
+			return -EIO;
 		udelay(mbx->usec_delay);
 	}
 
@@ -169,7 +169,7 @@
 	s32 ret_val;
 
 	if (!mbx->ops)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	ret_val = ixgbe_poll_for_msg(hw, mbx_id);
 	if (ret_val)
@@ -197,7 +197,7 @@
 
 	/* exit if either we can't write or there isn't a defined timeout */
 	if (!mbx->ops || !mbx->timeout)
-		return IXGBE_ERR_MBX;
+		return -EIO;
 
 	/* send msg */
 	ret_val = mbx->ops->write(hw, msg, size, mbx_id);
@@ -217,7 +217,7 @@
 		return 0;
 	}
 
-	return IXGBE_ERR_MBX;
+	return -EIO;
 }
 
 /**
@@ -238,7 +238,7 @@
 		return 0;
 	}
 
-	return IXGBE_ERR_MBX;
+	return -EIO;
 }
 
 /**
@@ -259,7 +259,7 @@
 		return 0;
 	}
 
-	return IXGBE_ERR_MBX;
+	return -EIO;
 }
 
 /**
@@ -295,7 +295,7 @@
 		return 0;
 	}
 
-	return IXGBE_ERR_MBX;
+	return -EIO;
 }
 
 /**
@@ -317,7 +317,7 @@
 	if (p2v_mailbox & IXGBE_PFMAILBOX_PFU)
 		return 0;
 
-	return IXGBE_ERR_MBX;
+	return -EIO;
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -7,7 +7,6 @@
 #include "ixgbe_type.h"
 
 #define IXGBE_VFMAILBOX_SIZE        16 /* 16 32 bit words - 64 bytes */
-#define IXGBE_ERR_MBX               -100
 
 #define IXGBE_VFMAILBOX             0x002FC
 #define IXGBE_VFMBMEM               0x00200
@@ -85,6 +84,8 @@
 #define IXGBE_VF_IPSEC_ADD	0x0d
 #define IXGBE_VF_IPSEC_DEL	0x0e
 
+#define IXGBE_VF_GET_LINK_STATE 0x10 /* get vf link state */
+
 /* length of permanent address message returned from PF */
 #define IXGBE_VF_PERMADDR_MSG_LEN 4
 /* word in permanent address message with the current multicast type */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -102,7 +102,7 @@
 	csum = ~csum;
 	do {
 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 		ixgbe_i2c_start(hw);
 		/* Device Address and write indication */
 		if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -150,7 +150,7 @@
 			hw_dbg(hw, "I2C byte read combined error.\n");
 	} while (retry < max_retry);
 
-	return IXGBE_ERR_I2C;
+	return -EIO;
 }
 
 /**
@@ -179,7 +179,7 @@
 	csum = ~csum;
 	do {
 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 		ixgbe_i2c_start(hw);
 		/* Device Address and write indication */
 		if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -215,7 +215,7 @@
 			hw_dbg(hw, "I2C byte write combined error.\n");
 	} while (retry < max_retry);
 
-	return IXGBE_ERR_I2C;
+	return -EIO;
 }
 
 /**
@@ -262,8 +262,8 @@
  **/
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
 {
+	u32 status = -EFAULT;
 	u32 phy_addr;
-	u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
 
 	if (!hw->phy.phy_semaphore_mask) {
 		if (hw->bus.lan_id)
@@ -282,7 +282,7 @@
 		if (ixgbe_probe_phy(hw, phy_addr))
 			return 0;
 		else
-			return IXGBE_ERR_PHY_ADDR_INVALID;
+			return -EFAULT;
 	}
 
 	for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
@@ -405,8 +405,7 @@
 		return status;
 
 	/* Don't reset PHY if it's shut down due to overtemp. */
-	if (!hw->phy.reset_if_overtemp &&
-	    (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
+	if (!hw->phy.reset_if_overtemp && hw->phy.ops.check_overtemp(hw))
 		return 0;
 
 	/* Blocked by MNG FW so bail */
@@ -454,7 +453,7 @@
 
 	if (ctrl & MDIO_CTRL1_RESET) {
 		hw_dbg(hw, "PHY reset polling failed to complete.\n");
-		return IXGBE_ERR_RESET_FAILED;
+		return -EIO;
 	}
 
 	return 0;
@@ -496,7 +495,7 @@
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		hw_dbg(hw, "PHY address command did not complete.\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	/* Address cycle complete, setup and write the read
@@ -523,7 +522,7 @@
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		hw_dbg(hw, "PHY read command didn't complete\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	/* Read operation is complete.  Get the data
@@ -555,7 +554,7 @@
 						phy_data);
 		hw->mac.ops.release_swfw_sync(hw, gssr);
 	} else {
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	}
 
 	return status;
@@ -600,7 +599,7 @@
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		hw_dbg(hw, "PHY address cmd didn't complete\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	/*
@@ -628,7 +627,7 @@
 
 	if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
 		hw_dbg(hw, "PHY write cmd didn't complete\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	return 0;
@@ -653,7 +652,7 @@
 						 phy_data);
 		hw->mac.ops.release_swfw_sync(hw, gssr);
 	} else {
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	}
 
 	return status;
@@ -851,9 +850,11 @@
 	rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn);
 	if (rp_pdev && rp_pdev->subordinate) {
 		bus = rp_pdev->subordinate->number;
+		pci_dev_put(rp_pdev);
 		return pci_get_domain_bus_and_slot(0, bus, 0);
 	}
 
+	pci_dev_put(rp_pdev);
 	return NULL;
 }
 
@@ -870,6 +871,7 @@
 	struct ixgbe_adapter *adapter = hw->back;
 	struct pci_dev *pdev = adapter->pdev;
 	struct pci_dev *func0_pdev;
+	bool has_mii = false;
 
 	/* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices
 	 * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0
@@ -880,15 +882,16 @@
 	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0));
 	if (func0_pdev) {
 		if (func0_pdev == pdev)
-			return true;
-		else
-			return false;
+			has_mii = true;
+		goto out;
 	}
 	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0));
 	if (func0_pdev == pdev)
-		return true;
+		has_mii = true;
 
-	return false;
+out:
+	pci_dev_put(func0_pdev);
+	return has_mii;
 }
 
 /**
@@ -1298,7 +1301,7 @@
 
 	if ((phy_data & MDIO_CTRL1_RESET) != 0) {
 		hw_dbg(hw, "PHY reset did not complete.\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	/* Get init offsets */
@@ -1355,12 +1358,12 @@
 				hw_dbg(hw, "SOL\n");
 			} else {
 				hw_dbg(hw, "Bad control value\n");
-				return IXGBE_ERR_PHY;
+				return -EIO;
 			}
 			break;
 		default:
 			hw_dbg(hw, "Bad control type\n");
-			return IXGBE_ERR_PHY;
+			return -EIO;
 		}
 	}
 
@@ -1368,7 +1371,7 @@
 
 err_eeprom:
 	hw_err(hw, "eeprom read at offset %d failed\n", data_offset);
-	return IXGBE_ERR_PHY;
+	return -EIO;
 }
 
 /**
@@ -1386,10 +1389,10 @@
 		return ixgbe_identify_qsfp_module_generic(hw);
 	default:
 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
-		return IXGBE_ERR_SFP_NOT_PRESENT;
+		return -ENOENT;
 	}
 
-	return IXGBE_ERR_SFP_NOT_PRESENT;
+	return -ENOENT;
 }
 
 /**
@@ -1414,7 +1417,7 @@
 
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
-		return IXGBE_ERR_SFP_NOT_PRESENT;
+		return -ENOENT;
 	}
 
 	/* LAN ID is needed for sfp_type determination */
@@ -1429,7 +1432,7 @@
 
 	if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
 		hw->phy.type = ixgbe_phy_sfp_unsupported;
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 	status = hw->phy.ops.read_i2c_eeprom(hw,
 					     IXGBE_SFF_1GBE_COMP_CODES,
@@ -1620,7 +1623,7 @@
 	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
 	      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
 		hw->phy.type = ixgbe_phy_sfp_unsupported;
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 
 	/* Anything else 82598-based is supported */
@@ -1644,7 +1647,7 @@
 		}
 		hw_dbg(hw, "SFP+ module not supported\n");
 		hw->phy.type = ixgbe_phy_sfp_unsupported;
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 	return 0;
 
@@ -1654,7 +1657,7 @@
 		hw->phy.id = 0;
 		hw->phy.type = ixgbe_phy_unknown;
 	}
-	return IXGBE_ERR_SFP_NOT_PRESENT;
+	return -ENOENT;
 }
 
 /**
@@ -1681,7 +1684,7 @@
 
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
-		return IXGBE_ERR_SFP_NOT_PRESENT;
+		return -ENOENT;
 	}
 
 	/* LAN ID is needed for sfp_type determination */
@@ -1695,7 +1698,7 @@
 
 	if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
 		hw->phy.type = ixgbe_phy_sfp_unsupported;
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 
 	hw->phy.id = identifier;
@@ -1763,7 +1766,7 @@
 		} else {
 			/* unsupported module type */
 			hw->phy.type = ixgbe_phy_sfp_unsupported;
-			return IXGBE_ERR_SFP_NOT_SUPPORTED;
+			return -EOPNOTSUPP;
 		}
 	}
 
@@ -1823,7 +1826,7 @@
 			}
 			hw_dbg(hw, "QSFP module not supported\n");
 			hw->phy.type = ixgbe_phy_sfp_unsupported;
-			return IXGBE_ERR_SFP_NOT_SUPPORTED;
+			return -EOPNOTSUPP;
 		}
 		return 0;
 	}
@@ -1834,7 +1837,7 @@
 	hw->phy.id = 0;
 	hw->phy.type = ixgbe_phy_unknown;
 
-	return IXGBE_ERR_SFP_NOT_PRESENT;
+	return -ENOENT;
 }
 
 /**
@@ -1854,14 +1857,14 @@
 	u16 sfp_type = hw->phy.sfp_type;
 
 	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 
 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
-		return IXGBE_ERR_SFP_NOT_PRESENT;
+		return -ENOENT;
 
 	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
 	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 
 	/*
 	 * Limiting active cables and 1G Phys must be initialized as
@@ -1882,11 +1885,11 @@
 	if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) {
 		hw_err(hw, "eeprom read at %d failed\n",
 		       IXGBE_PHY_INIT_OFFSET_NL);
-		return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
+		return -EIO;
 	}
 
 	if ((!*list_offset) || (*list_offset == 0xFFFF))
-		return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
+		return -EIO;
 
 	/* Shift offset to first ID word */
 	(*list_offset)++;
@@ -1905,7 +1908,7 @@
 				goto err_phy;
 			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
 				hw_dbg(hw, "SFP+ module not supported\n");
-				return IXGBE_ERR_SFP_NOT_SUPPORTED;
+				return -EOPNOTSUPP;
 			} else {
 				break;
 			}
@@ -1918,14 +1921,14 @@
 
 	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
 		hw_dbg(hw, "No matching SFP+ module found\n");
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 
 	return 0;
 
 err_phy:
 	hw_err(hw, "eeprom read at offset %d failed\n", *list_offset);
-	return IXGBE_ERR_PHY;
+	return -EIO;
 }
 
 /**
@@ -2020,7 +2023,7 @@
 
 	do {
 		if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		ixgbe_i2c_start(hw);
 
@@ -2136,7 +2139,7 @@
 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
 
 	if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	do {
 		ixgbe_i2c_start(hw);
@@ -2378,7 +2381,7 @@
 
 	if (ack == 1) {
 		hw_dbg(hw, "I2C ack was not received.\n");
-		status = IXGBE_ERR_I2C;
+		status = -EIO;
 	}
 
 	ixgbe_lower_i2c_clk(hw, &i2cctl);
@@ -2450,7 +2453,7 @@
 		udelay(IXGBE_I2C_T_LOW);
 	} else {
 		hw_dbg(hw, "I2C data was not set to %X\n", data);
-		return IXGBE_ERR_I2C;
+		return -EIO;
 	}
 
 	return 0;
@@ -2546,7 +2549,7 @@
 	*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
 	if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
 		hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
-		return IXGBE_ERR_I2C;
+		return -EIO;
 	}
 
 	return 0;
@@ -2616,22 +2619,24 @@
  *  @hw: pointer to hardware structure
  *
  *  Checks if the LASI temp alarm status was triggered due to overtemp
+ *
+ *  Return true when an overtemp event detected, otherwise false.
  **/
-s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
+bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
 {
 	u16 phy_data = 0;
+	u32 status;
 
 	if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
-		return 0;
+		return false;
 
 	/* Check that the LASI temp alarm status was triggered */
-	hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
-			     MDIO_MMD_PMAPMD, &phy_data);
-
-	if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
-		return 0;
+	status = hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
+				      MDIO_MMD_PMAPMD, &phy_data);
+	if (status)
+		return false;
 
-	return IXGBE_ERR_OVERTEMP;
+	return !!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM);
 }
 
 /** ixgbe_set_copper_phy_power - Control power for copper phy
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -155,7 +155,7 @@
 s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
 					u16 *list_offset,
 					u16 *data_offset);
-s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
+bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
 s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 				u8 dev_addr, u8 *data);
 s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -989,6 +989,7 @@
 	u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED;
 	u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED;
 	u32 tsync_rx_mtrl = PTP_EV_PORT << 16;
+	u32 aflags = adapter->flags;
 	bool is_l2 = false;
 	u32 regval;
 
@@ -1009,20 +1010,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);
+		aflags &= ~(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);
+		aflags |= (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);
+		aflags |= (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:
@@ -1036,8 +1037,8 @@
 		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);
+		aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+			   IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
 		break;
 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
 	case HWTSTAMP_FILTER_NTP_ALL:
@@ -1048,7 +1049,7 @@
 		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;
+			aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED;
 			break;
 		}
 		/* fall through */
@@ -1059,8 +1060,6 @@
 		 * 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;
 	}
@@ -1092,8 +1091,8 @@
 			       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;
+		aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED;
+		aflags &= ~IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER;
 		is_l2 = true;
 		break;
 	default:
@@ -1126,6 +1125,9 @@
 
 	IXGBE_WRITE_FLUSH(hw);
 
+	/* configure adapter flags only when HW is actually configured */
+	adapter->flags = aflags;
+
 	/* clear TX/RX time stamp registers, just to be sure */
 	ixgbe_ptp_clear_tx_timestamp(adapter);
 	IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
@@ -1211,7 +1213,6 @@
 	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.
@@ -1246,18 +1247,6 @@
 	case ixgbe_mac_x550em_a:
 	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;
@@ -1290,6 +1279,50 @@
 }
 
 /**
+ * ixgbe_ptp_init_systime - Initialize SYSTIME registers
+ * @adapter: the ixgbe private board structure
+ *
+ * Initialize and start the SYSTIME registers.
+ */
+static void ixgbe_ptp_init_systime(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 tsauxc;
+
+	switch (hw->mac.type) {
+	case ixgbe_mac_X550EM_x:
+	case ixgbe_mac_x550em_a:
+	case ixgbe_mac_X550:
+		tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC);
+
+		/* Reset SYSTIME registers to 0 */
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIMR, 0);
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
+
+		/* Reset interrupt settings */
+		IXGBE_WRITE_REG(hw, IXGBE_TSIM, IXGBE_TSIM_TXTS);
+		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_TIMESYNC);
+
+		/* Activate the SYSTIME counter */
+		IXGBE_WRITE_REG(hw, IXGBE_TSAUXC,
+				tsauxc & ~IXGBE_TSAUXC_DISABLE_SYSTIME);
+		break;
+	case ixgbe_mac_X540:
+	case ixgbe_mac_82599EB:
+		/* Reset SYSTIME registers to 0 */
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0);
+		IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0);
+		break;
+	default:
+		/* Other devices aren't supported */
+		return;
+	};
+
+	IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
  * ixgbe_ptp_reset
  * @adapter: the ixgbe private board structure
  *
@@ -1315,6 +1348,8 @@
 
 	ixgbe_ptp_start_cyclecounter(adapter);
 
+	ixgbe_ptp_init_systime(adapter);
+
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
 	timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
 			 ktime_to_ns(ktime_get_real()));
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -28,6 +28,9 @@
 	struct vf_macvlans *mv_list;
 	int num_vf_macvlans, i;
 
+	/* Initialize list of VF macvlans */
+	INIT_LIST_HEAD(&adapter->vf_mvs.l);
+
 	num_vf_macvlans = hw->mac.num_rar_entries -
 			  (IXGBE_MAX_PF_MACVLANS + 1 + num_vfs);
 	if (!num_vf_macvlans)
@@ -36,8 +39,6 @@
 	mv_list = kcalloc(num_vf_macvlans, sizeof(struct vf_macvlans),
 			  GFP_KERNEL);
 	if (mv_list) {
-		/* Initialize list of VF macvlans */
-		INIT_LIST_HEAD(&adapter->vf_mvs.l);
 		for (i = 0; i < num_vf_macvlans; i++) {
 			mv_list[i].vf = -1;
 			mv_list[i].free = true;
@@ -96,6 +97,7 @@
 	for (i = 0; i < num_vfs; i++) {
 		/* enable spoof checking for all VFs */
 		adapter->vfinfo[i].spoofchk_enabled = true;
+		adapter->vfinfo[i].link_enable = true;
 
 		/* We support VF RSS querying only for 82599 and x540
 		 * devices at the moment. These devices share RSS
@@ -204,10 +206,13 @@
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
 	unsigned int num_vfs = adapter->num_vfs, vf;
+	unsigned long flags;
 	int rss;
 
+	spin_lock_irqsave(&adapter->vfs_lock, flags);
 	/* set num VFs to 0 to prevent access to vfinfo */
 	adapter->num_vfs = 0;
+	spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 
 	/* put the reference to all of the vf devices */
 	for (vf = 0; vf < num_vfs; ++vf) {
@@ -467,12 +472,16 @@
 	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
@@ -533,12 +542,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;
@@ -822,6 +825,57 @@
 	}
 }
 
+/**
+ * ixgbe_set_vf_rx_tx - Set VF rx tx
+ * @adapter: Pointer to adapter struct
+ * @vf: VF identifier
+ *
+ * Set or reset correct transmit and receive for vf
+ **/
+static void ixgbe_set_vf_rx_tx(struct ixgbe_adapter *adapter, int vf)
+{
+	u32 reg_cur_tx, reg_cur_rx, reg_req_tx, reg_req_rx;
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 reg_offset, vf_shift;
+
+	vf_shift = vf % 32;
+	reg_offset = vf / 32;
+
+	reg_cur_tx = IXGBE_READ_REG(hw, IXGBE_VFTE(reg_offset));
+	reg_cur_rx = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
+
+	if (adapter->vfinfo[vf].link_enable) {
+		reg_req_tx = reg_cur_tx | 1 << vf_shift;
+		reg_req_rx = reg_cur_rx | 1 << vf_shift;
+	} else {
+		reg_req_tx = reg_cur_tx & ~(1 << vf_shift);
+		reg_req_rx = reg_cur_rx & ~(1 << vf_shift);
+	}
+
+	/* The 82599 cannot support a mix of jumbo and non-jumbo PF/VFs.
+	 * For more info take a look at ixgbe_set_vf_lpe
+	 */
+	if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+		struct net_device *dev = adapter->netdev;
+		int pf_max_frame = dev->mtu + ETH_HLEN;
+
+#if IS_ENABLED(CONFIG_FCOE)
+		if (dev->features & NETIF_F_FCOE_MTU)
+			pf_max_frame = max_t(int, pf_max_frame,
+					     IXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif /* CONFIG_FCOE */
+
+		if (pf_max_frame > ETH_FRAME_LEN)
+			reg_req_rx = reg_cur_rx & ~(1 << vf_shift);
+	}
+
+	/* Enable/Disable particular VF */
+	if (reg_cur_tx != reg_req_tx)
+		IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg_req_tx);
+	if (reg_cur_rx != reg_req_rx)
+		IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg_req_rx);
+}
+
 static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
 {
 	struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
@@ -847,11 +901,6 @@
 	vf_shift = vf % 32;
 	reg_offset = vf / 32;
 
-	/* enable transmit for vf */
-	reg = IXGBE_READ_REG(hw, IXGBE_VFTE(reg_offset));
-	reg |= BIT(vf_shift);
-	IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg);
-
 	/* force drop enable for all VF Rx queues */
 	reg = IXGBE_QDE_ENABLE;
 	if (adapter->vfinfo[vf].pf_vlan)
@@ -859,27 +908,7 @@
 
 	ixgbe_write_qde(adapter, vf, reg);
 
-	/* enable receive for vf */
-	reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
-	reg |= BIT(vf_shift);
-	/*
-	 * The 82599 cannot support a mix of jumbo and non-jumbo PF/VFs.
-	 * For more info take a look at ixgbe_set_vf_lpe
-	 */
-	if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
-		struct net_device *dev = adapter->netdev;
-		int pf_max_frame = dev->mtu + ETH_HLEN;
-
-#ifdef CONFIG_FCOE
-		if (dev->features & NETIF_F_FCOE_MTU)
-			pf_max_frame = max_t(int, pf_max_frame,
-					     IXGBE_FCOE_JUMBO_FRAME_SIZE);
-
-#endif /* CONFIG_FCOE */
-		if (pf_max_frame > ETH_FRAME_LEN)
-			reg &= ~BIT(vf_shift);
-	}
-	IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg);
+	ixgbe_set_vf_rx_tx(adapter, vf);
 
 	/* enable VF mailbox for further messages */
 	adapter->vfinfo[vf].clear_to_send = true;
@@ -1159,9 +1188,9 @@
 
 	switch (xcast_mode) {
 	case IXGBEVF_XCAST_MODE_NONE:
-		disable = IXGBE_VMOLR_BAM | IXGBE_VMOLR_ROMPE |
+		disable = IXGBE_VMOLR_ROMPE |
 			  IXGBE_VMOLR_MPE | IXGBE_VMOLR_UPE | IXGBE_VMOLR_VPE;
-		enable = 0;
+		enable = IXGBE_VMOLR_BAM;
 		break;
 	case IXGBEVF_XCAST_MODE_MULTI:
 		disable = IXGBE_VMOLR_MPE | IXGBE_VMOLR_UPE | IXGBE_VMOLR_VPE;
@@ -1183,9 +1212,9 @@
 			return -EPERM;
 		}
 
-		disable = 0;
+		disable = IXGBE_VMOLR_VPE;
 		enable = IXGBE_VMOLR_BAM | IXGBE_VMOLR_ROMPE |
-			 IXGBE_VMOLR_MPE | IXGBE_VMOLR_UPE | IXGBE_VMOLR_VPE;
+			 IXGBE_VMOLR_MPE | IXGBE_VMOLR_UPE;
 		break;
 	default:
 		return -EOPNOTSUPP;
@@ -1204,6 +1233,26 @@
 	return 0;
 }
 
+static int ixgbe_get_vf_link_state(struct ixgbe_adapter *adapter,
+				   u32 *msgbuf, u32 vf)
+{
+	u32 *link_state = &msgbuf[1];
+
+	/* verify the PF is supporting the correct API */
+	switch (adapter->vfinfo[vf].vf_api) {
+	case ixgbe_mbox_api_12:
+	case ixgbe_mbox_api_13:
+	case ixgbe_mbox_api_14:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	*link_state = adapter->vfinfo[vf].link_enable;
+
+	return 0;
+}
+
 static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
 {
 	u32 mbx_size = IXGBE_VFMAILBOX_SIZE;
@@ -1249,7 +1298,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);
@@ -1269,6 +1318,9 @@
 	case IXGBE_VF_UPDATE_XCAST_MODE:
 		retval = ixgbe_update_vf_xcast_mode(adapter, msgbuf, vf);
 		break;
+	case IXGBE_VF_GET_LINK_STATE:
+		retval = ixgbe_get_vf_link_state(adapter, msgbuf, vf);
+		break;
 	case IXGBE_VF_IPSEC_ADD:
 		retval = ixgbe_ipsec_vf_add_sa(adapter, msgbuf, vf);
 		break;
@@ -1277,7 +1329,7 @@
 		break;
 	default:
 		e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
-		retval = IXGBE_ERR_MBX;
+		retval = -EIO;
 		break;
 	}
 
@@ -1307,8 +1359,10 @@
 void ixgbe_msg_task(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
+	unsigned long flags;
 	u32 vf;
 
+	spin_lock_irqsave(&adapter->vfs_lock, flags);
 	for (vf = 0; vf < adapter->num_vfs; vf++) {
 		/* process any reset requests */
 		if (!ixgbe_check_for_rst(hw, vf))
@@ -1322,18 +1376,7 @@
 		if (!ixgbe_check_for_ack(hw, vf))
 			ixgbe_rcv_ack_from_vf(adapter, vf);
 	}
-}
-
-void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter)
-{
-	struct ixgbe_hw *hw = &adapter->hw;
-
-	/* disable transmit and receive for all vfs */
-	IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
-	IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
-
-	IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
-	IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
+	spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 }
 
 static inline void ixgbe_ping_vf(struct ixgbe_adapter *adapter, int vf)
@@ -1361,6 +1404,21 @@
 	}
 }
 
+/**
+ * ixgbe_set_all_vfs - update vfs queues
+ * @adapter: Pointer to adapter struct
+ *
+ * Update setting transmit and receive queues for all vfs
+ **/
+void ixgbe_set_all_vfs(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0 ; i < adapter->num_vfs; i++)
+		ixgbe_set_vf_link_state(adapter, i,
+					adapter->vfinfo[i].link_state);
+}
+
 int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -1658,6 +1716,84 @@
 	return 0;
 }
 
+/**
+ * ixgbe_set_vf_link_state - Set link state
+ * @adapter: Pointer to adapter struct
+ * @vf: VF identifier
+ * @state: required link state
+ *
+ * Set a link force state on/off a single vf
+ **/
+void ixgbe_set_vf_link_state(struct ixgbe_adapter *adapter, int vf, int state)
+{
+	adapter->vfinfo[vf].link_state = state;
+
+	switch (state) {
+	case IFLA_VF_LINK_STATE_AUTO:
+		if (test_bit(__IXGBE_DOWN, &adapter->state))
+			adapter->vfinfo[vf].link_enable = false;
+		else
+			adapter->vfinfo[vf].link_enable = true;
+		break;
+	case IFLA_VF_LINK_STATE_ENABLE:
+		adapter->vfinfo[vf].link_enable = true;
+		break;
+	case IFLA_VF_LINK_STATE_DISABLE:
+		adapter->vfinfo[vf].link_enable = false;
+		break;
+	}
+
+	ixgbe_set_vf_rx_tx(adapter, vf);
+
+	/* restart the VF */
+	adapter->vfinfo[vf].clear_to_send = false;
+	ixgbe_ping_vf(adapter, vf);
+}
+
+/**
+ * ixgbe_ndo_set_vf_link_state - Set link state
+ * @netdev: network interface device structure
+ * @vf: VF identifier
+ * @state: required link state
+ *
+ * Set the link state of a specified VF, regardless of physical link state
+ **/
+int ixgbe_ndo_set_vf_link_state(struct net_device *netdev, int vf, int state)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int ret = 0;
+
+	if (vf < 0 || vf >= adapter->num_vfs) {
+		dev_err(&adapter->pdev->dev,
+			"NDO set VF link - invalid VF identifier %d\n", vf);
+		return -EINVAL;
+	}
+
+	switch (state) {
+	case IFLA_VF_LINK_STATE_ENABLE:
+		dev_info(&adapter->pdev->dev,
+			 "NDO set VF %d link state %d - not supported\n",
+			vf, state);
+		break;
+	case IFLA_VF_LINK_STATE_DISABLE:
+		dev_info(&adapter->pdev->dev,
+			 "NDO set VF %d link state disable\n", vf);
+		ixgbe_set_vf_link_state(adapter, vf, state);
+		break;
+	case IFLA_VF_LINK_STATE_AUTO:
+		dev_info(&adapter->pdev->dev,
+			 "NDO set VF %d link state auto\n", vf);
+		ixgbe_set_vf_link_state(adapter, vf, state);
+		break;
+	default:
+		dev_err(&adapter->pdev->dev,
+			"NDO set VF %d - invalid link state %d\n", vf, state);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 int ixgbe_ndo_set_vf_rss_query_en(struct net_device *netdev, int vf,
 				  bool setting)
 {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
@@ -17,8 +17,8 @@
 #endif
 void ixgbe_msg_task(struct ixgbe_adapter *adapter);
 int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
-void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
 void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
+void ixgbe_set_all_vfs(struct ixgbe_adapter *adapter);
 int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
 int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
 			   u8 qos, __be16 vlan_proto);
@@ -31,7 +31,9 @@
 int ixgbe_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting);
 int ixgbe_ndo_get_vf_config(struct net_device *netdev,
 			    int vf, struct ifla_vf_info *ivi);
+int ixgbe_ndo_set_vf_link_state(struct net_device *netdev, int vf, int state);
 void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
+void ixgbe_set_vf_link_state(struct ixgbe_adapter *adapter, int vf, int state);
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
 #ifdef CONFIG_PCI_IOV
 void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, unsigned int max_vfs);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1247,7 +1247,7 @@
 #define IXGBE_PSRTYPE_RQPL_SHIFT    29
 
 /* CTRL Bit Masks */
-#define IXGBE_CTRL_GIO_DIS      0x00000004 /* Global IO Master Disable bit */
+#define IXGBE_CTRL_GIO_DIS      0x00000004 /* Global IO Primary Disable bit */
 #define IXGBE_CTRL_LNK_RST      0x00000008 /* Link Reset. Resets everything. */
 #define IXGBE_CTRL_RST          0x04000000 /* Reset (SW) */
 #define IXGBE_CTRL_RST_MASK     (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST)
@@ -1810,7 +1810,7 @@
 /* STATUS Bit Masks */
 #define IXGBE_STATUS_LAN_ID         0x0000000C /* LAN ID */
 #define IXGBE_STATUS_LAN_ID_SHIFT   2          /* LAN ID Shift*/
-#define IXGBE_STATUS_GIO            0x00080000 /* GIO Master Enable Status */
+#define IXGBE_STATUS_GIO            0x00080000 /* GIO Primary Enable Status */
 
 #define IXGBE_STATUS_LAN_ID_0   0x00000000 /* LAN ID 0 */
 #define IXGBE_STATUS_LAN_ID_1   0x00000004 /* LAN ID 1 */
@@ -2192,8 +2192,8 @@
 #define IXGBE_PCIDEVCTRL2_4_8s		0xd
 #define IXGBE_PCIDEVCTRL2_17_34s	0xe
 
-/* Number of 100 microseconds we wait for PCI Express master disable */
-#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT	800
+/* Number of 100 microseconds we wait for PCI Express primary disable */
+#define IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT	800
 
 /* RAH */
 #define IXGBE_RAH_VIND_MASK     0x003C0000
@@ -3505,10 +3505,10 @@
 	s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *);
 	s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
 	s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
-	s32 (*check_overtemp)(struct ixgbe_hw *);
+	bool (*check_overtemp)(struct ixgbe_hw *);
 	s32 (*set_phy_power)(struct ixgbe_hw *, bool on);
 	s32 (*enter_lplu)(struct ixgbe_hw *);
-	s32 (*handle_lasi)(struct ixgbe_hw *hw);
+	s32 (*handle_lasi)(struct ixgbe_hw *hw, bool *);
 	s32 (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
 				      u8 *value);
 	s32 (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
@@ -3661,45 +3661,6 @@
 	const u32			*mvals;
 };
 
-
-/* Error Codes */
-#define IXGBE_ERR_EEPROM                        -1
-#define IXGBE_ERR_EEPROM_CHECKSUM               -2
-#define IXGBE_ERR_PHY                           -3
-#define IXGBE_ERR_CONFIG                        -4
-#define IXGBE_ERR_PARAM                         -5
-#define IXGBE_ERR_MAC_TYPE                      -6
-#define IXGBE_ERR_UNKNOWN_PHY                   -7
-#define IXGBE_ERR_LINK_SETUP                    -8
-#define IXGBE_ERR_ADAPTER_STOPPED               -9
-#define IXGBE_ERR_INVALID_MAC_ADDR              -10
-#define IXGBE_ERR_DEVICE_NOT_SUPPORTED          -11
-#define IXGBE_ERR_MASTER_REQUESTS_PENDING       -12
-#define IXGBE_ERR_INVALID_LINK_SETTINGS         -13
-#define IXGBE_ERR_AUTONEG_NOT_COMPLETE          -14
-#define IXGBE_ERR_RESET_FAILED                  -15
-#define IXGBE_ERR_SWFW_SYNC                     -16
-#define IXGBE_ERR_PHY_ADDR_INVALID              -17
-#define IXGBE_ERR_I2C                           -18
-#define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
-#define IXGBE_ERR_SFP_NOT_PRESENT               -20
-#define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT       -21
-#define IXGBE_ERR_NO_SAN_ADDR_PTR               -22
-#define IXGBE_ERR_FDIR_REINIT_FAILED            -23
-#define IXGBE_ERR_EEPROM_VERSION                -24
-#define IXGBE_ERR_NO_SPACE                      -25
-#define IXGBE_ERR_OVERTEMP                      -26
-#define IXGBE_ERR_FC_NOT_NEGOTIATED             -27
-#define IXGBE_ERR_FC_NOT_SUPPORTED              -28
-#define IXGBE_ERR_SFP_SETUP_NOT_COMPLETE        -30
-#define IXGBE_ERR_PBA_SECTION                   -31
-#define IXGBE_ERR_INVALID_ARGUMENT              -32
-#define IXGBE_ERR_HOST_INTERFACE_COMMAND        -33
-#define IXGBE_ERR_FDIR_CMD_INCOMPLETE		-38
-#define IXGBE_ERR_FW_RESP_INVALID		-39
-#define IXGBE_ERR_TOKEN_RETRY			-40
-#define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
-
 #define IXGBE_FUSES0_GROUP(_i)		(0x11158 + ((_i) * 4))
 #define IXGBE_FUSES0_300MHZ		BIT(5)
 #define IXGBE_FUSES0_REV_MASK		(3u << 6)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -84,7 +84,7 @@
 	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
 	if (status) {
 		hw_dbg(hw, "semaphore failed with %d", status);
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	}
 
 	ctrl = IXGBE_CTRL_RST;
@@ -103,7 +103,7 @@
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
-		status = IXGBE_ERR_RESET_FAILED;
+		status = -EIO;
 		hw_dbg(hw, "Reset polling failed to complete.\n");
 	}
 	msleep(100);
@@ -220,7 +220,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = ixgbe_read_eerd_generic(hw, offset, data);
 
@@ -243,7 +243,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data);
 
@@ -264,7 +264,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = ixgbe_write_eewr_generic(hw, offset, data);
 
@@ -287,7 +287,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data);
 
@@ -324,7 +324,7 @@
 	for (i = 0; i < checksum_last_word; i++) {
 		if (ixgbe_read_eerd_generic(hw, i, &word)) {
 			hw_dbg(hw, "EEPROM read failed\n");
-			return IXGBE_ERR_EEPROM;
+			return -EIO;
 		}
 		checksum += word;
 	}
@@ -349,8 +349,7 @@
 
 		if (ixgbe_read_eerd_generic(hw, pointer, &length)) {
 			hw_dbg(hw, "EEPROM read failed\n");
-			return IXGBE_ERR_EEPROM;
-			break;
+			return -EIO;
 		}
 
 		/* Skip pointer section if length is invalid. */
@@ -361,7 +360,7 @@
 		for (j = pointer + 1; j <= pointer + length; j++) {
 			if (ixgbe_read_eerd_generic(hw, j, &word)) {
 				hw_dbg(hw, "EEPROM read failed\n");
-				return IXGBE_ERR_EEPROM;
+				return -EIO;
 			}
 			checksum += word;
 		}
@@ -398,7 +397,7 @@
 	}
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = hw->eeprom.ops.calc_checksum(hw);
 	if (status < 0)
@@ -419,7 +418,7 @@
 	 */
 	if (read_checksum != checksum) {
 		hw_dbg(hw, "Invalid EEPROM checksum");
-		status = IXGBE_ERR_EEPROM_CHECKSUM;
+		status = -EIO;
 	}
 
 	/* If the user cares, return the calculated checksum */
@@ -456,7 +455,7 @@
 	}
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
-		return  IXGBE_ERR_SWFW_SYNC;
+		return  -EBUSY;
 
 	status = hw->eeprom.ops.calc_checksum(hw);
 	if (status < 0)
@@ -491,7 +490,7 @@
 	s32 status;
 
 	status = ixgbe_poll_flash_update_done_X540(hw);
-	if (status == IXGBE_ERR_EEPROM) {
+	if (status == -EIO) {
 		hw_dbg(hw, "Flash update time out\n");
 		return status;
 	}
@@ -541,7 +540,7 @@
 			return 0;
 		udelay(5);
 	}
-	return IXGBE_ERR_EEPROM;
+	return -EIO;
 }
 
 /**
@@ -576,7 +575,7 @@
 		 * SW_FW_SYNC bits (not just NVM)
 		 */
 		if (ixgbe_get_swfw_sync_semaphore(hw))
-			return IXGBE_ERR_SWFW_SYNC;
+			return -EBUSY;
 
 		swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
 		if (!(swfw_sync & (fwmask | swmask | hwmask))) {
@@ -600,7 +599,7 @@
 	 * bits in the SW_FW_SYNC register.
 	 */
 	if (ixgbe_get_swfw_sync_semaphore(hw))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
 	if (swfw_sync & (fwmask | hwmask)) {
 		swfw_sync |= swmask;
@@ -623,11 +622,11 @@
 			rmask |= IXGBE_GSSR_I2C_MASK;
 		ixgbe_release_swfw_sync_X540(hw, rmask);
 		ixgbe_release_swfw_sync_semaphore(hw);
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	}
 	ixgbe_release_swfw_sync_semaphore(hw);
 
-	return IXGBE_ERR_SWFW_SYNC;
+	return -EBUSY;
 }
 
 /**
@@ -681,7 +680,7 @@
 	if (i == timeout) {
 		hw_dbg(hw,
 		       "Software semaphore SMBI between device drivers not granted.\n");
-		return IXGBE_ERR_EEPROM;
+		return -EIO;
 	}
 
 	/* Now get the semaphore between SW/FW through the REGSMP bit */
@@ -698,7 +697,7 @@
 	 */
 	hw_dbg(hw, "REGSMP Software NVM semaphore not granted\n");
 	ixgbe_release_swfw_sync_semaphore(hw);
-	return IXGBE_ERR_EEPROM;
+	return -EIO;
 }
 
 /**
@@ -769,7 +768,7 @@
 	bool link_up;
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* Link should be up in order for the blink bit in the LED control
 	 * register to work. Force link and speed in the MAC if link is down.
@@ -805,7 +804,7 @@
 	u32 ledctl_reg;
 
 	if (index > 3)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* Restore the LED to its default value. */
 	ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -206,13 +206,13 @@
 	}
 	if (retry == IXGBE_CS4227_RETRIES) {
 		hw_err(hw, "CS4227 reset did not complete\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value);
 	if (status || !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) {
 		hw_err(hw, "CS4227 EEPROM did not load successfully\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	return 0;
@@ -350,13 +350,13 @@
 static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
 				     u32 device_type, u16 *phy_data)
 {
-	return IXGBE_NOT_IMPLEMENTED;
+	return -EOPNOTSUPP;
 }
 
 static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
 				      u32 device_type, u16 phy_data)
 {
-	return IXGBE_NOT_IMPLEMENTED;
+	return -EOPNOTSUPP;
 }
 
 /**
@@ -463,7 +463,7 @@
 		--retries;
 	} while (retries > 0);
 
-	return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+	return -EIO;
 }
 
 static const struct {
@@ -511,7 +511,7 @@
 	hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK;
 	hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK;
 	if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK)
-		return IXGBE_ERR_PHY_ADDR_INVALID;
+		return -EFAULT;
 
 	hw->phy.autoneg_advertised = hw->phy.speeds_supported;
 	hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL |
@@ -568,7 +568,7 @@
 
 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
 		hw_err(hw, "rx_pause not valid in strict IEEE mode\n");
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 	}
 
 	switch (hw->fc.requested_mode) {
@@ -600,8 +600,10 @@
 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup);
 	if (rc)
 		return rc;
+
 	if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN)
-		return IXGBE_ERR_OVERTEMP;
+		return -EIO;
+
 	return 0;
 }
 
@@ -675,7 +677,7 @@
 		*ctrl = command;
 	if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
 		hw_dbg(hw, "IOSF wait timed out\n");
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 	return 0;
@@ -715,7 +717,8 @@
 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
 		hw_dbg(hw, "Failed to read, error %x\n", error);
-		return IXGBE_ERR_PHY;
+		ret = -EIO;
+		goto out;
 	}
 
 	if (!ret)
@@ -750,9 +753,9 @@
 	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
 		return 0;
 	if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY)
-		return IXGBE_ERR_FW_RESP_INVALID;
+		return -EIO;
 
-	return IXGBE_ERR_TOKEN_RETRY;
+	return -EAGAIN;
 }
 
 /**
@@ -778,7 +781,7 @@
 		return status;
 	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
 		return 0;
-	return IXGBE_ERR_FW_RESP_INVALID;
+	return -EIO;
 }
 
 /**
@@ -942,7 +945,7 @@
 		local_buffer = buf;
 	} else {
 		if (buffer_size < ptr)
-			return  IXGBE_ERR_PARAM;
+			return  -EINVAL;
 		local_buffer = &buffer[ptr];
 	}
 
@@ -960,7 +963,7 @@
 	}
 
 	if (buffer && ((u32)start + (u32)length > buffer_size))
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	for (i = start; length; i++, length--) {
 		if (i == bufsz && !buffer) {
@@ -1012,7 +1015,7 @@
 		local_buffer = eeprom_ptrs;
 	} else {
 		if (buffer_size < IXGBE_EEPROM_LAST_WORD)
-			return IXGBE_ERR_PARAM;
+			return -EINVAL;
 		local_buffer = buffer;
 	}
 
@@ -1148,7 +1151,7 @@
 	 * calculated checksum
 	 */
 	if (read_checksum != checksum) {
-		status = IXGBE_ERR_EEPROM_CHECKSUM;
+		status = -EIO;
 		hw_dbg(hw, "Invalid EEPROM checksum");
 	}
 
@@ -1203,7 +1206,7 @@
 		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
 	} else {
 		hw_dbg(hw, "write ee hostif failed to get semaphore");
-		status = IXGBE_ERR_SWFW_SYNC;
+		status = -EBUSY;
 	}
 
 	return status;
@@ -1415,7 +1418,7 @@
 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
 		hw_dbg(hw, "Failed to write, error %x\n", error);
-		return IXGBE_ERR_PHY;
+		return -EIO;
 	}
 
 out:
@@ -1558,7 +1561,7 @@
 
 	/* iXFI is only supported with X552 */
 	if (mac->type != ixgbe_mac_X550EM_x)
-		return IXGBE_ERR_LINK_SETUP;
+		return -EIO;
 
 	/* Disable AN and force speed to 10G Serial. */
 	status = ixgbe_read_iosf_sb_reg_x550(hw,
@@ -1580,7 +1583,7 @@
 		break;
 	default:
 		/* Other link speeds are not supported by internal KR PHY. */
-		return IXGBE_ERR_LINK_SETUP;
+		return -EINVAL;
 	}
 
 	status = ixgbe_write_iosf_sb_reg_x550(hw,
@@ -1611,7 +1614,7 @@
 {
 	switch (hw->phy.sfp_type) {
 	case ixgbe_sfp_type_not_present:
-		return IXGBE_ERR_SFP_NOT_PRESENT;
+		return -ENOENT;
 	case ixgbe_sfp_type_da_cu_core0:
 	case ixgbe_sfp_type_da_cu_core1:
 		*linear = true;
@@ -1630,7 +1633,7 @@
 	case ixgbe_sfp_type_1g_cu_core0:
 	case ixgbe_sfp_type_1g_cu_core1:
 	default:
-		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+		return -EOPNOTSUPP;
 	}
 
 	return 0;
@@ -1660,7 +1663,7 @@
 	 * there is no reason to configure CS4227 and SFP not present error is
 	 * not accepted in the setup MAC link flow.
 	 */
-	if (status == IXGBE_ERR_SFP_NOT_PRESENT)
+	if (status == -ENOENT)
 		return 0;
 
 	if (status)
@@ -1718,7 +1721,7 @@
 		break;
 	default:
 		/* Other link speeds are not supported by internal PHY. */
-		return IXGBE_ERR_LINK_SETUP;
+		return -EINVAL;
 	}
 
 	status = mac->ops.write_iosf_sb_reg(hw,
@@ -1753,7 +1756,7 @@
 	/* If no SFP module present, then return success. Return success since
 	 * SFP not present error is not excepted in the setup MAC link flow.
 	 */
-	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
+	if (ret_val == -ENOENT)
 		return 0;
 
 	if (ret_val)
@@ -1803,7 +1806,7 @@
 	/* If no SFP module present, then return success. Return success since
 	 * SFP not present error is not excepted in the setup MAC link flow.
 	 */
-	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
+	if (ret_val == -ENOENT)
 		return 0;
 
 	if (ret_val)
@@ -1813,7 +1816,7 @@
 	ixgbe_setup_kr_speed_x550em(hw, speed);
 
 	if (hw->phy.mdio.prtad == MDIO_PRTAD_NONE)
-		return IXGBE_ERR_PHY_ADDR_INVALID;
+		return -EFAULT;
 
 	/* Get external PHY SKU id */
 	ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU,
@@ -1912,7 +1915,7 @@
 	u16 i, autoneg_status;
 
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 
 	status = ixgbe_check_mac_link_generic(hw, speed, link_up,
 					      link_up_wait_to_complete);
@@ -2095,9 +2098,9 @@
  */
 static void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
 {
-	s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
 	u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
 	ixgbe_link_speed speed;
+	s32 status = -EIO;
 	bool link_up;
 
 	/* AN should have completed when the cable was plugged in.
@@ -2115,7 +2118,7 @@
 	/* Check if auto-negotiation has completed */
 	status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info);
 	if (status || !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) {
-		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+		status = -EIO;
 		goto out;
 	}
 
@@ -2319,18 +2322,18 @@
  * @hw: pointer to hardware structure
  * @lsc: pointer to boolean flag which indicates whether external Base T
  *	 PHY interrupt is lsc
+ * @is_overtemp: indicate whether an overtemp event encountered
  *
  * Determime if external Base T PHY interrupt cause is high temperature
  * failure alarm or link status change.
- *
- * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
- * failure alarm, else return PHY access status.
  **/
-static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc,
+				       bool *is_overtemp)
 {
 	u32 status;
 	u16 reg;
 
+	*is_overtemp = false;
 	*lsc = false;
 
 	/* Vendor alarm triggered */
@@ -2362,7 +2365,8 @@
 	if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
 		/* power down the PHY in case the PHY FW didn't already */
 		ixgbe_set_copper_phy_power(hw, false);
-		return IXGBE_ERR_OVERTEMP;
+		*is_overtemp = true;
+		return -EIO;
 	}
 	if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) {
 		/*  device fault alarm triggered */
@@ -2376,7 +2380,8 @@
 		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;
+			*is_overtemp = true;
+			return -EIO;
 		}
 	}
 
@@ -2412,12 +2417,12 @@
  **/
 static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
 {
+	bool lsc, overtemp;
 	u32 status;
 	u16 reg;
-	bool lsc;
 
 	/* Clear interrupt flags */
-	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, &overtemp);
 
 	/* Enable link status change alarm */
 
@@ -2496,21 +2501,20 @@
 /**
  * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
  * @hw: pointer to hardware structure
+ * @is_overtemp: indicate whether an overtemp event encountered
  *
  * Handle external Base T PHY interrupt. If high temperature
  * failure alarm then return error, else if link status change
  * then setup internal/external PHY link
- *
- * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
- * failure alarm, else return PHY access status.
  **/
-static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw,
+					  bool *is_overtemp)
 {
 	struct ixgbe_phy_info *phy = &hw->phy;
 	bool lsc;
 	u32 status;
 
-	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, is_overtemp);
 	if (status)
 		return status;
 
@@ -2642,7 +2646,7 @@
 	u16 speed;
 
 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 
 	if (!(hw->mac.type == ixgbe_mac_X550EM_x &&
 	      !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))) {
@@ -2685,7 +2689,7 @@
 		break;
 	default:
 		/* Internal PHY does not support anything else */
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 	}
 
 	return ixgbe_setup_ixfi_x550em(hw, &force_speed);
@@ -2717,7 +2721,7 @@
 	u16 phy_data;
 
 	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* To turn on the LED, set mode to ON. */
 	hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
@@ -2739,7 +2743,7 @@
 	u16 phy_data;
 
 	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
-		return IXGBE_ERR_PARAM;
+		return -EINVAL;
 
 	/* To turn on the LED, set mode to ON. */
 	hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
@@ -2763,8 +2767,9 @@
  *
  *  Sends driver version number to firmware through the manageability
  *  block.  On success return 0
- *  else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring
- *  semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ *  else returns -EBUSY when encountering an error acquiring
+ *  semaphore, -EIO when command fails or -ENIVAL when incorrect
+ *  params passed.
  **/
 static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
 				     u8 build, u8 sub, u16 len,
@@ -2775,7 +2780,7 @@
 	int i;
 
 	if (!len || !driver_ver || (len > sizeof(fw_cmd.driver_string)))
-		return IXGBE_ERR_INVALID_ARGUMENT;
+		return -EINVAL;
 
 	fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
 	fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN + len;
@@ -2800,7 +2805,7 @@
 
 		if (fw_cmd.hdr.cmd_or_resp.ret_status !=
 		    FW_CEM_RESP_STATUS_SUCCESS)
-			return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+			return -EIO;
 		return 0;
 	}
 
@@ -2857,7 +2862,7 @@
 	/* Validate the requested mode */
 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
 		hw_err(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 	}
 
 	/* 10gig parts do not have a word in the EEPROM to determine the
@@ -2892,7 +2897,7 @@
 		break;
 	default:
 		hw_err(hw, "Flow control param set incorrectly\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	switch (hw->device_id) {
@@ -2936,8 +2941,8 @@
 static void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw)
 {
 	u32 link_s1, lp_an_page_low, an_cntl_1;
-	s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
 	ixgbe_link_speed speed;
+	s32 status = -EIO;
 	bool link_up;
 
 	/* AN should have completed when the cable was plugged in.
@@ -2963,7 +2968,7 @@
 
 	if (status || (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) {
 		hw_dbg(hw, "Auto-Negotiation did not complete\n");
-		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+		status = -EIO;
 		goto out;
 	}
 
@@ -3137,21 +3142,23 @@
 /**
  * ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp
  * @hw: pointer to hardware structure
+ *
+ * Return true when an overtemp event detected, otherwise false.
  */
-static s32 ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
+static bool ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
 {
 	u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 };
 	s32 rc;
 
 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store);
 	if (rc)
-		return rc;
+		return false;
 
 	if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) {
 		ixgbe_shutdown_fw_phy(hw);
-		return IXGBE_ERR_OVERTEMP;
+		return true;
 	}
-	return 0;
+	return false;
 }
 
 /**
@@ -3201,8 +3208,7 @@
 
 	/* Identify the PHY or SFP module */
 	ret_val = phy->ops.identify(hw);
-	if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED ||
-	    ret_val == IXGBE_ERR_PHY_ADDR_INVALID)
+	if (ret_val == -EOPNOTSUPP || ret_val == -EFAULT)
 		return ret_val;
 
 	/* Setup function pointers based on detected hardware */
@@ -3405,10 +3411,12 @@
 	/* flush pending Tx transactions */
 	ixgbe_clear_tx_pending(hw);
 
+	/* set MDIO speed before talking to the PHY in case it's the 1st time */
+	ixgbe_set_mdio_speed(hw);
+
 	/* PHY ops must be identified and initialized prior to reset */
 	status = hw->phy.ops.init(hw);
-	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED ||
-	    status == IXGBE_ERR_PHY_ADDR_INVALID)
+	if (status == -EOPNOTSUPP || status == -EFAULT)
 		return status;
 
 	/* start the external PHY */
@@ -3424,7 +3432,7 @@
 		hw->phy.sfp_setup_needed = false;
 	}
 
-	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+	if (status == -EOPNOTSUPP)
 		return status;
 
 	/* Reset PHY */
@@ -3448,7 +3456,7 @@
 	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
 	if (status) {
 		hw_dbg(hw, "semaphore failed with %d", status);
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 	}
 
 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
@@ -3466,7 +3474,7 @@
 	}
 
 	if (ctrl & IXGBE_CTRL_RST_MASK) {
-		status = IXGBE_ERR_RESET_FAILED;
+		status = -EIO;
 		hw_dbg(hw, "Reset polling failed to complete.\n");
 	}
 
@@ -3562,7 +3570,7 @@
 	/* Validate the requested mode */
 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
 		hw_err(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
-		return IXGBE_ERR_INVALID_LINK_SETTINGS;
+		return -EINVAL;
 	}
 
 	if (hw->fc.requested_mode == ixgbe_fc_default)
@@ -3619,7 +3627,7 @@
 		break;
 	default:
 		hw_err(hw, "Flow control param set incorrectly\n");
-		return IXGBE_ERR_CONFIG;
+		return -EIO;
 	}
 
 	status = hw->mac.ops.write_iosf_sb_reg(hw,
@@ -3715,7 +3723,7 @@
 			return 0;
 		if (hmask)
 			ixgbe_release_swfw_sync_X540(hw, hmask);
-		if (status != IXGBE_ERR_TOKEN_RETRY)
+		if (status != -EAGAIN)
 			return status;
 		msleep(FW_PHY_TOKEN_DELAY);
 	}
@@ -3759,7 +3767,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, mask))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
 
@@ -3785,7 +3793,7 @@
 	s32 status;
 
 	if (hw->mac.ops.acquire_swfw_sync(hw, mask))
-		return IXGBE_ERR_SWFW_SYNC;
+		return -EBUSY;
 
 	status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, phy_data);
 	hw->mac.ops.release_swfw_sync(hw, mask);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -583,12 +583,14 @@
 	u32 cmd_type;
 
 	while (budget-- > 0) {
-		if (unlikely(!ixgbe_desc_unused(xdp_ring)) ||
-		    !netif_carrier_ok(xdp_ring->netdev)) {
+		if (unlikely(!ixgbe_desc_unused(xdp_ring))) {
 			work_done = false;
 			break;
 		}
 
+		if (!netif_carrier_ok(xdp_ring->netdev))
+			break;
+
 		if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &desc))
 			break;
 
@@ -709,10 +711,14 @@
 	if (qid >= adapter->num_xdp_queues)
 		return -ENXIO;
 
-	if (!adapter->xdp_ring[qid]->xsk_umem)
+	ring = adapter->xdp_ring[qid];
+
+	if (test_bit(__IXGBE_TX_DISABLED, &ring->state))
+		return -ENETDOWN;
+
+	if (!ring->xsk_umem)
 		return -ENXIO;
 
-	ring = adapter->xdp_ring[qid];
 	if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
 		u64 eics = BIT_ULL(ring->q_vector->v_idx);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/ipsec.c
@@ -272,6 +272,11 @@
 		return -EINVAL;
 	}
 
+	if (xs->props.mode != XFRM_MODE_TRANSPORT) {
+		netdev_err(dev, "Unsupported mode for ipsec offload\n");
+		return -EINVAL;
+	}
+
 	if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
 		struct rx_sa rsa;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -387,6 +387,8 @@
 	u32 *rss_key;
 	u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE];
 	u32 flags;
+	bool link_state;
+
 #define IXGBEVF_FLAGS_LEGACY_RX		BIT(1)
 
 #ifdef CONFIG_XFRM
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -1079,11 +1079,14 @@
 	case XDP_TX:
 		xdp_ring = adapter->xdp_ring[rx_ring->queue_index];
 		result = ixgbevf_xmit_xdp_ring(xdp_ring, xdp);
+		if (result == IXGBEVF_XDP_CONSUMED)
+			goto out_failure;
 		break;
 	default:
 		bpf_warn_invalid_xdp_action(act);
 		/* fallthrough */
 	case XDP_ABORTED:
+out_failure:
 		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
 		/* fallthrough -- handle aborts by dropping packet */
 	case XDP_DROP:
@@ -1976,14 +1979,15 @@
 	if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX)
 		return;
 
-	set_ring_build_skb_enabled(rx_ring);
+	if (PAGE_SIZE < 8192)
+		if (max_frame > IXGBEVF_MAX_FRAME_BUILD_SKB)
+			set_ring_uses_large_buffer(rx_ring);
 
-	if (PAGE_SIZE < 8192) {
-		if (max_frame <= IXGBEVF_MAX_FRAME_BUILD_SKB)
-			return;
+	/* 82599 can't rely on RXDCTL.RLPML to restrict the size of the frame */
+	if (adapter->hw.mac.type == ixgbe_mac_82599_vf && !ring_uses_large_buffer(rx_ring))
+		return;
 
-		set_ring_uses_large_buffer(rx_ring);
-	}
+	set_ring_build_skb_enabled(rx_ring);
 }
 
 /**
@@ -2081,11 +2085,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;
 
@@ -2287,7 +2286,9 @@
 static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
 	struct ixgbe_hw *hw = &adapter->hw;
+	bool state;
 
 	ixgbevf_configure_msix(adapter);
 
@@ -2300,6 +2301,11 @@
 
 	spin_unlock_bh(&adapter->mbx_lock);
 
+	state = adapter->link_state;
+	hw->mac.ops.get_link_state(hw, &adapter->link_state);
+	if (state && state != adapter->link_state)
+		dev_info(&pdev->dev, "VF is administratively disabled\n");
+
 	smp_mb__before_atomic();
 	clear_bit(__IXGBEVF_DOWN, &adapter->state);
 	ixgbevf_napi_enable_all(adapter);
@@ -3070,6 +3076,8 @@
 	adapter->tx_ring_count = IXGBEVF_DEFAULT_TXD;
 	adapter->rx_ring_count = IXGBEVF_DEFAULT_RXD;
 
+	adapter->link_state = true;
+
 	set_bit(__IXGBEVF_DOWN, &adapter->state);
 	return 0;
 
@@ -3302,7 +3310,7 @@
 
 	ixgbevf_watchdog_update_link(adapter);
 
-	if (adapter->link_up)
+	if (adapter->link_up && adapter->link_state)
 		ixgbevf_watchdog_link_is_up(adapter);
 	else
 		ixgbevf_watchdog_link_is_down(adapter);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/mbx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/mbx.h
@@ -51,6 +51,16 @@
 /* bits 23:16 are used for exra info for certain messages */
 #define IXGBE_VT_MSGINFO_MASK	(0xFF << IXGBE_VT_MSGINFO_SHIFT)
 
+/* IXGBE_VT_MSGTYPE_NACK and IXGBE_VT_MSGTYPE_ACK were renamed to
+ * IXGBE_VT_MSGTYPE_FAILURE and IXGBE_VT_MSGTYPE_SUCCESS respectively
+ * with commit 0edbecd57057 upstream.
+ *
+ * One of the backported fixes use them with their new names. These
+ * aliases enable them to work with both older and newer names.
+ */
+#define IXGBE_VT_MSGTYPE_SUCCESS IXGBE_VT_MSGTYPE_ACK
+#define IXGBE_VT_MSGTYPE_FAILURE IXGBE_VT_MSGTYPE_NACK
+
 /* definitions to support mailbox API version negotiation */
 
 /* each element denotes a version of the API; existing numbers may not
@@ -97,6 +107,8 @@
 #define IXGBE_VF_IPSEC_ADD	0x0d
 #define IXGBE_VF_IPSEC_DEL	0x0e
 
+#define IXGBE_VF_GET_LINK_STATE 0x10 /* get vf link state */
+
 /* length of permanent address message returned from PF */
 #define IXGBE_VF_PERMADDR_MSG_LEN	4
 /* word in permanent address message with the current multicast type */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -574,6 +574,46 @@
 }
 
 /**
+ * ixgbevf_get_link_state_vf - Get VF link state from PF
+ * @hw: pointer to the HW structure
+ * @link_state: link state storage
+ *
+ * Returns state of the operation error or success.
+ */
+static s32 ixgbevf_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state)
+{
+	u32 msgbuf[2];
+	s32 ret_val;
+	s32 err;
+
+	msgbuf[0] = IXGBE_VF_GET_LINK_STATE;
+	msgbuf[1] = 0x0;
+
+	err = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2);
+
+	if (err || (msgbuf[0] & IXGBE_VT_MSGTYPE_FAILURE)) {
+		ret_val = IXGBE_ERR_MBX;
+	} else {
+		ret_val = 0;
+		*link_state = msgbuf[1];
+	}
+
+	return ret_val;
+}
+
+/**
+ * ixgbevf_hv_get_link_state_vf - * Hyper-V variant - just a stub.
+ * @hw: unused
+ * @link_state: unused
+ *
+ * Hyper-V variant; there is no mailbox communication.
+ */
+static s32 ixgbevf_hv_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
  *  ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
  *  @hw: pointer to the HW structure
  *  @vlan: 12 bit VLAN ID
@@ -950,6 +990,7 @@
 	.set_rar		= ixgbevf_set_rar_vf,
 	.update_mc_addr_list	= ixgbevf_update_mc_addr_list_vf,
 	.update_xcast_mode	= ixgbevf_update_xcast_mode,
+	.get_link_state		= ixgbevf_get_link_state_vf,
 	.set_uc_addr		= ixgbevf_set_uc_addr_vf,
 	.set_vfta		= ixgbevf_set_vfta_vf,
 	.set_rlpml		= ixgbevf_set_rlpml_vf,
@@ -967,6 +1008,7 @@
 	.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,
+	.get_link_state		= ixgbevf_hv_get_link_state_vf,
 	.set_uc_addr		= ixgbevf_hv_set_uc_addr_vf,
 	.set_vfta		= ixgbevf_hv_set_vfta_vf,
 	.set_rlpml		= ixgbevf_hv_set_rlpml_vf,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/intel/ixgbevf/vf.h
+++ linux-ein-5.4.0/drivers/net/ethernet/intel/ixgbevf/vf.h
@@ -42,6 +42,7 @@
 	s32 (*init_rx_addrs)(struct ixgbe_hw *);
 	s32 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *);
 	s32 (*update_xcast_mode)(struct ixgbe_hw *, int);
+	s32 (*get_link_state)(struct ixgbe_hw *hw, bool *link_state);
 	s32 (*enable_mc)(struct ixgbe_hw *);
 	s32 (*disable_mc)(struct ixgbe_hw *);
 	s32 (*clear_vfta)(struct ixgbe_hw *);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/korina.c
+++ linux-ein-5.4.0/drivers/net/ethernet/korina.c
@@ -219,7 +219,7 @@
 			dev_kfree_skb_any(skb);
 			spin_unlock_irqrestore(&lp->lock, flags);
 
-			return NETDEV_TX_BUSY;
+			return NETDEV_TX_OK;
 		}
 	}
 
@@ -1113,7 +1113,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:
@@ -1133,6 +1133,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-ein-5.4.0.orig/drivers/net/ethernet/lantiq_etop.c
+++ linux-ein-5.4.0/drivers/net/ethernet/lantiq_etop.c
@@ -466,7 +466,6 @@
 	len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
 
 	if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
-		dev_kfree_skb_any(skb);
 		netdev_err(dev, "tx ring full\n");
 		netif_tx_stop_queue(txq);
 		return NETDEV_TX_BUSY;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/lantiq_xrx200.c
+++ linux-ein-5.4.0/drivers/net/ethernet/lantiq_xrx200.c
@@ -154,6 +154,8 @@
 
 static int xrx200_alloc_skb(struct xrx200_chan *ch)
 {
+	struct sk_buff *skb = ch->skb[ch->dma.desc];
+	dma_addr_t mapping;
 	int ret = 0;
 
 	ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev,
@@ -163,16 +165,18 @@
 		goto skip;
 	}
 
-	ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->priv->dev,
-			ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
-			DMA_FROM_DEVICE);
-	if (unlikely(dma_mapping_error(ch->priv->dev,
-				       ch->dma.desc_base[ch->dma.desc].addr))) {
+	mapping = dma_map_single(ch->priv->dev, ch->skb[ch->dma.desc]->data,
+				 XRX200_DMA_DATA_LEN, DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(ch->priv->dev, mapping))) {
 		dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+		ch->skb[ch->dma.desc] = skb;
 		ret = -ENOMEM;
 		goto skip;
 	}
 
+	ch->dma.desc_base[ch->dma.desc].addr = mapping;
+	/* Make sure the address is written before we give it to HW */
+	wmb();
 skip:
 	ch->dma.desc_base[ch->dma.desc].ctl =
 		LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
@@ -196,6 +200,7 @@
 	ch->dma.desc %= LTQ_DESC_NUM;
 
 	if (ret) {
+		net_dev->stats.rx_dropped++;
 		netdev_err(net_dev, "failed to allocate new rx buffer\n");
 		return ret;
 	}
@@ -204,7 +209,7 @@
 	skb->protocol = eth_type_trans(skb, net_dev);
 	netif_receive_skb(skb);
 	net_dev->stats.rx_packets++;
-	net_dev->stats.rx_bytes += len - ETH_FCS_LEN;
+	net_dev->stats.rx_bytes += len;
 
 	return 0;
 }
@@ -230,8 +235,8 @@
 	}
 
 	if (rx < budget) {
-		napi_complete(&ch->napi);
-		ltq_dma_enable_irq(&ch->dma);
+		if (napi_complete_done(&ch->napi, rx))
+			ltq_dma_enable_irq(&ch->dma);
 	}
 
 	return rx;
@@ -245,6 +250,7 @@
 	int pkts = 0;
 	int bytes = 0;
 
+	netif_tx_lock(net_dev);
 	while (pkts < budget) {
 		struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->tx_free];
 
@@ -268,9 +274,13 @@
 	net_dev->stats.tx_bytes += bytes;
 	netdev_completed_queue(ch->priv->net_dev, pkts, bytes);
 
+	netif_tx_unlock(net_dev);
+	if (netif_queue_stopped(net_dev))
+		netif_wake_queue(net_dev);
+
 	if (pkts < budget) {
-		napi_complete(&ch->napi);
-		ltq_dma_enable_irq(&ch->dma);
+		if (napi_complete_done(&ch->napi, pkts))
+			ltq_dma_enable_irq(&ch->dma);
 	}
 
 	return pkts;
@@ -341,10 +351,12 @@
 {
 	struct xrx200_chan *ch = ptr;
 
-	ltq_dma_disable_irq(&ch->dma);
-	ltq_dma_ack_irq(&ch->dma);
+	if (napi_schedule_prep(&ch->napi)) {
+		ltq_dma_disable_irq(&ch->dma);
+		__napi_schedule(&ch->napi);
+	}
 
-	napi_schedule(&ch->napi);
+	ltq_dma_ack_irq(&ch->dma);
 
 	return IRQ_HANDLED;
 }
@@ -498,7 +510,7 @@
 
 	/* setup NAPI */
 	netif_napi_add(net_dev, &priv->chan_rx.napi, xrx200_poll_rx, 32);
-	netif_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32);
+	netif_tx_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32);
 
 	platform_set_drvdata(pdev, priv);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2476,6 +2476,7 @@
 	for (i = 0; i < mp->rxq_count; i++)
 		rxq_deinit(mp->rxq + i);
 out:
+	napi_disable(&mp->napi);
 	free_irq(dev->irq, dev);
 
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvneta.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvneta.c
@@ -101,12 +101,14 @@
 #define      MVNETA_DESC_SWAP                    BIT(6)
 #define      MVNETA_TX_BRST_SZ_MASK(burst)       ((burst) << 22)
 #define MVNETA_PORT_STATUS                       0x2444
-#define      MVNETA_TX_IN_PRGRS                  BIT(1)
+#define      MVNETA_TX_IN_PRGRS                  BIT(0)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
+/* Only exists on Armada XP and Armada 370 */
 #define MVNETA_SERDES_CFG			 0x24A0
 #define      MVNETA_SGMII_SERDES_PROTO		 0x0cc7
 #define      MVNETA_QSGMII_SERDES_PROTO		 0x0667
+#define      MVNETA_HSGMII_SERDES_PROTO		 0x1107
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -388,6 +390,8 @@
 	struct	u64_stats_sync syncp;
 	u64	rx_packets;
 	u64	rx_bytes;
+	u64	rx_dropped;
+	u64	rx_errors;
 	u64	tx_packets;
 	u64	tx_bytes;
 };
@@ -545,6 +549,20 @@
 };
 #endif
 
+enum mvneta_tx_buf_type {
+	MVNETA_TYPE_SKB,
+	MVNETA_TYPE_XDP_TX,
+	MVNETA_TYPE_XDP_NDO,
+};
+
+struct mvneta_tx_buf {
+	enum mvneta_tx_buf_type type;
+	union {
+		struct xdp_frame *xdpf;
+		struct sk_buff *skb;
+	};
+};
+
 struct mvneta_tx_queue {
 	/* Number of this TX queue, in the range 0-7 */
 	u8 id;
@@ -560,8 +578,8 @@
 	int tx_stop_threshold;
 	int tx_wake_threshold;
 
-	/* Array of transmitted skb */
-	struct sk_buff **tx_skb;
+	/* Array of transmitted buffers */
+	struct mvneta_tx_buf *buf;
 
 	/* Index of last TX DMA descriptor that was inserted */
 	int txq_put_index;
@@ -706,6 +724,8 @@
 		struct mvneta_pcpu_stats *cpu_stats;
 		u64 rx_packets;
 		u64 rx_bytes;
+		u64 rx_dropped;
+		u64 rx_errors;
 		u64 tx_packets;
 		u64 tx_bytes;
 
@@ -714,19 +734,20 @@
 			start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
 			rx_packets = cpu_stats->rx_packets;
 			rx_bytes   = cpu_stats->rx_bytes;
+			rx_dropped = cpu_stats->rx_dropped;
+			rx_errors  = cpu_stats->rx_errors;
 			tx_packets = cpu_stats->tx_packets;
 			tx_bytes   = cpu_stats->tx_bytes;
 		} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
 		stats->rx_packets += rx_packets;
 		stats->rx_bytes   += rx_bytes;
+		stats->rx_dropped += rx_dropped;
+		stats->rx_errors  += rx_errors;
 		stats->tx_packets += tx_packets;
 		stats->tx_bytes   += tx_bytes;
 	}
 
-	stats->rx_errors	= dev->stats.rx_errors;
-	stats->rx_dropped	= dev->stats.rx_dropped;
-
 	stats->tx_dropped	= dev->stats.tx_dropped;
 }
 
@@ -1401,7 +1422,7 @@
 			 */
 			if (txq_number == 1)
 				txq_map = (cpu == pp->rxq_def) ?
-					MVNETA_CPU_TXQ_ACCESS(1) : 0;
+					MVNETA_CPU_TXQ_ACCESS(0) : 0;
 
 		} else {
 			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
@@ -1703,8 +1724,14 @@
 static void mvneta_rx_error(struct mvneta_port *pp,
 			    struct mvneta_rx_desc *rx_desc)
 {
+	struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats);
 	u32 status = rx_desc->status;
 
+	/* update per-cpu counter */
+	u64_stats_update_begin(&stats->syncp);
+	stats->rx_errors++;
+	u64_stats_update_end(&stats->syncp);
+
 	switch (status & MVNETA_RXD_ERR_CODE_MASK) {
 	case MVNETA_RXD_ERR_CRC:
 		netdev_err(pp->dev, "bad rx status %08x (crc error), size=%d\n",
@@ -1761,14 +1788,9 @@
 	int i;
 
 	for (i = 0; i < num; i++) {
+		struct mvneta_tx_buf *buf = &txq->buf[txq->txq_get_index];
 		struct mvneta_tx_desc *tx_desc = txq->descs +
 			txq->txq_get_index;
-		struct sk_buff *skb = txq->tx_skb[txq->txq_get_index];
-
-		if (skb) {
-			bytes_compl += skb->len;
-			pkts_compl++;
-		}
 
 		mvneta_txq_inc_get(txq);
 
@@ -1776,9 +1798,12 @@
 			dma_unmap_single(pp->dev->dev.parent,
 					 tx_desc->buf_phys_addr,
 					 tx_desc->data_size, DMA_TO_DEVICE);
-		if (!skb)
+		if (!buf->skb)
 			continue;
-		dev_kfree_skb_any(skb);
+
+		bytes_compl += buf->skb->len;
+		pkts_compl++;
+		dev_kfree_skb_any(buf->skb);
 	}
 
 	netdev_tx_completed_queue(nq, pkts_compl, bytes_compl);
@@ -1965,7 +1990,6 @@
 			/* Check errors only for FIRST descriptor */
 			if (rx_status & MVNETA_RXD_ERR_SUMMARY) {
 				mvneta_rx_error(pp, rx_desc);
-				dev->stats.rx_errors++;
 				/* leave the descriptor untouched */
 				continue;
 			}
@@ -1976,11 +2000,17 @@
 			skb_size = max(rx_copybreak, rx_header_size);
 			rxq->skb = netdev_alloc_skb_ip_align(dev, skb_size);
 			if (unlikely(!rxq->skb)) {
+				struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats);
+
 				netdev_err(dev,
 					   "Can't allocate skb on queue %d\n",
 					   rxq->id);
-				dev->stats.rx_dropped++;
+
 				rxq->skb_alloc_err++;
+
+				u64_stats_update_begin(&stats->syncp);
+				stats->rx_dropped++;
+				u64_stats_update_end(&stats->syncp);
 				continue;
 			}
 			copy_size = min(skb_size, rx_bytes);
@@ -2137,7 +2167,6 @@
 			mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
 					      rx_desc->buf_phys_addr);
 err_drop_frame:
-			dev->stats.rx_errors++;
 			mvneta_rx_error(pp, rx_desc);
 			/* leave the descriptor untouched */
 			continue;
@@ -2225,16 +2254,19 @@
 mvneta_tso_put_hdr(struct sk_buff *skb,
 		   struct mvneta_port *pp, struct mvneta_tx_queue *txq)
 {
-	struct mvneta_tx_desc *tx_desc;
 	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+	struct mvneta_tx_desc *tx_desc;
 
-	txq->tx_skb[txq->txq_put_index] = NULL;
 	tx_desc = mvneta_txq_next_desc_get(txq);
 	tx_desc->data_size = hdr_len;
 	tx_desc->command = mvneta_skb_tx_csum(pp, skb);
 	tx_desc->command |= MVNETA_TXD_F_DESC;
 	tx_desc->buf_phys_addr = txq->tso_hdrs_phys +
 				 txq->txq_put_index * TSO_HEADER_SIZE;
+	buf->type = MVNETA_TYPE_SKB;
+	buf->skb = NULL;
+
 	mvneta_txq_inc_put(txq);
 }
 
@@ -2243,6 +2275,7 @@
 		    struct sk_buff *skb, char *data, int size,
 		    bool last_tcp, bool is_last)
 {
+	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
 	struct mvneta_tx_desc *tx_desc;
 
 	tx_desc = mvneta_txq_next_desc_get(txq);
@@ -2256,7 +2289,8 @@
 	}
 
 	tx_desc->command = 0;
-	txq->tx_skb[txq->txq_put_index] = NULL;
+	buf->type = MVNETA_TYPE_SKB;
+	buf->skb = NULL;
 
 	if (last_tcp) {
 		/* last descriptor in the TCP packet */
@@ -2264,7 +2298,7 @@
 
 		/* last descriptor in SKB */
 		if (is_last)
-			txq->tx_skb[txq->txq_put_index] = skb;
+			buf->skb = skb;
 	}
 	mvneta_txq_inc_put(txq);
 	return 0;
@@ -2349,6 +2383,7 @@
 	int i, nr_frags = skb_shinfo(skb)->nr_frags;
 
 	for (i = 0; i < nr_frags; i++) {
+		struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
 		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 		void *addr = skb_frag_address(frag);
 
@@ -2368,12 +2403,13 @@
 		if (i == nr_frags - 1) {
 			/* Last descriptor */
 			tx_desc->command = MVNETA_TXD_L_DESC | MVNETA_TXD_Z_PAD;
-			txq->tx_skb[txq->txq_put_index] = skb;
+			buf->skb = skb;
 		} else {
 			/* Descriptor in the middle: Not First, Not Last */
 			tx_desc->command = 0;
-			txq->tx_skb[txq->txq_put_index] = NULL;
+			buf->skb = NULL;
 		}
+		buf->type = MVNETA_TYPE_SKB;
 		mvneta_txq_inc_put(txq);
 	}
 
@@ -2401,6 +2437,7 @@
 	struct mvneta_port *pp = netdev_priv(dev);
 	u16 txq_id = skb_get_queue_mapping(skb);
 	struct mvneta_tx_queue *txq = &pp->txqs[txq_id];
+	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
 	struct mvneta_tx_desc *tx_desc;
 	int len = skb->len;
 	int frags = 0;
@@ -2433,16 +2470,17 @@
 		goto out;
 	}
 
+	buf->type = MVNETA_TYPE_SKB;
 	if (frags == 1) {
 		/* First and Last descriptor */
 		tx_cmd |= MVNETA_TXD_FLZ_DESC;
 		tx_desc->command = tx_cmd;
-		txq->tx_skb[txq->txq_put_index] = skb;
+		buf->skb = skb;
 		mvneta_txq_inc_put(txq);
 	} else {
 		/* First but not Last */
 		tx_cmd |= MVNETA_TXD_F_DESC;
-		txq->tx_skb[txq->txq_put_index] = NULL;
+		buf->skb = NULL;
 		mvneta_txq_inc_put(txq);
 		tx_desc->command = tx_cmd;
 		/* Continue with other skb fragments */
@@ -2789,11 +2827,10 @@
 	/* For the case where the last mvneta_poll did not process all
 	 * RX packets
 	 */
-	rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
-
 	cause_rx_tx |= pp->neta_armada3700 ? pp->cause_rx_tx :
 		port->cause_rx_tx;
 
+	rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
 	if (rx_queue) {
 		rx_queue = rx_queue - 1;
 		if (pp->bm_priv)
@@ -2989,9 +3026,8 @@
 
 	txq->last_desc = txq->size - 1;
 
-	txq->tx_skb = kmalloc_array(txq->size, sizeof(*txq->tx_skb),
-				    GFP_KERNEL);
-	if (!txq->tx_skb) {
+	txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL);
+	if (!txq->buf) {
 		dma_free_coherent(pp->dev->dev.parent,
 				  txq->size * MVNETA_DESC_ALIGNED_SIZE,
 				  txq->descs, txq->descs_phys);
@@ -3003,7 +3039,7 @@
 					   txq->size * TSO_HEADER_SIZE,
 					   &txq->tso_hdrs_phys, GFP_KERNEL);
 	if (!txq->tso_hdrs) {
-		kfree(txq->tx_skb);
+		kfree(txq->buf);
 		dma_free_coherent(pp->dev->dev.parent,
 				  txq->size * MVNETA_DESC_ALIGNED_SIZE,
 				  txq->descs, txq->descs_phys);
@@ -3011,7 +3047,9 @@
 	}
 
 	/* Setup XPS mapping */
-	if (txq_number > 1)
+	if (pp->neta_armada3700)
+		cpu = 0;
+	else if (txq_number > 1)
 		cpu = txq->id % num_present_cpus();
 	else
 		cpu = pp->rxq_def % num_present_cpus();
@@ -3056,7 +3094,7 @@
 {
 	struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id);
 
-	kfree(txq->tx_skb);
+	kfree(txq->buf);
 
 	if (txq->tso_hdrs)
 		dma_free_coherent(pp->dev->dev.parent,
@@ -3150,26 +3188,60 @@
 	return 0;
 }
 
-static int mvneta_comphy_init(struct mvneta_port *pp)
+static int mvneta_comphy_init(struct mvneta_port *pp, phy_interface_t interface)
 {
 	int ret;
 
-	if (!pp->comphy)
-		return 0;
-
-	ret = phy_set_mode_ext(pp->comphy, PHY_MODE_ETHERNET,
-			       pp->phy_interface);
+	ret = phy_set_mode_ext(pp->comphy, PHY_MODE_ETHERNET, interface);
 	if (ret)
 		return ret;
 
 	return phy_power_on(pp->comphy);
 }
 
+static int mvneta_config_interface(struct mvneta_port *pp,
+				   phy_interface_t interface)
+{
+	int ret = 0;
+
+	if (pp->comphy) {
+		if (interface == PHY_INTERFACE_MODE_SGMII ||
+		    interface == PHY_INTERFACE_MODE_1000BASEX ||
+		    interface == PHY_INTERFACE_MODE_2500BASEX) {
+			ret = mvneta_comphy_init(pp, interface);
+		}
+	} else {
+		switch (interface) {
+		case PHY_INTERFACE_MODE_QSGMII:
+			mvreg_write(pp, MVNETA_SERDES_CFG,
+				    MVNETA_QSGMII_SERDES_PROTO);
+			break;
+
+		case PHY_INTERFACE_MODE_SGMII:
+		case PHY_INTERFACE_MODE_1000BASEX:
+			mvreg_write(pp, MVNETA_SERDES_CFG,
+				    MVNETA_SGMII_SERDES_PROTO);
+			break;
+
+		case PHY_INTERFACE_MODE_2500BASEX:
+			mvreg_write(pp, MVNETA_SERDES_CFG,
+				    MVNETA_HSGMII_SERDES_PROTO);
+			break;
+		default:
+			break;
+		}
+	}
+
+	pp->phy_interface = interface;
+
+	return ret;
+}
+
 static void mvneta_start_dev(struct mvneta_port *pp)
 {
 	int cpu;
 
-	WARN_ON(mvneta_comphy_init(pp));
+	WARN_ON(mvneta_config_interface(pp, pp->phy_interface));
 
 	mvneta_max_rx_size_set(pp, pp->pkt_size);
 	mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
@@ -3544,17 +3616,13 @@
 	/* When at 2.5G, the link partner can send frames with shortened
 	 * preambles.
 	 */
-	if (state->speed == SPEED_2500)
+	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
 		new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
 
-	if (pp->comphy && pp->phy_interface != state->interface &&
-	    (state->interface == PHY_INTERFACE_MODE_SGMII ||
-	     state->interface == PHY_INTERFACE_MODE_1000BASEX ||
-	     state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
-		pp->phy_interface = state->interface;
-
-		WARN_ON(phy_power_off(pp->comphy));
-		WARN_ON(mvneta_comphy_init(pp));
+	if (pp->phy_interface != state->interface) {
+		if (pp->comphy)
+			WARN_ON(phy_power_off(pp->comphy));
+		WARN_ON(mvneta_config_interface(pp, state->interface));
 	}
 
 	if (new_ctrl0 != gmac_ctrl0)
@@ -3669,7 +3737,7 @@
 	/* Use the cpu associated to the rxq when it is online, in all
 	 * the other cases, use the cpu 0 which can't be offline.
 	 */
-	if (cpu_online(pp->rxq_def))
+	if (pp->rxq_def < nr_cpu_ids && cpu_online(pp->rxq_def))
 		elected_cpu = pp->rxq_def;
 
 	max_cpu = num_present_cpus();
@@ -3694,7 +3762,7 @@
 		 */
 		if (txq_number == 1)
 			txq_map = (cpu == elected_cpu) ?
-				MVNETA_CPU_TXQ_ACCESS(1) : 0;
+				MVNETA_CPU_TXQ_ACCESS(0) : 0;
 		else
 			txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
 				MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
@@ -3718,6 +3786,11 @@
 						  node_online);
 	struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
+	/* Armada 3700's per-cpu interrupt for mvneta is broken, all interrupts
+	 * are routed to CPU 0, so we don't need all the cpu-hotplug support
+	 */
+	if (pp->neta_armada3700)
+		return 0;
 
 	spin_lock(&pp->lock);
 	/*
@@ -4455,12 +4528,10 @@
 	/* MAC Cause register should be cleared */
 	mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
 
-	if (phy_mode == PHY_INTERFACE_MODE_QSGMII)
-		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_QSGMII_SERDES_PROTO);
-	else if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
-		 phy_interface_mode_is_8023z(phy_mode))
-		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
-	else if (!phy_interface_mode_is_rgmii(phy_mode))
+	if (phy_mode != PHY_INTERFACE_MODE_QSGMII &&
+	    phy_mode != PHY_INTERFACE_MODE_SGMII &&
+	    !phy_interface_mode_is_8023z(phy_mode) &&
+	    !phy_interface_mode_is_rgmii(phy_mode))
 		return -EINVAL;
 
 	return 0;
@@ -4647,7 +4718,7 @@
 	if (err < 0)
 		goto err_netdev;
 
-	err = mvneta_port_power_up(pp, phy_mode);
+	err = mvneta_port_power_up(pp, pp->phy_interface);
 	if (err < 0) {
 		dev_err(&pdev->dev, "can't power up port\n");
 		goto err_netdev;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -1202,5 +1202,6 @@
 void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name);
 
 void mvpp2_dbgfs_cleanup(struct mvpp2 *priv);
+void mvpp2_dbgfs_exit(void);
 
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
@@ -1070,7 +1070,7 @@
 		    (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS));
 
 	val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG);
-	val |= MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);
+	val &= ~MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);
 	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val);
 }
 
@@ -1422,6 +1422,9 @@
 	struct mvpp2_ethtool_fs *efs;
 	int ret;
 
+	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
+		return -EINVAL;
+
 	efs = port->rfs_rules[info->fs.location];
 	if (!efs)
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
@@ -691,6 +691,13 @@
 	return 0;
 }
 
+static struct dentry *mvpp2_root;
+
+void mvpp2_dbgfs_exit(void)
+{
+	debugfs_remove(mvpp2_root);
+}
+
 void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
 {
 	debugfs_remove_recursive(priv->dbgfs_dir);
@@ -700,10 +707,9 @@
 
 void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
 {
-	struct dentry *mvpp2_dir, *mvpp2_root;
+	struct dentry *mvpp2_dir;
 	int ret, i;
 
-	mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
 	if (!mvpp2_root)
 		mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -1073,7 +1073,7 @@
 	u32 val;
 
 	/* If the thread isn't used, don't do anything */
-	if (smp_processor_id() > port->priv->nthreads)
+	if (smp_processor_id() >= port->priv->nthreads)
 		return;
 
 	val = MVPP2_CAUSE_MISC_SUM_MASK |
@@ -1129,7 +1129,7 @@
 
 	regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
 	if (port->gop_id == 2)
-		val |= GENCONF_CTRL0_PORT0_RGMII | GENCONF_CTRL0_PORT1_RGMII;
+		val |= GENCONF_CTRL0_PORT0_RGMII;
 	else if (port->gop_id == 3)
 		val |= GENCONF_CTRL0_PORT1_RGMII_MII;
 	regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
@@ -1541,7 +1541,7 @@
 	for (q = 0; q < port->ntxqs; q++)
 		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++)
 			*pstats++ += mvpp2_read_index(port->priv,
-						      MVPP22_CTRS_TX_CTR(port->id, i),
+						      MVPP22_CTRS_TX_CTR(port->id, q),
 						      mvpp2_ethtool_txq_regs[i].offset);
 
 	/* Rxqs are numbered from 0 from the user standpoint, but not from the
@@ -1550,7 +1550,7 @@
 	for (q = 0; q < port->nrxqs; q++)
 		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++)
 			*pstats++ += mvpp2_read_index(port->priv,
-						      port->first_rxq + i,
+						      port->first_rxq + q,
 						      mvpp2_ethtool_rxq_regs[i].offset);
 }
 
@@ -2078,7 +2078,7 @@
 	int queue;
 
 	/* If the thread isn't used, don't do anything */
-	if (smp_processor_id() > port->priv->nthreads)
+	if (smp_processor_id() >= port->priv->nthreads)
 		return;
 
 	for (queue = 0; queue < port->ntxqs; queue++) {
@@ -2161,17 +2161,18 @@
 static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port,
 				   struct mvpp2_tx_queue *txq)
 {
-	unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+	unsigned int thread;
 	u32 val;
 
 	if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK)
 		txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK;
 
 	val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET);
-	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
-	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val);
-
-	put_cpu();
+	/* PKT-coalescing registers are per-queue + per-thread */
+	for (thread = 0; thread < MVPP2_MAX_THREADS; thread++) {
+		mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
+		mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val);
+	}
 }
 
 static u32 mvpp2_usec_to_cycles(u32 usec, unsigned long clk_hz)
@@ -3674,7 +3675,7 @@
 		valid = true;
 	}
 
-	if (priv->hw_version == MVPP22 && port->link_irq && !port->phylink) {
+	if (priv->hw_version == MVPP22 && port->link_irq) {
 		err = request_irq(port->link_irq, mvpp2_link_status_isr, 0,
 				  dev->name, port);
 		if (err) {
@@ -3696,6 +3697,7 @@
 	if (!valid) {
 		netdev_err(port->dev,
 			   "invalid configuration: no dt or link IRQ");
+		err = -ENOENT;
 		goto err_free_irq;
 	}
 
@@ -4231,6 +4233,11 @@
 		break;
 	case ETHTOOL_GRXCLSRLALL:
 		for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
+			if (loc == info->rule_cnt) {
+				ret = -EMSGSIZE;
+				break;
+			}
+
 			if (port->rfs_rules[i])
 				rules[loc++] = i;
 		}
@@ -4319,6 +4326,8 @@
 
 	if (!mvpp22_rss_is_supported())
 		return -EOPNOTSUPP;
+	if (rss_context >= MVPP22_N_RSS_TABLES)
+		return -EINVAL;
 
 	if (hfunc)
 		*hfunc = ETH_RSS_HASH_CRC32;
@@ -4742,12 +4751,16 @@
 	eth_hw_addr_random(dev);
 }
 
+static struct mvpp2_port *mvpp2_phylink_to_port(struct phylink_config *config)
+{
+	return container_of(config, struct mvpp2_port, phylink_config);
+}
+
 static void mvpp2_phylink_validate(struct phylink_config *config,
 				   unsigned long *supported,
 				   struct phylink_link_state *state)
 {
-	struct mvpp2_port *port = container_of(config, struct mvpp2_port,
-					       phylink_config);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 
 	/* Invalid combinations */
@@ -4770,8 +4783,6 @@
 
 	phylink_set(mask, Autoneg);
 	phylink_set_port_modes(mask);
-	phylink_set(mask, Pause);
-	phylink_set(mask, Asym_Pause);
 
 	switch (state->interface) {
 	case PHY_INTERFACE_MODE_10GKR:
@@ -4874,8 +4885,7 @@
 static int mvpp2_phylink_mac_link_state(struct phylink_config *config,
 					struct phylink_link_state *state)
 {
-	struct mvpp2_port *port = container_of(config, struct mvpp2_port,
-					       phylink_config);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 
 	if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
 		u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
@@ -4893,8 +4903,7 @@
 
 static void mvpp2_mac_an_restart(struct phylink_config *config)
 {
-	struct mvpp2_port *port = container_of(config, struct mvpp2_port,
-					       phylink_config);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 	u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
 
 	writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
@@ -5082,13 +5091,12 @@
 static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
 			     const struct phylink_link_state *state)
 {
-	struct net_device *dev = to_net_dev(config->dev);
-	struct mvpp2_port *port = netdev_priv(dev);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 	bool change_interface = port->phy_interface != state->interface;
 
 	/* Check for invalid configuration */
 	if (mvpp2_is_xlg(state->interface) && port->gop_id != 0) {
-		netdev_err(dev, "Invalid mode on %s\n", dev->name);
+		netdev_err(port->dev, "Invalid mode on %s\n", port->dev->name);
 		return;
 	}
 
@@ -5125,8 +5133,7 @@
 static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
 			      phy_interface_t interface, struct phy_device *phy)
 {
-	struct net_device *dev = to_net_dev(config->dev);
-	struct mvpp2_port *port = netdev_priv(dev);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 	u32 val;
 
 	if (!phylink_autoneg_inband(mode)) {
@@ -5147,14 +5154,13 @@
 
 	mvpp2_egress_enable(port);
 	mvpp2_ingress_enable(port);
-	netif_tx_wake_all_queues(dev);
+	netif_tx_wake_all_queues(port->dev);
 }
 
 static void mvpp2_mac_link_down(struct phylink_config *config,
 				unsigned int mode, phy_interface_t interface)
 {
-	struct net_device *dev = to_net_dev(config->dev);
-	struct mvpp2_port *port = netdev_priv(dev);
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
 	u32 val;
 
 	if (!phylink_autoneg_inband(mode)) {
@@ -5171,7 +5177,7 @@
 		}
 	}
 
-	netif_tx_stop_all_queues(dev);
+	netif_tx_stop_all_queues(port->dev);
 	mvpp2_egress_disable(port);
 	mvpp2_ingress_disable(port);
 
@@ -5727,6 +5733,10 @@
 			return PTR_ERR(priv->lms_base);
 	} else {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!res) {
+			dev_err(&pdev->dev, "Invalid resource\n");
+			return -EINVAL;
+		}
 		if (has_acpi_companion(&pdev->dev)) {
 			/* In case the MDIO memory region is declared in
 			 * the ACPI, it can already appear as 'in-use'
@@ -5768,7 +5778,7 @@
 
 	shared = num_present_cpus() - priv->nthreads;
 	if (shared > 0)
-		bitmap_fill(&priv->lock_map,
+		bitmap_set(&priv->lock_map, 0,
 			    min_t(int, shared, MVPP2_MAX_THREADS));
 
 	for (i = 0; i < MVPP2_MAX_THREADS; i++) {
@@ -5897,6 +5907,8 @@
 	return 0;
 
 err_port_probe:
+	fwnode_handle_put(port_fwnode);
+
 	i = 0;
 	fwnode_for_each_available_child_node(fwnode, port_fwnode) {
 		if (priv->port_list[i])
@@ -5923,8 +5935,8 @@
 {
 	struct mvpp2 *priv = platform_get_drvdata(pdev);
 	struct fwnode_handle *fwnode = pdev->dev.fwnode;
+	int i = 0, poolnum = MVPP2_BM_POOLS_NUM;
 	struct fwnode_handle *port_fwnode;
-	int i = 0;
 
 	mvpp2_dbgfs_cleanup(priv);
 
@@ -5938,7 +5950,10 @@
 
 	destroy_workqueue(priv->stats_queue);
 
-	for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
+	if (priv->percpu_pools)
+		poolnum = mvpp2_get_nrxqs(priv) * 2;
+
+	for (i = 0; i < poolnum; i++) {
 		struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
 
 		mvpp2_bm_pool_destroy(&pdev->dev, priv, bm_pool);
@@ -5994,7 +6009,18 @@
 	},
 };
 
-module_platform_driver(mvpp2_driver);
+static int __init mvpp2_driver_init(void)
+{
+	return platform_driver_register(&mvpp2_driver);
+}
+module_init(mvpp2_driver_init);
+
+static void __exit mvpp2_driver_exit(void)
+{
+	platform_driver_unregister(&mvpp2_driver);
+	mvpp2_dbgfs_exit();
+}
+module_exit(mvpp2_driver_exit);
 
 MODULE_DESCRIPTION("Marvell PPv2 Ethernet Driver - www.marvell.com");
 MODULE_AUTHOR("Marcin Wojtas <mw@semihalf.com>");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
@@ -29,16 +29,16 @@
 	/* Clear entry invalidation bit */
 	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
 
-	/* Write tcam index - indirect access */
-	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
-	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
-		mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
-
 	/* Write sram index - indirect access */
 	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
 	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
 		mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
 
+	/* Write tcam index - indirect access */
+	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
+	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
+		mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
+
 	return 0;
 }
 
@@ -405,6 +405,38 @@
 	return -EINVAL;
 }
 
+/* Drop flow control pause frames */
+static void mvpp2_prs_drop_fc(struct mvpp2 *priv)
+{
+	unsigned char da[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
+	struct mvpp2_prs_entry pe;
+	unsigned int len;
+
+	memset(&pe, 0, sizeof(pe));
+
+	/* For all ports - drop flow control frames */
+	pe.index = MVPP2_PE_FC_DROP;
+	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
+
+	/* Set match on DA */
+	len = ETH_ALEN;
+	while (len--)
+		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
+
+	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
+				 MVPP2_PRS_RI_DROP_MASK);
+
+	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
+
+	/* Mask all ports */
+	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
+
+	/* Update shadow table and hw entry */
+	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
+	mvpp2_prs_hw_write(priv, &pe);
+}
+
 /* Enable/disable dropping all mac da's */
 static void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add)
 {
@@ -1162,6 +1194,7 @@
 	mvpp2_prs_hw_write(priv, &pe);
 
 	/* Create dummy entries for drop all and promiscuous modes */
+	mvpp2_prs_drop_fc(priv);
 	mvpp2_prs_mac_drop_all_set(priv, 0, false);
 	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
 	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
@@ -1647,8 +1680,9 @@
 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
 				 MVPP2_PRS_RI_L3_PROTO_MASK);
-	/* Skip eth_type + 4 bytes of IPv6 header */
-	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
+	/* Jump to DIP of IPV6 header */
+	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
+				 MVPP2_MAX_L3_ADDR_SIZE,
 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
 	/* Set L3 offset */
 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.h
@@ -129,7 +129,7 @@
 #define MVPP2_PE_VID_EDSA_FLTR_DEFAULT	(MVPP2_PRS_TCAM_SRAM_SIZE - 7)
 #define MVPP2_PE_VLAN_DBL		(MVPP2_PRS_TCAM_SRAM_SIZE - 6)
 #define MVPP2_PE_VLAN_NONE		(MVPP2_PRS_TCAM_SRAM_SIZE - 5)
-/* reserved */
+#define MVPP2_PE_FC_DROP		(MVPP2_PRS_TCAM_SRAM_SIZE - 4)
 #define MVPP2_PE_MAC_MC_PROMISCUOUS	(MVPP2_PRS_TCAM_SRAM_SIZE - 3)
 #define MVPP2_PE_MAC_UC_PROMISCUOUS	(MVPP2_PRS_TCAM_SRAM_SIZE - 2)
 #define MVPP2_PE_MAC_NON_PROMISCUOUS	(MVPP2_PRS_TCAM_SRAM_SIZE - 1)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -725,8 +725,10 @@
 		if (!lmac)
 			return -ENOMEM;
 		lmac->name = kcalloc(1, sizeof("cgx_fwi_xxx_yyy"), GFP_KERNEL);
-		if (!lmac->name)
-			return -ENOMEM;
+		if (!lmac->name) {
+			err = -ENOMEM;
+			goto err_lmac_free;
+		}
 		sprintf(lmac->name, "cgx_fwi_%d_%d", cgx->cgx_id, i);
 		lmac->lmac_id = i;
 		lmac->cgx = cgx;
@@ -737,7 +739,7 @@
 						 CGX_LMAC_FWI + i * 9),
 				   cgx_fwi_event_handler, 0, lmac->name, lmac);
 		if (err)
-			return err;
+			goto err_irq;
 
 		/* Enable interrupt */
 		cgx_write(cgx, lmac->lmac_id, CGXX_CMRX_INT_ENA_W1S,
@@ -748,6 +750,12 @@
 	}
 
 	return cgx_lmac_verify_fwi_version(cgx);
+
+err_irq:
+	kfree(lmac->name);
+err_lmac_free:
+	kfree(lmac);
+	return err;
 }
 
 static int cgx_lmac_exit(struct cgx *cgx)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/octeontx2/af/common.h
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -43,7 +43,7 @@
 	void            *base;
 	dma_addr_t	iova;
 	int		alloc_sz;
-	u8		entry_sz;
+	u16		entry_sz;
 	u8		align;
 	u32		qsize;
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -1980,8 +1980,10 @@
 		    INTR_MASK(rvu->hw->total_pfs) & ~1ULL);
 
 	for (irq = 0; irq < rvu->num_vec; irq++) {
-		if (rvu->irq_allocated[irq])
+		if (rvu->irq_allocated[irq]) {
 			free_irq(pci_irq_vector(rvu->pdev, irq), rvu);
+			rvu->irq_allocated[irq] = false;
+		}
 	}
 
 	pci_free_irq_vectors(rvu->pdev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -2430,9 +2430,10 @@
 	if (link < 0)
 		return NIX_AF_ERR_RX_LINK_INVALID;
 
-	nix_find_link_frs(rvu, req, pcifunc);
 
 linkcfg:
+	nix_find_link_frs(rvu, req, pcifunc);
+
 	cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_LINKX_CFG(link));
 	cfg = (cfg & ~(0xFFFFULL << 16)) | ((u64)req->maxlen << 16);
 	if (req->update_minlen)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -1967,10 +1967,10 @@
 		index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
 		if (index >= mcam->bmap_entries)
 			break;
+		entry = index + 1;
 		if (mcam->entry2cntr_map[index] != req->cntr)
 			continue;
 
-		entry = index + 1;
 		npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
 					      index, req->cntr);
 	}
@@ -2013,10 +2013,11 @@
 		index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
 		if (index >= mcam->bmap_entries)
 			break;
+		entry = index + 1;
+
 		if (mcam->entry2cntr_map[index] != req->cntr)
 			continue;
 
-		entry = index + 1;
 		npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
 					      index, req->cntr);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/pxa168_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -1554,8 +1554,8 @@
 
 	mdiobus_unregister(pep->smi_bus);
 	mdiobus_free(pep->smi_bus);
-	unregister_netdev(dev);
 	cancel_work_sync(&pep->tx_timeout_task);
+	unregister_netdev(dev);
 	free_netdev(dev);
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/sky2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/sky2.c
@@ -203,7 +203,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;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/marvell/sky2.h
+++ linux-ein-5.4.0/drivers/net/ethernet/marvell/sky2.h
@@ -2201,7 +2201,7 @@
 	struct sk_buff	*skb;
 	dma_addr_t	data_addr;
 	DEFINE_DMA_UNMAP_LEN(data_size);
-	dma_addr_t	frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
+	dma_addr_t	frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT ?: 1];
 };
 
 enum flow_control {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -65,6 +65,17 @@
 	return __raw_readl(eth->base + reg);
 }
 
+u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned reg)
+{
+	u32 val;
+
+	val = mtk_r32(eth, reg);
+	val &= ~mask;
+	val |= set;
+	mtk_w32(eth, val, reg);
+	return reg;
+}
+
 static int mtk_mdio_busy_wait(struct mtk_eth *eth)
 {
 	unsigned long t_start = jiffies;
@@ -160,11 +171,21 @@
 	return 0;
 }
 
-static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed)
+static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth,
+				   phy_interface_t interface, int speed)
 {
 	u32 val;
 	int ret;
 
+	if (interface == PHY_INTERFACE_MODE_TRGMII) {
+		mtk_w32(eth, TRGMII_MODE, INTF_MODE);
+		val = 500000000;
+		ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], val);
+		if (ret)
+			dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret);
+		return;
+	}
+
 	val = (speed == SPEED_1000) ?
 		INTF_MODE_RGMII_1000 : INTF_MODE_RGMII_10_100;
 	mtk_w32(eth, val, INTF_MODE);
@@ -193,8 +214,8 @@
 	struct mtk_mac *mac = container_of(config, struct mtk_mac,
 					   phylink_config);
 	struct mtk_eth *eth = mac->hw;
-	u32 mcr_cur, mcr_new, sid;
-	int val, ge_mode, err;
+	u32 mcr_cur, mcr_new, sid, i;
+	int val, ge_mode, err = 0;
 
 	/* MT76x8 has no hardware settings between for the MAC */
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
@@ -251,10 +272,20 @@
 							      state->interface))
 					goto err_phy;
 			} else {
-				if (state->interface !=
-				    PHY_INTERFACE_MODE_TRGMII)
-					mtk_gmac0_rgmii_adjust(mac->hw,
-							       state->speed);
+				mtk_gmac0_rgmii_adjust(mac->hw,
+						       state->interface,
+						       state->speed);
+
+				/* mt7623_pad_clk_setup */
+				for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+					mtk_w32(mac->hw,
+						TD_DM_DRVP(8) | TD_DM_DRVN(8),
+						TRGMII_TD_ODT(i));
+
+				/* Assert/release MT7623 RXC reset */
+				mtk_m32(mac->hw, 0, RXC_RST | RXC_DQSISEL,
+					TRGMII_RCK_CTRL);
+				mtk_m32(mac->hw, RXC_RST, 0, TRGMII_RCK_CTRL);
 			}
 		}
 
@@ -644,32 +675,53 @@
 void mtk_stats_update_mac(struct mtk_mac *mac)
 {
 	struct mtk_hw_stats *hw_stats = mac->hw_stats;
-	unsigned int base = MTK_GDM1_TX_GBCNT;
-	u64 stats;
-
-	base += hw_stats->reg_offset;
+	struct mtk_eth *eth = mac->hw;
 
 	u64_stats_update_begin(&hw_stats->syncp);
 
-	hw_stats->rx_bytes += mtk_r32(mac->hw, base);
-	stats =  mtk_r32(mac->hw, base + 0x04);
-	if (stats)
-		hw_stats->rx_bytes += (stats << 32);
-	hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08);
-	hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10);
-	hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14);
-	hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18);
-	hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c);
-	hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20);
-	hw_stats->rx_flow_control_packets +=
-					mtk_r32(mac->hw, base + 0x24);
-	hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28);
-	hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c);
-	hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30);
-	stats =  mtk_r32(mac->hw, base + 0x34);
-	if (stats)
-		hw_stats->tx_bytes += (stats << 32);
-	hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38);
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		hw_stats->tx_packets += mtk_r32(mac->hw, MT7628_SDM_TPCNT);
+		hw_stats->tx_bytes += mtk_r32(mac->hw, MT7628_SDM_TBCNT);
+		hw_stats->rx_packets += mtk_r32(mac->hw, MT7628_SDM_RPCNT);
+		hw_stats->rx_bytes += mtk_r32(mac->hw, MT7628_SDM_RBCNT);
+		hw_stats->rx_checksum_errors +=
+			mtk_r32(mac->hw, MT7628_SDM_CS_ERR);
+	} else {
+		unsigned int offs = hw_stats->reg_offset;
+		u64 stats;
+
+		hw_stats->rx_bytes += mtk_r32(mac->hw,
+					      MTK_GDM1_RX_GBCNT_L + offs);
+		stats = mtk_r32(mac->hw, MTK_GDM1_RX_GBCNT_H + offs);
+		if (stats)
+			hw_stats->rx_bytes += (stats << 32);
+		hw_stats->rx_packets +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_GPCNT + offs);
+		hw_stats->rx_overflow +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_OERCNT + offs);
+		hw_stats->rx_fcs_errors +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_FERCNT + offs);
+		hw_stats->rx_short_errors +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_SERCNT + offs);
+		hw_stats->rx_long_errors +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_LENCNT + offs);
+		hw_stats->rx_checksum_errors +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_CERCNT + offs);
+		hw_stats->rx_flow_control_packets +=
+			mtk_r32(mac->hw, MTK_GDM1_RX_FCCNT + offs);
+		hw_stats->tx_skip +=
+			mtk_r32(mac->hw, MTK_GDM1_TX_SKIPCNT + offs);
+		hw_stats->tx_collisions +=
+			mtk_r32(mac->hw, MTK_GDM1_TX_COLCNT + offs);
+		hw_stats->tx_bytes +=
+			mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_L + offs);
+		stats =  mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_H + offs);
+		if (stats)
+			hw_stats->tx_bytes += (stats << 32);
+		hw_stats->tx_packets +=
+			mtk_r32(mac->hw, MTK_GDM1_TX_GPCNT + offs);
+	}
+
 	u64_stats_update_end(&hw_stats->syncp);
 }
 
@@ -750,6 +802,17 @@
 	rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
 }
 
+static void *mtk_max_lro_buf_alloc(gfp_t gfp_mask)
+{
+	unsigned int size = mtk_max_frag_size(MTK_MAX_LRO_RX_LENGTH);
+	unsigned long data;
+
+	data = __get_free_pages(gfp_mask | __GFP_COMP | __GFP_NOWARN,
+				get_order(size));
+
+	return (void *)data;
+}
+
 /* the qdma core needs scratch memory to be setup */
 static int mtk_init_fq_dma(struct mtk_eth *eth)
 {
@@ -1247,7 +1310,10 @@
 			goto release_desc;
 
 		/* alloc new buffer */
-		new_data = napi_alloc_frag(ring->frag_size);
+		if (ring->frag_size <= PAGE_SIZE)
+			new_data = napi_alloc_frag(ring->frag_size);
+		else
+			new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC);
 		if (unlikely(!new_data)) {
 			netdev->stats.rx_dropped++;
 			goto release_desc;
@@ -1284,7 +1350,7 @@
 		skb->protocol = eth_type_trans(skb, netdev);
 
 		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
-		    RX_DMA_VID(trxd.rxd3))
+		    (trxd.rxd2 & RX_DMA_VTAG))
 			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
 					       RX_DMA_VID(trxd.rxd3));
 		skb_record_rx_queue(skb, 0);
@@ -1644,7 +1710,10 @@
 		return -ENOMEM;
 
 	for (i = 0; i < rx_dma_size; i++) {
-		ring->data[i] = netdev_alloc_frag(ring->frag_size);
+		if (ring->frag_size <= PAGE_SIZE)
+			ring->data[i] = netdev_alloc_frag(ring->frag_size);
+		else
+			ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL);
 		if (!ring->data[i])
 			return -ENOMEM;
 	}
@@ -1910,6 +1979,9 @@
 	struct ethtool_rx_flow_spec *fsp =
 		(struct ethtool_rx_flow_spec *)&cmd->fs;
 
+	if (fsp->location >= ARRAY_SIZE(mac->hwlro_ip))
+		return -EINVAL;
+
 	/* only tcp dst ipv4 is meaningful, others are meaningless */
 	fsp->flow_type = TCP_V4_FLOW;
 	fsp->h_u.tcp_ip4_spec.ip4dst = ntohl(mac->hwlro_ip[fsp->location]);
@@ -1936,6 +2008,9 @@
 	int i;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (cnt == cmd->rule_cnt)
+			return -EMSGSIZE;
+
 		if (mac->hwlro_ip[i]) {
 			rule_locs[cnt] = i;
 			cnt++;
@@ -2847,6 +2922,8 @@
 	eth->netdev[id]->irq = eth->irq[0];
 	eth->netdev[id]->dev.of_node = np;
 
+	eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
+
 	return 0;
 
 free_netdev:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -264,8 +264,21 @@
 /* QDMA FQ Free Page Buffer Length Register */
 #define MTK_QDMA_FQ_BLEN	0x1B2C
 
-/* GMA1 Received Good Byte Count Register */
-#define MTK_GDM1_TX_GBCNT	0x2400
+/* GMA1 counter / statics register */
+#define MTK_GDM1_RX_GBCNT_L	0x2400
+#define MTK_GDM1_RX_GBCNT_H	0x2404
+#define MTK_GDM1_RX_GPCNT	0x2408
+#define MTK_GDM1_RX_OERCNT	0x2410
+#define MTK_GDM1_RX_FERCNT	0x2414
+#define MTK_GDM1_RX_SERCNT	0x2418
+#define MTK_GDM1_RX_LENCNT	0x241c
+#define MTK_GDM1_RX_CERCNT	0x2420
+#define MTK_GDM1_RX_FCCNT	0x2424
+#define MTK_GDM1_TX_SKIPCNT	0x2428
+#define MTK_GDM1_TX_COLCNT	0x242c
+#define MTK_GDM1_TX_GBCNT_L	0x2430
+#define MTK_GDM1_TX_GBCNT_H	0x2434
+#define MTK_GDM1_TX_GPCNT	0x2438
 #define MTK_STAT_OFFSET		0x40
 
 /* QDMA descriptor txd4 */
@@ -293,6 +306,7 @@
 #define RX_DMA_LSO		BIT(30)
 #define RX_DMA_PLEN0(_x)	(((_x) & 0x3fff) << 16)
 #define RX_DMA_GET_PLEN0(_x)	(((_x) >> 16) & 0x3fff)
+#define RX_DMA_VTAG		BIT(15)
 
 /* QDMA descriptor rxd3 */
 #define RX_DMA_VID(_x)		((_x) & 0xfff)
@@ -350,10 +364,13 @@
 #define DQSI0(x)		((x << 0) & GENMASK(6, 0))
 #define DQSI1(x)		((x << 8) & GENMASK(14, 8))
 #define RXCTL_DMWTLAT(x)	((x << 16) & GENMASK(18, 16))
+#define RXC_RST			BIT(31)
 #define RXC_DQSISEL		BIT(30)
 #define RCK_CTRL_RGMII_1000	(RXC_DQSISEL | RXCTL_DMWTLAT(2) | DQSI1(16))
 #define RCK_CTRL_RGMII_10_100	RXCTL_DMWTLAT(2)
 
+#define NUM_TRGMII_CTRL		5
+
 /* TRGMII RXC control register */
 #define TRGMII_TCK_CTRL		0x10340
 #define TXCTL_DMWTLAT(x)	((x << 16) & GENMASK(18, 16))
@@ -361,6 +378,11 @@
 #define TCK_CTRL_RGMII_1000	TXCTL_DMWTLAT(2)
 #define TCK_CTRL_RGMII_10_100	(TXC_INV | TXCTL_DMWTLAT(2))
 
+/* TRGMII TX Drive Strength */
+#define TRGMII_TD_ODT(i)	(0x10354 + 8 * (i))
+#define  TD_DM_DRVP(x)		((x) & 0xf)
+#define  TD_DM_DRVN(x)		(((x) & 0xf) << 4)
+
 /* TRGMII Interface mode register */
 #define INTF_MODE		0x10390
 #define TRGMII_INTF_DIS		BIT(0)
@@ -467,6 +489,13 @@
 #define MT7628_SDM_MAC_ADRL	(MT7628_SDM_OFFSET + 0x0c)
 #define MT7628_SDM_MAC_ADRH	(MT7628_SDM_OFFSET + 0x10)
 
+/* Counter / stat register */
+#define MT7628_SDM_TPCNT	(MT7628_SDM_OFFSET + 0x100)
+#define MT7628_SDM_TBCNT	(MT7628_SDM_OFFSET + 0x104)
+#define MT7628_SDM_RPCNT	(MT7628_SDM_OFFSET + 0x108)
+#define MT7628_SDM_RBCNT	(MT7628_SDM_OFFSET + 0x10c)
+#define MT7628_SDM_CS_ERR	(MT7628_SDM_OFFSET + 0x110)
+
 struct mtk_rx_dma {
 	unsigned int rxd1;
 	unsigned int rxd2;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -26,6 +26,7 @@
 			break;
 
 		ss->regmap[i] = syscon_node_to_regmap(np);
+		of_node_put(np);
 		if (IS_ERR(ss->regmap[i]))
 			return PTR_ERR(ss->regmap[i]);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ linux-ein-5.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, t;
 	int err = 0;
@@ -663,7 +663,7 @@
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_T, SPEED_1000,
 				       ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_CX_SGMII, SPEED_1000,
-				       ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
+				       ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_KX, SPEED_1000,
 				       ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_T, SPEED_10000,
@@ -675,9 +675,9 @@
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_KR, SPEED_10000,
 				       ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_CR, SPEED_10000,
-				       ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
+				       ETHTOOL_LINK_MODE_10000baseCR_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_SR, SPEED_10000,
-				       ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
+				       ETHTOOL_LINK_MODE_10000baseSR_Full_BIT);
 	MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_20GBASE_KR2, SPEED_20000,
 				       ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
 				       ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT);
@@ -2011,8 +2011,6 @@
 	return ret;
 }
 
-#define MLX4_EEPROM_PAGE_LEN 256
-
 static int mlx4_en_get_module_info(struct net_device *dev,
 				   struct ethtool_modinfo *modinfo)
 {
@@ -2047,7 +2045,7 @@
 		break;
 	case MLX4_MODULE_ID_SFP:
 		modinfo->type = ETH_MODULE_SFF_8472;
-		modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
 		break;
 	default:
 		return -EINVAL;
@@ -2085,7 +2083,7 @@
 			en_err(priv,
 			       "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n",
 			       i, offset, ee->len - i, ret);
-			return 0;
+			return ret;
 		}
 
 		i += ret;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -371,6 +371,9 @@
 	int nhoff = skb_network_offset(skb);
 	int ret = 0;
 
+	if (skb->encapsulation)
+		return -EPROTONOSUPPORT;
+
 	if (skb->protocol != htons(ETH_P_IP))
 		return -EPROTONOSUPPORT;
 
@@ -1383,8 +1386,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);
+	}
 }
 
 
@@ -1738,6 +1743,7 @@
 				mlx4_en_deactivate_cq(priv, cq);
 				goto tx_err;
 			}
+			clear_bit(MLX4_EN_TX_RING_STATE_RECOVERING, &tx_ring->state);
 			if (t != TX_XDP) {
 				tx_ring->tx_queue = netdev_get_tx_queue(dev, i);
 				tx_ring->recycle_ring = NULL;
@@ -1834,6 +1840,7 @@
 		local_bh_enable();
 	}
 
+	clear_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state);
 	netif_tx_start_all_queues(dev);
 	netif_device_attach(dev);
 
@@ -2004,7 +2011,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;
 
@@ -2274,9 +2281,14 @@
 				bool carry_xdp_prog)
 {
 	struct bpf_prog *xdp_prog;
-	int i, t;
+	int i, t, ret;
 
-	mlx4_en_copy_priv(tmp, priv, prof);
+	ret = mlx4_en_copy_priv(tmp, priv, prof);
+	if (ret) {
+		en_warn(priv, "%s: mlx4_en_copy_priv() failed, return\n",
+			__func__);
+		return ret;
+	}
 
 	if (mlx4_en_alloc_resources(tmp)) {
 		en_warn(priv,
@@ -2386,7 +2398,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 {
@@ -2395,7 +2407,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);
@@ -2865,7 +2879,8 @@
 		if (err) {
 			en_err(priv, "Failed starting port %d for XDP change\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);
 		}
 	}
 
@@ -3263,7 +3278,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);
@@ -3650,6 +3665,8 @@
 			en_err(priv, "Failed starting port\n");
 	}
 
+	if (!err)
+		err = mlx4_en_moderation_update(priv);
 out:
 	mutex_unlock(&mdev->state_lock);
 	kfree(tmp);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -942,6 +942,9 @@
 	bool clean_complete = true;
 	int done;
 
+	if (!budget)
+		return 0;
+
 	if (priv->tx_ring_num[TX_XDP]) {
 		xdp_tx_cq = priv->tx_cq[TX_XDP][cq->ring];
 		if (xdp_tx_cq->xdp_busy) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -43,6 +43,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/moduleparam.h>
+#include <linux/indirect_call_wrapper.h>
 
 #include "mlx4_en.h"
 
@@ -261,6 +262,10 @@
 	}
 }
 
+INDIRECT_CALLABLE_DECLARE(u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
+						   struct mlx4_en_tx_ring *ring,
+						   int index, u64 timestamp,
+						   int napi_mode));
 
 u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 			 struct mlx4_en_tx_ring *ring,
@@ -329,6 +334,11 @@
 	return tx_info->nr_txbb;
 }
 
+INDIRECT_CALLABLE_DECLARE(u32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv,
+						      struct mlx4_en_tx_ring *ring,
+						      int index, u64 timestamp,
+						      int napi_mode));
+
 u32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv,
 			    struct mlx4_en_tx_ring *ring,
 			    int index, u64 timestamp,
@@ -340,7 +350,7 @@
 		.dma = tx_info->map0_dma,
 	};
 
-	if (!mlx4_en_rx_recycle(ring->recycle_ring, &frame)) {
+	if (!napi_mode || !mlx4_en_rx_recycle(ring->recycle_ring, &frame)) {
 		dma_unmap_page(priv->ddev, tx_info->map0_dma,
 			       PAGE_SIZE, priv->dma_dir);
 		put_page(tx_info->page);
@@ -382,6 +392,35 @@
 	return cnt;
 }
 
+static void mlx4_en_handle_err_cqe(struct mlx4_en_priv *priv, struct mlx4_err_cqe *err_cqe,
+				   u16 cqe_index, struct mlx4_en_tx_ring *ring)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_tx_info *tx_info;
+	struct mlx4_en_tx_desc *tx_desc;
+	u16 wqe_index;
+	int desc_size;
+
+	en_err(priv, "CQE error - cqn 0x%x, ci 0x%x, vendor syndrome: 0x%x syndrome: 0x%x\n",
+	       ring->sp_cqn, cqe_index, err_cqe->vendor_err_syndrome, err_cqe->syndrome);
+	print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, err_cqe, sizeof(*err_cqe),
+		       false);
+
+	wqe_index = be16_to_cpu(err_cqe->wqe_index) & ring->size_mask;
+	tx_info = &ring->tx_info[wqe_index];
+	desc_size = tx_info->nr_txbb << LOG_TXBB_SIZE;
+	en_err(priv, "Related WQE - qpn 0x%x, wqe index 0x%x, wqe size 0x%x\n", ring->qpn,
+	       wqe_index, desc_size);
+	tx_desc = ring->buf + (wqe_index << LOG_TXBB_SIZE);
+	print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, tx_desc, desc_size, false);
+
+	if (test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state))
+		return;
+
+	en_err(priv, "Scheduling port restart\n");
+	queue_work(mdev->workqueue, &priv->restart_task);
+}
+
 bool mlx4_en_process_tx_cq(struct net_device *dev,
 			   struct mlx4_en_cq *cq, int napi_budget)
 {
@@ -428,13 +467,10 @@
 		dma_rmb();
 
 		if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
-			     MLX4_CQE_OPCODE_ERROR)) {
-			struct mlx4_err_cqe *cqe_err = (struct mlx4_err_cqe *)cqe;
-
-			en_err(priv, "CQE error - vendor syndrome: 0x%x syndrome: 0x%x\n",
-			       cqe_err->vendor_err_syndrome,
-			       cqe_err->syndrome);
-		}
+			     MLX4_CQE_OPCODE_ERROR))
+			if (!test_and_set_bit(MLX4_EN_TX_RING_STATE_RECOVERING, &ring->state))
+				mlx4_en_handle_err_cqe(priv, (struct mlx4_err_cqe *)cqe, index,
+						       ring);
 
 		/* Skip over last polled CQE */
 		new_index = be16_to_cpu(cqe->wqe_index) & size_mask;
@@ -449,7 +485,9 @@
 				timestamp = mlx4_en_get_cqe_ts(cqe);
 
 			/* free next descriptor */
-			last_nr_txbb = ring->free_tx_desc(
+			last_nr_txbb = INDIRECT_CALL_2(ring->free_tx_desc,
+						       mlx4_en_free_tx_desc,
+						       mlx4_en_recycle_tx_desc,
 					priv, ring, ring_index,
 					timestamp, napi_budget);
 
@@ -830,6 +868,7 @@
 	struct mlx4_en_tx_desc *tx_desc;
 	struct mlx4_wqe_data_seg *data;
 	struct mlx4_en_tx_info *tx_info;
+	u32 __maybe_unused ring_cons;
 	int tx_ind;
 	int nr_txbb;
 	int desc_size;
@@ -843,7 +882,6 @@
 	bool stop_queue;
 	bool inline_ok;
 	u8 data_offset;
-	u32 ring_cons;
 	bool bf_ok;
 
 	tx_ind = skb_get_queue_mapping(skb);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -823,6 +823,7 @@
 #define QUERY_DEV_CAP_MAD_DEMUX_OFFSET		0xb0
 #define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET	0xa8
 #define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET	0xac
+#define QUERY_DEV_CAP_MAP_CLOCK_TO_USER 0xc1
 #define QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET	0xcc
 #define QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET	0xd0
 #define QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET	0xd2
@@ -841,6 +842,8 @@
 
 	if (mlx4_is_mfunc(dev))
 		disable_unsupported_roce_caps(outbox);
+	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAP_CLOCK_TO_USER);
+	dev_cap->map_clock_to_user = field & 0x80;
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);
 	dev_cap->reserved_qps = 1 << (field & 0xf);
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET);
@@ -1864,8 +1867,8 @@
 #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
@@ -1873,7 +1876,7 @@
 #define  INIT_HCA_DRIVER_VERSION_SZ       0x40
 #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)
@@ -2734,7 +2737,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);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -131,6 +131,7 @@
 	u32 health_buffer_addrs;
 	struct mlx4_port_cap port_cap[MLX4_MAX_PORTS + 1];
 	bool wol_port[MLX4_MAX_PORTS + 1];
+	bool map_clock_to_user;
 };
 
 struct mlx4_func_cap {
@@ -182,8 +183,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-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -498,6 +498,7 @@
 		}
 	}
 
+	dev->caps.map_clock_to_user  = dev_cap->map_clock_to_user;
 	dev->caps.uar_page_size	     = PAGE_SIZE;
 	dev->caps.num_uars	     = dev_cap->uar_size / PAGE_SIZE;
 	dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay;
@@ -1948,6 +1949,11 @@
 	if (mlx4_is_slave(dev))
 		return -EOPNOTSUPP;
 
+	if (!dev->caps.map_clock_to_user) {
+		mlx4_dbg(dev, "Map clock to user is not supported.\n");
+		return -EOPNOTSUPP;
+	}
+
 	if (!params)
 		return -EINVAL;
 
@@ -2550,6 +2556,7 @@
 
 		if (!err || err == -ENOSPC) {
 			priv->def_counter[port] = idx;
+			err = 0;
 		} else if (err == -ENOENT) {
 			err = 0;
 			continue;
@@ -2600,7 +2607,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);
@@ -3518,6 +3526,7 @@
 
 		if (!SRIOV_VALID_STATE(dev->flags)) {
 			mlx4_err(dev, "Invalid SRIOV state\n");
+			err = -EINVAL;
 			goto err_close;
 		}
 	}
@@ -4352,12 +4361,14 @@
 static void mlx4_shutdown(struct pci_dev *pdev)
 {
 	struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+	struct mlx4_dev *dev = persist->dev;
 
 	mlx4_info(persist->dev, "mlx4_shutdown was called\n");
 	mutex_lock(&persist->interface_state_mutex);
 	if (persist->interface_state & MLX4_INTERFACE_STATE_UP)
 		mlx4_unload_one(pdev);
 	mutex_unlock(&persist->interface_state_mutex);
+	mlx4_pci_disable_device(dev);
 }
 
 static const struct pci_error_handlers mlx4_err_handler = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -271,6 +271,10 @@
 	} buf[MLX4_EN_CACHE_SIZE];
 };
 
+enum {
+	MLX4_EN_TX_RING_STATE_RECOVERING,
+};
+
 struct mlx4_en_priv;
 
 struct mlx4_en_tx_ring {
@@ -317,6 +321,7 @@
 	 * Only queue_stopped might be used if BQL is not properly working.
 	 */
 	unsigned long		queue_stopped;
+	unsigned long		state;
 	struct mlx4_hwq_resources sp_wqres;
 	struct mlx4_qp		sp_qp;
 	struct mlx4_qp_context	sp_context;
@@ -530,6 +535,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;
@@ -595,7 +604,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;
@@ -643,6 +652,7 @@
 	u32 pflags;
 	u8 rss_key[MLX4_EN_RSS_KEY_SIZE];
 	u8 rss_hash_fn;
+	unsigned long state;
 };
 
 enum mlx4_en_wol {
@@ -787,6 +797,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-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/mr.c
+++ linux-ein-5.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] = kvmalloc_array(s, sizeof(long), GFP_KERNEL | __GFP_ZERO);
 		if (!buddy->bits[i])
 			goto err_out_free;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/port.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -1973,6 +1973,7 @@
 #define I2C_ADDR_LOW  0x50
 #define I2C_ADDR_HIGH 0x51
 #define I2C_PAGE_SIZE 256
+#define I2C_HIGH_PAGE_SIZE 128
 
 /* Module Info Data */
 struct mlx4_cable_info {
@@ -2026,6 +2027,88 @@
 	return "Unknown Error";
 }
 
+static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id)
+{
+	struct mlx4_cmd_mailbox *inbox, *outbox;
+	struct mlx4_mad_ifc *inmad, *outmad;
+	struct mlx4_cable_info *cable_info;
+	int ret;
+
+	inbox = mlx4_alloc_cmd_mailbox(dev);
+	if (IS_ERR(inbox))
+		return PTR_ERR(inbox);
+
+	outbox = mlx4_alloc_cmd_mailbox(dev);
+	if (IS_ERR(outbox)) {
+		mlx4_free_cmd_mailbox(dev, inbox);
+		return PTR_ERR(outbox);
+	}
+
+	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
+	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
+
+	inmad->method = 0x1; /* Get */
+	inmad->class_version = 0x1;
+	inmad->mgmt_class = 0x1;
+	inmad->base_version = 0x1;
+	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
+
+	cable_info = (struct mlx4_cable_info *)inmad->data;
+	cable_info->dev_mem_address = 0;
+	cable_info->page_num = 0;
+	cable_info->i2c_addr = I2C_ADDR_LOW;
+	cable_info->size = cpu_to_be16(1);
+
+	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
+			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
+			   MLX4_CMD_NATIVE);
+	if (ret)
+		goto out;
+
+	if (be16_to_cpu(outmad->status)) {
+		/* Mad returned with bad status */
+		ret = be16_to_cpu(outmad->status);
+		mlx4_warn(dev,
+			  "MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
+			  0xFF60, port, I2C_ADDR_LOW, 0, 1, ret,
+			  cable_info_mad_err_str(ret));
+		ret = -ret;
+		goto out;
+	}
+	cable_info = (struct mlx4_cable_info *)outmad->data;
+	*module_id = cable_info->data[0];
+out:
+	mlx4_free_cmd_mailbox(dev, inbox);
+	mlx4_free_cmd_mailbox(dev, outbox);
+	return ret;
+}
+
+static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
+{
+	*i2c_addr = I2C_ADDR_LOW;
+	*page_num = 0;
+
+	if (*offset < I2C_PAGE_SIZE)
+		return;
+
+	*i2c_addr = I2C_ADDR_HIGH;
+	*offset -= I2C_PAGE_SIZE;
+}
+
+static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
+{
+	/* Offsets 0-255 belong to page 0.
+	 * Offsets 256-639 belong to pages 01, 02, 03.
+	 * For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2
+	 */
+	if (*offset < I2C_PAGE_SIZE)
+		*page_num = 0;
+	else
+		*page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE;
+	*i2c_addr = I2C_ADDR_LOW;
+	*offset -= *page_num * I2C_HIGH_PAGE_SIZE;
+}
+
 /**
  * mlx4_get_module_info - Read cable module eeprom data
  * @dev: mlx4_dev.
@@ -2045,12 +2128,30 @@
 	struct mlx4_cmd_mailbox *inbox, *outbox;
 	struct mlx4_mad_ifc *inmad, *outmad;
 	struct mlx4_cable_info *cable_info;
-	u16 i2c_addr;
+	u8 module_id, i2c_addr, page_num;
 	int ret;
 
 	if (size > MODULE_INFO_MAX_READ)
 		size = MODULE_INFO_MAX_READ;
 
+	ret = mlx4_get_module_id(dev, port, &module_id);
+	if (ret)
+		return ret;
+
+	switch (module_id) {
+	case MLX4_MODULE_ID_SFP:
+		mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
+		break;
+	case MLX4_MODULE_ID_QSFP:
+	case MLX4_MODULE_ID_QSFP_PLUS:
+	case MLX4_MODULE_ID_QSFP28:
+		mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
+		break;
+	default:
+		mlx4_err(dev, "Module ID not recognized: %#x\n", module_id);
+		return -EINVAL;
+	}
+
 	inbox = mlx4_alloc_cmd_mailbox(dev);
 	if (IS_ERR(inbox))
 		return PTR_ERR(inbox);
@@ -2076,11 +2177,9 @@
 		 */
 		size -= offset + size - I2C_PAGE_SIZE;
 
-	i2c_addr = I2C_ADDR_LOW;
-
 	cable_info = (struct mlx4_cable_info *)inmad->data;
 	cable_info->dev_mem_address = cpu_to_be16(offset);
-	cable_info->page_num = 0;
+	cable_info->page_num = page_num;
 	cable_info->i2c_addr = i2c_addr;
 	cable_info->size = cpu_to_be16(size);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -697,7 +697,8 @@
 			err = mlx4_bitmap_init(*bitmap + k, 1,
 					       MLX4_QP_TABLE_RAW_ETH_SIZE - 1, 0,
 					       0);
-			mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0);
+			if (!err)
+				mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0);
 		}
 
 		if (err)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -4986,6 +4986,7 @@
 
 	if (!fs_rule->mirr_mbox) {
 		mlx4_err(dev, "rule mirroring mailbox is null\n");
+		mlx4_free_cmd_mailbox(dev, mailbox);
 		return -EINVAL;
 	}
 	memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
@@ -45,7 +45,7 @@
 
 static inline bool mlx5_accel_is_ktls_device(struct mlx5_core_dev *mdev)
 {
-	if (!MLX5_CAP_GEN(mdev, tls))
+	if (!MLX5_CAP_GEN(mdev, tls_tx))
 		return false;
 
 	if (!MLX5_CAP_GEN(mdev, log_max_dek))
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -69,12 +69,10 @@
 	MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR		= 0x10,
 };
 
-static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
-					   struct mlx5_cmd_msg *in,
-					   struct mlx5_cmd_msg *out,
-					   void *uout, int uout_size,
-					   mlx5_cmd_cbk_t cbk,
-					   void *context, int page_queue)
+static struct mlx5_cmd_work_ent *
+cmd_alloc_ent(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in,
+	      struct mlx5_cmd_msg *out, void *uout, int uout_size,
+	      mlx5_cmd_cbk_t cbk, void *context, int page_queue)
 {
 	gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
 	struct mlx5_cmd_work_ent *ent;
@@ -83,6 +81,7 @@
 	if (!ent)
 		return ERR_PTR(-ENOMEM);
 
+	ent->idx	= -EINVAL;
 	ent->in		= in;
 	ent->out	= out;
 	ent->uout	= uout;
@@ -91,10 +90,16 @@
 	ent->context	= context;
 	ent->cmd	= cmd;
 	ent->page_queue = page_queue;
+	refcount_set(&ent->refcnt, 1);
 
 	return ent;
 }
 
+static void cmd_free_ent(struct mlx5_cmd_work_ent *ent)
+{
+	kfree(ent);
+}
+
 static u8 alloc_token(struct mlx5_cmd *cmd)
 {
 	u8 token;
@@ -109,7 +114,7 @@
 	return token;
 }
 
-static int alloc_ent(struct mlx5_cmd *cmd)
+static int cmd_alloc_index(struct mlx5_cmd *cmd)
 {
 	unsigned long flags;
 	int ret;
@@ -123,12 +128,33 @@
 	return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
 }
 
-static void free_ent(struct mlx5_cmd *cmd, int idx)
+static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
+{
+	lockdep_assert_held(&cmd->alloc_lock);
+	set_bit(idx, &cmd->bitmask);
+}
+
+static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
+{
+	refcount_inc(&ent->refcnt);
+}
+
+static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
 {
+	struct mlx5_cmd *cmd = ent->cmd;
 	unsigned long flags;
 
 	spin_lock_irqsave(&cmd->alloc_lock, flags);
-	set_bit(idx, &cmd->bitmask);
+	if (!refcount_dec_and_test(&ent->refcnt))
+		goto out;
+
+	if (ent->idx >= 0) {
+		cmd_free_index(cmd, ent->idx);
+		up(ent->page_queue ? &cmd->pages_sem : &cmd->sem);
+	}
+
+	cmd_free_ent(ent);
+out:
 	spin_unlock_irqrestore(&cmd->alloc_lock, flags);
 }
 
@@ -219,11 +245,6 @@
 	ent->ret = -ETIMEDOUT;
 }
 
-static void free_cmd(struct mlx5_cmd_work_ent *ent)
-{
-	kfree(ent);
-}
-
 static int verify_signature(struct mlx5_cmd_work_ent *ent)
 {
 	struct mlx5_cmd_mailbox *next = ent->out->next;
@@ -837,17 +858,43 @@
 	struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev,
 						 cmd);
 
+	mlx5_cmd_eq_recover(dev);
+
+	/* Maybe got handled by eq recover ? */
+	if (!test_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state)) {
+		mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, recovered after timeout\n", ent->idx,
+			       mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+		goto out; /* phew, already handled */
+	}
+
 	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, true);
+	mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, timeout. Will cause a leak of a command resource\n",
+		       ent->idx, mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+	mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
+
+out:
+	cmd_ent_put(ent); /* for the cmd_ent_get() took on schedule delayed work */
 }
 
 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 bool opcode_allowed(struct mlx5_cmd *cmd, u16 opcode)
+{
+	if (cmd->allowed_opcode == CMD_ALLOWED_OPCODE_ALL)
+		return true;
+
+	return cmd->allowed_opcode == opcode;
+}
+
+bool mlx5_cmd_is_down(struct mlx5_core_dev *dev)
+{
+	return pci_channel_offline(dev->pdev) ||
+	       dev->cmd.state != MLX5_CMDIF_STATE_UP ||
+	       dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR;
+}
+
 static void cmd_work_handler(struct work_struct *work)
 {
 	struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -861,17 +908,18 @@
 	int alloc_ret;
 	int cmd_mode;
 
+	complete(&ent->handling);
 	sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
 	down(sem);
 	if (!ent->page_queue) {
-		alloc_ret = alloc_ent(cmd);
+		alloc_ret = cmd_alloc_index(cmd);
 		if (alloc_ret < 0) {
 			mlx5_core_err(dev, "failed to allocate command entry\n");
 			if (ent->callback) {
 				ent->callback(-EAGAIN, ent->context);
 				mlx5_free_cmd_msg(dev, ent->out);
 				free_msg(dev, ent->in);
-				free_cmd(ent);
+				cmd_ent_put(ent);
 			} else {
 				ent->ret = -EAGAIN;
 				complete(&ent->done);
@@ -888,7 +936,6 @@
 	}
 
 	cmd->ent_arr[ent->idx] = ent;
-	set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
 	lay = get_inst(cmd, ent->idx);
 	ent->lay = lay;
 	memset(lay, 0, sizeof(*lay));
@@ -908,12 +955,13 @@
 	ent->ts1 = ktime_get_ns();
 	cmd_mode = cmd->mode;
 
-	if (ent->callback)
-		schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
+	if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, cb_timeout))
+		cmd_ent_get(ent);
+	set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
 
+	cmd_ent_get(ent); /* for the _real_ FW event on completion */
 	/* Skip sending command to fw if internal error */
-	if (pci_channel_offline(dev->pdev) ||
-	    dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+	if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) {
 		u8 status = 0;
 		u32 drv_synd;
 
@@ -921,7 +969,7 @@
 		MLX5_SET(mbox_out, ent->out, status, status);
 		MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
 
-		mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+		mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
 		return;
 	}
 
@@ -934,7 +982,7 @@
 		poll_timeout(ent);
 		/* make sure we read the descriptor after ownership is SW */
 		rmb();
-		mlx5_cmd_comp_handler(dev, 1UL << ent->idx, (ent->ret == -ETIMEDOUT));
+		mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, (ent->ret == -ETIMEDOUT));
 	}
 }
 
@@ -968,25 +1016,62 @@
 	}
 }
 
+enum {
+	MLX5_CMD_TIMEOUT_RECOVER_MSEC   = 5 * 1000,
+};
+
+static void wait_func_handle_exec_timeout(struct mlx5_core_dev *dev,
+					  struct mlx5_cmd_work_ent *ent)
+{
+	unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_RECOVER_MSEC);
+
+	mlx5_cmd_eq_recover(dev);
+
+	/* Re-wait on the ent->done after executing the recovery flow. If the
+	 * recovery flow (or any other recovery flow running simultaneously)
+	 * has recovered an EQE, it should cause the entry to be completed by
+	 * the command interface.
+	 */
+	if (wait_for_completion_timeout(&ent->done, timeout)) {
+		mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) recovered after timeout\n", ent->idx,
+			       mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+		return;
+	}
+
+	mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) No done completion\n", ent->idx,
+		       mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+
+	ent->ret = -ETIMEDOUT;
+	mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
+}
+
 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 (cmd->mode == CMD_MODE_POLLING || ent->polling) {
-		wait_for_completion(&ent->done);
-	} else if (!wait_for_completion_timeout(&ent->done, timeout)) {
-		ent->ret = -ETIMEDOUT;
-		mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+	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 || ent->polling)
+		wait_for_completion(&ent->done);
+	else if (!wait_for_completion_timeout(&ent->done, timeout))
+		wait_func_handle_exec_timeout(dev, ent);
 
+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);
@@ -1014,14 +1099,20 @@
 	if (callback && page_queue)
 		return -EINVAL;
 
-	ent = alloc_cmd(cmd, in, out, uout, uout_size, callback, context,
-			page_queue);
+	ent = cmd_alloc_ent(cmd, in, out, uout, uout_size,
+			    callback, context, page_queue);
 	if (IS_ERR(ent))
 		return PTR_ERR(ent);
 
+	/* put for this ent is when consumed, depending on the use case
+	 * 1) (!callback) blocking flow: by caller after wait_func completes
+	 * 2) (callback) flow: by mlx5_cmd_comp_handler() when ent is handled
+	 */
+
 	ent->token = token;
 	ent->polling = force_polling;
 
+	init_completion(&ent->handling);
 	if (!callback)
 		init_completion(&ent->done);
 
@@ -1036,11 +1127,11 @@
 	}
 
 	if (callback)
-		goto out;
+		goto out; /* mlx5_cmd_comp_handler() will put(ent) */
 
 	err = wait_func(dev, ent);
-	if (err == -ETIMEDOUT)
-		goto out;
+	if (err == -ETIMEDOUT || err == -ECANCELED)
+		goto out_free;
 
 	ds = ent->ts2 - ent->ts1;
 	op = MLX5_GET(mbox_in, in->first.data, opcode);
@@ -1057,7 +1148,7 @@
 	*status = ent->status;
 
 out_free:
-	free_cmd(ent);
+	cmd_ent_put(ent);
 out:
 	return err;
 }
@@ -1331,8 +1422,8 @@
 		return -EFAULT;
 
 	err = sscanf(outlen_str, "%d", &outlen);
-	if (err < 0)
-		return err;
+	if (err != 1)
+		return -EINVAL;
 
 	ptr = kzalloc(outlen, GFP_KERNEL);
 	if (!ptr)
@@ -1387,6 +1478,22 @@
 	mlx5_cmdif_debugfs_init(dev);
 }
 
+void mlx5_cmd_allowed_opcode(struct mlx5_core_dev *dev, u16 opcode)
+{
+	struct mlx5_cmd *cmd = &dev->cmd;
+	int i;
+
+	for (i = 0; i < cmd->max_reg_cmds; i++)
+		down(&cmd->sem);
+	down(&cmd->pages_sem);
+
+	cmd->allowed_opcode = opcode;
+
+	up(&cmd->pages_sem);
+	for (i = 0; i < cmd->max_reg_cmds; i++)
+		up(&cmd->sem);
+}
+
 static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
 {
 	struct mlx5_cmd *cmd = &dev->cmd;
@@ -1461,8 +1568,6 @@
 	vector = vec & 0xffffffff;
 	for (i = 0; i < (1 << cmd->log_sz); i++) {
 		if (test_bit(i, &vector)) {
-			struct semaphore *sem;
-
 			ent = cmd->ent_arr[i];
 
 			/* if we already completed the command, ignore it */
@@ -1472,18 +1577,19 @@
 				if (!forced) {
 					mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
 						      ent->idx);
-					free_ent(cmd, ent->idx);
-					free_cmd(ent);
+					cmd_ent_put(ent);
 				}
 				continue;
 			}
 
-			if (ent->callback)
-				cancel_delayed_work(&ent->cb_timeout_work);
-			if (ent->page_queue)
-				sem = &cmd->pages_sem;
-			else
-				sem = &cmd->sem;
+			if (ent->callback && cancel_delayed_work(&ent->cb_timeout_work))
+				cmd_ent_put(ent); /* timeout work was canceled */
+
+			if (!forced || /* Real FW completion */
+			     mlx5_cmd_is_down(dev) || /* No real FW completion is expected */
+			     !opcode_allowed(cmd, ent->op))
+				cmd_ent_put(ent);
+
 			ent->ts2 = ktime_get_ns();
 			memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
 			dump_command(dev, ent, 0);
@@ -1501,10 +1607,6 @@
 					      ent->ret, deliv_status_to_str(ent->status), ent->status);
 			}
 
-			/* only real completion will free the entry slot */
-			if (!forced)
-				free_ent(cmd, ent->idx);
-
 			if (ent->callback) {
 				ds = ent->ts2 - ent->ts1;
 				if (ent->op < ARRAY_SIZE(cmd->stats)) {
@@ -1532,21 +1634,26 @@
 				free_msg(dev, ent->in);
 
 				err = err ? err : ent->status;
-				if (!forced)
-					free_cmd(ent);
+				/* final consumer is done, release ent */
+				cmd_ent_put(ent);
 				callback(err, context);
 			} else {
+				/* release wait_func() so mlx5_cmd_invoke()
+				 * can make the final ent_put()
+				 */
 				complete(&ent->done);
 			}
-			up(sem);
 		}
 	}
 }
 
 void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
 {
+	struct mlx5_cmd *cmd = &dev->cmd;
+	unsigned long bitmask;
 	unsigned long flags;
 	u64 vector;
+	int i;
 
 	/* wait for pending handlers to complete */
 	mlx5_eq_synchronize_cmd_irq(dev);
@@ -1555,11 +1662,20 @@
 	if (!vector)
 		goto no_trig;
 
+	bitmask = vector;
+	/* we must increment the allocated entries refcount before triggering the completions
+	 * to guarantee pending commands will not get freed in the meanwhile.
+	 * For that reason, it also has to be done inside the alloc_lock.
+	 */
+	for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+		cmd_ent_get(cmd->ent_arr[i]);
 	vector |= MLX5_TRIGGERED_CMD_COMP;
 	spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
 
 	mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
 	mlx5_cmd_comp_handler(dev, vector, true);
+	for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+		cmd_ent_put(cmd->ent_arr[i]);
 	return;
 
 no_trig:
@@ -1571,12 +1687,17 @@
 	struct mlx5_cmd *cmd = &dev->cmd;
 	int i;
 
-	for (i = 0; i < cmd->max_reg_cmds; i++)
-		while (down_trylock(&cmd->sem))
+	for (i = 0; i < cmd->max_reg_cmds; i++) {
+		while (down_trylock(&cmd->sem)) {
 			mlx5_cmd_trigger_completions(dev);
+			cond_resched();
+		}
+	}
 
-	while (down_trylock(&cmd->pages_sem))
+	while (down_trylock(&cmd->pages_sem)) {
 		mlx5_cmd_trigger_completions(dev);
+		cond_resched();
+	}
 
 	/* Unlock cmdif */
 	up(&cmd->pages_sem);
@@ -1663,12 +1784,11 @@
 	int err;
 	u8 status = 0;
 	u32 drv_synd;
+	u16 opcode;
 	u8 token;
 
-	if (pci_channel_offline(dev->pdev) ||
-	    dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
-		u16 opcode = MLX5_GET(mbox_in, in, opcode);
-
+	opcode = MLX5_GET(mbox_in, in, opcode);
+	if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode)) {
 		err = mlx5_internal_err_ret_value(dev, opcode, &drv_synd, &status);
 		MLX5_SET(mbox_out, out, status, status);
 		MLX5_SET(mbox_out, out, syndrome, drv_synd);
@@ -1738,7 +1858,7 @@
 	ctx->dev = dev;
 	/* Starts at 1 to avoid doing wake_up if we are not cleaning up */
 	atomic_set(&ctx->num_inflight, 1);
-	init_waitqueue_head(&ctx->wait);
+	init_completion(&ctx->inflight_done);
 }
 EXPORT_SYMBOL(mlx5_cmd_init_async_ctx);
 
@@ -1752,8 +1872,8 @@
  */
 void mlx5_cmd_cleanup_async_ctx(struct mlx5_async_ctx *ctx)
 {
-	atomic_dec(&ctx->num_inflight);
-	wait_event(ctx->wait, atomic_read(&ctx->num_inflight) == 0);
+	if (!atomic_dec_and_test(&ctx->num_inflight))
+		wait_for_completion(&ctx->inflight_done);
 }
 EXPORT_SYMBOL(mlx5_cmd_cleanup_async_ctx);
 
@@ -1764,7 +1884,7 @@
 
 	work->user_callback(status, work);
 	if (atomic_dec_and_test(&ctx->num_inflight))
-		wake_up(&ctx->wait);
+		complete(&ctx->inflight_done);
 }
 
 int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size,
@@ -1780,7 +1900,7 @@
 	ret = cmd_exec(ctx->dev, in, in_size, out, out_size,
 		       mlx5_cmd_exec_cb_handler, work, false);
 	if (ret && atomic_dec_and_test(&ctx->num_inflight))
-		wake_up(&ctx->wait);
+		complete(&ctx->inflight_done);
 
 	return ret;
 }
@@ -1933,6 +2053,7 @@
 		goto err_free_page;
 	}
 
+	cmd->state = MLX5_CMDIF_STATE_DOWN;
 	cmd->checksum_disabled = 1;
 	cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
 	cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1;
@@ -1970,6 +2091,7 @@
 	mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
 
 	cmd->mode = CMD_MODE_POLLING;
+	cmd->allowed_opcode = CMD_ALLOWED_OPCODE_ALL;
 
 	create_msg_cache(dev);
 
@@ -2009,3 +2131,10 @@
 	dma_pool_destroy(cmd->pool);
 }
 EXPORT_SYMBOL(mlx5_cmd_cleanup);
+
+void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
+			enum mlx5_cmdif_state cmdif_state)
+{
+	dev->cmd.state = cmdif_state;
+}
+EXPORT_SYMBOL(mlx5_cmd_set_state);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -23,7 +23,10 @@
 	if (err)
 		return err;
 
-	return mlx5_firmware_flash(dev, fw, extack);
+	err = mlx5_firmware_flash(dev, fw, extack);
+	release_firmware(fw);
+
+	return err;
 }
 
 static u8 mlx5_fw_ver_major(u32 version)
@@ -52,7 +55,7 @@
 	u32 running_fw, stored_fw;
 	int err;
 
-	err = devlink_info_driver_name_put(req, DRIVER_NAME);
+	err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
 	if (err)
 		return err;
 
@@ -85,6 +88,22 @@
 	return 0;
 }
 
+static int mlx5_devlink_reload_down(struct devlink *devlink,
+				    struct netlink_ext_ack *extack)
+{
+	struct mlx5_core_dev *dev = devlink_priv(devlink);
+
+	return mlx5_unload_one(dev, false);
+}
+
+static int mlx5_devlink_reload_up(struct devlink *devlink,
+				  struct netlink_ext_ack *extack)
+{
+	struct mlx5_core_dev *dev = devlink_priv(devlink);
+
+	return mlx5_load_one(dev, false);
+}
+
 static const struct devlink_ops mlx5_devlink_ops = {
 #ifdef CONFIG_MLX5_ESWITCH
 	.eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
@@ -96,6 +115,8 @@
 #endif
 	.flash_update = mlx5_devlink_flash_update,
 	.info_get = mlx5_devlink_info_get,
+	.reload_down = mlx5_devlink_reload_down,
+	.reload_up = mlx5_devlink_reload_up,
 };
 
 struct devlink *mlx5_devlink_alloc(void)
@@ -177,12 +198,29 @@
 	MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE,
 };
 
+static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
+					     union devlink_param_value val,
+					     struct netlink_ext_ack *extack)
+{
+	struct mlx5_core_dev *dev = devlink_priv(devlink);
+	bool new_state = val.vbool;
+
+	if (new_state && !MLX5_CAP_GEN(dev, roce)) {
+		NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static const struct devlink_param mlx5_devlink_params[] = {
 	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE,
 			     "flow_steering_mode", DEVLINK_PARAM_TYPE_STRING,
 			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
 			     mlx5_devlink_fs_mode_get, mlx5_devlink_fs_mode_set,
 			     mlx5_devlink_fs_mode_validate),
+	DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
+			      NULL, NULL, mlx5_devlink_enable_roce_validate),
 };
 
 static void mlx5_devlink_set_params_init_values(struct devlink *devlink)
@@ -197,6 +235,11 @@
 	devlink_param_driverinit_value_set(devlink,
 					   MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE,
 					   value);
+
+	value.vbool = MLX5_CAP_GEN(dev, roce);
+	devlink_param_driverinit_value_set(devlink,
+					   DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
+					   value);
 }
 
 int mlx5_devlink_register(struct devlink *devlink, struct device *dev)
@@ -213,6 +256,7 @@
 		goto params_reg_err;
 	mlx5_devlink_set_params_init_values(devlink);
 	devlink_params_publish(devlink);
+	devlink_reload_enable(devlink);
 	return 0;
 
 params_reg_err:
@@ -222,6 +266,7 @@
 
 void mlx5_devlink_unregister(struct devlink *devlink)
 {
+	devlink_reload_disable(devlink);
 	devlink_params_unregister(devlink, mlx5_devlink_params,
 				  ARRAY_SIZE(mlx5_devlink_params));
 	devlink_unregister(devlink);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
@@ -480,7 +480,7 @@
 				(u64)timestamp_low;
 		break;
 	default:
-		if (tracer_event->event_id >= tracer->str_db.first_string_trace ||
+		if (tracer_event->event_id >= tracer->str_db.first_string_trace &&
 		    tracer_event->event_id <= tracer->str_db.first_string_trace +
 					      tracer->str_db.num_string_trace) {
 			tracer_event->type = TRACER_EVENT_TYPE_STRING;
@@ -600,7 +600,7 @@
 	} else {
 		cur_string = mlx5_tracer_message_get(tracer, tracer_event);
 		if (!cur_string) {
-			pr_debug("%s Got string event for unknown string tdsm: %d\n",
+			pr_debug("%s Got string event for unknown string tmsn: %d\n",
 				 __func__, tracer_event->string_event.tmsn);
 			return -1;
 		}
@@ -636,7 +636,7 @@
 			trace_timestamp = (timestamp_event.timestamp & MASK_52_7) |
 					  (str_frmt->timestamp & MASK_6_0);
 		else
-			trace_timestamp = ((timestamp_event.timestamp & MASK_52_7) - 1) |
+			trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) |
 					  (str_frmt->timestamp & MASK_6_0);
 
 		mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp);
@@ -673,6 +673,9 @@
 	if (!tracer->owner)
 		return;
 
+	if (unlikely(!tracer->str_db.loaded))
+		goto arm;
+
 	block_count = tracer->buff.size / TRACER_BLOCK_SIZE_BYTE;
 	start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE;
 
@@ -684,8 +687,8 @@
 		get_block_timestamp(tracer, &tmp_trace_block[TRACES_PER_BLOCK - 1]);
 
 	while (block_timestamp > tracer->last_timestamp) {
-		/* Check block override if its not the first block */
-		if (!tracer->last_timestamp) {
+		/* Check block override if it's not the first block */
+		if (tracer->last_timestamp) {
 			u64 *ts_event;
 			/* To avoid block override be the HW in case of buffer
 			 * wraparound, the time stamp of the previous block
@@ -730,6 +733,7 @@
 						      &tmp_trace_block[TRACES_PER_BLOCK - 1]);
 	}
 
+arm:
 	mlx5_fw_tracer_arm(dev);
 }
 
@@ -935,7 +939,7 @@
 		return NULL;
 	}
 
-	tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
+	tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
 	if (!tracer)
 		return ERR_PTR(-ENOMEM);
 
@@ -982,7 +986,7 @@
 	tracer->dev = NULL;
 	destroy_workqueue(tracer->work_queue);
 free_tracer:
-	kfree(tracer);
+	kvfree(tracer);
 	return ERR_PTR(err);
 }
 
@@ -1005,7 +1009,7 @@
 	err = mlx5_core_alloc_pd(dev, &tracer->buff.pdn);
 	if (err) {
 		mlx5_core_warn(dev, "FWTracer: Failed to allocate PD %d\n", err);
-		return err;
+		goto err_cancel_work;
 	}
 
 	err = mlx5_fw_tracer_create_mkey(tracer);
@@ -1017,12 +1021,20 @@
 	MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER);
 	mlx5_eq_notifier_register(dev, &tracer->nb);
 
-	mlx5_fw_tracer_start(tracer);
-
+	err = mlx5_fw_tracer_start(tracer);
+	if (err) {
+		mlx5_core_warn(dev, "FWTracer: Failed to start tracer %d\n", err);
+		goto err_notifier_unregister;
+	}
 	return 0;
 
+err_notifier_unregister:
+	mlx5_eq_notifier_unregister(dev, &tracer->nb);
+	mlx5_core_destroy_mkey(dev, &tracer->buff.mkey);
 err_dealloc_pd:
 	mlx5_core_dealloc_pd(dev, tracer->buff.pdn);
+err_cancel_work:
+	cancel_work_sync(&tracer->read_fw_strings_work);
 	return err;
 }
 
@@ -1061,7 +1073,7 @@
 	mlx5_fw_tracer_destroy_log_buf(tracer);
 	flush_workqueue(tracer->work_queue);
 	destroy_workqueue(tracer->work_queue);
-	kfree(tracer);
+	kvfree(tracer);
 }
 
 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
@@ -1076,8 +1088,7 @@
 			queue_work(tracer->work_queue, &tracer->ownership_change_work);
 		break;
 	case MLX5_TRACER_SUBTYPE_TRACES_AVAILABLE:
-		if (likely(tracer->str_db.loaded))
-			queue_work(tracer->work_queue, &tracer->handle_traces_work);
+		queue_work(tracer->work_queue, &tracer->handle_traces_work);
 		break;
 	default:
 		mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n",
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -92,11 +92,16 @@
 #define MLX5_MPWRQ_PAGES_PER_WQE		BIT(MLX5_MPWRQ_WQE_PAGE_ORDER)
 
 #define MLX5_MTT_OCTW(npages) (ALIGN(npages, 8) / 2)
-#define MLX5E_REQUIRED_WQE_MTTS		(ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8))
+/* Add another page to MLX5E_REQUIRED_WQE_MTTS as a buffer between
+ * WQEs, This page will absorb write overflow by the hardware, when
+ * receiving packets larger than MTU. These oversize packets are
+ * dropped by the driver at a later stage.
+ */
+#define MLX5E_REQUIRED_WQE_MTTS		(ALIGN(MLX5_MPWRQ_PAGES_PER_WQE + 1, 8))
 #define MLX5E_LOG_ALIGNED_MPWQE_PPW	(ilog2(MLX5E_REQUIRED_WQE_MTTS))
 #define MLX5E_REQUIRED_MTTS(wqes)	(wqes * MLX5E_REQUIRED_WQE_MTTS)
 #define MLX5E_MAX_RQ_NUM_MTTS	\
-	((1 << 16) * 2) /* So that MLX5_MTT_OCTW(num_mtts) fits into u16 */
+	(ALIGN_DOWN(U16_MAX, 4) * 2) /* So that MLX5_MTT_OCTW(num_mtts) fits into u16 */
 #define MLX5E_ORDER2_MAX_PACKET_MTU (order_base_2(10 * 1024))
 #define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE_MPW	\
 		(ilog2(MLX5E_MAX_RQ_NUM_MTTS / MLX5E_REQUIRED_WQE_MTTS))
@@ -367,10 +372,12 @@
 	MLX5E_SQ_STATE_AM,
 	MLX5E_SQ_STATE_TLS,
 	MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE,
+	MLX5E_SQ_STATE_PENDING_XSK_TX,
 };
 
 struct mlx5e_sq_wqe_info {
 	u8  opcode;
+	u8 num_wqebbs;
 
 	/* Auxiliary data for different opcodes. */
 	union {
@@ -692,6 +699,7 @@
 	u32                    rqn;
 	struct mlx5_core_dev  *mdev;
 	struct mlx5_core_mkey  umr_mkey;
+	struct mlx5e_dma_info  wqe_overflow;
 
 	/* XDP read-mostly */
 	struct xdp_rxq_info    xdp_rxq;
@@ -760,7 +768,7 @@
 	MLX5E_STATE_OPENED,
 	MLX5E_STATE_DESTROYING,
 	MLX5E_STATE_XDP_TX_ENABLED,
-	MLX5E_STATE_XDP_OPEN,
+	MLX5E_STATE_XDP_ACTIVE,
 };
 
 struct mlx5e_rqt {
@@ -816,7 +824,7 @@
 struct mlx5e_priv {
 	/* priv data path fields - start */
 	struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
-	int channel_tc2txq[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
+	int channel_tc2realtxq[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
 #ifdef CONFIG_MLX5_CORE_EN_DCB
 	struct mlx5e_dcbx_dp       dcbx_dp;
 #endif
@@ -947,7 +955,7 @@
 void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
 void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
 bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq);
-void mlx5e_poll_ico_cq(struct mlx5e_cq *cq);
+int mlx5e_poll_ico_cq(struct mlx5e_cq *cq);
 bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq);
 void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix);
 void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix);
@@ -1034,14 +1042,15 @@
 			struct mlx5e_channels *chs);
 void mlx5e_close_channels(struct mlx5e_channels *chs);
 
-/* Function pointer to be used to modify WH settings while
+/* Function pointer to be used to modify HW or kernel settings while
  * switching channels
  */
-typedef int (*mlx5e_fp_hw_modify)(struct mlx5e_priv *priv);
+typedef int (*mlx5e_fp_preactivate)(struct mlx5e_priv *priv);
 int mlx5e_safe_reopen_channels(struct mlx5e_priv *priv);
 int mlx5e_safe_switch_channels(struct mlx5e_priv *priv,
 			       struct mlx5e_channels *new_chs,
-			       mlx5e_fp_hw_modify hw_modify);
+			       mlx5e_fp_preactivate preactivate);
+int mlx5e_num_channels_changed(struct mlx5e_priv *priv);
 void mlx5e_activate_priv_channels(struct mlx5e_priv *priv);
 void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv);
 
@@ -1058,6 +1067,7 @@
 void mlx5e_activate_rq(struct mlx5e_rq *rq);
 void mlx5e_deactivate_rq(struct mlx5e_rq *rq);
 void mlx5e_free_rx_descs(struct mlx5e_rq *rq);
+void mlx5e_free_rx_in_progress_descs(struct mlx5e_rq *rq);
 void mlx5e_activate_icosq(struct mlx5e_icosq *icosq);
 void mlx5e_deactivate_icosq(struct mlx5e_icosq *icosq);
 
@@ -1099,7 +1109,7 @@
 int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv);
 
 int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
-void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
+void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv);
 
 int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
 void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
@@ -122,6 +122,22 @@
 #endif
 };
 
+#define MLX5E_TTC_NUM_GROUPS	3
+#define MLX5E_TTC_GROUP1_SIZE	(BIT(3) + MLX5E_NUM_TUNNEL_TT)
+#define MLX5E_TTC_GROUP2_SIZE	 BIT(1)
+#define MLX5E_TTC_GROUP3_SIZE	 BIT(0)
+#define MLX5E_TTC_TABLE_SIZE	(MLX5E_TTC_GROUP1_SIZE +\
+				 MLX5E_TTC_GROUP2_SIZE +\
+				 MLX5E_TTC_GROUP3_SIZE)
+
+#define MLX5E_INNER_TTC_NUM_GROUPS	3
+#define MLX5E_INNER_TTC_GROUP1_SIZE	BIT(3)
+#define MLX5E_INNER_TTC_GROUP2_SIZE	BIT(1)
+#define MLX5E_INNER_TTC_GROUP3_SIZE	BIT(0)
+#define MLX5E_INNER_TTC_TABLE_SIZE	(MLX5E_INNER_TTC_GROUP1_SIZE +\
+					 MLX5E_INNER_TTC_GROUP2_SIZE +\
+					 MLX5E_INNER_TTC_GROUP3_SIZE)
+
 #ifdef CONFIG_MLX5_EN_RXNFC
 
 struct mlx5e_ethtool_table {
@@ -218,18 +234,12 @@
 
 void mlx5e_set_ttc_basic_params(struct mlx5e_priv *priv, struct ttc_params *ttc_params);
 void mlx5e_set_ttc_ft_params(struct ttc_params *ttc_params);
-void mlx5e_set_inner_ttc_ft_params(struct ttc_params *ttc_params);
 
 int mlx5e_create_ttc_table(struct mlx5e_priv *priv, struct ttc_params *params,
 			   struct mlx5e_ttc_table *ttc);
 void mlx5e_destroy_ttc_table(struct mlx5e_priv *priv,
 			     struct mlx5e_ttc_table *ttc);
 
-int mlx5e_create_inner_ttc_table(struct mlx5e_priv *priv, struct ttc_params *params,
-				 struct mlx5e_ttc_table *ttc);
-void mlx5e_destroy_inner_ttc_table(struct mlx5e_priv *priv,
-				   struct mlx5e_ttc_table *ttc);
-
 void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft);
 
 void mlx5e_enable_cvlan_filter(struct mlx5e_priv *priv);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/health.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/health.c
@@ -197,9 +197,10 @@
 			struct devlink_health_reporter *reporter, char *err_str,
 			struct mlx5e_err_ctx *err_ctx)
 {
-	if (!reporter) {
-		netdev_err(priv->netdev, err_str);
-		return err_ctx->recover(&err_ctx->ctx);
-	}
+	netdev_err(priv->netdev, err_str);
+
+	if (!reporter)
+		return err_ctx->recover(err_ctx->ctx);
+
 	return devlink_health_report(reporter, err_str, err_ctx);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/health.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/health.h
@@ -10,8 +10,7 @@
 
 static inline bool cqe_syndrome_needs_recover(u8 syndrome)
 {
-	return syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR ||
-	       syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
+	return syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
 	       syndrome == MLX5_CQE_SYNDROME_LOCAL_PROT_ERR ||
 	       syndrome == MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
@@ -73,15 +73,31 @@
 	[MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2]	= 50000,
 	[MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]	= 50000,
 	[MLX5E_CAUI_4_100GBASE_CR4_KR4]		= 100000,
+	[MLX5E_100GAUI_2_100GBASE_CR2_KR2]	= 100000,
 	[MLX5E_200GAUI_4_200GBASE_CR4_KR4]	= 200000,
 	[MLX5E_400GAUI_8]			= 400000,
 };
 
+bool mlx5e_ptys_ext_supported(struct mlx5_core_dev *mdev)
+{
+	struct mlx5e_port_eth_proto eproto;
+	int err;
+
+	if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
+		return true;
+
+	err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
+	if (err)
+		return false;
+
+	return !!eproto.cap;
+}
+
 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
 				     const u32 **arr, u32 *size,
 				     bool force_legacy)
 {
-	bool ext = force_legacy ? false : MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	bool ext = force_legacy ? false : mlx5e_ptys_ext_supported(mdev);
 
 	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
 		      ARRAY_SIZE(mlx5e_link_speed);
@@ -176,7 +192,7 @@
 	bool ext;
 	int err;
 
-	ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	ext = mlx5e_ptys_ext_supported(mdev);
 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 	if (err)
 		goto out;
@@ -204,7 +220,7 @@
 	int err;
 	int i;
 
-	ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	ext = mlx5e_ptys_ext_supported(mdev);
 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
 	if (err)
 		return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/port.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/port.h
@@ -54,7 +54,7 @@
 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
 u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
 			       bool force_legacy);
-
+bool mlx5e_ptys_ext_supported(struct mlx5_core_dev *mdev);
 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
@@ -155,8 +155,11 @@
 		}
 
 		if (port_buffer->buffer[i].size <
-		    (xoff + max_mtu + (1 << MLX5E_BUFFER_CELL_SHIFT)))
+		    (xoff + max_mtu + (1 << MLX5E_BUFFER_CELL_SHIFT))) {
+			pr_err("buffer_size[%d]=%d is not enough for lossless buffer\n",
+			       i, port_buffer->buffer[i].size);
 			return -ENOMEM;
+		}
 
 		port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - xoff;
 		port_buffer->buffer[i].xon  =
@@ -232,6 +235,26 @@
 	return 0;
 }
 
+static int fill_pfc_en(struct mlx5_core_dev *mdev, u8 *pfc_en)
+{
+	u32 g_rx_pause, g_tx_pause;
+	int err;
+
+	err = mlx5_query_port_pause(mdev, &g_rx_pause, &g_tx_pause);
+	if (err)
+		return err;
+
+	/* If global pause enabled, set all active buffers to lossless.
+	 * Otherwise, check PFC setting.
+	 */
+	if (g_rx_pause || g_tx_pause)
+		*pfc_en = 0xff;
+	else
+		err = mlx5_query_port_pfc(mdev, pfc_en, NULL);
+
+	return err;
+}
+
 #define MINIMUM_MAX_MTU 9216
 int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
 				    u32 change, unsigned int mtu,
@@ -277,7 +300,7 @@
 
 	if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
 		update_prio2buffer = true;
-		err = mlx5_query_port_pfc(priv->mdev, &curr_pfc_en, NULL);
+		err = fill_pfc_en(priv->mdev, &curr_pfc_en);
 		if (err)
 			return err;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c
@@ -90,7 +90,7 @@
 		goto out;
 
 	mlx5e_reset_icosq_cc_pc(icosq);
-	mlx5e_free_rx_descs(rq);
+	mlx5e_free_rx_in_progress_descs(rq);
 	clear_bit(MLX5E_SQ_STATE_RECOVERING, &icosq->state);
 	mlx5e_activate_icosq(icosq);
 	mlx5e_activate_rq(rq);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -144,10 +144,10 @@
 #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
 	int ret;
 
-	ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
-					 fl6);
-	if (ret < 0)
-		return ret;
+	dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(mirred_dev), NULL, fl6,
+					      NULL);
+	if (IS_ERR(dst))
+		return PTR_ERR(dst);
 
 	if (!(*out_ttl))
 		*out_ttl = ip6_dst_hoplimit(dst);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
@@ -227,6 +227,10 @@
 	option_key = (struct geneve_opt *)&enc_opts.key->data[0];
 	option_mask = (struct geneve_opt *)&enc_opts.mask->data[0];
 
+	if (option_mask->opt_class == 0 && option_mask->type == 0 &&
+	    !memchr_inv(option_mask->opt_data, 0, option_mask->length * 4))
+		return 0;
+
 	if (option_key->length > max_tlv_option_data_len) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "Matching on GENEVE options: unsupported option len");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -27,6 +27,11 @@
 
 #define INL_HDR_START_SZ (sizeof(((struct mlx5_wqe_eth_seg *)NULL)->inline_hdr.start))
 
+static inline bool mlx5e_skb_is_multicast(struct sk_buff *skb)
+{
+	return skb->pkt_type == PACKET_MULTICAST || skb->pkt_type == PACKET_BROADCAST;
+}
+
 static inline bool
 mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n)
 {
@@ -179,6 +184,16 @@
 	}
 }
 
+static inline void mlx5e_rqwq_reset(struct mlx5e_rq *rq)
+{
+	if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+		mlx5_wq_ll_reset(&rq->mpwqe.wq);
+		rq->mpwqe.actual_wq_head = 0;
+	} else {
+		mlx5_wq_cyc_reset(&rq->wqe.wq);
+	}
+}
+
 /* SW parser related functions */
 
 struct mlx5e_swp_spec {
@@ -189,6 +204,15 @@
 	u8 tun_l4_proto;
 };
 
+static inline void mlx5e_eseg_swp_offsets_add_vlan(struct mlx5_wqe_eth_seg *eseg)
+{
+	/* SWP offsets are in 2-bytes words */
+	eseg->swp_outer_l3_offset += VLAN_HLEN / 2;
+	eseg->swp_outer_l4_offset += VLAN_HLEN / 2;
+	eseg->swp_inner_l3_offset += VLAN_HLEN / 2;
+	eseg->swp_inner_l4_offset += VLAN_HLEN / 2;
+}
+
 static inline void
 mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
 		   struct mlx5e_swp_spec *swp_spec)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
@@ -75,12 +75,18 @@
 static inline void mlx5e_xdp_tx_enable(struct mlx5e_priv *priv)
 {
 	set_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
+
+	if (priv->channels.params.xdp_prog)
+		set_bit(MLX5E_STATE_XDP_ACTIVE, &priv->state);
 }
 
 static inline void mlx5e_xdp_tx_disable(struct mlx5e_priv *priv)
 {
+	if (priv->channels.params.xdp_prog)
+		clear_bit(MLX5E_STATE_XDP_ACTIVE, &priv->state);
+
 	clear_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
-	/* let other device's napi(s) see our new state */
+	/* Let other device's napi(s) and XSK wakeups see our new state. */
 	synchronize_rcu();
 }
 
@@ -89,19 +95,9 @@
 	return test_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
 }
 
-static inline void mlx5e_xdp_set_open(struct mlx5e_priv *priv)
-{
-	set_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
-}
-
-static inline void mlx5e_xdp_set_closed(struct mlx5e_priv *priv)
-{
-	clear_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
-}
-
-static inline bool mlx5e_xdp_is_open(struct mlx5e_priv *priv)
+static inline bool mlx5e_xdp_is_active(struct mlx5e_priv *priv)
 {
-	return test_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
+	return test_bit(MLX5E_STATE_XDP_ACTIVE, &priv->state);
 }
 
 static inline void mlx5e_xmit_xdp_doorbell(struct mlx5e_xdpsq *sq)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
@@ -144,6 +144,7 @@
 {
 	clear_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
 	napi_synchronize(&c->napi);
+	synchronize_rcu(); /* Sync with the XSK wakeup. */
 
 	mlx5e_close_rq(&c->xskrq);
 	mlx5e_close_cq(&c->xskrq.cq);
@@ -151,6 +152,10 @@
 	mlx5e_close_cq(&c->xskicosq.cq);
 	mlx5e_close_xdpsq(&c->xsksq);
 	mlx5e_close_cq(&c->xsksq.cq);
+
+	memset(&c->xskrq, 0, sizeof(c->xskrq));
+	memset(&c->xsksq, 0, sizeof(c->xsksq));
+	memset(&c->xskicosq, 0, sizeof(c->xskicosq));
 }
 
 void mlx5e_activate_xsk(struct mlx5e_channel *c)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
@@ -14,7 +14,7 @@
 	struct mlx5e_channel *c;
 	u16 ix;
 
-	if (unlikely(!mlx5e_xdp_is_open(priv)))
+	if (unlikely(!mlx5e_xdp_is_active(priv)))
 		return -ENETDOWN;
 
 	if (unlikely(!mlx5e_qid_get_ch_if_in_group(params, qid, MLX5E_RQ_GROUP_XSK, &ix)))
@@ -33,6 +33,9 @@
 		if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &c->xskicosq.state)))
 			return 0;
 
+		if (test_and_set_bit(MLX5E_SQ_STATE_PENDING_XSK_TX, &c->xskicosq.state))
+			return 0;
+
 		spin_lock(&c->xskicosq_lock);
 		mlx5e_trigger_irq(&c->xskicosq);
 		spin_unlock(&c->xskicosq_lock);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
@@ -48,7 +48,7 @@
 }
 
 static inline void
-mlx5e_tx_tunnel_accel(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg)
+mlx5e_tx_tunnel_accel(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg, u16 ihs)
 {
 	struct mlx5e_swp_spec swp_spec = {};
 	unsigned int offset = 0;
@@ -82,6 +82,8 @@
 	}
 
 	mlx5e_set_eseg_swp(skb, eseg, &swp_spec);
+	if (skb_vlan_tag_present(skb) && ihs)
+		mlx5e_eseg_swp_offsets_add_vlan(eseg);
 }
 
 #else
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -117,7 +117,6 @@
 	struct xfrm_replay_state_esn *replay_esn;
 	u32 seq_bottom;
 	u8 overlap;
-	u32 *esn;
 
 	if (!(sa_entry->x->props.flags & XFRM_STATE_ESN)) {
 		sa_entry->esn_state.trigger = 0;
@@ -130,11 +129,9 @@
 
 	sa_entry->esn_state.esn = xfrm_replay_seqhi(sa_entry->x,
 						    htonl(seq_bottom));
-	esn = &sa_entry->esn_state.esn;
 
 	sa_entry->esn_state.trigger = 1;
 	if (unlikely(overlap && seq_bottom < MLX5E_IPSEC_ESN_SCOPE_MID)) {
-		++(*esn);
 		sa_entry->esn_state.overlap = 0;
 		return true;
 	} else if (unlikely(!overlap &&
@@ -515,9 +512,6 @@
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct net_device *netdev = priv->netdev;
 
-	if (!priv->ipsec)
-		return;
-
 	if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_CAP_ESP) ||
 	    !MLX5_CAP_ETH(mdev, swp)) {
 		mlx5_core_dbg(mdev, "mlx5e: ESP and SWP offload not supported\n");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
@@ -121,7 +121,9 @@
 
 	trailer_len = alen + plen + 2;
 
-	pskb_trim(skb, skb->len - trailer_len);
+	ret = pskb_trim(skb, skb->len - trailer_len);
+	if (unlikely(ret))
+		return ret;
 	if (skb->protocol == htons(ETH_P_IP)) {
 		ipv4hdr->tot_len = htons(ntohs(ipv4hdr->tot_len) - trailer_len);
 		ip_send_check(ipv4hdr);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
@@ -69,8 +69,8 @@
 	struct mlx5e_ktls_offload_context_tx *tx_priv =
 		mlx5e_get_ktls_tx_priv_ctx(tls_ctx);
 
-	mlx5_ktls_destroy_key(priv->mdev, tx_priv->key_id);
 	mlx5e_destroy_tis(priv->mdev, tx_priv->tisn);
+	mlx5_ktls_destroy_key(priv->mdev, tx_priv->key_id);
 	kvfree(tx_priv);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
@@ -38,8 +38,8 @@
 
 enum {
 	MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START     = 0,
-	MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 1,
-	MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING  = 2,
+	MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING  = 1,
+	MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 2,
 };
 
 struct mlx5e_ktls_offload_context_tx {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
@@ -180,7 +180,7 @@
 
 struct tx_sync_info {
 	u64 rcd_sn;
-	s32 sync_len;
+	u32 sync_len;
 	int nr_frags;
 	skb_frag_t frags[MAX_SKB_FRAGS];
 };
@@ -193,13 +193,14 @@
 
 static enum mlx5e_ktls_sync_retval
 tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
-		 u32 tcp_seq, struct tx_sync_info *info)
+		 u32 tcp_seq, int datalen, struct tx_sync_info *info)
 {
 	struct tls_offload_context_tx *tx_ctx = priv_tx->tx_ctx;
 	enum mlx5e_ktls_sync_retval ret = MLX5E_KTLS_SYNC_DONE;
 	struct tls_record_info *record;
 	int remaining, i = 0;
 	unsigned long flags;
+	bool ends_before;
 
 	spin_lock_irqsave(&tx_ctx->lock, flags);
 	record = tls_get_record(tx_ctx, tcp_seq, &info->rcd_sn);
@@ -209,9 +210,21 @@
 		goto out;
 	}
 
-	if (unlikely(tcp_seq < tls_record_start_seq(record))) {
-		ret = tls_record_is_start_marker(record) ?
-			MLX5E_KTLS_SYNC_SKIP_NO_DATA : MLX5E_KTLS_SYNC_FAIL;
+	/* There are the following cases:
+	 * 1. packet ends before start marker: bypass offload.
+	 * 2. packet starts before start marker and ends after it: drop,
+	 *    not supported, breaks contract with kernel.
+	 * 3. packet ends before tls record info starts: drop,
+	 *    this packet was already acknowledged and its record info
+	 *    was released.
+	 */
+	ends_before = before(tcp_seq + datalen - 1, tls_record_start_seq(record));
+
+	if (unlikely(tls_record_is_start_marker(record))) {
+		ret = ends_before ? MLX5E_KTLS_SYNC_SKIP_NO_DATA : MLX5E_KTLS_SYNC_FAIL;
+		goto out;
+	} else if (ends_before) {
+		ret = MLX5E_KTLS_SYNC_FAIL;
 		goto out;
 	}
 
@@ -337,7 +350,7 @@
 	u8 num_wqebbs;
 	int i = 0;
 
-	ret = tx_sync_info_get(priv_tx, seq, &info);
+	ret = tx_sync_info_get(priv_tx, seq, datalen, &info);
 	if (unlikely(ret != MLX5E_KTLS_SYNC_DONE)) {
 		if (ret == MLX5E_KTLS_SYNC_SKIP_NO_DATA) {
 			stats->tls_skip_no_sync_data++;
@@ -351,14 +364,6 @@
 		goto err_out;
 	}
 
-	if (unlikely(info.sync_len < 0)) {
-		if (likely(datalen <= -info.sync_len))
-			return MLX5E_KTLS_SYNC_DONE;
-
-		stats->tls_drop_bypass_req++;
-		goto err_out;
-	}
-
 	stats->tls_ooo++;
 
 	tx_post_resync_params(sq, priv_tx, info.rcd_sn);
@@ -378,8 +383,6 @@
 	if (unlikely(contig_wqebbs_room < num_wqebbs))
 		mlx5e_fill_sq_frag_edge(sq, wq, pi, contig_wqebbs_room);
 
-	tx_post_resync_params(sq, priv_tx, info.rcd_sn);
-
 	for (; i < info.nr_frags; i++) {
 		unsigned int orig_fsz, frag_offset = 0, n = 0;
 		skb_frag_t *f = &info.frags[i];
@@ -455,12 +458,18 @@
 		enum mlx5e_ktls_sync_retval ret =
 			mlx5e_ktls_tx_handle_ooo(priv_tx, sq, datalen, seq);
 
-		if (likely(ret == MLX5E_KTLS_SYNC_DONE))
+		switch (ret) {
+		case MLX5E_KTLS_SYNC_DONE:
 			*wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
-		else if (ret == MLX5E_KTLS_SYNC_FAIL)
+			break;
+		case MLX5E_KTLS_SYNC_SKIP_NO_DATA:
+			if (likely(!skb->decrypted))
+				goto out;
+			WARN_ON_ONCE(1);
+			/* fall-through */
+		default: /* MLX5E_KTLS_SYNC_FAIL */
 			goto err_out;
-		else /* ret == MLX5E_KTLS_SYNC_SKIP_NO_DATA */
-			goto out;
+		}
 	}
 
 	priv_tx->expected_seq = seq + datalen;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
@@ -269,7 +269,7 @@
 	int datalen;
 	u32 skb_seq;
 
-	if (MLX5_CAP_GEN(sq->channel->mdev, tls)) {
+	if (MLX5_CAP_GEN(sq->channel->mdev, tls_tx)) {
 		skb = mlx5e_ktls_handle_tx_skb(netdev, sq, skb, wqe, pi);
 		goto out;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
@@ -35,7 +35,6 @@
 #include <net/sock.h>
 
 #include "en.h"
-#include "accel/tls.h"
 #include "fpga/sdk.h"
 #include "en_accel/tls.h"
 
@@ -51,9 +50,14 @@
 
 #define NUM_TLS_SW_COUNTERS ARRAY_SIZE(mlx5e_tls_sw_stats_desc)
 
+static bool is_tls_atomic_stats(struct mlx5e_priv *priv)
+{
+	return priv->tls && !mlx5_accel_is_ktls_device(priv->mdev);
+}
+
 int mlx5e_tls_get_count(struct mlx5e_priv *priv)
 {
-	if (!priv->tls)
+	if (!is_tls_atomic_stats(priv))
 		return 0;
 
 	return NUM_TLS_SW_COUNTERS;
@@ -63,7 +67,7 @@
 {
 	unsigned int i, idx = 0;
 
-	if (!priv->tls)
+	if (!is_tls_atomic_stats(priv))
 		return 0;
 
 	for (i = 0; i < NUM_TLS_SW_COUNTERS; i++)
@@ -77,7 +81,7 @@
 {
 	int i, idx = 0;
 
-	if (!priv->tls)
+	if (!is_tls_atomic_stats(priv))
 		return 0;
 
 	for (i = 0; i < NUM_TLS_SW_COUNTERS; i++)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
@@ -227,11 +227,13 @@
 
 	ft->g = kcalloc(MLX5E_ARFS_NUM_GROUPS,
 			sizeof(*ft->g), GFP_KERNEL);
-	in = kvzalloc(inlen, GFP_KERNEL);
-	if  (!in || !ft->g) {
-		kvfree(ft->g);
-		kvfree(in);
+	if (!ft->g)
 		return -ENOMEM;
+
+	in = kvzalloc(inlen, GFP_KERNEL);
+	if (!in) {
+		err = -ENOMEM;
+		goto err_free_g;
 	}
 
 	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
@@ -251,7 +253,7 @@
 		break;
 	default:
 		err = -EINVAL;
-		goto out;
+		goto err_free_in;
 	}
 
 	switch (type) {
@@ -273,7 +275,7 @@
 		break;
 	default:
 		err = -EINVAL;
-		goto out;
+		goto err_free_in;
 	}
 
 	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
@@ -282,7 +284,7 @@
 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
 	if (IS_ERR(ft->g[ft->num_groups]))
-		goto err;
+		goto err_clean_group;
 	ft->num_groups++;
 
 	memset(in, 0, inlen);
@@ -291,18 +293,20 @@
 	MLX5_SET_CFG(in, end_flow_index, ix - 1);
 	ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
 	if (IS_ERR(ft->g[ft->num_groups]))
-		goto err;
+		goto err_clean_group;
 	ft->num_groups++;
 
 	kvfree(in);
 	return 0;
 
-err:
+err_clean_group:
 	err = PTR_ERR(ft->g[ft->num_groups]);
 	ft->g[ft->num_groups] = NULL;
-out:
+err_free_in:
 	kvfree(in);
-
+err_free_g:
+	kfree(ft->g);
+	ft->g = NULL;
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
@@ -109,12 +109,14 @@
 	if (!MLX5_CAP_GEN(priv->mdev, ets))
 		return -EOPNOTSUPP;
 
-	ets->ets_cap = mlx5_max_tc(priv->mdev) + 1;
-	for (i = 0; i < ets->ets_cap; i++) {
+	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
 		err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]);
 		if (err)
 			return err;
+	}
 
+	ets->ets_cap = mlx5_max_tc(priv->mdev) + 1;
+	for (i = 0; i < ets->ets_cap; i++) {
 		err = mlx5_query_port_tc_group(mdev, i, &tc_group[i]);
 		if (err)
 			return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -40,9 +40,7 @@
 {
 	struct mlx5_core_dev *mdev = priv->mdev;
 
-	strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver));
-	strlcpy(drvinfo->version, DRIVER_VERSION,
-		sizeof(drvinfo->version));
+	strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
 		 "%d.%d.%04d (%.16s)",
 		 fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev),
@@ -200,7 +198,7 @@
 					struct ptys2ethtool_config **arr,
 					u32 *size)
 {
-	bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	bool ext = mlx5e_ptys_ext_supported(mdev);
 
 	*arr = ext ? ptys2ext_ethtool_table : ptys2legacy_ethtool_table;
 	*size = ext ? ARRAY_SIZE(ptys2ext_ethtool_table) :
@@ -445,9 +443,7 @@
 
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
 		*cur_params = new_channels.params;
-		if (!netif_is_rxfh_configured(priv->netdev))
-			mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt,
-						      MLX5E_INDIR_RQT_SIZE, count);
+		mlx5e_num_channels_changed(priv);
 		goto out;
 	}
 
@@ -455,12 +451,8 @@
 	if (arfs_enabled)
 		mlx5e_arfs_disable(priv);
 
-	if (!netif_is_rxfh_configured(priv->netdev))
-		mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt,
-					      MLX5E_INDIR_RQT_SIZE, count);
-
 	/* Switch to new channels, set new parameters and close old ones */
-	err = mlx5e_safe_switch_channels(priv, &new_channels, NULL);
+	err = mlx5e_safe_switch_channels(priv, &new_channels, mlx5e_num_channels_changed);
 
 	if (arfs_enabled) {
 		int err2 = mlx5e_arfs_enable(priv);
@@ -706,11 +698,11 @@
 	return 0;
 }
 
-static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings *link_ksettings,
-						   u32 eth_proto_cap,
-						   u8 connector_type, bool ext)
+static void ptys2ethtool_supported_advertised_port(struct mlx5_core_dev *mdev,
+						   struct ethtool_link_ksettings *link_ksettings,
+						   u32 eth_proto_cap, u8 connector_type)
 {
-	if ((!connector_type && !ext) || connector_type >= MLX5E_CONNECTOR_TYPE_NUMBER) {
+	if (!MLX5_CAP_PCAM_FEATURE(mdev, ptys_connector_type)) {
 		if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR)
 				   | MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
 				   | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4)
@@ -842,9 +834,9 @@
 		[MLX5E_PORT_OTHER]              = PORT_OTHER,
 	};
 
-static u8 get_connector_port(u32 eth_proto, u8 connector_type, bool ext)
+static u8 get_connector_port(struct mlx5_core_dev *mdev, u32 eth_proto, u8 connector_type)
 {
-	if ((connector_type || ext) && connector_type < MLX5E_CONNECTOR_TYPE_NUMBER)
+	if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_connector_type))
 		return ptys2connector_type[connector_type];
 
 	if (eth_proto &
@@ -877,7 +869,7 @@
 			       struct ethtool_link_ksettings *link_ksettings)
 {
 	unsigned long *lp_advertising = link_ksettings->link_modes.lp_advertising;
-	bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	bool ext = mlx5e_ptys_ext_supported(mdev);
 
 	ptys2ethtool_adver_link(lp_advertising, eth_proto_lp, ext);
 }
@@ -906,7 +898,7 @@
 			   __func__, err);
 		goto err_query_regs;
 	}
-	ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability);
 	eth_proto_cap    = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
 					      eth_proto_capability);
 	eth_proto_admin  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
@@ -943,11 +935,11 @@
 			 link_ksettings);
 
 	eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
-
-	link_ksettings->base.port = get_connector_port(eth_proto_oper,
-						       connector_type, ext);
-	ptys2ethtool_supported_advertised_port(link_ksettings, eth_proto_admin,
-					       connector_type, ext);
+	connector_type = connector_type < MLX5E_CONNECTOR_TYPE_NUMBER ?
+			 connector_type : MLX5E_PORT_UNKNOWN;
+	link_ksettings->base.port = get_connector_port(mdev, eth_proto_oper, connector_type);
+	ptys2ethtool_supported_advertised_port(mdev, link_ksettings, eth_proto_admin,
+					       connector_type);
 	get_lp_advertising(mdev, eth_proto_lp, link_ksettings);
 
 	if (an_status == MLX5_AN_COMPLETE)
@@ -982,6 +974,22 @@
 	return mlx5e_ethtool_get_link_ksettings(priv, link_ksettings);
 }
 
+static int mlx5e_speed_validate(struct net_device *netdev, bool ext,
+				const unsigned long link_modes, u8 autoneg)
+{
+	/* Extended link-mode has no speed limitations. */
+	if (ext)
+		return 0;
+
+	if ((link_modes & MLX5E_PROT_MASK(MLX5E_56GBASE_R4)) &&
+	    autoneg != AUTONEG_ENABLE) {
+		netdev_err(netdev, "%s: 56G link speed requires autoneg enabled\n",
+			   __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes)
 {
 	u32 i, ptys_modes = 0;
@@ -1027,18 +1035,11 @@
 	return bitmap_intersects(modes, adver, __ETHTOOL_LINK_MODE_MASK_NBITS);
 }
 
-static bool ext_speed_requested(u32 speed)
-{
-#define MLX5E_MAX_PTYS_LEGACY_SPEED 100000
-	return !!(speed > MLX5E_MAX_PTYS_LEGACY_SPEED);
-}
-
-static bool ext_requested(u8 autoneg, const unsigned long *adver, u32 speed)
+static bool ext_requested(u8 autoneg, const unsigned long *adver, bool ext_supported)
 {
 	bool ext_link_mode = ext_link_mode_requested(adver);
-	bool ext_speed = ext_speed_requested(speed);
 
-	return  autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_speed;
+	return  autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_supported;
 }
 
 int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
@@ -1065,8 +1066,8 @@
 	autoneg = link_ksettings->base.autoneg;
 	speed = link_ksettings->base.speed;
 
-	ext = ext_requested(autoneg, adver, speed),
-	ext_supported = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
+	ext_supported = mlx5e_ptys_ext_supported(mdev);
+	ext = ext_requested(autoneg, adver, ext_supported);
 	if (!ext_supported && ext)
 		return -EOPNOTSUPP;
 
@@ -1081,13 +1082,9 @@
 	link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
 		mlx5e_port_speed2linkmodes(mdev, speed, !ext);
 
-	if ((link_modes & MLX5E_PROT_MASK(MLX5E_56GBASE_R4)) &&
-	    autoneg != AUTONEG_ENABLE) {
-		netdev_err(priv->netdev, "%s: 56G link speed requires autoneg enabled\n",
-			   __func__);
-		err = -EINVAL;
+	err = mlx5e_speed_validate(priv->netdev, ext, link_modes, autoneg);
+	if (err)
 		goto out;
-	}
 
 	link_modes = link_modes & eproto.cap;
 	if (!link_modes) {
@@ -1561,6 +1558,10 @@
 	int mode;
 	int err;
 
+	if (bitmap_weight((unsigned long *)&fecparam->fec,
+			  ETHTOOL_FEC_BASER_BIT + 1) > 1)
+		return -EOPNOTSUPP;
+
 	for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {
 		if (!(pplm_fec_2_ethtool[mode] & fecparam->fec))
 			continue;
@@ -1643,7 +1644,7 @@
 		break;
 	case MLX5_MODULE_ID_SFP:
 		modinfo->type       = ETH_MODULE_SFF_8472;
-		modinfo->eeprom_len = MLX5_EEPROM_PAGE_LENGTH;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
 		break;
 	default:
 		netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n",
@@ -1680,7 +1681,7 @@
 		if (size_read < 0) {
 			netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n",
 				   __func__, size_read);
-			return 0;
+			return size_read;
 		}
 
 		i += size_read;
@@ -1808,6 +1809,7 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct mlx5_core_dev *mdev = priv->mdev;
+	int err;
 
 	if (!MLX5_CAP_GEN(mdev, cqe_compression))
 		return -EOPNOTSUPP;
@@ -1817,7 +1819,10 @@
 		return -EINVAL;
 	}
 
-	mlx5e_modify_rx_cqe_compression_locked(priv, enable);
+	err = mlx5e_modify_rx_cqe_compression_locked(priv, enable);
+	if (err)
+		return err;
+
 	priv->channels.params.rx_cqe_compress_def = enable;
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
@@ -217,6 +217,9 @@
 		break;
 	}
 
+	if (WARN_ONCE(*rule_p, "VLAN rule already exists type %d", rule_type))
+		return 0;
+
 	*rule_p = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
 
 	if (IS_ERR(*rule_p)) {
@@ -397,8 +400,7 @@
 	for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
 		mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
 
-	if (priv->fs.vlan.cvlan_filter_disabled &&
-	    !(priv->netdev->flags & IFF_PROMISC))
+	if (priv->fs.vlan.cvlan_filter_disabled)
 		mlx5e_add_any_vid_rules(priv);
 }
 
@@ -415,8 +417,12 @@
 	for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
 		mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
 
-	if (priv->fs.vlan.cvlan_filter_disabled &&
-	    !(priv->netdev->flags & IFF_PROMISC))
+	WARN_ON_ONCE(!(test_bit(MLX5E_STATE_DESTROYING, &priv->state)));
+
+	/* must be called after DESTROY bit is set and
+	 * set_rx_mode is called and flushed
+	 */
+	if (priv->fs.vlan.cvlan_filter_disabled)
 		mlx5e_del_any_vid_rules(priv);
 }
 
@@ -904,22 +910,6 @@
 	return err;
 }
 
-#define MLX5E_TTC_NUM_GROUPS	3
-#define MLX5E_TTC_GROUP1_SIZE	(BIT(3) + MLX5E_NUM_TUNNEL_TT)
-#define MLX5E_TTC_GROUP2_SIZE	 BIT(1)
-#define MLX5E_TTC_GROUP3_SIZE	 BIT(0)
-#define MLX5E_TTC_TABLE_SIZE	(MLX5E_TTC_GROUP1_SIZE +\
-				 MLX5E_TTC_GROUP2_SIZE +\
-				 MLX5E_TTC_GROUP3_SIZE)
-
-#define MLX5E_INNER_TTC_NUM_GROUPS	3
-#define MLX5E_INNER_TTC_GROUP1_SIZE	BIT(3)
-#define MLX5E_INNER_TTC_GROUP2_SIZE	BIT(1)
-#define MLX5E_INNER_TTC_GROUP3_SIZE	BIT(0)
-#define MLX5E_INNER_TTC_TABLE_SIZE	(MLX5E_INNER_TTC_GROUP1_SIZE +\
-					 MLX5E_INNER_TTC_GROUP2_SIZE +\
-					 MLX5E_INNER_TTC_GROUP3_SIZE)
-
 static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc,
 					 bool use_ipv)
 {
@@ -937,6 +927,7 @@
 	in = kvzalloc(inlen, GFP_KERNEL);
 	if (!in) {
 		kfree(ft->g);
+		ft->g = NULL;
 		return -ENOMEM;
 	}
 
@@ -1077,6 +1068,7 @@
 	in = kvzalloc(inlen, GFP_KERNEL);
 	if (!in) {
 		kfree(ft->g);
+		ft->g = NULL;
 		return -ENOMEM;
 	}
 
@@ -1131,7 +1123,7 @@
 	ttc_params->inner_ttc = &priv->fs.inner_ttc;
 }
 
-void mlx5e_set_inner_ttc_ft_params(struct ttc_params *ttc_params)
+static void mlx5e_set_inner_ttc_ft_params(struct ttc_params *ttc_params)
 {
 	struct mlx5_flow_table_attr *ft_attr = &ttc_params->ft_attr;
 
@@ -1150,8 +1142,8 @@
 	ft_attr->prio = MLX5E_NIC_PRIO;
 }
 
-int mlx5e_create_inner_ttc_table(struct mlx5e_priv *priv, struct ttc_params *params,
-				 struct mlx5e_ttc_table *ttc)
+static int mlx5e_create_inner_ttc_table(struct mlx5e_priv *priv, struct ttc_params *params,
+					struct mlx5e_ttc_table *ttc)
 {
 	struct mlx5e_flow_table *ft = &ttc->ft;
 	int err;
@@ -1181,8 +1173,8 @@
 	return err;
 }
 
-void mlx5e_destroy_inner_ttc_table(struct mlx5e_priv *priv,
-				   struct mlx5e_ttc_table *ttc)
+static void mlx5e_destroy_inner_ttc_table(struct mlx5e_priv *priv,
+					  struct mlx5e_ttc_table *ttc)
 {
 	if (!mlx5e_tunnel_inner_ft_supported(priv->mdev))
 		return;
@@ -1356,6 +1348,7 @@
 	ft->g[ft->num_groups] = NULL;
 	mlx5e_destroy_groups(ft);
 	kvfree(in);
+	kfree(ft->g);
 
 	return err;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -266,12 +266,17 @@
 
 static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
 				 u64 npages, u8 page_shift,
-				 struct mlx5_core_mkey *umr_mkey)
+				 struct mlx5_core_mkey *umr_mkey,
+				 dma_addr_t filler_addr)
 {
-	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+	struct mlx5_mtt *mtt;
+	int inlen;
 	void *mkc;
 	u32 *in;
 	int err;
+	int i;
+
+	inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + sizeof(*mtt) * npages;
 
 	in = kvzalloc(inlen, GFP_KERNEL);
 	if (!in)
@@ -291,6 +296,18 @@
 	MLX5_SET(mkc, mkc, translations_octword_size,
 		 MLX5_MTT_OCTW(npages));
 	MLX5_SET(mkc, mkc, log_page_size, page_shift);
+	MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
+		 MLX5_MTT_OCTW(npages));
+
+	/* Initialize the mkey with all MTTs pointing to a default
+	 * page (filler_addr). When the channels are activated, UMR
+	 * WQEs will redirect the RX WQEs to the actual memory from
+	 * the RQ's pool, while the gaps (wqe_overflow) remain mapped
+	 * to the default page.
+	 */
+	mtt = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
+	for (i = 0 ; i < npages ; i++)
+		mtt[i].ptag = cpu_to_be64(filler_addr);
 
 	err = mlx5_core_create_mkey(mdev, umr_mkey, in, inlen);
 
@@ -302,7 +319,8 @@
 {
 	u64 num_mtts = MLX5E_REQUIRED_MTTS(mlx5_wq_ll_get_size(&rq->mpwqe.wq));
 
-	return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey);
+	return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey,
+				     rq->wqe_overflow.addr);
 }
 
 static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
@@ -370,6 +388,28 @@
 	mlx5e_reporter_rq_cqe_err(rq);
 }
 
+static int mlx5e_alloc_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
+{
+	rq->wqe_overflow.page = alloc_page(GFP_KERNEL);
+	if (!rq->wqe_overflow.page)
+		return -ENOMEM;
+
+	rq->wqe_overflow.addr = dma_map_page(rq->pdev, rq->wqe_overflow.page, 0,
+					     PAGE_SIZE, rq->buff.map_dir);
+	if (dma_mapping_error(rq->pdev, rq->wqe_overflow.addr)) {
+		__free_page(rq->wqe_overflow.page);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void mlx5e_free_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
+{
+	 dma_unmap_page(rq->pdev, rq->wqe_overflow.addr, PAGE_SIZE,
+			rq->buff.map_dir);
+	 __free_page(rq->wqe_overflow.page);
+}
+
 static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 			  struct mlx5e_params *params,
 			  struct mlx5e_xsk_param *xsk,
@@ -432,7 +472,11 @@
 		err = mlx5_wq_ll_create(mdev, &rqp->wq, rqc_wq, &rq->mpwqe.wq,
 					&rq->wq_ctrl);
 		if (err)
-			return err;
+			goto err_rq_wq_destroy;
+
+		err = mlx5e_alloc_mpwqe_rq_drop_page(rq);
+		if (err)
+			goto err_rq_wq_destroy;
 
 		rq->mpwqe.wq.db = &rq->mpwqe.wq.db[MLX5_RCV_DBR];
 
@@ -474,7 +518,7 @@
 
 		err = mlx5e_create_rq_umr_mkey(mdev, rq);
 		if (err)
-			goto err_rq_wq_destroy;
+			goto err_rq_drop_page;
 		rq->mkey_be = cpu_to_be32(rq->umr_mkey.key);
 
 		err = mlx5e_rq_alloc_mpwqe_info(rq, c);
@@ -485,7 +529,7 @@
 		err = mlx5_wq_cyc_create(mdev, &rqp->wq, rqc_wq, &rq->wqe.wq,
 					 &rq->wq_ctrl);
 		if (err)
-			return err;
+			goto err_rq_wq_destroy;
 
 		rq->wqe.wq.db = &rq->wqe.wq.db[MLX5_RCV_DBR];
 
@@ -622,6 +666,8 @@
 	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
 		kvfree(rq->mpwqe.info);
 		mlx5_core_destroy_mkey(mdev, &rq->umr_mkey);
+err_rq_drop_page:
+		mlx5e_free_mpwqe_rq_drop_page(rq);
 		break;
 	default: /* MLX5_WQ_TYPE_CYCLIC */
 		kvfree(rq->wqe.frags);
@@ -649,6 +695,7 @@
 	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
 		kvfree(rq->mpwqe.info);
 		mlx5_core_destroy_mkey(rq->mdev, &rq->umr_mkey);
+		mlx5e_free_mpwqe_rq_drop_page(rq);
 		break;
 	default: /* MLX5_WQ_TYPE_CYCLIC */
 		kvfree(rq->wqe.frags);
@@ -723,6 +770,9 @@
 	if (!in)
 		return -ENOMEM;
 
+	if (curr_state == MLX5_RQC_STATE_RST && next_state == MLX5_RQC_STATE_RDY)
+		mlx5e_rqwq_reset(rq);
+
 	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
 
 	MLX5_SET(modify_rq_in, in, rq_state, curr_state);
@@ -821,6 +871,29 @@
 	return -ETIMEDOUT;
 }
 
+void mlx5e_free_rx_in_progress_descs(struct mlx5e_rq *rq)
+{
+	struct mlx5_wq_ll *wq;
+	u16 head;
+	int i;
+
+	if (rq->wq_type != MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
+		return;
+
+	wq = &rq->mpwqe.wq;
+	head = wq->head;
+
+	/* Outstanding UMR WQEs (in progress) start at wq->head */
+	for (i = 0; i < rq->mpwqe.umr_in_progress; i++) {
+		rq->dealloc_wqe(rq, head);
+		head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
+	}
+
+	rq->mpwqe.actual_wq_head = wq->head;
+	rq->mpwqe.umr_in_progress = 0;
+	rq->mpwqe.umr_completed = 0;
+}
+
 void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
 {
 	__be16 wqe_ix_be;
@@ -828,14 +901,8 @@
 
 	if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
 		struct mlx5_wq_ll *wq = &rq->mpwqe.wq;
-		u16 head = wq->head;
-		int i;
 
-		/* Outstanding UMR WQEs (in progress) start at wq->head */
-		for (i = 0; i < rq->mpwqe.umr_in_progress; i++) {
-			rq->dealloc_wqe(rq, head);
-			head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
-		}
+		mlx5e_free_rx_in_progress_descs(rq);
 
 		while (!mlx5_wq_ll_is_empty(wq)) {
 			struct mlx5e_rx_wqe_ll *wqe;
@@ -1693,11 +1760,10 @@
 			  struct mlx5e_params *params,
 			  struct mlx5e_channel_param *cparam)
 {
-	struct mlx5e_priv *priv = c->priv;
 	int err, tc;
 
 	for (tc = 0; tc < params->num_tc; tc++) {
-		int txq_ix = c->ix + tc * priv->max_nch;
+		int txq_ix = c->ix + tc * params->num_channels;
 
 		err = mlx5e_open_txqsq(c, c->priv->tisn[c->lag_port][tc], txq_ix,
 				       params, &cparam->sq, &c->sq[tc], tc);
@@ -2299,8 +2365,9 @@
 {
 	switch (params->rq_wq_type) {
 	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
-		return order_base_2(MLX5E_UMR_WQEBBS) +
-			mlx5e_get_rq_log_wq_sz(rqp->rqc);
+		return max_t(u8, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE,
+			     order_base_2(MLX5E_UMR_WQEBBS) +
+			     mlx5e_get_rq_log_wq_sz(rqp->rqc));
 	default: /* MLX5_WQ_TYPE_CYCLIC */
 		return MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE;
 	}
@@ -2739,7 +2806,8 @@
 		mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen);
 	}
 
-	if (!mlx5e_tunnel_inner_ft_supported(priv->mdev))
+	/* Verify inner tirs resources allocated */
+	if (!priv->inner_indir_tir[0].tirn)
 		return;
 
 	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
@@ -2878,41 +2946,52 @@
 		netdev_set_tc_queue(netdev, tc, nch, 0);
 }
 
-static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv)
+static void mlx5e_update_netdev_queues(struct mlx5e_priv *priv)
 {
-	int i, tc;
+	int num_txqs = priv->channels.num * priv->channels.params.num_tc;
+	int num_rxqs = priv->channels.num * priv->profile->rq_groups;
+	struct net_device *netdev = priv->netdev;
 
-	for (i = 0; i < priv->max_nch; i++)
-		for (tc = 0; tc < priv->profile->max_tc; tc++)
-			priv->channel_tc2txq[i][tc] = i + tc * priv->max_nch;
+	mlx5e_netdev_set_tcs(netdev);
+	netif_set_real_num_tx_queues(netdev, num_txqs);
+	netif_set_real_num_rx_queues(netdev, num_rxqs);
 }
 
-static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
+int mlx5e_num_channels_changed(struct mlx5e_priv *priv)
 {
-	struct mlx5e_channel *c;
-	struct mlx5e_txqsq *sq;
-	int i, tc;
+	u16 count = priv->channels.params.num_channels;
+
+	if (!netif_is_rxfh_configured(priv->netdev))
+		mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt,
+					      MLX5E_INDIR_RQT_SIZE, count);
+
+	return 0;
+}
+
+static void mlx5e_build_txq_maps(struct mlx5e_priv *priv)
+{
+	int i, ch;
+
+	ch = priv->channels.num;
+
+	for (i = 0; i < ch; i++) {
+		int tc;
+
+		for (tc = 0; tc < priv->channels.params.num_tc; tc++) {
+			struct mlx5e_channel *c = priv->channels.c[i];
+			struct mlx5e_txqsq *sq = &c->sq[tc];
 
-	for (i = 0; i < priv->channels.num; i++) {
-		c = priv->channels.c[i];
-		for (tc = 0; tc < c->num_tc; tc++) {
-			sq = &c->sq[tc];
 			priv->txq2sq[sq->txq_ix] = sq;
+			priv->channel_tc2realtxq[i][tc] = i + tc * ch;
 		}
 	}
 }
 
 void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
 {
-	int num_txqs = priv->channels.num * priv->channels.params.num_tc;
-	int num_rxqs = priv->channels.num * priv->profile->rq_groups;
-	struct net_device *netdev = priv->netdev;
-
-	mlx5e_netdev_set_tcs(netdev);
-	netif_set_real_num_tx_queues(netdev, num_txqs);
-	netif_set_real_num_rx_queues(netdev, num_rxqs);
+	mlx5e_update_netdev_queues(priv);
 
-	mlx5e_build_tx2sq_maps(priv);
+	mlx5e_build_txq_maps(priv);
 	mlx5e_activate_channels(&priv->channels);
 	mlx5e_xdp_tx_enable(priv);
 	netif_tx_start_all_queues(priv->netdev);
@@ -2946,7 +3025,7 @@
 
 static void mlx5e_switch_priv_channels(struct mlx5e_priv *priv,
 				       struct mlx5e_channels *new_chs,
-				       mlx5e_fp_hw_modify hw_modify)
+				       mlx5e_fp_preactivate preactivate)
 {
 	struct net_device *netdev = priv->netdev;
 	int new_num_txqs;
@@ -2965,9 +3044,11 @@
 
 	priv->channels = *new_chs;
 
-	/* New channels are ready to roll, modify HW settings if needed */
-	if (hw_modify)
-		hw_modify(priv);
+	/* New channels are ready to roll, call the preactivate hook if needed
+	 * to modify HW settings or update kernel parameters.
+	 */
+	if (preactivate)
+		preactivate(priv);
 
 	priv->profile->update_rx(priv);
 	mlx5e_activate_priv_channels(priv);
@@ -2979,7 +3060,7 @@
 
 int mlx5e_safe_switch_channels(struct mlx5e_priv *priv,
 			       struct mlx5e_channels *new_chs,
-			       mlx5e_fp_hw_modify hw_modify)
+			       mlx5e_fp_preactivate preactivate)
 {
 	int err;
 
@@ -2987,7 +3068,7 @@
 	if (err)
 		return err;
 
-	mlx5e_switch_priv_channels(priv, new_chs, hw_modify);
+	mlx5e_switch_priv_channels(priv, new_chs, preactivate);
 	return 0;
 }
 
@@ -3005,15 +3086,32 @@
 	priv->tstamp.rx_filter = HWTSTAMP_FILTER_NONE;
 }
 
+static void mlx5e_modify_admin_state(struct mlx5_core_dev *mdev,
+				     enum mlx5_port_status state)
+{
+	struct mlx5_eswitch *esw = mdev->priv.eswitch;
+	int vport_admin_state;
+
+	mlx5_set_port_admin_status(mdev, state);
+
+	if (!MLX5_ESWITCH_MANAGER(mdev) || mlx5_eswitch_mode(esw) == MLX5_ESWITCH_OFFLOADS ||
+	    !MLX5_CAP_GEN(mdev, uplink_follow))
+		return;
+
+	if (state == MLX5_PORT_UP)
+		vport_admin_state = MLX5_VPORT_ADMIN_STATE_AUTO;
+	else
+		vport_admin_state = MLX5_VPORT_ADMIN_STATE_DOWN;
+
+	mlx5_eswitch_set_vport_state(esw, MLX5_VPORT_UPLINK, vport_admin_state);
+}
+
 int mlx5e_open_locked(struct net_device *netdev)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
-	bool is_xdp = priv->channels.params.xdp_prog;
 	int err;
 
 	set_bit(MLX5E_STATE_OPENED, &priv->state);
-	if (is_xdp)
-		mlx5e_xdp_set_open(priv);
 
 	err = mlx5e_open_channels(priv, &priv->channels);
 	if (err)
@@ -3028,8 +3126,6 @@
 	return 0;
 
 err_clear_state_opened_flag:
-	if (is_xdp)
-		mlx5e_xdp_set_closed(priv);
 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
 	return err;
 }
@@ -3042,7 +3138,7 @@
 	mutex_lock(&priv->state_lock);
 	err = mlx5e_open_locked(netdev);
 	if (!err)
-		mlx5_set_port_admin_status(priv->mdev, MLX5_PORT_UP);
+		mlx5e_modify_admin_state(priv->mdev, MLX5_PORT_UP);
 	mutex_unlock(&priv->state_lock);
 
 	if (mlx5_vxlan_allowed(priv->mdev->vxlan))
@@ -3061,8 +3157,6 @@
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
 		return 0;
 
-	if (priv->channels.params.xdp_prog)
-		mlx5e_xdp_set_closed(priv);
 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
 
 	netif_carrier_off(priv->netdev);
@@ -3081,7 +3175,7 @@
 		return -ENODEV;
 
 	mutex_lock(&priv->state_lock);
-	mlx5_set_port_admin_status(priv->mdev, MLX5_PORT_DOWN);
+	mlx5e_modify_admin_state(priv->mdev, MLX5_PORT_DOWN);
 	err = mlx5e_close_locked(netdev);
 	mutex_unlock(&priv->state_lock);
 
@@ -3380,14 +3474,15 @@
 	return err;
 }
 
-void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc)
+void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv)
 {
 	int i;
 
 	for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
 		mlx5e_destroy_tir(priv->mdev, &priv->indir_tir[i]);
 
-	if (!inner_ttc || !mlx5e_tunnel_inner_ft_supported(priv->mdev))
+	/* Verify inner tirs resources allocated */
+	if (!priv->inner_indir_tir[0].tirn)
 		return;
 
 	for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
@@ -3536,6 +3631,7 @@
 
 		s->rx_packets   += rq_stats->packets + xskrq_stats->packets;
 		s->rx_bytes     += rq_stats->bytes + xskrq_stats->bytes;
+		s->multicast    += rq_stats->mcast_packets + xskrq_stats->mcast_packets;
 
 		for (j = 0; j < priv->max_opened_tc; j++) {
 			struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
@@ -3551,10 +3647,14 @@
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
-	struct mlx5e_vport_stats *vstats = &priv->stats.vport;
 	struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 
-	if (!mlx5e_monitor_counter_supported(priv)) {
+	/* In switchdev mode, monitor counters doesn't monitor
+	 * rx/tx stats of 802_3. The update stats mechanism
+	 * should keep the 802_3 layout counters updated
+	 */
+	if (!mlx5e_monitor_counter_supported(priv) ||
+	    mlx5e_is_uplink_rep(priv)) {
 		/* update HW stats in background for next time */
 		mlx5e_queue_update_stats(priv);
 	}
@@ -3581,12 +3681,6 @@
 	stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors +
 			   stats->rx_frame_errors;
 	stats->tx_errors = stats->tx_aborted_errors + stats->tx_carrier_errors;
-
-	/* vport multicast also counts packets that are dropped due to steering
-	 * or rx out of buffer
-	 */
-	stats->multicast =
-		VPORT_COUNTER_GET(vstats, received_eth_multicast.packets);
 }
 
 static void mlx5e_set_rx_mode(struct net_device *dev)
@@ -3706,20 +3800,67 @@
 	return mlx5_set_port_fcs(mdev, !enable);
 }
 
+static int mlx5e_set_rx_port_ts(struct mlx5_core_dev *mdev, bool enable)
+{
+	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {};
+	bool supported, curr_state;
+	int err;
+
+	if (!MLX5_CAP_GEN(mdev, ports_check))
+		return 0;
+
+	err = mlx5_query_ports_check(mdev, in, sizeof(in));
+	if (err)
+		return err;
+
+	supported = MLX5_GET(pcmr_reg, in, rx_ts_over_crc_cap);
+	curr_state = MLX5_GET(pcmr_reg, in, rx_ts_over_crc);
+
+	if (!supported || enable == curr_state)
+		return 0;
+
+	MLX5_SET(pcmr_reg, in, local_port, 1);
+	MLX5_SET(pcmr_reg, in, rx_ts_over_crc, enable);
+
+	return mlx5_set_ports_check(mdev, in, sizeof(in));
+}
+
 static int set_feature_rx_fcs(struct net_device *netdev, bool enable)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct mlx5e_channels *chs = &priv->channels;
+	struct mlx5_core_dev *mdev = priv->mdev;
 	int err;
 
 	mutex_lock(&priv->state_lock);
 
-	priv->channels.params.scatter_fcs_en = enable;
-	err = mlx5e_modify_channels_scatter_fcs(&priv->channels, enable);
-	if (err)
-		priv->channels.params.scatter_fcs_en = !enable;
+	if (enable) {
+		err = mlx5e_set_rx_port_ts(mdev, false);
+		if (err)
+			goto out;
 
-	mutex_unlock(&priv->state_lock);
+		chs->params.scatter_fcs_en = true;
+		err = mlx5e_modify_channels_scatter_fcs(chs, true);
+		if (err) {
+			chs->params.scatter_fcs_en = false;
+			mlx5e_set_rx_port_ts(mdev, true);
+		}
+	} else {
+		chs->params.scatter_fcs_en = false;
+		err = mlx5e_modify_channels_scatter_fcs(chs, false);
+		if (err) {
+			chs->params.scatter_fcs_en = true;
+			goto out;
+		}
+		err = mlx5e_set_rx_port_ts(mdev, true);
+		if (err) {
+			mlx5_core_warn(mdev, "Failed to set RX port timestamp %d\n", err);
+			err = 0;
+		}
+	}
 
+out:
+	mutex_unlock(&priv->state_lock);
 	return err;
 }
 
@@ -3761,12 +3902,11 @@
 
 static int mlx5e_handle_feature(struct net_device *netdev,
 				netdev_features_t *features,
-				netdev_features_t wanted_features,
 				netdev_features_t feature,
 				mlx5e_feature_handler feature_handler)
 {
-	netdev_features_t changes = wanted_features ^ netdev->features;
-	bool enable = !!(wanted_features & feature);
+	netdev_features_t changes = *features ^ netdev->features;
+	bool enable = !!(*features & feature);
 	int err;
 
 	if (!(changes & feature))
@@ -3774,22 +3914,22 @@
 
 	err = feature_handler(netdev, enable);
 	if (err) {
+		MLX5E_SET_FEATURE(features, feature, !enable);
 		netdev_err(netdev, "%s feature %pNF failed, err %d\n",
 			   enable ? "Enable" : "Disable", &feature, err);
 		return err;
 	}
 
-	MLX5E_SET_FEATURE(features, feature, enable);
 	return 0;
 }
 
 int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
 {
-	netdev_features_t oper_features = netdev->features;
+	netdev_features_t oper_features = features;
 	int err = 0;
 
 #define MLX5E_HANDLE_FEATURE(feature, handler) \
-	mlx5e_handle_feature(netdev, &oper_features, features, feature, handler)
+	mlx5e_handle_feature(netdev, &oper_features, feature, handler)
 
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_LRO, set_feature_lro);
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_VLAN_CTAG_FILTER,
@@ -3835,6 +3975,13 @@
 		}
 	}
 
+	if (params->xdp_prog) {
+		if (features & NETIF_F_LRO) {
+			netdev_warn(netdev, "LRO is incompatible with XDP\n");
+			features &= ~NETIF_F_LRO;
+		}
+	}
+
 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS)) {
 		features &= ~NETIF_F_RXHASH;
 		if (netdev->features & NETIF_F_RXHASH)
@@ -4230,6 +4377,21 @@
 	mlx5e_vxlan_queue_work(priv, be16_to_cpu(ti->port), 0);
 }
 
+static bool mlx5e_gre_tunnel_inner_proto_offload_supported(struct mlx5_core_dev *mdev,
+							   struct sk_buff *skb)
+{
+	switch (skb->inner_protocol) {
+	case htons(ETH_P_IP):
+	case htons(ETH_P_IPV6):
+	case htons(ETH_P_TEB):
+		return true;
+	case htons(ETH_P_MPLS_UC):
+	case htons(ETH_P_MPLS_MC):
+		return MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_gre);
+	}
+	return false;
+}
+
 static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
 						     struct sk_buff *skb,
 						     netdev_features_t features)
@@ -4252,7 +4414,9 @@
 
 	switch (proto) {
 	case IPPROTO_GRE:
-		return features;
+		if (mlx5e_gre_tunnel_inner_proto_offload_supported(priv->mdev, skb))
+			return features;
+		break;
 	case IPPROTO_IPIP:
 	case IPPROTO_IPV6:
 		if (mlx5e_tunnel_proto_supported(priv->mdev, IPPROTO_IPIP))
@@ -4379,16 +4543,6 @@
 	return 0;
 }
 
-static int mlx5e_xdp_update_state(struct mlx5e_priv *priv)
-{
-	if (priv->channels.params.xdp_prog)
-		mlx5e_xdp_set_open(priv);
-	else
-		mlx5e_xdp_set_closed(priv);
-
-	return 0;
-}
-
 static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -4428,7 +4582,7 @@
 		mlx5e_set_rq_type(priv->mdev, &new_channels.params);
 		old_prog = priv->channels.params.xdp_prog;
 
-		err = mlx5e_safe_switch_channels(priv, &new_channels, mlx5e_xdp_update_state);
+		err = mlx5e_safe_switch_channels(priv, &new_channels, NULL);
 		if (err)
 			goto unlock;
 	} else {
@@ -4479,6 +4633,11 @@
 
 unlock:
 	mutex_unlock(&priv->state_lock);
+
+	/* Need to fix some features. */
+	if (!err)
+		netdev_update_features(netdev);
+
 	return err;
 }
 
@@ -4906,6 +5065,8 @@
 		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL |
 					   NETIF_F_GSO_UDP_TUNNEL_CSUM;
 		netdev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
+		netdev->vlan_features |= NETIF_F_GSO_UDP_TUNNEL |
+					 NETIF_F_GSO_UDP_TUNNEL_CSUM;
 	}
 
 	if (mlx5e_tunnel_proto_supported(mdev, IPPROTO_GRE)) {
@@ -5028,7 +5189,6 @@
 	if (err)
 		mlx5_core_err(mdev, "TLS initialization failed, %d\n", err);
 	mlx5e_build_nic_netdev(netdev);
-	mlx5e_build_tc2txq_maps(priv);
 	mlx5e_health_create_reporters(priv);
 
 	return 0;
@@ -5100,7 +5260,7 @@
 err_destroy_direct_tirs:
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
 err_destroy_indirect_tirs:
-	mlx5e_destroy_indirect_tirs(priv, true);
+	mlx5e_destroy_indirect_tirs(priv);
 err_destroy_direct_rqts:
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 err_destroy_indirect_rqts:
@@ -5119,7 +5279,7 @@
 	mlx5e_destroy_direct_tirs(priv, priv->xsk_tir);
 	mlx5e_destroy_direct_rqts(priv, priv->xsk_tir);
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
-	mlx5e_destroy_indirect_tirs(priv, true);
+	mlx5e_destroy_indirect_tirs(priv);
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 	mlx5e_destroy_rqt(priv, &priv->indir_rqt);
 	mlx5e_close_drop_rq(&priv->drop_rq);
@@ -5151,7 +5311,7 @@
 
 	/* Marking the link as currently not needed by the Driver */
 	if (!netif_running(netdev))
-		mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN);
+		mlx5e_modify_admin_state(mdev, MLX5_PORT_DOWN);
 
 	mlx5e_set_netdev_mtu_boundaries(priv);
 	mlx5e_set_dev_port_mtu(priv);
@@ -5312,9 +5472,10 @@
 	max_nch = mlx5e_get_max_num_channels(priv->mdev);
 	if (priv->channels.params.num_channels > max_nch) {
 		mlx5_core_warn(priv->mdev, "MLX5E: Reducing number of channels to %d\n", max_nch);
+		/* Reducing the number of channels - RXFH has to be reset. */
+		priv->netdev->priv_flags &= ~IFF_RXFH_CONFIGURED;
 		priv->channels.params.num_channels = max_nch;
-		mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt,
-					      MLX5E_INDIR_RQT_SIZE, max_nch);
+		mlx5e_num_channels_changed(priv);
 	}
 
 	err = profile->init_tx(priv);
@@ -5334,6 +5495,8 @@
 	profile->cleanup_tx(priv);
 
 out:
+	set_bit(MLX5E_STATE_DESTROYING, &priv->state);
+	cancel_work_sync(&priv->update_stats_work);
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -71,14 +71,17 @@
 {
 	struct mlx5e_priv *priv = netdev_priv(dev);
 	struct mlx5_core_dev *mdev = priv->mdev;
+	int count;
 
 	strlcpy(drvinfo->driver, mlx5e_rep_driver_name,
 		sizeof(drvinfo->driver));
-	strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
-	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
-		 "%d.%d.%04d (%.16s)",
-		 fw_rev_maj(mdev), fw_rev_min(mdev),
-		 fw_rev_sub(mdev), mdev->board_id);
+	count = snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+			 "%d.%d.%04d (%.16s)", fw_rev_maj(mdev),
+			 fw_rev_min(mdev), fw_rev_sub(mdev), mdev->board_id);
+	if (count >= sizeof(drvinfo->fw_version))
+		snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+			 "%d.%d.%04d", fw_rev_maj(mdev),
+			 fw_rev_min(mdev), fw_rev_sub(mdev));
 }
 
 static void mlx5e_uplink_rep_get_drvinfo(struct net_device *dev,
@@ -1434,6 +1437,8 @@
 
 	params->num_tc                = 1;
 	params->tunneled_offload_en = false;
+	if (rep->vport != MLX5_VPORT_UPLINK)
+		params->vlan_strip_disable = true;
 
 	mlx5_query_min_inline(mdev, &params->tx_min_inline_mode);
 
@@ -1597,7 +1602,7 @@
 err_destroy_direct_tirs:
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
 err_destroy_indirect_tirs:
-	mlx5e_destroy_indirect_tirs(priv, false);
+	mlx5e_destroy_indirect_tirs(priv);
 err_destroy_direct_rqts:
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 err_destroy_indirect_rqts:
@@ -1614,7 +1619,7 @@
 	mlx5_del_flow_rules(rpriv->vport_rx_rule);
 	mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
-	mlx5e_destroy_indirect_tirs(priv, false);
+	mlx5e_destroy_indirect_tirs(priv);
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 	mlx5e_destroy_rqt(priv, &priv->indir_rqt);
 	mlx5e_close_drop_rq(&priv->drop_rq);
@@ -1736,6 +1741,9 @@
 	INIT_WORK(&rpriv->uplink_priv.reoffload_flows_work,
 		  mlx5e_tc_reoffload_flows_work);
 
+	if (MLX5_CAP_GEN(mdev, uplink_follow))
+		mlx5_modify_vport_admin_state(mdev, MLX5_VPORT_STATE_OP_MOD_UPLINK,
+					      0, 0, MLX5_VPORT_ADMIN_STATE_AUTO);
 	mlx5_lag_add(mdev, netdev);
 	priv->events_nb.notifier_call = uplink_rep_async_event;
 	mlx5_notifier_register(mdev, &priv->events_nb);
@@ -1814,29 +1822,30 @@
 	struct mlx5_eswitch_rep *rep = rpriv->rep;
 	struct netdev_phys_item_id ppid = {};
 	unsigned int dl_port_index = 0;
+	u16 pfnum;
 
 	if (!is_devlink_port_supported(dev, rpriv))
 		return 0;
 
 	mlx5e_rep_get_port_parent_id(rpriv->netdev, &ppid);
+	pfnum = PCI_FUNC(dev->pdev->devfn);
 
 	if (rep->vport == MLX5_VPORT_UPLINK) {
 		devlink_port_attrs_set(&rpriv->dl_port,
 				       DEVLINK_PORT_FLAVOUR_PHYSICAL,
-				       PCI_FUNC(dev->pdev->devfn), false, 0,
+				       pfnum, false, 0,
 				       &ppid.id[0], ppid.id_len);
 		dl_port_index = vport_to_devlink_port_index(dev, rep->vport);
 	} else if (rep->vport == MLX5_VPORT_PF) {
 		devlink_port_attrs_pci_pf_set(&rpriv->dl_port,
 					      &ppid.id[0], ppid.id_len,
-					      dev->pdev->devfn);
+					      pfnum);
 		dl_port_index = rep->vport;
 	} else if (mlx5_eswitch_is_vf_vport(dev->priv.eswitch,
 					    rpriv->rep->vport)) {
 		devlink_port_attrs_pci_vf_set(&rpriv->dl_port,
 					      &ppid.id[0], ppid.id_len,
-					      dev->pdev->devfn,
-					      rep->vport - 1);
+					      pfnum, rep->vport - 1);
 		dl_port_index = vport_to_devlink_port_index(dev, rep->vport);
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -49,6 +49,7 @@
 #include "en/xdp.h"
 #include "en/xsk/rx.h"
 #include "en/health.h"
+#include "en/txrx.h"
 
 static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
 {
@@ -247,8 +248,8 @@
 	if (unlikely(!dma_info->page))
 		return -ENOMEM;
 
-	dma_info->addr = dma_map_page(rq->pdev, dma_info->page, 0,
-				      PAGE_SIZE, rq->buff.map_dir);
+	dma_info->addr = dma_map_page_attrs(rq->pdev, dma_info->page, 0, PAGE_SIZE,
+					    rq->buff.map_dir, DMA_ATTR_SKIP_CPU_SYNC);
 	if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
 		page_pool_recycle_direct(rq->page_pool, dma_info->page);
 		dma_info->page = NULL;
@@ -269,7 +270,8 @@
 
 void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info)
 {
-	dma_unmap_page(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir);
+	dma_unmap_page_attrs(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir,
+			     DMA_ATTR_SKIP_CPU_SYNC);
 }
 
 void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
@@ -477,6 +479,7 @@
 	/* fill sq frag edge with nops to avoid wqe wrapping two pages */
 	for (; wi < edge_wi; wi++) {
 		wi->opcode = MLX5_OPCODE_NOP;
+		wi->num_wqebbs = 1;
 		mlx5e_post_nop(wq, sq->sqn, &sq->pc);
 	}
 }
@@ -525,6 +528,7 @@
 	umr_wqe->uctrl.xlt_offset = cpu_to_be16(xlt_offset);
 
 	sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_UMR;
+	sq->db.ico_wqe[pi].num_wqebbs = MLX5E_UMR_WQEBBS;
 	sq->db.ico_wqe[pi].umr.rq = rq;
 	sq->pc += MLX5E_UMR_WQEBBS;
 
@@ -585,7 +589,7 @@
 	return !!err;
 }
 
-void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
+int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
 {
 	struct mlx5e_icosq *sq = container_of(cq, struct mlx5e_icosq, cq);
 	struct mlx5_cqe64 *cqe;
@@ -593,11 +597,11 @@
 	int i;
 
 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
-		return;
+		return 0;
 
 	cqe = mlx5_cqwq_get_cqe(&cq->wq);
 	if (likely(!cqe))
-		return;
+		return 0;
 
 	/* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
 	 * otherwise a cq overrun may occur
@@ -628,17 +632,14 @@
 
 			ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
 			wi = &sq->db.ico_wqe[ci];
+			sqcc += wi->num_wqebbs;
 
-			if (likely(wi->opcode == MLX5_OPCODE_UMR)) {
-				sqcc += MLX5E_UMR_WQEBBS;
+			if (likely(wi->opcode == MLX5_OPCODE_UMR))
 				wi->umr.rq->mpwqe.umr_completed++;
-			} else if (likely(wi->opcode == MLX5_OPCODE_NOP)) {
-				sqcc++;
-			} else {
+			else if (unlikely(wi->opcode != MLX5_OPCODE_NOP))
 				netdev_WARN_ONCE(cq->channel->netdev,
 						 "Bad OPCODE in ICOSQ WQE info: 0x%x\n",
 						 wi->opcode);
-			}
 
 		} while (!last_wqe);
 
@@ -647,6 +648,8 @@
 	sq->cc = sqcc;
 
 	mlx5_cqwq_update_db_record(&cq->wq);
+
+	return i;
 }
 
 bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
@@ -1021,6 +1024,9 @@
 		mlx5e_enable_ecn(rq, skb);
 
 	skb->protocol = eth_type_trans(skb, netdev);
+
+	if (unlikely(mlx5e_skb_is_multicast(skb)))
+		stats->mcast_packets++;
 }
 
 static inline void mlx5e_complete_rx_cqe(struct mlx5e_rq *rq,
@@ -1427,6 +1433,7 @@
 
 #ifdef CONFIG_MLX5_CORE_IPOIB
 
+#define MLX5_IB_GRH_SGID_OFFSET 8
 #define MLX5_IB_GRH_DGID_OFFSET 24
 #define MLX5_GID_SIZE           16
 
@@ -1440,6 +1447,7 @@
 	struct net_device *netdev;
 	struct mlx5e_priv *priv;
 	char *pseudo_header;
+	u32 flags_rqpn;
 	u32 qpn;
 	u8 *dgid;
 	u8 g;
@@ -1461,7 +1469,8 @@
 	tstamp = &priv->tstamp;
 	stats = &priv->channel_stats[rq->ix].rq;
 
-	g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
+	flags_rqpn = be32_to_cpu(cqe->flags_rqpn);
+	g = (flags_rqpn >> 28) & 3;
 	dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET;
 	if ((!g) || dgid[0] != 0xff)
 		skb->pkt_type = PACKET_HOST;
@@ -1470,9 +1479,15 @@
 	else
 		skb->pkt_type = PACKET_MULTICAST;
 
-	/* TODO: IB/ipoib: Allow mcast packets from other VFs
-	 * 68996a6e760e5c74654723eeb57bf65628ae87f4
+	/* Drop packets that this interface sent, ie multicast packets
+	 * that the HCA has replicated.
 	 */
+	if (g && (qpn == (flags_rqpn & 0xffffff)) &&
+	    (memcmp(netdev->dev_addr + 4, skb->data + MLX5_IB_GRH_SGID_OFFSET,
+		    MLX5_GID_SIZE) == 0)) {
+		skb->dev = NULL;
+		return;
+	}
 
 	skb_pull(skb, MLX5_IB_GRH_BYTES);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -297,6 +297,9 @@
 			s->tx_tls_drop_bypass_req   += sq_stats->tls_drop_bypass_req;
 #endif
 			s->tx_cqes		+= sq_stats->cqes;
+
+			/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92657 */
+			barrier();
 		}
 	}
 }
@@ -1601,7 +1604,7 @@
 			for (j = 0; j < NUM_SQ_STATS; j++)
 				sprintf(data + (idx++) * ETH_GSTRING_LEN,
 					sq_stats_desc[j].format,
-					priv->channel_tc2txq[i][tc]);
+					i + tc * max_nch);
 
 	for (i = 0; i < max_nch; i++) {
 		for (j = 0; j < NUM_XSKSQ_STATS * is_xsk; j++)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -68,6 +68,7 @@
 	u64 tx_nop;
 	u64 rx_lro_packets;
 	u64 rx_lro_bytes;
+	u64 rx_mcast_packets;
 	u64 rx_ecn_mark;
 	u64 rx_removed_vlan_packets;
 	u64 rx_csum_unnecessary;
@@ -235,6 +236,7 @@
 	u64 csum_none;
 	u64 lro_packets;
 	u64 lro_bytes;
+	u64 mcast_packets;
 	u64 ecn_mark;
 	u64 removed_vlan_packets;
 	u64 xdp_drop;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -57,6 +57,7 @@
 #include "lib/devcom.h"
 #include "lib/geneve.h"
 #include "diag/en_tc_tracepoint.h"
+#include <asm/div64.h>
 
 struct mlx5_nic_flow_attr {
 	u32 action;
@@ -443,12 +444,32 @@
 static
 struct mlx5_core_dev *mlx5e_hairpin_get_mdev(struct net *net, int ifindex)
 {
+	struct mlx5_core_dev *mdev;
 	struct net_device *netdev;
 	struct mlx5e_priv *priv;
 
-	netdev = __dev_get_by_index(net, ifindex);
+	netdev = dev_get_by_index(net, ifindex);
+	if (!netdev)
+		return ERR_PTR(-ENODEV);
+
 	priv = netdev_priv(netdev);
-	return priv->mdev;
+	mdev = priv->mdev;
+	dev_put(netdev);
+
+	/* Mirred tc action holds a refcount on the ifindex net_device (see
+	 * net/sched/act_mirred.c:tcf_mirred_get_dev). So, it's okay to continue using mdev
+	 * after dev_put(netdev), while we're in the context of adding a tc flow.
+	 *
+	 * The mdev pointer corresponds to the peer/out net_device of a hairpin. It is then
+	 * stored in a hairpin object, which exists until all flows, that refer to it, get
+	 * removed.
+	 *
+	 * On the other hand, after a hairpin object has been created, the peer net_device may
+	 * be removed/unbound while there are still some hairpin flows that are using it. This
+	 * case is handled by mlx5e_tc_hairpin_update_dead_peer, which is hooked to
+	 * NETDEV_UNREGISTER event of the peer net_device.
+	 */
+	return mdev;
 }
 
 static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp)
@@ -586,7 +607,7 @@
 	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
 		ttc_params->indir_tirn[tt] = hp->indir_tirn[tt];
 
-	ft_attr->max_fte = MLX5E_NUM_TT;
+	ft_attr->max_fte = MLX5E_TTC_TABLE_SIZE;
 	ft_attr->level = MLX5E_TC_TTC_FT_LEVEL;
 	ft_attr->prio = MLX5E_TC_PRIO;
 }
@@ -647,6 +668,10 @@
 
 	func_mdev = priv->mdev;
 	peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+	if (IS_ERR(peer_mdev)) {
+		err = PTR_ERR(peer_mdev);
+		goto create_pair_err;
+	}
 
 	pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params);
 	if (IS_ERR(pair)) {
@@ -785,6 +810,11 @@
 	int err;
 
 	peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+	if (IS_ERR(peer_mdev)) {
+		NL_SET_ERR_MSG_MOD(extack, "invalid ifindex of mirred device");
+		return PTR_ERR(peer_mdev);
+	}
+
 	if (!MLX5_CAP_GEN(priv->mdev, hairpin) || !MLX5_CAP_GEN(peer_mdev, hairpin)) {
 		NL_SET_ERR_MSG_MOD(extack, "hairpin is not supported");
 		return -EOPNOTSUPP;
@@ -1615,8 +1645,11 @@
 
 	flow_flag_clear(flow, DUP);
 
-	mlx5e_tc_del_fdb_flow(flow->peer_flow->priv, flow->peer_flow);
-	kvfree(flow->peer_flow);
+	if (refcount_dec_and_test(&flow->peer_flow->refcnt)) {
+		mlx5e_tc_del_fdb_flow(flow->peer_flow->priv, flow->peer_flow);
+		kfree(flow->peer_flow);
+	}
+
 	flow->peer_flow = NULL;
 }
 
@@ -1834,8 +1867,8 @@
 	      BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
 	      BIT(FLOW_DISSECTOR_KEY_ENC_OPTS))) {
 		NL_SET_ERR_MSG_MOD(extack, "Unsupported key");
-		netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
-			    dissector->used_keys);
+		netdev_dbg(priv->netdev, "Unsupported key used: 0x%x\n",
+			   dissector->used_keys);
 		return -EOPNOTSUPP;
 	}
 
@@ -2421,10 +2454,11 @@
 		field_bsize = f->size * BITS_PER_BYTE;
 
 		if (field_bsize == 32) {
-			mask_be32 = *(__be32 *)&mask;
+			mask_be32 = (__be32)mask;
 			mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
 		} else if (field_bsize == 16) {
-			mask_be16 = *(__be16 *)&mask;
+			mask_be32 = (__be32)mask;
+			mask_be16 = *(__be16 *)&mask_be32;
 			mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
 		}
 
@@ -3166,8 +3200,12 @@
 	if (err)
 		return err;
 
-	*out_dev = dev_get_by_index_rcu(dev_net(vlan_dev),
-					dev_get_iflink(vlan_dev));
+	rcu_read_lock();
+	*out_dev = dev_get_by_index_rcu(dev_net(vlan_dev), dev_get_iflink(vlan_dev));
+	rcu_read_unlock();
+	if (!*out_dev)
+		return -ENODEV;
+
 	if (is_vlan_dev(*out_dev))
 		err = add_vlan_push_action(priv, attr, out_dev, action);
 
@@ -3178,12 +3216,13 @@
 			       struct mlx5_esw_flow_attr *attr,
 			       u32 *action)
 {
-	int nest_level = attr->parse_attr->filter_dev->lower_level;
 	struct flow_action_entry vlan_act = {
 		.id = FLOW_ACTION_VLAN_POP,
 	};
-	int err = 0;
+	int nest_level, err = 0;
 
+	nest_level = attr->parse_attr->filter_dev->lower_level -
+						priv->netdev->lower_level;
 	while (nest_level--) {
 		err = parse_tc_vlan_action(priv, &vlan_act, attr, action);
 		if (err)
@@ -3443,6 +3482,12 @@
 		attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
 	}
 
+	if (!(attr->action &
+	      (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+		NL_SET_ERR_MSG(extack, "Rule must have at least one forward/drop action");
+		return -EOPNOTSUPP;
+	}
+
 	if (attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "current firmware doesn't support split rule for port mirroring");
@@ -3933,15 +3978,22 @@
 	return err;
 }
 
-static int apply_police_params(struct mlx5e_priv *priv, u32 rate,
+static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
 			       struct netlink_ext_ack *extack)
 {
 	struct mlx5e_rep_priv *rpriv = priv->ppriv;
 	struct mlx5_eswitch *esw;
+	u32 rate_mbps = 0;
 	u16 vport_num;
-	u32 rate_mbps;
 	int err;
 
+	vport_num = rpriv->rep->vport;
+	if (vport_num >= MLX5_VPORT_ECPF) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Ingress rate limit is supported only for Eswitch ports connected to VFs");
+		return -EOPNOTSUPP;
+	}
+
 	esw = priv->mdev->priv.eswitch;
 	/* rate is given in bytes/sec.
 	 * First convert to bits/sec and then round to the nearest mbit/secs.
@@ -3949,8 +4001,10 @@
 	 * Moreover, if rate is non zero we choose to configure to a minimum of
 	 * 1 mbit/sec.
 	 */
-	rate_mbps = rate ? max_t(u32, (rate * 8 + 500000) / 1000000, 1) : 0;
-	vport_num = rpriv->rep->vport;
+	if (rate) {
+		rate = (rate * BITS_PER_BYTE) + 500000;
+		rate_mbps = max_t(u32, do_div(rate, 1000000), 1);
+	}
 
 	err = mlx5_esw_modify_vport_rate(esw, vport_num, rate_mbps);
 	if (err)
@@ -4055,7 +4109,7 @@
 	list_for_each_entry_safe(hpe, tmp, &init_wait_list, dead_peer_wait_list) {
 		wait_for_completion(&hpe->res_ready);
 		if (!IS_ERR_OR_NULL(hpe->hp) && hpe->peer_vhca_id == peer_vhca_id)
-			hpe->hp->pair->peer_gone = true;
+			mlx5_core_hairpin_clear_dead_peer(hpe->hp->pair);
 
 		mlx5e_hairpin_put(priv, hpe);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -93,7 +93,7 @@
 	if (txq_ix >= num_channels)
 		txq_ix = priv->txq2sq[txq_ix]->ch_ix;
 
-	return priv->channel_tc2txq[txq_ix][up];
+	return priv->channel_tc2realtxq[txq_ix][up];
 }
 
 static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
@@ -341,8 +341,8 @@
 	dseg =  wqe->data;
 
 #if IS_ENABLED(CONFIG_GENEVE)
-	if (skb->encapsulation)
-		mlx5e_tx_tunnel_accel(skb, eseg);
+	if (skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL)
+		mlx5e_tx_tunnel_accel(skb, eseg, ihs);
 #endif
 	mlx5e_txwqe_build_eseg_csum(sq, skb, eseg);
 
@@ -537,10 +537,9 @@
 void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
 {
 	struct mlx5e_tx_wqe_info *wi;
+	u32 dma_fifo_cc, nbytes = 0;
+	u16 ci, sqcc, npkts = 0;
 	struct sk_buff *skb;
-	u32 dma_fifo_cc;
-	u16 sqcc;
-	u16 ci;
 	int i;
 
 	sqcc = sq->cc;
@@ -565,11 +564,15 @@
 		}
 
 		dev_kfree_skb_any(skb);
+		npkts++;
+		nbytes += wi->num_bytes;
 		sqcc += wi->num_wqebbs;
 	}
 
 	sq->dma_fifo_cc = dma_fifo_cc;
 	sq->cc = sqcc;
+
+	netdev_tx_completed_queue(sq->txq, npkts, nbytes);
 }
 
 #ifdef CONFIG_MLX5_CORE_IPOIB
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -78,6 +78,7 @@
 	u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 
 	sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_NOP;
+	sq->db.ico_wqe[pi].num_wqebbs = 1;
 	nopwqe = mlx5e_post_nop(wq, sq->sqn, &sq->pc);
 	mlx5e_notify_hw(wq, sq->pc, sq->uar_map, &nopwqe->ctrl);
 }
@@ -144,7 +145,11 @@
 
 	busy |= rq->post_wqes(rq);
 	if (xsk_open) {
-		mlx5e_poll_ico_cq(&c->xskicosq.cq);
+		if (mlx5e_poll_ico_cq(&c->xskicosq.cq))
+			/* Don't clear the flag if nothing was polled to prevent
+			 * queueing more WQEs and overflowing XSKICOSQ.
+			 */
+			clear_bit(MLX5E_SQ_STATE_PENDING_XSK_TX, &c->xskicosq.state);
 		busy |= mlx5e_poll_xdpsq_cq(&xsksq->cq);
 		busy_xsk |= mlx5e_napi_xsk_post(xsksq, xskrq);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -190,6 +190,29 @@
 	return count_eqe;
 }
 
+static void mlx5_eq_async_int_lock(struct mlx5_eq_async *eq, unsigned long *flags)
+	__acquires(&eq->lock)
+{
+	if (in_irq())
+		spin_lock(&eq->lock);
+	else
+		spin_lock_irqsave(&eq->lock, *flags);
+}
+
+static void mlx5_eq_async_int_unlock(struct mlx5_eq_async *eq, unsigned long *flags)
+	__releases(&eq->lock)
+{
+	if (in_irq())
+		spin_unlock(&eq->lock);
+	else
+		spin_unlock_irqrestore(&eq->lock, *flags);
+}
+
+enum async_eq_nb_action {
+	ASYNC_EQ_IRQ_HANDLER = 0,
+	ASYNC_EQ_RECOVER = 1,
+};
+
 static int mlx5_eq_async_int(struct notifier_block *nb,
 			     unsigned long action, void *data)
 {
@@ -199,11 +222,14 @@
 	struct mlx5_eq_table *eqt;
 	struct mlx5_core_dev *dev;
 	struct mlx5_eqe *eqe;
+	unsigned long flags;
 	int num_eqes = 0;
 
 	dev = eq->dev;
 	eqt = dev->priv.eq_table;
 
+	mlx5_eq_async_int_lock(eq_async, &flags);
+
 	eqe = next_eqe_sw(eq);
 	if (!eqe)
 		goto out;
@@ -224,8 +250,19 @@
 
 out:
 	eq_update_ci(eq, 1);
+	mlx5_eq_async_int_unlock(eq_async, &flags);
 
-	return 0;
+	return unlikely(action == ASYNC_EQ_RECOVER) ? num_eqes : 0;
+}
+
+void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev)
+{
+	struct mlx5_eq_async *eq = &dev->priv.eq_table->cmd_eq;
+	int eqes;
+
+	eqes = mlx5_eq_async_int(&eq->irq_nb, ASYNC_EQ_RECOVER, NULL);
+	if (eqes)
+		mlx5_core_warn(dev, "Recovered %d EQEs on cmd_eq\n", eqes);
 }
 
 static void init_eq_buf(struct mlx5_eq *eq)
@@ -563,6 +600,40 @@
 		gather_user_async_events(dev, mask);
 }
 
+static int
+setup_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq_async *eq,
+	       struct mlx5_eq_param *param, const char *name)
+{
+	int err;
+
+	eq->irq_nb.notifier_call = mlx5_eq_async_int;
+	spin_lock_init(&eq->lock);
+
+	err = create_async_eq(dev, &eq->core, param);
+	if (err) {
+		mlx5_core_warn(dev, "failed to create %s EQ %d\n", name, err);
+		return err;
+	}
+	err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
+	if (err) {
+		mlx5_core_warn(dev, "failed to enable %s EQ %d\n", name, err);
+		destroy_async_eq(dev, &eq->core);
+	}
+	return err;
+}
+
+static void cleanup_async_eq(struct mlx5_core_dev *dev,
+			     struct mlx5_eq_async *eq, const char *name)
+{
+	int err;
+
+	mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
+	err = destroy_async_eq(dev, &eq->core);
+	if (err)
+		mlx5_core_err(dev, "failed to destroy %s eq, err(%d)\n",
+			      name, err);
+}
+
 static int create_async_eqs(struct mlx5_core_dev *dev)
 {
 	struct mlx5_eq_table *table = dev->priv.eq_table;
@@ -572,77 +643,48 @@
 	MLX5_NB_INIT(&table->cq_err_nb, cq_err_event_notifier, CQ_ERROR);
 	mlx5_eq_notifier_register(dev, &table->cq_err_nb);
 
-	table->cmd_eq.irq_nb.notifier_call = mlx5_eq_async_int;
 	param = (struct mlx5_eq_param) {
 		.irq_index = 0,
 		.nent = MLX5_NUM_CMD_EQE,
+		.mask[0] = 1ull << MLX5_EVENT_TYPE_CMD,
 	};
-
-	param.mask[0] = 1ull << MLX5_EVENT_TYPE_CMD;
-	err = create_async_eq(dev, &table->cmd_eq.core, &param);
-	if (err) {
-		mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
-		goto err0;
-	}
-	err = mlx5_eq_enable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
-	if (err) {
-		mlx5_core_warn(dev, "failed to enable cmd EQ %d\n", err);
+	mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_CREATE_EQ);
+	err = setup_async_eq(dev, &table->cmd_eq, &param, "cmd");
+	if (err)
 		goto err1;
-	}
+
 	mlx5_cmd_use_events(dev);
+	mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
 
-	table->async_eq.irq_nb.notifier_call = mlx5_eq_async_int;
 	param = (struct mlx5_eq_param) {
 		.irq_index = 0,
 		.nent = MLX5_NUM_ASYNC_EQE,
 	};
 
 	gather_async_events_mask(dev, param.mask);
-	err = create_async_eq(dev, &table->async_eq.core, &param);
-	if (err) {
-		mlx5_core_warn(dev, "failed to create async EQ %d\n", err);
+	err = setup_async_eq(dev, &table->async_eq, &param, "async");
+	if (err)
 		goto err2;
-	}
-	err = mlx5_eq_enable(dev, &table->async_eq.core,
-			     &table->async_eq.irq_nb);
-	if (err) {
-		mlx5_core_warn(dev, "failed to enable async EQ %d\n", err);
-		goto err3;
-	}
 
-	table->pages_eq.irq_nb.notifier_call = mlx5_eq_async_int;
 	param = (struct mlx5_eq_param) {
 		.irq_index = 0,
 		.nent = /* TODO: sriov max_vf + */ 1,
+		.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST,
 	};
 
-	param.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST;
-	err = create_async_eq(dev, &table->pages_eq.core, &param);
-	if (err) {
-		mlx5_core_warn(dev, "failed to create pages EQ %d\n", err);
-		goto err4;
-	}
-	err = mlx5_eq_enable(dev, &table->pages_eq.core,
-			     &table->pages_eq.irq_nb);
-	if (err) {
-		mlx5_core_warn(dev, "failed to enable pages EQ %d\n", err);
-		goto err5;
-	}
+	err = setup_async_eq(dev, &table->pages_eq, &param, "pages");
+	if (err)
+		goto err3;
 
-	return err;
+	return 0;
 
-err5:
-	destroy_async_eq(dev, &table->pages_eq.core);
-err4:
-	mlx5_eq_disable(dev, &table->async_eq.core, &table->async_eq.irq_nb);
 err3:
-	destroy_async_eq(dev, &table->async_eq.core);
+	cleanup_async_eq(dev, &table->async_eq, "async");
 err2:
 	mlx5_cmd_use_polling(dev);
-	mlx5_eq_disable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
+	cleanup_async_eq(dev, &table->cmd_eq, "cmd");
 err1:
-	destroy_async_eq(dev, &table->cmd_eq.core);
-err0:
+	mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
 	mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
 	return err;
 }
@@ -650,28 +692,13 @@
 static void destroy_async_eqs(struct mlx5_core_dev *dev)
 {
 	struct mlx5_eq_table *table = dev->priv.eq_table;
-	int err;
-
-	mlx5_eq_disable(dev, &table->pages_eq.core, &table->pages_eq.irq_nb);
-	err = destroy_async_eq(dev, &table->pages_eq.core);
-	if (err)
-		mlx5_core_err(dev, "failed to destroy pages eq, err(%d)\n",
-			      err);
-
-	mlx5_eq_disable(dev, &table->async_eq.core, &table->async_eq.irq_nb);
-	err = destroy_async_eq(dev, &table->async_eq.core);
-	if (err)
-		mlx5_core_err(dev, "failed to destroy async eq, err(%d)\n",
-			      err);
 
+	cleanup_async_eq(dev, &table->pages_eq, "pages");
+	cleanup_async_eq(dev, &table->async_eq, "async");
+	mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_DESTROY_EQ);
 	mlx5_cmd_use_polling(dev);
-
-	mlx5_eq_disable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
-	err = destroy_async_eq(dev, &table->cmd_eq.core);
-	if (err)
-		mlx5_core_err(dev, "failed to destroy command eq, err(%d)\n",
-			      err);
-
+	cleanup_async_eq(dev, &table->cmd_eq, "cmd");
+	mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
 	mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
 }
 
@@ -901,13 +928,24 @@
 	mutex_unlock(&table->lock);
 }
 
+#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
+#define MLX5_MAX_ASYNC_EQS 4
+#else
+#define MLX5_MAX_ASYNC_EQS 3
+#endif
+
 int mlx5_eq_table_create(struct mlx5_core_dev *dev)
 {
 	struct mlx5_eq_table *eq_table = dev->priv.eq_table;
+	int num_eqs = MLX5_CAP_GEN(dev, max_num_eqs) ?
+		      MLX5_CAP_GEN(dev, max_num_eqs) :
+		      1 << MLX5_CAP_GEN(dev, log_max_eq);
 	int err;
 
 	eq_table->num_comp_eqs =
-		mlx5_irq_get_num_comp(eq_table->irq_table);
+		min_t(int,
+		      mlx5_irq_get_num_comp(eq_table->irq_table),
+		      num_eqs - MLX5_MAX_ASYNC_EQS);
 
 	err = create_async_eqs(dev);
 	if (err) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1592,6 +1592,10 @@
 	struct mlx5_vport *vport;
 
 	vport = mlx5_eswitch_get_vport(esw, vport_num);
+
+	if (!vport->qos.enabled)
+		return -EOPNOTSUPP;
+
 	MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
 
 	return mlx5_modify_scheduling_element_cmd(esw->dev,
@@ -1919,7 +1923,7 @@
 		mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
 		mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
 	}
-
+	esw_destroy_tsar(esw);
 	return err;
 }
 
@@ -2094,6 +2098,8 @@
 				 u16 vport, int link_state)
 {
 	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
+	int opmod = MLX5_VPORT_STATE_OP_MOD_ESW_VPORT;
+	int other_vport = 1;
 	int err = 0;
 
 	if (!ESW_ALLOWED(esw))
@@ -2101,15 +2107,17 @@
 	if (IS_ERR(evport))
 		return PTR_ERR(evport);
 
+	if (vport == MLX5_VPORT_UPLINK) {
+		opmod = MLX5_VPORT_STATE_OP_MOD_UPLINK;
+		other_vport = 0;
+		vport = 0;
+	}
 	mutex_lock(&esw->state_lock);
 
-	err = mlx5_modify_vport_admin_state(esw->dev,
-					    MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
-					    vport, 1, link_state);
+	err = mlx5_modify_vport_admin_state(esw->dev, opmod, vport, other_vport, link_state);
 	if (err) {
-		mlx5_core_warn(esw->dev,
-			       "Failed to set vport %d link state, err = %d",
-			       vport, err);
+		mlx5_core_warn(esw->dev, "Failed to set vport %d link state, opmod = %d, err = %d",
+			       vport, opmod, err);
 		goto unlock;
 	}
 
@@ -2151,8 +2159,6 @@
 	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
 	int err = 0;
 
-	if (!ESW_ALLOWED(esw))
-		return -EPERM;
 	if (IS_ERR(evport))
 		return PTR_ERR(evport);
 	if (vlan > 4095 || qos > 7)
@@ -2180,6 +2186,9 @@
 	u8 set_flags = 0;
 	int err;
 
+	if (!ESW_ALLOWED(esw))
+		return vlan ? -EPERM : 0;
+
 	if (vlan || qos)
 		set_flags = SET_VLAN_STRIP | SET_VLAN_INSERT;
 
@@ -2319,25 +2328,17 @@
 
 int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting)
 {
-	int err = 0;
-
 	if (!esw)
 		return -EOPNOTSUPP;
 
 	if (!ESW_ALLOWED(esw))
 		return -EPERM;
 
-	mutex_lock(&esw->state_lock);
-	if (esw->mode != MLX5_ESWITCH_LEGACY) {
-		err = -EOPNOTSUPP;
-		goto out;
-	}
+	if (esw->mode != MLX5_ESWITCH_LEGACY)
+		return -EOPNOTSUPP;
 
 	*setting = esw->fdb_table.legacy.vepa_uplink_rule ? 1 : 0;
-
-out:
-	mutex_unlock(&esw->state_lock);
-	return err;
+	return 0;
 }
 
 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
@@ -2372,12 +2373,15 @@
 		max_guarantee = evport->info.min_rate;
 	}
 
-	return max_t(u32, max_guarantee / fw_max_bw_share, 1);
+	if (max_guarantee)
+		return max_t(u32, max_guarantee / fw_max_bw_share, 1);
+	return 0;
 }
 
-static int normalize_vports_min_rate(struct mlx5_eswitch *esw, u32 divider)
+static int normalize_vports_min_rate(struct mlx5_eswitch *esw)
 {
 	u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
+	u32 divider = calculate_vports_min_rate_divider(esw);
 	struct mlx5_vport *evport;
 	u32 vport_max_rate;
 	u32 vport_min_rate;
@@ -2390,9 +2394,9 @@
 			continue;
 		vport_min_rate = evport->info.min_rate;
 		vport_max_rate = evport->info.max_rate;
-		bw_share = MLX5_MIN_BW_SHARE;
+		bw_share = 0;
 
-		if (vport_min_rate)
+		if (divider)
 			bw_share = MLX5_RATE_TO_BW_SHARE(vport_min_rate,
 							 divider,
 							 fw_max_bw_share);
@@ -2417,7 +2421,6 @@
 	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
 	u32 fw_max_bw_share;
 	u32 previous_min_rate;
-	u32 divider;
 	bool min_rate_supported;
 	bool max_rate_supported;
 	int err = 0;
@@ -2442,8 +2445,7 @@
 
 	previous_min_rate = evport->info.min_rate;
 	evport->info.min_rate = min_rate;
-	divider = calculate_vports_min_rate_divider(esw);
-	err = normalize_vports_min_rate(esw, divider);
+	err = normalize_vports_min_rate(esw);
 	if (err) {
 		evport->info.min_rate = previous_min_rate;
 		goto unlock;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -606,6 +606,8 @@
 static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {}
 static inline bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1) { return true; }
 static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; }
+static inline
+int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, u16 vport, int link_state) { return 0; }
 static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
 {
 	return ERR_PTR(-EOPNOTSUPP);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -858,7 +858,7 @@
  */
 #define ESW_SIZE (16 * 1024 * 1024)
 const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024,
-				    64 * 1024, 4 * 1024 };
+				    64 * 1024, 128 };
 
 static int
 get_sz_from_pool(struct mlx5_eswitch *esw)
@@ -1143,35 +1143,37 @@
 	}
 	esw->fdb_table.offloads.send_to_vport_grp = g;
 
-	/* create peer esw miss group */
-	memset(flow_group_in, 0, inlen);
-
-	esw_set_flow_group_source_port(esw, flow_group_in);
+	if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
+		/* create peer esw miss group */
+		memset(flow_group_in, 0, inlen);
+
+		esw_set_flow_group_source_port(esw, flow_group_in);
+
+		if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+			match_criteria = MLX5_ADDR_OF(create_flow_group_in,
+						      flow_group_in,
+						      match_criteria);
 
-	if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
-		match_criteria = MLX5_ADDR_OF(create_flow_group_in,
-					      flow_group_in,
-					      match_criteria);
-
-		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
-				 misc_parameters.source_eswitch_owner_vhca_id);
+			MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+					 misc_parameters.source_eswitch_owner_vhca_id);
 
-		MLX5_SET(create_flow_group_in, flow_group_in,
-			 source_eswitch_owner_vhca_id_valid, 1);
-	}
-
-	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
-	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
-		 ix + esw->total_vports - 1);
-	ix += esw->total_vports;
+			MLX5_SET(create_flow_group_in, flow_group_in,
+				 source_eswitch_owner_vhca_id_valid, 1);
+		}
 
-	g = mlx5_create_flow_group(fdb, flow_group_in);
-	if (IS_ERR(g)) {
-		err = PTR_ERR(g);
-		esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
-		goto peer_miss_err;
+		MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
+		MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
+			 ix + esw->total_vports - 1);
+		ix += esw->total_vports;
+
+		g = mlx5_create_flow_group(fdb, flow_group_in);
+		if (IS_ERR(g)) {
+			err = PTR_ERR(g);
+			esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
+			goto peer_miss_err;
+		}
+		esw->fdb_table.offloads.peer_miss_grp = g;
 	}
-	esw->fdb_table.offloads.peer_miss_grp = g;
 
 	/* create miss group */
 	memset(flow_group_in, 0, inlen);
@@ -1206,7 +1208,8 @@
 miss_rule_err:
 	mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
 miss_err:
-	mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
+	if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+		mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
 peer_miss_err:
 	mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
 send_vport_err:
@@ -1229,7 +1232,8 @@
 	mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
 	mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
 	mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
-	mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
+	if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+		mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
 	mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
 
 	mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
@@ -1973,10 +1977,6 @@
 	if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
 		return false;
 
-	if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
-	    mlx5_ecpf_vport_exists(esw->dev))
-		return false;
-
 	return true;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
@@ -267,6 +267,8 @@
 	for (curr_dest = 0; curr_dest < num_vport_dests; curr_dest++) {
 		struct mlx5_termtbl_handle *tt = attr->dests[curr_dest].termtbl;
 
+		attr->dests[curr_dest].termtbl = NULL;
+
 		/* search for the destination associated with the
 		 * current term table
 		 */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/events.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/events.c
@@ -346,8 +346,10 @@
 	events->dev = dev;
 	dev->priv.events = events;
 	events->wq = create_singlethread_workqueue("mlx5_events");
-	if (!events->wq)
+	if (!events->wq) {
+		kfree(events);
 		return -ENOMEM;
+	}
 	INIT_WORK(&events->pcie_core_work, mlx5_pcie_event);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
@@ -850,6 +850,7 @@
 	mutex_lock(&fpga_xfrm->lock);
 	if (!--fpga_xfrm->num_rules) {
 		mlx5_fpga_ipsec_release_sa_ctx(fpga_xfrm->sa_ctx);
+		kfree(fpga_xfrm->sa_ctx);
 		fpga_xfrm->sa_ctx = NULL;
 	}
 	mutex_unlock(&fpga_xfrm->lock);
@@ -1478,7 +1479,7 @@
 	if (!memcmp(&xfrm->attrs, attrs, sizeof(xfrm->attrs)))
 		return 0;
 
-	if (!mlx5_fpga_esp_validate_xfrm_attrs(mdev, attrs)) {
+	if (mlx5_fpga_esp_validate_xfrm_attrs(mdev, attrs)) {
 		mlx5_core_warn(mdev, "Tried to create an esp with unsupported attrs\n");
 		return -EOPNOTSUPP;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -496,6 +496,13 @@
 		goto out;
 	}
 
+	if (rule->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_PORT &&
+	    --fte->dests_size) {
+		fte->modify_mask |= BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION);
+		fte->action.action &= ~MLX5_FLOW_CONTEXT_ACTION_ALLOW;
+		goto out;
+	}
+
 	if ((fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
 	    --fte->dests_size) {
 		fte->modify_mask |=
@@ -629,7 +636,7 @@
 	fte->action = *flow_act;
 	fte->flow_context = spec->flow_context;
 
-	tree_init_node(&fte->node, NULL, del_sw_fte);
+	tree_init_node(&fte->node, del_hw_fte, del_sw_fte);
 
 	return fte;
 }
@@ -809,18 +816,15 @@
 {
 	struct mlx5_flow_root_namespace *root = find_root(&prio->node);
 	struct mlx5_flow_table *iter;
-	int i = 0;
 	int err;
 
 	fs_for_each_ft(iter, prio) {
-		i++;
 		err = root->cmds->modify_flow_table(root, iter, ft);
 		if (err) {
-			mlx5_core_warn(dev, "Failed to modify flow table %d\n",
-				       iter->id);
+			mlx5_core_err(dev,
+				      "Failed to modify flow table id %d, type %d, err %d\n",
+				      iter->id, iter->type, err);
 			/* The driver is out of sync with the FW */
-			if (i > 1)
-				WARN_ON(true);
 			return err;
 		}
 	}
@@ -964,17 +968,19 @@
 static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,
 			      struct fs_prio *prio)
 {
-	struct mlx5_flow_table *next_ft;
+	struct mlx5_flow_table *next_ft, *first_ft;
 	int err = 0;
 
 	/* Connect_prev_fts and update_root_ft_create are mutually exclusive */
 
-	if (list_empty(&prio->node.children)) {
+	first_ft = list_first_entry_or_null(&prio->node.children,
+					    struct mlx5_flow_table, node.list);
+	if (!first_ft || first_ft->level > ft->level) {
 		err = connect_prev_fts(dev, ft, prio);
 		if (err)
 			return err;
 
-		next_ft = find_next_chained_ft(prio);
+		next_ft = first_ft ? first_ft : find_next_chained_ft(prio);
 		err = connect_fwd_rules(dev, ft, next_ft);
 		if (err)
 			return err;
@@ -1064,6 +1070,7 @@
 destroy_ft:
 	root->cmds->destroy_flow_table(root, ft);
 free_ft:
+	rhltable_destroy(&ft->fgs_hash);
 	kfree(ft);
 unlock_root:
 	mutex_unlock(&root->chain_lock);
@@ -1443,9 +1450,22 @@
 	return NULL;
 }
 
-static bool check_conflicting_actions(u32 action1, u32 action2)
+static bool check_conflicting_actions_vlan(const struct mlx5_fs_vlan *vlan0,
+					   const struct mlx5_fs_vlan *vlan1)
 {
-	u32 xored_actions = action1 ^ action2;
+	return vlan0->ethtype != vlan1->ethtype ||
+	       vlan0->vid != vlan1->vid ||
+	       vlan0->prio != vlan1->prio;
+}
+
+static bool check_conflicting_actions(const struct mlx5_flow_act *act1,
+				      const struct mlx5_flow_act *act2)
+{
+	u32 action1 = act1->action;
+	u32 action2 = act2->action;
+	u32 xored_actions;
+
+	xored_actions = action1 ^ action2;
 
 	/* if one rule only wants to count, it's ok */
 	if (action1 == MLX5_FLOW_CONTEXT_ACTION_COUNT ||
@@ -1462,6 +1482,22 @@
 			     MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2))
 		return true;
 
+	if (action1 & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT &&
+	    act1->pkt_reformat != act2->pkt_reformat)
+		return true;
+
+	if (action1 & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+	    act1->modify_hdr != act2->modify_hdr)
+		return true;
+
+	if (action1 & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH &&
+	    check_conflicting_actions_vlan(&act1->vlan[0], &act2->vlan[0]))
+		return true;
+
+	if (action1 & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2 &&
+	    check_conflicting_actions_vlan(&act1->vlan[1], &act2->vlan[1]))
+		return true;
+
 	return false;
 }
 
@@ -1469,7 +1505,7 @@
 				  const struct mlx5_flow_context *flow_context,
 				  const struct mlx5_flow_act *flow_act)
 {
-	if (check_conflicting_actions(flow_act->action, fte->action.action)) {
+	if (check_conflicting_actions(flow_act, &fte->action)) {
 		mlx5_core_warn(get_dev(&fte->node),
 			       "Found two FTEs with conflicting actions\n");
 		return -EEXIST;
@@ -1555,16 +1591,16 @@
 	struct match_list first;
 };
 
-static void free_match_list(struct match_list_head *head)
+static void free_match_list(struct match_list_head *head, bool ft_locked)
 {
 	if (!list_empty(&head->list)) {
 		struct match_list *iter, *match_tmp;
 
 		list_del(&head->first.list);
-		tree_put_node(&head->first.g->node, false);
+		tree_put_node(&head->first.g->node, ft_locked);
 		list_for_each_entry_safe(iter, match_tmp, &head->list,
 					 list) {
-			tree_put_node(&iter->g->node, false);
+			tree_put_node(&iter->g->node, ft_locked);
 			list_del(&iter->list);
 			kfree(iter);
 		}
@@ -1573,7 +1609,8 @@
 
 static int build_match_list(struct match_list_head *match_head,
 			    struct mlx5_flow_table *ft,
-			    const struct mlx5_flow_spec *spec)
+			    const struct mlx5_flow_spec *spec,
+			    bool ft_locked)
 {
 	struct rhlist_head *tmp, *list;
 	struct mlx5_flow_group *g;
@@ -1598,9 +1635,9 @@
 
 		curr_match = kmalloc(sizeof(*curr_match), GFP_ATOMIC);
 		if (!curr_match) {
-			free_match_list(match_head);
-			err = -ENOMEM;
-			goto out;
+			rcu_read_unlock();
+			free_match_list(match_head, ft_locked);
+			return -ENOMEM;
 		}
 		if (!tree_get_node(&g->node)) {
 			kfree(curr_match);
@@ -1609,7 +1646,6 @@
 		curr_match->g = g;
 		list_add_tail(&curr_match->list, &match_head->list);
 	}
-out:
 	rcu_read_unlock();
 	return err;
 }
@@ -1691,6 +1727,7 @@
 		if (!fte_tmp)
 			continue;
 		rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
+		/* No error check needed here, because insert_fte() is not called */
 		up_write_ref_node(&fte_tmp->node, false);
 		tree_put_node(&fte_tmp->node, false);
 		kmem_cache_free(steering->ftes_cache, fte);
@@ -1739,7 +1776,8 @@
 		up_write_ref_node(&g->node, false);
 		rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
 		up_write_ref_node(&fte->node, false);
-		tree_put_node(&fte->node, false);
+		if (IS_ERR(rule))
+			tree_put_node(&fte->node, false);
 		return rule;
 	}
 	rule = ERR_PTR(-ENOENT);
@@ -1778,7 +1816,7 @@
 	version = atomic_read(&ft->node.version);
 
 	/* Collect all fgs which has a matching match_criteria */
-	err = build_match_list(&match_head, ft, spec);
+	err = build_match_list(&match_head, ft, spec, take_write);
 	if (err) {
 		if (take_write)
 			up_write_ref_node(&ft->node, false);
@@ -1792,7 +1830,7 @@
 
 	rule = try_add_to_existing_fg(ft, &match_head.list, spec, flow_act, dest,
 				      dest_num, version);
-	free_match_list(&match_head);
+	free_match_list(&match_head, take_write);
 	if (!IS_ERR(rule) ||
 	    (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) {
 		if (take_write)
@@ -1839,7 +1877,8 @@
 	up_write_ref_node(&g->node, false);
 	rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
 	up_write_ref_node(&fte->node, false);
-	tree_put_node(&fte->node, false);
+	if (IS_ERR(rule))
+		tree_put_node(&fte->node, false);
 	tree_put_node(&g->node, false);
 	return rule;
 
@@ -1927,13 +1966,18 @@
 	down_write_ref_node(&fte->node, false);
 	for (i = handle->num_rules - 1; i >= 0; i--)
 		tree_remove_node(&handle->rule[i]->node, true);
-	if (fte->modify_mask && fte->dests_size) {
-		modify_fte(fte);
-		up_write_ref_node(&fte->node, false);
-	} else {
+	if (list_empty(&fte->node.children)) {
 		del_hw_fte(&fte->node);
-		up_write(&fte->node.lock);
+		/* Avoid double call to del_hw_fte */
+		fte->node.del_hw_func = NULL;
+		up_write_ref_node(&fte->node, false);
 		tree_put_node(&fte->node, false);
+	} else if (fte->dests_size) {
+		if (fte->modify_mask)
+			modify_fte(fte);
+		up_write_ref_node(&fte->node, false);
+	} else {
+		up_write_ref_node(&fte->node, false);
 	}
 	kfree(handle);
 }
@@ -2014,7 +2058,7 @@
 				node.list) == ft))
 		return 0;
 
-	next_ft = find_next_chained_ft(prio);
+	next_ft = find_next_ft(ft);
 	err = connect_fwd_rules(dev, next_ft, ft);
 	if (err)
 		return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -239,7 +239,7 @@
 			return err;
 	}
 
-	if (MLX5_CAP_GEN(dev, tls)) {
+	if (MLX5_CAP_GEN(dev, tls_tx)) {
 		err = mlx5_core_get_caps(dev, MLX5_CAP_TLS);
 		if (err)
 			return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -193,15 +193,23 @@
 
 void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
 {
+	bool err_detected = false;
+
+	/* Mark the device as fatal in order to abort FW commands */
+	if ((check_fatal_sensors(dev) || force) &&
+	    dev->state == MLX5_DEVICE_STATE_UP) {
+		dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
+		err_detected = true;
+	}
 	mutex_lock(&dev->intf_state_mutex);
-	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
-		goto unlock;
+	if (!err_detected && dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
+		goto unlock;/* a previous error is still being handled */
 	if (dev->state == MLX5_DEVICE_STATE_UNINITIALIZED) {
 		dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 		goto unlock;
 	}
 
-	if (check_fatal_sensors(dev) || force) {
+	if (check_fatal_sensors(dev) || force) { /* protected state setting */
 		dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 		mlx5_cmd_flush(dev);
 	}
@@ -243,7 +251,7 @@
 		if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
 			break;
 
-		cond_resched();
+		msleep(20);
 	} while (!time_after(jiffies, end));
 
 	if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
@@ -39,7 +39,7 @@
 	struct mlx5e_priv *priv = mlx5i_epriv(dev);
 
 	mlx5e_ethtool_get_drvinfo(priv, drvinfo);
-	strlcpy(drvinfo->driver, DRIVER_NAME "[ib_ipoib]",
+	strlcpy(drvinfo->driver, KBUILD_MODNAME "[ib_ipoib]",
 		sizeof(drvinfo->driver));
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -319,17 +319,6 @@
 	}
 
 	mlx5e_set_ttc_basic_params(priv, &ttc_params);
-	mlx5e_set_inner_ttc_ft_params(&ttc_params);
-	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
-		ttc_params.indir_tirn[tt] = priv->inner_indir_tir[tt].tirn;
-
-	err = mlx5e_create_inner_ttc_table(priv, &ttc_params, &priv->fs.inner_ttc);
-	if (err) {
-		netdev_err(priv->netdev, "Failed to create inner ttc table, err=%d\n",
-			   err);
-		goto err_destroy_arfs_tables;
-	}
-
 	mlx5e_set_ttc_ft_params(&ttc_params);
 	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
 		ttc_params.indir_tirn[tt] = priv->indir_tir[tt].tirn;
@@ -338,13 +327,11 @@
 	if (err) {
 		netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n",
 			   err);
-		goto err_destroy_inner_ttc_table;
+		goto err_destroy_arfs_tables;
 	}
 
 	return 0;
 
-err_destroy_inner_ttc_table:
-	mlx5e_destroy_inner_ttc_table(priv, &priv->fs.inner_ttc);
 err_destroy_arfs_tables:
 	mlx5e_arfs_destroy_tables(priv);
 
@@ -354,7 +341,6 @@
 static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv)
 {
 	mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
-	mlx5e_destroy_inner_ttc_table(priv, &priv->fs.inner_ttc);
 	mlx5e_arfs_destroy_tables(priv);
 }
 
@@ -379,7 +365,7 @@
 	if (err)
 		goto err_destroy_indirect_rqts;
 
-	err = mlx5e_create_indirect_tirs(priv, true);
+	err = mlx5e_create_indirect_tirs(priv, false);
 	if (err)
 		goto err_destroy_direct_rqts;
 
@@ -396,7 +382,7 @@
 err_destroy_direct_tirs:
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
 err_destroy_indirect_tirs:
-	mlx5e_destroy_indirect_tirs(priv, true);
+	mlx5e_destroy_indirect_tirs(priv);
 err_destroy_direct_rqts:
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 err_destroy_indirect_rqts:
@@ -412,7 +398,7 @@
 {
 	mlx5i_destroy_flow_steering(priv);
 	mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
-	mlx5e_destroy_indirect_tirs(priv, true);
+	mlx5e_destroy_indirect_tirs(priv);
 	mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
 	mlx5e_destroy_rqt(priv, &priv->indir_rqt);
 	mlx5e_close_drop_rq(&priv->drop_rq);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
@@ -265,10 +265,8 @@
 		fen_info = container_of(info, struct fib_entry_notifier_info,
 					info);
 		fi = fen_info->fi;
-		if (fi->nh) {
-			NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
-			return notifier_from_errno(-EINVAL);
-		}
+		if (fi->nh)
+			return NOTIFY_DONE;
 		fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
 		if (fib_dev != ldev->pf[0].netdev &&
 		    fib_dev != ldev->pf[1].netdev) {
@@ -307,6 +305,11 @@
 	struct lag_mp *mp = &ldev->lag_mp;
 	int err;
 
+	/* always clear mfi, as it might become stale when a route delete event
+	 * has been missed
+	 */
+	mp->mfi = NULL;
+
 	if (mp->fib_nb.notifier_call)
 		return 0;
 
@@ -328,4 +331,5 @@
 
 	unregister_fib_notifier(&mp->fib_nb);
 	mp->fib_nb.notifier_call = NULL;
+	mp->mfi = NULL;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -388,16 +388,37 @@
 	return 0;
 }
 
+enum {
+	MLX5_MTPPS_REG_CAP_PIN_X_MODE_SUPPORT_PPS_IN = BIT(0),
+	MLX5_MTPPS_REG_CAP_PIN_X_MODE_SUPPORT_PPS_OUT = BIT(1),
+};
+
 static int mlx5_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
 			   enum ptp_pin_function func, unsigned int chan)
 {
-	return (func == PTP_PF_PHYSYNC) ? -EOPNOTSUPP : 0;
+	struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock,
+						ptp_info);
+
+	switch (func) {
+	case PTP_PF_NONE:
+		return 0;
+	case PTP_PF_EXTTS:
+		return !(clock->pps_info.pin_caps[pin] &
+			 MLX5_MTPPS_REG_CAP_PIN_X_MODE_SUPPORT_PPS_IN);
+	case PTP_PF_PEROUT:
+		return !(clock->pps_info.pin_caps[pin] &
+			 MLX5_MTPPS_REG_CAP_PIN_X_MODE_SUPPORT_PPS_OUT);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
 }
 
 static const struct ptp_clock_info mlx5_ptp_clock_info = {
 	.owner		= THIS_MODULE,
-	.name		= "mlx5_p2p",
-	.max_adj	= 100000000,
+	.name		= "mlx5_ptp",
+	.max_adj	= 50000000,
 	.n_alarm	= 0,
 	.n_ext_ts	= 0,
 	.n_per_out	= 0,
@@ -477,8 +498,9 @@
 	switch (clock->ptp_info.pin_config[pin].func) {
 	case PTP_PF_EXTTS:
 		ptp_event.index = pin;
-		ptp_event.timestamp = timecounter_cyc2time(&clock->tc,
-					be64_to_cpu(eqe->data.pps.time_stamp));
+		ptp_event.timestamp =
+			mlx5_timecounter_cyc2time(clock,
+						  be64_to_cpu(eqe->data.pps.time_stamp));
 		if (clock->pps_info.enabled) {
 			ptp_event.type = PTP_CLOCK_PPSUSR;
 			ptp_event.pps_times.ts_real =
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
@@ -3,6 +3,7 @@
 
 #include <linux/mlx5/vport.h>
 #include "lib/devcom.h"
+#include "mlx5_core.h"
 
 static LIST_HEAD(devcom_list);
 
@@ -14,7 +15,7 @@
 struct mlx5_devcom_component {
 	struct {
 		void *data;
-	} device[MLX5_MAX_PORTS];
+	} device[MLX5_DEVCOM_PORTS_SUPPORTED];
 
 	mlx5_devcom_event_handler_t handler;
 	struct rw_semaphore sem;
@@ -25,7 +26,7 @@
 	struct list_head list;
 
 	struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS];
-	struct mlx5_core_dev *devs[MLX5_MAX_PORTS];
+	struct mlx5_core_dev *devs[MLX5_DEVCOM_PORTS_SUPPORTED];
 };
 
 struct mlx5_devcom {
@@ -74,13 +75,16 @@
 
 	if (!mlx5_core_is_pf(dev))
 		return NULL;
+	if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED)
+		return NULL;
 
+	mlx5_dev_list_lock();
 	sguid0 = mlx5_query_nic_system_image_guid(dev);
 	list_for_each_entry(iter, &devcom_list, list) {
 		struct mlx5_core_dev *tmp_dev = NULL;
 
 		idx = -1;
-		for (i = 0; i < MLX5_MAX_PORTS; i++) {
+		for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) {
 			if (iter->devs[i])
 				tmp_dev = iter->devs[i];
 			else
@@ -100,8 +104,10 @@
 
 	if (!priv) {
 		priv = mlx5_devcom_list_alloc();
-		if (!priv)
-			return ERR_PTR(-ENOMEM);
+		if (!priv) {
+			devcom = ERR_PTR(-ENOMEM);
+			goto out;
+		}
 
 		idx = 0;
 		new_priv = true;
@@ -110,13 +116,16 @@
 	priv->devs[idx] = dev;
 	devcom = mlx5_devcom_alloc(priv, idx);
 	if (!devcom) {
-		kfree(priv);
-		return ERR_PTR(-ENOMEM);
+		if (new_priv)
+			kfree(priv);
+		devcom = ERR_PTR(-ENOMEM);
+		goto out;
 	}
 
 	if (new_priv)
 		list_add(&priv->list, &devcom_list);
-
+out:
+	mlx5_dev_list_unlock();
 	return devcom;
 }
 
@@ -129,20 +138,23 @@
 	if (IS_ERR_OR_NULL(devcom))
 		return;
 
+	mlx5_dev_list_lock();
 	priv = devcom->priv;
 	priv->devs[devcom->idx] = NULL;
 
 	kfree(devcom);
 
-	for (i = 0; i < MLX5_MAX_PORTS; i++)
+	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
 		if (priv->devs[i])
 			break;
 
-	if (i != MLX5_MAX_PORTS)
-		return;
+	if (i != MLX5_DEVCOM_PORTS_SUPPORTED)
+		goto out;
 
 	list_del(&priv->list);
 	kfree(priv);
+out:
+	mlx5_dev_list_unlock();
 }
 
 void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
@@ -191,7 +203,7 @@
 
 	comp = &devcom->priv->components[id];
 	down_write(&comp->sem);
-	for (i = 0; i < MLX5_MAX_PORTS; i++)
+	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
 		if (i != devcom->idx && comp->device[i].data) {
 			err = comp->handler(event, comp->device[i].data,
 					    event_data);
@@ -239,7 +251,7 @@
 		return NULL;
 	}
 
-	for (i = 0; i < MLX5_MAX_PORTS; i++)
+	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
 		if (i != devcom->idx)
 			break;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
@@ -6,6 +6,8 @@
 
 #include <linux/mlx5/driver.h>
 
+#define MLX5_DEVCOM_PORTS_SUPPORTED 2
+
 enum mlx5_devcom_components {
 	MLX5_DEVCOM_ESW_OFFLOADS,
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
@@ -38,6 +38,7 @@
 struct mlx5_eq_async {
 	struct mlx5_eq          core;
 	struct notifier_block   irq_nb;
+	spinlock_t              lock; /* To avoid irq EQ handle races with resiliency flows */
 };
 
 struct mlx5_eq_comp {
@@ -82,6 +83,7 @@
 struct cpumask *mlx5_eq_comp_cpumask(struct mlx5_core_dev *dev, int ix);
 
 u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq);
+void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev);
 void mlx5_eq_synchronize_async_irq(struct mlx5_core_dev *dev);
 void mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev *dev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
@@ -105,6 +105,7 @@
 		geneve->opt_type = opt->type;
 		geneve->obj_id = res;
 		geneve->refcount++;
+		res = 0;
 	}
 
 unlock:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -50,6 +50,7 @@
 #ifdef CONFIG_RFS_ACCEL
 #include <linux/cpu_rmap.h>
 #endif
+#include <linux/version.h>
 #include <net/devlink.h>
 #include "mlx5_core.h"
 #include "lib/eq.h"
@@ -74,7 +75,6 @@
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(DRIVER_VERSION);
 
 unsigned int mlx5_core_debug_mask;
 module_param_named(debug_mask, mlx5_core_debug_mask, uint, 0644);
@@ -221,13 +221,16 @@
 	strncat(string, ",", remaining_size);
 
 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
-	strncat(string, DRIVER_NAME, remaining_size);
+	strncat(string, KBUILD_MODNAME, remaining_size);
 
 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
 	strncat(string, ",", remaining_size);
 
 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
-	strncat(string, DRIVER_VERSION, remaining_size);
+
+	snprintf(string + strlen(string), remaining_size, "%u.%u.%u",
+		 (u8)((LINUX_VERSION_CODE >> 16) & 0xff), (u8)((LINUX_VERSION_CODE >> 8) & 0xff),
+		 (u16)(LINUX_VERSION_CODE & 0xffff));
 
 	/*Send the command*/
 	MLX5_SET(set_driver_version_in, in, opcode,
@@ -303,7 +306,7 @@
 		return -ENODEV;
 	}
 
-	err = pci_request_regions(pdev, DRIVER_NAME);
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
 	if (err)
 		dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n");
 
@@ -794,6 +797,11 @@
 
 static void mlx5_pci_close(struct mlx5_core_dev *dev)
 {
+	/* health work might still be active, and it needs pci bar in
+	 * order to know the NIC state. Therefore, drain the health WQ
+	 * before removing the pci bars
+	 */
+	mlx5_drain_health_wq(dev);
 	iounmap(dev->iseg);
 	pci_clear_master(dev->pdev);
 	release_bar(dev->pdev);
@@ -878,7 +886,7 @@
 
 	dev->dm = mlx5_dm_create(dev);
 	if (IS_ERR(dev->dm))
-		mlx5_core_warn(dev, "Failed to init device memory%d\n", err);
+		mlx5_core_warn(dev, "Failed to init device memory %ld\n", PTR_ERR(dev->dm));
 
 	dev->tracer = mlx5_fw_tracer_create(dev);
 	dev->hv_vhca = mlx5_hv_vhca_create(dev);
@@ -966,6 +974,8 @@
 		goto err_cmd_cleanup;
 	}
 
+	mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_UP);
+
 	err = mlx5_core_enable_hca(dev, 0);
 	if (err) {
 		mlx5_core_err(dev, "enable hca failed\n");
@@ -1027,6 +1037,7 @@
 err_disable_hca:
 	mlx5_core_disable_hca(dev, 0);
 err_cmd_cleanup:
+	mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN);
 	mlx5_cmd_cleanup(dev);
 
 	return err;
@@ -1044,6 +1055,7 @@
 	}
 	mlx5_reclaim_startup_pages(dev);
 	mlx5_core_disable_hca(dev, 0);
+	mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN);
 	mlx5_cmd_cleanup(dev);
 
 	return 0;
@@ -1168,7 +1180,7 @@
 	mlx5_put_uars_page(dev, dev->priv.uar);
 }
 
-static int mlx5_load_one(struct mlx5_core_dev *dev, bool boot)
+int mlx5_load_one(struct mlx5_core_dev *dev, bool boot)
 {
 	int err = 0;
 
@@ -1183,7 +1195,7 @@
 
 	err = mlx5_function_setup(dev, boot);
 	if (err)
-		goto out;
+		goto err_function;
 
 	if (boot) {
 		err = mlx5_init_once(dev);
@@ -1197,6 +1209,12 @@
 	if (err)
 		goto err_load;
 
+	if (boot) {
+		err = mlx5_devlink_register(priv_to_devlink(dev), dev->device);
+		if (err)
+			goto err_devlink_reg;
+	}
+
 	if (mlx5_device_registered(dev)) {
 		mlx5_attach_device(dev);
 	} else {
@@ -1214,22 +1232,24 @@
 	return err;
 
 err_reg_dev:
+	if (boot)
+		mlx5_devlink_unregister(priv_to_devlink(dev));
+err_devlink_reg:
 	mlx5_unload(dev);
 err_load:
 	if (boot)
 		mlx5_cleanup_once(dev);
 function_teardown:
 	mlx5_function_teardown(dev, boot);
+err_function:
 	dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
 	mutex_unlock(&dev->intf_state_mutex);
 
 	return err;
 }
 
-static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup)
+int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup)
 {
-	int err = 0;
-
 	if (cleanup) {
 		mlx5_unregister_device(dev);
 		mlx5_drain_health_wq(dev);
@@ -1257,7 +1277,7 @@
 	mlx5_function_teardown(dev, cleanup);
 out:
 	mutex_unlock(&dev->intf_state_mutex);
-	return err;
+	return 0;
 }
 
 static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
@@ -1353,10 +1373,6 @@
 
 	request_module_nowait(MLX5_IB_MOD);
 
-	err = mlx5_devlink_register(devlink, &pdev->dev);
-	if (err)
-		goto clean_load;
-
 	err = mlx5_crdump_enable(dev);
 	if (err)
 		dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
@@ -1364,9 +1380,6 @@
 	pci_save_state(pdev);
 	return 0;
 
-clean_load:
-	mlx5_unload_one(dev, true);
-
 err_load_one:
 	mlx5_pci_close(dev);
 pci_init_err:
@@ -1551,6 +1564,22 @@
 	mlx5_pci_disable_device(dev);
 }
 
+static int mlx5_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
+
+	mlx5_unload_one(dev, false);
+
+	return 0;
+}
+
+static int mlx5_resume(struct pci_dev *pdev)
+{
+	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
+
+	return mlx5_load_one(dev, false);
+}
+
 static const struct pci_device_id mlx5_core_pci_table[] = {
 	{ PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTIB) },
 	{ PCI_VDEVICE(MELLANOX, 0x1012), MLX5_PCI_DEV_IS_VF},	/* Connect-IB VF */
@@ -1567,6 +1596,7 @@
 	{ PCI_VDEVICE(MELLANOX, 0x101d) },			/* ConnectX-6 Dx */
 	{ PCI_VDEVICE(MELLANOX, 0x101e), MLX5_PCI_DEV_IS_VF},	/* ConnectX Family mlx5Gen Virtual Function */
 	{ PCI_VDEVICE(MELLANOX, 0x101f) },			/* ConnectX-6 LX */
+	{ PCI_VDEVICE(MELLANOX, 0x1021) },			/* ConnectX-7 */
 	{ PCI_VDEVICE(MELLANOX, 0xa2d2) },			/* BlueField integrated ConnectX-5 network controller */
 	{ PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF},	/* BlueField integrated ConnectX-5 network controller VF */
 	{ PCI_VDEVICE(MELLANOX, 0xa2d6) },			/* BlueField-2 integrated ConnectX-6 Dx network controller */
@@ -1589,10 +1619,12 @@
 }
 
 static struct pci_driver mlx5_core_driver = {
-	.name           = DRIVER_NAME,
+	.name           = KBUILD_MODNAME,
 	.id_table       = mlx5_core_pci_table,
 	.probe          = init_one,
 	.remove         = remove_one,
+	.suspend        = mlx5_suspend,
+	.resume         = mlx5_resume,
 	.shutdown	= shutdown,
 	.err_handler	= &mlx5_err_handler,
 	.sriov_configure   = mlx5_core_sriov_configure,
@@ -1609,10 +1641,13 @@
 	}
 }
 
-static int __init init(void)
+static int __init mlx5_init(void)
 {
 	int err;
 
+	WARN_ONCE(strcmp(MLX5_ADEV_NAME, KBUILD_MODNAME),
+		  "mlx5_core name not in sync with kernel module name");
+
 	get_random_bytes(&sw_owner_id, sizeof(sw_owner_id));
 
 	mlx5_core_verify_params();
@@ -1634,7 +1669,7 @@
 	return err;
 }
 
-static void __exit cleanup(void)
+static void __exit mlx5_cleanup(void)
 {
 #ifdef CONFIG_MLX5_CORE_EN
 	mlx5e_cleanup();
@@ -1643,5 +1678,5 @@
 	mlx5_unregister_debugfs();
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(mlx5_init);
+module_exit(mlx5_cleanup);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -43,9 +43,6 @@
 #include <linux/mlx5/fs.h>
 #include <linux/mlx5/driver.h>
 
-#define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "5.0-0"
-
 extern uint mlx5_core_debug_mask;
 
 #define mlx5_core_dbg(__dev, format, ...)				\
@@ -243,4 +240,7 @@
 
 u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
 void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state);
+
+int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup);
+int mlx5_load_one(struct mlx5_core_dev *dev, bool boot);
 #endif /* __MLX5_CORE_H__ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -167,7 +167,8 @@
 	fp = list_entry(dev->priv.free_list.next, struct fw_page, list);
 	n = find_first_bit(&fp->bitmask, 8 * sizeof(fp->bitmask));
 	if (n >= MLX5_NUM_4K_IN_PAGE) {
-		mlx5_core_warn(dev, "alloc 4k bug\n");
+		mlx5_core_warn(dev, "alloc 4k bug: fw page = 0x%llx, n = %u, bitmask: %lu, max num of 4K pages: %d\n",
+			       fp->addr, n, fp->bitmask,  MLX5_NUM_4K_IN_PAGE);
 		return -ENOENT;
 	}
 	clear_bit(n, &fp->bitmask);
@@ -339,6 +340,24 @@
 	return err;
 }
 
+static u32 fwp_fill_manage_pages_out(struct fw_page *fwp, u32 *out, u32 index,
+				     u32 npages)
+{
+	u32 pages_set = 0;
+	unsigned int n;
+
+	for_each_clear_bit(n, &fwp->bitmask, MLX5_NUM_4K_IN_PAGE) {
+		MLX5_ARRAY_SET64(manage_pages_out, out, pas, index + pages_set,
+				 fwp->addr + (n * MLX5_ADAPTER_PAGE_SIZE));
+		pages_set++;
+
+		if (!--npages)
+			break;
+	}
+
+	return pages_set;
+}
+
 static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
 			     u32 *in, int in_size, u32 *out, int out_size)
 {
@@ -348,7 +367,7 @@
 	u32 npages;
 	u32 i = 0;
 
-	if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
+	if (!mlx5_cmd_is_down(dev))
 		return mlx5_cmd_exec(dev, in, in_size, out, out_size);
 
 	/* No hard feelings, we want our pages back! */
@@ -362,8 +381,7 @@
 		if (fwp->func_id != func_id)
 			continue;
 
-		MLX5_ARRAY_SET64(manage_pages_out, out, pas, i, fwp->addr);
-		i++;
+		i += fwp_fill_manage_pages_out(fwp, out, i, npages - i);
 	}
 
 	MLX5_SET(manage_pages_out, out, output_num_entries, i);
@@ -486,8 +504,8 @@
 
 int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
 {
-	u16 uninitialized_var(func_id);
-	s32 uninitialized_var(npages);
+	u16 func_id;
+	s32 npages;
 	int err;
 
 	err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -115,7 +115,7 @@
 	return 0;
 
 err_request_irq:
-	for (; i >= 0; i--) {
+	while (i--) {
 		struct mlx5_irq *irq = mlx5_irq_get(dev, i);
 		int irqn = pci_irq_vector(dev->pdev, i);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -293,7 +293,40 @@
 	return 0;
 }
 
-static int mlx5_eeprom_page(int offset)
+static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
+				u8 *module_id)
+{
+	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
+	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
+	int err, status;
+	u8 *ptr;
+
+	MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
+	MLX5_SET(mcia_reg, in, module, module_num);
+	MLX5_SET(mcia_reg, in, device_address, 0);
+	MLX5_SET(mcia_reg, in, page_number, 0);
+	MLX5_SET(mcia_reg, in, size, 1);
+	MLX5_SET(mcia_reg, in, l, 0);
+
+	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+				   sizeof(out), MLX5_REG_MCIA, 0, 0);
+	if (err)
+		return err;
+
+	status = MLX5_GET(mcia_reg, out, status);
+	if (status) {
+		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
+			      status);
+		return -EIO;
+	}
+	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
+
+	*module_id = ptr[0];
+
+	return 0;
+}
+
+static int mlx5_qsfp_eeprom_page(u16 offset)
 {
 	if (offset < MLX5_EEPROM_PAGE_LENGTH)
 		/* Addresses between 0-255 - page 00 */
@@ -307,7 +340,7 @@
 		    MLX5_EEPROM_HIGH_PAGE_LENGTH);
 }
 
-static int mlx5_eeprom_high_page_offset(int page_num)
+static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
 {
 	if (!page_num) /* Page 0 always start from low page */
 		return 0;
@@ -316,35 +349,62 @@
 	return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
 }
 
+static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
+{
+	*i2c_addr = MLX5_I2C_ADDR_LOW;
+	*page_num = mlx5_qsfp_eeprom_page(*offset);
+	*offset -=  mlx5_qsfp_eeprom_high_page_offset(*page_num);
+}
+
+static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
+{
+	*i2c_addr = MLX5_I2C_ADDR_LOW;
+	*page_num = 0;
+
+	if (*offset < MLX5_EEPROM_PAGE_LENGTH)
+		return;
+
+	*i2c_addr = MLX5_I2C_ADDR_HIGH;
+	*offset -= MLX5_EEPROM_PAGE_LENGTH;
+}
+
 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 			     u16 offset, u16 size, u8 *data)
 {
-	int module_num, page_num, status, err;
+	int module_num, status, err, page_num = 0;
+	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
-	u32 in[MLX5_ST_SZ_DW(mcia_reg)];
-	u16 i2c_addr;
-	void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
+	u16 i2c_addr = 0;
+	u8 module_id;
+	void *ptr;
 
 	err = mlx5_query_module_num(dev, &module_num);
 	if (err)
 		return err;
 
-	memset(in, 0, sizeof(in));
-	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
-
-	/* Get the page number related to the given offset */
-	page_num = mlx5_eeprom_page(offset);
+	err = mlx5_query_module_id(dev, module_num, &module_id);
+	if (err)
+		return err;
 
-	/* Set the right offset according to the page number,
-	 * For page_num > 0, relative offset is always >= 128 (high page).
-	 */
-	offset -= mlx5_eeprom_high_page_offset(page_num);
+	switch (module_id) {
+	case MLX5_MODULE_ID_SFP:
+		mlx5_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
+		break;
+	case MLX5_MODULE_ID_QSFP:
+	case MLX5_MODULE_ID_QSFP_PLUS:
+	case MLX5_MODULE_ID_QSFP28:
+		mlx5_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
+		break;
+	default:
+		mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
+		return -EINVAL;
+	}
 
 	if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
 		/* Cross pages read, read until offset 256 in low page */
 		size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
 
-	i2c_addr = MLX5_I2C_ADDR_LOW;
+	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
 
 	MLX5_SET(mcia_reg, in, l, 0);
 	MLX5_SET(mcia_reg, in, module, module_num);
@@ -365,6 +425,7 @@
 		return -EIO;
 	}
 
+	ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
 	memcpy(data, ptr, size);
 
 	return size;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
@@ -116,7 +116,7 @@
 static void mlx5_rdma_del_roce_addr(struct mlx5_core_dev *dev)
 {
 	mlx5_core_roce_gid_set(dev, 0, 0, 0,
-			       NULL, NULL, false, 0, 0);
+			       NULL, NULL, false, 0, 1);
 }
 
 static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *gid)
@@ -156,6 +156,9 @@
 {
 	int err;
 
+	if (!MLX5_CAP_GEN(dev, roce))
+		return;
+
 	err = mlx5_nic_vport_enable_roce(dev);
 	if (err) {
 		mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -211,8 +211,7 @@
 		host_total_vfs = MLX5_GET(query_esw_functions_out, out,
 					  host_params_context.host_total_vfs);
 		kvfree(out);
-		if (host_total_vfs)
-			return host_total_vfs;
+		return host_total_vfs;
 	}
 
 done:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
@@ -667,6 +667,7 @@
 		switch (action_type) {
 		case DR_ACTION_TYP_DROP:
 			attr.final_icm_addr = nic_dmn->drop_icm_addr;
+			attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48;
 			break;
 		case DR_ACTION_TYP_FT:
 			dest_action = action;
@@ -930,7 +931,6 @@
 
 	action->rewrite.data = (void *)ops;
 	action->rewrite.num_of_actions = i;
-	action->rewrite.chunk->byte_size = i * sizeof(*ops);
 
 	ret = mlx5dr_send_postsend_action(dmn, action);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
@@ -92,6 +92,7 @@
 	caps->eswitch_manager	= MLX5_CAP_GEN(mdev, eswitch_manager);
 	caps->gvmi		= MLX5_CAP_GEN(mdev, vhca_id);
 	caps->flex_protocols	= MLX5_CAP_GEN(mdev, flex_parser_protocols);
+	caps->sw_format_ver	= MLX5_CAP_GEN(mdev, steering_format_version);
 
 	if (mlx5dr_matcher_supp_flex_parser_icmp_v4(caps)) {
 		caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0);
@@ -422,11 +423,12 @@
 
 	err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
 	if (err)
-		return err;
+		goto err_free_in;
 
 	*reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id);
-	kvfree(in);
 
+err_free_in:
+	kvfree(in);
 	return err;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c
@@ -2,6 +2,7 @@
 /* Copyright (c) 2019 Mellanox Technologies. */
 
 #include <linux/mlx5/eswitch.h>
+#include <linux/err.h>
 #include "dr_types.h"
 
 static int dr_domain_init_cache(struct mlx5dr_domain *dmn)
@@ -64,9 +65,9 @@
 	}
 
 	dmn->uar = mlx5_get_uars_page(dmn->mdev);
-	if (!dmn->uar) {
+	if (IS_ERR(dmn->uar)) {
 		mlx5dr_err(dmn, "Couldn't allocate UAR\n");
-		ret = -ENOMEM;
+		ret = PTR_ERR(dmn->uar);
 		goto clean_pd;
 	}
 
@@ -223,6 +224,11 @@
 	if (ret)
 		return ret;
 
+	if (dmn->info.caps.sw_format_ver != MLX5_STEERING_FORMAT_CONNECTX_5) {
+		mlx5dr_err(dmn, "SW steering is not supported on this device\n");
+		return -EOPNOTSUPP;
+	}
+
 	ret = dr_domain_query_fdb_caps(mdev, dmn);
 	if (ret)
 		return ret;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c
@@ -209,7 +209,7 @@
 	/* We need to copy the refcount since this ste
 	 * may have been traversed several times
 	 */
-	refcount_set(&new_ste->refcount, refcount_read(&cur_ste->refcount));
+	new_ste->refcount = cur_ste->refcount;
 
 	/* Link old STEs rule_mem list to the new ste */
 	mlx5dr_rule_update_rule_member(cur_ste, new_ste);
@@ -638,6 +638,9 @@
 	if (!rule_mem)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&rule_mem->list);
+	INIT_LIST_HEAD(&rule_mem->use_ste_list);
+
 	rule_mem->ste = ste;
 	list_add_tail(&rule_mem->list, &nic_rule->rule_members_list);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /* Copyright (c) 2019 Mellanox Technologies. */
 
+#include <linux/smp.h>
 #include "dr_types.h"
 
 #define QUEUE_SIZE 128
@@ -180,7 +181,7 @@
 							 in, pas));
 
 	err = mlx5_core_create_qp(mdev, &dr_qp->mqp, in, inlen);
-	kfree(in);
+	kvfree(in);
 
 	if (err) {
 		mlx5_core_warn(mdev, " Can't create QP\n");
@@ -557,7 +558,8 @@
 	int ret;
 
 	send_info.write.addr = (uintptr_t)action->rewrite.data;
-	send_info.write.length = action->rewrite.chunk->byte_size;
+	send_info.write.length = action->rewrite.num_of_actions *
+				 DR_MODIFY_ACTION_SIZE;
 	send_info.write.lkey = 0;
 	send_info.remote_addr = action->rewrite.chunk->mr_addr;
 	send_info.rkey = action->rewrite.chunk->rkey;
@@ -601,6 +603,7 @@
 	MLX5_SET(qpc, qpc, log_ack_req_freq, 0);
 	MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt);
 	MLX5_SET(qpc, qpc, rnr_retry, attr->rnr_retry);
+	MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 0x8); /* ~1ms */
 
 	return mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RTR2RTS_QP, 0, qpc,
 				   &dr_qp->mqp);
@@ -687,6 +690,12 @@
 	pr_info("CQ event %u on CQ #%u\n", event, mcq->cqn);
 }
 
+static void dr_cq_complete(struct mlx5_core_cq *mcq,
+			   struct mlx5_eqe *eqe)
+{
+	pr_err("CQ completion CQ: #%u\n", mcq->cqn);
+}
+
 static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
 				      struct mlx5_uars_page *uar,
 				      size_t ncqe)
@@ -729,7 +738,7 @@
 	if (!in)
 		goto err_cqwq;
 
-	vector = smp_processor_id() % mlx5_comp_vectors_count(mdev);
+	vector = raw_smp_processor_id() % mlx5_comp_vectors_count(mdev);
 	err = mlx5_vector2eqn(mdev, vector, &eqn, &irqn);
 	if (err) {
 		kvfree(in);
@@ -748,6 +757,7 @@
 	mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas);
 
 	cq->mcq.event = dr_cq_event;
+	cq->mcq.comp  = dr_cq_complete;
 
 	err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out));
 	kvfree(in);
@@ -759,7 +769,12 @@
 	cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
 	cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
 	*cq->mcq.set_ci_db = 0;
-	*cq->mcq.arm_db = 0;
+
+	/* set no-zero value, in order to avoid the HW to run db-recovery on
+	 * CQ that used in polling mode.
+	 */
+	*cq->mcq.arm_db = cpu_to_be32(2 << 28);
+
 	cq->mcq.vector = 0;
 	cq->mcq.irqn = irqn;
 	cq->mcq.uar = uar;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c
@@ -340,7 +340,7 @@
 	if (dst->next_htbl)
 		dst->next_htbl->pointing_ste = dst;
 
-	refcount_set(&dst->refcount, refcount_read(&src->refcount));
+	dst->refcount = src->refcount;
 
 	INIT_LIST_HEAD(&dst->rule_list);
 	list_splice_tail_init(&src->rule_list, &dst->rule_list);
@@ -557,7 +557,7 @@
 
 bool mlx5dr_ste_not_used_ste(struct mlx5dr_ste *ste)
 {
-	return !refcount_read(&ste->refcount);
+	return !ste->refcount;
 }
 
 /* Init one ste as a pattern for ste data array */
@@ -681,14 +681,14 @@
 	htbl->ste_arr = chunk->ste_arr;
 	htbl->hw_ste_arr = chunk->hw_ste_arr;
 	htbl->miss_list = chunk->miss_list;
-	refcount_set(&htbl->refcount, 0);
+	htbl->refcount = 0;
 
 	for (i = 0; i < chunk->num_of_entries; i++) {
 		struct mlx5dr_ste *ste = &htbl->ste_arr[i];
 
 		ste->hw_ste = htbl->hw_ste_arr + i * DR_STE_SIZE_REDUCED;
 		ste->htbl = htbl;
-		refcount_set(&ste->refcount, 0);
+		ste->refcount = 0;
 		INIT_LIST_HEAD(&ste->miss_list_node);
 		INIT_LIST_HEAD(&htbl->miss_list[i]);
 		INIT_LIST_HEAD(&ste->rule_list);
@@ -705,7 +705,7 @@
 
 int mlx5dr_ste_htbl_free(struct mlx5dr_ste_htbl *htbl)
 {
-	if (refcount_read(&htbl->refcount))
+	if (htbl->refcount)
 		return -EBUSY;
 
 	mlx5dr_icm_free_chunk(htbl->chunk);
@@ -2257,7 +2257,9 @@
 	struct mlx5dr_cmd_vport_cap *vport_cap;
 	struct mlx5dr_domain *dmn = sb->dmn;
 	struct mlx5dr_cmd_caps *caps;
+	u8 *bit_mask = sb->bit_mask;
 	u8 *tag = hw_ste->tag;
+	bool source_gvmi_set;
 
 	DR_STE_SET_TAG(src_gvmi_qp, tag, source_qp, misc, source_sqn);
 
@@ -2278,7 +2280,8 @@
 	if (!vport_cap)
 		return -EINVAL;
 
-	if (vport_cap->vport_gvmi)
+	source_gvmi_set = MLX5_GET(ste_src_gvmi_qp, bit_mask, source_gvmi);
+	if (vport_cap->vport_gvmi && source_gvmi_set)
 		MLX5_SET(ste_src_gvmi_qp, tag, source_gvmi, vport_cap->vport_gvmi);
 
 	misc->source_eswitch_owner_vhca_id = 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
@@ -9,7 +9,7 @@
 	struct mlx5dr_matcher *last_matcher = NULL;
 	struct mlx5dr_htbl_connect_info info;
 	struct mlx5dr_ste_htbl *last_htbl;
-	int ret;
+	int ret = -EOPNOTSUPP;
 
 	if (action && action->action_type != DR_ACTION_TYP_FT)
 		return -EOPNOTSUPP;
@@ -68,6 +68,9 @@
 		}
 	}
 
+	if (ret)
+		goto out;
+
 	/* Release old action */
 	if (tbl->miss_action)
 		refcount_dec(&tbl->miss_action->refcount);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
@@ -117,7 +117,7 @@
 struct mlx5dr_ste {
 	u8 *hw_ste;
 	/* refcount: indicates the num of rules that using this ste */
-	refcount_t refcount;
+	u32 refcount;
 
 	/* attached to the miss_list head at each htbl entry */
 	struct list_head miss_list_node;
@@ -149,7 +149,7 @@
 struct mlx5dr_ste_htbl {
 	u8 lu_type;
 	u16 byte_mask;
-	refcount_t refcount;
+	u32 refcount;
 	struct mlx5dr_icm_chunk *chunk;
 	struct mlx5dr_ste *ste_arr;
 	u8 *hw_ste_arr;
@@ -200,13 +200,14 @@
 
 static inline void mlx5dr_htbl_put(struct mlx5dr_ste_htbl *htbl)
 {
-	if (refcount_dec_and_test(&htbl->refcount))
+	htbl->refcount--;
+	if (!htbl->refcount)
 		mlx5dr_ste_htbl_free(htbl);
 }
 
 static inline void mlx5dr_htbl_get(struct mlx5dr_ste_htbl *htbl)
 {
-	refcount_inc(&htbl->refcount);
+	htbl->refcount++;
 }
 
 /* STE utils */
@@ -248,14 +249,15 @@
 				  struct mlx5dr_matcher *matcher,
 				  struct mlx5dr_matcher_rx_tx *nic_matcher)
 {
-	if (refcount_dec_and_test(&ste->refcount))
+	ste->refcount--;
+	if (!ste->refcount)
 		mlx5dr_ste_free(ste, matcher, nic_matcher);
 }
 
 /* initial as 0, increased only when ste appears in a new rule */
 static inline void mlx5dr_ste_get(struct mlx5dr_ste *ste)
 {
-	refcount_inc(&ste->refcount);
+	ste->refcount++;
 }
 
 void mlx5dr_ste_set_hit_addr_by_next_htbl(u8 *hw_ste,
@@ -611,6 +613,7 @@
 	u8 max_ft_level;
 	u16 roce_min_src_udp;
 	u8 num_esw_ports;
+	u8 sw_format_ver;
 	bool eswitch_manager;
 	bool rx_sw_owner;
 	bool tx_sw_owner;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
@@ -43,11 +43,10 @@
 	err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action);
 	if (err && action) {
 		err = mlx5dr_action_destroy(action);
-		if (err) {
-			action = NULL;
-			mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n",
-				      err);
-		}
+		if (err)
+			mlx5_core_err(ns->dev,
+				      "Failed to destroy action (%d)\n", err);
+		action = NULL;
 	}
 	ft->fs_dr_table.miss_action = action;
 	if (old_miss_action) {
@@ -247,29 +246,9 @@
 
 	/* The order of the actions are must to be keep, only the following
 	 * order is supported by SW steering:
-	 * TX: push vlan -> modify header -> encap
+	 * TX: modify header -> push vlan -> encap
 	 * RX: decap -> pop vlan -> modify header
 	 */
-	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
-		tmp_action = create_action_push_vlan(domain, &fte->action.vlan[0]);
-		if (!tmp_action) {
-			err = -ENOMEM;
-			goto free_actions;
-		}
-		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-		actions[num_actions++] = tmp_action;
-	}
-
-	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
-		tmp_action = create_action_push_vlan(domain, &fte->action.vlan[1]);
-		if (!tmp_action) {
-			err = -ENOMEM;
-			goto free_actions;
-		}
-		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-		actions[num_actions++] = tmp_action;
-	}
-
 	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
 		enum mlx5dr_action_reformat_type decap_type =
 			DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2;
@@ -322,6 +301,26 @@
 		actions[num_actions++] =
 			fte->action.modify_hdr->action.dr_action;
 
+	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
+		tmp_action = create_action_push_vlan(domain, &fte->action.vlan[0]);
+		if (!tmp_action) {
+			err = -ENOMEM;
+			goto free_actions;
+		}
+		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
+		actions[num_actions++] = tmp_action;
+	}
+
+	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
+		tmp_action = create_action_push_vlan(domain, &fte->action.vlan[1]);
+		if (!tmp_action) {
+			err = -ENOMEM;
+			goto free_actions;
+		}
+		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
+		actions[num_actions++] = tmp_action;
+	}
+
 	if (delay_encap_set)
 		actions[num_actions++] =
 			fte->action.pkt_reformat->action.dr_action;
@@ -352,26 +351,16 @@
 	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
 		list_for_each_entry(dst, &fte->node.children, node.list) {
 			enum mlx5_flow_destination_type type = dst->dest_attr.type;
-			u32 id;
 
 			if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
 				err = -ENOSPC;
 				goto free_actions;
 			}
 
-			switch (type) {
-			case MLX5_FLOW_DESTINATION_TYPE_COUNTER:
-				id = dst->dest_attr.counter_id;
+			if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
+				continue;
 
-				tmp_action =
-					mlx5dr_action_create_flow_counter(id);
-				if (!tmp_action) {
-					err = -ENOMEM;
-					goto free_actions;
-				}
-				fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-				actions[num_actions++] = tmp_action;
-				break;
+			switch (type) {
 			case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
 				tmp_action = create_ft_action(dev, dst);
 				if (!tmp_action) {
@@ -397,6 +386,32 @@
 		}
 	}
 
+	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
+		list_for_each_entry(dst, &fte->node.children, node.list) {
+			u32 id;
+
+			if (dst->dest_attr.type !=
+			    MLX5_FLOW_DESTINATION_TYPE_COUNTER)
+				continue;
+
+			if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+				err = -ENOSPC;
+				goto free_actions;
+			}
+
+			id = dst->dest_attr.counter_id;
+			tmp_action =
+				mlx5dr_action_create_flow_counter(id);
+			if (!tmp_action) {
+				err = -ENOMEM;
+				goto free_actions;
+			}
+
+			fs_dr_actions[fs_dr_num_actions++] = tmp_action;
+			actions[num_actions++] = tmp_action;
+		}
+	}
+
 	params.match_sz = match_sz;
 	params.match_buf = (u64 *)fte->val;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
@@ -457,6 +457,15 @@
 	return err;
 }
 
+static void mlx5_hairpin_unpair_peer_sq(struct mlx5_hairpin *hp)
+{
+	int i;
+
+	for (i = 0; i < hp->num_channels; i++)
+		mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
+				       MLX5_SQC_STATE_RST, 0, 0);
+}
+
 static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
 {
 	int i;
@@ -465,13 +474,9 @@
 	for (i = 0; i < hp->num_channels; i++)
 		mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn[i], MLX5_RQC_STATE_RDY,
 				       MLX5_RQC_STATE_RST, 0, 0);
-
 	/* unset peer SQs */
-	if (hp->peer_gone)
-		return;
-	for (i = 0; i < hp->num_channels; i++)
-		mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
-				       MLX5_SQC_STATE_RST, 0, 0);
+	if (!hp->peer_gone)
+		mlx5_hairpin_unpair_peer_sq(hp);
 }
 
 struct mlx5_hairpin *
@@ -518,3 +523,16 @@
 	mlx5_hairpin_destroy_queues(hp);
 	kfree(hp);
 }
+
+void mlx5_core_hairpin_clear_dead_peer(struct mlx5_hairpin *hp)
+{
+	int i;
+
+	mlx5_hairpin_unpair_peer_sq(hp);
+
+	/* destroy peer SQ */
+	for (i = 0; i < hp->num_channels; i++)
+		mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
+
+	hp->peer_gone = true;
+}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/wq.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/wq.c
@@ -96,6 +96,13 @@
 	return err;
 }
 
+void mlx5_wq_cyc_reset(struct mlx5_wq_cyc *wq)
+{
+	wq->wqe_ctr = 0;
+	wq->cur_sz = 0;
+	mlx5_wq_cyc_update_db_record(wq);
+}
+
 int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
 		      void *qpc, struct mlx5_wq_qp *wq,
 		      struct mlx5_wq_ctrl *wq_ctrl)
@@ -194,6 +201,19 @@
 	return err;
 }
 
+static void mlx5_wq_ll_init_list(struct mlx5_wq_ll *wq)
+{
+	struct mlx5_wqe_srq_next_seg *next_seg;
+	int i;
+
+	for (i = 0; i < wq->fbc.sz_m1; i++) {
+		next_seg = mlx5_wq_ll_get_wqe(wq, i);
+		next_seg->next_wqe_index = cpu_to_be16(i + 1);
+	}
+	next_seg = mlx5_wq_ll_get_wqe(wq, i);
+	wq->tail_next = &next_seg->next_wqe_index;
+}
+
 int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
 		      void *wqc, struct mlx5_wq_ll *wq,
 		      struct mlx5_wq_ctrl *wq_ctrl)
@@ -201,9 +221,7 @@
 	u8 log_wq_stride = MLX5_GET(wq, wqc, log_wq_stride);
 	u8 log_wq_sz     = MLX5_GET(wq, wqc, log_wq_sz);
 	struct mlx5_frag_buf_ctrl *fbc = &wq->fbc;
-	struct mlx5_wqe_srq_next_seg *next_seg;
 	int err;
-	int i;
 
 	err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
 	if (err) {
@@ -222,13 +240,7 @@
 
 	mlx5_init_fbc(wq_ctrl->buf.frags, log_wq_stride, log_wq_sz, fbc);
 
-	for (i = 0; i < fbc->sz_m1; i++) {
-		next_seg = mlx5_wq_ll_get_wqe(wq, i);
-		next_seg->next_wqe_index = cpu_to_be16(i + 1);
-	}
-	next_seg = mlx5_wq_ll_get_wqe(wq, i);
-	wq->tail_next = &next_seg->next_wqe_index;
-
+	mlx5_wq_ll_init_list(wq);
 	wq_ctrl->mdev = mdev;
 
 	return 0;
@@ -239,6 +251,15 @@
 	return err;
 }
 
+void mlx5_wq_ll_reset(struct mlx5_wq_ll *wq)
+{
+	wq->head = 0;
+	wq->wqe_ctr = 0;
+	wq->cur_sz = 0;
+	mlx5_wq_ll_init_list(wq);
+	mlx5_wq_ll_update_db_record(wq);
+}
+
 void mlx5_wq_destroy(struct mlx5_wq_ctrl *wq_ctrl)
 {
 	mlx5_frag_buf_free(wq_ctrl->mdev, &wq_ctrl->buf);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlx5/core/wq.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlx5/core/wq.h
@@ -80,10 +80,12 @@
 		       void *wqc, struct mlx5_wq_cyc *wq,
 		       struct mlx5_wq_ctrl *wq_ctrl);
 u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq);
+void mlx5_wq_cyc_reset(struct mlx5_wq_cyc *wq);
 
 int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
 		      void *qpc, struct mlx5_wq_qp *wq,
 		      struct mlx5_wq_ctrl *wq_ctrl);
+void mlx5_wq_ll_reset(struct mlx5_wq_ll *wq);
 
 int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
 		     void *cqc, struct mlx5_cqwq *wq,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/netlink.h>
+#include <linux/vmalloc.h>
 #include <linux/xz.h>
 #include "mlxfw_mfa2.h"
 #include "mlxfw_mfa2_file.h"
@@ -548,7 +549,7 @@
 	comp_size = be32_to_cpu(comp->size);
 	comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
 
-	comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL);
+	comp_data = vzalloc(sizeof(*comp_data) + comp_buf_size);
 	if (!comp_data)
 		return ERR_PTR(-ENOMEM);
 	comp_data->comp.data_size = comp_size;
@@ -570,7 +571,7 @@
 	comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
 	return &comp_data->comp;
 err_out:
-	kfree(comp_data);
+	vfree(comp_data);
 	return ERR_PTR(err);
 }
 
@@ -579,7 +580,7 @@
 	const struct mlxfw_mfa2_comp_data *comp_data;
 
 	comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
-	kfree(comp_data);
+	vfree(comp_data);
 }
 
 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c
@@ -31,6 +31,8 @@
 
 	if (tlv->type == MLXFW_MFA2_TLV_MULTI_PART) {
 		multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, tlv);
+		if (!multi)
+			return NULL;
 		tlv_len = NLA_ALIGN(tlv_len + be16_to_cpu(multi->total_len));
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -444,7 +444,8 @@
 	if (trans->core->fw_flash_in_progress)
 		timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS);
 
-	queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, timeout);
+	queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw,
+			   timeout << trans->retries);
 }
 
 static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core,
@@ -493,6 +494,9 @@
 		err = mlxsw_emad_transmit(trans->core, trans);
 		if (err == 0)
 			return;
+
+		if (!atomic_dec_and_test(&trans->active))
+			return;
 	} else {
 		err = -EIO;
 	}
@@ -592,7 +596,7 @@
 	err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_emad_rx_listener,
 				       mlxsw_core);
 	if (err)
-		return err;
+		goto err_trap_register;
 
 	err = mlxsw_core->driver->basic_trap_groups_set(mlxsw_core);
 	if (err)
@@ -604,6 +608,7 @@
 err_emad_trap_set:
 	mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
 				   mlxsw_core);
+err_trap_register:
 	destroy_workqueue(mlxsw_core->emad_wq);
 	return err;
 }
@@ -1280,6 +1285,8 @@
 	if (!reload)
 		devlink_resources_unregister(devlink, NULL);
 	mlxsw_core->bus->fini(mlxsw_core->bus_priv);
+	if (!reload)
+		devlink_free(devlink);
 
 	return;
 
@@ -1576,7 +1583,7 @@
 	err = mlxsw_emad_reg_access(mlxsw_core, reg, payload, type, trans,
 				    bulk_list, cb, cb_priv, tid);
 	if (err) {
-		kfree(trans);
+		kfree_rcu(trans, rcu);
 		return err;
 	}
 	return 0;
@@ -1801,11 +1808,13 @@
 			break;
 		}
 	}
-	rcu_read_unlock();
-	if (!found)
+	if (!found) {
+		rcu_read_unlock();
 		goto drop;
+	}
 
 	rxl->func(skb, local_port, rxl_item->priv);
+	rcu_read_unlock();
 	return;
 
 drop:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
@@ -316,7 +316,7 @@
 
 	block = kzalloc(sizeof(*block), GFP_KERNEL);
 	if (!block)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	INIT_LIST_HEAD(&block->resource_list);
 	block->afa = mlxsw_afa;
 
@@ -344,7 +344,7 @@
 	mlxsw_afa_set_destroy(block->first_set);
 err_first_set_create:
 	kfree(block);
-	return NULL;
+	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(mlxsw_afa_block_create);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -19,22 +19,14 @@
 #define MLXSW_THERMAL_ASIC_TEMP_NORM	75000	/* 75C */
 #define MLXSW_THERMAL_ASIC_TEMP_HIGH	85000	/* 85C */
 #define MLXSW_THERMAL_ASIC_TEMP_HOT	105000	/* 105C */
-#define MLXSW_THERMAL_ASIC_TEMP_CRIT	110000	/* 110C */
+#define MLXSW_THERMAL_ASIC_TEMP_CRIT	140000	/* 140C */
 #define MLXSW_THERMAL_HYSTERESIS_TEMP	5000	/* 5C */
 #define MLXSW_THERMAL_MODULE_TEMP_SHIFT	(MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
 #define MLXSW_THERMAL_ZONE_MAX_NAME	16
 #define MLXSW_THERMAL_TEMP_SCORE_MAX	GENMASK(31, 0)
 #define MLXSW_THERMAL_MAX_STATE	10
+#define MLXSW_THERMAL_MIN_STATE	2
 #define MLXSW_THERMAL_MAX_DUTY	255
-/* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values
- * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for
- * setting fan speed dynamic minimum. For example, if value is set to 14 (40%)
- * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
- * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
- */
-#define MLXSW_THERMAL_SPEED_MIN		(MLXSW_THERMAL_MAX_STATE + 2)
-#define MLXSW_THERMAL_SPEED_MAX		(MLXSW_THERMAL_MAX_STATE * 2)
-#define MLXSW_THERMAL_SPEED_MIN_LEVEL	2		/* 20% */
 
 /* External cooling devices, allowed for binding to mlxsw thermal zones. */
 static char * const mlxsw_thermal_external_allowed_cdev[] = {
@@ -177,6 +169,12 @@
 	if (err)
 		return err;
 
+	if (crit_temp > emerg_temp) {
+		dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
+			 tz->tzdev->type, crit_temp, emerg_temp);
+		return 0;
+	}
+
 	/* According to the system thermal requirements, the thermal zones are
 	 * defined with four trip points. The critical and emergency
 	 * temperature thresholds, provided by QSFP module are set as "active"
@@ -191,11 +189,8 @@
 		tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
 	tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
 	tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
-	if (emerg_temp > crit_temp)
-		tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp +
+	tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp +
 					MLXSW_THERMAL_MODULE_TEMP_SHIFT;
-	else
-		tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp;
 
 	return 0;
 }
@@ -390,8 +385,7 @@
 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 				   int trip, enum thermal_trend *trend)
 {
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-	struct mlxsw_thermal *thermal = tz->parent;
+	struct mlxsw_thermal *thermal = tzdev->devdata;
 
 	if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
 		return -EINVAL;
@@ -592,6 +586,22 @@
 	return 0;
 }
 
+static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
+					  int trip, enum thermal_trend *trend)
+{
+	struct mlxsw_thermal_module *tz = tzdev->devdata;
+	struct mlxsw_thermal *thermal = tz->parent;
+
+	if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
+		return -EINVAL;
+
+	if (tzdev == thermal->tz_highest_dev)
+		return 1;
+
+	*trend = THERMAL_TREND_STABLE;
+	return 0;
+}
+
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
@@ -603,7 +613,7 @@
 	.set_trip_temp	= mlxsw_thermal_module_trip_temp_set,
 	.get_trip_hyst	= mlxsw_thermal_module_trip_hyst_get,
 	.set_trip_hyst	= mlxsw_thermal_module_trip_hyst_set,
-	.get_trend	= mlxsw_thermal_trend_get,
+	.get_trend	= mlxsw_thermal_module_trend_get,
 };
 
 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
@@ -642,7 +652,7 @@
 	.set_trip_temp	= mlxsw_thermal_module_trip_temp_set,
 	.get_trip_hyst	= mlxsw_thermal_module_trip_hyst_get,
 	.set_trip_hyst	= mlxsw_thermal_module_trip_hyst_set,
-	.get_trend	= mlxsw_thermal_trend_get,
+	.get_trend	= mlxsw_thermal_module_trend_get,
 };
 
 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
@@ -685,49 +695,16 @@
 	struct mlxsw_thermal *thermal = cdev->devdata;
 	struct device *dev = thermal->bus_info->dev;
 	char mfsc_pl[MLXSW_REG_MFSC_LEN];
-	unsigned long cur_state, i;
 	int idx;
-	u8 duty;
 	int err;
 
+	if (state > MLXSW_THERMAL_MAX_STATE)
+		return -EINVAL;
+
 	idx = mlxsw_get_cooling_device_idx(thermal, cdev);
 	if (idx < 0)
 		return idx;
 
-	/* Verify if this request is for changing allowed fan dynamical
-	 * minimum. If it is - update cooling levels accordingly and update
-	 * state, if current state is below the newly requested minimum state.
-	 * For example, if current state is 5, and minimal state is to be
-	 * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed
-	 * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be
-	 * overwritten.
-	 */
-	if (state >= MLXSW_THERMAL_SPEED_MIN &&
-	    state <= MLXSW_THERMAL_SPEED_MAX) {
-		state -= MLXSW_THERMAL_MAX_STATE;
-		for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++)
-			thermal->cooling_levels[i] = max(state, i);
-
-		mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
-		err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
-		if (err)
-			return err;
-
-		duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
-		cur_state = mlxsw_duty_to_state(duty);
-
-		/* If current fan state is lower than requested dynamical
-		 * minimum, increase fan speed up to dynamical minimum.
-		 */
-		if (state < cur_state)
-			return 0;
-
-		state = cur_state;
-	}
-
-	if (state > MLXSW_THERMAL_MAX_STATE)
-		return -EINVAL;
-
 	/* Normalize the state to the valid speed range. */
 	state = thermal->cooling_levels[state];
 	mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
@@ -1022,8 +999,7 @@
 
 	/* Initialize cooling levels per PWM state. */
 	for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
-		thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL,
-						 i);
+		thermal->cooling_levels[i] = max(MLXSW_THERMAL_MIN_STATE, i);
 
 	thermal->polling_delay = bus_info->low_frequency ?
 				 MLXSW_THERMAL_SLOW_POLL_INT :
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -47,6 +47,7 @@
 #define MLXSW_I2C_MBOX_SIZE_BITS	12
 #define MLXSW_I2C_ADDR_BUF_SIZE		4
 #define MLXSW_I2C_BLK_DEF		32
+#define MLXSW_I2C_BLK_MAX		100
 #define MLXSW_I2C_RETRY			5
 #define MLXSW_I2C_TIMEOUT_MSECS		5000
 #define MLXSW_I2C_MAX_DATA_SIZE		256
@@ -427,7 +428,7 @@
 	} else {
 		/* No input mailbox is case of initialization query command. */
 		reg_size = MLXSW_I2C_MAX_DATA_SIZE;
-		num = reg_size / mlxsw_i2c->block_size;
+		num = DIV_ROUND_UP(reg_size, mlxsw_i2c->block_size);
 
 		if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
 			dev_err(&client->dev, "Could not acquire lock");
@@ -575,7 +576,7 @@
 			return -EOPNOTSUPP;
 		}
 
-		mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF,
+		mlxsw_i2c->block_size = min_t(u16, MLXSW_I2C_BLK_MAX,
 					      min_t(u16, quirks->max_read_len,
 						    quirks->max_write_len));
 	} else {
@@ -649,6 +650,7 @@
 	return 0;
 
 errout:
+	mutex_destroy(&mlxsw_i2c->cmd.lock);
 	i2c_set_clientdata(client, NULL);
 
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -204,8 +204,8 @@
 
 err_register_netdev:
 	mlxsw_m->ports[local_port] = NULL;
-	free_netdev(dev);
 err_dev_addr_get:
+	free_netdev(dev);
 err_alloc_etherdev:
 	mlxsw_core_port_fini(mlxsw_m->core, local_port);
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -1318,36 +1318,64 @@
 			    mbox->mapaddr);
 }
 
-static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
-			      const struct pci_device_id *id)
+static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci,
+				    const struct pci_device_id *id,
+				    u32 *p_sys_status)
 {
 	unsigned long end;
-	char mrsr_pl[MLXSW_REG_MRSR_LEN];
-	int err;
+	u32 val;
 
-	mlxsw_reg_mrsr_pack(mrsr_pl);
-	err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
-	if (err)
-		return err;
 	if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) {
 		msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
 		return 0;
 	}
 
-	/* We must wait for the HW to become responsive once again. */
+	/* We must wait for the HW to become responsive. */
 	msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS);
 
 	end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
 	do {
-		u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
-
+		val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
 		if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC)
 			return 0;
 		cond_resched();
 	} while (time_before(jiffies, end));
+
+	*p_sys_status = val & MLXSW_PCI_FW_READY_MASK;
+
 	return -EBUSY;
 }
 
+static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
+			      const struct pci_device_id *id)
+{
+	struct pci_dev *pdev = mlxsw_pci->pdev;
+	char mrsr_pl[MLXSW_REG_MRSR_LEN];
+	u32 sys_status;
+	int err;
+
+	err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n",
+			sys_status);
+		return err;
+	}
+
+	mlxsw_reg_mrsr_pack(mrsr_pl);
+	err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
+	if (err)
+		return err;
+
+	err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n",
+			sys_status);
+		return err;
+	}
+
+	return 0;
+}
+
 static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci)
 {
 	int err;
@@ -1373,23 +1401,12 @@
 	u16 num_pages;
 	int err;
 
-	mutex_init(&mlxsw_pci->cmd.lock);
-	init_waitqueue_head(&mlxsw_pci->cmd.wait);
-
 	mlxsw_pci->core = mlxsw_core;
 
 	mbox = mlxsw_cmd_mbox_alloc();
 	if (!mbox)
 		return -ENOMEM;
 
-	err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
-	if (err)
-		goto mbox_put;
-
-	err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
-	if (err)
-		goto err_out_mbox_alloc;
-
 	err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id);
 	if (err)
 		goto err_sw_reset;
@@ -1496,9 +1513,6 @@
 	mlxsw_pci_free_irq_vectors(mlxsw_pci);
 err_alloc_irq:
 err_sw_reset:
-	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
-err_out_mbox_alloc:
-	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
 mbox_put:
 	mlxsw_cmd_mbox_free(mbox);
 	return err;
@@ -1512,8 +1526,6 @@
 	mlxsw_pci_aqs_fini(mlxsw_pci);
 	mlxsw_pci_fw_area_fini(mlxsw_pci);
 	mlxsw_pci_free_irq_vectors(mlxsw_pci);
-	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
-	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
 }
 
 static struct mlxsw_pci_queue *
@@ -1727,6 +1739,37 @@
 	.features		= MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET,
 };
 
+static int mlxsw_pci_cmd_init(struct mlxsw_pci *mlxsw_pci)
+{
+	int err;
+
+	mutex_init(&mlxsw_pci->cmd.lock);
+	init_waitqueue_head(&mlxsw_pci->cmd.wait);
+
+	err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
+	if (err)
+		goto err_in_mbox_alloc;
+
+	err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
+	if (err)
+		goto err_out_mbox_alloc;
+
+	return 0;
+
+err_out_mbox_alloc:
+	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
+err_in_mbox_alloc:
+	mutex_destroy(&mlxsw_pci->cmd.lock);
+	return err;
+}
+
+static void mlxsw_pci_cmd_fini(struct mlxsw_pci *mlxsw_pci)
+{
+	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
+	mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
+	mutex_destroy(&mlxsw_pci->cmd.lock);
+}
+
 static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	const char *driver_name = pdev->driver->name;
@@ -1782,6 +1825,10 @@
 	mlxsw_pci->pdev = pdev;
 	pci_set_drvdata(pdev, mlxsw_pci);
 
+	err = mlxsw_pci_cmd_init(mlxsw_pci);
+	if (err)
+		goto err_pci_cmd_init;
+
 	mlxsw_pci->bus_info.device_kind = driver_name;
 	mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev);
 	mlxsw_pci->bus_info.dev = &pdev->dev;
@@ -1799,6 +1846,8 @@
 	return 0;
 
 err_bus_device_register:
+	mlxsw_pci_cmd_fini(mlxsw_pci);
+err_pci_cmd_init:
 	iounmap(mlxsw_pci->hw_addr);
 err_ioremap:
 err_pci_resource_len_check:
@@ -1816,6 +1865,7 @@
 	struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
 
 	mlxsw_core_bus_device_unregister(mlxsw_pci->core, false);
+	mlxsw_pci_cmd_fini(mlxsw_pci);
 	iounmap(mlxsw_pci->hw_addr);
 	pci_release_regions(mlxsw_pci->pdev);
 	pci_disable_device(mlxsw_pci->pdev);
@@ -1826,6 +1876,7 @@
 {
 	pci_driver->probe = mlxsw_pci_probe;
 	pci_driver->remove = mlxsw_pci_remove;
+	pci_driver->shutdown = mlxsw_pci_remove;
 	return pci_register_driver(pci_driver);
 }
 EXPORT_SYMBOL(mlxsw_pci_driver_register);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -5421,6 +5421,7 @@
 	MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
 	MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
 	MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
+	MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,
 
 	__MLXSW_REG_HTGT_TRAP_GROUP_MAX,
 	MLXSW_REG_HTGT_TRAP_GROUP_MAX = __MLXSW_REG_HTGT_TRAP_GROUP_MAX - 1
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -812,23 +812,17 @@
 	u64 len;
 	int err;
 
+	if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
+		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
 	memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
 
 	if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
 		return NETDEV_TX_BUSY;
 
-	if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
-		struct sk_buff *skb_orig = skb;
-
-		skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
-		if (!skb) {
-			this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
-			dev_kfree_skb_any(skb_orig);
-			return NETDEV_TX_OK;
-		}
-		dev_consume_skb_any(skb_orig);
-	}
-
 	if (eth_skb_pad(skb)) {
 		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
 		return NETDEV_TX_OK;
@@ -1167,6 +1161,9 @@
 			     periodic_hw_stats.update_dw.work);
 
 	if (!netif_carrier_ok(mlxsw_sp_port->dev))
+		/* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as
+		 * necessary when port goes down.
+		 */
 		goto out;
 
 	mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
@@ -3935,6 +3932,7 @@
 	mlxsw_sp_cpu_port_remove(mlxsw_sp);
 	kfree(mlxsw_sp->port_to_module);
 	kfree(mlxsw_sp->ports);
+	mlxsw_sp->ports = NULL;
 }
 
 static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
@@ -3989,6 +3987,7 @@
 	kfree(mlxsw_sp->port_to_module);
 err_port_to_module_alloc:
 	kfree(mlxsw_sp->ports);
+	mlxsw_sp->ports = NULL;
 	return err;
 }
 
@@ -4043,6 +4042,14 @@
 	}
 }
 
+static struct mlxsw_sp_port *
+mlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u8 local_port)
+{
+	if (mlxsw_sp->ports && mlxsw_sp->ports[local_port])
+		return mlxsw_sp->ports[local_port];
+	return NULL;
+}
+
 static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
 			       unsigned int count,
 			       struct netlink_ext_ack *extack)
@@ -4061,7 +4068,7 @@
 	local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X);
 	local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X);
 
-	mlxsw_sp_port = mlxsw_sp->ports[local_port];
+	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
 	if (!mlxsw_sp_port) {
 		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
 			local_port);
@@ -4139,7 +4146,7 @@
 	local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X);
 	local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X);
 
-	mlxsw_sp_port = mlxsw_sp->ports[local_port];
+	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
 	if (!mlxsw_sp_port) {
 		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
 			local_port);
@@ -4176,6 +4183,15 @@
 	return 0;
 }
 
+static void
+mlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+	int i;
+
+	for (i = 0; i < TC_MAX_QUEUE; i++)
+		mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0;
+}
+
 static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
 				     char *pude_pl, void *priv)
 {
@@ -4197,6 +4213,7 @@
 	} else {
 		netdev_info(mlxsw_sp_port->dev, "link down\n");
 		netif_carrier_off(mlxsw_sp_port->dev);
+		mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port);
 	}
 }
 
@@ -4398,8 +4415,8 @@
 	MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false),
 	MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false),
 	MLXSW_SP_RXL_MARK(DECAP_ECN0, TRAP_TO_CPU, ROUTER_EXP, false),
-	MLXSW_SP_RXL_MARK(IPV4_VRRP, TRAP_TO_CPU, ROUTER_EXP, false),
-	MLXSW_SP_RXL_MARK(IPV6_VRRP, TRAP_TO_CPU, ROUTER_EXP, false),
+	MLXSW_SP_RXL_MARK(IPV4_VRRP, TRAP_TO_CPU, VRRP, false),
+	MLXSW_SP_RXL_MARK(IPV6_VRRP, TRAP_TO_CPU, VRRP, false),
 	/* PKT Sample trap */
 	MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU,
 		  false, SP_IP2ME, DISCARD),
@@ -4483,6 +4500,10 @@
 			rate = 19 * 1024;
 			burst_size = 12;
 			break;
+		case MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP:
+			rate = 360;
+			burst_size = 7;
+			break;
 		default:
 			continue;
 		}
@@ -4522,6 +4543,7 @@
 		case MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF:
 		case MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM:
 		case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0:
+		case MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP:
 			priority = 5;
 			tc = 5;
 			break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
@@ -88,8 +88,8 @@
 	 * to be written using PEFA register to all indexes for all regions.
 	 */
 	afa_block = mlxsw_afa_block_create(mlxsw_sp->afa);
-	if (!afa_block) {
-		err = -ENOMEM;
+	if (IS_ERR(afa_block)) {
+		err = PTR_ERR(afa_block);
 		goto err_afa_block;
 	}
 	err = mlxsw_afa_block_continue(afa_block);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/rhashtable.h>
 #include <linux/netdevice.h>
+#include <linux/mutex.h>
 #include <net/net_namespace.h>
 #include <net/tc_act/tc_vlan.h>
 
@@ -25,6 +26,7 @@
 	struct mlxsw_sp_fid *dummy_fid;
 	struct rhashtable ruleset_ht;
 	struct list_head rules;
+	struct mutex rules_lock; /* Protects rules list */
 	struct {
 		struct delayed_work dw;
 		unsigned long interval;	/* ms */
@@ -442,7 +444,7 @@
 
 	rulei = kzalloc(sizeof(*rulei), GFP_KERNEL);
 	if (!rulei)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	if (afa_block) {
 		rulei->act_block = afa_block;
@@ -701,7 +703,9 @@
 			goto err_ruleset_block_bind;
 	}
 
+	mutex_lock(&mlxsw_sp->acl->rules_lock);
 	list_add_tail(&rule->list, &mlxsw_sp->acl->rules);
+	mutex_unlock(&mlxsw_sp->acl->rules_lock);
 	block->rule_count++;
 	block->egress_blocker_rule_count += rule->rulei->egress_bind_blocker;
 	return 0;
@@ -723,7 +727,9 @@
 
 	block->egress_blocker_rule_count -= rule->rulei->egress_bind_blocker;
 	ruleset->ht_key.block->rule_count--;
+	mutex_lock(&mlxsw_sp->acl->rules_lock);
 	list_del(&rule->list);
+	mutex_unlock(&mlxsw_sp->acl->rules_lock);
 	if (!ruleset->ht_key.chain_index &&
 	    mlxsw_sp_acl_ruleset_is_singular(ruleset))
 		mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp, ruleset,
@@ -783,19 +789,18 @@
 	struct mlxsw_sp_acl_rule *rule;
 	int err;
 
-	/* Protect internal structures from changes */
-	rtnl_lock();
+	mutex_lock(&acl->rules_lock);
 	list_for_each_entry(rule, &acl->rules, list) {
 		err = mlxsw_sp_acl_rule_activity_update(acl->mlxsw_sp,
 							rule);
 		if (err)
 			goto err_rule_update;
 	}
-	rtnl_unlock();
+	mutex_unlock(&acl->rules_lock);
 	return 0;
 
 err_rule_update:
-	rtnl_unlock();
+	mutex_unlock(&acl->rules_lock);
 	return err;
 }
 
@@ -880,6 +885,7 @@
 	acl->dummy_fid = fid;
 
 	INIT_LIST_HEAD(&acl->rules);
+	mutex_init(&acl->rules_lock);
 	err = mlxsw_sp_acl_tcam_init(mlxsw_sp, &acl->tcam);
 	if (err)
 		goto err_acl_ops_init;
@@ -892,6 +898,7 @@
 	return 0;
 
 err_acl_ops_init:
+	mutex_destroy(&acl->rules_lock);
 	mlxsw_sp_fid_put(fid);
 err_fid_get:
 	rhashtable_destroy(&acl->ruleset_ht);
@@ -908,6 +915,7 @@
 
 	cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw);
 	mlxsw_sp_acl_tcam_fini(mlxsw_sp, &acl->tcam);
+	mutex_destroy(&acl->rules_lock);
 	WARN_ON(!list_empty(&acl->rules));
 	mlxsw_sp_fid_put(acl->dummy_fid);
 	rhashtable_destroy(&acl->ruleset_ht);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
@@ -301,6 +301,7 @@
 			     unsigned long *p_index)
 {
 	unsigned int num_rows, entry_size;
+	unsigned long index;
 
 	/* We only allow allocations of entire rows */
 	if (num_erps % erp_core->num_erp_banks != 0)
@@ -309,10 +310,11 @@
 	entry_size = erp_core->erpt_entries_size[region_type];
 	num_rows = num_erps / erp_core->num_erp_banks;
 
-	*p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
-	if (*p_index == 0)
+	index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
+	if (!index)
 		return -ENOBUFS;
-	*p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
+
+	*p_index = index - MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -290,13 +290,14 @@
 	int err;
 
 	group->tcam = tcam;
-	mutex_init(&group->lock);
 	INIT_LIST_HEAD(&group->region_list);
 
 	err = mlxsw_sp_acl_tcam_group_id_get(tcam, &group->id);
 	if (err)
 		return err;
 
+	mutex_init(&group->lock);
+
 	return 0;
 }
 
@@ -986,8 +987,9 @@
 				unsigned int priority,
 				struct mlxsw_afk_element_usage *elusage)
 {
+	struct mlxsw_sp_acl_tcam_vchunk *vchunk, *vchunk2;
 	struct mlxsw_sp_acl_tcam_vregion *vregion;
-	struct mlxsw_sp_acl_tcam_vchunk *vchunk;
+	struct list_head *pos;
 	int err;
 
 	if (priority == MLXSW_SP_ACL_TCAM_CATCHALL_PRIO)
@@ -1025,7 +1027,14 @@
 	}
 
 	mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(vregion);
-	list_add_tail(&vchunk->list, &vregion->vchunk_list);
+
+	/* Position the vchunk inside the list according to priority */
+	list_for_each(pos, &vregion->vchunk_list) {
+		vchunk2 = list_entry(pos, typeof(*vchunk2), list);
+		if (vchunk2->priority > priority)
+			break;
+	}
+	list_add_tail(&vchunk->list, pos);
 	mutex_unlock(&vregion->lock);
 
 	return vchunk;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h
@@ -7,8 +7,8 @@
 #include "spectrum.h"
 
 enum mlxsw_sp_counter_sub_pool_id {
-	MLXSW_SP_COUNTER_SUB_POOL_FLOW,
 	MLXSW_SP_COUNTER_SUB_POOL_RIF,
+	MLXSW_SP_COUNTER_SUB_POOL_FLOW,
 };
 
 int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
@@ -227,8 +227,6 @@
 static int mlxsw_sp_dcbnl_app_validate(struct net_device *dev,
 				       struct dcb_app *app)
 {
-	int prio;
-
 	if (app->priority >= IEEE_8021QAZ_MAX_TCS) {
 		netdev_err(dev, "APP entry with priority value %u is invalid\n",
 			   app->priority);
@@ -242,17 +240,6 @@
 				   app->protocol);
 			return -EINVAL;
 		}
-
-		/* Warn about any DSCP APP entries with the same PID. */
-		prio = fls(dcb_ieee_getapp_mask(dev, app));
-		if (prio--) {
-			if (prio < app->priority)
-				netdev_warn(dev, "Choosing priority %d for DSCP %d in favor of previously-active value of %d\n",
-					    app->priority, app->protocol, prio);
-			else if (prio > app->priority)
-				netdev_warn(dev, "Ignoring new priority %d for DSCP %d in favor of current value of %d\n",
-					    app->priority, app->protocol, prio);
-		}
 		break;
 
 	case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
@@ -215,7 +215,7 @@
 start_again:
 	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
 	if (err)
-		return err;
+		goto err_ctx_prepare;
 	j = 0;
 	for (; i < rif_count; i++) {
 		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
@@ -247,6 +247,7 @@
 	return 0;
 err_entry_append:
 err_entry_get:
+err_ctx_prepare:
 	rtnl_unlock();
 	devlink_dpipe_entry_clear(&entry);
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -123,9 +123,12 @@
 			u8 prio = act->vlan.prio;
 			u16 vid = act->vlan.vid;
 
-			return mlxsw_sp_acl_rulei_act_vlan(mlxsw_sp, rulei,
-							   act->id, vid,
-							   proto, prio, extack);
+			err = mlxsw_sp_acl_rulei_act_vlan(mlxsw_sp, rulei,
+							  act->id, vid,
+							  proto, prio, extack);
+			if (err)
+				return err;
+			break;
 			}
 		default:
 			NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c
@@ -524,6 +524,16 @@
 	u16 erif_index = 0;
 	int err;
 
+	/* Add the eRIF */
+	if (mlxsw_sp_mr_vif_valid(rve->mr_vif)) {
+		erif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
+		err = mr->mr_ops->route_erif_add(mlxsw_sp,
+						 rve->mr_route->route_priv,
+						 erif_index);
+		if (err)
+			return err;
+	}
+
 	/* Update the route action, as the new eVIF can be a tunnel or a pimreg
 	 * device which will require updating the action.
 	 */
@@ -533,17 +543,7 @@
 						      rve->mr_route->route_priv,
 						      route_action);
 		if (err)
-			return err;
-	}
-
-	/* Add the eRIF */
-	if (mlxsw_sp_mr_vif_valid(rve->mr_vif)) {
-		erif_index = mlxsw_sp_rif_index(rve->mr_vif->rif);
-		err = mr->mr_ops->route_erif_add(mlxsw_sp,
-						 rve->mr_route->route_priv,
-						 erif_index);
-		if (err)
-			goto err_route_erif_add;
+			goto err_route_action_update;
 	}
 
 	/* Update the minimum MTU */
@@ -561,14 +561,14 @@
 	return 0;
 
 err_route_min_mtu_update:
-	if (mlxsw_sp_mr_vif_valid(rve->mr_vif))
-		mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv,
-					   erif_index);
-err_route_erif_add:
 	if (route_action != rve->mr_route->route_action)
 		mr->mr_ops->route_action_update(mlxsw_sp,
 						rve->mr_route->route_priv,
 						rve->mr_route->route_action);
+err_route_action_update:
+	if (mlxsw_sp_mr_vif_valid(rve->mr_vif))
+		mr->mr_ops->route_erif_del(mlxsw_sp, rve->mr_route->route_priv,
+					   erif_index);
 	return err;
 }
 
@@ -637,12 +637,12 @@
 	return 0;
 
 err_erif_unresolve:
-	list_for_each_entry_from_reverse(erve, &mr_vif->route_evif_list,
-					 vif_node)
+	list_for_each_entry_continue_reverse(erve, &mr_vif->route_evif_list,
+					     vif_node)
 		mlxsw_sp_mr_route_evif_unresolve(mr_table, erve);
 err_irif_unresolve:
-	list_for_each_entry_from_reverse(irve, &mr_vif->route_ivif_list,
-					 vif_node)
+	list_for_each_entry_continue_reverse(irve, &mr_vif->route_ivif_list,
+					     vif_node)
 		mlxsw_sp_mr_route_ivif_unresolve(mr_table, irve);
 	mr_vif->rif = NULL;
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c
@@ -199,8 +199,8 @@
 	int err;
 
 	afa_block = mlxsw_afa_block_create(mlxsw_sp->afa);
-	if (!afa_block)
-		return ERR_PTR(-ENOMEM);
+	if (IS_ERR(afa_block))
+		return afa_block;
 
 	err = mlxsw_afa_block_append_allocated_counter(afa_block,
 						       counter_index);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
@@ -294,8 +294,8 @@
 	.fdb_clear_offload = mlxsw_sp_nve_vxlan_clear_offload,
 };
 
-static bool mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp,
-					     bool learning_en)
+static int mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp,
+					    bool learning_en)
 {
 	char tnpc_pl[MLXSW_REG_TNPC_LEN];
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
@@ -195,6 +195,20 @@
 	return -EOPNOTSUPP;
 }
 
+static u64
+mlxsw_sp_xstats_backlog(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
+{
+	return xstats->backlog[tclass_num] +
+	       xstats->backlog[tclass_num + 8];
+}
+
+static u64
+mlxsw_sp_xstats_tail_drop(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
+{
+	return xstats->tail_drop[tclass_num] +
+	       xstats->tail_drop[tclass_num + 8];
+}
+
 static void
 mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats,
 				       u8 prio_bitmap, u64 *tx_packets,
@@ -269,7 +283,7 @@
 					       &stats_base->tx_bytes);
 	red_base->prob_mark = xstats->ecn;
 	red_base->prob_drop = xstats->wred_drop[tclass_num];
-	red_base->pdrop = xstats->tail_drop[tclass_num];
+	red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num);
 
 	stats_base->overlimits = red_base->prob_drop + red_base->prob_mark;
 	stats_base->drops = red_base->prob_drop + red_base->pdrop;
@@ -369,7 +383,8 @@
 
 	early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
 	marks = xstats->ecn - xstats_base->prob_mark;
-	pdrops = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
+	pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
+		 xstats_base->pdrop;
 
 	res->pdrop += pdrops;
 	res->prob_drop += early_drops;
@@ -402,9 +417,10 @@
 
 	overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
 		     stats_base->overlimits;
-	drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
+	drops = xstats->wred_drop[tclass_num] +
+		mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
 		stats_base->drops;
-	backlog = xstats->backlog[tclass_num];
+	backlog = mlxsw_sp_xstats_backlog(xstats, tclass_num);
 
 	_bstats_update(stats_ptr->bstats, tx_bytes, tx_packets);
 	stats_ptr->qstats->overlimits += overlimits;
@@ -575,9 +591,9 @@
 	tx_packets = stats->tx_packets - stats_base->tx_packets;
 
 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
-		drops += xstats->tail_drop[i];
+		drops += mlxsw_sp_xstats_tail_drop(xstats, i);
 		drops += xstats->wred_drop[i];
-		backlog += xstats->backlog[i];
+		backlog += mlxsw_sp_xstats_backlog(xstats, i);
 	}
 	drops = drops - stats_base->drops;
 
@@ -613,7 +629,7 @@
 
 	stats_base->drops = 0;
 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
-		stats_base->drops += xstats->tail_drop[i];
+		stats_base->drops += mlxsw_sp_xstats_tail_drop(xstats, i);
 		stats_base->drops += xstats->wred_drop[i];
 	}
 
@@ -650,6 +666,13 @@
 	    mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle)
 		return 0;
 
+	if (!p->child_handle) {
+		/* This is an invisible FIFO replacing the original Qdisc.
+		 * Ignore it--the original Qdisc's destroy will follow.
+		 */
+		return 0;
+	}
+
 	/* See if the grafted qdisc is already offloaded on any tclass. If so,
 	 * unoffload it.
 	 */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3871,7 +3871,7 @@
 {
 	const struct fib_nh *nh = fib_info_nh(fi, 0);
 
-	return nh->fib_nh_scope == RT_SCOPE_LINK ||
+	return nh->fib_nh_gw_family ||
 	       mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
 }
 
@@ -5637,8 +5637,13 @@
 	if (mlxsw_sp_fib6_rt_should_ignore(rt))
 		return;
 
+	/* Multipath routes are first added to the FIB trie and only then
+	 * notified. If we vetoed the addition, we will get a delete
+	 * notification for a route we do not have. Therefore, do not warn if
+	 * route was not found.
+	 */
 	fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
-	if (WARN_ON(!fib6_entry))
+	if (!fib6_entry)
 		return;
 
 	/* If not all the nexthops are deleted, then only reduce the nexthop
@@ -6282,7 +6287,7 @@
 	}
 
 	fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
-	if (WARN_ON(!fib_work))
+	if (!fib_work)
 		return NOTIFY_BAD;
 
 	fib_work->mlxsw_sp = router->mlxsw_sp;
@@ -6980,6 +6985,9 @@
 
 	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 		rif = mlxsw_sp->router->rifs[i];
+		if (rif && rif->ops &&
+		    rif->ops->type == MLXSW_SP_RIF_TYPE_IPIP_LB)
+			continue;
 		if (rif && rif->dev && rif->dev != dev &&
 		    !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
 					     mlxsw_sp->mac_mask)) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -299,22 +299,17 @@
 	u64 len;
 	int err;
 
+	if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
+		this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
 	memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
 
 	if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
 		return NETDEV_TX_BUSY;
 
-	if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
-		struct sk_buff *skb_orig = skb;
-
-		skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
-		if (!skb) {
-			this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
-			dev_kfree_skb_any(skb_orig);
-			return NETDEV_TX_OK;
-		}
-		dev_consume_skb_any(skb_orig);
-	}
 	mlxsw_sx_txhdr_construct(skb, &tx_info);
 	/* TX header is consumed by HW on the way so we shouldn't count its
 	 * bytes as being sent.
@@ -1263,6 +1258,7 @@
 		if (mlxsw_sx_port_created(mlxsw_sx, i))
 			mlxsw_sx_port_remove(mlxsw_sx, i);
 	kfree(mlxsw_sx->ports);
+	mlxsw_sx->ports = NULL;
 }
 
 static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
@@ -1297,6 +1293,7 @@
 		if (mlxsw_sx_port_created(mlxsw_sx, i))
 			mlxsw_sx_port_remove(mlxsw_sx, i);
 	kfree(mlxsw_sx->ports);
+	mlxsw_sx->ports = NULL;
 	return err;
 }
 
@@ -1380,6 +1377,12 @@
 	u8 module, width;
 	int err;
 
+	if (!mlxsw_sx->ports || !mlxsw_sx->ports[local_port]) {
+		dev_err(mlxsw_sx->bus_info->dev, "Port number \"%d\" does not exist\n",
+			local_port);
+		return -EINVAL;
+	}
+
 	if (new_type == DEVLINK_PORT_TYPE_AUTO)
 		return -EOPNOTSUPP;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/micrel/ks8842.c
+++ linux-ein-5.4.0/drivers/net/ethernet/micrel/ks8842.c
@@ -1136,6 +1136,10 @@
 	unsigned i;
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem) {
+		dev_err(&pdev->dev, "Invalid resource\n");
+		return -EINVAL;
+	}
 	if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME))
 		goto err_mem_region;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/micrel/ks8851_mll.c
+++ linux-ein-5.4.0/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -157,21 +157,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;
 }
 
 /**
@@ -190,22 +216,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
@@ -324,8 +334,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;
@@ -429,7 +438,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 */
 	/**
@@ -446,7 +455,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);
 }
 
 /**
@@ -548,14 +557,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;
 	}
 
@@ -581,6 +593,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;
 }
 
@@ -650,6 +663,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);
@@ -679,13 +693,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 */
@@ -706,10 +720,9 @@
 {
 	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
@@ -723,9 +736,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;
 }
 
@@ -1251,6 +1262,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-ein-5.4.0.orig/drivers/net/ethernet/micrel/ksz884x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/micrel/ksz884x.c
@@ -1649,8 +1649,7 @@
 
 #define HW_DELAY(hw, reg)			\
 	do {					\
-		u16 dummy;			\
-		dummy = readw(hw->io + reg);	\
+		readw(hw->io + reg);		\
 	} while (0)
 
 /**
@@ -5694,7 +5693,7 @@
 		 * from the bridge.
 		 */
 		if ((hw->features & STP_SUPPORT) && !promiscuous &&
-		    (dev->priv_flags & IFF_BRIDGE_PORT)) {
+		    netif_is_bridge_port(dev)) {
 			struct ksz_switch *sw = hw->ksz_switch;
 			int port = priv->port.first_port;
 
@@ -6929,7 +6928,7 @@
 	char banner[sizeof(version)];
 	struct ksz_switch *sw = NULL;
 
-	result = pci_enable_device(pdev);
+	result = pcim_enable_device(pdev);
 	if (result)
 		return result;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/encx24j600-regmap.c
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/encx24j600-regmap.c
@@ -364,7 +364,7 @@
 		goto err_out;
 
 	usleep_range(26, 100);
-	while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
+	while (((ret = regmap_read(ctx->regmap, MISTAT, &mistat)) == 0) &&
 	       (mistat & BUSY))
 		cpu_relax();
 
@@ -402,7 +402,7 @@
 		goto err_out;
 
 	usleep_range(26, 100);
-	while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
+	while (((ret = regmap_read(ctx->regmap, MISTAT, &mistat)) == 0) &&
 	       (mistat & BUSY))
 		cpu_relax();
 
@@ -502,13 +502,19 @@
 	.reg_read = regmap_encx24j600_phy_reg_read,
 };
 
-void devm_regmap_init_encx24j600(struct device *dev,
-				 struct encx24j600_context *ctx)
+int devm_regmap_init_encx24j600(struct device *dev,
+				struct encx24j600_context *ctx)
 {
 	mutex_init(&ctx->mutex);
 	regcfg.lock_arg = ctx;
 	ctx->regmap = devm_regmap_init(dev, &regmap_encx24j600, ctx, &regcfg);
+	if (IS_ERR(ctx->regmap))
+		return PTR_ERR(ctx->regmap);
 	ctx->phymap = devm_regmap_init(dev, &phymap_encx24j600, ctx, &phycfg);
+	if (IS_ERR(ctx->phymap))
+		return PTR_ERR(ctx->phymap);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/encx24j600.c
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/encx24j600.c
@@ -1027,10 +1027,13 @@
 	priv->speed = SPEED_100;
 
 	priv->ctx.spi = spi;
-	devm_regmap_init_encx24j600(&spi->dev, &priv->ctx);
 	ndev->irq = spi->irq;
 	ndev->netdev_ops = &encx24j600_netdev_ops;
 
+	ret = devm_regmap_init_encx24j600(&spi->dev, &priv->ctx);
+	if (ret)
+		goto out_free;
+
 	mutex_init(&priv->lock);
 
 	/* Reset device and check if it is connected */
@@ -1070,7 +1073,7 @@
 	if (unlikely(ret)) {
 		netif_err(priv, probe, ndev, "Error %d initializing card encx24j600 card\n",
 			  ret);
-		goto out_free;
+		goto out_stop;
 	}
 
 	eidled = encx24j600_read_reg(priv, EIDLED);
@@ -1088,6 +1091,8 @@
 
 out_unregister:
 	unregister_netdev(priv->ndev);
+out_stop:
+	kthread_stop(priv->kworker_task);
 out_free:
 	free_netdev(ndev);
 
@@ -1100,6 +1105,7 @@
 	struct encx24j600_priv *priv = dev_get_drvdata(&spi->dev);
 
 	unregister_netdev(priv->ndev);
+	kthread_stop(priv->kworker_task);
 
 	free_netdev(priv->ndev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/encx24j600_hw.h
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/encx24j600_hw.h
@@ -15,8 +15,8 @@
 	int bank;
 };
 
-void devm_regmap_init_encx24j600(struct device *dev,
-				 struct encx24j600_context *ctx);
+int devm_regmap_init_encx24j600(struct device *dev,
+				struct encx24j600_context *ctx);
 
 /* Single-byte instructions */
 #define BANK_SELECT(bank) (0xC0 | ((bank & (BANK_MASK >> BANK_SHIFT)) << 1))
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -780,7 +780,9 @@
 
 	wol->supported = 0;
 	wol->wolopts = 0;
-	phy_ethtool_get_wol(netdev->phydev, wol);
+
+	if (netdev->phydev)
+		phy_ethtool_get_wol(netdev->phydev, wol);
 
 	wol->supported |= WAKE_BCAST | WAKE_UCAST | WAKE_MCAST |
 		WAKE_MAGIC | WAKE_PHY | WAKE_ARP;
@@ -809,9 +811,8 @@
 
 	device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts);
 
-	phy_ethtool_set_wol(netdev->phydev, wol);
-
-	return 0;
+	return netdev->phydev ? phy_ethtool_set_wol(netdev->phydev, wol)
+			: -ENETDOWN;
 }
 #endif /* CONFIG_PM */
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/lan743x_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/lan743x_main.c
@@ -12,6 +12,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/iopoll.h>
 #include <linux/crc16.h>
+#include <linux/of_net.h>
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
 
@@ -80,6 +81,18 @@
 				  !(data & HW_CFG_LRST_), 100000, 10000000);
 }
 
+static int lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter *adapter,
+					   int offset, u32 bit_mask,
+					   int target_value, int udelay_min,
+					   int udelay_max, int count)
+{
+	u32 data;
+
+	return readx_poll_timeout_atomic(LAN743X_CSR_READ_OP, offset, data,
+					 target_value == !!(data & bit_mask),
+					 udelay_max, udelay_min * count);
+}
+
 static int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter,
 				    int offset, u32 bit_mask,
 				    int target_value, int usleep_min,
@@ -145,7 +158,8 @@
 
 	int_sts = lan743x_csr_read(adapter, INT_STS);
 	if (int_sts & INT_BIT_SW_GP_) {
-		lan743x_csr_write(adapter, INT_STS, INT_BIT_SW_GP_);
+		/* disable the interrupt to prevent repeated re-triggering */
+		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
 		intr->software_isr_flag = 1;
 	}
 }
@@ -155,9 +169,8 @@
 	struct lan743x_tx *tx = context;
 	struct lan743x_adapter *adapter = tx->adapter;
 	bool enable_flag = true;
-	u32 int_en = 0;
 
-	int_en = lan743x_csr_read(adapter, INT_EN_SET);
+	lan743x_csr_read(adapter, INT_EN_SET);
 	if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) {
 		lan743x_csr_write(adapter, INT_EN_CLR,
 				  INT_BIT_DMA_TX_(tx->channel_number));
@@ -672,14 +685,12 @@
 static int lan743x_dp_write(struct lan743x_adapter *adapter,
 			    u32 select, u32 addr, u32 length, u32 *buf)
 {
-	int ret = -EIO;
 	u32 dp_sel;
 	int i;
 
-	mutex_lock(&adapter->dp_lock);
-	if (lan743x_csr_wait_for_bit(adapter, DP_SEL, DP_SEL_DPRDY_,
-				     1, 40, 100, 100))
-		goto unlock;
+	if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, DP_SEL_DPRDY_,
+					    1, 40, 100, 100))
+		return -EIO;
 	dp_sel = lan743x_csr_read(adapter, DP_SEL);
 	dp_sel &= ~DP_SEL_MASK_;
 	dp_sel |= select;
@@ -689,15 +700,13 @@
 		lan743x_csr_write(adapter, DP_ADDR, addr + i);
 		lan743x_csr_write(adapter, DP_DATA_0, buf[i]);
 		lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_);
-		if (lan743x_csr_wait_for_bit(adapter, DP_SEL, DP_SEL_DPRDY_,
-					     1, 40, 100, 100))
-			goto unlock;
+		if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL,
+						    DP_SEL_DPRDY_,
+						    1, 40, 100, 100))
+			return -EIO;
 	}
-	ret = 0;
 
-unlock:
-	mutex_unlock(&adapter->dp_lock);
-	return ret;
+	return 0;
 }
 
 static u32 lan743x_mac_mii_access(u16 id, u16 index, int read)
@@ -804,26 +813,29 @@
 	data |= MAC_CR_CNTR_RST_;
 	lan743x_csr_write(adapter, MAC_CR, data);
 
-	mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
-	mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
-	adapter->mac_address[0] = mac_addr_lo & 0xFF;
-	adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
-	adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
-	adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
-	adapter->mac_address[4] = mac_addr_hi & 0xFF;
-	adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
-
-	if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
-	    mac_addr_lo == 0xFFFFFFFF) {
-		mac_address_valid = false;
-	} else if (!is_valid_ether_addr(adapter->mac_address)) {
-		mac_address_valid = false;
-	}
+	if (!is_valid_ether_addr(adapter->mac_address)) {
+		mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
+		mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
+		adapter->mac_address[0] = mac_addr_lo & 0xFF;
+		adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
+		adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
+		adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
+		adapter->mac_address[4] = mac_addr_hi & 0xFF;
+		adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
+
+		if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
+		    mac_addr_lo == 0xFFFFFFFF) {
+			mac_address_valid = false;
+		} else if (!is_valid_ether_addr(adapter->mac_address)) {
+			mac_address_valid = false;
+		}
 
-	if (!mac_address_valid)
-		eth_random_addr(adapter->mac_address);
+		if (!mac_address_valid)
+			eth_random_addr(adapter->mac_address);
+	}
 	lan743x_mac_set_address(adapter, adapter->mac_address);
 	ether_addr_copy(netdev->dev_addr, adapter->mac_address);
+
 	return 0;
 }
 
@@ -921,8 +933,7 @@
 }
 
 static void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter,
-					   u8 duplex, u16 local_adv,
-					   u16 remote_adv)
+					   u16 local_adv, u16 remote_adv)
 {
 	struct lan743x_phy *phy = &adapter->phy;
 	u8 cap;
@@ -949,22 +960,17 @@
 
 	phy_print_status(phydev);
 	if (phydev->state == PHY_RUNNING) {
-		struct ethtool_link_ksettings ksettings;
 		int remote_advertisement = 0;
 		int local_advertisement = 0;
 
-		memset(&ksettings, 0, sizeof(ksettings));
-		phy_ethtool_get_link_ksettings(netdev, &ksettings);
 		local_advertisement =
 			linkmode_adv_to_mii_adv_t(phydev->advertising);
 		remote_advertisement =
 			linkmode_adv_to_mii_adv_t(phydev->lp_advertising);
 
-		lan743x_phy_update_flowcontrol(adapter,
-					       ksettings.base.duplex,
-					       local_advertisement,
+		lan743x_phy_update_flowcontrol(adapter, local_advertisement,
 					       remote_advertisement);
-		lan743x_ptp_update_latency(adapter, ksettings.base.speed);
+		lan743x_ptp_update_latency(adapter, phydev->speed);
 	}
 }
 
@@ -1247,13 +1253,13 @@
 		goto clear_active;
 
 	if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) {
-		dev_kfree_skb(buffer_info->skb);
+		dev_kfree_skb_any(buffer_info->skb);
 		goto clear_skb;
 	}
 
 	if (cleanup) {
 		lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
-		dev_kfree_skb(buffer_info->skb);
+		dev_kfree_skb_any(buffer_info->skb);
 	} else {
 		ignore_sync = (buffer_info->flags &
 			       TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0;
@@ -1563,7 +1569,7 @@
 	if (required_number_of_descriptors >
 		lan743x_tx_get_avail_desc(tx)) {
 		if (required_number_of_descriptors > (tx->ring_size - 1)) {
-			dev_kfree_skb(skb);
+			dev_kfree_skb_irq(skb);
 		} else {
 			/* save to overflow buffer */
 			tx->overflow_skb = skb;
@@ -1596,7 +1602,7 @@
 				   start_frame_length,
 				   do_timestamp,
 				   skb->ip_summed == CHECKSUM_PARTIAL)) {
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		goto unlock;
 	}
 
@@ -1615,7 +1621,7 @@
 			 * frame assembler clean up was performed inside
 			 *	lan743x_tx_frame_add_fragment
 			 */
-			dev_kfree_skb(skb);
+			dev_kfree_skb_irq(skb);
 			goto unlock;
 		}
 	}
@@ -1635,10 +1641,9 @@
 	bool start_transmitter = false;
 	unsigned long irq_flags = 0;
 	u32 ioc_bit = 0;
-	u32 int_sts = 0;
 
 	ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
-	int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
+	lan743x_csr_read(adapter, DMAC_INT_STS);
 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C)
 		lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit);
 	spin_lock_irqsave(&tx->ring_lock, irq_flags);
@@ -1712,6 +1717,16 @@
 		ret = -EINVAL;
 		goto cleanup;
 	}
+	if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev,
+				      DMA_BIT_MASK(64))) {
+		if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev,
+					      DMA_BIT_MASK(32))) {
+			dev_warn(&tx->adapter->pdev->dev,
+				 "lan743x_: No suitable DMA available\n");
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+	}
 	ring_allocation_size = ALIGN(tx->ring_size *
 				     sizeof(struct lan743x_tx_descriptor),
 				     PAGE_SIZE);
@@ -1894,13 +1909,21 @@
 	return ((++index) % rx->ring_size);
 }
 
-static struct sk_buff *lan743x_rx_allocate_skb(struct lan743x_rx *rx)
+static struct sk_buff *lan743x_rx_allocate_skb(struct lan743x_rx *rx, gfp_t gfp)
 {
 	int length = 0;
 
 	length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING);
 	return __netdev_alloc_skb(rx->adapter->netdev,
-				  length, GFP_ATOMIC | GFP_DMA);
+				  length, gfp);
+}
+
+static void lan743x_rx_update_tail(struct lan743x_rx *rx, int index)
+{
+	/* update the tail once per 8 descriptors */
+	if ((index & 7) == 7)
+		lan743x_csr_write(rx->adapter, RX_TAIL(rx->channel_number),
+				  index);
 }
 
 static int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index,
@@ -1933,6 +1956,7 @@
 	descriptor->data0 = (RX_DESC_DATA0_OWN_ |
 			    (length & RX_DESC_DATA0_BUF_LENGTH_MASK_));
 	skb_reserve(buffer_info->skb, RX_HEAD_PADDING);
+	lan743x_rx_update_tail(rx, index);
 
 	return 0;
 }
@@ -1951,6 +1975,7 @@
 	descriptor->data0 = (RX_DESC_DATA0_OWN_ |
 			    ((buffer_info->buffer_length) &
 			    RX_DESC_DATA0_BUF_LENGTH_MASK_));
+	lan743x_rx_update_tail(rx, index);
 }
 
 static void lan743x_rx_release_ring_element(struct lan743x_rx *rx, int index)
@@ -2063,7 +2088,8 @@
 			struct sk_buff *new_skb = NULL;
 			int packet_length;
 
-			new_skb = lan743x_rx_allocate_skb(rx);
+			new_skb = lan743x_rx_allocate_skb(rx,
+							  GFP_ATOMIC | GFP_DMA);
 			if (!new_skb) {
 				/* failed to allocate next skb.
 				 * Memory is very low.
@@ -2162,6 +2188,7 @@
 {
 	struct lan743x_rx *rx = container_of(napi, struct lan743x_rx, napi);
 	struct lan743x_adapter *adapter = rx->adapter;
+	int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
 	u32 rx_tail_flags = 0;
 	int count;
 
@@ -2170,27 +2197,19 @@
 		lan743x_csr_write(adapter, DMAC_INT_STS,
 				  DMAC_INT_BIT_RXFRM_(rx->channel_number));
 	}
-	count = 0;
-	while (count < weight) {
-		int rx_process_result = lan743x_rx_process_packet(rx);
-
-		if (rx_process_result == RX_PROCESS_RESULT_PACKET_RECEIVED) {
-			count++;
-		} else if (rx_process_result ==
-			RX_PROCESS_RESULT_NOTHING_TO_DO) {
+	for (count = 0; count < weight; count++) {
+		result = lan743x_rx_process_packet(rx);
+		if (result == RX_PROCESS_RESULT_NOTHING_TO_DO)
 			break;
-		} else if (rx_process_result ==
-			RX_PROCESS_RESULT_PACKET_DROPPED) {
-			continue;
-		}
 	}
 	rx->frame_count += count;
-	if (count == weight)
-		goto done;
+	if (count == weight || result == RX_PROCESS_RESULT_PACKET_RECEIVED)
+		return weight;
 
 	if (!napi_complete_done(napi, count))
-		goto done;
+		return count;
 
+	/* re-arm interrupts, must write to rx tail on some chip variants */
 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)
 		rx_tail_flags |= RX_TAIL_SET_TOP_INT_VEC_EN_;
 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) {
@@ -2200,10 +2219,10 @@
 				  INT_BIT_DMA_RX_(rx->channel_number));
 	}
 
-	/* update RX_TAIL */
-	lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
-			  rx_tail_flags | rx->last_tail);
-done:
+	if (rx_tail_flags)
+		lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
+				  rx_tail_flags | rx->last_tail);
+
 	return count;
 }
 
@@ -2259,6 +2278,16 @@
 		ret = -EINVAL;
 		goto cleanup;
 	}
+	if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev,
+				      DMA_BIT_MASK(64))) {
+		if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev,
+					      DMA_BIT_MASK(32))) {
+			dev_warn(&rx->adapter->pdev->dev,
+				 "lan743x_: No suitable DMA available\n");
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+	}
 	ring_allocation_size = ALIGN(rx->ring_size *
 				     sizeof(struct lan743x_rx_descriptor),
 				     PAGE_SIZE);
@@ -2297,7 +2326,8 @@
 
 	rx->last_head = 0;
 	for (index = 0; index < rx->ring_size; index++) {
-		struct sk_buff *new_skb = lan743x_rx_allocate_skb(rx);
+		struct sk_buff *new_skb = lan743x_rx_allocate_skb(rx,
+								   GFP_KERNEL);
 
 		ret = lan743x_rx_init_ring_element(rx, index, new_skb);
 		if (ret)
@@ -2348,7 +2378,7 @@
 
 	netif_napi_add(adapter->netdev,
 		       &rx->napi, lan743x_rx_napi_poll,
-		       rx->ring_size - 1);
+		       NAPI_POLL_WEIGHT);
 
 	lan743x_csr_write(adapter, DMAC_CMD,
 			  DMAC_CMD_RX_SWR_(rx->channel_number));
@@ -2674,7 +2704,6 @@
 
 	adapter->intr.irq = adapter->pdev->irq;
 	lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
-	mutex_init(&adapter->dp_lock);
 
 	ret = lan743x_gpio_init(adapter);
 	if (ret)
@@ -2756,6 +2785,7 @@
 {
 	struct lan743x_adapter *adapter = NULL;
 	struct net_device *netdev = NULL;
+	const void *mac_addr;
 	int ret = -ENODEV;
 
 	netdev = devm_alloc_etherdev(&pdev->dev,
@@ -2772,6 +2802,10 @@
 			      NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
 	netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
 
+	mac_addr = of_get_mac_address(pdev->dev.of_node);
+	if (!IS_ERR(mac_addr))
+		ether_addr_copy(adapter->mac_address, mac_addr);
+
 	ret = lan743x_pci_init(adapter, pdev);
 	if (ret)
 		goto return_error;
@@ -3005,6 +3039,8 @@
 	if (ret) {
 		netif_err(adapter, probe, adapter->netdev,
 			  "lan743x_hardware_init returned %d\n", ret);
+		lan743x_pci_cleanup(adapter);
+		return ret;
 	}
 
 	/* open netdev when netdev is at running state while resume.
@@ -3030,6 +3066,8 @@
 	{ 0, }
 };
 
+MODULE_DEVICE_TABLE(pci, lan743x_pcidev_tbl);
+
 static struct pci_driver lan743x_pcidev_driver = {
 	.name     = DRIVER_NAME,
 	.id_table = lan743x_pcidev_tbl,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/microchip/lan743x_main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/microchip/lan743x_main.h
@@ -706,9 +706,6 @@
 	struct lan743x_csr      csr;
 	struct lan743x_intr     intr;
 
-	/* lock, used to prevent concurrent access to data port */
-	struct mutex		dp_lock;
-
 	struct lan743x_gpio	gpio;
 	struct lan743x_ptp	ptp;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/moxa/moxart_ether.c
+++ linux-ein-5.4.0/drivers/net/ethernet/moxa/moxart_ether.c
@@ -74,11 +74,6 @@
 static void moxart_mac_free_memory(struct net_device *ndev)
 {
 	struct moxart_mac_priv_t *priv = netdev_priv(ndev);
-	int i;
-
-	for (i = 0; i < RX_DESC_NUM; i++)
-		dma_unmap_single(&ndev->dev, priv->rx_mapping[i],
-				 priv->rx_buf_size, DMA_FROM_DEVICE);
 
 	if (priv->tx_desc_base)
 		dma_free_coherent(&priv->pdev->dev,
@@ -147,11 +142,11 @@
 		       desc + RX_REG_OFFSET_DESC1);
 
 		priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i;
-		priv->rx_mapping[i] = dma_map_single(&ndev->dev,
+		priv->rx_mapping[i] = dma_map_single(&priv->pdev->dev,
 						     priv->rx_buf[i],
 						     priv->rx_buf_size,
 						     DMA_FROM_DEVICE);
-		if (dma_mapping_error(&ndev->dev, priv->rx_mapping[i]))
+		if (dma_mapping_error(&priv->pdev->dev, priv->rx_mapping[i]))
 			netdev_err(ndev, "DMA mapping error\n");
 
 		moxart_desc_write(priv->rx_mapping[i],
@@ -193,6 +188,7 @@
 static int moxart_mac_stop(struct net_device *ndev)
 {
 	struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+	int i;
 
 	napi_disable(&priv->napi);
 
@@ -204,6 +200,11 @@
 	/* disable all functions */
 	writel(0, priv->base + REG_MAC_CTRL);
 
+	/* unmap areas mapped in moxart_mac_setup_desc_ring() */
+	for (i = 0; i < RX_DESC_NUM; i++)
+		dma_unmap_single(&priv->pdev->dev, priv->rx_mapping[i],
+				 priv->rx_buf_size, DMA_FROM_DEVICE);
+
 	return 0;
 }
 
@@ -240,7 +241,7 @@
 		if (len > RX_BUF_SIZE)
 			len = RX_BUF_SIZE;
 
-		dma_sync_single_for_cpu(&ndev->dev,
+		dma_sync_single_for_cpu(&priv->pdev->dev,
 					priv->rx_mapping[rx_head],
 					priv->rx_buf_size, DMA_FROM_DEVICE);
 		skb = netdev_alloc_skb_ip_align(ndev, len);
@@ -294,7 +295,7 @@
 	unsigned int tx_tail = priv->tx_tail;
 
 	while (tx_tail != tx_head) {
-		dma_unmap_single(&ndev->dev, priv->tx_mapping[tx_tail],
+		dma_unmap_single(&priv->pdev->dev, priv->tx_mapping[tx_tail],
 				 priv->tx_len[tx_tail], DMA_TO_DEVICE);
 
 		ndev->stats.tx_packets++;
@@ -357,9 +358,9 @@
 
 	len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len;
 
-	priv->tx_mapping[tx_head] = dma_map_single(&ndev->dev, skb->data,
+	priv->tx_mapping[tx_head] = dma_map_single(&priv->pdev->dev, skb->data,
 						   len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&ndev->dev, priv->tx_mapping[tx_head])) {
+	if (dma_mapping_error(&priv->pdev->dev, priv->tx_mapping[tx_head])) {
 		netdev_err(ndev, "DMA mapping error\n");
 		goto out_unlock;
 	}
@@ -378,7 +379,7 @@
 		len = ETH_ZLEN;
 	}
 
-	dma_sync_single_for_device(&ndev->dev, priv->tx_mapping[tx_head],
+	dma_sync_single_for_device(&priv->pdev->dev, priv->tx_mapping[tx_head],
 				   priv->tx_buf_size, DMA_TO_DEVICE);
 
 	txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | (len & TX_DESC1_BUF_SIZE_MASK);
@@ -481,6 +482,10 @@
 	priv->pdev = pdev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto init_fail;
+	}
 	ndev->base_addr = res->start;
 	priv->base = devm_ioremap_resource(p_dev, res);
 	if (IS_ERR(priv->base)) {
@@ -494,7 +499,7 @@
 	priv->tx_buf_size = TX_BUF_SIZE;
 	priv->rx_buf_size = RX_BUF_SIZE;
 
-	priv->tx_desc_base = dma_alloc_coherent(&pdev->dev, TX_REG_DESC_SIZE *
+	priv->tx_desc_base = dma_alloc_coherent(p_dev, TX_REG_DESC_SIZE *
 						TX_DESC_NUM, &priv->tx_base,
 						GFP_DMA | GFP_KERNEL);
 	if (!priv->tx_desc_base) {
@@ -502,7 +507,7 @@
 		goto init_fail;
 	}
 
-	priv->rx_desc_base = dma_alloc_coherent(&pdev->dev, RX_REG_DESC_SIZE *
+	priv->rx_desc_base = dma_alloc_coherent(p_dev, RX_REG_DESC_SIZE *
 						RX_DESC_NUM, &priv->rx_base,
 						GFP_DMA | GFP_KERNEL);
 	if (!priv->rx_desc_base) {
@@ -541,10 +546,8 @@
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	ret = register_netdev(ndev);
-	if (ret) {
-		free_netdev(ndev);
+	if (ret)
 		goto init_fail;
-	}
 
 	netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n",
 		   __func__, ndev->irq, ndev->dev_addr);
@@ -564,7 +567,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-ein-5.4.0.orig/drivers/net/ethernet/mscc/ocelot.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mscc/ocelot.c
@@ -1024,12 +1024,6 @@
 	switch (cfg.rx_filter) {
 	case HWTSTAMP_FILTER_NONE:
 		break;
-	case HWTSTAMP_FILTER_ALL:
-	case HWTSTAMP_FILTER_SOME:
-	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
-	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-	case HWTSTAMP_FILTER_NTP_ALL:
 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
@@ -1189,7 +1183,10 @@
 				 SOF_TIMESTAMPING_RAW_HARDWARE;
 	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
 			 BIT(HWTSTAMP_TX_ONESTEP_SYNC);
-	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
+	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+			   BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
+			   BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+			   BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
 
 	return 0;
 }
@@ -1716,10 +1713,8 @@
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 	int ret = 0;
 
-	if (!ocelot_netdevice_dev_check(dev))
-		return 0;
-
 	if (event == NETDEV_PRECHANGEUPPER &&
+	    ocelot_netdevice_dev_check(dev) &&
 	    netif_is_lag_master(info->upper_dev)) {
 		struct netdev_lag_upper_info *lag_upper_info = info->upper_info;
 		struct netlink_ext_ack *extack;
@@ -1979,14 +1974,18 @@
 
 static int ocelot_init_timestamp(struct ocelot *ocelot)
 {
+	struct ptp_clock *ptp_clock;
+
 	ocelot->ptp_info = ocelot_ptp_clock_info;
-	ocelot->ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
-	if (IS_ERR(ocelot->ptp_clock))
-		return PTR_ERR(ocelot->ptp_clock);
+	ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
+	if (IS_ERR(ptp_clock))
+		return PTR_ERR(ptp_clock);
 	/* Check if PHC support is missing at the configuration level */
-	if (!ocelot->ptp_clock)
+	if (!ptp_clock)
 		return 0;
 
+	ocelot->ptp_clock = ptp_clock;
+
 	ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
 	ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
 	ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
@@ -2154,8 +2153,12 @@
 	ocelot_write_rix(ocelot,
 			 ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)),
 			 ANA_PGID_PGID, PGID_MC);
-	ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4);
-	ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6);
+	ocelot_write_rix(ocelot,
+			 ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)),
+			 ANA_PGID_PGID, PGID_MCIPV4);
+	ocelot_write_rix(ocelot,
+			 ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)),
+			 ANA_PGID_PGID, PGID_MCIPV6);
 
 	/* CPU port Injection/Extraction configuration */
 	ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
@@ -2213,6 +2216,8 @@
 	destroy_workqueue(ocelot->stats_queue);
 	mutex_destroy(&ocelot->stats_lock);
 	ocelot_ace_deinit();
+	if (ocelot->ptp_clock)
+		ptp_clock_unregister(ocelot->ptp_clock);
 
 	for (i = 0; i < ocelot->num_phys_ports; i++) {
 		port = ocelot->ports[i];
--- linux-ein-5.4.0.orig/drivers/net/ethernet/mscc/ocelot_board.c
+++ linux-ein-5.4.0/drivers/net/ethernet/mscc/ocelot_board.c
@@ -112,6 +112,14 @@
 		if (err != 4)
 			break;
 
+		/* At this point the IFH was read correctly, so it is safe to
+		 * presume that there is no error. The err needs to be reset
+		 * otherwise a frame could come in CPU queue between the while
+		 * condition and the check for error later on. And in that case
+		 * the new frame is just removed and not processed.
+		 */
+		err = 0;
+
 		ocelot_parse_ifh(ifh, &info);
 
 		dev = ocelot->ports[info.port]->dev;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ linux-ein-5.4.0/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -3849,6 +3849,7 @@
 		dev_err(&pdev->dev,
 			"invalid sram_size %dB or board span %ldB\n",
 			mgp->sram_size, mgp->board_span);
+		status = -EINVAL;
 		goto abort_with_ioremap;
 	}
 	memcpy_fromio(mgp->eeprom_strings,
@@ -3955,6 +3956,7 @@
 	myri10ge_free_slices(mgp);
 
 abort_with_firmware:
+	kfree(mgp->msix_vectors);
 	myri10ge_dummy_rdma(mgp, 0);
 
 abort_with_ioremap:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/natsemi/jazzsonic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -235,11 +235,13 @@
 
 	err = register_netdev(dev);
 	if (err)
-		goto out1;
+		goto undo_probe1;
 
 	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-ein-5.4.0.orig/drivers/net/ethernet/natsemi/macsonic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/macsonic.c
@@ -540,10 +540,14 @@
 
 	err = register_netdev(dev);
 	if (err)
-		goto out;
+		goto undo_probe;
 
 	return 0;
 
+undo_probe:
+	dma_free_coherent(lp->device,
+			  SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+			  lp->descriptors, lp->descriptors_laddr);
 out:
 	free_netdev(dev);
 
@@ -618,12 +622,16 @@
 
 	err = register_netdev(ndev);
 	if (err)
-		goto out;
+		goto undo_probe;
 
 	nubus_set_drvdata(board, ndev);
 
 	return 0;
 
+undo_probe:
+	dma_free_coherent(lp->device,
+			  SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+			  lp->descriptors, lp->descriptors_laddr);
 out:
 	free_netdev(ndev);
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/natsemi/natsemi.c
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/natsemi.c
@@ -819,7 +819,7 @@
 		printk(version);
 #endif
 
-	i = pci_enable_device(pdev);
+	i = pcim_enable_device(pdev);
 	if (i) return i;
 
 	/* natsemi has a non-standard PM control register
@@ -852,7 +852,7 @@
 	ioaddr = ioremap(iostart, iosize);
 	if (!ioaddr) {
 		i = -ENOMEM;
-		goto err_ioremap;
+		goto err_pci_request_regions;
 	}
 
 	/* Work around the dropped serial bit. */
@@ -974,9 +974,6 @@
  err_register_netdev:
 	iounmap(ioaddr);
 
- err_ioremap:
-	pci_release_regions(pdev);
-
  err_pci_request_regions:
 	free_netdev(dev);
 	return i;
@@ -3242,7 +3239,6 @@
 
 	NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround);
 	unregister_netdev (dev);
-	pci_release_regions (pdev);
 	iounmap(ioaddr);
 	free_netdev (dev);
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/natsemi/sonic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/sonic.c
@@ -64,6 +64,8 @@
 
 	netif_dbg(lp, ifup, dev, "%s: initializing sonic driver\n", __func__);
 
+	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) {
@@ -114,6 +116,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
@@ -130,6 +150,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);
@@ -169,6 +192,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);
@@ -206,8 +232,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)
@@ -215,7 +239,8 @@
 	struct sonic_local *lp = netdev_priv(dev);
 	dma_addr_t laddr;
 	int length;
-	int entry = lp->next_tx;
+	int entry;
+	unsigned long flags;
 
 	netif_dbg(lp, tx_queued, dev, "%s: skb=%p\n", __func__, skb);
 
@@ -231,12 +256,16 @@
 	 */
 
 	laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
-	if (!laddr) {
+	if (dma_mapping_error(lp->device, laddr)) {
 		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 */
@@ -246,10 +275,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;
@@ -272,6 +297,8 @@
 
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
 
+	spin_unlock_irqrestore(&lp->lock, flags);
+
 	return NETDEV_TX_OK;
 }
 
@@ -284,15 +311,28 @@
 	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 {
+		SONIC_WRITE(SONIC_ISR, status); /* clear the interrupt(s) */
+
 		if (status & SONIC_INT_PKTRX) {
 			netif_dbg(lp, intr, dev, "%s: packet rx\n", __func__);
 			sonic_rx(dev);	/* got packet(s) */
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
 		}
 
 		if (status & SONIC_INT_TXDN) {
@@ -300,11 +340,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
 			 */
 
 			netif_dbg(lp, intr, dev, "%s: tx done\n", __func__);
@@ -313,18 +354,19 @@
 				if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0)
 					break;
 
-				if (td_status & 0x0001) {
+				if (td_status & SONIC_TCR_PTX) {
 					lp->stats.tx_packets++;
 					lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE);
 				} else {
-					lp->stats.tx_errors++;
-					if (td_status & 0x0642)
+					if (td_status & (SONIC_TCR_EXD |
+					    SONIC_TCR_EXC | SONIC_TCR_BCM))
 						lp->stats.tx_aborted_errors++;
-					if (td_status & 0x0180)
+					if (td_status &
+					    (SONIC_TCR_NCRS | SONIC_TCR_CRLS))
 						lp->stats.tx_carrier_errors++;
-					if (td_status & 0x0020)
+					if (td_status & SONIC_TCR_OWC)
 						lp->stats.tx_window_errors++;
-					if (td_status & 0x0004)
+					if (td_status & SONIC_TCR_FU)
 						lp->stats.tx_fifo_errors++;
 				}
 
@@ -346,7 +388,6 @@
 			if (freed_some || lp->tx_skb[entry] == NULL)
 				netif_wake_queue(dev);  /* The ring is no longer full */
 			lp->cur_tx = entry;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
 		}
 
 		/*
@@ -355,42 +396,37 @@
 		if (status & SONIC_INT_RFO) {
 			netif_dbg(lp, rx_err, dev, "%s: rx fifo overrun\n",
 				  __func__);
-			lp->stats.rx_fifo_errors++;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
 		}
 		if (status & SONIC_INT_RDE) {
 			netif_dbg(lp, rx_err, dev, "%s: rx descriptors exhausted\n",
 				  __func__);
-			lp->stats.rx_dropped++;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
 		}
 		if (status & SONIC_INT_RBAE) {
 			netif_dbg(lp, rx_err, dev, "%s: rx buffer area exceeded\n",
 				  __func__);
-			lp->stats.rx_dropped++;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
 		}
 
 		/* counter overruns; all counters are 16bit wide */
-		if (status & SONIC_INT_FAE) {
+		if (status & SONIC_INT_FAE)
 			lp->stats.rx_frame_errors += 65536;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
-		}
-		if (status & SONIC_INT_CRC) {
+		if (status & SONIC_INT_CRC)
 			lp->stats.rx_crc_errors += 65536;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
-		}
-		if (status & SONIC_INT_MP) {
+		if (status & SONIC_INT_MP)
 			lp->stats.rx_missed_errors += 65536;
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
-		}
 
 		/* transmit error */
 		if (status & SONIC_INT_TXER) {
-			if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU)
-				netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n",
-					  __func__);
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
+			u16 tcr = SONIC_READ(SONIC_TCR);
+
+			netif_dbg(lp, tx_err, dev, "%s: TXER intr, TCR %04x\n",
+				  __func__, tcr);
+
+			if (tcr & (SONIC_TCR_EXD | SONIC_TCR_EXC |
+				   SONIC_TCR_FU | SONIC_TCR_BCM)) {
+				/* Aborted transmission. Try again. */
+				netif_stop_queue(dev);
+				SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
+			}
 		}
 
 		/* bus retry */
@@ -400,107 +436,164 @@
 			/* ... to help debug DMA problems causing endless interrupts. */
 			/* Bounce the eth interface to turn on the interrupt again. */
 			SONIC_WRITE(SONIC_IMR, 0);
-			SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
 		}
 
-		/* 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;
+}
+
+/* Allocate and map a new skb to be used as a receive buffer. */
+static bool sonic_alloc_rb(struct net_device *dev, struct sonic_local *lp,
+			   struct sk_buff **new_skb, dma_addr_t *new_addr)
+{
+	*new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
+	if (!*new_skb)
+		return false;
+
+	if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
+		skb_reserve(*new_skb, 2);
+
+	*new_addr = dma_map_single(lp->device, skb_put(*new_skb, SONIC_RBSIZE),
+				   SONIC_RBSIZE, DMA_FROM_DEVICE);
+	if (dma_mapping_error(lp->device, *new_addr)) {
+		dev_kfree_skb(*new_skb);
+		*new_skb = NULL;
+		return false;
+	}
+
+	return true;
+}
+
+/* Place a new receive resource in the Receive Resource Area and update RWP. */
+static void sonic_update_rra(struct net_device *dev, struct sonic_local *lp,
+			     dma_addr_t old_addr, dma_addr_t new_addr)
+{
+	unsigned int entry = sonic_rr_entry(dev, SONIC_READ(SONIC_RWP));
+	unsigned int end = sonic_rr_entry(dev, SONIC_READ(SONIC_RRP));
+	u32 buf;
+
+	/* The resources in the range [RRP, RWP) belong to the SONIC. This loop
+	 * scans the other resources in the RRA, those in the range [RWP, RRP).
+	 */
+	do {
+		buf = (sonic_rra_get(dev, entry, SONIC_RR_BUFADR_H) << 16) |
+		      sonic_rra_get(dev, entry, SONIC_RR_BUFADR_L);
+
+		if (buf == old_addr)
+			break;
+
+		entry = (entry + 1) & SONIC_RRS_MASK;
+	} while (entry != end);
+
+	WARN_ONCE(buf != old_addr, "failed to find resource!\n");
+
+	sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, new_addr >> 16);
+	sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, new_addr & 0xffff);
+
+	entry = (entry + 1) & SONIC_RRS_MASK;
+
+	SONIC_WRITE(SONIC_RWP, sonic_rr_addr(dev, entry));
+}
+
 /*
  * We have a good packet(s), pass it/them up the network stack.
  */
 static void sonic_rx(struct net_device *dev)
 {
 	struct sonic_local *lp = netdev_priv(dev);
-	int status;
 	int entry = lp->cur_rx;
+	int prev_entry = lp->eol_rx;
+	bool rbe = false;
 
 	while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
-		struct sk_buff *used_skb;
-		struct sk_buff *new_skb;
-		dma_addr_t new_laddr;
-		u16 bufadr_l;
-		u16 bufadr_h;
-		int pkt_len;
-
-		status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
-		if (status & SONIC_RCR_PRX) {
-			/* Malloc up new buffer. */
-			new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
-			if (new_skb == NULL) {
-				lp->stats.rx_dropped++;
+		u16 status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
+
+		/* If the RD has LPKT set, the chip has finished with the RB */
+		if ((status & SONIC_RCR_PRX) && (status & SONIC_RCR_LPKT)) {
+			struct sk_buff *new_skb;
+			dma_addr_t new_laddr;
+			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;
 			}
-			/* provide 16 byte IP header alignment unless DMA requires otherwise */
-			if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
-				skb_reserve(new_skb, 2);
-
-			new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
-		                               SONIC_RBSIZE, DMA_FROM_DEVICE);
-			if (!new_laddr) {
-				dev_kfree_skb(new_skb);
-				printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name);
+
+			if (sonic_alloc_rb(dev, lp, &new_skb, &new_laddr)) {
+				struct sk_buff *used_skb = lp->rx_skb[i];
+				int pkt_len;
+
+				/* Pass the used buffer up the stack */
+				dma_unmap_single(lp->device, addr, SONIC_RBSIZE,
+						 DMA_FROM_DEVICE);
+
+				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);
+				netif_rx(used_skb);
+				lp->stats.rx_packets++;
+				lp->stats.rx_bytes += pkt_len;
+
+				lp->rx_skb[i] = new_skb;
+				lp->rx_laddr[i] = new_laddr;
+			} else {
+				/* Failed to obtain a new buffer so re-use it */
+				new_laddr = addr;
 				lp->stats.rx_dropped++;
-				break;
 			}
-
-			/* 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];
-			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);
-			netif_rx(used_skb);
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
-
-			/* and insert the new skb */
-			lp->rx_laddr[entry] = new_laddr;
-			lp->rx_skb[entry] = 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);
-		} else {
-			/* This should only happen, if we enable accepting broken packets. */
-			lp->stats.rx_errors++;
-			if (status & SONIC_RCR_FAER)
-				lp->stats.rx_frame_errors++;
-			if (status & SONIC_RCR_CRCR)
-				lp->stats.rx_crc_errors++;
-		}
-		if (status & SONIC_RCR_LPKT) {
-			/*
-			 * this was the last packet out of the current receive buffer
-			 * give the buffer back to the SONIC
+			/* If RBE is already asserted when RWP advances then
+			 * it's safe to clear RBE after processing this packet.
 			 */
-			lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
-			if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff;
-			SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
-			if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) {
-				netif_dbg(lp, rx_err, dev, "%s: rx buffer exhausted\n",
-					  __func__);
-				SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
-			}
-		} else
-			printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
-			     dev->name);
+			rbe = rbe || SONIC_READ(SONIC_ISR) & SONIC_INT_RBE;
+			sonic_update_rra(dev, lp, addr, new_laddr);
+		}
 		/*
 		 * give back the descriptor
 		 */
-		sonic_rda_put(dev, entry, SONIC_RD_LINK,
-			sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL);
+		sonic_rda_put(dev, entry, SONIC_RD_STATUS, 0);
 		sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
-		sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK,
-			sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL);
-		lp->eol_rx = entry;
-		lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK;
+
+		prev_entry = entry;
+		entry = (entry + 1) & SONIC_RDS_MASK;
+	}
+
+	lp->cur_rx = entry;
+
+	if (prev_entry != lp->eol_rx) {
+		/* Advance the EOL flag to put descriptors back into service */
+		sonic_rda_put(dev, prev_entry, SONIC_RD_LINK, SONIC_EOL |
+			      sonic_rda_get(dev, prev_entry, SONIC_RD_LINK));
+		sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK, ~SONIC_EOL &
+			      sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK));
+		lp->eol_rx = prev_entry;
 	}
+
+	if (rbe)
+		SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE);
 	/*
 	 * If any worth-while packets have been received, netif_rx()
 	 * has done a mark_bh(NET_BH) for us and will work on them
@@ -550,6 +643,8 @@
 		    (netdev_mc_count(dev) > 15)) {
 			rcr |= SONIC_RCR_AMC;
 		} else {
+			unsigned long flags;
+
 			netif_dbg(lp, ifup, dev, "%s: mc_count %d\n", __func__,
 				  netdev_mc_count(dev));
 			sonic_set_cam_enable(dev, 1);  /* always enable our own address */
@@ -563,9 +658,14 @@
 				i++;
 			}
 			SONIC_WRITE(SONIC_CDC, 16);
-			/* issue Load CAM command */
 			SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
+
+			/* LCAM and TXP commands can't be used simultaneously */
+			spin_lock_irqsave(&lp->lock, flags);
+			sonic_quiesce(dev, SONIC_CR_TXP);
 			SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
+			sonic_quiesce(dev, SONIC_CR_LCAM);
+			spin_unlock_irqrestore(&lp->lock, flags);
 		}
 	}
 
@@ -580,7 +680,6 @@
  */
 static int sonic_init(struct net_device *dev)
 {
-	unsigned int cmd;
 	struct sonic_local *lp = netdev_priv(dev);
 	int i;
 
@@ -592,12 +691,16 @@
 	SONIC_WRITE(SONIC_ISR, 0x7fff);
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
 
+	/* While in reset mode, clear CAM Enable register */
+	SONIC_WRITE(SONIC_CE, 0);
+
 	/*
 	 * clear software reset flag, disable receiver, clear and
 	 * enable interrupts, then completely initialize the SONIC
 	 */
 	SONIC_WRITE(SONIC_CMD, 0);
-	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS | SONIC_CR_STP);
+	sonic_quiesce(dev, SONIC_CR_ALL);
 
 	/*
 	 * initialize the receive resource area
@@ -615,15 +718,10 @@
 	}
 
 	/* initialize all RRA registers */
-	lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR *
-					SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
-	lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
-					SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
-
-	SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
-	SONIC_WRITE(SONIC_REA, lp->rra_end);
-	SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
-	SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
+	SONIC_WRITE(SONIC_RSA, sonic_rr_addr(dev, 0));
+	SONIC_WRITE(SONIC_REA, sonic_rr_addr(dev, SONIC_NUM_RRS));
+	SONIC_WRITE(SONIC_RRP, sonic_rr_addr(dev, 0));
+	SONIC_WRITE(SONIC_RWP, sonic_rr_addr(dev, SONIC_NUM_RRS - 1));
 	SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
 	SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1));
 
@@ -631,14 +729,7 @@
 	netif_dbg(lp, ifup, dev, "%s: issuing RRRA command\n", __func__);
 
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
-	i = 0;
-	while (i++ < 100) {
-		if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
-			break;
-	}
-
-	netif_dbg(lp, ifup, dev, "%s: status=%x, i=%d\n", __func__,
-		  SONIC_READ(SONIC_CMD), i);
+	sonic_quiesce(dev, SONIC_CR_RRRA);
 
 	/*
 	 * Initialize the receive descriptors so that they
@@ -713,28 +804,17 @@
 	 * load the CAM
 	 */
 	SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
-
-	i = 0;
-	while (i++ < 100) {
-		if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
-			break;
-	}
-	netif_dbg(lp, ifup, dev, "%s: CMD=%x, ISR=%x, i=%d\n", __func__,
-		  SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i);
+	sonic_quiesce(dev, SONIC_CR_LCAM);
 
 	/*
 	 * enable receiver, disable loopback
 	 * and enable all interrupts
 	 */
-	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN | SONIC_CR_STP);
 	SONIC_WRITE(SONIC_RCR, SONIC_RCR_DEFAULT);
 	SONIC_WRITE(SONIC_TCR, SONIC_TCR_DEFAULT);
 	SONIC_WRITE(SONIC_ISR, 0x7fff);
 	SONIC_WRITE(SONIC_IMR, SONIC_IMR_DEFAULT);
-
-	cmd = SONIC_READ(SONIC_CMD);
-	if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
-		printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN);
 
 	netif_dbg(lp, ifup, dev, "%s: new status=%x\n", __func__,
 		  SONIC_READ(SONIC_CMD));
--- linux-ein-5.4.0.orig/drivers/net/ethernet/natsemi/sonic.h
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/sonic.h
@@ -110,6 +110,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
  */
@@ -175,6 +178,7 @@
 #define SONIC_TCR_NCRS          0x0100
 #define SONIC_TCR_CRLS          0x0080
 #define SONIC_TCR_EXC           0x0040
+#define SONIC_TCR_OWC           0x0020
 #define SONIC_TCR_PMB           0x0008
 #define SONIC_TCR_FU            0x0004
 #define SONIC_TCR_BCM           0x0002
@@ -274,8 +278,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 */
 
@@ -312,8 +317,6 @@
 	u32 rda_laddr;              /* logical DMA address of RDA */
 	dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */
 	dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */
-	unsigned int rra_end;
-	unsigned int cur_rwp;
 	unsigned int cur_rx;
 	unsigned int cur_tx;           /* first unacked transmit packet */
 	unsigned int eol_rx;
@@ -322,6 +325,7 @@
 	int msg_enable;
 	struct device *device;         /* generic device */
 	struct net_device_stats stats;
+	spinlock_t lock;
 };
 
 #define TX_TIMEOUT (3 * HZ)
@@ -344,30 +348,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 */
@@ -447,6 +451,22 @@
 			     (entry * SIZEOF_SONIC_RR) + offset);
 }
 
+static inline u16 sonic_rr_addr(struct net_device *dev, int entry)
+{
+	struct sonic_local *lp = netdev_priv(dev);
+
+	return lp->rra_laddr +
+	       entry * SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
+}
+
+static inline u16 sonic_rr_entry(struct net_device *dev, u16 addr)
+{
+	struct sonic_local *lp = netdev_priv(dev);
+
+	return (addr - (u16)lp->rra_laddr) / (SIZEOF_SONIC_RR *
+					      SONIC_BUS_SCALE(lp->dma_bitmode));
+}
+
 static const char version[] =
     "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/natsemi/xtsonic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/natsemi/xtsonic.c
@@ -120,7 +120,7 @@
 	.ndo_set_mac_address	= eth_mac_addr,
 };
 
-static int __init sonic_probe1(struct net_device *dev)
+static int sonic_probe1(struct net_device *dev)
 {
 	unsigned int silicon_revision;
 	struct sonic_local *lp = netdev_priv(dev);
@@ -265,11 +265,14 @@
 	sonic_msg_init(dev);
 
 	if ((err = register_netdev(dev)))
-		goto out1;
+		goto undo_probe1;
 
 	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_region(dev->base_addr, SONIC_MEM_SIZE);
 out:
 	free_netdev(dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/neterion/s2io.c
+++ linux-ein-5.4.0/drivers/net/ethernet/neterion/s2io.c
@@ -2375,7 +2375,7 @@
 			skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
 			if (skb) {
 				swstats->mem_freed += skb->truesize;
-				dev_kfree_skb(skb);
+				dev_kfree_skb_irq(skb);
 				cnt++;
 			}
 		}
@@ -7122,9 +7122,8 @@
 		if (ret) {
 			DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
 				  dev->name);
-			s2io_reset(sp);
-			free_rx_buffers(sp);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_fill_buff;
 		}
 		DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
 			  ring->rx_bufs_left);
@@ -7162,18 +7161,16 @@
 	/* Enable Rx Traffic and interrupts on the NIC */
 	if (start_nic(sp)) {
 		DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
-		s2io_reset(sp);
-		free_rx_buffers(sp);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_out;
 	}
 
 	/* Add interrupt service routine */
 	if (s2io_add_isr(sp) != 0) {
 		if (sp->config.intr_type == MSI_X)
 			s2io_rem_isr(sp);
-		s2io_reset(sp);
-		free_rx_buffers(sp);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_out;
 	}
 
 	timer_setup(&sp->alarm_timer, s2io_alarm_handle, 0);
@@ -7193,6 +7190,20 @@
 	}
 
 	return 0;
+
+err_out:
+	if (config->napi) {
+		if (config->intr_type == MSI_X) {
+			for (i = 0; i < sp->config.rx_ring_num; i++)
+				napi_disable(&sp->mac_control.rings[i].napi);
+		} else {
+			napi_disable(&sp->napi);
+		}
+	}
+err_fill_buff:
+	s2io_reset(sp);
+	free_rx_buffers(sp);
+	return ret;
 }
 
 /**
@@ -7276,7 +7287,7 @@
 	int ring_no = ring_data->ring_no;
 	u16 l3_csum, l4_csum;
 	unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
-	struct lro *uninitialized_var(lro);
+	struct lro *lro;
 	u8 err_mask;
 	struct swStat *swstats = &sp->mac_control.stats_info->sw_stat;
 
@@ -8565,7 +8576,7 @@
 			return;
 		}
 
-		if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) {
+		if (do_s2io_prog_unicast(netdev, netdev->dev_addr) == FAILURE) {
 			s2io_card_down(sp);
 			pr_err("Can't restore mac addr after reset.\n");
 			return;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-config.h
+++ linux-ein-5.4.0/drivers/net/ethernet/neterion/vxge/vxge-config.h
@@ -2045,7 +2045,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-ein-5.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -3524,13 +3524,13 @@
 
 	kfree(vdev->vpaths);
 
-	/* we are safe to free it now */
-	free_netdev(dev);
-
 	vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered",
 			buf);
 	vxge_debug_entryexit(vdev->level_trace,	"%s: %s:%d  Exiting...", buf,
 			     __func__, __LINE__);
+
+	/* we are safe to free it now */
+	free_netdev(dev);
 }
 
 /*
@@ -4197,6 +4197,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;
@@ -4239,9 +4242,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
@@ -4846,3 +4849,5 @@
 }
 module_init(vxge_starter);
 module_exit(vxge_closer);
+MODULE_FIRMWARE(VXGE_PXE_FIRMWARE);
+MODULE_FIRMWARE(VXGE_FIRMWARE);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/neterion/vxge/vxge-main.h
@@ -452,49 +452,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-ein-5.4.0.orig/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
@@ -30,8 +30,6 @@
  */
 enum vxge_hw_status vxge_hw_vpath_intr_enable(struct __vxge_hw_vpath_handle *vp)
 {
-	u64 val64;
-
 	struct __vxge_hw_virtualpath *vpath;
 	struct vxge_hw_vpath_reg __iomem *vp_reg;
 	enum vxge_hw_status status = VXGE_HW_OK;
@@ -84,7 +82,7 @@
 	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
 			&vp_reg->xgmac_vp_int_status);
 
-	val64 = readq(&vp_reg->vpath_general_int_status);
+	readq(&vp_reg->vpath_general_int_status);
 
 	/* Mask unwanted interrupts */
 
@@ -157,8 +155,6 @@
 enum vxge_hw_status vxge_hw_vpath_intr_disable(
 			struct __vxge_hw_vpath_handle *vp)
 {
-	u64 val64;
-
 	struct __vxge_hw_virtualpath *vpath;
 	enum vxge_hw_status status = VXGE_HW_OK;
 	struct vxge_hw_vpath_reg __iomem *vp_reg;
@@ -179,8 +175,6 @@
 		(u32)VXGE_HW_INTR_MASK_ALL,
 		&vp_reg->vpath_general_int_mask);
 
-	val64 = VXGE_HW_TIM_CLR_INT_EN_VP(1 << (16 - vpath->vp_id));
-
 	writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_mask);
 
 	__vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
@@ -487,9 +481,7 @@
  */
 void vxge_hw_device_flush_io(struct __vxge_hw_device *hldev)
 {
-	u32 val32;
-
-	val32 = readl(&hldev->common_reg->titan_general_int_status);
+	readl(&hldev->common_reg->titan_general_int_status);
 }
 
 /**
@@ -1716,8 +1708,8 @@
 enum vxge_hw_status
 vxge_hw_vpath_mac_addr_add(
 	struct __vxge_hw_vpath_handle *vp,
-	u8 (macaddr)[ETH_ALEN],
-	u8 (macaddr_mask)[ETH_ALEN],
+	u8 *macaddr,
+	u8 *macaddr_mask,
 	enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode)
 {
 	u32 i;
@@ -1779,8 +1771,8 @@
 enum vxge_hw_status
 vxge_hw_vpath_mac_addr_get(
 	struct __vxge_hw_vpath_handle *vp,
-	u8 (macaddr)[ETH_ALEN],
-	u8 (macaddr_mask)[ETH_ALEN])
+	u8 *macaddr,
+	u8 *macaddr_mask)
 {
 	u32 i;
 	u64 data1 = 0ULL;
@@ -1831,8 +1823,8 @@
 enum vxge_hw_status
 vxge_hw_vpath_mac_addr_get_next(
 	struct __vxge_hw_vpath_handle *vp,
-	u8 (macaddr)[ETH_ALEN],
-	u8 (macaddr_mask)[ETH_ALEN])
+	u8 *macaddr,
+	u8 *macaddr_mask)
 {
 	u32 i;
 	u64 data1 = 0ULL;
@@ -1884,8 +1876,8 @@
 enum vxge_hw_status
 vxge_hw_vpath_mac_addr_delete(
 	struct __vxge_hw_vpath_handle *vp,
-	u8 (macaddr)[ETH_ALEN],
-	u8 (macaddr_mask)[ETH_ALEN])
+	u8 *macaddr,
+	u8 *macaddr_mask)
 {
 	u32 i;
 	u64 data1 = 0ULL;
@@ -2375,7 +2367,6 @@
 	u8 t_code;
 	enum vxge_hw_status status = VXGE_HW_OK;
 	void *first_rxdh;
-	u64 val64 = 0;
 	int new_count = 0;
 
 	ring->cmpl_cnt = 0;
@@ -2403,8 +2394,7 @@
 			}
 			writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(new_count),
 				&ring->vp_reg->prc_rxd_doorbell);
-			val64 =
-			  readl(&ring->common_reg->titan_general_int_status);
+			readl(&ring->common_reg->titan_general_int_status);
 			ring->doorbell_cnt = 0;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/abm/cls.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/abm/cls.c
@@ -176,10 +176,8 @@
 	u8 mask, val;
 	int err;
 
-	if (!nfp_abm_u32_check_knode(alink->abm, knode, proto, extack)) {
-		err = -EOPNOTSUPP;
+	if (!nfp_abm_u32_check_knode(alink->abm, knode, proto, extack))
 		goto err_delete;
-	}
 
 	tos_off = proto == htons(ETH_P_IP) ? 16 : 20;
 
@@ -200,18 +198,14 @@
 		if ((iter->val & cmask) == (val & cmask) &&
 		    iter->band != knode->res->classid) {
 			NL_SET_ERR_MSG_MOD(extack, "conflict with already offloaded filter");
-			err = -EOPNOTSUPP;
 			goto err_delete;
 		}
 	}
 
 	if (!match) {
 		match = kzalloc(sizeof(*match), GFP_KERNEL);
-		if (!match) {
-			err = -ENOMEM;
-			goto err_delete;
-		}
-
+		if (!match)
+			return -ENOMEM;
 		list_add(&match->list, &alink->dscp_map);
 	}
 	match->handle = knode->handle;
@@ -227,7 +221,7 @@
 
 err_delete:
 	nfp_abm_u32_knode_delete(alink, knode);
-	return err;
+	return -EOPNOTSUPP;
 }
 
 static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/abm/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/abm/main.c
@@ -283,6 +283,7 @@
 	if (!nfp_nsp_has_hwinfo_lookup(nsp)) {
 		nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n");
 		eth_hw_addr_random(nn->dp.netdev);
+		nfp_nsp_close(nsp);
 		return;
 	}
 
@@ -332,8 +333,10 @@
 		goto err_free_alink;
 
 	alink->prio_map = kzalloc(abm->prio_map_len, GFP_KERNEL);
-	if (!alink->prio_map)
+	if (!alink->prio_map) {
+		err = -ENOMEM;
 		goto err_free_alink;
+	}
 
 	/* This is a multi-host app, make sure MAC/PHY is up, but don't
 	 * make the MAC/PHY state follow the state of any of the ports.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
@@ -454,6 +454,7 @@
 			dev_consume_skb_any(skb);
 		else
 			dev_kfree_skb_any(skb);
+		return;
 	}
 
 	nfp_ccm_rx(&bpf->ccm, skb);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -182,15 +182,21 @@
 nfp_bpf_check_mtu(struct nfp_app *app, struct net_device *netdev, int new_mtu)
 {
 	struct nfp_net *nn = netdev_priv(netdev);
-	unsigned int max_mtu;
+	struct nfp_bpf_vnic *bv;
+	struct bpf_prog *prog;
 
 	if (~nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)
 		return 0;
 
-	max_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32;
-	if (new_mtu > max_mtu) {
-		nn_info(nn, "BPF offload active, MTU over %u not supported\n",
-			max_mtu);
+	if (nn->xdp_hw.prog) {
+		prog = nn->xdp_hw.prog;
+	} else {
+		bv = nn->app_priv;
+		prog = bv->tc_prog;
+	}
+
+	if (nfp_bpf_offload_check_mtu(nn, prog, new_mtu)) {
+		nn_info(nn, "BPF offload active, potential packet access beyond hardware packet boundary");
 		return -EBUSY;
 	}
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -560,6 +560,8 @@
 void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog);
 int nfp_bpf_jit(struct nfp_prog *prog);
 bool nfp_bpf_supported_opcode(u8 code);
+bool nfp_bpf_offload_check_mtu(struct nfp_net *nn, struct bpf_prog *prog,
+			       unsigned int mtu);
 
 int nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx,
 		    int prev_insn_idx);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/bpf/offload.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/bpf/offload.c
@@ -477,19 +477,28 @@
 	return 0;
 }
 
+bool nfp_bpf_offload_check_mtu(struct nfp_net *nn, struct bpf_prog *prog,
+			       unsigned int mtu)
+{
+	unsigned int fw_mtu, pkt_off;
+
+	fw_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32;
+	pkt_off = min(prog->aux->max_pkt_offset, mtu);
+
+	return fw_mtu < pkt_off;
+}
+
 static int
 nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog,
 		 struct netlink_ext_ack *extack)
 {
 	struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
-	unsigned int fw_mtu, pkt_off, max_stack, max_prog_len;
+	unsigned int max_stack, max_prog_len;
 	dma_addr_t dma_addr;
 	void *img;
 	int err;
 
-	fw_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32;
-	pkt_off = min(prog->aux->max_pkt_offset, nn->dp.netdev->mtu);
-	if (fw_mtu < pkt_off) {
+	if (nfp_bpf_offload_check_mtu(nn, prog, nn->dp.netdev->mtu)) {
 		NL_SET_ERR_MSG_MOD(extack, "BPF offload not supported with potential packet access beyond HW packet split boundary");
 		return -EOPNOTSUPP;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -164,6 +164,7 @@
  * @qos_rate_limiters:	Current active qos rate limiters
  * @qos_stats_lock:	Lock on qos stats updates
  * @pre_tun_rule_cnt:	Number of pre-tunnel rules offloaded
+ * @merge_table:	Hash table to store merged flows
  */
 struct nfp_flower_priv {
 	struct nfp_app *app;
@@ -196,6 +197,7 @@
 	unsigned int qos_rate_limiters;
 	spinlock_t qos_stats_lock; /* Protect the qos stats */
 	int pre_tun_rule_cnt;
+	struct rhashtable merge_table;
 };
 
 /**
@@ -310,6 +312,12 @@
 };
 
 extern const struct rhashtable_params nfp_flower_table_params;
+extern const struct rhashtable_params merge_table_params;
+
+struct nfp_merge_info {
+	u64 parent_ctx;
+	struct rhash_head ht_node;
+};
 
 struct nfp_fl_stats_frame {
 	__be32 stats_con_id;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/flower/metadata.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/flower/metadata.c
@@ -65,17 +65,17 @@
 	freed_stats_id = priv->stats_ring_size;
 	/* Check for unallocated entries first. */
 	if (priv->stats_ids.init_unalloc > 0) {
-		if (priv->active_mem_unit == priv->total_mem_units) {
-			priv->stats_ids.init_unalloc--;
-			priv->active_mem_unit = 0;
-		}
-
 		*stats_context_id =
 			FIELD_PREP(NFP_FL_STAT_ID_STAT,
 				   priv->stats_ids.init_unalloc - 1) |
 			FIELD_PREP(NFP_FL_STAT_ID_MU_NUM,
 				   priv->active_mem_unit);
-		priv->active_mem_unit++;
+
+		if (++priv->active_mem_unit == priv->total_mem_units) {
+			priv->stats_ids.init_unalloc--;
+			priv->active_mem_unit = 0;
+		}
+
 		return 0;
 	}
 
@@ -327,8 +327,14 @@
 		goto err_free_ctx_entry;
 	}
 
+	/* Do net allocate a mask-id for pre_tun_rules. These flows are used to
+	 * configure the pre_tun table and are never actually send to the
+	 * firmware as an add-flow message. This causes the mask-id allocation
+	 * on the firmware to get out of sync if allocated here.
+	 */
 	new_mask_id = 0;
-	if (!nfp_check_mask_add(app, nfp_flow->mask_data,
+	if (!nfp_flow->pre_tun_rule.dev &&
+	    !nfp_check_mask_add(app, nfp_flow->mask_data,
 				nfp_flow->meta.mask_len,
 				&nfp_flow->meta.flags, &new_mask_id)) {
 		NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot allocate a new mask id");
@@ -359,7 +365,8 @@
 			goto err_remove_mask;
 		}
 
-		if (!nfp_check_mask_remove(app, nfp_flow->mask_data,
+		if (!nfp_flow->pre_tun_rule.dev &&
+		    !nfp_check_mask_remove(app, nfp_flow->mask_data,
 					   nfp_flow->meta.mask_len,
 					   NULL, &new_mask_id)) {
 			NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot release mask id");
@@ -374,8 +381,10 @@
 	return 0;
 
 err_remove_mask:
-	nfp_check_mask_remove(app, nfp_flow->mask_data, nfp_flow->meta.mask_len,
-			      NULL, &new_mask_id);
+	if (!nfp_flow->pre_tun_rule.dev)
+		nfp_check_mask_remove(app, nfp_flow->mask_data,
+				      nfp_flow->meta.mask_len,
+				      NULL, &new_mask_id);
 err_remove_rhash:
 	WARN_ON_ONCE(rhashtable_remove_fast(&priv->stats_ctx_table,
 					    &ctx_entry->ht_node,
@@ -406,9 +415,10 @@
 
 	__nfp_modify_flow_metadata(priv, nfp_flow);
 
-	nfp_check_mask_remove(app, nfp_flow->mask_data,
-			      nfp_flow->meta.mask_len, &nfp_flow->meta.flags,
-			      &new_mask_id);
+	if (!nfp_flow->pre_tun_rule.dev)
+		nfp_check_mask_remove(app, nfp_flow->mask_data,
+				      nfp_flow->meta.mask_len, &nfp_flow->meta.flags,
+				      &new_mask_id);
 
 	/* Update flow payload with mask ids. */
 	nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;
@@ -480,6 +490,12 @@
 	.automatic_shrinking	= true,
 };
 
+const struct rhashtable_params merge_table_params = {
+	.key_offset	= offsetof(struct nfp_merge_info, parent_ctx),
+	.head_offset	= offsetof(struct nfp_merge_info, ht_node),
+	.key_len	= sizeof(u64),
+};
+
 int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
 			     unsigned int host_num_mems)
 {
@@ -496,6 +512,10 @@
 	if (err)
 		goto err_free_flow_table;
 
+	err = rhashtable_init(&priv->merge_table, &merge_table_params);
+	if (err)
+		goto err_free_stats_ctx_table;
+
 	get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
 
 	/* Init ring buffer and unallocated mask_ids. */
@@ -503,7 +523,7 @@
 		kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
 			      NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
 	if (!priv->mask_ids.mask_id_free_list.buf)
-		goto err_free_stats_ctx_table;
+		goto err_free_merge_table;
 
 	priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
 
@@ -540,6 +560,8 @@
 	kfree(priv->mask_ids.last_used);
 err_free_mask_id:
 	kfree(priv->mask_ids.mask_id_free_list.buf);
+err_free_merge_table:
+	rhashtable_destroy(&priv->merge_table);
 err_free_stats_ctx_table:
 	rhashtable_destroy(&priv->stats_ctx_table);
 err_free_flow_table:
@@ -558,6 +580,8 @@
 				    nfp_check_rhashtable_empty, NULL);
 	rhashtable_free_and_destroy(&priv->stats_ctx_table,
 				    nfp_check_rhashtable_empty, NULL);
+	rhashtable_free_and_destroy(&priv->merge_table,
+				    nfp_check_rhashtable_empty, NULL);
 	kvfree(priv->stats);
 	kfree(priv->mask_ids.mask_id_free_list.buf);
 	kfree(priv->mask_ids.last_used);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -923,6 +923,8 @@
 	struct netlink_ext_ack *extack = NULL;
 	struct nfp_fl_payload *merge_flow;
 	struct nfp_fl_key_ls merge_key_ls;
+	struct nfp_merge_info *merge_info;
+	u64 parent_ctx = 0;
 	int err;
 
 	ASSERT_RTNL();
@@ -933,6 +935,15 @@
 	    nfp_flower_is_merge_flow(sub_flow2))
 		return -EINVAL;
 
+	/* check if the two flows are already merged */
+	parent_ctx = (u64)(be32_to_cpu(sub_flow1->meta.host_ctx_id)) << 32;
+	parent_ctx |= (u64)(be32_to_cpu(sub_flow2->meta.host_ctx_id));
+	if (rhashtable_lookup_fast(&priv->merge_table,
+				   &parent_ctx, merge_table_params)) {
+		nfp_flower_cmsg_warn(app, "The two flows are already merged.\n");
+		return 0;
+	}
+
 	err = nfp_flower_can_merge(sub_flow1, sub_flow2);
 	if (err)
 		return err;
@@ -974,16 +985,33 @@
 	if (err)
 		goto err_release_metadata;
 
+	merge_info = kmalloc(sizeof(*merge_info), GFP_KERNEL);
+	if (!merge_info) {
+		err = -ENOMEM;
+		goto err_remove_rhash;
+	}
+	merge_info->parent_ctx = parent_ctx;
+	err = rhashtable_insert_fast(&priv->merge_table, &merge_info->ht_node,
+				     merge_table_params);
+	if (err)
+		goto err_destroy_merge_info;
+
 	err = nfp_flower_xmit_flow(app, merge_flow,
 				   NFP_FLOWER_CMSG_TYPE_FLOW_MOD);
 	if (err)
-		goto err_remove_rhash;
+		goto err_remove_merge_info;
 
 	merge_flow->in_hw = true;
 	sub_flow1->in_hw = false;
 
 	return 0;
 
+err_remove_merge_info:
+	WARN_ON_ONCE(rhashtable_remove_fast(&priv->merge_table,
+					    &merge_info->ht_node,
+					    merge_table_params));
+err_destroy_merge_info:
+	kfree(merge_info);
 err_remove_rhash:
 	WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table,
 					    &merge_flow->fl_node,
@@ -1211,7 +1239,9 @@
 {
 	struct nfp_flower_priv *priv = app->priv;
 	struct nfp_fl_payload_link *link, *temp;
+	struct nfp_merge_info *merge_info;
 	struct nfp_fl_payload *origin;
+	u64 parent_ctx = 0;
 	bool mod = false;
 	int err;
 
@@ -1248,8 +1278,22 @@
 err_free_links:
 	/* Clean any links connected with the merged flow. */
 	list_for_each_entry_safe(link, temp, &merge_flow->linked_flows,
-				 merge_flow.list)
+				 merge_flow.list) {
+		u32 ctx_id = be32_to_cpu(link->sub_flow.flow->meta.host_ctx_id);
+
+		parent_ctx = (parent_ctx << 32) | (u64)(ctx_id);
 		nfp_flower_unlink_flow(link);
+	}
+
+	merge_info = rhashtable_lookup_fast(&priv->merge_table,
+					    &parent_ctx,
+					    merge_table_params);
+	if (merge_info) {
+		WARN_ON_ONCE(rhashtable_remove_fast(&priv->merge_table,
+						    &merge_info->ht_node,
+						    merge_table_params));
+		kfree(merge_info);
+	}
 
 	kfree(merge_flow->action_data);
 	kfree(merge_flow->mask_data);
@@ -1368,7 +1412,8 @@
 		ctx_id = be32_to_cpu(sub_flow->meta.host_ctx_id);
 		priv->stats[ctx_id].pkts += pkts;
 		priv->stats[ctx_id].bytes += bytes;
-		max_t(u64, priv->stats[ctx_id].used, used);
+		priv->stats[ctx_id].used = max_t(u64, used,
+						 priv->stats[ctx_id].used);
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -588,12 +588,12 @@
 			  int port, bool mod)
 {
 	struct nfp_flower_priv *priv = app->priv;
-	int ida_idx = NFP_MAX_MAC_INDEX, err;
 	struct nfp_tun_offloaded_mac *entry;
+	int ida_idx = -1, err;
 	u16 nfp_mac_idx = 0;
 
 	entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
-	if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) {
+	if (entry && (nfp_tunnel_is_mac_idx_global(entry->index) || netif_is_lag_port(netdev))) {
 		if (entry->bridge_count ||
 		    !nfp_flower_is_supported_bridge(netdev)) {
 			nfp_tunnel_offloaded_macs_inc_ref_and_link(entry,
@@ -663,7 +663,7 @@
 err_free_entry:
 	kfree(entry);
 err_free_ida:
-	if (ida_idx != NFP_MAX_MAC_INDEX)
+	if (ida_idx != -1)
 		ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
 
 	return err;
@@ -677,6 +677,7 @@
 	struct nfp_flower_repr_priv *repr_priv;
 	struct nfp_tun_offloaded_mac *entry;
 	struct nfp_repr *repr;
+	u16 nfp_mac_idx;
 	int ida_idx;
 
 	entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
@@ -695,8 +696,6 @@
 		entry->bridge_count--;
 
 		if (!entry->bridge_count && entry->ref_count) {
-			u16 nfp_mac_idx;
-
 			nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
 			if (__nfp_tunnel_offload_mac(app, mac, nfp_mac_idx,
 						     false)) {
@@ -712,7 +711,6 @@
 
 	/* If MAC is now used by 1 repr set the offloaded MAC index to port. */
 	if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
-		u16 nfp_mac_idx;
 		int port, err;
 
 		repr_priv = list_first_entry(&entry->repr_list,
@@ -740,8 +738,14 @@
 	WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
 					    &entry->ht_node,
 					    offloaded_macs_params));
+
+	if (nfp_flower_is_supported_bridge(netdev))
+		nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
+	else
+		nfp_mac_idx = entry->index;
+
 	/* If MAC has global ID then extract and free the ida entry. */
-	if (nfp_tunnel_is_mac_idx_global(entry->index)) {
+	if (nfp_tunnel_is_mac_idx_global(nfp_mac_idx)) {
 		ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
 		ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/nfp_asm.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/nfp_asm.c
@@ -196,7 +196,7 @@
 	}
 
 	reg->dst_lmextn = swreg_lmextn(dst);
-	reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg);
+	reg->src_lmextn = swreg_lmextn(lreg) || swreg_lmextn(rreg);
 
 	return 0;
 }
@@ -277,7 +277,7 @@
 	}
 
 	reg->dst_lmextn = swreg_lmextn(dst);
-	reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg);
+	reg->src_lmextn = swreg_lmextn(lreg) || swreg_lmextn(rreg);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -557,7 +557,6 @@
  * @exn_name:           Name for Exception interrupt
  * @shared_handler:     Handler for shared interrupts
  * @shared_name:        Name for shared interrupt
- * @me_freq_mhz:        ME clock_freq (MHz)
  * @reconfig_lock:	Protects @reconfig_posted, @reconfig_timer_active,
  *			@reconfig_sync_present and HW reconfiguration request
  *			regs/machinery from async requests (sync must take
@@ -639,8 +638,6 @@
 	irq_handler_t shared_handler;
 	char shared_name[IFNAMSIZ + 8];
 
-	u32 me_freq_mhz;
-
 	bool link_up;
 	spinlock_t link_status_lock;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -273,6 +273,8 @@
 	port = nfp_port_from_netdev(netdev);
 	eth_port = nfp_port_get_eth_port(port);
 	if (eth_port) {
+		ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
 		cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ?
 			AUTONEG_ENABLE : AUTONEG_DISABLE;
 		nfp_net_set_fec_link_mode(eth_port, cmd);
@@ -731,8 +733,8 @@
 	struct nfp_eth_table_port *eth_port;
 	struct nfp_port *port;
 
-	param->active_fec = ETHTOOL_FEC_NONE_BIT;
-	param->fec = ETHTOOL_FEC_NONE_BIT;
+	param->active_fec = ETHTOOL_FEC_NONE;
+	param->fec = ETHTOOL_FEC_NONE;
 
 	port = nfp_port_from_netdev(netdev);
 	eth_port = nfp_port_get_eth_port(port);
@@ -1125,6 +1127,11 @@
 	u8 data;
 
 	port = nfp_port_from_netdev(netdev);
+	if (!port)
+		return -EOPNOTSUPP;
+
+	/* update port state to get latest interface */
+	set_bit(NFP_PORT_CHANGED, &port->flags);
 	eth_port = nfp_port_get_eth_port(port);
 	if (!eth_port)
 		return -EOPNOTSUPP;
@@ -1267,7 +1274,7 @@
 	 * ME timestamp ticks.  There are 16 ME clock cycles for each timestamp
 	 * count.
 	 */
-	factor = nn->me_freq_mhz / 16;
+	factor = nn->tlv_caps.me_freq_mhz / 16;
 
 	/* Each pair of (usecs, max_frames) fields specifies that interrupts
 	 * should be coalesced until
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
@@ -542,11 +542,13 @@
 	const u32 barcfg_msix_general =
 		NFP_PCIE_BAR_PCIE2CPP_MapType(
 			NFP_PCIE_BAR_PCIE2CPP_MapType_GENERAL) |
-		NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT;
+		NFP_PCIE_BAR_PCIE2CPP_LengthSelect(
+			NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT);
 	const u32 barcfg_msix_xpb =
 		NFP_PCIE_BAR_PCIE2CPP_MapType(
 			NFP_PCIE_BAR_PCIE2CPP_MapType_BULK) |
-		NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT |
+		NFP_PCIE_BAR_PCIE2CPP_LengthSelect(
+			NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT) |
 		NFP_PCIE_BAR_PCIE2CPP_Target_BaseAddress(
 			NFP_CPP_TARGET_ISLAND_XPB);
 	const u32 barcfg_explicit[4] = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+++ linux-ein-5.4.0/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
@@ -803,8 +803,10 @@
 		return -ENOMEM;
 
 	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-	if (!cache)
+	if (!cache) {
+		nfp_cpp_area_free(area);
 		return -ENOMEM;
+	}
 
 	cache->id = 0;
 	cache->addr = 0;
@@ -872,7 +874,6 @@
 	}
 
 	/* Adjust the start address to be cache size aligned */
-	cache->id = id;
 	cache->addr = addr & ~(u64)(cache->size - 1);
 
 	/* Re-init to the new ID and address */
@@ -892,6 +893,8 @@
 		return NULL;
 	}
 
+	cache->id = id;
+
 exit:
 	/* Adjust offset */
 	*offset = addr - cache->addr;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ni/nixge.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ni/nixge.c
@@ -249,25 +249,26 @@
 	struct sk_buff *skb;
 	int i;
 
-	for (i = 0; i < RX_BD_NUM; i++) {
-		phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
-						     phys);
-
-		dma_unmap_single(ndev->dev.parent, phys_addr,
-				 NIXGE_MAX_JUMBO_FRAME_SIZE,
-				 DMA_FROM_DEVICE);
-
-		skb = (struct sk_buff *)(uintptr_t)
-			nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
-						 sw_id_offset);
-		dev_kfree_skb(skb);
-	}
+	if (priv->rx_bd_v) {
+		for (i = 0; i < RX_BD_NUM; i++) {
+			phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+							     phys);
+
+			dma_unmap_single(ndev->dev.parent, phys_addr,
+					 NIXGE_MAX_JUMBO_FRAME_SIZE,
+					 DMA_FROM_DEVICE);
+
+			skb = (struct sk_buff *)(uintptr_t)
+				nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+							 sw_id_offset);
+			dev_kfree_skb(skb);
+		}
 
-	if (priv->rx_bd_v)
 		dma_free_coherent(ndev->dev.parent,
 				  sizeof(*priv->rx_bd_v) * RX_BD_NUM,
 				  priv->rx_bd_v,
 				  priv->rx_bd_p);
+	}
 
 	if (priv->tx_skb)
 		devm_kfree(ndev->dev.parent, priv->tx_skb);
@@ -899,6 +900,7 @@
 err_rx_irq:
 	free_irq(priv->tx_irq, ndev);
 err_tx_irq:
+	napi_disable(&priv->napi);
 	phy_stop(phy);
 	phy_disconnect(phy);
 	tasklet_kill(&priv->dma_err_tasklet);
@@ -1318,19 +1320,21 @@
 	netif_napi_add(ndev, &priv->napi, nixge_poll, NAPI_POLL_WEIGHT);
 	err = nixge_of_get_resources(pdev);
 	if (err)
-		return err;
+		goto free_netdev;
 	__nixge_hw_set_mac_address(ndev);
 
 	priv->tx_irq = platform_get_irq_byname(pdev, "tx");
 	if (priv->tx_irq < 0) {
 		netdev_err(ndev, "could not find 'tx' irq");
-		return priv->tx_irq;
+		err = priv->tx_irq;
+		goto free_netdev;
 	}
 
 	priv->rx_irq = platform_get_irq_byname(pdev, "rx");
 	if (priv->rx_irq < 0) {
 		netdev_err(ndev, "could not find 'rx' irq");
-		return priv->rx_irq;
+		err = priv->rx_irq;
+		goto free_netdev;
 	}
 
 	priv->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/nvidia/forcedeth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/nvidia/forcedeth.c
@@ -6099,6 +6099,7 @@
 	return 0;
 
 out_error:
+	nv_mgmt_release_sema(dev);
 	if (phystate_orig)
 		writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
 out_freering:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/nxp/lpc_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/nxp/lpc_eth.c
@@ -815,7 +815,8 @@
 	if (mdiobus_register(pldat->mii_bus))
 		goto err_out_unregister_bus;
 
-	if (lpc_mii_probe(pldat->ndev) != 0)
+	err = lpc_mii_probe(pldat->ndev);
+	if (err)
 		goto err_out_unregister_bus;
 
 	return 0;
@@ -1006,9 +1007,6 @@
 	napi_disable(&pldat->napi);
 	netif_stop_queue(ndev);
 
-	if (ndev->phydev)
-		phy_stop(ndev->phydev);
-
 	spin_lock_irqsave(&pldat->lock, flags);
 	__lpc_eth_reset(pldat);
 	netif_carrier_off(ndev);
@@ -1016,6 +1014,8 @@
 	writel(0, LPC_ENET_MAC2(pldat->net_base));
 	spin_unlock_irqrestore(&pldat->lock, flags);
 
+	if (ndev->phydev)
+		phy_stop(ndev->phydev);
 	clk_disable_unprepare(pldat->clk);
 
 	return 0;
@@ -1470,6 +1470,7 @@
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct netdata_local *pldat;
+	int ret;
 
 	if (device_may_wakeup(&pdev->dev))
 		disable_irq_wake(ndev->irq);
@@ -1479,7 +1480,9 @@
 			pldat = netdev_priv(ndev);
 
 			/* Enable interface clock */
-			clk_enable(pldat->clk);
+			ret = clk_enable(pldat->clk);
+			if (ret)
+				return ret;
 
 			/* Reset and initialize */
 			__lpc_eth_reset(pldat);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -107,7 +107,7 @@
 {
 	u8 *data = skb->data;
 	unsigned int offset;
-	u16 *hi, *id;
+	u16 hi, id;
 	u32 lo;
 
 	if (ptp_classify_raw(skb) == PTP_CLASS_NONE)
@@ -118,14 +118,11 @@
 	if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
 		return 0;
 
-	hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
-	id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+	hi = get_unaligned_be16(data + offset + OFF_PTP_SOURCE_UUID + 0);
+	lo = get_unaligned_be32(data + offset + OFF_PTP_SOURCE_UUID + 2);
+	id = get_unaligned_be16(data + offset + OFF_PTP_SEQUENCE_ID);
 
-	memcpy(&lo, &hi[1], sizeof(lo));
-
-	return (uid_hi == *hi &&
-		uid_lo == lo &&
-		seqid  == *id);
+	return (uid_hi == hi && uid_lo == lo && seqid == id);
 }
 
 static void
@@ -135,7 +132,6 @@
 	struct pci_dev *pdev;
 	u64 ns;
 	u32 hi, lo, val;
-	u16 uid, seq;
 
 	if (!adapter->hwts_rx_en)
 		return;
@@ -151,10 +147,7 @@
 	lo = pch_src_uuid_lo_read(pdev);
 	hi = pch_src_uuid_hi_read(pdev);
 
-	uid = hi & 0xffff;
-	seq = (hi >> 16) & 0xffff;
-
-	if (!pch_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+	if (!pch_ptp_match(skb, hi, lo, hi >> 16))
 		goto out;
 
 	ns = pch_rx_snap_read(pdev);
@@ -1173,6 +1166,7 @@
 		buffer_info->dma = 0;
 		buffer_info->time_stamp = 0;
 		tx_ring->next_to_use = ring_num;
+		dev_kfree_skb_any(skb);
 		return;
 	}
 	buffer_info->mapped = true;
@@ -2487,6 +2481,7 @@
 	unregister_netdev(netdev);
 
 	pch_gbe_phy_hw_reset(&adapter->hw);
+	pci_dev_put(adapter->ptp_pdev);
 
 	free_netdev(netdev);
 }
@@ -2535,9 +2530,13 @@
 	adapter->pdev = pdev;
 	adapter->hw.back = adapter;
 	adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
+
 	adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
-	if (adapter->pdata && adapter->pdata->platform_init)
-		adapter->pdata->platform_init(pdev);
+	if (adapter->pdata && adapter->pdata->platform_init) {
+		ret = adapter->pdata->platform_init(pdev);
+		if (ret)
+			goto err_free_netdev;
+	}
 
 	adapter->ptp_pdev =
 		pci_get_domain_bus_and_slot(pci_domain_nr(adapter->pdev->bus),
@@ -2564,7 +2563,7 @@
 	/* setup the private structure */
 	ret = pch_gbe_sw_init(adapter);
 	if (ret)
-		goto err_free_netdev;
+		goto err_put_dev;
 
 	/* Initialize PHY */
 	ret = pch_gbe_init_phy(adapter);
@@ -2622,6 +2621,8 @@
 
 err_free_adapter:
 	pch_gbe_phy_hw_reset(&adapter->hw);
+err_put_dev:
+	pci_dev_put(adapter->ptp_pdev);
 err_free_netdev:
 	free_netdev(netdev);
 	return ret;
@@ -2632,7 +2633,7 @@
  */
 static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
 {
-	unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
+	unsigned long flags = GPIOF_OUT_INIT_HIGH;
 	unsigned gpio = MINNOW_PHY_RESET_GPIO;
 	int ret;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pasemi/pasemi_mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -1078,16 +1078,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 */
@@ -1419,7 +1423,7 @@
 	write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2);
 }
 
-static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct pasemi_mac * const mac = netdev_priv(dev);
 	struct pasemi_mac_txring * const txring = tx_ring(mac);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -102,15 +102,18 @@
 			   void *p)
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
+	unsigned int offset;
 	unsigned int size;
 
 	regs->version = IONIC_DEV_CMD_REG_VERSION;
 
+	offset = 0;
 	size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
-	memcpy_fromio(p, lif->ionic->idev.dev_info_regs->words, size);
+	memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
 
+	offset += size;
 	size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
-	memcpy_fromio(p, lif->ionic->idev.dev_cmd_regs->words, size);
+	memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
 }
 
 static int ionic_get_link_ksettings(struct net_device *netdev,
@@ -122,6 +125,11 @@
 
 	ethtool_link_ksettings_zero_link_mode(ks, supported);
 
+	if (!idev->port_info) {
+		netdev_err(netdev, "port_info not initialized\n");
+		return -EOPNOTSUPP;
+	}
+
 	/* The port_info data is found in a DMA space that the NIC keeps
 	 * up-to-date, so there's no need to request the data from the
 	 * NIC, we already have it in our memory space.
@@ -565,7 +573,7 @@
 		info->data = lif->nxqs;
 		break;
 	default:
-		netdev_err(netdev, "Command parameter %d is not supported\n",
+		netdev_dbg(netdev, "Command parameter %d is not supported\n",
 			   info->cmd);
 		err = -EOPNOTSUPP;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pensando/ionic/ionic_if.h
+++ linux-ein-5.4.0/drivers/net/ethernet/pensando/ionic/ionic_if.h
@@ -862,7 +862,7 @@
 #define IONIC_RXQ_COMP_CSUM_F_VLAN	0x40
 #define IONIC_RXQ_COMP_CSUM_F_CALC	0x80
 	u8     pkt_type_color;
-#define IONIC_RXQ_COMP_PKT_TYPE_MASK	0x0f
+#define IONIC_RXQ_COMP_PKT_TYPE_MASK	0x7f
 };
 
 enum ionic_pkt_type {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ linux-ein-5.4.0/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -167,10 +167,10 @@
 	return 0;
 }
 
-static void ionic_intr_free(struct ionic_lif *lif, int index)
+static void ionic_intr_free(struct ionic *ionic, int index)
 {
-	if (index != INTR_INDEX_NOT_ASSIGNED && index < lif->ionic->nintrs)
-		clear_bit(index, lif->ionic->intrs);
+	if (index != INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs)
+		clear_bit(index, ionic->intrs);
 }
 
 static int ionic_qcq_enable(struct ionic_qcq *qcq)
@@ -190,6 +190,7 @@
 			.oper = IONIC_Q_ENABLE,
 		},
 	};
+	int ret;
 
 	idev = &lif->ionic->idev;
 	dev = lif->ionic->dev;
@@ -197,16 +198,24 @@
 	dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n",
 		ctx.cmd.q_control.index, ctx.cmd.q_control.type);
 
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
+
+	ret = ionic_adminq_post_wait(lif, &ctx);
+	if (ret)
+		return ret;
+
+	if (qcq->napi.poll)
+		napi_enable(&qcq->napi);
+
 	if (qcq->flags & IONIC_QCQ_F_INTR) {
 		irq_set_affinity_hint(qcq->intr.vector,
 				      &qcq->intr.affinity_mask);
-		napi_enable(&qcq->napi);
-		ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
 				IONIC_INTR_MASK_CLEAR);
 	}
 
-	return ionic_adminq_post_wait(lif, &ctx);
+	return 0;
 }
 
 static int ionic_qcq_disable(struct ionic_qcq *qcq)
@@ -247,7 +256,6 @@
 static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
 {
 	struct ionic_dev *idev = &lif->ionic->idev;
-	struct device *dev = lif->ionic->dev;
 
 	if (!qcq)
 		return;
@@ -260,7 +268,6 @@
 	if (qcq->flags & IONIC_QCQ_F_INTR) {
 		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
 				IONIC_INTR_MASK_SET);
-		devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
 		netif_napi_del(&qcq->napi);
 	}
 
@@ -278,8 +285,12 @@
 	qcq->base = NULL;
 	qcq->base_pa = 0;
 
-	if (qcq->flags & IONIC_QCQ_F_INTR)
-		ionic_intr_free(lif, qcq->intr.index);
+	if (qcq->flags & IONIC_QCQ_F_INTR) {
+		irq_set_affinity_hint(qcq->intr.vector, NULL);
+		devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
+		qcq->intr.vector = 0;
+		ionic_intr_free(lif->ionic, qcq->intr.index);
+	}
 
 	devm_kfree(dev, qcq->cq.info);
 	qcq->cq.info = NULL;
@@ -321,11 +332,6 @@
 static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
 				      struct ionic_qcq *n_qcq)
 {
-	if (WARN_ON(n_qcq->flags & IONIC_QCQ_F_INTR)) {
-		ionic_intr_free(n_qcq->cq.lif, n_qcq->intr.index);
-		n_qcq->flags &= ~IONIC_QCQ_F_INTR;
-	}
-
 	n_qcq->intr.vector = src_qcq->intr.vector;
 	n_qcq->intr.index = src_qcq->intr.index;
 }
@@ -409,8 +415,15 @@
 		ionic_intr_mask_assert(idev->intr_ctrl, new->intr.index,
 				       IONIC_INTR_MASK_SET);
 
-		new->intr.cpu = new->intr.index % num_online_cpus();
-		if (cpu_online(new->intr.cpu))
+		err = ionic_request_irq(lif, new);
+		if (err) {
+			netdev_warn(lif->netdev, "irq request failed %d\n", err);
+			goto err_out_free_intr;
+		}
+
+		new->intr.cpu = cpumask_local_spread(new->intr.index,
+						     dev_to_node(dev));
+		if (new->intr.cpu != -1)
 			cpumask_set_cpu(new->intr.cpu,
 					&new->intr.affinity_mask);
 	} else {
@@ -422,13 +435,13 @@
 	if (!new->cq.info) {
 		netdev_err(lif->netdev, "Cannot allocate completion queue info\n");
 		err = -ENOMEM;
-		goto err_out_free_intr;
+		goto err_out_free_irq;
 	}
 
 	err = ionic_cq_init(lif, &new->cq, &new->intr, num_descs, cq_desc_size);
 	if (err) {
 		netdev_err(lif->netdev, "Cannot initialize completion queue\n");
-		goto err_out_free_intr;
+		goto err_out_free_irq;
 	}
 
 	new->base = dma_alloc_coherent(dev, total_size, &new->base_pa,
@@ -436,7 +449,7 @@
 	if (!new->base) {
 		netdev_err(lif->netdev, "Cannot allocate queue DMA memory\n");
 		err = -ENOMEM;
-		goto err_out_free_intr;
+		goto err_out_free_irq;
 	}
 
 	new->total_size = total_size;
@@ -462,8 +475,12 @@
 
 	return 0;
 
+err_out_free_irq:
+	if (flags & IONIC_QCQ_F_INTR)
+		devm_free_irq(dev, new->intr.vector, &new->napi);
 err_out_free_intr:
-	ionic_intr_free(lif, new->intr.index);
+	if (flags & IONIC_QCQ_F_INTR)
+		ionic_intr_free(lif->ionic, new->intr.index);
 err_out:
 	dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err);
 	return err;
@@ -638,12 +655,6 @@
 	netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi,
 		       NAPI_POLL_WEIGHT);
 
-	err = ionic_request_irq(lif, qcq);
-	if (err) {
-		netif_napi_del(&qcq->napi);
-		return err;
-	}
-
 	qcq->flags |= IONIC_QCQ_F_INITED;
 
 	ionic_debugfs_add_qcq(lif, qcq);
@@ -666,7 +677,7 @@
 	eid = le64_to_cpu(comp->event.eid);
 
 	/* Have we run out of new completions to process? */
-	if (eid <= lif->last_eid)
+	if ((s64)(eid - lif->last_eid) <= 0)
 		return false;
 
 	lif->last_eid = eid;
@@ -809,8 +820,7 @@
 	if (f)
 		return 0;
 
-	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM (id %d)\n", addr,
-		   ctx.comp.rx_filter_add.filter_id);
+	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
 
 	memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
 	err = ionic_adminq_post_wait(lif, &ctx);
@@ -839,6 +849,9 @@
 		return -ENOENT;
 	}
 
+	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
+		   addr, f->filter_id);
+
 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
 	ionic_rx_filter_free(lif, f);
 	spin_unlock_bh(&lif->rx_filters.lock);
@@ -847,9 +860,6 @@
 	if (err)
 		return err;
 
-	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr,
-		   ctx.cmd.rx_filter_del.filter_id);
-
 	return 0;
 }
 
@@ -913,6 +923,10 @@
 
 static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
 {
+	/* Don't delete our own address from the uc list */
+	if (ether_addr_equal(addr, netdev->dev_addr))
+		return 0;
+
 	return ionic_lif_addr(netdev_priv(netdev), addr, false);
 }
 
@@ -1187,6 +1201,7 @@
 
 	netdev->hw_features |= netdev->hw_enc_features;
 	netdev->features |= netdev->hw_features;
+	netdev->vlan_features |= netdev->features & ~NETIF_F_VLAN_FEATURES;
 
 	netdev->priv_flags |= IFF_UNICAST_FLT;
 
@@ -1290,13 +1305,11 @@
 	};
 	int err;
 
+	netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid);
 	err = ionic_adminq_post_wait(lif, &ctx);
 	if (err)
 		return err;
 
-	netdev_dbg(netdev, "rx_filter add VLAN %d (id %d)\n", vid,
-		   ctx.comp.rx_filter_add.filter_id);
-
 	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
 }
 
@@ -1321,8 +1334,8 @@
 		return -ENOENT;
 	}
 
-	netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n", vid,
-		   le32_to_cpu(ctx.cmd.rx_filter_del.filter_id));
+	netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n",
+		   vid, f->filter_id);
 
 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
 	ionic_rx_filter_free(lif, f);
@@ -1364,12 +1377,9 @@
 
 static int ionic_lif_rss_init(struct ionic_lif *lif)
 {
-	u8 rss_key[IONIC_RSS_HASH_KEY_SIZE];
 	unsigned int tbl_sz;
 	unsigned int i;
 
-	netdev_rss_key_fill(rss_key, IONIC_RSS_HASH_KEY_SIZE);
-
 	lif->rss_types = IONIC_RSS_TYPE_IPV4     |
 			 IONIC_RSS_TYPE_IPV4_TCP |
 			 IONIC_RSS_TYPE_IPV4_UDP |
@@ -1382,12 +1392,18 @@
 	for (i = 0; i < tbl_sz; i++)
 		lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
 
-	return ionic_lif_rss_config(lif, lif->rss_types, rss_key, NULL);
+	return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
 }
 
-static int ionic_lif_rss_deinit(struct ionic_lif *lif)
+static void ionic_lif_rss_deinit(struct ionic_lif *lif)
 {
-	return ionic_lif_rss_config(lif, 0x0, NULL, NULL);
+	int tbl_sz;
+
+	tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+	memset(lif->rss_ind_tbl, 0, tbl_sz);
+	memset(lif->rss_hash_key, 0, IONIC_RSS_HASH_KEY_SIZE);
+
+	ionic_lif_rss_config(lif, 0x0, NULL, NULL);
 }
 
 static void ionic_txrx_disable(struct ionic_lif *lif)
@@ -1710,6 +1726,7 @@
 		dev_err(dev, "Failed to allocate rss indirection table, aborting\n");
 		goto err_out_free_qcqs;
 	}
+	netdev_rss_key_fill(lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
 
 	list_add_tail(&lif->list, &ionic->lifs);
 
@@ -1855,13 +1872,6 @@
 	netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi,
 		       NAPI_POLL_WEIGHT);
 
-	err = ionic_request_irq(lif, qcq);
-	if (err) {
-		netdev_warn(lif->netdev, "adminq irq request failed %d\n", err);
-		netif_napi_del(&qcq->napi);
-		return err;
-	}
-
 	napi_enable(&qcq->napi);
 
 	if (qcq->flags & IONIC_QCQ_F_INTR)
@@ -1989,7 +1999,7 @@
 		return -EINVAL;
 	}
 
-	lif->dbid_inuse = bitmap_alloc(lif->dbid_count, GFP_KERNEL);
+	lif->dbid_inuse = bitmap_zalloc(lif->dbid_count, GFP_KERNEL);
 	if (!lif->dbid_inuse) {
 		dev_err(dev, "Failed alloc doorbell id bitmap, aborting\n");
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
+++ linux-ein-5.4.0/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c
@@ -36,10 +36,12 @@
 
 	spin_lock_init(&lif->rx_filters.lock);
 
+	spin_lock_bh(&lif->rx_filters.lock);
 	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
 		INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]);
 		INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]);
 	}
+	spin_unlock_bh(&lif->rx_filters.lock);
 
 	return 0;
 }
@@ -51,11 +53,13 @@
 	struct hlist_node *tmp;
 	unsigned int i;
 
+	spin_lock_bh(&lif->rx_filters.lock);
 	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
 		head = &lif->rx_filters.by_id[i];
 		hlist_for_each_entry_safe(f, tmp, head, by_id)
 			ionic_rx_filter_free(lif, f);
 	}
+	spin_unlock_bh(&lif->rx_filters.lock);
 }
 
 int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
@@ -91,6 +95,7 @@
 	f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id);
 	f->rxq_index = rxq_index;
 	memcpy(&f->cmd, ac, sizeof(f->cmd));
+	netdev_dbg(lif->netdev, "rx_filter add filter_id %d\n", f->filter_id);
 
 	INIT_HLIST_NODE(&f->by_hash);
 	INIT_HLIST_NODE(&f->by_id);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
@@ -257,7 +257,7 @@
 	unsigned int len;
 	unsigned int i;
 
-	len = netdev->mtu + ETH_HLEN;
+	len = netdev->mtu + ETH_HLEN + VLAN_HLEN;
 
 	for (i = ionic_q_space_avail(q); i; i--) {
 		skb = ionic_rx_skb_alloc(q, len, &dma_addr);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/Kconfig
@@ -78,6 +78,7 @@
 	depends on PCI
 	select ZLIB_INFLATE
 	select CRC8
+	select CRC32
 	select NET_DEVLINK
 	---help---
 	  This enables the support for ...
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -564,11 +564,6 @@
 	.ndo_set_features = netxen_set_features,
 };
 
-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)
 {
@@ -664,7 +659,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
@@ -1607,6 +1602,8 @@
 	free_netdev(netdev);
 
 err_out_free_res:
+	if (NX_IS_REVISION_P3(pdev->revision))
+		pci_disable_pcie_error_reporting(pdev);
 	pci_release_regions(pdev);
 
 err_out_disable_pdev:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -396,7 +396,7 @@
 		vf_tids += segs[NUM_TASK_PF_SEGMENTS].count;
 	}
 
-	iids->vf_cids += vf_cids * p_mngr->vf_count;
+	iids->vf_cids = vf_cids;
 	iids->tids += vf_tids * p_mngr->vf_count;
 
 	DP_VERBOSE(p_hwfn, QED_MSG_ILT,
@@ -1023,6 +1023,7 @@
 		p_dma->p_virt = NULL;
 	}
 	kfree(p_mngr->ilt_shadow);
+	p_mngr->ilt_shadow = NULL;
 }
 
 static int qed_ilt_blk_alloc(struct qed_hwfn *p_hwfn,
@@ -2073,8 +2074,8 @@
 	num_srqs = min_t(u32, QED_RDMA_MAX_SRQS, p_params->num_srqs);
 
 	if (p_hwfn->mcp_info->func_info.protocol == QED_PCI_ETH_RDMA) {
-		DP_NOTICE(p_hwfn,
-			  "Current day drivers don't support RoCE & iWARP simultaneously on the same PF. Default to RoCE-only\n");
+		DP_VERBOSE(p_hwfn, QED_MSG_SP,
+			   "Current day drivers don't support RoCE & iWARP simultaneously on the same PF. Default to RoCE-only\n");
 		p_hwfn->hw_info.personality = QED_PCI_ETH_ROCE;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
@@ -1293,9 +1293,11 @@
 		p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_STATIC;
 
 	p_hwfn->p_dcbx_info->set.enabled = dcbx_info->operational.enabled;
+	BUILD_BUG_ON(sizeof(dcbx_info->operational.params) !=
+		     sizeof(p_hwfn->p_dcbx_info->set.config.params));
 	memcpy(&p_hwfn->p_dcbx_info->set.config.params,
 	       &dcbx_info->operational.params,
-	       sizeof(struct qed_dcbx_admin_params));
+	       sizeof(p_hwfn->p_dcbx_info->set.config.params));
 	p_hwfn->p_dcbx_info->set.config.valid = true;
 
 	memcpy(params, &p_hwfn->p_dcbx_info->set, sizeof(struct qed_dcbx_set));
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_debug.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_debug.c
@@ -8197,6 +8197,10 @@
 		DP_ERR(cdev, "qed_dbg_mcp_trace failed. rc = %d\n", rc);
 	}
 
+	/* Re-populate nvm attribute info */
+	qed_mcp_nvm_info_free(p_hwfn);
+	qed_mcp_nvm_info_populate(p_hwfn);
+
 	/* nvm cfg1 */
 	rc = qed_dbg_nvm_image(cdev,
 			       (u8 *)buffer + offset + REGDUMP_HEADER_SIZE,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -1368,6 +1368,8 @@
 
 void qed_resc_free(struct qed_dev *cdev)
 {
+	struct qed_rdma_info *rdma_info;
+	struct qed_hwfn *p_hwfn;
 	int i;
 
 	if (IS_VF(cdev)) {
@@ -1385,7 +1387,8 @@
 	qed_llh_free(cdev);
 
 	for_each_hwfn(cdev, i) {
-		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
+		p_hwfn = cdev->hwfns + i;
+		rdma_info = p_hwfn->p_rdma_info;
 
 		qed_cxt_mngr_free(p_hwfn);
 		qed_qm_info_free(p_hwfn);
@@ -1404,8 +1407,10 @@
 			qed_ooo_free(p_hwfn);
 		}
 
-		if (QED_IS_RDMA_PERSONALITY(p_hwfn))
+		if (QED_IS_RDMA_PERSONALITY(p_hwfn) && rdma_info) {
+			qed_spq_unregister_async_cb(p_hwfn, rdma_info->proto);
 			qed_rdma_info_free(p_hwfn);
+		}
 
 		qed_iov_free(p_hwfn);
 		qed_l2_free(p_hwfn);
@@ -3087,7 +3092,7 @@
 		}
 
 		/* Log and clear previous pglue_b errors if such exist */
-		qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt);
+		qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt, true);
 
 		/* Enable the PF's internal FID_enable in the PXP */
 		rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt,
@@ -4137,7 +4142,8 @@
 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
 					BIT(QED_MF_LLH_PROTO_CLSS) |
 					BIT(QED_MF_LL2_NON_UNICAST) |
-					BIT(QED_MF_INTER_PF_SWITCH);
+					BIT(QED_MF_INTER_PF_SWITCH) |
+					BIT(QED_MF_DISABLE_ARFS);
 			break;
 		case NVM_CFG1_GLOB_MF_MODE_DEFAULT:
 			cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
@@ -4150,6 +4156,14 @@
 
 		DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
 			cdev->mf_bits);
+
+		/* In CMT the PF is unknown when the GFS block processes the
+		 * packet. Therefore cannot use searcher as it has a per PF
+		 * database, and thus ARFS must be disabled.
+		 *
+		 */
+		if (QED_IS_CMT(cdev))
+			cdev->mf_bits |= BIT(QED_MF_DISABLE_ARFS);
 	}
 
 	DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
@@ -4418,12 +4432,6 @@
 	return 0;
 }
 
-static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
-{
-	kfree(p_hwfn->nvm_info.image_att);
-	p_hwfn->nvm_info.image_att = NULL;
-}
-
 static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
 				 void __iomem *p_regview,
 				 void __iomem *p_doorbells,
@@ -4508,7 +4516,7 @@
 	return rc;
 err3:
 	if (IS_LEAD_HWFN(p_hwfn))
-		qed_nvm_info_free(p_hwfn);
+		qed_mcp_nvm_info_free(p_hwfn);
 err2:
 	if (IS_LEAD_HWFN(p_hwfn))
 		qed_iov_free_hw_info(p_hwfn->cdev);
@@ -4569,7 +4577,7 @@
 		if (rc) {
 			if (IS_PF(cdev)) {
 				qed_init_free(p_hwfn);
-				qed_nvm_info_free(p_hwfn);
+				qed_mcp_nvm_info_free(p_hwfn);
 				qed_mcp_free(p_hwfn);
 				qed_hw_hwfn_free(p_hwfn);
 			}
@@ -4603,7 +4611,7 @@
 
 	qed_iov_free_hw_info(cdev);
 
-	qed_nvm_info_free(p_hwfn);
+	qed_mcp_nvm_info_free(p_hwfn);
 }
 
 static void qed_chain_free_next_ptr(struct qed_dev *cdev,
@@ -4648,26 +4656,20 @@
 
 static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
 {
-	void **pp_virt_addr_tbl = p_chain->pbl.pp_virt_addr_tbl;
+	struct addr_tbl_entry *pp_addr_tbl = p_chain->pbl.pp_addr_tbl;
 	u32 page_cnt = p_chain->page_cnt, i, pbl_size;
-	u8 *p_pbl_virt = p_chain->pbl_sp.p_virt_table;
 
-	if (!pp_virt_addr_tbl)
+	if (!pp_addr_tbl)
 		return;
 
-	if (!p_pbl_virt)
-		goto out;
-
 	for (i = 0; i < page_cnt; i++) {
-		if (!pp_virt_addr_tbl[i])
+		if (!pp_addr_tbl[i].virt_addr || !pp_addr_tbl[i].dma_map)
 			break;
 
 		dma_free_coherent(&cdev->pdev->dev,
 				  QED_CHAIN_PAGE_SIZE,
-				  pp_virt_addr_tbl[i],
-				  *(dma_addr_t *)p_pbl_virt);
-
-		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
+				  pp_addr_tbl[i].virt_addr,
+				  pp_addr_tbl[i].dma_map);
 	}
 
 	pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
@@ -4677,9 +4679,9 @@
 				  pbl_size,
 				  p_chain->pbl_sp.p_virt_table,
 				  p_chain->pbl_sp.p_phys_table);
-out:
-	vfree(p_chain->pbl.pp_virt_addr_tbl);
-	p_chain->pbl.pp_virt_addr_tbl = NULL;
+
+	vfree(p_chain->pbl.pp_addr_tbl);
+	p_chain->pbl.pp_addr_tbl = NULL;
 }
 
 void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain)
@@ -4780,19 +4782,19 @@
 {
 	u32 page_cnt = p_chain->page_cnt, size, i;
 	dma_addr_t p_phys = 0, p_pbl_phys = 0;
-	void **pp_virt_addr_tbl = NULL;
+	struct addr_tbl_entry *pp_addr_tbl;
 	u8 *p_pbl_virt = NULL;
 	void *p_virt = NULL;
 
-	size = page_cnt * sizeof(*pp_virt_addr_tbl);
-	pp_virt_addr_tbl = vzalloc(size);
-	if (!pp_virt_addr_tbl)
+	size = page_cnt * sizeof(*pp_addr_tbl);
+	pp_addr_tbl =  vzalloc(size);
+	if (!pp_addr_tbl)
 		return -ENOMEM;
 
 	/* The allocation of the PBL table is done with its full size, since it
 	 * is expected to be successive.
 	 * qed_chain_init_pbl_mem() is called even in a case of an allocation
-	 * failure, since pp_virt_addr_tbl was previously allocated, and it
+	 * failure, since tbl was previously allocated, and it
 	 * should be saved to allow its freeing during the error flow.
 	 */
 	size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
@@ -4806,8 +4808,7 @@
 		p_chain->b_external_pbl = true;
 	}
 
-	qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys,
-			       pp_virt_addr_tbl);
+	qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, pp_addr_tbl);
 	if (!p_pbl_virt)
 		return -ENOMEM;
 
@@ -4826,7 +4827,8 @@
 		/* Fill the PBL table with the physical address of the page */
 		*(dma_addr_t *)p_pbl_virt = p_phys;
 		/* Keep the virtual address of the page */
-		p_chain->pbl.pp_virt_addr_tbl[i] = p_virt;
+		p_chain->pbl.pp_addr_tbl[i].virt_addr = p_virt;
+		p_chain->pbl.pp_addr_tbl[i].dma_map = p_phys;
 
 		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
 	}
@@ -5137,6 +5139,11 @@
 
 	num_vports = p_hwfn->qm_info.num_vports;
 
+	if (num_vports < 2) {
+		DP_NOTICE(p_hwfn, "Unexpected num_vports: %d\n", num_vports);
+		return -EINVAL;
+	}
+
 	/* Accounting for the vports which are configured for WFQ explicitly */
 	for (i = 0; i < num_vports; i++) {
 		u32 tmp_speed;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_int.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_int.c
@@ -256,9 +256,10 @@
 #define PGLUE_ATTENTION_ZLR_VALID		(1 << 25)
 #define PGLUE_ATTENTION_ILT_VALID		(1 << 23)
 
-int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn,
-				struct qed_ptt *p_ptt)
+int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+				bool hw_init)
 {
+	char msg[256];
 	u32 tmp;
 
 	tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS2);
@@ -272,22 +273,23 @@
 		details = qed_rd(p_hwfn, p_ptt,
 				 PGLUE_B_REG_TX_ERR_WR_DETAILS);
 
-		DP_NOTICE(p_hwfn,
-			  "Illegal write by chip to [%08x:%08x] blocked.\n"
-			  "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n"
-			  "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n",
-			  addr_hi, addr_lo, details,
-			  (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID),
-			  (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID),
-			  GET_FIELD(details,
-				    PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0,
-			  tmp,
-			  GET_FIELD(tmp,
-				    PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0,
-			  GET_FIELD(tmp,
-				    PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0,
-			  GET_FIELD(tmp,
-				    PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0);
+		snprintf(msg, sizeof(msg),
+			 "Illegal write by chip to [%08x:%08x] blocked.\n"
+			 "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n"
+			 "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]",
+			 addr_hi, addr_lo, details,
+			 (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID),
+			 (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID),
+			 !!GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VF_VALID),
+			 tmp,
+			 !!GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_WAS_ERR),
+			 !!GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_BME),
+			 !!GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_FID_EN));
+
+		if (hw_init)
+			DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "%s\n", msg);
+		else
+			DP_NOTICE(p_hwfn, "%s\n", msg);
 	}
 
 	tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS2);
@@ -320,8 +322,14 @@
 	}
 
 	tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL);
-	if (tmp & PGLUE_ATTENTION_ICPL_VALID)
-		DP_NOTICE(p_hwfn, "ICPL error - %08x\n", tmp);
+	if (tmp & PGLUE_ATTENTION_ICPL_VALID) {
+		snprintf(msg, sizeof(msg), "ICPL error - %08x", tmp);
+
+		if (hw_init)
+			DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "%s\n", msg);
+		else
+			DP_NOTICE(p_hwfn, "%s\n", msg);
+	}
 
 	tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS);
 	if (tmp & PGLUE_ATTENTION_ZLR_VALID) {
@@ -360,7 +368,7 @@
 
 static int qed_pglueb_rbc_attn_cb(struct qed_hwfn *p_hwfn)
 {
-	return qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt);
+	return qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt, false);
 }
 
 #define QED_DORQ_ATTENTION_REASON_MASK  (0xfffff)
@@ -1172,7 +1180,8 @@
 			index, attn_bits, attn_acks, asserted_bits,
 			deasserted_bits, p_sb_attn_sw->known_attn);
 	} else if (asserted_bits == 0x100) {
-		DP_INFO(p_hwfn, "MFW indication via attention\n");
+		DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
+			   "MFW indication via attention\n");
 	} else {
 		DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
 			   "MFW indication [deassertion]\n");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_int.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_int.h
@@ -431,7 +431,7 @@
 
 #define QED_MAPPING_MEMORY_SIZE(dev)	(NUM_OF_SBS(dev))
 
-int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn,
-				struct qed_ptt *p_ptt);
+int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+				bool hw_init);
 
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1307,6 +1307,14 @@
 	prev_weight = weight;
 
 	while (weight) {
+		/* If the HW device is during recovery, all resources are
+		 * immediately reset without receiving a per-cid indication
+		 * from HW. In this case we don't expect the cid_map to be
+		 * cleared.
+		 */
+		if (p_hwfn->cdev->recov_in_prog)
+			return 0;
+
 		msleep(QED_IWARP_MAX_CID_CLEAN_TIME);
 
 		weight = bitmap_weight(bmap->bitmap, bmap->max_count);
@@ -2742,14 +2750,18 @@
 	iwarp_info->partial_fpdus = kcalloc((u16)p_hwfn->p_rdma_info->num_qps,
 					    sizeof(*iwarp_info->partial_fpdus),
 					    GFP_KERNEL);
-	if (!iwarp_info->partial_fpdus)
+	if (!iwarp_info->partial_fpdus) {
+		rc = -ENOMEM;
 		goto err;
+	}
 
 	iwarp_info->max_num_partial_fpdus = (u16)p_hwfn->p_rdma_info->num_qps;
 
 	iwarp_info->mpa_intermediate_buf = kzalloc(buff_size, GFP_KERNEL);
-	if (!iwarp_info->mpa_intermediate_buf)
+	if (!iwarp_info->mpa_intermediate_buf) {
+		rc = -ENOMEM;
 		goto err;
+	}
 
 	/* The mpa_bufs array serves for pending RX packets received on the
 	 * mpa ll2 that don't have place on the tx ring and require later
@@ -2759,8 +2771,10 @@
 	iwarp_info->mpa_bufs = kcalloc(data.input.rx_num_desc,
 				       sizeof(*iwarp_info->mpa_bufs),
 				       GFP_KERNEL);
-	if (!iwarp_info->mpa_bufs)
+	if (!iwarp_info->mpa_bufs) {
+		rc = -ENOMEM;
 		goto err;
+	}
 
 	INIT_LIST_HEAD(&iwarp_info->mpa_buf_pending_list);
 	INIT_LIST_HEAD(&iwarp_info->mpa_buf_list);
@@ -2832,8 +2846,6 @@
 	if (rc)
 		return rc;
 
-	qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_IWARP);
-
 	return qed_iwarp_ll2_stop(p_hwfn);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -2001,6 +2001,9 @@
 			     struct qed_ptt *p_ptt,
 			     struct qed_arfs_config_params *p_cfg_params)
 {
+	if (test_bit(QED_MF_DISABLE_ARFS, &p_hwfn->cdev->mf_bits))
+		return;
+
 	if (p_cfg_params->mode != QED_FILTER_CONFIG_MODE_DISABLE) {
 		qed_gft_config(p_hwfn, p_ptt, p_hwfn->rel_pf_id,
 			       p_cfg_params->tcp,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -113,7 +113,10 @@
 static int qed_ll2_alloc_buffer(struct qed_dev *cdev,
 				u8 **data, dma_addr_t *phys_addr)
 {
-	*data = kmalloc(cdev->ll2->rx_size, GFP_ATOMIC);
+	size_t size = cdev->ll2->rx_size + NET_SKB_PAD +
+		      SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+	*data = kmalloc(size, GFP_ATOMIC);
 	if (!(*data)) {
 		DP_INFO(cdev, "Failed to allocate LL2 buffer data\n");
 		return -ENOMEM;
@@ -353,6 +356,9 @@
 	unsigned long flags;
 	int rc = -EINVAL;
 
+	if (!p_ll2_conn)
+		return rc;
+
 	spin_lock_irqsave(&p_tx->lock, flags);
 	if (p_tx->b_completing_packet) {
 		rc = -EBUSY;
@@ -526,7 +532,16 @@
 	unsigned long flags = 0;
 	int rc = 0;
 
+	if (!p_ll2_conn)
+		return rc;
+
 	spin_lock_irqsave(&p_rx->lock, flags);
+
+	if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) {
+		spin_unlock_irqrestore(&p_rx->lock, flags);
+		return 0;
+	}
+
 	cq_new_idx = le16_to_cpu(*p_rx->p_fw_cons);
 	cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain);
 
@@ -847,6 +862,9 @@
 	struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie;
 	int rc;
 
+	if (!p_ll2_conn)
+		return 0;
+
 	if (!QED_LL2_RX_REGISTERED(p_ll2_conn))
 		return 0;
 
@@ -870,6 +888,9 @@
 	u16 new_idx = 0, num_bds = 0;
 	int rc;
 
+	if (!p_ll2_conn)
+		return 0;
+
 	if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
 		return 0;
 
@@ -1642,6 +1663,8 @@
 	if (!p_ll2_conn)
 		return -EINVAL;
 	p_rx = &p_ll2_conn->rx_queue;
+	if (!p_rx->set_prod_addr)
+		return -EIO;
 
 	spin_lock_irqsave(&p_rx->lock, flags);
 	if (!list_empty(&p_rx->free_descq))
@@ -2429,7 +2452,7 @@
 	INIT_LIST_HEAD(&cdev->ll2->list);
 	spin_lock_init(&cdev->ll2->lock);
 
-	cdev->ll2->rx_size = NET_SKB_PAD + ETH_HLEN +
+	cdev->ll2->rx_size = PRM_DMA_PAD_BYTES_NUM + ETH_HLEN +
 			     L1_CACHE_BYTES + params->mtu;
 
 	/* Allocate memory for LL2.
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -123,9 +123,9 @@
 	enum core_tx_dest tx_dest;
 	u8 tx_stats_en;
 	bool main_func_queue;
+	struct qed_ll2_cbs cbs;
 	struct qed_ll2_rx_queue rx_queue;
 	struct qed_ll2_tx_queue tx_queue;
-	struct qed_ll2_cbs cbs;
 };
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -280,6 +280,8 @@
 		dev_info->fw_eng = FW_ENGINEERING_VERSION;
 		dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH,
 						       &cdev->mf_bits);
+		if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits))
+			dev_info->b_arfs_capable = true;
 		dev_info->tx_switching = true;
 
 		if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME)
@@ -557,7 +559,12 @@
 			rc = cnt;
 	}
 
-	if (rc > 0) {
+	/* For VFs, we should return with an error in case we didn't get the
+	 * exact number of msix vectors as we requested.
+	 * Not doing that will lead to a crash when starting queues for
+	 * this VF.
+	 */
+	if ((IS_PF(cdev) && rc > 0) || (IS_VF(cdev) && rc == cnt)) {
 		/* MSI-x configuration was achieved */
 		int_params->out.int_mode = QED_INT_MODE_MSIX;
 		int_params->out.num_vectors = rc;
@@ -1087,9 +1094,6 @@
 #define QED_PERIODIC_DB_REC_INTERVAL_MS		100
 #define QED_PERIODIC_DB_REC_INTERVAL \
 	msecs_to_jiffies(QED_PERIODIC_DB_REC_INTERVAL_MS)
-#define QED_PERIODIC_DB_REC_WAIT_COUNT		10
-#define QED_PERIODIC_DB_REC_WAIT_INTERVAL \
-	(QED_PERIODIC_DB_REC_INTERVAL_MS / QED_PERIODIC_DB_REC_WAIT_COUNT)
 
 static int qed_slowpath_delayed_work(struct qed_hwfn *hwfn,
 				     enum qed_slowpath_wq_flag wq_flag,
@@ -1123,7 +1127,7 @@
 
 static void qed_slowpath_wq_stop(struct qed_dev *cdev)
 {
-	int i, sleep_count = QED_PERIODIC_DB_REC_WAIT_COUNT;
+	int i;
 
 	if (IS_VF(cdev))
 		return;
@@ -1135,13 +1139,7 @@
 		/* Stop queuing new delayed works */
 		cdev->hwfns[i].slowpath_wq_active = false;
 
-		/* Wait until the last periodic doorbell recovery is executed */
-		while (test_bit(QED_SLOWPATH_PERIODIC_DB_REC,
-				&cdev->hwfns[i].slowpath_task_flags) &&
-		       sleep_count--)
-			msleep(QED_PERIODIC_DB_REC_WAIT_INTERVAL);
-
-		flush_workqueue(cdev->hwfns[i].slowpath_wq);
+		cancel_delayed_work(&cdev->hwfns[i].slowpath_task);
 		destroy_workqueue(cdev->hwfns[i].slowpath_wq);
 	}
 }
@@ -1240,6 +1238,7 @@
 			} else {
 				DP_NOTICE(cdev,
 					  "Failed to acquire PTT for aRFS\n");
+				rc = -EINVAL;
 				goto err;
 			}
 		}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -498,14 +498,18 @@
 
 		spin_lock_bh(&p_hwfn->mcp_info->cmd_lock);
 
-		if (!qed_mcp_has_pending_cmd(p_hwfn))
+		if (!qed_mcp_has_pending_cmd(p_hwfn)) {
+			spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 			break;
+		}
 
 		rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt);
-		if (!rc)
+		if (!rc) {
+			spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 			break;
-		else if (rc != -EAGAIN)
+		} else if (rc != -EAGAIN) {
 			goto err;
+		}
 
 		spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 
@@ -522,6 +526,8 @@
 		return -EAGAIN;
 	}
 
+	spin_lock_bh(&p_hwfn->mcp_info->cmd_lock);
+
 	/* Send the mailbox command */
 	qed_mcp_reread_offsets(p_hwfn, p_ptt);
 	seq_num = ++p_hwfn->mcp_info->drv_mb_seq;
@@ -548,14 +554,18 @@
 
 		spin_lock_bh(&p_hwfn->mcp_info->cmd_lock);
 
-		if (p_cmd_elem->b_is_completed)
+		if (p_cmd_elem->b_is_completed) {
+			spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 			break;
+		}
 
 		rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt);
-		if (!rc)
+		if (!rc) {
+			spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 			break;
-		else if (rc != -EAGAIN)
+		} else if (rc != -EAGAIN) {
 			goto err;
+		}
 
 		spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 	} while (++cnt < max_retries);
@@ -576,6 +586,7 @@
 		return -EAGAIN;
 	}
 
+	spin_lock_bh(&p_hwfn->mcp_info->cmd_lock);
 	qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem);
 	spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock);
 
@@ -3149,12 +3160,20 @@
 	return rc;
 }
 
+void qed_mcp_nvm_info_free(struct qed_hwfn *p_hwfn)
+{
+	kfree(p_hwfn->nvm_info.image_att);
+	p_hwfn->nvm_info.image_att = NULL;
+	p_hwfn->nvm_info.valid = false;
+}
+
 int
 qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn,
 			  enum qed_nvm_images image_id,
 			  struct qed_nvm_image_att *p_image_att)
 {
 	enum nvm_image_type type;
+	int rc;
 	u32 i;
 
 	/* Translate image_id into MFW definitions */
@@ -3180,7 +3199,10 @@
 		return -EINVAL;
 	}
 
-	qed_mcp_nvm_info_populate(p_hwfn);
+	rc = qed_mcp_nvm_info_populate(p_hwfn);
+	if (rc)
+		return rc;
+
 	for (i = 0; i < p_hwfn->nvm_info.num_images; i++)
 		if (type == p_hwfn->nvm_info.image_att[i].image_type)
 			break;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -1193,6 +1193,13 @@
 int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn);
 
 /**
+ * @brief Delete nvm info shadow in the given hardware function
+ *
+ * @param p_hwfn
+ */
+void qed_mcp_nvm_info_free(struct qed_hwfn *p_hwfn);
+
+/**
  * @brief Get the engine affinity configuration.
  *
  * @param p_hwfn
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_ptp.c
@@ -44,8 +44,8 @@
 /* Add/subtract the Adjustment_Value when making a Drift adjustment */
 #define QED_DRIFT_CNTR_DIRECTION_SHIFT		31
 #define QED_TIMESTAMP_MASK			BIT(16)
-/* Param mask for Hardware to detect/timestamp the unicast PTP packets */
-#define QED_PTP_UCAST_PARAM_MASK		0xF
+/* Param mask for Hardware to detect/timestamp the L2/L4 unicast PTP packets */
+#define QED_PTP_UCAST_PARAM_MASK              0x70F
 
 static enum qed_resc_lock qed_ptcdev_to_resc(struct qed_hwfn *p_hwfn)
 {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -1245,8 +1245,7 @@
 
 	if (!rdma_cxt || !in_params || !out_params ||
 	    !p_hwfn->p_rdma_info->active) {
-		DP_ERR(p_hwfn->cdev,
-		       "qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n",
+		pr_err("qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n",
 		       rdma_cxt, in_params, out_params);
 		return NULL;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_roce.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_roce.c
@@ -107,13 +107,20 @@
 	 * Beyond the added delay we clear the bitmap anyway.
 	 */
 	while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) {
+		/* If the HW device is during recovery, all resources are
+		 * immediately reset without receiving a per-cid indication
+		 * from HW. In this case we don't expect the cid bitmap to be
+		 * cleared.
+		 */
+		if (p_hwfn->cdev->recov_in_prog)
+			return;
+
 		msleep(100);
 		if (wait_count++ > 20) {
 			DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n");
 			break;
 		}
 	}
-	qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE);
 }
 
 static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_sriov.c
@@ -96,6 +96,7 @@
 		p_ramrod->personality = PERSONALITY_ETH;
 		break;
 	case QED_PCI_ETH_ROCE:
+	case QED_PCI_ETH_IWARP:
 		p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
 		break;
 	default:
@@ -3002,12 +3003,16 @@
 	u8 mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED;
 	struct qed_filter_accept_flags *flags = &params->accept_flags;
 	struct qed_public_vf_info *vf_info;
+	u16 tlv_mask;
+
+	tlv_mask = BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) |
+		   BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN);
 
 	/* Untrusted VFs can't even be trusted to know that fact.
 	 * Simply indicate everything is configured fine, and trace
 	 * configuration 'behind their back'.
 	 */
-	if (!(*tlvs & BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM)))
+	if (!(*tlvs & tlv_mask))
 		return 0;
 
 	vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true);
@@ -3024,6 +3029,13 @@
 			flags->tx_accept_filter &= ~mask;
 	}
 
+	if (params->update_accept_any_vlan_flg) {
+		vf_info->accept_any_vlan = params->accept_any_vlan;
+
+		if (vf_info->forced_vlan && !vf_info->is_trusted_configured)
+			params->accept_any_vlan = false;
+	}
+
 	return 0;
 }
 
@@ -3800,11 +3812,11 @@
 	return found;
 }
 
-static void qed_iov_get_link(struct qed_hwfn *p_hwfn,
-			     u16 vfid,
-			     struct qed_mcp_link_params *p_params,
-			     struct qed_mcp_link_state *p_link,
-			     struct qed_mcp_link_capabilities *p_caps)
+static int qed_iov_get_link(struct qed_hwfn *p_hwfn,
+			    u16 vfid,
+			    struct qed_mcp_link_params *p_params,
+			    struct qed_mcp_link_state *p_link,
+			    struct qed_mcp_link_capabilities *p_caps)
 {
 	struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn,
 						       vfid,
@@ -3812,7 +3824,7 @@
 	struct qed_bulletin_content *p_bulletin;
 
 	if (!p_vf)
-		return;
+		return -EINVAL;
 
 	p_bulletin = p_vf->bulletin.p_virt;
 
@@ -3822,6 +3834,7 @@
 		__qed_vf_get_link_state(p_hwfn, p_link, p_bulletin);
 	if (p_caps)
 		__qed_vf_get_link_caps(p_hwfn, p_caps, p_bulletin);
+	return 0;
 }
 
 static int
@@ -4391,6 +4404,9 @@
 	}
 
 	vf = qed_iov_get_vf_info(QED_LEADING_HWFN(cdev), (u16)vfid, true);
+	if (!vf)
+		return -EINVAL;
+
 	vport_id = vf->vport_id;
 
 	return qed_configure_vport_wfq(cdev, vport_id, rate);
@@ -4683,6 +4699,7 @@
 	struct qed_public_vf_info *vf_info;
 	struct qed_mcp_link_state link;
 	u32 tx_rate;
+	int ret;
 
 	/* Sanitize request */
 	if (IS_VF(cdev))
@@ -4696,7 +4713,9 @@
 
 	vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true);
 
-	qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL);
+	ret = qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL);
+	if (ret)
+		return ret;
 
 	/* Fill information about VF */
 	ivi->vf = vf_id;
@@ -4712,6 +4731,7 @@
 	tx_rate = vf_info->tx_rate;
 	ivi->max_tx_rate = tx_rate ? tx_rate : link.speed;
 	ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id);
+	ivi->trusted = vf_info->is_trusted_request;
 
 	return 0;
 }
@@ -5133,7 +5153,7 @@
 
 		/* Validate that the VF has a configured vport */
 		vf = qed_iov_get_vf_info(hwfn, i, true);
-		if (!vf->vport_instance)
+		if (!vf || !vf->vport_instance)
 			continue;
 
 		memset(&params, 0, sizeof(params));
@@ -5142,6 +5162,12 @@
 
 		params.update_ctl_frame_check = 1;
 		params.mac_chk_en = !vf_info->is_trusted_configured;
+		params.update_accept_any_vlan_flg = 0;
+
+		if (vf_info->accept_any_vlan && vf_info->forced_vlan) {
+			params.update_accept_any_vlan_flg = 1;
+			params.accept_any_vlan = vf_info->accept_any_vlan;
+		}
 
 		if (vf_info->rx_accept_mode & mask) {
 			flags->update_rx_mode_config = 1;
@@ -5157,13 +5183,20 @@
 		if (!vf_info->is_trusted_configured) {
 			flags->rx_accept_filter &= ~mask;
 			flags->tx_accept_filter &= ~mask;
+			params.accept_any_vlan = false;
 		}
 
 		if (flags->update_rx_mode_config ||
 		    flags->update_tx_mode_config ||
-		    params.update_ctl_frame_check)
+		    params.update_ctl_frame_check ||
+		    params.update_accept_any_vlan_flg) {
+			DP_VERBOSE(hwfn, QED_MSG_IOV,
+				   "vport update config for %s VF[abs 0x%x rel 0x%x]\n",
+				   vf_info->is_trusted_configured ? "trusted" : "untrusted",
+				   vf->abs_vf_id, vf->relative_vf_id);
 			qed_sp_vport_update(hwfn, &params,
 					    QED_SPQ_MODE_EBLOCK, NULL);
+		}
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_sriov.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_sriov.h
@@ -88,6 +88,7 @@
 	bool is_trusted_request;
 	u8 rx_accept_mode;
 	u8 tx_accept_mode;
+	bool accept_any_vlan;
 };
 
 struct qed_iov_vf_init_params {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qed/qed_vf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qed/qed_vf.c
@@ -81,12 +81,17 @@
 	mutex_unlock(&(p_hwfn->vf_iov_info->mutex));
 }
 
+#define QED_VF_CHANNEL_USLEEP_ITERATIONS	90
+#define QED_VF_CHANNEL_USLEEP_DELAY		100
+#define QED_VF_CHANNEL_MSLEEP_ITERATIONS	10
+#define QED_VF_CHANNEL_MSLEEP_DELAY		25
+
 static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size)
 {
 	union vfpf_tlvs *p_req = p_hwfn->vf_iov_info->vf2pf_request;
 	struct ustorm_trigger_vf_zone trigger;
 	struct ustorm_vf_zone *zone_data;
-	int rc = 0, time = 100;
+	int iter, rc = 0;
 
 	zone_data = (struct ustorm_vf_zone *)PXP_VF_BAR0_START_USDM_ZONE_B;
 
@@ -126,11 +131,19 @@
 	REG_WR(p_hwfn, (uintptr_t)&zone_data->trigger, *((u32 *)&trigger));
 
 	/* When PF would be done with the response, it would write back to the
-	 * `done' address. Poll until then.
+	 * `done' address from a coherent DMA zone. Poll until then.
 	 */
-	while ((!*done) && time) {
-		msleep(25);
-		time--;
+
+	iter = QED_VF_CHANNEL_USLEEP_ITERATIONS;
+	while (!*done && iter--) {
+		udelay(QED_VF_CHANNEL_USLEEP_DELAY);
+		dma_rmb();
+	}
+
+	iter = QED_VF_CHANNEL_MSLEEP_ITERATIONS;
+	while (!*done && iter--) {
+		msleep(QED_VF_CHANNEL_MSLEEP_DELAY);
+		dma_rmb();
 	}
 
 	if (!*done) {
@@ -526,6 +539,9 @@
 						    p_iov->bulletin.size,
 						    &p_iov->bulletin.phys,
 						    GFP_KERNEL);
+	if (!p_iov->bulletin.p_virt)
+		goto free_pf2vf_reply;
+
 	DP_VERBOSE(p_hwfn, QED_MSG_IOV,
 		   "VF's bulletin Board [%p virt 0x%llx phys 0x%08x bytes]\n",
 		   p_iov->bulletin.p_virt,
@@ -565,6 +581,10 @@
 
 	return rc;
 
+free_pf2vf_reply:
+	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+			  sizeof(union pfvf_tlvs),
+			  p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys);
 free_vf2pf_request:
 	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
 			  sizeof(union vfpf_tlvs),
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede.h
@@ -163,6 +163,8 @@
 	struct list_head entry;
 	struct list_head rdma_event_list;
 	struct workqueue_struct *rdma_wq;
+	struct kref refcnt;
+	struct completion event_comp;
 	bool exp_recovery;
 };
 
@@ -572,12 +574,14 @@
 #define RX_RING_SIZE		((u16)BIT(RX_RING_SIZE_POW))
 #define NUM_RX_BDS_MAX		(RX_RING_SIZE - 1)
 #define NUM_RX_BDS_MIN		128
+#define NUM_RX_BDS_KDUMP_MIN	63
 #define NUM_RX_BDS_DEF		((u16)BIT(10) - 1)
 
 #define TX_RING_SIZE_POW	13
 #define TX_RING_SIZE		((u16)BIT(TX_RING_SIZE_POW))
 #define NUM_TX_BDS_MAX		(TX_RING_SIZE - 1)
 #define NUM_TX_BDS_MIN		128
+#define NUM_TX_BDS_KDUMP_MIN	63
 #define NUM_TX_BDS_DEF		NUM_TX_BDS_MAX
 
 #define QEDE_MIN_PKT_LEN		64
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_filter.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_filter.c
@@ -336,6 +336,9 @@
 {
 	int i;
 
+	if (!edev->dev_info.common.b_arfs_capable)
+		return -EINVAL;
+
 	edev->arfs = vzalloc(sizeof(*edev->arfs));
 	if (!edev->arfs)
 		return -ENOMEM;
@@ -1230,7 +1233,7 @@
 	netif_addr_lock_bh(ndev);
 
 	mc_count = netdev_mc_count(ndev);
-	if (mc_count < 64) {
+	if (mc_count <= 64) {
 		netdev_for_each_mc_addr(ha, ndev) {
 			ether_addr_copy(temp, ha->addr);
 			temp += ETH_ALEN;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_fp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_fp.c
@@ -723,6 +723,9 @@
 	buf = page_address(bd->data) + bd->page_offset;
 	skb = build_skb(buf, rxq->rx_buf_seg_size);
 
+	if (unlikely(!skb))
+		return NULL;
+
 	skb_reserve(skb, pad);
 	skb_put(skb, len);
 
@@ -1597,6 +1600,13 @@
 			data_split = true;
 		}
 	} else {
+		if (unlikely(skb->len > ETH_TX_MAX_NON_LSO_PKT_LEN)) {
+			DP_ERR(edev, "Unexpected non LSO skb length = 0x%x\n", skb->len);
+			qede_free_failed_tx_pkt(txq, first_bd, 0, false);
+			qede_update_tx_producer(txq);
+			return NETDEV_TX_OK;
+		}
+
 		val |= ((skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) <<
 			 ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT);
 	}
@@ -1737,6 +1747,11 @@
 			      ntohs(udp_hdr(skb)->dest) != gnv_port))
 				return features & ~(NETIF_F_CSUM_MASK |
 						    NETIF_F_GSO_MASK);
+		} else if (l4_proto == IPPROTO_IPIP) {
+			/* IPIP tunnels are unknown to the device or at least unsupported natively,
+			 * offloads for them can't be done trivially, so disable them for such skb.
+			 */
+			return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -29,6 +29,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <linux/crash_dump.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/version.h>
@@ -707,8 +708,14 @@
 	edev->dp_module = dp_module;
 	edev->dp_level = dp_level;
 	edev->ops = qed_ops;
-	edev->q_num_rx_buffers = NUM_RX_BDS_DEF;
-	edev->q_num_tx_buffers = NUM_TX_BDS_DEF;
+
+	if (is_kdump_kernel()) {
+		edev->q_num_rx_buffers = NUM_RX_BDS_KDUMP_MIN;
+		edev->q_num_tx_buffers = NUM_TX_BDS_KDUMP_MIN;
+	} else {
+		edev->q_num_rx_buffers = NUM_RX_BDS_DEF;
+		edev->q_num_tx_buffers = NUM_TX_BDS_DEF;
+	}
 
 	DP_INFO(edev, "Allocated netdev with %d tx queues and %d rx queues\n",
 		info->num_queues, info->num_queues);
@@ -763,7 +770,7 @@
 		      NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
 		      NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_TC;
 
-	if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1)
+	if (edev->dev_info.common.b_arfs_capable)
 		hw_features |= NETIF_F_NTUPLE;
 
 	if (edev->dev_info.common.vxlan_enable ||
@@ -1151,7 +1158,7 @@
 
 	/* PTP not supported on VFs */
 	if (!is_vf)
-		qede_ptp_enable(edev, (mode == QEDE_PROBE_NORMAL));
+		qede_ptp_enable(edev);
 
 	edev->ops->register_ops(cdev, &qede_ll_ops, edev);
 
@@ -1240,6 +1247,7 @@
 	if (system_state == SYSTEM_POWER_OFF)
 		return;
 	qed_ops->common->remove(cdev);
+	edev->cdev = NULL;
 
 	/* Since this can happen out-of-sync with other flows,
 	 * don't release the netdevice until after slowpath stop
@@ -1406,6 +1414,7 @@
 		rxq->rx_buf_seg_size = roundup_pow_of_two(size);
 	} else {
 		rxq->rx_buf_seg_size = PAGE_SIZE;
+		edev->ndev->features &= ~NETIF_F_GRO_HW;
 	}
 
 	/* Allocate the parallel driver ring for Rx buffers */
@@ -1450,6 +1459,7 @@
 		}
 	}
 
+	edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
 	if (!edev->gro_disable)
 		qede_set_tpa_param(rxq);
 err:
@@ -1702,8 +1712,6 @@
 		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
 			 edev->ndev->name, queue_id);
 	}
-
-	edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
 }
 
 static int qede_set_real_num_queues(struct qede_dev *edev)
@@ -1765,6 +1773,7 @@
 	}
 
 	edev->int_info.used_cnt = 0;
+	edev->int_info.msix_cnt = 0;
 }
 
 static int qede_req_msix_irqs(struct qede_dev *edev)
@@ -2203,7 +2212,7 @@
 	qede_vlan_mark_nonconfigured(edev);
 	edev->ops->fastpath_stop(edev->cdev);
 
-	if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
+	if (edev->dev_info.common.b_arfs_capable) {
 		qede_poll_for_freeing_arfs_filters(edev);
 		qede_free_arfs(edev);
 	}
@@ -2270,10 +2279,9 @@
 	if (rc)
 		goto err2;
 
-	if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
-		rc = qede_alloc_arfs(edev);
-		if (rc)
-			DP_NOTICE(edev, "aRFS memory allocation failed\n");
+	if (qede_alloc_arfs(edev)) {
+		edev->ndev->features &= ~NETIF_F_NTUPLE;
+		edev->dev_info.common.b_arfs_capable = false;
 	}
 
 	qede_napi_add_enable(edev);
@@ -2310,7 +2318,6 @@
 	goto out;
 err4:
 	qede_sync_free_irqs(edev);
-	memset(&edev->int_info.msix_cnt, 0, sizeof(struct qed_int_info));
 err3:
 	qede_napi_disable_remove(edev);
 err2:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_ptp.c
@@ -411,6 +411,7 @@
 	if (ptp->tx_skb) {
 		dev_kfree_skb_any(ptp->tx_skb);
 		ptp->tx_skb = NULL;
+		clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags);
 	}
 
 	/* Disable PTP in HW */
@@ -422,7 +423,7 @@
 	edev->ptp = NULL;
 }
 
-static int qede_ptp_init(struct qede_dev *edev, bool init_tc)
+static int qede_ptp_init(struct qede_dev *edev)
 {
 	struct qede_ptp *ptp;
 	int rc;
@@ -443,25 +444,19 @@
 	/* Init work queue for Tx timestamping */
 	INIT_WORK(&ptp->work, qede_ptp_task);
 
-	/* Init cyclecounter and timecounter. This is done only in the first
-	 * load. If done in every load, PTP application will fail when doing
-	 * unload / load (e.g. MTU change) while it is running.
-	 */
-	if (init_tc) {
-		memset(&ptp->cc, 0, sizeof(ptp->cc));
-		ptp->cc.read = qede_ptp_read_cc;
-		ptp->cc.mask = CYCLECOUNTER_MASK(64);
-		ptp->cc.shift = 0;
-		ptp->cc.mult = 1;
+	/* Init cyclecounter and timecounter */
+	memset(&ptp->cc, 0, sizeof(ptp->cc));
+	ptp->cc.read = qede_ptp_read_cc;
+	ptp->cc.mask = CYCLECOUNTER_MASK(64);
+	ptp->cc.shift = 0;
+	ptp->cc.mult = 1;
 
-		timecounter_init(&ptp->tc, &ptp->cc,
-				 ktime_to_ns(ktime_get_real()));
-	}
+	timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
 
-	return rc;
+	return 0;
 }
 
-int qede_ptp_enable(struct qede_dev *edev, bool init_tc)
+int qede_ptp_enable(struct qede_dev *edev)
 {
 	struct qede_ptp *ptp;
 	int rc;
@@ -482,7 +477,7 @@
 
 	edev->ptp = ptp;
 
-	rc = qede_ptp_init(edev, init_tc);
+	rc = qede_ptp_init(edev);
 	if (rc)
 		goto err1;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_ptp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_ptp.h
@@ -41,7 +41,7 @@
 void qede_ptp_tx_ts(struct qede_dev *edev, struct sk_buff *skb);
 int qede_ptp_hw_ts(struct qede_dev *edev, struct ifreq *req);
 void qede_ptp_disable(struct qede_dev *edev);
-int qede_ptp_enable(struct qede_dev *edev, bool init_tc);
+int qede_ptp_enable(struct qede_dev *edev);
 int qede_ptp_get_ts_info(struct qede_dev *edev, struct ethtool_ts_info *ts);
 
 static inline void qede_ptp_record_rx_ts(struct qede_dev *edev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qede/qede_rdma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qede/qede_rdma.c
@@ -59,6 +59,9 @@
 static int qede_rdma_create_wq(struct qede_dev *edev)
 {
 	INIT_LIST_HEAD(&edev->rdma_info.rdma_event_list);
+	kref_init(&edev->rdma_info.refcnt);
+	init_completion(&edev->rdma_info.event_comp);
+
 	edev->rdma_info.rdma_wq = create_singlethread_workqueue("rdma_wq");
 	if (!edev->rdma_info.rdma_wq) {
 		DP_NOTICE(edev, "qedr: Could not create workqueue\n");
@@ -83,10 +86,26 @@
 	}
 }
 
+static void qede_rdma_complete_event(struct kref *ref)
+{
+	struct qede_rdma_dev *rdma_dev =
+		container_of(ref, struct qede_rdma_dev, refcnt);
+
+	/* no more events will be added after this */
+	complete(&rdma_dev->event_comp);
+}
+
 static void qede_rdma_destroy_wq(struct qede_dev *edev)
 {
+	/* Avoid race with add_event flow, make sure it finishes before
+	 * we start accessing the list and cleaning up the work
+	 */
+	kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event);
+	wait_for_completion(&edev->rdma_info.event_comp);
+
 	qede_rdma_cleanup_event(edev);
 	destroy_workqueue(edev->rdma_info.rdma_wq);
+	edev->rdma_info.rdma_wq = NULL;
 }
 
 int qede_rdma_dev_add(struct qede_dev *edev, bool recovery)
@@ -307,18 +326,27 @@
 	if (edev->rdma_info.exp_recovery)
 		return;
 
-	if (!edev->rdma_info.qedr_dev)
+	if (!edev->rdma_info.qedr_dev || !edev->rdma_info.rdma_wq)
 		return;
 
+	/* We don't want the cleanup flow to start while we're allocating and
+	 * scheduling the work
+	 */
+	if (!kref_get_unless_zero(&edev->rdma_info.refcnt))
+		return; /* already being destroyed */
+
 	event_node = qede_rdma_get_free_event_node(edev);
 	if (!event_node)
-		return;
+		goto out;
 
 	event_node->event = event;
 	event_node->ptr = edev;
 
 	INIT_WORK(&event_node->work, qede_rdma_handle_event);
 	queue_work(edev->rdma_info.rdma_wq, &event_node->work);
+
+out:
+	kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event);
 }
 
 void qede_rdma_dev_event_open(struct qede_dev *edev)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qla3xxx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -115,7 +115,7 @@
 		value = readl(&port_regs->CommonRegs.semaphoreReg);
 		if ((value & (sem_mask >> 16)) == sem_bits)
 			return 0;
-		ssleep(1);
+		mdelay(1000);
 	} while (--seconds);
 	return -1;
 }
@@ -155,7 +155,7 @@
 				      "driver lock acquired\n");
 			return 1;
 		}
-		ssleep(1);
+		mdelay(1000);
 	} while (++i < 10);
 
 	netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
@@ -316,12 +316,11 @@
 			 * buffer
 			 */
 			skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
-			map = pci_map_single(qdev->pdev,
+			map = dma_map_single(&qdev->pdev->dev,
 					     lrg_buf_cb->skb->data,
-					     qdev->lrg_buffer_len -
-					     QL_HEADER_SPACE,
-					     PCI_DMA_FROMDEVICE);
-			err = pci_dma_mapping_error(qdev->pdev, map);
+					     qdev->lrg_buffer_len - QL_HEADER_SPACE,
+					     DMA_FROM_DEVICE);
+			err = dma_mapping_error(&qdev->pdev->dev, map);
 			if (err) {
 				netdev_err(qdev->ndev,
 					   "PCI mapping failed with error: %d\n",
@@ -1803,13 +1802,12 @@
 				 * first buffer
 				 */
 				skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
-				map = pci_map_single(qdev->pdev,
+				map = dma_map_single(&qdev->pdev->dev,
 						     lrg_buf_cb->skb->data,
-						     qdev->lrg_buffer_len -
-						     QL_HEADER_SPACE,
-						     PCI_DMA_FROMDEVICE);
+						     qdev->lrg_buffer_len - QL_HEADER_SPACE,
+						     DMA_FROM_DEVICE);
 
-				err = pci_dma_mapping_error(qdev->pdev, map);
+				err = dma_mapping_error(&qdev->pdev->dev, map);
 				if (err) {
 					netdev_err(qdev->ndev,
 						   "PCI mapping failed with error: %d\n",
@@ -1944,18 +1942,16 @@
 		goto invalid_seg_count;
 	}
 
-	pci_unmap_single(qdev->pdev,
+	dma_unmap_single(&qdev->pdev->dev,
 			 dma_unmap_addr(&tx_cb->map[0], mapaddr),
-			 dma_unmap_len(&tx_cb->map[0], maplen),
-			 PCI_DMA_TODEVICE);
+			 dma_unmap_len(&tx_cb->map[0], maplen), DMA_TO_DEVICE);
 	tx_cb->seg_count--;
 	if (tx_cb->seg_count) {
 		for (i = 1; i < tx_cb->seg_count; i++) {
-			pci_unmap_page(qdev->pdev,
-				       dma_unmap_addr(&tx_cb->map[i],
-						      mapaddr),
+			dma_unmap_page(&qdev->pdev->dev,
+				       dma_unmap_addr(&tx_cb->map[i], mapaddr),
 				       dma_unmap_len(&tx_cb->map[i], maplen),
-				       PCI_DMA_TODEVICE);
+				       DMA_TO_DEVICE);
 		}
 	}
 	qdev->ndev->stats.tx_packets++;
@@ -2022,10 +2018,9 @@
 	qdev->ndev->stats.rx_bytes += length;
 
 	skb_put(skb, length);
-	pci_unmap_single(qdev->pdev,
+	dma_unmap_single(&qdev->pdev->dev,
 			 dma_unmap_addr(lrg_buf_cb2, mapaddr),
-			 dma_unmap_len(lrg_buf_cb2, maplen),
-			 PCI_DMA_FROMDEVICE);
+			 dma_unmap_len(lrg_buf_cb2, maplen), DMA_FROM_DEVICE);
 	prefetch(skb->data);
 	skb_checksum_none_assert(skb);
 	skb->protocol = eth_type_trans(skb, qdev->ndev);
@@ -2068,10 +2063,9 @@
 	skb2 = lrg_buf_cb2->skb;
 
 	skb_put(skb2, length);	/* Just the second buffer length here. */
-	pci_unmap_single(qdev->pdev,
+	dma_unmap_single(&qdev->pdev->dev,
 			 dma_unmap_addr(lrg_buf_cb2, mapaddr),
-			 dma_unmap_len(lrg_buf_cb2, maplen),
-			 PCI_DMA_FROMDEVICE);
+			 dma_unmap_len(lrg_buf_cb2, maplen), DMA_FROM_DEVICE);
 	prefetch(skb2->data);
 
 	skb_checksum_none_assert(skb2);
@@ -2320,9 +2314,9 @@
 	/*
 	 * Map the skb buffer first.
 	 */
-	map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	map = dma_map_single(&qdev->pdev->dev, skb->data, len, DMA_TO_DEVICE);
 
-	err = pci_dma_mapping_error(qdev->pdev, map);
+	err = dma_mapping_error(&qdev->pdev->dev, map);
 	if (err) {
 		netdev_err(qdev->ndev, "PCI mapping failed with error: %d\n",
 			   err);
@@ -2358,11 +2352,11 @@
 		    (seg == 7 && seg_cnt > 8) ||
 		    (seg == 12 && seg_cnt > 13) ||
 		    (seg == 17 && seg_cnt > 18)) {
-			map = pci_map_single(qdev->pdev, oal,
+			map = dma_map_single(&qdev->pdev->dev, oal,
 					     sizeof(struct oal),
-					     PCI_DMA_TODEVICE);
+					     DMA_TO_DEVICE);
 
-			err = pci_dma_mapping_error(qdev->pdev, map);
+			err = dma_mapping_error(&qdev->pdev->dev, map);
 			if (err) {
 				netdev_err(qdev->ndev,
 					   "PCI mapping outbound address list with error: %d\n",
@@ -2424,24 +2418,24 @@
 		    (seg == 7 && seg_cnt > 8) ||
 		    (seg == 12 && seg_cnt > 13) ||
 		    (seg == 17 && seg_cnt > 18)) {
-			pci_unmap_single(qdev->pdev,
-				dma_unmap_addr(&tx_cb->map[seg], mapaddr),
-				dma_unmap_len(&tx_cb->map[seg], maplen),
-				 PCI_DMA_TODEVICE);
+			dma_unmap_single(&qdev->pdev->dev,
+					 dma_unmap_addr(&tx_cb->map[seg], mapaddr),
+					 dma_unmap_len(&tx_cb->map[seg], maplen),
+					 DMA_TO_DEVICE);
 			oal++;
 			seg++;
 		}
 
-		pci_unmap_page(qdev->pdev,
+		dma_unmap_page(&qdev->pdev->dev,
 			       dma_unmap_addr(&tx_cb->map[seg], mapaddr),
 			       dma_unmap_len(&tx_cb->map[seg], maplen),
-			       PCI_DMA_TODEVICE);
+			       DMA_TO_DEVICE);
 	}
 
-	pci_unmap_single(qdev->pdev,
+	dma_unmap_single(&qdev->pdev->dev,
 			 dma_unmap_addr(&tx_cb->map[0], mapaddr),
 			 dma_unmap_addr(&tx_cb->map[0], maplen),
-			 PCI_DMA_TODEVICE);
+			 DMA_TO_DEVICE);
 
 	return NETDEV_TX_BUSY;
 
@@ -2476,6 +2470,7 @@
 					     skb_shinfo(skb)->nr_frags);
 	if (tx_cb->seg_count == -1) {
 		netdev_err(ndev, "%s: invalid segment count!\n", __func__);
+		dev_kfree_skb_any(skb);
 		return NETDEV_TX_OK;
 	}
 
@@ -2526,9 +2521,8 @@
 	wmb();
 
 	qdev->req_q_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 (size_t) qdev->req_q_size,
-				 &qdev->req_q_phy_addr);
+	    dma_alloc_coherent(&qdev->pdev->dev, (size_t)qdev->req_q_size,
+			       &qdev->req_q_phy_addr, GFP_KERNEL);
 
 	if ((qdev->req_q_virt_addr == NULL) ||
 	    LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
@@ -2537,16 +2531,14 @@
 	}
 
 	qdev->rsp_q_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 (size_t) qdev->rsp_q_size,
-				 &qdev->rsp_q_phy_addr);
+	    dma_alloc_coherent(&qdev->pdev->dev, (size_t)qdev->rsp_q_size,
+			       &qdev->rsp_q_phy_addr, GFP_KERNEL);
 
 	if ((qdev->rsp_q_virt_addr == NULL) ||
 	    LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
 		netdev_err(qdev->ndev, "rspQ allocation failed\n");
-		pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
-				    qdev->req_q_virt_addr,
-				    qdev->req_q_phy_addr);
+		dma_free_coherent(&qdev->pdev->dev, (size_t)qdev->req_q_size,
+				  qdev->req_q_virt_addr, qdev->req_q_phy_addr);
 		return -ENOMEM;
 	}
 
@@ -2562,15 +2554,13 @@
 		return;
 	}
 
-	pci_free_consistent(qdev->pdev,
-			    qdev->req_q_size,
-			    qdev->req_q_virt_addr, qdev->req_q_phy_addr);
+	dma_free_coherent(&qdev->pdev->dev, qdev->req_q_size,
+			  qdev->req_q_virt_addr, qdev->req_q_phy_addr);
 
 	qdev->req_q_virt_addr = NULL;
 
-	pci_free_consistent(qdev->pdev,
-			    qdev->rsp_q_size,
-			    qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
+	dma_free_coherent(&qdev->pdev->dev, qdev->rsp_q_size,
+			  qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
 
 	qdev->rsp_q_virt_addr = NULL;
 
@@ -2594,12 +2584,13 @@
 		return -ENOMEM;
 
 	qdev->lrg_buf_q_alloc_virt_addr =
-		pci_alloc_consistent(qdev->pdev,
-				     qdev->lrg_buf_q_alloc_size,
-				     &qdev->lrg_buf_q_alloc_phy_addr);
+		dma_alloc_coherent(&qdev->pdev->dev,
+				   qdev->lrg_buf_q_alloc_size,
+				   &qdev->lrg_buf_q_alloc_phy_addr, GFP_KERNEL);
 
 	if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
 		netdev_err(qdev->ndev, "lBufQ failed\n");
+		kfree(qdev->lrg_buf);
 		return -ENOMEM;
 	}
 	qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
@@ -2614,15 +2605,17 @@
 		qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
 
 	qdev->small_buf_q_alloc_virt_addr =
-		pci_alloc_consistent(qdev->pdev,
-				     qdev->small_buf_q_alloc_size,
-				     &qdev->small_buf_q_alloc_phy_addr);
+		dma_alloc_coherent(&qdev->pdev->dev,
+				   qdev->small_buf_q_alloc_size,
+				   &qdev->small_buf_q_alloc_phy_addr, GFP_KERNEL);
 
 	if (qdev->small_buf_q_alloc_virt_addr == NULL) {
 		netdev_err(qdev->ndev, "Small Buffer Queue allocation failed\n");
-		pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
-				    qdev->lrg_buf_q_alloc_virt_addr,
-				    qdev->lrg_buf_q_alloc_phy_addr);
+		dma_free_coherent(&qdev->pdev->dev,
+				  qdev->lrg_buf_q_alloc_size,
+				  qdev->lrg_buf_q_alloc_virt_addr,
+				  qdev->lrg_buf_q_alloc_phy_addr);
+		kfree(qdev->lrg_buf);
 		return -ENOMEM;
 	}
 
@@ -2639,17 +2632,15 @@
 		return;
 	}
 	kfree(qdev->lrg_buf);
-	pci_free_consistent(qdev->pdev,
-			    qdev->lrg_buf_q_alloc_size,
-			    qdev->lrg_buf_q_alloc_virt_addr,
-			    qdev->lrg_buf_q_alloc_phy_addr);
+	dma_free_coherent(&qdev->pdev->dev, qdev->lrg_buf_q_alloc_size,
+			  qdev->lrg_buf_q_alloc_virt_addr,
+			  qdev->lrg_buf_q_alloc_phy_addr);
 
 	qdev->lrg_buf_q_virt_addr = NULL;
 
-	pci_free_consistent(qdev->pdev,
-			    qdev->small_buf_q_alloc_size,
-			    qdev->small_buf_q_alloc_virt_addr,
-			    qdev->small_buf_q_alloc_phy_addr);
+	dma_free_coherent(&qdev->pdev->dev, qdev->small_buf_q_alloc_size,
+			  qdev->small_buf_q_alloc_virt_addr,
+			  qdev->small_buf_q_alloc_phy_addr);
 
 	qdev->small_buf_q_virt_addr = NULL;
 
@@ -2667,9 +2658,9 @@
 		 QL_SMALL_BUFFER_SIZE);
 
 	qdev->small_buf_virt_addr =
-		pci_alloc_consistent(qdev->pdev,
-				     qdev->small_buf_total_size,
-				     &qdev->small_buf_phy_addr);
+		dma_alloc_coherent(&qdev->pdev->dev,
+				   qdev->small_buf_total_size,
+				   &qdev->small_buf_phy_addr, GFP_KERNEL);
 
 	if (qdev->small_buf_virt_addr == NULL) {
 		netdev_err(qdev->ndev, "Failed to get small buffer memory\n");
@@ -2702,10 +2693,10 @@
 		return;
 	}
 	if (qdev->small_buf_virt_addr != NULL) {
-		pci_free_consistent(qdev->pdev,
-				    qdev->small_buf_total_size,
-				    qdev->small_buf_virt_addr,
-				    qdev->small_buf_phy_addr);
+		dma_free_coherent(&qdev->pdev->dev,
+				  qdev->small_buf_total_size,
+				  qdev->small_buf_virt_addr,
+				  qdev->small_buf_phy_addr);
 
 		qdev->small_buf_virt_addr = NULL;
 	}
@@ -2720,10 +2711,10 @@
 		lrg_buf_cb = &qdev->lrg_buf[i];
 		if (lrg_buf_cb->skb) {
 			dev_kfree_skb(lrg_buf_cb->skb);
-			pci_unmap_single(qdev->pdev,
+			dma_unmap_single(&qdev->pdev->dev,
 					 dma_unmap_addr(lrg_buf_cb, mapaddr),
 					 dma_unmap_len(lrg_buf_cb, maplen),
-					 PCI_DMA_FROMDEVICE);
+					 DMA_FROM_DEVICE);
 			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
 		} else {
 			break;
@@ -2756,6 +2747,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)) {
@@ -2766,23 +2760,17 @@
 			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
 			 */
 			skb_reserve(skb, QL_HEADER_SPACE);
-			map = pci_map_single(qdev->pdev,
-					     skb->data,
-					     qdev->lrg_buffer_len -
-					     QL_HEADER_SPACE,
-					     PCI_DMA_FROMDEVICE);
+			map = dma_map_single(&qdev->pdev->dev, skb->data,
+					     qdev->lrg_buffer_len - QL_HEADER_SPACE,
+					     DMA_FROM_DEVICE);
 
-			err = pci_dma_mapping_error(qdev->pdev, map);
+			err = dma_mapping_error(&qdev->pdev->dev, map);
 			if (err) {
 				netdev_err(qdev->ndev,
 					   "PCI mapping failed with error: %d\n",
@@ -2792,6 +2780,7 @@
 				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 -
@@ -2866,8 +2855,8 @@
 	 * Network Completion Queue Producer Index Register
 	 */
 	qdev->shadow_reg_virt_addr =
-		pci_alloc_consistent(qdev->pdev,
-				     PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+		dma_alloc_coherent(&qdev->pdev->dev, PAGE_SIZE,
+				   &qdev->shadow_reg_phy_addr, GFP_KERNEL);
 
 	if (qdev->shadow_reg_virt_addr != NULL) {
 		qdev->preq_consumer_index = qdev->shadow_reg_virt_addr;
@@ -2922,10 +2911,9 @@
 err_buffer_queues:
 	ql_free_net_req_rsp_queues(qdev);
 err_req_rsp:
-	pci_free_consistent(qdev->pdev,
-			    PAGE_SIZE,
-			    qdev->shadow_reg_virt_addr,
-			    qdev->shadow_reg_phy_addr);
+	dma_free_coherent(&qdev->pdev->dev, PAGE_SIZE,
+			  qdev->shadow_reg_virt_addr,
+			  qdev->shadow_reg_phy_addr);
 
 	return -ENOMEM;
 }
@@ -2938,10 +2926,9 @@
 	ql_free_buffer_queues(qdev);
 	ql_free_net_req_rsp_queues(qdev);
 	if (qdev->shadow_reg_virt_addr != NULL) {
-		pci_free_consistent(qdev->pdev,
-				    PAGE_SIZE,
-				    qdev->shadow_reg_virt_addr,
-				    qdev->shadow_reg_phy_addr);
+		dma_free_coherent(&qdev->pdev->dev, PAGE_SIZE,
+				  qdev->shadow_reg_virt_addr,
+				  qdev->shadow_reg_phy_addr);
 		qdev->shadow_reg_virt_addr = NULL;
 	}
 }
@@ -3291,7 +3278,7 @@
 		if ((value & ISP_CONTROL_SR) == 0)
 			break;
 
-		ssleep(1);
+		mdelay(1000);
 	} while ((--max_wait_time));
 
 	/*
@@ -3327,7 +3314,7 @@
 						   ispControlStatus);
 			if ((value & ISP_CONTROL_FSR) == 0)
 				break;
-			ssleep(1);
+			mdelay(1000);
 		} while ((--max_wait_time));
 	}
 	if (max_wait_time == 0)
@@ -3495,20 +3482,19 @@
 
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 
-	err = ql_wait_for_drvr_lock(qdev);
-	if (err) {
-		err = ql_adapter_initialize(qdev);
-		if (err) {
-			netdev_err(ndev, "Unable to initialize adapter\n");
-			goto err_init;
-		}
-		netdev_err(ndev, "Releasing driver lock\n");
-		ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
-	} else {
+	if (!ql_wait_for_drvr_lock(qdev)) {
 		netdev_err(ndev, "Could not acquire driver lock\n");
+		err = -ENODEV;
 		goto err_lock;
 	}
 
+	err = ql_adapter_initialize(qdev);
+	if (err) {
+		netdev_err(ndev, "Unable to initialize adapter\n");
+		goto err_init;
+	}
+	ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+
 	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 
 	set_bit(QL_ADAPTER_UP, &qdev->flags);
@@ -3630,7 +3616,8 @@
 		qdev->mem_map_registers;
 	unsigned long hw_flags;
 
-	if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START), &qdev->flags)) {
+	if (test_bit(QL_RESET_PER_SCSI, &qdev->flags) ||
+	    test_bit(QL_RESET_START, &qdev->flags)) {
 		clear_bit(QL_LINK_MASTER, &qdev->flags);
 
 		/*
@@ -3642,18 +3629,15 @@
 			if (tx_cb->skb) {
 				netdev_printk(KERN_DEBUG, ndev,
 					      "Freeing lost SKB\n");
-				pci_unmap_single(qdev->pdev,
-					 dma_unmap_addr(&tx_cb->map[0],
-							mapaddr),
-					 dma_unmap_len(&tx_cb->map[0], maplen),
-					 PCI_DMA_TODEVICE);
+				dma_unmap_single(&qdev->pdev->dev,
+						 dma_unmap_addr(&tx_cb->map[0], mapaddr),
+						 dma_unmap_len(&tx_cb->map[0], maplen),
+						 DMA_TO_DEVICE);
 				for (j = 1; j < tx_cb->seg_count; j++) {
-					pci_unmap_page(qdev->pdev,
-					       dma_unmap_addr(&tx_cb->map[j],
-							      mapaddr),
-					       dma_unmap_len(&tx_cb->map[j],
-							     maplen),
-					       PCI_DMA_TODEVICE);
+					dma_unmap_page(&qdev->pdev->dev,
+						       dma_unmap_addr(&tx_cb->map[j], mapaddr),
+						       dma_unmap_len(&tx_cb->map[j], maplen),
+						       DMA_TO_DEVICE);
 				}
 				dev_kfree_skb(tx_cb->skb);
 				tx_cb->skb = NULL;
@@ -3769,7 +3753,7 @@
 	struct net_device *ndev = NULL;
 	struct ql3_adapter *qdev = NULL;
 	static int cards_found;
-	int uninitialized_var(pci_using_dac), err;
+	int pci_using_dac, err;
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -3785,13 +3769,10 @@
 
 	pci_set_master(pdev);
 
-	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+	if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
 		pci_using_dac = 1;
-		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-	} else if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) {
+	else if (!(err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))))
 		pci_using_dac = 0;
-		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-	}
 
 	if (err) {
 		pr_err("%s no usable DMA configuration\n", pci_name(pdev));
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -1079,8 +1079,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 */
@@ -2987,7 +2993,7 @@
 		QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
 		dev_info(&adapter->pdev->dev,
 			 "%s: lock recovery initiated\n", __func__);
-		msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+		mdelay(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
 		val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
 		id = ((val >> 2) & 0xF);
 		if (id == adapter->portnum) {
@@ -3023,7 +3029,7 @@
 		if (status)
 			break;
 
-		msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+		mdelay(QLC_83XX_DRV_LOCK_WAIT_DELAY);
 		i++;
 
 		if (i == 1)
@@ -3158,8 +3164,10 @@
 
 		indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
 		ret = QLCRD32(adapter, indirect_addr, &err);
-		if (err == -EIO)
+		if (err == -EIO) {
+			qlcnic_83xx_unlock_flash(adapter);
 			return err;
+		}
 
 		word = ret;
 		*(u32 *)p_data  = word;
@@ -3651,7 +3659,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;
@@ -3681,6 +3689,8 @@
 
 done:
 	qlcnic_free_mbx_args(&cmd);
+
+fail_mbx_args:
 	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);
 
 fail_diag_irq:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1720,7 +1720,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;
@@ -2043,6 +2043,7 @@
 			break;
 		}
 		entry += p_hdr->size;
+		cond_resched();
 	}
 	p_dev->ahw->reset.seq_index = index;
 }
@@ -2250,7 +2251,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,
@@ -2523,7 +2525,13 @@
 		goto disable_mbx_intr;
 
 	qlcnic_83xx_clear_function_resources(adapter);
-	qlcnic_dcb_enable(adapter->dcb);
+
+	err = qlcnic_dcb_enable(adapter->dcb);
+	if (err) {
+		qlcnic_dcb_free(adapter->dcb);
+		goto disable_mbx_intr;
+	}
+
 	qlcnic_83xx_initialize_nic(adapter, 1);
 	qlcnic_dcb_get_info(adapter->dcb);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -629,7 +629,13 @@
 	int i, err, ring;
 
 	if (dev->flags & QLCNIC_NEED_FLR) {
-		pci_reset_function(dev->pdev);
+		err = pci_reset_function(dev->pdev);
+		if (err) {
+			dev_err(&dev->pdev->dev,
+				"Adapter reset failed (%d). Please reboot\n",
+				err);
+			return err;
+		}
 		dev->flags &= ~QLCNIC_NEED_FLR;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
@@ -42,17 +42,12 @@
 	unsigned long			state;
 };
 
-static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb)
-{
-	kfree(dcb);
-}
-
 static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb)
 {
 	if (dcb && dcb->ops->get_hw_capability)
 		return dcb->ops->get_hw_capability(dcb);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static inline void qlcnic_dcb_free(struct qlcnic_dcb *dcb)
@@ -66,7 +61,7 @@
 	if (dcb && dcb->ops->attach)
 		return dcb->ops->attach(dcb);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static inline int
@@ -75,7 +70,7 @@
 	if (dcb && dcb->ops->query_hw_capability)
 		return dcb->ops->query_hw_capability(dcb, buf);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static inline void qlcnic_dcb_get_info(struct qlcnic_dcb *dcb)
@@ -90,7 +85,7 @@
 	if (dcb && dcb->ops->query_cee_param)
 		return dcb->ops->query_cee_param(dcb, buf, type);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb)
@@ -98,7 +93,7 @@
 	if (dcb && dcb->ops->get_cee_cfg)
 		return dcb->ops->get_cee_cfg(dcb);
 
-	return 0;
+	return -EOPNOTSUPP;
 }
 
 static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *msg)
@@ -113,9 +108,8 @@
 		dcb->ops->init_dcbnl_ops(dcb);
 }
 
-static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb)
+static inline int qlcnic_dcb_enable(struct qlcnic_dcb *dcb)
 {
-	if (dcb && qlcnic_dcb_attach(dcb))
-		qlcnic_clear_dcb_ops(dcb);
+	return dcb ? qlcnic_dcb_attach(dcb) : 0;
 }
 #endif
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1049,7 +1049,7 @@
 	for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
 		skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
 		if (!skb)
-			break;
+			goto error;
 		qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
 		skb_put(skb, QLCNIC_ILB_PKT_SIZE);
 		adapter->ahw->diag_cnt = 0;
@@ -1073,6 +1073,7 @@
 			cnt++;
 	}
 	if (cnt != i) {
+error:
 		dev_err(&adapter->pdev->dev,
 			"LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
 		if (mode != QLCNIC_ILB_MODE)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -440,7 +440,6 @@
 	QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, 1);
 	msleep(20);
 
-	qlcnic_rom_unlock(adapter);
 	/* big hammer don't reset CAM block on reset */
 	QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2509,6 +2509,7 @@
 		qlcnic_sriov_vf_register_map(ahw);
 		break;
 	default:
+		err = -EINVAL;
 		goto err_out_free_hw_res;
 	}
 
@@ -2638,7 +2639,13 @@
 			 "Device does not support MSI interrupts\n");
 
 	if (qlcnic_82xx_check(adapter)) {
-		qlcnic_dcb_enable(adapter->dcb);
+		err = qlcnic_dcb_enable(adapter->dcb);
+		if (err) {
+			qlcnic_dcb_free(adapter->dcb);
+			dev_err(&pdev->dev, "Failed to enable DCB\n");
+			goto err_out_free_hw;
+		}
+
 		qlcnic_dcb_get_info(adapter->dcb);
 		err = qlcnic_setup_intr(adapter);
 
@@ -2708,6 +2715,7 @@
 	kfree(ahw);
 
 err_out_free_res:
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_regions(pdev);
 
 err_out_disable_pdev:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ linux-ein-5.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;
@@ -1424,6 +1426,7 @@
 
 	if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
 		vfree(fw_dump->tmpl_hdr);
+		fw_dump->tmpl_hdr = NULL;
 
 		if (qlcnic_83xx_md_check_extended_dump_capability(adapter))
 			extended = !qlcnic_83xx_extend_md_capab(adapter);
@@ -1442,6 +1445,8 @@
 			struct qlcnic_83xx_dump_template_hdr *hdr;
 
 			hdr = fw_dump->tmpl_hdr;
+			if (!hdr)
+				return;
 			hdr->drv_cap_mask = 0x1f;
 			fw_dump->cap_mask = 0x1f;
 			dev_info(&pdev->dev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -202,7 +202,7 @@
 				   struct qlcnic_info *, u16);
 int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
 void qlcnic_sriov_free_vlans(struct qlcnic_adapter *);
-void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *);
+int qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *);
 bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *);
 void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *,
 			      struct qlcnic_vf_info *, u16);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -222,6 +222,8 @@
 	return 0;
 
 qlcnic_destroy_async_wq:
+	while (i--)
+		kfree(sriov->vf_info[i].vp);
 	destroy_workqueue(bc->bc_async_wq);
 
 qlcnic_destroy_trans_wq:
@@ -433,7 +435,7 @@
 					    struct qlcnic_cmd_args *cmd)
 {
 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-	int i, num_vlans;
+	int i, num_vlans, ret;
 	u16 *vlans;
 
 	if (sriov->allowed_vlans)
@@ -444,7 +446,9 @@
 	dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n",
 		 sriov->num_allowed_vlans);
 
-	qlcnic_sriov_alloc_vlans(adapter);
+	ret = qlcnic_sriov_alloc_vlans(adapter);
+	if (ret)
+		return ret;
 
 	if (!sriov->any_vlan)
 		return 0;
@@ -2160,7 +2164,7 @@
 	return err;
 }
 
-void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
+int qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_sriov *sriov = adapter->ahw->sriov;
 	struct qlcnic_vf_info *vf;
@@ -2170,7 +2174,11 @@
 		vf = &sriov->vf_info[i];
 		vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans,
 					  sizeof(*vf->sriov_vlans), GFP_KERNEL);
+		if (!vf->sriov_vlans)
+			return -ENOMEM;
 	}
+
+	return 0;
 }
 
 void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -598,7 +598,9 @@
 	if (err)
 		goto del_flr_queue;
 
-	qlcnic_sriov_alloc_vlans(adapter);
+	err = qlcnic_sriov_alloc_vlans(adapter);
+	if (err)
+		goto del_flr_queue;
 
 	return err;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/emac/emac-mac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/emac/emac-mac.c
@@ -1439,6 +1439,7 @@
 {
 	struct emac_tpd tpd;
 	u32 prod_idx;
+	int len;
 
 	memset(&tpd, 0, sizeof(tpd));
 
@@ -1458,9 +1459,10 @@
 	if (skb_network_offset(skb) != ETH_HLEN)
 		TPD_TYP_SET(&tpd, 1);
 
+	len = skb->len;
 	emac_tx_fill_tpd(adpt, tx_q, skb, &tpd);
 
-	netdev_sent_queue(adpt->netdev, skb->len);
+	netdev_sent_queue(adpt->netdev, len);
 
 	/* Make sure the are enough free descriptors to hold one
 	 * maximum-sized SKB.  We need one desc for each fragment,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/emac/emac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -485,13 +485,24 @@
 
 	ret = clk_prepare_enable(adpt->clk[EMAC_CLK_CFG_AHB]);
 	if (ret)
-		return ret;
+		goto disable_clk_axi;
 
 	ret = clk_set_rate(adpt->clk[EMAC_CLK_HIGH_SPEED], 19200000);
 	if (ret)
-		return ret;
+		goto disable_clk_cfg_ahb;
+
+	ret = clk_prepare_enable(adpt->clk[EMAC_CLK_HIGH_SPEED]);
+	if (ret)
+		goto disable_clk_cfg_ahb;
+
+	return 0;
+
+disable_clk_cfg_ahb:
+	clk_disable_unprepare(adpt->clk[EMAC_CLK_CFG_AHB]);
+disable_clk_axi:
+	clk_disable_unprepare(adpt->clk[EMAC_CLK_AXI]);
 
-	return clk_prepare_enable(adpt->clk[EMAC_CLK_HIGH_SPEED]);
+	return ret;
 }
 
 /* Enable clocks; needs emac_clks_phase1_init to be called before */
@@ -727,19 +738,26 @@
 	struct net_device *netdev = dev_get_drvdata(&pdev->dev);
 	struct emac_adapter *adpt = netdev_priv(netdev);
 
+	netif_carrier_off(netdev);
+	netif_tx_disable(netdev);
+
 	unregister_netdev(netdev);
 	netif_napi_del(&adpt->rx_q.napi);
 
+	free_irq(adpt->irq.irq, &adpt->irq);
+	cancel_work_sync(&adpt->work_thread);
+
 	emac_clks_teardown(adpt);
 
 	put_device(&adpt->phydev->mdio.dev);
 	mdiobus_unregister(adpt->mii_bus);
-	free_netdev(netdev);
 
 	if (adpt->phy.digital)
 		iounmap(adpt->phy.digital);
 	iounmap(adpt->phy.base);
 
+	free_netdev(netdev);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/qca_debug.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -30,6 +30,8 @@
 
 #define QCASPI_MAX_REGS 0x20
 
+#define QCASPI_RX_MAX_FRAMES 4
+
 static const u16 qcaspi_spi_regs[] = {
 	SPI_REG_BFR_SIZE,
 	SPI_REG_WRBUF_SPC_AVA,
@@ -249,31 +251,30 @@
 {
 	struct qcaspi *qca = netdev_priv(dev);
 
-	ring->rx_max_pending = 4;
+	ring->rx_max_pending = QCASPI_RX_MAX_FRAMES;
 	ring->tx_max_pending = TX_RING_MAX_LEN;
-	ring->rx_pending = 4;
+	ring->rx_pending = QCASPI_RX_MAX_FRAMES;
 	ring->tx_pending = qca->txr.count;
 }
 
 static int
 qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
 	struct qcaspi *qca = netdev_priv(dev);
 
-	if ((ring->rx_pending) ||
+	if (ring->rx_pending != QCASPI_RX_MAX_FRAMES ||
 	    (ring->rx_mini_pending) ||
 	    (ring->rx_jumbo_pending))
 		return -EINVAL;
 
-	if (netif_running(dev))
-		ops->ndo_stop(dev);
+	if (qca->spi_thread)
+		kthread_park(qca->spi_thread);
 
 	qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN);
 	qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN);
 
-	if (netif_running(dev))
-		ops->ndo_open(dev);
+	if (qca->spi_thread)
+		kthread_unpark(qca->spi_thread);
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/qca_spi.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -434,7 +434,7 @@
 				skb_put(qca->rx_skb, retcode);
 				qca->rx_skb->protocol = eth_type_trans(
 					qca->rx_skb, qca->rx_skb->dev);
-				qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+				skb_checksum_none_assert(qca->rx_skb);
 				netif_rx_ni(qca->rx_skb);
 				qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
 					net_dev->mtu + VLAN_ETH_HLEN);
@@ -573,9 +573,20 @@
 	netdev_info(qca->net_dev, "SPI thread created\n");
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
+		if (kthread_should_park()) {
+			netif_tx_disable(qca->net_dev);
+			netif_carrier_off(qca->net_dev);
+			qcaspi_flush_tx_ring(qca);
+			kthread_parkme();
+			if (qca->sync == QCASPI_SYNC_READY) {
+				netif_carrier_on(qca->net_dev);
+				netif_wake_queue(qca->net_dev);
+			}
+			continue;
+		}
+
 		if ((qca->intr_req == qca->intr_svc) &&
-		    (qca->txr.skb[qca->txr.head] == NULL) &&
-		    (qca->sync == QCASPI_SYNC_READY))
+		    !qca->txr.skb[qca->txr.head])
 			schedule();
 
 		set_current_state(TASK_RUNNING);
@@ -602,11 +613,17 @@
 			if (intr_cause & SPI_INT_CPU_ON) {
 				qcaspi_qca7k_sync(qca, QCASPI_EVENT_CPUON);
 
+				/* Frame decoding in progress */
+				if (qca->frm_handle.state != qca->frm_handle.init)
+					qca->net_dev->stats.rx_dropped++;
+
+				qcafrm_fsm_init_spi(&qca->frm_handle);
+				qca->stats.device_reset++;
+
 				/* not synced. */
 				if (qca->sync != QCASPI_SYNC_READY)
 					continue;
 
-				qca->stats.device_reset++;
 				netif_wake_queue(qca->net_dev);
 				netif_carrier_on(qca->net_dev);
 			}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/qca_uart.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -107,7 +107,7 @@
 			skb_put(qca->rx_skb, retcode);
 			qca->rx_skb->protocol = eth_type_trans(
 						qca->rx_skb, qca->rx_skb->dev);
-			qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+			skb_checksum_none_assert(qca->rx_skb);
 			netif_rx_ni(qca->rx_skb);
 			qca->rx_skb = netdev_alloc_skb_ip_align(netdev,
 								netdev->mtu +
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -13,25 +13,6 @@
 #include "rmnet_vnd.h"
 #include "rmnet_private.h"
 
-/* Locking scheme -
- * The shared resource which needs to be protected is realdev->rx_handler_data.
- * For the writer path, this is using rtnl_lock(). The writer paths are
- * rmnet_newlink(), rmnet_dellink() and rmnet_force_unassociate_device(). These
- * paths are already called with rtnl_lock() acquired in. There is also an
- * ASSERT_RTNL() to ensure that we are calling with rtnl acquired. For
- * dereference here, we will need to use rtnl_dereference(). Dev list writing
- * needs to happen with rtnl_lock() acquired for netdev_master_upper_dev_link().
- * For the reader path, the real_dev->rx_handler_data is called in the TX / RX
- * path. We only need rcu_read_lock() for these scenarios. In these cases,
- * the rcu_read_lock() is held in __dev_queue_xmit() and
- * netif_receive_skb_internal(), so readers need to use rcu_dereference_rtnl()
- * to get the relevant information. For dev list reading, we again acquire
- * rcu_read_lock() in rmnet_dellink() for netdev_master_upper_dev_get_rcu().
- * We also use unregister_netdevice_many() to free all rmnet devices in
- * rmnet_force_unassociate_device() so we dont lose the rtnl_lock() and free in
- * same context.
- */
-
 /* Local Definitions and Declarations */
 
 static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
@@ -51,9 +32,10 @@
 	return rtnl_dereference(real_dev->rx_handler_data);
 }
 
-static int rmnet_unregister_real_device(struct net_device *real_dev,
-					struct rmnet_port *port)
+static int rmnet_unregister_real_device(struct net_device *real_dev)
 {
+	struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
+
 	if (port->nr_rmnet_devs)
 		return -EINVAL;
 
@@ -61,22 +43,27 @@
 
 	kfree(port);
 
-	/* release reference on real_dev */
-	dev_put(real_dev);
-
 	netdev_dbg(real_dev, "Removed from rmnet\n");
 	return 0;
 }
 
-static int rmnet_register_real_device(struct net_device *real_dev)
+static int rmnet_register_real_device(struct net_device *real_dev,
+				      struct netlink_ext_ack *extack)
 {
 	struct rmnet_port *port;
 	int rc, entry;
 
 	ASSERT_RTNL();
 
-	if (rmnet_is_real_dev_registered(real_dev))
+	if (rmnet_is_real_dev_registered(real_dev)) {
+		port = rmnet_get_port_rtnl(real_dev);
+		if (port->rmnet_mode != RMNET_EPMODE_VND) {
+			NL_SET_ERR_MSG_MOD(extack, "bridge device already exists");
+			return -EINVAL;
+		}
+
 		return 0;
+	}
 
 	port = kzalloc(sizeof(*port), GFP_ATOMIC);
 	if (!port)
@@ -89,9 +76,6 @@
 		return -EBUSY;
 	}
 
-	/* hold on to real dev for MAP data */
-	dev_hold(real_dev);
-
 	for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
 		INIT_HLIST_HEAD(&port->muxed_ep[entry]);
 
@@ -99,28 +83,33 @@
 	return 0;
 }
 
-static void rmnet_unregister_bridge(struct net_device *dev,
-				    struct rmnet_port *port)
+static void rmnet_unregister_bridge(struct rmnet_port *port)
 {
-	struct rmnet_port *bridge_port;
-	struct net_device *bridge_dev;
+	struct net_device *bridge_dev, *real_dev, *rmnet_dev;
+	struct rmnet_port *real_port;
 
 	if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
 		return;
 
-	/* bridge slave handling */
+	rmnet_dev = port->rmnet_dev;
 	if (!port->nr_rmnet_devs) {
-		bridge_dev = port->bridge_ep;
-
-		bridge_port = rmnet_get_port_rtnl(bridge_dev);
-		bridge_port->bridge_ep = NULL;
-		bridge_port->rmnet_mode = RMNET_EPMODE_VND;
+		/* bridge device */
+		real_dev = port->bridge_ep;
+		bridge_dev = port->dev;
+
+		real_port = rmnet_get_port_rtnl(real_dev);
+		real_port->bridge_ep = NULL;
+		real_port->rmnet_mode = RMNET_EPMODE_VND;
 	} else {
+		/* real device */
 		bridge_dev = port->bridge_ep;
 
-		bridge_port = rmnet_get_port_rtnl(bridge_dev);
-		rmnet_unregister_real_device(bridge_dev, bridge_port);
+		port->bridge_ep = NULL;
+		port->rmnet_mode = RMNET_EPMODE_VND;
 	}
+
+	netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
+	rmnet_unregister_real_device(bridge_dev);
 }
 
 static int rmnet_newlink(struct net *src_net, struct net_device *dev,
@@ -135,6 +124,11 @@
 	int err = 0;
 	u16 mux_id;
 
+	if (!tb[IFLA_LINK]) {
+		NL_SET_ERR_MSG_MOD(extack, "link not specified");
+		return -EINVAL;
+	}
+
 	real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
 	if (!real_dev || !dev)
 		return -ENODEV;
@@ -148,7 +142,7 @@
 
 	mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
 
-	err = rmnet_register_real_device(real_dev);
+	err = rmnet_register_real_device(real_dev, extack);
 	if (err)
 		goto err0;
 
@@ -157,7 +151,12 @@
 	if (err)
 		goto err1;
 
+	err = netdev_upper_dev_link(real_dev, dev, extack);
+	if (err < 0)
+		goto err2;
+
 	port->rmnet_mode = mode;
+	port->rmnet_dev = dev;
 
 	hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
 
@@ -173,8 +172,11 @@
 
 	return 0;
 
+err2:
+	unregister_netdevice(dev);
+	rmnet_vnd_dellink(mux_id, port, ep);
 err1:
-	rmnet_unregister_real_device(real_dev, port);
+	rmnet_unregister_real_device(real_dev);
 err0:
 	kfree(ep);
 	return err;
@@ -183,77 +185,74 @@
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct rmnet_priv *priv = netdev_priv(dev);
-	struct net_device *real_dev;
+	struct net_device *real_dev, *bridge_dev;
+	struct rmnet_port *real_port, *bridge_port;
 	struct rmnet_endpoint *ep;
-	struct rmnet_port *port;
-	u8 mux_id;
+	u8 mux_id = priv->mux_id;
 
 	real_dev = priv->real_dev;
 
-	if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+	if (!rmnet_is_real_dev_registered(real_dev))
 		return;
 
-	port = rmnet_get_port_rtnl(real_dev);
-
-	mux_id = rmnet_vnd_get_mux(dev);
+	real_port = rmnet_get_port_rtnl(real_dev);
+	bridge_dev = real_port->bridge_ep;
+	if (bridge_dev) {
+		bridge_port = rmnet_get_port_rtnl(bridge_dev);
+		rmnet_unregister_bridge(bridge_port);
+	}
 
-	ep = rmnet_get_endpoint(port, mux_id);
+	ep = rmnet_get_endpoint(real_port, mux_id);
 	if (ep) {
 		hlist_del_init_rcu(&ep->hlnode);
-		rmnet_unregister_bridge(dev, port);
-		rmnet_vnd_dellink(mux_id, port, ep);
+		rmnet_vnd_dellink(mux_id, real_port, ep);
 		kfree(ep);
 	}
-	rmnet_unregister_real_device(real_dev, port);
 
+	netdev_upper_dev_unlink(real_dev, dev);
+	rmnet_unregister_real_device(real_dev);
 	unregister_netdevice_queue(dev, head);
 }
 
-static void rmnet_force_unassociate_device(struct net_device *dev)
+static void rmnet_force_unassociate_device(struct net_device *real_dev)
 {
-	struct net_device *real_dev = dev;
 	struct hlist_node *tmp_ep;
 	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 	unsigned long bkt_ep;
 	LIST_HEAD(list);
 
-	if (!rmnet_is_real_dev_registered(real_dev))
-		return;
-
-	ASSERT_RTNL();
-
-	port = rmnet_get_port_rtnl(dev);
-
-	rcu_read_lock();
-	rmnet_unregister_bridge(dev, port);
-
-	hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
-		unregister_netdevice_queue(ep->egress_dev, &list);
-		rmnet_vnd_dellink(ep->mux_id, port, ep);
+	port = rmnet_get_port_rtnl(real_dev);
 
-		hlist_del_init_rcu(&ep->hlnode);
-		kfree(ep);
+	if (port->nr_rmnet_devs) {
+		/* real device */
+		rmnet_unregister_bridge(port);
+		hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
+			unregister_netdevice_queue(ep->egress_dev, &list);
+			netdev_upper_dev_unlink(real_dev, ep->egress_dev);
+			rmnet_vnd_dellink(ep->mux_id, port, ep);
+			hlist_del_init_rcu(&ep->hlnode);
+			kfree(ep);
+		}
+		rmnet_unregister_real_device(real_dev);
+		unregister_netdevice_many(&list);
+	} else {
+		rmnet_unregister_bridge(port);
 	}
-
-	rcu_read_unlock();
-	unregister_netdevice_many(&list);
-
-	rmnet_unregister_real_device(real_dev, port);
 }
 
 static int rmnet_config_notify_cb(struct notifier_block *nb,
 				  unsigned long event, void *data)
 {
-	struct net_device *dev = netdev_notifier_info_to_dev(data);
+	struct net_device *real_dev = netdev_notifier_info_to_dev(data);
 
-	if (!dev)
+	if (!rmnet_is_real_dev_registered(real_dev))
 		return NOTIFY_DONE;
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
-		netdev_dbg(dev, "Kernel unregister\n");
-		rmnet_force_unassociate_device(dev);
+		netdev_dbg(real_dev, "Kernel unregister\n");
+		rmnet_force_unassociate_device(real_dev);
 		break;
 
 	default:
@@ -288,32 +287,41 @@
 {
 	struct rmnet_priv *priv = netdev_priv(dev);
 	struct net_device *real_dev;
-	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 	u16 mux_id;
 
 	if (!dev)
 		return -ENODEV;
 
-	real_dev = __dev_get_by_index(dev_net(dev),
-				      nla_get_u32(tb[IFLA_LINK]));
-
-	if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+	real_dev = priv->real_dev;
+	if (!rmnet_is_real_dev_registered(real_dev))
 		return -ENODEV;
 
 	port = rmnet_get_port_rtnl(real_dev);
 
 	if (data[IFLA_RMNET_MUX_ID]) {
 		mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
-		ep = rmnet_get_endpoint(port, priv->mux_id);
-		if (!ep)
-			return -ENODEV;
 
-		hlist_del_init_rcu(&ep->hlnode);
-		hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
+		if (mux_id != priv->mux_id) {
+			struct rmnet_endpoint *ep;
 
-		ep->mux_id = mux_id;
-		priv->mux_id = mux_id;
+			ep = rmnet_get_endpoint(port, priv->mux_id);
+			if (!ep)
+				return -ENODEV;
+
+			if (rmnet_get_endpoint(port, mux_id)) {
+				NL_SET_ERR_MSG_MOD(extack,
+						   "MUX ID already exists");
+				return -EINVAL;
+			}
+
+			hlist_del_init_rcu(&ep->hlnode);
+			hlist_add_head_rcu(&ep->hlnode,
+					   &port->muxed_ep[mux_id]);
+
+			ep->mux_id = mux_id;
+			priv->mux_id = mux_id;
+		}
 	}
 
 	if (data[IFLA_RMNET_FLAGS]) {
@@ -367,7 +375,7 @@
 
 struct rtnl_link_ops rmnet_link_ops __read_mostly = {
 	.kind		= "rmnet",
-	.maxtype	= __IFLA_RMNET_MAX,
+	.maxtype	= IFLA_RMNET_MAX,
 	.priv_size	= sizeof(struct rmnet_priv),
 	.setup		= rmnet_vnd_setup,
 	.validate	= rmnet_rtnl_validate,
@@ -379,11 +387,10 @@
 	.fill_info	= rmnet_fill_info,
 };
 
-/* Needs either rcu_read_lock() or rtnl lock */
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev)
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev)
 {
 	if (rmnet_is_real_dev_registered(real_dev))
-		return rcu_dereference_rtnl(real_dev->rx_handler_data);
+		return rcu_dereference_bh(real_dev->rx_handler_data);
 	else
 		return NULL;
 }
@@ -409,7 +416,7 @@
 	struct rmnet_port *port, *slave_port;
 	int err;
 
-	port = rmnet_get_port(real_dev);
+	port = rmnet_get_port_rtnl(real_dev);
 
 	/* If there is more than one rmnet dev attached, its probably being
 	 * used for muxing. Skip the briding in that case
@@ -420,13 +427,21 @@
 	if (rmnet_is_real_dev_registered(slave_dev))
 		return -EBUSY;
 
-	err = rmnet_register_real_device(slave_dev);
+	err = rmnet_register_real_device(slave_dev, extack);
 	if (err)
 		return -EBUSY;
 
-	slave_port = rmnet_get_port(slave_dev);
+	err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
+					   extack);
+	if (err) {
+		rmnet_unregister_real_device(slave_dev);
+		return err;
+	}
+
+	slave_port = rmnet_get_port_rtnl(slave_dev);
 	slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
 	slave_port->bridge_ep = real_dev;
+	slave_port->rmnet_dev = rmnet_dev;
 
 	port->rmnet_mode = RMNET_EPMODE_BRIDGE;
 	port->bridge_ep = slave_dev;
@@ -438,16 +453,9 @@
 int rmnet_del_bridge(struct net_device *rmnet_dev,
 		     struct net_device *slave_dev)
 {
-	struct rmnet_priv *priv = netdev_priv(rmnet_dev);
-	struct net_device *real_dev = priv->real_dev;
-	struct rmnet_port *port, *slave_port;
+	struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
 
-	port = rmnet_get_port(real_dev);
-	port->rmnet_mode = RMNET_EPMODE_VND;
-	port->bridge_ep = NULL;
-
-	slave_port = rmnet_get_port(slave_dev);
-	rmnet_unregister_real_device(slave_dev, slave_port);
+	rmnet_unregister_bridge(port);
 
 	netdev_dbg(slave_dev, "removed from rmnet as slave\n");
 	return 0;
@@ -473,8 +481,8 @@
 
 static void __exit rmnet_exit(void)
 {
-	unregister_netdevice_notifier(&rmnet_dev_notifier);
 	rtnl_link_unregister(&rmnet_link_ops);
+	unregister_netdevice_notifier(&rmnet_dev_notifier);
 }
 
 module_init(rmnet_init)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -28,6 +28,7 @@
 	u8 rmnet_mode;
 	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
 	struct net_device *bridge_ep;
+	struct net_device *rmnet_dev;
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
@@ -65,7 +66,7 @@
 	struct rmnet_priv_stats stats;
 };
 
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev);
 struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
 int rmnet_add_bridge(struct net_device *rmnet_dev,
 		     struct net_device *slave_dev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -159,6 +159,9 @@
 static void
 rmnet_bridge_handler(struct sk_buff *skb, struct net_device *bridge_dev)
 {
+	if (skb_mac_header_was_set(skb))
+		skb_push(skb, skb->mac_len);
+
 	if (bridge_dev) {
 		skb->dev = bridge_dev;
 		dev_queue_xmit(skb);
@@ -184,7 +187,12 @@
 		return RX_HANDLER_PASS;
 
 	dev = skb->dev;
-	port = rmnet_get_port(dev);
+	port = rmnet_get_port_rcu(dev);
+	if (unlikely(!port)) {
+		atomic_long_inc(&skb->dev->rx_nohandler);
+		kfree_skb(skb);
+		goto done;
+	}
 
 	switch (port->rmnet_mode) {
 	case RMNET_EPMODE_VND:
@@ -217,7 +225,7 @@
 	skb->dev = priv->real_dev;
 	mux_id = priv->mux_id;
 
-	port = rmnet_get_port(skb->dev);
+	port = rmnet_get_port_rcu(skb->dev);
 	if (!port)
 		goto drop;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -266,14 +266,6 @@
 	return 0;
 }
 
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
-{
-	struct rmnet_priv *priv;
-
-	priv = netdev_priv(rmnet_dev);
-	return priv->mux_id;
-}
-
 int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 {
 	netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
+++ linux-ein-5.4.0/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
@@ -16,6 +16,5 @@
 		      struct rmnet_endpoint *ep);
 void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
 void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
 void rmnet_vnd_setup(struct net_device *dev);
 #endif /* _RMNET_VND_H_ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/rdc/r6040.c
+++ linux-ein-5.4.0/drivers/net/ethernet/rdc/r6040.c
@@ -119,6 +119,8 @@
 #define PHY_ST		0x8A	/* PHY status register */
 #define MAC_SM		0xAC	/* MAC status machine */
 #define  MAC_SM_RST	0x0002	/* MAC status machine reset */
+#define MD_CSC		0xb6	/* MDC speed control register */
+#define  MD_CSC_DEFAULT	0x0030
 #define MAC_ID		0xBE	/* Identifier register */
 
 #define TX_DCNT		0x80	/* TX descriptor count */
@@ -354,8 +356,9 @@
 {
 	void __iomem *ioaddr = lp->base;
 	int limit = MAC_DEF_TIMEOUT;
-	u16 cmd;
+	u16 cmd, md_csc;
 
+	md_csc = ioread16(ioaddr + MD_CSC);
 	iowrite16(MAC_RST, ioaddr + MCR1);
 	while (limit--) {
 		cmd = ioread16(ioaddr + MCR1);
@@ -367,6 +370,10 @@
 	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
 	iowrite16(0, ioaddr + MAC_SM);
 	mdelay(5);
+
+	/* Restore MDIO clock frequency */
+	if (md_csc != MD_CSC_DEFAULT)
+		iowrite16(md_csc, ioaddr + MD_CSC);
 }
 
 static void r6040_init_mac_regs(struct net_device *dev)
@@ -1155,10 +1162,12 @@
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to register net device\n");
-		goto err_out_mdio_unregister;
+		goto err_out_phy_disconnect;
 	}
 	return 0;
 
+err_out_phy_disconnect:
+	phy_disconnect(dev->phydev);
 err_out_mdio_unregister:
 	mdiobus_unregister(lp->mii_bus);
 err_out_mdio:
@@ -1182,6 +1191,7 @@
 	struct r6040_private *lp = netdev_priv(dev);
 
 	unregister_netdev(dev);
+	phy_disconnect(dev->phydev);
 	mdiobus_unregister(lp->mii_bus);
 	mdiobus_free(lp->mii_bus);
 	netif_napi_del(&lp->napi);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/realtek/r8169_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/realtek/r8169_main.c
@@ -52,6 +52,7 @@
 #define FIRMWARE_8168G_3	"rtl_nic/rtl8168g-3.fw"
 #define FIRMWARE_8168H_1	"rtl_nic/rtl8168h-1.fw"
 #define FIRMWARE_8168H_2	"rtl_nic/rtl8168h-2.fw"
+#define FIRMWARE_8168FP_3	"rtl_nic/rtl8168fp-3.fw"
 #define FIRMWARE_8107E_1	"rtl_nic/rtl8107e-1.fw"
 #define FIRMWARE_8107E_2	"rtl_nic/rtl8107e-2.fw"
 #define FIRMWARE_8125A_3	"rtl_nic/rtl8125a-3.fw"
@@ -135,6 +136,7 @@
 	RTL_GIGA_MAC_VER_49,
 	RTL_GIGA_MAC_VER_50,
 	RTL_GIGA_MAC_VER_51,
+	RTL_GIGA_MAC_VER_52,
 	RTL_GIGA_MAC_VER_60,
 	RTL_GIGA_MAC_VER_61,
 	RTL_GIGA_MAC_NONE
@@ -202,6 +204,7 @@
 	[RTL_GIGA_MAC_VER_49] = {"RTL8168ep/8111ep"			},
 	[RTL_GIGA_MAC_VER_50] = {"RTL8168ep/8111ep"			},
 	[RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep"			},
+	[RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117",  FIRMWARE_8168FP_3},
 	[RTL_GIGA_MAC_VER_60] = {"RTL8125"				},
 	[RTL_GIGA_MAC_VER_61] = {"RTL8125",		FIRMWARE_8125A_3},
 };
@@ -212,6 +215,7 @@
 	{ PCI_VDEVICE(REALTEK,	0x8129) },
 	{ PCI_VDEVICE(REALTEK,	0x8136), RTL_CFG_NO_GBIT },
 	{ PCI_VDEVICE(REALTEK,	0x8161) },
+	{ PCI_VDEVICE(REALTEK,	0x8162) },
 	{ PCI_VDEVICE(REALTEK,	0x8167) },
 	{ PCI_VDEVICE(REALTEK,	0x8168) },
 	{ PCI_VDEVICE(NCUBE,	0x8168) },
@@ -680,6 +684,7 @@
 	struct rtl8169_counters *counters;
 	struct rtl8169_tc_offsets tc_offset;
 	u32 saved_wolopts;
+	int eee_adv;
 
 	const char *fw_name;
 	struct rtl_fw *rtl_fw;
@@ -712,6 +717,7 @@
 MODULE_FIRMWARE(FIRMWARE_8168G_3);
 MODULE_FIRMWARE(FIRMWARE_8168H_1);
 MODULE_FIRMWARE(FIRMWARE_8168H_2);
+MODULE_FIRMWARE(FIRMWARE_8168FP_3);
 MODULE_FIRMWARE(FIRMWARE_8107E_1);
 MODULE_FIRMWARE(FIRMWARE_8107E_2);
 MODULE_FIRMWARE(FIRMWARE_8125A_3);
@@ -741,12 +747,6 @@
 	RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
 }
 
-static void rtl_tx_performance_tweak(struct rtl8169_private *tp, u16 force)
-{
-	pcie_capability_clear_and_set_word(tp->pci_dev, PCI_EXP_DEVCTL,
-					   PCI_EXP_DEVCTL_READRQ, force);
-}
-
 static bool rtl_is_8125(struct rtl8169_private *tp)
 {
 	return tp->mac_version >= RTL_GIGA_MAC_VER_60;
@@ -756,7 +756,7 @@
 {
 	return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
 	       tp->mac_version != RTL_GIGA_MAC_VER_39 &&
-	       tp->mac_version <= RTL_GIGA_MAC_VER_51;
+	       tp->mac_version <= RTL_GIGA_MAC_VER_52;
 }
 
 static bool rtl_supports_eee(struct rtl8169_private *tp)
@@ -1092,6 +1092,17 @@
 	rtl_writephy(tp, reg_addr, (val & ~m) | p);
 }
 
+static void r8168g_phy_param(struct phy_device *phydev, u16 parm,
+			     u16 mask, u16 val)
+{
+	int oldpage = phy_select_page(phydev, 0x0a43);
+
+	__phy_write(phydev, 0x13, parm);
+	__phy_modify(phydev, 0x14, mask, val);
+
+	phy_restore_page(phydev, oldpage, 0);
+}
+
 DECLARE_RTL_COND(rtl_ephyar_cond)
 {
 	return RTL_R32(tp, EPHYAR) & EPHYAR_FLAG;
@@ -1115,6 +1126,13 @@
 		RTL_R32(tp, EPHYAR) & EPHYAR_DATA_MASK : ~0;
 }
 
+static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
+{
+	/* based on RTL8168FP_OOBMAC_BASE in vendor driver */
+	if (tp->mac_version == RTL_GIGA_MAC_VER_52 && type == ERIAR_OOB)
+		*cmd |= 0x7f0 << 18;
+}
+
 DECLARE_RTL_COND(rtl_eriar_cond)
 {
 	return RTL_R32(tp, ERIAR) & ERIAR_FLAG;
@@ -1123,9 +1141,12 @@
 static void _rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
 			   u32 val, int type)
 {
+	u32 cmd = ERIAR_WRITE_CMD | type | mask | addr;
+
 	BUG_ON((addr & 3) || (mask == 0));
 	RTL_W32(tp, ERIDR, val);
-	RTL_W32(tp, ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
+	r8168fp_adjust_ocp_cmd(tp, &cmd, type);
+	RTL_W32(tp, ERIAR, cmd);
 
 	rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
 }
@@ -1138,7 +1159,10 @@
 
 static u32 _rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
 {
-	RTL_W32(tp, ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
+	u32 cmd = ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr;
+
+	r8168fp_adjust_ocp_cmd(tp, &cmd, type);
+	RTL_W32(tp, ERIAR, cmd);
 
 	return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
 		RTL_R32(tp, ERIDR) : ~0;
@@ -1262,9 +1286,7 @@
 	case RTL_GIGA_MAC_VER_31:
 		rtl8168dp_driver_start(tp);
 		break;
-	case RTL_GIGA_MAC_VER_49:
-	case RTL_GIGA_MAC_VER_50:
-	case RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52:
 		rtl8168ep_driver_start(tp);
 		break;
 	default:
@@ -1296,9 +1318,7 @@
 	case RTL_GIGA_MAC_VER_31:
 		rtl8168dp_driver_stop(tp);
 		break;
-	case RTL_GIGA_MAC_VER_49:
-	case RTL_GIGA_MAC_VER_50:
-	case RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52:
 		rtl8168ep_driver_stop(tp);
 		break;
 	default:
@@ -1326,9 +1346,7 @@
 	case RTL_GIGA_MAC_VER_28:
 	case RTL_GIGA_MAC_VER_31:
 		return r8168dp_check_dash(tp);
-	case RTL_GIGA_MAC_VER_49:
-	case RTL_GIGA_MAC_VER_50:
-	case RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52:
 		return r8168ep_check_dash(tp);
 	default:
 		return false;
@@ -1503,7 +1521,7 @@
 		break;
 	case RTL_GIGA_MAC_VER_34:
 	case RTL_GIGA_MAC_VER_37:
-	case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_52:
 		options = RTL_R8(tp, Config2) & ~PME_SIGNAL;
 		if (wolopts)
 			options |= PME_SIGNAL;
@@ -1516,6 +1534,7 @@
 	rtl_lock_config_regs(tp);
 
 	device_set_wakeup_enable(tp_to_dev(tp), wolopts);
+	tp->dev->wol_enabled = wolopts ? 1 : 0;
 }
 
 static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -1805,7 +1824,7 @@
 {
 	switch(stringset) {
 	case ETH_SS_STATS:
-		memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
+		memcpy(data, rtl8169_gstrings, sizeof(rtl8169_gstrings));
 		break;
 	}
 }
@@ -2074,6 +2093,10 @@
 	}
 
 	ret = phy_ethtool_set_eee(tp->phydev, data);
+
+	if (!ret)
+		tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN,
+					   MDIO_AN_EEE_ADV);
 out:
 	pm_runtime_put_noidle(d);
 	return ret;
@@ -2104,10 +2127,16 @@
 static void rtl_enable_eee(struct rtl8169_private *tp)
 {
 	struct phy_device *phydev = tp->phydev;
-	int supported = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
+	int adv;
+
+	/* respect EEE advertisement the user may have set */
+	if (tp->eee_adv >= 0)
+		adv = tp->eee_adv;
+	else
+		adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
 
-	if (supported > 0)
-		phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, supported);
+	if (adv >= 0)
+		phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv);
 }
 
 static void rtl8169_get_mac_version(struct rtl8169_private *tp)
@@ -2132,6 +2161,9 @@
 		{ 0x7cf, 0x608,	RTL_GIGA_MAC_VER_60 },
 		{ 0x7c8, 0x608,	RTL_GIGA_MAC_VER_61 },
 
+		/* RTL8117 */
+		{ 0x7cf, 0x54a,	RTL_GIGA_MAC_VER_52 },
+
 		/* 8168EP family. */
 		{ 0x7cf, 0x502,	RTL_GIGA_MAC_VER_51 },
 		{ 0x7cf, 0x501,	RTL_GIGA_MAC_VER_50 },
@@ -2190,6 +2222,8 @@
 		{ 0x7cf, 0x348,	RTL_GIGA_MAC_VER_07 },
 		{ 0x7cf, 0x248,	RTL_GIGA_MAC_VER_07 },
 		{ 0x7cf, 0x340,	RTL_GIGA_MAC_VER_13 },
+		/* RTL8401, reportedly works if treated as RTL8101e */
+		{ 0x7cf, 0x240,	RTL_GIGA_MAC_VER_13 },
 		{ 0x7cf, 0x343,	RTL_GIGA_MAC_VER_10 },
 		{ 0x7cf, 0x342,	RTL_GIGA_MAC_VER_16 },
 		{ 0x7c8, 0x348,	RTL_GIGA_MAC_VER_09 },
@@ -2256,8 +2290,11 @@
 static void rtl_apply_firmware(struct rtl8169_private *tp)
 {
 	/* TODO: release firmware if rtl_fw_write_firmware signals failure. */
-	if (tp->rtl_fw)
+	if (tp->rtl_fw) {
 		rtl_fw_write_firmware(tp, tp->rtl_fw);
+		/* At least one firmware doesn't reset tp->ocp_base. */
+		tp->ocp_base = OCP_STD_PHY_BASE;
+	}
 }
 
 static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -3228,12 +3265,8 @@
 
 	phy_modify_paged(phydev, 0x0bcc, 0x14, BIT(8), 0);
 	phy_modify_paged(phydev, 0x0a44, 0x11, 0, BIT(7) | BIT(6));
-	phy_write(phydev, 0x1f, 0x0a43);
-	phy_write(phydev, 0x13, 0x8084);
-	phy_clear_bits(phydev, 0x14, BIT(14) | BIT(13));
-	phy_set_bits(phydev, 0x10, BIT(12) | BIT(1) | BIT(0));
-
-	phy_write(phydev, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x8084, 0x6000, 0x0000);
+	phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x1003);
 }
 
 static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
@@ -3263,9 +3296,7 @@
 	phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2));
 
 	/* Enable UC LPF tune function */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x8012);
-	rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000);
+	r8168g_phy_param(tp->phydev, 0x8012, 0x0000, 0x8000);
 
 	phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
 
@@ -3295,73 +3326,48 @@
 
 static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
 {
+	struct phy_device *phydev = tp->phydev;
 	u16 dout_tapbin;
 	u32 data;
 
 	rtl_apply_firmware(tp);
 
 	/* CHN EST parameters adjust - giga master */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x809b);
-	rtl_w0w1_phy(tp, 0x14, 0x8000, 0xf800);
-	rtl_writephy(tp, 0x13, 0x80a2);
-	rtl_w0w1_phy(tp, 0x14, 0x8000, 0xff00);
-	rtl_writephy(tp, 0x13, 0x80a4);
-	rtl_w0w1_phy(tp, 0x14, 0x8500, 0xff00);
-	rtl_writephy(tp, 0x13, 0x809c);
-	rtl_w0w1_phy(tp, 0x14, 0xbd00, 0xff00);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x809b, 0xf800, 0x8000);
+	r8168g_phy_param(phydev, 0x80a2, 0xff00, 0x8000);
+	r8168g_phy_param(phydev, 0x80a4, 0xff00, 0x8500);
+	r8168g_phy_param(phydev, 0x809c, 0xff00, 0xbd00);
 
 	/* CHN EST parameters adjust - giga slave */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x80ad);
-	rtl_w0w1_phy(tp, 0x14, 0x7000, 0xf800);
-	rtl_writephy(tp, 0x13, 0x80b4);
-	rtl_w0w1_phy(tp, 0x14, 0x5000, 0xff00);
-	rtl_writephy(tp, 0x13, 0x80ac);
-	rtl_w0w1_phy(tp, 0x14, 0x4000, 0xff00);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x80ad, 0xf800, 0x7000);
+	r8168g_phy_param(phydev, 0x80b4, 0xff00, 0x5000);
+	r8168g_phy_param(phydev, 0x80ac, 0xff00, 0x4000);
 
 	/* CHN EST parameters adjust - fnet */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x808e);
-	rtl_w0w1_phy(tp, 0x14, 0x1200, 0xff00);
-	rtl_writephy(tp, 0x13, 0x8090);
-	rtl_w0w1_phy(tp, 0x14, 0xe500, 0xff00);
-	rtl_writephy(tp, 0x13, 0x8092);
-	rtl_w0w1_phy(tp, 0x14, 0x9f00, 0xff00);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x808e, 0xff00, 0x1200);
+	r8168g_phy_param(phydev, 0x8090, 0xff00, 0xe500);
+	r8168g_phy_param(phydev, 0x8092, 0xff00, 0x9f00);
 
 	/* enable R-tune & PGA-retune function */
 	dout_tapbin = 0;
-	rtl_writephy(tp, 0x1f, 0x0a46);
-	data = rtl_readphy(tp, 0x13);
+	data = phy_read_paged(phydev, 0x0a46, 0x13);
 	data &= 3;
 	data <<= 2;
 	dout_tapbin |= data;
-	data = rtl_readphy(tp, 0x12);
+	data = phy_read_paged(phydev, 0x0a46, 0x12);
 	data &= 0xc000;
 	data >>= 14;
 	dout_tapbin |= data;
 	dout_tapbin = ~(dout_tapbin^0x08);
 	dout_tapbin <<= 12;
 	dout_tapbin &= 0xf000;
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x827a);
-	rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000);
-	rtl_writephy(tp, 0x13, 0x827b);
-	rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000);
-	rtl_writephy(tp, 0x13, 0x827c);
-	rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000);
-	rtl_writephy(tp, 0x13, 0x827d);
-	rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000);
-
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x0811);
-	rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0a42);
-	rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0000);
+
+	r8168g_phy_param(phydev, 0x827a, 0xf000, dout_tapbin);
+	r8168g_phy_param(phydev, 0x827b, 0xf000, dout_tapbin);
+	r8168g_phy_param(phydev, 0x827c, 0xf000, dout_tapbin);
+	r8168g_phy_param(phydev, 0x827d, 0xf000, dout_tapbin);
+	r8168g_phy_param(phydev, 0x0811, 0x0000, 0x0800);
+	phy_modify_paged(phydev, 0x0a42, 0x16, 0x0000, 0x0002);
 
 	/* enable GPHY 10M */
 	phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11));
@@ -3369,22 +3375,13 @@
 	/* SAR ADC performance */
 	phy_modify_paged(tp->phydev, 0x0bca, 0x17, BIT(12) | BIT(13), BIT(14));
 
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x803f);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x8047);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x804f);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x8057);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x805f);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x8067);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x13, 0x806f);
-	rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x803f, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x8047, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x804f, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x8057, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x805f, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x8067, 0x3000, 0x0000);
+	r8168g_phy_param(phydev, 0x806f, 0x3000, 0x0000);
 
 	/* disable phy pfm mode */
 	phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0);
@@ -3397,24 +3394,18 @@
 static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
 {
 	u16 ioffset_p3, ioffset_p2, ioffset_p1, ioffset_p0;
+	struct phy_device *phydev = tp->phydev;
 	u16 rlen;
 	u32 data;
 
 	rtl_apply_firmware(tp);
 
 	/* CHIN EST parameter update */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x808a);
-	rtl_w0w1_phy(tp, 0x14, 0x000a, 0x003f);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x808a, 0x003f, 0x000a);
 
 	/* enable R-tune & PGA-retune function */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x0811);
-	rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0a42);
-	rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x0811, 0x0000, 0x0800);
+	phy_modify_paged(phydev, 0x0a42, 0x16, 0x0000, 0x0002);
 
 	/* enable GPHY 10M */
 	phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11));
@@ -3434,26 +3425,20 @@
 	data = (ioffset_p3<<12)|(ioffset_p2<<8)|(ioffset_p1<<4)|(ioffset_p0);
 
 	if ((ioffset_p3 != 0x0f) || (ioffset_p2 != 0x0f) ||
-	    (ioffset_p1 != 0x0f) || (ioffset_p0 != 0x0f)) {
-		rtl_writephy(tp, 0x1f, 0x0bcf);
-		rtl_writephy(tp, 0x16, data);
-		rtl_writephy(tp, 0x1f, 0x0000);
-	}
+	    (ioffset_p1 != 0x0f) || (ioffset_p0 != 0x0f))
+		phy_write_paged(phydev, 0x0bcf, 0x16, data);
 
 	/* Modify rlen (TX LPF corner frequency) level */
-	rtl_writephy(tp, 0x1f, 0x0bcd);
-	data = rtl_readphy(tp, 0x16);
+	data = phy_read_paged(phydev, 0x0bcd, 0x16);
 	data &= 0x000f;
 	rlen = 0;
 	if (data > 3)
 		rlen = data - 3;
 	data = rlen | (rlen<<4) | (rlen<<8) | (rlen<<12);
-	rtl_writephy(tp, 0x17, data);
-	rtl_writephy(tp, 0x1f, 0x0bcd);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	phy_write_paged(phydev, 0x0bcd, 0x17, data);
 
 	/* disable phy pfm mode */
-	phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0);
+	phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0);
 
 	rtl8168g_disable_aldps(tp);
 	rtl8168g_config_eee_phy(tp);
@@ -3462,22 +3447,21 @@
 
 static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp)
 {
+	struct phy_device *phydev = tp->phydev;
+
 	/* Enable PHY auto speed down */
-	phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2));
+	phy_modify_paged(phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2));
 
 	rtl8168g_phy_adjust_10m_aldps(tp);
 
 	/* Enable EEE auto-fallback function */
-	phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2));
+	phy_modify_paged(phydev, 0x0a4b, 0x11, 0, BIT(2));
 
 	/* Enable UC LPF tune function */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x8012);
-	rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x8012, 0x0000, 0x8000);
 
 	/* set rg_sel_sdm_rate */
-	phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
+	phy_modify_paged(phydev, 0x0c42, 0x11, BIT(13), BIT(14));
 
 	rtl8168g_disable_aldps(tp);
 	rtl8168g_config_eee_phy(tp);
@@ -3486,63 +3470,38 @@
 
 static void rtl8168ep_2_hw_phy_config(struct rtl8169_private *tp)
 {
+	struct phy_device *phydev = tp->phydev;
+
 	rtl8168g_phy_adjust_10m_aldps(tp);
 
 	/* Enable UC LPF tune function */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x8012);
-	rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000);
-	rtl_writephy(tp, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x8012, 0x0000, 0x8000);
 
 	/* Set rg_sel_sdm_rate */
 	phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
 
 	/* Channel estimation parameters */
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x80f3);
-	rtl_w0w1_phy(tp, 0x14, 0x8b00, ~0x8bff);
-	rtl_writephy(tp, 0x13, 0x80f0);
-	rtl_w0w1_phy(tp, 0x14, 0x3a00, ~0x3aff);
-	rtl_writephy(tp, 0x13, 0x80ef);
-	rtl_w0w1_phy(tp, 0x14, 0x0500, ~0x05ff);
-	rtl_writephy(tp, 0x13, 0x80f6);
-	rtl_w0w1_phy(tp, 0x14, 0x6e00, ~0x6eff);
-	rtl_writephy(tp, 0x13, 0x80ec);
-	rtl_w0w1_phy(tp, 0x14, 0x6800, ~0x68ff);
-	rtl_writephy(tp, 0x13, 0x80ed);
-	rtl_w0w1_phy(tp, 0x14, 0x7c00, ~0x7cff);
-	rtl_writephy(tp, 0x13, 0x80f2);
-	rtl_w0w1_phy(tp, 0x14, 0xf400, ~0xf4ff);
-	rtl_writephy(tp, 0x13, 0x80f4);
-	rtl_w0w1_phy(tp, 0x14, 0x8500, ~0x85ff);
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x8110);
-	rtl_w0w1_phy(tp, 0x14, 0xa800, ~0xa8ff);
-	rtl_writephy(tp, 0x13, 0x810f);
-	rtl_w0w1_phy(tp, 0x14, 0x1d00, ~0x1dff);
-	rtl_writephy(tp, 0x13, 0x8111);
-	rtl_w0w1_phy(tp, 0x14, 0xf500, ~0xf5ff);
-	rtl_writephy(tp, 0x13, 0x8113);
-	rtl_w0w1_phy(tp, 0x14, 0x6100, ~0x61ff);
-	rtl_writephy(tp, 0x13, 0x8115);
-	rtl_w0w1_phy(tp, 0x14, 0x9200, ~0x92ff);
-	rtl_writephy(tp, 0x13, 0x810e);
-	rtl_w0w1_phy(tp, 0x14, 0x0400, ~0x04ff);
-	rtl_writephy(tp, 0x13, 0x810c);
-	rtl_w0w1_phy(tp, 0x14, 0x7c00, ~0x7cff);
-	rtl_writephy(tp, 0x13, 0x810b);
-	rtl_w0w1_phy(tp, 0x14, 0x5a00, ~0x5aff);
-	rtl_writephy(tp, 0x1f, 0x0a43);
-	rtl_writephy(tp, 0x13, 0x80d1);
-	rtl_w0w1_phy(tp, 0x14, 0xff00, ~0xffff);
-	rtl_writephy(tp, 0x13, 0x80cd);
-	rtl_w0w1_phy(tp, 0x14, 0x9e00, ~0x9eff);
-	rtl_writephy(tp, 0x13, 0x80d3);
-	rtl_w0w1_phy(tp, 0x14, 0x0e00, ~0x0eff);
-	rtl_writephy(tp, 0x13, 0x80d5);
-	rtl_w0w1_phy(tp, 0x14, 0xca00, ~0xcaff);
-	rtl_writephy(tp, 0x13, 0x80d7);
-	rtl_w0w1_phy(tp, 0x14, 0x8400, ~0x84ff);
+	r8168g_phy_param(phydev, 0x80f3, 0xff00, 0x8b00);
+	r8168g_phy_param(phydev, 0x80f0, 0xff00, 0x3a00);
+	r8168g_phy_param(phydev, 0x80ef, 0xff00, 0x0500);
+	r8168g_phy_param(phydev, 0x80f6, 0xff00, 0x6e00);
+	r8168g_phy_param(phydev, 0x80ec, 0xff00, 0x6800);
+	r8168g_phy_param(phydev, 0x80ed, 0xff00, 0x7c00);
+	r8168g_phy_param(phydev, 0x80f2, 0xff00, 0xf400);
+	r8168g_phy_param(phydev, 0x80f4, 0xff00, 0x8500);
+	r8168g_phy_param(phydev, 0x8110, 0xff00, 0xa800);
+	r8168g_phy_param(phydev, 0x810f, 0xff00, 0x1d00);
+	r8168g_phy_param(phydev, 0x8111, 0xff00, 0xf500);
+	r8168g_phy_param(phydev, 0x8113, 0xff00, 0x6100);
+	r8168g_phy_param(phydev, 0x8115, 0xff00, 0x9200);
+	r8168g_phy_param(phydev, 0x810e, 0xff00, 0x0400);
+	r8168g_phy_param(phydev, 0x810c, 0xff00, 0x7c00);
+	r8168g_phy_param(phydev, 0x810b, 0xff00, 0x5a00);
+	r8168g_phy_param(phydev, 0x80d1, 0xff00, 0xff00);
+	r8168g_phy_param(phydev, 0x80cd, 0xff00, 0x9e00);
+	r8168g_phy_param(phydev, 0x80d3, 0xff00, 0x0e00);
+	r8168g_phy_param(phydev, 0x80d5, 0xff00, 0xca00);
+	r8168g_phy_param(phydev, 0x80d7, 0xff00, 0x8400);
 
 	/* Force PWM-mode */
 	rtl_writephy(tp, 0x1f, 0x0bcd);
@@ -3561,6 +3520,46 @@
 	rtl_enable_eee(tp);
 }
 
+static void rtl8117_hw_phy_config(struct rtl8169_private *tp)
+{
+	struct phy_device *phydev = tp->phydev;
+
+	/* CHN EST parameters adjust - fnet */
+	r8168g_phy_param(phydev, 0x808e, 0xff00, 0x4800);
+	r8168g_phy_param(phydev, 0x8090, 0xff00, 0xcc00);
+	r8168g_phy_param(phydev, 0x8092, 0xff00, 0xb000);
+
+	r8168g_phy_param(phydev, 0x8088, 0xff00, 0x6000);
+	r8168g_phy_param(phydev, 0x808b, 0x3f00, 0x0b00);
+	r8168g_phy_param(phydev, 0x808d, 0x1f00, 0x0600);
+	r8168g_phy_param(phydev, 0x808c, 0xff00, 0xb000);
+	r8168g_phy_param(phydev, 0x80a0, 0xff00, 0x2800);
+	r8168g_phy_param(phydev, 0x80a2, 0xff00, 0x5000);
+	r8168g_phy_param(phydev, 0x809b, 0xf800, 0xb000);
+	r8168g_phy_param(phydev, 0x809a, 0xff00, 0x4b00);
+	r8168g_phy_param(phydev, 0x809d, 0x3f00, 0x0800);
+	r8168g_phy_param(phydev, 0x80a1, 0xff00, 0x7000);
+	r8168g_phy_param(phydev, 0x809f, 0x1f00, 0x0300);
+	r8168g_phy_param(phydev, 0x809e, 0xff00, 0x8800);
+	r8168g_phy_param(phydev, 0x80b2, 0xff00, 0x2200);
+	r8168g_phy_param(phydev, 0x80ad, 0xf800, 0x9800);
+	r8168g_phy_param(phydev, 0x80af, 0x3f00, 0x0800);
+	r8168g_phy_param(phydev, 0x80b3, 0xff00, 0x6f00);
+	r8168g_phy_param(phydev, 0x80b1, 0x1f00, 0x0300);
+	r8168g_phy_param(phydev, 0x80b0, 0xff00, 0x9300);
+
+	r8168g_phy_param(phydev, 0x8011, 0x0000, 0x0800);
+
+	/* enable GPHY 10M */
+	phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11));
+
+	r8168g_phy_param(phydev, 0x8016, 0x0000, 0x0400);
+
+	rtl8168g_disable_aldps(tp);
+	rtl8168h_config_eee_phy(tp);
+	rtl_enable_eee(tp);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -3657,38 +3656,22 @@
 	phy_modify_paged(phydev, 0xad1, 0x15, 0x0000, 0x03ff);
 	phy_modify_paged(phydev, 0xad1, 0x16, 0x0000, 0x03ff);
 
-	phy_write(phydev, 0x1f, 0x0a43);
-	phy_write(phydev, 0x13, 0x80ea);
-	phy_modify(phydev, 0x14, 0xff00, 0xc400);
-	phy_write(phydev, 0x13, 0x80eb);
-	phy_modify(phydev, 0x14, 0x0700, 0x0300);
-	phy_write(phydev, 0x13, 0x80f8);
-	phy_modify(phydev, 0x14, 0xff00, 0x1c00);
-	phy_write(phydev, 0x13, 0x80f1);
-	phy_modify(phydev, 0x14, 0xff00, 0x3000);
-	phy_write(phydev, 0x13, 0x80fe);
-	phy_modify(phydev, 0x14, 0xff00, 0xa500);
-	phy_write(phydev, 0x13, 0x8102);
-	phy_modify(phydev, 0x14, 0xff00, 0x5000);
-	phy_write(phydev, 0x13, 0x8105);
-	phy_modify(phydev, 0x14, 0xff00, 0x3300);
-	phy_write(phydev, 0x13, 0x8100);
-	phy_modify(phydev, 0x14, 0xff00, 0x7000);
-	phy_write(phydev, 0x13, 0x8104);
-	phy_modify(phydev, 0x14, 0xff00, 0xf000);
-	phy_write(phydev, 0x13, 0x8106);
-	phy_modify(phydev, 0x14, 0xff00, 0x6500);
-	phy_write(phydev, 0x13, 0x80dc);
-	phy_modify(phydev, 0x14, 0xff00, 0xed00);
-	phy_write(phydev, 0x13, 0x80df);
-	phy_set_bits(phydev, 0x14, BIT(8));
-	phy_write(phydev, 0x13, 0x80e1);
-	phy_clear_bits(phydev, 0x14, BIT(8));
-	phy_write(phydev, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x80ea, 0xff00, 0xc400);
+	r8168g_phy_param(phydev, 0x80eb, 0x0700, 0x0300);
+	r8168g_phy_param(phydev, 0x80f8, 0xff00, 0x1c00);
+	r8168g_phy_param(phydev, 0x80f1, 0xff00, 0x3000);
+	r8168g_phy_param(phydev, 0x80fe, 0xff00, 0xa500);
+	r8168g_phy_param(phydev, 0x8102, 0xff00, 0x5000);
+	r8168g_phy_param(phydev, 0x8105, 0xff00, 0x3300);
+	r8168g_phy_param(phydev, 0x8100, 0xff00, 0x7000);
+	r8168g_phy_param(phydev, 0x8104, 0xff00, 0xf000);
+	r8168g_phy_param(phydev, 0x8106, 0xff00, 0x6500);
+	r8168g_phy_param(phydev, 0x80dc, 0xff00, 0xed00);
+	r8168g_phy_param(phydev, 0x80df, 0x0000, 0x0100);
+	r8168g_phy_param(phydev, 0x80e1, 0x0100, 0x0000);
 
 	phy_modify_paged(phydev, 0xbf0, 0x13, 0x003f, 0x0038);
-	phy_write_paged(phydev, 0xa43, 0x13, 0x819f);
-	phy_write_paged(phydev, 0xa43, 0x14, 0xd0b6);
+	r8168g_phy_param(phydev, 0x819f, 0xffff, 0xd0b6);
 
 	phy_write_paged(phydev, 0xbc3, 0x12, 0x5555);
 	phy_modify_paged(phydev, 0xbf0, 0x15, 0x0e00, 0x0a00);
@@ -3743,22 +3726,16 @@
 	phy_write(phydev, 0x14, 0x0002);
 	for (i = 0; i < 25; i++)
 		phy_write(phydev, 0x14, 0x0000);
-
-	phy_write(phydev, 0x13, 0x8257);
-	phy_write(phydev, 0x14, 0x020F);
-
-	phy_write(phydev, 0x13, 0x80EA);
-	phy_write(phydev, 0x14, 0x7843);
 	phy_write(phydev, 0x1f, 0x0000);
 
+	r8168g_phy_param(phydev, 0x8257, 0xffff, 0x020F);
+	r8168g_phy_param(phydev, 0x80ea, 0xffff, 0x7843);
+
 	rtl_apply_firmware(tp);
 
 	phy_modify_paged(phydev, 0xd06, 0x14, 0x0000, 0x2000);
 
-	phy_write(phydev, 0x1f, 0x0a43);
-	phy_write(phydev, 0x13, 0x81a2);
-	phy_set_bits(phydev, 0x14, BIT(8));
-	phy_write(phydev, 0x1f, 0x0000);
+	r8168g_phy_param(phydev, 0x81a2, 0x0000, 0x0100);
 
 	phy_modify_paged(phydev, 0xb54, 0x16, 0xff00, 0xdb00);
 	phy_modify_paged(phydev, 0xa45, 0x12, 0x0001, 0x0000);
@@ -3826,6 +3803,7 @@
 		[RTL_GIGA_MAC_VER_49] = rtl8168ep_1_hw_phy_config,
 		[RTL_GIGA_MAC_VER_50] = rtl8168ep_2_hw_phy_config,
 		[RTL_GIGA_MAC_VER_51] = rtl8168ep_2_hw_phy_config,
+		[RTL_GIGA_MAC_VER_52] = rtl8117_hw_phy_config,
 		[RTL_GIGA_MAC_VER_60] = rtl8125_1_hw_phy_config,
 		[RTL_GIGA_MAC_VER_61] = rtl8125_2_hw_phy_config,
 	};
@@ -3919,7 +3897,7 @@
 	case RTL_GIGA_MAC_VER_32:
 	case RTL_GIGA_MAC_VER_33:
 	case RTL_GIGA_MAC_VER_34:
-	case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_61:
 		RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) |
 			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
 		break;
@@ -3944,7 +3922,9 @@
 	}
 
 	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_33:
+	case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
+	case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
+	case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_33:
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_39:
 	case RTL_GIGA_MAC_VER_43:
@@ -3955,6 +3935,7 @@
 	case RTL_GIGA_MAC_VER_48:
 	case RTL_GIGA_MAC_VER_50:
 	case RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_52:
 	case RTL_GIGA_MAC_VER_60:
 	case RTL_GIGA_MAC_VER_61:
 		RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~0x80);
@@ -3973,7 +3954,9 @@
 static void rtl_pll_power_up(struct rtl8169_private *tp)
 {
 	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_33:
+	case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
+	case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
+	case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_33:
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_39:
 	case RTL_GIGA_MAC_VER_43:
@@ -3986,6 +3969,7 @@
 	case RTL_GIGA_MAC_VER_48:
 	case RTL_GIGA_MAC_VER_50:
 	case RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_52:
 	case RTL_GIGA_MAC_VER_60:
 	case RTL_GIGA_MAC_VER_61:
 		RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0xc0);
@@ -4017,7 +4001,7 @@
 	case RTL_GIGA_MAC_VER_38:
 		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
 		break;
-	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:
 		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
 		break;
 	case RTL_GIGA_MAC_VER_60 ... RTL_GIGA_MAC_VER_61:
@@ -4039,14 +4023,12 @@
 {
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1);
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B);
 }
 
 static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
 {
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1);
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
 }
 
 static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -4061,104 +4043,80 @@
 
 static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
 {
-	RTL_W8(tp, MaxTxPacketSize, 0x3f);
+	RTL_W8(tp, MaxTxPacketSize, 0x24);
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01);
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B);
 }
 
 static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
 {
-	RTL_W8(tp, MaxTxPacketSize, 0x0c);
+	RTL_W8(tp, MaxTxPacketSize, 0x3f);
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01);
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-}
-
-static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
-{
-	rtl_tx_performance_tweak(tp,
-		PCI_EXP_DEVCTL_READRQ_512B | PCI_EXP_DEVCTL_NOSNOOP_EN);
-}
-
-static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
-{
-	rtl_tx_performance_tweak(tp,
-		PCI_EXP_DEVCTL_READRQ_4096B | PCI_EXP_DEVCTL_NOSNOOP_EN);
 }
 
 static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
 {
-	r8168b_0_hw_jumbo_enable(tp);
-
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0));
 }
 
 static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
 {
-	r8168b_0_hw_jumbo_disable(tp);
-
 	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
 }
 
-static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
+static void rtl_jumbo_config(struct rtl8169_private *tp)
 {
-	rtl_unlock_config_regs(tp);
-	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_11:
-		r8168b_0_hw_jumbo_enable(tp);
-		break;
-	case RTL_GIGA_MAC_VER_12:
-	case RTL_GIGA_MAC_VER_17:
-		r8168b_1_hw_jumbo_enable(tp);
-		break;
-	case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
-		r8168c_hw_jumbo_enable(tp);
-		break;
-	case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
-		r8168dp_hw_jumbo_enable(tp);
-		break;
-	case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
-		r8168e_hw_jumbo_enable(tp);
-		break;
-	default:
-		break;
-	}
-	rtl_lock_config_regs(tp);
-}
+	bool jumbo = tp->dev->mtu > ETH_DATA_LEN;
+	int readrq = 4096;
 
-static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
-{
 	rtl_unlock_config_regs(tp);
 	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_11:
-		r8168b_0_hw_jumbo_disable(tp);
-		break;
 	case RTL_GIGA_MAC_VER_12:
 	case RTL_GIGA_MAC_VER_17:
-		r8168b_1_hw_jumbo_disable(tp);
+		if (jumbo) {
+			readrq = 512;
+			r8168b_1_hw_jumbo_enable(tp);
+		} else {
+			r8168b_1_hw_jumbo_disable(tp);
+		}
 		break;
 	case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
-		r8168c_hw_jumbo_disable(tp);
+		if (jumbo) {
+			readrq = 512;
+			r8168c_hw_jumbo_enable(tp);
+		} else {
+			r8168c_hw_jumbo_disable(tp);
+		}
 		break;
 	case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
-		r8168dp_hw_jumbo_disable(tp);
+		if (jumbo)
+			r8168dp_hw_jumbo_enable(tp);
+		else
+			r8168dp_hw_jumbo_disable(tp);
 		break;
-	case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
-		r8168e_hw_jumbo_disable(tp);
+	case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
+		if (jumbo) {
+			pcie_set_readrq(tp->pci_dev, 512);
+			r8168e_hw_jumbo_enable(tp);
+		} else {
+			r8168e_hw_jumbo_disable(tp);
+		}
 		break;
 	default:
 		break;
 	}
 	rtl_lock_config_regs(tp);
-}
 
-static void rtl_jumbo_config(struct rtl8169_private *tp, int mtu)
-{
-	if (mtu > ETH_DATA_LEN)
-		rtl_hw_jumbo_enable(tp);
-	else
-		rtl_hw_jumbo_disable(tp);
+	if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii)
+		pcie_set_readrq(tp->pci_dev, readrq);
+
+	/* Chip doesn't support pause in jumbo mode */
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
+			 tp->phydev->advertising, !jumbo);
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+			 tp->phydev->advertising, !jumbo);
+	phy_start_aneg(tp->phydev);
 }
 
 DECLARE_RTL_COND(rtl_chipcmd_cond)
@@ -4229,7 +4187,7 @@
 		rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
 		break;
 	case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
-	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:
 		RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
 		rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
 		break;
@@ -4301,6 +4259,8 @@
 		/* Unconditionally log net taps. */
 		netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
 		rx_mode |= AcceptAllPhys;
+	} else if (!(dev->flags & IFF_MULTICAST)) {
+		rx_mode &= ~AcceptMulticast;
 	} else if (netdev_mc_count(dev) > MC_FILTER_LIMIT ||
 		   dev->flags & IFF_ALLMULTI ||
 		   tp->mac_version == RTL_GIGA_MAC_VER_35) {
@@ -4557,18 +4517,12 @@
 	rtl_set_def_aspm_entry_latency(tp);
 
 	rtl_disable_clock_request(tp);
-
-	if (tp->dev->mtu <= ETH_DATA_LEN)
-		rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
 }
 
 static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
 {
 	rtl_set_def_aspm_entry_latency(tp);
 
-	if (tp->dev->mtu <= ETH_DATA_LEN)
-		rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_disable_clock_request(tp);
 }
 
@@ -4583,8 +4537,6 @@
 
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_ephy_init(tp, e_info_8168d_4);
 
 	rtl_enable_clock_request(tp);
@@ -4659,8 +4611,6 @@
 {
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
 	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
 	rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06);
@@ -4687,7 +4637,7 @@
 		{ 0x08, 0x0001,	0x0002 },
 		{ 0x09, 0x0000,	0x0080 },
 		{ 0x19, 0x0000,	0x0224 },
-		{ 0x00, 0x0000,	0x0004 },
+		{ 0x00, 0x0000,	0x0008 },
 		{ 0x0c, 0x3df0,	0x0200 },
 	};
 
@@ -4704,7 +4654,7 @@
 		{ 0x06, 0x00c0,	0x0020 },
 		{ 0x0f, 0xffff,	0x5200 },
 		{ 0x19, 0x0000,	0x0224 },
-		{ 0x00, 0x0000,	0x0004 },
+		{ 0x00, 0x0000,	0x0008 },
 		{ 0x0c, 0x3df0,	0x0200 },
 	};
 
@@ -4723,8 +4673,6 @@
 
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_reset_packet_filter(tp);
 	rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f);
 
@@ -4739,6 +4687,7 @@
 	rtl_eri_clear_bits(tp, 0x1b0, ERIAR_MASK_0011, BIT(12));
 
 	rtl_pcie_state_l2l3_disable(tp);
+	rtl_hw_aspm_clkreq_enable(tp, true);
 }
 
 static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
@@ -4961,8 +4910,6 @@
 
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_reset_packet_filter(tp);
 
 	rtl_eri_set_bits(tp, 0xdc, ERIAR_MASK_1111, BIT(4));
@@ -5020,8 +4967,6 @@
 
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_reset_packet_filter(tp);
 
 	rtl_eri_set_bits(tp, 0xd4, ERIAR_MASK_1111, 0x1f80);
@@ -5106,6 +5051,71 @@
 	rtl_hw_aspm_clkreq_enable(tp, true);
 }
 
+static void rtl_hw_start_8117(struct rtl8169_private *tp)
+{
+	static const struct ephy_info e_info_8117[] = {
+		{ 0x19, 0x0040,	0x1100 },
+		{ 0x59, 0x0040,	0x1100 },
+	};
+	int rg_saw_cnt;
+
+	rtl8168ep_stop_cmac(tp);
+
+	/* disable aspm and clock request before access ephy */
+	rtl_hw_aspm_clkreq_enable(tp, false);
+	rtl_ephy_init(tp, e_info_8117);
+
+	rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06);
+	rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f);
+
+	rtl_set_def_aspm_entry_latency(tp);
+
+	rtl_reset_packet_filter(tp);
+
+	rtl_eri_set_bits(tp, 0xd4, ERIAR_MASK_1111, 0x1f90);
+
+	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
+
+	RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN);
+
+	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
+	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
+
+	rtl8168_config_eee_mac(tp);
+
+	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
+	RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN);
+
+	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN);
+
+	rtl_eri_clear_bits(tp, 0x1b0, ERIAR_MASK_0011, BIT(12));
+
+	rtl_pcie_state_l2l3_disable(tp);
+
+	rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff;
+	if (rg_saw_cnt > 0) {
+		u16 sw_cnt_1ms_ini;
+
+		sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff;
+		r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);
+	}
+
+	r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070);
+	r8168_mac_ocp_write(tp, 0xea80, 0x0003);
+	r8168_mac_ocp_modify(tp, 0xe052, 0x0000, 0x0009);
+	r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f);
+
+	r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
+	r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
+	r8168_mac_ocp_write(tp, 0xc094, 0x0000);
+	r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
+
+	/* firmware is for MAC only */
+	rtl_apply_firmware(tp);
+
+	rtl_hw_aspm_clkreq_enable(tp, true);
+}
+
 static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
 {
 	static const struct ephy_info e_info_8102e_1[] = {
@@ -5124,8 +5134,6 @@
 
 	RTL_W8(tp, DBG_REG, FIX_NAK_1);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	RTL_W8(tp, Config1,
 	       LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
@@ -5141,8 +5149,6 @@
 {
 	rtl_set_def_aspm_entry_latency(tp);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	RTL_W8(tp, Config1, MEMMAP | IOMAP | VPD | PMEnable);
 	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
 }
@@ -5203,8 +5209,6 @@
 
 	rtl_ephy_init(tp, e_info_8402);
 
-	rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
 	rtl_set_fifo_size(tp, 0x00, 0x00, 0x02, 0x06);
 	rtl_reset_packet_filter(tp);
 	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
@@ -5226,7 +5230,6 @@
 	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
 
 	rtl_pcie_state_l2l3_disable(tp);
-	rtl_hw_aspm_clkreq_enable(tp, true);
 }
 
 DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
@@ -5399,6 +5402,7 @@
 		[RTL_GIGA_MAC_VER_49] = rtl_hw_start_8168ep_1,
 		[RTL_GIGA_MAC_VER_50] = rtl_hw_start_8168ep_2,
 		[RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3,
+		[RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117,
 		[RTL_GIGA_MAC_VER_60] = rtl_hw_start_8125_1,
 		[RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125_2,
 	};
@@ -5420,10 +5424,18 @@
 
 static void rtl_hw_start_8168(struct rtl8169_private *tp)
 {
-	if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
-	    tp->mac_version == RTL_GIGA_MAC_VER_16)
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_11:
+	case RTL_GIGA_MAC_VER_12:
+	case RTL_GIGA_MAC_VER_13:
+	case RTL_GIGA_MAC_VER_16:
+	case RTL_GIGA_MAC_VER_17:
 		pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL,
 					 PCI_EXP_DEVCTL_NOSNOOP_EN);
+		break;
+	default:
+		break;
+	}
 
 	if (rtl_is_8168evl_up(tp))
 		RTL_W8(tp, MaxTxPacketSize, EarlySize);
@@ -5480,7 +5492,7 @@
 	rtl_set_rx_tx_desc_registers(tp);
 	rtl_lock_config_regs(tp);
 
-	rtl_jumbo_config(tp, tp->dev->mtu);
+	rtl_jumbo_config(tp);
 
 	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
 	RTL_R16(tp, CPlusCmd);
@@ -5495,10 +5507,13 @@
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
 
-	rtl_jumbo_config(tp, new_mtu);
-
 	dev->mtu = new_mtu;
 	netdev_update_features(dev);
+	rtl_jumbo_config(tp);
+
+	/* Reportedly at least Asus X453MA truncates packets otherwise */
+	if (tp->mac_version == RTL_GIGA_MAC_VER_37)
+		rtl_init_rxcfg(tp);
 
 	return 0;
 }
@@ -5828,7 +5843,8 @@
 		opts[1] |= transport_offset << TCPHO_SHIFT;
 	} else {
 		if (unlikely(rtl_test_hw_pad_bug(tp, skb)))
-			return !eth_skb_pad(skb);
+			/* eth_skb_pad would free the skb on error */
+			return !__skb_put_padto(skb, ETH_ZLEN, false);
 	}
 
 	return true;
@@ -6054,7 +6070,7 @@
 		struct ring_info *tx_skb = tp->tx_skb + entry;
 		u32 status;
 
-		status = le32_to_cpu(tp->TxDescArray[entry].opts1);
+		status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
 		if (status & DescOwn)
 			break;
 
@@ -6137,7 +6153,7 @@
 		struct RxDesc *desc = tp->RxDescArray + entry;
 		u32 status;
 
-		status = le32_to_cpu(desc->opts1);
+		status = le32_to_cpu(READ_ONCE(desc->opts1));
 		if (status & DescOwn)
 			break;
 
@@ -6242,12 +6258,11 @@
 	if (unlikely(status & RxFIFOOver &&
 	    tp->mac_version == RTL_GIGA_MAC_VER_11)) {
 		netif_stop_queue(tp->dev);
-		/* XXX - Hack alert. See rtl_task(). */
-		set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
+		rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
 	}
 
 	rtl_irq_disable(tp);
-	napi_schedule_irqoff(&tp->napi);
+	napi_schedule(&tp->napi);
 out:
 	rtl_ack_events(tp, status);
 
@@ -6317,12 +6332,17 @@
 static void r8169_phylink_handler(struct net_device *ndev)
 {
 	struct rtl8169_private *tp = netdev_priv(ndev);
+	struct device *d = tp_to_dev(tp);
 
 	if (netif_carrier_ok(ndev)) {
 		rtl_link_chg_patch(tp);
-		pm_request_resume(&tp->pci_dev->dev);
+		pm_request_resume(d);
+		netif_wake_queue(tp->dev);
 	} else {
-		pm_runtime_idle(&tp->pci_dev->dev);
+		/* In few cases rx is broken after link-down otherwise */
+		if (rtl_is_8125(tp))
+			rtl_reset_work(tp);
+		pm_runtime_idle(d);
 	}
 
 	if (net_ratelimit())
@@ -6346,8 +6366,6 @@
 	if (!tp->supports_gmii)
 		phy_set_max_speed(phydev, SPEED_100);
 
-	phy_support_asym_pause(phydev);
-
 	phy_attached_info(phydev);
 
 	return 0;
@@ -6399,9 +6417,9 @@
 
 	cancel_work_sync(&tp->wk.work);
 
-	phy_disconnect(tp->phydev);
+	free_irq(pci_irq_vector(pdev, 0), tp);
 
-	pci_free_irq(pdev, 0, tp);
+	phy_disconnect(tp->phydev);
 
 	dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
 			  tp->RxPhyAddr);
@@ -6452,8 +6470,8 @@
 
 	rtl_request_firmware(tp);
 
-	retval = pci_request_irq(pdev, 0, rtl8169_interrupt, NULL, tp,
-				 dev->name);
+	retval = request_irq(pci_irq_vector(pdev, 0), rtl8169_interrupt,
+			     IRQF_SHARED, dev->name, tp);
 	if (retval < 0)
 		goto err_release_fw_2;
 
@@ -6486,7 +6504,7 @@
 	return retval;
 
 err_free_irq:
-	pci_free_irq(pdev, 0, tp);
+	free_irq(pci_irq_vector(pdev, 0), tp);
 err_release_fw_2:
 	rtl_release_firmware(tp);
 	rtl8169_rx_clear(tp);
@@ -6800,7 +6818,7 @@
 		RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
 		rtl_lock_config_regs(tp);
 		/* fall through */
-	case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24:
+	case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17:
 		flags = PCI_IRQ_LEGACY;
 		break;
 	default:
@@ -6878,7 +6896,8 @@
 	new_bus->priv = tp;
 	new_bus->parent = &pdev->dev;
 	new_bus->irq[0] = PHY_IGNORE_INTERRUPT;
-	snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x", pci_dev_id(pdev));
+	snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x",
+		 pci_domain_nr(pdev->bus), pci_dev_id(pdev));
 
 	new_bus->read = r8169_mdio_read_reg;
 	new_bus->write = r8169_mdio_write_reg;
@@ -6891,6 +6910,13 @@
 	if (!tp->phydev) {
 		mdiobus_unregister(new_bus);
 		return -ENODEV;
+	} else if (!tp->phydev->drv) {
+		/* Most chip versions fail with the genphy driver.
+		 * Therefore ensure that the dedicated PHY driver is loaded.
+		 */
+		dev_err(&pdev->dev, "realtek.ko not loaded, maybe it needs to be added to initramfs?\n");
+		mdiobus_unregister(new_bus);
+		return -EUNATCH;
 	}
 
 	/* PHY will be woken up in rtl_open() */
@@ -6953,7 +6979,7 @@
 static void rtl_hw_initialize(struct rtl8169_private *tp)
 {
 	switch (tp->mac_version) {
-	case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_51:
+	case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52:
 		rtl8168ep_stop_cmac(tp);
 		/* fall through */
 	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
@@ -7063,6 +7089,7 @@
 	tp->pci_dev = pdev;
 	tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
 	tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
+	tp->eee_adv = -1;
 
 	/* Get the *optional* external "ether_clk" used on some boards */
 	rc = rtl_get_ether_clk(tp);
@@ -7072,8 +7099,7 @@
 	/* Disable ASPM completely as that cause random device stop working
 	 * problems as well as full system hangs for some PCIe devices users.
 	 */
-	rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
-					  PCIE_LINK_STATE_L1);
+	rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_1);
 	tp->aspm_manageable = !rc;
 
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
@@ -7147,12 +7173,10 @@
 
 	netif_napi_add(dev, &tp->napi, rtl8169_poll, NAPI_POLL_WEIGHT);
 
-	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
-		NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX |
-		NETIF_F_HW_VLAN_CTAG_RX;
-	dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
-		NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX |
-		NETIF_F_HW_VLAN_CTAG_RX;
+	dev->features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+			 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
+	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+			   NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
 	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
 		NETIF_F_HIGHDMA;
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
@@ -7170,25 +7194,25 @@
 		dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
 
 	if (rtl_chip_supports_csum_v2(tp)) {
-		dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
-		dev->features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+		dev->hw_features |= NETIF_F_IPV6_CSUM;
+		dev->features |= NETIF_F_IPV6_CSUM;
+	}
+
+	/* There has been a number of reports that using SG/TSO results in
+	 * tx timeouts. However for a lot of people SG/TSO works fine.
+	 * Therefore disable both features by default, but allow users to
+	 * enable them. Use at own risk!
+	 */
+	if (rtl_chip_supports_csum_v2(tp)) {
+		dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
 		dev->gso_max_size = RTL_GSO_MAX_SIZE_V2;
 		dev->gso_max_segs = RTL_GSO_MAX_SEGS_V2;
 	} else {
+		dev->hw_features |= NETIF_F_SG | NETIF_F_TSO;
 		dev->gso_max_size = RTL_GSO_MAX_SIZE_V1;
 		dev->gso_max_segs = RTL_GSO_MAX_SEGS_V1;
 	}
 
-	/* RTL8168e-vl and one RTL8168c variant are known to have a
-	 * HW issue with TSO.
-	 */
-	if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
-	    tp->mac_version == RTL_GIGA_MAC_VER_22) {
-		dev->vlan_features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG);
-		dev->hw_features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG);
-		dev->features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG);
-	}
-
 	dev->hw_features |= NETIF_F_RXALL;
 	dev->hw_features |= NETIF_F_RXFCS;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/renesas/ravb_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/renesas/ravb_main.c
@@ -736,14 +736,14 @@
 	ravb_write(ndev, ~(EIS_QFS | EIS_RESERVED), EIS);
 	if (eis & EIS_QFS) {
 		ris2 = ravb_read(ndev, RIS2);
-		ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF | RIS2_RESERVED),
+		ravb_write(ndev, ~(RIS2_QFF0 | RIS2_QFF1 | RIS2_RFFF | RIS2_RESERVED),
 			   RIS2);
 
 		/* Receive Descriptor Empty int */
 		if (ris2 & RIS2_QFF0)
 			priv->stats[RAVB_BE].rx_over_errors++;
 
-		    /* Receive Descriptor Empty int */
+		/* Receive Descriptor Empty int */
 		if (ris2 & RIS2_QFF1)
 			priv->stats[RAVB_NC].rx_over_errors++;
 
@@ -911,31 +911,20 @@
 	int q = napi - priv->napi;
 	int mask = BIT(q);
 	int quota = budget;
-	u32 ris0, tis;
 
-	for (;;) {
-		tis = ravb_read(ndev, TIS);
-		ris0 = ravb_read(ndev, RIS0);
-		if (!((ris0 & mask) || (tis & mask)))
-			break;
-
-		/* Processing RX Descriptor Ring */
-		if (ris0 & mask) {
-			/* Clear RX interrupt */
-			ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0);
-			if (ravb_rx(ndev, &quota, q))
-				goto out;
-		}
-		/* Processing TX Descriptor Ring */
-		if (tis & mask) {
-			spin_lock_irqsave(&priv->lock, flags);
-			/* Clear TX interrupt */
-			ravb_write(ndev, ~(mask | TIS_RESERVED), TIS);
-			ravb_tx_free(ndev, q, true);
-			netif_wake_subqueue(ndev, q);
-			spin_unlock_irqrestore(&priv->lock, flags);
-		}
-	}
+	/* Processing RX Descriptor Ring */
+	/* Clear RX interrupt */
+	ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0);
+	if (ravb_rx(ndev, &quota, q))
+		goto out;
+
+	/* Processing RX Descriptor Ring */
+	spin_lock_irqsave(&priv->lock, flags);
+	/* Clear TX interrupt */
+	ravb_write(ndev, ~(mask | TIS_RESERVED), TIS);
+	ravb_tx_free(ndev, q, true);
+	netif_wake_subqueue(ndev, q);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	napi_complete(napi);
 
@@ -1391,13 +1380,13 @@
 	if (priv->chip_id == RCAR_GEN2)
 		ravb_ptp_init(ndev, priv->pdev);
 
-	netif_tx_start_all_queues(ndev);
-
 	/* PHY control start */
 	error = ravb_phy_start(ndev);
 	if (error)
 		goto out_ptp_stop;
 
+	netif_tx_start_all_queues(ndev);
+
 	return 0;
 
 out_ptp_stop:
@@ -1444,6 +1433,13 @@
 	struct ravb_private *priv = container_of(work, struct ravb_private,
 						 work);
 	struct net_device *ndev = priv->ndev;
+	int error;
+
+	if (!rtnl_trylock()) {
+		usleep_range(1000, 2000);
+		schedule_work(&priv->work);
+		return;
+	}
 
 	netif_tx_stop_all_queues(ndev);
 
@@ -1452,20 +1448,44 @@
 		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);
+		goto out_unlock;
+	}
 	ravb_emac_init(ndev);
 
+out:
 	/* Initialise PTP Clock driver */
 	if (priv->chip_id == RCAR_GEN2)
 		ravb_ptp_init(ndev, priv->pdev);
 
 	netif_tx_start_all_queues(ndev);
+
+out_unlock:
+	rtnl_unlock();
 }
 
 /* Packet transmit function for Ethernet AVB */
@@ -1477,7 +1497,7 @@
 	struct ravb_tstamp_skb *ts_skb;
 	struct ravb_tx_desc *desc;
 	unsigned long flags;
-	u32 dma_addr;
+	dma_addr_t dma_addr;
 	void *buffer;
 	u32 entry;
 	u32 len;
@@ -1692,6 +1712,8 @@
 			of_phy_deregister_fixed_link(np);
 	}
 
+	cancel_work_sync(&priv->work);
+
 	if (priv->chip_id != RCAR_GEN2) {
 		free_irq(priv->tx_irqs[RAVB_NC], ndev);
 		free_irq(priv->rx_irqs[RAVB_NC], ndev);
@@ -1719,12 +1741,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;
@@ -2013,7 +2039,9 @@
 	ndev->hw_features = NETIF_F_RXCSUM;
 
 	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
+	error = pm_runtime_resume_and_get(&pdev->dev);
+	if (error < 0)
+		goto out_rpm_disable;
 
 	/* The Ether-specific entries in the device structure. */
 	ndev->base_addr = res->start;
@@ -2184,6 +2212,7 @@
 	free_netdev(ndev);
 
 	pm_runtime_put(&pdev->dev);
+out_rpm_disable:
 	pm_runtime_disable(&pdev->dev);
 	return error;
 }
@@ -2197,15 +2226,15 @@
 	if (priv->chip_id != RCAR_GEN2)
 		ravb_ptp_stop(ndev);
 
-	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
-			  priv->desc_bat_dma);
 	/* Set reset mode */
 	ravb_write(ndev, CCC_OPC_RESET, CCC);
-	pm_runtime_put_sync(&pdev->dev);
 	unregister_netdev(ndev);
 	netif_napi_del(&priv->napi[RAVB_NC]);
 	netif_napi_del(&priv->napi[RAVB_BE]);
 	ravb_mdio_release(priv);
+	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
+			  priv->desc_bat_dma);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	free_netdev(ndev);
 	platform_set_drvdata(pdev, NULL);
@@ -2312,6 +2341,7 @@
 		ret = ravb_open(ndev);
 		if (ret < 0)
 			return ret;
+		ravb_set_rx_mode(ndev);
 		netif_device_attach(ndev);
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/renesas/sh_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/renesas/sh_eth.c
@@ -610,6 +610,8 @@
 			  EESR_TDE,
 	.fdr_value	= 0x0000070f,
 
+	.trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
+
 	.no_psr		= 1,
 	.apr		= 1,
 	.mpr		= 1,
@@ -828,6 +830,8 @@
 
 	.fdr_value	= 0x0000070f,
 
+	.trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
+
 	.apr		= 1,
 	.mpr		= 1,
 	.tpauser	= 1,
@@ -1131,6 +1135,9 @@
 			  EESIPR_CEEFIP | EESIPR_CELFIP |
 			  EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
 			  EESIPR_PREIP | EESIPR_CERFIP,
+
+	.trscer_err_mask = DESC_I_RINT8,
+
 	.tsu		= 1,
 	.dual_port	= 1,
 };
@@ -2204,24 +2211,28 @@
 	if (cd->tsu) {
 		add_tsu_reg(ARSTR);
 		add_tsu_reg(TSU_CTRST);
-		add_tsu_reg(TSU_FWEN0);
-		add_tsu_reg(TSU_FWEN1);
-		add_tsu_reg(TSU_FCM);
-		add_tsu_reg(TSU_BSYSL0);
-		add_tsu_reg(TSU_BSYSL1);
-		add_tsu_reg(TSU_PRISL0);
-		add_tsu_reg(TSU_PRISL1);
-		add_tsu_reg(TSU_FWSL0);
-		add_tsu_reg(TSU_FWSL1);
+		if (cd->dual_port) {
+			add_tsu_reg(TSU_FWEN0);
+			add_tsu_reg(TSU_FWEN1);
+			add_tsu_reg(TSU_FCM);
+			add_tsu_reg(TSU_BSYSL0);
+			add_tsu_reg(TSU_BSYSL1);
+			add_tsu_reg(TSU_PRISL0);
+			add_tsu_reg(TSU_PRISL1);
+			add_tsu_reg(TSU_FWSL0);
+			add_tsu_reg(TSU_FWSL1);
+		}
 		add_tsu_reg(TSU_FWSLC);
-		add_tsu_reg(TSU_QTAGM0);
-		add_tsu_reg(TSU_QTAGM1);
-		add_tsu_reg(TSU_FWSR);
-		add_tsu_reg(TSU_FWINMK);
-		add_tsu_reg(TSU_ADQT0);
-		add_tsu_reg(TSU_ADQT1);
-		add_tsu_reg(TSU_VTAG0);
-		add_tsu_reg(TSU_VTAG1);
+		if (cd->dual_port) {
+			add_tsu_reg(TSU_QTAGM0);
+			add_tsu_reg(TSU_QTAGM1);
+			add_tsu_reg(TSU_FWSR);
+			add_tsu_reg(TSU_FWINMK);
+			add_tsu_reg(TSU_ADQT0);
+			add_tsu_reg(TSU_ADQT1);
+			add_tsu_reg(TSU_VTAG0);
+			add_tsu_reg(TSU_VTAG1);
+		}
 		add_tsu_reg(TSU_ADSBSY);
 		add_tsu_reg(TSU_TEN);
 		add_tsu_reg(TSU_POST1);
@@ -2311,7 +2322,7 @@
 {
 	switch (stringset) {
 	case ETH_SS_STATS:
-		memcpy(data, *sh_eth_gstrings_stats,
+		memcpy(data, sh_eth_gstrings_stats,
 		       sizeof(sh_eth_gstrings_stats));
 		break;
 	}
@@ -2556,6 +2567,7 @@
 	else
 		txdesc->status |= cpu_to_le32(TD_TACT);
 
+	wmb(); /* cur_tx must be incremented after TACT bit was set */
 	mdp->cur_tx++;
 
 	if (!(sh_eth_read(ndev, EDTRR) & mdp->cd->edtrr_trns))
@@ -2636,10 +2648,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;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/rocker/rocker_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/rocker/rocker_main.c
@@ -647,10 +647,10 @@
 err_dma_event_ring_bufs_alloc:
 	rocker_dma_ring_destroy(rocker, &rocker->event_ring);
 err_dma_event_ring_create:
+	rocker_dma_cmd_ring_waits_free(rocker);
+err_dma_cmd_ring_waits_alloc:
 	rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,
 				  PCI_DMA_BIDIRECTIONAL);
-err_dma_cmd_ring_waits_alloc:
-	rocker_dma_cmd_ring_waits_free(rocker);
 err_dma_cmd_ring_bufs_alloc:
 	rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/rocker/rocker_ofdpa.c
+++ linux-ein-5.4.0/drivers/net/ethernet/rocker/rocker_ofdpa.c
@@ -1273,7 +1273,7 @@
 	bool removing;
 	int err = 0;
 
-	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (!entry)
 		return -ENOMEM;
 
@@ -2795,7 +2795,8 @@
 		if (!ofdpa_port)
 			continue;
 		nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
-		ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
+		ofdpa_flow_tbl_del(ofdpa_port,
+				   OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT,
 				   flow_entry);
 	}
 	spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -2277,18 +2277,18 @@
 	char *opt;
 
 	if (!str || !*str)
-		return -EINVAL;
+		return 1;
 	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;
 		}
 	}
-	return 0;
+	return 1;
 
 err:
 	pr_err("%s: ERROR broken module parameter conversion\n", __func__);
-	return -EINVAL;
+	return 1;
 }
 
 __setup("sxgbeeth=", sxgbe_cmdline_opt);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/ef10.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/ef10.c
@@ -2056,7 +2056,10 @@
 
 	efx_update_sw_stats(efx, stats);
 out:
+	/* releasing a DMA coherent buffer with BH disabled can panic */
+	spin_unlock_bh(&efx->stats_lock);
 	efx_nic_free_buffer(efx, &stats_buf);
+	spin_lock_bh(&efx->stats_lock);
 	return rc;
 }
 
@@ -6160,6 +6163,11 @@
 		n_parts++;
 	}
 
+	if (!n_parts) {
+		kfree(parts);
+		return 0;
+	}
+
 	rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts));
 fail:
 	if (rc)
@@ -6593,6 +6601,30 @@
 	return rc;
 }
 
+static unsigned int efx_ef10_recycle_ring_size(const struct efx_nic *efx)
+{
+	unsigned int ret = EFX_RECYCLE_RING_SIZE_10G;
+
+	/* There is no difference between PFs and VFs. The side is based on
+	 * the maximum link speed of a given NIC.
+	 */
+	switch (efx->pci_dev->device & 0xfff) {
+	case 0x0903:	/* Farmingdale can do up to 10G */
+		break;
+	case 0x0923:	/* Greenport can do up to 40G */
+	case 0x0a03:	/* Medford can do up to 40G */
+		ret *= 4;
+		break;
+	default:	/* Medford2 can do up to 100G */
+		ret *= 10;
+	}
+
+	if (IS_ENABLED(CONFIG_PPC64))
+		ret *= 4;
+
+	return ret;
+}
+
 #define EF10_OFFLOAD_FEATURES		\
 	(NETIF_F_IP_CSUM |		\
 	 NETIF_F_HW_VLAN_CTAG_FILTER |	\
@@ -6705,6 +6737,7 @@
 	.hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
 			    1 << HWTSTAMP_FILTER_ALL,
 	.rx_hash_key_size = 40,
+	.rx_recycle_ring_size = efx_ef10_recycle_ring_size,
 };
 
 const struct efx_nic_type efx_hunt_a0_nic_type = {
@@ -6840,4 +6873,5 @@
 	.hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
 			    1 << HWTSTAMP_FILTER_ALL,
 	.rx_hash_key_size = 40,
+	.rx_recycle_ring_size = efx_ef10_recycle_ring_size,
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/ef10_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -403,12 +403,18 @@
 	return rc;
 }
 
+/* Disable SRIOV and remove VFs
+ * If some VFs are attached to a guest (using Xen, only) nothing is
+ * done if force=false, and vports are freed if force=true (for the non
+ * attachedc ones, only) but SRIOV is not disabled and VFs are not
+ * removed in either case.
+ */
 static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
 {
 	struct pci_dev *dev = efx->pci_dev;
-	unsigned int vfs_assigned = 0;
-
-	vfs_assigned = pci_vfs_assigned(dev);
+	struct efx_ef10_nic_data *nic_data = efx->nic_data;
+	unsigned int vfs_assigned = pci_vfs_assigned(dev);
+	int i, rc = 0;
 
 	if (vfs_assigned && !force) {
 		netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
@@ -416,12 +422,17 @@
 		return -EBUSY;
 	}
 
-	if (!vfs_assigned)
+	if (!vfs_assigned) {
+		for (i = 0; i < efx->vf_count; i++)
+			nic_data->vf[i].pci_dev = NULL;
 		pci_disable_sriov(dev);
+	} else {
+		rc = -EBUSY;
+	}
 
 	efx_ef10_sriov_free_vf_vswitching(efx);
 	efx->vf_count = 0;
-	return 0;
+	return rc;
 }
 
 int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
@@ -440,7 +451,6 @@
 void efx_ef10_sriov_fini(struct efx_nic *efx)
 {
 	struct efx_ef10_nic_data *nic_data = efx->nic_data;
-	unsigned int i;
 	int rc;
 
 	if (!nic_data->vf) {
@@ -450,14 +460,7 @@
 		return;
 	}
 
-	/* Remove any VFs in the host */
-	for (i = 0; i < efx->vf_count; ++i) {
-		struct efx_nic *vf_efx = nic_data->vf[i].efx;
-
-		if (vf_efx)
-			vf_efx->pci_dev->driver->remove(vf_efx->pci_dev);
-	}
-
+	/* Disable SRIOV and remove any VFs in the host */
 	rc = efx_ef10_pci_sriov_disable(efx, true);
 	if (rc)
 		netif_dbg(efx, drv, efx->net_dev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/efx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/efx.c
@@ -519,6 +519,7 @@
 		if (tx_queue->channel)
 			tx_queue->channel = channel;
 		tx_queue->buffer = NULL;
+		tx_queue->cb_page = NULL;
 		memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/efx.h
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/efx.h
@@ -57,6 +57,12 @@
 #define EFX_MAX_EVQ_SIZE 16384UL
 #define EFX_MIN_EVQ_SIZE 512UL
 
+/* Number of RX buffers to recycle pages for.  When creating the RX page recycle
+ * ring, this number is divided by the number of buffers per page to calculate
+ * the number of pages to store in the RX page recycle ring.
+ */
+#define EFX_RECYCLE_RING_SIZE_10G	256
+
 /* Maximum number of TCP segments we support for soft-TSO */
 #define EFX_TSO_MAX_SEGS	100
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/ethtool.c
@@ -128,20 +128,14 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_link_state *link_state = &efx->link_state;
-	u32 supported;
 
 	mutex_lock(&efx->mac_lock);
 	efx->phy_op->get_link_ksettings(efx, cmd);
 	mutex_unlock(&efx->mac_lock);
 
 	/* Both MACs support pause frames (bidirectional and respond-only) */
-	ethtool_convert_link_mode_to_legacy_u32(&supported,
-						cmd->link_modes.supported);
-
-	supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-
-	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-						supported);
+	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
+	ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);
 
 	if (LOOPBACK_INTERNAL(efx)) {
 		cmd->base.speed = link_state->speed;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/falcon/farch.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/falcon/farch.c
@@ -870,17 +870,12 @@
 {
 	struct ef4_channel *channel = ef4_rx_queue_channel(rx_queue);
 	struct ef4_nic *efx = rx_queue->efx;
-	bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+	bool __maybe_unused rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
 	bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
 	bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
-	bool rx_ev_other_err, rx_ev_pause_frm;
-	bool rx_ev_hdr_type, rx_ev_mcast_pkt;
-	unsigned rx_ev_pkt_type;
+	bool rx_ev_pause_frm;
 
-	rx_ev_hdr_type = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
-	rx_ev_mcast_pkt = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT);
 	rx_ev_tobe_disc = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC);
-	rx_ev_pkt_type = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE);
 	rx_ev_buf_owner_id_err = EF4_QWORD_FIELD(*event,
 						 FSF_AZ_RX_EV_BUF_OWNER_ID_ERR);
 	rx_ev_ip_hdr_chksum_err = EF4_QWORD_FIELD(*event,
@@ -893,10 +888,6 @@
 			  0 : EF4_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB));
 	rx_ev_pause_frm = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR);
 
-	/* Every error apart from tobe_disc and pause_frm */
-	rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
-			   rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
-			   rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
 
 	/* Count errors that are not in MAC stats.  Ignore expected
 	 * checksum errors during self-test. */
@@ -916,6 +907,13 @@
 	 * to a FIFO overflow.
 	 */
 #ifdef DEBUG
+	{
+	/* Every error apart from tobe_disc and pause_frm */
+
+	bool rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
+				rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
+				rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
+
 	if (rx_ev_other_err && net_ratelimit()) {
 		netif_dbg(efx, rx_err, efx->net_dev,
 			  " RX queue %d unexpected RX event "
@@ -932,6 +930,7 @@
 			  rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
 			  rx_ev_pause_frm ? " [PAUSE]" : "");
 	}
+	}
 #endif
 
 	/* The frame must be discarded if any of these are true. */
@@ -1643,15 +1642,11 @@
  */
 void ef4_farch_dimension_resources(struct ef4_nic *efx, unsigned sram_lim_qw)
 {
-	unsigned vi_count, buftbl_min;
+	unsigned vi_count;
 
 	/* Account for the buffer table entries backing the datapath channels
 	 * and the descriptor caches for those channels.
 	 */
-	buftbl_min = ((efx->n_rx_channels * EF4_MAX_DMAQ_SIZE +
-		       efx->n_tx_channels * EF4_TXQ_TYPES * EF4_MAX_DMAQ_SIZE +
-		       efx->n_channels * EF4_MAX_EVQ_SIZE)
-		      * sizeof(ef4_qword_t) / EF4_BUF_SIZE);
 	vi_count = max(efx->n_channels, efx->n_tx_channels * EF4_TXQ_TYPES);
 
 	efx->tx_dc_base = sram_lim_qw - vi_count * TX_DC_ENTRIES;
@@ -2532,7 +2527,6 @@
 	enum ef4_farch_filter_table_id table_id;
 	struct ef4_farch_filter_table *table;
 	unsigned int filter_idx;
-	struct ef4_farch_filter_spec *spec;
 	int rc;
 
 	table_id = ef4_farch_filter_id_table_id(filter_id);
@@ -2543,7 +2537,6 @@
 	filter_idx = ef4_farch_filter_id_index(filter_id);
 	if (filter_idx >= table->size)
 		return -ENOENT;
-	spec = &table->spec[filter_idx];
 
 	spin_lock_bh(&efx->filter_lock);
 	rc = ef4_farch_filter_remove(efx, table, filter_idx, priority);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/falcon/rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/falcon/rx.c
@@ -726,7 +726,10 @@
 					    efx->rx_bufs_per_page);
 	rx_queue->page_ring = kcalloc(page_ring_size,
 				      sizeof(*rx_queue->page_ring), GFP_KERNEL);
-	rx_queue->page_ptr_mask = page_ring_size - 1;
+	if (!rx_queue->page_ring)
+		rx_queue->page_ptr_mask = 0;
+	else
+		rx_queue->page_ptr_mask = page_ring_size - 1;
 }
 
 void ef4_init_rx_queue(struct ef4_rx_queue *rx_queue)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/mcdi.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/mcdi.c
@@ -163,9 +163,9 @@
 	/* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
 	spin_lock_bh(&mcdi->iface_lock);
 	++mcdi->seqno;
+	seqno = mcdi->seqno & SEQ_MASK;
 	spin_unlock_bh(&mcdi->iface_lock);
 
-	seqno = mcdi->seqno & SEQ_MASK;
 	xflags = 0;
 	if (mcdi->mode == MCDI_MODE_EVENTS)
 		xflags |= MCDI_HEADER_XFLAGS_EVREQ;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/net_driver.h
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/net_driver.h
@@ -1243,6 +1243,7 @@
  * @udp_tnl_add_port: Add a UDP tunnel port
  * @udp_tnl_has_port: Check if a port has been added as UDP tunnel
  * @udp_tnl_del_port: Remove a UDP tunnel port
+ * @rx_recycle_ring_size: Size of the RX recycle ring
  * @revision: Hardware architecture revision
  * @txd_ptr_tbl_base: TX descriptor ring base address
  * @rxd_ptr_tbl_base: RX descriptor ring base address
@@ -1413,6 +1414,7 @@
 	int (*udp_tnl_add_port)(struct efx_nic *efx, struct efx_udp_tunnel tnl);
 	bool (*udp_tnl_has_port)(struct efx_nic *efx, __be16 port);
 	int (*udp_tnl_del_port)(struct efx_nic *efx, struct efx_udp_tunnel tnl);
+	unsigned int (*rx_recycle_ring_size)(const struct efx_nic *efx);
 
 	int revision;
 	unsigned int txd_ptr_tbl_base;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/nic.h
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/nic.h
@@ -607,6 +607,11 @@
 
 bool efx_nic_event_present(struct efx_channel *channel);
 
+static inline unsigned int efx_rx_recycle_ring_size(const struct efx_nic *efx)
+{
+	return efx->type->rx_recycle_ring_size(efx);
+}
+
 /* Some statistics are computed as A - B where A and B each increase
  * linearly with some hardware counter(s) and the counters are read
  * asynchronously.  If the counters contributing to B are always read
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/ptp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/ptp.c
@@ -560,13 +560,45 @@
 				    u32 nic_major, u32 nic_minor,
 				    s32 correction)
 {
+	u32 sync_timestamp;
 	ktime_t kt = { 0 };
+	s16 delta;
 
 	if (!(nic_major & 0x80000000)) {
 		WARN_ON_ONCE(nic_major >> 16);
-		/* Use the top bits from the latest sync event. */
-		nic_major &= 0xffff;
-		nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
+
+		/* Medford provides 48 bits of timestamp, so we must get the top
+		 * 16 bits from the timesync event state.
+		 *
+		 * We only have the lower 16 bits of the time now, but we do
+		 * have a full resolution timestamp at some point in past. As
+		 * long as the difference between the (real) now and the sync
+		 * is less than 2^15, then we can reconstruct the difference
+		 * between those two numbers using only the lower 16 bits of
+		 * each.
+		 *
+		 * Put another way
+		 *
+		 * a - b = ((a mod k) - b) mod k
+		 *
+		 * when -k/2 < (a-b) < k/2. In our case k is 2^16. We know
+		 * (a mod k) and b, so can calculate the delta, a - b.
+		 *
+		 */
+		sync_timestamp = last_sync_timestamp_major(efx);
+
+		/* Because delta is s16 this does an implicit mask down to
+		 * 16 bits which is what we need, assuming
+		 * MEDFORD_TX_SECS_EVENT_BITS is 16. delta is signed so that
+		 * we can deal with the (unlikely) case of sync timestamps
+		 * arriving from the future.
+		 */
+		delta = nic_major - sync_timestamp;
+
+		/* Recover the fully specified time now, by applying the offset
+		 * to the (fully specified) sync time.
+		 */
+		nic_major = sync_timestamp + delta;
 
 		kt = ptp->nic_to_kernel_time(nic_major, nic_minor,
 					     correction);
@@ -616,7 +648,7 @@
 	} else if (rc == -EINVAL) {
 		fmt = MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS;
 	} else if (rc == -EPERM) {
-		netif_info(efx, probe, efx->net_dev, "no PTP support\n");
+		pci_info(efx->pci_dev, "no PTP support\n");
 		return rc;
 	} else {
 		efx_mcdi_display_error(efx, MC_CMD_PTP, sizeof(inbuf),
@@ -792,7 +824,7 @@
 	 * should only have been called during probe.
 	 */
 	if (rc == -ENOSYS || rc == -EPERM)
-		netif_info(efx, probe, efx->net_dev, "no PTP support\n");
+		pci_info(efx->pci_dev, "no PTP support\n");
 	else if (rc)
 		efx_mcdi_display_error(efx, MC_CMD_PTP,
 				       MC_CMD_PTP_IN_DISABLE_LEN,
@@ -1061,7 +1093,29 @@
 
 	tx_queue = &ptp_data->channel->tx_queue[type];
 	if (tx_queue && tx_queue->timestamping) {
+		/* This code invokes normal driver TX code which is always
+		 * protected from softirqs when called from generic TX code,
+		 * which in turn disables preemption. Look at __dev_queue_xmit
+		 * which uses rcu_read_lock_bh disabling preemption for RCU
+		 * plus disabling softirqs. We do not need RCU reader
+		 * protection here.
+		 *
+		 * Although it is theoretically safe for current PTP TX/RX code
+		 * running without disabling softirqs, there are three good
+		 * reasond for doing so:
+		 *
+		 *      1) The code invoked is mainly implemented for non-PTP
+		 *         packets and it is always executed with softirqs
+		 *         disabled.
+		 *      2) This being a single PTP packet, better to not
+		 *         interrupt its processing by softirqs which can lead
+		 *         to high latencies.
+		 *      3) netdev_xmit_more checks preemption is disabled and
+		 *         triggers a BUG_ON if not.
+		 */
+		local_bh_disable();
 		efx_enqueue_skb(tx_queue, skb);
+		local_bh_enable();
 	} else {
 		WARN_ONCE(1, "PTP channel has no timestamped tx queue\n");
 		dev_kfree_skb_any(skb);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/rx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/rx.c
@@ -27,13 +27,6 @@
 /* Preferred number of descriptors to fill at once */
 #define EFX_RX_PREFERRED_BATCH 8U
 
-/* Number of RX buffers to recycle pages for.  When creating the RX page recycle
- * ring, this number is divided by the number of buffers per page to calculate
- * the number of pages to store in the RX page recycle ring.
- */
-#define EFX_RECYCLE_RING_SIZE_IOMMU 4096
-#define EFX_RECYCLE_RING_SIZE_NOIOMMU (2 * EFX_RX_PREFERRED_BATCH)
-
 /* Size of buffer allocated for skb header area. */
 #define EFX_SKB_HEADERS  128u
 
@@ -710,16 +703,7 @@
 {
 	unsigned int bufs_in_recycle_ring, page_ring_size;
 
-	/* Set the RX recycle ring size */
-#ifdef CONFIG_PPC64
-	bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_IOMMU;
-#else
-	if (iommu_present(&pci_bus_type))
-		bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_IOMMU;
-	else
-		bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_NOIOMMU;
-#endif /* CONFIG_PPC64 */
-
+	bufs_in_recycle_ring = efx_rx_recycle_ring_size(efx);
 	page_ring_size = roundup_pow_of_two(bufs_in_recycle_ring /
 					    efx->rx_bufs_per_page);
 	rx_queue->page_ring = kcalloc(page_ring_size,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/siena.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/siena.c
@@ -946,6 +946,12 @@
 
 #endif /* CONFIG_SFC_MTD */
 
+static unsigned int efx_siena_recycle_ring_size(const struct efx_nic *efx)
+{
+	/* Maximum link speed is 10G */
+	return EFX_RECYCLE_RING_SIZE_10G;
+}
+
 /**************************************************************************
  *
  * Revision-dependent attributes used by efx.c and nic.c
@@ -1084,4 +1090,5 @@
 			     1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT |
 			     1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT),
 	.rx_hash_key_size = 16,
+	.rx_recycle_ring_size = efx_siena_recycle_ring_size,
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sfc/siena_sriov.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sfc/siena_sriov.c
@@ -1056,7 +1056,7 @@
 		return;
 
 	if (efx_siena_sriov_cmd(efx, false, &efx->vi_scale, &count)) {
-		netif_info(efx, probe, efx->net_dev, "no SR-IOV VFs probed\n");
+		pci_info(efx->pci_dev, "no SR-IOV VFs probed\n");
 		return;
 	}
 	if (count > 0 && count > max_vfs)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sis/sis900.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sis/sis900.c
@@ -443,7 +443,7 @@
 #endif
 
 	/* setup various bits in PCI command register */
-	ret = pci_enable_device(pci_dev);
+	ret = pcim_enable_device(pci_dev);
 	if(ret) return ret;
 
 	i = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
@@ -469,7 +469,7 @@
 	ioaddr = pci_iomap(pci_dev, 0, 0);
 	if (!ioaddr) {
 		ret = -ENOMEM;
-		goto err_out_cleardev;
+		goto err_out;
 	}
 
 	sis_priv = netdev_priv(net_dev);
@@ -579,8 +579,6 @@
 		sis_priv->tx_ring_dma);
 err_out_unmap:
 	pci_iounmap(pci_dev, ioaddr);
-err_out_cleardev:
-	pci_release_regions(pci_dev);
  err_out:
 	free_netdev(net_dev);
 	return ret;
@@ -787,10 +785,9 @@
 static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *phy)
 {
 	u16 cap;
-	u16 status;
 
-	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
-	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+	mdio_read(net_dev, phy->phy_addr, MII_STATUS);
+	mdio_read(net_dev, phy->phy_addr, MII_STATUS);
 
 	cap = MII_NWAY_CSMA_CD |
 		((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) |
@@ -2490,7 +2487,6 @@
 		sis_priv->tx_ring_dma);
 	pci_iounmap(pci_dev, sis_priv->ioaddr);
 	free_netdev(net_dev);
-	pci_release_regions(pci_dev);
 }
 
 #ifdef CONFIG_PM
--- linux-ein-5.4.0.orig/drivers/net/ethernet/smsc/smc911x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/smsc/smc911x.c
@@ -936,7 +936,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 */
@@ -2069,6 +2069,11 @@
 
 	ndev->dma = (unsigned char)-1;
 	ndev->irq = platform_get_irq(pdev, 0);
+	if (ndev->irq < 0) {
+		ret = ndev->irq;
+		goto release_both;
+	}
+
 	lp = netdev_priv(ndev);
 	lp->netdev = ndev;
 #ifdef SMC_DYNAMIC_BUS_CONFIG
--- linux-ein-5.4.0.orig/drivers/net/ethernet/smsc/smc91x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/smsc/smc91x.c
@@ -2274,7 +2274,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
@@ -2283,7 +2283,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-ein-5.4.0.orig/drivers/net/ethernet/smsc/smsc911x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/smsc/smsc911x.c
@@ -2433,7 +2433,7 @@
 	if (irq == -EPROBE_DEFER) {
 		retval = -EPROBE_DEFER;
 		goto out_0;
-	} else if (irq <= 0) {
+	} else if (irq < 0) {
 		pr_warn("Could not allocate irq resource\n");
 		retval = -ENODEV;
 		goto out_0;
@@ -2502,20 +2502,20 @@
 
 	retval = smsc911x_init(dev);
 	if (retval < 0)
-		goto out_disable_resources;
+		goto out_init_fail;
 
 	netif_carrier_off(dev);
 
 	retval = smsc911x_mii_init(pdev, dev);
 	if (retval) {
 		SMSC_WARN(pdata, probe, "Error %i initialising mii", retval);
-		goto out_disable_resources;
+		goto out_init_fail;
 	}
 
 	retval = register_netdev(dev);
 	if (retval) {
 		SMSC_WARN(pdata, probe, "Error %i registering device", retval);
-		goto out_disable_resources;
+		goto out_init_fail;
 	} else {
 		SMSC_TRACE(pdata, probe,
 			   "Network interface: \"%s\"", dev->name);
@@ -2556,9 +2556,10 @@
 
 	return 0;
 
-out_disable_resources:
+out_init_fail:
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+out_disable_resources:
 	(void)smsc911x_disable_resources(pdev);
 out_enable_resources_fail:
 	smsc911x_free_resources(pdev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/socionext/netsec.c
+++ linux-ein-5.4.0/drivers/net/ethernet/socionext/netsec.c
@@ -847,8 +847,8 @@
 		enum dma_data_direction dma_dir =
 			page_pool_get_dma_dir(rx_ring->page_pool);
 
-		dma_handle = page_pool_get_dma_addr(page) +
-			NETSEC_RXBUF_HEADROOM;
+		dma_handle = page_pool_get_dma_addr(page) + xdpf->headroom +
+			sizeof(*xdpf);
 		dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len,
 					   dma_dir);
 		tx_desc.buf_type = TYPE_NETSEC_XDP_TX;
@@ -928,7 +928,6 @@
 	struct netsec_rx_pkt_info rx_info;
 	enum dma_data_direction dma_dir;
 	struct bpf_prog *xdp_prog;
-	struct sk_buff *skb = NULL;
 	u16 xdp_xmit = 0;
 	u32 xdp_act = 0;
 	int done = 0;
@@ -942,7 +941,8 @@
 		struct netsec_de *de = dring->vaddr + (DESC_SZ * idx);
 		struct netsec_desc *desc = &dring->desc[idx];
 		struct page *page = virt_to_page(desc->addr);
-		u32 xdp_result = XDP_PASS;
+		u32 xdp_result = NETSEC_XDP_PASS;
+		struct sk_buff *skb = NULL;
 		u16 pkt_len, desc_len;
 		dma_addr_t dma_handle;
 		struct xdp_buff xdp;
@@ -1693,14 +1693,17 @@
 		goto err1;
 
 	/* set phy power down */
-	data = netsec_phy_read(priv->mii_bus, priv->phy_addr, MII_BMCR) |
-		BMCR_PDOWN;
-	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR, data);
+	data = netsec_phy_read(priv->mii_bus, priv->phy_addr, MII_BMCR);
+	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR,
+			 data | BMCR_PDOWN);
 
 	ret = netsec_reset_hardware(priv, true);
 	if (ret)
 		goto err2;
 
+	/* Restore phy power state */
+	netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR, data);
+
 	spin_lock_init(&priv->desc_ring[NETSEC_RING_TX].lock);
 	spin_lock_init(&priv->desc_ring[NETSEC_RING_RX].lock);
 
@@ -1933,11 +1936,13 @@
 			ret = PTR_ERR(priv->phydev);
 			dev_err(priv->dev, "get_phy_device err(%d)\n", ret);
 			priv->phydev = NULL;
+			mdiobus_unregister(bus);
 			return -ENODEV;
 		}
 
 		ret = phy_device_register(priv->phydev);
 		if (ret) {
+			phy_device_free(priv->phydev);
 			mdiobus_unregister(bus);
 			dev_err(priv->dev,
 				"phy_device_register err(%d)\n", ret);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/socionext/sni_ave.c
+++ linux-ein-5.4.0/drivers/net/ethernet/socionext/sni_ave.c
@@ -424,16 +424,22 @@
 		phy_ethtool_get_wol(ndev->phydev, wol);
 }
 
-static int ave_ethtool_set_wol(struct net_device *ndev,
-			       struct ethtool_wolinfo *wol)
+static int __ave_ethtool_set_wol(struct net_device *ndev,
+				 struct ethtool_wolinfo *wol)
 {
-	int ret;
-
 	if (!ndev->phydev ||
 	    (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)))
 		return -EOPNOTSUPP;
 
-	ret = phy_ethtool_set_wol(ndev->phydev, wol);
+	return phy_ethtool_set_wol(ndev->phydev, wol);
+}
+
+static int ave_ethtool_set_wol(struct net_device *ndev,
+			       struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = __ave_ethtool_set_wol(ndev, wol);
 	if (!ret)
 		device_set_wakeup_enable(&ndev->dev, !!wol->wolopts);
 
@@ -1185,7 +1191,7 @@
 	ret = regmap_update_bits(priv->regmap, SG_ETPINMODE,
 				 priv->pinmode_mask, priv->pinmode_val);
 	if (ret)
-		return ret;
+		goto out_reset_assert;
 
 	ave_global_reset(ndev);
 
@@ -1216,7 +1222,7 @@
 
 	/* set wol initial state disabled */
 	wol.wolopts = 0;
-	ave_ethtool_set_wol(ndev, &wol);
+	__ave_ethtool_set_wol(ndev, &wol);
 
 	if (!phy_interface_is_rgmii(phydev))
 		phy_set_max_speed(phydev, SPEED_100);
@@ -1768,7 +1774,7 @@
 
 	ave_ethtool_get_wol(ndev, &wol);
 	wol.wolopts = priv->wolopts;
-	ave_ethtool_set_wol(ndev, &wol);
+	__ave_ethtool_set_wol(ndev, &wol);
 
 	if (ndev->phydev) {
 		ret = phy_resume(ndev->phydev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -195,6 +195,19 @@
 	  This selects Allwinner SoC glue layer support for the
 	  stmmac device driver. This driver is used for H3/A83T/A64
 	  EMAC ethernet controller.
+
+config DWMAC_IMX8
+	tristate "NXP IMX8 DWMAC support"
+	default ARCH_MXC
+	depends on OF && (ARCH_MXC || COMPILE_TEST)
+	select MFD_SYSCON
+	---help---
+	  Support for ethernet controller on NXP i.MX8 SOCs.
+
+	  This selects NXP SoC glue layer support for the stmmac
+	  device driver. This driver is used for i.MX8 series like
+	  iMX8MP/iMX8DXL GMAC ethernet controller.
+
 endif
 
 config STMMAC_PCI
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_DWMAC_SUN8I)	+= dwmac-sun8i.o
 obj-$(CONFIG_DWMAC_DWC_QOS_ETH)	+= dwmac-dwc-qos-eth.o
 obj-$(CONFIG_DWMAC_GENERIC)	+= dwmac-generic.o
+obj-$(CONFIG_DWMAC_IMX8)	+= dwmac-imx.o
 stmmac-platform-objs:= stmmac_platform.o
 dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
@@ -57,10 +57,6 @@
 #define TSE_PCS_USE_SGMII_ENA				BIT(0)
 #define TSE_PCS_IF_USE_SGMII				0x03
 
-#define SGMII_ADAPTER_CTRL_REG				0x00
-#define SGMII_ADAPTER_DISABLE				0x0001
-#define SGMII_ADAPTER_ENABLE				0x0000
-
 #define AUTONEGO_LINK_TIMER				20
 
 static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs)
@@ -202,12 +198,8 @@
 			   unsigned int speed)
 {
 	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
-	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 	u32 val;
 
-	writew(SGMII_ADAPTER_ENABLE,
-	       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
-
 	pcs->autoneg = phy_dev->autoneg;
 
 	if (phy_dev->autoneg == AUTONEG_ENABLE) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
@@ -10,6 +10,10 @@
 #include <linux/phy.h>
 #include <linux/timer.h>
 
+#define SGMII_ADAPTER_CTRL_REG		0x00
+#define SGMII_ADAPTER_ENABLE		0x0000
+#define SGMII_ADAPTER_DISABLE		0x0001
+
 struct tse_pcs {
 	struct device *dev;
 	void __iomem *tse_pcs_base;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/common.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -176,6 +176,7 @@
 	unsigned long mac_errors[32];
 	unsigned long mtl_errors[32];
 	unsigned long dma_errors[32];
+	unsigned long dma_dpp_errors[32];
 };
 
 /* Number of fields in Safety Stats */
@@ -362,11 +363,15 @@
 	unsigned int dvlan;
 	unsigned int l3l4fnum;
 	unsigned int arpoffsel;
+	/* TSN Features */
+	unsigned int estwid;
+	unsigned int estdep;
+	unsigned int estsel;
+	unsigned int fpesel;
 };
 
-/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
-#define BUF_SIZE_16KiB 16384
-/* RX Buffer size must be < 8191 and multiple of 4/8/16 bytes */
+/* RX Buffer size must be multiple of 4/8/16 bytes */
+#define BUF_SIZE_16KiB 16368
 #define BUF_SIZE_8KiB 8188
 #define BUF_SIZE_4KiB 4096
 #define BUF_SIZE_2KiB 2048
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
@@ -40,7 +40,7 @@
 static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
 				   struct plat_stmmacenet_data *plat_dat)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
 	u32 burst_map = 0;
 	u32 bit_index = 0;
 	u32 a_index = 0;
@@ -52,9 +52,10 @@
 			return -ENOMEM;
 	}
 
-	plat_dat->axi->axi_lpi_en = of_property_read_bool(np, "snps,en-lpi");
-	if (of_property_read_u32(np, "snps,write-requests",
-				 &plat_dat->axi->axi_wr_osr_lmt)) {
+	plat_dat->axi->axi_lpi_en = device_property_read_bool(dev,
+							      "snps,en-lpi");
+	if (device_property_read_u32(dev, "snps,write-requests",
+				     &plat_dat->axi->axi_wr_osr_lmt)) {
 		/**
 		 * Since the register has a reset value of 1, if property
 		 * is missing, default to 1.
@@ -68,8 +69,8 @@
 		plat_dat->axi->axi_wr_osr_lmt--;
 	}
 
-	if (of_property_read_u32(np, "snps,read-requests",
-				 &plat_dat->axi->axi_rd_osr_lmt)) {
+	if (device_property_read_u32(dev, "snps,read-requests",
+				     &plat_dat->axi->axi_rd_osr_lmt)) {
 		/**
 		 * Since the register has a reset value of 1, if property
 		 * is missing, default to 1.
@@ -82,7 +83,7 @@
 		 */
 		plat_dat->axi->axi_rd_osr_lmt--;
 	}
-	of_property_read_u32(np, "snps,burst-map", &burst_map);
+	device_property_read_u32(dev, "snps,burst-map", &burst_map);
 
 	/* converts burst-map bitmask to burst array */
 	for (bit_index = 0; bit_index < 7; bit_index++) {
@@ -270,6 +271,7 @@
 			      struct plat_stmmacenet_data *data,
 			      struct stmmac_resources *res)
 {
+	struct device *dev = &pdev->dev;
 	struct tegra_eqos *eqos;
 	int err;
 
@@ -282,6 +284,9 @@
 	eqos->dev = &pdev->dev;
 	eqos->regs = res->addr;
 
+	if (!is_of_node(dev->fwnode))
+		goto bypass_clk_reset_gpio;
+
 	eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
 	if (IS_ERR(eqos->clk_master)) {
 		err = PTR_ERR(eqos->clk_master);
@@ -354,9 +359,11 @@
 
 	usleep_range(2000, 4000);
 
+bypass_clk_reset_gpio:
 	data->fix_mac_speed = tegra_eqos_fix_speed;
 	data->init = tegra_eqos_init;
 	data->bsp_priv = eqos;
+	data->sph_disable = 1;
 
 	err = tegra_eqos_init(pdev, eqos);
 	if (err < 0)
@@ -421,7 +428,7 @@
 	void *priv;
 	int ret;
 
-	data = of_device_get_match_data(&pdev->dev);
+	data = device_get_match_data(&pdev->dev);
 
 	memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
 
@@ -478,7 +485,7 @@
 	const struct dwc_eth_dwmac_data *data;
 	int err;
 
-	data = of_device_get_match_data(&pdev->dev);
+	data = device_get_match_data(&pdev->dev);
 
 	err = stmmac_dvr_remove(&pdev->dev);
 	if (err < 0)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
@@ -71,6 +71,7 @@
 
 static const struct of_device_id dwmac_generic_match[] = {
 	{ .compatible = "st,spear600-gmac"},
+	{ .compatible = "snps,dwmac-3.40a"},
 	{ .compatible = "snps,dwmac-3.50a"},
 	{ .compatible = "snps,dwmac-3.610"},
 	{ .compatible = "snps,dwmac-3.70a"},
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx8
+ *
+ * Copyright 2020 NXP
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#define GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(21, 16)
+#define GPR_ENET_QOS_INTF_SEL_MII	(0x0 << 16)
+#define GPR_ENET_QOS_INTF_SEL_RMII	(0x4 << 16)
+#define GPR_ENET_QOS_INTF_SEL_RGMII	(0x1 << 16)
+#define GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 19)
+#define GPR_ENET_QOS_CLK_TX_CLK_SEL	(0x1 << 20)
+#define GPR_ENET_QOS_RGMII_EN		(0x1 << 21)
+
+struct imx_dwmac_ops {
+	u32 addr_width;
+	bool mac_rgmii_txclk_auto_adj;
+
+	int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);
+};
+
+struct imx_priv_data {
+	struct device *dev;
+	struct clk *clk_tx;
+	struct clk *clk_mem;
+	struct regmap *intf_regmap;
+	u32 intf_reg_off;
+	bool rmii_refclk_ext;
+
+	const struct imx_dwmac_ops *ops;
+	struct plat_stmmacenet_data *plat_dat;
+};
+
+static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
+{
+	struct imx_priv_data *dwmac = plat_dat->bsp_priv;
+	int val;
+
+	switch (plat_dat->interface) {
+	case PHY_INTERFACE_MODE_MII:
+		val = GPR_ENET_QOS_INTF_SEL_MII;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		val = GPR_ENET_QOS_INTF_SEL_RMII;
+		val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL);
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		val = GPR_ENET_QOS_INTF_SEL_RGMII |
+		      GPR_ENET_QOS_RGMII_EN;
+		break;
+	default:
+		pr_debug("imx dwmac doesn't support %d interface\n",
+			 plat_dat->interface);
+		return -EINVAL;
+	}
+
+	val |= GPR_ENET_QOS_CLK_GEN_EN;
+	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
+				  GPR_ENET_QOS_INTF_MODE_MASK, val);
+};
+
+static int
+imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
+{
+	int ret = 0;
+
+	/* TBD: depends on imx8dxl scu interfaces to be upstreamed */
+	return ret;
+}
+
+static int imx_dwmac_init(struct platform_device *pdev, void *priv)
+{
+	struct plat_stmmacenet_data *plat_dat;
+	struct imx_priv_data *dwmac = priv;
+	int ret;
+
+	plat_dat = dwmac->plat_dat;
+
+	ret = clk_prepare_enable(dwmac->clk_mem);
+	if (ret) {
+		dev_err(&pdev->dev, "mem clock enable failed\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(dwmac->clk_tx);
+	if (ret) {
+		dev_err(&pdev->dev, "tx clock enable failed\n");
+		goto clk_tx_en_failed;
+	}
+
+	if (dwmac->ops->set_intf_mode) {
+		ret = dwmac->ops->set_intf_mode(plat_dat);
+		if (ret)
+			goto intf_mode_failed;
+	}
+
+	return 0;
+
+intf_mode_failed:
+	clk_disable_unprepare(dwmac->clk_tx);
+clk_tx_en_failed:
+	clk_disable_unprepare(dwmac->clk_mem);
+	return ret;
+}
+
+static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+	struct imx_priv_data *dwmac = priv;
+
+	if (dwmac->clk_tx)
+		clk_disable_unprepare(dwmac->clk_tx);
+	clk_disable_unprepare(dwmac->clk_mem);
+}
+
+static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
+{
+	struct plat_stmmacenet_data *plat_dat;
+	struct imx_priv_data *dwmac = priv;
+	unsigned long rate;
+	int err;
+
+	plat_dat = dwmac->plat_dat;
+
+	if (dwmac->ops->mac_rgmii_txclk_auto_adj ||
+	    (plat_dat->interface == PHY_INTERFACE_MODE_RMII) ||
+	    (plat_dat->interface == PHY_INTERFACE_MODE_MII))
+		return;
+
+	switch (speed) {
+	case SPEED_1000:
+		rate = 125000000;
+		break;
+	case SPEED_100:
+		rate = 25000000;
+		break;
+	case SPEED_10:
+		rate = 2500000;
+		break;
+	default:
+		dev_err(dwmac->dev, "invalid speed %u\n", speed);
+		return;
+	}
+
+	err = clk_set_rate(dwmac->clk_tx, rate);
+	if (err < 0)
+		dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
+}
+
+static int
+imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	int err = 0;
+
+	if (of_get_property(np, "snps,rmii_refclk_ext", NULL))
+		dwmac->rmii_refclk_ext = true;
+
+	dwmac->clk_tx = devm_clk_get(dev, "tx");
+	if (IS_ERR(dwmac->clk_tx)) {
+		dev_err(dev, "failed to get tx clock\n");
+		return PTR_ERR(dwmac->clk_tx);
+	}
+
+	dwmac->clk_mem = NULL;
+	if (of_machine_is_compatible("fsl,imx8dxl")) {
+		dwmac->clk_mem = devm_clk_get(dev, "mem");
+		if (IS_ERR(dwmac->clk_mem)) {
+			dev_err(dev, "failed to get mem clock\n");
+			return PTR_ERR(dwmac->clk_mem);
+		}
+	}
+
+	if (of_machine_is_compatible("fsl,imx8mp")) {
+		/* Binding doc describes the propety:
+		   is required by i.MX8MP.
+		   is optinoal for i.MX8DXL.
+		 */
+		dwmac->intf_regmap = syscon_regmap_lookup_by_phandle(np, "intf_mode");
+		if (IS_ERR(dwmac->intf_regmap))
+			return PTR_ERR(dwmac->intf_regmap);
+
+		err = of_property_read_u32_index(np, "intf_mode", 1, &dwmac->intf_reg_off);
+		if (err) {
+			dev_err(dev, "Can't get intf mode reg offset (%d)\n", err);
+			return err;
+		}
+	}
+
+	return err;
+}
+
+static int imx_dwmac_probe(struct platform_device *pdev)
+{
+	struct plat_stmmacenet_data *plat_dat;
+	struct stmmac_resources stmmac_res;
+	struct imx_priv_data *dwmac;
+	const struct imx_dwmac_ops *data;
+	int ret;
+
+	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+	if (ret)
+		return ret;
+
+	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+	if (!dwmac)
+		return -ENOMEM;
+
+	plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+	if (IS_ERR(plat_dat))
+		return PTR_ERR(plat_dat);
+
+	data = of_device_get_match_data(&pdev->dev);
+	if (!data) {
+		dev_err(&pdev->dev, "failed to get match data\n");
+		ret = -EINVAL;
+		goto err_match_data;
+	}
+
+	dwmac->ops = data;
+	dwmac->dev = &pdev->dev;
+
+	ret = imx_dwmac_parse_dt(dwmac, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse OF data\n");
+		goto err_parse_dt;
+	}
+
+	plat_dat->addr64 = dwmac->ops->addr_width;
+	plat_dat->init = imx_dwmac_init;
+	plat_dat->exit = imx_dwmac_exit;
+	plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
+	plat_dat->bsp_priv = dwmac;
+	dwmac->plat_dat = plat_dat;
+
+	ret = imx_dwmac_init(pdev, dwmac);
+	if (ret)
+		goto err_dwmac_init;
+
+	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	if (ret)
+		goto err_drv_probe;
+
+	return 0;
+
+err_dwmac_init:
+err_drv_probe:
+	imx_dwmac_exit(pdev, plat_dat->bsp_priv);
+err_parse_dt:
+err_match_data:
+	stmmac_remove_config_dt(pdev, plat_dat);
+	return ret;
+}
+
+static struct imx_dwmac_ops imx8mp_dwmac_data = {
+	.addr_width = 34,
+	.mac_rgmii_txclk_auto_adj = false,
+	.set_intf_mode = imx8mp_set_intf_mode,
+};
+
+static struct imx_dwmac_ops imx8dxl_dwmac_data = {
+	.addr_width = 32,
+	.mac_rgmii_txclk_auto_adj = true,
+	.set_intf_mode = imx8dxl_set_intf_mode,
+};
+
+static const struct of_device_id imx_dwmac_match[] = {
+	{ .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data },
+	{ .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, imx_dwmac_match);
+
+static struct platform_driver imx_dwmac_driver = {
+	.probe  = imx_dwmac_probe,
+	.remove = stmmac_pltfr_remove,
+	.driver = {
+		.name           = "imx-dwmac",
+		.pm		= &stmmac_pltfr_pm_ops,
+		.of_match_table = imx_dwmac_match,
+	},
+};
+module_platform_driver(imx_dwmac_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");
+MODULE_LICENSE("GPL v2");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -288,10 +288,7 @@
 		val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
 		break;
 	default:
-		dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
-			phy_modes(gmac->phy_mode));
-		err = -EINVAL;
-		goto err_remove_config_dt;
+		goto err_unsupported_phy;
 	}
 	regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
 
@@ -308,16 +305,25 @@
 			NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
 		break;
 	default:
-		dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
-			phy_modes(gmac->phy_mode));
-		err = -EINVAL;
-		goto err_remove_config_dt;
+		goto err_unsupported_phy;
 	}
 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
 
 	/* 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:
+		goto err_unsupported_phy;
+	}
 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
 
 	if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
@@ -337,6 +343,9 @@
 	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;
+	plat_dat->tx_fifo_size = 8192;
+	plat_dat->rx_fifo_size = 8192;
 
 	err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 	if (err)
@@ -344,6 +353,11 @@
 
 	return 0;
 
+err_unsupported_phy:
+	dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
+		phy_modes(gmac->phy_mode));
+	err = -EINVAL;
+
 err_remove_config_dt:
 	stmmac_remove_config_dt(pdev, plat_dat);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -29,7 +29,6 @@
 #define PRG_ETH0_EXT_RMII_MODE		4
 
 /* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */
-#define PRG_ETH0_CLK_M250_SEL_SHIFT	4
 #define PRG_ETH0_CLK_M250_SEL_MASK	GENMASK(4, 4)
 
 #define PRG_ETH0_TXDLY_SHIFT		5
@@ -112,6 +111,15 @@
 	struct device *dev = dwmac->dev;
 	const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
 	struct meson8b_dwmac_clk_configs *clk_configs;
+	static const struct clk_div_table div_table[] = {
+		{ .div = 2, .val = 2, },
+		{ .div = 3, .val = 3, },
+		{ .div = 4, .val = 4, },
+		{ .div = 5, .val = 5, },
+		{ .div = 6, .val = 6, },
+		{ .div = 7, .val = 7, },
+		{ /* end of array */ }
+	};
 
 	clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
 	if (!clk_configs)
@@ -134,8 +142,9 @@
 	}
 
 	clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
-	clk_configs->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
-	clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
+	clk_configs->m250_mux.shift = __ffs(PRG_ETH0_CLK_M250_SEL_MASK);
+	clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK >>
+				     clk_configs->m250_mux.shift;
 	clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names,
 					 MUX_CLK_NUM_PARENTS, &clk_mux_ops,
 					 &clk_configs->m250_mux.hw);
@@ -146,9 +155,9 @@
 	clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
 	clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
 	clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
-	clk_configs->m250_div.flags = CLK_DIVIDER_ONE_BASED |
-				CLK_DIVIDER_ALLOW_ZERO |
-				CLK_DIVIDER_ROUND_CLOSEST;
+	clk_configs->m250_div.table = div_table;
+	clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO |
+				      CLK_DIVIDER_ROUND_CLOSEST;
 	clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
 					 &clk_divider_ops,
 					 &clk_configs->m250_div.hw);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -75,6 +75,11 @@
 	unsigned int value;
 };
 
+struct ethqos_emac_driver_data {
+	const struct ethqos_emac_por *por;
+	unsigned int num_por;
+};
+
 struct qcom_ethqos {
 	struct platform_device *pdev;
 	void __iomem *rgmii_base;
@@ -171,6 +176,11 @@
 	{ .offset = RGMII_IO_MACRO_CONFIG2,	.value = 0x00002060 },
 };
 
+static const struct ethqos_emac_driver_data emac_v2_3_0_data = {
+	.por = emac_v2_3_0_por,
+	.num_por = ARRAY_SIZE(emac_v2_3_0_por),
+};
+
 static int ethqos_dll_configure(struct qcom_ethqos *ethqos)
 {
 	unsigned int val;
@@ -413,6 +423,7 @@
 			dll_lock = rgmii_readl(ethqos, SDC4_STATUS);
 			if (dll_lock & SDC4_STATUS_DLL_LOCK)
 				break;
+			retry--;
 		} while (retry > 0);
 		if (!retry)
 			dev_err(&ethqos->pdev->dev,
@@ -441,6 +452,7 @@
 	struct device_node *np = pdev->dev.of_node;
 	struct plat_stmmacenet_data *plat_dat;
 	struct stmmac_resources stmmac_res;
+	const struct ethqos_emac_driver_data *data;
 	struct qcom_ethqos *ethqos;
 	struct resource *res;
 	int ret;
@@ -470,7 +482,9 @@
 		goto err_mem;
 	}
 
-	ethqos->por = of_device_get_match_data(&pdev->dev);
+	data = of_device_get_match_data(&pdev->dev);
+	ethqos->por = data->por;
+	ethqos->num_por = data->num_por;
 
 	ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii");
 	if (IS_ERR(ethqos->rgmii_clk)) {
@@ -491,6 +505,8 @@
 	plat_dat->has_gmac4 = 1;
 	plat_dat->pmt = 1;
 	plat_dat->tso_en = of_property_read_bool(np, "snps,tso");
+	if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
+		plat_dat->rx_clk_runs_in_lpi = 1;
 
 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 	if (ret)
@@ -525,7 +541,7 @@
 }
 
 static const struct of_device_id qcom_ethqos_match[] = {
-	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_por},
+	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, qcom_ethqos_match);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -1411,7 +1411,7 @@
 
 	ret = rk_gmac_clk_init(plat_dat);
 	if (ret)
-		return ret;
+		goto err_remove_config_dt;
 
 	ret = rk_gmac_powerup(plat_dat->bsp_priv);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -18,9 +18,6 @@
 
 #include "altr_tse_pcs.h"
 
-#define SGMII_ADAPTER_CTRL_REG                          0x00
-#define SGMII_ADAPTER_DISABLE                           0x0001
-
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
@@ -62,14 +59,13 @@
 {
 	struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
 	void __iomem *splitter_base = dwmac->splitter_base;
-	void __iomem *tse_pcs_base = dwmac->pcs.tse_pcs_base;
 	void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base;
 	struct device *dev = dwmac->dev;
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct phy_device *phy_dev = ndev->phydev;
 	u32 val;
 
-	if ((tse_pcs_base) && (sgmii_adapter_base))
+	if (sgmii_adapter_base)
 		writew(SGMII_ADAPTER_DISABLE,
 		       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 
@@ -93,8 +89,11 @@
 		writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
 	}
 
-	if (tse_pcs_base && sgmii_adapter_base)
+	if (phy_dev && sgmii_adapter_base) {
+		writew(SGMII_ADAPTER_ENABLE,
+		       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 		tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed);
+	}
 }
 
 static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
@@ -241,6 +240,8 @@
 	switch (phymode) {
 	case PHY_INTERFACE_MODE_RGMII:
 	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
 		*val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
 		break;
 	case PHY_INTERFACE_MODE_MII:
@@ -289,16 +290,19 @@
 	    phymode == PHY_INTERFACE_MODE_MII ||
 	    phymode == PHY_INTERFACE_MODE_GMII ||
 	    phymode == PHY_INTERFACE_MODE_SGMII) {
-		ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2);
 		regmap_read(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG,
 			    &module);
 		module |= (SYSMGR_FPGAGRP_MODULE_EMAC << (reg_shift / 2));
 		regmap_write(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG,
 			     module);
-	} else {
-		ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2));
 	}
 
+	if (dwmac->f2h_ptp_ref_clk)
+		ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2);
+	else
+		ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK <<
+			  (reg_shift / 2));
+
 	regmap_write(sys_mgr_base_addr, reg_offset, ctrl);
 
 	/* Deassert reset for the phy configuration to be sampled by
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -111,6 +111,7 @@
 	int (*parse_data)(struct stm32_dwmac *dwmac,
 			  struct device *dev);
 	u32 syscfg_eth_mask;
+	bool clk_rx_enable_in_suspend;
 };
 
 static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat)
@@ -128,7 +129,8 @@
 	if (ret)
 		return ret;
 
-	if (!dwmac->dev->power.is_suspended) {
+	if (!dwmac->ops->clk_rx_enable_in_suspend ||
+	    !dwmac->dev->power.is_suspended) {
 		ret = clk_prepare_enable(dwmac->clk_rx);
 		if (ret) {
 			clk_disable_unprepare(dwmac->clk_tx);
@@ -330,7 +332,7 @@
 	/* Get IRQ information early to have an ability to ask for deferred
 	 * probe if needed before we went too far with resource allocation.
 	 */
-	dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev,
+	dwmac->irq_pwr_wakeup = platform_get_irq_byname_optional(pdev,
 							"stm32_pwr_wakeup");
 	if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
@@ -508,7 +510,8 @@
 	.suspend = stm32mp1_suspend,
 	.resume = stm32mp1_resume,
 	.parse_data = stm32mp1_parse_data,
-	.syscfg_eth_mask = SYSCFG_MP1_ETH_MASK
+	.syscfg_eth_mask = SYSCFG_MP1_ETH_MASK,
+	.clk_rx_enable_in_suspend = true
 };
 
 static const struct of_device_id stm32_dwmac_match[] = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -64,6 +64,7 @@
  * @variant:	reference to the current board variant
  * @regmap:	regmap for using the syscon
  * @internal_phy_powered: Does the internal PHY is enabled
+ * @use_internal_phy: Is the internal PHY selected for use
  * @mux_handle:	Internal pointer used by mdio-mux lib
  */
 struct sunxi_priv_data {
@@ -74,6 +75,7 @@
 	const struct emac_variant *variant;
 	struct regmap_field *regmap_field;
 	bool internal_phy_powered;
+	bool use_internal_phy;
 	void *mux_handle;
 };
 
@@ -335,14 +337,30 @@
 	}
 }
 
-static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan,
+				       bool rx, bool tx)
 {
-	writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN);
+	u32 value = readl(ioaddr + EMAC_INT_EN);
+
+	if (rx)
+		value |= EMAC_RX_INT;
+	if (tx)
+		value |= EMAC_TX_INT;
+
+	writel(value, ioaddr + EMAC_INT_EN);
 }
 
-static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan,
+					bool rx, bool tx)
 {
-	writel(0, ioaddr + EMAC_INT_EN);
+	u32 value = readl(ioaddr + EMAC_INT_EN);
+
+	if (rx)
+		value &= ~EMAC_RX_INT;
+	if (tx)
+		value &= ~EMAC_TX_INT;
+
+	writel(value, ioaddr + EMAC_INT_EN);
 }
 
 static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
@@ -523,8 +541,11 @@
 	.dma_interrupt = sun8i_dwmac_dma_interrupt,
 };
 
+static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv);
+
 static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
 {
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct sunxi_priv_data *gmac = priv;
 	int ret;
 
@@ -538,13 +559,25 @@
 
 	ret = clk_prepare_enable(gmac->tx_clk);
 	if (ret) {
-		if (gmac->regulator)
-			regulator_disable(gmac->regulator);
 		dev_err(&pdev->dev, "Could not enable AHB clock\n");
-		return ret;
+		goto err_disable_regulator;
+	}
+
+	if (gmac->use_internal_phy) {
+		ret = sun8i_dwmac_power_internal_phy(netdev_priv(ndev));
+		if (ret)
+			goto err_disable_clk;
 	}
 
 	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(gmac->tx_clk);
+err_disable_regulator:
+	if (gmac->regulator)
+		regulator_disable(gmac->regulator);
+
+	return ret;
 }
 
 static void sun8i_dwmac_core_init(struct mac_device_info *hw,
@@ -701,7 +734,7 @@
 
 	if (err) {
 		dev_err(priv->device, "EMAC reset timeout\n");
-		return -EFAULT;
+		return err;
 	}
 	return 0;
 }
@@ -815,7 +848,6 @@
 	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
 	u32 reg, val;
 	int ret = 0;
-	bool need_power_ephy = false;
 
 	if (current_child ^ desired_child) {
 		regmap_field_read(gmac->regmap_field, &reg);
@@ -823,13 +855,12 @@
 		case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
 			dev_info(priv->device, "Switch mux to internal PHY");
 			val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
-
-			need_power_ephy = true;
+			gmac->use_internal_phy = true;
 			break;
 		case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
 			dev_info(priv->device, "Switch mux to external PHY");
 			val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN;
-			need_power_ephy = false;
+			gmac->use_internal_phy = false;
 			break;
 		default:
 			dev_err(priv->device, "Invalid child ID %x\n",
@@ -837,7 +868,7 @@
 			return -EINVAL;
 		}
 		regmap_field_write(gmac->regmap_field, val);
-		if (need_power_ephy) {
+		if (gmac->use_internal_phy) {
 			ret = sun8i_dwmac_power_internal_phy(priv);
 			if (ret)
 				return ret;
@@ -864,6 +895,7 @@
 
 	ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn,
 			    &gmac->mux_handle, priv, priv->mii);
+	of_node_put(mdio_mux);
 	return ret;
 }
 
@@ -957,6 +989,9 @@
 		/* default */
 		break;
 	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
 		reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII;
 		break;
 	case PHY_INTERFACE_MODE_RMII:
@@ -985,17 +1020,12 @@
 	struct sunxi_priv_data *gmac = priv;
 
 	if (gmac->variant->soc_has_internal_phy) {
-		/* sun8i_dwmac_exit could be called with mdiomux uninit */
-		if (gmac->mux_handle)
-			mdio_mux_uninit(gmac->mux_handle);
 		if (gmac->internal_phy_powered)
 			sun8i_dwmac_unpower_internal_phy(gmac);
 	}
 
 	sun8i_dwmac_unset_syscon(gmac);
 
-	reset_control_put(gmac->rst_ephy);
-
 	clk_disable_unprepare(gmac->tx_clk);
 
 	if (gmac->regulator)
@@ -1193,6 +1223,8 @@
 	plat_dat->init = sun8i_dwmac_init;
 	plat_dat->exit = sun8i_dwmac_exit;
 	plat_dat->setup = sun8i_dwmac_setup;
+	plat_dat->tx_fifo_size = 4096;
+	plat_dat->rx_fifo_size = 16384;
 
 	ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv);
 	if (ret)
@@ -1224,12 +1256,32 @@
 
 	return ret;
 dwmac_mux:
+	reset_control_put(gmac->rst_ephy);
+	clk_put(gmac->ephy_clk);
 	sun8i_dwmac_unset_syscon(gmac);
 dwmac_exit:
 	stmmac_pltfr_remove(pdev);
 return ret;
 }
 
+static int sun8i_dwmac_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+
+	if (gmac->variant->soc_has_internal_phy) {
+		mdio_mux_uninit(gmac->mux_handle);
+		sun8i_dwmac_unpower_internal_phy(gmac);
+		reset_control_put(gmac->rst_ephy);
+		clk_put(gmac->ephy_clk);
+	}
+
+	stmmac_pltfr_remove(pdev);
+
+	return 0;
+}
+
 static const struct of_device_id sun8i_dwmac_match[] = {
 	{ .compatible = "allwinner,sun8i-h3-emac",
 		.data = &emac_variant_h3 },
@@ -1249,7 +1301,7 @@
 
 static struct platform_driver sun8i_dwmac_driver = {
 	.probe  = sun8i_dwmac_probe,
-	.remove = stmmac_pltfr_remove,
+	.remove = sun8i_dwmac_remove,
 	.driver = {
 		.name           = "dwmac-sun8i",
 		.pm		= &stmmac_pltfr_pm_ops,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -30,7 +30,7 @@
 static int sun7i_gmac_init(struct platform_device *pdev, void *priv)
 {
 	struct sunxi_priv_data *gmac = priv;
-	int ret;
+	int ret = 0;
 
 	if (gmac->regulator) {
 		ret = regulator_enable(gmac->regulator);
@@ -44,18 +44,18 @@
 	 * 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);
 		ret = clk_prepare(gmac->tx_clk);
-		if (ret)
-			return ret;
+		if (ret && gmac->regulator)
+			regulator_disable(gmac->regulator);
 	}
 
-	return 0;
+	return ret;
 }
 
 static void sun7i_gmac_exit(struct platform_device *pdev, void *priv)
@@ -146,6 +146,8 @@
 	plat_dat->init = sun7i_gmac_init;
 	plat_dat->exit = sun7i_gmac_exit;
 	plat_dat->fix_mac_speed = sun7i_fix_speed;
+	plat_dat->tx_fifo_size = 4096;
+	plat_dat->rx_fifo_size = 16384;
 
 	ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -76,10 +76,10 @@
 #define LPI_CTRL_STATUS_TLPIEN	0x00000001	/* Transmit LPI Entry */
 
 /* GMAC HW ADDR regs */
-#define GMAC_ADDR_HIGH(reg)	(((reg > 15) ? 0x00000800 : 0x00000040) + \
-				(reg * 8))
-#define GMAC_ADDR_LOW(reg)	(((reg > 15) ? 0x00000804 : 0x00000044) + \
-				(reg * 8))
+#define GMAC_ADDR_HIGH(reg)	((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
+				 0x00000040 + (reg * 8))
+#define GMAC_ADDR_LOW(reg)	((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
+				 0x00000044 + (reg * 8))
 #define GMAC_MAX_PERFECT_ADDRESSES	1
 
 #define GMAC_PCS_BASE		0x000000c0	/* PCS register base */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -24,6 +24,7 @@
 static void dwmac1000_core_init(struct mac_device_info *hw,
 				struct net_device *dev)
 {
+	struct stmmac_priv *priv = netdev_priv(dev);
 	void __iomem *ioaddr = hw->pcsr;
 	u32 value = readl(ioaddr + GMAC_CONTROL);
 	int mtu = dev->mtu;
@@ -35,7 +36,7 @@
 	 * Broadcom tags can look like invalid LLC/SNAP packets and cause the
 	 * hardware to truncate packets on reception.
 	 */
-	if (netdev_uses_dsa(dev))
+	if (netdev_uses_dsa(dev) || !priv->plat->enh_desc)
 		value &= ~GMAC_CONTROL_ACS;
 
 	if (mtu > 1500)
@@ -165,6 +166,9 @@
 		value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
 	} 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;
 
@@ -208,7 +212,7 @@
 			reg++;
 		}
 
-		while (reg <= perfect_addr_number) {
+		while (reg < perfect_addr_number) {
 			writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
 			writel(0, ioaddr + GMAC_ADDR_LOW(reg));
 			reg++;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -218,11 +218,18 @@
 				readl(ioaddr + DMA_BUS_MODE + i * 4);
 }
 
-static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
-				     struct dma_features *dma_cap)
+static int dwmac1000_get_hw_feature(void __iomem *ioaddr,
+				    struct dma_features *dma_cap)
 {
 	u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
 
+	if (!hw_cap) {
+		/* 0x00000000 is the value read on old hardware that does not
+		 * implement this register
+		 */
+		return -EOPNOTSUPP;
+	}
+
 	dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
 	dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
 	dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
@@ -252,6 +259,8 @@
 	dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
 	/* Alternate (enhanced) DESC mode */
 	dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
+
+	return 0;
 }
 
 static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -59,6 +59,8 @@
 #define GMAC_RXQCTRL_MCBCQEN_SHIFT	20
 #define GMAC_RXQCTRL_TACPQE		BIT(21)
 #define GMAC_RXQCTRL_TACPQE_SHIFT	21
+#define GMAC_RXQCTRL_FPRQ		GENMASK(26, 24)
+#define GMAC_RXQCTRL_FPRQ_SHIFT		24
 
 /* MAC Packet Filtering */
 #define GMAC_PACKET_FILTER_PR		BIT(0)
@@ -170,6 +172,8 @@
 #define GMAC_CONFIG_SARC		GENMASK(30, 28)
 #define GMAC_CONFIG_SARC_SHIFT		28
 #define GMAC_CONFIG_IPC			BIT(27)
+#define GMAC_CONFIG_IPG			GENMASK(26, 24)
+#define GMAC_CONFIG_IPG_SHIFT		24
 #define GMAC_CONFIG_2K			BIT(22)
 #define GMAC_CONFIG_ACS			BIT(20)
 #define GMAC_CONFIG_BE			BIT(18)
@@ -177,12 +181,18 @@
 #define GMAC_CONFIG_JE			BIT(16)
 #define GMAC_CONFIG_PS			BIT(15)
 #define GMAC_CONFIG_FES			BIT(14)
+#define GMAC_CONFIG_FES_SHIFT		14
 #define GMAC_CONFIG_DM			BIT(13)
 #define GMAC_CONFIG_LM			BIT(12)
 #define GMAC_CONFIG_DCRS		BIT(9)
 #define GMAC_CONFIG_TE			BIT(1)
 #define GMAC_CONFIG_RE			BIT(0)
 
+/* MAC extended config */
+#define GMAC_CONFIG_EIPG		GENMASK(29, 25)
+#define GMAC_CONFIG_EIPG_SHIFT		25
+#define GMAC_CONFIG_EIPG_EN		BIT(24)
+
 /* MAC HW features0 bitmap */
 #define GMAC_HW_FEAT_SAVLANINS		BIT(27)
 #define GMAC_HW_FEAT_ADDMAC		BIT(18)
@@ -217,6 +227,10 @@
 
 /* MAC HW features3 bitmap */
 #define GMAC_HW_FEAT_ASP		GENMASK(29, 28)
+#define GMAC_HW_FEAT_FPESEL		BIT(26)
+#define GMAC_HW_FEAT_ESTWID		GENMASK(21, 20)
+#define GMAC_HW_FEAT_ESTDEP		GENMASK(19, 17)
+#define GMAC_HW_FEAT_ESTSEL		BIT(16)
 #define GMAC_HW_FEAT_FRPES		GENMASK(14, 13)
 #define GMAC_HW_FEAT_FRPBS		GENMASK(12, 11)
 #define GMAC_HW_FEAT_FRPSEL		BIT(10)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -215,6 +215,9 @@
 	if (queue == 0 || queue == 4) {
 		value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK;
 		value |= MTL_RXQ_DMA_Q04MDMACH(chan);
+	} else if (queue > 4) {
+		value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4);
+		value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4);
 	} else {
 		value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue);
 		value |= MTL_RXQ_DMA_QXMDMACH(chan, queue);
@@ -736,11 +739,14 @@
 				    bool is_double)
 {
 	void __iomem *ioaddr = hw->pcsr;
+	u32 value;
 
 	writel(hash, ioaddr + GMAC_VLAN_HASH_TABLE);
 
+	value = readl(ioaddr + GMAC_VLAN_TAG);
+
 	if (hash) {
-		u32 value = GMAC_VLAN_VTHM | GMAC_VLAN_ETV;
+		value |= GMAC_VLAN_VTHM | GMAC_VLAN_ETV;
 		if (is_double) {
 			value |= GMAC_VLAN_EDVLP;
 			value |= GMAC_VLAN_ESVL;
@@ -749,8 +755,6 @@
 
 		writel(value, ioaddr + GMAC_VLAN_TAG);
 	} else {
-		u32 value = readl(ioaddr + GMAC_VLAN_TAG);
-
 		value &= ~(GMAC_VLAN_VTHM | GMAC_VLAN_ETV);
 		value &= ~(GMAC_VLAN_EDVLP | GMAC_VLAN_ESVL);
 		value &= ~GMAC_VLAN_DOVLTC;
@@ -869,6 +873,8 @@
 	.sarc_configure = dwmac4_sarc_configure,
 	.enable_vlan = dwmac4_enable_vlan,
 	.set_arp_offload = dwmac4_set_arp_offload,
+	.est_configure = dwmac5_est_configure,
+	.fpe_configure = dwmac5_fpe_configure,
 };
 
 const struct stmmac_ops dwmac510_ops = {
@@ -910,6 +916,8 @@
 	.sarc_configure = dwmac4_sarc_configure,
 	.enable_vlan = dwmac4_enable_vlan,
 	.set_arp_offload = dwmac4_set_arp_offload,
+	.est_configure = dwmac5_est_configure,
+	.fpe_configure = dwmac5_fpe_configure,
 };
 
 int dwmac4_setup(struct stmmac_priv *priv)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -431,8 +431,8 @@
 
 static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
 {
-	p->des0 = cpu_to_le32(addr);
-	p->des1 = 0;
+	p->des0 = cpu_to_le32(lower_32_bits(addr));
+	p->des1 = cpu_to_le32(upper_32_bits(addr));
 }
 
 static void dwmac4_clear(struct dma_desc *p)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -80,6 +80,7 @@
 	writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
 
 	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
+	writel(upper_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_HADDR(chan));
 }
 
 static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
@@ -98,6 +99,7 @@
 	writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
 
 	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
+	writel(upper_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_HADDR(chan));
 }
 
 static void dwmac4_dma_init_channel(void __iomem *ioaddr,
@@ -116,6 +118,23 @@
 	       ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
+static void dwmac410_dma_init_channel(void __iomem *ioaddr,
+				      struct stmmac_dma_cfg *dma_cfg, u32 chan)
+{
+	u32 value;
+
+	/* common channel control register config */
+	value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+	if (dma_cfg->pblx8)
+		value = value | DMA_BUS_MODE_PBL;
+
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+
+	/* Mask interrupts by writing to CSR7 */
+	writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
+	       ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
 static void dwmac4_dma_init(void __iomem *ioaddr,
 			    struct stmmac_dma_cfg *dma_cfg, int atds)
 {
@@ -132,7 +151,7 @@
 	if (dma_cfg->aal)
 		value |= DMA_SYS_BUS_AAL;
 
-	writel(value, ioaddr + DMA_SYS_BUS_MODE);
+	writel(value | DMA_SYS_EAME, ioaddr + DMA_SYS_BUS_MODE);
 }
 
 static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
@@ -194,7 +213,7 @@
 				       u32 channel, int fifosz, u8 qmode)
 {
 	unsigned int rqs = fifosz / 256 - 1;
-	u32 mtl_rx_op, mtl_rx_int;
+	u32 mtl_rx_op;
 
 	mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
 
@@ -265,11 +284,6 @@
 	}
 
 	writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
-
-	/* Enable MTL RX overflow */
-	mtl_rx_int = readl(ioaddr + MTL_CHAN_INT_CTRL(channel));
-	writel(mtl_rx_int | MTL_RX_OVERFLOW_INT_EN,
-	       ioaddr + MTL_CHAN_INT_CTRL(channel));
 }
 
 static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
@@ -324,8 +338,8 @@
 	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
 }
 
-static void dwmac4_get_hw_feature(void __iomem *ioaddr,
-				  struct dma_features *dma_cap)
+static int dwmac4_get_hw_feature(void __iomem *ioaddr,
+				 struct dma_features *dma_cap)
 {
 	u32 hw_cap = readl(ioaddr + GMAC_HW_FEATURE0);
 
@@ -384,10 +398,16 @@
 
 	/* 5.10 Features */
 	dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
+	dma_cap->fpesel = (hw_cap & GMAC_HW_FEAT_FPESEL) >> 26;
+	dma_cap->estwid = (hw_cap & GMAC_HW_FEAT_ESTWID) >> 20;
+	dma_cap->estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP) >> 17;
+	dma_cap->estsel = (hw_cap & GMAC_HW_FEAT_ESTSEL) >> 16;
 	dma_cap->frpes = (hw_cap & GMAC_HW_FEAT_FRPES) >> 13;
 	dma_cap->frpbs = (hw_cap & GMAC_HW_FEAT_FRPBS) >> 11;
 	dma_cap->frpsel = (hw_cap & GMAC_HW_FEAT_FRPSEL) >> 10;
 	dma_cap->dvlan = (hw_cap & GMAC_HW_FEAT_DVLAN) >> 5;
+
+	return 0;
 }
 
 /* Enable/disable TSO feature and set MSS */
@@ -462,7 +482,7 @@
 const struct stmmac_dma_ops dwmac410_dma_ops = {
 	.reset = dwmac4_dma_reset,
 	.init = dwmac4_dma_init,
-	.init_chan = dwmac4_dma_init_channel,
+	.init_chan = dwmac410_dma_init_channel,
 	.init_rx_chan = dwmac4_dma_init_rx_chan,
 	.init_tx_chan = dwmac4_dma_init_tx_chan,
 	.axi = dwmac4_dma_axi,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -65,6 +65,7 @@
 #define DMA_SYS_BUS_MB			BIT(14)
 #define DMA_AXI_1KBBE			BIT(13)
 #define DMA_SYS_BUS_AAL			BIT(12)
+#define DMA_SYS_EAME			BIT(11)
 #define DMA_AXI_BLEN256			BIT(7)
 #define DMA_AXI_BLEN128			BIT(6)
 #define DMA_AXI_BLEN64			BIT(5)
@@ -91,7 +92,9 @@
 #define DMA_CHAN_CONTROL(x)		DMA_CHANX_BASE_ADDR(x)
 #define DMA_CHAN_TX_CONTROL(x)		(DMA_CHANX_BASE_ADDR(x) + 0x4)
 #define DMA_CHAN_RX_CONTROL(x)		(DMA_CHANX_BASE_ADDR(x) + 0x8)
+#define DMA_CHAN_TX_BASE_HADDR(x)	(DMA_CHANX_BASE_ADDR(x) + 0x10)
 #define DMA_CHAN_TX_BASE_ADDR(x)	(DMA_CHANX_BASE_ADDR(x) + 0x14)
+#define DMA_CHAN_RX_BASE_HADDR(x)	(DMA_CHANX_BASE_ADDR(x) + 0x18)
 #define DMA_CHAN_RX_BASE_ADDR(x)	(DMA_CHANX_BASE_ADDR(x) + 0x1c)
 #define DMA_CHAN_TX_END_ADDR(x)		(DMA_CHANX_BASE_ADDR(x) + 0x20)
 #define DMA_CHAN_RX_END_ADDR(x)		(DMA_CHANX_BASE_ADDR(x) + 0x28)
@@ -164,6 +167,8 @@
 /* DMA default interrupt mask for 4.00 */
 #define DMA_CHAN_INTR_DEFAULT_MASK	(DMA_CHAN_INTR_NORMAL | \
 					 DMA_CHAN_INTR_ABNORMAL)
+#define DMA_CHAN_INTR_DEFAULT_RX	(DMA_CHAN_INTR_ENA_RIE)
+#define DMA_CHAN_INTR_DEFAULT_TX	(DMA_CHAN_INTR_ENA_TIE)
 
 #define DMA_CHAN_INTR_NORMAL_4_10	(DMA_CHAN_INTR_ENA_NIE_4_10 | \
 					 DMA_CHAN_INTR_ENA_RIE | \
@@ -174,6 +179,8 @@
 /* DMA default interrupt mask for 4.10a */
 #define DMA_CHAN_INTR_DEFAULT_MASK_4_10	(DMA_CHAN_INTR_NORMAL_4_10 | \
 					 DMA_CHAN_INTR_ABNORMAL_4_10)
+#define DMA_CHAN_INTR_DEFAULT_RX_4_10	(DMA_CHAN_INTR_ENA_RIE)
+#define DMA_CHAN_INTR_DEFAULT_TX_4_10	(DMA_CHAN_INTR_ENA_TIE)
 
 /* channel 0 specific fields */
 #define DMA_CHAN0_DBG_STAT_TPS		GENMASK(15, 12)
@@ -182,9 +189,10 @@
 #define DMA_CHAN0_DBG_STAT_RPS_SHIFT	8
 
 int dwmac4_dma_reset(void __iomem *ioaddr);
-void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan);
+void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
 void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan);
 void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan);
 void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/delay.h>
 #include "common.h"
 #include "dwmac4_dma.h"
@@ -14,22 +15,14 @@
 int dwmac4_dma_reset(void __iomem *ioaddr)
 {
 	u32 value = readl(ioaddr + DMA_BUS_MODE);
-	int limit;
 
 	/* DMA SW reset */
 	value |= DMA_BUS_MODE_SFT_RESET;
 	writel(value, ioaddr + DMA_BUS_MODE);
-	limit = 10;
-	while (limit--) {
-		if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
-			break;
-		mdelay(10);
-	}
 
-	if (limit < 0)
-		return -EBUSY;
-
-	return 0;
+	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+				 !(value & DMA_BUS_MODE_SFT_RESET),
+				 10000, 1000000);
 }
 
 void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
@@ -60,10 +53,6 @@
 
 	value &= ~DMA_CONTROL_ST;
 	writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
-
-	value = readl(ioaddr + GMAC_CONFIG);
-	value &= ~GMAC_CONFIG_TE;
-	writel(value, ioaddr + GMAC_CONFIG);
 }
 
 void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
@@ -97,21 +86,52 @@
 	writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
 }
 
-void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
 {
-	writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr +
-	       DMA_CHAN_INTR_ENA(chan));
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value |= DMA_CHAN_INTR_DEFAULT_RX;
+	if (tx)
+		value |= DMA_CHAN_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
-void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
 {
-	writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
-	       ioaddr + DMA_CHAN_INTR_ENA(chan));
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value |= DMA_CHAN_INTR_DEFAULT_RX_4_10;
+	if (tx)
+		value |= DMA_CHAN_INTR_DEFAULT_TX_4_10;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
-void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
 {
-	writel(0, ioaddr + DMA_CHAN_INTR_ENA(chan));
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value &= ~DMA_CHAN_INTR_DEFAULT_RX;
+	if (tx)
+		value &= ~DMA_CHAN_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
+void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10;
+	if (tx)
+		value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
 int dwmac4_dma_interrupt(void __iomem *ioaddr,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -520,9 +520,9 @@
 		return 0;
 	}
 
-	val |= PPSCMDx(index, 0x2);
 	val |= TRGTMODSELx(index, 0x2);
 	val |= PPSEN0;
+	writel(val, ioaddr + MAC_PPS_CONTROL);
 
 	writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
 
@@ -547,6 +547,82 @@
 	writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
 
 	/* Finally, activate it */
+	val |= PPSCMDx(index, 0x2);
 	writel(val, ioaddr + MAC_PPS_CONTROL);
 	return 0;
 }
+
+static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+	u32 ctrl;
+
+	writel(val, ioaddr + MTL_EST_GCL_DATA);
+
+	ctrl = (reg << ADDR_SHIFT);
+	ctrl |= gcl ? 0 : GCRR;
+
+	writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+	ctrl |= SRWO;
+	writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+	return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
+				  ctrl, !(ctrl & SRWO), 100, 5000);
+}
+
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+			 unsigned int ptp_rate)
+{
+	int i, ret = 0x0;
+	u32 ctrl;
+
+	ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
+	ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
+	ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
+	ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
+	ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
+	ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < cfg->gcl_size; i++) {
+		ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
+		if (ret)
+			return ret;
+	}
+
+	ctrl = readl(ioaddr + MTL_EST_CONTROL);
+	ctrl &= ~PTOV;
+	ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
+	if (cfg->enable)
+		ctrl |= EEST | SSWL;
+	else
+		ctrl &= ~EEST;
+
+	writel(ctrl, ioaddr + MTL_EST_CONTROL);
+	return 0;
+}
+
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+			  bool enable)
+{
+	u32 value;
+
+	if (!enable) {
+		value = readl(ioaddr + MAC_FPE_CTRL_STS);
+
+		value &= ~EFPE;
+
+		writel(value, ioaddr + MAC_FPE_CTRL_STS);
+		return;
+	}
+
+	value = readl(ioaddr + GMAC_RXQ_CTRL1);
+	value &= ~GMAC_RXQCTRL_FPRQ;
+	value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
+	writel(value, ioaddr + GMAC_RXQ_CTRL1);
+
+	value = readl(ioaddr + MAC_FPE_CTRL_STS);
+	value |= EFPE;
+	writel(value, ioaddr + MAC_FPE_CTRL_STS);
+}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -11,6 +11,9 @@
 #define PRTYEN				BIT(1)
 #define TMOUTEN				BIT(0)
 
+#define MAC_FPE_CTRL_STS		0x00000234
+#define EFPE				BIT(0)
+
 #define MAC_PPS_CONTROL			0x00000b70
 #define PPS_MAXIDX(x)			((((x) + 1) * 8) - 1)
 #define PPS_MINIDX(x)			((x) * 8)
@@ -30,6 +33,23 @@
 #define MAC_PPSx_INTERVAL(x)		(0x00000b88 + ((x) * 0x10))
 #define MAC_PPSx_WIDTH(x)		(0x00000b8c + ((x) * 0x10))
 
+#define MTL_EST_CONTROL			0x00000c50
+#define PTOV				GENMASK(31, 24)
+#define PTOV_SHIFT			24
+#define SSWL				BIT(1)
+#define EEST				BIT(0)
+#define MTL_EST_GCL_CONTROL		0x00000c80
+#define BTR_LOW				0x0
+#define BTR_HIGH			0x1
+#define CTR_LOW				0x2
+#define CTR_HIGH			0x3
+#define TER				0x4
+#define LLR				0x5
+#define ADDR_SHIFT			8
+#define GCRR				BIT(2)
+#define SRWO				BIT(0)
+#define MTL_EST_GCL_DATA		0x00000c84
+
 #define MTL_RXP_CONTROL_STATUS		0x00000ca0
 #define RXPI				BIT(31)
 #define NPE				GENMASK(23, 16)
@@ -83,5 +103,9 @@
 int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
 			   struct stmmac_pps_cfg *cfg, bool enable,
 			   u32 sub_second_inc, u32 systime_flags);
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+			 unsigned int ptp_rate);
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+			  bool enable);
 
 #endif /* __DWMAC5_H__ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -96,6 +96,8 @@
 
 /* DMA default interrupt mask */
 #define DMA_INTR_DEFAULT_MASK	(DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+#define DMA_INTR_DEFAULT_RX	(DMA_INTR_ENA_RIE)
+#define DMA_INTR_DEFAULT_TX	(DMA_INTR_ENA_TIE)
 
 /* DMA Status register defines */
 #define DMA_STATUS_GLPII	0x40000000	/* GMAC LPI interrupt */
@@ -128,10 +130,11 @@
 
 #define NUM_DWMAC100_DMA_REGS	9
 #define NUM_DWMAC1000_DMA_REGS	23
+#define NUM_DWMAC4_DMA_REGS	27
 
 void dwmac_enable_dma_transmission(void __iomem *ioaddr);
-void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan);
+void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
 void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan);
 void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan);
 void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -16,19 +16,14 @@
 int dwmac_dma_reset(void __iomem *ioaddr)
 {
 	u32 value = readl(ioaddr + DMA_BUS_MODE);
-	int err;
 
 	/* DMA SW reset */
 	value |= DMA_BUS_MODE_SFT_RESET;
 	writel(value, ioaddr + DMA_BUS_MODE);
 
-	err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
 				 !(value & DMA_BUS_MODE_SFT_RESET),
 				 10000, 100000);
-	if (err)
-		return -EBUSY;
-
-	return 0;
 }
 
 /* CSR1 enables the transmit DMA to check for new descriptor */
@@ -37,14 +32,28 @@
 	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
 }
 
-void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
 {
-	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+	if (rx)
+		value |= DMA_INTR_DEFAULT_RX;
+	if (tx)
+		value |= DMA_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_INTR_ENA);
 }
 
-void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
 {
-	writel(0, ioaddr + DMA_INTR_ENA);
+	u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+	if (rx)
+		value &= ~DMA_INTR_DEFAULT_RX;
+	if (tx)
+		value &= ~DMA_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_INTR_ENA);
 }
 
 void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -73,6 +73,9 @@
 #define XGMAC_RXQ_CTRL0			0x000000a0
 #define XGMAC_RXQEN(x)			GENMASK((x) * 2 + 1, (x) * 2)
 #define XGMAC_RXQEN_SHIFT(x)		((x) * 2)
+#define XGMAC_RXQ_CTRL1			0x000000a4
+#define XGMAC_RQ			GENMASK(7, 4)
+#define XGMAC_RQ_SHIFT			4
 #define XGMAC_RXQ_CTRL2			0x000000a8
 #define XGMAC_RXQ_CTRL3			0x000000ac
 #define XGMAC_PSRQ(x)			GENMASK((x) * 8 + 7, (x) * 8)
@@ -136,6 +139,10 @@
 #define XGMAC_HWFEAT_TXQCNT		GENMASK(9, 6)
 #define XGMAC_HWFEAT_RXQCNT		GENMASK(3, 0)
 #define XGMAC_HW_FEATURE3		0x00000128
+#define XGMAC_HWFEAT_FPESEL		BIT(26)
+#define XGMAC_HWFEAT_ESTWID		GENMASK(24, 23)
+#define XGMAC_HWFEAT_ESTDEP		GENMASK(22, 20)
+#define XGMAC_HWFEAT_ESTSEL		BIT(19)
 #define XGMAC_HWFEAT_ASP		GENMASK(15, 14)
 #define XGMAC_HWFEAT_DVLAN		BIT(13)
 #define XGMAC_HWFEAT_FRPES		GENMASK(12, 11)
@@ -148,6 +155,8 @@
 #define XGMAC_MDIO_ADDR			0x00000200
 #define XGMAC_MDIO_DATA			0x00000204
 #define XGMAC_MDIO_C22P			0x00000220
+#define XGMAC_FPE_CTRL_STS		0x00000280
+#define XGMAC_EFPE			BIT(0)
 #define XGMAC_ADDRx_HIGH(x)		(0x00000300 + (x) * 0x8)
 #define XGMAC_ADDR_MAX			32
 #define XGMAC_AE			BIT(31)
@@ -212,7 +221,7 @@
 	((val) << XGMAC_PPS_MINIDX(x))
 #define XGMAC_PPSCMD_START		0x2
 #define XGMAC_PPSCMD_STOP		0x5
-#define XGMAC_PPSEN0			BIT(4)
+#define XGMAC_PPSENx(x)			BIT(4 + (x) * 8)
 #define XGMAC_PPSx_TARGET_TIME_SEC(x)	(0x00000d80 + (x) * 0x10)
 #define XGMAC_PPSx_TARGET_TIME_NSEC(x)	(0x00000d84 + (x) * 0x10)
 #define XGMAC_TRGTBUSY0			BIT(31)
@@ -237,6 +246,22 @@
 #define XGMAC_TC_PRTY_MAP1		0x00001044
 #define XGMAC_PSTC(x)			GENMASK((x) * 8 + 7, (x) * 8)
 #define XGMAC_PSTC_SHIFT(x)		((x) * 8)
+#define XGMAC_MTL_EST_CONTROL		0x00001050
+#define XGMAC_PTOV			GENMASK(31, 23)
+#define XGMAC_PTOV_SHIFT		23
+#define XGMAC_SSWL			BIT(1)
+#define XGMAC_EEST			BIT(0)
+#define XGMAC_MTL_EST_GCL_CONTROL	0x00001080
+#define XGMAC_BTR_LOW			0x0
+#define XGMAC_BTR_HIGH			0x1
+#define XGMAC_CTR_LOW			0x2
+#define XGMAC_CTR_HIGH			0x3
+#define XGMAC_TER			0x4
+#define XGMAC_LLR			0x5
+#define XGMAC_ADDR_SHIFT		8
+#define XGMAC_GCRR			BIT(2)
+#define XGMAC_SRWO			BIT(0)
+#define XGMAC_MTL_EST_GCL_DATA		0x00001084
 #define XGMAC_MTL_RXP_CONTROL_STATUS	0x000010a0
 #define XGMAC_RXPI			BIT(31)
 #define XGMAC_NPE			GENMASK(23, 16)
@@ -256,6 +281,8 @@
 #define XGMAC_RXCEIE			BIT(4)
 #define XGMAC_TXCEIE			BIT(0)
 #define XGMAC_MTL_ECC_INT_STATUS	0x000010cc
+#define XGMAC_MTL_DPP_CONTROL		0x000010e0
+#define XGMAC_DPP_DISABLE		BIT(0)
 #define XGMAC_MTL_TXQ_OPMODE(x)		(0x00001100 + (0x80 * (x)))
 #define XGMAC_TQS			GENMASK(25, 16)
 #define XGMAC_TQS_SHIFT			16
@@ -331,6 +358,7 @@
 #define XGMAC_DCEIE			BIT(1)
 #define XGMAC_TCEIE			BIT(0)
 #define XGMAC_DMA_ECC_INT_STATUS	0x0000306c
+#define XGMAC_DMA_DPP_INT_STATUS	0x00003074
 #define XGMAC_DMA_CH_CONTROL(x)		(0x00003100 + (0x80 * (x)))
 #define XGMAC_SPH			BIT(24)
 #define XGMAC_PBLx8			BIT(16)
@@ -343,6 +371,8 @@
 #define XGMAC_DMA_CH_RX_CONTROL(x)	(0x00003108 + (0x80 * (x)))
 #define XGMAC_RxPBL			GENMASK(21, 16)
 #define XGMAC_RxPBL_SHIFT		16
+#define XGMAC_RBSZ			GENMASK(14, 1)
+#define XGMAC_RBSZ_SHIFT		1
 #define XGMAC_RXST			BIT(0)
 #define XGMAC_DMA_CH_TxDESC_HADDR(x)	(0x00003110 + (0x80 * (x)))
 #define XGMAC_DMA_CH_TxDESC_LADDR(x)	(0x00003114 + (0x80 * (x)))
@@ -361,6 +391,8 @@
 #define XGMAC_TIE			BIT(0)
 #define XGMAC_DMA_INT_DEFAULT_EN	(XGMAC_NIE | XGMAC_AIE | XGMAC_RBUE | \
 					XGMAC_RIE | XGMAC_TBUE | XGMAC_TIE)
+#define XGMAC_DMA_INT_DEFAULT_RX	(XGMAC_RBUE | XGMAC_RIE)
+#define XGMAC_DMA_INT_DEFAULT_TX	(XGMAC_TIE)
 #define XGMAC_DMA_CH_Rx_WATCHDOG(x)	(0x0000313c + (0x80 * (x)))
 #define XGMAC_RWT			GENMASK(7, 0)
 #define XGMAC_DMA_CH_STATUS(x)		(0x00003160 + (0x80 * (x)))
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -757,6 +757,44 @@
 	{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
 };
 
+#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error"
+#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error"
+
+static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = {
+	{ true, "TDPES0", DPP_TX_ERR },
+	{ true, "TDPES1", DPP_TX_ERR },
+	{ true, "TDPES2", DPP_TX_ERR },
+	{ true, "TDPES3", DPP_TX_ERR },
+	{ true, "TDPES4", DPP_TX_ERR },
+	{ true, "TDPES5", DPP_TX_ERR },
+	{ true, "TDPES6", DPP_TX_ERR },
+	{ true, "TDPES7", DPP_TX_ERR },
+	{ true, "TDPES8", DPP_TX_ERR },
+	{ true, "TDPES9", DPP_TX_ERR },
+	{ true, "TDPES10", DPP_TX_ERR },
+	{ true, "TDPES11", DPP_TX_ERR },
+	{ true, "TDPES12", DPP_TX_ERR },
+	{ true, "TDPES13", DPP_TX_ERR },
+	{ true, "TDPES14", DPP_TX_ERR },
+	{ true, "TDPES15", DPP_TX_ERR },
+	{ true, "RDPES0", DPP_RX_ERR },
+	{ true, "RDPES1", DPP_RX_ERR },
+	{ true, "RDPES2", DPP_RX_ERR },
+	{ true, "RDPES3", DPP_RX_ERR },
+	{ true, "RDPES4", DPP_RX_ERR },
+	{ true, "RDPES5", DPP_RX_ERR },
+	{ true, "RDPES6", DPP_RX_ERR },
+	{ true, "RDPES7", DPP_RX_ERR },
+	{ true, "RDPES8", DPP_RX_ERR },
+	{ true, "RDPES9", DPP_RX_ERR },
+	{ true, "RDPES10", DPP_RX_ERR },
+	{ true, "RDPES11", DPP_RX_ERR },
+	{ true, "RDPES12", DPP_RX_ERR },
+	{ true, "RDPES13", DPP_RX_ERR },
+	{ true, "RDPES14", DPP_RX_ERR },
+	{ true, "RDPES15", DPP_RX_ERR },
+};
+
 static void dwxgmac3_handle_dma_err(struct net_device *ndev,
 				    void __iomem *ioaddr, bool correctable,
 				    struct stmmac_safety_stats *stats)
@@ -768,6 +806,13 @@
 
 	dwxgmac3_log_error(ndev, value, correctable, "DMA",
 			   dwxgmac3_dma_errors, STAT_OFF(dma_errors), stats);
+
+	value = readl(ioaddr + XGMAC_DMA_DPP_INT_STATUS);
+	writel(value, ioaddr + XGMAC_DMA_DPP_INT_STATUS);
+
+	dwxgmac3_log_error(ndev, value, false, "DMA_DPP",
+			   dwxgmac3_dma_dpp_errors,
+			   STAT_OFF(dma_dpp_errors), stats);
 }
 
 static int dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
@@ -804,6 +849,12 @@
 	value |= XGMAC_TMOUTEN; /* FSM Timeout Feature */
 	writel(value, ioaddr + XGMAC_MAC_FSM_CONTROL);
 
+	/* 5. Enable Data Path Parity Protection */
+	value = readl(ioaddr + XGMAC_MTL_DPP_CONTROL);
+	/* already enabled by default, explicit enable it again */
+	value &= ~XGMAC_DPP_DISABLE;
+	writel(value, ioaddr + XGMAC_MTL_DPP_CONTROL);
+
 	return 0;
 }
 
@@ -837,7 +888,11 @@
 		ret |= !corr;
 	}
 
-	err = dma & (XGMAC_DEUIS | XGMAC_DECIS);
+	/* DMA_DPP_Interrupt_Status is indicated by MCSIS bit in
+	 * DMA_Safety_Interrupt_Status, so we handle DMA Data Path
+	 * Parity Errors here
+	 */
+	err = dma & (XGMAC_DEUIS | XGMAC_DECIS | XGMAC_MCSIS);
 	corr = dma & XGMAC_DECIS;
 	if (err) {
 		dwxgmac3_handle_dma_err(ndev, ioaddr, corr, stats);
@@ -853,6 +908,7 @@
 	{ dwxgmac3_mac_errors },
 	{ dwxgmac3_mtl_errors },
 	{ dwxgmac3_dma_errors },
+	{ dwxgmac3_dma_dpp_errors },
 };
 
 static int dwxgmac3_safety_feat_dump(struct stmmac_safety_stats *stats,
@@ -1101,7 +1157,19 @@
 
 	val |= XGMAC_PPSCMDx(index, XGMAC_PPSCMD_START);
 	val |= XGMAC_TRGTMODSELx(index, XGMAC_PPSCMD_START);
-	val |= XGMAC_PPSEN0;
+
+	/* XGMAC Core has 4 PPS outputs at most.
+	 *
+	 * Prior XGMAC Core 3.20, Fixed mode or Flexible mode are selectable for
+	 * PPS0 only via PPSEN0. PPS{1,2,3} are in Flexible mode by default,
+	 * and can not be switched to Fixed mode, since PPSEN{1,2,3} are
+	 * read-only reserved to 0.
+	 * But we always set PPSEN{1,2,3} do not make things worse ;-)
+	 *
+	 * From XGMAC Core 3.20 and later, PPSEN{0,1,2,3} are writable and must
+	 * be set, or the PPS outputs stay in Fixed PPS mode by default.
+	 */
+	val |= XGMAC_PPSENx(index);
 
 	writel(cfg->start.tv_sec, ioaddr + XGMAC_PPSx_TARGET_TIME_SEC(index));
 
@@ -1344,6 +1412,81 @@
 	writel(value, ioaddr + XGMAC_RX_CONFIG);
 }
 
+static int dwxgmac3_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+	u32 ctrl;
+
+	writel(val, ioaddr + XGMAC_MTL_EST_GCL_DATA);
+
+	ctrl = (reg << XGMAC_ADDR_SHIFT);
+	ctrl |= gcl ? 0 : XGMAC_GCRR;
+
+	writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+	ctrl |= XGMAC_SRWO;
+	writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+	return readl_poll_timeout_atomic(ioaddr + XGMAC_MTL_EST_GCL_CONTROL,
+					 ctrl, !(ctrl & XGMAC_SRWO), 100, 5000);
+}
+
+static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+				  unsigned int ptp_rate)
+{
+	int i, ret = 0x0;
+	u32 ctrl;
+
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_LOW, cfg->btr[0], false);
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_HIGH, cfg->btr[1], false);
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_TER, cfg->ter, false);
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_LLR, cfg->gcl_size, false);
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_LOW, cfg->ctr[0], false);
+	ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_HIGH, cfg->ctr[1], false);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < cfg->gcl_size; i++) {
+		ret = dwxgmac3_est_write(ioaddr, i, cfg->gcl[i], true);
+		if (ret)
+			return ret;
+	}
+
+	ctrl = readl(ioaddr + XGMAC_MTL_EST_CONTROL);
+	ctrl &= ~XGMAC_PTOV;
+	ctrl |= ((1000000000 / ptp_rate) * 9) << XGMAC_PTOV_SHIFT;
+	if (cfg->enable)
+		ctrl |= XGMAC_EEST | XGMAC_SSWL;
+	else
+		ctrl &= ~XGMAC_EEST;
+
+	writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL);
+	return 0;
+}
+
+static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq,
+				   u32 num_rxq, bool enable)
+{
+	u32 value;
+
+	if (!enable) {
+		value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+
+		value &= ~XGMAC_EFPE;
+
+		writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+		return;
+	}
+
+	value = readl(ioaddr + XGMAC_RXQ_CTRL1);
+	value &= ~XGMAC_RQ;
+	value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
+	writel(value, ioaddr + XGMAC_RXQ_CTRL1);
+
+	value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+	value |= XGMAC_EFPE;
+	writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+}
+
 const struct stmmac_ops dwxgmac210_ops = {
 	.core_init = dwxgmac2_core_init,
 	.set_mac = dwxgmac2_set_mac,
@@ -1387,6 +1530,8 @@
 	.config_l3_filter = dwxgmac2_config_l3_filter,
 	.config_l4_filter = dwxgmac2_config_l4_filter,
 	.set_arp_offload = dwxgmac2_set_arp_offload,
+	.est_configure = dwxgmac3_est_configure,
+	.fpe_configure = dwxgmac3_fpe_configure,
 };
 
 int dwxgmac2_setup(struct stmmac_priv *priv)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -255,14 +255,30 @@
 	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
 }
 
-static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan,
+				    bool rx, bool tx)
 {
-	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+
+	if (rx)
+		value |= XGMAC_DMA_INT_DEFAULT_RX;
+	if (tx)
+		value |= XGMAC_DMA_INT_DEFAULT_TX;
+
+	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 }
 
-static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan,
+				     bool rx, bool tx)
 {
-	writel(0, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+
+	if (rx)
+		value &= ~XGMAC_DMA_INT_DEFAULT_RX;
+	if (tx)
+		value &= ~XGMAC_DMA_INT_DEFAULT_TX;
+
+	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 }
 
 static void dwxgmac2_dma_start_tx(void __iomem *ioaddr, u32 chan)
@@ -356,8 +372,8 @@
 	return ret;
 }
 
-static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
-				    struct dma_features *dma_cap)
+static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
+				   struct dma_features *dma_cap)
 {
 	u32 hw_cap;
 
@@ -420,11 +436,17 @@
 
 	/* MAC HW feature 3 */
 	hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
+	dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
+	dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
+	dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
+	dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
 	dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
 	dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
 	dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
 	dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
 	dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
+
+	return 0;
 }
 
 static void dwxgmac2_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 nchan)
@@ -489,7 +511,8 @@
 	u32 value;
 
 	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
-	value |= bfsize << 1;
+	value &= ~XGMAC_RBSZ;
+	value |= bfsize << XGMAC_RBSZ_SHIFT;
 	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -187,8 +187,10 @@
 	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
 				   void __iomem *ioaddr);
 	void (*enable_dma_transmission) (void __iomem *ioaddr);
-	void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan);
-	void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan);
+	void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan,
+			       bool rx, bool tx);
+	void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan,
+				bool rx, bool tx);
 	void (*start_tx)(void __iomem *ioaddr, u32 chan);
 	void (*stop_tx)(void __iomem *ioaddr, u32 chan);
 	void (*start_rx)(void __iomem *ioaddr, u32 chan);
@@ -196,8 +198,8 @@
 	int (*dma_interrupt) (void __iomem *ioaddr,
 			      struct stmmac_extra_stats *x, u32 chan);
 	/* If supported then get the optional core features */
-	void (*get_hw_feature)(void __iomem *ioaddr,
-			       struct dma_features *dma_cap);
+	int (*get_hw_feature)(void __iomem *ioaddr,
+			      struct dma_features *dma_cap);
 	/* Program the HW RX Watchdog */
 	void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt, u32 number_chan);
 	void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
@@ -247,7 +249,7 @@
 #define stmmac_dma_interrupt_status(__priv, __args...) \
 	stmmac_do_callback(__priv, dma, dma_interrupt, __args)
 #define stmmac_get_hw_feature(__priv, __args...) \
-	stmmac_do_void_callback(__priv, dma, get_hw_feature, __args)
+	stmmac_do_callback(__priv, dma, get_hw_feature, __args)
 #define stmmac_rx_watchdog(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, rx_watchdog, __args)
 #define stmmac_set_tx_ring_len(__priv, __args...) \
@@ -274,6 +276,7 @@
 struct stmmac_tc_entry;
 struct stmmac_pps_cfg;
 struct stmmac_rss;
+struct stmmac_est;
 
 /* Helpers to program the MAC core */
 struct stmmac_ops {
@@ -371,6 +374,10 @@
 				bool en, bool udp, bool sa, bool inv,
 				u32 match);
 	void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
+	int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
+			     unsigned int ptp_rate);
+	void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+			      bool enable);
 };
 
 #define stmmac_core_init(__priv, __args...) \
@@ -457,6 +464,10 @@
 	stmmac_do_callback(__priv, mac, config_l4_filter, __args)
 #define stmmac_set_arp_offload(__priv, __args...) \
 	stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
+#define stmmac_est_configure(__priv, __args...) \
+	stmmac_do_callback(__priv, mac, est_configure, __args)
+#define stmmac_fpe_configure(__priv, __args...) \
+	stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
 
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
@@ -514,6 +525,7 @@
 struct tc_cls_u32_offload;
 struct tc_cbs_qopt_offload;
 struct flow_cls_offload;
+struct tc_taprio_qopt_offload;
 
 struct stmmac_tc_ops {
 	int (*init)(struct stmmac_priv *priv);
@@ -523,6 +535,8 @@
 			 struct tc_cbs_qopt_offload *qopt);
 	int (*setup_cls)(struct stmmac_priv *priv,
 			 struct flow_cls_offload *cls);
+	int (*setup_taprio)(struct stmmac_priv *priv,
+			    struct tc_taprio_qopt_offload *qopt);
 };
 
 #define stmmac_tc_init(__priv, __args...) \
@@ -533,6 +547,8 @@
 	stmmac_do_callback(__priv, tc, setup_cbs, __args)
 #define stmmac_tc_setup_cls(__priv, __args...) \
 	stmmac_do_callback(__priv, tc, setup_cls, __args)
+#define stmmac_tc_setup_taprio(__priv, __args...) \
+	stmmac_do_callback(__priv, tc, setup_taprio, __args)
 
 struct stmmac_counters;
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -119,6 +119,13 @@
 #define MMC_RX_ICMP_GD_OCTETS		0x180
 #define MMC_RX_ICMP_ERR_OCTETS		0x184
 
+#define MMC_TX_FPE_FRAG			0x1a8
+#define MMC_TX_HOLD_REQ			0x1ac
+#define MMC_RX_PKT_ASSEMBLY_ERR		0x1c8
+#define MMC_RX_PKT_SMD_ERR		0x1cc
+#define MMC_RX_PKT_ASSEMBLY_OK		0x1d0
+#define MMC_RX_FPE_FRAG			0x1d4
+
 /* XGMAC MMC Registers */
 #define MMC_XGMAC_TX_OCTET_GB		0x14
 #define MMC_XGMAC_TX_PKT_GB		0x1c
@@ -170,8 +177,10 @@
 #define MMC_XGMAC_RX_DISCARD_OCT_GB	0x1b4
 #define MMC_XGMAC_RX_ALIGN_ERR_PKT	0x1bc
 
+#define MMC_XGMAC_TX_FPE_INTR_MASK	0x204
 #define MMC_XGMAC_TX_FPE_FRAG		0x208
 #define MMC_XGMAC_TX_HOLD_REQ		0x20c
+#define MMC_XGMAC_RX_FPE_INTR_MASK	0x224
 #define MMC_XGMAC_RX_PKT_ASSEMBLY_ERR	0x228
 #define MMC_XGMAC_RX_PKT_SMD_ERR	0x22c
 #define MMC_XGMAC_RX_PKT_ASSEMBLY_OK	0x230
@@ -315,6 +324,15 @@
 	mmc->mmc_rx_tcp_err_octets += readl(mmcaddr + MMC_RX_TCP_ERR_OCTETS);
 	mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
 	mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
+
+	mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_TX_FPE_FRAG);
+	mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_TX_HOLD_REQ);
+	mmc->mmc_rx_packet_assembly_err_cntr +=
+		readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_ERR);
+	mmc->mmc_rx_packet_smd_err_cntr += readl(mmcaddr + MMC_RX_PKT_SMD_ERR);
+	mmc->mmc_rx_packet_assembly_ok_cntr +=
+		readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_OK);
+	mmc->mmc_rx_fpe_fragment_cntr += readl(mmcaddr + MMC_RX_FPE_FRAG);
 }
 
 const struct stmmac_mmc_ops dwmac_mmc_ops = {
@@ -336,6 +354,8 @@
 {
 	writel(0x0, mmcaddr + MMC_RX_INTR_MASK);
 	writel(0x0, mmcaddr + MMC_TX_INTR_MASK);
+	writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_TX_FPE_INTR_MASK);
+	writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_FPE_INTR_MASK);
 	writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_IPC_INTR_MASK);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -88,6 +88,7 @@
 	struct napi_struct rx_napi ____cacheline_aligned_in_smp;
 	struct napi_struct tx_napi ____cacheline_aligned_in_smp;
 	struct stmmac_priv *priv_data;
+	spinlock_t lock;
 	u32 index;
 };
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -21,10 +21,18 @@
 #include "dwxgmac2.h"
 
 #define REG_SPACE_SIZE	0x1060
+#define GMAC4_REG_SPACE_SIZE	0x116C
 #define MAC100_ETHTOOL_NAME	"st_mac100"
 #define GMAC_ETHTOOL_NAME	"st_gmac"
 #define XGMAC_ETHTOOL_NAME	"st_xgmac"
 
+/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h
+ *
+ * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the
+ * same time due to the conflicting macro names.
+ */
+#define GMAC4_DMA_CHAN_BASE_ADDR  0x00001100
+
 #define ETHTOOL_DMA_OFFSET	55
 
 struct stmmac_stats {
@@ -413,6 +421,8 @@
 
 	if (priv->plat->has_xgmac)
 		return XGMAC_REGSIZE * 4;
+	else if (priv->plat->has_gmac4)
+		return GMAC4_REG_SPACE_SIZE;
 	return REG_SPACE_SIZE;
 }
 
@@ -425,8 +435,13 @@
 	stmmac_dump_mac_regs(priv, priv->hw, reg_space);
 	stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
 
-	if (!priv->plat->has_xgmac) {
-		/* Copy DMA registers to where ethtool expects them */
+	/* Copy DMA registers to where ethtool expects them */
+	if (priv->plat->has_gmac4) {
+		/* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */
+		memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
+		       &reg_space[GMAC4_DMA_CHAN_BASE_ADDR / 4],
+		       NUM_DWMAC4_DMA_REGS * 4);
+	} else if (!priv->plat->has_xgmac) {
 		memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
 		       &reg_space[DMA_BUS_MODE / 4],
 		       NUM_DWMAC1000_DMA_REGS * 4);
@@ -600,9 +615,14 @@
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
+	if (!priv->plat->pmt)
+		return phylink_ethtool_get_wol(priv->phylink, wol);
+
 	mutex_lock(&priv->lock);
 	if (device_can_wakeup(priv->device)) {
 		wol->supported = WAKE_MAGIC | WAKE_UCAST;
+		if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame)
+			wol->supported &= ~WAKE_MAGIC;
 		wol->wolopts = priv->wolopts;
 	}
 	mutex_unlock(&priv->lock);
@@ -613,15 +633,23 @@
 	struct stmmac_priv *priv = netdev_priv(dev);
 	u32 support = WAKE_MAGIC | WAKE_UCAST;
 
+	if (!device_can_wakeup(priv->device))
+		return -EOPNOTSUPP;
+
+	if (!priv->plat->pmt) {
+		int ret = phylink_ethtool_set_wol(priv->phylink, wol);
+
+		if (!ret)
+			device_set_wakeup_enable(priv->device, !!wol->wolopts);
+		return ret;
+	}
+
 	/* By default almost all GMAC devices support the WoL via
 	 * magic frame but we can disable it if the HW capability
 	 * register shows no support for pmt_magic_frame. */
 	if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
 		wol->wolopts &= ~WAKE_MAGIC;
 
-	if (!device_can_wakeup(priv->device))
-		return -EINVAL;
-
 	if (wol->wolopts & ~support)
 		return -EINVAL;
 
@@ -662,23 +690,16 @@
 	struct stmmac_priv *priv = netdev_priv(dev);
 	int ret;
 
-	if (!edata->eee_enabled) {
+	if (!priv->dma_cap.eee)
+		return -EOPNOTSUPP;
+
+	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.
-		 */
-		edata->eee_enabled = stmmac_eee_init(priv);
-		if (!edata->eee_enabled)
-			return -EOPNOTSUPP;
-	}
 
 	ret = phylink_ethtool_set_eee(priv->phylink, edata);
 	if (ret)
 		return ret;
 
-	priv->eee_enabled = edata->eee_enabled;
 	priv->tx_lpi_timer = edata->tx_lpi_timer;
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -10,6 +10,7 @@
 *******************************************************************************/
 
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/delay.h>
 #include "common.h"
 #include "stmmac_ptp.h"
@@ -26,12 +27,16 @@
 	unsigned long data;
 	u32 reg_value;
 
-	/* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
-	 *	formula = (1/ptp_clock) * 1000000000
-	 * where ptp_clock is 50MHz if fine method is used to update system
+	/* For GMAC3.x, 4.x versions, in "fine adjustement mode" set sub-second
+	 * increment to twice the number of nanoseconds of a clock cycle.
+	 * The calculation of the default_addend value by the caller will set it
+	 * to mid-range = 2^31 when the remainder of this division is zero,
+	 * which will make the accumulator overflow once every 2 ptp_clock
+	 * cycles, adding twice the number of nanoseconds of a clock cycle :
+	 * 2000000000ULL / ptp_clock.
 	 */
 	if (value & PTP_TCR_TSCFUPDT)
-		data = (1000000000ULL / 50000000);
+		data = (2000000000ULL / ptp_clock);
 	else
 		data = (1000000000ULL / ptp_clock);
 
@@ -39,7 +44,8 @@
 	if (!(value & PTP_TCR_TSCTRLSSR))
 		data = (data * 1000) / 465;
 
-	data &= PTP_SSIR_SSINC_MASK;
+	if (data > PTP_SSIR_SSINC_MAX)
+		data = PTP_SSIR_SSINC_MAX;
 
 	reg_value = data;
 	if (gmac4)
@@ -53,7 +59,6 @@
 
 static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
 {
-	int limit;
 	u32 value;
 
 	writel(sec, ioaddr + PTP_STSUR);
@@ -64,16 +69,9 @@
 	writel(value, ioaddr + PTP_TCR);
 
 	/* wait for present system time initialize to complete */
-	limit = 10;
-	while (limit--) {
-		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
-			break;
-		mdelay(10);
-	}
-	if (limit < 0)
-		return -EBUSY;
-
-	return 0;
+	return readl_poll_timeout(ioaddr + PTP_TCR, value,
+				 !(value & PTP_TCR_TSINIT),
+				 10000, 100000);
 }
 
 static int config_addend(void __iomem *ioaddr, u32 addend)
@@ -145,15 +143,20 @@
 
 static void get_systime(void __iomem *ioaddr, u64 *systime)
 {
-	u64 ns;
+	u64 ns, sec0, sec1;
 
-	/* Get the TSSS value */
-	ns = readl(ioaddr + PTP_STNSR);
-	/* Get the TSS and convert sec time value to nanosecond */
-	ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
+	/* Get the TSS value */
+	sec1 = readl_relaxed(ioaddr + PTP_STSR);
+	do {
+		sec0 = sec1;
+		/* Get the TSSS value */
+		ns = readl_relaxed(ioaddr + PTP_STNSR);
+		/* Get the TSS value */
+		sec1 = readl_relaxed(ioaddr + PTP_STSR);
+	} while (sec0 != sec1);
 
 	if (systime)
-		*systime = ns;
+		*systime = ns + (sec1 * 1000000000ULL);
 }
 
 const struct stmmac_hwtimestamp stmmac_ptp = {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -45,7 +45,7 @@
 #include "dwxgmac2.h"
 #include "hwif.h"
 
-#define	STMMAC_ALIGN(x)		__ALIGN_KERNEL(x, SMP_CACHE_BYTES)
+#define	STMMAC_ALIGN(x)		ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)
 #define	TSO_MAX_BUFF_SIZE	(SZ_16K - 1)
 
 /* Module parameters */
@@ -105,12 +105,34 @@
 static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
 
 #ifdef CONFIG_DEBUG_FS
+static const struct net_device_ops stmmac_netdev_ops;
 static void stmmac_init_fs(struct net_device *dev);
 static void stmmac_exit_fs(struct net_device *dev);
 #endif
 
 #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
 
+static int stmmac_bus_clks_enable(struct stmmac_priv *priv, bool enabled)
+{
+	int ret = 0;
+
+	if (enabled) {
+		ret = clk_prepare_enable(priv->plat->stmmac_clk);
+		if (ret)
+			return ret;
+		ret = clk_prepare_enable(priv->plat->pclk);
+		if (ret) {
+			clk_disable_unprepare(priv->plat->stmmac_clk);
+			return ret;
+		}
+	} else {
+		clk_disable_unprepare(priv->plat->stmmac_clk);
+		clk_disable_unprepare(priv->plat->pclk);
+	}
+
+	return ret;
+}
+
 /**
  * stmmac_verify_args - verify the driver parameters.
  * Description: it checks the driver parameters and set a default in case of
@@ -174,32 +196,6 @@
 	}
 }
 
-/**
- * stmmac_stop_all_queues - Stop all queues
- * @priv: driver private structure
- */
-static void stmmac_stop_all_queues(struct stmmac_priv *priv)
-{
-	u32 tx_queues_cnt = priv->plat->tx_queues_to_use;
-	u32 queue;
-
-	for (queue = 0; queue < tx_queues_cnt; queue++)
-		netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
-}
-
-/**
- * stmmac_start_all_queues - Start all queues
- * @priv: driver private structure
- */
-static void stmmac_start_all_queues(struct stmmac_priv *priv)
-{
-	u32 tx_queues_cnt = priv->plat->tx_queues_to_use;
-	u32 queue;
-
-	for (queue = 0; queue < tx_queues_cnt; queue++)
-		netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue));
-}
-
 static void stmmac_service_event_schedule(struct stmmac_priv *priv)
 {
 	if (!test_bit(STMMAC_DOWN, &priv->state) &&
@@ -250,7 +246,7 @@
 			priv->clk_csr = STMMAC_CSR_100_150M;
 		else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
 			priv->clk_csr = STMMAC_CSR_150_250M;
-		else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
+		else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M))
 			priv->clk_csr = STMMAC_CSR_250_300M;
 	}
 
@@ -386,9 +382,8 @@
 	/* Using PCS we cannot dial with the phy registers at this stage
 	 * so we do not support extra feature like EEE.
 	 */
-	if ((priv->hw->pcs == STMMAC_PCS_RGMII) ||
-	    (priv->hw->pcs == STMMAC_PCS_TBI) ||
-	    (priv->hw->pcs == STMMAC_PCS_RTBI))
+	if (priv->hw->pcs == STMMAC_PCS_TBI ||
+	    priv->hw->pcs == STMMAC_PCS_RTBI)
 		return false;
 
 	/* Check if MAC core supports the EEE feature. */
@@ -629,7 +624,8 @@
 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 			ptp_v2 = PTP_TCR_TSVER2ENA;
 			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
-			ts_event_en = PTP_TCR_TSEVNTENA;
+			if (priv->synopsys_id < DWMAC_CORE_4_10)
+				ts_event_en = PTP_TCR_TSEVNTENA;
 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
 			ptp_over_ethernet = PTP_TCR_TSIPENA;
@@ -956,7 +952,8 @@
 
 	stmmac_mac_set(priv, priv->ioaddr, true);
 	if (phy && priv->dma_cap.eee) {
-		priv->eee_active = phy_init_eee(phy, 1) >= 0;
+		priv->eee_active =
+			phy_init_eee(phy, !priv->plat->rx_clk_runs_in_lpi) >= 0;
 		priv->eee_enabled = stmmac_eee_init(priv);
 		stmmac_set_eee_pls(priv, priv->hw, true);
 	}
@@ -1006,6 +1003,7 @@
  */
 static int stmmac_init_phy(struct net_device *dev)
 {
+	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
 	struct stmmac_priv *priv = netdev_priv(dev);
 	struct device_node *node;
 	int ret;
@@ -1022,6 +1020,11 @@
 		int addr = priv->plat->phy_addr;
 		struct phy_device *phydev;
 
+		if (addr < 0) {
+			netdev_err(priv->dev, "no phy found\n");
+			return -ENODEV;
+		}
+
 		phydev = mdiobus_get_phy(priv->mii, addr);
 		if (!phydev) {
 			netdev_err(priv->dev, "no phy at addr %d\n", addr);
@@ -1031,6 +1034,9 @@
 		ret = phylink_connect_phy(priv->phylink, phydev);
 	}
 
+	phylink_ethtool_get_wol(priv->phylink, &wol);
+	device_set_wakeup_capable(priv->device, !!wol.supported);
+
 	return ret;
 }
 
@@ -1108,7 +1114,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;
@@ -1292,19 +1300,9 @@
 	struct stmmac_priv *priv = netdev_priv(dev);
 	u32 rx_count = priv->plat->rx_queues_to_use;
 	int ret = -ENOMEM;
-	int bfsize = 0;
 	int queue;
 	int i;
 
-	bfsize = stmmac_set_16kib_bfsize(priv, dev->mtu);
-	if (bfsize < 0)
-		bfsize = 0;
-
-	if (bfsize < BUF_SIZE_16KiB)
-		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
-
-	priv->dma_buf_sz = bfsize;
-
 	/* RX INITIALIZATION */
 	netif_dbg(priv, probe, priv->dev,
 		  "SKB addresses:\nskb\t\tskb data\tdma data\n");
@@ -1346,8 +1344,6 @@
 		}
 	}
 
-	buf_sz = bfsize;
-
 	return 0;
 
 err_init_rx_buffers:
@@ -1476,6 +1472,19 @@
 }
 
 /**
+ * stmmac_free_tx_skbufs - free TX skb buffers
+ * @priv: private structure
+ */
+static void stmmac_free_tx_skbufs(struct stmmac_priv *priv)
+{
+	u32 tx_queue_cnt = priv->plat->tx_queues_to_use;
+	u32 queue;
+
+	for (queue = 0; queue < tx_queue_cnt; queue++)
+		dma_free_tx_skbufs(priv, queue);
+}
+
+/**
  * free_dma_rx_desc_resources - free RX dma desc resources
  * @priv: private structure
  */
@@ -1502,10 +1511,8 @@
 					  rx_q->dma_erx, rx_q->dma_rx_phy);
 
 		kfree(rx_q->buf_pool);
-		if (rx_q->page_pool) {
-			page_pool_request_shutdown(rx_q->page_pool);
+		if (rx_q->page_pool)
 			page_pool_destroy(rx_q->page_pool);
-		}
 	}
 }
 
@@ -1976,7 +1983,7 @@
 
 	/* We still have pending packets, let's call for a new scheduling */
 	if (tx_q->dirty_tx != tx_q->cur_tx)
-		mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(10));
+		mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer));
 
 	__netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
 
@@ -2010,6 +2017,8 @@
 	tx_q->cur_tx = 0;
 	tx_q->mss = 0;
 	netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, chan));
+	stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+			    tx_q->dma_tx_phy, chan);
 	stmmac_start_tx_dma(priv, chan);
 
 	priv->dev->stats.tx_errors++;
@@ -2068,17 +2077,25 @@
 	int status = stmmac_dma_interrupt_status(priv, priv->ioaddr,
 						 &priv->xstats, chan);
 	struct stmmac_channel *ch = &priv->channel[chan];
+	unsigned long flags;
 
 	if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) {
 		if (napi_schedule_prep(&ch->rx_napi)) {
-			stmmac_disable_dma_irq(priv, priv->ioaddr, chan);
+			spin_lock_irqsave(&ch->lock, flags);
+			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+			spin_unlock_irqrestore(&ch->lock, flags);
 			__napi_schedule_irqoff(&ch->rx_napi);
-			status |= handle_tx;
 		}
 	}
 
-	if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use))
-		napi_schedule_irqoff(&ch->tx_napi);
+	if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) {
+		if (napi_schedule_prep(&ch->tx_napi)) {
+			spin_lock_irqsave(&ch->lock, flags);
+			stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+			spin_unlock_irqrestore(&ch->lock, flags);
+			__napi_schedule_irqoff(&ch->tx_napi);
+		}
+	}
 
 	return status;
 }
@@ -2273,14 +2290,14 @@
 
 	ch = &priv->channel[tx_q->queue_index];
 
-	/*
-	 * If NAPI is already running we can miss some events. Let's rearm
-	 * the timer and try again.
-	 */
-	if (likely(napi_schedule_prep(&ch->tx_napi)))
+	if (likely(napi_schedule_prep(&ch->tx_napi))) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ch->lock, flags);
+		stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, 0, 1);
+		spin_unlock_irqrestore(&ch->lock, flags);
 		__napi_schedule(&ch->tx_napi);
-	else
-		mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(10));
+	}
 }
 
 /**
@@ -2656,9 +2673,17 @@
 static int stmmac_open(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
+	struct platform_device *pdev = to_platform_device(priv->device);
+	int bfsize = 0;
 	u32 chan;
 	int ret;
 
+	ret = stmmac_bus_clks_enable(priv, true);
+	if (ret)
+		return ret;
+	if (priv->plat->init)
+		priv->plat->init(pdev, priv->plat->bsp_priv);
+
 	if (priv->hw->pcs != STMMAC_PCS_RGMII &&
 	    priv->hw->pcs != STMMAC_PCS_TBI &&
 	    priv->hw->pcs != STMMAC_PCS_RTBI) {
@@ -2675,7 +2700,16 @@
 	memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
 	priv->xstats.threshold = tc;
 
-	priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
+	bfsize = stmmac_set_16kib_bfsize(priv, dev->mtu);
+	if (bfsize < 0)
+		bfsize = 0;
+
+	if (bfsize < BUF_SIZE_16KiB)
+		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
+
+	priv->dma_buf_sz = bfsize;
+	buf_sz = bfsize;
+
 	priv->rx_copybreak = STMMAC_RX_COPYBREAK;
 
 	ret = alloc_dma_desc_resources(priv);
@@ -2737,7 +2771,7 @@
 	}
 
 	stmmac_enable_all_queues(priv);
-	stmmac_start_all_queues(priv);
+	netif_tx_start_all_queues(priv->dev);
 
 	return 0;
 
@@ -2769,17 +2803,14 @@
 static int stmmac_release(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
-	u32 chan;
+	struct platform_device *pdev = to_platform_device(priv->device);
 
-	if (priv->eee_enabled)
-		del_timer_sync(&priv->eee_ctrl_timer);
+	u32 chan;
 
 	/* Stop and disconnect the PHY */
 	phylink_stop(priv->phylink);
 	phylink_disconnect_phy(priv->phylink);
 
-	stmmac_stop_all_queues(priv);
-
 	stmmac_disable_all_queues(priv);
 
 	for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
@@ -2792,6 +2823,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 */
 	stmmac_stop_all_dma(priv);
 
@@ -2805,6 +2841,10 @@
 
 	stmmac_release_ptp(priv);
 
+	if (priv->plat->exit)
+		priv->plat->exit(pdev, priv->plat->bsp_priv);
+	stmmac_bus_clks_enable(priv, false);
+
 	return 0;
 }
 
@@ -3105,6 +3145,7 @@
 
 	tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * sizeof(*desc));
 	stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
+	stmmac_tx_timer_arm(priv, queue);
 
 	return NETDEV_TX_OK;
 
@@ -3332,6 +3373,7 @@
 
 	tx_q->tx_tail_addr = tx_q->dma_tx_phy + (tx_q->cur_tx * sizeof(*desc));
 	stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr, queue);
+	stmmac_tx_timer_arm(priv, queue);
 
 	return NETDEV_TX_OK;
 
@@ -3443,6 +3485,55 @@
 	stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue);
 }
 
+static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv,
+				       struct dma_desc *p,
+				       int status, unsigned int len)
+{
+	int ret, coe = priv->hw->rx_csum;
+	unsigned int plen = 0, hlen = 0;
+
+	/* Not first descriptor, buffer is always zero */
+	if (priv->sph && len)
+		return 0;
+
+	/* First descriptor, get split header length */
+	ret = stmmac_get_rx_header_len(priv, p, &hlen);
+	if (priv->sph && hlen) {
+		priv->xstats.rx_split_hdr_pkt_n++;
+		return hlen;
+	}
+
+	/* First descriptor, not last descriptor and not split header */
+	if (status & rx_not_ls)
+		return priv->dma_buf_sz;
+
+	plen = stmmac_get_rx_frame_len(priv, p, coe);
+
+	/* First descriptor and last descriptor and not split header */
+	return min_t(unsigned int, priv->dma_buf_sz, plen);
+}
+
+static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
+				       struct dma_desc *p,
+				       int status, unsigned int len)
+{
+	int coe = priv->hw->rx_csum;
+	unsigned int plen = 0;
+
+	/* Not split header, buffer is not available */
+	if (!priv->sph)
+		return 0;
+
+	/* Not last descriptor */
+	if (status & rx_not_ls)
+		return priv->dma_buf_sz;
+
+	plen = stmmac_get_rx_frame_len(priv, p, coe);
+
+	/* Last descriptor */
+	return plen - len;
+}
+
 /**
  * stmmac_rx - manage the receive process
  * @priv: driver private structure
@@ -3472,11 +3563,10 @@
 		stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
 	}
 	while (count < limit) {
-		unsigned int hlen = 0, prev_len = 0;
+		unsigned int buf1_len = 0, buf2_len = 0;
 		enum pkt_hash_types hash_type;
 		struct stmmac_rx_buffer *buf;
 		struct dma_desc *np, *p;
-		unsigned int sec_len;
 		int entry;
 		u32 hash;
 
@@ -3491,11 +3581,12 @@
 			len = 0;
 		}
 
+read_again:
 		if (count >= limit)
 			break;
 
-read_again:
-		sec_len = 0;
+		buf1_len = 0;
+		buf2_len = 0;
 		entry = next_entry;
 		buf = &rx_q->buf_pool[entry];
 
@@ -3520,7 +3611,6 @@
 			np = rx_q->dma_rx + next_entry;
 
 		prefetch(np);
-		prefetch(page_address(buf->page));
 
 		if (priv->extend_desc)
 			stmmac_rx_extended_status(priv, &priv->dev->stats,
@@ -3537,69 +3627,61 @@
 			goto read_again;
 		if (unlikely(error)) {
 			dev_kfree_skb(skb);
+			skb = NULL;
 			count++;
 			continue;
 		}
 
 		/* Buffer is good. Go on. */
 
-		if (likely(status & rx_not_ls)) {
-			len += priv->dma_buf_sz;
-		} else {
-			prev_len = len;
-			len = stmmac_get_rx_frame_len(priv, p, coe);
+		prefetch(page_address(buf->page));
+		if (buf->sec_page)
+			prefetch(page_address(buf->sec_page));
 
-			/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
-			 * Type frames (LLC/LLC-SNAP)
-			 *
-			 * llc_snap is never checked in GMAC >= 4, so this ACS
-			 * feature is always disabled and packets need to be
-			 * stripped manually.
-			 */
-			if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
-			    unlikely(status != llc_snap))
-				len -= ETH_FCS_LEN;
+		buf1_len = stmmac_rx_buf1_len(priv, p, status, len);
+		len += buf1_len;
+		buf2_len = stmmac_rx_buf2_len(priv, p, status, len);
+		len += buf2_len;
+
+		/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+		 * Type frames (LLC/LLC-SNAP)
+		 *
+		 * llc_snap is never checked in GMAC >= 4, so this ACS
+		 * feature is always disabled and packets need to be
+		 * stripped manually.
+		 */
+		if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
+		    unlikely(status != llc_snap)) {
+			if (buf2_len)
+				buf2_len -= ETH_FCS_LEN;
+			else
+				buf1_len -= ETH_FCS_LEN;
+
+			len -= ETH_FCS_LEN;
 		}
 
 		if (!skb) {
-			int ret = stmmac_get_rx_header_len(priv, p, &hlen);
-
-			if (priv->sph && !ret && (hlen > 0)) {
-				sec_len = len;
-				if (!(status & rx_not_ls))
-					sec_len = sec_len - hlen;
-				len = hlen;
-
-				prefetch(page_address(buf->sec_page));
-				priv->xstats.rx_split_hdr_pkt_n++;
-			}
-
-			skb = napi_alloc_skb(&ch->rx_napi, len);
+			skb = napi_alloc_skb(&ch->rx_napi, buf1_len);
 			if (!skb) {
 				priv->dev->stats.rx_dropped++;
 				count++;
-				continue;
+				goto drain_data;
 			}
 
-			dma_sync_single_for_cpu(priv->device, buf->addr, len,
-						DMA_FROM_DEVICE);
+			dma_sync_single_for_cpu(priv->device, buf->addr,
+						buf1_len, DMA_FROM_DEVICE);
 			skb_copy_to_linear_data(skb, page_address(buf->page),
-						len);
-			skb_put(skb, len);
+						buf1_len);
+			skb_put(skb, buf1_len);
 
 			/* Data payload copied into SKB, page ready for recycle */
 			page_pool_recycle_direct(rx_q->page_pool, buf->page);
 			buf->page = NULL;
-		} else {
-			unsigned int buf_len = len - prev_len;
-
-			if (likely(status & rx_not_ls))
-				buf_len = priv->dma_buf_sz;
-
+		} else if (buf1_len) {
 			dma_sync_single_for_cpu(priv->device, buf->addr,
-						buf_len, DMA_FROM_DEVICE);
+						buf1_len, DMA_FROM_DEVICE);
 			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-					buf->page, 0, buf_len,
+					buf->page, 0, buf1_len,
 					priv->dma_buf_sz);
 
 			/* Data payload appended into SKB */
@@ -3607,22 +3689,23 @@
 			buf->page = NULL;
 		}
 
-		if (sec_len > 0) {
+		if (buf2_len) {
 			dma_sync_single_for_cpu(priv->device, buf->sec_addr,
-						sec_len, DMA_FROM_DEVICE);
+						buf2_len, DMA_FROM_DEVICE);
 			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-					buf->sec_page, 0, sec_len,
+					buf->sec_page, 0, buf2_len,
 					priv->dma_buf_sz);
 
-			len += sec_len;
-
 			/* Data payload appended into SKB */
 			page_pool_release_page(rx_q->page_pool, buf->sec_page);
 			buf->sec_page = NULL;
 		}
 
+drain_data:
 		if (likely(status & rx_not_ls))
 			goto read_again;
+		if (!skb)
+			continue;
 
 		/* Got entire packet into SKB. Finish it. */
 
@@ -3640,13 +3723,14 @@
 
 		skb_record_rx_queue(skb, queue);
 		napi_gro_receive(&ch->rx_napi, skb);
+		skb = NULL;
 
 		priv->dev->stats.rx_packets++;
 		priv->dev->stats.rx_bytes += len;
 		count++;
 	}
 
-	if (status & rx_not_ls) {
+	if (status & rx_not_ls || skb) {
 		rx_q->state_saved = true;
 		rx_q->state.skb = skb;
 		rx_q->state.error = error;
@@ -3671,8 +3755,14 @@
 	priv->xstats.napi_poll++;
 
 	work_done = stmmac_rx(priv, budget, chan);
-	if (work_done < budget && napi_complete_done(napi, work_done))
-		stmmac_enable_dma_irq(priv, priv->ioaddr, chan);
+	if (work_done < budget && napi_complete_done(napi, work_done)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ch->lock, flags);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+		spin_unlock_irqrestore(&ch->lock, flags);
+	}
+
 	return work_done;
 }
 
@@ -3681,7 +3771,6 @@
 	struct stmmac_channel *ch =
 		container_of(napi, struct stmmac_channel, tx_napi);
 	struct stmmac_priv *priv = ch->priv_data;
-	struct stmmac_tx_queue *tx_q;
 	u32 chan = ch->index;
 	int work_done;
 
@@ -3690,15 +3779,12 @@
 	work_done = stmmac_tx_clean(priv, DMA_TX_SIZE, chan);
 	work_done = min(work_done, budget);
 
-	if (work_done < budget)
-		napi_complete_done(napi, work_done);
+	if (work_done < budget && napi_complete_done(napi, work_done)) {
+		unsigned long flags;
 
-	/* Force transmission restart */
-	tx_q = &priv->tx_queue[chan];
-	if (tx_q->cur_tx != tx_q->dirty_tx) {
-		stmmac_enable_dma_transmission(priv, priv->ioaddr);
-		stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr,
-				       chan);
+		spin_lock_irqsave(&ch->lock, flags);
+		stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+		spin_unlock_irqrestore(&ch->lock, flags);
 	}
 
 	return work_done;
@@ -3749,12 +3835,24 @@
 static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
+	int txfifosz = priv->plat->tx_fifo_size;
+
+	if (txfifosz == 0)
+		txfifosz = priv->dma_cap.tx_fifo_size;
+
+	txfifosz /= priv->plat->tx_queues_to_use;
 
 	if (netif_running(dev)) {
 		netdev_err(priv->dev, "must be stopped to change its MTU\n");
 		return -EBUSY;
 	}
 
+	new_mtu = STMMAC_ALIGN(new_mtu);
+
+	/* If condition true, FIFO is too small or MTU too large */
+	if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB))
+		return -EINVAL;
+
 	dev->mtu = new_mtu;
 
 	netdev_update_features(dev);
@@ -3819,7 +3917,7 @@
 /**
  *  stmmac_interrupt - main ISR
  *  @irq: interrupt number.
- *  @dev_id: to pass the net device pointer.
+ *  @dev_id: to pass the net device pointer (must be valid).
  *  Description: this is the main driver interrupt service routine.
  *  It can call:
  *  o DMA service routine (to manage incoming frame reception and transmission
@@ -3843,11 +3941,6 @@
 	if (priv->irq_wake)
 		pm_wakeup_event(priv->device, 0);
 
-	if (unlikely(!dev)) {
-		netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
-		return IRQ_NONE;
-	}
-
 	/* Check if adapter is up */
 	if (test_bit(STMMAC_DOWN, &priv->state))
 		return IRQ_HANDLED;
@@ -3858,7 +3951,6 @@
 	/* To handle GMAC own interrupts */
 	if ((priv->plat->has_gmac) || xmac) {
 		int status = stmmac_host_irq_status(priv, priv->hw, &priv->xstats);
-		int mtl_status;
 
 		if (unlikely(status)) {
 			/* For LPI we need to save the tx status */
@@ -3869,17 +3961,8 @@
 		}
 
 		for (queue = 0; queue < queues_count; queue++) {
-			struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
-
-			mtl_status = stmmac_host_mtl_irq_status(priv, priv->hw,
-								queue);
-			if (mtl_status != -EINVAL)
-				status |= mtl_status;
-
-			if (status & CORE_IRQ_MTL_RX_OVERFLOW)
-				stmmac_set_rx_tail_ptr(priv, priv->ioaddr,
-						       rx_q->rx_tail_addr,
-						       queue);
+			status = stmmac_host_mtl_irq_status(priv, priv->hw,
+							    queue);
 		}
 
 		/* PCS link status */
@@ -3973,6 +4056,21 @@
 
 static LIST_HEAD(stmmac_block_cb_list);
 
+int stmmactc_setup_mqprio(struct net_device *ndev, void *type_data)
+{
+	struct tc_mqprio_qopt *mqprio = type_data;
+	u8 num_tc;
+	int i;
+
+	num_tc = mqprio->num_tc;
+	netif_set_real_num_tx_queues(ndev, num_tc);
+	netdev_set_num_tc(ndev, num_tc);
+	for (i = 0; i < num_tc; i++)
+		netdev_set_tc_queue(ndev, i, 1, i);
+
+	return 0;
+}
+
 static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 			   void *type_data)
 {
@@ -3986,6 +4084,10 @@
 						  priv, priv, true);
 	case TC_SETUP_QDISC_CBS:
 		return stmmac_tc_setup_cbs(priv, priv, type_data);
+	case TC_SETUP_QDISC_TAPRIO:
+		return stmmac_tc_setup_taprio(priv, priv, type_data);
+	case TC_SETUP_QDISC_MQPRIO:
+		return stmmactc_setup_mqprio(ndev, type_data);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -4156,17 +4258,76 @@
 		   priv->dma_cap.number_rx_channel);
 	seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
 		   priv->dma_cap.number_tx_channel);
+	seq_printf(seq, "\tNumber of Additional RX queues: %d\n",
+		   priv->dma_cap.number_rx_queues);
+	seq_printf(seq, "\tNumber of Additional TX queues: %d\n",
+		   priv->dma_cap.number_tx_queues);
 	seq_printf(seq, "\tEnhanced descriptors: %s\n",
 		   (priv->dma_cap.enh_desc) ? "Y" : "N");
-
+	seq_printf(seq, "\tTX Fifo Size: %d\n", priv->dma_cap.tx_fifo_size);
+	seq_printf(seq, "\tRX Fifo Size: %d\n", priv->dma_cap.rx_fifo_size);
+	seq_printf(seq, "\tHash Table Size: %d\n", priv->dma_cap.hash_tb_sz);
+	seq_printf(seq, "\tTSO: %s\n", priv->dma_cap.tsoen ? "Y" : "N");
+	seq_printf(seq, "\tNumber of PPS Outputs: %d\n",
+		   priv->dma_cap.pps_out_num);
+	seq_printf(seq, "\tSafety Features: %s\n",
+		   priv->dma_cap.asp ? "Y" : "N");
+	seq_printf(seq, "\tFlexible RX Parser: %s\n",
+		   priv->dma_cap.frpsel ? "Y" : "N");
+	seq_printf(seq, "\tEnhanced Addressing: %d\n",
+		   priv->dma_cap.addr64);
+	seq_printf(seq, "\tReceive Side Scaling: %s\n",
+		   priv->dma_cap.rssen ? "Y" : "N");
+	seq_printf(seq, "\tVLAN Hash Filtering: %s\n",
+		   priv->dma_cap.vlhash ? "Y" : "N");
+	seq_printf(seq, "\tSplit Header: %s\n",
+		   priv->dma_cap.sphen ? "Y" : "N");
+	seq_printf(seq, "\tVLAN TX Insertion: %s\n",
+		   priv->dma_cap.vlins ? "Y" : "N");
+	seq_printf(seq, "\tDouble VLAN: %s\n",
+		   priv->dma_cap.dvlan ? "Y" : "N");
+	seq_printf(seq, "\tNumber of L3/L4 Filters: %d\n",
+		   priv->dma_cap.l3l4fnum);
+	seq_printf(seq, "\tARP Offloading: %s\n",
+		   priv->dma_cap.arpoffsel ? "Y" : "N");
 	return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(stmmac_dma_cap);
 
+/* Use network device events to rename debugfs file entries.
+ */
+static int stmmac_device_event(struct notifier_block *unused,
+			       unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct stmmac_priv *priv = netdev_priv(dev);
+
+	if (dev->netdev_ops != &stmmac_netdev_ops)
+		goto done;
+
+	switch (event) {
+	case NETDEV_CHANGENAME:
+		if (priv->dbgfs_dir)
+			priv->dbgfs_dir = debugfs_rename(stmmac_fs_dir,
+							 priv->dbgfs_dir,
+							 stmmac_fs_dir,
+							 dev->name);
+		break;
+	}
+done:
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block stmmac_notifier = {
+	.notifier_call = stmmac_device_event,
+};
+
 static void stmmac_init_fs(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
+	rtnl_lock();
+
 	/* Create per netdev entries */
 	priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
 
@@ -4177,6 +4338,8 @@
 	/* Entry to report the DMA HW features */
 	debugfs_create_file("dma_cap", 0444, priv->dbgfs_dir, dev,
 			    &stmmac_dma_cap_fops);
+
+	rtnl_unlock();
 }
 
 static void stmmac_exit_fs(struct net_device *dev)
@@ -4250,6 +4413,11 @@
 {
 	struct stmmac_priv *priv = netdev_priv(ndev);
 	bool is_double = false;
+	int ret;
+
+	ret = stmmac_bus_clks_enable(priv, true);
+	if (ret)
+		return ret;
 
 	if (!priv->dma_cap.vlhash)
 		return -EOPNOTSUPP;
@@ -4257,7 +4425,10 @@
 		is_double = true;
 
 	clear_bit(vid, priv->active_vlans);
-	return stmmac_vlan_update(priv, is_double);
+	ret = stmmac_vlan_update(priv, is_double);
+
+	stmmac_bus_clks_enable(priv, false);
+	return ret;
 }
 
 static const struct net_device_ops stmmac_netdev_ops = {
@@ -4424,6 +4595,7 @@
 		     struct plat_stmmacenet_data *plat_dat,
 		     struct stmmac_resources *res)
 {
+	struct platform_device *pdev = to_platform_device(device);
 	struct net_device *ndev = NULL;
 	struct stmmac_priv *priv;
 	u32 queue, rxq, maxq;
@@ -4510,12 +4682,20 @@
 		dev_info(priv->device, "TSO feature enabled\n");
 	}
 
-	if (priv->dma_cap.sphen) {
+	if (priv->dma_cap.sphen && !priv->plat->sph_disable) {
 		ndev->hw_features |= NETIF_F_GRO;
 		priv->sph = true;
 		dev_info(priv->device, "SPH feature enabled\n");
 	}
 
+	/* The current IP register MAC_HW_Feature1[ADDR64] only define
+	 * 32/40/64 bit width, but some SOC support others like i.MX8MP
+	 * support 34 bits but it map to 40 bits width in MAC_HW_Feature1[ADDR64].
+	 * So overwrite dma_cap.addr64 according to HW real design.
+	 */
+	if (priv->plat->addr64)
+		priv->dma_cap.addr64 = priv->plat->addr64;
+
 	if (priv->dma_cap.addr64) {
 		ret = dma_set_mask_and_coherent(device,
 				DMA_BIT_MASK(priv->dma_cap.addr64));
@@ -4587,6 +4767,7 @@
 	for (queue = 0; queue < maxq; queue++) {
 		struct stmmac_channel *ch = &priv->channel[queue];
 
+		spin_lock_init(&ch->lock);
 		ch->priv_data = priv;
 		ch->index = queue;
 
@@ -4616,15 +4797,14 @@
 
 	stmmac_check_pcs_mode(priv);
 
-	if (priv->hw->pcs != STMMAC_PCS_RGMII  &&
-	    priv->hw->pcs != STMMAC_PCS_TBI &&
+	if (priv->hw->pcs != STMMAC_PCS_TBI &&
 	    priv->hw->pcs != STMMAC_PCS_RTBI) {
 		/* MDIO bus Registration */
 		ret = stmmac_mdio_register(ndev);
 		if (ret < 0) {
-			dev_err(priv->device,
-				"%s: MDIO bus (id: %d) registration failed",
-				__func__, priv->plat->bus_id);
+			dev_err_probe(priv->device, ret,
+				      "%s: MDIO bus (id: %d) registration failed\n",
+				      __func__, priv->plat->bus_id);
 			goto error_mdio_register;
 		}
 	}
@@ -4646,13 +4826,16 @@
 	stmmac_init_fs(ndev);
 #endif
 
+	if (priv->plat->exit)
+		priv->plat->exit(pdev, priv->plat->bsp_priv);
+	stmmac_bus_clks_enable(priv, false);
+
 	return ret;
 
 error_netdev_register:
 	phylink_destroy(priv->phylink);
 error_phy_setup:
-	if (priv->hw->pcs != STMMAC_PCS_RGMII &&
-	    priv->hw->pcs != STMMAC_PCS_TBI &&
+	if (priv->hw->pcs != STMMAC_PCS_TBI &&
 	    priv->hw->pcs != STMMAC_PCS_RTBI)
 		stmmac_mdio_unregister(ndev);
 error_mdio_register:
@@ -4666,6 +4849,7 @@
 	}
 error_hw_init:
 	destroy_workqueue(priv->wq);
+	stmmac_bus_clks_enable(priv, false);
 
 	return ret;
 }
@@ -4681,22 +4865,23 @@
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	bool netif_status = netif_running(ndev);
 
 	netdev_info(priv->dev, "%s: removing driver", __func__);
 
-#ifdef CONFIG_DEBUG_FS
-	stmmac_exit_fs(ndev);
-#endif
 	stmmac_stop_all_dma(priv);
 
 	stmmac_mac_set(priv, priv->ioaddr, false);
 	netif_carrier_off(ndev);
 	unregister_netdev(ndev);
+#ifdef CONFIG_DEBUG_FS
+	stmmac_exit_fs(ndev);
+#endif
 	phylink_destroy(priv->phylink);
 	if (priv->plat->stmmac_rst)
 		reset_control_assert(priv->plat->stmmac_rst);
-	clk_disable_unprepare(priv->plat->pclk);
-	clk_disable_unprepare(priv->plat->stmmac_clk);
+	if (netif_status)
+		stmmac_bus_clks_enable(priv, false);
 	if (priv->hw->pcs != STMMAC_PCS_RGMII &&
 	    priv->hw->pcs != STMMAC_PCS_TBI &&
 	    priv->hw->pcs != STMMAC_PCS_RTBI)
@@ -4719,6 +4904,7 @@
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	u32 chan;
 
 	if (!ndev || !netif_running(ndev))
 		return 0;
@@ -4728,15 +4914,22 @@
 	mutex_lock(&priv->lock);
 
 	netif_device_detach(ndev);
-	stmmac_stop_all_queues(priv);
 
 	stmmac_disable_all_queues(priv);
 
+	for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
+		del_timer_sync(&priv->tx_queue[chan].txtimer);
+
+	if (priv->eee_enabled) {
+		priv->tx_path_in_lpi_mode = false;
+		del_timer_sync(&priv->eee_ctrl_timer);
+	}
+
 	/* Stop TX/RX DMA */
 	stmmac_stop_all_dma(priv);
 
 	/* Enable Power down mode by programming the PMT regs */
-	if (device_may_wakeup(priv->device)) {
+	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
 		stmmac_pmt(priv, priv->hw, priv->wolopts);
 		priv->irq_wake = 1;
 	} else {
@@ -4751,8 +4944,7 @@
 		/* Disable clock in case of PWM is off */
 		if (priv->plat->clk_ptp_ref)
 			clk_disable_unprepare(priv->plat->clk_ptp_ref);
-		clk_disable_unprepare(priv->plat->pclk);
-		clk_disable_unprepare(priv->plat->stmmac_clk);
+		stmmac_bus_clks_enable(priv, false);
 	}
 	mutex_unlock(&priv->lock);
 
@@ -4784,6 +4976,8 @@
 		tx_q->cur_tx = 0;
 		tx_q->dirty_tx = 0;
 		tx_q->mss = 0;
+
+		netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue));
 	}
 }
 
@@ -4797,6 +4991,7 @@
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	int ret = 0;
 
 	if (!netif_running(ndev))
 		return 0;
@@ -4807,7 +5002,7 @@
 	 * this bit because it can generate problems while resuming
 	 * from another devices (e.g. serial console).
 	 */
-	if (device_may_wakeup(priv->device)) {
+	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
 		mutex_lock(&priv->lock);
 		stmmac_pmt(priv, priv->hw, 0);
 		mutex_unlock(&priv->lock);
@@ -4815,8 +5010,9 @@
 	} else {
 		pinctrl_pm_select_default_state(priv->device);
 		/* enable the clk previously disabled */
-		clk_prepare_enable(priv->plat->stmmac_clk);
-		clk_prepare_enable(priv->plat->pclk);
+		ret = stmmac_bus_clks_enable(priv, true);
+		if (ret)
+			return ret;
 		if (priv->plat->clk_ptp_ref)
 			clk_prepare_enable(priv->plat->clk_ptp_ref);
 		/* reset the phy so that it's ready */
@@ -4824,12 +5020,17 @@
 			stmmac_mdio_reset(priv->mii);
 	}
 
-	netif_device_attach(ndev);
+	if (!device_may_wakeup(priv->device)) {
+		rtnl_lock();
+		phylink_start(priv->phylink);
+		rtnl_unlock();
+	}
 
 	mutex_lock(&priv->lock);
 
 	stmmac_reset_queues_param(priv);
 
+	stmmac_free_tx_skbufs(priv);
 	stmmac_clear_descriptors(priv);
 
 	stmmac_hw_setup(ndev, false);
@@ -4838,18 +5039,12 @@
 
 	stmmac_enable_all_queues(priv);
 
-	stmmac_start_all_queues(priv);
-
 	mutex_unlock(&priv->lock);
 
-	if (!device_may_wakeup(priv->device)) {
-		rtnl_lock();
-		phylink_start(priv->phylink);
-		rtnl_unlock();
-	}
-
 	phylink_mac_change(priv->phylink, true);
 
+	netif_device_attach(ndev);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(stmmac_resume);
@@ -4860,7 +5055,7 @@
 	char *opt;
 
 	if (!str || !*str)
-		return -EINVAL;
+		return 1;
 	while ((opt = strsep(&str, ",")) != NULL) {
 		if (!strncmp(opt, "debug:", 6)) {
 			if (kstrtoint(opt + 6, 0, &debug))
@@ -4891,11 +5086,11 @@
 				goto err;
 		}
 	}
-	return 0;
+	return 1;
 
 err:
 	pr_err("%s: ERROR broken module parameter conversion", __func__);
-	return -EINVAL;
+	return 1;
 }
 
 __setup("stmmaceth=", stmmac_cmdline_opt);
@@ -4907,6 +5102,7 @@
 	/* Create debugfs main directory if it doesn't exist yet */
 	if (!stmmac_fs_dir)
 		stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+	register_netdevice_notifier(&stmmac_notifier);
 #endif
 
 	return 0;
@@ -4915,6 +5111,7 @@
 static void __exit stmmac_exit(void)
 {
 #ifdef CONFIG_DEBUG_FS
+	unregister_netdevice_notifier(&stmmac_notifier);
 	debugfs_remove_recursive(stmmac_fs_dir);
 #endif
 }
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -260,6 +260,7 @@
  */
 int stmmac_mdio_reset(struct mii_bus *bus)
 {
+	int ret = 0;
 #if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
 	struct net_device *ndev = bus->priv;
 	struct stmmac_priv *priv = netdev_priv(ndev);
@@ -273,8 +274,10 @@
 		reset_gpio = devm_gpiod_get_optional(priv->device,
 						     "snps,reset",
 						     GPIOD_OUT_LOW);
-		if (IS_ERR(reset_gpio))
-			return PTR_ERR(reset_gpio);
+		if (IS_ERR_OR_NULL(reset_gpio)) {
+			ret = PTR_ERR_OR_ZERO(reset_gpio);
+			goto mdio_gpio_reset_end;
+		}
 
 		device_property_read_u32_array(priv->device,
 					       "snps,reset-delays-us",
@@ -291,6 +294,8 @@
 		if (delays[2])
 			msleep(DIV_ROUND_UP(delays[2], 1000));
 	}
+
+mdio_gpio_reset_end:
 #endif
 
 	/* This is a workaround for problems with the STE101P PHY.
@@ -301,7 +306,7 @@
 	if (!priv->plat->has_gmac4)
 		writel(0, priv->ioaddr + mii_address);
 #endif
-	return 0;
+	return ret;
 }
 
 /**
@@ -358,8 +363,12 @@
 	new_bus->parent = priv->device;
 
 	err = of_mdiobus_register(new_bus, mdio_node);
-	if (err != 0) {
-		dev_err(dev, "Cannot register the MDIO bus\n");
+	if (err == -ENODEV) {
+		err = 0;
+		dev_info(dev, "MDIO bus is disabled\n");
+		goto bus_register_fail;
+	} else if (err) {
+		dev_err_probe(dev, err, "Cannot register the MDIO bus\n");
 		goto bus_register_fail;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -119,6 +119,7 @@
 	plat->has_gmac4 = 1;
 	plat->force_sf_dma_mode = 0;
 	plat->tso_en = 1;
+	plat->sph_disable = 1;
 
 	plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
 
@@ -481,7 +482,7 @@
 		return -ENOMEM;
 
 	/* Enable pci device */
-	ret = pci_enable_device(pdev);
+	ret = pcim_enable_device(pdev);
 	if (ret) {
 		dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
 			__func__);
@@ -538,8 +539,6 @@
 		pcim_iounmap_regions(pdev, BIT(i));
 		break;
 	}
-
-	pci_disable_device(pdev);
 }
 
 static int __maybe_unused stmmac_pci_suspend(struct device *dev)
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -107,10 +107,10 @@
 
 	axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
 	axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
-	axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
-	axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
-	axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
-	axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
+	axi->axi_kbbe = of_property_read_bool(np, "snps,kbbe");
+	axi->axi_fb = of_property_read_bool(np, "snps,fb");
+	axi->axi_mb = of_property_read_bool(np, "snps,mb");
+	axi->axi_rb =  of_property_read_bool(np, "snps,rb");
 
 	if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
 		axi->axi_wr_osr_lmt = 1;
@@ -320,7 +320,7 @@
 static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
 			 struct device_node *np, struct device *dev)
 {
-	bool mdio = true;
+	bool mdio = !of_phy_is_fixed_link(np);
 	static const struct of_device_id need_mdio_ids[] = {
 		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
 		{},
@@ -428,8 +428,7 @@
 	plat->phylink_node = np;
 
 	/* Get max speed of operation from device tree */
-	if (of_property_read_u32(np, "max-speed", &plat->max_speed))
-		plat->max_speed = -1;
+	of_property_read_u32(np, "max-speed", &plat->max_speed);
 
 	plat->bus_id = of_alias_get_id(np, "ethernet");
 	if (plat->bus_id < 0)
@@ -505,9 +504,18 @@
 		plat->pmt = 1;
 	}
 
+	if (of_device_is_compatible(np, "snps,dwmac-3.40a")) {
+		plat->has_gmac = 1;
+		plat->enh_desc = 1;
+		plat->tx_coe = 1;
+		plat->bugged_jumbo = 1;
+		plat->pmt = 1;
+	}
+
 	if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
 	    of_device_is_compatible(np, "snps,dwmac-4.10a") ||
-	    of_device_is_compatible(np, "snps,dwmac-4.20a")) {
+	    of_device_is_compatible(np, "snps,dwmac-4.20a") ||
+	    of_device_is_compatible(np, "snps,dwmac-5.10a")) {
 		plat->has_gmac4 = 1;
 		plat->has_gmac = 0;
 		plat->pmt = 1;
@@ -547,7 +555,7 @@
 	dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
 
 	plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
-	if (plat->force_thresh_dma_mode) {
+	if (plat->force_thresh_dma_mode && plat->force_sf_dma_mode) {
 		plat->force_sf_dma_mode = 0;
 		dev_warn(&pdev->dev,
 			 "force_sf_dma_mode is ignored if force_thresh_dma_mode is set.\n");
@@ -624,6 +632,8 @@
 void stmmac_remove_config_dt(struct platform_device *pdev,
 			     struct plat_stmmacenet_data *plat)
 {
+	clk_disable_unprepare(plat->stmmac_clk);
+	clk_disable_unprepare(plat->pclk);
 	of_node_put(plat->phy_node);
 	of_node_put(plat->mdio_node);
 }
@@ -663,16 +673,22 @@
 	 * In case the wake up interrupt is not passed from the platform
 	 * so the driver will continue to use the mac irq (ndev->irq)
 	 */
-	stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+	stmmac_res->wol_irq =
+		platform_get_irq_byname_optional(pdev, "eth_wake_irq");
 	if (stmmac_res->wol_irq < 0) {
 		if (stmmac_res->wol_irq == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
+		dev_info(&pdev->dev, "IRQ eth_wake_irq not found\n");
 		stmmac_res->wol_irq = stmmac_res->irq;
 	}
 
-	stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-	if (stmmac_res->lpi_irq == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
+	stmmac_res->lpi_irq =
+		platform_get_irq_byname_optional(pdev, "eth_lpi");
+	if (stmmac_res->lpi_irq < 0) {
+		if (stmmac_res->lpi_irq == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_info(&pdev->dev, "IRQ eth_lpi not found\n");
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
@@ -694,7 +710,7 @@
 	struct plat_stmmacenet_data *plat = priv->plat;
 	int ret = stmmac_dvr_remove(&pdev->dev);
 
-	if (plat->exit)
+	if (plat->exit && ndev && netif_running(ndev))
 		plat->exit(pdev, plat->bsp_priv);
 
 	stmmac_remove_config_dt(pdev, plat);
@@ -719,7 +735,7 @@
 	struct platform_device *pdev = to_platform_device(dev);
 
 	ret = stmmac_suspend(dev);
-	if (priv->plat->exit)
+	if (priv->plat->exit && ndev && netif_running(ndev))
 		priv->plat->exit(pdev, priv->plat->bsp_priv);
 
 	return ret;
@@ -738,7 +754,7 @@
 	struct stmmac_priv *priv = netdev_priv(ndev);
 	struct platform_device *pdev = to_platform_device(dev);
 
-	if (priv->plat->init)
+	if (priv->plat->init && ndev && netif_running(ndev))
 		priv->plat->init(pdev, priv->plat->bsp_priv);
 
 	return stmmac_resume(dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -61,7 +61,7 @@
 #define	PTP_TCR_TSENMACADDR	BIT(18)
 
 /* SSIR defines */
-#define	PTP_SSIR_SSINC_MASK		0xff
+#define	PTP_SSIR_SSINC_MAX		0xff
 #define	GMAC4_PTP_SSIR_SSINC_SHIFT	16
 
 #endif	/* __STMMAC_PTP_H__ */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -80,7 +80,7 @@
 	if (attr->max_size && (attr->max_size > size))
 		size = attr->max_size;
 
-	skb = netdev_alloc_skb_ip_align(priv->dev, size);
+	skb = netdev_alloc_skb(priv->dev, size);
 	if (!skb)
 		return NULL;
 
@@ -244,6 +244,8 @@
 					 struct net_device *orig_ndev)
 {
 	struct stmmac_test_priv *tpriv = pt->af_packet_priv;
+	unsigned char *src = tpriv->packet->src;
+	unsigned char *dst = tpriv->packet->dst;
 	struct stmmachdr *shdr;
 	struct ethhdr *ehdr;
 	struct udphdr *uhdr;
@@ -260,15 +262,15 @@
 		goto out;
 
 	ehdr = (struct ethhdr *)skb_mac_header(skb);
-	if (tpriv->packet->dst) {
-		if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
+	if (dst) {
+		if (!ether_addr_equal_unaligned(ehdr->h_dest, dst))
 			goto out;
 	}
 	if (tpriv->packet->sarc) {
-		if (!ether_addr_equal(ehdr->h_source, ehdr->h_dest))
+		if (!ether_addr_equal_unaligned(ehdr->h_source, ehdr->h_dest))
 			goto out;
-	} else if (tpriv->packet->src) {
-		if (!ether_addr_equal(ehdr->h_source, tpriv->packet->src))
+	} else if (src) {
+		if (!ether_addr_equal_unaligned(ehdr->h_source, src))
 			goto out;
 	}
 
@@ -624,6 +626,8 @@
 		return -EOPNOTSUPP;
 	if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries)
 		return -EOPNOTSUPP;
+	if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins)
+		return -EOPNOTSUPP;
 
 	while (--tries) {
 		/* We only need to check the mc_addr for collisions */
@@ -666,6 +670,8 @@
 
 	if (stmmac_filter_check(priv))
 		return -EOPNOTSUPP;
+	if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries)
+		return -EOPNOTSUPP;
 	if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins)
 		return -EOPNOTSUPP;
 
@@ -710,7 +716,7 @@
 	struct ethhdr *ehdr;
 
 	ehdr = (struct ethhdr *)skb_mac_header(skb);
-	if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr))
+	if (!ether_addr_equal_unaligned(ehdr->h_source, orig_ndev->dev_addr))
 		goto out;
 	if (ehdr->h_proto != htons(ETH_P_PAUSE))
 		goto out;
@@ -847,12 +853,16 @@
 	if (tpriv->vlan_id) {
 		if (skb->vlan_proto != htons(proto))
 			goto out;
-		if (skb->vlan_tci != tpriv->vlan_id)
+		if (skb->vlan_tci != tpriv->vlan_id) {
+			/* Means filter did not work. */
+			tpriv->ok = false;
+			complete(&tpriv->comp);
 			goto out;
+		}
 	}
 
 	ehdr = (struct ethhdr *)skb_mac_header(skb);
-	if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
+	if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->dst))
 		goto out;
 
 	ihdr = ip_hdr(skb);
@@ -1287,16 +1297,19 @@
 	struct stmmac_packet_attrs attr = { };
 	struct flow_dissector *dissector;
 	struct flow_cls_offload *cls;
+	int ret, old_enable = 0;
 	struct flow_rule *rule;
-	int ret;
 
 	if (!tc_can_offload(priv->dev))
 		return -EOPNOTSUPP;
 	if (!priv->dma_cap.l3l4fnum)
 		return -EOPNOTSUPP;
-	if (priv->rss.enable)
+	if (priv->rss.enable) {
+		old_enable = priv->rss.enable;
+		priv->rss.enable = false;
 		stmmac_rss_configure(priv, priv->hw, NULL,
 				     priv->plat->rx_queues_to_use);
+	}
 
 	dissector = kzalloc(sizeof(*dissector), GFP_KERNEL);
 	if (!dissector) {
@@ -1363,7 +1376,8 @@
 cleanup_dissector:
 	kfree(dissector);
 cleanup_rss:
-	if (priv->rss.enable) {
+	if (old_enable) {
+		priv->rss.enable = old_enable;
 		stmmac_rss_configure(priv, priv->hw, &priv->rss,
 				     priv->plat->rx_queues_to_use);
 	}
@@ -1408,16 +1422,19 @@
 	struct stmmac_packet_attrs attr = { };
 	struct flow_dissector *dissector;
 	struct flow_cls_offload *cls;
+	int ret, old_enable = 0;
 	struct flow_rule *rule;
-	int ret;
 
 	if (!tc_can_offload(priv->dev))
 		return -EOPNOTSUPP;
 	if (!priv->dma_cap.l3l4fnum)
 		return -EOPNOTSUPP;
-	if (priv->rss.enable)
+	if (priv->rss.enable) {
+		old_enable = priv->rss.enable;
+		priv->rss.enable = false;
 		stmmac_rss_configure(priv, priv->hw, NULL,
 				     priv->plat->rx_queues_to_use);
+	}
 
 	dissector = kzalloc(sizeof(*dissector), GFP_KERNEL);
 	if (!dissector) {
@@ -1489,7 +1506,8 @@
 cleanup_dissector:
 	kfree(dissector);
 cleanup_rss:
-	if (priv->rss.enable) {
+	if (old_enable) {
+		priv->rss.enable = old_enable;
 		stmmac_rss_configure(priv, priv->hw, &priv->rss,
 				     priv->plat->rx_queues_to_use);
 	}
@@ -1542,7 +1560,7 @@
 	struct arphdr *ahdr;
 
 	ehdr = (struct ethhdr *)skb_mac_header(skb);
-	if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->src))
+	if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->src))
 		goto out;
 
 	ahdr = arp_hdr(skb);
@@ -1596,12 +1614,16 @@
 	}
 
 	ret = stmmac_set_arp_offload(priv, priv->hw, true, ip_addr);
-	if (ret)
+	if (ret) {
+		kfree_skb(skb);
 		goto cleanup;
+	}
 
 	ret = dev_set_promiscuity(priv->dev, 1);
-	if (ret)
+	if (ret) {
+		kfree_skb(skb);
 		goto cleanup;
+	}
 
 	skb_set_queue_mapping(skb, 0);
 	ret = dev_queue_xmit(skb);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ linux-ein-5.4.0/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -332,7 +332,12 @@
 
 		priv->plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_AVB;
 	} else if (!qopt->enable) {
-		return stmmac_dma_qmode(priv, priv->ioaddr, queue, MTL_QUEUE_DCB);
+		ret = stmmac_dma_qmode(priv, priv->ioaddr, queue,
+				       MTL_QUEUE_DCB);
+		if (ret)
+			return ret;
+
+		priv->plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB;
 	}
 
 	/* Port Transmit Rate and Speed Divider */
@@ -579,6 +584,10 @@
 {
 	int ret = 0;
 
+	/* When RSS is enabled, the filtering will be bypassed */
+	if (priv->rss.enable)
+		return -EBUSY;
+
 	switch (cls->command) {
 	case FLOW_CLS_REPLACE:
 		ret = tc_add_flow(priv, cls);
@@ -593,9 +602,162 @@
 	return ret;
 }
 
+static int tc_setup_taprio(struct stmmac_priv *priv,
+			   struct tc_taprio_qopt_offload *qopt)
+{
+	u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
+	struct plat_stmmacenet_data *plat = priv->plat;
+	struct timespec64 time, current_time;
+	ktime_t current_time_ns;
+	bool fpe = false;
+	int i, ret = 0;
+	u64 ctr;
+
+	if (!priv->dma_cap.estsel)
+		return -EOPNOTSUPP;
+
+	switch (wid) {
+	case 0x1:
+		wid = 16;
+		break;
+	case 0x2:
+		wid = 20;
+		break;
+	case 0x3:
+		wid = 24;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	switch (dep) {
+	case 0x1:
+		dep = 64;
+		break;
+	case 0x2:
+		dep = 128;
+		break;
+	case 0x3:
+		dep = 256;
+		break;
+	case 0x4:
+		dep = 512;
+		break;
+	case 0x5:
+		dep = 1024;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (!qopt->enable)
+		goto disable;
+	if (qopt->num_entries >= dep)
+		return -EINVAL;
+	if (!qopt->base_time)
+		return -ERANGE;
+	if (!qopt->cycle_time)
+		return -ERANGE;
+
+	if (!plat->est) {
+		plat->est = devm_kzalloc(priv->device, sizeof(*plat->est),
+					 GFP_KERNEL);
+		if (!plat->est)
+			return -ENOMEM;
+	} else {
+		memset(plat->est, 0, sizeof(*plat->est));
+	}
+
+	size = qopt->num_entries;
+
+	priv->plat->est->gcl_size = size;
+	priv->plat->est->enable = qopt->enable;
+
+	for (i = 0; i < size; i++) {
+		s64 delta_ns = qopt->entries[i].interval;
+		u32 gates = qopt->entries[i].gate_mask;
+
+		if (delta_ns > GENMASK(wid, 0))
+			return -ERANGE;
+		if (gates > GENMASK(31 - wid, 0))
+			return -ERANGE;
+
+		switch (qopt->entries[i].command) {
+		case TC_TAPRIO_CMD_SET_GATES:
+			if (fpe)
+				return -EINVAL;
+			break;
+		case TC_TAPRIO_CMD_SET_AND_HOLD:
+			gates |= BIT(0);
+			fpe = true;
+			break;
+		case TC_TAPRIO_CMD_SET_AND_RELEASE:
+			gates &= ~BIT(0);
+			fpe = true;
+			break;
+		default:
+			return -EOPNOTSUPP;
+		}
+
+		priv->plat->est->gcl[i] = delta_ns | (gates << wid);
+	}
+
+	/* Adjust for real system time */
+	priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, &current_time);
+	current_time_ns = timespec64_to_ktime(current_time);
+	if (ktime_after(qopt->base_time, current_time_ns)) {
+		time = ktime_to_timespec64(qopt->base_time);
+	} else {
+		ktime_t base_time;
+		s64 n;
+
+		n = div64_s64(ktime_sub_ns(current_time_ns, qopt->base_time),
+			      qopt->cycle_time);
+		base_time = ktime_add_ns(qopt->base_time,
+					 (n + 1) * qopt->cycle_time);
+
+		time = ktime_to_timespec64(base_time);
+	}
+
+	priv->plat->est->btr[0] = (u32)time.tv_nsec;
+	priv->plat->est->btr[1] = (u32)time.tv_sec;
+
+	ctr = qopt->cycle_time;
+	priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
+	priv->plat->est->ctr[1] = (u32)ctr;
+
+	if (fpe && !priv->dma_cap.fpesel)
+		return -EOPNOTSUPP;
+
+	ret = stmmac_fpe_configure(priv, priv->ioaddr,
+				   priv->plat->tx_queues_to_use,
+				   priv->plat->rx_queues_to_use, fpe);
+	if (ret && fpe) {
+		netdev_err(priv->dev, "failed to enable Frame Preemption\n");
+		return ret;
+	}
+
+	ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+				   priv->plat->clk_ptp_rate);
+	if (ret) {
+		netdev_err(priv->dev, "failed to configure EST\n");
+		goto disable;
+	}
+
+	netdev_info(priv->dev, "configured EST\n");
+	return 0;
+
+disable:
+	priv->plat->est->enable = false;
+	stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+			     priv->plat->clk_ptp_rate);
+	return ret;
+}
+
 const struct stmmac_tc_ops dwmac510_tc_ops = {
 	.init = tc_init,
 	.setup_cls_u32 = tc_setup_cls_u32,
 	.setup_cbs = tc_setup_cbs,
 	.setup_cls = tc_setup_cls,
+	.setup_taprio = tc_setup_taprio,
 };
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/Kconfig
@@ -73,6 +73,7 @@
 config SUNVNET_COMMON
 	tristate "Common routines to support Sun Virtual Networking"
 	depends on SUN_LDOMS
+	depends on INET
 	default m
 
 config SUNVNET
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/cassini.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/cassini.c
@@ -1337,7 +1337,7 @@
 	writel(val, cp->regs + REG_RX_PAGE_SIZE);
 
 	/* enable the header parser if desired */
-	if (CAS_HP_FIRMWARE == cas_prog_null)
+	if (&CAS_HP_FIRMWARE[0] == &cas_prog_null[0])
 		return;
 
 	val = CAS_BASE(HP_CFG_NUM_CPU, CAS_NCPUS > 63 ? 0 : CAS_NCPUS);
@@ -2291,7 +2291,7 @@
 	drops = 0;
 	while (1) {
 		struct cas_rx_comp *rxc = rxcs + entry;
-		struct sk_buff *uninitialized_var(skb);
+		struct sk_buff *skb;
 		int type, len;
 		u64 words[4];
 		int i, dring;
@@ -3807,7 +3807,7 @@
 
 	/* program header parser */
 	if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) ||
-	    (CAS_HP_ALT_FIRMWARE == cas_prog_null)) {
+	    (&CAS_HP_ALT_FIRMWARE[0] == &cas_prog_null[0])) {
 		cas_load_firmware(cp, CAS_HP_FIRMWARE);
 	} else {
 		cas_load_firmware(cp, CAS_HP_ALT_FIRMWARE);
@@ -4971,7 +4971,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
@@ -5138,13 +5138,14 @@
 		cas_shutdown(cp);
 	mutex_unlock(&cp->pm_mutex);
 
+	vfree(cp->fw_data);
+
 	pci_iounmap(pdev, cp->regs);
 
 
 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-ein-5.4.0.orig/drivers/net/ethernet/sun/ldmvsw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/ldmvsw.c
@@ -290,6 +290,9 @@
 
 	hp = mdesc_grab();
 
+	if (!hp)
+		return -ENODEV;
+
 	rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
 	err = -ENODEV;
 	if (!rmac) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/niu.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/niu.c
@@ -429,7 +429,7 @@
 	struct niu_link_config *lp = &np->link_config;
 	u16 pll_cfg, pll_sts;
 	int max_retry = 100;
-	u64 uninitialized_var(sig), mask, val;
+	u64 sig, mask, val;
 	u32 tx_cfg, rx_cfg;
 	unsigned long i;
 	int err;
@@ -526,7 +526,7 @@
 	struct niu_link_config *lp = &np->link_config;
 	u32 tx_cfg, rx_cfg, pll_cfg, pll_sts;
 	int max_retry = 100;
-	u64 uninitialized_var(sig), mask, val;
+	u64 sig, mask, val;
 	unsigned long i;
 	int err;
 
@@ -714,7 +714,7 @@
 
 static int esr_reset(struct niu *np)
 {
-	u32 uninitialized_var(reset);
+	u32 reset;
 	int err;
 
 	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
@@ -3931,8 +3931,6 @@
 		mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
 	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
 		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
-	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
-		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
 	if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
 		mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
 	if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
@@ -4505,7 +4503,7 @@
 
 		err = niu_rbr_fill(np, rp, GFP_KERNEL);
 		if (err)
-			return err;
+			goto out_err;
 	}
 
 	tx_rings = kcalloc(num_tx_rings, sizeof(struct tx_ring_info),
@@ -8146,10 +8144,10 @@
 				     "VPD_SCAN: Reading in property [%s] len[%d]\n",
 				     namebuf, prop_len);
 			for (i = 0; i < prop_len; i++) {
-				err = niu_pci_eeprom_read(np, off + i);
-				if (err >= 0)
-					*prop_buf = err;
-				++prop_buf;
+				err =  niu_pci_eeprom_read(np, off + i);
+				if (err < 0)
+					return err;
+				*prop_buf++ = err;
 			}
 		}
 
@@ -8160,14 +8158,14 @@
 }
 
 /* ESPC_PIO_EN_ENABLE must be set */
-static void niu_pci_vpd_fetch(struct niu *np, u32 start)
+static int niu_pci_vpd_fetch(struct niu *np, u32 start)
 {
 	u32 offset;
 	int err;
 
 	err = niu_pci_eeprom_read16_swp(np, start + 1);
 	if (err < 0)
-		return;
+		return err;
 
 	offset = err + 3;
 
@@ -8176,12 +8174,14 @@
 		u32 end;
 
 		err = niu_pci_eeprom_read(np, here);
+		if (err < 0)
+			return err;
 		if (err != 0x90)
-			return;
+			return -EINVAL;
 
 		err = niu_pci_eeprom_read16_swp(np, here + 1);
 		if (err < 0)
-			return;
+			return err;
 
 		here = start + offset + 3;
 		end = start + offset + err;
@@ -8189,9 +8189,13 @@
 		offset += err;
 
 		err = niu_pci_vpd_scan_props(np, here, end);
-		if (err < 0 || err == 1)
-			return;
+		if (err < 0)
+			return err;
+		/* ret == 1 is not an error */
+		if (err == 1)
+			return 0;
 	}
+	return 0;
 }
 
 /* ESPC_PIO_EN_ENABLE must be set */
@@ -9282,8 +9286,11 @@
 		offset = niu_pci_vpd_offset(np);
 		netif_printk(np, probe, KERN_DEBUG, np->dev,
 			     "%s() VPD offset [%08x]\n", __func__, offset);
-		if (offset)
-			niu_pci_vpd_fetch(np, offset);
+		if (offset) {
+			err = niu_pci_vpd_fetch(np, offset);
+			if (err < 0)
+				return err;
+		}
 		nw64(ESPC_PIO_EN, 0);
 
 		if (np->flags & NIU_FLAGS_VPD_VALID) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/sunhme.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/sunhme.c
@@ -2064,9 +2064,9 @@
 
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
-			dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
+			dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE);
 			skb_copy_from_linear_data(skb, copy_skb->data, len);
-			dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
+			dma_sync_single_for_device(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE);
 			/* Reuse original ring buffer. */
 			hme_write_rxd(hp, this,
 				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -3164,7 +3164,7 @@
 	if (err) {
 		printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
 		       "aborting.\n");
-		goto err_out_iounmap;
+		goto err_out_free_coherent;
 	}
 
 	pci_set_drvdata(pdev, hp);
@@ -3197,6 +3197,10 @@
 
 	return 0;
 
+err_out_free_coherent:
+	dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+			  hp->happy_block, hp->hblock_dvma);
+
 err_out_iounmap:
 	iounmap(hp->gregs);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/sunvnet.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/sunvnet.c
@@ -431,6 +431,9 @@
 
 	hp = mdesc_grab();
 
+	if (!hp)
+		return -ENODEV;
+
 	vp = vnet_find_parent(hp, vdev->mp, vdev);
 	if (IS_ERR(vp)) {
 		pr_err("Cannot find port parent vnet\n");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/sun/sunvnet_common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/sun/sunvnet_common.c
@@ -1353,27 +1353,12 @@
 		if (vio_version_after_eq(&port->vio, 1, 3))
 			localmtu -= VLAN_HLEN;
 
-		if (skb->protocol == htons(ETH_P_IP)) {
-			struct flowi4 fl4;
-			struct rtable *rt = NULL;
-
-			memset(&fl4, 0, sizeof(fl4));
-			fl4.flowi4_oif = dev->ifindex;
-			fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
-			fl4.daddr = ip_hdr(skb)->daddr;
-			fl4.saddr = ip_hdr(skb)->saddr;
-
-			rt = ip_route_output_key(dev_net(dev), &fl4);
-			if (!IS_ERR(rt)) {
-				skb_dst_set(skb, &rt->dst);
-				icmp_send(skb, ICMP_DEST_UNREACH,
-					  ICMP_FRAG_NEEDED,
-					  htonl(localmtu));
-			}
-		}
+		if (skb->protocol == htons(ETH_P_IP))
+			icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+				      htonl(localmtu));
 #if IS_ENABLED(CONFIG_IPV6)
 		else if (skb->protocol == htons(ETH_P_IPV6))
-			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, localmtu);
+			icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, localmtu);
 #endif
 		goto out_dropped;
 	}
--- linux-ein-5.4.0.orig/drivers/net/ethernet/synopsys/dwc-xlgmac-common.c
+++ linux-ein-5.4.0/drivers/net/ethernet/synopsys/dwc-xlgmac-common.c
@@ -513,7 +513,7 @@
 
 void xlgmac_print_all_hw_features(struct xlgmac_pdata *pdata)
 {
-	char *str = NULL;
+	char __maybe_unused *str = NULL;
 
 	XLGMAC_PR("\n");
 	XLGMAC_PR("=====================================================\n");
--- linux-ein-5.4.0.orig/drivers/net/ethernet/tehuti/tehuti.c
+++ linux-ein-5.4.0/drivers/net/ethernet/tehuti/tehuti.c
@@ -2052,6 +2052,7 @@
 		/*bdx_hw_reset(priv); */
 		if (bdx_read_mac(priv)) {
 			pr_err("load MAC address failed\n");
+			err = -EFAULT;
 			goto err_out_iomap;
 		}
 		SET_NETDEV_DEV(ndev, &pdev->dev);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/Kconfig
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/Kconfig
@@ -22,6 +22,7 @@
 	depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 ) || COMPILE_TEST
 	select TI_DAVINCI_MDIO
 	select PHYLIB
+	select GENERIC_ALLOCATOR
 	---help---
 	  This driver supports TI's DaVinci Ethernet .
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/cpsw.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/cpsw.c
@@ -890,8 +890,8 @@
 {
 	struct cpsw_common *cpsw = dev_id;
 
-	cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX);
 	writel(0, &cpsw->wr_regs->rx_en);
+	cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX);
 
 	if (cpsw->quirk_irq) {
 		disable_irq_nosync(cpsw->irqs_table[0]);
@@ -1753,6 +1753,8 @@
 
 err_cleanup:
 	if (!cpsw->usage_count) {
+		napi_disable(&cpsw->napi_rx);
+		napi_disable(&cpsw->napi_tx);
 		cpdma_ctlr_stop(cpsw->dma);
 		cpsw_destroy_xdp_rxqs(cpsw);
 	}
@@ -2209,7 +2211,7 @@
 				  HOST_PORT_NUM, ALE_VLAN, vid);
 	ret |= cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
 				  0, ALE_VLAN, vid);
-	ret |= cpsw_ale_flush_multicast(cpsw->ale, 0, vid);
+	ret |= cpsw_ale_flush_multicast(cpsw->ale, ALE_PORT_HOST, vid);
 err:
 	pm_runtime_put(cpsw->dev);
 	return ret;
@@ -2876,6 +2878,7 @@
 				       CPSW_MAX_QUEUES, CPSW_MAX_QUEUES);
 	if (!ndev) {
 		dev_err(dev, "error allocating net_device\n");
+		ret = -ENOMEM;
 		goto clean_cpts;
 	}
 
@@ -2999,11 +3002,15 @@
 	struct cpsw_common *cpsw = dev_get_drvdata(dev);
 	int i;
 
+	rtnl_lock();
+
 	for (i = 0; i < cpsw->data.slaves; i++)
 		if (cpsw->slaves[i].ndev)
 			if (netif_running(cpsw->slaves[i].ndev))
 				cpsw_ndo_stop(cpsw->slaves[i].ndev);
 
+	rtnl_unlock();
+
 	/* Select sleep pin state */
 	pinctrl_pm_select_sleep_state(dev);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/cpsw_ale.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/cpsw_ale.c
@@ -60,23 +60,37 @@
 
 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
 {
-	int idx;
+	int idx, idx2;
+	u32 hi_val = 0;
 
 	idx    = start / 32;
+	idx2 = (start + bits - 1) / 32;
+	/* Check if bits to be fetched exceed a word */
+	if (idx != idx2) {
+		idx2 = 2 - idx2; /* flip */
+		hi_val = ale_entry[idx2] << ((idx2 * 32) - start);
+	}
 	start -= idx * 32;
 	idx    = 2 - idx; /* flip */
-	return (ale_entry[idx] >> start) & BITMASK(bits);
+	return (hi_val + (ale_entry[idx] >> start)) & BITMASK(bits);
 }
 
 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
 				      u32 value)
 {
-	int idx;
+	int idx, idx2;
 
 	value &= BITMASK(bits);
-	idx    = start / 32;
+	idx = start / 32;
+	idx2 = (start + bits - 1) / 32;
+	/* Check if bits to be set exceed a word */
+	if (idx != idx2) {
+		idx2 = 2 - idx2; /* flip */
+		ale_entry[idx2] &= ~(BITMASK(bits + start - (idx2 * 32)));
+		ale_entry[idx2] |= (value >> ((idx2 * 32) - start));
+	}
 	start -= idx * 32;
-	idx    = 2 - idx; /* flip */
+	idx = 2 - idx; /* flip */
 	ale_entry[idx] &= ~(BITMASK(bits) << start);
 	ale_entry[idx] |=  (value << start);
 }
@@ -779,6 +793,7 @@
 void cpsw_ale_stop(struct cpsw_ale *ale)
 {
 	del_timer_sync(&ale->timer);
+	cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
 	cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
 }
 
@@ -862,6 +877,7 @@
 					ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS;
 	}
 
+	cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
 	return ale;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/cpts.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/cpts.c
@@ -454,7 +454,9 @@
 	for (i = 0; i < CPTS_MAX_EVENTS; i++)
 		list_add(&cpts->pool_data[i].list, &cpts->pool);
 
-	clk_enable(cpts->refclk);
+	err = clk_enable(cpts->refclk);
+	if (err)
+		return err;
 
 	cpts_write32(cpts, CPTS_EN, control);
 	cpts_write32(cpts, TS_PEND_EN, int_enable);
@@ -485,6 +487,7 @@
 
 	ptp_clock_unregister(cpts->clock);
 	cpts->clock = NULL;
+	cpts->phc_index = -1;
 
 	cpts_write32(cpts, 0, int_enable);
 	cpts_write32(cpts, 0, control);
@@ -667,6 +670,7 @@
 	cpts->cc.read = cpts_systim_read;
 	cpts->cc.mask = CLOCKSOURCE_MASK(32);
 	cpts->info = cpts_info;
+	cpts->phc_index = -1;
 
 	cpts_calc_mult_shift(cpts);
 	/* save cc.mult original value as it can be modified
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/davinci_cpdma.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -1018,7 +1018,6 @@
 	struct cpdma_chan		*chan = si->chan;
 	struct cpdma_ctlr		*ctlr = chan->ctlr;
 	int				len = si->len;
-	int				swlen = len;
 	struct cpdma_desc __iomem	*desc;
 	dma_addr_t			buffer;
 	u32				mode;
@@ -1046,7 +1045,6 @@
 	if (si->data_dma) {
 		buffer = si->data_dma;
 		dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
-		swlen |= CPDMA_DMA_EXT_MAP;
 	} else {
 		buffer = dma_map_single(ctlr->dev, si->data_virt, len, chan->dir);
 		ret = dma_mapping_error(ctlr->dev, buffer);
@@ -1065,7 +1063,8 @@
 	writel_relaxed(mode | len, &desc->hw_mode);
 	writel_relaxed((uintptr_t)si->token, &desc->sw_token);
 	writel_relaxed(buffer, &desc->sw_buffer);
-	writel_relaxed(swlen, &desc->sw_len);
+	writel_relaxed(si->data_dma ? len | CPDMA_DMA_EXT_MAP : len,
+		       &desc->sw_len);
 	desc_read(desc, sw_len);
 
 	__cpdma_chan_submit(chan, desc);
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/davinci_emac.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/davinci_emac.c
@@ -169,11 +169,11 @@
 /* EMAC mac_status register */
 #define EMAC_MACSTATUS_TXERRCODE_MASK	(0xF00000)
 #define EMAC_MACSTATUS_TXERRCODE_SHIFT	(20)
-#define EMAC_MACSTATUS_TXERRCH_MASK	(0x7)
+#define EMAC_MACSTATUS_TXERRCH_MASK	(0x70000)
 #define EMAC_MACSTATUS_TXERRCH_SHIFT	(16)
 #define EMAC_MACSTATUS_RXERRCODE_MASK	(0xF000)
 #define EMAC_MACSTATUS_RXERRCODE_SHIFT	(12)
-#define EMAC_MACSTATUS_RXERRCH_MASK	(0x7)
+#define EMAC_MACSTATUS_RXERRCH_MASK	(0x700)
 #define EMAC_MACSTATUS_RXERRCH_SHIFT	(8)
 
 /* EMAC RX register masks */
@@ -412,8 +412,20 @@
 	u32 int_ctrl, num_interrupts = 0;
 	u32 prescale = 0, addnl_dvdr = 1, coal_intvl = 0;
 
-	if (!coal->rx_coalesce_usecs)
-		return -EINVAL;
+	if (!coal->rx_coalesce_usecs) {
+		priv->coal_intvl = 0;
+
+		switch (priv->version) {
+		case EMAC_VERSION_2:
+			emac_ctrl_write(EMAC_DM646X_CMINTCTRL, 0);
+			break;
+		default:
+			emac_ctrl_write(EMAC_CTRL_EWINTTCNT, 0);
+			break;
+		}
+
+		return 0;
+	}
 
 	coal_intvl = coal->rx_coalesce_usecs;
 
@@ -1226,7 +1238,7 @@
 	struct net_device *ndev = priv->ndev;
 	struct device *emac_dev = &ndev->dev;
 	u32 status = 0;
-	u32 num_tx_pkts = 0, num_rx_pkts = 0;
+	u32 num_rx_pkts = 0;
 
 	/* Check interrupt vectors and call packet processing */
 	status = emac_read(EMAC_MACINVECTOR);
@@ -1237,8 +1249,7 @@
 		mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
 
 	if (status & mask) {
-		num_tx_pkts = cpdma_chan_process(priv->txchan,
-					      EMAC_DEF_TX_MAX_SERVICE);
+		cpdma_chan_process(priv->txchan, EMAC_DEF_TX_MAX_SERVICE);
 	} /* TX processing */
 
 	mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/davinci_mdio.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/davinci_mdio.c
@@ -397,6 +397,8 @@
 	data->dev = dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
 	data->regs = devm_ioremap(dev, res->start, resource_size(res));
 	if (!data->regs)
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/netcp_core.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/netcp_core.c
@@ -1262,7 +1262,7 @@
 }
 
 /* Submit the packet */
-static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct netcp_intf *netcp = netdev_priv(ndev);
 	struct netcp_stats *tx_stats = &netcp->stats;
@@ -1350,9 +1350,9 @@
 	tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id,
 					     KNAV_QUEUE_SHARED);
 	if (IS_ERR(tx_pipe->dma_queue)) {
+		ret = PTR_ERR(tx_pipe->dma_queue);
 		dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n",
 			name, ret);
-		ret = PTR_ERR(tx_pipe->dma_queue);
 		goto err;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/ti/tlan.c
+++ linux-ein-5.4.0/drivers/net/ethernet/ti/tlan.c
@@ -314,9 +314,8 @@
 	pci_release_regions(pdev);
 #endif
 
-	free_netdev(dev);
-
 	cancel_work_sync(&priv->tlan_tqueue);
+	free_netdev(dev);
 }
 
 static void tlan_start(struct net_device *dev)
@@ -673,7 +672,6 @@
 static void  __init tlan_eisa_probe(void)
 {
 	long	ioaddr;
-	int	rc = -ENODEV;
 	int	irq;
 	u16	device_id;
 
@@ -738,8 +736,7 @@
 
 
 		/* Setup the newly found eisa adapter */
-		rc = tlan_probe1(NULL, ioaddr, irq,
-				 12, NULL);
+		tlan_probe1(NULL, ioaddr, irq, 12, NULL);
 		continue;
 
 out:
--- linux-ein-5.4.0.orig/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ linux-ein-5.4.0/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -317,15 +317,17 @@
 
 	/* set up the hardware pointers in each descriptor */
 	for (i = 0; i < no; i++, descr++) {
+		dma_addr_t cpu_addr;
+
 		gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
-		descr->bus_addr =
-			dma_map_single(ctodev(card), descr,
-				       GELIC_DESCR_SIZE,
-				       DMA_BIDIRECTIONAL);
 
-		if (!descr->bus_addr)
+		cpu_addr = dma_map_single(ctodev(card), descr,
+					  GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL);
+
+		if (dma_mapping_error(ctodev(card), cpu_addr))
 			goto iommu_error;
 
+		descr->bus_addr = cpu_to_be32(cpu_addr);
 		descr->next = descr + 1;
 		descr->prev = descr - 1;
 	}
@@ -365,28 +367,30 @@
  *
  * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
  * Activate the descriptor state-wise
+ *
+ * Gelic RX sk_buffs must be aligned to GELIC_NET_RXBUF_ALIGN and the length
+ * must be a multiple of GELIC_NET_RXBUF_ALIGN.
  */
 static int gelic_descr_prepare_rx(struct gelic_card *card,
 				  struct gelic_descr *descr)
 {
+	static const unsigned int rx_skb_size =
+		ALIGN(GELIC_NET_MAX_FRAME, GELIC_NET_RXBUF_ALIGN) +
+		GELIC_NET_RXBUF_ALIGN - 1;
+	dma_addr_t cpu_addr;
 	int offset;
-	unsigned int bufsize;
 
 	if (gelic_descr_get_status(descr) !=  GELIC_DESCR_DMA_NOT_IN_USE)
 		dev_info(ctodev(card), "%s: ERROR status\n", __func__);
-	/* we need to round up the buffer size to a multiple of 128 */
-	bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
 
-	/* and we need to have it 128 byte aligned, therefore we allocate a
-	 * bit more */
-	descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
+	descr->skb = netdev_alloc_skb(*card->netdev, rx_skb_size);
 	if (!descr->skb) {
 		descr->buf_addr = 0; /* tell DMAC don't touch memory */
 		dev_info(ctodev(card),
 			 "%s:allocate skb failed !!\n", __func__);
 		return -ENOMEM;
 	}
-	descr->buf_size = cpu_to_be32(bufsize);
+	descr->buf_size = cpu_to_be32(rx_skb_size);
 	descr->dmac_cmd_status = 0;
 	descr->result_size = 0;
 	descr->valid_size = 0;
@@ -397,11 +401,10 @@
 	if (offset)
 		skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
 	/* io-mmu-map the skb */
-	descr->buf_addr = cpu_to_be32(dma_map_single(ctodev(card),
-						     descr->skb->data,
-						     GELIC_NET_MAX_MTU,
-						     DMA_FROM_DEVICE));
-	if (!descr->buf_addr) {
+	cpu_addr = dma_map_single(ctodev(card), descr->skb->data,
+				  GELIC_NET_MAX_FRAME, DMA_FROM_DEVICE);
+	descr->buf_addr = cpu_to_be32(cpu_addr);
+	if (dma_mapping_error(ctodev(card), cpu_addr)) {
 		dev_kfree_skb_any(descr->skb);
 		descr->skb = NULL;
 		dev_info(ctodev(card),
@@ -781,7 +784,7 @@
 
 	buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
 
-	if (!buf) {
+	if (dma_mapping_error(ctodev(card), buf)) {
 		dev_err(ctodev(card),
 			"dma map 2 failed (%p, %i). Dropping packet\n",
 			skb->data, skb->len);
@@ -917,7 +920,7 @@
 	data_error = be32_to_cpu(descr->data_error);
 	/* unmap skb buffer */
 	dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr),
-			 GELIC_NET_MAX_MTU,
+			 GELIC_NET_MAX_FRAME,
 			 DMA_FROM_DEVICE);
 
 	skb_put(skb, be32_to_cpu(descr->valid_size)?
--- linux-ein-5.4.0.orig/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ linux-ein-5.4.0/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -19,8 +19,9 @@
 #define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
 #define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
 
-#define GELIC_NET_MAX_MTU               VLAN_ETH_FRAME_LEN
-#define GELIC_NET_MIN_MTU               VLAN_ETH_ZLEN
+#define GELIC_NET_MAX_FRAME             2312
+#define GELIC_NET_MAX_MTU               2294
+#define GELIC_NET_MIN_MTU               64
 #define GELIC_NET_RXBUF_ALIGN           128
 #define GELIC_CARD_RX_CSUM_DEFAULT      1 /* hw chksum */
 #define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
--- linux-ein-5.4.0.orig/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
+++ linux-ein-5.4.0/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
@@ -1217,7 +1217,7 @@
 		key_index = wl->current_key;
 
 	if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
-		/* reques to change default key index */
+		/* request to change default key index */
 		pr_debug("%s: request to change default key to %d\n",
 			 __func__, key_index);
 		wl->current_key = key_index;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/toshiba/spider_net.c
+++ linux-ein-5.4.0/drivers/net/ethernet/toshiba/spider_net.c
@@ -283,8 +283,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);
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/ethernet/toshiba/tc35815.c
+++ linux-ein-5.4.0/drivers/net/ethernet/toshiba/tc35815.c
@@ -644,7 +644,7 @@
 		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, mask);
 		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mask);
 	}
-	linkmode_and(phydev->supported, phydev->supported, mask);
+	linkmode_andnot(phydev->supported, phydev->supported, mask);
 	linkmode_copy(phydev->advertising, phydev->supported);
 
 	lp->link = 0;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/tundra/tsi108_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -1302,12 +1302,15 @@
 
 	data->rxring = dma_alloc_coherent(&data->pdev->dev, rxring_size,
 					  &data->rxdma, GFP_KERNEL);
-	if (!data->rxring)
+	if (!data->rxring) {
+		free_irq(data->irq_num, dev);
 		return -ENOMEM;
+	}
 
 	data->txring = dma_alloc_coherent(&data->pdev->dev, txring_size,
 					  &data->txdma, GFP_KERNEL);
 	if (!data->txring) {
+		free_irq(data->irq_num, dev);
 		dma_free_coherent(&data->pdev->dev, rxring_size, data->rxring,
 				    data->rxdma);
 		return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/via/via-velocity.c
+++ linux-ein-5.4.0/drivers/net/ethernet/via/via-velocity.c
@@ -865,26 +865,13 @@
  */
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
 {
-	u32 curr_status;
 	struct mac_regs __iomem *regs = vptr->mac_regs;
 
 	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
-	curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
 
 	/* Set mii link status */
 	set_mii_flow_control(vptr);
 
-	/*
-	   Check if new status is consistent with current status
-	   if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) ||
-	       (mii_status==curr_status)) {
-	   vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
-	   vptr->mii_status=check_connection_type(vptr->mac_regs);
-	   VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
-	   return 0;
-	   }
-	 */
-
 	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
 		MII_REG_BITS_ON(AUXCR_MDPPS, MII_NCONFIG, vptr->mac_regs);
 
--- linux-ein-5.4.0.orig/drivers/net/ethernet/wiznet/w5100.c
+++ linux-ein-5.4.0/drivers/net/ethernet/wiznet/w5100.c
@@ -1052,6 +1052,8 @@
 		mac_addr = data->mac_addr;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -EINVAL;
 	if (resource_size(mem) < W5100_BUS_DIRECT_SIZE)
 		ops = &w5100_mmio_indirect_ops;
 	else
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xilinx/ll_temac.h
+++ linux-ein-5.4.0/drivers/net/ethernet/xilinx/ll_temac.h
@@ -375,10 +375,14 @@
 	int tx_bd_next;
 	int tx_bd_tail;
 	int rx_bd_ci;
+	int rx_bd_tail;
 
 	/* DMA channel control setup */
 	u32 tx_chnl_ctrl;
 	u32 rx_chnl_ctrl;
+	u8 coalesce_count_rx;
+
+	struct delayed_work restart_work;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -51,6 +51,7 @@
 #include <linux/ip.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <linux/dma-mapping.h>
 #include <linux/processor.h>
 #include <linux/platform_data/xilinx-ll-temac.h>
@@ -102,7 +103,7 @@
  */
 #define HARD_ACS_RDY_POLL_NS (20 * NSEC_PER_MSEC)
 
-/**
+/*
  * temac_indirect_busywait - Wait for current indirect register access
  * to complete.
  */
@@ -117,7 +118,7 @@
 		return 0;
 }
 
-/**
+/*
  * temac_indirect_in32 - Indirect register read access.  This function
  * must be called without lp->indirect_lock being held.
  */
@@ -132,7 +133,7 @@
 	return val;
 }
 
-/**
+/*
  * temac_indirect_in32_locked - Indirect register read access.  This
  * function must be called with lp->indirect_lock being held.  Use
  * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
@@ -160,7 +161,7 @@
 	return temac_ior(lp, XTE_LSW0_OFFSET);
 }
 
-/**
+/*
  * temac_indirect_out32 - Indirect register write access.  This function
  * must be called without lp->indirect_lock being held.
  */
@@ -173,7 +174,7 @@
 	spin_unlock_irqrestore(lp->indirect_lock, flags);
 }
 
-/**
+/*
  * temac_indirect_out32_locked - Indirect register write access.  This
  * function must be called with lp->indirect_lock being held.  Use
  * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
@@ -198,7 +199,7 @@
 	WARN_ON(temac_indirect_busywait(lp));
 }
 
-/**
+/*
  * temac_dma_in32_* - Memory mapped DMA read, these function expects a
  * register input that is based on DCR word addresses which are then
  * converted to memory mapped byte addresses.  To be assigned to
@@ -214,7 +215,7 @@
 	return ioread32(lp->sdma_regs + (reg << 2));
 }
 
-/**
+/*
  * temac_dma_out32_* - Memory mapped DMA read, these function expects
  * a register input that is based on DCR word addresses which are then
  * converted to memory mapped byte addresses.  To be assigned to
@@ -236,7 +237,7 @@
  */
 #ifdef CONFIG_PPC_DCR
 
-/**
+/*
  * temac_dma_dcr_in32 - DCR based DMA read
  */
 static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
@@ -244,7 +245,7 @@
 	return dcr_read(lp->sdma_dcrs, reg);
 }
 
-/**
+/*
  * temac_dma_dcr_out32 - DCR based DMA write
  */
 static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value)
@@ -252,7 +253,7 @@
 	dcr_write(lp->sdma_dcrs, reg, value);
 }
 
-/**
+/*
  * temac_dcr_setup - If the DMA is DCR based, then setup the address and
  * I/O  functions
  */
@@ -289,7 +290,7 @@
 
 #endif
 
-/**
+/*
  * temac_dma_bd_release - Release buffer descriptor rings
  */
 static void temac_dma_bd_release(struct net_device *ndev)
@@ -319,7 +320,7 @@
 				lp->tx_bd_v, lp->tx_bd_p);
 }
 
-/**
+/*
  * temac_dma_bd_init - Setup buffer descriptor rings
  */
 static int temac_dma_bd_init(struct net_device *ndev)
@@ -367,6 +368,8 @@
 		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
 					      XTE_MAX_JUMBO_FRAME_SIZE,
 					      DMA_FROM_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, skb_dma_addr))
+			goto out;
 		lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
 		lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
 		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
@@ -387,12 +390,13 @@
 	lp->tx_bd_next = 0;
 	lp->tx_bd_tail = 0;
 	lp->rx_bd_ci = 0;
+	lp->rx_bd_tail = RX_BD_NUM - 1;
 
 	/* Enable RX DMA transfers */
 	wmb();
 	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
 	lp->dma_out(lp, RX_TAILDESC_PTR,
-		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * lp->rx_bd_tail));
 
 	/* Prepare for TX DMA transfer */
 	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
@@ -585,7 +589,7 @@
 	{}
 };
 
-/**
+/*
  * temac_setoptions
  */
 static u32 temac_setoptions(struct net_device *ndev, u32 options)
@@ -766,12 +770,15 @@
 	stat = be32_to_cpu(cur_p->app0);
 
 	while (stat & STS_CTRL_APP0_CMPLT) {
+		/* Make sure that the other fields are read after bd is
+		 * released by dma
+		 */
+		rmb();
 		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
 				 be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
 		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
 		if (skb)
 			dev_consume_skb_irq(skb);
-		cur_p->app0 = 0;
 		cur_p->app1 = 0;
 		cur_p->app2 = 0;
 		cur_p->app3 = 0;
@@ -780,6 +787,12 @@
 		ndev->stats.tx_packets++;
 		ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
 
+		/* app0 must be visible last, as it is used to flag
+		 * availability of the bd
+		 */
+		smp_mb();
+		cur_p->app0 = 0;
+
 		lp->tx_bd_ci++;
 		if (lp->tx_bd_ci >= TX_BD_NUM)
 			lp->tx_bd_ci = 0;
@@ -788,6 +801,9 @@
 		stat = be32_to_cpu(cur_p->app0);
 	}
 
+	/* Matches barrier in temac_start_xmit */
+	smp_mb();
+
 	netif_wake_queue(ndev);
 }
 
@@ -803,6 +819,9 @@
 		if (cur_p->app0)
 			return NETDEV_TX_BUSY;
 
+		/* Make sure to read next bd app0 after this one */
+		rmb();
+
 		tail++;
 		if (tail >= TX_BD_NUM)
 			tail = 0;
@@ -830,9 +849,19 @@
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
 	if (temac_check_tx_bd_space(lp, num_frag + 1)) {
-		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 temac_start_xmit_done */
+		smp_mb();
+
+		/* Space might have just been freed - check again */
+		if (temac_check_tx_bd_space(lp, num_frag + 1))
+			return NETDEV_TX_BUSY;
+
+		netif_wake_queue(ndev);
 	}
 
 	cur_p->app0 = 0;
@@ -850,12 +879,15 @@
 	skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
 				      skb_headlen(skb), DMA_TO_DEVICE);
 	cur_p->len = cpu_to_be32(skb_headlen(skb));
+	if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent, skb_dma_addr))) {
+		dev_kfree_skb_any(skb);
+		ndev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	cur_p->phys = cpu_to_be32(skb_dma_addr);
-	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
-		lp->tx_bd_tail++;
-		if (lp->tx_bd_tail >= TX_BD_NUM)
+		if (++lp->tx_bd_tail >= TX_BD_NUM)
 			lp->tx_bd_tail = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
@@ -863,6 +895,27 @@
 					      skb_frag_address(frag),
 					      skb_frag_size(frag),
 					      DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, skb_dma_addr)) {
+			if (--lp->tx_bd_tail < 0)
+				lp->tx_bd_tail = TX_BD_NUM - 1;
+			cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+			while (--ii >= 0) {
+				--frag;
+				dma_unmap_single(ndev->dev.parent,
+						 be32_to_cpu(cur_p->phys),
+						 skb_frag_size(frag),
+						 DMA_TO_DEVICE);
+				if (--lp->tx_bd_tail < 0)
+					lp->tx_bd_tail = TX_BD_NUM - 1;
+				cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+			}
+			dma_unmap_single(ndev->dev.parent,
+					 be32_to_cpu(cur_p->phys),
+					 skb_headlen(skb), DMA_TO_DEVICE);
+			dev_kfree_skb_any(skb);
+			ndev->stats.tx_dropped++;
+			return NETDEV_TX_OK;
+		}
 		cur_p->phys = cpu_to_be32(skb_dma_addr);
 		cur_p->len = cpu_to_be32(skb_frag_size(frag));
 		cur_p->app0 = 0;
@@ -870,6 +923,11 @@
 	}
 	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
+	/* Mark last fragment with skb address, so it can be consumed
+	 * in temac_start_xmit_done()
+	 */
+	ptr_to_txbd((void *)skb, cur_p);
+
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	lp->tx_bd_tail++;
 	if (lp->tx_bd_tail >= TX_BD_NUM)
@@ -881,34 +939,62 @@
 	wmb();
 	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
+	if (temac_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1))
+		netif_stop_queue(ndev);
+
 	return NETDEV_TX_OK;
 }
 
+static int ll_temac_recv_buffers_available(struct temac_local *lp)
+{
+	int available;
+
+	if (!lp->rx_skb[lp->rx_bd_ci])
+		return 0;
+	available = 1 + lp->rx_bd_tail - lp->rx_bd_ci;
+	if (available <= 0)
+		available += RX_BD_NUM;
+	return available;
+}
 
 static void ll_temac_recv(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
-	struct sk_buff *skb, *new_skb;
-	unsigned int bdstat;
-	struct cdmac_bd *cur_p;
-	dma_addr_t tail_p, skb_dma_addr;
-	int length;
 	unsigned long flags;
+	int rx_bd;
+	bool update_tail = false;
 
 	spin_lock_irqsave(&lp->rx_lock, flags);
 
-	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
-	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-
-	bdstat = be32_to_cpu(cur_p->app0);
-	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
+	/* Process all received buffers, passing them on network
+	 * stack.  After this, the buffer descriptors will be in an
+	 * un-allocated stage, where no skb is allocated for it, and
+	 * they are therefore not available for TEMAC/DMA.
+	 */
+	do {
+		struct cdmac_bd *bd = &lp->rx_bd_v[lp->rx_bd_ci];
+		struct sk_buff *skb = lp->rx_skb[lp->rx_bd_ci];
+		unsigned int bdstat = be32_to_cpu(bd->app0);
+		int length;
+
+		/* While this should not normally happen, we can end
+		 * here when GFP_ATOMIC allocations fail, and we
+		 * therefore have un-allocated buffers.
+		 */
+		if (!skb)
+			break;
 
-		skb = lp->rx_skb[lp->rx_bd_ci];
-		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
+		/* Loop over all completed buffer descriptors */
+		if (!(bdstat & STS_CTRL_APP0_CMPLT))
+			break;
 
-		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(bd->phys),
 				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+		/* The buffer is not valid for DMA anymore */
+		bd->phys = 0;
+		bd->len = 0;
 
+		length = be32_to_cpu(bd->app4) & 0x3FFF;
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
 		skb_checksum_none_assert(skb);
@@ -923,43 +1009,102 @@
 			 * (back) for proper IP checksum byte order
 			 * (be16).
 			 */
-			skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
+			skb->csum = htons(be32_to_cpu(bd->app3) & 0xFFFF);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
 		if (!skb_defer_rx_timestamp(skb))
 			netif_rx(skb);
+		/* The skb buffer is now owned by network stack above */
+		lp->rx_skb[lp->rx_bd_ci] = NULL;
 
 		ndev->stats.rx_packets++;
 		ndev->stats.rx_bytes += length;
 
-		new_skb = netdev_alloc_skb_ip_align(ndev,
-						XTE_MAX_JUMBO_FRAME_SIZE);
-		if (!new_skb) {
-			spin_unlock_irqrestore(&lp->rx_lock, flags);
-			return;
+		rx_bd = lp->rx_bd_ci;
+		if (++lp->rx_bd_ci >= RX_BD_NUM)
+			lp->rx_bd_ci = 0;
+	} while (rx_bd != lp->rx_bd_tail);
+
+	/* DMA operations will halt when the last buffer descriptor is
+	 * processed (ie. the one pointed to by RX_TAILDESC_PTR).
+	 * When that happens, no more interrupt events will be
+	 * generated.  No IRQ_COAL or IRQ_DLY, and not even an
+	 * IRQ_ERR.  To avoid stalling, we schedule a delayed work
+	 * when there is a potential risk of that happening.  The work
+	 * will call this function, and thus re-schedule itself until
+	 * enough buffers are available again.
+	 */
+	if (ll_temac_recv_buffers_available(lp) < lp->coalesce_count_rx)
+		schedule_delayed_work(&lp->restart_work, HZ / 1000);
+
+	/* Allocate new buffers for those buffer descriptors that were
+	 * passed to network stack.  Note that GFP_ATOMIC allocations
+	 * can fail (e.g. when a larger burst of GFP_ATOMIC
+	 * allocations occurs), so while we try to allocate all
+	 * buffers in the same interrupt where they were processed, we
+	 * continue with what we could get in case of allocation
+	 * failure.  Allocation of remaining buffers will be retried
+	 * in following calls.
+	 */
+	while (1) {
+		struct sk_buff *skb;
+		struct cdmac_bd *bd;
+		dma_addr_t skb_dma_addr;
+
+		rx_bd = lp->rx_bd_tail + 1;
+		if (rx_bd >= RX_BD_NUM)
+			rx_bd = 0;
+		bd = &lp->rx_bd_v[rx_bd];
+
+		if (bd->phys)
+			break;	/* All skb's allocated */
+
+		skb = netdev_alloc_skb_ip_align(ndev, XTE_MAX_JUMBO_FRAME_SIZE);
+		if (!skb) {
+			dev_warn(&ndev->dev, "skb alloc failed\n");
+			break;
 		}
 
-		cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
-		skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
 					      XTE_MAX_JUMBO_FRAME_SIZE,
 					      DMA_FROM_DEVICE);
-		cur_p->phys = cpu_to_be32(skb_dma_addr);
-		cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
-		lp->rx_skb[lp->rx_bd_ci] = new_skb;
+		if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent,
+						   skb_dma_addr))) {
+			dev_kfree_skb_any(skb);
+			break;
+		}
 
-		lp->rx_bd_ci++;
-		if (lp->rx_bd_ci >= RX_BD_NUM)
-			lp->rx_bd_ci = 0;
+		bd->phys = cpu_to_be32(skb_dma_addr);
+		bd->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+		bd->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+		lp->rx_skb[rx_bd] = skb;
+
+		lp->rx_bd_tail = rx_bd;
+		update_tail = true;
+	}
 
-		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-		bdstat = be32_to_cpu(cur_p->app0);
+	/* Move tail pointer when buffers have been allocated */
+	if (update_tail) {
+		lp->dma_out(lp, RX_TAILDESC_PTR,
+			lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_tail);
 	}
-	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
 	spin_unlock_irqrestore(&lp->rx_lock, flags);
 }
 
+/* Function scheduled to ensure a restart in case of DMA halt
+ * condition caused by running out of buffer descriptors.
+ */
+static void ll_temac_restart_work_func(struct work_struct *work)
+{
+	struct temac_local *lp = container_of(work, struct temac_local,
+					      restart_work.work);
+	struct net_device *ndev = lp->ndev;
+
+	ll_temac_recv(ndev);
+}
+
 static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
 {
 	struct net_device *ndev = _ndev;
@@ -1052,6 +1197,8 @@
 
 	dev_dbg(&ndev->dev, "temac_close()\n");
 
+	cancel_delayed_work_sync(&lp->restart_work);
+
 	free_irq(lp->tx_irq, ndev);
 	free_irq(lp->rx_irq, ndev);
 
@@ -1184,6 +1331,7 @@
 	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
+	INIT_DELAYED_WORK(&lp->restart_work, ll_temac_restart_work_func);
 
 	/* Setup mutex for synchronization of indirect register access */
 	if (pdata) {
@@ -1197,6 +1345,8 @@
 		lp->indirect_lock = devm_kmalloc(&pdev->dev,
 						 sizeof(*lp->indirect_lock),
 						 GFP_KERNEL);
+		if (!lp->indirect_lock)
+			return -ENOMEM;
 		spin_lock_init(lp->indirect_lock);
 	}
 
@@ -1290,14 +1440,13 @@
 		 */
 		lp->tx_chnl_ctrl = 0x10220000;
 		lp->rx_chnl_ctrl = 0xff070000;
+		lp->coalesce_count_rx = 0x07;
 
 		/* Finished with the DMA node; drop the reference */
 		of_node_put(dma_np);
 	} else if (pdata) {
 		/* 2nd memory resource specifies DMA registers */
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		lp->sdma_regs = devm_ioremap_nocache(&pdev->dev, res->start,
-						     resource_size(res));
+		lp->sdma_regs = devm_platform_ioremap_resource(pdev, 1);
 		if (IS_ERR(lp->sdma_regs)) {
 			dev_err(&pdev->dev,
 				"could not map DMA registers\n");
@@ -1321,23 +1470,26 @@
 				(pdata->tx_irq_count << 16);
 		else
 			lp->tx_chnl_ctrl = 0x10220000;
-		if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+		if (pdata->rx_irq_timeout || pdata->rx_irq_count) {
 			lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
 				(pdata->rx_irq_count << 16);
-		else
+			lp->coalesce_count_rx = pdata->rx_irq_count;
+		} else {
 			lp->rx_chnl_ctrl = 0xff070000;
+			lp->coalesce_count_rx = 0x07;
+		}
 	}
 
 	/* Error handle returned DMA RX and TX interrupts */
-	if (lp->rx_irq < 0) {
-		if (lp->rx_irq != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "could not get DMA RX irq\n");
-		return lp->rx_irq;
-	}
-	if (lp->tx_irq < 0) {
-		if (lp->tx_irq != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "could not get DMA TX irq\n");
-		return lp->tx_irq;
+	if (lp->rx_irq <= 0) {
+		rc = lp->rx_irq ?: -EINVAL;
+		return dev_err_probe(&pdev->dev, rc,
+				     "could not get DMA RX irq\n");
+	}
+	if (lp->tx_irq <= 0) {
+		rc = lp->tx_irq ?: -EINVAL;
+		return dev_err_probe(&pdev->dev, rc,
+				     "could not get DMA TX irq\n");
 	}
 
 	if (temac_np) {
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ linux-ein-5.4.0/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -435,7 +435,7 @@
 	void __iomem *regs;
 	void __iomem *dma_regs;
 
-	struct tasklet_struct dma_err_tasklet;
+	struct work_struct dma_err_task;
 
 	int tx_irq;
 	int rx_irq;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ linux-ein-5.4.0/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -41,8 +41,9 @@
 #include "xilinx_axienet.h"
 
 /* Descriptors defines for Tx and Rx DMA */
-#define TX_BD_NUM_DEFAULT		64
+#define TX_BD_NUM_DEFAULT		128
 #define RX_BD_NUM_DEFAULT		1024
+#define TX_BD_NUM_MIN			(MAX_SKB_FRAGS + 1)
 #define TX_BD_NUM_MAX			4096
 #define RX_BD_NUM_MAX			4096
 
@@ -437,9 +438,10 @@
 	lp->options |= options;
 }
 
-static void __axienet_device_reset(struct axienet_local *lp)
+static int __axienet_device_reset(struct axienet_local *lp)
 {
 	u32 timeout;
+
 	/* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset
 	 * process of Axi DMA takes a while to complete as all pending
 	 * commands/transfers will be flushed or completed during this
@@ -455,9 +457,11 @@
 		if (--timeout == 0) {
 			netdev_err(lp->ndev, "%s: DMA reset timeout!\n",
 				   __func__);
-			break;
+			return -ETIMEDOUT;
 		}
 	}
+
+	return 0;
 }
 
 /**
@@ -470,13 +474,17 @@
  * areconnected to Axi Ethernet reset lines, this in turn resets the Axi
  * Ethernet core. No separate hardware reset is done for the Axi Ethernet
  * core.
+ * Returns 0 on success or a negative error number otherwise.
  */
-static void axienet_device_reset(struct net_device *ndev)
+static int axienet_device_reset(struct net_device *ndev)
 {
 	u32 axienet_status;
 	struct axienet_local *lp = netdev_priv(ndev);
+	int ret;
 
-	__axienet_device_reset(lp);
+	ret = __axienet_device_reset(lp);
+	if (ret)
+		return ret;
 
 	lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
 	lp->options |= XAE_OPTION_VLAN;
@@ -491,9 +499,11 @@
 			lp->options |= XAE_OPTION_JUMBO;
 	}
 
-	if (axienet_dma_bd_init(ndev)) {
+	ret = axienet_dma_bd_init(ndev);
+	if (ret) {
 		netdev_err(ndev, "%s: descriptor allocation failed\n",
 			   __func__);
+		return ret;
 	}
 
 	axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
@@ -518,6 +528,8 @@
 	axienet_setoptions(ndev, lp->options);
 
 	netif_trans_update(ndev);
+
+	return 0;
 }
 
 /**
@@ -624,7 +636,7 @@
 	num_frag = skb_shinfo(skb)->nr_frags;
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-	if (axienet_check_tx_bd_space(lp, num_frag)) {
+	if (axienet_check_tx_bd_space(lp, num_frag + 1)) {
 		if (netif_queue_stopped(ndev))
 			return NETDEV_TX_BUSY;
 
@@ -634,7 +646,7 @@
 		smp_mb();
 
 		/* Space might have just been freed - check again */
-		if (axienet_check_tx_bd_space(lp, num_frag))
+		if (axienet_check_tx_bd_space(lp, num_frag + 1))
 			return NETDEV_TX_BUSY;
 
 		netif_wake_queue(ndev);
@@ -644,7 +656,7 @@
 		if (lp->features & XAE_FEATURE_FULL_TX_CSUM) {
 			/* Tx Full Checksum Offload Enabled */
 			cur_p->app0 |= 2;
-		} else if (lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) {
+		} else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) {
 			csum_start_off = skb_transport_offset(skb);
 			csum_index_off = csum_start_off + skb->csum_offset;
 			/* Tx Partial Checksum Offload Enabled */
@@ -806,7 +818,7 @@
 		/* Write to the Rx channel control register */
 		axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
 
-		tasklet_schedule(&lp->dma_err_tasklet);
+		schedule_work(&lp->dma_err_task);
 		axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
 	}
 out:
@@ -855,7 +867,7 @@
 		/* write to the Rx channel control register */
 		axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
 
-		tasklet_schedule(&lp->dma_err_tasklet);
+		schedule_work(&lp->dma_err_task);
 		axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
 	}
 out:
@@ -891,7 +903,7 @@
 	return IRQ_HANDLED;
 }
 
-static void axienet_dma_err_handler(unsigned long data);
+static void axienet_dma_err_handler(struct work_struct *work);
 
 /**
  * axienet_open - Driver open routine.
@@ -921,8 +933,9 @@
 	 */
 	mutex_lock(&lp->mii_bus->mdio_lock);
 	axienet_mdio_disable(lp);
-	axienet_device_reset(ndev);
-	ret = axienet_mdio_enable(lp);
+	ret = axienet_device_reset(ndev);
+	if (ret == 0)
+		ret = axienet_mdio_enable(lp);
 	mutex_unlock(&lp->mii_bus->mdio_lock);
 	if (ret < 0)
 		return ret;
@@ -935,9 +948,8 @@
 
 	phylink_start(lp->phylink);
 
-	/* Enable tasklets for Axi DMA error handling */
-	tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
-		     (unsigned long) lp);
+	/* Enable worker thread for Axi DMA error handling */
+	INIT_WORK(&lp->dma_err_task, axienet_dma_err_handler);
 
 	/* Enable interrupts for Axi DMA Tx */
 	ret = request_irq(lp->tx_irq, axienet_tx_irq, IRQF_SHARED,
@@ -966,7 +978,7 @@
 err_tx_irq:
 	phylink_stop(lp->phylink);
 	phylink_disconnect_phy(lp->phylink);
-	tasklet_kill(&lp->dma_err_tasklet);
+	cancel_work_sync(&lp->dma_err_task);
 	dev_err(lp->dev, "request_irq() failed\n");
 	return ret;
 }
@@ -1025,7 +1037,7 @@
 	axienet_mdio_enable(lp);
 	mutex_unlock(&lp->mii_bus->mdio_lock);
 
-	tasklet_kill(&lp->dma_err_tasklet);
+	cancel_work_sync(&lp->dma_err_task);
 
 	if (lp->eth_irq > 0)
 		free_irq(lp->eth_irq, ndev);
@@ -1212,7 +1224,8 @@
 	if (ering->rx_pending > RX_BD_NUM_MAX ||
 	    ering->rx_mini_pending ||
 	    ering->rx_jumbo_pending ||
-	    ering->rx_pending > TX_BD_NUM_MAX)
+	    ering->tx_pending < TX_BD_NUM_MIN ||
+	    ering->tx_pending > TX_BD_NUM_MAX)
 		return -EINVAL;
 
 	if (netif_running(ndev))
@@ -1505,17 +1518,18 @@
 };
 
 /**
- * axienet_dma_err_handler - Tasklet handler for Axi DMA Error
- * @data:	Data passed
+ * axienet_dma_err_handler - Work queue task for Axi DMA Error
+ * @work:	pointer to work_struct
  *
  * Resets the Axi DMA and Axi Ethernet devices, and reconfigures the
  * Tx/Rx BDs.
  */
-static void axienet_dma_err_handler(unsigned long data)
+static void axienet_dma_err_handler(struct work_struct *work)
 {
 	u32 axienet_status;
 	u32 cr, i;
-	struct axienet_local *lp = (struct axienet_local *) data;
+	struct axienet_local *lp = container_of(work, struct axienet_local,
+						dma_err_task);
 	struct net_device *ndev = lp->ndev;
 	struct axidma_bd *cur_p;
 
@@ -1677,6 +1691,18 @@
 	lp->options = XAE_OPTION_DEFAULTS;
 	lp->rx_bd_num = RX_BD_NUM_DEFAULT;
 	lp->tx_bd_num = TX_BD_NUM_DEFAULT;
+
+	lp->clk = devm_clk_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(lp->clk)) {
+		ret = PTR_ERR(lp->clk);
+		goto free_netdev;
+	}
+	ret = clk_prepare_enable(lp->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to enable clock: %d\n", ret);
+		goto free_netdev;
+	}
+
 	/* Map device registers */
 	ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
@@ -1790,10 +1816,6 @@
 		/* Check for these resources directly on the Ethernet node. */
 		struct resource *res = platform_get_resource(pdev,
 							     IORESOURCE_MEM, 1);
-		if (!res) {
-			dev_err(&pdev->dev, "unable to get DMA memory resource\n");
-			goto free_netdev;
-		}
 		lp->dma_regs = devm_ioremap_resource(&pdev->dev, res);
 		lp->rx_irq = platform_get_irq(pdev, 1);
 		lp->tx_irq = platform_get_irq(pdev, 0);
@@ -1828,20 +1850,6 @@
 
 	lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
 	if (lp->phy_node) {
-		lp->clk = devm_clk_get(&pdev->dev, NULL);
-		if (IS_ERR(lp->clk)) {
-			dev_warn(&pdev->dev, "Failed to get clock: %ld\n",
-				 PTR_ERR(lp->clk));
-			lp->clk = NULL;
-		} else {
-			ret = clk_prepare_enable(lp->clk);
-			if (ret) {
-				dev_err(&pdev->dev, "Unable to enable clock: %d\n",
-					ret);
-				goto free_netdev;
-			}
-		}
-
 		ret = axienet_mdio_setup(lp);
 		if (ret)
 			dev_warn(&pdev->dev,
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ linux-ein-5.4.0/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -541,7 +541,7 @@
 	xemaclite_enable_interrupts(lp);
 
 	if (lp->deferred_skb) {
-		dev_kfree_skb(lp->deferred_skb);
+		dev_kfree_skb_irq(lp->deferred_skb);
 		lp->deferred_skb = NULL;
 		dev->stats.tx_errors++;
 	}
@@ -820,10 +820,10 @@
 static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
 {
 	struct mii_bus *bus;
-	int rc;
 	struct resource res;
 	struct device_node *np = of_get_parent(lp->phy_node);
 	struct device_node *npp;
+	int rc, ret;
 
 	/* Don't register the MDIO bus if the phy_node or its parent node
 	 * can't be found.
@@ -833,8 +833,14 @@
 		return -ENODEV;
 	}
 	npp = of_get_parent(np);
-
-	of_address_to_resource(npp, 0, &res);
+	ret = of_address_to_resource(npp, 0, &res);
+	of_node_put(npp);
+	if (ret) {
+		dev_err(dev, "%s resource error!\n",
+			dev->of_node->full_name);
+		of_node_put(np);
+		return ret;
+	}
 	if (lp->ndev->mem_start != res.start) {
 		struct phy_device *phydev;
 		phydev = of_phy_find_device(lp->phy_node);
@@ -843,6 +849,7 @@
 				 "MDIO of the phy is not registered yet\n");
 		else
 			put_device(&phydev->mdio.dev);
+		of_node_put(np);
 		return 0;
 	}
 
@@ -855,6 +862,7 @@
 	bus = mdiobus_alloc();
 	if (!bus) {
 		dev_err(dev, "Failed to allocate mdiobus\n");
+		of_node_put(np);
 		return -ENOMEM;
 	}
 
@@ -867,6 +875,7 @@
 	bus->parent = dev;
 
 	rc = of_mdiobus_register(bus, np);
+	of_node_put(np);
 	if (rc) {
 		dev_err(dev, "Failed to register mdio bus.\n");
 		goto err_register;
@@ -923,8 +932,6 @@
 	xemaclite_disable_interrupts(lp);
 
 	if (lp->phy_node) {
-		u32 bmcr;
-
 		lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
 					     xemaclite_adjust_link, 0,
 					     PHY_INTERFACE_MODE_MII);
@@ -935,19 +942,6 @@
 
 		/* EmacLite doesn't support giga-bit speeds */
 		phy_set_max_speed(lp->phy_dev, SPEED_100);
-
-		/* Don't advertise 1000BASE-T Full/Half duplex speeds */
-		phy_write(lp->phy_dev, MII_CTRL1000, 0);
-
-		/* Advertise only 10 and 100mbps full/half duplex speeds */
-		phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL |
-			  ADVERTISE_CSMA);
-
-		/* Restart auto negotiation */
-		bmcr = phy_read(lp->phy_dev, MII_BMCR);
-		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
-		phy_write(lp->phy_dev, MII_BMCR, bmcr);
-
 		phy_start(lp->phy_dev);
 	}
 
@@ -1187,15 +1181,16 @@
 	if (rc) {
 		dev_err(dev,
 			"Cannot register network device, aborting\n");
-		goto error;
+		goto put_node;
 	}
 
 	dev_info(dev,
-		 "Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n",
-		 (unsigned int __force)ndev->mem_start,
-		 (unsigned int __force)lp->base_addr, ndev->irq);
+		 "Xilinx EmacLite at 0x%08X mapped to 0x%p, irq=%d\n",
+		 (unsigned int __force)ndev->mem_start, lp->base_addr, ndev->irq);
 	return 0;
 
+put_node:
+	of_node_put(lp->phy_node);
 error:
 	free_netdev(ndev);
 	return rc;
--- linux-ein-5.4.0.orig/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ linux-ein-5.4.0/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -503,6 +503,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-ein-5.4.0.orig/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ linux-ein-5.4.0/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -517,25 +517,14 @@
 	return ret;
 }
 
-static int ixp4xx_mdio_register(void)
+static int ixp4xx_mdio_register(struct eth_regs __iomem *regs)
 {
 	int err;
 
 	if (!(mdio_bus = mdiobus_alloc()))
 		return -ENOMEM;
 
-	if (cpu_is_ixp43x()) {
-		/* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
-		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
-			return -ENODEV;
-		mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
-	} else {
-		/* All MII PHY accesses use NPE-B Ethernet registers */
-		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
-			return -ENODEV;
-		mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
-	}
-
+	mdio_regs = regs;
 	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
 	spin_lock_init(&mdio_lock);
 	mdio_bus->name = "IXP4xx MII Bus";
@@ -1374,7 +1363,7 @@
 	.ndo_validate_addr = eth_validate_addr,
 };
 
-static int eth_init_one(struct platform_device *pdev)
+static int ixp4xx_eth_probe(struct platform_device *pdev)
 {
 	struct port *port;
 	struct net_device *dev;
@@ -1384,7 +1373,7 @@
 	char phy_id[MII_BUS_ID_SIZE + 3];
 	int err;
 
-	if (!(dev = alloc_etherdev(sizeof(struct port))))
+	if (!(dev = devm_alloc_etherdev(&pdev->dev, sizeof(struct port))))
 		return -ENOMEM;
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1394,20 +1383,51 @@
 
 	switch (port->id) {
 	case IXP4XX_ETH_NPEA:
+		/* If the MDIO bus is not up yet, defer probe */
+		if (!mdio_bus)
+			return -EPROBE_DEFER;
 		port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT;
 		regs_phys  = IXP4XX_EthA_BASE_PHYS;
 		break;
 	case IXP4XX_ETH_NPEB:
+		/*
+		 * On all except IXP43x, NPE-B is used for the MDIO bus.
+		 * If there is no NPE-B in the feature set, bail out, else
+		 * register the MDIO bus.
+		 */
+		if (!cpu_is_ixp43x()) {
+			if (!(ixp4xx_read_feature_bits() &
+			      IXP4XX_FEATURE_NPEB_ETH0))
+				return -ENODEV;
+			/* Else register the MDIO bus on NPE-B */
+			if ((err = ixp4xx_mdio_register(IXP4XX_EthC_BASE_VIRT)))
+				return err;
+		}
+		if (!mdio_bus)
+			return -EPROBE_DEFER;
 		port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
 		regs_phys  = IXP4XX_EthB_BASE_PHYS;
 		break;
 	case IXP4XX_ETH_NPEC:
+		/*
+		 * IXP43x lacks NPE-B and uses NPE-C for the MDIO bus access,
+		 * of there is no NPE-C, no bus, nothing works, so bail out.
+		 */
+		if (cpu_is_ixp43x()) {
+			if (!(ixp4xx_read_feature_bits() &
+			      IXP4XX_FEATURE_NPEC_ETH))
+				return -ENODEV;
+			/* Else register the MDIO bus on NPE-C */
+			if ((err = ixp4xx_mdio_register(IXP4XX_EthC_BASE_VIRT)))
+				return err;
+		}
+		if (!mdio_bus)
+			return -EPROBE_DEFER;
 		port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
 		regs_phys  = IXP4XX_EthC_BASE_PHYS;
 		break;
 	default:
-		err = -ENODEV;
-		goto err_free;
+		return -ENODEV;
 	}
 
 	dev->netdev_ops = &ixp4xx_netdev_ops;
@@ -1416,10 +1436,8 @@
 
 	netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
 
-	if (!(port->npe = npe_request(NPE_ID(port->id)))) {
-		err = -EIO;
-		goto err_free;
-	}
+	if (!(port->npe = npe_request(NPE_ID(port->id))))
+		return -EIO;
 
 	port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name);
 	if (!port->mem_res) {
@@ -1465,12 +1483,10 @@
 	release_resource(port->mem_res);
 err_npe_rel:
 	npe_release(port->npe);
-err_free:
-	free_netdev(dev);
 	return err;
 }
 
-static int eth_remove_one(struct platform_device *pdev)
+static int ixp4xx_eth_remove(struct platform_device *pdev)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 	struct phy_device *phydev = dev->phydev;
@@ -1478,45 +1494,21 @@
 
 	unregister_netdev(dev);
 	phy_disconnect(phydev);
+	ixp4xx_mdio_remove();
 	npe_port_tab[NPE_ID(port->id)] = NULL;
 	npe_release(port->npe);
 	release_resource(port->mem_res);
-	free_netdev(dev);
 	return 0;
 }
 
 static struct platform_driver ixp4xx_eth_driver = {
 	.driver.name	= DRV_NAME,
-	.probe		= eth_init_one,
-	.remove		= eth_remove_one,
+	.probe		= ixp4xx_eth_probe,
+	.remove		= ixp4xx_eth_remove,
 };
-
-static int __init eth_init_module(void)
-{
-	int err;
-
-	/*
-	 * FIXME: we bail out on device tree boot but this really needs
-	 * to be fixed in a nicer way: this registers the MDIO bus before
-	 * even matching the driver infrastructure, we should only probe
-	 * detected hardware.
-	 */
-	if (of_have_populated_dt())
-		return -ENODEV;
-	if ((err = ixp4xx_mdio_register()))
-		return err;
-	return platform_driver_register(&ixp4xx_eth_driver);
-}
-
-static void __exit eth_cleanup_module(void)
-{
-	platform_driver_unregister(&ixp4xx_eth_driver);
-	ixp4xx_mdio_remove();
-}
+module_platform_driver(ixp4xx_eth_driver);
 
 MODULE_AUTHOR("Krzysztof Halasa");
 MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:ixp4xx_eth");
-module_init(eth_init_module);
-module_exit(eth_cleanup_module);
--- linux-ein-5.4.0.orig/drivers/net/fddi/Kconfig
+++ linux-ein-5.4.0/drivers/net/fddi/Kconfig
@@ -40,17 +40,20 @@
 
 config DEFXX_MMIO
 	bool
-	prompt "Use MMIO instead of PIO" if PCI || EISA
+	prompt "Use MMIO instead of IOP" if PCI || EISA
 	depends on DEFXX
-	default n if PCI || EISA
+	default n if EISA
 	default y
 	---help---
 	  This instructs the driver to use EISA or PCI memory-mapped I/O
-	  (MMIO) as appropriate instead of programmed I/O ports (PIO).
+	  (MMIO) as appropriate instead of programmed I/O ports (IOP).
 	  Enabling this gives an improvement in processing time in parts
-	  of the driver, but it may cause problems with EISA (DEFEA)
-	  adapters.  TURBOchannel does not have the concept of I/O ports,
-	  so MMIO is always used for these (DEFTA) adapters.
+	  of the driver, but it requires a memory window to be configured
+	  for EISA (DEFEA) adapters that may not always be available.
+	  Conversely some PCIe host bridges do not support IOP, so MMIO
+	  may be required to access PCI (DEFPA) adapters on downstream PCI
+	  buses with some systems.  TURBOchannel does not have the concept
+	  of I/O ports, so MMIO is always used for these (DEFTA) adapters.
 
 	  If unsure, say N.
 
--- linux-ein-5.4.0.orig/drivers/net/fddi/defxx.c
+++ linux-ein-5.4.0/drivers/net/fddi/defxx.c
@@ -495,6 +495,25 @@
 	.ndo_set_mac_address	= dfx_ctl_set_mac_address,
 };
 
+static void dfx_register_res_alloc_err(const char *print_name, bool mmio,
+				       bool eisa)
+{
+	pr_err("%s: Cannot use %s, no address set, aborting\n",
+	       print_name, mmio ? "MMIO" : "I/O");
+	pr_err("%s: Recompile driver with \"CONFIG_DEFXX_MMIO=%c\"\n",
+	       print_name, mmio ? 'n' : 'y');
+	if (eisa && mmio)
+		pr_err("%s: Or run ECU and set adapter's MMIO location\n",
+		       print_name);
+}
+
+static void dfx_register_res_err(const char *print_name, bool mmio,
+				 unsigned long start, unsigned long len)
+{
+	pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, aborting\n",
+	       print_name, mmio ? "MMIO" : "I/O", len, start);
+}
+
 /*
  * ================
  * = dfx_register =
@@ -568,15 +587,12 @@
 	dev_set_drvdata(bdev, dev);
 
 	dfx_get_bars(bdev, bar_start, bar_len);
-	if (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0) {
-		pr_err("%s: Cannot use MMIO, no address set, aborting\n",
-		       print_name);
-		pr_err("%s: Run ECU and set adapter's MMIO location\n",
-		       print_name);
-		pr_err("%s: Or recompile driver with \"CONFIG_DEFXX_MMIO=n\""
-		       "\n", print_name);
+	if (bar_len[0] == 0 ||
+	    (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0)) {
+		dfx_register_res_alloc_err(print_name, dfx_use_mmio,
+					   dfx_bus_eisa);
 		err = -ENXIO;
-		goto err_out;
+		goto err_out_disable;
 	}
 
 	if (dfx_use_mmio)
@@ -585,18 +601,16 @@
 	else
 		region = request_region(bar_start[0], bar_len[0], print_name);
 	if (!region) {
-		pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, "
-		       "aborting\n", dfx_use_mmio ? "MMIO" : "I/O", print_name,
-		       (long)bar_len[0], (long)bar_start[0]);
+		dfx_register_res_err(print_name, dfx_use_mmio,
+				     bar_start[0], bar_len[0]);
 		err = -EBUSY;
 		goto err_out_disable;
 	}
 	if (bar_start[1] != 0) {
 		region = request_region(bar_start[1], bar_len[1], print_name);
 		if (!region) {
-			pr_err("%s: Cannot reserve I/O resource "
-			       "0x%lx @ 0x%lx, aborting\n", print_name,
-			       (long)bar_len[1], (long)bar_start[1]);
+			dfx_register_res_err(print_name, 0,
+					     bar_start[1], bar_len[1]);
 			err = -EBUSY;
 			goto err_out_csr_region;
 		}
@@ -604,9 +618,8 @@
 	if (bar_start[2] != 0) {
 		region = request_region(bar_start[2], bar_len[2], print_name);
 		if (!region) {
-			pr_err("%s: Cannot reserve I/O resource "
-			       "0x%lx @ 0x%lx, aborting\n", print_name,
-			       (long)bar_len[2], (long)bar_start[2]);
+			dfx_register_res_err(print_name, 0,
+					     bar_start[2], bar_len[2]);
 			err = -EBUSY;
 			goto err_out_bh_region;
 		}
@@ -3831,10 +3844,24 @@
 	int status;
 
 	status = pci_register_driver(&dfx_pci_driver);
-	if (!status)
-		status = eisa_driver_register(&dfx_eisa_driver);
-	if (!status)
-		status = tc_register_driver(&dfx_tc_driver);
+	if (status)
+		goto err_pci_register;
+
+	status = eisa_driver_register(&dfx_eisa_driver);
+	if (status)
+		goto err_eisa_register;
+
+	status = tc_register_driver(&dfx_tc_driver);
+	if (status)
+		goto err_tc_register;
+
+	return 0;
+
+err_tc_register:
+	eisa_driver_unregister(&dfx_eisa_driver);
+err_eisa_register:
+	pci_unregister_driver(&dfx_pci_driver);
+err_pci_register:
 	return status;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/fddi/defza.c
+++ linux-ein-5.4.0/drivers/net/fddi/defza.c
@@ -1504,9 +1504,8 @@
 	release_mem_region(start, len);
 
 err_out_kfree:
-	free_netdev(dev);
-
 	pr_err("%s: initialization failure, aborting!\n", fp->name);
+	free_netdev(dev);
 	return ret;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/fjes/fjes_hw.c
+++ linux-ein-5.4.0/drivers/net/fjes/fjes_hw.c
@@ -220,21 +220,25 @@
 
 	mem_size = FJES_DEV_REQ_BUF_SIZE(hw->max_epid);
 	hw->hw_info.req_buf = kzalloc(mem_size, GFP_KERNEL);
-	if (!(hw->hw_info.req_buf))
-		return -ENOMEM;
+	if (!(hw->hw_info.req_buf)) {
+		result = -ENOMEM;
+		goto free_ep_info;
+	}
 
 	hw->hw_info.req_buf_size = mem_size;
 
 	mem_size = FJES_DEV_RES_BUF_SIZE(hw->max_epid);
 	hw->hw_info.res_buf = kzalloc(mem_size, GFP_KERNEL);
-	if (!(hw->hw_info.res_buf))
-		return -ENOMEM;
+	if (!(hw->hw_info.res_buf)) {
+		result = -ENOMEM;
+		goto free_req_buf;
+	}
 
 	hw->hw_info.res_buf_size = mem_size;
 
 	result = fjes_hw_alloc_shared_status_region(hw);
 	if (result)
-		return result;
+		goto free_res_buf;
 
 	hw->hw_info.buffer_share_bit = 0;
 	hw->hw_info.buffer_unshare_reserve_bit = 0;
@@ -245,11 +249,11 @@
 
 			result = fjes_hw_alloc_epbuf(&buf_pair->tx);
 			if (result)
-				return result;
+				goto free_epbuf;
 
 			result = fjes_hw_alloc_epbuf(&buf_pair->rx);
 			if (result)
-				return result;
+				goto free_epbuf;
 
 			spin_lock_irqsave(&hw->rx_status_lock, flags);
 			fjes_hw_setup_epbuf(&buf_pair->tx, mac,
@@ -272,6 +276,25 @@
 	fjes_hw_init_command_registers(hw, &param);
 
 	return 0;
+
+free_epbuf:
+	for (epidx = 0; epidx < hw->max_epid ; epidx++) {
+		if (epidx == hw->my_epid)
+			continue;
+		fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx);
+		fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx);
+	}
+	fjes_hw_free_shared_status_region(hw);
+free_res_buf:
+	kfree(hw->hw_info.res_buf);
+	hw->hw_info.res_buf = NULL;
+free_req_buf:
+	kfree(hw->hw_info.req_buf);
+	hw->hw_info.req_buf = NULL;
+free_ep_info:
+	kfree(hw->ep_shm_info);
+	hw->ep_shm_info = NULL;
+	return result;
 }
 
 static void fjes_hw_cleanup(struct fjes_hw *hw)
--- linux-ein-5.4.0.orig/drivers/net/fjes/fjes_main.c
+++ linux-ein-5.4.0/drivers/net/fjes/fjes_main.c
@@ -166,6 +166,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;
@@ -1259,9 +1262,18 @@
 	adapter->interrupt_watch_enable = false;
 
 	res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -EINVAL;
+		goto err_free_control_wq;
+	}
 	hw->hw_res.start = res->start;
 	hw->hw_res.size = resource_size(res);
 	hw->hw_res.irq = platform_get_irq(plat_dev, 0);
+	if (hw->hw_res.irq < 0) {
+		err = hw->hw_res.irq;
+		goto err_free_control_wq;
+	}
+
 	err = fjes_hw_init(&adapter->hw);
 	if (err)
 		goto err_free_control_wq;
--- linux-ein-5.4.0.orig/drivers/net/geneve.c
+++ linux-ein-5.4.0/drivers/net/geneve.c
@@ -221,8 +221,7 @@
 	if (ip_tunnel_collect_metadata() || gs->collect_md) {
 		__be16 flags;
 
-		flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT |
-			(gnvh->oam ? TUNNEL_OAM : 0) |
+		flags = TUNNEL_KEY | (gnvh->oam ? TUNNEL_OAM : 0) |
 			(gnvh->critical ? TUNNEL_CRIT_OPT : 0);
 
 		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
@@ -773,7 +772,8 @@
 				       struct net_device *dev,
 				       struct geneve_sock *gs4,
 				       struct flowi4 *fl4,
-				       const struct ip_tunnel_info *info)
+				       const struct ip_tunnel_info *info,
+				       __be16 dport, __be16 sport)
 {
 	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
 	struct geneve_dev *geneve = netdev_priv(dev);
@@ -789,6 +789,8 @@
 	fl4->flowi4_proto = IPPROTO_UDP;
 	fl4->daddr = info->key.u.ipv4.dst;
 	fl4->saddr = info->key.u.ipv4.src;
+	fl4->fl4_dport = dport;
+	fl4->fl4_sport = sport;
 
 	tos = info->key.tos;
 	if ((tos == 1) && !geneve->collect_md) {
@@ -823,7 +825,8 @@
 					   struct net_device *dev,
 					   struct geneve_sock *gs6,
 					   struct flowi6 *fl6,
-					   const struct ip_tunnel_info *info)
+					   const struct ip_tunnel_info *info,
+					   __be16 dport, __be16 sport)
 {
 	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
 	struct geneve_dev *geneve = netdev_priv(dev);
@@ -839,21 +842,25 @@
 	fl6->flowi6_proto = IPPROTO_UDP;
 	fl6->daddr = info->key.u.ipv6.dst;
 	fl6->saddr = info->key.u.ipv6.src;
+	fl6->fl6_dport = dport;
+	fl6->fl6_sport = sport;
+
 	prio = info->key.tos;
 	if ((prio == 1) && !geneve->collect_md) {
 		prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
 		use_cache = false;
 	}
 
-	fl6->flowlabel = ip6_make_flowinfo(RT_TOS(prio),
-					   info->key.label);
+	fl6->flowlabel = ip6_make_flowinfo(prio, info->key.label);
 	dst_cache = (struct dst_cache *)&info->dst_cache;
 	if (use_cache) {
 		dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
 		if (dst)
 			return dst;
 	}
-	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);
 	}
@@ -883,14 +890,18 @@
 	__be16 sport;
 	int err;
 
-	rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
+	if (!pskb_inet_may_pull(skb))
+		return -EINVAL;
+
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
+			      geneve->info.key.tp_dst, sport);
 	if (IS_ERR(rt))
 		return PTR_ERR(rt);
 
 	skb_tunnel_check_pmtu(skb, &rt->dst,
 			      GENEVE_IPV4_HLEN + info->options_len);
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	if (geneve->collect_md) {
 		tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
 		ttl = key->ttl;
@@ -945,13 +956,17 @@
 	__be16 sport;
 	int err;
 
-	dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
+	if (!pskb_inet_may_pull(skb))
+		return -EINVAL;
+
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
+				geneve->info.key.tp_dst, sport);
 	if (IS_ERR(dst))
 		return PTR_ERR(dst);
 
 	skb_tunnel_check_pmtu(skb, dst, GENEVE_IPV6_HLEN + info->options_len);
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	if (geneve->collect_md) {
 		prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
 		ttl = key->ttl;
@@ -985,9 +1000,10 @@
 	if (geneve->collect_md) {
 		info = skb_tunnel_info(skb);
 		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
-			err = -EINVAL;
 			netdev_dbg(dev, "no tunnel metadata\n");
-			goto tx_error;
+			dev_kfree_skb(skb);
+			dev->stats.tx_dropped++;
+			return NETDEV_TX_OK;
 		}
 	} else {
 		info = &geneve->info;
@@ -1004,7 +1020,7 @@
 
 	if (likely(!err))
 		return NETDEV_TX_OK;
-tx_error:
+
 	dev_kfree_skb(skb);
 
 	if (err == -ELOOP)
@@ -1031,13 +1047,18 @@
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct geneve_dev *geneve = netdev_priv(dev);
+	__be16 sport;
 
 	if (ip_tunnel_info_af(info) == AF_INET) {
 		struct rtable *rt;
 		struct flowi4 fl4;
+
 		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
 
-		rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
+		rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
+				      geneve->info.key.tp_dst, sport);
 		if (IS_ERR(rt))
 			return PTR_ERR(rt);
 
@@ -1047,9 +1068,13 @@
 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
 		struct dst_entry *dst;
 		struct flowi6 fl6;
+
 		struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
 
-		dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
+		dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
+					geneve->info.key.tp_dst, sport);
 		if (IS_ERR(dst))
 			return PTR_ERR(dst);
 
@@ -1060,8 +1085,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->info.key.tp_dst;
 	return 0;
 }
@@ -1205,7 +1229,7 @@
 		enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
 
 		if (df < 0 || df > GENEVE_DF_MAX) {
-			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_GENEVE_DF],
+			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_DF],
 					    "Invalid DF attribute");
 			return -EINVAL;
 		}
@@ -1612,11 +1636,11 @@
 			     struct netlink_ext_ack *extack)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
+	enum ifla_geneve_df df = geneve->df;
 	struct geneve_sock *gs4, *gs6;
 	struct ip_tunnel_info info;
 	bool metadata;
 	bool use_udp6_rx_checksums;
-	enum ifla_geneve_df df;
 	bool ttl_inherit;
 	int err;
 
@@ -1646,6 +1670,7 @@
 	geneve->collect_md = metadata;
 	geneve->use_udp6_rx_checksums = use_udp6_rx_checksums;
 	geneve->ttl_inherit = ttl_inherit;
+	geneve->df = df;
 	geneve_unquiesce(geneve, gs4, gs6);
 
 	return 0;
@@ -1843,8 +1868,6 @@
 		if (!net_eq(dev_net(geneve->dev), net))
 			unregister_netdevice_queue(geneve->dev, head);
 	}
-
-	WARN_ON_ONCE(!list_empty(&gn->sock_list));
 }
 
 static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
@@ -1859,6 +1882,12 @@
 	/* unregister the devices gathered above */
 	unregister_netdevice_many(&list);
 	rtnl_unlock();
+
+	list_for_each_entry(net, net_list, exit_list) {
+		const struct geneve_net *gn = net_generic(net, geneve_net_id);
+
+		WARN_ON_ONCE(!list_empty(&gn->sock_list));
+	}
 }
 
 static struct pernet_operations geneve_net_ops = {
--- linux-ein-5.4.0.orig/drivers/net/gtp.c
+++ linux-ein-5.4.0/drivers/net/gtp.c
@@ -38,7 +38,6 @@
 	struct hlist_node	hlist_addr;
 
 	union {
-		u64		tid;
 		struct {
 			u64	tid;
 			u16	flow;
@@ -298,7 +297,9 @@
 			gtp->sk1u = NULL;
 		udp_sk(sk)->encap_type = 0;
 		rcu_assign_sk_user_data(sk, NULL);
+		release_sock(sk);
 		sock_put(sk);
+		return;
 	}
 	release_sock(sk);
 }
@@ -541,14 +542,14 @@
 		mtu = dst_mtu(&rt->dst);
 	}
 
-	rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu);
+	rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu, false);
 
-	if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) &&
-	    mtu < ntohs(iph->tot_len)) {
+	if (iph->frag_off & htons(IP_DF) &&
+	    ((!skb_is_gso(skb) && skb->len > mtu) ||
+	     (skb_is_gso(skb) && !skb_gso_validate_network_len(skb, mtu)))) {
 		netdev_dbg(dev, "packet too big, fragmentation needed\n");
-		memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-			  htonl(mtu));
+		icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+			      htonl(mtu));
 		goto err_rt;
 	}
 
@@ -641,9 +642,16 @@
 }
 
 static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
-static void gtp_hashtable_free(struct gtp_dev *gtp);
 static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);
 
+static void gtp_destructor(struct net_device *dev)
+{
+	struct gtp_dev *gtp = netdev_priv(dev);
+
+	kfree(gtp->addr_hash);
+	kfree(gtp->tid_hash);
+}
+
 static int gtp_newlink(struct net *src_net, struct net_device *dev,
 		       struct nlattr *tb[], struct nlattr *data[],
 		       struct netlink_ext_ack *extack)
@@ -657,44 +665,54 @@
 
 	gtp = netdev_priv(dev);
 
-	err = gtp_encap_enable(gtp, data);
-	if (err < 0)
-		return err;
-
-	if (!data[IFLA_GTP_PDP_HASHSIZE])
+	if (!data[IFLA_GTP_PDP_HASHSIZE]) {
 		hashsize = 1024;
-	else
+	} else {
 		hashsize = nla_get_u32(data[IFLA_GTP_PDP_HASHSIZE]);
+		if (!hashsize)
+			hashsize = 1024;
+	}
 
 	err = gtp_hashtable_new(gtp, hashsize);
 	if (err < 0)
-		goto out_encap;
+		return err;
+
+	err = gtp_encap_enable(gtp, data);
+	if (err < 0)
+		goto out_hashtable;
 
 	err = register_netdevice(dev);
 	if (err < 0) {
 		netdev_dbg(dev, "failed to register new netdev %d\n", err);
-		goto out_hashtable;
+		goto out_encap;
 	}
 
 	gn = net_generic(dev_net(dev), gtp_net_id);
 	list_add_rcu(&gtp->list, &gn->gtp_dev_list);
+	dev->priv_destructor = gtp_destructor;
 
 	netdev_dbg(dev, "registered new GTP interface\n");
 
 	return 0;
 
-out_hashtable:
-	gtp_hashtable_free(gtp);
 out_encap:
 	gtp_encap_disable(gtp);
+out_hashtable:
+	kfree(gtp->addr_hash);
+	kfree(gtp->tid_hash);
 	return err;
 }
 
 static void gtp_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct gtp_dev *gtp = netdev_priv(dev);
+	struct pdp_ctx *pctx;
+	int i;
+
+	for (i = 0; i < gtp->hash_size; i++)
+		hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i], hlist_tid)
+			pdp_context_delete(pctx);
 
-	gtp_hashtable_free(gtp);
 	list_del_rcu(&gtp->list);
 	unregister_netdevice_queue(dev, head);
 }
@@ -751,12 +769,12 @@
 	int i;
 
 	gtp->addr_hash = kmalloc_array(hsize, sizeof(struct hlist_head),
-				       GFP_KERNEL);
+				       GFP_KERNEL | __GFP_NOWARN);
 	if (gtp->addr_hash == NULL)
 		return -ENOMEM;
 
 	gtp->tid_hash = kmalloc_array(hsize, sizeof(struct hlist_head),
-				      GFP_KERNEL);
+				      GFP_KERNEL | __GFP_NOWARN);
 	if (gtp->tid_hash == NULL)
 		goto err1;
 
@@ -772,20 +790,6 @@
 	return -ENOMEM;
 }
 
-static void gtp_hashtable_free(struct gtp_dev *gtp)
-{
-	struct pdp_ctx *pctx;
-	int i;
-
-	for (i = 0; i < gtp->hash_size; i++)
-		hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i], hlist_tid)
-			pdp_context_delete(pctx);
-
-	synchronize_rcu();
-	kfree(gtp->addr_hash);
-	kfree(gtp->tid_hash);
-}
-
 static struct sock *gtp_encap_enable_socket(int fd, int type,
 					    struct gtp_dev *gtp)
 {
@@ -802,19 +806,21 @@
 		return NULL;
 	}
 
-	if (sock->sk->sk_protocol != IPPROTO_UDP) {
+	sk = sock->sk;
+	if (sk->sk_protocol != IPPROTO_UDP ||
+	    sk->sk_type != SOCK_DGRAM ||
+	    (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)) {
 		pr_debug("socket fd=%d not UDP\n", fd);
 		sk = ERR_PTR(-EINVAL);
 		goto out_sock;
 	}
 
-	lock_sock(sock->sk);
-	if (sock->sk->sk_user_data) {
+	lock_sock(sk);
+	if (sk->sk_user_data) {
 		sk = ERR_PTR(-EBUSY);
-		goto out_sock;
+		goto out_rel_sock;
 	}
 
-	sk = sock->sk;
 	sock_hold(sk);
 
 	tuncfg.sk_user_data = gtp;
@@ -824,8 +830,9 @@
 
 	setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);
 
-out_sock:
+out_rel_sock:
 	release_sock(sock->sk);
+out_sock:
 	sockfd_put(sock);
 	return sk;
 }
@@ -926,24 +933,31 @@
 	}
 }
 
-static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
-			struct genl_info *info)
+static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
+		       struct genl_info *info)
 {
+	struct pdp_ctx *pctx, *pctx_tid = NULL;
 	struct net_device *dev = gtp->dev;
 	u32 hash_ms, hash_tid = 0;
-	struct pdp_ctx *pctx;
+	unsigned int version;
 	bool found = false;
 	__be32 ms_addr;
 
 	ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
 	hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size;
+	version = nla_get_u32(info->attrs[GTPA_VERSION]);
 
-	hlist_for_each_entry_rcu(pctx, &gtp->addr_hash[hash_ms], hlist_addr) {
-		if (pctx->ms_addr_ip4.s_addr == ms_addr) {
-			found = true;
-			break;
-		}
-	}
+	pctx = ipv4_pdp_find(gtp, ms_addr);
+	if (pctx)
+		found = true;
+	if (version == GTP_V0)
+		pctx_tid = gtp0_pdp_find(gtp,
+					 nla_get_u64(info->attrs[GTPA_TID]));
+	else if (version == GTP_V1)
+		pctx_tid = gtp1_pdp_find(gtp,
+					 nla_get_u32(info->attrs[GTPA_I_TEI]));
+	if (pctx_tid)
+		found = true;
 
 	if (found) {
 		if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
@@ -951,6 +965,11 @@
 		if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
 			return -EOPNOTSUPP;
 
+		if (pctx && pctx_tid)
+			return -EEXIST;
+		if (!pctx)
+			pctx = pctx_tid;
+
 		ipv4_pdp_fill(pctx, info);
 
 		if (pctx->gtp_version == GTP_V0)
@@ -1074,7 +1093,7 @@
 		goto out_unlock;
 	}
 
-	err = ipv4_pdp_add(gtp, sk, info);
+	err = gtp_pdp_add(gtp, sk, info);
 
 out_unlock:
 	rcu_read_unlock();
@@ -1155,16 +1174,17 @@
 static struct genl_family gtp_genl_family;
 
 static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
-			      u32 type, struct pdp_ctx *pctx)
+			      int flags, u32 type, struct pdp_ctx *pctx)
 {
 	void *genlh;
 
-	genlh = genlmsg_put(skb, snd_portid, snd_seq, &gtp_genl_family, 0,
+	genlh = genlmsg_put(skb, snd_portid, snd_seq, &gtp_genl_family, flags,
 			    type);
 	if (genlh == NULL)
 		goto nlmsg_failure;
 
 	if (nla_put_u32(skb, GTPA_VERSION, pctx->gtp_version) ||
+	    nla_put_u32(skb, GTPA_LINK, pctx->dev->ifindex) ||
 	    nla_put_be32(skb, GTPA_PEER_ADDRESS, pctx->peer_addr_ip4.s_addr) ||
 	    nla_put_be32(skb, GTPA_MS_ADDRESS, pctx->ms_addr_ip4.s_addr))
 		goto nla_put_failure;
@@ -1213,8 +1233,8 @@
 		goto err_unlock;
 	}
 
-	err = gtp_genl_fill_info(skb2, NETLINK_CB(skb).portid,
-				 info->snd_seq, info->nlhdr->nlmsg_type, pctx);
+	err = gtp_genl_fill_info(skb2, NETLINK_CB(skb).portid, info->snd_seq,
+				 0, info->nlhdr->nlmsg_type, pctx);
 	if (err < 0)
 		goto err_unlock_free;
 
@@ -1232,43 +1252,47 @@
 				struct netlink_callback *cb)
 {
 	struct gtp_dev *last_gtp = (struct gtp_dev *)cb->args[2], *gtp;
+	int i, j, bucket = cb->args[0], skip = cb->args[1];
 	struct net *net = sock_net(skb->sk);
-	struct gtp_net *gn = net_generic(net, gtp_net_id);
-	unsigned long tid = cb->args[1];
-	int i, k = cb->args[0], ret;
 	struct pdp_ctx *pctx;
+	struct gtp_net *gn;
+
+	gn = net_generic(net, gtp_net_id);
 
 	if (cb->args[4])
 		return 0;
 
+	rcu_read_lock();
 	list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) {
 		if (last_gtp && last_gtp != gtp)
 			continue;
 		else
 			last_gtp = NULL;
 
-		for (i = k; i < gtp->hash_size; i++) {
-			hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i], hlist_tid) {
-				if (tid && tid != pctx->u.tid)
-					continue;
-				else
-					tid = 0;
-
-				ret = gtp_genl_fill_info(skb,
-							 NETLINK_CB(cb->skb).portid,
-							 cb->nlh->nlmsg_seq,
-							 cb->nlh->nlmsg_type, pctx);
-				if (ret < 0) {
+		for (i = bucket; i < gtp->hash_size; i++) {
+			j = 0;
+			hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i],
+						 hlist_tid) {
+				if (j >= skip &&
+				    gtp_genl_fill_info(skb,
+					    NETLINK_CB(cb->skb).portid,
+					    cb->nlh->nlmsg_seq,
+					    NLM_F_MULTI,
+					    cb->nlh->nlmsg_type, pctx)) {
 					cb->args[0] = i;
-					cb->args[1] = pctx->u.tid;
+					cb->args[1] = j;
 					cb->args[2] = (unsigned long)gtp;
 					goto out;
 				}
+				j++;
 			}
+			skip = 0;
 		}
+		bucket = 0;
 	}
 	cb->args[4] = 1;
 out:
+	rcu_read_unlock();
 	return skb->len;
 }
 
@@ -1353,26 +1377,26 @@
 
 	get_random_bytes(&gtp_h_initval, sizeof(gtp_h_initval));
 
-	err = rtnl_link_register(&gtp_link_ops);
+	err = register_pernet_subsys(&gtp_net_ops);
 	if (err < 0)
 		goto error_out;
 
-	err = genl_register_family(&gtp_genl_family);
+	err = rtnl_link_register(&gtp_link_ops);
 	if (err < 0)
-		goto unreg_rtnl_link;
+		goto unreg_pernet_subsys;
 
-	err = register_pernet_subsys(&gtp_net_ops);
+	err = genl_register_family(&gtp_genl_family);
 	if (err < 0)
-		goto unreg_genl_family;
+		goto unreg_rtnl_link;
 
 	pr_info("GTP module loaded (pdp ctx size %zd bytes)\n",
 		sizeof(struct pdp_ctx));
 	return 0;
 
-unreg_genl_family:
-	genl_unregister_family(&gtp_genl_family);
 unreg_rtnl_link:
 	rtnl_link_unregister(&gtp_link_ops);
+unreg_pernet_subsys:
+	unregister_pernet_subsys(&gtp_net_ops);
 error_out:
 	pr_err("error loading GTP module loaded\n");
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/hamradio/6pack.c
+++ linux-ein-5.4.0/drivers/net/hamradio/6pack.c
@@ -68,9 +68,9 @@
 #define SIXP_DAMA_OFF		0
 
 /* default level 2 parameters */
-#define SIXP_TXDELAY			(HZ/4)	/* in 1 s */
+#define SIXP_TXDELAY			25	/* 250 ms */
 #define SIXP_PERSIST			50	/* in 256ths */
-#define SIXP_SLOTTIME			(HZ/10)	/* in 1 s */
+#define SIXP_SLOTTIME			10	/* 100 ms */
 #define SIXP_INIT_RESYNC_TIMEOUT	(3*HZ/2) /* in 1 s */
 #define SIXP_RESYNC_TIMEOUT		5*HZ	/* in 1 s */
 
@@ -311,7 +311,6 @@
 {
 	/* Finish setting up the DEVICE info. */
 	dev->netdev_ops		= &sp_netdev_ops;
-	dev->needs_free_netdev	= true;
 	dev->mtu		= SIXP_MTU;
 	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
 	dev->header_ops 	= &ax25_header_ops;
@@ -654,10 +653,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;
 
@@ -674,14 +673,16 @@
 	 */
 	netif_stop_queue(sp->dev);
 
+	unregister_netdev(sp->dev);
+
 	del_timer_sync(&sp->tx_t);
 	del_timer_sync(&sp->resync_t);
 
-	/* Free all 6pack frame buffers. */
+	/* 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. */
@@ -839,6 +840,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-ein-5.4.0.orig/drivers/net/hamradio/baycom_epp.c
+++ linux-ein-5.4.0/drivers/net/hamradio/baycom_epp.c
@@ -758,7 +758,7 @@
  * ===================== network driver interface =========================
  */
 
-static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct baycom_state *bc = netdev_priv(dev);
 
--- linux-ein-5.4.0.orig/drivers/net/hamradio/bpqether.c
+++ linux-ein-5.4.0/drivers/net/hamradio/bpqether.c
@@ -127,7 +127,8 @@
 {
 	struct bpqdev *bpq;
 
-	list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) {
+	list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list,
+				lockdep_rtnl_is_held()) {
 		if (bpq->ethdev == dev)
 			return bpq->axdev;
 	}
@@ -510,7 +511,7 @@
 	if (!net_eq(dev_net(dev), &init_net))
 		return NOTIFY_DONE;
 
-	if (!dev_is_ethdev(dev))
+	if (!dev_is_ethdev(dev) && !bpq_get_ax25_dev(dev))
 		return NOTIFY_DONE;
 
 	switch (event) {
--- linux-ein-5.4.0.orig/drivers/net/hamradio/mkiss.c
+++ linux-ein-5.4.0/drivers/net/hamradio/mkiss.c
@@ -31,6 +31,8 @@
 
 #define AX_MTU		236
 
+/* some arch define END as assembly function ending, just undef it */
+#undef	END
 /* SLIP/KISS protocol characters. */
 #define END             0300		/* indicates end of frame	*/
 #define ESC             0333		/* indicates byte stuffing	*/
@@ -773,10 +775,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;
@@ -793,13 +795,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-ein-5.4.0.orig/drivers/net/hamradio/scc.c
+++ linux-ein-5.4.0/drivers/net/hamradio/scc.c
@@ -300,12 +300,12 @@
 	spin_lock_irqsave(&scc->lock, flags);	
 	if (scc->tx_buff != NULL)
 	{
-		dev_kfree_skb(scc->tx_buff);
+		dev_kfree_skb_irq(scc->tx_buff);
 		scc->tx_buff = NULL;
 	}
 	
 	while (!skb_queue_empty(&scc->tx_queue))
-		dev_kfree_skb(skb_dequeue(&scc->tx_queue));
+		dev_kfree_skb_irq(skb_dequeue(&scc->tx_queue));
 
 	spin_unlock_irqrestore(&scc->lock, flags);
 }
@@ -1667,7 +1667,7 @@
 	if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {
 		struct sk_buff *skb_del;
 		skb_del = skb_dequeue(&scc->tx_queue);
-		dev_kfree_skb(skb_del);
+		dev_kfree_skb_irq(skb_del);
 	}
 	skb_queue_tail(&scc->tx_queue, skb);
 	netif_trans_update(dev);
--- linux-ein-5.4.0.orig/drivers/net/hamradio/yam.c
+++ linux-ein-5.4.0/drivers/net/hamradio/yam.c
@@ -951,9 +951,7 @@
 				 sizeof(struct yamdrv_ioctl_mcs));
 		if (IS_ERR(ym))
 			return PTR_ERR(ym);
-		if (ym->cmd != SIOCYAMSMCS)
-			return -EINVAL;
-		if (ym->bitrate > YAM_MAXBITRATE) {
+		if (ym->cmd != SIOCYAMSMCS || ym->bitrate > YAM_MAXBITRATE) {
 			kfree(ym);
 			return -EINVAL;
 		}
@@ -1133,6 +1131,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-ein-5.4.0.orig/drivers/net/hippi/rrunner.c
+++ linux-ein-5.4.0/drivers/net/hippi/rrunner.c
@@ -1242,7 +1242,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;
 	}
@@ -1346,7 +1346,9 @@
 
 	rrpriv->fw_running = 0;
 
+	spin_unlock_irqrestore(&rrpriv->lock, flags);
 	del_timer_sync(&rrpriv->timer);
+	spin_lock_irqsave(&rrpriv->lock, flags);
 
 	writel(0, &regs->TxPi);
 	writel(0, &regs->IpRxPi);
--- linux-ein-5.4.0.orig/drivers/net/hyperv/Kconfig
+++ linux-ein-5.4.0/drivers/net/hyperv/Kconfig
@@ -3,5 +3,6 @@
 	tristate "Microsoft Hyper-V virtual network driver"
 	depends on HYPERV
 	select UCS2_STRING
+	select NLS
 	help
 	  Select this option to enable the Hyper-V virtual network driver.
--- linux-ein-5.4.0.orig/drivers/net/hyperv/hyperv_net.h
+++ linux-ein-5.4.0/drivers/net/hyperv/hyperv_net.h
@@ -169,7 +169,6 @@
 
 	u8 hw_mac_adr[ETH_ALEN];
 	u8 rss_key[NETVSC_HASH_KEYLEN];
-	u16 rx_table[ITAB_NUM];
 };
 
 
@@ -880,6 +879,7 @@
 	unsigned long rx_no_memory;
 	unsigned long stop_queue;
 	unsigned long wake_queue;
+	unsigned long vlan_error;
 };
 
 struct netvsc_ethtool_pcpu_stats {
@@ -938,6 +938,8 @@
 
 	u32 tx_table[VRSS_SEND_TAB_SIZE];
 
+	u16 rx_table[ITAB_NUM];
+
 	/* Ethtool settings */
 	u8 duplex;
 	u32 speed;
@@ -953,6 +955,9 @@
 	u32 vf_alloc;
 	/* Serial number of the VF to team with */
 	u32 vf_serial;
+
+	/* completion variable to confirm vf association */
+	struct completion vf_add;
 };
 
 /* Per channel data */
--- linux-ein-5.4.0.orig/drivers/net/hyperv/netvsc.c
+++ linux-ein-5.4.0/drivers/net/hyperv/netvsc.c
@@ -99,7 +99,7 @@
 
 	init_waitqueue_head(&net_device->wait_drain);
 	net_device->destroy = false;
-	net_device->tx_disable = false;
+	net_device->tx_disable = true;
 
 	net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
 	net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
@@ -1223,6 +1223,10 @@
 
 	net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
 	net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
+
+	if (net_device_ctx->vf_alloc)
+		complete(&net_device_ctx->vf_add);
+
 	netdev_info(ndev, "VF slot %u %s\n",
 		    net_device_ctx->vf_serial,
 		    net_device_ctx->vf_alloc ? "added" : "removed");
--- linux-ein-5.4.0.orig/drivers/net/hyperv/netvsc_drv.c
+++ linux-ein-5.4.0/drivers/net/hyperv/netvsc_drv.c
@@ -285,9 +285,9 @@
 		else if (flow.basic.n_proto == htons(ETH_P_IPV6))
 			hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd);
 		else
-			hash = 0;
+			return 0;
 
-		skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
+		__skb_set_sw_hash(skb, hash, false);
 	}
 
 	return hash;
@@ -366,7 +366,7 @@
 	}
 	rcu_read_unlock();
 
-	while (unlikely(txq >= ndev->real_num_tx_queues))
+	while (txq >= ndev->real_num_tx_queues)
 		txq -= ndev->real_num_tx_queues;
 
 	return txq;
@@ -501,7 +501,7 @@
 	int rc;
 
 	skb->dev = vf_netdev;
-	skb->queue_mapping = qdisc_skb_cb(skb)->slave_dev_queue_mapping;
+	skb_record_rx_queue(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
 
 	rc = dev_queue_xmit(skb);
 	if (likely(rc == NET_XMIT_SUCCESS || rc == NET_XMIT_CN)) {
@@ -531,12 +531,13 @@
 	u32 hash;
 	struct hv_page_buffer pb[MAX_PAGE_BUFFER_COUNT];
 
-	/* if VF is present and up then redirect packets
-	 * already called with rcu_read_lock_bh
+	/* If VF is present and up then redirect packets to it.
+	 * Skip the VF if it is marked down or has no carrier.
+	 * If netpoll is in uses, then VF can not be used either.
 	 */
 	vf_netdev = rcu_dereference_bh(net_device_ctx->vf_netdev);
 	if (vf_netdev && netif_running(vf_netdev) &&
-	    !netpoll_tx_running(net))
+	    netif_carrier_ok(vf_netdev) && !netpoll_tx_running(net))
 		return netvsc_vf_xmit(net, vf_netdev, skb);
 
 	/* We will atmost need two pages to describe the rndis
@@ -604,6 +605,29 @@
 		*hash_info = hash;
 	}
 
+	/* When using AF_PACKET we need to drop VLAN header from
+	 * the frame and update the SKB to allow the HOST OS
+	 * to transmit the 802.1Q packet
+	 */
+	if (skb->protocol == htons(ETH_P_8021Q)) {
+		u16 vlan_tci;
+
+		skb_reset_mac_header(skb);
+		if (eth_type_vlan(eth_hdr(skb)->h_proto)) {
+			if (unlikely(__skb_vlan_pop(skb, &vlan_tci) != 0)) {
+				++net_device_ctx->eth_stats.vlan_error;
+				goto drop;
+			}
+
+			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
+			/* Update the NDIS header pkt lengths */
+			packet->total_data_buflen -= VLAN_HLEN;
+			packet->total_bytes -= VLAN_HLEN;
+			rndis_msg->msg_len = packet->total_data_buflen;
+			rndis_msg->msg.pkt.data_len = packet->total_data_buflen;
+		}
+	}
+
 	if (skb_vlan_tag_present(skb)) {
 		struct ndis_pkt_8021q_info *vlan;
 
@@ -795,8 +819,7 @@
 	    skb->protocol == htons(ETH_P_IP))
 		netvsc_comp_ipcsum(skb);
 
-	/* Do L4 checksum offload if enabled and present.
-	 */
+	/* 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)
@@ -974,6 +997,7 @@
 	}
 
 	/* In any case device is now ready */
+	nvdev->tx_disable = false;
 	netif_device_attach(ndev);
 
 	/* Note: enable and attach happen when sub-channels setup */
@@ -1344,6 +1368,7 @@
 	{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
 	{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
 	{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
+	{ "vlan_error", offsetof(struct netvsc_ethtool_stats, vlan_error) },
 }, pcpu_stats[] = {
 	{ "cpu%u_rx_packets",
 		offsetof(struct netvsc_ethtool_pcpu_stats, rx_packets) },
@@ -1444,6 +1469,9 @@
 	pcpu_sum = kvmalloc_array(num_possible_cpus(),
 				  sizeof(struct netvsc_ethtool_pcpu_stats),
 				  GFP_KERNEL);
+	if (!pcpu_sum)
+		return;
+
 	netvsc_get_pcpu_stats(dev, pcpu_sum);
 	for_each_present_cpu(cpu) {
 		struct netvsc_ethtool_pcpu_stats *this_sum = &pcpu_sum[cpu];
@@ -1659,7 +1687,7 @@
 	rndis_dev = ndev->extension;
 	if (indir) {
 		for (i = 0; i < ITAB_NUM; i++)
-			indir[i] = rndis_dev->rx_table[i];
+			indir[i] = ndc->rx_table[i];
 	}
 
 	if (key)
@@ -1689,7 +1717,7 @@
 				return -EINVAL;
 
 		for (i = 0; i < ITAB_NUM; i++)
-			rndis_dev->rx_table[i] = indir[i];
+			ndc->rx_table[i] = indir[i];
 	}
 
 	if (!key) {
@@ -2056,9 +2084,6 @@
 		goto upper_link_failed;
 	}
 
-	/* set slave flag before open to prevent IPv6 addrconf */
-	vf_netdev->flags |= IFF_SLAVE;
-
 	schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
 
 	call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
@@ -2129,6 +2154,7 @@
 {
 	struct device *parent = vf_netdev->dev.parent;
 	struct net_device_context *ndev_ctx;
+	struct net_device *ndev;
 	struct pci_dev *pdev;
 	u32 serial;
 
@@ -2155,11 +2181,38 @@
 			return hv_get_drvdata(ndev_ctx->device_ctx);
 	}
 
+	/* Fallback path to check synthetic vf with help of mac addr.
+	 * Because this function can be called before vf_netdev is
+	 * initialized (NETDEV_POST_INIT) when its perm_addr has not been copied
+	 * from dev_addr, also try to match to its dev_addr.
+	 * Note: On Hyper-V and Azure, it's not possible to set a MAC address
+	 * on a VF that matches to the MAC of a unrelated NETVSC device.
+	 */
+	list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
+		ndev = hv_get_drvdata(ndev_ctx->device_ctx);
+		if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr) ||
+		    ether_addr_equal(vf_netdev->dev_addr, ndev->perm_addr))
+			return ndev;
+	}
+
 	netdev_notice(vf_netdev,
 		      "no netdev found for vf serial:%u\n", serial);
 	return NULL;
 }
 
+static int netvsc_prepare_bonding(struct net_device *vf_netdev)
+{
+	struct net_device *ndev;
+
+	ndev = get_netvsc_byslot(vf_netdev);
+	if (!ndev)
+		return NOTIFY_DONE;
+
+	/* set slave flag before open to prevent IPv6 addrconf */
+	vf_netdev->flags |= IFF_SLAVE;
+	return NOTIFY_DONE;
+}
+
 static int netvsc_register_vf(struct net_device *vf_netdev)
 {
 	struct net_device_context *net_device_ctx;
@@ -2228,6 +2281,11 @@
 	if (!netvsc_dev)
 		return NOTIFY_DONE;
 
+	if (vf_is_up && !net_device_ctx->vf_alloc) {
+		netdev_info(ndev, "Waiting for the VF association from host\n");
+		wait_for_completion(&net_device_ctx->vf_add);
+	}
+
 	netvsc_switch_datapath(ndev, vf_is_up);
 	netdev_info(ndev, "Data path switched %s VF: %s\n",
 		    vf_is_up ? "to" : "from", vf_netdev->name);
@@ -2249,6 +2307,7 @@
 
 	netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
 
+	reinit_completion(&net_device_ctx->vf_add);
 	netdev_rx_handler_unregister(vf_netdev);
 	netdev_upper_dev_unlink(vf_netdev, ndev);
 	RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
@@ -2286,6 +2345,7 @@
 
 	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
 
+	init_completion(&net_device_ctx->vf_add);
 	spin_lock_init(&net_device_ctx->lock);
 	INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
 	INIT_DELAYED_WORK(&net_device_ctx->vf_takeover, netvsc_vf_setup);
@@ -2351,6 +2411,8 @@
 	else
 		net->max_mtu = ETH_DATA_LEN;
 
+	nvdev->tx_disable = false;
+
 	ret = register_netdevice(net);
 	if (ret != 0) {
 		pr_err("Unable to register netdev.\n");
@@ -2469,6 +2531,8 @@
 		return NOTIFY_DONE;
 
 	switch (event) {
+	case NETDEV_POST_INIT:
+		return netvsc_prepare_bonding(event_dev);
 	case NETDEV_REGISTER:
 		return netvsc_register_vf(event_dev);
 	case NETDEV_UNREGISTER:
@@ -2502,12 +2566,17 @@
 	}
 	netvsc_ring_bytes = ring_size * PAGE_SIZE;
 
+	register_netdevice_notifier(&netvsc_netdev_notifier);
+
 	ret = vmbus_driver_register(&netvsc_drv);
 	if (ret)
-		return ret;
+		goto err_vmbus_reg;
 
-	register_netdevice_notifier(&netvsc_netdev_notifier);
 	return 0;
+
+err_vmbus_reg:
+	unregister_netdevice_notifier(&netvsc_netdev_notifier);
+	return ret;
 }
 
 MODULE_LICENSE("GPL");
--- linux-ein-5.4.0.orig/drivers/net/hyperv/rndis_filter.c
+++ linux-ein-5.4.0/drivers/net/hyperv/rndis_filter.c
@@ -767,6 +767,7 @@
 				   const u8 *rss_key, u16 flag)
 {
 	struct net_device *ndev = rdev->ndev;
+	struct net_device_context *ndc = netdev_priv(ndev);
 	struct rndis_request *request;
 	struct rndis_set_request *set;
 	struct rndis_set_complete *set_complete;
@@ -806,7 +807,7 @@
 	/* Set indirection table entries */
 	itab = (u32 *)(rssp + 1);
 	for (i = 0; i < ITAB_NUM; i++)
-		itab[i] = rdev->rx_table[i];
+		itab[i] = ndc->rx_table[i];
 
 	/* Set hask key values */
 	keyp = (u8 *)((unsigned long)rssp + rssp->hashkey_offset);
@@ -1165,6 +1166,9 @@
 	wait_event(nvdev->subchan_open,
 		   atomic_read(&nvdev->open_chn) == nvdev->num_chn);
 
+	for (i = 0; i < VRSS_SEND_TAB_SIZE; i++)
+		ndev_ctx->tx_table[i] = i % nvdev->num_chn;
+
 	/* ignore failures from setting rss parameters, still have channels */
 	if (dev_info)
 		rndis_filter_set_rss_param(rdev, dev_info->rss_key);
@@ -1174,9 +1178,6 @@
 	netif_set_real_num_tx_queues(ndev, nvdev->num_chn);
 	netif_set_real_num_rx_queues(ndev, nvdev->num_chn);
 
-	for (i = 0; i < VRSS_SEND_TAB_SIZE; i++)
-		ndev_ctx->tx_table[i] = i % nvdev->num_chn;
-
 	return 0;
 }
 
@@ -1305,6 +1306,7 @@
 				      struct netvsc_device_info *device_info)
 {
 	struct net_device *net = hv_get_drvdata(dev);
+	struct net_device_context *ndc = netdev_priv(net);
 	struct netvsc_device *net_device;
 	struct rndis_device *rndis_device;
 	struct ndis_recv_scale_cap rsscap;
@@ -1391,9 +1393,11 @@
 	/* We will use the given number of channels if available. */
 	net_device->num_chn = min(net_device->max_chn, device_info->num_chn);
 
-	for (i = 0; i < ITAB_NUM; i++)
-		rndis_device->rx_table[i] = ethtool_rxfh_indir_default(
+	if (!netif_is_rxfh_configured(net)) {
+		for (i = 0; i < ITAB_NUM; i++)
+			ndc->rx_table[i] = ethtool_rxfh_indir_default(
 						i, net_device->num_chn);
+	}
 
 	atomic_set(&net_device->open_chn, 1);
 	vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
@@ -1432,8 +1436,6 @@
 	/* Halt and release the rndis device */
 	rndis_filter_halt_device(net_dev, rndis_dev);
 
-	net_dev->extension = NULL;
-
 	netvsc_device_remove(dev);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/adf7242.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/adf7242.c
@@ -882,7 +882,9 @@
 	int ret;
 	u8 lqi, len_u8, *data;
 
-	adf7242_read_reg(lp, 0, &len_u8);
+	ret = adf7242_read_reg(lp, 0, &len_u8);
+	if (ret)
+		return ret;
 
 	len = len_u8;
 
@@ -1160,9 +1162,10 @@
 
 static void adf7242_debugfs_init(struct adf7242_local *lp)
 {
-	char debugfs_dir_name[DNAME_INLINE_LEN + 1] = "adf7242-";
+	char debugfs_dir_name[DNAME_INLINE_LEN + 1];
 
-	strncat(debugfs_dir_name, dev_name(&lp->spi->dev), DNAME_INLINE_LEN);
+	snprintf(debugfs_dir_name, sizeof(debugfs_dir_name),
+		 "adf7242-%s", dev_name(&lp->spi->dev));
 
 	lp->debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
 
@@ -1262,7 +1265,7 @@
 					     WQ_MEM_RECLAIM);
 	if (unlikely(!lp->wqueue)) {
 		ret = -ENOMEM;
-		goto err_hw_init;
+		goto err_alloc_wq;
 	}
 
 	ret = adf7242_hw_init(lp);
@@ -1294,6 +1297,8 @@
 	return ret;
 
 err_hw_init:
+	destroy_workqueue(lp->wqueue);
+err_alloc_wq:
 	mutex_destroy(&lp->bmux);
 	ieee802154_free_hw(lp->hw);
 
@@ -1306,10 +1311,11 @@
 
 	debugfs_remove_recursive(lp->debugfs_root);
 
+	ieee802154_unregister_hw(lp->hw);
+
 	cancel_delayed_work_sync(&lp->work);
 	destroy_workqueue(lp->wqueue);
 
-	ieee802154_unregister_hw(lp->hw);
 	mutex_destroy(&lp->bmux);
 	ieee802154_free_hw(lp->hw);
 
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/at86rf230.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/at86rf230.c
@@ -100,6 +100,7 @@
 	unsigned long cal_timeout;
 	bool is_tx;
 	bool is_tx_from_off;
+	bool was_tx;
 	u8 tx_retry;
 	struct sk_buff *tx_skb;
 	struct at86rf230_state_change tx;
@@ -343,7 +344,11 @@
 	if (ctx->free)
 		kfree(ctx);
 
-	ieee802154_wake_queue(lp->hw);
+	if (lp->was_tx) {
+		lp->was_tx = 0;
+		dev_kfree_skb_any(lp->tx_skb);
+		ieee802154_wake_queue(lp->hw);
+	}
 }
 
 static void
@@ -352,7 +357,11 @@
 	struct at86rf230_state_change *ctx = context;
 	struct at86rf230_local *lp = ctx->lp;
 
-	lp->is_tx = 0;
+	if (lp->is_tx) {
+		lp->was_tx = 1;
+		lp->is_tx = 0;
+	}
+
 	at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
 				     at86rf230_async_error_recover_complete);
 }
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/atusb.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/atusb.c
@@ -93,7 +93,9 @@
 
 	ret = usb_control_msg(usb_dev, pipe, request, requesttype,
 			      value, index, data, size, timeout);
-	if (ret < 0) {
+	if (ret < size) {
+		ret = ret < 0 ? ret : -ENODATA;
+
 		atusb->err = ret;
 		dev_err(&usb_dev->dev,
 			"%s: req 0x%02x val 0x%x idx 0x%x, error %d\n",
@@ -365,6 +367,7 @@
 			return -ENOMEM;
 		}
 		usb_anchor_urb(urb, &atusb->idle_urbs);
+		usb_free_urb(urb);
 		n--;
 	}
 	return 0;
@@ -860,9 +863,9 @@
 	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);
+	/* We cannot call atusb_control_msg() here, since this request may read various length data */
+	ret = usb_control_msg(atusb->usb_dev, usb_rcvctrlpipe(usb_dev, 0), ATUSB_BUILD,
+			      ATUSB_REQ_FROM_DEV, 0, 0, build, ATUSB_BUILD_SIZE, 1000);
 	if (ret >= 0) {
 		build[ret] = 0;
 		dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/ca8210.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/ca8210.c
@@ -926,7 +926,7 @@
 
 	dev_dbg(&spi->dev, "%s called\n", __func__);
 
-	cas_ctl = kmalloc(sizeof(*cas_ctl), GFP_ATOMIC);
+	cas_ctl = kzalloc(sizeof(*cas_ctl), GFP_ATOMIC);
 	if (!cas_ctl)
 		return -ENOMEM;
 
@@ -1770,6 +1770,7 @@
 			status
 		);
 		if (status != MAC_TRANSACTION_OVERFLOW) {
+			dev_kfree_skb_any(priv->tx_skb);
 			ieee802154_wake_queue(priv->hw);
 			return 0;
 		}
@@ -1943,10 +1944,9 @@
 	struct ca8210_priv  *priv
 )
 {
-	int status;
 	struct ieee802154_hdr header = { };
 	struct secspec secspec;
-	unsigned int mac_len;
+	int mac_len, status;
 
 	dev_dbg(&priv->spi->dev, "%s called\n", __func__);
 
@@ -1954,6 +1954,8 @@
 	 * packet
 	 */
 	mac_len = ieee802154_hdr_peek_addrs(skb, &header);
+	if (mac_len < 0)
+		return mac_len;
 
 	secspec.security_level = header.sec.level;
 	secspec.key_id_mode = header.sec.key_id_mode;
@@ -2780,7 +2782,6 @@
 	struct device_node *np = spi->dev.of_node;
 	struct ca8210_priv *priv = spi_get_drvdata(spi);
 	struct ca8210_platform_data *pdata = spi->dev.platform_data;
-	int ret = 0;
 
 	if (!np)
 		return -EFAULT;
@@ -2797,18 +2798,8 @@
 		dev_crit(&spi->dev, "Failed to register external clk\n");
 		return PTR_ERR(priv->clk);
 	}
-	ret = of_clk_add_provider(np, of_clk_src_simple_get, priv->clk);
-	if (ret) {
-		clk_unregister(priv->clk);
-		dev_crit(
-			&spi->dev,
-			"Failed to register external clock as clock provider\n"
-		);
-	} else {
-		dev_info(&spi->dev, "External clock set as clock provider\n");
-	}
 
-	return ret;
+	return of_clk_add_provider(np, of_clk_src_simple_get, priv->clk);
 }
 
 /**
@@ -2820,8 +2811,8 @@
 {
 	struct ca8210_priv *priv = spi_get_drvdata(spi);
 
-	if (!priv->clk)
-		return
+	if (IS_ERR_OR_NULL(priv->clk))
+		return;
 
 	of_clk_del_provider(spi->dev.of_node);
 	clk_unregister(priv->clk);
@@ -2924,6 +2915,7 @@
 	);
 	if (!priv->irq_workqueue) {
 		dev_crit(&priv->spi->dev, "alloc of irq_workqueue failed!\n");
+		destroy_workqueue(priv->mlme_workqueue);
 		return -ENOMEM;
 	}
 
@@ -2974,8 +2966,8 @@
 	ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
 	ca8210_hw->phy->cca_ed_level = -9800;
 	ca8210_hw->phy->symbol_duration = 16;
-	ca8210_hw->phy->lifs_period = 40;
-	ca8210_hw->phy->sifs_period = 12;
+	ca8210_hw->phy->lifs_period = 40 * ca8210_hw->phy->symbol_duration;
+	ca8210_hw->phy->sifs_period = 12 * ca8210_hw->phy->symbol_duration;
 	ca8210_hw->flags =
 		IEEE802154_HW_AFILT |
 		IEEE802154_HW_OMIT_CKSUM |
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/cc2520.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/cc2520.c
@@ -507,6 +507,7 @@
 		goto err_tx;
 
 	if (status & CC2520_STATUS_TX_UNDERFLOW) {
+		rc = -EINVAL;
 		dev_err(&priv->spi->dev, "cc2520 tx underflow exception\n");
 		goto err_tx;
 	}
@@ -972,7 +973,7 @@
 
 		if (timeout-- <= 0) {
 			dev_err(&priv->spi->dev, "oscillator start failed!\n");
-			return ret;
+			return -ETIMEDOUT;
 		}
 		udelay(1);
 	} while (!(status & CC2520_STATUS_XOSC32M_STABLE));
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/mac802154_hwsim.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/mac802154_hwsim.c
@@ -418,7 +418,7 @@
 	struct hwsim_edge *e;
 	u32 v0, v1;
 
-	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
+	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
 	    !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
 		return -EINVAL;
 
@@ -480,7 +480,7 @@
 	struct hwsim_edge *e;
 	u32 v0, v1;
 
-	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
+	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
 	    !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
 		return -EINVAL;
 
@@ -522,20 +522,20 @@
 static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
 {
 	struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
-	struct hwsim_edge_info *einfo;
+	struct hwsim_edge_info *einfo, *einfo_old;
 	struct hwsim_phy *phy_v0;
 	struct hwsim_edge *e;
 	u32 v0, v1;
 	u8 lqi;
 
-	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
+	if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
 	    !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
 		return -EINVAL;
 
 	if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
 		return -EINVAL;
 
-	if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] &&
+	if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] ||
 	    !edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI])
 		return -EINVAL;
 
@@ -560,8 +560,10 @@
 	list_for_each_entry_rcu(e, &phy_v0->edges, list) {
 		if (e->endpoint->idx == v1) {
 			einfo->lqi = lqi;
-			rcu_assign_pointer(e->info, einfo);
+			einfo_old = rcu_replace_pointer(e->info, einfo,
+							lockdep_is_held(&hwsim_phys_lock));
 			rcu_read_unlock();
+			kfree_rcu(einfo_old, rcu);
 			mutex_unlock(&hwsim_phys_lock);
 			return 0;
 		}
@@ -715,6 +717,8 @@
 
 	return 0;
 
+sub_fail:
+	hwsim_edge_unsubscribe_me(phy);
 me_fail:
 	rcu_read_lock();
 	list_for_each_entry_rcu(e, &phy->edges, list) {
@@ -722,8 +726,6 @@
 		hwsim_free_edge(e);
 	}
 	rcu_read_unlock();
-sub_fail:
-	hwsim_edge_unsubscribe_me(phy);
 	return -ENOMEM;
 }
 
@@ -786,6 +788,7 @@
 		goto err_pib;
 	}
 
+	pib->channel = 13;
 	rcu_assign_pointer(phy->pib, pib);
 	phy->idx = idx;
 	INIT_LIST_HEAD(&phy->edges);
@@ -824,12 +827,17 @@
 static void hwsim_del(struct hwsim_phy *phy)
 {
 	struct hwsim_pib *pib;
+	struct hwsim_edge *e;
 
 	hwsim_edge_unsubscribe_me(phy);
 
 	list_del(&phy->list);
 
 	rcu_read_lock();
+	list_for_each_entry_rcu(e, &phy->edges, list) {
+		list_del_rcu(&e->list);
+		hwsim_free_edge(e);
+	}
 	pib = rcu_dereference(phy->pib);
 	rcu_read_unlock();
 
--- linux-ein-5.4.0.orig/drivers/net/ieee802154/mcr20a.c
+++ linux-ein-5.4.0/drivers/net/ieee802154/mcr20a.c
@@ -976,8 +976,8 @@
 	dev_dbg(printdev(lp), "%s\n", __func__);
 
 	phy->symbol_duration = 16;
-	phy->lifs_period = 40;
-	phy->sifs_period = 12;
+	phy->lifs_period = 40 * phy->symbol_duration;
+	phy->sifs_period = 12 * phy->symbol_duration;
 
 	hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
 			IEEE802154_HW_AFILT |
--- linux-ein-5.4.0.orig/drivers/net/ifb.c
+++ linux-ein-5.4.0/drivers/net/ifb.c
@@ -75,7 +75,7 @@
 	}
 
 	while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
-		skb->tc_redirected = 0;
+		skb->redirected = 0;
 		skb->tc_skip_classify = 1;
 
 		u64_stats_update_begin(&txp->tsync);
@@ -96,7 +96,7 @@
 		rcu_read_unlock();
 		skb->skb_iif = txp->dev->ifindex;
 
-		if (!skb->tc_from_ingress) {
+		if (!skb->from_ingress) {
 			dev_queue_xmit(skb);
 		} else {
 			skb_pull_rcsum(skb, skb->mac_len);
@@ -243,7 +243,7 @@
 	txp->rx_bytes += skb->len;
 	u64_stats_update_end(&txp->rsync);
 
-	if (!skb->tc_redirected || !skb->skb_iif) {
+	if (!skb->redirected || !skb->skb_iif) {
 		dev_kfree_skb(skb);
 		dev->stats.rx_dropped++;
 		return NETDEV_TX_OK;
--- linux-ein-5.4.0.orig/drivers/net/ipvlan/ipvlan_core.c
+++ linux-ein-5.4.0/drivers/net/ipvlan/ipvlan_core.c
@@ -293,6 +293,7 @@
 		}
 		if (dev)
 			dev_put(dev);
+		cond_resched();
 	}
 }
 
@@ -411,7 +412,7 @@
 	return addr;
 }
 
-static int ipvlan_process_v4_outbound(struct sk_buff *skb)
+static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb)
 {
 	const struct iphdr *ip4h = ip_hdr(skb);
 	struct net_device *dev = skb->dev;
@@ -436,27 +437,28 @@
 		goto err;
 	}
 	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++;
+		DEV_STATS_INC(dev, tx_errors);
 	else
 		ret = NET_XMIT_SUCCESS;
 	goto out;
 err:
-	dev->stats.tx_errors++;
+	DEV_STATS_INC(dev, tx_errors);
 	kfree_skb(skb);
 out:
 	return ret;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
-static int ipvlan_process_v6_outbound(struct sk_buff *skb)
+
+static noinline_for_stack int
+ipvlan_route_v6_outbound(struct net_device *dev, struct sk_buff *skb)
 {
 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-	struct net_device *dev = skb->dev;
-	struct net *net = dev_net(dev);
-	struct dst_entry *dst;
-	int err, ret = NET_XMIT_DROP;
 	struct flowi6 fl6 = {
 		.flowi6_oif = dev->ifindex,
 		.daddr = ip6h->daddr,
@@ -466,24 +468,38 @@
 		.flowi6_mark = skb->mark,
 		.flowi6_proto = ip6h->nexthdr,
 	};
+	struct dst_entry *dst;
+	int err;
 
-	dst = ip6_route_output(net, NULL, &fl6);
-	if (dst->error) {
-		ret = dst->error;
+	dst = ip6_route_output(dev_net(dev), NULL, &fl6);
+	err = dst->error;
+	if (err) {
 		dst_release(dst);
-		goto err;
+		return err;
 	}
 	skb_dst_set(skb, dst);
-	err = ip6_local_out(net, skb->sk, skb);
+	return 0;
+}
+
+static int ipvlan_process_v6_outbound(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	int err, ret = NET_XMIT_DROP;
+
+	err = ipvlan_route_v6_outbound(dev, skb);
+	if (unlikely(err)) {
+		DEV_STATS_INC(dev, tx_errors);
+		kfree_skb(skb);
+		return err;
+	}
+
+	memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+
+	err = ip6_local_out(dev_net(dev), skb->sk, skb);
 	if (unlikely(net_xmit_eval(err)))
-		dev->stats.tx_errors++;
+		DEV_STATS_INC(dev, tx_errors);
 	else
 		ret = NET_XMIT_SUCCESS;
-	goto out;
-err:
-	dev->stats.tx_errors++;
-	kfree_skb(skb);
-out:
 	return ret;
 }
 #else
@@ -495,22 +511,25 @@
 
 static int ipvlan_process_outbound(struct sk_buff *skb)
 {
-	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_debug_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 */
+		struct ethhdr *ethh = eth_hdr(skb);
+
+		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);
@@ -576,7 +595,8 @@
 				consume_skb(skb);
 				return NET_XMIT_DROP;
 			}
-			return ipvlan_rcv_frame(addr, &skb, true);
+			ipvlan_rcv_frame(addr, &skb, true);
+			return NET_XMIT_SUCCESS;
 		}
 	}
 out:
@@ -587,7 +607,7 @@
 static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
 {
 	const struct ipvl_dev *ipvlan = netdev_priv(dev);
-	struct ethhdr *eth = eth_hdr(skb);
+	struct ethhdr *eth = skb_eth_hdr(skb);
 	struct ipvl_addr *addr;
 	void *lyr3h;
 	int addr_type;
@@ -602,7 +622,8 @@
 					consume_skb(skb);
 					return NET_XMIT_DROP;
 				}
-				return ipvlan_rcv_frame(addr, &skb, true);
+				ipvlan_rcv_frame(addr, &skb, true);
+				return NET_XMIT_SUCCESS;
 			}
 		}
 		skb = skb_share_check(skb, GFP_ATOMIC);
@@ -614,9 +635,11 @@
 		 * the skb for the main-dev. At the RX side we just return
 		 * RX_PASS for it to be processed further on the stack.
 		 */
-		return dev_forward_skb(ipvlan->phy_dev, skb);
+		dev_forward_skb(ipvlan->phy_dev, skb);
+		return NET_XMIT_SUCCESS;
 
 	} else if (is_multicast_ether_addr(eth->h_dest)) {
+		skb_reset_mac_header(skb);
 		ipvlan_skb_crossing_ns(skb, NULL);
 		ipvlan_multicast_enqueue(ipvlan->port, skb, true);
 		return NET_XMIT_SUCCESS;
--- linux-ein-5.4.0.orig/drivers/net/ipvlan/ipvlan_l3s.c
+++ linux-ein-5.4.0/drivers/net/ipvlan/ipvlan_l3s.c
@@ -101,6 +101,11 @@
 		goto out;
 
 	skb->dev = addr->master->dev;
+	skb->skb_iif = skb->dev->ifindex;
+#if IS_ENABLED(CONFIG_IPV6)
+	if (addr->atype == IPVL_IPV6)
+		IP6CB(skb)->iif = skb->dev->ifindex;
+#endif
 	len = skb->len + ETH_HLEN;
 	ipvlan_count_rx(addr->master, len, true, false);
 out:
--- linux-ein-5.4.0.orig/drivers/net/ipvlan/ipvlan_main.c
+++ linux-ein-5.4.0/drivers/net/ipvlan/ipvlan_main.c
@@ -106,12 +106,21 @@
 	kfree(port);
 }
 
+#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_CSUM_MASK | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+	(NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
 	 NETIF_F_GSO | NETIF_F_TSO | 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))
 
@@ -125,7 +134,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 | NETIF_F_VLAN_CHALLENGED;
+	dev->features |= IPVLAN_ALWAYS_ON;
+	dev->vlan_features = phy_dev->vlan_features & IPVLAN_FEATURES;
+	dev->vlan_features |= IPVLAN_ALWAYS_ON_OFLOADS;
 	dev->hw_enc_features |= dev->features;
 	dev->gso_max_size = phy_dev->gso_max_size;
 	dev->gso_max_segs = phy_dev->gso_max_segs;
@@ -164,7 +175,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 ||
@@ -178,7 +188,7 @@
 		ipvlan_ht_addr_add(ipvlan, addr);
 	rcu_read_unlock();
 
-	return dev_uc_add(phy_dev, phy_dev->dev_addr);
+	return 0;
 }
 
 static int ipvlan_stop(struct net_device *dev)
@@ -190,8 +200,6 @@
 	dev_uc_unsync(phy_dev, dev);
 	dev_mc_unsync(phy_dev, dev);
 
-	dev_uc_del(phy_dev, phy_dev->dev_addr);
-
 	rcu_read_lock();
 	list_for_each_entry_rcu(addr, &ipvlan->addrs, anode)
 		ipvlan_ht_addr_del(addr);
@@ -228,7 +236,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)
@@ -305,6 +320,7 @@
 		s->rx_dropped = rx_errs;
 		s->tx_dropped = tx_drps;
 	}
+	s->tx_errors = DEV_STATS_READ(dev, tx_errors);
 }
 
 static int ipvlan_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
@@ -720,7 +736,8 @@
 
 		write_pnet(&port->pnet, newnet);
 
-		ipvlan_migrate_l3s_hook(oldnet, newnet);
+		if (port->mode == IPVLAN_MODE_L3S)
+			ipvlan_migrate_l3s_hook(oldnet, newnet);
 		break;
 	}
 	case NETDEV_UNREGISTER:
@@ -735,10 +752,9 @@
 
 	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;
 			ipvlan->dev->gso_max_segs = dev->gso_max_segs;
-			netdev_features_change(ipvlan->dev);
+			netdev_update_features(ipvlan->dev);
 		}
 		break;
 
--- linux-ein-5.4.0.orig/drivers/net/ipvlan/ipvtap.c
+++ linux-ein-5.4.0/drivers/net/ipvlan/ipvtap.c
@@ -194,7 +194,7 @@
 	.notifier_call	= ipvtap_device_event,
 };
 
-static int ipvtap_init(void)
+static int __init ipvtap_init(void)
 {
 	int err;
 
@@ -228,7 +228,7 @@
 }
 module_init(ipvtap_init);
 
-static void ipvtap_exit(void)
+static void __exit ipvtap_exit(void)
 {
 	rtnl_link_unregister(&ipvtap_link_ops);
 	unregister_netdevice_notifier(&ipvtap_notifier_block);
--- linux-ein-5.4.0.orig/drivers/net/loopback.c
+++ linux-ein-5.4.0/drivers/net/loopback.c
@@ -206,7 +206,7 @@
 	int err;
 
 	err = -ENOMEM;
-	dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);
+	dev = alloc_netdev(0, "lo", NET_NAME_PREDICTABLE, loopback_setup);
 	if (!dev)
 		goto out;
 
--- linux-ein-5.4.0.orig/drivers/net/macsec.c
+++ linux-ein-5.4.0/drivers/net/macsec.c
@@ -16,6 +16,7 @@
 #include <net/genetlink.h>
 #include <net/sock.h>
 #include <net/gro_cells.h>
+#include <linux/if_arp.h>
 
 #include <uapi/linux/if_macsec.h>
 
@@ -316,6 +317,19 @@
 	return sa;
 }
 
+static struct macsec_rx_sa *macsec_active_rxsa_get(struct macsec_rx_sc *rx_sc)
+{
+	struct macsec_rx_sa *sa = NULL;
+	int an;
+
+	for (an = 0; an < MACSEC_NUM_AN; an++)	{
+		sa = macsec_rxsa_get(rx_sc->sa[an]);
+		if (sa)
+			break;
+	}
+	return sa;
+}
+
 static void free_rx_sc_rcu(struct rcu_head *head)
 {
 	struct macsec_rx_sc *rx_sc = container_of(head, struct macsec_rx_sc, rcu_head);
@@ -560,18 +574,28 @@
 	skb->protocol = eth_hdr(skb)->h_proto;
 }
 
+static unsigned int macsec_msdu_len(struct sk_buff *skb)
+{
+	struct macsec_dev *macsec = macsec_priv(skb->dev);
+	struct macsec_secy *secy = &macsec->secy;
+	bool sci_present = macsec_skb_cb(skb)->has_sci;
+
+	return skb->len - macsec_hdr_len(sci_present) - secy->icv_len;
+}
+
 static void macsec_count_tx(struct sk_buff *skb, struct macsec_tx_sc *tx_sc,
 			    struct macsec_tx_sa *tx_sa)
 {
+	unsigned int msdu_len = macsec_msdu_len(skb);
 	struct pcpu_tx_sc_stats *txsc_stats = this_cpu_ptr(tx_sc->stats);
 
 	u64_stats_update_begin(&txsc_stats->syncp);
 	if (tx_sc->encrypt) {
-		txsc_stats->stats.OutOctetsEncrypted += skb->len;
+		txsc_stats->stats.OutOctetsEncrypted += msdu_len;
 		txsc_stats->stats.OutPktsEncrypted++;
 		this_cpu_inc(tx_sa->stats->OutPktsEncrypted);
 	} else {
-		txsc_stats->stats.OutOctetsProtected += skb->len;
+		txsc_stats->stats.OutOctetsProtected += msdu_len;
 		txsc_stats->stats.OutPktsProtected++;
 		this_cpu_inc(tx_sa->stats->OutPktsProtected);
 	}
@@ -601,9 +625,10 @@
 	aead_request_free(macsec_skb_cb(skb)->req);
 
 	rcu_read_lock_bh();
-	macsec_encrypt_finish(skb, dev);
 	macsec_count_tx(skb, &macsec->secy.tx_sc, macsec_skb_cb(skb)->tx_sa);
-	len = skb->len;
+	/* packet is encrypted/protected so tx_bytes must be calculated */
+	len = macsec_msdu_len(skb) + 2 * ETH_ALEN;
+	macsec_encrypt_finish(skb, dev);
 	ret = dev_queue_xmit(skb);
 	count_tx(dev, ret, len);
 	rcu_read_unlock_bh();
@@ -759,6 +784,7 @@
 
 	macsec_skb_cb(skb)->req = req;
 	macsec_skb_cb(skb)->tx_sa = tx_sa;
+	macsec_skb_cb(skb)->has_sci = sci_present;
 	aead_request_set_callback(req, 0, macsec_encrypt_done, skb);
 
 	dev_hold(skb->dev);
@@ -799,15 +825,17 @@
 		u64_stats_update_begin(&rxsc_stats->syncp);
 		rxsc_stats->stats.InPktsLate++;
 		u64_stats_update_end(&rxsc_stats->syncp);
+		DEV_STATS_INC(secy->netdev, rx_dropped);
 		return false;
 	}
 
 	if (secy->validate_frames != MACSEC_VALIDATE_DISABLED) {
+		unsigned int msdu_len = macsec_msdu_len(skb);
 		u64_stats_update_begin(&rxsc_stats->syncp);
 		if (hdr->tci_an & MACSEC_TCI_E)
-			rxsc_stats->stats.InOctetsDecrypted += skb->len;
+			rxsc_stats->stats.InOctetsDecrypted += msdu_len;
 		else
-			rxsc_stats->stats.InOctetsValidated += skb->len;
+			rxsc_stats->stats.InOctetsValidated += msdu_len;
 		u64_stats_update_end(&rxsc_stats->syncp);
 	}
 
@@ -820,6 +848,8 @@
 			u64_stats_update_begin(&rxsc_stats->syncp);
 			rxsc_stats->stats.InPktsNotValid++;
 			u64_stats_update_end(&rxsc_stats->syncp);
+			this_cpu_inc(rx_sa->stats->InPktsNotValid);
+			DEV_STATS_INC(secy->netdev, rx_errors);
 			return false;
 		}
 
@@ -905,9 +935,9 @@
 
 	macsec_finalize_skb(skb, macsec->secy.icv_len,
 			    macsec_extra_len(macsec_skb_cb(skb)->has_sci));
+	len = skb->len;
 	macsec_reset_skb(skb, macsec->secy.netdev);
 
-	len = skb->len;
 	if (gro_cells_receive(&macsec->gro_cells, skb) == NET_RX_SUCCESS)
 		count_rx(dev, len);
 
@@ -1049,6 +1079,7 @@
 			u64_stats_update_begin(&secy_stats->syncp);
 			secy_stats->stats.InPktsNoTag++;
 			u64_stats_update_end(&secy_stats->syncp);
+			DEV_STATS_INC(macsec->secy.netdev, rx_dropped);
 			continue;
 		}
 
@@ -1079,6 +1110,7 @@
 	struct macsec_rx_sa *rx_sa;
 	struct macsec_rxh_data *rxd;
 	struct macsec_dev *macsec;
+	unsigned int len;
 	sci_t sci;
 	u32 pn;
 	bool cbit;
@@ -1159,6 +1191,7 @@
 		u64_stats_update_begin(&secy_stats->syncp);
 		secy_stats->stats.InPktsBadTag++;
 		u64_stats_update_end(&secy_stats->syncp);
+		DEV_STATS_INC(secy->netdev, rx_errors);
 		goto drop_nosa;
 	}
 
@@ -1169,11 +1202,15 @@
 		/* If validateFrames is Strict or the C bit in the
 		 * SecTAG is set, discard
 		 */
+		struct macsec_rx_sa *active_rx_sa = macsec_active_rxsa_get(rx_sc);
 		if (hdr->tci_an & MACSEC_TCI_C ||
 		    secy->validate_frames == MACSEC_VALIDATE_STRICT) {
 			u64_stats_update_begin(&rxsc_stats->syncp);
 			rxsc_stats->stats.InPktsNotUsingSA++;
 			u64_stats_update_end(&rxsc_stats->syncp);
+			DEV_STATS_INC(secy->netdev, rx_errors);
+			if (active_rx_sa)
+				this_cpu_inc(active_rx_sa->stats->InPktsNotUsingSA);
 			goto drop_nosa;
 		}
 
@@ -1183,6 +1220,8 @@
 		u64_stats_update_begin(&rxsc_stats->syncp);
 		rxsc_stats->stats.InPktsUnusedSA++;
 		u64_stats_update_end(&rxsc_stats->syncp);
+		if (active_rx_sa)
+			this_cpu_inc(active_rx_sa->stats->InPktsUnusedSA);
 		goto deliver;
 	}
 
@@ -1200,6 +1239,7 @@
 			u64_stats_update_begin(&rxsc_stats->syncp);
 			rxsc_stats->stats.InPktsLate++;
 			u64_stats_update_end(&rxsc_stats->syncp);
+			DEV_STATS_INC(macsec->secy.netdev, rx_dropped);
 			goto drop;
 		}
 	}
@@ -1228,6 +1268,7 @@
 deliver:
 	macsec_finalize_skb(skb, secy->icv_len,
 			    macsec_extra_len(macsec_skb_cb(skb)->has_sci));
+	len = skb->len;
 	macsec_reset_skb(skb, secy->netdev);
 
 	if (rx_sa)
@@ -1237,9 +1278,9 @@
 	skb_orphan(skb);
 	ret = gro_cells_receive(&macsec->gro_cells, skb);
 	if (ret == NET_RX_SUCCESS)
-		count_rx(dev, skb->len);
+		count_rx(dev, len);
 	else
-		macsec->secy.netdev->stats.rx_dropped++;
+		DEV_STATS_INC(macsec->secy.netdev, rx_dropped);
 
 	rcu_read_unlock();
 
@@ -1276,6 +1317,7 @@
 			u64_stats_update_begin(&secy_stats->syncp);
 			secy_stats->stats.InPktsNoSCI++;
 			u64_stats_update_end(&secy_stats->syncp);
+			DEV_STATS_INC(macsec->secy.netdev, rx_errors);
 			continue;
 		}
 
@@ -1294,7 +1336,7 @@
 			secy_stats->stats.InPktsUnknownSCI++;
 			u64_stats_update_end(&secy_stats->syncp);
 		} else {
-			macsec->secy.netdev->stats.rx_dropped++;
+			DEV_STATS_INC(macsec->secy.netdev, rx_dropped);
 		}
 	}
 
@@ -2727,21 +2769,21 @@
 
 	if (!secy->operational) {
 		kfree_skb(skb);
-		dev->stats.tx_dropped++;
+		DEV_STATS_INC(dev, tx_dropped);
 		return NETDEV_TX_OK;
 	}
 
+	len = skb->len;
 	skb = macsec_encrypt(skb, dev);
 	if (IS_ERR(skb)) {
 		if (PTR_ERR(skb) != -EINPROGRESS)
-			dev->stats.tx_dropped++;
+			DEV_STATS_INC(dev, tx_dropped);
 		return NETDEV_TX_OK;
 	}
 
 	macsec_count_tx(skb, &macsec->secy.tx_sc, macsec_skb_cb(skb)->tx_sa);
 
 	macsec_encrypt_finish(skb, dev);
-	len = skb->len;
 	ret = dev_queue_xmit(skb);
 	count_tx(dev, ret, len);
 	return ret;
@@ -2882,6 +2924,11 @@
 	dev_uc_sync(real_dev, dev);
 }
 
+static sci_t dev_to_sci(struct net_device *dev, __be16 port)
+{
+	return make_sci(dev->dev_addr, port);
+}
+
 static int macsec_set_mac_address(struct net_device *dev, void *p)
 {
 	struct macsec_dev *macsec = macsec_priv(dev);
@@ -2903,6 +2950,7 @@
 
 out:
 	ether_addr_copy(dev->dev_addr, addr->sa_data);
+	macsec->secy.sci = dev_to_sci(dev, MACSEC_PORT_ES);
 	return 0;
 }
 
@@ -2947,8 +2995,9 @@
 		s->tx_bytes   += tmp.tx_bytes;
 	}
 
-	s->rx_dropped = dev->stats.rx_dropped;
-	s->tx_dropped = dev->stats.tx_dropped;
+	s->rx_dropped = DEV_STATS_READ(dev, rx_dropped);
+	s->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
+	s->rx_errors = DEV_STATS_READ(dev, rx_errors);
 }
 
 static int macsec_get_iflink(const struct net_device *dev)
@@ -2977,6 +3026,7 @@
 
 static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = {
 	[IFLA_MACSEC_SCI] = { .type = NLA_U64 },
+	[IFLA_MACSEC_PORT] = { .type = NLA_U16 },
 	[IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
 	[IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
 	[IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
@@ -3176,11 +3226,6 @@
 	return false;
 }
 
-static sci_t dev_to_sci(struct net_device *dev, __be16 port)
-{
-	return make_sci(dev->dev_addr, port);
-}
-
 static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
 {
 	struct macsec_dev *macsec = macsec_priv(dev);
@@ -3223,25 +3268,40 @@
 			  struct netlink_ext_ack *extack)
 {
 	struct macsec_dev *macsec = macsec_priv(dev);
+	rx_handler_func_t *rx_handler;
+	u8 icv_len = DEFAULT_ICV_LEN;
 	struct net_device *real_dev;
-	int err;
+	int err, mtu;
 	sci_t sci;
-	u8 icv_len = DEFAULT_ICV_LEN;
-	rx_handler_func_t *rx_handler;
 
 	if (!tb[IFLA_LINK])
 		return -EINVAL;
 	real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
 	if (!real_dev)
 		return -ENODEV;
+	if (real_dev->type != ARPHRD_ETHER)
+		return -EINVAL;
 
 	dev->priv_flags |= IFF_MACSEC;
 
 	macsec->real_dev = real_dev;
 
+	/* send_sci must be set to true when transmit sci explicitly is set */
+	if ((data && data[IFLA_MACSEC_SCI]) &&
+	    (data && data[IFLA_MACSEC_INC_SCI])) {
+		u8 send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
+
+		if (!send_sci)
+			return -EINVAL;
+	}
+
 	if (data && data[IFLA_MACSEC_ICV_LEN])
 		icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
-	dev->mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
+	mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
+	if (mtu < 0)
+		dev->mtu = 0;
+	else
+		dev->mtu = mtu;
 
 	rx_handler = rtnl_dereference(real_dev->rx_handler);
 	if (rx_handler && rx_handler != macsec_handle_frame)
--- linux-ein-5.4.0.orig/drivers/net/macvlan.c
+++ linux-ein-5.4.0/drivers/net/macvlan.c
@@ -138,7 +138,7 @@
 	u32 idx = macvlan_eth_hash(addr);
 	struct hlist_head *h = &vlan->port->vlan_source_hash[idx];
 
-	hlist_for_each_entry_rcu(entry, h, hlist) {
+	hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
 		if (ether_addr_equal_64bits(entry->addr, addr) &&
 		    entry->vlan == vlan)
 			return entry;
@@ -334,6 +334,8 @@
 		if (src)
 			dev_put(src->dev);
 		consume_skb(skb);
+
+		cond_resched();
 	}
 }
 
@@ -359,10 +361,11 @@
 	}
 	spin_unlock(&port->bc_queue.lock);
 
+	schedule_work(&port->bc_work);
+
 	if (err)
 		goto free_nskb;
 
-	schedule_work(&port->bc_work);
 	return;
 
 free_nskb:
@@ -444,6 +447,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)) {
 		unsigned int hash;
@@ -512,10 +519,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;
 		}
@@ -757,7 +765,7 @@
 	if (dev->flags & IFF_UP) {
 		if (change & IFF_ALLMULTI)
 			dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
-		if (change & IFF_PROMISC)
+		if (!macvlan_passthru(vlan->port) && change & IFF_PROMISC)
 			dev_set_promiscuity(lowerdev,
 					    dev->flags & IFF_PROMISC ? 1 : -1);
 
@@ -1158,7 +1166,7 @@
 {
 	ether_setup(dev);
 
-	dev->min_mtu		= 0;
+	/* ether_setup() has set dev->min_mtu to ETH_MIN_MTU. */
 	dev->max_mtu		= ETH_MAX_MTU;
 	dev->priv_flags	       &= ~IFF_TX_SKB_SHARING;
 	netif_keep_dst(dev);
@@ -1251,6 +1259,9 @@
 static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],
 			    struct netlink_ext_ack *extack)
 {
+	struct nlattr *nla, *head;
+	int rem, len;
+
 	if (tb[IFLA_ADDRESS]) {
 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
 			return -EINVAL;
@@ -1298,6 +1309,20 @@
 			return -EADDRNOTAVAIL;
 	}
 
+	if (data[IFLA_MACVLAN_MACADDR_DATA]) {
+		head = nla_data(data[IFLA_MACVLAN_MACADDR_DATA]);
+		len = nla_len(data[IFLA_MACVLAN_MACADDR_DATA]);
+
+		nla_for_each_attr(nla, head, len, rem) {
+			if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
+			    nla_len(nla) != ETH_ALEN)
+				return -EINVAL;
+
+			if (!is_valid_ether_addr(nla_data(nla)))
+				return -EADDRNOTAVAIL;
+		}
+	}
+
 	if (data[IFLA_MACVLAN_MACADDR_COUNT])
 		return -EINVAL;
 
@@ -1354,10 +1379,6 @@
 		len = nla_len(data[IFLA_MACVLAN_MACADDR_DATA]);
 
 		nla_for_each_attr(nla, head, len, rem) {
-			if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
-			    nla_len(nla) != ETH_ALEN)
-				continue;
-
 			addr = nla_data(nla);
 			ret = macvlan_hash_add_source(vlan, addr);
 			if (ret)
@@ -1478,8 +1499,10 @@
 	/* the macvlan port may be freed by macvlan_uninit when fail to register.
 	 * so we destroy the macvlan port only when it's valid.
 	 */
-	if (create && macvlan_port_get_rtnl(lowerdev))
+	if (create && macvlan_port_get_rtnl(lowerdev)) {
+		macvlan_flush_sources(port, vlan);
 		macvlan_port_destroy(port->dev);
+	}
 	return err;
 }
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);
@@ -1581,7 +1604,7 @@
 	struct hlist_head *h = &vlan->port->vlan_source_hash[i];
 	struct macvlan_source_entry *entry;
 
-	hlist_for_each_entry_rcu(entry, h, hlist) {
+	hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
 		if (entry->vlan != vlan)
 			continue;
 		if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr))
@@ -1700,7 +1723,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-ein-5.4.0.orig/drivers/net/macvtap.c
+++ linux-ein-5.4.0/drivers/net/macvtap.c
@@ -133,11 +133,17 @@
 	dev->tx_queue_len = TUN_READQ_SIZE;
 }
 
+static struct net *macvtap_link_net(const struct net_device *dev)
+{
+	return dev_net(macvlan_dev_real_dev(dev));
+}
+
 static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
 	.kind		= "macvtap",
 	.setup		= macvtap_setup,
 	.newlink	= macvtap_newlink,
 	.dellink	= macvtap_dellink,
+	.get_link_net	= macvtap_link_net,
 	.priv_size      = sizeof(struct macvtap_dev),
 };
 
--- linux-ein-5.4.0.orig/drivers/net/net_failover.c
+++ linux-ein-5.4.0/drivers/net/net_failover.c
@@ -61,7 +61,8 @@
 	return 0;
 
 err_standby_open:
-	dev_close(primary_dev);
+	if (primary_dev)
+		dev_close(primary_dev);
 err_primary_open:
 	netif_tx_disable(dev);
 	return err;
@@ -129,14 +130,10 @@
 			txq = ops->ndo_select_queue(primary_dev, skb, sb_dev);
 		else
 			txq = netdev_pick_tx(primary_dev, skb, NULL);
-
-		qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
-
-		return txq;
+	} else {
+		txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
 	}
 
-	txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
-
 	/* Save the original txq to restore before passing to the driver */
 	qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
 
--- linux-ein-5.4.0.orig/drivers/net/netdevsim/bpf.c
+++ linux-ein-5.4.0/drivers/net/netdevsim/bpf.c
@@ -347,10 +347,12 @@
 {
 	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
 
-	nmap->entry[idx].key = kmalloc(offmap->map.key_size, GFP_USER);
+	nmap->entry[idx].key = kmalloc(offmap->map.key_size,
+				       GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
 	if (!nmap->entry[idx].key)
 		return -ENOMEM;
-	nmap->entry[idx].value = kmalloc(offmap->map.value_size, GFP_USER);
+	nmap->entry[idx].value = kmalloc(offmap->map.value_size,
+					 GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
 	if (!nmap->entry[idx].value) {
 		kfree(nmap->entry[idx].key);
 		nmap->entry[idx].key = NULL;
@@ -492,7 +494,7 @@
 	if (offmap->map.map_flags)
 		return -EINVAL;
 
-	nmap = kzalloc(sizeof(*nmap), GFP_USER);
+	nmap = kzalloc(sizeof(*nmap), GFP_KERNEL_ACCOUNT);
 	if (!nmap)
 		return -ENOMEM;
 
@@ -510,6 +512,7 @@
 				goto err_free;
 			key = nmap->entry[i].key;
 			*key = i;
+			memset(nmap->entry[i].value, 0, offmap->map.value_size);
 		}
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/netdevsim/dev.c
+++ linux-ein-5.4.0/drivers/net/netdevsim/dev.c
@@ -73,7 +73,7 @@
 
 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
 {
-	char dev_ddir_name[16];
+	char dev_ddir_name[sizeof(DRV_NAME) + 10];
 
 	sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
 	nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
--- linux-ein-5.4.0.orig/drivers/net/netdevsim/netdev.c
+++ linux-ein-5.4.0/drivers/net/netdevsim/netdev.c
@@ -292,6 +292,7 @@
 
 	ns = netdev_priv(dev);
 	ns->netdev = dev;
+	u64_stats_init(&ns->syncp);
 	ns->nsim_dev = nsim_dev;
 	ns->nsim_dev_port = nsim_dev_port;
 	ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
@@ -301,7 +302,7 @@
 	rtnl_lock();
 	err = nsim_bpf_init(ns);
 	if (err)
-		goto err_free_netdev;
+		goto err_rtnl_unlock;
 
 	nsim_ipsec_init(ns);
 
@@ -315,8 +316,8 @@
 err_ipsec_teardown:
 	nsim_ipsec_teardown(ns);
 	nsim_bpf_uninit(ns);
+err_rtnl_unlock:
 	rtnl_unlock();
-err_free_netdev:
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
--- linux-ein-5.4.0.orig/drivers/net/ntb_netdev.c
+++ linux-ein-5.4.0/drivers/net/ntb_netdev.c
@@ -137,7 +137,7 @@
 enqueue_again:
 	rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
 	if (rc) {
-		dev_kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		ndev->stats.rx_errors++;
 		ndev->stats.rx_fifo_errors++;
 	}
@@ -192,7 +192,7 @@
 		ndev->stats.tx_aborted_errors++;
 	}
 
-	dev_kfree_skb(skb);
+	dev_kfree_skb_any(skb);
 
 	if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {
 		/* Make sure anybody stopping the queue after this sees the new
@@ -484,7 +484,14 @@
 	rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
 	if (rc)
 		return rc;
-	return ntb_transport_register_client(&ntb_netdev_client);
+
+	rc = ntb_transport_register_client(&ntb_netdev_client);
+	if (rc) {
+		ntb_transport_unregister_client_dev(KBUILD_MODNAME);
+		return rc;
+	}
+
+	return 0;
 }
 module_init(ntb_netdev_init_module);
 
--- linux-ein-5.4.0.orig/drivers/net/phy/Kconfig
+++ linux-ein-5.4.0/drivers/net/phy/Kconfig
@@ -193,6 +193,7 @@
 	depends on 64BIT
 	depends on PCI
 	select MDIO_CAVIUM
+	select MDIO_DEVRES
 	help
 	  This driver supports the MDIO interfaces found on Cavium
 	  ThunderX SoCs when the MDIO bus device appears as a PCI
--- linux-ein-5.4.0.orig/drivers/net/phy/aquantia_main.c
+++ linux-ein-5.4.0/drivers/net/phy/aquantia_main.c
@@ -34,6 +34,8 @@
 #define MDIO_AN_VEND_PROV			0xc400
 #define MDIO_AN_VEND_PROV_1000BASET_FULL	BIT(15)
 #define MDIO_AN_VEND_PROV_1000BASET_HALF	BIT(14)
+#define MDIO_AN_VEND_PROV_5000BASET_FULL	BIT(11)
+#define MDIO_AN_VEND_PROV_2500BASET_FULL	BIT(10)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_EN		BIT(4)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK	GENMASK(3, 0)
 #define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT	4
@@ -230,9 +232,20 @@
 			      phydev->advertising))
 		reg |= MDIO_AN_VEND_PROV_1000BASET_HALF;
 
+	/* Handle the case when the 2.5G and 5G speeds are not advertised */
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+			      phydev->advertising))
+		reg |= MDIO_AN_VEND_PROV_2500BASET_FULL;
+
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+			      phydev->advertising))
+		reg |= MDIO_AN_VEND_PROV_5000BASET_FULL;
+
 	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
 				     MDIO_AN_VEND_PROV_1000BASET_HALF |
-				     MDIO_AN_VEND_PROV_1000BASET_FULL, reg);
+				     MDIO_AN_VEND_PROV_1000BASET_FULL |
+				     MDIO_AN_VEND_PROV_2500BASET_FULL |
+				     MDIO_AN_VEND_PROV_5000BASET_FULL, reg);
 	if (ret < 0)
 		return ret;
 	if (ret > 0)
@@ -627,6 +640,8 @@
 	.config_intr	= aqr_config_intr,
 	.ack_interrupt	= aqr_ack_interrupt,
 	.read_status	= aqr_read_status,
+	.suspend	= aqr107_suspend,
+	.resume		= aqr107_resume,
 },
 {
 	PHY_ID_MATCH_MODEL(PHY_ID_AQR106),
--- linux-ein-5.4.0.orig/drivers/net/phy/bcm-phy-lib.c
+++ linux-ein-5.4.0/drivers/net/phy/bcm-phy-lib.c
@@ -190,7 +190,7 @@
 
 int bcm_phy_set_eee(struct phy_device *phydev, bool enable)
 {
-	int val;
+	int val, mask = 0;
 
 	/* Enable EEE at PHY level */
 	val = phy_read_mmd(phydev, MDIO_MMD_AN, BRCM_CL45VEN_EEE_CONTROL);
@@ -209,10 +209,17 @@
 	if (val < 0)
 		return val;
 
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+			      phydev->supported))
+		mask |= MDIO_EEE_1000T;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+			      phydev->supported))
+		mask |= MDIO_EEE_100TX;
+
 	if (enable)
-		val |= (MDIO_EEE_100TX | MDIO_EEE_1000T);
+		val |= mask;
 	else
-		val &= ~(MDIO_EEE_100TX | MDIO_EEE_1000T);
+		val &= ~mask;
 
 	phy_write_mmd(phydev, MDIO_MMD_AN, BCM_CL45VEN_EEE_ADV, (u32)val);
 
--- linux-ein-5.4.0.orig/drivers/net/phy/bcm63xx.c
+++ linux-ein-5.4.0/drivers/net/phy/bcm63xx.c
@@ -73,6 +73,7 @@
 	/* same phy as above, with just a different OUI */
 	.phy_id		= 0x002bdc00,
 	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM63XX (2)",
 	/* PHY_BASIC_FEATURES */
 	.flags		= PHY_IS_INTERNAL,
 	.config_init	= bcm63xx_config_init,
--- linux-ein-5.4.0.orig/drivers/net/phy/bcm7xxx.c
+++ linux-ein-5.4.0/drivers/net/phy/bcm7xxx.c
@@ -26,7 +26,12 @@
 #define MII_BCM7XXX_SHD_2_ADDR_CTRL	0xe
 #define MII_BCM7XXX_SHD_2_CTRL_STAT	0xf
 #define MII_BCM7XXX_SHD_2_BIAS_TRIM	0x1a
+#define MII_BCM7XXX_SHD_3_PCS_CTRL	0x0
+#define MII_BCM7XXX_SHD_3_PCS_STATUS	0x1
+#define MII_BCM7XXX_SHD_3_EEE_CAP	0x2
 #define MII_BCM7XXX_SHD_3_AN_EEE_ADV	0x3
+#define MII_BCM7XXX_SHD_3_EEE_LP	0x4
+#define MII_BCM7XXX_SHD_3_EEE_WK_ERR	0x5
 #define MII_BCM7XXX_SHD_3_PCS_CTRL_2	0x6
 #define  MII_BCM7XXX_PCS_CTRL_2_DEF	0x4400
 #define MII_BCM7XXX_SHD_3_AN_STAT	0xb
@@ -210,25 +215,37 @@
 	return genphy_config_aneg(phydev);
 }
 
-static int phy_set_clr_bits(struct phy_device *dev, int location,
-					int set_mask, int clr_mask)
+static int __phy_set_clr_bits(struct phy_device *dev, int location,
+			      int set_mask, int clr_mask)
 {
 	int v, ret;
 
-	v = phy_read(dev, location);
+	v = __phy_read(dev, location);
 	if (v < 0)
 		return v;
 
 	v &= ~clr_mask;
 	v |= set_mask;
 
-	ret = phy_write(dev, location, v);
+	ret = __phy_write(dev, location, v);
 	if (ret < 0)
 		return ret;
 
 	return v;
 }
 
+static int phy_set_clr_bits(struct phy_device *dev, int location,
+			    int set_mask, int clr_mask)
+{
+	int ret;
+
+	mutex_lock(&dev->mdio.bus->mdio_lock);
+	ret = __phy_set_clr_bits(dev, location, set_mask, clr_mask);
+	mutex_unlock(&dev->mdio.bus->mdio_lock);
+
+	return ret;
+}
+
 static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
 {
 	int ret;
@@ -392,6 +409,93 @@
 	return bcm7xxx_28nm_ephy_apd_enable(phydev);
 }
 
+#define MII_BCM7XXX_REG_INVALID	0xff
+
+static u8 bcm7xxx_28nm_ephy_regnum_to_shd(u16 regnum)
+{
+	switch (regnum) {
+	case MDIO_CTRL1:
+		return MII_BCM7XXX_SHD_3_PCS_CTRL;
+	case MDIO_STAT1:
+		return MII_BCM7XXX_SHD_3_PCS_STATUS;
+	case MDIO_PCS_EEE_ABLE:
+		return MII_BCM7XXX_SHD_3_EEE_CAP;
+	case MDIO_AN_EEE_ADV:
+		return MII_BCM7XXX_SHD_3_AN_EEE_ADV;
+	case MDIO_AN_EEE_LPABLE:
+		return MII_BCM7XXX_SHD_3_EEE_LP;
+	case MDIO_PCS_EEE_WK_ERR:
+		return MII_BCM7XXX_SHD_3_EEE_WK_ERR;
+	default:
+		return MII_BCM7XXX_REG_INVALID;
+	}
+}
+
+static bool bcm7xxx_28nm_ephy_dev_valid(int devnum)
+{
+	return devnum == MDIO_MMD_AN || devnum == MDIO_MMD_PCS;
+}
+
+static int bcm7xxx_28nm_ephy_read_mmd(struct phy_device *phydev,
+				      int devnum, u16 regnum)
+{
+	u8 shd = bcm7xxx_28nm_ephy_regnum_to_shd(regnum);
+	int ret;
+
+	if (!bcm7xxx_28nm_ephy_dev_valid(devnum) ||
+	    shd == MII_BCM7XXX_REG_INVALID)
+		return -EOPNOTSUPP;
+
+	/* set shadow mode 2 */
+	ret = __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
+				 MII_BCM7XXX_SHD_MODE_2, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Access the desired shadow register address */
+	ret = __phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd);
+	if (ret < 0)
+		goto reset_shadow_mode;
+
+	ret = __phy_read(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT);
+
+reset_shadow_mode:
+	/* reset shadow mode 2 */
+	__phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
+			   MII_BCM7XXX_SHD_MODE_2);
+	return ret;
+}
+
+static int bcm7xxx_28nm_ephy_write_mmd(struct phy_device *phydev,
+				       int devnum, u16 regnum, u16 val)
+{
+	u8 shd = bcm7xxx_28nm_ephy_regnum_to_shd(regnum);
+	int ret;
+
+	if (!bcm7xxx_28nm_ephy_dev_valid(devnum) ||
+	    shd == MII_BCM7XXX_REG_INVALID)
+		return -EOPNOTSUPP;
+
+	/* set shadow mode 2 */
+	ret = __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
+				 MII_BCM7XXX_SHD_MODE_2, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Access the desired shadow register address */
+	ret = __phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd);
+	if (ret < 0)
+		goto reset_shadow_mode;
+
+	/* Write the desired value in the shadow register */
+	__phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, val);
+
+reset_shadow_mode:
+	/* reset shadow mode 2 */
+	return __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
+				  MII_BCM7XXX_SHD_MODE_2);
+}
+
 static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev)
 {
 	int ret;
@@ -563,6 +667,8 @@
 	.get_strings	= bcm_phy_get_strings,				\
 	.get_stats	= bcm7xxx_28nm_get_phy_stats,			\
 	.probe		= bcm7xxx_28nm_probe,				\
+	.read_mmd	= bcm7xxx_28nm_ephy_read_mmd,			\
+	.write_mmd	= bcm7xxx_28nm_ephy_write_mmd,			\
 }
 
 #define BCM7XXX_40NM_EPHY(_oui, _name)					\
--- linux-ein-5.4.0.orig/drivers/net/phy/broadcom.c
+++ linux-ein-5.4.0/drivers/net/phy/broadcom.c
@@ -11,6 +11,7 @@
  */
 
 #include "bcm-phy-lib.h"
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/brcmphy.h>
@@ -26,18 +27,13 @@
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
+static int bcm54xx_config_clock_delay(struct phy_device *phydev);
+
 static int bcm54210e_config_init(struct phy_device *phydev)
 {
 	int val;
 
-	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
-	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
-	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
-	bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val);
-
-	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
-	val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
-	bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
+	bcm54xx_config_clock_delay(phydev);
 
 	if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
 		val = phy_read(phydev, MII_CTRL1000);
@@ -429,6 +425,17 @@
 	return err;
 }
 
+static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
+{
+	return -EOPNOTSUPP;
+}
+
+static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
+			      u16 val)
+{
+	return -EOPNOTSUPP;
+}
+
 static int bcm5481_config_aneg(struct phy_device *phydev)
 {
 	struct device_node *np = phydev->mdio.dev.of_node;
@@ -484,6 +491,26 @@
 	if (err < 0)
 		return err;
 
+	/* The datasheet indicates the PHY needs up to 1us to complete a reset,
+	 * build some slack here.
+	 */
+	usleep_range(1000, 2000);
+
+	/* The PHY requires 65 MDC clock cycles to complete a write operation
+	 * and turnaround the line properly.
+	 *
+	 * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
+	 * may flag the lack of turn-around as a read failure. This is
+	 * particularly true with this combination since the MDIO controller
+	 * only used 64 MDC cycles. This is not a critical failure in this
+	 * specific case and it has no functional impact otherwise, so we let
+	 * that one go through. If there is a genuine bus error, the next read
+	 * of MII_BRCM_FET_INTREG will error out.
+	 */
+	err = phy_read(phydev, MII_BMCR);
+	if (err < 0 && err != -EIO)
+		return err;
+
 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
 	if (reg < 0)
 		return reg;
@@ -651,6 +678,7 @@
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM54616S",
 	/* PHY_GBIT_FEATURES */
+	.soft_reset     = genphy_soft_reset,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= bcm54616s_config_aneg,
 	.ack_interrupt	= bcm_phy_ack_intr,
@@ -679,6 +707,8 @@
 	.phy_id_mask    = 0xfffffff0,
 	.name           = "Broadcom BCM54810",
 	/* PHY_GBIT_FEATURES */
+	.read_mmd	= bcm54810_read_mmd,
+	.write_mmd	= bcm54810_write_mmd,
 	.config_init    = bcm54xx_config_init,
 	.config_aneg    = bcm5481_config_aneg,
 	.ack_interrupt  = bcm_phy_ack_intr,
--- linux-ein-5.4.0.orig/drivers/net/phy/dp83640.c
+++ linux-ein-5.4.0/drivers/net/phy/dp83640.c
@@ -1119,7 +1119,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);
 
@@ -1348,6 +1348,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:
@@ -1355,6 +1356,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:
@@ -1362,6 +1364,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:
@@ -1369,6 +1372,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;
--- linux-ein-5.4.0.orig/drivers/net/phy/dp83640_reg.h
+++ linux-ein-5.4.0/drivers/net/phy/dp83640_reg.h
@@ -5,7 +5,7 @@
 #ifndef HAVE_DP83640_REGISTERS
 #define HAVE_DP83640_REGISTERS
 
-#define PAGE0                     0x0000
+/* #define PAGE0                  0x0000 */
 #define PHYCR2                    0x001c /* PHY Control Register 2 */
 
 #define PAGE4                     0x0004
--- linux-ein-5.4.0.orig/drivers/net/phy/dp83822.c
+++ linux-ein-5.4.0/drivers/net/phy/dp83822.c
@@ -197,9 +197,7 @@
 		if (misr_status < 0)
 			return misr_status;
 
-		misr_status |= (DP83822_RX_ERR_HF_INT_EN |
-				DP83822_FALSE_CARRIER_HF_INT_EN |
-				DP83822_ANEG_COMPLETE_INT_EN |
+		misr_status |= (DP83822_ANEG_COMPLETE_INT_EN |
 				DP83822_DUP_MODE_CHANGE_INT_EN |
 				DP83822_SPEED_CHANGED_INT_EN |
 				DP83822_LINK_STAT_INT_EN |
@@ -238,7 +236,7 @@
 		if (err < 0)
 			return err;
 
-		err = phy_write(phydev, MII_DP83822_MISR1, 0);
+		err = phy_write(phydev, MII_DP83822_MISR2, 0);
 		if (err < 0)
 			return err;
 
--- linux-ein-5.4.0.orig/drivers/net/phy/dp83867.c
+++ linux-ein-5.4.0/drivers/net/phy/dp83867.c
@@ -25,7 +25,8 @@
 #define DP83867_CFG3		0x1e
 
 /* Extended Registers */
-#define DP83867_CFG4            0x0031
+#define DP83867_FLD_THR_CFG	0x002e
+#define DP83867_CFG4		0x0031
 #define DP83867_CFG4_SGMII_ANEG_MASK (BIT(5) | BIT(6))
 #define DP83867_CFG4_SGMII_ANEG_TIMER_11MS   (3 << 5)
 #define DP83867_CFG4_SGMII_ANEG_TIMER_800US  (2 << 5)
@@ -74,18 +75,23 @@
 #define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK	GENMASK(2, 0)
 #define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT	0
 #define DP83867_STRAP_STS2_CLK_SKEW_NONE	BIT(2)
+#define DP83867_STRAP_STS2_STRAP_FLD		BIT(10)
 
 /* PHY CTRL bits */
 #define DP83867_PHYCR_FIFO_DEPTH_SHIFT		14
 #define DP83867_PHYCR_FIFO_DEPTH_MAX		0x03
 #define DP83867_PHYCR_FIFO_DEPTH_MASK		GENMASK(15, 14)
 #define DP83867_PHYCR_RESERVED_MASK		BIT(11)
+#define DP83867_PHYCR_FORCE_LINK_GOOD		BIT(10)
 
 /* RGMIIDCTL bits */
 #define DP83867_RGMII_TX_CLK_DELAY_MAX		0xf
 #define DP83867_RGMII_TX_CLK_DELAY_SHIFT	4
+#define DP83867_RGMII_TX_CLK_DELAY_INV	(DP83867_RGMII_TX_CLK_DELAY_MAX + 1)
 #define DP83867_RGMII_RX_CLK_DELAY_MAX		0xf
 #define DP83867_RGMII_RX_CLK_DELAY_SHIFT	0
+#define DP83867_RGMII_RX_CLK_DELAY_INV	(DP83867_RGMII_RX_CLK_DELAY_MAX + 1)
+
 
 /* IO_MUX_CFG bits */
 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK	0x1f
@@ -95,9 +101,16 @@
 #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK	(0x1f << 8)
 #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT	8
 
+/* CFG3 bits */
+#define DP83867_CFG3_INT_OE			BIT(7)
+#define DP83867_CFG3_ROBUST_AUTO_MDIX		BIT(9)
+
 /* CFG4 bits */
 #define DP83867_CFG4_PORT_MIRROR_EN              BIT(0)
 
+/* FLD_THR_CFG */
+#define DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK	0x7
+
 enum {
 	DP83867_PORT_MIRROING_KEEP,
 	DP83867_PORT_MIRROING_EN,
@@ -164,7 +177,49 @@
 	return 0;
 }
 
-#ifdef CONFIG_OF_MDIO
+static int dp83867_verify_rgmii_cfg(struct phy_device *phydev)
+{
+	struct dp83867_private *dp83867 = phydev->priv;
+
+	/* Existing behavior was to use default pin strapping delay in rgmii
+	 * mode, but rgmii should have meant no delay.  Warn existing users.
+	 */
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR,
+					     DP83867_STRAP_STS2);
+		const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
+				   DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
+		const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
+				   DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
+
+		if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
+		    rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
+			phydev_warn(phydev,
+				    "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
+				    "Should be 'rgmii-id' to use internal delays txskew:%x rxskew:%x\n",
+				    txskew, rxskew);
+	}
+
+	/* RX delay *must* be specified if internal delay of RX is used. */
+	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	     phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) &&
+	     dp83867->rx_id_delay == DP83867_RGMII_RX_CLK_DELAY_INV) {
+		phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
+		return -EINVAL;
+	}
+
+	/* TX delay *must* be specified if internal delay of TX is used. */
+	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	     phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) &&
+	     dp83867->tx_id_delay == DP83867_RGMII_TX_CLK_DELAY_INV) {
+		phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF_MDIO)
 static int dp83867_of_init(struct phy_device *phydev)
 {
 	struct dp83867_private *dp83867 = phydev->priv;
@@ -205,55 +260,25 @@
 	dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
 					"ti,sgmii-ref-clock-output-enable");
 
-	/* Existing behavior was to use default pin strapping delay in rgmii
-	 * mode, but rgmii should have meant no delay.  Warn existing users.
-	 */
-	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
-		const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
-		const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
-				   DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
-		const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
-				   DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
 
-		if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
-		    rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
-			phydev_warn(phydev,
-				    "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
-				    "Should be 'rgmii-id' to use internal delays\n");
-	}
-
-	/* RX delay *must* be specified if internal delay of RX is used. */
-	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
-		ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
-					   &dp83867->rx_id_delay);
-		if (ret) {
-			phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
-			return ret;
-		}
-		if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
-			phydev_err(phydev,
-				   "ti,rx-internal-delay value of %u out of range\n",
-				   dp83867->rx_id_delay);
-			return -EINVAL;
-		}
+	dp83867->rx_id_delay = DP83867_RGMII_RX_CLK_DELAY_INV;
+	ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
+				   &dp83867->rx_id_delay);
+	if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
+		phydev_err(phydev,
+			   "ti,rx-internal-delay value of %u out of range\n",
+			   dp83867->rx_id_delay);
+		return -EINVAL;
 	}
 
-	/* TX delay *must* be specified if internal delay of RX is used. */
-	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
-		ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
-					   &dp83867->tx_id_delay);
-		if (ret) {
-			phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
-			return ret;
-		}
-		if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
-			phydev_err(phydev,
-				   "ti,tx-internal-delay value of %u out of range\n",
-				   dp83867->tx_id_delay);
-			return -EINVAL;
-		}
+	dp83867->tx_id_delay = DP83867_RGMII_TX_CLK_DELAY_INV;
+	ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
+				   &dp83867->tx_id_delay);
+	if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
+		phydev_err(phydev,
+			   "ti,tx-internal-delay value of %u out of range\n",
+			   dp83867->tx_id_delay);
+		return -EINVAL;
 	}
 
 	if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
@@ -304,7 +329,7 @@
 	int ret, val, bs;
 	u16 delay;
 
-	ret = dp83867_of_init(phydev);
+	ret = dp83867_verify_rgmii_cfg(phydev);
 	if (ret)
 		return ret;
 
@@ -313,6 +338,20 @@
 		phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
 				   BIT(7));
 
+	bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
+	if (bs & DP83867_STRAP_STS2_STRAP_FLD) {
+		/* When using strap to enable FLD, the ENERGY_LOST_FLD_THR will
+		 * be set to 0x2. This may causes the PHY link to be unstable -
+		 * the default value 0x1 need to be restored.
+		 */
+		ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
+				     DP83867_FLD_THR_CFG,
+				     DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK,
+				     0x1);
+		if (ret)
+			return ret;
+	}
+
 	if (phy_interface_is_rgmii(phydev)) {
 		val = phy_read(phydev, MII_DP83867_PHYCTRL);
 		if (val < 0)
@@ -359,8 +398,12 @@
 
 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);
 
-		delay = (dp83867->rx_id_delay |
-			(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+		delay = 0;
+		if (dp83867->rx_id_delay != DP83867_RGMII_RX_CLK_DELAY_INV)
+			delay |= dp83867->rx_id_delay;
+		if (dp83867->tx_id_delay != DP83867_RGMII_TX_CLK_DELAY_INV)
+			delay |= dp83867->tx_id_delay <<
+				 DP83867_RGMII_TX_CLK_DELAY_SHIFT;
 
 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
 			      delay);
@@ -408,14 +451,23 @@
 		else
 			val &= ~DP83867_SGMII_TYPE;
 		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val);
+
+		/* This is a SW workaround for link instability if RX_CTRL is
+		 * not strapped to mode 3 or 4 in HW. This is required for SGMII
+		 * in addition to clearing bit 7, handled above.
+		 */
+		if (dp83867->rxctrl_strap_quirk)
+			phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
+					 BIT(8));
 	}
 
+	val = phy_read(phydev, DP83867_CFG3);
 	/* 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);
-	}
+	if (phy_interrupt_is_valid(phydev))
+		val |= DP83867_CFG3_INT_OE;
+
+	val |= DP83867_CFG3_ROBUST_AUTO_MDIX;
+	phy_write(phydev, DP83867_CFG3, val);
 
 	if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
 		dp83867_config_port_mirroring(phydev);
@@ -449,7 +501,8 @@
 
 	usleep_range(10, 20);
 
-	return 0;
+	return phy_modify(phydev, MII_DP83867_PHYCTRL,
+			 DP83867_PHYCR_FORCE_LINK_GOOD, 0);
 }
 
 static struct phy_driver dp83867_driver[] = {
--- linux-ein-5.4.0.orig/drivers/net/phy/fixed_phy.c
+++ linux-ein-5.4.0/drivers/net/phy/fixed_phy.c
@@ -212,16 +212,13 @@
 	 */
 	gpiod = gpiod_get_from_of_node(fixed_link_node, "link-gpios", 0,
 				       GPIOD_IN, "mdio");
-	of_node_put(fixed_link_node);
-	if (IS_ERR(gpiod)) {
-		if (PTR_ERR(gpiod) == -EPROBE_DEFER)
-			return gpiod;
-
+	if (IS_ERR(gpiod) && PTR_ERR(gpiod) != -EPROBE_DEFER) {
 		if (PTR_ERR(gpiod) != -ENOENT)
 			pr_err("error getting GPIO for fixed link %pOF, proceed without\n",
 			       fixed_link_node);
 		gpiod = NULL;
 	}
+	of_node_put(fixed_link_node);
 
 	return gpiod;
 }
--- linux-ein-5.4.0.orig/drivers/net/phy/intel-xway.c
+++ linux-ein-5.4.0/drivers/net/phy/intel-xway.c
@@ -11,6 +11,18 @@
 
 #define XWAY_MDIO_IMASK			0x19	/* interrupt mask */
 #define XWAY_MDIO_ISTAT			0x1A	/* interrupt status */
+#define XWAY_MDIO_LED			0x1B	/* led control */
+
+/* bit 15:12 are reserved */
+#define XWAY_MDIO_LED_LED3_EN		BIT(11)	/* Enable the integrated function of LED3 */
+#define XWAY_MDIO_LED_LED2_EN		BIT(10)	/* Enable the integrated function of LED2 */
+#define XWAY_MDIO_LED_LED1_EN		BIT(9)	/* Enable the integrated function of LED1 */
+#define XWAY_MDIO_LED_LED0_EN		BIT(8)	/* Enable the integrated function of LED0 */
+/* bit 7:4 are reserved */
+#define XWAY_MDIO_LED_LED3_DA		BIT(3)	/* Direct Access to LED3 */
+#define XWAY_MDIO_LED_LED2_DA		BIT(2)	/* Direct Access to LED2 */
+#define XWAY_MDIO_LED_LED1_DA		BIT(1)	/* Direct Access to LED1 */
+#define XWAY_MDIO_LED_LED0_DA		BIT(0)	/* Direct Access to LED0 */
 
 #define XWAY_MDIO_INIT_WOL		BIT(15)	/* Wake-On-LAN */
 #define XWAY_MDIO_INIT_MSRE		BIT(14)
@@ -159,6 +171,15 @@
 	/* Clear all pending interrupts */
 	phy_read(phydev, XWAY_MDIO_ISTAT);
 
+	/* Ensure that integrated led function is enabled for all leds */
+	err = phy_write(phydev, XWAY_MDIO_LED,
+			XWAY_MDIO_LED_LED0_EN |
+			XWAY_MDIO_LED_LED1_EN |
+			XWAY_MDIO_LED_LED2_EN |
+			XWAY_MDIO_LED_LED3_EN);
+	if (err)
+		return err;
+
 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
 		      XWAY_MMD_LEDCH_NACS_NONE |
 		      XWAY_MMD_LEDCH_SBF_F02HZ |
--- linux-ein-5.4.0.orig/drivers/net/phy/marvell.c
+++ linux-ein-5.4.0/drivers/net/phy/marvell.c
@@ -358,7 +358,7 @@
 	return marvell_config_aneg(phydev);
 }
 
-#ifdef CONFIG_OF_MDIO
+#if IS_ENABLED(CONFIG_OF_MDIO)
 /* Set and/or override some configuration registers based on the
  * marvell,reg-init property stored in the of_node for the phydev.
  *
@@ -444,9 +444,9 @@
 	else
 		mscr = 0;
 
-	return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
-				MII_88E1121_PHY_MSCR_REG,
-				MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+	return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,
+					MII_88E1121_PHY_MSCR_REG,
+					MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
 }
 
 static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -460,11 +460,13 @@
 			return err;
 	}
 
+	changed = err;
+
 	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
 	if (err < 0)
 		return err;
 
-	changed = err;
+	changed |= err;
 
 	err = genphy_config_aneg(phydev);
 	if (err < 0)
@@ -886,16 +888,15 @@
 {
 	int err;
 
-	err = genphy_soft_reset(phydev);
+	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
 	if (err < 0)
 		return err;
 
-	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
+	err = genphy_config_aneg(phydev);
 	if (err < 0)
 		return err;
 
-	err = genphy_config_aneg(phydev);
-	return 0;
+	return genphy_soft_reset(phydev);
 }
 
 static int m88e1118_config_init(struct phy_device *phydev)
@@ -917,6 +918,12 @@
 	if (err < 0)
 		return err;
 
+	if (phy_interface_is_rgmii(phydev)) {
+		err = m88e1121_config_aneg_rgmii_delays(phydev);
+		if (err < 0)
+			return err;
+	}
+
 	/* Adjust LED Control */
 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
 		err = phy_write(phydev, 0x10, 0x1100);
@@ -1401,8 +1408,8 @@
 	int err;
 
 	/* Suspend the fiber mode first */
-	if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
-			       phydev->supported)) {
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
+			      phydev->supported)) {
 		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
 		if (err < 0)
 			goto error;
@@ -1436,8 +1443,8 @@
 	int err;
 
 	/* Resume the fiber mode first */
-	if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
-			       phydev->supported)) {
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
+			      phydev->supported)) {
 		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
 		if (err < 0)
 			goto error;
@@ -2401,9 +2408,31 @@
 		.get_stats = marvell_get_stats,
 	},
 	{
-		.phy_id = MARVELL_PHY_ID_88E6390,
+		.phy_id = MARVELL_PHY_ID_88E6341_FAMILY,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E6341 Family",
+		/* PHY_GBIT_FEATURES */
+		.probe = m88e1510_probe,
+		.config_init = &marvell_config_init,
+		.config_aneg = &m88e6390_config_aneg,
+		.read_status = &marvell_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.did_interrupt = &m88e1121_did_interrupt,
+		.resume = &genphy_resume,
+		.suspend = &genphy_suspend,
+		.read_page = marvell_read_page,
+		.write_page = marvell_write_page,
+		.get_sset_count = marvell_get_sset_count,
+		.get_strings = marvell_get_strings,
+		.get_stats = marvell_get_stats,
+		.get_tunable = m88e1540_get_tunable,
+		.set_tunable = m88e1540_set_tunable,
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E6390_FAMILY,
 		.phy_id_mask = MARVELL_PHY_ID_MASK,
-		.name = "Marvell 88E6390",
+		.name = "Marvell 88E6390 Family",
 		/* PHY_GBIT_FEATURES */
 		.probe = m88e6390_probe,
 		.config_init = &marvell_config_init,
@@ -2441,7 +2470,8 @@
 	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
 	{ MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },
 	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
-	{ MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK },
+	{ MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK },
+	{ MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK },
 	{ }
 };
 
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-aspeed.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-aspeed.c
@@ -61,6 +61,13 @@
 
 	iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
 
+	rc = readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
+				!(ctrl & ASPEED_MDIO_CTRL_FIRE),
+				ASPEED_MDIO_INTERVAL_US,
+				ASPEED_MDIO_TIMEOUT_US);
+	if (rc < 0)
+		return rc;
+
 	rc = readl_poll_timeout(ctx->base + ASPEED_MDIO_DATA, data,
 				data & ASPEED_MDIO_DATA_IDLE,
 				ASPEED_MDIO_INTERVAL_US,
@@ -141,6 +148,7 @@
 	{ .compatible = "aspeed,ast2600-mdio", },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, aspeed_mdio_of_match);
 
 static struct platform_driver aspeed_mdio_driver = {
 	.driver = {
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-bcm-iproc.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-bcm-iproc.c
@@ -178,6 +178,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 */ },
@@ -188,6 +205,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-ein-5.4.0.orig/drivers/net/phy/mdio-bcm-unimac.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-bcm-unimac.c
@@ -242,11 +242,9 @@
 		return -ENOMEM;
 	}
 
-	priv->clk = devm_clk_get(&pdev->dev, NULL);
-	if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
+	priv->clk = devm_clk_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
 		return PTR_ERR(priv->clk);
-	else
-		priv->clk = NULL;
 
 	ret = clk_prepare_enable(priv->clk);
 	if (ret)
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-i2c.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-i2c.c
@@ -10,10 +10,9 @@
  * of their settings.
  */
 #include <linux/i2c.h>
+#include <linux/mdio/mdio-i2c.h>
 #include <linux/phy.h>
 
-#include "mdio-i2c.h"
-
 /*
  * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
  * specified to be present in SFP modules.  These correspond with PHY
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-mux-bcm-iproc.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-mux-bcm-iproc.c
@@ -288,8 +288,13 @@
 static int mdio_mux_iproc_resume(struct device *dev)
 {
 	struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
+	int rc;
 
-	clk_prepare_enable(md->core_clk);
+	rc = clk_prepare_enable(md->core_clk);
+	if (rc) {
+		dev_err(md->dev, "failed to enable core clk\n");
+		return rc;
+	}
 	mdio_mux_iproc_config(md);
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-mux-meson-g12a.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-mux-meson-g12a.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/device.h>
@@ -148,6 +149,7 @@
 
 static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
 {
+	u32 value;
 	int ret;
 
 	/* Enable the phy clock */
@@ -161,18 +163,25 @@
 
 	/* Initialize ephy control */
 	writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
-	writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
-	       FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
-	       FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
-	       PHY_CNTL1_CLK_EN |
-	       PHY_CNTL1_CLKFREQ |
-	       PHY_CNTL1_PHY_ENB,
-	       priv->regs + ETH_PHY_CNTL1);
+
+	/* Make sure we get a 0 -> 1 transition on the enable bit */
+	value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
+		FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
+		FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
+		PHY_CNTL1_CLK_EN |
+		PHY_CNTL1_CLKFREQ;
+	writel(value, priv->regs + ETH_PHY_CNTL1);
 	writel(PHY_CNTL2_USE_INTERNAL |
 	       PHY_CNTL2_SMI_SRC_MAC |
 	       PHY_CNTL2_RX_CLK_EPHY,
 	       priv->regs + ETH_PHY_CNTL2);
 
+	value |= PHY_CNTL1_PHY_ENB;
+	writel(value, priv->regs + ETH_PHY_CNTL1);
+
+	/* The phy needs a bit of time to power up */
+	mdelay(10);
+
 	return 0;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-mux.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-mux.c
@@ -82,6 +82,17 @@
 
 static int parent_count;
 
+static void mdio_mux_uninit_children(struct mdio_mux_parent_bus *pb)
+{
+	struct mdio_mux_child_bus *cb = pb->children;
+
+	while (cb) {
+		mdiobus_unregister(cb->mii_bus);
+		mdiobus_free(cb->mii_bus);
+		cb = cb->next;
+	}
+}
+
 int mdio_mux_init(struct device *dev,
 		  struct device_node *mux_node,
 		  int (*switch_fn)(int cur, int desired, void *data),
@@ -144,7 +155,7 @@
 		cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
 		if (!cb) {
 			ret_val = -ENOMEM;
-			continue;
+			goto err_loop;
 		}
 		cb->bus_number = v;
 		cb->parent = pb;
@@ -152,8 +163,7 @@
 		cb->mii_bus = mdiobus_alloc();
 		if (!cb->mii_bus) {
 			ret_val = -ENOMEM;
-			devm_kfree(dev, cb);
-			continue;
+			goto err_loop;
 		}
 		cb->mii_bus->priv = cb;
 
@@ -165,11 +175,15 @@
 		cb->mii_bus->write = mdio_mux_write;
 		r = of_mdiobus_register(cb->mii_bus, child_bus_node);
 		if (r) {
+			mdiobus_free(cb->mii_bus);
+			if (r == -EPROBE_DEFER) {
+				ret_val = r;
+				goto err_loop;
+			}
+			devm_kfree(dev, cb);
 			dev_err(dev,
 				"Error: Failed to register MDIO bus for child %pOF\n",
 				child_bus_node);
-			mdiobus_free(cb->mii_bus);
-			devm_kfree(dev, cb);
 		} else {
 			cb->next = pb->children;
 			pb->children = cb;
@@ -182,6 +196,10 @@
 
 	dev_err(dev, "Error: No acceptable child buses found\n");
 	devm_kfree(dev, pb);
+
+err_loop:
+	mdio_mux_uninit_children(pb);
+	of_node_put(child_bus_node);
 err_pb_kz:
 	put_device(&parent_bus->dev);
 err_parent_bus:
@@ -193,14 +211,8 @@
 void mdio_mux_uninit(void *mux_handle)
 {
 	struct mdio_mux_parent_bus *pb = mux_handle;
-	struct mdio_mux_child_bus *cb = pb->children;
-
-	while (cb) {
-		mdiobus_unregister(cb->mii_bus);
-		mdiobus_free(cb->mii_bus);
-		cb = cb->next;
-	}
 
+	mdio_mux_uninit_children(pb);
 	put_device(&pb->mii_bus->dev);
 }
 EXPORT_SYMBOL_GPL(mdio_mux_uninit);
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-octeon.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-octeon.c
@@ -72,7 +72,6 @@
 
 	return 0;
 fail_register:
-	mdiobus_free(bus->mii_bus);
 	smi_en.u64 = 0;
 	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
 	return err;
@@ -86,7 +85,6 @@
 	bus = platform_get_drvdata(pdev);
 
 	mdiobus_unregister(bus->mii_bus);
-	mdiobus_free(bus->mii_bus);
 	smi_en.u64 = 0;
 	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-thunder.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-thunder.c
@@ -104,6 +104,7 @@
 		if (i >= ARRAY_SIZE(nexus->buses))
 			break;
 	}
+	fwnode_handle_put(fwn);
 	return 0;
 
 err_release_regions:
@@ -126,7 +127,6 @@
 			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);
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio-xgene.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio-xgene.c
@@ -11,6 +11,7 @@
 #include <linux/efi.h>
 #include <linux/if_vlan.h>
 #include <linux/io.h>
+#include <linux/mdio/mdio-xgene.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/of_net.h>
@@ -18,7 +19,6 @@
 #include <linux/prefetch.h>
 #include <linux/phy.h>
 #include <net/ip.h>
-#include "mdio-xgene.h"
 
 static bool xgene_mdio_status;
 
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio_bus.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio_bus.c
@@ -62,8 +62,8 @@
 	struct reset_control *reset = NULL;
 
 	if (mdiodev->dev.of_node)
-		reset = devm_reset_control_get_exclusive(&mdiodev->dev,
-							 "phy");
+		reset = of_reset_control_get_exclusive(mdiodev->dev.of_node,
+						       "phy");
 	if (IS_ERR(reset)) {
 		if (PTR_ERR(reset) == -ENOENT || PTR_ERR(reset) == -ENOTSUPP)
 			reset = NULL;
@@ -107,6 +107,8 @@
 	if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
 		return -EINVAL;
 
+	reset_control_put(mdiodev->reset_ctrl);
+
 	mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
 
 	return 0;
@@ -115,7 +117,12 @@
 
 struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
 {
-	struct mdio_device *mdiodev = bus->mdio_map[addr];
+	struct mdio_device *mdiodev;
+
+	if (addr < 0 || addr >= ARRAY_SIZE(bus->mdio_map))
+		return NULL;
+
+	mdiodev = bus->mdio_map[addr];
 
 	if (!mdiodev)
 		return NULL;
@@ -383,6 +390,13 @@
 	bus->dev.groups = NULL;
 	dev_set_name(&bus->dev, "%s", bus->id);
 
+	/* We need to set state to MDIOBUS_UNREGISTERED to correctly release
+	 * the device in mdiobus_free()
+	 *
+	 * State will be updated later in this function in case of success
+	 */
+	bus->state = MDIOBUS_UNREGISTERED;
+
 	err = device_register(&bus->dev);
 	if (err) {
 		pr_err("mii_bus %s failed to register\n", bus->id);
@@ -410,7 +424,7 @@
 		bus->reset(bus);
 
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		if ((bus->phy_mask & (1 << i)) == 0) {
+		if ((bus->phy_mask & BIT(i)) == 0) {
 			struct phy_device *phydev;
 
 			phydev = mdiobus_scan(bus, i);
@@ -424,7 +438,7 @@
 	mdiobus_setup_mdiodev_from_board_info(bus, mdiobus_create_device);
 
 	bus->state = MDIOBUS_REGISTERED;
-	pr_info("%s: probed\n", bus->name);
+	dev_dbg(&bus->dev, "probed\n");
 	return 0;
 
 error:
@@ -451,7 +465,8 @@
 	struct mdio_device *mdiodev;
 	int i;
 
-	BUG_ON(bus->state != MDIOBUS_REGISTERED);
+	if (WARN_ON_ONCE(bus->state != MDIOBUS_REGISTERED))
+		return;
 	bus->state = MDIOBUS_UNREGISTERED;
 
 	for (i = 0; i < PHY_MAX_ADDR; i++) {
@@ -743,7 +758,6 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(mdio_bus_init);
 
 #if IS_ENABLED(CONFIG_PHYLIB)
 void mdio_bus_exit(void)
--- linux-ein-5.4.0.orig/drivers/net/phy/mdio_device.c
+++ linux-ein-5.4.0/drivers/net/phy/mdio_device.c
@@ -180,6 +180,16 @@
 	return 0;
 }
 
+static void mdio_shutdown(struct device *dev)
+{
+	struct mdio_device *mdiodev = to_mdio_device(dev);
+	struct device_driver *drv = mdiodev->dev.driver;
+	struct mdio_driver *mdiodrv = to_mdio_driver(drv);
+
+	if (mdiodrv->shutdown)
+		mdiodrv->shutdown(mdiodev);
+}
+
 /**
  * mdio_driver_register - register an mdio_driver with the MDIO layer
  * @new_driver: new mdio_driver to register
@@ -194,6 +204,7 @@
 	mdiodrv->driver.bus = &mdio_bus_type;
 	mdiodrv->driver.probe = mdio_probe;
 	mdiodrv->driver.remove = mdio_remove;
+	mdiodrv->driver.shutdown = mdio_shutdown;
 
 	retval = driver_register(&mdiodrv->driver);
 	if (retval) {
--- linux-ein-5.4.0.orig/drivers/net/phy/meson-gxl.c
+++ linux-ein-5.4.0/drivers/net/phy/meson-gxl.c
@@ -235,6 +235,8 @@
 		.config_intr	= meson_gxl_config_intr,
 		.suspend        = genphy_suspend,
 		.resume         = genphy_resume,
+		.read_mmd	= genphy_read_mmd_unsupported,
+		.write_mmd	= genphy_write_mmd_unsupported,
 	}, {
 		PHY_ID_MATCH_EXACT(0x01803301),
 		.name		= "Meson G12A Internal PHY",
@@ -245,6 +247,8 @@
 		.config_intr	= meson_gxl_config_intr,
 		.suspend        = genphy_suspend,
 		.resume         = genphy_resume,
+		.read_mmd	= genphy_read_mmd_unsupported,
+		.write_mmd	= genphy_write_mmd_unsupported,
 	},
 };
 
--- linux-ein-5.4.0.orig/drivers/net/phy/micrel.c
+++ linux-ein-5.4.0/drivers/net/phy/micrel.c
@@ -19,12 +19,14 @@
  *			 ksz9477
  */
 
+#include <linux/bitfield.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 
 /* Operation Mode Strap Override */
 #define MII_KSZPHY_OMSO				0x16
@@ -281,7 +283,7 @@
 		}
 	}
 
-	if (priv->led_mode >= 0)
+	if (priv->type && priv->led_mode >= 0)
 		kszphy_setup_led(phydev, priv->type->led_mode_reg, priv->led_mode);
 
 	return 0;
@@ -297,10 +299,10 @@
 
 	type = priv->type;
 
-	if (type->has_broadcast_disable)
+	if (type && type->has_broadcast_disable)
 		kszphy_broadcast_disable(phydev);
 
-	if (type->has_nand_tree_disable)
+	if (type && type->has_nand_tree_disable)
 		kszphy_nand_tree_disable(phydev);
 
 	return kszphy_config_reset(phydev);
@@ -342,11 +344,11 @@
 }
 
 static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev,
-					    const u32 ksz_phy_id)
+					    const bool ksz_8051)
 {
 	int ret;
 
-	if ((phydev->phy_id & MICREL_PHY_ID_MASK) != ksz_phy_id)
+	if ((phydev->phy_id & MICREL_PHY_ID_MASK) != PHY_ID_KSZ8051)
 		return 0;
 
 	ret = phy_read(phydev, MII_BMSR);
@@ -359,7 +361,7 @@
 	 * the switch does not.
 	 */
 	ret &= BMSR_ERCAP;
-	if (ksz_phy_id == PHY_ID_KSZ8051)
+	if (ksz_8051)
 		return ret;
 	else
 		return !ret;
@@ -367,7 +369,7 @@
 
 static int ksz8051_match_phy_device(struct phy_device *phydev)
 {
-	return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ8051);
+	return ksz8051_ksz8795_match_phy_device(phydev, true);
 }
 
 static int ksz8081_config_init(struct phy_device *phydev)
@@ -395,7 +397,7 @@
 
 static int ksz8795_match_phy_device(struct phy_device *phydev)
 {
-	return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ87XX);
+	return ksz8051_ksz8795_match_phy_device(phydev, false);
 }
 
 static int ksz9021_load_values_from_of(struct phy_device *phydev,
@@ -489,9 +491,50 @@
 
 /* MMD Address 0x2 */
 #define MII_KSZ9031RN_CONTROL_PAD_SKEW	4
+#define MII_KSZ9031RN_RX_CTL_M		GENMASK(7, 4)
+#define MII_KSZ9031RN_TX_CTL_M		GENMASK(3, 0)
+
 #define MII_KSZ9031RN_RX_DATA_PAD_SKEW	5
+#define MII_KSZ9031RN_RXD3		GENMASK(15, 12)
+#define MII_KSZ9031RN_RXD2		GENMASK(11, 8)
+#define MII_KSZ9031RN_RXD1		GENMASK(7, 4)
+#define MII_KSZ9031RN_RXD0		GENMASK(3, 0)
+
 #define MII_KSZ9031RN_TX_DATA_PAD_SKEW	6
+#define MII_KSZ9031RN_TXD3		GENMASK(15, 12)
+#define MII_KSZ9031RN_TXD2		GENMASK(11, 8)
+#define MII_KSZ9031RN_TXD1		GENMASK(7, 4)
+#define MII_KSZ9031RN_TXD0		GENMASK(3, 0)
+
 #define MII_KSZ9031RN_CLK_PAD_SKEW	8
+#define MII_KSZ9031RN_GTX_CLK		GENMASK(9, 5)
+#define MII_KSZ9031RN_RX_CLK		GENMASK(4, 0)
+
+/* KSZ9031 has internal RGMII_IDRX = 1.2ns and RGMII_IDTX = 0ns. To
+ * provide different RGMII options we need to configure delay offset
+ * for each pad relative to build in delay.
+ */
+/* keep rx as "No delay adjustment" and set rx_clk to +0.60ns to get delays of
+ * 1.80ns
+ */
+#define RX_ID				0x7
+#define RX_CLK_ID			0x19
+
+/* set rx to +0.30ns and rx_clk to -0.90ns to compensate the
+ * internal 1.2ns delay.
+ */
+#define RX_ND				0xc
+#define RX_CLK_ND			0x0
+
+/* set tx to -0.42ns and tx_clk to +0.96ns to get 1.38ns delay */
+#define TX_ID				0x0
+#define TX_CLK_ID			0x1f
+
+/* set tx and tx_clk to "No delay adjustment" to keep 0ns
+ * dealy
+ */
+#define TX_ND				0x7
+#define TX_CLK_ND			0xf
 
 /* MMD Address 0x1C */
 #define MII_KSZ9031RN_EDPD		0x23
@@ -500,7 +543,8 @@
 static int ksz9031_of_load_skew_values(struct phy_device *phydev,
 				       const struct device_node *of_node,
 				       u16 reg, size_t field_sz,
-				       const char *field[], u8 numfields)
+				       const char *field[], u8 numfields,
+				       bool *update)
 {
 	int val[4] = {-1, -2, -3, -4};
 	int matches = 0;
@@ -516,6 +560,8 @@
 	if (!matches)
 		return 0;
 
+	*update |= true;
+
 	if (matches < numfields)
 		newval = phy_read_mmd(phydev, 2, reg);
 	else
@@ -564,6 +610,67 @@
 			     reg | MII_KSZ9031RN_EDPD_ENABLE);
 }
 
+static int ksz9031_config_rgmii_delay(struct phy_device *phydev)
+{
+	u16 rx, tx, rx_clk, tx_clk;
+	int ret;
+
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_RGMII:
+		tx = TX_ND;
+		tx_clk = TX_CLK_ND;
+		rx = RX_ND;
+		rx_clk = RX_CLK_ND;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_ID:
+		tx = TX_ID;
+		tx_clk = TX_CLK_ID;
+		rx = RX_ID;
+		rx_clk = RX_CLK_ID;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+		tx = TX_ND;
+		tx_clk = TX_CLK_ND;
+		rx = RX_ID;
+		rx_clk = RX_CLK_ID;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		tx = TX_ID;
+		tx_clk = TX_CLK_ID;
+		rx = RX_ND;
+		rx_clk = RX_CLK_ND;
+		break;
+	default:
+		return 0;
+	}
+
+	ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_CONTROL_PAD_SKEW,
+			    FIELD_PREP(MII_KSZ9031RN_RX_CTL_M, rx) |
+			    FIELD_PREP(MII_KSZ9031RN_TX_CTL_M, tx));
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_RX_DATA_PAD_SKEW,
+			    FIELD_PREP(MII_KSZ9031RN_RXD3, rx) |
+			    FIELD_PREP(MII_KSZ9031RN_RXD2, rx) |
+			    FIELD_PREP(MII_KSZ9031RN_RXD1, rx) |
+			    FIELD_PREP(MII_KSZ9031RN_RXD0, rx));
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_TX_DATA_PAD_SKEW,
+			    FIELD_PREP(MII_KSZ9031RN_TXD3, tx) |
+			    FIELD_PREP(MII_KSZ9031RN_TXD2, tx) |
+			    FIELD_PREP(MII_KSZ9031RN_TXD1, tx) |
+			    FIELD_PREP(MII_KSZ9031RN_TXD0, tx));
+	if (ret < 0)
+		return ret;
+
+	return phy_write_mmd(phydev, 2, MII_KSZ9031RN_CLK_PAD_SKEW,
+			     FIELD_PREP(MII_KSZ9031RN_GTX_CLK, tx_clk) |
+			     FIELD_PREP(MII_KSZ9031RN_RX_CLK, rx_clk));
+}
+
 static int ksz9031_config_init(struct phy_device *phydev)
 {
 	const struct device *dev = &phydev->mdio.dev;
@@ -596,21 +703,33 @@
 	} while (!of_node && dev_walker);
 
 	if (of_node) {
+		bool update = false;
+
+		if (phy_interface_is_rgmii(phydev)) {
+			result = ksz9031_config_rgmii_delay(phydev);
+			if (result < 0)
+				return result;
+		}
+
 		ksz9031_of_load_skew_values(phydev, of_node,
 				MII_KSZ9031RN_CLK_PAD_SKEW, 5,
-				clk_skews, 2);
+				clk_skews, 2, &update);
 
 		ksz9031_of_load_skew_values(phydev, of_node,
 				MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
-				control_skews, 2);
+				control_skews, 2, &update);
 
 		ksz9031_of_load_skew_values(phydev, of_node,
 				MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
-				rx_data_skews, 4);
+				rx_data_skews, 4, &update);
 
 		ksz9031_of_load_skew_values(phydev, of_node,
 				MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
-				tx_data_skews, 4);
+				tx_data_skews, 4, &update);
+
+		if (update && phydev->interface != PHY_INTERFACE_MODE_RGMII)
+			phydev_warn(phydev,
+				    "*-skew-ps values should be used only with phy-mode = \"rgmii\"\n");
 
 		/* Silicon Errata Sheet (DS80000691D or DS80000692D):
 		 * When the device links in the 1000BASE-T slave mode only,
@@ -704,6 +823,50 @@
 	return phy_write_mmd(phydev, 2, reg, newval);
 }
 
+#define KSZ9131RN_MMD_COMMON_CTRL_REG	2
+#define KSZ9131RN_RXC_DLL_CTRL		76
+#define KSZ9131RN_TXC_DLL_CTRL		77
+#define KSZ9131RN_DLL_CTRL_BYPASS	BIT_MASK(12)
+#define KSZ9131RN_DLL_ENABLE_DELAY	0
+#define KSZ9131RN_DLL_DISABLE_DELAY	BIT(12)
+
+static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
+{
+	u16 rxcdll_val, txcdll_val;
+	int ret;
+
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_RGMII:
+		rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
+		txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_ID:
+		rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
+		txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+		rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
+		txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
+		txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
+		break;
+	default:
+		return 0;
+	}
+
+	ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+			     KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
+			     rxcdll_val);
+	if (ret < 0)
+		return ret;
+
+	return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+			      KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
+			      txcdll_val);
+}
+
 static int ksz9131_config_init(struct phy_device *phydev)
 {
 	const struct device *dev = &phydev->mdio.dev;
@@ -730,6 +893,12 @@
 	if (!of_node)
 		return 0;
 
+	if (phy_interface_is_rgmii(phydev)) {
+		ret = ksz9131_config_rgmii_delay(phydev);
+		if (ret < 0)
+			return ret;
+	}
+
 	ret = ksz9131_of_load_skew_values(phydev, of_node,
 					  MII_KSZ9031RN_CLK_PAD_SKEW, 5,
 					  clk_skews, 2);
@@ -902,6 +1071,12 @@
 
 	genphy_resume(phydev);
 
+	/* After switching from power-down to normal mode, an internal global
+	 * reset is automatically generated. Wait a minimum of 1 ms before
+	 * read/write access to the PHY registers.
+	 */
+	usleep_range(1000, 2000);
+
 	ret = kszphy_config_reset(phydev);
 	if (ret)
 		return ret;
@@ -932,7 +1107,7 @@
 
 	priv->type = type;
 
-	if (type->led_mode_reg) {
+	if (type && type->led_mode_reg) {
 		ret = of_property_read_u32(np, "micrel,led-mode",
 				&priv->led_mode);
 		if (ret)
@@ -953,7 +1128,8 @@
 		unsigned long rate = clk_get_rate(clk);
 		bool rmii_ref_clk_sel_25_mhz;
 
-		priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel;
+		if (type)
+			priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel;
 		rmii_ref_clk_sel_25_mhz = of_property_read_bool(np,
 				"micrel,rmii-reference-clock-select-25-mhz");
 
@@ -1033,8 +1209,9 @@
 	.get_sset_count = kszphy_get_sset_count,
 	.get_strings	= kszphy_get_strings,
 	.get_stats	= kszphy_get_stats,
-	.suspend	= genphy_suspend,
-	.resume		= genphy_resume,
+	/* No suspend/resume callbacks because of errata DS80000700A,
+	 * receiver error following software power down.
+	 */
 }, {
 	.phy_id		= PHY_ID_KSZ8041RNLI,
 	.phy_id_mask	= MICREL_PHY_ID_MASK,
@@ -1088,6 +1265,7 @@
 	.probe		= kszphy_probe,
 	.config_init	= ksz8081_config_init,
 	.ack_interrupt	= kszphy_ack_interrupt,
+	.soft_reset	= genphy_soft_reset,
 	.config_intr	= kszphy_config_intr,
 	.get_sset_count = kszphy_get_sset_count,
 	.get_strings	= kszphy_get_strings,
@@ -1140,14 +1318,28 @@
 	.suspend	= genphy_suspend,
 	.resume		= kszphy_resume,
 }, {
+	.phy_id		= PHY_ID_LAN8814,
+	.phy_id_mask	= MICREL_PHY_ID_MASK,
+	.name		= "Microchip INDY Gigabit Quad PHY",
+	.driver_data	= &ksz9021_type,
+	.probe		= kszphy_probe,
+	.soft_reset	= genphy_soft_reset,
+	.read_status	= ksz9031_read_status,
+	.get_sset_count	= kszphy_get_sset_count,
+	.get_strings	= kszphy_get_strings,
+	.get_stats	= kszphy_get_stats,
+	.suspend	= genphy_suspend,
+	.resume		= kszphy_resume,
+}, {
 	.phy_id		= PHY_ID_KSZ9131,
 	.phy_id_mask	= MICREL_PHY_ID_MASK,
 	.name		= "Microchip KSZ9131 Gigabit PHY",
 	/* PHY_GBIT_FEATURES */
 	.driver_data	= &ksz9021_type,
 	.probe		= kszphy_probe,
+	.soft_reset	= genphy_soft_reset,
 	.config_init	= ksz9131_config_init,
-	.read_status	= ksz9031_read_status,
+	.read_status	= genphy_read_status,
 	.ack_interrupt	= kszphy_ack_interrupt,
 	.config_intr	= kszphy_config_intr,
 	.get_sset_count = kszphy_get_sset_count,
@@ -1177,8 +1369,6 @@
 	.name		= "Micrel KSZ87XX Switch",
 	/* PHY_BASIC_FEATURES */
 	.config_init	= kszphy_config_init,
-	.config_aneg	= ksz8873mll_config_aneg,
-	.read_status	= ksz8873mll_read_status,
 	.match_phy_device = ksz8795_match_phy_device,
 	.suspend	= genphy_suspend,
 	.resume		= genphy_resume,
@@ -1212,6 +1402,7 @@
 	{ PHY_ID_KSZ8081, MICREL_PHY_ID_MASK },
 	{ PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK },
 	{ PHY_ID_KSZ886X, MICREL_PHY_ID_MASK },
+	{ PHY_ID_LAN8814, MICREL_PHY_ID_MASK },
 	{ }
 };
 
--- linux-ein-5.4.0.orig/drivers/net/phy/microchip.c
+++ linux-ein-5.4.0/drivers/net/phy/microchip.c
@@ -326,6 +326,37 @@
 	return genphy_config_aneg(phydev);
 }
 
+static void lan88xx_link_change_notify(struct phy_device *phydev)
+{
+	int temp;
+
+	/* At forced 100 F/H mode, chip may fail to set mode correctly
+	 * when cable is switched between long(~50+m) and short one.
+	 * As workaround, set to 10 before setting to 100
+	 * at forced 100 F/H mode.
+	 */
+	if (!phydev->autoneg && phydev->speed == 100) {
+		/* disable phy interrupt */
+		temp = phy_read(phydev, LAN88XX_INT_MASK);
+		temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
+		phy_write(phydev, LAN88XX_INT_MASK, temp);
+
+		temp = phy_read(phydev, MII_BMCR);
+		temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
+		phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
+		temp |= BMCR_SPEED100;
+		phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
+
+		/* clear pending interrupt generated while workaround */
+		temp = phy_read(phydev, LAN88XX_INT_STS);
+
+		/* enable phy interrupt back */
+		temp = phy_read(phydev, LAN88XX_INT_MASK);
+		temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
+		phy_write(phydev, LAN88XX_INT_MASK, temp);
+	}
+}
+
 static struct phy_driver microchip_phy_driver[] = {
 {
 	.phy_id		= 0x0007c130,
@@ -339,6 +370,7 @@
 
 	.config_init	= lan88xx_config_init,
 	.config_aneg	= lan88xx_config_aneg,
+	.link_change_notify = lan88xx_link_change_notify,
 
 	.ack_interrupt	= lan88xx_phy_ack_interrupt,
 	.config_intr	= lan88xx_phy_config_intr,
--- linux-ein-5.4.0.orig/drivers/net/phy/microchip_t1.c
+++ linux-ein-5.4.0/drivers/net/phy/microchip_t1.c
@@ -3,9 +3,21 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 
+/* External Register Control Register */
+#define LAN87XX_EXT_REG_CTL                     (0x14)
+#define LAN87XX_EXT_REG_CTL_RD_CTL              (0x1000)
+#define LAN87XX_EXT_REG_CTL_WR_CTL              (0x0800)
+
+/* External Register Read Data Register */
+#define LAN87XX_EXT_REG_RD_DATA                 (0x15)
+
+/* External Register Write Data Register */
+#define LAN87XX_EXT_REG_WR_DATA                 (0x16)
+
 /* Interrupt Source Register */
 #define LAN87XX_INTERRUPT_SOURCE                (0x18)
 
@@ -14,9 +26,160 @@
 #define LAN87XX_MASK_LINK_UP                    (0x0004)
 #define LAN87XX_MASK_LINK_DOWN                  (0x0002)
 
+/* phyaccess nested types */
+#define	PHYACC_ATTR_MODE_READ		0
+#define	PHYACC_ATTR_MODE_WRITE		1
+#define	PHYACC_ATTR_MODE_MODIFY		2
+
+#define	PHYACC_ATTR_BANK_SMI		0
+#define	PHYACC_ATTR_BANK_MISC		1
+#define	PHYACC_ATTR_BANK_PCS		2
+#define	PHYACC_ATTR_BANK_AFE		3
+#define	PHYACC_ATTR_BANK_MAX		7
+
 #define DRIVER_AUTHOR	"Nisar Sayed <nisar.sayed@microchip.com>"
 #define DRIVER_DESC	"Microchip LAN87XX T1 PHY driver"
 
+struct access_ereg_val {
+	u8  mode;
+	u8  bank;
+	u8  offset;
+	u16 val;
+	u16 mask;
+};
+
+static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
+		       u8 offset, u16 val)
+{
+	u16 ereg = 0;
+	int rc = 0;
+
+	if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX)
+		return -EINVAL;
+
+	if (bank == PHYACC_ATTR_BANK_SMI) {
+		if (mode == PHYACC_ATTR_MODE_WRITE)
+			rc = phy_write(phydev, offset, val);
+		else
+			rc = phy_read(phydev, offset);
+		return rc;
+	}
+
+	if (mode == PHYACC_ATTR_MODE_WRITE) {
+		ereg = LAN87XX_EXT_REG_CTL_WR_CTL;
+		rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val);
+		if (rc < 0)
+			return rc;
+	} else {
+		ereg = LAN87XX_EXT_REG_CTL_RD_CTL;
+	}
+
+	ereg |= (bank << 8) | offset;
+
+	rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg);
+	if (rc < 0)
+		return rc;
+
+	if (mode == PHYACC_ATTR_MODE_READ)
+		rc = phy_read(phydev, LAN87XX_EXT_REG_RD_DATA);
+
+	return rc;
+}
+
+static int access_ereg_modify_changed(struct phy_device *phydev,
+				      u8 bank, u8 offset, u16 val, u16 mask)
+{
+	int new = 0, rc = 0;
+
+	if (bank > PHYACC_ATTR_BANK_MAX)
+		return -EINVAL;
+
+	rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, bank, offset, val);
+	if (rc < 0)
+		return rc;
+
+	new = val | (rc & (mask ^ 0xFFFF));
+	rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, bank, offset, new);
+
+	return rc;
+}
+
+static int lan87xx_phy_init(struct phy_device *phydev)
+{
+	static const struct access_ereg_val init[] = {
+		/* TX Amplitude = 5 */
+		{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_AFE, 0x0B,
+		 0x000A, 0x001E},
+		/* Clear SMI interrupts */
+		{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 0x18,
+		 0, 0},
+		/* Clear MISC interrupts */
+		{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 0x08,
+		 0, 0},
+		/* Turn on TC10 Ring Oscillator (ROSC) */
+		{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_MISC, 0x20,
+		 0x0020, 0x0020},
+		/* WUR Detect Length to 1.2uS, LPC Detect Length to 1.09uS */
+		{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_PCS, 0x20,
+		 0x283C, 0},
+		/* Wake_In Debounce Length to 39uS, Wake_Out Length to 79uS */
+		{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x21,
+		 0x274F, 0},
+		/* Enable Auto Wake Forward to Wake_Out, ROSC on, Sleep,
+		 * and Wake_In to wake PHY
+		 */
+		{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x20,
+		 0x80A7, 0},
+		/* Enable WUP Auto Fwd, Enable Wake on MDI, Wakeup Debouncer
+		 * to 128 uS
+		 */
+		{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x24,
+		 0xF110, 0},
+		/* Enable HW Init */
+		{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_SMI, 0x1A,
+		 0x0100, 0x0100},
+	};
+	int rc, i;
+
+	/* Start manual initialization procedures in Managed Mode */
+	rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
+					0x1a, 0x0000, 0x0100);
+	if (rc < 0)
+		return rc;
+
+	/* Soft Reset the SMI block */
+	rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
+					0x00, 0x8000, 0x8000);
+	if (rc < 0)
+		return rc;
+
+	/* Check to see if the self-clearing bit is cleared */
+	usleep_range(1000, 2000);
+	rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
+			 PHYACC_ATTR_BANK_SMI, 0x00, 0);
+	if (rc < 0)
+		return rc;
+	if ((rc & 0x8000) != 0)
+		return -ETIMEDOUT;
+
+	/* PHY Initialization */
+	for (i = 0; i < ARRAY_SIZE(init); i++) {
+		if (init[i].mode == PHYACC_ATTR_MODE_MODIFY) {
+			rc = access_ereg_modify_changed(phydev, init[i].bank,
+							init[i].offset,
+							init[i].val,
+							init[i].mask);
+		} else {
+			rc = access_ereg(phydev, init[i].mode, init[i].bank,
+					 init[i].offset, init[i].val);
+		}
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
+
 static int lan87xx_phy_config_intr(struct phy_device *phydev)
 {
 	int rc, val = 0;
@@ -40,6 +203,13 @@
 	return rc < 0 ? rc : 0;
 }
 
+static int lan87xx_config_init(struct phy_device *phydev)
+{
+	int rc = lan87xx_phy_init(phydev);
+
+	return rc < 0 ? rc : 0;
+}
+
 static struct phy_driver microchip_t1_phy_driver[] = {
 	{
 		.phy_id         = 0x0007c150,
@@ -48,6 +218,7 @@
 
 		.features       = PHY_BASIC_T1_FEATURES,
 
+		.config_init	= lan87xx_config_init,
 		.config_aneg    = genphy_config_aneg,
 
 		.ack_interrupt  = lan87xx_phy_ack_interrupt,
--- linux-ein-5.4.0.orig/drivers/net/phy/mscc.c
+++ linux-ein-5.4.0/drivers/net/phy/mscc.c
@@ -302,11 +302,11 @@
 				BIT(VSC8531_FORCE_LED_OFF) | \
 				BIT(VSC8531_FORCE_LED_ON))
 
-#define MSCC_VSC8584_REVB_INT8051_FW		"mscc_vsc8584_revb_int8051_fb48.bin"
+#define MSCC_VSC8584_REVB_INT8051_FW		"microchip/mscc_vsc8584_revb_int8051_fb48.bin"
 #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR	0xe800
 #define MSCC_VSC8584_REVB_INT8051_FW_CRC	0xfb48
 
-#define MSCC_VSC8574_REVB_INT8051_FW		"mscc_vsc8574_revb_int8051_29e8.bin"
+#define MSCC_VSC8574_REVB_INT8051_FW		"microchip/mscc_vsc8574_revb_int8051_29e8.bin"
 #define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR	0x4000
 #define MSCC_VSC8574_REVB_INT8051_FW_CRC	0x29e8
 
--- linux-ein-5.4.0.orig/drivers/net/phy/phy-c45.c
+++ linux-ein-5.4.0/drivers/net/phy/phy-c45.c
@@ -239,9 +239,10 @@
 
 		/* The link state is latched low so that momentary link
 		 * drops can be detected. Do not double-read the status
-		 * in polling mode to detect such short link drops.
+		 * in polling mode to detect such short link drops except
+		 * the link was already down.
 		 */
-		if (!phy_polling_mode(phydev)) {
+		if (!phy_polling_mode(phydev) || !phydev->link) {
 			val = phy_read_mmd(phydev, devad, MDIO_STAT1);
 			if (val < 0)
 				return val;
--- linux-ein-5.4.0.orig/drivers/net/phy/phy-core.c
+++ linux-ein-5.4.0/drivers/net/phy/phy-core.c
@@ -128,11 +128,11 @@
 	PHY_SETTING(   2500, FULL,   2500baseT_Full		),
 	PHY_SETTING(   2500, FULL,   2500baseX_Full		),
 	/* 1G */
-	PHY_SETTING(   1000, FULL,   1000baseKX_Full		),
 	PHY_SETTING(   1000, FULL,   1000baseT_Full		),
 	PHY_SETTING(   1000, HALF,   1000baseT_Half		),
 	PHY_SETTING(   1000, FULL,   1000baseT1_Full		),
 	PHY_SETTING(   1000, FULL,   1000baseX_Full		),
+	PHY_SETTING(   1000, FULL,   1000baseKX_Full		),
 	/* 100M */
 	PHY_SETTING(    100, FULL,    100baseT_Full		),
 	PHY_SETTING(    100, FULL,    100baseT1_Full		),
--- linux-ein-5.4.0.orig/drivers/net/phy/phy.c
+++ linux-ein-5.4.0/drivers/net/phy/phy.c
@@ -116,10 +116,15 @@
  */
 static int phy_clear_interrupt(struct phy_device *phydev)
 {
-	if (phydev->drv->ack_interrupt)
-		return phydev->drv->ack_interrupt(phydev);
+	int ret = 0;
 
-	return 0;
+	if (phydev->drv->ack_interrupt) {
+		mutex_lock(&phydev->lock);
+		ret = phydev->drv->ack_interrupt(phydev);
+		mutex_unlock(&phydev->lock);
+	}
+
+	return ret;
 }
 
 /**
@@ -345,15 +350,16 @@
 
 	phydev->autoneg = autoneg;
 
-	phydev->speed = speed;
+	if (autoneg == AUTONEG_DISABLE) {
+		phydev->speed = speed;
+		phydev->duplex = duplex;
+	}
 
 	linkmode_copy(phydev->advertising, advertising);
 
 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
 			 phydev->advertising, autoneg == AUTONEG_ENABLE);
 
-	phydev->duplex = duplex;
-
 	phydev->mdix_ctrl = cmd->base.eth_tp_mdix_ctrl;
 
 	/* Restart the PHY */
@@ -366,6 +372,7 @@
 void phy_ethtool_ksettings_get(struct phy_device *phydev,
 			       struct ethtool_link_ksettings *cmd)
 {
+	mutex_lock(&phydev->lock);
 	linkmode_copy(cmd->link_modes.supported, phydev->supported);
 	linkmode_copy(cmd->link_modes.advertising, phydev->advertising);
 	linkmode_copy(cmd->link_modes.lp_advertising, phydev->lp_advertising);
@@ -382,6 +389,7 @@
 	cmd->base.autoneg = phydev->autoneg;
 	cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl;
 	cmd->base.eth_tp_mdix = phydev->mdix;
+	mutex_unlock(&phydev->lock);
 }
 EXPORT_SYMBOL(phy_ethtool_ksettings_get);
 
@@ -552,7 +560,7 @@
 }
 
 /**
- * phy_start_aneg - start auto-negotiation for this PHY device
+ * _phy_start_aneg - start auto-negotiation for this PHY device
  * @phydev: the phy_device struct
  *
  * Description: Sanitizes the settings (if we're not autonegotiating
@@ -560,25 +568,43 @@
  *   If the PHYCONTROL Layer is operating, we change the state to
  *   reflect the beginning of Auto-negotiation or forcing.
  */
-int phy_start_aneg(struct phy_device *phydev)
+static int _phy_start_aneg(struct phy_device *phydev)
 {
 	int err;
 
+	lockdep_assert_held(&phydev->lock);
+
 	if (!phydev->drv)
 		return -EIO;
 
-	mutex_lock(&phydev->lock);
-
 	if (AUTONEG_DISABLE == phydev->autoneg)
 		phy_sanitize_settings(phydev);
 
 	err = phy_config_aneg(phydev);
 	if (err < 0)
-		goto out_unlock;
+		return err;
 
 	if (phy_is_started(phydev))
 		err = phy_check_link_status(phydev);
-out_unlock:
+
+	return err;
+}
+
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
+ *
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ *   them), and then calls the driver's config_aneg function.
+ *   If the PHYCONTROL Layer is operating, we change the state to
+ *   reflect the beginning of Auto-negotiation or forcing.
+ */
+int phy_start_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	mutex_lock(&phydev->lock);
+	err = _phy_start_aneg(phydev);
 	mutex_unlock(&phydev->lock);
 
 	return err;
@@ -740,6 +766,36 @@
 }
 
 /**
+ * phy_did_interrupt - Checks if the PHY generated an interrupt
+ * @phydev: target phy_device struct
+ */
+static int phy_did_interrupt(struct phy_device *phydev)
+{
+	int ret;
+
+	mutex_lock(&phydev->lock);
+	ret = phydev->drv->did_interrupt(phydev);
+	mutex_unlock(&phydev->lock);
+
+	return ret;
+}
+
+/**
+ * phy_handle_interrupt - PHY specific interrupt handler
+ * @phydev: target phy_device struct
+ */
+static int phy_handle_interrupt(struct phy_device *phydev)
+{
+	int ret;
+
+	mutex_lock(&phydev->lock);
+	ret = phydev->drv->handle_interrupt(phydev);
+	mutex_unlock(&phydev->lock);
+
+	return ret;
+}
+
+/**
  * phy_interrupt - PHY interrupt handler
  * @irq: interrupt line
  * @phy_dat: phy_device pointer
@@ -750,18 +806,19 @@
 {
 	struct phy_device *phydev = phy_dat;
 
-	if (phydev->drv->did_interrupt && !phydev->drv->did_interrupt(phydev))
+	if (phydev->drv->did_interrupt && !phy_did_interrupt(phydev))
 		return IRQ_NONE;
 
 	if (phydev->drv->handle_interrupt) {
-		if (phydev->drv->handle_interrupt(phydev))
+		if (phy_handle_interrupt(phydev))
 			goto phy_err;
 	} else {
 		/* reschedule state queue work to run as soon as possible */
 		phy_trigger_machine(phydev);
 	}
 
-	if (phy_clear_interrupt(phydev))
+	/* did_interrupt() may have cleared the interrupt already */
+	if (!phydev->drv->did_interrupt && phy_clear_interrupt(phydev))
 		goto phy_err;
 	return IRQ_HANDLED;
 
@@ -833,7 +890,7 @@
  */
 void phy_stop(struct phy_device *phydev)
 {
-	if (!phy_is_started(phydev)) {
+	if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) {
 		WARN(1, "called from state %s\n",
 		     phy_state_to_str(phydev->state));
 		return;
@@ -1159,9 +1216,11 @@
 		/* Restart autonegotiation so the new modes get sent to the
 		 * link partner.
 		 */
-		ret = phy_restart_aneg(phydev);
-		if (ret < 0)
-			return ret;
+		if (phydev->autoneg == AUTONEG_ENABLE) {
+			ret = phy_restart_aneg(phydev);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	return 0;
--- linux-ein-5.4.0.orig/drivers/net/phy/phy_device.c
+++ linux-ein-5.4.0/drivers/net/phy/phy_device.c
@@ -246,7 +246,7 @@
 	 * MDIO bus driver and clock gated at this point.
 	 */
 	if (!netdev)
-		return !phydev->suspended;
+		goto out;
 
 	if (netdev->wol_enabled)
 		return false;
@@ -266,7 +266,8 @@
 	if (device_may_wakeup(&netdev->dev))
 		return false;
 
-	return true;
+out:
+	return !phydev->suspended;
 }
 
 static int mdio_bus_phy_suspend(struct device *dev)
@@ -284,6 +285,8 @@
 	if (!mdio_bus_phy_may_suspend(phydev))
 		return 0;
 
+	phydev->suspended_by_mdio_bus = 1;
+
 	return phy_suspend(phydev);
 }
 
@@ -292,9 +295,11 @@
 	struct phy_device *phydev = to_phy_device(dev);
 	int ret;
 
-	if (!mdio_bus_phy_may_suspend(phydev))
+	if (!phydev->suspended_by_mdio_bus)
 		goto no_resume;
 
+	phydev->suspended_by_mdio_bus = 0;
+
 	ret = phy_resume(phydev);
 	if (ret < 0)
 		return ret;
@@ -488,7 +493,7 @@
 
 	if (phydev->is_c45) {
 		for (i = 1; i < num_ids; i++) {
-			if (!(phydev->c45_ids.devices_in_package & (1 << i)))
+			if (phydev->c45_ids.device_ids[i] == 0xffffffff)
 				continue;
 
 			if ((phydrv->phy_id & phydrv->phy_id_mask) ==
@@ -552,7 +557,7 @@
 	.pm = MDIO_BUS_PHY_PM_OPS,
 };
 
-static int phy_request_driver_module(struct phy_device *dev, int phy_id)
+static int phy_request_driver_module(struct phy_device *dev, u32 phy_id)
 {
 	int ret;
 
@@ -564,15 +569,15 @@
 	 * then modprobe isn't available.
 	 */
 	if (IS_ENABLED(CONFIG_MODULES) && ret < 0 && ret != -ENOENT) {
-		phydev_err(dev, "error %d loading PHY driver module for ID 0x%08x\n",
-			   ret, phy_id);
+		phydev_err(dev, "error %d loading PHY driver module for ID 0x%08lx\n",
+			   ret, (unsigned long)phy_id);
 		return ret;
 	}
 
 	return 0;
 }
 
-struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
+struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
 				     bool is_c45,
 				     struct phy_c45_device_ids *c45_ids)
 {
@@ -596,8 +601,8 @@
 	mdiodev->device_free = phy_mdio_device_free;
 	mdiodev->device_remove = phy_mdio_device_remove;
 
-	dev->speed = 0;
-	dev->duplex = -1;
+	dev->speed = SPEED_UNKNOWN;
+	dev->duplex = DUPLEX_UNKNOWN;
 	dev->pause = 0;
 	dev->asym_pause = 0;
 	dev->link = 0;
@@ -610,7 +615,9 @@
 	if (c45_ids)
 		dev->c45_ids = *c45_ids;
 	dev->irq = bus->irq[addr];
+
 	dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
+	device_initialize(&mdiodev->dev);
 
 	dev->state = PHY_DOWN;
 
@@ -632,7 +639,7 @@
 		int i;
 
 		for (i = 1; i < num_ids; i++) {
-			if (!(c45_ids->devices_in_package & (1 << i)))
+			if (c45_ids->device_ids[i] == 0xffffffff)
 				continue;
 
 			ret = phy_request_driver_module(dev,
@@ -644,10 +651,8 @@
 		ret = phy_request_driver_module(dev, phy_id);
 	}
 
-	if (!ret) {
-		device_initialize(&mdiodev->dev);
-	} else {
-		kfree(dev);
+	if (ret) {
+		put_device(&mdiodev->dev);
 		dev = ERR_PTR(ret);
 	}
 
@@ -792,8 +797,10 @@
 
 	/* Grab the bits from PHYIR2, and put them in the lower half */
 	phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
-	if (phy_reg < 0)
-		return -EIO;
+	if (phy_reg < 0) {
+		/* returning -ENODEV doesn't stop bus scanning */
+		return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
+	}
 
 	*phy_id |= phy_reg;
 
@@ -812,10 +819,13 @@
  */
 struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
 {
-	struct phy_c45_device_ids c45_ids = {0};
+	struct phy_c45_device_ids c45_ids;
 	u32 phy_id = 0;
 	int r;
 
+	c45_ids.devices_in_package = 0;
+	memset(c45_ids.device_ids, 0xff, sizeof(c45_ids.device_ids));
+
 	r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
 	if (r)
 		return ERR_PTR(r);
@@ -1302,6 +1312,7 @@
 
 error_module_put:
 	module_put(d->driver->owner);
+	d->driver = NULL;
 error_put_device:
 	put_device(d);
 	if (ndev_owner != bus->owner)
@@ -1411,7 +1422,8 @@
 
 	phy_led_triggers_unregister(phydev);
 
-	module_put(phydev->mdio.dev.driver->owner);
+	if (phydev->mdio.dev.driver)
+		module_put(phydev->mdio.dev.driver->owner);
 
 	/* If the device had no specific driver before (i.e. - it
 	 * was using the generic driver), we unbind the device
@@ -1422,6 +1434,9 @@
 	    phy_driver_is_genphy_10g(phydev))
 		device_release_driver(&phydev->mdio.dev);
 
+	/* Assert the reset signal */
+	phy_device_reset(phydev, 1);
+
 	/*
 	 * The phydev might go away on the put_device() below, so avoid
 	 * a use-after-free bug by reading the underlying bus first.
@@ -1433,9 +1448,6 @@
 		ndev_owner = dev->dev.parent->driver->owner;
 	if (ndev_owner != bus->owner)
 		module_put(bus->owner);
-
-	/* Assert the reset signal */
-	phy_device_reset(phydev, 1);
 }
 EXPORT_SYMBOL(phy_detach);
 
@@ -1755,9 +1767,10 @@
 
 	/* The link state is latched low so that momentary link
 	 * drops can be detected. Do not double-read the status
-	 * in polling mode to detect such short link drops.
+	 * in polling mode to detect such short link drops except
+	 * the link was already down.
 	 */
-	if (!phy_polling_mode(phydev)) {
+	if (!phy_polling_mode(phydev) || !phydev->link) {
 		status = phy_read(phydev, MII_BMSR);
 		if (status < 0)
 			return status;
--- linux-ein-5.4.0.orig/drivers/net/phy/phylink.c
+++ linux-ein-5.4.0/drivers/net/phy/phylink.c
@@ -444,8 +444,7 @@
 
 	pl->cur_interface = link_state.interface;
 	pl->ops->mac_link_up(pl->config, pl->link_an_mode,
-			     pl->phy_state.interface,
-			     pl->phydev);
+			     pl->cur_interface, pl->phydev);
 
 	if (ndev)
 		netif_carrier_on(ndev);
@@ -583,6 +582,11 @@
 		return ret;
 	}
 
+	if (!fwnode_device_is_available(ref.fwnode)) {
+		fwnode_handle_put(ref.fwnode);
+		return 0;
+	}
+
 	pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
 	if (!pl->sfp_bus)
 		return -ENOMEM;
@@ -1332,7 +1336,7 @@
 		return -EOPNOTSUPP;
 
 	if (!phylink_test(pl->supported, Asym_Pause) &&
-	    !pause->autoneg && pause->rx_pause != pause->tx_pause)
+	    pause->rx_pause != pause->tx_pause)
 		return -EINVAL;
 
 	config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK);
--- linux-ein-5.4.0.orig/drivers/net/phy/realtek.c
+++ linux-ein-5.4.0/drivers/net/phy/realtek.c
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0+
-/*
- * drivers/net/phy/realtek.c
+/* drivers/net/phy/realtek.c
  *
  * Driver for Realtek PHYs
  *
@@ -29,9 +28,10 @@
 #define RTL8211F_INSR				0x1d
 
 #define RTL8211F_TX_DELAY			BIT(8)
-#define RTL8211E_TX_DELAY			BIT(1)
-#define RTL8211E_RX_DELAY			BIT(2)
-#define RTL8211E_MODE_MII_GMII			BIT(3)
+
+#define RTL8211E_CTRL_DELAY			BIT(13)
+#define RTL8211E_TX_DELAY			BIT(12)
+#define RTL8211E_RX_DELAY			BIT(11)
 
 #define RTL8201F_ISR				0x1e
 #define RTL8201F_IER				0x13
@@ -171,7 +171,9 @@
 
 static int rtl8211f_config_init(struct phy_device *phydev)
 {
+	struct device *dev = &phydev->mdio.dev;
 	u16 val;
+	int ret;
 
 	/* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and
 	 * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin.
@@ -189,7 +191,22 @@
 		return 0;
 	}
 
-	return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
+	ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
+				       val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to update the TX delay register\n");
+		return ret;
+	} else if (ret) {
+		dev_dbg(dev,
+			"%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
+			val ? "Enabling" : "Disabling");
+	} else {
+		dev_dbg(dev,
+			"2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
+			val ? "enabled" : "disabled");
+	}
+
+	return 0;
 }
 
 static int rtl8211e_config_init(struct phy_device *phydev)
@@ -200,16 +217,16 @@
 	/* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
 	switch (phydev->interface) {
 	case PHY_INTERFACE_MODE_RGMII:
-		val = 0;
+		val = RTL8211E_CTRL_DELAY | 0;
 		break;
 	case PHY_INTERFACE_MODE_RGMII_ID:
-		val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
+		val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
 		break;
 	case PHY_INTERFACE_MODE_RGMII_RXID:
-		val = RTL8211E_RX_DELAY;
+		val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
 		break;
 	case PHY_INTERFACE_MODE_RGMII_TXID:
-		val = RTL8211E_TX_DELAY;
+		val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
 		break;
 	default: /* the rest of the modes imply leaving delays as is. */
 		return 0;
@@ -217,11 +234,12 @@
 
 	/* According to a sample driver there is a 0x1c config register on the
 	 * 0xa4 extension page (0x7) layout. It can be used to disable/enable
-	 * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can
-	 * also be used to customize the whole configuration register:
-	 * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select,
-	 * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
-	 * for details).
+	 * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
+	 * The configuration register definition:
+	 * 14 = reserved
+	 * 13 = Force Tx RX Delay controlled by bit12 bit11,
+	 * 12 = RX Delay, 11 = TX Delay
+	 * 10:0 = Test && debug settings reserved by realtek
 	 */
 	oldpage = phy_select_page(phydev, 0x7);
 	if (oldpage < 0)
@@ -231,7 +249,8 @@
 	if (ret)
 		goto err_restore_page;
 
-	ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
+	ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
+			   | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
 			   val);
 
 err_restore_page:
@@ -438,6 +457,15 @@
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
 		.read_page	= rtl821x_read_page,
+		.write_page	= rtl821x_write_page,
+	}, {
+		PHY_ID_MATCH_MODEL(0x001cc880),
+		.name		= "RTL8208 Fast Ethernet",
+		.read_mmd	= genphy_read_mmd_unsupported,
+		.write_mmd	= genphy_write_mmd_unsupported,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.read_page	= rtl821x_read_page,
 		.write_page	= rtl821x_write_page,
 	}, {
 		PHY_ID_MATCH_EXACT(0x001cc910),
--- linux-ein-5.4.0.orig/drivers/net/phy/sfp-bus.c
+++ linux-ein-5.4.0/drivers/net/phy/sfp-bus.c
@@ -9,6 +9,12 @@
 
 #include "sfp.h"
 
+struct sfp_quirk {
+	const char *vendor;
+	const char *part;
+	void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
+};
+
 /**
  * struct sfp_bus - internal representation of a sfp bus
  */
@@ -21,6 +27,7 @@
 	const struct sfp_socket_ops *socket_ops;
 	struct device *sfp_dev;
 	struct sfp *sfp;
+	const struct sfp_quirk *sfp_quirk;
 
 	const struct sfp_upstream_ops *upstream_ops;
 	void *upstream;
@@ -30,6 +37,71 @@
 	bool started;
 };
 
+static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
+				unsigned long *modes)
+{
+	phylink_set(modes, 2500baseX_Full);
+}
+
+static const struct sfp_quirk sfp_quirks[] = {
+	{
+		// Alcatel Lucent G-010S-P can operate at 2500base-X, but
+		// incorrectly report 2500MBd NRZ in their EEPROM
+		.vendor = "ALCATELLUCENT",
+		.part = "G010SP",
+		.modes = sfp_quirk_2500basex,
+	}, {
+		// Alcatel Lucent G-010S-A can operate at 2500base-X, but
+		// report 3.2GBd NRZ in their EEPROM
+		.vendor = "ALCATELLUCENT",
+		.part = "3FE46541AA",
+		.modes = sfp_quirk_2500basex,
+	}, {
+		// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
+		// NRZ in their EEPROM
+		.vendor = "HUAWEI",
+		.part = "MA5671A",
+		.modes = sfp_quirk_2500basex,
+	},
+};
+
+static size_t sfp_strlen(const char *str, size_t maxlen)
+{
+	size_t size, i;
+
+	/* Trailing characters should be filled with space chars */
+	for (i = 0, size = 0; i < maxlen; i++)
+		if (str[i] != ' ')
+			size = i + 1;
+
+	return size;
+}
+
+static bool sfp_match(const char *qs, const char *str, size_t len)
+{
+	if (!qs)
+		return true;
+	if (strlen(qs) != len)
+		return false;
+	return !strncmp(qs, str, len);
+}
+
+static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
+{
+	const struct sfp_quirk *q;
+	unsigned int i;
+	size_t vs, ps;
+
+	vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
+	ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
+
+	for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
+		if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
+		    sfp_match(q->part, id->base.vendor_pn, ps))
+			return q;
+
+	return NULL;
+}
 /**
  * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
@@ -233,6 +305,9 @@
 			phylink_set(modes, 1000baseX_Full);
 	}
 
+	if (bus->sfp_quirk)
+		bus->sfp_quirk->modes(id, modes);
+
 	bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
 
 	phylink_set(support, Autoneg);
@@ -553,6 +628,8 @@
 	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
 	int ret = 0;
 
+	bus->sfp_quirk = sfp_lookup_quirk(id);
+
 	if (ops && ops->module_insert)
 		ret = ops->module_insert(bus->upstream, id);
 
@@ -566,6 +643,8 @@
 
 	if (ops && ops->module_remove)
 		ops->module_remove(bus->upstream);
+
+	bus->sfp_quirk = NULL;
 }
 EXPORT_SYMBOL_GPL(sfp_module_remove);
 
--- linux-ein-5.4.0.orig/drivers/net/phy/sfp.c
+++ linux-ein-5.4.0/drivers/net/phy/sfp.c
@@ -7,6 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
+#include <linux/mdio/mdio-i2c.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
@@ -16,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 
-#include "mdio-i2c.h"
 #include "sfp.h"
 #include "swphy.h"
 
@@ -115,7 +115,7 @@
 	[SFP_S_LINK_UP] = "link_up",
 	[SFP_S_TX_FAULT] = "tx_fault",
 	[SFP_S_REINIT] = "reinit",
-	[SFP_S_TX_DISABLE] = "rx_disable",
+	[SFP_S_TX_DISABLE] = "tx_disable",
 };
 
 static const char *sm_state_to_str(unsigned short sm_state)
@@ -1878,7 +1878,7 @@
 
 	platform_set_drvdata(pdev, sfp);
 
-	err = devm_add_action(sfp->dev, sfp_cleanup, sfp);
+	err = devm_add_action_or_reset(sfp->dev, sfp_cleanup, sfp);
 	if (err < 0)
 		return err;
 
@@ -1970,7 +1970,8 @@
 			continue;
 
 		sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
-		if (!sfp->gpio_irq[i]) {
+		if (sfp->gpio_irq[i] < 0) {
+			sfp->gpio_irq[i] = 0;
 			poll = true;
 			continue;
 		}
--- linux-ein-5.4.0.orig/drivers/net/phy/smsc.c
+++ linux-ein-5.4.0/drivers/net/phy/smsc.c
@@ -108,8 +108,11 @@
 static int lan87xx_read_status(struct phy_device *phydev)
 {
 	struct smsc_phy_priv *priv = phydev->priv;
+	int err;
 
-	int err = genphy_read_status(phydev);
+	err = genphy_read_status(phydev);
+	if (err)
+		return err;
 
 	if (!phydev->link && priv->energy_enable) {
 		int i;
--- linux-ein-5.4.0.orig/drivers/net/phy/xilinx_gmii2rgmii.c
+++ linux-ein-5.4.0/drivers/net/phy/xilinx_gmii2rgmii.c
@@ -82,6 +82,7 @@
 
 	if (!priv->phy_dev->drv) {
 		dev_info(dev, "Attached phy not ready\n");
+		put_device(&priv->phy_dev->mdio.dev);
 		return -EPROBE_DEFER;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/plip/plip.c
+++ linux-ein-5.4.0/drivers/net/plip/plip.c
@@ -444,12 +444,12 @@
 	}
 	rcv->state = PLIP_PK_DONE;
 	if (rcv->skb) {
-		kfree_skb(rcv->skb);
+		dev_kfree_skb_irq(rcv->skb);
 		rcv->skb = NULL;
 	}
 	snd->state = PLIP_PK_DONE;
 	if (snd->skb) {
-		dev_kfree_skb(snd->skb);
+		dev_consume_skb_irq(snd->skb);
 		snd->skb = NULL;
 	}
 	spin_unlock_irq(&nl->lock);
@@ -1103,7 +1103,7 @@
 		/* Any address will do - we take the first. We already
 		   have the first two bytes filled with 0xfc, from
 		   plip_init_dev(). */
-		const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
+		const struct in_ifaddr *ifa = rtnl_dereference(in_dev->ifa_list);
 		if (ifa != NULL) {
 			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
 		}
--- linux-ein-5.4.0.orig/drivers/net/ppp/ppp_async.c
+++ linux-ein-5.4.0/drivers/net/ppp/ppp_async.c
@@ -470,6 +470,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;
@@ -874,15 +878,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-ein-5.4.0.orig/drivers/net/ppp/ppp_generic.c
+++ linux-ein-5.4.0/drivers/net/ppp/ppp_generic.c
@@ -69,6 +69,8 @@
 #define MPHDRLEN	6	/* multilink protocol header length */
 #define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
 
+#define PPP_PROTO_LEN	2
+
 /*
  * An instance of /dev/ppp can be associated with either a ppp
  * interface unit or a ppp channel.  In both cases, file->private_data
@@ -283,7 +285,7 @@
 static int ppp_connect_channel(struct channel *pch, int unit);
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
-static int unit_get(struct idr *p, void *ptr);
+static int unit_get(struct idr *p, void *ptr, int min);
 static int unit_set(struct idr *p, void *ptr, int n);
 static void unit_put(struct idr *p, int n);
 static void *unit_find(struct idr *p, int n);
@@ -498,6 +500,9 @@
 
 	if (!pf)
 		return -ENXIO;
+	/* All PPP packets should start with the 2-byte protocol */
+	if (count < PPP_PROTO_LEN)
+		return -EINVAL;
 	ret = -ENOMEM;
 	skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL);
 	if (!skb)
@@ -959,9 +964,20 @@
 	mutex_lock(&pn->all_ppp_mutex);
 
 	if (unit < 0) {
-		ret = unit_get(&pn->units_idr, ppp);
+		ret = unit_get(&pn->units_idr, ppp, 0);
 		if (ret < 0)
 			goto err;
+		if (!ifname_is_set) {
+			while (1) {
+				snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ret);
+				if (!__dev_get_by_name(ppp->ppp_net, ppp->dev->name))
+					break;
+				unit_put(&pn->units_idr, ret);
+				ret = unit_get(&pn->units_idr, ppp, ret + 1);
+				if (ret < 0)
+					goto err;
+			}
+		}
 	} else {
 		/* Caller asked for a specific unit number. Fail with -EEXIST
 		 * if unavailable. For backward compatibility, return -EEXIST
@@ -1110,7 +1126,7 @@
 	 * the PPP unit identifer as suffix (i.e. ppp<unit_id>). This allows
 	 * userspace to infer the device name using to the PPPIOCGUNIT ioctl.
 	 */
-	if (!tb[IFLA_IFNAME])
+	if (!tb[IFLA_IFNAME] || !nla_len(tb[IFLA_IFNAME]) || !*(char *)nla_data(tb[IFLA_IFNAME]))
 		conf.ifname_is_set = false;
 
 	err = ppp_dev_configure(src_net, dev, &conf);
@@ -1506,6 +1522,8 @@
 	int len;
 	unsigned char *cp;
 
+	skb->dev = ppp->dev;
+
 	if (proto < 0x8000) {
 #ifdef CONFIG_PPP_FILTER
 		/* check if we should pass this packet */
@@ -1533,7 +1551,7 @@
 	}
 
 	++ppp->stats64.tx_packets;
-	ppp->stats64.tx_bytes += skb->len - 2;
+	ppp->stats64.tx_bytes += skb->len - PPP_PROTO_LEN;
 
 	switch (proto) {
 	case PPP_IP:
@@ -3294,9 +3312,9 @@
 }
 
 /* get new free unit number and associate pointer with it */
-static int unit_get(struct idr *p, void *ptr)
+static int unit_get(struct idr *p, void *ptr, int min)
 {
-	return idr_alloc(p, ptr, 0, 0, GFP_KERNEL);
+	return idr_alloc(p, ptr, min, 0, GFP_KERNEL);
 }
 
 /* put unit number back to a pool */
--- linux-ein-5.4.0.orig/drivers/net/ppp/ppp_synctty.c
+++ linux-ein-5.4.0/drivers/net/ppp/ppp_synctty.c
@@ -463,6 +463,10 @@
 	case PPPIOCSMRU:
 		if (get_user(val, (int __user *) argp))
 			break;
+		if (val > U16_MAX) {
+			err = -EINVAL;
+			break;
+		}
 		if (val < PPP_MRU)
 			val = PPP_MRU;
 		ap->mru = val;
@@ -698,7 +702,7 @@
 
 	/* strip address/control field if present */
 	p = skb->data;
-	if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+	if (skb->len >= 2 && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
 		/* chop off address/control */
 		if (skb->len < 3)
 			goto err;
--- linux-ein-5.4.0.orig/drivers/net/ppp/pppoe.c
+++ linux-ein-5.4.0/drivers/net/ppp/pppoe.c
@@ -492,6 +492,9 @@
 	if (!skb)
 		goto out;
 
+	if (skb->pkt_type != PACKET_HOST)
+		goto abort;
+
 	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
 		goto abort;
 
--- linux-ein-5.4.0.orig/drivers/net/slip/slhc.c
+++ linux-ein-5.4.0/drivers/net/slip/slhc.c
@@ -232,7 +232,7 @@
 	struct cstate *cs = lcs->next;
 	unsigned long deltaS, deltaA;
 	short changes = 0;
-	int hlen;
+	int nlen, hlen;
 	unsigned char new_seq[16];
 	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
--- linux-ein-5.4.0.orig/drivers/net/slip/slip.c
+++ linux-ein-5.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 ?
@@ -855,7 +862,11 @@
 	sl->tty = NULL;
 	tty->disc_data = NULL;
 	clear_bit(SLF_INUSE, &sl->flags);
+	sl_free_netdev(sl->dev);
+	/* do not call free_netdev before rtnl_unlock */
+	rtnl_unlock();
 	free_netdev(sl->dev);
+	return err;
 
 err_exit:
 	rtnl_unlock();
@@ -881,10 +892,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-ein-5.4.0.orig/drivers/net/sungem_phy.c
+++ linux-ein-5.4.0/drivers/net/sungem_phy.c
@@ -454,6 +454,7 @@
 		int can_low_power = 1;
 		if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
 			can_low_power = 0;
+		of_node_put(np);
 		if (can_low_power) {
 			/* Enable automatic low-power */
 			sungem_phy_write(phy, 0x1c, 0x9002);
--- linux-ein-5.4.0.orig/drivers/net/tap.c
+++ linux-ein-5.4.0/drivers/net/tap.c
@@ -525,7 +525,7 @@
 	q->sock.state = SS_CONNECTED;
 	q->sock.file = file;
 	q->sock.ops = &tap_socket_ops;
-	sock_init_data(&q->sock, &q->sk);
+	sock_init_data_uid(&q->sock, &q->sk, current_fsuid());
 	q->sk.sk_write_space = tap_sock_write_space;
 	q->sk.sk_destruct = tap_sock_destruct;
 	q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
@@ -715,9 +715,8 @@
 	skb_probe_transport_header(skb);
 
 	/* Move network header to the right position for VLAN tagged packets */
-	if ((skb->protocol == htons(ETH_P_8021Q) ||
-	     skb->protocol == htons(ETH_P_8021AD)) &&
-	    __vlan_get_protocol(skb, skb->protocol, &depth) != 0)
+	if (eth_type_vlan(skb->protocol) &&
+	    vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
 		skb_set_network_header(skb, depth);
 
 	rcu_read_lock();
@@ -1095,10 +1094,9 @@
 			return -ENOLINK;
 		}
 		ret = 0;
-		u = tap->dev->type;
+		dev_get_mac_address(&sa, dev_net(tap->dev), tap->dev->name);
 		if (copy_to_user(&ifr->ifr_name, tap->dev->name, IFNAMSIZ) ||
-		    copy_to_user(&ifr->ifr_hwaddr.sa_data, tap->dev->dev_addr, ETH_ALEN) ||
-		    put_user(u, &ifr->ifr_hwaddr.sa_family))
+		    copy_to_user(&ifr->ifr_hwaddr, &sa, sizeof(sa)))
 			ret = -EFAULT;
 		tap_put_tap_dev(tap);
 		rtnl_unlock();
@@ -1113,7 +1111,7 @@
 			rtnl_unlock();
 			return -ENOLINK;
 		}
-		ret = dev_set_mac_address(tap->dev, &sa, NULL);
+		ret = dev_set_mac_address_user(tap->dev, &sa, NULL);
 		tap_put_tap_dev(tap);
 		rtnl_unlock();
 		return ret;
@@ -1178,9 +1176,8 @@
 	}
 
 	/* Move network header to the right position for VLAN tagged packets */
-	if ((skb->protocol == htons(ETH_P_8021Q) ||
-	     skb->protocol == htons(ETH_P_8021AD)) &&
-	    __vlan_get_protocol(skb, skb->protocol, &depth) != 0)
+	if (eth_type_vlan(skb->protocol) &&
+	    vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
 		skb_set_network_header(skb, depth);
 
 	rcu_read_lock();
@@ -1215,7 +1212,8 @@
 	struct xdp_buff *xdp;
 	int i;
 
-	if (ctl && (ctl->type == TUN_MSG_PTR)) {
+	if (m->msg_controllen == sizeof(struct tun_msg_ctl) &&
+	    ctl && ctl->type == TUN_MSG_PTR) {
 		for (i = 0; i < ctl->num; i++) {
 			xdp = &((struct xdp_buff *)ctl->ptr)[i];
 			tap_get_user_xdp(q, xdp);
--- linux-ein-5.4.0.orig/drivers/net/team/team.c
+++ linux-ein-5.4.0/drivers/net/team/team.c
@@ -284,10 +284,12 @@
 	return 0;
 
 inst_rollback:
-	for (i--; i >= 0; i--)
+	for (i--; i >= 0; i--) {
 		__team_option_inst_del_option(team, dst_opts[i]);
+		list_del(&dst_opts[i]->list);
+	}
 
-	i = option_count - 1;
+	i = option_count;
 alloc_rollback:
 	for (i--; i >= 0; i--)
 		kfree(dst_opts[i]);
@@ -468,6 +470,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) {
@@ -483,6 +488,7 @@
 	}
 
 	spin_unlock(&mode_list_lock);
+	module_put(THIS_MODULE);
 	return mode;
 }
 
@@ -987,7 +993,8 @@
 	unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
 					IFF_XMIT_DST_RELEASE_PERM;
 
-	list_for_each_entry(port, &team->port_list, list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
 		vlan_features = netdev_increment_features(vlan_features,
 					port->dev->vlan_features,
 					TEAM_VLAN_FEATURES);
@@ -1001,6 +1008,7 @@
 		if (port->dev->hard_header_len > max_hard_header_len)
 			max_hard_header_len = port->dev->hard_header_len;
 	}
+	rcu_read_unlock();
 
 	team->dev->vlan_features = vlan_features;
 	team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
@@ -1016,9 +1024,7 @@
 
 static void team_compute_features(struct team *team)
 {
-	mutex_lock(&team->lock);
 	__team_compute_features(team);
-	mutex_unlock(&team->lock);
 	netdev_change_features(team->dev);
 }
 
@@ -1266,10 +1272,12 @@
 		}
 	}
 
-	netif_addr_lock_bh(dev);
-	dev_uc_sync_multiple(port_dev, dev);
-	dev_mc_sync_multiple(port_dev, dev);
-	netif_addr_unlock_bh(dev);
+	if (dev->flags & IFF_UP) {
+		netif_addr_lock_bh(dev);
+		dev_uc_sync_multiple(port_dev, dev);
+		dev_mc_sync_multiple(port_dev, dev);
+		netif_addr_unlock_bh(dev);
+	}
 
 	port->index = -1;
 	list_add_tail_rcu(&port->list, &team->port_list);
@@ -1340,8 +1348,10 @@
 	netdev_rx_handler_unregister(port_dev);
 	team_port_disable_netpoll(port);
 	vlan_vids_del_by_dev(port_dev, dev);
-	dev_uc_unsync(port_dev, dev);
-	dev_mc_unsync(port_dev, dev);
+	if (dev->flags & IFF_UP) {
+		dev_uc_unsync(port_dev, dev);
+		dev_mc_unsync(port_dev, dev);
+	}
 	dev_close(port_dev);
 	team_port_leave(team, port);
 
@@ -1616,6 +1626,7 @@
 
 	team->dev = dev;
 	team_set_no_mode(team);
+	team->notifier_ctx = false;
 
 	team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats);
 	if (!team->pcpu_stats)
@@ -1690,6 +1701,14 @@
 
 static int team_close(struct net_device *dev)
 {
+	struct team *team = netdev_priv(dev);
+	struct team_port *port;
+
+	list_for_each_entry(port, &team->port_list, list) {
+		dev_uc_unsync(port->dev, dev);
+		dev_mc_unsync(port->dev, dev);
+	}
+
 	return 0;
 }
 
@@ -2074,7 +2093,8 @@
 	cmd->base.duplex = DUPLEX_UNKNOWN;
 	cmd->base.port = PORT_OTHER;
 
-	list_for_each_entry(port, &team->port_list, list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(port, &team->port_list, list) {
 		if (team_port_txable(port)) {
 			if (port->state.speed != SPEED_UNKNOWN)
 				speed += port->state.speed;
@@ -2083,6 +2103,8 @@
 				cmd->base.duplex = port->state.duplex;
 		}
 	}
+	rcu_read_unlock();
+
 	cmd->base.speed = speed ? : SPEED_UNKNOWN;
 
 	return 0;
@@ -2101,13 +2123,28 @@
 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);
 	eth_hw_addr_inherit(dev, port_dev);
+
+	if (port_dev->flags & IFF_POINTOPOINT) {
+		dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+		dev->flags |= (IFF_POINTOPOINT | IFF_NOARP);
+	} else if ((port_dev->flags & (IFF_BROADCAST | IFF_MULTICAST)) ==
+		    (IFF_BROADCAST | IFF_MULTICAST)) {
+		dev->flags |= (IFF_BROADCAST | IFF_MULTICAST);
+		dev->flags &= ~(IFF_POINTOPOINT | IFF_NOARP);
+	}
 }
 
 static int team_dev_type_check_change(struct net_device *dev,
@@ -2138,8 +2175,11 @@
 
 static void team_setup(struct net_device *dev)
 {
+	struct team *team = netdev_priv(dev);
+
 	ether_setup(dev);
 	dev->max_mtu = ETH_MAX_MTU;
+	team->header_ops_cache = dev->header_ops;
 
 	dev->netdev_ops = &team_netdev_ops;
 	dev->ethtool_ops = &team_ethtool_ops;
@@ -2164,7 +2204,9 @@
 
 	dev->hw_features = TEAM_VLAN_FEATURES |
 			   NETIF_F_HW_VLAN_CTAG_RX |
-			   NETIF_F_HW_VLAN_CTAG_FILTER;
+			   NETIF_F_HW_VLAN_CTAG_FILTER |
+			   NETIF_F_HW_VLAN_STAG_RX |
+			   NETIF_F_HW_VLAN_STAG_FILTER;
 
 	dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
 	dev->features |= dev->hw_features;
@@ -2237,6 +2279,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)
@@ -2993,7 +3037,11 @@
 		team_del_slave(port->team->dev, dev);
 		break;
 	case NETDEV_FEAT_CHANGE:
-		team_compute_features(port->team);
+		if (!port->team->notifier_ctx) {
+			port->team->notifier_ctx = true;
+			team_compute_features(port->team);
+			port->team->notifier_ctx = false;
+		}
 		break;
 	case NETDEV_PRECHANGEMTU:
 		/* Forbid to change mtu of underlaying device */
--- linux-ein-5.4.0.orig/drivers/net/thunderbolt.c
+++ linux-ein-5.4.0/drivers/net/thunderbolt.c
@@ -958,12 +958,11 @@
 		*tucso = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
 					    ip_hdr(skb)->daddr, 0,
 					    ip_hdr(skb)->protocol, 0);
-	} else if (skb_is_gso_v6(skb)) {
+	} else if (skb_is_gso(skb) && skb_is_gso_v6(skb)) {
 		tucso = dest + ((void *)&(tcp_hdr(skb)->check) - data);
 		*tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
 					  &ipv6_hdr(skb)->daddr, 0,
 					  IPPROTO_TCP, 0);
-		return false;
 	} else if (protocol == htons(ETH_P_IPV6)) {
 		tucso = dest + skb_checksum_start_offset(skb) + skb->csum_offset;
 		*tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -1339,12 +1338,21 @@
 				  TBNET_MATCH_FRAGS_ID);
 
 	ret = tb_register_property_dir("network", tbnet_dir);
-	if (ret) {
-		tb_property_free_dir(tbnet_dir);
-		return ret;
-	}
+	if (ret)
+		goto err_free_dir;
+
+	ret = tb_register_service_driver(&tbnet_driver);
+	if (ret)
+		goto err_unregister;
+
+	return 0;
+
+err_unregister:
+	tb_unregister_property_dir("network", tbnet_dir);
+err_free_dir:
+	tb_property_free_dir(tbnet_dir);
 
-	return tb_register_service_driver(&tbnet_driver);
+	return ret;
 }
 module_init(tbnet_init);
 
--- linux-ein-5.4.0.orig/drivers/net/tun.c
+++ linux-ein-5.4.0/drivers/net/tun.c
@@ -68,6 +68,14 @@
 #include <linux/bpf.h>
 #include <linux/bpf_trace.h>
 #include <linux/mutex.h>
+#include <linux/ieee802154.h>
+#include <linux/if_ltalk.h>
+#include <uapi/linux/if_fddi.h>
+#include <uapi/linux/if_hippi.h>
+#include <uapi/linux/if_fc.h>
+#include <net/ax25.h>
+#include <net/rose.h>
+#include <net/6lowpan.h>
 
 #include <linux/uaccess.h>
 #include <linux/proc_fs.h>
@@ -242,6 +250,9 @@
 	struct tun_prog __rcu *steering_prog;
 	struct tun_prog __rcu *filter_prog;
 	struct ethtool_link_ksettings link_ksettings;
+	/* init args */
+	struct file *file;
+	struct ifreq *ifr;
 };
 
 struct veth {
@@ -267,6 +278,9 @@
 }
 EXPORT_SYMBOL(tun_ptr_to_xdp);
 
+static void tun_flow_init(struct tun_struct *tun);
+static void tun_flow_uninit(struct tun_struct *tun);
+
 static int tun_napi_receive(struct napi_struct *napi, int budget)
 {
 	struct tun_file *tfile = container_of(napi, struct tun_file, napi);
@@ -313,12 +327,18 @@
 	tfile->napi_enabled = napi_en;
 	tfile->napi_frags_enabled = napi_en && napi_frags;
 	if (napi_en) {
-		netif_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
-			       NAPI_POLL_WEIGHT);
+		netif_tx_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
+				  NAPI_POLL_WEIGHT);
 		napi_enable(&tfile->napi);
 	}
 }
 
+static void tun_napi_enable(struct tun_file *tfile)
+{
+	if (tfile->napi_enabled)
+		napi_enable(&tfile->napi);
+}
+
 static void tun_napi_disable(struct tun_file *tfile)
 {
 	if (tfile->napi_enabled)
@@ -682,7 +702,8 @@
 	tun = rtnl_dereference(tfile->tun);
 
 	if (tun && clean) {
-		tun_napi_disable(tfile);
+		if (!tfile->detached)
+			tun_napi_disable(tfile);
 		tun_napi_del(tfile);
 	}
 
@@ -694,6 +715,7 @@
 				   tun->tfiles[tun->numqueues - 1]);
 		ntfile = rtnl_dereference(tun->tfiles[index]);
 		ntfile->queue_index = index;
+		ntfile->xdp_rxq.queue_index = index;
 		rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
 				   NULL);
 
@@ -701,8 +723,10 @@
 		if (clean) {
 			RCU_INIT_POINTER(tfile->tun, NULL);
 			sock_put(&tfile->sk);
-		} else
+		} else {
 			tun_disable_queue(tun, tfile);
+			tun_napi_disable(tfile);
+		}
 
 		synchronize_net();
 		tun_flow_delete_by_queue(tun, tun->numqueues + 1);
@@ -725,7 +749,6 @@
 		if (tun)
 			xdp_rxq_info_unreg(&tfile->xdp_rxq);
 		ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free);
-		sock_put(&tfile->sk);
 	}
 }
 
@@ -741,6 +764,9 @@
 	if (dev)
 		netdev_state_change(dev);
 	rtnl_unlock();
+
+	if (clean)
+		sock_put(&tfile->sk);
 }
 
 static void tun_detach_all(struct net_device *dev)
@@ -775,6 +801,7 @@
 		sock_put(&tfile->sk);
 	}
 	list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
+		tun_napi_del(tfile);
 		tun_enable_queue(tfile);
 		tun_queue_purge(tfile);
 		xdp_rxq_info_unreg(&tfile->xdp_rxq);
@@ -855,6 +882,7 @@
 
 	if (tfile->detached) {
 		tun_enable_queue(tfile);
+		tun_napi_enable(tfile);
 	} else {
 		sock_hold(&tfile->sk);
 		tun_napi_init(tun, tfile, napi, napi_frags);
@@ -1006,6 +1034,49 @@
 
 static const struct ethtool_ops tun_ethtool_ops;
 
+static int tun_net_init(struct net_device *dev)
+{
+	struct tun_struct *tun = netdev_priv(dev);
+	struct ifreq *ifr = tun->ifr;
+	int err;
+
+	tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
+	if (!tun->pcpu_stats)
+		return -ENOMEM;
+
+	spin_lock_init(&tun->lock);
+
+	err = security_tun_dev_alloc_security(&tun->security);
+	if (err < 0) {
+		free_percpu(tun->pcpu_stats);
+		return err;
+	}
+
+	tun_flow_init(tun);
+
+	dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
+			   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
+			   NETIF_F_HW_VLAN_STAG_TX;
+	dev->features = dev->hw_features | NETIF_F_LLTX;
+	dev->vlan_features = dev->features &
+			     ~(NETIF_F_HW_VLAN_CTAG_TX |
+			       NETIF_F_HW_VLAN_STAG_TX);
+
+	tun->flags = (tun->flags & ~TUN_FEATURES) |
+		      (ifr->ifr_flags & TUN_FEATURES);
+
+	INIT_LIST_HEAD(&tun->disabled);
+	err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI,
+			 ifr->ifr_flags & IFF_NAPI_FRAGS, false);
+	if (err < 0) {
+		tun_flow_uninit(tun);
+		security_tun_dev_free_security(tun->security);
+		free_percpu(tun->pcpu_stats);
+		return err;
+	}
+	return 0;
+}
+
 /* Net device detach from fd. */
 static void tun_net_uninit(struct net_device *dev)
 {
@@ -1063,6 +1134,7 @@
 {
 	struct tun_struct *tun = netdev_priv(dev);
 	int txq = skb->queue_mapping;
+	struct netdev_queue *queue;
 	struct tun_file *tfile;
 	int len = skb->len;
 
@@ -1109,6 +1181,10 @@
 	if (ptr_ring_produce(&tfile->tx_ring, skb))
 		goto drop;
 
+	/* NETIF_F_LLTX requires to do our own update of trans_start */
+	queue = netdev_get_tx_queue(dev, txq);
+	queue->trans_start = jiffies;
+
 	/* Notify and wake up reader process */
 	if (tfile->flags & TUN_FASYNC)
 		kill_fasync(&tfile->fasync, SIGIO, POLL_IN);
@@ -1259,6 +1335,7 @@
 }
 
 static const struct net_device_ops tun_netdev_ops = {
+	.ndo_init		= tun_net_init,
 	.ndo_uninit		= tun_net_uninit,
 	.ndo_open		= tun_net_open,
 	.ndo_stop		= tun_net_close,
@@ -1339,6 +1416,7 @@
 }
 
 static const struct net_device_ops tap_netdev_ops = {
+	.ndo_init		= tun_net_init,
 	.ndo_uninit		= tun_net_uninit,
 	.ndo_open		= tun_net_open,
 	.ndo_stop		= tun_net_close,
@@ -1379,7 +1457,7 @@
 #define MAX_MTU 65535
 
 /* Initialize net device. */
-static void tun_net_init(struct net_device *dev)
+static void tun_net_initialize(struct net_device *dev)
 {
 	struct tun_struct *tun = netdev_priv(dev);
 
@@ -1468,8 +1546,9 @@
 	int err;
 	int i;
 
-	if (it->nr_segs > MAX_SKB_FRAGS + 1)
-		return ERR_PTR(-ENOMEM);
+	if (it->nr_segs > MAX_SKB_FRAGS + 1 ||
+	    len > (ETH_MAX_MTU - NET_SKB_PAD - NET_IP_ALIGN))
+		return ERR_PTR(-EMSGSIZE);
 
 	local_bh_disable();
 	skb = napi_get_frags(&tfile->napi);
@@ -1594,7 +1673,7 @@
 	if (zerocopy)
 		return false;
 
-	if (SKB_DATA_ALIGN(len + TUN_RX_PAD) +
+	if (SKB_DATA_ALIGN(len + TUN_RX_PAD + XDP_PACKET_HEADROOM) +
 	    SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE)
 		return false;
 
@@ -1715,8 +1794,12 @@
 			alloc_frag->offset += buflen;
 		}
 		err = tun_xdp_act(tun, xdp_prog, &xdp, act);
-		if (err < 0)
-			goto err_xdp;
+		if (err < 0) {
+			if (act == XDP_REDIRECT || act == XDP_TX)
+				put_page(alloc_frag->page);
+			goto out;
+		}
+
 		if (err == XDP_REDIRECT)
 			xdp_do_flush_map();
 		if (err != XDP_PASS)
@@ -1730,8 +1813,6 @@
 
 	return __tun_build_skb(tfile, alloc_frag, buf, buflen, len, pad);
 
-err_xdp:
-	put_page(alloc_frag->page);
 out:
 	rcu_read_unlock();
 	local_bh_enable();
@@ -1906,8 +1987,11 @@
 		skb->dev = tun->dev;
 		break;
 	case IFF_TAP:
-		if (!frags)
-			skb->protocol = eth_type_trans(skb, tun->dev);
+		if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
+			err = -ENOMEM;
+			goto drop;
+		}
+		skb->protocol = eth_type_trans(skb, tun->dev);
 		break;
 	}
 
@@ -1923,6 +2007,7 @@
 
 	skb_reset_network_header(skb);
 	skb_probe_transport_header(skb);
+	skb_record_rx_queue(skb, tfile->queue_index);
 
 	if (skb_xdp) {
 		struct bpf_prog *xdp_prog;
@@ -1936,6 +2021,10 @@
 			if (ret != XDP_PASS) {
 				rcu_read_unlock();
 				local_bh_enable();
+				if (frags) {
+					tfile->napi.skb = NULL;
+					mutex_unlock(&tfile->napi_mutex);
+				}
 				return total_len;
 			}
 		}
@@ -1959,22 +2048,33 @@
 	}
 
 	if (frags) {
+		u32 headlen;
+
 		/* Exercise flow dissector code path. */
-		u32 headlen = eth_get_headlen(tun->dev, skb->data,
-					      skb_headlen(skb));
+		skb_push(skb, ETH_HLEN);
+		headlen = eth_get_headlen(tun->dev, skb->data,
+					  skb_headlen(skb));
 
 		if (unlikely(headlen > skb_headlen(skb))) {
+			WARN_ON_ONCE(1);
+			err = -ENOMEM;
 			this_cpu_inc(tun->pcpu_stats->rx_dropped);
+napi_busy:
 			napi_free_frags(&tfile->napi);
 			rcu_read_unlock();
 			mutex_unlock(&tfile->napi_mutex);
-			WARN_ON(1);
-			return -ENOMEM;
+			return err;
 		}
 
-		local_bh_disable();
-		napi_gro_frags(&tfile->napi);
-		local_bh_enable();
+		if (likely(napi_schedule_prep(&tfile->napi))) {
+			local_bh_disable();
+			napi_gro_frags(&tfile->napi);
+			napi_complete(&tfile->napi);
+			local_bh_enable();
+		} else {
+			err = -EBUSY;
+			goto napi_busy;
+		}
 		mutex_unlock(&tfile->napi_mutex);
 	} else if (tfile->napi_enabled) {
 		struct sk_buff_head *queue = &tfile->sk.sk_write_queue;
@@ -2015,12 +2115,15 @@
 	struct tun_file *tfile = file->private_data;
 	struct tun_struct *tun = tun_get(tfile);
 	ssize_t result;
+	int noblock = 0;
 
 	if (!tun)
 		return -EBADFD;
 
-	result = tun_get_user(tun, tfile, NULL, from,
-			      file->f_flags & O_NONBLOCK, false);
+	if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT))
+		noblock = 1;
+
+	result = tun_get_user(tun, tfile, NULL, from, noblock, false);
 
 	tun_put(tun);
 	return result;
@@ -2241,10 +2344,15 @@
 	struct tun_file *tfile = file->private_data;
 	struct tun_struct *tun = tun_get(tfile);
 	ssize_t len = iov_iter_count(to), ret;
+	int noblock = 0;
 
 	if (!tun)
 		return -EBADFD;
-	ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL);
+
+	if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT))
+		noblock = 1;
+
+	ret = tun_do_read(tun, tfile, to, noblock, NULL);
 	ret = min_t(ssize_t, ret, len);
 	if (ret > 0)
 		iocb->ki_pos = ret;
@@ -2486,6 +2594,7 @@
 	skb->protocol = eth_type_trans(skb, tun->dev);
 	skb_reset_network_header(skb);
 	skb_probe_transport_header(skb);
+	skb_record_rx_queue(skb, tfile->queue_index);
 
 	if (skb_xdp) {
 		err = do_xdp_generic(xdp_prog, skb);
@@ -2497,7 +2606,6 @@
 	    !tfile->detached)
 		rxhash = __skb_get_hash_symmetric(skb);
 
-	skb_record_rx_queue(skb, tfile->queue_index);
 	netif_receive_skb(skb);
 
 	/* No need for get_cpu_ptr() here since this function is
@@ -2527,7 +2635,8 @@
 	if (!tun)
 		return -EBADFD;
 
-	if (ctl && (ctl->type == TUN_MSG_PTR)) {
+	if (m->msg_controllen == sizeof(struct tun_msg_ctl) &&
+	    ctl && ctl->type == TUN_MSG_PTR) {
 		struct tun_page tpage;
 		int n = ctl->num;
 		int flush = 0;
@@ -2782,9 +2891,6 @@
 
 		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;
@@ -2803,41 +2909,16 @@
 		tun->rx_batched = 0;
 		RCU_INIT_POINTER(tun->steering_prog, NULL);
 
-		tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
-		if (!tun->pcpu_stats) {
-			err = -ENOMEM;
-			goto err_free_dev;
-		}
+		tun->ifr = ifr;
+		tun->file = file;
 
-		spin_lock_init(&tun->lock);
-
-		err = security_tun_dev_alloc_security(&tun->security);
-		if (err < 0)
-			goto err_free_stat;
-
-		tun_net_init(dev);
-		tun_flow_init(tun);
-
-		dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
-				   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
-				   NETIF_F_HW_VLAN_STAG_TX;
-		dev->features = dev->hw_features | NETIF_F_LLTX;
-		dev->vlan_features = dev->features &
-				     ~(NETIF_F_HW_VLAN_CTAG_TX |
-				       NETIF_F_HW_VLAN_STAG_TX);
-
-		tun->flags = (tun->flags & ~TUN_FEATURES) |
-			      (ifr->ifr_flags & TUN_FEATURES);
-
-		INIT_LIST_HEAD(&tun->disabled);
-		err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
-				 ifr->ifr_flags & IFF_NAPI_FRAGS, false);
-		if (err < 0)
-			goto err_free_flow;
+		tun_net_initialize(dev);
 
 		err = register_netdevice(tun->dev);
-		if (err < 0)
-			goto err_detach;
+		if (err < 0) {
+			free_netdev(dev);
+			return err;
+		}
 		/* free_netdev() won't check refcnt, to aovid race
 		 * with dev_put() we need publish tun after registration.
 		 */
@@ -2856,20 +2937,6 @@
 
 	strcpy(ifr->ifr_name, tun->dev->name);
 	return 0;
-
-err_detach:
-	tun_detach_all(dev);
-	/* register_netdevice() already called tun_free_netdev() */
-	goto err_free_dev;
-
-err_free_flow:
-	tun_flow_uninit(tun);
-	security_tun_dev_free_security(tun->security);
-err_free_stat:
-	free_percpu(tun->pcpu_stats);
-err_free_dev:
-	free_netdev(dev);
-	return err;
 }
 
 static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)
@@ -3022,6 +3089,45 @@
 	return __tun_set_ebpf(tun, prog_p, prog);
 }
 
+/* Return correct value for tun->dev->addr_len based on tun->dev->type. */
+static unsigned char tun_get_addr_len(unsigned short type)
+{
+	switch (type) {
+	case ARPHRD_IP6GRE:
+	case ARPHRD_TUNNEL6:
+		return sizeof(struct in6_addr);
+	case ARPHRD_IPGRE:
+	case ARPHRD_TUNNEL:
+	case ARPHRD_SIT:
+		return 4;
+	case ARPHRD_ETHER:
+		return ETH_ALEN;
+	case ARPHRD_IEEE802154:
+	case ARPHRD_IEEE802154_MONITOR:
+		return IEEE802154_EXTENDED_ADDR_LEN;
+	case ARPHRD_PHONET_PIPE:
+	case ARPHRD_PPP:
+	case ARPHRD_NONE:
+		return 0;
+	case ARPHRD_6LOWPAN:
+		return EUI64_ADDR_LEN;
+	case ARPHRD_FDDI:
+		return FDDI_K_ALEN;
+	case ARPHRD_HIPPI:
+		return HIPPI_ALEN;
+	case ARPHRD_IEEE802:
+		return FC_ALEN;
+	case ARPHRD_ROSE:
+		return ROSE_ADDR_LEN;
+	case ARPHRD_NETROM:
+		return AX25_ADDR_LEN;
+	case ARPHRD_LOCALTLK:
+		return LTALK_ALEN;
+	default:
+		return 0;
+	}
+}
+
 static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 			    unsigned long arg, int ifreq_len)
 {
@@ -3029,10 +3135,11 @@
 	struct net *net = sock_net(&tfile->sk);
 	struct tun_struct *tun;
 	void __user* argp = (void __user*)arg;
-	unsigned int ifindex, carrier;
+	unsigned int carrier;
 	struct ifreq ifr;
 	kuid_t owner;
 	kgid_t group;
+	int ifindex;
 	int sndbuf;
 	int vnet_hdr_sz;
 	int le;
@@ -3089,7 +3196,9 @@
 		ret = -EFAULT;
 		if (copy_from_user(&ifindex, argp, sizeof(ifindex)))
 			goto unlock;
-
+		ret = -EINVAL;
+		if (ifindex < 0)
+			goto unlock;
 		ret = 0;
 		tfile->ifindex = ifindex;
 		goto unlock;
@@ -3177,6 +3286,7 @@
 			ret = -EBUSY;
 		} else {
 			tun->dev->type = (int) arg;
+			tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
 			tun_debug(KERN_INFO, tun, "linktype set to %d\n",
 				  tun->dev->type);
 			ret = 0;
@@ -3203,7 +3313,7 @@
 	case SIOCGIFHWADDR:
 		/* Get hw address */
 		memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
-		ifr.ifr_hwaddr.sa_family = tun->dev->type;
+		dev_get_mac_address(&ifr.ifr_hwaddr, net, tun->dev->name);
 		if (copy_to_user(argp, &ifr, ifreq_len))
 			ret = -EFAULT;
 		break;
@@ -3213,7 +3323,7 @@
 		tun_debug(KERN_DEBUG, tun, "set hw address: %pM\n",
 			  ifr.ifr_hwaddr.sa_data);
 
-		ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr, NULL);
+		ret = dev_set_mac_address_user(tun->dev, &ifr.ifr_hwaddr, NULL);
 		break;
 
 	case TUNGETSNDBUF:
@@ -3428,7 +3538,7 @@
 	tfile->socket.file = file;
 	tfile->socket.ops = &tun_socket_ops;
 
-	sock_init_data(&tfile->socket, &tfile->sk);
+	sock_init_data_uid(&tfile->socket, &tfile->sk, current_fsuid());
 
 	tfile->sk.sk_write_space = tun_sock_write_space;
 	tfile->sk.sk_sndbuf = INT_MAX;
--- linux-ein-5.4.0.orig/drivers/net/usb/Kconfig
+++ linux-ein-5.4.0/drivers/net/usb/Kconfig
@@ -99,6 +99,10 @@
 config USB_RTL8152
 	tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 	select MII
+	select CRC32
+	select CRYPTO
+	select CRYPTO_HASH
+	select CRYPTO_SHA256
 	help
 	  This option adds support for Realtek RTL8152 based USB 2.0
 	  10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000
@@ -113,6 +117,7 @@
 	select PHYLIB
 	select MICROCHIP_PHY
 	select FIXED_PHY
+	select CRC32
 	help
 	  This option adds support for Microchip LAN78XX based USB 2
 	  & USB 3 10/100/1000 Ethernet adapters.
--- linux-ein-5.4.0.orig/drivers/net/usb/aqc111.c
+++ linux-ein-5.4.0/drivers/net/usb/aqc111.c
@@ -1079,17 +1079,17 @@
 	u16 pkt_count = 0;
 	u64 desc_hdr = 0;
 	u16 vlan_tag = 0;
-	u32 skb_len = 0;
+	u32 skb_len;
 
 	if (!skb)
 		goto err;
 
-	if (skb->len == 0)
+	skb_len = skb->len;
+	if (skb_len < sizeof(desc_hdr))
 		goto err;
 
-	skb_len = skb->len;
 	/* RX Descriptor Header */
-	skb_trim(skb, skb->len - sizeof(desc_hdr));
+	skb_trim(skb, skb_len - sizeof(desc_hdr));
 	desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb));
 
 	/* Check these packets */
@@ -1102,10 +1102,15 @@
 	if (start_of_descs != desc_offset)
 		goto err;
 
-	/* self check desc_offset from header*/
-	if (desc_offset >= skb_len)
+	/* self check desc_offset from header and make sure that the
+	 * bounds of the metadata array are inside the SKB
+	 */
+	if (pkt_count * 2 + desc_offset >= skb_len)
 		goto err;
 
+	/* Packets must not overlap the metadata array */
+	skb_trim(skb, desc_offset);
+
 	if (pkt_count == 0)
 		goto err;
 
--- linux-ein-5.4.0.orig/drivers/net/usb/asix_common.c
+++ linux-ein-5.4.0/drivers/net/usb/asix_common.c
@@ -296,7 +296,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;
 	}
--- linux-ein-5.4.0.orig/drivers/net/usb/ax88172a.c
+++ linux-ein-5.4.0/drivers/net/usb/ax88172a.c
@@ -186,7 +186,9 @@
 	u8 buf[ETH_ALEN];
 	struct ax88172a_private *priv;
 
-	usbnet_get_endpoints(dev, intf);
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		return ret;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -198,6 +200,7 @@
 	ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 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-ein-5.4.0.orig/drivers/net/usb/ax88179_178a.c
+++ linux-ein-5.4.0/drivers/net/usb/ax88179_178a.c
@@ -295,12 +295,12 @@
 	int ret;
 
 	if (2 == size) {
-		u16 buf;
+		u16 buf = 0;
 		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
 		le16_to_cpus(&buf);
 		*((u16 *)data) = buf;
 	} else if (4 == size) {
-		u32 buf;
+		u32 buf = 0;
 		ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
 		le32_to_cpus(&buf);
 		*((u32 *)data) = buf;
@@ -1361,57 +1361,119 @@
 	u16 hdr_off;
 	u32 *pkt_hdr;
 
-	/* This check is no longer done by usbnet */
-	if (skb->len < dev->net->hard_header_len)
-		return 0;
+	/* 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).
+	 */
+
+	/* SKB contents for current firmware:
+	 *   <packet 1> <padding>
+	 *   ...
+	 *   <packet N> <padding>
+	 *   <per-packet metadata entry 1> <dummy header>
+	 *   ...
+	 *   <per-packet metadata entry N> <dummy header>
+	 *   <padding2> <rx_hdr>
+	 *
+	 * where:
+	 *   <packet N> contains pkt_len bytes:
+	 *		2 bytes of IP alignment pseudo header
+	 *		packet received
+	 *   <per-packet metadata entry N> contains 4 bytes:
+	 *		pkt_len and fields AX_RXHDR_*
+	 *   <padding>	0-7 bytes to terminate at
+	 *		8 bytes boundary (64-bit).
+	 *   <padding2> 4 bytes to make rx_hdr terminate at
+	 *		8 bytes boundary (64-bit)
+	 *   <dummy-header> contains 4 bytes:
+	 *		pkt_len=0 and AX_RXHDR_DROP_ERR
+	 *   <rx-hdr>	contains 4 bytes:
+	 *		pkt_cnt and hdr_off (offset of
+	 *		  <per-packet metadata entry 1>)
+	 *
+	 * pkt_cnt is number of entrys in the per-packet metadata.
+	 * In current firmware there is 2 entrys per packet.
+	 * The first points to the packet and the
+	 *  second is a dummy header.
+	 * This was done probably to align fields in 64-bit and
+	 *  maintain compatibility with old firmware.
+	 * This code assumes that <dummy header> and <padding2> are
+	 *  optional.
+	 */
 
+	if (skb->len < 4)
+		return 0;
 	skb_trim(skb, skb->len - 4);
 	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 * 4 + 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 > 0; pkt_cnt--, pkt_hdr++) {
+		u16 pkt_len_plus_padd;
 		u16 pkt_len;
 
 		le32_to_cpus(pkt_hdr);
 		pkt_len = (*pkt_hdr >> 16) & 0x1fff;
+		pkt_len_plus_padd = (pkt_len + 7) & 0xfff8;
+
+		/* Skip dummy header used for alignment
+		 */
+		if (pkt_len == 0)
+			continue;
+
+		if (pkt_len_plus_padd > skb->len)
+			return 0;
 
 		/* 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++;
+		if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) ||
+		    pkt_len < 2 + ETH_HLEN) {
+			dev->net->stats.rx_errors++;
+			skb_pull(skb, pkt_len_plus_padd);
 			continue;
 		}
 
-		if (pkt_cnt == 0) {
-			/* Skip IP alignment psudo header */
+		/* last packet */
+		if (pkt_len_plus_padd == skb->len) {
+			skb_trim(skb, pkt_len);
+
+			/* Skip IP alignment pseudo header */
 			skb_pull(skb, 2);
-			skb->len = pkt_len;
-			skb_set_tail_pointer(skb, pkt_len);
-			skb->truesize = pkt_len + sizeof(struct sk_buff);
+
+			skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd);
 			ax88179_rx_checksum(skb, pkt_hdr);
 			return 1;
 		}
 
 		ax_skb = skb_clone(skb, GFP_ATOMIC);
-		if (ax_skb) {
-			ax_skb->len = pkt_len;
-			ax_skb->data = skb->data + 2;
-			skb_set_tail_pointer(ax_skb, pkt_len);
-			ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
-			ax88179_rx_checksum(ax_skb, pkt_hdr);
-			usbnet_skb_return(dev, ax_skb);
-		} else {
+		if (!ax_skb)
 			return 0;
-		}
+		skb_trim(ax_skb, pkt_len);
+
+		/* Skip IP alignment pseudo header */
+		skb_pull(ax_skb, 2);
 
-		skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-		pkt_hdr++;
+		skb->truesize = pkt_len_plus_padd +
+				SKB_DATA_ALIGN(sizeof(struct sk_buff));
+		ax88179_rx_checksum(ax_skb, pkt_hdr);
+		usbnet_skb_return(dev, ax_skb);
+
+		skb_pull(skb, pkt_len_plus_padd);
 	}
-	return 1;
+
+	return 0;
 }
 
 static struct sk_buff *
@@ -1532,11 +1594,11 @@
 
 	*tmp16 = AX_PHYPWR_RSTCTL_IPRL;
 	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
-	msleep(200);
+	msleep(500);
 
 	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
 	ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
-	msleep(100);
+	msleep(200);
 
 	/* Ethernet PHY Auto Detach*/
 	ax88179_auto_detach(dev, 0);
@@ -1718,6 +1780,7 @@
 	.status = ax88179_status,
 	.link_reset = ax88179_link_reset,
 	.reset	= ax88179_reset,
+	.stop	= ax88179_stop,
 	.flags	= FLAG_ETHER | FLAG_FRAMING_AX,
 	.rx_fixup = ax88179_rx_fixup,
 	.tx_fixup = ax88179_tx_fixup,
--- linux-ein-5.4.0.orig/drivers/net/usb/cdc-phonet.c
+++ linux-ein-5.4.0/drivers/net/usb/cdc-phonet.c
@@ -387,6 +387,8 @@
 
 	err = register_netdev(dev);
 	if (err) {
+		/* Set disconnected flag so that disconnect() returns early. */
+		pnd->disconnected = 1;
 		usb_driver_release_interface(&usbpn_driver, data_intf);
 		goto out;
 	}
--- linux-ein-5.4.0.orig/drivers/net/usb/cdc_eem.c
+++ linux-ein-5.4.0/drivers/net/usb/cdc_eem.c
@@ -123,10 +123,10 @@
 	}
 
 	skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
+	dev_kfree_skb_any(skb);
 	if (!skb2)
 		return NULL;
 
-	dev_kfree_skb_any(skb);
 	skb = skb2;
 
 done:
--- linux-ein-5.4.0.orig/drivers/net/usb/cdc_ether.c
+++ linux-ein-5.4.0/drivers/net/usb/cdc_ether.c
@@ -571,6 +571,11 @@
 	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
 	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
 
+#define ZAURUS_FAKE_INTERFACE \
+	.bInterfaceClass	= USB_CLASS_COMM, \
+	.bInterfaceSubClass	= USB_CDC_SUBCLASS_MDLM, \
+	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
+
 /* SA-1100 based Sharp Zaurus ("collie"), or compatible;
  * wire-incompatible with true CDC Ethernet implementations.
  * (And, it seems, needlessly so...)
@@ -600,6 +605,13 @@
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,   /* A-300 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info        = 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
 	.idProduct		= 0x8006,	/* B-500/SL-5600 */
 	ZAURUS_MASTER_INTERFACE,
 	.driver_info		= 0,
@@ -607,11 +619,25 @@
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,   /* B-500/SL-5600 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info        = 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
 	.idProduct		= 0x8007,	/* C-700 */
 	ZAURUS_MASTER_INTERFACE,
 	.driver_info		= 0,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8007,   /* C-700 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info        = 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	.idProduct              = 0x9031,	/* C-750 C-760 */
@@ -628,6 +654,13 @@
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
+	.idProduct              = 0x9032,	/* SL-6000 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
 	/* reported with some C860 units */
 	.idProduct              = 0x9050,	/* C-860 */
 	ZAURUS_MASTER_INTERFACE,
@@ -752,6 +785,13 @@
 },
 #endif
 
+/* Lenovo ThinkPad OneLink+ Dock (based on Realtek RTL8153) */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3054, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
 /* ThinkPad USB-C Dock (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3062, USB_CLASS_COMM,
@@ -766,6 +806,13 @@
 	.driver_info = 0,
 },
 
+/* ThinkPad Thunderbolt 3 Dock Gen 2 (based on Realtek RTL8153) */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3082, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
 /* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
@@ -787,6 +834,13 @@
 	.driver_info = 0,
 },
 
+/* Lenovo Powered USB-C Travel Hub (4X90S92381, based on Realtek RTL8153) */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x721e, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
 /* ThinkPad USB-C Dock Gen 2 (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0xa387, USB_CLASS_COMM,
@@ -808,14 +862,21 @@
 	.driver_info = 0,
 },
 
-/* Microsoft Surface 3 dock (based on Realtek RTL8153) */
+/* Microsoft Surface Ethernet Adapter (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x07c6, USB_CLASS_COMM,
 			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
 	.driver_info = 0,
 },
 
-	/* TP-LINK UE300 USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+/* Microsoft Surface Ethernet Adapter (based on Realtek RTL8153B) */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x0927, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
+/* TP-LINK UE300 USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
 {
 	USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, 0x0601, USB_CLASS_COMM,
 			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
@@ -948,6 +1009,18 @@
 				      USB_CDC_SUBCLASS_ETHERNET,
 				      USB_CDC_PROTO_NONE),
 	.driver_info = (unsigned long)&wwan_info,
+}, {
+	/* Cinterion PLS82/PLS62 modem by GEMALTO/THALES */
+	USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x005b, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET,
+				      USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long)&wwan_info,
+}, {
+	/* Cinterion PLS83/PLS63 modem by GEMALTO/THALES */
+	USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0069, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET,
+				      USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long)&wwan_info,
 }, {
 	USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
 			USB_CDC_PROTO_NONE),
--- linux-ein-5.4.0.orig/drivers/net/usb/cdc_mbim.c
+++ linux-ein-5.4.0/drivers/net/usb/cdc_mbim.c
@@ -653,6 +653,21 @@
 	  .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
 	},
 
+	/* Telit LN920 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1061, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+	  .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+	},
+
+	/* Telit FN990 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1071, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+	  .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+	},
+
+	/* Telit FE990 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1081, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+	  .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+	},
+
 	/* 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-ein-5.4.0.orig/drivers/net/usb/cdc_ncm.c
+++ linux-ein-5.4.0/drivers/net/usb/cdc_ncm.c
@@ -175,8 +175,17 @@
 	u32 val, max, min;
 
 	/* clamp new_tx to sane values */
-	min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
-	max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
+	if (ctx->is_ndp16)
+		min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
+	else
+		min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32);
+
+	if (le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) == 0)
+		max = CDC_NCM_NTB_MAX_SIZE_TX; /* dwNtbOutMaxSize not set */
+	else
+		max = clamp_t(u32, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize),
+			      USB_CDC_NCM_NTB_MIN_OUT_SIZE,
+			      CDC_NCM_NTB_MAX_SIZE_TX);
 
 	/* some devices set dwNtbOutMaxSize too low for the above default */
 	min = min(min, max);
@@ -307,10 +316,17 @@
 	if (enable == (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
 		return len;
 
-	if (enable && !ctx->delayed_ndp16) {
-		ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
-		if (!ctx->delayed_ndp16)
-			return -ENOMEM;
+	if (enable) {
+		if (ctx->is_ndp16 && !ctx->delayed_ndp16) {
+			ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+			if (!ctx->delayed_ndp16)
+				return -ENOMEM;
+		}
+		if (!ctx->is_ndp16 && !ctx->delayed_ndp32) {
+			ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+			if (!ctx->delayed_ndp32)
+				return -ENOMEM;
+		}
 	}
 
 	/* flush pending data before changing flag */
@@ -512,6 +528,9 @@
 			dev_err(&dev->intf->dev, "SET_CRC_MODE failed\n");
 	}
 
+	/* use ndp16 by default */
+	ctx->is_ndp16 = 1;
+
 	/* set NTB format, if both formats are supported.
 	 *
 	 * "The host shall only send this command while the NCM Data
@@ -519,14 +538,27 @@
 	 */
 	if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) &
 						USB_CDC_NCM_NTB32_SUPPORTED) {
-		dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n");
-		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)
+		if (ctx->drvflags & CDC_NCM_FLAG_PREFER_NTB32) {
+			ctx->is_ndp16 = 0;
+			dev_dbg(&dev->intf->dev, "Setting NTB format to 32-bit\n");
+			err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
+					       USB_TYPE_CLASS | USB_DIR_OUT
+					       | USB_RECIP_INTERFACE,
+					       USB_CDC_NCM_NTB32_FORMAT,
+					       iface_no, NULL, 0);
+		} else {
+			ctx->is_ndp16 = 1;
+			dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n");
+			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) {
+			ctx->is_ndp16 = 1;
 			dev_err(&dev->intf->dev, "SET_NTB_FORMAT failed\n");
+		}
 	}
 
 	/* set initial device values */
@@ -549,7 +581,10 @@
 		ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
 
 	/* set up maximum NDP size */
-	ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp16) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe16);
+	if (ctx->is_ndp16)
+		ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp16) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe16);
+	else
+		ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp32) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe32);
 
 	/* initial coalescing timer interval */
 	ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
@@ -734,7 +769,10 @@
 		ctx->tx_curr_skb = NULL;
 	}
 
-	kfree(ctx->delayed_ndp16);
+	if (ctx->is_ndp16)
+		kfree(ctx->delayed_ndp16);
+	else
+		kfree(ctx->delayed_ndp32);
 
 	kfree(ctx);
 }
@@ -772,10 +810,8 @@
 	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)
@@ -879,32 +915,6 @@
 		goto error2;
 	}
 
-	/*
-	 * 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) {
@@ -929,9 +939,15 @@
 
 	/* 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);
-		if (!ctx->delayed_ndp16)
-			goto error2;
+		if (ctx->is_ndp16) {
+			ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+			if (!ctx->delayed_ndp16)
+				goto error2;
+		} else {
+			ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+			if (!ctx->delayed_ndp32)
+				goto error2;
+		}
 		dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
 	}
 
@@ -1055,7 +1071,7 @@
 /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly
  * allocating a new one within skb
  */
-static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
+static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
 {
 	struct usb_cdc_ncm_ndp16 *ndp16 = NULL;
 	struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
@@ -1110,12 +1126,73 @@
 	return ndp16;
 }
 
+static struct usb_cdc_ncm_ndp32 *cdc_ncm_ndp32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
+{
+	struct usb_cdc_ncm_ndp32 *ndp32 = NULL;
+	struct usb_cdc_ncm_nth32 *nth32 = (void *)skb->data;
+	size_t ndpoffset = le32_to_cpu(nth32->dwNdpIndex);
+
+	/* If NDP should be moved to the end of the NCM package, we can't follow the
+	 * NTH32 header as we would normally do. NDP isn't written to the SKB yet, and
+	 * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
+	 */
+	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
+		if (ctx->delayed_ndp32->dwSignature == sign)
+			return ctx->delayed_ndp32;
+
+		/* We can only push a single NDP to the end. Return
+		 * NULL to send what we've already got and queue this
+		 * skb for later.
+		 */
+		else if (ctx->delayed_ndp32->dwSignature)
+			return NULL;
+	}
+
+	/* follow the chain of NDPs, looking for a match */
+	while (ndpoffset) {
+		ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb->data + ndpoffset);
+		if  (ndp32->dwSignature == sign)
+			return ndp32;
+		ndpoffset = le32_to_cpu(ndp32->dwNextNdpIndex);
+	}
+
+	/* align new NDP */
+	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
+		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);
+
+	/* verify that there is room for the NDP and the datagram (reserve) */
+	if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
+		return NULL;
+
+	/* link to it */
+	if (ndp32)
+		ndp32->dwNextNdpIndex = cpu_to_le32(skb->len);
+	else
+		nth32->dwNdpIndex = cpu_to_le32(skb->len);
+
+	/* push a new empty NDP */
+	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
+		ndp32 = skb_put_zero(skb, ctx->max_ndp_size);
+	else
+		ndp32 = ctx->delayed_ndp32;
+
+	ndp32->dwSignature = sign;
+	ndp32->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp32) + sizeof(struct usb_cdc_ncm_dpe32));
+	return ndp32;
+}
+
 struct sk_buff *
 cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
 {
 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-	struct usb_cdc_ncm_nth16 *nth16;
-	struct usb_cdc_ncm_ndp16 *ndp16;
+	union {
+		struct usb_cdc_ncm_nth16 *nth16;
+		struct usb_cdc_ncm_nth32 *nth32;
+	} nth;
+	union {
+		struct usb_cdc_ncm_ndp16 *ndp16;
+		struct usb_cdc_ncm_ndp32 *ndp32;
+	} ndp;
 	struct sk_buff *skb_out;
 	u16 n = 0, index, ndplen;
 	u8 ready2send = 0;
@@ -1126,7 +1203,10 @@
 	 * accordingly. Otherwise, we should check here.
 	 */
 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
-		delayed_ndp_size = ALIGN(ctx->max_ndp_size, ctx->tx_ndp_modulus);
+		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;
 
@@ -1152,6 +1232,9 @@
 			 * further.
 			 */
 			if (skb_out == NULL) {
+				/* If even the smallest allocation fails, abort. */
+				if (ctx->tx_curr_size == USB_CDC_NCM_NTB_MIN_OUT_SIZE)
+					goto alloc_failed;
 				ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1,
 							      (unsigned)CDC_NCM_LOW_MEM_MAX_CNT);
 				ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt;
@@ -1170,20 +1253,23 @@
 			skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC);
 
 			/* No allocation possible so we will abort */
-			if (skb_out == NULL) {
-				if (skb != NULL) {
-					dev_kfree_skb_any(skb);
-					dev->net->stats.tx_dropped++;
-				}
-				goto exit_no_skb;
-			}
+			if (!skb_out)
+				goto alloc_failed;
 			ctx->tx_low_mem_val--;
 		}
-		/* fill out the initial 16-bit NTB header */
-		nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16));
-		nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
-		nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16));
-		nth16->wSequence = cpu_to_le16(ctx->tx_seq++);
+		if (ctx->is_ndp16) {
+			/* fill out the initial 16-bit NTB header */
+			nth.nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16));
+			nth.nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
+			nth.nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16));
+			nth.nth16->wSequence = cpu_to_le16(ctx->tx_seq++);
+		} else {
+			/* fill out the initial 32-bit NTB header */
+			nth.nth32 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth32));
+			nth.nth32->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH32_SIGN);
+			nth.nth32->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth32));
+			nth.nth32->wSequence = cpu_to_le16(ctx->tx_seq++);
+		}
 
 		/* count total number of frames in this NTB */
 		ctx->tx_curr_frame_num = 0;
@@ -1205,13 +1291,17 @@
 		}
 
 		/* get the appropriate NDP for this skb */
-		ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
+		if (ctx->is_ndp16)
+			ndp.ndp16 = cdc_ncm_ndp16(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
+		else
+			ndp.ndp32 = cdc_ncm_ndp32(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
 
 		/* align beginning of next frame */
 		cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_curr_size);
 
 		/* check if we had enough room left for both NDP and frame */
-		if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) {
+		if ((ctx->is_ndp16 && !ndp.ndp16) || (!ctx->is_ndp16 && !ndp.ndp32) ||
+		    skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) {
 			if (n == 0) {
 				/* won't fit, MTU problem? */
 				dev_kfree_skb_any(skb);
@@ -1233,13 +1323,22 @@
 		}
 
 		/* calculate frame number withing this NDP */
-		ndplen = le16_to_cpu(ndp16->wLength);
-		index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1;
+		if (ctx->is_ndp16) {
+			ndplen = le16_to_cpu(ndp.ndp16->wLength);
+			index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1;
+
+			/* OK, add this skb */
+			ndp.ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len);
+			ndp.ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
+			ndp.ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
+		} else {
+			ndplen = le16_to_cpu(ndp.ndp32->wLength);
+			index = (ndplen - sizeof(struct usb_cdc_ncm_ndp32)) / sizeof(struct usb_cdc_ncm_dpe32) - 1;
 
-		/* OK, add this skb */
-		ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len);
-		ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
-		ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
+			ndp.ndp32->dpe32[index].dwDatagramLength = cpu_to_le32(skb->len);
+			ndp.ndp32->dpe32[index].dwDatagramIndex = cpu_to_le32(skb_out->len);
+			ndp.ndp32->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe32));
+		}
 		skb_put_data(skb_out, skb->data, skb->len);
 		ctx->tx_curr_frame_payload += skb->len;	/* count real tx payload data */
 		dev_kfree_skb_any(skb);
@@ -1286,13 +1385,22 @@
 
 	/* 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_curr_size - ctx->max_ndp_size);
-		nth16->wNdpIndex = cpu_to_le16(skb_out->len);
-		skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size);
+		if (ctx->is_ndp16) {
+			nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
+			cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
+			nth.nth16->wNdpIndex = cpu_to_le16(skb_out->len);
+			skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size);
+
+			/* Zero out delayed NDP - signature checking will naturally fail. */
+			ndp.ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
+		} else {
+			nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
+			cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
+			nth.nth32->dwNdpIndex = cpu_to_le32(skb_out->len);
+			skb_put_data(skb_out, ctx->delayed_ndp32, ctx->max_ndp_size);
 
-		/* Zero out delayed NDP - signature checking will naturally fail. */
-		ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
+			ndp.ndp32 = memset(ctx->delayed_ndp32, 0, ctx->max_ndp_size);
+		}
 	}
 
 	/* If collected data size is less or equal ctx->min_tx_pkt
@@ -1307,15 +1415,21 @@
 	if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
 	    skb_out->len > ctx->min_tx_pkt) {
 		padding_count = ctx->tx_curr_size - skb_out->len;
-		skb_put_zero(skb_out, padding_count);
+		if (!WARN_ON(padding_count > ctx->tx_curr_size))
+			skb_put_zero(skb_out, padding_count);
 	} else if (skb_out->len < ctx->tx_curr_size &&
 		   (skb_out->len % dev->maxpacket) == 0) {
 		skb_put_u8(skb_out, 0);	/* force short packet */
 	}
 
 	/* set final frame length */
-	nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
-	nth16->wBlockLength = cpu_to_le16(skb_out->len);
+	if (ctx->is_ndp16) {
+		nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
+		nth.nth16->wBlockLength = cpu_to_le16(skb_out->len);
+	} else {
+		nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
+		nth.nth32->dwBlockLength = cpu_to_le32(skb_out->len);
+	}
 
 	/* return skb */
 	ctx->tx_curr_skb = NULL;
@@ -1333,6 +1447,11 @@
 
 	return skb_out;
 
+alloc_failed:
+	if (skb) {
+		dev_kfree_skb_any(skb);
+		dev->net->stats.tx_dropped++;
+	}
 exit_no_skb:
 	/* Start timer, if there is a remaining non-empty skb */
 	if (ctx->tx_curr_skb != NULL && n > 0)
@@ -1398,7 +1517,12 @@
 		goto error;
 
 	spin_lock_bh(&ctx->mtx);
-	skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
+
+	if (ctx->is_ndp16)
+		skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
+	else
+		skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN));
+
 	spin_unlock_bh(&ctx->mtx);
 	return skb_out;
 
@@ -1459,6 +1583,54 @@
 }
 EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth16);
 
+int cdc_ncm_rx_verify_nth32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
+{
+	struct usbnet *dev = netdev_priv(skb_in->dev);
+	struct usb_cdc_ncm_nth32 *nth32;
+	int len;
+	int ret = -EINVAL;
+
+	if (ctx == NULL)
+		goto error;
+
+	if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth32) +
+					sizeof(struct usb_cdc_ncm_ndp32))) {
+		netif_dbg(dev, rx_err, dev->net, "frame too short\n");
+		goto error;
+	}
+
+	nth32 = (struct usb_cdc_ncm_nth32 *)skb_in->data;
+
+	if (nth32->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH32_SIGN)) {
+		netif_dbg(dev, rx_err, dev->net,
+			  "invalid NTH32 signature <%#010x>\n",
+			  le32_to_cpu(nth32->dwSignature));
+		goto error;
+	}
+
+	len = le32_to_cpu(nth32->dwBlockLength);
+	if (len > ctx->rx_max) {
+		netif_dbg(dev, rx_err, dev->net,
+			  "unsupported NTB block length %u/%u\n", len,
+			  ctx->rx_max);
+		goto error;
+	}
+
+	if ((ctx->rx_seq + 1) != le16_to_cpu(nth32->wSequence) &&
+	    (ctx->rx_seq || le16_to_cpu(nth32->wSequence)) &&
+	    !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth32->wSequence))) {
+		netif_dbg(dev, rx_err, dev->net,
+			  "sequence number glitch prev=%d curr=%d\n",
+			  ctx->rx_seq, le16_to_cpu(nth32->wSequence));
+	}
+	ctx->rx_seq = le16_to_cpu(nth32->wSequence);
+
+	ret = le32_to_cpu(nth32->dwNdpIndex);
+error:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth32);
+
 /* verify NDP header and return number of datagrams, or negative error */
 int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
 {
@@ -1495,6 +1667,42 @@
 }
 EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16);
 
+/* verify NDP header and return number of datagrams, or negative error */
+int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
+{
+	struct usbnet *dev = netdev_priv(skb_in->dev);
+	struct usb_cdc_ncm_ndp32 *ndp32;
+	int ret = -EINVAL;
+
+	if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
+		netif_dbg(dev, rx_err, dev->net, "invalid NDP offset  <%u>\n",
+			  ndpoffset);
+		goto error;
+	}
+	ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
+
+	if (le16_to_cpu(ndp32->wLength) < USB_CDC_NCM_NDP32_LENGTH_MIN) {
+		netif_dbg(dev, rx_err, dev->net, "invalid DPT32 length <%u>\n",
+			  le16_to_cpu(ndp32->wLength));
+		goto error;
+	}
+
+	ret = ((le16_to_cpu(ndp32->wLength) -
+					sizeof(struct usb_cdc_ncm_ndp32)) /
+					sizeof(struct usb_cdc_ncm_dpe32));
+	ret--; /* we process NDP entries except for the last one */
+
+	if ((sizeof(struct usb_cdc_ncm_ndp32) +
+	     ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
+		netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
+		ret = -EINVAL;
+	}
+
+error:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp32);
+
 int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
 {
 	struct sk_buff *skb;
@@ -1503,34 +1711,66 @@
 	int nframes;
 	int x;
 	int offset;
-	struct usb_cdc_ncm_ndp16 *ndp16;
-	struct usb_cdc_ncm_dpe16 *dpe16;
+	union {
+		struct usb_cdc_ncm_ndp16 *ndp16;
+		struct usb_cdc_ncm_ndp32 *ndp32;
+	} ndp;
+	union {
+		struct usb_cdc_ncm_dpe16 *dpe16;
+		struct usb_cdc_ncm_dpe32 *dpe32;
+	} dpe;
+
 	int ndpoffset;
 	int loopcount = 50; /* arbitrary max preventing infinite loop */
 	u32 payload = 0;
 
-	ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
+	if (ctx->is_ndp16)
+		ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
+	else
+		ndpoffset = cdc_ncm_rx_verify_nth32(ctx, skb_in);
+
 	if (ndpoffset < 0)
 		goto error;
 
 next_ndp:
-	nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
-	if (nframes < 0)
-		goto error;
+	if (ctx->is_ndp16) {
+		nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
+		if (nframes < 0)
+			goto error;
 
-	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
+		ndp.ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
 
-	if (ndp16->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)) {
-		netif_dbg(dev, rx_err, dev->net,
-			  "invalid DPT16 signature <%#010x>\n",
-			  le32_to_cpu(ndp16->dwSignature));
-		goto err_ndp;
-	}
-	dpe16 = ndp16->dpe16;
-
-	for (x = 0; x < nframes; x++, dpe16++) {
-		offset = le16_to_cpu(dpe16->wDatagramIndex);
-		len = le16_to_cpu(dpe16->wDatagramLength);
+		if (ndp.ndp16->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)) {
+			netif_dbg(dev, rx_err, dev->net,
+				  "invalid DPT16 signature <%#010x>\n",
+				  le32_to_cpu(ndp.ndp16->dwSignature));
+			goto err_ndp;
+		}
+		dpe.dpe16 = ndp.ndp16->dpe16;
+	} else {
+		nframes = cdc_ncm_rx_verify_ndp32(skb_in, ndpoffset);
+		if (nframes < 0)
+			goto error;
+
+		ndp.ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
+
+		if (ndp.ndp32->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN)) {
+			netif_dbg(dev, rx_err, dev->net,
+				  "invalid DPT32 signature <%#010x>\n",
+				  le32_to_cpu(ndp.ndp32->dwSignature));
+			goto err_ndp;
+		}
+		dpe.dpe32 = ndp.ndp32->dpe32;
+	}
+
+	for (x = 0; x < nframes; x++) {
+		if (ctx->is_ndp16) {
+			offset = le16_to_cpu(dpe.dpe16->wDatagramIndex);
+			len = le16_to_cpu(dpe.dpe16->wDatagramLength);
+		} else {
+			offset = le32_to_cpu(dpe.dpe32->dwDatagramIndex);
+			len = le32_to_cpu(dpe.dpe32->dwDatagramLength);
+		}
 
 		/*
 		 * CDC NCM ch. 3.7
@@ -1561,10 +1801,19 @@
 			usbnet_skb_return(dev, skb);
 			payload += len;	/* count payload bytes in this NTB */
 		}
+
+		if (ctx->is_ndp16)
+			dpe.dpe16++;
+		else
+			dpe.dpe32++;
 	}
 err_ndp:
 	/* are there more NDPs to process? */
-	ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
+	if (ctx->is_ndp16)
+		ndpoffset = le16_to_cpu(ndp.ndp16->wNextNdpIndex);
+	else
+		ndpoffset = le32_to_cpu(ndp.ndp32->dwNextNdpIndex);
+
 	if (ndpoffset && loopcount--)
 		goto next_ndp;
 
@@ -1585,6 +1834,15 @@
 	uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
 	uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
 
+	/* if the speed hasn't changed, don't report it.
+	 * RTL8156 shipped before 2021 sends notification about every 32ms.
+	 */
+	if (dev->rx_speed == rx_speed && dev->tx_speed == tx_speed)
+		return;
+
+	dev->rx_speed = rx_speed;
+	dev->tx_speed = tx_speed;
+
 	/*
 	 * Currently the USB-NET API does not support reporting the actual
 	 * device speed. Do print it instead.
@@ -1625,10 +1883,8 @@
 		 * 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);
+		if (netif_carrier_ok(dev->net) != !!event->wValue)
+			usbnet_link_change(dev, !!event->wValue, 0);
 		break;
 
 	case USB_CDC_NOTIFY_SPEED_CHANGE:
@@ -1651,7 +1907,7 @@
 static const struct driver_info cdc_ncm_info = {
 	.description = "CDC NCM",
 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-			| FLAG_LINK_INTR,
+			| FLAG_LINK_INTR | FLAG_ETHER,
 	.bind = cdc_ncm_bind,
 	.unbind = cdc_ncm_unbind,
 	.manage_power = usbnet_manage_power,
--- linux-ein-5.4.0.orig/drivers/net/usb/dm9601.c
+++ linux-ein-5.4.0/drivers/net/usb/dm9601.c
@@ -221,13 +221,18 @@
 	struct usbnet *dev = netdev_priv(netdev);
 
 	__le16 res;
+	int err;
 
 	if (phy_id) {
 		netdev_dbg(dev->net, "Only internal phy supported\n");
 		return 0;
 	}
 
-	dm_read_shared_word(dev, 1, loc, &res);
+	err = dm_read_shared_word(dev, 1, loc, &res);
+	if (err < 0) {
+		netdev_err(dev->net, "MDIO read error: %d\n", err);
+		return 0;
+	}
 
 	netdev_dbg(dev->net,
 		   "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
@@ -625,6 +630,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-ein-5.4.0.orig/drivers/net/usb/hso.c
+++ linux-ein-5.4.0/drivers/net/usb/hso.c
@@ -611,7 +611,7 @@
 	return serial;
 }
 
-static int get_free_serial_index(void)
+static int obtain_minor(struct hso_serial *serial)
 {
 	int index;
 	unsigned long flags;
@@ -619,8 +619,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);
@@ -629,15 +631,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);
 }
 
@@ -1389,8 +1388,9 @@
 	unsigned long flags;
 
 	if (old)
-		hso_dbg(0x16, "Termios called with: cflags new[%d] - old[%d]\n",
-			tty->termios.c_cflag, old->c_cflag);
+		hso_dbg(0x16, "Termios called with: cflags new[%u] - old[%u]\n",
+			(unsigned int)tty->termios.c_cflag,
+			(unsigned int)old->c_cflag);
 
 	/* the actual setup */
 	spin_lock_irqsave(&serial->serial_lock, flags);
@@ -1689,7 +1689,7 @@
 	spin_unlock_irqrestore(&serial->serial_lock, flags);
 
 	return usb_control_msg(serial->parent->usb,
-			       usb_rcvctrlpipe(serial->parent->usb, 0), 0x22,
+			       usb_sndctrlpipe(serial->parent->usb, 0), 0x22,
 			       0x21, val, if_num, NULL, 0,
 			       USB_CTRL_SET_TIMEOUT);
 }
@@ -2229,6 +2229,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)
@@ -2252,22 +2253,22 @@
 static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
 				    int rx_size, int tx_size)
 {
-	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;
+	}
 
-	/* 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;
@@ -2309,6 +2310,7 @@
 	return 0;
 exit:
 	hso_serial_tty_unregister(serial);
+exit2:
 	hso_serial_common_free(serial);
 	return -1;
 }
@@ -2434,7 +2436,7 @@
 	if (hso_dev->usb_gone)
 		rv = 0;
 	else
-		rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0),
+		rv = usb_control_msg(hso_dev->usb, usb_sndctrlpipe(hso_dev->usb, 0),
 				       enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0,
 				       USB_CTRL_SET_TIMEOUT);
 	mutex_unlock(&hso_dev->mutex);
@@ -2495,7 +2497,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);
@@ -2508,13 +2510,13 @@
 				      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);
@@ -2523,18 +2525,18 @@
 	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])
-			goto exit;
+			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)
-		goto exit;
+		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);
 
@@ -2542,7 +2544,7 @@
 	result = register_netdev(net);
 	if (result) {
 		dev_err(&interface->dev, "Failed to register device\n");
-		goto exit;
+		goto err_free_tx_buf;
 	}
 
 	hso_log_port(hso_dev);
@@ -2550,8 +2552,21 @@
 	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;
 }
 
@@ -2617,32 +2632,31 @@
 		num_urbs = 2;
 		serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
 					   GFP_KERNEL);
+		if (!serial->tiocmget)
+			goto exit;
 		serial->tiocmget->serial_state_notification
 			= kzalloc(sizeof(struct hso_serial_state_notification),
 					   GFP_KERNEL);
-		/* it isn't going to break our heart if serial->tiocmget
-		 *  allocation fails don't bother checking this.
-		 */
-		if (serial->tiocmget && serial->tiocmget->serial_state_notification) {
-			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);
-			} else
-				hso_free_tiomget(serial);
+		if (!serial->tiocmget->serial_state_notification)
+			goto exit;
+		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;
 		}
-	}
-	else
+
+		tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!tiocmget->urb)
+			goto exit;
+
+		mutex_init(&tiocmget->mutex);
+		init_waitqueue_head(&tiocmget->waitq);
+	} else {
 		num_urbs = 1;
+	}
 
 	if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE,
 				     BULK_URB_TX_SIZE))
@@ -2664,9 +2678,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);
 
@@ -2706,14 +2717,14 @@
 
 	serial = kzalloc(sizeof(*serial), GFP_KERNEL);
 	if (!serial)
-		goto exit;
+		goto err_free_dev;
 
 	hso_dev->port_data.dev_serial = serial;
 	serial->parent = hso_dev;
 
 	if (hso_serial_common_create
 	    (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE))
-		goto exit;
+		goto err_free_serial;
 
 	serial->tx_data_length--;
 	serial->write_data = hso_mux_serial_write_data;
@@ -2723,20 +2734,15 @@
 	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);
 
 	/* done, return it */
 	return hso_dev;
 
-exit:
-	if (serial) {
-		tty_unregister_device(tty_drv, serial->minor);
-		kfree(serial);
-	}
+err_free_serial:
+	kfree(serial);
+err_free_dev:
 	kfree(hso_dev);
 	return NULL;
 
@@ -3109,8 +3115,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-ein-5.4.0.orig/drivers/net/usb/huawei_cdc_ncm.c
+++ linux-ein-5.4.0/drivers/net/usb/huawei_cdc_ncm.c
@@ -77,11 +77,11 @@
 	 */
 	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.
+	/* For many Huawei devices the NTB32 mode is the default and the best mode
+	 * they work with. Huawei E5785 and E5885 devices refuse to work in NTB16 mode at all.
 	 */
-	drvflags |= CDC_NCM_FLAG_RESET_NTB16;
+	drvflags |= CDC_NCM_FLAG_PREFER_NTB32;
+
 	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
 	if (ret)
 		goto err;
--- linux-ein-5.4.0.orig/drivers/net/usb/ipheth.c
+++ linux-ein-5.4.0/drivers/net/usb/ipheth.c
@@ -59,7 +59,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)
 
@@ -121,7 +121,7 @@
 	if (tx_buf == NULL)
 		goto free_rx_urb;
 
-	rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+	rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
 				    GFP_KERNEL, &rx_urb->transfer_dma);
 	if (rx_buf == NULL)
 		goto free_tx_buf;
@@ -146,7 +146,7 @@
 
 static void ipheth_free_urbs(struct ipheth_device *iphone)
 {
-	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
+	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
 			  iphone->rx_urb->transfer_dma);
 	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
 			  iphone->tx_urb->transfer_dma);
@@ -317,7 +317,7 @@
 
 	usb_fill_bulk_urb(dev->rx_urb, udev,
 			  usb_rcvbulkpipe(udev, dev->bulk_in),
-			  dev->rx_buf, IPHETH_BUF_SIZE,
+			  dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
 			  ipheth_rcvbulk_callback,
 			  dev);
 	dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
--- linux-ein-5.4.0.orig/drivers/net/usb/kalmia.c
+++ linux-ein-5.4.0/drivers/net/usb/kalmia.c
@@ -65,8 +65,8 @@
 		init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT);
 	if (status != 0) {
 		netdev_err(dev->net,
-			"Error sending init packet. Status %i, length %i\n",
-			status, act_len);
+			"Error sending init packet. Status %i\n",
+			status);
 		return status;
 	}
 	else if (act_len != init_msg_len) {
@@ -83,8 +83,8 @@
 
 	if (status != 0)
 		netdev_err(dev->net,
-			"Error receiving init result. Status %i, length %i\n",
-			status, act_len);
+			"Error receiving init result. Status %i\n",
+			status);
 	else if (act_len != expected_len)
 		netdev_err(dev->net, "Unexpected init result length: %i\n",
 			act_len);
--- linux-ein-5.4.0.orig/drivers/net/usb/lan78xx.c
+++ linux-ein-5.4.0/drivers/net/usb/lan78xx.c
@@ -20,6 +20,7 @@
 #include <linux/mdio.h>
 #include <linux/phy.h>
 #include <net/ip6_checksum.h>
+#include <net/vxlan.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/irq.h>
@@ -63,6 +64,8 @@
 #define LAN7801_USB_PRODUCT_ID		(0x7801)
 #define LAN78XX_EEPROM_MAGIC		(0x78A5)
 #define LAN78XX_OTP_MAGIC		(0x78F3)
+#define AT29M2AF_USB_VENDOR_ID		(0x07C9)
+#define AT29M2AF_USB_PRODUCT_ID	(0x0012)
 
 #define	MII_READ			1
 #define	MII_WRITE			0
@@ -376,10 +379,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;
@@ -511,7 +510,7 @@
 		}
 	} else {
 		netdev_warn(dev->net,
-			    "Failed to read stat ret = 0x%x", ret);
+			    "Failed to read stat ret = %d", ret);
 	}
 
 	kfree(stats);
@@ -825,20 +824,19 @@
 				u32 length, u8 *data)
 {
 	int i;
-	int ret;
 	u32 buf;
 	unsigned long timeout;
 
-	ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+	lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
 
 	if (buf & OTP_PWR_DN_PWRDN_N_) {
 		/* clear it and wait to be cleared */
-		ret = lan78xx_write_reg(dev, OTP_PWR_DN, 0);
+		lan78xx_write_reg(dev, OTP_PWR_DN, 0);
 
 		timeout = jiffies + HZ;
 		do {
 			usleep_range(1, 10);
-			ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+			lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
 			if (time_after(jiffies, timeout)) {
 				netdev_warn(dev->net,
 					    "timeout on OTP_PWR_DN");
@@ -848,18 +846,18 @@
 	}
 
 	for (i = 0; i < length; i++) {
-		ret = lan78xx_write_reg(dev, OTP_ADDR1,
+		lan78xx_write_reg(dev, OTP_ADDR1,
 					((offset + i) >> 8) & OTP_ADDR1_15_11);
-		ret = lan78xx_write_reg(dev, OTP_ADDR2,
+		lan78xx_write_reg(dev, OTP_ADDR2,
 					((offset + i) & OTP_ADDR2_10_3));
 
-		ret = lan78xx_write_reg(dev, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
-		ret = lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
+		lan78xx_write_reg(dev, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
+		lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
 
 		timeout = jiffies + HZ;
 		do {
 			udelay(1);
-			ret = lan78xx_read_reg(dev, OTP_STATUS, &buf);
+			lan78xx_read_reg(dev, OTP_STATUS, &buf);
 			if (time_after(jiffies, timeout)) {
 				netdev_warn(dev->net,
 					    "timeout on OTP_STATUS");
@@ -867,7 +865,7 @@
 			}
 		} while (buf & OTP_STATUS_BUSY_);
 
-		ret = lan78xx_read_reg(dev, OTP_RD_DATA, &buf);
+		lan78xx_read_reg(dev, OTP_RD_DATA, &buf);
 
 		data[i] = (u8)(buf & 0xFF);
 	}
@@ -879,20 +877,19 @@
 				 u32 length, u8 *data)
 {
 	int i;
-	int ret;
 	u32 buf;
 	unsigned long timeout;
 
-	ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+	lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
 
 	if (buf & OTP_PWR_DN_PWRDN_N_) {
 		/* clear it and wait to be cleared */
-		ret = lan78xx_write_reg(dev, OTP_PWR_DN, 0);
+		lan78xx_write_reg(dev, OTP_PWR_DN, 0);
 
 		timeout = jiffies + HZ;
 		do {
 			udelay(1);
-			ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+			lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
 			if (time_after(jiffies, timeout)) {
 				netdev_warn(dev->net,
 					    "timeout on OTP_PWR_DN completion");
@@ -902,21 +899,21 @@
 	}
 
 	/* set to BYTE program mode */
-	ret = lan78xx_write_reg(dev, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
+	lan78xx_write_reg(dev, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
 
 	for (i = 0; i < length; i++) {
-		ret = lan78xx_write_reg(dev, OTP_ADDR1,
+		lan78xx_write_reg(dev, OTP_ADDR1,
 					((offset + i) >> 8) & OTP_ADDR1_15_11);
-		ret = lan78xx_write_reg(dev, OTP_ADDR2,
+		lan78xx_write_reg(dev, OTP_ADDR2,
 					((offset + i) & OTP_ADDR2_10_3));
-		ret = lan78xx_write_reg(dev, OTP_PRGM_DATA, data[i]);
-		ret = lan78xx_write_reg(dev, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
-		ret = lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
+		lan78xx_write_reg(dev, OTP_PRGM_DATA, data[i]);
+		lan78xx_write_reg(dev, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
+		lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
 
 		timeout = jiffies + HZ;
 		do {
 			udelay(1);
-			ret = lan78xx_read_reg(dev, OTP_STATUS, &buf);
+			lan78xx_read_reg(dev, OTP_STATUS, &buf);
 			if (time_after(jiffies, timeout)) {
 				netdev_warn(dev->net,
 					    "Timeout on OTP_STATUS completion");
@@ -1041,7 +1038,6 @@
 			container_of(param, struct lan78xx_priv, set_multicast);
 	struct lan78xx_net *dev = pdata->dev;
 	int i;
-	int ret;
 
 	netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n",
 		  pdata->rfe_ctl);
@@ -1050,14 +1046,14 @@
 			       DP_SEL_VHF_HASH_LEN, pdata->mchash_table);
 
 	for (i = 1; i < NUM_OF_MAF; i++) {
-		ret = lan78xx_write_reg(dev, MAF_HI(i), 0);
-		ret = lan78xx_write_reg(dev, MAF_LO(i),
+		lan78xx_write_reg(dev, MAF_HI(i), 0);
+		lan78xx_write_reg(dev, MAF_LO(i),
 					pdata->pfilter_table[i][1]);
-		ret = lan78xx_write_reg(dev, MAF_HI(i),
+		lan78xx_write_reg(dev, MAF_HI(i),
 					pdata->pfilter_table[i][0]);
 	}
 
-	ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+	lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
 }
 
 static void lan78xx_set_multicast(struct net_device *netdev)
@@ -1127,7 +1123,6 @@
 				      u16 lcladv, u16 rmtadv)
 {
 	u32 flow = 0, fct_flow = 0;
-	int ret;
 	u8 cap;
 
 	if (dev->fc_autoneg)
@@ -1150,10 +1145,10 @@
 		  (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
 		  (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
 
-	ret = lan78xx_write_reg(dev, FCT_FLOW, fct_flow);
+	lan78xx_write_reg(dev, FCT_FLOW, fct_flow);
 
 	/* threshold value should be set before enabling flow */
-	ret = lan78xx_write_reg(dev, FLOW, flow);
+	lan78xx_write_reg(dev, FLOW, flow);
 
 	return 0;
 }
@@ -1162,7 +1157,7 @@
 {
 	struct phy_device *phydev = dev->net->phydev;
 	struct ethtool_link_ksettings ecmd;
-	int ladv, radv, ret;
+	int ladv, radv, ret, link;
 	u32 buf;
 
 	/* clear LAN78xx interrupt status */
@@ -1170,9 +1165,12 @@
 	if (unlikely(ret < 0))
 		return -EIO;
 
+	mutex_lock(&phydev->lock);
 	phy_read_status(phydev);
+	link = phydev->link;
+	mutex_unlock(&phydev->lock);
 
-	if (!phydev->link && dev->link_on) {
+	if (!link && dev->link_on) {
 		dev->link_on = false;
 
 		/* reset MAC */
@@ -1185,7 +1183,7 @@
 			return -EIO;
 
 		del_timer(&dev->stat_monitor);
-	} else if (phydev->link && !dev->link_on) {
+	} else if (link && !dev->link_on) {
 		dev->link_on = true;
 
 		phy_ethtool_ksettings_get(phydev, &ecmd);
@@ -1474,9 +1472,14 @@
 
 static u32 lan78xx_get_link(struct net_device *net)
 {
+	u32 link;
+
+	mutex_lock(&net->phydev->lock);
 	phy_read_status(net->phydev);
+	link = net->phydev->link;
+	mutex_unlock(&net->phydev->lock);
 
-	return net->phydev->link;
+	return link;
 }
 
 static void lan78xx_get_drvinfo(struct net_device *net,
@@ -1674,11 +1677,10 @@
 static void lan78xx_init_mac_address(struct lan78xx_net *dev)
 {
 	u32 addr_lo, addr_hi;
-	int ret;
 	u8 addr[6];
 
-	ret = lan78xx_read_reg(dev, RX_ADDRL, &addr_lo);
-	ret = lan78xx_read_reg(dev, RX_ADDRH, &addr_hi);
+	lan78xx_read_reg(dev, RX_ADDRL, &addr_lo);
+	lan78xx_read_reg(dev, RX_ADDRH, &addr_hi);
 
 	addr[0] = addr_lo & 0xFF;
 	addr[1] = (addr_lo >> 8) & 0xFF;
@@ -1711,12 +1713,12 @@
 			  (addr[2] << 16) | (addr[3] << 24);
 		addr_hi = addr[4] | (addr[5] << 8);
 
-		ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
-		ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
+		lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
+		lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
 	}
 
-	ret = lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
-	ret = lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_);
+	lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
+	lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_);
 
 	ether_addr_copy(dev->net->dev_addr, addr);
 }
@@ -1808,6 +1810,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);
@@ -1848,33 +1851,8 @@
 static void lan78xx_link_status_change(struct net_device *net)
 {
 	struct phy_device *phydev = net->phydev;
-	int ret, temp;
-
-	/* At forced 100 F/H mode, chip may fail to set mode correctly
-	 * when cable is switched between long(~50+m) and short one.
-	 * As workaround, set to 10 before setting to 100
-	 * at forced 100 F/H mode.
-	 */
-	if (!phydev->autoneg && (phydev->speed == 100)) {
-		/* disable phy interrupt */
-		temp = phy_read(phydev, LAN88XX_INT_MASK);
-		temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_;
-		ret = phy_write(phydev, LAN88XX_INT_MASK, temp);
 
-		temp = phy_read(phydev, MII_BMCR);
-		temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
-		phy_write(phydev, MII_BMCR, temp); /* set to 10 first */
-		temp |= BMCR_SPEED100;
-		phy_write(phydev, MII_BMCR, temp); /* set to 100 later */
-
-		/* clear pending interrupt generated while workaround */
-		temp = phy_read(phydev, LAN88XX_INT_STS);
-
-		/* enable phy interrupt back */
-		temp = phy_read(phydev, LAN88XX_INT_MASK);
-		temp |= LAN88XX_INT_MASK_MDINTPIN_EN_;
-		ret = phy_write(phydev, LAN88XX_INT_MASK, temp);
-	}
+	phy_print_status(phydev);
 }
 
 static int irq_map(struct irq_domain *d, unsigned int irq,
@@ -1927,14 +1905,13 @@
 	struct lan78xx_net *dev =
 			container_of(data, struct lan78xx_net, domain_data);
 	u32 buf;
-	int ret;
 
 	/* call register access here because irq_bus_lock & irq_bus_sync_unlock
 	 * are only two callbacks executed in non-atomic contex.
 	 */
-	ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
+	lan78xx_read_reg(dev, INT_EP_CTL, &buf);
 	if (buf != data->irqenable)
-		ret = lan78xx_write_reg(dev, INT_EP_CTL, data->irqenable);
+		lan78xx_write_reg(dev, INT_EP_CTL, data->irqenable);
 
 	mutex_unlock(&data->irq_lock);
 }
@@ -2001,7 +1978,6 @@
 static int lan8835_fixup(struct phy_device *phydev)
 {
 	int buf;
-	int ret;
 	struct lan78xx_net *dev = netdev_priv(phydev->attached_dev);
 
 	/* LED2/PME_N/IRQ_N/RGMII_ID pin to IRQ_N mode */
@@ -2011,11 +1987,11 @@
 	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8010, buf);
 
 	/* RGMII MAC TXC Delay Enable */
-	ret = lan78xx_write_reg(dev, MAC_RGMII_ID,
+	lan78xx_write_reg(dev, MAC_RGMII_ID,
 				MAC_RGMII_ID_TXC_DELAY_EN_);
 
 	/* RGMII TX DLL Tune Adjust */
-	ret = lan78xx_write_reg(dev, RGMII_TX_BYP_DLL, 0x3D00);
+	lan78xx_write_reg(dev, RGMII_TX_BYP_DLL, 0x3D00);
 
 	dev->interface = PHY_INTERFACE_MODE_RGMII_TXID;
 
@@ -2130,7 +2106,7 @@
 	if (dev->domain_data.phyirq > 0)
 		phydev->irq = dev->domain_data.phyirq;
 	else
-		phydev->irq = 0;
+		phydev->irq = PHY_POLL;
 	netdev_dbg(dev->net, "phydev->irq = %d\n", phydev->irq);
 
 	/* set to AUTOMDIX */
@@ -2199,28 +2175,27 @@
 
 static int lan78xx_set_rx_max_frame_length(struct lan78xx_net *dev, int size)
 {
-	int ret = 0;
 	u32 buf;
 	bool rxenabled;
 
-	ret = lan78xx_read_reg(dev, MAC_RX, &buf);
+	lan78xx_read_reg(dev, MAC_RX, &buf);
 
 	rxenabled = ((buf & MAC_RX_RXEN_) != 0);
 
 	if (rxenabled) {
 		buf &= ~MAC_RX_RXEN_;
-		ret = lan78xx_write_reg(dev, MAC_RX, buf);
+		lan78xx_write_reg(dev, MAC_RX, buf);
 	}
 
 	/* add 4 to size for FCS */
 	buf &= ~MAC_RX_MAX_SIZE_MASK_;
 	buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT_) & MAC_RX_MAX_SIZE_MASK_);
 
-	ret = lan78xx_write_reg(dev, MAC_RX, buf);
+	lan78xx_write_reg(dev, MAC_RX, buf);
 
 	if (rxenabled) {
 		buf |= MAC_RX_RXEN_;
-		ret = lan78xx_write_reg(dev, MAC_RX, buf);
+		lan78xx_write_reg(dev, MAC_RX, buf);
 	}
 
 	return 0;
@@ -2277,13 +2252,12 @@
 	int ll_mtu = new_mtu + netdev->hard_header_len;
 	int old_hard_mtu = dev->hard_mtu;
 	int old_rx_urb_size = dev->rx_urb_size;
-	int ret;
 
 	/* no second zero-length packet read wanted after mtu-sized packets */
 	if ((ll_mtu % dev->maxpacket) == 0)
 		return -EDOM;
 
-	ret = lan78xx_set_rx_max_frame_length(dev, new_mtu + VLAN_ETH_HLEN);
+	lan78xx_set_rx_max_frame_length(dev, new_mtu + VLAN_ETH_HLEN);
 
 	netdev->mtu = new_mtu;
 
@@ -2306,7 +2280,6 @@
 	struct lan78xx_net *dev = netdev_priv(netdev);
 	struct sockaddr *addr = p;
 	u32 addr_lo, addr_hi;
-	int ret;
 
 	if (netif_running(netdev))
 		return -EBUSY;
@@ -2323,12 +2296,12 @@
 	addr_hi = netdev->dev_addr[4] |
 		  netdev->dev_addr[5] << 8;
 
-	ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
-	ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
+	lan78xx_write_reg(dev, RX_ADDRL, addr_lo);
+	lan78xx_write_reg(dev, RX_ADDRH, addr_hi);
 
 	/* Added to support MAC address changes */
-	ret = lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
-	ret = lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_);
+	lan78xx_write_reg(dev, MAF_LO(0), addr_lo);
+	lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_);
 
 	return 0;
 }
@@ -2340,7 +2313,6 @@
 	struct lan78xx_net *dev = netdev_priv(netdev);
 	struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
 	unsigned long flags;
-	int ret;
 
 	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
 
@@ -2364,7 +2336,7 @@
 
 	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
 
-	ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+	lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
 
 	return 0;
 }
@@ -2563,7 +2535,8 @@
 	if (dev->chipid == ID_REV_CHIP_ID_7801_)
 		buf &= ~MAC_CR_GMII_EN_;
 
-	if (dev->chipid == ID_REV_CHIP_ID_7800_) {
+	if (dev->chipid == ID_REV_CHIP_ID_7800_ ||
+	    dev->chipid == ID_REV_CHIP_ID_7850_) {
 		ret = lan78xx_read_raw_eeprom(dev, 0, 1, &sig);
 		if (!ret && sig != EEPROM_INDICATOR) {
 			/* Implies there is no external eeprom. Set mac speed */
@@ -2723,11 +2696,6 @@
 	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)
 {
@@ -2739,8 +2707,10 @@
 		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_;
 
@@ -2869,78 +2839,12 @@
 	return NETDEV_TX_OK;
 }
 
-static 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);
-	if (ret) {
-		netdev_warn(dev->net, "lan78xx_get_endpoints failed: %d\n",
-			    ret);
-		return ret;
-	}
-
 	dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL);
 
 	pdata = (struct lan78xx_priv *)(dev->data[0]);
@@ -3670,6 +3574,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,
@@ -3683,6 +3600,7 @@
 	.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 void lan78xx_stat_monitor(struct timer_list *t)
@@ -3695,6 +3613,7 @@
 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;
@@ -3743,6 +3662,34 @@
 
 	mutex_init(&dev->stats.access_lock);
 
+	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;
@@ -3752,19 +3699,9 @@
 
 	/* MTU range: 68 - 9000 */
 	netdev->max_mtu = MAX_SINGLE_PACKET_SIZE;
+	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) {
@@ -3777,11 +3714,18 @@
 			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;
 		}
 	}
 
 	dev->maxpacket = usb_maxpacket(dev->udev, dev->pipe_out, 1);
 
+	/* Reject broken descriptors. */
+	if (dev->maxpacket == 0) {
+		ret = -ENODEV;
+		goto out4;
+	}
+
 	/* driver requires remote-wakeup capability during autosuspend. */
 	intf->needs_remote_wakeup = 1;
 
@@ -3849,7 +3793,6 @@
 static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol)
 {
 	u32 buf;
-	int ret;
 	int mask_index;
 	u16 crc;
 	u32 temp_wucsr;
@@ -3858,26 +3801,26 @@
 	const u8 ipv6_multicast[3] = { 0x33, 0x33 };
 	const u8 arp_type[2] = { 0x08, 0x06 };
 
-	ret = lan78xx_read_reg(dev, MAC_TX, &buf);
+	lan78xx_read_reg(dev, MAC_TX, &buf);
 	buf &= ~MAC_TX_TXEN_;
-	ret = lan78xx_write_reg(dev, MAC_TX, buf);
-	ret = lan78xx_read_reg(dev, MAC_RX, &buf);
+	lan78xx_write_reg(dev, MAC_TX, buf);
+	lan78xx_read_reg(dev, MAC_RX, &buf);
 	buf &= ~MAC_RX_RXEN_;
-	ret = lan78xx_write_reg(dev, MAC_RX, buf);
+	lan78xx_write_reg(dev, MAC_RX, buf);
 
-	ret = lan78xx_write_reg(dev, WUCSR, 0);
-	ret = lan78xx_write_reg(dev, WUCSR2, 0);
-	ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
+	lan78xx_write_reg(dev, WUCSR, 0);
+	lan78xx_write_reg(dev, WUCSR2, 0);
+	lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL);
 
 	temp_wucsr = 0;
 
 	temp_pmt_ctl = 0;
-	ret = lan78xx_read_reg(dev, PMT_CTL, &temp_pmt_ctl);
+	lan78xx_read_reg(dev, PMT_CTL, &temp_pmt_ctl);
 	temp_pmt_ctl &= ~PMT_CTL_RES_CLR_WKP_EN_;
 	temp_pmt_ctl |= PMT_CTL_RES_CLR_WKP_STS_;
 
 	for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++)
-		ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_CFG(mask_index), 0);
 
 	mask_index = 0;
 	if (wol & WAKE_PHY) {
@@ -3906,30 +3849,30 @@
 
 		/* set WUF_CFG & WUF_MASK for IPv4 Multicast */
 		crc = lan78xx_wakeframe_crc16(ipv4_multicast, 3);
-		ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
+		lan78xx_write_reg(dev, WUF_CFG(mask_index),
 					WUF_CFGX_EN_ |
 					WUF_CFGX_TYPE_MCAST_ |
 					(0 << WUF_CFGX_OFFSET_SHIFT_) |
 					(crc & WUF_CFGX_CRC16_MASK_));
 
-		ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 7);
-		ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK0(mask_index), 7);
+		lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
 		mask_index++;
 
 		/* for IPv6 Multicast */
 		crc = lan78xx_wakeframe_crc16(ipv6_multicast, 2);
-		ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
+		lan78xx_write_reg(dev, WUF_CFG(mask_index),
 					WUF_CFGX_EN_ |
 					WUF_CFGX_TYPE_MCAST_ |
 					(0 << WUF_CFGX_OFFSET_SHIFT_) |
 					(crc & WUF_CFGX_CRC16_MASK_));
 
-		ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 3);
-		ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK0(mask_index), 3);
+		lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
 		mask_index++;
 
 		temp_pmt_ctl |= PMT_CTL_WOL_EN_;
@@ -3950,16 +3893,16 @@
 		 * for packettype (offset 12,13) = ARP (0x0806)
 		 */
 		crc = lan78xx_wakeframe_crc16(arp_type, 2);
-		ret = lan78xx_write_reg(dev, WUF_CFG(mask_index),
+		lan78xx_write_reg(dev, WUF_CFG(mask_index),
 					WUF_CFGX_EN_ |
 					WUF_CFGX_TYPE_ALL_ |
 					(0 << WUF_CFGX_OFFSET_SHIFT_) |
 					(crc & WUF_CFGX_CRC16_MASK_));
 
-		ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 0x3000);
-		ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
-		ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK0(mask_index), 0x3000);
+		lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0);
+		lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0);
 		mask_index++;
 
 		temp_pmt_ctl |= PMT_CTL_WOL_EN_;
@@ -3967,7 +3910,7 @@
 		temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_;
 	}
 
-	ret = lan78xx_write_reg(dev, WUCSR, temp_wucsr);
+	lan78xx_write_reg(dev, WUCSR, temp_wucsr);
 
 	/* when multiple WOL bits are set */
 	if (hweight_long((unsigned long)wol) > 1) {
@@ -3975,16 +3918,16 @@
 		temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_;
 		temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_;
 	}
-	ret = lan78xx_write_reg(dev, PMT_CTL, temp_pmt_ctl);
+	lan78xx_write_reg(dev, PMT_CTL, temp_pmt_ctl);
 
 	/* clear WUPS */
-	ret = lan78xx_read_reg(dev, PMT_CTL, &buf);
+	lan78xx_read_reg(dev, PMT_CTL, &buf);
 	buf |= PMT_CTL_WUPS_MASK_;
-	ret = lan78xx_write_reg(dev, PMT_CTL, buf);
+	lan78xx_write_reg(dev, PMT_CTL, buf);
 
-	ret = lan78xx_read_reg(dev, MAC_RX, &buf);
+	lan78xx_read_reg(dev, MAC_RX, &buf);
 	buf |= MAC_RX_RXEN_;
-	ret = lan78xx_write_reg(dev, MAC_RX, buf);
+	lan78xx_write_reg(dev, MAC_RX, buf);
 
 	return 0;
 }
@@ -4176,6 +4119,10 @@
 	/* LAN7801 USB Gigabit Ethernet Device */
 	USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7801_USB_PRODUCT_ID),
 	},
+	{
+	/* ATM2-AF USB Gigabit Ethernet Device */
+	USB_DEVICE(AT29M2AF_USB_VENDOR_ID, AT29M2AF_USB_PRODUCT_ID),
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(usb, products);
--- linux-ein-5.4.0.orig/drivers/net/usb/mcs7830.c
+++ linux-ein-5.4.0/drivers/net/usb/mcs7830.c
@@ -108,8 +108,16 @@
 
 static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
 {
-	return usbnet_read_cmd(dev, MCS7830_RD_BREQ, MCS7830_RD_BMREQ,
-				0x0000, index, data, size);
+	int ret;
+
+	ret = usbnet_read_cmd(dev, MCS7830_RD_BREQ, MCS7830_RD_BMREQ,
+			      0x0000, index, data, size);
+	if (ret < 0)
+		return ret;
+	else if (ret < size)
+		return -ENODATA;
+
+	return ret;
 }
 
 static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data)
--- linux-ein-5.4.0.orig/drivers/net/usb/pegasus.c
+++ linux-ein-5.4.0/drivers/net/usb/pegasus.c
@@ -495,11 +495,11 @@
 		goto goon;
 
 	rx_status = buf[count - 2];
-	if (rx_status & 0x1e) {
+	if (rx_status & 0x1c) {
 		netif_dbg(pegasus, rx_err, net,
 			  "RX packet error %x\n", rx_status);
 		net->stats.rx_errors++;
-		if (rx_status & 0x06)	/* long or runt	*/
+		if (rx_status & 0x04)	/* runt	*/
 			net->stats.rx_length_errors++;
 		if (rx_status & 0x08)
 			net->stats.rx_crc_errors++;
@@ -747,12 +747,16 @@
 	set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp);
 }
 
-static inline void get_interrupt_interval(pegasus_t *pegasus)
+static inline int get_interrupt_interval(pegasus_t *pegasus)
 {
 	u16 data;
 	u8 interval;
+	int ret;
+
+	ret = read_eprom_word(pegasus, 4, &data);
+	if (ret < 0)
+		return ret;
 
-	read_eprom_word(pegasus, 4, &data);
 	interval = data >> 8;
 	if (pegasus->usb->speed != USB_SPEED_HIGH) {
 		if (interval < 0x80) {
@@ -767,6 +771,8 @@
 		}
 	}
 	pegasus->intr_interval = interval;
+
+	return 0;
 }
 
 static void set_carrier(struct net_device *net)
@@ -1186,7 +1192,9 @@
 				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 
 	pegasus->features = usb_dev_id[dev_index].private;
-	get_interrupt_interval(pegasus);
+	res = get_interrupt_interval(pegasus);
+	if (res)
+		goto out2;
 	if (reset_mac(pegasus)) {
 		dev_err(&intf->dev, "can't reset MAC\n");
 		res = -EIO;
--- linux-ein-5.4.0.orig/drivers/net/usb/plusb.c
+++ linux-ein-5.4.0/drivers/net/usb/plusb.c
@@ -57,9 +57,7 @@
 static inline int
 pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
 {
-	return usbnet_read_cmd(dev, req,
-				USB_DIR_IN | USB_TYPE_VENDOR |
-				USB_RECIP_DEVICE,
+	return usbnet_write_cmd(dev, req, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 				val, index, NULL, 0);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/usb/qmi_wwan.c
+++ linux-ein-5.4.0/drivers/net/usb/qmi_wwan.c
@@ -61,7 +61,6 @@
 
 enum qmi_wwan_quirks {
 	QMI_WWAN_QUIRK_DTR = 1 << 0,	/* needs "set DTR" request */
-	QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1,	/* check num. endpoints */
 };
 
 struct qmimux_hdr {
@@ -338,6 +337,9 @@
 		netdev_dbg(net, "mode: raw IP\n");
 	} else if (!net->header_ops) { /* don't bother if already set */
 		ether_setup(net);
+		/* Restoring min/max mtu values set originally by usbnet */
+		net->min_mtu = 0;
+		net->max_mtu = ETH_MAX_MTU;
 		clear_bit(EVENT_NO_IP_ALIGN, &dev->flags);
 		netdev_dbg(net, "mode: Ethernet\n");
 	}
@@ -439,13 +441,6 @@
 		goto err;
 	}
 
-	/* 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;
-	}
-
 	ret = qmimux_register_device(dev->net, mux_id);
 	if (!ret) {
 		info->flags |= QMI_WWAN_FLAG_MUX;
@@ -475,13 +470,6 @@
 	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;
-	}
-
 	del_dev = qmimux_find_dev(dev, mux_id);
 	if (!del_dev) {
 		netdev_err(dev->net, "mux_id not present\n");
@@ -916,16 +904,6 @@
 	.data           = QMI_WWAN_QUIRK_DTR,
 };
 
-static const struct driver_info	qmi_wwan_info_quirk_quectel_dyncfg = {
-	.description	= "WWAN/QMI device",
-	.flags		= FLAG_WWAN | FLAG_SEND_ZLP,
-	.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 | QMI_WWAN_QUIRK_QUECTEL_DYNCFG,
-};
-
 #define HUAWEI_VENDOR_ID	0x12D1
 
 /* map QMI/wwan function by a fixed interface number */
@@ -946,14 +924,18 @@
 #define QMI_GOBI_DEVICE(vend, prod) \
 	QMI_FIXED_INTF(vend, prod, 0)
 
-/* Quectel does not use fixed interface numbers on at least some of their
- * devices. We need to check the number of endpoints to ensure that we bind to
- * the correct interface.
+/* Many devices have QMI and DIAG functions which are distinguishable
+ * from other vendor specific functions by class, subclass and
+ * protocol all being 0xff. The DIAG function has exactly 2 endpoints
+ * and is silently rejected when probed.
+ *
+ * This makes it possible to match dynamically numbered QMI functions
+ * as seen on e.g. many Quectel modems.
  */
-#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \
+#define QMI_MATCH_FF_FF_FF(vend, prod) \
 	USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \
 				      USB_SUBCLASS_VENDOR_SPEC, 0xff), \
-	.driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg
+	.driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr
 
 static const struct usb_device_id products[] = {
 	/* 1. CDC ECM like devices match on the control interface */
@@ -1059,9 +1041,12 @@
 		USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
 		.driver_info = (unsigned long)&qmi_wwan_info,
 	},
-	{QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)},	/* Quectel EC25, EC20 R2.0  Mini PCIe */
-	{QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)},	/* Quectel EP06/EG06/EM06 */
-	{QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)},	/* Quectel EG12/EM12 */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)},	/* Quectel EC25, EC20 R2.0  Mini PCIe */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)},	/* Quectel EP06/EG06/EM06 */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)},	/* Quectel EG12/EM12 */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)},	/* Quectel EM160R-GL */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)},	/* Quectel RM500Q-GL */
+	{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)},	/* Quectel RM520N */
 
 	/* 3. Combined interface devices matching on interface number */
 	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */
@@ -1095,7 +1080,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)},
@@ -1193,7 +1178,9 @@
 	{QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
 	{QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
 	{QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
+	{QMI_QUIRK_SET_DTR(0x05c6, 0x9091, 2)},	/* Compal RXM-G1 */
 	{QMI_FIXED_INTF(0x05c6, 0x90b2, 3)},    /* ublox R410M */
+	{QMI_QUIRK_SET_DTR(0x05c6, 0x90db, 2)},	/* Compal RXM-G1 */
 	{QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
 	{QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
 	{QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)},	/* YUGA CLM920-NC5 */
@@ -1213,6 +1200,7 @@
 	{QMI_FIXED_INTF(0x1435, 0xd182, 5)},	/* Wistron NeWeb D18 */
 	{QMI_FIXED_INTF(0x1435, 0xd191, 4)},	/* Wistron NeWeb D19Q1 */
 	{QMI_QUIRK_SET_DTR(0x1508, 0x1001, 4)},	/* Fibocom NL668 series */
+	{QMI_FIXED_INTF(0x1690, 0x7588, 4)},    /* ASKEY WWHC050 */
 	{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 */
@@ -1259,6 +1247,7 @@
 	{QMI_FIXED_INTF(0x19d2, 0x0168, 4)},
 	{QMI_FIXED_INTF(0x19d2, 0x0176, 3)},
 	{QMI_FIXED_INTF(0x19d2, 0x0178, 3)},
+	{QMI_FIXED_INTF(0x19d2, 0x0189, 4)},    /* ZTE MF290 */
 	{QMI_FIXED_INTF(0x19d2, 0x0191, 4)},	/* ZTE EuFi890 */
 	{QMI_FIXED_INTF(0x19d2, 0x0199, 1)},	/* ZTE MF820S */
 	{QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
@@ -1281,6 +1270,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)},
@@ -1295,7 +1285,7 @@
 	{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_QUIRK_SET_DTR(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 */
@@ -1326,12 +1316,18 @@
 	{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, 0x1031, 3)}, /* Telit LE910C1-EUX */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x103a, 0)}, /* Telit LE910C4-WWX */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)},	/* Telit LE922A */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)},	/* Telit FN980 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1060, 2)},	/* Telit LN920 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1070, 2)},	/* Telit FN990 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1080, 2)}, /* Telit FE990 */
 	{QMI_FIXED_INTF(0x1bc7, 0x1100, 3)},	/* Telit ME910 */
 	{QMI_FIXED_INTF(0x1bc7, 0x1101, 3)},	/* Telit ME910 dual modem */
 	{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},	/* Telit LE920 */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1201, 2)},	/* Telit LE920, LE920A4 */
+	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1230, 2)},	/* Telit LE910Cx */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1260, 2)},	/* Telit LE910Cx */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1261, 2)},	/* Telit LE910Cx */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1900, 1)},	/* Telit LN940 series */
@@ -1346,12 +1342,14 @@
 	{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, 0x0063, 10)},	/* Cinterion ALASxx (1 RmNet) */
 	{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_QUIRK_SET_DTR(0x1e2d, 0x00b0, 4)},	/* Cinterion CLS8 */
+	{QMI_FIXED_INTF(0x1e2d, 0x00b7, 0)},	/* Cinterion MV31 RmNet */
 	{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 */
@@ -1361,18 +1359,29 @@
 	{QMI_FIXED_INTF(0x413c, 0x81b3, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
 	{QMI_FIXED_INTF(0x413c, 0x81b6, 8)},	/* Dell Wireless 5811e */
 	{QMI_FIXED_INTF(0x413c, 0x81b6, 10)},	/* Dell Wireless 5811e */
+	{QMI_FIXED_INTF(0x413c, 0x81c2, 8)},	/* Dell Wireless 5811e */
+	{QMI_FIXED_INTF(0x413c, 0x81cc, 8)},	/* Dell Wireless 5816e */
 	{QMI_FIXED_INTF(0x413c, 0x81d7, 0)},	/* Dell Wireless 5821e */
+	{QMI_FIXED_INTF(0x413c, 0x81d7, 1)},	/* Dell Wireless 5821e preproduction config */
 	{QMI_FIXED_INTF(0x413c, 0x81e0, 0)},	/* Dell Wireless 5821e with eSIM support*/
+	{QMI_FIXED_INTF(0x413c, 0x81e4, 0)},	/* Dell Wireless 5829e with eSIM support*/
+	{QMI_FIXED_INTF(0x413c, 0x81e6, 0)},	/* Dell Wireless 5829e */
 	{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_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)},	/* SIMCom 7100E, 7230E, 7600E ++ */
 	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)},	/* Quectel EC21 Mini PCIe */
 	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)},	/* Quectel EG91 */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0195, 4)},	/* Quectel EG95 */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0435, 4)}, /* Quectel AG35 */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x0801, 4)}, /* Quectel RG520 */
 	{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)},	/* Quectel BG96 */
+	{QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)},	/* Quectel EM05GV2 */
 	{QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)},	/* Fibocom NL678 series */
 	{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)},	/* Foxconn T77W968 LTE */
 	{QMI_FIXED_INTF(0x0489, 0xe0b5, 0)},	/* Foxconn T77W968 LTE with eSIM support*/
+	{QMI_FIXED_INTF(0x2692, 0x9025, 4)},    /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
+	{QMI_QUIRK_SET_DTR(0x1546, 0x1342, 4)},	/* u-blox LARA-L6 */
 
 	/* 4. Gobi 1000 devices */
 	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
@@ -1453,7 +1462,6 @@
 {
 	struct usb_device_id *id = (struct usb_device_id *)prod;
 	struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
-	const struct driver_info *info;
 
 	/* Workaround to enable dynamic IDs.  This disables usbnet
 	 * blacklisting functionality.  Which, if required, can be
@@ -1489,12 +1497,8 @@
 	 * different. Ignore the current interface if the number of endpoints
 	 * equals the number for the diag interface (two).
 	 */
-	info = (void *)id->driver_info;
-
-	if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) {
-		if (desc->bNumEndpoints == 2)
-			return -ENODEV;
-	}
+	if (desc->bNumEndpoints == 2)
+		return -ENODEV;
 
 	return usbnet_probe(intf, id);
 }
--- linux-ein-5.4.0.orig/drivers/net/usb/r8152.c
+++ linux-ein-5.4.0/drivers/net/usb/r8152.c
@@ -29,7 +29,7 @@
 #define NETNEXT_VERSION		"10"
 
 /* Information for net */
-#define NET_VERSION		"10"
+#define NET_VERSION		"11"
 
 #define DRIVER_VERSION		"v1." NETNEXT_VERSION "." NET_VERSION
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -63,6 +63,7 @@
 #define PLA_LED_FEATURE		0xdd92
 #define PLA_PHYAR		0xde00
 #define PLA_BOOT_CTRL		0xe004
+#define PLA_LWAKE_CTRL_REG	0xe007
 #define PLA_GPHY_INTR_IMR	0xe022
 #define PLA_EEE_CR		0xe040
 #define PLA_EEEP_CR		0xe080
@@ -90,6 +91,7 @@
 #define PLA_TALLYCNT		0xe890
 #define PLA_SFF_STS_7		0xe8de
 #define PLA_PHYSTATUS		0xe908
+#define PLA_CONFIG6		0xe90a /* CONFIG6 */
 #define PLA_BP_BA		0xfc26
 #define PLA_BP_0		0xfc28
 #define PLA_BP_1		0xfc2a
@@ -102,6 +104,7 @@
 #define PLA_BP_EN		0xfc38
 
 #define USB_USB2PHY		0xb41e
+#define USB_SSPHYLINK1		0xb426
 #define USB_SSPHYLINK2		0xb428
 #define USB_U2P3_CTRL		0xb460
 #define USB_CSR_DUMMY1		0xb464
@@ -286,6 +289,9 @@
 #define LINK_ON_WAKE_EN		0x0010
 #define LINK_OFF_WAKE_EN	0x0008
 
+/* PLA_CONFIG6 */
+#define LANWAKE_CLR_EN		BIT(0)
+
 /* PLA_CONFIG5 */
 #define BWF_EN			0x0040
 #define MWF_EN			0x0020
@@ -298,6 +304,7 @@
 /* PLA_PHY_PWR */
 #define TX_10M_IDLE_EN		0x0080
 #define PFM_PWM_SWITCH		0x0040
+#define TEST_IO_OFF		BIT(4)
 
 /* PLA_MAC_PWR_CTRL */
 #define D3_CLK_GATED_EN		0x00004000
@@ -310,6 +317,7 @@
 #define MAC_CLK_SPDWN_EN	BIT(15)
 
 /* PLA_MAC_PWR_CTRL3 */
+#define PLA_MCU_SPDWN_EN	BIT(14)
 #define PKT_AVAIL_SPDWN_EN	0x0100
 #define SUSPEND_SPDWN_EN	0x0004
 #define U1U2_SPDWN_EN		0x0002
@@ -340,6 +348,9 @@
 /* PLA_BOOT_CTRL */
 #define AUTOLOAD_DONE		0x0002
 
+/* PLA_LWAKE_CTRL_REG */
+#define LANWAKE_PIN		BIT(7)
+
 /* PLA_SUSPEND_FLAG */
 #define LINK_CHG_EVENT		BIT(0)
 
@@ -353,6 +364,9 @@
 #define USB2PHY_SUSPEND		0x0001
 #define USB2PHY_L1		0x0002
 
+/* USB_SSPHYLINK1 */
+#define DELAY_PHY_PWR_CHG	BIT(1)
+
 /* USB_SSPHYLINK2 */
 #define pwd_dn_scale_mask	0x3ffe
 #define pwd_dn_scale(x)		((x) << 1)
@@ -622,6 +636,7 @@
 	SCHEDULE_TASKLET,
 	GREEN_ETHERNET,
 	DELL_TB_RX_AGG_BUG,
+	LENOVO_MACPASSTHRU,
 };
 
 /* Define these values to match your device */
@@ -836,7 +851,7 @@
 
 	ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
 			      RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-			      value, index, tmp, size, 500);
+			      value, index, tmp, size, USB_CTRL_GET_TIMEOUT);
 	if (ret < 0)
 		memset(data, 0xff, size);
 	else
@@ -859,7 +874,7 @@
 
 	ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
 			      RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-			      value, index, tmp, size, 500);
+			      value, index, tmp, size, USB_CTRL_SET_TIMEOUT);
 
 	kfree(tmp);
 
@@ -1222,38 +1237,52 @@
 	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) {
-		/* test for MAC address pass-through bit */
-		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
-		if ((ocp_data & PASS_THRU_MASK) != 1) {
-			netif_dbg(tp, probe, tp->netdev,
-				  "No efuse for RTL8153-AD MAC pass through\n");
-			return -ENODEV;
-		}
+	char *mac_obj_name;
+	acpi_object_type mac_obj_type;
+	int mac_strlen;
+
+	if (test_bit(LENOVO_MACPASSTHRU, &tp->flags)) {
+		mac_obj_name = "\\MACA";
+		mac_obj_type = ACPI_TYPE_STRING;
+		mac_strlen = 0x16;
 	} else {
-		/* test for RTL8153-BND and RTL8153-BD */
-		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1);
-		if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) {
-			netif_dbg(tp, probe, tp->netdev,
-				  "Invalid variant for MAC pass through\n");
-			return -ENODEV;
+		/* test for -AD variant of RTL8153 */
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+		if ((ocp_data & AD_MASK) == 0x1000) {
+			/* test for MAC address pass-through bit */
+			ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE);
+			if ((ocp_data & PASS_THRU_MASK) != 1) {
+				netif_dbg(tp, probe, tp->netdev,
+						"No efuse for RTL8153-AD MAC pass through\n");
+				return -ENODEV;
+			}
+		} else {
+			/* test for RTL8153-BND and RTL8153-BD */
+			ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1);
+			if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) {
+				netif_dbg(tp, probe, tp->netdev,
+						"Invalid variant for MAC pass through\n");
+				return -ENODEV;
+			}
 		}
+
+		mac_obj_name = "\\_SB.AMAC";
+		mac_obj_type = ACPI_TYPE_BUFFER;
+		mac_strlen = 0x17;
 	}
 
 	/* returns _AUXMAC_#AABBCCDDEEFF# */
-	status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer);
+	status = acpi_evaluate_object(NULL, mac_obj_name, NULL, &buffer);
 	obj = (union acpi_object *)buffer.pointer;
 	if (!ACPI_SUCCESS(status))
 		return -ENODEV;
-	if (obj->type != ACPI_TYPE_BUFFER || obj->string.length != 0x17) {
+	if (obj->type != mac_obj_type || obj->string.length != mac_strlen) {
 		netif_warn(tp, probe, tp->netdev,
 			   "Invalid buffer for 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,
@@ -1465,7 +1494,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:
@@ -2237,6 +2268,9 @@
 	struct r8152 *tp = container_of(napi, struct r8152, napi);
 	int work_done;
 
+	if (!budget)
+		return 0;
+
 	work_done = rx_bottom(tp, budget);
 
 	if (work_done < budget) {
@@ -2822,29 +2856,6 @@
 		device_set_wakeup_enable(&tp->udev->dev, false);
 }
 
-static void r8153_mac_clk_spd(struct r8152 *tp, bool enable)
-{
-	/* MAC clock speed down */
-	if (enable) {
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL,
-			       ALDPS_SPDWN_RATIO);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2,
-			       EEE_SPDWN_RATIO);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
-			       PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN |
-			       U1U2_SPDWN_EN | L1_SPDWN_EN);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
-			       PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN |
-			       TP100_SPDWN_EN | TP500_SPDWN_EN | EEE_SPDWN_EN |
-			       TP1000_SPDWN_EN);
-	} else {
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0);
-		ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0);
-	}
-}
-
 static void r8153_u1u2en(struct r8152 *tp, bool enable)
 {
 	u8 u1u2[8];
@@ -2992,6 +3003,8 @@
 		}
 
 		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			break;
 	}
 
 	return data;
@@ -3142,11 +3155,9 @@
 	if (enable) {
 		r8153_u1u2en(tp, false);
 		r8153_u2p3en(tp, false);
-		r8153_mac_clk_spd(tp, true);
 		rtl_runtime_suspend_enable(tp, true);
 	} else {
 		rtl_runtime_suspend_enable(tp, false);
-		r8153_mac_clk_spd(tp, false);
 
 		switch (tp->version) {
 		case RTL_VER_03:
@@ -3175,7 +3186,6 @@
 		r8153b_ups_en(tp, false);
 		r8153_queue_wake(tp, false);
 		rtl_runtime_suspend_enable(tp, false);
-		r8153_u2p3en(tp, true);
 		r8153b_u1u2en(tp, true);
 	}
 }
@@ -3703,7 +3713,6 @@
 
 	r8153_aldps_en(tp, true);
 	r8152b_enable_fc(tp);
-	r8153_u2p3en(tp, true);
 
 	set_bit(PHY_RESET, &tp->flags);
 }
@@ -3713,7 +3722,6 @@
 	u32 ocp_data;
 	int i;
 
-	r8153_mac_clk_spd(tp, false);
 	rxdy_gated_en(tp, true);
 	r8153_teredo_off(tp);
 
@@ -3775,8 +3783,6 @@
 	u32 ocp_data;
 	int i;
 
-	r8153_mac_clk_spd(tp, true);
-
 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
 	ocp_data &= ~NOW_IS_OOB;
 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
@@ -4004,6 +4010,8 @@
 
 static void rtl8153_up(struct r8152 *tp)
 {
+	u32 ocp_data;
+
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
 
@@ -4011,6 +4019,19 @@
 	r8153_u2p3en(tp, false);
 	r8153_aldps_en(tp, false);
 	r8153_first_init(tp);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
+	ocp_data |= LANWAKE_CLR_EN;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG);
+	ocp_data &= ~LANWAKE_PIN;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1);
+	ocp_data &= ~DELAY_PHY_PWR_CHG;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK1, ocp_data);
+
 	r8153_aldps_en(tp, true);
 
 	switch (tp->version) {
@@ -4029,11 +4050,17 @@
 
 static void rtl8153_down(struct r8152 *tp)
 {
+	u32 ocp_data;
+
 	if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
 		rtl_drop_queued_tx(tp);
 		return;
 	}
 
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
+	ocp_data &= ~LANWAKE_CLR_EN;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
+
 	r8153_u1u2en(tp, false);
 	r8153_u2p3en(tp, false);
 	r8153_power_cut_en(tp, false);
@@ -4044,6 +4071,8 @@
 
 static void rtl8153b_up(struct r8152 *tp)
 {
+	u32 ocp_data;
+
 	if (test_bit(RTL8152_UNPLUG, &tp->flags))
 		return;
 
@@ -4054,18 +4083,27 @@
 	r8153_first_init(tp);
 	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B);
 
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
 	r8153_aldps_en(tp, true);
-	r8153_u2p3en(tp, true);
 	r8153b_u1u2en(tp, true);
 }
 
 static void rtl8153b_down(struct r8152 *tp)
 {
+	u32 ocp_data;
+
 	if (test_bit(RTL8152_UNPLUG, &tp->flags)) {
 		rtl_drop_queued_tx(tp);
 		return;
 	}
 
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data |= PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
 	r8153b_u1u2en(tp, false);
 	r8153_u2p3en(tp, false);
 	r8153b_power_cut_en(tp, false);
@@ -4299,9 +4337,10 @@
 		tp->rtl_ops.down(tp);
 
 		mutex_unlock(&tp->control);
+	}
 
+	if (!res)
 		usb_autopm_put_interface(tp->intf);
-	}
 
 	free_all_mem(tp);
 
@@ -4375,7 +4414,10 @@
 		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
 		    AUTOLOAD_DONE)
 			break;
+
 		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			break;
 	}
 
 	data = r8153_phy_status(tp, 0);
@@ -4449,11 +4491,24 @@
 
 	ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
 
+	/* MAC clock speed down */
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0);
+
 	r8153_power_cut_en(tp, false);
 	r8153_u1u2en(tp, true);
-	r8153_mac_clk_spd(tp, false);
 	usb_enable_lpm(tp->udev);
 
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
+	ocp_data |= LANWAKE_CLR_EN;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6, ocp_data);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG);
+	ocp_data &= ~LANWAKE_PIN;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_LWAKE_CTRL_REG, ocp_data);
+
 	/* rx aggregation */
 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
 	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
@@ -4493,7 +4548,10 @@
 		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
 		    AUTOLOAD_DONE)
 			break;
+
 		msleep(20);
+		if (test_bit(RTL8152_UNPLUG, &tp->flags))
+			break;
 	}
 
 	data = r8153_phy_status(tp, 0);
@@ -4526,6 +4584,19 @@
 	ocp_data |= MAC_CLK_SPDWN_EN;
 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
 
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	if (tp->version == RTL_VER_09) {
+		/* Disable Test IO for 32QFN */
+		if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) {
+			ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+			ocp_data |= TEST_IO_OFF;
+			ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+		}
+	}
+
 	set_bit(GREEN_ETHERNET, &tp->flags);
 
 	/* rx aggregation */
@@ -5015,7 +5086,7 @@
 {
 	switch (stringset) {
 	case ETH_SS_STATS:
-		memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
+		memcpy(data, rtl8152_gstrings, sizeof(rtl8152_gstrings));
 		break;
 	}
 }
@@ -5479,7 +5550,10 @@
 		ops->in_nway		= rtl8153_in_nway;
 		ops->hw_phy_cfg		= r8153_hw_phy_cfg;
 		ops->autosuspend_en	= rtl8153_runtime_enable;
-		tp->rx_buf_sz		= 32 * 1024;
+		if (tp->udev->speed < USB_SPEED_SUPER)
+			tp->rx_buf_sz	= 16 * 1024;
+		else
+			tp->rx_buf_sz	= 32 * 1024;
 		tp->eee_en		= true;
 		tp->eee_adv		= MDIO_EEE_1000T | MDIO_EEE_100TX;
 		break;
@@ -5525,7 +5599,8 @@
 
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 			      RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-			      PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
+			      PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp),
+			      USB_CTRL_GET_TIMEOUT);
 	if (ret > 0)
 		ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK;
 
@@ -5587,6 +5662,9 @@
 		return -ENODEV;
 	}
 
+	if (intf->cur_altsetting->desc.bNumEndpoints < 3)
+		return -ENODEV;
+
 	usb_reset_device(udev);
 	netdev = alloc_etherdev(sizeof(struct r8152));
 	if (!netdev) {
@@ -5644,6 +5722,10 @@
 		netdev->hw_features &= ~NETIF_F_RXCSUM;
 	}
 
+	if (le16_to_cpu(udev->descriptor.idVendor) == VENDOR_ID_LENOVO &&
+	    le16_to_cpu(udev->descriptor.idProduct) == 0x3082)
+		set_bit(LENOVO_MACPASSTHRU, &tp->flags);
+
 	if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial &&
 	    (!strcmp(udev->serial, "000001000000") || !strcmp(udev->serial, "000002000000"))) {
 		dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation");
@@ -5687,6 +5769,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);
 	queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
 	set_ethernet_addr(tp);
@@ -5700,10 +5787,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
@@ -5715,6 +5798,9 @@
 
 out1:
 	tasklet_kill(&tp->tx_tl);
+	cancel_delayed_work_sync(&tp->hw_phy_work);
+	if (tp->rtl_ops.unload)
+		tp->rtl_ops.unload(tp);
 	usb_set_intfdata(intf, NULL);
 out:
 	free_netdev(netdev);
@@ -5760,13 +5846,17 @@
 	{REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3054)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3062)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3069)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3082)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x720c)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7214)},
+	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x721e)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0xa387)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)},
 	{REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA,  0x09ff)},
--- linux-ein-5.4.0.orig/drivers/net/usb/rndis_host.c
+++ linux-ein-5.4.0/drivers/net/usb/rndis_host.c
@@ -201,7 +201,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;
@@ -255,7 +255,8 @@
 
 	off = le32_to_cpu(u.get_c->offset);
 	len = le32_to_cpu(u.get_c->len);
-	if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
+	if (unlikely((off > CONTROL_BUFFER_SIZE - 8) ||
+		     (len > CONTROL_BUFFER_SIZE - 8 - off)))
 		goto response_error;
 
 	if (*reply_len != -1 && len != *reply_len)
@@ -387,7 +388,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);
@@ -609,6 +610,11 @@
 				      USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	.driver_info = (unsigned long) &rndis_poll_status_info,
 }, {
+	/* Hytera Communications DMR radios' "Radio to PC Network" */
+	USB_VENDOR_AND_INTERFACE_INFO(0x238b,
+				      USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+	.driver_info = (unsigned long)&rndis_info,
+}, {
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	.driver_info = (unsigned long) &rndis_info,
--- linux-ein-5.4.0.orig/drivers/net/usb/rtl8150.c
+++ linux-ein-5.4.0/drivers/net/usb/rtl8150.c
@@ -274,12 +274,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;
 
-	get_registers(dev, IDR, sizeof(node_id), node_id);
-	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+	ret = get_registers(dev, IDR, sizeof(node_id), 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)
--- linux-ein-5.4.0.orig/drivers/net/usb/smsc75xx.c
+++ linux-ein-5.4.0/drivers/net/usb/smsc75xx.c
@@ -90,7 +90,9 @@
 	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;
@@ -1482,7 +1484,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);
@@ -1491,7 +1493,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;
@@ -1501,6 +1503,13 @@
 	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 	dev->net->max_mtu = MAX_SINGLE_PACKET_SIZE;
 	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)
@@ -1510,7 +1519,6 @@
 		cancel_work_sync(&pdata->set_multicast);
 		netif_dbg(dev, ifdown, dev->net, "free pdata\n");
 		kfree(pdata);
-		pdata = NULL;
 		dev->data[0] = 0;
 	}
 }
@@ -2192,6 +2200,13 @@
 		size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING;
 		align_count = (4 - ((size + RXW_PADDING) % 4)) % 4;
 
+		if (unlikely(size > skb->len)) {
+			netif_dbg(dev, rx_err, dev->net,
+				  "size err rx_cmd_a=0x%08x\n",
+				  rx_cmd_a);
+			return 0;
+		}
+
 		if (unlikely(rx_cmd_a & RX_CMD_A_RED)) {
 			netif_dbg(dev, rx_err, dev->net,
 				  "Error rx_cmd_a=0x%08x\n", rx_cmd_a);
--- linux-ein-5.4.0.orig/drivers/net/usb/smsc95xx.c
+++ linux-ein-5.4.0/drivers/net/usb/smsc95xx.c
@@ -1040,7 +1040,7 @@
 
 	if (timeout >= 100) {
 		netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n");
-		return ret;
+		return -ETIMEDOUT;
 	}
 
 	ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
@@ -1287,11 +1287,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;
 	pdata->chip_id = val;
 	pdata->mdix_ctrl = get_mdix_status(dev->net);
@@ -1317,6 +1320,10 @@
 	schedule_delayed_work(&pdata->carrier_check, CARRIER_CHECK_DELAY);
 
 	return 0;
+
+free_pdata:
+	kfree(pdata);
+	return ret;
 }
 
 static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -1324,7 +1331,7 @@
 	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
 
 	if (pdata) {
-		cancel_delayed_work(&pdata->carrier_check);
+		cancel_delayed_work_sync(&pdata->carrier_check);
 		netif_dbg(dev, ifdown, dev->net, "free pdata\n");
 		kfree(pdata);
 		pdata = NULL;
@@ -1928,6 +1935,12 @@
 		size = (u16)((header & RX_STS_FL_) >> 16);
 		align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
 
+		if (unlikely(size > skb->len)) {
+			netif_dbg(dev, rx_err, dev->net,
+				  "size err header=0x%08x\n", header);
+			return 0;
+		}
+
 		if (unlikely(header & RX_STS_ES_)) {
 			netif_dbg(dev, rx_err, dev->net,
 				  "Error header=0x%08x\n", header);
--- linux-ein-5.4.0.orig/drivers/net/usb/sr9700.c
+++ linux-ein-5.4.0/drivers/net/usb/sr9700.c
@@ -410,7 +410,7 @@
 		/* ignore the CRC length */
 		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
-		if (len > ETH_FRAME_LEN)
+		if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
 			return 0;
 
 		/* the last packet of current skb */
--- linux-ein-5.4.0.orig/drivers/net/usb/usbnet.c
+++ linux-ein-5.4.0/drivers/net/usb/usbnet.c
@@ -833,13 +833,11 @@
 
 	mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
 
-	/* deferred work (task, timer, softirq) must also stop.
-	 * can't flush_scheduled_work() until we drop rtnl (later),
-	 * else workers could deadlock; so make workers a NOP.
-	 */
+	/* deferred work (timer, softirq, task) must also stop */
 	dev->flags = 0;
 	del_timer_sync (&dev->delay);
 	tasklet_kill (&dev->bh);
+	cancel_work_sync(&dev->kevent);
 	if (!pm)
 		usb_autopm_put_interface(dev->intf);
 
@@ -1587,6 +1585,7 @@
 	struct usbnet		*dev;
 	struct usb_device	*xdev;
 	struct net_device	*net;
+	struct urb		*urb;
 
 	dev = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
@@ -1603,9 +1602,11 @@
 	net = dev->net;
 	unregister_netdev (net);
 
-	cancel_work_sync(&dev->kevent);
-
-	usb_scuttle_anchored_urbs(&dev->deferred);
+	while ((urb = usb_get_from_anchor(&dev->deferred))) {
+		dev_kfree_skb(urb->context);
+		kfree(urb->sg);
+		usb_free_urb(urb);
+	}
 
 	if (dev->driver_info->unbind)
 		dev->driver_info->unbind (dev, intf);
@@ -1755,6 +1756,10 @@
 	} else if (!info->in || !info->out)
 		status = usbnet_get_endpoints (dev, udev);
 	else {
+		u8 ep_addrs[3] = {
+			info->in + USB_DIR_IN, info->out + USB_DIR_OUT, 0
+		};
+
 		dev->in = usb_rcvbulkpipe (xdev, info->in);
 		dev->out = usb_sndbulkpipe (xdev, info->out);
 		if (!(info->flags & FLAG_NO_SETINT))
@@ -1764,6 +1769,8 @@
 		else
 			status = 0;
 
+		if (status == 0 && !usb_check_bulk_endpoints(udev, ep_addrs))
+			status = -EINVAL;
 	}
 	if (status >= 0 && dev->status)
 		status = init_status (dev, udev);
@@ -1773,6 +1780,11 @@
 	if (!dev->rx_urb_size)
 		dev->rx_urb_size = dev->hard_mtu;
 	dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
+	if (dev->maxpacket == 0) {
+		/* that is a broken device */
+		status = -ENODEV;
+		goto out4;
+	}
 
 	/* let userspace know we have a random address */
 	if (ether_addr_equal(net->dev_addr, node_id))
@@ -1982,7 +1994,7 @@
 		   cmd, reqtype, value, index, size);
 
 	if (size) {
-		buf = kmalloc(size, GFP_KERNEL);
+		buf = kmalloc(size, GFP_NOIO);
 		if (!buf)
 			goto out;
 	}
@@ -2014,7 +2026,7 @@
 		   cmd, reqtype, value, index, size);
 
 	if (data) {
-		buf = kmemdup(data, size, GFP_KERNEL);
+		buf = kmemdup(data, size, GFP_NOIO);
 		if (!buf)
 			goto out;
 	} else {
@@ -2115,7 +2127,7 @@
 int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
 			   u16 value, u16 index, const void *data, u16 size)
 {
-	struct usb_ctrlrequest *req = NULL;
+	struct usb_ctrlrequest *req;
 	struct urb *urb;
 	int err = -ENOMEM;
 	void *buf = NULL;
@@ -2133,7 +2145,7 @@
 		if (!buf) {
 			netdev_err(dev->net, "Error allocating buffer"
 				   " in %s!\n", __func__);
-			goto fail_free;
+			goto fail_free_urb;
 		}
 	}
 
@@ -2157,14 +2169,21 @@
 	if (err < 0) {
 		netdev_err(dev->net, "Error submitting the control"
 			   " message: status=%d\n", err);
-		goto fail_free;
+		goto fail_free_all;
 	}
 	return 0;
 
+fail_free_all:
+	kfree(req);
 fail_free_buf:
 	kfree(buf);
-fail_free:
-	kfree(req);
+	/*
+	 * avoid a double free
+	 * needed because the flag can be set only
+	 * after filling the URB
+	 */
+	urb->transfer_flags = 0;
+fail_free_urb:
 	usb_free_urb(urb);
 fail:
 	return err;
--- linux-ein-5.4.0.orig/drivers/net/usb/zaurus.c
+++ linux-ein-5.4.0/drivers/net/usb/zaurus.c
@@ -256,6 +256,11 @@
 	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
 	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
 
+#define ZAURUS_FAKE_INTERFACE \
+	.bInterfaceClass	= USB_CLASS_COMM, \
+	.bInterfaceSubClass	= USB_CDC_SUBCLASS_MDLM, \
+	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
+
 /* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
 {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
@@ -284,11 +289,25 @@
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,	/* A-300 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info = (unsigned long)&bogus_mdlm_info,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
 	.idProduct		= 0x8006,	/* B-500/SL-5600 */
 	ZAURUS_MASTER_INTERFACE,
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,	/* B-500/SL-5600 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info = (unsigned long)&bogus_mdlm_info,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 	          | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor		= 0x04DD,
 	.idProduct		= 0x8007,	/* C-700 */
@@ -296,6 +315,13 @@
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8007,	/* C-700 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info = (unsigned long)&bogus_mdlm_info,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	.idProduct              = 0x9031,	/* C-750 C-760 */
@@ -315,6 +341,13 @@
 	.driver_info = ZAURUS_PXA_INFO,
 }, {
 	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+			    | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x9032,	/* SL-6000 */
+	ZAURUS_FAKE_INTERFACE,
+	.driver_info = (unsigned long)&bogus_mdlm_info,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	/* reported with some C860 units */
--- linux-ein-5.4.0.orig/drivers/net/veth.c
+++ linux-ein-5.4.0/drivers/net/veth.c
@@ -209,9 +209,10 @@
 {
 	/* Write ptr_ring before reading rx_notify_masked */
 	smp_mb();
-	if (!rq->rx_notify_masked) {
-		rq->rx_notify_masked = true;
-		napi_schedule(&rq->xdp_napi);
+	if (!READ_ONCE(rq->rx_notify_masked) &&
+	    napi_schedule_prep(&rq->xdp_napi)) {
+		WRITE_ONCE(rq->rx_notify_masked, true);
+		__napi_schedule(&rq->xdp_napi);
 	}
 }
 
@@ -237,6 +238,7 @@
 {
 	struct veth_priv *rcv_priv, *priv = netdev_priv(dev);
 	struct veth_rq *rq = NULL;
+	int ret = NETDEV_TX_OK;
 	struct net_device *rcv;
 	int length = skb->len;
 	bool rcv_xdp = false;
@@ -244,7 +246,7 @@
 
 	rcu_read_lock();
 	rcv = rcu_dereference(priv->peer);
-	if (unlikely(!rcv)) {
+	if (unlikely(!rcv) || !pskb_may_pull(skb, ETH_HLEN)) {
 		kfree_skb(skb);
 		goto drop;
 	}
@@ -254,8 +256,6 @@
 	if (rxq < rcv->real_num_rx_queues) {
 		rq = &rcv_priv->rq[rxq];
 		rcv_xdp = rcu_access_pointer(rq->xdp_prog);
-		if (rcv_xdp)
-			skb_record_rx_queue(skb, rxq);
 	}
 
 	skb_tx_timestamp(skb);
@@ -271,6 +271,7 @@
 	} else {
 drop:
 		atomic64_inc(&priv->dropped);
+		ret = NET_XMIT_DROP;
 	}
 
 	if (rcv_xdp)
@@ -278,7 +279,7 @@
 
 	rcu_read_unlock();
 
-	return NETDEV_TX_OK;
+	return ret;
 }
 
 static u64 veth_stats_tx(struct pcpu_lstats *result, struct net_device *dev)
@@ -510,13 +511,15 @@
 					struct veth_xdp_tx_bq *bq)
 {
 	void *hard_start = frame->data - frame->headroom;
-	void *head = hard_start - sizeof(struct xdp_frame);
 	int len = frame->len, delta = 0;
 	struct xdp_frame orig_frame;
 	struct bpf_prog *xdp_prog;
 	unsigned int headroom;
 	struct sk_buff *skb;
 
+	/* bpf_xdp_adjust_head() assures BPF cannot access xdp_frame area */
+	hard_start -= sizeof(struct xdp_frame);
+
 	rcu_read_lock();
 	xdp_prog = rcu_dereference(rq->xdp_prog);
 	if (likely(xdp_prog)) {
@@ -538,7 +541,6 @@
 			break;
 		case XDP_TX:
 			orig_frame = *frame;
-			xdp.data_hard_start = head;
 			xdp.rxq->mem = frame->mem;
 			if (unlikely(veth_xdp_tx(rq->dev, &xdp, bq) < 0)) {
 				trace_xdp_exception(rq->dev, xdp_prog, act);
@@ -550,7 +552,6 @@
 			goto xdp_xmit;
 		case XDP_REDIRECT:
 			orig_frame = *frame;
-			xdp.data_hard_start = head;
 			xdp.rxq->mem = frame->mem;
 			if (xdp_do_redirect(rq->dev, &xdp, xdp_prog)) {
 				frame = &orig_frame;
@@ -572,7 +573,7 @@
 	rcu_read_unlock();
 
 	headroom = sizeof(struct xdp_frame) + frame->headroom - delta;
-	skb = veth_build_skb(head, headroom, len, 0);
+	skb = veth_build_skb(hard_start, headroom, len, 0);
 	if (!skb) {
 		xdp_return_frame(frame);
 		goto err;
@@ -782,8 +783,10 @@
 		/* Write rx_notify_masked before reading ptr_ring */
 		smp_store_mb(rq->rx_notify_masked, false);
 		if (unlikely(!__ptr_ring_empty(&rq->xdp_ring))) {
-			rq->rx_notify_masked = true;
-			napi_schedule(&rq->xdp_napi);
+			if (napi_schedule_prep(&rq->xdp_napi)) {
+				WRITE_ONCE(rq->rx_notify_masked, true);
+				__napi_schedule(&rq->xdp_napi);
+			}
 		}
 	}
 
@@ -1254,10 +1257,7 @@
 
 		nla_peer = data[VETH_INFO_PEER];
 		ifmp = nla_data(nla_peer);
-		err = rtnl_nla_parse_ifla(peer_tb,
-					  nla_data(nla_peer) + sizeof(struct ifinfomsg),
-					  nla_len(nla_peer) - sizeof(struct ifinfomsg),
-					  NULL);
+		err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
 		if (err < 0)
 			return err;
 
--- linux-ein-5.4.0.orig/drivers/net/virtio_net.c
+++ linux-ein-5.4.0/drivers/net/virtio_net.c
@@ -63,6 +63,11 @@
 	VIRTIO_NET_F_GUEST_CSUM
 };
 
+#define GUEST_OFFLOAD_GRO_HW_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
+				(1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
+				(1ULL << VIRTIO_NET_F_GUEST_ECN)  | \
+				(1ULL << VIRTIO_NET_F_GUEST_UFO))
+
 struct virtnet_stat_desc {
 	char desc[ETH_GSTRING_LEN];
 	size_t offset;
@@ -190,6 +195,9 @@
 	/* # of XDP queue pairs currently used by the driver */
 	u16 xdp_queue_pairs;
 
+	/* xdp_queue_pairs may be 0, when xdp is already loaded. So add this. */
+	bool xdp_enabled;
+
 	/* I like... big packets and I cannot lie! */
 	bool big_packets;
 
@@ -205,9 +213,15 @@
 	/* Packet virtio header size */
 	u8 hdr_len;
 
-	/* Work struct for refilling if we run low on memory. */
+	/* Work struct for delayed refilling if we run low on memory. */
 	struct delayed_work refill;
 
+	/* Is delayed refill enabled? */
+	bool refill_enabled;
+
+	/* The lock to synchronize the access to refill_enabled */
+	spinlock_t refill_lock;
+
 	/* Work struct for config space updates */
 	struct work_struct config_work;
 
@@ -311,6 +325,20 @@
 	return p;
 }
 
+static void enable_delayed_refill(struct virtnet_info *vi)
+{
+	spin_lock_bh(&vi->refill_lock);
+	vi->refill_enabled = true;
+	spin_unlock_bh(&vi->refill_lock);
+}
+
+static void disable_delayed_refill(struct virtnet_info *vi)
+{
+	spin_lock_bh(&vi->refill_lock);
+	vi->refill_enabled = false;
+	spin_unlock_bh(&vi->refill_lock);
+}
+
 static void virtqueue_napi_schedule(struct napi_struct *napi,
 				    struct virtqueue *vq)
 {
@@ -371,7 +399,7 @@
 				   struct receive_queue *rq,
 				   struct page *page, unsigned int offset,
 				   unsigned int len, unsigned int truesize,
-				   bool hdr_valid)
+				   bool hdr_valid, unsigned int metasize)
 {
 	struct sk_buff *skb;
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
@@ -393,6 +421,7 @@
 	else
 		hdr_padded_len = sizeof(struct padded_vnet_hdr);
 
+	/* hdr_valid means no XDP, so we can copy the vnet header */
 	if (hdr_valid)
 		memcpy(hdr, p, hdr_len);
 
@@ -400,11 +429,20 @@
 	offset += hdr_padded_len;
 	p += hdr_padded_len;
 
-	copy = len;
-	if (copy > skb_tailroom(skb))
-		copy = skb_tailroom(skb);
+	/* Copy all frame if it fits skb->head, otherwise
+	 * we let virtio_net_hdr_to_skb() and GRO pull headers as needed.
+	 */
+	if (len <= skb_tailroom(skb))
+		copy = len;
+	else
+		copy = ETH_HLEN + metasize;
 	skb_put_data(skb, p, copy);
 
+	if (metasize) {
+		__skb_pull(skb, metasize);
+		skb_metadata_set(skb, metasize);
+	}
+
 	len -= copy;
 	offset += copy;
 
@@ -450,10 +488,6 @@
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
 	int err;
 
-	/* virtqueue want to use data area in-front of packet */
-	if (unlikely(xdpf->metasize > 0))
-		return -EOPNOTSUPP;
-
 	if (unlikely(xdpf->headroom < vi->hdr_len))
 		return -EOVERFLOW;
 
@@ -474,12 +508,41 @@
 	return 0;
 }
 
-static struct send_queue *virtnet_xdp_sq(struct virtnet_info *vi)
-{
-	unsigned int qp;
-
-	qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id();
-	return &vi->sq[qp];
+/* when vi->curr_queue_pairs > nr_cpu_ids, the txq/sq is only used for xdp tx on
+ * the current cpu, so it does not need to be locked.
+ *
+ * Here we use marco instead of inline functions because we have to deal with
+ * three issues at the same time: 1. the choice of sq. 2. judge and execute the
+ * lock/unlock of txq 3. make sparse happy. It is difficult for two inline
+ * functions to perfectly solve these three problems at the same time.
+ */
+#define virtnet_xdp_get_sq(vi) ({                                       \
+	struct netdev_queue *txq;                                       \
+	typeof(vi) v = (vi);                                            \
+	unsigned int qp;                                                \
+									\
+	if (v->curr_queue_pairs > nr_cpu_ids) {                         \
+		qp = v->curr_queue_pairs - v->xdp_queue_pairs;          \
+		qp += smp_processor_id();                               \
+		txq = netdev_get_tx_queue(v->dev, qp);                  \
+		__netif_tx_acquire(txq);                                \
+	} else {                                                        \
+		qp = smp_processor_id() % v->curr_queue_pairs;          \
+		txq = netdev_get_tx_queue(v->dev, qp);                  \
+		__netif_tx_lock(txq, raw_smp_processor_id());           \
+	}                                                               \
+	v->sq + qp;                                                     \
+})
+
+#define virtnet_xdp_put_sq(vi, q) {                                     \
+	struct netdev_queue *txq;                                       \
+	typeof(vi) v = (vi);                                            \
+									\
+	txq = netdev_get_tx_queue(v->dev, (q) - v->sq);                 \
+	if (v->curr_queue_pairs > nr_cpu_ids)                           \
+		__netif_tx_release(txq);                                \
+	else                                                            \
+		__netif_tx_unlock(txq);                                 \
 }
 
 static int virtnet_xdp_xmit(struct net_device *dev,
@@ -505,7 +568,7 @@
 	if (!xdp_prog)
 		return -ENXIO;
 
-	sq = virtnet_xdp_sq(vi);
+	sq = virtnet_xdp_get_sq(vi);
 
 	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
 		ret = -EINVAL;
@@ -553,12 +616,13 @@
 	sq->stats.kicks += kicks;
 	u64_stats_update_end(&sq->stats.syncp);
 
+	virtnet_xdp_put_sq(vi, sq);
 	return ret;
 }
 
 static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
 {
-	return vi->xdp_queue_pairs ? VIRTIO_XDP_HEADROOM : 0;
+	return vi->xdp_enabled ? VIRTIO_XDP_HEADROOM : 0;
 }
 
 /* We copy the packet for XDP in the following cases:
@@ -582,8 +646,13 @@
 				       int page_off,
 				       unsigned int *len)
 {
-	struct page *page = alloc_page(GFP_ATOMIC);
+	int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	struct page *page;
+
+	if (page_off + *len + tailroom > PAGE_SIZE)
+		return NULL;
 
+	page = alloc_page(GFP_ATOMIC);
 	if (!page)
 		return NULL;
 
@@ -591,7 +660,6 @@
 	page_off += *len;
 
 	while (--*num_buf) {
-		int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 		unsigned int buflen;
 		void *buf;
 		int off;
@@ -644,6 +712,7 @@
 	unsigned int delta = 0;
 	struct page *xdp_page;
 	int err;
+	unsigned int metasize = 0;
 
 	len -= vi->hdr_len;
 	stats->bytes += len;
@@ -683,8 +752,8 @@
 
 		xdp.data_hard_start = buf + VIRTNET_RX_PAD + vi->hdr_len;
 		xdp.data = xdp.data_hard_start + xdp_headroom;
-		xdp_set_data_meta_invalid(&xdp);
 		xdp.data_end = xdp.data + len;
+		xdp.data_meta = xdp.data;
 		xdp.rxq = &rq->xdp_rxq;
 		orig_data = xdp.data;
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
@@ -695,6 +764,7 @@
 			/* Recalculate length in case bpf program changed it */
 			delta = orig_data - xdp.data;
 			len = xdp.data_end - xdp.data;
+			metasize = xdp.data - xdp.data_meta;
 			break;
 		case XDP_TX:
 			stats->xdp_tx++;
@@ -740,6 +810,9 @@
 		memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len);
 	} /* keep zeroed vnet hdr since packet was changed by bpf */
 
+	if (metasize)
+		skb_metadata_set(skb, metasize);
+
 err:
 	return skb;
 
@@ -760,8 +833,8 @@
 				   struct virtnet_rq_stats *stats)
 {
 	struct page *page = buf;
-	struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len,
-					  PAGE_SIZE, true);
+	struct sk_buff *skb =
+		page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, true, 0);
 
 	stats->bytes += len - vi->hdr_len;
 	if (unlikely(!skb))
@@ -793,6 +866,7 @@
 	unsigned int truesize;
 	unsigned int headroom = mergeable_ctx_to_headroom(ctx);
 	int err;
+	unsigned int metasize = 0;
 
 	head_skb = NULL;
 	stats->bytes += len - vi->hdr_len;
@@ -839,8 +913,8 @@
 		data = page_address(xdp_page) + offset;
 		xdp.data_hard_start = data - VIRTIO_XDP_HEADROOM + vi->hdr_len;
 		xdp.data = data + vi->hdr_len;
-		xdp_set_data_meta_invalid(&xdp);
 		xdp.data_end = xdp.data + (len - vi->hdr_len);
+		xdp.data_meta = xdp.data;
 		xdp.rxq = &rq->xdp_rxq;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
@@ -848,24 +922,27 @@
 
 		switch (act) {
 		case XDP_PASS:
+			metasize = xdp.data - xdp.data_meta;
+
 			/* recalculate offset to account for any header
-			 * adjustments. Note other cases do not build an
-			 * skb and avoid using offset
+			 * adjustments and minus the metasize to copy the
+			 * metadata in page_to_skb(). Note other cases do not
+			 * build an skb and avoid using offset
 			 */
-			offset = xdp.data -
-					page_address(xdp_page) - vi->hdr_len;
+			offset = xdp.data - page_address(xdp_page) -
+				 vi->hdr_len - metasize;
 
-			/* recalculate len if xdp.data or xdp.data_end were
-			 * adjusted
+			/* recalculate len if xdp.data, xdp.data_end or
+			 * xdp.data_meta were adjusted
 			 */
-			len = xdp.data_end - xdp.data + vi->hdr_len;
+			len = xdp.data_end - xdp.data + vi->hdr_len + metasize;
 			/* We can only create skb based on xdp_page. */
 			if (unlikely(xdp_page != page)) {
 				rcu_read_unlock();
 				put_page(page);
-				head_skb = page_to_skb(vi, rq, xdp_page,
-						       offset, len,
-						       PAGE_SIZE, false);
+				head_skb = page_to_skb(vi, rq, xdp_page, offset,
+						       len, PAGE_SIZE, false,
+						       metasize);
 				return head_skb;
 			}
 			break;
@@ -921,7 +998,8 @@
 		goto err_skb;
 	}
 
-	head_skb = page_to_skb(vi, rq, page, offset, len, truesize, !xdp_prog);
+	head_skb = page_to_skb(vi, rq, page, offset, len, truesize, !xdp_prog,
+			       metasize);
 	curr_skb = head_skb;
 
 	if (unlikely(!curr_skb))
@@ -1231,9 +1309,11 @@
 			break;
 	} while (rq->vq->num_free);
 	if (virtqueue_kick_prepare(rq->vq) && virtqueue_notify(rq->vq)) {
-		u64_stats_update_begin(&rq->stats.syncp);
+		unsigned long flags;
+
+		flags = u64_stats_update_begin_irqsave(&rq->stats.syncp);
 		rq->stats.kicks++;
-		u64_stats_update_end(&rq->stats.syncp);
+		u64_stats_update_end_irqrestore(&rq->stats.syncp, flags);
 	}
 
 	return !oom;
@@ -1332,8 +1412,12 @@
 	}
 
 	if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) {
-		if (!try_fill_recv(vi, rq, GFP_ATOMIC))
-			schedule_delayed_work(&vi->refill, 0);
+		if (!try_fill_recv(vi, rq, GFP_ATOMIC)) {
+			spin_lock(&vi->refill_lock);
+			if (vi->refill_enabled)
+				schedule_delayed_work(&vi->refill, 0);
+			spin_unlock(&vi->refill_lock);
+		}
 	}
 
 	u64_stats_update_begin(&rq->stats.syncp);
@@ -1435,12 +1519,13 @@
 		xdp_do_flush_map();
 
 	if (xdp_xmit & VIRTIO_XDP_TX) {
-		sq = virtnet_xdp_sq(vi);
+		sq = virtnet_xdp_get_sq(vi);
 		if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
 			u64_stats_update_begin(&sq->stats.syncp);
 			sq->stats.kicks++;
 			u64_stats_update_end(&sq->stats.syncp);
 		}
+		virtnet_xdp_put_sq(vi, sq);
 	}
 
 	return received;
@@ -1451,6 +1536,8 @@
 	struct virtnet_info *vi = netdev_priv(dev);
 	int i, err;
 
+	enable_delayed_refill(vi);
+
 	for (i = 0; i < vi->max_queue_pairs; i++) {
 		if (i < vi->curr_queue_pairs)
 			/* Make sure we have some buffers: if oom use wq. */
@@ -1481,6 +1568,8 @@
 	struct virtnet_info *vi = sq->vq->vdev->priv;
 	unsigned int index = vq2txq(sq->vq);
 	struct netdev_queue *txq;
+	int opaque;
+	bool done;
 
 	if (unlikely(is_xdp_raw_buffer_queue(vi, index))) {
 		/* We don't need to enable cb for XDP */
@@ -1490,10 +1579,28 @@
 
 	txq = netdev_get_tx_queue(vi->dev, index);
 	__netif_tx_lock(txq, raw_smp_processor_id());
+	virtqueue_disable_cb(sq->vq);
 	free_old_xmit_skbs(sq, true);
+
+	opaque = virtqueue_enable_cb_prepare(sq->vq);
+
+	done = napi_complete_done(napi, 0);
+
+	if (!done)
+		virtqueue_disable_cb(sq->vq);
+
 	__netif_tx_unlock(txq);
 
-	virtqueue_napi_complete(napi, sq->vq, 0);
+	if (done) {
+		if (unlikely(virtqueue_poll(sq->vq, opaque))) {
+			if (napi_schedule_prep(napi)) {
+				__netif_tx_lock(txq, raw_smp_processor_id());
+				virtqueue_disable_cb(sq->vq);
+				__netif_tx_unlock(txq);
+				__napi_schedule(napi);
+			}
+		}
+	}
 
 	if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
 		netif_tx_wake_queue(txq);
@@ -1525,7 +1632,7 @@
 	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
 				    virtio_is_little_endian(vi->vdev), false,
 				    0))
-		BUG();
+		return -EPROTO;
 
 	if (vi->mergeable_rx_bufs)
 		hdr->num_buffers = 0;
@@ -1801,12 +1908,14 @@
 	struct virtnet_info *vi = netdev_priv(dev);
 	int i;
 
+	/* Make sure NAPI doesn't schedule refill work */
+	disable_delayed_refill(vi);
 	/* Make sure refill_work doesn't re-enable napi! */
 	cancel_delayed_work_sync(&vi->refill);
 
 	for (i = 0; i < vi->max_queue_pairs; i++) {
-		xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq);
 		napi_disable(&vi->rq[i].napi);
+		xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq);
 		virtnet_napi_tx_disable(&vi->sq[i].napi);
 	}
 
@@ -2065,14 +2174,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;
 }
 
@@ -2314,7 +2425,6 @@
 static void virtnet_freeze_down(struct virtio_device *vdev)
 {
 	struct virtnet_info *vi = vdev->priv;
-	int i;
 
 	/* Make sure no work handler is accessing the device */
 	flush_work(&vi->config_work);
@@ -2322,14 +2432,8 @@
 	netif_tx_lock_bh(vi->dev);
 	netif_device_detach(vi->dev);
 	netif_tx_unlock_bh(vi->dev);
-	cancel_delayed_work_sync(&vi->refill);
-
-	if (netif_running(vi->dev)) {
-		for (i = 0; i < vi->max_queue_pairs; i++) {
-			napi_disable(&vi->rq[i].napi);
-			virtnet_napi_tx_disable(&vi->sq[i].napi);
-		}
-	}
+	if (netif_running(vi->dev))
+		virtnet_close(vi->dev);
 }
 
 static int init_vqs(struct virtnet_info *vi);
@@ -2337,7 +2441,7 @@
 static int virtnet_restore_up(struct virtio_device *vdev)
 {
 	struct virtnet_info *vi = vdev->priv;
-	int err, i;
+	int err;
 
 	err = init_vqs(vi);
 	if (err)
@@ -2345,16 +2449,12 @@
 
 	virtio_device_ready(vdev);
 
-	if (netif_running(vi->dev)) {
-		for (i = 0; i < vi->curr_queue_pairs; i++)
-			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
-				schedule_delayed_work(&vi->refill, 0);
+	enable_delayed_refill(vi);
 
-		for (i = 0; i < vi->max_queue_pairs; i++) {
-			virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
-			virtnet_napi_tx_enable(vi, vi->sq[i].vq,
-					       &vi->sq[i].napi);
-		}
+	if (netif_running(vi->dev)) {
+		err = virtnet_open(vi->dev);
+		if (err)
+			return err;
 	}
 
 	netif_tx_lock_bh(vi->dev);
@@ -2414,7 +2514,7 @@
 	        virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
 		virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO) ||
 		virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))) {
-		NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO/CSUM, disable LRO/CSUM first");
+		NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing GRO_HW/CSUM, disable GRO_HW/CSUM first");
 		return -EOPNOTSUPP;
 	}
 
@@ -2435,10 +2535,9 @@
 
 	/* XDP requires extra queues for XDP_TX */
 	if (curr_qp + xdp_qp > vi->max_queue_pairs) {
-		NL_SET_ERR_MSG_MOD(extack, "Too few free TX rings available");
-		netdev_warn(dev, "request %i queues but max is %i\n",
+		netdev_warn(dev, "XDP request %i queues but max is %i. XDP_TX and XDP_REDIRECT will operate in a slower locked tx mode.\n",
 			    curr_qp + xdp_qp, vi->max_queue_pairs);
-		return -ENOMEM;
+		xdp_qp = 0;
 	}
 
 	old_prog = rtnl_dereference(vi->rq[0].xdp_prog);
@@ -2475,11 +2574,14 @@
 	vi->xdp_queue_pairs = xdp_qp;
 
 	if (prog) {
+		vi->xdp_enabled = true;
 		for (i = 0; i < vi->max_queue_pairs; i++) {
 			rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
 			if (i == 0 && !old_prog)
 				virtnet_clear_guest_offloads(vi);
 		}
+	} else {
+		vi->xdp_enabled = false;
 	}
 
 	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -2563,14 +2665,15 @@
 	u64 offloads;
 	int err;
 
-	if ((dev->features ^ features) & NETIF_F_LRO) {
-		if (vi->xdp_queue_pairs)
+	if ((dev->features ^ features) & NETIF_F_GRO_HW) {
+		if (vi->xdp_enabled)
 			return -EBUSY;
 
-		if (features & NETIF_F_LRO)
+		if (features & NETIF_F_GRO_HW)
 			offloads = vi->guest_offloads_capable;
 		else
-			offloads = 0;
+			offloads = vi->guest_offloads_capable &
+				   ~GUEST_OFFLOAD_GRO_HW_MASK;
 
 		err = virtnet_set_guest_offloads(vi, offloads);
 		if (err)
@@ -2689,6 +2792,27 @@
 			put_page(vi->rq[i].alloc_frag.page);
 }
 
+static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
+{
+	if (!is_xdp_frame(buf))
+		dev_kfree_skb(buf);
+	else
+		xdp_return_frame(ptr_to_xdp(buf));
+}
+
+static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf)
+{
+	struct virtnet_info *vi = vq->vdev->priv;
+	int i = vq2rxq(vq);
+
+	if (vi->mergeable_rx_bufs)
+		put_page(virt_to_head_page(buf));
+	else if (vi->big_packets)
+		give_pages(&vi->rq[i], buf);
+	else
+		put_page(virt_to_head_page(buf));
+}
+
 static void free_unused_bufs(struct virtnet_info *vi)
 {
 	void *buf;
@@ -2696,26 +2820,16 @@
 
 	for (i = 0; i < vi->max_queue_pairs; i++) {
 		struct virtqueue *vq = vi->sq[i].vq;
-		while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-			if (!is_xdp_frame(buf))
-				dev_kfree_skb(buf);
-			else
-				xdp_return_frame(ptr_to_xdp(buf));
-		}
+		while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
+			virtnet_sq_free_unused_buf(vq, buf);
+		cond_resched();
 	}
 
 	for (i = 0; i < vi->max_queue_pairs; i++) {
 		struct virtqueue *vq = vi->rq[i].vq;
-
-		while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-			if (vi->mergeable_rx_bufs) {
-				put_page(virt_to_head_page(buf));
-			} else if (vi->big_packets) {
-				give_pages(&vi->rq[i], buf);
-			} else {
-				put_page(virt_to_head_page(buf));
-			}
-		}
+		while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
+			virtnet_rq_free_unused_buf(vq, buf);
+		cond_resched();
 	}
 }
 
@@ -2750,10 +2864,11 @@
 {
 	vq_callback_t **callbacks;
 	struct virtqueue **vqs;
-	int ret = -ENOMEM;
-	int i, total_vqs;
 	const char **names;
+	int ret = -ENOMEM;
+	int total_vqs;
 	bool *ctx;
+	u16 i;
 
 	/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
 	 * possible N-1 RX/TX queue pairs used in multiqueue mode, followed by
@@ -2790,8 +2905,8 @@
 	for (i = 0; i < vi->max_queue_pairs; i++) {
 		callbacks[rxq2vq(i)] = skb_recv_done;
 		callbacks[txq2vq(i)] = skb_xmit_done;
-		sprintf(vi->rq[i].name, "input.%d", i);
-		sprintf(vi->sq[i].name, "output.%d", i);
+		sprintf(vi->rq[i].name, "input.%u", i);
+		sprintf(vi->sq[i].name, "output.%u", i);
 		names[rxq2vq(i)] = vi->rq[i].name;
 		names[txq2vq(i)] = vi->sq[i].name;
 		if (ctx)
@@ -3046,9 +3161,9 @@
 		dev->features |= NETIF_F_RXCSUM;
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6))
-		dev->features |= NETIF_F_LRO;
+		dev->features |= NETIF_F_GRO_HW;
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS))
-		dev->hw_features |= NETIF_F_LRO;
+		dev->hw_features |= NETIF_F_GRO_HW;
 
 	dev->vlan_features = dev->features;
 
@@ -3071,6 +3186,7 @@
 	vdev->priv = vi;
 
 	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+	spin_lock_init(&vi->refill_lock);
 
 	/* If we can receive ANY GSO packets, we must allocate large ones. */
 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
@@ -3106,6 +3222,7 @@
 			dev_err(&vdev->dev,
 				"device MTU appears to have changed it is now %d < %d",
 				mtu, dev->min_mtu);
+			err = -EINVAL;
 			goto free;
 		}
 
@@ -3149,22 +3266,28 @@
 		}
 	}
 
-	err = register_netdev(dev);
+	/* serialize netdev register + virtio_device_ready() with ndo_open() */
+	rtnl_lock();
+
+	err = register_netdevice(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
+		rtnl_unlock();
 		goto free_failover;
 	}
 
 	virtio_device_ready(vdev);
 
+	_virtnet_set_queues(vi, vi->curr_queue_pairs);
+
+	rtnl_unlock();
+
 	err = virtnet_cpu_notif_add(vi);
 	if (err) {
 		pr_debug("virtio_net: registering cpu notifier failed\n");
 		goto free_unregister_netdev;
 	}
 
-	virtnet_set_queues(vi, vi->curr_queue_pairs);
-
 	/* Assume link up if device can't report link status,
 	   otherwise get link status from config. */
 	netif_carrier_off(dev);
@@ -3255,8 +3378,11 @@
 	virtnet_set_queues(vi, vi->curr_queue_pairs);
 
 	err = virtnet_cpu_notif_add(vi);
-	if (err)
+	if (err) {
+		virtnet_freeze_down(vdev);
+		remove_vq_common(vi);
 		return err;
+	}
 
 	return 0;
 }
--- linux-ein-5.4.0.orig/drivers/net/vmxnet3/vmxnet3_drv.c
+++ linux-ein-5.4.0/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -595,6 +595,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;
 				}
@@ -619,6 +620,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;
 				}
@@ -861,7 +863,8 @@
 
 			switch (protocol) {
 			case IPPROTO_TCP:
-				ctx->l4_hdr_size = tcp_hdrlen(skb);
+				ctx->l4_hdr_size = skb->encapsulation ? inner_tcp_hdrlen(skb) :
+						   tcp_hdrlen(skb);
 				break;
 			case IPPROTO_UDP:
 				ctx->l4_hdr_size = sizeof(struct udphdr);
@@ -1583,6 +1586,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
@@ -3633,7 +3640,6 @@
 	vmxnet3_free_intr_resources(adapter);
 
 	netif_device_detach(netdev);
-	netif_tx_stop_all_queues(netdev);
 
 	/* Create wake-up filters. */
 	pmConf = adapter->pm_conf;
--- linux-ein-5.4.0.orig/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ linux-ein-5.4.0/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -702,6 +702,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-ein-5.4.0.orig/drivers/net/vrf.c
+++ linux-ein-5.4.0/drivers/net/vrf.c
@@ -33,6 +33,7 @@
 #include <net/l3mdev.h>
 #include <net/fib_rules.h>
 #include <net/netns/generic.h>
+#include <net/netfilter/nf_conntrack.h>
 
 #define DRV_NAME	"vrf"
 #define DRV_VERSION	"1.0"
@@ -147,12 +148,26 @@
 	return NETDEV_TX_OK;
 }
 
+static void vrf_nf_set_untracked(struct sk_buff *skb)
+{
+	if (skb_get_nfct(skb) == 0)
+		nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
+}
+
+static void vrf_nf_reset_ct(struct sk_buff *skb)
+{
+	if (skb_get_nfct(skb) == IP_CT_UNTRACKED)
+		nf_reset_ct(skb);
+}
+
 #if IS_ENABLED(CONFIG_IPV6)
 static int vrf_ip6_local_out(struct net *net, struct sock *sk,
 			     struct sk_buff *skb)
 {
 	int err;
 
+	vrf_nf_reset_ct(skb);
+
 	err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net,
 		      sk, skb, NULL, skb_dst(skb)->dev, dst_output);
 
@@ -188,8 +203,8 @@
 	fl6.flowi6_proto = iph->nexthdr;
 	fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
 
-	dst = ip6_route_output(net, NULL, &fl6);
-	if (dst == dst_null)
+	dst = ip6_dst_lookup_flow(net, NULL, &fl6, NULL);
+	if (IS_ERR(dst) || dst == dst_null)
 		goto err;
 
 	skb_dst_drop(skb);
@@ -206,6 +221,7 @@
 	/* strip the ethernet header added for pass through VRF device */
 	__skb_pull(skb, skb_network_offset(skb));
 
+	memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
 	ret = vrf_ip6_local_out(net, skb->sk, skb);
 	if (unlikely(net_xmit_eval(ret)))
 		dev->stats.tx_errors++;
@@ -232,6 +248,8 @@
 {
 	int err;
 
+	vrf_nf_reset_ct(skb);
+
 	err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
 		      skb, NULL, skb_dst(skb)->dev, dst_output);
 	if (likely(err == 1))
@@ -287,6 +305,7 @@
 					       RT_SCOPE_LINK);
 	}
 
+	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 	ret = vrf_ip_local_out(dev_net(skb_dst(skb)->dev), skb->sk, skb);
 	if (unlikely(net_xmit_eval(ret)))
 		vrf_dev->stats.tx_errors++;
@@ -332,8 +351,7 @@
 	return ret;
 }
 
-static int vrf_finish_direct(struct net *net, struct sock *sk,
-			     struct sk_buff *skb)
+static void vrf_finish_direct(struct sk_buff *skb)
 {
 	struct net_device *vrf_dev = skb->dev;
 
@@ -352,7 +370,7 @@
 		skb_pull(skb, ETH_HLEN);
 	}
 
-	return 1;
+	vrf_nf_reset_ct(skb);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -366,7 +384,7 @@
 	struct neighbour *neigh;
 	int ret;
 
-	nf_reset_ct(skb);
+	vrf_nf_reset_ct(skb);
 
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
@@ -431,15 +449,41 @@
 	return skb;
 }
 
+static int vrf_output6_direct_finish(struct net *net, struct sock *sk,
+				     struct sk_buff *skb)
+{
+	vrf_finish_direct(skb);
+
+	return vrf_ip6_local_out(net, sk, skb);
+}
+
 static int vrf_output6_direct(struct net *net, struct sock *sk,
 			      struct sk_buff *skb)
 {
+	int err = 1;
+
 	skb->protocol = htons(ETH_P_IPV6);
 
-	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
-			    net, sk, skb, NULL, skb->dev,
-			    vrf_finish_direct,
-			    !(IPCB(skb)->flags & IPSKB_REROUTED));
+	if (!(IPCB(skb)->flags & IPSKB_REROUTED))
+		err = nf_hook(NFPROTO_IPV6, NF_INET_POST_ROUTING, net, sk, skb,
+			      NULL, skb->dev, vrf_output6_direct_finish);
+
+	if (likely(err == 1))
+		vrf_finish_direct(skb);
+
+	return err;
+}
+
+static int vrf_ip6_out_direct_finish(struct net *net, struct sock *sk,
+				     struct sk_buff *skb)
+{
+	int err;
+
+	err = vrf_output6_direct(net, sk, skb);
+	if (likely(err == 1))
+		err = vrf_ip6_local_out(net, sk, skb);
+
+	return err;
 }
 
 static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
@@ -452,18 +496,15 @@
 	skb->dev = vrf_dev;
 
 	err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk,
-		      skb, NULL, vrf_dev, vrf_output6_direct);
+		      skb, NULL, vrf_dev, vrf_ip6_out_direct_finish);
 
 	if (likely(err == 1))
 		err = vrf_output6_direct(net, sk, skb);
 
-	/* reset skb device */
 	if (likely(err == 1))
-		nf_reset_ct(skb);
-	else
-		skb = NULL;
+		return skb;
 
-	return skb;
+	return NULL;
 }
 
 static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
@@ -474,7 +515,10 @@
 	if (rt6_need_strict(&ipv6_hdr(skb)->daddr))
 		return skb;
 
-	if (qdisc_tx_is_default(vrf_dev))
+	vrf_nf_set_untracked(skb);
+
+	if (qdisc_tx_is_default(vrf_dev) ||
+	    IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
 		return vrf_ip6_out_direct(vrf_dev, sk, skb);
 
 	return vrf_ip6_out_redirect(vrf_dev, skb);
@@ -560,7 +604,7 @@
 	bool is_v6gw = false;
 	int ret = -EINVAL;
 
-	nf_reset_ct(skb);
+	vrf_nf_reset_ct(skb);
 
 	/* Be paranoid, rather than too clever. */
 	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
@@ -642,15 +686,41 @@
 	return skb;
 }
 
+static int vrf_output_direct_finish(struct net *net, struct sock *sk,
+				    struct sk_buff *skb)
+{
+	vrf_finish_direct(skb);
+
+	return vrf_ip_local_out(net, sk, skb);
+}
+
 static int vrf_output_direct(struct net *net, struct sock *sk,
 			     struct sk_buff *skb)
 {
+	int err = 1;
+
 	skb->protocol = htons(ETH_P_IP);
 
-	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
-			    net, sk, skb, NULL, skb->dev,
-			    vrf_finish_direct,
-			    !(IPCB(skb)->flags & IPSKB_REROUTED));
+	if (!(IPCB(skb)->flags & IPSKB_REROUTED))
+		err = nf_hook(NFPROTO_IPV4, NF_INET_POST_ROUTING, net, sk, skb,
+			      NULL, skb->dev, vrf_output_direct_finish);
+
+	if (likely(err == 1))
+		vrf_finish_direct(skb);
+
+	return err;
+}
+
+static int vrf_ip_out_direct_finish(struct net *net, struct sock *sk,
+				    struct sk_buff *skb)
+{
+	int err;
+
+	err = vrf_output_direct(net, sk, skb);
+	if (likely(err == 1))
+		err = vrf_ip_local_out(net, sk, skb);
+
+	return err;
 }
 
 static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
@@ -663,18 +733,15 @@
 	skb->dev = vrf_dev;
 
 	err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
-		      skb, NULL, vrf_dev, vrf_output_direct);
+		      skb, NULL, vrf_dev, vrf_ip_out_direct_finish);
 
 	if (likely(err == 1))
 		err = vrf_output_direct(net, sk, skb);
 
-	/* reset skb device */
 	if (likely(err == 1))
-		nf_reset_ct(skb);
-	else
-		skb = NULL;
+		return skb;
 
-	return skb;
+	return NULL;
 }
 
 static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,
@@ -686,7 +753,10 @@
 	    ipv4_is_lbcast(ip_hdr(skb)->daddr))
 		return skb;
 
-	if (qdisc_tx_is_default(vrf_dev))
+	vrf_nf_set_untracked(skb);
+
+	if (qdisc_tx_is_default(vrf_dev) ||
+	    IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
 		return vrf_ip_out_direct(vrf_dev, sk, skb);
 
 	return vrf_ip_out_redirect(vrf_dev, skb);
@@ -860,9 +930,6 @@
 
 	dev->flags = IFF_MASTER | IFF_NOARP;
 
-	/* MTU is irrelevant for VRF device; set to 64k similar to lo */
-	dev->mtu = 64 * 1024;
-
 	/* similarly, oper state is irrelevant; set to up to avoid confusion */
 	dev->operstate = IF_OPER_UP;
 	return 0;
@@ -992,14 +1059,20 @@
 	bool is_ndisc = ipv6_ndisc_frame(skb);
 
 	/* loopback, multicast & non-ND link-local traffic; do not push through
-	 * packet taps again. Reset pkt_type for upper layers to process skb
+	 * packet taps again. Reset pkt_type for upper layers to process skb.
+	 * For strict packets with a source LLA, determine the dst using the
+	 * original ifindex.
 	 */
 	if (skb->pkt_type == PACKET_LOOPBACK || (need_strict && !is_ndisc)) {
 		skb->dev = vrf_dev;
 		skb->skb_iif = vrf_dev->ifindex;
 		IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
+
 		if (skb->pkt_type == PACKET_LOOPBACK)
 			skb->pkt_type = PACKET_HOST;
+		else if (ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)
+			vrf_ip6_input_dst(skb, vrf_dev, orig_iif);
+
 		goto out;
 	}
 
@@ -1289,7 +1362,8 @@
 	 * which breaks networking.
 	 */
 	dev->min_mtu = IPV6_MIN_MTU;
-	dev->max_mtu = ETH_MAX_MTU;
+	dev->max_mtu = IP6_MAX_MTU;
+	dev->mtu = dev->max_mtu;
 }
 
 static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],
--- linux-ein-5.4.0.orig/drivers/net/vxlan.c
+++ linux-ein-5.4.0/drivers/net/vxlan.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/udp.h>
 #include <linux/igmp.h>
+#include <linux/inetdevice.h>
 #include <linux/if_ether.h>
 #include <linux/ethtool.h>
 #include <net/arp.h>
@@ -91,6 +92,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)
@@ -679,11 +841,11 @@
 
 	rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
 	if (rd == NULL)
-		return -ENOBUFS;
+		return -ENOMEM;
 
 	if (dst_cache_init(&rd->dst_cache, GFP_ATOMIC)) {
 		kfree(rd);
-		return -ENOBUFS;
+		return -ENOMEM;
 	}
 
 	rd->remote_ip = *ip;
@@ -698,6 +860,32 @@
 	return 1;
 }
 
+static bool vxlan_parse_gpe_proto(struct vxlanhdr *hdr, __be16 *protocol)
+{
+	struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)hdr;
+
+	/* Need to have Next Protocol set for interfaces in GPE mode. */
+	if (!gpe->np_applied)
+		return false;
+	/* "The initial version is 0. If a receiver does not support the
+	 * version indicated it MUST drop the packet.
+	 */
+	if (gpe->version != 0)
+		return false;
+	/* "When the O bit is set to 1, the packet is an OAM packet and OAM
+	 * processing MUST occur." However, we don't implement OAM
+	 * processing, thus drop the packet.
+	 */
+	if (gpe->oam_flag)
+		return false;
+
+	*protocol = tun_p_to_eth_p(gpe->next_protocol);
+	if (!*protocol)
+		return false;
+
+	return true;
+}
+
 static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
 					  unsigned int off,
 					  struct vxlanhdr *vh, size_t hdrlen,
@@ -1225,6 +1413,7 @@
 	for (h = 0; h < FDB_HASH_SIZE; ++h) {
 		struct vxlan_fdb *f;
 
+		rcu_read_lock();
 		hlist_for_each_entry_rcu(f, &vxlan->fdb_head[h], hlist) {
 			struct vxlan_rdst *rd;
 
@@ -1237,12 +1426,15 @@
 						     cb->nlh->nlmsg_seq,
 						     RTM_NEWNEIGH,
 						     NLM_F_MULTI, rd);
-				if (err < 0)
+				if (err < 0) {
+					rcu_read_unlock();
 					goto out;
+				}
 skip:
 				*idx += 1;
 			}
 		}
+		rcu_read_unlock();
 	}
 out:
 	return err;
@@ -1560,35 +1752,6 @@
 	unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
 }
 
-static bool vxlan_parse_gpe_hdr(struct vxlanhdr *unparsed,
-				__be16 *protocol,
-				struct sk_buff *skb, u32 vxflags)
-{
-	struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)unparsed;
-
-	/* Need to have Next Protocol set for interfaces in GPE mode. */
-	if (!gpe->np_applied)
-		return false;
-	/* "The initial version is 0. If a receiver does not support the
-	 * version indicated it MUST drop the packet.
-	 */
-	if (gpe->version != 0)
-		return false;
-	/* "When the O bit is set to 1, the packet is an OAM packet and OAM
-	 * processing MUST occur." However, we don't implement OAM
-	 * processing, thus drop the packet.
-	 */
-	if (gpe->oam_flag)
-		return false;
-
-	*protocol = tun_p_to_eth_p(gpe->next_protocol);
-	if (!*protocol)
-		return false;
-
-	unparsed->vx_flags &= ~VXLAN_GPE_USED_BITS;
-	return true;
-}
-
 static bool vxlan_set_mac(struct vxlan_dev *vxlan,
 			  struct vxlan_sock *vs,
 			  struct sk_buff *skb, __be32 vni)
@@ -1690,8 +1853,9 @@
 	 * used by VXLAN extensions if explicitly requested.
 	 */
 	if (vs->flags & VXLAN_F_GPE) {
-		if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags))
+		if (!vxlan_parse_gpe_proto(&unparsed, &protocol))
 			goto drop;
+		unparsed.vx_flags &= ~VXLAN_GPE_USED_BITS;
 		raw_proto = true;
 	}
 
@@ -1924,6 +2088,10 @@
 	ns_olen = request->len - skb_network_offset(request) -
 		sizeof(struct ipv6hdr) - 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;
@@ -1987,6 +2155,7 @@
 	struct neighbour *n;
 	struct nd_msg *msg;
 
+	rcu_read_lock();
 	in6_dev = __in6_dev_get(dev);
 	if (!in6_dev)
 		goto out;
@@ -2038,6 +2207,7 @@
 	}
 
 out:
+	rcu_read_unlock();
 	consume_skb(skb);
 	return NETDEV_TX_OK;
 }
@@ -2276,7 +2446,6 @@
 	bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
 	struct dst_entry *ndst;
 	struct flowi6 fl6;
-	int err;
 
 	if (!sock6)
 		return ERR_PTR(-EIO);
@@ -2299,10 +2468,9 @@
 	fl6.fl6_dport = dport;
 	fl6.fl6_sport = sport;
 
-	err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
-					 sock6->sock->sk,
-					 &ndst, &fl6);
-	if (unlikely(err < 0)) {
+	ndst = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net, sock6->sock->sk,
+					       &fl6, NULL);
+	if (unlikely(IS_ERR(ndst))) {
 		netdev_dbg(dev, "no route to %pI6\n", daddr);
 		return ERR_PTR(-ENETUNREACH);
 	}
@@ -2519,6 +2687,13 @@
 			goto 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;
+		}
+
 		if (!info) {
 			/* Bypass encapsulation if the destination is local */
 			err = encap_bypass_if_local(skb, dev, vxlan, dst,
@@ -2542,7 +2717,7 @@
 		}
 
 		ndst = &rt->dst;
-		skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM);
+		skb_tunnel_check_pmtu(skb, ndst, vxlan_headroom(flags & VXLAN_F_GPE));
 
 		tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
 		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
@@ -2582,7 +2757,7 @@
 				goto out_unlock;
 		}
 
-		skb_tunnel_check_pmtu(skb, ndst, VXLAN6_HEADROOM);
+		skb_tunnel_check_pmtu(skb, ndst, vxlan_headroom((flags & VXLAN_F_GPE) | VXLAN_F_IPV6));
 
 		tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
 		ttl = ttl ? : ip6_dst_hoplimit(ndst);
@@ -2615,6 +2790,7 @@
 		dev->stats.tx_carrier_errors++;
 	dst_release(ndst);
 	dev->stats.tx_errors++;
+tx_free:
 	kfree_skb(skb);
 }
 
@@ -2669,6 +2845,20 @@
 #endif
 	}
 
+	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, vni, &fan_rdst, 0);
+		return NETDEV_TX_OK;
+	}
+
 	eth = eth_hdr(skb);
 	f = vxlan_find_mac(vxlan, eth->h_dest, vni);
 	did_rsc = false;
@@ -2781,10 +2971,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;
 }
 
@@ -2852,8 +3051,10 @@
 			if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP)))
 				continue;
 			/* the all_zeros_mac entry is deleted at vxlan_uninit */
-			if (!is_zero_ether_addr(f->eth_addr))
-				vxlan_fdb_destroy(vxlan, f, true, true);
+			if (is_zero_ether_addr(f->eth_addr) &&
+			    f->vni == vxlan->cfg.vni)
+				continue;
+			vxlan_fdb_destroy(vxlan, f, true, true);
 		}
 		spin_unlock_bh(&vxlan->hash_lock[h]);
 	}
@@ -2889,14 +3090,12 @@
 	struct vxlan_rdst *dst = &vxlan->default_dst;
 	struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
 							 dst->remote_ifindex);
-	bool use_ipv6 = !!(vxlan->cfg.flags & VXLAN_F_IPV6);
 
 	/* This check is different than dev->max_mtu, because it looks at
 	 * the lowerdev->mtu, rather than the static dev->max_mtu
 	 */
 	if (lowerdev) {
-		int max_mtu = lowerdev->mtu -
-			      (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
+		int max_mtu = lowerdev->mtu - vxlan_headroom(vxlan->cfg.flags);
 		if (new_mtu > max_mtu)
 			return -EINVAL;
 	}
@@ -3045,12 +3244,12 @@
 
 	vxlan->dev = dev;
 
-	gro_cells_init(&vxlan->gro_cells, dev);
-
 	for (h = 0; h < FDB_HASH_SIZE; ++h) {
 		spin_lock_init(&vxlan->hash_lock[h]);
 		INIT_HLIST_HEAD(&vxlan->fdb_head[h]);
 	}
+
+	INIT_LIST_HEAD(&vxlan->fan.fan_maps);
 }
 
 static void vxlan_ether_setup(struct net_device *dev)
@@ -3139,7 +3338,7 @@
 		u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
 
 		if (id >= VXLAN_N_VID) {
-			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_ID],
+			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_VXLAN_ID],
 					    "VXLAN ID must be lower than 16777216");
 			return -ERANGE;
 		}
@@ -3150,7 +3349,7 @@
 			= nla_data(data[IFLA_VXLAN_PORT_RANGE]);
 
 		if (ntohs(p->high) < ntohs(p->low)) {
-			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_PORT_RANGE],
+			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_VXLAN_PORT_RANGE],
 					    "Invalid source port range");
 			return -EINVAL;
 		}
@@ -3160,7 +3359,7 @@
 		enum ifla_vxlan_df df = nla_get_u8(data[IFLA_VXLAN_DF]);
 
 		if (df < 0 || df > VXLAN_DF_MAX) {
-			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_DF],
+			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_VXLAN_DF],
 					    "Invalid DF attribute");
 			return -EINVAL;
 		}
@@ -3497,11 +3696,11 @@
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_rdst *dst = &vxlan->default_dst;
 	unsigned short needed_headroom = ETH_HLEN;
-	bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6);
 	int max_mtu = ETH_MAX_MTU;
+	u32 flags = conf->flags;
 
 	if (!changelink) {
-		if (conf->flags & VXLAN_F_GPE)
+		if (flags & VXLAN_F_GPE)
 			vxlan_raw_setup(dev);
 		else
 			vxlan_ether_setup(dev);
@@ -3523,9 +3722,11 @@
 		dev->gso_max_segs = lowerdev->gso_max_segs;
 
 		needed_headroom = lowerdev->hard_header_len;
+		needed_headroom += lowerdev->needed_headroom;
+
+		dev->needed_tailroom = lowerdev->needed_tailroom;
 
-		max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
-					   VXLAN_HEADROOM);
+		max_mtu = lowerdev->mtu - vxlan_headroom(flags);
 		if (max_mtu < ETH_MIN_MTU)
 			max_mtu = ETH_MIN_MTU;
 
@@ -3536,10 +3737,9 @@
 	if (dev->mtu > max_mtu)
 		dev->mtu = max_mtu;
 
-	if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
-		needed_headroom += VXLAN6_HEADROOM;
-	else
-		needed_headroom += VXLAN_HEADROOM;
+	if (flags & VXLAN_F_COLLECT_METADATA)
+		flags |= VXLAN_F_IPV6;
+	needed_headroom += vxlan_headroom(flags);
 	dev->needed_headroom = needed_headroom;
 
 	memcpy(&vxlan->cfg, conf, sizeof(*conf));
@@ -3602,8 +3802,10 @@
 
 	if (dst->remote_ifindex) {
 		remote_dev = __dev_get_by_index(net, dst->remote_ifindex);
-		if (!remote_dev)
+		if (!remote_dev) {
+			err = -ENODEV;
 			goto errout;
+		}
 
 		err = netdev_upper_dev_link(remote_dev, dev, extack);
 		if (err)
@@ -3722,6 +3924,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]) {
 		if (changelink && (conf->saddr.sa.sa_family != AF_INET)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "New local address family does not match old");
@@ -4058,6 +4266,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;
 }
 
@@ -4104,6 +4313,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_TTL_INHERIT,
 		       !!(vxlan->cfg.flags & VXLAN_F_TTL_INHERIT)) ||
@@ -4399,12 +4628,27 @@
 	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 vxlan_destroy_tunnels(struct net *net, struct list_head *head)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct vxlan_dev *vxlan, *next;
 	struct net_device *dev, *aux;
-	unsigned int h;
 
 	for_each_netdev_safe(net, dev, aux)
 		if (dev->rtnl_link_ops == &vxlan_link_ops)
@@ -4418,14 +4662,13 @@
 			unregister_netdevice_queue(vxlan->dev, head);
 	}
 
-	for (h = 0; h < PORT_HASH_SIZE; ++h)
-		WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h]));
 }
 
 static void __net_exit vxlan_exit_batch_net(struct list_head *net_list)
 {
 	struct net *net;
 	LIST_HEAD(list);
+	unsigned int h;
 
 	rtnl_lock();
 	list_for_each_entry(net, net_list, exit_list)
@@ -4433,6 +4676,13 @@
 
 	unregister_netdevice_many(&list);
 	rtnl_unlock();
+
+	list_for_each_entry(net, net_list, exit_list) {
+		struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+
+		for (h = 0; h < PORT_HASH_SIZE; ++h)
+			WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h]));
+	}
 }
 
 static struct pernet_operations vxlan_net_ops = {
@@ -4464,7 +4714,20 @@
 	if (rc)
 		goto out4;
 
+#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 */
 out4:
 	unregister_switchdev_notifier(&vxlan_switchdev_notifier_block);
 out3:
@@ -4478,6 +4741,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_switchdev_notifier(&vxlan_switchdev_notifier_block);
 	unregister_netdevice_notifier(&vxlan_notifier_block);
--- linux-ein-5.4.0.orig/drivers/net/wan/Kconfig
+++ linux-ein-5.4.0/drivers/net/wan/Kconfig
@@ -200,7 +200,7 @@
 	depends on WANXL && !PREVENT_FIRMWARE_BUILD
 	help
 	  Allows you to rebuild firmware run by the QUICC processor.
-	  It requires as68k, ld68k and hexdump programs.
+	  It requires m68k toolchains and hexdump programs.
 
 	  You should never need this option, say N.
 
@@ -282,6 +282,7 @@
 	tristate "Slic Maxim ds26522 card support"
 	depends on SPI
 	depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST
+	select BITREVERSE
 	help
 	  This module initializes and configures the slic maxim card
 	  in T1 or E1 mode.
--- linux-ein-5.4.0.orig/drivers/net/wan/Makefile
+++ linux-ein-5.4.0/drivers/net/wan/Makefile
@@ -40,17 +40,17 @@
 
 ifeq ($(CONFIG_WANXL_BUILD_FIRMWARE),y)
 ifeq ($(ARCH),m68k)
-  AS68K = $(AS)
-  LD68K = $(LD)
+  M68KCC = $(CC)
+  M68KLD = $(LD)
 else
-  AS68K = as68k
-  LD68K = ld68k
+  M68KCC = $(CROSS_COMPILE_M68K)gcc
+  M68KLD = $(CROSS_COMPILE_M68K)ld
 endif
 
 quiet_cmd_build_wanxlfw = BLD FW  $@
       cmd_build_wanxlfw = \
-	$(CPP) -D__ASSEMBLY__ -Wp,-MD,$(depfile) -I$(srctree)/include/uapi $< | $(AS68K) -m68360 -o $(obj)/wanxlfw.o; \
-	$(LD68K) --oformat binary -Ttext 0x1000 $(obj)/wanxlfw.o -o $(obj)/wanxlfw.bin; \
+	$(M68KCC) -D__ASSEMBLY__ -Wp,-MD,$(depfile) -I$(srctree)/include/uapi -c -o $(obj)/wanxlfw.o $<; \
+	$(M68KLD) --oformat binary -Ttext 0x1000 $(obj)/wanxlfw.o -o $(obj)/wanxlfw.bin; \
 	hexdump -ve '"\n" 16/1 "0x%02X,"' $(obj)/wanxlfw.bin | sed 's/0x  ,//g;1s/^/static const u8 firmware[]={/;$$s/,$$/\n};\n/' >$(obj)/wanxlfw.inc; \
 	rm -f $(obj)/wanxlfw.bin $(obj)/wanxlfw.o
 
--- linux-ein-5.4.0.orig/drivers/net/wan/cosa.c
+++ linux-ein-5.4.0/drivers/net/wan/cosa.c
@@ -889,6 +889,7 @@
 			chan->tx_status = 1;
 			spin_unlock_irqrestore(&cosa->lock, flags);
 			up(&chan->wsem);
+			kfree(kbuf);
 			return -ERESTARTSYS;
 		}
 	}
--- linux-ein-5.4.0.orig/drivers/net/wan/farsync.c
+++ linux-ein-5.4.0/drivers/net/wan/farsync.c
@@ -569,8 +569,8 @@
 static void fst_process_tx_work_q(unsigned long work_q);
 static void fst_process_int_work_q(unsigned long work_q);
 
-static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0);
-static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0);
+static DECLARE_TASKLET_OLD(fst_tx_task, fst_process_tx_work_q);
+static DECLARE_TASKLET_OLD(fst_int_task, fst_process_int_work_q);
 
 static struct fst_card_info *fst_card_array[FST_MAX_CARDS];
 static spinlock_t fst_work_q_lock;
@@ -2613,6 +2613,7 @@
 	for (i = 0; i < card->nports; i++) {
 		struct net_device *dev = port_to_dev(&card->ports[i]);
 		unregister_hdlc_device(dev);
+		free_netdev(dev);
 	}
 
 	fst_disable_intr(card);
@@ -2633,6 +2634,7 @@
 				    card->tx_dma_handle_card);
 	}
 	fst_card_array[card->card_no] = NULL;
+	kfree(card);
 }
 
 static struct pci_driver fst_driver = {
--- linux-ein-5.4.0.orig/drivers/net/wan/fsl_ucc_hdlc.c
+++ linux-ein-5.4.0/drivers/net/wan/fsl_ucc_hdlc.c
@@ -34,6 +34,8 @@
 #define TDM_PPPOHT_SLIC_MAXIN
 #define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
 
+static int uhdlc_close(struct net_device *dev);
+
 static struct ucc_tdm_info utdm_primary_info = {
 	.uf_info = {
 		.tsa = 0,
@@ -73,7 +75,7 @@
 	},
 };
 
-static struct ucc_tdm_info utdm_info[MAX_HDLC_NUM];
+static struct ucc_tdm_info utdm_info[UCC_MAX_NUM];
 
 static int uhdlc_init(struct ucc_hdlc_private *priv)
 {
@@ -204,14 +206,18 @@
 	priv->rx_skbuff = kcalloc(priv->rx_ring_size,
 				  sizeof(*priv->rx_skbuff),
 				  GFP_KERNEL);
-	if (!priv->rx_skbuff)
+	if (!priv->rx_skbuff) {
+		ret = -ENOMEM;
 		goto free_ucc_pram;
+	}
 
 	priv->tx_skbuff = kcalloc(priv->tx_ring_size,
 				  sizeof(*priv->tx_skbuff),
 				  GFP_KERNEL);
-	if (!priv->tx_skbuff)
+	if (!priv->tx_skbuff) {
+		ret = -ENOMEM;
 		goto free_rx_skbuff;
+	}
 
 	priv->skb_curtx = 0;
 	priv->skb_dirtytx = 0;
@@ -245,6 +251,11 @@
 		ret = -ENOMEM;
 		goto free_riptr;
 	}
+	if (riptr != (u16)riptr || tiptr != (u16)tiptr) {
+		dev_err(priv->dev, "MURAM allocation out of addressable range\n");
+		ret = -ENOMEM;
+		goto free_tiptr;
+	}
 
 	/* Set RIPTR, TIPTR */
 	iowrite16be(riptr, &priv->ucc_pram->riptr);
@@ -701,6 +712,7 @@
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	struct ucc_hdlc_private *priv = hdlc->priv;
 	struct ucc_tdm *utdm = priv->utdm;
+	int rc = 0;
 
 	if (priv->hdlc_busy != 1) {
 		if (request_irq(priv->ut_info->uf_info.irq,
@@ -724,10 +736,13 @@
 		napi_enable(&priv->napi);
 		netdev_reset_queue(dev);
 		netif_start_queue(dev);
-		hdlc_open(dev);
+
+		rc = hdlc_open(dev);
+		if (rc)
+			uhdlc_close(dev);
 	}
 
-	return 0;
+	return rc;
 }
 
 static void uhdlc_memclean(struct ucc_hdlc_private *priv)
@@ -817,6 +832,8 @@
 	netdev_reset_queue(dev);
 	priv->hdlc_busy = 0;
 
+	hdlc_close(dev);
+
 	return 0;
 }
 
@@ -1240,9 +1257,11 @@
 free_dev:
 	free_netdev(dev);
 undo_uhdlc_init:
-	iounmap(utdm->siram);
+	if (utdm)
+		iounmap(utdm->siram);
 unmap_si_regs:
-	iounmap(utdm->si_regs);
+	if (utdm)
+		iounmap(utdm->si_regs);
 free_utdm:
 	if (uhdlc_priv->tsa)
 		kfree(utdm);
--- linux-ein-5.4.0.orig/drivers/net/wan/hdlc.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc.c
@@ -46,7 +46,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-ein-5.4.0.orig/drivers/net/wan/hdlc_cisco.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc_cisco.c
@@ -118,6 +118,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);
@@ -370,6 +371,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;
 		call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
 		netif_dormant_on(dev);
--- linux-ein-5.4.0.orig/drivers/net/wan/hdlc_fr.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc_fr.c
@@ -273,63 +273,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);
@@ -425,14 +431,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;
 		}
@@ -492,10 +500,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);
@@ -555,6 +561,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);
@@ -1041,7 +1048,7 @@
 {
 	dev->type = ARPHRD_DLCI;
 	dev->flags = IFF_POINTOPOINT;
-	dev->hard_header_len = 10;
+	dev->hard_header_len = 0;
 	dev->addr_len = 2;
 	netif_keep_dst(dev);
 }
@@ -1093,6 +1100,7 @@
 	dev->mtu = HDLC_MAX_MTU;
 	dev->min_mtu = 68;
 	dev->max_mtu = HDLC_MAX_MTU;
+	dev->needed_headroom = 10;
 	dev->priv_flags |= IFF_NO_QUEUE;
 	dev->ml_priv = pvc;
 
--- linux-ein-5.4.0.orig/drivers/net/wan/hdlc_ppp.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc_ppp.c
@@ -251,6 +251,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);
 }
@@ -383,11 +384,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]) {
@@ -395,6 +393,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;
@@ -406,6 +406,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 */
@@ -424,6 +426,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)
@@ -562,6 +569,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:
--- linux-ein-5.4.0.orig/drivers/net/wan/hdlc_raw_eth.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc_raw_eth.c
@@ -99,6 +99,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);
 		call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
 		netif_dormant_off(dev);
--- linux-ein-5.4.0.orig/drivers/net/wan/hdlc_x25.c
+++ linux-ein-5.4.0/drivers/net/wan/hdlc_x25.c
@@ -62,10 +62,13 @@
 {
 	unsigned char *ptr;
 
-	skb_push(skb, 1);
-
-	if (skb_cow(skb, 1))
+	if (skb_cow(skb, 1)) {
+		kfree_skb(skb);
 		return NET_RX_DROP;
+	}
+
+	skb_push(skb, 1);
+	skb_reset_network_header(skb);
 
 	ptr  = skb->data;
 	*ptr = X25_IFACE_DATA;
@@ -79,6 +82,13 @@
 static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+	skb_reset_network_header(skb);
+	skb->protocol = hdlc_type_trans(skb, dev);
+
+	if (dev_nit_active(dev))
+		dev_queue_xmit_nit(skb, dev);
+
 	hdlc->xmit(skb, dev); /* Ignore return value :-( */
 }
 
@@ -93,6 +103,7 @@
 	switch (skb->data[0]) {
 	case X25_IFACE_DATA:	/* Data to be transmitted */
 		skb_pull(skb, 1);
+		skb_reset_network_header(skb);
 		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
 			dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
--- linux-ein-5.4.0.orig/drivers/net/wan/ixp4xx_hss.c
+++ linux-ein-5.4.0/drivers/net/wan/ixp4xx_hss.c
@@ -258,7 +258,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;
@@ -858,7 +858,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-ein-5.4.0.orig/drivers/net/wan/lapbether.c
+++ linux-ein-5.4.0/drivers/net/wan/lapbether.c
@@ -51,6 +51,8 @@
 	struct list_head	node;
 	struct net_device	*ethdev;	/* link to ethernet device */
 	struct net_device	*axdev;		/* lapbeth device (lapb#) */
+	bool			up;
+	spinlock_t		up_lock;	/* Protects "up" */
 };
 
 static LIST_HEAD(lapbeth_devices);
@@ -98,8 +100,9 @@
 	rcu_read_lock();
 	lapbeth = lapbeth_get_x25_dev(dev);
 	if (!lapbeth)
-		goto drop_unlock;
-	if (!netif_running(lapbeth->axdev))
+		goto drop_unlock_rcu;
+	spin_lock_bh(&lapbeth->up_lock);
+	if (!lapbeth->up)
 		goto drop_unlock;
 
 	len = skb->data[0] + skb->data[1] * 256;
@@ -114,11 +117,14 @@
 		goto drop_unlock;
 	}
 out:
+	spin_unlock_bh(&lapbeth->up_lock);
 	rcu_read_unlock();
 	return 0;
 drop_unlock:
 	kfree_skb(skb);
 	goto out;
+drop_unlock_rcu:
+	rcu_read_unlock();
 drop:
 	kfree_skb(skb);
 	return 0;
@@ -128,10 +134,12 @@
 {
 	unsigned char *ptr;
 
-	skb_push(skb, 1);
-
-	if (skb_cow(skb, 1))
+	if (skb_cow(skb, 1)) {
+		kfree_skb(skb);
 		return NET_RX_DROP;
+	}
+
+	skb_push(skb, 1);
 
 	ptr  = skb->data;
 	*ptr = X25_IFACE_DATA;
@@ -146,13 +154,17 @@
 static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
 				      struct net_device *dev)
 {
+	struct lapbethdev *lapbeth = netdev_priv(dev);
 	int err;
 
-	/*
-	 * Just to be *really* sure not to send anything if the interface
-	 * is down, the ethernet device may have gone.
+	spin_lock_bh(&lapbeth->up_lock);
+	if (!lapbeth->up)
+		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 (!netif_running(dev))
+	if (skb->len < 1)
 		goto drop;
 
 	switch (skb->data[0]) {
@@ -177,6 +189,7 @@
 		goto drop;
 	}
 out:
+	spin_unlock_bh(&lapbeth->up_lock);
 	return NETDEV_TX_OK;
 drop:
 	kfree_skb(skb);
@@ -190,8 +203,6 @@
 	struct net_device *dev;
 	int size = skb->len;
 
-	skb->protocol = htons(ETH_P_X25);
-
 	ptr = skb_push(skb, 2);
 
 	*ptr++ = size % 256;
@@ -202,6 +213,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);
@@ -266,6 +281,7 @@
  */
 static int lapbeth_open(struct net_device *dev)
 {
+	struct lapbethdev *lapbeth = netdev_priv(dev);
 	int err;
 
 	if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) {
@@ -273,15 +289,21 @@
 		return -ENODEV;
 	}
 
-	netif_start_queue(dev);
+	spin_lock_bh(&lapbeth->up_lock);
+	lapbeth->up = true;
+	spin_unlock_bh(&lapbeth->up_lock);
+
 	return 0;
 }
 
 static int lapbeth_close(struct net_device *dev)
 {
+	struct lapbethdev *lapbeth = netdev_priv(dev);
 	int err;
 
-	netif_stop_queue(dev);
+	spin_lock_bh(&lapbeth->up_lock);
+	lapbeth->up = false;
+	spin_unlock_bh(&lapbeth->up_lock);
 
 	if ((err = lapb_unregister(dev)) != LAPB_OK)
 		pr_err("lapb_unregister error: %d\n", err);
@@ -303,7 +325,7 @@
 	dev->netdev_ops	     = &lapbeth_netdev_ops;
 	dev->needs_free_netdev = true;
 	dev->type            = ARPHRD_X25;
-	dev->hard_header_len = 3;
+	dev->hard_header_len = 0;
 	dev->mtu             = 1000;
 	dev->addr_len        = 0;
 }
@@ -319,17 +341,33 @@
 
 	ASSERT_RTNL();
 
+	if (dev->type != ARPHRD_ETHER)
+		return -EINVAL;
+
 	ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
 			    lapbeth_setup);
 	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;
 
 	dev_hold(dev);
 	lapbeth->ethdev = dev;
 
+	lapbeth->up = false;
+	spin_lock_init(&lapbeth->up_lock);
+
 	rc = -EIO;
 	if (register_netdevice(ndev))
 		goto fail;
@@ -368,7 +406,7 @@
 	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
-	if (!dev_is_ethdev(dev))
+	if (!dev_is_ethdev(dev) && !lapbeth_get_x25_dev(dev))
 		return NOTIFY_DONE;
 
 	switch (event) {
--- linux-ein-5.4.0.orig/drivers/net/wan/lmc/lmc_main.c
+++ linux-ein-5.4.0/drivers/net/wan/lmc/lmc_main.c
@@ -912,6 +912,8 @@
         break;
     default:
 	printk(KERN_WARNING "%s: LMC UNKNOWN CARD!\n", dev->name);
+	unregister_hdlc_device(dev);
+	return -EIO;
         break;
     }
 
--- linux-ein-5.4.0.orig/drivers/net/wan/lmc/lmc_proto.c
+++ linux-ein-5.4.0/drivers/net/wan/lmc/lmc_proto.c
@@ -101,17 +101,13 @@
     switch(sc->if_type){
     case LMC_PPP:
 	    return hdlc_type_trans(skb, sc->lmc_device);
-	    break;
     case LMC_NET:
         return htons(ETH_P_802_2);
-        break;
     case LMC_RAW: /* Packet type for skbuff kind of useless */
         return htons(ETH_P_802_2);
-        break;
     default:
         printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name);
         return htons(ETH_P_802_2);
-        break;
     }
     lmc_trace(sc->lmc_device, "lmc_proto_tye out");
 
--- linux-ein-5.4.0.orig/drivers/net/wan/sdla.c
+++ linux-ein-5.4.0/drivers/net/wan/sdla.c
@@ -708,7 +708,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-ein-5.4.0.orig/drivers/net/wan/x25_asy.c
+++ linux-ein-5.4.0/drivers/net/wan/x25_asy.c
@@ -183,7 +183,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)
 {
@@ -195,13 +195,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 */
 	skb_put_data(skb, sl->rbuff, count);
 	skb->protocol = x25_type_trans(skb, sl->dev);
 	err = lapb_data_received(skb->dev, skb);
@@ -209,7 +208,6 @@
 		kfree_skb(skb);
 		printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
 	} else {
-		netif_rx(skb);
 		dev->stats.rx_packets++;
 	}
 }
@@ -356,12 +354,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);
 }
 
@@ -657,7 +664,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-ein-5.4.0.orig/drivers/net/wan/z85230.c
+++ linux-ein-5.4.0/drivers/net/wan/z85230.c
@@ -702,7 +702,7 @@
 irqreturn_t z8530_interrupt(int irq, void *dev_id)
 {
 	struct z8530_dev *dev=dev_id;
-	u8 uninitialized_var(intr);
+	u8 intr;
 	static volatile int locker=0;
 	int work=0;
 	struct z8530_irqhandler *irqs;
--- linux-ein-5.4.0.orig/drivers/net/wimax/i2400m/op-rfkill.c
+++ linux-ein-5.4.0/drivers/net/wimax/i2400m/op-rfkill.c
@@ -86,7 +86,7 @@
 	if (cmd == NULL)
 		goto error_alloc;
 	cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_RF_CONTROL);
-	cmd->hdr.length = sizeof(cmd->sw_rf);
+	cmd->hdr.length = cpu_to_le16(sizeof(cmd->sw_rf));
 	cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
 	cmd->sw_rf.hdr.type = cpu_to_le16(I2400M_TLV_RF_OPERATION);
 	cmd->sw_rf.hdr.length = cpu_to_le16(sizeof(cmd->sw_rf.status));
--- linux-ein-5.4.0.orig/drivers/net/wimax/i2400m/usb-fw.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/wireless/ath/ar5523/ar5523.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -153,6 +153,10 @@
 			ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START");
 			return;
 		}
+		if (!cmd->odata) {
+			ar5523_err(ar, "Unexpected WDCMSG_TARGET_START reply");
+			return;
+		}
 		memcpy(cmd->odata, hdr + 1, sizeof(u32));
 		cmd->olen = sizeof(u32);
 		cmd->res = 0;
@@ -237,6 +241,11 @@
 	}
 }
 
+static void ar5523_cancel_tx_cmd(struct ar5523 *ar)
+{
+	usb_kill_urb(ar->tx_cmd.urb_tx);
+}
+
 static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata,
 		      int ilen, void *odata, int olen, int flags)
 {
@@ -255,7 +264,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;
@@ -275,6 +285,7 @@
 	}
 
 	if (!wait_for_completion_timeout(&cmd->done, 2 * HZ)) {
+		ar5523_cancel_tx_cmd(ar);
 		cmd->odata = NULL;
 		ar5523_err(ar, "timeout waiting for command %02x reply\n",
 			   code);
@@ -1769,6 +1780,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath.h
@@ -197,12 +197,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/ce.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/ce.c
@@ -1299,29 +1299,24 @@
 	struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
 	u32 ctrl_addr = ce_state->ctrl_addr;
 
-	spin_lock_bh(&ce->ce_lock);
-
-	/* Clear the copy-complete interrupts that will be handled here. */
+	/*
+	 * Clear before handling
+	 *
+	 * Misc CE interrupts are not being handled, but still need
+	 * to be cleared.
+	 *
+	 * NOTE: When the last copy engine interrupt is cleared the
+	 * hardware will go to sleep.  Once this happens any access to
+	 * the CE registers can cause a hardware fault.
+	 */
 	ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
-					  wm_regs->cc_mask);
-
-	spin_unlock_bh(&ce->ce_lock);
+					  wm_regs->cc_mask | wm_regs->wm_mask);
 
 	if (ce_state->recv_cb)
 		ce_state->recv_cb(ce_state);
 
 	if (ce_state->send_cb)
 		ce_state->send_cb(ce_state);
-
-	spin_lock_bh(&ce->ce_lock);
-
-	/*
-	 * Misc CE interrupts are not being handled, but still need
-	 * to be cleared.
-	 */
-	ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask);
-
-	spin_unlock_bh(&ce->ce_lock);
 }
 EXPORT_SYMBOL(ath10k_ce_per_engine_service);
 
@@ -1372,45 +1367,55 @@
 	ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 }
 
-int ath10k_ce_disable_interrupts(struct ath10k *ar)
+void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id)
 {
 	struct ath10k_ce *ce = ath10k_ce_priv(ar);
 	struct ath10k_ce_pipe *ce_state;
 	u32 ctrl_addr;
-	int ce_id;
 
-	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
-		ce_state  = &ce->ce_states[ce_id];
-		if (ce_state->attr_flags & CE_ATTR_POLL)
-			continue;
+	ce_state  = &ce->ce_states[ce_id];
+	if (ce_state->attr_flags & CE_ATTR_POLL)
+		return;
 
-		ctrl_addr = ath10k_ce_base_address(ar, ce_id);
+	ctrl_addr = ath10k_ce_base_address(ar, ce_id);
 
-		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
-		ath10k_ce_error_intr_disable(ar, ctrl_addr);
-		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
-	}
+	ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
+	ath10k_ce_error_intr_disable(ar, ctrl_addr);
+	ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
+}
+EXPORT_SYMBOL(ath10k_ce_disable_interrupt);
 
-	return 0;
+void ath10k_ce_disable_interrupts(struct ath10k *ar)
+{
+	int ce_id;
+
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+		ath10k_ce_disable_interrupt(ar, ce_id);
 }
 EXPORT_SYMBOL(ath10k_ce_disable_interrupts);
 
-void ath10k_ce_enable_interrupts(struct ath10k *ar)
+void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id)
 {
 	struct ath10k_ce *ce = ath10k_ce_priv(ar);
-	int ce_id;
 	struct ath10k_ce_pipe *ce_state;
 
+	ce_state  = &ce->ce_states[ce_id];
+	if (ce_state->attr_flags & CE_ATTR_POLL)
+		return;
+
+	ath10k_ce_per_engine_handler_adjust(ce_state);
+}
+EXPORT_SYMBOL(ath10k_ce_enable_interrupt);
+
+void ath10k_ce_enable_interrupts(struct ath10k *ar)
+{
+	int ce_id;
+
 	/* Enable interrupts for copy engine that
 	 * are not using polling mode.
 	 */
-	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
-		ce_state  = &ce->ce_states[ce_id];
-		if (ce_state->attr_flags & CE_ATTR_POLL)
-			continue;
-
-		ath10k_ce_per_engine_handler_adjust(ce_state);
-	}
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+		ath10k_ce_enable_interrupt(ar, ce_id);
 }
 EXPORT_SYMBOL(ath10k_ce_enable_interrupts);
 
@@ -1555,7 +1560,7 @@
 		ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries);
 		if (ret) {
 			dma_free_coherent(ar->dev,
-					  (nentries * sizeof(struct ce_desc_64) +
+					  (nentries * sizeof(struct ce_desc) +
 					   CE_DESC_RING_ALIGN),
 					  src_ring->base_addr_owner_space_unaligned,
 					  base_addr);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/ce.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/ce.h
@@ -255,10 +255,13 @@
 /*==================CE Interrupt Handlers====================*/
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
-int ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id);
+void ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id);
 void ath10k_ce_enable_interrupts(struct ath10k *ar);
 void ath10k_ce_dump_registers(struct ath10k *ar,
 			      struct ath10k_fw_crash_data *crash_data);
+
 void ath10k_ce_alloc_rri(struct ath10k *ar);
 void ath10k_ce_free_rri(struct ath10k *ar);
 
@@ -369,18 +372,14 @@
 	(((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \
 		CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
 #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS			0x0000
-#define CE_INTERRUPT_SUMMARY		(GENMASK(CE_COUNT_MAX - 1, 0))
 
 static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar)
 {
 	struct ath10k_ce *ce = ath10k_ce_priv(ar);
 
-	if (!ar->hw_params.per_ce_irq)
-		return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(
-			ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
-			CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
-	else
-		return CE_INTERRUPT_SUMMARY;
+	return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(
+		ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
+		CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
 }
 
 /* Host software's Copy Engine configuration. */
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/core.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/core.c
@@ -118,7 +118,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -154,7 +153,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -217,7 +215,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -252,7 +249,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -287,7 +283,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -325,7 +320,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -366,7 +360,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -414,7 +407,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -459,7 +451,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -494,7 +485,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -531,7 +521,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -539,6 +528,33 @@
 		.tx_stats_over_pktlog = false,
 	},
 	{
+		.id = QCA9377_HW_1_1_DEV_VERSION,
+		.dev_id = QCA9377_1_0_DEVICE_ID,
+		.bus = ATH10K_BUS_SDIO,
+		.name = "qca9377 hw1.1 sdio",
+		.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+		.uart_pin = 19,
+		.otp_exe_param = 0,
+		.channel_counters_freq_hz = 88000,
+		.max_probe_resp_desc_thres = 0,
+		.cal_data_len = 8124,
+		.fw = {
+			.dir = QCA9377_HW_1_0_FW_DIR,
+			.board = QCA9377_HW_1_0_BOARD_DATA_FILE,
+			.board_size = QCA9377_BOARD_DATA_SZ,
+			.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+		},
+		.hw_ops = &qca6174_ops,
+		.hw_clk = qca6174_clk,
+		.target_cpu_freq = 176000000,
+		.decap_align_bytes = 4,
+		.n_cipher_suites = 8,
+		.num_peers = TARGET_QCA9377_HL_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
+		.uart_pin_workaround = true,
+	},
+	{
 		.id = QCA4019_HW_1_0_DEV_VERSION,
 		.dev_id = 0,
 		.bus = ATH10K_BUS_AHB,
@@ -573,7 +589,6 @@
 		.num_wds_entries = 0x20,
 		.target_64bit = false,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
-		.per_ce_irq = false,
 		.shadow_reg_support = false,
 		.rri_on_ddr = false,
 		.hw_filter_reset_required = true,
@@ -601,7 +616,6 @@
 		.num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES,
 		.target_64bit = true,
 		.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC,
-		.per_ce_irq = true,
 		.shadow_reg_support = true,
 		.rri_on_ddr = true,
 		.hw_filter_reset_required = false,
@@ -2157,7 +2171,7 @@
 
 static int ath10k_init_hw_params(struct ath10k *ar)
 {
-	const struct ath10k_hw_params *uninitialized_var(hw_params);
+	const struct ath10k_hw_params *hw_params;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
@@ -2953,7 +2967,8 @@
 		ath10k_debug_print_board_info(ar);
 	}
 
-	device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr));
+	if (is_zero_ether_addr(ar->mac_addr))
+		device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr));
 
 	ret = ath10k_core_init_firmware_features(ar);
 	if (ret) {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/core.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/core.h
@@ -969,6 +969,11 @@
 	u32 low_5ghz_chan;
 	u32 high_5ghz_chan;
 	bool ani_enabled;
+	u32 sys_cap_info;
+
+	/* protected by data_lock */
+	bool hw_rfkill_on;
+
 	/* protected by conf_mutex */
 	u8 ps_state_enable;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/coredump.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/coredump.c
@@ -1208,9 +1208,11 @@
 		dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
 		dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA);
 		dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len);
-		memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
-		       crash_data->ramdump_buf_len);
-		sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+		if (crash_data->ramdump_buf_len) {
+			memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
+			       crash_data->ramdump_buf_len);
+			sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+		}
 	}
 
 	mutex_unlock(&ar->dump_mutex);
@@ -1257,6 +1259,9 @@
 	if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
 		crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar);
 
+		if (!crash_data->ramdump_buf_len)
+			return 0;
+
 		crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len);
 		if (!crash_data->ramdump_buf)
 			return -ENOMEM;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/debug.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/debug.c
@@ -1138,7 +1138,7 @@
 				 u32 sset, u8 *data)
 {
 	if (sset == ETH_SS_STATS)
-		memcpy(data, *ath10k_gstrings_stats,
+		memcpy(data, ath10k_gstrings_stats,
 		       sizeof(ath10k_gstrings_stats));
 }
 
@@ -1516,7 +1516,7 @@
 	*len += scnprintf(buf + *len, buf_len - *len,
 			  "No.  Preamble Rate_code ");
 
-	for (i = 0; i < WMI_TPC_TX_N_CHAIN; i++)
+	for (i = 0; i < tpc_stats->num_tx_chain; i++)
 		*len += scnprintf(buf + *len, buf_len - *len,
 				  "tpc_value%d ", i);
 
@@ -1737,11 +1737,17 @@
 	return ret;
 }
 
+static bool ath10k_skip_cal_data(struct ath10k *ar)
+{
+	return (ar->hif.bus == ATH10K_BUS_SDIO &&
+		ar->cal_mode == ATH10K_CAL_MODE_OTP);
+}
+
 void ath10k_debug_stop(struct ath10k *ar)
 {
 	lockdep_assert_held(&ar->conf_mutex);
 
-	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
+	if (!ath10k_skip_cal_data(ar) && !test_bit(ATH10K_FW_FEATURE_NON_BMI,
 		      ar->normal_mode_fw.fw_file.fw_features))
 		ath10k_debug_cal_data_fetch(ar);
 
@@ -2532,6 +2538,7 @@
 	ath10k_debug_fw_stats_reset(ar);
 
 	kfree(ar->debug.tpc_stats);
+	kfree(ar->debug.tpc_stats_final);
 }
 
 int ath10k_debug_register(struct ath10k *ar)
@@ -2584,7 +2591,7 @@
 	debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar,
 			    &fops_fw_dbglog);
 
-	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
+	if (!ath10k_skip_cal_data(ar) && !test_bit(ATH10K_FW_FEATURE_NON_BMI,
 		      ar->normal_mode_fw.fw_file.fw_features)) {
 		debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar,
 				    &fops_cal_data);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/htt.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/htt.h
@@ -835,6 +835,7 @@
 
 #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
@@ -2033,6 +2034,7 @@
 	int (*htt_h2t_aggr_cfg_msg)(struct ath10k_htt *htt,
 				    u8 max_subfrms_ampdu,
 				    u8 max_subfrms_amsdu);
+	void (*htt_flush_tx)(struct ath10k_htt *htt);
 };
 
 static inline int ath10k_htt_send_rx_ring_cfg(struct ath10k_htt *htt)
@@ -2072,6 +2074,12 @@
 	return htt->tx_ops->htt_tx(htt, txmode, msdu);
 }
 
+static inline void ath10k_htt_flush_tx(struct ath10k_htt *htt)
+{
+	if (htt->tx_ops->htt_flush_tx)
+		htt->tx_ops->htt_flush_tx(htt);
+}
+
 static inline int ath10k_htt_alloc_txbuff(struct ath10k_htt *htt)
 {
 	if (!htt->tx_ops->htt_alloc_txbuff)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -142,6 +142,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) {
@@ -941,6 +949,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);
@@ -985,11 +994,16 @@
 		 */
 		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
@@ -1725,16 +1739,97 @@
 	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,
 				 bool fill_crypt_header,
 				 u8 *rx_hdr,
-				 enum ath10k_pkt_rx_err *err)
+				 enum ath10k_pkt_rx_err *err,
+				 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;
@@ -1747,6 +1842,7 @@
 	bool is_decrypted;
 	bool is_mgmt;
 	u32 attention;
+	bool frag_pn_check = true, multicast_check = true;
 
 	if (skb_queue_empty(amsdu))
 		return;
@@ -1845,7 +1941,37 @@
 	}
 
 	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);
 
@@ -1863,6 +1989,11 @@
 
 		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;
 	}
 }
 
@@ -1970,14 +2101,62 @@
 	ath10k_unchain_msdu(amsdu, unchain_cnt);
 }
 
+static bool ath10k_htt_rx_validate_amsdu(struct ath10k *ar,
+					 struct sk_buff_head *amsdu)
+{
+	u8 *subframe_hdr;
+	struct sk_buff *first;
+	bool is_first, is_last;
+	struct htt_rx_desc *rxd;
+	struct ieee80211_hdr *hdr;
+	size_t hdr_len, crypto_len;
+	enum htt_rx_mpdu_encrypt_type enctype;
+	int bytes_aligned = ar->hw_params.decap_align_bytes;
+
+	first = skb_peek(amsdu);
+
+	rxd = (void *)first->data - sizeof(*rxd);
+	hdr = (void *)rxd->rx_hdr_status;
+
+	is_first = !!(rxd->msdu_end.common.info0 &
+		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
+	is_last = !!(rxd->msdu_end.common.info0 &
+		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
+
+	/* Return in case of non-aggregated msdu */
+	if (is_first && is_last)
+		return true;
+
+	/* First msdu flag is not set for the first msdu of the list */
+	if (!is_first)
+		return false;
+
+	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
+		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
+
+	subframe_hdr = (u8 *)hdr + round_up(hdr_len, bytes_aligned) +
+		       crypto_len;
+
+	/* Validate if the amsdu has a proper first subframe.
+	 * There are chances a single msdu can be received as amsdu when
+	 * the unauthenticated amsdu flag of a QoS header
+	 * gets flipped in non-SPP AMSDU's, in such cases the first
+	 * subframe has llc/snap header in place of a valid da.
+	 * return false if the da matches rfc1042 pattern
+	 */
+	if (ether_addr_equal(subframe_hdr, rfc1042_header))
+		return false;
+
+	return true;
+}
+
 static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
 					struct sk_buff_head *amsdu,
 					struct ieee80211_rx_status *rx_status)
 {
-	/* FIXME: It might be a good idea to do some fuzzy-testing to drop
-	 * invalid/dangerous frames.
-	 */
-
 	if (!rx_status->freq) {
 		ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n");
 		return false;
@@ -1988,6 +2167,11 @@
 		return false;
 	}
 
+	if (!ath10k_htt_rx_validate_amsdu(ar, amsdu)) {
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid amsdu received\n");
+		return false;
+	}
+
 	return true;
 }
 
@@ -2050,7 +2234,8 @@
 		ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
 
 	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
-	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
+	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0,
+			     false);
 	msdus_to_queue = skb_queue_len(&amsdu);
 	ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
 
@@ -2183,6 +2368,11 @@
 	fw_desc = &rx->fw_desc;
 	rx_desc_len = fw_desc->len;
 
+	if (fw_desc->u.bits.discard) {
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt discard mpdu\n");
+		goto err;
+	}
+
 	/* I have not yet seen any case where num_mpdu_ranges > 1.
 	 * qcacld does not seem handle that case either, so we introduce the
 	 * same limitiation here as well.
@@ -2483,6 +2673,13 @@
 	rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len);
 	rx_desc_info = __le32_to_cpu(rx_desc->info);
 
+	hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
+
+	if (is_multicast_ether_addr(hdr->addr1)) {
+		/* Discard the fragment with multicast DA */
+		goto err;
+	}
+
 	if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) {
 		spin_unlock_bh(&ar->data_lock);
 		return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
@@ -2490,8 +2687,6 @@
 						    HTT_RX_NON_TKIP_MIC);
 	}
 
-	hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
-
 	if (ieee80211_has_retry(hdr->frame_control))
 		goto err;
 
@@ -2726,7 +2921,7 @@
 		spin_lock_bh(&ar->data_lock);
 
 		peer = ath10k_peer_find_by_id(ar, peer_id);
-		if (!peer) {
+		if (!peer || !peer->sta) {
 			spin_unlock_bh(&ar->data_lock);
 			rcu_read_unlock();
 			continue;
@@ -3000,7 +3195,7 @@
 			ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
 			ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
 			ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
-					     NULL);
+					     NULL, peer_id, frag);
 			ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
 			break;
 		case -EAGAIN:
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -147,6 +147,9 @@
 	htt->num_pending_tx--;
 	if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
 		ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
+
+	if (htt->num_pending_tx == 0)
+		wake_up(&htt->empty_tx_wq);
 }
 
 int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
@@ -529,9 +532,14 @@
 	htt->tx_mem_allocated = false;
 }
 
-void ath10k_htt_tx_stop(struct ath10k_htt *htt)
+static void ath10k_htt_flush_tx_queue(struct ath10k_htt *htt)
 {
 	idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
+}
+
+void ath10k_htt_tx_stop(struct ath10k_htt *htt)
+{
+	ath10k_htt_flush_tx_queue(htt);
 	idr_destroy(&htt->pending_tx);
 }
 
@@ -1535,7 +1543,9 @@
 err_unmap_msdu:
 	dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
 err_free_msdu_id:
+	spin_lock_bh(&htt->tx_lock);
 	ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+	spin_unlock_bh(&htt->tx_lock);
 err:
 	return res;
 }
@@ -1742,7 +1752,9 @@
 err_unmap_msdu:
 	dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
 err_free_msdu_id:
+	spin_lock_bh(&htt->tx_lock);
 	ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+	spin_unlock_bh(&htt->tx_lock);
 err:
 	return res;
 }
@@ -1774,6 +1786,7 @@
 	.htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32,
 	.htt_tx = ath10k_htt_tx_hl,
 	.htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32,
+	.htt_flush_tx = ath10k_htt_flush_tx_queue,
 };
 
 void ath10k_htt_set_tx_ops(struct ath10k_htt *htt)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/hw.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/hw.c
@@ -155,6 +155,9 @@
 	.num_target_ce_config_wlan	= 7,
 	.ce_desc_meta_data_mask		= 0xFFFC,
 	.ce_desc_meta_data_lsb		= 2,
+	.rfkill_pin			= 16,
+	.rfkill_cfg			= 0,
+	.rfkill_on_level		= 1,
 };
 
 const struct ath10k_hw_values qca99x0_values = {
@@ -1145,6 +1148,7 @@
 const struct ath10k_hw_ops qca99x0_ops = {
 	.rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes,
 	.rx_desc_get_msdu_limit_error = ath10k_qca99x0_rx_desc_msdu_limit_error,
+	.is_rssi_enable = ath10k_htt_tx_rssi_enable,
 };
 
 const struct ath10k_hw_ops qca6174_ops = {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/hw.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/hw.h
@@ -379,6 +379,9 @@
 	u8 num_target_ce_config_wlan;
 	u16 ce_desc_meta_data_mask;
 	u8 ce_desc_meta_data_lsb;
+	u32 rfkill_pin;
+	u32 rfkill_cfg;
+	bool rfkill_on_level;
 };
 
 extern const struct ath10k_hw_values qca988x_values;
@@ -590,9 +593,6 @@
 	/* Target rx ring fill level */
 	u32 rx_ring_fill_level;
 
-	/* target supporting per ce IRQ */
-	bool per_ce_irq;
-
 	/* target supporting shadow register for ce write */
 	bool shadow_reg_support;
 
@@ -768,6 +768,9 @@
 #define TARGET_HL_TLV_AST_SKID_LIMIT		16
 #define TARGET_HL_TLV_NUM_WDS_ENTRIES		2
 
+/* Target specific defines for QCA9377 high latency firmware */
+#define TARGET_QCA9377_HL_NUM_PEERS		15
+
 /* Diagnostic Window */
 #define CE_DIAG_PIPE	7
 
@@ -810,7 +813,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/mac.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/mac.c
@@ -12,6 +12,7 @@
 #include <linux/etherdevice.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
+#include <linux/bitfield.h>
 
 #include "hif.h"
 #include "core.h"
@@ -856,11 +857,36 @@
 	return 0;
 }
 
+static void ath10k_peer_map_cleanup(struct ath10k *ar, struct ath10k_peer *peer)
+{
+	int peer_id, i;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	for_each_set_bit(peer_id, peer->peer_ids,
+			 ATH10K_MAX_NUM_PEER_IDS) {
+		ar->peer_map[peer_id] = NULL;
+	}
+
+	/* Double check that peer is properly un-referenced from
+	 * the peer_map
+	 */
+	for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
+		if (ar->peer_map[i] == peer) {
+			ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %pK idx %d)\n",
+				    peer->addr, peer, i);
+			ar->peer_map[i] = NULL;
+		}
+	}
+
+	list_del(&peer->list);
+	kfree(peer);
+	ar->num_peers--;
+}
+
 static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
 {
 	struct ath10k_peer *peer, *tmp;
-	int peer_id;
-	int i;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -872,25 +898,7 @@
 		ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
 			    peer->addr, vdev_id);
 
-		for_each_set_bit(peer_id, peer->peer_ids,
-				 ATH10K_MAX_NUM_PEER_IDS) {
-			ar->peer_map[peer_id] = NULL;
-		}
-
-		/* Double check that peer is properly un-referenced from
-		 * the peer_map
-		 */
-		for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
-			if (ar->peer_map[i] == peer) {
-				ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %pK idx %d)\n",
-					    peer->addr, peer, i);
-				ar->peer_map[i] = NULL;
-			}
-		}
-
-		list_del(&peer->list);
-		kfree(peer);
-		ar->num_peers--;
+		ath10k_peer_map_cleanup(ar, peer);
 	}
 	spin_unlock_bh(&ar->data_lock);
 }
@@ -985,8 +993,12 @@
 	ath10k_mac_vif_beacon_free(arvif);
 
 	if (arvif->beacon_buf) {
-		dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
-				  arvif->beacon_buf, arvif->beacon_paddr);
+		if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
+			kfree(arvif->beacon_buf);
+		else
+			dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+					  arvif->beacon_buf,
+					  arvif->beacon_paddr);
 		arvif->beacon_buf = NULL;
 	}
 }
@@ -1040,7 +1052,7 @@
 	arg.channel.min_power = 0;
 	arg.channel.max_power = channel->max_power * 2;
 	arg.channel.max_reg_power = channel->max_reg_power * 2;
-	arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
+	arg.channel.max_antenna_gain = channel->max_antenna_gain;
 
 	reinit_completion(&ar->vdev_setup_done);
 	reinit_completion(&ar->vdev_delete_done);
@@ -1486,7 +1498,7 @@
 	arg.channel.min_power = 0;
 	arg.channel.max_power = chandef->chan->max_power * 2;
 	arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
-	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
+	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain;
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		arg.ssid = arvif->u.ap.ssid;
@@ -3145,7 +3157,7 @@
 			ch->min_power = 0;
 			ch->max_power = channel->max_power * 2;
 			ch->max_reg_power = channel->max_reg_power * 2;
-			ch->max_antenna_gain = channel->max_antenna_gain * 2;
+			ch->max_antenna_gain = channel->max_antenna_gain;
 			ch->reg_class_id = 0; /* FIXME */
 
 			/* FIXME: why use only legacy modes, why not any
@@ -3624,23 +3636,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 enum ath10k_mac_tx_path
@@ -3708,7 +3713,7 @@
 			 struct ieee80211_vif *vif,
 			 enum ath10k_hw_txrx_mode txmode,
 			 enum ath10k_mac_tx_path txpath,
-			 struct sk_buff *skb)
+			 struct sk_buff *skb, bool noque_offchan)
 {
 	struct ieee80211_hw *hw = ar->hw;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -3738,10 +3743,10 @@
 		}
 	}
 
-	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+	if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
 		if (!ath10k_mac_tx_frm_has_freq(ar)) {
-			ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n",
-				   skb);
+			ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n",
+				   skb, skb->len);
 
 			skb_queue_tail(&ar->offchan_tx_queue, skb);
 			ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -3803,8 +3808,8 @@
 
 		mutex_lock(&ar->conf_mutex);
 
-		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n",
-			   skb);
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n",
+			   skb, skb->len);
 
 		hdr = (struct ieee80211_hdr *)skb->data;
 		peer_addr = ieee80211_get_DA(hdr);
@@ -3850,7 +3855,7 @@
 		txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
 		txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
 
-		ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+		ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true);
 		if (ret) {
 			ath10k_warn(ar, "failed to transmit offchannel frame: %d\n",
 				    ret);
@@ -3860,8 +3865,8 @@
 		time_left =
 		wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
 		if (time_left == 0)
-			ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n",
-				    skb);
+			ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n",
+				    skb, skb->len);
 
 		if (!peer && tmp_peer_created) {
 			ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
@@ -3903,12 +3908,17 @@
 			     ar->running_fw->fw_file.fw_features)) {
 			paddr = dma_map_single(ar->dev, skb->data,
 					       skb->len, DMA_TO_DEVICE);
-			if (!paddr)
+			if (dma_mapping_error(ar->dev, paddr)) {
+				ieee80211_free_txskb(ar->hw, skb);
 				continue;
+			}
 			ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr);
 			if (ret) {
 				ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
 					    ret);
+				/* remove this msdu from idr tracking */
+				ath10k_wmi_cleanup_mgmt_tx_send(ar, skb);
+
 				dma_unmap_single(ar->dev, paddr, skb->len,
 						 DMA_TO_DEVICE);
 				ieee80211_free_txskb(ar->hw, skb);
@@ -4065,7 +4075,7 @@
 	if (ret)
 		return ret;
 
-	skb = ieee80211_tx_dequeue(hw, txq);
+	skb = ieee80211_tx_dequeue_ni(hw, txq);
 	if (!skb) {
 		spin_lock_bh(&ar->htt.tx_lock);
 		ath10k_htt_tx_dec_pending(htt);
@@ -4097,7 +4107,7 @@
 		spin_unlock_bh(&ar->htt.tx_lock);
 	}
 
-	ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+	ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false);
 	if (unlikely(ret)) {
 		ath10k_warn(ar, "failed to push frame: %d\n", ret);
 
@@ -4378,7 +4388,7 @@
 		spin_unlock_bh(&ar->htt.tx_lock);
 	}
 
-	ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb);
+	ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false);
 	if (ret) {
 		ath10k_warn(ar, "failed to transmit frame: %d\n", ret);
 		if (is_htt) {
@@ -4754,6 +4764,63 @@
 	return 0;
 }
 
+static int ath10k_mac_rfkill_config(struct ath10k *ar)
+{
+	u32 param;
+	int ret;
+
+	if (ar->hw_values->rfkill_pin == 0) {
+		ath10k_warn(ar, "ath10k does not support hardware rfkill with this device\n");
+		return -EOPNOTSUPP;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
+		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
+		   ar->hw_values->rfkill_pin, ar->hw_values->rfkill_cfg,
+		   ar->hw_values->rfkill_on_level);
+
+	param = FIELD_PREP(WMI_TLV_RFKILL_CFG_RADIO_LEVEL,
+			   ar->hw_values->rfkill_on_level) |
+		FIELD_PREP(WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM,
+			   ar->hw_values->rfkill_pin) |
+		FIELD_PREP(WMI_TLV_RFKILL_CFG_PIN_AS_GPIO,
+			   ar->hw_values->rfkill_cfg);
+
+	ret = ath10k_wmi_pdev_set_param(ar,
+					ar->wmi.pdev_param->rfkill_config,
+					param);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to set rfkill config 0x%x: %d\n",
+			    param, ret);
+		return ret;
+	}
+	return 0;
+}
+
+int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable)
+{
+	enum wmi_tlv_rfkill_enable_radio param;
+	int ret;
+
+	if (enable)
+		param = WMI_TLV_RFKILL_ENABLE_RADIO_ON;
+	else
+		param = WMI_TLV_RFKILL_ENABLE_RADIO_OFF;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac rfkill enable %d", param);
+
+	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rfkill_enable,
+					param);
+	if (ret) {
+		ath10k_warn(ar, "failed to set rfkill enable param %d: %d\n",
+			    param, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int ath10k_start(struct ieee80211_hw *hw)
 {
 	struct ath10k *ar = hw->priv;
@@ -4788,6 +4855,16 @@
 		goto err;
 	}
 
+	spin_lock_bh(&ar->data_lock);
+
+	if (ar->hw_rfkill_on) {
+		ar->hw_rfkill_on = false;
+		spin_unlock_bh(&ar->data_lock);
+		goto err;
+	}
+
+	spin_unlock_bh(&ar->data_lock);
+
 	ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL);
 	if (ret) {
 		ath10k_err(ar, "Could not init hif: %d\n", ret);
@@ -4801,6 +4878,14 @@
 		goto err_power_down;
 	}
 
+	if (ar->sys_cap_info & WMI_TLV_SYS_CAP_INFO_RFKILL) {
+		ret = ath10k_mac_rfkill_config(ar);
+		if (ret && ret != -EOPNOTSUPP) {
+			ath10k_warn(ar, "failed to configure rfkill: %d", ret);
+			goto err_core_stop;
+		}
+	}
+
 	param = ar->wmi.pdev_param->pmf_qos;
 	ret = ath10k_wmi_pdev_set_param(ar, param, 1);
 	if (ret) {
@@ -4960,7 +5045,8 @@
 
 	mutex_lock(&ar->conf_mutex);
 	if (ar->state != ATH10K_STATE_OFF) {
-		ath10k_halt(ar);
+		if (!ar->hw_rfkill_on)
+			ath10k_halt(ar);
 		ar->state = ATH10K_STATE_OFF;
 	}
 	mutex_unlock(&ar->conf_mutex);
@@ -5253,10 +5339,25 @@
 	if (vif->type == NL80211_IFTYPE_ADHOC ||
 	    vif->type == NL80211_IFTYPE_MESH_POINT ||
 	    vif->type == NL80211_IFTYPE_AP) {
-		arvif->beacon_buf = dma_alloc_coherent(ar->dev,
-						       IEEE80211_MAX_FRAME_LEN,
-						       &arvif->beacon_paddr,
-						       GFP_ATOMIC);
+		if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
+			arvif->beacon_buf = kmalloc(IEEE80211_MAX_FRAME_LEN,
+						    GFP_KERNEL);
+
+			/* Using a kernel pointer in place of a dma_addr_t
+			 * token can lead to undefined behavior if that
+			 * makes it into cache management functions. Use a
+			 * known-invalid address token instead, which
+			 * avoids the warning and makes it easier to catch
+			 * bugs if it does end up getting used.
+			 */
+			arvif->beacon_paddr = DMA_MAPPING_ERROR;
+		} else {
+			arvif->beacon_buf =
+				dma_alloc_coherent(ar->dev,
+						   IEEE80211_MAX_FRAME_LEN,
+						   &arvif->beacon_paddr,
+						   GFP_ATOMIC);
+		}
 		if (!arvif->beacon_buf) {
 			ret = -ENOMEM;
 			ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
@@ -5269,6 +5370,7 @@
 
 	if (arvif->nohwcrypt &&
 	    !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+		ret = -EINVAL;
 		ath10k_warn(ar, "cryptmode module param needed for sw crypto\n");
 		goto err;
 	}
@@ -5470,8 +5572,12 @@
 
 err:
 	if (arvif->beacon_buf) {
-		dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
-				  arvif->beacon_buf, arvif->beacon_paddr);
+		if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
+			kfree(arvif->beacon_buf);
+		else
+			dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+					  arvif->beacon_buf,
+					  arvif->beacon_paddr);
 		arvif->beacon_buf = NULL;
 	}
 
@@ -6619,10 +6725,7 @@
 				/* Clean up the peer object as well since we
 				 * must have failed to do this above.
 				 */
-				list_del(&peer->list);
-				ar->peer_map[i] = NULL;
-				kfree(peer);
-				ar->num_peers--;
+				ath10k_peer_map_cleanup(ar, peer);
 			}
 		}
 		spin_unlock_bh(&ar->data_lock);
@@ -7080,6 +7183,7 @@
 					ath10k_wmi_peer_flush(ar, arvif->vdev_id,
 							      arvif->bssid, bitmap);
 			}
+			ath10k_htt_flush_tx(&ar->htt);
 		}
 		return;
 	}
@@ -7125,7 +7229,7 @@
 				  struct ieee80211_channel *channel)
 {
 	int ret;
-	enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR;
+	enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -8809,7 +8913,6 @@
 	ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
 
 	if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
-		ar->hw->wiphy->max_sched_scan_reqs = 1;
 		ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS;
 		ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
 		ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/mac.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/mac.h
@@ -72,6 +72,7 @@
 					    u8 tid);
 int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val);
 void ath10k_mac_wait_tx_complete(struct ath10k *ar);
+int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable);
 
 static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif,
 				      struct sk_buff *skb)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/pci.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/pci.c
@@ -1604,11 +1604,22 @@
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	u32 i;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH10K_STATE_ON) {
+		ath10k_warn(ar, "Skipping pci_dump_memory_reg invalid state\n");
+		ret = -EIO;
+		goto done;
+	}
 
 	for (i = 0; i < region->len; i += 4)
 		*(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i);
 
-	return region->len;
+	ret = region->len;
+done:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
 }
 
 /* if an error happened returns < 0, otherwise the length */
@@ -1704,7 +1715,11 @@
 			count = ath10k_pci_dump_memory_sram(ar, current_region, buf);
 			break;
 		case ATH10K_MEM_REGION_TYPE_IOREG:
-			count = ath10k_pci_dump_memory_reg(ar, current_region, buf);
+			ret = ath10k_pci_dump_memory_reg(ar, current_region, buf);
+			if (ret < 0)
+				break;
+
+			count = ret;
 			break;
 		default:
 			ret = ath10k_pci_dump_memory_generic(ar, current_region, buf);
@@ -1945,8 +1960,9 @@
 	ath10k_pci_irq_enable(ar);
 	ath10k_pci_rx_post(ar);
 
-	pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
-				   ar_pci->link_ctl);
+	pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+					   PCI_EXP_LNKCTL_ASPMC,
+					   ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC);
 
 	return 0;
 }
@@ -2059,6 +2075,7 @@
 	ath10k_pci_irq_sync(ar);
 	napi_synchronize(&ar->napi);
 	napi_disable(&ar->napi);
+	cancel_work_sync(&ar_pci->dump_work);
 
 	/* Most likely the device has HTT Rx ring configured. The only way to
 	 * prevent the device from accessing (and possible corrupting) host
@@ -2802,8 +2819,8 @@
 
 	pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
 				  &ar_pci->link_ctl);
-	pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
-				   ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
+	pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+				   PCI_EXP_LNKCTL_ASPMC);
 
 	/*
 	 * Bring the target up cleanly.
@@ -3490,7 +3507,7 @@
 	struct ath10k_pci *ar_pci;
 	enum ath10k_hw_rev hw_rev;
 	struct ath10k_bus_params bus_params = {};
-	bool pci_ps;
+	bool pci_ps, is_qca988x = false;
 	int (*pci_soft_reset)(struct ath10k *ar);
 	int (*pci_hard_reset)(struct ath10k *ar);
 	u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr);
@@ -3500,6 +3517,7 @@
 	case QCA988X_2_0_DEVICE_ID:
 		hw_rev = ATH10K_HW_QCA988X;
 		pci_ps = false;
+		is_qca988x = true;
 		pci_soft_reset = ath10k_pci_warm_reset;
 		pci_hard_reset = ath10k_pci_qca988x_chip_reset;
 		targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
@@ -3619,24 +3637,39 @@
 		goto err_deinit_irq;
 	}
 
+	bus_params.dev_type = ATH10K_DEV_TYPE_LL;
+	bus_params.link_can_suspend = true;
+	/* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that
+	 * fall off the bus during chip_reset. These chips have the same pci
+	 * device id as the QCA9880 BR4A or 2R4E. So that's why the check.
+	 */
+	if (is_qca988x) {
+		bus_params.chip_id =
+			ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+		if (bus_params.chip_id != 0xffffffff) {
+			if (!ath10k_pci_chip_is_supported(pdev->device,
+							  bus_params.chip_id)) {
+				ret = -ENODEV;
+				goto err_unsupported;
+			}
+		}
+	}
+
 	ret = ath10k_pci_chip_reset(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to reset chip: %d\n", ret);
 		goto err_free_irq;
 	}
 
-	bus_params.dev_type = ATH10K_DEV_TYPE_LL;
-	bus_params.link_can_suspend = true;
 	bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
 	if (bus_params.chip_id == 0xffffffff) {
-		ath10k_err(ar, "failed to get chip id\n");
-		goto err_free_irq;
+		ret = -ENODEV;
+		goto err_unsupported;
 	}
 
 	if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
-		ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
-			   pdev->device, bus_params.chip_id);
-		goto err_free_irq;
+		ret = -ENODEV;
+		goto err_unsupported;
 	}
 
 	ret = ath10k_core_register(ar, &bus_params);
@@ -3647,6 +3680,10 @@
 
 	return 0;
 
+err_unsupported:
+	ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
+		   pdev->device, bus_params.chip_id);
+
 err_free_irq:
 	ath10k_pci_free_irq(ar);
 	ath10k_pci_rx_retry_sync(ar);
@@ -3733,18 +3770,22 @@
 
 static int __init ath10k_pci_init(void)
 {
-	int ret;
+	int ret1, ret2;
 
-	ret = pci_register_driver(&ath10k_pci_driver);
-	if (ret)
+	ret1 = pci_register_driver(&ath10k_pci_driver);
+	if (ret1)
 		printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
-		       ret);
+		       ret1);
 
-	ret = ath10k_ahb_init();
-	if (ret)
-		printk(KERN_ERR "ahb init failed: %d\n", ret);
+	ret2 = ath10k_ahb_init();
+	if (ret2)
+		printk(KERN_ERR "ahb init failed: %d\n", ret2);
 
-	return ret;
+	if (ret1 && ret2)
+		return ret1;
+
+	/* registered to at least one bus */
+	return 0;
 }
 module_init(ath10k_pci_init);
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/qmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/qmi.c
@@ -581,22 +581,29 @@
 {
 	struct wlfw_host_cap_resp_msg_v01 resp = {};
 	struct wlfw_host_cap_req_msg_v01 req = {};
+	struct qmi_elem_info *req_ei;
 	struct ath10k *ar = qmi->ar;
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 	struct qmi_txn txn;
 	int ret;
 
 	req.daemon_support_valid = 1;
 	req.daemon_support = 0;
 
-	ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
-			   wlfw_host_cap_resp_msg_v01_ei, &resp);
+	ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei,
+			   &resp);
 	if (ret < 0)
 		goto out;
 
+	if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags))
+		req_ei = wlfw_host_cap_8bit_req_msg_v01_ei;
+	else
+		req_ei = wlfw_host_cap_req_msg_v01_ei;
+
 	ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 			       QMI_WLFW_HOST_CAP_REQ_V01,
 			       WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
-			       wlfw_host_cap_req_msg_v01_ei, &req);
+			       req_ei, &req);
 	if (ret < 0) {
 		qmi_txn_cancel(&txn);
 		ath10k_err(ar, "failed to send host capability request: %d\n", ret);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
@@ -1988,6 +1988,28 @@
 	{}
 };
 
+struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type     = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type     = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support),
+	},
+	{}
+};
+
 struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
 	{
 		.data_type      = QMI_STRUCT,
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
@@ -575,6 +575,7 @@
 
 #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
+extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[];
 
 struct wlfw_host_cap_resp_msg_v01 {
 	struct qmi_response_type_v01 resp;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -1282,7 +1282,19 @@
 #define FW_RX_DESC_UDP              (1 << 6)
 
 struct fw_rx_desc_hl {
-	u8 info0;
+	union {
+		struct {
+		u8 discard:1,
+		   forward:1,
+		   any_err:1,
+		   dup_err:1,
+		   reserved:1,
+		   inspect:1,
+		   extension:2;
+		} bits;
+		u8 info0;
+	} u;
+
 	u8 version;
 	u8 len;
 	u8 flags;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/sdio.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/sdio.c
@@ -14,6 +14,8 @@
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sd.h>
 #include <linux/bitfield.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
 #include "core.h"
 #include "bmi.h"
 #include "debug.h"
@@ -24,6 +26,10 @@
 #include "trace.h"
 #include "sdio.h"
 
+static unsigned char macaddr[ETH_ALEN];
+module_param_array(macaddr, byte, NULL, 0);
+MODULE_PARM_DESC(macaddr, "SDIO ath10k MAC address");
+
 /* inlined helper functions */
 
 static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
@@ -550,6 +556,10 @@
 				    le16_to_cpu(htc_hdr->len),
 				    ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH);
 			ret = -ENOMEM;
+
+			queue_work(ar->workqueue, &ar->restart_work);
+			ath10k_warn(ar, "exceeds length, start recovery\n");
+
 			goto err;
 		}
 
@@ -1582,23 +1592,33 @@
 				     size_t buf_len)
 {
 	int ret;
+	void *mem;
+
+	mem = kzalloc(buf_len, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
 
 	/* set window register to start read cycle */
 	ret = ath10k_sdio_write32(ar, MBOX_WINDOW_READ_ADDR_ADDRESS, address);
 	if (ret) {
 		ath10k_warn(ar, "failed to set mbox window read address: %d", ret);
-		return ret;
+		goto out;
 	}
 
 	/* read the data */
-	ret = ath10k_sdio_read(ar, MBOX_WINDOW_DATA_ADDRESS, buf, buf_len);
+	ret = ath10k_sdio_read(ar, MBOX_WINDOW_DATA_ADDRESS, mem, buf_len);
 	if (ret) {
 		ath10k_warn(ar, "failed to read from mbox window data address: %d\n",
 			    ret);
-		return ret;
+		goto out;
 	}
 
-	return 0;
+	memcpy(buf, mem, buf_len);
+
+out:
+	kfree(mem);
+
+	return ret;
 }
 
 static int ath10k_sdio_hif_diag_read32(struct ath10k *ar, u32 address,
@@ -1983,6 +2003,7 @@
 static int ath10k_sdio_probe(struct sdio_func *func,
 			     const struct sdio_device_id *id)
 {
+	struct device *sdhc_dev = func->card->host->parent;
 	struct ath10k_sdio *ar_sdio;
 	struct ath10k *ar;
 	enum ath10k_hw_rev hw_rev;
@@ -2005,6 +2026,21 @@
 		return -ENOMEM;
 	}
 
+	if (is_valid_ether_addr(macaddr))
+		ether_addr_copy(ar->mac_addr, macaddr);
+
+	if (is_zero_ether_addr(ar->mac_addr) && sdhc_dev->of_node) {
+		struct device_node *np_wlan;
+		const char *mac;
+
+		np_wlan = of_get_compatible_child(sdhc_dev->of_node, "qcom,ath10k");
+		if (np_wlan) {
+			mac = of_get_mac_address(np_wlan);
+			if (!IS_ERR(mac))
+				ether_addr_copy(ar->mac_addr, mac);
+		}
+	}
+
 	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
 		   func->num, func->vendor, func->device,
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/snoc.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/snoc.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2018 The Linux Foundation. All rights reserved.
  */
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -821,12 +822,20 @@
 
 static inline void ath10k_snoc_irq_disable(struct ath10k *ar)
 {
-	ath10k_ce_disable_interrupts(ar);
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+	int id;
+
+	for (id = 0; id < CE_COUNT_MAX; id++)
+		disable_irq(ar_snoc->ce_irqs[id].irq_line);
 }
 
 static inline void ath10k_snoc_irq_enable(struct ath10k *ar)
 {
-	ath10k_ce_enable_interrupts(ar);
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+	int id;
+
+	for (id = 0; id < CE_COUNT_MAX; id++)
+		enable_irq(ar_snoc->ce_irqs[id].irq_line);
 }
 
 static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)
@@ -919,6 +928,7 @@
 {
 	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 
+	bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
 	napi_enable(&ar->napi);
 	ath10k_snoc_irq_enable(ar);
 	ath10k_snoc_rx_post(ar);
@@ -1039,12 +1049,15 @@
 	ret = ath10k_snoc_init_pipes(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to initialize CE: %d\n", ret);
-		goto err_wlan_enable;
+		goto err_free_rri;
 	}
 
+	ath10k_ce_enable_interrupts(ar);
+
 	return 0;
 
-err_wlan_enable:
+err_free_rri:
+	ath10k_ce_free_rri(ar);
 	ath10k_snoc_wlan_disable(ar);
 
 	return ret;
@@ -1155,7 +1168,9 @@
 		return IRQ_HANDLED;
 	}
 
-	ath10k_snoc_irq_disable(ar);
+	ath10k_ce_disable_interrupt(ar, ce_id);
+	set_bit(ce_id, ar_snoc->pending_ce_irqs);
+
 	napi_schedule(&ar->napi);
 
 	return IRQ_HANDLED;
@@ -1164,20 +1179,25 @@
 static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
 {
 	struct ath10k *ar = container_of(ctx, struct ath10k, napi);
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 	int done = 0;
+	int ce_id;
 
 	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
 		napi_complete(ctx);
 		return done;
 	}
 
-	ath10k_ce_per_engine_service_any(ar);
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+		if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {
+			ath10k_ce_per_engine_service(ar, ce_id);
+			ath10k_ce_enable_interrupt(ar, ce_id);
+		}
+
 	done = ath10k_htt_txrx_compl_task(ar, budget);
 
-	if (done < budget) {
+	if (done < budget)
 		napi_complete(ctx);
-		ath10k_snoc_irq_enable(ar);
-	}
 
 	return done;
 }
@@ -1191,13 +1211,12 @@
 static int ath10k_snoc_request_irq(struct ath10k *ar)
 {
 	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
-	int irqflags = IRQF_TRIGGER_RISING;
 	int ret, id;
 
 	for (id = 0; id < CE_COUNT_MAX; id++) {
 		ret = request_irq(ar_snoc->ce_irqs[id].irq_line,
 				  ath10k_snoc_per_engine_handler,
-				  irqflags, ce_name[id], ar);
+				  IRQF_NO_AUTOEN, ce_name[id], ar);
 		if (ret) {
 			ath10k_err(ar,
 				   "failed to register IRQ handler for CE %d: %d",
@@ -1261,6 +1280,15 @@
 	return ret;
 }
 
+static void ath10k_snoc_quirks_init(struct ath10k *ar)
+{
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+	struct device *dev = &ar_snoc->dev->dev;
+
+	if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
+		set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
+}
+
 int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
 {
 	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -1678,6 +1706,8 @@
 	ar->ce_priv = &ar_snoc->ce;
 	msa_size = drv_data->msa_size;
 
+	ath10k_snoc_quirks_init(ar);
+
 	ret = ath10k_snoc_resource_init(ar);
 	if (ret) {
 		ath10k_warn(ar, "failed to initialize resource: %d\n", ret);
@@ -1718,13 +1748,16 @@
 	ret = ath10k_qmi_init(ar, msa_size);
 	if (ret) {
 		ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
-		goto err_core_destroy;
+		goto err_power_off;
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
 
 	return 0;
 
+err_power_off:
+	ath10k_hw_power_off(ar);
+
 err_free_irq:
 	ath10k_snoc_free_irq(ar);
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/snoc.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/snoc.h
@@ -63,6 +63,7 @@
 	ATH10K_SNOC_FLAG_REGISTERED,
 	ATH10K_SNOC_FLAG_UNREGISTERING,
 	ATH10K_SNOC_FLAG_RECOVERY,
+	ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
 };
 
 struct ath10k_snoc {
@@ -80,6 +81,7 @@
 	struct ath10k_clk_info *clk;
 	struct ath10k_qmi *qmi;
 	unsigned long flags;
+	DECLARE_BITMAP(pending_ce_irqs, CE_COUNT_MAX);
 };
 
 static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/txrx.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/txrx.c
@@ -80,13 +80,13 @@
 
 	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
 	ath10k_htt_tx_dec_pending(htt);
-	if (htt->num_pending_tx == 0)
-		wake_up(&htt->empty_tx_wq);
 	spin_unlock_bh(&htt->tx_lock);
 
+	rcu_read_lock();
 	if (txq && txq->sta && skb_cb->airtime_est)
 		ieee80211_sta_register_airtime(txq->sta, txq->tid,
 					       skb_cb->airtime_est, 0);
+	rcu_read_unlock();
 
 	if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
 		dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
@@ -95,6 +95,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 (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/usb.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/usb.c
@@ -38,6 +38,10 @@
 	struct ath10k_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 = list_first_entry(&pipe->urb_list_head,
@@ -55,6 +59,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++;
@@ -435,6 +443,7 @@
 			ath10k_dbg(ar, ATH10K_DBG_USB_BULK,
 				   "usb bulk transmit failed: %d\n", ret);
 			usb_unanchor_urb(urb);
+			usb_free_urb(urb);
 			ret = -EINVAL;
 			goto err_free_urb_to_pipe;
 		}
@@ -516,7 +525,7 @@
 			      req,
 			      USB_DIR_IN | USB_TYPE_VENDOR |
 			      USB_RECIP_DEVICE, value, index, buf,
-			      size, 2 * HZ);
+			      size, 2000);
 
 	if (ret < 0) {
 		ath10k_warn(ar, "Failed to read usb control message: %d\n",
@@ -856,6 +865,11 @@
 				   le16_to_cpu(endpoint->wMaxPacketSize),
 				   endpoint->bInterval);
 		}
+
+		/* Ignore broken descriptors. */
+		if (usb_endpoint_maxp(endpoint) == 0)
+			continue;
+
 		urbcount = 0;
 
 		pipe_num =
@@ -1000,6 +1014,8 @@
 
 	ar_usb = ath10k_usb_priv(ar);
 	ret = ath10k_usb_create(ar, interface);
+	if (ret)
+		goto err;
 	ar_usb->ar = ar;
 
 	ar->dev_id = product_id;
@@ -1012,7 +1028,7 @@
 	ret = ath10k_core_register(ar, &bus_params);
 	if (ret) {
 		ath10k_warn(ar, "failed to register driver core: %d\n", ret);
-		goto err;
+		goto err_usb_destroy;
 	}
 
 	/* TODO: remove this once USB support is fully implemented */
@@ -1020,6 +1036,9 @@
 
 	return 0;
 
+err_usb_destroy:
+	ath10k_usb_destroy(ar);
+
 err:
 	ath10k_core_destroy(ar);
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -133,6 +133,7 @@
 	struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
 					    struct sk_buff *skb,
 					    dma_addr_t paddr);
+	int (*cleanup_mgmt_tx_send)(struct ath10k *ar, struct sk_buff *msdu);
 	struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
 					  u32 log_level);
 	struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
@@ -442,6 +443,15 @@
 }
 
 static inline int
+ath10k_wmi_cleanup_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu)
+{
+	if (!ar->wmi.ops->cleanup_mgmt_tx_send)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->cleanup_mgmt_tx_send(ar, msdu);
+}
+
+static inline int
 ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
 			dma_addr_t paddr)
 {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -409,6 +409,49 @@
 	return 0;
 }
 
+static void ath10k_wmi_tlv_event_rfkill_state_change(struct ath10k *ar,
+						     struct sk_buff *skb)
+{
+	const struct wmi_tlv_rfkill_state_change_ev *ev;
+	const void **tb;
+	bool radio;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar,
+			    "failed to parse rfkill state change event: %d\n",
+			    ret);
+		return;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_RFKILL_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
+		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
+		   __le32_to_cpu(ev->gpio_pin_num),
+		   __le32_to_cpu(ev->int_type),
+		   __le32_to_cpu(ev->radio_state));
+
+	radio = (__le32_to_cpu(ev->radio_state) == WMI_TLV_RFKILL_RADIO_STATE_ON);
+
+	spin_lock_bh(&ar->data_lock);
+
+	if (!radio)
+		ar->hw_rfkill_on = true;
+
+	spin_unlock_bh(&ar->data_lock);
+
+	/* notify cfg80211 radio state change */
+	ath10k_mac_rfkill_enable_radio(ar, radio);
+	wiphy_rfkill_set_hw_state(ar->hw->wiphy, !radio);
+}
+
 static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar,
 					    struct sk_buff *skb)
 {
@@ -445,13 +488,13 @@
 	case WMI_TDLS_TEARDOWN_REASON_TX:
 	case WMI_TDLS_TEARDOWN_REASON_RSSI:
 	case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
+		rcu_read_lock();
 		station = ieee80211_find_sta_by_ifaddr(ar->hw,
 						       ev->peer_macaddr.addr,
 						       NULL);
 		if (!station) {
 			ath10k_warn(ar, "did not find station from tdls peer event");
-			kfree(tb);
-			return;
+			goto exit;
 		}
 		arvif = ath10k_get_arvif(ar, __le32_to_cpu(ev->vdev_id));
 		ieee80211_tdls_oper_request(
@@ -461,7 +504,13 @@
 					GFP_ATOMIC
 					);
 		break;
+	default:
+		kfree(tb);
+		return;
 	}
+
+exit:
+	rcu_read_unlock();
 	kfree(tb);
 }
 
@@ -629,6 +678,9 @@
 	case WMI_TLV_TX_PAUSE_EVENTID:
 		ath10k_wmi_tlv_event_tx_pause(ar, skb);
 		break;
+	case WMI_TLV_RFKILL_STATE_CHANGE_EVENTID:
+		ath10k_wmi_tlv_event_rfkill_state_change(ar, skb);
+		break;
 	case WMI_TLV_PDEV_TEMPERATURE_EVENTID:
 		ath10k_wmi_tlv_event_temperature(ar, skb);
 		break;
@@ -1212,6 +1264,7 @@
 	arg->num_mem_reqs = ev->num_mem_reqs;
 	arg->service_map = svc_bmap;
 	arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap);
+	arg->sys_cap_info = ev->sys_cap_info;
 
 	ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
 				  ath10k_wmi_tlv_parse_mem_reqs, arg);
@@ -1260,13 +1313,15 @@
 
 	switch (tag) {
 	case WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT:
+		arg->service_map_ext_valid = true;
 		arg->service_map_ext_len = *(__le32 *)ptr;
 		arg->service_map_ext = ptr + sizeof(__le32);
 		return 0;
 	default:
 		break;
 	}
-	return -EPROTO;
+
+	return 0;
 }
 
 static int ath10k_wmi_tlv_op_pull_svc_avail(struct ath10k *ar,
@@ -2838,6 +2893,18 @@
 }
 
 static int
+ath10k_wmi_tlv_op_cleanup_mgmt_tx_send(struct ath10k *ar,
+				       struct sk_buff *msdu)
+{
+	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
+	struct ath10k_wmi *wmi = &ar->wmi;
+
+	idr_remove(&wmi->mgmt_pending_tx, cb->msdu_id);
+
+	return 0;
+}
+
+static int
 ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
 				 dma_addr_t paddr)
 {
@@ -2911,6 +2978,8 @@
 	if (desc_id < 0)
 		goto err_free_skb;
 
+	cb->msdu_id = desc_id;
+
 	ptr = (void *)skb->data;
 	tlv = ptr;
 	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
@@ -3650,6 +3719,7 @@
 	struct wmi_tlv *tlv;
 	struct sk_buff *skb;
 	__le32 *channel_list;
+	u16 tlv_len;
 	size_t len;
 	void *ptr;
 	u32 i;
@@ -3707,10 +3777,12 @@
 	/* nlo_configured_parameters(nlo_list) */
 	cmd->no_of_ssids = __cpu_to_le32(min_t(u8, pno->uc_networks_count,
 					       WMI_NLO_MAX_SSIDS));
+	tlv_len = __le32_to_cpu(cmd->no_of_ssids) *
+		sizeof(struct nlo_configured_parameters);
 
 	tlv = ptr;
 	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
-	tlv->len = __cpu_to_le16(len);
+	tlv->len = __cpu_to_le16(tlv_len);
 
 	ptr += sizeof(*tlv);
 	nlo_list = ptr;
@@ -4204,6 +4276,8 @@
 	.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED,
 	.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED,
 	.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
+	.rfkill_config = WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG,
+	.rfkill_enable = WMI_TLV_PDEV_PARAM_RFKILL_ENABLE,
 };
 
 static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
@@ -4336,6 +4410,7 @@
 	.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
 	/* .gen_mgmt_tx = not implemented; HTT is used */
 	.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
+	.cleanup_mgmt_tx_send = ath10k_wmi_tlv_op_cleanup_mgmt_tx_send,
 	.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
 	.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
 	.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -7,6 +7,8 @@
 #ifndef _WMI_TLV_H
 #define _WMI_TLV_H
 
+#include <linux/bitops.h>
+
 #define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
 #define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1)
 #define WMI_TLV_CMD_UNSUPPORTED 0
@@ -2235,6 +2237,31 @@
 	__le32 vdev_id;
 } __packed;
 
+enum wmi_tlv_sys_cap_info_flags {
+	WMI_TLV_SYS_CAP_INFO_RXTX_LED	= BIT(0),
+	WMI_TLV_SYS_CAP_INFO_RFKILL	= BIT(1),
+};
+
+#define WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM		GENMASK(5, 0)
+#define WMI_TLV_RFKILL_CFG_RADIO_LEVEL		BIT(6)
+#define WMI_TLV_RFKILL_CFG_PIN_AS_GPIO		GENMASK(10, 7)
+
+enum wmi_tlv_rfkill_enable_radio {
+	WMI_TLV_RFKILL_ENABLE_RADIO_ON	= 0,
+	WMI_TLV_RFKILL_ENABLE_RADIO_OFF	= 1,
+};
+
+enum wmi_tlv_rfkill_radio_state {
+	WMI_TLV_RFKILL_RADIO_STATE_OFF	= 1,
+	WMI_TLV_RFKILL_RADIO_STATE_ON	= 2,
+};
+
+struct wmi_tlv_rfkill_state_change_ev {
+	__le32 gpio_pin_num;
+	__le32 int_type;
+	__le32 radio_state;
+};
+
 void ath10k_wmi_tlv_attach(struct ath10k *ar);
 
 enum wmi_nlo_auth_algorithm {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2541,6 +2541,10 @@
 	if (ieee80211_is_beacon(hdr->frame_control))
 		ath10k_mac_handle_beacon(ar, skb);
 
+	if (ieee80211_is_beacon(hdr->frame_control) ||
+	    ieee80211_is_probe_resp(hdr->frame_control))
+		status->boottime_ns = ktime_get_boottime_ns();
+
 	ath10k_dbg(ar, ATH10K_DBG_MGMT,
 		   "event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
 		   skb, skb->len,
@@ -4668,16 +4672,13 @@
 	}
 
 	pream_idx = 0;
-	for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
+	for (i = 0; i < tpc_stats->rate_max; i++) {
 		memset(tpc_value, 0, sizeof(tpc_value));
 		memset(buff, 0, sizeof(buff));
 		if (i == pream_table[pream_idx])
 			pream_idx++;
 
-		for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
-			if (j >= __le32_to_cpu(ev->num_tx_chain))
-				break;
-
+		for (j = 0; j < tpc_stats->num_tx_chain; j++) {
 			tpc[j] = ath10k_tpc_config_get_rate(ar, ev, i, j + 1,
 							    rate_code[i],
 							    type);
@@ -4790,7 +4791,7 @@
 
 void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
 {
-	u32 num_tx_chain;
+	u32 num_tx_chain, rate_max;
 	u8 rate_code[WMI_TPC_RATE_MAX];
 	u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
 	struct wmi_pdev_tpc_config_event *ev;
@@ -4806,6 +4807,13 @@
 		return;
 	}
 
+	rate_max = __le32_to_cpu(ev->rate_max);
+	if (rate_max > WMI_TPC_RATE_MAX) {
+		ath10k_warn(ar, "number of rate is %d greater than TPC configured rate %d\n",
+			    rate_max, WMI_TPC_RATE_MAX);
+		rate_max = WMI_TPC_RATE_MAX;
+	}
+
 	tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
 	if (!tpc_stats)
 		return;
@@ -4822,8 +4830,8 @@
 		__le32_to_cpu(ev->twice_antenna_reduction);
 	tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
 	tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
-	tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-	tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
+	tpc_stats->num_tx_chain = num_tx_chain;
+	tpc_stats->rate_max = rate_max;
 
 	ath10k_tpc_config_disp_tables(ar, ev, tpc_stats,
 				      rate_code, pream_table,
@@ -5018,16 +5026,13 @@
 	}
 
 	pream_idx = 0;
-	for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
+	for (i = 0; i < tpc_stats->rate_max; i++) {
 		memset(tpc_value, 0, sizeof(tpc_value));
 		memset(buff, 0, sizeof(buff));
 		if (i == pream_table[pream_idx])
 			pream_idx++;
 
-		for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
-			if (j >= __le32_to_cpu(ev->num_tx_chain))
-				break;
-
+		for (j = 0; j < tpc_stats->num_tx_chain; j++) {
 			tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
 							       rate_code[i],
 							       type, pream_idx);
@@ -5043,7 +5048,7 @@
 
 void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
 {
-	u32 num_tx_chain;
+	u32 num_tx_chain, rate_max;
 	u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
 	u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
 	struct wmi_pdev_tpc_final_table_event *ev;
@@ -5051,12 +5056,24 @@
 
 	ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
 
+	num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
+	if (num_tx_chain > WMI_TPC_TX_N_CHAIN) {
+		ath10k_warn(ar, "number of tx chain is %d greater than TPC final configured tx chain %d\n",
+			    num_tx_chain, WMI_TPC_TX_N_CHAIN);
+		return;
+	}
+
+	rate_max = __le32_to_cpu(ev->rate_max);
+	if (rate_max > WMI_TPC_FINAL_RATE_MAX) {
+		ath10k_warn(ar, "number of rate is %d greater than TPC final configured rate %d\n",
+			    rate_max, WMI_TPC_FINAL_RATE_MAX);
+		rate_max = WMI_TPC_FINAL_RATE_MAX;
+	}
+
 	tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
 	if (!tpc_stats)
 		return;
 
-	num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-
 	ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
 					    num_tx_chain);
 
@@ -5069,8 +5086,8 @@
 		__le32_to_cpu(ev->twice_antenna_reduction);
 	tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
 	tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
-	tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-	tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
+	tpc_stats->num_tx_chain = num_tx_chain;
+	tpc_stats->rate_max = rate_max;
 
 	ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
 					       rate_code, pream_table,
@@ -5393,6 +5410,12 @@
 	arg->service_map = ev->wmi_service_bitmap;
 	arg->service_map_len = sizeof(ev->wmi_service_bitmap);
 
+	/* Deliberately skipping ev->sys_cap_info as WMI and WMI-TLV have
+	 * different values. We would need a translation to handle that,
+	 * but as we don't currently need anything from sys_cap_info from
+	 * WMI interface (only from WMI-TLV) safest it to skip it.
+	 */
+
 	n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
 		  ARRAY_SIZE(arg->mem_reqs));
 	for (i = 0; i < n; i++)
@@ -5443,9 +5466,12 @@
 	ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd);
 	ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan);
 	ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan);
+	ar->sys_cap_info = __le32_to_cpu(arg.sys_cap_info);
 
 	ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
 			arg.service_map, arg.service_map_len);
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sys_cap_info 0x%x\n",
+		   ar->sys_cap_info);
 
 	if (ar->num_rf_chains > ar->max_spatial_stream) {
 		ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
@@ -5646,8 +5672,13 @@
 			    ret);
 	}
 
-	ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map,
-			       __le32_to_cpu(arg.service_map_ext_len));
+	/*
+	 * Initialization of "arg.service_map_ext_valid" to ZERO is necessary
+	 * for the below logic to work.
+	 */
+	if (arg.service_map_ext_valid)
+		ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map,
+				       __le32_to_cpu(arg.service_map_ext_len));
 }
 
 static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
@@ -9422,7 +9453,7 @@
 
 	msdu = pkt_addr->vaddr;
 	dma_unmap_single(ar->dev, pkt_addr->paddr,
-			 msdu->len, DMA_FROM_DEVICE);
+			 msdu->len, DMA_TO_DEVICE);
 	ieee80211_free_txskb(ar->hw, msdu);
 
 	return 0;
@@ -9440,7 +9471,5 @@
 	}
 
 	cancel_work_sync(&ar->svc_rdy_work);
-
-	if (ar->svc_rdy_skb)
-		dev_kfree_skb(ar->svc_rdy_skb);
+	dev_kfree_skb(ar->svc_rdy_skb);
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wmi.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2045,7 +2045,9 @@
 	union {
 		__le32 reginfo1;
 		struct {
+			/* note: power unit is 1 dBm */
 			u8 antenna_max;
+			/* note: power unit is 0.5 dBm */
 			u8 max_tx_power;
 		} __packed;
 	} __packed;
@@ -2065,6 +2067,7 @@
 	u32 min_power;
 	u32 max_power;
 	u32 max_reg_power;
+	/* note: power unit is 1 dBm */
 	u32 max_antenna_gain;
 	u32 reg_class_id;
 	enum wmi_phy_mode mode;
@@ -3786,6 +3789,8 @@
 	u32 arp_srcaddr;
 	u32 arp_dstaddr;
 	u32 enable_btcoex;
+	u32 rfkill_config;
+	u32 rfkill_enable;
 };
 
 #define WMI_PDEV_PARAM_UNSUPPORTED 0
@@ -6851,12 +6856,14 @@
 	__le32 num_mem_reqs;
 	__le32 low_5ghz_chan;
 	__le32 high_5ghz_chan;
+	__le32 sys_cap_info;
 	const __le32 *service_map;
 	size_t service_map_len;
 	const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
 };
 
 struct wmi_svc_avail_ev_arg {
+	bool service_map_ext_valid;
 	__le32 service_map_ext_len;
 	const __le32 *service_map_ext;
 };
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath10k/wow.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath10k/wow.c
@@ -337,14 +337,15 @@
 			if (patterns[i].mask[j / 8] & BIT(j % 8))
 				bitmask[j] = 0xff;
 		old_pattern.mask = bitmask;
-		new_pattern = old_pattern;
 
 		if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {
-			if (patterns[i].pkt_offset < ETH_HLEN)
+			if (patterns[i].pkt_offset < ETH_HLEN) {
 				ath10k_wow_convert_8023_to_80211(&new_pattern,
 								 &old_pattern);
-			else
+			} else {
+				new_pattern = old_pattern;
 				new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
+			}
 		}
 
 		if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath5k/eeprom.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -529,7 +529,7 @@
 		ee->ee_n_piers[mode]++;
 
 		freq2 = (val >> 8) & 0xff;
-		if (!freq2)
+		if (!freq2 || i >= max)
 			break;
 
 		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
@@ -746,6 +746,9 @@
 			}
 		}
 
+		if (idx == AR5K_EEPROM_N_PD_CURVES)
+			goto err_out;
+
 		ee->ee_pd_gains[mode] = 1;
 
 		pd = &chinfo[pier].pd_curves[idx];
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -521,7 +521,7 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		ath_key_delete(common, key->hw_key_idx);
 		break;
 	default:
 		ret = -EINVAL;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/bmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/bmi.c
@@ -246,7 +246,7 @@
 		return -EACCES;
 	}
 
-	size = sizeof(cid) + sizeof(addr) + sizeof(param);
+	size = sizeof(cid) + sizeof(addr) + sizeof(*param);
 	if (size > ar->bmi.max_cmd_size) {
 		WARN_ON(1);
 		return -EINVAL;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/debug.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/debug.c
@@ -1027,14 +1027,17 @@
 {
 	struct ath6kl *ar = file->private_data;
 	unsigned long lrssi_roam_threshold;
+	int ret;
 
 	if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
 		return -EINVAL;
 
 	ar->lrssi_roam_threshold = lrssi_roam_threshold;
 
-	ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
+	ret = ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
 
+	if (ret)
+		return ret;
 	return count;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -960,8 +960,8 @@
 	 * Thus the possibility of ar->htc_target being NULL
 	 * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
 	 */
-	if (WARN_ON_ONCE(!target)) {
-		ath6kl_err("Target not yet initialized\n");
+	if (!target) {
+		ath6kl_dbg(ATH6KL_DBG_HTC, "Target not yet initialized\n");
 		status = -EINVAL;
 		goto free_skb;
 	}
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/init.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/init.c
@@ -1575,7 +1575,7 @@
 
 int ath6kl_init_hw_params(struct ath6kl *ar)
 {
-	const struct ath6kl_hw *uninitialized_var(hw);
+	const struct ath6kl_hw *hw;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/main.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/usb.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/usb.c
@@ -340,6 +340,11 @@
 				   le16_to_cpu(endpoint->wMaxPacketSize),
 				   endpoint->bInterval);
 		}
+
+		/* Ignore broken descriptors. */
+		if (usb_endpoint_maxp(endpoint) == 0)
+			continue;
+
 		urbcount = 0;
 
 		pipe_num =
@@ -907,7 +912,7 @@
 				 req,
 				 USB_DIR_IN | USB_TYPE_VENDOR |
 				 USB_RECIP_DEVICE, value, index, buf,
-				 size, 2 * HZ);
+				 size, 2000);
 
 	if (ret < 0) {
 		ath6kl_warn("Failed to read usb control message: %d\n", ret);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath6kl/wmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2510,8 +2510,10 @@
 		goto free_data_skb;
 
 	for (index = 0; index < num_pri_streams; index++) {
-		if (WARN_ON(!data_sync_bufs[index].skb))
+		if (WARN_ON(!data_sync_bufs[index].skb)) {
+			ret = -ENOMEM;
 			goto free_data_skb;
+		}
 
 		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
 					       data_sync_bufs[index].
@@ -2645,6 +2647,11 @@
 		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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ahb.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ahb.c
@@ -136,8 +136,8 @@
 
 	ah = sc->sc_ah;
 	ath9k_hw_name(ah, hw_name, sizeof(hw_name));
-	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
-		   hw_name, (unsigned long)mem, irq);
+	wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n",
+		   hw_name, mem, irq);
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3351,7 +3351,8 @@
 			"Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n",
 			cptr, code, reference, length, major, minor);
 		if ((!AR_SREV_9485(ah) && length >= 1024) ||
-		    (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) {
+		    (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485) ||
+		    (length > cptr)) {
 			ath_dbg(common, EEPROM, "Skipping bad header\n");
 			cptr -= COMP_HDR_LEN;
 			continue;
@@ -4183,7 +4184,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;
@@ -5614,7 +5615,7 @@
 
 static u8 ar9003_get_eepmisc(struct ath_hw *ah)
 {
-	return ah->eeprom.map4k.baseEepHeader.eepMisc;
+	return ah->eeprom.ar9300_eep.baseEepHeader.opCapFlags.eepMisc;
 }
 
 const struct eeprom_ops eep_ar9300_ops = {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -1099,17 +1099,22 @@
 {
 	u32 dma_dbg_chain, dma_dbg_complete;
 	u8 dcu_chain_state, dcu_complete_state;
+	unsigned int dbg_reg, reg_offset;
 	int i;
 
-	for (i = 0; i < NUM_STATUS_READS; i++) {
-		if (queue < 6)
-			dma_dbg_chain = REG_READ(ah, AR_DMADBG_4);
-		else
-			dma_dbg_chain = REG_READ(ah, AR_DMADBG_5);
+	if (queue < 6) {
+		dbg_reg = AR_DMADBG_4;
+		reg_offset = queue * 5;
+	} else {
+		dbg_reg = AR_DMADBG_5;
+		reg_offset = (queue - 6) * 5;
+	}
 
+	for (i = 0; i < NUM_STATUS_READS; i++) {
+		dma_dbg_chain = REG_READ(ah, dbg_reg);
 		dma_dbg_complete = REG_READ(ah, AR_DMADBG_6);
 
-		dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f;
+		dcu_chain_state = (dma_dbg_chain >> reg_offset) & 0x1f;
 		dcu_complete_state = dma_dbg_complete & 0x3;
 
 		if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1))
@@ -1128,6 +1133,7 @@
 	u8 dcu_chain_state, dcu_complete_state;
 	bool dcu_wait_frdone = false;
 	unsigned long chk_dcu = 0;
+	unsigned int reg_offset;
 	unsigned int i = 0;
 
 	dma_dbg_4 = REG_READ(ah, AR_DMADBG_4);
@@ -1139,12 +1145,15 @@
 		goto exit;
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-		if (i < 6)
+		if (i < 6) {
 			chk_dbg = dma_dbg_4;
-		else
+			reg_offset = i * 5;
+		} else {
 			chk_dbg = dma_dbg_5;
+			reg_offset = (i - 6) * 5;
+		}
 
-		dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f;
+		dcu_chain_state = (chk_dbg >> reg_offset) & 0x1f;
 		if (dcu_chain_state == 0x6) {
 			dcu_wait_frdone = true;
 			chk_dcu |= BIT(i);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -720,7 +720,7 @@
 #define AR_CH0_TOP2		(AR_SREV_9300(ah) ? 0x1628c : \
 					(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
 #define AR_CH0_TOP2_XPABIASLVL		(AR_SREV_9561(ah) ? 0x1e00 : 0xf000)
-#define AR_CH0_TOP2_XPABIASLVL_S	12
+#define AR_CH0_TOP2_XPABIASLVL_S	(AR_SREV_9561(ah) ? 9 : 12)
 
 #define AR_CH0_XTAL		(AR_SREV_9300(ah) ? 0x16294 : \
 				 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ath9k.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -177,7 +177,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;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
@@ -84,7 +84,7 @@
 			val = swahb32(val);
 		}
 
-		__raw_writel(val, mem + reg);
+		iowrite32(val, mem + reg);
 		usleep_range(100, 120);
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/debug.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/debug.c
@@ -1223,8 +1223,11 @@
 
 	ah->nf_override = val;
 
-	if (ah->curchan)
+	if (ah->curchan) {
+		ath9k_ps_wakeup(sc);
 		ath9k_hw_loadnf(ah, ah->curchan);
+		ath9k_ps_restore(sc);
+	}
 
 	return count;
 }
@@ -1281,7 +1284,7 @@
 			  u32 sset, u8 *data)
 {
 	if (sset == ETH_SS_STATS)
-		memcpy(data, *ath9k_gstrings_stats,
+		memcpy(data, ath9k_gstrings_stats,
 		       sizeof(ath9k_gstrings_stats));
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -244,11 +244,11 @@
 		ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
 					  skb, txok);
 		if (txok) {
-			TX_STAT_INC(skb_success);
-			TX_STAT_ADD(skb_success_bytes, ln);
+			TX_STAT_INC(hif_dev, skb_success);
+			TX_STAT_ADD(hif_dev, skb_success_bytes, ln);
 		}
 		else
-			TX_STAT_INC(skb_failed);
+			TX_STAT_INC(hif_dev, skb_failed);
 	}
 }
 
@@ -302,7 +302,7 @@
 	hif_dev->tx.tx_buf_cnt++;
 	if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
 		__hif_usb_tx(hif_dev); /* Check for pending SKBs */
-	TX_STAT_INC(buf_completed);
+	TX_STAT_INC(hif_dev, buf_completed);
 	spin_unlock(&hif_dev->tx.tx_lock);
 }
 
@@ -353,7 +353,7 @@
 			tx_buf->len += tx_buf->offset;
 
 		__skb_queue_tail(&tx_buf->skb_queue, nskb);
-		TX_STAT_INC(skb_queued);
+		TX_STAT_INC(hif_dev, skb_queued);
 	}
 
 	usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev,
@@ -368,11 +368,10 @@
 		__skb_queue_head_init(&tx_buf->skb_queue);
 		list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
 		hif_dev->tx.tx_buf_cnt++;
+	} else {
+		TX_STAT_INC(hif_dev, buf_queued);
 	}
 
-	if (!ret)
-		TX_STAT_INC(buf_queued);
-
 	return ret;
 }
 
@@ -449,10 +448,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);
 }
@@ -506,7 +514,7 @@
 			ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
 						  skb, false);
 			hif_dev->tx.tx_skb_cnt--;
-			TX_STAT_INC(skb_failed);
+			TX_STAT_INC(hif_dev, skb_failed);
 		}
 	}
 
@@ -526,6 +534,24 @@
 	.send = hif_usb_send,
 };
 
+/* Need to free remain_skb allocated in ath9k_hif_usb_rx_stream
+ * in case ath9k_hif_usb_rx_stream wasn't called next time to
+ * process the buffer and subsequently free it.
+ */
+static void ath9k_hif_usb_free_rx_remain_skb(struct hif_device_usb *hif_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hif_dev->rx_lock, flags);
+	if (hif_dev->remain_skb) {
+		dev_kfree_skb_any(hif_dev->remain_skb);
+		hif_dev->remain_skb = NULL;
+		hif_dev->rx_remain_len = 0;
+		RX_STAT_INC(hif_dev, skb_dropped);
+	}
+	spin_unlock_irqrestore(&hif_dev->rx_lock, flags);
+}
+
 static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
 				    struct sk_buff *skb)
 {
@@ -553,11 +579,11 @@
 			memcpy(ptr, skb->data, rx_remain_len);
 
 			rx_pkt_len += rx_remain_len;
-			hif_dev->rx_remain_len = 0;
 			skb_put(remain_skb, rx_pkt_len);
 
 			skb_pool[pool_index++] = remain_skb;
-
+			hif_dev->remain_skb = NULL;
+			hif_dev->rx_remain_len = 0;
 		} else {
 			index = rx_remain_len;
 		}
@@ -576,9 +602,21 @@
 		pkt_len = get_unaligned_le16(ptr + index);
 		pkt_tag = get_unaligned_le16(ptr + index + 2);
 
+		/* It is supposed that if we have an invalid pkt_tag or
+		 * pkt_len then the whole input SKB is considered invalid
+		 * and dropped; the associated packets already in skb_pool
+		 * are dropped, too.
+		 */
 		if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) {
-			RX_STAT_INC(skb_dropped);
-			return;
+			RX_STAT_INC(hif_dev, skb_dropped);
+			goto invalid_pkt;
+		}
+
+		if (pkt_len > 2 * MAX_RX_BUF_SIZE) {
+			dev_err(&hif_dev->udev->dev,
+				"ath9k_htc: invalid pkt_len (%x)\n", pkt_len);
+			RX_STAT_INC(hif_dev, skb_dropped);
+			goto invalid_pkt;
 		}
 
 		pad_len = 4 - (pkt_len & 0x3);
@@ -590,11 +628,6 @@
 
 		if (index > MAX_RX_BUF_SIZE) {
 			spin_lock(&hif_dev->rx_lock);
-			hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
-			hif_dev->rx_transfer_len =
-				MAX_RX_BUF_SIZE - chk_idx - 4;
-			hif_dev->rx_pad_len = pad_len;
-
 			nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
 			if (!nskb) {
 				dev_err(&hif_dev->udev->dev,
@@ -602,8 +635,14 @@
 				spin_unlock(&hif_dev->rx_lock);
 				goto err;
 			}
+
+			hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
+			hif_dev->rx_transfer_len =
+				MAX_RX_BUF_SIZE - chk_idx - 4;
+			hif_dev->rx_pad_len = pad_len;
+
 			skb_reserve(nskb, 32);
-			RX_STAT_INC(skb_allocated);
+			RX_STAT_INC(hif_dev, skb_allocated);
 
 			memcpy(nskb->data, &(skb->data[chk_idx+4]),
 			       hif_dev->rx_transfer_len);
@@ -612,6 +651,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,
@@ -619,7 +663,7 @@
 				goto err;
 			}
 			skb_reserve(nskb, 32);
-			RX_STAT_INC(skb_allocated);
+			RX_STAT_INC(hif_dev, skb_allocated);
 
 			memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
 			skb_put(nskb, pkt_len);
@@ -629,18 +673,25 @@
 
 err:
 	for (i = 0; i < pool_index; i++) {
-		RX_STAT_ADD(skb_completed_bytes, skb_pool[i]->len);
+		RX_STAT_ADD(hif_dev, skb_completed_bytes, skb_pool[i]->len);
 		ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
 				 skb_pool[i]->len, USB_WLAN_RX_PIPE);
-		RX_STAT_INC(skb_completed);
+		RX_STAT_INC(hif_dev, skb_completed);
 	}
+	return;
+invalid_pkt:
+	for (i = 0; i < pool_index; i++) {
+		dev_kfree_skb_any(skb_pool[i]);
+		RX_STAT_INC(hif_dev, skb_dropped);
+	}
+	return;
 }
 
 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)
@@ -680,21 +731,21 @@
 	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 sk_buff *nskb;
-	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)
 		return;
 
 	if (!hif_dev)
-		goto free;
+		goto free_skb;
 
 	switch (urb->status) {
 	case 0:
@@ -703,7 +754,7 @@
 	case -ECONNRESET:
 	case -ENODEV:
 	case -ESHUTDOWN:
-		goto free;
+		goto free_skb;
 	default:
 		skb_reset_tail_pointer(skb);
 		skb_trim(skb, 0);
@@ -714,24 +765,28 @@
 	if (likely(urb->actual_length != 0)) {
 		skb_put(skb, urb->actual_length);
 
-		/* Process the command first */
+		/*
+		 * Process the command first.
+		 * skb is either freed here or passed to be
+		 * managed to another callback function.
+		 */
 		ath9k_htc_rx_msg(hif_dev->htc_handle, skb,
 				 skb->len, USB_REG_IN_PIPE);
 
-
-		nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
-		if (!nskb) {
+		skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
+		if (!skb) {
 			dev_err(&hif_dev->udev->dev,
 				"ath9k_htc: REG_IN memory allocation failure\n");
-			urb->context = NULL;
-			return;
+			goto free_rx_buf;
 		}
 
+		rx_buf->skb = skb;
+
 		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);
+				 skb->data, MAX_REG_IN_BUF_SIZE,
+				 ath9k_hif_usb_reg_in_cb, rx_buf, 1);
 	}
 
 resubmit:
@@ -739,12 +794,14 @@
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
 	if (ret) {
 		usb_unanchor_urb(urb);
-		goto free;
+		goto free_skb;
 	}
 
 	return;
-free:
+free_skb:
 	kfree_skb(skb);
+free_rx_buf:
+	kfree(rx_buf);
 	urb->context = NULL;
 }
 
@@ -753,27 +810,33 @@
 	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_kill_urb(tx_buf->urb);
 		list_del(&tx_buf->list);
 		usb_free_urb(tx_buf->urb);
 		kfree(tx_buf->buf);
 		kfree(tx_buf);
 	}
+	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);
 }
@@ -790,7 +853,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;
 
@@ -823,12 +886,14 @@
 static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
 	usb_kill_anchored_urbs(&hif_dev->rx_submitted);
+	ath9k_hif_usb_free_rx_remain_skb(hif_dev);
 }
 
 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);
@@ -836,6 +901,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) {
@@ -850,11 +921,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);
@@ -880,6 +954,8 @@
 err_skb:
 	usb_free_urb(urb);
 err_urb:
+	kfree(rx_buf);
+err_rxb:
 	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
 	return ret;
 }
@@ -891,14 +967,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) {
@@ -913,11 +996,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);
@@ -943,6 +1029,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;
 }
@@ -973,7 +1061,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);
@@ -1216,7 +1304,7 @@
 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;
@@ -1271,10 +1359,24 @@
 static int ath9k_hif_usb_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
+	struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in, *int_out;
 	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *alt;
 	struct hif_device_usb *hif_dev;
 	int ret = 0;
 
+	/* Verify the expected endpoints are present */
+	alt = interface->cur_altsetting;
+	if (usb_find_common_endpoints(alt, &bulk_in, &bulk_out, &int_in, &int_out) < 0 ||
+	    usb_endpoint_num(bulk_in) != USB_WLAN_RX_PIPE ||
+	    usb_endpoint_num(bulk_out) != USB_WLAN_TX_PIPE ||
+	    usb_endpoint_num(int_in) != USB_REG_IN_PIPE ||
+	    usb_endpoint_num(int_out) != USB_REG_OUT_PIPE) {
+		dev_err(&udev->dev,
+			"ath9k_htc: Device endpoint numbers are not the expected ones\n");
+		return -ENODEV;
+	}
+
 	if (id->driver_info == STORAGE_DEVICE)
 		return send_eject_command(interface);
 
@@ -1341,8 +1443,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -86,6 +86,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)
 
@@ -133,5 +138,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc.h
@@ -325,14 +325,18 @@
 }
 
 #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 CAB_STAT_INC   priv->debug.tx_stats.cab_queued++
-
-#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+#define __STAT_SAFE(hif_dev, expr)	do { ((hif_dev)->htc_handle->drv_priv ? (expr) : 0); } while (0)
+#define CAB_STAT_INC(priv)		do { ((priv)->debug.tx_stats.cab_queued++); } while (0)
+#define TX_QSTAT_INC(priv, q)		do { ((priv)->debug.tx_stats.queue_stats[q]++); } while (0)
+
+#define TX_STAT_INC(hif_dev, c) \
+		__STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.tx_stats.c++)
+#define TX_STAT_ADD(hif_dev, c, a) \
+		__STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.tx_stats.c += a)
+#define RX_STAT_INC(hif_dev, c) \
+		__STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.skbrx_stats.c++)
+#define RX_STAT_ADD(hif_dev, c, a) \
+		__STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.skbrx_stats.c += a)
 
 void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
 			   struct ath_rx_status *rs);
@@ -372,13 +376,13 @@
 			    struct ethtool_stats *stats, u64 *data);
 #else
 
-#define TX_STAT_INC(c) do { } while (0)
-#define TX_STAT_ADD(c, a) do { } while (0)
-#define RX_STAT_INC(c) do { } while (0)
-#define RX_STAT_ADD(c, a) do { } while (0)
-#define CAB_STAT_INC   do { } while (0)
+#define TX_STAT_INC(hif_dev, c)		do { } while (0)
+#define TX_STAT_ADD(hif_dev, c, a)	do { } while (0)
+#define RX_STAT_INC(hif_dev, c)		do { } while (0)
+#define RX_STAT_ADD(hif_dev, c, a)	do { } while (0)
 
-#define TX_QSTAT_INC(c) do { } while (0)
+#define CAB_STAT_INC(priv)
+#define TX_QSTAT_INC(priv, c)
 
 static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
 					 struct ath_rx_status *rs)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -428,7 +428,7 @@
 			      u32 sset, u8 *data)
 {
 	if (sset == ETH_SS_STATS)
-		memcpy(data, *ath9k_htc_gstrings_stats,
+		memcpy(data, ath9k_htc_gstrings_stats,
 		       sizeof(ath9k_htc_gstrings_stats));
 }
 
@@ -491,7 +491,7 @@
 
 	priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
 					     priv->hw->wiphy->debugfsdir);
-	if (!priv->debug.debugfs_phy)
+	if (IS_ERR(priv->debug.debugfs_phy))
 		return -ENOMEM;
 
 	ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -246,7 +246,7 @@
 	if (unlikely(r)) {
 		ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n",
 			reg_offset, r);
-		return -EIO;
+		return -1;
 	}
 
 	return be32_to_cpu(val);
@@ -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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1460,7 +1460,7 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		ath_key_delete(common, key->hw_key_idx);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1674,7 +1674,7 @@
 	case IEEE80211_AMPDU_TX_START:
 		ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
 		if (!ret)
-			ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+			ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -106,20 +106,20 @@
 
 	switch (qnum) {
 	case 0:
-		TX_QSTAT_INC(IEEE80211_AC_VO);
+		TX_QSTAT_INC(priv, IEEE80211_AC_VO);
 		epid = priv->data_vo_ep;
 		break;
 	case 1:
-		TX_QSTAT_INC(IEEE80211_AC_VI);
+		TX_QSTAT_INC(priv, IEEE80211_AC_VI);
 		epid = priv->data_vi_ep;
 		break;
 	case 2:
-		TX_QSTAT_INC(IEEE80211_AC_BE);
+		TX_QSTAT_INC(priv, IEEE80211_AC_BE);
 		epid = priv->data_be_ep;
 		break;
 	case 3:
 	default:
-		TX_QSTAT_INC(IEEE80211_AC_BK);
+		TX_QSTAT_INC(priv, IEEE80211_AC_BK);
 		epid = priv->data_bk_ep;
 		break;
 	}
@@ -323,7 +323,7 @@
 	memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
 
 	if (is_cab) {
-		CAB_STAT_INC;
+		CAB_STAT_INC(priv);
 		tx_ctl->epid = priv->cab_ep;
 		return;
 	}
@@ -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);
@@ -973,6 +974,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",
@@ -982,11 +985,32 @@
 
 	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;
+	}
+
+	if (rxstatus->rs_keyix >= ATH_KEYMAX &&
+	    rxstatus->rs_keyix != ATH9K_RXKEYIX_INVALID) {
+		ath_dbg(common, ANY,
+			"Invalid keyix, dropping (keyix: %d)\n",
+			rxstatus->rs_keyix);
 		goto rx_next;
 	}
 
@@ -1011,7 +1035,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -30,6 +30,7 @@
 	hdr->endpoint_id = epid;
 	hdr->flags = flags;
 	hdr->payload_len = cpu_to_be16(len);
+	memset(hdr->control, 0, sizeof(hdr->control));
 
 	status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
 
@@ -113,6 +114,15 @@
 
 	if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
 		epid = svc_rspmsg->endpoint_id;
+
+		/* Check that the received epid for the endpoint to attach
+		 * a new service is valid. ENDPOINT0 can't be used here as it
+		 * is already reserved for HTC_CTRL_RSVD_SVC service and thus
+		 * should not be modified.
+		 */
+		if (epid <= ENDPOINT0 || 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];
@@ -170,7 +180,6 @@
 	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;
 	}
 
@@ -206,7 +215,6 @@
 	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;
 	}
 
@@ -271,6 +279,10 @@
 	conn_msg->dl_pipeid = endpoint->dl_pipeid;
 	conn_msg->ul_pipeid = endpoint->ul_pipeid;
 
+	/* To prevent infoleak */
+	conn_msg->svc_meta_len = 0;
+	conn_msg->pad = 0;
+
 	ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 	if (ret)
 		goto err;
@@ -279,7 +291,6 @@
 	if (!time_left) {
 		dev_err(target->dev, "Service connection timeout for: %d\n",
 			service_connreq->service_id);
-		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
@@ -339,6 +350,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));
 
@@ -357,40 +370,34 @@
 }
 
 static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
-				      struct sk_buff *skb)
+				      struct sk_buff *skb, u32 len)
 {
 	uint32_t *pattern = (uint32_t *)skb->data;
 
-	switch (*pattern) {
-	case 0x33221199:
-		{
+	if (*pattern == 0x33221199 && len >= sizeof(struct htc_panic_bad_vaddr)) {
 		struct htc_panic_bad_vaddr *htc_panic;
 		htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
 		dev_err(htc_handle->dev, "ath: firmware panic! "
 			"exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
 			htc_panic->exccause, htc_panic->pc,
 			htc_panic->badvaddr);
-		break;
-		}
-	case 0x33221299:
-		{
+		return;
+	}
+	if (*pattern == 0x33221299) {
 		struct htc_panic_bad_epid *htc_panic;
 		htc_panic = (struct htc_panic_bad_epid *) skb->data;
 		dev_err(htc_handle->dev, "ath: firmware panic! "
 			"bad epid: 0x%08x\n", htc_panic->epid);
-		break;
-		}
-	default:
-		dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
-		break;
+		return;
 	}
+	dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
 }
 
 /*
  * HTC Messages are handled directly here and the obtained SKB
  * is freed.
  *
- * Service messages (Data, WMI) passed to the corresponding
+ * Service messages (Data, WMI) are passed to the corresponding
  * endpoint RX handlers, which have to free the SKB.
  */
 void ath9k_htc_rx_msg(struct htc_target *htc_handle,
@@ -404,16 +411,26 @@
 	if (!htc_handle || !skb)
 		return;
 
+	/* A valid message requires len >= 8.
+	 *
+	 *   sizeof(struct htc_frame_hdr) == 8
+	 *   sizeof(struct htc_ready_msg) == 8
+	 *   sizeof(struct htc_panic_bad_vaddr) == 16
+	 *   sizeof(struct htc_panic_bad_epid) == 8
+	 */
+	if (unlikely(len < sizeof(struct htc_frame_hdr)))
+		goto invalid;
 	htc_hdr = (struct htc_frame_hdr *) skb->data;
 	epid = htc_hdr->endpoint_id;
 
 	if (epid == 0x99) {
-		ath9k_htc_fw_panic_report(htc_handle, skb);
+		ath9k_htc_fw_panic_report(htc_handle, skb, len);
 		kfree_skb(skb);
 		return;
 	}
 
 	if (epid < 0 || epid >= ENDPOINT_MAX) {
+invalid:
 		if (pipe_id != USB_REG_IN_PIPE)
 			dev_kfree_skb_any(skb);
 		else
@@ -425,21 +442,30 @@
 
 		/* Handle trailer */
 		if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
-			if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
+			if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) {
 				/* Move past the Watchdog pattern */
 				htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
+				len -= 4;
+			}
 		}
 
 		/* Get the message ID */
+		if (unlikely(len < sizeof(struct htc_frame_hdr) + sizeof(__be16)))
+			goto invalid;
 		msg_id = (__be16 *) ((void *) htc_hdr +
 				     sizeof(struct htc_frame_hdr));
 
 		/* Now process HTC messages */
 		switch (be16_to_cpu(*msg_id)) {
 		case HTC_MSG_READY_ID:
+			if (unlikely(len < sizeof(struct htc_ready_msg)))
+				goto invalid;
 			htc_process_target_rdy(htc_handle, htc_hdr);
 			break;
 		case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
+			if (unlikely(len < sizeof(struct htc_frame_hdr) +
+				     sizeof(struct htc_conn_svc_rspmsg)))
+				goto invalid;
 			htc_process_conn_rsp(htc_handle, htc_hdr);
 			break;
 		default:
@@ -458,6 +484,8 @@
 		if (endpoint->ep_callbacks.rx)
 			endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
 						  skb, epid);
+		else
+			goto invalid;
 	}
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/hw.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/hw.c
@@ -287,7 +287,7 @@
 
 	srev = REG_READ(ah, AR_SREV);
 
-	if (srev == -EIO) {
+	if (srev == -1) {
 		ath_err(ath9k_hw_common(ah),
 			"Failed to read SREV register");
 		return false;
@@ -1622,7 +1622,6 @@
 		ath9k_hw_gpio_request_out(ah, i, NULL,
 					  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 		ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
-		ath9k_hw_gpio_free(ah, i);
 	}
 }
 
@@ -2730,14 +2729,17 @@
 static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
 				  const char *label)
 {
+	int err;
+
 	if (ah->caps.gpio_requested & BIT(gpio))
 		return;
 
-	/* may be requested by BSP, free anyway */
-	gpio_free(gpio);
-
-	if (gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label))
+	err = gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label);
+	if (err) {
+		ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n",
+			gpio, err);
 		return;
+	}
 
 	ah->caps.gpio_requested |= BIT(gpio);
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/hw.h
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/hw.h
@@ -819,6 +819,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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/init.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/init.c
@@ -230,7 +230,7 @@
 	struct ath_hw *ah = hw_priv;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_softc *sc = (struct ath_softc *) common->priv;
-	unsigned long uninitialized_var(flags);
+	unsigned long flags;
 	u32 val;
 
 	if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/main.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/main.c
@@ -200,7 +200,7 @@
 void ath_restart_work(struct ath_softc *sc)
 {
 	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
-				     ATH_HW_CHECK_POLL_INT);
+				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
 
 	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
 		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
@@ -304,6 +304,11 @@
 		hchan = ah->curchan;
 	}
 
+	if (!hchan) {
+		fastcc = false;
+		hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef);
+	}
+
 	if (!ath_prepare_reset(sc))
 		fastcc = false;
 
@@ -525,8 +530,10 @@
 	ath9k_debug_sync_cause(sc, sync_cause);
 	status &= ah->imask;	/* discard unasked-for bits */
 
-	if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
+	if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
+		ath9k_hw_kill_interrupts(sc->sc_ah);
 		return IRQ_HANDLED;
+	}
 
 	/*
 	 * If there are no status bits set, then this interrupt was not
@@ -818,12 +825,81 @@
 	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->status.status_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, j;
+	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;
+
+			for (j = 0; !key_in_use &&
+			     !list_empty(&txq->txq_fifo[idx]) &&
+			     j < ATH_TXFIFO_DEPTH; j++) {
+				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);
 
@@ -891,6 +967,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;
@@ -1457,6 +1541,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);
 
@@ -1533,12 +1620,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;
 }
@@ -1700,6 +1786,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)
@@ -1729,7 +1821,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)
@@ -1921,7 +2021,7 @@
 		ath9k_ps_wakeup(sc);
 		ret = ath_tx_aggr_start(sc, sta, tid, ssn);
 		if (!ret)
-			ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+			ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		ath9k_ps_restore(sc);
 		break;
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
@@ -2128,7 +2228,7 @@
 	}
 
 	ieee80211_queue_delayed_work(hw, &sc->hw_check_work,
-				     ATH_HW_CHECK_POLL_INT);
+				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
 }
 
 static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/pci.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/pci.c
@@ -993,8 +993,8 @@
 	sc->sc_ah->msi_reg = 0;
 
 	ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
-	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
-		   hw_name, (unsigned long)sc->mem, pdev->irq);
+	wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n",
+		   hw_name, sc->mem, pdev->irq);
 
 	return 0;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/wmi.c
+++ linux-ein-5.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);
 }
 
@@ -215,6 +218,10 @@
 	if (unlikely(wmi->stopped))
 		goto free_skb;
 
+	/* Validate the obtained SKB. */
+	if (unlikely(skb->len < sizeof(struct wmi_cmd_hdr)))
+		goto free_skb;
+
 	hdr = (struct wmi_cmd_hdr *) skb->data;
 	cmd_id = be16_to_cpu(hdr->command_id);
 
@@ -232,10 +239,10 @@
 		spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 		goto free_skb;
 	}
-	spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 
 	/* WMI command response */
 	ath9k_wmi_rsp_callback(wmi, skb);
+	spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 
 free_skb:
 	kfree_skb(skb);
@@ -273,7 +280,8 @@
 
 static int ath9k_wmi_cmd_issue(struct wmi *wmi,
 			       struct sk_buff *skb,
-			       enum wmi_cmd_id cmd, u16 len)
+			       enum wmi_cmd_id cmd, u16 len,
+			       u8 *rsp_buf, u32 rsp_len)
 {
 	struct wmi_cmd_hdr *hdr;
 	unsigned long flags;
@@ -283,6 +291,11 @@
 	hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
 
 	spin_lock_irqsave(&wmi->wmi_lock, flags);
+
+	/* record the rsp buffer and length */
+	wmi->cmd_rsp_buf = rsp_buf;
+	wmi->cmd_rsp_len = rsp_len;
+
 	wmi->last_seq_id = wmi->tx_seq_id;
 	spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 
@@ -298,8 +311,8 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	u16 headroom = sizeof(struct htc_frame_hdr) +
 		       sizeof(struct wmi_cmd_hdr);
+	unsigned long time_left, flags;
 	struct sk_buff *skb;
-	unsigned long time_left;
 	int ret = 0;
 
 	if (ah->ah_flags & AH_UNPLUGGED)
@@ -323,11 +336,7 @@
 		goto out;
 	}
 
-	/* record the rsp buffer and length */
-	wmi->cmd_rsp_buf = rsp_buf;
-	wmi->cmd_rsp_len = rsp_len;
-
-	ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
+	ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len);
 	if (ret)
 		goto out;
 
@@ -335,8 +344,10 @@
 	if (!time_left) {
 		ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
 			wmi_cmd_to_name(cmd_id));
+		spin_lock_irqsave(&wmi->wmi_lock, flags);
+		wmi->last_seq_id = 0;
+		spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 		mutex_unlock(&wmi->op_mutex);
-		kfree_skb(skb);
 		return -ETIMEDOUT;
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/wmi.h
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/wireless/ath/ath9k/xmit.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/ath9k/xmit.c
@@ -141,8 +141,8 @@
 {
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	BUILD_BUG_ON(sizeof(struct ath_frame_info) >
-		     sizeof(tx_info->rate_driver_data));
-	return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
+		     sizeof(tx_info->status.status_driver_data));
+	return (struct ath_frame_info *) &tx_info->status.status_driver_data[0];
 }
 
 static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno)
@@ -1271,6 +1271,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);
@@ -2111,6 +2116,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;
@@ -2492,6 +2498,16 @@
 	spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
 }
 
+static void ath_clear_tx_status(struct ieee80211_tx_info *tx_info)
+{
+	void *ptr = &tx_info->status;
+
+	memset(ptr + sizeof(tx_info->status.rates), 0,
+	       sizeof(tx_info->status) -
+	       sizeof(tx_info->status.rates) -
+	       sizeof(tx_info->status.status_driver_data));
+}
+
 static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
 			     struct ath_tx_status *ts, int nframes, int nbad,
 			     int txok)
@@ -2503,6 +2519,8 @@
 	struct ath_hw *ah = sc->sc_ah;
 	u8 i, tx_rateindex;
 
+	ath_clear_tx_status(tx_info);
+
 	if (txok)
 		tx_info->status.ack_signal = ts->ts_rssi;
 
@@ -2517,6 +2535,13 @@
 	tx_info->status.ampdu_len = nframes;
 	tx_info->status.ampdu_ack_len = nframes - nbad;
 
+	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
+
+	for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
+		tx_info->status.rates[i].count = 0;
+		tx_info->status.rates[i].idx = -1;
+	}
+
 	if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
 	    (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) {
 		/*
@@ -2538,16 +2563,6 @@
 			tx_info->status.rates[tx_rateindex].count =
 				hw->max_rate_tries;
 	}
-
-	for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
-		tx_info->status.rates[i].count = 0;
-		tx_info->status.rates[i].idx = -1;
-	}
-
-	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
-
-	/* we report airtime in ath_tx_count_airtime(), don't report twice */
-	tx_info->status.tx_time = 0;
 }
 
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/carl9170/Kconfig
+++ linux-ein-5.4.0/drivers/net/wireless/ath/carl9170/Kconfig
@@ -16,13 +16,11 @@
 
 config CARL9170_LEDS
 	bool "SoftLED Support"
-	depends on CARL9170
-	select MAC80211_LEDS
-	select LEDS_CLASS
-	select NEW_LEDS
 	default y
+	depends on CARL9170
+	depends on MAC80211_LEDS
 	help
-	  This option is necessary, if you want your device' LEDs to blink
+	  This option is necessary, if you want your device's LEDs to blink.
 
 	  Say Y, unless you need the LEDs for firmware debugging.
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/carl9170/fw.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/carl9170/fw.c
@@ -338,9 +338,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-ein-5.4.0.orig/drivers/net/wireless/ath/carl9170/main.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/carl9170/main.c
@@ -582,11 +582,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 +638,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();
 
@@ -1449,8 +1436,7 @@
 		rcu_assign_pointer(sta_info->agg[tid], tid_info);
 		spin_unlock_bh(&ar->tx_ampdu_list_lock);
 
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-		break;
+		return IEEE80211_AMPDU_TX_START_IMMEDIATE;
 
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
@@ -1930,7 +1916,7 @@
 		WARN_ON(!(tx_streams >= 1 && tx_streams <=
 			IEEE80211_HT_MCS_TX_MAX_STREAMS));
 
-		tx_params = (tx_streams - 1) <<
+		tx_params |= (tx_streams - 1) <<
 			    IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
 
 		carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/carl9170/tx.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/carl9170/tx.c
@@ -1557,6 +1557,9 @@
 					goto out;
 			}
 		} while (ar->beacon_enabled && i--);
+
+		/* no entry found in list */
+		return NULL;
 	}
 
 out:
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -182,10 +182,12 @@
 	if (cd == NULL)
 		return;
 	list_del(&cd->head);
-	for (i = 0; i < dpd->num_radar_types; i++) {
-		struct pri_detector *de = cd->detectors[i];
-		if (de != NULL)
-			de->exit(de);
+	if (cd->detectors) {
+		for (i = 0; i < dpd->num_radar_types; i++) {
+			struct pri_detector *de = cd->detectors[i];
+			if (de != NULL)
+				de->exit(de);
+		}
 	}
 	kfree(cd->detectors);
 	kfree(cd);
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/key.c
+++ linux-ein-5.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-ein-5.4.0.orig/drivers/net/wireless/ath/wcn36xx/Kconfig
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wcn36xx/Kconfig
@@ -17,3 +17,12 @@
 	  Enabled debugfs support
 
 	  If unsure, say Y to make it easier to debug problems.
+
+config WCN36XX_SNAPDRAGON_HACKS
+	bool "Dragonboard 410c WCN36XX MAC address generation hacks"
+	default n
+	depends on WCN36XX
+	---help---
+	  Upon probe, WCN36XX will try to read its MAC address from
+	  a file located at /lib/firmware/wlan/macaddr0. If the file
+	  is not present, it will randomly generate a new MAC address.
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -563,6 +563,10 @@
 	dxe = ctl->desc;
 
 	while (!(READ_ONCE(dxe->ctrl) & WCN36xx_DXE_CTRL_VLD)) {
+		/* do not read until we own DMA descriptor */
+		dma_rmb();
+
+		/* read/modify DMA descriptor */
 		skb = ctl->skb;
 		dma_addr = dxe->dst_addr_l;
 		ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl, GFP_ATOMIC);
@@ -573,9 +577,15 @@
 			dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
 					DMA_FROM_DEVICE);
 			wcn36xx_rx_skb(wcn, skb);
-		} /* else keep old skb not submitted and use it for rx DMA */
+		}
+		/* else keep old skb not submitted and reuse it for rx DMA
+		 * (dropping the packet that it contained)
+		 */
 
+		/* flush descriptor changes before re-marking as valid */
+		dma_wmb();
 		dxe->ctrl = ctrl;
+
 		ctl = ctl->next;
 		dxe = ctl->desc;
 	}
@@ -942,4 +952,9 @@
 
 	wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch);
 	wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch);
+
+	wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_l_ch);
+	wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_h_ch);
+	wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_l_ch);
+	wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_h_ch);
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wcn36xx/main.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wcn36xx/main.c
@@ -134,7 +134,9 @@
 		.cap =	IEEE80211_HT_CAP_GRN_FLD |
 			IEEE80211_HT_CAP_SGI_20 |
 			IEEE80211_HT_CAP_DSSSCCK40 |
-			IEEE80211_HT_CAP_LSIG_TXOP_PROT,
+			IEEE80211_HT_CAP_LSIG_TXOP_PROT |
+			IEEE80211_HT_CAP_SGI_40 |
+			IEEE80211_HT_CAP_SUP_WIDTH_20_40,
 		.ht_supported = true,
 		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
 		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -163,7 +165,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,
 		}
 	}
@@ -293,23 +295,16 @@
 		goto out_free_dxe_pool;
 	}
 
-	wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
-	if (!wcn->hal_buf) {
-		wcn36xx_err("Failed to allocate smd buf\n");
-		ret = -ENOMEM;
-		goto out_free_dxe_ctl;
-	}
-
 	ret = wcn36xx_smd_load_nv(wcn);
 	if (ret) {
 		wcn36xx_err("Failed to push NV to chip\n");
-		goto out_free_smd_buf;
+		goto out_free_dxe_ctl;
 	}
 
 	ret = wcn36xx_smd_start(wcn);
 	if (ret) {
 		wcn36xx_err("Failed to start chip\n");
-		goto out_free_smd_buf;
+		goto out_free_dxe_ctl;
 	}
 
 	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
@@ -336,8 +331,6 @@
 
 out_smd_stop:
 	wcn36xx_smd_stop(wcn);
-out_free_smd_buf:
-	kfree(wcn->hal_buf);
 out_free_dxe_ctl:
 	wcn36xx_dxe_free_ctl_blks(wcn);
 out_free_dxe_pool:
@@ -374,8 +367,6 @@
 
 	wcn36xx_dxe_free_mem_pools(wcn);
 	wcn36xx_dxe_free_ctl_blks(wcn);
-
-	kfree(wcn->hal_buf);
 }
 
 static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
@@ -1084,6 +1075,7 @@
 	enum ieee80211_ampdu_mlme_action action = params->action;
 	u16 tid = params->tid;
 	u16 *ssn = &params->ssn;
+	int ret = 0;
 
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
 		    action, tid);
@@ -1106,7 +1098,7 @@
 		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
 		spin_unlock_bh(&sta_priv->ampdu_lock);
 
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		spin_lock_bh(&sta_priv->ampdu_lock);
@@ -1131,7 +1123,7 @@
 
 	mutex_unlock(&wcn->conf_mutex);
 
-	return 0;
+	return ret;
 }
 
 static const struct ieee80211_ops wcn36xx_ops = {
@@ -1302,6 +1294,14 @@
 	void *wcnss;
 	int ret;
 	const u8 *addr;
+#ifdef	CONFIG_WCN36XX_SNAPDRAGON_HACKS
+	int status;
+	const struct firmware *addr_file = NULL;
+	u8 tmp[18], _addr[ETH_ALEN];
+	static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
+	static const char *files = {"wlan/macaddr0"};
+#endif
+
 
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
 
@@ -1322,6 +1322,12 @@
 	mutex_init(&wcn->hal_mutex);
 	mutex_init(&wcn->scan_lock);
 
+	wcn->hal_buf = devm_kmalloc(wcn->dev, WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
+	if (!wcn->hal_buf) {
+		ret = -ENOMEM;
+		goto out_wq;
+	}
+
 	ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
 	if (ret < 0) {
 		wcn36xx_err("failed to set DMA mask: %d\n", ret);
@@ -1341,15 +1347,43 @@
 	if (addr && ret != ETH_ALEN) {
 		wcn36xx_err("invalid local-mac-address\n");
 		ret = -EINVAL;
-		goto out_wq;
-	} else if (addr) {
+		goto out_destroy_ept;
+	}
+#ifdef	CONFIG_WCN36XX_SNAPDRAGON_HACKS
+	else if (addr == NULL) {
+		addr = _addr;
+		status = request_firmware(&addr_file, files, &pdev->dev);
+
+		if (status < 0) {
+			/* Assign a random mac with Qualcomm oui */
+			dev_err(&pdev->dev, "Failed (%d) to read macaddress"
+			"file %s, using a random address instead", status, files);
+			memcpy(addr, qcom_oui, 3);
+			get_random_bytes(addr + 3, 3);
+		} else {
+			memset(tmp, 0, sizeof(tmp));
+			memcpy(tmp, addr_file->data, sizeof(tmp) - 1);
+			sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+			&addr[0],
+			&addr[1],
+			&addr[2],
+			&addr[3],
+			&addr[4],
+			&addr[5]);
+
+			release_firmware(addr_file);
+		}
+	}
+#endif
+
+	if (addr) {
 		wcn36xx_info("mac address: %pM\n", addr);
 		SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
 	}
 
 	ret = wcn36xx_platform_get_resources(wcn, pdev);
 	if (ret)
-		goto out_wq;
+		goto out_destroy_ept;
 
 	wcn36xx_init_ieee80211(wcn);
 	ret = ieee80211_register_hw(wcn->hw);
@@ -1361,6 +1395,8 @@
 out_unmap:
 	iounmap(wcn->ccu_base);
 	iounmap(wcn->dxe_base);
+out_destroy_ept:
+	rpmsg_destroy_ept(wcn->smd_channel);
 out_wq:
 	ieee80211_free_hw(hw);
 out_err:
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wcn36xx/smd.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -2311,7 +2311,7 @@
 			wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
 				    tmp->bss_index);
 			vif = wcn36xx_priv_to_vif(tmp);
-			ieee80211_connection_loss(vif);
+			ieee80211_beacon_loss(vif);
 		}
 		return 0;
 	}
@@ -2326,7 +2326,7 @@
 			wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
 				    rsp->bss_index);
 			vif = wcn36xx_priv_to_vif(tmp);
-			ieee80211_connection_loss(vif);
+			ieee80211_beacon_loss(vif);
 			return 0;
 		}
 	}
@@ -2340,30 +2340,52 @@
 					      size_t len)
 {
 	struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;
-	struct wcn36xx_vif *tmp;
+	struct wcn36xx_vif *vif_priv;
+	struct ieee80211_vif *vif;
+	struct ieee80211_bss_conf *bss_conf;
 	struct ieee80211_sta *sta;
+	bool found = false;
 
 	if (len != sizeof(*rsp)) {
 		wcn36xx_warn("Corrupted delete sta indication\n");
 		return -EIO;
 	}
 
-	wcn36xx_dbg(WCN36XX_DBG_HAL, "delete station indication %pM index %d\n",
-		    rsp->addr2, rsp->sta_id);
+	wcn36xx_dbg(WCN36XX_DBG_HAL,
+		    "delete station indication %pM index %d reason %d\n",
+		    rsp->addr2, rsp->sta_id, rsp->reason_code);
 
-	list_for_each_entry(tmp, &wcn->vif_list, list) {
+	list_for_each_entry(vif_priv, &wcn->vif_list, list) {
 		rcu_read_lock();
-		sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
-		if (sta)
-			ieee80211_report_low_ack(sta, 0);
+		vif = wcn36xx_priv_to_vif(vif_priv);
+
+		if (vif->type == NL80211_IFTYPE_STATION) {
+			/* We could call ieee80211_find_sta too, but checking
+			 * bss_conf is clearer.
+			 */
+			bss_conf = &vif->bss_conf;
+			if (vif_priv->sta_assoc &&
+			    !memcmp(bss_conf->bssid, rsp->addr2, ETH_ALEN)) {
+				found = true;
+				wcn36xx_dbg(WCN36XX_DBG_HAL,
+					    "connection loss bss_index %d\n",
+					    vif_priv->bss_index);
+				ieee80211_connection_loss(vif);
+			}
+		} else {
+			sta = ieee80211_find_sta(vif, rsp->addr2);
+			if (sta) {
+				found = true;
+				ieee80211_report_low_ack(sta, 0);
+			}
+		}
+
 		rcu_read_unlock();
-		if (sta)
+		if (found)
 			return 0;
 	}
 
-	wcn36xx_warn("STA with addr %pM and index %d not found\n",
-		     rsp->addr2,
-		     rsp->sta_id);
+	wcn36xx_warn("BSS or STA with addr %pM not found\n", rsp->addr2);
 	return -ENOENT;
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wil6210/Kconfig
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wil6210/Kconfig
@@ -2,6 +2,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-ein-5.4.0.orig/drivers/net/wireless/ath/wil6210/debugfs.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1021,20 +1021,14 @@
 	void *cmd;
 	int cmdlen = len - sizeof(struct wmi_cmd_hdr);
 	u16 cmdid;
-	int rc, rc1;
+	int rc1;
 
-	if (cmdlen < 0)
+	if (cmdlen < 0 || *ppos != 0)
 		return -EINVAL;
 
-	wmi = kmalloc(len, GFP_KERNEL);
-	if (!wmi)
-		return -ENOMEM;
-
-	rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
-	if (rc < 0) {
-		kfree(wmi);
-		return rc;
-	}
+	wmi = memdup_user(buf, len);
+	if (IS_ERR(wmi))
+		return PTR_ERR(wmi);
 
 	cmd = (cmdlen > 0) ? &wmi[1] : NULL;
 	cmdid = le16_to_cpu(wmi->command_id);
@@ -1044,7 +1038,7 @@
 
 	wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
 
-	return rc;
+	return len;
 }
 
 static const struct file_operations fops_wmi = {
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -880,6 +880,7 @@
 	u8 data_offset;
 	struct wil_rx_status_extended *s;
 	u16 sring_idx = sring - wil->srings;
+	int invalid_buff_id_retry;
 
 	BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));
 
@@ -893,9 +894,9 @@
 	/* Extract the buffer ID from the status message */
 	buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg));
 
+	invalid_buff_id_retry = 0;
 	while (!buff_id) {
 		struct wil_rx_status_extended *s;
-		int invalid_buff_id_retry = 0;
 
 		wil_dbg_txrx(wil,
 			     "buff_id is not updated yet by HW, (swhead 0x%x)\n",
--- linux-ein-5.4.0.orig/drivers/net/wireless/ath/wil6210/wmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/ath/wil6210/wmi.c
@@ -2505,7 +2505,8 @@
 	cmd->mgmt_frm_type = type;
 	/* BUG: FW API define ieLen as u8. Will fix FW */
 	cmd->ie_len = cpu_to_le16(ie_len);
-	memcpy(cmd->ie_info, ie, ie_len);
+	if (ie_len)
+		memcpy(cmd->ie_info, ie, ie_len);
 	rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len);
 	kfree(cmd);
 out:
@@ -2541,7 +2542,8 @@
 	}
 
 	cmd->ie_len = cpu_to_le16(ie_len);
-	memcpy(cmd->ie_info, ie, ie_len);
+	if (ie_len)
+		memcpy(cmd->ie_info, ie, ie_len);
 	rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len);
 	kfree(cmd);
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/atmel/atmel_cs.c
+++ linux-ein-5.4.0/drivers/net/wireless/atmel/atmel_cs.c
@@ -73,6 +73,7 @@
 static int atmel_probe(struct pcmcia_device *p_dev)
 {
 	struct local_info *local;
+	int ret;
 
 	dev_dbg(&p_dev->dev, "atmel_attach()\n");
 
@@ -83,8 +84,16 @@
 
 	p_dev->priv = local;
 
-	return atmel_config(p_dev);
-} /* atmel_attach */
+	ret = atmel_config(p_dev);
+	if (ret)
+		goto err_free_priv;
+
+	return 0;
+
+err_free_priv:
+	kfree(p_dev->priv);
+	return ret;
+}
 
 static void atmel_detach(struct pcmcia_device *link)
 {
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/b43.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/b43.h
@@ -651,7 +651,7 @@
 	union {
 		__be16 d16;
 		__be32 d32;
-	} data __packed;
+	} __packed data;
 } __packed;
 
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/debugfs.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/debugfs.c
@@ -493,7 +493,7 @@
 	struct b43_wldev *dev;
 	struct b43_debugfs_fops *dfops;
 	struct b43_dfs_file *dfile;
-	ssize_t uninitialized_var(ret);
+	ssize_t ret;
 	char *buf;
 	const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
 	const size_t buforder = get_order(bufsize);
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/dma.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/dma.c
@@ -37,7 +37,7 @@
 static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
 			   enum b43_addrtype addrtype)
 {
-	u32 uninitialized_var(addr);
+	u32 addr;
 
 	switch (addrtype) {
 	case B43_DMA_ADDR_LOW:
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/lo.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/lo.c
@@ -729,7 +729,7 @@
 	};
 	int max_rx_gain;
 	struct b43_lo_calib *cal;
-	struct lo_g_saved_values uninitialized_var(saved_regs);
+	struct lo_g_saved_values saved_regs;
 	/* Values from the "TXCTL Register and Value Table" */
 	u16 txctl_reg;
 	u16 txctl_value;
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/main.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/main.c
@@ -5569,7 +5569,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-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/phy_g.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/phy_g.c
@@ -2297,7 +2297,7 @@
 	b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
 	b43_set_all_gains(dev, 3, 8, 1);
 
-	start = (channel - 5 > 0) ? channel - 5 : 1;
+	start = (channel > 5) ? channel - 5 : 1;
 	end = (channel + 5 < 14) ? channel + 5 : 13;
 
 	for (i = start; i <= end; i++) {
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/phy_n.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/phy_n.c
@@ -582,7 +582,7 @@
 	u16 data[4];
 	s16 gain[2];
 	u16 minmax[2];
-	static const u16 lna_gain[4] = { -2, 10, 19, 25 };
+	static const s16 lna_gain[4] = { -2, 10, 19, 25 };
 
 	if (nphy->hang_avoid)
 		b43_nphy_stay_in_carrier_search(dev, 1);
@@ -5308,7 +5308,7 @@
 
 	for (i = 0; i < 4; i++) {
 		if (dev->phy.rev >= 3)
-			table[i] = coef[i];
+			coef[i] = table[i];
 		else
 			coef[i] = 0;
 	}
@@ -5643,7 +5643,7 @@
 	u8 rfctl[2];
 	u8 afectl_core;
 	u16 tmp[6];
-	u16 uninitialized_var(cur_hpf1), uninitialized_var(cur_hpf2), cur_lna;
+	u16 cur_hpf1, cur_hpf2, cur_lna;
 	u32 real, imag;
 	enum nl80211_band band;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43/xmit.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43/xmit.c
@@ -422,10 +422,10 @@
 	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
 	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
 		unsigned int len;
-		struct ieee80211_hdr *uninitialized_var(hdr);
+		struct ieee80211_hdr *hdr;
 		int rts_rate, rts_rate_fb;
 		int rts_rate_ofdm, rts_rate_fb_ofdm;
-		struct b43_plcp_hdr6 *uninitialized_var(plcp);
+		struct b43_plcp_hdr6 *plcp;
 		struct ieee80211_rate *rts_cts_rate;
 
 		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
@@ -436,7 +436,7 @@
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
 		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
-			struct ieee80211_cts *uninitialized_var(cts);
+			struct ieee80211_cts *cts;
 
 			switch (dev->fw.hdr_format) {
 			case B43_FW_HDR_598:
@@ -458,7 +458,7 @@
 			mac_ctl |= B43_TXH_MAC_SENDCTS;
 			len = sizeof(struct ieee80211_cts);
 		} else {
-			struct ieee80211_rts *uninitialized_var(rts);
+			struct ieee80211_rts *rts;
 
 			switch (dev->fw.hdr_format) {
 			case B43_FW_HDR_598:
@@ -650,8 +650,8 @@
 	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
 	__le16 fctl;
 	u16 phystat0, phystat3;
-	u16 uninitialized_var(chanstat), uninitialized_var(mactime);
-	u32 uninitialized_var(macstat);
+	u16 chanstat, mactime;
+	u32 macstat;
 	u16 chanid;
 	int padding, rate_idx;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/b43legacy.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/b43legacy.h
@@ -379,7 +379,7 @@
 	union {
 		__be16 d16;
 		__be32 d32;
-	} data __packed;
+	} __packed data;
 } __packed;
 
 #define B43legacy_PHYMODE(phytype)	(1 << (phytype))
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/debugfs.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/debugfs.c
@@ -190,7 +190,7 @@
 	struct b43legacy_wldev *dev;
 	struct b43legacy_debugfs_fops *dfops;
 	struct b43legacy_dfs_file *dfile;
-	ssize_t uninitialized_var(ret);
+	ssize_t ret;
 	char *buf;
 	const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
 	const size_t buforder = get_order(bufsize);
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/main.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -1275,8 +1275,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;
@@ -2579,7 +2580,7 @@
 static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
 				      unsigned int new_mode)
 {
-	struct b43legacy_wldev *uninitialized_var(up_dev);
+	struct b43legacy_wldev *up_dev;
 	struct b43legacy_wldev *down_dev;
 	int err;
 	bool gmode = false;
@@ -3741,7 +3742,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;
@@ -3800,6 +3801,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-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/phy.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/phy.c
@@ -1123,7 +1123,7 @@
 	struct b43legacy_phy *phy = &dev->phy;
 	u16 regstack[12] = { 0 };
 	u16 mls;
-	u16 fval;
+	s16 fval;
 	int i;
 	int j;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/radio.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/radio.c
@@ -283,7 +283,7 @@
 			    & 0x7FFF);
 	b43legacy_set_all_gains(dev, 3, 8, 1);
 
-	start = (channel - 5 > 0) ? channel - 5 : 1;
+	start = (channel > 5) ? channel - 5 : 1;
 	end = (channel + 5 < 14) ? channel + 5 : 13;
 
 	for (i = start; i <= end; i++) {
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/b43legacy/xmit.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/b43legacy/xmit.c
@@ -558,6 +558,7 @@
 	default:
 		b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
 		       chanstat);
+		goto drop;
 	}
 
 	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -951,6 +951,9 @@
 #define BRCMF_SDIO_DEVICE(dev_id)	\
 	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)}
 
+#define CYF_SDIO_DEVICE(dev_id)	\
+	{SDIO_DEVICE(SDIO_VENDOR_ID_CYPRESS, dev_id)}
+
 /* devices we support, null terminated */
 static const struct sdio_device_id brcmf_sdmmc_ids[] = {
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143),
@@ -969,8 +972,10 @@
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
+	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373),
 	BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012),
+	CYF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43439),
 	{ /* end: all zeroes */ }
 };
 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
@@ -1168,13 +1173,9 @@
 	},
 };
 
-void brcmf_sdio_register(void)
+int brcmf_sdio_register(void)
 {
-	int ret;
-
-	ret = sdio_register_driver(&brcmf_sdmmc_driver);
-	if (ret)
-		brcmf_err("sdio_register_driver failed: %d\n", ret);
+	return sdio_register_driver(&brcmf_sdmmc_driver);
 }
 
 void brcmf_sdio_exit(void)
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -274,11 +274,26 @@
 
 #ifdef CONFIG_BRCMFMAC_SDIO
 void brcmf_sdio_exit(void);
-void brcmf_sdio_register(void);
+int brcmf_sdio_register(void);
+#else
+static inline void brcmf_sdio_exit(void) { }
+static inline int brcmf_sdio_register(void) { return 0; }
 #endif
+
 #ifdef CONFIG_BRCMFMAC_USB
 void brcmf_usb_exit(void);
-void brcmf_usb_register(void);
+int brcmf_usb_register(void);
+#else
+static inline void brcmf_usb_exit(void) { }
+static inline int brcmf_usb_register(void) { return 0; }
+#endif
+
+#ifdef CONFIG_BRCMFMAC_PCIE
+void brcmf_pcie_exit(void);
+int brcmf_pcie_register(void);
+#else
+static inline void brcmf_pcie_exit(void) { }
+static inline int brcmf_pcie_register(void) { return 0; }
 #endif
 
 #endif /* BRCMFMAC_BUS_H */
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -82,9 +82,14 @@
 
 #define BRCMF_ND_INFO_TIMEOUT		msecs_to_jiffies(2000)
 
+#define BRCMF_PS_MAX_TIMEOUT_MS		2000
+
 #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
 	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
 
+#define BRCMF_MAX_CHANSPEC_LIST \
+	(BRCMF_DCMD_MEDLEN / sizeof(__le32) - 1)
+
 static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
 {
 	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
@@ -705,8 +710,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 */
@@ -1264,13 +1268,14 @@
 {
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct brcmf_wsec_pmk_le pmk;
-	int i, err;
+	int err;
+
+	memset(&pmk, 0, sizeof(pmk));
 
-	/* convert to firmware key format */
-	pmk.key_len = cpu_to_le16(pmk_len << 1);
-	pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
-	for (i = 0; i < pmk_len; i++)
-		snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
+	/* pass pmk directly */
+	pmk.key_len = cpu_to_le16(pmk_len);
+	pmk.flags = cpu_to_le16(0);
+	memcpy(pmk.key, pmk_data, pmk_len);
 
 	/* store psk in firmware */
 	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
@@ -2610,8 +2615,9 @@
 	struct brcmf_sta_info_le sta_info_le;
 	u32 sta_flags;
 	u32 is_tdls_peer;
-	s32 total_rssi;
-	s32 count_rssi;
+	s32 total_rssi_avg = 0;
+	s32 total_rssi = 0;
+	s32 count_rssi = 0;
 	int rssi;
 	u32 i;
 
@@ -2677,25 +2683,27 @@
 			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES);
 			sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
 		}
-		total_rssi = 0;
-		count_rssi = 0;
 		for (i = 0; i < BRCMF_ANT_MAX; i++) {
-			if (sta_info_le.rssi[i]) {
-				sinfo->chain_signal_avg[count_rssi] =
-					sta_info_le.rssi[i];
-				sinfo->chain_signal[count_rssi] =
-					sta_info_le.rssi[i];
-				total_rssi += sta_info_le.rssi[i];
-				count_rssi++;
-			}
+			if (sta_info_le.rssi[i] == 0 ||
+			    sta_info_le.rx_lastpkt_rssi[i] == 0)
+				continue;
+			sinfo->chains |= BIT(count_rssi);
+			sinfo->chain_signal[count_rssi] =
+				sta_info_le.rx_lastpkt_rssi[i];
+			sinfo->chain_signal_avg[count_rssi] =
+				sta_info_le.rssi[i];
+			total_rssi += sta_info_le.rx_lastpkt_rssi[i];
+			total_rssi_avg += sta_info_le.rssi[i];
+			count_rssi++;
 		}
 		if (count_rssi) {
-			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
-			sinfo->chains = count_rssi;
-
 			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
-			total_rssi /= count_rssi;
-			sinfo->signal = total_rssi;
+			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
+			sinfo->filled |=
+				BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+			sinfo->signal = total_rssi / count_rssi;
+			sinfo->signal_avg = total_rssi_avg / count_rssi;
 		} else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
 			&ifp->vif->sme_state)) {
 			memset(&scb_val, 0, sizeof(scb_val));
@@ -2789,6 +2797,12 @@
 		else
 			bphy_err(drvr, "error (%d)\n", err);
 	}
+
+	err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret",
+				min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS));
+	if (err)
+		bphy_err(drvr, "Unable to set pm timeout, (%d)\n", err);
+
 done:
 	brcmf_dbg(TRACE, "Exit\n");
 	return err;
@@ -5374,7 +5388,8 @@
 	return false;
 }
 
-static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
+static bool brcmf_is_linkdown(struct brcmf_cfg80211_vif *vif,
+			    const struct brcmf_event_msg *e)
 {
 	u32 event = e->event_code;
 	u16 flags = e->flags;
@@ -5383,6 +5398,8 @@
 	    (event == BRCMF_E_DISASSOC_IND) ||
 	    ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
 		brcmf_dbg(CONN, "Processing link down\n");
+		clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
+		clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
 		return true;
 	}
 	return false;
@@ -5449,6 +5466,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) {
+		bphy_err(drvr, "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,
@@ -5675,7 +5697,7 @@
 		} else
 			brcmf_bss_connect_done(cfg, ndev, e, true);
 		brcmf_net_setcarrier(ifp, true);
-	} else if (brcmf_is_linkdown(e)) {
+	} else if (brcmf_is_linkdown(ifp->vif, e)) {
 		brcmf_dbg(CONN, "Linkdown\n");
 		if (!brcmf_is_ibssmode(ifp->vif)) {
 			brcmf_bss_connect_done(cfg, ndev, e, false);
@@ -6053,6 +6075,13 @@
 			band->channels[i].flags = IEEE80211_CHAN_DISABLED;
 
 	total = le32_to_cpu(list->count);
+	if (total > BRCMF_MAX_CHANSPEC_LIST) {
+		bphy_err(drvr, "Invalid count of channel Spec. (%u)\n",
+			 total);
+		err = -EINVAL;
+		goto fail_pbuf;
+	}
+
 	for (i = 0; i < total; i++) {
 		ch.chspec = (u16)le32_to_cpu(list->element[i]);
 		cfg->d11inf.decchspec(&ch);
@@ -6198,6 +6227,13 @@
 		band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ];
 		list = (struct brcmf_chanspec_list *)pbuf;
 		num_chan = le32_to_cpu(list->count);
+		if (num_chan > BRCMF_MAX_CHANSPEC_LIST) {
+			bphy_err(drvr, "Invalid count of channel Spec. (%u)\n",
+				 num_chan);
+			kfree(pbuf);
+			return -EINVAL;
+		}
+
 		for (i = 0; i < num_chan; i++) {
 			ch.chspec = (u16)le32_to_cpu(list->element[i]);
 			cfg->d11inf.decchspec(&ch);
@@ -7203,6 +7239,7 @@
 	brcmf_btcoex_detach(cfg);
 	wiphy_unregister(cfg->wiphy);
 	wl_deinit_priv(cfg);
+	cancel_work_sync(&cfg->escan_timeout_work);
 	brcmf_free_wiphy(cfg->wiphy);
 	kfree(cfg);
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -604,6 +604,7 @@
 			*srsize = (32 * 1024);
 		break;
 	case BRCM_CC_43430_CHIP_ID:
+	case CY_CC_43439_CHIP_ID:
 		/* assume sr for now as we can not check
 		 * firmware sr capability at this point.
 		 */
@@ -1196,7 +1197,8 @@
 	brcmf_chip_resetcore(core, 0, 0, 0);
 
 	/* disable bank #3 remap for this device */
-	if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) {
+	if (chip->pub.chip == BRCM_CC_43430_CHIP_ID ||
+	    chip->pub.chip == CY_CC_43439_CHIP_ID) {
 		sr = container_of(core, struct brcmf_core_priv, pub);
 		brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3);
 		brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0);
@@ -1353,6 +1355,7 @@
 		reg = chip->ops->read32(chip->ctx, addr);
 		return (reg & pmu_cc3_mask) != 0;
 	case BRCM_CC_43430_CHIP_ID:
+	case CY_CC_43439_CHIP_ID:
 		addr = CORE_CC_REG(base, sr_control1);
 		reg = chip->ops->read32(chip->ctx, addr);
 		return reg != 0;
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -264,6 +264,7 @@
 			 err);
 		goto done;
 	}
+	buf[sizeof(buf) - 1] = '\0';
 	ptr = (char *)buf;
 	strsep(&ptr, "\n");
 
@@ -280,15 +281,17 @@
 	if (err) {
 		brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
 	} else {
+		buf[sizeof(buf) - 1] = '\0';
 		clmver = (char *)buf;
-		/* store CLM version for adding it to revinfo debugfs file */
-		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
 
 		/* Replace all newline/linefeed characters with space
 		 * character
 		 */
 		strreplace(clmver, '\n', ' ');
 
+		/* store CLM version for adding it to revinfo debugfs file */
+		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
+
 		brcmf_dbg(INFO, "CLM version = %s\n", clmver);
 	}
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -290,6 +290,7 @@
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct ethhdr *eh;
 	int head_delta;
+	unsigned int tx_bytes = skb->len;
 
 	brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
 
@@ -332,6 +333,7 @@
 			bphy_err(drvr, "%s: failed to expand headroom\n",
 				 brcmf_ifname(ifp));
 			atomic_inc(&drvr->bus_if->stats.pktcow_failed);
+			dev_kfree_skb(skb);
 			goto done;
 		}
 	}
@@ -361,7 +363,7 @@
 		ndev->stats.tx_dropped++;
 	} else {
 		ndev->stats.tx_packets++;
-		ndev->stats.tx_bytes += skb->len;
+		ndev->stats.tx_bytes += tx_bytes;
 	}
 
 	/* Return ok: we always eat the packet */
@@ -483,7 +485,7 @@
 	ret = brcmf_proto_hdrpull(drvr, true, skb, ifp);
 
 	if (ret || !(*ifp) || !(*ifp)->ndev) {
-		if (ret != -ENODATA && *ifp)
+		if (ret != -ENODATA && *ifp && (*ifp)->ndev)
 			(*ifp)->ndev->stats.rx_errors++;
 		brcmu_pkt_buf_free_skb(skb);
 		return -ENODATA;
@@ -1350,6 +1352,11 @@
 	brcmf_fweh_detach(drvr);
 	brcmf_proto_detach(drvr);
 
+	if (drvr->mon_if) {
+		brcmf_net_detach(drvr->mon_if->ndev, false);
+		drvr->mon_if = NULL;
+	}
+
 	/* make sure primary interface removed last */
 	for (i = BRCMF_MAX_IFS - 1; i > -1; i--) {
 		if (drvr->iflist[i])
@@ -1433,40 +1440,34 @@
 	}
 }
 
-static void brcmf_driver_register(struct work_struct *work)
-{
-#ifdef CONFIG_BRCMFMAC_SDIO
-	brcmf_sdio_register();
-#endif
-#ifdef CONFIG_BRCMFMAC_USB
-	brcmf_usb_register();
-#endif
-#ifdef CONFIG_BRCMFMAC_PCIE
-	brcmf_pcie_register();
-#endif
-}
-static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
-
 int __init brcmf_core_init(void)
 {
-	if (!schedule_work(&brcmf_driver_work))
-		return -EBUSY;
+	int err;
+
+	err = brcmf_sdio_register();
+	if (err)
+		return err;
 
+	err = brcmf_usb_register();
+	if (err)
+		goto error_usb_register;
+
+	err = brcmf_pcie_register();
+	if (err)
+		goto error_pcie_register;
 	return 0;
+
+error_pcie_register:
+	brcmf_usb_exit();
+error_usb_register:
+	brcmf_sdio_exit();
+	return err;
 }
 
 void __exit brcmf_core_exit(void)
 {
-	cancel_work_sync(&brcmf_driver_work);
-
-#ifdef CONFIG_BRCMFMAC_SDIO
 	brcmf_sdio_exit();
-#endif
-#ifdef CONFIG_BRCMFMAC_USB
 	brcmf_usb_exit();
-#endif
-#ifdef CONFIG_BRCMFMAC_PCIE
 	brcmf_pcie_exit();
-#endif
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
@@ -40,6 +40,18 @@
 	BRCM_CC_43340_CHIP_ID, 2, "pov-tab-p1006w-data"
 };
 
+static const struct brcmf_dmi_data predia_basic_data = {
+	BRCM_CC_43341_CHIP_ID, 2, "predia-basic"
+};
+
+/* Note the Voyo winpad A15 tablet uses the same Ampak AP6330 module, with the
+ * exact same nvram file as the Prowise-PT301 tablet. Since the nvram for the
+ * Prowise-PT301 is already in linux-firmware we just point to that here.
+ */
+static const struct brcmf_dmi_data voyo_winpad_a15_data = {
+	BRCM_CC_4330_CHIP_ID, 4, "Prowise-PT301"
+};
+
 static const struct dmi_system_id dmi_platform_data[] = {
 	{
 		/* ACEPC T8 Cherry Trail Z8350 mini PC */
@@ -64,6 +76,16 @@
 		.driver_data = (void *)&acepc_t8_data,
 	},
 	{
+		/* Cyberbook T116 rugged tablet */
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "20170531"),
+		},
+		/* The factory image nvram file is identical to the ACEPC T8 one */
+		.driver_data = (void *)&acepc_t8_data,
+	},
+	{
 		/* Match for the GPDwin which unfortunately uses somewhat
 		 * generic dmi strings, which is why we test for 4 strings.
 		 * Comparing against 23 other byt/cht boards, board_vendor
@@ -111,6 +133,26 @@
 		},
 		.driver_data = (void *)&pov_tab_p1006w_data,
 	},
+	{
+		/* Predia Basic tablet (+ with keyboard dock) */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
+			/* Mx.WT107.KUBNGEA02 with the version-nr dropped */
+			DMI_MATCH(DMI_BIOS_VERSION, "Mx.WT107.KUBNGEA"),
+		},
+		.driver_data = (void *)&predia_basic_data,
+	},
+	{
+		/* Voyo winpad A15 tablet */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+			/* Above strings are too generic, also match on BIOS date */
+			DMI_MATCH(DMI_BIOS_DATE, "11/20/2014"),
+		},
+		.driver_data = (void *)&voyo_winpad_a15_data,
+	},
 	{}
 };
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -245,7 +245,8 @@
 	brcmf_feat_firmware_capabilities(ifp);
 	memset(&gscan_cfg, 0, sizeof(gscan_cfg));
 	if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID &&
-	    drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID)
+	    drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID &&
+	    drvr->bus_if->chip != CY_CC_43439_CHIP_ID)
 		brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
 					  "pfn_gscan_cfg",
 					  &gscan_cfg, sizeof(gscan_cfg));
@@ -283,13 +284,14 @@
 	if (!err)
 		ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
 
+	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
+
 	if (drvr->settings->feature_disable) {
 		brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
 			  ifp->drvr->feat_flags,
 			  drvr->settings->feature_disable);
 		ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
 	}
-	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
 
 	brcmf_feat_firmware_overrides(drvr);
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -207,6 +207,8 @@
 		size = BRCMF_FW_MAX_NVRAM_SIZE;
 	else
 		size = data_len;
+	/* Add space for properties we may add */
+	size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1;
 	/* Alloc for extra 0 byte + roundup by 4 + length field */
 	size += 1 + 3 + sizeof(u32);
 	nvp->nvram = kzalloc(size, GFP_KERNEL);
@@ -701,6 +703,11 @@
 	u32 i, j;
 	char end = '\0';
 
+	if (chiprev >= BITS_PER_TYPE(u32)) {
+		brcmf_err("Invalid chip revision %u\n", chiprev);
+		return NULL;
+	}
+
 	for (i = 0; i < table_size; i++) {
 		if (mapping_table[i].chipid == chip &&
 		    mapping_table[i].revmask & BIT(chiprev))
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -11,6 +11,8 @@
 
 #define BRCMF_FW_DEFAULT_PATH		"brcm/"
 
+#define CY_FW_DEFAULT_PATH		"cypress/"
+
 /**
  * struct brcmf_firmware_mapping - Used to map chipid/revmask to firmware
  *	filename and nvram filename. Each bus type implementation should create
@@ -32,6 +34,11 @@
 	BRCMF_FW_DEFAULT_PATH fw_base; \
 MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin")
 
+#define CY_FW_DEF(fw_name, fw_base) \
+static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \
+	CY_FW_DEFAULT_PATH fw_base; \
+MODULE_FIRMWARE(CY_FW_DEFAULT_PATH fw_base ".bin")
+
 #define BRCMF_FW_ENTRY(chipid, mask, name) \
 	{ chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -228,6 +228,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) {
+			bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx);
+			goto event_free;
+		}
 
 		/* convert event message */
 		emsg_be = &event->emsg;
@@ -304,10 +308,12 @@
 {
 	struct brcmf_fweh_info *fweh = &drvr->fweh;
 
-	/* cancel the worker */
-	cancel_work_sync(&fweh->event_work);
-	WARN_ON(!list_empty(&fweh->event_q));
-	memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
+	/* cancel the worker if initialized */
+	if (fweh->event_work.func) {
+		cancel_work_sync(&fweh->event_work);
+		WARN_ON(!list_empty(&fweh->event_q));
+		memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
+	}
 }
 
 /**
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -19,7 +19,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_BRCM			0x00000001	/* Running a Broadcom driver */
 #define BRCMF_STA_WME			0x00000002	/* WMM association */
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -643,6 +643,7 @@
 static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
 				int ifidx)
 {
+	struct brcmf_fws_hanger_item *hi;
 	bool (*matchfn)(struct sk_buff *, void *) = NULL;
 	struct sk_buff *skb;
 	int prec;
@@ -654,6 +655,9 @@
 		skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
 		while (skb) {
 			hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+			hi = &fws->hanger.items[hslot];
+			WARN_ON(skb != hi->pkt);
+			hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
 			brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
 						true);
 			brcmu_pkt_buf_free_skb(skb);
@@ -2145,8 +2149,7 @@
 		brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
 		brcmf_fws_schedule_deq(fws);
 	} else {
-		bphy_err(drvr, "drop skb: no hanger slot\n");
-		brcmf_txfinalize(ifp, skb, false);
+		bphy_err(drvr, "no hanger slot available\n");
 		rc = -ENOMEM;
 	}
 	brcmf_fws_unlock(fws);
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -345,8 +345,11 @@
 		count++;
 	} while (count < pktids->array_size);
 
-	if (count == pktids->array_size)
+	if (count == pktids->array_size) {
+		dma_unmap_single(dev, *physaddr, skb->len - data_offset,
+				 pktids->direction);
 		return -ENOMEM;
+	}
 
 	array[*idx].data_offset = data_offset;
 	array[*idx].physaddr = *physaddr;
@@ -1619,6 +1622,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-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -2092,7 +2092,8 @@
 	/* firmware requires unique mac address for p2pdev interface */
 	if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) {
 		bphy_err(drvr, "discovery vif must be different from primary interface\n");
-		return ERR_PTR(-EINVAL);
+		err = -EINVAL;
+		goto fail;
 	}
 
 	brcmf_p2p_generate_bss_mac(p2p, addr);
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/bcma/bcma.h>
 #include <linux/sched.h>
+#include <linux/io.h>
 #include <asm/unaligned.h>
 
 #include <soc.h>
@@ -445,47 +446,6 @@
 
 
 static void
-brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
-			  void *srcaddr, u32 len)
-{
-	void __iomem *address = devinfo->tcm + mem_offset;
-	__le32 *src32;
-	__le16 *src16;
-	u8 *src8;
-
-	if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) {
-		if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) {
-			src8 = (u8 *)srcaddr;
-			while (len) {
-				iowrite8(*src8, address);
-				address++;
-				src8++;
-				len--;
-			}
-		} else {
-			len = len / 2;
-			src16 = (__le16 *)srcaddr;
-			while (len) {
-				iowrite16(le16_to_cpu(*src16), address);
-				address += 2;
-				src16++;
-				len--;
-			}
-		}
-	} else {
-		len = len / 4;
-		src32 = (__le32 *)srcaddr;
-		while (len) {
-			iowrite32(le32_to_cpu(*src32), address);
-			address += 4;
-			src32++;
-			len--;
-		}
-	}
-}
-
-
-static void
 brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
 			  void *dstaddr, u32 len)
 {
@@ -656,7 +616,7 @@
 	}
 
 	if (!brcmf_chip_set_active(devinfo->ci, resetintr))
-		return -EINVAL;
+		return -EIO;
 	return 0;
 }
 
@@ -1149,6 +1109,10 @@
 				BRCMF_NROF_H2D_COMMON_MSGRINGS;
 		max_completionrings = BRCMF_NROF_D2H_COMMON_MSGRINGS;
 	}
+	if (max_flowrings > 512) {
+		brcmf_err(bus, "invalid max_flowrings(%d)\n", max_flowrings);
+		return -EIO;
+	}
 
 	if (devinfo->dma_idx_sz != 0) {
 		bufsz = (max_submissionrings + max_completionrings) *
@@ -1346,6 +1310,18 @@
 {
 }
 
+static int brcmf_pcie_preinit(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+
+	brcmf_dbg(PCIE, "Enter\n");
+
+	brcmf_pcie_intr_enable(buspub->devinfo);
+	brcmf_pcie_hostready(buspub->devinfo);
+
+	return 0;
+}
 
 static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb)
 {
@@ -1427,6 +1403,8 @@
 	struct brcmf_fw_request *fwreq;
 	int err;
 
+	brcmf_pcie_intr_disable(devinfo);
+
 	brcmf_pcie_bus_console_read(devinfo, true);
 
 	brcmf_detach(dev);
@@ -1452,6 +1430,7 @@
 }
 
 static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
+	.preinit = brcmf_pcie_preinit,
 	.txdata = brcmf_pcie_tx,
 	.stop = brcmf_pcie_down,
 	.txctl = brcmf_pcie_tx_ctlpkt,
@@ -1559,8 +1538,8 @@
 		return err;
 
 	brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name);
-	brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase,
-				  (void *)fw->data, fw->size);
+	memcpy_toio(devinfo->tcm + devinfo->ci->rambase,
+		    (void *)fw->data, fw->size);
 
 	resetintr = get_unaligned_le32(fw->data);
 	release_firmware(fw);
@@ -1574,7 +1553,7 @@
 		brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
 		address = devinfo->ci->rambase + devinfo->ci->ramsize -
 			  nvram_len;
-		brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len);
+		memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
 		brcmf_fw_nvram_free(nvram);
 	} else {
 		brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
@@ -1773,6 +1752,8 @@
 	ret = brcmf_chip_get_raminfo(devinfo->ci);
 	if (ret) {
 		brcmf_err(bus, "Failed to get RAM info\n");
+		release_firmware(fw);
+		brcmf_fw_nvram_free(nvram);
 		goto fail;
 	}
 
@@ -1822,9 +1803,6 @@
 
 	init_waitqueue_head(&devinfo->mbdata_resp_wait);
 
-	brcmf_pcie_intr_enable(devinfo);
-	brcmf_pcie_hostready(devinfo);
-
 	ret = brcmf_attach(&devinfo->pdev->dev);
 	if (ret)
 		goto fail;
@@ -1934,16 +1912,18 @@
 	fwreq = brcmf_pcie_prepare_fw_request(devinfo);
 	if (!fwreq) {
 		ret = -ENOMEM;
-		goto fail_bus;
+		goto fail_brcmf;
 	}
 
 	ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup);
 	if (ret < 0) {
 		kfree(fwreq);
-		goto fail_bus;
+		goto fail_brcmf;
 	}
 	return 0;
 
+fail_brcmf:
+	brcmf_free(&devinfo->pdev->dev);
 fail_bus:
 	kfree(bus->msgbuf);
 	kfree(bus);
@@ -2069,7 +2049,7 @@
 
 	err = brcmf_pcie_probe(pdev, NULL);
 	if (err)
-		brcmf_err(bus, "probe after resume failed, err=%d\n", err);
+		__brcmf_err(NULL, __func__, "probe after resume failed, err=%d\n", err);
 
 	return err;
 }
@@ -2133,15 +2113,10 @@
 };
 
 
-void brcmf_pcie_register(void)
+int brcmf_pcie_register(void)
 {
-	int err;
-
 	brcmf_dbg(PCIE, "Enter\n");
-	err = pci_register_driver(&brcmf_pciedrvr);
-	if (err)
-		brcmf_err(NULL, "PCIE driver registration failed, err=%d\n",
-			  err);
+	return pci_register_driver(&brcmf_pciedrvr);
 }
 
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h
@@ -11,9 +11,4 @@
 	struct brcmf_pciedev_info *devinfo;
 };
 
-
-void brcmf_pcie_exit(void);
-void brcmf_pcie_register(void);
-
-
 #endif /* BRCMFMAC_PCIE_H */
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -154,12 +154,12 @@
 	struct brcmf_pno_macaddr_le pfn_mac;
 	u8 *mac_addr = NULL;
 	u8 *mac_mask = NULL;
-	int err, i;
+	int err, i, ri;
 
-	for (i = 0; i < pi->n_reqs; i++)
-		if (pi->reqs[i]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
-			mac_addr = pi->reqs[i]->mac_addr;
-			mac_mask = pi->reqs[i]->mac_addr_mask;
+	for (ri = 0; ri < pi->n_reqs; ri++)
+		if (pi->reqs[ri]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+			mac_addr = pi->reqs[ri]->mac_addr;
+			mac_mask = pi->reqs[ri]->mac_addr_mask;
 			break;
 		}
 
@@ -181,7 +181,7 @@
 	pfn_mac.mac[0] |= 0x02;
 
 	brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n",
-		  pi->reqs[i]->reqid, pfn_mac.mac);
+		  pi->reqs[ri]->reqid, pfn_mac.mac);
 	err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
 				       sizeof(pfn_mac));
 	if (err)
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -550,7 +550,7 @@
 	BRCMF_SDIO_FT_SUB,
 };
 
-#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
+#define SDIOD_DRVSTR_KEY(chip, pmu)     (((unsigned int)(chip) << 16) | (pmu))
 
 /* SDIO Pad drive strength to select value mappings */
 struct sdiod_drive_str {
@@ -610,6 +610,7 @@
 BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
 /* Note the names are not postfixed with a1 for backward compatibility */
 BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
+CY_FW_DEF(43439, "cyfmac43439-sdio");
 BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
 BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
 BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
@@ -636,6 +637,7 @@
 	BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
 	BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
 	BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+	BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439),
 	BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
 	BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
 };
@@ -1934,7 +1936,10 @@
 			if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
 					       BRCMF_SDIO_FT_NORMAL)) {
 				rd->len = 0;
+				brcmf_sdio_rxfail(bus, true, true);
+				sdio_release_host(bus->sdiodev->func1);
 				brcmu_pkt_buf_free_skb(pkt);
+				continue;
 			}
 			bus->sdcnt.rx_readahead_cnt++;
 			if (rd->len != roundup(rd_new.len, 16)) {
@@ -3364,6 +3369,7 @@
 	/* Take arm out of reset */
 	if (!brcmf_chip_set_active(bus->ci, rstvec)) {
 		brcmf_err("error getting out of ARM core reset\n");
+		bcmerror = -EIO;
 		goto err;
 	}
 
@@ -3682,7 +3688,11 @@
 			if (bus->idlecount > bus->idletime) {
 				brcmf_dbg(SDIO, "idle\n");
 				sdio_claim_host(bus->sdiodev->func1);
-				brcmf_sdio_wd_timer(bus, false);
+#ifdef DEBUG
+				if (!BRCMF_FWCON_ON() ||
+				    bus->console_interval == 0)
+#endif
+					brcmf_sdio_wd_timer(bus, false);
 				bus->idlecount = 0;
 				brcmf_sdio_bus_sleep(bus, true, false);
 				sdio_release_host(bus->sdiodev->func1);
@@ -4225,6 +4235,12 @@
 	}
 
 	if (err == 0) {
+		/* Assign bus interface call back */
+		sdiod->bus_if->dev = sdiod->dev;
+		sdiod->bus_if->ops = &brcmf_sdio_bus_ops;
+		sdiod->bus_if->chip = bus->ci->chip;
+		sdiod->bus_if->chiprev = bus->ci->chiprev;
+
 		/* Allow full data communication using DPC from now on. */
 		brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
 
@@ -4241,12 +4257,6 @@
 
 	sdio_release_host(sdiod->func1);
 
-	/* Assign bus interface call back */
-	sdiod->bus_if->dev = sdiod->dev;
-	sdiod->bus_if->ops = &brcmf_sdio_bus_ops;
-	sdiod->bus_if->chip = bus->ci->chip;
-	sdiod->bus_if->chiprev = bus->ci->chiprev;
-
 	err = brcmf_alloc(sdiod->dev, sdiod->settings);
 	if (err) {
 		brcmf_err("brcmf_alloc failed\n");
@@ -4426,6 +4436,7 @@
 		brcmf_sdiod_intr_unregister(bus->sdiodev);
 
 		brcmf_detach(bus->sdiodev->dev);
+		brcmf_free(bus->sdiodev->dev);
 
 		cancel_work_sync(&bus->datawork);
 		if (bus->brcmf_wq)
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -430,6 +430,7 @@
 			usb_free_urb(req->urb);
 		list_del(q->next);
 	}
+	kfree(reqs);
 	return NULL;
 
 }
@@ -1348,7 +1349,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)) {
@@ -1361,7 +1362,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;
@@ -1557,12 +1558,8 @@
 	usb_deregister(&brcmf_usbdrvr);
 }
 
-void brcmf_usb_register(void)
+int brcmf_usb_register(void)
 {
-	int ret;
-
 	brcmf_dbg(USB, "Enter\n");
-	ret = usb_register(&brcmf_usbdrvr);
-	if (ret)
-		brcmf_err("usb_register failed %d\n", ret);
+	return usb_register(&brcmf_usbdrvr);
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -850,8 +850,7 @@
 				     "START: tid %d is not agg\'able\n", tid);
 			return -EINVAL;
 		}
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-		break;
+		return IEEE80211_AMPDU_TX_START_IMMEDIATE;
 
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
@@ -1223,6 +1222,7 @@
 {
 	struct brcms_info *wl;
 	struct ieee80211_hw *hw;
+	int ret;
 
 	dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
 		 pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
@@ -1247,11 +1247,16 @@
 	wl = brcms_attach(pdev);
 	if (!wl) {
 		pr_err("%s: brcms_attach failed!\n", __func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_free_ieee80211;
 	}
 	brcms_led_register(wl);
 
 	return 0;
+
+err_free_ieee80211:
+	ieee80211_free_hw(hw);
+	return ret;
 }
 
 static int brcms_suspend(struct bcma_device *pdev)
--- linux-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -5065,8 +5065,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-ein-5.4.0.orig/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
+++ linux-ein-5.4.0/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
@@ -48,6 +48,7 @@
 #define BRCM_CC_4366_CHIP_ID		0x4366
 #define BRCM_CC_43664_CHIP_ID		43664
 #define BRCM_CC_4371_CHIP_ID		0x4371
+#define CY_CC_43439_CHIP_ID		43439
 #define CY_CC_4373_CHIP_ID		0x4373
 #define CY_CC_43012_CHIP_ID		43012
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/cisco/airo.c
+++ linux-ein-5.4.0/drivers/net/wireless/cisco/airo.c
@@ -1925,6 +1925,10 @@
 		airo_print_err(dev->name, "%s: skb == NULL!",__func__);
 		return NETDEV_TX_OK;
 	}
+	if (skb_padto(skb, ETH_ZLEN)) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	npacks = skb_queue_len (&ai->txq);
 
 	if (npacks >= MAXTXQ - 1) {
@@ -2127,6 +2131,10 @@
 		airo_print_err(dev->name, "%s: skb == NULL!", __func__);
 		return NETDEV_TX_OK;
 	}
+	if (skb_padto(skb, ETH_ZLEN)) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 
 	/* Find a vacant FID */
 	for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
@@ -2201,6 +2209,10 @@
 		airo_print_err(dev->name, "%s: skb == NULL!", __func__);
 		return NETDEV_TX_OK;
 	}
+	if (skb_padto(skb, ETH_ZLEN)) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 
 	/* Find a vacant FID */
 	for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
@@ -6092,8 +6104,11 @@
 {
 	struct airo_info *local = dev->ml_priv;
 	StatusRid status_rid;		/* Card status info */
+	int ret;
 
-	readStatusRid(local, &status_rid, 1);
+	ret = readStatusRid(local, &status_rid, 1);
+	if (ret)
+		return -EBUSY;
 
 	vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000;
 	/* If more than one rate, set auto */
@@ -7790,16 +7805,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;
@@ -7813,7 +7820,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-ein-5.4.0.orig/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -2294,10 +2294,11 @@
 		return -ENOMEM;
 
 	packet->rxp = (struct ipw2100_rx *)packet->skb->data;
-	packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
+	packet->dma_addr = dma_map_single(&priv->pci_dev->dev,
+					  packet->skb->data,
 					  sizeof(struct ipw2100_rx),
-					  PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(priv->pci_dev, packet->dma_addr)) {
+					  DMA_FROM_DEVICE);
+	if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) {
 		dev_kfree_skb(packet->skb);
 		return -ENOMEM;
 	}
@@ -2478,9 +2479,8 @@
 		return;
 	}
 
-	pci_unmap_single(priv->pci_dev,
-			 packet->dma_addr,
-			 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
+	dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
+			 sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
 
 	skb_put(packet->skb, status->frame_size);
 
@@ -2562,8 +2562,8 @@
 		return;
 	}
 
-	pci_unmap_single(priv->pci_dev, packet->dma_addr,
-			 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
+	dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
+			 sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
 	memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
 		packet->skb->data, status->frame_size);
 
@@ -2688,9 +2688,9 @@
 
 		/* Sync the DMA for the RX buffer so CPU is sure to get
 		 * the correct values */
-		pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
-					    sizeof(struct ipw2100_rx),
-					    PCI_DMA_FROMDEVICE);
+		dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr,
+					sizeof(struct ipw2100_rx),
+					DMA_FROM_DEVICE);
 
 		if (unlikely(ipw2100_corruption_check(priv, i))) {
 			ipw2100_corruption_detected(priv, i);
@@ -2922,9 +2922,8 @@
 				     (packet->index + 1 + i) % txq->entries,
 				     tbd->host_addr, tbd->buf_length);
 
-			pci_unmap_single(priv->pci_dev,
-					 tbd->host_addr,
-					 tbd->buf_length, PCI_DMA_TODEVICE);
+			dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr,
+					 tbd->buf_length, DMA_TO_DEVICE);
 		}
 
 		libipw_txb_free(packet->info.d_struct.txb);
@@ -3164,15 +3163,13 @@
 			tbd->buf_length = packet->info.d_struct.txb->
 			    fragments[i]->len - LIBIPW_3ADDR_LEN;
 
-			tbd->host_addr = pci_map_single(priv->pci_dev,
+			tbd->host_addr = dma_map_single(&priv->pci_dev->dev,
 							packet->info.d_struct.
-							txb->fragments[i]->
-							data +
+							txb->fragments[i]->data +
 							LIBIPW_3ADDR_LEN,
 							tbd->buf_length,
-							PCI_DMA_TODEVICE);
-			if (pci_dma_mapping_error(priv->pci_dev,
-						  tbd->host_addr)) {
+							DMA_TO_DEVICE);
+			if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) {
 				IPW_DEBUG_TX("dma mapping error\n");
 				break;
 			}
@@ -3181,10 +3178,10 @@
 				     txq->next, tbd->host_addr,
 				     tbd->buf_length);
 
-			pci_dma_sync_single_for_device(priv->pci_dev,
-						       tbd->host_addr,
-						       tbd->buf_length,
-						       PCI_DMA_TODEVICE);
+			dma_sync_single_for_device(&priv->pci_dev->dev,
+						   tbd->host_addr,
+						   tbd->buf_length,
+						   DMA_TO_DEVICE);
 
 			txq->next++;
 			txq->next %= txq->entries;
@@ -3206,8 +3203,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;
@@ -3438,9 +3436,9 @@
 		return -ENOMEM;
 
 	for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
-		v = pci_zalloc_consistent(priv->pci_dev,
-					  sizeof(struct ipw2100_cmd_header),
-					  &p);
+		v = dma_alloc_coherent(&priv->pci_dev->dev,
+				       sizeof(struct ipw2100_cmd_header), &p,
+				       GFP_KERNEL);
 		if (!v) {
 			printk(KERN_ERR DRV_NAME ": "
 			       "%s: PCI alloc failed for msg "
@@ -3459,11 +3457,10 @@
 		return 0;
 
 	for (j = 0; j < i; j++) {
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct ipw2100_cmd_header),
-				    priv->msg_buffers[j].info.c_struct.cmd,
-				    priv->msg_buffers[j].info.c_struct.
-				    cmd_phys);
+		dma_free_coherent(&priv->pci_dev->dev,
+				  sizeof(struct ipw2100_cmd_header),
+				  priv->msg_buffers[j].info.c_struct.cmd,
+				  priv->msg_buffers[j].info.c_struct.cmd_phys);
 	}
 
 	kfree(priv->msg_buffers);
@@ -3494,11 +3491,10 @@
 		return;
 
 	for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct ipw2100_cmd_header),
-				    priv->msg_buffers[i].info.c_struct.cmd,
-				    priv->msg_buffers[i].info.c_struct.
-				    cmd_phys);
+		dma_free_coherent(&priv->pci_dev->dev,
+				  sizeof(struct ipw2100_cmd_header),
+				  priv->msg_buffers[i].info.c_struct.cmd,
+				  priv->msg_buffers[i].info.c_struct.cmd_phys);
 	}
 
 	kfree(priv->msg_buffers);
@@ -4321,7 +4317,8 @@
 	IPW_DEBUG_INFO("enter\n");
 
 	q->size = entries * sizeof(struct ipw2100_status);
-	q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic);
+	q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
+				    GFP_KERNEL);
 	if (!q->drv) {
 		IPW_DEBUG_WARNING("Can not allocate status queue.\n");
 		return -ENOMEM;
@@ -4337,9 +4334,10 @@
 	IPW_DEBUG_INFO("enter\n");
 
 	if (priv->status_queue.drv) {
-		pci_free_consistent(priv->pci_dev, priv->status_queue.size,
-				    priv->status_queue.drv,
-				    priv->status_queue.nic);
+		dma_free_coherent(&priv->pci_dev->dev,
+				  priv->status_queue.size,
+				  priv->status_queue.drv,
+				  priv->status_queue.nic);
 		priv->status_queue.drv = NULL;
 	}
 
@@ -4355,7 +4353,8 @@
 
 	q->entries = entries;
 	q->size = entries * sizeof(struct ipw2100_bd);
-	q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic);
+	q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
+				    GFP_KERNEL);
 	if (!q->drv) {
 		IPW_DEBUG_INFO
 		    ("can't allocate shared memory for buffer descriptors\n");
@@ -4375,7 +4374,8 @@
 		return;
 
 	if (q->drv) {
-		pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
+		dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv,
+				  q->nic);
 		q->drv = NULL;
 	}
 
@@ -4435,9 +4435,9 @@
 	}
 
 	for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
-		v = pci_alloc_consistent(priv->pci_dev,
-					 sizeof(struct ipw2100_data_header),
-					 &p);
+		v = dma_alloc_coherent(&priv->pci_dev->dev,
+				       sizeof(struct ipw2100_data_header), &p,
+				       GFP_KERNEL);
 		if (!v) {
 			printk(KERN_ERR DRV_NAME
 			       ": %s: PCI alloc failed for tx " "buffers.\n",
@@ -4457,11 +4457,10 @@
 		return 0;
 
 	for (j = 0; j < i; j++) {
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct ipw2100_data_header),
-				    priv->tx_buffers[j].info.d_struct.data,
-				    priv->tx_buffers[j].info.d_struct.
-				    data_phys);
+		dma_free_coherent(&priv->pci_dev->dev,
+				  sizeof(struct ipw2100_data_header),
+				  priv->tx_buffers[j].info.d_struct.data,
+				  priv->tx_buffers[j].info.d_struct.data_phys);
 	}
 
 	kfree(priv->tx_buffers);
@@ -4538,12 +4537,10 @@
 			priv->tx_buffers[i].info.d_struct.txb = NULL;
 		}
 		if (priv->tx_buffers[i].info.d_struct.data)
-			pci_free_consistent(priv->pci_dev,
-					    sizeof(struct ipw2100_data_header),
-					    priv->tx_buffers[i].info.d_struct.
-					    data,
-					    priv->tx_buffers[i].info.d_struct.
-					    data_phys);
+			dma_free_coherent(&priv->pci_dev->dev,
+					  sizeof(struct ipw2100_data_header),
+					  priv->tx_buffers[i].info.d_struct.data,
+					  priv->tx_buffers[i].info.d_struct.data_phys);
 	}
 
 	kfree(priv->tx_buffers);
@@ -4606,9 +4603,10 @@
 		return 0;
 
 	for (j = 0; j < i; j++) {
-		pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
+		dma_unmap_single(&priv->pci_dev->dev,
+				 priv->rx_buffers[j].dma_addr,
 				 sizeof(struct ipw2100_rx_packet),
-				 PCI_DMA_FROMDEVICE);
+				 DMA_FROM_DEVICE);
 		dev_kfree_skb(priv->rx_buffers[j].skb);
 	}
 
@@ -4660,10 +4658,10 @@
 
 	for (i = 0; i < RX_QUEUE_LENGTH; i++) {
 		if (priv->rx_buffers[i].rxp) {
-			pci_unmap_single(priv->pci_dev,
+			dma_unmap_single(&priv->pci_dev->dev,
 					 priv->rx_buffers[i].dma_addr,
 					 sizeof(struct ipw2100_rx),
-					 PCI_DMA_FROMDEVICE);
+					 DMA_FROM_DEVICE);
 			dev_kfree_skb(priv->rx_buffers[i].skb);
 		}
 	}
@@ -6007,7 +6005,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,
@@ -6137,7 +6135,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 */
@@ -6195,7 +6193,7 @@
 	pci_set_master(pci_dev);
 	pci_set_drvdata(pci_dev, priv);
 
-	err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+	err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_set_dma_mask.\n");
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -1945,8 +1945,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;
@@ -3441,9 +3442,10 @@
 		/* In the reset function, these buffers may have been allocated
 		 * to an SKB, so we need to unmap and free potential storage */
 		if (rxq->pool[i].skb != NULL) {
-			pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
-					 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(rxq->pool[i].skb);
+			dma_unmap_single(&priv->pci_dev->dev,
+					 rxq->pool[i].dma_addr,
+					 IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
+			dev_kfree_skb_irq(rxq->pool[i].skb);
 			rxq->pool[i].skb = NULL;
 		}
 		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
@@ -3775,7 +3777,8 @@
 	}
 
 	q->bd =
-	    pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr);
+	    dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count,
+			       &q->q.dma_addr, GFP_KERNEL);
 	if (!q->bd) {
 		IPW_ERROR("pci_alloc_consistent(%zd) failed\n",
 			  sizeof(q->bd[0]) * count);
@@ -3817,9 +3820,10 @@
 
 	/* unmap chunks if any */
 	for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
-		pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]),
+		dma_unmap_single(&dev->dev,
+				 le32_to_cpu(bd->u.data.chunk_ptr[i]),
 				 le16_to_cpu(bd->u.data.chunk_len[i]),
-				 PCI_DMA_TODEVICE);
+				 DMA_TO_DEVICE);
 		if (txq->txb[txq->q.last_used]) {
 			libipw_txb_free(txq->txb[txq->q.last_used]);
 			txq->txb[txq->q.last_used] = NULL;
@@ -3851,8 +3855,8 @@
 	}
 
 	/* free buffers belonging to queue itself */
-	pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
-			    q->dma_addr);
+	dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
+			  q->dma_addr);
 	kfree(txq->txb);
 
 	/* 0 fill whole structure */
@@ -5197,8 +5201,8 @@
 		list_del(element);
 
 		rxb->dma_addr =
-		    pci_map_single(priv->pci_dev, rxb->skb->data,
-				   IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		    dma_map_single(&priv->pci_dev->dev, rxb->skb->data,
+				   IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
 
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
@@ -5231,8 +5235,9 @@
 
 	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
 		if (rxq->pool[i].skb != NULL) {
-			pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
-					 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dma_unmap_single(&priv->pci_dev->dev,
+					 rxq->pool[i].dma_addr,
+					 IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb(rxq->pool[i].skb);
 		}
 	}
@@ -8270,9 +8275,8 @@
 		}
 		priv->rxq->queue[i] = NULL;
 
-		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-					    IPW_RX_BUF_SIZE,
-					    PCI_DMA_FROMDEVICE);
+		dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr,
+					IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
 
 		pkt = (struct ipw_rx_packet *)rxb->skb->data;
 		IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
@@ -8424,8 +8428,8 @@
 			rxb->skb = NULL;
 		}
 
-		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-				 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr,
+				 IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
 		list_add_tail(&rxb->list, &priv->rxq->rx_used);
 
 		i = (i + 1) % RX_QUEUE_SIZE;
@@ -10224,11 +10228,10 @@
 			   txb->fragments[i]->len - hdr_len);
 
 		tfd->u.data.chunk_ptr[i] =
-		    cpu_to_le32(pci_map_single
-				(priv->pci_dev,
-				 txb->fragments[i]->data + hdr_len,
-				 txb->fragments[i]->len - hdr_len,
-				 PCI_DMA_TODEVICE));
+		    cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
+					       txb->fragments[i]->data + hdr_len,
+					       txb->fragments[i]->len - hdr_len,
+					       DMA_TO_DEVICE));
 		tfd->u.data.chunk_len[i] =
 		    cpu_to_le16(txb->fragments[i]->len - hdr_len);
 	}
@@ -10258,10 +10261,10 @@
 			dev_kfree_skb_any(txb->fragments[i]);
 			txb->fragments[i] = skb;
 			tfd->u.data.chunk_ptr[i] =
-			    cpu_to_le32(pci_map_single
-					(priv->pci_dev, skb->data,
-					 remaining_bytes,
-					 PCI_DMA_TODEVICE));
+			    cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
+						       skb->data,
+						       remaining_bytes,
+						       DMA_TO_DEVICE));
 
 			le32_add_cpu(&tfd->u.data.num_chunks, 1);
 		}
@@ -10680,7 +10683,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;
@@ -11411,9 +11414,14 @@
 	set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
 
 	/* With that information in place, we can now register the wiphy... */
-	if (wiphy_register(wdev->wiphy))
-		rc = -EIO;
+	rc = wiphy_register(wdev->wiphy);
+	if (rc)
+		goto out;
+
+	return 0;
 out:
+	kfree(priv->ieee->a_band.channels);
+	kfree(priv->ieee->bg_band.channels);
 	return rc;
 }
 
@@ -11631,9 +11639,9 @@
 
 	pci_set_master(pdev);
 
-	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
 	if (!err)
-		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 	if (err) {
 		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
 		goto out_pci_disable_device;
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
@@ -383,7 +383,7 @@
 
 		/* Each fragment may need to have room for encryption
 		 * pre/postfix */
-		if (host_encrypt)
+		if (host_encrypt && crypt && crypt->ops)
 			bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
 			    crypt->ops->extra_mpdu_postfix_len;
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
@@ -633,8 +633,10 @@
 	}
 
 	if (ext->alg != IW_ENCODE_ALG_NONE) {
-		memcpy(sec.keys[idx], ext->key, ext->key_len);
-		sec.key_sizes[idx] = ext->key_len;
+		int key_len = clamp_val(ext->key_len, 0, SCM_KEY_LEN);
+
+		memcpy(sec.keys[idx], ext->key, key_len);
+		sec.key_sizes[idx] = key_len;
 		sec.flags |= (1 << idx);
 		if (ext->alg == IW_ENCODE_ALG_WEP) {
 			sec.encode_alg[idx] = SEC_ALG_WEP;
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -1376,8 +1376,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;
@@ -2301,9 +2302,7 @@
 	il3945_hw_txq_ctx_free(il);
 exit:
 	memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
-
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
+	dev_kfree_skb(il->beacon_skb);
 	il->beacon_skb = NULL;
 
 	/* clear out any free frames */
@@ -3383,10 +3382,12 @@
  *
  *****************************************************************************/
 
-static void
+static int
 il3945_setup_deferred_work(struct il_priv *il)
 {
 	il->workqueue = create_singlethread_workqueue(DRV_NAME);
+	if (!il->workqueue)
+		return -ENOMEM;
 
 	init_waitqueue_head(&il->wait_command_queue);
 
@@ -3403,8 +3404,10 @@
 	timer_setup(&il->watchdog, il_bg_watchdog, 0);
 
 	tasklet_init(&il->irq_tasklet,
-		     (void (*)(unsigned long))il3945_irq_tasklet,
+		     il3945_irq_tasklet,
 		     (unsigned long)il);
+
+	return 0;
 }
 
 static void
@@ -3726,7 +3729,10 @@
 	}
 
 	il_set_rxon_channel(il, &il->bands[NL80211_BAND_2GHZ].channels[5]);
-	il3945_setup_deferred_work(il);
+	err = il3945_setup_deferred_work(il);
+	if (err)
+		goto out_remove_sysfs;
+
 	il3945_setup_handlers(il);
 	il_power_initialize(il);
 
@@ -3738,7 +3744,7 @@
 
 	err = il3945_setup_mac(il);
 	if (err)
-		goto out_remove_sysfs;
+		goto out_destroy_workqueue;
 
 	il_dbgfs_register(il, DRV_NAME);
 
@@ -3747,9 +3753,10 @@
 
 	return 0;
 
-out_remove_sysfs:
+out_destroy_workqueue:
 	destroy_workqueue(il->workqueue);
 	il->workqueue = NULL;
+out_remove_sysfs:
 	sysfs_remove_group(&pdev->dev.kobj, &il3945_attribute_group);
 out_release_irq:
 	free_irq(il->pci_dev->irq, il);
@@ -3846,9 +3853,7 @@
 	il_free_channel_map(il);
 	il_free_geos(il);
 	kfree(il->scan_cmd);
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
-
+	dev_kfree_skb(il->beacon_skb);
 	ieee80211_free_hw(il->hw);
 }
 
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/3945-rs.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/3945-rs.c
@@ -374,7 +374,7 @@
 }
 
 static void *
-il3945_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+il3945_rs_alloc(struct ieee80211_hw *hw)
 {
 	return hw->priv;
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/3945.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/3945.c
@@ -2100,7 +2100,7 @@
 
 		/* set tx power value for all OFDM rates */
 		for (rate_idx = 0; rate_idx < IL_OFDM_RATES; rate_idx++) {
-			s32 uninitialized_var(power_idx);
+			s32 power_idx;
 			int rc;
 
 			/* use channel group's clip-power table,
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -2265,7 +2265,7 @@
 	if (tid_data->tfds_in_queue == 0) {
 		D_HT("HW queue is empty\n");
 		tid_data->agg.state = IL_AGG_ON;
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 	} else {
 		D_HT("HW queue is NOT empty: %d packets in HW queue\n",
 		     tid_data->tfds_in_queue);
@@ -2768,7 +2768,7 @@
 	struct ieee80211_tx_info *info;
 	struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32 status = le32_to_cpu(tx_resp->u.status);
-	int uninitialized_var(tid);
+	int tid;
 	int sta_id;
 	int freed;
 	u8 *qc = NULL;
@@ -4344,8 +4344,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;
@@ -6216,10 +6217,12 @@
 	mutex_unlock(&il->mutex);
 }
 
-static void
+static int
 il4965_setup_deferred_work(struct il_priv *il)
 {
 	il->workqueue = create_singlethread_workqueue(DRV_NAME);
+	if (!il->workqueue)
+		return -ENOMEM;
 
 	init_waitqueue_head(&il->wait_command_queue);
 
@@ -6238,8 +6241,10 @@
 	timer_setup(&il->watchdog, il_bg_watchdog, 0);
 
 	tasklet_init(&il->irq_tasklet,
-		     (void (*)(unsigned long))il4965_irq_tasklet,
+		     il4965_irq_tasklet,
 		     (unsigned long)il);
+
+	return 0;
 }
 
 static void
@@ -6629,7 +6634,10 @@
 		goto out_disable_msi;
 	}
 
-	il4965_setup_deferred_work(il);
+	err = il4965_setup_deferred_work(il);
+	if (err)
+		goto out_free_irq;
+
 	il4965_setup_handlers(il);
 
 	/*********************************************
@@ -6667,6 +6675,7 @@
 out_destroy_workqueue:
 	destroy_workqueue(il->workqueue);
 	il->workqueue = NULL;
+out_free_irq:
 	free_irq(il->pci_dev->irq, il);
 out_disable_msi:
 	pci_disable_msi(il->pci_dev);
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/4965-rs.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/4965-rs.c
@@ -2403,7 +2403,7 @@
 		/* Repeat initial/next rate.
 		 * For legacy IL_NUMBER_TRY == 1, this loop will not execute.
 		 * For HT IL_HT_NUMBER_TRY == 3, this executes twice. */
-		while (repeat_rate > 0 && idx < LINK_QUAL_MAX_RETRY_NUM) {
+		while (repeat_rate > 0 && idx < (LINK_QUAL_MAX_RETRY_NUM - 1)) {
 			if (is_legacy(tbl_type.lq_type)) {
 				if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
 					ant_toggle_cnt++;
@@ -2474,7 +2474,7 @@
 }
 
 static void *
-il4965_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+il4965_rs_alloc(struct ieee80211_hw *hw)
 {
 	return hw->priv;
 }
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlegacy/common.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlegacy/common.c
@@ -699,7 +699,7 @@
 	u32 gp = _il_rd(il, CSR_EEPROM_GP);
 	int sz;
 	int ret;
-	u16 addr;
+	int addr;
 
 	/* allocate eeprom */
 	sz = il->cfg->eeprom_size;
@@ -4286,8 +4286,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);
@@ -5182,8 +5182,7 @@
 	memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
 
 	/* new association get rid of ibss beacon skb */
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
+	dev_consume_skb_irq(il->beacon_skb);
 	il->beacon_skb = NULL;
 	il->timestamp = 0;
 
@@ -5302,10 +5301,7 @@
 	}
 
 	spin_lock_irqsave(&il->lock, flags);
-
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
-
+	dev_consume_skb_irq(il->beacon_skb);
 	il->beacon_skb = skb;
 
 	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
--- linux-ein-5.4.0.orig/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ linux-ein-5.4.0/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -137,7 +137,7 @@
 	.pcie_l1_allowed = true,
 };
 
-static const struct iwl_base_params iwl_22560_base_params = {
+static const struct iwl_base_params iwl_ax210_base_params = {
 	.eeprom_size = OTP_LOW_IMAGE_SIZE_32K,
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
@@ -195,40 +195,26 @@
 	.trans.csr = &iwl_csr_v1,					\
 	.gp2_reg_addr = 0xa02c68
 
-#define IWL_DEVICE_22560						\
-	IWL_DEVICE_22000_COMMON,					\
-	.trans.device_family = IWL_DEVICE_FAMILY_22560,			\
-	.trans.base_params = &iwl_22560_base_params,			\
-	.trans.csr = &iwl_csr_v2
-
 #define IWL_DEVICE_AX210						\
 	IWL_DEVICE_22000_COMMON,					\
 	.trans.umac_prph_offset = 0x300000,				\
 	.trans.device_family = IWL_DEVICE_FAMILY_AX210,			\
-	.trans.base_params = &iwl_22560_base_params,			\
+	.trans.base_params = &iwl_ax210_base_params,			\
 	.trans.csr = &iwl_csr_v1,					\
 	.min_txq_size = 128,						\
 	.gp2_reg_addr = 0xd02c68,					\
 	.min_256_ba_txq_size = 512
 
-const struct iwl_cfg iwl22000_2ac_cfg_hr = {
-	.name = "Intel(R) Dual Band Wireless AC 22000",
-	.fw_name_pre = IWL_22000_HR_FW_PRE,
-	IWL_DEVICE_22500,
-};
-
-const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb = {
-	.name = "Intel(R) Dual Band Wireless AC 22000",
-	.fw_name_pre = IWL_22000_HR_CDB_FW_PRE,
-	IWL_DEVICE_22500,
-	.cdb = true,
-};
-
-const struct iwl_cfg iwl22000_2ac_cfg_jf = {
-	.name = "Intel(R) Dual Band Wireless AC 22000",
-	.fw_name_pre = IWL_22000_JF_FW_PRE,
-	IWL_DEVICE_22500,
-};
+/*
+ * If the device doesn't support HE, no need to have that many buffers.
+ * 22000 devices can split multiple frames into a single RB, so fewer are
+ * needed; AX210 cannot (but use smaller RBs by default) - these sizes
+ * were picked according to 8 MSDUs inside 256 A-MSDUs in an A-MPDU, with
+ * additional overhead to account for processing time.
+ */
+#define IWL_NUM_RBDS_NON_HE		512
+#define IWL_NUM_RBDS_22000_HE		2048
+#define IWL_NUM_RBDS_AX210_HE		4096
 
 const struct iwl_cfg iwl_ax101_cfg_qu_hr = {
 	.name = "Intel(R) Wi-Fi 6 AX101",
@@ -241,6 +227,7 @@
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.tx_with_siso_diversity = true,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax201_cfg_qu_hr = {
@@ -253,6 +240,7 @@
 	 * HT size; mac80211 would otherwise pick the HE max (256) by default.
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0 = {
@@ -265,6 +253,7 @@
 	 * HT size; mac80211 would otherwise pick the HE max (256) by default.
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = {
@@ -277,6 +266,7 @@
 	 * HT size; mac80211 would otherwise pick the HE max (256) by default.
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax101_cfg_quz_hr = {
@@ -289,42 +279,46 @@
 	 * HT size; mac80211 would otherwise pick the HE max (256) by default.
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax201_cfg_quz_hr = {
-		.name = "Intel(R) Wi-Fi 6 AX201 160MHz",
-		.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
-		IWL_DEVICE_22500,
-		/*
+	.name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+	.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+	IWL_DEVICE_22500,
+	/*
          * This device doesn't support receiving BlockAck with a large bitmap
          * so we need to restrict the size of transmitted aggregation to the
          * HT size; mac80211 would otherwise pick the HE max (256) by default.
          */
-		.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax1650s_cfg_quz_hr = {
-		.name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)",
-		.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
-		IWL_DEVICE_22500,
-		/*
+	.name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)",
+	.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+	IWL_DEVICE_22500,
+	/*
          * This device doesn't support receiving BlockAck with a large bitmap
          * so we need to restrict the size of transmitted aggregation to the
          * HT size; mac80211 would otherwise pick the HE max (256) by default.
          */
-		.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax1650i_cfg_quz_hr = {
-		.name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)",
-		.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
-		IWL_DEVICE_22500,
-		/*
+	.name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)",
+	.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+	IWL_DEVICE_22500,
+	/*
          * This device doesn't support receiving BlockAck with a large bitmap
          * so we need to restrict the size of transmitted aggregation to the
          * HT size; mac80211 would otherwise pick the HE max (256) by default.
          */
-		.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg iwl_ax200_cfg_cc = {
@@ -338,6 +332,7 @@
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.trans.bisr_workaround = 1,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg killer1650x_2ax_cfg = {
@@ -351,6 +346,7 @@
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.trans.bisr_workaround = 1,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 const struct iwl_cfg killer1650w_2ax_cfg = {
@@ -364,6 +360,7 @@
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.trans.bisr_workaround = 1,
+	.num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
 /*
@@ -375,48 +372,56 @@
 	.name = "Intel(R) Wireless-AC 9461",
 	.fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9462",
 	.fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9560",
 	.fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9560 160MHz",
 	.fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9461_2ac_cfg_qu_c0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9461",
 	.fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9462_2ac_cfg_qu_c0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9462",
 	.fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_cfg_qu_c0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9560",
 	.fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_160_cfg_qu_c0_jf_b0 = {
 	.name = "Intel(R) Wireless-AC 9560 160MHz",
 	.fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
 	IWL_DEVICE_22500,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0 = {
@@ -429,6 +434,7 @@
 	 * HT size; mac80211 would otherwise pick the HE max (256) by default.
 	 */
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_cfg_quz_a0_jf_b0_soc = {
@@ -443,6 +449,7 @@
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.integrated = true,
 	.soc_latency = 5000,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc = {
@@ -457,6 +464,7 @@
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.integrated = true,
 	.soc_latency = 5000,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9461_2ac_cfg_quz_a0_jf_b0_soc = {
@@ -471,6 +479,7 @@
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.integrated = true,
 	.soc_latency = 5000,
+	.num_rbds = IWL_NUM_RBDS_NON_HE,
 };
 
 const struct iwl_cfg iwl9462_2ac_cfg_quz_a0_jf_b0_soc = {
@@ -485,6 +494,7 @@
 	.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 	.integrated = true,
 	.soc_latency = 500
[file cut: first 33554432 bytes kept]
[document cut: first 31080720 of 33554253 characters kept]
